From fa50fda276cd461bd8eaf33edf731a8799d81910 Mon Sep 17 00:00:00 2001 From: PaulDalek Date: Tue, 10 Dec 2024 22:17:11 +0100 Subject: [PATCH 01/19] Expanded exisitng envs validation logic into extensive validation mechanism for options from all sources. --- lib/envs.js | 258 ----- lib/validation.js | 2802 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 2802 insertions(+), 258 deletions(-) delete mode 100644 lib/envs.js create mode 100644 lib/validation.js diff --git a/lib/envs.js b/lib/envs.js deleted file mode 100644 index c3ab2f49..00000000 --- a/lib/envs.js +++ /dev/null @@ -1,258 +0,0 @@ -/******************************************************************************* - -Highcharts Export Server - -Copyright (c) 2016-2024, Highsoft - -Licenced under the MIT licence. - -Additionally a valid Highcharts license is required for use. - -See LICENSE file in root for details. - -*******************************************************************************/ - -/** - * @overview This file is responsible for parsing the environment variables - * with the 'zod' library. The parsed environment variables are then exported - * to be used in the application as "envs". We should not use the `process.env` - * directly in the application as these would not be parsed properly. - * - * The environment variables are parsed and validated only once when - * the application starts. We should write a custom validator or a transformer - * for each of the options. - */ - -import dotenv from 'dotenv'; -import { z } from 'zod'; - -import { defaultConfig } from './schemas/config.js'; - -// Load .env into environment variables -dotenv.config(); - -// Object with custom validators and transformers, to avoid repetition -// in the Config object -const v = { - // Splits string value into elements in an array, trims every element, checks - // if an array is correct, if it is empty, and if it is, returns undefined - array: (filterArray) => - z - .string() - .transform((value) => - value - .split(',') - .map((value) => value.trim()) - .filter((value) => filterArray.includes(value)) - ) - .transform((value) => (value.length ? value : undefined)), - - // Allows only true, false and correctly parse the value to boolean - // or no value in which case the returned value will be undefined - boolean: () => - z - .enum(['true', 'false', '']) - .transform((value) => (value !== '' ? value === 'true' : undefined)), - - // Allows passed values or no value in which case the returned value will - // be undefined - enum: (values) => - z - .enum([...values, '']) - .transform((value) => (value !== '' ? value : undefined)), - - // Trims the string value and checks if it is empty or contains stringified - // values such as false, undefined, null, NaN, if it does, returns undefined - string: () => - z - .string() - .trim() - .refine( - (value) => - !['false', 'undefined', 'null', 'NaN'].includes(value) || - value === '', - (value) => ({ - message: `The string contains forbidden values, received '${value}'` - }) - ) - .transform((value) => (value !== '' ? value : undefined)), - - // Allows positive numbers or no value in which case the returned value will - // be undefined - positiveNum: () => - z - .string() - .trim() - .refine( - (value) => - value === '' || (!isNaN(parseFloat(value)) && parseFloat(value) > 0), - (value) => ({ - message: `The value must be numeric and positive, received '${value}'` - }) - ) - .transform((value) => (value !== '' ? parseFloat(value) : undefined)), - - // Allows non-negative numbers or no value in which case the returned value - // will be undefined - nonNegativeNum: () => - z - .string() - .trim() - .refine( - (value) => - value === '' || (!isNaN(parseFloat(value)) && parseFloat(value) >= 0), - (value) => ({ - message: `The value must be numeric and non-negative, received '${value}'` - }) - ) - .transform((value) => (value !== '' ? parseFloat(value) : undefined)) -}; - -export const Config = z.object({ - // puppeteer - PUPPETEER_ARGS: v.string(), - - // highcharts - HIGHCHARTS_VERSION: z - .string() - .trim() - .refine( - (value) => /^(latest|\d+(\.\d+){0,2})$/.test(value) || value === '', - (value) => ({ - message: `HIGHCHARTS_VERSION must be 'latest', a major version, or in the form XX.YY.ZZ, received '${value}'` - }) - ) - .transform((value) => (value !== '' ? value : undefined)), - HIGHCHARTS_CDN_URL: z - .string() - .trim() - .refine( - (value) => - value.startsWith('https://') || - value.startsWith('http://') || - value === '', - (value) => ({ - message: `Invalid value for HIGHCHARTS_CDN_URL. It should start with http:// or https://, received '${value}'` - }) - ) - .transform((value) => (value !== '' ? value : undefined)), - HIGHCHARTS_FORCE_FETCH: v.boolean(), - HIGHCHARTS_CACHE_PATH: v.string(), - HIGHCHARTS_ADMIN_TOKEN: v.string(), - HIGHCHARTS_CORE_SCRIPTS: v.array(defaultConfig.highcharts.coreScripts), - HIGHCHARTS_MODULE_SCRIPTS: v.array(defaultConfig.highcharts.moduleScripts), - HIGHCHARTS_INDICATOR_SCRIPTS: v.array( - defaultConfig.highcharts.indicatorScripts - ), - HIGHCHARTS_CUSTOM_SCRIPTS: v.array(defaultConfig.highcharts.customScripts), - - // export - EXPORT_INFILE: v.string(), - EXPORT_INSTR: v.string(), - EXPORT_OPTIONS: v.string(), - EXPORT_SVG: v.string(), - EXPORT_OUTFILE: v.string(), - EXPORT_TYPE: v.enum(['jpeg', 'png', 'pdf', 'svg']), - EXPORT_CONSTR: v.enum(['chart', 'stockChart', 'mapChart', 'ganttChart']), - EXPORT_B64: v.boolean(), - EXPORT_NO_DOWNLOAD: v.boolean(), - EXPORT_HEIGHT: v.positiveNum(), - EXPORT_WIDTH: v.positiveNum(), - EXPORT_SCALE: v.positiveNum(), - EXPORT_DEFAULT_HEIGHT: v.positiveNum(), - EXPORT_DEFAULT_WIDTH: v.positiveNum(), - EXPORT_DEFAULT_SCALE: v.positiveNum(), - EXPORT_GLOBAL_OPTIONS: v.string(), - EXPORT_THEME_OPTIONS: v.string(), - EXPORT_BATCH: v.string(), - EXPORT_RASTERIZATION_TIMEOUT: v.nonNegativeNum(), - - // custom - CUSTOM_LOGIC_ALLOW_CODE_EXECUTION: v.boolean(), - CUSTOM_LOGIC_ALLOW_FILE_RESOURCES: v.boolean(), - CUSTOM_LOGIC_CUSTOM_CODE: v.string(), - CUSTOM_LOGIC_CALLBACK: v.string(), - CUSTOM_LOGIC_RESOURCES: v.string(), - CUSTOM_LOGIC_LOAD_CONFIG: v.string(), - CUSTOM_LOGIC_CREATE_CONFIG: v.string(), - - // server - SERVER_ENABLE: v.boolean(), - SERVER_HOST: v.string(), - SERVER_PORT: v.positiveNum(), - SERVER_BENCHMARKING: v.boolean(), - - // server proxy - SERVER_PROXY_HOST: v.string(), - SERVER_PROXY_PORT: v.positiveNum(), - SERVER_PROXY_TIMEOUT: v.nonNegativeNum(), - - // server rate limiting - SERVER_RATE_LIMITING_ENABLE: v.boolean(), - SERVER_RATE_LIMITING_MAX_REQUESTS: v.nonNegativeNum(), - SERVER_RATE_LIMITING_WINDOW: v.nonNegativeNum(), - SERVER_RATE_LIMITING_DELAY: v.nonNegativeNum(), - SERVER_RATE_LIMITING_TRUST_PROXY: v.boolean(), - SERVER_RATE_LIMITING_SKIP_KEY: v.string(), - SERVER_RATE_LIMITING_SKIP_TOKEN: v.string(), - - // server ssl - SERVER_SSL_ENABLE: v.boolean(), - SERVER_SSL_FORCE: v.boolean(), - SERVER_SSL_PORT: v.positiveNum(), - SERVER_SSL_CERT_PATH: v.string(), - - // pool - POOL_MIN_WORKERS: v.nonNegativeNum(), - POOL_MAX_WORKERS: v.nonNegativeNum(), - POOL_WORK_LIMIT: v.positiveNum(), - POOL_ACQUIRE_TIMEOUT: v.nonNegativeNum(), - POOL_CREATE_TIMEOUT: v.nonNegativeNum(), - POOL_DESTROY_TIMEOUT: v.nonNegativeNum(), - POOL_IDLE_TIMEOUT: v.nonNegativeNum(), - POOL_CREATE_RETRY_INTERVAL: v.nonNegativeNum(), - POOL_REAPER_INTERVAL: v.nonNegativeNum(), - POOL_BENCHMARKING: v.boolean(), - - // logger - LOGGING_LEVEL: z - .string() - .trim() - .refine( - (value) => - value === '' || - (!isNaN(parseFloat(value)) && - parseFloat(value) >= 0 && - parseFloat(value) <= 5), - (value) => ({ - message: `Invalid value for LOGGING_LEVEL. We only accept values from 0 to 5 as logging levels, received '${value}'` - }) - ) - .transform((value) => (value !== '' ? parseFloat(value) : undefined)), - LOGGING_FILE: v.string(), - LOGGING_DEST: v.string(), - LOGGING_TO_CONSOLE: v.boolean(), - LOGGING_TO_FILE: v.boolean(), - - // ui - UI_ENABLE: v.boolean(), - UI_ROUTE: v.string(), - - // other - OTHER_NODE_ENV: v.enum(['development', 'production', 'test']), - OTHER_LISTEN_TO_PROCESS_EXITS: v.boolean(), - OTHER_NO_LOGO: v.boolean(), - OTHER_HARD_RESET_PAGE: v.boolean(), - OTHER_BROWSER_SHELL_MODE: v.boolean(), - - // debugger - DEBUG_ENABLE: v.boolean(), - DEBUG_HEADLESS: v.boolean(), - DEBUG_DEVTOOLS: v.boolean(), - DEBUG_LISTEN_TO_CONSOLE: v.boolean(), - DEBUG_DUMPIO: v.boolean(), - DEBUG_SLOW_MO: v.nonNegativeNum(), - DEBUG_DEBUGGING_PORT: v.positiveNum() -}); - -export const envs = Config.partial().parse(process.env); diff --git a/lib/validation.js b/lib/validation.js new file mode 100644 index 00000000..1cfc327d --- /dev/null +++ b/lib/validation.js @@ -0,0 +1,2802 @@ +/******************************************************************************* + +Highcharts Export Server + +Copyright (c) 2016-2024, Highsoft + +Licenced under the MIT licence. + +Additionally a valid Highcharts license is required for use. + +See LICENSE file in root for details. + +*******************************************************************************/ + +/** + * @overview This file handles parsing and validating options from multiple + * sources (the config file, custom JSON, environment variables, CLI arguments, + * and request payload) using the 'zod' library. + * + * Environment variables are parsed and validated only once at application + * startup, and the validated results are exported as `envs` for use throughout + * the application. + * + * Options from other sources, however, are parsed and validated on demand, + * each time an export is attempted. + */ + +import dotenv from 'dotenv'; +import { z } from 'zod'; + +import { defaultConfig } from './schemas/config.js'; + +// Load the .env into environment variables +dotenv.config(); + +// Get scripts names of each category from the default config +const { coreScripts, moduleScripts, indicatorScripts } = + defaultConfig.highcharts; + +// Sets the custom error map globally +z.setErrorMap(_customErrorMap); + +/** + * Object containing custom general validators and parsers to avoid repetition + * in schema objects. All validators apply to values from various sources, + * including the default config file, a custom JSON file loaded with the option + * called `loadConfig`, the .env file, CLI arguments, and the request payload. + * The `strictCheck` flag enables stricter validation and parsing rules. This + * flag is set to false for values that come from the .env file or CLI arguments + * because they are provided as strings and need to be parsed accordingly first. + */ +const v = { + /** + * The `boolean` validator that returns a Zod schema with an optional stricter + * check based on the `strictCheck` parameter. + * + * The validation schema ensures that: + * + * - When `strictCheck` is true, the schema will accept values are true + * and false and the schema will validate against the default boolean + * validator. + * + * - When `strictCheck` is false, the schema will accept values are true, + * false, null, 'true', 'false', 'undefined', 'null', and ''. The strings + * 'undefined', 'null', and '' will be transformed to null, the string 'true' + * will be transformed to the boolean value true, and 'false' will + * be transformed to the boolean value false. + * + * @function boolean + * + * @param {boolean} strictCheck - Determines if stricter validation should + * be applied. + * + * @returns {z.ZodSchema} A Zod schema object for validating boolean values. + */ + boolean(strictCheck) { + return strictCheck + ? z.boolean() + : z + .union([ + z + .enum(['true', 'false', 'undefined', 'null', '']) + .transform((value) => + !['undefined', 'null', ''].includes(value) + ? value === 'true' + : null + ), + z.boolean() + ]) + .nullable(); + }, + + /** + * The `string` validator that returns a Zod schema with an optional stricter + * check based on the `strictCheck` parameter. + * + * The validation schema ensures that: + * + * - When `strictCheck` is true, the schema will accept trimmed strings except + * the forbidden values: 'false', 'undefined', 'null', and ''. + * + * - When `strictCheck` is false, the schema will accept trimmed strings + * and null. The forbidden values: 'false', 'undefined', 'null', and '' will + * be transformed to null. + * + * @function string + * + * @param {boolean} strictCheck - Determines if stricter validation should + * be applied. + * + * @returns {z.ZodSchema} A Zod schema object for validating string values. + */ + string(strictCheck) { + return strictCheck + ? z + .string() + .trim() + .refine( + (value) => !['false', 'undefined', 'null', ''].includes(value), + { + params: { + errorMessage: `The string contains a forbidden value` + } + } + ) + : z + .string() + .trim() + .transform((value) => + !['false', 'undefined', 'null', ''].includes(value) ? value : null + ) + .nullable(); + }, + + /** + * The `enum` validator that returns a Zod schema with an optional stricter + * check based on the `strictCheck` parameter. + * + * The schema will validate against the provided `values` array. + * + * The validation schema ensures that: + * + * - When `strictCheck` is true, the schema will validate against the `values` + * array with the default enum validator. + * + * - When `strictCheck` is false, the schema will accept also null, + * 'undefined', 'null', and '', which will be transformed to null. + * + * @function enum + * + * @param {Array.} values - An array of valid string values + * for the enum. + * @param {boolean} strictCheck - Determines if stricter validation should + * be applied. + * + * @returns {z.ZodSchema} A Zod schema object for validating enum values. + */ + enum(values, strictCheck) { + return strictCheck + ? z.enum([...values]) + : z + .enum([...values, 'undefined', 'null', '']) + .transform((value) => + !['undefined', 'null', ''].includes(value) ? value : null + ) + .nullable(); + }, + + /** + * The `stringArray` validator that returns a Zod schema with an optional + * stricter check based on the `strictCheck` parameter. + * + * The validation schema ensures that: + * + * - When `strictCheck` is true, the schema will accept an array of trimmed + * string values filtered by the logic provided through the `filterCallback`. + * + * - When `strictCheck` is false, the schema will accept null and trimmed + * string values which will be splitted into an array of strings and filtered + * from the '[' and ']' characters and by the logic provided through + * the `filterCallback`. If the array is empty, it will be transformed + * to null. + * + * @function stringArray + * + * @param {function} filterCallback - The filter callback. + * @param {string} separator - The separator for spliting a string. + * @param {boolean} strictCheck - Determines if stricter validation should + * be applied. + * + * @returns {z.ZodSchema} A Zod schema object for validating array of string + * values. + */ + stringArray(filterCallback, separator, strictCheck) { + const arraySchema = z.string().trim().array(); + const stringSchema = z + .string() + .trim() + .transform((value) => { + if (value.startsWith('[')) { + value = value.slice(1); + } + if (value.endsWith(']')) { + value = value.slice(0, -1); + } + return value.split(separator); + }); + + const transformCallback = (value) => + value.map((value) => value.trim()).filter(filterCallback); + + return strictCheck + ? arraySchema.transform(transformCallback) + : z + .union([stringSchema, arraySchema]) + .transform(transformCallback) + .transform((value) => (value.length ? value : null)) + .nullable(); + }, + + /** + * The `positiveNum` validator that returns a Zod schema with an optional + * stricter check based on the `strictCheck` parameter. + * + * The validation schema ensures that: + * + * - When `strictCheck` is true, the schema will accept positive number values + * and validate against the default positive number validator. + * + * - When `strictCheck` is false, the schema will accept positive number + * values, null, and trimmed string values that can either be 'undefined', + * 'null', '', or represent a positive number. It will transform the string + * to a positive number, or to null if it is 'undefined', 'null', or ''. + * + * @function positiveNum + * + * @param {boolean} strictCheck - Determines if stricter validation should + * be applied. + * + * @returns {z.ZodSchema} A Zod schema object for validating positive number + * values. + */ + positiveNum(strictCheck) { + return strictCheck + ? z.number().positive() + : z + .union([ + z + .string() + .trim() + .refine( + (value) => + (!isNaN(Number(value)) && Number(value) > 0) || + ['undefined', 'null', ''].includes(value), + { + params: { + errorMessage: `The value must be numeric and positive` + } + } + ) + .transform((value) => + !['undefined', 'null', ''].includes(value) + ? Number(value) + : null + ), + z.number().positive() + ]) + .nullable(); + }, + + /** + * The `nonNegativeNum` validator that returns a Zod schema with an optional + * stricter check based on the `strictCheck` parameter. + * + * The validation schema ensures that: + * + * - When `strictCheck` is true, the schema will accept non-negative number + * values and validate against the default non-negative number validator. + * + * - When `strictCheck` is false, the schema will accept non-negative number + * values, null, and trimmed string values that can either be 'undefined', + * 'null', '', or represent a non-negative number. It will transform + * the string to a non-negative number, or to null if it is 'undefined', + * 'null', or ''. + * + * @function nonNegativeNum + * + * @param {boolean} strictCheck - Determines if stricter validation should + * be applied. + * + * @returns {z.ZodSchema} A Zod schema object for validating non-negative + * number values. + */ + nonNegativeNum(strictCheck) { + return strictCheck + ? z.number().nonnegative() + : z + .union([ + z + .string() + .trim() + .refine( + (value) => + (!isNaN(Number(value)) && Number(value) >= 0) || + ['undefined', 'null', ''].includes(value), + { + params: { + errorMessage: `The value must be numeric and non-negative` + } + } + ) + .transform((value) => + !['undefined', 'null', ''].includes(value) + ? Number(value) + : null + ), + z.number().nonnegative() + ]) + .nullable(); + }, + + /** + * The `startsWith` validator that returns a Zod schema with an optional + * stricter check based on the `strictCheck` parameter. + * + * The schema will validate against the provided `prefixes` array to check + * whether a string value starts with any of the values provided + * in the `prefixes` array. + * + * The validation schema ensures that: + * + * - When `strictCheck` is true, the schema will accept trimmed string values + * that start with values from the prefixes array. + * + * - When `strictCheck` is false, the schema will accept trimmed string values + * that start with values from the prefixes array, null, 'undefined', 'null', + * and '' where the schema will transform them to null. + * + * @function startsWith + * + * @param {Array.} prefixes - An array of prefixes to validate + * the string against. + * @param {boolean} strictCheck - Determines if stricter validation should + * be applied. + * + * @returns {z.ZodSchema} A Zod schema object for validating strings that + * starts with values. + */ + startsWith(prefixes, strictCheck) { + return strictCheck + ? z + .string() + .trim() + .refine( + (value) => prefixes.some((prefix) => value.startsWith(prefix)), + { + params: { + errorMessage: `The value must be a string that starts with ${prefixes.join(', ')}` + } + } + ) + : z + .string() + .trim() + .refine( + (value) => + prefixes.some((prefix) => value.startsWith(prefix)) || + ['undefined', 'null', ''].includes(value), + { + params: { + errorMessage: `The value must be a string that starts with ${prefixes.join(', ')}` + } + } + ) + .transform((value) => + !['undefined', 'null', ''].includes(value) ? value : null + ) + .nullable(); + }, + + /** + * The `chartConfig` validator that returns a Zod schema. + * + * The validation schema ensures that the schema will accept object values + * or trimmed string values that contain ' + value.indexOf('= 0 || + value.indexOf('= 0 || + (value.startsWith('{') && value.endsWith('}')) || + ['undefined', 'null', ''].includes(value), + { + params: { + errorMessage: `The value must be a string that contains ' + !['undefined', 'null', ''].includes(value) ? value : null + ), + z.object({}).passthrough() + ]) + .nullable(); + }, + + /** + * The `additionalOptions` validator that returns a Zod schema. + * + * The validation schema ensures that the schema will accept object values + * or trimmed string values that end with '.json' and are at least one + * character long excluding the extension, start with the '{' and end + * with the '}', and null. The 'undefined', 'null', and '' values will + * be transformed to null. + * + * @function additionalOptions + * + * @returns {z.ZodSchema} A Zod schema object for validating additional chart + * options value. + */ + additionalOptions() { + return z + .union([ + z + .string() + .trim() + .refine( + (value) => + (value.length >= 6 && value.endsWith('.json')) || + (value.startsWith('{') && value.endsWith('}')) || + ['undefined', 'null', ''].includes(value), + { + params: { + errorMessage: `The value must be a string that ends with '.json' or starts with '{' and ends with '}'` + } + } + ) + .transform((value) => + !['undefined', 'null', ''].includes(value) ? value : null + ), + z.object({}).passthrough() + ]) + .nullable(); + } +}; + +/** + * Object containing custom config validators and parsers to avoid repetition + * in schema objects. All validators apply to values from various sources, + * including the default config file, a custom JSON file loaded with the option + * called `loadConfig`, the .env file, CLI arguments, and the request payload. + * The `strictCheck` flag enables stricter validation and parsing rules. This + * flag is set to false for values that come from the .env file or CLI arguments + * because they are provided as strings and need to be parsed accordingly first. + */ +const config = { + /** + * The `args` validator that returns a Zod schema with an optional stricter + * check based on the `strictCheck` parameter. + * + * The validation schema ensures the same work as the `stringArray` validator. + * + * @function args + * + * @param {boolean} strictCheck - Determines if stricter validation should + * be applied. + * + * @returns {z.ZodSchema} A Zod schema object for validating the `args` + * option. + */ + args(strictCheck) { + return v.stringArray( + (value) => !['false', 'undefined', 'null', ''].includes(value), + ';', + strictCheck + ); + }, + + /** + * The `version` validator that returns a Zod schema with an optional stricter + * check based on the `strictCheck` parameter. + * + * The validation schema ensures that: + * + * - When `strictCheck` is true, the schema will accept trimmed string values + * that are a RegExp-based that allows to be 'latest', or in the format XX, + * XX.YY, or XX.YY.ZZ, where XX, YY, and ZZ are numeric for the Highcharts + * version option. + * + * - When `strictCheck` is false, the schema will accept also null, + * 'undefined', 'null', or '' and in all cases the schema will transform them + * to null. + * + * @function version + * + * @param {boolean} strictCheck - Determines if stricter validation should + * be applied. + * + * @returns {z.ZodSchema} A Zod schema object for validating the `version` + * option. + */ + version(strictCheck) { + return strictCheck + ? z + .string() + .trim() + .refine((value) => /^(latest|\d{1,2}(\.\d{1,2}){0,2})$/.test(value), { + params: { + errorMessage: + "The value must be 'latest', a major version, or in the form XX.YY.ZZ" + } + }) + : z + .string() + .trim() + .refine( + (value) => + /^(latest|\d{1,2}(\.\d{1,2}){0,2})$/.test(value) || + ['undefined', 'null', ''].includes(value), + { + params: { + errorMessage: + "The value must be 'latest', a major version, or in the form XX.YY.ZZ" + } + } + ) + .transform((value) => + !['undefined', 'null', ''].includes(value) ? value : null + ) + .nullable(); + }, + + /** + * The `cdnUrl` validator that returns a Zod schema with an optional stricter + * check based on the `strictCheck` parameter. + * + * The validation schema ensures the same work as the `startsWith` validator. + * + * @function cdnUrl + * + * @param {boolean} strictCheck - Determines if stricter validation should + * be applied. + * + * @returns {z.ZodSchema} A Zod schema object for validating the `cdnUrl` + * option. + */ + cdnUrl(strictCheck) { + return v.startsWith(['http://', 'https://'], strictCheck); + }, + + /** + * The `forceFetch` validator that returns a Zod schema with an optional + * stricter check based on the `strictCheck` parameter. + * + * The validation schema ensures the same work as the `boolean` validator. + * + * @function forceFetch + * + * @param {boolean} strictCheck - Determines if stricter validation should + * be applied. + * + * @returns {z.ZodSchema} A Zod schema object for validating the `forceFetch` + * option. + */ + forceFetch(strictCheck) { + return v.boolean(strictCheck); + }, + + /** + * The `cachePath` validator that returns a Zod schema with an optional + * stricter check based on the `strictCheck` parameter. + * + * The validation schema ensures the same work as the `string` validator. + * + * @function cachePath + * + * @param {boolean} strictCheck - Determines if stricter validation should + * be applied. + * + * @returns {z.ZodSchema} A Zod schema object for validating the `cachePath` + * option. + */ + cachePath(strictCheck) { + return v.string(strictCheck); + }, + + /** + * The `adminToken` validator that returns a Zod schema with an optional + * stricter check based on the `strictCheck` parameter. + * + * The validation schema ensures the same work as the `string` validator. + * + * @function adminToken + * + * @param {boolean} strictCheck - Determines if stricter validation should + * be applied. + * + * @returns {z.ZodSchema} A Zod schema object for validating the `adminToken` + * option. + */ + adminToken(strictCheck) { + return v.string(strictCheck); + }, + + /** + * The `coreScripts` validator that returns a Zod schema with an optional + * stricter check based on the `strictCheck` parameter. + * + * The validation schema ensures the same work as the `stringArray` validator. + * + * @function coreScripts + * + * @param {boolean} strictCheck - Determines if stricter validation should + * be applied. + * + * @returns {z.ZodSchema} A Zod schema object for validating the `coreScripts` + * option. + */ + coreScripts(strictCheck) { + return v.stringArray( + (value) => coreScripts.value.includes(value), + ',', + strictCheck + ); + }, + + /** + * The `moduleScripts` validator that returns a Zod schema with an optional + * stricter check based on the `strictCheck` parameter. + * + * The validation schema ensures the same work as the `stringArray` validator. + * + * @function moduleScripts + * + * @param {boolean} strictCheck - Determines if stricter validation should + * be applied. + * + * @returns {z.ZodSchema} A Zod schema object for validating + * the `moduleScripts` option. + */ + moduleScripts(strictCheck) { + return v.stringArray( + (value) => moduleScripts.value.includes(value), + ',', + strictCheck + ); + }, + + /** + * The `indicatorScripts` validator that returns a Zod schema with an optional + * stricter check based on the `strictCheck` parameter. + * + * The validation schema ensures the same work as the `stringArray` validator. + * + * @function indicatorScripts + * + * @param {boolean} strictCheck - Determines if stricter validation should + * be applied. + * + * @returns {z.ZodSchema} A Zod schema object for validating + * the `indicatorScripts` option. + */ + indicatorScripts(strictCheck) { + return v.stringArray( + (value) => indicatorScripts.value.includes(value), + ',', + strictCheck + ); + }, + + /** + * The `customScripts` validator that returns a Zod schema with an optional + * stricter check based on the `strictCheck` parameter. + * + * The validation schema ensures the same work as the `stringArray` validator. + * + * @function customScripts + * + * @param {boolean} strictCheck - Determines if stricter validation should + * be applied. + * + * @returns {z.ZodSchema} A Zod schema object for validating + * the `customScripts` option. + */ + customScripts(strictCheck) { + return v.stringArray( + (value) => value.startsWith('https://') || value.startsWith('http://'), + ',', + strictCheck + ); + }, + + /** + * The `infile` validator that returns a Zod schema with an optional stricter + * check based on the `strictCheck` parameter. + * + * The validation schema ensures that: + * + * - When `strictCheck` is true, the schema will accept trimmed string values + * that end with '.json' or '.svg', are at least one character long excluding + * the extension, or null. + * + * - When `strictCheck` is false, the schema will accept trimmed string values + * that end with '.json' or '.svg', are at least one character long excluding + * the extension and will be null if the provided value is null, 'undefined', + * 'null', or ''. + * + * @function infile + * + * @param {boolean} strictCheck - Determines if stricter validation should + * be applied. + * + * @returns {z.ZodSchema} A Zod schema object for validating the `infile` + * option. + */ + infile(strictCheck) { + return strictCheck + ? z + .string() + .trim() + .refine( + (value) => + (value.length >= 6 && value.endsWith('.json')) || + (value.length >= 5 && value.endsWith('.svg')), + { + params: { + errorMessage: `The value must be a string that ends with .json or .svg` + } + } + ) + .nullable() + : z + .string() + .trim() + .refine( + (value) => + (value.length >= 6 && value.endsWith('.json')) || + (value.length >= 5 && value.endsWith('.svg')) || + ['undefined', 'null', ''].includes(value), + { + params: { + errorMessage: `The value must be a string that ends with .json or .svg` + } + } + ) + .transform((value) => + !['undefined', 'null', ''].includes(value) ? value : null + ) + .nullable(); + }, + + /** + * The `instr` validator that returns a Zod schema. + * + * The validation schema ensures the same work as the `options` validator. + * + * @function instr + * + * @returns {z.ZodSchema} A Zod schema object for validating the `instr` + * option. + */ + instr() { + return v.chartConfig(); + }, + + /** + * The `options` validator that returns a Zod schema. + * + * The validation schema ensures the same work as the `options` validator. + * + * @function options + * + * @returns {z.ZodSchema} A Zod schema object for validating the `options` + * option. + */ + options() { + return v.chartConfig(); + }, + + /** + * The `svg` validator that returns a Zod schema. + * + * The validation schema ensures that the schema will accept object values + * or trimmed string values that contain ' + value.indexOf('= 0 || + value.indexOf('= 0 || + ['false', 'undefined', 'null', ''].includes(value), + { + params: { + errorMessage: `The value must be a string that contains ' + !['false', 'undefined', 'null', ''].includes(value) ? value : null + ) + .nullable(); + }, + + /** + * The `outfile` validator that returns a Zod schema with an optional stricter + * check based on the `strictCheck` parameter. + * + * The validation schema ensures that: + * + * - When `strictCheck` is true, the schema will accept trimmed string values + * that end with '.jpeg', '.jpg', '.png', '.pdf', or '.svg', are at least one + * character long excluding the extension, or null. + * + * - When `strictCheck` is false, the schema will accept trimmed string values + * that end with '.jpeg', '.jpg', '.png', '.pdf', or '.svg', are at least one + * character long excluding the extension and will be null if the provided + * value is null, 'undefined', 'null', or ''. + * + * @function outfile + * + * @param {boolean} strictCheck - Determines if stricter validation should + * be applied. + * + * @returns {z.ZodSchema} A Zod schema object for validating the `outfile` + * option. + */ + outfile(strictCheck) { + return strictCheck + ? z + .string() + .trim() + .refine( + (value) => + (value.length >= 6 && value.endsWith('.jpeg')) || + (value.length >= 5 && + (value.endsWith('.jpg') || + value.endsWith('.png') || + value.endsWith('.pdf') || + value.endsWith('.svg'))), + { + params: { + errorMessage: `The value must be a string that ends with .jpeg, .jpg, .png, .pdf, or .svg` + } + } + ) + .nullable() + : z + .string() + .trim() + .refine( + (value) => + (value.length >= 6 && value.endsWith('.jpeg')) || + (value.length >= 5 && + (value.endsWith('.jpg') || + value.endsWith('.png') || + value.endsWith('.pdf') || + value.endsWith('.svg'))) || + ['undefined', 'null', ''].includes(value), + { + params: { + errorMessage: `The value must be a string that ends with .jpeg, .jpg, .png, .pdf, or .svg` + } + } + ) + .transform((value) => + !['undefined', 'null', ''].includes(value) ? value : null + ) + .nullable(); + }, + + /** + * The `type` validator that returns a Zod schema with an optional stricter + * check based on the `strictCheck` parameter. + * + * The validation schema ensures the same work as the `enum` validator. + * + * @function type + * + * @param {boolean} strictCheck - Determines if stricter validation should + * be applied. + * + * @returns {z.ZodSchema} A Zod schema object for validating the `type` + * option. + */ + type(strictCheck) { + return v.enum(['jpeg', 'jpg', 'png', 'pdf', 'svg'], strictCheck); + }, + + /** + * The `constr` validator that returns a Zod schema with an optional stricter + * check based on the `strictCheck` parameter. + * + * The validation schema ensures the same work as the `enum` validator. + * + * @function constr + * + * @param {boolean} strictCheck - Determines if stricter validation should + * be applied. + * + * @returns {z.ZodSchema} A Zod schema object for validating the `constr` + * option. + */ + constr(strictCheck) { + return v.enum( + ['chart', 'stockChart', 'mapChart', 'ganttChart'], + strictCheck + ); + }, + + /** + * The `b64` validator that returns a Zod schema with an optional stricter + * check based on the `strictCheck` parameter. + * + * The validation schema ensures the same work as the `boolean` validator. + * + * @function b64 + * + * @param {boolean} strictCheck - Determines if stricter validation should + * be applied. + * + * @returns {z.ZodSchema} A Zod schema object for validating the `b64` option. + */ + b64(strictCheck) { + return v.boolean(strictCheck); + }, + + /** + * The `noDownload` validator that returns a Zod schema with an optional + * stricter check based on the `strictCheck` parameter. + * + * The validation schema ensures the same work as the `boolean` validator. + * + * @function noDownload + * + * @param {boolean} strictCheck - Determines if stricter validation should + * be applied. + * + * @returns {z.ZodSchema} A Zod schema object for validating the `noDownload` + * option. + */ + noDownload(strictCheck) { + return v.boolean(strictCheck); + }, + + /** + * The `defaultHeight` validator that returns a Zod schema with an optional + * stricter check based on the `strictCheck` parameter. + * + * The validation schema ensures the same work as the `positiveNum` validator. + * + * @function defaultHeight + * + * @param {boolean} strictCheck - Determines if stricter validation should + * be applied. + * + * @returns {z.ZodSchema} A Zod schema object for validating + * the `defaultHeight` option. + */ + defaultHeight(strictCheck) { + return v.positiveNum(strictCheck); + }, + + /** + * The `defaultWidth` validator that returns a Zod schema with an optional + * stricter check based on the `strictCheck` parameter. + * + * The validation schema ensures the same work as the `positiveNum` validator. + * + * @function defaultWidth + * + * @param {boolean} strictCheck - Determines if stricter validation should + * be applied. + * + * @returns {z.ZodSchema} A Zod schema object for validating + * the `defaultWidth` option. + */ + defaultWidth(strictCheck) { + return v.positiveNum(strictCheck); + }, + + /** + * The `defaultScale` validator that returns a Zod schema with an optional + * stricter check based on the `strictCheck` parameter. + * + * The validation schema ensures that: + * + * - When `strictCheck` is true, the schema will accept number values that + * are between 0.1 and 5 (inclusive). + * + * - When `strictCheck` is false, the schema will accept number values + * and stringified number values that are between 0.1 and 5 (inclusive), null, + * 'undefined', 'null', and '' which will be transformed to null. + * + * @function defaultScale + * + * @param {boolean} strictCheck - Determines if stricter validation should + * be applied. + * + * @returns {z.ZodSchema} A Zod schema object for validating + * the `defaultScale` option. + */ + defaultScale(strictCheck) { + return strictCheck + ? z.number().gte(0.1).lte(5) + : z + .union([ + z + .string() + .trim() + .refine( + (value) => + (!isNaN(Number(value)) && + value !== true && + !value.startsWith('[') && + Number(value) >= 0.1 && + Number(value) <= 5) || + ['undefined', 'null', ''].includes(value), + { + params: { + errorMessage: 'The value must be within a 0.1 and 5.0 range' + } + } + ) + .transform((value) => + !['undefined', 'null', ''].includes(value) + ? Number(value) + : null + ), + z.number().gte(0.1).lte(5) + ]) + .nullable(); + }, + + /** + * The `height` validator that returns a Zod schema with an optional stricter + * check based on the `strictCheck` parameter. + * + * The validation schema ensures the same work as a nullable `defaultHeight` + * validator. + * + * @function height + * + * @param {boolean} strictCheck - Determines if stricter validation should + * be applied. + * + * @returns {z.ZodSchema} A Zod schema object for validating the `height` + * option. + */ + height(strictCheck) { + return this.defaultHeight(strictCheck).nullable(); + }, + + /** + * The `width` validator that returns a Zod schema with an optional stricter + * check based on the `strictCheck` parameter. + * + * The validation schema ensures the same work as a nullable `defaultWidth` + * validator. + * + * @function width + * + * @param {boolean} strictCheck - Determines if stricter validation should + * be applied. + * + * @returns {z.ZodSchema} A Zod schema object for validating the `width` + * option. + */ + width(strictCheck) { + return this.defaultWidth(strictCheck).nullable(); + }, + + /** + * The `scale` validator that returns a Zod schema with an optional stricter + * check based on the `strictCheck` parameter. + * + * The validation schema ensures the same work as a nullable `defaultScale` + * validator. + * + * @function scale + * + * @param {boolean} strictCheck - Determines if stricter validation should + * be applied. + * + * @returns {z.ZodSchema} A Zod schema object for validating the `scale` + * option. + */ + scale(strictCheck) { + return this.defaultScale(strictCheck).nullable(); + }, + + /** + * The `globalOptions` validator that returns a Zod schema. + * + * The validation schema ensures the same work as the `additionalOptions` + * validator. + * + * @function globalOptions + * + * @returns {z.ZodSchema} A Zod schema object for validating + * the `globalOptions` option. + */ + globalOptions() { + return v.additionalOptions(); + }, + + /** + * The `themeOptions` validator that returns a Zod schema. + * + * The validation schema ensures the same work as the `additionalOptions` + * validator. + * + * @function themeOptions + * + * @returns {z.ZodSchema} A Zod schema object for validating + * the `themeOptions` option. + */ + themeOptions() { + return v.additionalOptions(); + }, + + /** + * The `batch` validator that returns a Zod schema with an optional stricter + * check based on the `strictCheck` parameter. + * + * The validation schema ensures the same work as the `string` validator. + * + * @function batch + * + * @param {boolean} strictCheck - Determines if stricter validation should + * be applied. + * + * @returns {z.ZodSchema} A Zod schema object for validating the `batch` + * option. + */ + batch(strictCheck) { + return v.string(strictCheck); + }, + + /** + * The `rasterizationTimeout` validator that returns a Zod schema with + * an optional stricter check based on the `strictCheck` parameter. + * + * The validation schema ensures the same work as the `nonNegativeNum` + * validator. + * + * @function rasterizationTimeout + * + * @param {boolean} strictCheck - Determines if stricter validation should + * be applied. + * + * @returns {z.ZodSchema} A Zod schema object for validating + * the `rasterizationTimeout` option. + */ + rasterizationTimeout(strictCheck) { + return v.nonNegativeNum(strictCheck); + }, + + /** + * The `allowCodeExecution` validator that returns a Zod schema with + * an optional stricter check based on the `strictCheck` parameter. + * + * The validation schema ensures the same work as the `boolean` validator. + * + * @function allowCodeExecution + * + * @param {boolean} strictCheck - Determines if stricter validation should + * be applied. + * + * @returns {z.ZodSchema} A Zod schema object for validating + * the `allowCodeExecution` option. + */ + allowCodeExecution(strictCheck) { + return v.boolean(strictCheck); + }, + + /** + * The `allowFileResources` validator that returns a Zod schema with + * an optional stricter check based on the `strictCheck` parameter. + * + * The validation schema ensures the same work as the `boolean` validator. + * + * @function allowFileResources + * + * @param {boolean} strictCheck - Determines if stricter validation should + * be applied. + * + * @returns {z.ZodSchema} A Zod schema object for validating + * the `allowFileResources` option. + */ + allowFileResources(strictCheck) { + return v.boolean(strictCheck); + }, + + /** + * The `customCode` validator that returns a Zod schema with an optional + * stricter check based on the `strictCheck` parameter. + * + * The validation schema ensures the same work as the `string` validator. + * + * @function customCode + * + * @param {boolean} strictCheck - Determines if stricter validation should + * be applied. + * + * @returns {z.ZodSchema} A Zod schema object for validating the `customCode` + * option. + */ + customCode(strictCheck) { + return v.string(strictCheck); + }, + + /** + * The `callback` validator that returns a Zod schema with an optional + * stricter check based on the `strictCheck` parameter. + * + * The validation schema ensures the same work as the `string` validator. + * + * @function callback + * + * @param {boolean} strictCheck - Determines if stricter validation should + * be applied. + * + * @returns {z.ZodSchema} A Zod schema object for validating the `callback` + * option. + */ + callback(strictCheck) { + return v.string(strictCheck); + }, + + /** + * The `resources` validator that returns a Zod schema with an optional + * stricter check based on the `strictCheck` parameter. + * + * The validation schema ensures that: + * + * - When `strictCheck` is true, the schema will accept a partial object + * with allowed properties `js`, `css`, and `files` where each of the allowed + * properties can be null, stringified version of the object, string that ends + * with the '.json', and null. + * + * - When `strictCheck` is false, the schema will accept a stringified version + * of a partial object with allowed properties `js`, `css`, and `files` where + * each of the allowed properties can be null, string that ends with the + * '.json', and will be null if the provided value is 'undefined', 'null' + * or ''. + * + * @function resources + * + * @param {boolean} strictCheck - Determines if stricter validation should + * be applied. + * + * @returns {z.ZodSchema} A Zod schema object for validating the `resources` + * option. + */ + resources(strictCheck) { + const objectSchema = z + .object({ + js: v.string(false), + css: v.string(false), + files: v + .stringArray( + (value) => !['undefined', 'null', ''].includes(value), + ',', + true + ) + .nullable() + }) + .partial(); + + const stringSchema1 = z + .string() + .trim() + .refine( + (value) => + (value.startsWith('{') && value.endsWith('}')) || + (value.length >= 6 && value.endsWith('.json')), + { + params: { + errorMessage: `The value must be a string that starts with '{' and ends with '}` + } + } + ); + + const stringSchema2 = z + .string() + .trim() + .refine( + (value) => + (value.startsWith('{') && value.endsWith('}')) || + (value.length >= 6 && value.endsWith('.json')) || + ['undefined', 'null', ''].includes(value), + { + params: { + errorMessage: `The value must be a string that ends with '.json'` + } + } + ) + .transform((value) => + !['undefined', 'null', ''].includes(value) ? value : null + ); + + return strictCheck + ? z.union([objectSchema, stringSchema1]).nullable() + : z.union([objectSchema, stringSchema2]).nullable(); + }, + + /** + * The `loadConfig` validator that returns a Zod schema with an optional + * stricter check based on the `strictCheck` parameter. + * + * The validation schema ensures the same work as the `string` validator. + * Additionally, it must be a string that ends with '.json'. + * + * @function loadConfig + * + * @param {boolean} strictCheck - Determines if stricter validation should + * be applied. + * + * @returns {z.ZodSchema} A Zod schema object for validating the `loadConfig` + * option. + */ + loadConfig(strictCheck) { + return v + .string(strictCheck) + .refine( + (value) => + value === null || (value.length >= 6 && value.endsWith('.json')), + { + params: { + errorMessage: `The value must be a string that ends with .json ` + } + } + ); + }, + + /** + * The `createConfig` validator that returns a Zod schema with an optional + * stricter check based on the `strictCheck` parameter. + * + * The validation schema ensures the same work as the `loadConfig` validator. + * + * @function createConfig + * + * @param {boolean} strictCheck - Determines if stricter validation should + * be applied. + * + * @returns {z.ZodSchema} A Zod schema object for validating + * the `createConfig` option. + */ + createConfig(strictCheck) { + return this.loadConfig(strictCheck); + }, + + /** + * The `enableServer` validator that returns a Zod schema with an optional + * stricter check based on the `strictCheck` parameter. + * + * The validation schema ensures the same work as the `boolean` validator. + * + * @function enableServer + * + * @param {boolean} strictCheck - Determines if stricter validation should + * be applied. + * + * @returns {z.ZodSchema} A Zod schema object for validating + * the `enableServer` option. + */ + enableServer(strictCheck) { + return v.boolean(strictCheck); + }, + + /** + * The `host` validator that returns a Zod schema with an optional stricter + * check based on the `strictCheck` parameter. + * + * The validation schema ensures the same work as the `string` validator. + * + * @function host + * + * @param {boolean} strictCheck - Determines if stricter validation should + * be applied. + * + * @returns {z.ZodSchema} A Zod schema object for validating the `host` + * option. + */ + host(strictCheck) { + return v.string(strictCheck); + }, + + /** + * The `port` validator that returns a Zod schema with an optional stricter + * check based on the `strictCheck` parameter. + * + * The validation schema ensures the same work as the `nonNegativeNum` + * validator. + * + * @function port + * + * @param {boolean} strictCheck - Determines if stricter validation should + * be applied. + * + * @returns {z.ZodSchema} A Zod schema object for validating the `port` + * option. + */ + port(strictCheck) { + return v.nonNegativeNum(strictCheck); + }, + + /** + * The `serverBenchmarking` validator that returns a Zod schema with + * an optional stricter check based on the `strictCheck` parameter. + * + * The validation schema ensures the same work as the `boolean` validator. + * + * @function serverBenchmarking + * + * @param {boolean} strictCheck - Determines if stricter validation should + * be applied. + * + * @returns {z.ZodSchema} A Zod schema object for validating + * the `serverBenchmarking` option. + */ + serverBenchmarking(strictCheck) { + return v.boolean(strictCheck); + }, + + /** + * The `proxyHost` validator that returns a Zod schema with an optional + * stricter check based on the `strictCheck` parameter. + * + * The validation schema ensures the same work as the `string` validator. + * + * @function proxyHost + * + * @param {boolean} strictCheck - Determines if stricter validation should + * be applied. + * + * @returns {z.ZodSchema} A Zod schema object for validating the `proxyHost` + * option. + */ + proxyHost(strictCheck) { + return v.string(strictCheck); + }, + + /** + * The `proxyPort` validator that returns a Zod schema with an optional + * stricter check based on the `strictCheck` parameter. + * + * The validation schema ensures the same work as a nullable `nonNegativeNum` + * validator. + * + * @function proxyPort + * + * @param {boolean} strictCheck - Determines if stricter validation should + * be applied. + * + * @returns {z.ZodSchema} A Zod schema object for validating the `proxyPort` + * option. + */ + proxyPort(strictCheck) { + return v.nonNegativeNum(strictCheck).nullable(); + }, + + /** + * The `proxyTimeout` validator that returns a Zod schema with an optional + * stricter check based on the `strictCheck` parameter. + * + * The validation schema ensures the same work as the `nonNegativeNum` + * validator. + * + * @function proxyTimeout + * + * @param {boolean} strictCheck - Determines if stricter validation should + * be applied. + * + * @returns {z.ZodSchema} A Zod schema object for validating + * the `proxyTimeout` option. + */ + proxyTimeout(strictCheck) { + return v.nonNegativeNum(strictCheck); + }, + + /** + * The `enableRateLimiting` validator that returns a Zod schema with + * an optional stricter check based on the `strictCheck` parameter. + * + * The validation schema ensures the same work as the `boolean` validator. + * + * @function enableRateLimiting + * + * @param {boolean} strictCheck - Determines if stricter validation should + * be applied. + * + * @returns {z.ZodSchema} A Zod schema object for validating + * the `enableRateLimiting` option. + */ + enableRateLimiting(strictCheck) { + return v.boolean(strictCheck); + }, + + /** + * The `maxRequests` validator that returns a Zod schema with an optional + * stricter check based on the `strictCheck` parameter. + * + * The validation schema ensures the same work as the `nonNegativeNum` + * validator. + * + * @function maxRequests + * + * @param {boolean} strictCheck - Determines if stricter validation should + * be applied. + * + * @returns {z.ZodSchema} A Zod schema object for validating the `maxRequests` + * option. + */ + maxRequests(strictCheck) { + return v.nonNegativeNum(strictCheck); + }, + + /** + * The `window` validator that returns a Zod schema with an optional stricter + * check based on the `strictCheck` parameter. + * + * The validation schema ensures the same work as the `nonNegativeNum` + * validator. + * + * @function window + * + * @param {boolean} strictCheck - Determines if stricter validation should + * be applied. + * + * @returns {z.ZodSchema} A Zod schema object for validating the `window` + * option. + */ + window(strictCheck) { + return v.nonNegativeNum(strictCheck); + }, + + /** + * The `delay` validator that returns a Zod schema with an optional stricter + * check based on the `strictCheck` parameter. + * + * The validation schema ensures the same work as the `nonNegativeNum` + * validator. + * + * @function delay + * + * @param {boolean} strictCheck - Determines if stricter validation should + * be applied. + * + * @returns {z.ZodSchema} A Zod schema object for validating the `delay` + * option. + */ + delay(strictCheck) { + return v.nonNegativeNum(strictCheck); + }, + + /** + * The `trustProxy` validator that returns a Zod schema with an optional + * stricter check based on the `strictCheck` parameter. + * + * The validation schema ensures the same work as the `boolean` validator. + * + * @function trustProxy + * + * @param {boolean} strictCheck - Determines if stricter validation should + * be applied. + * + * @returns {z.ZodSchema} A Zod schema object for validating the `trustProxy` + * option. + */ + trustProxy(strictCheck) { + return v.boolean(strictCheck); + }, + + /** + * The `skipKey` validator that returns a Zod schema with an optional stricter + * check based on the `strictCheck` parameter. + * + * The validation schema ensures the same work as the `string` validator. + * + * @function skipKey + * + * @param {boolean} strictCheck - Determines if stricter validation should + * be applied. + * + * @returns {z.ZodSchema} A Zod schema object for validating the `skipKey` + * option. + */ + skipKey(strictCheck) { + return v.string(strictCheck); + }, + + /** + * The `skipToken` validator that returns a Zod schema with an optional + * stricter check based on the `strictCheck` parameter. + * + * The validation schema ensures the same work as the `string` validator. + * + * @function skipToken + * + * @param {boolean} strictCheck - Determines if stricter validation should + * be applied. + * + * @returns {z.ZodSchema} A Zod schema object for validating the `skipToken` + * option. + */ + skipToken(strictCheck) { + return v.string(strictCheck); + }, + + /** + * The `enableSsl` validator that returns a Zod schema with an optional + * stricter check based on the `strictCheck` parameter. + * + * The validation schema ensures the same work as the `boolean` validator. + * + * @function enableSsl + * + * @param {boolean} strictCheck - Determines if stricter validation should + * be applied. + * + * @returns {z.ZodSchema} A Zod schema object for validating the `enableSsl` + * option. + */ + enableSsl(strictCheck) { + return v.boolean(strictCheck); + }, + + /** + * The `sslForce` validator that returns a Zod schema with an optional + * stricter check based on the `strictCheck` parameter. + * + * The validation schema ensures the same work as the `boolean` validator. + * + * @function sslForce + * + * @param {boolean} strictCheck - Determines if stricter validation should + * be applied. + * + * @returns {z.ZodSchema} A Zod schema object for validating the `sslForce` + * option. + */ + sslForce(strictCheck) { + return v.boolean(strictCheck); + }, + + /** + * The `sslPort` validator that returns a Zod schema with an optional stricter + * check based on the `strictCheck` parameter. + * + * The validation schema ensures the same work as the `nonNegativeNum` + * validator. + * + * @function sslPort + * + * @param {boolean} strictCheck - Determines if stricter validation should + * be applied. + * + * @returns {z.ZodSchema} A Zod schema object for validating the `sslPort` + * option. + */ + sslPort(strictCheck) { + return v.nonNegativeNum(strictCheck); + }, + + /** + * The `sslCertPath` validator that returns a Zod schema with an optional + * stricter check based on the `strictCheck` parameter. + * + * The validation schema ensures the same work as the `string` validator. + * + * @function sslCertPath + * + * @param {boolean} strictCheck - Determines if stricter validation should + * be applied. + * + * @returns {z.ZodSchema} A Zod schema object for validating the `sslCertPath` + * option. + */ + sslCertPath(strictCheck) { + return v.string(strictCheck); + }, + + /** + * The `minWorkers` validator that returns a Zod schema with an optional + * stricter check based on the `strictCheck` parameter. + * + * The validation schema ensures the same work as the `positiveNum` validator. + * + * @function minWorkers + * + * @param {boolean} strictCheck - Determines if stricter validation should + * be applied. + * + * @returns {z.ZodSchema} A Zod schema object for validating the `minWorkers` + * option. + */ + minWorkers(strictCheck) { + return v.positiveNum(strictCheck); + }, + + /** + * The `maxWorkers` validator that returns a Zod schema with an optional + * stricter check based on the `strictCheck` parameter. + * + * The validation schema ensures the same work as the `positiveNum` validator. + * + * @function maxWorkers + * + * @param {boolean} strictCheck - Determines if stricter validation should + * be applied. + * + * @returns {z.ZodSchema} A Zod schema object for validating the `maxWorkers` + * option. + */ + maxWorkers(strictCheck) { + return v.positiveNum(strictCheck); + }, + + /** + * The `workLimit` validator that returns a Zod schema with an optional + * stricter check based on the `strictCheck` parameter. + * + * The validation schema ensures the same work as the `positiveNum` validator. + * + * @function workLimit + * + * @param {boolean} strictCheck - Determines if stricter validation should + * be applied. + * + * @returns {z.ZodSchema} A Zod schema object for validating the `workLimit` + * option. + */ + workLimit(strictCheck) { + return v.positiveNum(strictCheck); + }, + + /** + * The `acquireTimeout` validator that returns a Zod schema with an optional + * stricter check based on the `strictCheck` parameter. + * + * The validation schema ensures the same work as the `nonNegativeNum` + * validator. + * + * @function acquireTimeout + * + * @param {boolean} strictCheck - Determines if stricter validation should + * be applied. + * + * @returns {z.ZodSchema} A Zod schema object for validating + * the `acquireTimeout` option. + */ + acquireTimeout(strictCheck) { + return v.nonNegativeNum(strictCheck); + }, + + /** + * The `createTimeout` validator that returns a Zod schema with an optional + * stricter check based on the `strictCheck` parameter. + * + * The validation schema ensures the same work as the `nonNegativeNum` + * validator. + * + * @function createTimeout + * + * @param {boolean} strictCheck - Determines if stricter validation should + * be applied. + * + * @returns {z.ZodSchema} A Zod schema object for validating + * the `createTimeout` option. + */ + createTimeout(strictCheck) { + return v.nonNegativeNum(strictCheck); + }, + + /** + * The `destroyTimeout` validator that returns a Zod schema with an optional + * stricter check based on the `strictCheck` parameter. + * + * The validation schema ensures the same work as the `nonNegativeNum` + * validator. + * + * @function destroyTimeout + * + * @param {boolean} strictCheck - Determines if stricter validation should + * be applied. + * + * @returns {z.ZodSchema} A Zod schema object for validating + * the `destroyTimeout` option. + */ + destroyTimeout(strictCheck) { + return v.nonNegativeNum(strictCheck); + }, + + /** + * The `idleTimeout` validator that returns a Zod schema with an optional + * stricter check based on the `strictCheck` parameter. + * + * The validation schema ensures the same work as the `nonNegativeNum` + * validator. + * + * @function idleTimeout + * + * @param {boolean} strictCheck - Determines if stricter validation should + * be applied. + * + * @returns {z.ZodSchema} A Zod schema object for validating + * the `idleTimeout` option. + */ + idleTimeout(strictCheck) { + return v.nonNegativeNum(strictCheck); + }, + + /** + * The `createRetryInterval` validator that returns a Zod schema with + * an optional stricter check based on the `strictCheck` parameter. + * + * The validation schema ensures the same work as the `nonNegativeNum` + * validator. + * + * @function createRetryInterval + * + * @param {boolean} strictCheck - Determines if stricter validation should + * be applied. + * + * @returns {z.ZodSchema} A Zod schema object for validating + * the `createRetryInterval` option. + */ + createRetryInterval(strictCheck) { + return v.nonNegativeNum(strictCheck); + }, + + /** + * The `reaperInterval` validator that returns a Zod schema with an optional + * stricter check based on the `strictCheck` parameter. + * + * The validation schema ensures the same work as the `nonNegativeNum` + * validator. + * + * @function reaperInterval + * + * @param {boolean} strictCheck - Determines if stricter validation should + * be applied. + * + * @returns {z.ZodSchema} A Zod schema object for validating + * the `reaperInterval` option. + */ + reaperInterval(strictCheck) { + return v.nonNegativeNum(strictCheck); + }, + + /** + * The `poolBenchmarking` validator that returns a Zod schema with an optional + * stricter check based on the `strictCheck` parameter. + * + * The validation schema ensures the same work as the `boolean` validator. + * + * @function poolBenchmarking + * + * @param {boolean} strictCheck - Determines if stricter validation should + * be applied. + * + * @returns {z.ZodSchema} A Zod schema object for validating + * the `poolBenchmarking` option. + */ + poolBenchmarking(strictCheck) { + return v.boolean(strictCheck); + }, + + /** + * The `resourcesInterval` validator that returns a Zod schema with + * an optional stricter check based on the `strictCheck` parameter. + * + * The validation schema ensures the same work as the `nonNegativeNum` + * validator. + * + * @function resourcesInterval + * + * @param {boolean} strictCheck - Determines if stricter validation should + * be applied. + * + * @returns {z.ZodSchema} A Zod schema object for validating + * the `resourcesInterval` option. + */ + resourcesInterval(strictCheck) { + return v.nonNegativeNum(strictCheck); + }, + + /** + * The `logLevel` validator that returns a Zod schema with an optional + * stricter check based on the `strictCheck` parameter. + * + * The validation schema ensures that: + * + * - When `strictCheck` is true, the schema will accept integer number values + * that are between 0 and 5 (inclusive). + * + * - When `strictCheck` is false, the schema will accept integer number values + * and stringified integer number values that are between 1 and 5 (inclusive), + * null, 'undefined', 'null', and '' which will be transformed to null. + * + * @function logLevel + * + * @param {boolean} strictCheck - Determines if stricter validation should + * be applied. + * + * @returns {z.ZodSchema} A Zod schema object for validating the `logLevel` + * option. + */ + logLevel(strictCheck) { + return strictCheck + ? z.number().int().gte(0).lte(5) + : z + .union([ + z + .string() + .trim() + .refine( + (value) => + (!isNaN(Number(value)) && + value !== true && + !value.startsWith('[') && + Number.isInteger(Number(value)) && + Number(value) >= 0 && + Number(value) <= 5) || + ['undefined', 'null', ''].includes(value), + { + params: { + errorMessage: 'The value must be within a 0 and 5 range' + } + } + ) + .transform((value) => + !['undefined', 'null', ''].includes(value) + ? Number(value) + : null + ), + z.number().int().gte(0).lte(5) + ]) + .nullable(); + }, + + /** + * The `logFile` validator that returns a Zod schema with an optional stricter + * check based on the `strictCheck` parameter. + * + * The validation schema ensures the same work as the `string` validator. + * Additionally, it must be a string that ends with '.log'. + * + * @function logFile + * + * @param {boolean} strictCheck - Determines if stricter validation should + * be applied. + * + * @returns {z.ZodSchema} A Zod schema object for validating the `logFile` + * option. + */ + logFile(strictCheck) { + return v + .string(strictCheck) + .refine( + (value) => + value === null || (value.length >= 5 && value.endsWith('.log')), + { + params: { + errorMessage: `The value must be a string that ends with '.log'` + } + } + ); + }, + + /** + * The `logDest` validator that returns a Zod schema with an optional stricter + * check based on the `strictCheck` parameter. + * + * The validation schema ensures the same work as the `string` validator. + * + * @function logDest + * + * @param {boolean} strictCheck - Determines if stricter validation should + * be applied. + * + * @returns {z.ZodSchema} A Zod schema object for validating the `logDest` + * option. + */ + logDest(strictCheck) { + return v.string(strictCheck); + }, + + /** + * The `logToConsole` validator that returns a Zod schema with an optional + * stricter check based on the `strictCheck` parameter. + * + * The validation schema ensures the same work as the `boolean` validator. + * + * @function logToConsole + * + * @param {boolean} strictCheck - Determines if stricter validation should + * be applied. + * + * @returns {z.ZodSchema} A Zod schema object for validating + * the `logToConsole` option. + */ + logToConsole(strictCheck) { + return v.boolean(strictCheck); + }, + + /** + * The `logToFile` validator that returns a Zod schema with an optional + * stricter check based on the `strictCheck` parameter. + * + * The validation schema ensures the same work as the `boolean` validator. + * + * @function logToFile + * + * @param {boolean} strictCheck - Determines if stricter validation should + * be applied. + * + * @returns {z.ZodSchema} A Zod schema object for validating the `logToFile` + * option. + */ + logToFile(strictCheck) { + return v.boolean(strictCheck); + }, + + /** + * The `enableUi` validator that returns a Zod schema with an optional + * stricter check based on the `strictCheck` parameter. + * + * The validation schema ensures the same work as the `boolean` validator. + * + * @function enableUi + * + * @param {boolean} strictCheck - Determines if stricter validation should + * be applied. + * + * @returns {z.ZodSchema} A Zod schema object for validating the `enableUi` + * option. + */ + enableUi(strictCheck) { + return v.boolean(strictCheck); + }, + + /** + * The `uiRoute` validator that returns a Zod schema with an optional + * stricter check based on the `strictCheck` parameter. + * + * The validation schema ensures the same work as the `startsWith` validator. + * + * @function uiRoute + * + * @param {boolean} strictCheck - Determines if stricter validation should + * be applied. + * + * @returns {z.ZodSchema} A Zod schema object for validating the `uiRoute` + * option. + */ + uiRoute(strictCheck) { + return v.startsWith(['/'], strictCheck); + }, + + /** + * The `nodeEnv` validator that returns a Zod schema with an optional + * stricter check based on the `strictCheck` parameter. + * + * The validation schema ensures the same work as the `enum` validator. + * + * @function nodeEnv + * + * @param {boolean} strictCheck - Determines if stricter validation should + * be applied. + * + * @returns {z.ZodSchema} A Zod schema object for validating the `nodeEnv` + * option. + */ + nodeEnv(strictCheck) { + return v.enum(['development', 'production', 'test'], strictCheck); + }, + + /** + * The `listenToProcessExits` validator that returns a Zod schema with + * an optional stricter check based on the `strictCheck` parameter. + * + * The validation schema ensures the same work as the `boolean` validator. + * + * @function listenToProcessExits + * + * @param {boolean} strictCheck - Determines if stricter validation should + * be applied. + * + * @returns {z.ZodSchema} A Zod schema object for validating + * the `listenToProcessExits` option. + */ + listenToProcessExits(strictCheck) { + return v.boolean(strictCheck); + }, + + /** + * The `noLogo` validator that returns a Zod schema with an optional + * stricter check based on the `strictCheck` parameter. + * + * The validation schema ensures the same work as the `boolean` validator. + * + * @function noLogo + * + * @param {boolean} strictCheck - Determines if stricter validation should + * be applied. + * + * @returns {z.ZodSchema} A Zod schema object for validating the `noLogo` + * option. + */ + noLogo(strictCheck) { + return v.boolean(strictCheck); + }, + + /** + * The `hardResetPage` validator that returns a Zod schema with an optional + * stricter check based on the `strictCheck` parameter. + * + * The validation schema ensures the same work as the `boolean` validator. + * + * @function hardResetPage + * + * @param {boolean} strictCheck - Determines if stricter validation should + * be applied. + * + * @returns {z.ZodSchema} A Zod schema object for validating + * the `hardResetPage` option. + */ + hardResetPage(strictCheck) { + return v.boolean(strictCheck); + }, + + /** + * The `browserShellMode` validator that returns a Zod schema with an optional + * stricter check based on the `strictCheck` parameter. + * + * The validation schema ensures the same work as the `boolean` validator. + * + * @function browserShellMode + * + * @param {boolean} strictCheck - Determines if stricter validation should + * be applied. + * + * @returns {z.ZodSchema} A Zod schema object for validating + * the `browserShellMode` option. + */ + browserShellMode(strictCheck) { + return v.boolean(strictCheck); + }, + + /** + * The `enableDebug` validator that returns a Zod schema with an optional + * stricter check based on the `strictCheck` parameter. + * + * The validation schema ensures the same work as the `boolean` validator. + * + * @function enableDebug + * + * @param {boolean} strictCheck - Determines if stricter validation should + * be applied. + * + * @returns {z.ZodSchema} A Zod schema object for validating the `enableDebug` + * option. + */ + enableDebug(strictCheck) { + return v.boolean(strictCheck); + }, + + /** + * The `headless` validator that returns a Zod schema with an optional + * stricter check based on the `strictCheck` parameter. + * + * The validation schema ensures the same work as the `boolean` validator. + * + * @function headless + * + * @param {boolean} strictCheck - Determines if stricter validation should + * be applied. + * + * @returns {z.ZodSchema} A Zod schema object for validating the `headless` + * option. + */ + headless(strictCheck) { + return v.boolean(strictCheck); + }, + + /** + * The `devtools` validator that returns a Zod schema with an optional + * stricter check based on the `strictCheck` parameter. + * + * The validation schema ensures the same work as the `boolean` validator. + * + * @function devtools + * + * @param {boolean} strictCheck - Determines if stricter validation should + * be applied. + * + * @returns {z.ZodSchema} A Zod schema object for validating the `devtools` + * option. + */ + devtools(strictCheck) { + return v.boolean(strictCheck); + }, + + /** + * The `listenToConsole` validator that returns a Zod schema with an optional + * stricter check based on the `strictCheck` parameter. + * + * The validation schema ensures the same work as the `boolean` validator. + * + * @function listenToConsole + * + * @param {boolean} strictCheck - Determines if stricter validation should + * be applied. + * + * @returns {z.ZodSchema} A Zod schema object for validating + * the `listenToConsole` option. + */ + listenToConsole(strictCheck) { + return v.boolean(strictCheck); + }, + + /** + * The `dumpio` validator that returns a Zod schema with an optional stricter + * check based on the `strictCheck` parameter. + * + * The validation schema ensures the same work as the `boolean` validator. + * + * @function dumpio + * + * @param {boolean} strictCheck - Determines if stricter validation should + * be applied. + * + * @returns {z.ZodSchema} A Zod schema object for validating the `dumpio` + * option. + */ + dumpio(strictCheck) { + return v.boolean(strictCheck); + }, + + /** + * The `slowMo` validator that returns a Zod schema with an optional stricter + * check based on the `strictCheck` parameter. + * + * The validation schema ensures the same work as the `nonNegativeNum` + * validator. + * + * @function slowMo + * + * @param {boolean} strictCheck - Determines if stricter validation should + * be applied. + * + * @returns {z.ZodSchema} A Zod schema object for validating the `slowMo` + * option. + */ + slowMo(strictCheck) { + return v.nonNegativeNum(strictCheck); + }, + + /** + * The `debuggingPort` validator that returns a Zod schema with an optional + * stricter check based on the `strictCheck` parameter. + * + * The validation schema ensures the same work as the `nonNegativeNum` + * validator. + * + * @function debuggingPort + * + * @param {boolean} strictCheck - Determines if stricter validation should + * be applied. + * + * @returns {z.ZodSchema} A Zod schema object for validating + * the `debuggingPort` option. + */ + debuggingPort(strictCheck) { + return v.nonNegativeNum(strictCheck); + }, + + /** + * The `requestId` validator that returns a Zod schema with an optional + * stricter check based on the `strictCheck` parameter. + * + * The validation schema ensures the same work as the `string` validator. + * Additionally, it must be a stringified UUID or can be null. + * + * @function requestId + * + * @param {boolean} strictCheck - Determines if stricter validation should + * be applied. + * + * @returns {z.ZodSchema} A Zod schema object for validating the `requestId` + * option. + */ + requestId() { + return ( + z + .string() + /// TO DO: Correct + .uuid({ message: 'The value must be a stringified UUID' }) + .nullable() + ); + } +}; + +// Schema for the puppeteer section of options +const PuppeteerSchema = (strictCheck) => + z + .object({ + args: config.args(strictCheck) + }) + .partial(); + +// Schema for the highcharts section of options +const HighchartsSchema = (strictCheck) => + z + .object({ + version: config.version(strictCheck), + cdnUrl: config.cdnUrl(strictCheck), + forceFetch: config.forceFetch(strictCheck), + cachePath: config.cachePath(strictCheck), + coreScripts: config.coreScripts(strictCheck), + moduleScripts: config.moduleScripts(strictCheck), + indicatorScripts: config.indicatorScripts(strictCheck), + customScripts: config.customScripts(strictCheck) + }) + .partial(); + +// Schema for the export section of options +const ExportSchema = (strictCheck) => + z + .object({ + infile: config.infile(strictCheck), + instr: config.instr(), + options: config.options(), + svg: config.svg(), + outfile: config.outfile(strictCheck), + type: config.type(strictCheck), + constr: config.constr(strictCheck), + b64: config.b64(strictCheck), + noDownload: config.noDownload(strictCheck), + defaultHeight: config.defaultHeight(strictCheck), + defaultWidth: config.defaultWidth(strictCheck), + defaultScale: config.defaultScale(strictCheck), + height: config.height(strictCheck), + width: config.width(strictCheck), + scale: config.scale(strictCheck), + globalOptions: config.globalOptions(), + themeOptions: config.themeOptions(), + batch: config.batch(false), + rasterizationTimeout: config.rasterizationTimeout(strictCheck) + }) + .partial(); + +// Schema for the customLogic section of options +const CustomLogicSchema = (strictCheck) => + z + .object({ + allowCodeExecution: config.allowCodeExecution(strictCheck), + allowFileResources: config.allowFileResources(strictCheck), + customCode: config.customCode(false), + callback: config.callback(false), + resources: config.resources(strictCheck), + loadConfig: config.loadConfig(false), + createConfig: config.createConfig(false) + }) + .partial(); + +// Schema for the server.proxy section of options +const ProxySchema = (strictCheck) => + z + .object({ + host: config.proxyHost(false), + port: config.proxyPort(strictCheck), + timeout: config.proxyTimeout(strictCheck) + }) + .partial(); + +// Schema for the server.rateLimiting section of options +const RateLimitingSchema = (strictCheck) => + z + .object({ + enable: config.enableRateLimiting(strictCheck), + maxRequests: config.maxRequests(strictCheck), + window: config.window(strictCheck), + delay: config.delay(strictCheck), + trustProxy: config.trustProxy(strictCheck), + skipKey: config.skipKey(false), + skipToken: config.skipToken(false) + }) + .partial(); + +// Schema for the server.ssl section of options +const SslSchema = (strictCheck) => + z + .object({ + enable: config.enableSsl(strictCheck), + force: config.sslForce(strictCheck), + port: config.sslPort(strictCheck), + certPath: config.sslCertPath(false) + }) + .partial(); + +// Schema for the server section of options +const ServerSchema = (strictCheck) => + z.object({ + enable: config.enableServer(strictCheck).optional(), + host: config.host(strictCheck).optional(), + port: config.port(strictCheck).optional(), + benchmarking: config.serverBenchmarking(strictCheck).optional(), + proxy: ProxySchema(strictCheck).optional(), + rateLimiting: RateLimitingSchema(strictCheck).optional(), + ssl: SslSchema(strictCheck).optional() + }); + +// Schema for the pool section of options +const PoolSchema = (strictCheck) => + z + .object({ + minWorkers: config.minWorkers(strictCheck), + maxWorkers: config.maxWorkers(strictCheck), + workLimit: config.workLimit(strictCheck), + acquireTimeout: config.acquireTimeout(strictCheck), + createTimeout: config.createTimeout(strictCheck), + destroyTimeout: config.destroyTimeout(strictCheck), + idleTimeout: config.idleTimeout(strictCheck), + createRetryInterval: config.createRetryInterval(strictCheck), + reaperInterval: config.reaperInterval(strictCheck), + benchmarking: config.poolBenchmarking(strictCheck) + }) + .partial(); + +// Schema for the logging section of options +const LoggingSchema = (strictCheck) => + z + .object({ + level: config.logLevel(strictCheck), + file: config.logFile(strictCheck), + dest: config.logDest(strictCheck), + toConsole: config.logToConsole(strictCheck), + toFile: config.logToFile(strictCheck) + }) + .partial(); + +// Schema for the ui section of options +const UiSchema = (strictCheck) => + z + .object({ + enable: config.enableUi(strictCheck), + route: config.uiRoute(strictCheck) + }) + .partial(); + +// Schema for the other section of options +const OtherSchema = (strictCheck) => + z + .object({ + nodeEnv: config.nodeEnv(strictCheck), + listenToProcessExits: config.listenToProcessExits(strictCheck), + noLogo: config.noLogo(strictCheck), + hardResetPage: config.hardResetPage(strictCheck), + browserShellMode: config.browserShellMode(strictCheck) + }) + .partial(); + +// Schema for the debug section of options +const DebugSchema = (strictCheck) => + z + .object({ + enable: config.enableDebug(strictCheck), + headless: config.headless(strictCheck), + devtools: config.devtools(strictCheck), + listenToConsole: config.listenToConsole(strictCheck), + dumpio: config.dumpio(strictCheck), + slowMo: config.slowMo(strictCheck), + debuggingPort: config.debuggingPort(strictCheck) + }) + .partial(); + +// Schema for the payload section of options +const PayloadSchema = () => + z + .object({ + requestId: config.requestId() + }) + .partial(); + +// Strict schema for the config +export const StrictConfigSchema = z.object({ + puppeteer: PuppeteerSchema(true), + highcharts: HighchartsSchema(true), + export: ExportSchema(true), + customLogic: CustomLogicSchema(true), + server: ServerSchema(true), + pool: PoolSchema(true), + logging: LoggingSchema(true), + ui: UiSchema(true), + other: OtherSchema(true), + debug: DebugSchema(true), + payload: PayloadSchema() +}); + +// Loose schema for the config +export const LooseConfigSchema = z.object({ + puppeteer: PuppeteerSchema(false), + highcharts: HighchartsSchema(false), + export: ExportSchema(false), + customLogic: CustomLogicSchema(false), + server: ServerSchema(false), + pool: PoolSchema(false), + logging: LoggingSchema(false), + ui: UiSchema(false), + other: OtherSchema(false), + debug: DebugSchema(false), + payload: PayloadSchema() +}); + +// Schema for the environment variables config +export const EnvSchema = z.object({ + // puppeteer + PUPPETEER_ARGS: config.args(false), + + // highcharts + HIGHCHARTS_VERSION: config.version(false), + HIGHCHARTS_CDN_URL: config.cdnUrl(false), + HIGHCHARTS_FORCE_FETCH: config.forceFetch(false), + HIGHCHARTS_CACHE_PATH: config.cachePath(false), + HIGHCHARTS_ADMIN_TOKEN: config.adminToken(false), + HIGHCHARTS_CORE_SCRIPTS: config.coreScripts(false), + HIGHCHARTS_MODULE_SCRIPTS: config.moduleScripts(false), + HIGHCHARTS_INDICATOR_SCRIPTS: config.indicatorScripts(false), + HIGHCHARTS_CUSTOM_SCRIPTS: config.customScripts(false), + + // export + EXPORT_INFILE: config.infile(false), + EXPORT_INSTR: config.instr(), + EXPORT_OPTIONS: config.options(), + EXPORT_SVG: config.svg(), + EXPORT_TYPE: config.type(false), + EXPORT_CONSTR: config.constr(false), + EXPORT_OUTFILE: config.outfile(false), + EXPORT_B64: config.b64(false), + EXPORT_NO_DOWNLOAD: config.noDownload(false), + EXPORT_HEIGHT: config.height(false), + EXPORT_WIDTH: config.width(false), + EXPORT_SCALE: config.scale(false), + EXPORT_DEFAULT_HEIGHT: config.defaultHeight(false), + EXPORT_DEFAULT_WIDTH: config.defaultWidth(false), + EXPORT_DEFAULT_SCALE: config.defaultScale(false), + EXPORT_GLOBAL_OPTIONS: config.globalOptions(), + EXPORT_THEME_OPTIONS: config.themeOptions(), + EXPORT_BATCH: config.batch(false), + EXPORT_RASTERIZATION_TIMEOUT: config.rasterizationTimeout(false), + + // custom + CUSTOM_LOGIC_ALLOW_CODE_EXECUTION: config.allowCodeExecution(false), + CUSTOM_LOGIC_ALLOW_FILE_RESOURCES: config.allowFileResources(false), + CUSTOM_LOGIC_CUSTOM_CODE: config.customCode(false), + CUSTOM_LOGIC_CALLBACK: config.callback(false), + CUSTOM_LOGIC_RESOURCES: config.resources(false), + CUSTOM_LOGIC_LOAD_CONFIG: config.loadConfig(false), + CUSTOM_LOGIC_CREATE_CONFIG: config.createConfig(false), + + // server + SERVER_ENABLE: config.enableServer(false), + SERVER_HOST: config.host(false), + SERVER_PORT: config.port(false), + SERVER_BENCHMARKING: config.serverBenchmarking(false), + + // server proxy + SERVER_PROXY_HOST: config.proxyHost(false), + SERVER_PROXY_PORT: config.proxyPort(false), + SERVER_PROXY_TIMEOUT: config.proxyTimeout(false), + + // server rate limiting + SERVER_RATE_LIMITING_ENABLE: config.enableRateLimiting(false), + SERVER_RATE_LIMITING_MAX_REQUESTS: config.maxRequests(false), + SERVER_RATE_LIMITING_WINDOW: config.window(false), + SERVER_RATE_LIMITING_DELAY: config.delay(false), + SERVER_RATE_LIMITING_TRUST_PROXY: config.trustProxy(false), + SERVER_RATE_LIMITING_SKIP_KEY: config.skipKey(false), + SERVER_RATE_LIMITING_SKIP_TOKEN: config.skipToken(false), + + // server ssl + SERVER_SSL_ENABLE: config.enableSsl(false), + SERVER_SSL_FORCE: config.sslForce(false), + SERVER_SSL_PORT: config.sslPort(false), + SERVER_SSL_CERT_PATH: config.sslCertPath(false), + + // pool + POOL_MIN_WORKERS: config.minWorkers(false), + POOL_MAX_WORKERS: config.maxWorkers(false), + POOL_WORK_LIMIT: config.workLimit(false), + POOL_ACQUIRE_TIMEOUT: config.acquireTimeout(false), + POOL_CREATE_TIMEOUT: config.createTimeout(false), + POOL_DESTROY_TIMEOUT: config.destroyTimeout(false), + POOL_IDLE_TIMEOUT: config.idleTimeout(false), + POOL_CREATE_RETRY_INTERVAL: config.createRetryInterval(false), + POOL_REAPER_INTERVAL: config.reaperInterval(false), + POOL_BENCHMARKING: config.poolBenchmarking(false), + + // logging + LOGGING_LEVEL: config.logLevel(false), + LOGGING_FILE: config.logFile(false), + LOGGING_DEST: config.logDest(false), + LOGGING_TO_CONSOLE: config.logToConsole(false), + LOGGING_TO_FILE: config.logToFile(false), + + // ui + UI_ENABLE: config.enableUi(false), + UI_ROUTE: config.uiRoute(false), + + // other + OTHER_NODE_ENV: config.nodeEnv(false), + OTHER_LISTEN_TO_PROCESS_EXITS: config.listenToProcessExits(false), + OTHER_NO_LOGO: config.noLogo(false), + OTHER_HARD_RESET_PAGE: config.hardResetPage(false), + OTHER_BROWSER_SHELL_MODE: config.browserShellMode(false), + + // debugger + DEBUG_ENABLE: config.enableDebug(false), + DEBUG_HEADLESS: config.headless(false), + DEBUG_DEVTOOLS: config.devtools(false), + DEBUG_LISTEN_TO_CONSOLE: config.listenToConsole(false), + DEBUG_DUMPIO: config.dumpio(false), + DEBUG_SLOW_MO: config.slowMo(false), + DEBUG_DEBUGGING_PORT: config.debuggingPort(false) +}); + +/** + * Validates the environment variables options using the EnvSchema. + * + * @param {Object} process.env - The configuration options from environment + * variables file to validate. + * + * @returns {Object} The parsed and validated environment variables. + */ +export const envs = EnvSchema.partial().parse(process.env); + +/** + * Validates the configuration options using the `StrictConfigSchema`. + * + * @function strictValidate + * + * @param {Object} configOptions - The configuration options to validate. + * + * @returns {Object} The parsed and validated configuration options. + */ +export function strictValidate(configOptions) { + return StrictConfigSchema.partial().parse(configOptions); +} + +/** + * Validates the configuration options using the `LooseConfigSchema`. + * + * @function looseValidate + * + * @param {Object} configOptions - The configuration options to validate. + * + * @returns {Object} The parsed and validated configuration options. + */ +export function looseValidate(configOptions) { + return LooseConfigSchema.partial().parse(configOptions); +} + +/** + * Validates a provided option using the specific validator from the config + * object. + * + * @function validateOption + * + * @param {string} name - The name of an option to validate. + * @param {any} option - The option to validate. + * @param {boolean} strictCheck - Determines if stricter validation should + * be applied. + * + * @returns {any} The parsed and validated option value. + */ +export function validateOption(name, option, strictCheck) { + return config[name](strictCheck).parse(option); +} + +/** + * Custom error mapping function for Zod schema validation. + * + * This function customizes the error messages produced by Zod schema + * validation, providing more specific and user-friendly feedback based on the + * issue type and context. + * + * The function modifies the error messages as follows: + * + * - For missing required values (undefined), it returns a message indicating + * that no value was provided for the specific property. + * + * - For custom validation errors, if a custom error message is provided in the + * issue parameters, it includes this message along with the invalid data + * received. + * + * - For all other errors, it appends property-specific information to the + * default error message provided by Zod. + * + * @function _customErrorMap + * + * @param {z.ZodIssue} issue - The issue object representing the validation + * error. + * @param {Object} context - The context object providing additional information + * about the validation error. + * + * @returns {Object} An object containing the customized error message. + */ +function _customErrorMap(issue, context) { + // Get the chain of properties which error directly refers to + const propertyName = issue.path.join('.'); + + // Create the first part of the message about the property information + const propertyInfo = `Invalid value for the ${propertyName}`; + + // Modified message for the invalid type + if (issue.code === z.ZodIssueCode.invalid_type) { + // Modified message for the required values + if (issue.received === z.ZodParsedType.undefined) { + return { + message: `${propertyInfo} - No value was provided.` + }; + } + + // Modified message for the specific invalid type when values exist + return { + message: `${propertyInfo} - Invalid type. ${context.defaultError}.` + }; + } + + // Modified message for the custom validation + if (issue.code === z.ZodIssueCode.custom) { + // If the custom message for error exist, include it + if (issue.params?.errorMessage) { + return { + message: `${propertyInfo} - ${issue.params?.errorMessage}, received '${context.data}'.` + }; + } + } + + // Modified message for the invalid union error + if (issue.code === z.ZodIssueCode.invalid_union) { + // Create the first part of the message about the multiple errors + let message = `Multiple errors occurred for the ${propertyName}:\n`; + + // Cycle through all errors and create a correct message + issue.unionErrors.forEach((value) => { + const index = value.issues[0].message.indexOf('-'); + message += + index !== -1 + ? `${value.issues[0].message}\n`.substring(index) + : `${value.issues[0].message}\n`; + }); + + // Return the final message for the invalid union error + return { + message + }; + } + + // Return the default error message, extended by the info about the property + return { + message: `${propertyInfo} - ${context.defaultError}.` + }; +} + +export default { + StrictConfigSchema, + LooseConfigSchema, + EnvSchema, + envs, + strictValidate, + looseValidate, + validateOption +}; From 8aa49a73e1c896403a6fc2714b2943ac1d4895f9 Mon Sep 17 00:00:00 2001 From: PaulDalek Date: Tue, 10 Dec 2024 22:18:37 +0100 Subject: [PATCH 02/19] Added a new function to API called logZodIssues to log zod errors appropriately. --- README.md | 6 ++++++ lib/index.js | 2 ++ lib/logger.js | 23 +++++++++++++++++++++++ 3 files changed, 31 insertions(+) diff --git a/README.md b/README.md index 07686bbe..ded6f11a 100644 --- a/README.md +++ b/README.md @@ -802,6 +802,12 @@ This package supports both CommonJS and ES modules. - `@param {Error} error` - The error object. - `@param {string} customMessage` - An optional custom message to be logged along with the error. +- `function logZodIssues(newLevel, issues = [], customMessage)`: Logs an error message about Zod issues with the validation. Optionally, a custom message can be provided. + + - `@param {number} newLevel` - The log level. + - `@param {Error[]} issues` - The array of Zod issues. + - `@param {string} customMessage` - An optional custom message to be logged along with the error. + - `function setLogLevel(newLevel)`: Sets the log level to the specified value. Log levels are (0 = no logging, 1 = error, 2 = warning, 3 = notice, 4 = verbose or 5 = benchmark). - `@param {number} newLevel` - The new log level to be set. diff --git a/lib/index.js b/lib/index.js index 24daefc8..dfa1ee78 100644 --- a/lib/index.js +++ b/lib/index.js @@ -32,6 +32,7 @@ import { getOptions, setOptions } from './config.js'; import { log, logWithStack, + logZodIssues, initLogging, setLogLevel, enableFileLogging @@ -137,6 +138,7 @@ export default { // Logs log, logWithStack, + logZodIssues, setLogLevel, enableFileLogging, diff --git a/lib/logger.js b/lib/logger.js index 82f0be67..7524f0bc 100644 --- a/lib/logger.js +++ b/lib/logger.js @@ -179,6 +179,28 @@ export function logWithStack(newLevel, error, customMessage) { } } +/** + * Logs an error message about Zod issues with the validation. Optionally, + * a custom message can be provided. + * + * @function logZodIssues + * + * @param {number} newLevel - The log level. + * @param {Error[]} issues - The array of Zod issues. + * @param {string} customMessage - An optional custom message to be logged + * along with the error. + */ +export function logZodIssues(newLevel, issues = [], customMessage) { + logWithStack( + newLevel, + null, + [ + `${customMessage} - the following Zod issues occured:`, + ...issues.map((issue) => `- ${issue.message}`) + ].join('\n') + ); +} + /** * Sets the log level to the specified value. Log levels are (0 = no logging, * 1 = error, 2 = warning, 3 = notice, 4 = verbose or 5 = benchmark). @@ -251,6 +273,7 @@ export default { initLogging, log, logWithStack, + logZodIssues, setLogLevel, enableFileLogging }; From 935486e2d37ad69014a5394ec3f53af490bb46b4 Mon Sep 17 00:00:00 2001 From: PaulDalek Date: Tue, 10 Dec 2024 22:19:01 +0100 Subject: [PATCH 03/19] Validate options. --- lib/chart.js | 26 +++++++++- lib/config.js | 34 ++++++++++--- lib/errors/ValidationError.js | 33 ++++++++++++ lib/server/middlewares/validation.js | 75 +++++++++++++++------------- 4 files changed, 126 insertions(+), 42 deletions(-) create mode 100644 lib/errors/ValidationError.js diff --git a/lib/chart.js b/lib/chart.js index 8c1bfe61..6365e4bc 100644 --- a/lib/chart.js +++ b/lib/chart.js @@ -22,7 +22,7 @@ See LICENSE file in root for details. import { readFileSync, writeFileSync } from 'fs'; import { getOptions } from './config.js'; -import { log, logWithStack } from './logger.js'; +import { log, logWithStack, logZodIssues } from './logger.js'; import { killPool, postWork, getPoolStats } from './pool.js'; import { sanitize } from './sanitize.js'; import { @@ -32,6 +32,7 @@ import { roundNumber, wrapAround } from './utils.js'; +import { strictValidate, validateOption } from './validation.js'; import ExportError from './errors/ExportError.js'; @@ -98,7 +99,20 @@ export async function startExport(options = getOptions(), endCallback) { log(4, '[chart] Attempting to export from a file input.'); // Try to read the file to get the string representation - exportOptions.instr = readFileSync(exportOptions.infile, 'utf8'); + try { + exportOptions.instr = validateOption( + 'instr', + readFileSync(exportOptions.infile, 'utf8'), + false + ); + } catch (error) { + logZodIssues( + 1, + error.issues, + '[config] The `infile` option validation error' + ); + throw error; + } // Export from a file options return _exportAsString(exportOptions.instr, options, endCallback); @@ -457,6 +471,14 @@ async function _prepareExport(options, endCallback, json, svg) { ..._findChartSize(exportOptions) }; + // The last strict validation of options right before exporting process + try { + // Validate final options + options = strictValidate(options); + } catch (error) { + logZodIssues(1, error.issues, '[config] Final options validation error'); + } + // Post the work to the pool try { const result = await postWork(exportOptions.strInj || json || svg, options); diff --git a/lib/config.js b/lib/config.js index 27c4ebd0..66e30a3b 100644 --- a/lib/config.js +++ b/lib/config.js @@ -22,9 +22,9 @@ See LICENSE file in root for details. import { readFileSync } from 'fs'; -import { log, logWithStack } from './logger.js'; -import { envs } from './envs.js'; +import { log, logWithStack, logZodIssues } from './logger.js'; import { deepCopy } from './utils.js'; +import { envs, looseValidate, strictValidate } from './validation.js'; import { defaultConfig, nestedArgs } from './schemas/config.js'; // Sets the global options with initial values from the default config @@ -77,14 +77,36 @@ export function setOptions( // Only for the CLI usage if (cliArgs.length) { - // Get options from the custom JSON loaded via the `loadConfig` - configOptions = _loadConfigFile(cliArgs); + try { + // Validate options from the custom JSON loaded via the `loadConfig` + configOptions = strictValidate(_loadConfigFile(cliArgs)); + } catch (error) { + logZodIssues( + 1, + error.issues, + '[config] Custom JSON options validation error' + ); + } + } + + // Apply custom options if there are any + if (customOptions && Object.keys(customOptions).length !== 0) { + try { + // Validate custom options provided by the user + customOptions = strictValidate(customOptions); + } catch (error) { + logZodIssues(1, error.issues, '[config] Custom options validation error'); + } } // Only for the CLI usage if (cliArgs.length) { - // Get options from the CLI - cliOptions = _pairArgumentValue(nestedArgs, cliArgs); + try { + // Validate options from the CLI + cliOptions = looseValidate(_pairArgumentValue(nestedArgs, cliArgs)); + } catch (error) { + logZodIssues(1, error.issues, '[config] CLI options validation error'); + } } // Get the reference to the global options object or a copy of the object diff --git a/lib/errors/ValidationError.js b/lib/errors/ValidationError.js new file mode 100644 index 00000000..7418a4f3 --- /dev/null +++ b/lib/errors/ValidationError.js @@ -0,0 +1,33 @@ +/******************************************************************************* + +Highcharts Export Server + +Copyright (c) 2016-2024, Highsoft + +Licenced under the MIT licence. + +Additionally a valid Highcharts license is required for use. + +See LICENSE file in root for details. + +*******************************************************************************/ + +import HttpError from './HttpError.js'; + +/** + * The `ValidationError` error class that extends `HttpError`. Used to handle + * errors related to validation of provided options. + */ +class ValidationError extends HttpError { + /** + * Creates an instance of `ValidationError`. + */ + constructor() { + super( + 'The provided options are not correct. Please check if your data is of the correct types.', + 400 + ); + } +} + +export default ValidationError; diff --git a/lib/server/middlewares/validation.js b/lib/server/middlewares/validation.js index 04dce82e..82aae968 100644 --- a/lib/server/middlewares/validation.js +++ b/lib/server/middlewares/validation.js @@ -26,7 +26,7 @@ See LICENSE file in root for details. import { v4 as uuid } from 'uuid'; import { getAllowCodeExecution } from '../../chart.js'; -import { log } from '../../logger.js'; +import { log, logZodIssues } from '../../logger.js'; import { fixConstr, fixType, @@ -34,11 +34,13 @@ import { isObjectEmpty, isPrivateRangeUrlFound } from '../../utils.js'; +import { looseValidate } from '../../validation.js'; import HttpError from '../../errors/HttpError.js'; import NoCorrectBodyError from '../../errors/NoCorrectBodyError.js'; import NoCorrectChartDataError from '../../errors/NoCorrectChartDataError.js'; import PrivateRangeUrlError from '../../errors/PrivateRangeUrlError.js'; +import ValidationError from '../../errors/ValidationError.js'; /** * Middleware for validating the content-type header. @@ -135,39 +137,44 @@ function requestBodyMiddleware(request, _response, next) { throw PrivateRangeUrlError(); } - // Get options from the body and store parsed structure in the request - request.validatedOptions = { - export: { - instr, - svg: body.svg, - outfile: - body.outfile || - `${request.params.filename || 'chart'}.${fixType(body.type)}`, - type: fixType(body.type), - constr: fixConstr(body.constr), - b64: body.b64, - noDownload: body.noDownload, - height: body.height, - width: body.width, - scale: body.scale, - globalOptions: isCorrectJSON( - body.globalOptions, - true, - allowCodeExecution - ), - themeOptions: isCorrectJSON(body.themeOptions, true, allowCodeExecution) - }, - customLogic: { - allowCodeExecution, - allowFileResources: false, - customCode: body.customCode, - callback: body.callback, - resources: isCorrectJSON(body.resources, true, allowCodeExecution) - }, - payload: { - requestId - } - }; + try { + // Validate options from the body and store parsed structure in the request + request.validatedOptions = looseValidate({ + export: { + instr, + svg: body.svg, + outfile: + body.outfile || + `${request.params.filename || 'chart'}.${fixType(body.type)}`, + type: fixType(body.type), + constr: fixConstr(body.constr), + b64: body.b64, + noDownload: body.noDownload, + height: body.height, + width: body.width, + scale: body.scale, + globalOptions: isCorrectJSON( + body.globalOptions, + true, + allowCodeExecution + ), + themeOptions: isCorrectJSON(body.themeOptions, true, allowCodeExecution) + }, + customLogic: { + allowCodeExecution, + allowFileResources: false, + customCode: body.customCode, + callback: body.callback, + resources: isCorrectJSON(body.resources, true, allowCodeExecution) + }, + payload: { + requestId + } + }); + } catch (error) { + logZodIssues(1, error.issues, '[config] Request options validation error'); + throw new ValidationError(); + } return next(); } From 4192bae6c78fc2d0f2b43f501df453bbe6eeaceb Mon Sep 17 00:00:00 2001 From: PaulDalek Date: Tue, 10 Dec 2024 22:19:16 +0100 Subject: [PATCH 04/19] Added exhaustive testing of options validations. --- tests/unit/envs.test.js | 76 - tests/unit/validation/cli.test.js | 667 +++++++ tests/unit/validation/config.test.js | 678 +++++++ tests/unit/validation/envs.test.js | 341 ++++ tests/unit/validation/shared.js | 2565 ++++++++++++++++++++++++++ tests/utils/testUtils.js | 129 ++ 6 files changed, 4380 insertions(+), 76 deletions(-) delete mode 100644 tests/unit/envs.test.js create mode 100644 tests/unit/validation/cli.test.js create mode 100644 tests/unit/validation/config.test.js create mode 100644 tests/unit/validation/envs.test.js create mode 100644 tests/unit/validation/shared.js create mode 100644 tests/utils/testUtils.js diff --git a/tests/unit/envs.test.js b/tests/unit/envs.test.js deleted file mode 100644 index bf13f9a8..00000000 --- a/tests/unit/envs.test.js +++ /dev/null @@ -1,76 +0,0 @@ -/******************************************************************************* - -Highcharts Export Server - -Copyright (c) 2016-2024, Highsoft - -Licenced under the MIT licence. - -Additionally a valid Highcharts license is required for use. - -See LICENSE file in root for details. - -*******************************************************************************/ - -import { Config } from '../../lib/envs.js'; - -describe('Environment variables should be correctly parsed', () => { - test('HIGHCHARTS_VERSION accepts latests and not unrelated strings', () => { - const env = { HIGHCHARTS_VERSION: 'string-other-than-latest' }; - expect(() => Config.partial().parse(env)).toThrow(); - - env.HIGHCHARTS_VERSION = 'latest'; - expect(Config.partial().parse(env).HIGHCHARTS_VERSION).toEqual('latest'); - }); - - test('HIGHCHARTS_VERSION accepts proper version strings like XX.YY.ZZ', () => { - const env = { HIGHCHARTS_VERSION: '11' }; - expect(Config.partial().parse(env).HIGHCHARTS_VERSION).toEqual('11'); - - env.HIGHCHARTS_VERSION = '11.0.0'; - expect(Config.partial().parse(env).HIGHCHARTS_VERSION).toEqual('11.0.0'); - - env.HIGHCHARTS_VERSION = '9.1'; - expect(Config.partial().parse(env).HIGHCHARTS_VERSION).toEqual('9.1'); - - env.HIGHCHARTS_VERSION = '11a.2.0'; - expect(() => Config.partial().parse(env)).toThrow(); - }); - - test('HIGHCHARTS_CDN_URL should start with http:// or https://', () => { - const env = { HIGHCHARTS_CDN_URL: 'http://example.com' }; - expect(Config.partial().parse(env).HIGHCHARTS_CDN_URL).toEqual( - 'http://example.com' - ); - - env.HIGHCHARTS_CDN_URL = 'https://example.com'; - expect(Config.partial().parse(env).HIGHCHARTS_CDN_URL).toEqual( - 'https://example.com' - ); - - env.HIGHCHARTS_CDN_URL = 'example.com'; - expect(() => Config.partial().parse(env)).toThrow(); - }); - - test('CORE, MODULE, INDICATOR scripts should be arrays', () => { - const env = { - HIGHCHARTS_CORE_SCRIPTS: 'core1, core2, highcharts', - HIGHCHARTS_MODULE_SCRIPTS: 'module1, map, module2', - HIGHCHARTS_INDICATOR_SCRIPTS: 'indicators-all, indicator1, indicator2' - }; - - const parsed = Config.partial().parse(env); - - expect(parsed.HIGHCHARTS_CORE_SCRIPTS).toEqual(['highcharts']); - expect(parsed.HIGHCHARTS_MODULE_SCRIPTS).toEqual(['map']); - expect(parsed.HIGHCHARTS_INDICATOR_SCRIPTS).toEqual(['indicators-all']); - }); - - test('HIGHCHARTS_FORCE_FETCH should be a boolean', () => { - const env = { HIGHCHARTS_FORCE_FETCH: 'true' }; - expect(Config.partial().parse(env).HIGHCHARTS_FORCE_FETCH).toEqual(true); - - env.HIGHCHARTS_FORCE_FETCH = 'false'; - expect(Config.partial().parse(env).HIGHCHARTS_FORCE_FETCH).toEqual(false); - }); -}); diff --git a/tests/unit/validation/cli.test.js b/tests/unit/validation/cli.test.js new file mode 100644 index 00000000..df90c4ff --- /dev/null +++ b/tests/unit/validation/cli.test.js @@ -0,0 +1,667 @@ +/******************************************************************************* + +Highcharts Export Server + +Copyright (c) 2016-2024, Highsoft + +Licenced under the MIT licence. + +Additionally a valid Highcharts license is required for use. + +See LICENSE file in root for details. + +*******************************************************************************/ + +import { describe } from '@jest/globals'; + +import { configTests } from './shared.js'; +import { LooseConfigSchema } from '../../../lib/validation.js'; + +describe('CLI options should be correctly parsed and validated', () => { + // Return config tests with a specific schema and strictCheck flag injected + const tests = configTests(LooseConfigSchema.partial(), false); + + // puppeteer + tests.puppeteer('puppeteer', { + args: [ + '--allow-running-insecure-content', + '--ash-no-nudges', + '--autoplay-policy=user-gesture-required', + '--block-new-web-contents', + '--disable-accelerated-2d-canvas', + '--disable-background-networking', + '--disable-background-timer-throttling', + '--disable-backgrounding-occluded-windows', + '--disable-breakpad', + '--disable-checker-imaging', + '--disable-client-side-phishing-detection', + '--disable-component-extensions-with-background-pages', + '--disable-component-update', + '--disable-default-apps', + '--disable-dev-shm-usage', + '--disable-domain-reliability', + '--disable-extensions', + '--disable-features=CalculateNativeWinOcclusion,InterestFeedContentSuggestions,WebOTP', + '--disable-hang-monitor', + '--disable-ipc-flooding-protection', + '--disable-logging', + '--disable-notifications', + '--disable-offer-store-unmasked-wallet-cards', + '--disable-popup-blocking', + '--disable-print-preview', + '--disable-prompt-on-repost', + '--disable-renderer-backgrounding', + '--disable-search-engine-choice-screen', + '--disable-session-crashed-bubble', + '--disable-setuid-sandbox', + '--disable-site-isolation-trials', + '--disable-speech-api', + '--disable-sync', + '--enable-unsafe-webgpu', + '--hide-crash-restore-bubble', + '--hide-scrollbars', + '--metrics-recording-only', + '--mute-audio', + '--no-default-browser-check', + '--no-first-run', + '--no-pings', + '--no-sandbox', + '--no-startup-window', + '--no-zygote', + '--password-store=basic', + '--process-per-tab', + '--use-mock-keychain' + ] + }); + + // highcharts + tests.highcharts('highcharts', { + version: 'latest', + cdnUrl: 'https://code.highcharts.com', + forceFetch: false, + cachePath: '.cache', + coreScripts: ['highcharts', 'highcharts-more', 'highcharts-3d'], + moduleScripts: [ + 'stock', + 'map', + 'gantt', + 'exporting', + 'parallel-coordinates', + 'accessibility', + // 'annotations-advanced', + 'boost-canvas', + 'boost', + 'data', + 'data-tools', + 'draggable-points', + 'static-scale', + 'broken-axis', + 'heatmap', + 'tilemap', + 'tiledwebmap', + 'timeline', + 'treemap', + 'treegraph', + 'item-series', + 'drilldown', + 'histogram-bellcurve', + 'bullet', + 'funnel', + 'funnel3d', + 'geoheatmap', + 'pyramid3d', + 'networkgraph', + 'overlapping-datalabels', + 'pareto', + 'pattern-fill', + 'pictorial', + 'price-indicator', + 'sankey', + 'arc-diagram', + 'dependency-wheel', + 'series-label', + 'series-on-point', + 'solid-gauge', + 'sonification', + // 'stock-tools', + 'streamgraph', + 'sunburst', + 'variable-pie', + 'variwide', + 'vector', + 'venn', + 'windbarb', + 'wordcloud', + 'xrange', + 'no-data-to-display', + 'drag-panes', + 'debugger', + 'dumbbell', + 'lollipop', + 'cylinder', + 'organization', + 'dotplot', + 'marker-clusters', + 'hollowcandlestick', + 'heikinashi', + 'flowmap', + 'export-data', + 'navigator', + 'textpath' + ], + indicatorScripts: ['indicators-all'], + customScripts: [ + 'https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.30.1/moment.min.js', + 'https://cdnjs.cloudflare.com/ajax/libs/moment-timezone/0.5.45/moment-timezone-with-data.min.js' + ] + }); + + // export + tests.export('export', { + infile: null, + instr: null, + options: null, + svg: null, + outfile: null, + type: 'png', + constr: 'chart', + b64: false, + noDownload: false, + defaultHeight: 400, + defaultWidth: 600, + defaultScale: 1, + height: null, + width: null, + scale: null, + globalOptions: null, + themeOptions: null, + batch: null, + rasterizationTimeout: 1500 + }); + + // customLogic + tests.customLogic('customLogic', { + allowCodeExecution: false, + allowFileResources: false, + customCode: null, + callback: null, + resources: null, + loadConfig: null, + createConfig: null + }); + + // server + tests.server('server', { + enable: false, + host: '0.0.0.0', + port: 7801, + benchmarking: false, + proxy: { + host: null, + port: null, + timeout: 5000 + }, + rateLimiting: { + enable: false, + maxRequests: 10, + window: 1, + delay: 0, + trustProxy: false, + skipKey: null, + skipToken: null + }, + ssl: { + enable: false, + force: false, + port: 443, + certPath: null + } + }); + + // pool + tests.pool('pool', { + minWorkers: 4, + maxWorkers: 8, + workLimit: 40, + acquireTimeout: 5000, + createTimeout: 5000, + destroyTimeout: 5000, + idleTimeout: 30000, + createRetryInterval: 200, + reaperInterval: 1000, + benchmarking: false + }); + + // logging + tests.logging('logging', { + level: 4, + file: 'highcharts-export-server.log', + dest: 'log', + toConsole: true, + toFile: true + }); + + // ui + tests.ui('ui', { + enable: false, + route: '/' + }); + + // other + tests.other('other', { + nodeEnv: 'production', + listenToProcessExits: true, + noLogo: false, + hardResetPage: false, + browserShellMode: true + }); + + // debug + tests.debug('debug', { + enable: false, + headless: true, + devtools: false, + listenToConsole: false, + dumpio: false, + slowMo: 0, + debuggingPort: 9222 + }); + + // payload + tests.payload('payload', { + requestId: 'd4faa416-0e85-433a-9f84-e735567d8fa5' + }); +}); + +describe('Puppeteer configuration options should be correctly parsed and validated', () => { + // Return config tests with a specific schema and strictCheck flag injected + const tests = configTests(LooseConfigSchema.shape.puppeteer, false); + + // puppeteer.args + tests.puppeteerArgs( + 'args', + '--disable-sync; --enable-unsafe-webgpu; --hide-crash-restore-bubble; --hide-scrollbars; --metrics-recording-only', + [ + '--disable-sync', + '--enable-unsafe-webgpu', + '--hide-crash-restore-bubble', + '--hide-scrollbars', + '--metrics-recording-only' + ] + ); +}); + +describe('Highcharts configuration options should be correctly parsed and validated', () => { + // Return config tests with a specific schema and strictCheck flag injected + const tests = configTests(LooseConfigSchema.shape.highcharts, false); + + // highcharts.version + tests.highchartsVersion('version'); + + // highcharts.cdnUrl + tests.highchartsCdnUrl( + 'cdnUrl', + ['http://example.com', 'https://example.com'], + ['http:a.com', 'http:/b.com', 'https:c.com', 'https:/d.com'] + ); + + // highcharts.forceFetch + tests.highchartsForceFetch('forceFetch'); + + // highcharts.cachePath + tests.highchartsCachePath('cachePath'); + + // highcharts.coreScripts + tests.highchartsCoreScripts( + 'coreScripts', + 'highcharts, highcharts-more, text1, highcharts-3d, text2', + ['highcharts', 'highcharts-more', 'highcharts-3d'] + ); + + // highcharts.moduleScripts + tests.highchartsModuleScripts( + 'moduleScripts', + 'data, text1, data-tools, text2', + ['data', 'data-tools'] + ); + + // highcharts.indicatorScripts + tests.highchartsIndicatorScripts( + 'indicatorScripts', + 'text1, indicators-all, text2', + ['indicators-all'] + ); + + // highcharts.customScripts + tests.highchartsCustomScripts( + 'customScripts', + 'https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.30.1/moment.min.js, text1, https://cdnjs.cloudflare.com/ajax/libs/moment-timezone/0.5.45/moment-timezone-with-data.min.js, text2', + [ + 'https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.30.1/moment.min.js', + 'https://cdnjs.cloudflare.com/ajax/libs/moment-timezone/0.5.45/moment-timezone-with-data.min.js' + ] + ); +}); + +describe('Export configuration options should be correctly parsed and validated', () => { + // Return config tests with a specific schema and strictCheck flag injected + const tests = configTests(LooseConfigSchema.shape.export, false); + + // export.infile + tests.exportInfile('infile'); + + // export.instr + tests.exportInstr('instr'); + + // export.options + tests.exportOptions('options'); + + // export.svg + tests.exportSvg('svg'); + + // export.outfile + tests.exportOutfile('outfile'); + + // export.type + tests.exportType( + 'type', + ['jpeg', 'jpg', 'png', 'pdf', 'svg'], + ['json', 'txt'] + ); + + // export.constr + tests.exportConstr( + 'constr', + ['chart', 'stockChart', 'mapChart', 'ganttChart'], + ['stock', 'map', 'gantt'] + ); + + // export.b64 + tests.exportB64('b64'); + + // export.noDownload + tests.exportNoDownload('noDownload'); + + // export.defaultHeight + tests.exportDefaultHeight('defaultHeight'); + + // export.defaultWidth + tests.exportDefaultWidth('defaultWidth'); + + // export.defaultScale + tests.exportDefaultScale('defaultScale'); + + // export.height + tests.exportHeight('height'); + + // export.width + tests.exportWidth('width'); + + // export.scale + tests.exportScale('scale'); + + // export.globalOptions + tests.exportGlobalOptions('globalOptions'); + + // export.themeOptions + tests.exportThemeOptions('themeOptions'); + + // export.batch + tests.exportBatch('batch'); + + // export.rasterizationTimeout + tests.exportRasterizationTimeout('rasterizationTimeout'); +}); + +describe('Custom Logic configuration options should be correctly parsed and validated', () => { + // Return config tests with a specific schema and strictCheck flag injected + const tests = configTests(LooseConfigSchema.shape.customLogic, false); + + // customLogic.allowCodeExecution + tests.customLogicAllowCodeExecution('allowCodeExecution'); + + // customLogic.allowFileResources + tests.customLogicAllowFileResources('allowFileResources'); + + // customLogic.customCode + tests.customLogicCustomCode('customCode'); + + // customLogic.callback + tests.customLogicCallback('callback'); + + // customLogic.resources + tests.customLogicResources('resources'); + + // customLogic.loadConfig + tests.customLogicLoadConfig('loadConfig'); + + // customLogic.createConfig + tests.customLogicCreateConfig('createConfig'); +}); + +describe('Server configuration options should be correctly parsed and validated', () => { + // Return config tests with a specific schema and strictCheck flag injected + const tests = configTests(LooseConfigSchema.shape.server, false); + + // server.enable + tests.serverEnable('enable'); + + // server.host + tests.serverHost('host'); + + // server.port + tests.serverPort('port'); + + // server.benchmarking + tests.serverBenchmarking('benchmarking'); + + // server.proxy + tests.serverProxy('proxy', { + host: null, + port: null, + timeout: 5000 + }); + + // server.rateLimiting + tests.serverRateLimiting('rateLimiting', { + enable: false, + maxRequests: 10, + window: 1, + delay: 0, + trustProxy: false, + skipKey: null, + skipToken: null + }); + + // server.ssl + tests.serverSsl('ssl', { + enable: false, + force: false, + port: 443, + certPath: null + }); +}); + +describe('Server Proxy configuration options should be correctly parsed and validated', () => { + // Return config tests with a specific schema and strictCheck flag injected + const tests = configTests(LooseConfigSchema.shape.server.shape.proxy, false); + + // server.proxy.host + tests.serverProxyHost('host'); + + // server.proxy.port + tests.serverProxyPort('port'); + + // server.proxy.timeout + tests.serverProxyTimeout('timeout'); +}); + +describe('Server Rate Limiting configuration options should be correctly parsed and validated', () => { + // Return config tests with a specific schema and strictCheck flag injected + const tests = configTests( + LooseConfigSchema.shape.server.shape.rateLimiting, + false + ); + + // server.rateLimiting.enable + tests.serverRateLimitingEnable('enable'); + + // server.rateLimiting.maxRequests + tests.serverRateLimitingMaxRequests('maxRequests'); + + // server.rateLimiting.window + tests.serverRateLimitingWindow('window'); + + // server.rateLimiting.delay + tests.serverRateLimitingDelay('delay'); + + // server.rateLimiting.trustProxy + tests.serverRateLimitingTrustProxy('trustProxy'); + + // server.rateLimiting.skipKey + tests.serverRateLimitingSkipKey('skipKey'); + + // server.rateLimiting.skipToken + tests.serverRateLimitingSkipToken('skipToken'); +}); + +describe('Server SSL configuration options should be correctly parsed and validated', () => { + // Return config tests with a specific schema and strictCheck flag injected + const tests = configTests(LooseConfigSchema.shape.server.shape.ssl, false); + + // server.ssl.enable + tests.serverSslEnable('enable'); + + // server.ssl.force + tests.serverSslForce('force'); + + // server.ssl.port + tests.serverSslPort('port'); + + // server.ssl.certPath + tests.serverSslCertPath('certPath'); +}); + +describe('Pool configuration options should be correctly parsed and validated', () => { + // Return config tests with a specific schema and strictCheck flag injected + const tests = configTests(LooseConfigSchema.shape.pool, false); + + // pool.minWorkers + tests.poolMinWorkers('minWorkers'); + + // pool.maxWorkers + tests.poolMaxWorkers('maxWorkers'); + + // pool.workLimit + tests.poolWorkLimit('workLimit'); + + // pool.acquireTimeout + tests.poolAcquireTimeout('acquireTimeout'); + + // pool.createTimeout + tests.poolCreateTimeout('createTimeout'); + + // pool.destroyTimeout + tests.poolDestroyTimeout('destroyTimeout'); + + // pool.idleTimeout + tests.poolIdleTimeout('idleTimeout'); + + // pool.createRetryInterval + tests.poolCreateRetryInterval('createRetryInterval'); + + // pool.reaperInterval + tests.poolReaperInterval('reaperInterval'); + + // pool.benchmarking + tests.poolBenchmarking('benchmarking'); +}); + +describe('Logging configuration options should be correctly parsed and validated', () => { + // Return config tests with a specific schema and strictCheck flag injected + const tests = configTests(LooseConfigSchema.shape.logging, false); + + // logging.level + tests.loggingLevel('level'); + + // logging.file + tests.loggingFile('file'); + + // logging.dest + tests.loggingDest('dest'); + + // logging.toConsole + tests.loggingToConsole('toConsole'); + + // logging.toFile + tests.loggingToFile('toFile'); +}); + +describe('UI configuration options should be correctly parsed and validated', () => { + // Return config tests with a specific schema and strictCheck flag injected + const tests = configTests(LooseConfigSchema.shape.ui, false); + + // ui.enable + tests.uiEnable('enable'); + + // ui.route + tests.uiRoute('route', ['/', '/ui'], ['ui', 'example/ui/']); +}); + +describe('Other configuration options should be correctly parsed and validated', () => { + // Return config tests with a specific schema and strictCheck flag injected + const tests = configTests(LooseConfigSchema.shape.other, false); + + // other.nodeEnv + tests.otherNodeEnv( + 'nodeEnv', + ['development', 'production', 'test'], + ['dev-env', 'prod-env', 'test-env'] + ); + + // other.listenToProcessExits + tests.otherListenToProcessExits('listenToProcessExits'); + + // other.noLogo + tests.otherNoLogo('noLogo'); + + // other.hardResetPage + tests.otherHardResetPage('hardResetPage'); + + // other.browserShellMode + tests.otherBrowserShellMode('browserShellMode'); +}); + +describe('Debug configuration options should be correctly parsed and validated', () => { + // Return config tests with a specific schema and strictCheck flag injected + const tests = configTests(LooseConfigSchema.shape.debug, false); + + // debug.enable + tests.debugEnable('enable'); + + // debug.headless + tests.debugHeadless('headless'); + + // debug.devtools + tests.debugDevtools('devtools'); + + // debug.listenToConsole + tests.debugListenToConsole('listenToConsole'); + + // debug.dumpio + tests.debugDumpio('dumpio'); + + // debug.slowMo + tests.debugSlowMo('slowMo'); + + // debug.debuggingPort + tests.debugDebuggingPort('debuggingPort'); +}); + +describe('Payload configuration options should be correctly parsed and validated', () => { + // Return config tests with a specific schema and strictCheck flag injected + const tests = configTests(LooseConfigSchema.shape.payload, false); + + // payload.requestId + tests.payloadRequestId('requestId'); +}); diff --git a/tests/unit/validation/config.test.js b/tests/unit/validation/config.test.js new file mode 100644 index 00000000..72890cd5 --- /dev/null +++ b/tests/unit/validation/config.test.js @@ -0,0 +1,678 @@ +/******************************************************************************* + +Highcharts Export Server + +Copyright (c) 2016-2024, Highsoft + +Licenced under the MIT licence. + +Additionally a valid Highcharts license is required for use. + +See LICENSE file in root for details. + +*******************************************************************************/ + +import { describe } from '@jest/globals'; + +import { configTests } from './shared.js'; +import { StrictConfigSchema } from '../../../lib/validation.js'; + +describe('Configuration options should be correctly parsed and validated', () => { + // Return config tests with a specific schema and strictCheck flag injected + const tests = configTests(StrictConfigSchema.partial(), true); + + // puppeteer + tests.puppeteer('puppeteer', { + args: [ + '--allow-running-insecure-content', + '--ash-no-nudges', + '--autoplay-policy=user-gesture-required', + '--block-new-web-contents', + '--disable-accelerated-2d-canvas', + '--disable-background-networking', + '--disable-background-timer-throttling', + '--disable-backgrounding-occluded-windows', + '--disable-breakpad', + '--disable-checker-imaging', + '--disable-client-side-phishing-detection', + '--disable-component-extensions-with-background-pages', + '--disable-component-update', + '--disable-default-apps', + '--disable-dev-shm-usage', + '--disable-domain-reliability', + '--disable-extensions', + '--disable-features=CalculateNativeWinOcclusion,InterestFeedContentSuggestions,WebOTP', + '--disable-hang-monitor', + '--disable-ipc-flooding-protection', + '--disable-logging', + '--disable-notifications', + '--disable-offer-store-unmasked-wallet-cards', + '--disable-popup-blocking', + '--disable-print-preview', + '--disable-prompt-on-repost', + '--disable-renderer-backgrounding', + '--disable-search-engine-choice-screen', + '--disable-session-crashed-bubble', + '--disable-setuid-sandbox', + '--disable-site-isolation-trials', + '--disable-speech-api', + '--disable-sync', + '--enable-unsafe-webgpu', + '--hide-crash-restore-bubble', + '--hide-scrollbars', + '--metrics-recording-only', + '--mute-audio', + '--no-default-browser-check', + '--no-first-run', + '--no-pings', + '--no-sandbox', + '--no-startup-window', + '--no-zygote', + '--password-store=basic', + '--process-per-tab', + '--use-mock-keychain' + ] + }); + + // highcharts + tests.highcharts('highcharts', { + version: 'latest', + cdnUrl: 'https://code.highcharts.com', + forceFetch: false, + cachePath: '.cache', + coreScripts: ['highcharts', 'highcharts-more', 'highcharts-3d'], + moduleScripts: [ + 'stock', + 'map', + 'gantt', + 'exporting', + 'parallel-coordinates', + 'accessibility', + // 'annotations-advanced', + 'boost-canvas', + 'boost', + 'data', + 'data-tools', + 'draggable-points', + 'static-scale', + 'broken-axis', + 'heatmap', + 'tilemap', + 'tiledwebmap', + 'timeline', + 'treemap', + 'treegraph', + 'item-series', + 'drilldown', + 'histogram-bellcurve', + 'bullet', + 'funnel', + 'funnel3d', + 'geoheatmap', + 'pyramid3d', + 'networkgraph', + 'overlapping-datalabels', + 'pareto', + 'pattern-fill', + 'pictorial', + 'price-indicator', + 'sankey', + 'arc-diagram', + 'dependency-wheel', + 'series-label', + 'series-on-point', + 'solid-gauge', + 'sonification', + // 'stock-tools', + 'streamgraph', + 'sunburst', + 'variable-pie', + 'variwide', + 'vector', + 'venn', + 'windbarb', + 'wordcloud', + 'xrange', + 'no-data-to-display', + 'drag-panes', + 'debugger', + 'dumbbell', + 'lollipop', + 'cylinder', + 'organization', + 'dotplot', + 'marker-clusters', + 'hollowcandlestick', + 'heikinashi', + 'flowmap', + 'export-data', + 'navigator', + 'textpath' + ], + indicatorScripts: ['indicators-all'], + customScripts: [ + 'https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.30.1/moment.min.js', + 'https://cdnjs.cloudflare.com/ajax/libs/moment-timezone/0.5.45/moment-timezone-with-data.min.js' + ] + }); + + // export + tests.export('export', { + infile: null, + instr: null, + options: null, + svg: null, + outfile: null, + type: 'png', + constr: 'chart', + b64: false, + noDownload: false, + defaultHeight: 400, + defaultWidth: 600, + defaultScale: 1, + height: null, + width: null, + scale: null, + globalOptions: null, + themeOptions: null, + batch: null, + rasterizationTimeout: 1500 + }); + + // customLogic + tests.customLogic('customLogic', { + allowCodeExecution: false, + allowFileResources: false, + customCode: null, + callback: null, + resources: null, + loadConfig: null, + createConfig: null + }); + + // server + tests.server('server', { + enable: false, + host: '0.0.0.0', + port: 7801, + benchmarking: false, + proxy: { + host: null, + port: null, + timeout: 5000 + }, + rateLimiting: { + enable: false, + maxRequests: 10, + window: 1, + delay: 0, + trustProxy: false, + skipKey: null, + skipToken: null + }, + ssl: { + enable: false, + force: false, + port: 443, + certPath: null + } + }); + + // pool + tests.pool('pool', { + minWorkers: 4, + maxWorkers: 8, + workLimit: 40, + acquireTimeout: 5000, + createTimeout: 5000, + destroyTimeout: 5000, + idleTimeout: 30000, + createRetryInterval: 200, + reaperInterval: 1000, + benchmarking: false + }); + + // logging + tests.logging('logging', { + level: 4, + file: 'highcharts-export-server.log', + dest: 'log', + toConsole: true, + toFile: true + }); + + // ui + tests.ui('ui', { + enable: false, + route: '/' + }); + + // other + tests.other('other', { + nodeEnv: 'production', + listenToProcessExits: true, + noLogo: false, + hardResetPage: false, + browserShellMode: true + }); + + // debug + tests.debug('debug', { + enable: false, + headless: true, + devtools: false, + listenToConsole: false, + dumpio: false, + slowMo: 0, + debuggingPort: 9222 + }); + + // payload + tests.payload('payload', { + requestId: 'd4faa416-0e85-433a-9f84-e735567d8fa5' + }); +}); + +describe('Puppeteer configuration options should be correctly parsed and validated', () => { + // Return config tests with a specific schema and strictCheck flag injected + const tests = configTests(StrictConfigSchema.shape.puppeteer, true); + + // puppeteer.args + tests.puppeteerArgs( + 'args', + [ + '--disable-sync', + '--enable-unsafe-webgpu', + '--hide-crash-restore-bubble', + '--hide-scrollbars', + '--metrics-recording-only' + ], + [ + '--disable-sync', + '--enable-unsafe-webgpu', + '--hide-crash-restore-bubble', + '--hide-scrollbars', + '--metrics-recording-only' + ] + ); +}); + +describe('Highcharts configuration options should be correctly parsed and validated', () => { + // Return config tests with a specific schema and strictCheck flag injected + const tests = configTests(StrictConfigSchema.shape.highcharts, true); + + // highcharts.version + tests.highchartsVersion('version'); + + // highcharts.cdnUrl + tests.highchartsCdnUrl( + 'cdnUrl', + ['http://example.com', 'https://example.com'], + ['http:a.com', 'http:/b.com', 'https:c.com', 'https:/d.com'] + ); + + // highcharts.forceFetch + tests.highchartsForceFetch('forceFetch'); + + // highcharts.cachePath + tests.highchartsCachePath('cachePath'); + + // highcharts.coreScripts + tests.highchartsCoreScripts( + 'coreScripts', + ['highcharts', 'highcharts-more', 'text1', 'highcharts-3d', 'text2'], + ['highcharts', 'highcharts-more', 'highcharts-3d'] + ); + + // highcharts.moduleScripts + tests.highchartsModuleScripts( + 'moduleScripts', + ['data', 'text1', 'data-tools', 'text2'], + ['data', 'data-tools'] + ); + + // highcharts.indicatorScripts + tests.highchartsIndicatorScripts( + 'indicatorScripts', + ['text1', 'indicators-all', 'text2'], + ['indicators-all'] + ); + + // highcharts.customScripts + tests.highchartsCustomScripts( + 'customScripts', + [ + 'https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.30.1/moment.min.js', + 'text1', + 'https://cdnjs.cloudflare.com/ajax/libs/moment-timezone/0.5.45/moment-timezone-with-data.min.js', + 'text2' + ], + [ + 'https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.30.1/moment.min.js', + 'https://cdnjs.cloudflare.com/ajax/libs/moment-timezone/0.5.45/moment-timezone-with-data.min.js' + ] + ); +}); + +describe('Export configuration options should be correctly parsed and validated', () => { + // Return config tests with a specific schema and strictCheck flag injected + const tests = configTests(StrictConfigSchema.shape.export, true); + + // export.infile + tests.exportInfile('infile'); + + // export.instr + tests.exportInstr('instr'); + + // export.options + tests.exportOptions('options'); + + // export.svg + tests.exportSvg('svg'); + + // export.outfile + tests.exportOutfile('outfile'); + + // export.type + tests.exportType( + 'type', + ['jpeg', 'jpg', 'png', 'pdf', 'svg'], + ['json', 'txt'] + ); + + // export.constr + tests.exportConstr( + 'constr', + ['chart', 'stockChart', 'mapChart', 'ganttChart'], + ['stock', 'map', 'gantt'] + ); + + // export.b64 + tests.exportB64('b64'); + + // export.noDownload + tests.exportNoDownload('noDownload'); + + // export.defaultHeight + tests.exportDefaultHeight('defaultHeight'); + + // export.defaultWidth + tests.exportDefaultWidth('defaultWidth'); + + // export.defaultScale + tests.exportDefaultScale('defaultScale'); + + // export.height + tests.exportHeight('height'); + + // export.width + tests.exportWidth('width'); + + // export.scale + tests.exportScale('scale'); + + // export.globalOptions + tests.exportGlobalOptions('globalOptions'); + + // export.themeOptions + tests.exportThemeOptions('themeOptions'); + + // export.batch + tests.exportBatch('batch'); + + // export.rasterizationTimeout + tests.exportRasterizationTimeout('rasterizationTimeout'); +}); + +describe('Custom Logic configuration options should be correctly parsed and validated', () => { + // Return config tests with a specific schema and strictCheck flag injected + const tests = configTests(StrictConfigSchema.shape.customLogic, true); + + // customLogic.allowCodeExecution + tests.customLogicAllowCodeExecution('allowCodeExecution'); + + // customLogic.allowFileResources + tests.customLogicAllowFileResources('allowFileResources'); + + // customLogic.customCode + tests.customLogicCustomCode('customCode'); + + // customLogic.callback + tests.customLogicCallback('callback'); + + // customLogic.resources + tests.customLogicResources('resources'); + + // customLogic.loadConfig + tests.customLogicLoadConfig('loadConfig'); + + // customLogic.createConfig + tests.customLogicCreateConfig('createConfig'); +}); + +describe('Server configuration options should be correctly parsed and validated', () => { + // Return config tests with a specific schema and strictCheck flag injected + const tests = configTests(StrictConfigSchema.shape.server, true); + + // server.enable + tests.serverEnable('enable'); + + // server.host + tests.serverHost('host'); + + // server.port + tests.serverPort('port'); + + // server.benchmarking + tests.serverBenchmarking('benchmarking'); + + // server.proxy + tests.serverProxy('proxy', { + host: null, + port: null, + timeout: 5000 + }); + + // server.rateLimiting + tests.serverRateLimiting('rateLimiting', { + enable: false, + maxRequests: 10, + window: 1, + delay: 0, + trustProxy: false, + skipKey: null, + skipToken: null + }); + + // server.ssl + tests.serverSsl('ssl', { + enable: false, + force: false, + port: 443, + certPath: null + }); +}); + +describe('Server Proxy configuration options should be correctly parsed and validated', () => { + // Return config tests with a specific schema and strictCheck flag injected + const tests = configTests(StrictConfigSchema.shape.server.shape.proxy, true); + + // server.proxy.host + tests.serverProxyHost('host'); + + // server.proxy.port + tests.serverProxyPort('port'); + + // server.proxy.timeout + tests.serverProxyTimeout('timeout'); +}); + +describe('Server Rate Limiting configuration options should be correctly parsed and validated', () => { + // Return config tests with a specific schema and strictCheck flag injected + const tests = configTests( + StrictConfigSchema.shape.server.shape.rateLimiting, + true + ); + + // server.rateLimiting.enable + tests.serverRateLimitingEnable('enable'); + + // server.rateLimiting.maxRequests + tests.serverRateLimitingMaxRequests('maxRequests'); + + // server.rateLimiting.window + tests.serverRateLimitingWindow('window'); + + // server.rateLimiting.delay + tests.serverRateLimitingDelay('delay'); + + // server.rateLimiting.trustProxy + tests.serverRateLimitingTrustProxy('trustProxy'); + + // server.rateLimiting.skipKey + tests.serverRateLimitingSkipKey('skipKey'); + + // server.rateLimiting.skipToken + tests.serverRateLimitingSkipToken('skipToken'); +}); + +describe('Server SSL configuration options should be correctly parsed and validated', () => { + // Return config tests with a specific schema and strictCheck flag injected + const tests = configTests(StrictConfigSchema.shape.server.shape.ssl, true); + + // server.ssl.enable + tests.serverSslEnable('enable'); + + // server.ssl.force + tests.serverSslForce('force'); + + // server.ssl.port + tests.serverSslPort('port'); + + // server.ssl.certPath + tests.serverSslCertPath('certPath'); +}); + +describe('Pool configuration options should be correctly parsed and validated', () => { + // Return config tests with a specific schema and strictCheck flag injected + const tests = configTests(StrictConfigSchema.shape.pool, true); + + // pool.minWorkers + tests.poolMinWorkers('minWorkers'); + + // pool.maxWorkers + tests.poolMaxWorkers('maxWorkers'); + + // pool.workLimit + tests.poolWorkLimit('workLimit'); + + // pool.acquireTimeout + tests.poolAcquireTimeout('acquireTimeout'); + + // pool.createTimeout + tests.poolCreateTimeout('createTimeout'); + + // pool.destroyTimeout + tests.poolDestroyTimeout('destroyTimeout'); + + // pool.idleTimeout + tests.poolIdleTimeout('idleTimeout'); + + // pool.createRetryInterval + tests.poolCreateRetryInterval('createRetryInterval'); + + // pool.reaperInterval + tests.poolReaperInterval('reaperInterval'); + + // pool.benchmarking + tests.poolBenchmarking('benchmarking'); +}); + +describe('Logging configuration options should be correctly parsed and validated', () => { + // Return config tests with a specific schema and strictCheck flag injected + const tests = configTests(StrictConfigSchema.shape.logging, true); + + // logging.level + tests.loggingLevel('level'); + + // logging.file + tests.loggingFile('file'); + + // logging.dest + tests.loggingDest('dest'); + + // logging.toConsole + tests.loggingToConsole('toConsole'); + + // logging.toFile + tests.loggingToFile('toFile'); +}); + +describe('UI configuration options should be correctly parsed and validated', () => { + // Return config tests with a specific schema and strictCheck flag injected + const tests = configTests(StrictConfigSchema.shape.ui, true); + + // ui.enable + tests.uiEnable('enable'); + + // ui.route + tests.uiRoute('route', ['/', '/ui'], ['ui', 'example/ui/']); +}); + +describe('Other configuration options should be correctly parsed and validated', () => { + // Return config tests with a specific schema and strictCheck flag injected + const tests = configTests(StrictConfigSchema.shape.other, true); + + // other.nodeEnv + tests.otherNodeEnv( + 'nodeEnv', + ['development', 'production', 'test'], + ['dev-env', 'prod-env', 'test-env'] + ); + + // other.listenToProcessExits + tests.otherListenToProcessExits('listenToProcessExits'); + + // other.noLogo + tests.otherNoLogo('noLogo'); + + // other.hardResetPage + tests.otherHardResetPage('hardResetPage'); + + // other.browserShellMode + tests.otherBrowserShellMode('browserShellMode'); +}); + +describe('Debug configuration options should be correctly parsed and validated', () => { + // Return config tests with a specific schema and strictCheck flag injected + const tests = configTests(StrictConfigSchema.shape.debug, true); + + // debug.enable + tests.debugEnable('enable'); + + // debug.headless + tests.debugHeadless('headless'); + + // debug.devtools + tests.debugDevtools('devtools'); + + // debug.listenToConsole + tests.debugListenToConsole('listenToConsole'); + + // debug.dumpio + tests.debugDumpio('dumpio'); + + // debug.slowMo + tests.debugSlowMo('slowMo'); + + // debug.debuggingPort + tests.debugDebuggingPort('debuggingPort'); +}); + +describe('Payload configuration options should be correctly parsed and validated', () => { + // Return config tests with a specific schema and strictCheck flag injected + const tests = configTests(StrictConfigSchema.shape.payload, true); + + // payload.requestId + tests.payloadRequestId('requestId'); +}); diff --git a/tests/unit/validation/envs.test.js b/tests/unit/validation/envs.test.js new file mode 100644 index 00000000..1b428e27 --- /dev/null +++ b/tests/unit/validation/envs.test.js @@ -0,0 +1,341 @@ +/******************************************************************************* + +Highcharts Export Server + +Copyright (c) 2016-2024, Highsoft + +Licenced under the MIT licence. + +Additionally a valid Highcharts license is required for use. + +See LICENSE file in root for details. + +*******************************************************************************/ + +import { describe } from '@jest/globals'; + +import { configTests } from './shared.js'; +import { EnvSchema } from '../../../lib/validation.js'; + +// Return config tests with a specific schema and strictCheck flag injected +const tests = configTests(EnvSchema.partial(), false); + +describe('PUPPETEER environment variables should be correctly parsed and validated', () => { + // PUPPETEER_ARGS + tests.puppeteerArgs( + 'PUPPETEER_ARGS', + '--disable-sync; --enable-unsafe-webgpu; --hide-crash-restore-bubble; --hide-scrollbars; --metrics-recording-only', + [ + '--disable-sync', + '--enable-unsafe-webgpu', + '--hide-crash-restore-bubble', + '--hide-scrollbars', + '--metrics-recording-only' + ] + ); +}); + +describe('HIGHCHARTS environment variables should be correctly parsed and validated', () => { + // HIGHCHARTS_VERSION + tests.highchartsVersion('HIGHCHARTS_VERSION'); + + // HIGHCHARTS_CDN_URL + tests.highchartsCdnUrl( + 'HIGHCHARTS_CDN_URL', + ['http://example.com', 'https://example.com'], + ['http:a.com', 'http:/b.com', 'https:c.com', 'https:/d.com'] + ); + + // HIGHCHARTS_FORCE_FETCH + tests.highchartsForceFetch('HIGHCHARTS_FORCE_FETCH'); + + // HIGHCHARTS_CACHE_PATH + tests.highchartsCachePath('HIGHCHARTS_CACHE_PATH'); + + // HIGHCHARTS_ADMIN_TOKEN + tests.highchartsAdminToken('HIGHCHARTS_ADMIN_TOKEN'); + + // HIGHCHARTS_CORE_SCRIPTS + tests.highchartsCoreScripts( + 'HIGHCHARTS_CORE_SCRIPTS', + 'highcharts, highcharts-more, text1, highcharts-3d, text2', + ['highcharts', 'highcharts-more', 'highcharts-3d'] + ); + + // HIGHCHARTS_MODULE_SCRIPTS + tests.highchartsModuleScripts( + 'HIGHCHARTS_MODULE_SCRIPTS', + 'data, text1, data-tools, text2', + ['data', 'data-tools'] + ); + + // HIGHCHARTS_INDICATOR_SCRIPTS + tests.highchartsIndicatorScripts( + 'HIGHCHARTS_INDICATOR_SCRIPTS', + 'text1, indicators-all, text2', + ['indicators-all'] + ); + + // HIGHCHARTS_CUSTOM_SCRIPTS + tests.highchartsCustomScripts( + 'HIGHCHARTS_CUSTOM_SCRIPTS', + 'https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.30.1/moment.min.js, text1, https://cdnjs.cloudflare.com/ajax/libs/moment-timezone/0.5.45/moment-timezone-with-data.min.js, text2', + [ + 'https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.30.1/moment.min.js', + 'https://cdnjs.cloudflare.com/ajax/libs/moment-timezone/0.5.45/moment-timezone-with-data.min.js' + ] + ); +}); + +describe('EXPORT environment variables should be correctly parsed and validated', () => { + // EXPORT_INFILE + tests.exportInfile('EXPORT_INFILE'); + + // EXPORT_INSTR + tests.exportInstr('EXPORT_INSTR'); + + // EXPORT_OPTIONS + tests.exportOptions('EXPORT_OPTIONS'); + + // EXPORT_SVG + tests.exportSvg('EXPORT_SVG'); + + // EXPORT_OUTFILE + tests.exportOutfile('EXPORT_OUTFILE'); + + // EXPORT_TYPE + tests.exportType( + 'EXPORT_TYPE', + ['jpeg', 'jpg', 'png', 'pdf', 'svg'], + ['json', 'txt'] + ); + + // EXPORT_CONSTR + tests.exportConstr( + 'EXPORT_CONSTR', + ['chart', 'stockChart', 'mapChart', 'ganttChart'], + ['stock', 'map', 'gantt'] + ); + + // EXPORT_B64 + tests.exportB64('EXPORT_B64'); + + // EXPORT_NO_DOWNLOAD + tests.exportNoDownload('EXPORT_NO_DOWNLOAD'); + + // EXPORT_DEFAULT_HEIGHT + tests.exportDefaultHeight('EXPORT_DEFAULT_HEIGHT'); + + // EXPORT_DEFAULT_WIDTH + tests.exportDefaultWidth('EXPORT_DEFAULT_WIDTH'); + + // EXPORT_DEFAULT_SCALE + tests.exportDefaultScale('EXPORT_DEFAULT_SCALE'); + + // EXPORT_HEIGHT + tests.exportDefaultHeight('EXPORT_HEIGHT'); + + // EXPORT_WIDTH + tests.exportDefaultWidth('EXPORT_WIDTH'); + + // EXPORT_SCALE + tests.exportDefaultScale('EXPORT_SCALE'); + + // EXPORT_GLOBAL_OPTIONS + tests.exportGlobalOptions('EXPORT_GLOBAL_OPTIONS'); + + // EXPORT_THEME_OPTIONS + tests.exportThemeOptions('EXPORT_THEME_OPTIONS'); + + // EXPORT_BATCH + tests.exportBatch('EXPORT_BATCH'); + + // EXPORT_RASTERIZATION_TIMEOUT + tests.exportRasterizationTimeout('EXPORT_RASTERIZATION_TIMEOUT'); +}); + +describe('CUSTOM_LOGIC environment variables should be correctly parsed and validated', () => { + // CUSTOM_LOGIC_ALLOW_CODE_EXECUTION + tests.customLogicAllowCodeExecution('CUSTOM_LOGIC_ALLOW_CODE_EXECUTION'); + + // CUSTOM_LOGIC_ALLOW_FILE_RESOURCES + tests.customLogicAllowFileResources('CUSTOM_LOGIC_ALLOW_FILE_RESOURCES'); + + // CUSTOM_LOGIC_CUSTOM_CODE + tests.customLogicCustomCode('CUSTOM_LOGIC_CUSTOM_CODE'); + + // CUSTOM_LOGIC_CALLBACK + tests.customLogicCallback('CUSTOM_LOGIC_CALLBACK'); + + // CUSTOM_LOGIC_RESOURCES + tests.customLogicResources('CUSTOM_LOGIC_RESOURCES'); + + // CUSTOM_LOGIC_LOAD_CONFIG + tests.customLogicLoadConfig('CUSTOM_LOGIC_LOAD_CONFIG'); + + // CUSTOM_LOGIC_CREATE_CONFIG + tests.customLogicCreateConfig('CUSTOM_LOGIC_CREATE_CONFIG'); +}); + +describe('SERVER environment variables should be correctly parsed and validated', () => { + // SERVER_ENABLE + tests.serverEnable('SERVER_ENABLE'); + + // SERVER_HOST + tests.serverHost('SERVER_HOST'); + + // SERVER_PORT + tests.serverPort('SERVER_PORT'); + + // SERVER_BENCHMARKING + tests.serverBenchmarking('SERVER_BENCHMARKING'); +}); + +describe('SERVER_PROXY environment variables should be correctly parsed and validated', () => { + // SERVER_PROXY_HOST + tests.serverProxyHost('SERVER_PROXY_HOST'); + + // SERVER_PROXY_PORT + tests.serverProxyPort('SERVER_PROXY_PORT'); + + // SERVER_PROXY_TIMEOUT + tests.serverProxyTimeout('SERVER_PROXY_TIMEOUT'); +}); + +describe('SERVER_RATE_LIMITING environment variables should be correctly parsed and validated', () => { + // SERVER_RATE_LIMITING_ENABLE + tests.serverRateLimitingEnable('SERVER_RATE_LIMITING_ENABLE'); + + // SERVER_RATE_LIMITING_MAX_REQUESTS + tests.serverRateLimitingMaxRequests('SERVER_RATE_LIMITING_MAX_REQUESTS'); + + // SERVER_RATE_LIMITING_WINDOW + tests.serverRateLimitingWindow('SERVER_RATE_LIMITING_WINDOW'); + + // SERVER_RATE_LIMITING_DELAY + tests.serverRateLimitingDelay('SERVER_RATE_LIMITING_DELAY'); + + // SERVER_RATE_LIMITING_TRUST_PROXY + tests.serverRateLimitingTrustProxy('SERVER_RATE_LIMITING_TRUST_PROXY'); + + // SERVER_RATE_LIMITING_SKIP_KEY + tests.serverRateLimitingSkipKey('SERVER_RATE_LIMITING_SKIP_KEY'); + + // SERVER_RATE_LIMITING_SKIP_TOKEN + tests.serverRateLimitingSkipToken('SERVER_RATE_LIMITING_SKIP_TOKEN'); +}); + +describe('SERVER_SSL environment variables should be correctly parsed and validated', () => { + // SERVER_SSL_ENABLE + tests.serverSslEnable('SERVER_SSL_ENABLE'); + + // SERVER_SSL_FORCE + tests.serverSslForce('SERVER_SSL_FORCE'); + + // SERVER_SSL_PORT + tests.serverSslPort('SERVER_SSL_PORT'); + + // SERVER_SSL_CERT_PATH + tests.serverSslCertPath('SERVER_SSL_CERT_PATH'); +}); + +describe('POOL environment variables should be correctly parsed and validated', () => { + // POOL_MIN_WORKERS + tests.poolMinWorkers('POOL_MIN_WORKERS'); + + // POOL_MAX_WORKERS + tests.poolMaxWorkers('POOL_MAX_WORKERS'); + + // POOL_WORK_LIMIT + tests.poolWorkLimit('POOL_WORK_LIMIT'); + + // POOL_ACQUIRE_TIMEOUT + tests.poolAcquireTimeout('POOL_ACQUIRE_TIMEOUT'); + + // POOL_CREATE_TIMEOUT + tests.poolCreateTimeout('POOL_CREATE_TIMEOUT'); + + // POOL_DESTROY_TIMEOUT + tests.poolDestroyTimeout('POOL_DESTROY_TIMEOUT'); + + // POOL_IDLE_TIMEOUT + tests.poolIdleTimeout('POOL_IDLE_TIMEOUT'); + + // POOL_CREATE_RETRY_INTERVAL + tests.poolCreateRetryInterval('POOL_CREATE_RETRY_INTERVAL'); + + // POOL_REAPER_INTERVAL + tests.poolReaperInterval('POOL_REAPER_INTERVAL'); + + // POOL_BENCHMARKING + tests.poolBenchmarking('POOL_BENCHMARKING'); +}); + +describe('LOGGING environment variables should be correctly parsed and validated', () => { + // LOGGING_LEVEL + tests.loggingLevel('LOGGING_LEVEL'); + + // LOGGING_FILE + tests.loggingFile('LOGGING_FILE'); + + // LOGGING_DEST + tests.loggingDest('LOGGING_DEST'); + + // LOGGING_TO_CONSOLE + tests.loggingToConsole('LOGGING_TO_CONSOLE'); + + // LOGGING_TO_FILE + tests.loggingToFile('LOGGING_TO_FILE'); +}); + +describe('UI environment variables should be correctly parsed and validated', () => { + // UI_ENABLE + tests.uiEnable('UI_ENABLE'); + + // UI_ROUTE + tests.uiRoute('UI_ROUTE', ['/', '/ui'], ['ui', 'example/ui/']); +}); + +describe('OTHER environment variables should be correctly parsed and validated', () => { + // OTHER_NODE_ENV + tests.otherNodeEnv( + 'OTHER_NODE_ENV', + ['development', 'production', 'test'], + ['dev-env', 'prod-env', 'test-env'] + ); + + // OTHER_LISTEN_TO_PROCESS_EXITS + tests.otherListenToProcessExits('OTHER_LISTEN_TO_PROCESS_EXITS'); + + // OTHER_NO_LOGO + tests.otherNoLogo('OTHER_NO_LOGO'); + + // OTHER_HARD_RESET_PAGE + tests.otherHardResetPage('OTHER_HARD_RESET_PAGE'); + + // OTHER_BROWSER_SHELL_MODE + tests.otherBrowserShellMode('OTHER_BROWSER_SHELL_MODE'); +}); + +describe('DEBUG environment variables should be correctly parsed and validated', () => { + // DEBUG_ENABLE + tests.debugEnable('DEBUG_ENABLE'); + + // DEBUG_HEADLESS + tests.debugHeadless('DEBUG_HEADLESS'); + + // DEBUG_DEVTOOLS + tests.debugDevtools('DEBUG_DEVTOOLS'); + + // DEBUG_LISTEN_TO_CONSOLE + tests.debugListenToConsole('DEBUG_LISTEN_TO_CONSOLE'); + + // DEBUG_DUMPIO + tests.debugDumpio('DEBUG_DUMPIO'); + + // DEBUG_SLOW_MO + tests.debugSlowMo('DEBUG_SLOW_MO'); + + // DEBUG_DEBUGGING_PORT + tests.debugDebuggingPort('DEBUG_DEBUGGING_PORT'); +}); diff --git a/tests/unit/validation/shared.js b/tests/unit/validation/shared.js new file mode 100644 index 00000000..2f0a015b --- /dev/null +++ b/tests/unit/validation/shared.js @@ -0,0 +1,2565 @@ +/******************************************************************************* + +Highcharts Export Server + +Copyright (c) 2016-2024, Highsoft + +Licenced under the MIT licence. + +Additionally a valid Highcharts license is required for use. + +See LICENSE file in root for details. + +*******************************************************************************/ + +import { describe, expect, it } from '@jest/globals'; + +import { validatePropOfSchema } from '../../utils/testUtils.js'; + +/** + * Runs a series of tests to validate and parse configuration properties using + * the injected schema. Optionally performs strict checks. + * + * @param {Object} schema - The schema used for validation and parsing. + * @param {boolean} strictCheck - A flag indicating whether to enforce strict + * validation. + */ +export function configTests(schema, strictCheck) { + /** + * Verifies that a property with the value undefined is accepted. + * + * @function acceptUndefined + * + * @param {string} property - The property to check for accepting null. + * + * @throws {Error} Throws an `Error` if the schema validation fails. + */ + const acceptUndefined = (property) => { + const obj = { [property]: undefined }; + expect(schema.parse(obj)[property]).toBe(undefined); + }; + + /** + * Verifies that a property with the value null is accepted. + * + * @function acceptNull + * + * @param {string} property - The property to check for accepting null. + * + * @throws {Error} Throws an `Error` if the schema validation fails. + */ + const acceptNull = (property) => { + const obj = { [property]: null }; + expect(schema.parse(obj)[property]).toBe(null); + }; + + /** + * Verifies that a property with the string value 'null' is converted to null. + * + * @function stringNullToNull + * + * @param {string} property - The property to check for conversion of 'null' + * to null. + * + * @throws {Error} Throws an `Error` if the schema validation fails. + */ + const stringNullToNull = (property) => { + const obj = { [property]: 'null' }; + expect(schema.parse(obj)[property]).toBe(null); + }; + + /** + * Verifies that a property with the string value 'undefined' is converted to + * null. + * + * @function stringUndefinedToNull + * + * @param {string} property - The property to check for conversion of + * 'undefined' to null. + * + * @throws {Error} Throws an `Error` if the schema validation fails. + */ + const stringUndefinedToNull = (property) => { + const obj = { [property]: 'undefined' }; + expect(schema.parse(obj)[property]).toBe(null); + }; + + /** + * Verifies that a property with the string value '' is converted to null. + * + * @function emptyStringToNull + * + * @param {string} property - The property to check for conversion of '' to + * null. + * + * @throws {Error} Throws an `Error` if the schema validation fails. + */ + const emptyStringToNull = (property) => { + const obj = { [property]: '' }; + expect(schema.parse(obj)[property]).toBe(null); + }; + + /** + * Verifies that a property set to null causes a schema validation error. + * + * @function nullThrow + * + * @param {string} property - The property to check for a thrown validation + * error. + * + * @throws {Error} Throws an `Error` if the schema validation fails. + */ + const nullThrow = (property) => { + const obj = { [property]: null }; + expect(() => schema.parse(obj)).toThrow(); + }; + + /** + * Verifies that a property set to 'null' causes a schema validation error. + * + * @function stringNullThrow + * + * @param {string} property - The property to check for a thrown validation + * error. + * + * @throws {Error} Throws an `Error` if the schema validation fails. + */ + const stringNullThrow = (property) => { + const obj = { [property]: 'null' }; + expect(() => schema.parse(obj)).toThrow(); + }; + + /** + * Verifies that a property set to 'undefined' causes a schema validation + * error. + * + * @function stringUndefinedThrow + * + * @param {string} property - The property to check for a thrown validation + * error. + * + * @throws {Error} Throws an `Error` if the schema validation fails. + */ + const stringUndefinedThrow = (property) => { + const obj = { [property]: 'undefined' }; + expect(() => schema.parse(obj)).toThrow(); + }; + + /** + * Verifies that a property set to '' causes a schema validation error. + * + * @function emptyStringThrow + * + * @param {string} property - The property to check for a thrown validation + * error. + * + * @throws {Error} Throws an `Error` if the schema validation fails. + */ + const emptyStringThrow = (property) => { + const obj = { [property]: '' }; + expect(() => schema.parse(obj)).toThrow(); + }; + + /** + * Object that contains all tests for validating and parsing values of the + * options config. + */ + const validationTests = { + /** + * The boolean validator. + */ + boolean(property) { + it('should accept a boolean value', () => { + const obj = { [property]: true }; + expect(schema.parse(obj)[property]).toBe(true); + obj[property] = false; + expect(schema.parse(obj)[property]).toBe(false); + }); + + it('should accept undefined', () => { + acceptUndefined(property); + }); + + if (strictCheck) { + it('should not accept a stringified boolean value', () => { + const obj = { [property]: 'true' }; + expect(() => schema.parse(obj)).toThrow(); + obj[property] = 'false'; + expect(() => schema.parse(obj)).toThrow(); + }); + + it('should not accept null', () => { + nullThrow(property); + }); + + it('should not accept a stringified undefined', () => { + stringUndefinedThrow(property); + }); + + it('should not accept a stringified null', () => { + stringNullThrow(property); + }); + + it('should not accept an empty string', () => { + emptyStringThrow(property); + }); + + it('should not accept values of other types', () => + validatePropOfSchema(schema, property, ['boolean', 'undefined'])); + } else { + it('should accept a stringified boolean value and transform it to a boolean', () => { + const obj = { [property]: 'true' }; + expect(schema.parse(obj)[property]).toBe(true); + obj[property] = 'false'; + expect(schema.parse(obj)[property]).toBe(false); + }); + + it('should accept null', () => { + acceptNull(property); + }); + + it('should accept a stringified undefined and transform it to null', () => { + stringUndefinedToNull(property); + }); + + it('should accept a stringified null and transform it to null', () => { + stringNullToNull(property); + }); + + it('should accept an empty string and transform it to null', () => { + emptyStringToNull(property); + }); + + it('should not accept values of other types', () => + validatePropOfSchema(schema, property, [ + 'emptyString', + 'stringBoolean', + 'stringUndefined', + 'stringNull', + 'boolean', + 'undefined', + 'null' + ])); + } + }, + + /** + * The string validator. + */ + string(property, strictCheck) { + it('should accept a string value', () => { + const obj = { [property]: 'text' }; + expect(schema.parse(obj)[property]).toBe('text'); + obj[property] = 'some-other-text'; + expect(schema.parse(obj)[property]).toBe('some-other-text'); + }); + + it('should accept undefined', () => { + acceptUndefined(property); + }); + + if (strictCheck) { + it("should not accept 'false', 'undefined', 'null', '' values", () => { + const obj = { [property]: 'false' }; + expect(() => schema.parse(obj)).toThrow(); + obj[property] = 'undefined'; + expect(() => schema.parse(obj)).toThrow(); + obj[property] = 'null'; + expect(() => schema.parse(obj)).toThrow(); + obj[property] = ''; + expect(() => schema.parse(obj)).toThrow(); + }); + + it('should not accept null', () => { + nullThrow(property); + }); + + it('should not accept a stringified undefined', () => { + stringUndefinedThrow(property); + }); + + it('should not accept a stringified null', () => { + stringNullThrow(property); + }); + + it('should not accept an empty string', () => { + emptyStringThrow(property); + }); + + it('should not accept values of other types', () => + validatePropOfSchema(schema, property, [ + 'string', + 'stringBoolean', + 'stringNumber', + 'stringBigInt', + 'stringSymbol', + 'stringObject', + 'stringArray', + 'stringFunction', + 'stringOther', + 'undefined' + ])); + } else { + it("should accept 'false', 'undefined', 'null', '' values and trasform to null", () => { + const obj = { [property]: 'false' }; + expect(schema.parse(obj)[property]).toBe(null); + obj[property] = 'undefined'; + expect(schema.parse(obj)[property]).toBe(null); + obj[property] = 'null'; + expect(schema.parse(obj)[property]).toBe(null); + obj[property] = ''; + expect(schema.parse(obj)[property]).toBe(null); + }); + + it('should accept null', () => { + acceptNull(property); + }); + + it('should accept a stringified undefined and transform it to null', () => { + stringUndefinedToNull(property); + }); + + it('should accept a stringified null and transform it to null', () => { + stringNullToNull(property); + }); + + it('should accept an empty string and transform it to null', () => { + emptyStringToNull(property); + }); + + it('should not accept values of other types', () => + validatePropOfSchema(schema, property, [ + 'emptyString', + 'string', + 'stringBoolean', + 'stringNumber', + 'stringBigInt', + 'stringUndefined', + 'stringNull', + 'stringSymbol', + 'stringObject', + 'stringArray', + 'stringFunction', + 'stringOther', + 'undefined', + 'null' + ])); + } + }, + + /** + * The accept values validator. + */ + acceptValues(property, correctValue, incorrectValue) { + it(`should accept the following ${correctValue.join(', ')} values`, () => { + correctValue.forEach((value) => { + expect(schema.parse({ [property]: value })[property]).toBe(value); + }); + }); + + it(`should not accept the following ${incorrectValue.join(', ')} values`, () => { + incorrectValue.forEach((value) => { + expect(() => schema.parse({ [property]: value })).toThrow(); + }); + }); + + it('should accept undefined', () => { + acceptUndefined(property); + }); + + if (strictCheck) { + it('should not accept null', () => { + nullThrow(property); + }); + + it('should not accept a stringified undefined', () => { + stringUndefinedThrow(property); + }); + + it('should not accept a stringified null', () => { + stringNullThrow(property); + }); + + it('should not accept an empty string', () => { + emptyStringThrow(property); + }); + + it('should not accept values of other types', () => + validatePropOfSchema(schema, property, ['undefined'])); + } else { + it('should accept null', () => { + acceptNull(property); + }); + + it('should accept a stringified undefined and transform it to null', () => { + stringUndefinedToNull(property); + }); + + it('should accept a stringified null and transform it to null', () => { + stringNullToNull(property); + }); + + it('should accept an empty string and transform it to null', () => { + emptyStringToNull(property); + }); + + it('should not accept values of other types', () => + validatePropOfSchema(schema, property, [ + 'emptyString', + 'stringUndefined', + 'stringNull', + 'undefined', + 'null' + ])); + } + }, + + /** + * The nullable accept values validator. + */ + nullableAcceptValues(property, correctValue, incorrectValue) { + it(`should accept the following ${correctValue.join(', ')} values`, () => { + correctValue.forEach((value) => { + expect(schema.parse({ [property]: value })[property]).toBe(value); + }); + }); + + it(`should not accept the following ${incorrectValue.join(', ')} values`, () => { + incorrectValue.forEach((value) => { + expect(() => schema.parse({ [property]: value })).toThrow(); + }); + }); + + it('should accept undefined', () => { + acceptUndefined(property); + }); + + it('should accept null', () => { + acceptNull(property); + }); + + if (strictCheck) { + it('should not accept a stringified undefined', () => { + stringUndefinedThrow(property); + }); + + it('should not accept a stringified null', () => { + stringNullThrow(property); + }); + + it('should not accept an empty string', () => { + emptyStringThrow(property); + }); + + it('should not accept values of other types', () => + validatePropOfSchema(schema, property, ['undefined', 'null'])); + } else { + it('should accept a stringified undefined and transform it to null', () => { + stringUndefinedToNull(property); + }); + + it('should accept a stringified null and transform it to null', () => { + stringNullToNull(property); + }); + + it('should accept an empty string and transform it to null', () => { + emptyStringToNull(property); + }); + + it('should not accept values of other types', () => + validatePropOfSchema(schema, property, [ + 'emptyString', + 'stringUndefined', + 'stringNull', + 'undefined', + 'null' + ])); + } + }, + + /** + * The array of strings validator. + */ + stringArray(property, value, correctValue, separator = ',') { + it('should accept a string value or an array of strings and correctly parse it to an array of strings', () => { + const obj = { [property]: value }; + expect(schema.parse(obj)[property]).toEqual(correctValue); + }); + + it('should accept undefined', () => { + acceptUndefined(property); + }); + + if (strictCheck) { + it('should accept an empty array', () => { + const obj = { [property]: [] }; + expect(schema.parse(obj)[property]).toEqual([]); + }); + + it('should accept an array of strings and filter it from the forbidden values', () => { + const obj = { + [property]: [...value, 'false', 'undefined', 'null', ''] + }; + expect(schema.parse(obj)[property]).toEqual(correctValue); + }); + + it('should not accept null', () => { + nullThrow(property); + }); + + it('should not accept a stringified undefined', () => { + stringUndefinedThrow(property); + }); + + it('should not accept a stringified null', () => { + stringNullThrow(property); + }); + + it('should not accept an empty string', () => { + emptyStringThrow(property); + }); + + it('should not accept values of other types', () => + validatePropOfSchema(schema, property, ['undefined', 'array'])); + } else { + it("should accept a stringified array of the 'values' string and correctly parse it to an array of strings", () => { + const obj = { [property]: `[${value}]` }; + expect(schema.parse(obj)[property]).toEqual(correctValue); + }); + + it('should filter a stringified array of a values string from forbidden values and correctly parse it to an array of strings', () => { + const obj = { + [property]: `[${value}${separator} false${separator} undefined${separator} null${separator}]` + }; + expect(schema.parse(obj)[property]).toEqual(correctValue); + }); + + it('should accept null', () => { + acceptNull(property); + }); + + it('should accept a stringified undefined and transform it to null', () => { + stringUndefinedToNull(property); + }); + + it('should accept a stringified null and transform it to null', () => { + stringNullToNull(property); + }); + + it('should accept an empty string and transform it to null', () => { + emptyStringToNull(property); + }); + + it('should not accept values of other types', () => + validatePropOfSchema(schema, property, [ + 'emptyString', + 'string', + 'stringBoolean', + 'stringNumber', + 'stringBigInt', + 'stringUndefined', + 'stringNull', + 'stringSymbol', + 'stringObject', + 'stringArray', + 'stringFunction', + 'stringOther', + 'array', + 'undefined', + 'null' + ])); + } + }, + + /** + * The positive number validator. + */ + positiveNum(property) { + it('should accept a positive number value', () => { + const obj = { [property]: 0.1 }; + expect(schema.parse(obj)[property]).toBe(0.1); + obj[property] = 100.5; + expect(schema.parse(obj)[property]).toBe(100.5); + obj[property] = 750; + expect(schema.parse(obj)[property]).toBe(750); + }); + + it('should not accept negative and non-positive number value', () => { + const obj = { [property]: 0 }; + expect(() => schema.parse(obj)).toThrow(); + obj[property] = -100; + expect(() => schema.parse(obj)).toThrow(); + }); + + it('should not accept stringified negative and non-positive number value', () => { + const obj = { [property]: '0' }; + expect(() => schema.parse(obj)).toThrow(); + obj[property] = '-100'; + expect(() => schema.parse(obj)).toThrow(); + }); + + it('should accept undefined', () => { + acceptUndefined(property); + }); + + if (strictCheck) { + it('should not accept a stringified positive number value', () => { + const obj = { [property]: '0.1' }; + expect(() => schema.parse(obj)).toThrow(); + obj[property] = '100.5'; + expect(() => schema.parse(obj)).toThrow(); + obj[property] = '750'; + expect(() => schema.parse(obj)).toThrow(); + }); + + it('should not accept null', () => { + nullThrow(property); + }); + + it('should not accept a stringified undefined', () => { + stringUndefinedThrow(property); + }); + + it('should not accept a stringified null', () => { + stringNullThrow(property); + }); + + it('should not accept an empty string', () => { + emptyStringThrow(property); + }); + + it('should not accept values of other types', () => + validatePropOfSchema(schema, property, [ + 'emptyString', + 'stringNumber', + 'stringUndefined', + 'stringNull', + 'number', + 'undefined', + 'null' + ])); + } else { + it('should accept a stringified positive number value', () => { + const obj = { [property]: '0.1' }; + expect(schema.parse(obj)[property]).toBe(0.1); + obj[property] = '100.5'; + expect(schema.parse(obj)[property]).toBe(100.5); + obj[property] = '750'; + expect(schema.parse(obj)[property]).toBe(750); + }); + + it('should accept null', () => { + acceptNull(property); + }); + + it('should accept a stringified undefined and transform it to null', () => { + stringUndefinedToNull(property); + }); + + it('should accept a stringified null and transform it to null', () => { + stringNullToNull(property); + }); + + it('should accept an empty string and transform it to null', () => { + emptyStringToNull(property); + }); + + it('should not accept values of other types', () => + validatePropOfSchema(schema, property, [ + 'emptyString', + 'stringNumber', + 'stringUndefined', + 'stringNull', + 'number', + 'undefined', + 'null' + ])); + } + }, + + /** + * The nullable positive number validator. + */ + nullablePositiveNum(property) { + it('should accept a positive number value', () => { + const obj = { [property]: 0.1 }; + expect(schema.parse(obj)[property]).toBe(0.1); + obj[property] = 100.5; + expect(schema.parse(obj)[property]).toBe(100.5); + obj[property] = 750; + expect(schema.parse(obj)[property]).toBe(750); + }); + + it('should not accept negative and non-positive number value', () => { + const obj = { [property]: 0 }; + expect(() => schema.parse(obj)).toThrow(); + obj[property] = -100; + expect(() => schema.parse(obj)).toThrow(); + }); + + it('should not accept stringified negative and non-positive number value', () => { + const obj = { [property]: '0' }; + expect(() => schema.parse(obj)).toThrow(); + obj[property] = '-100'; + expect(() => schema.parse(obj)).toThrow(); + }); + + it('should accept undefined', () => { + acceptUndefined(property); + }); + + it('should accept null', () => { + acceptNull(property); + }); + + if (strictCheck) { + it('should not accept a stringified positive number value', () => { + const obj = { [property]: '0.1' }; + expect(() => schema.parse(obj)).toThrow(); + obj[property] = '100.5'; + expect(() => schema.parse(obj)).toThrow(); + obj[property] = '750'; + expect(() => schema.parse(obj)).toThrow(); + }); + + it('should not accept a stringified undefined', () => { + stringUndefinedThrow(property); + }); + + it('should not accept a stringified null', () => { + stringNullThrow(property); + }); + + it('should not accept an empty string', () => { + emptyStringThrow(property); + }); + + it('should not accept values of other types', () => + validatePropOfSchema(schema, property, [ + 'emptyString', + 'stringNumber', + 'stringUndefined', + 'stringNull', + 'number', + 'undefined', + 'null' + ])); + } else { + it('should accept a stringified positive number value', () => { + const obj = { [property]: '0.1' }; + expect(schema.parse(obj)[property]).toBe(0.1); + obj[property] = '100.5'; + expect(schema.parse(obj)[property]).toBe(100.5); + obj[property] = '750'; + expect(schema.parse(obj)[property]).toBe(750); + }); + + it('should accept a stringified undefined and transform it to null', () => { + stringUndefinedToNull(property); + }); + + it('should accept a stringified null and transform it to null', () => { + stringNullToNull(property); + }); + + it('should accept an empty string and transform it to null', () => { + emptyStringToNull(property); + }); + + it('should not accept values of other types', () => + validatePropOfSchema(schema, property, [ + 'emptyString', + 'stringNumber', + 'stringUndefined', + 'stringNull', + 'number', + 'undefined', + 'null' + ])); + } + }, + + /** + * The non-negative number validator. + */ + nonNegativeNum(property) { + it('should accept a non-negative number value', () => { + const obj = { [property]: 0 }; + expect(schema.parse(obj)[property]).toBe(0); + obj[property] = 1000; + expect(schema.parse(obj)[property]).toBe(1000); + }); + + it('should not accept a negative number value', () => { + const obj = { [property]: -1000 }; + expect(() => schema.parse(obj)).toThrow(); + }); + + it('should not accept a stringified negative number value', () => { + const obj = { [property]: '-1000' }; + expect(() => schema.parse(obj)).toThrow(); + }); + + it('should accept undefined', () => { + acceptUndefined(property); + }); + + if (strictCheck) { + it('should not accept a stringified non-negative number value', () => { + const obj = { [property]: '0' }; + expect(() => schema.parse(obj)).toThrow(); + obj[property] = '1000'; + expect(() => schema.parse(obj)).toThrow(); + }); + + it('should not accept null', () => { + nullThrow(property); + }); + + it('should not accept a stringified undefined', () => { + stringUndefinedThrow(property); + }); + + it('should not accept a stringified null', () => { + stringNullThrow(property); + }); + + it('should not accept an empty string', () => { + emptyStringThrow(property); + }); + + it('should not accept values of other types', () => + validatePropOfSchema(schema, property, [ + 'emptyString', + 'stringNumber', + 'stringUndefined', + 'stringNull', + 'number', + 'undefined', + 'null' + ])); + } else { + it('should accept a stringified non-negative number value', () => { + const obj = { [property]: '0' }; + expect(schema.parse(obj)[property]).toBe(0); + obj[property] = '1000'; + expect(schema.parse(obj)[property]).toBe(1000); + }); + + it('should accept null', () => { + acceptNull(property); + }); + + it('should accept a stringified undefined and transform it to null', () => { + stringUndefinedToNull(property); + }); + + it('should accept a stringified null and transform it to null', () => { + stringNullToNull(property); + }); + + it('should accept an empty string and transform it to null', () => { + emptyStringToNull(property); + }); + + it('should not accept values of other types', () => + validatePropOfSchema(schema, property, [ + 'emptyString', + 'stringNumber', + 'stringUndefined', + 'stringNull', + 'number', + 'undefined', + 'null' + ])); + } + }, + + /** + * The nullable non-negative number validator. + */ + nullableNonNegativeNum(property) { + it('should accept a non-negative number value', () => { + const obj = { [property]: 0 }; + expect(schema.parse(obj)[property]).toBe(0); + obj[property] = 1000; + expect(schema.parse(obj)[property]).toBe(1000); + }); + + it('should not accept a negative number value', () => { + const obj = { [property]: -1000 }; + expect(() => schema.parse(obj)).toThrow(); + }); + + it('should not accept a stringified negative number value', () => { + const obj = { [property]: '-1000' }; + expect(() => schema.parse(obj)).toThrow(); + }); + + it('should accept undefined', () => { + acceptUndefined(property); + }); + + it('should accept null', () => { + acceptNull(property); + }); + + if (strictCheck) { + it('should not accept a stringified non-negative number value', () => { + const obj = { [property]: '0' }; + expect(() => schema.parse(obj)).toThrow(); + obj[property] = '1000'; + expect(() => schema.parse(obj)).toThrow(); + }); + + it('should not accept a stringified undefined', () => { + stringUndefinedThrow(property); + }); + + it('should not accept a stringified null', () => { + stringNullThrow(property); + }); + + it('should not accept an empty string', () => { + emptyStringThrow(property); + }); + + it('should not accept values of other types', () => + validatePropOfSchema(schema, property, [ + 'emptyString', + 'stringNumber', + 'stringUndefined', + 'stringNull', + 'number', + 'undefined', + 'null' + ])); + } else { + it('should accept a stringified non-negative number value', () => { + const obj = { [property]: '0' }; + expect(schema.parse(obj)[property]).toBe(0); + obj[property] = '1000'; + expect(schema.parse(obj)[property]).toBe(1000); + }); + + it('should accept a stringified undefined and transform it to null', () => { + stringUndefinedToNull(property); + }); + + it('should accept a stringified null and transform it to null', () => { + stringNullToNull(property); + }); + + it('should accept an empty string and transform it to null', () => { + emptyStringToNull(property); + }); + + it('should not accept values of other types', () => + validatePropOfSchema(schema, property, [ + 'emptyString', + 'stringNumber', + 'stringUndefined', + 'stringNull', + 'number', + 'undefined', + 'null' + ])); + } + }, + + /** + * The svg validator. + */ + svg(property) { + it('should accept a string value that starts with the { + const obj = { + [property]: "..." + }; + expect(schema.parse(obj)[property]).toBe( + "..." + ); + obj[property] = + '...'; + expect(schema.parse(obj)[property]).toBe( + '...' + ); + }); + + it('should accept undefined', () => { + acceptUndefined(property); + }); + + it("should accept 'false', 'undefined', 'null', '' values and trasform to null", () => { + const obj = { [property]: 'false' }; + expect(schema.parse(obj)[property]).toBe(null); + obj[property] = 'undefined'; + expect(schema.parse(obj)[property]).toBe(null); + obj[property] = 'null'; + expect(schema.parse(obj)[property]).toBe(null); + obj[property] = ''; + expect(schema.parse(obj)[property]).toBe(null); + }); + + it('should accept null', () => { + acceptNull(property); + }); + + it('should accept a stringified undefined and transform it to null', () => { + stringUndefinedToNull(property); + }); + + it('should accept a stringified null and transform it to null', () => { + stringNullToNull(property); + }); + + it('should accept an empty string and transform it to null', () => { + emptyStringToNull(property); + }); + + it('should not accept values of other types', () => + validatePropOfSchema(schema, property, [ + 'emptyString', + 'string', + 'stringBoolean', + 'stringNumber', + 'stringBigInt', + 'stringUndefined', + 'stringNull', + 'stringSymbol', + 'stringObject', + 'stringArray', + 'stringFunction', + 'stringOther', + 'undefined', + 'null' + ])); + }, + + /** + * The chartConfig validator. + */ + chartConfig(property) { + it('should accept any object values', () => { + const obj = { [property]: {} }; + expect(schema.parse(obj)[property]).toEqual({}); + obj[property] = { a: 1 }; + expect(schema.parse(obj)[property]).toEqual({ a: 1 }); + obj[property] = { a: '1', b: { c: 3 } }; + expect(schema.parse(obj)[property]).toEqual({ a: '1', b: { c: 3 } }); + }); + + it("should accept a string value that starts with the '{' and ends with the '}'", () => { + const obj = { [property]: '{}' }; + expect(schema.parse(obj)[property]).toBe('{}'); + obj[property] = '{ a: 1 }'; + expect(schema.parse(obj)[property]).toBe('{ a: 1 }'); + obj[property] = '{ a: "1", b: { c: 3 } }'; + expect(schema.parse(obj)[property]).toBe('{ a: "1", b: { c: 3 } }'); + }); + + it('should accept a string value that starts with the { + const obj = { + [property]: "..." + }; + expect(schema.parse(obj)[property]).toBe( + "..." + ); + obj[property] = + '...'; + expect(schema.parse(obj)[property]).toBe( + '...' + ); + }); + + it('should not accept any array values', () => { + const obj = { [property]: [] }; + expect(() => schema.parse(obj)).toThrow(); + obj[property] = [1]; + expect(() => schema.parse(obj)).toThrow(); + obj[property] = ['a']; + expect(() => schema.parse(obj)).toThrow(); + obj[property] = [{ a: 1 }]; + expect(() => schema.parse(obj)).toThrow(); + }); + + it('should not accept any other object based values', () => { + const obj = { [property]: function () {} }; + expect(() => schema.parse(obj)).toThrow(); + obj[property] = () => {}; + expect(() => schema.parse(obj)).toThrow(); + obj[property] = new Date(); + expect(() => schema.parse(obj)).toThrow(); + }); + + it('should accept undefined', () => { + acceptUndefined(property); + }); + + it('should accept null', () => { + acceptNull(property); + }); + + it('should accept a stringified undefined and transform it to null', () => { + stringUndefinedToNull(property); + }); + + it('should accept a stringified null and transform it to null', () => { + stringNullToNull(property); + }); + + it('should accept an empty string and transform it to null', () => { + emptyStringToNull(property); + }); + + it('should not accept values of other types', () => + validatePropOfSchema(schema, property, [ + 'undefined', + 'null', + 'emptyString', + 'stringUndefined', + 'stringNull', + 'stringObject', + 'object', + 'other' + ])); + }, + + /** + * The additionalOptions validator. + */ + additionalOptions(property) { + it('should accept any object values', () => { + const obj = { [property]: {} }; + expect(schema.parse(obj)[property]).toEqual({}); + obj[property] = { a: 1 }; + expect(schema.parse(obj)[property]).toEqual({ a: 1 }); + obj[property] = { a: '1', b: { c: 3 } }; + expect(schema.parse(obj)[property]).toEqual({ a: '1', b: { c: 3 } }); + }); + + it("should accept a string value that starts with the '{' and ends with the '}'", () => { + const obj = { [property]: '{}' }; + expect(schema.parse(obj)[property]).toBe('{}'); + obj[property] = '{ a: 1 }'; + expect(schema.parse(obj)[property]).toBe('{ a: 1 }'); + obj[property] = '{ a: "1", b: { c: 3 } }'; + expect(schema.parse(obj)[property]).toBe('{ a: "1", b: { c: 3 } }'); + }); + + it('should accept string values that end with .json', () => { + const obj = { [property]: 'options.json' }; + expect(schema.parse(obj)[property]).toBe('options.json'); + }); + + it('should not accept string values that do not end with .json', () => { + const obj = { [property]: 'options.pdf' }; + expect(() => schema.parse(obj)).toThrow(); + obj[property] = 'options.png'; + expect(() => schema.parse(obj)).toThrow(); + }); + + it('should not accept string values that are not at least one character long without the extensions', () => { + const obj = { [property]: '.json' }; + expect(() => schema.parse(obj)).toThrow(); + }); + + it('should not accept any array values', () => { + const obj = { [property]: [] }; + expect(() => schema.parse(obj)).toThrow(); + obj[property] = [1]; + expect(() => schema.parse(obj)).toThrow(); + obj[property] = ['a']; + expect(() => schema.parse(obj)).toThrow(); + obj[property] = [{ a: 1 }]; + expect(() => schema.parse(obj)).toThrow(); + }); + + it('should not accept any other object based values', () => { + const obj = { [property]: function () {} }; + expect(() => schema.parse(obj)).toThrow(); + obj[property] = () => {}; + expect(() => schema.parse(obj)).toThrow(); + obj[property] = new Date(); + expect(() => schema.parse(obj)).toThrow(); + }); + + it('should accept undefined', () => { + acceptUndefined(property); + }); + + it('should accept null', () => { + acceptNull(property); + }); + + it('should accept a stringified undefined and transform it to null', () => { + stringUndefinedToNull(property); + }); + + it('should accept a stringified null and transform it to null', () => { + stringNullToNull(property); + }); + + it('should accept an empty string and transform it to null', () => { + emptyStringToNull(property); + }); + + it('should not accept values of other types', () => + validatePropOfSchema(schema, property, [ + 'undefined', + 'null', + 'emptyString', + 'stringUndefined', + 'stringNull', + 'stringObject', + 'object', + 'other' + ])); + }, + + /** + * The infile option validator. + */ + infile(property) { + it('should accept string values that end with .json or .svg', () => { + const obj = { [property]: 'chart.json' }; + expect(schema.parse(obj)[property]).toBe('chart.json'); + obj[property] = 'chart.svg'; + expect(schema.parse(obj)[property]).toBe('chart.svg'); + }); + + it('should not accept string values that do not end with .json or .svg', () => { + const obj = { [property]: 'chart.pdf' }; + expect(() => schema.parse(obj)).toThrow(); + obj[property] = 'chart.png'; + expect(() => schema.parse(obj)).toThrow(); + }); + + it('should not accept string values that are not at least one character long without the extensions', () => { + const obj = { [property]: '.json' }; + expect(() => schema.parse(obj)).toThrow(); + obj[property] = '.svg'; + expect(() => schema.parse(obj)).toThrow(); + }); + + it('should accept undefined', () => { + acceptUndefined(property); + }); + + it('should accept null', () => { + acceptNull(property); + }); + + if (strictCheck) { + it('should not accept a stringified undefined', () => { + stringUndefinedThrow(property); + }); + + it('should not accept a stringified null', () => { + stringNullThrow(property); + }); + + it('should not accept an empty string', () => { + emptyStringThrow(property); + }); + + it('should not accept values of other types', () => + validatePropOfSchema(schema, property, ['undefined', 'null'])); + } else { + it('should accept a stringified undefined and transform it to null', () => { + stringUndefinedToNull(property); + }); + + it('should accept a stringified null and transform it to null', () => { + stringNullToNull(property); + }); + + it('should accept an empty string and transform it to null', () => { + emptyStringToNull(property); + }); + + it('should not accept values of other types', () => + validatePropOfSchema(schema, property, [ + 'emptyString', + 'stringUndefined', + 'stringNull', + 'undefined', + 'null' + ])); + } + }, + + /** + * The outfile option validator. + */ + outfile(property) { + it('should accept string values that end with .jpeg, .jpg, .png, .pdf, or .svg', () => { + const obj = { [property]: 'chart.jpeg' }; + expect(schema.parse(obj)[property]).toBe('chart.jpeg'); + obj[property] = 'chart.jpg'; + expect(schema.parse(obj)[property]).toBe('chart.jpg'); + obj[property] = 'chart.png'; + expect(schema.parse(obj)[property]).toBe('chart.png'); + obj[property] = 'chart.pdf'; + expect(schema.parse(obj)[property]).toBe('chart.pdf'); + obj[property] = 'chart.svg'; + expect(schema.parse(obj)[property]).toBe('chart.svg'); + }); + + it('should not accept string values that do not end with .jpeg, .jpg, .png, .pdf, or .svg', () => { + const obj = { [property]: 'chart.json' }; + expect(() => schema.parse(obj)).toThrow(); + obj[property] = 'chart.txt'; + expect(() => schema.parse(obj)).toThrow(); + }); + + it('should not accept string values that are not at least one character long without the extensions', () => { + const obj = { [property]: '.jpeg' }; + expect(() => schema.parse(obj)).toThrow(); + obj[property] = '.jpg'; + expect(() => schema.parse(obj)).toThrow(); + obj[property] = '.png'; + expect(() => schema.parse(obj)).toThrow(); + obj[property] = '.pdf'; + expect(() => schema.parse(obj)).toThrow(); + obj[property] = '.svg'; + expect(() => schema.parse(obj)).toThrow(); + }); + + it('should accept undefined', () => { + acceptUndefined(property); + }); + + it('should accept null', () => { + acceptNull(property); + }); + + if (strictCheck) { + it('should not accept a stringified undefined', () => { + stringUndefinedThrow(property); + }); + + it('should not accept a stringified null', () => { + stringNullThrow(property); + }); + + it('should not accept an empty string', () => { + emptyStringThrow(property); + }); + + it('should not accept values of other types', () => + validatePropOfSchema(schema, property, ['undefined', 'null'])); + } else { + it('should accept a stringified undefined and transform it to null', () => { + stringUndefinedToNull(property); + }); + + it('should accept a stringified null and transform it to null', () => { + stringNullToNull(property); + }); + + it('should accept an empty string and transform it to null', () => { + emptyStringToNull(property); + }); + + it('should not accept values of other types', () => + validatePropOfSchema(schema, property, [ + 'emptyString', + 'stringUndefined', + 'stringNull', + 'undefined', + 'null' + ])); + } + }, + + /** + * The version option validator. + */ + version(property) { + it("should accept the 'latest' value", () => { + const obj = { [property]: 'latest' }; + expect(schema.parse(obj)[property]).toBe('latest'); + }); + + it('should accept a value in XX, XX.YY, XX.YY.ZZ formats', () => { + const obj = { [property]: '1' }; + expect(schema.parse(obj)[property]).toBe('1'); + obj[property] = '11'; + expect(schema.parse(obj)[property]).toBe('11'); + obj[property] = '1.1'; + expect(schema.parse(obj)[property]).toBe('1.1'); + obj[property] = '1.11'; + expect(schema.parse(obj)[property]).toBe('1.11'); + obj[property] = '11.1'; + expect(schema.parse(obj)[property]).toBe('11.1'); + obj[property] = '11.11'; + expect(schema.parse(obj)[property]).toBe('11.11'); + obj[property] = '1.1.1'; + expect(schema.parse(obj)[property]).toBe('1.1.1'); + obj[property] = '1.1.11'; + expect(schema.parse(obj)[property]).toBe('1.1.11'); + obj[property] = '1.11.1'; + expect(schema.parse(obj)[property]).toBe('1.11.1'); + obj[property] = '1.11.11'; + expect(schema.parse(obj)[property]).toBe('1.11.11'); + obj[property] = '11.1.1'; + expect(schema.parse(obj)[property]).toBe('11.1.1'); + obj[property] = '11.1.11'; + expect(schema.parse(obj)[property]).toBe('11.1.11'); + obj[property] = '11.11.1'; + expect(schema.parse(obj)[property]).toBe('11.11.1'); + obj[property] = '11.11.11'; + expect(schema.parse(obj)[property]).toBe('11.11.11'); + }); + + it('should not accept other string value', () => { + const obj = { [property]: 'string-other-than-latest' }; + expect(() => schema.parse(obj)).toThrow(); + obj[property] = '11a.2.0'; + expect(() => schema.parse(obj)).toThrow(); + obj[property] = '11.2.123'; + expect(() => schema.parse(obj)).toThrow(); + }); + + it('should accept undefined', () => { + acceptUndefined(property); + }); + + if (strictCheck) { + it('should not accept null', () => { + nullThrow(property); + }); + + it('should not accept a stringified undefined', () => { + stringUndefinedThrow(property); + }); + + it('should not accept a stringified null', () => { + stringNullThrow(property); + }); + + it('should not accept an empty string', () => { + emptyStringThrow(property); + }); + + it('should not accept values of other types', () => + validatePropOfSchema(schema, property, [ + 'stringNumber', + 'undefined' + ])); + } else { + it('should accept null', () => { + acceptNull(property); + }); + + it('should accept a stringified undefined and transform it to null', () => { + stringUndefinedToNull(property); + }); + + it('should accept a stringified null and transform it to null', () => { + stringNullToNull(property); + }); + + it('should accept an empty string and transform it to null', () => { + emptyStringToNull(property); + }); + + it('should not accept values of other types', () => + validatePropOfSchema(schema, property, [ + 'emptyString', + 'stringNumber', + 'stringUndefined', + 'stringNull', + 'undefined', + 'null' + ])); + } + }, + + /** + * The scale option validator. + */ + scale(property) { + it('should accept number values between the 0.1 and 5.0', () => { + const obj = { [property]: 0.1 }; + expect(schema.parse(obj)[property]).toBe(0.1); + obj[property] = 1; + expect(schema.parse(obj)[property]).toBe(1); + obj[property] = 1.5; + expect(schema.parse(obj)[property]).toBe(1.5); + obj[property] = 5; + expect(schema.parse(obj)[property]).toBe(5); + }); + + it('should not accept number values outside the 0.1 and 5.0', () => { + const obj = { [property]: -1.1 }; + expect(() => schema.parse(obj)).toThrow(); + obj[property] = 0; + expect(() => schema.parse(obj)).toThrow(); + obj[property] = 5.5; + expect(() => schema.parse(obj)).toThrow(); + }); + + it('should not accept stringified number values outside the 0.1 and 5.0', () => { + const obj = { [property]: '-1.1' }; + expect(() => schema.parse(obj)).toThrow(); + obj[property] = '0'; + expect(() => schema.parse(obj)).toThrow(); + obj[property] = '5.5'; + expect(() => schema.parse(obj)).toThrow(); + }); + + it('should accept undefined', () => { + acceptUndefined(property); + }); + + if (strictCheck) { + it('should not accept stringified number values between the 0.1 and 5.0', () => { + const obj = { [property]: '0.1' }; + expect(() => schema.parse(obj)).toThrow(); + obj[property] = '1'; + expect(() => schema.parse(obj)).toThrow(); + obj[property] = '1.5'; + expect(() => schema.parse(obj)).toThrow(); + obj[property] = '5'; + expect(() => schema.parse(obj)).toThrow(); + }); + + it('should not accept null', () => { + nullThrow(property); + }); + + it('should not accept a stringified undefined', () => { + stringUndefinedThrow(property); + }); + + it('should not accept a stringified null', () => { + stringNullThrow(property); + }); + + it('should not accept an empty string', () => { + emptyStringThrow(property); + }); + + it('should not accept values of other types', () => + validatePropOfSchema(schema, property, ['number', 'undefined'])); + } else { + it('should accept stringified number values between the 0.1 and 5.0', () => { + const obj = { [property]: '0.1' }; + expect(schema.parse(obj)[property]).toBe(0.1); + obj[property] = '1'; + expect(schema.parse(obj)[property]).toBe(1); + obj[property] = '1.5'; + expect(schema.parse(obj)[property]).toBe(1.5); + obj[property] = '5'; + expect(schema.parse(obj)[property]).toBe(5); + }); + + it('should accept null', () => { + acceptNull(property); + }); + + it('should accept a stringified undefined and transform it to null', () => { + stringUndefinedToNull(property); + }); + + it('should accept a stringified null and transform it to null', () => { + stringNullToNull(property); + }); + + it('should accept an empty string and transform it to null', () => { + emptyStringToNull(property); + }); + + it('should not accept values of other types', () => + validatePropOfSchema(schema, property, [ + 'emptyString', + 'stringNumber', + 'stringUndefined', + 'stringNull', + 'number', + 'undefined', + 'null' + ])); + } + }, + + /** + * The nullable scale option validator. + */ + nullableScale(property) { + it('should accept number values between the 0.1 and 5.0', () => { + const obj = { [property]: 0.1 }; + expect(schema.parse(obj)[property]).toBe(0.1); + obj[property] = 1; + expect(schema.parse(obj)[property]).toBe(1); + obj[property] = 1.5; + expect(schema.parse(obj)[property]).toBe(1.5); + obj[property] = 5; + expect(schema.parse(obj)[property]).toBe(5); + }); + + it('should not accept number values outside the 0.1 and 5.0', () => { + const obj = { [property]: -1.1 }; + expect(() => schema.parse(obj)).toThrow(); + obj[property] = 0; + expect(() => schema.parse(obj)).toThrow(); + obj[property] = 5.5; + expect(() => schema.parse(obj)).toThrow(); + }); + + it('should not accept stringified number values outside the 0.1 and 5.0', () => { + const obj = { [property]: '-1.1' }; + expect(() => schema.parse(obj)).toThrow(); + obj[property] = '0'; + expect(() => schema.parse(obj)).toThrow(); + obj[property] = '5.5'; + expect(() => schema.parse(obj)).toThrow(); + }); + + it('should accept undefined', () => { + acceptUndefined(property); + }); + + it('should accept null', () => { + acceptNull(property); + }); + + if (strictCheck) { + it('should not accept stringified number values between the 0.1 and 5.0', () => { + const obj = { [property]: '0.1' }; + expect(() => schema.parse(obj)).toThrow(); + obj[property] = '1'; + expect(() => schema.parse(obj)).toThrow(); + obj[property] = '1.5'; + expect(() => schema.parse(obj)).toThrow(); + obj[property] = '5'; + expect(() => schema.parse(obj)).toThrow(); + }); + + it('should not accept a stringified undefined', () => { + stringUndefinedThrow(property); + }); + + it('should not accept a stringified null', () => { + stringNullThrow(property); + }); + + it('should not accept an empty string', () => { + emptyStringThrow(property); + }); + + it('should not accept values of other types', () => + validatePropOfSchema(schema, property, [ + 'number', + 'undefined', + 'null' + ])); + } else { + it('should accept stringified number values between the 0.1 and 5.0', () => { + const obj = { [property]: '0.1' }; + expect(schema.parse(obj)[property]).toBe(0.1); + obj[property] = '1'; + expect(schema.parse(obj)[property]).toBe(1); + obj[property] = '1.5'; + expect(schema.parse(obj)[property]).toBe(1.5); + obj[property] = '5'; + expect(schema.parse(obj)[property]).toBe(5); + }); + + it('should accept a stringified undefined and transform it to null', () => { + stringUndefinedToNull(property); + }); + + it('should accept a stringified null and transform it to null', () => { + stringNullToNull(property); + }); + + it('should accept an empty string and transform it to null', () => { + emptyStringToNull(property); + }); + + it('should not accept values of other types', () => + validatePropOfSchema(schema, property, [ + 'emptyString', + 'stringNumber', + 'stringUndefined', + 'stringNull', + 'number', + 'undefined', + 'null' + ])); + } + }, + + /** + * The logLevel option validator. + */ + logLevel(property) { + it('should accept integer number values between the 0 and 5', () => { + const obj = { [property]: 0 }; + expect(schema.parse(obj)[property]).toBe(0); + obj[property] = 1; + expect(schema.parse(obj)[property]).toBe(1); + obj[property] = 3; + expect(schema.parse(obj)[property]).toBe(3); + obj[property] = 5; + expect(schema.parse(obj)[property]).toBe(5); + }); + + it('should not accept float number values between the 0 and 5', () => { + const obj = { [property]: 0.1 }; + expect(() => schema.parse(obj)).toThrow(); + obj[property] = 1.1; + expect(() => schema.parse(obj)).toThrow(); + obj[property] = 3.1; + expect(() => schema.parse(obj)).toThrow(); + obj[property] = 4.1; + expect(() => schema.parse(obj)).toThrow(); + }); + + it('should not accept stringified float number values between the 0 and 5', () => { + const obj = { [property]: '0.1' }; + expect(() => schema.parse(obj)).toThrow(); + obj[property] = '1.1'; + expect(() => schema.parse(obj)).toThrow(); + obj[property] = '3.1'; + expect(() => schema.parse(obj)).toThrow(); + obj[property] = '4.1'; + expect(() => schema.parse(obj)).toThrow(); + }); + + it('should not accept number values that fall outside the 0 and 5 range', () => { + const obj = { [property]: -1.1 }; + expect(() => schema.parse(obj)).toThrow(); + obj[property] = 6; + expect(() => schema.parse(obj)).toThrow(); + }); + + it('should not accept stringified number number values that fall outside the 0 and 5 range', () => { + const obj = { [property]: '-1.1' }; + expect(() => schema.parse(obj)).toThrow(); + obj[property] = '6'; + expect(() => schema.parse(obj)).toThrow(); + }); + + it('should accept undefined', () => { + acceptUndefined(property); + }); + + if (strictCheck) { + it('should not accept null', () => { + nullThrow(property); + }); + + it('should not accept a stringified undefined', () => { + stringUndefinedThrow(property); + }); + + it('should not accept a stringified null', () => { + stringNullThrow(property); + }); + + it('should not accept an empty string', () => { + emptyStringThrow(property); + }); + + it('should not accept values of other types', () => + validatePropOfSchema(schema, property, ['number', 'undefined'])); + } else { + it('should accept stringified number values between the 0 and 5', () => { + const obj = { [property]: '0' }; + expect(schema.parse(obj)[property]).toBe(0); + obj[property] = '1'; + expect(schema.parse(obj)[property]).toBe(1); + obj[property] = '3'; + expect(schema.parse(obj)[property]).toBe(3); + obj[property] = '5'; + expect(schema.parse(obj)[property]).toBe(5); + }); + + it('should accept null', () => { + acceptNull(property); + }); + + it('should accept a stringified undefined and transform it to null', () => { + stringUndefinedToNull(property); + }); + + it('should accept a stringified null and transform it to null', () => { + stringNullToNull(property); + }); + + it('should accept an empty string and transform it to null', () => { + emptyStringToNull(property); + }); + + it('should not accept values of other types', () => + validatePropOfSchema(schema, property, [ + 'emptyString', + 'stringNumber', + 'stringUndefined', + 'stringNull', + 'number', + 'undefined', + 'null' + ])); + } + }, + + /** + * The logFile option validator. + */ + logFile(property, strictCheck) { + it('should accept a string value that ends with the .log extension and is at least one character long without the extension', () => { + const obj = { [property]: 'text.log' }; + expect(schema.parse(obj)[property]).toBe('text.log'); + obj[property] = 't.log'; + expect(schema.parse(obj)[property]).toBe('t.log'); + }); + + it('should not accept a string value that does not end with the .log extension or is not at least one character long without the extension', () => { + const obj = { [property]: 'text' }; + expect(() => schema.parse(obj)).toThrow(); + obj[property] = '.log'; + expect(() => schema.parse(obj)).toThrow(); + }); + + it('should accept undefined', () => { + acceptUndefined(property); + }); + + if (strictCheck) { + it("should not accept 'false', 'undefined', 'null', '' values", () => { + const obj = { [property]: 'false' }; + expect(() => schema.parse(obj)).toThrow(); + obj[property] = 'undefined'; + expect(() => schema.parse(obj)).toThrow(); + obj[property] = 'null'; + expect(() => schema.parse(obj)).toThrow(); + obj[property] = ''; + expect(() => schema.parse(obj)).toThrow(); + }); + + it('should not accept null', () => { + nullThrow(property); + }); + + it('should not accept a stringified undefined', () => { + stringUndefinedThrow(property); + }); + + it('should not accept a stringified null', () => { + stringNullThrow(property); + }); + + it('should not accept an empty string', () => { + emptyStringThrow(property); + }); + + it('should not accept values of other types', () => + validatePropOfSchema(schema, property, [ + 'string', + 'stringBoolean', + 'stringNumber', + 'stringBigInt', + 'stringSymbol', + 'stringObject', + 'stringArray', + 'stringFunction', + 'stringOther', + 'undefined' + ])); + } else { + it("should accept 'false', 'undefined', 'null', '' values and trasform to null", () => { + const obj = { [property]: 'false' }; + expect(schema.parse(obj)[property]).toBe(null); + obj[property] = 'undefined'; + expect(schema.parse(obj)[property]).toBe(null); + obj[property] = 'null'; + expect(schema.parse(obj)[property]).toBe(null); + obj[property] = ''; + expect(schema.parse(obj)[property]).toBe(null); + }); + + it('should accept null', () => { + acceptNull(property); + }); + + it('should accept a stringified undefined and transform it to null', () => { + stringUndefinedToNull(property); + }); + + it('should accept a stringified null and transform it to null', () => { + stringNullToNull(property); + }); + + it('should accept an empty string and transform it to null', () => { + emptyStringToNull(property); + }); + + it('should not accept values of other types', () => + validatePropOfSchema(schema, property, [ + 'emptyString', + 'string', + 'stringBoolean', + 'stringNumber', + 'stringBigInt', + 'stringUndefined', + 'stringNull', + 'stringSymbol', + 'stringObject', + 'stringArray', + 'stringFunction', + 'stringOther', + 'undefined', + 'null' + ])); + } + }, + + /** + * The resources option validator. + */ + resources(property) { + it("should accept an object with properties 'js', 'css', and 'files'", () => { + const obj = { [property]: { js: '', css: '', files: [] } }; + expect(schema.parse(obj)[property]).toEqual({ + js: null, + css: null, + files: [] + }); + }); + + it("should accept an object with properties 'js', 'css', and 'files' with null values", () => { + const obj = { [property]: { js: null, css: null, files: null } }; + expect(schema.parse(obj)[property]).toEqual({ + js: null, + css: null, + files: null + }); + }); + + it("should accept a partial object with some properties from the 'js', 'css', and 'files'", () => { + const obj = { [property]: { js: 'console.log(1);' } }; + expect(schema.parse(obj)[property]).toEqual({ js: 'console.log(1);' }); + }); + + it("should accept a stringified object with properties 'js', 'css', and 'files'", () => { + const obj = { [property]: "{ js: '', css: '', files: [] }" }; + expect(schema.parse(obj)[property]).toBe( + "{ js: '', css: '', files: [] }" + ); + }); + + it("should accept a stringified object with properties 'js', 'css', and 'files' with null values", () => { + const obj = { [property]: '{ js: null, css: null, files: null }' }; + expect(schema.parse(obj)[property]).toBe( + '{ js: null, css: null, files: null }' + ); + }); + + it("should accept a stringified partial object with some properties from the 'js', 'css', and 'files'", () => { + const obj = { [property]: "{ js: 'console.log(1);' }" }; + expect(schema.parse(obj)[property]).toBe("{ js: 'console.log(1);' }"); + }); + + it('should accept string values that end with .json', () => { + const obj = { [property]: 'resources.json' }; + expect(schema.parse(obj)[property]).toBe('resources.json'); + }); + + it('should not accept string values that do not end with .json', () => { + const obj = { [property]: 'resources.js' }; + expect(() => schema.parse(obj)).toThrow(); + }); + + it('should not accept string values that are not at least one character long without the extensions', () => { + const obj = { [property]: '.json' }; + expect(() => schema.parse(obj)).toThrow(); + }); + + it('should accept undefined', () => { + acceptUndefined(property); + }); + + it('should accept null', () => { + acceptNull(property); + }); + + if (strictCheck) { + it('should not accept a stringified undefined', () => { + stringUndefinedThrow(property); + }); + + it('should not accept a stringified null', () => { + stringNullThrow(property); + }); + + it('should not accept an empty string', () => { + emptyStringThrow(property); + }); + + it('should not accept values of other types', () => + validatePropOfSchema(schema, property, [ + 'stringObject', + 'object', + 'other', + 'undefined', + 'null' + ])); + } else { + it('should accept a stringified undefined and transform it to null', () => { + stringUndefinedToNull(property); + }); + + it('should accept a stringified null and transform it to null', () => { + stringNullToNull(property); + }); + + it('should accept an empty string and transform it to null', () => { + emptyStringToNull(property); + }); + + it('should not accept values of other types', () => + validatePropOfSchema(schema, property, [ + 'emptyString', + 'stringObject', + 'stringUndefined', + 'stringNull', + 'object', + 'other', + 'undefined', + 'null' + ])); + } + }, + + /** + * The createConfig/loadConfig options validator. + */ + customConfig(property, strictCheck) { + it('should accept a string value that ends with the .json extension and is at least one character long without the extension', () => { + const obj = { [property]: 'text.json' }; + expect(schema.parse(obj)[property]).toBe('text.json'); + obj[property] = 't.json'; + expect(schema.parse(obj)[property]).toBe('t.json'); + }); + + it('should not accept a string value that does not end with the .json extension or is not at least one character long without the extension', () => { + const obj = { [property]: 'text' }; + expect(() => schema.parse(obj)).toThrow(); + obj[property] = '.json'; + expect(() => schema.parse(obj)).toThrow(); + }); + + it('should accept undefined', () => { + acceptUndefined(property); + }); + + if (strictCheck) { + it("should not accept 'false', 'undefined', 'null', '' values", () => { + const obj = { [property]: 'false' }; + expect(() => schema.parse(obj)).toThrow(); + obj[property] = 'undefined'; + expect(() => schema.parse(obj)).toThrow(); + obj[property] = 'null'; + expect(() => schema.parse(obj)).toThrow(); + obj[property] = ''; + expect(() => schema.parse(obj)).toThrow(); + }); + + it('should not accept null', () => { + nullThrow(property); + }); + + it('should not accept a stringified undefined', () => { + stringUndefinedThrow(property); + }); + + it('should not accept a stringified null', () => { + stringNullThrow(property); + }); + + it('should not accept an empty string', () => { + emptyStringThrow(property); + }); + + it('should not accept values of other types', () => + validatePropOfSchema(schema, property, [ + 'string', + 'stringBoolean', + 'stringNumber', + 'stringBigInt', + 'stringSymbol', + 'stringObject', + 'stringArray', + 'stringFunction', + 'stringOther', + 'undefined' + ])); + } else { + it("should accept 'false', 'undefined', 'null', '' values and trasform to null", () => { + const obj = { [property]: 'false' }; + expect(schema.parse(obj)[property]).toBe(null); + obj[property] = 'undefined'; + expect(schema.parse(obj)[property]).toBe(null); + obj[property] = 'null'; + expect(schema.parse(obj)[property]).toBe(null); + obj[property] = ''; + expect(schema.parse(obj)[property]).toBe(null); + }); + + it('should accept null', () => { + acceptNull(property); + }); + + it('should accept a stringified undefined and transform it to null', () => { + stringUndefinedToNull(property); + }); + + it('should accept a stringified null and transform it to null', () => { + stringNullToNull(property); + }); + + it('should accept an empty string and transform it to null', () => { + emptyStringToNull(property); + }); + + it('should not accept values of other types', () => + validatePropOfSchema(schema, property, [ + 'emptyString', + 'string', + 'stringBoolean', + 'stringNumber', + 'stringBigInt', + 'stringUndefined', + 'stringNull', + 'stringSymbol', + 'stringObject', + 'stringArray', + 'stringFunction', + 'stringOther', + 'undefined', + 'null' + ])); + } + }, + + /** + * The config object validator. + */ + configObject(property, value) { + it(`should accept an object with the ${property} properties`, () => { + const obj = { [property]: value }; + expect(schema.parse(obj)[property]).toEqual(value); + }); + + it(`should accept an object with the ${property} properties and filter out other properties`, () => { + const obj = { [property]: { ...value, extraProp: true } }; + expect(schema.parse(obj)[property]).toEqual({ ...value }); + }); + + it(`should accept a partial object with some ${property} properties`, () => { + for (const [key, val] of Object.entries(value)) { + expect( + schema.parse({ [property]: { [key]: val } })[property] + ).toEqual({ [key]: val }); + } + expect( + schema.parse({ [property]: { extraProp: true } })[property] + ).toEqual({}); + }); + + it('should accept object with no properties and transform it to undefined', () => { + const obj = {}; + expect(schema.parse(obj)[property]).toBe(undefined); + }); + + it('should accept undefined', () => { + acceptUndefined(property); + }); + + it('should not accept values of other types', () => + validatePropOfSchema(schema, property, [ + 'undefined', + 'object', + 'other' + ])); + }, + + /** + * The requestId validator. + */ + requestId(property) { + it('should accept a correct UUID string value', () => { + const obj = { [property]: 'b012bde4-8b91-4d68-8b48-cd099358a17f' }; + expect(schema.parse(obj)[property]).toBe( + 'b012bde4-8b91-4d68-8b48-cd099358a17f' + ); + obj[property] = '0694de13-ac56-44f9-813c-1c91674e6a19'; + expect(schema.parse(obj)[property]).toBe( + '0694de13-ac56-44f9-813c-1c91674e6a19' + ); + }); + + it('should accept undefined', () => { + acceptUndefined(property); + }); + + it('should accept null', () => { + acceptNull(property); + }); + + it("should not accept 'false', 'undefined', 'null', '' values", () => { + const obj = { [property]: 'false' }; + expect(() => schema.parse(obj)).toThrow(); + obj[property] = 'undefined'; + expect(() => schema.parse(obj)).toThrow(); + obj[property] = 'null'; + expect(() => schema.parse(obj)).toThrow(); + obj[property] = ''; + expect(() => schema.parse(obj)).toThrow(); + }); + + it('should not accept a stringified undefined', () => { + stringUndefinedThrow(property); + }); + + it('should not accept a stringified null', () => { + stringNullThrow(property); + }); + + it('should not accept an empty string', () => { + emptyStringThrow(property); + }); + + it('should not accept values of other types', () => + validatePropOfSchema(schema, property, ['null', 'undefined'])); + } + }; + + // The options config validation tests + return { + puppeteer: (property, value) => { + describe(property, () => validationTests.configObject(property, value)); + }, + puppeteerArgs: (property, value, filteredValue) => { + describe(property, () => + validationTests.stringArray(property, value, filteredValue, ';') + ); + }, + highcharts: (property, value) => { + describe(property, () => validationTests.configObject(property, value)); + }, + highchartsVersion: (property) => { + describe(property, () => validationTests.version(property)); + }, + highchartsCdnUrl: (property, correctValue, incorrectValue) => { + describe(property, () => + validationTests.acceptValues(property, correctValue, incorrectValue) + ); + }, + highchartsForceFetch: (property) => { + describe(property, () => validationTests.boolean(property)); + }, + highchartsCachePath: (property) => { + describe(property, () => validationTests.string(property, strictCheck)); + }, + highchartsAdminToken: (property) => { + describe(property, () => validationTests.string(property, false)); + }, + highchartsCoreScripts: (property, value, filteredValue) => { + describe(property, () => + validationTests.stringArray(property, value, filteredValue) + ); + }, + highchartsModuleScripts: (property, value, filteredValue) => { + describe(property, () => + validationTests.stringArray(property, value, filteredValue) + ); + }, + highchartsIndicatorScripts: (property, value, filteredValue) => { + describe(property, () => + validationTests.stringArray(property, value, filteredValue) + ); + }, + highchartsCustomScripts: (property, value, filteredValue) => { + describe(property, () => + validationTests.stringArray(property, value, filteredValue) + ); + }, + export: (property, value) => { + describe(property, () => validationTests.configObject(property, value)); + }, + exportInfile: (property) => { + describe(property, () => validationTests.infile(property)); + }, + exportInstr: (property) => { + describe(property, () => validationTests.chartConfig(property, false)); + }, + exportOptions: (property) => { + describe(property, () => validationTests.chartConfig(property, false)); + }, + exportSvg: (property) => { + describe(property, () => validationTests.svg(property)); + }, + exportOutfile: (property) => { + describe(property, () => validationTests.outfile(property)); + }, + exportType: (property, correctValue, incorrectValue) => { + describe(property, () => + validationTests.acceptValues(property, correctValue, incorrectValue) + ); + }, + exportConstr: (property, correctValue, incorrectValue) => { + describe(property, () => + validationTests.acceptValues(property, correctValue, incorrectValue) + ); + }, + exportB64: (property) => { + describe(property, () => validationTests.boolean(property)); + }, + exportNoDownload: (property) => { + describe(property, () => validationTests.boolean(property)); + }, + exportDefaultHeight: (property) => { + describe(property, () => validationTests.positiveNum(property)); + }, + exportDefaultWidth: (property) => { + describe(property, () => validationTests.positiveNum(property)); + }, + exportDefaultScale: (property) => { + describe(property, () => validationTests.scale(property)); + }, + exportHeight: (property) => { + describe(property, () => validationTests.nullablePositiveNum(property)); + }, + exportWidth: (property) => { + describe(property, () => validationTests.nullablePositiveNum(property)); + }, + exportScale: (property) => { + describe(property, () => validationTests.nullableScale(property)); + }, + exportGlobalOptions: (property) => { + describe(property, () => + validationTests.additionalOptions(property, false) + ); + }, + exportThemeOptions: (property) => { + describe(property, () => + validationTests.additionalOptions(property, false) + ); + }, + exportBatch: (property) => { + describe(property, () => validationTests.string(property, false)); + }, + exportRasterizationTimeout: (property) => { + describe(property, () => validationTests.nonNegativeNum(property)); + }, + customLogic: (property, value) => { + describe(property, () => validationTests.configObject(property, value)); + }, + customLogicAllowCodeExecution: (property) => { + describe(property, () => validationTests.boolean(property)); + }, + customLogicAllowFileResources: (property) => { + describe(property, () => validationTests.boolean(property)); + }, + customLogicCustomCode: (property) => { + describe(property, () => validationTests.string(property, false)); + }, + customLogicCallback: (property) => { + describe(property, () => validationTests.string(property, false)); + }, + customLogicResources: (property) => { + describe(property, () => validationTests.resources(property)); + }, + customLogicLoadConfig: (property) => { + describe(property, () => validationTests.customConfig(property, false)); + }, + customLogicCreateConfig: (property) => { + describe(property, () => validationTests.customConfig(property, false)); + }, + server: (property, value) => { + describe(property, () => validationTests.configObject(property, value)); + }, + serverEnable: (property) => { + describe(property, () => validationTests.boolean(property)); + }, + serverHost: (property) => { + describe(property, () => validationTests.string(property, strictCheck)); + }, + serverPort: (property) => { + describe(property, () => validationTests.nonNegativeNum(property)); + }, + serverBenchmarking: (property) => { + describe(property, () => validationTests.boolean(property)); + }, + serverProxy: (property, value) => { + describe(property, () => validationTests.configObject(property, value)); + }, + serverProxyHost: (property) => { + describe(property, () => validationTests.string(property, false)); + }, + serverProxyPort: (property) => { + describe(property, () => + validationTests.nullableNonNegativeNum(property) + ); + }, + serverProxyTimeout: (property) => { + describe(property, () => validationTests.nonNegativeNum(property)); + }, + serverRateLimiting: (property, value) => { + describe(property, () => validationTests.configObject(property, value)); + }, + serverRateLimitingEnable: (property) => { + describe(property, () => validationTests.boolean(property)); + }, + serverRateLimitingMaxRequests: (property) => { + describe(property, () => validationTests.nonNegativeNum(property)); + }, + serverRateLimitingWindow: (property) => { + describe(property, () => validationTests.nonNegativeNum(property)); + }, + serverRateLimitingDelay: (property) => { + describe(property, () => validationTests.nonNegativeNum(property)); + }, + serverRateLimitingTrustProxy: (property) => { + describe(property, () => validationTests.boolean(property)); + }, + serverRateLimitingSkipKey: (property) => { + describe(property, () => validationTests.string(property, false)); + }, + serverRateLimitingSkipToken: (property) => { + describe(property, () => validationTests.string(property, false)); + }, + serverSsl: (property, value) => { + describe(property, () => validationTests.configObject(property, value)); + }, + serverSslEnable: (property) => { + describe(property, () => validationTests.boolean(property)); + }, + serverSslForce: (property) => { + describe(property, () => validationTests.boolean(property)); + }, + serverSslPort: (property) => { + describe(property, () => validationTests.nonNegativeNum(property)); + }, + serverSslCertPath: (property) => { + describe(property, () => validationTests.string(property, false)); + }, + pool: (property, value) => { + describe(property, () => validationTests.configObject(property, value)); + }, + poolMinWorkers: (property) => { + describe(property, () => validationTests.positiveNum(property)); + }, + poolMaxWorkers: (property) => { + describe(property, () => validationTests.positiveNum(property)); + }, + poolWorkLimit: (property) => { + describe(property, () => validationTests.positiveNum(property)); + }, + poolAcquireTimeout: (property) => { + describe(property, () => validationTests.nonNegativeNum(property)); + }, + poolCreateTimeout: (property) => { + describe(property, () => validationTests.nonNegativeNum(property)); + }, + poolDestroyTimeout: (property) => { + describe(property, () => validationTests.nonNegativeNum(property)); + }, + poolIdleTimeout: (property) => { + describe(property, () => validationTests.nonNegativeNum(property)); + }, + poolCreateRetryInterval: (property) => { + describe(property, () => validationTests.nonNegativeNum(property)); + }, + poolReaperInterval: (property) => { + describe(property, () => validationTests.nonNegativeNum(property)); + }, + poolBenchmarking: (property) => { + describe(property, () => validationTests.boolean(property)); + }, + logging: (property, value) => { + describe(property, () => validationTests.configObject(property, value)); + }, + loggingLevel: (property) => { + describe(property, () => validationTests.logLevel(property, strictCheck)); + }, + loggingFile: (property) => { + describe(property, () => validationTests.logFile(property, strictCheck)); + }, + loggingDest: (property) => { + describe(property, () => validationTests.string(property, strictCheck)); + }, + loggingToConsole: (property) => { + describe(property, () => validationTests.boolean(property)); + }, + loggingToFile: (property) => { + describe(property, () => validationTests.boolean(property)); + }, + ui: (property, value) => { + describe(property, () => validationTests.configObject(property, value)); + }, + uiEnable: (property) => { + describe(property, () => validationTests.boolean(property)); + }, + uiRoute: (property, correctValue, incorrectValue) => { + describe(property, () => + validationTests.acceptValues(property, correctValue, incorrectValue) + ); + }, + other: (property, value) => { + describe(property, () => validationTests.configObject(property, value)); + }, + otherNodeEnv: (property, correctValue, incorrectValue) => { + describe(property, () => + validationTests.acceptValues(property, correctValue, incorrectValue) + ); + }, + otherListenToProcessExits: (property) => { + describe(property, () => validationTests.boolean(property)); + }, + otherNoLogo: (property) => { + describe(property, () => validationTests.boolean(property)); + }, + otherHardResetPage: (property) => { + describe(property, () => validationTests.boolean(property)); + }, + otherBrowserShellMode: (property) => { + describe(property, () => validationTests.boolean(property)); + }, + debug: (property, value) => { + describe(property, () => validationTests.configObject(property, value)); + }, + debugEnable: (property) => { + describe(property, () => validationTests.boolean(property)); + }, + debugHeadless: (property) => { + describe(property, () => validationTests.boolean(property)); + }, + debugDevtools: (property) => { + describe(property, () => validationTests.boolean(property)); + }, + debugListenToConsole: (property) => { + describe(property, () => validationTests.boolean(property)); + }, + debugDumpio: (property) => { + describe(property, () => validationTests.boolean(property)); + }, + debugSlowMo: (property) => { + describe(property, () => validationTests.nonNegativeNum(property)); + }, + debugDebuggingPort: (property) => { + describe(property, () => validationTests.nonNegativeNum(property)); + }, + payload: (property, value) => { + describe(property, () => validationTests.configObject(property, value)); + }, + payloadRequestId: (property) => { + describe(property, () => validationTests.requestId(property)); + } + }; +} diff --git a/tests/utils/testUtils.js b/tests/utils/testUtils.js new file mode 100644 index 00000000..18fd8176 --- /dev/null +++ b/tests/utils/testUtils.js @@ -0,0 +1,129 @@ +/******************************************************************************* + +Highcharts Export Server + +Copyright (c) 2016-2024, Highsoft + +Licenced under the MIT licence. + +Additionally a valid Highcharts license is required for use. + +See LICENSE file in root for details. + +*******************************************************************************/ + +/** + * @overview Provides utilities for Jest tests to validate schema properties + * and test value parsing. This module includes a comprehensive set + * of categorized test values, functions for filtering these values based + * on type categories, and a utility for validating specific schema properties + * against allowed and disallowed types. + */ + +import { expect } from '@jest/globals'; + +/** + * A collection of possible values for various data types used in Jest tests, + * categorized by specific types and their stringified versions. + */ +export const possibleValues = { + // String + emptyString: [''], + string: ['string', '1.0.1.0.1'], + + // Boolean + boolean: [true, false], + stringBoolean: ['true', 'false'], + + // Number + number: [0, 0.1, 1, -1, -0.1, NaN], + stringNumber: ['0', '0.1', '1', '-0.1', 'NaN'], + + // BigInt + bigInt: [BigInt(1)], + stringBigInt: ['BigInt(1)'], + + // Undefined + undefined: [undefined], + stringUndefined: ['undefined'], + + // Null + null: [null], + stringNull: ['null'], + + // Symbol + symbol: [Symbol('a')], + stringSymbol: ["Symbol('a')"], + + // Object + object: [{}, { a: 1 }, { a: '1', b: { c: 3 } }], + stringObject: ['{}', '{ a: 1 }', '{ a: "1", b: { c: 3 } }'], + + // Array objects + array: [[], [1], ['a'], [{ a: 1 }]], + stringArray: ['[]', '[1]', '["a"]', '[{ a: 1 }]'], + + // Function objects + function: [function () {}, () => {}], + stringFunction: ['function () {}', '() => {}'], + + // Other objects + other: [new Date(), new Error(''), new RegExp('abc')], + stringOther: ['new Date()', 'new Error("")', 'new RegExp("abc")'] +}; + +/** + * Filters values from an object based on specified categories. + * + * The function iterates over the entries of the `values` object and collects + * items from the arrays that correspond to keys not present in the `categories` + * array. + * + * @function excludeFromValues + * + * @param {Object} values - An object where keys are category names and values + * are arrays of items. + * @param {Array.} [categories=[]] - An array of category names to be + * excluded from the values. + * + * @returns {Array.<*>} An array of items from the `values` object that are not + * in the specified `categories`. + */ +export function excludeFromValues(values, categories = []) { + const filteredArray = []; + Object.entries(values).forEach(([key, value]) => { + if (!categories.includes(key)) { + filteredArray.push(...value); + } + }); + return filteredArray; +} + +/** + * Validates a specific property of a provided schema by testing it against + * various values and ensuring that values not matching the types in the + * `filterTypes` list throw errors. + * + * The function filters the `possibleValues` object to exclude values of the + * types specified in the `filterTypes` array. It then iterates over the + * remaining values and ensures that parsing those values for the specified + * property in the schema results in an error. + * + * @function validatePropOfSchema + * + * @param {ZodSchema} schema - The Zod schema object to be validated. + * @param {string} property - The property of the schema to be validated. + * @param {Array.} [filterTypes=[]] - An array of type categories to be + * excluded from validation. Values of these types will be skipped in the + * validation process. + */ +export function validatePropOfSchema(schema, property, filterTypes = []) { + // Filter the possibleValues object to exclude values of types from + // the filterTypes array + const otherValues = excludeFromValues(possibleValues, filterTypes); + + // Ensure all other values fail validation + otherValues.forEach((value) => { + expect(() => schema.parse({ [property]: value })).toThrow(); + }); +} From 046ce23ef000a93a2983b2420295b7fb4164db75 Mon Sep 17 00:00:00 2001 From: PaulDalek Date: Tue, 10 Dec 2024 22:19:27 +0100 Subject: [PATCH 05/19] Corrected an import. --- lib/server/routes/versionChange.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/server/routes/versionChange.js b/lib/server/routes/versionChange.js index a8d9a411..c24e534d 100644 --- a/lib/server/routes/versionChange.js +++ b/lib/server/routes/versionChange.js @@ -18,7 +18,7 @@ See LICENSE file in root for details. */ import { updateHighchartsVersion, getHighchartsVersion } from '../../cache.js'; -import { envs } from '../../envs.js'; +import { envs } from '../../validation.js'; import HttpError from '../../errors/HttpError.js'; From 14a13766c517750b9e9370e0e7dd5d1494d3cb1a Mon Sep 17 00:00:00 2001 From: PaulDalek Date: Sun, 5 Jan 2025 23:19:59 +0100 Subject: [PATCH 06/19] Built scripts. --- dist/index.cjs | 4 ++-- dist/index.esm.js | 2 +- dist/index.esm.js.map | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/dist/index.cjs b/dist/index.cjs index 40d941ee..d1dafa20 100644 --- a/dist/index.cjs +++ b/dist/index.cjs @@ -1,2 +1,2 @@ -"use strict";Object.defineProperty(exports,"__esModule",{value:!0}),require("colors");var fs=require("fs"),path=require("path"),httpsProxyAgent=require("https-proxy-agent"),url=require("url"),dotenv=require("dotenv"),zod=require("zod"),http=require("http"),https=require("https"),tarn=require("tarn"),uuid=require("uuid"),puppeteer=require("puppeteer"),DOMPurify=require("dompurify"),jsdom=require("jsdom"),promises=require("fs/promises"),cors=require("cors"),express=require("express"),multer=require("multer"),rateLimit=require("express-rate-limit"),_documentCurrentScript="undefined"!=typeof document?document.currentScript:null;const __dirname$1=url.fileURLToPath(new URL("../.","undefined"==typeof document?require("url").pathToFileURL(__filename).href:_documentCurrentScript&&"SCRIPT"===_documentCurrentScript.tagName.toUpperCase()&&_documentCurrentScript.src||new URL("index.cjs",document.baseURI).href));function deepCopy(e){if(null===e||"object"!=typeof e)return e;const t=Array.isArray(e)?[]:{};for(const o in e)Object.prototype.hasOwnProperty.call(e,o)&&(t[o]=deepCopy(e[o]));return t}function fixConstr(e){try{const t=`${e.toLowerCase().replace("chart","")}Chart`;return"Chart"===t&&t.toLowerCase(),["chart","stockChart","mapChart","ganttChart"].includes(t)?t:"chart"}catch{return"chart"}}function fixOutfile(e,t){return`${getAbsolutePath(t||"chart").split(".").shift()}.${e}`}function fixType(e,t=null){const o={"image/png":"png","image/jpeg":"jpeg","application/pdf":"pdf","image/svg+xml":"svg"},r=Object.values(o);if(t){const o=t.split(".").pop();"jpg"===o?e="jpeg":r.includes(o)&&e!==o&&(e=o)}return o[e]||r.find((t=>t===e))||"png"}function getAbsolutePath(e){return path.isAbsolute(e)?e:path.join(__dirname$1,e)}function getBase64(e,t){return"pdf"===t||"svg"==t?Buffer.from(e,"utf8").toString("base64"):e}function getNewDate(){return(new Date).toString().split("(")[0].trim()}function getNewDateTime(){return(new Date).getTime()}function isObject(e){return"[object Object]"===Object.prototype.toString.call(e)}function isObjectEmpty(e){return"object"==typeof e&&!Array.isArray(e)&&null!==e&&0===Object.keys(e).length}function isPrivateRangeUrlFound(e){return[/xlink:href="(?:http:\/\/|https:\/\/)?localhost\b/,/xlink:href="(?:http:\/\/|https:\/\/)?10\.\d{1,3}\.\d{1,3}\.\d{1,3}\b/,/xlink:href="(?:http:\/\/|https:\/\/)?127\.\d{1,3}\.\d{1,3}\.\d{1,3}\b/,/xlink:href="(?:http:\/\/|https:\/\/)?172\.(1[6-9]|2[0-9]|3[0-1])\.\d{1,3}\.\d{1,3}\b/,/xlink:href="(?:http:\/\/|https:\/\/)?192\.168\.\d{1,3}\.\d{1,3}\b/].some((t=>t.test(e)))}function measureTime(){const e=process.hrtime.bigint();return()=>Number(process.hrtime.bigint()-e)/1e6}function roundNumber(e,t=1){const o=Math.pow(10,t||0);return Math.round(+e*o)/o}function wrapAround(e,t,o=!1){if(e&&"string"==typeof e)return(e=e.trim()).endsWith(".js")?t?wrapAround(fs.readFileSync(getAbsolutePath(e),"utf8"),t,o):null:!o&&(e.startsWith("function()")||e.startsWith("function ()")||e.startsWith("()=>")||e.startsWith("() =>"))?`(${e})()`:e.replace(/;$/,"")}const colors=["red","yellow","blue","gray","green"],logging={toConsole:!0,toFile:!1,pathCreated:!1,pathToLog:"",levelsDesc:[{title:"error",color:colors[0]},{title:"warning",color:colors[1]},{title:"notice",color:colors[2]},{title:"verbose",color:colors[3]},{title:"benchmark",color:colors[4]}]};function log(...e){const[t,...o]=e,{levelsDesc:r,level:n}=logging;if(5!==t&&(0===t||t>n||n>r.length))return;const i=`${getNewDate()} [${r[t-1].title}] -`;logging.toFile&&_logToFile(o,i),logging.toConsole&&console.log.apply(void 0,[i.toString()[logging.levelsDesc[t-1].color]].concat(o))}function logWithStack(e,t,o){const r=o||t.message,{level:n,levelsDesc:i}=logging;if(0===e||e>n||n>i.length)return;const s=`${getNewDate()} [${i[e-1].title}] -`,a=t.stack,l=[r];a&&l.push("\n",a),logging.toFile&&_logToFile(l,s),logging.toConsole&&console.log.apply(void 0,[s.toString()[logging.levelsDesc[e-1].color]].concat([l.shift()[colors[e-1]],...l]))}function initLogging(e){const{level:t,dest:o,file:r,toConsole:n,toFile:i}=e;setLogLevel(t),enableConsoleLogging(n),enableFileLogging(o,r,i)}function setLogLevel(e){e>=0&&e<=logging.levelsDesc.length&&(logging.level=e)}function enableConsoleLogging(e){logging.toConsole=e}function enableFileLogging(e,t,o){logging.toFile=o,o&&(logging.dest=e,logging.file=t)}function _logToFile(e,t){logging.pathCreated||(!fs.existsSync(getAbsolutePath(logging.dest))&&fs.mkdirSync(getAbsolutePath(logging.dest)),logging.pathToLog=getAbsolutePath(path.join(logging.dest,logging.file)),logging.pathCreated=!0),fs.appendFile(logging.pathToLog,[t].concat(e).join(" ")+"\n",(e=>{e&&logging.toFile&&logging.pathCreated&&(logging.toFile=!1,logging.pathCreated=!1,logWithStack(2,e,"[logger] Unable to write to log file."))}))}const defaultConfig={puppeteer:{args:{value:["--allow-running-insecure-content","--ash-no-nudges","--autoplay-policy=user-gesture-required","--block-new-web-contents","--disable-accelerated-2d-canvas","--disable-background-networking","--disable-background-timer-throttling","--disable-backgrounding-occluded-windows","--disable-breakpad","--disable-checker-imaging","--disable-client-side-phishing-detection","--disable-component-extensions-with-background-pages","--disable-component-update","--disable-default-apps","--disable-dev-shm-usage","--disable-domain-reliability","--disable-extensions","--disable-features=CalculateNativeWinOcclusion,InterestFeedContentSuggestions,WebOTP","--disable-hang-monitor","--disable-ipc-flooding-protection","--disable-logging","--disable-notifications","--disable-offer-store-unmasked-wallet-cards","--disable-popup-blocking","--disable-print-preview","--disable-prompt-on-repost","--disable-renderer-backgrounding","--disable-search-engine-choice-screen","--disable-session-crashed-bubble","--disable-setuid-sandbox","--disable-site-isolation-trials","--disable-speech-api","--disable-sync","--enable-unsafe-webgpu","--hide-crash-restore-bubble","--hide-scrollbars","--metrics-recording-only","--mute-audio","--no-default-browser-check","--no-first-run","--no-pings","--no-sandbox","--no-startup-window","--no-zygote","--password-store=basic","--process-per-tab","--use-mock-keychain"],types:["string[]"],envLink:"PUPPETEER_ARGS",cliName:"puppeteerArgs",description:"Array of Puppeteer arguments",promptOptions:{type:"list",separator:";"}}},highcharts:{version:{value:"latest",types:["string"],envLink:"HIGHCHARTS_VERSION",description:"Highcharts version",promptOptions:{type:"text"}},cdnUrl:{value:"https://code.highcharts.com",types:["string"],envLink:"HIGHCHARTS_CDN_URL",description:"CDN URL for Highcharts scripts",promptOptions:{type:"text"}},forceFetch:{value:!1,types:["boolean"],envLink:"HIGHCHARTS_FORCE_FETCH",description:"Flag to refetch scripts after each server rerun",promptOptions:{type:"toggle"}},cachePath:{value:".cache",types:["string"],envLink:"HIGHCHARTS_CACHE_PATH",description:"Directory path for cached Highcharts scripts",promptOptions:{type:"text"}},coreScripts:{value:["highcharts","highcharts-more","highcharts-3d"],types:["string[]"],envLink:"HIGHCHARTS_CORE_SCRIPTS",description:"Highcharts core scripts to fetch",promptOptions:{type:"multiselect",instructions:"Space: Select specific, A: Select all, Enter: Confirm"}},moduleScripts:{value:["stock","map","gantt","exporting","parallel-coordinates","accessibility","boost-canvas","boost","data","data-tools","draggable-points","static-scale","broken-axis","heatmap","tilemap","tiledwebmap","timeline","treemap","treegraph","item-series","drilldown","histogram-bellcurve","bullet","funnel","funnel3d","geoheatmap","pyramid3d","networkgraph","overlapping-datalabels","pareto","pattern-fill","pictorial","price-indicator","sankey","arc-diagram","dependency-wheel","series-label","series-on-point","solid-gauge","sonification","streamgraph","sunburst","variable-pie","variwide","vector","venn","windbarb","wordcloud","xrange","no-data-to-display","drag-panes","debugger","dumbbell","lollipop","cylinder","organization","dotplot","marker-clusters","hollowcandlestick","heikinashi","flowmap","export-data","navigator","textpath"],types:["string[]"],envLink:"HIGHCHARTS_MODULE_SCRIPTS",description:"Highcharts module scripts to fetch",promptOptions:{type:"multiselect",instructions:"Space: Select specific, A: Select all, Enter: Confirm"}},indicatorScripts:{value:["indicators-all"],types:["string[]"],envLink:"HIGHCHARTS_INDICATOR_SCRIPTS",description:"Highcharts indicator scripts to fetch",promptOptions:{type:"multiselect",instructions:"Space: Select specific, A: Select all, Enter: Confirm"}},customScripts:{value:["https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.30.1/moment.min.js","https://cdnjs.cloudflare.com/ajax/libs/moment-timezone/0.5.45/moment-timezone-with-data.min.js"],types:["string[]"],envLink:"HIGHCHARTS_CUSTOM_SCRIPTS",description:"Additional custom scripts or dependencies to fetch",promptOptions:{type:"list",separator:";"}}},export:{infile:{value:null,types:["string","null"],envLink:"EXPORT_INFILE",description:"Input filename with type, formatted correctly as JSON or SVG",promptOptions:{type:"text"}},instr:{value:null,types:["string","null"],envLink:"EXPORT_INSTR",description:"Overrides the `infile` with JSON, stringified JSON, or SVG input",promptOptions:{type:"text"}},options:{value:null,types:["Object","null"],envLink:"EXPORT_OPTIONS",description:"Alias for the `instr` option",promptOptions:{type:"text"}},svg:{value:null,types:["string","null"],envLink:"EXPORT_SVG",description:"SVG string representation of the chart to render",promptOptions:{type:"text"}},batch:{value:null,types:["string","null"],envLink:"EXPORT_BATCH",description:'Batch job string with input/output pairs: "in=out;in=out;..."',promptOptions:{type:"text"}},outfile:{value:null,types:["string","null"],envLink:"EXPORT_OUTFILE",description:"Output filename with type. Can be jpeg, png, pdf, or svg and ignores `type` option",promptOptions:{type:"text"}},type:{value:"png",types:["string"],envLink:"EXPORT_TYPE",description:"File export format. Can be jpeg, png, pdf, or svg",promptOptions:{type:"select",hint:"Default: png",choices:["png","jpeg","pdf","svg"]}},constr:{value:"chart",types:["string"],envLink:"EXPORT_CONSTR",description:"Chart constructor. Can be chart, stockChart, mapChart, or ganttChart",promptOptions:{type:"select",hint:"Default: chart",choices:["chart","stockChart","mapChart","ganttChart"]}},b64:{value:!1,types:["boolean"],envLink:"EXPORT_B64",description:"Whether or not to the chart should be received in Base64 format instead of binary",promptOptions:{type:"toggle"}},noDownload:{value:!1,types:["boolean"],envLink:"EXPORT_NO_DOWNLOAD",description:"Whether or not to include or exclude attachment headers in the response",promptOptions:{type:"toggle"}},height:{value:null,types:["number","null"],envLink:"EXPORT_HEIGHT",description:"Height of the exported chart, overrides chart settings",promptOptions:{type:"number"}},width:{value:null,types:["number","null"],envLink:"EXPORT_WIDTH",description:"Width of the exported chart, overrides chart settings",promptOptions:{type:"number"}},scale:{value:null,types:["number","null"],envLink:"EXPORT_SCALE",description:"Scale of the exported chart, overrides chart settings. Ranges from 0.1 to 5.0",promptOptions:{type:"number"}},defaultHeight:{value:400,types:["number"],envLink:"EXPORT_DEFAULT_HEIGHT",description:"Default height of the exported chart if not set",promptOptions:{type:"number"}},defaultWidth:{value:600,types:["number"],envLink:"EXPORT_DEFAULT_WIDTH",description:"Default width of the exported chart if not set",promptOptions:{type:"number"}},defaultScale:{value:1,types:["number"],envLink:"EXPORT_DEFAULT_SCALE",description:"Default scale of the exported chart if not set. Ranges from 0.1 to 5.0",promptOptions:{type:"number",min:.1,max:5}},globalOptions:{value:null,types:["Object","string","null"],envLink:"EXPORT_GLOBAL_OPTIONS",description:"JSON, stringified JSON or filename with global options for Highcharts.setOptions",promptOptions:{type:"text"}},themeOptions:{value:null,types:["Object","string","null"],envLink:"EXPORT_THEME_OPTIONS",description:"JSON, stringified JSON or filename with theme options for Highcharts.setOptions",promptOptions:{type:"text"}},rasterizationTimeout:{value:1500,types:["number"],envLink:"EXPORT_RASTERIZATION_TIMEOUT",description:"Milliseconds to wait for webpage rendering",promptOptions:{type:"number"}}},customLogic:{allowCodeExecution:{value:!1,types:["boolean"],envLink:"CUSTOM_LOGIC_ALLOW_CODE_EXECUTION",description:"Allows or disallows execution of arbitrary code during exporting",promptOptions:{type:"toggle"}},allowFileResources:{value:!1,types:["boolean"],envLink:"CUSTOM_LOGIC_ALLOW_FILE_RESOURCES",description:"Allows or disallows injection of filesystem resources (disabled in server mode)",promptOptions:{type:"toggle"}},customCode:{value:null,types:["string","null"],envLink:"CUSTOM_LOGIC_CUSTOM_CODE",description:"Custom code to execute before chart initialization. Can be a function, code wrapped in a function, or a .js filename",promptOptions:{type:"text"}},callback:{value:null,types:["string","null"],envLink:"CUSTOM_LOGIC_CALLBACK",description:"JavaScript code to run during construction. Can be a function or a .js filename",promptOptions:{type:"text"}},resources:{value:null,types:["Object","string","null"],envLink:"CUSTOM_LOGIC_RESOURCES",description:"Additional resources as JSON, stringified JSON, or filename, containing files, js, and css sections",promptOptions:{type:"text"}},loadConfig:{value:null,types:["string","null"],envLink:"CUSTOM_LOGIC_LOAD_CONFIG",legacyName:"fromFile",description:"File with a pre-defined configuration to use",promptOptions:{type:"text"}},createConfig:{value:null,types:["string","null"],envLink:"CUSTOM_LOGIC_CREATE_CONFIG",description:"Prompt-based option setting, saved to a provided config file",promptOptions:{type:"text"}}},server:{enable:{value:!1,types:["boolean"],envLink:"SERVER_ENABLE",cliName:"enableServer",description:"Starts the server when true",promptOptions:{type:"toggle"}},host:{value:"0.0.0.0",types:["string"],envLink:"SERVER_HOST",description:"Hostname of the server",promptOptions:{type:"text"}},port:{value:7801,types:["number"],envLink:"SERVER_PORT",description:"Port number for the server",promptOptions:{type:"number"}},uploadLimit:{value:3,types:["number"],envLink:"SERVER_UPLOAD_LIMIT",description:"Maximum request body size in MB",promptOptions:{type:"number"}},benchmarking:{value:!1,types:["boolean"],envLink:"SERVER_BENCHMARKING",cliName:"serverBenchmarking",description:"Displays or not action durations in milliseconds during server requests",promptOptions:{type:"toggle"}},proxy:{host:{value:null,types:["string","null"],envLink:"SERVER_PROXY_HOST",cliName:"proxyHost",description:"Host of the proxy server, if applicable",promptOptions:{type:"text"}},port:{value:null,types:["number","null"],envLink:"SERVER_PROXY_PORT",cliName:"proxyPort",description:"Port of the proxy server, if applicable",promptOptions:{type:"number"}},timeout:{value:5e3,types:["number"],envLink:"SERVER_PROXY_TIMEOUT",cliName:"proxyTimeout",description:"Timeout in milliseconds for the proxy server, if applicable",promptOptions:{type:"number"}}},rateLimiting:{enable:{value:!1,types:["boolean"],envLink:"SERVER_RATE_LIMITING_ENABLE",cliName:"enableRateLimiting",description:"Enables or disables rate limiting on the server",promptOptions:{type:"toggle"}},maxRequests:{value:10,types:["number"],envLink:"SERVER_RATE_LIMITING_MAX_REQUESTS",legacyName:"rateLimit",description:"Maximum number of requests allowed per minute",promptOptions:{type:"number"}},window:{value:1,types:["number"],envLink:"SERVER_RATE_LIMITING_WINDOW",description:"Time window in minutes for rate limiting",promptOptions:{type:"number"}},delay:{value:0,types:["number"],envLink:"SERVER_RATE_LIMITING_DELAY",description:"Delay duration between successive requests before reaching the limit",promptOptions:{type:"number"}},trustProxy:{value:!1,types:["boolean"],envLink:"SERVER_RATE_LIMITING_TRUST_PROXY",description:"Set to true if the server is behind a load balancer",promptOptions:{type:"toggle"}},skipKey:{value:null,types:["string","null"],envLink:"SERVER_RATE_LIMITING_SKIP_KEY",description:"Key to bypass the rate limiter, used with `skipToken`",promptOptions:{type:"text"}},skipToken:{value:null,types:["string","null"],envLink:"SERVER_RATE_LIMITING_SKIP_TOKEN",description:"Token to bypass the rate limiter, used with `skipKey`",promptOptions:{type:"text"}}},ssl:{enable:{value:!1,types:["boolean"],envLink:"SERVER_SSL_ENABLE",cliName:"enableSsl",description:"Enables or disables SSL protocol",promptOptions:{type:"toggle"}},force:{value:!1,types:["boolean"],envLink:"SERVER_SSL_FORCE",cliName:"sslForce",legacyName:"sslOnly",description:"Forces the server to use HTTPS only when true",promptOptions:{type:"toggle"}},port:{value:443,types:["number"],envLink:"SERVER_SSL_PORT",cliName:"sslPort",description:"Port for the SSL server",promptOptions:{type:"number"}},certPath:{value:null,types:["string","null"],envLink:"SERVER_SSL_CERT_PATH",cliName:"sslCertPath",legacyName:"sslPath",description:"Path to the SSL certificate/key file",promptOptions:{type:"text"}}}},pool:{minWorkers:{value:4,types:["number"],envLink:"POOL_MIN_WORKERS",description:"Minimum and initial number of pool workers to spawn",promptOptions:{type:"number"}},maxWorkers:{value:8,types:["number"],envLink:"POOL_MAX_WORKERS",legacyName:"workers",description:"Maximum number of pool workers to spawn",promptOptions:{type:"number"}},workLimit:{value:40,types:["number"],envLink:"POOL_WORK_LIMIT",description:"Number of tasks a worker can handle before restarting",promptOptions:{type:"number"}},acquireTimeout:{value:5e3,types:["number"],envLink:"POOL_ACQUIRE_TIMEOUT",description:"Timeout in milliseconds for acquiring a resource",promptOptions:{type:"number"}},createTimeout:{value:5e3,types:["number"],envLink:"POOL_CREATE_TIMEOUT",description:"Timeout in milliseconds for creating a resource",promptOptions:{type:"number"}},destroyTimeout:{value:5e3,types:["number"],envLink:"POOL_DESTROY_TIMEOUT",description:"Timeout in milliseconds for destroying a resource",promptOptions:{type:"number"}},idleTimeout:{value:3e4,types:["number"],envLink:"POOL_IDLE_TIMEOUT",description:"Timeout in milliseconds for destroying idle resources",promptOptions:{type:"number"}},createRetryInterval:{value:200,types:["number"],envLink:"POOL_CREATE_RETRY_INTERVAL",description:"Interval in milliseconds before retrying resource creation on failure",promptOptions:{type:"number"}},reaperInterval:{value:1e3,types:["number"],envLink:"POOL_REAPER_INTERVAL",description:"Interval in milliseconds to check and destroy idle resources",promptOptions:{type:"number"}},benchmarking:{value:!1,types:["boolean"],envLink:"POOL_BENCHMARKING",cliName:"poolBenchmarking",description:"Shows statistics for the pool of resources",promptOptions:{type:"toggle"}}},logging:{level:{value:4,types:["number"],envLink:"LOGGING_LEVEL",cliName:"logLevel",description:"Logging verbosity level",promptOptions:{type:"number",round:0,min:0,max:5}},file:{value:"highcharts-export-server.log",types:["string"],envLink:"LOGGING_FILE",cliName:"logFile",description:"Log file name. Requires `logToFile` and `logDest` to be set",promptOptions:{type:"text"}},dest:{value:"log",types:["string"],envLink:"LOGGING_DEST",cliName:"logDest",description:"Path to store log files. Requires `logToFile` to be set",promptOptions:{type:"text"}},toConsole:{value:!0,types:["boolean"],envLink:"LOGGING_TO_CONSOLE",cliName:"logToConsole",description:"Enables or disables console logging",promptOptions:{type:"toggle"}},toFile:{value:!0,types:["boolean"],envLink:"LOGGING_TO_FILE",cliName:"logToFile",description:"Enables or disables logging to a file",promptOptions:{type:"toggle"}}},ui:{enable:{value:!1,types:["boolean"],envLink:"UI_ENABLE",cliName:"enableUi",description:"Enables or disables the UI for the export server",promptOptions:{type:"toggle"}},route:{value:"/",types:["string"],envLink:"UI_ROUTE",cliName:"uiRoute",description:"The endpoint route for the UI",promptOptions:{type:"text"}}},other:{nodeEnv:{value:"production",types:["string"],envLink:"OTHER_NODE_ENV",description:"The Node.js environment type",promptOptions:{type:"text"}},listenToProcessExits:{value:!0,types:["boolean"],envLink:"OTHER_LISTEN_TO_PROCESS_EXITS",description:"Whether or not to attach process.exit handlers",promptOptions:{type:"toggle"}},noLogo:{value:!1,types:["boolean"],envLink:"OTHER_NO_LOGO",description:"Display or skip printing the logo on startup",promptOptions:{type:"toggle"}},hardResetPage:{value:!1,types:["boolean"],envLink:"OTHER_HARD_RESET_PAGE",description:"Whether or not to reset the page content entirely",promptOptions:{type:"toggle"}},browserShellMode:{value:!0,types:["boolean"],envLink:"OTHER_BROWSER_SHELL_MODE",description:"Whether or not to set the browser to run in shell mode",promptOptions:{type:"toggle"}}},debug:{enable:{value:!1,types:["boolean"],envLink:"DEBUG_ENABLE",cliName:"enableDebug",description:"Enables or disables debug mode for the underlying browser",promptOptions:{type:"toggle"}},headless:{value:!1,types:["boolean"],envLink:"DEBUG_HEADLESS",description:"Whether or not to set the browser to run in headless mode during debugging",promptOptions:{type:"toggle"}},devtools:{value:!1,types:["boolean"],envLink:"DEBUG_DEVTOOLS",description:"Enables or disables DevTools in headful mode",promptOptions:{type:"toggle"}},listenToConsole:{value:!1,types:["boolean"],envLink:"DEBUG_LISTEN_TO_CONSOLE",description:"Enables or disables listening to console messages from the browser",promptOptions:{type:"toggle"}},dumpio:{value:!1,types:["boolean"],envLink:"DEBUG_DUMPIO",description:"Redirects or not browser stdout and stderr to process.stdout and process.stderr",promptOptions:{type:"toggle"}},slowMo:{value:0,types:["number"],envLink:"DEBUG_SLOW_MO",description:"Delays Puppeteer operations by the specified milliseconds",promptOptions:{type:"number"}},debuggingPort:{value:9222,types:["number"],envLink:"DEBUG_DEBUGGING_PORT",description:"Port used for debugging",promptOptions:{type:"number"}}}},nestedProps=_createNestedProps(defaultConfig),absoluteProps=_createAbsoluteProps(defaultConfig);function _createNestedProps(e,t={},o=""){return Object.keys(e).forEach((r=>{const n=e[r];void 0===n.value?_createNestedProps(n,t,`${o}.${r}`):(t[n.cliName||r]=`${o}.${r}`.substring(1),void 0!==n.legacyName&&(t[n.legacyName]=`${o}.${r}`.substring(1)))})),t}function _createAbsoluteProps(e,t=[]){return Object.keys(e).forEach((o=>{const r=e[o];void 0===r.types?_createAbsoluteProps(r,t):r.types.includes("Object")&&t.push(o)})),t}dotenv.config();const v={array:e=>zod.z.string().transform((t=>t.split(",").map((e=>e.trim())).filter((t=>e.includes(t))))).transform((e=>e.length?e:void 0)),boolean:()=>zod.z.enum(["true","false",""]).transform((e=>""!==e?"true"===e:void 0)),enum:e=>zod.z.enum([...e,""]).transform((e=>""!==e?e:void 0)),string:()=>zod.z.string().trim().refine((e=>!["false","undefined","null","NaN"].includes(e)||""===e),(e=>({message:`The string contains forbidden values, received '${e}'`}))).transform((e=>""!==e?e:void 0)),positiveNum:()=>zod.z.string().trim().refine((e=>""===e||!isNaN(parseFloat(e))&&parseFloat(e)>0),(e=>({message:`The value must be numeric and positive, received '${e}'`}))).transform((e=>""!==e?parseFloat(e):void 0)),nonNegativeNum:()=>zod.z.string().trim().refine((e=>""===e||!isNaN(parseFloat(e))&&parseFloat(e)>=0),(e=>({message:`The value must be numeric and non-negative, received '${e}'`}))).transform((e=>""!==e?parseFloat(e):void 0))},Config=zod.z.object({PUPPETEER_ARGS:v.string(),HIGHCHARTS_VERSION:zod.z.string().trim().refine((e=>/^(latest|\d+(\.\d+){0,2})$/.test(e)||""===e),(e=>({message:`HIGHCHARTS_VERSION must be 'latest', a major version, or in the form XX.YY.ZZ, received '${e}'`}))).transform((e=>""!==e?e:void 0)),HIGHCHARTS_CDN_URL:zod.z.string().trim().refine((e=>e.startsWith("https://")||e.startsWith("http://")||""===e),(e=>({message:`Invalid value for HIGHCHARTS_CDN_URL. It should start with http:// or https://, received '${e}'`}))).transform((e=>""!==e?e:void 0)),HIGHCHARTS_FORCE_FETCH:v.boolean(),HIGHCHARTS_CACHE_PATH:v.string(),HIGHCHARTS_ADMIN_TOKEN:v.string(),HIGHCHARTS_CORE_SCRIPTS:v.array(defaultConfig.highcharts.coreScripts.value),HIGHCHARTS_MODULE_SCRIPTS:v.array(defaultConfig.highcharts.moduleScripts.value),HIGHCHARTS_INDICATOR_SCRIPTS:v.array(defaultConfig.highcharts.indicatorScripts.value),HIGHCHARTS_CUSTOM_SCRIPTS:v.array(defaultConfig.highcharts.customScripts.value),EXPORT_INFILE:v.string(),EXPORT_INSTR:v.string(),EXPORT_OPTIONS:v.string(),EXPORT_SVG:v.string(),EXPORT_BATCH:v.string(),EXPORT_OUTFILE:v.string(),EXPORT_TYPE:v.enum(["jpeg","png","pdf","svg"]),EXPORT_CONSTR:v.enum(["chart","stockChart","mapChart","ganttChart"]),EXPORT_B64:v.boolean(),EXPORT_NO_DOWNLOAD:v.boolean(),EXPORT_HEIGHT:v.positiveNum(),EXPORT_WIDTH:v.positiveNum(),EXPORT_SCALE:v.positiveNum(),EXPORT_DEFAULT_HEIGHT:v.positiveNum(),EXPORT_DEFAULT_WIDTH:v.positiveNum(),EXPORT_DEFAULT_SCALE:v.positiveNum(),EXPORT_GLOBAL_OPTIONS:v.string(),EXPORT_THEME_OPTIONS:v.string(),EXPORT_RASTERIZATION_TIMEOUT:v.nonNegativeNum(),CUSTOM_LOGIC_ALLOW_CODE_EXECUTION:v.boolean(),CUSTOM_LOGIC_ALLOW_FILE_RESOURCES:v.boolean(),CUSTOM_LOGIC_CUSTOM_CODE:v.string(),CUSTOM_LOGIC_CALLBACK:v.string(),CUSTOM_LOGIC_RESOURCES:v.string(),CUSTOM_LOGIC_LOAD_CONFIG:v.string(),CUSTOM_LOGIC_CREATE_CONFIG:v.string(),SERVER_ENABLE:v.boolean(),SERVER_HOST:v.string(),SERVER_PORT:v.positiveNum(),SERVER_UPLOAD_LIMIT:v.positiveNum(),SERVER_BENCHMARKING:v.boolean(),SERVER_PROXY_HOST:v.string(),SERVER_PROXY_PORT:v.positiveNum(),SERVER_PROXY_TIMEOUT:v.nonNegativeNum(),SERVER_RATE_LIMITING_ENABLE:v.boolean(),SERVER_RATE_LIMITING_MAX_REQUESTS:v.nonNegativeNum(),SERVER_RATE_LIMITING_WINDOW:v.nonNegativeNum(),SERVER_RATE_LIMITING_DELAY:v.nonNegativeNum(),SERVER_RATE_LIMITING_TRUST_PROXY:v.boolean(),SERVER_RATE_LIMITING_SKIP_KEY:v.string(),SERVER_RATE_LIMITING_SKIP_TOKEN:v.string(),SERVER_SSL_ENABLE:v.boolean(),SERVER_SSL_FORCE:v.boolean(),SERVER_SSL_PORT:v.positiveNum(),SERVER_SSL_CERT_PATH:v.string(),POOL_MIN_WORKERS:v.nonNegativeNum(),POOL_MAX_WORKERS:v.nonNegativeNum(),POOL_WORK_LIMIT:v.positiveNum(),POOL_ACQUIRE_TIMEOUT:v.nonNegativeNum(),POOL_CREATE_TIMEOUT:v.nonNegativeNum(),POOL_DESTROY_TIMEOUT:v.nonNegativeNum(),POOL_IDLE_TIMEOUT:v.nonNegativeNum(),POOL_CREATE_RETRY_INTERVAL:v.nonNegativeNum(),POOL_REAPER_INTERVAL:v.nonNegativeNum(),POOL_BENCHMARKING:v.boolean(),LOGGING_LEVEL:zod.z.string().trim().refine((e=>""===e||!isNaN(parseFloat(e))&&parseFloat(e)>=0&&parseFloat(e)<=5),(e=>({message:`Invalid value for LOGGING_LEVEL. We only accept values from 0 to 5 as logging levels, received '${e}'`}))).transform((e=>""!==e?parseFloat(e):void 0)),LOGGING_FILE:v.string(),LOGGING_DEST:v.string(),LOGGING_TO_CONSOLE:v.boolean(),LOGGING_TO_FILE:v.boolean(),UI_ENABLE:v.boolean(),UI_ROUTE:v.string(),OTHER_NODE_ENV:v.enum(["development","production","test"]),OTHER_LISTEN_TO_PROCESS_EXITS:v.boolean(),OTHER_NO_LOGO:v.boolean(),OTHER_HARD_RESET_PAGE:v.boolean(),OTHER_BROWSER_SHELL_MODE:v.boolean(),DEBUG_ENABLE:v.boolean(),DEBUG_HEADLESS:v.boolean(),DEBUG_DEVTOOLS:v.boolean(),DEBUG_LISTEN_TO_CONSOLE:v.boolean(),DEBUG_DUMPIO:v.boolean(),DEBUG_SLOW_MO:v.nonNegativeNum(),DEBUG_DEBUGGING_PORT:v.positiveNum()}),envs=Config.partial().parse(process.env),globalOptions=_initGlobalOptions(defaultConfig);function getOptions(e=!0){return e?globalOptions:deepCopy(globalOptions)}function setOptions(e={},t=[],o=!1){let r={},n={};t.length&&(r=_loadConfigFile(t),n=_pairArgumentValue(nestedProps,t));const i=getOptions(o);return _updateOptions(defaultConfig,i,r,e,n),i}function mergeOptions(e,t){if(isObject(t))for(const[o,r]of Object.entries(t))e[o]=isObject(r)&&!absoluteProps.includes(o)&&void 0!==e[o]?mergeOptions(e[o],r):void 0!==r?r:e[o];return e}function mapToNewOptions(e){const t={};if("[object Object]"===Object.prototype.toString.call(e))for(const[o,r]of Object.entries(e)){const e=nestedProps[o]?nestedProps[o].split("."):[];e.reduce(((t,o,n)=>t[o]=e.length-1===n?r:t[o]||{}),t)}return t}function isAllowedConfig(config,toString=!1,allowFunctions=!1){try{if(!isObject(config)&&"string"!=typeof config)return null;const objectConfig="string"==typeof config?allowFunctions?eval(`(${config})`):JSON.parse(config):config,stringifiedOptions=_optionsStringify(objectConfig,allowFunctions,!1),parsedOptions=allowFunctions?JSON.parse(_optionsStringify(objectConfig,allowFunctions,!0),((_,value)=>"string"==typeof value&&value.startsWith("function")?eval(`(${value})`):value)):JSON.parse(stringifiedOptions);return toString?stringifiedOptions:parsedOptions}catch(e){return null}}function _initGlobalOptions(e){const t={};for(const[o,r]of Object.entries(e))t[o]=Object.prototype.hasOwnProperty.call(r,"value")?r.value:_initGlobalOptions(r);return t}function _updateOptions(e,t,o,r,n){Object.keys(e).forEach((i=>{const s=e[i],a=o&&o[i],l=r&&r[i],c=n&&n[i];if(void 0===s.value)_updateOptions(s,t[i],a,l,c);else{null!=a&&(t[i]=a);const e=envs[s.envLink];s.envLink in envs&&null!=e&&(t[i]=e),null!=l&&(t[i]=l),null!=c&&(t[i]=c)}}))}function _optionsStringify(e,t,o){return JSON.stringify(e,((e,r)=>{if("string"==typeof r&&(r=r.trim()),"function"==typeof r||"string"==typeof r&&r.startsWith("function")&&r.endsWith("}")){if(t)return o?`"EXP_FUN${(r+"").replaceAll(/\s+/g," ")}EXP_FUN"`:`EXP_FUN${(r+"").replaceAll(/\s+/g," ")}EXP_FUN`;throw new Error}return r})).replaceAll(o?/\\"EXP_FUN|EXP_FUN\\"/g:/"EXP_FUN|EXP_FUN"/g,"")}function _loadConfigFile(e){const t=e.findIndex((e=>"loadConfig"===e.replace(/-/g,""))),o=t>-1&&e[t+1];if(o)try{return JSON.parse(fs.readFileSync(getAbsolutePath(o)))}catch(e){logWithStack(2,e,`[config] Unable to load the configuration from the ${o} file.`)}return{}}function _pairArgumentValue(e,t){const o={};for(let r=0;r{if(i.length-1===s){const i=t[++r];i||log(2,`[config] Missing value for the CLI '--${n}' argument. Using the default value.`),e[o]=i||null}else void 0===e[o]&&(e[o]={});return e[o]}),o)}return o}async function fetch(e,t={}){return new Promise(((o,r)=>{_getProtocolModule(e).get(e,t,(e=>{let t="";e.on("data",(e=>{t+=e})),e.on("end",(()=>{t||r("Nothing was fetched from the URL."),e.text=t,o(e)}))})).on("error",(e=>{r(e)}))}))}function _getProtocolModule(e){return e.startsWith("https")?https:http}class ExportError extends Error{constructor(e,t){super(),this.message=e,this.stackMessage=e,t&&(this.statusCode=t)}setError(e){return this.error=e,e.name&&(this.name=e.name),e.statusCode&&(this.statusCode=e.statusCode),e.stack&&(this.stackMessage=e.message,this.stack=e.stack),this}}const cache={cdnUrl:"https://code.highcharts.com",activeManifest:{},sources:"",hcVersion:""};async function checkAndUpdateCache(e,t){let o;const r=getCachePath(),n=path.join(r,"manifest.json"),i=path.join(r,"sources.js");if(!fs.existsSync(r)&&fs.mkdirSync(r,{recursive:!0}),!fs.existsSync(n)||e.forceFetch)log(3,"[cache] Fetching and caching Highcharts dependencies."),o=await _updateCache(e,t,i);else{let r=!1;const s=JSON.parse(fs.readFileSync(n));if(s.modules&&Array.isArray(s.modules)){const e={};s.modules.forEach((t=>e[t]=1)),s.modules=e}const{coreScripts:a,moduleScripts:l,indicatorScripts:c}=e,p=a.length+l.length+c.length;s.version!==e.version?(log(2,"[cache] A Highcharts version mismatch in the cache, need to re-fetch."),r=!0):Object.keys(s.modules||{}).length!==p?(log(2,"[cache] The cache and the requested modules do not match, need to re-fetch."),r=!0):r=(l||[]).some((e=>{if(!s.modules[e])return log(2,`[cache] The ${e} is missing in the cache, need to re-fetch.`),!0})),r?o=await _updateCache(e,t,i):(log(3,"[cache] Dependency cache is up to date, proceeding."),cache.sources=fs.readFileSync(i,"utf8"),o=s.modules,cache.hcVersion=extractVersion(cache.sources))}await _saveConfigToManifest(e,o)}function getHighchartsVersion(){return cache.hcVersion}async function updateHighchartsVersion(e){const t=getOptions();t.highcharts.version=e,await checkAndUpdateCache(t.highcharts,t.server.proxy)}function extractVersion(e){return e.substring(0,e.indexOf("*/")).replace("/*","").replace("*/","").replace(/\n/g,"").trim()}function extractModuleName(e){return e.replace(/(.*)\/|(.*)modules\/|stock\/(.*)indicators\/|maps\/(.*)modules\//gi,"")}function getCachePath(){return getAbsolutePath(getOptions().highcharts.cachePath)}async function _fetchAndProcessScript(e,t,o,r=!1){e.endsWith(".js")&&(e=e.substring(0,e.length-3)),log(4,`[cache] Fetching script - ${e}.js`);const n=await fetch(`${e}.js`,t);if(200===n.statusCode&&"string"==typeof n.text){if(o){o[extractModuleName(e)]=1}return n.text}if(r)throw new ExportError(`[cache] Could not fetch the ${e}.js. The script might not exist in the requested version (status code: ${n.statusCode}).`,404).setError(n);log(2,`[cache] Could not fetch the ${e}.js. The script might not exist in the requested version.`)}async function _saveConfigToManifest(e,t={}){const o={version:e.version,modules:t};cache.activeManifest=o,log(3,"[cache] Writing a new manifest.");try{fs.writeFileSync(path.join(getCachePath(),"manifest.json"),JSON.stringify(o),"utf8")}catch(e){throw new ExportError("[cache] Error writing the cache manifest.",500).setError(e)}}async function _fetchScripts(e,t,o,r,n){let i;const s=r.host,a=r.port;if(s&&a)try{i=new httpsProxyAgent.HttpsProxyAgent({host:s,port:a})}catch(e){throw new ExportError("[cache] Could not create a Proxy Agent.",500).setError(e)}const l=i?{agent:i,timeout:r.timeout}:{},c=[...e.map((e=>_fetchAndProcessScript(`${e}`,l,n,!0))),...t.map((e=>_fetchAndProcessScript(`${e}`,l,n))),...o.map((e=>_fetchAndProcessScript(`${e}`,l)))];return(await Promise.all(c)).join(";\n")}async function _updateCache(e,t,o){const r="latest"===e.version?null:`${e.version}`,n=e.cdnUrl||cache.cdnUrl;try{const i={};return log(3,`[cache] Updating cache version to Highcharts: ${r||"latest"}.`),cache.sources=await _fetchScripts([...e.coreScripts.map((e=>r?`${n}/${r}/${e}`:`${n}/${e}`))],[...e.moduleScripts.map((e=>"map"===e?r?`${n}/maps/${r}/modules/${e}`:`${n}/maps/modules/${e}`:r?`${n}/${r}/modules/${e}`:`${n}/modules/${e}`)),...e.indicatorScripts.map((e=>r?`${n}/stock/${r}/indicators/${e}`:`${n}/stock/indicators/${e}`))],e.customScripts,t,i),cache.hcVersion=extractVersion(cache.sources),fs.writeFileSync(o,cache.sources),i}catch(e){throw new ExportError("[cache] Unable to update the local Highcharts cache.",500).setError(e)}}function setupHighcharts(){Highcharts.animObject=function(){return{duration:0}}}async function createChart(e){const{getOptions:t,merge:o,setOptions:r,wrap:n}=Highcharts;Highcharts.setOptionsObj=o(!1,{},t()),window.isRenderComplete=!1,n(Highcharts.Chart.prototype,"init",(function(e,t,r){((t=o(t,{exporting:{enabled:!1},plotOptions:{series:{label:{enabled:!1}}},tooltip:{}})).series||[]).forEach((function(e){e.animation=!1})),window.onHighchartsRender||(window.onHighchartsRender=Highcharts.addEvent(this,"render",(()=>{window.isRenderComplete=!0}))),e.apply(this,[t,r])})),n(Highcharts.Series.prototype,"init",(function(e,t,o){e.apply(this,[t,o])}));const i={chart:{animation:!1,height:e.export.height,width:e.export.width},exporting:{enabled:!1}},s=new Function(`return ${e.export.instr}`)(),a=new Function(`return ${e.export.themeOptions}`)(),l=new Function(`return ${e.export.globalOptions}`)(),c=o(!1,a,s,i),p=e.customLogic.callback?new Function(`return ${e.customLogic.callback}`)():null;e.customLogic.customCode&&new Function("options",e.customLogic.customCode)(s),l&&r(l),Highcharts[e.export.constr]("container",c,p);const u=t();for(const e in u)"function"!=typeof u[e]&&delete u[e];r(Highcharts.setOptionsObj),Highcharts.setOptionsObj={}}const template=fs.readFileSync(path.join(__dirname$1,"templates","template.html"),"utf8");let browser=null;async function createBrowser(e){const{debug:t,other:o}=getOptions(),{enable:r,...n}=t,i={headless:!o.browserShellMode||"shell",userDataDir:"tmp",args:e||[],handleSIGINT:!1,handleSIGTERM:!1,handleSIGHUP:!1,waitForInitialPage:!1,defaultViewport:null,...r&&n};if(!browser){let e=0;const t=async()=>{try{log(3,`[browser] Attempting to get a browser instance (try ${++e}).`),browser=await puppeteer.launch(i)}catch(o){if(logWithStack(1,o,"[browser] Failed to launch a browser instance."),!(e<25))throw o;log(3,`[browser] Retry to open a browser (${e} out of 25).`),await new Promise((e=>setTimeout(e,4e3))),await t()}};try{await t(),"shell"===i.headless&&log(3,"[browser] Launched browser in shell mode."),r&&log(3,"[browser] Launched browser in debug mode.")}catch(e){throw new ExportError("[browser] Maximum retries to open a browser instance reached.",500).setError(e)}if(!browser)throw new ExportError("[browser] Cannot find a browser to open.",500)}return browser}async function closeBrowser(){browser&&browser.connected&&await browser.close(),browser=null,log(4,"[browser] Closed the browser.")}async function newPage(e){if(!browser||!browser.connected)throw new ExportError("[browser] Browser is not yet connected.",500);if(e.page=await browser.newPage(),await e.page.setCacheEnabled(!1),await _setPageContent(e.page),_setPageEvents(e.page),!e.page||e.page.isClosed())throw new ExportError("[browser] The page is invalid or closed.",400)}async function clearPage(e,t=!1){try{if(e.page&&!e.page.isClosed())return t?(await e.page.goto("about:blank",{waitUntil:"domcontentloaded"}),await _setPageContent(e.page)):await e.page.evaluate((()=>{document.body.innerHTML='
'})),!0}catch(t){logWithStack(2,t,`[pool] Pool resource [${e.id}] - Content of the page could not be cleared.`),e.workCount=getOptions().pool.workLimit+1}return!1}async function addPageResources(e,t){const o=[],r=t.resources;if(r){const n=[];if(r.js&&n.push({content:r.js}),r.files)for(const e of r.files){const t=!e.startsWith("http");n.push(t?{content:fs.readFileSync(getAbsolutePath(e),"utf8")}:{url:e})}for(const t of n)try{o.push(await e.addScriptTag(t))}catch(e){logWithStack(2,e,"[browser] The JS resource cannot be loaded.")}n.length=0;const i=[];if(r.css){let n=r.css.match(/@import\s*([^;]*);/g);if(n)for(let e of n)e&&(e=e.replace("url(","").replace("@import","").replace(/"/g,"").replace(/'/g,"").replace(/;/,"").replace(/\)/g,"").trim(),e.startsWith("http")?i.push({url:e}):t.allowFileResources&&i.push({path:path.join(__dirname$1,e)}));i.push({content:r.css.replace(/@import\s*([^;]*);/g,"")||" "});for(const t of i)try{o.push(await e.addStyleTag(t))}catch(e){logWithStack(2,e,"[browser] The CSS resource cannot be loaded.")}i.length=0}}return o}async function clearPageResources(e,t){try{for(const e of t)await e.dispose();await e.evaluate((()=>{if("undefined"!=typeof Highcharts){const e=Highcharts.charts;if(Array.isArray(e)&&e.length)for(const t of e)t&&t.destroy(),Highcharts.charts.shift()}const[...e]=document.getElementsByTagName("script"),[,...t]=document.getElementsByTagName("style"),[...o]=document.getElementsByTagName("link");for(const r of[...e,...t,...o])r.remove()}))}catch(e){logWithStack(2,e,"[browser] Could not clear page's resources.")}}async function _setPageContent(e){await e.setContent(template,{waitUntil:"domcontentloaded"}),await e.addScriptTag({path:path.join(getCachePath(),"sources.js")}),await e.evaluate(setupHighcharts)}function _setPageEvents(e){const{debug:t}=getOptions();e.on("pageerror",(async()=>{e.isClosed()})),t.enable&&t.listenToConsole&&e.on("console",(e=>{console.log(`[debug] ${e.text()}`)}))}var cssTemplate=()=>"\n\nhtml, body {\n margin: 0;\n padding: 0;\n box-sizing: border-box;\n}\n\n#table-div, #sliders, #datatable, #controls, .ld-row {\n display: none;\n height: 0;\n}\n\n#chart-container {\n box-sizing: border-box;\n margin: 0;\n overflow: auto;\n font-size: 0;\n}\n\n#chart-container > figure, div {\n margin-top: 0 !important;\n margin-bottom: 0 !important;\n}\n\n",svgTemplate=e=>`\n\n\n \n \n Highcharts Export\n \n \n \n
\n ${e}\n
\n \n\n\n`;async function puppeteerExport(e,t){const o=[];try{const r=t.export;let n=!1;if(r.svg){if(log(4,"[export] Treating as SVG input."),"svg"===r.type)return r.svg;n=!0,await _setAsSvg(e,r.svg)}else log(4,"[export] Treating as JSON config."),await _setAsOptions(e,t);o.push(...await addPageResources(e,t.customLogic));const i=n?await e.evaluate((e=>{const t=document.querySelector("#chart-container svg:first-of-type"),o=t.height.baseVal.value*e,r=t.width.baseVal.value*e;return document.body.style.zoom=e,document.body.style.margin="0px",{chartHeight:o,chartWidth:r}}),parseFloat(r.scale)):await e.evaluate((()=>{const{chartHeight:e,chartWidth:t}=window.Highcharts.charts[0];return document.body.style.zoom=1,{chartHeight:e,chartWidth:t}})),{x:s,y:a}=await _getClipRegion(e),l=Math.abs(Math.ceil(i.chartHeight||r.height)),c=Math.abs(Math.ceil(i.chartWidth||r.width));let p;switch(await e.setViewport({height:l,width:c,deviceScaleFactor:n?1:parseFloat(r.scale)}),r.type){case"svg":p=await _createSVG(e);break;case"png":case"jpeg":p=await _createImage(e,r.type,{width:c,height:l,x:s,y:a},r.rasterizationTimeout);break;case"pdf":p=await _createPDF(e,l,c,r.rasterizationTimeout);break;default:throw new ExportError(`[export] Unsupported output format: ${r.type}.`,400)}return await clearPageResources(e,o),p}catch(t){return await clearPageResources(e,o),t}}async function _setAsSvg(e,t){await e.setContent(svgTemplate(t),{waitUntil:"domcontentloaded"})}async function _setAsOptions(e,t){await e.evaluate(createChart,t)}async function _getClipRegion(e){return e.$eval("#chart-container",(e=>{const{x:t,y:o,width:r,height:n}=e.getBoundingClientRect();return{x:t,y:o,width:r,height:Math.trunc(n>1?n:500)}}))}async function _createSVG(e){return e.$eval("#container svg:first-of-type",(e=>e.outerHTML))}async function _createImage(e,t,o,r){return Promise.race([e.screenshot({type:t,clip:o,encoding:"base64",fullPage:!1,optimizeForSpeed:!0,captureBeyondViewport:!0,..."png"!==t?{quality:80}:{},omitBackground:"png"==t}),new Promise(((e,t)=>setTimeout((()=>t(new ExportError("Rasterization timeout",408))),r||1500)))])}async function _createPDF(e,t,o,r){return await e.emulateMediaType("screen"),e.pdf({height:t+1,width:o,encoding:"base64",timeout:r||1500})}let pool=null;const poolStats={exportsAttempted:0,exportsPerformed:0,exportsDropped:0,exportsFromSvg:0,exportsFromOptions:0,exportsFromSvgAttempts:0,exportsFromOptionsAttempts:0,timeSpent:0,timeSpentAverage:0};async function initPool(e=getOptions().pool,t=[]){await createBrowser(t);try{if(log(3,`[pool] Initializing pool with workers: min ${e.minWorkers}, max ${e.maxWorkers}.`),pool)return void log(4,"[pool] Already initialized, please kill it before creating a new one.");e.minWorkers>e.maxWorkers&&(e.minWorkers=e.maxWorkers),pool=new tarn.Pool({..._factory(e),min:e.minWorkers,max:e.maxWorkers,acquireTimeoutMillis:e.acquireTimeout,createTimeoutMillis:e.createTimeout,destroyTimeoutMillis:e.destroyTimeout,idleTimeoutMillis:e.idleTimeout,createRetryIntervalMillis:e.createRetryInterval,reapIntervalMillis:e.reaperInterval,propagateCreateError:!1}),pool.on("release",(async e=>{const t=await clearPage(e,!1);log(4,`[pool] Pool resource [${e.id}] - Releasing a worker. Clear page status: ${t}.`)})),pool.on("destroySuccess",((e,t)=>{log(4,`[pool] Pool resource [${t.id}] - Destroyed a worker successfully.`),t.page=null}));const t=[];for(let o=0;o{pool.release(e)})),log(3,"[pool] The pool is ready"+(t.length?` with ${t.length} initial resources waiting.`:"."))}catch(e){throw new ExportError("[pool] Could not configure and create the pool of workers.",500).setError(e)}}async function killPool(){if(log(3,"[pool] Killing pool with all workers and closing browser."),pool){for(const e of pool.used)pool.release(e.resource);pool.destroyed||(await pool.destroy(),log(4,"[pool] Destroyed the pool of resources.")),pool=null}await closeBrowser()}async function postWork(e){let t;try{if(log(4,"[pool] Work received, starting to process."),++poolStats.exportsAttempted,getOptions().pool.benchmarking&&getPoolInfo(),!pool)throw new ExportError("[pool] Work received, but pool has not been started.",500);const o=measureTime();try{log(4,"[pool] Acquiring a worker handle."),t=await pool.acquire().promise,e.server.benchmarking&&log(5,e._requestId?`[benchmark] Request [${e._requestId}] - `:"[benchmark] ",`Acquiring a worker handle took ${o()}ms.`)}catch(t){throw new ExportError("[pool] "+(e._requestId?`Request [${e._requestId}] - `:"")+`Error encountered when acquiring an available entry: ${o()}ms.`,400).setError(t)}if(log(4,"[pool] Acquired a worker handle."),!t.page)throw t.workCount=e.pool.workLimit+1,new ExportError("[pool] Resolved worker page is invalid: the pool setup is wonky.",400);const r=getNewDateTime();log(4,`[pool] Pool resource [${t.id}] - Starting work on this pool entry.`);const n=measureTime(),i=await puppeteerExport(t.page,e);if(i instanceof Error)throw"Rasterization timeout"===i.message&&(t.workCount=e.pool.workLimit+1,t.page=null),"TimeoutError"===i.name||"Rasterization timeout"===i.message?new ExportError("[pool] "+(e._requestId?`Request [${e._requestId}] - `:"")+"Rasterization timeout: your chart may be too complex or large, and failed to render within the allotted time.").setError(i):new ExportError("[pool] "+(e._requestId?`Request [${e._requestId}] - `:"")+`Error encountered during export: ${n()}ms.`).setError(i);e.server.benchmarking&&log(5,e._requestId?`[benchmark] Request [${e._requestId}] - `:"[benchmark] ",`Exporting a chart sucessfully took ${n()}ms.`),pool.release(t);const s=getNewDateTime()-r;return poolStats.timeSpent+=s,poolStats.timeSpentAverage=poolStats.timeSpent/++poolStats.exportsPerformed,log(4,`[pool] Work completed in ${s}ms.`),{result:i,options:e}}catch(e){throw++poolStats.exportsDropped,t&&pool.release(t),e}}function getPoolStats(){return poolStats}function getPoolInfoJSON(){return{min:pool.min,max:pool.max,used:pool.numUsed(),available:pool.numFree(),allCreated:pool.numUsed()+pool.numFree(),pendingAcquires:pool.numPendingAcquires(),pendingCreates:pool.numPendingCreates(),pendingValidations:pool.numPendingValidations(),pendingDestroys:pool.pendingDestroys.length,absoluteAll:pool.numUsed()+pool.numFree()+pool.numPendingAcquires()+pool.numPendingCreates()+pool.numPendingValidations()+pool.pendingDestroys.length}}function getPoolInfo(){const{min:e,max:t,used:o,available:r,allCreated:n,pendingAcquires:i,pendingCreates:s,pendingValidations:a,pendingDestroys:l,absoluteAll:c}=getPoolInfoJSON();log(5,`[pool] The minimum number of resources allowed by pool: ${e}.`),log(5,`[pool] The maximum number of resources allowed by pool: ${t}.`),log(5,`[pool] The number of used resources: ${o}.`),log(5,`[pool] The number of free resources: ${r}.`),log(5,`[pool] The number of all created (used and free) resources: ${n}.`),log(5,`[pool] The number of resources waiting to be acquired: ${i}.`),log(5,`[pool] The number of resources waiting to be created: ${s}.`),log(5,`[pool] The number of resources waiting to be validated: ${a}.`),log(5,`[pool] The number of resources waiting to be destroyed: ${l}.`),log(5,`[pool] The number of all resources: ${c}.`)}function _factory(e){return{create:async()=>{const t={id:uuid.v4(),workCount:Math.round(Math.random()*(e.workLimit/2))};try{const e=getNewDateTime();return await newPage(t),log(3,`[pool] Pool resource [${t.id}] - Successfully created a worker, took ${getNewDateTime()-e}ms.`),t}catch(e){throw log(3,`[pool] Pool resource [${t.id}] - Error encountered when creating a new page.`),e}},validate:async t=>t.page?t.page.isClosed()?(log(3,`[pool] Pool resource [${t.id}] - Validation failed (page is closed or invalid).`),!1):t.page.mainFrame().detached?(log(3,`[pool] Pool resource [${t.id}] - Validation failed (page's frame is detached).`),!1):!(e.workLimit&&++t.workCount>e.workLimit)||(log(3,`[pool] Pool resource [${t.id}] - Validation failed (exceeded the ${e.workLimit} works per resource limit).`),!1):(log(3,`[pool] Pool resource [${t.id}] - Validation failed (no valid page is found).`),!1),destroy:async e=>{if(log(3,`[pool] Pool resource [${e.id}] - Destroying a worker.`),e.page&&!e.page.isClosed())try{e.page.removeAllListeners("pageerror"),e.page.removeAllListeners("console"),e.page.removeAllListeners("framedetached"),await e.page.close()}catch(t){throw log(3,`[pool] Pool resource [${e.id}] - Page could not be closed upon destroying.`),t}}}}function sanitize(e){const t=new jsdom.JSDOM("").window;return DOMPurify(t).sanitize(e,{ADD_TAGS:["foreignObject"]})}let allowCodeExecution=!1;async function singleExport(e){if(!e||!e.export)throw new ExportError("[chart] No expected `export` options were found. Please provide one of the following options: `infile`, `instr`, `options`, or `svg` to generate a valid image.",400);await startExport(e,(async(e,t)=>{if(e)throw e;const{b64:o,outfile:r,type:n}=t.options.export;try{o?fs.writeFileSync(`${r.split(".").shift()||"chart"}.txt`,getBase64(t.result,n)):fs.writeFileSync(r||`chart.${n}`,"svg"!==n?Buffer.from(t.result,"base64"):t.result)}catch(e){throw new ExportError("[chart] Error while saving a chart.",500).setError(e)}await killPool()}))}async function batchExport(e){if(!(e&&e.export&&e.export.batch))throw new ExportError("[chart] No expected `export` options were found. Please provide the `batch` option to generate valid images.",400);{const t=[];for(let o of e.export.batch.split(";")||[])o=o.split("="),2===o.length?t.push(startExport({...e,export:{...e.export,infile:o[0],outfile:o[1]}},((e,t)=>{if(e)throw e;const{b64:o,outfile:r,type:n}=t.options.export;try{o?fs.writeFileSync(`${r.split(".").shift()||"chart"}.txt`,getBase64(t.result,n)):fs.writeFileSync(r,"svg"!==n?Buffer.from(t.result,"base64"):t.result)}catch(e){throw new ExportError("[chart] Error while saving a chart.",500).setError(e)}}))):log(2,"[chart] No correct pair found for the batch export.");const o=await Promise.allSettled(t);await killPool(),o.forEach(((e,t)=>{e.reason&&logWithStack(1,e.reason,`[chart] Batch export number ${t+1} could not be correctly completed.`)}))}}async function startExport(e,t){try{log(4,"[chart] Starting the exporting process.");const o=mergeOptions(getOptions(!1),e),r=o.export;if(null!==r.infile){let e;log(4,"[chart] Attempting to export from a file input.");try{e=fs.readFileSync(getAbsolutePath(r.infile),"utf8")}catch(e){throw new ExportError("[chart] Error loading content from a file input.",400).setError(e)}if(r.infile.endsWith(".svg"))r.svg=e;else{if(!r.infile.endsWith(".json"))throw new ExportError("[chart] Incorrect value of the `infile` option.",400);r.instr=e}}if(null!==r.svg){log(4,"[chart] Attempting to export from an SVG input."),++getPoolStats().exportsFromSvgAttempts;const e=await _exportFromSvg(sanitize(r.svg),o);return++getPoolStats().exportsFromSvg,t(null,e)}if(null!==r.instr||null!==r.options){log(4,"[chart] Attempting to export from options input."),++getPoolStats().exportsFromOptionsAttempts;const e=await _exportFromOptions(r.instr||r.options,o);return++getPoolStats().exportsFromOptions,t(null,e)}return t(new ExportError("[chart] No valid input specified. Check if at least one of the following parameters is correctly set: 'infile', 'instr', 'options', or 'svg'.",400))}catch(e){return t(e)}}function getAllowCodeExecution(){return allowCodeExecution}function setAllowCodeExecution(e){allowCodeExecution=e}async function _exportFromSvg(e,t){if("string"==typeof e&&(e.indexOf("=0||e.indexOf("=0))return log(4,"[chart] Parsing input as SVG."),t.export.svg=e,t.export.instr=null,t.export.options=null,_prepareExport(t);throw new ExportError("[chart] Not a correct SVG input.",400)}async function _exportFromOptions(e,t){log(4,"[chart] Parsing input from options.");const o=isAllowedConfig(e,!0,t.customLogic.allowCodeExecution);if(null===o||"string"!=typeof o||!o.startsWith("{")||!o.endsWith("}"))throw new ExportError("[chart] Invalid configuration provided - Only options configurations and SVG are allowed for this server. If this is your server, JavaScript custom code can be enabled by starting the server with the `allowCodeExecution` options set to true.",403);return t.export.instr=o,t.export.svg=null,_prepareExport(t)}async function _prepareExport(e){const{export:t,customLogic:o}=e;return t.type=fixType(t.type,t.outfile),t.outfile=fixOutfile(t.type,t.outfile),log(3,`[chart] The custom logic is ${o.allowCodeExecution?"allowed":"disallowed"}.`),_handleCustomLogic(o,o.allowCodeExecution),_handleGlobalAndTheme(t,o.allowFileResources,o.allowCodeExecution),e.export={...t,..._findChartSize(t)},postWork(e)}function _findChartSize(e){const{chart:t,exporting:o}=e.options||isAllowedConfig(e.instr)||!1,{chart:r,exporting:n}=isAllowedConfig(e.globalOptions)||!1,{chart:i,exporting:s}=isAllowedConfig(e.themeOptions)||!1,a=roundNumber(Math.max(.1,Math.min(e.scale||o?.scale||n?.scale||s?.scale||e.defaultScale||1,5)),2),l={height:e.height||o?.sourceHeight||t?.height||n?.sourceHeight||r?.height||s?.sourceHeight||i?.height||e.defaultHeight||400,width:e.width||o?.sourceWidth||t?.width||n?.sourceWidth||r?.width||s?.sourceWidth||i?.width||e.defaultWidth||600,scale:a};for(let[e,t]of Object.entries(l))l[e]="string"==typeof t?+t.replace(/px|%/gi,""):t;return l}function _handleCustomLogic(e,t){if(t){if("string"==typeof e.resources)e.resources=_handleResources(e.resources,e.allowFileResources,!0);else if(!e.resources)try{e.resources=_handleResources(fs.readFileSync(getAbsolutePath("resources.json"),"utf8"),e.allowFileResources,!0)}catch(e){log(2,"[chart] Unable to load the default `resources.json` file.")}try{e.customCode=wrapAround(e.customCode,e.allowFileResources)}catch(t){logWithStack(2,t,"[chart] The `customCode` cannot be loaded."),e.customCode=null}try{e.callback=wrapAround(e.callback,e.allowFileResources,!0)}catch(t){logWithStack(2,t,"[chart] The `callback` cannot be loaded."),e.callback=null}[null,void 0].includes(e.customCode)&&log(3,"[chart] No value for the `customCode` option found."),[null,void 0].includes(e.callback)&&log(3,"[chart] No value for the `callback` option found."),[null,void 0].includes(e.resources)&&log(3,"[chart] No value for the `resources` option found.")}else if(e.callback||e.resources||e.customCode)throw e.callback=null,e.resources=null,e.customCode=null,new ExportError("[chart] The 'callback', 'resources', and 'customCode' options have been disabled for this server.",403)}function _handleResources(e=null,t,o){const r=["js","css","files"];let n=e,i=!1;if(t&&e.endsWith(".json"))try{n=isAllowedConfig(fs.readFileSync(getAbsolutePath(e),"utf8"),!1,o)}catch{return null}else n=isAllowedConfig(e,!1,o),n&&!t&&delete n.files;for(const e in n)r.includes(e)?i||(i=!0):delete n[e];return i?(n.files&&(n.files=n.files.map((e=>e.trim())),(!n.files||n.files.length<=0)&&delete n.files),n):null}function _handleGlobalAndTheme(e,t,o){["globalOptions","themeOptions"].forEach((r=>{try{e[r]&&(t&&"string"==typeof e[r]&&e[r].endsWith(".json")?e[r]=isAllowedConfig(fs.readFileSync(getAbsolutePath(e[r]),"utf8"),!0,o):e[r]=isAllowedConfig(e[r],!0,o))}catch(t){logWithStack(2,t,`[chart] The \`${r}\` cannot be loaded.`),e[r]=null}})),[null,void 0].includes(e.globalOptions)&&log(3,"[chart] No value for the `globalOptions` option found."),[null,void 0].includes(e.themeOptions)&&log(3,"[chart] No value for the `themeOptions` option found.")}const timerIds=[];function addTimer(e){timerIds.push(e)}function clearAllTimers(){log(4,"[timer] Clearing all registered intervals and timeouts.");for(const e of timerIds)clearInterval(e),clearTimeout(e)}function logErrorMiddleware(e,t,o,r){return logWithStack(1,e),"development"!==getOptions().other.nodeEnv&&delete e.stack,r(e)}function returnErrorMiddleware(e,t,o,r){const{message:n,stack:i}=e,s=e.statusCode||400;o.status(s).json({statusCode:s,message:n,stack:i})}function errorMiddleware(e){e.use(logErrorMiddleware),e.use(returnErrorMiddleware)}function rateLimitingMiddleware(e,t=getOptions().server.rateLimiting){try{if(t.enable){const o="Too many requests, you have been rate limited. Please try again later.",r={max:t.maxRequests||30,window:t.window||1,delay:t.delay||0,trustProxy:t.trustProxy||!1,skipKey:t.skipKey||!1,skipToken:t.skipToken||!1};r.trustProxy&&e.enable("trust proxy");const n=rateLimit({windowMs:60*r.window*1e3,max:r.max,delayMs:r.delay,handler:(e,t)=>{t.format({json:()=>{t.status(429).send({message:o})},default:()=>{t.status(429).send(o)}})},skip:e=>!1!==r.skipKey&&!1!==r.skipToken&&e.query.key===r.skipKey&&e.query.access_token===r.skipToken&&(log(4,"[rate limiting] Skipping rate limiter."),!0)});e.use(n),log(3,`[rate limiting] Enabled rate limiting with ${r.max} requests per ${r.window} minute for each IP, trusting proxy: ${r.trustProxy}.`)}}catch(e){throw new ExportError("[rate limiting] Could not configure and set the rate limiting options.",500).setError(e)}}class HttpError extends ExportError{constructor(e,t){super(e,t)}setStatus(e){return this.statusCode=e,this}}function contentTypeMiddleware(e,t,o){try{const t=e.headers["content-type"]||"";if(!t.includes("application/json")&&!t.includes("application/x-www-form-urlencoded")&&!t.includes("multipart/form-data"))throw new HttpError("[validation] Content-Type must be application/json, application/x-www-form-urlencoded, or multipart/form-data.",415);return o()}catch(e){return o(e)}}function requestBodyMiddleware(e,t,o){try{const t=e.body,r=uuid.v4().replace(/-/g,"");if(!t||isObjectEmpty(t))throw log(2,`[validation] Request [${r}] - The request from ${e.headers["x-forwarded-for"]||e.connection.remoteAddress} was incorrect. Received payload is empty.`),new HttpError("[validation] The request body is required. Please ensure that your Content-Type header is correct. Accepted types are 'application/json' and 'multipart/form-data'.",400);const n=getAllowCodeExecution(),i=isAllowedConfig(t.instr||t.options||t.infile||t.data,!0,n);if(null===i&&!t.svg)throw log(2,`[validation] Request [${r}] - The request from ${e.headers["x-forwarded-for"]||e.connection.remoteAddress} was incorrect. Received payload is missing correct chart data for export: ${JSON.stringify(t)}.`),new HttpError("[validation] No correct chart data found. Ensure that you are using either application/json or multipart/form-data headers. If sending JSON, make sure the chart data is in the 'infile', 'options', or 'data' attribute. If sending SVG, ensure it is in the 'svg' attribute.",400);if(t.svg&&isPrivateRangeUrlFound(t.svg))throw new HttpError("[validation] SVG potentially contain at least one forbidden URL in 'xlink:href' element. Please review the SVG content and ensure that all referenced URLs comply with security policies.",400);return e.validatedOptions={_requestId:r,export:{instr:i,svg:t.svg,outfile:t.outfile||`${e.params.filename||"chart"}.${fixType(t.type)}`,type:fixType(t.type,t.outfile),constr:fixConstr(t.constr),b64:t.b64,noDownload:t.noDownload,height:t.height,width:t.width,scale:t.scale,globalOptions:isAllowedConfig(t.globalOptions,!0,n),themeOptions:isAllowedConfig(t.themeOptions,!0,n)},customLogic:{allowCodeExecution:n,allowFileResources:!1,customCode:t.customCode,callback:t.callback,resources:isAllowedConfig(t.resources,!0,n)}},o()}catch(e){return o(e)}}function validationMiddleware(e){e.post(["/","/:filename"],contentTypeMiddleware),e.post(["/","/:filename"],requestBodyMiddleware)}const reversedMime={png:"image/png",jpeg:"image/jpeg",gif:"image/gif",pdf:"application/pdf",svg:"image/svg+xml"};async function requestExport(e,t,o){try{const o=measureTime();let r=!1;e.socket.on("close",(e=>{e&&(r=!0)}));const n=e.validatedOptions,i=n._requestId;log(4,`[export] Got an incoming HTTP request with ID ${i}.`),await startExport(n,((n,s)=>{if(e.socket.removeAllListeners("close"),r)log(3,`[export] Request [${i}] - The client closed the connection before the chart finished processing.`);else{if(n)throw n;if(!s||!s.result)throw log(2,`[export] Request [${i}] - Request from ${e.headers["x-forwarded-for"]||e.connection.remoteAddress} was incorrect. Received result is ${s.result}.`),new HttpError("[export] Unexpected return of the export result from the chart generation. Please check your request data.",400);if(s.result){log(3,`[export] Request [${i}] - The whole exporting process took ${o()}ms.`);const{type:e,b64:r,noDownload:n,outfile:a}=s.options.export;return r?t.send(getBase64(s.result,e)):(t.header("Content-Type",reversedMime[e]||"image/png"),n||t.attachment(a),"svg"===e?t.send(s.result):t.send(Buffer.from(s.result,"base64")))}}}))}catch(e){return o(e)}}function exportRoutes(e){e.post("/",requestExport),e.post("/:filename",requestExport)}const serverStartTime=new Date,packageFile=JSON.parse(fs.readFileSync(path.join(__dirname$1,"package.json"))),successRates=[],recordInterval=6e4,windowSize=30;function _calculateMovingAverage(){return successRates.reduce(((e,t)=>e+t),0)/successRates.length}function _startSuccessRate(){return setInterval((()=>{const e=getPoolStats(),t=0===e.exportsAttempted?1:e.exportsPerformed/e.exportsAttempted*100;successRates.push(t),successRates.length>windowSize&&successRates.shift()}),recordInterval)}function healthRoutes(e){addTimer(_startSuccessRate()),e.get("/health",((e,t,o)=>{try{log(4,"[health] Returning server health.");const e=getPoolStats(),o=successRates.length,r=_calculateMovingAverage();t.send({status:"OK",bootTime:serverStartTime,uptime:`${Math.floor((getNewDateTime()-serverStartTime.getTime())/1e3/60)} minutes`,serverVersion:packageFile.version,highchartsVersion:getHighchartsVersion(),averageExportTime:e.timeSpentAverage,attemptedExports:e.exportsAttempted,performedExports:e.exportsPerformed,failedExports:e.exportsDropped,sucessRatio:e.exportsPerformed/e.exportsAttempted*100,pool:getPoolInfoJSON(),period:o,movingAverage:r,message:isNaN(r)||!successRates.length?"Too early to report. No exports made yet. Please check back soon.":`Last ${o} minutes had a success rate of ${r.toFixed(2)}%.`,svgExports:e.exportsFromSvg,jsonExports:e.exportsFromOptions,svgExportsAttempts:e.exportsFromSvgAttempts,jsonExportsAttempts:e.exportsFromOptionsAttempts})}catch(e){return o(e)}}))}function uiRoutes(e){e.get(getOptions().ui.route||"/",((e,t,o)=>{try{t.sendFile(path.join(__dirname$1,"public","index.html"),{acceptRanges:!1})}catch(e){return o(e)}}))}function versionChangeRoutes(e){e.post("/version_change/:newVersion",(async(e,t,o)=>{try{const o=envs.HIGHCHARTS_ADMIN_TOKEN;if(!o||!o.length)throw new HttpError("[version] The server is not configured to perform run-time version changes: HIGHCHARTS_ADMIN_TOKEN is not set.",401);const r=e.get("hc-auth");if(!r||r!==o)throw new HttpError("[version] Invalid or missing token: Set the token in the hc-auth header.",401);const n=e.params.newVersion;if(!n)throw new HttpError("[version] No new version supplied.",400);try{await updateHighchartsVersion(n)}catch(e){throw new HttpError(`[version] Version change: ${e.message}`,400).setError(e)}t.status(200).send({statusCode:200,highchartsVersion:getHighchartsVersion(),message:`Successfully updated Highcharts to version: ${n}.`})}catch(e){return o(e)}}))}const activeServers=new Map,app=express();async function startServer(e=getOptions().server){try{if(!e.enable||!app)throw new ExportError("[server] Server cannot be started (not enabled or no correct Express app found).",500);const t=1024*e.uploadLimit*1024,o=multer.memoryStorage(),r=multer({storage:o,limits:{fieldSize:t}});if(app.disable("x-powered-by"),app.use(cors({methods:["POST","GET","OPTIONS"]})),app.use(((e,t,o)=>{t.set("Accept-Ranges","none"),o()})),app.use(express.json({limit:t})),app.use(express.urlencoded({extended:!0,limit:t})),app.use(r.none()),app.use(express.static(path.join(__dirname$1,"public"))),!e.ssl.force){const t=http.createServer(app);_attachServerErrorHandlers(t),t.listen(e.port,e.host,(()=>{activeServers.set(e.port,t),log(3,`[server] Started HTTP server on ${e.host}:${e.port}.`)}))}if(e.ssl.enable){let t,o;try{t=await promises.readFile(path.join(getAbsolutePath(e.ssl.certPath),"server.key"),"utf8"),o=await promises.readFile(path.join(getAbsolutePath(e.ssl.certPath),"server.crt"),"utf8")}catch(t){log(2,`[server] Unable to load key/certificate from the '${e.ssl.certPath}' path. Could not run secured layer server.`)}if(t&&o){const r=https.createServer({key:t,cert:o},app);_attachServerErrorHandlers(r),r.listen(e.ssl.port,e.host,(()=>{activeServers.set(e.ssl.port,r),log(3,`[server] Started HTTPS server on ${e.host}:${e.ssl.port}.`)}))}}rateLimitingMiddleware(app,e.rateLimiting),validationMiddleware(app),healthRoutes(app),exportRoutes(app),uiRoutes(app),versionChangeRoutes(app),errorMiddleware(app)}catch(e){throw new ExportError("[server] Could not configure and start the server.",500).setError(e)}}function closeServers(){if(activeServers.size>0){log(4,"[server] Closing all servers.");for(const[e,t]of activeServers)t.close((()=>{activeServers.delete(e),log(4,`[server] Closed server on port: ${e}.`)}))}}function getServers(){return activeServers}function getExpress(){return express}function getApp(){return app}function enableRateLimiting(e){rateLimitingMiddleware(app,e)}function use(e,...t){app.use(e,...t)}function get(e,...t){app.get(e,...t)}function post(e,...t){app.post(e,...t)}function _attachServerErrorHandlers(e){e.on("clientError",((e,t)=>{logWithStack(1,e,`[server] Client error: ${e.message}, destroying socket.`),t.destroy()})),e.on("error",(e=>{logWithStack(1,e,`[server] Server error: ${e.message}`)})),e.on("connection",(e=>{e.on("error",(e=>{logWithStack(1,e,`[server] Socket error: ${e.message}`)}))}))}var server={startServer:startServer,closeServers:closeServers,getServers:getServers,getExpress:getExpress,getApp:getApp,enableRateLimiting:enableRateLimiting,use:use,get:get,post:post};async function shutdownCleanUp(e){await Promise.allSettled([clearAllTimers(),closeServers(),killPool()]),process.exit(e)}async function initExport(e){const t=mergeOptions(getOptions(!1),e);setAllowCodeExecution(t.customLogic.allowCodeExecution),initLogging(t.logging),t.other.listenToProcessExits&&_attachProcessExitListeners(),await checkAndUpdateCache(t.highcharts,t.server.proxy),await initPool(t.pool,t.puppeteer.args)}function _attachProcessExitListeners(){log(3,"[process] Attaching exit listeners to the process."),process.on("exit",(e=>{log(4,`[process] Process exited with code ${e}.`)})),process.on("SIGINT",(async(e,t)=>{log(4,`[process] The ${e} event with code: ${t}.`),await shutdownCleanUp(0)})),process.on("SIGTERM",(async(e,t)=>{log(4,`[process] The ${e} event with code: ${t}.`),await shutdownCleanUp(0)})),process.on("SIGHUP",(async(e,t)=>{log(4,`[process] The ${e} event with code: ${t}.`),await shutdownCleanUp(0)})),process.on("uncaughtException",(async(e,t)=>{logWithStack(1,e,`[process] The ${t} error.`),await shutdownCleanUp(1)}))}var index={server:server,startServer:startServer,getOptions:getOptions,setOptions:setOptions,mergeOptions:mergeOptions,mapToNewOptions:mapToNewOptions,initExport:initExport,singleExport:singleExport,batchExport:batchExport,startExport:startExport,checkAndUpdateCache:checkAndUpdateCache,initPool:initPool,killPool:killPool,log:log,logWithStack:logWithStack,setLogLevel:setLogLevel,enableConsoleLogging:enableConsoleLogging,enableFileLogging:enableFileLogging,shutdownCleanUp:shutdownCleanUp};exports.default=index,exports.initExport=initExport; -//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguY2pzIiwic291cmNlcyI6WyIuLi9saWIvdXRpbHMuanMiLCIuLi9saWIvbG9nZ2VyLmpzIiwiLi4vbGliL3NjaGVtYXMvY29uZmlnLmpzIiwiLi4vbGliL2VudnMuanMiLCIuLi9saWIvY29uZmlnLmpzIiwiLi4vbGliL2ZldGNoLmpzIiwiLi4vbGliL2Vycm9ycy9FeHBvcnRFcnJvci5qcyIsIi4uL2xpYi9jYWNoZS5qcyIsIi4uL2xpYi9oaWdoY2hhcnRzLmpzIiwiLi4vbGliL2Jyb3dzZXIuanMiLCIuLi90ZW1wbGF0ZXMvc3ZnRXhwb3J0L2Nzcy5qcyIsIi4uL3RlbXBsYXRlcy9zdmdFeHBvcnQvc3ZnRXhwb3J0LmpzIiwiLi4vbGliL2V4cG9ydC5qcyIsIi4uL2xpYi9wb29sLmpzIiwiLi4vbGliL3Nhbml0aXplLmpzIiwiLi4vbGliL2NoYXJ0LmpzIiwiLi4vbGliL3RpbWVyLmpzIiwiLi4vbGliL3NlcnZlci9taWRkbGV3YXJlcy9lcnJvci5qcyIsIi4uL2xpYi9zZXJ2ZXIvbWlkZGxld2FyZXMvcmF0ZUxpbWl0aW5nLmpzIiwiLi4vbGliL2Vycm9ycy9IdHRwRXJyb3IuanMiLCIuLi9saWIvc2VydmVyL21pZGRsZXdhcmVzL3ZhbGlkYXRpb24uanMiLCIuLi9saWIvc2VydmVyL3JvdXRlcy9leHBvcnQuanMiLCIuLi9saWIvc2VydmVyL3JvdXRlcy9oZWFsdGguanMiLCIuLi9saWIvc2VydmVyL3JvdXRlcy91aS5qcyIsIi4uL2xpYi9zZXJ2ZXIvcm91dGVzL3ZlcnNpb25DaGFuZ2UuanMiLCIuLi9saWIvc2VydmVyL3NlcnZlci5qcyIsIi4uL2xpYi9yZXNvdXJjZVJlbGVhc2UuanMiLCIuLi9saWIvaW5kZXguanMiXSwic291cmNlc0NvbnRlbnQiOlsiLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcclxuXHJcbkhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlclxyXG5cclxuQ29weXJpZ2h0IChjKSAyMDE2LTIwMjUsIEhpZ2hzb2Z0XHJcblxyXG5MaWNlbmNlZCB1bmRlciB0aGUgTUlUIGxpY2VuY2UuXHJcblxyXG5BZGRpdGlvbmFsbHkgYSB2YWxpZCBIaWdoY2hhcnRzIGxpY2Vuc2UgaXMgcmVxdWlyZWQgZm9yIHVzZS5cclxuXHJcblNlZSBMSUNFTlNFIGZpbGUgaW4gcm9vdCBmb3IgZGV0YWlscy5cclxuXHJcbioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXHJcblxyXG4vKipcclxuICogQG92ZXJ2aWV3IFRoZSBIaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXIgdXRpbGl0eSBtb2R1bGUgcHJvdmlkZXNcclxuICogYSBjb21wcmVoZW5zaXZlIHNldCBvZiBoZWxwZXIgZnVuY3Rpb25zIGFuZCBjb25zdGFudHMgZGVzaWduZWQgdG8gc3RyZWFtbGluZVxyXG4gKiBhbmQgZW5oYW5jZSB2YXJpb3VzIG9wZXJhdGlvbnMgcmVxdWlyZWQgZm9yIEhpZ2hjaGFydHMgZXhwb3J0IHRhc2tzLlxyXG4gKi9cclxuXHJcbmltcG9ydCB7IHJlYWRGaWxlU3luYyB9IGZyb20gJ2ZzJztcclxuaW1wb3J0IHsgaXNBYnNvbHV0ZSwgam9pbiB9IGZyb20gJ3BhdGgnO1xyXG5pbXBvcnQgeyBmaWxlVVJMVG9QYXRoIH0gZnJvbSAndXJsJztcclxuXHJcbmNvbnN0IE1BWF9CQUNLT0ZGX0FUVEVNUFRTID0gNjtcclxuXHJcbi8vIFRoZSBkaXJlY3RvcnkgcGF0aFxyXG5leHBvcnQgY29uc3QgX19kaXJuYW1lID0gZmlsZVVSTFRvUGF0aChuZXcgVVJMKCcuLi8uJywgaW1wb3J0Lm1ldGEudXJsKSk7XHJcblxyXG4vKipcclxuICogQ2xlYXJzIGFuZCBzdGFuZGFyZGl6ZXMgdGV4dCBieSByZXBsYWNpbmcgbXVsdGlwbGUgY29uc2VjdXRpdmUgd2hpdGVzcGFjZVxyXG4gKiBjaGFyYWN0ZXJzIHdpdGggYSBzaW5nbGUgc3BhY2UgYW5kIHRyaW1taW5nIGFueSBsZWFkaW5nIG9yIHRyYWlsaW5nXHJcbiAqIHdoaXRlc3BhY2UuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBjbGVhclRleHRcclxuICpcclxuICogQHBhcmFtIHtzdHJpbmd9IHRleHQgLSBUaGUgaW5wdXQgdGV4dCB0byBiZSBjbGVhcmVkLlxyXG4gKiBAcGFyYW0ge1JlZ0V4cH0gW3J1bGU9L1xcc1xccysvZ10gLSBUaGUgcmVndWxhciBleHByZXNzaW9uIHJ1bGUgdG8gbWF0Y2hcclxuICogbXVsdGlwbGUgY29uc2VjdXRpdmUgd2hpdGVzcGFjZSBjaGFyYWN0ZXJzLiBUaGUgZGVmYXVsdCB2YWx1ZVxyXG4gKiBpcyB0aGUgJy9cXHNcXHMrL2cnIFJlZ0V4cC5cclxuICogQHBhcmFtIHtzdHJpbmd9IFtyZXBsYWNlcj0nICddIC0gVGhlIHN0cmluZyB1c2VkIHRvIHJlcGxhY2UgbXVsdGlwbGVcclxuICogY29uc2VjdXRpdmUgd2hpdGVzcGFjZSBjaGFyYWN0ZXJzLiBUaGUgZGVmYXVsdCB2YWx1ZSBpcyB0aGUgJyAnIHN0cmluZy5cclxuICpcclxuICogQHJldHVybnMge3N0cmluZ30gVGhlIGNsZWFyZWQgYW5kIHN0YW5kYXJkaXplZCB0ZXh0LlxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIGNsZWFyVGV4dCh0ZXh0LCBydWxlID0gL1xcc1xccysvZywgcmVwbGFjZXIgPSAnICcpIHtcclxuICByZXR1cm4gdGV4dC5yZXBsYWNlQWxsKHJ1bGUsIHJlcGxhY2VyKS50cmltKCk7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBDcmVhdGVzIGEgZGVlcCBjb3B5IG9mIHRoZSBnaXZlbiBvYmplY3Qgb3IgYXJyYXkuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBkZWVwQ29weVxyXG4gKlxyXG4gKiBAcGFyYW0geyhPYmplY3R8QXJyYXkpfSBvYmpBcnIgLSBUaGUgb2JqZWN0IG9yIGFycmF5IHRvIGJlIGRlZXBseSBjb3BpZWQuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHsoT2JqZWN0fEFycmF5KX0gVGhlIGRlZXAgY29weSBvZiB0aGUgcHJvdmlkZWQgb2JqZWN0IG9yIGFycmF5LlxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIGRlZXBDb3B5KG9iakFycikge1xyXG4gIC8vIElmIHRoZSBgb2JqQXJyYCBpcyBudWxsIG9yIG5vdCBvZiB0aGUgYG9iamVjdGAgdHlwZSwgcmV0dXJuIGl0XHJcbiAgaWYgKG9iakFyciA9PT0gbnVsbCB8fCB0eXBlb2Ygb2JqQXJyICE9PSAnb2JqZWN0Jykge1xyXG4gICAgcmV0dXJuIG9iakFycjtcclxuICB9XHJcblxyXG4gIC8vIFByZXBhcmUgZWl0aGVyIGEgbmV3IGFycmF5IG9yIGEgbmV3IG9iamVjdFxyXG4gIGNvbnN0IG9iakFyckNvcHkgPSBBcnJheS5pc0FycmF5KG9iakFycikgPyBbXSA6IHt9O1xyXG5cclxuICAvLyBSZWN1cnNpdmVseSBjb3B5IGVhY2ggcHJvcGVydHlcclxuICBmb3IgKGNvbnN0IGtleSBpbiBvYmpBcnIpIHtcclxuICAgIGlmIChPYmplY3QucHJvdG90eXBlLmhhc093blByb3BlcnR5LmNhbGwob2JqQXJyLCBrZXkpKSB7XHJcbiAgICAgIG9iakFyckNvcHlba2V5XSA9IGRlZXBDb3B5KG9iakFycltrZXldKTtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIC8vIFJldHVybiB0aGUgY29waWVkIG9iamVjdFxyXG4gIHJldHVybiBvYmpBcnJDb3B5O1xyXG59XHJcblxyXG4vKipcclxuICogSW1wbGVtZW50cyBhbiBleHBvbmVudGlhbCBiYWNrb2ZmIHN0cmF0ZWd5IGZvciByZXRyeWluZyBhIGZ1bmN0aW9uIHVudGlsXHJcbiAqIGEgY2VydGFpbiBudW1iZXIgb2YgYXR0ZW1wdHMgYXJlIHJlYWNoZWQuXHJcbiAqXHJcbiAqIEBhc3luY1xyXG4gKiBAZnVuY3Rpb24gZXhwQmFja29mZlxyXG4gKlxyXG4gKiBAcGFyYW0ge0Z1bmN0aW9ufSBmbiAtIFRoZSBmdW5jdGlvbiB0byBiZSByZXRyaWVkLlxyXG4gKiBAcGFyYW0ge251bWJlcn0gW2F0dGVtcHQ9MF0gLSBUaGUgY3VycmVudCBhdHRlbXB0IG51bWJlci4gVGhlIGRlZmF1bHQgdmFsdWVcclxuICogaXMgMC5cclxuICogQHBhcmFtIHsuLi51bmtub3dufSBhcmdzIC0gQXJndW1lbnRzIHRvIGJlIHBhc3NlZCB0byB0aGUgZnVuY3Rpb24uXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtQcm9taXNlPHVua25vd24+fSBBIFByb21pc2UgdGhhdCByZXNvbHZlcyB0byB0aGUgcmVzdWx0XHJcbiAqIG9mIHRoZSBmdW5jdGlvbiBpZiBzdWNjZXNzZnVsLlxyXG4gKlxyXG4gKiBAdGhyb3dzIHtFcnJvcn0gVGhyb3dzIGFuIGBFcnJvcmAgaWYgdGhlIG1heGltdW0gbnVtYmVyIG9mIGF0dGVtcHRzXHJcbiAqIGlzIHJlYWNoZWQuXHJcbiAqL1xyXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gZXhwQmFja29mZihmbiwgYXR0ZW1wdCA9IDAsIC4uLmFyZ3MpIHtcclxuICB0cnkge1xyXG4gICAgLy8gVHJ5IHRvIGNhbGwgdGhlIGZ1bmN0aW9uXHJcbiAgICByZXR1cm4gYXdhaXQgZm4oLi4uYXJncyk7XHJcbiAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgIC8vIENhbGN1bGF0ZSBkZWxheSBpbiBtc1xyXG4gICAgY29uc3QgZGVsYXlJbk1zID0gMiAqKiBhdHRlbXB0ICogMTAwMDtcclxuXHJcbiAgICAvLyBJZiB0aGUgYXR0ZW1wdCBleGNlZWRzIHRoZSBtYXhpbXVtIGF0dGVtcHRzIG9mIHJlcGVhdCwgdGhyb3cgYW4gZXJyb3JcclxuICAgIGlmICgrK2F0dGVtcHQgPj0gTUFYX0JBQ0tPRkZfQVRURU1QVFMpIHtcclxuICAgICAgdGhyb3cgZXJyb3I7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gV2FpdCBnaXZlbiBhbW91bnQgb2YgdGltZVxyXG4gICAgYXdhaXQgbmV3IFByb21pc2UoKHJlc3BvbnNlKSA9PiBzZXRUaW1lb3V0KHJlc3BvbnNlLCBkZWxheUluTXMpKTtcclxuXHJcbiAgICAvLy8gVE8gRE86IENvcnJlY3RcclxuICAgIC8vIC8vIEluZm9ybWF0aW9uIGFib3V0IHRoZSByZXNvdXJjZSB0aW1lb3V0XHJcbiAgICAvLyBsb2coXHJcbiAgICAvLyAgIDMsXHJcbiAgICAvLyAgIGBbdXRpbHNdIFdhaXRlZCAke2RlbGF5SW5Nc31tcyB1bnRpbCBuZXh0IGNhbGwgZm9yIHRoZSByZXNvdXJjZSBvZiBJRDogJHthcmdzWzBdfS5gXHJcbiAgICAvLyApO1xyXG5cclxuICAgIC8vIFRyeSBhZ2FpblxyXG4gICAgcmV0dXJuIGV4cEJhY2tvZmYoZm4sIGF0dGVtcHQsIC4uLmFyZ3MpO1xyXG4gIH1cclxufVxyXG5cclxuLyoqXHJcbiAqIEFkanVzdHMgdGhlIGNvbnN0cnVjdG9yIG5hbWUgYnkgdHJhbnNmb3JtaW5nIGFuZCBub3JtYWxpemluZyBpdCBiYXNlZFxyXG4gKiBvbiBjb21tb24gY2hhcnQgdHlwZXMuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBmaXhDb25zdHJcclxuICpcclxuICogQHBhcmFtIHtzdHJpbmd9IGNvbnN0ciAtIFRoZSBvcmlnaW5hbCBjb25zdHJ1Y3RvciBuYW1lIHRvIGJlIGZpeGVkLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7c3RyaW5nfSBUaGUgY29ycmVjdGVkIGNvbnN0cnVjdG9yIG5hbWUsIG9yICdjaGFydCcgaWYgdGhlIGlucHV0XHJcbiAqIGlzIG5vdCByZWNvZ25pemVkLlxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIGZpeENvbnN0cihjb25zdHIpIHtcclxuICB0cnkge1xyXG4gICAgLy8gRml4IHRoZSBjb25zdHJ1Y3RvciBieSBsb3dlcmluZyBjYXNpbmdcclxuICAgIGNvbnN0IGZpeGVkQ29uc3RyID0gYCR7Y29uc3RyLnRvTG93ZXJDYXNlKCkucmVwbGFjZSgnY2hhcnQnLCAnJyl9Q2hhcnRgO1xyXG5cclxuICAgIC8vIEhhbmRsZSB0aGUgY2FzZSB3aGVyZSB0aGUgcmVzdWx0IGlzIGp1c3QgJ0NoYXJ0J1xyXG4gICAgaWYgKGZpeGVkQ29uc3RyID09PSAnQ2hhcnQnKSB7XHJcbiAgICAgIGZpeGVkQ29uc3RyLnRvTG93ZXJDYXNlKCk7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gUmV0dXJuIHRoZSBjb3JyZWN0ZWQgY29uc3RydWN0b3IsIG90aGVyd2lzZSBkZWZhdWx0IHRvICdjaGFydCdcclxuICAgIHJldHVybiBbJ2NoYXJ0JywgJ3N0b2NrQ2hhcnQnLCAnbWFwQ2hhcnQnLCAnZ2FudHRDaGFydCddLmluY2x1ZGVzKFxyXG4gICAgICBmaXhlZENvbnN0clxyXG4gICAgKVxyXG4gICAgICA/IGZpeGVkQ29uc3RyXHJcbiAgICAgIDogJ2NoYXJ0JztcclxuICB9IGNhdGNoIHtcclxuICAgIC8vIERlZmF1bHQgdG8gJ2NoYXJ0JyBpbiBjYXNlIG9mIGFueSBlcnJvclxyXG4gICAgcmV0dXJuICdjaGFydCc7XHJcbiAgfVxyXG59XHJcblxyXG4vKipcclxuICogRml4ZXMgdGhlIG91dGZpbGUgYmFzZWQgb24gcHJvdmlkZWQgdHlwZS5cclxuICpcclxuICogQGZ1bmN0aW9uIGZpeE91dGZpbGVcclxuICpcclxuICogQHBhcmFtIHtzdHJpbmd9IHR5cGUgLSBUaGUgb3JpZ2luYWwgZXhwb3J0IHR5cGUuXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSBvdXRmaWxlIC0gVGhlIGZpbGUgcGF0aCBvciBuYW1lLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7c3RyaW5nfSBUaGUgY29ycmVjdGVkIG91dGZpbGUuXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gZml4T3V0ZmlsZSh0eXBlLCBvdXRmaWxlKSB7XHJcbiAgLy8gR2V0IHRoZSBmaWxlIG5hbWUgZnJvbSB0aGUgYG91dGZpbGVgIG9wdGlvblxyXG4gIGNvbnN0IGZpbGVOYW1lID0gZ2V0QWJzb2x1dGVQYXRoKG91dGZpbGUgfHwgJ2NoYXJ0JylcclxuICAgIC5zcGxpdCgnLicpXHJcbiAgICAuc2hpZnQoKTtcclxuXHJcbiAgLy8gUmV0dXJuIGEgY29ycmVjdCBvdXRmaWxlXHJcbiAgcmV0dXJuIGAke2ZpbGVOYW1lfS4ke3R5cGV9YDtcclxufVxyXG5cclxuLyoqXHJcbiAqIEZpeGVzIHRoZSBleHBvcnQgdHlwZSBiYXNlZCBvbiBNSU1FIHR5cGVzIGFuZCBmaWxlIGV4dGVuc2lvbnMuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBmaXhUeXBlXHJcbiAqXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSB0eXBlIC0gVGhlIG9yaWdpbmFsIGV4cG9ydCB0eXBlLlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gW291dGZpbGU9bnVsbF0gLSBUaGUgZmlsZSBwYXRoIG9yIG5hbWUuIFRoZSBkZWZhdWx0IHZhbHVlXHJcbiAqIGlzIG51bGwuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtzdHJpbmd9IFRoZSBjb3JyZWN0ZWQgZXhwb3J0IHR5cGUuXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gZml4VHlwZSh0eXBlLCBvdXRmaWxlID0gbnVsbCkge1xyXG4gIC8vIE1JTUUgdHlwZXNcclxuICBjb25zdCBtaW1lVHlwZXMgPSB7XHJcbiAgICAnaW1hZ2UvcG5nJzogJ3BuZycsXHJcbiAgICAnaW1hZ2UvanBlZyc6ICdqcGVnJyxcclxuICAgICdhcHBsaWNhdGlvbi9wZGYnOiAncGRmJyxcclxuICAgICdpbWFnZS9zdmcreG1sJzogJ3N2ZydcclxuICB9O1xyXG5cclxuICAvLyBHZXQgZm9ybWF0c1xyXG4gIGNvbnN0IGZvcm1hdHMgPSBPYmplY3QudmFsdWVzKG1pbWVUeXBlcyk7XHJcblxyXG4gIC8vIENoZWNrIGlmIHR5cGUgYW5kIG91dGZpbGUncyBleHRlbnNpb25zIGFyZSB0aGUgc2FtZVxyXG4gIGlmIChvdXRmaWxlKSB7XHJcbiAgICBjb25zdCBvdXRUeXBlID0gb3V0ZmlsZS5zcGxpdCgnLicpLnBvcCgpO1xyXG5cclxuICAgIC8vIFN1cHBvcnQgdGhlIEpQRyB0eXBlXHJcbiAgICBpZiAob3V0VHlwZSA9PT0gJ2pwZycpIHtcclxuICAgICAgdHlwZSA9ICdqcGVnJztcclxuICAgIH0gZWxzZSBpZiAoZm9ybWF0cy5pbmNsdWRlcyhvdXRUeXBlKSAmJiB0eXBlICE9PSBvdXRUeXBlKSB7XHJcbiAgICAgIHR5cGUgPSBvdXRUeXBlO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgLy8gUmV0dXJuIGEgY29ycmVjdCB0eXBlXHJcbiAgcmV0dXJuIG1pbWVUeXBlc1t0eXBlXSB8fCBmb3JtYXRzLmZpbmQoKHQpID0+IHQgPT09IHR5cGUpIHx8ICdwbmcnO1xyXG59XHJcblxyXG4vKipcclxuICogQ2hlY2tzIGlmIHRoZSBnaXZlbiBwYXRoIGlzIHJlbGF0aXZlIG9yIGFic29sdXRlIGFuZCByZXR1cm5zIHRoZSBjb3JyZWN0ZWQsXHJcbiAqIGFic29sdXRlIHBhdGguXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBpc0Fic29sdXRlUGF0aFxyXG4gKlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gcGF0aCAtIFRoZSBwYXRoIHRvIGJlIGNoZWNrZWQgb24uXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtzdHJpbmd9IFRoZSBhYnNvbHV0ZSBwYXRoLlxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIGdldEFic29sdXRlUGF0aChwYXRoKSB7XHJcbiAgcmV0dXJuIGlzQWJzb2x1dGUocGF0aCkgPyBwYXRoIDogam9pbihfX2Rpcm5hbWUsIHBhdGgpO1xyXG59XHJcblxyXG4vKipcclxuICogQ29udmVydHMgaW5wdXQgZGF0YSB0byBhIEJhc2U2NCBzdHJpbmcgYmFzZWQgb24gdGhlIGV4cG9ydCB0eXBlLlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gZ2V0QmFzZTY0XHJcbiAqXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSBpbnB1dCAtIFRoZSBpbnB1dCB0byBiZSB0cmFuc2Zvcm1lZCB0byBCYXNlNjQgZm9ybWF0LlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gdHlwZSAtIFRoZSBvcmlnaW5hbCBleHBvcnQgdHlwZS5cclxuICpcclxuICogQHJldHVybnMge3N0cmluZ30gVGhlIEJhc2U2NCBzdHJpbmcgcmVwcmVzZW50YXRpb24gb2YgdGhlIGlucHV0LlxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIGdldEJhc2U2NChpbnB1dCwgdHlwZSkge1xyXG4gIC8vIEZvciBwZGYgYW5kIHN2ZyB0eXBlcyB0aGUgaW5wdXQgbXVzdCBiZSB0cmFuc2Zvcm1lZCB0byBCYXNlNjQgZnJvbSBhIGJ1ZmZlclxyXG4gIGlmICh0eXBlID09PSAncGRmJyB8fCB0eXBlID09ICdzdmcnKSB7XHJcbiAgICByZXR1cm4gQnVmZmVyLmZyb20oaW5wdXQsICd1dGY4JykudG9TdHJpbmcoJ2Jhc2U2NCcpO1xyXG4gIH1cclxuXHJcbiAgLy8gRm9yIHBuZyBhbmQganBlZyBpbnB1dCBpcyBhbHJlYWR5IGEgQmFzZTY0IHN0cmluZ1xyXG4gIHJldHVybiBpbnB1dDtcclxufVxyXG5cclxuLyoqXHJcbiAqIFJldHVybnMgc3RyaW5naWZpZWQgZGF0ZSB3aXRob3V0IHRoZSBHTVQgdGV4dCBpbmZvcm1hdGlvbi5cclxuICpcclxuICogQGZ1bmN0aW9uIGdldE5ld0RhdGVcclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiBnZXROZXdEYXRlKCkge1xyXG4gIC8vIEdldCByaWQgb2YgdGhlIEdNVCB0ZXh0IGluZm9ybWF0aW9uXHJcbiAgcmV0dXJuIG5ldyBEYXRlKCkudG9TdHJpbmcoKS5zcGxpdCgnKCcpWzBdLnRyaW0oKTtcclxufVxyXG5cclxuLyoqXHJcbiAqIFJldHVybnMgdGhlIHN0b3JlZCB0aW1lIHZhbHVlIGluIG1pbGxpc2Vjb25kcy5cclxuICpcclxuICogQGZ1bmN0aW9uIGdldE5ld0RhdGVUaW1lXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gZ2V0TmV3RGF0ZVRpbWUoKSB7XHJcbiAgcmV0dXJuIG5ldyBEYXRlKCkuZ2V0VGltZSgpO1xyXG59XHJcblxyXG4vKipcclxuICogQ2hlY2tzIGlmIHRoZSBnaXZlbiBpdGVtIGlzIGFuIG9iamVjdC5cclxuICpcclxuICogQGZ1bmN0aW9uIGlzT2JqZWN0XHJcbiAqXHJcbiAqIEBwYXJhbSB7dW5rbm93bn0gaXRlbSAtIFRoZSBpdGVtIHRvIGJlIGNoZWNrZWQuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtib29sZWFufSBUcnVlIGlmIHRoZSBpdGVtIGlzIGFuIG9iamVjdCwgZmFsc2Ugb3RoZXJ3aXNlLlxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIGlzT2JqZWN0KGl0ZW0pIHtcclxuICByZXR1cm4gT2JqZWN0LnByb3RvdHlwZS50b1N0cmluZy5jYWxsKGl0ZW0pID09PSAnW29iamVjdCBPYmplY3RdJztcclxufVxyXG5cclxuLyoqXHJcbiAqIENoZWNrcyBpZiB0aGUgZ2l2ZW4gb2JqZWN0IGlzIGVtcHR5LlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gaXNPYmplY3RFbXB0eVxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gaXRlbSAtIFRoZSBvYmplY3QgdG8gYmUgY2hlY2tlZC5cclxuICpcclxuICogQHJldHVybnMge2Jvb2xlYW59IFRydWUgaWYgdGhlIG9iamVjdCBpcyBlbXB0eSwgZmFsc2Ugb3RoZXJ3aXNlLlxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIGlzT2JqZWN0RW1wdHkoaXRlbSkge1xyXG4gIHJldHVybiAoXHJcbiAgICB0eXBlb2YgaXRlbSA9PT0gJ29iamVjdCcgJiZcclxuICAgICFBcnJheS5pc0FycmF5KGl0ZW0pICYmXHJcbiAgICBpdGVtICE9PSBudWxsICYmXHJcbiAgICBPYmplY3Qua2V5cyhpdGVtKS5sZW5ndGggPT09IDBcclxuICApO1xyXG59XHJcblxyXG4vKipcclxuICogQ2hlY2tzIGlmIGEgcHJpdmF0ZSBJUCByYW5nZSBVUkwgaXMgZm91bmQgaW4gdGhlIGdpdmVuIHN0cmluZy5cclxuICpcclxuICogQGZ1bmN0aW9uIGlzUHJpdmF0ZVJhbmdlVXJsRm91bmRcclxuICpcclxuICogQHBhcmFtIHtzdHJpbmd9IGl0ZW0gLSBUaGUgc3RyaW5nIHRvIGJlIGNoZWNrZWQgZm9yIGEgcHJpdmF0ZSBJUCByYW5nZSBVUkwuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtib29sZWFufSBUcnVlIGlmIGEgcHJpdmF0ZSBJUCByYW5nZSBVUkwgaXMgZm91bmQsIGZhbHNlIG90aGVyd2lzZS5cclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiBpc1ByaXZhdGVSYW5nZVVybEZvdW5kKGl0ZW0pIHtcclxuICBjb25zdCByZWdleFBhdHRlcm5zID0gW1xyXG4gICAgL3hsaW5rOmhyZWY9XCIoPzpodHRwOlxcL1xcL3xodHRwczpcXC9cXC8pP2xvY2FsaG9zdFxcYi8sXHJcbiAgICAveGxpbms6aHJlZj1cIig/Omh0dHA6XFwvXFwvfGh0dHBzOlxcL1xcLyk/MTBcXC5cXGR7MSwzfVxcLlxcZHsxLDN9XFwuXFxkezEsM31cXGIvLFxyXG4gICAgL3hsaW5rOmhyZWY9XCIoPzpodHRwOlxcL1xcL3xodHRwczpcXC9cXC8pPzEyN1xcLlxcZHsxLDN9XFwuXFxkezEsM31cXC5cXGR7MSwzfVxcYi8sXHJcbiAgICAveGxpbms6aHJlZj1cIig/Omh0dHA6XFwvXFwvfGh0dHBzOlxcL1xcLyk/MTcyXFwuKDFbNi05XXwyWzAtOV18M1swLTFdKVxcLlxcZHsxLDN9XFwuXFxkezEsM31cXGIvLFxyXG4gICAgL3hsaW5rOmhyZWY9XCIoPzpodHRwOlxcL1xcL3xodHRwczpcXC9cXC8pPzE5MlxcLjE2OFxcLlxcZHsxLDN9XFwuXFxkezEsM31cXGIvXHJcbiAgXTtcclxuXHJcbiAgcmV0dXJuIHJlZ2V4UGF0dGVybnMuc29tZSgocGF0dGVybikgPT4gcGF0dGVybi50ZXN0KGl0ZW0pKTtcclxufVxyXG5cclxuLyoqXHJcbiAqIFV0aWxpdHkgdG8gbWVhc3VyZSBlbGFwc2VkIHRpbWUgdXNpbmcgdGhlIE5vZGUuanMgYHByb2Nlc3MuaHJ0aW1lKClgIG1ldGhvZC5cclxuICpcclxuICogQGZ1bmN0aW9uIG1lYXN1cmVUaW1lXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtGdW5jdGlvbn0gQSBmdW5jdGlvbiB0byBjYWxjdWxhdGUgdGhlIGVsYXBzZWQgdGltZSBpbiBtaWxsaXNlY29uZHMuXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gbWVhc3VyZVRpbWUoKSB7XHJcbiAgY29uc3Qgc3RhcnQgPSBwcm9jZXNzLmhydGltZS5iaWdpbnQoKTtcclxuICByZXR1cm4gKCkgPT4gTnVtYmVyKHByb2Nlc3MuaHJ0aW1lLmJpZ2ludCgpIC0gc3RhcnQpIC8gMTAwMDAwMDtcclxufVxyXG5cclxuLyoqXHJcbiAqIFJvdW5kcyBhIG51bWJlciB0byB0aGUgc3BlY2lmaWVkIHByZWNpc2lvbi5cclxuICpcclxuICogQGZ1bmN0aW9uIHJvdW5kTnVtYmVyXHJcbiAqXHJcbiAqIEBwYXJhbSB7bnVtYmVyfSB2YWx1ZSAtIFRoZSBudW1iZXIgdG8gYmUgcm91bmRlZC5cclxuICogQHBhcmFtIHtudW1iZXJ9IHByZWNpc2lvbiAtIFRoZSBudW1iZXIgb2YgZGVjaW1hbCBwbGFjZXMgdG8gcm91bmQgdG8uXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtudW1iZXJ9IFRoZSByb3VuZGVkIG51bWJlci5cclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiByb3VuZE51bWJlcih2YWx1ZSwgcHJlY2lzaW9uID0gMSkge1xyXG4gIGNvbnN0IG11bHRpcGxpZXIgPSBNYXRoLnBvdygxMCwgcHJlY2lzaW9uIHx8IDApO1xyXG4gIHJldHVybiBNYXRoLnJvdW5kKCt2YWx1ZSAqIG11bHRpcGxpZXIpIC8gbXVsdGlwbGllcjtcclxufVxyXG5cclxuLyoqXHJcbiAqIENvbnZlcnRzIGEgdmFsdWUgdG8gYSBib29sZWFuLlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gdG9Cb29sZWFuXHJcbiAqXHJcbiAqIEBwYXJhbSB7dW5rbm93bn0gaXRlbSAtIFRoZSB2YWx1ZSB0byBiZSBjb252ZXJ0ZWQgdG8gYSBib29sZWFuLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7Ym9vbGVhbn0gVGhlIGJvb2xlYW4gcmVwcmVzZW50YXRpb24gb2YgdGhlIGlucHV0IHZhbHVlLlxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIHRvQm9vbGVhbihpdGVtKSB7XHJcbiAgcmV0dXJuIFsnZmFsc2UnLCAndW5kZWZpbmVkJywgJ251bGwnLCAnTmFOJywgJzAnLCAnJ10uaW5jbHVkZXMoaXRlbSlcclxuICAgID8gZmFsc2VcclxuICAgIDogISFpdGVtO1xyXG59XHJcblxyXG4vKipcclxuICogV3JhcHMgY3VzdG9tIGNvZGUgdG8gZXhlY3V0ZSBpdCBzYWZlbHkuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiB3cmFwQXJvdW5kXHJcbiAqXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSBjdXN0b21Db2RlIC0gVGhlIGN1c3RvbSBjb2RlIHRvIGJlIHdyYXBwZWQuXHJcbiAqIEBwYXJhbSB7Ym9vbGVhbn0gYWxsb3dGaWxlUmVzb3VyY2VzIC0gRmxhZyB0byBhbGxvdyBsb2FkaW5nIGNvZGUgZnJvbSBhIGZpbGUuXHJcbiAqIEBwYXJhbSB7Ym9vbGVhbn0gW2lzQ2FsbGJhY2s9ZmFsc2VdIC0gRmxhZyB0aGF0IGluZGljYXRlcyB0aGUgcmV0dXJuZWQgY29kZVxyXG4gKiBtdXN0IGJlIGluIGEgY2FsbGJhY2sgZm9ybWF0LlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7KHN0cmluZ3xudWxsKX0gVGhlIHdyYXBwZWQgY3VzdG9tIGNvZGUgb3IgbnVsbCBpZiB3cmFwcGluZyBmYWlscy5cclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiB3cmFwQXJvdW5kKGN1c3RvbUNvZGUsIGFsbG93RmlsZVJlc291cmNlcywgaXNDYWxsYmFjayA9IGZhbHNlKSB7XHJcbiAgaWYgKGN1c3RvbUNvZGUgJiYgdHlwZW9mIGN1c3RvbUNvZGUgPT09ICdzdHJpbmcnKSB7XHJcbiAgICBjdXN0b21Db2RlID0gY3VzdG9tQ29kZS50cmltKCk7XHJcblxyXG4gICAgaWYgKGN1c3RvbUNvZGUuZW5kc1dpdGgoJy5qcycpKSB7XHJcbiAgICAgIC8vIExvYWQgYSBmaWxlIGlmIHRoZSBmaWxlIHJlc291cmNlcyBhcmUgYWxsb3dlZFxyXG4gICAgICByZXR1cm4gYWxsb3dGaWxlUmVzb3VyY2VzXHJcbiAgICAgICAgPyB3cmFwQXJvdW5kKFxyXG4gICAgICAgICAgICByZWFkRmlsZVN5bmMoZ2V0QWJzb2x1dGVQYXRoKGN1c3RvbUNvZGUpLCAndXRmOCcpLFxyXG4gICAgICAgICAgICBhbGxvd0ZpbGVSZXNvdXJjZXMsXHJcbiAgICAgICAgICAgIGlzQ2FsbGJhY2tcclxuICAgICAgICAgIClcclxuICAgICAgICA6IG51bGw7XHJcbiAgICB9IGVsc2UgaWYgKFxyXG4gICAgICAhaXNDYWxsYmFjayAmJlxyXG4gICAgICAoY3VzdG9tQ29kZS5zdGFydHNXaXRoKCdmdW5jdGlvbigpJykgfHxcclxuICAgICAgICBjdXN0b21Db2RlLnN0YXJ0c1dpdGgoJ2Z1bmN0aW9uICgpJykgfHxcclxuICAgICAgICBjdXN0b21Db2RlLnN0YXJ0c1dpdGgoJygpPT4nKSB8fFxyXG4gICAgICAgIGN1c3RvbUNvZGUuc3RhcnRzV2l0aCgnKCkgPT4nKSlcclxuICAgICkge1xyXG4gICAgICAvLyBUcmVhdCBhIGZ1bmN0aW9uIGFzIGEgc2VsZi1pbnZva2luZyBleHByZXNzaW9uXHJcbiAgICAgIHJldHVybiBgKCR7Y3VzdG9tQ29kZX0pKClgO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIE9yIHJldHVybiBhcyBhIHN0cmluZ2lmaWVkIGNvZGVcclxuICAgIHJldHVybiBjdXN0b21Db2RlLnJlcGxhY2UoLzskLywgJycpO1xyXG4gIH1cclxufVxyXG5cclxuZXhwb3J0IGRlZmF1bHQge1xyXG4gIF9fZGlybmFtZSxcclxuICBjbGVhclRleHQsXHJcbiAgZGVlcENvcHksXHJcbiAgZXhwQmFja29mZixcclxuICBmaXhDb25zdHIsXHJcbiAgZml4T3V0ZmlsZSxcclxuICBmaXhUeXBlLFxyXG4gIGdldEFic29sdXRlUGF0aCxcclxuICBnZXRCYXNlNjQsXHJcbiAgZ2V0TmV3RGF0ZSxcclxuICBnZXROZXdEYXRlVGltZSxcclxuICBpc09iamVjdCxcclxuICBpc09iamVjdEVtcHR5LFxyXG4gIGlzUHJpdmF0ZVJhbmdlVXJsRm91bmQsXHJcbiAgbWVhc3VyZVRpbWUsXHJcbiAgcm91bmROdW1iZXIsXHJcbiAgdG9Cb29sZWFuLFxyXG4gIHdyYXBBcm91bmRcclxufTtcclxuIiwiLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcclxuXHJcbkhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlclxyXG5cclxuQ29weXJpZ2h0IChjKSAyMDE2LTIwMjUsIEhpZ2hzb2Z0XHJcblxyXG5MaWNlbmNlZCB1bmRlciB0aGUgTUlUIGxpY2VuY2UuXHJcblxyXG5BZGRpdGlvbmFsbHkgYSB2YWxpZCBIaWdoY2hhcnRzIGxpY2Vuc2UgaXMgcmVxdWlyZWQgZm9yIHVzZS5cclxuXHJcblNlZSBMSUNFTlNFIGZpbGUgaW4gcm9vdCBmb3IgZGV0YWlscy5cclxuXHJcbioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXHJcblxyXG4vKipcclxuICogQG92ZXJ2aWV3IEEgbW9kdWxlIGZvciBtYW5hZ2luZyBsb2dnaW5nIGZ1bmN0aW9uYWxpdHkgd2l0aCBjdXN0b21pemFibGVcclxuICogbG9nIGxldmVscywgY29uc29sZSBhbmQgZmlsZSBsb2dnaW5nIG9wdGlvbnMsIGFuZCBlcnJvciBoYW5kbGluZyBzdXBwb3J0LlxyXG4gKiBUaGUgbW9kdWxlIGFsc28gZW5zdXJlcyB0aGF0IGZpbGUtYmFzZWQgbG9ncyBhcmUgc3RvcmVkIGluIGEgc3RydWN0dXJlZFxyXG4gKiBkaXJlY3RvcnksIGNyZWF0aW5nIHRoZSBuZWNlc3NhcnkgcGF0aHMgYXV0b21hdGljYWxseSBpZiB0aGV5IGRvIG5vdCBleGlzdC5cclxuICovXHJcblxyXG5pbXBvcnQgeyBhcHBlbmRGaWxlLCBleGlzdHNTeW5jLCBta2RpclN5bmMgfSBmcm9tICdmcyc7XHJcbmltcG9ydCB7IGpvaW4gfSBmcm9tICdwYXRoJztcclxuXHJcbmltcG9ydCB7IGdldEFic29sdXRlUGF0aCwgZ2V0TmV3RGF0ZSB9IGZyb20gJy4vdXRpbHMuanMnO1xyXG5cclxuLy8gVGhlIGF2YWlsYWJsZSBjb2xvcnNcclxuY29uc3QgY29sb3JzID0gWydyZWQnLCAneWVsbG93JywgJ2JsdWUnLCAnZ3JheScsICdncmVlbiddO1xyXG5cclxuLy8gVGhlIGRlZmF1bHQgbG9nZ2luZyBjb25maWdcclxuY29uc3QgbG9nZ2luZyA9IHtcclxuICAvLyBGbGFncyBmb3IgbG9nZ2luZyBzdGF0dXNcclxuICB0b0NvbnNvbGU6IHRydWUsXHJcbiAgdG9GaWxlOiBmYWxzZSxcclxuICBwYXRoQ3JlYXRlZDogZmFsc2UsXHJcbiAgLy8gRnVsbCBwYXRoIHRvIHRoZSBsb2cgZmlsZVxyXG4gIHBhdGhUb0xvZzogJycsXHJcbiAgLy8gTG9nIGxldmVsc1xyXG4gIGxldmVsc0Rlc2M6IFtcclxuICAgIHtcclxuICAgICAgdGl0bGU6ICdlcnJvcicsXHJcbiAgICAgIGNvbG9yOiBjb2xvcnNbMF1cclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHRpdGxlOiAnd2FybmluZycsXHJcbiAgICAgIGNvbG9yOiBjb2xvcnNbMV1cclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHRpdGxlOiAnbm90aWNlJyxcclxuICAgICAgY29sb3I6IGNvbG9yc1syXVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdGl0bGU6ICd2ZXJib3NlJyxcclxuICAgICAgY29sb3I6IGNvbG9yc1szXVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdGl0bGU6ICdiZW5jaG1hcmsnLFxyXG4gICAgICBjb2xvcjogY29sb3JzWzRdXHJcbiAgICB9XHJcbiAgXVxyXG59O1xyXG5cclxuLyoqXHJcbiAqIExvZ3MgYSBtZXNzYWdlLiBBY2NlcHRzIGEgdmFyaWFibGUgYW1vdW50IG9mIGFyZ3VtZW50cy4gQXJndW1lbnRzIGFmdGVyXHJcbiAqIHRoZSBgbGV2ZWxgIHdpbGwgYmUgcGFzc2VkIGRpcmVjdGx5IHRvIGBjb25zb2xlLmxvZ2AsIGFuZC9vciB3aWxsIGJlIGpvaW5lZFxyXG4gKiBhbmQgYXBwZW5kZWQgdG8gdGhlIGxvZyBmaWxlLlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gbG9nXHJcbiAqXHJcbiAqIEBwYXJhbSB7Li4udW5rbm93bn0gYXJncyAtIEFuIGFycmF5IG9mIGFyZ3VtZW50cyB3aGVyZSB0aGUgZmlyc3QgaXMgdGhlIGxvZ1xyXG4gKiBsZXZlbCBhbmQgdGhlIHJlc3QgYXJlIHN0cmluZ3MgdG8gYnVpbGQgYSBtZXNzYWdlIHdpdGguXHJcbiAqXHJcbiAqIEByZXR1cm5zIHt2b2lkfSBFbmRzIHRoZSBmdW5jdGlvbiBleGVjdXRpb24gd2hlbiBhdHRlbXB0aW5nIHRvIGxvZ1xyXG4gKiBpbmZvcm1hdGlvbiBhdCBhIGhpZ2hlciBsZXZlbCB0aGFuIHdoYXQgaXMgYWxsb3dlZC5cclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiBsb2coLi4uYXJncykge1xyXG4gIGNvbnN0IFtuZXdMZXZlbCwgLi4udGV4dHNdID0gYXJncztcclxuXHJcbiAgLy8gQ3VycmVudCBsb2dnaW5nIG9wdGlvbnNcclxuICBjb25zdCB7IGxldmVsc0Rlc2MsIGxldmVsIH0gPSBsb2dnaW5nO1xyXG5cclxuICAvLyBDaGVjayBpZiB0aGUgbG9nIGxldmVsIGlzIHdpdGhpbiBhIGNvcnJlY3QgcmFuZ2Ugb3IgaXMgaXQgYSBiZW5jaG1hcmsgbG9nXHJcbiAgaWYgKFxyXG4gICAgbmV3TGV2ZWwgIT09IDUgJiZcclxuICAgIChuZXdMZXZlbCA9PT0gMCB8fCBuZXdMZXZlbCA+IGxldmVsIHx8IGxldmVsID4gbGV2ZWxzRGVzYy5sZW5ndGgpXHJcbiAgKSB7XHJcbiAgICByZXR1cm47XHJcbiAgfVxyXG5cclxuICAvLyBDcmVhdGUgYSBtZXNzYWdlJ3MgcHJlZml4XHJcbiAgY29uc3QgcHJlZml4ID0gYCR7Z2V0TmV3RGF0ZSgpfSBbJHtsZXZlbHNEZXNjW25ld0xldmVsIC0gMV0udGl0bGV9XSAtYDtcclxuXHJcbiAgLy8gTG9nIHRvIGZpbGVcclxuICBpZiAobG9nZ2luZy50b0ZpbGUpIHtcclxuICAgIF9sb2dUb0ZpbGUodGV4dHMsIHByZWZpeCk7XHJcbiAgfVxyXG5cclxuICAvLyBMb2cgdG8gY29uc29sZVxyXG4gIGlmIChsb2dnaW5nLnRvQ29uc29sZSkge1xyXG4gICAgY29uc29sZS5sb2cuYXBwbHkoXHJcbiAgICAgIHVuZGVmaW5lZCxcclxuICAgICAgW3ByZWZpeC50b1N0cmluZygpW2xvZ2dpbmcubGV2ZWxzRGVzY1tuZXdMZXZlbCAtIDFdLmNvbG9yXV0uY29uY2F0KHRleHRzKVxyXG4gICAgKTtcclxuICB9XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBMb2dzIGFuIGVycm9yIG1lc3NhZ2Ugd2l0aCBpdHMgc3RhY2sgdHJhY2UuIE9wdGlvbmFsbHksIGEgY3VzdG9tIG1lc3NhZ2VcclxuICogY2FuIGJlIHByb3ZpZGVkLlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gbG9nV2l0aFN0YWNrXHJcbiAqXHJcbiAqIEBwYXJhbSB7bnVtYmVyfSBuZXdMZXZlbCAtIFRoZSBsb2cgbGV2ZWwuXHJcbiAqIEBwYXJhbSB7RXJyb3J9IGVycm9yIC0gVGhlIGVycm9yIG9iamVjdC5cclxuICogQHBhcmFtIHtzdHJpbmd9IGN1c3RvbU1lc3NhZ2UgLSBBbiBvcHRpb25hbCBjdXN0b20gbWVzc2FnZSB0byBiZSBsb2dnZWRcclxuICogYWxvbmcgd2l0aCB0aGUgZXJyb3IuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHt2b2lkfSBFbmRzIHRoZSBmdW5jdGlvbiBleGVjdXRpb24gd2hlbiBhdHRlbXB0aW5nIHRvIGxvZ1xyXG4gKiBpbmZvcm1hdGlvbiBhdCBhIGhpZ2hlciBsZXZlbCB0aGFuIHdoYXQgaXMgYWxsb3dlZC5cclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiBsb2dXaXRoU3RhY2sobmV3TGV2ZWwsIGVycm9yLCBjdXN0b21NZXNzYWdlKSB7XHJcbiAgLy8gR2V0IHRoZSBtYWluIG1lc3NhZ2VcclxuICBjb25zdCBtYWluTWVzc2FnZSA9IGN1c3RvbU1lc3NhZ2UgfHwgZXJyb3IubWVzc2FnZTtcclxuXHJcbiAgLy8gQ3VycmVudCBsb2dnaW5nIG9wdGlvbnNcclxuICBjb25zdCB7IGxldmVsLCBsZXZlbHNEZXNjIH0gPSBsb2dnaW5nO1xyXG5cclxuICAvLyBDaGVjayBpZiB0aGUgbG9nIGxldmVsIGlzIHdpdGhpbiBhIGNvcnJlY3QgcmFuZ2VcclxuICBpZiAobmV3TGV2ZWwgPT09IDAgfHwgbmV3TGV2ZWwgPiBsZXZlbCB8fCBsZXZlbCA+IGxldmVsc0Rlc2MubGVuZ3RoKSB7XHJcbiAgICByZXR1cm47XHJcbiAgfVxyXG5cclxuICAvLyBDcmVhdGUgYSBtZXNzYWdlJ3MgcHJlZml4XHJcbiAgY29uc3QgcHJlZml4ID0gYCR7Z2V0TmV3RGF0ZSgpfSBbJHtsZXZlbHNEZXNjW25ld0xldmVsIC0gMV0udGl0bGV9XSAtYDtcclxuXHJcbiAgLy8gQWRkIHRoZSB3aG9sZSBzdGFjayBtZXNzYWdlXHJcbiAgY29uc3Qgc3RhY2tNZXNzYWdlID0gZXJyb3Iuc3RhY2s7XHJcblxyXG4gIC8vIENvbWJpbmUgY3VzdG9tIG1lc3NhZ2Ugb3IgZXJyb3IgbWVzc2FnZSB3aXRoIGVycm9yIHN0YWNrIG1lc3NhZ2UsIGlmIGV4aXN0c1xyXG4gIGNvbnN0IHRleHRzID0gW21haW5NZXNzYWdlXTtcclxuICBpZiAoc3RhY2tNZXNzYWdlKSB7XHJcbiAgICB0ZXh0cy5wdXNoKCdcXG4nLCBzdGFja01lc3NhZ2UpO1xyXG4gIH1cclxuXHJcbiAgLy8gTG9nIHRvIGZpbGVcclxuICBpZiAobG9nZ2luZy50b0ZpbGUpIHtcclxuICAgIF9sb2dUb0ZpbGUodGV4dHMsIHByZWZpeCk7XHJcbiAgfVxyXG5cclxuICAvLyBMb2cgdG8gY29uc29sZVxyXG4gIGlmIChsb2dnaW5nLnRvQ29uc29sZSkge1xyXG4gICAgY29uc29sZS5sb2cuYXBwbHkoXHJcbiAgICAgIHVuZGVmaW5lZCxcclxuICAgICAgW3ByZWZpeC50b1N0cmluZygpW2xvZ2dpbmcubGV2ZWxzRGVzY1tuZXdMZXZlbCAtIDFdLmNvbG9yXV0uY29uY2F0KFtcclxuICAgICAgICB0ZXh0cy5zaGlmdCgpW2NvbG9yc1tuZXdMZXZlbCAtIDFdXSxcclxuICAgICAgICAuLi50ZXh0c1xyXG4gICAgICBdKVxyXG4gICAgKTtcclxuICB9XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBJbml0aWFsaXplcyBsb2dnaW5nIHdpdGggdGhlIHNwZWNpZmllZCBsb2dnaW5nIGNvbmZpZ3VyYXRpb24uXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBpbml0TG9nZ2luZ1xyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gbG9nZ2luZ09wdGlvbnMgLSBPYmplY3QgY29udGFpbmluZyBgbG9nZ2luZ2Agb3B0aW9ucy5cclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiBpbml0TG9nZ2luZyhsb2dnaW5nT3B0aW9ucykge1xyXG4gIC8vIEdldCBvcHRpb25zIGZyb20gdGhlIGBsb2dnaW5nT3B0aW9uc2Agb2JqZWN0XHJcbiAgY29uc3QgeyBsZXZlbCwgZGVzdCwgZmlsZSwgdG9Db25zb2xlLCB0b0ZpbGUgfSA9IGxvZ2dpbmdPcHRpb25zO1xyXG5cclxuICAvLyBTZXQgdGhlIGxvZ2dpbmcgbGV2ZWxcclxuICBzZXRMb2dMZXZlbChsZXZlbCk7XHJcblxyXG4gIC8vIFNldCB0aGUgY29uc29sZSBsb2dnaW5nXHJcbiAgZW5hYmxlQ29uc29sZUxvZ2dpbmcodG9Db25zb2xlKTtcclxuXHJcbiAgLy8gU2V0IHRoZSBmaWxlIGxvZ2dpbmdcclxuICBlbmFibGVGaWxlTG9nZ2luZyhkZXN0LCBmaWxlLCB0b0ZpbGUpO1xyXG59XHJcblxyXG4vKipcclxuICogU2V0cyB0aGUgbG9nIGxldmVsIHRvIHRoZSBzcGVjaWZpZWQgdmFsdWUuIExvZyBsZXZlbHMgYXJlICgwID0gbm8gbG9nZ2luZyxcclxuICogMSA9IGVycm9yLCAyID0gd2FybmluZywgMyA9IG5vdGljZSwgNCA9IHZlcmJvc2UsIG9yIDUgPSBiZW5jaG1hcmspLlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gc2V0TG9nTGV2ZWxcclxuICpcclxuICogQHBhcmFtIHtudW1iZXJ9IGxldmVsIC0gVGhlIGxvZyBsZXZlbCB0byBiZSBzZXQuXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gc2V0TG9nTGV2ZWwobGV2ZWwpIHtcclxuICBpZiAobGV2ZWwgPj0gMCAmJiBsZXZlbCA8PSBsb2dnaW5nLmxldmVsc0Rlc2MubGVuZ3RoKSB7XHJcbiAgICBsb2dnaW5nLmxldmVsID0gbGV2ZWw7XHJcbiAgfVxyXG59XHJcblxyXG4vKipcclxuICogRW5hYmxlcyBjb25zb2xlIGxvZ2dpbmcuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBlbmFibGVDb25zb2xlTG9nZ2luZ1xyXG4gKlxyXG4gKiBAcGFyYW0ge2Jvb2xlYW59IHRvQ29uc29sZSAtIFRoZSBmbGFnIGZvciBzZXR0aW5nIHRoZSBsb2dnaW5nIHRvIHRoZSBjb25zb2xlLlxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIGVuYWJsZUNvbnNvbGVMb2dnaW5nKHRvQ29uc29sZSkge1xyXG4gIC8vIFVwZGF0ZSBvcHRpb25zIGZvciB0aGUgY29uc29sZSBsb2dnaW5nXHJcbiAgbG9nZ2luZy50b0NvbnNvbGUgPSB0b0NvbnNvbGU7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBFbmFibGVzIGZpbGUgbG9nZ2luZyB3aXRoIHRoZSBzcGVjaWZpZWQgZGVzdGluYXRpb24gYW5kIGxvZyBmaWxlLlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gZW5hYmxlRmlsZUxvZ2dpbmdcclxuICpcclxuICogQHBhcmFtIHtzdHJpbmd9IGRlc3QgLSBUaGUgZGVzdGluYXRpb24gcGF0aCBmb3IgdGhlIGxvZyBmaWxlLlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gZmlsZSAtIFRoZSBsb2cgZmlsZSBuYW1lLlxyXG4gKiBAcGFyYW0ge2Jvb2xlYW59IHRvRmlsZSAtIFRoZSBmbGFnIGZvciBzZXR0aW5nIHRoZSBsb2dnaW5nIHRvIGEgZmlsZS5cclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiBlbmFibGVGaWxlTG9nZ2luZyhkZXN0LCBmaWxlLCB0b0ZpbGUpIHtcclxuICAvLyBVcGRhdGUgb3B0aW9ucyBmb3IgdGhlIGZpbGUgbG9nZ2luZ1xyXG4gIGxvZ2dpbmcudG9GaWxlID0gdG9GaWxlO1xyXG5cclxuICAvLyBTZXQgdGhlIGBkZXN0YCBhbmQgYGZpbGVgIG9ubHkgaWYgdGhlIGZpbGUgbG9nZ2luZyBpcyBlbmFibGVkXHJcbiAgaWYgKHRvRmlsZSkge1xyXG4gICAgbG9nZ2luZy5kZXN0ID0gZGVzdDtcclxuICAgIGxvZ2dpbmcuZmlsZSA9IGZpbGU7XHJcbiAgfVxyXG59XHJcblxyXG4vKipcclxuICogTG9ncyB0aGUgcHJvdmlkZWQgdGV4dHMgdG8gYSBmaWxlLCBpZiBmaWxlIGxvZ2dpbmcgaXMgZW5hYmxlZC4gSXQgY3JlYXRlc1xyXG4gKiB0aGUgbmVjZXNzYXJ5IGRpcmVjdG9yeSBzdHJ1Y3R1cmUgaWYgbm90IGFscmVhZHkgY3JlYXRlZCBhbmQgYXBwZW5kc1xyXG4gKiB0aGUgY29udGVudCwgaW5jbHVkaW5nIGFuIG9wdGlvbmFsIHByZWZpeCwgdG8gdGhlIHNwZWNpZmllZCBsb2cgZmlsZS5cclxuICpcclxuICogQGZ1bmN0aW9uIF9sb2dUb0ZpbGVcclxuICpcclxuICogQHBhcmFtIHtBcnJheS48c3RyaW5nPn0gdGV4dHMgLSBBbiBhcnJheSBvZiB0ZXh0cyB0byBiZSBsb2dnZWQuXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSBwcmVmaXggLSBBbiBvcHRpb25hbCBwcmVmaXggdG8gYmUgYWRkZWQgdG8gZWFjaCBsb2cgZW50cnkuXHJcbiAqL1xyXG5mdW5jdGlvbiBfbG9nVG9GaWxlKHRleHRzLCBwcmVmaXgpIHtcclxuICBpZiAoIWxvZ2dpbmcucGF0aENyZWF0ZWQpIHtcclxuICAgIC8vIENyZWF0ZSBpZiBkb2VzIG5vdCBleGlzdFxyXG4gICAgIWV4aXN0c1N5bmMoZ2V0QWJzb2x1dGVQYXRoKGxvZ2dpbmcuZGVzdCkpICYmXHJcbiAgICAgIG1rZGlyU3luYyhnZXRBYnNvbHV0ZVBhdGgobG9nZ2luZy5kZXN0KSk7XHJcblxyXG4gICAgLy8gQ3JlYXRlIHRoZSBmdWxsIHBhdGhcclxuICAgIGxvZ2dpbmcucGF0aFRvTG9nID0gZ2V0QWJzb2x1dGVQYXRoKGpvaW4obG9nZ2luZy5kZXN0LCBsb2dnaW5nLmZpbGUpKTtcclxuXHJcbiAgICAvLyBXZSBub3cgYXNzdW1lIHRoZSBwYXRoIGlzIGF2YWlsYWJsZSwgZS5nLiBpdCdzIHRoZSByZXNwb25zaWJpbGl0eVxyXG4gICAgLy8gb2YgdGhlIHVzZXIgdG8gY3JlYXRlIHRoZSBwYXRoIHdpdGggdGhlIGNvcnJlY3QgYWNjZXNzIHJpZ2h0cy5cclxuICAgIGxvZ2dpbmcucGF0aENyZWF0ZWQgPSB0cnVlO1xyXG4gIH1cclxuXHJcbiAgLy8gQWRkIHRoZSBjb250ZW50IHRvIGEgZmlsZVxyXG4gIGFwcGVuZEZpbGUoXHJcbiAgICBsb2dnaW5nLnBhdGhUb0xvZyxcclxuICAgIFtwcmVmaXhdLmNvbmNhdCh0ZXh0cykuam9pbignICcpICsgJ1xcbicsXHJcbiAgICAoZXJyb3IpID0+IHtcclxuICAgICAgaWYgKGVycm9yICYmIGxvZ2dpbmcudG9GaWxlICYmIGxvZ2dpbmcucGF0aENyZWF0ZWQpIHtcclxuICAgICAgICBsb2dnaW5nLnRvRmlsZSA9IGZhbHNlO1xyXG4gICAgICAgIGxvZ2dpbmcucGF0aENyZWF0ZWQgPSBmYWxzZTtcclxuICAgICAgICBsb2dXaXRoU3RhY2soMiwgZXJyb3IsIGBbbG9nZ2VyXSBVbmFibGUgdG8gd3JpdGUgdG8gbG9nIGZpbGUuYCk7XHJcbiAgICAgIH1cclxuICAgIH1cclxuICApO1xyXG59XHJcblxyXG5leHBvcnQgZGVmYXVsdCB7XHJcbiAgbG9nLFxyXG4gIGxvZ1dpdGhTdGFjayxcclxuICBpbml0TG9nZ2luZyxcclxuICBzZXRMb2dMZXZlbCxcclxuICBlbmFibGVDb25zb2xlTG9nZ2luZyxcclxuICBlbmFibGVGaWxlTG9nZ2luZ1xyXG59O1xyXG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxyXG5cclxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXHJcblxyXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNSwgSGlnaHNvZnRcclxuXHJcbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cclxuXHJcbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxyXG5cclxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxyXG5cclxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cclxuXHJcbi8qKlxyXG4gKiBAb3ZlcnZpZXcgQ29uZmlndXJhdGlvbiBtYW5hZ2VtZW50IG1vZHVsZSBmb3IgdGhlIEhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlci5cclxuICogUHJvdmlkZXMgZGVmYXVsdCBjb25maWd1cmF0aW9ucyB0aGF0IHN1cHBvcnQgZW52aXJvbm1lbnQgdmFyaWFibGVzLCBDTElcclxuICogYXJndW1lbnRzLCBhbmQgaW50ZXJhY3RpdmUgcHJvbXB0cyBmb3IgY3VzdG9taXphdGlvbiBvZiBvcHRpb25zIGFuZCBmZWF0dXJlcy5cclxuICogQWRkaXRpb25hbGx5LCBpdCBtYXBzIGxlZ2FjeSBvcHRpb25zIHRvIG1vZGVybiBzdHJ1Y3R1cmVzLCBnZW5lcmF0ZXMgbmVzdGVkXHJcbiAqIGFyZ3VtZW50IG1hcHBpbmdzLCBhbmQgZGlzcGxheXMgQ0xJIHVzYWdlIGluZm9ybWF0aW9uLlxyXG4gKi9cclxuXHJcbi8qKlxyXG4gKiBUaGUgY29uZmlndXJhdGlvbiBvYmplY3QgY29udGFpbmluZyBhbGwgYXZhaWxhYmxlIG9wdGlvbnMsIG9yZ2FuaXplZFxyXG4gKiBieSBzZWN0aW9ucy5cclxuICpcclxuICogVGhpcyBvYmplY3QgaW5jbHVkZXM6XHJcbiAqIC0gRGVmYXVsdCB2YWx1ZXMgZm9yIGVhY2ggb3B0aW9uXHJcbiAqIC0gRGF0YSB0eXBlcyBmb3IgdmFsaWRhdGlvblxyXG4gKiAtIE5hbWVzIG9mIGNvcnJlc3BvbmRpbmcgZW52aXJvbm1lbnQgdmFyaWFibGVzXHJcbiAqIC0gRGVzY3JpcHRpb25zIG9mIGVhY2ggcHJvcGVydHlcclxuICogLSBJbmZvcm1hdGlvbiB1c2VkIGZvciBwcm9tcHRzIGluIGludGVyYWN0aXZlIGNvbmZpZ3VyYXRpb25cclxuICogLSBbT3B0aW9uYWxdIENvcnJlc3BvbmRpbmcgQ0xJIGFyZ3VtZW50IG5hbWVzIGZvciBDTEkgdXNhZ2VcclxuICogLSBbT3B0aW9uYWxdIExlZ2FjeSBuYW1lcyBmcm9tIHRoZSBwcmV2aW91cyBQaGFudG9tSlMtYmFzZWQgc2VydmVyXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgZGVmYXVsdENvbmZpZyA9IHtcclxuICBwdXBwZXRlZXI6IHtcclxuICAgIGFyZ3M6IHtcclxuICAgICAgdmFsdWU6IFtcclxuICAgICAgICAnLS1hbGxvdy1ydW5uaW5nLWluc2VjdXJlLWNvbnRlbnQnLFxyXG4gICAgICAgICctLWFzaC1uby1udWRnZXMnLFxyXG4gICAgICAgICctLWF1dG9wbGF5LXBvbGljeT11c2VyLWdlc3R1cmUtcmVxdWlyZWQnLFxyXG4gICAgICAgICctLWJsb2NrLW5ldy13ZWItY29udGVudHMnLFxyXG4gICAgICAgICctLWRpc2FibGUtYWNjZWxlcmF0ZWQtMmQtY2FudmFzJyxcclxuICAgICAgICAnLS1kaXNhYmxlLWJhY2tncm91bmQtbmV0d29ya2luZycsXHJcbiAgICAgICAgJy0tZGlzYWJsZS1iYWNrZ3JvdW5kLXRpbWVyLXRocm90dGxpbmcnLFxyXG4gICAgICAgICctLWRpc2FibGUtYmFja2dyb3VuZGluZy1vY2NsdWRlZC13aW5kb3dzJyxcclxuICAgICAgICAnLS1kaXNhYmxlLWJyZWFrcGFkJyxcclxuICAgICAgICAnLS1kaXNhYmxlLWNoZWNrZXItaW1hZ2luZycsXHJcbiAgICAgICAgJy0tZGlzYWJsZS1jbGllbnQtc2lkZS1waGlzaGluZy1kZXRlY3Rpb24nLFxyXG4gICAgICAgICctLWRpc2FibGUtY29tcG9uZW50LWV4dGVuc2lvbnMtd2l0aC1iYWNrZ3JvdW5kLXBhZ2VzJyxcclxuICAgICAgICAnLS1kaXNhYmxlLWNvbXBvbmVudC11cGRhdGUnLFxyXG4gICAgICAgICctLWRpc2FibGUtZGVmYXVsdC1hcHBzJyxcclxuICAgICAgICAnLS1kaXNhYmxlLWRldi1zaG0tdXNhZ2UnLFxyXG4gICAgICAgICctLWRpc2FibGUtZG9tYWluLXJlbGlhYmlsaXR5JyxcclxuICAgICAgICAnLS1kaXNhYmxlLWV4dGVuc2lvbnMnLFxyXG4gICAgICAgICctLWRpc2FibGUtZmVhdHVyZXM9Q2FsY3VsYXRlTmF0aXZlV2luT2NjbHVzaW9uLEludGVyZXN0RmVlZENvbnRlbnRTdWdnZXN0aW9ucyxXZWJPVFAnLFxyXG4gICAgICAgICctLWRpc2FibGUtaGFuZy1tb25pdG9yJyxcclxuICAgICAgICAnLS1kaXNhYmxlLWlwYy1mbG9vZGluZy1wcm90ZWN0aW9uJyxcclxuICAgICAgICAnLS1kaXNhYmxlLWxvZ2dpbmcnLFxyXG4gICAgICAgICctLWRpc2FibGUtbm90aWZpY2F0aW9ucycsXHJcbiAgICAgICAgJy0tZGlzYWJsZS1vZmZlci1zdG9yZS11bm1hc2tlZC13YWxsZXQtY2FyZHMnLFxyXG4gICAgICAgICctLWRpc2FibGUtcG9wdXAtYmxvY2tpbmcnLFxyXG4gICAgICAgICctLWRpc2FibGUtcHJpbnQtcHJldmlldycsXHJcbiAgICAgICAgJy0tZGlzYWJsZS1wcm9tcHQtb24tcmVwb3N0JyxcclxuICAgICAgICAnLS1kaXNhYmxlLXJlbmRlcmVyLWJhY2tncm91bmRpbmcnLFxyXG4gICAgICAgICctLWRpc2FibGUtc2VhcmNoLWVuZ2luZS1jaG9pY2Utc2NyZWVuJyxcclxuICAgICAgICAnLS1kaXNhYmxlLXNlc3Npb24tY3Jhc2hlZC1idWJibGUnLFxyXG4gICAgICAgICctLWRpc2FibGUtc2V0dWlkLXNhbmRib3gnLFxyXG4gICAgICAgICctLWRpc2FibGUtc2l0ZS1pc29sYXRpb24tdHJpYWxzJyxcclxuICAgICAgICAnLS1kaXNhYmxlLXNwZWVjaC1hcGknLFxyXG4gICAgICAgICctLWRpc2FibGUtc3luYycsXHJcbiAgICAgICAgJy0tZW5hYmxlLXVuc2FmZS13ZWJncHUnLFxyXG4gICAgICAgICctLWhpZGUtY3Jhc2gtcmVzdG9yZS1idWJibGUnLFxyXG4gICAgICAgICctLWhpZGUtc2Nyb2xsYmFycycsXHJcbiAgICAgICAgJy0tbWV0cmljcy1yZWNvcmRpbmctb25seScsXHJcbiAgICAgICAgJy0tbXV0ZS1hdWRpbycsXHJcbiAgICAgICAgJy0tbm8tZGVmYXVsdC1icm93c2VyLWNoZWNrJyxcclxuICAgICAgICAnLS1uby1maXJzdC1ydW4nLFxyXG4gICAgICAgICctLW5vLXBpbmdzJyxcclxuICAgICAgICAnLS1uby1zYW5kYm94JyxcclxuICAgICAgICAnLS1uby1zdGFydHVwLXdpbmRvdycsXHJcbiAgICAgICAgJy0tbm8tenlnb3RlJyxcclxuICAgICAgICAnLS1wYXNzd29yZC1zdG9yZT1iYXNpYycsXHJcbiAgICAgICAgJy0tcHJvY2Vzcy1wZXItdGFiJyxcclxuICAgICAgICAnLS11c2UtbW9jay1rZXljaGFpbidcclxuICAgICAgXSxcclxuICAgICAgdHlwZXM6IFsnc3RyaW5nW10nXSxcclxuICAgICAgZW52TGluazogJ1BVUFBFVEVFUl9BUkdTJyxcclxuICAgICAgY2xpTmFtZTogJ3B1cHBldGVlckFyZ3MnLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ0FycmF5IG9mIFB1cHBldGVlciBhcmd1bWVudHMnLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ2xpc3QnLFxyXG4gICAgICAgIHNlcGFyYXRvcjogJzsnXHJcbiAgICAgIH1cclxuICAgIH1cclxuICB9LFxyXG4gIGhpZ2hjaGFydHM6IHtcclxuICAgIHZlcnNpb246IHtcclxuICAgICAgdmFsdWU6ICdsYXRlc3QnLFxyXG4gICAgICB0eXBlczogWydzdHJpbmcnXSxcclxuICAgICAgZW52TGluazogJ0hJR0hDSEFSVFNfVkVSU0lPTicsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnSGlnaGNoYXJ0cyB2ZXJzaW9uJyxcclxuICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgIHR5cGU6ICd0ZXh0J1xyXG4gICAgICB9XHJcbiAgICB9LFxyXG4gICAgY2RuVXJsOiB7XHJcbiAgICAgIHZhbHVlOiAnaHR0cHM6Ly9jb2RlLmhpZ2hjaGFydHMuY29tJyxcclxuICAgICAgdHlwZXM6IFsnc3RyaW5nJ10sXHJcbiAgICAgIGVudkxpbms6ICdISUdIQ0hBUlRTX0NETl9VUkwnLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ0NETiBVUkwgZm9yIEhpZ2hjaGFydHMgc2NyaXB0cycsXHJcbiAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICB0eXBlOiAndGV4dCdcclxuICAgICAgfVxyXG4gICAgfSxcclxuICAgIGZvcmNlRmV0Y2g6IHtcclxuICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICB0eXBlczogWydib29sZWFuJ10sXHJcbiAgICAgIGVudkxpbms6ICdISUdIQ0hBUlRTX0ZPUkNFX0ZFVENIJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdGbGFnIHRvIHJlZmV0Y2ggc2NyaXB0cyBhZnRlciBlYWNoIHNlcnZlciByZXJ1bicsXHJcbiAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICB0eXBlOiAndG9nZ2xlJ1xyXG4gICAgICB9XHJcbiAgICB9LFxyXG4gICAgY2FjaGVQYXRoOiB7XHJcbiAgICAgIHZhbHVlOiAnLmNhY2hlJyxcclxuICAgICAgdHlwZXM6IFsnc3RyaW5nJ10sXHJcbiAgICAgIGVudkxpbms6ICdISUdIQ0hBUlRTX0NBQ0hFX1BBVEgnLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ0RpcmVjdG9yeSBwYXRoIGZvciBjYWNoZWQgSGlnaGNoYXJ0cyBzY3JpcHRzJyxcclxuICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgIHR5cGU6ICd0ZXh0J1xyXG4gICAgICB9XHJcbiAgICB9LFxyXG4gICAgY29yZVNjcmlwdHM6IHtcclxuICAgICAgdmFsdWU6IFsnaGlnaGNoYXJ0cycsICdoaWdoY2hhcnRzLW1vcmUnLCAnaGlnaGNoYXJ0cy0zZCddLFxyXG4gICAgICB0eXBlczogWydzdHJpbmdbXSddLFxyXG4gICAgICBlbnZMaW5rOiAnSElHSENIQVJUU19DT1JFX1NDUklQVFMnLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ0hpZ2hjaGFydHMgY29yZSBzY3JpcHRzIHRvIGZldGNoJyxcclxuICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgIHR5cGU6ICdtdWx0aXNlbGVjdCcsXHJcbiAgICAgICAgaW5zdHJ1Y3Rpb25zOiAnU3BhY2U6IFNlbGVjdCBzcGVjaWZpYywgQTogU2VsZWN0IGFsbCwgRW50ZXI6IENvbmZpcm0nXHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICBtb2R1bGVTY3JpcHRzOiB7XHJcbiAgICAgIHZhbHVlOiBbXHJcbiAgICAgICAgJ3N0b2NrJyxcclxuICAgICAgICAnbWFwJyxcclxuICAgICAgICAnZ2FudHQnLFxyXG4gICAgICAgICdleHBvcnRpbmcnLFxyXG4gICAgICAgICdwYXJhbGxlbC1jb29yZGluYXRlcycsXHJcbiAgICAgICAgJ2FjY2Vzc2liaWxpdHknLFxyXG4gICAgICAgIC8vICdhbm5vdGF0aW9ucy1hZHZhbmNlZCcsXHJcbiAgICAgICAgJ2Jvb3N0LWNhbnZhcycsXHJcbiAgICAgICAgJ2Jvb3N0JyxcclxuICAgICAgICAnZGF0YScsXHJcbiAgICAgICAgJ2RhdGEtdG9vbHMnLFxyXG4gICAgICAgICdkcmFnZ2FibGUtcG9pbnRzJyxcclxuICAgICAgICAnc3RhdGljLXNjYWxlJyxcclxuICAgICAgICAnYnJva2VuLWF4aXMnLFxyXG4gICAgICAgICdoZWF0bWFwJyxcclxuICAgICAgICAndGlsZW1hcCcsXHJcbiAgICAgICAgJ3RpbGVkd2VibWFwJyxcclxuICAgICAgICAndGltZWxpbmUnLFxyXG4gICAgICAgICd0cmVlbWFwJyxcclxuICAgICAgICAndHJlZWdyYXBoJyxcclxuICAgICAgICAnaXRlbS1zZXJpZXMnLFxyXG4gICAgICAgICdkcmlsbGRvd24nLFxyXG4gICAgICAgICdoaXN0b2dyYW0tYmVsbGN1cnZlJyxcclxuICAgICAgICAnYnVsbGV0JyxcclxuICAgICAgICAnZnVubmVsJyxcclxuICAgICAgICAnZnVubmVsM2QnLFxyXG4gICAgICAgICdnZW9oZWF0bWFwJyxcclxuICAgICAgICAncHlyYW1pZDNkJyxcclxuICAgICAgICAnbmV0d29ya2dyYXBoJyxcclxuICAgICAgICAnb3ZlcmxhcHBpbmctZGF0YWxhYmVscycsXHJcbiAgICAgICAgJ3BhcmV0bycsXHJcbiAgICAgICAgJ3BhdHRlcm4tZmlsbCcsXHJcbiAgICAgICAgJ3BpY3RvcmlhbCcsXHJcbiAgICAgICAgJ3ByaWNlLWluZGljYXRvcicsXHJcbiAgICAgICAgJ3NhbmtleScsXHJcbiAgICAgICAgJ2FyYy1kaWFncmFtJyxcclxuICAgICAgICAnZGVwZW5kZW5jeS13aGVlbCcsXHJcbiAgICAgICAgJ3Nlcmllcy1sYWJlbCcsXHJcbiAgICAgICAgJ3Nlcmllcy1vbi1wb2ludCcsXHJcbiAgICAgICAgJ3NvbGlkLWdhdWdlJyxcclxuICAgICAgICAnc29uaWZpY2F0aW9uJyxcclxuICAgICAgICAvLyAnc3RvY2stdG9vbHMnLFxyXG4gICAgICAgICdzdHJlYW1ncmFwaCcsXHJcbiAgICAgICAgJ3N1bmJ1cnN0JyxcclxuICAgICAgICAndmFyaWFibGUtcGllJyxcclxuICAgICAgICAndmFyaXdpZGUnLFxyXG4gICAgICAgICd2ZWN0b3InLFxyXG4gICAgICAgICd2ZW5uJyxcclxuICAgICAgICAnd2luZGJhcmInLFxyXG4gICAgICAgICd3b3JkY2xvdWQnLFxyXG4gICAgICAgICd4cmFuZ2UnLFxyXG4gICAgICAgICduby1kYXRhLXRvLWRpc3BsYXknLFxyXG4gICAgICAgICdkcmFnLXBhbmVzJyxcclxuICAgICAgICAnZGVidWdnZXInLFxyXG4gICAgICAgICdkdW1iYmVsbCcsXHJcbiAgICAgICAgJ2xvbGxpcG9wJyxcclxuICAgICAgICAnY3lsaW5kZXInLFxyXG4gICAgICAgICdvcmdhbml6YXRpb24nLFxyXG4gICAgICAgICdkb3RwbG90JyxcclxuICAgICAgICAnbWFya2VyLWNsdXN0ZXJzJyxcclxuICAgICAgICAnaG9sbG93Y2FuZGxlc3RpY2snLFxyXG4gICAgICAgICdoZWlraW5hc2hpJyxcclxuICAgICAgICAnZmxvd21hcCcsXHJcbiAgICAgICAgJ2V4cG9ydC1kYXRhJyxcclxuICAgICAgICAnbmF2aWdhdG9yJyxcclxuICAgICAgICAndGV4dHBhdGgnXHJcbiAgICAgIF0sXHJcbiAgICAgIHR5cGVzOiBbJ3N0cmluZ1tdJ10sXHJcbiAgICAgIGVudkxpbms6ICdISUdIQ0hBUlRTX01PRFVMRV9TQ1JJUFRTJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdIaWdoY2hhcnRzIG1vZHVsZSBzY3JpcHRzIHRvIGZldGNoJyxcclxuICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgIHR5cGU6ICdtdWx0aXNlbGVjdCcsXHJcbiAgICAgICAgaW5zdHJ1Y3Rpb25zOiAnU3BhY2U6IFNlbGVjdCBzcGVjaWZpYywgQTogU2VsZWN0IGFsbCwgRW50ZXI6IENvbmZpcm0nXHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICBpbmRpY2F0b3JTY3JpcHRzOiB7XHJcbiAgICAgIHZhbHVlOiBbJ2luZGljYXRvcnMtYWxsJ10sXHJcbiAgICAgIHR5cGVzOiBbJ3N0cmluZ1tdJ10sXHJcbiAgICAgIGVudkxpbms6ICdISUdIQ0hBUlRTX0lORElDQVRPUl9TQ1JJUFRTJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdIaWdoY2hhcnRzIGluZGljYXRvciBzY3JpcHRzIHRvIGZldGNoJyxcclxuICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgIHR5cGU6ICdtdWx0aXNlbGVjdCcsXHJcbiAgICAgICAgaW5zdHJ1Y3Rpb25zOiAnU3BhY2U6IFNlbGVjdCBzcGVjaWZpYywgQTogU2VsZWN0IGFsbCwgRW50ZXI6IENvbmZpcm0nXHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICBjdXN0b21TY3JpcHRzOiB7XHJcbiAgICAgIHZhbHVlOiBbXHJcbiAgICAgICAgJ2h0dHBzOi8vY2RuanMuY2xvdWRmbGFyZS5jb20vYWpheC9saWJzL21vbWVudC5qcy8yLjMwLjEvbW9tZW50Lm1pbi5qcycsXHJcbiAgICAgICAgJ2h0dHBzOi8vY2RuanMuY2xvdWRmbGFyZS5jb20vYWpheC9saWJzL21vbWVudC10aW1lem9uZS8wLjUuNDUvbW9tZW50LXRpbWV6b25lLXdpdGgtZGF0YS5taW4uanMnXHJcbiAgICAgIF0sXHJcbiAgICAgIHR5cGVzOiBbJ3N0cmluZ1tdJ10sXHJcbiAgICAgIGVudkxpbms6ICdISUdIQ0hBUlRTX0NVU1RPTV9TQ1JJUFRTJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdBZGRpdGlvbmFsIGN1c3RvbSBzY3JpcHRzIG9yIGRlcGVuZGVuY2llcyB0byBmZXRjaCcsXHJcbiAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICB0eXBlOiAnbGlzdCcsXHJcbiAgICAgICAgc2VwYXJhdG9yOiAnOydcclxuICAgICAgfVxyXG4gICAgfVxyXG4gIH0sXHJcbiAgZXhwb3J0OiB7XHJcbiAgICBpbmZpbGU6IHtcclxuICAgICAgdmFsdWU6IG51bGwsXHJcbiAgICAgIHR5cGVzOiBbJ3N0cmluZycsICdudWxsJ10sXHJcbiAgICAgIGVudkxpbms6ICdFWFBPUlRfSU5GSUxFJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ0lucHV0IGZpbGVuYW1lIHdpdGggdHlwZSwgZm9ybWF0dGVkIGNvcnJlY3RseSBhcyBKU09OIG9yIFNWRycsXHJcbiAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICB0eXBlOiAndGV4dCdcclxuICAgICAgfVxyXG4gICAgfSxcclxuICAgIGluc3RyOiB7XHJcbiAgICAgIHZhbHVlOiBudWxsLFxyXG4gICAgICB0eXBlczogWydzdHJpbmcnLCAnbnVsbCddLFxyXG4gICAgICBlbnZMaW5rOiAnRVhQT1JUX0lOU1RSJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ092ZXJyaWRlcyB0aGUgYGluZmlsZWAgd2l0aCBKU09OLCBzdHJpbmdpZmllZCBKU09OLCBvciBTVkcgaW5wdXQnLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ3RleHQnXHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICBvcHRpb25zOiB7XHJcbiAgICAgIHZhbHVlOiBudWxsLFxyXG4gICAgICB0eXBlczogWydPYmplY3QnLCAnbnVsbCddLFxyXG4gICAgICBlbnZMaW5rOiAnRVhQT1JUX09QVElPTlMnLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ0FsaWFzIGZvciB0aGUgYGluc3RyYCBvcHRpb24nLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ3RleHQnXHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICBzdmc6IHtcclxuICAgICAgdmFsdWU6IG51bGwsXHJcbiAgICAgIHR5cGVzOiBbJ3N0cmluZycsICdudWxsJ10sXHJcbiAgICAgIGVudkxpbms6ICdFWFBPUlRfU1ZHJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdTVkcgc3RyaW5nIHJlcHJlc2VudGF0aW9uIG9mIHRoZSBjaGFydCB0byByZW5kZXInLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ3RleHQnXHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICBiYXRjaDoge1xyXG4gICAgICB2YWx1ZTogbnVsbCxcclxuICAgICAgdHlwZXM6IFsnc3RyaW5nJywgJ251bGwnXSxcclxuICAgICAgZW52TGluazogJ0VYUE9SVF9CQVRDSCcsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdCYXRjaCBqb2Igc3RyaW5nIHdpdGggaW5wdXQvb3V0cHV0IHBhaXJzOiBcImluPW91dDtpbj1vdXQ7Li4uXCInLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ3RleHQnXHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICBvdXRmaWxlOiB7XHJcbiAgICAgIHZhbHVlOiBudWxsLFxyXG4gICAgICB0eXBlczogWydzdHJpbmcnLCAnbnVsbCddLFxyXG4gICAgICBlbnZMaW5rOiAnRVhQT1JUX09VVEZJTEUnLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnT3V0cHV0IGZpbGVuYW1lIHdpdGggdHlwZS4gQ2FuIGJlIGpwZWcsIHBuZywgcGRmLCBvciBzdmcgYW5kIGlnbm9yZXMgYHR5cGVgIG9wdGlvbicsXHJcbiAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICB0eXBlOiAndGV4dCdcclxuICAgICAgfVxyXG4gICAgfSxcclxuICAgIHR5cGU6IHtcclxuICAgICAgdmFsdWU6ICdwbmcnLFxyXG4gICAgICB0eXBlczogWydzdHJpbmcnXSxcclxuICAgICAgZW52TGluazogJ0VYUE9SVF9UWVBFJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdGaWxlIGV4cG9ydCBmb3JtYXQuIENhbiBiZSBqcGVnLCBwbmcsIHBkZiwgb3Igc3ZnJyxcclxuICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgIHR5cGU6ICdzZWxlY3QnLFxyXG4gICAgICAgIGhpbnQ6ICdEZWZhdWx0OiBwbmcnLFxyXG4gICAgICAgIGNob2ljZXM6IFsncG5nJywgJ2pwZWcnLCAncGRmJywgJ3N2ZyddXHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICBjb25zdHI6IHtcclxuICAgICAgdmFsdWU6ICdjaGFydCcsXHJcbiAgICAgIHR5cGVzOiBbJ3N0cmluZyddLFxyXG4gICAgICBlbnZMaW5rOiAnRVhQT1JUX0NPTlNUUicsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdDaGFydCBjb25zdHJ1Y3Rvci4gQ2FuIGJlIGNoYXJ0LCBzdG9ja0NoYXJ0LCBtYXBDaGFydCwgb3IgZ2FudHRDaGFydCcsXHJcbiAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICB0eXBlOiAnc2VsZWN0JyxcclxuICAgICAgICBoaW50OiAnRGVmYXVsdDogY2hhcnQnLFxyXG4gICAgICAgIGNob2ljZXM6IFsnY2hhcnQnLCAnc3RvY2tDaGFydCcsICdtYXBDaGFydCcsICdnYW50dENoYXJ0J11cclxuICAgICAgfVxyXG4gICAgfSxcclxuICAgIGI2NDoge1xyXG4gICAgICB2YWx1ZTogZmFsc2UsXHJcbiAgICAgIHR5cGVzOiBbJ2Jvb2xlYW4nXSxcclxuICAgICAgZW52TGluazogJ0VYUE9SVF9CNjQnLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnV2hldGhlciBvciBub3QgdG8gdGhlIGNoYXJ0IHNob3VsZCBiZSByZWNlaXZlZCBpbiBCYXNlNjQgZm9ybWF0IGluc3RlYWQgb2YgYmluYXJ5JyxcclxuICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgIHR5cGU6ICd0b2dnbGUnXHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICBub0Rvd25sb2FkOiB7XHJcbiAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgdHlwZXM6IFsnYm9vbGVhbiddLFxyXG4gICAgICBlbnZMaW5rOiAnRVhQT1JUX05PX0RPV05MT0FEJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ1doZXRoZXIgb3Igbm90IHRvIGluY2x1ZGUgb3IgZXhjbHVkZSBhdHRhY2htZW50IGhlYWRlcnMgaW4gdGhlIHJlc3BvbnNlJyxcclxuICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgIHR5cGU6ICd0b2dnbGUnXHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICBoZWlnaHQ6IHtcclxuICAgICAgdmFsdWU6IG51bGwsXHJcbiAgICAgIHR5cGVzOiBbJ251bWJlcicsICdudWxsJ10sXHJcbiAgICAgIGVudkxpbms6ICdFWFBPUlRfSEVJR0hUJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdIZWlnaHQgb2YgdGhlIGV4cG9ydGVkIGNoYXJ0LCBvdmVycmlkZXMgY2hhcnQgc2V0dGluZ3MnLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ251bWJlcidcclxuICAgICAgfVxyXG4gICAgfSxcclxuICAgIHdpZHRoOiB7XHJcbiAgICAgIHZhbHVlOiBudWxsLFxyXG4gICAgICB0eXBlczogWydudW1iZXInLCAnbnVsbCddLFxyXG4gICAgICBlbnZMaW5rOiAnRVhQT1JUX1dJRFRIJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdXaWR0aCBvZiB0aGUgZXhwb3J0ZWQgY2hhcnQsIG92ZXJyaWRlcyBjaGFydCBzZXR0aW5ncycsXHJcbiAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICB0eXBlOiAnbnVtYmVyJ1xyXG4gICAgICB9XHJcbiAgICB9LFxyXG4gICAgc2NhbGU6IHtcclxuICAgICAgdmFsdWU6IG51bGwsXHJcbiAgICAgIHR5cGVzOiBbJ251bWJlcicsICdudWxsJ10sXHJcbiAgICAgIGVudkxpbms6ICdFWFBPUlRfU0NBTEUnLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnU2NhbGUgb2YgdGhlIGV4cG9ydGVkIGNoYXJ0LCBvdmVycmlkZXMgY2hhcnQgc2V0dGluZ3MuIFJhbmdlcyBmcm9tIDAuMSB0byA1LjAnLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ251bWJlcidcclxuICAgICAgfVxyXG4gICAgfSxcclxuICAgIGRlZmF1bHRIZWlnaHQ6IHtcclxuICAgICAgdmFsdWU6IDQwMCxcclxuICAgICAgdHlwZXM6IFsnbnVtYmVyJ10sXHJcbiAgICAgIGVudkxpbms6ICdFWFBPUlRfREVGQVVMVF9IRUlHSFQnLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ0RlZmF1bHQgaGVpZ2h0IG9mIHRoZSBleHBvcnRlZCBjaGFydCBpZiBub3Qgc2V0JyxcclxuICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgIHR5cGU6ICdudW1iZXInXHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICBkZWZhdWx0V2lkdGg6IHtcclxuICAgICAgdmFsdWU6IDYwMCxcclxuICAgICAgdHlwZXM6IFsnbnVtYmVyJ10sXHJcbiAgICAgIGVudkxpbms6ICdFWFBPUlRfREVGQVVMVF9XSURUSCcsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnRGVmYXVsdCB3aWR0aCBvZiB0aGUgZXhwb3J0ZWQgY2hhcnQgaWYgbm90IHNldCcsXHJcbiAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICB0eXBlOiAnbnVtYmVyJ1xyXG4gICAgICB9XHJcbiAgICB9LFxyXG4gICAgZGVmYXVsdFNjYWxlOiB7XHJcbiAgICAgIHZhbHVlOiAxLFxyXG4gICAgICB0eXBlczogWydudW1iZXInXSxcclxuICAgICAgZW52TGluazogJ0VYUE9SVF9ERUZBVUxUX1NDQUxFJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ0RlZmF1bHQgc2NhbGUgb2YgdGhlIGV4cG9ydGVkIGNoYXJ0IGlmIG5vdCBzZXQuIFJhbmdlcyBmcm9tIDAuMSB0byA1LjAnLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgICAgbWluOiAwLjEsXHJcbiAgICAgICAgbWF4OiA1XHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICBnbG9iYWxPcHRpb25zOiB7XHJcbiAgICAgIHZhbHVlOiBudWxsLFxyXG4gICAgICB0eXBlczogWydPYmplY3QnLCAnc3RyaW5nJywgJ251bGwnXSxcclxuICAgICAgZW52TGluazogJ0VYUE9SVF9HTE9CQUxfT1BUSU9OUycsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdKU09OLCBzdHJpbmdpZmllZCBKU09OIG9yIGZpbGVuYW1lIHdpdGggZ2xvYmFsIG9wdGlvbnMgZm9yIEhpZ2hjaGFydHMuc2V0T3B0aW9ucycsXHJcbiAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICB0eXBlOiAndGV4dCdcclxuICAgICAgfVxyXG4gICAgfSxcclxuICAgIHRoZW1lT3B0aW9uczoge1xyXG4gICAgICB2YWx1ZTogbnVsbCxcclxuICAgICAgdHlwZXM6IFsnT2JqZWN0JywgJ3N0cmluZycsICdudWxsJ10sXHJcbiAgICAgIGVudkxpbms6ICdFWFBPUlRfVEhFTUVfT1BUSU9OUycsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdKU09OLCBzdHJpbmdpZmllZCBKU09OIG9yIGZpbGVuYW1lIHdpdGggdGhlbWUgb3B0aW9ucyBmb3IgSGlnaGNoYXJ0cy5zZXRPcHRpb25zJyxcclxuICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgIHR5cGU6ICd0ZXh0J1xyXG4gICAgICB9XHJcbiAgICB9LFxyXG4gICAgcmFzdGVyaXphdGlvblRpbWVvdXQ6IHtcclxuICAgICAgdmFsdWU6IDE1MDAsXHJcbiAgICAgIHR5cGVzOiBbJ251bWJlciddLFxyXG4gICAgICBlbnZMaW5rOiAnRVhQT1JUX1JBU1RFUklaQVRJT05fVElNRU9VVCcsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnTWlsbGlzZWNvbmRzIHRvIHdhaXQgZm9yIHdlYnBhZ2UgcmVuZGVyaW5nJyxcclxuICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgIHR5cGU6ICdudW1iZXInXHJcbiAgICAgIH1cclxuICAgIH1cclxuICB9LFxyXG4gIGN1c3RvbUxvZ2ljOiB7XHJcbiAgICBhbGxvd0NvZGVFeGVjdXRpb246IHtcclxuICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICB0eXBlczogWydib29sZWFuJ10sXHJcbiAgICAgIGVudkxpbms6ICdDVVNUT01fTE9HSUNfQUxMT1dfQ09ERV9FWEVDVVRJT04nLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnQWxsb3dzIG9yIGRpc2FsbG93cyBleGVjdXRpb24gb2YgYXJiaXRyYXJ5IGNvZGUgZHVyaW5nIGV4cG9ydGluZycsXHJcbiAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICB0eXBlOiAndG9nZ2xlJ1xyXG4gICAgICB9XHJcbiAgICB9LFxyXG4gICAgYWxsb3dGaWxlUmVzb3VyY2VzOiB7XHJcbiAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgdHlwZXM6IFsnYm9vbGVhbiddLFxyXG4gICAgICBlbnZMaW5rOiAnQ1VTVE9NX0xPR0lDX0FMTE9XX0ZJTEVfUkVTT1VSQ0VTJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ0FsbG93cyBvciBkaXNhbGxvd3MgaW5qZWN0aW9uIG9mIGZpbGVzeXN0ZW0gcmVzb3VyY2VzIChkaXNhYmxlZCBpbiBzZXJ2ZXIgbW9kZSknLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ3RvZ2dsZSdcclxuICAgICAgfVxyXG4gICAgfSxcclxuICAgIGN1c3RvbUNvZGU6IHtcclxuICAgICAgdmFsdWU6IG51bGwsXHJcbiAgICAgIHR5cGVzOiBbJ3N0cmluZycsICdudWxsJ10sXHJcbiAgICAgIGVudkxpbms6ICdDVVNUT01fTE9HSUNfQ1VTVE9NX0NPREUnLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnQ3VzdG9tIGNvZGUgdG8gZXhlY3V0ZSBiZWZvcmUgY2hhcnQgaW5pdGlhbGl6YXRpb24uIENhbiBiZSBhIGZ1bmN0aW9uLCBjb2RlIHdyYXBwZWQgaW4gYSBmdW5jdGlvbiwgb3IgYSAuanMgZmlsZW5hbWUnLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ3RleHQnXHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICBjYWxsYmFjazoge1xyXG4gICAgICB2YWx1ZTogbnVsbCxcclxuICAgICAgdHlwZXM6IFsnc3RyaW5nJywgJ251bGwnXSxcclxuICAgICAgZW52TGluazogJ0NVU1RPTV9MT0dJQ19DQUxMQkFDSycsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdKYXZhU2NyaXB0IGNvZGUgdG8gcnVuIGR1cmluZyBjb25zdHJ1Y3Rpb24uIENhbiBiZSBhIGZ1bmN0aW9uIG9yIGEgLmpzIGZpbGVuYW1lJyxcclxuICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgIHR5cGU6ICd0ZXh0J1xyXG4gICAgICB9XHJcbiAgICB9LFxyXG4gICAgcmVzb3VyY2VzOiB7XHJcbiAgICAgIHZhbHVlOiBudWxsLFxyXG4gICAgICB0eXBlczogWydPYmplY3QnLCAnc3RyaW5nJywgJ251bGwnXSxcclxuICAgICAgZW52TGluazogJ0NVU1RPTV9MT0dJQ19SRVNPVVJDRVMnLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnQWRkaXRpb25hbCByZXNvdXJjZXMgYXMgSlNPTiwgc3RyaW5naWZpZWQgSlNPTiwgb3IgZmlsZW5hbWUsIGNvbnRhaW5pbmcgZmlsZXMsIGpzLCBhbmQgY3NzIHNlY3Rpb25zJyxcclxuICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgIHR5cGU6ICd0ZXh0J1xyXG4gICAgICB9XHJcbiAgICB9LFxyXG4gICAgbG9hZENvbmZpZzoge1xyXG4gICAgICB2YWx1ZTogbnVsbCxcclxuICAgICAgdHlwZXM6IFsnc3RyaW5nJywgJ251bGwnXSxcclxuICAgICAgZW52TGluazogJ0NVU1RPTV9MT0dJQ19MT0FEX0NPTkZJRycsXHJcbiAgICAgIGxlZ2FjeU5hbWU6ICdmcm9tRmlsZScsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnRmlsZSB3aXRoIGEgcHJlLWRlZmluZWQgY29uZmlndXJhdGlvbiB0byB1c2UnLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ3RleHQnXHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICBjcmVhdGVDb25maWc6IHtcclxuICAgICAgdmFsdWU6IG51bGwsXHJcbiAgICAgIHR5cGVzOiBbJ3N0cmluZycsICdudWxsJ10sXHJcbiAgICAgIGVudkxpbms6ICdDVVNUT01fTE9HSUNfQ1JFQVRFX0NPTkZJRycsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdQcm9tcHQtYmFzZWQgb3B0aW9uIHNldHRpbmcsIHNhdmVkIHRvIGEgcHJvdmlkZWQgY29uZmlnIGZpbGUnLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ3RleHQnXHJcbiAgICAgIH1cclxuICAgIH1cclxuICB9LFxyXG4gIHNlcnZlcjoge1xyXG4gICAgZW5hYmxlOiB7XHJcbiAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgdHlwZXM6IFsnYm9vbGVhbiddLFxyXG4gICAgICBlbnZMaW5rOiAnU0VSVkVSX0VOQUJMRScsXHJcbiAgICAgIGNsaU5hbWU6ICdlbmFibGVTZXJ2ZXInLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ1N0YXJ0cyB0aGUgc2VydmVyIHdoZW4gdHJ1ZScsXHJcbiAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICB0eXBlOiAndG9nZ2xlJ1xyXG4gICAgICB9XHJcbiAgICB9LFxyXG4gICAgaG9zdDoge1xyXG4gICAgICB2YWx1ZTogJzAuMC4wLjAnLFxyXG4gICAgICB0eXBlczogWydzdHJpbmcnXSxcclxuICAgICAgZW52TGluazogJ1NFUlZFUl9IT1NUJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdIb3N0bmFtZSBvZiB0aGUgc2VydmVyJyxcclxuICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgIHR5cGU6ICd0ZXh0J1xyXG4gICAgICB9XHJcbiAgICB9LFxyXG4gICAgcG9ydDoge1xyXG4gICAgICB2YWx1ZTogNzgwMSxcclxuICAgICAgdHlwZXM6IFsnbnVtYmVyJ10sXHJcbiAgICAgIGVudkxpbms6ICdTRVJWRVJfUE9SVCcsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnUG9ydCBudW1iZXIgZm9yIHRoZSBzZXJ2ZXInLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ251bWJlcidcclxuICAgICAgfVxyXG4gICAgfSxcclxuICAgIHVwbG9hZExpbWl0OiB7XHJcbiAgICAgIHZhbHVlOiAzLFxyXG4gICAgICB0eXBlczogWydudW1iZXInXSxcclxuICAgICAgZW52TGluazogJ1NFUlZFUl9VUExPQURfTElNSVQnLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ01heGltdW0gcmVxdWVzdCBib2R5IHNpemUgaW4gTUInLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ251bWJlcidcclxuICAgICAgfVxyXG4gICAgfSxcclxuICAgIGJlbmNobWFya2luZzoge1xyXG4gICAgICB2YWx1ZTogZmFsc2UsXHJcbiAgICAgIHR5cGVzOiBbJ2Jvb2xlYW4nXSxcclxuICAgICAgZW52TGluazogJ1NFUlZFUl9CRU5DSE1BUktJTkcnLFxyXG4gICAgICBjbGlOYW1lOiAnc2VydmVyQmVuY2htYXJraW5nJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ0Rpc3BsYXlzIG9yIG5vdCBhY3Rpb24gZHVyYXRpb25zIGluIG1pbGxpc2Vjb25kcyBkdXJpbmcgc2VydmVyIHJlcXVlc3RzJyxcclxuICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgIHR5cGU6ICd0b2dnbGUnXHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICBwcm94eToge1xyXG4gICAgICBob3N0OiB7XHJcbiAgICAgICAgdmFsdWU6IG51bGwsXHJcbiAgICAgICAgdHlwZXM6IFsnc3RyaW5nJywgJ251bGwnXSxcclxuICAgICAgICBlbnZMaW5rOiAnU0VSVkVSX1BST1hZX0hPU1QnLFxyXG4gICAgICAgIGNsaU5hbWU6ICdwcm94eUhvc3QnLFxyXG4gICAgICAgIGRlc2NyaXB0aW9uOiAnSG9zdCBvZiB0aGUgcHJveHkgc2VydmVyLCBpZiBhcHBsaWNhYmxlJyxcclxuICAgICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgICB0eXBlOiAndGV4dCdcclxuICAgICAgICB9XHJcbiAgICAgIH0sXHJcbiAgICAgIHBvcnQ6IHtcclxuICAgICAgICB2YWx1ZTogbnVsbCxcclxuICAgICAgICB0eXBlczogWydudW1iZXInLCAnbnVsbCddLFxyXG4gICAgICAgIGVudkxpbms6ICdTRVJWRVJfUFJPWFlfUE9SVCcsXHJcbiAgICAgICAgY2xpTmFtZTogJ3Byb3h5UG9ydCcsXHJcbiAgICAgICAgZGVzY3JpcHRpb246ICdQb3J0IG9mIHRoZSBwcm94eSBzZXJ2ZXIsIGlmIGFwcGxpY2FibGUnLFxyXG4gICAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICAgIHR5cGU6ICdudW1iZXInXHJcbiAgICAgICAgfVxyXG4gICAgICB9LFxyXG4gICAgICB0aW1lb3V0OiB7XHJcbiAgICAgICAgdmFsdWU6IDUwMDAsXHJcbiAgICAgICAgdHlwZXM6IFsnbnVtYmVyJ10sXHJcbiAgICAgICAgZW52TGluazogJ1NFUlZFUl9QUk9YWV9USU1FT1VUJyxcclxuICAgICAgICBjbGlOYW1lOiAncHJveHlUaW1lb3V0JyxcclxuICAgICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAgICdUaW1lb3V0IGluIG1pbGxpc2Vjb25kcyBmb3IgdGhlIHByb3h5IHNlcnZlciwgaWYgYXBwbGljYWJsZScsXHJcbiAgICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgICAgdHlwZTogJ251bWJlcidcclxuICAgICAgICB9XHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICByYXRlTGltaXRpbmc6IHtcclxuICAgICAgZW5hYmxlOiB7XHJcbiAgICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICAgIHR5cGVzOiBbJ2Jvb2xlYW4nXSxcclxuICAgICAgICBlbnZMaW5rOiAnU0VSVkVSX1JBVEVfTElNSVRJTkdfRU5BQkxFJyxcclxuICAgICAgICBjbGlOYW1lOiAnZW5hYmxlUmF0ZUxpbWl0aW5nJyxcclxuICAgICAgICBkZXNjcmlwdGlvbjogJ0VuYWJsZXMgb3IgZGlzYWJsZXMgcmF0ZSBsaW1pdGluZyBvbiB0aGUgc2VydmVyJyxcclxuICAgICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgICB0eXBlOiAndG9nZ2xlJ1xyXG4gICAgICAgIH1cclxuICAgICAgfSxcclxuICAgICAgbWF4UmVxdWVzdHM6IHtcclxuICAgICAgICB2YWx1ZTogMTAsXHJcbiAgICAgICAgdHlwZXM6IFsnbnVtYmVyJ10sXHJcbiAgICAgICAgZW52TGluazogJ1NFUlZFUl9SQVRFX0xJTUlUSU5HX01BWF9SRVFVRVNUUycsXHJcbiAgICAgICAgbGVnYWN5TmFtZTogJ3JhdGVMaW1pdCcsXHJcbiAgICAgICAgZGVzY3JpcHRpb246ICdNYXhpbXVtIG51bWJlciBvZiByZXF1ZXN0cyBhbGxvd2VkIHBlciBtaW51dGUnLFxyXG4gICAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICAgIHR5cGU6ICdudW1iZXInXHJcbiAgICAgICAgfVxyXG4gICAgICB9LFxyXG4gICAgICB3aW5kb3c6IHtcclxuICAgICAgICB2YWx1ZTogMSxcclxuICAgICAgICB0eXBlczogWydudW1iZXInXSxcclxuICAgICAgICBlbnZMaW5rOiAnU0VSVkVSX1JBVEVfTElNSVRJTkdfV0lORE9XJyxcclxuICAgICAgICBkZXNjcmlwdGlvbjogJ1RpbWUgd2luZG93IGluIG1pbnV0ZXMgZm9yIHJhdGUgbGltaXRpbmcnLFxyXG4gICAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICAgIHR5cGU6ICdudW1iZXInXHJcbiAgICAgICAgfVxyXG4gICAgICB9LFxyXG4gICAgICBkZWxheToge1xyXG4gICAgICAgIHZhbHVlOiAwLFxyXG4gICAgICAgIHR5cGVzOiBbJ251bWJlciddLFxyXG4gICAgICAgIGVudkxpbms6ICdTRVJWRVJfUkFURV9MSU1JVElOR19ERUxBWScsXHJcbiAgICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgICAnRGVsYXkgZHVyYXRpb24gYmV0d2VlbiBzdWNjZXNzaXZlIHJlcXVlc3RzIGJlZm9yZSByZWFjaGluZyB0aGUgbGltaXQnLFxyXG4gICAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICAgIHR5cGU6ICdudW1iZXInXHJcbiAgICAgICAgfVxyXG4gICAgICB9LFxyXG4gICAgICB0cnVzdFByb3h5OiB7XHJcbiAgICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICAgIHR5cGVzOiBbJ2Jvb2xlYW4nXSxcclxuICAgICAgICBlbnZMaW5rOiAnU0VSVkVSX1JBVEVfTElNSVRJTkdfVFJVU1RfUFJPWFknLFxyXG4gICAgICAgIGRlc2NyaXB0aW9uOiAnU2V0IHRvIHRydWUgaWYgdGhlIHNlcnZlciBpcyBiZWhpbmQgYSBsb2FkIGJhbGFuY2VyJyxcclxuICAgICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgICB0eXBlOiAndG9nZ2xlJ1xyXG4gICAgICAgIH1cclxuICAgICAgfSxcclxuICAgICAgc2tpcEtleToge1xyXG4gICAgICAgIHZhbHVlOiBudWxsLFxyXG4gICAgICAgIHR5cGVzOiBbJ3N0cmluZycsICdudWxsJ10sXHJcbiAgICAgICAgZW52TGluazogJ1NFUlZFUl9SQVRFX0xJTUlUSU5HX1NLSVBfS0VZJyxcclxuICAgICAgICBkZXNjcmlwdGlvbjogJ0tleSB0byBieXBhc3MgdGhlIHJhdGUgbGltaXRlciwgdXNlZCB3aXRoIGBza2lwVG9rZW5gJyxcclxuICAgICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgICB0eXBlOiAndGV4dCdcclxuICAgICAgICB9XHJcbiAgICAgIH0sXHJcbiAgICAgIHNraXBUb2tlbjoge1xyXG4gICAgICAgIHZhbHVlOiBudWxsLFxyXG4gICAgICAgIHR5cGVzOiBbJ3N0cmluZycsICdudWxsJ10sXHJcbiAgICAgICAgZW52TGluazogJ1NFUlZFUl9SQVRFX0xJTUlUSU5HX1NLSVBfVE9LRU4nLFxyXG4gICAgICAgIGRlc2NyaXB0aW9uOiAnVG9rZW4gdG8gYnlwYXNzIHRoZSByYXRlIGxpbWl0ZXIsIHVzZWQgd2l0aCBgc2tpcEtleWAnLFxyXG4gICAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICAgIHR5cGU6ICd0ZXh0J1xyXG4gICAgICAgIH1cclxuICAgICAgfVxyXG4gICAgfSxcclxuICAgIHNzbDoge1xyXG4gICAgICBlbmFibGU6IHtcclxuICAgICAgICB2YWx1ZTogZmFsc2UsXHJcbiAgICAgICAgdHlwZXM6IFsnYm9vbGVhbiddLFxyXG4gICAgICAgIGVudkxpbms6ICdTRVJWRVJfU1NMX0VOQUJMRScsXHJcbiAgICAgICAgY2xpTmFtZTogJ2VuYWJsZVNzbCcsXHJcbiAgICAgICAgZGVzY3JpcHRpb246ICdFbmFibGVzIG9yIGRpc2FibGVzIFNTTCBwcm90b2NvbCcsXHJcbiAgICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgICAgdHlwZTogJ3RvZ2dsZSdcclxuICAgICAgICB9XHJcbiAgICAgIH0sXHJcbiAgICAgIGZvcmNlOiB7XHJcbiAgICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICAgIHR5cGVzOiBbJ2Jvb2xlYW4nXSxcclxuICAgICAgICBlbnZMaW5rOiAnU0VSVkVSX1NTTF9GT1JDRScsXHJcbiAgICAgICAgY2xpTmFtZTogJ3NzbEZvcmNlJyxcclxuICAgICAgICBsZWdhY3lOYW1lOiAnc3NsT25seScsXHJcbiAgICAgICAgZGVzY3JpcHRpb246ICdGb3JjZXMgdGhlIHNlcnZlciB0byB1c2UgSFRUUFMgb25seSB3aGVuIHRydWUnLFxyXG4gICAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICAgIHR5cGU6ICd0b2dnbGUnXHJcbiAgICAgICAgfVxyXG4gICAgICB9LFxyXG4gICAgICBwb3J0OiB7XHJcbiAgICAgICAgdmFsdWU6IDQ0MyxcclxuICAgICAgICB0eXBlczogWydudW1iZXInXSxcclxuICAgICAgICBlbnZMaW5rOiAnU0VSVkVSX1NTTF9QT1JUJyxcclxuICAgICAgICBjbGlOYW1lOiAnc3NsUG9ydCcsXHJcbiAgICAgICAgZGVzY3JpcHRpb246ICdQb3J0IGZvciB0aGUgU1NMIHNlcnZlcicsXHJcbiAgICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgICAgdHlwZTogJ251bWJlcidcclxuICAgICAgICB9XHJcbiAgICAgIH0sXHJcbiAgICAgIGNlcnRQYXRoOiB7XHJcbiAgICAgICAgdmFsdWU6IG51bGwsXHJcbiAgICAgICAgdHlwZXM6IFsnc3RyaW5nJywgJ251bGwnXSxcclxuICAgICAgICBlbnZMaW5rOiAnU0VSVkVSX1NTTF9DRVJUX1BBVEgnLFxyXG4gICAgICAgIGNsaU5hbWU6ICdzc2xDZXJ0UGF0aCcsXHJcbiAgICAgICAgbGVnYWN5TmFtZTogJ3NzbFBhdGgnLFxyXG4gICAgICAgIGRlc2NyaXB0aW9uOiAnUGF0aCB0byB0aGUgU1NMIGNlcnRpZmljYXRlL2tleSBmaWxlJyxcclxuICAgICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgICB0eXBlOiAndGV4dCdcclxuICAgICAgICB9XHJcbiAgICAgIH1cclxuICAgIH1cclxuICB9LFxyXG4gIHBvb2w6IHtcclxuICAgIG1pbldvcmtlcnM6IHtcclxuICAgICAgdmFsdWU6IDQsXHJcbiAgICAgIHR5cGVzOiBbJ251bWJlciddLFxyXG4gICAgICBlbnZMaW5rOiAnUE9PTF9NSU5fV09SS0VSUycsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnTWluaW11bSBhbmQgaW5pdGlhbCBudW1iZXIgb2YgcG9vbCB3b3JrZXJzIHRvIHNwYXduJyxcclxuICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgIHR5cGU6ICdudW1iZXInXHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICBtYXhXb3JrZXJzOiB7XHJcbiAgICAgIHZhbHVlOiA4LFxyXG4gICAgICB0eXBlczogWydudW1iZXInXSxcclxuICAgICAgZW52TGluazogJ1BPT0xfTUFYX1dPUktFUlMnLFxyXG4gICAgICBsZWdhY3lOYW1lOiAnd29ya2VycycsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnTWF4aW11bSBudW1iZXIgb2YgcG9vbCB3b3JrZXJzIHRvIHNwYXduJyxcclxuICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgIHR5cGU6ICdudW1iZXInXHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICB3b3JrTGltaXQ6IHtcclxuICAgICAgdmFsdWU6IDQwLFxyXG4gICAgICB0eXBlczogWydudW1iZXInXSxcclxuICAgICAgZW52TGluazogJ1BPT0xfV09SS19MSU1JVCcsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnTnVtYmVyIG9mIHRhc2tzIGEgd29ya2VyIGNhbiBoYW5kbGUgYmVmb3JlIHJlc3RhcnRpbmcnLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ251bWJlcidcclxuICAgICAgfVxyXG4gICAgfSxcclxuICAgIGFjcXVpcmVUaW1lb3V0OiB7XHJcbiAgICAgIHZhbHVlOiA1MDAwLFxyXG4gICAgICB0eXBlczogWydudW1iZXInXSxcclxuICAgICAgZW52TGluazogJ1BPT0xfQUNRVUlSRV9USU1FT1VUJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdUaW1lb3V0IGluIG1pbGxpc2Vjb25kcyBmb3IgYWNxdWlyaW5nIGEgcmVzb3VyY2UnLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ251bWJlcidcclxuICAgICAgfVxyXG4gICAgfSxcclxuICAgIGNyZWF0ZVRpbWVvdXQ6IHtcclxuICAgICAgdmFsdWU6IDUwMDAsXHJcbiAgICAgIHR5cGVzOiBbJ251bWJlciddLFxyXG4gICAgICBlbnZMaW5rOiAnUE9PTF9DUkVBVEVfVElNRU9VVCcsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnVGltZW91dCBpbiBtaWxsaXNlY29uZHMgZm9yIGNyZWF0aW5nIGEgcmVzb3VyY2UnLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ251bWJlcidcclxuICAgICAgfVxyXG4gICAgfSxcclxuICAgIGRlc3Ryb3lUaW1lb3V0OiB7XHJcbiAgICAgIHZhbHVlOiA1MDAwLFxyXG4gICAgICB0eXBlczogWydudW1iZXInXSxcclxuICAgICAgZW52TGluazogJ1BPT0xfREVTVFJPWV9USU1FT1VUJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdUaW1lb3V0IGluIG1pbGxpc2Vjb25kcyBmb3IgZGVzdHJveWluZyBhIHJlc291cmNlJyxcclxuICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgIHR5cGU6ICdudW1iZXInXHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICBpZGxlVGltZW91dDoge1xyXG4gICAgICB2YWx1ZTogMzAwMDAsXHJcbiAgICAgIHR5cGVzOiBbJ251bWJlciddLFxyXG4gICAgICBlbnZMaW5rOiAnUE9PTF9JRExFX1RJTUVPVVQnLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ1RpbWVvdXQgaW4gbWlsbGlzZWNvbmRzIGZvciBkZXN0cm95aW5nIGlkbGUgcmVzb3VyY2VzJyxcclxuICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgIHR5cGU6ICdudW1iZXInXHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICBjcmVhdGVSZXRyeUludGVydmFsOiB7XHJcbiAgICAgIHZhbHVlOiAyMDAsXHJcbiAgICAgIHR5cGVzOiBbJ251bWJlciddLFxyXG4gICAgICBlbnZMaW5rOiAnUE9PTF9DUkVBVEVfUkVUUllfSU5URVJWQUwnLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnSW50ZXJ2YWwgaW4gbWlsbGlzZWNvbmRzIGJlZm9yZSByZXRyeWluZyByZXNvdXJjZSBjcmVhdGlvbiBvbiBmYWlsdXJlJyxcclxuICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgIHR5cGU6ICdudW1iZXInXHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICByZWFwZXJJbnRlcnZhbDoge1xyXG4gICAgICB2YWx1ZTogMTAwMCxcclxuICAgICAgdHlwZXM6IFsnbnVtYmVyJ10sXHJcbiAgICAgIGVudkxpbms6ICdQT09MX1JFQVBFUl9JTlRFUlZBTCcsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdJbnRlcnZhbCBpbiBtaWxsaXNlY29uZHMgdG8gY2hlY2sgYW5kIGRlc3Ryb3kgaWRsZSByZXNvdXJjZXMnLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ251bWJlcidcclxuICAgICAgfVxyXG4gICAgfSxcclxuICAgIGJlbmNobWFya2luZzoge1xyXG4gICAgICB2YWx1ZTogZmFsc2UsXHJcbiAgICAgIHR5cGVzOiBbJ2Jvb2xlYW4nXSxcclxuICAgICAgZW52TGluazogJ1BPT0xfQkVOQ0hNQVJLSU5HJyxcclxuICAgICAgY2xpTmFtZTogJ3Bvb2xCZW5jaG1hcmtpbmcnLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ1Nob3dzIHN0YXRpc3RpY3MgZm9yIHRoZSBwb29sIG9mIHJlc291cmNlcycsXHJcbiAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICB0eXBlOiAndG9nZ2xlJ1xyXG4gICAgICB9XHJcbiAgICB9XHJcbiAgfSxcclxuICBsb2dnaW5nOiB7XHJcbiAgICBsZXZlbDoge1xyXG4gICAgICB2YWx1ZTogNCxcclxuICAgICAgdHlwZXM6IFsnbnVtYmVyJ10sXHJcbiAgICAgIGVudkxpbms6ICdMT0dHSU5HX0xFVkVMJyxcclxuICAgICAgY2xpTmFtZTogJ2xvZ0xldmVsJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdMb2dnaW5nIHZlcmJvc2l0eSBsZXZlbCcsXHJcbiAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgICByb3VuZDogMCxcclxuICAgICAgICBtaW46IDAsXHJcbiAgICAgICAgbWF4OiA1XHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICBmaWxlOiB7XHJcbiAgICAgIHZhbHVlOiAnaGlnaGNoYXJ0cy1leHBvcnQtc2VydmVyLmxvZycsXHJcbiAgICAgIHR5cGVzOiBbJ3N0cmluZyddLFxyXG4gICAgICBlbnZMaW5rOiAnTE9HR0lOR19GSUxFJyxcclxuICAgICAgY2xpTmFtZTogJ2xvZ0ZpbGUnLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnTG9nIGZpbGUgbmFtZS4gUmVxdWlyZXMgYGxvZ1RvRmlsZWAgYW5kIGBsb2dEZXN0YCB0byBiZSBzZXQnLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ3RleHQnXHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICBkZXN0OiB7XHJcbiAgICAgIHZhbHVlOiAnbG9nJyxcclxuICAgICAgdHlwZXM6IFsnc3RyaW5nJ10sXHJcbiAgICAgIGVudkxpbms6ICdMT0dHSU5HX0RFU1QnLFxyXG4gICAgICBjbGlOYW1lOiAnbG9nRGVzdCcsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnUGF0aCB0byBzdG9yZSBsb2cgZmlsZXMuIFJlcXVpcmVzIGBsb2dUb0ZpbGVgIHRvIGJlIHNldCcsXHJcbiAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICB0eXBlOiAndGV4dCdcclxuICAgICAgfVxyXG4gICAgfSxcclxuICAgIHRvQ29uc29sZToge1xyXG4gICAgICB2YWx1ZTogdHJ1ZSxcclxuICAgICAgdHlwZXM6IFsnYm9vbGVhbiddLFxyXG4gICAgICBlbnZMaW5rOiAnTE9HR0lOR19UT19DT05TT0xFJyxcclxuICAgICAgY2xpTmFtZTogJ2xvZ1RvQ29uc29sZScsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnRW5hYmxlcyBvciBkaXNhYmxlcyBjb25zb2xlIGxvZ2dpbmcnLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ3RvZ2dsZSdcclxuICAgICAgfVxyXG4gICAgfSxcclxuICAgIHRvRmlsZToge1xyXG4gICAgICB2YWx1ZTogdHJ1ZSxcclxuICAgICAgdHlwZXM6IFsnYm9vbGVhbiddLFxyXG4gICAgICBlbnZMaW5rOiAnTE9HR0lOR19UT19GSUxFJyxcclxuICAgICAgY2xpTmFtZTogJ2xvZ1RvRmlsZScsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnRW5hYmxlcyBvciBkaXNhYmxlcyBsb2dnaW5nIHRvIGEgZmlsZScsXHJcbiAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICB0eXBlOiAndG9nZ2xlJ1xyXG4gICAgICB9XHJcbiAgICB9XHJcbiAgfSxcclxuICB1aToge1xyXG4gICAgZW5hYmxlOiB7XHJcbiAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgdHlwZXM6IFsnYm9vbGVhbiddLFxyXG4gICAgICBlbnZMaW5rOiAnVUlfRU5BQkxFJyxcclxuICAgICAgY2xpTmFtZTogJ2VuYWJsZVVpJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdFbmFibGVzIG9yIGRpc2FibGVzIHRoZSBVSSBmb3IgdGhlIGV4cG9ydCBzZXJ2ZXInLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ3RvZ2dsZSdcclxuICAgICAgfVxyXG4gICAgfSxcclxuICAgIHJvdXRlOiB7XHJcbiAgICAgIHZhbHVlOiAnLycsXHJcbiAgICAgIHR5cGVzOiBbJ3N0cmluZyddLFxyXG4gICAgICBlbnZMaW5rOiAnVUlfUk9VVEUnLFxyXG4gICAgICBjbGlOYW1lOiAndWlSb3V0ZScsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnVGhlIGVuZHBvaW50IHJvdXRlIGZvciB0aGUgVUknLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ3RleHQnXHJcbiAgICAgIH1cclxuICAgIH1cclxuICB9LFxyXG4gIG90aGVyOiB7XHJcbiAgICBub2RlRW52OiB7XHJcbiAgICAgIHZhbHVlOiAncHJvZHVjdGlvbicsXHJcbiAgICAgIHR5cGVzOiBbJ3N0cmluZyddLFxyXG4gICAgICBlbnZMaW5rOiAnT1RIRVJfTk9ERV9FTlYnLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ1RoZSBOb2RlLmpzIGVudmlyb25tZW50IHR5cGUnLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ3RleHQnXHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICBsaXN0ZW5Ub1Byb2Nlc3NFeGl0czoge1xyXG4gICAgICB2YWx1ZTogdHJ1ZSxcclxuICAgICAgdHlwZXM6IFsnYm9vbGVhbiddLFxyXG4gICAgICBlbnZMaW5rOiAnT1RIRVJfTElTVEVOX1RPX1BST0NFU1NfRVhJVFMnLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ1doZXRoZXIgb3Igbm90IHRvIGF0dGFjaCBwcm9jZXNzLmV4aXQgaGFuZGxlcnMnLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ3RvZ2dsZSdcclxuICAgICAgfVxyXG4gICAgfSxcclxuICAgIG5vTG9nbzoge1xyXG4gICAgICB2YWx1ZTogZmFsc2UsXHJcbiAgICAgIHR5cGVzOiBbJ2Jvb2xlYW4nXSxcclxuICAgICAgZW52TGluazogJ09USEVSX05PX0xPR08nLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ0Rpc3BsYXkgb3Igc2tpcCBwcmludGluZyB0aGUgbG9nbyBvbiBzdGFydHVwJyxcclxuICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgIHR5cGU6ICd0b2dnbGUnXHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICBoYXJkUmVzZXRQYWdlOiB7XHJcbiAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgdHlwZXM6IFsnYm9vbGVhbiddLFxyXG4gICAgICBlbnZMaW5rOiAnT1RIRVJfSEFSRF9SRVNFVF9QQUdFJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdXaGV0aGVyIG9yIG5vdCB0byByZXNldCB0aGUgcGFnZSBjb250ZW50IGVudGlyZWx5JyxcclxuICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgIHR5cGU6ICd0b2dnbGUnXHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICBicm93c2VyU2hlbGxNb2RlOiB7XHJcbiAgICAgIHZhbHVlOiB0cnVlLFxyXG4gICAgICB0eXBlczogWydib29sZWFuJ10sXHJcbiAgICAgIGVudkxpbms6ICdPVEhFUl9CUk9XU0VSX1NIRUxMX01PREUnLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ1doZXRoZXIgb3Igbm90IHRvIHNldCB0aGUgYnJvd3NlciB0byBydW4gaW4gc2hlbGwgbW9kZScsXHJcbiAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICB0eXBlOiAndG9nZ2xlJ1xyXG4gICAgICB9XHJcbiAgICB9XHJcbiAgfSxcclxuICBkZWJ1Zzoge1xyXG4gICAgZW5hYmxlOiB7XHJcbiAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgdHlwZXM6IFsnYm9vbGVhbiddLFxyXG4gICAgICBlbnZMaW5rOiAnREVCVUdfRU5BQkxFJyxcclxuICAgICAgY2xpTmFtZTogJ2VuYWJsZURlYnVnJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdFbmFibGVzIG9yIGRpc2FibGVzIGRlYnVnIG1vZGUgZm9yIHRoZSB1bmRlcmx5aW5nIGJyb3dzZXInLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ3RvZ2dsZSdcclxuICAgICAgfVxyXG4gICAgfSxcclxuICAgIGhlYWRsZXNzOiB7XHJcbiAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgdHlwZXM6IFsnYm9vbGVhbiddLFxyXG4gICAgICBlbnZMaW5rOiAnREVCVUdfSEVBRExFU1MnLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnV2hldGhlciBvciBub3QgdG8gc2V0IHRoZSBicm93c2VyIHRvIHJ1biBpbiBoZWFkbGVzcyBtb2RlIGR1cmluZyBkZWJ1Z2dpbmcnLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ3RvZ2dsZSdcclxuICAgICAgfVxyXG4gICAgfSxcclxuICAgIGRldnRvb2xzOiB7XHJcbiAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgdHlwZXM6IFsnYm9vbGVhbiddLFxyXG4gICAgICBlbnZMaW5rOiAnREVCVUdfREVWVE9PTFMnLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ0VuYWJsZXMgb3IgZGlzYWJsZXMgRGV2VG9vbHMgaW4gaGVhZGZ1bCBtb2RlJyxcclxuICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgIHR5cGU6ICd0b2dnbGUnXHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICBsaXN0ZW5Ub0NvbnNvbGU6IHtcclxuICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICB0eXBlczogWydib29sZWFuJ10sXHJcbiAgICAgIGVudkxpbms6ICdERUJVR19MSVNURU5fVE9fQ09OU09MRScsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdFbmFibGVzIG9yIGRpc2FibGVzIGxpc3RlbmluZyB0byBjb25zb2xlIG1lc3NhZ2VzIGZyb20gdGhlIGJyb3dzZXInLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ3RvZ2dsZSdcclxuICAgICAgfVxyXG4gICAgfSxcclxuICAgIGR1bXBpbzoge1xyXG4gICAgICB2YWx1ZTogZmFsc2UsXHJcbiAgICAgIHR5cGVzOiBbJ2Jvb2xlYW4nXSxcclxuICAgICAgZW52TGluazogJ0RFQlVHX0RVTVBJTycsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdSZWRpcmVjdHMgb3Igbm90IGJyb3dzZXIgc3Rkb3V0IGFuZCBzdGRlcnIgdG8gcHJvY2Vzcy5zdGRvdXQgYW5kIHByb2Nlc3Muc3RkZXJyJyxcclxuICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgIHR5cGU6ICd0b2dnbGUnXHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICBzbG93TW86IHtcclxuICAgICAgdmFsdWU6IDAsXHJcbiAgICAgIHR5cGVzOiBbJ251bWJlciddLFxyXG4gICAgICBlbnZMaW5rOiAnREVCVUdfU0xPV19NTycsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnRGVsYXlzIFB1cHBldGVlciBvcGVyYXRpb25zIGJ5IHRoZSBzcGVjaWZpZWQgbWlsbGlzZWNvbmRzJyxcclxuICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgIHR5cGU6ICdudW1iZXInXHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICBkZWJ1Z2dpbmdQb3J0OiB7XHJcbiAgICAgIHZhbHVlOiA5MjIyLFxyXG4gICAgICB0eXBlczogWydudW1iZXInXSxcclxuICAgICAgZW52TGluazogJ0RFQlVHX0RFQlVHR0lOR19QT1JUJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdQb3J0IHVzZWQgZm9yIGRlYnVnZ2luZycsXHJcbiAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICB0eXBlOiAnbnVtYmVyJ1xyXG4gICAgICB9XHJcbiAgICB9XHJcbiAgfVxyXG59O1xyXG5cclxuLy8gUHJvcGVydGllcyBuZXN0aW5nIGxldmVsIG9mIGFsbCBvcHRpb25zXHJcbmV4cG9ydCBjb25zdCBuZXN0ZWRQcm9wcyA9IF9jcmVhdGVOZXN0ZWRQcm9wcyhkZWZhdWx0Q29uZmlnKTtcclxuXHJcbi8vIFByb3BlcnRpZXMgbmFtZXMgdGhhdCBzaG91bGQgbm90IGJlIHJlY3Vyc2l2ZWx5IG1lcmdlZFxyXG5leHBvcnQgY29uc3QgYWJzb2x1dGVQcm9wcyA9IF9jcmVhdGVBYnNvbHV0ZVByb3BzKGRlZmF1bHRDb25maWcpO1xyXG5cclxuLyoqXHJcbiAqIFJlY3Vyc2l2ZWx5IGdlbmVyYXRlcyBhIG1hcHBpbmcgb2YgbmVzdGVkIGFyZ3VtZW50IGNoYWlucyBmcm9tIGEgbmVzdGVkXHJcbiAqIGNvbmZpZyBvYmplY3QuIFRoaXMgZnVuY3Rpb24gdHJhdmVyc2VzIGEgbmVzdGVkIG9iamVjdCBhbmQgY3JlYXRlcyBhIG1hcHBpbmdcclxuICogd2hlcmUgZWFjaCBrZXkgaXMgYW4gYXJndW1lbnQgbmFtZSAoZWl0aGVyIGZyb20gYGNsaU5hbWVgLCBgbGVnYWN5TmFtZWAsXHJcbiAqIG9yIHRoZSBvcmlnaW5hbCBrZXkpIGFuZCBlYWNoIHZhbHVlIGlzIGEgc3RyaW5nIHJlcHJlc2VudGluZyB0aGUgY2hhaW5cclxuICogb2YgbmVzdGVkIHByb3BlcnRpZXMgbGVhZGluZyB0byB0aGF0IGFyZ3VtZW50LlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gX2NyZWF0ZU5lc3RlZFByb3BzXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBjb25maWcgLSBUaGUgY29uZmlndXJhdGlvbiBvYmplY3QuXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBbbmVzdGVkUHJvcHM9e31dIC0gVGhlIGFjY3VtdWxhdG9yIG9iamVjdCBmb3Igc3RvcmluZ1xyXG4gKiB0aGUgcmVzdWx0aW5nIGFyZ3VtZW50cyBjaGFpbnMuICBUaGUgZGVmYXVsdCB2YWx1ZSBpcyBhbiBlbXB0eSBvYmplY3QuXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSBbcHJvcENoYWluPScnXSAtIFRoZSBjdXJyZW50IGNoYWluIG9mIG5lc3RlZCBwcm9wZXJ0aWVzLFxyXG4gKiB1c2VkIGludGVybmFsbHkgZHVyaW5nIHJlY3Vyc2lvbi4gIFRoZSBkZWZhdWx0IHZhbHVlIGlzIGFuIGVtcHR5IHN0cmluZy5cclxuICpcclxuICogQHJldHVybnMge09iamVjdH0gQW4gb2JqZWN0IG1hcHBpbmcgYXJndW1lbnQgbmFtZXMgdG8gdGhlaXIgY29ycmVzcG9uZGluZ1xyXG4gKiBuZXN0ZWQgcHJvcGVydHkgY2hhaW5zLlxyXG4gKi9cclxuZnVuY3Rpb24gX2NyZWF0ZU5lc3RlZFByb3BzKGNvbmZpZywgbmVzdGVkUHJvcHMgPSB7fSwgcHJvcENoYWluID0gJycpIHtcclxuICBPYmplY3Qua2V5cyhjb25maWcpLmZvckVhY2goKGtleSkgPT4ge1xyXG4gICAgLy8gR2V0IHRoZSBzcGVjaWZpYyBzZWN0aW9uXHJcbiAgICBjb25zdCBlbnRyeSA9IGNvbmZpZ1trZXldO1xyXG5cclxuICAgIC8vIENoZWNrIGlmIHRoZXJlIGlzIHN0aWxsIG1vcmUgZGVwdGggdG8gdHJhdmVyc2VcclxuICAgIGlmICh0eXBlb2YgZW50cnkudmFsdWUgPT09ICd1bmRlZmluZWQnKSB7XHJcbiAgICAgIC8vIFJlY3Vyc2UgaW50byBkZWVwZXIgbGV2ZWxzIG9mIG5lc3RlZCBhcmd1bWVudHNcclxuICAgICAgX2NyZWF0ZU5lc3RlZFByb3BzKGVudHJ5LCBuZXN0ZWRQcm9wcywgYCR7cHJvcENoYWlufS4ke2tleX1gKTtcclxuICAgIH0gZWxzZSB7XHJcbiAgICAgIC8vIENyZWF0ZSB0aGUgY2hhaW4gb2YgbmVzdGVkIGFyZ3VtZW50c1xyXG4gICAgICBuZXN0ZWRQcm9wc1tlbnRyeS5jbGlOYW1lIHx8IGtleV0gPSBgJHtwcm9wQ2hhaW59LiR7a2V5fWAuc3Vic3RyaW5nKDEpO1xyXG5cclxuICAgICAgLy8gU3VwcG9ydCBmb3IgdGhlIGxlZ2FjeSwgUGhhbnRvbUpTIHByb3BlcnRpZXMgbmFtZXNcclxuICAgICAgaWYgKGVudHJ5LmxlZ2FjeU5hbWUgIT09IHVuZGVmaW5lZCkge1xyXG4gICAgICAgIG5lc3RlZFByb3BzW2VudHJ5LmxlZ2FjeU5hbWVdID0gYCR7cHJvcENoYWlufS4ke2tleX1gLnN1YnN0cmluZygxKTtcclxuICAgICAgfVxyXG4gICAgfVxyXG4gIH0pO1xyXG5cclxuICAvLyBSZXR1cm4gdGhlIG9iamVjdCB3aXRoIG5lc3RlZCBhcmd1bWVudCBjaGFpbnNcclxuICByZXR1cm4gbmVzdGVkUHJvcHM7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBSZWN1cnNpdmVseSBnYXRoZXJzIHRoZSBuYW1lcyBvZiBwcm9wZXJ0aWVzIGZyb20gYSBjb25maWd1cmF0aW9uIG9iamVjdCB0aGF0XHJcbiAqIGNhbiBiZSB0cmVhdGVkIGFzIGFic29sdXRlIHByb3BlcnRpZXMuIFRoZXNlIHByb3BlcnRpZXMgaGF2ZSB2YWx1ZXMgdGhhdFxyXG4gKiBhcmUgb2JqZWN0cyBhbmQgZG8gbm90IGNvbnRhaW4gZnVydGhlciBuZXN0ZWQgZGVwdGggd2hlbiBtZXJnaW5nIGFuIG9iamVjdFxyXG4gKiBjb250YWluaW5nIHRoZXNlIG9wdGlvbnMuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBfY3JlYXRlQWJzb2x1dGVQcm9wc1xyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gY29uZmlnIC0gVGhlIGNvbmZpZ3VyYXRpb24gb2JqZWN0LlxyXG4gKiBAcGFyYW0ge0FycmF5LjxzdHJpbmc+fSBbYWJzb2x1dGVQcm9wcz1bXV0gLSBBbiBhcnJheSB0byBjb2xsZWN0IHRoZSBuYW1lc1xyXG4gKiBvZiBhYnNvbHV0ZSBwcm9wZXJ0aWVzLiBUaGUgZGVmYXVsdCB2YWx1ZSBpcyBhbiBlbXB0eSBhcnJheS5cclxuICpcclxuICogQHJldHVybnMge0FycmF5LjxzdHJpbmc+fSBBbiBhcnJheSBjb250YWluaW5nIHRoZSBuYW1lcyBvZiBhYnNvbHV0ZVxyXG4gKiBwcm9wZXJ0aWVzLlxyXG4gKi9cclxuZnVuY3Rpb24gX2NyZWF0ZUFic29sdXRlUHJvcHMoY29uZmlnLCBhYnNvbHV0ZVByb3BzID0gW10pIHtcclxuICBPYmplY3Qua2V5cyhjb25maWcpLmZvckVhY2goKGtleSkgPT4ge1xyXG4gICAgLy8gR2V0IHRoZSBzcGVjaWZpYyBzZWN0aW9uXHJcbiAgICBjb25zdCBlbnRyeSA9IGNvbmZpZ1trZXldO1xyXG5cclxuICAgIC8vIENoZWNrIGlmIHRoZXJlIGlzIHN0aWxsIG1vcmUgZGVwdGggdG8gdHJhdmVyc2VcclxuICAgIGlmICh0eXBlb2YgZW50cnkudHlwZXMgPT09ICd1bmRlZmluZWQnKSB7XHJcbiAgICAgIC8vIFJlY3Vyc2UgaW50byBkZWVwZXIgbGV2ZWxzXHJcbiAgICAgIF9jcmVhdGVBYnNvbHV0ZVByb3BzKGVudHJ5LCBhYnNvbHV0ZVByb3BzKTtcclxuICAgIH0gZWxzZSB7XHJcbiAgICAgIC8vIElmIHRoZSBvcHRpb24gY2FuIGJlIGFuIG9iamVjdCwgc2F2ZSBpdHMgdHlwZSBpbiB0aGUgYXJyYXlcclxuICAgICAgaWYgKGVudHJ5LnR5cGVzLmluY2x1ZGVzKCdPYmplY3QnKSkge1xyXG4gICAgICAgIGFic29sdXRlUHJvcHMucHVzaChrZXkpO1xyXG4gICAgICB9XHJcbiAgICB9XHJcbiAgfSk7XHJcblxyXG4gIC8vIFJldHVybiB0aGUgYXJyYXkgd2l0aCB0aGUgbmFtZXMgb2YgYWJzb2x1dGUgcHJvcGVydGllc1xyXG4gIHJldHVybiBhYnNvbHV0ZVByb3BzO1xyXG59XHJcblxyXG5leHBvcnQgZGVmYXVsdCB7XHJcbiAgZGVmYXVsdENvbmZpZyxcclxuICBuZXN0ZWRQcm9wcyxcclxuICBhYnNvbHV0ZVByb3BzXHJcbn07XHJcbiIsIi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXHJcblxyXG5IaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXJcclxuXHJcbkNvcHlyaWdodCAoYykgMjAxNi0yMDI1LCBIaWdoc29mdFxyXG5cclxuTGljZW5jZWQgdW5kZXIgdGhlIE1JVCBsaWNlbmNlLlxyXG5cclxuQWRkaXRpb25hbGx5IGEgdmFsaWQgSGlnaGNoYXJ0cyBsaWNlbnNlIGlzIHJlcXVpcmVkIGZvciB1c2UuXHJcblxyXG5TZWUgTElDRU5TRSBmaWxlIGluIHJvb3QgZm9yIGRldGFpbHMuXHJcblxyXG4qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xyXG5cclxuLyoqXHJcbiAqIEBvdmVydmlldyBUaGlzIGZpbGUgaXMgcmVzcG9uc2libGUgZm9yIHBhcnNpbmcgdGhlIGVudmlyb25tZW50IHZhcmlhYmxlc1xyXG4gKiB3aXRoIHRoZSAnem9kJyBsaWJyYXJ5LiBUaGUgcGFyc2VkIGVudmlyb25tZW50IHZhcmlhYmxlcyBhcmUgdGhlbiBleHBvcnRlZFxyXG4gKiB0byBiZSB1c2VkIGluIHRoZSBhcHBsaWNhdGlvbiBhcyBgZW52c2AuIFdlIHNob3VsZCBub3QgdXNlIHRoZSBgcHJvY2Vzcy5lbnZgXHJcbiAqIGRpcmVjdGx5IGluIHRoZSBhcHBsaWNhdGlvbiBhcyB0aGVzZSB3b3VsZCBub3QgYmUgcGFyc2VkIHByb3Blcmx5LlxyXG4gKlxyXG4gKiBUaGUgZW52aXJvbm1lbnQgdmFyaWFibGVzIGFyZSBwYXJzZWQgYW5kIHZhbGlkYXRlZCBvbmx5IG9uY2Ugd2hlblxyXG4gKiB0aGUgYXBwbGljYXRpb24gc3RhcnRzLiBXZSBzaG91bGQgd3JpdGUgYSBjdXN0b20gdmFsaWRhdG9yIG9yIGEgdHJhbnNmb3JtZXJcclxuICogZm9yIGVhY2ggb2YgdGhlIG9wdGlvbnMuXHJcbiAqL1xyXG5cclxuaW1wb3J0IGRvdGVudiBmcm9tICdkb3RlbnYnO1xyXG5pbXBvcnQgeyB6IH0gZnJvbSAnem9kJztcclxuXHJcbmltcG9ydCB7IGRlZmF1bHRDb25maWcgfSBmcm9tICcuL3NjaGVtYXMvY29uZmlnLmpzJztcclxuXHJcbi8vIExvYWQgLmVudiBpbnRvIGVudmlyb25tZW50IHZhcmlhYmxlc1xyXG5kb3RlbnYuY29uZmlnKCk7XHJcblxyXG4vLyBPYmplY3Qgd2l0aCBjdXN0b20gdmFsaWRhdG9ycyBhbmQgdHJhbnNmb3JtZXJzLCB0byBhdm9pZCByZXBldGl0aW9uXHJcbi8vIGluIHRoZSBDb25maWcgb2JqZWN0XHJcbmNvbnN0IHYgPSB7XHJcbiAgLy8gU3BsaXRzIHN0cmluZyB2YWx1ZSBpbnRvIGVsZW1lbnRzIGluIGFuIGFycmF5LCB0cmltcyBldmVyeSBlbGVtZW50LCBjaGVja3NcclxuICAvLyBpZiBhbiBhcnJheSBpcyBjb3JyZWN0LCBpZiBpdCBpcyBlbXB0eSwgYW5kIGlmIGl0IGlzLCByZXR1cm5zIHVuZGVmaW5lZFxyXG4gIGFycmF5OiAoZmlsdGVyQXJyYXkpID0+XHJcbiAgICB6XHJcbiAgICAgIC5zdHJpbmcoKVxyXG4gICAgICAudHJhbnNmb3JtKCh2YWx1ZSkgPT5cclxuICAgICAgICB2YWx1ZVxyXG4gICAgICAgICAgLnNwbGl0KCcsJylcclxuICAgICAgICAgIC5tYXAoKHZhbHVlKSA9PiB2YWx1ZS50cmltKCkpXHJcbiAgICAgICAgICAuZmlsdGVyKCh2YWx1ZSkgPT4gZmlsdGVyQXJyYXkuaW5jbHVkZXModmFsdWUpKVxyXG4gICAgICApXHJcbiAgICAgIC50cmFuc2Zvcm0oKHZhbHVlKSA9PiAodmFsdWUubGVuZ3RoID8gdmFsdWUgOiB1bmRlZmluZWQpKSxcclxuXHJcbiAgLy8gQWxsb3dzIG9ubHkgdHJ1ZSwgZmFsc2UgYW5kIGNvcnJlY3RseSBwYXJzZSB0aGUgdmFsdWUgdG8gYm9vbGVhblxyXG4gIC8vIG9yIG5vIHZhbHVlIGluIHdoaWNoIGNhc2UgdGhlIHJldHVybmVkIHZhbHVlIHdpbGwgYmUgdW5kZWZpbmVkXHJcbiAgYm9vbGVhbjogKCkgPT5cclxuICAgIHpcclxuICAgICAgLmVudW0oWyd0cnVlJywgJ2ZhbHNlJywgJyddKVxyXG4gICAgICAudHJhbnNmb3JtKCh2YWx1ZSkgPT4gKHZhbHVlICE9PSAnJyA/IHZhbHVlID09PSAndHJ1ZScgOiB1bmRlZmluZWQpKSxcclxuXHJcbiAgLy8gQWxsb3dzIHBhc3NlZCB2YWx1ZXMgb3Igbm8gdmFsdWUgaW4gd2hpY2ggY2FzZSB0aGUgcmV0dXJuZWQgdmFsdWUgd2lsbFxyXG4gIC8vIGJlIHVuZGVmaW5lZFxyXG4gIGVudW06ICh2YWx1ZXMpID0+XHJcbiAgICB6XHJcbiAgICAgIC5lbnVtKFsuLi52YWx1ZXMsICcnXSlcclxuICAgICAgLnRyYW5zZm9ybSgodmFsdWUpID0+ICh2YWx1ZSAhPT0gJycgPyB2YWx1ZSA6IHVuZGVmaW5lZCkpLFxyXG5cclxuICAvLyBUcmltcyB0aGUgc3RyaW5nIHZhbHVlIGFuZCBjaGVja3MgaWYgaXQgaXMgZW1wdHkgb3IgY29udGFpbnMgc3RyaW5naWZpZWRcclxuICAvLyB2YWx1ZXMgc3VjaCBhcyBmYWxzZSwgdW5kZWZpbmVkLCBudWxsLCBOYU4sIGlmIGl0IGRvZXMsIHJldHVybnMgdW5kZWZpbmVkXHJcbiAgc3RyaW5nOiAoKSA9PlxyXG4gICAgelxyXG4gICAgICAuc3RyaW5nKClcclxuICAgICAgLnRyaW0oKVxyXG4gICAgICAucmVmaW5lKFxyXG4gICAgICAgICh2YWx1ZSkgPT5cclxuICAgICAgICAgICFbJ2ZhbHNlJywgJ3VuZGVmaW5lZCcsICdudWxsJywgJ05hTiddLmluY2x1ZGVzKHZhbHVlKSB8fFxyXG4gICAgICAgICAgdmFsdWUgPT09ICcnLFxyXG4gICAgICAgICh2YWx1ZSkgPT4gKHtcclxuICAgICAgICAgIG1lc3NhZ2U6IGBUaGUgc3RyaW5nIGNvbnRhaW5zIGZvcmJpZGRlbiB2YWx1ZXMsIHJlY2VpdmVkICcke3ZhbHVlfSdgXHJcbiAgICAgICAgfSlcclxuICAgICAgKVxyXG4gICAgICAudHJhbnNmb3JtKCh2YWx1ZSkgPT4gKHZhbHVlICE9PSAnJyA/IHZhbHVlIDogdW5kZWZpbmVkKSksXHJcblxyXG4gIC8vIEFsbG93cyBwb3NpdGl2ZSBudW1iZXJzIG9yIG5vIHZhbHVlIGluIHdoaWNoIGNhc2UgdGhlIHJldHVybmVkIHZhbHVlIHdpbGxcclxuICAvLyBiZSB1bmRlZmluZWRcclxuICBwb3NpdGl2ZU51bTogKCkgPT5cclxuICAgIHpcclxuICAgICAgLnN0cmluZygpXHJcbiAgICAgIC50cmltKClcclxuICAgICAgLnJlZmluZShcclxuICAgICAgICAodmFsdWUpID0+XHJcbiAgICAgICAgICB2YWx1ZSA9PT0gJycgfHwgKCFpc05hTihwYXJzZUZsb2F0KHZhbHVlKSkgJiYgcGFyc2VGbG9hdCh2YWx1ZSkgPiAwKSxcclxuICAgICAgICAodmFsdWUpID0+ICh7XHJcbiAgICAgICAgICBtZXNzYWdlOiBgVGhlIHZhbHVlIG11c3QgYmUgbnVtZXJpYyBhbmQgcG9zaXRpdmUsIHJlY2VpdmVkICcke3ZhbHVlfSdgXHJcbiAgICAgICAgfSlcclxuICAgICAgKVxyXG4gICAgICAudHJhbnNmb3JtKCh2YWx1ZSkgPT4gKHZhbHVlICE9PSAnJyA/IHBhcnNlRmxvYXQodmFsdWUpIDogdW5kZWZpbmVkKSksXHJcblxyXG4gIC8vIEFsbG93cyBub24tbmVnYXRpdmUgbnVtYmVycyBvciBubyB2YWx1ZSBpbiB3aGljaCBjYXNlIHRoZSByZXR1cm5lZCB2YWx1ZVxyXG4gIC8vIHdpbGwgYmUgdW5kZWZpbmVkXHJcbiAgbm9uTmVnYXRpdmVOdW06ICgpID0+XHJcbiAgICB6XHJcbiAgICAgIC5zdHJpbmcoKVxyXG4gICAgICAudHJpbSgpXHJcbiAgICAgIC5yZWZpbmUoXHJcbiAgICAgICAgKHZhbHVlKSA9PlxyXG4gICAgICAgICAgdmFsdWUgPT09ICcnIHx8ICghaXNOYU4ocGFyc2VGbG9hdCh2YWx1ZSkpICYmIHBhcnNlRmxvYXQodmFsdWUpID49IDApLFxyXG4gICAgICAgICh2YWx1ZSkgPT4gKHtcclxuICAgICAgICAgIG1lc3NhZ2U6IGBUaGUgdmFsdWUgbXVzdCBiZSBudW1lcmljIGFuZCBub24tbmVnYXRpdmUsIHJlY2VpdmVkICcke3ZhbHVlfSdgXHJcbiAgICAgICAgfSlcclxuICAgICAgKVxyXG4gICAgICAudHJhbnNmb3JtKCh2YWx1ZSkgPT4gKHZhbHVlICE9PSAnJyA/IHBhcnNlRmxvYXQodmFsdWUpIDogdW5kZWZpbmVkKSlcclxufTtcclxuXHJcbmV4cG9ydCBjb25zdCBDb25maWcgPSB6Lm9iamVjdCh7XHJcbiAgLy8gcHVwcGV0ZWVyXHJcbiAgUFVQUEVURUVSX0FSR1M6IHYuc3RyaW5nKCksXHJcblxyXG4gIC8vIGhpZ2hjaGFydHNcclxuICBISUdIQ0hBUlRTX1ZFUlNJT046IHpcclxuICAgIC5zdHJpbmcoKVxyXG4gICAgLnRyaW0oKVxyXG4gICAgLnJlZmluZShcclxuICAgICAgKHZhbHVlKSA9PiAvXihsYXRlc3R8XFxkKyhcXC5cXGQrKXswLDJ9KSQvLnRlc3QodmFsdWUpIHx8IHZhbHVlID09PSAnJyxcclxuICAgICAgKHZhbHVlKSA9PiAoe1xyXG4gICAgICAgIG1lc3NhZ2U6IGBISUdIQ0hBUlRTX1ZFUlNJT04gbXVzdCBiZSAnbGF0ZXN0JywgYSBtYWpvciB2ZXJzaW9uLCBvciBpbiB0aGUgZm9ybSBYWC5ZWS5aWiwgcmVjZWl2ZWQgJyR7dmFsdWV9J2BcclxuICAgICAgfSlcclxuICAgIClcclxuICAgIC50cmFuc2Zvcm0oKHZhbHVlKSA9PiAodmFsdWUgIT09ICcnID8gdmFsdWUgOiB1bmRlZmluZWQpKSxcclxuICBISUdIQ0hBUlRTX0NETl9VUkw6IHpcclxuICAgIC5zdHJpbmcoKVxyXG4gICAgLnRyaW0oKVxyXG4gICAgLnJlZmluZShcclxuICAgICAgKHZhbHVlKSA9PlxyXG4gICAgICAgIHZhbHVlLnN0YXJ0c1dpdGgoJ2h0dHBzOi8vJykgfHxcclxuICAgICAgICB2YWx1ZS5zdGFydHNXaXRoKCdodHRwOi8vJykgfHxcclxuICAgICAgICB2YWx1ZSA9PT0gJycsXHJcbiAgICAgICh2YWx1ZSkgPT4gKHtcclxuICAgICAgICBtZXNzYWdlOiBgSW52YWxpZCB2YWx1ZSBmb3IgSElHSENIQVJUU19DRE5fVVJMLiBJdCBzaG91bGQgc3RhcnQgd2l0aCBodHRwOi8vIG9yIGh0dHBzOi8vLCByZWNlaXZlZCAnJHt2YWx1ZX0nYFxyXG4gICAgICB9KVxyXG4gICAgKVxyXG4gICAgLnRyYW5zZm9ybSgodmFsdWUpID0+ICh2YWx1ZSAhPT0gJycgPyB2YWx1ZSA6IHVuZGVmaW5lZCkpLFxyXG4gIEhJR0hDSEFSVFNfRk9SQ0VfRkVUQ0g6IHYuYm9vbGVhbigpLFxyXG4gIEhJR0hDSEFSVFNfQ0FDSEVfUEFUSDogdi5zdHJpbmcoKSxcclxuICBISUdIQ0hBUlRTX0FETUlOX1RPS0VOOiB2LnN0cmluZygpLFxyXG4gIEhJR0hDSEFSVFNfQ09SRV9TQ1JJUFRTOiB2LmFycmF5KGRlZmF1bHRDb25maWcuaGlnaGNoYXJ0cy5jb3JlU2NyaXB0cy52YWx1ZSksXHJcbiAgSElHSENIQVJUU19NT0RVTEVfU0NSSVBUUzogdi5hcnJheShcclxuICAgIGRlZmF1bHRDb25maWcuaGlnaGNoYXJ0cy5tb2R1bGVTY3JpcHRzLnZhbHVlXHJcbiAgKSxcclxuICBISUdIQ0hBUlRTX0lORElDQVRPUl9TQ1JJUFRTOiB2LmFycmF5KFxyXG4gICAgZGVmYXVsdENvbmZpZy5oaWdoY2hhcnRzLmluZGljYXRvclNjcmlwdHMudmFsdWVcclxuICApLFxyXG4gIEhJR0hDSEFSVFNfQ1VTVE9NX1NDUklQVFM6IHYuYXJyYXkoXHJcbiAgICBkZWZhdWx0Q29uZmlnLmhpZ2hjaGFydHMuY3VzdG9tU2NyaXB0cy52YWx1ZVxyXG4gICksXHJcblxyXG4gIC8vIGV4cG9ydFxyXG4gIEVYUE9SVF9JTkZJTEU6IHYuc3RyaW5nKCksXHJcbiAgRVhQT1JUX0lOU1RSOiB2LnN0cmluZygpLFxyXG4gIEVYUE9SVF9PUFRJT05TOiB2LnN0cmluZygpLFxyXG4gIEVYUE9SVF9TVkc6IHYuc3RyaW5nKCksXHJcbiAgRVhQT1JUX0JBVENIOiB2LnN0cmluZygpLFxyXG4gIEVYUE9SVF9PVVRGSUxFOiB2LnN0cmluZygpLFxyXG4gIEVYUE9SVF9UWVBFOiB2LmVudW0oWydqcGVnJywgJ3BuZycsICdwZGYnLCAnc3ZnJ10pLFxyXG4gIEVYUE9SVF9DT05TVFI6IHYuZW51bShbJ2NoYXJ0JywgJ3N0b2NrQ2hhcnQnLCAnbWFwQ2hhcnQnLCAnZ2FudHRDaGFydCddKSxcclxuICBFWFBPUlRfQjY0OiB2LmJvb2xlYW4oKSxcclxuICBFWFBPUlRfTk9fRE9XTkxPQUQ6IHYuYm9vbGVhbigpLFxyXG4gIEVYUE9SVF9IRUlHSFQ6IHYucG9zaXRpdmVOdW0oKSxcclxuICBFWFBPUlRfV0lEVEg6IHYucG9zaXRpdmVOdW0oKSxcclxuICBFWFBPUlRfU0NBTEU6IHYucG9zaXRpdmVOdW0oKSxcclxuICBFWFBPUlRfREVGQVVMVF9IRUlHSFQ6IHYucG9zaXRpdmVOdW0oKSxcclxuICBFWFBPUlRfREVGQVVMVF9XSURUSDogdi5wb3NpdGl2ZU51bSgpLFxyXG4gIEVYUE9SVF9ERUZBVUxUX1NDQUxFOiB2LnBvc2l0aXZlTnVtKCksXHJcbiAgRVhQT1JUX0dMT0JBTF9PUFRJT05TOiB2LnN0cmluZygpLFxyXG4gIEVYUE9SVF9USEVNRV9PUFRJT05TOiB2LnN0cmluZygpLFxyXG4gIEVYUE9SVF9SQVNURVJJWkFUSU9OX1RJTUVPVVQ6IHYubm9uTmVnYXRpdmVOdW0oKSxcclxuXHJcbiAgLy8gY3VzdG9tXHJcbiAgQ1VTVE9NX0xPR0lDX0FMTE9XX0NPREVfRVhFQ1VUSU9OOiB2LmJvb2xlYW4oKSxcclxuICBDVVNUT01fTE9HSUNfQUxMT1dfRklMRV9SRVNPVVJDRVM6IHYuYm9vbGVhbigpLFxyXG4gIENVU1RPTV9MT0dJQ19DVVNUT01fQ09ERTogdi5zdHJpbmcoKSxcclxuICBDVVNUT01fTE9HSUNfQ0FMTEJBQ0s6IHYuc3RyaW5nKCksXHJcbiAgQ1VTVE9NX0xPR0lDX1JFU09VUkNFUzogdi5zdHJpbmcoKSxcclxuICBDVVNUT01fTE9HSUNfTE9BRF9DT05GSUc6IHYuc3RyaW5nKCksXHJcbiAgQ1VTVE9NX0xPR0lDX0NSRUFURV9DT05GSUc6IHYuc3RyaW5nKCksXHJcblxyXG4gIC8vIHNlcnZlclxyXG4gIFNFUlZFUl9FTkFCTEU6IHYuYm9vbGVhbigpLFxyXG4gIFNFUlZFUl9IT1NUOiB2LnN0cmluZygpLFxyXG4gIFNFUlZFUl9QT1JUOiB2LnBvc2l0aXZlTnVtKCksXHJcbiAgU0VSVkVSX1VQTE9BRF9MSU1JVDogdi5wb3NpdGl2ZU51bSgpLFxyXG4gIFNFUlZFUl9CRU5DSE1BUktJTkc6IHYuYm9vbGVhbigpLFxyXG5cclxuICAvLyBzZXJ2ZXIgcHJveHlcclxuICBTRVJWRVJfUFJPWFlfSE9TVDogdi5zdHJpbmcoKSxcclxuICBTRVJWRVJfUFJPWFlfUE9SVDogdi5wb3NpdGl2ZU51bSgpLFxyXG4gIFNFUlZFUl9QUk9YWV9USU1FT1VUOiB2Lm5vbk5lZ2F0aXZlTnVtKCksXHJcblxyXG4gIC8vIHNlcnZlciByYXRlIGxpbWl0aW5nXHJcbiAgU0VSVkVSX1JBVEVfTElNSVRJTkdfRU5BQkxFOiB2LmJvb2xlYW4oKSxcclxuICBTRVJWRVJfUkFURV9MSU1JVElOR19NQVhfUkVRVUVTVFM6IHYubm9uTmVnYXRpdmVOdW0oKSxcclxuICBTRVJWRVJfUkFURV9MSU1JVElOR19XSU5ET1c6IHYubm9uTmVnYXRpdmVOdW0oKSxcclxuICBTRVJWRVJfUkFURV9MSU1JVElOR19ERUxBWTogdi5ub25OZWdhdGl2ZU51bSgpLFxyXG4gIFNFUlZFUl9SQVRFX0xJTUlUSU5HX1RSVVNUX1BST1hZOiB2LmJvb2xlYW4oKSxcclxuICBTRVJWRVJfUkFURV9MSU1JVElOR19TS0lQX0tFWTogdi5zdHJpbmcoKSxcclxuICBTRVJWRVJfUkFURV9MSU1JVElOR19TS0lQX1RPS0VOOiB2LnN0cmluZygpLFxyXG5cclxuICAvLyBzZXJ2ZXIgc3NsXHJcbiAgU0VSVkVSX1NTTF9FTkFCTEU6IHYuYm9vbGVhbigpLFxyXG4gIFNFUlZFUl9TU0xfRk9SQ0U6IHYuYm9vbGVhbigpLFxyXG4gIFNFUlZFUl9TU0xfUE9SVDogdi5wb3NpdGl2ZU51bSgpLFxyXG4gIFNFUlZFUl9TU0xfQ0VSVF9QQVRIOiB2LnN0cmluZygpLFxyXG5cclxuICAvLyBwb29sXHJcbiAgUE9PTF9NSU5fV09SS0VSUzogdi5ub25OZWdhdGl2ZU51bSgpLFxyXG4gIFBPT0xfTUFYX1dPUktFUlM6IHYubm9uTmVnYXRpdmVOdW0oKSxcclxuICBQT09MX1dPUktfTElNSVQ6IHYucG9zaXRpdmVOdW0oKSxcclxuICBQT09MX0FDUVVJUkVfVElNRU9VVDogdi5ub25OZWdhdGl2ZU51bSgpLFxyXG4gIFBPT0xfQ1JFQVRFX1RJTUVPVVQ6IHYubm9uTmVnYXRpdmVOdW0oKSxcclxuICBQT09MX0RFU1RST1lfVElNRU9VVDogdi5ub25OZWdhdGl2ZU51bSgpLFxyXG4gIFBPT0xfSURMRV9USU1FT1VUOiB2Lm5vbk5lZ2F0aXZlTnVtKCksXHJcbiAgUE9PTF9DUkVBVEVfUkVUUllfSU5URVJWQUw6IHYubm9uTmVnYXRpdmVOdW0oKSxcclxuICBQT09MX1JFQVBFUl9JTlRFUlZBTDogdi5ub25OZWdhdGl2ZU51bSgpLFxyXG4gIFBPT0xfQkVOQ0hNQVJLSU5HOiB2LmJvb2xlYW4oKSxcclxuXHJcbiAgLy8gbG9nZ2VyXHJcbiAgTE9HR0lOR19MRVZFTDogelxyXG4gICAgLnN0cmluZygpXHJcbiAgICAudHJpbSgpXHJcbiAgICAucmVmaW5lKFxyXG4gICAgICAodmFsdWUpID0+XHJcbiAgICAgICAgdmFsdWUgPT09ICcnIHx8XHJcbiAgICAgICAgKCFpc05hTihwYXJzZUZsb2F0KHZhbHVlKSkgJiZcclxuICAgICAgICAgIHBhcnNlRmxvYXQodmFsdWUpID49IDAgJiZcclxuICAgICAgICAgIHBhcnNlRmxvYXQodmFsdWUpIDw9IDUpLFxyXG4gICAgICAodmFsdWUpID0+ICh7XHJcbiAgICAgICAgbWVzc2FnZTogYEludmFsaWQgdmFsdWUgZm9yIExPR0dJTkdfTEVWRUwuIFdlIG9ubHkgYWNjZXB0IHZhbHVlcyBmcm9tIDAgdG8gNSBhcyBsb2dnaW5nIGxldmVscywgcmVjZWl2ZWQgJyR7dmFsdWV9J2BcclxuICAgICAgfSlcclxuICAgIClcclxuICAgIC50cmFuc2Zvcm0oKHZhbHVlKSA9PiAodmFsdWUgIT09ICcnID8gcGFyc2VGbG9hdCh2YWx1ZSkgOiB1bmRlZmluZWQpKSxcclxuICBMT0dHSU5HX0ZJTEU6IHYuc3RyaW5nKCksXHJcbiAgTE9HR0lOR19ERVNUOiB2LnN0cmluZygpLFxyXG4gIExPR0dJTkdfVE9fQ09OU09MRTogdi5ib29sZWFuKCksXHJcbiAgTE9HR0lOR19UT19GSUxFOiB2LmJvb2xlYW4oKSxcclxuXHJcbiAgLy8gdWlcclxuICBVSV9FTkFCTEU6IHYuYm9vbGVhbigpLFxyXG4gIFVJX1JPVVRFOiB2LnN0cmluZygpLFxyXG5cclxuICAvLyBvdGhlclxyXG4gIE9USEVSX05PREVfRU5WOiB2LmVudW0oWydkZXZlbG9wbWVudCcsICdwcm9kdWN0aW9uJywgJ3Rlc3QnXSksXHJcbiAgT1RIRVJfTElTVEVOX1RPX1BST0NFU1NfRVhJVFM6IHYuYm9vbGVhbigpLFxyXG4gIE9USEVSX05PX0xPR086IHYuYm9vbGVhbigpLFxyXG4gIE9USEVSX0hBUkRfUkVTRVRfUEFHRTogdi5ib29sZWFuKCksXHJcbiAgT1RIRVJfQlJPV1NFUl9TSEVMTF9NT0RFOiB2LmJvb2xlYW4oKSxcclxuXHJcbiAgLy8gZGVidWdnZXJcclxuICBERUJVR19FTkFCTEU6IHYuYm9vbGVhbigpLFxyXG4gIERFQlVHX0hFQURMRVNTOiB2LmJvb2xlYW4oKSxcclxuICBERUJVR19ERVZUT09MUzogdi5ib29sZWFuKCksXHJcbiAgREVCVUdfTElTVEVOX1RPX0NPTlNPTEU6IHYuYm9vbGVhbigpLFxyXG4gIERFQlVHX0RVTVBJTzogdi5ib29sZWFuKCksXHJcbiAgREVCVUdfU0xPV19NTzogdi5ub25OZWdhdGl2ZU51bSgpLFxyXG4gIERFQlVHX0RFQlVHR0lOR19QT1JUOiB2LnBvc2l0aXZlTnVtKClcclxufSk7XHJcblxyXG5leHBvcnQgY29uc3QgZW52cyA9IENvbmZpZy5wYXJ0aWFsKCkucGFyc2UocHJvY2Vzcy5lbnYpO1xyXG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxyXG5cclxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXHJcblxyXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNSwgSGlnaHNvZnRcclxuXHJcbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cclxuXHJcbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxyXG5cclxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxyXG5cclxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cclxuXHJcbi8qKlxyXG4gKiBAb3ZlcnZpZXcgTWFuYWdlcyBjb25maWd1cmF0aW9uIGZvciB0aGUgSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyIGJ5IGxvYWRpbmdcclxuICogYW5kIG1lcmdpbmcgb3B0aW9ucyBmcm9tIG11bHRpcGxlIHNvdXJjZXMsIHN1Y2ggYXMgZGVmYXVsdCBzZXR0aW5ncyxcclxuICogZW52aXJvbm1lbnQgdmFyaWFibGVzLCB1c2VyLXByb3ZpZGVkIG9wdGlvbnMsIGFuZCBjb21tYW5kLWxpbmUgYXJndW1lbnRzLlxyXG4gKiBFbnN1cmVzIHRoZSBnbG9iYWwgb3B0aW9ucyBhcmUgdXAtdG8tZGF0ZSB3aXRoIHRoZSBoaWdoZXN0IHByaW9yaXR5IHZhbHVlcy5cclxuICogUHJvdmlkZXMgZnVuY3Rpb25zIGZvciBhY2Nlc3NpbmcgYW5kIHVwZGF0aW5nIGNvbmZpZ3VyYXRpb24uXHJcbiAqL1xyXG5cclxuaW1wb3J0IHsgcmVhZEZpbGVTeW5jIH0gZnJvbSAnZnMnO1xyXG5pbXBvcnQgeyBqb2luIH0gZnJvbSAncGF0aCc7XHJcblxyXG5pbXBvcnQgeyBsb2csIGxvZ1dpdGhTdGFjayB9IGZyb20gJy4vbG9nZ2VyLmpzJztcclxuaW1wb3J0IHsgZW52cyB9IGZyb20gJy4vZW52cy5qcyc7XHJcbmltcG9ydCB7IF9fZGlybmFtZSwgaXNPYmplY3QsIGRlZXBDb3B5LCBnZXRBYnNvbHV0ZVBhdGggfSBmcm9tICcuL3V0aWxzLmpzJztcclxuaW1wb3J0IHsgZGVmYXVsdENvbmZpZywgbmVzdGVkUHJvcHMsIGFic29sdXRlUHJvcHMgfSBmcm9tICcuL3NjaGVtYXMvY29uZmlnLmpzJztcclxuXHJcbi8vIFNldHMgdGhlIGdsb2JhbCBvcHRpb25zIHdpdGggaW5pdGlhbCB2YWx1ZXMgZnJvbSB0aGUgZGVmYXVsdCBjb25maWdcclxuY29uc3QgZ2xvYmFsT3B0aW9ucyA9IF9pbml0R2xvYmFsT3B0aW9ucyhkZWZhdWx0Q29uZmlnKTtcclxuXHJcbi8qKlxyXG4gKiBHZXRzIHRoZSByZWZlcmVuY2UgdG8gdGhlIGdsb2JhbCBvcHRpb25zIG9mIHRoZSBzZXJ2ZXIgaW5zdGFuY2Ugb2JqZWN0XHJcbiAqIG9yIGl0cyBjb3B5LlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gZ2V0T3B0aW9uc1xyXG4gKlxyXG4gKiBAcGFyYW0ge2Jvb2xlYW59IFtnZXRSZWZlcmVuY2U9dHJ1ZV0gLSBPcHRpb25hbCBwYXJhbWV0ZXIgdG8gZGVjaWRlIHdoZXRoZXJcclxuICogdG8gcmV0dXJuIHRoZSByZWZlcmVuY2UgdG8gdGhlIGdsb2JhbCBvcHRpb25zIG9mIHRoZSBzZXJ2ZXIgaW5zdGFuY2Ugb2JqZWN0XHJcbiAqIG9yIHJldHVybiBhIGNvcHkgb2YgaXQuIFRoZSBkZWZhdWx0IHZhbHVlIGlzIHRydWUuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtPYmplY3R9IFRoZSByZWZlcmVuY2UgdG8gdGhlIGdsb2JhbCBvcHRpb25zIG9mIHRoZSBzZXJ2ZXIgaW5zdGFuY2VcclxuICogb2JqZWN0IG9yIGl0cyBjb3B5LlxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIGdldE9wdGlvbnMoZ2V0UmVmZXJlbmNlID0gdHJ1ZSkge1xyXG4gIHJldHVybiBnZXRSZWZlcmVuY2UgPyBnbG9iYWxPcHRpb25zIDogZGVlcENvcHkoZ2xvYmFsT3B0aW9ucyk7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBTZXRzIHRoZSBnbG9iYWwgb3B0aW9ucyBvZiB0aGUgZXhwb3J0IHNlcnZlciBpbnN0YW5jZSwga2VlcGluZyB0aGUgcHJpbmNpcGxlXHJcbiAqIG9mIHRoZSBvcHRpb25zIGxvYWQgcHJpb3JpdHkgZnJvbSBhbGwgYXZhaWxhYmxlIHNvdXJjZXMuIEl0IGFjY2VwdHMgb3B0aW9uYWxcclxuICogYGN1c3RvbU9wdGlvbnNgIG9iamVjdCBhbmQgYGNsaUFyZ3NgIGFycmF5IHdpdGggYXJndW1lbnRzIGZyb20gdGhlIENMSS4gVGhlc2VcclxuICogb3B0aW9ucyB3aWxsIGJlIHZhbGlkYXRlZCBhbmQgYXBwbGllZCBpZiBwcm92aWRlZC5cclxuICpcclxuICogVGhlIHByaW9yaXR5IG9yZGVyIG9mIHNldHRpbmcgdmFsdWVzIGlzOlxyXG4gKlxyXG4gKiAxLiBPcHRpb25zIGZyb20gdGhlIGBsaWIvc2NoZW1hcy9jb25maWcuanNgIGZpbGUgKGRlZmF1bHQgdmFsdWVzKS5cclxuICogMi4gT3B0aW9ucyBmcm9tIGEgY3VzdG9tIEpTT04gZmlsZSAobG9hZGVkIGJ5IHRoZSBgbG9hZENvbmZpZ2Agb3B0aW9uKS5cclxuICogMy4gT3B0aW9ucyBmcm9tIHRoZSBlbnZpcm9ubWVudCB2YXJpYWJsZXMgKHRoZSBgLmVudmAgZmlsZSkuXHJcbiAqIDQuIE9wdGlvbnMgZnJvbSB0aGUgZmlyc3QgcGFyYW1ldGVyIChieSBkZWZhdWx0IGFuIGVtcHR5IG9iamVjdCkuXHJcbiAqIDUuIE9wdGlvbnMgZnJvbSB0aGUgQ0xJLlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gc2V0T3B0aW9uc1xyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gW2N1c3RvbU9wdGlvbnM9e31dIC0gT3B0aW9uYWwgY3VzdG9tIG9wdGlvbnMgZm9yIGFkZGl0aW9uYWxcclxuICogY29uZmlndXJhdGlvbi4gVGhlIGRlZmF1bHQgdmFsdWUgaXMgYW4gZW1wdHkgb2JqZWN0LlxyXG4gKiBAcGFyYW0ge0FycmF5LjxzdHJpbmc+fSBbY2xpQXJncz1bXV0gLSBPcHRpb25hbCBjb21tYW5kIGxpbmUgYXJndW1lbnRzXHJcbiAqIGZvciBhZGRpdGlvbmFsIGNvbmZpZ3VyYXRpb24uIFRoZSBkZWZhdWx0IHZhbHVlIGlzIGFuIGVtcHR5IGFycmF5LlxyXG4gKiBAcGFyYW0ge2Jvb2xlYW59IFttb2RpZnlHbG9iYWw9ZmFsc2VdIC0gT3B0aW9uYWwgcGFyYW1ldGVyIHRvIGRlY2lkZVxyXG4gKiB3aGV0aGVyIHRvIHVwZGF0ZSBhbmQgcmV0dXJuIHRoZSByZWZlcmVuY2UgdG8gdGhlIGdsb2JhbCBvcHRpb25zXHJcbiAqIG9mIHRoZSBzZXJ2ZXIgaW5zdGFuY2Ugb2JqZWN0IG9yIHJldHVybiBhIGNvcHkgb2YgaXQuIFRoZSBkZWZhdWx0IHZhbHVlXHJcbiAqIGlzIGZhbHNlLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7T2JqZWN0fSBUaGUgdXBkYXRlZCBnZW5lcmFsIG9wdGlvbnMgb2JqZWN0LCByZWZsZWN0aW5nIHRoZSBtZXJnZWRcclxuICogY29uZmlndXJhdGlvbiBmcm9tIGFsbCBhdmFpbGFibGUgc291cmNlcy5cclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiBzZXRPcHRpb25zKFxyXG4gIGN1c3RvbU9wdGlvbnMgPSB7fSxcclxuICBjbGlBcmdzID0gW10sXHJcbiAgbW9kaWZ5R2xvYmFsID0gZmFsc2VcclxuKSB7XHJcbiAgLy8gT2JqZWN0IGZvciBvcHRpb25zIGxvYWRlZCB2aWEgdGhlIGBsb2FkQ29uZmlnYCBvcHRpb25cclxuICBsZXQgY29uZmlnT3B0aW9ucyA9IHt9O1xyXG5cclxuICAvLyBPYmplY3QgZm9yIG9wdGlvbnMgZnJvbSB0aGUgQ0xJXHJcbiAgbGV0IGNsaU9wdGlvbnMgPSB7fTtcclxuXHJcbiAgLy8gT25seSBmb3IgdGhlIENMSSB1c2FnZVxyXG4gIGlmIChjbGlBcmdzLmxlbmd0aCkge1xyXG4gICAgLy8gR2V0IG9wdGlvbnMgZnJvbSB0aGUgY3VzdG9tIEpTT04gbG9hZGVkIHZpYSB0aGUgYGxvYWRDb25maWdgXHJcbiAgICBjb25maWdPcHRpb25zID0gX2xvYWRDb25maWdGaWxlKGNsaUFyZ3MpO1xyXG5cclxuICAgIC8vIEdldCBvcHRpb25zIGZyb20gdGhlIENMSVxyXG4gICAgY2xpT3B0aW9ucyA9IF9wYWlyQXJndW1lbnRWYWx1ZShuZXN0ZWRQcm9wcywgY2xpQXJncyk7XHJcbiAgfVxyXG5cclxuICAvLyBHZXQgdGhlIHJlZmVyZW5jZSB0byB0aGUgZ2xvYmFsIG9wdGlvbnMgb2JqZWN0IG9yIGEgY29weSBvZiB0aGUgb2JqZWN0XHJcbiAgY29uc3QgZ2VuZXJhbE9wdGlvbnMgPSBnZXRPcHRpb25zKG1vZGlmeUdsb2JhbCk7XHJcblxyXG4gIC8vIFVwZGF0ZSB2YWx1ZXMgb2YgdGhlIGdlbmVyYWwgb3B0aW9ucyB3aXRoIHZhbHVlcyBmcm9tIGVhY2ggc291cmNlIHBvc3NpYmxlXHJcbiAgX3VwZGF0ZU9wdGlvbnMoXHJcbiAgICBkZWZhdWx0Q29uZmlnLFxyXG4gICAgZ2VuZXJhbE9wdGlvbnMsXHJcbiAgICBjb25maWdPcHRpb25zLFxyXG4gICAgY3VzdG9tT3B0aW9ucyxcclxuICAgIGNsaU9wdGlvbnNcclxuICApO1xyXG5cclxuICAvLyBSZXR1cm4gb3B0aW9uc1xyXG4gIHJldHVybiBnZW5lcmFsT3B0aW9ucztcclxufVxyXG5cclxuLyoqXHJcbiAqIE1lcmdlcyB0d28gc2V0cyBvZiBjb25maWd1cmF0aW9uIG9wdGlvbnMsIGNvbnNpZGVyaW5nIGFic29sdXRlIHByb3BlcnRpZXMuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBtZXJnZU9wdGlvbnNcclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IG9yaWdpbmFsT3B0aW9ucyAtIE9yaWdpbmFsIGNvbmZpZ3VyYXRpb24gb3B0aW9ucy5cclxuICogQHBhcmFtIHtPYmplY3R9IG5ld09wdGlvbnMgLSBOZXcgY29uZmlndXJhdGlvbiBvcHRpb25zIHRvIGJlIG1lcmdlZC5cclxuICpcclxuICogQHJldHVybnMge09iamVjdH0gTWVyZ2VkIGNvbmZpZ3VyYXRpb24gb3B0aW9ucy5cclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiBtZXJnZU9wdGlvbnMob3JpZ2luYWxPcHRpb25zLCBuZXdPcHRpb25zKSB7XHJcbiAgLy8gQ2hlY2sgaWYgdGhlIGBuZXdPcHRpb25zYCBpcyBhIGNvcnJlY3Qgb2JqZWN0XHJcbiAgaWYgKGlzT2JqZWN0KG5ld09wdGlvbnMpKSB7XHJcbiAgICBmb3IgKGNvbnN0IFtrZXksIHZhbHVlXSBvZiBPYmplY3QuZW50cmllcyhuZXdPcHRpb25zKSkge1xyXG4gICAgICBvcmlnaW5hbE9wdGlvbnNba2V5XSA9XHJcbiAgICAgICAgaXNPYmplY3QodmFsdWUpICYmXHJcbiAgICAgICAgIWFic29sdXRlUHJvcHMuaW5jbHVkZXMoa2V5KSAmJlxyXG4gICAgICAgIG9yaWdpbmFsT3B0aW9uc1trZXldICE9PSB1bmRlZmluZWRcclxuICAgICAgICAgID8gbWVyZ2VPcHRpb25zKG9yaWdpbmFsT3B0aW9uc1trZXldLCB2YWx1ZSlcclxuICAgICAgICAgIDogdmFsdWUgIT09IHVuZGVmaW5lZFxyXG4gICAgICAgICAgICA/IHZhbHVlXHJcbiAgICAgICAgICAgIDogb3JpZ2luYWxPcHRpb25zW2tleV07XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICAvLyBSZXR1cm4gdGhlIHJlc3VsdCBvcHRpb25zXHJcbiAgcmV0dXJuIG9yaWdpbmFsT3B0aW9ucztcclxufVxyXG5cclxuLyoqXHJcbiAqIE1hcHMgb2xkLXN0cnVjdHVyZWQgY29uZmlndXJhdGlvbiBvcHRpb25zIChQaGFudG9tSlMpIHRvIGEgbmV3IGZvcm1hdFxyXG4gKiAoUHVwcGV0ZWVyKS4gVGhpcyBmdW5jdGlvbiBjb252ZXJ0cyBmbGF0LCBvbGQtc3RydWN0dXJlZCBvcHRpb25zIGludG9cclxuICogYSBuZXcsIG5lc3RlZCBjb25maWd1cmF0aW9uIGZvcm1hdCBiYXNlZCBvbiBhIHByZWRlZmluZWQgbWFwcGluZ1xyXG4gKiAoYG5lc3RlZFByb3BzYCkuIFRoZSBuZXcgZm9ybWF0IGlzIHVzZWQgZm9yIFB1cHBldGVlciwgd2hpbGUgdGhlIG9sZCBmb3JtYXRcclxuICogd2FzIHVzZWQgZm9yIFBoYW50b21KUy5cclxuICpcclxuICogQGZ1bmN0aW9uIG1hcFRvTmV3T3B0aW9uc1xyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gb2xkT3B0aW9ucyAtIFRoZSBvbGQsIGZsYXQgY29uZmlndXJhdGlvbiBvcHRpb25zXHJcbiAqIHRvIGJlIGNvbnZlcnRlZC5cclxuICpcclxuICogQHJldHVybnMge09iamVjdH0gQSBuZXcgb2JqZWN0IGNvbnRhaW5pbmcgb3B0aW9ucyBzdHJ1Y3R1cmVkIGFjY29yZGluZ1xyXG4gKiB0byB0aGUgbWFwcGluZyBkZWZpbmVkIGluIGBuZXN0ZWRQcm9wc2Agb3IgYW4gZW1wdHkgb2JqZWN0IGlmIHRoZSBwcm92aWRlZFxyXG4gKiBgb2xkT3B0aW9uc2AgaXMgbm90IGEgY29ycmVjdCBvYmplY3QuXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gbWFwVG9OZXdPcHRpb25zKG9sZE9wdGlvbnMpIHtcclxuICAvLyBBbiBvYmplY3QgZm9yIHRoZSBuZXcgc3RydWN0dXJlZCBvcHRpb25zXHJcbiAgY29uc3QgbmV3T3B0aW9ucyA9IHt9O1xyXG5cclxuICAvLyBDaGVjayBpZiBwcm92aWRlZCB2YWx1ZSBpcyBhIGNvcnJlY3Qgb2JqZWN0XHJcbiAgaWYgKE9iamVjdC5wcm90b3R5cGUudG9TdHJpbmcuY2FsbChvbGRPcHRpb25zKSA9PT0gJ1tvYmplY3QgT2JqZWN0XScpIHtcclxuICAgIC8vIEl0ZXJhdGUgb3ZlciBlYWNoIGtleS12YWx1ZSBwYWlyIGluIHRoZSBvbGQtc3RydWN0dXJlZCBvcHRpb25zXHJcbiAgICBmb3IgKGNvbnN0IFtrZXksIHZhbHVlXSBvZiBPYmplY3QuZW50cmllcyhvbGRPcHRpb25zKSkge1xyXG4gICAgICAvLyBJZiB0aGVyZSBpcyBhIG5lc3RlZCBtYXBwaW5nLCBzcGxpdCBpdCBpbnRvIGEgcHJvcGVydGllcyBjaGFpblxyXG4gICAgICBjb25zdCBwcm9wZXJ0aWVzQ2hhaW4gPSBuZXN0ZWRQcm9wc1trZXldXHJcbiAgICAgICAgPyBuZXN0ZWRQcm9wc1trZXldLnNwbGl0KCcuJylcclxuICAgICAgICA6IFtdO1xyXG5cclxuICAgICAgLy8gSWYgaXQgaXMgdGhlIGxhc3QgcHJvcGVydHkgaW4gdGhlIGNoYWluLCBhc3NpZ24gdGhlIHZhbHVlLCBvdGhlcndpc2UsXHJcbiAgICAgIC8vIGNyZWF0ZSBvciByZXVzZSB0aGUgbmVzdGVkIG9iamVjdFxyXG4gICAgICBwcm9wZXJ0aWVzQ2hhaW4ucmVkdWNlKFxyXG4gICAgICAgIChvYmosIHByb3AsIGluZGV4KSA9PlxyXG4gICAgICAgICAgKG9ialtwcm9wXSA9XHJcbiAgICAgICAgICAgIHByb3BlcnRpZXNDaGFpbi5sZW5ndGggLSAxID09PSBpbmRleCA/IHZhbHVlIDogb2JqW3Byb3BdIHx8IHt9KSxcclxuICAgICAgICBuZXdPcHRpb25zXHJcbiAgICAgICk7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICAvLyBSZXR1cm4gdGhlIG5ldywgc3RydWN0dXJlZCBvcHRpb25zIG9iamVjdFxyXG4gIHJldHVybiBuZXdPcHRpb25zO1xyXG59XHJcblxyXG4vKipcclxuICogVmFsaWRhdGVzLCBwYXJzZXMsIGFuZCBjaGVja3MgaWYgdGhlIHByb3ZpZGVkIGNvbmZpZyBpcyBhbGxvd2VkIHNldFxyXG4gKiBvZiBvcHRpb25zLlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gaXNBbGxvd2VkQ29uZmlnXHJcbiAqXHJcbiAqIEBwYXJhbSB7dW5rbm93bn0gY29uZmlnIC0gVGhlIGNvbmZpZyB0byBiZSB2YWxpZGF0ZWQgYW5kIHBhcnNlZCBhcyBhIHNldFxyXG4gKiBvZiBvcHRpb25zLiBNdXN0IGJlIGVpdGhlciBhbiBvYmplY3Qgb3IgYSBzdHJpbmcuXHJcbiAqIEBwYXJhbSB7Ym9vbGVhbn0gW3RvU3RyaW5nPWZhbHNlXSAtIFdoZXRoZXIgdG8gcmV0dXJuIGEgc3RyaW5naWZpZWQgdmVyc2lvblxyXG4gKiBvZiB0aGUgcGFyc2VkIGNvbmZpZy4gVGhlIGRlZmF1bHQgdmFsdWUgaXMgZmFsc2UuXHJcbiAqIEBwYXJhbSB7Ym9vbGVhbn0gW2FsbG93RnVuY3Rpb25zPWZhbHNlXSAtIFdoZXRoZXIgdG8gYWxsb3cgZnVuY3Rpb25zXHJcbiAqIGluIHRoZSBwYXJzZWQgY29uZmlnLiBJZiB0cnVlLCBmdW5jdGlvbnMgYXJlIHByZXNlcnZlZC4gT3RoZXJ3aXNlLCB3aGVuXHJcbiAqIGEgZnVuY3Rpb24gaXMgZm91bmQsIG51bGwgaXMgcmV0dXJuZWQuIFRoZSBkZWZhdWx0IHZhbHVlIGlzIGZhbHNlLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7KE9iamVjdHxzdHJpbmd8bnVsbCl9IFJldHVybnMgYSBwYXJzZWQgc2V0IG9mIG9wdGlvbnMgb2JqZWN0LFxyXG4gKiBhIHN0cmluZ2lmaWVkIHNldCBvZiBvcHRpb25zIG9iamVjdCBpZiB0aGUgYHRvU3RyaW5nYCBpcyB0cnVlLCBhbmQgbnVsbFxyXG4gKiBpZiB0aGUgY29uZmlnIGlzIG5vdCBhIHZhbGlkIHNldCBvZiBvcHRpb25zIG9yIHBhcnNpbmcgZmFpbHMuXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gaXNBbGxvd2VkQ29uZmlnKFxyXG4gIGNvbmZpZyxcclxuICB0b1N0cmluZyA9IGZhbHNlLFxyXG4gIGFsbG93RnVuY3Rpb25zID0gZmFsc2VcclxuKSB7XHJcbiAgdHJ5IHtcclxuICAgIC8vIEFjY2VwdCBvbmx5IG9iamVjdHMgYW5kIHN0cmluZ3NcclxuICAgIGlmICghaXNPYmplY3QoY29uZmlnKSAmJiB0eXBlb2YgY29uZmlnICE9PSAnc3RyaW5nJykge1xyXG4gICAgICAvLyBSZXR1cm4gbnVsbCBpZiBhbnkgb3RoZXIgdHlwZVxyXG4gICAgICByZXR1cm4gbnVsbDtcclxuICAgIH1cclxuXHJcbiAgICAvLyBHZXQgdGhlIG9iamVjdCByZXByZXNlbnRhdGlvbiBvZiB0aGUgb3JpZ2luYWwgY29uZmlnXHJcbiAgICBjb25zdCBvYmplY3RDb25maWcgPVxyXG4gICAgICB0eXBlb2YgY29uZmlnID09PSAnc3RyaW5nJ1xyXG4gICAgICAgID8gYWxsb3dGdW5jdGlvbnNcclxuICAgICAgICAgID8gZXZhbChgKCR7Y29uZmlnfSlgKVxyXG4gICAgICAgICAgOiBKU09OLnBhcnNlKGNvbmZpZylcclxuICAgICAgICA6IGNvbmZpZztcclxuXHJcbiAgICAvLyBQcmVzZXJ2ZSBvciByZW1vdmUgcG90ZW50aWFsIGZ1bmN0aW9ucyBiYXNlZCBvbiB0aGUgYGFsbG93RnVuY3Rpb25zYCBmbGFnXHJcbiAgICBjb25zdCBzdHJpbmdpZmllZE9wdGlvbnMgPSBfb3B0aW9uc1N0cmluZ2lmeShcclxuICAgICAgb2JqZWN0Q29uZmlnLFxyXG4gICAgICBhbGxvd0Z1bmN0aW9ucyxcclxuICAgICAgZmFsc2VcclxuICAgICk7XHJcblxyXG4gICAgLy8gUGFyc2UgdGhlIGNvbmZpZyB0byBjaGVjayBpZiBpdCBpcyB2YWxpZCBzZXQgb2Ygb3B0aW9uc1xyXG4gICAgY29uc3QgcGFyc2VkT3B0aW9ucyA9IGFsbG93RnVuY3Rpb25zXHJcbiAgICAgID8gSlNPTi5wYXJzZShcclxuICAgICAgICAgIF9vcHRpb25zU3RyaW5naWZ5KG9iamVjdENvbmZpZywgYWxsb3dGdW5jdGlvbnMsIHRydWUpLFxyXG4gICAgICAgICAgKF8sIHZhbHVlKSA9PlxyXG4gICAgICAgICAgICB0eXBlb2YgdmFsdWUgPT09ICdzdHJpbmcnICYmIHZhbHVlLnN0YXJ0c1dpdGgoJ2Z1bmN0aW9uJylcclxuICAgICAgICAgICAgICA/IGV2YWwoYCgke3ZhbHVlfSlgKVxyXG4gICAgICAgICAgICAgIDogdmFsdWVcclxuICAgICAgICApXHJcbiAgICAgIDogSlNPTi5wYXJzZShzdHJpbmdpZmllZE9wdGlvbnMpO1xyXG5cclxuICAgIC8vIFJldHVybiBzdHJpbmdpZmllZCBvciBvYmplY3Qgb3B0aW9ucyBiYXNlZCBvbiB0aGUgYHRvU3RyaW5nYCBmbGFnXHJcbiAgICByZXR1cm4gdG9TdHJpbmcgPyBzdHJpbmdpZmllZE9wdGlvbnMgOiBwYXJzZWRPcHRpb25zO1xyXG4gIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICAvLyBSZXR1cm4gbnVsbCBpZiBwYXJzaW5nIGZhaWxzXHJcbiAgICByZXR1cm4gbnVsbDtcclxuICB9XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBQcmludHMgdGhlIEhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlciBsb2dvLCB2ZXJzaW9uLCBhbmQgbGljZW5zZSBpbmZvcm1hdGlvbi5cclxuICpcclxuICogQGZ1bmN0aW9uIHByaW50TGljZW5zZVxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIHByaW50TGljZW5zZSgpIHtcclxuICAvLyBQcmludCB0aGUgbG9nbyBhbmQgdmVyc2lvbiBpbmZvcm1hdGlvblxyXG4gIHByaW50VmVyc2lvbigpO1xyXG5cclxuICAvLyBQcmludCB0aGUgbGljZW5zZSBpbmZvcm1hdGlvblxyXG4gIGNvbnNvbGUubG9nKFxyXG4gICAgJ1RoaXMgc29mdHdhcmUgcmVxdWlyZXMgYSB2YWxpZCBIaWdoY2hhcnRzIGxpY2Vuc2UgZm9yIGNvbW1lcmNpYWwgdXNlLlxcbidcclxuICAgICAgLnllbGxvdyxcclxuICAgICdcXG5Gb3IgYSBmdWxsIGxpc3Qgb2YgQ0xJIG9wdGlvbnMsIHR5cGU6JyxcclxuICAgICdcXG5oaWdoY2hhcnRzLWV4cG9ydC1zZXJ2ZXIgLS1oZWxwXFxuJy5ncmVlbixcclxuICAgICdcXG5JZiB5b3UgZG8gbm90IGhhdmUgYSBsaWNlbnNlLCBvbmUgY2FuIGJlIG9idGFpbmVkIGhlcmU6JyxcclxuICAgICdcXG5odHRwczovL3Nob3AuaGlnaHNvZnQuY29tL1xcbicuZ3JlZW4sXHJcbiAgICAnXFxuVG8gY3VzdG9taXplIHlvdXIgaW5zdGFsbGF0aW9uLCBwbGVhc2UgcmVmZXIgdG8gdGhlIFJFQURNRSBmaWxlIGF0OicsXHJcbiAgICAnXFxuaHR0cHM6Ly9naXRodWIuY29tL2hpZ2hjaGFydHMvbm9kZS1leHBvcnQtc2VydmVyI3JlYWRtZVxcbicuZ3JlZW5cclxuICApO1xyXG59XHJcblxyXG4vKipcclxuICogUHJpbnRzIHVzYWdlIGluZm9ybWF0aW9uIGZvciBDTEkgYXJndW1lbnRzLCBkaXNwbGF5aW5nIGF2YWlsYWJsZSBvcHRpb25zXHJcbiAqIGFuZCB0aGVpciBkZXNjcmlwdGlvbnMuIEl0IGNhbiBsaXN0IHByb3BlcnRpZXMgcmVjdXJzaXZlbHkgaWYgY2F0ZWdvcmllc1xyXG4gKiBjb250YWluIG5lc3RlZCBvcHRpb25zLlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gcHJpbnRVc2FnZVxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIHByaW50VXNhZ2UoKSB7XHJcbiAgLy8gRGlzcGxheSBSRUFETUUgYW5kIGdlbmVyYWwgdXNhZ2UgaW5mb3JtYXRpb25cclxuICBjb25zb2xlLmxvZyhcclxuICAgICdcXG5Vc2FnZSBvZiBDTEkgYXJndW1lbnRzOicuYm9sZCxcclxuICAgICdcXG4tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLScsXHJcbiAgICBgXFxuRm9yIG1vcmUgZGV0YWlsZWQgaW5mb3JtYXRpb24sIHZpc2l0IHRoZSBSRUFETUUgZmlsZSBhdDogJHsnaHR0cHM6Ly9naXRodWIuY29tL2hpZ2hjaGFydHMvbm9kZS1leHBvcnQtc2VydmVyI3JlYWRtZScuZ3JlZW59LlxcbmBcclxuICApO1xyXG5cclxuICAvLyBJdGVyYXRlIHRocm91Z2ggZWFjaCBjYXRlZ29yeSBpbiB0aGUgYGRlZmF1bHRDb25maWdgIGFuZCBkaXNwbGF5IHVzYWdlIGluZm9cclxuICBPYmplY3Qua2V5cyhkZWZhdWx0Q29uZmlnKS5mb3JFYWNoKChjYXRlZ29yeSkgPT4ge1xyXG4gICAgY29uc29sZS5sb2coYCR7Y2F0ZWdvcnkudG9VcHBlckNhc2UoKX1gLmJvbGQucmVkKTtcclxuICAgIF9jeWNsZUNhdGVnb3JpZXMoZGVmYXVsdENvbmZpZ1tjYXRlZ29yeV0pO1xyXG4gICAgY29uc29sZS5sb2coJycpO1xyXG4gIH0pO1xyXG59XHJcblxyXG4vKipcclxuICogUHJpbnRzIHRoZSBIaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXIgbG9nbyBvciB0ZXh0IHdpdGggdGhlIHZlcnNpb25cclxuICogaW5mb3JtYXRpb24uXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBwcmludFZlcnNpb25cclxuICpcclxuICogQHBhcmFtIHtib29sZWFufSBbbm9Mb2dvPWZhbHNlXSAtIElmIHRydWUsIG9ubHkgcHJpbnRzIHRleHQgd2l0aCB0aGUgdmVyc2lvblxyXG4gKiBpbmZvcm1hdGlvbiwgd2l0aG91dCB0aGUgbG9nby4gVGhlIGRlZmF1bHQgdmFsdWUgaXMgZmFsc2UuXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gcHJpbnRWZXJzaW9uKG5vTG9nbyA9IGZhbHNlKSB7XHJcbiAgLy8gR2V0IHBhY2thZ2UgdmVyc2lvbiBlaXRoZXIgZnJvbSBgLmVudmAgb3IgZnJvbSBgcGFja2FnZS5qc29uYFxyXG4gIGNvbnN0IHBhY2thZ2VWZXJzaW9uID0gSlNPTi5wYXJzZShcclxuICAgIHJlYWRGaWxlU3luYyhqb2luKF9fZGlybmFtZSwgJ3BhY2thZ2UuanNvbicpKVxyXG4gICkudmVyc2lvbjtcclxuXHJcbiAgLy8gUHJpbnQgdGV4dCBvbmx5XHJcbiAgaWYgKG5vTG9nbykge1xyXG4gICAgY29uc29sZS5sb2coYEhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlciB2JHtwYWNrYWdlVmVyc2lvbn1gKTtcclxuICB9IGVsc2Uge1xyXG4gICAgLy8gUHJpbnQgdGhlIGxvZ29cclxuICAgIGNvbnNvbGUubG9nKFxyXG4gICAgICByZWFkRmlsZVN5bmMoam9pbihfX2Rpcm5hbWUsICdtc2cnLCAnc3RhcnR1cC5tc2cnKSkudG9TdHJpbmcoKS5ib2xkXHJcbiAgICAgICAgLnllbGxvdyxcclxuICAgICAgYHYke3BhY2thZ2VWZXJzaW9ufVxcbmAuYm9sZFxyXG4gICAgKTtcclxuICB9XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBJbml0aWFsaXplcyBhbmQgcmV0dXJucyBnbG9iYWwgb3B0aW9ucyBvYmplY3QgYmFzZWQgb24gcHJvdmlkZWRcclxuICogY29uZmlndXJhdGlvbiwgc2V0dGluZyB2YWx1ZXMgZnJvbSBuZXN0ZWQgcHJvcGVydGllcyByZWN1cnNpdmVseS5cclxuICpcclxuICogQGZ1bmN0aW9uIF9pbml0R2xvYmFsT3B0aW9uc1xyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gY29uZmlnIC0gVGhlIGNvbmZpZ3VyYXRpb24gb2JqZWN0IHRvIGJlIHVzZWQgZm9yIGluaXRpYWxpemluZ1xyXG4gKiBvcHRpb25zLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7T2JqZWN0fSBJbml0aWFsaXplZCBvcHRpb25zIG9iamVjdC5cclxuICovXHJcbmZ1bmN0aW9uIF9pbml0R2xvYmFsT3B0aW9ucyhjb25maWcpIHtcclxuICBjb25zdCBvcHRpb25zID0ge307XHJcblxyXG4gIC8vIFN0YXJ0IGluaXRpYWxpemluZyB0aGUgYG9wdGlvbnNgIG9iamVjdCByZWN1cnNpdmVseVxyXG4gIGZvciAoY29uc3QgW25hbWUsIGl0ZW1dIG9mIE9iamVjdC5lbnRyaWVzKGNvbmZpZykpIHtcclxuICAgIG9wdGlvbnNbbmFtZV0gPSBPYmplY3QucHJvdG90eXBlLmhhc093blByb3BlcnR5LmNhbGwoaXRlbSwgJ3ZhbHVlJylcclxuICAgICAgPyBpdGVtLnZhbHVlXHJcbiAgICAgIDogX2luaXRHbG9iYWxPcHRpb25zKGl0ZW0pO1xyXG4gIH1cclxuXHJcbiAgLy8gUmV0dXJuIHRoZSBjcmVhdGVkIGBvcHRpb25zYCBvYmplY3RcclxuICByZXR1cm4gb3B0aW9ucztcclxufVxyXG5cclxuLyoqXHJcbiAqIFVwZGF0ZXMgb3B0aW9ucyBvYmplY3Qgd2l0aCB2YWx1ZXMgZnJvbSB2YXJpb3VzIHNvdXJjZXMsIGZvbGxvd2luZyBhIHNwZWNpZmljXHJcbiAqIHByaW9yaXRpemF0aW9uIG9yZGVyLiBUaGUgZnVuY3Rpb24gY2hlY2tzIGZvciB2YWx1ZXMgaW4gdGhlIGZvbGxvd2luZyBvcmRlclxyXG4gKiBvZiBwcmVjZWRlbmNlOiB0aGUgYGxvYWRDb25maWdgIGNvbmZpZ3VyYXRpb24gb3B0aW9ucywgZW52aXJvbm1lbnQgdmFyaWFibGVzLFxyXG4gKiBjdXN0b20gb3B0aW9ucywgYW5kIENMSSBvcHRpb25zLlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gX3VwZGF0ZU9wdGlvbnNcclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IGNvbmZpZyAtIFRoZSBjb25maWd1cmF0aW9uIG9iamVjdCwgd2hpY2ggaW5jbHVkZXMgdGhlIGluaXRpYWxcclxuICogc2V0dGluZ3MgYW5kIG1ldGFkYXRhIGZvciBlYWNoIG9wdGlvbi4gVGhpcyBvYmplY3QgaXMgdXNlZCB0byBkZXRlcm1pbmVcclxuICogdGhlIHN0cnVjdHVyZSBhbmQgZGVmYXVsdCB2YWx1ZXMgZm9yIHRoZSBvcHRpb25zLlxyXG4gKiBAcGFyYW0ge09iamVjdH0gb3B0aW9ucyAtIFRoZSBvcHRpb25zIG9iamVjdCB0aGF0IHdpbGwgYmUgdXBkYXRlZCB3aXRoIHZhbHVlc1xyXG4gKiBmcm9tIG90aGVyIHNvdXJjZXMuXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBjb25maWdPcHQgLSBUaGUgY29uZmlndXJhdGlvbiBvcHRpb25zIG9iamVjdCwgbG9hZGVkIHdpdGhcclxuICogdGhlIGBsb2FkQ29uZmlnYCBvcHRpb24sIHdoaWNoIG1heSBwcm92aWRlIHZhbHVlcyB0byBvdmVycmlkZSBkZWZhdWx0cy5cclxuICogQHBhcmFtIHtPYmplY3R9IGN1c3RvbU9wdCAtIFRoZSBjdXN0b20gb3B0aW9ucyBvYmplY3QsIHR5cGljYWxseSBjb250YWluaW5nXHJcbiAqIGFkZGl0aW9uYWwgYW5kIHVzZXItZGVmaW5lZCB2YWx1ZXMsIHdoaWNoIG1heSBvdmVycmlkZSBjb25maWd1cmF0aW9uIG9wdGlvbnMuXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBjbGlPcHQgLSBUaGUgQ0xJIG9wdGlvbnMgb2JqZWN0LCB3aGljaCBtYXkgaW5jbHVkZSB2YWx1ZXNcclxuICogcHJvdmlkZWQgdGhyb3VnaCBjb21tYW5kLWxpbmUgYXJndW1lbnRzIGFuZCBoYXMgdGhlIGhpZ2hlc3QgcHJlY2VkZW5jZSBhbW9uZ1xyXG4gKiBvcHRpb25zLlxyXG4gKi9cclxuZnVuY3Rpb24gX3VwZGF0ZU9wdGlvbnMoY29uZmlnLCBvcHRpb25zLCBjb25maWdPcHQsIGN1c3RvbU9wdCwgY2xpT3B0KSB7XHJcbiAgT2JqZWN0LmtleXMoY29uZmlnKS5mb3JFYWNoKChrZXkpID0+IHtcclxuICAgIC8vIEdldCB0aGUgY29uZmlnIGVudHJ5IG9mIGEgc3BlY2lmaWMgb3B0aW9uXHJcbiAgICBjb25zdCBlbnRyeSA9IGNvbmZpZ1trZXldO1xyXG5cclxuICAgIC8vIEdhdGhlciB2YWx1ZXMgZm9yIHRoZSBvcHRpb25zIGZyb20gZXZlcnkgcG9zc2libGUgc291cmNlLCBpZiBleGlzdHNcclxuICAgIGNvbnN0IGNvbmZpZ1ZhbCA9IGNvbmZpZ09wdCAmJiBjb25maWdPcHRba2V5XTtcclxuICAgIGNvbnN0IGN1c3RvbVZhbCA9IGN1c3RvbU9wdCAmJiBjdXN0b21PcHRba2V5XTtcclxuICAgIGNvbnN0IGNsaVZhbCA9IGNsaU9wdCAmJiBjbGlPcHRba2V5XTtcclxuXHJcbiAgICAvLyBJZiB0aGUgdmFsdWUgbm90IGZvdW5kLCBuZWVkIHRvIGdvIGRlZXBlclxyXG4gICAgaWYgKHR5cGVvZiBlbnRyeS52YWx1ZSA9PT0gJ3VuZGVmaW5lZCcpIHtcclxuICAgICAgX3VwZGF0ZU9wdGlvbnMoZW50cnksIG9wdGlvbnNba2V5XSwgY29uZmlnVmFsLCBjdXN0b21WYWwsIGNsaVZhbCk7XHJcbiAgICB9IGVsc2Uge1xyXG4gICAgICAvLyBJZiBhIHZhbHVlIGZyb20gY3VzdG9tIEpTT04gb3B0aW9ucyBleGlzdHMsIGl0IHRha2UgcHJlY2VkZW5jZVxyXG4gICAgICBpZiAoY29uZmlnVmFsICE9PSB1bmRlZmluZWQgJiYgY29uZmlnVmFsICE9PSBudWxsKSB7XHJcbiAgICAgICAgb3B0aW9uc1trZXldID0gY29uZmlnVmFsO1xyXG4gICAgICB9XHJcblxyXG4gICAgICAvLyBJZiBhIHZhbHVlIGZyb20gZW52aXJvbm1lbnQgdmFyaWFibGVzIGV4aXN0cywgaXQgdGFrZSBwcmVjZWRlbmNlXHJcbiAgICAgIGNvbnN0IGVudlZhbCA9IGVudnNbZW50cnkuZW52TGlua107XHJcbiAgICAgIGlmIChlbnRyeS5lbnZMaW5rIGluIGVudnMgJiYgZW52VmFsICE9PSB1bmRlZmluZWQgJiYgZW52VmFsICE9PSBudWxsKSB7XHJcbiAgICAgICAgb3B0aW9uc1trZXldID0gZW52VmFsO1xyXG4gICAgICB9XHJcblxyXG4gICAgICAvLyBJZiBhIHZhbHVlIGZyb20gdXNlciBvcHRpb25zIGV4aXN0cywgaXQgdGFrZSBwcmVjZWRlbmNlXHJcbiAgICAgIGlmIChjdXN0b21WYWwgIT09IHVuZGVmaW5lZCAmJiBjdXN0b21WYWwgIT09IG51bGwpIHtcclxuICAgICAgICBvcHRpb25zW2tleV0gPSBjdXN0b21WYWw7XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIC8vIElmIGEgdmFsdWUgZnJvbSBDTEkgb3B0aW9ucyBleGlzdHMsIGl0IHRha2UgcHJlY2VkZW5jZVxyXG4gICAgICBpZiAoY2xpVmFsICE9PSB1bmRlZmluZWQgJiYgY2xpVmFsICE9PSBudWxsKSB7XHJcbiAgICAgICAgb3B0aW9uc1trZXldID0gY2xpVmFsO1xyXG4gICAgICB9XHJcbiAgICB9XHJcbiAgfSk7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBDb252ZXJ0cyB0aGUgcHJvdmlkZWQgb3B0aW9ucyBvYmplY3QgdG8gYSBKU09OLWZvcm1hdHRlZCBzdHJpbmdcclxuICogd2l0aCB0aGUgb3B0aW9uIHRvIHByZXNlcnZlIGZ1bmN0aW9ucy4gSW4gb3JkZXIgZm9yIGEgZnVuY3Rpb25cclxuICogdG8gYmUgcHJlc2VydmVkLCBpdCBuZWVkcyB0byBmb2xsb3cgdGhlIGZvcm1hdCBgZnVuY3Rpb24gKC4uLikgey4uLn1gLlxyXG4gKiBTdWNoIGEgZnVuY3Rpb24gY2FuIGFsc28gYmUgc3RyaW5naWZpZWQuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBfb3B0aW9uc1N0cmluZ2lmeVxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gb3B0aW9ucyAtIFRoZSBvcHRpb25zIG9iamVjdCB0byBiZSBjb252ZXJ0ZWQgdG8gYSBzdHJpbmcuXHJcbiAqIEBwYXJhbSB7Ym9vbGVhbn0gYWxsb3dGdW5jdGlvbnMgLSBJZiBzZXQgdG8gdHJ1ZSwgZnVuY3Rpb25zIGFyZSBwcmVzZXJ2ZWRcclxuICogaW4gdGhlIG91dHB1dC4gT3RoZXJ3aXNlIGFuIGVycm9yIGlzIHRocm93bi5cclxuICogQHBhcmFtIHtib29sZWFufSBzdHJpbmdpZnlGdW5jdGlvbnMgLSBJZiBzZXQgdG8gdHJ1ZSwgZnVuY3Rpb25zIGFyZSBzYXZlZFxyXG4gKiBhcyBzdHJpbmdzLiBUaGUgYGFsbG93RnVuY3Rpb25zYCBtdXN0IGJlIHNldCB0byB0cnVlIGFzIHdlbGwgZm9yIHRoaXMgdG8gdGFrZVxyXG4gKiBhbiBlZmZlY3QuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtzdHJpbmd9IFRoZSBKU09OLWZvcm1hdHRlZCBzdHJpbmcgcmVwcmVzZW50aW5nIHRoZSBvcHRpb25zLlxyXG4gKlxyXG4gKiBAdGhyb3dzIHtFcnJvcn0gVGhyb3dzIGFuIGBFcnJvcmAgd2hlbiBmdW5jdGlvbnMgYXJlIG5vdCBhbGxvd2VkIGJ1dCBhcmVcclxuICogZm91bmQgaW4gcHJvdmlkZWQgb3B0aW9ucyBvYmplY3QuXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gX29wdGlvbnNTdHJpbmdpZnkob3B0aW9ucywgYWxsb3dGdW5jdGlvbnMsIHN0cmluZ2lmeUZ1bmN0aW9ucykge1xyXG4gIGNvbnN0IHJlcGxhY2VyQ2FsbGJhY2sgPSAoXywgdmFsdWUpID0+IHtcclxuICAgIC8vIFRyaW0gc3RyaW5nIHZhbHVlc1xyXG4gICAgaWYgKHR5cGVvZiB2YWx1ZSA9PT0gJ3N0cmluZycpIHtcclxuICAgICAgdmFsdWUgPSB2YWx1ZS50cmltKCk7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gSWYgdmFsdWUgaXMgYSBmdW5jdGlvbiBvciBzdHJpbmdpZmllZCBmdW5jdGlvblxyXG4gICAgaWYgKFxyXG4gICAgICB0eXBlb2YgdmFsdWUgPT09ICdmdW5jdGlvbicgfHxcclxuICAgICAgKHR5cGVvZiB2YWx1ZSA9PT0gJ3N0cmluZycgJiZcclxuICAgICAgICB2YWx1ZS5zdGFydHNXaXRoKCdmdW5jdGlvbicpICYmXHJcbiAgICAgICAgdmFsdWUuZW5kc1dpdGgoJ30nKSlcclxuICAgICkge1xyXG4gICAgICAvLyBJZiBhbGxvd0Z1bmN0aW9ucyBpcyBzZXQgdG8gdHJ1ZSwgcHJlc2VydmUgZnVuY3Rpb25zXHJcbiAgICAgIGlmIChhbGxvd0Z1bmN0aW9ucykge1xyXG4gICAgICAgIC8vIEJhc2VkIG9uIHRoZSBgc3RyaW5naWZ5RnVuY3Rpb25zYCBvcHRpb25zLCBzZXQgZnVuY3Rpb24gdmFsdWVzXHJcbiAgICAgICAgcmV0dXJuIHN0cmluZ2lmeUZ1bmN0aW9uc1xyXG4gICAgICAgICAgPyAvLyBBcyBzdHJpbmdpZmllZCBmdW5jdGlvbnNcclxuICAgICAgICAgICAgYFwiRVhQX0ZVTiR7KHZhbHVlICsgJycpLnJlcGxhY2VBbGwoL1xccysvZywgJyAnKX1FWFBfRlVOXCJgXHJcbiAgICAgICAgICA6IC8vIEFzIGZ1bmN0aW9uc1xyXG4gICAgICAgICAgICBgRVhQX0ZVTiR7KHZhbHVlICsgJycpLnJlcGxhY2VBbGwoL1xccysvZywgJyAnKX1FWFBfRlVOYDtcclxuICAgICAgfSBlbHNlIHtcclxuICAgICAgICAvLyBUaHJvdyBhbiBlcnJvciBvdGhlcndpc2VcclxuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoKTtcclxuICAgICAgfVxyXG4gICAgfVxyXG5cclxuICAgIC8vIEluIGFsbCBvdGhlciBjYXNlcywgc2ltcGx5IHJldHVybiB0aGUgdmFsdWVcclxuICAgIHJldHVybiB2YWx1ZTtcclxuICB9O1xyXG5cclxuICAvLyBTdHJpbmdpZnkgb3B0aW9ucyBhbmQgaWYgcmVxdWlyZWQsIHJlcGxhY2Ugc3BlY2lhbCBmdW5jdGlvbnMgbWFya3NcclxuICByZXR1cm4gSlNPTi5zdHJpbmdpZnkob3B0aW9ucywgcmVwbGFjZXJDYWxsYmFjaykucmVwbGFjZUFsbChcclxuICAgIHN0cmluZ2lmeUZ1bmN0aW9ucyA/IC9cXFxcXCJFWFBfRlVOfEVYUF9GVU5cXFxcXCIvZyA6IC9cIkVYUF9GVU58RVhQX0ZVTlwiL2csXHJcbiAgICAnJ1xyXG4gICk7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBMb2FkcyBhZGRpdGlvbmFsIGNvbmZpZ3VyYXRpb24gZnJvbSBhIHNwZWNpZmllZCBmaWxlIHByb3ZpZGVkIHZpYVxyXG4gKiB0aGUgYGxvYWRDb25maWdgIG9wdGlvbiBpbiB0aGUgY29tbWFuZC1saW5lIGFyZ3VtZW50cy5cclxuICpcclxuICogQGZ1bmN0aW9uIF9sb2FkQ29uZmlnRmlsZVxyXG4gKlxyXG4gKiBAcGFyYW0ge0FycmF5LjxzdHJpbmc+fSBjbGlBcmdzIC0gQ29tbWFuZC1saW5lIGFyZ3VtZW50cyB0byBzZWFyY2hcclxuICogZm9yIHRoZSBgbG9hZENvbmZpZ2Agb3B0aW9uIGFuZCB0aGUgY29ycmVzcG9uZGluZyBmaWxlIHBhdGguXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtPYmplY3R9IFRoZSBhZGRpdGlvbmFsIGNvbmZpZ3VyYXRpb24gbG9hZGVkIGZyb20gdGhlIHNwZWNpZmllZFxyXG4gKiBmaWxlLCBvciBhbiBlbXB0eSBvYmplY3QgaWYgdGhlIGZpbGUgaXMgbm90IGZvdW5kLCBpbnZhbGlkLCBvciBhbiBlcnJvclxyXG4gKiBvY2N1cnMuXHJcbiAqL1xyXG5mdW5jdGlvbiBfbG9hZENvbmZpZ0ZpbGUoY2xpQXJncykge1xyXG4gIC8vIENoZWNrIGlmIHRoZSBgbG9hZENvbmZpZ2Agb3B0aW9uIHdhcyB1c2VkXHJcbiAgY29uc3QgY29uZmlnSW5kZXggPSBjbGlBcmdzLmZpbmRJbmRleChcclxuICAgIChhcmcpID0+IGFyZy5yZXBsYWNlKC8tL2csICcnKSA9PT0gJ2xvYWRDb25maWcnXHJcbiAgKTtcclxuXHJcbiAgLy8gR2V0IHRoZSBgbG9hZENvbmZpZ2Agb3B0aW9uIHZhbHVlXHJcbiAgY29uc3QgY29uZmlnRmlsZU5hbWUgPSBjb25maWdJbmRleCA+IC0xICYmIGNsaUFyZ3NbY29uZmlnSW5kZXggKyAxXTtcclxuXHJcbiAgLy8gQ2hlY2sgaWYgdGhlIGBsb2FkQ29uZmlnYCBpcyBwcmVzZW50IGFuZCBoYXMgYSBjb3JyZWN0IHZhbHVlXHJcbiAgaWYgKGNvbmZpZ0ZpbGVOYW1lKSB7XHJcbiAgICB0cnkge1xyXG4gICAgICAvLyBMb2FkIGFuIG9wdGlvbmFsIGN1c3RvbSBKU09OIGNvbmZpZyBmaWxlXHJcbiAgICAgIHJldHVybiBKU09OLnBhcnNlKHJlYWRGaWxlU3luYyhnZXRBYnNvbHV0ZVBhdGgoY29uZmlnRmlsZU5hbWUpKSk7XHJcbiAgICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgICBsb2dXaXRoU3RhY2soXHJcbiAgICAgICAgMixcclxuICAgICAgICBlcnJvcixcclxuICAgICAgICBgW2NvbmZpZ10gVW5hYmxlIHRvIGxvYWQgdGhlIGNvbmZpZ3VyYXRpb24gZnJvbSB0aGUgJHtjb25maWdGaWxlTmFtZX0gZmlsZS5gXHJcbiAgICAgICk7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICAvLyBObyBhZGRpdGlvbmFsIG9wdGlvbnMgdG8gcmV0dXJuXHJcbiAgcmV0dXJuIHt9O1xyXG59XHJcblxyXG4vKipcclxuICogUGFyc2VzIGNvbW1hbmQtbGluZSBhcmd1bWVudHMgYW5kIHBhaXJzIGVhY2ggYXJndW1lbnQgd2l0aCBpdHMgY29ycmVzcG9uZGluZ1xyXG4gKiBvcHRpb24gaW4gdGhlIGNvbmZpZ3VyYXRpb24uIFRoZSB2YWx1ZXMgYXJlIHN0cnVjdHVyZWQgaW50byBhIG5lc3RlZCBvcHRpb25zXHJcbiAqIG9iamVjdCwgYmFzZWQgb24gcHJlZGVmaW5lZCBtYXBwaW5ncy5cclxuICpcclxuICogQGZ1bmN0aW9uIF9wYWlyQXJndW1lbnRWYWx1ZVxyXG4gKlxyXG4gKiBAcGFyYW0ge0FycmF5LjxzdHJpbmc+fSBuZXN0ZWRQcm9wcyAtIEFuIGFycmF5IG9mIG5lc3RpbmcgbGV2ZWwgZm9yIGFsbFxyXG4gKiBvcHRpb25zLlxyXG4gKiBAcGFyYW0ge0FycmF5LjxzdHJpbmc+fSBjbGlBcmdzIC0gQW4gYXJyYXkgb2YgY29tbWFuZC1saW5lIGFyZ3VtZW50c1xyXG4gKiBjb250YWluaW5nIG9wdGlvbnMgYW5kIHRoZWlyIGFzc29jaWF0ZWQgdmFsdWVzLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7T2JqZWN0fSBBbiB1cGRhdGVkIG9wdGlvbnMgb2JqZWN0IHdoZXJlIGVhY2ggb3B0aW9uIGZyb21cclxuICogdGhlIGNvbW1hbmQtbGluZSBpcyBwYWlyZWQgd2l0aCBpdHMgdmFsdWUsIHN0cnVjdHVyZWQgaW50byBuZXN0ZWQgb2JqZWN0c1xyXG4gKiBhcyBkZWZpbmVkLlxyXG4gKi9cclxuZnVuY3Rpb24gX3BhaXJBcmd1bWVudFZhbHVlKG5lc3RlZFByb3BzLCBjbGlBcmdzKSB7XHJcbiAgLy8gQW4gZW1wdHkgb2JqZWN0IHRvIGNvbGxlY3QgYW5kIHN0cnVjdHVyaXplIGRhdGEgZnJvbSB0aGUgYXJnc1xyXG4gIGNvbnN0IGNsaU9wdGlvbnMgPSB7fTtcclxuXHJcbiAgLy8gQ3ljbGUgdGhyb3VnaCBhbGwgQ0xJIGFyZ3MgYW5kIGZpbHRlciB0aGVtXHJcbiAgZm9yIChsZXQgaSA9IDA7IGkgPCBjbGlBcmdzLmxlbmd0aDsgaSsrKSB7XHJcbiAgICBjb25zdCBvcHRpb24gPSBjbGlBcmdzW2ldLnJlcGxhY2UoLy0vZywgJycpO1xyXG5cclxuICAgIC8vIEZpbmQgdGhlIHJpZ2h0IHBsYWNlIGZvciBwcm9wZXJ0eSdzIHZhbHVlXHJcbiAgICBjb25zdCBwcm9wZXJ0aWVzQ2hhaW4gPSBuZXN0ZWRQcm9wc1tvcHRpb25dXHJcbiAgICAgID8gbmVzdGVkUHJvcHNbb3B0aW9uXS5zcGxpdCgnLicpXHJcbiAgICAgIDogW107XHJcblxyXG4gICAgLy8gQ3JlYXRlIG9wdGlvbnMgb2JqZWN0IHdpdGggdmFsdWVzIGZyb20gQ0xJIGZvciBsYXRlciBwYXJzaW5nIGFuZCBtZXJnaW5nXHJcbiAgICBwcm9wZXJ0aWVzQ2hhaW4ucmVkdWNlKChvYmosIHByb3AsIGluZGV4KSA9PiB7XHJcbiAgICAgIGlmIChwcm9wZXJ0aWVzQ2hhaW4ubGVuZ3RoIC0gMSA9PT0gaW5kZXgpIHtcclxuICAgICAgICBjb25zdCB2YWx1ZSA9IGNsaUFyZ3NbKytpXTtcclxuICAgICAgICBpZiAoIXZhbHVlKSB7XHJcbiAgICAgICAgICBsb2coXHJcbiAgICAgICAgICAgIDIsXHJcbiAgICAgICAgICAgIGBbY29uZmlnXSBNaXNzaW5nIHZhbHVlIGZvciB0aGUgQ0xJICctLSR7b3B0aW9ufScgYXJndW1lbnQuIFVzaW5nIHRoZSBkZWZhdWx0IHZhbHVlLmBcclxuICAgICAgICAgICk7XHJcbiAgICAgICAgfVxyXG4gICAgICAgIG9ialtwcm9wXSA9IHZhbHVlIHx8IG51bGw7XHJcbiAgICAgIH0gZWxzZSBpZiAob2JqW3Byb3BdID09PSB1bmRlZmluZWQpIHtcclxuICAgICAgICBvYmpbcHJvcF0gPSB7fTtcclxuICAgICAgfVxyXG4gICAgICByZXR1cm4gb2JqW3Byb3BdO1xyXG4gICAgfSwgY2xpT3B0aW9ucyk7XHJcbiAgfVxyXG5cclxuICAvLyBSZXR1cm4gcGFyc2VkIENMSSBvcHRpb25zXHJcbiAgcmV0dXJuIGNsaU9wdGlvbnM7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBSZWN1cnNpdmVseSB0cmF2ZXJzZXMgdGhlIG9wdGlvbnMgb2JqZWN0IHRvIHByaW50IHRoZSB1c2FnZSBpbmZvcm1hdGlvblxyXG4gKiBmb3IgZWFjaCBvcHRpb24gY2F0ZWdvcnkgYW5kIGluZGl2aWR1YWwgb3B0aW9uLlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gX2N5Y2xlQ2F0ZWdvcmllc1xyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gb3B0aW9ucyAtIFRoZSBvcHRpb25zIG9iamVjdCBjb250YWluaW5nIENMSSBvcHRpb25zLlxyXG4gKiBJdCBtYXkgaW5jbHVkZSBuZXN0ZWQgY2F0ZWdvcmllcyBhbmQgaW5kaXZpZHVhbCBvcHRpb25zLlxyXG4gKi9cclxuZnVuY3Rpb24gX2N5Y2xlQ2F0ZWdvcmllcyhvcHRpb25zKSB7XHJcbiAgZm9yIChjb25zdCBbbmFtZSwgb3B0aW9uXSBvZiBPYmplY3QuZW50cmllcyhvcHRpb25zKSkge1xyXG4gICAgLy8gSWYgdGhlIGN1cnJlbnQgZW50cnkgaXMgYSBjYXRlZ29yeSBhbmQgbm90IGEgbGVhZiBvcHRpb24sIHJlY3Vyc2UgaW50byBpdFxyXG4gICAgaWYgKCFPYmplY3QucHJvdG90eXBlLmhhc093blByb3BlcnR5LmNhbGwob3B0aW9uLCAndmFsdWUnKSkge1xyXG4gICAgICBfY3ljbGVDYXRlZ29yaWVzKG9wdGlvbik7XHJcbiAgICB9IGVsc2Uge1xyXG4gICAgICAvLyBQcmVwYXJlIGRlc2NyaXB0aW9uXHJcbiAgICAgIGNvbnN0IGRlc2NOYW1lID0gYCAtLSR7b3B0aW9uLmNsaU5hbWUgfHwgbmFtZX1gO1xyXG5cclxuICAgICAgLy8gR2V0IHRoZSB2YWx1ZVxyXG4gICAgICBsZXQgb3B0aW9uVmFsdWUgPSBvcHRpb24udmFsdWU7XHJcblxyXG4gICAgICAvLyBQcmVwYXJlIHZhbHVlIGZvciBvcHRpb24gdGhhdCBpcyBub3QgbnVsbCBhbmQgaXMgYXJyYXkgb2Ygc3RyaW5nc1xyXG4gICAgICBpZiAob3B0aW9uVmFsdWUgIT09IG51bGwgJiYgb3B0aW9uLnR5cGVzLmluY2x1ZGVzKCdzdHJpbmdbXScpKSB7XHJcbiAgICAgICAgb3B0aW9uVmFsdWUgPVxyXG4gICAgICAgICAgJ1snICsgb3B0aW9uVmFsdWUubWFwKChpdGVtKSA9PiBgJyR7aXRlbX0nYCkuam9pbignLCAnKSArICddJztcclxuICAgICAgfVxyXG5cclxuICAgICAgLy8gUHJlcGFyZSB2YWx1ZSBmb3Igb3B0aW9uIHRoYXQgaXMgbm90IG51bGwgYW5kIGlzIGEgc3RyaW5nXHJcbiAgICAgIGlmIChvcHRpb25WYWx1ZSAhPT0gbnVsbCAmJiBvcHRpb24udHlwZXMuaW5jbHVkZXMoJ3N0cmluZycpKSB7XHJcbiAgICAgICAgb3B0aW9uVmFsdWUgPSBgJyR7b3B0aW9uVmFsdWV9J2A7XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIC8vIERpc3BsYXkgY29ycmVjdGx5IGFsaWduZWQgbWVzc2FnZXNcclxuICAgICAgY29uc29sZS5sb2coXHJcbiAgICAgICAgZGVzY05hbWUuZ3JlZW4sXHJcbiAgICAgICAgYCR7KCc8JyArIG9wdGlvbi50eXBlcy5qb2luKCd8JykgKyAnPicpLnllbGxvd31gLFxyXG4gICAgICAgIGAke1N0cmluZyhvcHRpb25WYWx1ZSkuYm9sZH1gLmJsdWUsXHJcbiAgICAgICAgYC0gJHtvcHRpb24uZGVzY3JpcHRpb259LmBcclxuICAgICAgKTtcclxuICAgIH1cclxuICB9XHJcbn1cclxuXHJcbmV4cG9ydCBkZWZhdWx0IHtcclxuICBnZXRPcHRpb25zLFxyXG4gIHNldE9wdGlvbnMsXHJcbiAgbWVyZ2VPcHRpb25zLFxyXG4gIG1hcFRvTmV3T3B0aW9ucyxcclxuICBpc0FsbG93ZWRDb25maWcsXHJcbiAgcHJpbnRMaWNlbnNlLFxyXG4gIHByaW50VXNhZ2UsXHJcbiAgcHJpbnRWZXJzaW9uXHJcbn07XHJcbiIsIi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXHJcblxyXG5IaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXJcclxuXHJcbkNvcHlyaWdodCAoYykgMjAxNi0yMDI1LCBIaWdoc29mdFxyXG5cclxuTGljZW5jZWQgdW5kZXIgdGhlIE1JVCBsaWNlbmNlLlxyXG5cclxuQWRkaXRpb25hbGx5IGEgdmFsaWQgSGlnaGNoYXJ0cyBsaWNlbnNlIGlzIHJlcXVpcmVkIGZvciB1c2UuXHJcblxyXG5TZWUgTElDRU5TRSBmaWxlIGluIHJvb3QgZm9yIGRldGFpbHMuXHJcblxyXG4qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xyXG5cclxuLyoqXHJcbiAqIEBvdmVydmlldyBIVFRQIHV0aWxpdHkgbW9kdWxlIGZvciBmZXRjaGluZyBhbmQgcG9zdGluZyBkYXRhLiBTdXBwb3J0cyBib3RoXHJcbiAqIEhUVFAgYW5kIEhUVFBTIHByb3RvY29scywgcHJvdmlkaW5nIG1ldGhvZHMgdG8gbWFrZSBHRVQgYW5kIFBPU1QgcmVxdWVzdHNcclxuICogd2l0aCBjdXN0b21pemFibGUgb3B0aW9ucy4gSW5jbHVkZXMgcHJvdG9jb2wgZGV0ZXJtaW5hdGlvbiBiYXNlZCBvbiBVUkxcclxuICogYW5kIGF1Z21lbnRzIHJlc3BvbnNlIG9iamVjdHMgd2l0aCBhICd0ZXh0JyBwcm9wZXJ0eSBmb3IgZWFzaWVyIGRhdGEgYWNjZXNzLlxyXG4gKi9cclxuXHJcbmltcG9ydCBodHRwIGZyb20gJ2h0dHAnO1xyXG5pbXBvcnQgaHR0cHMgZnJvbSAnaHR0cHMnO1xyXG5cclxuLyoqXHJcbiAqIEZldGNoZXMgZGF0YSBmcm9tIHRoZSBzcGVjaWZpZWQgVVJMIHVzaW5nIGVpdGhlciBIVFRQIG9yIEhUVFBTIHByb3RvY29sLlxyXG4gKlxyXG4gKiBAYXN5bmNcclxuICogQGZ1bmN0aW9uIGZldGNoXHJcbiAqXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSB1cmwgLSBUaGUgVVJMIHRvIGZldGNoIGRhdGEgZnJvbS5cclxuICogQHBhcmFtIHtPYmplY3R9IFtyZXF1ZXN0T3B0aW9ucz17fV0gLSBPcHRpb25zIGZvciB0aGUgSFRUUC9IVFRQUyByZXF1ZXN0LlxyXG4gKiBUaGUgZGVmYXVsdCB2YWx1ZSBpcyBhbiBlbXB0eSBvYmplY3QuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtQcm9taXNlPE9iamVjdD59IEEgUHJvbWlzZSB0aGF0IHJlc29sdmVzIHRvIHRoZSBIVFRQL0hUVFBTIHJlc3BvbnNlXHJcbiAqIG9iamVjdCB3aXRoIGFkZGVkICd0ZXh0JyBwcm9wZXJ0eSBvciByZWplY3Rpbmcgd2l0aCBhbiBlcnJvci5cclxuICovXHJcbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBmZXRjaCh1cmwsIHJlcXVlc3RPcHRpb25zID0ge30pIHtcclxuICByZXR1cm4gbmV3IFByb21pc2UoKHJlc29sdmUsIHJlamVjdCkgPT4ge1xyXG4gICAgX2dldFByb3RvY29sTW9kdWxlKHVybClcclxuICAgICAgLmdldCh1cmwsIHJlcXVlc3RPcHRpb25zLCAocmVzcG9uc2UpID0+IHtcclxuICAgICAgICBsZXQgcmVzcG9uc2VEYXRhID0gJyc7XHJcblxyXG4gICAgICAgIC8vIEEgY2h1bmsgb2YgZGF0YSBoYXMgYmVlbiByZWNlaXZlZFxyXG4gICAgICAgIHJlc3BvbnNlLm9uKCdkYXRhJywgKGNodW5rKSA9PiB7XHJcbiAgICAgICAgICByZXNwb25zZURhdGEgKz0gY2h1bms7XHJcbiAgICAgICAgfSk7XHJcblxyXG4gICAgICAgIC8vIFRoZSB3aG9sZSByZXNwb25zZSBoYXMgYmVlbiByZWNlaXZlZFxyXG4gICAgICAgIHJlc3BvbnNlLm9uKCdlbmQnLCAoKSA9PiB7XHJcbiAgICAgICAgICBpZiAoIXJlc3BvbnNlRGF0YSkge1xyXG4gICAgICAgICAgICByZWplY3QoJ05vdGhpbmcgd2FzIGZldGNoZWQgZnJvbSB0aGUgVVJMLicpO1xyXG4gICAgICAgICAgfVxyXG4gICAgICAgICAgcmVzcG9uc2UudGV4dCA9IHJlc3BvbnNlRGF0YTtcclxuICAgICAgICAgIHJlc29sdmUocmVzcG9uc2UpO1xyXG4gICAgICAgIH0pO1xyXG4gICAgICB9KVxyXG4gICAgICAub24oJ2Vycm9yJywgKGVycm9yKSA9PiB7XHJcbiAgICAgICAgcmVqZWN0KGVycm9yKTtcclxuICAgICAgfSk7XHJcbiAgfSk7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBTZW5kcyBhIFBPU1QgcmVxdWVzdCB0byB0aGUgc3BlY2lmaWVkIFVSTCB3aXRoIHRoZSBwcm92aWRlZCBKU09OIGJvZHkgdXNpbmdcclxuICogZWl0aGVyIEhUVFAgb3IgSFRUUFMgcHJvdG9jb2wuXHJcbiAqXHJcbiAqIEBhc3luY1xyXG4gKiBAZnVuY3Rpb24gcG9zdFxyXG4gKlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gdXJsIC0gVGhlIFVSTCB0byBzZW5kIHRoZSBQT1NUIHJlcXVlc3QgdG8uXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBbYm9keT17fV0gLSBUaGUgSlNPTiBib2R5IHRvIGluY2x1ZGUgaW4gdGhlIFBPU1QgcmVxdWVzdC5cclxuICogVGhlIGRlZmF1bHQgdmFsdWUgaXMgYW4gZW1wdHkgb2JqZWN0LlxyXG4gKiBAcGFyYW0ge09iamVjdH0gW3JlcXVlc3RPcHRpb25zPXt9XSAtIE9wdGlvbnMgZm9yIHRoZSBIVFRQL0hUVFBTIHJlcXVlc3QuXHJcbiAqIFRoZSBkZWZhdWx0IHZhbHVlIGlzIGFuIGVtcHR5IG9iamVjdC5cclxuICpcclxuICogQHJldHVybnMge1Byb21pc2U8T2JqZWN0Pn0gQSBQcm9taXNlIHRoYXQgcmVzb2x2ZXMgdG8gdGhlIEhUVFAvSFRUUFMgcmVzcG9uc2VcclxuICogb2JqZWN0IHdpdGggYWRkZWQgJ3RleHQnIHByb3BlcnR5IG9yIHJlamVjdGluZyB3aXRoIGFuIGVycm9yLlxyXG4gKi9cclxuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIHBvc3QodXJsLCBib2R5ID0ge30sIHJlcXVlc3RPcHRpb25zID0ge30pIHtcclxuICByZXR1cm4gbmV3IFByb21pc2UoKHJlc29sdmUsIHJlamVjdCkgPT4ge1xyXG4gICAgY29uc3QgZGF0YSA9IEpTT04uc3RyaW5naWZ5KGJvZHkpO1xyXG5cclxuICAgIC8vIFNldCBkZWZhdWx0IGhlYWRlcnMgYW5kIG1lcmdlIHdpdGggcmVxdWVzdE9wdGlvbnNcclxuICAgIGNvbnN0IG9wdGlvbnMgPSBPYmplY3QuYXNzaWduKFxyXG4gICAgICB7XHJcbiAgICAgICAgbWV0aG9kOiAnUE9TVCcsXHJcbiAgICAgICAgaGVhZGVyczoge1xyXG4gICAgICAgICAgJ0NvbnRlbnQtVHlwZSc6ICdhcHBsaWNhdGlvbi9qc29uJyxcclxuICAgICAgICAgICdDb250ZW50LUxlbmd0aCc6IGRhdGEubGVuZ3RoXHJcbiAgICAgICAgfVxyXG4gICAgICB9LFxyXG4gICAgICByZXF1ZXN0T3B0aW9uc1xyXG4gICAgKTtcclxuXHJcbiAgICBjb25zdCByZXF1ZXN0ID0gX2dldFByb3RvY29sTW9kdWxlKHVybClcclxuICAgICAgLnJlcXVlc3QodXJsLCBvcHRpb25zLCAocmVzcG9uc2UpID0+IHtcclxuICAgICAgICBsZXQgcmVzcG9uc2VEYXRhID0gJyc7XHJcblxyXG4gICAgICAgIC8vIEEgY2h1bmsgb2YgZGF0YSBoYXMgYmVlbiByZWNlaXZlZFxyXG4gICAgICAgIHJlc3BvbnNlLm9uKCdkYXRhJywgKGNodW5rKSA9PiB7XHJcbiAgICAgICAgICByZXNwb25zZURhdGEgKz0gY2h1bms7XHJcbiAgICAgICAgfSk7XHJcblxyXG4gICAgICAgIC8vIFRoZSB3aG9sZSByZXNwb25zZSBoYXMgYmVlbiByZWNlaXZlZFxyXG4gICAgICAgIHJlc3BvbnNlLm9uKCdlbmQnLCAoKSA9PiB7XHJcbiAgICAgICAgICB0cnkge1xyXG4gICAgICAgICAgICByZXNwb25zZS50ZXh0ID0gcmVzcG9uc2VEYXRhO1xyXG4gICAgICAgICAgICByZXNvbHZlKHJlc3BvbnNlKTtcclxuICAgICAgICAgIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICAgICAgICAgIHJlamVjdChlcnJvcik7XHJcbiAgICAgICAgICB9XHJcbiAgICAgICAgfSk7XHJcbiAgICAgIH0pXHJcbiAgICAgIC5vbignZXJyb3InLCAoZXJyb3IpID0+IHtcclxuICAgICAgICByZWplY3QoZXJyb3IpO1xyXG4gICAgICB9KTtcclxuXHJcbiAgICAvLyBXcml0ZSB0aGUgcmVxdWVzdCBib2R5IGFuZCBlbmQgdGhlIHJlcXVlc3RcclxuICAgIHJlcXVlc3Qud3JpdGUoZGF0YSk7XHJcbiAgICByZXF1ZXN0LmVuZCgpO1xyXG4gIH0pO1xyXG59XHJcblxyXG4vKipcclxuICogUmV0dXJucyB0aGUgSFRUUCBvciBIVFRQUyBwcm90b2NvbCBtb2R1bGUgYmFzZWQgb24gdGhlIHByb3ZpZGVkIFVSTC5cclxuICpcclxuICogQGZ1bmN0aW9uIF9nZXRQcm90b2NvbE1vZHVsZVxyXG4gKlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gdXJsIC0gVGhlIFVSTCB0byBkZXRlcm1pbmUgdGhlIHByb3RvY29sLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7T2JqZWN0fSBUaGUgSFRUUCBvciBIVFRQUyBwcm90b2NvbCBtb2R1bGUgKGh0dHAgb3IgaHR0cHMpLlxyXG4gKi9cclxuZnVuY3Rpb24gX2dldFByb3RvY29sTW9kdWxlKHVybCkge1xyXG4gIHJldHVybiB1cmwuc3RhcnRzV2l0aCgnaHR0cHMnKSA/IGh0dHBzIDogaHR0cDtcclxufVxyXG5cclxuZXhwb3J0IGRlZmF1bHQge1xyXG4gIGZldGNoLFxyXG4gIHBvc3RcclxufTtcclxuIiwiLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcclxuXHJcbkhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlclxyXG5cclxuQ29weXJpZ2h0IChjKSAyMDE2LTIwMjUsIEhpZ2hzb2Z0XHJcblxyXG5MaWNlbmNlZCB1bmRlciB0aGUgTUlUIGxpY2VuY2UuXHJcblxyXG5BZGRpdGlvbmFsbHkgYSB2YWxpZCBIaWdoY2hhcnRzIGxpY2Vuc2UgaXMgcmVxdWlyZWQgZm9yIHVzZS5cclxuXHJcblNlZSBMSUNFTlNFIGZpbGUgaW4gcm9vdCBmb3IgZGV0YWlscy5cclxuXHJcbioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXHJcblxyXG4vKipcclxuICogQSBjdXN0b20gZXJyb3IgY2xhc3MgZm9yIGhhbmRsaW5nIGV4cG9ydC1yZWxhdGVkIGVycm9ycy4gRXh0ZW5kcyB0aGUgbmF0aXZlXHJcbiAqIGBFcnJvcmAgY2xhc3MgdG8gaW5jbHVkZSBhZGRpdGlvbmFsIHByb3BlcnRpZXMgbGlrZSBzdGF0dXMgY29kZSBhbmQgc3RhY2tcclxuICogdHJhY2UgZGV0YWlscy5cclxuICovXHJcbmNsYXNzIEV4cG9ydEVycm9yIGV4dGVuZHMgRXJyb3Ige1xyXG4gIC8qKlxyXG4gICAqIENyZWF0ZXMgYW4gaW5zdGFuY2Ugb2YgdGhlIGBFeHBvcnRFcnJvcmAuXHJcbiAgICpcclxuICAgKiBAcGFyYW0ge3N0cmluZ30gbWVzc2FnZSAtIFRoZSBlcnJvciBtZXNzYWdlIHRvIGJlIGRpc3BsYXllZC5cclxuICAgKiBAcGFyYW0ge251bWJlcn0gc3RhdHVzQ29kZSAtIE9wdGlvbmFsIEhUVFAgc3RhdHVzIGNvZGUgYXNzb2NpYXRlZFxyXG4gICAqIHdpdGggdGhlIGVycm9yIChlLmcuLCA0MDAsIDUwMCkuXHJcbiAgICovXHJcbiAgY29uc3RydWN0b3IobWVzc2FnZSwgc3RhdHVzQ29kZSkge1xyXG4gICAgc3VwZXIoKTtcclxuXHJcbiAgICB0aGlzLm1lc3NhZ2UgPSBtZXNzYWdlO1xyXG4gICAgdGhpcy5zdGFja01lc3NhZ2UgPSBtZXNzYWdlO1xyXG5cclxuICAgIGlmIChzdGF0dXNDb2RlKSB7XHJcbiAgICAgIHRoaXMuc3RhdHVzQ29kZSA9IHN0YXR1c0NvZGU7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICAvKipcclxuICAgKiBTZXRzIGFkZGl0aW9uYWwgZXJyb3IgZGV0YWlscyBiYXNlZCBvbiBhbiBleGlzdGluZyBlcnJvciBvYmplY3QuXHJcbiAgICpcclxuICAgKiBAcGFyYW0ge0Vycm9yfSBlcnJvciAtIEFuIGVycm9yIG9iamVjdCBjb250YWluaW5nIGRldGFpbHMgdG8gcG9wdWxhdGVcclxuICAgKiB0aGUgYEV4cG9ydEVycm9yYCBpbnN0YW5jZS5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHtFeHBvcnRFcnJvcn0gVGhlIHVwZGF0ZWQgaW5zdGFuY2Ugb2YgdGhlIGBFeHBvcnRFcnJvcmAgY2xhc3MuXHJcbiAgICovXHJcbiAgc2V0RXJyb3IoZXJyb3IpIHtcclxuICAgIHRoaXMuZXJyb3IgPSBlcnJvcjtcclxuXHJcbiAgICBpZiAoZXJyb3IubmFtZSkge1xyXG4gICAgICB0aGlzLm5hbWUgPSBlcnJvci5uYW1lO1xyXG4gICAgfVxyXG5cclxuICAgIGlmIChlcnJvci5zdGF0dXNDb2RlKSB7XHJcbiAgICAgIHRoaXMuc3RhdHVzQ29kZSA9IGVycm9yLnN0YXR1c0NvZGU7XHJcbiAgICB9XHJcblxyXG4gICAgaWYgKGVycm9yLnN0YWNrKSB7XHJcbiAgICAgIHRoaXMuc3RhY2tNZXNzYWdlID0gZXJyb3IubWVzc2FnZTtcclxuICAgICAgdGhpcy5zdGFjayA9IGVycm9yLnN0YWNrO1xyXG4gICAgfVxyXG5cclxuICAgIHJldHVybiB0aGlzO1xyXG4gIH1cclxufVxyXG5cclxuZXhwb3J0IGRlZmF1bHQgRXhwb3J0RXJyb3I7XHJcbiIsIi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXHJcblxyXG5IaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXJcclxuXHJcbkNvcHlyaWdodCAoYykgMjAxNi0yMDI1LCBIaWdoc29mdFxyXG5cclxuTGljZW5jZWQgdW5kZXIgdGhlIE1JVCBsaWNlbmNlLlxyXG5cclxuQWRkaXRpb25hbGx5IGEgdmFsaWQgSGlnaGNoYXJ0cyBsaWNlbnNlIGlzIHJlcXVpcmVkIGZvciB1c2UuXHJcblxyXG5TZWUgTElDRU5TRSBmaWxlIGluIHJvb3QgZm9yIGRldGFpbHMuXHJcblxyXG4qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xyXG5cclxuLyoqXHJcbiAqIEBvdmVydmlldyBUaGUgY2FjaGUgbWFuYWdlciBpcyByZXNwb25zaWJsZSBmb3IgaGFuZGxpbmcgYW5kIG1hbmFnaW5nXHJcbiAqIHRoZSBIaWdoY2hhcnRzIGxpYnJhcnkgYWxvbmcgd2l0aCBpdHMgZGVwZW5kZW5jaWVzLiBJdCBlbnN1cmVzIHRoYXQgdGhlc2VcclxuICogcmVzb3VyY2VzIGFyZSBzdG9yZWQgYW5kIHJldHJpZXZlZCBlZmZpY2llbnRseSB0byBvcHRpbWl6ZSBwZXJmb3JtYW5jZVxyXG4gKiBhbmQgcmVkdWNlIHJlZHVuZGFudCBuZXR3b3JrIHJlcXVlc3RzLiBUaGUgY2FjaGUgaXMgc3RvcmVkIGluIHRoZSBgLmNhY2hlYFxyXG4gKiBkaXJlY3RvcnkgYnkgZGVmYXVsdCwgd2hpY2ggc2VydmVzIGFzIGEgZGVkaWNhdGVkIGZvbGRlciBmb3Iga2VlcGluZyBjYWNoZWRcclxuICogZmlsZXMuXHJcbiAqL1xyXG5cclxuaW1wb3J0IHsgZXhpc3RzU3luYywgbWtkaXJTeW5jLCByZWFkRmlsZVN5bmMsIHdyaXRlRmlsZVN5bmMgfSBmcm9tICdmcyc7XHJcbmltcG9ydCB7IGpvaW4gfSBmcm9tICdwYXRoJztcclxuXHJcbmltcG9ydCB7IEh0dHBzUHJveHlBZ2VudCB9IGZyb20gJ2h0dHBzLXByb3h5LWFnZW50JztcclxuXHJcbmltcG9ydCB7IGdldE9wdGlvbnMgfSBmcm9tICcuL2NvbmZpZy5qcyc7XHJcbmltcG9ydCB7IGZldGNoIH0gZnJvbSAnLi9mZXRjaC5qcyc7XHJcbmltcG9ydCB7IGxvZyB9IGZyb20gJy4vbG9nZ2VyLmpzJztcclxuaW1wb3J0IHsgX19kaXJuYW1lLCBnZXRBYnNvbHV0ZVBhdGggfSBmcm9tICcuL3V0aWxzLmpzJztcclxuXHJcbmltcG9ydCBFeHBvcnRFcnJvciBmcm9tICcuL2Vycm9ycy9FeHBvcnRFcnJvci5qcyc7XHJcblxyXG4vLyBUaGUgaW5pdGlhbCBjYWNoZSB0ZW1wbGF0ZVxyXG5jb25zdCBjYWNoZSA9IHtcclxuICBjZG5Vcmw6ICdodHRwczovL2NvZGUuaGlnaGNoYXJ0cy5jb20nLFxyXG4gIGFjdGl2ZU1hbmlmZXN0OiB7fSxcclxuICBzb3VyY2VzOiAnJyxcclxuICBoY1ZlcnNpb246ICcnXHJcbn07XHJcblxyXG4vKipcclxuICogQ2hlY2tzIHRoZSBjYWNoZSBmb3IgSGlnaGNoYXJ0cyBkZXBlbmRlbmNpZXMsIHVwZGF0ZXMgdGhlIGNhY2hlIGlmIG5lZWRlZCxcclxuICogYW5kIGxvYWRzIHRoZSBzb3VyY2VzLlxyXG4gKlxyXG4gKiBAYXN5bmNcclxuICogQGZ1bmN0aW9uIGNoZWNrQW5kVXBkYXRlQ2FjaGVcclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IGhpZ2hjaGFydHNPcHRpb25zIC0gT2JqZWN0IGNvbnRhaW5pbmcgYGhpZ2hjaGFydHNgIG9wdGlvbnMuXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBzZXJ2ZXJQcm94eU9wdGlvbnMgLSBPYmplY3QgY29udGFpbmluZyBgc2VydmVyLnByb3h5YFxyXG4gKiBvcHRpb25zLlxyXG4gKi9cclxuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIGNoZWNrQW5kVXBkYXRlQ2FjaGUoXHJcbiAgaGlnaGNoYXJ0c09wdGlvbnMsXHJcbiAgc2VydmVyUHJveHlPcHRpb25zXHJcbikge1xyXG4gIGxldCBmZXRjaGVkTW9kdWxlcztcclxuXHJcbiAgLy8gR2V0IHRoZSBjYWNoZSBwYXRoXHJcbiAgY29uc3QgY2FjaGVQYXRoID0gZ2V0Q2FjaGVQYXRoKCk7XHJcblxyXG4gIC8vIFByZXBhcmUgcGF0aHMgdG8gbWFuaWZlc3QgYW5kIHNvdXJjZXMgZnJvbSB0aGUgY2FjaGUgZm9sZGVyXHJcbiAgY29uc3QgbWFuaWZlc3RQYXRoID0gam9pbihjYWNoZVBhdGgsICdtYW5pZmVzdC5qc29uJyk7XHJcbiAgY29uc3Qgc291cmNlUGF0aCA9IGpvaW4oY2FjaGVQYXRoLCAnc291cmNlcy5qcycpO1xyXG5cclxuICAvLyBDcmVhdGUgdGhlIGNhY2hlIGRlc3RpbmF0aW9uIGlmIGl0IGRvZXNuJ3QgZXhpc3QgYWxyZWFkeVxyXG4gICFleGlzdHNTeW5jKGNhY2hlUGF0aCkgJiYgbWtkaXJTeW5jKGNhY2hlUGF0aCwgeyByZWN1cnNpdmU6IHRydWUgfSk7XHJcblxyXG4gIC8vIEZldGNoIGFsbCB0aGUgc2NyaXB0cyBlaXRoZXIgaWYgdGhlIGBtYW5pZmVzdC5qc29uYCBkb2VzIG5vdCBleGlzdFxyXG4gIC8vIG9yIGlmIHRoZSBgZm9yY2VGZXRjaGAgb3B0aW9uIGlzIGVuYWJsZWRcclxuICBpZiAoIWV4aXN0c1N5bmMobWFuaWZlc3RQYXRoKSB8fCBoaWdoY2hhcnRzT3B0aW9ucy5mb3JjZUZldGNoKSB7XHJcbiAgICBsb2coMywgJ1tjYWNoZV0gRmV0Y2hpbmcgYW5kIGNhY2hpbmcgSGlnaGNoYXJ0cyBkZXBlbmRlbmNpZXMuJyk7XHJcbiAgICBmZXRjaGVkTW9kdWxlcyA9IGF3YWl0IF91cGRhdGVDYWNoZShcclxuICAgICAgaGlnaGNoYXJ0c09wdGlvbnMsXHJcbiAgICAgIHNlcnZlclByb3h5T3B0aW9ucyxcclxuICAgICAgc291cmNlUGF0aFxyXG4gICAgKTtcclxuICB9IGVsc2Uge1xyXG4gICAgbGV0IHJlcXVlc3RVcGRhdGUgPSBmYWxzZTtcclxuXHJcbiAgICAvLyBSZWFkIHRoZSBtYW5pZmVzdCBKU09OXHJcbiAgICBjb25zdCBtYW5pZmVzdCA9IEpTT04ucGFyc2UocmVhZEZpbGVTeW5jKG1hbmlmZXN0UGF0aCkpO1xyXG5cclxuICAgIC8vIENoZWNrIGlmIHRoZSBtb2R1bGVzIGlzIGFuIGFycmF5LCBpZiBzbywgd2UgcmV3cml0ZSBpdCB0byBhIG1hcCB0byBtYWtlXHJcbiAgICAvLyBpdCBlYXNpZXIgdG8gcmVzb2x2ZSBtb2R1bGVzLlxyXG4gICAgaWYgKG1hbmlmZXN0Lm1vZHVsZXMgJiYgQXJyYXkuaXNBcnJheShtYW5pZmVzdC5tb2R1bGVzKSkge1xyXG4gICAgICBjb25zdCBtb2R1bGVNYXAgPSB7fTtcclxuICAgICAgbWFuaWZlc3QubW9kdWxlcy5mb3JFYWNoKChtKSA9PiAobW9kdWxlTWFwW21dID0gMSkpO1xyXG4gICAgICBtYW5pZmVzdC5tb2R1bGVzID0gbW9kdWxlTWFwO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIEdldCB0aGUgYWN0dWFsIG51bWJlciBvZiBzY3JpcHRzIHRvIGJlIGZldGNoZWRcclxuICAgIGNvbnN0IHsgY29yZVNjcmlwdHMsIG1vZHVsZVNjcmlwdHMsIGluZGljYXRvclNjcmlwdHMgfSA9IGhpZ2hjaGFydHNPcHRpb25zO1xyXG4gICAgY29uc3QgbnVtYmVyT2ZNb2R1bGVzID1cclxuICAgICAgY29yZVNjcmlwdHMubGVuZ3RoICsgbW9kdWxlU2NyaXB0cy5sZW5ndGggKyBpbmRpY2F0b3JTY3JpcHRzLmxlbmd0aDtcclxuXHJcbiAgICAvLyBDb21wYXJlIHRoZSBsb2FkZWQgaGlnaGNoYXJ0cyBjb25maWcgd2l0aCB0aGUgY29udGVudHMgaW4gY2FjaGUuXHJcbiAgICAvLyBJZiB0aGVyZSBhcmUgY2hhbmdlcywgZmV0Y2ggcmVxdWVzdGVkIG1vZHVsZXMgYW5kIHByb2R1Y3RzLFxyXG4gICAgLy8gYW5kIGJha2UgdGhlbSBpbnRvIGEgZ2lhbnQgYmxvYi4gU2F2ZSB0aGUgYmxvYi5cclxuICAgIGlmIChtYW5pZmVzdC52ZXJzaW9uICE9PSBoaWdoY2hhcnRzT3B0aW9ucy52ZXJzaW9uKSB7XHJcbiAgICAgIGxvZyhcclxuICAgICAgICAyLFxyXG4gICAgICAgICdbY2FjaGVdIEEgSGlnaGNoYXJ0cyB2ZXJzaW9uIG1pc21hdGNoIGluIHRoZSBjYWNoZSwgbmVlZCB0byByZS1mZXRjaC4nXHJcbiAgICAgICk7XHJcbiAgICAgIHJlcXVlc3RVcGRhdGUgPSB0cnVlO1xyXG4gICAgfSBlbHNlIGlmIChPYmplY3Qua2V5cyhtYW5pZmVzdC5tb2R1bGVzIHx8IHt9KS5sZW5ndGggIT09IG51bWJlck9mTW9kdWxlcykge1xyXG4gICAgICBsb2coXHJcbiAgICAgICAgMixcclxuICAgICAgICAnW2NhY2hlXSBUaGUgY2FjaGUgYW5kIHRoZSByZXF1ZXN0ZWQgbW9kdWxlcyBkbyBub3QgbWF0Y2gsIG5lZWQgdG8gcmUtZmV0Y2guJ1xyXG4gICAgICApO1xyXG4gICAgICByZXF1ZXN0VXBkYXRlID0gdHJ1ZTtcclxuICAgIH0gZWxzZSB7XHJcbiAgICAgIC8vIENoZWNrIGVhY2ggbW9kdWxlLCBpZiBhbnl0aGluZyBpcyBtaXNzaW5nIHJlZmV0Y2ggZXZlcnl0aGluZ1xyXG4gICAgICByZXF1ZXN0VXBkYXRlID0gKG1vZHVsZVNjcmlwdHMgfHwgW10pLnNvbWUoKG1vZHVsZU5hbWUpID0+IHtcclxuICAgICAgICBpZiAoIW1hbmlmZXN0Lm1vZHVsZXNbbW9kdWxlTmFtZV0pIHtcclxuICAgICAgICAgIGxvZyhcclxuICAgICAgICAgICAgMixcclxuICAgICAgICAgICAgYFtjYWNoZV0gVGhlICR7bW9kdWxlTmFtZX0gaXMgbWlzc2luZyBpbiB0aGUgY2FjaGUsIG5lZWQgdG8gcmUtZmV0Y2guYFxyXG4gICAgICAgICAgKTtcclxuICAgICAgICAgIHJldHVybiB0cnVlO1xyXG4gICAgICAgIH1cclxuICAgICAgfSk7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gVXBkYXRlIGNhY2hlIGlmIG5lZWRlZFxyXG4gICAgaWYgKHJlcXVlc3RVcGRhdGUpIHtcclxuICAgICAgZmV0Y2hlZE1vZHVsZXMgPSBhd2FpdCBfdXBkYXRlQ2FjaGUoXHJcbiAgICAgICAgaGlnaGNoYXJ0c09wdGlvbnMsXHJcbiAgICAgICAgc2VydmVyUHJveHlPcHRpb25zLFxyXG4gICAgICAgIHNvdXJjZVBhdGhcclxuICAgICAgKTtcclxuICAgIH0gZWxzZSB7XHJcbiAgICAgIGxvZygzLCAnW2NhY2hlXSBEZXBlbmRlbmN5IGNhY2hlIGlzIHVwIHRvIGRhdGUsIHByb2NlZWRpbmcuJyk7XHJcblxyXG4gICAgICAvLyBMb2FkIHRoZSBzb3VyY2VzXHJcbiAgICAgIGNhY2hlLnNvdXJjZXMgPSByZWFkRmlsZVN5bmMoc291cmNlUGF0aCwgJ3V0ZjgnKTtcclxuXHJcbiAgICAgIC8vIEdldCBjdXJyZW50IG1vZHVsZXMgbWFwXHJcbiAgICAgIGZldGNoZWRNb2R1bGVzID0gbWFuaWZlc3QubW9kdWxlcztcclxuXHJcbiAgICAgIC8vIEV4dHJhY3QgYW5kIHNhdmUgdmVyc2lvbiBvZiBjdXJyZW50bHkgdXNlZCBIaWdoY2hhcnRzXHJcbiAgICAgIGNhY2hlLmhjVmVyc2lvbiA9IGV4dHJhY3RWZXJzaW9uKGNhY2hlLnNvdXJjZXMpO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgLy8gRmluYWxseSwgc2F2ZSB0aGUgbmV3IG1hbmlmZXN0LCB3aGljaCBpcyBiYXNpY2FsbHkgb3VyIGN1cnJlbnQgY29uZmlnXHJcbiAgLy8gaW4gYSBzbGlnaHRseSBkaWZmZXJlbnQgZm9ybWF0XHJcbiAgYXdhaXQgX3NhdmVDb25maWdUb01hbmlmZXN0KGhpZ2hjaGFydHNPcHRpb25zLCBmZXRjaGVkTW9kdWxlcyk7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBHZXRzIHRoZSB2ZXJzaW9uIG9mIEhpZ2hjaGFydHMgZnJvbSB0aGUgY2FjaGUuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBnZXRIaWdoY2hhcnRzVmVyc2lvblxyXG4gKlxyXG4gKiBAcmV0dXJucyB7c3RyaW5nfSBUaGUgY2FjaGVkIEhpZ2hjaGFydHMgdmVyc2lvbi5cclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiBnZXRIaWdoY2hhcnRzVmVyc2lvbigpIHtcclxuICByZXR1cm4gY2FjaGUuaGNWZXJzaW9uO1xyXG59XHJcblxyXG4vKipcclxuICogVXBkYXRlcyB0aGUgSGlnaGNoYXJ0cyB2ZXJzaW9uIGluIHRoZSBhcHBsaWVkIGNvbmZpZ3VyYXRpb24gYW5kIGNoZWNrc1xyXG4gKiB0aGUgY2FjaGUgZm9yIHRoZSBuZXcgdmVyc2lvbi5cclxuICpcclxuICogQGFzeW5jXHJcbiAqIEBmdW5jdGlvbiB1cGRhdGVIaWdoY2hhcnRzVmVyc2lvblxyXG4gKlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gbmV3VmVyc2lvbiAtIFRoZSBuZXcgSGlnaGNoYXJ0cyB2ZXJzaW9uIHRvIGJlIGFwcGxpZWQuXHJcbiAqL1xyXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gdXBkYXRlSGlnaGNoYXJ0c1ZlcnNpb24obmV3VmVyc2lvbikge1xyXG4gIC8vIEdldCB0aGUgcmVmZXJlbmNlIHRvIHRoZSBnbG9iYWwgb3B0aW9ucyB0byB1cGRhdGUgdG8gdGhlIG5ldyB2ZXJzaW9uXHJcbiAgY29uc3Qgb3B0aW9ucyA9IGdldE9wdGlvbnMoKTtcclxuXHJcbiAgLy8gU2V0IHRvIHRoZSBuZXcgdmVyc2lvblxyXG4gIG9wdGlvbnMuaGlnaGNoYXJ0cy52ZXJzaW9uID0gbmV3VmVyc2lvbjtcclxuXHJcbiAgLy8gQ2hlY2sgaWYgY2FjaGUgbmVlZHMgdG8gYmUgdXBkYXRlZFxyXG4gIGF3YWl0IGNoZWNrQW5kVXBkYXRlQ2FjaGUob3B0aW9ucy5oaWdoY2hhcnRzLCBvcHRpb25zLnNlcnZlci5wcm94eSk7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBFeHRyYWN0cyBIaWdoY2hhcnRzIHZlcnNpb24gZnJvbSB0aGUgY2FjaGUncyBzb3VyY2VzIHN0cmluZy5cclxuICpcclxuICogQGZ1bmN0aW9uIGV4dHJhY3RWZXJzaW9uXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBjYWNoZVNvdXJjZXMgLSBUaGUgY2FjaGUgc291cmNlcyBvYmplY3QuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtzdHJpbmd9IFRoZSBleHRyYWN0ZWQgSGlnaGNoYXJ0cyB2ZXJzaW9uLlxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIGV4dHJhY3RWZXJzaW9uKGNhY2hlU291cmNlcykge1xyXG4gIHJldHVybiBjYWNoZVNvdXJjZXNcclxuICAgIC5zdWJzdHJpbmcoMCwgY2FjaGVTb3VyY2VzLmluZGV4T2YoJyovJykpXHJcbiAgICAucmVwbGFjZSgnLyonLCAnJylcclxuICAgIC5yZXBsYWNlKCcqLycsICcnKVxyXG4gICAgLnJlcGxhY2UoL1xcbi9nLCAnJylcclxuICAgIC50cmltKCk7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBFeHRyYWN0cyB0aGUgSGlnaGNoYXJ0cyBtb2R1bGUgbmFtZSBiYXNlZCBvbiB0aGUgc2NyaXB0UGF0aC5cclxuICpcclxuICogQGZ1bmN0aW9uIGV4dHJhY3RNb2R1bGVOYW1lXHJcbiAqXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSBzY3JpcHRQYXRoIC0gVGhlIHBhdGggb2YgdGhlIHNjcmlwdCBmcm9tIHdoaWNoIHRoZSBtb2R1bGVcclxuICogbmFtZSB3aWxsIGJlIGV4dHJhY3RlZC5cclxuICpcclxuICogQHJldHVybnMge3N0cmluZ30gVGhlIGV4dHJhY3RlZCBtb2R1bGUgbmFtZS5cclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiBleHRyYWN0TW9kdWxlTmFtZShzY3JpcHRQYXRoKSB7XHJcbiAgcmV0dXJuIHNjcmlwdFBhdGgucmVwbGFjZShcclxuICAgIC8oLiopXFwvfCguKiltb2R1bGVzXFwvfHN0b2NrXFwvKC4qKWluZGljYXRvcnNcXC98bWFwc1xcLyguKiltb2R1bGVzXFwvL2dpLFxyXG4gICAgJydcclxuICApO1xyXG59XHJcblxyXG4vKipcclxuICogUmV0cmlldmVzIHRoZSBjdXJyZW50IGNhY2hlIG9iamVjdC5cclxuICpcclxuICogQGZ1bmN0aW9uIGdldENhY2hlXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtPYmplY3R9IFRoZSBjYWNoZSBvYmplY3QgY29udGFpbmluZyB2YXJpb3VzIGNhY2hlZCBkYXRhLlxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIGdldENhY2hlKCkge1xyXG4gIHJldHVybiBjYWNoZTtcclxufVxyXG5cclxuLyoqXHJcbiAqIEdldHMgdGhlIGNhY2hlIHBhdGggZm9yIEhpZ2hjaGFydHMuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBnZXRDYWNoZVBhdGhcclxuICpcclxuICogQHJldHVybnMge3N0cmluZ30gVGhlIGFic29sdXRlIHBhdGggdG8gdGhlIGNhY2hlIGRpcmVjdG9yeSBmb3IgSGlnaGNoYXJ0cy5cclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiBnZXRDYWNoZVBhdGgoKSB7XHJcbiAgcmV0dXJuIGdldEFic29sdXRlUGF0aChnZXRPcHRpb25zKCkuaGlnaGNoYXJ0cy5jYWNoZVBhdGgpOyAvLyAjNTYyXHJcbn1cclxuXHJcbi8qKlxyXG4gKiBGZXRjaGVzIGEgc2luZ2xlIHNjcmlwdCBhbmQgdXBkYXRlcyB0aGUgYGZldGNoZWRNb2R1bGVzYCBhY2NvcmRpbmdseS5cclxuICpcclxuICogQGFzeW5jXHJcbiAqIEBmdW5jdGlvbiBfZmV0Y2hBbmRQcm9jZXNzU2NyaXB0XHJcbiAqXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSBzY3JpcHQgLSBBIHBhdGggdG8gc2NyaXB0IHRvIGdldC5cclxuICogQHBhcmFtIHtPYmplY3R9IHJlcXVlc3RPcHRpb25zIC0gQWRkaXRpb25hbCBvcHRpb25zIGZvciB0aGUgcHJveHkgYWdlbnRcclxuICogdG8gdXNlIGZvciBhIHJlcXVlc3QuXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBmZXRjaGVkTW9kdWxlcyAtIEFuIG9iamVjdCB3aGljaCB0cmFja3Mgd2hpY2ggSGlnaGNoYXJ0c1xyXG4gKiBtb2R1bGVzIGhhdmUgYmVlbiBmZXRjaGVkLlxyXG4gKiBAcGFyYW0ge2Jvb2xlYW59IFtzaG91bGRUaHJvd0Vycm9yPWZhbHNlXSAtIEEgZmxhZyB0byBpbmRpY2F0ZSBpZiB0aGUgZXJyb3JcclxuICogc2hvdWxkIGJlIHRocm93bi4gVGhpcyBzaG91bGQgYmUgdXNlZCBvbmx5IGZvciB0aGUgY29yZSBzY3JpcHRzLiBUaGUgZGVmYXVsdFxyXG4gKiB2YWx1ZSBpcyBmYWxzZS5cclxuICpcclxuICogQHJldHVybnMge1Byb21pc2U8c3RyaW5nPn0gQSBQcm9taXNlIHRoYXQgcmVzb2x2ZXMgdG8gdGhlIHRleHQgcmVwcmVzZW50YXRpb25cclxuICogb2YgdGhlIGZldGNoZWQgc2NyaXB0LlxyXG4gKlxyXG4gKiBAdGhyb3dzIHtFeHBvcnRFcnJvcn0gVGhyb3dzIGFuIGBFeHBvcnRFcnJvcmAgaWYgdGhlcmUgaXMgYSBwcm9ibGVtXHJcbiAqIHdpdGggZmV0Y2hpbmcgdGhlIHNjcmlwdC5cclxuICovXHJcbmFzeW5jIGZ1bmN0aW9uIF9mZXRjaEFuZFByb2Nlc3NTY3JpcHQoXHJcbiAgc2NyaXB0LFxyXG4gIHJlcXVlc3RPcHRpb25zLFxyXG4gIGZldGNoZWRNb2R1bGVzLFxyXG4gIHNob3VsZFRocm93RXJyb3IgPSBmYWxzZVxyXG4pIHtcclxuICAvLyBHZXQgcmlkIG9mIHRoZSAuanMgZnJvbSB0aGUgY3VzdG9tIHN0cmluZ3NcclxuICBpZiAoc2NyaXB0LmVuZHNXaXRoKCcuanMnKSkge1xyXG4gICAgc2NyaXB0ID0gc2NyaXB0LnN1YnN0cmluZygwLCBzY3JpcHQubGVuZ3RoIC0gMyk7XHJcbiAgfVxyXG4gIGxvZyg0LCBgW2NhY2hlXSBGZXRjaGluZyBzY3JpcHQgLSAke3NjcmlwdH0uanNgKTtcclxuXHJcbiAgLy8gRmV0Y2ggdGhlIHNjcmlwdFxyXG4gIGNvbnN0IHJlc3BvbnNlID0gYXdhaXQgZmV0Y2goYCR7c2NyaXB0fS5qc2AsIHJlcXVlc3RPcHRpb25zKTtcclxuXHJcbiAgLy8gSWYgT0ssIHJldHVybiBpdHMgdGV4dCByZXByZXNlbnRhdGlvblxyXG4gIGlmIChyZXNwb25zZS5zdGF0dXNDb2RlID09PSAyMDAgJiYgdHlwZW9mIHJlc3BvbnNlLnRleHQgPT0gJ3N0cmluZycpIHtcclxuICAgIGlmIChmZXRjaGVkTW9kdWxlcykge1xyXG4gICAgICBjb25zdCBtb2R1bGVOYW1lID0gZXh0cmFjdE1vZHVsZU5hbWUoc2NyaXB0KTtcclxuICAgICAgZmV0Y2hlZE1vZHVsZXNbbW9kdWxlTmFtZV0gPSAxO1xyXG4gICAgfVxyXG4gICAgcmV0dXJuIHJlc3BvbnNlLnRleHQ7XHJcbiAgfVxyXG5cclxuICAvLyBCYXNlZCBvbiB0aGUgYHNob3VsZFRocm93RXJyb3JgIGZsYWcsIGRlY2lkZSBob3cgdG8gc2VydmUgZXJyb3IgbWVzc2FnZVxyXG4gIGlmIChzaG91bGRUaHJvd0Vycm9yKSB7XHJcbiAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoXHJcbiAgICAgIGBbY2FjaGVdIENvdWxkIG5vdCBmZXRjaCB0aGUgJHtzY3JpcHR9LmpzLiBUaGUgc2NyaXB0IG1pZ2h0IG5vdCBleGlzdCBpbiB0aGUgcmVxdWVzdGVkIHZlcnNpb24gKHN0YXR1cyBjb2RlOiAke3Jlc3BvbnNlLnN0YXR1c0NvZGV9KS5gLFxyXG4gICAgICA0MDRcclxuICAgICkuc2V0RXJyb3IocmVzcG9uc2UpO1xyXG4gIH0gZWxzZSB7XHJcbiAgICBsb2coXHJcbiAgICAgIDIsXHJcbiAgICAgIGBbY2FjaGVdIENvdWxkIG5vdCBmZXRjaCB0aGUgJHtzY3JpcHR9LmpzLiBUaGUgc2NyaXB0IG1pZ2h0IG5vdCBleGlzdCBpbiB0aGUgcmVxdWVzdGVkIHZlcnNpb24uYFxyXG4gICAgKTtcclxuICB9XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBTYXZlcyB0aGUgcHJvdmlkZWQgY29uZmlndXJhdGlvbiBhbmQgZmV0Y2hlZCBtb2R1bGVzIHRvIHRoZSBjYWNoZSBtYW5pZmVzdFxyXG4gKiBmaWxlLlxyXG4gKlxyXG4gKiBAYXN5bmNcclxuICogQGZ1bmN0aW9uIF9zYXZlQ29uZmlnVG9NYW5pZmVzdFxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gaGlnaGNoYXJ0c09wdGlvbnMgLSBPYmplY3QgY29udGFpbmluZyBgaGlnaGNoYXJ0c2Agb3B0aW9ucy5cclxuICogQHBhcmFtIHtPYmplY3R9IFtmZXRjaGVkTW9kdWxlcz17fV0gLSBBbiBvYmplY3Qgd2hpY2ggdHJhY2tzIHdoaWNoIEhpZ2hjaGFydHNcclxuICogbW9kdWxlcyBoYXZlIGJlZW4gZmV0Y2hlZC4gVGhlIGRlZmF1bHQgdmFsdWUgaXMgYW4gZW1wdHkgb2JqZWN0LlxyXG4gKlxyXG4gKiBAdGhyb3dzIHtFeHBvcnRFcnJvcn0gVGhyb3dzIGFuIGBFeHBvcnRFcnJvcmAgaWYgYW4gZXJyb3Igb2NjdXJzIHdoaWxlXHJcbiAqIHdyaXRpbmcgdGhlIGNhY2hlIG1hbmlmZXN0LlxyXG4gKi9cclxuYXN5bmMgZnVuY3Rpb24gX3NhdmVDb25maWdUb01hbmlmZXN0KGhpZ2hjaGFydHNPcHRpb25zLCBmZXRjaGVkTW9kdWxlcyA9IHt9KSB7XHJcbiAgY29uc3QgbmV3TWFuaWZlc3QgPSB7XHJcbiAgICB2ZXJzaW9uOiBoaWdoY2hhcnRzT3B0aW9ucy52ZXJzaW9uLFxyXG4gICAgbW9kdWxlczogZmV0Y2hlZE1vZHVsZXNcclxuICB9O1xyXG5cclxuICAvLyBVcGRhdGUgY2FjaGUgb2JqZWN0IHdpdGggdGhlIGN1cnJlbnQgbW9kdWxlc1xyXG4gIGNhY2hlLmFjdGl2ZU1hbmlmZXN0ID0gbmV3TWFuaWZlc3Q7XHJcblxyXG4gIGxvZygzLCAnW2NhY2hlXSBXcml0aW5nIGEgbmV3IG1hbmlmZXN0LicpO1xyXG4gIHRyeSB7XHJcbiAgICB3cml0ZUZpbGVTeW5jKFxyXG4gICAgICBqb2luKGdldENhY2hlUGF0aCgpLCAnbWFuaWZlc3QuanNvbicpLFxyXG4gICAgICBKU09OLnN0cmluZ2lmeShuZXdNYW5pZmVzdCksXHJcbiAgICAgICd1dGY4J1xyXG4gICAgKTtcclxuICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgdGhyb3cgbmV3IEV4cG9ydEVycm9yKFxyXG4gICAgICAnW2NhY2hlXSBFcnJvciB3cml0aW5nIHRoZSBjYWNoZSBtYW5pZmVzdC4nLFxyXG4gICAgICA1MDBcclxuICAgICkuc2V0RXJyb3IoZXJyb3IpO1xyXG4gIH1cclxufVxyXG5cclxuLyoqXHJcbiAqIEZldGNoZXMgSGlnaGNoYXJ0cyBgc2NyaXB0c2AgYW5kIGBjdXN0b21TY3JpcHRzYCBmcm9tIHRoZSBnaXZlbiBDRE5zLlxyXG4gKlxyXG4gKiBAYXN5bmNcclxuICogQGZ1bmN0aW9uIF9mZXRjaFNjcmlwdHNcclxuICpcclxuICogQHBhcmFtIHtBcnJheS48c3RyaW5nPn0gY29yZVNjcmlwdHMgLSBIaWdoY2hhcnRzIGNvcmUgc2NyaXB0cyB0byBmZXRjaC5cclxuICogQHBhcmFtIHtBcnJheS48c3RyaW5nPn0gbW9kdWxlU2NyaXB0cyAtIEhpZ2hjaGFydHMgbW9kdWxlcyB0byBmZXRjaC5cclxuICogQHBhcmFtIHtBcnJheS48c3RyaW5nPn0gY3VzdG9tU2NyaXB0cyAtIEN1c3RvbSBzY3JpcHQgcGF0aHMgdG8gZmV0Y2ggKGZ1bGxcclxuICogVVJMcykuXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBzZXJ2ZXJQcm94eU9wdGlvbnMgLSBPYmplY3QgY29udGFpbmluZyBgc2VydmVyLnByb3h5YFxyXG4gKiBvcHRpb25zLlxyXG4gKiBAcGFyYW0ge09iamVjdH0gZmV0Y2hlZE1vZHVsZXMgLSBBbiBvYmplY3Qgd2hpY2ggdHJhY2tzIHdoaWNoIEhpZ2hjaGFydHNcclxuICogbW9kdWxlcyBoYXZlIGJlZW4gZmV0Y2hlZC5cclxuICpcclxuICogQHJldHVybnMge1Byb21pc2U8c3RyaW5nPn0gQSBQcm9taXNlIHRoYXQgcmVzb2x2ZXMgdG8gdGhlIGZldGNoZWQgc2NyaXB0c1xyXG4gKiBjb250ZW50IGpvaW5lZC5cclxuICpcclxuICogQHRocm93cyB7RXhwb3J0RXJyb3J9IFRocm93cyBhbiBgRXhwb3J0RXJyb3JgIGlmIGFuIGVycm9yIG9jY3VycyB3aGlsZVxyXG4gKiBzZXR0aW5nIGFuIEhUVFAgQWdlbnQgZm9yIHByb3h5LlxyXG4gKi9cclxuYXN5bmMgZnVuY3Rpb24gX2ZldGNoU2NyaXB0cyhcclxuICBjb3JlU2NyaXB0cyxcclxuICBtb2R1bGVTY3JpcHRzLFxyXG4gIGN1c3RvbVNjcmlwdHMsXHJcbiAgc2VydmVyUHJveHlPcHRpb25zLFxyXG4gIGZldGNoZWRNb2R1bGVzXHJcbikge1xyXG4gIC8vIENvbmZpZ3VyZSBwcm94eSBpZiBleGlzdHNcclxuICBsZXQgcHJveHlBZ2VudDtcclxuICBjb25zdCBwcm94eUhvc3QgPSBzZXJ2ZXJQcm94eU9wdGlvbnMuaG9zdDtcclxuICBjb25zdCBwcm94eVBvcnQgPSBzZXJ2ZXJQcm94eU9wdGlvbnMucG9ydDtcclxuXHJcbiAgLy8gVHJ5IHRvIGNyZWF0ZSBhIFByb3h5IEFnZW50XHJcbiAgaWYgKHByb3h5SG9zdCAmJiBwcm94eVBvcnQpIHtcclxuICAgIHRyeSB7XHJcbiAgICAgIHByb3h5QWdlbnQgPSBuZXcgSHR0cHNQcm94eUFnZW50KHtcclxuICAgICAgICBob3N0OiBwcm94eUhvc3QsXHJcbiAgICAgICAgcG9ydDogcHJveHlQb3J0XHJcbiAgICAgIH0pO1xyXG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICAgdGhyb3cgbmV3IEV4cG9ydEVycm9yKFxyXG4gICAgICAgICdbY2FjaGVdIENvdWxkIG5vdCBjcmVhdGUgYSBQcm94eSBBZ2VudC4nLFxyXG4gICAgICAgIDUwMFxyXG4gICAgICApLnNldEVycm9yKGVycm9yKTtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIC8vIElmIGV4aXN0cywgYWRkIHByb3h5IGFnZW50IHRvIHJlcXVlc3Qgb3B0aW9uc1xyXG4gIGNvbnN0IHJlcXVlc3RPcHRpb25zID0gcHJveHlBZ2VudFxyXG4gICAgPyB7XHJcbiAgICAgICAgYWdlbnQ6IHByb3h5QWdlbnQsXHJcbiAgICAgICAgdGltZW91dDogc2VydmVyUHJveHlPcHRpb25zLnRpbWVvdXRcclxuICAgICAgfVxyXG4gICAgOiB7fTtcclxuXHJcbiAgY29uc3QgYWxsRmV0Y2hQcm9taXNlcyA9IFtcclxuICAgIC4uLmNvcmVTY3JpcHRzLm1hcCgoc2NyaXB0KSA9PlxyXG4gICAgICBfZmV0Y2hBbmRQcm9jZXNzU2NyaXB0KGAke3NjcmlwdH1gLCByZXF1ZXN0T3B0aW9ucywgZmV0Y2hlZE1vZHVsZXMsIHRydWUpXHJcbiAgICApLFxyXG4gICAgLi4ubW9kdWxlU2NyaXB0cy5tYXAoKHNjcmlwdCkgPT5cclxuICAgICAgX2ZldGNoQW5kUHJvY2Vzc1NjcmlwdChgJHtzY3JpcHR9YCwgcmVxdWVzdE9wdGlvbnMsIGZldGNoZWRNb2R1bGVzKVxyXG4gICAgKSxcclxuICAgIC4uLmN1c3RvbVNjcmlwdHMubWFwKChzY3JpcHQpID0+XHJcbiAgICAgIF9mZXRjaEFuZFByb2Nlc3NTY3JpcHQoYCR7c2NyaXB0fWAsIHJlcXVlc3RPcHRpb25zKVxyXG4gICAgKVxyXG4gIF07XHJcblxyXG4gIGNvbnN0IGZldGNoZWRTY3JpcHRzID0gYXdhaXQgUHJvbWlzZS5hbGwoYWxsRmV0Y2hQcm9taXNlcyk7XHJcbiAgcmV0dXJuIGZldGNoZWRTY3JpcHRzLmpvaW4oJztcXG4nKTtcclxufVxyXG5cclxuLyoqXHJcbiAqIFVwZGF0ZXMgdGhlIGxvY2FsIGNhY2hlIHdpdGggSGlnaGNoYXJ0cyBzY3JpcHRzIGFuZCB0aGVpciB2ZXJzaW9ucy5cclxuICpcclxuICogQGFzeW5jXHJcbiAqIEBmdW5jdGlvbiBfdXBkYXRlQ2FjaGVcclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IGhpZ2hjaGFydHNPcHRpb25zIC0gT2JqZWN0IGNvbnRhaW5pbmcgYGhpZ2hjaGFydHNgIG9wdGlvbnMuXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBzZXJ2ZXJQcm94eU9wdGlvbnMgLSBPYmplY3QgY29udGFpbmluZyBgc2VydmVyLnByb3h5YFxyXG4gKiBvcHRpb25zLlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gc291cmNlUGF0aCAtIFRoZSBwYXRoIHRvIHRoZSBzb3VyY2UgZmlsZSBpbiB0aGUgY2FjaGUuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtQcm9taXNlPE9iamVjdD59IEEgUHJvbWlzZSB0aGF0IHJlc29sdmVzIHRvIGFuIG9iamVjdCByZXByZXNlbnRpbmdcclxuICogdGhlIGZldGNoZWQgbW9kdWxlcy5cclxuICpcclxuICogQHRocm93cyB7RXhwb3J0RXJyb3J9IFRocm93cyBhbiBgRXhwb3J0RXJyb3JgIGlmIHRoZXJlIGlzIGFuIGlzc3VlIHVwZGF0aW5nXHJcbiAqIHRoZSBsb2NhbCBIaWdoY2hhcnRzIGNhY2hlLlxyXG4gKi9cclxuYXN5bmMgZnVuY3Rpb24gX3VwZGF0ZUNhY2hlKGhpZ2hjaGFydHNPcHRpb25zLCBzZXJ2ZXJQcm94eU9wdGlvbnMsIHNvdXJjZVBhdGgpIHtcclxuICAvLyBHZXQgSGlnaGNoYXJ0cyB2ZXJzaW9uIGZvciBzY3JpcHRzXHJcbiAgY29uc3QgaGNWZXJzaW9uID1cclxuICAgIGhpZ2hjaGFydHNPcHRpb25zLnZlcnNpb24gPT09ICdsYXRlc3QnXHJcbiAgICAgID8gbnVsbFxyXG4gICAgICA6IGAke2hpZ2hjaGFydHNPcHRpb25zLnZlcnNpb259YDtcclxuXHJcbiAgLy8gR2V0IHRoZSBDRE4gdXJsIGZvciBzY3JpcHRzXHJcbiAgY29uc3QgY2RuVXJsID0gaGlnaGNoYXJ0c09wdGlvbnMuY2RuVXJsIHx8IGNhY2hlLmNkblVybDtcclxuXHJcbiAgdHJ5IHtcclxuICAgIGNvbnN0IGZldGNoZWRNb2R1bGVzID0ge307XHJcblxyXG4gICAgbG9nKFxyXG4gICAgICAzLFxyXG4gICAgICBgW2NhY2hlXSBVcGRhdGluZyBjYWNoZSB2ZXJzaW9uIHRvIEhpZ2hjaGFydHM6ICR7aGNWZXJzaW9uIHx8ICdsYXRlc3QnfS5gXHJcbiAgICApO1xyXG5cclxuICAgIGNhY2hlLnNvdXJjZXMgPSBhd2FpdCBfZmV0Y2hTY3JpcHRzKFxyXG4gICAgICBbXHJcbiAgICAgICAgLi4uaGlnaGNoYXJ0c09wdGlvbnMuY29yZVNjcmlwdHMubWFwKChjKSA9PlxyXG4gICAgICAgICAgaGNWZXJzaW9uID8gYCR7Y2RuVXJsfS8ke2hjVmVyc2lvbn0vJHtjfWAgOiBgJHtjZG5Vcmx9LyR7Y31gXHJcbiAgICAgICAgKVxyXG4gICAgICBdLFxyXG4gICAgICBbXHJcbiAgICAgICAgLi4uaGlnaGNoYXJ0c09wdGlvbnMubW9kdWxlU2NyaXB0cy5tYXAoKG0pID0+XHJcbiAgICAgICAgICBtID09PSAnbWFwJ1xyXG4gICAgICAgICAgICA/IGhjVmVyc2lvblxyXG4gICAgICAgICAgICAgID8gYCR7Y2RuVXJsfS9tYXBzLyR7aGNWZXJzaW9ufS9tb2R1bGVzLyR7bX1gXHJcbiAgICAgICAgICAgICAgOiBgJHtjZG5Vcmx9L21hcHMvbW9kdWxlcy8ke219YFxyXG4gICAgICAgICAgICA6IGhjVmVyc2lvblxyXG4gICAgICAgICAgICAgID8gYCR7Y2RuVXJsfS8ke2hjVmVyc2lvbn0vbW9kdWxlcy8ke219YFxyXG4gICAgICAgICAgICAgIDogYCR7Y2RuVXJsfS9tb2R1bGVzLyR7bX1gXHJcbiAgICAgICAgKSxcclxuICAgICAgICAuLi5oaWdoY2hhcnRzT3B0aW9ucy5pbmRpY2F0b3JTY3JpcHRzLm1hcCgoaSkgPT5cclxuICAgICAgICAgIGhjVmVyc2lvblxyXG4gICAgICAgICAgICA/IGAke2NkblVybH0vc3RvY2svJHtoY1ZlcnNpb259L2luZGljYXRvcnMvJHtpfWBcclxuICAgICAgICAgICAgOiBgJHtjZG5Vcmx9L3N0b2NrL2luZGljYXRvcnMvJHtpfWBcclxuICAgICAgICApXHJcbiAgICAgIF0sXHJcbiAgICAgIGhpZ2hjaGFydHNPcHRpb25zLmN1c3RvbVNjcmlwdHMsXHJcbiAgICAgIHNlcnZlclByb3h5T3B0aW9ucyxcclxuICAgICAgZmV0Y2hlZE1vZHVsZXNcclxuICAgICk7XHJcblxyXG4gICAgLy8gRXh0cmFjdCBhbmQgc2F2ZSB2ZXJzaW9uIG9mIGN1cnJlbnRseSB1c2VkIEhpZ2hjaGFydHNcclxuICAgIGNhY2hlLmhjVmVyc2lvbiA9IGV4dHJhY3RWZXJzaW9uKGNhY2hlLnNvdXJjZXMpO1xyXG5cclxuICAgIC8vIFNhdmUgdGhlIGZldGNoZWQgbW9kdWxlcyBpbnRvIGNhY2hlcycgc291cmNlIEpTT05cclxuICAgIHdyaXRlRmlsZVN5bmMoc291cmNlUGF0aCwgY2FjaGUuc291cmNlcyk7XHJcbiAgICByZXR1cm4gZmV0Y2hlZE1vZHVsZXM7XHJcbiAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcihcclxuICAgICAgJ1tjYWNoZV0gVW5hYmxlIHRvIHVwZGF0ZSB0aGUgbG9jYWwgSGlnaGNoYXJ0cyBjYWNoZS4nLFxyXG4gICAgICA1MDBcclxuICAgICkuc2V0RXJyb3IoZXJyb3IpO1xyXG4gIH1cclxufVxyXG5cclxuZXhwb3J0IGRlZmF1bHQge1xyXG4gIGNoZWNrQW5kVXBkYXRlQ2FjaGUsXHJcbiAgZ2V0SGlnaGNoYXJ0c1ZlcnNpb24sXHJcbiAgdXBkYXRlSGlnaGNoYXJ0c1ZlcnNpb24sXHJcbiAgZXh0cmFjdFZlcnNpb24sXHJcbiAgZXh0cmFjdE1vZHVsZU5hbWUsXHJcbiAgZ2V0Q2FjaGUsXHJcbiAgZ2V0Q2FjaGVQYXRoXHJcbn07XHJcbiIsIi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXHJcblxyXG5IaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXJcclxuXHJcbkNvcHlyaWdodCAoYykgMjAxNi0yMDI1LCBIaWdoc29mdFxyXG5cclxuTGljZW5jZWQgdW5kZXIgdGhlIE1JVCBsaWNlbmNlLlxyXG5cclxuQWRkaXRpb25hbGx5IGEgdmFsaWQgSGlnaGNoYXJ0cyBsaWNlbnNlIGlzIHJlcXVpcmVkIGZvciB1c2UuXHJcblxyXG5TZWUgTElDRU5TRSBmaWxlIGluIHJvb3QgZm9yIGRldGFpbHMuXHJcblxyXG4qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xyXG5cclxuLyoqXHJcbiAqIEBvdmVydmlldyBQcm92aWRlcyBtZXRob2RzIGZvciBpbml0aWFsaXppbmcgSGlnaGNoYXJ0cyB3aXRoIGN1c3RvbWl6ZWRcclxuICogYW5pbWF0aW9uIHNldHRpbmdzIGFuZCB0cmlnZ2VyaW5nIHRoZSBjcmVhdGlvbiBvZiBIaWdoY2hhcnRzIGNoYXJ0cyB3aXRoXHJcbiAqIGV4cG9ydC1zcGVjaWZpYyBjb25maWd1cmF0aW9ucyBpbiB0aGUgcGFnZSBjb250ZXh0LiBTdXBwb3J0cyBkeW5hbWljIG9wdGlvblxyXG4gKiBtZXJnaW5nLCBjdXN0b20gbG9naWMgaW5qZWN0aW9uLCBhbmQgY29udHJvbCBvdmVyIHJlbmRlcmluZyBiZWhhdmlvcnMuIFVzZWRcclxuICogYnkgdGhlIFB1cHBldGVlciBwYWdlLlxyXG4gKi9cclxuXHJcbi8qIGVzbGludC1kaXNhYmxlIG5vLXVuZGVmICovXHJcblxyXG4vKipcclxuICogU2V0dGluZyB0aGUgYEhpZ2hjaGFydHMuYW5pbU9iamVjdGAgZnVuY3Rpb24uIENhbGxlZCB3aGVuIGluaXRpbmcgdGhlIHBhZ2UuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBzZXR1cEhpZ2hjaGFydHNcclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiBzZXR1cEhpZ2hjaGFydHMoKSB7XHJcbiAgSGlnaGNoYXJ0cy5hbmltT2JqZWN0ID0gZnVuY3Rpb24gKCkge1xyXG4gICAgcmV0dXJuIHsgZHVyYXRpb246IDAgfTtcclxuICB9O1xyXG59XHJcblxyXG4vKipcclxuICogQ3JlYXRlcyB0aGUgYWN0dWFsIEhpZ2hjaGFydHMgY2hhcnQgb24gYSBwYWdlLlxyXG4gKlxyXG4gKiBAYXN5bmNcclxuICogQGZ1bmN0aW9uIGNyZWF0ZUNoYXJ0XHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBvcHRpb25zIC0gVGhlIGBvcHRpb25zYCBvYmplY3QgY29udGFpbmluZyBjb21wbGV0ZSBzZXRcclxuICogb2Ygb3B0aW9ucy5cclxuICovXHJcbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBjcmVhdGVDaGFydChvcHRpb25zKSB7XHJcbiAgLy8gR2V0IHJlcXVpcmVkIGZ1bmN0aW9uc1xyXG4gIGNvbnN0IHsgZ2V0T3B0aW9ucywgbWVyZ2UsIHNldE9wdGlvbnMsIHdyYXAgfSA9IEhpZ2hjaGFydHM7XHJcblxyXG4gIC8vIENyZWF0ZSBhIHNlcGFyYXRlIG9iamVjdCBmb3IgYSBwb3RlbnRpYWwgYHNldE9wdGlvbnNgIHVzYWdlcyBpbiBvcmRlclxyXG4gIC8vIHRvIHByZXZlbnQgZnJvbSBwb2xsdXRpbmcgb3RoZXIgZXhwb3J0cyB0aGF0IGNhbiBoYXBwZW4gb24gdGhlIHNhbWUgcGFnZVxyXG4gIEhpZ2hjaGFydHMuc2V0T3B0aW9uc09iaiA9IG1lcmdlKGZhbHNlLCB7fSwgZ2V0T3B0aW9ucygpKTtcclxuXHJcbiAgLy8gTk9URTogSXMgdGhpcyB1c2VkIGZvciBhbnl0aGluZyB1c2VmdWw/XHJcbiAgd2luZG93LmlzUmVuZGVyQ29tcGxldGUgPSBmYWxzZTtcclxuICB3cmFwKEhpZ2hjaGFydHMuQ2hhcnQucHJvdG90eXBlLCAnaW5pdCcsIGZ1bmN0aW9uIChwcm9jZWVkLCB1c2VyT3B0aW9ucywgY2IpIHtcclxuICAgIC8vIE92ZXJyaWRlIHVzZXJPcHRpb25zIHdpdGggaW1hZ2UgZnJpZW5kbHkgb3B0aW9uc1xyXG4gICAgdXNlck9wdGlvbnMgPSBtZXJnZSh1c2VyT3B0aW9ucywge1xyXG4gICAgICBleHBvcnRpbmc6IHtcclxuICAgICAgICBlbmFibGVkOiBmYWxzZVxyXG4gICAgICB9LFxyXG4gICAgICBwbG90T3B0aW9uczoge1xyXG4gICAgICAgIHNlcmllczoge1xyXG4gICAgICAgICAgbGFiZWw6IHtcclxuICAgICAgICAgICAgZW5hYmxlZDogZmFsc2VcclxuICAgICAgICAgIH1cclxuICAgICAgICB9XHJcbiAgICAgIH0sXHJcbiAgICAgIC8qIEV4cGVjdHMgdG9vbHRpcCBpbiB1c2VyT3B0aW9ucyB3aGVuIGZvckV4cG9ydCBpcyB0cnVlLlxyXG4gICAgICAgIGh0dHBzOi8vZ2l0aHViLmNvbS9oaWdoY2hhcnRzL2hpZ2hjaGFydHMvYmxvYi8zYWQ0MzBhMzUzYjgwNTZiOWU3NjRhYTRlNWNkNjgyOGFhNDc5ZGIyL2pzL3BhcnRzL0NoYXJ0LmpzI0wyNDFcclxuICAgICAgICAqL1xyXG4gICAgICB0b29sdGlwOiB7fVxyXG4gICAgfSk7XHJcblxyXG4gICAgKHVzZXJPcHRpb25zLnNlcmllcyB8fCBbXSkuZm9yRWFjaChmdW5jdGlvbiAoc2VyaWVzKSB7XHJcbiAgICAgIHNlcmllcy5hbmltYXRpb24gPSBmYWxzZTtcclxuICAgIH0pO1xyXG5cclxuICAgIC8vIEFkZCBmbGFnIHRvIGtub3cgaWYgY2hhcnQgcmVuZGVyIGhhcyBiZWVuIGNhbGxlZC5cclxuICAgIGlmICghd2luZG93Lm9uSGlnaGNoYXJ0c1JlbmRlcikge1xyXG4gICAgICB3aW5kb3cub25IaWdoY2hhcnRzUmVuZGVyID0gSGlnaGNoYXJ0cy5hZGRFdmVudCh0aGlzLCAncmVuZGVyJywgKCkgPT4ge1xyXG4gICAgICAgIHdpbmRvdy5pc1JlbmRlckNvbXBsZXRlID0gdHJ1ZTtcclxuICAgICAgfSk7XHJcbiAgICB9XHJcblxyXG4gICAgcHJvY2VlZC5hcHBseSh0aGlzLCBbdXNlck9wdGlvbnMsIGNiXSk7XHJcbiAgfSk7XHJcblxyXG4gIHdyYXAoSGlnaGNoYXJ0cy5TZXJpZXMucHJvdG90eXBlLCAnaW5pdCcsIGZ1bmN0aW9uIChwcm9jZWVkLCBjaGFydCwgb3B0aW9ucykge1xyXG4gICAgcHJvY2VlZC5hcHBseSh0aGlzLCBbY2hhcnQsIG9wdGlvbnNdKTtcclxuICB9KTtcclxuXHJcbiAgLy8gU29tZSBtYW5kYXRvcnkgYWRkaXRpb25hbCBgY2hhcnRgIGFuZCBgZXhwb3J0aW5nYCBvcHRpb25zXHJcbiAgY29uc3QgYWRkaXRpb25hbE9wdGlvbnMgPSB7XHJcbiAgICBjaGFydDoge1xyXG4gICAgICAvLyBCeSBkZWZhdWx0IGFuaW1hdGlvbiBpcyBkaXNhYmxlZFxyXG4gICAgICBhbmltYXRpb246IGZhbHNlLFxyXG4gICAgICAvLyBHZXQgdGhlIHJpZ2h0IHNpemUgdmFsdWVzXHJcbiAgICAgIGhlaWdodDogb3B0aW9ucy5leHBvcnQuaGVpZ2h0LFxyXG4gICAgICB3aWR0aDogb3B0aW9ucy5leHBvcnQud2lkdGhcclxuICAgIH0sXHJcbiAgICBleHBvcnRpbmc6IHtcclxuICAgICAgLy8gTm8gbmVlZCBmb3IgdGhlIGV4cG9ydGluZyBidXR0b25cclxuICAgICAgZW5hYmxlZDogZmFsc2VcclxuICAgIH1cclxuICB9O1xyXG5cclxuICAvLyBHZXQgdGhlIGlucHV0IHRvIGV4cG9ydCBmcm9tIHRoZSBgaW5zdHJgIG9wdGlvblxyXG4gIGNvbnN0IHVzZXJPcHRpb25zID0gbmV3IEZ1bmN0aW9uKGByZXR1cm4gJHtvcHRpb25zLmV4cG9ydC5pbnN0cn1gKSgpO1xyXG5cclxuICAvLyBHZXQgdGhlIGB0aGVtZU9wdGlvbnNgIG9wdGlvblxyXG4gIGNvbnN0IHRoZW1lT3B0aW9ucyA9IG5ldyBGdW5jdGlvbihgcmV0dXJuICR7b3B0aW9ucy5leHBvcnQudGhlbWVPcHRpb25zfWApKCk7XHJcblxyXG4gIC8vIEdldCB0aGUgYGdsb2JhbE9wdGlvbnNgIG9wdGlvblxyXG4gIGNvbnN0IGdsb2JhbE9wdGlvbnMgPSBuZXcgRnVuY3Rpb24oXHJcbiAgICBgcmV0dXJuICR7b3B0aW9ucy5leHBvcnQuZ2xvYmFsT3B0aW9uc31gXHJcbiAgKSgpO1xyXG5cclxuICAvLyBNZXJnZSB0aGUgZm9sbG93aW5nIG9wdGlvbnMgb2JqZWN0cyB0byBjcmVhdGUgZmluYWwgb3B0aW9uc1xyXG4gIGNvbnN0IGZpbmFsT3B0aW9ucyA9IG1lcmdlKFxyXG4gICAgZmFsc2UsXHJcbiAgICB0aGVtZU9wdGlvbnMsXHJcbiAgICB1c2VyT3B0aW9ucyxcclxuICAgIC8vIFBsYWNlZCBpdCBoZXJlIGluc3RlYWQgaW4gdGhlIGluaXQgYmVjYXVzZSBvZiB0aGUgc2l6ZSBpc3N1ZXNcclxuICAgIGFkZGl0aW9uYWxPcHRpb25zXHJcbiAgKTtcclxuXHJcbiAgLy8gUHJlcGFyZSB0aGUgYGNhbGxiYWNrYCBvcHRpb25cclxuICBjb25zdCBmaW5hbENhbGxiYWNrID0gb3B0aW9ucy5jdXN0b21Mb2dpYy5jYWxsYmFja1xyXG4gICAgPyBuZXcgRnVuY3Rpb24oYHJldHVybiAke29wdGlvbnMuY3VzdG9tTG9naWMuY2FsbGJhY2t9YCkoKVxyXG4gICAgOiBudWxsO1xyXG5cclxuICAvLyBUcmlnZ2VyIHRoZSBgY3VzdG9tQ29kZWAgb3B0aW9uXHJcbiAgaWYgKG9wdGlvbnMuY3VzdG9tTG9naWMuY3VzdG9tQ29kZSkge1xyXG4gICAgbmV3IEZ1bmN0aW9uKCdvcHRpb25zJywgb3B0aW9ucy5jdXN0b21Mb2dpYy5jdXN0b21Db2RlKSh1c2VyT3B0aW9ucyk7XHJcbiAgfVxyXG5cclxuICAvLyBTZXQgdGhlIGdsb2JhbCBvcHRpb25zIGlmIGV4aXN0XHJcbiAgaWYgKGdsb2JhbE9wdGlvbnMpIHtcclxuICAgIHNldE9wdGlvbnMoZ2xvYmFsT3B0aW9ucyk7XHJcbiAgfVxyXG5cclxuICAvLyBDYWxsIHRoZSBjaGFydCBjcmVhdGlvblxyXG4gIEhpZ2hjaGFydHNbb3B0aW9ucy5leHBvcnQuY29uc3RyXSgnY29udGFpbmVyJywgZmluYWxPcHRpb25zLCBmaW5hbENhbGxiYWNrKTtcclxuXHJcbiAgLy8gR2V0IHRoZSBjdXJyZW50IGdsb2JhbCBvcHRpb25zXHJcbiAgY29uc3QgZGVmYXVsdE9wdGlvbnMgPSBnZXRPcHRpb25zKCk7XHJcblxyXG4gIC8vIENsZWFyIGl0IGp1c3QgaW4gY2FzZSAoZS5nLiB0aGUgYHNldE9wdGlvbnNgIHdhcyB1c2VkIGluIHRoZSBgY3VzdG9tQ29kZWApXHJcbiAgZm9yIChjb25zdCBwcm9wIGluIGRlZmF1bHRPcHRpb25zKSB7XHJcbiAgICBpZiAodHlwZW9mIGRlZmF1bHRPcHRpb25zW3Byb3BdICE9PSAnZnVuY3Rpb24nKSB7XHJcbiAgICAgIGRlbGV0ZSBkZWZhdWx0T3B0aW9uc1twcm9wXTtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIC8vIFNldCB0aGUgZGVmYXVsdCBvcHRpb25zIGJhY2tcclxuICBzZXRPcHRpb25zKEhpZ2hjaGFydHMuc2V0T3B0aW9uc09iaik7XHJcblxyXG4gIC8vIEVtcHR5IHRoZSBjdXN0b20gZ2xvYmFsIG9wdGlvbnMgb2JqZWN0XHJcbiAgSGlnaGNoYXJ0cy5zZXRPcHRpb25zT2JqID0ge307XHJcbn1cclxuXHJcbmV4cG9ydCBkZWZhdWx0IHtcclxuICBzZXR1cEhpZ2hjaGFydHMsXHJcbiAgY3JlYXRlQ2hhcnRcclxufTtcclxuIiwiLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcclxuXHJcbkhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlclxyXG5cclxuQ29weXJpZ2h0IChjKSAyMDE2LTIwMjUsIEhpZ2hzb2Z0XHJcblxyXG5MaWNlbmNlZCB1bmRlciB0aGUgTUlUIGxpY2VuY2UuXHJcblxyXG5BZGRpdGlvbmFsbHkgYSB2YWxpZCBIaWdoY2hhcnRzIGxpY2Vuc2UgaXMgcmVxdWlyZWQgZm9yIHVzZS5cclxuXHJcblNlZSBMSUNFTlNFIGZpbGUgaW4gcm9vdCBmb3IgZGV0YWlscy5cclxuXHJcbioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXHJcblxyXG4vKipcclxuICogQG92ZXJ2aWV3IFRoaXMgbW9kdWxlIHByb3ZpZGVzIGZ1bmN0aW9ucyBmb3IgbWFuYWdpbmcgUHVwcGV0ZWVyIGJyb3dzZXJcclxuICogaW5zdGFuY2UsIGNyZWF0aW5nIGFuZCBjbGVhcmluZyBwYWdlcywgaW5qZWN0aW5nIGN1c3RvbSByZXNvdXJjZXMsXHJcbiAqIGFuZCBzZXR0aW5nIHVwIEhpZ2hjaGFydHMgZm9yIHNlcnZlci1zaWRlIHJlbmRlcmluZy4gVGhlIG1vZHVsZSBlbnN1cmVzXHJcbiAqIHRoYXQgcmVzb3VyY2VzIGFyZSBjb3JyZWN0bHkgbWFuYWdlZCBhbmQgY2FuIGhhbmRsZSBmYWlsdXJlcyBkdXJpbmdcclxuICogb3BlcmF0aW9ucyBsaWtlIGxhdW5jaGluZyB0aGUgYnJvd3NlciBvciBjcmVhdGluZyBuZXcgcGFnZXMuXHJcbiAqL1xyXG5cclxuaW1wb3J0IHsgcmVhZEZpbGVTeW5jIH0gZnJvbSAnZnMnO1xyXG5pbXBvcnQgeyBqb2luIH0gZnJvbSAncGF0aCc7XHJcblxyXG5pbXBvcnQgcHVwcGV0ZWVyIGZyb20gJ3B1cHBldGVlcic7XHJcblxyXG5pbXBvcnQgeyBnZXRDYWNoZVBhdGggfSBmcm9tICcuL2NhY2hlLmpzJztcclxuaW1wb3J0IHsgZ2V0T3B0aW9ucyB9IGZyb20gJy4vY29uZmlnLmpzJztcclxuaW1wb3J0IHsgc2V0dXBIaWdoY2hhcnRzIH0gZnJvbSAnLi9oaWdoY2hhcnRzLmpzJztcclxuaW1wb3J0IHsgbG9nLCBsb2dXaXRoU3RhY2sgfSBmcm9tICcuL2xvZ2dlci5qcyc7XHJcbmltcG9ydCB7IF9fZGlybmFtZSwgZ2V0QWJzb2x1dGVQYXRoIH0gZnJvbSAnLi91dGlscy5qcyc7XHJcblxyXG5pbXBvcnQgRXhwb3J0RXJyb3IgZnJvbSAnLi9lcnJvcnMvRXhwb3J0RXJyb3IuanMnO1xyXG5cclxuLy8gR2V0IHRoZSB0ZW1wbGF0ZSBmb3IgcGFnZXNcclxuY29uc3QgdGVtcGxhdGUgPSByZWFkRmlsZVN5bmMoXHJcbiAgam9pbihfX2Rpcm5hbWUsICd0ZW1wbGF0ZXMnLCAndGVtcGxhdGUuaHRtbCcpLFxyXG4gICd1dGY4J1xyXG4pO1xyXG5cclxuLy8gVG8gc2F2ZSB0aGUgYnJvd3NlclxyXG5sZXQgYnJvd3NlciA9IG51bGw7XHJcblxyXG4vKipcclxuICogUmV0cmlldmVzIHRoZSBleGlzdGluZyBQdXBwZXRlZXIgYnJvd3NlciBpbnN0YW5jZS5cclxuICpcclxuICogQGZ1bmN0aW9uIGdldEJyb3dzZXJcclxuICpcclxuICogQHJldHVybnMge09iamVjdH0gVGhlIFB1cHBldGVlciBicm93c2VyIGluc3RhbmNlLlxyXG4gKlxyXG4gKiBAdGhyb3dzIHtFeHBvcnRFcnJvcn0gVGhyb3dzIGFuIGBFeHBvcnRFcnJvcmAgaWYgbm8gdmFsaWQgYnJvd3NlclxyXG4gKiBoYXMgYmVlbiBjcmVhdGVkLlxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIGdldEJyb3dzZXIoKSB7XHJcbiAgaWYgKCFicm93c2VyKSB7XHJcbiAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoJ1ticm93c2VyXSBObyB2YWxpZCBicm93c2VyIGhhcyBiZWVuIGNyZWF0ZWQuJywgNTAwKTtcclxuICB9XHJcbiAgcmV0dXJuIGJyb3dzZXI7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBDcmVhdGVzIGEgUHVwcGV0ZWVyIGJyb3dzZXIgaW5zdGFuY2Ugd2l0aCB0aGUgc3BlY2lmaWVkIGFyZ3VtZW50cy5cclxuICpcclxuICogQGFzeW5jXHJcbiAqIEBmdW5jdGlvbiBjcmVhdGVCcm93c2VyXHJcbiAqXHJcbiAqIEBwYXJhbSB7QXJyYXkuPHN0cmluZz59IHB1cHBldGVlckFyZ3MgLSBBZGRpdGlvbmFsIGFyZ3VtZW50cyBmb3IgUHVwcGV0ZWVyXHJcbiAqIGxhdW5jaC5cclxuICpcclxuICogQHJldHVybnMge1Byb21pc2U8T2JqZWN0Pn0gQSBQcm9taXNlIHRoYXQgcmVzb2x2ZXMgdG8gdGhlIGNyZWF0ZWQgUHVwcGV0ZWVyXHJcbiAqIGJyb3dzZXIgaW5zdGFuY2UuXHJcbiAqXHJcbiAqIEB0aHJvd3Mge0V4cG9ydEVycm9yfSBUaHJvd3MgYW4gYEV4cG9ydEVycm9yYCBpZiBtYXggcmV0cmllcyB0byBvcGVuXHJcbiAqIGEgYnJvd3NlciBpbnN0YW5jZSBhcmUgcmVhY2hlZCwgb3IgaWYgbm8gYnJvd3NlciBpbnN0YW5jZSBpcyBmb3VuZCBhZnRlclxyXG4gKiByZXRyaWVzLlxyXG4gKi9cclxuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIGNyZWF0ZUJyb3dzZXIocHVwcGV0ZWVyQXJncykge1xyXG4gIC8vIEdldCBgZGVidWdgIGFuZCBgb3RoZXJgIG9wdGlvbnNcclxuICBjb25zdCB7IGRlYnVnLCBvdGhlciB9ID0gZ2V0T3B0aW9ucygpO1xyXG5cclxuICAvLyBHZXQgdGhlIGBkZWJ1Z2Agb3B0aW9uc1xyXG4gIGNvbnN0IHsgZW5hYmxlOiBlbmFibGVkRGVidWcsIC4uLmRlYnVnT3B0aW9ucyB9ID0gZGVidWc7XHJcblxyXG4gIC8vIExhdW5jaCBvcHRpb25zIGZvciB0aGUgYnJvd3NlciBpbnN0YW5jZVxyXG4gIGNvbnN0IGxhdW5jaE9wdGlvbnMgPSB7XHJcbiAgICBoZWFkbGVzczogb3RoZXIuYnJvd3NlclNoZWxsTW9kZSA/ICdzaGVsbCcgOiB0cnVlLFxyXG4gICAgdXNlckRhdGFEaXI6ICd0bXAnLFxyXG4gICAgYXJnczogcHVwcGV0ZWVyQXJncyB8fCBbXSxcclxuICAgIGhhbmRsZVNJR0lOVDogZmFsc2UsXHJcbiAgICBoYW5kbGVTSUdURVJNOiBmYWxzZSxcclxuICAgIGhhbmRsZVNJR0hVUDogZmFsc2UsXHJcbiAgICB3YWl0Rm9ySW5pdGlhbFBhZ2U6IGZhbHNlLFxyXG4gICAgZGVmYXVsdFZpZXdwb3J0OiBudWxsLFxyXG4gICAgLi4uKGVuYWJsZWREZWJ1ZyAmJiBkZWJ1Z09wdGlvbnMpXHJcbiAgfTtcclxuXHJcbiAgLy8gQ3JlYXRlIGEgYnJvd3NlclxyXG4gIGlmICghYnJvd3Nlcikge1xyXG4gICAgLy8gQSBjb3VudGVyIGZvciB0aGUgYnJvd3NlcidzIGxhdW5jaCByZXRyaWVzXHJcbiAgICBsZXQgdHJ5Q291bnQgPSAwO1xyXG5cclxuICAgIGNvbnN0IG9wZW4gPSBhc3luYyAoKSA9PiB7XHJcbiAgICAgIHRyeSB7XHJcbiAgICAgICAgbG9nKFxyXG4gICAgICAgICAgMyxcclxuICAgICAgICAgIGBbYnJvd3Nlcl0gQXR0ZW1wdGluZyB0byBnZXQgYSBicm93c2VyIGluc3RhbmNlICh0cnkgJHsrK3RyeUNvdW50fSkuYFxyXG4gICAgICAgICk7XHJcblxyXG4gICAgICAgIC8vIExhdW5jaCB0aGUgYnJvd3NlclxyXG4gICAgICAgIGJyb3dzZXIgPSBhd2FpdCBwdXBwZXRlZXIubGF1bmNoKGxhdW5jaE9wdGlvbnMpO1xyXG4gICAgICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgICAgIGxvZ1dpdGhTdGFjayhcclxuICAgICAgICAgIDEsXHJcbiAgICAgICAgICBlcnJvcixcclxuICAgICAgICAgICdbYnJvd3Nlcl0gRmFpbGVkIHRvIGxhdW5jaCBhIGJyb3dzZXIgaW5zdGFuY2UuJ1xyXG4gICAgICAgICk7XHJcblxyXG4gICAgICAgIC8vIFJldHJ5IHRvIGxhdW5jaCBicm93c2VyIHVudGlsIHJlYWNoaW5nIG1heCBhdHRlbXB0c1xyXG4gICAgICAgIGlmICh0cnlDb3VudCA8IDI1KSB7XHJcbiAgICAgICAgICBsb2coMywgYFticm93c2VyXSBSZXRyeSB0byBvcGVuIGEgYnJvd3NlciAoJHt0cnlDb3VudH0gb3V0IG9mIDI1KS5gKTtcclxuXHJcbiAgICAgICAgICAvLyBXYWl0IGZvciBhIDQgc2Vjb25kcyBiZWZvcmUgdHJ5aW5nIGFnYWluXHJcbiAgICAgICAgICBhd2FpdCBuZXcgUHJvbWlzZSgocmVzcG9uc2UpID0+IHNldFRpbWVvdXQocmVzcG9uc2UsIDQwMDApKTtcclxuICAgICAgICAgIGF3YWl0IG9wZW4oKTtcclxuICAgICAgICB9IGVsc2Uge1xyXG4gICAgICAgICAgdGhyb3cgZXJyb3I7XHJcbiAgICAgICAgfVxyXG4gICAgICB9XHJcbiAgICB9O1xyXG5cclxuICAgIHRyeSB7XHJcbiAgICAgIGF3YWl0IG9wZW4oKTtcclxuXHJcbiAgICAgIC8vIFNoZWxsIG1vZGUgaW5mb3JtXHJcbiAgICAgIGlmIChsYXVuY2hPcHRpb25zLmhlYWRsZXNzID09PSAnc2hlbGwnKSB7XHJcbiAgICAgICAgbG9nKDMsIGBbYnJvd3Nlcl0gTGF1bmNoZWQgYnJvd3NlciBpbiBzaGVsbCBtb2RlLmApO1xyXG4gICAgICB9XHJcblxyXG4gICAgICAvLyBEZWJ1ZyBtb2RlIGluZm9ybVxyXG4gICAgICBpZiAoZW5hYmxlZERlYnVnKSB7XHJcbiAgICAgICAgbG9nKDMsIGBbYnJvd3Nlcl0gTGF1bmNoZWQgYnJvd3NlciBpbiBkZWJ1ZyBtb2RlLmApO1xyXG4gICAgICB9XHJcbiAgICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoXHJcbiAgICAgICAgJ1ticm93c2VyXSBNYXhpbXVtIHJldHJpZXMgdG8gb3BlbiBhIGJyb3dzZXIgaW5zdGFuY2UgcmVhY2hlZC4nLFxyXG4gICAgICAgIDUwMFxyXG4gICAgICApLnNldEVycm9yKGVycm9yKTtcclxuICAgIH1cclxuXHJcbiAgICBpZiAoIWJyb3dzZXIpIHtcclxuICAgICAgdGhyb3cgbmV3IEV4cG9ydEVycm9yKCdbYnJvd3Nlcl0gQ2Fubm90IGZpbmQgYSBicm93c2VyIHRvIG9wZW4uJywgNTAwKTtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIC8vIFJldHVybiBhIGJyb3dzZXIgaW5zdGFuY2VcclxuICByZXR1cm4gYnJvd3NlcjtcclxufVxyXG5cclxuLyoqXHJcbiAqIENsb3NlcyB0aGUgUHVwcGV0ZWVyIGJyb3dzZXIgaW5zdGFuY2UgaWYgaXQgaXMgY29ubmVjdGVkLlxyXG4gKlxyXG4gKiBAYXN5bmNcclxuICogQGZ1bmN0aW9uIGNsb3NlQnJvd3NlclxyXG4gKi9cclxuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIGNsb3NlQnJvd3NlcigpIHtcclxuICAvLyBDbG9zZSB0aGUgYnJvd3NlciB3aGVuIGNvbm5lY3RlZFxyXG4gIGlmIChicm93c2VyICYmIGJyb3dzZXIuY29ubmVjdGVkKSB7XHJcbiAgICBhd2FpdCBicm93c2VyLmNsb3NlKCk7XHJcbiAgfVxyXG4gIGJyb3dzZXIgPSBudWxsO1xyXG4gIGxvZyg0LCAnW2Jyb3dzZXJdIENsb3NlZCB0aGUgYnJvd3Nlci4nKTtcclxufVxyXG5cclxuLyoqXHJcbiAqIENyZWF0ZXMgYSBuZXcgUHVwcGV0ZWVyIHBhZ2Ugd2l0aGluIGFuIGV4aXN0aW5nIGJyb3dzZXIgaW5zdGFuY2UuXHJcbiAqIFRoZSBmdW5jdGlvbiBjcmVhdGVzIGEgbmV3IHBhZ2UsIGRpc2FibGVzIGNhY2hpbmcsIHNldHMgY29udGVudCB1c2luZ1xyXG4gKiB0aGUgYF9zZXRQYWdlQ29udGVudCgpYCwgYW5kIHJldHVybnMgdGhlIGNyZWF0ZWQgUHVwcGV0ZWVyIHBhZ2UuXHJcbiAqXHJcbiAqIEBhc3luY1xyXG4gKiBAZnVuY3Rpb24gbmV3UGFnZVxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gcG9vbFJlc291cmNlIC0gVGhlIHBvb2wgcmVzb3VyY2UgdGhhdCBjb250YWlucyBgaWRgLFxyXG4gKiBgd29ya0NvdW50YCwgYW5kIGBwYWdlYC5cclxuICpcclxuICogQHRocm93cyB7RXhwb3J0RXJyb3J9IFRocm93cyBhbiBgRXhwb3J0RXJyb3JgIGlmIG5vIHZhbGlkIGJyb3dzZXJcclxuICogaGFzIGJlZW4gY29ubmVjdGVkIG9yIGlmIGEgcGFnZSBpcyBpbnZhbGlkIG9yIGNsb3NlZC5cclxuICovXHJcbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBuZXdQYWdlKHBvb2xSZXNvdXJjZSkge1xyXG4gIC8vIEVycm9yIGluIGNhc2Ugb2Ygbm8gY29ubmVjdGVkIGJyb3dzZXJcclxuICBpZiAoIWJyb3dzZXIgfHwgIWJyb3dzZXIuY29ubmVjdGVkKSB7XHJcbiAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoYFticm93c2VyXSBCcm93c2VyIGlzIG5vdCB5ZXQgY29ubmVjdGVkLmAsIDUwMCk7XHJcbiAgfVxyXG5cclxuICAvLyBDcmVhdGUgYSBwYWdlXHJcbiAgcG9vbFJlc291cmNlLnBhZ2UgPSBhd2FpdCBicm93c2VyLm5ld1BhZ2UoKTtcclxuXHJcbiAgLy8gRGlzYWJsZSBjYWNoZVxyXG4gIGF3YWl0IHBvb2xSZXNvdXJjZS5wYWdlLnNldENhY2hlRW5hYmxlZChmYWxzZSk7XHJcblxyXG4gIC8vIFNldCB0aGUgY29udGVudFxyXG4gIGF3YWl0IF9zZXRQYWdlQ29udGVudChwb29sUmVzb3VyY2UucGFnZSk7XHJcblxyXG4gIC8vIFNldCBwYWdlIGV2ZW50c1xyXG4gIF9zZXRQYWdlRXZlbnRzKHBvb2xSZXNvdXJjZS5wYWdlKTtcclxuXHJcbiAgLy8gQ2hlY2sgaWYgdGhlIHBhZ2UgaXMgY29ycmVjdGx5IGNyZWF0ZWRcclxuICBpZiAoIXBvb2xSZXNvdXJjZS5wYWdlIHx8IHBvb2xSZXNvdXJjZS5wYWdlLmlzQ2xvc2VkKCkpIHtcclxuICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcignW2Jyb3dzZXJdIFRoZSBwYWdlIGlzIGludmFsaWQgb3IgY2xvc2VkLicsIDQwMCk7XHJcbiAgfVxyXG59XHJcblxyXG4vKipcclxuICogQ2xlYXJzIHRoZSBjb250ZW50IG9mIGEgUHVwcGV0ZWVyIFBhZ2UgYmFzZWQgb24gdGhlIHNwZWNpZmllZCBtb2RlLiBMb2dzXHJcbiAqIHRocm93biBlcnJvciBpZiBjbGVhcmluZyBvZiBhIHBhZ2UncyBjb250ZW50IGZhaWxzLlxyXG4gKlxyXG4gKiBAYXN5bmNcclxuICogQGZ1bmN0aW9uIGNsZWFyUGFnZVxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gcG9vbFJlc291cmNlIC0gVGhlIHBvb2wgcmVzb3VyY2UgdGhhdCBjb250YWlucyBwYWdlIGFuZCBpZC5cclxuICogQHBhcmFtIHtib29sZWFufSBbaGFyZFJlc2V0PWZhbHNlXSAtIEEgZmxhZyBpbmRpY2F0aW5nIHRoZSB0eXBlIG9mIGNsZWFyaW5nXHJcbiAqIHRvIGJlIHBlcmZvcm1lZC4gSWYgdHJ1ZSwgbmF2aWdhdGVzIHRvIGBhYm91dDpibGFua2AgYW5kIHJlc2V0cyBjb250ZW50XHJcbiAqIGFuZCBzY3JpcHRzLiBJZiBmYWxzZSwgY2xlYXJzIHRoZSBib2R5IGNvbnRlbnQgYnkgc2V0dGluZyBhIHByZWRlZmluZWQgSFRNTFxyXG4gKiBzdHJ1Y3R1cmUuIFRoZSBkZWZhdWx0IHZhbHVlIGlzIGZhbHNlLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7UHJvbWlzZTxib29sZWFuPn0gQSBQcm9taXNlIHRoYXQgcmVzb2x2ZXMgdG8gdHJ1ZSB3aGVuIHBhZ2VcclxuICogaXMgY29ycmVjdGx5IGNsZWFyZWQgYW5kIGZhbHNlIHdoZW4gaXQgaXMgbm90LlxyXG4gKi9cclxuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIGNsZWFyUGFnZShwb29sUmVzb3VyY2UsIGhhcmRSZXNldCA9IGZhbHNlKSB7XHJcbiAgdHJ5IHtcclxuICAgIGlmIChwb29sUmVzb3VyY2UucGFnZSAmJiAhcG9vbFJlc291cmNlLnBhZ2UuaXNDbG9zZWQoKSkge1xyXG4gICAgICBpZiAoaGFyZFJlc2V0KSB7XHJcbiAgICAgICAgLy8gTmF2aWdhdGUgdG8gYGFib3V0OmJsYW5rYFxyXG4gICAgICAgIGF3YWl0IHBvb2xSZXNvdXJjZS5wYWdlLmdvdG8oJ2Fib3V0OmJsYW5rJywge1xyXG4gICAgICAgICAgd2FpdFVudGlsOiAnZG9tY29udGVudGxvYWRlZCdcclxuICAgICAgICB9KTtcclxuXHJcbiAgICAgICAgLy8gU2V0IHRoZSBjb250ZW50IGFuZCBhbmQgc2NyaXB0cyBhZ2FpblxyXG4gICAgICAgIGF3YWl0IF9zZXRQYWdlQ29udGVudChwb29sUmVzb3VyY2UucGFnZSk7XHJcbiAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgLy8gQ2xlYXIgYm9keSBjb250ZW50XHJcbiAgICAgICAgYXdhaXQgcG9vbFJlc291cmNlLnBhZ2UuZXZhbHVhdGUoKCkgPT4ge1xyXG4gICAgICAgICAgZG9jdW1lbnQuYm9keS5pbm5lckhUTUwgPVxyXG4gICAgICAgICAgICAnPGRpdiBpZD1cImNoYXJ0LWNvbnRhaW5lclwiPjxkaXYgaWQ9XCJjb250YWluZXJcIj48L2Rpdj48L2Rpdj4nO1xyXG4gICAgICAgIH0pO1xyXG4gICAgICB9XHJcbiAgICAgIHJldHVybiB0cnVlO1xyXG4gICAgfVxyXG4gIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICBsb2dXaXRoU3RhY2soXHJcbiAgICAgIDIsXHJcbiAgICAgIGVycm9yLFxyXG4gICAgICBgW3Bvb2xdIFBvb2wgcmVzb3VyY2UgWyR7cG9vbFJlc291cmNlLmlkfV0gLSBDb250ZW50IG9mIHRoZSBwYWdlIGNvdWxkIG5vdCBiZSBjbGVhcmVkLmBcclxuICAgICk7XHJcblxyXG4gICAgLy8gU2V0IHRoZSBgd29ya0xpbWl0YCB0byBleGNlZWRlZCBpbiBvcmRlciB0byByZWNyZWF0ZSB0aGUgcmVzb3VyY2VcclxuICAgIHBvb2xSZXNvdXJjZS53b3JrQ291bnQgPSBnZXRPcHRpb25zKCkucG9vbC53b3JrTGltaXQgKyAxO1xyXG4gIH1cclxuICByZXR1cm4gZmFsc2U7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBBZGRzIGN1c3RvbSBKUyBhbmQgQ1NTIHJlc291cmNlcyB0byBhIFB1cHBldGVlciBQYWdlIGJhc2VkIG9uIHRoZSBzcGVjaWZpZWRcclxuICogb3B0aW9ucy5cclxuICpcclxuICogQGFzeW5jXHJcbiAqIEBmdW5jdGlvbiBhZGRQYWdlUmVzb3VyY2VzXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBwYWdlIC0gVGhlIFB1cHBldGVlciBwYWdlIG9iamVjdCB0byB3aGljaCByZXNvdXJjZXMgd2lsbFxyXG4gKiBiZSBhZGRlZC5cclxuICogQHBhcmFtIHtPYmplY3R9IGN1c3RvbUxvZ2ljT3B0aW9ucyAtIFRoZSBvYmplY3QgY29udGFpbmluZyBgY3VzdG9tTG9naWNgXHJcbiAqIG9wdGlvbnMuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtQcm9taXNlPEFycmF5LjxPYmplY3Q+Pn0gQSBQcm9taXNlIHRoYXQgcmVzb2x2ZXMgdG8gYW4gYXJyYXlcclxuICogb2YgaW5qZWN0ZWQgcmVzb3VyY2VzLlxyXG4gKi9cclxuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIGFkZFBhZ2VSZXNvdXJjZXMocGFnZSwgY3VzdG9tTG9naWNPcHRpb25zKSB7XHJcbiAgLy8gSW5qZWN0ZWQgcmVzb3VyY2VzIGFycmF5XHJcbiAgY29uc3QgaW5qZWN0ZWRSZXNvdXJjZXMgPSBbXTtcclxuXHJcbiAgLy8gVXNlIHJlc291cmNlc1xyXG4gIGNvbnN0IHJlc291cmNlcyA9IGN1c3RvbUxvZ2ljT3B0aW9ucy5yZXNvdXJjZXM7XHJcbiAgaWYgKHJlc291cmNlcykge1xyXG4gICAgY29uc3QgaW5qZWN0ZWRKcyA9IFtdO1xyXG5cclxuICAgIC8vIExvYWQgY3VzdG9tIEpTIGNvZGVcclxuICAgIGlmIChyZXNvdXJjZXMuanMpIHtcclxuICAgICAgaW5qZWN0ZWRKcy5wdXNoKHtcclxuICAgICAgICBjb250ZW50OiByZXNvdXJjZXMuanNcclxuICAgICAgfSk7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gTG9hZCBzY3JpcHRzIGZyb20gYWxsIGN1c3RvbSBmaWxlc1xyXG4gICAgaWYgKHJlc291cmNlcy5maWxlcykge1xyXG4gICAgICBmb3IgKGNvbnN0IGZpbGUgb2YgcmVzb3VyY2VzLmZpbGVzKSB7XHJcbiAgICAgICAgY29uc3QgaXNMb2NhbCA9ICFmaWxlLnN0YXJ0c1dpdGgoJ2h0dHAnKSA/IHRydWUgOiBmYWxzZTtcclxuXHJcbiAgICAgICAgLy8gQWRkIGVhY2ggY3VzdG9tIHNjcmlwdCBmcm9tIHJlc291cmNlcycgZmlsZXNcclxuICAgICAgICBpbmplY3RlZEpzLnB1c2goXHJcbiAgICAgICAgICBpc0xvY2FsXHJcbiAgICAgICAgICAgID8ge1xyXG4gICAgICAgICAgICAgICAgY29udGVudDogcmVhZEZpbGVTeW5jKGdldEFic29sdXRlUGF0aChmaWxlKSwgJ3V0ZjgnKVxyXG4gICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgOiB7XHJcbiAgICAgICAgICAgICAgICB1cmw6IGZpbGVcclxuICAgICAgICAgICAgICB9XHJcbiAgICAgICAgKTtcclxuICAgICAgfVxyXG4gICAgfVxyXG5cclxuICAgIGZvciAoY29uc3QganNSZXNvdXJjZSBvZiBpbmplY3RlZEpzKSB7XHJcbiAgICAgIHRyeSB7XHJcbiAgICAgICAgaW5qZWN0ZWRSZXNvdXJjZXMucHVzaChhd2FpdCBwYWdlLmFkZFNjcmlwdFRhZyhqc1Jlc291cmNlKSk7XHJcbiAgICAgIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICAgICAgbG9nV2l0aFN0YWNrKDIsIGVycm9yLCBgW2Jyb3dzZXJdIFRoZSBKUyByZXNvdXJjZSBjYW5ub3QgYmUgbG9hZGVkLmApO1xyXG4gICAgICB9XHJcbiAgICB9XHJcbiAgICBpbmplY3RlZEpzLmxlbmd0aCA9IDA7XHJcblxyXG4gICAgLy8gTG9hZCBDU1NcclxuICAgIGNvbnN0IGluamVjdGVkQ3NzID0gW107XHJcbiAgICBpZiAocmVzb3VyY2VzLmNzcykge1xyXG4gICAgICBsZXQgY3NzSW1wb3J0cyA9IHJlc291cmNlcy5jc3MubWF0Y2goL0BpbXBvcnRcXHMqKFteO10qKTsvZyk7XHJcbiAgICAgIGlmIChjc3NJbXBvcnRzKSB7XHJcbiAgICAgICAgLy8gSGFuZGxlIGNzcyBzZWN0aW9uXHJcbiAgICAgICAgZm9yIChsZXQgY3NzSW1wb3J0UGF0aCBvZiBjc3NJbXBvcnRzKSB7XHJcbiAgICAgICAgICBpZiAoY3NzSW1wb3J0UGF0aCkge1xyXG4gICAgICAgICAgICBjc3NJbXBvcnRQYXRoID0gY3NzSW1wb3J0UGF0aFxyXG4gICAgICAgICAgICAgIC5yZXBsYWNlKCd1cmwoJywgJycpXHJcbiAgICAgICAgICAgICAgLnJlcGxhY2UoJ0BpbXBvcnQnLCAnJylcclxuICAgICAgICAgICAgICAucmVwbGFjZSgvXCIvZywgJycpXHJcbiAgICAgICAgICAgICAgLnJlcGxhY2UoLycvZywgJycpXHJcbiAgICAgICAgICAgICAgLnJlcGxhY2UoLzsvLCAnJylcclxuICAgICAgICAgICAgICAucmVwbGFjZSgvXFwpL2csICcnKVxyXG4gICAgICAgICAgICAgIC50cmltKCk7XHJcblxyXG4gICAgICAgICAgICAvLyBBZGQgZWFjaCBjdXN0b20gY3NzIGZyb20gcmVzb3VyY2VzXHJcbiAgICAgICAgICAgIGlmIChjc3NJbXBvcnRQYXRoLnN0YXJ0c1dpdGgoJ2h0dHAnKSkge1xyXG4gICAgICAgICAgICAgIGluamVjdGVkQ3NzLnB1c2goe1xyXG4gICAgICAgICAgICAgICAgdXJsOiBjc3NJbXBvcnRQYXRoXHJcbiAgICAgICAgICAgICAgfSk7XHJcbiAgICAgICAgICAgIH0gZWxzZSBpZiAoY3VzdG9tTG9naWNPcHRpb25zLmFsbG93RmlsZVJlc291cmNlcykge1xyXG4gICAgICAgICAgICAgIGluamVjdGVkQ3NzLnB1c2goe1xyXG4gICAgICAgICAgICAgICAgcGF0aDogam9pbihfX2Rpcm5hbWUsIGNzc0ltcG9ydFBhdGgpXHJcbiAgICAgICAgICAgICAgfSk7XHJcbiAgICAgICAgICAgIH1cclxuICAgICAgICAgIH1cclxuICAgICAgICB9XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIC8vIFRoZSByZXN0IG9mIHRoZSBDU1Mgc2VjdGlvbiB3aWxsIGJlIGNvbnRlbnQgYnkgbm93XHJcbiAgICAgIGluamVjdGVkQ3NzLnB1c2goe1xyXG4gICAgICAgIGNvbnRlbnQ6IHJlc291cmNlcy5jc3MucmVwbGFjZSgvQGltcG9ydFxccyooW147XSopOy9nLCAnJykgfHwgJyAnXHJcbiAgICAgIH0pO1xyXG5cclxuICAgICAgZm9yIChjb25zdCBjc3NSZXNvdXJjZSBvZiBpbmplY3RlZENzcykge1xyXG4gICAgICAgIHRyeSB7XHJcbiAgICAgICAgICBpbmplY3RlZFJlc291cmNlcy5wdXNoKGF3YWl0IHBhZ2UuYWRkU3R5bGVUYWcoY3NzUmVzb3VyY2UpKTtcclxuICAgICAgICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgICAgICAgbG9nV2l0aFN0YWNrKFxyXG4gICAgICAgICAgICAyLFxyXG4gICAgICAgICAgICBlcnJvcixcclxuICAgICAgICAgICAgYFticm93c2VyXSBUaGUgQ1NTIHJlc291cmNlIGNhbm5vdCBiZSBsb2FkZWQuYFxyXG4gICAgICAgICAgKTtcclxuICAgICAgICB9XHJcbiAgICAgIH1cclxuICAgICAgaW5qZWN0ZWRDc3MubGVuZ3RoID0gMDtcclxuICAgIH1cclxuICB9XHJcbiAgcmV0dXJuIGluamVjdGVkUmVzb3VyY2VzO1xyXG59XHJcblxyXG4vKipcclxuICogQ2xlYXJzIG91dCBhbGwgc3RhdGUgc2V0IG9uIHRoZSBwYWdlIHdpdGggYGFkZFNjcmlwdFRhZ2AgYW5kIGBhZGRTdHlsZVRhZ2AuXHJcbiAqIFJlbW92ZXMgaW5qZWN0ZWQgcmVzb3VyY2VzIGFuZCByZXNldHMgQ1NTIGFuZCBzY3JpcHQgdGFncyBvbiB0aGUgcGFnZS5cclxuICogQWRkaXRpb25hbGx5LCBpdCBkZXN0cm95cyBwcmV2aW91c2x5IGV4aXN0aW5nIGNoYXJ0cy5cclxuICpcclxuICogQGFzeW5jXHJcbiAqIEBmdW5jdGlvbiBjbGVhclBhZ2VSZXNvdXJjZXNcclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IHBhZ2UgLSBUaGUgUHVwcGV0ZWVyIHBhZ2Ugb2JqZWN0IGZyb20gd2hpY2ggcmVzb3VyY2VzIHdpbGxcclxuICogYmUgY2xlYXJlZC5cclxuICogQHBhcmFtIHtBcnJheS48T2JqZWN0Pn0gaW5qZWN0ZWRSZXNvdXJjZXMgLSBBcnJheSBvZiBpbmplY3RlZCByZXNvdXJjZXNcclxuICogdG8gYmUgY2xlYXJlZC5cclxuICovXHJcbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBjbGVhclBhZ2VSZXNvdXJjZXMocGFnZSwgaW5qZWN0ZWRSZXNvdXJjZXMpIHtcclxuICB0cnkge1xyXG4gICAgZm9yIChjb25zdCByZXNvdXJjZSBvZiBpbmplY3RlZFJlc291cmNlcykge1xyXG4gICAgICBhd2FpdCByZXNvdXJjZS5kaXNwb3NlKCk7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gRGVzdHJveSBvbGQgY2hhcnRzIGFmdGVyIGV4cG9ydCBpcyBkb25lIGFuZCByZXNldCBhbGwgQ1NTIGFuZCBzY3JpcHQgdGFnc1xyXG4gICAgYXdhaXQgcGFnZS5ldmFsdWF0ZSgoKSA9PiB7XHJcbiAgICAgIC8vIFdlIGFyZSBub3QgZ3VhcmFudGVlZCB0aGF0IEhpZ2hjaGFydHMgaXMgbG9hZGVkLCB3aGVuIGRvaW5nIFNWRyBleHBvcnRzXHJcbiAgICAgIGlmICh0eXBlb2YgSGlnaGNoYXJ0cyAhPT0gJ3VuZGVmaW5lZCcpIHtcclxuICAgICAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgbm8tdW5kZWZcclxuICAgICAgICBjb25zdCBvbGRDaGFydHMgPSBIaWdoY2hhcnRzLmNoYXJ0cztcclxuXHJcbiAgICAgICAgLy8gQ2hlY2sgaW4gYW55IGFscmVhZHkgZXhpc3RpbmcgY2hhcnRzXHJcbiAgICAgICAgaWYgKEFycmF5LmlzQXJyYXkob2xkQ2hhcnRzKSAmJiBvbGRDaGFydHMubGVuZ3RoKSB7XHJcbiAgICAgICAgICAvLyBEZXN0cm95IG9sZCBjaGFydHNcclxuICAgICAgICAgIGZvciAoY29uc3Qgb2xkQ2hhcnQgb2Ygb2xkQ2hhcnRzKSB7XHJcbiAgICAgICAgICAgIG9sZENoYXJ0ICYmIG9sZENoYXJ0LmRlc3Ryb3koKTtcclxuICAgICAgICAgICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIG5vLXVuZGVmXHJcbiAgICAgICAgICAgIEhpZ2hjaGFydHMuY2hhcnRzLnNoaWZ0KCk7XHJcbiAgICAgICAgICB9XHJcbiAgICAgICAgfVxyXG4gICAgICB9XHJcblxyXG4gICAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgbm8tdW5kZWZcclxuICAgICAgY29uc3QgWy4uLnNjcmlwdHNUb1JlbW92ZV0gPSBkb2N1bWVudC5nZXRFbGVtZW50c0J5VGFnTmFtZSgnc2NyaXB0Jyk7XHJcbiAgICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBuby11bmRlZlxyXG4gICAgICBjb25zdCBbLCAuLi5zdHlsZXNUb1JlbW92ZV0gPSBkb2N1bWVudC5nZXRFbGVtZW50c0J5VGFnTmFtZSgnc3R5bGUnKTtcclxuICAgICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIG5vLXVuZGVmXHJcbiAgICAgIGNvbnN0IFsuLi5saW5rc1RvUmVtb3ZlXSA9IGRvY3VtZW50LmdldEVsZW1lbnRzQnlUYWdOYW1lKCdsaW5rJyk7XHJcblxyXG4gICAgICAvLyBSZW1vdmUgdGFnc1xyXG4gICAgICBmb3IgKGNvbnN0IGVsZW1lbnQgb2YgW1xyXG4gICAgICAgIC4uLnNjcmlwdHNUb1JlbW92ZSxcclxuICAgICAgICAuLi5zdHlsZXNUb1JlbW92ZSxcclxuICAgICAgICAuLi5saW5rc1RvUmVtb3ZlXHJcbiAgICAgIF0pIHtcclxuICAgICAgICBlbGVtZW50LnJlbW92ZSgpO1xyXG4gICAgICB9XHJcbiAgICB9KTtcclxuICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgbG9nV2l0aFN0YWNrKDIsIGVycm9yLCBgW2Jyb3dzZXJdIENvdWxkIG5vdCBjbGVhciBwYWdlJ3MgcmVzb3VyY2VzLmApO1xyXG4gIH1cclxufVxyXG5cclxuLyoqXHJcbiAqIFNldHMgdGhlIGNvbnRlbnQgZm9yIGEgUHVwcGV0ZWVyIFBhZ2UgdXNpbmcgYSBwcmVkZWZpbmVkIHRlbXBsYXRlXHJcbiAqIGFuZCBhZGRpdGlvbmFsIHNjcmlwdHMuXHJcbiAqXHJcbiAqIEBhc3luY1xyXG4gKiBAZnVuY3Rpb24gX3NldFBhZ2VDb250ZW50XHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBwYWdlIC0gVGhlIFB1cHBldGVlciBwYWdlIG9iamVjdCB0byB3aGljaCB0aGUgY29udGVudFxyXG4gKiBpcyBiZWluZyBzZXQuXHJcbiAqL1xyXG5hc3luYyBmdW5jdGlvbiBfc2V0UGFnZUNvbnRlbnQocGFnZSkge1xyXG4gIC8vIFNldCB0aGUgaW5pdGlhbCBwYWdlIGNvbnRlbnRcclxuICBhd2FpdCBwYWdlLnNldENvbnRlbnQodGVtcGxhdGUsIHsgd2FpdFVudGlsOiAnZG9tY29udGVudGxvYWRlZCcgfSk7XHJcblxyXG4gIC8vIEFkZCBhbGwgcmVnaXN0ZXJlZCBIaWdjaGFydHMgc2NyaXB0cywgcXVpdGUgZGVtYW5kaW5nXHJcbiAgYXdhaXQgcGFnZS5hZGRTY3JpcHRUYWcoeyBwYXRoOiBqb2luKGdldENhY2hlUGF0aCgpLCAnc291cmNlcy5qcycpIH0pO1xyXG5cclxuICAvLyBTZXQgdGhlIGluaXRpYWwgYGFuaW1PYmplY3RgIGZvciBIaWdoY2hhcnRzXHJcbiAgYXdhaXQgcGFnZS5ldmFsdWF0ZShzZXR1cEhpZ2hjaGFydHMpO1xyXG59XHJcblxyXG4vKipcclxuICogU2V0IGV2ZW50cyAobGlrZSBgcGFnZWVycm9yYCBhbmQgYGNvbnNvbGVgKSBmb3IgYSBQdXBwZXRlZXIgUGFnZSBpbiBvcmRlclxyXG4gKiB0byBjYXRjaCBhbmQgZGlzcGxheSBlcnJvcnMgYW5kIGNvbnNvbGUgbG9ncyBmcm9tIHRoZSB3aW5kb3cgY29udGV4dC5cclxuICpcclxuICogQGZ1bmN0aW9uIF9zZXRQYWdlRXZlbnRzXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBwYWdlIC0gVGhlIFB1cHBldGVlciBwYWdlIG9iamVjdCB0byB3aGljaCB0aGUgbGlzdGVuZXJzXHJcbiAqIGFyZSBiZWluZyBzZXQuXHJcbiAqL1xyXG5mdW5jdGlvbiBfc2V0UGFnZUV2ZW50cyhwYWdlKSB7XHJcbiAgLy8gR2V0IGBkZWJ1Z2Agb3B0aW9uc1xyXG4gIGNvbnN0IHsgZGVidWcgfSA9IGdldE9wdGlvbnMoKTtcclxuXHJcbiAgLy8gU2V0IHRoZSBgcGFnZWVycm9yYCBsaXN0ZW5lclxyXG4gIHBhZ2Uub24oJ3BhZ2VlcnJvcicsIGFzeW5jICgpID0+IHtcclxuICAgIC8vIEl0IHdvdWxkIHNlZW0gbGlrZSB0aGlzIG1heSBmaXJlIGF0IHRoZSBzYW1lIHRpbWUgb3Igc2hvcnRseSBiZWZvcmVcclxuICAgIC8vIGEgcGFnZSBpcyBjbG9zZWQuXHJcbiAgICBpZiAocGFnZS5pc0Nsb3NlZCgpKSB7XHJcbiAgICAgIHJldHVybjtcclxuICAgIH1cclxuICB9KTtcclxuXHJcbiAgLy8gU2V0IHRoZSBgY29uc29sZWAgbGlzdGVuZXIsIGlmIG5lZWRlZFxyXG4gIGlmIChkZWJ1Zy5lbmFibGUgJiYgZGVidWcubGlzdGVuVG9Db25zb2xlKSB7XHJcbiAgICBwYWdlLm9uKCdjb25zb2xlJywgKG1lc3NhZ2UpID0+IHtcclxuICAgICAgY29uc29sZS5sb2coYFtkZWJ1Z10gJHttZXNzYWdlLnRleHQoKX1gKTtcclxuICAgIH0pO1xyXG4gIH1cclxufVxyXG5cclxuZXhwb3J0IGRlZmF1bHQge1xyXG4gIGdldEJyb3dzZXIsXHJcbiAgY3JlYXRlQnJvd3NlcixcclxuICBjbG9zZUJyb3dzZXIsXHJcbiAgbmV3UGFnZSxcclxuICBjbGVhclBhZ2UsXHJcbiAgYWRkUGFnZVJlc291cmNlcyxcclxuICBjbGVhclBhZ2VSZXNvdXJjZXNcclxufTtcclxuIiwiLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcclxuXHJcbkhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlclxyXG5cclxuQ29weXJpZ2h0IChjKSAyMDE2LTIwMjUsIEhpZ2hzb2Z0XHJcblxyXG5MaWNlbmNlZCB1bmRlciB0aGUgTUlUIGxpY2VuY2UuXHJcblxyXG5BZGRpdGlvbmFsbHkgYSB2YWxpZCBIaWdoY2hhcnRzIGxpY2Vuc2UgaXMgcmVxdWlyZWQgZm9yIHVzZS5cclxuXHJcblNlZSBMSUNFTlNFIGZpbGUgaW4gcm9vdCBmb3IgZGV0YWlscy5cclxuXHJcbioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXHJcblxyXG4vKipcclxuICogVGhlIENTUyB0byBiZSB1c2VkIG9uIHRoZSBleHBvcnRlZCBwYWdlLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7c3RyaW5nfSBUaGUgQ1NTIGNvbmZpZ3VyYXRpb24uXHJcbiAqL1xyXG5leHBvcnQgZGVmYXVsdCAoKSA9PiBgXHJcblxyXG5odG1sLCBib2R5IHtcclxuICBtYXJnaW46IDA7XHJcbiAgcGFkZGluZzogMDtcclxuICBib3gtc2l6aW5nOiBib3JkZXItYm94O1xyXG59XHJcblxyXG4jdGFibGUtZGl2LCAjc2xpZGVycywgI2RhdGF0YWJsZSwgI2NvbnRyb2xzLCAubGQtcm93IHtcclxuICBkaXNwbGF5OiBub25lO1xyXG4gIGhlaWdodDogMDtcclxufVxyXG5cclxuI2NoYXJ0LWNvbnRhaW5lciB7XHJcbiAgYm94LXNpemluZzogYm9yZGVyLWJveDtcclxuICBtYXJnaW46IDA7XHJcbiAgb3ZlcmZsb3c6IGF1dG87XHJcbiAgZm9udC1zaXplOiAwO1xyXG59XHJcblxyXG4jY2hhcnQtY29udGFpbmVyID4gZmlndXJlLCBkaXYge1xyXG4gIG1hcmdpbi10b3A6IDAgIWltcG9ydGFudDtcclxuICBtYXJnaW4tYm90dG9tOiAwICFpbXBvcnRhbnQ7XHJcbn1cclxuXHJcbmA7XHJcbiIsIi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXHJcblxyXG5IaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXJcclxuXHJcbkNvcHlyaWdodCAoYykgMjAxNi0yMDI1LCBIaWdoc29mdFxyXG5cclxuTGljZW5jZWQgdW5kZXIgdGhlIE1JVCBsaWNlbmNlLlxyXG5cclxuQWRkaXRpb25hbGx5IGEgdmFsaWQgSGlnaGNoYXJ0cyBsaWNlbnNlIGlzIHJlcXVpcmVkIGZvciB1c2UuXHJcblxyXG5TZWUgTElDRU5TRSBmaWxlIGluIHJvb3QgZm9yIGRldGFpbHMuXHJcblxyXG4qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xyXG5cclxuaW1wb3J0IGNzc1RlbXBsYXRlIGZyb20gJy4vY3NzLmpzJztcclxuXHJcbi8qKlxyXG4gKiBUaGUgU1ZHIHRlbXBsYXRlIHRvIHVzZSB3aGVuIGxvYWRpbmcgU1ZHIGNvbnRlbnQgdG8gYmUgZXhwb3J0ZWQuXHJcbiAqXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSBzdmcgLSBUaGUgU1ZHIGlucHV0IGNvbnRlbnQgdG8gYmUgZXhwb3J0ZWQuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtzdHJpbmd9IFRoZSBTVkcgdGVtcGxhdGUuXHJcbiAqL1xyXG5leHBvcnQgZGVmYXVsdCAoc3ZnKSA9PiBgXHJcbjwhRE9DVFlQRSBodG1sPlxyXG48aHRtbCBsYW5nPSdlbi1VUyc+XHJcbiAgPGhlYWQ+XHJcbiAgICA8bWV0YSBodHRwLWVxdWl2PVwiQ29udGVudC1UeXBlXCIgY29udGVudD1cInRleHQvaHRtbDsgY2hhcnNldD11dGYtOFwiPlxyXG4gICAgPHRpdGxlPkhpZ2hjaGFydHMgRXhwb3J0PC90aXRsZT5cclxuICA8L2hlYWQ+XHJcbiAgPHN0eWxlPlxyXG4gICAgJHtjc3NUZW1wbGF0ZSgpfVxyXG4gIDwvc3R5bGU+XHJcbiAgPGJvZHk+XHJcbiAgICA8ZGl2IGlkPVwiY2hhcnQtY29udGFpbmVyXCI+XHJcbiAgICAgICR7c3ZnfVxyXG4gICAgPC9kaXY+XHJcbiAgPC9ib2R5PlxyXG48L2h0bWw+XHJcblxyXG5gO1xyXG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxyXG5cclxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXHJcblxyXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNSwgSGlnaHNvZnRcclxuXHJcbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cclxuXHJcbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxyXG5cclxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxyXG5cclxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cclxuXHJcbi8qKlxyXG4gKiBAb3ZlcnZpZXcgVGhpcyBtb2R1bGUgaGFuZGxlcyBjaGFydCBleHBvcnQgZnVuY3Rpb25hbGl0eSB1c2luZyBQdXBwZXRlZXIuXHJcbiAqIEl0IHN1cHBvcnRzIGV4cG9ydGluZyBjaGFydHMgYXMgU1ZHLCBQTkcsIEpQRUcsIGFuZCBQREYgZm9ybWF0cy4gVGhlIG1vZHVsZVxyXG4gKiBtYW5hZ2VzIHBhZ2UgcmVzb3VyY2VzLCBzZXRzIHVwIHRoZSBleHBvcnQgZW52aXJvbm1lbnQsIGFuZCBwcm9jZXNzZXMgY2hhcnRcclxuICogY29uZmlndXJhdGlvbnMgb3IgU1ZHIGlucHV0cyBmb3IgcmVuZGVyaW5nLiBFeHBvcnRzIHRvIGEgY2hhcnQgZnJvbSBhIHBhZ2VcclxuICogdXNpbmcgUHVwcGV0ZWVyLlxyXG4gKi9cclxuXHJcbmltcG9ydCB7IGFkZFBhZ2VSZXNvdXJjZXMsIGNsZWFyUGFnZVJlc291cmNlcyB9IGZyb20gJy4vYnJvd3Nlci5qcyc7XHJcbmltcG9ydCB7IGNyZWF0ZUNoYXJ0IH0gZnJvbSAnLi9oaWdoY2hhcnRzLmpzJztcclxuaW1wb3J0IHsgbG9nIH0gZnJvbSAnLi9sb2dnZXIuanMnO1xyXG5cclxuaW1wb3J0IHN2Z1RlbXBsYXRlIGZyb20gJy4uL3RlbXBsYXRlcy9zdmdFeHBvcnQvc3ZnRXhwb3J0LmpzJztcclxuXHJcbmltcG9ydCBFeHBvcnRFcnJvciBmcm9tICcuL2Vycm9ycy9FeHBvcnRFcnJvci5qcyc7XHJcblxyXG4vKipcclxuICogRXhwb3J0cyB0byBhIGNoYXJ0IGZyb20gYSBwYWdlIHVzaW5nIFB1cHBldGVlci5cclxuICpcclxuICogQGFzeW5jXHJcbiAqIEBmdW5jdGlvbiBwdXBwZXRlZXJFeHBvcnRcclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IHBhZ2UgLSBQdXBwZXRlZXIgcGFnZSBvYmplY3QuXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBvcHRpb25zIC0gVGhlIGBvcHRpb25zYCBvYmplY3QgY29udGFpbmluZyBjb21wbGV0ZSBzZXRcclxuICogb2Ygb3B0aW9ucy5cclxuICpcclxuICogQHJldHVybnMge1Byb21pc2U8KHN0cmluZ3xCdWZmZXJ8RXhwb3J0RXJyb3IpPn0gQSBQcm9taXNlIHRoYXQgcmVzb2x2ZXNcclxuICogdG8gdGhlIGV4cG9ydGVkIGRhdGEgb3IgcmVqZWN0aW5nIHdpdGggYW4gYEV4cG9ydEVycm9yYC5cclxuICpcclxuICogQHRocm93cyB7RXhwb3J0RXJyb3J9IFRocm93cyBhbiBgRXhwb3J0RXJyb3JgIGlmIGV4cG9ydCB0byBhbiB1bnN1cHBvcnRlZFxyXG4gKiBvdXRwdXQgZm9ybWF0IG9jY3Vycy5cclxuICovXHJcbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBwdXBwZXRlZXJFeHBvcnQocGFnZSwgb3B0aW9ucykge1xyXG4gIC8vIEluamVjdGVkIHJlc291cmNlcyBhcnJheSAoYWRkaXRpb25hbCBKUyBhbmQgQ1NTKVxyXG4gIGNvbnN0IGluamVjdGVkUmVzb3VyY2VzID0gW107XHJcblxyXG4gIHRyeSB7XHJcbiAgICAvLyBHZXQgdGhlIGBleHBvcnRgIG9wdGlvbnNcclxuICAgIGNvbnN0IGV4cG9ydE9wdGlvbnMgPSBvcHRpb25zLmV4cG9ydDtcclxuXHJcbiAgICBsZXQgaXNTVkcgPSBmYWxzZTtcclxuICAgIGlmIChleHBvcnRPcHRpb25zLnN2Zykge1xyXG4gICAgICBsb2coNCwgJ1tleHBvcnRdIFRyZWF0aW5nIGFzIFNWRyBpbnB1dC4nKTtcclxuXHJcbiAgICAgIC8vIElmIHRoZSBgdHlwZWAgaXMgYWxzbyBTVkcsIHJldHVybiB0aGUgaW5wdXRcclxuICAgICAgaWYgKGV4cG9ydE9wdGlvbnMudHlwZSA9PT0gJ3N2ZycpIHtcclxuICAgICAgICByZXR1cm4gZXhwb3J0T3B0aW9ucy5zdmc7XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIC8vIE1hcmsgYXMgU1ZHIGV4cG9ydCBmb3IgdGhlIGxhdGVyIHNpemUgY29ycmVjdGlvbnNcclxuICAgICAgaXNTVkcgPSB0cnVlO1xyXG5cclxuICAgICAgLy8gU1ZHIGV4cG9ydFxyXG4gICAgICBhd2FpdCBfc2V0QXNTdmcocGFnZSwgZXhwb3J0T3B0aW9ucy5zdmcpO1xyXG4gICAgfSBlbHNlIHtcclxuICAgICAgbG9nKDQsICdbZXhwb3J0XSBUcmVhdGluZyBhcyBKU09OIGNvbmZpZy4nKTtcclxuXHJcbiAgICAgIC8vIE9wdGlvbnMgZXhwb3J0XHJcbiAgICAgIGF3YWl0IF9zZXRBc09wdGlvbnMocGFnZSwgb3B0aW9ucyk7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gS2VlcHMgdHJhY2sgb2YgYWxsIHJlc291cmNlcyBhZGRlZCBvbiB0aGUgcGFnZSB3aXRoIGFkZFhYWFRhZy4gZXRjXHJcbiAgICAvLyBJdCdzIFZJVEFMIHRoYXQgYWxsIGFkZGVkIHJlc291cmNlcyBlbmRzIHVwIGhlcmUgc28gd2UgY2FuIGNsZWFyIHRoaW5nc1xyXG4gICAgLy8gb3V0IHdoZW4gZG9pbmcgYSBuZXcgZXhwb3J0IGluIHRoZSBzYW1lIHBhZ2UhXHJcbiAgICBpbmplY3RlZFJlc291cmNlcy5wdXNoKFxyXG4gICAgICAuLi4oYXdhaXQgYWRkUGFnZVJlc291cmNlcyhwYWdlLCBvcHRpb25zLmN1c3RvbUxvZ2ljKSlcclxuICAgICk7XHJcblxyXG4gICAgLy8gR2V0IHRoZSByZWFsIGNoYXJ0IHNpemUgYW5kIHNldCB0aGUgem9vbSBhY2NvcmRpbmdseVxyXG4gICAgY29uc3Qgc2l6ZSA9IGlzU1ZHXHJcbiAgICAgID8gYXdhaXQgcGFnZS5ldmFsdWF0ZSgoc2NhbGUpID0+IHtcclxuICAgICAgICAgIGNvbnN0IHN2Z0VsZW1lbnQgPSBkb2N1bWVudC5xdWVyeVNlbGVjdG9yKFxyXG4gICAgICAgICAgICAnI2NoYXJ0LWNvbnRhaW5lciBzdmc6Zmlyc3Qtb2YtdHlwZSdcclxuICAgICAgICAgICk7XHJcblxyXG4gICAgICAgICAgLy8gR2V0IHRoZSB2YWx1ZXMgY29ycmVjdGx5IHNjYWxlZFxyXG4gICAgICAgICAgY29uc3QgY2hhcnRIZWlnaHQgPSBzdmdFbGVtZW50LmhlaWdodC5iYXNlVmFsLnZhbHVlICogc2NhbGU7XHJcbiAgICAgICAgICBjb25zdCBjaGFydFdpZHRoID0gc3ZnRWxlbWVudC53aWR0aC5iYXNlVmFsLnZhbHVlICogc2NhbGU7XHJcblxyXG4gICAgICAgICAgLy8gSW4gY2FzZSBvZiBTVkcgdGhlIHpvb20gbXVzdCBiZSBzZXQgZGlyZWN0bHkgZm9yIGJvZHkgYXMgc2NhbGVcclxuICAgICAgICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBuby11bmRlZlxyXG4gICAgICAgICAgZG9jdW1lbnQuYm9keS5zdHlsZS56b29tID0gc2NhbGU7XHJcblxyXG4gICAgICAgICAgLy8gU2V0IHRoZSBtYXJnaW4gdG8gMHB4XHJcbiAgICAgICAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgbm8tdW5kZWZcclxuICAgICAgICAgIGRvY3VtZW50LmJvZHkuc3R5bGUubWFyZ2luID0gJzBweCc7XHJcblxyXG4gICAgICAgICAgcmV0dXJuIHtcclxuICAgICAgICAgICAgY2hhcnRIZWlnaHQsXHJcbiAgICAgICAgICAgIGNoYXJ0V2lkdGhcclxuICAgICAgICAgIH07XHJcbiAgICAgICAgfSwgcGFyc2VGbG9hdChleHBvcnRPcHRpb25zLnNjYWxlKSlcclxuICAgICAgOiBhd2FpdCBwYWdlLmV2YWx1YXRlKCgpID0+IHtcclxuICAgICAgICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBuby11bmRlZlxyXG4gICAgICAgICAgY29uc3QgeyBjaGFydEhlaWdodCwgY2hhcnRXaWR0aCB9ID0gd2luZG93LkhpZ2hjaGFydHMuY2hhcnRzWzBdO1xyXG5cclxuICAgICAgICAgIC8vIE5vIG5lZWQgZm9yIHN1Y2ggc2NhbGUgbWFuaXB1bGF0aW9uIGluIGNhc2Ugb2Ygb3RoZXIgdHlwZXNcclxuICAgICAgICAgIC8vIG9mIGV4cG9ydHMuIFJlc2V0IHRoZSB6b29tIGZvciBvdGhlciBleHBvcnRzIHRoYW4gdG8gU1ZHc1xyXG4gICAgICAgICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIG5vLXVuZGVmXHJcbiAgICAgICAgICBkb2N1bWVudC5ib2R5LnN0eWxlLnpvb20gPSAxO1xyXG5cclxuICAgICAgICAgIHJldHVybiB7XHJcbiAgICAgICAgICAgIGNoYXJ0SGVpZ2h0LFxyXG4gICAgICAgICAgICBjaGFydFdpZHRoXHJcbiAgICAgICAgICB9O1xyXG4gICAgICAgIH0pO1xyXG5cclxuICAgIC8vIEdldCB0aGUgY2xpcCByZWdpb24gZm9yIHRoZSBwYWdlXHJcbiAgICBjb25zdCB7IHgsIHkgfSA9IGF3YWl0IF9nZXRDbGlwUmVnaW9uKHBhZ2UpO1xyXG5cclxuICAgIC8vIFNldCBmaW5hbCBgaGVpZ2h0YCBmb3Igdmlld3BvcnRcclxuICAgIGNvbnN0IHZpZXdwb3J0SGVpZ2h0ID0gTWF0aC5hYnMoXHJcbiAgICAgIE1hdGguY2VpbChzaXplLmNoYXJ0SGVpZ2h0IHx8IGV4cG9ydE9wdGlvbnMuaGVpZ2h0KVxyXG4gICAgKTtcclxuXHJcbiAgICAvLyBTZXQgZmluYWwgYHdpZHRoYCBmb3Igdmlld3BvcnRcclxuICAgIGNvbnN0IHZpZXdwb3J0V2lkdGggPSBNYXRoLmFicyhcclxuICAgICAgTWF0aC5jZWlsKHNpemUuY2hhcnRXaWR0aCB8fCBleHBvcnRPcHRpb25zLndpZHRoKVxyXG4gICAgKTtcclxuXHJcbiAgICAvLyBTZXQgdGhlIGZpbmFsIHZpZXdwb3J0IG5vdyB0aGF0IHdlIGhhdmUgdGhlIHJlYWwgaGVpZ2h0XHJcbiAgICBhd2FpdCBwYWdlLnNldFZpZXdwb3J0KHtcclxuICAgICAgaGVpZ2h0OiB2aWV3cG9ydEhlaWdodCxcclxuICAgICAgd2lkdGg6IHZpZXdwb3J0V2lkdGgsXHJcbiAgICAgIGRldmljZVNjYWxlRmFjdG9yOiBpc1NWRyA/IDEgOiBwYXJzZUZsb2F0KGV4cG9ydE9wdGlvbnMuc2NhbGUpXHJcbiAgICB9KTtcclxuXHJcbiAgICBsZXQgcmVzdWx0O1xyXG4gICAgLy8gUmFzdGVyaXphdGlvbiBwcm9jZXNzXHJcbiAgICBzd2l0Y2ggKGV4cG9ydE9wdGlvbnMudHlwZSkge1xyXG4gICAgICBjYXNlICdzdmcnOlxyXG4gICAgICAgIHJlc3VsdCA9IGF3YWl0IF9jcmVhdGVTVkcocGFnZSk7XHJcbiAgICAgICAgYnJlYWs7XHJcbiAgICAgIGNhc2UgJ3BuZyc6XHJcbiAgICAgIGNhc2UgJ2pwZWcnOlxyXG4gICAgICAgIHJlc3VsdCA9IGF3YWl0IF9jcmVhdGVJbWFnZShcclxuICAgICAgICAgIHBhZ2UsXHJcbiAgICAgICAgICBleHBvcnRPcHRpb25zLnR5cGUsXHJcbiAgICAgICAgICB7XHJcbiAgICAgICAgICAgIHdpZHRoOiB2aWV3cG9ydFdpZHRoLFxyXG4gICAgICAgICAgICBoZWlnaHQ6IHZpZXdwb3J0SGVpZ2h0LFxyXG4gICAgICAgICAgICB4LFxyXG4gICAgICAgICAgICB5XHJcbiAgICAgICAgICB9LFxyXG4gICAgICAgICAgZXhwb3J0T3B0aW9ucy5yYXN0ZXJpemF0aW9uVGltZW91dFxyXG4gICAgICAgICk7XHJcbiAgICAgICAgYnJlYWs7XHJcbiAgICAgIGNhc2UgJ3BkZic6XHJcbiAgICAgICAgcmVzdWx0ID0gYXdhaXQgX2NyZWF0ZVBERihcclxuICAgICAgICAgIHBhZ2UsXHJcbiAgICAgICAgICB2aWV3cG9ydEhlaWdodCxcclxuICAgICAgICAgIHZpZXdwb3J0V2lkdGgsXHJcbiAgICAgICAgICBleHBvcnRPcHRpb25zLnJhc3Rlcml6YXRpb25UaW1lb3V0XHJcbiAgICAgICAgKTtcclxuICAgICAgICBicmVhaztcclxuICAgICAgZGVmYXVsdDpcclxuICAgICAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoXHJcbiAgICAgICAgICBgW2V4cG9ydF0gVW5zdXBwb3J0ZWQgb3V0cHV0IGZvcm1hdDogJHtleHBvcnRPcHRpb25zLnR5cGV9LmAsXHJcbiAgICAgICAgICA0MDBcclxuICAgICAgICApO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIENsZWFyIHByZXZpb3VzbHkgaW5qZWN0ZWQgSlMgYW5kIENTUyByZXNvdXJjZXNcclxuICAgIGF3YWl0IGNsZWFyUGFnZVJlc291cmNlcyhwYWdlLCBpbmplY3RlZFJlc291cmNlcyk7XHJcbiAgICByZXR1cm4gcmVzdWx0O1xyXG4gIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICBhd2FpdCBjbGVhclBhZ2VSZXNvdXJjZXMocGFnZSwgaW5qZWN0ZWRSZXNvdXJjZXMpO1xyXG4gICAgcmV0dXJuIGVycm9yO1xyXG4gIH1cclxufVxyXG5cclxuLyoqXHJcbiAqIFNldHMgdGhlIHNwZWNpZmllZCBwYWdlJ3MgY29udGVudCB3aXRoIHByb3ZpZGVkIGV4cG9ydCBpbnB1dCB3aXRoaW5cclxuICogdGhlIHdpbmRvdyBjb250ZXh0IHVzaW5nIHRoZSBgcGFnZS5zZXRDb250ZW50YCBmdW5jdGlvbi5cclxuICpcclxuICogQGFzeW5jXHJcbiAqIEBmdW5jdGlvbiBfc2V0QXNTdmdcclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IHBhZ2UgLSBQdXBwZXRlZXIgcGFnZSBvYmplY3QuXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSBzdmcgLSBUaGUgU1ZHIGlucHV0IGNvbnRlbnQgdG8gYmUgZXhwb3J0ZWQuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtQcm9taXNlPHZvaWQ+fSBBIFByb21pc2UgdGhhdCByZXNvbHZlcyBhZnRlciB0aGUgY29udGVudCBpcyBzZXQuXHJcbiAqL1xyXG5hc3luYyBmdW5jdGlvbiBfc2V0QXNTdmcocGFnZSwgc3ZnKSB7XHJcbiAgYXdhaXQgcGFnZS5zZXRDb250ZW50KHN2Z1RlbXBsYXRlKHN2ZyksIHtcclxuICAgIHdhaXRVbnRpbDogJ2RvbWNvbnRlbnRsb2FkZWQnXHJcbiAgfSk7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBTZXRzIHRoZSBvcHRpb25zIHdpdGggc3BlY2lmaWVkIGV4cG9ydCBpbnB1dCBhbmQgc2l6ZXMgYXMgY29uZmlndXJhdGlvbiBpbnRvXHJcbiAqIHRoZSBgY3JlYXRlQ2hhcnRgIGZ1bmN0aW9uIHdpdGhpbiB0aGUgd2luZG93IGNvbnRleHQgdXNpbmdcclxuICogdGhlIGBwYWdlLmV2YWx1YXRlYCBmdW5jdGlvbi5cclxuICpcclxuICogQGFzeW5jXHJcbiAqIEBmdW5jdGlvbiBfc2V0QXNPcHRpb25zXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBwYWdlIC0gUHVwcGV0ZWVyIHBhZ2Ugb2JqZWN0LlxyXG4gKiBAcGFyYW0ge09iamVjdH0gb3B0aW9ucyAtIFRoZSBgb3B0aW9uc2Agb2JqZWN0IGNvbnRhaW5pbmcgY29tcGxldGUgc2V0XHJcbiAqIG9mIG9wdGlvbnMuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtQcm9taXNlPHZvaWQ+fSBBIFByb21pc2UgdGhhdCByZXNvbHZlcyBhZnRlciB0aGUgY29uZmlndXJhdGlvblxyXG4gKiBpcyBzZXQuXHJcbiAqL1xyXG5hc3luYyBmdW5jdGlvbiBfc2V0QXNPcHRpb25zKHBhZ2UsIG9wdGlvbnMpIHtcclxuICBhd2FpdCBwYWdlLmV2YWx1YXRlKGNyZWF0ZUNoYXJ0LCBvcHRpb25zKTtcclxufVxyXG5cclxuLyoqXHJcbiAqIFJldHJpZXZlcyB0aGUgY2xpcHBpbmcgcmVnaW9uIGNvb3JkaW5hdGVzIG9mIHRoZSBzcGVjaWZpZWQgcGFnZSBlbGVtZW50XHJcbiAqIHdpdGggdGhlICdjaGFydC1jb250YWluZXInIGlkLlxyXG4gKlxyXG4gKiBAYXN5bmNcclxuICogQGZ1bmN0aW9uIF9nZXRDbGlwUmVnaW9uXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBwYWdlIC0gUHVwcGV0ZWVyIHBhZ2Ugb2JqZWN0LlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7UHJvbWlzZTxPYmplY3Q+fSBBIFByb21pc2UgdGhhdCByZXNvbHZlcyB0byBhbiBvYmplY3QgY29udGFpbmluZ1xyXG4gKiBgeGAsIGB5YCwgYHdpZHRoYCwgYW5kIGBoZWlnaHRgIHByb3BlcnRpZXMuXHJcbiAqL1xyXG5hc3luYyBmdW5jdGlvbiBfZ2V0Q2xpcFJlZ2lvbihwYWdlKSB7XHJcbiAgcmV0dXJuIHBhZ2UuJGV2YWwoJyNjaGFydC1jb250YWluZXInLCAoZWxlbWVudCkgPT4ge1xyXG4gICAgY29uc3QgeyB4LCB5LCB3aWR0aCwgaGVpZ2h0IH0gPSBlbGVtZW50LmdldEJvdW5kaW5nQ2xpZW50UmVjdCgpO1xyXG4gICAgcmV0dXJuIHtcclxuICAgICAgeCxcclxuICAgICAgeSxcclxuICAgICAgd2lkdGgsXHJcbiAgICAgIGhlaWdodDogTWF0aC50cnVuYyhoZWlnaHQgPiAxID8gaGVpZ2h0IDogNTAwKVxyXG4gICAgfTtcclxuICB9KTtcclxufVxyXG5cclxuLyoqXHJcbiAqIENyZWF0ZXMgYW4gU1ZHIGJ5IGV2YWx1YXRpbmcgdGhlIGBvdXRlckhUTUxgIG9mIHRoZSBmaXJzdCAnc3ZnJyBlbGVtZW50XHJcbiAqIGluc2lkZSBhbiBlbGVtZW50IHdpdGggdGhlIGlkICdjb250YWluZXInLlxyXG4gKlxyXG4gKiBAYXN5bmNcclxuICogQGZ1bmN0aW9uIF9jcmVhdGVTVkdcclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IHBhZ2UgLSBQdXBwZXRlZXIgcGFnZSBvYmplY3QuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtQcm9taXNlPHN0cmluZz59IEEgUHJvbWlzZSB0aGF0IHJlc29sdmVzIHRvIHRoZSBTVkcgc3RyaW5nLlxyXG4gKi9cclxuYXN5bmMgZnVuY3Rpb24gX2NyZWF0ZVNWRyhwYWdlKSB7XHJcbiAgcmV0dXJuIHBhZ2UuJGV2YWwoXHJcbiAgICAnI2NvbnRhaW5lciBzdmc6Zmlyc3Qtb2YtdHlwZScsXHJcbiAgICAoZWxlbWVudCkgPT4gZWxlbWVudC5vdXRlckhUTUxcclxuICApO1xyXG59XHJcblxyXG4vKipcclxuICogQ3JlYXRlcyBhbiBpbWFnZSB1c2luZyBQdXBwZXRlZXIncyBwYWdlIGBzY3JlZW5zaG90YCBmdW5jdGlvbmFsaXR5IHdpdGhcclxuICogc3BlY2lmaWVkIG9wdGlvbnMuXHJcbiAqXHJcbiAqIEBhc3luY1xyXG4gKiBAZnVuY3Rpb24gX2NyZWF0ZUltYWdlXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBwYWdlIC0gUHVwcGV0ZWVyIHBhZ2Ugb2JqZWN0LlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gdHlwZSAtIEltYWdlIHR5cGUuXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBjbGlwIC0gQ2xpcHBpbmcgcmVnaW9uIGNvb3JkaW5hdGVzLlxyXG4gKiBAcGFyYW0ge251bWJlcn0gcmFzdGVyaXphdGlvblRpbWVvdXQgLSBUaW1lb3V0IGZvciByYXN0ZXJpemF0aW9uXHJcbiAqIGluIG1pbGxpc2Vjb25kcy5cclxuICpcclxuICogQHJldHVybnMge1Byb21pc2U8QnVmZmVyPn0gQSBQcm9taXNlIHRoYXQgcmVzb2x2ZXMgdG8gdGhlIGltYWdlIGJ1ZmZlclxyXG4gKiBvciByZWplY3Rpbmcgd2l0aCBhbiBgRXhwb3J0RXJyb3JgIGZvciB0aW1lb3V0LlxyXG4gKi9cclxuYXN5bmMgZnVuY3Rpb24gX2NyZWF0ZUltYWdlKHBhZ2UsIHR5cGUsIGNsaXAsIHJhc3Rlcml6YXRpb25UaW1lb3V0KSB7XHJcbiAgcmV0dXJuIFByb21pc2UucmFjZShbXHJcbiAgICBwYWdlLnNjcmVlbnNob3Qoe1xyXG4gICAgICB0eXBlLFxyXG4gICAgICBjbGlwLFxyXG4gICAgICBlbmNvZGluZzogJ2Jhc2U2NCcsXHJcbiAgICAgIGZ1bGxQYWdlOiBmYWxzZSxcclxuICAgICAgb3B0aW1pemVGb3JTcGVlZDogdHJ1ZSxcclxuICAgICAgY2FwdHVyZUJleW9uZFZpZXdwb3J0OiB0cnVlLFxyXG4gICAgICAuLi4odHlwZSAhPT0gJ3BuZycgPyB7IHF1YWxpdHk6IDgwIH0gOiB7fSksXHJcbiAgICAgIC8vIEFsd2F5cyByZW5kZXIgb24gYSB0cmFuc3BhcmVudCBwYWdlIGlmIHRoZSBleHBlY3RlZCB0eXBlIGZvcm1hdCBpcyBQTkdcclxuICAgICAgb21pdEJhY2tncm91bmQ6IHR5cGUgPT0gJ3BuZycgLy8gIzQ0NywgIzQ2M1xyXG4gICAgfSksXHJcbiAgICBuZXcgUHJvbWlzZSgoX3Jlc29sdmUsIHJlamVjdCkgPT5cclxuICAgICAgc2V0VGltZW91dChcclxuICAgICAgICAoKSA9PiByZWplY3QobmV3IEV4cG9ydEVycm9yKCdSYXN0ZXJpemF0aW9uIHRpbWVvdXQnLCA0MDgpKSxcclxuICAgICAgICByYXN0ZXJpemF0aW9uVGltZW91dCB8fCAxNTAwXHJcbiAgICAgIClcclxuICAgIClcclxuICBdKTtcclxufVxyXG5cclxuLyoqXHJcbiAqIENyZWF0ZXMgYSBQREYgdXNpbmcgUHVwcGV0ZWVyJ3MgcGFnZSBgcGRmYCBmdW5jdGlvbmFsaXR5IHdpdGggc3BlY2lmaWVkXHJcbiAqIG9wdGlvbnMuXHJcbiAqXHJcbiAqIEBhc3luY1xyXG4gKiBAZnVuY3Rpb24gX2NyZWF0ZVBERlxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gcGFnZSAtIFB1cHBldGVlciBwYWdlIG9iamVjdC5cclxuICogQHBhcmFtIHtudW1iZXJ9IGhlaWdodCAtIFBERiBoZWlnaHQuXHJcbiAqIEBwYXJhbSB7bnVtYmVyfSB3aWR0aCAtIFBERiB3aWR0aC5cclxuICogQHBhcmFtIHtudW1iZXJ9IHJhc3Rlcml6YXRpb25UaW1lb3V0IC0gVGltZW91dCBmb3IgcmFzdGVyaXphdGlvblxyXG4gKiBpbiBtaWxsaXNlY29uZHMuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtQcm9taXNlPEJ1ZmZlcj59IEEgUHJvbWlzZSB0aGF0IHJlc29sdmVzIHRvIHRoZSBQREYgYnVmZmVyLlxyXG4gKi9cclxuYXN5bmMgZnVuY3Rpb24gX2NyZWF0ZVBERihwYWdlLCBoZWlnaHQsIHdpZHRoLCByYXN0ZXJpemF0aW9uVGltZW91dCkge1xyXG4gIGF3YWl0IHBhZ2UuZW11bGF0ZU1lZGlhVHlwZSgnc2NyZWVuJyk7XHJcbiAgcmV0dXJuIHBhZ2UucGRmKHtcclxuICAgIC8vIFRoaXMgd2lsbCByZW1vdmUgYW4gZXh0cmEgZW1wdHkgcGFnZSBpbiBQREYgZXhwb3J0c1xyXG4gICAgaGVpZ2h0OiBoZWlnaHQgKyAxLFxyXG4gICAgd2lkdGgsXHJcbiAgICBlbmNvZGluZzogJ2Jhc2U2NCcsXHJcbiAgICB0aW1lb3V0OiByYXN0ZXJpemF0aW9uVGltZW91dCB8fCAxNTAwXHJcbiAgfSk7XHJcbn1cclxuXHJcbmV4cG9ydCBkZWZhdWx0IHtcclxuICBwdXBwZXRlZXJFeHBvcnRcclxufTtcclxuIiwiLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcclxuXHJcbkhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlclxyXG5cclxuQ29weXJpZ2h0IChjKSAyMDE2LTIwMjUsIEhpZ2hzb2Z0XHJcblxyXG5MaWNlbmNlZCB1bmRlciB0aGUgTUlUIGxpY2VuY2UuXHJcblxyXG5BZGRpdGlvbmFsbHkgYSB2YWxpZCBIaWdoY2hhcnRzIGxpY2Vuc2UgaXMgcmVxdWlyZWQgZm9yIHVzZS5cclxuXHJcblNlZSBMSUNFTlNFIGZpbGUgaW4gcm9vdCBmb3IgZGV0YWlscy5cclxuXHJcbioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXHJcblxyXG4vKipcclxuICogQG92ZXJ2aWV3IFRoaXMgbW9kdWxlIHByb3ZpZGVzIGEgd29ya2VyIHBvb2wgaW1wbGVtZW50YXRpb24gZm9yIG1hbmFnaW5nXHJcbiAqIHRoZSBicm93c2VyIGluc3RhbmNlIGFuZCBwYWdlcywgc3BlY2lmaWNhbGx5IGRlc2lnbmVkIGZvciB1c2Ugd2l0aFxyXG4gKiB0aGUgSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyLiBJdCBvcHRpbWl6ZXMgcmVzb3VyY2VzIHVzYWdlIGFuZCBwZXJmb3JtYW5jZVxyXG4gKiBieSBtYWludGFpbmluZyBhIHBvb2wgb2Ygd29ya2VycyB0aGF0IGNhbiBoYW5kbGUgY29uY3VycmVudCBleHBvcnQgdGFza3NcclxuICogdXNpbmcgUHVwcGV0ZWVyLlxyXG4gKi9cclxuXHJcbmltcG9ydCB7IFBvb2wgfSBmcm9tICd0YXJuJztcclxuaW1wb3J0IHsgdjQgYXMgdXVpZCB9IGZyb20gJ3V1aWQnO1xyXG5cclxuaW1wb3J0IHsgY3JlYXRlQnJvd3NlciwgY2xvc2VCcm93c2VyLCBuZXdQYWdlLCBjbGVhclBhZ2UgfSBmcm9tICcuL2Jyb3dzZXIuanMnO1xyXG5pbXBvcnQgeyBnZXRPcHRpb25zIH0gZnJvbSAnLi9jb25maWcuanMnO1xyXG5pbXBvcnQgeyBwdXBwZXRlZXJFeHBvcnQgfSBmcm9tICcuL2V4cG9ydC5qcyc7XHJcbmltcG9ydCB7IGxvZywgbG9nV2l0aFN0YWNrIH0gZnJvbSAnLi9sb2dnZXIuanMnO1xyXG5pbXBvcnQgeyBnZXROZXdEYXRlVGltZSwgbWVhc3VyZVRpbWUgfSBmcm9tICcuL3V0aWxzLmpzJztcclxuXHJcbmltcG9ydCBFeHBvcnRFcnJvciBmcm9tICcuL2Vycm9ycy9FeHBvcnRFcnJvci5qcyc7XHJcblxyXG4vLyBUaGUgcG9vbCBpbnN0YW5jZVxyXG5sZXQgcG9vbCA9IG51bGw7XHJcblxyXG4vLyBQb29sIHN0YXRpc3RpY3NcclxuY29uc3QgcG9vbFN0YXRzID0ge1xyXG4gIGV4cG9ydHNBdHRlbXB0ZWQ6IDAsXHJcbiAgZXhwb3J0c1BlcmZvcm1lZDogMCxcclxuICBleHBvcnRzRHJvcHBlZDogMCxcclxuICBleHBvcnRzRnJvbVN2ZzogMCxcclxuICBleHBvcnRzRnJvbU9wdGlvbnM6IDAsXHJcbiAgZXhwb3J0c0Zyb21TdmdBdHRlbXB0czogMCxcclxuICBleHBvcnRzRnJvbU9wdGlvbnNBdHRlbXB0czogMCxcclxuICB0aW1lU3BlbnQ6IDAsXHJcbiAgdGltZVNwZW50QXZlcmFnZTogMFxyXG59O1xyXG5cclxuLyoqXHJcbiAqIEluaXRpYWxpemVzIHRoZSBleHBvcnQgcG9vbCB3aXRoIHRoZSBwcm92aWRlZCBjb25maWd1cmF0aW9uLCBjcmVhdGluZ1xyXG4gKiBhIGJyb3dzZXIgaW5zdGFuY2UgYW5kIHNldHRpbmcgdXAgd29ya2VyIHJlc291cmNlcy5cclxuICpcclxuICogQGFzeW5jXHJcbiAqIEBmdW5jdGlvbiBpbml0UG9vbFxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gW3Bvb2xPcHRpb25zPWdldE9wdGlvbnMoKS5wb29sXSAtIE9iamVjdCBjb250YWluaW5nIGBwb29sYFxyXG4gKiBvcHRpb25zLiBUaGUgZGVmYXVsdCB2YWx1ZSBpcyB0aGUgZ2xvYmFsIHBvb2wgb3B0aW9ucyBvZiB0aGUgZXhwb3J0IHNlcnZlclxyXG4gKiBpbnN0YW5jZS5cclxuICogQHBhcmFtIHtBcnJheS48c3RyaW5nPn0gW3B1cHBldGVlckFyZ3M9W11dIC0gQWRkaXRpb25hbCBhcmd1bWVudHNcclxuICogZm9yIFB1cHBldGVlciBsYXVuY2guIFRoZSBkZWZhdWx0IHZhbHVlIGlzIGFuIGVtcHR5IGFycmF5LlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7UHJvbWlzZTx2b2lkPn0gQSBQcm9taXNlIHRoYXQgcmVzb2x2ZXMgdG8gZW5kaW5nIHRoZSBmdW5jdGlvblxyXG4gKiBleGVjdXRpb24gd2hlbiBhbiBhbHJlYWR5IGluaXRpYWxpemVkIHBvb2wgb2YgcmVzb3VyY2VzIGlzIGZvdW5kLlxyXG4gKlxyXG4gKiBAdGhyb3dzIHtFeHBvcnRFcnJvcn0gVGhyb3dzIGFuIGBFeHBvcnRFcnJvcmAgaWYgY291bGQgbm90IGNyZWF0ZSB0aGUgcG9vbFxyXG4gKiBvZiB3b3JrZXJzLlxyXG4gKi9cclxuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIGluaXRQb29sKFxyXG4gIHBvb2xPcHRpb25zID0gZ2V0T3B0aW9ucygpLnBvb2wsXHJcbiAgcHVwcGV0ZWVyQXJncyA9IFtdXHJcbikge1xyXG4gIC8vIENyZWF0ZSBhIGJyb3dzZXIgaW5zdGFuY2Ugd2l0aCB0aGUgcHVwcGV0ZWVyIGFyZ3VtZW50c1xyXG4gIGF3YWl0IGNyZWF0ZUJyb3dzZXIocHVwcGV0ZWVyQXJncyk7XHJcblxyXG4gIHRyeSB7XHJcbiAgICBsb2coXHJcbiAgICAgIDMsXHJcbiAgICAgIGBbcG9vbF0gSW5pdGlhbGl6aW5nIHBvb2wgd2l0aCB3b3JrZXJzOiBtaW4gJHtwb29sT3B0aW9ucy5taW5Xb3JrZXJzfSwgbWF4ICR7cG9vbE9wdGlvbnMubWF4V29ya2Vyc30uYFxyXG4gICAgKTtcclxuXHJcbiAgICBpZiAocG9vbCkge1xyXG4gICAgICBsb2coXHJcbiAgICAgICAgNCxcclxuICAgICAgICAnW3Bvb2xdIEFscmVhZHkgaW5pdGlhbGl6ZWQsIHBsZWFzZSBraWxsIGl0IGJlZm9yZSBjcmVhdGluZyBhIG5ldyBvbmUuJ1xyXG4gICAgICApO1xyXG4gICAgICByZXR1cm47XHJcbiAgICB9XHJcblxyXG4gICAgLy8gS2VlcCBhbiBleWUgb24gYSBjb3JyZWN0IG1pbiBhbmQgbWF4IHdvcmtlcnMgbnVtYmVyXHJcbiAgICBpZiAocG9vbE9wdGlvbnMubWluV29ya2VycyA+IHBvb2xPcHRpb25zLm1heFdvcmtlcnMpIHtcclxuICAgICAgcG9vbE9wdGlvbnMubWluV29ya2VycyA9IHBvb2xPcHRpb25zLm1heFdvcmtlcnM7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gQ3JlYXRlIGEgcG9vbCBhbG9uZyB3aXRoIGEgbWluaW1hbCBudW1iZXIgb2YgcmVzb3VyY2VzXHJcbiAgICBwb29sID0gbmV3IFBvb2woe1xyXG4gICAgICAvLyBHZXQgdGhlIGBjcmVhdGVgLCBgdmFsaWRhdGVgLCBhbmQgYGRlc3Ryb3lgIGZ1bmN0aW9uc1xyXG4gICAgICAuLi5fZmFjdG9yeShwb29sT3B0aW9ucyksXHJcbiAgICAgIG1pbjogcG9vbE9wdGlvbnMubWluV29ya2VycyxcclxuICAgICAgbWF4OiBwb29sT3B0aW9ucy5tYXhXb3JrZXJzLFxyXG4gICAgICBhY3F1aXJlVGltZW91dE1pbGxpczogcG9vbE9wdGlvbnMuYWNxdWlyZVRpbWVvdXQsXHJcbiAgICAgIGNyZWF0ZVRpbWVvdXRNaWxsaXM6IHBvb2xPcHRpb25zLmNyZWF0ZVRpbWVvdXQsXHJcbiAgICAgIGRlc3Ryb3lUaW1lb3V0TWlsbGlzOiBwb29sT3B0aW9ucy5kZXN0cm95VGltZW91dCxcclxuICAgICAgaWRsZVRpbWVvdXRNaWxsaXM6IHBvb2xPcHRpb25zLmlkbGVUaW1lb3V0LFxyXG4gICAgICBjcmVhdGVSZXRyeUludGVydmFsTWlsbGlzOiBwb29sT3B0aW9ucy5jcmVhdGVSZXRyeUludGVydmFsLFxyXG4gICAgICByZWFwSW50ZXJ2YWxNaWxsaXM6IHBvb2xPcHRpb25zLnJlYXBlckludGVydmFsLFxyXG4gICAgICBwcm9wYWdhdGVDcmVhdGVFcnJvcjogZmFsc2VcclxuICAgIH0pO1xyXG5cclxuICAgIC8vIFNldCBldmVudHNcclxuICAgIHBvb2wub24oJ3JlbGVhc2UnLCBhc3luYyAocmVzb3VyY2UpID0+IHtcclxuICAgICAgLy8gQ2xlYXIgcGFnZVxyXG4gICAgICBjb25zdCBjbGVhclN0YXR1cyA9IGF3YWl0IGNsZWFyUGFnZShyZXNvdXJjZSwgZmFsc2UpO1xyXG4gICAgICBsb2coXHJcbiAgICAgICAgNCxcclxuICAgICAgICBgW3Bvb2xdIFBvb2wgcmVzb3VyY2UgWyR7cmVzb3VyY2UuaWR9XSAtIFJlbGVhc2luZyBhIHdvcmtlci4gQ2xlYXIgcGFnZSBzdGF0dXM6ICR7Y2xlYXJTdGF0dXN9LmBcclxuICAgICAgKTtcclxuICAgIH0pO1xyXG5cclxuICAgIHBvb2wub24oJ2Rlc3Ryb3lTdWNjZXNzJywgKF9ldmVudElkLCByZXNvdXJjZSkgPT4ge1xyXG4gICAgICBsb2coXHJcbiAgICAgICAgNCxcclxuICAgICAgICBgW3Bvb2xdIFBvb2wgcmVzb3VyY2UgWyR7cmVzb3VyY2UuaWR9XSAtIERlc3Ryb3llZCBhIHdvcmtlciBzdWNjZXNzZnVsbHkuYFxyXG4gICAgICApO1xyXG4gICAgICByZXNvdXJjZS5wYWdlID0gbnVsbDtcclxuICAgIH0pO1xyXG5cclxuICAgIGNvbnN0IGluaXRpYWxSZXNvdXJjZXMgPSBbXTtcclxuICAgIC8vIENyZWF0ZSBhbiBpbml0aWFsIG51bWJlciBvZiByZXNvdXJjZXNcclxuICAgIGZvciAobGV0IGkgPSAwOyBpIDwgcG9vbE9wdGlvbnMubWluV29ya2VyczsgaSsrKSB7XHJcbiAgICAgIHRyeSB7XHJcbiAgICAgICAgY29uc3QgcmVzb3VyY2UgPSBhd2FpdCBwb29sLmFjcXVpcmUoKS5wcm9taXNlO1xyXG4gICAgICAgIGluaXRpYWxSZXNvdXJjZXMucHVzaChyZXNvdXJjZSk7XHJcbiAgICAgIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICAgICAgbG9nV2l0aFN0YWNrKDIsIGVycm9yLCAnW3Bvb2xdIENvdWxkIG5vdCBjcmVhdGUgYW4gaW5pdGlhbCByZXNvdXJjZS4nKTtcclxuICAgICAgfVxyXG4gICAgfVxyXG5cclxuICAgIC8vIFJlbGVhc2UgdGhlIGluaXRpYWwgbnVtYmVyIG9mIHJlc291cmNlcyBiYWNrIHRvIHRoZSBwb29sXHJcbiAgICBpbml0aWFsUmVzb3VyY2VzLmZvckVhY2goKHJlc291cmNlKSA9PiB7XHJcbiAgICAgIHBvb2wucmVsZWFzZShyZXNvdXJjZSk7XHJcbiAgICB9KTtcclxuXHJcbiAgICBsb2coXHJcbiAgICAgIDMsXHJcbiAgICAgIGBbcG9vbF0gVGhlIHBvb2wgaXMgcmVhZHkke2luaXRpYWxSZXNvdXJjZXMubGVuZ3RoID8gYCB3aXRoICR7aW5pdGlhbFJlc291cmNlcy5sZW5ndGh9IGluaXRpYWwgcmVzb3VyY2VzIHdhaXRpbmcuYCA6ICcuJ31gXHJcbiAgICApO1xyXG4gIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoXHJcbiAgICAgICdbcG9vbF0gQ291bGQgbm90IGNvbmZpZ3VyZSBhbmQgY3JlYXRlIHRoZSBwb29sIG9mIHdvcmtlcnMuJyxcclxuICAgICAgNTAwXHJcbiAgICApLnNldEVycm9yKGVycm9yKTtcclxuICB9XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBLaWxscyBhbGwgd29ya2VycyBpbiB0aGUgcG9vbCwgZGVzdHJveXMgdGhlIHBvb2wsIGFuZCBjbG9zZXMgdGhlIGJyb3dzZXJcclxuICogaW5zdGFuY2UuXHJcbiAqXHJcbiAqIEBhc3luY1xyXG4gKiBAZnVuY3Rpb24ga2lsbFBvb2xcclxuICpcclxuICogQHJldHVybnMge1Byb21pc2U8dm9pZD59IEEgUHJvbWlzZSB0aGF0IHJlc29sdmVzIGFmdGVyIHRoZSB3b3JrZXJzIGFyZVxyXG4gKiBraWxsZWQsIHRoZSBwb29sIGlzIGRlc3Ryb3llZCwgYW5kIHRoZSBicm93c2VyIGlzIGNsb3NlZC5cclxuICovXHJcbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBraWxsUG9vbCgpIHtcclxuICBsb2coMywgJ1twb29sXSBLaWxsaW5nIHBvb2wgd2l0aCBhbGwgd29ya2VycyBhbmQgY2xvc2luZyBicm93c2VyLicpO1xyXG5cclxuICAvLyBJZiBzdGlsbCBhbGl2ZSwgZGVzdHJveSB0aGUgcG9vbCBvZiBwYWdlcyBiZWZvcmUgY2xvc2luZyBhIGJyb3dzZXJcclxuICBpZiAocG9vbCkge1xyXG4gICAgLy8gRnJlZSB1cCBub3QgcmVsZWFzZWQgd29ya2Vyc1xyXG4gICAgZm9yIChjb25zdCB3b3JrZXIgb2YgcG9vbC51c2VkKSB7XHJcbiAgICAgIHBvb2wucmVsZWFzZSh3b3JrZXIucmVzb3VyY2UpO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIERlc3Ryb3kgdGhlIHBvb2wgaWYgaXQgaXMgc3RpbGwgYXZhaWxhYmxlXHJcbiAgICBpZiAoIXBvb2wuZGVzdHJveWVkKSB7XHJcbiAgICAgIGF3YWl0IHBvb2wuZGVzdHJveSgpO1xyXG4gICAgICBsb2coNCwgJ1twb29sXSBEZXN0cm95ZWQgdGhlIHBvb2wgb2YgcmVzb3VyY2VzLicpO1xyXG4gICAgfVxyXG4gICAgcG9vbCA9IG51bGw7XHJcbiAgfVxyXG5cclxuICAvLyBDbG9zZSB0aGUgYnJvd3NlciBpbnN0YW5jZVxyXG4gIGF3YWl0IGNsb3NlQnJvd3NlcigpO1xyXG59XHJcblxyXG4vKipcclxuICogUHJvY2Vzc2VzIHRoZSBleHBvcnQgd29yayB1c2luZyBhIHdvcmtlciBmcm9tIHRoZSBwb29sLiBBY3F1aXJlcyBhIHdvcmtlclxyXG4gKiBoYW5kbGUgZnJvbSB0aGUgcG9vbCwgcGVyZm9ybXMgdGhlIGV4cG9ydCB1c2luZyBwdXBwZXRlZXIsIGFuZCByZWxlYXNlc1xyXG4gKiB0aGUgd29ya2VyIGhhbmRsZSBiYWNrIHRvIHRoZSBwb29sLlxyXG4gKlxyXG4gKiBAYXN5bmNcclxuICogQGZ1bmN0aW9uIHBvc3RXb3JrXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBvcHRpb25zIC0gVGhlIGBvcHRpb25zYCBvYmplY3QgY29udGFpbmluZyBjb21wbGV0ZSBzZXRcclxuICogb2Ygb3B0aW9ucy5cclxuICpcclxuICogQHJldHVybnMge1Byb21pc2U8T2JqZWN0Pn0gQSBQcm9taXNlIHRoYXQgcmVzb2x2ZXMgdG8gdGhlIGV4cG9ydCByZXN1bHRcclxuICogYW5kIG9wdGlvbnMuXHJcbiAqXHJcbiAqIEB0aHJvd3Mge0V4cG9ydEVycm9yfSBUaHJvd3MgYW4gYEV4cG9ydEVycm9yYCBpZiBhbiBlcnJvciBvY2N1cnMgZHVyaW5nXHJcbiAqIHRoZSBleHBvcnQgcHJvY2Vzcy5cclxuICovXHJcbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBwb3N0V29yayhvcHRpb25zKSB7XHJcbiAgbGV0IHdvcmtlckhhbmRsZTtcclxuXHJcbiAgdHJ5IHtcclxuICAgIGxvZyg0LCAnW3Bvb2xdIFdvcmsgcmVjZWl2ZWQsIHN0YXJ0aW5nIHRvIHByb2Nlc3MuJyk7XHJcblxyXG4gICAgLy8gQW4gZXhwb3J0IGF0dGVtcHQgY291bnRlZFxyXG4gICAgKytwb29sU3RhdHMuZXhwb3J0c0F0dGVtcHRlZDtcclxuXHJcbiAgICAvLyBEaXNwbGF5IHRoZSBwb29sIGluZm9ybWF0aW9uIGlmIG5lZWRlZFxyXG4gICAgaWYgKGdldE9wdGlvbnMoKS5wb29sLmJlbmNobWFya2luZykge1xyXG4gICAgICBnZXRQb29sSW5mbygpO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIFRocm93IGFuIGVycm9yIGluIGNhc2Ugb2YgbGFja2luZyB0aGUgcG9vbCBpbnN0YW5jZVxyXG4gICAgaWYgKCFwb29sKSB7XHJcbiAgICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcihcclxuICAgICAgICAnW3Bvb2xdIFdvcmsgcmVjZWl2ZWQsIGJ1dCBwb29sIGhhcyBub3QgYmVlbiBzdGFydGVkLicsXHJcbiAgICAgICAgNTAwXHJcbiAgICAgICk7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gVGhlIGFjcXVpcmUgY291bnRlclxyXG4gICAgY29uc3QgYWNxdWlyZUNvdW50ZXIgPSBtZWFzdXJlVGltZSgpO1xyXG5cclxuICAgIC8vIFRyeSB0byBhY3F1aXJlIHRoZSB3b3JrZXIgYWxvbmcgd2l0aCB0aGUgaWQsIHdvcmtzIGNvdW50IGFuZCBwYWdlXHJcbiAgICB0cnkge1xyXG4gICAgICBsb2coNCwgJ1twb29sXSBBY3F1aXJpbmcgYSB3b3JrZXIgaGFuZGxlLicpO1xyXG5cclxuICAgICAgLy8gQWNxdWlyZSBhIHBvb2wgcmVzb3VyY2VcclxuICAgICAgd29ya2VySGFuZGxlID0gYXdhaXQgcG9vbC5hY3F1aXJlKCkucHJvbWlzZTtcclxuXHJcbiAgICAgIC8vIENoZWNrIHRoZSBwYWdlIGFjcXVpcmUgdGltZVxyXG4gICAgICBpZiAob3B0aW9ucy5zZXJ2ZXIuYmVuY2htYXJraW5nKSB7XHJcbiAgICAgICAgbG9nKFxyXG4gICAgICAgICAgNSxcclxuICAgICAgICAgIG9wdGlvbnMuX3JlcXVlc3RJZFxyXG4gICAgICAgICAgICA/IGBbYmVuY2htYXJrXSBSZXF1ZXN0IFske29wdGlvbnMuX3JlcXVlc3RJZH1dIC0gYFxyXG4gICAgICAgICAgICA6ICdbYmVuY2htYXJrXSAnLFxyXG4gICAgICAgICAgYEFjcXVpcmluZyBhIHdvcmtlciBoYW5kbGUgdG9vayAke2FjcXVpcmVDb3VudGVyKCl9bXMuYFxyXG4gICAgICAgICk7XHJcbiAgICAgIH1cclxuICAgIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcihcclxuICAgICAgICAnW3Bvb2xdICcgK1xyXG4gICAgICAgICAgKG9wdGlvbnMuX3JlcXVlc3RJZCA/IGBSZXF1ZXN0IFske29wdGlvbnMuX3JlcXVlc3RJZH1dIC0gYCA6ICcnKSArXHJcbiAgICAgICAgICBgRXJyb3IgZW5jb3VudGVyZWQgd2hlbiBhY3F1aXJpbmcgYW4gYXZhaWxhYmxlIGVudHJ5OiAke2FjcXVpcmVDb3VudGVyKCl9bXMuYCxcclxuICAgICAgICA0MDBcclxuICAgICAgKS5zZXRFcnJvcihlcnJvcik7XHJcbiAgICB9XHJcbiAgICBsb2coNCwgJ1twb29sXSBBY3F1aXJlZCBhIHdvcmtlciBoYW5kbGUuJyk7XHJcblxyXG4gICAgaWYgKCF3b3JrZXJIYW5kbGUucGFnZSkge1xyXG4gICAgICAvLyBTZXQgdGhlIGB3b3JrTGltaXRgIHRvIGV4Y2VlZGVkIGluIG9yZGVyIHRvIHJlY3JlYXRlIHRoZSByZXNvdXJjZVxyXG4gICAgICB3b3JrZXJIYW5kbGUud29ya0NvdW50ID0gb3B0aW9ucy5wb29sLndvcmtMaW1pdCArIDE7XHJcbiAgICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcihcclxuICAgICAgICAnW3Bvb2xdIFJlc29sdmVkIHdvcmtlciBwYWdlIGlzIGludmFsaWQ6IHRoZSBwb29sIHNldHVwIGlzIHdvbmt5LicsXHJcbiAgICAgICAgNDAwXHJcbiAgICAgICk7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gU2F2ZSB0aGUgc3RhcnQgdGltZVxyXG4gICAgY29uc3Qgd29ya1N0YXJ0ID0gZ2V0TmV3RGF0ZVRpbWUoKTtcclxuXHJcbiAgICBsb2coXHJcbiAgICAgIDQsXHJcbiAgICAgIGBbcG9vbF0gUG9vbCByZXNvdXJjZSBbJHt3b3JrZXJIYW5kbGUuaWR9XSAtIFN0YXJ0aW5nIHdvcmsgb24gdGhpcyBwb29sIGVudHJ5LmBcclxuICAgICk7XHJcblxyXG4gICAgLy8gUGVyZm9ybSBhbiBleHBvcnQgb24gYSBwdXBwZXRlZXIgbGV2ZWxcclxuICAgIGNvbnN0IGV4cG9ydENvdW50ZXIgPSBtZWFzdXJlVGltZSgpO1xyXG4gICAgY29uc3QgcmVzdWx0ID0gYXdhaXQgcHVwcGV0ZWVyRXhwb3J0KHdvcmtlckhhbmRsZS5wYWdlLCBvcHRpb25zKTtcclxuXHJcbiAgICAvLyBDaGVjayBpZiBpdCdzIGFuIGVycm9yXHJcbiAgICBpZiAocmVzdWx0IGluc3RhbmNlb2YgRXJyb3IpIHtcclxuICAgICAgLy8gTk9URTpcclxuICAgICAgLy8gSWYgdGhlcmUncyBhIHJhc3Rlcml6YXRpb24gdGltZW91dCwgd2Ugd2FudCBuZWVkIHRvIGZsdXNoIHRoZSBwYWdlLlxyXG4gICAgICAvLyBUaGlzIGlzIGJlY2F1c2UgdGhlIHBhZ2UgbWF5IGJlIGluIGEgc3RhdGUgd2hlcmUgaXQncyB3YWl0aW5nIGZvclxyXG4gICAgICAvLyB0aGUgc2NyZWVuc2hvdCB0byBmaW5pc2ggZXZlbiB0aG91Z2ggdGhlIHRpbWVvdXQgaGFzIG9jY3VyZWQuXHJcbiAgICAgIC8vIFdoaWNoIG9mIGNvdXJzZSBjYXVzZXMgYSBsb3Qgb2YgaXNzdWVzIHdpdGggdGhlIGV2ZW50IHN5c3RlbSxcclxuICAgICAgLy8gYW5kIHBhZ2UgY29uc2lzdGVuY3kuXHJcbiAgICAgIC8vXHJcbiAgICAgIC8vIE5PVEU6XHJcbiAgICAgIC8vIE9ubHkgcGFnZS5zY3JlZW5zaG90IHdpbGwgdGhyb3cgdGhpcywgdGltZW91dHMgZm9yIFBERidzIGFyZVxyXG4gICAgICAvLyBoYW5kbGVkIGJ5IHRoZSBwYWdlLnBkZiBmdW5jdGlvbiBpdHNlbGYuXHJcbiAgICAgIC8vXHJcbiAgICAgIC8vIC4uLnllcywgdGhpcyBpcyB1Z2x5LlxyXG4gICAgICBpZiAocmVzdWx0Lm1lc3NhZ2UgPT09ICdSYXN0ZXJpemF0aW9uIHRpbWVvdXQnKSB7XHJcbiAgICAgICAgLy8gU2V0IHRoZSBgd29ya0xpbWl0YCB0byBleGNlZWRlZCBpbiBvcmRlciB0byByZWNyZWF0ZSB0aGUgcmVzb3VyY2VcclxuICAgICAgICB3b3JrZXJIYW5kbGUud29ya0NvdW50ID0gb3B0aW9ucy5wb29sLndvcmtMaW1pdCArIDE7XHJcbiAgICAgICAgd29ya2VySGFuZGxlLnBhZ2UgPSBudWxsO1xyXG4gICAgICB9XHJcblxyXG4gICAgICBpZiAoXHJcbiAgICAgICAgcmVzdWx0Lm5hbWUgPT09ICdUaW1lb3V0RXJyb3InIHx8XHJcbiAgICAgICAgcmVzdWx0Lm1lc3NhZ2UgPT09ICdSYXN0ZXJpemF0aW9uIHRpbWVvdXQnXHJcbiAgICAgICkge1xyXG4gICAgICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcihcclxuICAgICAgICAgICdbcG9vbF0gJyArXHJcbiAgICAgICAgICAgIChvcHRpb25zLl9yZXF1ZXN0SWQgPyBgUmVxdWVzdCBbJHtvcHRpb25zLl9yZXF1ZXN0SWR9XSAtIGAgOiAnJykgK1xyXG4gICAgICAgICAgICAnUmFzdGVyaXphdGlvbiB0aW1lb3V0OiB5b3VyIGNoYXJ0IG1heSBiZSB0b28gY29tcGxleCBvciBsYXJnZSwgYW5kIGZhaWxlZCB0byByZW5kZXIgd2l0aGluIHRoZSBhbGxvdHRlZCB0aW1lLidcclxuICAgICAgICApLnNldEVycm9yKHJlc3VsdCk7XHJcbiAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgdGhyb3cgbmV3IEV4cG9ydEVycm9yKFxyXG4gICAgICAgICAgJ1twb29sXSAnICtcclxuICAgICAgICAgICAgKG9wdGlvbnMuX3JlcXVlc3RJZCA/IGBSZXF1ZXN0IFske29wdGlvbnMuX3JlcXVlc3RJZH1dIC0gYCA6ICcnKSArXHJcbiAgICAgICAgICAgIGBFcnJvciBlbmNvdW50ZXJlZCBkdXJpbmcgZXhwb3J0OiAke2V4cG9ydENvdW50ZXIoKX1tcy5gXHJcbiAgICAgICAgKS5zZXRFcnJvcihyZXN1bHQpO1xyXG4gICAgICB9XHJcbiAgICB9XHJcblxyXG4gICAgLy8gQ2hlY2sgdGhlIFB1cHBldGVlciBleHBvcnQgdGltZVxyXG4gICAgaWYgKG9wdGlvbnMuc2VydmVyLmJlbmNobWFya2luZykge1xyXG4gICAgICBsb2coXHJcbiAgICAgICAgNSxcclxuICAgICAgICBvcHRpb25zLl9yZXF1ZXN0SWRcclxuICAgICAgICAgID8gYFtiZW5jaG1hcmtdIFJlcXVlc3QgWyR7b3B0aW9ucy5fcmVxdWVzdElkfV0gLSBgXHJcbiAgICAgICAgICA6ICdbYmVuY2htYXJrXSAnLFxyXG4gICAgICAgIGBFeHBvcnRpbmcgYSBjaGFydCBzdWNlc3NmdWxseSB0b29rICR7ZXhwb3J0Q291bnRlcigpfW1zLmBcclxuICAgICAgKTtcclxuICAgIH1cclxuXHJcbiAgICAvLyBSZWxlYXNlIHRoZSByZXNvdXJjZSBiYWNrIHRvIHRoZSBwb29sXHJcbiAgICBwb29sLnJlbGVhc2Uod29ya2VySGFuZGxlKTtcclxuXHJcbiAgICAvLyBVc2VkIGZvciBzdGF0aXN0aWNzIGluIGF2ZXJhZ2VUaW1lIGFuZCBwcm9jZXNzZWRXb3JrQ291bnQsIHdoaWNoXHJcbiAgICAvLyBpbiB0dXJuIGlzIHVzZWQgYnkgdGhlIC9oZWFsdGggcm91dGUuXHJcbiAgICBjb25zdCB3b3JrRW5kID0gZ2V0TmV3RGF0ZVRpbWUoKTtcclxuICAgIGNvbnN0IGV4cG9ydFRpbWUgPSB3b3JrRW5kIC0gd29ya1N0YXJ0O1xyXG5cclxuICAgIHBvb2xTdGF0cy50aW1lU3BlbnQgKz0gZXhwb3J0VGltZTtcclxuICAgIHBvb2xTdGF0cy50aW1lU3BlbnRBdmVyYWdlID1cclxuICAgICAgcG9vbFN0YXRzLnRpbWVTcGVudCAvICsrcG9vbFN0YXRzLmV4cG9ydHNQZXJmb3JtZWQ7XHJcblxyXG4gICAgbG9nKDQsIGBbcG9vbF0gV29yayBjb21wbGV0ZWQgaW4gJHtleHBvcnRUaW1lfW1zLmApO1xyXG5cclxuICAgIC8vIE90aGVyd2lzZSByZXR1cm4gdGhlIHJlc3VsdFxyXG4gICAgcmV0dXJuIHtcclxuICAgICAgcmVzdWx0LFxyXG4gICAgICBvcHRpb25zXHJcbiAgICB9O1xyXG4gIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICArK3Bvb2xTdGF0cy5leHBvcnRzRHJvcHBlZDtcclxuXHJcbiAgICBpZiAod29ya2VySGFuZGxlKSB7XHJcbiAgICAgIHBvb2wucmVsZWFzZSh3b3JrZXJIYW5kbGUpO1xyXG4gICAgfVxyXG5cclxuICAgIHRocm93IGVycm9yO1xyXG4gIH1cclxufVxyXG5cclxuLyoqXHJcbiAqIFJldHJpZXZlcyB0aGUgY3VycmVudCBwb29sIGluc3RhbmNlLlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gZ2V0UG9vbFxyXG4gKlxyXG4gKiBAcmV0dXJucyB7KE9iamVjdHxudWxsKX0gVGhlIGN1cnJlbnQgcG9vbCBpbnN0YW5jZSBpZiBpbml0aWFsaXplZCwgb3IgbnVsbFxyXG4gKiBpZiB0aGUgcG9vbCBoYXMgbm90IGJlZW4gY3JlYXRlZC5cclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiBnZXRQb29sKCkge1xyXG4gIHJldHVybiBwb29sO1xyXG59XHJcblxyXG4vKipcclxuICogR2V0cyB0aGUgc3RhdGlzdGljIG9mIGEgcG9vbCBpbnN0YWNlIGFib3V0IGV4cG9ydHMuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBnZXRQb29sU3RhdHNcclxuICpcclxuICogQHJldHVybnMge09iamVjdH0gVGhlIGN1cnJlbnQgcG9vbCBzdGF0aXN0aWNzLlxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIGdldFBvb2xTdGF0cygpIHtcclxuICByZXR1cm4gcG9vbFN0YXRzO1xyXG59XHJcblxyXG4vKipcclxuICogUmV0cmlldmVzIHBvb2wgaW5mb3JtYXRpb24gaW4gSlNPTiBmb3JtYXQsIGluY2x1ZGluZyBtaW5pbXVtIGFuZCBtYXhpbXVtXHJcbiAqIHdvcmtlcnMsIGF2YWlsYWJsZSB3b3JrZXJzLCB3b3JrZXJzIGluIHVzZSwgYW5kIHBlbmRpbmcgYWNxdWlyZSByZXF1ZXN0cy5cclxuICpcclxuICogQGZ1bmN0aW9uIGdldFBvb2xJbmZvSlNPTlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7T2JqZWN0fSBQb29sIGluZm9ybWF0aW9uIGluIEpTT04gZm9ybWF0LlxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIGdldFBvb2xJbmZvSlNPTigpIHtcclxuICByZXR1cm4ge1xyXG4gICAgbWluOiBwb29sLm1pbixcclxuICAgIG1heDogcG9vbC5tYXgsXHJcbiAgICB1c2VkOiBwb29sLm51bVVzZWQoKSxcclxuICAgIGF2YWlsYWJsZTogcG9vbC5udW1GcmVlKCksXHJcbiAgICBhbGxDcmVhdGVkOiBwb29sLm51bVVzZWQoKSArIHBvb2wubnVtRnJlZSgpLFxyXG4gICAgcGVuZGluZ0FjcXVpcmVzOiBwb29sLm51bVBlbmRpbmdBY3F1aXJlcygpLFxyXG4gICAgcGVuZGluZ0NyZWF0ZXM6IHBvb2wubnVtUGVuZGluZ0NyZWF0ZXMoKSxcclxuICAgIHBlbmRpbmdWYWxpZGF0aW9uczogcG9vbC5udW1QZW5kaW5nVmFsaWRhdGlvbnMoKSxcclxuICAgIHBlbmRpbmdEZXN0cm95czogcG9vbC5wZW5kaW5nRGVzdHJveXMubGVuZ3RoLFxyXG4gICAgYWJzb2x1dGVBbGw6XHJcbiAgICAgIHBvb2wubnVtVXNlZCgpICtcclxuICAgICAgcG9vbC5udW1GcmVlKCkgK1xyXG4gICAgICBwb29sLm51bVBlbmRpbmdBY3F1aXJlcygpICtcclxuICAgICAgcG9vbC5udW1QZW5kaW5nQ3JlYXRlcygpICtcclxuICAgICAgcG9vbC5udW1QZW5kaW5nVmFsaWRhdGlvbnMoKSArXHJcbiAgICAgIHBvb2wucGVuZGluZ0Rlc3Ryb3lzLmxlbmd0aFxyXG4gIH07XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBMb2dzIGluZm9ybWF0aW9uIGFib3V0IHRoZSBjdXJyZW50IHN0YXRlIG9mIHRoZSBwb29sLCBpbmNsdWRpbmcgdGhlIG1pbmltdW1cclxuICogYW5kIG1heGltdW0gd29ya2VycywgYXZhaWxhYmxlIHdvcmtlcnMsIHdvcmtlcnMgaW4gdXNlLCBhbmQgcGVuZGluZyBhY3F1aXJlXHJcbiAqIHJlcXVlc3RzLlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gZ2V0UG9vbEluZm9cclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiBnZXRQb29sSW5mbygpIHtcclxuICBjb25zdCB7XHJcbiAgICBtaW4sXHJcbiAgICBtYXgsXHJcbiAgICB1c2VkLFxyXG4gICAgYXZhaWxhYmxlLFxyXG4gICAgYWxsQ3JlYXRlZCxcclxuICAgIHBlbmRpbmdBY3F1aXJlcyxcclxuICAgIHBlbmRpbmdDcmVhdGVzLFxyXG4gICAgcGVuZGluZ1ZhbGlkYXRpb25zLFxyXG4gICAgcGVuZGluZ0Rlc3Ryb3lzLFxyXG4gICAgYWJzb2x1dGVBbGxcclxuICB9ID0gZ2V0UG9vbEluZm9KU09OKCk7XHJcblxyXG4gIGxvZyg1LCBgW3Bvb2xdIFRoZSBtaW5pbXVtIG51bWJlciBvZiByZXNvdXJjZXMgYWxsb3dlZCBieSBwb29sOiAke21pbn0uYCk7XHJcbiAgbG9nKDUsIGBbcG9vbF0gVGhlIG1heGltdW0gbnVtYmVyIG9mIHJlc291cmNlcyBhbGxvd2VkIGJ5IHBvb2w6ICR7bWF4fS5gKTtcclxuICBsb2coNSwgYFtwb29sXSBUaGUgbnVtYmVyIG9mIHVzZWQgcmVzb3VyY2VzOiAke3VzZWR9LmApO1xyXG4gIGxvZyg1LCBgW3Bvb2xdIFRoZSBudW1iZXIgb2YgZnJlZSByZXNvdXJjZXM6ICR7YXZhaWxhYmxlfS5gKTtcclxuICBsb2coXHJcbiAgICA1LFxyXG4gICAgYFtwb29sXSBUaGUgbnVtYmVyIG9mIGFsbCBjcmVhdGVkICh1c2VkIGFuZCBmcmVlKSByZXNvdXJjZXM6ICR7YWxsQ3JlYXRlZH0uYFxyXG4gICk7XHJcbiAgbG9nKFxyXG4gICAgNSxcclxuICAgIGBbcG9vbF0gVGhlIG51bWJlciBvZiByZXNvdXJjZXMgd2FpdGluZyB0byBiZSBhY3F1aXJlZDogJHtwZW5kaW5nQWNxdWlyZXN9LmBcclxuICApO1xyXG4gIGxvZyhcclxuICAgIDUsXHJcbiAgICBgW3Bvb2xdIFRoZSBudW1iZXIgb2YgcmVzb3VyY2VzIHdhaXRpbmcgdG8gYmUgY3JlYXRlZDogJHtwZW5kaW5nQ3JlYXRlc30uYFxyXG4gICk7XHJcbiAgbG9nKFxyXG4gICAgNSxcclxuICAgIGBbcG9vbF0gVGhlIG51bWJlciBvZiByZXNvdXJjZXMgd2FpdGluZyB0byBiZSB2YWxpZGF0ZWQ6ICR7cGVuZGluZ1ZhbGlkYXRpb25zfS5gXHJcbiAgKTtcclxuICBsb2coXHJcbiAgICA1LFxyXG4gICAgYFtwb29sXSBUaGUgbnVtYmVyIG9mIHJlc291cmNlcyB3YWl0aW5nIHRvIGJlIGRlc3Ryb3llZDogJHtwZW5kaW5nRGVzdHJveXN9LmBcclxuICApO1xyXG4gIGxvZyg1LCBgW3Bvb2xdIFRoZSBudW1iZXIgb2YgYWxsIHJlc291cmNlczogJHthYnNvbHV0ZUFsbH0uYCk7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBGYWN0b3J5IGZ1bmN0aW9uIHRoYXQgcmV0dXJucyBhbiBvYmplY3Qgd2l0aCBgY3JlYXRlYCwgYHZhbGlkYXRlYCxcclxuICogYW5kIGBkZXN0cm95YCBmdW5jdGlvbnMgZm9yIHRoZSBwb29sIGluc3RhbmNlLlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gX2ZhY3RvcnlcclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IHBvb2xPcHRpb25zIC0gT2JqZWN0IGNvbnRhaW5pbmcgYHBvb2xgIG9wdGlvbnMuXHJcbiAqL1xyXG5mdW5jdGlvbiBfZmFjdG9yeShwb29sT3B0aW9ucykge1xyXG4gIHJldHVybiB7XHJcbiAgICAvKipcclxuICAgICAqIENyZWF0ZXMgYSBuZXcgd29ya2VyIHBhZ2UgZm9yIHRoZSBleHBvcnQgcG9vbC5cclxuICAgICAqXHJcbiAgICAgKiBAYXN5bmNcclxuICAgICAqIEBmdW5jdGlvbiBjcmVhdGVcclxuICAgICAqXHJcbiAgICAgKiBAcmV0dXJucyB7UHJvbWlzZTxPYmplY3Q+fSBBIFByb21pc2UgdGhhdCByZXNvbHZlcyB0byBhbiBvYmplY3RcclxuICAgICAqIGNvbnRhaW5pbmcgdGhlIHdvcmtlciBJRCwgYSByZWZlcmVuY2UgdG8gdGhlIGJyb3dzZXIgcGFnZSwgYW5kIGluaXRpYWxcclxuICAgICAqIHdvcmsgY291bnQuXHJcbiAgICAgKlxyXG4gICAgICogQHRocm93cyB7RXhwb3J0RXJyb3J9IFRocm93cyBhbiBgRXhwb3J0RXJyb3JgIGlmIHRoZXJlIGlzIGFuIGVycm9yIGR1cmluZ1xyXG4gICAgICogdGhlIGNyZWF0aW9uIG9mIHRoZSBuZXcgcGFnZS5cclxuICAgICAqL1xyXG4gICAgY3JlYXRlOiBhc3luYyAoKSA9PiB7XHJcbiAgICAgIC8vIEluaXQgdGhlIHJlc291cmNlIHdpdGggdW5pcXVlIGlkIGFuZCB3b3JrIGNvdW50XHJcbiAgICAgIGNvbnN0IHBvb2xSZXNvdXJjZSA9IHtcclxuICAgICAgICBpZDogdXVpZCgpLFxyXG4gICAgICAgIC8vIFRyeSB0byBkaXN0cmlidXRlIHRoZSBpbml0aWFsIHdvcmsgY291bnRcclxuICAgICAgICB3b3JrQ291bnQ6IE1hdGgucm91bmQoTWF0aC5yYW5kb20oKSAqIChwb29sT3B0aW9ucy53b3JrTGltaXQgLyAyKSlcclxuICAgICAgfTtcclxuXHJcbiAgICAgIHRyeSB7XHJcbiAgICAgICAgLy8gU3RhcnQgbWVhc3VyaW5nIGEgcGFnZSBjcmVhdGlvbiB0aW1lXHJcbiAgICAgICAgY29uc3Qgc3RhcnREYXRlID0gZ2V0TmV3RGF0ZVRpbWUoKTtcclxuXHJcbiAgICAgICAgLy8gQ3JlYXRlIGEgbmV3IHBhZ2VcclxuICAgICAgICBhd2FpdCBuZXdQYWdlKHBvb2xSZXNvdXJjZSk7XHJcblxyXG4gICAgICAgIC8vIE1lYXN1cmUgdGhlIHRpbWUgb2YgZnVsbCBjcmVhdGlvbiBhbmQgY29uZmlndXJhdGlvbiBvZiBhIHBhZ2VcclxuICAgICAgICBsb2coXHJcbiAgICAgICAgICAzLFxyXG4gICAgICAgICAgYFtwb29sXSBQb29sIHJlc291cmNlIFske3Bvb2xSZXNvdXJjZS5pZH1dIC0gU3VjY2Vzc2Z1bGx5IGNyZWF0ZWQgYSB3b3JrZXIsIHRvb2sgJHtcclxuICAgICAgICAgICAgZ2V0TmV3RGF0ZVRpbWUoKSAtIHN0YXJ0RGF0ZVxyXG4gICAgICAgICAgfW1zLmBcclxuICAgICAgICApO1xyXG5cclxuICAgICAgICAvLyBSZXR1cm4gcmVhZHkgcG9vbCByZXNvdXJjZVxyXG4gICAgICAgIHJldHVybiBwb29sUmVzb3VyY2U7XHJcbiAgICAgIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICAgICAgbG9nKFxyXG4gICAgICAgICAgMyxcclxuICAgICAgICAgIGBbcG9vbF0gUG9vbCByZXNvdXJjZSBbJHtwb29sUmVzb3VyY2UuaWR9XSAtIEVycm9yIGVuY291bnRlcmVkIHdoZW4gY3JlYXRpbmcgYSBuZXcgcGFnZS5gXHJcbiAgICAgICAgKTtcclxuICAgICAgICB0aHJvdyBlcnJvcjtcclxuICAgICAgfVxyXG4gICAgfSxcclxuXHJcbiAgICAvKipcclxuICAgICAqIFZhbGlkYXRlcyBhIHdvcmtlciBwYWdlIGluIHRoZSBleHBvcnQgcG9vbCwgY2hlY2tpbmcgaWYgaXQgaGFzIGV4Y2VlZGVkXHJcbiAgICAgKiB0aGUgd29yayBsaW1pdC5cclxuICAgICAqXHJcbiAgICAgKiBAYXN5bmNcclxuICAgICAqIEBmdW5jdGlvbiB2YWxpZGF0ZVxyXG4gICAgICpcclxuICAgICAqIEBwYXJhbSB7T2JqZWN0fSBwb29sUmVzb3VyY2UgLSBUaGUgaGFuZGxlIHRvIHRoZSB3b3JrZXIsIGNvbnRhaW5pbmdcclxuICAgICAqIHRoZSB3b3JrZXIncyBJRCwgYSByZWZlcmVuY2UgdG8gdGhlIGJyb3dzZXIgcGFnZSwgYW5kIHdvcmsgY291bnQuXHJcbiAgICAgKlxyXG4gICAgICogQHJldHVybnMge1Byb21pc2U8Ym9vbGVhbj59IEEgUHJvbWlzZSB0aGF0IHJlc29sdmVzIHRvIHRydWUgaWYgdGhlIHdvcmtlclxyXG4gICAgICogaXMgdmFsaWQgYW5kIHdpdGhpbiB0aGUgd29yayBsaW1pdDsgb3RoZXJ3aXNlLCB0byBmYWxzZS5cclxuICAgICAqL1xyXG4gICAgdmFsaWRhdGU6IGFzeW5jIChwb29sUmVzb3VyY2UpID0+IHtcclxuICAgICAgLy8gTk9URTpcclxuICAgICAgLy8gSW4gY2VydGFpbiBjYXNlcyBhY3F1aXJpbmcgdGhyb3dzIGEgVGFyZ2V0Q2xvc2VFcnJvciwgd2hpY2ggbWF5XHJcbiAgICAgIC8vIGJlIGNhdXNlZCBieSB0d28gdGhpbmdzOlxyXG4gICAgICAvLyAtIFRoZSBwYWdlIGlzIGNsb3NlZCBhbmQgYXR0ZW1wdGVkIHRvIGJlIHJldXNlZC5cclxuICAgICAgLy8gLSBMb3N0IGNvbnRhY3Qgd2l0aCB0aGUgYnJvd3Nlci5cclxuICAgICAgLy9cclxuICAgICAgLy8gV2hhdCB3ZSdyZSBzZWVpbmcgaW4gbG9ncyBpcyB0aGF0IHN1Y2Nlc3NpdmUgZXhwb3J0cyB0eXBpY2FsbHlcclxuICAgICAgLy8gc3VjY2VlZHMsIGFuZCB0aGUgc2VydmVyIHJlY292ZXJzLCBpbmRpY2F0aW5nIHRoYXQgaXQncyBsaWtlbHlcclxuICAgICAgLy8gdGhlIGZpcnN0IGNhc2UuIFRoaXMgaXMgYW4gYXR0ZW1wdCBhdCBhbGxpZXZhdGluZyB0aGUgaXNzdWUgYnlcclxuICAgICAgLy8gc2ltcGx5IG5vdCB2YWxpZGF0aW5nIHRoZSB3b3JrZXIgaWYgdGhlIHBhZ2UgaXMgbnVsbCBvciBjbG9zZWQuXHJcbiAgICAgIC8vXHJcbiAgICAgIC8vIFRoZSBhY3R1YWwgcmVzdWx0IGZyb20gd2hlbiB0aGlzIGhhcHBlbmVkLCB3YXMgdGhhdCBhIHdvcmtlciB3b3VsZFxyXG4gICAgICAvLyBiZSBjb21wbGV0ZWx5IGxvY2tlZCwgc3RvcHBpbmcgaXQgZnJvbSBiZWluZyBhY3F1aXJlZCB1bnRpbFxyXG4gICAgICAvLyBpdHMgd29yayBjb3VudCByZWFjaGVkIHRoZSBsaW1pdC5cclxuXHJcbiAgICAgIC8vIENoZWNrIGlmIHRoZSBgcGFnZWAgaXMgdmFsaWRcclxuICAgICAgaWYgKCFwb29sUmVzb3VyY2UucGFnZSkge1xyXG4gICAgICAgIGxvZyhcclxuICAgICAgICAgIDMsXHJcbiAgICAgICAgICBgW3Bvb2xdIFBvb2wgcmVzb3VyY2UgWyR7cG9vbFJlc291cmNlLmlkfV0gLSBWYWxpZGF0aW9uIGZhaWxlZCAobm8gdmFsaWQgcGFnZSBpcyBmb3VuZCkuYFxyXG4gICAgICAgICk7XHJcbiAgICAgICAgcmV0dXJuIGZhbHNlO1xyXG4gICAgICB9XHJcblxyXG4gICAgICAvLyBDaGVjayBpZiB0aGUgYHBhZ2VgIGlzIGNsb3NlZFxyXG4gICAgICBpZiAocG9vbFJlc291cmNlLnBhZ2UuaXNDbG9zZWQoKSkge1xyXG4gICAgICAgIGxvZyhcclxuICAgICAgICAgIDMsXHJcbiAgICAgICAgICBgW3Bvb2xdIFBvb2wgcmVzb3VyY2UgWyR7cG9vbFJlc291cmNlLmlkfV0gLSBWYWxpZGF0aW9uIGZhaWxlZCAocGFnZSBpcyBjbG9zZWQgb3IgaW52YWxpZCkuYFxyXG4gICAgICAgICk7XHJcbiAgICAgICAgcmV0dXJuIGZhbHNlO1xyXG4gICAgICB9XHJcblxyXG4gICAgICAvLyBDaGVjayBpZiB0aGUgYG1haW5GcmFtZWAgaXMgZGV0YWNoZWRcclxuICAgICAgaWYgKHBvb2xSZXNvdXJjZS5wYWdlLm1haW5GcmFtZSgpLmRldGFjaGVkKSB7XHJcbiAgICAgICAgbG9nKFxyXG4gICAgICAgICAgMyxcclxuICAgICAgICAgIGBbcG9vbF0gUG9vbCByZXNvdXJjZSBbJHtwb29sUmVzb3VyY2UuaWR9XSAtIFZhbGlkYXRpb24gZmFpbGVkIChwYWdlJ3MgZnJhbWUgaXMgZGV0YWNoZWQpLmBcclxuICAgICAgICApO1xyXG4gICAgICAgIHJldHVybiBmYWxzZTtcclxuICAgICAgfVxyXG5cclxuICAgICAgLy8gQ2hlY2sgaWYgdGhlIGB3b3JrTGltaXRgIGlzIGV4Y2VlZGVkXHJcbiAgICAgIGlmIChcclxuICAgICAgICBwb29sT3B0aW9ucy53b3JrTGltaXQgJiZcclxuICAgICAgICArK3Bvb2xSZXNvdXJjZS53b3JrQ291bnQgPiBwb29sT3B0aW9ucy53b3JrTGltaXRcclxuICAgICAgKSB7XHJcbiAgICAgICAgbG9nKFxyXG4gICAgICAgICAgMyxcclxuICAgICAgICAgIGBbcG9vbF0gUG9vbCByZXNvdXJjZSBbJHtwb29sUmVzb3VyY2UuaWR9XSAtIFZhbGlkYXRpb24gZmFpbGVkIChleGNlZWRlZCB0aGUgJHtwb29sT3B0aW9ucy53b3JrTGltaXR9IHdvcmtzIHBlciByZXNvdXJjZSBsaW1pdCkuYFxyXG4gICAgICAgICk7XHJcbiAgICAgICAgcmV0dXJuIGZhbHNlO1xyXG4gICAgICB9XHJcblxyXG4gICAgICAvLyBUaGUgYHBvb2xSZXNvdXJjZWAgaXMgdmFsaWRhdGVkXHJcbiAgICAgIHJldHVybiB0cnVlO1xyXG4gICAgfSxcclxuXHJcbiAgICAvKipcclxuICAgICAqIERlc3Ryb3lzIGEgd29ya2VyIGVudHJ5IGluIHRoZSBleHBvcnQgcG9vbCwgY2xvc2luZyBpdHMgYXNzb2NpYXRlZCBwYWdlLlxyXG4gICAgICpcclxuICAgICAqIEBhc3luY1xyXG4gICAgICogQGZ1bmN0aW9uIGRlc3Ryb3lcclxuICAgICAqXHJcbiAgICAgKiBAcGFyYW0ge09iamVjdH0gcG9vbFJlc291cmNlIC0gVGhlIGhhbmRsZSB0byB0aGUgd29ya2VyLCBjb250YWluaW5nXHJcbiAgICAgKiB0aGUgd29ya2VyJ3MgSUQsIGEgcmVmZXJlbmNlIHRvIHRoZSBicm93c2VyIHBhZ2UsIGFuZCB3b3JrIGNvdW50LlxyXG4gICAgICovXHJcbiAgICBkZXN0cm95OiBhc3luYyAocG9vbFJlc291cmNlKSA9PiB7XHJcbiAgICAgIGxvZyhcclxuICAgICAgICAzLFxyXG4gICAgICAgIGBbcG9vbF0gUG9vbCByZXNvdXJjZSBbJHtwb29sUmVzb3VyY2UuaWR9XSAtIERlc3Ryb3lpbmcgYSB3b3JrZXIuYFxyXG4gICAgICApO1xyXG5cclxuICAgICAgaWYgKHBvb2xSZXNvdXJjZS5wYWdlICYmICFwb29sUmVzb3VyY2UucGFnZS5pc0Nsb3NlZCgpKSB7XHJcbiAgICAgICAgdHJ5IHtcclxuICAgICAgICAgIC8vIFJlbW92ZSBhbGwgYXR0YWNoZWQgZXZlbnQgbGlzdGVuZXJzIGZyb20gdGhlIHJlc291cmNlXHJcbiAgICAgICAgICBwb29sUmVzb3VyY2UucGFnZS5yZW1vdmVBbGxMaXN0ZW5lcnMoJ3BhZ2VlcnJvcicpO1xyXG4gICAgICAgICAgcG9vbFJlc291cmNlLnBhZ2UucmVtb3ZlQWxsTGlzdGVuZXJzKCdjb25zb2xlJyk7XHJcbiAgICAgICAgICBwb29sUmVzb3VyY2UucGFnZS5yZW1vdmVBbGxMaXN0ZW5lcnMoJ2ZyYW1lZGV0YWNoZWQnKTtcclxuXHJcbiAgICAgICAgICAvLyBXZSBuZWVkIHRvIHdhaXQgYXJvdW5kIGZvciB0aGlzXHJcbiAgICAgICAgICBhd2FpdCBwb29sUmVzb3VyY2UucGFnZS5jbG9zZSgpO1xyXG4gICAgICAgIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICAgICAgICBsb2coXHJcbiAgICAgICAgICAgIDMsXHJcbiAgICAgICAgICAgIGBbcG9vbF0gUG9vbCByZXNvdXJjZSBbJHtwb29sUmVzb3VyY2UuaWR9XSAtIFBhZ2UgY291bGQgbm90IGJlIGNsb3NlZCB1cG9uIGRlc3Ryb3lpbmcuYFxyXG4gICAgICAgICAgKTtcclxuICAgICAgICAgIHRocm93IGVycm9yO1xyXG4gICAgICAgIH1cclxuICAgICAgfVxyXG4gICAgfVxyXG4gIH07XHJcbn1cclxuXHJcbmV4cG9ydCBkZWZhdWx0IHtcclxuICBpbml0UG9vbCxcclxuICBraWxsUG9vbCxcclxuICBwb3N0V29yayxcclxuICBnZXRQb29sLFxyXG4gIGdldFBvb2xTdGF0cyxcclxuICBnZXRQb29sSW5mbyxcclxuICBnZXRQb29sSW5mb0pTT05cclxufTtcclxuIiwiLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcclxuXHJcbkhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlclxyXG5cclxuQ29weXJpZ2h0IChjKSAyMDE2LTIwMjUsIEhpZ2hzb2Z0XHJcblxyXG5MaWNlbmNlZCB1bmRlciB0aGUgTUlUIGxpY2VuY2UuXHJcblxyXG5BZGRpdGlvbmFsbHkgYSB2YWxpZCBIaWdoY2hhcnRzIGxpY2Vuc2UgaXMgcmVxdWlyZWQgZm9yIHVzZS5cclxuXHJcblNlZSBMSUNFTlNFIGZpbGUgaW4gcm9vdCBmb3IgZGV0YWlscy5cclxuXHJcbioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXHJcblxyXG4vKipcclxuICogQG92ZXJ2aWV3IFVzZWQgdG8gc2FuaXRpemUgdGhlIHN0cmluZ3MgY29taW5nIGZyb20gdGhlIGV4cG9ydGluZyBtb2R1bGVcclxuICogdG8gcHJldmVudCBYU1MgYXR0YWNrcyAod2l0aCB0aGUgRE9NUHVyaWZ5IGxpYnJhcnkpLlxyXG4gKi9cclxuXHJcbmltcG9ydCBET01QdXJpZnkgZnJvbSAnZG9tcHVyaWZ5JztcclxuaW1wb3J0IHsgSlNET00gfSBmcm9tICdqc2RvbSc7XHJcblxyXG4vKipcclxuICogU2FuaXRpemVzIGEgZ2l2ZW4gSFRNTCBzdHJpbmcgYnkgcmVtb3ZpbmcgPHNjcmlwdD4gdGFncy4gVGhpcyBmdW5jdGlvbiB1c2VzXHJcbiAqIGEgcmVndWxhciBleHByZXNzaW9uIHRvIGZpbmQgYW5kIHJlbW92ZSBhbGwgb2NjdXJyZW5jZXMgb2YgPHNjcmlwdD48L3NjcmlwdD5cclxuICogdGFncyBhbmQgYW55IGNvbnRlbnQgd2l0aGluIHRoZW0uXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBzYW5pdGl6ZVxyXG4gKlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gaW5wdXQgLSBUaGUgSFRNTCBzdHJpbmcgdG8gYmUgc2FuaXRpemVkLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7c3RyaW5nfSBUaGUgc2FuaXRpemVkIEhUTUwgc3RyaW5nLlxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIHNhbml0aXplKGlucHV0KSB7XHJcbiAgLy8gR2V0IHRoZSB2aXJ0dWFsIERPTVxyXG4gIGNvbnN0IHdpbmRvdyA9IG5ldyBKU0RPTSgnJykud2luZG93O1xyXG5cclxuICAvLyBDcmVhdGUgYSBwdXJpZnlpbmcgaW5zdGFuY2VcclxuICBjb25zdCBwdXJpZnkgPSBET01QdXJpZnkod2luZG93KTtcclxuXHJcbiAgLy8gUmV0dXJuIHNhbml0aXplZCBpbnB1dFxyXG4gIHJldHVybiBwdXJpZnkuc2FuaXRpemUoaW5wdXQsIHsgQUREX1RBR1M6IFsnZm9yZWlnbk9iamVjdCddIH0pO1xyXG59XHJcblxyXG5leHBvcnQgZGVmYXVsdCB7XHJcbiAgc2FuaXRpemVcclxufTtcclxuIiwiLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcclxuXHJcbkhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlclxyXG5cclxuQ29weXJpZ2h0IChjKSAyMDE2LTIwMjUsIEhpZ2hzb2Z0XHJcblxyXG5MaWNlbmNlZCB1bmRlciB0aGUgTUlUIGxpY2VuY2UuXHJcblxyXG5BZGRpdGlvbmFsbHkgYSB2YWxpZCBIaWdoY2hhcnRzIGxpY2Vuc2UgaXMgcmVxdWlyZWQgZm9yIHVzZS5cclxuXHJcblNlZSBMSUNFTlNFIGZpbGUgaW4gcm9vdCBmb3IgZGV0YWlscy5cclxuXHJcbioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXHJcblxyXG4vKipcclxuICogQG92ZXJ2aWV3IFRoaXMgbW9kdWxlIHByb3ZpZGVzIGZ1bmN0aW9ucyB0byBwcmVwYXJlIGZvciB0aGUgZXhwb3J0aW5nIGNoYXJ0c1xyXG4gKiBpbnRvIHZhcmlvdXMgaW1hZ2Ugb3V0cHV0IGZvcm1hdHMgc3VjaCBhcyBKUEVHLCBQTkcsIFBERiwgYW5kIFNWR3MuXHJcbiAqIEl0IHN1cHBvcnRzIHNpbmdsZSBhbmQgYmF0Y2ggZXhwb3J0IG9wZXJhdGlvbnMgYW5kIGFsbG93cyBjdXN0b21pemF0aW9uXHJcbiAqIHRocm91Z2ggb3B0aW9ucyBwYXNzZWQgZnJvbSBjb25maWd1cmF0aW9ucyBvciBBUElzLlxyXG4gKi9cclxuXHJcbmltcG9ydCB7IHJlYWRGaWxlU3luYywgd3JpdGVGaWxlU3luYyB9IGZyb20gJ2ZzJztcclxuXHJcbmltcG9ydCB7IGdldE9wdGlvbnMsIG1lcmdlT3B0aW9ucywgaXNBbGxvd2VkQ29uZmlnIH0gZnJvbSAnLi9jb25maWcuanMnO1xyXG5pbXBvcnQgeyBsb2csIGxvZ1dpdGhTdGFjayB9IGZyb20gJy4vbG9nZ2VyLmpzJztcclxuaW1wb3J0IHsga2lsbFBvb2wsIHBvc3RXb3JrLCBnZXRQb29sU3RhdHMgfSBmcm9tICcuL3Bvb2wuanMnO1xyXG5pbXBvcnQgeyBzYW5pdGl6ZSB9IGZyb20gJy4vc2FuaXRpemUuanMnO1xyXG5pbXBvcnQge1xyXG4gIGZpeE91dGZpbGUsXHJcbiAgZml4VHlwZSxcclxuICBnZXRBYnNvbHV0ZVBhdGgsXHJcbiAgZ2V0QmFzZTY0LFxyXG4gIHJvdW5kTnVtYmVyLFxyXG4gIHdyYXBBcm91bmRcclxufSBmcm9tICcuL3V0aWxzLmpzJztcclxuXHJcbmltcG9ydCBFeHBvcnRFcnJvciBmcm9tICcuL2Vycm9ycy9FeHBvcnRFcnJvci5qcyc7XHJcblxyXG4vLyBUaGUgZ2xvYmFsIGZsYWcgZm9yIHRoZSBjb2RlIGV4ZWN1dGlvbiBwZXJtaXNzaW9uXHJcbmxldCBhbGxvd0NvZGVFeGVjdXRpb24gPSBmYWxzZTtcclxuXHJcbi8qKlxyXG4gKiBTdGFydHMgYSBzaW5nbGUgZXhwb3J0IHByb2Nlc3MgYmFzZWQgb24gdGhlIHNwZWNpZmllZCBvcHRpb25zIGFuZCBzYXZlc1xyXG4gKiB0aGUgaW1hZ2UgaW4gdGhlIHByb3ZpZGVkIG91dGZpbGUuXHJcbiAqXHJcbiAqIEBhc3luY1xyXG4gKiBAZnVuY3Rpb24gc2luZ2xlRXhwb3J0XHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBvcHRpb25zIC0gVGhlIGBvcHRpb25zYCBvYmplY3QsIHdoaWNoIG1heSBiZSBhIHBhcnRpYWxcclxuICogb3IgY29tcGxldGUgc2V0IG9mIG9wdGlvbnMuIEl0IG11c3QgY29udGFpbiBhdCBsZWFzdCBvbmUgb2YgdGhlIGZvbGxvd2luZ1xyXG4gKiBwcm9wZXJ0aWVzOiBgaW5maWxlYCwgYGluc3RyYCwgYG9wdGlvbnNgLCBvciBgc3ZnYCB0byBnZW5lcmF0ZSBhIHZhbGlkIGltYWdlLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7UHJvbWlzZTx2b2lkPn0gQSBQcm9taXNlIHRoYXQgcmVzb2x2ZXMgb25jZSB0aGUgc2luZ2xlIGV4cG9ydFxyXG4gKiBwcm9jZXNzIGlzIGNvbXBsZXRlZC5cclxuICpcclxuICogQHRocm93cyB7RXhwb3J0RXJyb3J9IFRocm93cyBhbiBgRXhwb3J0RXJyb3JgIGlmIGFuIGVycm9yIG9jY3VycyBkdXJpbmdcclxuICogdGhlIHNpbmdsZSBleHBvcnQgcHJvY2Vzcy5cclxuICovXHJcbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBzaW5nbGVFeHBvcnQob3B0aW9ucykge1xyXG4gIC8vIENoZWNrIGlmIHRoZSBleHBvcnQgbWFrZXMgc2Vuc2VcclxuICBpZiAob3B0aW9ucyAmJiBvcHRpb25zLmV4cG9ydCkge1xyXG4gICAgLy8gUGVyZm9ybSBhbiBleHBvcnRcclxuICAgIGF3YWl0IHN0YXJ0RXhwb3J0KG9wdGlvbnMsIGFzeW5jIChlcnJvciwgZGF0YSkgPT4ge1xyXG4gICAgICAvLyBFeGl0IHByb2Nlc3Mgd2hlbiBlcnJvciBleGlzdHNcclxuICAgICAgaWYgKGVycm9yKSB7XHJcbiAgICAgICAgdGhyb3cgZXJyb3I7XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIC8vIEdldCB0aGUgYGI2NGAsIGBvdXRmaWxlYCwgYW5kIGB0eXBlYCBmb3IgYSBjaGFydFxyXG4gICAgICBjb25zdCB7IGI2NCwgb3V0ZmlsZSwgdHlwZSB9ID0gZGF0YS5vcHRpb25zLmV4cG9ydDtcclxuXHJcbiAgICAgIC8vIFNhdmUgdGhlIHJlc3VsdFxyXG4gICAgICB0cnkge1xyXG4gICAgICAgIGlmIChiNjQpIHtcclxuICAgICAgICAgIC8vIEFzIGEgQmFzZTY0IHN0cmluZyB0byBhIHR4dCBmaWxlXHJcbiAgICAgICAgICB3cml0ZUZpbGVTeW5jKFxyXG4gICAgICAgICAgICBgJHtvdXRmaWxlLnNwbGl0KCcuJykuc2hpZnQoKSB8fCAnY2hhcnQnfS50eHRgLFxyXG4gICAgICAgICAgICBnZXRCYXNlNjQoZGF0YS5yZXN1bHQsIHR5cGUpXHJcbiAgICAgICAgICApO1xyXG4gICAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgICAvLyBBcyBhIGNvcnJlY3QgaW1hZ2UgZm9ybWF0XHJcbiAgICAgICAgICB3cml0ZUZpbGVTeW5jKFxyXG4gICAgICAgICAgICBvdXRmaWxlIHx8IGBjaGFydC4ke3R5cGV9YCxcclxuICAgICAgICAgICAgdHlwZSAhPT0gJ3N2ZycgPyBCdWZmZXIuZnJvbShkYXRhLnJlc3VsdCwgJ2Jhc2U2NCcpIDogZGF0YS5yZXN1bHRcclxuICAgICAgICAgICk7XHJcbiAgICAgICAgfVxyXG4gICAgICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcihcclxuICAgICAgICAgICdbY2hhcnRdIEVycm9yIHdoaWxlIHNhdmluZyBhIGNoYXJ0LicsXHJcbiAgICAgICAgICA1MDBcclxuICAgICAgICApLnNldEVycm9yKGVycm9yKTtcclxuICAgICAgfVxyXG5cclxuICAgICAgLy8gS2lsbCBwb29sIGFuZCBjbG9zZSBicm93c2VyIGFmdGVyIGZpbmlzaGluZyBzaW5nbGUgZXhwb3J0XHJcbiAgICAgIGF3YWl0IGtpbGxQb29sKCk7XHJcbiAgICB9KTtcclxuICB9IGVsc2Uge1xyXG4gICAgdGhyb3cgbmV3IEV4cG9ydEVycm9yKFxyXG4gICAgICAnW2NoYXJ0XSBObyBleHBlY3RlZCBgZXhwb3J0YCBvcHRpb25zIHdlcmUgZm91bmQuIFBsZWFzZSBwcm92aWRlIG9uZSBvZiB0aGUgZm9sbG93aW5nIG9wdGlvbnM6IGBpbmZpbGVgLCBgaW5zdHJgLCBgb3B0aW9uc2AsIG9yIGBzdmdgIHRvIGdlbmVyYXRlIGEgdmFsaWQgaW1hZ2UuJyxcclxuICAgICAgNDAwXHJcbiAgICApO1xyXG4gIH1cclxufVxyXG5cclxuLyoqXHJcbiAqIFN0YXJ0cyBhIGJhdGNoIGV4cG9ydCBwcm9jZXNzIGZvciBtdWx0aXBsZSBjaGFydHMgYmFzZWQgb24gdGhlIGluZm9ybWF0aW9uXHJcbiAqIGluIHRoZSBgYmF0Y2hgIG9wdGlvbi4gVGhlIGBiYXRjaGAgaXMgYSBzdHJpbmcgaW4gdGhlIGZvbGxvd2luZyBmb3JtYXQ6XHJcbiAqIFwiaW5maWxlMS5qc29uPW91dGZpbGUxLnBuZztpbmZpbGUyLmpzb249b3V0ZmlsZTIucG5nOy4uLlwiLiBSZXN1bHRzIGFyZSBzYXZlZFxyXG4gKiBpbiBwcm92aWRlZCBvdXRmaWxlcy5cclxuICpcclxuICogQGFzeW5jXHJcbiAqIEBmdW5jdGlvbiBiYXRjaEV4cG9ydFxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gb3B0aW9ucyAtIFRoZSBgb3B0aW9uc2Agb2JqZWN0LCB3aGljaCBtYXkgYmUgYSBwYXJ0aWFsXHJcbiAqIG9yIGNvbXBsZXRlIHNldCBvZiBvcHRpb25zLiBJdCBtdXN0IGNvbnRhaW4gdGhlIGBiYXRjaGAgb3B0aW9uIHRvIGdlbmVyYXRlXHJcbiAqIHZhbGlkIGltYWdlcy5cclxuICpcclxuICogQHJldHVybnMge1Byb21pc2U8dm9pZD59IEEgUHJvbWlzZSB0aGF0IHJlc29sdmVzIG9uY2UgdGhlIGJhdGNoIGV4cG9ydFxyXG4gKiBwcm9jZXNzZXMgYXJlIGNvbXBsZXRlZC5cclxuICpcclxuICogQHRocm93cyB7RXhwb3J0RXJyb3J9IFRocm93cyBhbiBgRXhwb3J0RXJyb3JgIGlmIGFuIGVycm9yIG9jY3VycyBkdXJpbmdcclxuICogYW55IG9mIHRoZSBiYXRjaCBleHBvcnQgcHJvY2Vzcy5cclxuICovXHJcbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBiYXRjaEV4cG9ydChvcHRpb25zKSB7XHJcbiAgLy8gQ2hlY2sgaWYgdGhlIGV4cG9ydCBtYWtlcyBzZW5zZVxyXG4gIGlmIChvcHRpb25zICYmIG9wdGlvbnMuZXhwb3J0ICYmIG9wdGlvbnMuZXhwb3J0LmJhdGNoKSB7XHJcbiAgICAvLyBBbiBhcnJheSBmb3IgY29sbGVjdGluZyBiYXRjaCBleHBvcnRzXHJcbiAgICBjb25zdCBiYXRjaEZ1bmN0aW9ucyA9IFtdO1xyXG5cclxuICAgIC8vIFNwbGl0IGFuZCBwYWlyIHRoZSBgYmF0Y2hgIGFyZ3VtZW50c1xyXG4gICAgZm9yIChsZXQgcGFpciBvZiBvcHRpb25zLmV4cG9ydC5iYXRjaC5zcGxpdCgnOycpIHx8IFtdKSB7XHJcbiAgICAgIHBhaXIgPSBwYWlyLnNwbGl0KCc9Jyk7XHJcbiAgICAgIGlmIChwYWlyLmxlbmd0aCA9PT0gMikge1xyXG4gICAgICAgIGJhdGNoRnVuY3Rpb25zLnB1c2goXHJcbiAgICAgICAgICBzdGFydEV4cG9ydChcclxuICAgICAgICAgICAge1xyXG4gICAgICAgICAgICAgIC4uLm9wdGlvbnMsXHJcbiAgICAgICAgICAgICAgZXhwb3J0OiB7XHJcbiAgICAgICAgICAgICAgICAuLi5vcHRpb25zLmV4cG9ydCxcclxuICAgICAgICAgICAgICAgIGluZmlsZTogcGFpclswXSxcclxuICAgICAgICAgICAgICAgIG91dGZpbGU6IHBhaXJbMV1cclxuICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgIH0sXHJcbiAgICAgICAgICAgIChlcnJvciwgZGF0YSkgPT4ge1xyXG4gICAgICAgICAgICAgIC8vIEV4aXQgcHJvY2VzcyB3aGVuIGVycm9yIGV4aXN0c1xyXG4gICAgICAgICAgICAgIGlmIChlcnJvcikge1xyXG4gICAgICAgICAgICAgICAgdGhyb3cgZXJyb3I7XHJcbiAgICAgICAgICAgICAgfVxyXG5cclxuICAgICAgICAgICAgICAvLyBHZXQgdGhlIGBiNjRgLCBgb3V0ZmlsZWAsIGFuZCBgdHlwZWAgZm9yIGEgY2hhcnRcclxuICAgICAgICAgICAgICBjb25zdCB7IGI2NCwgb3V0ZmlsZSwgdHlwZSB9ID0gZGF0YS5vcHRpb25zLmV4cG9ydDtcclxuXHJcbiAgICAgICAgICAgICAgLy8gU2F2ZSB0aGUgcmVzdWx0XHJcbiAgICAgICAgICAgICAgdHJ5IHtcclxuICAgICAgICAgICAgICAgIGlmIChiNjQpIHtcclxuICAgICAgICAgICAgICAgICAgLy8gQXMgYSBCYXNlNjQgc3RyaW5nIHRvIGEgdHh0IGZpbGVcclxuICAgICAgICAgICAgICAgICAgd3JpdGVGaWxlU3luYyhcclxuICAgICAgICAgICAgICAgICAgICBgJHtvdXRmaWxlLnNwbGl0KCcuJykuc2hpZnQoKSB8fCAnY2hhcnQnfS50eHRgLFxyXG4gICAgICAgICAgICAgICAgICAgIGdldEJhc2U2NChkYXRhLnJlc3VsdCwgdHlwZSlcclxuICAgICAgICAgICAgICAgICAgKTtcclxuICAgICAgICAgICAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgICAgICAgICAgIC8vIEFzIGEgY29ycmVjdCBpbWFnZSBmb3JtYXRcclxuICAgICAgICAgICAgICAgICAgd3JpdGVGaWxlU3luYyhcclxuICAgICAgICAgICAgICAgICAgICBvdXRmaWxlLFxyXG4gICAgICAgICAgICAgICAgICAgIHR5cGUgIT09ICdzdmcnXHJcbiAgICAgICAgICAgICAgICAgICAgICA/IEJ1ZmZlci5mcm9tKGRhdGEucmVzdWx0LCAnYmFzZTY0JylcclxuICAgICAgICAgICAgICAgICAgICAgIDogZGF0YS5yZXN1bHRcclxuICAgICAgICAgICAgICAgICAgKTtcclxuICAgICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgICAgICAgICAgICAgdGhyb3cgbmV3IEV4cG9ydEVycm9yKFxyXG4gICAgICAgICAgICAgICAgICAnW2NoYXJ0XSBFcnJvciB3aGlsZSBzYXZpbmcgYSBjaGFydC4nLFxyXG4gICAgICAgICAgICAgICAgICA1MDBcclxuICAgICAgICAgICAgICAgICkuc2V0RXJyb3IoZXJyb3IpO1xyXG4gICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgfVxyXG4gICAgICAgICAgKVxyXG4gICAgICAgICk7XHJcbiAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgbG9nKDIsICdbY2hhcnRdIE5vIGNvcnJlY3QgcGFpciBmb3VuZCBmb3IgdGhlIGJhdGNoIGV4cG9ydC4nKTtcclxuICAgICAgfVxyXG4gICAgfVxyXG5cclxuICAgIC8vIEF3YWl0IGFsbCBleHBvcnRzIGFyZSBkb25lXHJcbiAgICBjb25zdCBiYXRjaFJlc3VsdHMgPSBhd2FpdCBQcm9taXNlLmFsbFNldHRsZWQoYmF0Y2hGdW5jdGlvbnMpO1xyXG5cclxuICAgIC8vIEtpbGwgcG9vbCBhbmQgY2xvc2UgYnJvd3NlciBhZnRlciBmaW5pc2hpbmcgYmF0Y2ggZXhwb3J0XHJcbiAgICBhd2FpdCBraWxsUG9vbCgpO1xyXG5cclxuICAgIC8vIExvZyBlcnJvcnMgaWYgZm91bmRcclxuICAgIGJhdGNoUmVzdWx0cy5mb3JFYWNoKChyZXN1bHQsIGluZGV4KSA9PiB7XHJcbiAgICAgIC8vIExvZyB0aGUgZXJyb3Igd2l0aCBzdGFjayBhYm91dCB0aGUgc3BlY2lmaWMgYmF0Y2ggZXhwb3J0XHJcbiAgICAgIGlmIChyZXN1bHQucmVhc29uKSB7XHJcbiAgICAgICAgbG9nV2l0aFN0YWNrKFxyXG4gICAgICAgICAgMSxcclxuICAgICAgICAgIHJlc3VsdC5yZWFzb24sXHJcbiAgICAgICAgICBgW2NoYXJ0XSBCYXRjaCBleHBvcnQgbnVtYmVyICR7aW5kZXggKyAxfSBjb3VsZCBub3QgYmUgY29ycmVjdGx5IGNvbXBsZXRlZC5gXHJcbiAgICAgICAgKTtcclxuICAgICAgfVxyXG4gICAgfSk7XHJcbiAgfSBlbHNlIHtcclxuICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcihcclxuICAgICAgJ1tjaGFydF0gTm8gZXhwZWN0ZWQgYGV4cG9ydGAgb3B0aW9ucyB3ZXJlIGZvdW5kLiBQbGVhc2UgcHJvdmlkZSB0aGUgYGJhdGNoYCBvcHRpb24gdG8gZ2VuZXJhdGUgdmFsaWQgaW1hZ2VzLicsXHJcbiAgICAgIDQwMFxyXG4gICAgKTtcclxuICB9XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBTdGFydHMgYW4gZXhwb3J0IHByb2Nlc3MuIFRoZSBgY3VzdG9tT3B0aW9uc2AgcGFyYW1ldGVyIGlzIGFuIG9iamVjdCB0aGF0XHJcbiAqIG1heSBiZSBwYXJ0aWFsIG9yIGNvbXBsZXRlIHNldCBvZiBvcHRpb25zLiBUaGUgYGVuZENhbGxiYWNrYCBpcyBjYWxsZWQgd2hlblxyXG4gKiB0aGUgZXhwb3J0IGlzIGNvbXBsZXRlZCwgd2l0aCB0aGUgYGVycm9yYCBvYmplY3QgYXMgdGhlIGZpcnN0IGFyZ3VtZW50XHJcbiAqIGFuZCB0aGUgYGRhdGFgIG9iamVjdCBhcyB0aGUgc2Vjb25kLCB3aGljaCBjb250YWlucyB0aGUgQmFzZTY0IHJlcHJlc2VudGF0aW9uXHJcbiAqIG9mIHRoZSBjaGFydCBpbiB0aGUgYHJlc3VsdGAgcHJvcGVydHkgYW5kIHRoZSBmdWxsIHNldCBvZiBleHBvcnQgb3B0aW9uc1xyXG4gKiBpbiB0aGUgYG9wdGlvbnNgIHByb3BlcnR5LlxyXG4gKlxyXG4gKiBAYXN5bmNcclxuICogQGZ1bmN0aW9uIHN0YXJ0RXhwb3J0XHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBjdXN0b21PcHRpb25zIC0gVGhlIGBjdXN0b21PcHRpb25zYCBvYmplY3QsIHdoaWNoIG1heVxyXG4gKiBiZSBhIHBhcnRpYWwgb3IgY29tcGxldGUgc2V0IG9mIG9wdGlvbnMuIElmIHRoZSBwcm92aWRlZCBvcHRpb25zIGFyZSBwYXJ0aWFsLFxyXG4gKiBtaXNzaW5nIHZhbHVlcyB3aWxsIGJlIG1lcmdlZCB3aXRoIHRoZSBkZWZhdWx0IGdlbmVyYWwgb3B0aW9ucywgcmV0cmlldmVkXHJcbiAqIHVzaW5nIHRoZSBgZ2V0T3B0aW9uc2AgZnVuY3Rpb24uXHJcbiAqIEBwYXJhbSB7RnVuY3Rpb259IGVuZENhbGxiYWNrIC0gVGhlIGNhbGxiYWNrIGZ1bmN0aW9uIHRvIGJlIGludm9rZWQgdXBvblxyXG4gKiBmaW5hbGl6aW5nIHdvcmsgb3IgdXBvbiBlcnJvciBvY2N1cmFuY2Ugb2YgdGhlIGV4cG9ydGluZyBwcm9jZXNzLiBUaGUgZmlyc3RcclxuICogYXJndW1lbnQgaXMgYGVycm9yYCBvYmplY3QgYW5kIHRoZSBgZGF0YWAgb2JqZWN0IGlzIHRoZSBzZWNvbmQsIHRoYXQgY29udGFpbnNcclxuICogdGhlIEJhc2U2NCByZXByZXNlbnRhdGlvbiBvZiB0aGUgY2hhcnQgaW4gdGhlIGByZXN1bHRgIHByb3BlcnR5IGFuZCB0aGUgZnVsbFxyXG4gKiBzZXQgb2YgZXhwb3J0IG9wdGlvbnMgaW4gdGhlIGBvcHRpb25zYCBwcm9wZXJ0eS5cclxuICpcclxuICogQHJldHVybnMge1Byb21pc2U8dm9pZD59IFRoaXMgZnVuY3Rpb24gZG9lcyBub3QgcmV0dXJuIGEgdmFsdWUgZGlyZWN0bHkuXHJcbiAqIEluc3RlYWQsIGl0IGNvbW11bmljYXRlcyByZXN1bHRzIHZpYSB0aGUgYGVuZENhbGxiYWNrYC5cclxuICpcclxuICogQHRocm93cyB7RXhwb3J0RXJyb3J9IFRocm93cyBhbiBgRXhwb3J0RXJyb3JgIGlmIHRoZXJlIGlzIGEgcHJvYmxlbSB3aXRoXHJcbiAqIHByb2Nlc3NpbmcgaW5wdXQgb2YgYW55IHR5cGUuIFRoZSBlcnJvciBpcyBwYXNzZWQgaW50byB0aGUgYGVuZENhbGxiYWNrYFxyXG4gKiBmdW5jdGlvbiBhbmQgcHJvY2Vzc2VkIHRoZXJlLlxyXG4gKi9cclxuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIHN0YXJ0RXhwb3J0KGN1c3RvbU9wdGlvbnMsIGVuZENhbGxiYWNrKSB7XHJcbiAgdHJ5IHtcclxuICAgIC8vIFN0YXJ0aW5nIGV4cG9ydGluZyBwcm9jZXNzIG1lc3NhZ2VcclxuICAgIGxvZyg0LCAnW2NoYXJ0XSBTdGFydGluZyB0aGUgZXhwb3J0aW5nIHByb2Nlc3MuJyk7XHJcblxyXG4gICAgLy8gTWVyZ2UgdGhlIGN1c3RvbSBvcHRpb25zIGludG8gZGVmYXVsdCBvbmVzXHJcbiAgICBjb25zdCBvcHRpb25zID0gbWVyZ2VPcHRpb25zKGdldE9wdGlvbnMoZmFsc2UpLCBjdXN0b21PcHRpb25zKTtcclxuXHJcbiAgICAvLyBHZXQgdGhlIGV4cG9ydCBvcHRpb25zXHJcbiAgICBjb25zdCBleHBvcnRPcHRpb25zID0gb3B0aW9ucy5leHBvcnQ7XHJcblxyXG4gICAgLy8gRXhwb3J0IHVzaW5nIG9wdGlvbnMgZnJvbSB0aGUgZmlsZSBhcyBhbiBpbnB1dFxyXG4gICAgaWYgKGV4cG9ydE9wdGlvbnMuaW5maWxlICE9PSBudWxsKSB7XHJcbiAgICAgIGxvZyg0LCAnW2NoYXJ0XSBBdHRlbXB0aW5nIHRvIGV4cG9ydCBmcm9tIGEgZmlsZSBpbnB1dC4nKTtcclxuXHJcbiAgICAgIGxldCBmaWxlQ29udGVudDtcclxuICAgICAgdHJ5IHtcclxuICAgICAgICAvLyBUcnkgdG8gcmVhZCB0aGUgZmlsZSB0byBnZXQgdGhlIHN0cmluZyByZXByZXNlbnRhdGlvblxyXG4gICAgICAgIGZpbGVDb250ZW50ID0gcmVhZEZpbGVTeW5jKFxyXG4gICAgICAgICAgZ2V0QWJzb2x1dGVQYXRoKGV4cG9ydE9wdGlvbnMuaW5maWxlKSxcclxuICAgICAgICAgICd1dGY4J1xyXG4gICAgICAgICk7XHJcbiAgICAgIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICAgICAgdGhyb3cgbmV3IEV4cG9ydEVycm9yKFxyXG4gICAgICAgICAgJ1tjaGFydF0gRXJyb3IgbG9hZGluZyBjb250ZW50IGZyb20gYSBmaWxlIGlucHV0LicsXHJcbiAgICAgICAgICA0MDBcclxuICAgICAgICApLnNldEVycm9yKGVycm9yKTtcclxuICAgICAgfVxyXG5cclxuICAgICAgLy8gQ2hlY2sgdGhlIGZpbGUncyBleHRlbnNpb25cclxuICAgICAgaWYgKGV4cG9ydE9wdGlvbnMuaW5maWxlLmVuZHNXaXRoKCcuc3ZnJykpIHtcclxuICAgICAgICAvLyBTZXQgdG8gdGhlIGBzdmdgIG9wdGlvblxyXG4gICAgICAgIGV4cG9ydE9wdGlvbnMuc3ZnID0gZmlsZUNvbnRlbnQ7XHJcbiAgICAgIH0gZWxzZSBpZiAoZXhwb3J0T3B0aW9ucy5pbmZpbGUuZW5kc1dpdGgoJy5qc29uJykpIHtcclxuICAgICAgICAvLyBTZXQgdG8gdGhlIGBpbnN0cmAgb3B0aW9uXHJcbiAgICAgICAgZXhwb3J0T3B0aW9ucy5pbnN0ciA9IGZpbGVDb250ZW50O1xyXG4gICAgICB9IGVsc2Uge1xyXG4gICAgICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcihcclxuICAgICAgICAgICdbY2hhcnRdIEluY29ycmVjdCB2YWx1ZSBvZiB0aGUgYGluZmlsZWAgb3B0aW9uLicsXHJcbiAgICAgICAgICA0MDBcclxuICAgICAgICApO1xyXG4gICAgICB9XHJcbiAgICB9XHJcblxyXG4gICAgLy8gRXhwb3J0IHVzaW5nIFNWRyBhcyBhbiBpbnB1dFxyXG4gICAgaWYgKGV4cG9ydE9wdGlvbnMuc3ZnICE9PSBudWxsKSB7XHJcbiAgICAgIGxvZyg0LCAnW2NoYXJ0XSBBdHRlbXB0aW5nIHRvIGV4cG9ydCBmcm9tIGFuIFNWRyBpbnB1dC4nKTtcclxuXHJcbiAgICAgIC8vIFNWRyBleHBvcnRzIGF0dGVtcHRzIGNvdW50ZXJcclxuICAgICAgKytnZXRQb29sU3RhdHMoKS5leHBvcnRzRnJvbVN2Z0F0dGVtcHRzO1xyXG5cclxuICAgICAgLy8gRXhwb3J0IGZyb20gYW4gU1ZHIHN0cmluZ1xyXG4gICAgICBjb25zdCByZXN1bHQgPSBhd2FpdCBfZXhwb3J0RnJvbVN2ZyhcclxuICAgICAgICBzYW5pdGl6ZShleHBvcnRPcHRpb25zLnN2ZyksIC8vICMyMDlcclxuICAgICAgICBvcHRpb25zXHJcbiAgICAgICk7XHJcblxyXG4gICAgICAvLyBTVkcgZXhwb3J0cyBjb3VudGVyXHJcbiAgICAgICsrZ2V0UG9vbFN0YXRzKCkuZXhwb3J0c0Zyb21Tdmc7XHJcblxyXG4gICAgICAvLyBQYXNzIFNWRyBleHBvcnQgcmVzdWx0IHRvIHRoZSBlbmQgY2FsbGJhY2tcclxuICAgICAgcmV0dXJuIGVuZENhbGxiYWNrKG51bGwsIHJlc3VsdCk7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gRXhwb3J0IHVzaW5nIG9wdGlvbnMgYXMgYW4gaW5wdXRcclxuICAgIGlmIChleHBvcnRPcHRpb25zLmluc3RyICE9PSBudWxsIHx8IGV4cG9ydE9wdGlvbnMub3B0aW9ucyAhPT0gbnVsbCkge1xyXG4gICAgICBsb2coNCwgJ1tjaGFydF0gQXR0ZW1wdGluZyB0byBleHBvcnQgZnJvbSBvcHRpb25zIGlucHV0LicpO1xyXG5cclxuICAgICAgLy8gT3B0aW9ucyBleHBvcnRzIGF0dGVtcHRzIGNvdW50ZXJcclxuICAgICAgKytnZXRQb29sU3RhdHMoKS5leHBvcnRzRnJvbU9wdGlvbnNBdHRlbXB0cztcclxuXHJcbiAgICAgIC8vIEV4cG9ydCBmcm9tIG9wdGlvbnNcclxuICAgICAgY29uc3QgcmVzdWx0ID0gYXdhaXQgX2V4cG9ydEZyb21PcHRpb25zKFxyXG4gICAgICAgIGV4cG9ydE9wdGlvbnMuaW5zdHIgfHwgZXhwb3J0T3B0aW9ucy5vcHRpb25zLFxyXG4gICAgICAgIG9wdGlvbnNcclxuICAgICAgKTtcclxuXHJcbiAgICAgIC8vIE9wdGlvbnMgZXhwb3J0cyBjb3VudGVyXHJcbiAgICAgICsrZ2V0UG9vbFN0YXRzKCkuZXhwb3J0c0Zyb21PcHRpb25zO1xyXG5cclxuICAgICAgLy8gUGFzcyBvcHRpb25zIGV4cG9ydCByZXN1bHQgdG8gdGhlIGVuZCBjYWxsYmFja1xyXG4gICAgICByZXR1cm4gZW5kQ2FsbGJhY2sobnVsbCwgcmVzdWx0KTtcclxuICAgIH1cclxuXHJcbiAgICAvLyBObyBpbnB1dCBzcGVjaWZpZWQsIHBhc3MgYW4gZXJyb3IgbWVzc2FnZSB0byB0aGUgY2FsbGJhY2tcclxuICAgIHJldHVybiBlbmRDYWxsYmFjayhcclxuICAgICAgbmV3IEV4cG9ydEVycm9yKFxyXG4gICAgICAgIGBbY2hhcnRdIE5vIHZhbGlkIGlucHV0IHNwZWNpZmllZC4gQ2hlY2sgaWYgYXQgbGVhc3Qgb25lIG9mIHRoZSBmb2xsb3dpbmcgcGFyYW1ldGVycyBpcyBjb3JyZWN0bHkgc2V0OiAnaW5maWxlJywgJ2luc3RyJywgJ29wdGlvbnMnLCBvciAnc3ZnJy5gLFxyXG4gICAgICAgIDQwMFxyXG4gICAgICApXHJcbiAgICApO1xyXG4gIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICByZXR1cm4gZW5kQ2FsbGJhY2soZXJyb3IpO1xyXG4gIH1cclxufVxyXG5cclxuLyoqXHJcbiAqIFJldHJpZXZlcyBhbmQgcmV0dXJucyB0aGUgY3VycmVudCBzdGF0dXMgb2YgdGhlIGNvZGUgZXhlY3V0aW9uIHBlcm1pc3Npb24uXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBnZXRBbGxvd0NvZGVFeGVjdXRpb25cclxuICpcclxuICogQHJldHVybnMge2Jvb2xlYW59IFRoZSB2YWx1ZSBvZiB0aGUgZ2xvYmFsIGBhbGxvd0NvZGVFeGVjdXRpb25gIG9wdGlvbi5cclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiBnZXRBbGxvd0NvZGVFeGVjdXRpb24oKSB7XHJcbiAgcmV0dXJuIGFsbG93Q29kZUV4ZWN1dGlvbjtcclxufVxyXG5cclxuLyoqXHJcbiAqIFNldHMgdGhlIGNvZGUgZXhlY3V0aW9uIHBlcm1pc3Npb24gYmFzZWQgb24gdGhlIHByb3ZpZGVkIGJvb2xlYW4gdmFsdWUuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBzZXRBbGxvd0NvZGVFeGVjdXRpb25cclxuICpcclxuICogQHBhcmFtIHtib29sZWFufSB2YWx1ZSAtIFRoZSB2YWx1ZSB0byBiZSBhc3NpZ25lZCB0byB0aGUgZ2xvYmFsXHJcbiAqIGBhbGxvd0NvZGVFeGVjdXRpb25gIG9wdGlvbi5cclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiBzZXRBbGxvd0NvZGVFeGVjdXRpb24odmFsdWUpIHtcclxuICBhbGxvd0NvZGVFeGVjdXRpb24gPSB2YWx1ZTtcclxufVxyXG5cclxuLyoqXHJcbiAqIEV4cG9ydHMgZnJvbSBhbiBTVkcgYmFzZWQgaW5wdXQgd2l0aCB0aGUgcHJvdmlkZWQgb3B0aW9ucy5cclxuICpcclxuICogQGFzeW5jXHJcbiAqIEBmdW5jdGlvbiBfZXhwb3J0RnJvbVN2Z1xyXG4gKlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gaW5wdXRUb0V4cG9ydCAtIFRoZSBTVkcgYmFzZWQgaW5wdXQgdG8gYmUgZXhwb3J0ZWQuXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBvcHRpb25zIC0gVGhlIGBvcHRpb25zYCBvYmplY3QgY29udGFpbmluZyBjb21wbGV0ZSBzZXRcclxuICogb2Ygb3B0aW9ucy5cclxuICpcclxuICogQHJldHVybnMge1Byb21pc2U8dW5rbm93bj59IEEgUHJvbWlzZSB0aGF0IHJlc29sdmVzIHRvIGEgcmVzdWx0IG9mIHRoZSBleHBvcnRcclxuICogcHJvY2Vzcy5cclxuICpcclxuICogQHRocm93cyB7RXhwb3J0RXJyb3J9IFRocm93cyBhbiBgRXhwb3J0RXJyb3JgIGlmIHRoZXJlIGlzIG5vdCBhIGNvcnJlY3QgU1ZHXHJcbiAqIGlucHV0LlxyXG4gKi9cclxuYXN5bmMgZnVuY3Rpb24gX2V4cG9ydEZyb21TdmcoaW5wdXRUb0V4cG9ydCwgb3B0aW9ucykge1xyXG4gIC8vIENoZWNrIGlmIGl0IGlzIFNWR1xyXG4gIGlmIChcclxuICAgIHR5cGVvZiBpbnB1dFRvRXhwb3J0ID09PSAnc3RyaW5nJyAmJlxyXG4gICAgKGlucHV0VG9FeHBvcnQuaW5kZXhPZignPHN2ZycpID49IDAgfHwgaW5wdXRUb0V4cG9ydC5pbmRleE9mKCc8P3htbCcpID49IDApXHJcbiAgKSB7XHJcbiAgICBsb2coNCwgJ1tjaGFydF0gUGFyc2luZyBpbnB1dCBhcyBTVkcuJyk7XHJcblxyXG4gICAgLy8gU2V0IHRoZSBleHBvcnQgaW5wdXQgYXMgU1ZHXHJcbiAgICBvcHRpb25zLmV4cG9ydC5zdmcgPSBpbnB1dFRvRXhwb3J0O1xyXG5cclxuICAgIC8vIFJlc2V0IHRoZSByZXN0IG9mIHRoZSBleHBvcnQgaW5wdXQgb3B0aW9uc1xyXG4gICAgb3B0aW9ucy5leHBvcnQuaW5zdHIgPSBudWxsO1xyXG4gICAgb3B0aW9ucy5leHBvcnQub3B0aW9ucyA9IG51bGw7XHJcblxyXG4gICAgLy8gQ2FsbCB0aGUgZnVuY3Rpb24gd2l0aCBhbiBTVkcgc3RyaW5nIGFzIGFuIGV4cG9ydCBpbnB1dFxyXG4gICAgcmV0dXJuIF9wcmVwYXJlRXhwb3J0KG9wdGlvbnMpO1xyXG4gIH0gZWxzZSB7XHJcbiAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoJ1tjaGFydF0gTm90IGEgY29ycmVjdCBTVkcgaW5wdXQuJywgNDAwKTtcclxuICB9XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBFeHBvcnRzIGZyb20gYW4gb3B0aW9ucyBiYXNlZCBpbnB1dCB3aXRoIHRoZSBwcm92aWRlZCBvcHRpb25zLlxyXG4gKlxyXG4gKiBAYXN5bmNcclxuICogQGZ1bmN0aW9uIF9leHBvcnRGcm9tT3B0aW9uc1xyXG4gKlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gaW5wdXRUb0V4cG9ydCAtIFRoZSBvcHRpb25zIGJhc2VkIGlucHV0IHRvIGJlIGV4cG9ydGVkLlxyXG4gKiBAcGFyYW0ge09iamVjdH0gb3B0aW9ucyAtIFRoZSBgb3B0aW9uc2Agb2JqZWN0IGNvbnRhaW5pbmcgY29tcGxldGUgc2V0XHJcbiAqIG9mIG9wdGlvbnMuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtQcm9taXNlPHVua25vd24+fSBBIFByb21pc2UgdGhhdCByZXNvbHZlcyB0byBhIHJlc3VsdCBvZiB0aGUgZXhwb3J0XHJcbiAqIHByb2Nlc3MuXHJcbiAqXHJcbiAqIEB0aHJvd3Mge0V4cG9ydEVycm9yfSBUaHJvd3MgYW4gYEV4cG9ydEVycm9yYCBpZiB0aGVyZSBpcyBub3QgYSBjb3JyZWN0XHJcbiAqIGNoYXJ0IG9wdGlvbnMgaW5wdXQuXHJcbiAqL1xyXG5hc3luYyBmdW5jdGlvbiBfZXhwb3J0RnJvbU9wdGlvbnMoaW5wdXRUb0V4cG9ydCwgb3B0aW9ucykge1xyXG4gIGxvZyg0LCAnW2NoYXJ0XSBQYXJzaW5nIGlucHV0IGZyb20gb3B0aW9ucy4nKTtcclxuXHJcbiAgLy8gVHJ5IHRvIGNoZWNrLCB2YWxpZGF0ZSBhbmQgcGFyc2UgdG8gc3RyaW5naWZpZWQgb3B0aW9uc1xyXG4gIGNvbnN0IHN0cmluZ2lmaWVkT3B0aW9ucyA9IGlzQWxsb3dlZENvbmZpZyhcclxuICAgIGlucHV0VG9FeHBvcnQsXHJcbiAgICB0cnVlLFxyXG4gICAgb3B0aW9ucy5jdXN0b21Mb2dpYy5hbGxvd0NvZGVFeGVjdXRpb25cclxuICApO1xyXG5cclxuICAvLyBDaGVjayBpZiBhIGNvcnJlY3Qgc3RyaW5naWZpZWQgb3B0aW9uc1xyXG4gIGlmIChcclxuICAgIHN0cmluZ2lmaWVkT3B0aW9ucyA9PT0gbnVsbCB8fFxyXG4gICAgdHlwZW9mIHN0cmluZ2lmaWVkT3B0aW9ucyAhPT0gJ3N0cmluZycgfHxcclxuICAgICFzdHJpbmdpZmllZE9wdGlvbnMuc3RhcnRzV2l0aCgneycpIHx8XHJcbiAgICAhc3RyaW5naWZpZWRPcHRpb25zLmVuZHNXaXRoKCd9JylcclxuICApIHtcclxuICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcihcclxuICAgICAgJ1tjaGFydF0gSW52YWxpZCBjb25maWd1cmF0aW9uIHByb3ZpZGVkIC0gT25seSBvcHRpb25zIGNvbmZpZ3VyYXRpb25zIGFuZCBTVkcgYXJlIGFsbG93ZWQgZm9yIHRoaXMgc2VydmVyLiBJZiB0aGlzIGlzIHlvdXIgc2VydmVyLCBKYXZhU2NyaXB0IGN1c3RvbSBjb2RlIGNhbiBiZSBlbmFibGVkIGJ5IHN0YXJ0aW5nIHRoZSBzZXJ2ZXIgd2l0aCB0aGUgYGFsbG93Q29kZUV4ZWN1dGlvbmAgb3B0aW9ucyBzZXQgdG8gdHJ1ZS4nLFxyXG4gICAgICA0MDNcclxuICAgICk7XHJcbiAgfVxyXG5cclxuICAvLyBTZXQgdGhlIGV4cG9ydCBpbnB1dCBhcyBhIHN0cmluZ2lmaWVkIGNoYXJ0IG9wdGlvbnNcclxuICBvcHRpb25zLmV4cG9ydC5pbnN0ciA9IHN0cmluZ2lmaWVkT3B0aW9ucztcclxuXHJcbiAgLy8gUmVzZXQgdGhlIHJlc3Qgb2YgdGhlIGV4cG9ydCBpbnB1dCBvcHRpb25zXHJcbiAgb3B0aW9ucy5leHBvcnQuc3ZnID0gbnVsbDtcclxuXHJcbiAgLy8gQ2FsbCB0aGUgZnVuY3Rpb24gd2l0aCBhIHN0cmluZ2lmaWVkIGNoYXJ0IG9wdGlvbnNcclxuICByZXR1cm4gX3ByZXBhcmVFeHBvcnQob3B0aW9ucyk7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBGdW5jdGlvbiBmb3IgZmluYWxpemluZyBvcHRpb25zIGFuZCBjb25maWd1cmF0aW9ucyBiZWZvcmUgZXhwb3J0LlxyXG4gKlxyXG4gKiBAYXN5bmNcclxuICogQGZ1bmN0aW9uIF9wcmVwYXJlRXhwb3J0XHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBvcHRpb25zIC0gVGhlIGBvcHRpb25zYCBvYmplY3QgY29udGFpbmluZyBjb21wbGV0ZSBzZXRcclxuICogb2Ygb3B0aW9ucy5cclxuICpcclxuICogQHJldHVybnMge1Byb21pc2U8dW5rbm93bj59IEEgUHJvbWlzZSB0aGF0IHJlc29sdmVzIHRvIGEgcmVzdWx0IG9mIHRoZSBleHBvcnRcclxuICogcHJvY2Vzcy5cclxuICovXHJcbmFzeW5jIGZ1bmN0aW9uIF9wcmVwYXJlRXhwb3J0KG9wdGlvbnMpIHtcclxuICBjb25zdCB7IGV4cG9ydDogZXhwb3J0T3B0aW9ucywgY3VzdG9tTG9naWM6IGN1c3RvbUxvZ2ljT3B0aW9ucyB9ID0gb3B0aW9ucztcclxuXHJcbiAgLy8gUHJlcGFyZSB0aGUgYHR5cGVgIG9wdGlvblxyXG4gIGV4cG9ydE9wdGlvbnMudHlwZSA9IGZpeFR5cGUoZXhwb3J0T3B0aW9ucy50eXBlLCBleHBvcnRPcHRpb25zLm91dGZpbGUpO1xyXG5cclxuICAvLyBQcmVwYXJlIHRoZSBgb3V0ZmlsZWAgb3B0aW9uXHJcbiAgZXhwb3J0T3B0aW9ucy5vdXRmaWxlID0gZml4T3V0ZmlsZShleHBvcnRPcHRpb25zLnR5cGUsIGV4cG9ydE9wdGlvbnMub3V0ZmlsZSk7XHJcblxyXG4gIC8vIE5vdGlmeSBhYm91dCB0aGUgY3VzdG9tIGxvZ2ljIHVzYWdlIHN0YXR1c1xyXG4gIGxvZyhcclxuICAgIDMsXHJcbiAgICBgW2NoYXJ0XSBUaGUgY3VzdG9tIGxvZ2ljIGlzICR7Y3VzdG9tTG9naWNPcHRpb25zLmFsbG93Q29kZUV4ZWN1dGlvbiA/ICdhbGxvd2VkJyA6ICdkaXNhbGxvd2VkJ30uYFxyXG4gICk7XHJcblxyXG4gIC8vIFByZXBhcmUgdGhlIGN1c3RvbSBsb2dpYyBvcHRpb25zIChgY3VzdG9tQ29kZWAsIGBjYWxsYmFja2AsIGByZXNvdXJjZXNgKVxyXG4gIF9oYW5kbGVDdXN0b21Mb2dpYyhjdXN0b21Mb2dpY09wdGlvbnMsIGN1c3RvbUxvZ2ljT3B0aW9ucy5hbGxvd0NvZGVFeGVjdXRpb24pO1xyXG5cclxuICAvLyBQcmVwYXJlIHRoZSBgZ2xvYmFsT3B0aW9uc2AgYW5kIGB0aGVtZU9wdGlvbnNgIG9wdGlvbnNcclxuICBfaGFuZGxlR2xvYmFsQW5kVGhlbWUoXHJcbiAgICBleHBvcnRPcHRpb25zLFxyXG4gICAgY3VzdG9tTG9naWNPcHRpb25zLmFsbG93RmlsZVJlc291cmNlcyxcclxuICAgIGN1c3RvbUxvZ2ljT3B0aW9ucy5hbGxvd0NvZGVFeGVjdXRpb25cclxuICApO1xyXG5cclxuICAvLyBQcmVwYXJlIHRoZSBgaGVpZ2h0YCwgYHdpZHRoYCwgYW5kIGBzY2FsZWAgb3B0aW9uc1xyXG4gIG9wdGlvbnMuZXhwb3J0ID0ge1xyXG4gICAgLi4uZXhwb3J0T3B0aW9ucyxcclxuICAgIC4uLl9maW5kQ2hhcnRTaXplKGV4cG9ydE9wdGlvbnMpXHJcbiAgfTtcclxuXHJcbiAgLy8gUG9zdCB0aGUgd29yayB0byB0aGUgcG9vbFxyXG4gIHJldHVybiBwb3N0V29yayhvcHRpb25zKTtcclxufVxyXG5cclxuLyoqXHJcbiAqIENhbGN1bGF0ZXMgdGhlIGBoZWlnaHRgLCBgd2lkdGhgIGFuZCBgc2NhbGVgIGZvciBjaGFydCBleHBvcnRzIGJhc2VkXHJcbiAqIG9uIHRoZSBwcm92aWRlZCBleHBvcnQgb3B0aW9ucy5cclxuICpcclxuICogVGhlIGZ1bmN0aW9uIHByaW9yaXRpemVzIHZhbHVlcyBpbiB0aGUgZm9sbG93aW5nIG9yZGVyOlxyXG4gKiAxLiBUaGUgYGhlaWdodGAsIGB3aWR0aGAsIGBzY2FsZWAgZnJvbSB0aGUgYGV4cG9ydE9wdGlvbnNgLlxyXG4gKiAyLiBPcHRpb25zIGZyb20gdGhlIGNoYXJ0IGNvbmZpZ3VyYXRpb24gKGZyb20gYGV4cG9ydGluZ2AgYW5kIGBjaGFydGApLlxyXG4gKiAzLiBPcHRpb25zIGZyb20gdGhlIGdsb2JhbCBvcHRpb25zIChmcm9tIGBleHBvcnRpbmdgIGFuZCBgY2hhcnRgKS5cclxuICogNC4gT3B0aW9ucyBmcm9tIHRoZSB0aGVtZSBvcHRpb25zIChmcm9tIGBleHBvcnRpbmdgIGFuZCBgY2hhcnRgIHNlY3Rpb25zKS5cclxuICogNS4gRmFsbGJhY2sgZGVmYXVsdCB2YWx1ZXMgKGBoZWlnaHQgPSA0MDBgLCBgd2lkdGggPSA2MDBgLCBgc2NhbGUgPSAxYCkuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBfZmluZENoYXJ0U2l6ZVxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gZXhwb3J0T3B0aW9ucyAtIFRoZSBvYmplY3QgY29udGFpbmluZyBgZXhwb3J0YCBvcHRpb25zLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7T2JqZWN0fSBBbiBvYmplY3QgY29udGFpbmluZyB0aGUgY2FsY3VsYXRlZCBgaGVpZ2h0YCwgYHdpZHRoYFxyXG4gKiBhbmQgYHNjYWxlYCB2YWx1ZXMgZm9yIHRoZSBjaGFydCBleHBvcnQuXHJcbiAqL1xyXG5mdW5jdGlvbiBfZmluZENoYXJ0U2l6ZShleHBvcnRPcHRpb25zKSB7XHJcbiAgLy8gQ2hlY2sgdGhlIGBvcHRpb25zYCBhbmQgYGluc3RyYCBmb3IgY2hhcnQgYW5kIGV4cG9ydGluZyBzZWN0aW9uc1xyXG4gIGNvbnN0IHsgY2hhcnQ6IG9wdGlvbnNDaGFydCwgZXhwb3J0aW5nOiBvcHRpb25zRXhwb3J0aW5nIH0gPVxyXG4gICAgZXhwb3J0T3B0aW9ucy5vcHRpb25zIHx8IGlzQWxsb3dlZENvbmZpZyhleHBvcnRPcHRpb25zLmluc3RyKSB8fCBmYWxzZTtcclxuXHJcbiAgLy8gQ2hlY2sgdGhlIGBnbG9iYWxPcHRpb25zYCBmb3IgY2hhcnQgYW5kIGV4cG9ydGluZyBzZWN0aW9uc1xyXG4gIGNvbnN0IHsgY2hhcnQ6IGdsb2JhbE9wdGlvbnNDaGFydCwgZXhwb3J0aW5nOiBnbG9iYWxPcHRpb25zRXhwb3J0aW5nIH0gPVxyXG4gICAgaXNBbGxvd2VkQ29uZmlnKGV4cG9ydE9wdGlvbnMuZ2xvYmFsT3B0aW9ucykgfHwgZmFsc2U7XHJcblxyXG4gIC8vIENoZWNrIHRoZSBgdGhlbWVPcHRpb25zYCBmb3IgY2hhcnQgYW5kIGV4cG9ydGluZyBzZWN0aW9uc1xyXG4gIGNvbnN0IHsgY2hhcnQ6IHRoZW1lT3B0aW9uc0NoYXJ0LCBleHBvcnRpbmc6IHRoZW1lT3B0aW9uc0V4cG9ydGluZyB9ID1cclxuICAgIGlzQWxsb3dlZENvbmZpZyhleHBvcnRPcHRpb25zLnRoZW1lT3B0aW9ucykgfHwgZmFsc2U7XHJcblxyXG4gIC8vIEZpbmQgdGhlIGBzY2FsZWAgdmFsdWU6XHJcbiAgLy8gLSBJdCBjYW5ub3QgYmUgbG93ZXIgdGhhbiAwLjFcclxuICAvLyAtIEl0IGNhbm5vdCBiZSBoaWdoZXIgdGhhbiA1LjBcclxuICAvLyAtIEl0IG11c3QgYmUgcm91bmRlZCB0byAyIGRlY2ltYWwgcGxhY2VzIChlLmcuIDAuMjMyMzQgLT4gMC4yMylcclxuICBjb25zdCBzY2FsZSA9IHJvdW5kTnVtYmVyKFxyXG4gICAgTWF0aC5tYXgoXHJcbiAgICAgIDAuMSxcclxuICAgICAgTWF0aC5taW4oXHJcbiAgICAgICAgZXhwb3J0T3B0aW9ucy5zY2FsZSB8fFxyXG4gICAgICAgICAgb3B0aW9uc0V4cG9ydGluZz8uc2NhbGUgfHxcclxuICAgICAgICAgIGdsb2JhbE9wdGlvbnNFeHBvcnRpbmc/LnNjYWxlIHx8XHJcbiAgICAgICAgICB0aGVtZU9wdGlvbnNFeHBvcnRpbmc/LnNjYWxlIHx8XHJcbiAgICAgICAgICBleHBvcnRPcHRpb25zLmRlZmF1bHRTY2FsZSB8fFxyXG4gICAgICAgICAgMSxcclxuICAgICAgICA1LjBcclxuICAgICAgKVxyXG4gICAgKSxcclxuICAgIDJcclxuICApO1xyXG5cclxuICAvLyBGaW5kIHRoZSBgaGVpZ2h0YCB2YWx1ZVxyXG4gIGNvbnN0IGhlaWdodCA9XHJcbiAgICBleHBvcnRPcHRpb25zLmhlaWdodCB8fFxyXG4gICAgb3B0aW9uc0V4cG9ydGluZz8uc291cmNlSGVpZ2h0IHx8XHJcbiAgICBvcHRpb25zQ2hhcnQ/LmhlaWdodCB8fFxyXG4gICAgZ2xvYmFsT3B0aW9uc0V4cG9ydGluZz8uc291cmNlSGVpZ2h0IHx8XHJcbiAgICBnbG9iYWxPcHRpb25zQ2hhcnQ/LmhlaWdodCB8fFxyXG4gICAgdGhlbWVPcHRpb25zRXhwb3J0aW5nPy5zb3VyY2VIZWlnaHQgfHxcclxuICAgIHRoZW1lT3B0aW9uc0NoYXJ0Py5oZWlnaHQgfHxcclxuICAgIGV4cG9ydE9wdGlvbnMuZGVmYXVsdEhlaWdodCB8fFxyXG4gICAgNDAwO1xyXG5cclxuICAvLyBGaW5kIHRoZSBgd2lkdGhgIHZhbHVlXHJcbiAgY29uc3Qgd2lkdGggPVxyXG4gICAgZXhwb3J0T3B0aW9ucy53aWR0aCB8fFxyXG4gICAgb3B0aW9uc0V4cG9ydGluZz8uc291cmNlV2lkdGggfHxcclxuICAgIG9wdGlvbnNDaGFydD8ud2lkdGggfHxcclxuICAgIGdsb2JhbE9wdGlvbnNFeHBvcnRpbmc/LnNvdXJjZVdpZHRoIHx8XHJcbiAgICBnbG9iYWxPcHRpb25zQ2hhcnQ/LndpZHRoIHx8XHJcbiAgICB0aGVtZU9wdGlvbnNFeHBvcnRpbmc/LnNvdXJjZVdpZHRoIHx8XHJcbiAgICB0aGVtZU9wdGlvbnNDaGFydD8ud2lkdGggfHxcclxuICAgIGV4cG9ydE9wdGlvbnMuZGVmYXVsdFdpZHRoIHx8XHJcbiAgICA2MDA7XHJcblxyXG4gIC8vIEdhdGhlciBgaGVpZ2h0YCwgYHdpZHRoYCBhbmQgYHNjYWxlYCBpbmZvcm1hdGlvbiBpbiBvbmUgb2JqZWN0XHJcbiAgY29uc3Qgc2l6ZSA9IHsgaGVpZ2h0LCB3aWR0aCwgc2NhbGUgfTtcclxuXHJcbiAgLy8gR2V0IHJpZCBvZiBwb3RlbnRpYWwgYHB4YCBhbmQgYCVgXHJcbiAgZm9yIChsZXQgW3BhcmFtLCB2YWx1ZV0gb2YgT2JqZWN0LmVudHJpZXMoc2l6ZSkpIHtcclxuICAgIHNpemVbcGFyYW1dID1cclxuICAgICAgdHlwZW9mIHZhbHVlID09PSAnc3RyaW5nJyA/ICt2YWx1ZS5yZXBsYWNlKC9weHwlL2dpLCAnJykgOiB2YWx1ZTtcclxuICB9XHJcblxyXG4gIC8vIFJldHVybiB0aGUgc2l6ZSBvYmplY3RcclxuICByZXR1cm4gc2l6ZTtcclxufVxyXG5cclxuLyoqXHJcbiAqIEhhbmRsZXMgdGhlIGV4ZWN1dGlvbiBvZiBjdXN0b20gbG9naWMgb3B0aW9ucywgaW5jbHVkaW5nIGxvYWRpbmcgYHJlc291cmNlc2AsXHJcbiAqIGBjdXN0b21Db2RlYCwgYW5kIGBjYWxsYmFja2AuIElmIGNvZGUgZXhlY3V0aW9uIGlzIGFsbG93ZWQsIGl0IHByb2Nlc3Nlc1xyXG4gKiB0aGUgY3VzdG9tIGxvZ2ljIG9wdGlvbnMgYWNjb3JkaW5nbHkuIElmIGNvZGUgZXhlY3V0aW9uIGlzIG5vdCBhbGxvd2VkLFxyXG4gKiBpdCBkaXNhYmxlcyB0aGUgdXNhZ2Ugb2YgcmVzb3VyY2VzLCBjdXN0b20gY29kZSBhbmQgY2FsbGJhY2suXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBfaGFuZGxlQ3VzdG9tTG9naWNcclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IGN1c3RvbUxvZ2ljT3B0aW9ucyAtIFRoZSBvYmplY3QgY29udGFpbmluZyBgY3VzdG9tTG9naWNgXHJcbiAqIG9wdGlvbnMuXHJcbiAqIEBwYXJhbSB7Ym9vbGVhbn0gYWxsb3dDb2RlRXhlY3V0aW9uIC0gQSBmbGFnIGluZGljYXRpbmcgd2hldGhlciBjb2RlXHJcbiAqIGV4ZWN1dGlvbiBpcyBhbGxvd2VkLlxyXG4gKlxyXG4gKiBAdGhyb3dzIHtFeHBvcnRFcnJvcn0gVGhyb3dzIGFuIGBFeHBvcnRFcnJvcmAgaWYgY29kZSBleGVjdXRpb25cclxuICogaXMgbm90IGFsbG93ZWQgYnV0IGN1c3RvbSBsb2dpYyBvcHRpb25zIGFyZSBzdGlsbCBwcm92aWRlZC5cclxuICovXHJcbmZ1bmN0aW9uIF9oYW5kbGVDdXN0b21Mb2dpYyhjdXN0b21Mb2dpY09wdGlvbnMsIGFsbG93Q29kZUV4ZWN1dGlvbikge1xyXG4gIC8vIEluIGNhc2Ugb2YgYWxsb3dpbmcgY29kZSBleGVjdXRpb25cclxuICBpZiAoYWxsb3dDb2RlRXhlY3V0aW9uKSB7XHJcbiAgICAvLyBQcm9jZXNzIHRoZSBgcmVzb3VyY2VzYCBvcHRpb25cclxuICAgIGlmICh0eXBlb2YgY3VzdG9tTG9naWNPcHRpb25zLnJlc291cmNlcyA9PT0gJ3N0cmluZycpIHtcclxuICAgICAgLy8gQ3VzdG9tIHN0cmluZ2lmaWVkIHJlc291cmNlc1xyXG4gICAgICBjdXN0b21Mb2dpY09wdGlvbnMucmVzb3VyY2VzID0gX2hhbmRsZVJlc291cmNlcyhcclxuICAgICAgICBjdXN0b21Mb2dpY09wdGlvbnMucmVzb3VyY2VzLFxyXG4gICAgICAgIGN1c3RvbUxvZ2ljT3B0aW9ucy5hbGxvd0ZpbGVSZXNvdXJjZXMsXHJcbiAgICAgICAgdHJ1ZVxyXG4gICAgICApO1xyXG4gICAgfSBlbHNlIGlmICghY3VzdG9tTG9naWNPcHRpb25zLnJlc291cmNlcykge1xyXG4gICAgICB0cnkge1xyXG4gICAgICAgIC8vIExvYWQgdGhlIGRlZmF1bHQgb25lXHJcbiAgICAgICAgY3VzdG9tTG9naWNPcHRpb25zLnJlc291cmNlcyA9IF9oYW5kbGVSZXNvdXJjZXMoXHJcbiAgICAgICAgICByZWFkRmlsZVN5bmMoZ2V0QWJzb2x1dGVQYXRoKCdyZXNvdXJjZXMuanNvbicpLCAndXRmOCcpLFxyXG4gICAgICAgICAgY3VzdG9tTG9naWNPcHRpb25zLmFsbG93RmlsZVJlc291cmNlcyxcclxuICAgICAgICAgIHRydWVcclxuICAgICAgICApO1xyXG4gICAgICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgICAgIGxvZygyLCAnW2NoYXJ0XSBVbmFibGUgdG8gbG9hZCB0aGUgZGVmYXVsdCBgcmVzb3VyY2VzLmpzb25gIGZpbGUuJyk7XHJcbiAgICAgIH1cclxuICAgIH1cclxuXHJcbiAgICAvLyBQcm9jZXNzIHRoZSBgY3VzdG9tQ29kZWAgb3B0aW9uXHJcbiAgICB0cnkge1xyXG4gICAgICAvLyBUcnkgdG8gbG9hZCBjdXN0b20gY29kZSBhbmQgd3JhcCBhcm91bmQgaXQgaW4gYSBzZWxmIGludm9raW5nIGZ1bmN0aW9uXHJcbiAgICAgIGN1c3RvbUxvZ2ljT3B0aW9ucy5jdXN0b21Db2RlID0gd3JhcEFyb3VuZChcclxuICAgICAgICBjdXN0b21Mb2dpY09wdGlvbnMuY3VzdG9tQ29kZSxcclxuICAgICAgICBjdXN0b21Mb2dpY09wdGlvbnMuYWxsb3dGaWxlUmVzb3VyY2VzXHJcbiAgICAgICk7XHJcbiAgICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgICBsb2dXaXRoU3RhY2soMiwgZXJyb3IsICdbY2hhcnRdIFRoZSBgY3VzdG9tQ29kZWAgY2Fubm90IGJlIGxvYWRlZC4nKTtcclxuXHJcbiAgICAgIC8vIEluIGNhc2Ugb2YgYW4gZXJyb3IsIHNldCB0aGUgb3B0aW9uIHdpdGggbnVsbFxyXG4gICAgICBjdXN0b21Mb2dpY09wdGlvbnMuY3VzdG9tQ29kZSA9IG51bGw7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gUHJvY2VzcyB0aGUgYGNhbGxiYWNrYCBvcHRpb25cclxuICAgIHRyeSB7XHJcbiAgICAgIC8vIFRyeSB0byBsb2FkIGNhbGxiYWNrIGZ1bmN0aW9uXHJcbiAgICAgIGN1c3RvbUxvZ2ljT3B0aW9ucy5jYWxsYmFjayA9IHdyYXBBcm91bmQoXHJcbiAgICAgICAgY3VzdG9tTG9naWNPcHRpb25zLmNhbGxiYWNrLFxyXG4gICAgICAgIGN1c3RvbUxvZ2ljT3B0aW9ucy5hbGxvd0ZpbGVSZXNvdXJjZXMsXHJcbiAgICAgICAgdHJ1ZVxyXG4gICAgICApO1xyXG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICAgbG9nV2l0aFN0YWNrKDIsIGVycm9yLCAnW2NoYXJ0XSBUaGUgYGNhbGxiYWNrYCBjYW5ub3QgYmUgbG9hZGVkLicpO1xyXG5cclxuICAgICAgLy8gSW4gY2FzZSBvZiBhbiBlcnJvciwgc2V0IHRoZSBvcHRpb24gd2l0aCBudWxsXHJcbiAgICAgIGN1c3RvbUxvZ2ljT3B0aW9ucy5jYWxsYmFjayA9IG51bGw7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gQ2hlY2sgaWYgdGhlcmUgaXMgdGhlIGBjdXN0b21Db2RlYCBwcmVzZW50XHJcbiAgICBpZiAoW251bGwsIHVuZGVmaW5lZF0uaW5jbHVkZXMoY3VzdG9tTG9naWNPcHRpb25zLmN1c3RvbUNvZGUpKSB7XHJcbiAgICAgIGxvZygzLCAnW2NoYXJ0XSBObyB2YWx1ZSBmb3IgdGhlIGBjdXN0b21Db2RlYCBvcHRpb24gZm91bmQuJyk7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gQ2hlY2sgaWYgdGhlcmUgaXMgdGhlIGBjYWxsYmFja2AgcHJlc2VudFxyXG4gICAgaWYgKFtudWxsLCB1bmRlZmluZWRdLmluY2x1ZGVzKGN1c3RvbUxvZ2ljT3B0aW9ucy5jYWxsYmFjaykpIHtcclxuICAgICAgbG9nKDMsICdbY2hhcnRdIE5vIHZhbHVlIGZvciB0aGUgYGNhbGxiYWNrYCBvcHRpb24gZm91bmQuJyk7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gQ2hlY2sgaWYgdGhlcmUgaXMgdGhlIGByZXNvdXJjZXNgIHByZXNlbnRcclxuICAgIGlmIChbbnVsbCwgdW5kZWZpbmVkXS5pbmNsdWRlcyhjdXN0b21Mb2dpY09wdGlvbnMucmVzb3VyY2VzKSkge1xyXG4gICAgICBsb2coMywgJ1tjaGFydF0gTm8gdmFsdWUgZm9yIHRoZSBgcmVzb3VyY2VzYCBvcHRpb24gZm91bmQuJyk7XHJcbiAgICB9XHJcbiAgfSBlbHNlIHtcclxuICAgIC8vIElmIHRoZSBgYWxsb3dDb2RlRXhlY3V0aW9uYCBmbGFnIGlzIHNldCB0byBmYWxzZSwgd2Ugc2hvdWxkIHJlZnVzZVxyXG4gICAgLy8gdGhlIHVzYWdlIG9mIHRoZSBgY2FsbGJhY2tgLCBgcmVzb3VyY2VzYCwgYW5kIGBjdXN0b21Db2RlYCBvcHRpb25zLlxyXG4gICAgLy8gQWRkaXRpb25hbGx5LCB0aGUgd29ya2VyIHdpbGwgcmVmdXNlIHRvIHJ1biBhcmJpdHJhcnkgSmF2YVNjcmlwdC5cclxuICAgIGlmIChcclxuICAgICAgY3VzdG9tTG9naWNPcHRpb25zLmNhbGxiYWNrIHx8XHJcbiAgICAgIGN1c3RvbUxvZ2ljT3B0aW9ucy5yZXNvdXJjZXMgfHxcclxuICAgICAgY3VzdG9tTG9naWNPcHRpb25zLmN1c3RvbUNvZGVcclxuICAgICkge1xyXG4gICAgICAvLyBSZXNldCBhbGwgY3VzdG9tIGNvZGUgb3B0aW9uc1xyXG4gICAgICBjdXN0b21Mb2dpY09wdGlvbnMuY2FsbGJhY2sgPSBudWxsO1xyXG4gICAgICBjdXN0b21Mb2dpY09wdGlvbnMucmVzb3VyY2VzID0gbnVsbDtcclxuICAgICAgY3VzdG9tTG9naWNPcHRpb25zLmN1c3RvbUNvZGUgPSBudWxsO1xyXG5cclxuICAgICAgLy8gU2VuZCBhIG1lc3NhZ2Ugc2F5aW5nIHRoYXQgdGhlIGV4cG9ydGVyIGRvZXMgbm90IHN1cHBvcnQgdGhlc2Ugc2V0dGluZ3NcclxuICAgICAgdGhyb3cgbmV3IEV4cG9ydEVycm9yKFxyXG4gICAgICAgIGBbY2hhcnRdIFRoZSAnY2FsbGJhY2snLCAncmVzb3VyY2VzJywgYW5kICdjdXN0b21Db2RlJyBvcHRpb25zIGhhdmUgYmVlbiBkaXNhYmxlZCBmb3IgdGhpcyBzZXJ2ZXIuYCxcclxuICAgICAgICA0MDNcclxuICAgICAgKTtcclxuICAgIH1cclxuICB9XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBIYW5kbGVzIGFuZCB2YWxpZGF0ZXMgcmVzb3VyY2VzIGZyb20gdGhlIGByZXNvdXJjZXNgIG9wdGlvbiBmb3IgZXhwb3J0LlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gX2hhbmRsZVJlc291cmNlc1xyXG4gKlxyXG4gKiBAcGFyYW0geyhPYmplY3R8c3RyaW5nfG51bGwpfSBbcmVzb3VyY2VzPW51bGxdIC0gVGhlIHJlc291cmNlcyB0byBiZSBoYW5kbGVkLlxyXG4gKiBDYW4gYmUgZWl0aGVyIGEgSlNPTiBvYmplY3QsIHN0cmluZ2lmaWVkIEpTT04sIGEgcGF0aCB0byBhIEpTT04gZmlsZSxcclxuICogb3IgbnVsbC4gVGhlIGRlZmF1bHQgdmFsdWUgaXMgbnVsbC5cclxuICogQHBhcmFtIHtib29sZWFufSBhbGxvd0ZpbGVSZXNvdXJjZXMgLSBBIGZsYWcgaW5kaWNhdGluZyB3aGV0aGVyIGxvYWRpbmdcclxuICogcmVzb3VyY2VzIGZyb20gZmlsZXMgaXMgYWxsb3dlZC5cclxuICogQHBhcmFtIHtib29sZWFufSBhbGxvd0NvZGVFeGVjdXRpb24gLSBBIGZsYWcgaW5kaWNhdGluZyB3aGV0aGVyIGNvZGVcclxuICogZXhlY3V0aW9uIGlzIGFsbG93ZWQuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHsoT2JqZWN0fG51bGwpfSBUaGUgaGFuZGxlZCByZXNvdXJjZXMgb3IgbnVsbCBpZiBubyB2YWxpZCByZXNvdXJjZXNcclxuICogYXJlIGZvdW5kLlxyXG4gKi9cclxuZnVuY3Rpb24gX2hhbmRsZVJlc291cmNlcyhcclxuICByZXNvdXJjZXMgPSBudWxsLFxyXG4gIGFsbG93RmlsZVJlc291cmNlcyxcclxuICBhbGxvd0NvZGVFeGVjdXRpb25cclxuKSB7XHJcbiAgLy8gTGlzdCBvZiBhbGxvd2VkIHNlY3Rpb25zIGluIHRoZSByZXNvdXJjZXMgSlNPTlxyXG4gIGNvbnN0IGFsbG93ZWRQcm9wcyA9IFsnanMnLCAnY3NzJywgJ2ZpbGVzJ107XHJcblxyXG4gIGxldCBoYW5kbGVkUmVzb3VyY2VzID0gcmVzb3VyY2VzO1xyXG4gIGxldCBjb3JyZWN0UmVzb3VyY2VzID0gZmFsc2U7XHJcblxyXG4gIC8vIFRyeSB0byBsb2FkIHJlc291cmNlcyBmcm9tIGEgZmlsZVxyXG4gIGlmIChhbGxvd0ZpbGVSZXNvdXJjZXMgJiYgcmVzb3VyY2VzLmVuZHNXaXRoKCcuanNvbicpKSB7XHJcbiAgICB0cnkge1xyXG4gICAgICBoYW5kbGVkUmVzb3VyY2VzID0gaXNBbGxvd2VkQ29uZmlnKFxyXG4gICAgICAgIHJlYWRGaWxlU3luYyhnZXRBYnNvbHV0ZVBhdGgocmVzb3VyY2VzKSwgJ3V0ZjgnKSxcclxuICAgICAgICBmYWxzZSxcclxuICAgICAgICBhbGxvd0NvZGVFeGVjdXRpb25cclxuICAgICAgKTtcclxuICAgIH0gY2F0Y2gge1xyXG4gICAgICByZXR1cm4gbnVsbDtcclxuICAgIH1cclxuICB9IGVsc2Uge1xyXG4gICAgLy8gVHJ5IHRvIGdldCBKU09OXHJcbiAgICBoYW5kbGVkUmVzb3VyY2VzID0gaXNBbGxvd2VkQ29uZmlnKHJlc291cmNlcywgZmFsc2UsIGFsbG93Q29kZUV4ZWN1dGlvbik7XHJcblxyXG4gICAgLy8gR2V0IHJpZCBvZiB0aGUgZmlsZXMgc2VjdGlvblxyXG4gICAgaWYgKGhhbmRsZWRSZXNvdXJjZXMgJiYgIWFsbG93RmlsZVJlc291cmNlcykge1xyXG4gICAgICBkZWxldGUgaGFuZGxlZFJlc291cmNlcy5maWxlcztcclxuICAgIH1cclxuICB9XHJcblxyXG4gIC8vIEZpbHRlciBmcm9tIHVubmVjZXNzYXJ5IHByb3BlcnRpZXNcclxuICBmb3IgKGNvbnN0IHByb3BOYW1lIGluIGhhbmRsZWRSZXNvdXJjZXMpIHtcclxuICAgIGlmICghYWxsb3dlZFByb3BzLmluY2x1ZGVzKHByb3BOYW1lKSkge1xyXG4gICAgICBkZWxldGUgaGFuZGxlZFJlc291cmNlc1twcm9wTmFtZV07XHJcbiAgICB9IGVsc2UgaWYgKCFjb3JyZWN0UmVzb3VyY2VzKSB7XHJcbiAgICAgIGNvcnJlY3RSZXNvdXJjZXMgPSB0cnVlO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgLy8gQ2hlY2sgaWYgYXQgbGVhc3Qgb25lIG9mIGFsbG93ZWQgcHJvcGVydGllcyBpcyBwcmVzZW50XHJcbiAgaWYgKCFjb3JyZWN0UmVzb3VyY2VzKSB7XHJcbiAgICByZXR1cm4gbnVsbDtcclxuICB9XHJcblxyXG4gIC8vIEhhbmRsZSBmaWxlcyBzZWN0aW9uXHJcbiAgaWYgKGhhbmRsZWRSZXNvdXJjZXMuZmlsZXMpIHtcclxuICAgIGhhbmRsZWRSZXNvdXJjZXMuZmlsZXMgPSBoYW5kbGVkUmVzb3VyY2VzLmZpbGVzLm1hcCgoaXRlbSkgPT4gaXRlbS50cmltKCkpO1xyXG4gICAgaWYgKCFoYW5kbGVkUmVzb3VyY2VzLmZpbGVzIHx8IGhhbmRsZWRSZXNvdXJjZXMuZmlsZXMubGVuZ3RoIDw9IDApIHtcclxuICAgICAgZGVsZXRlIGhhbmRsZWRSZXNvdXJjZXMuZmlsZXM7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICAvLyBSZXR1cm4gcmVzb3VyY2VzXHJcbiAgcmV0dXJuIGhhbmRsZWRSZXNvdXJjZXM7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBIYW5kbGVzIHRoZSBsb2FkaW5nIGFuZCB2YWxpZGF0aW9uIG9mIHRoZSBgZ2xvYmFsT3B0aW9uc2AgYW5kIGB0aGVtZU9wdGlvbnNgXHJcbiAqIGluIHRoZSBleHBvcnQgb3B0aW9ucy4gSWYgdGhlIG9wdGlvbiBpcyBhIHN0cmluZyBhbmQgcmVmZXJlbmNlcyBhIEpTT04gZmlsZVxyXG4gKiAod2hlbiB0aGUgYGFsbG93RmlsZVJlc291cmNlc2AgaXMgdHJ1ZSksIGl0IHJlYWRzIGFuZCBwYXJzZXMgdGhlIGZpbGUuXHJcbiAqIE90aGVyd2lzZSwgaXQgYXR0ZW1wdHMgdG8gcGFyc2UgdGhlIHN0cmluZyBvciBvYmplY3QgYXMgSlNPTi4gSWYgYW55IGVycm9yc1xyXG4gKiBvY2N1ciBkdXJpbmcgdGhpcyBwcm9jZXNzLCB0aGUgb3B0aW9uIGlzIHNldCB0byBudWxsLiBJZiB0aGVyZSBpcyBhbiBlcnJvclxyXG4gKiBsb2FkaW5nIG9yIHBhcnNpbmcgdGhlIGBnbG9iYWxPcHRpb25zYCBvciBgdGhlbWVPcHRpb25zYCwgdGhlIGVycm9yIGlzIGxvZ2dlZFxyXG4gKiBhbmQgdGhlIG9wdGlvbiBpcyBzZXQgdG8gbnVsbC5cclxuICpcclxuICogQGZ1bmN0aW9uIF9oYW5kbGVHbG9iYWxBbmRUaGVtZVxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gZXhwb3J0T3B0aW9ucyAtIFRoZSBvYmplY3QgY29udGFpbmluZyBgZXhwb3J0YCBvcHRpb25zLlxyXG4gKiBAcGFyYW0ge2Jvb2xlYW59IGFsbG93RmlsZVJlc291cmNlcyAtIEEgZmxhZyBpbmRpY2F0aW5nIHdoZXRoZXIgbG9hZGluZ1xyXG4gKiByZXNvdXJjZXMgZnJvbSBmaWxlcyBpcyBhbGxvd2VkLlxyXG4gKiBAcGFyYW0ge2Jvb2xlYW59IGFsbG93Q29kZUV4ZWN1dGlvbiAtIEEgZmxhZyBpbmRpY2F0aW5nIHdoZXRoZXIgY29kZVxyXG4gKiBleGVjdXRpb24gaXMgYWxsb3dlZC5cclxuICovXHJcbmZ1bmN0aW9uIF9oYW5kbGVHbG9iYWxBbmRUaGVtZShcclxuICBleHBvcnRPcHRpb25zLFxyXG4gIGFsbG93RmlsZVJlc291cmNlcyxcclxuICBhbGxvd0NvZGVFeGVjdXRpb25cclxuKSB7XHJcbiAgLy8gQ2hlY2sgdGhlIGBnbG9iYWxPcHRpb25zYCBhbmQgYHRoZW1lT3B0aW9uc2Agb3B0aW9uc1xyXG4gIFsnZ2xvYmFsT3B0aW9ucycsICd0aGVtZU9wdGlvbnMnXS5mb3JFYWNoKChvcHRpb25zTmFtZSkgPT4ge1xyXG4gICAgdHJ5IHtcclxuICAgICAgLy8gQ2hlY2sgaWYgdGhlIG9wdGlvbiBleGlzdHNcclxuICAgICAgaWYgKGV4cG9ydE9wdGlvbnNbb3B0aW9uc05hbWVdKSB7XHJcbiAgICAgICAgLy8gQ2hlY2sgaWYgaXQgaXMgYSBzdHJpbmcgYW5kIGEgZmlsZSBuYW1lIHdpdGggdGhlIGAuanNvbmAgZXh0ZW5zaW9uXHJcbiAgICAgICAgaWYgKFxyXG4gICAgICAgICAgYWxsb3dGaWxlUmVzb3VyY2VzICYmXHJcbiAgICAgICAgICB0eXBlb2YgZXhwb3J0T3B0aW9uc1tvcHRpb25zTmFtZV0gPT09ICdzdHJpbmcnICYmXHJcbiAgICAgICAgICBleHBvcnRPcHRpb25zW29wdGlvbnNOYW1lXS5lbmRzV2l0aCgnLmpzb24nKVxyXG4gICAgICAgICkge1xyXG4gICAgICAgICAgLy8gQ2hlY2sgaWYgdGhlIGZpbGUgY29udGVudCBjYW4gYmUgYSBjb25maWcsIGFuZCBzYXZlIGl0IGFzIGEgc3RyaW5nXHJcbiAgICAgICAgICBleHBvcnRPcHRpb25zW29wdGlvbnNOYW1lXSA9IGlzQWxsb3dlZENvbmZpZyhcclxuICAgICAgICAgICAgcmVhZEZpbGVTeW5jKGdldEFic29sdXRlUGF0aChleHBvcnRPcHRpb25zW29wdGlvbnNOYW1lXSksICd1dGY4JyksXHJcbiAgICAgICAgICAgIHRydWUsXHJcbiAgICAgICAgICAgIGFsbG93Q29kZUV4ZWN1dGlvblxyXG4gICAgICAgICAgKTtcclxuICAgICAgICB9IGVsc2Uge1xyXG4gICAgICAgICAgLy8gQ2hlY2sgaWYgdGhlIHZhbHVlIGNhbiBiZSBhIGNvbmZpZywgYW5kIHNhdmUgaXQgYXMgYSBzdHJpbmdcclxuICAgICAgICAgIGV4cG9ydE9wdGlvbnNbb3B0aW9uc05hbWVdID0gaXNBbGxvd2VkQ29uZmlnKFxyXG4gICAgICAgICAgICBleHBvcnRPcHRpb25zW29wdGlvbnNOYW1lXSxcclxuICAgICAgICAgICAgdHJ1ZSxcclxuICAgICAgICAgICAgYWxsb3dDb2RlRXhlY3V0aW9uXHJcbiAgICAgICAgICApO1xyXG4gICAgICAgIH1cclxuICAgICAgfVxyXG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICAgbG9nV2l0aFN0YWNrKFxyXG4gICAgICAgIDIsXHJcbiAgICAgICAgZXJyb3IsXHJcbiAgICAgICAgYFtjaGFydF0gVGhlIFxcYCR7b3B0aW9uc05hbWV9XFxgIGNhbm5vdCBiZSBsb2FkZWQuYFxyXG4gICAgICApO1xyXG5cclxuICAgICAgLy8gSW4gY2FzZSBvZiBhbiBlcnJvciwgc2V0IHRoZSBvcHRpb24gd2l0aCBudWxsXHJcbiAgICAgIGV4cG9ydE9wdGlvbnNbb3B0aW9uc05hbWVdID0gbnVsbDtcclxuICAgIH1cclxuICB9KTtcclxuXHJcbiAgLy8gQ2hlY2sgaWYgdGhlcmUgaXMgdGhlIGBnbG9iYWxPcHRpb25zYCBwcmVzZW50XHJcbiAgaWYgKFtudWxsLCB1bmRlZmluZWRdLmluY2x1ZGVzKGV4cG9ydE9wdGlvbnMuZ2xvYmFsT3B0aW9ucykpIHtcclxuICAgIGxvZygzLCAnW2NoYXJ0XSBObyB2YWx1ZSBmb3IgdGhlIGBnbG9iYWxPcHRpb25zYCBvcHRpb24gZm91bmQuJyk7XHJcbiAgfVxyXG5cclxuICAvLyBDaGVjayBpZiB0aGVyZSBpcyB0aGUgYHRoZW1lT3B0aW9uc2AgcHJlc2VudFxyXG4gIGlmIChbbnVsbCwgdW5kZWZpbmVkXS5pbmNsdWRlcyhleHBvcnRPcHRpb25zLnRoZW1lT3B0aW9ucykpIHtcclxuICAgIGxvZygzLCAnW2NoYXJ0XSBObyB2YWx1ZSBmb3IgdGhlIGB0aGVtZU9wdGlvbnNgIG9wdGlvbiBmb3VuZC4nKTtcclxuICB9XHJcbn1cclxuXHJcbmV4cG9ydCBkZWZhdWx0IHtcclxuICBzdGFydEV4cG9ydCxcclxuICBzaW5nbGVFeHBvcnQsXHJcbiAgYmF0Y2hFeHBvcnQsXHJcbiAgZ2V0QWxsb3dDb2RlRXhlY3V0aW9uLFxyXG4gIHNldEFsbG93Q29kZUV4ZWN1dGlvblxyXG59O1xyXG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxyXG5cclxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXHJcblxyXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNSwgSGlnaHNvZnRcclxuXHJcbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cclxuXHJcbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxyXG5cclxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxyXG5cclxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cclxuXHJcbi8qKlxyXG4gKiBAb3ZlcnZpZXcgVGhpcyBtb2R1bGUgcHJvdmlkZXMgdXRpbGl0eSBmdW5jdGlvbnMgZm9yIG1hbmFnaW5nIGludGVydmFsc1xyXG4gKiBhbmQgdGltZW91dHMgaW4gYSBjZW50cmFsaXplZCBtYW5uZXIuIEl0IG1haW50YWlucyBhIHJlZ2lzdHJ5IG9mIGFsbCBhY3RpdmVcclxuICogdGltZXJzIGFuZCBhbGxvd3MgZm9yIHRoZWlyIGVmZmljaWVudCBjbGVhbnVwIHdoZW4gbmVlZGVkLiBUaGlzIGNhbiBiZSB1c2VmdWxcclxuICogaW4gYXBwbGljYXRpb25zIHdoZXJlIHByb3BlciByZXNvdXJjZSBtYW5hZ2VtZW50IGFuZCBjbGVhbiBzaHV0ZG93biBvZiB0aW1lcnNcclxuICogYXJlIGNyaXRpY2FsIHRvIGF2b2lkIG1lbW9yeSBsZWFrcyBvciB1bmludGVuZGVkIGJlaGF2aW9yLlxyXG4gKi9cclxuXHJcbmltcG9ydCB7IGxvZyB9IGZyb20gJy4vbG9nZ2VyLmpzJztcclxuXHJcbi8vIEFycmF5IHRoYXQgY29udGFpbnMgaWRzIG9mIGFsbCBvbmdvaW5nIGludGVydmFscyBhbmQgdGltZW91dHNcclxuY29uc3QgdGltZXJJZHMgPSBbXTtcclxuXHJcbi8qKlxyXG4gKiBBZGRzIGlkIG9mIHRoZSBgc2V0SW50ZXJ2YWxgIG9yIGBzZXRUaW1lb3V0YCBhbmQgdG8gdGhlIGB0aW1lcklkc2AgYXJyYXkuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBhZGRUaW1lclxyXG4gKlxyXG4gKiBAcGFyYW0ge05vZGVKUy5UaW1lb3V0fSBpZCAtIElkIG9mIGFuIGludGVydmFsIG9yIGEgdGltZW91dC5cclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiBhZGRUaW1lcihpZCkge1xyXG4gIHRpbWVySWRzLnB1c2goaWQpO1xyXG59XHJcblxyXG4vKipcclxuICogQ2xlYXJzIGFsbCBvZiBvbmdvaW5nIGludGVydmFscyBhbmQgdGltZW91dHMgYnkgaWRzIGdhdGhlcmVkXHJcbiAqIGluIHRoZSBgdGltZXJJZHNgIGFycmF5LlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gY2xlYXJBbGxUaW1lcnNcclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiBjbGVhckFsbFRpbWVycygpIHtcclxuICBsb2coNCwgYFt0aW1lcl0gQ2xlYXJpbmcgYWxsIHJlZ2lzdGVyZWQgaW50ZXJ2YWxzIGFuZCB0aW1lb3V0cy5gKTtcclxuICBmb3IgKGNvbnN0IGlkIG9mIHRpbWVySWRzKSB7XHJcbiAgICBjbGVhckludGVydmFsKGlkKTtcclxuICAgIGNsZWFyVGltZW91dChpZCk7XHJcbiAgfVxyXG59XHJcblxyXG5leHBvcnQgZGVmYXVsdCB7XHJcbiAgYWRkVGltZXIsXHJcbiAgY2xlYXJBbGxUaW1lcnNcclxufTtcclxuIiwiLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcclxuXHJcbkhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlclxyXG5cclxuQ29weXJpZ2h0IChjKSAyMDE2LTIwMjUsIEhpZ2hzb2Z0XHJcblxyXG5MaWNlbmNlZCB1bmRlciB0aGUgTUlUIGxpY2VuY2UuXHJcblxyXG5BZGRpdGlvbmFsbHkgYSB2YWxpZCBIaWdoY2hhcnRzIGxpY2Vuc2UgaXMgcmVxdWlyZWQgZm9yIHVzZS5cclxuXHJcblNlZSBMSUNFTlNFIGZpbGUgaW4gcm9vdCBmb3IgZGV0YWlscy5cclxuXHJcbioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXHJcblxyXG4vKipcclxuICogQG92ZXJ2aWV3IFByb3ZpZGVzIG1pZGRsZXdhcmUgZnVuY3Rpb25zIGZvciBsb2dnaW5nIGVycm9ycyB3aXRoIHN0YWNrIHRyYWNlc1xyXG4gKiBhbmQgaGFuZGxpbmcgZXJyb3IgcmVzcG9uc2VzIGluIGFuIEV4cHJlc3MgYXBwbGljYXRpb24uXHJcbiAqL1xyXG5cclxuaW1wb3J0IHsgZ2V0T3B0aW9ucyB9IGZyb20gJy4uLy4uL2NvbmZpZy5qcyc7XHJcbmltcG9ydCB7IGxvZ1dpdGhTdGFjayB9IGZyb20gJy4uLy4uL2xvZ2dlci5qcyc7XHJcblxyXG4vKipcclxuICogTWlkZGxld2FyZSBmb3IgbG9nZ2luZyBlcnJvcnMgd2l0aCBzdGFjayB0cmFjZSBhbmQgaGFuZGxpbmcgZXJyb3IgcmVzcG9uc2UuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBsb2dFcnJvck1pZGRsZXdhcmVcclxuICpcclxuICogQHBhcmFtIHtFcnJvcn0gZXJyb3IgLSBUaGUgZXJyb3Igb2JqZWN0LlxyXG4gKiBAcGFyYW0ge0V4cHJlc3MuUmVxdWVzdH0gcmVxdWVzdCAtIFRoZSBFeHByZXNzIHJlcXVlc3Qgb2JqZWN0LlxyXG4gKiBAcGFyYW0ge0V4cHJlc3MuUmVzcG9uc2V9IHJlc3BvbnNlIC0gVGhlIEV4cHJlc3MgcmVzcG9uc2Ugb2JqZWN0LlxyXG4gKiBAcGFyYW0ge0Z1bmN0aW9ufSBuZXh0IC0gVGhlIG5leHQgbWlkZGxld2FyZSBmdW5jdGlvbi5cclxuICpcclxuICogQHJldHVybnMge3VuZGVmaW5lZH0gVGhlIGNhbGwgdG8gdGhlIG5leHQgbWlkZGxld2FyZSBmdW5jdGlvbiB3aXRoXHJcbiAqIHRoZSBwYXNzZWQgZXJyb3IuXHJcbiAqL1xyXG5mdW5jdGlvbiBsb2dFcnJvck1pZGRsZXdhcmUoZXJyb3IsIHJlcXVlc3QsIHJlc3BvbnNlLCBuZXh0KSB7XHJcbiAgLy8gRGlzcGxheSB0aGUgZXJyb3Igd2l0aCBzdGFjayBpbiBhIGNvcnJlY3QgZm9ybWF0XHJcbiAgbG9nV2l0aFN0YWNrKDEsIGVycm9yKTtcclxuXHJcbiAgLy8gRGVsZXRlIHRoZSBzdGFjayBmb3IgdGhlIGVudmlyb25tZW50IG90aGVyIHRoYW4gdGhlIGRldmVsb3BtZW50XHJcbiAgaWYgKGdldE9wdGlvbnMoKS5vdGhlci5ub2RlRW52ICE9PSAnZGV2ZWxvcG1lbnQnKSB7XHJcbiAgICBkZWxldGUgZXJyb3Iuc3RhY2s7XHJcbiAgfVxyXG5cclxuICAvLyBDYWxsIHRoZSBgcmV0dXJuRXJyb3JNaWRkbGV3YXJlYCBtaWRkbGV3YXJlXHJcbiAgcmV0dXJuIG5leHQoZXJyb3IpO1xyXG59XHJcblxyXG4vKipcclxuICogTWlkZGxld2FyZSBmb3IgcmV0dXJuaW5nIGVycm9yIHJlc3BvbnNlLlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gcmV0dXJuRXJyb3JNaWRkbGV3YXJlXHJcbiAqXHJcbiAqIEBwYXJhbSB7RXJyb3J9IGVycm9yIC0gVGhlIGVycm9yIG9iamVjdC5cclxuICogQHBhcmFtIHtFeHByZXNzLlJlcXVlc3R9IHJlcXVlc3QgLSBUaGUgRXhwcmVzcyByZXF1ZXN0IG9iamVjdC5cclxuICogQHBhcmFtIHtFeHByZXNzLlJlc3BvbnNlfSByZXNwb25zZSAtIFRoZSBFeHByZXNzIHJlc3BvbnNlIG9iamVjdC5cclxuICogQHBhcmFtIHtGdW5jdGlvbn0gbmV4dCAtIFRoZSBuZXh0IG1pZGRsZXdhcmUgZnVuY3Rpb24uXHJcbiAqL1xyXG5mdW5jdGlvbiByZXR1cm5FcnJvck1pZGRsZXdhcmUoZXJyb3IsIHJlcXVlc3QsIHJlc3BvbnNlLCBuZXh0KSB7XHJcbiAgLy8gR2F0aGVyIGFsbCByZXF1aWVkIGluZm9ybWF0aW9uIGZvciB0aGUgcmVzcG9uc2VcclxuICBjb25zdCB7IG1lc3NhZ2UsIHN0YWNrIH0gPSBlcnJvcjtcclxuXHJcbiAgLy8gVXNlIHRoZSBlcnJvcidzIHN0YXR1cyBjb2RlIG9yIHRoZSBkZWZhdWx0IDQwMFxyXG4gIGNvbnN0IHN0YXR1c0NvZGUgPSBlcnJvci5zdGF0dXNDb2RlIHx8IDQwMDtcclxuXHJcbiAgLy8gU2V0IGFuZCByZXR1cm4gcmVzcG9uc2VcclxuICByZXNwb25zZS5zdGF0dXMoc3RhdHVzQ29kZSkuanNvbih7IHN0YXR1c0NvZGUsIG1lc3NhZ2UsIHN0YWNrIH0pO1xyXG59XHJcblxyXG4vKipcclxuICogQWRkcyB0aGUgZXJyb3IgbWlkZGxld2FyZXMgdG8gdGhlIHBhc3NlZCBleHByZXNzIGFwcCBpbnN0YW5jZS5cclxuICpcclxuICogQHBhcmFtIHtFeHByZXNzfSBhcHAgLSBUaGUgRXhwcmVzcyBhcHAgaW5zdGFuY2UuXHJcbiAqL1xyXG5leHBvcnQgZGVmYXVsdCBmdW5jdGlvbiBlcnJvck1pZGRsZXdhcmUoYXBwKSB7XHJcbiAgLy8gQWRkIGxvZyBlcnJvciBtaWRkbGV3YXJlXHJcbiAgYXBwLnVzZShsb2dFcnJvck1pZGRsZXdhcmUpO1xyXG5cclxuICAvLyBBZGQgc2V0IHN0YXR1cyBhbmQgcmV0dXJuIGVycm9yIG1pZGRsZXdhcmVcclxuICBhcHAudXNlKHJldHVybkVycm9yTWlkZGxld2FyZSk7XHJcbn1cclxuIiwiLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcclxuXHJcbkhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlclxyXG5cclxuQ29weXJpZ2h0IChjKSAyMDE2LTIwMjUsIEhpZ2hzb2Z0XHJcblxyXG5MaWNlbmNlZCB1bmRlciB0aGUgTUlUIGxpY2VuY2UuXHJcblxyXG5BZGRpdGlvbmFsbHkgYSB2YWxpZCBIaWdoY2hhcnRzIGxpY2Vuc2UgaXMgcmVxdWlyZWQgZm9yIHVzZS5cclxuXHJcblNlZSBMSUNFTlNFIGZpbGUgaW4gcm9vdCBmb3IgZGV0YWlscy5cclxuXHJcbioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXHJcblxyXG4vKipcclxuICogQG92ZXJ2aWV3IFByb3ZpZGVzIG1pZGRsZXdhcmUgZnVuY3Rpb25zIGZvciBjb25maWd1cmluZyBhbmQgZW5hYmxpbmcgcmF0ZVxyXG4gKiBsaW1pdGluZyBpbiBhbiBFeHByZXNzIGFwcGxpY2F0aW9uLlxyXG4gKi9cclxuXHJcbmltcG9ydCByYXRlTGltaXQgZnJvbSAnZXhwcmVzcy1yYXRlLWxpbWl0JztcclxuXHJcbmltcG9ydCB7IGdldE9wdGlvbnMgfSBmcm9tICcuLi8uLi9jb25maWcuanMnO1xyXG5pbXBvcnQgeyBsb2cgfSBmcm9tICcuLi8uLi9sb2dnZXIuanMnO1xyXG5cclxuaW1wb3J0IEV4cG9ydEVycm9yIGZyb20gJy4uLy4uL2Vycm9ycy9FeHBvcnRFcnJvci5qcyc7XHJcblxyXG4vKipcclxuICogTWlkZGxld2FyZSBmb3IgZW5hYmxpbmcgcmF0ZSBsaW1pdGluZyBvbiB0aGUgc3BlY2lmaWVkIEV4cHJlc3MgYXBwLlxyXG4gKlxyXG4gKiBAcGFyYW0ge0V4cHJlc3N9IGFwcCAtIFRoZSBFeHByZXNzIGFwcCBpbnN0YW5jZS5cclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IFtyYXRlTGltaXRpbmdPcHRpb25zPWdldE9wdGlvbnMoKS5zZXJ2ZXIucmF0ZUxpbWl0aW5nXSAtXHJcbiAqIE9iamVjdCBjb250YWluaW5nIGByYXRlTGltaXRpbmdgIG9wdGlvbnMuIFRoZSBkZWZhdWx0IHZhbHVlIGlzIHRoZSBnbG9iYWxcclxuICogcmF0ZSBsaW1pdGluZyBvcHRpb25zIG9mIHRoZSBleHBvcnQgc2VydmVyIGluc3RhbmNlLlxyXG4gKlxyXG4gKiBAdGhyb3dzIHtFeHBvcnRFcnJvcn0gVGhyb3dzIGFuIGBFeHBvcnRFcnJvcmAgaWYgY291bGQgbm90IGNvbmZpZ3VyZSBhbmQgc2V0XHJcbiAqIHRoZSByYXRlIGxpbWl0aW5nIG9wdGlvbnMuXHJcbiAqL1xyXG5leHBvcnQgZGVmYXVsdCBmdW5jdGlvbiByYXRlTGltaXRpbmdNaWRkbGV3YXJlKFxyXG4gIGFwcCxcclxuICByYXRlTGltaXRpbmdPcHRpb25zID0gZ2V0T3B0aW9ucygpLnNlcnZlci5yYXRlTGltaXRpbmdcclxuKSB7XHJcbiAgdHJ5IHtcclxuICAgIC8vIENoZWNrIGlmIHRoZSByYXRlIGxpbWl0aW5nIGlzIGVuYWJsZWRcclxuICAgIGlmIChyYXRlTGltaXRpbmdPcHRpb25zLmVuYWJsZSkge1xyXG4gICAgICBjb25zdCBtc2cgPVxyXG4gICAgICAgICdUb28gbWFueSByZXF1ZXN0cywgeW91IGhhdmUgYmVlbiByYXRlIGxpbWl0ZWQuIFBsZWFzZSB0cnkgYWdhaW4gbGF0ZXIuJztcclxuXHJcbiAgICAgIC8vIE9wdGlvbnMgZm9yIHRoZSByYXRlIGxpbWl0ZXJcclxuICAgICAgY29uc3QgcmF0ZU9wdGlvbnMgPSB7XHJcbiAgICAgICAgbWF4OiByYXRlTGltaXRpbmdPcHRpb25zLm1heFJlcXVlc3RzIHx8IDMwLFxyXG4gICAgICAgIHdpbmRvdzogcmF0ZUxpbWl0aW5nT3B0aW9ucy53aW5kb3cgfHwgMSxcclxuICAgICAgICBkZWxheTogcmF0ZUxpbWl0aW5nT3B0aW9ucy5kZWxheSB8fCAwLFxyXG4gICAgICAgIHRydXN0UHJveHk6IHJhdGVMaW1pdGluZ09wdGlvbnMudHJ1c3RQcm94eSB8fCBmYWxzZSxcclxuICAgICAgICBza2lwS2V5OiByYXRlTGltaXRpbmdPcHRpb25zLnNraXBLZXkgfHwgZmFsc2UsXHJcbiAgICAgICAgc2tpcFRva2VuOiByYXRlTGltaXRpbmdPcHRpb25zLnNraXBUb2tlbiB8fCBmYWxzZVxyXG4gICAgICB9O1xyXG5cclxuICAgICAgLy8gU2V0IGlmIGJlaGluZCBhIHByb3h5XHJcbiAgICAgIGlmIChyYXRlT3B0aW9ucy50cnVzdFByb3h5KSB7XHJcbiAgICAgICAgYXBwLmVuYWJsZSgndHJ1c3QgcHJveHknKTtcclxuICAgICAgfVxyXG5cclxuICAgICAgLy8gQ3JlYXRlIGEgbGltaXRlclxyXG4gICAgICBjb25zdCBsaW1pdGVyID0gcmF0ZUxpbWl0KHtcclxuICAgICAgICB3aW5kb3dNczogcmF0ZU9wdGlvbnMud2luZG93ICogNjAgKiAxMDAwLFxyXG4gICAgICAgIC8vIExpbWl0IGVhY2ggSVAgdG8gMTAwIHJlcXVlc3RzIHBlciB3aW5kb3dNc1xyXG4gICAgICAgIG1heDogcmF0ZU9wdGlvbnMubWF4LFxyXG4gICAgICAgIC8vIERpc2FibGUgZGVsYXlpbmcsIGZ1bGwgc3BlZWQgdW50aWwgdGhlIG1heCBsaW1pdCBpcyByZWFjaGVkXHJcbiAgICAgICAgZGVsYXlNczogcmF0ZU9wdGlvbnMuZGVsYXksXHJcbiAgICAgICAgaGFuZGxlcjogKHJlcXVlc3QsIHJlc3BvbnNlKSA9PiB7XHJcbiAgICAgICAgICByZXNwb25zZS5mb3JtYXQoe1xyXG4gICAgICAgICAgICBqc29uOiAoKSA9PiB7XHJcbiAgICAgICAgICAgICAgcmVzcG9uc2Uuc3RhdHVzKDQyOSkuc2VuZCh7IG1lc3NhZ2U6IG1zZyB9KTtcclxuICAgICAgICAgICAgfSxcclxuICAgICAgICAgICAgZGVmYXVsdDogKCkgPT4ge1xyXG4gICAgICAgICAgICAgIHJlc3BvbnNlLnN0YXR1cyg0MjkpLnNlbmQobXNnKTtcclxuICAgICAgICAgICAgfVxyXG4gICAgICAgICAgfSk7XHJcbiAgICAgICAgfSxcclxuICAgICAgICBza2lwOiAocmVxdWVzdCkgPT4ge1xyXG4gICAgICAgICAgLy8gQWxsb3cgYnlwYXNzaW5nIHRoZSBsaW1pdGVyIGlmIGEgdmFsaWQga2V5L3Rva2VuIGhhcyBiZWVuIHNlbnRcclxuICAgICAgICAgIGlmIChcclxuICAgICAgICAgICAgcmF0ZU9wdGlvbnMuc2tpcEtleSAhPT0gZmFsc2UgJiZcclxuICAgICAgICAgICAgcmF0ZU9wdGlvbnMuc2tpcFRva2VuICE9PSBmYWxzZSAmJlxyXG4gICAgICAgICAgICByZXF1ZXN0LnF1ZXJ5LmtleSA9PT0gcmF0ZU9wdGlvbnMuc2tpcEtleSAmJlxyXG4gICAgICAgICAgICByZXF1ZXN0LnF1ZXJ5LmFjY2Vzc190b2tlbiA9PT0gcmF0ZU9wdGlvbnMuc2tpcFRva2VuXHJcbiAgICAgICAgICApIHtcclxuICAgICAgICAgICAgbG9nKDQsICdbcmF0ZSBsaW1pdGluZ10gU2tpcHBpbmcgcmF0ZSBsaW1pdGVyLicpO1xyXG4gICAgICAgICAgICByZXR1cm4gdHJ1ZTtcclxuICAgICAgICAgIH1cclxuICAgICAgICAgIHJldHVybiBmYWxzZTtcclxuICAgICAgICB9XHJcbiAgICAgIH0pO1xyXG5cclxuICAgICAgLy8gVXNlIGEgbGltaXRlciBhcyBhIG1pZGRsZXdhcmVcclxuICAgICAgYXBwLnVzZShsaW1pdGVyKTtcclxuXHJcbiAgICAgIGxvZyhcclxuICAgICAgICAzLFxyXG4gICAgICAgIGBbcmF0ZSBsaW1pdGluZ10gRW5hYmxlZCByYXRlIGxpbWl0aW5nIHdpdGggJHtyYXRlT3B0aW9ucy5tYXh9IHJlcXVlc3RzIHBlciAke3JhdGVPcHRpb25zLndpbmRvd30gbWludXRlIGZvciBlYWNoIElQLCB0cnVzdGluZyBwcm94eTogJHtyYXRlT3B0aW9ucy50cnVzdFByb3h5fS5gXHJcbiAgICAgICk7XHJcbiAgICB9XHJcbiAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcihcclxuICAgICAgJ1tyYXRlIGxpbWl0aW5nXSBDb3VsZCBub3QgY29uZmlndXJlIGFuZCBzZXQgdGhlIHJhdGUgbGltaXRpbmcgb3B0aW9ucy4nLFxyXG4gICAgICA1MDBcclxuICAgICkuc2V0RXJyb3IoZXJyb3IpO1xyXG4gIH1cclxufVxyXG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxyXG5cclxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXHJcblxyXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNSwgSGlnaHNvZnRcclxuXHJcbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cclxuXHJcbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxyXG5cclxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxyXG5cclxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cclxuXHJcbmltcG9ydCBFeHBvcnRFcnJvciBmcm9tICcuL0V4cG9ydEVycm9yLmpzJztcclxuXHJcbi8qKlxyXG4gKiBBIGN1c3RvbSBIVFRQIGVycm9yIGNsYXNzIHRoYXQgZXh0ZW5kcyB0aGUgYEV4cG9ydEVycm9yYC4gVXNlZCB0byBoYW5kbGVcclxuICogZXJyb3JzIHdpdGggSFRUUCBzdGF0dXMgY29kZXMuXHJcbiAqL1xyXG5jbGFzcyBIdHRwRXJyb3IgZXh0ZW5kcyBFeHBvcnRFcnJvciB7XHJcbiAgLyoqXHJcbiAgICogQ3JlYXRlcyBhbiBpbnN0YW5jZSBvZiB0aGUgYEh0dHBFcnJvcmAuXHJcbiAgICpcclxuICAgKiBAcGFyYW0ge3N0cmluZ30gbWVzc2FnZSAtIFRoZSBlcnJvciBtZXNzYWdlIHRvIGJlIGRpc3BsYXllZC5cclxuICAgKiBAcGFyYW0ge251bWJlcn0gc3RhdHVzQ29kZSAtIE9wdGlvbmFsIEhUVFAgc3RhdHVzIGNvZGUgYXNzb2NpYXRlZFxyXG4gICAqIHdpdGggdGhlIGVycm9yIChlLmcuLCA0MDAsIDUwMCkuXHJcbiAgICovXHJcbiAgY29uc3RydWN0b3IobWVzc2FnZSwgc3RhdHVzQ29kZSkge1xyXG4gICAgc3VwZXIobWVzc2FnZSwgc3RhdHVzQ29kZSk7XHJcbiAgfVxyXG5cclxuICAvKipcclxuICAgKiBTZXRzIG9yIHVwZGF0ZXMgdGhlIEhUVFAgc3RhdHVzIGNvZGUgZm9yIHRoZSBlcnJvci5cclxuICAgKlxyXG4gICAqIEBwYXJhbSB7bnVtYmVyfSBzdGF0dXNDb2RlIC0gVGhlIEhUVFAgc3RhdHVzIGNvZGUgdG8gYXNzaWduIHRvIHRoZSBlcnJvci5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHtIdHRwRXJyb3J9IFRoZSB1cGRhdGVkIGluc3RhbmNlIG9mIHRoZSBgSHR0cEVycm9yYCBjbGFzcy5cclxuICAgKi9cclxuICBzZXRTdGF0dXMoc3RhdHVzQ29kZSkge1xyXG4gICAgdGhpcy5zdGF0dXNDb2RlID0gc3RhdHVzQ29kZTtcclxuXHJcbiAgICByZXR1cm4gdGhpcztcclxuICB9XHJcbn1cclxuXHJcbmV4cG9ydCBkZWZhdWx0IEh0dHBFcnJvcjtcclxuIiwiLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcclxuXHJcbkhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlclxyXG5cclxuQ29weXJpZ2h0IChjKSAyMDE2LTIwMjUsIEhpZ2hzb2Z0XHJcblxyXG5MaWNlbmNlZCB1bmRlciB0aGUgTUlUIGxpY2VuY2UuXHJcblxyXG5BZGRpdGlvbmFsbHkgYSB2YWxpZCBIaWdoY2hhcnRzIGxpY2Vuc2UgaXMgcmVxdWlyZWQgZm9yIHVzZS5cclxuXHJcblNlZSBMSUNFTlNFIGZpbGUgaW4gcm9vdCBmb3IgZGV0YWlscy5cclxuXHJcbioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXHJcblxyXG4vKipcclxuICogQG92ZXJ2aWV3IFByb3ZpZGVzIG1pZGRsZXdhcmUgZnVuY3Rpb25zIGZvciB2YWxpZGF0aW5nIGluY29taW5nIEhUVFAgcmVxdWVzdHNcclxuICogaW4gYW4gRXhwcmVzcyBhcHBsaWNhdGlvbi4gVGhpcyBtb2R1bGUgZW5zdXJlcyB0aGF0IHJlcXVlc3RzIGNvbnRhaW5cclxuICogYXBwcm9wcmlhdGUgY29udGVudCB0eXBlcyBhbmQgdmFsaWQgcmVxdWVzdCBib2RpZXMsIGluY2x1ZGluZyBwcm9wZXIgSlNPTlxyXG4gKiBzdHJ1Y3R1cmVzIGFuZCBjaGFydCBkYXRhIGZvciBleHBvcnRzLiBJdCBjaGVja3MgZm9yIHBvdGVudGlhbCBpc3N1ZXMgc3VjaFxyXG4gKiBhcyBtaXNzaW5nIG9yIG1hbGZvcm1lZCBkYXRhLCBwcml2YXRlIHJhbmdlIFVSTHMgaW4gU1ZHIHBheWxvYWRzLCBhbmQgYWxsb3dzXHJcbiAqIGZvciBmbGV4aWJsZSBvcHRpb25zIHZhbGlkYXRpb24uIFRoZSBtaWRkbGV3YXJlIGxvZ3MgZGV0YWlsZWQgaW5mb3JtYXRpb25cclxuICogYW5kIGhhbmRsZXMgZXJyb3JzIHJlbGF0ZWQgdG8gaW5jb3JyZWN0IHBheWxvYWRzLCBjaGFydCBkYXRhLCBhbmQgcHJpdmF0ZSBVUkxcclxuICogdXNhZ2UuXHJcbiAqL1xyXG5cclxuaW1wb3J0IHsgdjQgYXMgdXVpZCB9IGZyb20gJ3V1aWQnO1xyXG5cclxuaW1wb3J0IHsgZ2V0QWxsb3dDb2RlRXhlY3V0aW9uIH0gZnJvbSAnLi4vLi4vY2hhcnQuanMnO1xyXG5pbXBvcnQgeyBpc0FsbG93ZWRDb25maWcgfSBmcm9tICcuLi8uLi9jb25maWcuanMnO1xyXG5pbXBvcnQgeyBsb2cgfSBmcm9tICcuLi8uLi9sb2dnZXIuanMnO1xyXG5pbXBvcnQge1xyXG4gIGZpeENvbnN0cixcclxuICBmaXhUeXBlLFxyXG4gIGlzT2JqZWN0RW1wdHksXHJcbiAgaXNQcml2YXRlUmFuZ2VVcmxGb3VuZFxyXG59IGZyb20gJy4uLy4uL3V0aWxzLmpzJztcclxuXHJcbmltcG9ydCBIdHRwRXJyb3IgZnJvbSAnLi4vLi4vZXJyb3JzL0h0dHBFcnJvci5qcyc7XHJcblxyXG4vKipcclxuICogTWlkZGxld2FyZSBmb3IgdmFsaWRhdGluZyB0aGUgY29udGVudC10eXBlIGhlYWRlci5cclxuICpcclxuICogQGZ1bmN0aW9uIGNvbnRlbnRUeXBlTWlkZGxld2FyZVxyXG4gKlxyXG4gKiBAcGFyYW0ge0V4cHJlc3MuUmVxdWVzdH0gcmVxdWVzdCAtIFRoZSBFeHByZXNzIHJlcXVlc3Qgb2JqZWN0LlxyXG4gKiBAcGFyYW0ge0V4cHJlc3MuUmVzcG9uc2V9IHJlc3BvbnNlIC0gVGhlIEV4cHJlc3MgcmVzcG9uc2Ugb2JqZWN0LlxyXG4gKiBAcGFyYW0ge0Z1bmN0aW9ufSBuZXh0IC0gVGhlIG5leHQgbWlkZGxld2FyZSBmdW5jdGlvbi5cclxuICpcclxuICogQHJldHVybnMge3VuZGVmaW5lZH0gVGhlIGNhbGwgdG8gdGhlIG5leHQgbWlkZGxld2FyZSBmdW5jdGlvbi5cclxuICpcclxuICogQHRocm93cyB7SHR0cEVycm9yfSBUaHJvd3MgYW4gYEh0dHBFcnJvcmAgaWYgdGhlIGNvbnRlbnQtdHlwZVxyXG4gKiBpcyBub3QgY29ycmVjdC5cclxuICovXHJcbmZ1bmN0aW9uIGNvbnRlbnRUeXBlTWlkZGxld2FyZShyZXF1ZXN0LCByZXNwb25zZSwgbmV4dCkge1xyXG4gIHRyeSB7XHJcbiAgICAvLyBHZXQgdGhlIGNvbnRlbnQgdHlwZSBoZWFkZXJcclxuICAgIGNvbnN0IGNvbnRlbnRUeXBlID0gcmVxdWVzdC5oZWFkZXJzWydjb250ZW50LXR5cGUnXSB8fCAnJztcclxuXHJcbiAgICAvLyBBbGxvdyBvbmx5IEpTT04sIFVSTC1lbmNvZGVkIGFuZCBmb3JtIGRhdGEgd2l0aG91dCBmaWxlcyB0eXBlcyBvZiBkYXRhXHJcbiAgICBpZiAoXHJcbiAgICAgICFjb250ZW50VHlwZS5pbmNsdWRlcygnYXBwbGljYXRpb24vanNvbicpICYmXHJcbiAgICAgICFjb250ZW50VHlwZS5pbmNsdWRlcygnYXBwbGljYXRpb24veC13d3ctZm9ybS11cmxlbmNvZGVkJykgJiZcclxuICAgICAgIWNvbnRlbnRUeXBlLmluY2x1ZGVzKCdtdWx0aXBhcnQvZm9ybS1kYXRhJylcclxuICAgICkge1xyXG4gICAgICB0aHJvdyBuZXcgSHR0cEVycm9yKFxyXG4gICAgICAgICdbdmFsaWRhdGlvbl0gQ29udGVudC1UeXBlIG11c3QgYmUgYXBwbGljYXRpb24vanNvbiwgYXBwbGljYXRpb24veC13d3ctZm9ybS11cmxlbmNvZGVkLCBvciBtdWx0aXBhcnQvZm9ybS1kYXRhLicsXHJcbiAgICAgICAgNDE1XHJcbiAgICAgICk7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gQ2FsbCB0aGUgYHJlcXVlc3RCb2R5TWlkZGxld2FyZWAgbWlkZGxld2FyZVxyXG4gICAgcmV0dXJuIG5leHQoKTtcclxuICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgcmV0dXJuIG5leHQoZXJyb3IpO1xyXG4gIH1cclxufVxyXG5cclxuLyoqXHJcbiAqIE1pZGRsZXdhcmUgZm9yIHZhbGlkYXRpbmcgdGhlIHJlcXVlc3QncyBib2R5LlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gcmVxdWVzdEJvZHlNaWRkbGV3YXJlXHJcbiAqXHJcbiAqIEBwYXJhbSB7RXhwcmVzcy5SZXF1ZXN0fSByZXF1ZXN0IC0gVGhlIEV4cHJlc3MgcmVxdWVzdCBvYmplY3QuXHJcbiAqIEBwYXJhbSB7RXhwcmVzcy5SZXNwb25zZX0gcmVzcG9uc2UgLSBUaGUgRXhwcmVzcyByZXNwb25zZSBvYmplY3QuXHJcbiAqIEBwYXJhbSB7RnVuY3Rpb259IG5leHQgLSBUaGUgbmV4dCBtaWRkbGV3YXJlIGZ1bmN0aW9uLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7dW5kZWZpbmVkfSBUaGUgY2FsbCB0byB0aGUgbmV4dCBtaWRkbGV3YXJlIGZ1bmN0aW9uLlxyXG4gKlxyXG4gKiBAdGhyb3dzIHtIdHRwRXJyb3J9IFRocm93cyBhbiBgSHR0cEVycm9yYCBpZiB0aGUgYm9keSBpcyBub3QgY29ycmVjdC5cclxuICogQHRocm93cyB7SHR0cEVycm9yfSBUaHJvd3MgYW4gYEh0dHBFcnJvcmAgaWYgdGhlIGNoYXJ0IGRhdGEgZnJvbSB0aGUgYm9keVxyXG4gKiBpcyBub3QgY29ycmVjdC5cclxuICogQHRocm93cyB7SHR0cEVycm9yfSBUaHJvd3MgYW4gYEh0dHBFcnJvcmAgaW4gY2FzZSBvZiB0aGUgcHJpdmF0ZSByYW5nZSB1cmxcclxuICogZXJyb3IuXHJcbiAqL1xyXG5mdW5jdGlvbiByZXF1ZXN0Qm9keU1pZGRsZXdhcmUocmVxdWVzdCwgcmVzcG9uc2UsIG5leHQpIHtcclxuICB0cnkge1xyXG4gICAgLy8gR2V0IHRoZSByZXF1ZXN0IGJvZHlcclxuICAgIGNvbnN0IGJvZHkgPSByZXF1ZXN0LmJvZHk7XHJcblxyXG4gICAgLy8gQ3JlYXRlIGEgdW5pcXVlIElEIGZvciBhIHJlcXVlc3RcclxuICAgIGNvbnN0IHJlcXVlc3RJZCA9IHV1aWQoKS5yZXBsYWNlKC8tL2csICcnKTtcclxuXHJcbiAgICAvLyBUaHJvdyBhbiBlcnJvciBpZiB0aGVyZSBpcyBubyBjb3JyZWN0IGJvZHlcclxuICAgIGlmICghYm9keSB8fCBpc09iamVjdEVtcHR5KGJvZHkpKSB7XHJcbiAgICAgIGxvZyhcclxuICAgICAgICAyLFxyXG4gICAgICAgIGBbdmFsaWRhdGlvbl0gUmVxdWVzdCBbJHtyZXF1ZXN0SWR9XSAtIFRoZSByZXF1ZXN0IGZyb20gJHtcclxuICAgICAgICAgIHJlcXVlc3QuaGVhZGVyc1sneC1mb3J3YXJkZWQtZm9yJ10gfHwgcmVxdWVzdC5jb25uZWN0aW9uLnJlbW90ZUFkZHJlc3NcclxuICAgICAgICB9IHdhcyBpbmNvcnJlY3QuIFJlY2VpdmVkIHBheWxvYWQgaXMgZW1wdHkuYFxyXG4gICAgICApO1xyXG5cclxuICAgICAgdGhyb3cgbmV3IEh0dHBFcnJvcihcclxuICAgICAgICBcIlt2YWxpZGF0aW9uXSBUaGUgcmVxdWVzdCBib2R5IGlzIHJlcXVpcmVkLiBQbGVhc2UgZW5zdXJlIHRoYXQgeW91ciBDb250ZW50LVR5cGUgaGVhZGVyIGlzIGNvcnJlY3QuIEFjY2VwdGVkIHR5cGVzIGFyZSAnYXBwbGljYXRpb24vanNvbicgYW5kICdtdWx0aXBhcnQvZm9ybS1kYXRhJy5cIixcclxuICAgICAgICA0MDBcclxuICAgICAgKTtcclxuICAgIH1cclxuXHJcbiAgICAvLyBHZXQgdGhlIGFsbG93Q29kZUV4ZWN1dGlvbiBvcHRpb24gZm9yIHRoZSBzZXJ2ZXJcclxuICAgIGNvbnN0IGFsbG93Q29kZUV4ZWN1dGlvbiA9IGdldEFsbG93Q29kZUV4ZWN1dGlvbigpO1xyXG5cclxuICAgIC8vIEZpbmQgYSBjb3JyZWN0IGNoYXJ0IG9wdGlvbnNcclxuICAgIGNvbnN0IGluc3RyID0gaXNBbGxvd2VkQ29uZmlnKFxyXG4gICAgICAvLyBVc2Ugb25lIG9mIHRoZSBiZWxvd1xyXG4gICAgICBib2R5Lmluc3RyIHx8IGJvZHkub3B0aW9ucyB8fCBib2R5LmluZmlsZSB8fCBib2R5LmRhdGEsXHJcbiAgICAgIC8vIFN0cmluZ2lmeSBvcHRpb25zXHJcbiAgICAgIHRydWUsXHJcbiAgICAgIC8vIEFsbG93IG9yIGRpc2FsbG93IGZ1bmN0aW9uc1xyXG4gICAgICBhbGxvd0NvZGVFeGVjdXRpb25cclxuICAgICk7XHJcblxyXG4gICAgLy8gVGhyb3cgYW4gZXJyb3IgaWYgdGhlcmUgaXMgbm8gY29ycmVjdCBjaGFydCBkYXRhXHJcbiAgICBpZiAoaW5zdHIgPT09IG51bGwgJiYgIWJvZHkuc3ZnKSB7XHJcbiAgICAgIGxvZyhcclxuICAgICAgICAyLFxyXG4gICAgICAgIGBbdmFsaWRhdGlvbl0gUmVxdWVzdCBbJHtyZXF1ZXN0SWR9XSAtIFRoZSByZXF1ZXN0IGZyb20gJHtcclxuICAgICAgICAgIHJlcXVlc3QuaGVhZGVyc1sneC1mb3J3YXJkZWQtZm9yJ10gfHwgcmVxdWVzdC5jb25uZWN0aW9uLnJlbW90ZUFkZHJlc3NcclxuICAgICAgICB9IHdhcyBpbmNvcnJlY3QuIFJlY2VpdmVkIHBheWxvYWQgaXMgbWlzc2luZyBjb3JyZWN0IGNoYXJ0IGRhdGEgZm9yIGV4cG9ydDogJHtKU09OLnN0cmluZ2lmeShib2R5KX0uYFxyXG4gICAgICApO1xyXG5cclxuICAgICAgdGhyb3cgbmV3IEh0dHBFcnJvcihcclxuICAgICAgICBcIlt2YWxpZGF0aW9uXSBObyBjb3JyZWN0IGNoYXJ0IGRhdGEgZm91bmQuIEVuc3VyZSB0aGF0IHlvdSBhcmUgdXNpbmcgZWl0aGVyIGFwcGxpY2F0aW9uL2pzb24gb3IgbXVsdGlwYXJ0L2Zvcm0tZGF0YSBoZWFkZXJzLiBJZiBzZW5kaW5nIEpTT04sIG1ha2Ugc3VyZSB0aGUgY2hhcnQgZGF0YSBpcyBpbiB0aGUgJ2luZmlsZScsICdvcHRpb25zJywgb3IgJ2RhdGEnIGF0dHJpYnV0ZS4gSWYgc2VuZGluZyBTVkcsIGVuc3VyZSBpdCBpcyBpbiB0aGUgJ3N2ZycgYXR0cmlidXRlLlwiLFxyXG4gICAgICAgIDQwMFxyXG4gICAgICApO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIFRocm93IGFuIGVycm9yIGlmIHRlc3Qgb2YgeGxpbms6aHJlZiBlbGVtZW50cyBmcm9tIHBheWxvYWQncyBTVkcgZmFpbHNcclxuICAgIGlmIChib2R5LnN2ZyAmJiBpc1ByaXZhdGVSYW5nZVVybEZvdW5kKGJvZHkuc3ZnKSkge1xyXG4gICAgICB0aHJvdyBuZXcgSHR0cEVycm9yKFxyXG4gICAgICAgIFwiW3ZhbGlkYXRpb25dIFNWRyBwb3RlbnRpYWxseSBjb250YWluIGF0IGxlYXN0IG9uZSBmb3JiaWRkZW4gVVJMIGluICd4bGluazpocmVmJyBlbGVtZW50LiBQbGVhc2UgcmV2aWV3IHRoZSBTVkcgY29udGVudCBhbmQgZW5zdXJlIHRoYXQgYWxsIHJlZmVyZW5jZWQgVVJMcyBjb21wbHkgd2l0aCBzZWN1cml0eSBwb2xpY2llcy5cIixcclxuICAgICAgICA0MDBcclxuICAgICAgKTtcclxuICAgIH1cclxuXHJcbiAgICAvLyBHZXQgb3B0aW9ucyBmcm9tIHRoZSBib2R5IGFuZCBzdG9yZSBwYXJzZWQgc3RydWN0dXJlIGluIHRoZSByZXF1ZXN0XHJcbiAgICByZXF1ZXN0LnZhbGlkYXRlZE9wdGlvbnMgPSB7XHJcbiAgICAgIC8vIFNldCB0aGUgY3JlYXRlZCBJRCBhcyBhIGBfcmVxdWVzdElkYCBwcm9wZXJ0eSBpbiB0aGUgdmFsaWRhdGVkIG9wdGlvbnNcclxuICAgICAgX3JlcXVlc3RJZDogcmVxdWVzdElkLFxyXG4gICAgICBleHBvcnQ6IHtcclxuICAgICAgICBpbnN0cixcclxuICAgICAgICBzdmc6IGJvZHkuc3ZnLFxyXG4gICAgICAgIG91dGZpbGU6XHJcbiAgICAgICAgICBib2R5Lm91dGZpbGUgfHxcclxuICAgICAgICAgIGAke3JlcXVlc3QucGFyYW1zLmZpbGVuYW1lIHx8ICdjaGFydCd9LiR7Zml4VHlwZShib2R5LnR5cGUpfWAsXHJcbiAgICAgICAgdHlwZTogZml4VHlwZShib2R5LnR5cGUsIGJvZHkub3V0ZmlsZSksXHJcbiAgICAgICAgY29uc3RyOiBmaXhDb25zdHIoYm9keS5jb25zdHIpLFxyXG4gICAgICAgIGI2NDogYm9keS5iNjQsXHJcbiAgICAgICAgbm9Eb3dubG9hZDogYm9keS5ub0Rvd25sb2FkLFxyXG4gICAgICAgIGhlaWdodDogYm9keS5oZWlnaHQsXHJcbiAgICAgICAgd2lkdGg6IGJvZHkud2lkdGgsXHJcbiAgICAgICAgc2NhbGU6IGJvZHkuc2NhbGUsXHJcbiAgICAgICAgZ2xvYmFsT3B0aW9uczogaXNBbGxvd2VkQ29uZmlnKFxyXG4gICAgICAgICAgYm9keS5nbG9iYWxPcHRpb25zLFxyXG4gICAgICAgICAgdHJ1ZSxcclxuICAgICAgICAgIGFsbG93Q29kZUV4ZWN1dGlvblxyXG4gICAgICAgICksXHJcbiAgICAgICAgdGhlbWVPcHRpb25zOiBpc0FsbG93ZWRDb25maWcoXHJcbiAgICAgICAgICBib2R5LnRoZW1lT3B0aW9ucyxcclxuICAgICAgICAgIHRydWUsXHJcbiAgICAgICAgICBhbGxvd0NvZGVFeGVjdXRpb25cclxuICAgICAgICApXHJcbiAgICAgIH0sXHJcbiAgICAgIGN1c3RvbUxvZ2ljOiB7XHJcbiAgICAgICAgYWxsb3dDb2RlRXhlY3V0aW9uLFxyXG4gICAgICAgIGFsbG93RmlsZVJlc291cmNlczogZmFsc2UsXHJcbiAgICAgICAgY3VzdG9tQ29kZTogYm9keS5jdXN0b21Db2RlLFxyXG4gICAgICAgIGNhbGxiYWNrOiBib2R5LmNhbGxiYWNrLFxyXG4gICAgICAgIHJlc291cmNlczogaXNBbGxvd2VkQ29uZmlnKGJvZHkucmVzb3VyY2VzLCB0cnVlLCBhbGxvd0NvZGVFeGVjdXRpb24pXHJcbiAgICAgIH1cclxuICAgIH07XHJcblxyXG4gICAgLy8gQ2FsbCB0aGUgbmV4dCBtaWRkbGV3YXJlXHJcbiAgICByZXR1cm4gbmV4dCgpO1xyXG4gIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICByZXR1cm4gbmV4dChlcnJvcik7XHJcbiAgfVxyXG59XHJcblxyXG4vKipcclxuICogQWRkcyB0aGUgdmFsaWRhdGlvbiBtaWRkbGV3YXJlcyB0byB0aGUgcGFzc2VkIGV4cHJlc3MgYXBwIGluc3RhbmNlLlxyXG4gKlxyXG4gKiBAcGFyYW0ge0V4cHJlc3N9IGFwcCAtIFRoZSBFeHByZXNzIGFwcCBpbnN0YW5jZS5cclxuICovXHJcbmV4cG9ydCBkZWZhdWx0IGZ1bmN0aW9uIHZhbGlkYXRpb25NaWRkbGV3YXJlKGFwcCkge1xyXG4gIC8vIEFkZCBjb250ZW50IHR5cGUgdmFsaWRhdGlvbiBtaWRkbGV3YXJlXHJcbiAgYXBwLnBvc3QoWycvJywgJy86ZmlsZW5hbWUnXSwgY29udGVudFR5cGVNaWRkbGV3YXJlKTtcclxuXHJcbiAgLy8gQWRkIHJlcXVlc3QgYm9keSByZXF1ZXN0IHZhbGlkYXRpb24gbWlkZGxld2FyZVxyXG4gIGFwcC5wb3N0KFsnLycsICcvOmZpbGVuYW1lJ10sIHJlcXVlc3RCb2R5TWlkZGxld2FyZSk7XHJcbn1cclxuIiwiLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcclxuXHJcbkhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlclxyXG5cclxuQ29weXJpZ2h0IChjKSAyMDE2LTIwMjUsIEhpZ2hzb2Z0XHJcblxyXG5MaWNlbmNlZCB1bmRlciB0aGUgTUlUIGxpY2VuY2UuXHJcblxyXG5BZGRpdGlvbmFsbHkgYSB2YWxpZCBIaWdoY2hhcnRzIGxpY2Vuc2UgaXMgcmVxdWlyZWQgZm9yIHVzZS5cclxuXHJcblNlZSBMSUNFTlNFIGZpbGUgaW4gcm9vdCBmb3IgZGV0YWlscy5cclxuXHJcbioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXHJcblxyXG4vKipcclxuICogQG92ZXJ2aWV3IERlZmluZXMgdGhlIGV4cG9ydCByb3V0ZXMgYW5kIGxvZ2ljIGZvciBoYW5kbGluZyBjaGFydCBleHBvcnRcclxuICogcmVxdWVzdHMgaW4gYW4gRXhwcmVzcyBzZXJ2ZXIuIFRoaXMgbW9kdWxlIHByb2Nlc3NlcyBpbmNvbWluZyByZXF1ZXN0c1xyXG4gKiB0byBleHBvcnQgY2hhcnRzIGluIHZhcmlvdXMgZm9ybWF0cyAoZS5nLiBKUEVHLCBQTkcsIFBERiwgU1ZHKS4gSXQgaW50ZWdyYXRlc1xyXG4gKiB3aXRoIEhpZ2hjaGFydHMnIGNvcmUgZnVuY3Rpb25hbGl0aWVzIGFuZCBzdXBwb3J0cyBib3RoIGltbWVkaWF0ZSBkb3dubG9hZFxyXG4gKiByZXNwb25zZXMgYW5kIEJhc2U2NC1lbmNvZGVkIGNvbnRlbnQgcmV0dXJucy4gVGhlIGNvZGUgYWxzbyBmZWF0dXJlc1xyXG4gKiBiZW5jaG1hcmtpbmcgZm9yIHBlcmZvcm1hbmNlIG1vbml0b3JpbmcuXHJcbiAqL1xyXG5cclxuaW1wb3J0IHsgc3RhcnRFeHBvcnQgfSBmcm9tICcuLi8uLi9jaGFydC5qcyc7XHJcbmltcG9ydCB7IGxvZyB9IGZyb20gJy4uLy4uL2xvZ2dlci5qcyc7XHJcbmltcG9ydCB7IGdldEJhc2U2NCwgbWVhc3VyZVRpbWUgfSBmcm9tICcuLi8uLi91dGlscy5qcyc7XHJcblxyXG5pbXBvcnQgSHR0cEVycm9yIGZyb20gJy4uLy4uL2Vycm9ycy9IdHRwRXJyb3IuanMnO1xyXG5cclxuLy8gUmV2ZXJzZWQgTUlNRSB0eXBlc1xyXG5jb25zdCByZXZlcnNlZE1pbWUgPSB7XHJcbiAgcG5nOiAnaW1hZ2UvcG5nJyxcclxuICBqcGVnOiAnaW1hZ2UvanBlZycsXHJcbiAgZ2lmOiAnaW1hZ2UvZ2lmJyxcclxuICBwZGY6ICdhcHBsaWNhdGlvbi9wZGYnLFxyXG4gIHN2ZzogJ2ltYWdlL3N2Zyt4bWwnXHJcbn07XHJcblxyXG4vKipcclxuICogSGFuZGxlcyB0aGUgZXhwb3J0IHJlcXVlc3RzIGZyb20gdGhlIGNsaWVudC5cclxuICpcclxuICogQGFzeW5jXHJcbiAqIEBmdW5jdGlvbiByZXF1ZXN0RXhwb3J0XHJcbiAqXHJcbiAqIEBwYXJhbSB7RXhwcmVzcy5SZXF1ZXN0fSByZXF1ZXN0IC0gVGhlIEV4cHJlc3MgcmVxdWVzdCBvYmplY3QuXHJcbiAqIEBwYXJhbSB7RXhwcmVzcy5SZXNwb25zZX0gcmVzcG9uc2UgLSBUaGUgRXhwcmVzcyByZXNwb25zZSBvYmplY3QuXHJcbiAqIEBwYXJhbSB7RnVuY3Rpb259IG5leHQgLSBUaGUgbmV4dCBtaWRkbGV3YXJlIGZ1bmN0aW9uLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7UHJvbWlzZTx2b2lkPn0gQSBQcm9taXNlIHRoYXQgcmVzb2x2ZXMgb25jZSB0aGUgZXhwb3J0IHByb2Nlc3NcclxuICogaXMgY29tcGxldGUuXHJcbiAqL1xyXG5hc3luYyBmdW5jdGlvbiByZXF1ZXN0RXhwb3J0KHJlcXVlc3QsIHJlc3BvbnNlLCBuZXh0KSB7XHJcbiAgdHJ5IHtcclxuICAgIC8vIFN0YXJ0IGNvdW50aW5nIHRpbWUgZm9yIGEgcmVxdWVzdFxyXG4gICAgY29uc3QgcmVxdWVzdENvdW50ZXIgPSBtZWFzdXJlVGltZSgpO1xyXG5cclxuICAgIC8vIEluIGNhc2UgdGhlIGNvbm5lY3Rpb24gaXMgY2xvc2VkLCBmb3JjZSB0byBhYm9ydCBmdXJ0aGVyIGFjdGlvbnNcclxuICAgIGxldCBjb25uZWN0aW9uQWJvcnRlZCA9IGZhbHNlO1xyXG4gICAgcmVxdWVzdC5zb2NrZXQub24oJ2Nsb3NlJywgKGhhZEVycm9ycykgPT4ge1xyXG4gICAgICBpZiAoaGFkRXJyb3JzKSB7XHJcbiAgICAgICAgY29ubmVjdGlvbkFib3J0ZWQgPSB0cnVlO1xyXG4gICAgICB9XHJcbiAgICB9KTtcclxuXHJcbiAgICAvLyBHZXQgdGhlIG9wdGlvbnMgcHJldmlvdXNseSB2YWxpZGF0ZWQgaW4gdGhlIHZhbGlkYXRpb24gbWlkZGxld2FyZVxyXG4gICAgY29uc3QgcmVxdWVzdE9wdGlvbnMgPSByZXF1ZXN0LnZhbGlkYXRlZE9wdGlvbnM7XHJcblxyXG4gICAgLy8gR2V0IHRoZSByZXF1ZXN0IGlkXHJcbiAgICBjb25zdCByZXF1ZXN0SWQgPSByZXF1ZXN0T3B0aW9ucy5fcmVxdWVzdElkO1xyXG5cclxuICAgIC8vIEluZm8gYWJvdXQgYW4gaW5jb21pbmcgcmVxdWVzdCB3aXRoIGNvcnJlY3QgZGF0YVxyXG4gICAgbG9nKDQsIGBbZXhwb3J0XSBHb3QgYW4gaW5jb21pbmcgSFRUUCByZXF1ZXN0IHdpdGggSUQgJHtyZXF1ZXN0SWR9LmApO1xyXG5cclxuICAgIC8vIFN0YXJ0IHRoZSBleHBvcnQgcHJvY2Vzc1xyXG4gICAgYXdhaXQgc3RhcnRFeHBvcnQocmVxdWVzdE9wdGlvbnMsIChlcnJvciwgZGF0YSkgPT4ge1xyXG4gICAgICAvLyBSZW1vdmUgdGhlIGNsb3NlIGV2ZW50IGZyb20gdGhlIHNvY2tldFxyXG4gICAgICByZXF1ZXN0LnNvY2tldC5yZW1vdmVBbGxMaXN0ZW5lcnMoJ2Nsb3NlJyk7XHJcblxyXG4gICAgICAvLyBJZiB0aGUgY29ubmVjdGlvbiB3YXMgY2xvc2VkLCBkbyBub3RoaW5nXHJcbiAgICAgIGlmIChjb25uZWN0aW9uQWJvcnRlZCkge1xyXG4gICAgICAgIGxvZyhcclxuICAgICAgICAgIDMsXHJcbiAgICAgICAgICBgW2V4cG9ydF0gUmVxdWVzdCBbJHtyZXF1ZXN0SWR9XSAtIFRoZSBjbGllbnQgY2xvc2VkIHRoZSBjb25uZWN0aW9uIGJlZm9yZSB0aGUgY2hhcnQgZmluaXNoZWQgcHJvY2Vzc2luZy5gXHJcbiAgICAgICAgKTtcclxuICAgICAgICByZXR1cm47XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIC8vIElmIGVycm9yLCBsb2cgaXQgYW5kIHNlbmQgaXQgdG8gdGhlIGVycm9yIG1pZGRsZXdhcmVcclxuICAgICAgaWYgKGVycm9yKSB7XHJcbiAgICAgICAgdGhyb3cgZXJyb3I7XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIC8vIElmIGRhdGEgaXMgbWlzc2luZywgbG9nIHRoZSBtZXNzYWdlIGFuZCBzZW5kIGl0IHRvIHRoZSBlcnJvciBtaWRkbGV3YXJlXHJcbiAgICAgIGlmICghZGF0YSB8fCAhZGF0YS5yZXN1bHQpIHtcclxuICAgICAgICBsb2coXHJcbiAgICAgICAgICAyLFxyXG4gICAgICAgICAgYFtleHBvcnRdIFJlcXVlc3QgWyR7cmVxdWVzdElkfV0gLSBSZXF1ZXN0IGZyb20gJHtcclxuICAgICAgICAgICAgcmVxdWVzdC5oZWFkZXJzWyd4LWZvcndhcmRlZC1mb3InXSB8fFxyXG4gICAgICAgICAgICByZXF1ZXN0LmNvbm5lY3Rpb24ucmVtb3RlQWRkcmVzc1xyXG4gICAgICAgICAgfSB3YXMgaW5jb3JyZWN0LiBSZWNlaXZlZCByZXN1bHQgaXMgJHtkYXRhLnJlc3VsdH0uYFxyXG4gICAgICAgICk7XHJcblxyXG4gICAgICAgIHRocm93IG5ldyBIdHRwRXJyb3IoXHJcbiAgICAgICAgICAnW2V4cG9ydF0gVW5leHBlY3RlZCByZXR1cm4gb2YgdGhlIGV4cG9ydCByZXN1bHQgZnJvbSB0aGUgY2hhcnQgZ2VuZXJhdGlvbi4gUGxlYXNlIGNoZWNrIHlvdXIgcmVxdWVzdCBkYXRhLicsXHJcbiAgICAgICAgICA0MDBcclxuICAgICAgICApO1xyXG4gICAgICB9XHJcblxyXG4gICAgICAvLyBSZXR1cm4gdGhlIHJlc3VsdCBpbiBhbiBhcHByb3ByaWF0ZSBmb3JtYXRcclxuICAgICAgaWYgKGRhdGEucmVzdWx0KSB7XHJcbiAgICAgICAgbG9nKFxyXG4gICAgICAgICAgMyxcclxuICAgICAgICAgIGBbZXhwb3J0XSBSZXF1ZXN0IFske3JlcXVlc3RJZH1dIC0gVGhlIHdob2xlIGV4cG9ydGluZyBwcm9jZXNzIHRvb2sgJHtyZXF1ZXN0Q291bnRlcigpfW1zLmBcclxuICAgICAgICApO1xyXG5cclxuICAgICAgICAvLyBHZXQgdGhlIGB0eXBlYCwgYGI2NGAsIGBub0Rvd25sb2FkYCwgYW5kIGBvdXRmaWxlYCBmcm9tIG9wdGlvbnNcclxuICAgICAgICBjb25zdCB7IHR5cGUsIGI2NCwgbm9Eb3dubG9hZCwgb3V0ZmlsZSB9ID0gZGF0YS5vcHRpb25zLmV4cG9ydDtcclxuXHJcbiAgICAgICAgLy8gSWYgb25seSBCYXNlNjQgaXMgcmVxdWlyZWQsIHJldHVybiBpdFxyXG4gICAgICAgIGlmIChiNjQpIHtcclxuICAgICAgICAgIHJldHVybiByZXNwb25zZS5zZW5kKGdldEJhc2U2NChkYXRhLnJlc3VsdCwgdHlwZSkpO1xyXG4gICAgICAgIH1cclxuXHJcbiAgICAgICAgLy8gU2V0IGNvcnJlY3QgY29udGVudCB0eXBlXHJcbiAgICAgICAgcmVzcG9uc2UuaGVhZGVyKCdDb250ZW50LVR5cGUnLCByZXZlcnNlZE1pbWVbdHlwZV0gfHwgJ2ltYWdlL3BuZycpO1xyXG5cclxuICAgICAgICAvLyBEZWNpZGUgd2hldGhlciB0byBkb3dubG9hZCBvciBub3QgY2hhcnQgZmlsZVxyXG4gICAgICAgIGlmICghbm9Eb3dubG9hZCkge1xyXG4gICAgICAgICAgcmVzcG9uc2UuYXR0YWNobWVudChvdXRmaWxlKTtcclxuICAgICAgICB9XHJcblxyXG4gICAgICAgIC8vIElmIFNWRywgcmV0dXJuIHBsYWluIGNvbnRlbnQsIG90aGVyd2lzZSBhIGI2NCBzdHJpbmcgZnJvbSBhIGJ1ZmZlclxyXG4gICAgICAgIHJldHVybiB0eXBlID09PSAnc3ZnJ1xyXG4gICAgICAgICAgPyByZXNwb25zZS5zZW5kKGRhdGEucmVzdWx0KVxyXG4gICAgICAgICAgOiByZXNwb25zZS5zZW5kKEJ1ZmZlci5mcm9tKGRhdGEucmVzdWx0LCAnYmFzZTY0JykpO1xyXG4gICAgICB9XHJcbiAgICB9KTtcclxuICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgcmV0dXJuIG5leHQoZXJyb3IpO1xyXG4gIH1cclxufVxyXG5cclxuLyoqXHJcbiAqIEFkZHMgdGhlIGBleHBvcnRgIHJvdXRlcy5cclxuICpcclxuICogQGZ1bmN0aW9uIGV4cG9ydFJvdXRlc1xyXG4gKlxyXG4gKiBAcGFyYW0ge0V4cHJlc3N9IGFwcCAtIFRoZSBFeHByZXNzIGFwcCBpbnN0YW5jZS5cclxuICovXHJcbmV4cG9ydCBkZWZhdWx0IGZ1bmN0aW9uIGV4cG9ydFJvdXRlcyhhcHApIHtcclxuICAvKipcclxuICAgKiBBZGRzIHRoZSBQT1NUICcvJyAtIEEgcm91dGUgZm9yIGhhbmRsaW5nIFBPU1QgcmVxdWVzdHMgYXQgdGhlIHJvb3RcclxuICAgKiBlbmRwb2ludC5cclxuICAgKi9cclxuICBhcHAucG9zdCgnLycsIHJlcXVlc3RFeHBvcnQpO1xyXG5cclxuICAvKipcclxuICAgKiBBZGRzIHRoZSBQT1NUICcvOmZpbGVuYW1lJyAtIEEgcm91dGUgZm9yIGhhbmRsaW5nIFBPU1QgcmVxdWVzdHMgd2l0aFxyXG4gICAqIGEgc3BlY2lmaWVkIGZpbGVuYW1lIHBhcmFtZXRlci5cclxuICAgKi9cclxuICBhcHAucG9zdCgnLzpmaWxlbmFtZScsIHJlcXVlc3RFeHBvcnQpO1xyXG59XHJcbiIsIi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXHJcblxyXG5IaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXJcclxuXHJcbkNvcHlyaWdodCAoYykgMjAxNi0yMDI1LCBIaWdoc29mdFxyXG5cclxuTGljZW5jZWQgdW5kZXIgdGhlIE1JVCBsaWNlbmNlLlxyXG5cclxuQWRkaXRpb25hbGx5IGEgdmFsaWQgSGlnaGNoYXJ0cyBsaWNlbnNlIGlzIHJlcXVpcmVkIGZvciB1c2UuXHJcblxyXG5TZWUgTElDRU5TRSBmaWxlIGluIHJvb3QgZm9yIGRldGFpbHMuXHJcblxyXG4qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xyXG5cclxuLyoqXHJcbiAqIEBvdmVydmlldyBEZWZpbmVzIGFuIEV4cHJlc3Mgcm91dGUgZm9yIHNlcnZlciBoZWFsdGggbW9uaXRvcmluZywgaW5jbHVkaW5nXHJcbiAqIHVwdGltZSwgc3VjY2VzcyByYXRlcywgYW5kIG90aGVyIHNlcnZlciBzdGF0aXN0aWNzLlxyXG4gKi9cclxuXHJcbmltcG9ydCB7IHJlYWRGaWxlU3luYyB9IGZyb20gJ2ZzJztcclxuaW1wb3J0IHsgam9pbiB9IGZyb20gJ3BhdGgnO1xyXG5cclxuaW1wb3J0IHsgZ2V0SGlnaGNoYXJ0c1ZlcnNpb24gfSBmcm9tICcuLi8uLi9jYWNoZS5qcyc7XHJcbmltcG9ydCB7IGxvZyB9IGZyb20gJy4uLy4uL2xvZ2dlci5qcyc7XHJcbmltcG9ydCB7IGdldFBvb2xTdGF0cywgZ2V0UG9vbEluZm9KU09OIH0gZnJvbSAnLi4vLi4vcG9vbC5qcyc7XHJcbmltcG9ydCB7IGFkZFRpbWVyIH0gZnJvbSAnLi4vLi4vdGltZXIuanMnO1xyXG5pbXBvcnQgeyBfX2Rpcm5hbWUsIGdldE5ld0RhdGVUaW1lIH0gZnJvbSAnLi4vLi4vdXRpbHMuanMnO1xyXG5cclxuLy8gU2V0IHRoZSBzdGFydCBkYXRlIG9mIHRoZSBzZXJ2ZXJcclxuY29uc3Qgc2VydmVyU3RhcnRUaW1lID0gbmV3IERhdGUoKTtcclxuXHJcbi8vIEdldCB0aGUgYHBhY2thZ2UuanNvbmAgY29udGVudFxyXG5jb25zdCBwYWNrYWdlRmlsZSA9IEpTT04ucGFyc2UocmVhZEZpbGVTeW5jKGpvaW4oX19kaXJuYW1lLCAncGFja2FnZS5qc29uJykpKTtcclxuXHJcbi8vIEFuIGFycmF5IGZvciBzdWNjZXNzIHJhdGUgcmF0aW9zXHJcbmNvbnN0IHN1Y2Nlc3NSYXRlcyA9IFtdO1xyXG5cclxuLy8gUmVjb3JkIGV2ZXJ5IG1pbnV0ZVxyXG5jb25zdCByZWNvcmRJbnRlcnZhbCA9IDYwICogMTAwMDtcclxuXHJcbi8vIDMwIG1pbnV0ZXNcclxuY29uc3Qgd2luZG93U2l6ZSA9IDMwO1xyXG5cclxuLyoqXHJcbiAqIENhbGN1bGF0ZXMgbW92aW5nIGF2ZXJhZ2UgaW5kaWNhdG9yIGJhc2VkIG9uIHRoZSBkYXRhIGZyb20gdGhlIGBzdWNjZXNzUmF0ZXNgXHJcbiAqIGFycmF5LlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gX2NhbGN1bGF0ZU1vdmluZ0F2ZXJhZ2VcclxuICpcclxuICogQHJldHVybnMge251bWJlcn0gQSBtb3ZpbmcgYXZlcmFnZSBmb3Igc3VjY2VzcyByYXRpbyBvZiB0aGUgc2VydmVyIGV4cG9ydHMuXHJcbiAqL1xyXG5mdW5jdGlvbiBfY2FsY3VsYXRlTW92aW5nQXZlcmFnZSgpIHtcclxuICByZXR1cm4gc3VjY2Vzc1JhdGVzLnJlZHVjZSgoYSwgYikgPT4gYSArIGIsIDApIC8gc3VjY2Vzc1JhdGVzLmxlbmd0aDtcclxufVxyXG5cclxuLyoqXHJcbiAqIFN0YXJ0cyB0aGUgaW50ZXJ2YWwgcmVzcG9uc2libGUgZm9yIGNhbGN1bGF0aW5nIGN1cnJlbnQgc3VjY2VzcyByYXRlIHJhdGlvXHJcbiAqIGFuZCBjb2xsZWN0cyByZWNvcmRzIHRvIHRoZSBgc3VjY2Vzc1JhdGVzYCBhcnJheS5cclxuICpcclxuICogQGZ1bmN0aW9uIF9zdGFydFN1Y2Nlc3NSYXRlXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtOb2RlSlMuVGltZW91dH0gSWQgb2YgYW4gaW50ZXJ2YWwuXHJcbiAqL1xyXG5mdW5jdGlvbiBfc3RhcnRTdWNjZXNzUmF0ZSgpIHtcclxuICByZXR1cm4gc2V0SW50ZXJ2YWwoKCkgPT4ge1xyXG4gICAgY29uc3Qgc3RhdHMgPSBnZXRQb29sU3RhdHMoKTtcclxuICAgIGNvbnN0IHN1Y2Nlc3NSYXRpbyA9XHJcbiAgICAgIHN0YXRzLmV4cG9ydHNBdHRlbXB0ZWQgPT09IDBcclxuICAgICAgICA/IDFcclxuICAgICAgICA6IChzdGF0cy5leHBvcnRzUGVyZm9ybWVkIC8gc3RhdHMuZXhwb3J0c0F0dGVtcHRlZCkgKiAxMDA7XHJcblxyXG4gICAgc3VjY2Vzc1JhdGVzLnB1c2goc3VjY2Vzc1JhdGlvKTtcclxuICAgIGlmIChzdWNjZXNzUmF0ZXMubGVuZ3RoID4gd2luZG93U2l6ZSkge1xyXG4gICAgICBzdWNjZXNzUmF0ZXMuc2hpZnQoKTtcclxuICAgIH1cclxuICB9LCByZWNvcmRJbnRlcnZhbCk7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBBZGRzIHRoZSBgaGVhbHRoYCByb3V0ZXMuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBoZWFsdGhSb3V0ZXNcclxuICpcclxuICogQHBhcmFtIHtFeHByZXNzfSBhcHAgLSBUaGUgRXhwcmVzcyBhcHAgaW5zdGFuY2UuXHJcbiAqL1xyXG5leHBvcnQgZGVmYXVsdCBmdW5jdGlvbiBoZWFsdGhSb3V0ZXMoYXBwKSB7XHJcbiAgLy8gU3RhcnQgcHJvY2Vzc2luZyBzdWNjZXNzIHJhdGUgcmF0aW8gaW50ZXJ2YWwgYW5kIHNhdmUgaXRzIGlkIHRvIHRoZSBhcnJheVxyXG4gIC8vIGZvciB0aGUgZ3JhY2VmdWwgY2xlYXJpbmcgb24gc2h1dGRvd24gd2l0aCBpbmplY3RlZCBgYWRkVGltZXJgIGZ1bnRpb25cclxuICBhZGRUaW1lcihfc3RhcnRTdWNjZXNzUmF0ZSgpKTtcclxuXHJcbiAgLyoqXHJcbiAgICogQWRkcyB0aGUgR0VUICcvaGVhbHRoJyAtIEEgcm91dGUgZm9yIGdldHRpbmcgdGhlIGJhc2ljIHN0YXRzIG9mIHRoZSBzZXJ2ZXIuXHJcbiAgICovXHJcbiAgYXBwLmdldCgnL2hlYWx0aCcsIChyZXF1ZXN0LCByZXNwb25zZSwgbmV4dCkgPT4ge1xyXG4gICAgdHJ5IHtcclxuICAgICAgbG9nKDQsICdbaGVhbHRoXSBSZXR1cm5pbmcgc2VydmVyIGhlYWx0aC4nKTtcclxuXHJcbiAgICAgIGNvbnN0IHN0YXRzID0gZ2V0UG9vbFN0YXRzKCk7XHJcbiAgICAgIGNvbnN0IHBlcmlvZCA9IHN1Y2Nlc3NSYXRlcy5sZW5ndGg7XHJcbiAgICAgIGNvbnN0IG1vdmluZ0F2ZXJhZ2UgPSBfY2FsY3VsYXRlTW92aW5nQXZlcmFnZSgpO1xyXG5cclxuICAgICAgLy8gU2VuZCB0aGUgc2VydmVyJ3Mgc3RhdGlzdGljc1xyXG4gICAgICByZXNwb25zZS5zZW5kKHtcclxuICAgICAgICAvLyBTdGF0dXMgYW5kIHRpbWVzXHJcbiAgICAgICAgc3RhdHVzOiAnT0snLFxyXG4gICAgICAgIGJvb3RUaW1lOiBzZXJ2ZXJTdGFydFRpbWUsXHJcbiAgICAgICAgdXB0aW1lOiBgJHtNYXRoLmZsb29yKChnZXROZXdEYXRlVGltZSgpIC0gc2VydmVyU3RhcnRUaW1lLmdldFRpbWUoKSkgLyAxMDAwIC8gNjApfSBtaW51dGVzYCxcclxuXHJcbiAgICAgICAgLy8gVmVyc2lvbnNcclxuICAgICAgICBzZXJ2ZXJWZXJzaW9uOiBwYWNrYWdlRmlsZS52ZXJzaW9uLFxyXG4gICAgICAgIGhpZ2hjaGFydHNWZXJzaW9uOiBnZXRIaWdoY2hhcnRzVmVyc2lvbigpLFxyXG5cclxuICAgICAgICAvLyBFeHBvcnRzXHJcbiAgICAgICAgYXZlcmFnZUV4cG9ydFRpbWU6IHN0YXRzLnRpbWVTcGVudEF2ZXJhZ2UsXHJcbiAgICAgICAgYXR0ZW1wdGVkRXhwb3J0czogc3RhdHMuZXhwb3J0c0F0dGVtcHRlZCxcclxuICAgICAgICBwZXJmb3JtZWRFeHBvcnRzOiBzdGF0cy5leHBvcnRzUGVyZm9ybWVkLFxyXG4gICAgICAgIGZhaWxlZEV4cG9ydHM6IHN0YXRzLmV4cG9ydHNEcm9wcGVkLFxyXG4gICAgICAgIHN1Y2Vzc1JhdGlvOiAoc3RhdHMuZXhwb3J0c1BlcmZvcm1lZCAvIHN0YXRzLmV4cG9ydHNBdHRlbXB0ZWQpICogMTAwLFxyXG5cclxuICAgICAgICAvLyBQb29sXHJcbiAgICAgICAgcG9vbDogZ2V0UG9vbEluZm9KU09OKCksXHJcblxyXG4gICAgICAgIC8vIE1vdmluZyBhdmVyYWdlXHJcbiAgICAgICAgcGVyaW9kLFxyXG4gICAgICAgIG1vdmluZ0F2ZXJhZ2UsXHJcbiAgICAgICAgbWVzc2FnZTpcclxuICAgICAgICAgIGlzTmFOKG1vdmluZ0F2ZXJhZ2UpIHx8ICFzdWNjZXNzUmF0ZXMubGVuZ3RoXHJcbiAgICAgICAgICAgID8gJ1RvbyBlYXJseSB0byByZXBvcnQuIE5vIGV4cG9ydHMgbWFkZSB5ZXQuIFBsZWFzZSBjaGVjayBiYWNrIHNvb24uJ1xyXG4gICAgICAgICAgICA6IGBMYXN0ICR7cGVyaW9kfSBtaW51dGVzIGhhZCBhIHN1Y2Nlc3MgcmF0ZSBvZiAke21vdmluZ0F2ZXJhZ2UudG9GaXhlZCgyKX0lLmAsXHJcblxyXG4gICAgICAgIC8vIFNWRyBhbmQgSlNPTiBleHBvcnRzXHJcbiAgICAgICAgc3ZnRXhwb3J0czogc3RhdHMuZXhwb3J0c0Zyb21TdmcsXHJcbiAgICAgICAganNvbkV4cG9ydHM6IHN0YXRzLmV4cG9ydHNGcm9tT3B0aW9ucyxcclxuICAgICAgICBzdmdFeHBvcnRzQXR0ZW1wdHM6IHN0YXRzLmV4cG9ydHNGcm9tU3ZnQXR0ZW1wdHMsXHJcbiAgICAgICAganNvbkV4cG9ydHNBdHRlbXB0czogc3RhdHMuZXhwb3J0c0Zyb21PcHRpb25zQXR0ZW1wdHNcclxuICAgICAgfSk7XHJcbiAgICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgICByZXR1cm4gbmV4dChlcnJvcik7XHJcbiAgICB9XHJcbiAgfSk7XHJcbn1cclxuIiwiLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcclxuXHJcbkhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlclxyXG5cclxuQ29weXJpZ2h0IChjKSAyMDE2LTIwMjUsIEhpZ2hzb2Z0XHJcblxyXG5MaWNlbmNlZCB1bmRlciB0aGUgTUlUIGxpY2VuY2UuXHJcblxyXG5BZGRpdGlvbmFsbHkgYSB2YWxpZCBIaWdoY2hhcnRzIGxpY2Vuc2UgaXMgcmVxdWlyZWQgZm9yIHVzZS5cclxuXHJcblNlZSBMSUNFTlNFIGZpbGUgaW4gcm9vdCBmb3IgZGV0YWlscy5cclxuXHJcbioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXHJcblxyXG4vKipcclxuICogQG92ZXJ2aWV3IERlZmluZXMgYW4gRXhwcmVzcyByb3V0ZSBmb3Igc2VydmluZyB0aGUgVUkgZm9yIHRoZSBleHBvcnQgc2VydmVyXHJcbiAqIHdoZW4gZW5hYmxlZC5cclxuICovXHJcblxyXG5pbXBvcnQgeyBqb2luIH0gZnJvbSAncGF0aCc7XHJcblxyXG5pbXBvcnQgeyBnZXRPcHRpb25zIH0gZnJvbSAnLi4vLi4vY29uZmlnLmpzJztcclxuaW1wb3J0IHsgX19kaXJuYW1lIH0gZnJvbSAnLi4vLi4vdXRpbHMuanMnO1xyXG5cclxuLyoqXHJcbiAqIEFkZHMgdGhlIGB1aWAgcm91dGVzLlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gdWlSb3V0ZXNcclxuICpcclxuICogQHBhcmFtIHtFeHByZXNzfSBhcHAgLSBUaGUgRXhwcmVzcyBhcHAgaW5zdGFuY2UuXHJcbiAqL1xyXG5leHBvcnQgZGVmYXVsdCBmdW5jdGlvbiB1aVJvdXRlcyhhcHApIHtcclxuICAvKipcclxuICAgKiBBZGRzIHRoZSBHRVQgJy8nIC0gQSByb3V0ZSBmb3IgYSBVSSB3aGVuIGVuYWJsZWQgb24gdGhlIGV4cG9ydCBzZXJ2ZXIuXHJcbiAgICovXHJcbiAgYXBwLmdldChnZXRPcHRpb25zKCkudWkucm91dGUgfHwgJy8nLCAocmVxdWVzdCwgcmVzcG9uc2UsIG5leHQpID0+IHtcclxuICAgIHRyeSB7XHJcbiAgICAgIHJlc3BvbnNlLnNlbmRGaWxlKGpvaW4oX19kaXJuYW1lLCAncHVibGljJywgJ2luZGV4Lmh0bWwnKSwge1xyXG4gICAgICAgIGFjY2VwdFJhbmdlczogZmFsc2VcclxuICAgICAgfSk7XHJcbiAgICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgICByZXR1cm4gbmV4dChlcnJvcik7XHJcbiAgICB9XHJcbiAgfSk7XHJcbn1cclxuIiwiLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcclxuXHJcbkhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlclxyXG5cclxuQ29weXJpZ2h0IChjKSAyMDE2LTIwMjUsIEhpZ2hzb2Z0XHJcblxyXG5MaWNlbmNlZCB1bmRlciB0aGUgTUlUIGxpY2VuY2UuXHJcblxyXG5BZGRpdGlvbmFsbHkgYSB2YWxpZCBIaWdoY2hhcnRzIGxpY2Vuc2UgaXMgcmVxdWlyZWQgZm9yIHVzZS5cclxuXHJcblNlZSBMSUNFTlNFIGZpbGUgaW4gcm9vdCBmb3IgZGV0YWlscy5cclxuXHJcbioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXHJcblxyXG4vKipcclxuICogQG92ZXJ2aWV3IERlZmluZXMgYW4gRXhwcmVzcyByb3V0ZSBmb3IgdXBkYXRpbmcgdGhlIEhpZ2hjaGFydHMgdmVyc2lvblxyXG4gKiBvbiB0aGUgc2VydmVyLCB3aXRoIGF1dGhlbnRpY2F0aW9uIGFuZCB2YWxpZGF0aW9uLlxyXG4gKi9cclxuXHJcbmltcG9ydCB7IHVwZGF0ZUhpZ2hjaGFydHNWZXJzaW9uLCBnZXRIaWdoY2hhcnRzVmVyc2lvbiB9IGZyb20gJy4uLy4uL2NhY2hlLmpzJztcclxuaW1wb3J0IHsgZW52cyB9IGZyb20gJy4uLy4uL2VudnMuanMnO1xyXG5cclxuaW1wb3J0IEh0dHBFcnJvciBmcm9tICcuLi8uLi9lcnJvcnMvSHR0cEVycm9yLmpzJztcclxuXHJcbi8qKlxyXG4gKiBBZGRzIHRoZSBgdmVyc2lvbl9jaGFuZ2VgIHJvdXRlcy5cclxuICpcclxuICogQGZ1bmN0aW9uIHZlcnNpb25DaGFuZ2VSb3V0ZXNcclxuICpcclxuICogQHBhcmFtIHtFeHByZXNzfSBhcHAgLSBUaGUgRXhwcmVzcyBhcHAgaW5zdGFuY2UuXHJcbiAqL1xyXG5leHBvcnQgZGVmYXVsdCBmdW5jdGlvbiB2ZXJzaW9uQ2hhbmdlUm91dGVzKGFwcCkge1xyXG4gIC8qKlxyXG4gICAqIEFkZHMgdGhlIFBPU1QgJy92ZXJzaW9uX2NoYW5nZS86bmV3VmVyc2lvbicgLSBBIHJvdXRlIGZvciBjaGFuZ2luZ1xyXG4gICAqIHRoZSBIaWdoY2hhcnRzIHZlcnNpb24gb24gdGhlIHNlcnZlci5cclxuICAgKi9cclxuICBhcHAucG9zdCgnL3ZlcnNpb25fY2hhbmdlLzpuZXdWZXJzaW9uJywgYXN5bmMgKHJlcXVlc3QsIHJlc3BvbnNlLCBuZXh0KSA9PiB7XHJcbiAgICB0cnkge1xyXG4gICAgICAvLyBHZXQgdGhlIHRva2VuIGRpcmVjdGx5IGZyb20gZW52c1xyXG4gICAgICBjb25zdCBhZG1pblRva2VuID0gZW52cy5ISUdIQ0hBUlRTX0FETUlOX1RPS0VOO1xyXG5cclxuICAgICAgLy8gQ2hlY2sgdGhlIGV4aXN0ZW5jZSBvZiB0aGUgdG9rZW5cclxuICAgICAgaWYgKCFhZG1pblRva2VuIHx8ICFhZG1pblRva2VuLmxlbmd0aCkge1xyXG4gICAgICAgIHRocm93IG5ldyBIdHRwRXJyb3IoXHJcbiAgICAgICAgICAnW3ZlcnNpb25dIFRoZSBzZXJ2ZXIgaXMgbm90IGNvbmZpZ3VyZWQgdG8gcGVyZm9ybSBydW4tdGltZSB2ZXJzaW9uIGNoYW5nZXM6IEhJR0hDSEFSVFNfQURNSU5fVE9LRU4gaXMgbm90IHNldC4nLFxyXG4gICAgICAgICAgNDAxXHJcbiAgICAgICAgKTtcclxuICAgICAgfVxyXG5cclxuICAgICAgLy8gR2V0IHRoZSB0b2tlbiBmcm9tIHRoZSBoYy1hdXRoIGhlYWRlclxyXG4gICAgICBjb25zdCB0b2tlbiA9IHJlcXVlc3QuZ2V0KCdoYy1hdXRoJyk7XHJcblxyXG4gICAgICAvLyBDaGVjayBpZiB0aGUgaGMtYXV0aCBoZWFkZXIgY29udGFpbiBhIGNvcnJlY3QgdG9rZW5cclxuICAgICAgaWYgKCF0b2tlbiB8fCB0b2tlbiAhPT0gYWRtaW5Ub2tlbikge1xyXG4gICAgICAgIHRocm93IG5ldyBIdHRwRXJyb3IoXHJcbiAgICAgICAgICAnW3ZlcnNpb25dIEludmFsaWQgb3IgbWlzc2luZyB0b2tlbjogU2V0IHRoZSB0b2tlbiBpbiB0aGUgaGMtYXV0aCBoZWFkZXIuJyxcclxuICAgICAgICAgIDQwMVxyXG4gICAgICAgICk7XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIC8vIENvbXBhcmUgdmVyc2lvbnNcclxuICAgICAgY29uc3QgbmV3VmVyc2lvbiA9IHJlcXVlc3QucGFyYW1zLm5ld1ZlcnNpb247XHJcbiAgICAgIGlmIChuZXdWZXJzaW9uKSB7XHJcbiAgICAgICAgdHJ5IHtcclxuICAgICAgICAgIC8vIFVwZGF0ZSB2ZXJzaW9uXHJcbiAgICAgICAgICBhd2FpdCB1cGRhdGVIaWdoY2hhcnRzVmVyc2lvbihuZXdWZXJzaW9uKTtcclxuICAgICAgICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgICAgICAgdGhyb3cgbmV3IEh0dHBFcnJvcihcclxuICAgICAgICAgICAgYFt2ZXJzaW9uXSBWZXJzaW9uIGNoYW5nZTogJHtlcnJvci5tZXNzYWdlfWAsXHJcbiAgICAgICAgICAgIDQwMFxyXG4gICAgICAgICAgKS5zZXRFcnJvcihlcnJvcik7XHJcbiAgICAgICAgfVxyXG5cclxuICAgICAgICAvLyBTdWNjZXNzXHJcbiAgICAgICAgcmVzcG9uc2Uuc3RhdHVzKDIwMCkuc2VuZCh7XHJcbiAgICAgICAgICBzdGF0dXNDb2RlOiAyMDAsXHJcbiAgICAgICAgICBoaWdoY2hhcnRzVmVyc2lvbjogZ2V0SGlnaGNoYXJ0c1ZlcnNpb24oKSxcclxuICAgICAgICAgIG1lc3NhZ2U6IGBTdWNjZXNzZnVsbHkgdXBkYXRlZCBIaWdoY2hhcnRzIHRvIHZlcnNpb246ICR7bmV3VmVyc2lvbn0uYFxyXG4gICAgICAgIH0pO1xyXG4gICAgICB9IGVsc2Uge1xyXG4gICAgICAgIC8vIE5vIHZlcnNpb24gc3BlY2lmaWVkXHJcbiAgICAgICAgdGhyb3cgbmV3IEh0dHBFcnJvcignW3ZlcnNpb25dIE5vIG5ldyB2ZXJzaW9uIHN1cHBsaWVkLicsIDQwMCk7XHJcbiAgICAgIH1cclxuICAgIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICAgIHJldHVybiBuZXh0KGVycm9yKTtcclxuICAgIH1cclxuICB9KTtcclxufVxyXG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxyXG5cclxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXHJcblxyXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNSwgSGlnaHNvZnRcclxuXHJcbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cclxuXHJcbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxyXG5cclxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxyXG5cclxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cclxuXHJcbi8qKlxyXG4gKiBAb3ZlcnZpZXcgQSBtb2R1bGUgdGhhdCBzZXRzIHVwIGFuZCBtYW5hZ2VzIEhUVFAgYW5kIEhUVFBTIHNlcnZlcnNcclxuICogZm9yIHRoZSBIaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXIuIEl0IGhhbmRsZXMgc2VydmVyIGluaXRpYWxpemF0aW9uLFxyXG4gKiBjb25maWd1cmF0aW9uLCBlcnJvciBoYW5kbGluZywgbWlkZGxld2FyZSBzZXR1cCwgcm91dGUgZGVmaW5pdGlvbiwgYW5kIHJhdGVcclxuICogbGltaXRpbmcuIFRoZSBtb2R1bGUgZXhwb3J0cyBmdW5jdGlvbnMgdG8gc3RhcnQsIHN0b3AsIGFuZCBtYW5hZ2Ugc2VydmVyXHJcbiAqIGluc3RhbmNlcywgYXMgd2VsbCBhcyB1dGlsaXR5IGZ1bmN0aW9ucyBmb3IgZGVmaW5pbmcgcm91dGVzIGFuZCBhdHRhY2hpbmdcclxuICogbWlkZGxld2FyZXMuXHJcbiAqL1xyXG5cclxuaW1wb3J0IHsgcmVhZEZpbGUgfSBmcm9tICdmcy9wcm9taXNlcyc7XHJcbmltcG9ydCB7IGpvaW4gfSBmcm9tICdwYXRoJztcclxuXHJcbmltcG9ydCBjb3JzIGZyb20gJ2NvcnMnO1xyXG5pbXBvcnQgZXhwcmVzcyBmcm9tICdleHByZXNzJztcclxuaW1wb3J0IGh0dHAgZnJvbSAnaHR0cCc7XHJcbmltcG9ydCBodHRwcyBmcm9tICdodHRwcyc7XHJcbmltcG9ydCBtdWx0ZXIgZnJvbSAnbXVsdGVyJztcclxuXHJcbmltcG9ydCB7IGdldE9wdGlvbnMgfSBmcm9tICcuLi9jb25maWcuanMnO1xyXG5pbXBvcnQgeyBsb2csIGxvZ1dpdGhTdGFjayB9IGZyb20gJy4uL2xvZ2dlci5qcyc7XHJcbmltcG9ydCB7IF9fZGlybmFtZSwgZ2V0QWJzb2x1dGVQYXRoIH0gZnJvbSAnLi4vdXRpbHMuanMnO1xyXG5cclxuaW1wb3J0IGVycm9yTWlkZGxld2FyZSBmcm9tICcuL21pZGRsZXdhcmVzL2Vycm9yLmpzJztcclxuaW1wb3J0IHJhdGVMaW1pdGluZ01pZGRsZXdhcmUgZnJvbSAnLi9taWRkbGV3YXJlcy9yYXRlTGltaXRpbmcuanMnO1xyXG5pbXBvcnQgdmFsaWRhdGlvbk1pZGRsZXdhcmUgZnJvbSAnLi9taWRkbGV3YXJlcy92YWxpZGF0aW9uLmpzJztcclxuXHJcbmltcG9ydCBleHBvcnRSb3V0ZXMgZnJvbSAnLi9yb3V0ZXMvZXhwb3J0LmpzJztcclxuaW1wb3J0IGhlYWx0aFJvdXRlcyBmcm9tICcuL3JvdXRlcy9oZWFsdGguanMnO1xyXG5pbXBvcnQgdWlSb3V0ZXMgZnJvbSAnLi9yb3V0ZXMvdWkuanMnO1xyXG5pbXBvcnQgdmVyc2lvbkNoYW5nZVJvdXRlcyBmcm9tICcuL3JvdXRlcy92ZXJzaW9uQ2hhbmdlLmpzJztcclxuXHJcbmltcG9ydCBFeHBvcnRFcnJvciBmcm9tICcuLi9lcnJvcnMvRXhwb3J0RXJyb3IuanMnO1xyXG5cclxuLy8gQXJyYXkgb2YgYW4gYWN0aXZlIHNlcnZlcnNcclxuY29uc3QgYWN0aXZlU2VydmVycyA9IG5ldyBNYXAoKTtcclxuXHJcbi8vIENyZWF0ZSBleHByZXNzIGFwcFxyXG5jb25zdCBhcHAgPSBleHByZXNzKCk7XHJcblxyXG4vKipcclxuICogU3RhcnRzIEhUVFAgb3IvYW5kIEhUVFBTIHNlcnZlciBiYXNlZCBvbiB0aGUgcHJvdmlkZWQgY29uZmlndXJhdGlvbi5cclxuICogVGhlIGBzZXJ2ZXJPcHRpb25zYCBvYmplY3QgY29udGFpbnMgYWxsIHNlcnZlciByZWxhdGVkIHByb3BlcnRpZXMgKHNlZVxyXG4gKiB0aGUgYHNlcnZlcmAgc2VjdGlvbiBpbiB0aGUgYGxpYi9zY2hlbWFzL2NvbmZpZy5qc2AgZmlsZSBmb3IgYSByZWZlcmVuY2UpLlxyXG4gKlxyXG4gKiBAYXN5bmNcclxuICogQGZ1bmN0aW9uIHN0YXJ0U2VydmVyXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBbc2VydmVyT3B0aW9ucz1nZXRPcHRpb25zKCkuc2VydmVyXSAtIE9iamVjdCBjb250YWluaW5nXHJcbiAqIGBzZXJ2ZXJgIG9wdGlvbnMuIFRoZSBkZWZhdWx0IHZhbHVlIGlzIHRoZSBnbG9iYWwgc2VydmVyIG9wdGlvbnNcclxuICogb2YgdGhlIGV4cG9ydCBzZXJ2ZXIgaW5zdGFuY2UuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtQcm9taXNlPHZvaWQ+fSBBIFByb21pc2UgdGhhdCByZXNvbHZlcyB0byBlbmRpbmcgdGhlIGZ1bmN0aW9uXHJcbiAqIGV4ZWN1dGlvbiB3aGVuIHRoZSBzZXJ2ZXIgc2hvdWxkIG5vdCBiZSBlbmFibGVkIG9yIHdoZW4gbm8gdmFsaWQgRXhwcmVzcyBhcHBcclxuICogaXMgZm91bmQuXHJcbiAqXHJcbiAqIEB0aHJvd3Mge0V4cG9ydEVycm9yfSBUaHJvd3MgYW4gYEV4cG9ydEVycm9yYCBpZiB0aGUgc2VydmVyIGNhbm5vdFxyXG4gKiBiZSBjb25maWd1cmVkIGFuZCBzdGFydGVkLlxyXG4gKi9cclxuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIHN0YXJ0U2VydmVyKHNlcnZlck9wdGlvbnMgPSBnZXRPcHRpb25zKCkuc2VydmVyKSB7XHJcbiAgdHJ5IHtcclxuICAgIC8vIFN0b3AgaWYgbm90IGVuYWJsZWRcclxuICAgIGlmICghc2VydmVyT3B0aW9ucy5lbmFibGUgfHwgIWFwcCkge1xyXG4gICAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoXHJcbiAgICAgICAgJ1tzZXJ2ZXJdIFNlcnZlciBjYW5ub3QgYmUgc3RhcnRlZCAobm90IGVuYWJsZWQgb3Igbm8gY29ycmVjdCBFeHByZXNzIGFwcCBmb3VuZCkuJyxcclxuICAgICAgICA1MDBcclxuICAgICAgKTtcclxuICAgIH1cclxuXHJcbiAgICAvLyBUb28gYmlnIGxpbWl0cyBsZWFkIHRvIHRpbWVvdXRzIGluIHRoZSBleHBvcnQgcHJvY2VzcyB3aGVuXHJcbiAgICAvLyB0aGUgcmFzdGVyaXphdGlvbiB0aW1lb3V0IGlzIHNldCB0b28gbG93XHJcbiAgICBjb25zdCB1cGxvYWRMaW1pdEJ5dGVzID0gc2VydmVyT3B0aW9ucy51cGxvYWRMaW1pdCAqIDEwMjQgKiAxMDI0O1xyXG5cclxuICAgIC8vIE1lbW9yeSBzdG9yYWdlIGZvciBtdWx0ZXIgcGFja2FnZVxyXG4gICAgY29uc3Qgc3RvcmFnZSA9IG11bHRlci5tZW1vcnlTdG9yYWdlKCk7XHJcblxyXG4gICAgLy8gRW5hYmxlIHBhcnNpbmcgb2YgZm9ybSBkYXRhIChmaWxlcykgd2l0aCBtdWx0ZXIgcGFja2FnZVxyXG4gICAgY29uc3QgdXBsb2FkID0gbXVsdGVyKHtcclxuICAgICAgc3RvcmFnZSxcclxuICAgICAgbGltaXRzOiB7XHJcbiAgICAgICAgZmllbGRTaXplOiB1cGxvYWRMaW1pdEJ5dGVzXHJcbiAgICAgIH1cclxuICAgIH0pO1xyXG5cclxuICAgIC8vIERpc2FibGUgdGhlIFgtUG93ZXJlZC1CeSBoZWFkZXJcclxuICAgIGFwcC5kaXNhYmxlKCd4LXBvd2VyZWQtYnknKTtcclxuXHJcbiAgICAvLyBFbmFibGUgQ09SUyBzdXBwb3J0XHJcbiAgICBhcHAudXNlKFxyXG4gICAgICBjb3JzKHtcclxuICAgICAgICBtZXRob2RzOiBbJ1BPU1QnLCAnR0VUJywgJ09QVElPTlMnXVxyXG4gICAgICB9KVxyXG4gICAgKTtcclxuXHJcbiAgICAvLyBHZXR0aW5nIGEgbG90IG9mIGBSYW5nZU5vdFNhdGlzZmlhYmxlRXJyb3JgIGV4Y2VwdGlvbnMgKGV2ZW4gdGhvdWdoIHRoaXNcclxuICAgIC8vIGlzIGEgZGVwcmVjYXRlZCBvcHRpb25zLCBsZXQncyB0cnkgdG8gc2V0IGl0IHRvIGZhbHNlKVxyXG4gICAgYXBwLnVzZSgocmVxdWVzdCwgcmVzcG9uc2UsIG5leHQpID0+IHtcclxuICAgICAgcmVzcG9uc2Uuc2V0KCdBY2NlcHQtUmFuZ2VzJywgJ25vbmUnKTtcclxuICAgICAgbmV4dCgpO1xyXG4gICAgfSk7XHJcblxyXG4gICAgLy8gRW5hYmxlIGJvZHkgcGFyc2VyIGZvciBKU09OIGRhdGFcclxuICAgIGFwcC51c2UoXHJcbiAgICAgIGV4cHJlc3MuanNvbih7XHJcbiAgICAgICAgbGltaXQ6IHVwbG9hZExpbWl0Qnl0ZXNcclxuICAgICAgfSlcclxuICAgICk7XHJcblxyXG4gICAgLy8gRW5hYmxlIGJvZHkgcGFyc2VyIGZvciBVUkwtZW5jb2RlZCBmb3JtIGRhdGFcclxuICAgIGFwcC51c2UoXHJcbiAgICAgIGV4cHJlc3MudXJsZW5jb2RlZCh7XHJcbiAgICAgICAgZXh0ZW5kZWQ6IHRydWUsXHJcbiAgICAgICAgbGltaXQ6IHVwbG9hZExpbWl0Qnl0ZXNcclxuICAgICAgfSlcclxuICAgICk7XHJcblxyXG4gICAgLy8gVXNlIG9ubHkgbm9uLWZpbGUgbXVsdGlwYXJ0IGZvcm0gZmllbGRzXHJcbiAgICBhcHAudXNlKHVwbG9hZC5ub25lKCkpO1xyXG5cclxuICAgIC8vIFNldCB1cCBzdGF0aWMgZm9sZGVyJ3Mgcm91dGVcclxuICAgIGFwcC51c2UoZXhwcmVzcy5zdGF0aWMoam9pbihfX2Rpcm5hbWUsICdwdWJsaWMnKSkpO1xyXG5cclxuICAgIC8vIExpc3RlbiBIVFRQIHNlcnZlclxyXG4gICAgaWYgKCFzZXJ2ZXJPcHRpb25zLnNzbC5mb3JjZSkge1xyXG4gICAgICAvLyBNYWluIHNlcnZlciBpbnN0YW5jZSAoSFRUUClcclxuICAgICAgY29uc3QgaHR0cFNlcnZlciA9IGh0dHAuY3JlYXRlU2VydmVyKGFwcCk7XHJcblxyXG4gICAgICAvLyBBdHRhY2ggZXJyb3IgaGFuZGxlcnMgYW5kIGxpc3RlbiB0byB0aGUgc2VydmVyXHJcbiAgICAgIF9hdHRhY2hTZXJ2ZXJFcnJvckhhbmRsZXJzKGh0dHBTZXJ2ZXIpO1xyXG5cclxuICAgICAgLy8gTGlzdGVuXHJcbiAgICAgIGh0dHBTZXJ2ZXIubGlzdGVuKHNlcnZlck9wdGlvbnMucG9ydCwgc2VydmVyT3B0aW9ucy5ob3N0LCAoKSA9PiB7XHJcbiAgICAgICAgLy8gU2F2ZSB0aGUgcmVmZXJlbmNlIHRvIEhUVFAgc2VydmVyXHJcbiAgICAgICAgYWN0aXZlU2VydmVycy5zZXQoc2VydmVyT3B0aW9ucy5wb3J0LCBodHRwU2VydmVyKTtcclxuXHJcbiAgICAgICAgbG9nKFxyXG4gICAgICAgICAgMyxcclxuICAgICAgICAgIGBbc2VydmVyXSBTdGFydGVkIEhUVFAgc2VydmVyIG9uICR7c2VydmVyT3B0aW9ucy5ob3N0fToke3NlcnZlck9wdGlvbnMucG9ydH0uYFxyXG4gICAgICAgICk7XHJcbiAgICAgIH0pO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIExpc3RlbiBIVFRQUyBzZXJ2ZXJcclxuICAgIGlmIChzZXJ2ZXJPcHRpb25zLnNzbC5lbmFibGUpIHtcclxuICAgICAgLy8gU2V0IHVwIGFuIFNTTCBzZXJ2ZXIgYWxzb1xyXG4gICAgICBsZXQga2V5LCBjZXJ0O1xyXG5cclxuICAgICAgdHJ5IHtcclxuICAgICAgICAvLyBHZXQgdGhlIFNTTCBrZXlcclxuICAgICAgICBrZXkgPSBhd2FpdCByZWFkRmlsZShcclxuICAgICAgICAgIGpvaW4oZ2V0QWJzb2x1dGVQYXRoKHNlcnZlck9wdGlvbnMuc3NsLmNlcnRQYXRoKSwgJ3NlcnZlci5rZXknKSxcclxuICAgICAgICAgICd1dGY4J1xyXG4gICAgICAgICk7XHJcblxyXG4gICAgICAgIC8vIEdldCB0aGUgU1NMIGNlcnRpZmljYXRlXHJcbiAgICAgICAgY2VydCA9IGF3YWl0IHJlYWRGaWxlKFxyXG4gICAgICAgICAgam9pbihnZXRBYnNvbHV0ZVBhdGgoc2VydmVyT3B0aW9ucy5zc2wuY2VydFBhdGgpLCAnc2VydmVyLmNydCcpLFxyXG4gICAgICAgICAgJ3V0ZjgnXHJcbiAgICAgICAgKTtcclxuICAgICAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICAgICBsb2coXHJcbiAgICAgICAgICAyLFxyXG4gICAgICAgICAgYFtzZXJ2ZXJdIFVuYWJsZSB0byBsb2FkIGtleS9jZXJ0aWZpY2F0ZSBmcm9tIHRoZSAnJHtzZXJ2ZXJPcHRpb25zLnNzbC5jZXJ0UGF0aH0nIHBhdGguIENvdWxkIG5vdCBydW4gc2VjdXJlZCBsYXllciBzZXJ2ZXIuYFxyXG4gICAgICAgICk7XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIGlmIChrZXkgJiYgY2VydCkge1xyXG4gICAgICAgIC8vIE1haW4gc2VydmVyIGluc3RhbmNlIChIVFRQUylcclxuICAgICAgICBjb25zdCBodHRwc1NlcnZlciA9IGh0dHBzLmNyZWF0ZVNlcnZlcih7IGtleSwgY2VydCB9LCBhcHApO1xyXG5cclxuICAgICAgICAvLyBBdHRhY2ggZXJyb3IgaGFuZGxlcnMgYW5kIGxpc3RlbiB0byB0aGUgc2VydmVyXHJcbiAgICAgICAgX2F0dGFjaFNlcnZlckVycm9ySGFuZGxlcnMoaHR0cHNTZXJ2ZXIpO1xyXG5cclxuICAgICAgICAvLyBMaXN0ZW5cclxuICAgICAgICBodHRwc1NlcnZlci5saXN0ZW4oc2VydmVyT3B0aW9ucy5zc2wucG9ydCwgc2VydmVyT3B0aW9ucy5ob3N0LCAoKSA9PiB7XHJcbiAgICAgICAgICAvLyBTYXZlIHRoZSByZWZlcmVuY2UgdG8gSFRUUFMgc2VydmVyXHJcbiAgICAgICAgICBhY3RpdmVTZXJ2ZXJzLnNldChzZXJ2ZXJPcHRpb25zLnNzbC5wb3J0LCBodHRwc1NlcnZlcik7XHJcblxyXG4gICAgICAgICAgbG9nKFxyXG4gICAgICAgICAgICAzLFxyXG4gICAgICAgICAgICBgW3NlcnZlcl0gU3RhcnRlZCBIVFRQUyBzZXJ2ZXIgb24gJHtzZXJ2ZXJPcHRpb25zLmhvc3R9OiR7c2VydmVyT3B0aW9ucy5zc2wucG9ydH0uYFxyXG4gICAgICAgICAgKTtcclxuICAgICAgICB9KTtcclxuICAgICAgfVxyXG4gICAgfVxyXG5cclxuICAgIC8vIFNldCB1cCB0aGUgcmF0ZSBsaW1pdGVyXHJcbiAgICByYXRlTGltaXRpbmdNaWRkbGV3YXJlKGFwcCwgc2VydmVyT3B0aW9ucy5yYXRlTGltaXRpbmcpO1xyXG5cclxuICAgIC8vIFNldCB1cCB0aGUgdmFsaWRhdGlvbiBoYW5kbGVyXHJcbiAgICB2YWxpZGF0aW9uTWlkZGxld2FyZShhcHApO1xyXG5cclxuICAgIC8vIFNldCB1cCByb3V0ZXNcclxuICAgIGhlYWx0aFJvdXRlcyhhcHApO1xyXG4gICAgZXhwb3J0Um91dGVzKGFwcCk7XHJcbiAgICB1aVJvdXRlcyhhcHApO1xyXG4gICAgdmVyc2lvbkNoYW5nZVJvdXRlcyhhcHApO1xyXG5cclxuICAgIC8vIFNldCB1cCB0aGUgY2VudHJhbGl6ZWQgZXJyb3IgaGFuZGxlclxyXG4gICAgZXJyb3JNaWRkbGV3YXJlKGFwcCk7XHJcbiAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcihcclxuICAgICAgJ1tzZXJ2ZXJdIENvdWxkIG5vdCBjb25maWd1cmUgYW5kIHN0YXJ0IHRoZSBzZXJ2ZXIuJyxcclxuICAgICAgNTAwXHJcbiAgICApLnNldEVycm9yKGVycm9yKTtcclxuICB9XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBDbG9zZXMgYWxsIHNlcnZlcnMgYXNzb2NpYXRlZCB3aXRoIEV4cHJlc3MgYXBwIGluc3RhbmNlLlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gY2xvc2VTZXJ2ZXJzXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gY2xvc2VTZXJ2ZXJzKCkge1xyXG4gIC8vIENoZWNrIGlmIHRoZXJlIGFyZSBzZXJ2ZXJzIHdvcmtpbmdcclxuICBpZiAoYWN0aXZlU2VydmVycy5zaXplID4gMCkge1xyXG4gICAgbG9nKDQsIGBbc2VydmVyXSBDbG9zaW5nIGFsbCBzZXJ2ZXJzLmApO1xyXG5cclxuICAgIC8vIENsb3NlIGVhY2ggb25lIG9mIHNlcnZlcnNcclxuICAgIGZvciAoY29uc3QgW3BvcnQsIHNlcnZlcl0gb2YgYWN0aXZlU2VydmVycykge1xyXG4gICAgICBzZXJ2ZXIuY2xvc2UoKCkgPT4ge1xyXG4gICAgICAgIGFjdGl2ZVNlcnZlcnMuZGVsZXRlKHBvcnQpO1xyXG4gICAgICAgIGxvZyg0LCBgW3NlcnZlcl0gQ2xvc2VkIHNlcnZlciBvbiBwb3J0OiAke3BvcnR9LmApO1xyXG4gICAgICB9KTtcclxuICAgIH1cclxuICB9XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBHZXQgYWxsIHNlcnZlcnMgYXNzb2NpYXRlZCB3aXRoIEV4cHJlc3MgYXBwIGluc3RhbmNlLlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gZ2V0U2VydmVyc1xyXG4gKlxyXG4gKiBAcmV0dXJucyB7QXJyYXkuPE9iamVjdD59IFNlcnZlcnMgYXNzb2NpYXRlZCB3aXRoIEV4cHJlc3MgYXBwIGluc3RhbmNlLlxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIGdldFNlcnZlcnMoKSB7XHJcbiAgcmV0dXJuIGFjdGl2ZVNlcnZlcnM7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBHZXQgdGhlIEV4cHJlc3MgaW5zdGFuY2UuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBnZXRFeHByZXNzXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtFeHByZXNzfSBUaGUgRXhwcmVzcyBpbnN0YW5jZS5cclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiBnZXRFeHByZXNzKCkge1xyXG4gIHJldHVybiBleHByZXNzO1xyXG59XHJcblxyXG4vKipcclxuICogR2V0IHRoZSBFeHByZXNzIGFwcCBpbnN0YW5jZS5cclxuICpcclxuICogQGZ1bmN0aW9uIGdldEFwcFxyXG4gKlxyXG4gKiBAcmV0dXJucyB7RXhwcmVzc30gVGhlIEV4cHJlc3MgYXBwIGluc3RhbmNlLlxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIGdldEFwcCgpIHtcclxuICByZXR1cm4gYXBwO1xyXG59XHJcblxyXG4vKipcclxuICogRW5hYmxlIHJhdGUgbGltaXRpbmcgZm9yIHRoZSBzZXJ2ZXIuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBlbmFibGVSYXRlTGltaXRpbmdcclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IHJhdGVMaW1pdGluZ09wdGlvbnMgLSBPYmplY3QgY29udGFpbmluZyBgcmF0ZUxpbWl0aW5nYFxyXG4gKiBvcHRpb25zLlxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIGVuYWJsZVJhdGVMaW1pdGluZyhyYXRlTGltaXRpbmdPcHRpb25zKSB7XHJcbiAgcmF0ZUxpbWl0aW5nTWlkZGxld2FyZShhcHAsIHJhdGVMaW1pdGluZ09wdGlvbnMpO1xyXG59XHJcblxyXG4vKipcclxuICogQXBwbHkgbWlkZGxld2FyZShzKSB0byBhIHNwZWNpZmljIHBhdGguXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiB1c2VcclxuICpcclxuICogQHBhcmFtIHtzdHJpbmd9IHBhdGggLSBUaGUgcGF0aCB0byB3aGljaCB0aGUgbWlkZGxld2FyZShzKSBzaG91bGQgYmUgYXBwbGllZC5cclxuICogQHBhcmFtIHsuLi5GdW5jdGlvbn0gbWlkZGxld2FyZXMgLSBUaGUgbWlkZGxld2FyZSBmdW5jdGlvbihzKSB0byBiZSBhcHBsaWVkLlxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIHVzZShwYXRoLCAuLi5taWRkbGV3YXJlcykge1xyXG4gIGFwcC51c2UocGF0aCwgLi4ubWlkZGxld2FyZXMpO1xyXG59XHJcblxyXG4vKipcclxuICogU2V0IHVwIGEgcm91dGUgd2l0aCBHRVQgbWV0aG9kIGFuZCBhcHBseSBtaWRkbGV3YXJlKHMpLlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gZ2V0XHJcbiAqXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSBwYXRoIC0gVGhlIHBhdGggdG8gd2hpY2ggdGhlIG1pZGRsZXdhcmUocykgc2hvdWxkIGJlIGFwcGxpZWQuXHJcbiAqIEBwYXJhbSB7Li4uRnVuY3Rpb259IG1pZGRsZXdhcmVzIC0gVGhlIG1pZGRsZXdhcmUgZnVuY3Rpb24ocykgdG8gYmUgYXBwbGllZC5cclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiBnZXQocGF0aCwgLi4ubWlkZGxld2FyZXMpIHtcclxuICBhcHAuZ2V0KHBhdGgsIC4uLm1pZGRsZXdhcmVzKTtcclxufVxyXG5cclxuLyoqXHJcbiAqIFNldCB1cCBhIHJvdXRlIHdpdGggUE9TVCBtZXRob2QgYW5kIGFwcGx5IG1pZGRsZXdhcmUocykuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBwb3N0XHJcbiAqXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSBwYXRoIC0gVGhlIHBhdGggdG8gd2hpY2ggdGhlIG1pZGRsZXdhcmUocykgc2hvdWxkIGJlIGFwcGxpZWQuXHJcbiAqIEBwYXJhbSB7Li4uRnVuY3Rpb259IG1pZGRsZXdhcmVzIC0gVGhlIG1pZGRsZXdhcmUgZnVuY3Rpb24ocykgdG8gYmUgYXBwbGllZC5cclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiBwb3N0KHBhdGgsIC4uLm1pZGRsZXdhcmVzKSB7XHJcbiAgYXBwLnBvc3QocGF0aCwgLi4ubWlkZGxld2FyZXMpO1xyXG59XHJcblxyXG4vKipcclxuICogQXR0YWNoIGVycm9yIGhhbmRsZXJzIHRvIHRoZSBzZXJ2ZXIuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBfYXR0YWNoU2VydmVyRXJyb3JIYW5kbGVyc1xyXG4gKlxyXG4gKiBAcGFyYW0geyhodHRwLlNlcnZlcnxodHRwcy5TZXJ2ZXIpfSBzZXJ2ZXIgLSBUaGUgSFRUUC9IVFRQUyBzZXJ2ZXIgaW5zdGFuY2UuXHJcbiAqL1xyXG5mdW5jdGlvbiBfYXR0YWNoU2VydmVyRXJyb3JIYW5kbGVycyhzZXJ2ZXIpIHtcclxuICBzZXJ2ZXIub24oJ2NsaWVudEVycm9yJywgKGVycm9yLCBzb2NrZXQpID0+IHtcclxuICAgIGxvZ1dpdGhTdGFjayhcclxuICAgICAgMSxcclxuICAgICAgZXJyb3IsXHJcbiAgICAgIGBbc2VydmVyXSBDbGllbnQgZXJyb3I6ICR7ZXJyb3IubWVzc2FnZX0sIGRlc3Ryb3lpbmcgc29ja2V0LmBcclxuICAgICk7XHJcbiAgICBzb2NrZXQuZGVzdHJveSgpO1xyXG4gIH0pO1xyXG5cclxuICBzZXJ2ZXIub24oJ2Vycm9yJywgKGVycm9yKSA9PiB7XHJcbiAgICBsb2dXaXRoU3RhY2soMSwgZXJyb3IsIGBbc2VydmVyXSBTZXJ2ZXIgZXJyb3I6ICR7ZXJyb3IubWVzc2FnZX1gKTtcclxuICB9KTtcclxuXHJcbiAgc2VydmVyLm9uKCdjb25uZWN0aW9uJywgKHNvY2tldCkgPT4ge1xyXG4gICAgc29ja2V0Lm9uKCdlcnJvcicsIChlcnJvcikgPT4ge1xyXG4gICAgICBsb2dXaXRoU3RhY2soMSwgZXJyb3IsIGBbc2VydmVyXSBTb2NrZXQgZXJyb3I6ICR7ZXJyb3IubWVzc2FnZX1gKTtcclxuICAgIH0pO1xyXG4gIH0pO1xyXG59XHJcblxyXG5leHBvcnQgZGVmYXVsdCB7XHJcbiAgc3RhcnRTZXJ2ZXIsXHJcbiAgY2xvc2VTZXJ2ZXJzLFxyXG4gIGdldFNlcnZlcnMsXHJcbiAgZ2V0RXhwcmVzcyxcclxuICBnZXRBcHAsXHJcbiAgZW5hYmxlUmF0ZUxpbWl0aW5nLFxyXG4gIHVzZSxcclxuICBnZXQsXHJcbiAgcG9zdFxyXG59O1xyXG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxyXG5cclxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXHJcblxyXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNSwgSGlnaHNvZnRcclxuXHJcbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cclxuXHJcbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxyXG5cclxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxyXG5cclxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cclxuXHJcbi8qKlxyXG4gKiBAb3ZlcnZpZXcgSGFuZGxlcyBncmFjZWZ1bCBzaHV0ZG93biBvZiB0aGUgSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyLCBlbnN1cmluZ1xyXG4gKiBwcm9wZXIgY2xlYW51cCBvZiByZXNvdXJjZXMgc3VjaCBhcyBicm93c2VyLCBwYWdlcywgc2VydmVycywgYW5kIHRpbWVycy5cclxuICovXHJcblxyXG5pbXBvcnQgeyBraWxsUG9vbCB9IGZyb20gJy4vcG9vbC5qcyc7XHJcbmltcG9ydCB7IGNsZWFyQWxsVGltZXJzIH0gZnJvbSAnLi90aW1lci5qcyc7XHJcbmltcG9ydCB7IGNsb3NlU2VydmVycyB9IGZyb20gJy4vc2VydmVyL3NlcnZlci5qcyc7XHJcblxyXG4vKipcclxuICogQ2xlYW5zIHVwIGZ1bmN0aW9uIHRvIHRyaWdnZXIgYmVmb3JlIGVuZGluZyBwcm9jZXNzIGZvciB0aGUgZ3JhY2VmdWxcclxuICogc2h1dGRvd24uXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBzaHV0ZG93bkNsZWFuVXBcclxuICpcclxuICogQHBhcmFtIHtudW1iZXJ9IGV4aXRDb2RlIC0gQW4gZXhpdCBjb2RlIGZvciB0aGUgYHByb2Nlc3MuZXhpdCgpYCBmdW5jdGlvbi5cclxuICovXHJcbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBzaHV0ZG93bkNsZWFuVXAoZXhpdENvZGUpIHtcclxuICAvLyBBd2FpdCBmcmVlaW5nIGFsbCByZXNvdXJjZXNcclxuICBhd2FpdCBQcm9taXNlLmFsbFNldHRsZWQoW1xyXG4gICAgLy8gQ2xlYXIgYWxsIG9uZ29pbmcgaW50ZXJ2YWxzXHJcbiAgICBjbGVhckFsbFRpbWVycygpLFxyXG5cclxuICAgIC8vIEdldCBhdmFpbGFibGUgc2VydmVyIGluc3RhbmNlcyAoSFRUUC9IVFRQUykgYW5kIGNsb3NlIHRoZW1cclxuICAgIGNsb3NlU2VydmVycygpLFxyXG5cclxuICAgIC8vIENsb3NlIGFuIGFjdGl2ZSBwb29sIGFsb25nIHdpdGggaXRzIHdvcmtlcnMgYW5kIHRoZSBicm93c2VyIGluc3RhbmNlXHJcbiAgICBraWxsUG9vbCgpXHJcbiAgXSk7XHJcblxyXG4gIC8vIEV4aXQgcHJvY2VzcyB3aXRoIGEgY29ycmVjdCBjb2RlXHJcbiAgcHJvY2Vzcy5leGl0KGV4aXRDb2RlKTtcclxufVxyXG5cclxuZXhwb3J0IGRlZmF1bHQge1xyXG4gIHNodXRkb3duQ2xlYW5VcFxyXG59O1xyXG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxyXG5cclxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXHJcblxyXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNSwgSGlnaHNvZnRcclxuXHJcbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cclxuXHJcbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxyXG5cclxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxyXG5cclxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cclxuXHJcbi8qKlxyXG4gKiBAb3ZlcnZpZXcgQ29yZSBtb2R1bGUgZm9yIGluaXRpYWxpemluZyBhbmQgbWFuYWdpbmcgdGhlIEhpZ2hjaGFydHMgRXhwb3J0XHJcbiAqIFNlcnZlci4gUHJvdmlkZXMgZnVuY3Rpb25hbGl0aWVzIGZvciBjb25maWd1cmluZyBleHBvcnRzLCBzZXR0aW5nIHVwIHNlcnZlclxyXG4gKiBvcGVyYXRpb25zLCBsb2dnaW5nLCBzY3JpcHRzIGNhY2hpbmcsIHJlc291cmNlIHBvb2xpbmcsIGFuZCBncmFjZWZ1bCBwcm9jZXNzXHJcbiAqIGNsZWFudXAuXHJcbiAqL1xyXG5cclxuaW1wb3J0ICdjb2xvcnMnO1xyXG5cclxuaW1wb3J0IHsgY2hlY2tBbmRVcGRhdGVDYWNoZSB9IGZyb20gJy4vY2FjaGUuanMnO1xyXG5pbXBvcnQge1xyXG4gIHNpbmdsZUV4cG9ydCxcclxuICBiYXRjaEV4cG9ydCxcclxuICBzdGFydEV4cG9ydCxcclxuICBzZXRBbGxvd0NvZGVFeGVjdXRpb25cclxufSBmcm9tICcuL2NoYXJ0LmpzJztcclxuaW1wb3J0IHtcclxuICBnZXRPcHRpb25zLFxyXG4gIHNldE9wdGlvbnMsXHJcbiAgbWVyZ2VPcHRpb25zLFxyXG4gIG1hcFRvTmV3T3B0aW9uc1xyXG59IGZyb20gJy4vY29uZmlnLmpzJztcclxuaW1wb3J0IHtcclxuICBsb2csXHJcbiAgbG9nV2l0aFN0YWNrLFxyXG4gIGluaXRMb2dnaW5nLFxyXG4gIHNldExvZ0xldmVsLFxyXG4gIGVuYWJsZUNvbnNvbGVMb2dnaW5nLFxyXG4gIGVuYWJsZUZpbGVMb2dnaW5nXHJcbn0gZnJvbSAnLi9sb2dnZXIuanMnO1xyXG5pbXBvcnQgeyBpbml0UG9vbCwga2lsbFBvb2wgfSBmcm9tICcuL3Bvb2wuanMnO1xyXG5pbXBvcnQgeyBzaHV0ZG93bkNsZWFuVXAgfSBmcm9tICcuL3Jlc291cmNlUmVsZWFzZS5qcyc7XHJcbmltcG9ydCBzZXJ2ZXIsIHsgc3RhcnRTZXJ2ZXIgfSBmcm9tICcuL3NlcnZlci9zZXJ2ZXIuanMnO1xyXG5cclxuLyoqXHJcbiAqIEluaXRpYWxpemVzIHRoZSBleHBvcnQgcHJvY2Vzcy4gVGFza3Mgc3VjaCBhcyBjb25maWd1cmluZyBsb2dnaW5nLCBjaGVja2luZ1xyXG4gKiB0aGUgY2FjaGUgYW5kIHNvdXJjZXMsIGFuZCBpbml0aWFsaXppbmcgdGhlIHJlc291cmNlIHBvb2wgb2NjdXIgZHVyaW5nIHRoaXNcclxuICogc3RhZ2UuIFRoaXMgZnVuY3Rpb24gbXVzdCBiZSBjYWxsZWQgYmVmb3JlIGF0dGVtcHRpbmcgdG8gZXhwb3J0IGNoYXJ0cyBvciBzZXRcclxuICogdXAgYSBzZXJ2ZXIuXHJcbiAqXHJcbiAqIEBhc3luY1xyXG4gKiBAZnVuY3Rpb24gaW5pdEV4cG9ydFxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gY3VzdG9tT3B0aW9ucyAtIFRoZSBgY3VzdG9tT3B0aW9uc2Agb2JqZWN0LCB3aGljaCBtYXlcclxuICogYmUgYSBwYXJ0aWFsIG9yIGNvbXBsZXRlIHNldCBvZiBvcHRpb25zLiBJZiB0aGUgcHJvdmlkZWQgb3B0aW9ucyBhcmUgcGFydGlhbCxcclxuICogbWlzc2luZyB2YWx1ZXMgd2lsbCBiZSBtZXJnZWQgd2l0aCB0aGUgZGVmYXVsdCBnZW5lcmFsIG9wdGlvbnMsIHJldHJpZXZlZFxyXG4gKiB1c2luZyB0aGUgYGdldE9wdGlvbnNgIGZ1bmN0aW9uLlxyXG4gKi9cclxuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIGluaXRFeHBvcnQoY3VzdG9tT3B0aW9ucykge1xyXG4gIC8vIEdldCB0aGUgZ2xvYmFsIG9wdGlvbnMgb2JqZWN0IGNvcHkgYW5kIGV4dGVuZCBpdCB3aXRoIHRoZSBpbmNvbWluZyBvcHRpb25zXHJcbiAgY29uc3Qgb3B0aW9ucyA9IG1lcmdlT3B0aW9ucyhnZXRPcHRpb25zKGZhbHNlKSwgY3VzdG9tT3B0aW9ucyk7XHJcblxyXG4gIC8vIFNldCB0aGUgYGFsbG93Q29kZUV4ZWN1dGlvbmAgcGVyIGV4cG9ydCBtb2R1bGUgc2NvcGVcclxuICBzZXRBbGxvd0NvZGVFeGVjdXRpb24ob3B0aW9ucy5jdXN0b21Mb2dpYy5hbGxvd0NvZGVFeGVjdXRpb24pO1xyXG5cclxuICAvLyBJbml0IHRoZSBsb2dnaW5nXHJcbiAgaW5pdExvZ2dpbmcob3B0aW9ucy5sb2dnaW5nKTtcclxuXHJcbiAgLy8gQXR0YWNoIHByb2Nlc3MnIGV4aXQgbGlzdGVuZXJzXHJcbiAgaWYgKG9wdGlvbnMub3RoZXIubGlzdGVuVG9Qcm9jZXNzRXhpdHMpIHtcclxuICAgIF9hdHRhY2hQcm9jZXNzRXhpdExpc3RlbmVycygpO1xyXG4gIH1cclxuXHJcbiAgLy8gQ2hlY2sgaWYgY2FjaGUgbmVlZHMgdG8gYmUgdXBkYXRlZFxyXG4gIGF3YWl0IGNoZWNrQW5kVXBkYXRlQ2FjaGUob3B0aW9ucy5oaWdoY2hhcnRzLCBvcHRpb25zLnNlcnZlci5wcm94eSk7XHJcblxyXG4gIC8vIEluaXQgdGhlIHBvb2xcclxuICBhd2FpdCBpbml0UG9vbChvcHRpb25zLnBvb2wsIG9wdGlvbnMucHVwcGV0ZWVyLmFyZ3MpO1xyXG59XHJcblxyXG4vKipcclxuICogQXR0YWNoZXMgZXhpdCBsaXN0ZW5lcnMgdG8gdGhlIHByb2Nlc3MsIGVuc3VyaW5nIHByb3BlciBjbGVhbnVwIG9mIHJlc291cmNlc1xyXG4gKiBhbmQgdGVybWluYXRpb24gb24gZXhpdCBzaWduYWxzLiBIYW5kbGVzICdleGl0JywgJ1NJR0lOVCcsICdTSUdURVJNJ1xyXG4gKiBhbmQgJ3VuY2F1Z2h0RXhjZXB0aW9uJyBldmVudHMuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBfYXR0YWNoUHJvY2Vzc0V4aXRMaXN0ZW5lcnNcclxuICovXHJcbmZ1bmN0aW9uIF9hdHRhY2hQcm9jZXNzRXhpdExpc3RlbmVycygpIHtcclxuICBsb2coMywgJ1twcm9jZXNzXSBBdHRhY2hpbmcgZXhpdCBsaXN0ZW5lcnMgdG8gdGhlIHByb2Nlc3MuJyk7XHJcblxyXG4gIC8vIEhhbmRsZXIgZm9yIHRoZSAnZXhpdCdcclxuICBwcm9jZXNzLm9uKCdleGl0JywgKGNvZGUpID0+IHtcclxuICAgIGxvZyg0LCBgW3Byb2Nlc3NdIFByb2Nlc3MgZXhpdGVkIHdpdGggY29kZSAke2NvZGV9LmApO1xyXG4gIH0pO1xyXG5cclxuICAvLyBIYW5kbGVyIGZvciB0aGUgJ1NJR0lOVCdcclxuICBwcm9jZXNzLm9uKCdTSUdJTlQnLCBhc3luYyAobmFtZSwgY29kZSkgPT4ge1xyXG4gICAgbG9nKDQsIGBbcHJvY2Vzc10gVGhlICR7bmFtZX0gZXZlbnQgd2l0aCBjb2RlOiAke2NvZGV9LmApO1xyXG4gICAgYXdhaXQgc2h1dGRvd25DbGVhblVwKDApO1xyXG4gIH0pO1xyXG5cclxuICAvLyBIYW5kbGVyIGZvciB0aGUgJ1NJR1RFUk0nXHJcbiAgcHJvY2Vzcy5vbignU0lHVEVSTScsIGFzeW5jIChuYW1lLCBjb2RlKSA9PiB7XHJcbiAgICBsb2coNCwgYFtwcm9jZXNzXSBUaGUgJHtuYW1lfSBldmVudCB3aXRoIGNvZGU6ICR7Y29kZX0uYCk7XHJcbiAgICBhd2FpdCBzaHV0ZG93bkNsZWFuVXAoMCk7XHJcbiAgfSk7XHJcblxyXG4gIC8vIEhhbmRsZXIgZm9yIHRoZSAnU0lHSFVQJ1xyXG4gIHByb2Nlc3Mub24oJ1NJR0hVUCcsIGFzeW5jIChuYW1lLCBjb2RlKSA9PiB7XHJcbiAgICBsb2coNCwgYFtwcm9jZXNzXSBUaGUgJHtuYW1lfSBldmVudCB3aXRoIGNvZGU6ICR7Y29kZX0uYCk7XHJcbiAgICBhd2FpdCBzaHV0ZG93bkNsZWFuVXAoMCk7XHJcbiAgfSk7XHJcblxyXG4gIC8vIEhhbmRsZXIgZm9yIHRoZSAndW5jYXVnaHRFeGNlcHRpb24nXHJcbiAgcHJvY2Vzcy5vbigndW5jYXVnaHRFeGNlcHRpb24nLCBhc3luYyAoZXJyb3IsIG5hbWUpID0+IHtcclxuICAgIGxvZ1dpdGhTdGFjaygxLCBlcnJvciwgYFtwcm9jZXNzXSBUaGUgJHtuYW1lfSBlcnJvci5gKTtcclxuICAgIGF3YWl0IHNodXRkb3duQ2xlYW5VcCgxKTtcclxuICB9KTtcclxufVxyXG5cclxuZXhwb3J0IGRlZmF1bHQge1xyXG4gIC8vIFNlcnZlclxyXG4gIHNlcnZlcixcclxuICBzdGFydFNlcnZlcixcclxuXHJcbiAgLy8gT3B0aW9uc1xyXG4gIGdldE9wdGlvbnMsXHJcbiAgc2V0T3B0aW9ucyxcclxuICBtZXJnZU9wdGlvbnMsXHJcbiAgbWFwVG9OZXdPcHRpb25zLFxyXG5cclxuICAvLyBFeHBvcnRpbmdcclxuICBpbml0RXhwb3J0LFxyXG4gIHNpbmdsZUV4cG9ydCxcclxuICBiYXRjaEV4cG9ydCxcclxuICBzdGFydEV4cG9ydCxcclxuXHJcbiAgLy8gQ2FjaGVcclxuICBjaGVja0FuZFVwZGF0ZUNhY2hlLFxyXG5cclxuICAvLyBQb29sXHJcbiAgaW5pdFBvb2wsXHJcbiAga2lsbFBvb2wsXHJcblxyXG4gIC8vIExvZ3NcclxuICBsb2csXHJcbiAgbG9nV2l0aFN0YWNrLFxyXG4gIHNldExvZ0xldmVsLFxyXG4gIGVuYWJsZUNvbnNvbGVMb2dnaW5nLFxyXG4gIGVuYWJsZUZpbGVMb2dnaW5nLFxyXG5cclxuICAvLyBVdGlsc1xyXG4gIHNodXRkb3duQ2xlYW5VcFxyXG59O1xyXG4iXSwibmFtZXMiOlsiX19kaXJuYW1lIiwiZmlsZVVSTFRvUGF0aCIsIlVSTCIsImRvY3VtZW50IiwicmVxdWlyZSIsInBhdGhUb0ZpbGVVUkwiLCJfX2ZpbGVuYW1lIiwiaHJlZiIsIl9kb2N1bWVudEN1cnJlbnRTY3JpcHQiLCJ0YWdOYW1lIiwidG9VcHBlckNhc2UiLCJzcmMiLCJiYXNlVVJJIiwiZGVlcENvcHkiLCJvYmpBcnIiLCJvYmpBcnJDb3B5IiwiQXJyYXkiLCJpc0FycmF5Iiwia2V5IiwiT2JqZWN0IiwicHJvdG90eXBlIiwiaGFzT3duUHJvcGVydHkiLCJjYWxsIiwiZml4Q29uc3RyIiwiY29uc3RyIiwiZml4ZWRDb25zdHIiLCJ0b0xvd2VyQ2FzZSIsInJlcGxhY2UiLCJpbmNsdWRlcyIsImZpeE91dGZpbGUiLCJ0eXBlIiwib3V0ZmlsZSIsImdldEFic29sdXRlUGF0aCIsInNwbGl0Iiwic2hpZnQiLCJmaXhUeXBlIiwibWltZVR5cGVzIiwiZm9ybWF0cyIsInZhbHVlcyIsIm91dFR5cGUiLCJwb3AiLCJmaW5kIiwidCIsInBhdGgiLCJpc0Fic29sdXRlIiwiam9pbiIsImdldEJhc2U2NCIsImlucHV0IiwiQnVmZmVyIiwiZnJvbSIsInRvU3RyaW5nIiwiZ2V0TmV3RGF0ZSIsIkRhdGUiLCJ0cmltIiwiZ2V0TmV3RGF0ZVRpbWUiLCJnZXRUaW1lIiwiaXNPYmplY3QiLCJpdGVtIiwiaXNPYmplY3RFbXB0eSIsImtleXMiLCJsZW5ndGgiLCJpc1ByaXZhdGVSYW5nZVVybEZvdW5kIiwic29tZSIsInBhdHRlcm4iLCJ0ZXN0IiwibWVhc3VyZVRpbWUiLCJzdGFydCIsInByb2Nlc3MiLCJocnRpbWUiLCJiaWdpbnQiLCJOdW1iZXIiLCJyb3VuZE51bWJlciIsInZhbHVlIiwicHJlY2lzaW9uIiwibXVsdGlwbGllciIsIk1hdGgiLCJwb3ciLCJyb3VuZCIsIndyYXBBcm91bmQiLCJjdXN0b21Db2RlIiwiYWxsb3dGaWxlUmVzb3VyY2VzIiwiaXNDYWxsYmFjayIsImVuZHNXaXRoIiwicmVhZEZpbGVTeW5jIiwic3RhcnRzV2l0aCIsImNvbG9ycyIsImxvZ2dpbmciLCJ0b0NvbnNvbGUiLCJ0b0ZpbGUiLCJwYXRoQ3JlYXRlZCIsInBhdGhUb0xvZyIsImxldmVsc0Rlc2MiLCJ0aXRsZSIsImNvbG9yIiwibG9nIiwiYXJncyIsIm5ld0xldmVsIiwidGV4dHMiLCJsZXZlbCIsInByZWZpeCIsIl9sb2dUb0ZpbGUiLCJjb25zb2xlIiwiYXBwbHkiLCJ1bmRlZmluZWQiLCJjb25jYXQiLCJsb2dXaXRoU3RhY2siLCJlcnJvciIsImN1c3RvbU1lc3NhZ2UiLCJtYWluTWVzc2FnZSIsIm1lc3NhZ2UiLCJzdGFja01lc3NhZ2UiLCJzdGFjayIsInB1c2giLCJpbml0TG9nZ2luZyIsImxvZ2dpbmdPcHRpb25zIiwiZGVzdCIsImZpbGUiLCJzZXRMb2dMZXZlbCIsImVuYWJsZUNvbnNvbGVMb2dnaW5nIiwiZW5hYmxlRmlsZUxvZ2dpbmciLCJleGlzdHNTeW5jIiwibWtkaXJTeW5jIiwiYXBwZW5kRmlsZSIsImRlZmF1bHRDb25maWciLCJwdXBwZXRlZXIiLCJ0eXBlcyIsImVudkxpbmsiLCJjbGlOYW1lIiwiZGVzY3JpcHRpb24iLCJwcm9tcHRPcHRpb25zIiwic2VwYXJhdG9yIiwiaGlnaGNoYXJ0cyIsInZlcnNpb24iLCJjZG5VcmwiLCJmb3JjZUZldGNoIiwiY2FjaGVQYXRoIiwiY29yZVNjcmlwdHMiLCJpbnN0cnVjdGlvbnMiLCJtb2R1bGVTY3JpcHRzIiwiaW5kaWNhdG9yU2NyaXB0cyIsImN1c3RvbVNjcmlwdHMiLCJleHBvcnQiLCJpbmZpbGUiLCJpbnN0ciIsIm9wdGlvbnMiLCJzdmciLCJiYXRjaCIsImhpbnQiLCJjaG9pY2VzIiwiYjY0Iiwibm9Eb3dubG9hZCIsImhlaWdodCIsIndpZHRoIiwic2NhbGUiLCJkZWZhdWx0SGVpZ2h0IiwiZGVmYXVsdFdpZHRoIiwiZGVmYXVsdFNjYWxlIiwibWluIiwibWF4IiwiZ2xvYmFsT3B0aW9ucyIsInRoZW1lT3B0aW9ucyIsInJhc3Rlcml6YXRpb25UaW1lb3V0IiwiY3VzdG9tTG9naWMiLCJhbGxvd0NvZGVFeGVjdXRpb24iLCJjYWxsYmFjayIsInJlc291cmNlcyIsImxvYWRDb25maWciLCJsZWdhY3lOYW1lIiwiY3JlYXRlQ29uZmlnIiwic2VydmVyIiwiZW5hYmxlIiwiaG9zdCIsInBvcnQiLCJ1cGxvYWRMaW1pdCIsImJlbmNobWFya2luZyIsInByb3h5IiwidGltZW91dCIsInJhdGVMaW1pdGluZyIsIm1heFJlcXVlc3RzIiwid2luZG93IiwiZGVsYXkiLCJ0cnVzdFByb3h5Iiwic2tpcEtleSIsInNraXBUb2tlbiIsInNzbCIsImZvcmNlIiwiY2VydFBhdGgiLCJwb29sIiwibWluV29ya2VycyIsIm1heFdvcmtlcnMiLCJ3b3JrTGltaXQiLCJhY3F1aXJlVGltZW91dCIsImNyZWF0ZVRpbWVvdXQiLCJkZXN0cm95VGltZW91dCIsImlkbGVUaW1lb3V0IiwiY3JlYXRlUmV0cnlJbnRlcnZhbCIsInJlYXBlckludGVydmFsIiwidWkiLCJyb3V0ZSIsIm90aGVyIiwibm9kZUVudiIsImxpc3RlblRvUHJvY2Vzc0V4aXRzIiwibm9Mb2dvIiwiaGFyZFJlc2V0UGFnZSIsImJyb3dzZXJTaGVsbE1vZGUiLCJkZWJ1ZyIsImhlYWRsZXNzIiwiZGV2dG9vbHMiLCJsaXN0ZW5Ub0NvbnNvbGUiLCJkdW1waW8iLCJzbG93TW8iLCJkZWJ1Z2dpbmdQb3J0IiwibmVzdGVkUHJvcHMiLCJfY3JlYXRlTmVzdGVkUHJvcHMiLCJhYnNvbHV0ZVByb3BzIiwiX2NyZWF0ZUFic29sdXRlUHJvcHMiLCJjb25maWciLCJwcm9wQ2hhaW4iLCJmb3JFYWNoIiwiZW50cnkiLCJzdWJzdHJpbmciLCJkb3RlbnYiLCJ2IiwiYXJyYXkiLCJmaWx0ZXJBcnJheSIsInoiLCJzdHJpbmciLCJ0cmFuc2Zvcm0iLCJtYXAiLCJmaWx0ZXIiLCJib29sZWFuIiwiZW51bSIsInJlZmluZSIsInBvc2l0aXZlTnVtIiwiaXNOYU4iLCJwYXJzZUZsb2F0Iiwibm9uTmVnYXRpdmVOdW0iLCJDb25maWciLCJvYmplY3QiLCJQVVBQRVRFRVJfQVJHUyIsIkhJR0hDSEFSVFNfVkVSU0lPTiIsIkhJR0hDSEFSVFNfQ0ROX1VSTCIsIkhJR0hDSEFSVFNfRk9SQ0VfRkVUQ0giLCJISUdIQ0hBUlRTX0NBQ0hFX1BBVEgiLCJISUdIQ0hBUlRTX0FETUlOX1RPS0VOIiwiSElHSENIQVJUU19DT1JFX1NDUklQVFMiLCJISUdIQ0hBUlRTX01PRFVMRV9TQ1JJUFRTIiwiSElHSENIQVJUU19JTkRJQ0FUT1JfU0NSSVBUUyIsIkhJR0hDSEFSVFNfQ1VTVE9NX1NDUklQVFMiLCJFWFBPUlRfSU5GSUxFIiwiRVhQT1JUX0lOU1RSIiwiRVhQT1JUX09QVElPTlMiLCJFWFBPUlRfU1ZHIiwiRVhQT1JUX0JBVENIIiwiRVhQT1JUX09VVEZJTEUiLCJFWFBPUlRfVFlQRSIsIkVYUE9SVF9DT05TVFIiLCJFWFBPUlRfQjY0IiwiRVhQT1JUX05PX0RPV05MT0FEIiwiRVhQT1JUX0hFSUdIVCIsIkVYUE9SVF9XSURUSCIsIkVYUE9SVF9TQ0FMRSIsIkVYUE9SVF9ERUZBVUxUX0hFSUdIVCIsIkVYUE9SVF9ERUZBVUxUX1dJRFRIIiwiRVhQT1JUX0RFRkFVTFRfU0NBTEUiLCJFWFBPUlRfR0xPQkFMX09QVElPTlMiLCJFWFBPUlRfVEhFTUVfT1BUSU9OUyIsIkVYUE9SVF9SQVNURVJJWkFUSU9OX1RJTUVPVVQiLCJDVVNUT01fTE9HSUNfQUxMT1dfQ09ERV9FWEVDVVRJT04iLCJDVVNUT01fTE9HSUNfQUxMT1dfRklMRV9SRVNPVVJDRVMiLCJDVVNUT01fTE9HSUNfQ1VTVE9NX0NPREUiLCJDVVNUT01fTE9HSUNfQ0FMTEJBQ0siLCJDVVNUT01fTE9HSUNfUkVTT1VSQ0VTIiwiQ1VTVE9NX0xPR0lDX0xPQURfQ09ORklHIiwiQ1VTVE9NX0xPR0lDX0NSRUFURV9DT05GSUciLCJTRVJWRVJfRU5BQkxFIiwiU0VSVkVSX0hPU1QiLCJTRVJWRVJfUE9SVCIsIlNFUlZFUl9VUExPQURfTElNSVQiLCJTRVJWRVJfQkVOQ0hNQVJLSU5HIiwiU0VSVkVSX1BST1hZX0hPU1QiLCJTRVJWRVJfUFJPWFlfUE9SVCIsIlNFUlZFUl9QUk9YWV9USU1FT1VUIiwiU0VSVkVSX1JBVEVfTElNSVRJTkdfRU5BQkxFIiwiU0VSVkVSX1JBVEVfTElNSVRJTkdfTUFYX1JFUVVFU1RTIiwiU0VSVkVSX1JBVEVfTElNSVRJTkdfV0lORE9XIiwiU0VSVkVSX1JBVEVfTElNSVRJTkdfREVMQVkiLCJTRVJWRVJfUkFURV9MSU1JVElOR19UUlVTVF9QUk9YWSIsIlNFUlZFUl9SQVRFX0xJTUlUSU5HX1NLSVBfS0VZIiwiU0VSVkVSX1JBVEVfTElNSVRJTkdfU0tJUF9UT0tFTiIsIlNFUlZFUl9TU0xfRU5BQkxFIiwiU0VSVkVSX1NTTF9GT1JDRSIsIlNFUlZFUl9TU0xfUE9SVCIsIlNFUlZFUl9TU0xfQ0VSVF9QQVRIIiwiUE9PTF9NSU5fV09SS0VSUyIsIlBPT0xfTUFYX1dPUktFUlMiLCJQT09MX1dPUktfTElNSVQiLCJQT09MX0FDUVVJUkVfVElNRU9VVCIsIlBPT0xfQ1JFQVRFX1RJTUVPVVQiLCJQT09MX0RFU1RST1lfVElNRU9VVCIsIlBPT0xfSURMRV9USU1FT1VUIiwiUE9PTF9DUkVBVEVfUkVUUllfSU5URVJWQUwiLCJQT09MX1JFQVBFUl9JTlRFUlZBTCIsIlBPT0xfQkVOQ0hNQVJLSU5HIiwiTE9HR0lOR19MRVZFTCIsIkxPR0dJTkdfRklMRSIsIkxPR0dJTkdfREVTVCIsIkxPR0dJTkdfVE9fQ09OU09MRSIsIkxPR0dJTkdfVE9fRklMRSIsIlVJX0VOQUJMRSIsIlVJX1JPVVRFIiwiT1RIRVJfTk9ERV9FTlYiLCJPVEhFUl9MSVNURU5fVE9fUFJPQ0VTU19FWElUUyIsIk9USEVSX05PX0xPR08iLCJPVEhFUl9IQVJEX1JFU0VUX1BBR0UiLCJPVEhFUl9CUk9XU0VSX1NIRUxMX01PREUiLCJERUJVR19FTkFCTEUiLCJERUJVR19IRUFETEVTUyIsIkRFQlVHX0RFVlRPT0xTIiwiREVCVUdfTElTVEVOX1RPX0NPTlNPTEUiLCJERUJVR19EVU1QSU8iLCJERUJVR19TTE9XX01PIiwiREVCVUdfREVCVUdHSU5HX1BPUlQiLCJlbnZzIiwicGFydGlhbCIsInBhcnNlIiwiZW52IiwiX2luaXRHbG9iYWxPcHRpb25zIiwiZ2V0T3B0aW9ucyIsImdldFJlZmVyZW5jZSIsInNldE9wdGlvbnMiLCJjdXN0b21PcHRpb25zIiwiY2xpQXJncyIsIm1vZGlmeUdsb2JhbCIsImNvbmZpZ09wdGlvbnMiLCJjbGlPcHRpb25zIiwiX2xvYWRDb25maWdGaWxlIiwiX3BhaXJBcmd1bWVudFZhbHVlIiwiZ2VuZXJhbE9wdGlvbnMiLCJfdXBkYXRlT3B0aW9ucyIsIm1lcmdlT3B0aW9ucyIsIm9yaWdpbmFsT3B0aW9ucyIsIm5ld09wdGlvbnMiLCJlbnRyaWVzIiwibWFwVG9OZXdPcHRpb25zIiwib2xkT3B0aW9ucyIsInByb3BlcnRpZXNDaGFpbiIsInJlZHVjZSIsIm9iaiIsInByb3AiLCJpbmRleCIsImlzQWxsb3dlZENvbmZpZyIsImFsbG93RnVuY3Rpb25zIiwib2JqZWN0Q29uZmlnIiwiZXZhbCIsIkpTT04iLCJzdHJpbmdpZmllZE9wdGlvbnMiLCJfb3B0aW9uc1N0cmluZ2lmeSIsInBhcnNlZE9wdGlvbnMiLCJfIiwibmFtZSIsImNvbmZpZ09wdCIsImN1c3RvbU9wdCIsImNsaU9wdCIsImNvbmZpZ1ZhbCIsImN1c3RvbVZhbCIsImNsaVZhbCIsImVudlZhbCIsInN0cmluZ2lmeUZ1bmN0aW9ucyIsInN0cmluZ2lmeSIsInJlcGxhY2VBbGwiLCJFcnJvciIsImNvbmZpZ0luZGV4IiwiZmluZEluZGV4IiwiYXJnIiwiY29uZmlnRmlsZU5hbWUiLCJpIiwib3B0aW9uIiwiYXN5bmMiLCJmZXRjaCIsInVybCIsInJlcXVlc3RPcHRpb25zIiwiUHJvbWlzZSIsInJlc29sdmUiLCJyZWplY3QiLCJfZ2V0UHJvdG9jb2xNb2R1bGUiLCJnZXQiLCJyZXNwb25zZSIsInJlc3BvbnNlRGF0YSIsIm9uIiwiY2h1bmsiLCJ0ZXh0IiwiaHR0cHMiLCJodHRwIiwiRXhwb3J0RXJyb3IiLCJjb25zdHJ1Y3RvciIsInN0YXR1c0NvZGUiLCJzdXBlciIsInRoaXMiLCJzZXRFcnJvciIsImNhY2hlIiwiYWN0aXZlTWFuaWZlc3QiLCJzb3VyY2VzIiwiaGNWZXJzaW9uIiwiY2hlY2tBbmRVcGRhdGVDYWNoZSIsImhpZ2hjaGFydHNPcHRpb25zIiwic2VydmVyUHJveHlPcHRpb25zIiwiZmV0Y2hlZE1vZHVsZXMiLCJnZXRDYWNoZVBhdGgiLCJtYW5pZmVzdFBhdGgiLCJzb3VyY2VQYXRoIiwicmVjdXJzaXZlIiwiX3VwZGF0ZUNhY2hlIiwicmVxdWVzdFVwZGF0ZSIsIm1hbmlmZXN0IiwibW9kdWxlcyIsIm1vZHVsZU1hcCIsIm0iLCJudW1iZXJPZk1vZHVsZXMiLCJtb2R1bGVOYW1lIiwiZXh0cmFjdFZlcnNpb24iLCJfc2F2ZUNvbmZpZ1RvTWFuaWZlc3QiLCJnZXRIaWdoY2hhcnRzVmVyc2lvbiIsInVwZGF0ZUhpZ2hjaGFydHNWZXJzaW9uIiwibmV3VmVyc2lvbiIsImNhY2hlU291cmNlcyIsImluZGV4T2YiLCJleHRyYWN0TW9kdWxlTmFtZSIsInNjcmlwdFBhdGgiLCJfZmV0Y2hBbmRQcm9jZXNzU2NyaXB0Iiwic2NyaXB0Iiwic2hvdWxkVGhyb3dFcnJvciIsIm5ld01hbmlmZXN0Iiwid3JpdGVGaWxlU3luYyIsIl9mZXRjaFNjcmlwdHMiLCJwcm94eUFnZW50IiwicHJveHlIb3N0IiwicHJveHlQb3J0IiwiSHR0cHNQcm94eUFnZW50IiwiYWdlbnQiLCJhbGxGZXRjaFByb21pc2VzIiwiYWxsIiwiYyIsInNldHVwSGlnaGNoYXJ0cyIsIkhpZ2hjaGFydHMiLCJhbmltT2JqZWN0IiwiZHVyYXRpb24iLCJjcmVhdGVDaGFydCIsIm1lcmdlIiwid3JhcCIsInNldE9wdGlvbnNPYmoiLCJpc1JlbmRlckNvbXBsZXRlIiwiQ2hhcnQiLCJwcm9jZWVkIiwidXNlck9wdGlvbnMiLCJjYiIsImV4cG9ydGluZyIsImVuYWJsZWQiLCJwbG90T3B0aW9ucyIsInNlcmllcyIsImxhYmVsIiwidG9vbHRpcCIsImFuaW1hdGlvbiIsIm9uSGlnaGNoYXJ0c1JlbmRlciIsImFkZEV2ZW50IiwiU2VyaWVzIiwiY2hhcnQiLCJhZGRpdGlvbmFsT3B0aW9ucyIsIkZ1bmN0aW9uIiwiZmluYWxPcHRpb25zIiwiZmluYWxDYWxsYmFjayIsImRlZmF1bHRPcHRpb25zIiwidGVtcGxhdGUiLCJicm93c2VyIiwiY3JlYXRlQnJvd3NlciIsInB1cHBldGVlckFyZ3MiLCJlbmFibGVkRGVidWciLCJkZWJ1Z09wdGlvbnMiLCJsYXVuY2hPcHRpb25zIiwidXNlckRhdGFEaXIiLCJoYW5kbGVTSUdJTlQiLCJoYW5kbGVTSUdURVJNIiwiaGFuZGxlU0lHSFVQIiwid2FpdEZvckluaXRpYWxQYWdlIiwiZGVmYXVsdFZpZXdwb3J0IiwidHJ5Q291bnQiLCJvcGVuIiwibGF1bmNoIiwic2V0VGltZW91dCIsImNsb3NlQnJvd3NlciIsImNvbm5lY3RlZCIsImNsb3NlIiwibmV3UGFnZSIsInBvb2xSZXNvdXJjZSIsInBhZ2UiLCJzZXRDYWNoZUVuYWJsZWQiLCJfc2V0UGFnZUNvbnRlbnQiLCJfc2V0UGFnZUV2ZW50cyIsImlzQ2xvc2VkIiwiY2xlYXJQYWdlIiwiaGFyZFJlc2V0IiwiZ290byIsIndhaXRVbnRpbCIsImV2YWx1YXRlIiwiYm9keSIsImlubmVySFRNTCIsImlkIiwid29ya0NvdW50IiwiYWRkUGFnZVJlc291cmNlcyIsImN1c3RvbUxvZ2ljT3B0aW9ucyIsImluamVjdGVkUmVzb3VyY2VzIiwiaW5qZWN0ZWRKcyIsImpzIiwiY29udGVudCIsImZpbGVzIiwiaXNMb2NhbCIsImpzUmVzb3VyY2UiLCJhZGRTY3JpcHRUYWciLCJpbmplY3RlZENzcyIsImNzcyIsImNzc0ltcG9ydHMiLCJtYXRjaCIsImNzc0ltcG9ydFBhdGgiLCJjc3NSZXNvdXJjZSIsImFkZFN0eWxlVGFnIiwiY2xlYXJQYWdlUmVzb3VyY2VzIiwicmVzb3VyY2UiLCJkaXNwb3NlIiwib2xkQ2hhcnRzIiwiY2hhcnRzIiwib2xkQ2hhcnQiLCJkZXN0cm95Iiwic2NyaXB0c1RvUmVtb3ZlIiwiZ2V0RWxlbWVudHNCeVRhZ05hbWUiLCJzdHlsZXNUb1JlbW92ZSIsImxpbmtzVG9SZW1vdmUiLCJlbGVtZW50IiwicmVtb3ZlIiwic2V0Q29udGVudCIsImNzc1RlbXBsYXRlIiwic3ZnVGVtcGxhdGUiLCJwdXBwZXRlZXJFeHBvcnQiLCJleHBvcnRPcHRpb25zIiwiaXNTVkciLCJfc2V0QXNTdmciLCJfc2V0QXNPcHRpb25zIiwic2l6ZSIsInN2Z0VsZW1lbnQiLCJxdWVyeVNlbGVjdG9yIiwiY2hhcnRIZWlnaHQiLCJiYXNlVmFsIiwiY2hhcnRXaWR0aCIsInN0eWxlIiwiem9vbSIsIm1hcmdpbiIsIngiLCJ5IiwiX2dldENsaXBSZWdpb24iLCJ2aWV3cG9ydEhlaWdodCIsImFicyIsImNlaWwiLCJ2aWV3cG9ydFdpZHRoIiwicmVzdWx0Iiwic2V0Vmlld3BvcnQiLCJkZXZpY2VTY2FsZUZhY3RvciIsIl9jcmVhdGVTVkciLCJfY3JlYXRlSW1hZ2UiLCJfY3JlYXRlUERGIiwiJGV2YWwiLCJnZXRCb3VuZGluZ0NsaWVudFJlY3QiLCJ0cnVuYyIsIm91dGVySFRNTCIsImNsaXAiLCJyYWNlIiwic2NyZWVuc2hvdCIsImVuY29kaW5nIiwiZnVsbFBhZ2UiLCJvcHRpbWl6ZUZvclNwZWVkIiwiY2FwdHVyZUJleW9uZFZpZXdwb3J0IiwicXVhbGl0eSIsIm9taXRCYWNrZ3JvdW5kIiwiX3Jlc29sdmUiLCJlbXVsYXRlTWVkaWFUeXBlIiwicGRmIiwicG9vbFN0YXRzIiwiZXhwb3J0c0F0dGVtcHRlZCIsImV4cG9ydHNQZXJmb3JtZWQiLCJleHBvcnRzRHJvcHBlZCIsImV4cG9ydHNGcm9tU3ZnIiwiZXhwb3J0c0Zyb21PcHRpb25zIiwiZXhwb3J0c0Zyb21TdmdBdHRlbXB0cyIsImV4cG9ydHNGcm9tT3B0aW9uc0F0dGVtcHRzIiwidGltZVNwZW50IiwidGltZVNwZW50QXZlcmFnZSIsImluaXRQb29sIiwicG9vbE9wdGlvbnMiLCJQb29sIiwiX2ZhY3RvcnkiLCJhY3F1aXJlVGltZW91dE1pbGxpcyIsImNyZWF0ZVRpbWVvdXRNaWxsaXMiLCJkZXN0cm95VGltZW91dE1pbGxpcyIsImlkbGVUaW1lb3V0TWlsbGlzIiwiY3JlYXRlUmV0cnlJbnRlcnZhbE1pbGxpcyIsInJlYXBJbnRlcnZhbE1pbGxpcyIsInByb3BhZ2F0ZUNyZWF0ZUVycm9yIiwiY2xlYXJTdGF0dXMiLCJfZXZlbnRJZCIsImluaXRpYWxSZXNvdXJjZXMiLCJhY3F1aXJlIiwicHJvbWlzZSIsInJlbGVhc2UiLCJraWxsUG9vbCIsIndvcmtlciIsInVzZWQiLCJkZXN0cm95ZWQiLCJwb3N0V29yayIsIndvcmtlckhhbmRsZSIsImdldFBvb2xJbmZvIiwiYWNxdWlyZUNvdW50ZXIiLCJfcmVxdWVzdElkIiwid29ya1N0YXJ0IiwiZXhwb3J0Q291bnRlciIsImV4cG9ydFRpbWUiLCJnZXRQb29sU3RhdHMiLCJnZXRQb29sSW5mb0pTT04iLCJudW1Vc2VkIiwiYXZhaWxhYmxlIiwibnVtRnJlZSIsImFsbENyZWF0ZWQiLCJwZW5kaW5nQWNxdWlyZXMiLCJudW1QZW5kaW5nQWNxdWlyZXMiLCJwZW5kaW5nQ3JlYXRlcyIsIm51bVBlbmRpbmdDcmVhdGVzIiwicGVuZGluZ1ZhbGlkYXRpb25zIiwibnVtUGVuZGluZ1ZhbGlkYXRpb25zIiwicGVuZGluZ0Rlc3Ryb3lzIiwiYWJzb2x1dGVBbGwiLCJjcmVhdGUiLCJ1dWlkIiwicmFuZG9tIiwic3RhcnREYXRlIiwidmFsaWRhdGUiLCJtYWluRnJhbWUiLCJkZXRhY2hlZCIsInJlbW92ZUFsbExpc3RlbmVycyIsInNhbml0aXplIiwiSlNET00iLCJET01QdXJpZnkiLCJBRERfVEFHUyIsInNpbmdsZUV4cG9ydCIsInN0YXJ0RXhwb3J0IiwiZGF0YSIsImJhdGNoRXhwb3J0IiwiYmF0Y2hGdW5jdGlvbnMiLCJwYWlyIiwiYmF0Y2hSZXN1bHRzIiwiYWxsU2V0dGxlZCIsInJlYXNvbiIsImVuZENhbGxiYWNrIiwiZmlsZUNvbnRlbnQiLCJfZXhwb3J0RnJvbVN2ZyIsIl9leHBvcnRGcm9tT3B0aW9ucyIsImdldEFsbG93Q29kZUV4ZWN1dGlvbiIsInNldEFsbG93Q29kZUV4ZWN1dGlvbiIsImlucHV0VG9FeHBvcnQiLCJfcHJlcGFyZUV4cG9ydCIsIl9oYW5kbGVDdXN0b21Mb2dpYyIsIl9oYW5kbGVHbG9iYWxBbmRUaGVtZSIsIl9maW5kQ2hhcnRTaXplIiwib3B0aW9uc0NoYXJ0Iiwib3B0aW9uc0V4cG9ydGluZyIsImdsb2JhbE9wdGlvbnNDaGFydCIsImdsb2JhbE9wdGlvbnNFeHBvcnRpbmciLCJ0aGVtZU9wdGlvbnNDaGFydCIsInRoZW1lT3B0aW9uc0V4cG9ydGluZyIsInNvdXJjZUhlaWdodCIsInNvdXJjZVdpZHRoIiwicGFyYW0iLCJfaGFuZGxlUmVzb3VyY2VzIiwiYWxsb3dlZFByb3BzIiwiaGFuZGxlZFJlc291cmNlcyIsImNvcnJlY3RSZXNvdXJjZXMiLCJwcm9wTmFtZSIsIm9wdGlvbnNOYW1lIiwidGltZXJJZHMiLCJhZGRUaW1lciIsImNsZWFyQWxsVGltZXJzIiwiY2xlYXJJbnRlcnZhbCIsImNsZWFyVGltZW91dCIsImxvZ0Vycm9yTWlkZGxld2FyZSIsInJlcXVlc3QiLCJuZXh0IiwicmV0dXJuRXJyb3JNaWRkbGV3YXJlIiwic3RhdHVzIiwianNvbiIsImVycm9yTWlkZGxld2FyZSIsImFwcCIsInVzZSIsInJhdGVMaW1pdGluZ01pZGRsZXdhcmUiLCJyYXRlTGltaXRpbmdPcHRpb25zIiwibXNnIiwicmF0ZU9wdGlvbnMiLCJsaW1pdGVyIiwicmF0ZUxpbWl0Iiwid2luZG93TXMiLCJkZWxheU1zIiwiaGFuZGxlciIsImZvcm1hdCIsInNlbmQiLCJkZWZhdWx0Iiwic2tpcCIsInF1ZXJ5IiwiYWNjZXNzX3Rva2VuIiwiSHR0cEVycm9yIiwic2V0U3RhdHVzIiwiY29udGVudFR5cGVNaWRkbGV3YXJlIiwiY29udGVudFR5cGUiLCJoZWFkZXJzIiwicmVxdWVzdEJvZHlNaWRkbGV3YXJlIiwicmVxdWVzdElkIiwiY29ubmVjdGlvbiIsInJlbW90ZUFkZHJlc3MiLCJ2YWxpZGF0ZWRPcHRpb25zIiwicGFyYW1zIiwiZmlsZW5hbWUiLCJ2YWxpZGF0aW9uTWlkZGxld2FyZSIsInBvc3QiLCJyZXZlcnNlZE1pbWUiLCJwbmciLCJqcGVnIiwiZ2lmIiwicmVxdWVzdEV4cG9ydCIsInJlcXVlc3RDb3VudGVyIiwiY29ubmVjdGlvbkFib3J0ZWQiLCJzb2NrZXQiLCJoYWRFcnJvcnMiLCJoZWFkZXIiLCJhdHRhY2htZW50IiwiZXhwb3J0Um91dGVzIiwic2VydmVyU3RhcnRUaW1lIiwicGFja2FnZUZpbGUiLCJzdWNjZXNzUmF0ZXMiLCJyZWNvcmRJbnRlcnZhbCIsIndpbmRvd1NpemUiLCJfY2FsY3VsYXRlTW92aW5nQXZlcmFnZSIsImEiLCJiIiwiX3N0YXJ0U3VjY2Vzc1JhdGUiLCJzZXRJbnRlcnZhbCIsInN0YXRzIiwic3VjY2Vzc1JhdGlvIiwiaGVhbHRoUm91dGVzIiwicGVyaW9kIiwibW92aW5nQXZlcmFnZSIsImJvb3RUaW1lIiwidXB0aW1lIiwiZmxvb3IiLCJzZXJ2ZXJWZXJzaW9uIiwiaGlnaGNoYXJ0c1ZlcnNpb24iLCJhdmVyYWdlRXhwb3J0VGltZSIsImF0dGVtcHRlZEV4cG9ydHMiLCJwZXJmb3JtZWRFeHBvcnRzIiwiZmFpbGVkRXhwb3J0cyIsInN1Y2Vzc1JhdGlvIiwidG9GaXhlZCIsInN2Z0V4cG9ydHMiLCJqc29uRXhwb3J0cyIsInN2Z0V4cG9ydHNBdHRlbXB0cyIsImpzb25FeHBvcnRzQXR0ZW1wdHMiLCJ1aVJvdXRlcyIsInNlbmRGaWxlIiwiYWNjZXB0UmFuZ2VzIiwidmVyc2lvbkNoYW5nZVJvdXRlcyIsImFkbWluVG9rZW4iLCJ0b2tlbiIsImFjdGl2ZVNlcnZlcnMiLCJNYXAiLCJleHByZXNzIiwic3RhcnRTZXJ2ZXIiLCJzZXJ2ZXJPcHRpb25zIiwidXBsb2FkTGltaXRCeXRlcyIsInN0b3JhZ2UiLCJtdWx0ZXIiLCJtZW1vcnlTdG9yYWdlIiwidXBsb2FkIiwibGltaXRzIiwiZmllbGRTaXplIiwiZGlzYWJsZSIsImNvcnMiLCJtZXRob2RzIiwic2V0IiwibGltaXQiLCJ1cmxlbmNvZGVkIiwiZXh0ZW5kZWQiLCJub25lIiwic3RhdGljIiwiaHR0cFNlcnZlciIsImNyZWF0ZVNlcnZlciIsIl9hdHRhY2hTZXJ2ZXJFcnJvckhhbmRsZXJzIiwibGlzdGVuIiwiY2VydCIsInJlYWRGaWxlIiwiaHR0cHNTZXJ2ZXIiLCJjbG9zZVNlcnZlcnMiLCJkZWxldGUiLCJnZXRTZXJ2ZXJzIiwiZ2V0RXhwcmVzcyIsImdldEFwcCIsImVuYWJsZVJhdGVMaW1pdGluZyIsIm1pZGRsZXdhcmVzIiwic2h1dGRvd25DbGVhblVwIiwiZXhpdENvZGUiLCJleGl0IiwiaW5pdEV4cG9ydCIsIl9hdHRhY2hQcm9jZXNzRXhpdExpc3RlbmVycyIsImNvZGUiXSwibWFwcGluZ3MiOiJ3bkJBMkJPLE1BQU1BLFlBQVlDLElBQWFBLGNBQUMsSUFBSUMsSUFBSSxPQUFRLG9CQUFBQyxTQUFBQyxRQUFBLE9BQUFDLGNBQUFDLFlBQUFDLEtBQUFDLHdCQUFBLFdBQUFBLHVCQUFBQyxRQUFBQyxlQUFBRix1QkFBQUcsS0FBQSxJQUFBVCxJQUFBLFlBQUFDLFNBQUFTLFNBQUFMLE9BK0JoRCxTQUFTTSxTQUFTQyxHQUV2QixHQUFlLE9BQVhBLEdBQXFDLGlCQUFYQSxFQUM1QixPQUFPQSxFQUlULE1BQU1DLEVBQWFDLE1BQU1DLFFBQVFILEdBQVUsR0FBSyxHQUdoRCxJQUFLLE1BQU1JLEtBQU9KLEVBQ1pLLE9BQU9DLFVBQVVDLGVBQWVDLEtBQUtSLEVBQVFJLEtBQy9DSCxFQUFXRyxHQUFPTCxTQUFTQyxFQUFPSSxLQUt0QyxPQUFPSCxDQUNULENBMkRPLFNBQVNRLFVBQVVDLEdBQ3hCLElBRUUs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 +"use strict";Object.defineProperty(exports,"__esModule",{value:!0}),require("colors");var fs=require("fs"),path=require("path"),httpsProxyAgent=require("https-proxy-agent"),url=require("url"),dotenv=require("dotenv"),zod=require("zod"),http=require("http"),https=require("https"),tarn=require("tarn"),uuid=require("uuid"),puppeteer=require("puppeteer"),DOMPurify=require("dompurify"),jsdom=require("jsdom"),promises=require("fs/promises"),cors=require("cors"),express=require("express"),multer=require("multer"),rateLimit=require("express-rate-limit"),_documentCurrentScript="undefined"!=typeof document?document.currentScript:null;const __dirname$1=url.fileURLToPath(new URL("../.","undefined"==typeof document?require("url").pathToFileURL(__filename).href:_documentCurrentScript&&"SCRIPT"===_documentCurrentScript.tagName.toUpperCase()&&_documentCurrentScript.src||new URL("index.cjs",document.baseURI).href));function deepCopy(e){if(null===e||"object"!=typeof e)return e;const t=Array.isArray(e)?[]:{};for(const o in e)Object.prototype.hasOwnProperty.call(e,o)&&(t[o]=deepCopy(e[o]));return t}function fixConstr(e){try{const t=`${e.toLowerCase().replace("chart","")}Chart`;return"Chart"===t&&t.toLowerCase(),["chart","stockChart","mapChart","ganttChart"].includes(t)?t:"chart"}catch{return"chart"}}function fixOutfile(e,t){return`${getAbsolutePath(t||"chart").split(".").shift()}.${e}`}function fixType(e,t=null){const o={"image/png":"png","image/jpeg":"jpeg","application/pdf":"pdf","image/svg+xml":"svg"},r=Object.values(o);if(t){const o=t.split(".").pop();"jpg"===o?e="jpeg":r.includes(o)&&e!==o&&(e=o)}return o[e]||r.find((t=>t===e))||"png"}function getAbsolutePath(e){return path.isAbsolute(e)?e:path.join(__dirname$1,e)}function getBase64(e,t){return"pdf"===t||"svg"==t?Buffer.from(e,"utf8").toString("base64"):e}function getNewDate(){return(new Date).toString().split("(")[0].trim()}function getNewDateTime(){return(new Date).getTime()}function isObject(e){return"[object Object]"===Object.prototype.toString.call(e)}function isObjectEmpty(e){return"object"==typeof e&&!Array.isArray(e)&&null!==e&&0===Object.keys(e).length}function isPrivateRangeUrlFound(e){return[/xlink:href="(?:http:\/\/|https:\/\/)?localhost\b/,/xlink:href="(?:http:\/\/|https:\/\/)?10\.\d{1,3}\.\d{1,3}\.\d{1,3}\b/,/xlink:href="(?:http:\/\/|https:\/\/)?127\.\d{1,3}\.\d{1,3}\.\d{1,3}\b/,/xlink:href="(?:http:\/\/|https:\/\/)?172\.(1[6-9]|2[0-9]|3[0-1])\.\d{1,3}\.\d{1,3}\b/,/xlink:href="(?:http:\/\/|https:\/\/)?192\.168\.\d{1,3}\.\d{1,3}\b/].some((t=>t.test(e)))}function measureTime(){const e=process.hrtime.bigint();return()=>Number(process.hrtime.bigint()-e)/1e6}function roundNumber(e,t=1){const o=Math.pow(10,t||0);return Math.round(+e*o)/o}function wrapAround(e,t,o=!1){if(e&&"string"==typeof e)return(e=e.trim()).endsWith(".js")?t?wrapAround(fs.readFileSync(getAbsolutePath(e),"utf8"),t,o):null:!o&&(e.startsWith("function()")||e.startsWith("function ()")||e.startsWith("()=>")||e.startsWith("() =>"))?`(${e})()`:e.replace(/;$/,"")}const colors=["red","yellow","blue","gray","green"],logging={toConsole:!0,toFile:!1,pathCreated:!1,pathToLog:"",levelsDesc:[{title:"error",color:colors[0]},{title:"warning",color:colors[1]},{title:"notice",color:colors[2]},{title:"verbose",color:colors[3]},{title:"benchmark",color:colors[4]}]};function log(...e){const[t,...o]=e,{levelsDesc:r,level:n}=logging;if(5!==t&&(0===t||t>n||n>r.length))return;const i=`${getNewDate()} [${r[t-1].title}] -`;logging.toFile&&_logToFile(o,i),logging.toConsole&&console.log.apply(void 0,[i.toString()[logging.levelsDesc[t-1].color]].concat(o))}function logWithStack(e,t,o){const r=o||t.message,{level:n,levelsDesc:i}=logging;if(0===e||e>n||n>i.length)return;const s=`${getNewDate()} [${i[e-1].title}] -`,a=t.stack,l=[r];a&&l.push("\n",a),logging.toFile&&_logToFile(l,s),logging.toConsole&&console.log.apply(void 0,[s.toString()[logging.levelsDesc[e-1].color]].concat([l.shift()[colors[e-1]],...l]))}function logZodIssues(e,t=[],o){logWithStack(e,null,[`${o} - the following Zod issues occured:`,...t.map((e=>`- ${e.message}`))].join("\n"))}function initLogging(e){const{level:t,dest:o,file:r,toConsole:n,toFile:i}=e;setLogLevel(t),enableConsoleLogging(n),enableFileLogging(o,r,i)}function setLogLevel(e){e>=0&&e<=logging.levelsDesc.length&&(logging.level=e)}function enableConsoleLogging(e){logging.toConsole=e}function enableFileLogging(e,t,o){logging.toFile=o,o&&(logging.dest=e,logging.file=t)}function _logToFile(e,t){logging.pathCreated||(!fs.existsSync(getAbsolutePath(logging.dest))&&fs.mkdirSync(getAbsolutePath(logging.dest)),logging.pathToLog=getAbsolutePath(path.join(logging.dest,logging.file)),logging.pathCreated=!0),fs.appendFile(logging.pathToLog,[t].concat(e).join(" ")+"\n",(e=>{e&&logging.toFile&&logging.pathCreated&&(logging.toFile=!1,logging.pathCreated=!1,logWithStack(2,e,"[logger] Unable to write to log file."))}))}const defaultConfig={puppeteer:{args:{value:["--allow-running-insecure-content","--ash-no-nudges","--autoplay-policy=user-gesture-required","--block-new-web-contents","--disable-accelerated-2d-canvas","--disable-background-networking","--disable-background-timer-throttling","--disable-backgrounding-occluded-windows","--disable-breakpad","--disable-checker-imaging","--disable-client-side-phishing-detection","--disable-component-extensions-with-background-pages","--disable-component-update","--disable-default-apps","--disable-dev-shm-usage","--disable-domain-reliability","--disable-extensions","--disable-features=CalculateNativeWinOcclusion,InterestFeedContentSuggestions,WebOTP","--disable-hang-monitor","--disable-ipc-flooding-protection","--disable-logging","--disable-notifications","--disable-offer-store-unmasked-wallet-cards","--disable-popup-blocking","--disable-print-preview","--disable-prompt-on-repost","--disable-renderer-backgrounding","--disable-search-engine-choice-screen","--disable-session-crashed-bubble","--disable-setuid-sandbox","--disable-site-isolation-trials","--disable-speech-api","--disable-sync","--enable-unsafe-webgpu","--hide-crash-restore-bubble","--hide-scrollbars","--metrics-recording-only","--mute-audio","--no-default-browser-check","--no-first-run","--no-pings","--no-sandbox","--no-startup-window","--no-zygote","--password-store=basic","--process-per-tab","--use-mock-keychain"],types:["string[]"],envLink:"PUPPETEER_ARGS",cliName:"puppeteerArgs",description:"Array of Puppeteer arguments",promptOptions:{type:"list",separator:";"}}},highcharts:{version:{value:"latest",types:["string"],envLink:"HIGHCHARTS_VERSION",description:"Highcharts version",promptOptions:{type:"text"}},cdnUrl:{value:"https://code.highcharts.com",types:["string"],envLink:"HIGHCHARTS_CDN_URL",description:"CDN URL for Highcharts scripts",promptOptions:{type:"text"}},forceFetch:{value:!1,types:["boolean"],envLink:"HIGHCHARTS_FORCE_FETCH",description:"Flag to refetch scripts after each server rerun",promptOptions:{type:"toggle"}},cachePath:{value:".cache",types:["string"],envLink:"HIGHCHARTS_CACHE_PATH",description:"Directory path for cached Highcharts scripts",promptOptions:{type:"text"}},coreScripts:{value:["highcharts","highcharts-more","highcharts-3d"],types:["string[]"],envLink:"HIGHCHARTS_CORE_SCRIPTS",description:"Highcharts core scripts to fetch",promptOptions:{type:"multiselect",instructions:"Space: Select specific, A: Select all, Enter: Confirm"}},moduleScripts:{value:["stock","map","gantt","exporting","parallel-coordinates","accessibility","boost-canvas","boost","data","data-tools","draggable-points","static-scale","broken-axis","heatmap","tilemap","tiledwebmap","timeline","treemap","treegraph","item-series","drilldown","histogram-bellcurve","bullet","funnel","funnel3d","geoheatmap","pyramid3d","networkgraph","overlapping-datalabels","pareto","pattern-fill","pictorial","price-indicator","sankey","arc-diagram","dependency-wheel","series-label","series-on-point","solid-gauge","sonification","streamgraph","sunburst","variable-pie","variwide","vector","venn","windbarb","wordcloud","xrange","no-data-to-display","drag-panes","debugger","dumbbell","lollipop","cylinder","organization","dotplot","marker-clusters","hollowcandlestick","heikinashi","flowmap","export-data","navigator","textpath"],types:["string[]"],envLink:"HIGHCHARTS_MODULE_SCRIPTS",description:"Highcharts module scripts to fetch",promptOptions:{type:"multiselect",instructions:"Space: Select specific, A: Select all, Enter: Confirm"}},indicatorScripts:{value:["indicators-all"],types:["string[]"],envLink:"HIGHCHARTS_INDICATOR_SCRIPTS",description:"Highcharts indicator scripts to fetch",promptOptions:{type:"multiselect",instructions:"Space: Select specific, A: Select all, Enter: Confirm"}},customScripts:{value:["https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.30.1/moment.min.js","https://cdnjs.cloudflare.com/ajax/libs/moment-timezone/0.5.45/moment-timezone-with-data.min.js"],types:["string[]"],envLink:"HIGHCHARTS_CUSTOM_SCRIPTS",description:"Additional custom scripts or dependencies to fetch",promptOptions:{type:"list",separator:";"}}},export:{infile:{value:null,types:["string","null"],envLink:"EXPORT_INFILE",description:"Input filename with type, formatted correctly as JSON or SVG",promptOptions:{type:"text"}},instr:{value:null,types:["string","null"],envLink:"EXPORT_INSTR",description:"Overrides the `infile` with JSON, stringified JSON, or SVG input",promptOptions:{type:"text"}},options:{value:null,types:["Object","null"],envLink:"EXPORT_OPTIONS",description:"Alias for the `instr` option",promptOptions:{type:"text"}},svg:{value:null,types:["string","null"],envLink:"EXPORT_SVG",description:"SVG string representation of the chart to render",promptOptions:{type:"text"}},batch:{value:null,types:["string","null"],envLink:"EXPORT_BATCH",description:'Batch job string with input/output pairs: "in=out;in=out;..."',promptOptions:{type:"text"}},outfile:{value:null,types:["string","null"],envLink:"EXPORT_OUTFILE",description:"Output filename with type. Can be jpeg, png, pdf, or svg and ignores `type` option",promptOptions:{type:"text"}},type:{value:"png",types:["string"],envLink:"EXPORT_TYPE",description:"File export format. Can be jpeg, png, pdf, or svg",promptOptions:{type:"select",hint:"Default: png",choices:["png","jpeg","pdf","svg"]}},constr:{value:"chart",types:["string"],envLink:"EXPORT_CONSTR",description:"Chart constructor. Can be chart, stockChart, mapChart, or ganttChart",promptOptions:{type:"select",hint:"Default: chart",choices:["chart","stockChart","mapChart","ganttChart"]}},b64:{value:!1,types:["boolean"],envLink:"EXPORT_B64",description:"Whether or not to the chart should be received in Base64 format instead of binary",promptOptions:{type:"toggle"}},noDownload:{value:!1,types:["boolean"],envLink:"EXPORT_NO_DOWNLOAD",description:"Whether or not to include or exclude attachment headers in the response",promptOptions:{type:"toggle"}},height:{value:null,types:["number","null"],envLink:"EXPORT_HEIGHT",description:"Height of the exported chart, overrides chart settings",promptOptions:{type:"number"}},width:{value:null,types:["number","null"],envLink:"EXPORT_WIDTH",description:"Width of the exported chart, overrides chart settings",promptOptions:{type:"number"}},scale:{value:null,types:["number","null"],envLink:"EXPORT_SCALE",description:"Scale of the exported chart, overrides chart settings. Ranges from 0.1 to 5.0",promptOptions:{type:"number"}},defaultHeight:{value:400,types:["number"],envLink:"EXPORT_DEFAULT_HEIGHT",description:"Default height of the exported chart if not set",promptOptions:{type:"number"}},defaultWidth:{value:600,types:["number"],envLink:"EXPORT_DEFAULT_WIDTH",description:"Default width of the exported chart if not set",promptOptions:{type:"number"}},defaultScale:{value:1,types:["number"],envLink:"EXPORT_DEFAULT_SCALE",description:"Default scale of the exported chart if not set. Ranges from 0.1 to 5.0",promptOptions:{type:"number",min:.1,max:5}},globalOptions:{value:null,types:["Object","string","null"],envLink:"EXPORT_GLOBAL_OPTIONS",description:"JSON, stringified JSON or filename with global options for Highcharts.setOptions",promptOptions:{type:"text"}},themeOptions:{value:null,types:["Object","string","null"],envLink:"EXPORT_THEME_OPTIONS",description:"JSON, stringified JSON or filename with theme options for Highcharts.setOptions",promptOptions:{type:"text"}},rasterizationTimeout:{value:1500,types:["number"],envLink:"EXPORT_RASTERIZATION_TIMEOUT",description:"Milliseconds to wait for webpage rendering",promptOptions:{type:"number"}}},customLogic:{allowCodeExecution:{value:!1,types:["boolean"],envLink:"CUSTOM_LOGIC_ALLOW_CODE_EXECUTION",description:"Allows or disallows execution of arbitrary code during exporting",promptOptions:{type:"toggle"}},allowFileResources:{value:!1,types:["boolean"],envLink:"CUSTOM_LOGIC_ALLOW_FILE_RESOURCES",description:"Allows or disallows injection of filesystem resources (disabled in server mode)",promptOptions:{type:"toggle"}},customCode:{value:null,types:["string","null"],envLink:"CUSTOM_LOGIC_CUSTOM_CODE",description:"Custom code to execute before chart initialization. Can be a function, code wrapped in a function, or a .js filename",promptOptions:{type:"text"}},callback:{value:null,types:["string","null"],envLink:"CUSTOM_LOGIC_CALLBACK",description:"JavaScript code to run during construction. Can be a function or a .js filename",promptOptions:{type:"text"}},resources:{value:null,types:["Object","string","null"],envLink:"CUSTOM_LOGIC_RESOURCES",description:"Additional resources as JSON, stringified JSON, or filename, containing files, js, and css sections",promptOptions:{type:"text"}},loadConfig:{value:null,types:["string","null"],envLink:"CUSTOM_LOGIC_LOAD_CONFIG",legacyName:"fromFile",description:"File with a pre-defined configuration to use",promptOptions:{type:"text"}},createConfig:{value:null,types:["string","null"],envLink:"CUSTOM_LOGIC_CREATE_CONFIG",description:"Prompt-based option setting, saved to a provided config file",promptOptions:{type:"text"}}},server:{enable:{value:!1,types:["boolean"],envLink:"SERVER_ENABLE",cliName:"enableServer",description:"Starts the server when true",promptOptions:{type:"toggle"}},host:{value:"0.0.0.0",types:["string"],envLink:"SERVER_HOST",description:"Hostname of the server",promptOptions:{type:"text"}},port:{value:7801,types:["number"],envLink:"SERVER_PORT",description:"Port number for the server",promptOptions:{type:"number"}},uploadLimit:{value:3,types:["number"],envLink:"SERVER_UPLOAD_LIMIT",description:"Maximum request body size in MB",promptOptions:{type:"number"}},benchmarking:{value:!1,types:["boolean"],envLink:"SERVER_BENCHMARKING",cliName:"serverBenchmarking",description:"Displays or not action durations in milliseconds during server requests",promptOptions:{type:"toggle"}},proxy:{host:{value:null,types:["string","null"],envLink:"SERVER_PROXY_HOST",cliName:"proxyHost",description:"Host of the proxy server, if applicable",promptOptions:{type:"text"}},port:{value:null,types:["number","null"],envLink:"SERVER_PROXY_PORT",cliName:"proxyPort",description:"Port of the proxy server, if applicable",promptOptions:{type:"number"}},timeout:{value:5e3,types:["number"],envLink:"SERVER_PROXY_TIMEOUT",cliName:"proxyTimeout",description:"Timeout in milliseconds for the proxy server, if applicable",promptOptions:{type:"number"}}},rateLimiting:{enable:{value:!1,types:["boolean"],envLink:"SERVER_RATE_LIMITING_ENABLE",cliName:"enableRateLimiting",description:"Enables or disables rate limiting on the server",promptOptions:{type:"toggle"}},maxRequests:{value:10,types:["number"],envLink:"SERVER_RATE_LIMITING_MAX_REQUESTS",legacyName:"rateLimit",description:"Maximum number of requests allowed per minute",promptOptions:{type:"number"}},window:{value:1,types:["number"],envLink:"SERVER_RATE_LIMITING_WINDOW",description:"Time window in minutes for rate limiting",promptOptions:{type:"number"}},delay:{value:0,types:["number"],envLink:"SERVER_RATE_LIMITING_DELAY",description:"Delay duration between successive requests before reaching the limit",promptOptions:{type:"number"}},trustProxy:{value:!1,types:["boolean"],envLink:"SERVER_RATE_LIMITING_TRUST_PROXY",description:"Set to true if the server is behind a load balancer",promptOptions:{type:"toggle"}},skipKey:{value:null,types:["string","null"],envLink:"SERVER_RATE_LIMITING_SKIP_KEY",description:"Key to bypass the rate limiter, used with `skipToken`",promptOptions:{type:"text"}},skipToken:{value:null,types:["string","null"],envLink:"SERVER_RATE_LIMITING_SKIP_TOKEN",description:"Token to bypass the rate limiter, used with `skipKey`",promptOptions:{type:"text"}}},ssl:{enable:{value:!1,types:["boolean"],envLink:"SERVER_SSL_ENABLE",cliName:"enableSsl",description:"Enables or disables SSL protocol",promptOptions:{type:"toggle"}},force:{value:!1,types:["boolean"],envLink:"SERVER_SSL_FORCE",cliName:"sslForce",legacyName:"sslOnly",description:"Forces the server to use HTTPS only when true",promptOptions:{type:"toggle"}},port:{value:443,types:["number"],envLink:"SERVER_SSL_PORT",cliName:"sslPort",description:"Port for the SSL server",promptOptions:{type:"number"}},certPath:{value:null,types:["string","null"],envLink:"SERVER_SSL_CERT_PATH",cliName:"sslCertPath",legacyName:"sslPath",description:"Path to the SSL certificate/key file",promptOptions:{type:"text"}}}},pool:{minWorkers:{value:4,types:["number"],envLink:"POOL_MIN_WORKERS",description:"Minimum and initial number of pool workers to spawn",promptOptions:{type:"number"}},maxWorkers:{value:8,types:["number"],envLink:"POOL_MAX_WORKERS",legacyName:"workers",description:"Maximum number of pool workers to spawn",promptOptions:{type:"number"}},workLimit:{value:40,types:["number"],envLink:"POOL_WORK_LIMIT",description:"Number of tasks a worker can handle before restarting",promptOptions:{type:"number"}},acquireTimeout:{value:5e3,types:["number"],envLink:"POOL_ACQUIRE_TIMEOUT",description:"Timeout in milliseconds for acquiring a resource",promptOptions:{type:"number"}},createTimeout:{value:5e3,types:["number"],envLink:"POOL_CREATE_TIMEOUT",description:"Timeout in milliseconds for creating a resource",promptOptions:{type:"number"}},destroyTimeout:{value:5e3,types:["number"],envLink:"POOL_DESTROY_TIMEOUT",description:"Timeout in milliseconds for destroying a resource",promptOptions:{type:"number"}},idleTimeout:{value:3e4,types:["number"],envLink:"POOL_IDLE_TIMEOUT",description:"Timeout in milliseconds for destroying idle resources",promptOptions:{type:"number"}},createRetryInterval:{value:200,types:["number"],envLink:"POOL_CREATE_RETRY_INTERVAL",description:"Interval in milliseconds before retrying resource creation on failure",promptOptions:{type:"number"}},reaperInterval:{value:1e3,types:["number"],envLink:"POOL_REAPER_INTERVAL",description:"Interval in milliseconds to check and destroy idle resources",promptOptions:{type:"number"}},benchmarking:{value:!1,types:["boolean"],envLink:"POOL_BENCHMARKING",cliName:"poolBenchmarking",description:"Shows statistics for the pool of resources",promptOptions:{type:"toggle"}}},logging:{level:{value:4,types:["number"],envLink:"LOGGING_LEVEL",cliName:"logLevel",description:"Logging verbosity level",promptOptions:{type:"number",round:0,min:0,max:5}},file:{value:"highcharts-export-server.log",types:["string"],envLink:"LOGGING_FILE",cliName:"logFile",description:"Log file name. Requires `logToFile` and `logDest` to be set",promptOptions:{type:"text"}},dest:{value:"log",types:["string"],envLink:"LOGGING_DEST",cliName:"logDest",description:"Path to store log files. Requires `logToFile` to be set",promptOptions:{type:"text"}},toConsole:{value:!0,types:["boolean"],envLink:"LOGGING_TO_CONSOLE",cliName:"logToConsole",description:"Enables or disables console logging",promptOptions:{type:"toggle"}},toFile:{value:!0,types:["boolean"],envLink:"LOGGING_TO_FILE",cliName:"logToFile",description:"Enables or disables logging to a file",promptOptions:{type:"toggle"}}},ui:{enable:{value:!1,types:["boolean"],envLink:"UI_ENABLE",cliName:"enableUi",description:"Enables or disables the UI for the export server",promptOptions:{type:"toggle"}},route:{value:"/",types:["string"],envLink:"UI_ROUTE",cliName:"uiRoute",description:"The endpoint route for the UI",promptOptions:{type:"text"}}},other:{nodeEnv:{value:"production",types:["string"],envLink:"OTHER_NODE_ENV",description:"The Node.js environment type",promptOptions:{type:"text"}},listenToProcessExits:{value:!0,types:["boolean"],envLink:"OTHER_LISTEN_TO_PROCESS_EXITS",description:"Whether or not to attach process.exit handlers",promptOptions:{type:"toggle"}},noLogo:{value:!1,types:["boolean"],envLink:"OTHER_NO_LOGO",description:"Display or skip printing the logo on startup",promptOptions:{type:"toggle"}},hardResetPage:{value:!1,types:["boolean"],envLink:"OTHER_HARD_RESET_PAGE",description:"Whether or not to reset the page content entirely",promptOptions:{type:"toggle"}},browserShellMode:{value:!0,types:["boolean"],envLink:"OTHER_BROWSER_SHELL_MODE",description:"Whether or not to set the browser to run in shell mode",promptOptions:{type:"toggle"}}},debug:{enable:{value:!1,types:["boolean"],envLink:"DEBUG_ENABLE",cliName:"enableDebug",description:"Enables or disables debug mode for the underlying browser",promptOptions:{type:"toggle"}},headless:{value:!1,types:["boolean"],envLink:"DEBUG_HEADLESS",description:"Whether or not to set the browser to run in headless mode during debugging",promptOptions:{type:"toggle"}},devtools:{value:!1,types:["boolean"],envLink:"DEBUG_DEVTOOLS",description:"Enables or disables DevTools in headful mode",promptOptions:{type:"toggle"}},listenToConsole:{value:!1,types:["boolean"],envLink:"DEBUG_LISTEN_TO_CONSOLE",description:"Enables or disables listening to console messages from the browser",promptOptions:{type:"toggle"}},dumpio:{value:!1,types:["boolean"],envLink:"DEBUG_DUMPIO",description:"Redirects or not browser stdout and stderr to process.stdout and process.stderr",promptOptions:{type:"toggle"}},slowMo:{value:0,types:["number"],envLink:"DEBUG_SLOW_MO",description:"Delays Puppeteer operations by the specified milliseconds",promptOptions:{type:"number"}},debuggingPort:{value:9222,types:["number"],envLink:"DEBUG_DEBUGGING_PORT",description:"Port used for debugging",promptOptions:{type:"number"}}}},nestedProps=_createNestedProps(defaultConfig),absoluteProps=_createAbsoluteProps(defaultConfig);function _createNestedProps(e,t={},o=""){return Object.keys(e).forEach((r=>{const n=e[r];void 0===n.value?_createNestedProps(n,t,`${o}.${r}`):(t[n.cliName||r]=`${o}.${r}`.substring(1),void 0!==n.legacyName&&(t[n.legacyName]=`${o}.${r}`.substring(1)))})),t}function _createAbsoluteProps(e,t=[]){return Object.keys(e).forEach((o=>{const r=e[o];void 0===r.types?_createAbsoluteProps(r,t):r.types.includes("Object")&&t.push(o)})),t}dotenv.config();const{coreScripts:coreScripts,moduleScripts:moduleScripts,indicatorScripts:indicatorScripts}=defaultConfig.highcharts;zod.z.setErrorMap(_customErrorMap);const v={boolean:e=>e?zod.z.boolean():zod.z.union([zod.z.enum(["true","false","undefined","null",""]).transform((e=>["undefined","null",""].includes(e)?null:"true"===e)),zod.z.boolean()]).nullable(),string:e=>e?zod.z.string().trim().refine((e=>!["false","undefined","null",""].includes(e)),{params:{errorMessage:"The string contains a forbidden value"}}):zod.z.string().trim().transform((e=>["false","undefined","null",""].includes(e)?null:e)).nullable(),enum:(e,t)=>t?zod.z.enum([...e]):zod.z.enum([...e,"undefined","null",""]).transform((e=>["undefined","null",""].includes(e)?null:e)).nullable(),stringArray(e,t,o){const r=zod.z.string().trim().array(),n=zod.z.string().trim().transform((e=>(e.startsWith("[")&&(e=e.slice(1)),e.endsWith("]")&&(e=e.slice(0,-1)),e.split(t)))),i=t=>t.map((e=>e.trim())).filter(e);return o?r.transform(i):zod.z.union([n,r]).transform(i).transform((e=>e.length?e:null)).nullable()},positiveNum:e=>e?zod.z.number().positive():zod.z.union([zod.z.string().trim().refine((e=>!isNaN(Number(e))&&Number(e)>0||["undefined","null",""].includes(e)),{params:{errorMessage:"The value must be numeric and positive"}}).transform((e=>["undefined","null",""].includes(e)?null:Number(e))),zod.z.number().positive()]).nullable(),nonNegativeNum:e=>e?zod.z.number().nonnegative():zod.z.union([zod.z.string().trim().refine((e=>!isNaN(Number(e))&&Number(e)>=0||["undefined","null",""].includes(e)),{params:{errorMessage:"The value must be numeric and non-negative"}}).transform((e=>["undefined","null",""].includes(e)?null:Number(e))),zod.z.number().nonnegative()]).nullable(),startsWith:(e,t)=>t?zod.z.string().trim().refine((t=>e.some((e=>t.startsWith(e)))),{params:{errorMessage:`The value must be a string that starts with ${e.join(", ")}`}}):zod.z.string().trim().refine((t=>e.some((e=>t.startsWith(e)))||["undefined","null",""].includes(t)),{params:{errorMessage:`The value must be a string that starts with ${e.join(", ")}`}}).transform((e=>["undefined","null",""].includes(e)?null:e)).nullable(),chartConfig:()=>zod.z.union([zod.z.string().trim().refine((e=>e.indexOf("=0||e.indexOf("=0||e.startsWith("{")&&e.endsWith("}")||["undefined","null",""].includes(e)),{params:{errorMessage:"The value must be a string that contains '["undefined","null",""].includes(e)?null:e)),zod.z.object({}).passthrough()]).nullable(),additionalOptions:()=>zod.z.union([zod.z.string().trim().refine((e=>e.length>=6&&e.endsWith(".json")||e.startsWith("{")&&e.endsWith("}")||["undefined","null",""].includes(e)),{params:{errorMessage:"The value must be a string that ends with '.json' or starts with '{' and ends with '}'"}}).transform((e=>["undefined","null",""].includes(e)?null:e)),zod.z.object({}).passthrough()]).nullable()},config={args:e=>v.stringArray((e=>!["false","undefined","null",""].includes(e)),";",e),version:e=>e?zod.z.string().trim().refine((e=>/^(latest|\d{1,2}(\.\d{1,2}){0,2})$/.test(e)),{params:{errorMessage:"The value must be 'latest', a major version, or in the form XX.YY.ZZ"}}):zod.z.string().trim().refine((e=>/^(latest|\d{1,2}(\.\d{1,2}){0,2})$/.test(e)||["undefined","null",""].includes(e)),{params:{errorMessage:"The value must be 'latest', a major version, or in the form XX.YY.ZZ"}}).transform((e=>["undefined","null",""].includes(e)?null:e)).nullable(),cdnUrl:e=>v.startsWith(["http://","https://"],e),forceFetch:e=>v.boolean(e),cachePath:e=>v.string(e),adminToken:e=>v.string(e),coreScripts:e=>v.stringArray((e=>coreScripts.value.includes(e)),",",e),moduleScripts:e=>v.stringArray((e=>moduleScripts.value.includes(e)),",",e),indicatorScripts:e=>v.stringArray((e=>indicatorScripts.value.includes(e)),",",e),customScripts:e=>v.stringArray((e=>e.startsWith("https://")||e.startsWith("http://")),",",e),infile:e=>e?zod.z.string().trim().refine((e=>e.length>=6&&e.endsWith(".json")||e.length>=5&&e.endsWith(".svg")),{params:{errorMessage:"The value must be a string that ends with .json or .svg"}}).nullable():zod.z.string().trim().refine((e=>e.length>=6&&e.endsWith(".json")||e.length>=5&&e.endsWith(".svg")||["undefined","null",""].includes(e)),{params:{errorMessage:"The value must be a string that ends with .json or .svg"}}).transform((e=>["undefined","null",""].includes(e)?null:e)).nullable(),instr:()=>v.chartConfig(),options:()=>v.chartConfig(),svg:()=>zod.z.string().trim().refine((e=>e.indexOf("=0||e.indexOf("=0||["false","undefined","null",""].includes(e)),{params:{errorMessage:"The value must be a string that contains '["false","undefined","null",""].includes(e)?null:e)).nullable(),outfile:e=>e?zod.z.string().trim().refine((e=>e.length>=6&&e.endsWith(".jpeg")||e.length>=5&&(e.endsWith(".jpg")||e.endsWith(".png")||e.endsWith(".pdf")||e.endsWith(".svg"))),{params:{errorMessage:"The value must be a string that ends with .jpeg, .jpg, .png, .pdf, or .svg"}}).nullable():zod.z.string().trim().refine((e=>e.length>=6&&e.endsWith(".jpeg")||e.length>=5&&(e.endsWith(".jpg")||e.endsWith(".png")||e.endsWith(".pdf")||e.endsWith(".svg"))||["undefined","null",""].includes(e)),{params:{errorMessage:"The value must be a string that ends with .jpeg, .jpg, .png, .pdf, or .svg"}}).transform((e=>["undefined","null",""].includes(e)?null:e)).nullable(),type:e=>v.enum(["jpeg","jpg","png","pdf","svg"],e),constr:e=>v.enum(["chart","stockChart","mapChart","ganttChart"],e),b64:e=>v.boolean(e),noDownload:e=>v.boolean(e),defaultHeight:e=>v.positiveNum(e),defaultWidth:e=>v.positiveNum(e),defaultScale:e=>e?zod.z.number().gte(.1).lte(5):zod.z.union([zod.z.string().trim().refine((e=>!isNaN(Number(e))&&!0!==e&&!e.startsWith("[")&&Number(e)>=.1&&Number(e)<=5||["undefined","null",""].includes(e)),{params:{errorMessage:"The value must be within a 0.1 and 5.0 range"}}).transform((e=>["undefined","null",""].includes(e)?null:Number(e))),zod.z.number().gte(.1).lte(5)]).nullable(),height(e){return this.defaultHeight(e).nullable()},width(e){return this.defaultWidth(e).nullable()},scale(e){return this.defaultScale(e).nullable()},globalOptions:()=>v.additionalOptions(),themeOptions:()=>v.additionalOptions(),batch:e=>v.string(e),rasterizationTimeout:e=>v.nonNegativeNum(e),allowCodeExecution:e=>v.boolean(e),allowFileResources:e=>v.boolean(e),customCode:e=>v.string(e),callback:e=>v.string(e),resources(e){const t=zod.z.object({js:v.string(!1),css:v.string(!1),files:v.stringArray((e=>!["undefined","null",""].includes(e)),",",!0).nullable()}).partial(),o=zod.z.string().trim().refine((e=>e.startsWith("{")&&e.endsWith("}")||e.length>=6&&e.endsWith(".json")),{params:{errorMessage:"The value must be a string that starts with '{' and ends with '}"}}),r=zod.z.string().trim().refine((e=>e.startsWith("{")&&e.endsWith("}")||e.length>=6&&e.endsWith(".json")||["undefined","null",""].includes(e)),{params:{errorMessage:"The value must be a string that ends with '.json'"}}).transform((e=>["undefined","null",""].includes(e)?null:e));return e?zod.z.union([t,o]).nullable():zod.z.union([t,r]).nullable()},loadConfig:e=>v.string(e).refine((e=>null===e||e.length>=6&&e.endsWith(".json")),{params:{errorMessage:"The value must be a string that ends with .json "}}),createConfig(e){return this.loadConfig(e)},enableServer:e=>v.boolean(e),host:e=>v.string(e),port:e=>v.nonNegativeNum(e),uploadLimit:e=>v.positiveNum(e),serverBenchmarking:e=>v.boolean(e),proxyHost:e=>v.string(e),proxyPort:e=>v.nonNegativeNum(e).nullable(),proxyTimeout:e=>v.nonNegativeNum(e),enableRateLimiting:e=>v.boolean(e),maxRequests:e=>v.nonNegativeNum(e),window:e=>v.nonNegativeNum(e),delay:e=>v.nonNegativeNum(e),trustProxy:e=>v.boolean(e),skipKey:e=>v.string(e),skipToken:e=>v.string(e),enableSsl:e=>v.boolean(e),sslForce:e=>v.boolean(e),sslPort:e=>v.nonNegativeNum(e),sslCertPath:e=>v.string(e),minWorkers:e=>v.positiveNum(e),maxWorkers:e=>v.positiveNum(e),workLimit:e=>v.positiveNum(e),acquireTimeout:e=>v.nonNegativeNum(e),createTimeout:e=>v.nonNegativeNum(e),destroyTimeout:e=>v.nonNegativeNum(e),idleTimeout:e=>v.nonNegativeNum(e),createRetryInterval:e=>v.nonNegativeNum(e),reaperInterval:e=>v.nonNegativeNum(e),poolBenchmarking:e=>v.boolean(e),resourcesInterval:e=>v.nonNegativeNum(e),logLevel:e=>e?zod.z.number().int().gte(0).lte(5):zod.z.union([zod.z.string().trim().refine((e=>!isNaN(Number(e))&&!0!==e&&!e.startsWith("[")&&Number.isInteger(Number(e))&&Number(e)>=0&&Number(e)<=5||["undefined","null",""].includes(e)),{params:{errorMessage:"The value must be within a 0 and 5 range"}}).transform((e=>["undefined","null",""].includes(e)?null:Number(e))),zod.z.number().int().gte(0).lte(5)]).nullable(),logFile:e=>v.string(e).refine((e=>null===e||e.length>=5&&e.endsWith(".log")),{params:{errorMessage:"The value must be a string that ends with '.log'"}}),logDest:e=>v.string(e),logToConsole:e=>v.boolean(e),logToFile:e=>v.boolean(e),enableUi:e=>v.boolean(e),uiRoute:e=>v.startsWith(["/"],e),nodeEnv:e=>v.enum(["development","production","test"],e),listenToProcessExits:e=>v.boolean(e),noLogo:e=>v.boolean(e),hardResetPage:e=>v.boolean(e),browserShellMode:e=>v.boolean(e),enableDebug:e=>v.boolean(e),headless:e=>v.boolean(e),devtools:e=>v.boolean(e),listenToConsole:e=>v.boolean(e),dumpio:e=>v.boolean(e),slowMo:e=>v.nonNegativeNum(e),debuggingPort:e=>v.nonNegativeNum(e),requestId:()=>zod.z.string().uuid({message:"The value must be a stringified UUID"}).nullable()},PuppeteerSchema=e=>zod.z.object({args:config.args(e)}).partial(),HighchartsSchema=e=>zod.z.object({version:config.version(e),cdnUrl:config.cdnUrl(e),forceFetch:config.forceFetch(e),cachePath:config.cachePath(e),coreScripts:config.coreScripts(e),moduleScripts:config.moduleScripts(e),indicatorScripts:config.indicatorScripts(e),customScripts:config.customScripts(e)}).partial(),ExportSchema=e=>zod.z.object({infile:config.infile(e),instr:config.instr(),options:config.options(),svg:config.svg(),outfile:config.outfile(e),type:config.type(e),constr:config.constr(e),b64:config.b64(e),noDownload:config.noDownload(e),defaultHeight:config.defaultHeight(e),defaultWidth:config.defaultWidth(e),defaultScale:config.defaultScale(e),height:config.height(e),width:config.width(e),scale:config.scale(e),globalOptions:config.globalOptions(),themeOptions:config.themeOptions(),batch:config.batch(!1),rasterizationTimeout:config.rasterizationTimeout(e)}).partial(),CustomLogicSchema=e=>zod.z.object({allowCodeExecution:config.allowCodeExecution(e),allowFileResources:config.allowFileResources(e),customCode:config.customCode(!1),callback:config.callback(!1),resources:config.resources(e),loadConfig:config.loadConfig(!1),createConfig:config.createConfig(!1)}).partial(),ProxySchema=e=>zod.z.object({host:config.proxyHost(!1),port:config.proxyPort(e),timeout:config.proxyTimeout(e)}).partial(),RateLimitingSchema=e=>zod.z.object({enable:config.enableRateLimiting(e),maxRequests:config.maxRequests(e),window:config.window(e),delay:config.delay(e),trustProxy:config.trustProxy(e),skipKey:config.skipKey(!1),skipToken:config.skipToken(!1)}).partial(),SslSchema=e=>zod.z.object({enable:config.enableSsl(e),force:config.sslForce(e),port:config.sslPort(e),certPath:config.sslCertPath(!1)}).partial(),ServerSchema=e=>zod.z.object({enable:config.enableServer(e).optional(),host:config.host(e).optional(),port:config.port(e).optional(),benchmarking:config.serverBenchmarking(e).optional(),proxy:ProxySchema(e).optional(),rateLimiting:RateLimitingSchema(e).optional(),ssl:SslSchema(e).optional()}),PoolSchema=e=>zod.z.object({minWorkers:config.minWorkers(e),maxWorkers:config.maxWorkers(e),workLimit:config.workLimit(e),acquireTimeout:config.acquireTimeout(e),createTimeout:config.createTimeout(e),destroyTimeout:config.destroyTimeout(e),idleTimeout:config.idleTimeout(e),createRetryInterval:config.createRetryInterval(e),reaperInterval:config.reaperInterval(e),benchmarking:config.poolBenchmarking(e)}).partial(),LoggingSchema=e=>zod.z.object({level:config.logLevel(e),file:config.logFile(e),dest:config.logDest(e),toConsole:config.logToConsole(e),toFile:config.logToFile(e)}).partial(),UiSchema=e=>zod.z.object({enable:config.enableUi(e),route:config.uiRoute(e)}).partial(),OtherSchema=e=>zod.z.object({nodeEnv:config.nodeEnv(e),listenToProcessExits:config.listenToProcessExits(e),noLogo:config.noLogo(e),hardResetPage:config.hardResetPage(e),browserShellMode:config.browserShellMode(e)}).partial(),DebugSchema=e=>zod.z.object({enable:config.enableDebug(e),headless:config.headless(e),devtools:config.devtools(e),listenToConsole:config.listenToConsole(e),dumpio:config.dumpio(e),slowMo:config.slowMo(e),debuggingPort:config.debuggingPort(e)}).partial(),StrictConfigSchema=zod.z.object({puppeteer:PuppeteerSchema(!0),highcharts:HighchartsSchema(!0),export:ExportSchema(!0),customLogic:CustomLogicSchema(!0),server:ServerSchema(!0),pool:PoolSchema(!0),logging:LoggingSchema(!0),ui:UiSchema(!0),other:OtherSchema(!0),debug:DebugSchema(!0)}),LooseConfigSchema=zod.z.object({puppeteer:PuppeteerSchema(!1),highcharts:HighchartsSchema(!1),export:ExportSchema(!1),customLogic:CustomLogicSchema(!1),server:ServerSchema(!1),pool:PoolSchema(!1),logging:LoggingSchema(!1),ui:UiSchema(!1),other:OtherSchema(!1),debug:DebugSchema(!1)}),EnvSchema=zod.z.object({PUPPETEER_ARGS:config.args(!1),HIGHCHARTS_VERSION:config.version(!1),HIGHCHARTS_CDN_URL:config.cdnUrl(!1),HIGHCHARTS_FORCE_FETCH:config.forceFetch(!1),HIGHCHARTS_CACHE_PATH:config.cachePath(!1),HIGHCHARTS_ADMIN_TOKEN:config.adminToken(!1),HIGHCHARTS_CORE_SCRIPTS:config.coreScripts(!1),HIGHCHARTS_MODULE_SCRIPTS:config.moduleScripts(!1),HIGHCHARTS_INDICATOR_SCRIPTS:config.indicatorScripts(!1),HIGHCHARTS_CUSTOM_SCRIPTS:config.customScripts(!1),EXPORT_INFILE:config.infile(!1),EXPORT_INSTR:config.instr(),EXPORT_OPTIONS:config.options(),EXPORT_SVG:config.svg(),EXPORT_BATCH:config.batch(!1),EXPORT_OUTFILE:config.outfile(!1),EXPORT_TYPE:config.type(!1),EXPORT_CONSTR:config.constr(!1),EXPORT_B64:config.b64(!1),EXPORT_NO_DOWNLOAD:config.noDownload(!1),EXPORT_HEIGHT:config.height(!1),EXPORT_WIDTH:config.width(!1),EXPORT_SCALE:config.scale(!1),EXPORT_DEFAULT_HEIGHT:config.defaultHeight(!1),EXPORT_DEFAULT_WIDTH:config.defaultWidth(!1),EXPORT_DEFAULT_SCALE:config.defaultScale(!1),EXPORT_GLOBAL_OPTIONS:config.globalOptions(),EXPORT_THEME_OPTIONS:config.themeOptions(),EXPORT_RASTERIZATION_TIMEOUT:config.rasterizationTimeout(!1),CUSTOM_LOGIC_ALLOW_CODE_EXECUTION:config.allowCodeExecution(!1),CUSTOM_LOGIC_ALLOW_FILE_RESOURCES:config.allowFileResources(!1),CUSTOM_LOGIC_CUSTOM_CODE:config.customCode(!1),CUSTOM_LOGIC_CALLBACK:config.callback(!1),CUSTOM_LOGIC_RESOURCES:config.resources(!1),CUSTOM_LOGIC_LOAD_CONFIG:config.loadConfig(!1),CUSTOM_LOGIC_CREATE_CONFIG:config.createConfig(!1),SERVER_ENABLE:config.enableServer(!1),SERVER_HOST:config.host(!1),SERVER_PORT:config.port(!1),SERVER_UPLOAD_LIMIT:config.uploadLimit(!1),SERVER_BENCHMARKING:config.serverBenchmarking(!1),SERVER_PROXY_HOST:config.proxyHost(!1),SERVER_PROXY_PORT:config.proxyPort(!1),SERVER_PROXY_TIMEOUT:config.proxyTimeout(!1),SERVER_RATE_LIMITING_ENABLE:config.enableRateLimiting(!1),SERVER_RATE_LIMITING_MAX_REQUESTS:config.maxRequests(!1),SERVER_RATE_LIMITING_WINDOW:config.window(!1),SERVER_RATE_LIMITING_DELAY:config.delay(!1),SERVER_RATE_LIMITING_TRUST_PROXY:config.trustProxy(!1),SERVER_RATE_LIMITING_SKIP_KEY:config.skipKey(!1),SERVER_RATE_LIMITING_SKIP_TOKEN:config.skipToken(!1),SERVER_SSL_ENABLE:config.enableSsl(!1),SERVER_SSL_FORCE:config.sslForce(!1),SERVER_SSL_PORT:config.sslPort(!1),SERVER_SSL_CERT_PATH:config.sslCertPath(!1),POOL_MIN_WORKERS:config.minWorkers(!1),POOL_MAX_WORKERS:config.maxWorkers(!1),POOL_WORK_LIMIT:config.workLimit(!1),POOL_ACQUIRE_TIMEOUT:config.acquireTimeout(!1),POOL_CREATE_TIMEOUT:config.createTimeout(!1),POOL_DESTROY_TIMEOUT:config.destroyTimeout(!1),POOL_IDLE_TIMEOUT:config.idleTimeout(!1),POOL_CREATE_RETRY_INTERVAL:config.createRetryInterval(!1),POOL_REAPER_INTERVAL:config.reaperInterval(!1),POOL_BENCHMARKING:config.poolBenchmarking(!1),LOGGING_LEVEL:config.logLevel(!1),LOGGING_FILE:config.logFile(!1),LOGGING_DEST:config.logDest(!1),LOGGING_TO_CONSOLE:config.logToConsole(!1),LOGGING_TO_FILE:config.logToFile(!1),UI_ENABLE:config.enableUi(!1),UI_ROUTE:config.uiRoute(!1),OTHER_NODE_ENV:config.nodeEnv(!1),OTHER_LISTEN_TO_PROCESS_EXITS:config.listenToProcessExits(!1),OTHER_NO_LOGO:config.noLogo(!1),OTHER_HARD_RESET_PAGE:config.hardResetPage(!1),OTHER_BROWSER_SHELL_MODE:config.browserShellMode(!1),DEBUG_ENABLE:config.enableDebug(!1),DEBUG_HEADLESS:config.headless(!1),DEBUG_DEVTOOLS:config.devtools(!1),DEBUG_LISTEN_TO_CONSOLE:config.listenToConsole(!1),DEBUG_DUMPIO:config.dumpio(!1),DEBUG_SLOW_MO:config.slowMo(!1),DEBUG_DEBUGGING_PORT:config.debuggingPort(!1)}),envs=EnvSchema.partial().parse(process.env);function strictValidate(e){return StrictConfigSchema.partial().parse(e)}function looseValidate(e){return LooseConfigSchema.partial().parse(e)}function validateOption(e,t,o){return config[e](o).parse(t)}function _customErrorMap(e,t){const o=e.path.join("."),r=`Invalid value for the ${o}`;if(e.code===zod.z.ZodIssueCode.invalid_type)return e.received===zod.z.ZodParsedType.undefined?{message:`${r} - No value was provided.`}:{message:`${r} - Invalid type. ${t.defaultError}.`};if(e.code===zod.z.ZodIssueCode.custom&&e.params?.errorMessage)return{message:`${r} - ${e.params?.errorMessage}, received '${t.data}'.`};if(e.code===zod.z.ZodIssueCode.invalid_union){let t=`Multiple errors occurred for the ${o}:\n`;return e.unionErrors.forEach((e=>{const o=e.issues[0].message.indexOf("-");t+=-1!==o?`${e.issues[0].message}\n`.substring(o):`${e.issues[0].message}\n`})),{message:t}}return{message:`${r} - ${t.defaultError}.`}}const globalOptions=_initGlobalOptions(defaultConfig);function getOptions(e=!0){return e?globalOptions:deepCopy(globalOptions)}function setOptions(e={},t=[],o=!1){let r={},n={};if(t.length)try{r=strictValidate(_loadConfigFile(t))}catch(e){logZodIssues(1,e.issues,"[config] Custom JSON options validation error")}if(e&&0!==Object.keys(e).length)try{e=strictValidate(e)}catch(e){logZodIssues(1,e.issues,"[config] Custom options validation error")}if(t.length)try{n=looseValidate(_pairArgumentValue(nestedProps,t))}catch(e){logZodIssues(1,e.issues,"[config] CLI options validation error")}const i=getOptions(o);return _updateOptions(defaultConfig,i,r,e,n),i}function mergeOptions(e,t){if(isObject(t))for(const[o,r]of Object.entries(t))e[o]=isObject(r)&&!absoluteProps.includes(o)&&void 0!==e[o]?mergeOptions(e[o],r):void 0!==r?r:e[o];return e}function mapToNewOptions(e){const t={};if("[object Object]"===Object.prototype.toString.call(e))for(const[o,r]of Object.entries(e)){const e=nestedProps[o]?nestedProps[o].split("."):[];e.reduce(((t,o,n)=>t[o]=e.length-1===n?r:t[o]||{}),t)}return t}function isAllowedConfig(config,toString=!1,allowFunctions=!1){try{if(!isObject(config)&&"string"!=typeof config)return null;const objectConfig="string"==typeof config?allowFunctions?eval(`(${config})`):JSON.parse(config):config,stringifiedOptions=_optionsStringify(objectConfig,allowFunctions,!1),parsedOptions=allowFunctions?JSON.parse(_optionsStringify(objectConfig,allowFunctions,!0),((_,value)=>"string"==typeof value&&value.startsWith("function")?eval(`(${value})`):value)):JSON.parse(stringifiedOptions);return toString?stringifiedOptions:parsedOptions}catch(e){return null}}function _initGlobalOptions(e){const t={};for(const[o,r]of Object.entries(e))t[o]=Object.prototype.hasOwnProperty.call(r,"value")?r.value:_initGlobalOptions(r);return t}function _updateOptions(e,t,o,r,n){Object.keys(e).forEach((i=>{const s=e[i],a=o&&o[i],l=r&&r[i],c=n&&n[i];if(void 0===s.value)_updateOptions(s,t[i],a,l,c);else{null!=a&&(t[i]=a);const e=envs[s.envLink];s.envLink in envs&&null!=e&&(t[i]=e),null!=l&&(t[i]=l),null!=c&&(t[i]=c)}}))}function _optionsStringify(e,t,o){return JSON.stringify(e,((e,r)=>{if("string"==typeof r&&(r=r.trim()),"function"==typeof r||"string"==typeof r&&r.startsWith("function")&&r.endsWith("}")){if(t)return o?`"EXP_FUN${(r+"").replaceAll(/\s+/g," ")}EXP_FUN"`:`EXP_FUN${(r+"").replaceAll(/\s+/g," ")}EXP_FUN`;throw new Error}return r})).replaceAll(o?/\\"EXP_FUN|EXP_FUN\\"/g:/"EXP_FUN|EXP_FUN"/g,"")}function _loadConfigFile(e){const t=e.findIndex((e=>"loadConfig"===e.replace(/-/g,""))),o=t>-1&&e[t+1];if(o)try{return JSON.parse(fs.readFileSync(getAbsolutePath(o)))}catch(e){logWithStack(2,e,`[config] Unable to load the configuration from the ${o} file.`)}return{}}function _pairArgumentValue(e,t){const o={};for(let r=0;r{if(i.length-1===s){const i=t[++r];i||log(2,`[config] Missing value for the CLI '--${n}' argument. Using the default value.`),e[o]=i||null}else void 0===e[o]&&(e[o]={});return e[o]}),o)}return o}async function fetch(e,t={}){return new Promise(((o,r)=>{_getProtocolModule(e).get(e,t,(e=>{let t="";e.on("data",(e=>{t+=e})),e.on("end",(()=>{t||r("Nothing was fetched from the URL."),e.text=t,o(e)}))})).on("error",(e=>{r(e)}))}))}function _getProtocolModule(e){return e.startsWith("https")?https:http}class ExportError extends Error{constructor(e,t){super(),this.message=e,this.stackMessage=e,t&&(this.statusCode=t)}setError(e){return this.error=e,e.name&&(this.name=e.name),e.statusCode&&(this.statusCode=e.statusCode),e.stack&&(this.stackMessage=e.message,this.stack=e.stack),this}}const cache={cdnUrl:"https://code.highcharts.com",activeManifest:{},sources:"",hcVersion:""};async function checkAndUpdateCache(e,t){let o;const r=getCachePath(),n=path.join(r,"manifest.json"),i=path.join(r,"sources.js");if(!fs.existsSync(r)&&fs.mkdirSync(r,{recursive:!0}),!fs.existsSync(n)||e.forceFetch)log(3,"[cache] Fetching and caching Highcharts dependencies."),o=await _updateCache(e,t,i);else{let r=!1;const s=JSON.parse(fs.readFileSync(n));if(s.modules&&Array.isArray(s.modules)){const e={};s.modules.forEach((t=>e[t]=1)),s.modules=e}const{coreScripts:a,moduleScripts:l,indicatorScripts:c}=e,p=a.length+l.length+c.length;s.version!==e.version?(log(2,"[cache] A Highcharts version mismatch in the cache, need to re-fetch."),r=!0):Object.keys(s.modules||{}).length!==p?(log(2,"[cache] The cache and the requested modules do not match, need to re-fetch."),r=!0):r=(l||[]).some((e=>{if(!s.modules[e])return log(2,`[cache] The ${e} is missing in the cache, need to re-fetch.`),!0})),r?o=await _updateCache(e,t,i):(log(3,"[cache] Dependency cache is up to date, proceeding."),cache.sources=fs.readFileSync(i,"utf8"),o=s.modules,cache.hcVersion=extractVersion(cache.sources))}await _saveConfigToManifest(e,o)}function getHighchartsVersion(){return cache.hcVersion}async function updateHighchartsVersion(e){const t=getOptions();t.highcharts.version=e,await checkAndUpdateCache(t.highcharts,t.server.proxy)}function extractVersion(e){return e.substring(0,e.indexOf("*/")).replace("/*","").replace("*/","").replace(/\n/g,"").trim()}function extractModuleName(e){return e.replace(/(.*)\/|(.*)modules\/|stock\/(.*)indicators\/|maps\/(.*)modules\//gi,"")}function getCachePath(){return getAbsolutePath(getOptions().highcharts.cachePath)}async function _fetchAndProcessScript(e,t,o,r=!1){e.endsWith(".js")&&(e=e.substring(0,e.length-3)),log(4,`[cache] Fetching script - ${e}.js`);const n=await fetch(`${e}.js`,t);if(200===n.statusCode&&"string"==typeof n.text){if(o){o[extractModuleName(e)]=1}return n.text}if(r)throw new ExportError(`[cache] Could not fetch the ${e}.js. The script might not exist in the requested version (status code: ${n.statusCode}).`,404).setError(n);log(2,`[cache] Could not fetch the ${e}.js. The script might not exist in the requested version.`)}async function _saveConfigToManifest(e,t={}){const o={version:e.version,modules:t};cache.activeManifest=o,log(3,"[cache] Writing a new manifest.");try{fs.writeFileSync(path.join(getCachePath(),"manifest.json"),JSON.stringify(o),"utf8")}catch(e){throw new ExportError("[cache] Error writing the cache manifest.",500).setError(e)}}async function _fetchScripts(e,t,o,r,n){let i;const s=r.host,a=r.port;if(s&&a)try{i=new httpsProxyAgent.HttpsProxyAgent({host:s,port:a})}catch(e){throw new ExportError("[cache] Could not create a Proxy Agent.",500).setError(e)}const l=i?{agent:i,timeout:r.timeout}:{},c=[...e.map((e=>_fetchAndProcessScript(`${e}`,l,n,!0))),...t.map((e=>_fetchAndProcessScript(`${e}`,l,n))),...o.map((e=>_fetchAndProcessScript(`${e}`,l)))];return(await Promise.all(c)).join(";\n")}async function _updateCache(e,t,o){const r="latest"===e.version?null:`${e.version}`,n=e.cdnUrl||cache.cdnUrl;try{const i={};return log(3,`[cache] Updating cache version to Highcharts: ${r||"latest"}.`),cache.sources=await _fetchScripts([...e.coreScripts.map((e=>r?`${n}/${r}/${e}`:`${n}/${e}`))],[...e.moduleScripts.map((e=>"map"===e?r?`${n}/maps/${r}/modules/${e}`:`${n}/maps/modules/${e}`:r?`${n}/${r}/modules/${e}`:`${n}/modules/${e}`)),...e.indicatorScripts.map((e=>r?`${n}/stock/${r}/indicators/${e}`:`${n}/stock/indicators/${e}`))],e.customScripts,t,i),cache.hcVersion=extractVersion(cache.sources),fs.writeFileSync(o,cache.sources),i}catch(e){throw new ExportError("[cache] Unable to update the local Highcharts cache.",500).setError(e)}}function setupHighcharts(){Highcharts.animObject=function(){return{duration:0}}}async function createChart(e){const{getOptions:t,merge:o,setOptions:r,wrap:n}=Highcharts;Highcharts.setOptionsObj=o(!1,{},t()),window.isRenderComplete=!1,n(Highcharts.Chart.prototype,"init",(function(e,t,r){((t=o(t,{exporting:{enabled:!1},plotOptions:{series:{label:{enabled:!1}}},tooltip:{}})).series||[]).forEach((function(e){e.animation=!1})),window.onHighchartsRender||(window.onHighchartsRender=Highcharts.addEvent(this,"render",(()=>{window.isRenderComplete=!0}))),e.apply(this,[t,r])})),n(Highcharts.Series.prototype,"init",(function(e,t,o){e.apply(this,[t,o])}));const i={chart:{animation:!1,height:e.export.height,width:e.export.width},exporting:{enabled:!1}},s=new Function(`return ${e.export.instr}`)(),a=new Function(`return ${e.export.themeOptions}`)(),l=new Function(`return ${e.export.globalOptions}`)(),c=o(!1,a,s,i),p=e.customLogic.callback?new Function(`return ${e.customLogic.callback}`)():null;e.customLogic.customCode&&new Function("options",e.customLogic.customCode)(s),l&&r(l),Highcharts[e.export.constr]("container",c,p);const u=t();for(const e in u)"function"!=typeof u[e]&&delete u[e];r(Highcharts.setOptionsObj),Highcharts.setOptionsObj={}}const template=fs.readFileSync(path.join(__dirname$1,"templates","template.html"),"utf8");let browser=null;async function createBrowser(e){const{debug:t,other:o}=getOptions(),{enable:r,...n}=t,i={headless:!o.browserShellMode||"shell",userDataDir:"tmp",args:e||[],handleSIGINT:!1,handleSIGTERM:!1,handleSIGHUP:!1,waitForInitialPage:!1,defaultViewport:null,...r&&n};if(!browser){let e=0;const t=async()=>{try{log(3,`[browser] Attempting to get a browser instance (try ${++e}).`),browser=await puppeteer.launch(i)}catch(o){if(logWithStack(1,o,"[browser] Failed to launch a browser instance."),!(e<25))throw o;log(3,`[browser] Retry to open a browser (${e} out of 25).`),await new Promise((e=>setTimeout(e,4e3))),await t()}};try{await t(),"shell"===i.headless&&log(3,"[browser] Launched browser in shell mode."),r&&log(3,"[browser] Launched browser in debug mode.")}catch(e){throw new ExportError("[browser] Maximum retries to open a browser instance reached.",500).setError(e)}if(!browser)throw new ExportError("[browser] Cannot find a browser to open.",500)}return browser}async function closeBrowser(){browser&&browser.connected&&await browser.close(),browser=null,log(4,"[browser] Closed the browser.")}async function newPage(e){if(!browser||!browser.connected)throw new ExportError("[browser] Browser is not yet connected.",500);if(e.page=await browser.newPage(),await e.page.setCacheEnabled(!1),await _setPageContent(e.page),_setPageEvents(e.page),!e.page||e.page.isClosed())throw new ExportError("[browser] The page is invalid or closed.",400)}async function clearPage(e,t=!1){try{if(e.page&&!e.page.isClosed())return t?(await e.page.goto("about:blank",{waitUntil:"domcontentloaded"}),await _setPageContent(e.page)):await e.page.evaluate((()=>{document.body.innerHTML='
'})),!0}catch(t){logWithStack(2,t,`[pool] Pool resource [${e.id}] - Content of the page could not be cleared.`),e.workCount=getOptions().pool.workLimit+1}return!1}async function addPageResources(e,t){const o=[],r=t.resources;if(r){const n=[];if(r.js&&n.push({content:r.js}),r.files)for(const e of r.files){const t=!e.startsWith("http");n.push(t?{content:fs.readFileSync(getAbsolutePath(e),"utf8")}:{url:e})}for(const t of n)try{o.push(await e.addScriptTag(t))}catch(e){logWithStack(2,e,"[browser] The JS resource cannot be loaded.")}n.length=0;const i=[];if(r.css){let n=r.css.match(/@import\s*([^;]*);/g);if(n)for(let e of n)e&&(e=e.replace("url(","").replace("@import","").replace(/"/g,"").replace(/'/g,"").replace(/;/,"").replace(/\)/g,"").trim(),e.startsWith("http")?i.push({url:e}):t.allowFileResources&&i.push({path:path.join(__dirname$1,e)}));i.push({content:r.css.replace(/@import\s*([^;]*);/g,"")||" "});for(const t of i)try{o.push(await e.addStyleTag(t))}catch(e){logWithStack(2,e,"[browser] The CSS resource cannot be loaded.")}i.length=0}}return o}async function clearPageResources(e,t){try{for(const e of t)await e.dispose();await e.evaluate((()=>{if("undefined"!=typeof Highcharts){const e=Highcharts.charts;if(Array.isArray(e)&&e.length)for(const t of e)t&&t.destroy(),Highcharts.charts.shift()}const[...e]=document.getElementsByTagName("script"),[,...t]=document.getElementsByTagName("style"),[...o]=document.getElementsByTagName("link");for(const r of[...e,...t,...o])r.remove()}))}catch(e){logWithStack(2,e,"[browser] Could not clear page's resources.")}}async function _setPageContent(e){await e.setContent(template,{waitUntil:"domcontentloaded"}),await e.addScriptTag({path:path.join(getCachePath(),"sources.js")}),await e.evaluate(setupHighcharts)}function _setPageEvents(e){const{debug:t}=getOptions();e.on("pageerror",(async()=>{e.isClosed()})),t.enable&&t.listenToConsole&&e.on("console",(e=>{console.log(`[debug] ${e.text()}`)}))}var cssTemplate=()=>"\n\nhtml, body {\n margin: 0;\n padding: 0;\n box-sizing: border-box;\n}\n\n#table-div, #sliders, #datatable, #controls, .ld-row {\n display: none;\n height: 0;\n}\n\n#chart-container {\n box-sizing: border-box;\n margin: 0;\n overflow: auto;\n font-size: 0;\n}\n\n#chart-container > figure, div {\n margin-top: 0 !important;\n margin-bottom: 0 !important;\n}\n\n",svgTemplate=e=>`\n\n\n \n \n Highcharts Export\n \n \n \n
\n ${e}\n
\n \n\n\n`;async function puppeteerExport(e,t){const o=[];try{const r=t.export;let n=!1;if(r.svg){if(log(4,"[export] Treating as SVG input."),"svg"===r.type)return r.svg;n=!0,await _setAsSvg(e,r.svg)}else log(4,"[export] Treating as JSON config."),await _setAsOptions(e,t);o.push(...await addPageResources(e,t.customLogic));const i=n?await e.evaluate((e=>{const t=document.querySelector("#chart-container svg:first-of-type"),o=t.height.baseVal.value*e,r=t.width.baseVal.value*e;return document.body.style.zoom=e,document.body.style.margin="0px",{chartHeight:o,chartWidth:r}}),parseFloat(r.scale)):await e.evaluate((()=>{const{chartHeight:e,chartWidth:t}=window.Highcharts.charts[0];return document.body.style.zoom=1,{chartHeight:e,chartWidth:t}})),{x:s,y:a}=await _getClipRegion(e),l=Math.abs(Math.ceil(i.chartHeight||r.height)),c=Math.abs(Math.ceil(i.chartWidth||r.width));let p;switch(await e.setViewport({height:l,width:c,deviceScaleFactor:n?1:parseFloat(r.scale)}),r.type){case"svg":p=await _createSVG(e);break;case"png":case"jpeg":p=await _createImage(e,r.type,{width:c,height:l,x:s,y:a},r.rasterizationTimeout);break;case"pdf":p=await _createPDF(e,l,c,r.rasterizationTimeout);break;default:throw new ExportError(`[export] Unsupported output format: ${r.type}.`,400)}return await clearPageResources(e,o),p}catch(t){return await clearPageResources(e,o),t}}async function _setAsSvg(e,t){await e.setContent(svgTemplate(t),{waitUntil:"domcontentloaded"})}async function _setAsOptions(e,t){await e.evaluate(createChart,t)}async function _getClipRegion(e){return e.$eval("#chart-container",(e=>{const{x:t,y:o,width:r,height:n}=e.getBoundingClientRect();return{x:t,y:o,width:r,height:Math.trunc(n>1?n:500)}}))}async function _createSVG(e){return e.$eval("#container svg:first-of-type",(e=>e.outerHTML))}async function _createImage(e,t,o,r){return Promise.race([e.screenshot({type:t,clip:o,encoding:"base64",fullPage:!1,optimizeForSpeed:!0,captureBeyondViewport:!0,..."png"!==t?{quality:80}:{},omitBackground:"png"==t}),new Promise(((e,t)=>setTimeout((()=>t(new ExportError("Rasterization timeout",408))),r||1500)))])}async function _createPDF(e,t,o,r){return await e.emulateMediaType("screen"),e.pdf({height:t+1,width:o,encoding:"base64",timeout:r||1500})}let pool=null;const poolStats={exportsAttempted:0,exportsPerformed:0,exportsDropped:0,exportsFromSvg:0,exportsFromOptions:0,exportsFromSvgAttempts:0,exportsFromOptionsAttempts:0,timeSpent:0,timeSpentAverage:0};async function initPool(e=getOptions().pool,t=[]){await createBrowser(t);try{if(log(3,`[pool] Initializing pool with workers: min ${e.minWorkers}, max ${e.maxWorkers}.`),pool)return void log(4,"[pool] Already initialized, please kill it before creating a new one.");e.minWorkers>e.maxWorkers&&(e.minWorkers=e.maxWorkers),pool=new tarn.Pool({..._factory(e),min:e.minWorkers,max:e.maxWorkers,acquireTimeoutMillis:e.acquireTimeout,createTimeoutMillis:e.createTimeout,destroyTimeoutMillis:e.destroyTimeout,idleTimeoutMillis:e.idleTimeout,createRetryIntervalMillis:e.createRetryInterval,reapIntervalMillis:e.reaperInterval,propagateCreateError:!1}),pool.on("release",(async e=>{const t=await clearPage(e,!1);log(4,`[pool] Pool resource [${e.id}] - Releasing a worker. Clear page status: ${t}.`)})),pool.on("destroySuccess",((e,t)=>{log(4,`[pool] Pool resource [${t.id}] - Destroyed a worker successfully.`),t.page=null}));const t=[];for(let o=0;o{pool.release(e)})),log(3,"[pool] The pool is ready"+(t.length?` with ${t.length} initial resources waiting.`:"."))}catch(e){throw new ExportError("[pool] Could not configure and create the pool of workers.",500).setError(e)}}async function killPool(){if(log(3,"[pool] Killing pool with all workers and closing browser."),pool){for(const e of pool.used)pool.release(e.resource);pool.destroyed||(await pool.destroy(),log(4,"[pool] Destroyed the pool of resources.")),pool=null}await closeBrowser()}async function postWork(e){let t;try{if(log(4,"[pool] Work received, starting to process."),++poolStats.exportsAttempted,getOptions().pool.benchmarking&&getPoolInfo(),!pool)throw new ExportError("[pool] Work received, but pool has not been started.",500);const o=measureTime();try{log(4,"[pool] Acquiring a worker handle."),t=await pool.acquire().promise,e.server.benchmarking&&log(5,e._requestId?`[benchmark] Request [${e._requestId}] - `:"[benchmark] ",`Acquiring a worker handle took ${o()}ms.`)}catch(t){throw new ExportError("[pool] "+(e._requestId?`Request [${e._requestId}] - `:"")+`Error encountered when acquiring an available entry: ${o()}ms.`,400).setError(t)}if(log(4,"[pool] Acquired a worker handle."),!t.page)throw t.workCount=e.pool.workLimit+1,new ExportError("[pool] Resolved worker page is invalid: the pool setup is wonky.",400);const r=getNewDateTime();log(4,`[pool] Pool resource [${t.id}] - Starting work on this pool entry.`);const n=measureTime(),i=await puppeteerExport(t.page,e);if(i instanceof Error)throw"Rasterization timeout"===i.message&&(t.workCount=e.pool.workLimit+1,t.page=null),"TimeoutError"===i.name||"Rasterization timeout"===i.message?new ExportError("[pool] "+(e._requestId?`Request [${e._requestId}] - `:"")+"Rasterization timeout: your chart may be too complex or large, and failed to render within the allotted time.").setError(i):new ExportError("[pool] "+(e._requestId?`Request [${e._requestId}] - `:"")+`Error encountered during export: ${n()}ms.`).setError(i);e.server.benchmarking&&log(5,e._requestId?`[benchmark] Request [${e._requestId}] - `:"[benchmark] ",`Exporting a chart sucessfully took ${n()}ms.`),pool.release(t);const s=getNewDateTime()-r;return poolStats.timeSpent+=s,poolStats.timeSpentAverage=poolStats.timeSpent/++poolStats.exportsPerformed,log(4,`[pool] Work completed in ${s}ms.`),{result:i,options:e}}catch(e){throw++poolStats.exportsDropped,t&&pool.release(t),e}}function getPoolStats(){return poolStats}function getPoolInfoJSON(){return{min:pool.min,max:pool.max,used:pool.numUsed(),available:pool.numFree(),allCreated:pool.numUsed()+pool.numFree(),pendingAcquires:pool.numPendingAcquires(),pendingCreates:pool.numPendingCreates(),pendingValidations:pool.numPendingValidations(),pendingDestroys:pool.pendingDestroys.length,absoluteAll:pool.numUsed()+pool.numFree()+pool.numPendingAcquires()+pool.numPendingCreates()+pool.numPendingValidations()+pool.pendingDestroys.length}}function getPoolInfo(){const{min:e,max:t,used:o,available:r,allCreated:n,pendingAcquires:i,pendingCreates:s,pendingValidations:a,pendingDestroys:l,absoluteAll:c}=getPoolInfoJSON();log(5,`[pool] The minimum number of resources allowed by pool: ${e}.`),log(5,`[pool] The maximum number of resources allowed by pool: ${t}.`),log(5,`[pool] The number of used resources: ${o}.`),log(5,`[pool] The number of free resources: ${r}.`),log(5,`[pool] The number of all created (used and free) resources: ${n}.`),log(5,`[pool] The number of resources waiting to be acquired: ${i}.`),log(5,`[pool] The number of resources waiting to be created: ${s}.`),log(5,`[pool] The number of resources waiting to be validated: ${a}.`),log(5,`[pool] The number of resources waiting to be destroyed: ${l}.`),log(5,`[pool] The number of all resources: ${c}.`)}function _factory(e){return{create:async()=>{const t={id:uuid.v4(),workCount:Math.round(Math.random()*(e.workLimit/2))};try{const e=getNewDateTime();return await newPage(t),log(3,`[pool] Pool resource [${t.id}] - Successfully created a worker, took ${getNewDateTime()-e}ms.`),t}catch(e){throw log(3,`[pool] Pool resource [${t.id}] - Error encountered when creating a new page.`),e}},validate:async t=>t.page?t.page.isClosed()?(log(3,`[pool] Pool resource [${t.id}] - Validation failed (page is closed or invalid).`),!1):t.page.mainFrame().detached?(log(3,`[pool] Pool resource [${t.id}] - Validation failed (page's frame is detached).`),!1):!(e.workLimit&&++t.workCount>e.workLimit)||(log(3,`[pool] Pool resource [${t.id}] - Validation failed (exceeded the ${e.workLimit} works per resource limit).`),!1):(log(3,`[pool] Pool resource [${t.id}] - Validation failed (no valid page is found).`),!1),destroy:async e=>{if(log(3,`[pool] Pool resource [${e.id}] - Destroying a worker.`),e.page&&!e.page.isClosed())try{e.page.removeAllListeners("pageerror"),e.page.removeAllListeners("console"),e.page.removeAllListeners("framedetached"),await e.page.close()}catch(t){throw log(3,`[pool] Pool resource [${e.id}] - Page could not be closed upon destroying.`),t}}}}function sanitize(e){const t=new jsdom.JSDOM("").window;return DOMPurify(t).sanitize(e,{ADD_TAGS:["foreignObject"]})}let allowCodeExecution=!1;async function singleExport(e){if(!e||!e.export)throw new ExportError("[chart] No expected `export` options were found. Please provide one of the following options: `infile`, `instr`, `options`, or `svg` to generate a valid image.",400);await startExport(e,(async(e,t)=>{if(e)throw e;const{b64:o,outfile:r,type:n}=t.options.export;try{o?fs.writeFileSync(`${r.split(".").shift()||"chart"}.txt`,getBase64(t.result,n)):fs.writeFileSync(r||`chart.${n}`,"svg"!==n?Buffer.from(t.result,"base64"):t.result)}catch(e){throw new ExportError("[chart] Error while saving a chart.",500).setError(e)}await killPool()}))}async function batchExport(e){if(!(e&&e.export&&e.export.batch))throw new ExportError("[chart] No expected `export` options were found. Please provide the `batch` option to generate valid images.",400);{const t=[];for(let o of e.export.batch.split(";")||[])o=o.split("="),2===o.length?t.push(startExport({...e,export:{...e.export,infile:o[0],outfile:o[1]}},((e,t)=>{if(e)throw e;const{b64:o,outfile:r,type:n}=t.options.export;try{o?fs.writeFileSync(`${r.split(".").shift()||"chart"}.txt`,getBase64(t.result,n)):fs.writeFileSync(r,"svg"!==n?Buffer.from(t.result,"base64"):t.result)}catch(e){throw new ExportError("[chart] Error while saving a chart.",500).setError(e)}}))):log(2,"[chart] No correct pair found for the batch export.");const o=await Promise.allSettled(t);await killPool(),o.forEach(((e,t)=>{e.reason&&logWithStack(1,e.reason,`[chart] Batch export number ${t+1} could not be correctly completed.`)}))}}async function startExport(e,t){try{log(4,"[chart] Starting the exporting process.");const o=mergeOptions(getOptions(!1),e),r=o.export;if(null!==r.infile){let e;log(4,"[chart] Attempting to export from a file input.");try{e=fs.readFileSync(getAbsolutePath(r.infile),"utf8")}catch(e){throw new ExportError("[chart] Error loading content from a file input.",400).setError(e)}if(r.infile.endsWith(".svg"))try{r.svg=validateOption("svg",e,!1)}catch(e){throw logZodIssues(1,e.issues,"[config] The `svg` option validation error"),e}else{if(!r.infile.endsWith(".json"))throw new ExportError("[chart] Incorrect value of the `infile` option.",400);try{r.instr=validateOption("instr",e,!1)}catch(e){throw logZodIssues(1,e.issues,"[config] The `instr` option validation error"),e}}}if(null!==r.svg){log(4,"[chart] Attempting to export from an SVG input."),++getPoolStats().exportsFromSvgAttempts;const e=await _exportFromSvg(sanitize(r.svg),o);return++getPoolStats().exportsFromSvg,t(null,e)}if(null!==r.instr||null!==r.options){log(4,"[chart] Attempting to export from options input."),++getPoolStats().exportsFromOptionsAttempts;const e=await _exportFromOptions(r.instr||r.options,o);return++getPoolStats().exportsFromOptions,t(null,e)}return t(new ExportError("[chart] No valid input specified. Check if at least one of the following parameters is correctly set: 'infile', 'instr', 'options', or 'svg'.",400))}catch(e){return t(e)}}function getAllowCodeExecution(){return allowCodeExecution}function setAllowCodeExecution(e){allowCodeExecution=e}async function _exportFromSvg(e,t){if("string"==typeof e&&(e.indexOf("=0||e.indexOf("=0))return log(4,"[chart] Parsing input as SVG."),t.export.svg=e,t.export.instr=null,t.export.options=null,_prepareExport(t);throw new ExportError("[chart] Not a correct SVG input.",400)}async function _exportFromOptions(e,t){log(4,"[chart] Parsing input from options.");const o=isAllowedConfig(e,!0,t.customLogic.allowCodeExecution);if(null===o||"string"!=typeof o||!o.startsWith("{")||!o.endsWith("}"))throw new ExportError("[chart] Invalid configuration provided - Only options configurations and SVG are allowed for this server. If this is your server, JavaScript custom code can be enabled by starting the server with the `allowCodeExecution` options set to true.",403);return t.export.instr=o,t.export.svg=null,_prepareExport(t)}async function _prepareExport(e){const{export:t,customLogic:o}=e;t.type=fixType(t.type,t.outfile),t.outfile=fixOutfile(t.type,t.outfile),log(3,`[chart] The custom logic is ${o.allowCodeExecution?"allowed":"disallowed"}.`),_handleCustomLogic(o,o.allowCodeExecution),_handleGlobalAndTheme(t,o.allowFileResources,o.allowCodeExecution),e.export={...t,..._findChartSize(t)};try{e=strictValidate(e)}catch(e){logZodIssues(1,e.issues,"[config] Final options validation error")}return postWork(e)}function _findChartSize(e){const{chart:t,exporting:o}=e.options||isAllowedConfig(e.instr)||!1,{chart:r,exporting:n}=isAllowedConfig(e.globalOptions)||!1,{chart:i,exporting:s}=isAllowedConfig(e.themeOptions)||!1,a=roundNumber(Math.max(.1,Math.min(e.scale||o?.scale||n?.scale||s?.scale||e.defaultScale||1,5)),2),l={height:e.height||o?.sourceHeight||t?.height||n?.sourceHeight||r?.height||s?.sourceHeight||i?.height||e.defaultHeight||400,width:e.width||o?.sourceWidth||t?.width||n?.sourceWidth||r?.width||s?.sourceWidth||i?.width||e.defaultWidth||600,scale:a};for(let[e,t]of Object.entries(l))l[e]="string"==typeof t?+t.replace(/px|%/gi,""):t;return l}function _handleCustomLogic(e,t){if(t){if("string"==typeof e.resources)e.resources=_handleResources(e.resources,e.allowFileResources,!0);else if(!e.resources)try{e.resources=_handleResources(fs.readFileSync(getAbsolutePath("resources.json"),"utf8"),e.allowFileResources,!0)}catch(e){log(2,"[chart] Unable to load the default `resources.json` file.")}try{e.customCode=wrapAround(e.customCode,e.allowFileResources)}catch(t){logWithStack(2,t,"[chart] The `customCode` cannot be loaded."),e.customCode=null}try{e.callback=wrapAround(e.callback,e.allowFileResources,!0)}catch(t){logWithStack(2,t,"[chart] The `callback` cannot be loaded."),e.callback=null}[null,void 0].includes(e.customCode)&&log(3,"[chart] No value for the `customCode` option found."),[null,void 0].includes(e.callback)&&log(3,"[chart] No value for the `callback` option found."),[null,void 0].includes(e.resources)&&log(3,"[chart] No value for the `resources` option found.")}else if(e.callback||e.resources||e.customCode)throw e.callback=null,e.resources=null,e.customCode=null,new ExportError("[chart] The 'callback', 'resources', and 'customCode' options have been disabled for this server.",403)}function _handleResources(e=null,t,o){const r=["js","css","files"];let n=e,i=!1;if(t&&e.endsWith(".json"))try{n=isAllowedConfig(fs.readFileSync(getAbsolutePath(e),"utf8"),!1,o)}catch{return null}else n=isAllowedConfig(e,!1,o),n&&!t&&delete n.files;for(const e in n)r.includes(e)?i||(i=!0):delete n[e];return i?(n.files&&(n.files=n.files.map((e=>e.trim())),(!n.files||n.files.length<=0)&&delete n.files),n):null}function _handleGlobalAndTheme(e,t,o){["globalOptions","themeOptions"].forEach((r=>{try{e[r]&&(t&&"string"==typeof e[r]&&e[r].endsWith(".json")?e[r]=isAllowedConfig(fs.readFileSync(getAbsolutePath(e[r]),"utf8"),!0,o):e[r]=isAllowedConfig(e[r],!0,o))}catch(t){logWithStack(2,t,`[chart] The \`${r}\` cannot be loaded.`),e[r]=null}})),[null,void 0].includes(e.globalOptions)&&log(3,"[chart] No value for the `globalOptions` option found."),[null,void 0].includes(e.themeOptions)&&log(3,"[chart] No value for the `themeOptions` option found.")}const timerIds=[];function addTimer(e){timerIds.push(e)}function clearAllTimers(){log(4,"[timer] Clearing all registered intervals and timeouts.");for(const e of timerIds)clearInterval(e),clearTimeout(e)}function logErrorMiddleware(e,t,o,r){return logWithStack(1,e),"development"!==getOptions().other.nodeEnv&&delete e.stack,r(e)}function returnErrorMiddleware(e,t,o,r){const{message:n,stack:i}=e,s=e.statusCode||400;o.status(s).json({statusCode:s,message:n,stack:i})}function errorMiddleware(e){e.use(logErrorMiddleware),e.use(returnErrorMiddleware)}function rateLimitingMiddleware(e,t=getOptions().server.rateLimiting){try{if(t.enable){const o="Too many requests, you have been rate limited. Please try again later.",r={max:t.maxRequests||30,window:t.window||1,delay:t.delay||0,trustProxy:t.trustProxy||!1,skipKey:t.skipKey||!1,skipToken:t.skipToken||!1};r.trustProxy&&e.enable("trust proxy");const n=rateLimit({windowMs:60*r.window*1e3,max:r.max,delayMs:r.delay,handler:(e,t)=>{t.format({json:()=>{t.status(429).send({message:o})},default:()=>{t.status(429).send(o)}})},skip:e=>!1!==r.skipKey&&!1!==r.skipToken&&e.query.key===r.skipKey&&e.query.access_token===r.skipToken&&(log(4,"[rate limiting] Skipping rate limiter."),!0)});e.use(n),log(3,`[rate limiting] Enabled rate limiting with ${r.max} requests per ${r.window} minute for each IP, trusting proxy: ${r.trustProxy}.`)}}catch(e){throw new ExportError("[rate limiting] Could not configure and set the rate limiting options.",500).setError(e)}}class HttpError extends ExportError{constructor(e,t){super(e,t)}setStatus(e){return this.statusCode=e,this}}function contentTypeMiddleware(e,t,o){try{const t=e.headers["content-type"]||"";if(!t.includes("application/json")&&!t.includes("application/x-www-form-urlencoded")&&!t.includes("multipart/form-data"))throw new HttpError("[validation] Content-Type must be application/json, application/x-www-form-urlencoded, or multipart/form-data.",415);return o()}catch(e){return o(e)}}function requestBodyMiddleware(e,t,o){try{const t=e.body,r=uuid.v4().replace(/-/g,"");if(!t||isObjectEmpty(t))throw log(2,`[validation] Request [${r}] - The request from ${e.headers["x-forwarded-for"]||e.connection.remoteAddress} was incorrect. Received payload is empty.`),new HttpError("[validation] The request body is required. Please ensure that your Content-Type header is correct. Accepted types are 'application/json' and 'multipart/form-data'.",400);const n=getAllowCodeExecution(),i=isAllowedConfig(t.instr||t.options||t.infile||t.data,!0,n);if(null===i&&!t.svg)throw log(2,`[validation] Request [${r}] - The request from ${e.headers["x-forwarded-for"]||e.connection.remoteAddress} was incorrect. Received payload is missing correct chart data for export: ${JSON.stringify(t)}.`),new HttpError("[validation] No correct chart data found. Ensure that you are using either application/json or multipart/form-data headers. If sending JSON, make sure the chart data is in the 'infile', 'options', or 'data' attribute. If sending SVG, ensure it is in the 'svg' attribute.",400);if(t.svg&&isPrivateRangeUrlFound(t.svg))throw new HttpError("[validation] SVG potentially contain at least one forbidden URL in 'xlink:href' element. Please review the SVG content and ensure that all referenced URLs comply with security policies.",400);try{e.validatedOptions=looseValidate({_requestId:r,export:{instr:i,svg:t.svg,outfile:t.outfile||`${e.params.filename||"chart"}.${fixType(t.type)}`,type:fixType(t.type,t.outfile),constr:fixConstr(t.constr),b64:t.b64,noDownload:t.noDownload,height:t.height,width:t.width,scale:t.scale,globalOptions:isAllowedConfig(t.globalOptions,!0,n),themeOptions:isAllowedConfig(t.themeOptions,!0,n)},customLogic:{allowCodeExecution:n,allowFileResources:!1,customCode:t.customCode,callback:t.callback,resources:isAllowedConfig(t.resources,!0,n)}})}catch(e){throw logZodIssues(1,e.issues,"[config] Request options validation error"),new HttpError("The provided options are not correct. Please check if your data is of the correct types.",400)}return o()}catch(e){return o(e)}}function validationMiddleware(e){e.post(["/","/:filename"],contentTypeMiddleware),e.post(["/","/:filename"],requestBodyMiddleware)}const reversedMime={png:"image/png",jpeg:"image/jpeg",gif:"image/gif",pdf:"application/pdf",svg:"image/svg+xml"};async function requestExport(e,t,o){try{const o=measureTime();let r=!1;e.socket.on("close",(e=>{e&&(r=!0)}));const n=e.validatedOptions,i=n._requestId;log(4,`[export] Got an incoming HTTP request with ID ${i}.`),await startExport(n,((n,s)=>{if(e.socket.removeAllListeners("close"),r)log(3,`[export] Request [${i}] - The client closed the connection before the chart finished processing.`);else{if(n)throw n;if(!s||!s.result)throw log(2,`[export] Request [${i}] - Request from ${e.headers["x-forwarded-for"]||e.connection.remoteAddress} was incorrect. Received result is ${s.result}.`),new HttpError("[export] Unexpected return of the export result from the chart generation. Please check your request data.",400);if(s.result){log(3,`[export] Request [${i}] - The whole exporting process took ${o()}ms.`);const{type:e,b64:r,noDownload:n,outfile:a}=s.options.export;return r?t.send(getBase64(s.result,e)):(t.header("Content-Type",reversedMime[e]||"image/png"),n||t.attachment(a),"svg"===e?t.send(s.result):t.send(Buffer.from(s.result,"base64")))}}}))}catch(e){return o(e)}}function exportRoutes(e){e.post("/",requestExport),e.post("/:filename",requestExport)}const serverStartTime=new Date,packageFile=JSON.parse(fs.readFileSync(path.join(__dirname$1,"package.json"))),successRates=[],recordInterval=6e4,windowSize=30;function _calculateMovingAverage(){return successRates.reduce(((e,t)=>e+t),0)/successRates.length}function _startSuccessRate(){return setInterval((()=>{const e=getPoolStats(),t=0===e.exportsAttempted?1:e.exportsPerformed/e.exportsAttempted*100;successRates.push(t),successRates.length>windowSize&&successRates.shift()}),recordInterval)}function healthRoutes(e){addTimer(_startSuccessRate()),e.get("/health",((e,t,o)=>{try{log(4,"[health] Returning server health.");const e=getPoolStats(),o=successRates.length,r=_calculateMovingAverage();t.send({status:"OK",bootTime:serverStartTime,uptime:`${Math.floor((getNewDateTime()-serverStartTime.getTime())/1e3/60)} minutes`,serverVersion:packageFile.version,highchartsVersion:getHighchartsVersion(),averageExportTime:e.timeSpentAverage,attemptedExports:e.exportsAttempted,performedExports:e.exportsPerformed,failedExports:e.exportsDropped,sucessRatio:e.exportsPerformed/e.exportsAttempted*100,pool:getPoolInfoJSON(),period:o,movingAverage:r,message:isNaN(r)||!successRates.length?"Too early to report. No exports made yet. Please check back soon.":`Last ${o} minutes had a success rate of ${r.toFixed(2)}%.`,svgExports:e.exportsFromSvg,jsonExports:e.exportsFromOptions,svgExportsAttempts:e.exportsFromSvgAttempts,jsonExportsAttempts:e.exportsFromOptionsAttempts})}catch(e){return o(e)}}))}function uiRoutes(e){e.get(getOptions().ui.route||"/",((e,t,o)=>{try{t.sendFile(path.join(__dirname$1,"public","index.html"),{acceptRanges:!1})}catch(e){return o(e)}}))}function versionChangeRoutes(e){e.post("/version_change/:newVersion",(async(e,t,o)=>{try{const o=envs.HIGHCHARTS_ADMIN_TOKEN;if(!o||!o.length)throw new HttpError("[version] The server is not configured to perform run-time version changes: HIGHCHARTS_ADMIN_TOKEN is not set.",401);const r=e.get("hc-auth");if(!r||r!==o)throw new HttpError("[version] Invalid or missing token: Set the token in the hc-auth header.",401);const n=e.params.newVersion;if(!n)throw new HttpError("[version] No new version supplied.",400);try{await updateHighchartsVersion(n)}catch(e){throw new HttpError(`[version] Version change: ${e.message}`,400).setError(e)}t.status(200).send({statusCode:200,highchartsVersion:getHighchartsVersion(),message:`Successfully updated Highcharts to version: ${n}.`})}catch(e){return o(e)}}))}const activeServers=new Map,app=express();async function startServer(e=getOptions().server){try{if(!e.enable||!app)throw new ExportError("[server] Server cannot be started (not enabled or no correct Express app found).",500);const t=1024*e.uploadLimit*1024,o=multer.memoryStorage(),r=multer({storage:o,limits:{fieldSize:t}});if(app.disable("x-powered-by"),app.use(cors({methods:["POST","GET","OPTIONS"]})),app.use(((e,t,o)=>{t.set("Accept-Ranges","none"),o()})),app.use(express.json({limit:t})),app.use(express.urlencoded({extended:!0,limit:t})),app.use(r.none()),app.use(express.static(path.join(__dirname$1,"public"))),!e.ssl.force){const t=http.createServer(app);_attachServerErrorHandlers(t),t.listen(e.port,e.host,(()=>{activeServers.set(e.port,t),log(3,`[server] Started HTTP server on ${e.host}:${e.port}.`)}))}if(e.ssl.enable){let t,o;try{t=await promises.readFile(path.join(getAbsolutePath(e.ssl.certPath),"server.key"),"utf8"),o=await promises.readFile(path.join(getAbsolutePath(e.ssl.certPath),"server.crt"),"utf8")}catch(t){log(2,`[server] Unable to load key/certificate from the '${e.ssl.certPath}' path. Could not run secured layer server.`)}if(t&&o){const r=https.createServer({key:t,cert:o},app);_attachServerErrorHandlers(r),r.listen(e.ssl.port,e.host,(()=>{activeServers.set(e.ssl.port,r),log(3,`[server] Started HTTPS server on ${e.host}:${e.ssl.port}.`)}))}}rateLimitingMiddleware(app,e.rateLimiting),validationMiddleware(app),healthRoutes(app),exportRoutes(app),uiRoutes(app),versionChangeRoutes(app),errorMiddleware(app)}catch(e){throw new ExportError("[server] Could not configure and start the server.",500).setError(e)}}function closeServers(){if(activeServers.size>0){log(4,"[server] Closing all servers.");for(const[e,t]of activeServers)t.close((()=>{activeServers.delete(e),log(4,`[server] Closed server on port: ${e}.`)}))}}function getServers(){return activeServers}function getExpress(){return express}function getApp(){return app}function enableRateLimiting(e){rateLimitingMiddleware(app,e)}function use(e,...t){app.use(e,...t)}function get(e,...t){app.get(e,...t)}function post(e,...t){app.post(e,...t)}function _attachServerErrorHandlers(e){e.on("clientError",((e,t)=>{logWithStack(1,e,`[server] Client error: ${e.message}, destroying socket.`),t.destroy()})),e.on("error",(e=>{logWithStack(1,e,`[server] Server error: ${e.message}`)})),e.on("connection",(e=>{e.on("error",(e=>{logWithStack(1,e,`[server] Socket error: ${e.message}`)}))}))}var server={startServer:startServer,closeServers:closeServers,getServers:getServers,getExpress:getExpress,getApp:getApp,enableRateLimiting:enableRateLimiting,use:use,get:get,post:post};async function shutdownCleanUp(e){await Promise.allSettled([clearAllTimers(),closeServers(),killPool()]),process.exit(e)}async function initExport(e){const t=mergeOptions(getOptions(!1),e);setAllowCodeExecution(t.customLogic.allowCodeExecution),initLogging(t.logging),t.other.listenToProcessExits&&_attachProcessExitListeners(),await checkAndUpdateCache(t.highcharts,t.server.proxy),await initPool(t.pool,t.puppeteer.args)}function _attachProcessExitListeners(){log(3,"[process] Attaching exit listeners to the process."),process.on("exit",(e=>{log(4,`[process] Process exited with code ${e}.`)})),process.on("SIGINT",(async(e,t)=>{log(4,`[process] The ${e} event with code: ${t}.`),await shutdownCleanUp(0)})),process.on("SIGTERM",(async(e,t)=>{log(4,`[process] The ${e} event with code: ${t}.`),await shutdownCleanUp(0)})),process.on("SIGHUP",(async(e,t)=>{log(4,`[process] The ${e} event with code: ${t}.`),await shutdownCleanUp(0)})),process.on("uncaughtException",(async(e,t)=>{logWithStack(1,e,`[process] The ${t} error.`),await shutdownCleanUp(1)}))}var index={server:server,startServer:startServer,getOptions:getOptions,setOptions:setOptions,mergeOptions:mergeOptions,mapToNewOptions:mapToNewOptions,initExport:initExport,singleExport:singleExport,batchExport:batchExport,startExport:startExport,checkAndUpdateCache:checkAndUpdateCache,initPool:initPool,killPool:killPool,log:log,logWithStack:logWithStack,logZodIssues:logZodIssues,setLogLevel:setLogLevel,enableConsoleLogging:enableConsoleLogging,enableFileLogging:enableFileLogging,shutdownCleanUp:shutdownCleanUp};exports.default=index,exports.initExport=initExport; +//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguY2pzIiwic291cmNlcyI6WyIuLi9saWIvdXRpbHMuanMiLCIuLi9saWIvbG9nZ2VyLmpzIiwiLi4vbGliL3NjaGVtYXMvY29uZmlnLmpzIiwiLi4vbGliL3ZhbGlkYXRpb24uanMiLCIuLi9saWIvY29uZmlnLmpzIiwiLi4vbGliL2ZldGNoLmpzIiwiLi4vbGliL2Vycm9ycy9FeHBvcnRFcnJvci5qcyIsIi4uL2xpYi9jYWNoZS5qcyIsIi4uL2xpYi9oaWdoY2hhcnRzLmpzIiwiLi4vbGliL2Jyb3dzZXIuanMiLCIuLi90ZW1wbGF0ZXMvc3ZnRXhwb3J0L2Nzcy5qcyIsIi4uL3RlbXBsYXRlcy9zdmdFeHBvcnQvc3ZnRXhwb3J0LmpzIiwiLi4vbGliL2V4cG9ydC5qcyIsIi4uL2xpYi9wb29sLmpzIiwiLi4vbGliL3Nhbml0aXplLmpzIiwiLi4vbGliL2NoYXJ0LmpzIiwiLi4vbGliL3RpbWVyLmpzIiwiLi4vbGliL3NlcnZlci9taWRkbGV3YXJlcy9lcnJvci5qcyIsIi4uL2xpYi9zZXJ2ZXIvbWlkZGxld2FyZXMvcmF0ZUxpbWl0aW5nLmpzIiwiLi4vbGliL2Vycm9ycy9IdHRwRXJyb3IuanMiLCIuLi9saWIvc2VydmVyL21pZGRsZXdhcmVzL3ZhbGlkYXRpb24uanMiLCIuLi9saWIvc2VydmVyL3JvdXRlcy9leHBvcnQuanMiLCIuLi9saWIvc2VydmVyL3JvdXRlcy9oZWFsdGguanMiLCIuLi9saWIvc2VydmVyL3JvdXRlcy91aS5qcyIsIi4uL2xpYi9zZXJ2ZXIvcm91dGVzL3ZlcnNpb25DaGFuZ2UuanMiLCIuLi9saWIvc2VydmVyL3NlcnZlci5qcyIsIi4uL2xpYi9yZXNvdXJjZVJlbGVhc2UuanMiLCIuLi9saWIvaW5kZXguanMiXSwic291cmNlc0NvbnRlbnQiOlsiLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcclxuXHJcbkhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlclxyXG5cclxuQ29weXJpZ2h0IChjKSAyMDE2LTIwMjUsIEhpZ2hzb2Z0XHJcblxyXG5MaWNlbmNlZCB1bmRlciB0aGUgTUlUIGxpY2VuY2UuXHJcblxyXG5BZGRpdGlvbmFsbHkgYSB2YWxpZCBIaWdoY2hhcnRzIGxpY2Vuc2UgaXMgcmVxdWlyZWQgZm9yIHVzZS5cclxuXHJcblNlZSBMSUNFTlNFIGZpbGUgaW4gcm9vdCBmb3IgZGV0YWlscy5cclxuXHJcbioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXHJcblxyXG4vKipcclxuICogQG92ZXJ2aWV3IFRoZSBIaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXIgdXRpbGl0eSBtb2R1bGUgcHJvdmlkZXNcclxuICogYSBjb21wcmVoZW5zaXZlIHNldCBvZiBoZWxwZXIgZnVuY3Rpb25zIGFuZCBjb25zdGFudHMgZGVzaWduZWQgdG8gc3RyZWFtbGluZVxyXG4gKiBhbmQgZW5oYW5jZSB2YXJpb3VzIG9wZXJhdGlvbnMgcmVxdWlyZWQgZm9yIEhpZ2hjaGFydHMgZXhwb3J0IHRhc2tzLlxyXG4gKi9cclxuXHJcbmltcG9ydCB7IHJlYWRGaWxlU3luYyB9IGZyb20gJ2ZzJztcclxuaW1wb3J0IHsgaXNBYnNvbHV0ZSwgam9pbiB9IGZyb20gJ3BhdGgnO1xyXG5pbXBvcnQgeyBmaWxlVVJMVG9QYXRoIH0gZnJvbSAndXJsJztcclxuXHJcbmNvbnN0IE1BWF9CQUNLT0ZGX0FUVEVNUFRTID0gNjtcclxuXHJcbi8vIFRoZSBkaXJlY3RvcnkgcGF0aFxyXG5leHBvcnQgY29uc3QgX19kaXJuYW1lID0gZmlsZVVSTFRvUGF0aChuZXcgVVJMKCcuLi8uJywgaW1wb3J0Lm1ldGEudXJsKSk7XHJcblxyXG4vKipcclxuICogQ2xlYXJzIGFuZCBzdGFuZGFyZGl6ZXMgdGV4dCBieSByZXBsYWNpbmcgbXVsdGlwbGUgY29uc2VjdXRpdmUgd2hpdGVzcGFjZVxyXG4gKiBjaGFyYWN0ZXJzIHdpdGggYSBzaW5nbGUgc3BhY2UgYW5kIHRyaW1taW5nIGFueSBsZWFkaW5nIG9yIHRyYWlsaW5nXHJcbiAqIHdoaXRlc3BhY2UuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBjbGVhclRleHRcclxuICpcclxuICogQHBhcmFtIHtzdHJpbmd9IHRleHQgLSBUaGUgaW5wdXQgdGV4dCB0byBiZSBjbGVhcmVkLlxyXG4gKiBAcGFyYW0ge1JlZ0V4cH0gW3J1bGU9L1xcc1xccysvZ10gLSBUaGUgcmVndWxhciBleHByZXNzaW9uIHJ1bGUgdG8gbWF0Y2hcclxuICogbXVsdGlwbGUgY29uc2VjdXRpdmUgd2hpdGVzcGFjZSBjaGFyYWN0ZXJzLiBUaGUgZGVmYXVsdCB2YWx1ZVxyXG4gKiBpcyB0aGUgJy9cXHNcXHMrL2cnIFJlZ0V4cC5cclxuICogQHBhcmFtIHtzdHJpbmd9IFtyZXBsYWNlcj0nICddIC0gVGhlIHN0cmluZyB1c2VkIHRvIHJlcGxhY2UgbXVsdGlwbGVcclxuICogY29uc2VjdXRpdmUgd2hpdGVzcGFjZSBjaGFyYWN0ZXJzLiBUaGUgZGVmYXVsdCB2YWx1ZSBpcyB0aGUgJyAnIHN0cmluZy5cclxuICpcclxuICogQHJldHVybnMge3N0cmluZ30gVGhlIGNsZWFyZWQgYW5kIHN0YW5kYXJkaXplZCB0ZXh0LlxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIGNsZWFyVGV4dCh0ZXh0LCBydWxlID0gL1xcc1xccysvZywgcmVwbGFjZXIgPSAnICcpIHtcclxuICByZXR1cm4gdGV4dC5yZXBsYWNlQWxsKHJ1bGUsIHJlcGxhY2VyKS50cmltKCk7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBDcmVhdGVzIGEgZGVlcCBjb3B5IG9mIHRoZSBnaXZlbiBvYmplY3Qgb3IgYXJyYXkuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBkZWVwQ29weVxyXG4gKlxyXG4gKiBAcGFyYW0geyhPYmplY3R8QXJyYXkpfSBvYmpBcnIgLSBUaGUgb2JqZWN0IG9yIGFycmF5IHRvIGJlIGRlZXBseSBjb3BpZWQuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHsoT2JqZWN0fEFycmF5KX0gVGhlIGRlZXAgY29weSBvZiB0aGUgcHJvdmlkZWQgb2JqZWN0IG9yIGFycmF5LlxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIGRlZXBDb3B5KG9iakFycikge1xyXG4gIC8vIElmIHRoZSBgb2JqQXJyYCBpcyBudWxsIG9yIG5vdCBvZiB0aGUgYG9iamVjdGAgdHlwZSwgcmV0dXJuIGl0XHJcbiAgaWYgKG9iakFyciA9PT0gbnVsbCB8fCB0eXBlb2Ygb2JqQXJyICE9PSAnb2JqZWN0Jykge1xyXG4gICAgcmV0dXJuIG9iakFycjtcclxuICB9XHJcblxyXG4gIC8vIFByZXBhcmUgZWl0aGVyIGEgbmV3IGFycmF5IG9yIGEgbmV3IG9iamVjdFxyXG4gIGNvbnN0IG9iakFyckNvcHkgPSBBcnJheS5pc0FycmF5KG9iakFycikgPyBbXSA6IHt9O1xyXG5cclxuICAvLyBSZWN1cnNpdmVseSBjb3B5IGVhY2ggcHJvcGVydHlcclxuICBmb3IgKGNvbnN0IGtleSBpbiBvYmpBcnIpIHtcclxuICAgIGlmIChPYmplY3QucHJvdG90eXBlLmhhc093blByb3BlcnR5LmNhbGwob2JqQXJyLCBrZXkpKSB7XHJcbiAgICAgIG9iakFyckNvcHlba2V5XSA9IGRlZXBDb3B5KG9iakFycltrZXldKTtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIC8vIFJldHVybiB0aGUgY29waWVkIG9iamVjdFxyXG4gIHJldHVybiBvYmpBcnJDb3B5O1xyXG59XHJcblxyXG4vKipcclxuICogSW1wbGVtZW50cyBhbiBleHBvbmVudGlhbCBiYWNrb2ZmIHN0cmF0ZWd5IGZvciByZXRyeWluZyBhIGZ1bmN0aW9uIHVudGlsXHJcbiAqIGEgY2VydGFpbiBudW1iZXIgb2YgYXR0ZW1wdHMgYXJlIHJlYWNoZWQuXHJcbiAqXHJcbiAqIEBhc3luY1xyXG4gKiBAZnVuY3Rpb24gZXhwQmFja29mZlxyXG4gKlxyXG4gKiBAcGFyYW0ge0Z1bmN0aW9ufSBmbiAtIFRoZSBmdW5jdGlvbiB0byBiZSByZXRyaWVkLlxyXG4gKiBAcGFyYW0ge251bWJlcn0gW2F0dGVtcHQ9MF0gLSBUaGUgY3VycmVudCBhdHRlbXB0IG51bWJlci4gVGhlIGRlZmF1bHQgdmFsdWVcclxuICogaXMgMC5cclxuICogQHBhcmFtIHsuLi51bmtub3dufSBhcmdzIC0gQXJndW1lbnRzIHRvIGJlIHBhc3NlZCB0byB0aGUgZnVuY3Rpb24uXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtQcm9taXNlPHVua25vd24+fSBBIFByb21pc2UgdGhhdCByZXNvbHZlcyB0byB0aGUgcmVzdWx0XHJcbiAqIG9mIHRoZSBmdW5jdGlvbiBpZiBzdWNjZXNzZnVsLlxyXG4gKlxyXG4gKiBAdGhyb3dzIHtFcnJvcn0gVGhyb3dzIGFuIGBFcnJvcmAgaWYgdGhlIG1heGltdW0gbnVtYmVyIG9mIGF0dGVtcHRzXHJcbiAqIGlzIHJlYWNoZWQuXHJcbiAqL1xyXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gZXhwQmFja29mZihmbiwgYXR0ZW1wdCA9IDAsIC4uLmFyZ3MpIHtcclxuICB0cnkge1xyXG4gICAgLy8gVHJ5IHRvIGNhbGwgdGhlIGZ1bmN0aW9uXHJcbiAgICByZXR1cm4gYXdhaXQgZm4oLi4uYXJncyk7XHJcbiAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgIC8vIENhbGN1bGF0ZSBkZWxheSBpbiBtc1xyXG4gICAgY29uc3QgZGVsYXlJbk1zID0gMiAqKiBhdHRlbXB0ICogMTAwMDtcclxuXHJcbiAgICAvLyBJZiB0aGUgYXR0ZW1wdCBleGNlZWRzIHRoZSBtYXhpbXVtIGF0dGVtcHRzIG9mIHJlcGVhdCwgdGhyb3cgYW4gZXJyb3JcclxuICAgIGlmICgrK2F0dGVtcHQgPj0gTUFYX0JBQ0tPRkZfQVRURU1QVFMpIHtcclxuICAgICAgdGhyb3cgZXJyb3I7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gV2FpdCBnaXZlbiBhbW91bnQgb2YgdGltZVxyXG4gICAgYXdhaXQgbmV3IFByb21pc2UoKHJlc3BvbnNlKSA9PiBzZXRUaW1lb3V0KHJlc3BvbnNlLCBkZWxheUluTXMpKTtcclxuXHJcbiAgICAvLy8gVE8gRE86IENvcnJlY3RcclxuICAgIC8vIC8vIEluZm9ybWF0aW9uIGFib3V0IHRoZSByZXNvdXJjZSB0aW1lb3V0XHJcbiAgICAvLyBsb2coXHJcbiAgICAvLyAgIDMsXHJcbiAgICAvLyAgIGBbdXRpbHNdIFdhaXRlZCAke2RlbGF5SW5Nc31tcyB1bnRpbCBuZXh0IGNhbGwgZm9yIHRoZSByZXNvdXJjZSBvZiBJRDogJHthcmdzWzBdfS5gXHJcbiAgICAvLyApO1xyXG5cclxuICAgIC8vIFRyeSBhZ2FpblxyXG4gICAgcmV0dXJuIGV4cEJhY2tvZmYoZm4sIGF0dGVtcHQsIC4uLmFyZ3MpO1xyXG4gIH1cclxufVxyXG5cclxuLyoqXHJcbiAqIEFkanVzdHMgdGhlIGNvbnN0cnVjdG9yIG5hbWUgYnkgdHJhbnNmb3JtaW5nIGFuZCBub3JtYWxpemluZyBpdCBiYXNlZFxyXG4gKiBvbiBjb21tb24gY2hhcnQgdHlwZXMuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBmaXhDb25zdHJcclxuICpcclxuICogQHBhcmFtIHtzdHJpbmd9IGNvbnN0ciAtIFRoZSBvcmlnaW5hbCBjb25zdHJ1Y3RvciBuYW1lIHRvIGJlIGZpeGVkLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7c3RyaW5nfSBUaGUgY29ycmVjdGVkIGNvbnN0cnVjdG9yIG5hbWUsIG9yICdjaGFydCcgaWYgdGhlIGlucHV0XHJcbiAqIGlzIG5vdCByZWNvZ25pemVkLlxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIGZpeENvbnN0cihjb25zdHIpIHtcclxuICB0cnkge1xyXG4gICAgLy8gRml4IHRoZSBjb25zdHJ1Y3RvciBieSBsb3dlcmluZyBjYXNpbmdcclxuICAgIGNvbnN0IGZpeGVkQ29uc3RyID0gYCR7Y29uc3RyLnRvTG93ZXJDYXNlKCkucmVwbGFjZSgnY2hhcnQnLCAnJyl9Q2hhcnRgO1xyXG5cclxuICAgIC8vIEhhbmRsZSB0aGUgY2FzZSB3aGVyZSB0aGUgcmVzdWx0IGlzIGp1c3QgJ0NoYXJ0J1xyXG4gICAgaWYgKGZpeGVkQ29uc3RyID09PSAnQ2hhcnQnKSB7XHJcbiAgICAgIGZpeGVkQ29uc3RyLnRvTG93ZXJDYXNlKCk7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gUmV0dXJuIHRoZSBjb3JyZWN0ZWQgY29uc3RydWN0b3IsIG90aGVyd2lzZSBkZWZhdWx0IHRvICdjaGFydCdcclxuICAgIHJldHVybiBbJ2NoYXJ0JywgJ3N0b2NrQ2hhcnQnLCAnbWFwQ2hhcnQnLCAnZ2FudHRDaGFydCddLmluY2x1ZGVzKFxyXG4gICAgICBmaXhlZENvbnN0clxyXG4gICAgKVxyXG4gICAgICA/IGZpeGVkQ29uc3RyXHJcbiAgICAgIDogJ2NoYXJ0JztcclxuICB9IGNhdGNoIHtcclxuICAgIC8vIERlZmF1bHQgdG8gJ2NoYXJ0JyBpbiBjYXNlIG9mIGFueSBlcnJvclxyXG4gICAgcmV0dXJuICdjaGFydCc7XHJcbiAgfVxyXG59XHJcblxyXG4vKipcclxuICogRml4ZXMgdGhlIG91dGZpbGUgYmFzZWQgb24gcHJvdmlkZWQgdHlwZS5cclxuICpcclxuICogQGZ1bmN0aW9uIGZpeE91dGZpbGVcclxuICpcclxuICogQHBhcmFtIHtzdHJpbmd9IHR5cGUgLSBUaGUgb3JpZ2luYWwgZXhwb3J0IHR5cGUuXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSBvdXRmaWxlIC0gVGhlIGZpbGUgcGF0aCBvciBuYW1lLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7c3RyaW5nfSBUaGUgY29ycmVjdGVkIG91dGZpbGUuXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gZml4T3V0ZmlsZSh0eXBlLCBvdXRmaWxlKSB7XHJcbiAgLy8gR2V0IHRoZSBmaWxlIG5hbWUgZnJvbSB0aGUgYG91dGZpbGVgIG9wdGlvblxyXG4gIGNvbnN0IGZpbGVOYW1lID0gZ2V0QWJzb2x1dGVQYXRoKG91dGZpbGUgfHwgJ2NoYXJ0JylcclxuICAgIC5zcGxpdCgnLicpXHJcbiAgICAuc2hpZnQoKTtcclxuXHJcbiAgLy8gUmV0dXJuIGEgY29ycmVjdCBvdXRmaWxlXHJcbiAgcmV0dXJuIGAke2ZpbGVOYW1lfS4ke3R5cGV9YDtcclxufVxyXG5cclxuLyoqXHJcbiAqIEZpeGVzIHRoZSBleHBvcnQgdHlwZSBiYXNlZCBvbiBNSU1FIHR5cGVzIGFuZCBmaWxlIGV4dGVuc2lvbnMuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBmaXhUeXBlXHJcbiAqXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSB0eXBlIC0gVGhlIG9yaWdpbmFsIGV4cG9ydCB0eXBlLlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gW291dGZpbGU9bnVsbF0gLSBUaGUgZmlsZSBwYXRoIG9yIG5hbWUuIFRoZSBkZWZhdWx0IHZhbHVlXHJcbiAqIGlzIG51bGwuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtzdHJpbmd9IFRoZSBjb3JyZWN0ZWQgZXhwb3J0IHR5cGUuXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gZml4VHlwZSh0eXBlLCBvdXRmaWxlID0gbnVsbCkge1xyXG4gIC8vIE1JTUUgdHlwZXNcclxuICBjb25zdCBtaW1lVHlwZXMgPSB7XHJcbiAgICAnaW1hZ2UvcG5nJzogJ3BuZycsXHJcbiAgICAnaW1hZ2UvanBlZyc6ICdqcGVnJyxcclxuICAgICdhcHBsaWNhdGlvbi9wZGYnOiAncGRmJyxcclxuICAgICdpbWFnZS9zdmcreG1sJzogJ3N2ZydcclxuICB9O1xyXG5cclxuICAvLyBHZXQgZm9ybWF0c1xyXG4gIGNvbnN0IGZvcm1hdHMgPSBPYmplY3QudmFsdWVzKG1pbWVUeXBlcyk7XHJcblxyXG4gIC8vIENoZWNrIGlmIHR5cGUgYW5kIG91dGZpbGUncyBleHRlbnNpb25zIGFyZSB0aGUgc2FtZVxyXG4gIGlmIChvdXRmaWxlKSB7XHJcbiAgICBjb25zdCBvdXRUeXBlID0gb3V0ZmlsZS5zcGxpdCgnLicpLnBvcCgpO1xyXG5cclxuICAgIC8vIFN1cHBvcnQgdGhlIEpQRyB0eXBlXHJcbiAgICBpZiAob3V0VHlwZSA9PT0gJ2pwZycpIHtcclxuICAgICAgdHlwZSA9ICdqcGVnJztcclxuICAgIH0gZWxzZSBpZiAoZm9ybWF0cy5pbmNsdWRlcyhvdXRUeXBlKSAmJiB0eXBlICE9PSBvdXRUeXBlKSB7XHJcbiAgICAgIHR5cGUgPSBvdXRUeXBlO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgLy8gUmV0dXJuIGEgY29ycmVjdCB0eXBlXHJcbiAgcmV0dXJuIG1pbWVUeXBlc1t0eXBlXSB8fCBmb3JtYXRzLmZpbmQoKHQpID0+IHQgPT09IHR5cGUpIHx8ICdwbmcnO1xyXG59XHJcblxyXG4vKipcclxuICogQ2hlY2tzIGlmIHRoZSBnaXZlbiBwYXRoIGlzIHJlbGF0aXZlIG9yIGFic29sdXRlIGFuZCByZXR1cm5zIHRoZSBjb3JyZWN0ZWQsXHJcbiAqIGFic29sdXRlIHBhdGguXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBpc0Fic29sdXRlUGF0aFxyXG4gKlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gcGF0aCAtIFRoZSBwYXRoIHRvIGJlIGNoZWNrZWQgb24uXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtzdHJpbmd9IFRoZSBhYnNvbHV0ZSBwYXRoLlxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIGdldEFic29sdXRlUGF0aChwYXRoKSB7XHJcbiAgcmV0dXJuIGlzQWJzb2x1dGUocGF0aCkgPyBwYXRoIDogam9pbihfX2Rpcm5hbWUsIHBhdGgpO1xyXG59XHJcblxyXG4vKipcclxuICogQ29udmVydHMgaW5wdXQgZGF0YSB0byBhIEJhc2U2NCBzdHJpbmcgYmFzZWQgb24gdGhlIGV4cG9ydCB0eXBlLlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gZ2V0QmFzZTY0XHJcbiAqXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSBpbnB1dCAtIFRoZSBpbnB1dCB0byBiZSB0cmFuc2Zvcm1lZCB0byBCYXNlNjQgZm9ybWF0LlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gdHlwZSAtIFRoZSBvcmlnaW5hbCBleHBvcnQgdHlwZS5cclxuICpcclxuICogQHJldHVybnMge3N0cmluZ30gVGhlIEJhc2U2NCBzdHJpbmcgcmVwcmVzZW50YXRpb24gb2YgdGhlIGlucHV0LlxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIGdldEJhc2U2NChpbnB1dCwgdHlwZSkge1xyXG4gIC8vIEZvciBwZGYgYW5kIHN2ZyB0eXBlcyB0aGUgaW5wdXQgbXVzdCBiZSB0cmFuc2Zvcm1lZCB0byBCYXNlNjQgZnJvbSBhIGJ1ZmZlclxyXG4gIGlmICh0eXBlID09PSAncGRmJyB8fCB0eXBlID09ICdzdmcnKSB7XHJcbiAgICByZXR1cm4gQnVmZmVyLmZyb20oaW5wdXQsICd1dGY4JykudG9TdHJpbmcoJ2Jhc2U2NCcpO1xyXG4gIH1cclxuXHJcbiAgLy8gRm9yIHBuZyBhbmQganBlZyBpbnB1dCBpcyBhbHJlYWR5IGEgQmFzZTY0IHN0cmluZ1xyXG4gIHJldHVybiBpbnB1dDtcclxufVxyXG5cclxuLyoqXHJcbiAqIFJldHVybnMgc3RyaW5naWZpZWQgZGF0ZSB3aXRob3V0IHRoZSBHTVQgdGV4dCBpbmZvcm1hdGlvbi5cclxuICpcclxuICogQGZ1bmN0aW9uIGdldE5ld0RhdGVcclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiBnZXROZXdEYXRlKCkge1xyXG4gIC8vIEdldCByaWQgb2YgdGhlIEdNVCB0ZXh0IGluZm9ybWF0aW9uXHJcbiAgcmV0dXJuIG5ldyBEYXRlKCkudG9TdHJpbmcoKS5zcGxpdCgnKCcpWzBdLnRyaW0oKTtcclxufVxyXG5cclxuLyoqXHJcbiAqIFJldHVybnMgdGhlIHN0b3JlZCB0aW1lIHZhbHVlIGluIG1pbGxpc2Vjb25kcy5cclxuICpcclxuICogQGZ1bmN0aW9uIGdldE5ld0RhdGVUaW1lXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gZ2V0TmV3RGF0ZVRpbWUoKSB7XHJcbiAgcmV0dXJuIG5ldyBEYXRlKCkuZ2V0VGltZSgpO1xyXG59XHJcblxyXG4vKipcclxuICogQ2hlY2tzIGlmIHRoZSBnaXZlbiBpdGVtIGlzIGFuIG9iamVjdC5cclxuICpcclxuICogQGZ1bmN0aW9uIGlzT2JqZWN0XHJcbiAqXHJcbiAqIEBwYXJhbSB7dW5rbm93bn0gaXRlbSAtIFRoZSBpdGVtIHRvIGJlIGNoZWNrZWQuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtib29sZWFufSBUcnVlIGlmIHRoZSBpdGVtIGlzIGFuIG9iamVjdCwgZmFsc2Ugb3RoZXJ3aXNlLlxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIGlzT2JqZWN0KGl0ZW0pIHtcclxuICByZXR1cm4gT2JqZWN0LnByb3RvdHlwZS50b1N0cmluZy5jYWxsKGl0ZW0pID09PSAnW29iamVjdCBPYmplY3RdJztcclxufVxyXG5cclxuLyoqXHJcbiAqIENoZWNrcyBpZiB0aGUgZ2l2ZW4gb2JqZWN0IGlzIGVtcHR5LlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gaXNPYmplY3RFbXB0eVxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gaXRlbSAtIFRoZSBvYmplY3QgdG8gYmUgY2hlY2tlZC5cclxuICpcclxuICogQHJldHVybnMge2Jvb2xlYW59IFRydWUgaWYgdGhlIG9iamVjdCBpcyBlbXB0eSwgZmFsc2Ugb3RoZXJ3aXNlLlxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIGlzT2JqZWN0RW1wdHkoaXRlbSkge1xyXG4gIHJldHVybiAoXHJcbiAgICB0eXBlb2YgaXRlbSA9PT0gJ29iamVjdCcgJiZcclxuICAgICFBcnJheS5pc0FycmF5KGl0ZW0pICYmXHJcbiAgICBpdGVtICE9PSBudWxsICYmXHJcbiAgICBPYmplY3Qua2V5cyhpdGVtKS5sZW5ndGggPT09IDBcclxuICApO1xyXG59XHJcblxyXG4vKipcclxuICogQ2hlY2tzIGlmIGEgcHJpdmF0ZSBJUCByYW5nZSBVUkwgaXMgZm91bmQgaW4gdGhlIGdpdmVuIHN0cmluZy5cclxuICpcclxuICogQGZ1bmN0aW9uIGlzUHJpdmF0ZVJhbmdlVXJsRm91bmRcclxuICpcclxuICogQHBhcmFtIHtzdHJpbmd9IGl0ZW0gLSBUaGUgc3RyaW5nIHRvIGJlIGNoZWNrZWQgZm9yIGEgcHJpdmF0ZSBJUCByYW5nZSBVUkwuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtib29sZWFufSBUcnVlIGlmIGEgcHJpdmF0ZSBJUCByYW5nZSBVUkwgaXMgZm91bmQsIGZhbHNlIG90aGVyd2lzZS5cclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiBpc1ByaXZhdGVSYW5nZVVybEZvdW5kKGl0ZW0pIHtcclxuICBjb25zdCByZWdleFBhdHRlcm5zID0gW1xyXG4gICAgL3hsaW5rOmhyZWY9XCIoPzpodHRwOlxcL1xcL3xodHRwczpcXC9cXC8pP2xvY2FsaG9zdFxcYi8sXHJcbiAgICAveGxpbms6aHJlZj1cIig/Omh0dHA6XFwvXFwvfGh0dHBzOlxcL1xcLyk/MTBcXC5cXGR7MSwzfVxcLlxcZHsxLDN9XFwuXFxkezEsM31cXGIvLFxyXG4gICAgL3hsaW5rOmhyZWY9XCIoPzpodHRwOlxcL1xcL3xodHRwczpcXC9cXC8pPzEyN1xcLlxcZHsxLDN9XFwuXFxkezEsM31cXC5cXGR7MSwzfVxcYi8sXHJcbiAgICAveGxpbms6aHJlZj1cIig/Omh0dHA6XFwvXFwvfGh0dHBzOlxcL1xcLyk/MTcyXFwuKDFbNi05XXwyWzAtOV18M1swLTFdKVxcLlxcZHsxLDN9XFwuXFxkezEsM31cXGIvLFxyXG4gICAgL3hsaW5rOmhyZWY9XCIoPzpodHRwOlxcL1xcL3xodHRwczpcXC9cXC8pPzE5MlxcLjE2OFxcLlxcZHsxLDN9XFwuXFxkezEsM31cXGIvXHJcbiAgXTtcclxuXHJcbiAgcmV0dXJuIHJlZ2V4UGF0dGVybnMuc29tZSgocGF0dGVybikgPT4gcGF0dGVybi50ZXN0KGl0ZW0pKTtcclxufVxyXG5cclxuLyoqXHJcbiAqIFV0aWxpdHkgdG8gbWVhc3VyZSBlbGFwc2VkIHRpbWUgdXNpbmcgdGhlIE5vZGUuanMgYHByb2Nlc3MuaHJ0aW1lKClgIG1ldGhvZC5cclxuICpcclxuICogQGZ1bmN0aW9uIG1lYXN1cmVUaW1lXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtGdW5jdGlvbn0gQSBmdW5jdGlvbiB0byBjYWxjdWxhdGUgdGhlIGVsYXBzZWQgdGltZSBpbiBtaWxsaXNlY29uZHMuXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gbWVhc3VyZVRpbWUoKSB7XHJcbiAgY29uc3Qgc3RhcnQgPSBwcm9jZXNzLmhydGltZS5iaWdpbnQoKTtcclxuICByZXR1cm4gKCkgPT4gTnVtYmVyKHByb2Nlc3MuaHJ0aW1lLmJpZ2ludCgpIC0gc3RhcnQpIC8gMTAwMDAwMDtcclxufVxyXG5cclxuLyoqXHJcbiAqIFJvdW5kcyBhIG51bWJlciB0byB0aGUgc3BlY2lmaWVkIHByZWNpc2lvbi5cclxuICpcclxuICogQGZ1bmN0aW9uIHJvdW5kTnVtYmVyXHJcbiAqXHJcbiAqIEBwYXJhbSB7bnVtYmVyfSB2YWx1ZSAtIFRoZSBudW1iZXIgdG8gYmUgcm91bmRlZC5cclxuICogQHBhcmFtIHtudW1iZXJ9IHByZWNpc2lvbiAtIFRoZSBudW1iZXIgb2YgZGVjaW1hbCBwbGFjZXMgdG8gcm91bmQgdG8uXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtudW1iZXJ9IFRoZSByb3VuZGVkIG51bWJlci5cclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiByb3VuZE51bWJlcih2YWx1ZSwgcHJlY2lzaW9uID0gMSkge1xyXG4gIGNvbnN0IG11bHRpcGxpZXIgPSBNYXRoLnBvdygxMCwgcHJlY2lzaW9uIHx8IDApO1xyXG4gIHJldHVybiBNYXRoLnJvdW5kKCt2YWx1ZSAqIG11bHRpcGxpZXIpIC8gbXVsdGlwbGllcjtcclxufVxyXG5cclxuLyoqXHJcbiAqIENvbnZlcnRzIGEgdmFsdWUgdG8gYSBib29sZWFuLlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gdG9Cb29sZWFuXHJcbiAqXHJcbiAqIEBwYXJhbSB7dW5rbm93bn0gaXRlbSAtIFRoZSB2YWx1ZSB0byBiZSBjb252ZXJ0ZWQgdG8gYSBib29sZWFuLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7Ym9vbGVhbn0gVGhlIGJvb2xlYW4gcmVwcmVzZW50YXRpb24gb2YgdGhlIGlucHV0IHZhbHVlLlxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIHRvQm9vbGVhbihpdGVtKSB7XHJcbiAgcmV0dXJuIFsnZmFsc2UnLCAndW5kZWZpbmVkJywgJ251bGwnLCAnTmFOJywgJzAnLCAnJ10uaW5jbHVkZXMoaXRlbSlcclxuICAgID8gZmFsc2VcclxuICAgIDogISFpdGVtO1xyXG59XHJcblxyXG4vKipcclxuICogV3JhcHMgY3VzdG9tIGNvZGUgdG8gZXhlY3V0ZSBpdCBzYWZlbHkuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiB3cmFwQXJvdW5kXHJcbiAqXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSBjdXN0b21Db2RlIC0gVGhlIGN1c3RvbSBjb2RlIHRvIGJlIHdyYXBwZWQuXHJcbiAqIEBwYXJhbSB7Ym9vbGVhbn0gYWxsb3dGaWxlUmVzb3VyY2VzIC0gRmxhZyB0byBhbGxvdyBsb2FkaW5nIGNvZGUgZnJvbSBhIGZpbGUuXHJcbiAqIEBwYXJhbSB7Ym9vbGVhbn0gW2lzQ2FsbGJhY2s9ZmFsc2VdIC0gRmxhZyB0aGF0IGluZGljYXRlcyB0aGUgcmV0dXJuZWQgY29kZVxyXG4gKiBtdXN0IGJlIGluIGEgY2FsbGJhY2sgZm9ybWF0LlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7KHN0cmluZ3xudWxsKX0gVGhlIHdyYXBwZWQgY3VzdG9tIGNvZGUgb3IgbnVsbCBpZiB3cmFwcGluZyBmYWlscy5cclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiB3cmFwQXJvdW5kKGN1c3RvbUNvZGUsIGFsbG93RmlsZVJlc291cmNlcywgaXNDYWxsYmFjayA9IGZhbHNlKSB7XHJcbiAgaWYgKGN1c3RvbUNvZGUgJiYgdHlwZW9mIGN1c3RvbUNvZGUgPT09ICdzdHJpbmcnKSB7XHJcbiAgICBjdXN0b21Db2RlID0gY3VzdG9tQ29kZS50cmltKCk7XHJcblxyXG4gICAgaWYgKGN1c3RvbUNvZGUuZW5kc1dpdGgoJy5qcycpKSB7XHJcbiAgICAgIC8vIExvYWQgYSBmaWxlIGlmIHRoZSBmaWxlIHJlc291cmNlcyBhcmUgYWxsb3dlZFxyXG4gICAgICByZXR1cm4gYWxsb3dGaWxlUmVzb3VyY2VzXHJcbiAgICAgICAgPyB3cmFwQXJvdW5kKFxyXG4gICAgICAgICAgICByZWFkRmlsZVN5bmMoZ2V0QWJzb2x1dGVQYXRoKGN1c3RvbUNvZGUpLCAndXRmOCcpLFxyXG4gICAgICAgICAgICBhbGxvd0ZpbGVSZXNvdXJjZXMsXHJcbiAgICAgICAgICAgIGlzQ2FsbGJhY2tcclxuICAgICAgICAgIClcclxuICAgICAgICA6IG51bGw7XHJcbiAgICB9IGVsc2UgaWYgKFxyXG4gICAgICAhaXNDYWxsYmFjayAmJlxyXG4gICAgICAoY3VzdG9tQ29kZS5zdGFydHNXaXRoKCdmdW5jdGlvbigpJykgfHxcclxuICAgICAgICBjdXN0b21Db2RlLnN0YXJ0c1dpdGgoJ2Z1bmN0aW9uICgpJykgfHxcclxuICAgICAgICBjdXN0b21Db2RlLnN0YXJ0c1dpdGgoJygpPT4nKSB8fFxyXG4gICAgICAgIGN1c3RvbUNvZGUuc3RhcnRzV2l0aCgnKCkgPT4nKSlcclxuICAgICkge1xyXG4gICAgICAvLyBUcmVhdCBhIGZ1bmN0aW9uIGFzIGEgc2VsZi1pbnZva2luZyBleHByZXNzaW9uXHJcbiAgICAgIHJldHVybiBgKCR7Y3VzdG9tQ29kZX0pKClgO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIE9yIHJldHVybiBhcyBhIHN0cmluZ2lmaWVkIGNvZGVcclxuICAgIHJldHVybiBjdXN0b21Db2RlLnJlcGxhY2UoLzskLywgJycpO1xyXG4gIH1cclxufVxyXG5cclxuZXhwb3J0IGRlZmF1bHQge1xyXG4gIF9fZGlybmFtZSxcclxuICBjbGVhclRleHQsXHJcbiAgZGVlcENvcHksXHJcbiAgZXhwQmFja29mZixcclxuICBmaXhDb25zdHIsXHJcbiAgZml4T3V0ZmlsZSxcclxuICBmaXhUeXBlLFxyXG4gIGdldEFic29sdXRlUGF0aCxcclxuICBnZXRCYXNlNjQsXHJcbiAgZ2V0TmV3RGF0ZSxcclxuICBnZXROZXdEYXRlVGltZSxcclxuICBpc09iamVjdCxcclxuICBpc09iamVjdEVtcHR5LFxyXG4gIGlzUHJpdmF0ZVJhbmdlVXJsRm91bmQsXHJcbiAgbWVhc3VyZVRpbWUsXHJcbiAgcm91bmROdW1iZXIsXHJcbiAgdG9Cb29sZWFuLFxyXG4gIHdyYXBBcm91bmRcclxufTtcclxuIiwiLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcclxuXHJcbkhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlclxyXG5cclxuQ29weXJpZ2h0IChjKSAyMDE2LTIwMjUsIEhpZ2hzb2Z0XHJcblxyXG5MaWNlbmNlZCB1bmRlciB0aGUgTUlUIGxpY2VuY2UuXHJcblxyXG5BZGRpdGlvbmFsbHkgYSB2YWxpZCBIaWdoY2hhcnRzIGxpY2Vuc2UgaXMgcmVxdWlyZWQgZm9yIHVzZS5cclxuXHJcblNlZSBMSUNFTlNFIGZpbGUgaW4gcm9vdCBmb3IgZGV0YWlscy5cclxuXHJcbioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXHJcblxyXG4vKipcclxuICogQG92ZXJ2aWV3IEEgbW9kdWxlIGZvciBtYW5hZ2luZyBsb2dnaW5nIGZ1bmN0aW9uYWxpdHkgd2l0aCBjdXN0b21pemFibGVcclxuICogbG9nIGxldmVscywgY29uc29sZSBhbmQgZmlsZSBsb2dnaW5nIG9wdGlvbnMsIGFuZCBlcnJvciBoYW5kbGluZyBzdXBwb3J0LlxyXG4gKiBUaGUgbW9kdWxlIGFsc28gZW5zdXJlcyB0aGF0IGZpbGUtYmFzZWQgbG9ncyBhcmUgc3RvcmVkIGluIGEgc3RydWN0dXJlZFxyXG4gKiBkaXJlY3RvcnksIGNyZWF0aW5nIHRoZSBuZWNlc3NhcnkgcGF0aHMgYXV0b21hdGljYWxseSBpZiB0aGV5IGRvIG5vdCBleGlzdC5cclxuICovXHJcblxyXG5pbXBvcnQgeyBhcHBlbmRGaWxlLCBleGlzdHNTeW5jLCBta2RpclN5bmMgfSBmcm9tICdmcyc7XHJcbmltcG9ydCB7IGpvaW4gfSBmcm9tICdwYXRoJztcclxuXHJcbmltcG9ydCB7IGdldEFic29sdXRlUGF0aCwgZ2V0TmV3RGF0ZSB9IGZyb20gJy4vdXRpbHMuanMnO1xyXG5cclxuLy8gVGhlIGF2YWlsYWJsZSBjb2xvcnNcclxuY29uc3QgY29sb3JzID0gWydyZWQnLCAneWVsbG93JywgJ2JsdWUnLCAnZ3JheScsICdncmVlbiddO1xyXG5cclxuLy8gVGhlIGRlZmF1bHQgbG9nZ2luZyBjb25maWdcclxuY29uc3QgbG9nZ2luZyA9IHtcclxuICAvLyBGbGFncyBmb3IgbG9nZ2luZyBzdGF0dXNcclxuICB0b0NvbnNvbGU6IHRydWUsXHJcbiAgdG9GaWxlOiBmYWxzZSxcclxuICBwYXRoQ3JlYXRlZDogZmFsc2UsXHJcbiAgLy8gRnVsbCBwYXRoIHRvIHRoZSBsb2cgZmlsZVxyXG4gIHBhdGhUb0xvZzogJycsXHJcbiAgLy8gTG9nIGxldmVsc1xyXG4gIGxldmVsc0Rlc2M6IFtcclxuICAgIHtcclxuICAgICAgdGl0bGU6ICdlcnJvcicsXHJcbiAgICAgIGNvbG9yOiBjb2xvcnNbMF1cclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHRpdGxlOiAnd2FybmluZycsXHJcbiAgICAgIGNvbG9yOiBjb2xvcnNbMV1cclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHRpdGxlOiAnbm90aWNlJyxcclxuICAgICAgY29sb3I6IGNvbG9yc1syXVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdGl0bGU6ICd2ZXJib3NlJyxcclxuICAgICAgY29sb3I6IGNvbG9yc1szXVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdGl0bGU6ICdiZW5jaG1hcmsnLFxyXG4gICAgICBjb2xvcjogY29sb3JzWzRdXHJcbiAgICB9XHJcbiAgXVxyXG59O1xyXG5cclxuLyoqXHJcbiAqIExvZ3MgYSBtZXNzYWdlLiBBY2NlcHRzIGEgdmFyaWFibGUgYW1vdW50IG9mIGFyZ3VtZW50cy4gQXJndW1lbnRzIGFmdGVyXHJcbiAqIHRoZSBgbGV2ZWxgIHdpbGwgYmUgcGFzc2VkIGRpcmVjdGx5IHRvIGBjb25zb2xlLmxvZ2AsIGFuZC9vciB3aWxsIGJlIGpvaW5lZFxyXG4gKiBhbmQgYXBwZW5kZWQgdG8gdGhlIGxvZyBmaWxlLlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gbG9nXHJcbiAqXHJcbiAqIEBwYXJhbSB7Li4udW5rbm93bn0gYXJncyAtIEFuIGFycmF5IG9mIGFyZ3VtZW50cyB3aGVyZSB0aGUgZmlyc3QgaXMgdGhlIGxvZ1xyXG4gKiBsZXZlbCBhbmQgdGhlIHJlc3QgYXJlIHN0cmluZ3MgdG8gYnVpbGQgYSBtZXNzYWdlIHdpdGguXHJcbiAqXHJcbiAqIEByZXR1cm5zIHt2b2lkfSBFbmRzIHRoZSBmdW5jdGlvbiBleGVjdXRpb24gd2hlbiBhdHRlbXB0aW5nIHRvIGxvZ1xyXG4gKiBpbmZvcm1hdGlvbiBhdCBhIGhpZ2hlciBsZXZlbCB0aGFuIHdoYXQgaXMgYWxsb3dlZC5cclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiBsb2coLi4uYXJncykge1xyXG4gIGNvbnN0IFtuZXdMZXZlbCwgLi4udGV4dHNdID0gYXJncztcclxuXHJcbiAgLy8gQ3VycmVudCBsb2dnaW5nIG9wdGlvbnNcclxuICBjb25zdCB7IGxldmVsc0Rlc2MsIGxldmVsIH0gPSBsb2dnaW5nO1xyXG5cclxuICAvLyBDaGVjayBpZiB0aGUgbG9nIGxldmVsIGlzIHdpdGhpbiBhIGNvcnJlY3QgcmFuZ2Ugb3IgaXMgaXQgYSBiZW5jaG1hcmsgbG9nXHJcbiAgaWYgKFxyXG4gICAgbmV3TGV2ZWwgIT09IDUgJiZcclxuICAgIChuZXdMZXZlbCA9PT0gMCB8fCBuZXdMZXZlbCA+IGxldmVsIHx8IGxldmVsID4gbGV2ZWxzRGVzYy5sZW5ndGgpXHJcbiAgKSB7XHJcbiAgICByZXR1cm47XHJcbiAgfVxyXG5cclxuICAvLyBDcmVhdGUgYSBtZXNzYWdlJ3MgcHJlZml4XHJcbiAgY29uc3QgcHJlZml4ID0gYCR7Z2V0TmV3RGF0ZSgpfSBbJHtsZXZlbHNEZXNjW25ld0xldmVsIC0gMV0udGl0bGV9XSAtYDtcclxuXHJcbiAgLy8gTG9nIHRvIGZpbGVcclxuICBpZiAobG9nZ2luZy50b0ZpbGUpIHtcclxuICAgIF9sb2dUb0ZpbGUodGV4dHMsIHByZWZpeCk7XHJcbiAgfVxyXG5cclxuICAvLyBMb2cgdG8gY29uc29sZVxyXG4gIGlmIChsb2dnaW5nLnRvQ29uc29sZSkge1xyXG4gICAgY29uc29sZS5sb2cuYXBwbHkoXHJcbiAgICAgIHVuZGVmaW5lZCxcclxuICAgICAgW3ByZWZpeC50b1N0cmluZygpW2xvZ2dpbmcubGV2ZWxzRGVzY1tuZXdMZXZlbCAtIDFdLmNvbG9yXV0uY29uY2F0KHRleHRzKVxyXG4gICAgKTtcclxuICB9XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBMb2dzIGFuIGVycm9yIG1lc3NhZ2Ugd2l0aCBpdHMgc3RhY2sgdHJhY2UuIE9wdGlvbmFsbHksIGEgY3VzdG9tIG1lc3NhZ2VcclxuICogY2FuIGJlIHByb3ZpZGVkLlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gbG9nV2l0aFN0YWNrXHJcbiAqXHJcbiAqIEBwYXJhbSB7bnVtYmVyfSBuZXdMZXZlbCAtIFRoZSBsb2cgbGV2ZWwuXHJcbiAqIEBwYXJhbSB7RXJyb3J9IGVycm9yIC0gVGhlIGVycm9yIG9iamVjdC5cclxuICogQHBhcmFtIHtzdHJpbmd9IGN1c3RvbU1lc3NhZ2UgLSBBbiBvcHRpb25hbCBjdXN0b20gbWVzc2FnZSB0byBiZSBsb2dnZWRcclxuICogYWxvbmcgd2l0aCB0aGUgZXJyb3IuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHt2b2lkfSBFbmRzIHRoZSBmdW5jdGlvbiBleGVjdXRpb24gd2hlbiBhdHRlbXB0aW5nIHRvIGxvZ1xyXG4gKiBpbmZvcm1hdGlvbiBhdCBhIGhpZ2hlciBsZXZlbCB0aGFuIHdoYXQgaXMgYWxsb3dlZC5cclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiBsb2dXaXRoU3RhY2sobmV3TGV2ZWwsIGVycm9yLCBjdXN0b21NZXNzYWdlKSB7XHJcbiAgLy8gR2V0IHRoZSBtYWluIG1lc3NhZ2VcclxuICBjb25zdCBtYWluTWVzc2FnZSA9IGN1c3RvbU1lc3NhZ2UgfHwgZXJyb3IubWVzc2FnZTtcclxuXHJcbiAgLy8gQ3VycmVudCBsb2dnaW5nIG9wdGlvbnNcclxuICBjb25zdCB7IGxldmVsLCBsZXZlbHNEZXNjIH0gPSBsb2dnaW5nO1xyXG5cclxuICAvLyBDaGVjayBpZiB0aGUgbG9nIGxldmVsIGlzIHdpdGhpbiBhIGNvcnJlY3QgcmFuZ2VcclxuICBpZiAobmV3TGV2ZWwgPT09IDAgfHwgbmV3TGV2ZWwgPiBsZXZlbCB8fCBsZXZlbCA+IGxldmVsc0Rlc2MubGVuZ3RoKSB7XHJcbiAgICByZXR1cm47XHJcbiAgfVxyXG5cclxuICAvLyBDcmVhdGUgYSBtZXNzYWdlJ3MgcHJlZml4XHJcbiAgY29uc3QgcHJlZml4ID0gYCR7Z2V0TmV3RGF0ZSgpfSBbJHtsZXZlbHNEZXNjW25ld0xldmVsIC0gMV0udGl0bGV9XSAtYDtcclxuXHJcbiAgLy8gQWRkIHRoZSB3aG9sZSBzdGFjayBtZXNzYWdlXHJcbiAgY29uc3Qgc3RhY2tNZXNzYWdlID0gZXJyb3Iuc3RhY2s7XHJcblxyXG4gIC8vIENvbWJpbmUgY3VzdG9tIG1lc3NhZ2Ugb3IgZXJyb3IgbWVzc2FnZSB3aXRoIGVycm9yIHN0YWNrIG1lc3NhZ2UsIGlmIGV4aXN0c1xyXG4gIGNvbnN0IHRleHRzID0gW21haW5NZXNzYWdlXTtcclxuICBpZiAoc3RhY2tNZXNzYWdlKSB7XHJcbiAgICB0ZXh0cy5wdXNoKCdcXG4nLCBzdGFja01lc3NhZ2UpO1xyXG4gIH1cclxuXHJcbiAgLy8gTG9nIHRvIGZpbGVcclxuICBpZiAobG9nZ2luZy50b0ZpbGUpIHtcclxuICAgIF9sb2dUb0ZpbGUodGV4dHMsIHByZWZpeCk7XHJcbiAgfVxyXG5cclxuICAvLyBMb2cgdG8gY29uc29sZVxyXG4gIGlmIChsb2dnaW5nLnRvQ29uc29sZSkge1xyXG4gICAgY29uc29sZS5sb2cuYXBwbHkoXHJcbiAgICAgIHVuZGVmaW5lZCxcclxuICAgICAgW3ByZWZpeC50b1N0cmluZygpW2xvZ2dpbmcubGV2ZWxzRGVzY1tuZXdMZXZlbCAtIDFdLmNvbG9yXV0uY29uY2F0KFtcclxuICAgICAgICB0ZXh0cy5zaGlmdCgpW2NvbG9yc1tuZXdMZXZlbCAtIDFdXSxcclxuICAgICAgICAuLi50ZXh0c1xyXG4gICAgICBdKVxyXG4gICAgKTtcclxuICB9XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBMb2dzIGFuIGVycm9yIG1lc3NhZ2UgYWJvdXQgWm9kIGlzc3VlcyB3aXRoIHRoZSB2YWxpZGF0aW9uLiBPcHRpb25hbGx5LFxyXG4gKiBhIGN1c3RvbSBtZXNzYWdlIGNhbiBiZSBwcm92aWRlZC5cclxuICpcclxuICogQGZ1bmN0aW9uIGxvZ1pvZElzc3Vlc1xyXG4gKlxyXG4gKiBAcGFyYW0ge251bWJlcn0gbmV3TGV2ZWwgLSBUaGUgbG9nIGxldmVsLlxyXG4gKiBAcGFyYW0ge0Vycm9yW119IGlzc3VlcyAtIFRoZSBhcnJheSBvZiBab2QgaXNzdWVzLlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gY3VzdG9tTWVzc2FnZSAtIEFuIG9wdGlvbmFsIGN1c3RvbSBtZXNzYWdlIHRvIGJlIGxvZ2dlZFxyXG4gKiBhbG9uZyB3aXRoIHRoZSBlcnJvci5cclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiBsb2dab2RJc3N1ZXMobmV3TGV2ZWwsIGlzc3VlcyA9IFtdLCBjdXN0b21NZXNzYWdlKSB7XHJcbiAgbG9nV2l0aFN0YWNrKFxyXG4gICAgbmV3TGV2ZWwsXHJcbiAgICBudWxsLFxyXG4gICAgW1xyXG4gICAgICBgJHtjdXN0b21NZXNzYWdlfSAtIHRoZSBmb2xsb3dpbmcgWm9kIGlzc3VlcyBvY2N1cmVkOmAsXHJcbiAgICAgIC4uLmlzc3Vlcy5tYXAoKGlzc3VlKSA9PiBgLSAke2lzc3VlLm1lc3NhZ2V9YClcclxuICAgIF0uam9pbignXFxuJylcclxuICApO1xyXG59XHJcblxyXG4vKipcclxuICogSW5pdGlhbGl6ZXMgbG9nZ2luZyB3aXRoIHRoZSBzcGVjaWZpZWQgbG9nZ2luZyBjb25maWd1cmF0aW9uLlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gaW5pdExvZ2dpbmdcclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IGxvZ2dpbmdPcHRpb25zIC0gT2JqZWN0IGNvbnRhaW5pbmcgYGxvZ2dpbmdgIG9wdGlvbnMuXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gaW5pdExvZ2dpbmcobG9nZ2luZ09wdGlvbnMpIHtcclxuICAvLyBHZXQgb3B0aW9ucyBmcm9tIHRoZSBgbG9nZ2luZ09wdGlvbnNgIG9iamVjdFxyXG4gIGNvbnN0IHsgbGV2ZWwsIGRlc3QsIGZpbGUsIHRvQ29uc29sZSwgdG9GaWxlIH0gPSBsb2dnaW5nT3B0aW9ucztcclxuXHJcbiAgLy8gU2V0IHRoZSBsb2dnaW5nIGxldmVsXHJcbiAgc2V0TG9nTGV2ZWwobGV2ZWwpO1xyXG5cclxuICAvLyBTZXQgdGhlIGNvbnNvbGUgbG9nZ2luZ1xyXG4gIGVuYWJsZUNvbnNvbGVMb2dnaW5nKHRvQ29uc29sZSk7XHJcblxyXG4gIC8vIFNldCB0aGUgZmlsZSBsb2dnaW5nXHJcbiAgZW5hYmxlRmlsZUxvZ2dpbmcoZGVzdCwgZmlsZSwgdG9GaWxlKTtcclxufVxyXG5cclxuLyoqXHJcbiAqIFNldHMgdGhlIGxvZyBsZXZlbCB0byB0aGUgc3BlY2lmaWVkIHZhbHVlLiBMb2cgbGV2ZWxzIGFyZSAoMCA9IG5vIGxvZ2dpbmcsXHJcbiAqIDEgPSBlcnJvciwgMiA9IHdhcm5pbmcsIDMgPSBub3RpY2UsIDQgPSB2ZXJib3NlLCBvciA1ID0gYmVuY2htYXJrKS5cclxuICpcclxuICogQGZ1bmN0aW9uIHNldExvZ0xldmVsXHJcbiAqXHJcbiAqIEBwYXJhbSB7bnVtYmVyfSBsZXZlbCAtIFRoZSBsb2cgbGV2ZWwgdG8gYmUgc2V0LlxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIHNldExvZ0xldmVsKGxldmVsKSB7XHJcbiAgaWYgKGxldmVsID49IDAgJiYgbGV2ZWwgPD0gbG9nZ2luZy5sZXZlbHNEZXNjLmxlbmd0aCkge1xyXG4gICAgbG9nZ2luZy5sZXZlbCA9IGxldmVsO1xyXG4gIH1cclxufVxyXG5cclxuLyoqXHJcbiAqIEVuYWJsZXMgY29uc29sZSBsb2dnaW5nLlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gZW5hYmxlQ29uc29sZUxvZ2dpbmdcclxuICpcclxuICogQHBhcmFtIHtib29sZWFufSB0b0NvbnNvbGUgLSBUaGUgZmxhZyBmb3Igc2V0dGluZyB0aGUgbG9nZ2luZyB0byB0aGUgY29uc29sZS5cclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiBlbmFibGVDb25zb2xlTG9nZ2luZyh0b0NvbnNvbGUpIHtcclxuICAvLyBVcGRhdGUgb3B0aW9ucyBmb3IgdGhlIGNvbnNvbGUgbG9nZ2luZ1xyXG4gIGxvZ2dpbmcudG9Db25zb2xlID0gdG9Db25zb2xlO1xyXG59XHJcblxyXG4vKipcclxuICogRW5hYmxlcyBmaWxlIGxvZ2dpbmcgd2l0aCB0aGUgc3BlY2lmaWVkIGRlc3RpbmF0aW9uIGFuZCBsb2cgZmlsZS5cclxuICpcclxuICogQGZ1bmN0aW9uIGVuYWJsZUZpbGVMb2dnaW5nXHJcbiAqXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSBkZXN0IC0gVGhlIGRlc3RpbmF0aW9uIHBhdGggZm9yIHRoZSBsb2cgZmlsZS5cclxuICogQHBhcmFtIHtzdHJpbmd9IGZpbGUgLSBUaGUgbG9nIGZpbGUgbmFtZS5cclxuICogQHBhcmFtIHtib29sZWFufSB0b0ZpbGUgLSBUaGUgZmxhZyBmb3Igc2V0dGluZyB0aGUgbG9nZ2luZyB0byBhIGZpbGUuXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gZW5hYmxlRmlsZUxvZ2dpbmcoZGVzdCwgZmlsZSwgdG9GaWxlKSB7XHJcbiAgLy8gVXBkYXRlIG9wdGlvbnMgZm9yIHRoZSBmaWxlIGxvZ2dpbmdcclxuICBsb2dnaW5nLnRvRmlsZSA9IHRvRmlsZTtcclxuXHJcbiAgLy8gU2V0IHRoZSBgZGVzdGAgYW5kIGBmaWxlYCBvbmx5IGlmIHRoZSBmaWxlIGxvZ2dpbmcgaXMgZW5hYmxlZFxyXG4gIGlmICh0b0ZpbGUpIHtcclxuICAgIGxvZ2dpbmcuZGVzdCA9IGRlc3Q7XHJcbiAgICBsb2dnaW5nLmZpbGUgPSBmaWxlO1xyXG4gIH1cclxufVxyXG5cclxuLyoqXHJcbiAqIExvZ3MgdGhlIHByb3ZpZGVkIHRleHRzIHRvIGEgZmlsZSwgaWYgZmlsZSBsb2dnaW5nIGlzIGVuYWJsZWQuIEl0IGNyZWF0ZXNcclxuICogdGhlIG5lY2Vzc2FyeSBkaXJlY3Rvcnkgc3RydWN0dXJlIGlmIG5vdCBhbHJlYWR5IGNyZWF0ZWQgYW5kIGFwcGVuZHNcclxuICogdGhlIGNvbnRlbnQsIGluY2x1ZGluZyBhbiBvcHRpb25hbCBwcmVmaXgsIHRvIHRoZSBzcGVjaWZpZWQgbG9nIGZpbGUuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBfbG9nVG9GaWxlXHJcbiAqXHJcbiAqIEBwYXJhbSB7QXJyYXkuPHN0cmluZz59IHRleHRzIC0gQW4gYXJyYXkgb2YgdGV4dHMgdG8gYmUgbG9nZ2VkLlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gcHJlZml4IC0gQW4gb3B0aW9uYWwgcHJlZml4IHRvIGJlIGFkZGVkIHRvIGVhY2ggbG9nIGVudHJ5LlxyXG4gKi9cclxuZnVuY3Rpb24gX2xvZ1RvRmlsZSh0ZXh0cywgcHJlZml4KSB7XHJcbiAgaWYgKCFsb2dnaW5nLnBhdGhDcmVhdGVkKSB7XHJcbiAgICAvLyBDcmVhdGUgaWYgZG9lcyBub3QgZXhpc3RcclxuICAgICFleGlzdHNTeW5jKGdldEFic29sdXRlUGF0aChsb2dnaW5nLmRlc3QpKSAmJlxyXG4gICAgICBta2RpclN5bmMoZ2V0QWJzb2x1dGVQYXRoKGxvZ2dpbmcuZGVzdCkpO1xyXG5cclxuICAgIC8vIENyZWF0ZSB0aGUgZnVsbCBwYXRoXHJcbiAgICBsb2dnaW5nLnBhdGhUb0xvZyA9IGdldEFic29sdXRlUGF0aChqb2luKGxvZ2dpbmcuZGVzdCwgbG9nZ2luZy5maWxlKSk7XHJcblxyXG4gICAgLy8gV2Ugbm93IGFzc3VtZSB0aGUgcGF0aCBpcyBhdmFpbGFibGUsIGUuZy4gaXQncyB0aGUgcmVzcG9uc2liaWxpdHlcclxuICAgIC8vIG9mIHRoZSB1c2VyIHRvIGNyZWF0ZSB0aGUgcGF0aCB3aXRoIHRoZSBjb3JyZWN0IGFjY2VzcyByaWdodHMuXHJcbiAgICBsb2dnaW5nLnBhdGhDcmVhdGVkID0gdHJ1ZTtcclxuICB9XHJcblxyXG4gIC8vIEFkZCB0aGUgY29udGVudCB0byBhIGZpbGVcclxuICBhcHBlbmRGaWxlKFxyXG4gICAgbG9nZ2luZy5wYXRoVG9Mb2csXHJcbiAgICBbcHJlZml4XS5jb25jYXQodGV4dHMpLmpvaW4oJyAnKSArICdcXG4nLFxyXG4gICAgKGVycm9yKSA9PiB7XHJcbiAgICAgIGlmIChlcnJvciAmJiBsb2dnaW5nLnRvRmlsZSAmJiBsb2dnaW5nLnBhdGhDcmVhdGVkKSB7XHJcbiAgICAgICAgbG9nZ2luZy50b0ZpbGUgPSBmYWxzZTtcclxuICAgICAgICBsb2dnaW5nLnBhdGhDcmVhdGVkID0gZmFsc2U7XHJcbiAgICAgICAgbG9nV2l0aFN0YWNrKDIsIGVycm9yLCBgW2xvZ2dlcl0gVW5hYmxlIHRvIHdyaXRlIHRvIGxvZyBmaWxlLmApO1xyXG4gICAgICB9XHJcbiAgICB9XHJcbiAgKTtcclxufVxyXG5cclxuZXhwb3J0IGRlZmF1bHQge1xyXG4gIGxvZyxcclxuICBsb2dXaXRoU3RhY2ssXHJcbiAgbG9nWm9kSXNzdWVzLFxyXG4gIGluaXRMb2dnaW5nLFxyXG4gIHNldExvZ0xldmVsLFxyXG4gIGVuYWJsZUNvbnNvbGVMb2dnaW5nLFxyXG4gIGVuYWJsZUZpbGVMb2dnaW5nXHJcbn07XHJcbiIsIi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXHJcblxyXG5IaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXJcclxuXHJcbkNvcHlyaWdodCAoYykgMjAxNi0yMDI1LCBIaWdoc29mdFxyXG5cclxuTGljZW5jZWQgdW5kZXIgdGhlIE1JVCBsaWNlbmNlLlxyXG5cclxuQWRkaXRpb25hbGx5IGEgdmFsaWQgSGlnaGNoYXJ0cyBsaWNlbnNlIGlzIHJlcXVpcmVkIGZvciB1c2UuXHJcblxyXG5TZWUgTElDRU5TRSBmaWxlIGluIHJvb3QgZm9yIGRldGFpbHMuXHJcblxyXG4qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xyXG5cclxuLyoqXHJcbiAqIEBvdmVydmlldyBDb25maWd1cmF0aW9uIG1hbmFnZW1lbnQgbW9kdWxlIGZvciB0aGUgSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyLlxyXG4gKiBQcm92aWRlcyBkZWZhdWx0IGNvbmZpZ3VyYXRpb25zIHRoYXQgc3VwcG9ydCBlbnZpcm9ubWVudCB2YXJpYWJsZXMsIENMSVxyXG4gKiBhcmd1bWVudHMsIGFuZCBpbnRlcmFjdGl2ZSBwcm9tcHRzIGZvciBjdXN0b21pemF0aW9uIG9mIG9wdGlvbnMgYW5kIGZlYXR1cmVzLlxyXG4gKiBBZGRpdGlvbmFsbHksIGl0IG1hcHMgbGVnYWN5IG9wdGlvbnMgdG8gbW9kZXJuIHN0cnVjdHVyZXMsIGdlbmVyYXRlcyBuZXN0ZWRcclxuICogYXJndW1lbnQgbWFwcGluZ3MsIGFuZCBkaXNwbGF5cyBDTEkgdXNhZ2UgaW5mb3JtYXRpb24uXHJcbiAqL1xyXG5cclxuLyoqXHJcbiAqIFRoZSBjb25maWd1cmF0aW9uIG9iamVjdCBjb250YWluaW5nIGFsbCBhdmFpbGFibGUgb3B0aW9ucywgb3JnYW5pemVkXHJcbiAqIGJ5IHNlY3Rpb25zLlxyXG4gKlxyXG4gKiBUaGlzIG9iamVjdCBpbmNsdWRlczpcclxuICogLSBEZWZhdWx0IHZhbHVlcyBmb3IgZWFjaCBvcHRpb25cclxuICogLSBEYXRhIHR5cGVzIGZvciB2YWxpZGF0aW9uXHJcbiAqIC0gTmFtZXMgb2YgY29ycmVzcG9uZGluZyBlbnZpcm9ubWVudCB2YXJpYWJsZXNcclxuICogLSBEZXNjcmlwdGlvbnMgb2YgZWFjaCBwcm9wZXJ0eVxyXG4gKiAtIEluZm9ybWF0aW9uIHVzZWQgZm9yIHByb21wdHMgaW4gaW50ZXJhY3RpdmUgY29uZmlndXJhdGlvblxyXG4gKiAtIFtPcHRpb25hbF0gQ29ycmVzcG9uZGluZyBDTEkgYXJndW1lbnQgbmFtZXMgZm9yIENMSSB1c2FnZVxyXG4gKiAtIFtPcHRpb25hbF0gTGVnYWN5IG5hbWVzIGZyb20gdGhlIHByZXZpb3VzIFBoYW50b21KUy1iYXNlZCBzZXJ2ZXJcclxuICovXHJcbmV4cG9ydCBjb25zdCBkZWZhdWx0Q29uZmlnID0ge1xyXG4gIHB1cHBldGVlcjoge1xyXG4gICAgYXJnczoge1xyXG4gICAgICB2YWx1ZTogW1xyXG4gICAgICAgICctLWFsbG93LXJ1bm5pbmctaW5zZWN1cmUtY29udGVudCcsXHJcbiAgICAgICAgJy0tYXNoLW5vLW51ZGdlcycsXHJcbiAgICAgICAgJy0tYXV0b3BsYXktcG9saWN5PXVzZXItZ2VzdHVyZS1yZXF1aXJlZCcsXHJcbiAgICAgICAgJy0tYmxvY2stbmV3LXdlYi1jb250ZW50cycsXHJcbiAgICAgICAgJy0tZGlzYWJsZS1hY2NlbGVyYXRlZC0yZC1jYW52YXMnLFxyXG4gICAgICAgICctLWRpc2FibGUtYmFja2dyb3VuZC1uZXR3b3JraW5nJyxcclxuICAgICAgICAnLS1kaXNhYmxlLWJhY2tncm91bmQtdGltZXItdGhyb3R0bGluZycsXHJcbiAgICAgICAgJy0tZGlzYWJsZS1iYWNrZ3JvdW5kaW5nLW9jY2x1ZGVkLXdpbmRvd3MnLFxyXG4gICAgICAgICctLWRpc2FibGUtYnJlYWtwYWQnLFxyXG4gICAgICAgICctLWRpc2FibGUtY2hlY2tlci1pbWFnaW5nJyxcclxuICAgICAgICAnLS1kaXNhYmxlLWNsaWVudC1zaWRlLXBoaXNoaW5nLWRldGVjdGlvbicsXHJcbiAgICAgICAgJy0tZGlzYWJsZS1jb21wb25lbnQtZXh0ZW5zaW9ucy13aXRoLWJhY2tncm91bmQtcGFnZXMnLFxyXG4gICAgICAgICctLWRpc2FibGUtY29tcG9uZW50LXVwZGF0ZScsXHJcbiAgICAgICAgJy0tZGlzYWJsZS1kZWZhdWx0LWFwcHMnLFxyXG4gICAgICAgICctLWRpc2FibGUtZGV2LXNobS11c2FnZScsXHJcbiAgICAgICAgJy0tZGlzYWJsZS1kb21haW4tcmVsaWFiaWxpdHknLFxyXG4gICAgICAgICctLWRpc2FibGUtZXh0ZW5zaW9ucycsXHJcbiAgICAgICAgJy0tZGlzYWJsZS1mZWF0dXJlcz1DYWxjdWxhdGVOYXRpdmVXaW5PY2NsdXNpb24sSW50ZXJlc3RGZWVkQ29udGVudFN1Z2dlc3Rpb25zLFdlYk9UUCcsXHJcbiAgICAgICAgJy0tZGlzYWJsZS1oYW5nLW1vbml0b3InLFxyXG4gICAgICAgICctLWRpc2FibGUtaXBjLWZsb29kaW5nLXByb3RlY3Rpb24nLFxyXG4gICAgICAgICctLWRpc2FibGUtbG9nZ2luZycsXHJcbiAgICAgICAgJy0tZGlzYWJsZS1ub3RpZmljYXRpb25zJyxcclxuICAgICAgICAnLS1kaXNhYmxlLW9mZmVyLXN0b3JlLXVubWFza2VkLXdhbGxldC1jYXJkcycsXHJcbiAgICAgICAgJy0tZGlzYWJsZS1wb3B1cC1ibG9ja2luZycsXHJcbiAgICAgICAgJy0tZGlzYWJsZS1wcmludC1wcmV2aWV3JyxcclxuICAgICAgICAnLS1kaXNhYmxlLXByb21wdC1vbi1yZXBvc3QnLFxyXG4gICAgICAgICctLWRpc2FibGUtcmVuZGVyZXItYmFja2dyb3VuZGluZycsXHJcbiAgICAgICAgJy0tZGlzYWJsZS1zZWFyY2gtZW5naW5lLWNob2ljZS1zY3JlZW4nLFxyXG4gICAgICAgICctLWRpc2FibGUtc2Vzc2lvbi1jcmFzaGVkLWJ1YmJsZScsXHJcbiAgICAgICAgJy0tZGlzYWJsZS1zZXR1aWQtc2FuZGJveCcsXHJcbiAgICAgICAgJy0tZGlzYWJsZS1zaXRlLWlzb2xhdGlvbi10cmlhbHMnLFxyXG4gICAgICAgICctLWRpc2FibGUtc3BlZWNoLWFwaScsXHJcbiAgICAgICAgJy0tZGlzYWJsZS1zeW5jJyxcclxuICAgICAgICAnLS1lbmFibGUtdW5zYWZlLXdlYmdwdScsXHJcbiAgICAgICAgJy0taGlkZS1jcmFzaC1yZXN0b3JlLWJ1YmJsZScsXHJcbiAgICAgICAgJy0taGlkZS1zY3JvbGxiYXJzJyxcclxuICAgICAgICAnLS1tZXRyaWNzLXJlY29yZGluZy1vbmx5JyxcclxuICAgICAgICAnLS1tdXRlLWF1ZGlvJyxcclxuICAgICAgICAnLS1uby1kZWZhdWx0LWJyb3dzZXItY2hlY2snLFxyXG4gICAgICAgICctLW5vLWZpcnN0LXJ1bicsXHJcbiAgICAgICAgJy0tbm8tcGluZ3MnLFxyXG4gICAgICAgICctLW5vLXNhbmRib3gnLFxyXG4gICAgICAgICctLW5vLXN0YXJ0dXAtd2luZG93JyxcclxuICAgICAgICAnLS1uby16eWdvdGUnLFxyXG4gICAgICAgICctLXBhc3N3b3JkLXN0b3JlPWJhc2ljJyxcclxuICAgICAgICAnLS1wcm9jZXNzLXBlci10YWInLFxyXG4gICAgICAgICctLXVzZS1tb2NrLWtleWNoYWluJ1xyXG4gICAgICBdLFxyXG4gICAgICB0eXBlczogWydzdHJpbmdbXSddLFxyXG4gICAgICBlbnZMaW5rOiAnUFVQUEVURUVSX0FSR1MnLFxyXG4gICAgICBjbGlOYW1lOiAncHVwcGV0ZWVyQXJncycsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnQXJyYXkgb2YgUHVwcGV0ZWVyIGFyZ3VtZW50cycsXHJcbiAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICB0eXBlOiAnbGlzdCcsXHJcbiAgICAgICAgc2VwYXJhdG9yOiAnOydcclxuICAgICAgfVxyXG4gICAgfVxyXG4gIH0sXHJcbiAgaGlnaGNoYXJ0czoge1xyXG4gICAgdmVyc2lvbjoge1xyXG4gICAgICB2YWx1ZTogJ2xhdGVzdCcsXHJcbiAgICAgIHR5cGVzOiBbJ3N0cmluZyddLFxyXG4gICAgICBlbnZMaW5rOiAnSElHSENIQVJUU19WRVJTSU9OJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdIaWdoY2hhcnRzIHZlcnNpb24nLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ3RleHQnXHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICBjZG5Vcmw6IHtcclxuICAgICAgdmFsdWU6ICdodHRwczovL2NvZGUuaGlnaGNoYXJ0cy5jb20nLFxyXG4gICAgICB0eXBlczogWydzdHJpbmcnXSxcclxuICAgICAgZW52TGluazogJ0hJR0hDSEFSVFNfQ0ROX1VSTCcsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnQ0ROIFVSTCBmb3IgSGlnaGNoYXJ0cyBzY3JpcHRzJyxcclxuICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgIHR5cGU6ICd0ZXh0J1xyXG4gICAgICB9XHJcbiAgICB9LFxyXG4gICAgZm9yY2VGZXRjaDoge1xyXG4gICAgICB2YWx1ZTogZmFsc2UsXHJcbiAgICAgIHR5cGVzOiBbJ2Jvb2xlYW4nXSxcclxuICAgICAgZW52TGluazogJ0hJR0hDSEFSVFNfRk9SQ0VfRkVUQ0gnLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ0ZsYWcgdG8gcmVmZXRjaCBzY3JpcHRzIGFmdGVyIGVhY2ggc2VydmVyIHJlcnVuJyxcclxuICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgIHR5cGU6ICd0b2dnbGUnXHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICBjYWNoZVBhdGg6IHtcclxuICAgICAgdmFsdWU6ICcuY2FjaGUnLFxyXG4gICAgICB0eXBlczogWydzdHJpbmcnXSxcclxuICAgICAgZW52TGluazogJ0hJR0hDSEFSVFNfQ0FDSEVfUEFUSCcsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnRGlyZWN0b3J5IHBhdGggZm9yIGNhY2hlZCBIaWdoY2hhcnRzIHNjcmlwdHMnLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ3RleHQnXHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICBjb3JlU2NyaXB0czoge1xyXG4gICAgICB2YWx1ZTogWydoaWdoY2hhcnRzJywgJ2hpZ2hjaGFydHMtbW9yZScsICdoaWdoY2hhcnRzLTNkJ10sXHJcbiAgICAgIHR5cGVzOiBbJ3N0cmluZ1tdJ10sXHJcbiAgICAgIGVudkxpbms6ICdISUdIQ0hBUlRTX0NPUkVfU0NSSVBUUycsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnSGlnaGNoYXJ0cyBjb3JlIHNjcmlwdHMgdG8gZmV0Y2gnLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ211bHRpc2VsZWN0JyxcclxuICAgICAgICBpbnN0cnVjdGlvbnM6ICdTcGFjZTogU2VsZWN0IHNwZWNpZmljLCBBOiBTZWxlY3QgYWxsLCBFbnRlcjogQ29uZmlybSdcclxuICAgICAgfVxyXG4gICAgfSxcclxuICAgIG1vZHVsZVNjcmlwdHM6IHtcclxuICAgICAgdmFsdWU6IFtcclxuICAgICAgICAnc3RvY2snLFxyXG4gICAgICAgICdtYXAnLFxyXG4gICAgICAgICdnYW50dCcsXHJcbiAgICAgICAgJ2V4cG9ydGluZycsXHJcbiAgICAgICAgJ3BhcmFsbGVsLWNvb3JkaW5hdGVzJyxcclxuICAgICAgICAnYWNjZXNzaWJpbGl0eScsXHJcbiAgICAgICAgLy8gJ2Fubm90YXRpb25zLWFkdmFuY2VkJyxcclxuICAgICAgICAnYm9vc3QtY2FudmFzJyxcclxuICAgICAgICAnYm9vc3QnLFxyXG4gICAgICAgICdkYXRhJyxcclxuICAgICAgICAnZGF0YS10b29scycsXHJcbiAgICAgICAgJ2RyYWdnYWJsZS1wb2ludHMnLFxyXG4gICAgICAgICdzdGF0aWMtc2NhbGUnLFxyXG4gICAgICAgICdicm9rZW4tYXhpcycsXHJcbiAgICAgICAgJ2hlYXRtYXAnLFxyXG4gICAgICAgICd0aWxlbWFwJyxcclxuICAgICAgICAndGlsZWR3ZWJtYXAnLFxyXG4gICAgICAgICd0aW1lbGluZScsXHJcbiAgICAgICAgJ3RyZWVtYXAnLFxyXG4gICAgICAgICd0cmVlZ3JhcGgnLFxyXG4gICAgICAgICdpdGVtLXNlcmllcycsXHJcbiAgICAgICAgJ2RyaWxsZG93bicsXHJcbiAgICAgICAgJ2hpc3RvZ3JhbS1iZWxsY3VydmUnLFxyXG4gICAgICAgICdidWxsZXQnLFxyXG4gICAgICAgICdmdW5uZWwnLFxyXG4gICAgICAgICdmdW5uZWwzZCcsXHJcbiAgICAgICAgJ2dlb2hlYXRtYXAnLFxyXG4gICAgICAgICdweXJhbWlkM2QnLFxyXG4gICAgICAgICduZXR3b3JrZ3JhcGgnLFxyXG4gICAgICAgICdvdmVybGFwcGluZy1kYXRhbGFiZWxzJyxcclxuICAgICAgICAncGFyZXRvJyxcclxuICAgICAgICAncGF0dGVybi1maWxsJyxcclxuICAgICAgICAncGljdG9yaWFsJyxcclxuICAgICAgICAncHJpY2UtaW5kaWNhdG9yJyxcclxuICAgICAgICAnc2Fua2V5JyxcclxuICAgICAgICAnYXJjLWRpYWdyYW0nLFxyXG4gICAgICAgICdkZXBlbmRlbmN5LXdoZWVsJyxcclxuICAgICAgICAnc2VyaWVzLWxhYmVsJyxcclxuICAgICAgICAnc2VyaWVzLW9uLXBvaW50JyxcclxuICAgICAgICAnc29saWQtZ2F1Z2UnLFxyXG4gICAgICAgICdzb25pZmljYXRpb24nLFxyXG4gICAgICAgIC8vICdzdG9jay10b29scycsXHJcbiAgICAgICAgJ3N0cmVhbWdyYXBoJyxcclxuICAgICAgICAnc3VuYnVyc3QnLFxyXG4gICAgICAgICd2YXJpYWJsZS1waWUnLFxyXG4gICAgICAgICd2YXJpd2lkZScsXHJcbiAgICAgICAgJ3ZlY3RvcicsXHJcbiAgICAgICAgJ3Zlbm4nLFxyXG4gICAgICAgICd3aW5kYmFyYicsXHJcbiAgICAgICAgJ3dvcmRjbG91ZCcsXHJcbiAgICAgICAgJ3hyYW5nZScsXHJcbiAgICAgICAgJ25vLWRhdGEtdG8tZGlzcGxheScsXHJcbiAgICAgICAgJ2RyYWctcGFuZXMnLFxyXG4gICAgICAgICdkZWJ1Z2dlcicsXHJcbiAgICAgICAgJ2R1bWJiZWxsJyxcclxuICAgICAgICAnbG9sbGlwb3AnLFxyXG4gICAgICAgICdjeWxpbmRlcicsXHJcbiAgICAgICAgJ29yZ2FuaXphdGlvbicsXHJcbiAgICAgICAgJ2RvdHBsb3QnLFxyXG4gICAgICAgICdtYXJrZXItY2x1c3RlcnMnLFxyXG4gICAgICAgICdob2xsb3djYW5kbGVzdGljaycsXHJcbiAgICAgICAgJ2hlaWtpbmFzaGknLFxyXG4gICAgICAgICdmbG93bWFwJyxcclxuICAgICAgICAnZXhwb3J0LWRhdGEnLFxyXG4gICAgICAgICduYXZpZ2F0b3InLFxyXG4gICAgICAgICd0ZXh0cGF0aCdcclxuICAgICAgXSxcclxuICAgICAgdHlwZXM6IFsnc3RyaW5nW10nXSxcclxuICAgICAgZW52TGluazogJ0hJR0hDSEFSVFNfTU9EVUxFX1NDUklQVFMnLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ0hpZ2hjaGFydHMgbW9kdWxlIHNjcmlwdHMgdG8gZmV0Y2gnLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ211bHRpc2VsZWN0JyxcclxuICAgICAgICBpbnN0cnVjdGlvbnM6ICdTcGFjZTogU2VsZWN0IHNwZWNpZmljLCBBOiBTZWxlY3QgYWxsLCBFbnRlcjogQ29uZmlybSdcclxuICAgICAgfVxyXG4gICAgfSxcclxuICAgIGluZGljYXRvclNjcmlwdHM6IHtcclxuICAgICAgdmFsdWU6IFsnaW5kaWNhdG9ycy1hbGwnXSxcclxuICAgICAgdHlwZXM6IFsnc3RyaW5nW10nXSxcclxuICAgICAgZW52TGluazogJ0hJR0hDSEFSVFNfSU5ESUNBVE9SX1NDUklQVFMnLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ0hpZ2hjaGFydHMgaW5kaWNhdG9yIHNjcmlwdHMgdG8gZmV0Y2gnLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ211bHRpc2VsZWN0JyxcclxuICAgICAgICBpbnN0cnVjdGlvbnM6ICdTcGFjZTogU2VsZWN0IHNwZWNpZmljLCBBOiBTZWxlY3QgYWxsLCBFbnRlcjogQ29uZmlybSdcclxuICAgICAgfVxyXG4gICAgfSxcclxuICAgIGN1c3RvbVNjcmlwdHM6IHtcclxuICAgICAgdmFsdWU6IFtcclxuICAgICAgICAnaHR0cHM6Ly9jZG5qcy5jbG91ZGZsYXJlLmNvbS9hamF4L2xpYnMvbW9tZW50LmpzLzIuMzAuMS9tb21lbnQubWluLmpzJyxcclxuICAgICAgICAnaHR0cHM6Ly9jZG5qcy5jbG91ZGZsYXJlLmNvbS9hamF4L2xpYnMvbW9tZW50LXRpbWV6b25lLzAuNS40NS9tb21lbnQtdGltZXpvbmUtd2l0aC1kYXRhLm1pbi5qcydcclxuICAgICAgXSxcclxuICAgICAgdHlwZXM6IFsnc3RyaW5nW10nXSxcclxuICAgICAgZW52TGluazogJ0hJR0hDSEFSVFNfQ1VTVE9NX1NDUklQVFMnLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ0FkZGl0aW9uYWwgY3VzdG9tIHNjcmlwdHMgb3IgZGVwZW5kZW5jaWVzIHRvIGZldGNoJyxcclxuICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgIHR5cGU6ICdsaXN0JyxcclxuICAgICAgICBzZXBhcmF0b3I6ICc7J1xyXG4gICAgICB9XHJcbiAgICB9XHJcbiAgfSxcclxuICBleHBvcnQ6IHtcclxuICAgIGluZmlsZToge1xyXG4gICAgICB2YWx1ZTogbnVsbCxcclxuICAgICAgdHlwZXM6IFsnc3RyaW5nJywgJ251bGwnXSxcclxuICAgICAgZW52TGluazogJ0VYUE9SVF9JTkZJTEUnLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnSW5wdXQgZmlsZW5hbWUgd2l0aCB0eXBlLCBmb3JtYXR0ZWQgY29ycmVjdGx5IGFzIEpTT04gb3IgU1ZHJyxcclxuICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgIHR5cGU6ICd0ZXh0J1xyXG4gICAgICB9XHJcbiAgICB9LFxyXG4gICAgaW5zdHI6IHtcclxuICAgICAgdmFsdWU6IG51bGwsXHJcbiAgICAgIHR5cGVzOiBbJ3N0cmluZycsICdudWxsJ10sXHJcbiAgICAgIGVudkxpbms6ICdFWFBPUlRfSU5TVFInLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnT3ZlcnJpZGVzIHRoZSBgaW5maWxlYCB3aXRoIEpTT04sIHN0cmluZ2lmaWVkIEpTT04sIG9yIFNWRyBpbnB1dCcsXHJcbiAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICB0eXBlOiAndGV4dCdcclxuICAgICAgfVxyXG4gICAgfSxcclxuICAgIG9wdGlvbnM6IHtcclxuICAgICAgdmFsdWU6IG51bGwsXHJcbiAgICAgIHR5cGVzOiBbJ09iamVjdCcsICdudWxsJ10sXHJcbiAgICAgIGVudkxpbms6ICdFWFBPUlRfT1BUSU9OUycsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnQWxpYXMgZm9yIHRoZSBgaW5zdHJgIG9wdGlvbicsXHJcbiAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICB0eXBlOiAndGV4dCdcclxuICAgICAgfVxyXG4gICAgfSxcclxuICAgIHN2Zzoge1xyXG4gICAgICB2YWx1ZTogbnVsbCxcclxuICAgICAgdHlwZXM6IFsnc3RyaW5nJywgJ251bGwnXSxcclxuICAgICAgZW52TGluazogJ0VYUE9SVF9TVkcnLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ1NWRyBzdHJpbmcgcmVwcmVzZW50YXRpb24gb2YgdGhlIGNoYXJ0IHRvIHJlbmRlcicsXHJcbiAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICB0eXBlOiAndGV4dCdcclxuICAgICAgfVxyXG4gICAgfSxcclxuICAgIGJhdGNoOiB7XHJcbiAgICAgIHZhbHVlOiBudWxsLFxyXG4gICAgICB0eXBlczogWydzdHJpbmcnLCAnbnVsbCddLFxyXG4gICAgICBlbnZMaW5rOiAnRVhQT1JUX0JBVENIJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ0JhdGNoIGpvYiBzdHJpbmcgd2l0aCBpbnB1dC9vdXRwdXQgcGFpcnM6IFwiaW49b3V0O2luPW91dDsuLi5cIicsXHJcbiAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICB0eXBlOiAndGV4dCdcclxuICAgICAgfVxyXG4gICAgfSxcclxuICAgIG91dGZpbGU6IHtcclxuICAgICAgdmFsdWU6IG51bGwsXHJcbiAgICAgIHR5cGVzOiBbJ3N0cmluZycsICdudWxsJ10sXHJcbiAgICAgIGVudkxpbms6ICdFWFBPUlRfT1VURklMRScsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdPdXRwdXQgZmlsZW5hbWUgd2l0aCB0eXBlLiBDYW4gYmUganBlZywgcG5nLCBwZGYsIG9yIHN2ZyBhbmQgaWdub3JlcyBgdHlwZWAgb3B0aW9uJyxcclxuICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgIHR5cGU6ICd0ZXh0J1xyXG4gICAgICB9XHJcbiAgICB9LFxyXG4gICAgdHlwZToge1xyXG4gICAgICB2YWx1ZTogJ3BuZycsXHJcbiAgICAgIHR5cGVzOiBbJ3N0cmluZyddLFxyXG4gICAgICBlbnZMaW5rOiAnRVhQT1JUX1RZUEUnLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ0ZpbGUgZXhwb3J0IGZvcm1hdC4gQ2FuIGJlIGpwZWcsIHBuZywgcGRmLCBvciBzdmcnLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ3NlbGVjdCcsXHJcbiAgICAgICAgaGludDogJ0RlZmF1bHQ6IHBuZycsXHJcbiAgICAgICAgY2hvaWNlczogWydwbmcnLCAnanBlZycsICdwZGYnLCAnc3ZnJ11cclxuICAgICAgfVxyXG4gICAgfSxcclxuICAgIGNvbnN0cjoge1xyXG4gICAgICB2YWx1ZTogJ2NoYXJ0JyxcclxuICAgICAgdHlwZXM6IFsnc3RyaW5nJ10sXHJcbiAgICAgIGVudkxpbms6ICdFWFBPUlRfQ09OU1RSJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ0NoYXJ0IGNvbnN0cnVjdG9yLiBDYW4gYmUgY2hhcnQsIHN0b2NrQ2hhcnQsIG1hcENoYXJ0LCBvciBnYW50dENoYXJ0JyxcclxuICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgIHR5cGU6ICdzZWxlY3QnLFxyXG4gICAgICAgIGhpbnQ6ICdEZWZhdWx0OiBjaGFydCcsXHJcbiAgICAgICAgY2hvaWNlczogWydjaGFydCcsICdzdG9ja0NoYXJ0JywgJ21hcENoYXJ0JywgJ2dhbnR0Q2hhcnQnXVxyXG4gICAgICB9XHJcbiAgICB9LFxyXG4gICAgYjY0OiB7XHJcbiAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgdHlwZXM6IFsnYm9vbGVhbiddLFxyXG4gICAgICBlbnZMaW5rOiAnRVhQT1JUX0I2NCcsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdXaGV0aGVyIG9yIG5vdCB0byB0aGUgY2hhcnQgc2hvdWxkIGJlIHJlY2VpdmVkIGluIEJhc2U2NCBmb3JtYXQgaW5zdGVhZCBvZiBiaW5hcnknLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ3RvZ2dsZSdcclxuICAgICAgfVxyXG4gICAgfSxcclxuICAgIG5vRG93bmxvYWQ6IHtcclxuICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICB0eXBlczogWydib29sZWFuJ10sXHJcbiAgICAgIGVudkxpbms6ICdFWFBPUlRfTk9fRE9XTkxPQUQnLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnV2hldGhlciBvciBub3QgdG8gaW5jbHVkZSBvciBleGNsdWRlIGF0dGFjaG1lbnQgaGVhZGVycyBpbiB0aGUgcmVzcG9uc2UnLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ3RvZ2dsZSdcclxuICAgICAgfVxyXG4gICAgfSxcclxuICAgIGhlaWdodDoge1xyXG4gICAgICB2YWx1ZTogbnVsbCxcclxuICAgICAgdHlwZXM6IFsnbnVtYmVyJywgJ251bGwnXSxcclxuICAgICAgZW52TGluazogJ0VYUE9SVF9IRUlHSFQnLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ0hlaWdodCBvZiB0aGUgZXhwb3J0ZWQgY2hhcnQsIG92ZXJyaWRlcyBjaGFydCBzZXR0aW5ncycsXHJcbiAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICB0eXBlOiAnbnVtYmVyJ1xyXG4gICAgICB9XHJcbiAgICB9LFxyXG4gICAgd2lkdGg6IHtcclxuICAgICAgdmFsdWU6IG51bGwsXHJcbiAgICAgIHR5cGVzOiBbJ251bWJlcicsICdudWxsJ10sXHJcbiAgICAgIGVudkxpbms6ICdFWFBPUlRfV0lEVEgnLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ1dpZHRoIG9mIHRoZSBleHBvcnRlZCBjaGFydCwgb3ZlcnJpZGVzIGNoYXJ0IHNldHRpbmdzJyxcclxuICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgIHR5cGU6ICdudW1iZXInXHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICBzY2FsZToge1xyXG4gICAgICB2YWx1ZTogbnVsbCxcclxuICAgICAgdHlwZXM6IFsnbnVtYmVyJywgJ251bGwnXSxcclxuICAgICAgZW52TGluazogJ0VYUE9SVF9TQ0FMRScsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdTY2FsZSBvZiB0aGUgZXhwb3J0ZWQgY2hhcnQsIG92ZXJyaWRlcyBjaGFydCBzZXR0aW5ncy4gUmFuZ2VzIGZyb20gMC4xIHRvIDUuMCcsXHJcbiAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICB0eXBlOiAnbnVtYmVyJ1xyXG4gICAgICB9XHJcbiAgICB9LFxyXG4gICAgZGVmYXVsdEhlaWdodDoge1xyXG4gICAgICB2YWx1ZTogNDAwLFxyXG4gICAgICB0eXBlczogWydudW1iZXInXSxcclxuICAgICAgZW52TGluazogJ0VYUE9SVF9ERUZBVUxUX0hFSUdIVCcsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnRGVmYXVsdCBoZWlnaHQgb2YgdGhlIGV4cG9ydGVkIGNoYXJ0IGlmIG5vdCBzZXQnLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ251bWJlcidcclxuICAgICAgfVxyXG4gICAgfSxcclxuICAgIGRlZmF1bHRXaWR0aDoge1xyXG4gICAgICB2YWx1ZTogNjAwLFxyXG4gICAgICB0eXBlczogWydudW1iZXInXSxcclxuICAgICAgZW52TGluazogJ0VYUE9SVF9ERUZBVUxUX1dJRFRIJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdEZWZhdWx0IHdpZHRoIG9mIHRoZSBleHBvcnRlZCBjaGFydCBpZiBub3Qgc2V0JyxcclxuICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgIHR5cGU6ICdudW1iZXInXHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICBkZWZhdWx0U2NhbGU6IHtcclxuICAgICAgdmFsdWU6IDEsXHJcbiAgICAgIHR5cGVzOiBbJ251bWJlciddLFxyXG4gICAgICBlbnZMaW5rOiAnRVhQT1JUX0RFRkFVTFRfU0NBTEUnLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnRGVmYXVsdCBzY2FsZSBvZiB0aGUgZXhwb3J0ZWQgY2hhcnQgaWYgbm90IHNldC4gUmFuZ2VzIGZyb20gMC4xIHRvIDUuMCcsXHJcbiAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgICBtaW46IDAuMSxcclxuICAgICAgICBtYXg6IDVcclxuICAgICAgfVxyXG4gICAgfSxcclxuICAgIGdsb2JhbE9wdGlvbnM6IHtcclxuICAgICAgdmFsdWU6IG51bGwsXHJcbiAgICAgIHR5cGVzOiBbJ09iamVjdCcsICdzdHJpbmcnLCAnbnVsbCddLFxyXG4gICAgICBlbnZMaW5rOiAnRVhQT1JUX0dMT0JBTF9PUFRJT05TJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ0pTT04sIHN0cmluZ2lmaWVkIEpTT04gb3IgZmlsZW5hbWUgd2l0aCBnbG9iYWwgb3B0aW9ucyBmb3IgSGlnaGNoYXJ0cy5zZXRPcHRpb25zJyxcclxuICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgIHR5cGU6ICd0ZXh0J1xyXG4gICAgICB9XHJcbiAgICB9LFxyXG4gICAgdGhlbWVPcHRpb25zOiB7XHJcbiAgICAgIHZhbHVlOiBudWxsLFxyXG4gICAgICB0eXBlczogWydPYmplY3QnLCAnc3RyaW5nJywgJ251bGwnXSxcclxuICAgICAgZW52TGluazogJ0VYUE9SVF9USEVNRV9PUFRJT05TJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ0pTT04sIHN0cmluZ2lmaWVkIEpTT04gb3IgZmlsZW5hbWUgd2l0aCB0aGVtZSBvcHRpb25zIGZvciBIaWdoY2hhcnRzLnNldE9wdGlvbnMnLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ3RleHQnXHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICByYXN0ZXJpemF0aW9uVGltZW91dDoge1xyXG4gICAgICB2YWx1ZTogMTUwMCxcclxuICAgICAgdHlwZXM6IFsnbnVtYmVyJ10sXHJcbiAgICAgIGVudkxpbms6ICdFWFBPUlRfUkFTVEVSSVpBVElPTl9USU1FT1VUJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdNaWxsaXNlY29uZHMgdG8gd2FpdCBmb3Igd2VicGFnZSByZW5kZXJpbmcnLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ251bWJlcidcclxuICAgICAgfVxyXG4gICAgfVxyXG4gIH0sXHJcbiAgY3VzdG9tTG9naWM6IHtcclxuICAgIGFsbG93Q29kZUV4ZWN1dGlvbjoge1xyXG4gICAgICB2YWx1ZTogZmFsc2UsXHJcbiAgICAgIHR5cGVzOiBbJ2Jvb2xlYW4nXSxcclxuICAgICAgZW52TGluazogJ0NVU1RPTV9MT0dJQ19BTExPV19DT0RFX0VYRUNVVElPTicsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdBbGxvd3Mgb3IgZGlzYWxsb3dzIGV4ZWN1dGlvbiBvZiBhcmJpdHJhcnkgY29kZSBkdXJpbmcgZXhwb3J0aW5nJyxcclxuICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgIHR5cGU6ICd0b2dnbGUnXHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICBhbGxvd0ZpbGVSZXNvdXJjZXM6IHtcclxuICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICB0eXBlczogWydib29sZWFuJ10sXHJcbiAgICAgIGVudkxpbms6ICdDVVNUT01fTE9HSUNfQUxMT1dfRklMRV9SRVNPVVJDRVMnLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnQWxsb3dzIG9yIGRpc2FsbG93cyBpbmplY3Rpb24gb2YgZmlsZXN5c3RlbSByZXNvdXJjZXMgKGRpc2FibGVkIGluIHNlcnZlciBtb2RlKScsXHJcbiAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICB0eXBlOiAndG9nZ2xlJ1xyXG4gICAgICB9XHJcbiAgICB9LFxyXG4gICAgY3VzdG9tQ29kZToge1xyXG4gICAgICB2YWx1ZTogbnVsbCxcclxuICAgICAgdHlwZXM6IFsnc3RyaW5nJywgJ251bGwnXSxcclxuICAgICAgZW52TGluazogJ0NVU1RPTV9MT0dJQ19DVVNUT01fQ09ERScsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdDdXN0b20gY29kZSB0byBleGVjdXRlIGJlZm9yZSBjaGFydCBpbml0aWFsaXphdGlvbi4gQ2FuIGJlIGEgZnVuY3Rpb24sIGNvZGUgd3JhcHBlZCBpbiBhIGZ1bmN0aW9uLCBvciBhIC5qcyBmaWxlbmFtZScsXHJcbiAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICB0eXBlOiAndGV4dCdcclxuICAgICAgfVxyXG4gICAgfSxcclxuICAgIGNhbGxiYWNrOiB7XHJcbiAgICAgIHZhbHVlOiBudWxsLFxyXG4gICAgICB0eXBlczogWydzdHJpbmcnLCAnbnVsbCddLFxyXG4gICAgICBlbnZMaW5rOiAnQ1VTVE9NX0xPR0lDX0NBTExCQUNLJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ0phdmFTY3JpcHQgY29kZSB0byBydW4gZHVyaW5nIGNvbnN0cnVjdGlvbi4gQ2FuIGJlIGEgZnVuY3Rpb24gb3IgYSAuanMgZmlsZW5hbWUnLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ3RleHQnXHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICByZXNvdXJjZXM6IHtcclxuICAgICAgdmFsdWU6IG51bGwsXHJcbiAgICAgIHR5cGVzOiBbJ09iamVjdCcsICdzdHJpbmcnLCAnbnVsbCddLFxyXG4gICAgICBlbnZMaW5rOiAnQ1VTVE9NX0xPR0lDX1JFU09VUkNFUycsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdBZGRpdGlvbmFsIHJlc291cmNlcyBhcyBKU09OLCBzdHJpbmdpZmllZCBKU09OLCBvciBmaWxlbmFtZSwgY29udGFpbmluZyBmaWxlcywganMsIGFuZCBjc3Mgc2VjdGlvbnMnLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ3RleHQnXHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICBsb2FkQ29uZmlnOiB7XHJcbiAgICAgIHZhbHVlOiBudWxsLFxyXG4gICAgICB0eXBlczogWydzdHJpbmcnLCAnbnVsbCddLFxyXG4gICAgICBlbnZMaW5rOiAnQ1VTVE9NX0xPR0lDX0xPQURfQ09ORklHJyxcclxuICAgICAgbGVnYWN5TmFtZTogJ2Zyb21GaWxlJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdGaWxlIHdpdGggYSBwcmUtZGVmaW5lZCBjb25maWd1cmF0aW9uIHRvIHVzZScsXHJcbiAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICB0eXBlOiAndGV4dCdcclxuICAgICAgfVxyXG4gICAgfSxcclxuICAgIGNyZWF0ZUNvbmZpZzoge1xyXG4gICAgICB2YWx1ZTogbnVsbCxcclxuICAgICAgdHlwZXM6IFsnc3RyaW5nJywgJ251bGwnXSxcclxuICAgICAgZW52TGluazogJ0NVU1RPTV9MT0dJQ19DUkVBVEVfQ09ORklHJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ1Byb21wdC1iYXNlZCBvcHRpb24gc2V0dGluZywgc2F2ZWQgdG8gYSBwcm92aWRlZCBjb25maWcgZmlsZScsXHJcbiAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICB0eXBlOiAndGV4dCdcclxuICAgICAgfVxyXG4gICAgfVxyXG4gIH0sXHJcbiAgc2VydmVyOiB7XHJcbiAgICBlbmFibGU6IHtcclxuICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICB0eXBlczogWydib29sZWFuJ10sXHJcbiAgICAgIGVudkxpbms6ICdTRVJWRVJfRU5BQkxFJyxcclxuICAgICAgY2xpTmFtZTogJ2VuYWJsZVNlcnZlcicsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnU3RhcnRzIHRoZSBzZXJ2ZXIgd2hlbiB0cnVlJyxcclxuICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgIHR5cGU6ICd0b2dnbGUnXHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICBob3N0OiB7XHJcbiAgICAgIHZhbHVlOiAnMC4wLjAuMCcsXHJcbiAgICAgIHR5cGVzOiBbJ3N0cmluZyddLFxyXG4gICAgICBlbnZMaW5rOiAnU0VSVkVSX0hPU1QnLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ0hvc3RuYW1lIG9mIHRoZSBzZXJ2ZXInLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ3RleHQnXHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICBwb3J0OiB7XHJcbiAgICAgIHZhbHVlOiA3ODAxLFxyXG4gICAgICB0eXBlczogWydudW1iZXInXSxcclxuICAgICAgZW52TGluazogJ1NFUlZFUl9QT1JUJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdQb3J0IG51bWJlciBmb3IgdGhlIHNlcnZlcicsXHJcbiAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICB0eXBlOiAnbnVtYmVyJ1xyXG4gICAgICB9XHJcbiAgICB9LFxyXG4gICAgdXBsb2FkTGltaXQ6IHtcclxuICAgICAgdmFsdWU6IDMsXHJcbiAgICAgIHR5cGVzOiBbJ251bWJlciddLFxyXG4gICAgICBlbnZMaW5rOiAnU0VSVkVSX1VQTE9BRF9MSU1JVCcsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnTWF4aW11bSByZXF1ZXN0IGJvZHkgc2l6ZSBpbiBNQicsXHJcbiAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICB0eXBlOiAnbnVtYmVyJ1xyXG4gICAgICB9XHJcbiAgICB9LFxyXG4gICAgYmVuY2htYXJraW5nOiB7XHJcbiAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgdHlwZXM6IFsnYm9vbGVhbiddLFxyXG4gICAgICBlbnZMaW5rOiAnU0VSVkVSX0JFTkNITUFSS0lORycsXHJcbiAgICAgIGNsaU5hbWU6ICdzZXJ2ZXJCZW5jaG1hcmtpbmcnLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnRGlzcGxheXMgb3Igbm90IGFjdGlvbiBkdXJhdGlvbnMgaW4gbWlsbGlzZWNvbmRzIGR1cmluZyBzZXJ2ZXIgcmVxdWVzdHMnLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ3RvZ2dsZSdcclxuICAgICAgfVxyXG4gICAgfSxcclxuICAgIHByb3h5OiB7XHJcbiAgICAgIGhvc3Q6IHtcclxuICAgICAgICB2YWx1ZTogbnVsbCxcclxuICAgICAgICB0eXBlczogWydzdHJpbmcnLCAnbnVsbCddLFxyXG4gICAgICAgIGVudkxpbms6ICdTRVJWRVJfUFJPWFlfSE9TVCcsXHJcbiAgICAgICAgY2xpTmFtZTogJ3Byb3h5SG9zdCcsXHJcbiAgICAgICAgZGVzY3JpcHRpb246ICdIb3N0IG9mIHRoZSBwcm94eSBzZXJ2ZXIsIGlmIGFwcGxpY2FibGUnLFxyXG4gICAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICAgIHR5cGU6ICd0ZXh0J1xyXG4gICAgICAgIH1cclxuICAgICAgfSxcclxuICAgICAgcG9ydDoge1xyXG4gICAgICAgIHZhbHVlOiBudWxsLFxyXG4gICAgICAgIHR5cGVzOiBbJ251bWJlcicsICdudWxsJ10sXHJcbiAgICAgICAgZW52TGluazogJ1NFUlZFUl9QUk9YWV9QT1JUJyxcclxuICAgICAgICBjbGlOYW1lOiAncHJveHlQb3J0JyxcclxuICAgICAgICBkZXNjcmlwdGlvbjogJ1BvcnQgb2YgdGhlIHByb3h5IHNlcnZlciwgaWYgYXBwbGljYWJsZScsXHJcbiAgICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgICAgdHlwZTogJ251bWJlcidcclxuICAgICAgICB9XHJcbiAgICAgIH0sXHJcbiAgICAgIHRpbWVvdXQ6IHtcclxuICAgICAgICB2YWx1ZTogNTAwMCxcclxuICAgICAgICB0eXBlczogWydudW1iZXInXSxcclxuICAgICAgICBlbnZMaW5rOiAnU0VSVkVSX1BST1hZX1RJTUVPVVQnLFxyXG4gICAgICAgIGNsaU5hbWU6ICdwcm94eVRpbWVvdXQnLFxyXG4gICAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICAgJ1RpbWVvdXQgaW4gbWlsbGlzZWNvbmRzIGZvciB0aGUgcHJveHkgc2VydmVyLCBpZiBhcHBsaWNhYmxlJyxcclxuICAgICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgICB0eXBlOiAnbnVtYmVyJ1xyXG4gICAgICAgIH1cclxuICAgICAgfVxyXG4gICAgfSxcclxuICAgIHJhdGVMaW1pdGluZzoge1xyXG4gICAgICBlbmFibGU6IHtcclxuICAgICAgICB2YWx1ZTogZmFsc2UsXHJcbiAgICAgICAgdHlwZXM6IFsnYm9vbGVhbiddLFxyXG4gICAgICAgIGVudkxpbms6ICdTRVJWRVJfUkFURV9MSU1JVElOR19FTkFCTEUnLFxyXG4gICAgICAgIGNsaU5hbWU6ICdlbmFibGVSYXRlTGltaXRpbmcnLFxyXG4gICAgICAgIGRlc2NyaXB0aW9uOiAnRW5hYmxlcyBvciBkaXNhYmxlcyByYXRlIGxpbWl0aW5nIG9uIHRoZSBzZXJ2ZXInLFxyXG4gICAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICAgIHR5cGU6ICd0b2dnbGUnXHJcbiAgICAgICAgfVxyXG4gICAgICB9LFxyXG4gICAgICBtYXhSZXF1ZXN0czoge1xyXG4gICAgICAgIHZhbHVlOiAxMCxcclxuICAgICAgICB0eXBlczogWydudW1iZXInXSxcclxuICAgICAgICBlbnZMaW5rOiAnU0VSVkVSX1JBVEVfTElNSVRJTkdfTUFYX1JFUVVFU1RTJyxcclxuICAgICAgICBsZWdhY3lOYW1lOiAncmF0ZUxpbWl0JyxcclxuICAgICAgICBkZXNjcmlwdGlvbjogJ01heGltdW0gbnVtYmVyIG9mIHJlcXVlc3RzIGFsbG93ZWQgcGVyIG1pbnV0ZScsXHJcbiAgICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgICAgdHlwZTogJ251bWJlcidcclxuICAgICAgICB9XHJcbiAgICAgIH0sXHJcbiAgICAgIHdpbmRvdzoge1xyXG4gICAgICAgIHZhbHVlOiAxLFxyXG4gICAgICAgIHR5cGVzOiBbJ251bWJlciddLFxyXG4gICAgICAgIGVudkxpbms6ICdTRVJWRVJfUkFURV9MSU1JVElOR19XSU5ET1cnLFxyXG4gICAgICAgIGRlc2NyaXB0aW9uOiAnVGltZSB3aW5kb3cgaW4gbWludXRlcyBmb3IgcmF0ZSBsaW1pdGluZycsXHJcbiAgICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgICAgdHlwZTogJ251bWJlcidcclxuICAgICAgICB9XHJcbiAgICAgIH0sXHJcbiAgICAgIGRlbGF5OiB7XHJcbiAgICAgICAgdmFsdWU6IDAsXHJcbiAgICAgICAgdHlwZXM6IFsnbnVtYmVyJ10sXHJcbiAgICAgICAgZW52TGluazogJ1NFUlZFUl9SQVRFX0xJTUlUSU5HX0RFTEFZJyxcclxuICAgICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAgICdEZWxheSBkdXJhdGlvbiBiZXR3ZWVuIHN1Y2Nlc3NpdmUgcmVxdWVzdHMgYmVmb3JlIHJlYWNoaW5nIHRoZSBsaW1pdCcsXHJcbiAgICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgICAgdHlwZTogJ251bWJlcidcclxuICAgICAgICB9XHJcbiAgICAgIH0sXHJcbiAgICAgIHRydXN0UHJveHk6IHtcclxuICAgICAgICB2YWx1ZTogZmFsc2UsXHJcbiAgICAgICAgdHlwZXM6IFsnYm9vbGVhbiddLFxyXG4gICAgICAgIGVudkxpbms6ICdTRVJWRVJfUkFURV9MSU1JVElOR19UUlVTVF9QUk9YWScsXHJcbiAgICAgICAgZGVzY3JpcHRpb246ICdTZXQgdG8gdHJ1ZSBpZiB0aGUgc2VydmVyIGlzIGJlaGluZCBhIGxvYWQgYmFsYW5jZXInLFxyXG4gICAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICAgIHR5cGU6ICd0b2dnbGUnXHJcbiAgICAgICAgfVxyXG4gICAgICB9LFxyXG4gICAgICBza2lwS2V5OiB7XHJcbiAgICAgICAgdmFsdWU6IG51bGwsXHJcbiAgICAgICAgdHlwZXM6IFsnc3RyaW5nJywgJ251bGwnXSxcclxuICAgICAgICBlbnZMaW5rOiAnU0VSVkVSX1JBVEVfTElNSVRJTkdfU0tJUF9LRVknLFxyXG4gICAgICAgIGRlc2NyaXB0aW9uOiAnS2V5IHRvIGJ5cGFzcyB0aGUgcmF0ZSBsaW1pdGVyLCB1c2VkIHdpdGggYHNraXBUb2tlbmAnLFxyXG4gICAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICAgIHR5cGU6ICd0ZXh0J1xyXG4gICAgICAgIH1cclxuICAgICAgfSxcclxuICAgICAgc2tpcFRva2VuOiB7XHJcbiAgICAgICAgdmFsdWU6IG51bGwsXHJcbiAgICAgICAgdHlwZXM6IFsnc3RyaW5nJywgJ251bGwnXSxcclxuICAgICAgICBlbnZMaW5rOiAnU0VSVkVSX1JBVEVfTElNSVRJTkdfU0tJUF9UT0tFTicsXHJcbiAgICAgICAgZGVzY3JpcHRpb246ICdUb2tlbiB0byBieXBhc3MgdGhlIHJhdGUgbGltaXRlciwgdXNlZCB3aXRoIGBza2lwS2V5YCcsXHJcbiAgICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgICAgdHlwZTogJ3RleHQnXHJcbiAgICAgICAgfVxyXG4gICAgICB9XHJcbiAgICB9LFxyXG4gICAgc3NsOiB7XHJcbiAgICAgIGVuYWJsZToge1xyXG4gICAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgICB0eXBlczogWydib29sZWFuJ10sXHJcbiAgICAgICAgZW52TGluazogJ1NFUlZFUl9TU0xfRU5BQkxFJyxcclxuICAgICAgICBjbGlOYW1lOiAnZW5hYmxlU3NsJyxcclxuICAgICAgICBkZXNjcmlwdGlvbjogJ0VuYWJsZXMgb3IgZGlzYWJsZXMgU1NMIHByb3RvY29sJyxcclxuICAgICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgICB0eXBlOiAndG9nZ2xlJ1xyXG4gICAgICAgIH1cclxuICAgICAgfSxcclxuICAgICAgZm9yY2U6IHtcclxuICAgICAgICB2YWx1ZTogZmFsc2UsXHJcbiAgICAgICAgdHlwZXM6IFsnYm9vbGVhbiddLFxyXG4gICAgICAgIGVudkxpbms6ICdTRVJWRVJfU1NMX0ZPUkNFJyxcclxuICAgICAgICBjbGlOYW1lOiAnc3NsRm9yY2UnLFxyXG4gICAgICAgIGxlZ2FjeU5hbWU6ICdzc2xPbmx5JyxcclxuICAgICAgICBkZXNjcmlwdGlvbjogJ0ZvcmNlcyB0aGUgc2VydmVyIHRvIHVzZSBIVFRQUyBvbmx5IHdoZW4gdHJ1ZScsXHJcbiAgICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgICAgdHlwZTogJ3RvZ2dsZSdcclxuICAgICAgICB9XHJcbiAgICAgIH0sXHJcbiAgICAgIHBvcnQ6IHtcclxuICAgICAgICB2YWx1ZTogNDQzLFxyXG4gICAgICAgIHR5cGVzOiBbJ251bWJlciddLFxyXG4gICAgICAgIGVudkxpbms6ICdTRVJWRVJfU1NMX1BPUlQnLFxyXG4gICAgICAgIGNsaU5hbWU6ICdzc2xQb3J0JyxcclxuICAgICAgICBkZXNjcmlwdGlvbjogJ1BvcnQgZm9yIHRoZSBTU0wgc2VydmVyJyxcclxuICAgICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgICB0eXBlOiAnbnVtYmVyJ1xyXG4gICAgICAgIH1cclxuICAgICAgfSxcclxuICAgICAgY2VydFBhdGg6IHtcclxuICAgICAgICB2YWx1ZTogbnVsbCxcclxuICAgICAgICB0eXBlczogWydzdHJpbmcnLCAnbnVsbCddLFxyXG4gICAgICAgIGVudkxpbms6ICdTRVJWRVJfU1NMX0NFUlRfUEFUSCcsXHJcbiAgICAgICAgY2xpTmFtZTogJ3NzbENlcnRQYXRoJyxcclxuICAgICAgICBsZWdhY3lOYW1lOiAnc3NsUGF0aCcsXHJcbiAgICAgICAgZGVzY3JpcHRpb246ICdQYXRoIHRvIHRoZSBTU0wgY2VydGlmaWNhdGUva2V5IGZpbGUnLFxyXG4gICAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICAgIHR5cGU6ICd0ZXh0J1xyXG4gICAgICAgIH1cclxuICAgICAgfVxyXG4gICAgfVxyXG4gIH0sXHJcbiAgcG9vbDoge1xyXG4gICAgbWluV29ya2Vyczoge1xyXG4gICAgICB2YWx1ZTogNCxcclxuICAgICAgdHlwZXM6IFsnbnVtYmVyJ10sXHJcbiAgICAgIGVudkxpbms6ICdQT09MX01JTl9XT1JLRVJTJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdNaW5pbXVtIGFuZCBpbml0aWFsIG51bWJlciBvZiBwb29sIHdvcmtlcnMgdG8gc3Bhd24nLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ251bWJlcidcclxuICAgICAgfVxyXG4gICAgfSxcclxuICAgIG1heFdvcmtlcnM6IHtcclxuICAgICAgdmFsdWU6IDgsXHJcbiAgICAgIHR5cGVzOiBbJ251bWJlciddLFxyXG4gICAgICBlbnZMaW5rOiAnUE9PTF9NQVhfV09SS0VSUycsXHJcbiAgICAgIGxlZ2FjeU5hbWU6ICd3b3JrZXJzJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdNYXhpbXVtIG51bWJlciBvZiBwb29sIHdvcmtlcnMgdG8gc3Bhd24nLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ251bWJlcidcclxuICAgICAgfVxyXG4gICAgfSxcclxuICAgIHdvcmtMaW1pdDoge1xyXG4gICAgICB2YWx1ZTogNDAsXHJcbiAgICAgIHR5cGVzOiBbJ251bWJlciddLFxyXG4gICAgICBlbnZMaW5rOiAnUE9PTF9XT1JLX0xJTUlUJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdOdW1iZXIgb2YgdGFza3MgYSB3b3JrZXIgY2FuIGhhbmRsZSBiZWZvcmUgcmVzdGFydGluZycsXHJcbiAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICB0eXBlOiAnbnVtYmVyJ1xyXG4gICAgICB9XHJcbiAgICB9LFxyXG4gICAgYWNxdWlyZVRpbWVvdXQ6IHtcclxuICAgICAgdmFsdWU6IDUwMDAsXHJcbiAgICAgIHR5cGVzOiBbJ251bWJlciddLFxyXG4gICAgICBlbnZMaW5rOiAnUE9PTF9BQ1FVSVJFX1RJTUVPVVQnLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ1RpbWVvdXQgaW4gbWlsbGlzZWNvbmRzIGZvciBhY3F1aXJpbmcgYSByZXNvdXJjZScsXHJcbiAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICB0eXBlOiAnbnVtYmVyJ1xyXG4gICAgICB9XHJcbiAgICB9LFxyXG4gICAgY3JlYXRlVGltZW91dDoge1xyXG4gICAgICB2YWx1ZTogNTAwMCxcclxuICAgICAgdHlwZXM6IFsnbnVtYmVyJ10sXHJcbiAgICAgIGVudkxpbms6ICdQT09MX0NSRUFURV9USU1FT1VUJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdUaW1lb3V0IGluIG1pbGxpc2Vjb25kcyBmb3IgY3JlYXRpbmcgYSByZXNvdXJjZScsXHJcbiAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICB0eXBlOiAnbnVtYmVyJ1xyXG4gICAgICB9XHJcbiAgICB9LFxyXG4gICAgZGVzdHJveVRpbWVvdXQ6IHtcclxuICAgICAgdmFsdWU6IDUwMDAsXHJcbiAgICAgIHR5cGVzOiBbJ251bWJlciddLFxyXG4gICAgICBlbnZMaW5rOiAnUE9PTF9ERVNUUk9ZX1RJTUVPVVQnLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ1RpbWVvdXQgaW4gbWlsbGlzZWNvbmRzIGZvciBkZXN0cm95aW5nIGEgcmVzb3VyY2UnLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ251bWJlcidcclxuICAgICAgfVxyXG4gICAgfSxcclxuICAgIGlkbGVUaW1lb3V0OiB7XHJcbiAgICAgIHZhbHVlOiAzMDAwMCxcclxuICAgICAgdHlwZXM6IFsnbnVtYmVyJ10sXHJcbiAgICAgIGVudkxpbms6ICdQT09MX0lETEVfVElNRU9VVCcsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnVGltZW91dCBpbiBtaWxsaXNlY29uZHMgZm9yIGRlc3Ryb3lpbmcgaWRsZSByZXNvdXJjZXMnLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ251bWJlcidcclxuICAgICAgfVxyXG4gICAgfSxcclxuICAgIGNyZWF0ZVJldHJ5SW50ZXJ2YWw6IHtcclxuICAgICAgdmFsdWU6IDIwMCxcclxuICAgICAgdHlwZXM6IFsnbnVtYmVyJ10sXHJcbiAgICAgIGVudkxpbms6ICdQT09MX0NSRUFURV9SRVRSWV9JTlRFUlZBTCcsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdJbnRlcnZhbCBpbiBtaWxsaXNlY29uZHMgYmVmb3JlIHJldHJ5aW5nIHJlc291cmNlIGNyZWF0aW9uIG9uIGZhaWx1cmUnLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ251bWJlcidcclxuICAgICAgfVxyXG4gICAgfSxcclxuICAgIHJlYXBlckludGVydmFsOiB7XHJcbiAgICAgIHZhbHVlOiAxMDAwLFxyXG4gICAgICB0eXBlczogWydudW1iZXInXSxcclxuICAgICAgZW52TGluazogJ1BPT0xfUkVBUEVSX0lOVEVSVkFMJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ0ludGVydmFsIGluIG1pbGxpc2Vjb25kcyB0byBjaGVjayBhbmQgZGVzdHJveSBpZGxlIHJlc291cmNlcycsXHJcbiAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICB0eXBlOiAnbnVtYmVyJ1xyXG4gICAgICB9XHJcbiAgICB9LFxyXG4gICAgYmVuY2htYXJraW5nOiB7XHJcbiAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgdHlwZXM6IFsnYm9vbGVhbiddLFxyXG4gICAgICBlbnZMaW5rOiAnUE9PTF9CRU5DSE1BUktJTkcnLFxyXG4gICAgICBjbGlOYW1lOiAncG9vbEJlbmNobWFya2luZycsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnU2hvd3Mgc3RhdGlzdGljcyBmb3IgdGhlIHBvb2wgb2YgcmVzb3VyY2VzJyxcclxuICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgIHR5cGU6ICd0b2dnbGUnXHJcbiAgICAgIH1cclxuICAgIH1cclxuICB9LFxyXG4gIGxvZ2dpbmc6IHtcclxuICAgIGxldmVsOiB7XHJcbiAgICAgIHZhbHVlOiA0LFxyXG4gICAgICB0eXBlczogWydudW1iZXInXSxcclxuICAgICAgZW52TGluazogJ0xPR0dJTkdfTEVWRUwnLFxyXG4gICAgICBjbGlOYW1lOiAnbG9nTGV2ZWwnLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ0xvZ2dpbmcgdmVyYm9zaXR5IGxldmVsJyxcclxuICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICAgIHJvdW5kOiAwLFxyXG4gICAgICAgIG1pbjogMCxcclxuICAgICAgICBtYXg6IDVcclxuICAgICAgfVxyXG4gICAgfSxcclxuICAgIGZpbGU6IHtcclxuICAgICAgdmFsdWU6ICdoaWdoY2hhcnRzLWV4cG9ydC1zZXJ2ZXIubG9nJyxcclxuICAgICAgdHlwZXM6IFsnc3RyaW5nJ10sXHJcbiAgICAgIGVudkxpbms6ICdMT0dHSU5HX0ZJTEUnLFxyXG4gICAgICBjbGlOYW1lOiAnbG9nRmlsZScsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdMb2cgZmlsZSBuYW1lLiBSZXF1aXJlcyBgbG9nVG9GaWxlYCBhbmQgYGxvZ0Rlc3RgIHRvIGJlIHNldCcsXHJcbiAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICB0eXBlOiAndGV4dCdcclxuICAgICAgfVxyXG4gICAgfSxcclxuICAgIGRlc3Q6IHtcclxuICAgICAgdmFsdWU6ICdsb2cnLFxyXG4gICAgICB0eXBlczogWydzdHJpbmcnXSxcclxuICAgICAgZW52TGluazogJ0xPR0dJTkdfREVTVCcsXHJcbiAgICAgIGNsaU5hbWU6ICdsb2dEZXN0JyxcclxuICAgICAgZGVzY3JpcHRpb246ICdQYXRoIHRvIHN0b3JlIGxvZyBmaWxlcy4gUmVxdWlyZXMgYGxvZ1RvRmlsZWAgdG8gYmUgc2V0JyxcclxuICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgIHR5cGU6ICd0ZXh0J1xyXG4gICAgICB9XHJcbiAgICB9LFxyXG4gICAgdG9Db25zb2xlOiB7XHJcbiAgICAgIHZhbHVlOiB0cnVlLFxyXG4gICAgICB0eXBlczogWydib29sZWFuJ10sXHJcbiAgICAgIGVudkxpbms6ICdMT0dHSU5HX1RPX0NPTlNPTEUnLFxyXG4gICAgICBjbGlOYW1lOiAnbG9nVG9Db25zb2xlJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdFbmFibGVzIG9yIGRpc2FibGVzIGNvbnNvbGUgbG9nZ2luZycsXHJcbiAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICB0eXBlOiAndG9nZ2xlJ1xyXG4gICAgICB9XHJcbiAgICB9LFxyXG4gICAgdG9GaWxlOiB7XHJcbiAgICAgIHZhbHVlOiB0cnVlLFxyXG4gICAgICB0eXBlczogWydib29sZWFuJ10sXHJcbiAgICAgIGVudkxpbms6ICdMT0dHSU5HX1RPX0ZJTEUnLFxyXG4gICAgICBjbGlOYW1lOiAnbG9nVG9GaWxlJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdFbmFibGVzIG9yIGRpc2FibGVzIGxvZ2dpbmcgdG8gYSBmaWxlJyxcclxuICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgIHR5cGU6ICd0b2dnbGUnXHJcbiAgICAgIH1cclxuICAgIH1cclxuICB9LFxyXG4gIHVpOiB7XHJcbiAgICBlbmFibGU6IHtcclxuICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICB0eXBlczogWydib29sZWFuJ10sXHJcbiAgICAgIGVudkxpbms6ICdVSV9FTkFCTEUnLFxyXG4gICAgICBjbGlOYW1lOiAnZW5hYmxlVWknLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ0VuYWJsZXMgb3IgZGlzYWJsZXMgdGhlIFVJIGZvciB0aGUgZXhwb3J0IHNlcnZlcicsXHJcbiAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICB0eXBlOiAndG9nZ2xlJ1xyXG4gICAgICB9XHJcbiAgICB9LFxyXG4gICAgcm91dGU6IHtcclxuICAgICAgdmFsdWU6ICcvJyxcclxuICAgICAgdHlwZXM6IFsnc3RyaW5nJ10sXHJcbiAgICAgIGVudkxpbms6ICdVSV9ST1VURScsXHJcbiAgICAgIGNsaU5hbWU6ICd1aVJvdXRlJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdUaGUgZW5kcG9pbnQgcm91dGUgZm9yIHRoZSBVSScsXHJcbiAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICB0eXBlOiAndGV4dCdcclxuICAgICAgfVxyXG4gICAgfVxyXG4gIH0sXHJcbiAgb3RoZXI6IHtcclxuICAgIG5vZGVFbnY6IHtcclxuICAgICAgdmFsdWU6ICdwcm9kdWN0aW9uJyxcclxuICAgICAgdHlwZXM6IFsnc3RyaW5nJ10sXHJcbiAgICAgIGVudkxpbms6ICdPVEhFUl9OT0RFX0VOVicsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnVGhlIE5vZGUuanMgZW52aXJvbm1lbnQgdHlwZScsXHJcbiAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICB0eXBlOiAndGV4dCdcclxuICAgICAgfVxyXG4gICAgfSxcclxuICAgIGxpc3RlblRvUHJvY2Vzc0V4aXRzOiB7XHJcbiAgICAgIHZhbHVlOiB0cnVlLFxyXG4gICAgICB0eXBlczogWydib29sZWFuJ10sXHJcbiAgICAgIGVudkxpbms6ICdPVEhFUl9MSVNURU5fVE9fUFJPQ0VTU19FWElUUycsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnV2hldGhlciBvciBub3QgdG8gYXR0YWNoIHByb2Nlc3MuZXhpdCBoYW5kbGVycycsXHJcbiAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICB0eXBlOiAndG9nZ2xlJ1xyXG4gICAgICB9XHJcbiAgICB9LFxyXG4gICAgbm9Mb2dvOiB7XHJcbiAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgdHlwZXM6IFsnYm9vbGVhbiddLFxyXG4gICAgICBlbnZMaW5rOiAnT1RIRVJfTk9fTE9HTycsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnRGlzcGxheSBvciBza2lwIHByaW50aW5nIHRoZSBsb2dvIG9uIHN0YXJ0dXAnLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ3RvZ2dsZSdcclxuICAgICAgfVxyXG4gICAgfSxcclxuICAgIGhhcmRSZXNldFBhZ2U6IHtcclxuICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICB0eXBlczogWydib29sZWFuJ10sXHJcbiAgICAgIGVudkxpbms6ICdPVEhFUl9IQVJEX1JFU0VUX1BBR0UnLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ1doZXRoZXIgb3Igbm90IHRvIHJlc2V0IHRoZSBwYWdlIGNvbnRlbnQgZW50aXJlbHknLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ3RvZ2dsZSdcclxuICAgICAgfVxyXG4gICAgfSxcclxuICAgIGJyb3dzZXJTaGVsbE1vZGU6IHtcclxuICAgICAgdmFsdWU6IHRydWUsXHJcbiAgICAgIHR5cGVzOiBbJ2Jvb2xlYW4nXSxcclxuICAgICAgZW52TGluazogJ09USEVSX0JST1dTRVJfU0hFTExfTU9ERScsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnV2hldGhlciBvciBub3QgdG8gc2V0IHRoZSBicm93c2VyIHRvIHJ1biBpbiBzaGVsbCBtb2RlJyxcclxuICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgIHR5cGU6ICd0b2dnbGUnXHJcbiAgICAgIH1cclxuICAgIH1cclxuICB9LFxyXG4gIGRlYnVnOiB7XHJcbiAgICBlbmFibGU6IHtcclxuICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICB0eXBlczogWydib29sZWFuJ10sXHJcbiAgICAgIGVudkxpbms6ICdERUJVR19FTkFCTEUnLFxyXG4gICAgICBjbGlOYW1lOiAnZW5hYmxlRGVidWcnLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ0VuYWJsZXMgb3IgZGlzYWJsZXMgZGVidWcgbW9kZSBmb3IgdGhlIHVuZGVybHlpbmcgYnJvd3NlcicsXHJcbiAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICB0eXBlOiAndG9nZ2xlJ1xyXG4gICAgICB9XHJcbiAgICB9LFxyXG4gICAgaGVhZGxlc3M6IHtcclxuICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICB0eXBlczogWydib29sZWFuJ10sXHJcbiAgICAgIGVudkxpbms6ICdERUJVR19IRUFETEVTUycsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdXaGV0aGVyIG9yIG5vdCB0byBzZXQgdGhlIGJyb3dzZXIgdG8gcnVuIGluIGhlYWRsZXNzIG1vZGUgZHVyaW5nIGRlYnVnZ2luZycsXHJcbiAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICB0eXBlOiAndG9nZ2xlJ1xyXG4gICAgICB9XHJcbiAgICB9LFxyXG4gICAgZGV2dG9vbHM6IHtcclxuICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICB0eXBlczogWydib29sZWFuJ10sXHJcbiAgICAgIGVudkxpbms6ICdERUJVR19ERVZUT09MUycsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnRW5hYmxlcyBvciBkaXNhYmxlcyBEZXZUb29scyBpbiBoZWFkZnVsIG1vZGUnLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ3RvZ2dsZSdcclxuICAgICAgfVxyXG4gICAgfSxcclxuICAgIGxpc3RlblRvQ29uc29sZToge1xyXG4gICAgICB2YWx1ZTogZmFsc2UsXHJcbiAgICAgIHR5cGVzOiBbJ2Jvb2xlYW4nXSxcclxuICAgICAgZW52TGluazogJ0RFQlVHX0xJU1RFTl9UT19DT05TT0xFJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ0VuYWJsZXMgb3IgZGlzYWJsZXMgbGlzdGVuaW5nIHRvIGNvbnNvbGUgbWVzc2FnZXMgZnJvbSB0aGUgYnJvd3NlcicsXHJcbiAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICB0eXBlOiAndG9nZ2xlJ1xyXG4gICAgICB9XHJcbiAgICB9LFxyXG4gICAgZHVtcGlvOiB7XHJcbiAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgdHlwZXM6IFsnYm9vbGVhbiddLFxyXG4gICAgICBlbnZMaW5rOiAnREVCVUdfRFVNUElPJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ1JlZGlyZWN0cyBvciBub3QgYnJvd3NlciBzdGRvdXQgYW5kIHN0ZGVyciB0byBwcm9jZXNzLnN0ZG91dCBhbmQgcHJvY2Vzcy5zdGRlcnInLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ3RvZ2dsZSdcclxuICAgICAgfVxyXG4gICAgfSxcclxuICAgIHNsb3dNbzoge1xyXG4gICAgICB2YWx1ZTogMCxcclxuICAgICAgdHlwZXM6IFsnbnVtYmVyJ10sXHJcbiAgICAgIGVudkxpbms6ICdERUJVR19TTE9XX01PJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdEZWxheXMgUHVwcGV0ZWVyIG9wZXJhdGlvbnMgYnkgdGhlIHNwZWNpZmllZCBtaWxsaXNlY29uZHMnLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ251bWJlcidcclxuICAgICAgfVxyXG4gICAgfSxcclxuICAgIGRlYnVnZ2luZ1BvcnQ6IHtcclxuICAgICAgdmFsdWU6IDkyMjIsXHJcbiAgICAgIHR5cGVzOiBbJ251bWJlciddLFxyXG4gICAgICBlbnZMaW5rOiAnREVCVUdfREVCVUdHSU5HX1BPUlQnLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ1BvcnQgdXNlZCBmb3IgZGVidWdnaW5nJyxcclxuICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgIHR5cGU6ICdudW1iZXInXHJcbiAgICAgIH1cclxuICAgIH1cclxuICB9XHJcbn07XHJcblxyXG4vLyBQcm9wZXJ0aWVzIG5lc3RpbmcgbGV2ZWwgb2YgYWxsIG9wdGlvbnNcclxuZXhwb3J0IGNvbnN0IG5lc3RlZFByb3BzID0gX2NyZWF0ZU5lc3RlZFByb3BzKGRlZmF1bHRDb25maWcpO1xyXG5cclxuLy8gUHJvcGVydGllcyBuYW1lcyB0aGF0IHNob3VsZCBub3QgYmUgcmVjdXJzaXZlbHkgbWVyZ2VkXHJcbmV4cG9ydCBjb25zdCBhYnNvbHV0ZVByb3BzID0gX2NyZWF0ZUFic29sdXRlUHJvcHMoZGVmYXVsdENvbmZpZyk7XHJcblxyXG4vKipcclxuICogUmVjdXJzaXZlbHkgZ2VuZXJhdGVzIGEgbWFwcGluZyBvZiBuZXN0ZWQgYXJndW1lbnQgY2hhaW5zIGZyb20gYSBuZXN0ZWRcclxuICogY29uZmlnIG9iamVjdC4gVGhpcyBmdW5jdGlvbiB0cmF2ZXJzZXMgYSBuZXN0ZWQgb2JqZWN0IGFuZCBjcmVhdGVzIGEgbWFwcGluZ1xyXG4gKiB3aGVyZSBlYWNoIGtleSBpcyBhbiBhcmd1bWVudCBuYW1lIChlaXRoZXIgZnJvbSBgY2xpTmFtZWAsIGBsZWdhY3lOYW1lYCxcclxuICogb3IgdGhlIG9yaWdpbmFsIGtleSkgYW5kIGVhY2ggdmFsdWUgaXMgYSBzdHJpbmcgcmVwcmVzZW50aW5nIHRoZSBjaGFpblxyXG4gKiBvZiBuZXN0ZWQgcHJvcGVydGllcyBsZWFkaW5nIHRvIHRoYXQgYXJndW1lbnQuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBfY3JlYXRlTmVzdGVkUHJvcHNcclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IGNvbmZpZyAtIFRoZSBjb25maWd1cmF0aW9uIG9iamVjdC5cclxuICogQHBhcmFtIHtPYmplY3R9IFtuZXN0ZWRQcm9wcz17fV0gLSBUaGUgYWNjdW11bGF0b3Igb2JqZWN0IGZvciBzdG9yaW5nXHJcbiAqIHRoZSByZXN1bHRpbmcgYXJndW1lbnRzIGNoYWlucy4gIFRoZSBkZWZhdWx0IHZhbHVlIGlzIGFuIGVtcHR5IG9iamVjdC5cclxuICogQHBhcmFtIHtzdHJpbmd9IFtwcm9wQ2hhaW49JyddIC0gVGhlIGN1cnJlbnQgY2hhaW4gb2YgbmVzdGVkIHByb3BlcnRpZXMsXHJcbiAqIHVzZWQgaW50ZXJuYWxseSBkdXJpbmcgcmVjdXJzaW9uLiAgVGhlIGRlZmF1bHQgdmFsdWUgaXMgYW4gZW1wdHkgc3RyaW5nLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7T2JqZWN0fSBBbiBvYmplY3QgbWFwcGluZyBhcmd1bWVudCBuYW1lcyB0byB0aGVpciBjb3JyZXNwb25kaW5nXHJcbiAqIG5lc3RlZCBwcm9wZXJ0eSBjaGFpbnMuXHJcbiAqL1xyXG5mdW5jdGlvbiBfY3JlYXRlTmVzdGVkUHJvcHMoY29uZmlnLCBuZXN0ZWRQcm9wcyA9IHt9LCBwcm9wQ2hhaW4gPSAnJykge1xyXG4gIE9iamVjdC5rZXlzKGNvbmZpZykuZm9yRWFjaCgoa2V5KSA9PiB7XHJcbiAgICAvLyBHZXQgdGhlIHNwZWNpZmljIHNlY3Rpb25cclxuICAgIGNvbnN0IGVudHJ5ID0gY29uZmlnW2tleV07XHJcblxyXG4gICAgLy8gQ2hlY2sgaWYgdGhlcmUgaXMgc3RpbGwgbW9yZSBkZXB0aCB0byB0cmF2ZXJzZVxyXG4gICAgaWYgKHR5cGVvZiBlbnRyeS52YWx1ZSA9PT0gJ3VuZGVmaW5lZCcpIHtcclxuICAgICAgLy8gUmVjdXJzZSBpbnRvIGRlZXBlciBsZXZlbHMgb2YgbmVzdGVkIGFyZ3VtZW50c1xyXG4gICAgICBfY3JlYXRlTmVzdGVkUHJvcHMoZW50cnksIG5lc3RlZFByb3BzLCBgJHtwcm9wQ2hhaW59LiR7a2V5fWApO1xyXG4gICAgfSBlbHNlIHtcclxuICAgICAgLy8gQ3JlYXRlIHRoZSBjaGFpbiBvZiBuZXN0ZWQgYXJndW1lbnRzXHJcbiAgICAgIG5lc3RlZFByb3BzW2VudHJ5LmNsaU5hbWUgfHwga2V5XSA9IGAke3Byb3BDaGFpbn0uJHtrZXl9YC5zdWJzdHJpbmcoMSk7XHJcblxyXG4gICAgICAvLyBTdXBwb3J0IGZvciB0aGUgbGVnYWN5LCBQaGFudG9tSlMgcHJvcGVydGllcyBuYW1lc1xyXG4gICAgICBpZiAoZW50cnkubGVnYWN5TmFtZSAhPT0gdW5kZWZpbmVkKSB7XHJcbiAgICAgICAgbmVzdGVkUHJvcHNbZW50cnkubGVnYWN5TmFtZV0gPSBgJHtwcm9wQ2hhaW59LiR7a2V5fWAuc3Vic3RyaW5nKDEpO1xyXG4gICAgICB9XHJcbiAgICB9XHJcbiAgfSk7XHJcblxyXG4gIC8vIFJldHVybiB0aGUgb2JqZWN0IHdpdGggbmVzdGVkIGFyZ3VtZW50IGNoYWluc1xyXG4gIHJldHVybiBuZXN0ZWRQcm9wcztcclxufVxyXG5cclxuLyoqXHJcbiAqIFJlY3Vyc2l2ZWx5IGdhdGhlcnMgdGhlIG5hbWVzIG9mIHByb3BlcnRpZXMgZnJvbSBhIGNvbmZpZ3VyYXRpb24gb2JqZWN0IHRoYXRcclxuICogY2FuIGJlIHRyZWF0ZWQgYXMgYWJzb2x1dGUgcHJvcGVydGllcy4gVGhlc2UgcHJvcGVydGllcyBoYXZlIHZhbHVlcyB0aGF0XHJcbiAqIGFyZSBvYmplY3RzIGFuZCBkbyBub3QgY29udGFpbiBmdXJ0aGVyIG5lc3RlZCBkZXB0aCB3aGVuIG1lcmdpbmcgYW4gb2JqZWN0XHJcbiAqIGNvbnRhaW5pbmcgdGhlc2Ugb3B0aW9ucy5cclxuICpcclxuICogQGZ1bmN0aW9uIF9jcmVhdGVBYnNvbHV0ZVByb3BzXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBjb25maWcgLSBUaGUgY29uZmlndXJhdGlvbiBvYmplY3QuXHJcbiAqIEBwYXJhbSB7QXJyYXkuPHN0cmluZz59IFthYnNvbHV0ZVByb3BzPVtdXSAtIEFuIGFycmF5IHRvIGNvbGxlY3QgdGhlIG5hbWVzXHJcbiAqIG9mIGFic29sdXRlIHByb3BlcnRpZXMuIFRoZSBkZWZhdWx0IHZhbHVlIGlzIGFuIGVtcHR5IGFycmF5LlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7QXJyYXkuPHN0cmluZz59IEFuIGFycmF5IGNvbnRhaW5pbmcgdGhlIG5hbWVzIG9mIGFic29sdXRlXHJcbiAqIHByb3BlcnRpZXMuXHJcbiAqL1xyXG5mdW5jdGlvbiBfY3JlYXRlQWJzb2x1dGVQcm9wcyhjb25maWcsIGFic29sdXRlUHJvcHMgPSBbXSkge1xyXG4gIE9iamVjdC5rZXlzKGNvbmZpZykuZm9yRWFjaCgoa2V5KSA9PiB7XHJcbiAgICAvLyBHZXQgdGhlIHNwZWNpZmljIHNlY3Rpb25cclxuICAgIGNvbnN0IGVudHJ5ID0gY29uZmlnW2tleV07XHJcblxyXG4gICAgLy8gQ2hlY2sgaWYgdGhlcmUgaXMgc3RpbGwgbW9yZSBkZXB0aCB0byB0cmF2ZXJzZVxyXG4gICAgaWYgKHR5cGVvZiBlbnRyeS50eXBlcyA9PT0gJ3VuZGVmaW5lZCcpIHtcclxuICAgICAgLy8gUmVjdXJzZSBpbnRvIGRlZXBlciBsZXZlbHNcclxuICAgICAgX2NyZWF0ZUFic29sdXRlUHJvcHMoZW50cnksIGFic29sdXRlUHJvcHMpO1xyXG4gICAgfSBlbHNlIHtcclxuICAgICAgLy8gSWYgdGhlIG9wdGlvbiBjYW4gYmUgYW4gb2JqZWN0LCBzYXZlIGl0cyB0eXBlIGluIHRoZSBhcnJheVxyXG4gICAgICBpZiAoZW50cnkudHlwZXMuaW5jbHVkZXMoJ09iamVjdCcpKSB7XHJcbiAgICAgICAgYWJzb2x1dGVQcm9wcy5wdXNoKGtleSk7XHJcbiAgICAgIH1cclxuICAgIH1cclxuICB9KTtcclxuXHJcbiAgLy8gUmV0dXJuIHRoZSBhcnJheSB3aXRoIHRoZSBuYW1lcyBvZiBhYnNvbHV0ZSBwcm9wZXJ0aWVzXHJcbiAgcmV0dXJuIGFic29sdXRlUHJvcHM7XHJcbn1cclxuXHJcbmV4cG9ydCBkZWZhdWx0IHtcclxuICBkZWZhdWx0Q29uZmlnLFxyXG4gIG5lc3RlZFByb3BzLFxyXG4gIGFic29sdXRlUHJvcHNcclxufTtcclxuIiwiLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcclxuXHJcbkhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlclxyXG5cclxuQ29weXJpZ2h0IChjKSAyMDE2LTIwMjUsIEhpZ2hzb2Z0XHJcblxyXG5MaWNlbmNlZCB1bmRlciB0aGUgTUlUIGxpY2VuY2UuXHJcblxyXG5BZGRpdGlvbmFsbHkgYSB2YWxpZCBIaWdoY2hhcnRzIGxpY2Vuc2UgaXMgcmVxdWlyZWQgZm9yIHVzZS5cclxuXHJcblNlZSBMSUNFTlNFIGZpbGUgaW4gcm9vdCBmb3IgZGV0YWlscy5cclxuXHJcbioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXHJcblxyXG4vKipcclxuICogQG92ZXJ2aWV3IFRoaXMgZmlsZSBoYW5kbGVzIHBhcnNpbmcgYW5kIHZhbGlkYXRpbmcgb3B0aW9ucyBmcm9tIG11bHRpcGxlXHJcbiAqIHNvdXJjZXMgKHRoZSBjb25maWcgZmlsZSwgY3VzdG9tIEpTT04sIGVudmlyb25tZW50IHZhcmlhYmxlcywgQ0xJIGFyZ3VtZW50cyxcclxuICogYW5kIHJlcXVlc3QgcGF5bG9hZCkgdXNpbmcgdGhlICd6b2QnIGxpYnJhcnkuXHJcbiAqXHJcbiAqIEVudmlyb25tZW50IHZhcmlhYmxlcyBhcmUgcGFyc2VkIGFuZCB2YWxpZGF0ZWQgb25seSBvbmNlIGF0IGFwcGxpY2F0aW9uXHJcbiAqIHN0YXJ0dXAsIGFuZCB0aGUgdmFsaWRhdGVkIHJlc3VsdHMgYXJlIGV4cG9ydGVkIGFzIGBlbnZzYCBmb3IgdXNlIHRocm91Z2hvdXRcclxuICogdGhlIGFwcGxpY2F0aW9uLlxyXG4gKlxyXG4gKiBPcHRpb25zIGZyb20gb3RoZXIgc291cmNlcywgaG93ZXZlciwgYXJlIHBhcnNlZCBhbmQgdmFsaWRhdGVkIG9uIGRlbWFuZCxcclxuICogZWFjaCB0aW1lIGFuIGV4cG9ydCBpcyBhdHRlbXB0ZWQuXHJcbiAqL1xyXG5cclxuaW1wb3J0IGRvdGVudiBmcm9tICdkb3RlbnYnO1xyXG5pbXBvcnQgeyB6IH0gZnJvbSAnem9kJztcclxuXHJcbmltcG9ydCB7IGRlZmF1bHRDb25maWcgfSBmcm9tICcuL3NjaGVtYXMvY29uZmlnLmpzJztcclxuXHJcbi8vIExvYWQgdGhlIC5lbnYgaW50byBlbnZpcm9ubWVudCB2YXJpYWJsZXNcclxuZG90ZW52LmNvbmZpZygpO1xyXG5cclxuLy8gR2V0IHNjcmlwdHMgbmFtZXMgb2YgZWFjaCBjYXRlZ29yeSBmcm9tIHRoZSBkZWZhdWx0IGNvbmZpZ1xyXG5jb25zdCB7IGNvcmVTY3JpcHRzLCBtb2R1bGVTY3JpcHRzLCBpbmRpY2F0b3JTY3JpcHRzIH0gPVxyXG4gIGRlZmF1bHRDb25maWcuaGlnaGNoYXJ0cztcclxuXHJcbi8vIFNldHMgdGhlIGN1c3RvbSBlcnJvciBtYXAgZ2xvYmFsbHlcclxuei5zZXRFcnJvck1hcChfY3VzdG9tRXJyb3JNYXApO1xyXG5cclxuLyoqXHJcbiAqIE9iamVjdCBjb250YWluaW5nIGN1c3RvbSBnZW5lcmFsIHZhbGlkYXRvcnMgYW5kIHBhcnNlcnMgdG8gYXZvaWQgcmVwZXRpdGlvblxyXG4gKiBpbiBzY2hlbWEgb2JqZWN0cy4gQWxsIHZhbGlkYXRvcnMgYXBwbHkgdG8gdmFsdWVzIGZyb20gdmFyaW91cyBzb3VyY2VzLFxyXG4gKiBpbmNsdWRpbmcgdGhlIGRlZmF1bHQgY29uZmlnIGZpbGUsIGEgY3VzdG9tIEpTT04gZmlsZSBsb2FkZWQgd2l0aCB0aGUgb3B0aW9uXHJcbiAqIGNhbGxlZCBgbG9hZENvbmZpZ2AsIHRoZSAuZW52IGZpbGUsIENMSSBhcmd1bWVudHMsIGFuZCB0aGUgcmVxdWVzdCBwYXlsb2FkLlxyXG4gKiBUaGUgYHN0cmljdENoZWNrYCBmbGFnIGVuYWJsZXMgc3RyaWN0ZXIgdmFsaWRhdGlvbiBhbmQgcGFyc2luZyBydWxlcy4gVGhpc1xyXG4gKiBmbGFnIGlzIHNldCB0byBmYWxzZSBmb3IgdmFsdWVzIHRoYXQgY29tZSBmcm9tIHRoZSAuZW52IGZpbGUgb3IgQ0xJIGFyZ3VtZW50c1xyXG4gKiBiZWNhdXNlIHRoZXkgYXJlIHByb3ZpZGVkIGFzIHN0cmluZ3MgYW5kIG5lZWQgdG8gYmUgcGFyc2VkIGFjY29yZGluZ2x5IGZpcnN0LlxyXG4gKi9cclxuY29uc3QgdiA9IHtcclxuICAvKipcclxuICAgKiBUaGUgYGJvb2xlYW5gIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGggYW4gb3B0aW9uYWwgc3RyaWN0ZXJcclxuICAgKiBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGF0OlxyXG4gICAqXHJcbiAgICogLSBXaGVuIGBzdHJpY3RDaGVja2AgaXMgdHJ1ZSwgdGhlIHNjaGVtYSB3aWxsIGFjY2VwdCB2YWx1ZXMgYXJlIHRydWVcclxuICAgKiBhbmQgZmFsc2UgYW5kIHRoZSBzY2hlbWEgd2lsbCB2YWxpZGF0ZSBhZ2FpbnN0IHRoZSBkZWZhdWx0IGJvb2xlYW5cclxuICAgKiB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiAtIFdoZW4gYHN0cmljdENoZWNrYCBpcyBmYWxzZSwgdGhlIHNjaGVtYSB3aWxsIGFjY2VwdCB2YWx1ZXMgYXJlIHRydWUsXHJcbiAgICogZmFsc2UsIG51bGwsICd0cnVlJywgJ2ZhbHNlJywgJ3VuZGVmaW5lZCcsICdudWxsJywgYW5kICcnLiBUaGUgc3RyaW5nc1xyXG4gICAqICd1bmRlZmluZWQnLCAnbnVsbCcsIGFuZCAnJyB3aWxsIGJlIHRyYW5zZm9ybWVkIHRvIG51bGwsIHRoZSBzdHJpbmcgJ3RydWUnXHJcbiAgICogd2lsbCBiZSB0cmFuc2Zvcm1lZCB0byB0aGUgYm9vbGVhbiB2YWx1ZSB0cnVlLCBhbmQgJ2ZhbHNlJyB3aWxsXHJcbiAgICogYmUgdHJhbnNmb3JtZWQgdG8gdGhlIGJvb2xlYW4gdmFsdWUgZmFsc2UuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gYm9vbGVhblxyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nIGJvb2xlYW4gdmFsdWVzLlxyXG4gICAqL1xyXG4gIGJvb2xlYW4oc3RyaWN0Q2hlY2spIHtcclxuICAgIHJldHVybiBzdHJpY3RDaGVja1xyXG4gICAgICA/IHouYm9vbGVhbigpXHJcbiAgICAgIDogelxyXG4gICAgICAgICAgLnVuaW9uKFtcclxuICAgICAgICAgICAgelxyXG4gICAgICAgICAgICAgIC5lbnVtKFsndHJ1ZScsICdmYWxzZScsICd1bmRlZmluZWQnLCAnbnVsbCcsICcnXSlcclxuICAgICAgICAgICAgICAudHJhbnNmb3JtKCh2YWx1ZSkgPT5cclxuICAgICAgICAgICAgICAgICFbJ3VuZGVmaW5lZCcsICdudWxsJywgJyddLmluY2x1ZGVzKHZhbHVlKVxyXG4gICAgICAgICAgICAgICAgICA/IHZhbHVlID09PSAndHJ1ZSdcclxuICAgICAgICAgICAgICAgICAgOiBudWxsXHJcbiAgICAgICAgICAgICAgKSxcclxuICAgICAgICAgICAgei5ib29sZWFuKClcclxuICAgICAgICAgIF0pXHJcbiAgICAgICAgICAubnVsbGFibGUoKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYHN0cmluZ2AgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbCBzdHJpY3RlclxyXG4gICAqIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoYXQ6XHJcbiAgICpcclxuICAgKiAtIFdoZW4gYHN0cmljdENoZWNrYCBpcyB0cnVlLCB0aGUgc2NoZW1hIHdpbGwgYWNjZXB0IHRyaW1tZWQgc3RyaW5ncyBleGNlcHRcclxuICAgKiB0aGUgZm9yYmlkZGVuIHZhbHVlczogJ2ZhbHNlJywgJ3VuZGVmaW5lZCcsICdudWxsJywgYW5kICcnLlxyXG4gICAqXHJcbiAgICogLSBXaGVuIGBzdHJpY3RDaGVja2AgaXMgZmFsc2UsIHRoZSBzY2hlbWEgd2lsbCBhY2NlcHQgdHJpbW1lZCBzdHJpbmdzXHJcbiAgICogYW5kIG51bGwuIFRoZSBmb3JiaWRkZW4gdmFsdWVzOiAnZmFsc2UnLCAndW5kZWZpbmVkJywgJ251bGwnLCBhbmQgJycgd2lsbFxyXG4gICAqIGJlIHRyYW5zZm9ybWVkIHRvIG51bGwuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gc3RyaW5nXHJcbiAgICpcclxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IHN0cmljdENoZWNrIC0gRGV0ZXJtaW5lcyBpZiBzdHJpY3RlciB2YWxpZGF0aW9uIHNob3VsZFxyXG4gICAqIGJlIGFwcGxpZWQuXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9IEEgWm9kIHNjaGVtYSBvYmplY3QgZm9yIHZhbGlkYXRpbmcgc3RyaW5nIHZhbHVlcy5cclxuICAgKi9cclxuICBzdHJpbmcoc3RyaWN0Q2hlY2spIHtcclxuICAgIHJldHVybiBzdHJpY3RDaGVja1xyXG4gICAgICA/IHpcclxuICAgICAgICAgIC5zdHJpbmcoKVxyXG4gICAgICAgICAgLnRyaW0oKVxyXG4gICAgICAgICAgLnJlZmluZShcclxuICAgICAgICAgICAgKHZhbHVlKSA9PiAhWydmYWxzZScsICd1bmRlZmluZWQnLCAnbnVsbCcsICcnXS5pbmNsdWRlcyh2YWx1ZSksXHJcbiAgICAgICAgICAgIHtcclxuICAgICAgICAgICAgICBwYXJhbXM6IHtcclxuICAgICAgICAgICAgICAgIGVycm9yTWVzc2FnZTogYFRoZSBzdHJpbmcgY29udGFpbnMgYSBmb3JiaWRkZW4gdmFsdWVgXHJcbiAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICB9XHJcbiAgICAgICAgICApXHJcbiAgICAgIDogelxyXG4gICAgICAgICAgLnN0cmluZygpXHJcbiAgICAgICAgICAudHJpbSgpXHJcbiAgICAgICAgICAudHJhbnNmb3JtKCh2YWx1ZSkgPT5cclxuICAgICAgICAgICAgIVsnZmFsc2UnLCAndW5kZWZpbmVkJywgJ251bGwnLCAnJ10uaW5jbHVkZXModmFsdWUpID8gdmFsdWUgOiBudWxsXHJcbiAgICAgICAgICApXHJcbiAgICAgICAgICAubnVsbGFibGUoKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYGVudW1gIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGggYW4gb3B0aW9uYWwgc3RyaWN0ZXJcclxuICAgKiBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgc2NoZW1hIHdpbGwgdmFsaWRhdGUgYWdhaW5zdCB0aGUgcHJvdmlkZWQgYHZhbHVlc2AgYXJyYXkuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGF0OlxyXG4gICAqXHJcbiAgICogLSBXaGVuIGBzdHJpY3RDaGVja2AgaXMgdHJ1ZSwgdGhlIHNjaGVtYSB3aWxsIHZhbGlkYXRlIGFnYWluc3QgdGhlIGB2YWx1ZXNgXHJcbiAgICogYXJyYXkgd2l0aCB0aGUgZGVmYXVsdCBlbnVtIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIC0gV2hlbiBgc3RyaWN0Q2hlY2tgIGlzIGZhbHNlLCB0aGUgc2NoZW1hIHdpbGwgYWNjZXB0IGFsc28gbnVsbCxcclxuICAgKiAndW5kZWZpbmVkJywgJ251bGwnLCBhbmQgJycsIHdoaWNoIHdpbGwgYmUgdHJhbnNmb3JtZWQgdG8gbnVsbC5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiBlbnVtXHJcbiAgICpcclxuICAgKiBAcGFyYW0ge0FycmF5LjxzdHJpbmc+fSB2YWx1ZXMgLSBBbiBhcnJheSBvZiB2YWxpZCBzdHJpbmcgdmFsdWVzXHJcbiAgICogZm9yIHRoZSBlbnVtLlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZyBlbnVtIHZhbHVlcy5cclxuICAgKi9cclxuICBlbnVtKHZhbHVlcywgc3RyaWN0Q2hlY2spIHtcclxuICAgIHJldHVybiBzdHJpY3RDaGVja1xyXG4gICAgICA/IHouZW51bShbLi4udmFsdWVzXSlcclxuICAgICAgOiB6XHJcbiAgICAgICAgICAuZW51bShbLi4udmFsdWVzLCAndW5kZWZpbmVkJywgJ251bGwnLCAnJ10pXHJcbiAgICAgICAgICAudHJhbnNmb3JtKCh2YWx1ZSkgPT5cclxuICAgICAgICAgICAgIVsndW5kZWZpbmVkJywgJ251bGwnLCAnJ10uaW5jbHVkZXModmFsdWUpID8gdmFsdWUgOiBudWxsXHJcbiAgICAgICAgICApXHJcbiAgICAgICAgICAubnVsbGFibGUoKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYHN0cmluZ0FycmF5YCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoIGFuIG9wdGlvbmFsXHJcbiAgICogc3RyaWN0ZXIgY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhhdDpcclxuICAgKlxyXG4gICAqIC0gV2hlbiBgc3RyaWN0Q2hlY2tgIGlzIHRydWUsIHRoZSBzY2hlbWEgd2lsbCBhY2NlcHQgYW4gYXJyYXkgb2YgdHJpbW1lZFxyXG4gICAqIHN0cmluZyB2YWx1ZXMgZmlsdGVyZWQgYnkgdGhlIGxvZ2ljIHByb3ZpZGVkIHRocm91Z2ggdGhlIGBmaWx0ZXJDYWxsYmFja2AuXHJcbiAgICpcclxuICAgKiAtIFdoZW4gYHN0cmljdENoZWNrYCBpcyBmYWxzZSwgdGhlIHNjaGVtYSB3aWxsIGFjY2VwdCBudWxsIGFuZCB0cmltbWVkXHJcbiAgICogc3RyaW5nIHZhbHVlcyB3aGljaCB3aWxsIGJlIHNwbGl0dGVkIGludG8gYW4gYXJyYXkgb2Ygc3RyaW5ncyBhbmQgZmlsdGVyZWRcclxuICAgKiBmcm9tIHRoZSAnWycgYW5kICddJyBjaGFyYWN0ZXJzIGFuZCBieSB0aGUgbG9naWMgcHJvdmlkZWQgdGhyb3VnaFxyXG4gICAqIHRoZSBgZmlsdGVyQ2FsbGJhY2tgLiBJZiB0aGUgYXJyYXkgaXMgZW1wdHksIGl0IHdpbGwgYmUgdHJhbnNmb3JtZWRcclxuICAgKiB0byBudWxsLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIHN0cmluZ0FycmF5XHJcbiAgICpcclxuICAgKiBAcGFyYW0ge2Z1bmN0aW9ufSBmaWx0ZXJDYWxsYmFjayAtIFRoZSBmaWx0ZXIgY2FsbGJhY2suXHJcbiAgICogQHBhcmFtIHtzdHJpbmd9IHNlcGFyYXRvciAtIFRoZSBzZXBhcmF0b3IgZm9yIHNwbGl0aW5nIGEgc3RyaW5nLlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZyBhcnJheSBvZiBzdHJpbmdcclxuICAgKiB2YWx1ZXMuXHJcbiAgICovXHJcbiAgc3RyaW5nQXJyYXkoZmlsdGVyQ2FsbGJhY2ssIHNlcGFyYXRvciwgc3RyaWN0Q2hlY2spIHtcclxuICAgIGNvbnN0IGFycmF5U2NoZW1hID0gei5zdHJpbmcoKS50cmltKCkuYXJyYXkoKTtcclxuICAgIGNvbnN0IHN0cmluZ1NjaGVtYSA9IHpcclxuICAgICAgLnN0cmluZygpXHJcbiAgICAgIC50cmltKClcclxuICAgICAgLnRyYW5zZm9ybSgodmFsdWUpID0+IHtcclxuICAgICAgICBpZiAodmFsdWUuc3RhcnRzV2l0aCgnWycpKSB7XHJcbiAgICAgICAgICB2YWx1ZSA9IHZhbHVlLnNsaWNlKDEpO1xyXG4gICAgICAgIH1cclxuICAgICAgICBpZiAodmFsdWUuZW5kc1dpdGgoJ10nKSkge1xyXG4gICAgICAgICAgdmFsdWUgPSB2YWx1ZS5zbGljZSgwLCAtMSk7XHJcbiAgICAgICAgfVxyXG4gICAgICAgIHJldHVybiB2YWx1ZS5zcGxpdChzZXBhcmF0b3IpO1xyXG4gICAgICB9KTtcclxuXHJcbiAgICBjb25zdCB0cmFuc2Zvcm1DYWxsYmFjayA9ICh2YWx1ZSkgPT5cclxuICAgICAgdmFsdWUubWFwKCh2YWx1ZSkgPT4gdmFsdWUudHJpbSgpKS5maWx0ZXIoZmlsdGVyQ2FsbGJhY2spO1xyXG5cclxuICAgIHJldHVybiBzdHJpY3RDaGVja1xyXG4gICAgICA/IGFycmF5U2NoZW1hLnRyYW5zZm9ybSh0cmFuc2Zvcm1DYWxsYmFjaylcclxuICAgICAgOiB6XHJcbiAgICAgICAgICAudW5pb24oW3N0cmluZ1NjaGVtYSwgYXJyYXlTY2hlbWFdKVxyXG4gICAgICAgICAgLnRyYW5zZm9ybSh0cmFuc2Zvcm1DYWxsYmFjaylcclxuICAgICAgICAgIC50cmFuc2Zvcm0oKHZhbHVlKSA9PiAodmFsdWUubGVuZ3RoID8gdmFsdWUgOiBudWxsKSlcclxuICAgICAgICAgIC5udWxsYWJsZSgpO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgcG9zaXRpdmVOdW1gIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGggYW4gb3B0aW9uYWxcclxuICAgKiBzdHJpY3RlciBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGF0OlxyXG4gICAqXHJcbiAgICogLSBXaGVuIGBzdHJpY3RDaGVja2AgaXMgdHJ1ZSwgdGhlIHNjaGVtYSB3aWxsIGFjY2VwdCBwb3NpdGl2ZSBudW1iZXIgdmFsdWVzXHJcbiAgICogYW5kIHZhbGlkYXRlIGFnYWluc3QgdGhlIGRlZmF1bHQgcG9zaXRpdmUgbnVtYmVyIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIC0gV2hlbiBgc3RyaWN0Q2hlY2tgIGlzIGZhbHNlLCB0aGUgc2NoZW1hIHdpbGwgYWNjZXB0IHBvc2l0aXZlIG51bWJlclxyXG4gICAqIHZhbHVlcywgbnVsbCwgYW5kIHRyaW1tZWQgc3RyaW5nIHZhbHVlcyB0aGF0IGNhbiBlaXRoZXIgYmUgJ3VuZGVmaW5lZCcsXHJcbiAgICogJ251bGwnLCAnJywgb3IgcmVwcmVzZW50IGEgcG9zaXRpdmUgbnVtYmVyLiBJdCB3aWxsIHRyYW5zZm9ybSB0aGUgc3RyaW5nXHJcbiAgICogdG8gYSBwb3NpdGl2ZSBudW1iZXIsIG9yIHRvIG51bGwgaWYgaXQgaXMgJ3VuZGVmaW5lZCcsICdudWxsJywgb3IgJycuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gcG9zaXRpdmVOdW1cclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZyBwb3NpdGl2ZSBudW1iZXJcclxuICAgKiB2YWx1ZXMuXHJcbiAgICovXHJcbiAgcG9zaXRpdmVOdW0oc3RyaWN0Q2hlY2spIHtcclxuICAgIHJldHVybiBzdHJpY3RDaGVja1xyXG4gICAgICA/IHoubnVtYmVyKCkucG9zaXRpdmUoKVxyXG4gICAgICA6IHpcclxuICAgICAgICAgIC51bmlvbihbXHJcbiAgICAgICAgICAgIHpcclxuICAgICAgICAgICAgICAuc3RyaW5nKClcclxuICAgICAgICAgICAgICAudHJpbSgpXHJcbiAgICAgICAgICAgICAgLnJlZmluZShcclxuICAgICAgICAgICAgICAgICh2YWx1ZSkgPT5cclxuICAgICAgICAgICAgICAgICAgKCFpc05hTihOdW1iZXIodmFsdWUpKSAmJiBOdW1iZXIodmFsdWUpID4gMCkgfHxcclxuICAgICAgICAgICAgICAgICAgWyd1bmRlZmluZWQnLCAnbnVsbCcsICcnXS5pbmNsdWRlcyh2YWx1ZSksXHJcbiAgICAgICAgICAgICAgICB7XHJcbiAgICAgICAgICAgICAgICAgIHBhcmFtczoge1xyXG4gICAgICAgICAgICAgICAgICAgIGVycm9yTWVzc2FnZTogYFRoZSB2YWx1ZSBtdXN0IGJlIG51bWVyaWMgYW5kIHBvc2l0aXZlYFxyXG4gICAgICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgICAgKVxyXG4gICAgICAgICAgICAgIC50cmFuc2Zvcm0oKHZhbHVlKSA9PlxyXG4gICAgICAgICAgICAgICAgIVsndW5kZWZpbmVkJywgJ251bGwnLCAnJ10uaW5jbHVkZXModmFsdWUpXHJcbiAgICAgICAgICAgICAgICAgID8gTnVtYmVyKHZhbHVlKVxyXG4gICAgICAgICAgICAgICAgICA6IG51bGxcclxuICAgICAgICAgICAgICApLFxyXG4gICAgICAgICAgICB6Lm51bWJlcigpLnBvc2l0aXZlKClcclxuICAgICAgICAgIF0pXHJcbiAgICAgICAgICAubnVsbGFibGUoKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYG5vbk5lZ2F0aXZlTnVtYCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoIGFuIG9wdGlvbmFsXHJcbiAgICogc3RyaWN0ZXIgY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhhdDpcclxuICAgKlxyXG4gICAqIC0gV2hlbiBgc3RyaWN0Q2hlY2tgIGlzIHRydWUsIHRoZSBzY2hlbWEgd2lsbCBhY2NlcHQgbm9uLW5lZ2F0aXZlIG51bWJlclxyXG4gICAqIHZhbHVlcyBhbmQgdmFsaWRhdGUgYWdhaW5zdCB0aGUgZGVmYXVsdCBub24tbmVnYXRpdmUgbnVtYmVyIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIC0gV2hlbiBgc3RyaWN0Q2hlY2tgIGlzIGZhbHNlLCB0aGUgc2NoZW1hIHdpbGwgYWNjZXB0IG5vbi1uZWdhdGl2ZSBudW1iZXJcclxuICAgKiB2YWx1ZXMsIG51bGwsIGFuZCB0cmltbWVkIHN0cmluZyB2YWx1ZXMgdGhhdCBjYW4gZWl0aGVyIGJlICd1bmRlZmluZWQnLFxyXG4gICAqICdudWxsJywgJycsIG9yIHJlcHJlc2VudCBhIG5vbi1uZWdhdGl2ZSBudW1iZXIuIEl0IHdpbGwgdHJhbnNmb3JtXHJcbiAgICogdGhlIHN0cmluZyB0byBhIG5vbi1uZWdhdGl2ZSBudW1iZXIsIG9yIHRvIG51bGwgaWYgaXQgaXMgJ3VuZGVmaW5lZCcsXHJcbiAgICogJ251bGwnLCBvciAnJy5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiBub25OZWdhdGl2ZU51bVxyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nIG5vbi1uZWdhdGl2ZVxyXG4gICAqIG51bWJlciB2YWx1ZXMuXHJcbiAgICovXHJcbiAgbm9uTmVnYXRpdmVOdW0oc3RyaWN0Q2hlY2spIHtcclxuICAgIHJldHVybiBzdHJpY3RDaGVja1xyXG4gICAgICA/IHoubnVtYmVyKCkubm9ubmVnYXRpdmUoKVxyXG4gICAgICA6IHpcclxuICAgICAgICAgIC51bmlvbihbXHJcbiAgICAgICAgICAgIHpcclxuICAgICAgICAgICAgICAuc3RyaW5nKClcclxuICAgICAgICAgICAgICAudHJpbSgpXHJcbiAgICAgICAgICAgICAgLnJlZmluZShcclxuICAgICAgICAgICAgICAgICh2YWx1ZSkgPT5cclxuICAgICAgICAgICAgICAgICAgKCFpc05hTihOdW1iZXIodmFsdWUpKSAmJiBOdW1iZXIodmFsdWUpID49IDApIHx8XHJcbiAgICAgICAgICAgICAgICAgIFsndW5kZWZpbmVkJywgJ251bGwnLCAnJ10uaW5jbHVkZXModmFsdWUpLFxyXG4gICAgICAgICAgICAgICAge1xyXG4gICAgICAgICAgICAgICAgICBwYXJhbXM6IHtcclxuICAgICAgICAgICAgICAgICAgICBlcnJvck1lc3NhZ2U6IGBUaGUgdmFsdWUgbXVzdCBiZSBudW1lcmljIGFuZCBub24tbmVnYXRpdmVgXHJcbiAgICAgICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgICApXHJcbiAgICAgICAgICAgICAgLnRyYW5zZm9ybSgodmFsdWUpID0+XHJcbiAgICAgICAgICAgICAgICAhWyd1bmRlZmluZWQnLCAnbnVsbCcsICcnXS5pbmNsdWRlcyh2YWx1ZSlcclxuICAgICAgICAgICAgICAgICAgPyBOdW1iZXIodmFsdWUpXHJcbiAgICAgICAgICAgICAgICAgIDogbnVsbFxyXG4gICAgICAgICAgICAgICksXHJcbiAgICAgICAgICAgIHoubnVtYmVyKCkubm9ubmVnYXRpdmUoKVxyXG4gICAgICAgICAgXSlcclxuICAgICAgICAgIC5udWxsYWJsZSgpO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgc3RhcnRzV2l0aGAgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbFxyXG4gICAqIHN0cmljdGVyIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSBzY2hlbWEgd2lsbCB2YWxpZGF0ZSBhZ2FpbnN0IHRoZSBwcm92aWRlZCBgcHJlZml4ZXNgIGFycmF5IHRvIGNoZWNrXHJcbiAgICogd2hldGhlciBhIHN0cmluZyB2YWx1ZSBzdGFydHMgd2l0aCBhbnkgb2YgdGhlIHZhbHVlcyBwcm92aWRlZFxyXG4gICAqIGluIHRoZSBgcHJlZml4ZXNgIGFycmF5LlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhhdDpcclxuICAgKlxyXG4gICAqIC0gV2hlbiBgc3RyaWN0Q2hlY2tgIGlzIHRydWUsIHRoZSBzY2hlbWEgd2lsbCBhY2NlcHQgdHJpbW1lZCBzdHJpbmcgdmFsdWVzXHJcbiAgICogdGhhdCBzdGFydCB3aXRoIHZhbHVlcyBmcm9tIHRoZSBwcmVmaXhlcyBhcnJheS5cclxuICAgKlxyXG4gICAqIC0gV2hlbiBgc3RyaWN0Q2hlY2tgIGlzIGZhbHNlLCB0aGUgc2NoZW1hIHdpbGwgYWNjZXB0IHRyaW1tZWQgc3RyaW5nIHZhbHVlc1xyXG4gICAqIHRoYXQgc3RhcnQgd2l0aCB2YWx1ZXMgZnJvbSB0aGUgcHJlZml4ZXMgYXJyYXksIG51bGwsICd1bmRlZmluZWQnLCAnbnVsbCcsXHJcbiAgICogYW5kICcnIHdoZXJlIHRoZSBzY2hlbWEgd2lsbCB0cmFuc2Zvcm0gdGhlbSB0byBudWxsLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIHN0YXJ0c1dpdGhcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7QXJyYXkuPHN0cmluZz59IHByZWZpeGVzIC0gQW4gYXJyYXkgb2YgcHJlZml4ZXMgdG8gdmFsaWRhdGVcclxuICAgKiB0aGUgc3RyaW5nIGFnYWluc3QuXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nIHN0cmluZ3MgdGhhdFxyXG4gICAqIHN0YXJ0cyB3aXRoIHZhbHVlcy5cclxuICAgKi9cclxuICBzdGFydHNXaXRoKHByZWZpeGVzLCBzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHN0cmljdENoZWNrXHJcbiAgICAgID8gelxyXG4gICAgICAgICAgLnN0cmluZygpXHJcbiAgICAgICAgICAudHJpbSgpXHJcbiAgICAgICAgICAucmVmaW5lKFxyXG4gICAgICAgICAgICAodmFsdWUpID0+IHByZWZpeGVzLnNvbWUoKHByZWZpeCkgPT4gdmFsdWUuc3RhcnRzV2l0aChwcmVmaXgpKSxcclxuICAgICAgICAgICAge1xyXG4gICAgICAgICAgICAgIHBhcmFtczoge1xyXG4gICAgICAgICAgICAgICAgZXJyb3JNZXNzYWdlOiBgVGhlIHZhbHVlIG11c3QgYmUgYSBzdHJpbmcgdGhhdCBzdGFydHMgd2l0aCAke3ByZWZpeGVzLmpvaW4oJywgJyl9YFxyXG4gICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgfVxyXG4gICAgICAgICAgKVxyXG4gICAgICA6IHpcclxuICAgICAgICAgIC5zdHJpbmcoKVxyXG4gICAgICAgICAgLnRyaW0oKVxyXG4gICAgICAgICAgLnJlZmluZShcclxuICAgICAgICAgICAgKHZhbHVlKSA9PlxyXG4gICAgICAgICAgICAgIHByZWZpeGVzLnNvbWUoKHByZWZpeCkgPT4gdmFsdWUuc3RhcnRzV2l0aChwcmVmaXgpKSB8fFxyXG4gICAgICAgICAgICAgIFsndW5kZWZpbmVkJywgJ251bGwnLCAnJ10uaW5jbHVkZXModmFsdWUpLFxyXG4gICAgICAgICAgICB7XHJcbiAgICAgICAgICAgICAgcGFyYW1zOiB7XHJcbiAgICAgICAgICAgICAgICBlcnJvck1lc3NhZ2U6IGBUaGUgdmFsdWUgbXVzdCBiZSBhIHN0cmluZyB0aGF0IHN0YXJ0cyB3aXRoICR7cHJlZml4ZXMuam9pbignLCAnKX1gXHJcbiAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICB9XHJcbiAgICAgICAgICApXHJcbiAgICAgICAgICAudHJhbnNmb3JtKCh2YWx1ZSkgPT5cclxuICAgICAgICAgICAgIVsndW5kZWZpbmVkJywgJ251bGwnLCAnJ10uaW5jbHVkZXModmFsdWUpID8gdmFsdWUgOiBudWxsXHJcbiAgICAgICAgICApXHJcbiAgICAgICAgICAubnVsbGFibGUoKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYGNoYXJ0Q29uZmlnYCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYS5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoYXQgdGhlIHNjaGVtYSB3aWxsIGFjY2VwdCBvYmplY3QgdmFsdWVzXHJcbiAgICogb3IgdHJpbW1lZCBzdHJpbmcgdmFsdWVzIHRoYXQgY29udGFpbiAnPHN2Zycgb3IgJzw/eG1sJyBlbGVtZW50cywgc3RhcnRcclxuICAgKiB3aXRoIHRoZSAneycgYW5kIGVuZCB3aXRoIHRoZSAnfScsIGFuZCBudWxsLiBUaGUgJ3VuZGVmaW5lZCcsICdudWxsJyxcclxuICAgKiBhbmQgJycgdmFsdWVzIHdpbGwgYmUgdHJhbnNmb3JtZWQgdG8gbnVsbC5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiBjaGFydENvbmZpZ1xyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nIGNoYXJ0XHJcbiAgICogY29uZmlndXJhdGlvbiB2YWx1ZS5cclxuICAgKi9cclxuICBjaGFydENvbmZpZygpIHtcclxuICAgIHJldHVybiB6XHJcbiAgICAgIC51bmlvbihbXHJcbiAgICAgICAgelxyXG4gICAgICAgICAgLnN0cmluZygpXHJcbiAgICAgICAgICAudHJpbSgpXHJcbiAgICAgICAgICAucmVmaW5lKFxyXG4gICAgICAgICAgICAodmFsdWUpID0+XHJcbiAgICAgICAgICAgICAgdmFsdWUuaW5kZXhPZignPHN2ZycpID49IDAgfHxcclxuICAgICAgICAgICAgICB2YWx1ZS5pbmRleE9mKCc8P3htbCcpID49IDAgfHxcclxuICAgICAgICAgICAgICAodmFsdWUuc3RhcnRzV2l0aCgneycpICYmIHZhbHVlLmVuZHNXaXRoKCd9JykpIHx8XHJcbiAgICAgICAgICAgICAgWyd1bmRlZmluZWQnLCAnbnVsbCcsICcnXS5pbmNsdWRlcyh2YWx1ZSksXHJcbiAgICAgICAgICAgIHtcclxuICAgICAgICAgICAgICBwYXJhbXM6IHtcclxuICAgICAgICAgICAgICAgIGVycm9yTWVzc2FnZTogYFRoZSB2YWx1ZSBtdXN0IGJlIGEgc3RyaW5nIHRoYXQgY29udGFpbnMgJzxzdmcnIG9yICc8P3htbCcgb3Igc3RhcnRzIHdpdGggJ3snIGFuZCBlbmRzIHdpdGggJ30nYFxyXG4gICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgfVxyXG4gICAgICAgICAgKVxyXG4gICAgICAgICAgLnRyYW5zZm9ybSgodmFsdWUpID0+XHJcbiAgICAgICAgICAgICFbJ3VuZGVmaW5lZCcsICdudWxsJywgJyddLmluY2x1ZGVzKHZhbHVlKSA/IHZhbHVlIDogbnVsbFxyXG4gICAgICAgICAgKSxcclxuICAgICAgICB6Lm9iamVjdCh7fSkucGFzc3Rocm91Z2goKVxyXG4gICAgICBdKVxyXG4gICAgICAubnVsbGFibGUoKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYGFkZGl0aW9uYWxPcHRpb25zYCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYS5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoYXQgdGhlIHNjaGVtYSB3aWxsIGFjY2VwdCBvYmplY3QgdmFsdWVzXHJcbiAgICogb3IgdHJpbW1lZCBzdHJpbmcgdmFsdWVzIHRoYXQgZW5kIHdpdGggJy5qc29uJyBhbmQgYXJlIGF0IGxlYXN0IG9uZVxyXG4gICAqIGNoYXJhY3RlciBsb25nIGV4Y2x1ZGluZyB0aGUgZXh0ZW5zaW9uLCBzdGFydCB3aXRoIHRoZSAneycgYW5kIGVuZFxyXG4gICAqIHdpdGggdGhlICd9JywgYW5kIG51bGwuIFRoZSAndW5kZWZpbmVkJywgJ251bGwnLCBhbmQgJycgdmFsdWVzIHdpbGxcclxuICAgKiBiZSB0cmFuc2Zvcm1lZCB0byBudWxsLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIGFkZGl0aW9uYWxPcHRpb25zXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9ICBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nIGFkZGl0aW9uYWwgY2hhcnRcclxuICAgKiBvcHRpb25zIHZhbHVlLlxyXG4gICAqL1xyXG4gIGFkZGl0aW9uYWxPcHRpb25zKCkge1xyXG4gICAgcmV0dXJuIHpcclxuICAgICAgLnVuaW9uKFtcclxuICAgICAgICB6XHJcbiAgICAgICAgICAuc3RyaW5nKClcclxuICAgICAgICAgIC50cmltKClcclxuICAgICAgICAgIC5yZWZpbmUoXHJcbiAgICAgICAgICAgICh2YWx1ZSkgPT5cclxuICAgICAgICAgICAgICAodmFsdWUubGVuZ3RoID49IDYgJiYgdmFsdWUuZW5kc1dpdGgoJy5qc29uJykpIHx8XHJcbiAgICAgICAgICAgICAgKHZhbHVlLnN0YXJ0c1dpdGgoJ3snKSAmJiB2YWx1ZS5lbmRzV2l0aCgnfScpKSB8fFxyXG4gICAgICAgICAgICAgIFsndW5kZWZpbmVkJywgJ251bGwnLCAnJ10uaW5jbHVkZXModmFsdWUpLFxyXG4gICAgICAgICAgICB7XHJcbiAgICAgICAgICAgICAgcGFyYW1zOiB7XHJcbiAgICAgICAgICAgICAgICBlcnJvck1lc3NhZ2U6IGBUaGUgdmFsdWUgbXVzdCBiZSBhIHN0cmluZyB0aGF0IGVuZHMgd2l0aCAnLmpzb24nIG9yIHN0YXJ0cyB3aXRoICd7JyBhbmQgZW5kcyB3aXRoICd9J2BcclxuICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgIH1cclxuICAgICAgICAgIClcclxuICAgICAgICAgIC50cmFuc2Zvcm0oKHZhbHVlKSA9PlxyXG4gICAgICAgICAgICAhWyd1bmRlZmluZWQnLCAnbnVsbCcsICcnXS5pbmNsdWRlcyh2YWx1ZSkgPyB2YWx1ZSA6IG51bGxcclxuICAgICAgICAgICksXHJcbiAgICAgICAgei5vYmplY3Qoe30pLnBhc3N0aHJvdWdoKClcclxuICAgICAgXSlcclxuICAgICAgLm51bGxhYmxlKCk7XHJcbiAgfVxyXG59O1xyXG5cclxuLyoqXHJcbiAqIE9iamVjdCBjb250YWluaW5nIGN1c3RvbSBjb25maWcgdmFsaWRhdG9ycyBhbmQgcGFyc2VycyB0byBhdm9pZCByZXBldGl0aW9uXHJcbiAqIGluIHNjaGVtYSBvYmplY3RzLiBBbGwgdmFsaWRhdG9ycyBhcHBseSB0byB2YWx1ZXMgZnJvbSB2YXJpb3VzIHNvdXJjZXMsXHJcbiAqIGluY2x1ZGluZyB0aGUgZGVmYXVsdCBjb25maWcgZmlsZSwgYSBjdXN0b20gSlNPTiBmaWxlIGxvYWRlZCB3aXRoIHRoZSBvcHRpb25cclxuICogY2FsbGVkIGBsb2FkQ29uZmlnYCwgdGhlIC5lbnYgZmlsZSwgQ0xJIGFyZ3VtZW50cywgYW5kIHRoZSByZXF1ZXN0IHBheWxvYWQuXHJcbiAqIFRoZSBgc3RyaWN0Q2hlY2tgIGZsYWcgZW5hYmxlcyBzdHJpY3RlciB2YWxpZGF0aW9uIGFuZCBwYXJzaW5nIHJ1bGVzLiBUaGlzXHJcbiAqIGZsYWcgaXMgc2V0IHRvIGZhbHNlIGZvciB2YWx1ZXMgdGhhdCBjb21lIGZyb20gdGhlIC5lbnYgZmlsZSBvciBDTEkgYXJndW1lbnRzXHJcbiAqIGJlY2F1c2UgdGhleSBhcmUgcHJvdmlkZWQgYXMgc3RyaW5ncyBhbmQgbmVlZCB0byBiZSBwYXJzZWQgYWNjb3JkaW5nbHkgZmlyc3QuXHJcbiAqL1xyXG5jb25zdCBjb25maWcgPSB7XHJcbiAgLyoqXHJcbiAgICogVGhlIGBhcmdzYCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoIGFuIG9wdGlvbmFsIHN0cmljdGVyXHJcbiAgICogY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhlIHNhbWUgd29yayBhcyB0aGUgYHN0cmluZ0FycmF5YCB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gYXJnc1xyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nIHRoZSBgYXJnc2BcclxuICAgKiBvcHRpb24uXHJcbiAgICovXHJcbiAgYXJncyhzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHYuc3RyaW5nQXJyYXkoXHJcbiAgICAgICh2YWx1ZSkgPT4gIVsnZmFsc2UnLCAndW5kZWZpbmVkJywgJ251bGwnLCAnJ10uaW5jbHVkZXModmFsdWUpLFxyXG4gICAgICAnOycsXHJcbiAgICAgIHN0cmljdENoZWNrXHJcbiAgICApO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgdmVyc2lvbmAgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbCBzdHJpY3RlclxyXG4gICAqIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoYXQ6XHJcbiAgICpcclxuICAgKiAtIFdoZW4gYHN0cmljdENoZWNrYCBpcyB0cnVlLCB0aGUgc2NoZW1hIHdpbGwgYWNjZXB0IHRyaW1tZWQgc3RyaW5nIHZhbHVlc1xyXG4gICAqIHRoYXQgYXJlIGEgUmVnRXhwLWJhc2VkIHRoYXQgYWxsb3dzIHRvIGJlICdsYXRlc3QnLCBvciBpbiB0aGUgZm9ybWF0IFhYLFxyXG4gICAqIFhYLllZLCBvciBYWC5ZWS5aWiwgd2hlcmUgWFgsIFlZLCBhbmQgWlogYXJlIG51bWVyaWMgZm9yIHRoZSBIaWdoY2hhcnRzXHJcbiAgICogdmVyc2lvbiBvcHRpb24uXHJcbiAgICpcclxuICAgKiAtIFdoZW4gYHN0cmljdENoZWNrYCBpcyBmYWxzZSwgdGhlIHNjaGVtYSB3aWxsIGFjY2VwdCBhbHNvIG51bGwsXHJcbiAgICogJ3VuZGVmaW5lZCcsICdudWxsJywgb3IgJycgYW5kIGluIGFsbCBjYXNlcyB0aGUgc2NoZW1hIHdpbGwgdHJhbnNmb3JtIHRoZW1cclxuICAgKiB0byBudWxsLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIHZlcnNpb25cclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZyB0aGUgYHZlcnNpb25gXHJcbiAgICogb3B0aW9uLlxyXG4gICAqL1xyXG4gIHZlcnNpb24oc3RyaWN0Q2hlY2spIHtcclxuICAgIHJldHVybiBzdHJpY3RDaGVja1xyXG4gICAgICA/IHpcclxuICAgICAgICAgIC5zdHJpbmcoKVxyXG4gICAgICAgICAgLnRyaW0oKVxyXG4gICAgICAgICAgLnJlZmluZSgodmFsdWUpID0+IC9eKGxhdGVzdHxcXGR7MSwyfShcXC5cXGR7MSwyfSl7MCwyfSkkLy50ZXN0KHZhbHVlKSwge1xyXG4gICAgICAgICAgICBwYXJhbXM6IHtcclxuICAgICAgICAgICAgICBlcnJvck1lc3NhZ2U6XHJcbiAgICAgICAgICAgICAgICBcIlRoZSB2YWx1ZSBtdXN0IGJlICdsYXRlc3QnLCBhIG1ham9yIHZlcnNpb24sIG9yIGluIHRoZSBmb3JtIFhYLllZLlpaXCJcclxuICAgICAgICAgICAgfVxyXG4gICAgICAgICAgfSlcclxuICAgICAgOiB6XHJcbiAgICAgICAgICAuc3RyaW5nKClcclxuICAgICAgICAgIC50cmltKClcclxuICAgICAgICAgIC5yZWZpbmUoXHJcbiAgICAgICAgICAgICh2YWx1ZSkgPT5cclxuICAgICAgICAgICAgICAvXihsYXRlc3R8XFxkezEsMn0oXFwuXFxkezEsMn0pezAsMn0pJC8udGVzdCh2YWx1ZSkgfHxcclxuICAgICAgICAgICAgICBbJ3VuZGVmaW5lZCcsICdudWxsJywgJyddLmluY2x1ZGVzKHZhbHVlKSxcclxuICAgICAgICAgICAge1xyXG4gICAgICAgICAgICAgIHBhcmFtczoge1xyXG4gICAgICAgICAgICAgICAgZXJyb3JNZXNzYWdlOlxyXG4gICAgICAgICAgICAgICAgICBcIlRoZSB2YWx1ZSBtdXN0IGJlICdsYXRlc3QnLCBhIG1ham9yIHZlcnNpb24sIG9yIGluIHRoZSBmb3JtIFhYLllZLlpaXCJcclxuICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgIH1cclxuICAgICAgICAgIClcclxuICAgICAgICAgIC50cmFuc2Zvcm0oKHZhbHVlKSA9PlxyXG4gICAgICAgICAgICAhWyd1bmRlZmluZWQnLCAnbnVsbCcsICcnXS5pbmNsdWRlcyh2YWx1ZSkgPyB2YWx1ZSA6IG51bGxcclxuICAgICAgICAgIClcclxuICAgICAgICAgIC5udWxsYWJsZSgpO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgY2RuVXJsYCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoIGFuIG9wdGlvbmFsIHN0cmljdGVyXHJcbiAgICogY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhlIHNhbWUgd29yayBhcyB0aGUgYHN0YXJ0c1dpdGhgIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiBjZG5VcmxcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZyB0aGUgYGNkblVybGBcclxuICAgKiBvcHRpb24uXHJcbiAgICovXHJcbiAgY2RuVXJsKHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gdi5zdGFydHNXaXRoKFsnaHR0cDovLycsICdodHRwczovLyddLCBzdHJpY3RDaGVjayk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGBmb3JjZUZldGNoYCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoIGFuIG9wdGlvbmFsXHJcbiAgICogc3RyaWN0ZXIgY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhlIHNhbWUgd29yayBhcyB0aGUgYGJvb2xlYW5gIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiBmb3JjZUZldGNoXHJcbiAgICpcclxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IHN0cmljdENoZWNrIC0gRGV0ZXJtaW5lcyBpZiBzdHJpY3RlciB2YWxpZGF0aW9uIHNob3VsZFxyXG4gICAqIGJlIGFwcGxpZWQuXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9IEEgWm9kIHNjaGVtYSBvYmplY3QgZm9yIHZhbGlkYXRpbmcgdGhlIGBmb3JjZUZldGNoYFxyXG4gICAqIG9wdGlvbi5cclxuICAgKi9cclxuICBmb3JjZUZldGNoKHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gdi5ib29sZWFuKHN0cmljdENoZWNrKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYGNhY2hlUGF0aGAgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbFxyXG4gICAqIHN0cmljdGVyIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgdGhlIGBzdHJpbmdgIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiBjYWNoZVBhdGhcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZyB0aGUgYGNhY2hlUGF0aGBcclxuICAgKiBvcHRpb24uXHJcbiAgICovXHJcbiAgY2FjaGVQYXRoKHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gdi5zdHJpbmcoc3RyaWN0Q2hlY2spO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgYWRtaW5Ub2tlbmAgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbFxyXG4gICAqIHN0cmljdGVyIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgdGhlIGBzdHJpbmdgIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiBhZG1pblRva2VuXHJcbiAgICpcclxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IHN0cmljdENoZWNrIC0gRGV0ZXJtaW5lcyBpZiBzdHJpY3RlciB2YWxpZGF0aW9uIHNob3VsZFxyXG4gICAqIGJlIGFwcGxpZWQuXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9IEEgWm9kIHNjaGVtYSBvYmplY3QgZm9yIHZhbGlkYXRpbmcgdGhlIGBhZG1pblRva2VuYFxyXG4gICAqIG9wdGlvbi5cclxuICAgKi9cclxuICBhZG1pblRva2VuKHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gdi5zdHJpbmcoc3RyaWN0Q2hlY2spO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgY29yZVNjcmlwdHNgIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGggYW4gb3B0aW9uYWxcclxuICAgKiBzdHJpY3RlciBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGUgc2FtZSB3b3JrIGFzIHRoZSBgc3RyaW5nQXJyYXlgIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiBjb3JlU2NyaXB0c1xyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nIHRoZSBgY29yZVNjcmlwdHNgXHJcbiAgICogb3B0aW9uLlxyXG4gICAqL1xyXG4gIGNvcmVTY3JpcHRzKHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gdi5zdHJpbmdBcnJheShcclxuICAgICAgKHZhbHVlKSA9PiBjb3JlU2NyaXB0cy52YWx1ZS5pbmNsdWRlcyh2YWx1ZSksXHJcbiAgICAgICcsJyxcclxuICAgICAgc3RyaWN0Q2hlY2tcclxuICAgICk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGBtb2R1bGVTY3JpcHRzYCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoIGFuIG9wdGlvbmFsXHJcbiAgICogc3RyaWN0ZXIgY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhlIHNhbWUgd29yayBhcyB0aGUgYHN0cmluZ0FycmF5YCB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gbW9kdWxlU2NyaXB0c1xyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nXHJcbiAgICogdGhlIGBtb2R1bGVTY3JpcHRzYCBvcHRpb24uXHJcbiAgICovXHJcbiAgbW9kdWxlU2NyaXB0cyhzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHYuc3RyaW5nQXJyYXkoXHJcbiAgICAgICh2YWx1ZSkgPT4gbW9kdWxlU2NyaXB0cy52YWx1ZS5pbmNsdWRlcyh2YWx1ZSksXHJcbiAgICAgICcsJyxcclxuICAgICAgc3RyaWN0Q2hlY2tcclxuICAgICk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGBpbmRpY2F0b3JTY3JpcHRzYCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoIGFuIG9wdGlvbmFsXHJcbiAgICogc3RyaWN0ZXIgY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhlIHNhbWUgd29yayBhcyB0aGUgYHN0cmluZ0FycmF5YCB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gaW5kaWNhdG9yU2NyaXB0c1xyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nXHJcbiAgICogdGhlIGBpbmRpY2F0b3JTY3JpcHRzYCBvcHRpb24uXHJcbiAgICovXHJcbiAgaW5kaWNhdG9yU2NyaXB0cyhzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHYuc3RyaW5nQXJyYXkoXHJcbiAgICAgICh2YWx1ZSkgPT4gaW5kaWNhdG9yU2NyaXB0cy52YWx1ZS5pbmNsdWRlcyh2YWx1ZSksXHJcbiAgICAgICcsJyxcclxuICAgICAgc3RyaWN0Q2hlY2tcclxuICAgICk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGBjdXN0b21TY3JpcHRzYCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoIGFuIG9wdGlvbmFsXHJcbiAgICogc3RyaWN0ZXIgY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhlIHNhbWUgd29yayBhcyB0aGUgYHN0cmluZ0FycmF5YCB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gY3VzdG9tU2NyaXB0c1xyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nXHJcbiAgICogdGhlIGBjdXN0b21TY3JpcHRzYCBvcHRpb24uXHJcbiAgICovXHJcbiAgY3VzdG9tU2NyaXB0cyhzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHYuc3RyaW5nQXJyYXkoXHJcbiAgICAgICh2YWx1ZSkgPT4gdmFsdWUuc3RhcnRzV2l0aCgnaHR0cHM6Ly8nKSB8fCB2YWx1ZS5zdGFydHNXaXRoKCdodHRwOi8vJyksXHJcbiAgICAgICcsJyxcclxuICAgICAgc3RyaWN0Q2hlY2tcclxuICAgICk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGBpbmZpbGVgIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGggYW4gb3B0aW9uYWwgc3RyaWN0ZXJcclxuICAgKiBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGF0OlxyXG4gICAqXHJcbiAgICogLSBXaGVuIGBzdHJpY3RDaGVja2AgaXMgdHJ1ZSwgdGhlIHNjaGVtYSB3aWxsIGFjY2VwdCB0cmltbWVkIHN0cmluZyB2YWx1ZXNcclxuICAgKiB0aGF0IGVuZCB3aXRoICcuanNvbicgb3IgJy5zdmcnLCBhcmUgYXQgbGVhc3Qgb25lIGNoYXJhY3RlciBsb25nIGV4Y2x1ZGluZ1xyXG4gICAqIHRoZSBleHRlbnNpb24sIG9yIG51bGwuXHJcbiAgICpcclxuICAgKiAtIFdoZW4gYHN0cmljdENoZWNrYCBpcyBmYWxzZSwgdGhlIHNjaGVtYSB3aWxsIGFjY2VwdCB0cmltbWVkIHN0cmluZyB2YWx1ZXNcclxuICAgKiB0aGF0IGVuZCB3aXRoICcuanNvbicgb3IgJy5zdmcnLCBhcmUgYXQgbGVhc3Qgb25lIGNoYXJhY3RlciBsb25nIGV4Y2x1ZGluZ1xyXG4gICAqIHRoZSBleHRlbnNpb24gYW5kIHdpbGwgYmUgbnVsbCBpZiB0aGUgcHJvdmlkZWQgdmFsdWUgaXMgbnVsbCwgJ3VuZGVmaW5lZCcsXHJcbiAgICogJ251bGwnLCBvciAnJy5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiBpbmZpbGVcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZyB0aGUgYGluZmlsZWBcclxuICAgKiBvcHRpb24uXHJcbiAgICovXHJcbiAgaW5maWxlKHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gc3RyaWN0Q2hlY2tcclxuICAgICAgPyB6XHJcbiAgICAgICAgICAuc3RyaW5nKClcclxuICAgICAgICAgIC50cmltKClcclxuICAgICAgICAgIC5yZWZpbmUoXHJcbiAgICAgICAgICAgICh2YWx1ZSkgPT5cclxuICAgICAgICAgICAgICAodmFsdWUubGVuZ3RoID49IDYgJiYgdmFsdWUuZW5kc1dpdGgoJy5qc29uJykpIHx8XHJcbiAgICAgICAgICAgICAgKHZhbHVlLmxlbmd0aCA+PSA1ICYmIHZhbHVlLmVuZHNXaXRoKCcuc3ZnJykpLFxyXG4gICAgICAgICAgICB7XHJcbiAgICAgICAgICAgICAgcGFyYW1zOiB7XHJcbiAgICAgICAgICAgICAgICBlcnJvck1lc3NhZ2U6IGBUaGUgdmFsdWUgbXVzdCBiZSBhIHN0cmluZyB0aGF0IGVuZHMgd2l0aCAuanNvbiBvciAuc3ZnYFxyXG4gICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgfVxyXG4gICAgICAgICAgKVxyXG4gICAgICAgICAgLm51bGxhYmxlKClcclxuICAgICAgOiB6XHJcbiAgICAgICAgICAuc3RyaW5nKClcclxuICAgICAgICAgIC50cmltKClcclxuICAgICAgICAgIC5yZWZpbmUoXHJcbiAgICAgICAgICAgICh2YWx1ZSkgPT5cclxuICAgICAgICAgICAgICAodmFsdWUubGVuZ3RoID49IDYgJiYgdmFsdWUuZW5kc1dpdGgoJy5qc29uJykpIHx8XHJcbiAgICAgICAgICAgICAgKHZhbHVlLmxlbmd0aCA+PSA1ICYmIHZhbHVlLmVuZHNXaXRoKCcuc3ZnJykpIHx8XHJcbiAgICAgICAgICAgICAgWyd1bmRlZmluZWQnLCAnbnVsbCcsICcnXS5pbmNsdWRlcyh2YWx1ZSksXHJcbiAgICAgICAgICAgIHtcclxuICAgICAgICAgICAgICBwYXJhbXM6IHtcclxuICAgICAgICAgICAgICAgIGVycm9yTWVzc2FnZTogYFRoZSB2YWx1ZSBtdXN0IGJlIGEgc3RyaW5nIHRoYXQgZW5kcyB3aXRoIC5qc29uIG9yIC5zdmdgXHJcbiAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICB9XHJcbiAgICAgICAgICApXHJcbiAgICAgICAgICAudHJhbnNmb3JtKCh2YWx1ZSkgPT5cclxuICAgICAgICAgICAgIVsndW5kZWZpbmVkJywgJ251bGwnLCAnJ10uaW5jbHVkZXModmFsdWUpID8gdmFsdWUgOiBudWxsXHJcbiAgICAgICAgICApXHJcbiAgICAgICAgICAubnVsbGFibGUoKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYGluc3RyYCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYS5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgdGhlIGBvcHRpb25zYCB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gaW5zdHJcclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZyB0aGUgYGluc3RyYFxyXG4gICAqIG9wdGlvbi5cclxuICAgKi9cclxuICBpbnN0cigpIHtcclxuICAgIHJldHVybiB2LmNoYXJ0Q29uZmlnKCk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGBvcHRpb25zYCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYS5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgdGhlIGBvcHRpb25zYCB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gb3B0aW9uc1xyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nIHRoZSBgb3B0aW9uc2BcclxuICAgKiBvcHRpb24uXHJcbiAgICovXHJcbiAgb3B0aW9ucygpIHtcclxuICAgIHJldHVybiB2LmNoYXJ0Q29uZmlnKCk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGBzdmdgIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhhdCB0aGUgc2NoZW1hIHdpbGwgYWNjZXB0IG9iamVjdCB2YWx1ZXNcclxuICAgKiBvciB0cmltbWVkIHN0cmluZyB2YWx1ZXMgdGhhdCBjb250YWluICc8c3ZnJyBvciAnPD94bWwnIGVsZW1lbnRzIGFuZCBudWxsLlxyXG4gICAqIFRoZSAndW5kZWZpbmVkJywgJ251bGwnLCBhbmQgJycgdmFsdWVzIHdpbGwgYmUgdHJhbnNmb3JtZWQgdG8gbnVsbC5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiBzdmdcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZyB0aGUgYHN2Z2Agb3B0aW9uLlxyXG4gICAqL1xyXG4gIHN2ZygpIHtcclxuICAgIHJldHVybiB6XHJcbiAgICAgIC5zdHJpbmcoKVxyXG4gICAgICAudHJpbSgpXHJcbiAgICAgIC5yZWZpbmUoXHJcbiAgICAgICAgKHZhbHVlKSA9PlxyXG4gICAgICAgICAgdmFsdWUuaW5kZXhPZignPHN2ZycpID49IDAgfHxcclxuICAgICAgICAgIHZhbHVlLmluZGV4T2YoJzw/eG1sJykgPj0gMCB8fFxyXG4gICAgICAgICAgWydmYWxzZScsICd1bmRlZmluZWQnLCAnbnVsbCcsICcnXS5pbmNsdWRlcyh2YWx1ZSksXHJcbiAgICAgICAge1xyXG4gICAgICAgICAgcGFyYW1zOiB7XHJcbiAgICAgICAgICAgIGVycm9yTWVzc2FnZTogYFRoZSB2YWx1ZSBtdXN0IGJlIGEgc3RyaW5nIHRoYXQgY29udGFpbnMgJzxzdmcnIG9yICc8P3htbCdgXHJcbiAgICAgICAgICB9XHJcbiAgICAgICAgfVxyXG4gICAgICApXHJcbiAgICAgIC50cmFuc2Zvcm0oKHZhbHVlKSA9PlxyXG4gICAgICAgICFbJ2ZhbHNlJywgJ3VuZGVmaW5lZCcsICdudWxsJywgJyddLmluY2x1ZGVzKHZhbHVlKSA/IHZhbHVlIDogbnVsbFxyXG4gICAgICApXHJcbiAgICAgIC5udWxsYWJsZSgpO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgb3V0ZmlsZWAgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbCBzdHJpY3RlclxyXG4gICAqIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoYXQ6XHJcbiAgICpcclxuICAgKiAtIFdoZW4gYHN0cmljdENoZWNrYCBpcyB0cnVlLCB0aGUgc2NoZW1hIHdpbGwgYWNjZXB0IHRyaW1tZWQgc3RyaW5nIHZhbHVlc1xyXG4gICAqIHRoYXQgZW5kIHdpdGggJy5qcGVnJywgJy5qcGcnLCAnLnBuZycsICcucGRmJywgb3IgJy5zdmcnLCBhcmUgYXQgbGVhc3Qgb25lXHJcbiAgICogY2hhcmFjdGVyIGxvbmcgZXhjbHVkaW5nIHRoZSBleHRlbnNpb24sIG9yIG51bGwuXHJcbiAgICpcclxuICAgKiAtIFdoZW4gYHN0cmljdENoZWNrYCBpcyBmYWxzZSwgdGhlIHNjaGVtYSB3aWxsIGFjY2VwdCB0cmltbWVkIHN0cmluZyB2YWx1ZXNcclxuICAgKiB0aGF0IGVuZCB3aXRoICcuanBlZycsICcuanBnJywgJy5wbmcnLCAnLnBkZicsIG9yICcuc3ZnJywgYXJlIGF0IGxlYXN0IG9uZVxyXG4gICAqIGNoYXJhY3RlciBsb25nIGV4Y2x1ZGluZyB0aGUgZXh0ZW5zaW9uIGFuZCB3aWxsIGJlIG51bGwgaWYgdGhlIHByb3ZpZGVkXHJcbiAgICogdmFsdWUgaXMgbnVsbCwgJ3VuZGVmaW5lZCcsICdudWxsJywgb3IgJycuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gb3V0ZmlsZVxyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nIHRoZSBgb3V0ZmlsZWBcclxuICAgKiBvcHRpb24uXHJcbiAgICovXHJcbiAgb3V0ZmlsZShzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHN0cmljdENoZWNrXHJcbiAgICAgID8gelxyXG4gICAgICAgICAgLnN0cmluZygpXHJcbiAgICAgICAgICAudHJpbSgpXHJcbiAgICAgICAgICAucmVmaW5lKFxyXG4gICAgICAgICAgICAodmFsdWUpID0+XHJcbiAgICAgICAgICAgICAgKHZhbHVlLmxlbmd0aCA+PSA2ICYmIHZhbHVlLmVuZHNXaXRoKCcuanBlZycpKSB8fFxyXG4gICAgICAgICAgICAgICh2YWx1ZS5sZW5ndGggPj0gNSAmJlxyXG4gICAgICAgICAgICAgICAgKHZhbHVlLmVuZHNXaXRoKCcuanBnJykgfHxcclxuICAgICAgICAgICAgICAgICAgdmFsdWUuZW5kc1dpdGgoJy5wbmcnKSB8fFxyXG4gICAgICAgICAgICAgICAgICB2YWx1ZS5lbmRzV2l0aCgnLnBkZicpIHx8XHJcbiAgICAgICAgICAgICAgICAgIHZhbHVlLmVuZHNXaXRoKCcuc3ZnJykpKSxcclxuICAgICAgICAgICAge1xyXG4gICAgICAgICAgICAgIHBhcmFtczoge1xyXG4gICAgICAgICAgICAgICAgZXJyb3JNZXNzYWdlOiBgVGhlIHZhbHVlIG11c3QgYmUgYSBzdHJpbmcgdGhhdCBlbmRzIHdpdGggLmpwZWcsIC5qcGcsIC5wbmcsIC5wZGYsIG9yIC5zdmdgXHJcbiAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICB9XHJcbiAgICAgICAgICApXHJcbiAgICAgICAgICAubnVsbGFibGUoKVxyXG4gICAgICA6IHpcclxuICAgICAgICAgIC5zdHJpbmcoKVxyXG4gICAgICAgICAgLnRyaW0oKVxyXG4gICAgICAgICAgLnJlZmluZShcclxuICAgICAgICAgICAgKHZhbHVlKSA9PlxyXG4gICAgICAgICAgICAgICh2YWx1ZS5sZW5ndGggPj0gNiAmJiB2YWx1ZS5lbmRzV2l0aCgnLmpwZWcnKSkgfHxcclxuICAgICAgICAgICAgICAodmFsdWUubGVuZ3RoID49IDUgJiZcclxuICAgICAgICAgICAgICAgICh2YWx1ZS5lbmRzV2l0aCgnLmpwZycpIHx8XHJcbiAgICAgICAgICAgICAgICAgIHZhbHVlLmVuZHNXaXRoKCcucG5nJykgfHxcclxuICAgICAgICAgICAgICAgICAgdmFsdWUuZW5kc1dpdGgoJy5wZGYnKSB8fFxyXG4gICAgICAgICAgICAgICAgICB2YWx1ZS5lbmRzV2l0aCgnLnN2ZycpKSkgfHxcclxuICAgICAgICAgICAgICBbJ3VuZGVmaW5lZCcsICdudWxsJywgJyddLmluY2x1ZGVzKHZhbHVlKSxcclxuICAgICAgICAgICAge1xyXG4gICAgICAgICAgICAgIHBhcmFtczoge1xyXG4gICAgICAgICAgICAgICAgZXJyb3JNZXNzYWdlOiBgVGhlIHZhbHVlIG11c3QgYmUgYSBzdHJpbmcgdGhhdCBlbmRzIHdpdGggLmpwZWcsIC5qcGcsIC5wbmcsIC5wZGYsIG9yIC5zdmdgXHJcbiAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICB9XHJcbiAgICAgICAgICApXHJcbiAgICAgICAgICAudHJhbnNmb3JtKCh2YWx1ZSkgPT5cclxuICAgICAgICAgICAgIVsndW5kZWZpbmVkJywgJ251bGwnLCAnJ10uaW5jbHVkZXModmFsdWUpID8gdmFsdWUgOiBudWxsXHJcbiAgICAgICAgICApXHJcbiAgICAgICAgICAubnVsbGFibGUoKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYHR5cGVgIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGggYW4gb3B0aW9uYWwgc3RyaWN0ZXJcclxuICAgKiBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGUgc2FtZSB3b3JrIGFzIHRoZSBgZW51bWAgdmFsaWRhdG9yLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIHR5cGVcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZyB0aGUgYHR5cGVgXHJcbiAgICogb3B0aW9uLlxyXG4gICAqL1xyXG4gIHR5cGUoc3RyaWN0Q2hlY2spIHtcclxuICAgIHJldHVybiB2LmVudW0oWydqcGVnJywgJ2pwZycsICdwbmcnLCAncGRmJywgJ3N2ZyddLCBzdHJpY3RDaGVjayk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGBjb25zdHJgIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGggYW4gb3B0aW9uYWwgc3RyaWN0ZXJcclxuICAgKiBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGUgc2FtZSB3b3JrIGFzIHRoZSBgZW51bWAgdmFsaWRhdG9yLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIGNvbnN0clxyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nIHRoZSBgY29uc3RyYFxyXG4gICAqIG9wdGlvbi5cclxuICAgKi9cclxuICBjb25zdHIoc3RyaWN0Q2hlY2spIHtcclxuICAgIHJldHVybiB2LmVudW0oXHJcbiAgICAgIFsnY2hhcnQnLCAnc3RvY2tDaGFydCcsICdtYXBDaGFydCcsICdnYW50dENoYXJ0J10sXHJcbiAgICAgIHN0cmljdENoZWNrXHJcbiAgICApO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgYjY0YCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoIGFuIG9wdGlvbmFsIHN0cmljdGVyXHJcbiAgICogY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhlIHNhbWUgd29yayBhcyB0aGUgYGJvb2xlYW5gIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiBiNjRcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZyB0aGUgYGI2NGAgb3B0aW9uLlxyXG4gICAqL1xyXG4gIGI2NChzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHYuYm9vbGVhbihzdHJpY3RDaGVjayk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGBub0Rvd25sb2FkYCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoIGFuIG9wdGlvbmFsXHJcbiAgICogc3RyaWN0ZXIgY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhlIHNhbWUgd29yayBhcyB0aGUgYGJvb2xlYW5gIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiBub0Rvd25sb2FkXHJcbiAgICpcclxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IHN0cmljdENoZWNrIC0gRGV0ZXJtaW5lcyBpZiBzdHJpY3RlciB2YWxpZGF0aW9uIHNob3VsZFxyXG4gICAqIGJlIGFwcGxpZWQuXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9IEEgWm9kIHNjaGVtYSBvYmplY3QgZm9yIHZhbGlkYXRpbmcgdGhlIGBub0Rvd25sb2FkYFxyXG4gICAqIG9wdGlvbi5cclxuICAgKi9cclxuICBub0Rvd25sb2FkKHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gdi5ib29sZWFuKHN0cmljdENoZWNrKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYGRlZmF1bHRIZWlnaHRgIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGggYW4gb3B0aW9uYWxcclxuICAgKiBzdHJpY3RlciBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGUgc2FtZSB3b3JrIGFzIHRoZSBgcG9zaXRpdmVOdW1gIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiBkZWZhdWx0SGVpZ2h0XHJcbiAgICpcclxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IHN0cmljdENoZWNrIC0gRGV0ZXJtaW5lcyBpZiBzdHJpY3RlciB2YWxpZGF0aW9uIHNob3VsZFxyXG4gICAqIGJlIGFwcGxpZWQuXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9IEEgWm9kIHNjaGVtYSBvYmplY3QgZm9yIHZhbGlkYXRpbmdcclxuICAgKiB0aGUgYGRlZmF1bHRIZWlnaHRgIG9wdGlvbi5cclxuICAgKi9cclxuICBkZWZhdWx0SGVpZ2h0KHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gdi5wb3NpdGl2ZU51bShzdHJpY3RDaGVjayk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGBkZWZhdWx0V2lkdGhgIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGggYW4gb3B0aW9uYWxcclxuICAgKiBzdHJpY3RlciBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGUgc2FtZSB3b3JrIGFzIHRoZSBgcG9zaXRpdmVOdW1gIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiBkZWZhdWx0V2lkdGhcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZ1xyXG4gICAqIHRoZSBgZGVmYXVsdFdpZHRoYCBvcHRpb24uXHJcbiAgICovXHJcbiAgZGVmYXVsdFdpZHRoKHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gdi5wb3NpdGl2ZU51bShzdHJpY3RDaGVjayk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGBkZWZhdWx0U2NhbGVgIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGggYW4gb3B0aW9uYWxcclxuICAgKiBzdHJpY3RlciBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGF0OlxyXG4gICAqXHJcbiAgICogLSBXaGVuIGBzdHJpY3RDaGVja2AgaXMgdHJ1ZSwgdGhlIHNjaGVtYSB3aWxsIGFjY2VwdCBudW1iZXIgdmFsdWVzIHRoYXRcclxuICAgKiBhcmUgYmV0d2VlbiAwLjEgYW5kIDUgKGluY2x1c2l2ZSkuXHJcbiAgICpcclxuICAgKiAtIFdoZW4gYHN0cmljdENoZWNrYCBpcyBmYWxzZSwgdGhlIHNjaGVtYSB3aWxsIGFjY2VwdCBudW1iZXIgdmFsdWVzXHJcbiAgICogYW5kIHN0cmluZ2lmaWVkIG51bWJlciB2YWx1ZXMgdGhhdCBhcmUgYmV0d2VlbiAwLjEgYW5kIDUgKGluY2x1c2l2ZSksIG51bGwsXHJcbiAgICogJ3VuZGVmaW5lZCcsICdudWxsJywgYW5kICcnIHdoaWNoIHdpbGwgYmUgdHJhbnNmb3JtZWQgdG8gbnVsbC5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiBkZWZhdWx0U2NhbGVcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZ1xyXG4gICAqIHRoZSBgZGVmYXVsdFNjYWxlYCBvcHRpb24uXHJcbiAgICovXHJcbiAgZGVmYXVsdFNjYWxlKHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gc3RyaWN0Q2hlY2tcclxuICAgICAgPyB6Lm51bWJlcigpLmd0ZSgwLjEpLmx0ZSg1KVxyXG4gICAgICA6IHpcclxuICAgICAgICAgIC51bmlvbihbXHJcbiAgICAgICAgICAgIHpcclxuICAgICAgICAgICAgICAuc3RyaW5nKClcclxuICAgICAgICAgICAgICAudHJpbSgpXHJcbiAgICAgICAgICAgICAgLnJlZmluZShcclxuICAgICAgICAgICAgICAgICh2YWx1ZSkgPT5cclxuICAgICAgICAgICAgICAgICAgKCFpc05hTihOdW1iZXIodmFsdWUpKSAmJlxyXG4gICAgICAgICAgICAgICAgICAgIHZhbHVlICE9PSB0cnVlICYmXHJcbiAgICAgICAgICAgICAgICAgICAgIXZhbHVlLnN0YXJ0c1dpdGgoJ1snKSAmJlxyXG4gICAgICAgICAgICAgICAgICAgIE51bWJlcih2YWx1ZSkgPj0gMC4xICYmXHJcbiAgICAgICAgICAgICAgICAgICAgTnVtYmVyKHZhbHVlKSA8PSA1KSB8fFxyXG4gICAgICAgICAgICAgICAgICBbJ3VuZGVmaW5lZCcsICdudWxsJywgJyddLmluY2x1ZGVzKHZhbHVlKSxcclxuICAgICAgICAgICAgICAgIHtcclxuICAgICAgICAgICAgICAgICAgcGFyYW1zOiB7XHJcbiAgICAgICAgICAgICAgICAgICAgZXJyb3JNZXNzYWdlOiAnVGhlIHZhbHVlIG11c3QgYmUgd2l0aGluIGEgMC4xIGFuZCA1LjAgcmFuZ2UnXHJcbiAgICAgICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgICApXHJcbiAgICAgICAgICAgICAgLnRyYW5zZm9ybSgodmFsdWUpID0+XHJcbiAgICAgICAgICAgICAgICAhWyd1bmRlZmluZWQnLCAnbnVsbCcsICcnXS5pbmNsdWRlcyh2YWx1ZSlcclxuICAgICAgICAgICAgICAgICAgPyBOdW1iZXIodmFsdWUpXHJcbiAgICAgICAgICAgICAgICAgIDogbnVsbFxyXG4gICAgICAgICAgICAgICksXHJcbiAgICAgICAgICAgIHoubnVtYmVyKCkuZ3RlKDAuMSkubHRlKDUpXHJcbiAgICAgICAgICBdKVxyXG4gICAgICAgICAgLm51bGxhYmxlKCk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGBoZWlnaHRgIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGggYW4gb3B0aW9uYWwgc3RyaWN0ZXJcclxuICAgKiBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGUgc2FtZSB3b3JrIGFzIGEgbnVsbGFibGUgYGRlZmF1bHRIZWlnaHRgXHJcbiAgICogdmFsaWRhdG9yLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIGhlaWdodFxyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nIHRoZSBgaGVpZ2h0YFxyXG4gICAqIG9wdGlvbi5cclxuICAgKi9cclxuICBoZWlnaHQoc3RyaWN0Q2hlY2spIHtcclxuICAgIHJldHVybiB0aGlzLmRlZmF1bHRIZWlnaHQoc3RyaWN0Q2hlY2spLm51bGxhYmxlKCk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGB3aWR0aGAgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbCBzdHJpY3RlclxyXG4gICAqIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgYSBudWxsYWJsZSBgZGVmYXVsdFdpZHRoYFxyXG4gICAqIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiB3aWR0aFxyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nIHRoZSBgd2lkdGhgXHJcbiAgICogb3B0aW9uLlxyXG4gICAqL1xyXG4gIHdpZHRoKHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gdGhpcy5kZWZhdWx0V2lkdGgoc3RyaWN0Q2hlY2spLm51bGxhYmxlKCk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGBzY2FsZWAgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbCBzdHJpY3RlclxyXG4gICAqIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgYSBudWxsYWJsZSBgZGVmYXVsdFNjYWxlYFxyXG4gICAqIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiBzY2FsZVxyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nIHRoZSBgc2NhbGVgXHJcbiAgICogb3B0aW9uLlxyXG4gICAqL1xyXG4gIHNjYWxlKHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gdGhpcy5kZWZhdWx0U2NhbGUoc3RyaWN0Q2hlY2spLm51bGxhYmxlKCk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGBnbG9iYWxPcHRpb25zYCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYS5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgdGhlIGBhZGRpdGlvbmFsT3B0aW9uc2BcclxuICAgKiB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gZ2xvYmFsT3B0aW9uc1xyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nXHJcbiAgICogdGhlIGBnbG9iYWxPcHRpb25zYCBvcHRpb24uXHJcbiAgICovXHJcbiAgZ2xvYmFsT3B0aW9ucygpIHtcclxuICAgIHJldHVybiB2LmFkZGl0aW9uYWxPcHRpb25zKCk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGB0aGVtZU9wdGlvbnNgIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhlIHNhbWUgd29yayBhcyB0aGUgYGFkZGl0aW9uYWxPcHRpb25zYFxyXG4gICAqIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiB0aGVtZU9wdGlvbnNcclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZ1xyXG4gICAqIHRoZSBgdGhlbWVPcHRpb25zYCBvcHRpb24uXHJcbiAgICovXHJcbiAgdGhlbWVPcHRpb25zKCkge1xyXG4gICAgcmV0dXJuIHYuYWRkaXRpb25hbE9wdGlvbnMoKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYGJhdGNoYCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoIGFuIG9wdGlvbmFsIHN0cmljdGVyXHJcbiAgICogY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhlIHNhbWUgd29yayBhcyB0aGUgYHN0cmluZ2AgdmFsaWRhdG9yLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIGJhdGNoXHJcbiAgICpcclxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IHN0cmljdENoZWNrIC0gRGV0ZXJtaW5lcyBpZiBzdHJpY3RlciB2YWxpZGF0aW9uIHNob3VsZFxyXG4gICAqIGJlIGFwcGxpZWQuXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9IEEgWm9kIHNjaGVtYSBvYmplY3QgZm9yIHZhbGlkYXRpbmcgdGhlIGBiYXRjaGBcclxuICAgKiBvcHRpb24uXHJcbiAgICovXHJcbiAgYmF0Y2goc3RyaWN0Q2hlY2spIHtcclxuICAgIHJldHVybiB2LnN0cmluZyhzdHJpY3RDaGVjayk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGByYXN0ZXJpemF0aW9uVGltZW91dGAgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aFxyXG4gICAqIGFuIG9wdGlvbmFsIHN0cmljdGVyIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgdGhlIGBub25OZWdhdGl2ZU51bWBcclxuICAgKiB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gcmFzdGVyaXphdGlvblRpbWVvdXRcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZ1xyXG4gICAqIHRoZSBgcmFzdGVyaXphdGlvblRpbWVvdXRgIG9wdGlvbi5cclxuICAgKi9cclxuICByYXN0ZXJpemF0aW9uVGltZW91dChzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHYubm9uTmVnYXRpdmVOdW0oc3RyaWN0Q2hlY2spO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgYWxsb3dDb2RlRXhlY3V0aW9uYCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoXHJcbiAgICogYW4gb3B0aW9uYWwgc3RyaWN0ZXIgY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhlIHNhbWUgd29yayBhcyB0aGUgYGJvb2xlYW5gIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiBhbGxvd0NvZGVFeGVjdXRpb25cclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZ1xyXG4gICAqIHRoZSBgYWxsb3dDb2RlRXhlY3V0aW9uYCBvcHRpb24uXHJcbiAgICovXHJcbiAgYWxsb3dDb2RlRXhlY3V0aW9uKHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gdi5ib29sZWFuKHN0cmljdENoZWNrKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYGFsbG93RmlsZVJlc291cmNlc2AgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aFxyXG4gICAqIGFuIG9wdGlvbmFsIHN0cmljdGVyIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgdGhlIGBib29sZWFuYCB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gYWxsb3dGaWxlUmVzb3VyY2VzXHJcbiAgICpcclxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IHN0cmljdENoZWNrIC0gRGV0ZXJtaW5lcyBpZiBzdHJpY3RlciB2YWxpZGF0aW9uIHNob3VsZFxyXG4gICAqIGJlIGFwcGxpZWQuXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9IEEgWm9kIHNjaGVtYSBvYmplY3QgZm9yIHZhbGlkYXRpbmdcclxuICAgKiB0aGUgYGFsbG93RmlsZVJlc291cmNlc2Agb3B0aW9uLlxyXG4gICAqL1xyXG4gIGFsbG93RmlsZVJlc291cmNlcyhzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHYuYm9vbGVhbihzdHJpY3RDaGVjayk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGBjdXN0b21Db2RlYCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoIGFuIG9wdGlvbmFsXHJcbiAgICogc3RyaWN0ZXIgY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhlIHNhbWUgd29yayBhcyB0aGUgYHN0cmluZ2AgdmFsaWRhdG9yLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIGN1c3RvbUNvZGVcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZyB0aGUgYGN1c3RvbUNvZGVgXHJcbiAgICogb3B0aW9uLlxyXG4gICAqL1xyXG4gIGN1c3RvbUNvZGUoc3RyaWN0Q2hlY2spIHtcclxuICAgIHJldHVybiB2LnN0cmluZyhzdHJpY3RDaGVjayk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGBjYWxsYmFja2AgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbFxyXG4gICAqIHN0cmljdGVyIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgdGhlIGBzdHJpbmdgIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiBjYWxsYmFja1xyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nIHRoZSBgY2FsbGJhY2tgXHJcbiAgICogb3B0aW9uLlxyXG4gICAqL1xyXG4gIGNhbGxiYWNrKHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gdi5zdHJpbmcoc3RyaWN0Q2hlY2spO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgcmVzb3VyY2VzYCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoIGFuIG9wdGlvbmFsXHJcbiAgICogc3RyaWN0ZXIgY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhhdDpcclxuICAgKlxyXG4gICAqIC0gV2hlbiBgc3RyaWN0Q2hlY2tgIGlzIHRydWUsIHRoZSBzY2hlbWEgd2lsbCBhY2NlcHQgYSBwYXJ0aWFsIG9iamVjdFxyXG4gICAqIHdpdGggYWxsb3dlZCBwcm9wZXJ0aWVzIGBqc2AsIGBjc3NgLCBhbmQgYGZpbGVzYCB3aGVyZSBlYWNoIG9mIHRoZSBhbGxvd2VkXHJcbiAgICogcHJvcGVydGllcyBjYW4gYmUgbnVsbCwgc3RyaW5naWZpZWQgdmVyc2lvbiBvZiB0aGUgb2JqZWN0LCBzdHJpbmcgdGhhdCBlbmRzXHJcbiAgICogd2l0aCB0aGUgJy5qc29uJywgYW5kIG51bGwuXHJcbiAgICpcclxuICAgKiAtIFdoZW4gYHN0cmljdENoZWNrYCBpcyBmYWxzZSwgdGhlIHNjaGVtYSB3aWxsIGFjY2VwdCBhIHN0cmluZ2lmaWVkIHZlcnNpb25cclxuICAgKiBvZiBhIHBhcnRpYWwgb2JqZWN0IHdpdGggYWxsb3dlZCBwcm9wZXJ0aWVzIGBqc2AsIGBjc3NgLCBhbmQgYGZpbGVzYCB3aGVyZVxyXG4gICAqIGVhY2ggb2YgdGhlIGFsbG93ZWQgcHJvcGVydGllcyBjYW4gYmUgbnVsbCwgc3RyaW5nIHRoYXQgZW5kcyB3aXRoIHRoZVxyXG4gICAqICcuanNvbicsIGFuZCB3aWxsIGJlIG51bGwgaWYgdGhlIHByb3ZpZGVkIHZhbHVlIGlzICd1bmRlZmluZWQnLCAnbnVsbCdcclxuICAgKiBvciAnJy5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiByZXNvdXJjZXNcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZyB0aGUgYHJlc291cmNlc2BcclxuICAgKiBvcHRpb24uXHJcbiAgICovXHJcbiAgcmVzb3VyY2VzKHN0cmljdENoZWNrKSB7XHJcbiAgICBjb25zdCBvYmplY3RTY2hlbWEgPSB6XHJcbiAgICAgIC5vYmplY3Qoe1xyXG4gICAgICAgIGpzOiB2LnN0cmluZyhmYWxzZSksXHJcbiAgICAgICAgY3NzOiB2LnN0cmluZyhmYWxzZSksXHJcbiAgICAgICAgZmlsZXM6IHZcclxuICAgICAgICAgIC5zdHJpbmdBcnJheShcclxuICAgICAgICAgICAgKHZhbHVlKSA9PiAhWyd1bmRlZmluZWQnLCAnbnVsbCcsICcnXS5pbmNsdWRlcyh2YWx1ZSksXHJcbiAgICAgICAgICAgICcsJyxcclxuICAgICAgICAgICAgdHJ1ZVxyXG4gICAgICAgICAgKVxyXG4gICAgICAgICAgLm51bGxhYmxlKClcclxuICAgICAgfSlcclxuICAgICAgLnBhcnRpYWwoKTtcclxuXHJcbiAgICBjb25zdCBzdHJpbmdTY2hlbWExID0gelxyXG4gICAgICAuc3RyaW5nKClcclxuICAgICAgLnRyaW0oKVxyXG4gICAgICAucmVmaW5lKFxyXG4gICAgICAgICh2YWx1ZSkgPT5cclxuICAgICAgICAgICh2YWx1ZS5zdGFydHNXaXRoKCd7JykgJiYgdmFsdWUuZW5kc1dpdGgoJ30nKSkgfHxcclxuICAgICAgICAgICh2YWx1ZS5sZW5ndGggPj0gNiAmJiB2YWx1ZS5lbmRzV2l0aCgnLmpzb24nKSksXHJcbiAgICAgICAge1xyXG4gICAgICAgICAgcGFyYW1zOiB7XHJcbiAgICAgICAgICAgIGVycm9yTWVzc2FnZTogYFRoZSB2YWx1ZSBtdXN0IGJlIGEgc3RyaW5nIHRoYXQgc3RhcnRzIHdpdGggJ3snIGFuZCBlbmRzIHdpdGggJ31gXHJcbiAgICAgICAgICB9XHJcbiAgICAgICAgfVxyXG4gICAgICApO1xyXG5cclxuICAgIGNvbnN0IHN0cmluZ1NjaGVtYTIgPSB6XHJcbiAgICAgIC5zdHJpbmcoKVxyXG4gICAgICAudHJpbSgpXHJcbiAgICAgIC5yZWZpbmUoXHJcbiAgICAgICAgKHZhbHVlKSA9PlxyXG4gICAgICAgICAgKHZhbHVlLnN0YXJ0c1dpdGgoJ3snKSAmJiB2YWx1ZS5lbmRzV2l0aCgnfScpKSB8fFxyXG4gICAgICAgICAgKHZhbHVlLmxlbmd0aCA+PSA2ICYmIHZhbHVlLmVuZHNXaXRoKCcuanNvbicpKSB8fFxyXG4gICAgICAgICAgWyd1bmRlZmluZWQnLCAnbnVsbCcsICcnXS5pbmNsdWRlcyh2YWx1ZSksXHJcbiAgICAgICAge1xyXG4gICAgICAgICAgcGFyYW1zOiB7XHJcbiAgICAgICAgICAgIGVycm9yTWVzc2FnZTogYFRoZSB2YWx1ZSBtdXN0IGJlIGEgc3RyaW5nIHRoYXQgZW5kcyB3aXRoICcuanNvbidgXHJcbiAgICAgICAgICB9XHJcbiAgICAgICAgfVxyXG4gICAgICApXHJcbiAgICAgIC50cmFuc2Zvcm0oKHZhbHVlKSA9PlxyXG4gICAgICAgICFbJ3VuZGVmaW5lZCcsICdudWxsJywgJyddLmluY2x1ZGVzKHZhbHVlKSA/IHZhbHVlIDogbnVsbFxyXG4gICAgICApO1xyXG5cclxuICAgIHJldHVybiBzdHJpY3RDaGVja1xyXG4gICAgICA/IHoudW5pb24oW29iamVjdFNjaGVtYSwgc3RyaW5nU2NoZW1hMV0pLm51bGxhYmxlKClcclxuICAgICAgOiB6LnVuaW9uKFtvYmplY3RTY2hlbWEsIHN0cmluZ1NjaGVtYTJdKS5udWxsYWJsZSgpO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgbG9hZENvbmZpZ2AgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbFxyXG4gICAqIHN0cmljdGVyIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgdGhlIGBzdHJpbmdgIHZhbGlkYXRvci5cclxuICAgKiBBZGRpdGlvbmFsbHksIGl0IG11c3QgYmUgYSBzdHJpbmcgdGhhdCBlbmRzIHdpdGggJy5qc29uJy5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiBsb2FkQ29uZmlnXHJcbiAgICpcclxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IHN0cmljdENoZWNrIC0gRGV0ZXJtaW5lcyBpZiBzdHJpY3RlciB2YWxpZGF0aW9uIHNob3VsZFxyXG4gICAqIGJlIGFwcGxpZWQuXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9IEEgWm9kIHNjaGVtYSBvYmplY3QgZm9yIHZhbGlkYXRpbmcgdGhlIGBsb2FkQ29uZmlnYFxyXG4gICAqIG9wdGlvbi5cclxuICAgKi9cclxuICBsb2FkQ29uZmlnKHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gdlxyXG4gICAgICAuc3RyaW5nKHN0cmljdENoZWNrKVxyXG4gICAgICAucmVmaW5lKFxyXG4gICAgICAgICh2YWx1ZSkgPT5cclxuICAgICAgICAgIHZhbHVlID09PSBudWxsIHx8ICh2YWx1ZS5sZW5ndGggPj0gNiAmJiB2YWx1ZS5lbmRzV2l0aCgnLmpzb24nKSksXHJcbiAgICAgICAge1xyXG4gICAgICAgICAgcGFyYW1zOiB7XHJcbiAgICAgICAgICAgIGVycm9yTWVzc2FnZTogYFRoZSB2YWx1ZSBtdXN0IGJlIGEgc3RyaW5nIHRoYXQgZW5kcyB3aXRoIC5qc29uIGBcclxuICAgICAgICAgIH1cclxuICAgICAgICB9XHJcbiAgICAgICk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGBjcmVhdGVDb25maWdgIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGggYW4gb3B0aW9uYWxcclxuICAgKiBzdHJpY3RlciBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGUgc2FtZSB3b3JrIGFzIHRoZSBgbG9hZENvbmZpZ2AgdmFsaWRhdG9yLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIGNyZWF0ZUNvbmZpZ1xyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nXHJcbiAgICogdGhlIGBjcmVhdGVDb25maWdgIG9wdGlvbi5cclxuICAgKi9cclxuICBjcmVhdGVDb25maWcoc3RyaWN0Q2hlY2spIHtcclxuICAgIHJldHVybiB0aGlzLmxvYWRDb25maWcoc3RyaWN0Q2hlY2spO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgZW5hYmxlU2VydmVyYCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoIGFuIG9wdGlvbmFsXHJcbiAgICogc3RyaWN0ZXIgY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhlIHNhbWUgd29yayBhcyB0aGUgYGJvb2xlYW5gIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiBlbmFibGVTZXJ2ZXJcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZ1xyXG4gICAqIHRoZSBgZW5hYmxlU2VydmVyYCBvcHRpb24uXHJcbiAgICovXHJcbiAgZW5hYmxlU2VydmVyKHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gdi5ib29sZWFuKHN0cmljdENoZWNrKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYGhvc3RgIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGggYW4gb3B0aW9uYWwgc3RyaWN0ZXJcclxuICAgKiBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGUgc2FtZSB3b3JrIGFzIHRoZSBgc3RyaW5nYCB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gaG9zdFxyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nIHRoZSBgaG9zdGBcclxuICAgKiBvcHRpb24uXHJcbiAgICovXHJcbiAgaG9zdChzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHYuc3RyaW5nKHN0cmljdENoZWNrKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYHBvcnRgIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGggYW4gb3B0aW9uYWwgc3RyaWN0ZXJcclxuICAgKiBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGUgc2FtZSB3b3JrIGFzIHRoZSBgbm9uTmVnYXRpdmVOdW1gXHJcbiAgICogdmFsaWRhdG9yLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIHBvcnRcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZyB0aGUgYHBvcnRgXHJcbiAgICogb3B0aW9uLlxyXG4gICAqL1xyXG4gIHBvcnQoc3RyaWN0Q2hlY2spIHtcclxuICAgIHJldHVybiB2Lm5vbk5lZ2F0aXZlTnVtKHN0cmljdENoZWNrKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYHVwbG9hZExpbWl0YCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoIGFuIG9wdGlvbmFsXHJcbiAgICogc3RyaWN0ZXIgY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhlIHNhbWUgd29yayBhcyB0aGUgYHBvc2l0aXZlTnVtYCB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gdXBsb2FkTGltaXRcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZyB0aGUgYHVwbG9hZExpbWl0YFxyXG4gICAqIG9wdGlvbi5cclxuICAgKi9cclxuICB1cGxvYWRMaW1pdChzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHYucG9zaXRpdmVOdW0oc3RyaWN0Q2hlY2spO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgc2VydmVyQmVuY2htYXJraW5nYCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoXHJcbiAgICogYW4gb3B0aW9uYWwgc3RyaWN0ZXIgY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhlIHNhbWUgd29yayBhcyB0aGUgYGJvb2xlYW5gIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiBzZXJ2ZXJCZW5jaG1hcmtpbmdcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZ1xyXG4gICAqIHRoZSBgc2VydmVyQmVuY2htYXJraW5nYCBvcHRpb24uXHJcbiAgICovXHJcbiAgc2VydmVyQmVuY2htYXJraW5nKHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gdi5ib29sZWFuKHN0cmljdENoZWNrKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYHByb3h5SG9zdGAgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbFxyXG4gICAqIHN0cmljdGVyIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgdGhlIGBzdHJpbmdgIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiBwcm94eUhvc3RcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZyB0aGUgYHByb3h5SG9zdGBcclxuICAgKiBvcHRpb24uXHJcbiAgICovXHJcbiAgcHJveHlIb3N0KHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gdi5zdHJpbmcoc3RyaWN0Q2hlY2spO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgcHJveHlQb3J0YCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoIGFuIG9wdGlvbmFsXHJcbiAgICogc3RyaWN0ZXIgY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhlIHNhbWUgd29yayBhcyBhIG51bGxhYmxlIGBub25OZWdhdGl2ZU51bWBcclxuICAgKiB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gcHJveHlQb3J0XHJcbiAgICpcclxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IHN0cmljdENoZWNrIC0gRGV0ZXJtaW5lcyBpZiBzdHJpY3RlciB2YWxpZGF0aW9uIHNob3VsZFxyXG4gICAqIGJlIGFwcGxpZWQuXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9IEEgWm9kIHNjaGVtYSBvYmplY3QgZm9yIHZhbGlkYXRpbmcgdGhlIGBwcm94eVBvcnRgXHJcbiAgICogb3B0aW9uLlxyXG4gICAqL1xyXG4gIHByb3h5UG9ydChzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHYubm9uTmVnYXRpdmVOdW0oc3RyaWN0Q2hlY2spLm51bGxhYmxlKCk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGBwcm94eVRpbWVvdXRgIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGggYW4gb3B0aW9uYWxcclxuICAgKiBzdHJpY3RlciBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGUgc2FtZSB3b3JrIGFzIHRoZSBgbm9uTmVnYXRpdmVOdW1gXHJcbiAgICogdmFsaWRhdG9yLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIHByb3h5VGltZW91dFxyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nXHJcbiAgICogdGhlIGBwcm94eVRpbWVvdXRgIG9wdGlvbi5cclxuICAgKi9cclxuICBwcm94eVRpbWVvdXQoc3RyaWN0Q2hlY2spIHtcclxuICAgIHJldHVybiB2Lm5vbk5lZ2F0aXZlTnVtKHN0cmljdENoZWNrKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYGVuYWJsZVJhdGVMaW1pdGluZ2AgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aFxyXG4gICAqIGFuIG9wdGlvbmFsIHN0cmljdGVyIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgdGhlIGBib29sZWFuYCB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gZW5hYmxlUmF0ZUxpbWl0aW5nXHJcbiAgICpcclxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IHN0cmljdENoZWNrIC0gRGV0ZXJtaW5lcyBpZiBzdHJpY3RlciB2YWxpZGF0aW9uIHNob3VsZFxyXG4gICAqIGJlIGFwcGxpZWQuXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9IEEgWm9kIHNjaGVtYSBvYmplY3QgZm9yIHZhbGlkYXRpbmdcclxuICAgKiB0aGUgYGVuYWJsZVJhdGVMaW1pdGluZ2Agb3B0aW9uLlxyXG4gICAqL1xyXG4gIGVuYWJsZVJhdGVMaW1pdGluZyhzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHYuYm9vbGVhbihzdHJpY3RDaGVjayk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGBtYXhSZXF1ZXN0c2AgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbFxyXG4gICAqIHN0cmljdGVyIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgdGhlIGBub25OZWdhdGl2ZU51bWBcclxuICAgKiB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gbWF4UmVxdWVzdHNcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZyB0aGUgYG1heFJlcXVlc3RzYFxyXG4gICAqIG9wdGlvbi5cclxuICAgKi9cclxuICBtYXhSZXF1ZXN0cyhzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHYubm9uTmVnYXRpdmVOdW0oc3RyaWN0Q2hlY2spO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgd2luZG93YCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoIGFuIG9wdGlvbmFsIHN0cmljdGVyXHJcbiAgICogY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhlIHNhbWUgd29yayBhcyB0aGUgYG5vbk5lZ2F0aXZlTnVtYFxyXG4gICAqIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiB3aW5kb3dcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZyB0aGUgYHdpbmRvd2BcclxuICAgKiBvcHRpb24uXHJcbiAgICovXHJcbiAgd2luZG93KHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gdi5ub25OZWdhdGl2ZU51bShzdHJpY3RDaGVjayk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGBkZWxheWAgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbCBzdHJpY3RlclxyXG4gICAqIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgdGhlIGBub25OZWdhdGl2ZU51bWBcclxuICAgKiB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gZGVsYXlcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZyB0aGUgYGRlbGF5YFxyXG4gICAqIG9wdGlvbi5cclxuICAgKi9cclxuICBkZWxheShzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHYubm9uTmVnYXRpdmVOdW0oc3RyaWN0Q2hlY2spO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgdHJ1c3RQcm94eWAgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbFxyXG4gICAqIHN0cmljdGVyIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgdGhlIGBib29sZWFuYCB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gdHJ1c3RQcm94eVxyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nIHRoZSBgdHJ1c3RQcm94eWBcclxuICAgKiBvcHRpb24uXHJcbiAgICovXHJcbiAgdHJ1c3RQcm94eShzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHYuYm9vbGVhbihzdHJpY3RDaGVjayk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGBza2lwS2V5YCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoIGFuIG9wdGlvbmFsIHN0cmljdGVyXHJcbiAgICogY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhlIHNhbWUgd29yayBhcyB0aGUgYHN0cmluZ2AgdmFsaWRhdG9yLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIHNraXBLZXlcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZyB0aGUgYHNraXBLZXlgXHJcbiAgICogb3B0aW9uLlxyXG4gICAqL1xyXG4gIHNraXBLZXkoc3RyaWN0Q2hlY2spIHtcclxuICAgIHJldHVybiB2LnN0cmluZyhzdHJpY3RDaGVjayk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGBza2lwVG9rZW5gIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGggYW4gb3B0aW9uYWxcclxuICAgKiBzdHJpY3RlciBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGUgc2FtZSB3b3JrIGFzIHRoZSBgc3RyaW5nYCB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gc2tpcFRva2VuXHJcbiAgICpcclxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IHN0cmljdENoZWNrIC0gRGV0ZXJtaW5lcyBpZiBzdHJpY3RlciB2YWxpZGF0aW9uIHNob3VsZFxyXG4gICAqIGJlIGFwcGxpZWQuXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9IEEgWm9kIHNjaGVtYSBvYmplY3QgZm9yIHZhbGlkYXRpbmcgdGhlIGBza2lwVG9rZW5gXHJcbiAgICogb3B0aW9uLlxyXG4gICAqL1xyXG4gIHNraXBUb2tlbihzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHYuc3RyaW5nKHN0cmljdENoZWNrKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYGVuYWJsZVNzbGAgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbFxyXG4gICAqIHN0cmljdGVyIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgdGhlIGBib29sZWFuYCB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gZW5hYmxlU3NsXHJcbiAgICpcclxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IHN0cmljdENoZWNrIC0gRGV0ZXJtaW5lcyBpZiBzdHJpY3RlciB2YWxpZGF0aW9uIHNob3VsZFxyXG4gICAqIGJlIGFwcGxpZWQuXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9IEEgWm9kIHNjaGVtYSBvYmplY3QgZm9yIHZhbGlkYXRpbmcgdGhlIGBlbmFibGVTc2xgXHJcbiAgICogb3B0aW9uLlxyXG4gICAqL1xyXG4gIGVuYWJsZVNzbChzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHYuYm9vbGVhbihzdHJpY3RDaGVjayk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGBzc2xGb3JjZWAgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbFxyXG4gICAqIHN0cmljdGVyIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgdGhlIGBib29sZWFuYCB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gc3NsRm9yY2VcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZyB0aGUgYHNzbEZvcmNlYFxyXG4gICAqIG9wdGlvbi5cclxuICAgKi9cclxuICBzc2xGb3JjZShzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHYuYm9vbGVhbihzdHJpY3RDaGVjayk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGBzc2xQb3J0YCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoIGFuIG9wdGlvbmFsIHN0cmljdGVyXHJcbiAgICogY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhlIHNhbWUgd29yayBhcyB0aGUgYG5vbk5lZ2F0aXZlTnVtYFxyXG4gICAqIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiBzc2xQb3J0XHJcbiAgICpcclxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IHN0cmljdENoZWNrIC0gRGV0ZXJtaW5lcyBpZiBzdHJpY3RlciB2YWxpZGF0aW9uIHNob3VsZFxyXG4gICAqIGJlIGFwcGxpZWQuXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9IEEgWm9kIHNjaGVtYSBvYmplY3QgZm9yIHZhbGlkYXRpbmcgdGhlIGBzc2xQb3J0YFxyXG4gICAqIG9wdGlvbi5cclxuICAgKi9cclxuICBzc2xQb3J0KHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gdi5ub25OZWdhdGl2ZU51bShzdHJpY3RDaGVjayk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGBzc2xDZXJ0UGF0aGAgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbFxyXG4gICAqIHN0cmljdGVyIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgdGhlIGBzdHJpbmdgIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiBzc2xDZXJ0UGF0aFxyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nIHRoZSBgc3NsQ2VydFBhdGhgXHJcbiAgICogb3B0aW9uLlxyXG4gICAqL1xyXG4gIHNzbENlcnRQYXRoKHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gdi5zdHJpbmcoc3RyaWN0Q2hlY2spO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgbWluV29ya2Vyc2AgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbFxyXG4gICAqIHN0cmljdGVyIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgdGhlIGBwb3NpdGl2ZU51bWAgdmFsaWRhdG9yLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIG1pbldvcmtlcnNcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZyB0aGUgYG1pbldvcmtlcnNgXHJcbiAgICogb3B0aW9uLlxyXG4gICAqL1xyXG4gIG1pbldvcmtlcnMoc3RyaWN0Q2hlY2spIHtcclxuICAgIHJldHVybiB2LnBvc2l0aXZlTnVtKHN0cmljdENoZWNrKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYG1heFdvcmtlcnNgIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGggYW4gb3B0aW9uYWxcclxuICAgKiBzdHJpY3RlciBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGUgc2FtZSB3b3JrIGFzIHRoZSBgcG9zaXRpdmVOdW1gIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiBtYXhXb3JrZXJzXHJcbiAgICpcclxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IHN0cmljdENoZWNrIC0gRGV0ZXJtaW5lcyBpZiBzdHJpY3RlciB2YWxpZGF0aW9uIHNob3VsZFxyXG4gICAqIGJlIGFwcGxpZWQuXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9IEEgWm9kIHNjaGVtYSBvYmplY3QgZm9yIHZhbGlkYXRpbmcgdGhlIGBtYXhXb3JrZXJzYFxyXG4gICAqIG9wdGlvbi5cclxuICAgKi9cclxuICBtYXhXb3JrZXJzKHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gdi5wb3NpdGl2ZU51bShzdHJpY3RDaGVjayk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGB3b3JrTGltaXRgIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGggYW4gb3B0aW9uYWxcclxuICAgKiBzdHJpY3RlciBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGUgc2FtZSB3b3JrIGFzIHRoZSBgcG9zaXRpdmVOdW1gIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiB3b3JrTGltaXRcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZyB0aGUgYHdvcmtMaW1pdGBcclxuICAgKiBvcHRpb24uXHJcbiAgICovXHJcbiAgd29ya0xpbWl0KHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gdi5wb3NpdGl2ZU51bShzdHJpY3RDaGVjayk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGBhY3F1aXJlVGltZW91dGAgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbFxyXG4gICAqIHN0cmljdGVyIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgdGhlIGBub25OZWdhdGl2ZU51bWBcclxuICAgKiB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gYWNxdWlyZVRpbWVvdXRcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZ1xyXG4gICAqIHRoZSBgYWNxdWlyZVRpbWVvdXRgIG9wdGlvbi5cclxuICAgKi9cclxuICBhY3F1aXJlVGltZW91dChzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHYubm9uTmVnYXRpdmVOdW0oc3RyaWN0Q2hlY2spO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgY3JlYXRlVGltZW91dGAgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbFxyXG4gICAqIHN0cmljdGVyIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgdGhlIGBub25OZWdhdGl2ZU51bWBcclxuICAgKiB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gY3JlYXRlVGltZW91dFxyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nXHJcbiAgICogdGhlIGBjcmVhdGVUaW1lb3V0YCBvcHRpb24uXHJcbiAgICovXHJcbiAgY3JlYXRlVGltZW91dChzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHYubm9uTmVnYXRpdmVOdW0oc3RyaWN0Q2hlY2spO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgZGVzdHJveVRpbWVvdXRgIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGggYW4gb3B0aW9uYWxcclxuICAgKiBzdHJpY3RlciBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGUgc2FtZSB3b3JrIGFzIHRoZSBgbm9uTmVnYXRpdmVOdW1gXHJcbiAgICogdmFsaWRhdG9yLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIGRlc3Ryb3lUaW1lb3V0XHJcbiAgICpcclxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IHN0cmljdENoZWNrIC0gRGV0ZXJtaW5lcyBpZiBzdHJpY3RlciB2YWxpZGF0aW9uIHNob3VsZFxyXG4gICAqIGJlIGFwcGxpZWQuXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9IEEgWm9kIHNjaGVtYSBvYmplY3QgZm9yIHZhbGlkYXRpbmdcclxuICAgKiB0aGUgYGRlc3Ryb3lUaW1lb3V0YCBvcHRpb24uXHJcbiAgICovXHJcbiAgZGVzdHJveVRpbWVvdXQoc3RyaWN0Q2hlY2spIHtcclxuICAgIHJldHVybiB2Lm5vbk5lZ2F0aXZlTnVtKHN0cmljdENoZWNrKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYGlkbGVUaW1lb3V0YCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoIGFuIG9wdGlvbmFsXHJcbiAgICogc3RyaWN0ZXIgY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhlIHNhbWUgd29yayBhcyB0aGUgYG5vbk5lZ2F0aXZlTnVtYFxyXG4gICAqIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiBpZGxlVGltZW91dFxyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nXHJcbiAgICogdGhlIGBpZGxlVGltZW91dGAgb3B0aW9uLlxyXG4gICAqL1xyXG4gIGlkbGVUaW1lb3V0KHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gdi5ub25OZWdhdGl2ZU51bShzdHJpY3RDaGVjayk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGBjcmVhdGVSZXRyeUludGVydmFsYCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoXHJcbiAgICogYW4gb3B0aW9uYWwgc3RyaWN0ZXIgY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhlIHNhbWUgd29yayBhcyB0aGUgYG5vbk5lZ2F0aXZlTnVtYFxyXG4gICAqIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiBjcmVhdGVSZXRyeUludGVydmFsXHJcbiAgICpcclxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IHN0cmljdENoZWNrIC0gRGV0ZXJtaW5lcyBpZiBzdHJpY3RlciB2YWxpZGF0aW9uIHNob3VsZFxyXG4gICAqIGJlIGFwcGxpZWQuXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9IEEgWm9kIHNjaGVtYSBvYmplY3QgZm9yIHZhbGlkYXRpbmdcclxuICAgKiB0aGUgYGNyZWF0ZVJldHJ5SW50ZXJ2YWxgIG9wdGlvbi5cclxuICAgKi9cclxuICBjcmVhdGVSZXRyeUludGVydmFsKHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gdi5ub25OZWdhdGl2ZU51bShzdHJpY3RDaGVjayk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGByZWFwZXJJbnRlcnZhbGAgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbFxyXG4gICAqIHN0cmljdGVyIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgdGhlIGBub25OZWdhdGl2ZU51bWBcclxuICAgKiB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gcmVhcGVySW50ZXJ2YWxcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZ1xyXG4gICAqIHRoZSBgcmVhcGVySW50ZXJ2YWxgIG9wdGlvbi5cclxuICAgKi9cclxuICByZWFwZXJJbnRlcnZhbChzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHYubm9uTmVnYXRpdmVOdW0oc3RyaWN0Q2hlY2spO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgcG9vbEJlbmNobWFya2luZ2AgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbFxyXG4gICAqIHN0cmljdGVyIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgdGhlIGBib29sZWFuYCB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gcG9vbEJlbmNobWFya2luZ1xyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nXHJcbiAgICogdGhlIGBwb29sQmVuY2htYXJraW5nYCBvcHRpb24uXHJcbiAgICovXHJcbiAgcG9vbEJlbmNobWFya2luZyhzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHYuYm9vbGVhbihzdHJpY3RDaGVjayk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGByZXNvdXJjZXNJbnRlcnZhbGAgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aFxyXG4gICAqIGFuIG9wdGlvbmFsIHN0cmljdGVyIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgdGhlIGBub25OZWdhdGl2ZU51bWBcclxuICAgKiB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gcmVzb3VyY2VzSW50ZXJ2YWxcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZ1xyXG4gICAqIHRoZSBgcmVzb3VyY2VzSW50ZXJ2YWxgIG9wdGlvbi5cclxuICAgKi9cclxuICByZXNvdXJjZXNJbnRlcnZhbChzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHYubm9uTmVnYXRpdmVOdW0oc3RyaWN0Q2hlY2spO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgbG9nTGV2ZWxgIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGggYW4gb3B0aW9uYWxcclxuICAgKiBzdHJpY3RlciBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGF0OlxyXG4gICAqXHJcbiAgICogLSBXaGVuIGBzdHJpY3RDaGVja2AgaXMgdHJ1ZSwgdGhlIHNjaGVtYSB3aWxsIGFjY2VwdCBpbnRlZ2VyIG51bWJlciB2YWx1ZXNcclxuICAgKiB0aGF0IGFyZSBiZXR3ZWVuIDAgYW5kIDUgKGluY2x1c2l2ZSkuXHJcbiAgICpcclxuICAgKiAtIFdoZW4gYHN0cmljdENoZWNrYCBpcyBmYWxzZSwgdGhlIHNjaGVtYSB3aWxsIGFjY2VwdCBpbnRlZ2VyIG51bWJlciB2YWx1ZXNcclxuICAgKiBhbmQgc3RyaW5naWZpZWQgaW50ZWdlciBudW1iZXIgdmFsdWVzIHRoYXQgYXJlIGJldHdlZW4gMSBhbmQgNSAoaW5jbHVzaXZlKSxcclxuICAgKiBudWxsLCAndW5kZWZpbmVkJywgJ251bGwnLCBhbmQgJycgd2hpY2ggd2lsbCBiZSB0cmFuc2Zvcm1lZCB0byBudWxsLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIGxvZ0xldmVsXHJcbiAgICpcclxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IHN0cmljdENoZWNrIC0gRGV0ZXJtaW5lcyBpZiBzdHJpY3RlciB2YWxpZGF0aW9uIHNob3VsZFxyXG4gICAqIGJlIGFwcGxpZWQuXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9IEEgWm9kIHNjaGVtYSBvYmplY3QgZm9yIHZhbGlkYXRpbmcgdGhlIGBsb2dMZXZlbGBcclxuICAgKiBvcHRpb24uXHJcbiAgICovXHJcbiAgbG9nTGV2ZWwoc3RyaWN0Q2hlY2spIHtcclxuICAgIHJldHVybiBzdHJpY3RDaGVja1xyXG4gICAgICA/IHoubnVtYmVyKCkuaW50KCkuZ3RlKDApLmx0ZSg1KVxyXG4gICAgICA6IHpcclxuICAgICAgICAgIC51bmlvbihbXHJcbiAgICAgICAgICAgIHpcclxuICAgICAgICAgICAgICAuc3RyaW5nKClcclxuICAgICAgICAgICAgICAudHJpbSgpXHJcbiAgICAgICAgICAgICAgLnJlZmluZShcclxuICAgICAgICAgICAgICAgICh2YWx1ZSkgPT5cclxuICAgICAgICAgICAgICAgICAgKCFpc05hTihOdW1iZXIodmFsdWUpKSAmJlxyXG4gICAgICAgICAgICAgICAgICAgIHZhbHVlICE9PSB0cnVlICYmXHJcbiAgICAgICAgICAgICAgICAgICAgIXZhbHVlLnN0YXJ0c1dpdGgoJ1snKSAmJlxyXG4gICAgICAgICAgICAgICAgICAgIE51bWJlci5pc0ludGVnZXIoTnVtYmVyKHZhbHVlKSkgJiZcclxuICAgICAgICAgICAgICAgICAgICBOdW1iZXIodmFsdWUpID49IDAgJiZcclxuICAgICAgICAgICAgICAgICAgICBOdW1iZXIodmFsdWUpIDw9IDUpIHx8XHJcbiAgICAgICAgICAgICAgICAgIFsndW5kZWZpbmVkJywgJ251bGwnLCAnJ10uaW5jbHVkZXModmFsdWUpLFxyXG4gICAgICAgICAgICAgICAge1xyXG4gICAgICAgICAgICAgICAgICBwYXJhbXM6IHtcclxuICAgICAgICAgICAgICAgICAgICBlcnJvck1lc3NhZ2U6ICdUaGUgdmFsdWUgbXVzdCBiZSB3aXRoaW4gYSAwIGFuZCA1IHJhbmdlJ1xyXG4gICAgICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgICAgKVxyXG4gICAgICAgICAgICAgIC50cmFuc2Zvcm0oKHZhbHVlKSA9PlxyXG4gICAgICAgICAgICAgICAgIVsndW5kZWZpbmVkJywgJ251bGwnLCAnJ10uaW5jbHVkZXModmFsdWUpXHJcbiAgICAgICAgICAgICAgICAgID8gTnVtYmVyKHZhbHVlKVxyXG4gICAgICAgICAgICAgICAgICA6IG51bGxcclxuICAgICAgICAgICAgICApLFxyXG4gICAgICAgICAgICB6Lm51bWJlcigpLmludCgpLmd0ZSgwKS5sdGUoNSlcclxuICAgICAgICAgIF0pXHJcbiAgICAgICAgICAubnVsbGFibGUoKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYGxvZ0ZpbGVgIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGggYW4gb3B0aW9uYWwgc3RyaWN0ZXJcclxuICAgKiBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGUgc2FtZSB3b3JrIGFzIHRoZSBgc3RyaW5nYCB2YWxpZGF0b3IuXHJcbiAgICogQWRkaXRpb25hbGx5LCBpdCBtdXN0IGJlIGEgc3RyaW5nIHRoYXQgZW5kcyB3aXRoICcubG9nJy5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiBsb2dGaWxlXHJcbiAgICpcclxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IHN0cmljdENoZWNrIC0gRGV0ZXJtaW5lcyBpZiBzdHJpY3RlciB2YWxpZGF0aW9uIHNob3VsZFxyXG4gICAqIGJlIGFwcGxpZWQuXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9IEEgWm9kIHNjaGVtYSBvYmplY3QgZm9yIHZhbGlkYXRpbmcgdGhlIGBsb2dGaWxlYFxyXG4gICAqIG9wdGlvbi5cclxuICAgKi9cclxuICBsb2dGaWxlKHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gdlxyXG4gICAgICAuc3RyaW5nKHN0cmljdENoZWNrKVxyXG4gICAgICAucmVmaW5lKFxyXG4gICAgICAgICh2YWx1ZSkgPT5cclxuICAgICAgICAgIHZhbHVlID09PSBudWxsIHx8ICh2YWx1ZS5sZW5ndGggPj0gNSAmJiB2YWx1ZS5lbmRzV2l0aCgnLmxvZycpKSxcclxuICAgICAgICB7XHJcbiAgICAgICAgICBwYXJhbXM6IHtcclxuICAgICAgICAgICAgZXJyb3JNZXNzYWdlOiBgVGhlIHZhbHVlIG11c3QgYmUgYSBzdHJpbmcgdGhhdCBlbmRzIHdpdGggJy5sb2cnYFxyXG4gICAgICAgICAgfVxyXG4gICAgICAgIH1cclxuICAgICAgKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYGxvZ0Rlc3RgIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGggYW4gb3B0aW9uYWwgc3RyaWN0ZXJcclxuICAgKiBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGUgc2FtZSB3b3JrIGFzIHRoZSBgc3RyaW5nYCB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gbG9nRGVzdFxyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nIHRoZSBgbG9nRGVzdGBcclxuICAgKiBvcHRpb24uXHJcbiAgICovXHJcbiAgbG9nRGVzdChzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHYuc3RyaW5nKHN0cmljdENoZWNrKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYGxvZ1RvQ29uc29sZWAgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbFxyXG4gICAqIHN0cmljdGVyIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgdGhlIGBib29sZWFuYCB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gbG9nVG9Db25zb2xlXHJcbiAgICpcclxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IHN0cmljdENoZWNrIC0gRGV0ZXJtaW5lcyBpZiBzdHJpY3RlciB2YWxpZGF0aW9uIHNob3VsZFxyXG4gICAqIGJlIGFwcGxpZWQuXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9IEEgWm9kIHNjaGVtYSBvYmplY3QgZm9yIHZhbGlkYXRpbmdcclxuICAgKiB0aGUgYGxvZ1RvQ29uc29sZWAgb3B0aW9uLlxyXG4gICAqL1xyXG4gIGxvZ1RvQ29uc29sZShzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHYuYm9vbGVhbihzdHJpY3RDaGVjayk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGBsb2dUb0ZpbGVgIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGggYW4gb3B0aW9uYWxcclxuICAgKiBzdHJpY3RlciBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGUgc2FtZSB3b3JrIGFzIHRoZSBgYm9vbGVhbmAgdmFsaWRhdG9yLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIGxvZ1RvRmlsZVxyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nIHRoZSBgbG9nVG9GaWxlYFxyXG4gICAqIG9wdGlvbi5cclxuICAgKi9cclxuICBsb2dUb0ZpbGUoc3RyaWN0Q2hlY2spIHtcclxuICAgIHJldHVybiB2LmJvb2xlYW4oc3RyaWN0Q2hlY2spO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgZW5hYmxlVWlgIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGggYW4gb3B0aW9uYWxcclxuICAgKiBzdHJpY3RlciBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGUgc2FtZSB3b3JrIGFzIHRoZSBgYm9vbGVhbmAgdmFsaWRhdG9yLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIGVuYWJsZVVpXHJcbiAgICpcclxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IHN0cmljdENoZWNrIC0gRGV0ZXJtaW5lcyBpZiBzdHJpY3RlciB2YWxpZGF0aW9uIHNob3VsZFxyXG4gICAqIGJlIGFwcGxpZWQuXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9IEEgWm9kIHNjaGVtYSBvYmplY3QgZm9yIHZhbGlkYXRpbmcgdGhlIGBlbmFibGVVaWBcclxuICAgKiBvcHRpb24uXHJcbiAgICovXHJcbiAgZW5hYmxlVWkoc3RyaWN0Q2hlY2spIHtcclxuICAgIHJldHVybiB2LmJvb2xlYW4oc3RyaWN0Q2hlY2spO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgdWlSb3V0ZWAgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbFxyXG4gICAqIHN0cmljdGVyIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgdGhlIGBzdGFydHNXaXRoYCB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gdWlSb3V0ZVxyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nIHRoZSBgdWlSb3V0ZWBcclxuICAgKiBvcHRpb24uXHJcbiAgICovXHJcbiAgdWlSb3V0ZShzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHYuc3RhcnRzV2l0aChbJy8nXSwgc3RyaWN0Q2hlY2spO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgbm9kZUVudmAgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbFxyXG4gICAqIHN0cmljdGVyIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgdGhlIGBlbnVtYCB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gbm9kZUVudlxyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nIHRoZSBgbm9kZUVudmBcclxuICAgKiBvcHRpb24uXHJcbiAgICovXHJcbiAgbm9kZUVudihzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHYuZW51bShbJ2RldmVsb3BtZW50JywgJ3Byb2R1Y3Rpb24nLCAndGVzdCddLCBzdHJpY3RDaGVjayk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGBsaXN0ZW5Ub1Byb2Nlc3NFeGl0c2AgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aFxyXG4gICAqIGFuIG9wdGlvbmFsIHN0cmljdGVyIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgdGhlIGBib29sZWFuYCB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gbGlzdGVuVG9Qcm9jZXNzRXhpdHNcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZ1xyXG4gICAqIHRoZSBgbGlzdGVuVG9Qcm9jZXNzRXhpdHNgIG9wdGlvbi5cclxuICAgKi9cclxuICBsaXN0ZW5Ub1Byb2Nlc3NFeGl0cyhzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHYuYm9vbGVhbihzdHJpY3RDaGVjayk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGBub0xvZ29gIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGggYW4gb3B0aW9uYWxcclxuICAgKiBzdHJpY3RlciBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGUgc2FtZSB3b3JrIGFzIHRoZSBgYm9vbGVhbmAgdmFsaWRhdG9yLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIG5vTG9nb1xyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nIHRoZSBgbm9Mb2dvYFxyXG4gICAqIG9wdGlvbi5cclxuICAgKi9cclxuICBub0xvZ28oc3RyaWN0Q2hlY2spIHtcclxuICAgIHJldHVybiB2LmJvb2xlYW4oc3RyaWN0Q2hlY2spO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgaGFyZFJlc2V0UGFnZWAgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbFxyXG4gICAqIHN0cmljdGVyIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgdGhlIGBib29sZWFuYCB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gaGFyZFJlc2V0UGFnZVxyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nXHJcbiAgICogdGhlIGBoYXJkUmVzZXRQYWdlYCBvcHRpb24uXHJcbiAgICovXHJcbiAgaGFyZFJlc2V0UGFnZShzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHYuYm9vbGVhbihzdHJpY3RDaGVjayk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGBicm93c2VyU2hlbGxNb2RlYCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoIGFuIG9wdGlvbmFsXHJcbiAgICogc3RyaWN0ZXIgY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhlIHNhbWUgd29yayBhcyB0aGUgYGJvb2xlYW5gIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiBicm93c2VyU2hlbGxNb2RlXHJcbiAgICpcclxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IHN0cmljdENoZWNrIC0gRGV0ZXJtaW5lcyBpZiBzdHJpY3RlciB2YWxpZGF0aW9uIHNob3VsZFxyXG4gICAqIGJlIGFwcGxpZWQuXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9IEEgWm9kIHNjaGVtYSBvYmplY3QgZm9yIHZhbGlkYXRpbmdcclxuICAgKiB0aGUgYGJyb3dzZXJTaGVsbE1vZGVgIG9wdGlvbi5cclxuICAgKi9cclxuICBicm93c2VyU2hlbGxNb2RlKHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gdi5ib29sZWFuKHN0cmljdENoZWNrKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYGVuYWJsZURlYnVnYCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoIGFuIG9wdGlvbmFsXHJcbiAgICogc3RyaWN0ZXIgY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhlIHNhbWUgd29yayBhcyB0aGUgYGJvb2xlYW5gIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiBlbmFibGVEZWJ1Z1xyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nIHRoZSBgZW5hYmxlRGVidWdgXHJcbiAgICogb3B0aW9uLlxyXG4gICAqL1xyXG4gIGVuYWJsZURlYnVnKHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gdi5ib29sZWFuKHN0cmljdENoZWNrKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYGhlYWRsZXNzYCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoIGFuIG9wdGlvbmFsXHJcbiAgICogc3RyaWN0ZXIgY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhlIHNhbWUgd29yayBhcyB0aGUgYGJvb2xlYW5gIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiBoZWFkbGVzc1xyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nIHRoZSBgaGVhZGxlc3NgXHJcbiAgICogb3B0aW9uLlxyXG4gICAqL1xyXG4gIGhlYWRsZXNzKHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gdi5ib29sZWFuKHN0cmljdENoZWNrKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYGRldnRvb2xzYCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoIGFuIG9wdGlvbmFsXHJcbiAgICogc3RyaWN0ZXIgY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhlIHNhbWUgd29yayBhcyB0aGUgYGJvb2xlYW5gIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiBkZXZ0b29sc1xyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nIHRoZSBgZGV2dG9vbHNgXHJcbiAgICogb3B0aW9uLlxyXG4gICAqL1xyXG4gIGRldnRvb2xzKHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gdi5ib29sZWFuKHN0cmljdENoZWNrKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYGxpc3RlblRvQ29uc29sZWAgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbFxyXG4gICAqIHN0cmljdGVyIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgdGhlIGBib29sZWFuYCB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gbGlzdGVuVG9Db25zb2xlXHJcbiAgICpcclxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IHN0cmljdENoZWNrIC0gRGV0ZXJtaW5lcyBpZiBzdHJpY3RlciB2YWxpZGF0aW9uIHNob3VsZFxyXG4gICAqIGJlIGFwcGxpZWQuXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9IEEgWm9kIHNjaGVtYSBvYmplY3QgZm9yIHZhbGlkYXRpbmdcclxuICAgKiB0aGUgYGxpc3RlblRvQ29uc29sZWAgb3B0aW9uLlxyXG4gICAqL1xyXG4gIGxpc3RlblRvQ29uc29sZShzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHYuYm9vbGVhbihzdHJpY3RDaGVjayk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGBkdW1waW9gIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGggYW4gb3B0aW9uYWwgc3RyaWN0ZXJcclxuICAgKiBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGUgc2FtZSB3b3JrIGFzIHRoZSBgYm9vbGVhbmAgdmFsaWRhdG9yLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIGR1bXBpb1xyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nIHRoZSBgZHVtcGlvYFxyXG4gICAqIG9wdGlvbi5cclxuICAgKi9cclxuICBkdW1waW8oc3RyaWN0Q2hlY2spIHtcclxuICAgIHJldHVybiB2LmJvb2xlYW4oc3RyaWN0Q2hlY2spO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgc2xvd01vYCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoIGFuIG9wdGlvbmFsIHN0cmljdGVyXHJcbiAgICogY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhlIHNhbWUgd29yayBhcyB0aGUgYG5vbk5lZ2F0aXZlTnVtYFxyXG4gICAqIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiBzbG93TW9cclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZyB0aGUgYHNsb3dNb2BcclxuICAgKiBvcHRpb24uXHJcbiAgICovXHJcbiAgc2xvd01vKHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gdi5ub25OZWdhdGl2ZU51bShzdHJpY3RDaGVjayk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGBkZWJ1Z2dpbmdQb3J0YCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoIGFuIG9wdGlvbmFsXHJcbiAgICogc3RyaWN0ZXIgY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhlIHNhbWUgd29yayBhcyB0aGUgYG5vbk5lZ2F0aXZlTnVtYFxyXG4gICAqIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiBkZWJ1Z2dpbmdQb3J0XHJcbiAgICpcclxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IHN0cmljdENoZWNrIC0gRGV0ZXJtaW5lcyBpZiBzdHJpY3RlciB2YWxpZGF0aW9uIHNob3VsZFxyXG4gICAqIGJlIGFwcGxpZWQuXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9IEEgWm9kIHNjaGVtYSBvYmplY3QgZm9yIHZhbGlkYXRpbmdcclxuICAgKiB0aGUgYGRlYnVnZ2luZ1BvcnRgIG9wdGlvbi5cclxuICAgKi9cclxuICBkZWJ1Z2dpbmdQb3J0KHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gdi5ub25OZWdhdGl2ZU51bShzdHJpY3RDaGVjayk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGByZXF1ZXN0SWRgIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGggYW4gb3B0aW9uYWxcclxuICAgKiBzdHJpY3RlciBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGUgc2FtZSB3b3JrIGFzIHRoZSBgc3RyaW5nYCB2YWxpZGF0b3IuXHJcbiAgICogQWRkaXRpb25hbGx5LCBpdCBtdXN0IGJlIGEgc3RyaW5naWZpZWQgVVVJRCBvciBjYW4gYmUgbnVsbC5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiByZXF1ZXN0SWRcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZyB0aGUgYHJlcXVlc3RJZGBcclxuICAgKiBvcHRpb24uXHJcbiAgICovXHJcbiAgcmVxdWVzdElkKCkge1xyXG4gICAgcmV0dXJuIChcclxuICAgICAgelxyXG4gICAgICAgIC5zdHJpbmcoKVxyXG4gICAgICAgIC8vLyBUTyBETzogQ29ycmVjdFxyXG4gICAgICAgIC51dWlkKHsgbWVzc2FnZTogJ1RoZSB2YWx1ZSBtdXN0IGJlIGEgc3RyaW5naWZpZWQgVVVJRCcgfSlcclxuICAgICAgICAubnVsbGFibGUoKVxyXG4gICAgKTtcclxuICB9XHJcbn07XHJcblxyXG4vLyBTY2hlbWEgZm9yIHRoZSBwdXBwZXRlZXIgc2VjdGlvbiBvZiBvcHRpb25zXHJcbmNvbnN0IFB1cHBldGVlclNjaGVtYSA9IChzdHJpY3RDaGVjaykgPT5cclxuICB6XHJcbiAgICAub2JqZWN0KHtcclxuICAgICAgYXJnczogY29uZmlnLmFyZ3Moc3RyaWN0Q2hlY2spXHJcbiAgICB9KVxyXG4gICAgLnBhcnRpYWwoKTtcclxuXHJcbi8vIFNjaGVtYSBmb3IgdGhlIGhpZ2hjaGFydHMgc2VjdGlvbiBvZiBvcHRpb25zXHJcbmNvbnN0IEhpZ2hjaGFydHNTY2hlbWEgPSAoc3RyaWN0Q2hlY2spID0+XHJcbiAgelxyXG4gICAgLm9iamVjdCh7XHJcbiAgICAgIHZlcnNpb246IGNvbmZpZy52ZXJzaW9uKHN0cmljdENoZWNrKSxcclxuICAgICAgY2RuVXJsOiBjb25maWcuY2RuVXJsKHN0cmljdENoZWNrKSxcclxuICAgICAgZm9yY2VGZXRjaDogY29uZmlnLmZvcmNlRmV0Y2goc3RyaWN0Q2hlY2spLFxyXG4gICAgICBjYWNoZVBhdGg6IGNvbmZpZy5jYWNoZVBhdGgoc3RyaWN0Q2hlY2spLFxyXG4gICAgICBjb3JlU2NyaXB0czogY29uZmlnLmNvcmVTY3JpcHRzKHN0cmljdENoZWNrKSxcclxuICAgICAgbW9kdWxlU2NyaXB0czogY29uZmlnLm1vZHVsZVNjcmlwdHMoc3RyaWN0Q2hlY2spLFxyXG4gICAgICBpbmRpY2F0b3JTY3JpcHRzOiBjb25maWcuaW5kaWNhdG9yU2NyaXB0cyhzdHJpY3RDaGVjayksXHJcbiAgICAgIGN1c3RvbVNjcmlwdHM6IGNvbmZpZy5jdXN0b21TY3JpcHRzKHN0cmljdENoZWNrKVxyXG4gICAgfSlcclxuICAgIC5wYXJ0aWFsKCk7XHJcblxyXG4vLyBTY2hlbWEgZm9yIHRoZSBleHBvcnQgc2VjdGlvbiBvZiBvcHRpb25zXHJcbmNvbnN0IEV4cG9ydFNjaGVtYSA9IChzdHJpY3RDaGVjaykgPT5cclxuICB6XHJcbiAgICAub2JqZWN0KHtcclxuICAgICAgaW5maWxlOiBjb25maWcuaW5maWxlKHN0cmljdENoZWNrKSxcclxuICAgICAgaW5zdHI6IGNvbmZpZy5pbnN0cigpLFxyXG4gICAgICBvcHRpb25zOiBjb25maWcub3B0aW9ucygpLFxyXG4gICAgICBzdmc6IGNvbmZpZy5zdmcoKSxcclxuICAgICAgb3V0ZmlsZTogY29uZmlnLm91dGZpbGUoc3RyaWN0Q2hlY2spLFxyXG4gICAgICB0eXBlOiBjb25maWcudHlwZShzdHJpY3RDaGVjayksXHJcbiAgICAgIGNvbnN0cjogY29uZmlnLmNvbnN0cihzdHJpY3RDaGVjayksXHJcbiAgICAgIGI2NDogY29uZmlnLmI2NChzdHJpY3RDaGVjayksXHJcbiAgICAgIG5vRG93bmxvYWQ6IGNvbmZpZy5ub0Rvd25sb2FkKHN0cmljdENoZWNrKSxcclxuICAgICAgZGVmYXVsdEhlaWdodDogY29uZmlnLmRlZmF1bHRIZWlnaHQoc3RyaWN0Q2hlY2spLFxyXG4gICAgICBkZWZhdWx0V2lkdGg6IGNvbmZpZy5kZWZhdWx0V2lkdGgoc3RyaWN0Q2hlY2spLFxyXG4gICAgICBkZWZhdWx0U2NhbGU6IGNvbmZpZy5kZWZhdWx0U2NhbGUoc3RyaWN0Q2hlY2spLFxyXG4gICAgICBoZWlnaHQ6IGNvbmZpZy5oZWlnaHQoc3RyaWN0Q2hlY2spLFxyXG4gICAgICB3aWR0aDogY29uZmlnLndpZHRoKHN0cmljdENoZWNrKSxcclxuICAgICAgc2NhbGU6IGNvbmZpZy5zY2FsZShzdHJpY3RDaGVjayksXHJcbiAgICAgIGdsb2JhbE9wdGlvbnM6IGNvbmZpZy5nbG9iYWxPcHRpb25zKCksXHJcbiAgICAgIHRoZW1lT3B0aW9uczogY29uZmlnLnRoZW1lT3B0aW9ucygpLFxyXG4gICAgICBiYXRjaDogY29uZmlnLmJhdGNoKGZhbHNlKSxcclxuICAgICAgcmFzdGVyaXphdGlvblRpbWVvdXQ6IGNvbmZpZy5yYXN0ZXJpemF0aW9uVGltZW91dChzdHJpY3RDaGVjaylcclxuICAgIH0pXHJcbiAgICAucGFydGlhbCgpO1xyXG5cclxuLy8gU2NoZW1hIGZvciB0aGUgY3VzdG9tTG9naWMgc2VjdGlvbiBvZiBvcHRpb25zXHJcbmNvbnN0IEN1c3RvbUxvZ2ljU2NoZW1hID0gKHN0cmljdENoZWNrKSA9PlxyXG4gIHpcclxuICAgIC5vYmplY3Qoe1xyXG4gICAgICBhbGxvd0NvZGVFeGVjdXRpb246IGNvbmZpZy5hbGxvd0NvZGVFeGVjdXRpb24oc3RyaWN0Q2hlY2spLFxyXG4gICAgICBhbGxvd0ZpbGVSZXNvdXJjZXM6IGNvbmZpZy5hbGxvd0ZpbGVSZXNvdXJjZXMoc3RyaWN0Q2hlY2spLFxyXG4gICAgICBjdXN0b21Db2RlOiBjb25maWcuY3VzdG9tQ29kZShmYWxzZSksXHJcbiAgICAgIGNhbGxiYWNrOiBjb25maWcuY2FsbGJhY2soZmFsc2UpLFxyXG4gICAgICByZXNvdXJjZXM6IGNvbmZpZy5yZXNvdXJjZXMoc3RyaWN0Q2hlY2spLFxyXG4gICAgICBsb2FkQ29uZmlnOiBjb25maWcubG9hZENvbmZpZyhmYWxzZSksXHJcbiAgICAgIGNyZWF0ZUNvbmZpZzogY29uZmlnLmNyZWF0ZUNvbmZpZyhmYWxzZSlcclxuICAgIH0pXHJcbiAgICAucGFydGlhbCgpO1xyXG5cclxuLy8gU2NoZW1hIGZvciB0aGUgc2VydmVyLnByb3h5IHNlY3Rpb24gb2Ygb3B0aW9uc1xyXG5jb25zdCBQcm94eVNjaGVtYSA9IChzdHJpY3RDaGVjaykgPT5cclxuICB6XHJcbiAgICAub2JqZWN0KHtcclxuICAgICAgaG9zdDogY29uZmlnLnByb3h5SG9zdChmYWxzZSksXHJcbiAgICAgIHBvcnQ6IGNvbmZpZy5wcm94eVBvcnQoc3RyaWN0Q2hlY2spLFxyXG4gICAgICB0aW1lb3V0OiBjb25maWcucHJveHlUaW1lb3V0KHN0cmljdENoZWNrKVxyXG4gICAgfSlcclxuICAgIC5wYXJ0aWFsKCk7XHJcblxyXG4vLyBTY2hlbWEgZm9yIHRoZSBzZXJ2ZXIucmF0ZUxpbWl0aW5nIHNlY3Rpb24gb2Ygb3B0aW9uc1xyXG5jb25zdCBSYXRlTGltaXRpbmdTY2hlbWEgPSAoc3RyaWN0Q2hlY2spID0+XHJcbiAgelxyXG4gICAgLm9iamVjdCh7XHJcbiAgICAgIGVuYWJsZTogY29uZmlnLmVuYWJsZVJhdGVMaW1pdGluZyhzdHJpY3RDaGVjayksXHJcbiAgICAgIG1heFJlcXVlc3RzOiBjb25maWcubWF4UmVxdWVzdHMoc3RyaWN0Q2hlY2spLFxyXG4gICAgICB3aW5kb3c6IGNvbmZpZy53aW5kb3coc3RyaWN0Q2hlY2spLFxyXG4gICAgICBkZWxheTogY29uZmlnLmRlbGF5KHN0cmljdENoZWNrKSxcclxuICAgICAgdHJ1c3RQcm94eTogY29uZmlnLnRydXN0UHJveHkoc3RyaWN0Q2hlY2spLFxyXG4gICAgICBza2lwS2V5OiBjb25maWcuc2tpcEtleShmYWxzZSksXHJcbiAgICAgIHNraXBUb2tlbjogY29uZmlnLnNraXBUb2tlbihmYWxzZSlcclxuICAgIH0pXHJcbiAgICAucGFydGlhbCgpO1xyXG5cclxuLy8gU2NoZW1hIGZvciB0aGUgc2VydmVyLnNzbCBzZWN0aW9uIG9mIG9wdGlvbnNcclxuY29uc3QgU3NsU2NoZW1hID0gKHN0cmljdENoZWNrKSA9PlxyXG4gIHpcclxuICAgIC5vYmplY3Qoe1xyXG4gICAgICBlbmFibGU6IGNvbmZpZy5lbmFibGVTc2woc3RyaWN0Q2hlY2spLFxyXG4gICAgICBmb3JjZTogY29uZmlnLnNzbEZvcmNlKHN0cmljdENoZWNrKSxcclxuICAgICAgcG9ydDogY29uZmlnLnNzbFBvcnQoc3RyaWN0Q2hlY2spLFxyXG4gICAgICBjZXJ0UGF0aDogY29uZmlnLnNzbENlcnRQYXRoKGZhbHNlKVxyXG4gICAgfSlcclxuICAgIC5wYXJ0aWFsKCk7XHJcblxyXG4vLyBTY2hlbWEgZm9yIHRoZSBzZXJ2ZXIgc2VjdGlvbiBvZiBvcHRpb25zXHJcbmNvbnN0IFNlcnZlclNjaGVtYSA9IChzdHJpY3RDaGVjaykgPT5cclxuICB6Lm9iamVjdCh7XHJcbiAgICBlbmFibGU6IGNvbmZpZy5lbmFibGVTZXJ2ZXIoc3RyaWN0Q2hlY2spLm9wdGlvbmFsKCksXHJcbiAgICBob3N0OiBjb25maWcuaG9zdChzdHJpY3RDaGVjaykub3B0aW9uYWwoKSxcclxuICAgIHBvcnQ6IGNvbmZpZy5wb3J0KHN0cmljdENoZWNrKS5vcHRpb25hbCgpLFxyXG4gICAgYmVuY2htYXJraW5nOiBjb25maWcuc2VydmVyQmVuY2htYXJraW5nKHN0cmljdENoZWNrKS5vcHRpb25hbCgpLFxyXG4gICAgcHJveHk6IFByb3h5U2NoZW1hKHN0cmljdENoZWNrKS5vcHRpb25hbCgpLFxyXG4gICAgcmF0ZUxpbWl0aW5nOiBSYXRlTGltaXRpbmdTY2hlbWEoc3RyaWN0Q2hlY2spLm9wdGlvbmFsKCksXHJcbiAgICBzc2w6IFNzbFNjaGVtYShzdHJpY3RDaGVjaykub3B0aW9uYWwoKVxyXG4gIH0pO1xyXG5cclxuLy8gU2NoZW1hIGZvciB0aGUgcG9vbCBzZWN0aW9uIG9mIG9wdGlvbnNcclxuY29uc3QgUG9vbFNjaGVtYSA9IChzdHJpY3RDaGVjaykgPT5cclxuICB6XHJcbiAgICAub2JqZWN0KHtcclxuICAgICAgbWluV29ya2VyczogY29uZmlnLm1pbldvcmtlcnMoc3RyaWN0Q2hlY2spLFxyXG4gICAgICBtYXhXb3JrZXJzOiBjb25maWcubWF4V29ya2VycyhzdHJpY3RDaGVjayksXHJcbiAgICAgIHdvcmtMaW1pdDogY29uZmlnLndvcmtMaW1pdChzdHJpY3RDaGVjayksXHJcbiAgICAgIGFjcXVpcmVUaW1lb3V0OiBjb25maWcuYWNxdWlyZVRpbWVvdXQoc3RyaWN0Q2hlY2spLFxyXG4gICAgICBjcmVhdGVUaW1lb3V0OiBjb25maWcuY3JlYXRlVGltZW91dChzdHJpY3RDaGVjayksXHJcbiAgICAgIGRlc3Ryb3lUaW1lb3V0OiBjb25maWcuZGVzdHJveVRpbWVvdXQoc3RyaWN0Q2hlY2spLFxyXG4gICAgICBpZGxlVGltZW91dDogY29uZmlnLmlkbGVUaW1lb3V0KHN0cmljdENoZWNrKSxcclxuICAgICAgY3JlYXRlUmV0cnlJbnRlcnZhbDogY29uZmlnLmNyZWF0ZVJldHJ5SW50ZXJ2YWwoc3RyaWN0Q2hlY2spLFxyXG4gICAgICByZWFwZXJJbnRlcnZhbDogY29uZmlnLnJlYXBlckludGVydmFsKHN0cmljdENoZWNrKSxcclxuICAgICAgYmVuY2htYXJraW5nOiBjb25maWcucG9vbEJlbmNobWFya2luZyhzdHJpY3RDaGVjaylcclxuICAgIH0pXHJcbiAgICAucGFydGlhbCgpO1xyXG5cclxuLy8gU2NoZW1hIGZvciB0aGUgbG9nZ2luZyBzZWN0aW9uIG9mIG9wdGlvbnNcclxuY29uc3QgTG9nZ2luZ1NjaGVtYSA9IChzdHJpY3RDaGVjaykgPT5cclxuICB6XHJcbiAgICAub2JqZWN0KHtcclxuICAgICAgbGV2ZWw6IGNvbmZpZy5sb2dMZXZlbChzdHJpY3RDaGVjayksXHJcbiAgICAgIGZpbGU6IGNvbmZpZy5sb2dGaWxlKHN0cmljdENoZWNrKSxcclxuICAgICAgZGVzdDogY29uZmlnLmxvZ0Rlc3Qoc3RyaWN0Q2hlY2spLFxyXG4gICAgICB0b0NvbnNvbGU6IGNvbmZpZy5sb2dUb0NvbnNvbGUoc3RyaWN0Q2hlY2spLFxyXG4gICAgICB0b0ZpbGU6IGNvbmZpZy5sb2dUb0ZpbGUoc3RyaWN0Q2hlY2spXHJcbiAgICB9KVxyXG4gICAgLnBhcnRpYWwoKTtcclxuXHJcbi8vIFNjaGVtYSBmb3IgdGhlIHVpIHNlY3Rpb24gb2Ygb3B0aW9uc1xyXG5jb25zdCBVaVNjaGVtYSA9IChzdHJpY3RDaGVjaykgPT5cclxuICB6XHJcbiAgICAub2JqZWN0KHtcclxuICAgICAgZW5hYmxlOiBjb25maWcuZW5hYmxlVWkoc3RyaWN0Q2hlY2spLFxyXG4gICAgICByb3V0ZTogY29uZmlnLnVpUm91dGUoc3RyaWN0Q2hlY2spXHJcbiAgICB9KVxyXG4gICAgLnBhcnRpYWwoKTtcclxuXHJcbi8vIFNjaGVtYSBmb3IgdGhlIG90aGVyIHNlY3Rpb24gb2Ygb3B0aW9uc1xyXG5jb25zdCBPdGhlclNjaGVtYSA9IChzdHJpY3RDaGVjaykgPT5cclxuICB6XHJcbiAgICAub2JqZWN0KHtcclxuICAgICAgbm9kZUVudjogY29uZmlnLm5vZGVFbnYoc3RyaWN0Q2hlY2spLFxyXG4gICAgICBsaXN0ZW5Ub1Byb2Nlc3NFeGl0czogY29uZmlnLmxpc3RlblRvUHJvY2Vzc0V4aXRzKHN0cmljdENoZWNrKSxcclxuICAgICAgbm9Mb2dvOiBjb25maWcubm9Mb2dvKHN0cmljdENoZWNrKSxcclxuICAgICAgaGFyZFJlc2V0UGFnZTogY29uZmlnLmhhcmRSZXNldFBhZ2Uoc3RyaWN0Q2hlY2spLFxyXG4gICAgICBicm93c2VyU2hlbGxNb2RlOiBjb25maWcuYnJvd3NlclNoZWxsTW9kZShzdHJpY3RDaGVjaylcclxuICAgIH0pXHJcbiAgICAucGFydGlhbCgpO1xyXG5cclxuLy8gU2NoZW1hIGZvciB0aGUgZGVidWcgc2VjdGlvbiBvZiBvcHRpb25zXHJcbmNvbnN0IERlYnVnU2NoZW1hID0gKHN0cmljdENoZWNrKSA9PlxyXG4gIHpcclxuICAgIC5vYmplY3Qoe1xyXG4gICAgICBlbmFibGU6IGNvbmZpZy5lbmFibGVEZWJ1ZyhzdHJpY3RDaGVjayksXHJcbiAgICAgIGhlYWRsZXNzOiBjb25maWcuaGVhZGxlc3Moc3RyaWN0Q2hlY2spLFxyXG4gICAgICBkZXZ0b29sczogY29uZmlnLmRldnRvb2xzKHN0cmljdENoZWNrKSxcclxuICAgICAgbGlzdGVuVG9Db25zb2xlOiBjb25maWcubGlzdGVuVG9Db25zb2xlKHN0cmljdENoZWNrKSxcclxuICAgICAgZHVtcGlvOiBjb25maWcuZHVtcGlvKHN0cmljdENoZWNrKSxcclxuICAgICAgc2xvd01vOiBjb25maWcuc2xvd01vKHN0cmljdENoZWNrKSxcclxuICAgICAgZGVidWdnaW5nUG9ydDogY29uZmlnLmRlYnVnZ2luZ1BvcnQoc3RyaWN0Q2hlY2spXHJcbiAgICB9KVxyXG4gICAgLnBhcnRpYWwoKTtcclxuXHJcbi8vLy9cclxuLy8gLy8gU2NoZW1hIGZvciB0aGUgcGF5bG9hZCBzZWN0aW9uIG9mIG9wdGlvbnNcclxuLy8gY29uc3QgUGF5bG9hZFNjaGVtYSA9ICgpID0+XHJcbi8vICAgelxyXG4vLyAgICAgLm9iamVjdCh7XHJcbi8vICAgICAgIHJlcXVlc3RJZDogY29uZmlnLnJlcXVlc3RJZCgpXHJcbi8vICAgICB9KVxyXG4vLyAgICAgLnBhcnRpYWwoKTtcclxuLy8vL1xyXG5cclxuLy8gU3RyaWN0IHNjaGVtYSBmb3IgdGhlIGNvbmZpZ1xyXG5leHBvcnQgY29uc3QgU3RyaWN0Q29uZmlnU2NoZW1hID0gei5vYmplY3Qoe1xyXG4gIHB1cHBldGVlcjogUHVwcGV0ZWVyU2NoZW1hKHRydWUpLFxyXG4gIGhpZ2hjaGFydHM6IEhpZ2hjaGFydHNTY2hlbWEodHJ1ZSksXHJcbiAgZXhwb3J0OiBFeHBvcnRTY2hlbWEodHJ1ZSksXHJcbiAgY3VzdG9tTG9naWM6IEN1c3RvbUxvZ2ljU2NoZW1hKHRydWUpLFxyXG4gIHNlcnZlcjogU2VydmVyU2NoZW1hKHRydWUpLFxyXG4gIHBvb2w6IFBvb2xTY2hlbWEodHJ1ZSksXHJcbiAgbG9nZ2luZzogTG9nZ2luZ1NjaGVtYSh0cnVlKSxcclxuICB1aTogVWlTY2hlbWEodHJ1ZSksXHJcbiAgb3RoZXI6IE90aGVyU2NoZW1hKHRydWUpLFxyXG4gIGRlYnVnOiBEZWJ1Z1NjaGVtYSh0cnVlKVxyXG4gIC8vLy8gcGF5bG9hZDogUGF5bG9hZFNjaGVtYSgpXHJcbn0pO1xyXG5cclxuLy8gTG9vc2Ugc2NoZW1hIGZvciB0aGUgY29uZmlnXHJcbmV4cG9ydCBjb25zdCBMb29zZUNvbmZpZ1NjaGVtYSA9IHoub2JqZWN0KHtcclxuICBwdXBwZXRlZXI6IFB1cHBldGVlclNjaGVtYShmYWxzZSksXHJcbiAgaGlnaGNoYXJ0czogSGlnaGNoYXJ0c1NjaGVtYShmYWxzZSksXHJcbiAgZXhwb3J0OiBFeHBvcnRTY2hlbWEoZmFsc2UpLFxyXG4gIGN1c3RvbUxvZ2ljOiBDdXN0b21Mb2dpY1NjaGVtYShmYWxzZSksXHJcbiAgc2VydmVyOiBTZXJ2ZXJTY2hlbWEoZmFsc2UpLFxyXG4gIHBvb2w6IFBvb2xTY2hlbWEoZmFsc2UpLFxyXG4gIGxvZ2dpbmc6IExvZ2dpbmdTY2hlbWEoZmFsc2UpLFxyXG4gIHVpOiBVaVNjaGVtYShmYWxzZSksXHJcbiAgb3RoZXI6IE90aGVyU2NoZW1hKGZhbHNlKSxcclxuICBkZWJ1ZzogRGVidWdTY2hlbWEoZmFsc2UpXHJcbiAgLy8vLyBwYXlsb2FkOiBQYXlsb2FkU2NoZW1hKClcclxufSk7XHJcblxyXG4vLyBTY2hlbWEgZm9yIHRoZSBlbnZpcm9ubWVudCB2YXJpYWJsZXMgY29uZmlnXHJcbmV4cG9ydCBjb25zdCBFbnZTY2hlbWEgPSB6Lm9iamVjdCh7XHJcbiAgLy8gcHVwcGV0ZWVyXHJcbiAgUFVQUEVURUVSX0FSR1M6IGNvbmZpZy5hcmdzKGZhbHNlKSxcclxuXHJcbiAgLy8gaGlnaGNoYXJ0c1xyXG4gIEhJR0hDSEFSVFNfVkVSU0lPTjogY29uZmlnLnZlcnNpb24oZmFsc2UpLFxyXG4gIEhJR0hDSEFSVFNfQ0ROX1VSTDogY29uZmlnLmNkblVybChmYWxzZSksXHJcbiAgSElHSENIQVJUU19GT1JDRV9GRVRDSDogY29uZmlnLmZvcmNlRmV0Y2goZmFsc2UpLFxyXG4gIEhJR0hDSEFSVFNfQ0FDSEVfUEFUSDogY29uZmlnLmNhY2hlUGF0aChmYWxzZSksXHJcbiAgSElHSENIQVJUU19BRE1JTl9UT0tFTjogY29uZmlnLmFkbWluVG9rZW4oZmFsc2UpLFxyXG4gIEhJR0hDSEFSVFNfQ09SRV9TQ1JJUFRTOiBjb25maWcuY29yZVNjcmlwdHMoZmFsc2UpLFxyXG4gIEhJR0hDSEFSVFNfTU9EVUxFX1NDUklQVFM6IGNvbmZpZy5tb2R1bGVTY3JpcHRzKGZhbHNlKSxcclxuICBISUdIQ0hBUlRTX0lORElDQVRPUl9TQ1JJUFRTOiBjb25maWcuaW5kaWNhdG9yU2NyaXB0cyhmYWxzZSksXHJcbiAgSElHSENIQVJUU19DVVNUT01fU0NSSVBUUzogY29uZmlnLmN1c3RvbVNjcmlwdHMoZmFsc2UpLFxyXG5cclxuICAvLyBleHBvcnRcclxuICBFWFBPUlRfSU5GSUxFOiBjb25maWcuaW5maWxlKGZhbHNlKSxcclxuICBFWFBPUlRfSU5TVFI6IGNvbmZpZy5pbnN0cigpLFxyXG4gIEVYUE9SVF9PUFRJT05TOiBjb25maWcub3B0aW9ucygpLFxyXG4gIEVYUE9SVF9TVkc6IGNvbmZpZy5zdmcoKSxcclxuICBFWFBPUlRfQkFUQ0g6IGNvbmZpZy5iYXRjaChmYWxzZSksXHJcbiAgRVhQT1JUX09VVEZJTEU6IGNvbmZpZy5vdXRmaWxlKGZhbHNlKSxcclxuICBFWFBPUlRfVFlQRTogY29uZmlnLnR5cGUoZmFsc2UpLFxyXG4gIEVYUE9SVF9DT05TVFI6IGNvbmZpZy5jb25zdHIoZmFsc2UpLFxyXG4gIEVYUE9SVF9CNjQ6IGNvbmZpZy5iNjQoZmFsc2UpLFxyXG4gIEVYUE9SVF9OT19ET1dOTE9BRDogY29uZmlnLm5vRG93bmxvYWQoZmFsc2UpLFxyXG4gIEVYUE9SVF9IRUlHSFQ6IGNvbmZpZy5oZWlnaHQoZmFsc2UpLFxyXG4gIEVYUE9SVF9XSURUSDogY29uZmlnLndpZHRoKGZhbHNlKSxcclxuICBFWFBPUlRfU0NBTEU6IGNvbmZpZy5zY2FsZShmYWxzZSksXHJcbiAgRVhQT1JUX0RFRkFVTFRfSEVJR0hUOiBjb25maWcuZGVmYXVsdEhlaWdodChmYWxzZSksXHJcbiAgRVhQT1JUX0RFRkFVTFRfV0lEVEg6IGNvbmZpZy5kZWZhdWx0V2lkdGgoZmFsc2UpLFxyXG4gIEVYUE9SVF9ERUZBVUxUX1NDQUxFOiBjb25maWcuZGVmYXVsdFNjYWxlKGZhbHNlKSxcclxuICBFWFBPUlRfR0xPQkFMX09QVElPTlM6IGNvbmZpZy5nbG9iYWxPcHRpb25zKCksXHJcbiAgRVhQT1JUX1RIRU1FX09QVElPTlM6IGNvbmZpZy50aGVtZU9wdGlvbnMoKSxcclxuICBFWFBPUlRfUkFTVEVSSVpBVElPTl9USU1FT1VUOiBjb25maWcucmFzdGVyaXphdGlvblRpbWVvdXQoZmFsc2UpLFxyXG5cclxuICAvLyBjdXN0b21cclxuICBDVVNUT01fTE9HSUNfQUxMT1dfQ09ERV9FWEVDVVRJT046IGNvbmZpZy5hbGxvd0NvZGVFeGVjdXRpb24oZmFsc2UpLFxyXG4gIENVU1RPTV9MT0dJQ19BTExPV19GSUxFX1JFU09VUkNFUzogY29uZmlnLmFsbG93RmlsZVJlc291cmNlcyhmYWxzZSksXHJcbiAgQ1VTVE9NX0xPR0lDX0NVU1RPTV9DT0RFOiBjb25maWcuY3VzdG9tQ29kZShmYWxzZSksXHJcbiAgQ1VTVE9NX0xPR0lDX0NBTExCQUNLOiBjb25maWcuY2FsbGJhY2soZmFsc2UpLFxyXG4gIENVU1RPTV9MT0dJQ19SRVNPVVJDRVM6IGNvbmZpZy5yZXNvdXJjZXMoZmFsc2UpLFxyXG4gIENVU1RPTV9MT0dJQ19MT0FEX0NPTkZJRzogY29uZmlnLmxvYWRDb25maWcoZmFsc2UpLFxyXG4gIENVU1RPTV9MT0dJQ19DUkVBVEVfQ09ORklHOiBjb25maWcuY3JlYXRlQ29uZmlnKGZhbHNlKSxcclxuXHJcbiAgLy8gc2VydmVyXHJcbiAgU0VSVkVSX0VOQUJMRTogY29uZmlnLmVuYWJsZVNlcnZlcihmYWxzZSksXHJcbiAgU0VSVkVSX0hPU1Q6IGNvbmZpZy5ob3N0KGZhbHNlKSxcclxuICBTRVJWRVJfUE9SVDogY29uZmlnLnBvcnQoZmFsc2UpLFxyXG4gIFNFUlZFUl9VUExPQURfTElNSVQ6IGNvbmZpZy51cGxvYWRMaW1pdChmYWxzZSksXHJcbiAgU0VSVkVSX0JFTkNITUFSS0lORzogY29uZmlnLnNlcnZlckJlbmNobWFya2luZyhmYWxzZSksXHJcblxyXG4gIC8vIHNlcnZlciBwcm94eVxyXG4gIFNFUlZFUl9QUk9YWV9IT1NUOiBjb25maWcucHJveHlIb3N0KGZhbHNlKSxcclxuICBTRVJWRVJfUFJPWFlfUE9SVDogY29uZmlnLnByb3h5UG9ydChmYWxzZSksXHJcbiAgU0VSVkVSX1BST1hZX1RJTUVPVVQ6IGNvbmZpZy5wcm94eVRpbWVvdXQoZmFsc2UpLFxyXG5cclxuICAvLyBzZXJ2ZXIgcmF0ZSBsaW1pdGluZ1xyXG4gIFNFUlZFUl9SQVRFX0xJTUlUSU5HX0VOQUJMRTogY29uZmlnLmVuYWJsZVJhdGVMaW1pdGluZyhmYWxzZSksXHJcbiAgU0VSVkVSX1JBVEVfTElNSVRJTkdfTUFYX1JFUVVFU1RTOiBjb25maWcubWF4UmVxdWVzdHMoZmFsc2UpLFxyXG4gIFNFUlZFUl9SQVRFX0xJTUlUSU5HX1dJTkRPVzogY29uZmlnLndpbmRvdyhmYWxzZSksXHJcbiAgU0VSVkVSX1JBVEVfTElNSVRJTkdfREVMQVk6IGNvbmZpZy5kZWxheShmYWxzZSksXHJcbiAgU0VSVkVSX1JBVEVfTElNSVRJTkdfVFJVU1RfUFJPWFk6IGNvbmZpZy50cnVzdFByb3h5KGZhbHNlKSxcclxuICBTRVJWRVJfUkFURV9MSU1JVElOR19TS0lQX0tFWTogY29uZmlnLnNraXBLZXkoZmFsc2UpLFxyXG4gIFNFUlZFUl9SQVRFX0xJTUlUSU5HX1NLSVBfVE9LRU46IGNvbmZpZy5za2lwVG9rZW4oZmFsc2UpLFxyXG5cclxuICAvLyBzZXJ2ZXIgc3NsXHJcbiAgU0VSVkVSX1NTTF9FTkFCTEU6IGNvbmZpZy5lbmFibGVTc2woZmFsc2UpLFxyXG4gIFNFUlZFUl9TU0xfRk9SQ0U6IGNvbmZpZy5zc2xGb3JjZShmYWxzZSksXHJcbiAgU0VSVkVSX1NTTF9QT1JUOiBjb25maWcuc3NsUG9ydChmYWxzZSksXHJcbiAgU0VSVkVSX1NTTF9DRVJUX1BBVEg6IGNvbmZpZy5zc2xDZXJ0UGF0aChmYWxzZSksXHJcblxyXG4gIC8vIHBvb2xcclxuICBQT09MX01JTl9XT1JLRVJTOiBjb25maWcubWluV29ya2VycyhmYWxzZSksXHJcbiAgUE9PTF9NQVhfV09SS0VSUzogY29uZmlnLm1heFdvcmtlcnMoZmFsc2UpLFxyXG4gIFBPT0xfV09SS19MSU1JVDogY29uZmlnLndvcmtMaW1pdChmYWxzZSksXHJcbiAgUE9PTF9BQ1FVSVJFX1RJTUVPVVQ6IGNvbmZpZy5hY3F1aXJlVGltZW91dChmYWxzZSksXHJcbiAgUE9PTF9DUkVBVEVfVElNRU9VVDogY29uZmlnLmNyZWF0ZVRpbWVvdXQoZmFsc2UpLFxyXG4gIFBPT0xfREVTVFJPWV9USU1FT1VUOiBjb25maWcuZGVzdHJveVRpbWVvdXQoZmFsc2UpLFxyXG4gIFBPT0xfSURMRV9USU1FT1VUOiBjb25maWcuaWRsZVRpbWVvdXQoZmFsc2UpLFxyXG4gIFBPT0xfQ1JFQVRFX1JFVFJZX0lOVEVSVkFMOiBjb25maWcuY3JlYXRlUmV0cnlJbnRlcnZhbChmYWxzZSksXHJcbiAgUE9PTF9SRUFQRVJfSU5URVJWQUw6IGNvbmZpZy5yZWFwZXJJbnRlcnZhbChmYWxzZSksXHJcbiAgUE9PTF9CRU5DSE1BUktJTkc6IGNvbmZpZy5wb29sQmVuY2htYXJraW5nKGZhbHNlKSxcclxuXHJcbiAgLy8gbG9nZ2luZ1xyXG4gIExPR0dJTkdfTEVWRUw6IGNvbmZpZy5sb2dMZXZlbChmYWxzZSksXHJcbiAgTE9HR0lOR19GSUxFOiBjb25maWcubG9nRmlsZShmYWxzZSksXHJcbiAgTE9HR0lOR19ERVNUOiBjb25maWcubG9nRGVzdChmYWxzZSksXHJcbiAgTE9HR0lOR19UT19DT05TT0xFOiBjb25maWcubG9nVG9Db25zb2xlKGZhbHNlKSxcclxuICBMT0dHSU5HX1RPX0ZJTEU6IGNvbmZpZy5sb2dUb0ZpbGUoZmFsc2UpLFxyXG5cclxuICAvLyB1aVxyXG4gIFVJX0VOQUJMRTogY29uZmlnLmVuYWJsZVVpKGZhbHNlKSxcclxuICBVSV9ST1VURTogY29uZmlnLnVpUm91dGUoZmFsc2UpLFxyXG5cclxuICAvLyBvdGhlclxyXG4gIE9USEVSX05PREVfRU5WOiBjb25maWcubm9kZUVudihmYWxzZSksXHJcbiAgT1RIRVJfTElTVEVOX1RPX1BST0NFU1NfRVhJVFM6IGNvbmZpZy5saXN0ZW5Ub1Byb2Nlc3NFeGl0cyhmYWxzZSksXHJcbiAgT1RIRVJfTk9fTE9HTzogY29uZmlnLm5vTG9nbyhmYWxzZSksXHJcbiAgT1RIRVJfSEFSRF9SRVNFVF9QQUdFOiBjb25maWcuaGFyZFJlc2V0UGFnZShmYWxzZSksXHJcbiAgT1RIRVJfQlJPV1NFUl9TSEVMTF9NT0RFOiBjb25maWcuYnJvd3NlclNoZWxsTW9kZShmYWxzZSksXHJcblxyXG4gIC8vIGRlYnVnZ2VyXHJcbiAgREVCVUdfRU5BQkxFOiBjb25maWcuZW5hYmxlRGVidWcoZmFsc2UpLFxyXG4gIERFQlVHX0hFQURMRVNTOiBjb25maWcuaGVhZGxlc3MoZmFsc2UpLFxyXG4gIERFQlVHX0RFVlRPT0xTOiBjb25maWcuZGV2dG9vbHMoZmFsc2UpLFxyXG4gIERFQlVHX0xJU1RFTl9UT19DT05TT0xFOiBjb25maWcubGlzdGVuVG9Db25zb2xlKGZhbHNlKSxcclxuICBERUJVR19EVU1QSU86IGNvbmZpZy5kdW1waW8oZmFsc2UpLFxyXG4gIERFQlVHX1NMT1dfTU86IGNvbmZpZy5zbG93TW8oZmFsc2UpLFxyXG4gIERFQlVHX0RFQlVHR0lOR19QT1JUOiBjb25maWcuZGVidWdnaW5nUG9ydChmYWxzZSlcclxufSk7XHJcblxyXG4vKipcclxuICogVmFsaWRhdGVzIHRoZSBlbnZpcm9ubWVudCB2YXJpYWJsZXMgb3B0aW9ucyB1c2luZyB0aGUgRW52U2NoZW1hLlxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gcHJvY2Vzcy5lbnYgLSBUaGUgY29uZmlndXJhdGlvbiBvcHRpb25zIGZyb20gZW52aXJvbm1lbnRcclxuICogdmFyaWFibGVzIGZpbGUgdG8gdmFsaWRhdGUuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtPYmplY3R9IFRoZSBwYXJzZWQgYW5kIHZhbGlkYXRlZCBlbnZpcm9ubWVudCB2YXJpYWJsZXMuXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgZW52cyA9IEVudlNjaGVtYS5wYXJ0aWFsKCkucGFyc2UocHJvY2Vzcy5lbnYpO1xyXG5cclxuLyoqXHJcbiAqIFZhbGlkYXRlcyB0aGUgY29uZmlndXJhdGlvbiBvcHRpb25zIHVzaW5nIHRoZSBgU3RyaWN0Q29uZmlnU2NoZW1hYC5cclxuICpcclxuICogQGZ1bmN0aW9uIHN0cmljdFZhbGlkYXRlXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBjb25maWdPcHRpb25zIC0gVGhlIGNvbmZpZ3VyYXRpb24gb3B0aW9ucyB0byB2YWxpZGF0ZS5cclxuICpcclxuICogQHJldHVybnMge09iamVjdH0gVGhlIHBhcnNlZCBhbmQgdmFsaWRhdGVkIGNvbmZpZ3VyYXRpb24gb3B0aW9ucy5cclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiBzdHJpY3RWYWxpZGF0ZShjb25maWdPcHRpb25zKSB7XHJcbiAgcmV0dXJuIFN0cmljdENvbmZpZ1NjaGVtYS5wYXJ0aWFsKCkucGFyc2UoY29uZmlnT3B0aW9ucyk7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBWYWxpZGF0ZXMgdGhlIGNvbmZpZ3VyYXRpb24gb3B0aW9ucyB1c2luZyB0aGUgYExvb3NlQ29uZmlnU2NoZW1hYC5cclxuICpcclxuICogQGZ1bmN0aW9uIGxvb3NlVmFsaWRhdGVcclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IGNvbmZpZ09wdGlvbnMgLSBUaGUgY29uZmlndXJhdGlvbiBvcHRpb25zIHRvIHZhbGlkYXRlLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7T2JqZWN0fSBUaGUgcGFyc2VkIGFuZCB2YWxpZGF0ZWQgY29uZmlndXJhdGlvbiBvcHRpb25zLlxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIGxvb3NlVmFsaWRhdGUoY29uZmlnT3B0aW9ucykge1xyXG4gIHJldHVybiBMb29zZUNvbmZpZ1NjaGVtYS5wYXJ0aWFsKCkucGFyc2UoY29uZmlnT3B0aW9ucyk7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBWYWxpZGF0ZXMgYSBwcm92aWRlZCBvcHRpb24gdXNpbmcgdGhlIHNwZWNpZmljIHZhbGlkYXRvciBmcm9tIHRoZSBjb25maWdcclxuICogb2JqZWN0LlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gdmFsaWRhdGVPcHRpb25cclxuICpcclxuICogQHBhcmFtIHtzdHJpbmd9IG5hbWUgLSBUaGUgbmFtZSBvZiBhbiBvcHRpb24gdG8gdmFsaWRhdGUuXHJcbiAqIEBwYXJhbSB7YW55fSBvcHRpb24gLSBUaGUgb3B0aW9uIHRvIHZhbGlkYXRlLlxyXG4gKiBAcGFyYW0ge2Jvb2xlYW59IHN0cmljdENoZWNrIC0gRGV0ZXJtaW5lcyBpZiBzdHJpY3RlciB2YWxpZGF0aW9uIHNob3VsZFxyXG4gKiBiZSBhcHBsaWVkLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7YW55fSBUaGUgcGFyc2VkIGFuZCB2YWxpZGF0ZWQgb3B0aW9uIHZhbHVlLlxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIHZhbGlkYXRlT3B0aW9uKG5hbWUsIG9wdGlvbiwgc3RyaWN0Q2hlY2spIHtcclxuICByZXR1cm4gY29uZmlnW25hbWVdKHN0cmljdENoZWNrKS5wYXJzZShvcHRpb24pO1xyXG59XHJcblxyXG4vKipcclxuICogQ3VzdG9tIGVycm9yIG1hcHBpbmcgZnVuY3Rpb24gZm9yIFpvZCBzY2hlbWEgdmFsaWRhdGlvbi5cclxuICpcclxuICogVGhpcyBmdW5jdGlvbiBjdXN0b21pemVzIHRoZSBlcnJvciBtZXNzYWdlcyBwcm9kdWNlZCBieSBab2Qgc2NoZW1hXHJcbiAqIHZhbGlkYXRpb24sIHByb3ZpZGluZyBtb3JlIHNwZWNpZmljIGFuZCB1c2VyLWZyaWVuZGx5IGZlZWRiYWNrIGJhc2VkIG9uIHRoZVxyXG4gKiBpc3N1ZSB0eXBlIGFuZCBjb250ZXh0LlxyXG4gKlxyXG4gKiBUaGUgZnVuY3Rpb24gbW9kaWZpZXMgdGhlIGVycm9yIG1lc3NhZ2VzIGFzIGZvbGxvd3M6XHJcbiAqXHJcbiAqIC0gRm9yIG1pc3NpbmcgcmVxdWlyZWQgdmFsdWVzICh1bmRlZmluZWQpLCBpdCByZXR1cm5zIGEgbWVzc2FnZSBpbmRpY2F0aW5nXHJcbiAqIHRoYXQgbm8gdmFsdWUgd2FzIHByb3ZpZGVkIGZvciB0aGUgc3BlY2lmaWMgcHJvcGVydHkuXHJcbiAqXHJcbiAqIC0gRm9yIGN1c3RvbSB2YWxpZGF0aW9uIGVycm9ycywgaWYgYSBjdXN0b20gZXJyb3IgbWVzc2FnZSBpcyBwcm92aWRlZCBpbiB0aGVcclxuICogaXNzdWUgcGFyYW1ldGVycywgaXQgaW5jbHVkZXMgdGhpcyBtZXNzYWdlIGFsb25nIHdpdGggdGhlIGludmFsaWQgZGF0YVxyXG4gKiByZWNlaXZlZC5cclxuICpcclxuICogLSBGb3IgYWxsIG90aGVyIGVycm9ycywgaXQgYXBwZW5kcyBwcm9wZXJ0eS1zcGVjaWZpYyBpbmZvcm1hdGlvbiB0byB0aGVcclxuICogZGVmYXVsdCBlcnJvciBtZXNzYWdlIHByb3ZpZGVkIGJ5IFpvZC5cclxuICpcclxuICogQGZ1bmN0aW9uIF9jdXN0b21FcnJvck1hcFxyXG4gKlxyXG4gKiBAcGFyYW0ge3ouWm9kSXNzdWV9IGlzc3VlIC0gVGhlIGlzc3VlIG9iamVjdCByZXByZXNlbnRpbmcgdGhlIHZhbGlkYXRpb25cclxuICogZXJyb3IuXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBjb250ZXh0IC0gVGhlIGNvbnRleHQgb2JqZWN0IHByb3ZpZGluZyBhZGRpdGlvbmFsIGluZm9ybWF0aW9uXHJcbiAqIGFib3V0IHRoZSB2YWxpZGF0aW9uIGVycm9yLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7T2JqZWN0fSBBbiBvYmplY3QgY29udGFpbmluZyB0aGUgY3VzdG9taXplZCBlcnJvciBtZXNzYWdlLlxyXG4gKi9cclxuZnVuY3Rpb24gX2N1c3RvbUVycm9yTWFwKGlzc3VlLCBjb250ZXh0KSB7XHJcbiAgLy8gR2V0IHRoZSBjaGFpbiBvZiBwcm9wZXJ0aWVzIHdoaWNoIGVycm9yIGRpcmVjdGx5IHJlZmVycyB0b1xyXG4gIGNvbnN0IHByb3BlcnR5TmFtZSA9IGlzc3VlLnBhdGguam9pbignLicpO1xyXG5cclxuICAvLyBDcmVhdGUgdGhlIGZpcnN0IHBhcnQgb2YgdGhlIG1lc3NhZ2UgYWJvdXQgdGhlIHByb3BlcnR5IGluZm9ybWF0aW9uXHJcbiAgY29uc3QgcHJvcGVydHlJbmZvID0gYEludmFsaWQgdmFsdWUgZm9yIHRoZSAke3Byb3BlcnR5TmFtZX1gO1xyXG5cclxuICAvLyBNb2RpZmllZCBtZXNzYWdlIGZvciB0aGUgaW52YWxpZCB0eXBlXHJcbiAgaWYgKGlzc3VlLmNvZGUgPT09IHouWm9kSXNzdWVDb2RlLmludmFsaWRfdHlwZSkge1xyXG4gICAgLy8gTW9kaWZpZWQgbWVzc2FnZSBmb3IgdGhlIHJlcXVpcmVkIHZhbHVlc1xyXG4gICAgaWYgKGlzc3VlLnJlY2VpdmVkID09PSB6LlpvZFBhcnNlZFR5cGUudW5kZWZpbmVkKSB7XHJcbiAgICAgIHJldHVybiB7XHJcbiAgICAgICAgbWVzc2FnZTogYCR7cHJvcGVydHlJbmZvfSAtIE5vIHZhbHVlIHdhcyBwcm92aWRlZC5gXHJcbiAgICAgIH07XHJcbiAgICB9XHJcblxyXG4gICAgLy8gTW9kaWZpZWQgbWVzc2FnZSBmb3IgdGhlIHNwZWNpZmljIGludmFsaWQgdHlwZSB3aGVuIHZhbHVlcyBleGlzdFxyXG4gICAgcmV0dXJuIHtcclxuICAgICAgbWVzc2FnZTogYCR7cHJvcGVydHlJbmZvfSAtIEludmFsaWQgdHlwZS4gJHtjb250ZXh0LmRlZmF1bHRFcnJvcn0uYFxyXG4gICAgfTtcclxuICB9XHJcblxyXG4gIC8vIE1vZGlmaWVkIG1lc3NhZ2UgZm9yIHRoZSBjdXN0b20gdmFsaWRhdGlvblxyXG4gIGlmIChpc3N1ZS5jb2RlID09PSB6LlpvZElzc3VlQ29kZS5jdXN0b20pIHtcclxuICAgIC8vIElmIHRoZSBjdXN0b20gbWVzc2FnZSBmb3IgZXJyb3IgZXhpc3QsIGluY2x1ZGUgaXRcclxuICAgIGlmIChpc3N1ZS5wYXJhbXM/LmVycm9yTWVzc2FnZSkge1xyXG4gICAgICByZXR1cm4ge1xyXG4gICAgICAgIG1lc3NhZ2U6IGAke3Byb3BlcnR5SW5mb30gLSAke2lzc3VlLnBhcmFtcz8uZXJyb3JNZXNzYWdlfSwgcmVjZWl2ZWQgJyR7Y29udGV4dC5kYXRhfScuYFxyXG4gICAgICB9O1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgLy8gTW9kaWZpZWQgbWVzc2FnZSBmb3IgdGhlIGludmFsaWQgdW5pb24gZXJyb3JcclxuICBpZiAoaXNzdWUuY29kZSA9PT0gei5ab2RJc3N1ZUNvZGUuaW52YWxpZF91bmlvbikge1xyXG4gICAgLy8gQ3JlYXRlIHRoZSBmaXJzdCBwYXJ0IG9mIHRoZSBtZXNzYWdlIGFib3V0IHRoZSBtdWx0aXBsZSBlcnJvcnNcclxuICAgIGxldCBtZXNzYWdlID0gYE11bHRpcGxlIGVycm9ycyBvY2N1cnJlZCBmb3IgdGhlICR7cHJvcGVydHlOYW1lfTpcXG5gO1xyXG5cclxuICAgIC8vIEN5Y2xlIHRocm91Z2ggYWxsIGVycm9ycyBhbmQgY3JlYXRlIGEgY29ycmVjdCBtZXNzYWdlXHJcbiAgICBpc3N1ZS51bmlvbkVycm9ycy5mb3JFYWNoKCh2YWx1ZSkgPT4ge1xyXG4gICAgICBjb25zdCBpbmRleCA9IHZhbHVlLmlzc3Vlc1swXS5tZXNzYWdlLmluZGV4T2YoJy0nKTtcclxuICAgICAgbWVzc2FnZSArPVxyXG4gICAgICAgIGluZGV4ICE9PSAtMVxyXG4gICAgICAgICAgPyBgJHt2YWx1ZS5pc3N1ZXNbMF0ubWVzc2FnZX1cXG5gLnN1YnN0cmluZyhpbmRleClcclxuICAgICAgICAgIDogYCR7dmFsdWUuaXNzdWVzWzBdLm1lc3NhZ2V9XFxuYDtcclxuICAgIH0pO1xyXG5cclxuICAgIC8vIFJldHVybiB0aGUgZmluYWwgbWVzc2FnZSBmb3IgdGhlIGludmFsaWQgdW5pb24gZXJyb3JcclxuICAgIHJldHVybiB7XHJcbiAgICAgIG1lc3NhZ2VcclxuICAgIH07XHJcbiAgfVxyXG5cclxuICAvLyBSZXR1cm4gdGhlIGRlZmF1bHQgZXJyb3IgbWVzc2FnZSwgZXh0ZW5kZWQgYnkgdGhlIGluZm8gYWJvdXQgdGhlIHByb3BlcnR5XHJcbiAgcmV0dXJuIHtcclxuICAgIG1lc3NhZ2U6IGAke3Byb3BlcnR5SW5mb30gLSAke2NvbnRleHQuZGVmYXVsdEVycm9yfS5gXHJcbiAgfTtcclxufVxyXG5cclxuZXhwb3J0IGRlZmF1bHQge1xyXG4gIFN0cmljdENvbmZpZ1NjaGVtYSxcclxuICBMb29zZUNvbmZpZ1NjaGVtYSxcclxuICBFbnZTY2hlbWEsXHJcbiAgZW52cyxcclxuICBzdHJpY3RWYWxpZGF0ZSxcclxuICBsb29zZVZhbGlkYXRlLFxyXG4gIHZhbGlkYXRlT3B0aW9uXHJcbn07XHJcbiIsIi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXHJcblxyXG5IaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXJcclxuXHJcbkNvcHlyaWdodCAoYykgMjAxNi0yMDI1LCBIaWdoc29mdFxyXG5cclxuTGljZW5jZWQgdW5kZXIgdGhlIE1JVCBsaWNlbmNlLlxyXG5cclxuQWRkaXRpb25hbGx5IGEgdmFsaWQgSGlnaGNoYXJ0cyBsaWNlbnNlIGlzIHJlcXVpcmVkIGZvciB1c2UuXHJcblxyXG5TZWUgTElDRU5TRSBmaWxlIGluIHJvb3QgZm9yIGRldGFpbHMuXHJcblxyXG4qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xyXG5cclxuLyoqXHJcbiAqIEBvdmVydmlldyBNYW5hZ2VzIGNvbmZpZ3VyYXRpb24gZm9yIHRoZSBIaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXIgYnkgbG9hZGluZ1xyXG4gKiBhbmQgbWVyZ2luZyBvcHRpb25zIGZyb20gbXVsdGlwbGUgc291cmNlcywgc3VjaCBhcyBkZWZhdWx0IHNldHRpbmdzLFxyXG4gKiBlbnZpcm9ubWVudCB2YXJpYWJsZXMsIHVzZXItcHJvdmlkZWQgb3B0aW9ucywgYW5kIGNvbW1hbmQtbGluZSBhcmd1bWVudHMuXHJcbiAqIEVuc3VyZXMgdGhlIGdsb2JhbCBvcHRpb25zIGFyZSB1cC10by1kYXRlIHdpdGggdGhlIGhpZ2hlc3QgcHJpb3JpdHkgdmFsdWVzLlxyXG4gKiBQcm92aWRlcyBmdW5jdGlvbnMgZm9yIGFjY2Vzc2luZyBhbmQgdXBkYXRpbmcgY29uZmlndXJhdGlvbi5cclxuICovXHJcblxyXG5pbXBvcnQgeyByZWFkRmlsZVN5bmMgfSBmcm9tICdmcyc7XHJcbmltcG9ydCB7IGpvaW4gfSBmcm9tICdwYXRoJztcclxuXHJcbmltcG9ydCB7IGxvZywgbG9nV2l0aFN0YWNrLCBsb2dab2RJc3N1ZXMgfSBmcm9tICcuL2xvZ2dlci5qcyc7XHJcbmltcG9ydCB7IF9fZGlybmFtZSwgaXNPYmplY3QsIGRlZXBDb3B5LCBnZXRBYnNvbHV0ZVBhdGggfSBmcm9tICcuL3V0aWxzLmpzJztcclxuaW1wb3J0IHsgZW52cywgbG9vc2VWYWxpZGF0ZSwgc3RyaWN0VmFsaWRhdGUgfSBmcm9tICcuL3ZhbGlkYXRpb24uanMnO1xyXG5pbXBvcnQgeyBkZWZhdWx0Q29uZmlnLCBuZXN0ZWRQcm9wcywgYWJzb2x1dGVQcm9wcyB9IGZyb20gJy4vc2NoZW1hcy9jb25maWcuanMnO1xyXG5cclxuLy8gU2V0cyB0aGUgZ2xvYmFsIG9wdGlvbnMgd2l0aCBpbml0aWFsIHZhbHVlcyBmcm9tIHRoZSBkZWZhdWx0IGNvbmZpZ1xyXG5jb25zdCBnbG9iYWxPcHRpb25zID0gX2luaXRHbG9iYWxPcHRpb25zKGRlZmF1bHRDb25maWcpO1xyXG5cclxuLyoqXHJcbiAqIEdldHMgdGhlIHJlZmVyZW5jZSB0byB0aGUgZ2xvYmFsIG9wdGlvbnMgb2YgdGhlIHNlcnZlciBpbnN0YW5jZSBvYmplY3RcclxuICogb3IgaXRzIGNvcHkuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBnZXRPcHRpb25zXHJcbiAqXHJcbiAqIEBwYXJhbSB7Ym9vbGVhbn0gW2dldFJlZmVyZW5jZT10cnVlXSAtIE9wdGlvbmFsIHBhcmFtZXRlciB0byBkZWNpZGUgd2hldGhlclxyXG4gKiB0byByZXR1cm4gdGhlIHJlZmVyZW5jZSB0byB0aGUgZ2xvYmFsIG9wdGlvbnMgb2YgdGhlIHNlcnZlciBpbnN0YW5jZSBvYmplY3RcclxuICogb3IgcmV0dXJuIGEgY29weSBvZiBpdC4gVGhlIGRlZmF1bHQgdmFsdWUgaXMgdHJ1ZS5cclxuICpcclxuICogQHJldHVybnMge09iamVjdH0gVGhlIHJlZmVyZW5jZSB0byB0aGUgZ2xvYmFsIG9wdGlvbnMgb2YgdGhlIHNlcnZlciBpbnN0YW5jZVxyXG4gKiBvYmplY3Qgb3IgaXRzIGNvcHkuXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gZ2V0T3B0aW9ucyhnZXRSZWZlcmVuY2UgPSB0cnVlKSB7XHJcbiAgcmV0dXJuIGdldFJlZmVyZW5jZSA/IGdsb2JhbE9wdGlvbnMgOiBkZWVwQ29weShnbG9iYWxPcHRpb25zKTtcclxufVxyXG5cclxuLyoqXHJcbiAqIFNldHMgdGhlIGdsb2JhbCBvcHRpb25zIG9mIHRoZSBleHBvcnQgc2VydmVyIGluc3RhbmNlLCBrZWVwaW5nIHRoZSBwcmluY2lwbGVcclxuICogb2YgdGhlIG9wdGlvbnMgbG9hZCBwcmlvcml0eSBmcm9tIGFsbCBhdmFpbGFibGUgc291cmNlcy4gSXQgYWNjZXB0cyBvcHRpb25hbFxyXG4gKiBgY3VzdG9tT3B0aW9uc2Agb2JqZWN0IGFuZCBgY2xpQXJnc2AgYXJyYXkgd2l0aCBhcmd1bWVudHMgZnJvbSB0aGUgQ0xJLiBUaGVzZVxyXG4gKiBvcHRpb25zIHdpbGwgYmUgdmFsaWRhdGVkIGFuZCBhcHBsaWVkIGlmIHByb3ZpZGVkLlxyXG4gKlxyXG4gKiBUaGUgcHJpb3JpdHkgb3JkZXIgb2Ygc2V0dGluZyB2YWx1ZXMgaXM6XHJcbiAqXHJcbiAqIDEuIE9wdGlvbnMgZnJvbSB0aGUgYGxpYi9zY2hlbWFzL2NvbmZpZy5qc2AgZmlsZSAoZGVmYXVsdCB2YWx1ZXMpLlxyXG4gKiAyLiBPcHRpb25zIGZyb20gYSBjdXN0b20gSlNPTiBmaWxlIChsb2FkZWQgYnkgdGhlIGBsb2FkQ29uZmlnYCBvcHRpb24pLlxyXG4gKiAzLiBPcHRpb25zIGZyb20gdGhlIGVudmlyb25tZW50IHZhcmlhYmxlcyAodGhlIGAuZW52YCBmaWxlKS5cclxuICogNC4gT3B0aW9ucyBmcm9tIHRoZSBmaXJzdCBwYXJhbWV0ZXIgKGJ5IGRlZmF1bHQgYW4gZW1wdHkgb2JqZWN0KS5cclxuICogNS4gT3B0aW9ucyBmcm9tIHRoZSBDTEkuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBzZXRPcHRpb25zXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBbY3VzdG9tT3B0aW9ucz17fV0gLSBPcHRpb25hbCBjdXN0b20gb3B0aW9ucyBmb3IgYWRkaXRpb25hbFxyXG4gKiBjb25maWd1cmF0aW9uLiBUaGUgZGVmYXVsdCB2YWx1ZSBpcyBhbiBlbXB0eSBvYmplY3QuXHJcbiAqIEBwYXJhbSB7QXJyYXkuPHN0cmluZz59IFtjbGlBcmdzPVtdXSAtIE9wdGlvbmFsIGNvbW1hbmQgbGluZSBhcmd1bWVudHNcclxuICogZm9yIGFkZGl0aW9uYWwgY29uZmlndXJhdGlvbi4gVGhlIGRlZmF1bHQgdmFsdWUgaXMgYW4gZW1wdHkgYXJyYXkuXHJcbiAqIEBwYXJhbSB7Ym9vbGVhbn0gW21vZGlmeUdsb2JhbD1mYWxzZV0gLSBPcHRpb25hbCBwYXJhbWV0ZXIgdG8gZGVjaWRlXHJcbiAqIHdoZXRoZXIgdG8gdXBkYXRlIGFuZCByZXR1cm4gdGhlIHJlZmVyZW5jZSB0byB0aGUgZ2xvYmFsIG9wdGlvbnNcclxuICogb2YgdGhlIHNlcnZlciBpbnN0YW5jZSBvYmplY3Qgb3IgcmV0dXJuIGEgY29weSBvZiBpdC4gVGhlIGRlZmF1bHQgdmFsdWVcclxuICogaXMgZmFsc2UuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtPYmplY3R9IFRoZSB1cGRhdGVkIGdlbmVyYWwgb3B0aW9ucyBvYmplY3QsIHJlZmxlY3RpbmcgdGhlIG1lcmdlZFxyXG4gKiBjb25maWd1cmF0aW9uIGZyb20gYWxsIGF2YWlsYWJsZSBzb3VyY2VzLlxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIHNldE9wdGlvbnMoXHJcbiAgY3VzdG9tT3B0aW9ucyA9IHt9LFxyXG4gIGNsaUFyZ3MgPSBbXSxcclxuICBtb2RpZnlHbG9iYWwgPSBmYWxzZVxyXG4pIHtcclxuICAvLyBPYmplY3QgZm9yIG9wdGlvbnMgbG9hZGVkIHZpYSB0aGUgYGxvYWRDb25maWdgIG9wdGlvblxyXG4gIGxldCBjb25maWdPcHRpb25zID0ge307XHJcblxyXG4gIC8vIE9iamVjdCBmb3Igb3B0aW9ucyBmcm9tIHRoZSBDTElcclxuICBsZXQgY2xpT3B0aW9ucyA9IHt9O1xyXG5cclxuICAvLyBPbmx5IGZvciB0aGUgQ0xJIHVzYWdlXHJcbiAgaWYgKGNsaUFyZ3MubGVuZ3RoKSB7XHJcbiAgICB0cnkge1xyXG4gICAgICAvLyBWYWxpZGF0ZSBvcHRpb25zIGZyb20gdGhlIGN1c3RvbSBKU09OIGxvYWRlZCB2aWEgdGhlIGBsb2FkQ29uZmlnYFxyXG4gICAgICBjb25maWdPcHRpb25zID0gc3RyaWN0VmFsaWRhdGUoX2xvYWRDb25maWdGaWxlKGNsaUFyZ3MpKTtcclxuICAgIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICAgIGxvZ1pvZElzc3VlcyhcclxuICAgICAgICAxLFxyXG4gICAgICAgIGVycm9yLmlzc3VlcyxcclxuICAgICAgICAnW2NvbmZpZ10gQ3VzdG9tIEpTT04gb3B0aW9ucyB2YWxpZGF0aW9uIGVycm9yJ1xyXG4gICAgICApO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgLy8gQXBwbHkgY3VzdG9tIG9wdGlvbnMgaWYgdGhlcmUgYXJlIGFueVxyXG4gIGlmIChjdXN0b21PcHRpb25zICYmIE9iamVjdC5rZXlzKGN1c3RvbU9wdGlvbnMpLmxlbmd0aCAhPT0gMCkge1xyXG4gICAgdHJ5IHtcclxuICAgICAgLy8gVmFsaWRhdGUgY3VzdG9tIG9wdGlvbnMgcHJvdmlkZWQgYnkgdGhlIHVzZXJcclxuICAgICAgY3VzdG9tT3B0aW9ucyA9IHN0cmljdFZhbGlkYXRlKGN1c3RvbU9wdGlvbnMpO1xyXG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICAgbG9nWm9kSXNzdWVzKDEsIGVycm9yLmlzc3VlcywgJ1tjb25maWddIEN1c3RvbSBvcHRpb25zIHZhbGlkYXRpb24gZXJyb3InKTtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIC8vIE9ubHkgZm9yIHRoZSBDTEkgdXNhZ2VcclxuICBpZiAoY2xpQXJncy5sZW5ndGgpIHtcclxuICAgIHRyeSB7XHJcbiAgICAgIC8vIFZhbGlkYXRlIG9wdGlvbnMgZnJvbSB0aGUgQ0xJXHJcbiAgICAgIGNsaU9wdGlvbnMgPSBsb29zZVZhbGlkYXRlKF9wYWlyQXJndW1lbnRWYWx1ZShuZXN0ZWRQcm9wcywgY2xpQXJncykpO1xyXG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICAgbG9nWm9kSXNzdWVzKDEsIGVycm9yLmlzc3VlcywgJ1tjb25maWddIENMSSBvcHRpb25zIHZhbGlkYXRpb24gZXJyb3InKTtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIC8vIEdldCB0aGUgcmVmZXJlbmNlIHRvIHRoZSBnbG9iYWwgb3B0aW9ucyBvYmplY3Qgb3IgYSBjb3B5IG9mIHRoZSBvYmplY3RcclxuICBjb25zdCBnZW5lcmFsT3B0aW9ucyA9IGdldE9wdGlvbnMobW9kaWZ5R2xvYmFsKTtcclxuXHJcbiAgLy8gVXBkYXRlIHZhbHVlcyBvZiB0aGUgZ2VuZXJhbCBvcHRpb25zIHdpdGggdmFsdWVzIGZyb20gZWFjaCBzb3VyY2UgcG9zc2libGVcclxuICBfdXBkYXRlT3B0aW9ucyhcclxuICAgIGRlZmF1bHRDb25maWcsXHJcbiAgICBnZW5lcmFsT3B0aW9ucyxcclxuICAgIGNvbmZpZ09wdGlvbnMsXHJcbiAgICBjdXN0b21PcHRpb25zLFxyXG4gICAgY2xpT3B0aW9uc1xyXG4gICk7XHJcblxyXG4gIC8vIFJldHVybiBvcHRpb25zXHJcbiAgcmV0dXJuIGdlbmVyYWxPcHRpb25zO1xyXG59XHJcblxyXG4vKipcclxuICogTWVyZ2VzIHR3byBzZXRzIG9mIGNvbmZpZ3VyYXRpb24gb3B0aW9ucywgY29uc2lkZXJpbmcgYWJzb2x1dGUgcHJvcGVydGllcy5cclxuICpcclxuICogQGZ1bmN0aW9uIG1lcmdlT3B0aW9uc1xyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gb3JpZ2luYWxPcHRpb25zIC0gT3JpZ2luYWwgY29uZmlndXJhdGlvbiBvcHRpb25zLlxyXG4gKiBAcGFyYW0ge09iamVjdH0gbmV3T3B0aW9ucyAtIE5ldyBjb25maWd1cmF0aW9uIG9wdGlvbnMgdG8gYmUgbWVyZ2VkLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7T2JqZWN0fSBNZXJnZWQgY29uZmlndXJhdGlvbiBvcHRpb25zLlxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIG1lcmdlT3B0aW9ucyhvcmlnaW5hbE9wdGlvbnMsIG5ld09wdGlvbnMpIHtcclxuICAvLyBDaGVjayBpZiB0aGUgYG5ld09wdGlvbnNgIGlzIGEgY29ycmVjdCBvYmplY3RcclxuICBpZiAoaXNPYmplY3QobmV3T3B0aW9ucykpIHtcclxuICAgIGZvciAoY29uc3QgW2tleSwgdmFsdWVdIG9mIE9iamVjdC5lbnRyaWVzKG5ld09wdGlvbnMpKSB7XHJcbiAgICAgIG9yaWdpbmFsT3B0aW9uc1trZXldID1cclxuICAgICAgICBpc09iamVjdCh2YWx1ZSkgJiZcclxuICAgICAgICAhYWJzb2x1dGVQcm9wcy5pbmNsdWRlcyhrZXkpICYmXHJcbiAgICAgICAgb3JpZ2luYWxPcHRpb25zW2tleV0gIT09IHVuZGVmaW5lZFxyXG4gICAgICAgICAgPyBtZXJnZU9wdGlvbnMob3JpZ2luYWxPcHRpb25zW2tleV0sIHZhbHVlKVxyXG4gICAgICAgICAgOiB2YWx1ZSAhPT0gdW5kZWZpbmVkXHJcbiAgICAgICAgICAgID8gdmFsdWVcclxuICAgICAgICAgICAgOiBvcmlnaW5hbE9wdGlvbnNba2V5XTtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIC8vIFJldHVybiB0aGUgcmVzdWx0IG9wdGlvbnNcclxuICByZXR1cm4gb3JpZ2luYWxPcHRpb25zO1xyXG59XHJcblxyXG4vKipcclxuICogTWFwcyBvbGQtc3RydWN0dXJlZCBjb25maWd1cmF0aW9uIG9wdGlvbnMgKFBoYW50b21KUykgdG8gYSBuZXcgZm9ybWF0XHJcbiAqIChQdXBwZXRlZXIpLiBUaGlzIGZ1bmN0aW9uIGNvbnZlcnRzIGZsYXQsIG9sZC1zdHJ1Y3R1cmVkIG9wdGlvbnMgaW50b1xyXG4gKiBhIG5ldywgbmVzdGVkIGNvbmZpZ3VyYXRpb24gZm9ybWF0IGJhc2VkIG9uIGEgcHJlZGVmaW5lZCBtYXBwaW5nXHJcbiAqIChgbmVzdGVkUHJvcHNgKS4gVGhlIG5ldyBmb3JtYXQgaXMgdXNlZCBmb3IgUHVwcGV0ZWVyLCB3aGlsZSB0aGUgb2xkIGZvcm1hdFxyXG4gKiB3YXMgdXNlZCBmb3IgUGhhbnRvbUpTLlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gbWFwVG9OZXdPcHRpb25zXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBvbGRPcHRpb25zIC0gVGhlIG9sZCwgZmxhdCBjb25maWd1cmF0aW9uIG9wdGlvbnNcclxuICogdG8gYmUgY29udmVydGVkLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7T2JqZWN0fSBBIG5ldyBvYmplY3QgY29udGFpbmluZyBvcHRpb25zIHN0cnVjdHVyZWQgYWNjb3JkaW5nXHJcbiAqIHRvIHRoZSBtYXBwaW5nIGRlZmluZWQgaW4gYG5lc3RlZFByb3BzYCBvciBhbiBlbXB0eSBvYmplY3QgaWYgdGhlIHByb3ZpZGVkXHJcbiAqIGBvbGRPcHRpb25zYCBpcyBub3QgYSBjb3JyZWN0IG9iamVjdC5cclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiBtYXBUb05ld09wdGlvbnMob2xkT3B0aW9ucykge1xyXG4gIC8vIEFuIG9iamVjdCBmb3IgdGhlIG5ldyBzdHJ1Y3R1cmVkIG9wdGlvbnNcclxuICBjb25zdCBuZXdPcHRpb25zID0ge307XHJcblxyXG4gIC8vIENoZWNrIGlmIHByb3ZpZGVkIHZhbHVlIGlzIGEgY29ycmVjdCBvYmplY3RcclxuICBpZiAoT2JqZWN0LnByb3RvdHlwZS50b1N0cmluZy5jYWxsKG9sZE9wdGlvbnMpID09PSAnW29iamVjdCBPYmplY3RdJykge1xyXG4gICAgLy8gSXRlcmF0ZSBvdmVyIGVhY2gga2V5LXZhbHVlIHBhaXIgaW4gdGhlIG9sZC1zdHJ1Y3R1cmVkIG9wdGlvbnNcclxuICAgIGZvciAoY29uc3QgW2tleSwgdmFsdWVdIG9mIE9iamVjdC5lbnRyaWVzKG9sZE9wdGlvbnMpKSB7XHJcbiAgICAgIC8vIElmIHRoZXJlIGlzIGEgbmVzdGVkIG1hcHBpbmcsIHNwbGl0IGl0IGludG8gYSBwcm9wZXJ0aWVzIGNoYWluXHJcbiAgICAgIGNvbnN0IHByb3BlcnRpZXNDaGFpbiA9IG5lc3RlZFByb3BzW2tleV1cclxuICAgICAgICA/IG5lc3RlZFByb3BzW2tleV0uc3BsaXQoJy4nKVxyXG4gICAgICAgIDogW107XHJcblxyXG4gICAgICAvLyBJZiBpdCBpcyB0aGUgbGFzdCBwcm9wZXJ0eSBpbiB0aGUgY2hhaW4sIGFzc2lnbiB0aGUgdmFsdWUsIG90aGVyd2lzZSxcclxuICAgICAgLy8gY3JlYXRlIG9yIHJldXNlIHRoZSBuZXN0ZWQgb2JqZWN0XHJcbiAgICAgIHByb3BlcnRpZXNDaGFpbi5yZWR1Y2UoXHJcbiAgICAgICAgKG9iaiwgcHJvcCwgaW5kZXgpID0+XHJcbiAgICAgICAgICAob2JqW3Byb3BdID1cclxuICAgICAgICAgICAgcHJvcGVydGllc0NoYWluLmxlbmd0aCAtIDEgPT09IGluZGV4ID8gdmFsdWUgOiBvYmpbcHJvcF0gfHwge30pLFxyXG4gICAgICAgIG5ld09wdGlvbnNcclxuICAgICAgKTtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIC8vIFJldHVybiB0aGUgbmV3LCBzdHJ1Y3R1cmVkIG9wdGlvbnMgb2JqZWN0XHJcbiAgcmV0dXJuIG5ld09wdGlvbnM7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBWYWxpZGF0ZXMsIHBhcnNlcywgYW5kIGNoZWNrcyBpZiB0aGUgcHJvdmlkZWQgY29uZmlnIGlzIGFsbG93ZWQgc2V0XHJcbiAqIG9mIG9wdGlvbnMuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBpc0FsbG93ZWRDb25maWdcclxuICpcclxuICogQHBhcmFtIHt1bmtub3dufSBjb25maWcgLSBUaGUgY29uZmlnIHRvIGJlIHZhbGlkYXRlZCBhbmQgcGFyc2VkIGFzIGEgc2V0XHJcbiAqIG9mIG9wdGlvbnMuIE11c3QgYmUgZWl0aGVyIGFuIG9iamVjdCBvciBhIHN0cmluZy5cclxuICogQHBhcmFtIHtib29sZWFufSBbdG9TdHJpbmc9ZmFsc2VdIC0gV2hldGhlciB0byByZXR1cm4gYSBzdHJpbmdpZmllZCB2ZXJzaW9uXHJcbiAqIG9mIHRoZSBwYXJzZWQgY29uZmlnLiBUaGUgZGVmYXVsdCB2YWx1ZSBpcyBmYWxzZS5cclxuICogQHBhcmFtIHtib29sZWFufSBbYWxsb3dGdW5jdGlvbnM9ZmFsc2VdIC0gV2hldGhlciB0byBhbGxvdyBmdW5jdGlvbnNcclxuICogaW4gdGhlIHBhcnNlZCBjb25maWcuIElmIHRydWUsIGZ1bmN0aW9ucyBhcmUgcHJlc2VydmVkLiBPdGhlcndpc2UsIHdoZW5cclxuICogYSBmdW5jdGlvbiBpcyBmb3VuZCwgbnVsbCBpcyByZXR1cm5lZC4gVGhlIGRlZmF1bHQgdmFsdWUgaXMgZmFsc2UuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHsoT2JqZWN0fHN0cmluZ3xudWxsKX0gUmV0dXJucyBhIHBhcnNlZCBzZXQgb2Ygb3B0aW9ucyBvYmplY3QsXHJcbiAqIGEgc3RyaW5naWZpZWQgc2V0IG9mIG9wdGlvbnMgb2JqZWN0IGlmIHRoZSBgdG9TdHJpbmdgIGlzIHRydWUsIGFuZCBudWxsXHJcbiAqIGlmIHRoZSBjb25maWcgaXMgbm90IGEgdmFsaWQgc2V0IG9mIG9wdGlvbnMgb3IgcGFyc2luZyBmYWlscy5cclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiBpc0FsbG93ZWRDb25maWcoXHJcbiAgY29uZmlnLFxyXG4gIHRvU3RyaW5nID0gZmFsc2UsXHJcbiAgYWxsb3dGdW5jdGlvbnMgPSBmYWxzZVxyXG4pIHtcclxuICB0cnkge1xyXG4gICAgLy8gQWNjZXB0IG9ubHkgb2JqZWN0cyBhbmQgc3RyaW5nc1xyXG4gICAgaWYgKCFpc09iamVjdChjb25maWcpICYmIHR5cGVvZiBjb25maWcgIT09ICdzdHJpbmcnKSB7XHJcbiAgICAgIC8vIFJldHVybiBudWxsIGlmIGFueSBvdGhlciB0eXBlXHJcbiAgICAgIHJldHVybiBudWxsO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIEdldCB0aGUgb2JqZWN0IHJlcHJlc2VudGF0aW9uIG9mIHRoZSBvcmlnaW5hbCBjb25maWdcclxuICAgIGNvbnN0IG9iamVjdENvbmZpZyA9XHJcbiAgICAgIHR5cGVvZiBjb25maWcgPT09ICdzdHJpbmcnXHJcbiAgICAgICAgPyBhbGxvd0Z1bmN0aW9uc1xyXG4gICAgICAgICAgPyBldmFsKGAoJHtjb25maWd9KWApXHJcbiAgICAgICAgICA6IEpTT04ucGFyc2UoY29uZmlnKVxyXG4gICAgICAgIDogY29uZmlnO1xyXG5cclxuICAgIC8vIFByZXNlcnZlIG9yIHJlbW92ZSBwb3RlbnRpYWwgZnVuY3Rpb25zIGJhc2VkIG9uIHRoZSBgYWxsb3dGdW5jdGlvbnNgIGZsYWdcclxuICAgIGNvbnN0IHN0cmluZ2lmaWVkT3B0aW9ucyA9IF9vcHRpb25zU3RyaW5naWZ5KFxyXG4gICAgICBvYmplY3RDb25maWcsXHJcbiAgICAgIGFsbG93RnVuY3Rpb25zLFxyXG4gICAgICBmYWxzZVxyXG4gICAgKTtcclxuXHJcbiAgICAvLyBQYXJzZSB0aGUgY29uZmlnIHRvIGNoZWNrIGlmIGl0IGlzIHZhbGlkIHNldCBvZiBvcHRpb25zXHJcbiAgICBjb25zdCBwYXJzZWRPcHRpb25zID0gYWxsb3dGdW5jdGlvbnNcclxuICAgICAgPyBKU09OLnBhcnNlKFxyXG4gICAgICAgICAgX29wdGlvbnNTdHJpbmdpZnkob2JqZWN0Q29uZmlnLCBhbGxvd0Z1bmN0aW9ucywgdHJ1ZSksXHJcbiAgICAgICAgICAoXywgdmFsdWUpID0+XHJcbiAgICAgICAgICAgIHR5cGVvZiB2YWx1ZSA9PT0gJ3N0cmluZycgJiYgdmFsdWUuc3RhcnRzV2l0aCgnZnVuY3Rpb24nKVxyXG4gICAgICAgICAgICAgID8gZXZhbChgKCR7dmFsdWV9KWApXHJcbiAgICAgICAgICAgICAgOiB2YWx1ZVxyXG4gICAgICAgIClcclxuICAgICAgOiBKU09OLnBhcnNlKHN0cmluZ2lmaWVkT3B0aW9ucyk7XHJcblxyXG4gICAgLy8gUmV0dXJuIHN0cmluZ2lmaWVkIG9yIG9iamVjdCBvcHRpb25zIGJhc2VkIG9uIHRoZSBgdG9TdHJpbmdgIGZsYWdcclxuICAgIHJldHVybiB0b1N0cmluZyA/IHN0cmluZ2lmaWVkT3B0aW9ucyA6IHBhcnNlZE9wdGlvbnM7XHJcbiAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgIC8vIFJldHVybiBudWxsIGlmIHBhcnNpbmcgZmFpbHNcclxuICAgIHJldHVybiBudWxsO1xyXG4gIH1cclxufVxyXG5cclxuLyoqXHJcbiAqIFByaW50cyB0aGUgSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyIGxvZ28sIHZlcnNpb24sIGFuZCBsaWNlbnNlIGluZm9ybWF0aW9uLlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gcHJpbnRMaWNlbnNlXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gcHJpbnRMaWNlbnNlKCkge1xyXG4gIC8vIFByaW50IHRoZSBsb2dvIGFuZCB2ZXJzaW9uIGluZm9ybWF0aW9uXHJcbiAgcHJpbnRWZXJzaW9uKCk7XHJcblxyXG4gIC8vIFByaW50IHRoZSBsaWNlbnNlIGluZm9ybWF0aW9uXHJcbiAgY29uc29sZS5sb2coXHJcbiAgICAnVGhpcyBzb2Z0d2FyZSByZXF1aXJlcyBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBmb3IgY29tbWVyY2lhbCB1c2UuXFxuJ1xyXG4gICAgICAueWVsbG93LFxyXG4gICAgJ1xcbkZvciBhIGZ1bGwgbGlzdCBvZiBDTEkgb3B0aW9ucywgdHlwZTonLFxyXG4gICAgJ1xcbmhpZ2hjaGFydHMtZXhwb3J0LXNlcnZlciAtLWhlbHBcXG4nLmdyZWVuLFxyXG4gICAgJ1xcbklmIHlvdSBkbyBub3QgaGF2ZSBhIGxpY2Vuc2UsIG9uZSBjYW4gYmUgb2J0YWluZWQgaGVyZTonLFxyXG4gICAgJ1xcbmh0dHBzOi8vc2hvcC5oaWdoc29mdC5jb20vXFxuJy5ncmVlbixcclxuICAgICdcXG5UbyBjdXN0b21pemUgeW91ciBpbnN0YWxsYXRpb24sIHBsZWFzZSByZWZlciB0byB0aGUgUkVBRE1FIGZpbGUgYXQ6JyxcclxuICAgICdcXG5odHRwczovL2dpdGh1Yi5jb20vaGlnaGNoYXJ0cy9ub2RlLWV4cG9ydC1zZXJ2ZXIjcmVhZG1lXFxuJy5ncmVlblxyXG4gICk7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBQcmludHMgdXNhZ2UgaW5mb3JtYXRpb24gZm9yIENMSSBhcmd1bWVudHMsIGRpc3BsYXlpbmcgYXZhaWxhYmxlIG9wdGlvbnNcclxuICogYW5kIHRoZWlyIGRlc2NyaXB0aW9ucy4gSXQgY2FuIGxpc3QgcHJvcGVydGllcyByZWN1cnNpdmVseSBpZiBjYXRlZ29yaWVzXHJcbiAqIGNvbnRhaW4gbmVzdGVkIG9wdGlvbnMuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBwcmludFVzYWdlXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gcHJpbnRVc2FnZSgpIHtcclxuICAvLyBEaXNwbGF5IFJFQURNRSBhbmQgZ2VuZXJhbCB1c2FnZSBpbmZvcm1hdGlvblxyXG4gIGNvbnNvbGUubG9nKFxyXG4gICAgJ1xcblVzYWdlIG9mIENMSSBhcmd1bWVudHM6Jy5ib2xkLFxyXG4gICAgJ1xcbi0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tJyxcclxuICAgIGBcXG5Gb3IgbW9yZSBkZXRhaWxlZCBpbmZvcm1hdGlvbiwgdmlzaXQgdGhlIFJFQURNRSBmaWxlIGF0OiAkeydodHRwczovL2dpdGh1Yi5jb20vaGlnaGNoYXJ0cy9ub2RlLWV4cG9ydC1zZXJ2ZXIjcmVhZG1lJy5ncmVlbn0uXFxuYFxyXG4gICk7XHJcblxyXG4gIC8vIEl0ZXJhdGUgdGhyb3VnaCBlYWNoIGNhdGVnb3J5IGluIHRoZSBgZGVmYXVsdENvbmZpZ2AgYW5kIGRpc3BsYXkgdXNhZ2UgaW5mb1xyXG4gIE9iamVjdC5rZXlzKGRlZmF1bHRDb25maWcpLmZvckVhY2goKGNhdGVnb3J5KSA9PiB7XHJcbiAgICBjb25zb2xlLmxvZyhgJHtjYXRlZ29yeS50b1VwcGVyQ2FzZSgpfWAuYm9sZC5yZWQpO1xyXG4gICAgX2N5Y2xlQ2F0ZWdvcmllcyhkZWZhdWx0Q29uZmlnW2NhdGVnb3J5XSk7XHJcbiAgICBjb25zb2xlLmxvZygnJyk7XHJcbiAgfSk7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBQcmludHMgdGhlIEhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlciBsb2dvIG9yIHRleHQgd2l0aCB0aGUgdmVyc2lvblxyXG4gKiBpbmZvcm1hdGlvbi5cclxuICpcclxuICogQGZ1bmN0aW9uIHByaW50VmVyc2lvblxyXG4gKlxyXG4gKiBAcGFyYW0ge2Jvb2xlYW59IFtub0xvZ289ZmFsc2VdIC0gSWYgdHJ1ZSwgb25seSBwcmludHMgdGV4dCB3aXRoIHRoZSB2ZXJzaW9uXHJcbiAqIGluZm9ybWF0aW9uLCB3aXRob3V0IHRoZSBsb2dvLiBUaGUgZGVmYXVsdCB2YWx1ZSBpcyBmYWxzZS5cclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiBwcmludFZlcnNpb24obm9Mb2dvID0gZmFsc2UpIHtcclxuICAvLyBHZXQgcGFja2FnZSB2ZXJzaW9uIGVpdGhlciBmcm9tIGAuZW52YCBvciBmcm9tIGBwYWNrYWdlLmpzb25gXHJcbiAgY29uc3QgcGFja2FnZVZlcnNpb24gPSBKU09OLnBhcnNlKFxyXG4gICAgcmVhZEZpbGVTeW5jKGpvaW4oX19kaXJuYW1lLCAncGFja2FnZS5qc29uJykpXHJcbiAgKS52ZXJzaW9uO1xyXG5cclxuICAvLyBQcmludCB0ZXh0IG9ubHlcclxuICBpZiAobm9Mb2dvKSB7XHJcbiAgICBjb25zb2xlLmxvZyhgSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyIHYke3BhY2thZ2VWZXJzaW9ufWApO1xyXG4gIH0gZWxzZSB7XHJcbiAgICAvLyBQcmludCB0aGUgbG9nb1xyXG4gICAgY29uc29sZS5sb2coXHJcbiAgICAgIHJlYWRGaWxlU3luYyhqb2luKF9fZGlybmFtZSwgJ21zZycsICdzdGFydHVwLm1zZycpKS50b1N0cmluZygpLmJvbGRcclxuICAgICAgICAueWVsbG93LFxyXG4gICAgICBgdiR7cGFja2FnZVZlcnNpb259XFxuYC5ib2xkXHJcbiAgICApO1xyXG4gIH1cclxufVxyXG5cclxuLyoqXHJcbiAqIEluaXRpYWxpemVzIGFuZCByZXR1cm5zIGdsb2JhbCBvcHRpb25zIG9iamVjdCBiYXNlZCBvbiBwcm92aWRlZFxyXG4gKiBjb25maWd1cmF0aW9uLCBzZXR0aW5nIHZhbHVlcyBmcm9tIG5lc3RlZCBwcm9wZXJ0aWVzIHJlY3Vyc2l2ZWx5LlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gX2luaXRHbG9iYWxPcHRpb25zXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBjb25maWcgLSBUaGUgY29uZmlndXJhdGlvbiBvYmplY3QgdG8gYmUgdXNlZCBmb3IgaW5pdGlhbGl6aW5nXHJcbiAqIG9wdGlvbnMuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtPYmplY3R9IEluaXRpYWxpemVkIG9wdGlvbnMgb2JqZWN0LlxyXG4gKi9cclxuZnVuY3Rpb24gX2luaXRHbG9iYWxPcHRpb25zKGNvbmZpZykge1xyXG4gIGNvbnN0IG9wdGlvbnMgPSB7fTtcclxuXHJcbiAgLy8gU3RhcnQgaW5pdGlhbGl6aW5nIHRoZSBgb3B0aW9uc2Agb2JqZWN0IHJlY3Vyc2l2ZWx5XHJcbiAgZm9yIChjb25zdCBbbmFtZSwgaXRlbV0gb2YgT2JqZWN0LmVudHJpZXMoY29uZmlnKSkge1xyXG4gICAgb3B0aW9uc1tuYW1lXSA9IE9iamVjdC5wcm90b3R5cGUuaGFzT3duUHJvcGVydHkuY2FsbChpdGVtLCAndmFsdWUnKVxyXG4gICAgICA/IGl0ZW0udmFsdWVcclxuICAgICAgOiBfaW5pdEdsb2JhbE9wdGlvbnMoaXRlbSk7XHJcbiAgfVxyXG5cclxuICAvLyBSZXR1cm4gdGhlIGNyZWF0ZWQgYG9wdGlvbnNgIG9iamVjdFxyXG4gIHJldHVybiBvcHRpb25zO1xyXG59XHJcblxyXG4vKipcclxuICogVXBkYXRlcyBvcHRpb25zIG9iamVjdCB3aXRoIHZhbHVlcyBmcm9tIHZhcmlvdXMgc291cmNlcywgZm9sbG93aW5nIGEgc3BlY2lmaWNcclxuICogcHJpb3JpdGl6YXRpb24gb3JkZXIuIFRoZSBmdW5jdGlvbiBjaGVja3MgZm9yIHZhbHVlcyBpbiB0aGUgZm9sbG93aW5nIG9yZGVyXHJcbiAqIG9mIHByZWNlZGVuY2U6IHRoZSBgbG9hZENvbmZpZ2AgY29uZmlndXJhdGlvbiBvcHRpb25zLCBlbnZpcm9ubWVudCB2YXJpYWJsZXMsXHJcbiAqIGN1c3RvbSBvcHRpb25zLCBhbmQgQ0xJIG9wdGlvbnMuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBfdXBkYXRlT3B0aW9uc1xyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gY29uZmlnIC0gVGhlIGNvbmZpZ3VyYXRpb24gb2JqZWN0LCB3aGljaCBpbmNsdWRlcyB0aGUgaW5pdGlhbFxyXG4gKiBzZXR0aW5ncyBhbmQgbWV0YWRhdGEgZm9yIGVhY2ggb3B0aW9uLiBUaGlzIG9iamVjdCBpcyB1c2VkIHRvIGRldGVybWluZVxyXG4gKiB0aGUgc3RydWN0dXJlIGFuZCBkZWZhdWx0IHZhbHVlcyBmb3IgdGhlIG9wdGlvbnMuXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBvcHRpb25zIC0gVGhlIG9wdGlvbnMgb2JqZWN0IHRoYXQgd2lsbCBiZSB1cGRhdGVkIHdpdGggdmFsdWVzXHJcbiAqIGZyb20gb3RoZXIgc291cmNlcy5cclxuICogQHBhcmFtIHtPYmplY3R9IGNvbmZpZ09wdCAtIFRoZSBjb25maWd1cmF0aW9uIG9wdGlvbnMgb2JqZWN0LCBsb2FkZWQgd2l0aFxyXG4gKiB0aGUgYGxvYWRDb25maWdgIG9wdGlvbiwgd2hpY2ggbWF5IHByb3ZpZGUgdmFsdWVzIHRvIG92ZXJyaWRlIGRlZmF1bHRzLlxyXG4gKiBAcGFyYW0ge09iamVjdH0gY3VzdG9tT3B0IC0gVGhlIGN1c3RvbSBvcHRpb25zIG9iamVjdCwgdHlwaWNhbGx5IGNvbnRhaW5pbmdcclxuICogYWRkaXRpb25hbCBhbmQgdXNlci1kZWZpbmVkIHZhbHVlcywgd2hpY2ggbWF5IG92ZXJyaWRlIGNvbmZpZ3VyYXRpb24gb3B0aW9ucy5cclxuICogQHBhcmFtIHtPYmplY3R9IGNsaU9wdCAtIFRoZSBDTEkgb3B0aW9ucyBvYmplY3QsIHdoaWNoIG1heSBpbmNsdWRlIHZhbHVlc1xyXG4gKiBwcm92aWRlZCB0aHJvdWdoIGNvbW1hbmQtbGluZSBhcmd1bWVudHMgYW5kIGhhcyB0aGUgaGlnaGVzdCBwcmVjZWRlbmNlIGFtb25nXHJcbiAqIG9wdGlvbnMuXHJcbiAqL1xyXG5mdW5jdGlvbiBfdXBkYXRlT3B0aW9ucyhjb25maWcsIG9wdGlvbnMsIGNvbmZpZ09wdCwgY3VzdG9tT3B0LCBjbGlPcHQpIHtcclxuICBPYmplY3Qua2V5cyhjb25maWcpLmZvckVhY2goKGtleSkgPT4ge1xyXG4gICAgLy8gR2V0IHRoZSBjb25maWcgZW50cnkgb2YgYSBzcGVjaWZpYyBvcHRpb25cclxuICAgIGNvbnN0IGVudHJ5ID0gY29uZmlnW2tleV07XHJcblxyXG4gICAgLy8gR2F0aGVyIHZhbHVlcyBmb3IgdGhlIG9wdGlvbnMgZnJvbSBldmVyeSBwb3NzaWJsZSBzb3VyY2UsIGlmIGV4aXN0c1xyXG4gICAgY29uc3QgY29uZmlnVmFsID0gY29uZmlnT3B0ICYmIGNvbmZpZ09wdFtrZXldO1xyXG4gICAgY29uc3QgY3VzdG9tVmFsID0gY3VzdG9tT3B0ICYmIGN1c3RvbU9wdFtrZXldO1xyXG4gICAgY29uc3QgY2xpVmFsID0gY2xpT3B0ICYmIGNsaU9wdFtrZXldO1xyXG5cclxuICAgIC8vIElmIHRoZSB2YWx1ZSBub3QgZm91bmQsIG5lZWQgdG8gZ28gZGVlcGVyXHJcbiAgICBpZiAodHlwZW9mIGVudHJ5LnZhbHVlID09PSAndW5kZWZpbmVkJykge1xyXG4gICAgICBfdXBkYXRlT3B0aW9ucyhlbnRyeSwgb3B0aW9uc1trZXldLCBjb25maWdWYWwsIGN1c3RvbVZhbCwgY2xpVmFsKTtcclxuICAgIH0gZWxzZSB7XHJcbiAgICAgIC8vIElmIGEgdmFsdWUgZnJvbSBjdXN0b20gSlNPTiBvcHRpb25zIGV4aXN0cywgaXQgdGFrZSBwcmVjZWRlbmNlXHJcbiAgICAgIGlmIChjb25maWdWYWwgIT09IHVuZGVmaW5lZCAmJiBjb25maWdWYWwgIT09IG51bGwpIHtcclxuICAgICAgICBvcHRpb25zW2tleV0gPSBjb25maWdWYWw7XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIC8vIElmIGEgdmFsdWUgZnJvbSBlbnZpcm9ubWVudCB2YXJpYWJsZXMgZXhpc3RzLCBpdCB0YWtlIHByZWNlZGVuY2VcclxuICAgICAgY29uc3QgZW52VmFsID0gZW52c1tlbnRyeS5lbnZMaW5rXTtcclxuICAgICAgaWYgKGVudHJ5LmVudkxpbmsgaW4gZW52cyAmJiBlbnZWYWwgIT09IHVuZGVmaW5lZCAmJiBlbnZWYWwgIT09IG51bGwpIHtcclxuICAgICAgICBvcHRpb25zW2tleV0gPSBlbnZWYWw7XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIC8vIElmIGEgdmFsdWUgZnJvbSB1c2VyIG9wdGlvbnMgZXhpc3RzLCBpdCB0YWtlIHByZWNlZGVuY2VcclxuICAgICAgaWYgKGN1c3RvbVZhbCAhPT0gdW5kZWZpbmVkICYmIGN1c3RvbVZhbCAhPT0gbnVsbCkge1xyXG4gICAgICAgIG9wdGlvbnNba2V5XSA9IGN1c3RvbVZhbDtcclxuICAgICAgfVxyXG5cclxuICAgICAgLy8gSWYgYSB2YWx1ZSBmcm9tIENMSSBvcHRpb25zIGV4aXN0cywgaXQgdGFrZSBwcmVjZWRlbmNlXHJcbiAgICAgIGlmIChjbGlWYWwgIT09IHVuZGVmaW5lZCAmJiBjbGlWYWwgIT09IG51bGwpIHtcclxuICAgICAgICBvcHRpb25zW2tleV0gPSBjbGlWYWw7XHJcbiAgICAgIH1cclxuICAgIH1cclxuICB9KTtcclxufVxyXG5cclxuLyoqXHJcbiAqIENvbnZlcnRzIHRoZSBwcm92aWRlZCBvcHRpb25zIG9iamVjdCB0byBhIEpTT04tZm9ybWF0dGVkIHN0cmluZ1xyXG4gKiB3aXRoIHRoZSBvcHRpb24gdG8gcHJlc2VydmUgZnVuY3Rpb25zLiBJbiBvcmRlciBmb3IgYSBmdW5jdGlvblxyXG4gKiB0byBiZSBwcmVzZXJ2ZWQsIGl0IG5lZWRzIHRvIGZvbGxvdyB0aGUgZm9ybWF0IGBmdW5jdGlvbiAoLi4uKSB7Li4ufWAuXHJcbiAqIFN1Y2ggYSBmdW5jdGlvbiBjYW4gYWxzbyBiZSBzdHJpbmdpZmllZC5cclxuICpcclxuICogQGZ1bmN0aW9uIF9vcHRpb25zU3RyaW5naWZ5XHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBvcHRpb25zIC0gVGhlIG9wdGlvbnMgb2JqZWN0IHRvIGJlIGNvbnZlcnRlZCB0byBhIHN0cmluZy5cclxuICogQHBhcmFtIHtib29sZWFufSBhbGxvd0Z1bmN0aW9ucyAtIElmIHNldCB0byB0cnVlLCBmdW5jdGlvbnMgYXJlIHByZXNlcnZlZFxyXG4gKiBpbiB0aGUgb3V0cHV0LiBPdGhlcndpc2UgYW4gZXJyb3IgaXMgdGhyb3duLlxyXG4gKiBAcGFyYW0ge2Jvb2xlYW59IHN0cmluZ2lmeUZ1bmN0aW9ucyAtIElmIHNldCB0byB0cnVlLCBmdW5jdGlvbnMgYXJlIHNhdmVkXHJcbiAqIGFzIHN0cmluZ3MuIFRoZSBgYWxsb3dGdW5jdGlvbnNgIG11c3QgYmUgc2V0IHRvIHRydWUgYXMgd2VsbCBmb3IgdGhpcyB0byB0YWtlXHJcbiAqIGFuIGVmZmVjdC5cclxuICpcclxuICogQHJldHVybnMge3N0cmluZ30gVGhlIEpTT04tZm9ybWF0dGVkIHN0cmluZyByZXByZXNlbnRpbmcgdGhlIG9wdGlvbnMuXHJcbiAqXHJcbiAqIEB0aHJvd3Mge0Vycm9yfSBUaHJvd3MgYW4gYEVycm9yYCB3aGVuIGZ1bmN0aW9ucyBhcmUgbm90IGFsbG93ZWQgYnV0IGFyZVxyXG4gKiBmb3VuZCBpbiBwcm92aWRlZCBvcHRpb25zIG9iamVjdC5cclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiBfb3B0aW9uc1N0cmluZ2lmeShvcHRpb25zLCBhbGxvd0Z1bmN0aW9ucywgc3RyaW5naWZ5RnVuY3Rpb25zKSB7XHJcbiAgY29uc3QgcmVwbGFjZXJDYWxsYmFjayA9IChfLCB2YWx1ZSkgPT4ge1xyXG4gICAgLy8gVHJpbSBzdHJpbmcgdmFsdWVzXHJcbiAgICBpZiAodHlwZW9mIHZhbHVlID09PSAnc3RyaW5nJykge1xyXG4gICAgICB2YWx1ZSA9IHZhbHVlLnRyaW0oKTtcclxuICAgIH1cclxuXHJcbiAgICAvLyBJZiB2YWx1ZSBpcyBhIGZ1bmN0aW9uIG9yIHN0cmluZ2lmaWVkIGZ1bmN0aW9uXHJcbiAgICBpZiAoXHJcbiAgICAgIHR5cGVvZiB2YWx1ZSA9PT0gJ2Z1bmN0aW9uJyB8fFxyXG4gICAgICAodHlwZW9mIHZhbHVlID09PSAnc3RyaW5nJyAmJlxyXG4gICAgICAgIHZhbHVlLnN0YXJ0c1dpdGgoJ2Z1bmN0aW9uJykgJiZcclxuICAgICAgICB2YWx1ZS5lbmRzV2l0aCgnfScpKVxyXG4gICAgKSB7XHJcbiAgICAgIC8vIElmIGFsbG93RnVuY3Rpb25zIGlzIHNldCB0byB0cnVlLCBwcmVzZXJ2ZSBmdW5jdGlvbnNcclxuICAgICAgaWYgKGFsbG93RnVuY3Rpb25zKSB7XHJcbiAgICAgICAgLy8gQmFzZWQgb24gdGhlIGBzdHJpbmdpZnlGdW5jdGlvbnNgIG9wdGlvbnMsIHNldCBmdW5jdGlvbiB2YWx1ZXNcclxuICAgICAgICByZXR1cm4gc3RyaW5naWZ5RnVuY3Rpb25zXHJcbiAgICAgICAgICA/IC8vIEFzIHN0cmluZ2lmaWVkIGZ1bmN0aW9uc1xyXG4gICAgICAgICAgICBgXCJFWFBfRlVOJHsodmFsdWUgKyAnJykucmVwbGFjZUFsbCgvXFxzKy9nLCAnICcpfUVYUF9GVU5cImBcclxuICAgICAgICAgIDogLy8gQXMgZnVuY3Rpb25zXHJcbiAgICAgICAgICAgIGBFWFBfRlVOJHsodmFsdWUgKyAnJykucmVwbGFjZUFsbCgvXFxzKy9nLCAnICcpfUVYUF9GVU5gO1xyXG4gICAgICB9IGVsc2Uge1xyXG4gICAgICAgIC8vIFRocm93IGFuIGVycm9yIG90aGVyd2lzZVxyXG4gICAgICAgIHRocm93IG5ldyBFcnJvcigpO1xyXG4gICAgICB9XHJcbiAgICB9XHJcblxyXG4gICAgLy8gSW4gYWxsIG90aGVyIGNhc2VzLCBzaW1wbHkgcmV0dXJuIHRoZSB2YWx1ZVxyXG4gICAgcmV0dXJuIHZhbHVlO1xyXG4gIH07XHJcblxyXG4gIC8vIFN0cmluZ2lmeSBvcHRpb25zIGFuZCBpZiByZXF1aXJlZCwgcmVwbGFjZSBzcGVjaWFsIGZ1bmN0aW9ucyBtYXJrc1xyXG4gIHJldHVybiBKU09OLnN0cmluZ2lmeShvcHRpb25zLCByZXBsYWNlckNhbGxiYWNrKS5yZXBsYWNlQWxsKFxyXG4gICAgc3RyaW5naWZ5RnVuY3Rpb25zID8gL1xcXFxcIkVYUF9GVU58RVhQX0ZVTlxcXFxcIi9nIDogL1wiRVhQX0ZVTnxFWFBfRlVOXCIvZyxcclxuICAgICcnXHJcbiAgKTtcclxufVxyXG5cclxuLyoqXHJcbiAqIExvYWRzIGFkZGl0aW9uYWwgY29uZmlndXJhdGlvbiBmcm9tIGEgc3BlY2lmaWVkIGZpbGUgcHJvdmlkZWQgdmlhXHJcbiAqIHRoZSBgbG9hZENvbmZpZ2Agb3B0aW9uIGluIHRoZSBjb21tYW5kLWxpbmUgYXJndW1lbnRzLlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gX2xvYWRDb25maWdGaWxlXHJcbiAqXHJcbiAqIEBwYXJhbSB7QXJyYXkuPHN0cmluZz59IGNsaUFyZ3MgLSBDb21tYW5kLWxpbmUgYXJndW1lbnRzIHRvIHNlYXJjaFxyXG4gKiBmb3IgdGhlIGBsb2FkQ29uZmlnYCBvcHRpb24gYW5kIHRoZSBjb3JyZXNwb25kaW5nIGZpbGUgcGF0aC5cclxuICpcclxuICogQHJldHVybnMge09iamVjdH0gVGhlIGFkZGl0aW9uYWwgY29uZmlndXJhdGlvbiBsb2FkZWQgZnJvbSB0aGUgc3BlY2lmaWVkXHJcbiAqIGZpbGUsIG9yIGFuIGVtcHR5IG9iamVjdCBpZiB0aGUgZmlsZSBpcyBub3QgZm91bmQsIGludmFsaWQsIG9yIGFuIGVycm9yXHJcbiAqIG9jY3Vycy5cclxuICovXHJcbmZ1bmN0aW9uIF9sb2FkQ29uZmlnRmlsZShjbGlBcmdzKSB7XHJcbiAgLy8gQ2hlY2sgaWYgdGhlIGBsb2FkQ29uZmlnYCBvcHRpb24gd2FzIHVzZWRcclxuICBjb25zdCBjb25maWdJbmRleCA9IGNsaUFyZ3MuZmluZEluZGV4KFxyXG4gICAgKGFyZykgPT4gYXJnLnJlcGxhY2UoLy0vZywgJycpID09PSAnbG9hZENvbmZpZydcclxuICApO1xyXG5cclxuICAvLyBHZXQgdGhlIGBsb2FkQ29uZmlnYCBvcHRpb24gdmFsdWVcclxuICBjb25zdCBjb25maWdGaWxlTmFtZSA9IGNvbmZpZ0luZGV4ID4gLTEgJiYgY2xpQXJnc1tjb25maWdJbmRleCArIDFdO1xyXG5cclxuICAvLyBDaGVjayBpZiB0aGUgYGxvYWRDb25maWdgIGlzIHByZXNlbnQgYW5kIGhhcyBhIGNvcnJlY3QgdmFsdWVcclxuICBpZiAoY29uZmlnRmlsZU5hbWUpIHtcclxuICAgIHRyeSB7XHJcbiAgICAgIC8vIExvYWQgYW4gb3B0aW9uYWwgY3VzdG9tIEpTT04gY29uZmlnIGZpbGVcclxuICAgICAgcmV0dXJuIEpTT04ucGFyc2UocmVhZEZpbGVTeW5jKGdldEFic29sdXRlUGF0aChjb25maWdGaWxlTmFtZSkpKTtcclxuICAgIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICAgIGxvZ1dpdGhTdGFjayhcclxuICAgICAgICAyLFxyXG4gICAgICAgIGVycm9yLFxyXG4gICAgICAgIGBbY29uZmlnXSBVbmFibGUgdG8gbG9hZCB0aGUgY29uZmlndXJhdGlvbiBmcm9tIHRoZSAke2NvbmZpZ0ZpbGVOYW1lfSBmaWxlLmBcclxuICAgICAgKTtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIC8vIE5vIGFkZGl0aW9uYWwgb3B0aW9ucyB0byByZXR1cm5cclxuICByZXR1cm4ge307XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBQYXJzZXMgY29tbWFuZC1saW5lIGFyZ3VtZW50cyBhbmQgcGFpcnMgZWFjaCBhcmd1bWVudCB3aXRoIGl0cyBjb3JyZXNwb25kaW5nXHJcbiAqIG9wdGlvbiBpbiB0aGUgY29uZmlndXJhdGlvbi4gVGhlIHZhbHVlcyBhcmUgc3RydWN0dXJlZCBpbnRvIGEgbmVzdGVkIG9wdGlvbnNcclxuICogb2JqZWN0LCBiYXNlZCBvbiBwcmVkZWZpbmVkIG1hcHBpbmdzLlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gX3BhaXJBcmd1bWVudFZhbHVlXHJcbiAqXHJcbiAqIEBwYXJhbSB7QXJyYXkuPHN0cmluZz59IG5lc3RlZFByb3BzIC0gQW4gYXJyYXkgb2YgbmVzdGluZyBsZXZlbCBmb3IgYWxsXHJcbiAqIG9wdGlvbnMuXHJcbiAqIEBwYXJhbSB7QXJyYXkuPHN0cmluZz59IGNsaUFyZ3MgLSBBbiBhcnJheSBvZiBjb21tYW5kLWxpbmUgYXJndW1lbnRzXHJcbiAqIGNvbnRhaW5pbmcgb3B0aW9ucyBhbmQgdGhlaXIgYXNzb2NpYXRlZCB2YWx1ZXMuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtPYmplY3R9IEFuIHVwZGF0ZWQgb3B0aW9ucyBvYmplY3Qgd2hlcmUgZWFjaCBvcHRpb24gZnJvbVxyXG4gKiB0aGUgY29tbWFuZC1saW5lIGlzIHBhaXJlZCB3aXRoIGl0cyB2YWx1ZSwgc3RydWN0dXJlZCBpbnRvIG5lc3RlZCBvYmplY3RzXHJcbiAqIGFzIGRlZmluZWQuXHJcbiAqL1xyXG5mdW5jdGlvbiBfcGFpckFyZ3VtZW50VmFsdWUobmVzdGVkUHJvcHMsIGNsaUFyZ3MpIHtcclxuICAvLyBBbiBlbXB0eSBvYmplY3QgdG8gY29sbGVjdCBhbmQgc3RydWN0dXJpemUgZGF0YSBmcm9tIHRoZSBhcmdzXHJcbiAgY29uc3QgY2xpT3B0aW9ucyA9IHt9O1xyXG5cclxuICAvLyBDeWNsZSB0aHJvdWdoIGFsbCBDTEkgYXJncyBhbmQgZmlsdGVyIHRoZW1cclxuICBmb3IgKGxldCBpID0gMDsgaSA8IGNsaUFyZ3MubGVuZ3RoOyBpKyspIHtcclxuICAgIGNvbnN0IG9wdGlvbiA9IGNsaUFyZ3NbaV0ucmVwbGFjZSgvLS9nLCAnJyk7XHJcblxyXG4gICAgLy8gRmluZCB0aGUgcmlnaHQgcGxhY2UgZm9yIHByb3BlcnR5J3MgdmFsdWVcclxuICAgIGNvbnN0IHByb3BlcnRpZXNDaGFpbiA9IG5lc3RlZFByb3BzW29wdGlvbl1cclxuICAgICAgPyBuZXN0ZWRQcm9wc1tvcHRpb25dLnNwbGl0KCcuJylcclxuICAgICAgOiBbXTtcclxuXHJcbiAgICAvLyBDcmVhdGUgb3B0aW9ucyBvYmplY3Qgd2l0aCB2YWx1ZXMgZnJvbSBDTEkgZm9yIGxhdGVyIHBhcnNpbmcgYW5kIG1lcmdpbmdcclxuICAgIHByb3BlcnRpZXNDaGFpbi5yZWR1Y2UoKG9iaiwgcHJvcCwgaW5kZXgpID0+IHtcclxuICAgICAgaWYgKHByb3BlcnRpZXNDaGFpbi5sZW5ndGggLSAxID09PSBpbmRleCkge1xyXG4gICAgICAgIGNvbnN0IHZhbHVlID0gY2xpQXJnc1srK2ldO1xyXG4gICAgICAgIGlmICghdmFsdWUpIHtcclxuICAgICAgICAgIGxvZyhcclxuICAgICAgICAgICAgMixcclxuICAgICAgICAgICAgYFtjb25maWddIE1pc3NpbmcgdmFsdWUgZm9yIHRoZSBDTEkgJy0tJHtvcHRpb259JyBhcmd1bWVudC4gVXNpbmcgdGhlIGRlZmF1bHQgdmFsdWUuYFxyXG4gICAgICAgICAgKTtcclxuICAgICAgICB9XHJcbiAgICAgICAgb2JqW3Byb3BdID0gdmFsdWUgfHwgbnVsbDtcclxuICAgICAgfSBlbHNlIGlmIChvYmpbcHJvcF0gPT09IHVuZGVmaW5lZCkge1xyXG4gICAgICAgIG9ialtwcm9wXSA9IHt9O1xyXG4gICAgICB9XHJcbiAgICAgIHJldHVybiBvYmpbcHJvcF07XHJcbiAgICB9LCBjbGlPcHRpb25zKTtcclxuICB9XHJcblxyXG4gIC8vIFJldHVybiBwYXJzZWQgQ0xJIG9wdGlvbnNcclxuICByZXR1cm4gY2xpT3B0aW9ucztcclxufVxyXG5cclxuLyoqXHJcbiAqIFJlY3Vyc2l2ZWx5IHRyYXZlcnNlcyB0aGUgb3B0aW9ucyBvYmplY3QgdG8gcHJpbnQgdGhlIHVzYWdlIGluZm9ybWF0aW9uXHJcbiAqIGZvciBlYWNoIG9wdGlvbiBjYXRlZ29yeSBhbmQgaW5kaXZpZHVhbCBvcHRpb24uXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBfY3ljbGVDYXRlZ29yaWVzXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBvcHRpb25zIC0gVGhlIG9wdGlvbnMgb2JqZWN0IGNvbnRhaW5pbmcgQ0xJIG9wdGlvbnMuXHJcbiAqIEl0IG1heSBpbmNsdWRlIG5lc3RlZCBjYXRlZ29yaWVzIGFuZCBpbmRpdmlkdWFsIG9wdGlvbnMuXHJcbiAqL1xyXG5mdW5jdGlvbiBfY3ljbGVDYXRlZ29yaWVzKG9wdGlvbnMpIHtcclxuICBmb3IgKGNvbnN0IFtuYW1lLCBvcHRpb25dIG9mIE9iamVjdC5lbnRyaWVzKG9wdGlvbnMpKSB7XHJcbiAgICAvLyBJZiB0aGUgY3VycmVudCBlbnRyeSBpcyBhIGNhdGVnb3J5IGFuZCBub3QgYSBsZWFmIG9wdGlvbiwgcmVjdXJzZSBpbnRvIGl0XHJcbiAgICBpZiAoIU9iamVjdC5wcm90b3R5cGUuaGFzT3duUHJvcGVydHkuY2FsbChvcHRpb24sICd2YWx1ZScpKSB7XHJcbiAgICAgIF9jeWNsZUNhdGVnb3JpZXMob3B0aW9uKTtcclxuICAgIH0gZWxzZSB7XHJcbiAgICAgIC8vIFByZXBhcmUgZGVzY3JpcHRpb25cclxuICAgICAgY29uc3QgZGVzY05hbWUgPSBgIC0tJHtvcHRpb24uY2xpTmFtZSB8fCBuYW1lfWA7XHJcblxyXG4gICAgICAvLyBHZXQgdGhlIHZhbHVlXHJcbiAgICAgIGxldCBvcHRpb25WYWx1ZSA9IG9wdGlvbi52YWx1ZTtcclxuXHJcbiAgICAgIC8vIFByZXBhcmUgdmFsdWUgZm9yIG9wdGlvbiB0aGF0IGlzIG5vdCBudWxsIGFuZCBpcyBhcnJheSBvZiBzdHJpbmdzXHJcbiAgICAgIGlmIChvcHRpb25WYWx1ZSAhPT0gbnVsbCAmJiBvcHRpb24udHlwZXMuaW5jbHVkZXMoJ3N0cmluZ1tdJykpIHtcclxuICAgICAgICBvcHRpb25WYWx1ZSA9XHJcbiAgICAgICAgICAnWycgKyBvcHRpb25WYWx1ZS5tYXAoKGl0ZW0pID0+IGAnJHtpdGVtfSdgKS5qb2luKCcsICcpICsgJ10nO1xyXG4gICAgICB9XHJcblxyXG4gICAgICAvLyBQcmVwYXJlIHZhbHVlIGZvciBvcHRpb24gdGhhdCBpcyBub3QgbnVsbCBhbmQgaXMgYSBzdHJpbmdcclxuICAgICAgaWYgKG9wdGlvblZhbHVlICE9PSBudWxsICYmIG9wdGlvbi50eXBlcy5pbmNsdWRlcygnc3RyaW5nJykpIHtcclxuICAgICAgICBvcHRpb25WYWx1ZSA9IGAnJHtvcHRpb25WYWx1ZX0nYDtcclxuICAgICAgfVxyXG5cclxuICAgICAgLy8gRGlzcGxheSBjb3JyZWN0bHkgYWxpZ25lZCBtZXNzYWdlc1xyXG4gICAgICBjb25zb2xlLmxvZyhcclxuICAgICAgICBkZXNjTmFtZS5ncmVlbixcclxuICAgICAgICBgJHsoJzwnICsgb3B0aW9uLnR5cGVzLmpvaW4oJ3wnKSArICc+JykueWVsbG93fWAsXHJcbiAgICAgICAgYCR7U3RyaW5nKG9wdGlvblZhbHVlKS5ib2xkfWAuYmx1ZSxcclxuICAgICAgICBgLSAke29wdGlvbi5kZXNjcmlwdGlvbn0uYFxyXG4gICAgICApO1xyXG4gICAgfVxyXG4gIH1cclxufVxyXG5cclxuZXhwb3J0IGRlZmF1bHQge1xyXG4gIGdldE9wdGlvbnMsXHJcbiAgc2V0T3B0aW9ucyxcclxuICBtZXJnZU9wdGlvbnMsXHJcbiAgbWFwVG9OZXdPcHRpb25zLFxyXG4gIGlzQWxsb3dlZENvbmZpZyxcclxuICBwcmludExpY2Vuc2UsXHJcbiAgcHJpbnRVc2FnZSxcclxuICBwcmludFZlcnNpb25cclxufTtcclxuIiwiLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcclxuXHJcbkhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlclxyXG5cclxuQ29weXJpZ2h0IChjKSAyMDE2LTIwMjUsIEhpZ2hzb2Z0XHJcblxyXG5MaWNlbmNlZCB1bmRlciB0aGUgTUlUIGxpY2VuY2UuXHJcblxyXG5BZGRpdGlvbmFsbHkgYSB2YWxpZCBIaWdoY2hhcnRzIGxpY2Vuc2UgaXMgcmVxdWlyZWQgZm9yIHVzZS5cclxuXHJcblNlZSBMSUNFTlNFIGZpbGUgaW4gcm9vdCBmb3IgZGV0YWlscy5cclxuXHJcbioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXHJcblxyXG4vKipcclxuICogQG92ZXJ2aWV3IEhUVFAgdXRpbGl0eSBtb2R1bGUgZm9yIGZldGNoaW5nIGFuZCBwb3N0aW5nIGRhdGEuIFN1cHBvcnRzIGJvdGhcclxuICogSFRUUCBhbmQgSFRUUFMgcHJvdG9jb2xzLCBwcm92aWRpbmcgbWV0aG9kcyB0byBtYWtlIEdFVCBhbmQgUE9TVCByZXF1ZXN0c1xyXG4gKiB3aXRoIGN1c3RvbWl6YWJsZSBvcHRpb25zLiBJbmNsdWRlcyBwcm90b2NvbCBkZXRlcm1pbmF0aW9uIGJhc2VkIG9uIFVSTFxyXG4gKiBhbmQgYXVnbWVudHMgcmVzcG9uc2Ugb2JqZWN0cyB3aXRoIGEgJ3RleHQnIHByb3BlcnR5IGZvciBlYXNpZXIgZGF0YSBhY2Nlc3MuXHJcbiAqL1xyXG5cclxuaW1wb3J0IGh0dHAgZnJvbSAnaHR0cCc7XHJcbmltcG9ydCBodHRwcyBmcm9tICdodHRwcyc7XHJcblxyXG4vKipcclxuICogRmV0Y2hlcyBkYXRhIGZyb20gdGhlIHNwZWNpZmllZCBVUkwgdXNpbmcgZWl0aGVyIEhUVFAgb3IgSFRUUFMgcHJvdG9jb2wuXHJcbiAqXHJcbiAqIEBhc3luY1xyXG4gKiBAZnVuY3Rpb24gZmV0Y2hcclxuICpcclxuICogQHBhcmFtIHtzdHJpbmd9IHVybCAtIFRoZSBVUkwgdG8gZmV0Y2ggZGF0YSBmcm9tLlxyXG4gKiBAcGFyYW0ge09iamVjdH0gW3JlcXVlc3RPcHRpb25zPXt9XSAtIE9wdGlvbnMgZm9yIHRoZSBIVFRQL0hUVFBTIHJlcXVlc3QuXHJcbiAqIFRoZSBkZWZhdWx0IHZhbHVlIGlzIGFuIGVtcHR5IG9iamVjdC5cclxuICpcclxuICogQHJldHVybnMge1Byb21pc2U8T2JqZWN0Pn0gQSBQcm9taXNlIHRoYXQgcmVzb2x2ZXMgdG8gdGhlIEhUVFAvSFRUUFMgcmVzcG9uc2VcclxuICogb2JqZWN0IHdpdGggYWRkZWQgJ3RleHQnIHByb3BlcnR5IG9yIHJlamVjdGluZyB3aXRoIGFuIGVycm9yLlxyXG4gKi9cclxuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIGZldGNoKHVybCwgcmVxdWVzdE9wdGlvbnMgPSB7fSkge1xyXG4gIHJldHVybiBuZXcgUHJvbWlzZSgocmVzb2x2ZSwgcmVqZWN0KSA9PiB7XHJcbiAgICBfZ2V0UHJvdG9jb2xNb2R1bGUodXJsKVxyXG4gICAgICAuZ2V0KHVybCwgcmVxdWVzdE9wdGlvbnMsIChyZXNwb25zZSkgPT4ge1xyXG4gICAgICAgIGxldCByZXNwb25zZURhdGEgPSAnJztcclxuXHJcbiAgICAgICAgLy8gQSBjaHVuayBvZiBkYXRhIGhhcyBiZWVuIHJlY2VpdmVkXHJcbiAgICAgICAgcmVzcG9uc2Uub24oJ2RhdGEnLCAoY2h1bmspID0+IHtcclxuICAgICAgICAgIHJlc3BvbnNlRGF0YSArPSBjaHVuaztcclxuICAgICAgICB9KTtcclxuXHJcbiAgICAgICAgLy8gVGhlIHdob2xlIHJlc3BvbnNlIGhhcyBiZWVuIHJlY2VpdmVkXHJcbiAgICAgICAgcmVzcG9uc2Uub24oJ2VuZCcsICgpID0+IHtcclxuICAgICAgICAgIGlmICghcmVzcG9uc2VEYXRhKSB7XHJcbiAgICAgICAgICAgIHJlamVjdCgnTm90aGluZyB3YXMgZmV0Y2hlZCBmcm9tIHRoZSBVUkwuJyk7XHJcbiAgICAgICAgICB9XHJcbiAgICAgICAgICByZXNwb25zZS50ZXh0ID0gcmVzcG9uc2VEYXRhO1xyXG4gICAgICAgICAgcmVzb2x2ZShyZXNwb25zZSk7XHJcbiAgICAgICAgfSk7XHJcbiAgICAgIH0pXHJcbiAgICAgIC5vbignZXJyb3InLCAoZXJyb3IpID0+IHtcclxuICAgICAgICByZWplY3QoZXJyb3IpO1xyXG4gICAgICB9KTtcclxuICB9KTtcclxufVxyXG5cclxuLyoqXHJcbiAqIFNlbmRzIGEgUE9TVCByZXF1ZXN0IHRvIHRoZSBzcGVjaWZpZWQgVVJMIHdpdGggdGhlIHByb3ZpZGVkIEpTT04gYm9keSB1c2luZ1xyXG4gKiBlaXRoZXIgSFRUUCBvciBIVFRQUyBwcm90b2NvbC5cclxuICpcclxuICogQGFzeW5jXHJcbiAqIEBmdW5jdGlvbiBwb3N0XHJcbiAqXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSB1cmwgLSBUaGUgVVJMIHRvIHNlbmQgdGhlIFBPU1QgcmVxdWVzdCB0by5cclxuICogQHBhcmFtIHtPYmplY3R9IFtib2R5PXt9XSAtIFRoZSBKU09OIGJvZHkgdG8gaW5jbHVkZSBpbiB0aGUgUE9TVCByZXF1ZXN0LlxyXG4gKiBUaGUgZGVmYXVsdCB2YWx1ZSBpcyBhbiBlbXB0eSBvYmplY3QuXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBbcmVxdWVzdE9wdGlvbnM9e31dIC0gT3B0aW9ucyBmb3IgdGhlIEhUVFAvSFRUUFMgcmVxdWVzdC5cclxuICogVGhlIGRlZmF1bHQgdmFsdWUgaXMgYW4gZW1wdHkgb2JqZWN0LlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7UHJvbWlzZTxPYmplY3Q+fSBBIFByb21pc2UgdGhhdCByZXNvbHZlcyB0byB0aGUgSFRUUC9IVFRQUyByZXNwb25zZVxyXG4gKiBvYmplY3Qgd2l0aCBhZGRlZCAndGV4dCcgcHJvcGVydHkgb3IgcmVqZWN0aW5nIHdpdGggYW4gZXJyb3IuXHJcbiAqL1xyXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gcG9zdCh1cmwsIGJvZHkgPSB7fSwgcmVxdWVzdE9wdGlvbnMgPSB7fSkge1xyXG4gIHJldHVybiBuZXcgUHJvbWlzZSgocmVzb2x2ZSwgcmVqZWN0KSA9PiB7XHJcbiAgICBjb25zdCBkYXRhID0gSlNPTi5zdHJpbmdpZnkoYm9keSk7XHJcblxyXG4gICAgLy8gU2V0IGRlZmF1bHQgaGVhZGVycyBhbmQgbWVyZ2Ugd2l0aCByZXF1ZXN0T3B0aW9uc1xyXG4gICAgY29uc3Qgb3B0aW9ucyA9IE9iamVjdC5hc3NpZ24oXHJcbiAgICAgIHtcclxuICAgICAgICBtZXRob2Q6ICdQT1NUJyxcclxuICAgICAgICBoZWFkZXJzOiB7XHJcbiAgICAgICAgICAnQ29udGVudC1UeXBlJzogJ2FwcGxpY2F0aW9uL2pzb24nLFxyXG4gICAgICAgICAgJ0NvbnRlbnQtTGVuZ3RoJzogZGF0YS5sZW5ndGhcclxuICAgICAgICB9XHJcbiAgICAgIH0sXHJcbiAgICAgIHJlcXVlc3RPcHRpb25zXHJcbiAgICApO1xyXG5cclxuICAgIGNvbnN0IHJlcXVlc3QgPSBfZ2V0UHJvdG9jb2xNb2R1bGUodXJsKVxyXG4gICAgICAucmVxdWVzdCh1cmwsIG9wdGlvbnMsIChyZXNwb25zZSkgPT4ge1xyXG4gICAgICAgIGxldCByZXNwb25zZURhdGEgPSAnJztcclxuXHJcbiAgICAgICAgLy8gQSBjaHVuayBvZiBkYXRhIGhhcyBiZWVuIHJlY2VpdmVkXHJcbiAgICAgICAgcmVzcG9uc2Uub24oJ2RhdGEnLCAoY2h1bmspID0+IHtcclxuICAgICAgICAgIHJlc3BvbnNlRGF0YSArPSBjaHVuaztcclxuICAgICAgICB9KTtcclxuXHJcbiAgICAgICAgLy8gVGhlIHdob2xlIHJlc3BvbnNlIGhhcyBiZWVuIHJlY2VpdmVkXHJcbiAgICAgICAgcmVzcG9uc2Uub24oJ2VuZCcsICgpID0+IHtcclxuICAgICAgICAgIHRyeSB7XHJcbiAgICAgICAgICAgIHJlc3BvbnNlLnRleHQgPSByZXNwb25zZURhdGE7XHJcbiAgICAgICAgICAgIHJlc29sdmUocmVzcG9uc2UpO1xyXG4gICAgICAgICAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICAgICAgICAgcmVqZWN0KGVycm9yKTtcclxuICAgICAgICAgIH1cclxuICAgICAgICB9KTtcclxuICAgICAgfSlcclxuICAgICAgLm9uKCdlcnJvcicsIChlcnJvcikgPT4ge1xyXG4gICAgICAgIHJlamVjdChlcnJvcik7XHJcbiAgICAgIH0pO1xyXG5cclxuICAgIC8vIFdyaXRlIHRoZSByZXF1ZXN0IGJvZHkgYW5kIGVuZCB0aGUgcmVxdWVzdFxyXG4gICAgcmVxdWVzdC53cml0ZShkYXRhKTtcclxuICAgIHJlcXVlc3QuZW5kKCk7XHJcbiAgfSk7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBSZXR1cm5zIHRoZSBIVFRQIG9yIEhUVFBTIHByb3RvY29sIG1vZHVsZSBiYXNlZCBvbiB0aGUgcHJvdmlkZWQgVVJMLlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gX2dldFByb3RvY29sTW9kdWxlXHJcbiAqXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSB1cmwgLSBUaGUgVVJMIHRvIGRldGVybWluZSB0aGUgcHJvdG9jb2wuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtPYmplY3R9IFRoZSBIVFRQIG9yIEhUVFBTIHByb3RvY29sIG1vZHVsZSAoaHR0cCBvciBodHRwcykuXHJcbiAqL1xyXG5mdW5jdGlvbiBfZ2V0UHJvdG9jb2xNb2R1bGUodXJsKSB7XHJcbiAgcmV0dXJuIHVybC5zdGFydHNXaXRoKCdodHRwcycpID8gaHR0cHMgOiBodHRwO1xyXG59XHJcblxyXG5leHBvcnQgZGVmYXVsdCB7XHJcbiAgZmV0Y2gsXHJcbiAgcG9zdFxyXG59O1xyXG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxyXG5cclxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXHJcblxyXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNSwgSGlnaHNvZnRcclxuXHJcbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cclxuXHJcbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxyXG5cclxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxyXG5cclxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cclxuXHJcbi8qKlxyXG4gKiBBIGN1c3RvbSBlcnJvciBjbGFzcyBmb3IgaGFuZGxpbmcgZXhwb3J0LXJlbGF0ZWQgZXJyb3JzLiBFeHRlbmRzIHRoZSBuYXRpdmVcclxuICogYEVycm9yYCBjbGFzcyB0byBpbmNsdWRlIGFkZGl0aW9uYWwgcHJvcGVydGllcyBsaWtlIHN0YXR1cyBjb2RlIGFuZCBzdGFja1xyXG4gKiB0cmFjZSBkZXRhaWxzLlxyXG4gKi9cclxuY2xhc3MgRXhwb3J0RXJyb3IgZXh0ZW5kcyBFcnJvciB7XHJcbiAgLyoqXHJcbiAgICogQ3JlYXRlcyBhbiBpbnN0YW5jZSBvZiB0aGUgYEV4cG9ydEVycm9yYC5cclxuICAgKlxyXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBtZXNzYWdlIC0gVGhlIGVycm9yIG1lc3NhZ2UgdG8gYmUgZGlzcGxheWVkLlxyXG4gICAqIEBwYXJhbSB7bnVtYmVyfSBzdGF0dXNDb2RlIC0gT3B0aW9uYWwgSFRUUCBzdGF0dXMgY29kZSBhc3NvY2lhdGVkXHJcbiAgICogd2l0aCB0aGUgZXJyb3IgKGUuZy4sIDQwMCwgNTAwKS5cclxuICAgKi9cclxuICBjb25zdHJ1Y3RvcihtZXNzYWdlLCBzdGF0dXNDb2RlKSB7XHJcbiAgICBzdXBlcigpO1xyXG5cclxuICAgIHRoaXMubWVzc2FnZSA9IG1lc3NhZ2U7XHJcbiAgICB0aGlzLnN0YWNrTWVzc2FnZSA9IG1lc3NhZ2U7XHJcblxyXG4gICAgaWYgKHN0YXR1c0NvZGUpIHtcclxuICAgICAgdGhpcy5zdGF0dXNDb2RlID0gc3RhdHVzQ29kZTtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIC8qKlxyXG4gICAqIFNldHMgYWRkaXRpb25hbCBlcnJvciBkZXRhaWxzIGJhc2VkIG9uIGFuIGV4aXN0aW5nIGVycm9yIG9iamVjdC5cclxuICAgKlxyXG4gICAqIEBwYXJhbSB7RXJyb3J9IGVycm9yIC0gQW4gZXJyb3Igb2JqZWN0IGNvbnRhaW5pbmcgZGV0YWlscyB0byBwb3B1bGF0ZVxyXG4gICAqIHRoZSBgRXhwb3J0RXJyb3JgIGluc3RhbmNlLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge0V4cG9ydEVycm9yfSBUaGUgdXBkYXRlZCBpbnN0YW5jZSBvZiB0aGUgYEV4cG9ydEVycm9yYCBjbGFzcy5cclxuICAgKi9cclxuICBzZXRFcnJvcihlcnJvcikge1xyXG4gICAgdGhpcy5lcnJvciA9IGVycm9yO1xyXG5cclxuICAgIGlmIChlcnJvci5uYW1lKSB7XHJcbiAgICAgIHRoaXMubmFtZSA9IGVycm9yLm5hbWU7XHJcbiAgICB9XHJcblxyXG4gICAgaWYgKGVycm9yLnN0YXR1c0NvZGUpIHtcclxuICAgICAgdGhpcy5zdGF0dXNDb2RlID0gZXJyb3Iuc3RhdHVzQ29kZTtcclxuICAgIH1cclxuXHJcbiAgICBpZiAoZXJyb3Iuc3RhY2spIHtcclxuICAgICAgdGhpcy5zdGFja01lc3NhZ2UgPSBlcnJvci5tZXNzYWdlO1xyXG4gICAgICB0aGlzLnN0YWNrID0gZXJyb3Iuc3RhY2s7XHJcbiAgICB9XHJcblxyXG4gICAgcmV0dXJuIHRoaXM7XHJcbiAgfVxyXG59XHJcblxyXG5leHBvcnQgZGVmYXVsdCBFeHBvcnRFcnJvcjtcclxuIiwiLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcclxuXHJcbkhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlclxyXG5cclxuQ29weXJpZ2h0IChjKSAyMDE2LTIwMjUsIEhpZ2hzb2Z0XHJcblxyXG5MaWNlbmNlZCB1bmRlciB0aGUgTUlUIGxpY2VuY2UuXHJcblxyXG5BZGRpdGlvbmFsbHkgYSB2YWxpZCBIaWdoY2hhcnRzIGxpY2Vuc2UgaXMgcmVxdWlyZWQgZm9yIHVzZS5cclxuXHJcblNlZSBMSUNFTlNFIGZpbGUgaW4gcm9vdCBmb3IgZGV0YWlscy5cclxuXHJcbioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXHJcblxyXG4vKipcclxuICogQG92ZXJ2aWV3IFRoZSBjYWNoZSBtYW5hZ2VyIGlzIHJlc3BvbnNpYmxlIGZvciBoYW5kbGluZyBhbmQgbWFuYWdpbmdcclxuICogdGhlIEhpZ2hjaGFydHMgbGlicmFyeSBhbG9uZyB3aXRoIGl0cyBkZXBlbmRlbmNpZXMuIEl0IGVuc3VyZXMgdGhhdCB0aGVzZVxyXG4gKiByZXNvdXJjZXMgYXJlIHN0b3JlZCBhbmQgcmV0cmlldmVkIGVmZmljaWVudGx5IHRvIG9wdGltaXplIHBlcmZvcm1hbmNlXHJcbiAqIGFuZCByZWR1Y2UgcmVkdW5kYW50IG5ldHdvcmsgcmVxdWVzdHMuIFRoZSBjYWNoZSBpcyBzdG9yZWQgaW4gdGhlIGAuY2FjaGVgXHJcbiAqIGRpcmVjdG9yeSBieSBkZWZhdWx0LCB3aGljaCBzZXJ2ZXMgYXMgYSBkZWRpY2F0ZWQgZm9sZGVyIGZvciBrZWVwaW5nIGNhY2hlZFxyXG4gKiBmaWxlcy5cclxuICovXHJcblxyXG5pbXBvcnQgeyBleGlzdHNTeW5jLCBta2RpclN5bmMsIHJlYWRGaWxlU3luYywgd3JpdGVGaWxlU3luYyB9IGZyb20gJ2ZzJztcclxuaW1wb3J0IHsgam9pbiB9IGZyb20gJ3BhdGgnO1xyXG5cclxuaW1wb3J0IHsgSHR0cHNQcm94eUFnZW50IH0gZnJvbSAnaHR0cHMtcHJveHktYWdlbnQnO1xyXG5cclxuaW1wb3J0IHsgZ2V0T3B0aW9ucyB9IGZyb20gJy4vY29uZmlnLmpzJztcclxuaW1wb3J0IHsgZmV0Y2ggfSBmcm9tICcuL2ZldGNoLmpzJztcclxuaW1wb3J0IHsgbG9nIH0gZnJvbSAnLi9sb2dnZXIuanMnO1xyXG5pbXBvcnQgeyBfX2Rpcm5hbWUsIGdldEFic29sdXRlUGF0aCB9IGZyb20gJy4vdXRpbHMuanMnO1xyXG5cclxuaW1wb3J0IEV4cG9ydEVycm9yIGZyb20gJy4vZXJyb3JzL0V4cG9ydEVycm9yLmpzJztcclxuXHJcbi8vIFRoZSBpbml0aWFsIGNhY2hlIHRlbXBsYXRlXHJcbmNvbnN0IGNhY2hlID0ge1xyXG4gIGNkblVybDogJ2h0dHBzOi8vY29kZS5oaWdoY2hhcnRzLmNvbScsXHJcbiAgYWN0aXZlTWFuaWZlc3Q6IHt9LFxyXG4gIHNvdXJjZXM6ICcnLFxyXG4gIGhjVmVyc2lvbjogJydcclxufTtcclxuXHJcbi8qKlxyXG4gKiBDaGVja3MgdGhlIGNhY2hlIGZvciBIaWdoY2hhcnRzIGRlcGVuZGVuY2llcywgdXBkYXRlcyB0aGUgY2FjaGUgaWYgbmVlZGVkLFxyXG4gKiBhbmQgbG9hZHMgdGhlIHNvdXJjZXMuXHJcbiAqXHJcbiAqIEBhc3luY1xyXG4gKiBAZnVuY3Rpb24gY2hlY2tBbmRVcGRhdGVDYWNoZVxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gaGlnaGNoYXJ0c09wdGlvbnMgLSBPYmplY3QgY29udGFpbmluZyBgaGlnaGNoYXJ0c2Agb3B0aW9ucy5cclxuICogQHBhcmFtIHtPYmplY3R9IHNlcnZlclByb3h5T3B0aW9ucyAtIE9iamVjdCBjb250YWluaW5nIGBzZXJ2ZXIucHJveHlgXHJcbiAqIG9wdGlvbnMuXHJcbiAqL1xyXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gY2hlY2tBbmRVcGRhdGVDYWNoZShcclxuICBoaWdoY2hhcnRzT3B0aW9ucyxcclxuICBzZXJ2ZXJQcm94eU9wdGlvbnNcclxuKSB7XHJcbiAgbGV0IGZldGNoZWRNb2R1bGVzO1xyXG5cclxuICAvLyBHZXQgdGhlIGNhY2hlIHBhdGhcclxuICBjb25zdCBjYWNoZVBhdGggPSBnZXRDYWNoZVBhdGgoKTtcclxuXHJcbiAgLy8gUHJlcGFyZSBwYXRocyB0byBtYW5pZmVzdCBhbmQgc291cmNlcyBmcm9tIHRoZSBjYWNoZSBmb2xkZXJcclxuICBjb25zdCBtYW5pZmVzdFBhdGggPSBqb2luKGNhY2hlUGF0aCwgJ21hbmlmZXN0Lmpzb24nKTtcclxuICBjb25zdCBzb3VyY2VQYXRoID0gam9pbihjYWNoZVBhdGgsICdzb3VyY2VzLmpzJyk7XHJcblxyXG4gIC8vIENyZWF0ZSB0aGUgY2FjaGUgZGVzdGluYXRpb24gaWYgaXQgZG9lc24ndCBleGlzdCBhbHJlYWR5XHJcbiAgIWV4aXN0c1N5bmMoY2FjaGVQYXRoKSAmJiBta2RpclN5bmMoY2FjaGVQYXRoLCB7IHJlY3Vyc2l2ZTogdHJ1ZSB9KTtcclxuXHJcbiAgLy8gRmV0Y2ggYWxsIHRoZSBzY3JpcHRzIGVpdGhlciBpZiB0aGUgYG1hbmlmZXN0Lmpzb25gIGRvZXMgbm90IGV4aXN0XHJcbiAgLy8gb3IgaWYgdGhlIGBmb3JjZUZldGNoYCBvcHRpb24gaXMgZW5hYmxlZFxyXG4gIGlmICghZXhpc3RzU3luYyhtYW5pZmVzdFBhdGgpIHx8IGhpZ2hjaGFydHNPcHRpb25zLmZvcmNlRmV0Y2gpIHtcclxuICAgIGxvZygzLCAnW2NhY2hlXSBGZXRjaGluZyBhbmQgY2FjaGluZyBIaWdoY2hhcnRzIGRlcGVuZGVuY2llcy4nKTtcclxuICAgIGZldGNoZWRNb2R1bGVzID0gYXdhaXQgX3VwZGF0ZUNhY2hlKFxyXG4gICAgICBoaWdoY2hhcnRzT3B0aW9ucyxcclxuICAgICAgc2VydmVyUHJveHlPcHRpb25zLFxyXG4gICAgICBzb3VyY2VQYXRoXHJcbiAgICApO1xyXG4gIH0gZWxzZSB7XHJcbiAgICBsZXQgcmVxdWVzdFVwZGF0ZSA9IGZhbHNlO1xyXG5cclxuICAgIC8vIFJlYWQgdGhlIG1hbmlmZXN0IEpTT05cclxuICAgIGNvbnN0IG1hbmlmZXN0ID0gSlNPTi5wYXJzZShyZWFkRmlsZVN5bmMobWFuaWZlc3RQYXRoKSk7XHJcblxyXG4gICAgLy8gQ2hlY2sgaWYgdGhlIG1vZHVsZXMgaXMgYW4gYXJyYXksIGlmIHNvLCB3ZSByZXdyaXRlIGl0IHRvIGEgbWFwIHRvIG1ha2VcclxuICAgIC8vIGl0IGVhc2llciB0byByZXNvbHZlIG1vZHVsZXMuXHJcbiAgICBpZiAobWFuaWZlc3QubW9kdWxlcyAmJiBBcnJheS5pc0FycmF5KG1hbmlmZXN0Lm1vZHVsZXMpKSB7XHJcbiAgICAgIGNvbnN0IG1vZHVsZU1hcCA9IHt9O1xyXG4gICAgICBtYW5pZmVzdC5tb2R1bGVzLmZvckVhY2goKG0pID0+IChtb2R1bGVNYXBbbV0gPSAxKSk7XHJcbiAgICAgIG1hbmlmZXN0Lm1vZHVsZXMgPSBtb2R1bGVNYXA7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gR2V0IHRoZSBhY3R1YWwgbnVtYmVyIG9mIHNjcmlwdHMgdG8gYmUgZmV0Y2hlZFxyXG4gICAgY29uc3QgeyBjb3JlU2NyaXB0cywgbW9kdWxlU2NyaXB0cywgaW5kaWNhdG9yU2NyaXB0cyB9ID0gaGlnaGNoYXJ0c09wdGlvbnM7XHJcbiAgICBjb25zdCBudW1iZXJPZk1vZHVsZXMgPVxyXG4gICAgICBjb3JlU2NyaXB0cy5sZW5ndGggKyBtb2R1bGVTY3JpcHRzLmxlbmd0aCArIGluZGljYXRvclNjcmlwdHMubGVuZ3RoO1xyXG5cclxuICAgIC8vIENvbXBhcmUgdGhlIGxvYWRlZCBoaWdoY2hhcnRzIGNvbmZpZyB3aXRoIHRoZSBjb250ZW50cyBpbiBjYWNoZS5cclxuICAgIC8vIElmIHRoZXJlIGFyZSBjaGFuZ2VzLCBmZXRjaCByZXF1ZXN0ZWQgbW9kdWxlcyBhbmQgcHJvZHVjdHMsXHJcbiAgICAvLyBhbmQgYmFrZSB0aGVtIGludG8gYSBnaWFudCBibG9iLiBTYXZlIHRoZSBibG9iLlxyXG4gICAgaWYgKG1hbmlmZXN0LnZlcnNpb24gIT09IGhpZ2hjaGFydHNPcHRpb25zLnZlcnNpb24pIHtcclxuICAgICAgbG9nKFxyXG4gICAgICAgIDIsXHJcbiAgICAgICAgJ1tjYWNoZV0gQSBIaWdoY2hhcnRzIHZlcnNpb24gbWlzbWF0Y2ggaW4gdGhlIGNhY2hlLCBuZWVkIHRvIHJlLWZldGNoLidcclxuICAgICAgKTtcclxuICAgICAgcmVxdWVzdFVwZGF0ZSA9IHRydWU7XHJcbiAgICB9IGVsc2UgaWYgKE9iamVjdC5rZXlzKG1hbmlmZXN0Lm1vZHVsZXMgfHwge30pLmxlbmd0aCAhPT0gbnVtYmVyT2ZNb2R1bGVzKSB7XHJcbiAgICAgIGxvZyhcclxuICAgICAgICAyLFxyXG4gICAgICAgICdbY2FjaGVdIFRoZSBjYWNoZSBhbmQgdGhlIHJlcXVlc3RlZCBtb2R1bGVzIGRvIG5vdCBtYXRjaCwgbmVlZCB0byByZS1mZXRjaC4nXHJcbiAgICAgICk7XHJcbiAgICAgIHJlcXVlc3RVcGRhdGUgPSB0cnVlO1xyXG4gICAgfSBlbHNlIHtcclxuICAgICAgLy8gQ2hlY2sgZWFjaCBtb2R1bGUsIGlmIGFueXRoaW5nIGlzIG1pc3NpbmcgcmVmZXRjaCBldmVyeXRoaW5nXHJcbiAgICAgIHJlcXVlc3RVcGRhdGUgPSAobW9kdWxlU2NyaXB0cyB8fCBbXSkuc29tZSgobW9kdWxlTmFtZSkgPT4ge1xyXG4gICAgICAgIGlmICghbWFuaWZlc3QubW9kdWxlc1ttb2R1bGVOYW1lXSkge1xyXG4gICAgICAgICAgbG9nKFxyXG4gICAgICAgICAgICAyLFxyXG4gICAgICAgICAgICBgW2NhY2hlXSBUaGUgJHttb2R1bGVOYW1lfSBpcyBtaXNzaW5nIGluIHRoZSBjYWNoZSwgbmVlZCB0byByZS1mZXRjaC5gXHJcbiAgICAgICAgICApO1xyXG4gICAgICAgICAgcmV0dXJuIHRydWU7XHJcbiAgICAgICAgfVxyXG4gICAgICB9KTtcclxuICAgIH1cclxuXHJcbiAgICAvLyBVcGRhdGUgY2FjaGUgaWYgbmVlZGVkXHJcbiAgICBpZiAocmVxdWVzdFVwZGF0ZSkge1xyXG4gICAgICBmZXRjaGVkTW9kdWxlcyA9IGF3YWl0IF91cGRhdGVDYWNoZShcclxuICAgICAgICBoaWdoY2hhcnRzT3B0aW9ucyxcclxuICAgICAgICBzZXJ2ZXJQcm94eU9wdGlvbnMsXHJcbiAgICAgICAgc291cmNlUGF0aFxyXG4gICAgICApO1xyXG4gICAgfSBlbHNlIHtcclxuICAgICAgbG9nKDMsICdbY2FjaGVdIERlcGVuZGVuY3kgY2FjaGUgaXMgdXAgdG8gZGF0ZSwgcHJvY2VlZGluZy4nKTtcclxuXHJcbiAgICAgIC8vIExvYWQgdGhlIHNvdXJjZXNcclxuICAgICAgY2FjaGUuc291cmNlcyA9IHJlYWRGaWxlU3luYyhzb3VyY2VQYXRoLCAndXRmOCcpO1xyXG5cclxuICAgICAgLy8gR2V0IGN1cnJlbnQgbW9kdWxlcyBtYXBcclxuICAgICAgZmV0Y2hlZE1vZHVsZXMgPSBtYW5pZmVzdC5tb2R1bGVzO1xyXG5cclxuICAgICAgLy8gRXh0cmFjdCBhbmQgc2F2ZSB2ZXJzaW9uIG9mIGN1cnJlbnRseSB1c2VkIEhpZ2hjaGFydHNcclxuICAgICAgY2FjaGUuaGNWZXJzaW9uID0gZXh0cmFjdFZlcnNpb24oY2FjaGUuc291cmNlcyk7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICAvLyBGaW5hbGx5LCBzYXZlIHRoZSBuZXcgbWFuaWZlc3QsIHdoaWNoIGlzIGJhc2ljYWxseSBvdXIgY3VycmVudCBjb25maWdcclxuICAvLyBpbiBhIHNsaWdodGx5IGRpZmZlcmVudCBmb3JtYXRcclxuICBhd2FpdCBfc2F2ZUNvbmZpZ1RvTWFuaWZlc3QoaGlnaGNoYXJ0c09wdGlvbnMsIGZldGNoZWRNb2R1bGVzKTtcclxufVxyXG5cclxuLyoqXHJcbiAqIEdldHMgdGhlIHZlcnNpb24gb2YgSGlnaGNoYXJ0cyBmcm9tIHRoZSBjYWNoZS5cclxuICpcclxuICogQGZ1bmN0aW9uIGdldEhpZ2hjaGFydHNWZXJzaW9uXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtzdHJpbmd9IFRoZSBjYWNoZWQgSGlnaGNoYXJ0cyB2ZXJzaW9uLlxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIGdldEhpZ2hjaGFydHNWZXJzaW9uKCkge1xyXG4gIHJldHVybiBjYWNoZS5oY1ZlcnNpb247XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBVcGRhdGVzIHRoZSBIaWdoY2hhcnRzIHZlcnNpb24gaW4gdGhlIGFwcGxpZWQgY29uZmlndXJhdGlvbiBhbmQgY2hlY2tzXHJcbiAqIHRoZSBjYWNoZSBmb3IgdGhlIG5ldyB2ZXJzaW9uLlxyXG4gKlxyXG4gKiBAYXN5bmNcclxuICogQGZ1bmN0aW9uIHVwZGF0ZUhpZ2hjaGFydHNWZXJzaW9uXHJcbiAqXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSBuZXdWZXJzaW9uIC0gVGhlIG5ldyBIaWdoY2hhcnRzIHZlcnNpb24gdG8gYmUgYXBwbGllZC5cclxuICovXHJcbmV4cG9ydCBhc3luYyBmdW5jdGlvbiB1cGRhdGVIaWdoY2hhcnRzVmVyc2lvbihuZXdWZXJzaW9uKSB7XHJcbiAgLy8gR2V0IHRoZSByZWZlcmVuY2UgdG8gdGhlIGdsb2JhbCBvcHRpb25zIHRvIHVwZGF0ZSB0byB0aGUgbmV3IHZlcnNpb25cclxuICBjb25zdCBvcHRpb25zID0gZ2V0T3B0aW9ucygpO1xyXG5cclxuICAvLyBTZXQgdG8gdGhlIG5ldyB2ZXJzaW9uXHJcbiAgb3B0aW9ucy5oaWdoY2hhcnRzLnZlcnNpb24gPSBuZXdWZXJzaW9uO1xyXG5cclxuICAvLyBDaGVjayBpZiBjYWNoZSBuZWVkcyB0byBiZSB1cGRhdGVkXHJcbiAgYXdhaXQgY2hlY2tBbmRVcGRhdGVDYWNoZShvcHRpb25zLmhpZ2hjaGFydHMsIG9wdGlvbnMuc2VydmVyLnByb3h5KTtcclxufVxyXG5cclxuLyoqXHJcbiAqIEV4dHJhY3RzIEhpZ2hjaGFydHMgdmVyc2lvbiBmcm9tIHRoZSBjYWNoZSdzIHNvdXJjZXMgc3RyaW5nLlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gZXh0cmFjdFZlcnNpb25cclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IGNhY2hlU291cmNlcyAtIFRoZSBjYWNoZSBzb3VyY2VzIG9iamVjdC5cclxuICpcclxuICogQHJldHVybnMge3N0cmluZ30gVGhlIGV4dHJhY3RlZCBIaWdoY2hhcnRzIHZlcnNpb24uXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gZXh0cmFjdFZlcnNpb24oY2FjaGVTb3VyY2VzKSB7XHJcbiAgcmV0dXJuIGNhY2hlU291cmNlc1xyXG4gICAgLnN1YnN0cmluZygwLCBjYWNoZVNvdXJjZXMuaW5kZXhPZignKi8nKSlcclxuICAgIC5yZXBsYWNlKCcvKicsICcnKVxyXG4gICAgLnJlcGxhY2UoJyovJywgJycpXHJcbiAgICAucmVwbGFjZSgvXFxuL2csICcnKVxyXG4gICAgLnRyaW0oKTtcclxufVxyXG5cclxuLyoqXHJcbiAqIEV4dHJhY3RzIHRoZSBIaWdoY2hhcnRzIG1vZHVsZSBuYW1lIGJhc2VkIG9uIHRoZSBzY3JpcHRQYXRoLlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gZXh0cmFjdE1vZHVsZU5hbWVcclxuICpcclxuICogQHBhcmFtIHtzdHJpbmd9IHNjcmlwdFBhdGggLSBUaGUgcGF0aCBvZiB0aGUgc2NyaXB0IGZyb20gd2hpY2ggdGhlIG1vZHVsZVxyXG4gKiBuYW1lIHdpbGwgYmUgZXh0cmFjdGVkLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7c3RyaW5nfSBUaGUgZXh0cmFjdGVkIG1vZHVsZSBuYW1lLlxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIGV4dHJhY3RNb2R1bGVOYW1lKHNjcmlwdFBhdGgpIHtcclxuICByZXR1cm4gc2NyaXB0UGF0aC5yZXBsYWNlKFxyXG4gICAgLyguKilcXC98KC4qKW1vZHVsZXNcXC98c3RvY2tcXC8oLiopaW5kaWNhdG9yc1xcL3xtYXBzXFwvKC4qKW1vZHVsZXNcXC8vZ2ksXHJcbiAgICAnJ1xyXG4gICk7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBSZXRyaWV2ZXMgdGhlIGN1cnJlbnQgY2FjaGUgb2JqZWN0LlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gZ2V0Q2FjaGVcclxuICpcclxuICogQHJldHVybnMge09iamVjdH0gVGhlIGNhY2hlIG9iamVjdCBjb250YWluaW5nIHZhcmlvdXMgY2FjaGVkIGRhdGEuXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gZ2V0Q2FjaGUoKSB7XHJcbiAgcmV0dXJuIGNhY2hlO1xyXG59XHJcblxyXG4vKipcclxuICogR2V0cyB0aGUgY2FjaGUgcGF0aCBmb3IgSGlnaGNoYXJ0cy5cclxuICpcclxuICogQGZ1bmN0aW9uIGdldENhY2hlUGF0aFxyXG4gKlxyXG4gKiBAcmV0dXJucyB7c3RyaW5nfSBUaGUgYWJzb2x1dGUgcGF0aCB0byB0aGUgY2FjaGUgZGlyZWN0b3J5IGZvciBIaWdoY2hhcnRzLlxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIGdldENhY2hlUGF0aCgpIHtcclxuICByZXR1cm4gZ2V0QWJzb2x1dGVQYXRoKGdldE9wdGlvbnMoKS5oaWdoY2hhcnRzLmNhY2hlUGF0aCk7IC8vICM1NjJcclxufVxyXG5cclxuLyoqXHJcbiAqIEZldGNoZXMgYSBzaW5nbGUgc2NyaXB0IGFuZCB1cGRhdGVzIHRoZSBgZmV0Y2hlZE1vZHVsZXNgIGFjY29yZGluZ2x5LlxyXG4gKlxyXG4gKiBAYXN5bmNcclxuICogQGZ1bmN0aW9uIF9mZXRjaEFuZFByb2Nlc3NTY3JpcHRcclxuICpcclxuICogQHBhcmFtIHtzdHJpbmd9IHNjcmlwdCAtIEEgcGF0aCB0byBzY3JpcHQgdG8gZ2V0LlxyXG4gKiBAcGFyYW0ge09iamVjdH0gcmVxdWVzdE9wdGlvbnMgLSBBZGRpdGlvbmFsIG9wdGlvbnMgZm9yIHRoZSBwcm94eSBhZ2VudFxyXG4gKiB0byB1c2UgZm9yIGEgcmVxdWVzdC5cclxuICogQHBhcmFtIHtPYmplY3R9IGZldGNoZWRNb2R1bGVzIC0gQW4gb2JqZWN0IHdoaWNoIHRyYWNrcyB3aGljaCBIaWdoY2hhcnRzXHJcbiAqIG1vZHVsZXMgaGF2ZSBiZWVuIGZldGNoZWQuXHJcbiAqIEBwYXJhbSB7Ym9vbGVhbn0gW3Nob3VsZFRocm93RXJyb3I9ZmFsc2VdIC0gQSBmbGFnIHRvIGluZGljYXRlIGlmIHRoZSBlcnJvclxyXG4gKiBzaG91bGQgYmUgdGhyb3duLiBUaGlzIHNob3VsZCBiZSB1c2VkIG9ubHkgZm9yIHRoZSBjb3JlIHNjcmlwdHMuIFRoZSBkZWZhdWx0XHJcbiAqIHZhbHVlIGlzIGZhbHNlLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7UHJvbWlzZTxzdHJpbmc+fSBBIFByb21pc2UgdGhhdCByZXNvbHZlcyB0byB0aGUgdGV4dCByZXByZXNlbnRhdGlvblxyXG4gKiBvZiB0aGUgZmV0Y2hlZCBzY3JpcHQuXHJcbiAqXHJcbiAqIEB0aHJvd3Mge0V4cG9ydEVycm9yfSBUaHJvd3MgYW4gYEV4cG9ydEVycm9yYCBpZiB0aGVyZSBpcyBhIHByb2JsZW1cclxuICogd2l0aCBmZXRjaGluZyB0aGUgc2NyaXB0LlxyXG4gKi9cclxuYXN5bmMgZnVuY3Rpb24gX2ZldGNoQW5kUHJvY2Vzc1NjcmlwdChcclxuICBzY3JpcHQsXHJcbiAgcmVxdWVzdE9wdGlvbnMsXHJcbiAgZmV0Y2hlZE1vZHVsZXMsXHJcbiAgc2hvdWxkVGhyb3dFcnJvciA9IGZhbHNlXHJcbikge1xyXG4gIC8vIEdldCByaWQgb2YgdGhlIC5qcyBmcm9tIHRoZSBjdXN0b20gc3RyaW5nc1xyXG4gIGlmIChzY3JpcHQuZW5kc1dpdGgoJy5qcycpKSB7XHJcbiAgICBzY3JpcHQgPSBzY3JpcHQuc3Vic3RyaW5nKDAsIHNjcmlwdC5sZW5ndGggLSAzKTtcclxuICB9XHJcbiAgbG9nKDQsIGBbY2FjaGVdIEZldGNoaW5nIHNjcmlwdCAtICR7c2NyaXB0fS5qc2ApO1xyXG5cclxuICAvLyBGZXRjaCB0aGUgc2NyaXB0XHJcbiAgY29uc3QgcmVzcG9uc2UgPSBhd2FpdCBmZXRjaChgJHtzY3JpcHR9LmpzYCwgcmVxdWVzdE9wdGlvbnMpO1xyXG5cclxuICAvLyBJZiBPSywgcmV0dXJuIGl0cyB0ZXh0IHJlcHJlc2VudGF0aW9uXHJcbiAgaWYgKHJlc3BvbnNlLnN0YXR1c0NvZGUgPT09IDIwMCAmJiB0eXBlb2YgcmVzcG9uc2UudGV4dCA9PSAnc3RyaW5nJykge1xyXG4gICAgaWYgKGZldGNoZWRNb2R1bGVzKSB7XHJcbiAgICAgIGNvbnN0IG1vZHVsZU5hbWUgPSBleHRyYWN0TW9kdWxlTmFtZShzY3JpcHQpO1xyXG4gICAgICBmZXRjaGVkTW9kdWxlc1ttb2R1bGVOYW1lXSA9IDE7XHJcbiAgICB9XHJcbiAgICByZXR1cm4gcmVzcG9uc2UudGV4dDtcclxuICB9XHJcblxyXG4gIC8vIEJhc2VkIG9uIHRoZSBgc2hvdWxkVGhyb3dFcnJvcmAgZmxhZywgZGVjaWRlIGhvdyB0byBzZXJ2ZSBlcnJvciBtZXNzYWdlXHJcbiAgaWYgKHNob3VsZFRocm93RXJyb3IpIHtcclxuICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcihcclxuICAgICAgYFtjYWNoZV0gQ291bGQgbm90IGZldGNoIHRoZSAke3NjcmlwdH0uanMuIFRoZSBzY3JpcHQgbWlnaHQgbm90IGV4aXN0IGluIHRoZSByZXF1ZXN0ZWQgdmVyc2lvbiAoc3RhdHVzIGNvZGU6ICR7cmVzcG9uc2Uuc3RhdHVzQ29kZX0pLmAsXHJcbiAgICAgIDQwNFxyXG4gICAgKS5zZXRFcnJvcihyZXNwb25zZSk7XHJcbiAgfSBlbHNlIHtcclxuICAgIGxvZyhcclxuICAgICAgMixcclxuICAgICAgYFtjYWNoZV0gQ291bGQgbm90IGZldGNoIHRoZSAke3NjcmlwdH0uanMuIFRoZSBzY3JpcHQgbWlnaHQgbm90IGV4aXN0IGluIHRoZSByZXF1ZXN0ZWQgdmVyc2lvbi5gXHJcbiAgICApO1xyXG4gIH1cclxufVxyXG5cclxuLyoqXHJcbiAqIFNhdmVzIHRoZSBwcm92aWRlZCBjb25maWd1cmF0aW9uIGFuZCBmZXRjaGVkIG1vZHVsZXMgdG8gdGhlIGNhY2hlIG1hbmlmZXN0XHJcbiAqIGZpbGUuXHJcbiAqXHJcbiAqIEBhc3luY1xyXG4gKiBAZnVuY3Rpb24gX3NhdmVDb25maWdUb01hbmlmZXN0XHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBoaWdoY2hhcnRzT3B0aW9ucyAtIE9iamVjdCBjb250YWluaW5nIGBoaWdoY2hhcnRzYCBvcHRpb25zLlxyXG4gKiBAcGFyYW0ge09iamVjdH0gW2ZldGNoZWRNb2R1bGVzPXt9XSAtIEFuIG9iamVjdCB3aGljaCB0cmFja3Mgd2hpY2ggSGlnaGNoYXJ0c1xyXG4gKiBtb2R1bGVzIGhhdmUgYmVlbiBmZXRjaGVkLiBUaGUgZGVmYXVsdCB2YWx1ZSBpcyBhbiBlbXB0eSBvYmplY3QuXHJcbiAqXHJcbiAqIEB0aHJvd3Mge0V4cG9ydEVycm9yfSBUaHJvd3MgYW4gYEV4cG9ydEVycm9yYCBpZiBhbiBlcnJvciBvY2N1cnMgd2hpbGVcclxuICogd3JpdGluZyB0aGUgY2FjaGUgbWFuaWZlc3QuXHJcbiAqL1xyXG5hc3luYyBmdW5jdGlvbiBfc2F2ZUNvbmZpZ1RvTWFuaWZlc3QoaGlnaGNoYXJ0c09wdGlvbnMsIGZldGNoZWRNb2R1bGVzID0ge30pIHtcclxuICBjb25zdCBuZXdNYW5pZmVzdCA9IHtcclxuICAgIHZlcnNpb246IGhpZ2hjaGFydHNPcHRpb25zLnZlcnNpb24sXHJcbiAgICBtb2R1bGVzOiBmZXRjaGVkTW9kdWxlc1xyXG4gIH07XHJcblxyXG4gIC8vIFVwZGF0ZSBjYWNoZSBvYmplY3Qgd2l0aCB0aGUgY3VycmVudCBtb2R1bGVzXHJcbiAgY2FjaGUuYWN0aXZlTWFuaWZlc3QgPSBuZXdNYW5pZmVzdDtcclxuXHJcbiAgbG9nKDMsICdbY2FjaGVdIFdyaXRpbmcgYSBuZXcgbWFuaWZlc3QuJyk7XHJcbiAgdHJ5IHtcclxuICAgIHdyaXRlRmlsZVN5bmMoXHJcbiAgICAgIGpvaW4oZ2V0Q2FjaGVQYXRoKCksICdtYW5pZmVzdC5qc29uJyksXHJcbiAgICAgIEpTT04uc3RyaW5naWZ5KG5ld01hbmlmZXN0KSxcclxuICAgICAgJ3V0ZjgnXHJcbiAgICApO1xyXG4gIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoXHJcbiAgICAgICdbY2FjaGVdIEVycm9yIHdyaXRpbmcgdGhlIGNhY2hlIG1hbmlmZXN0LicsXHJcbiAgICAgIDUwMFxyXG4gICAgKS5zZXRFcnJvcihlcnJvcik7XHJcbiAgfVxyXG59XHJcblxyXG4vKipcclxuICogRmV0Y2hlcyBIaWdoY2hhcnRzIGBzY3JpcHRzYCBhbmQgYGN1c3RvbVNjcmlwdHNgIGZyb20gdGhlIGdpdmVuIENETnMuXHJcbiAqXHJcbiAqIEBhc3luY1xyXG4gKiBAZnVuY3Rpb24gX2ZldGNoU2NyaXB0c1xyXG4gKlxyXG4gKiBAcGFyYW0ge0FycmF5LjxzdHJpbmc+fSBjb3JlU2NyaXB0cyAtIEhpZ2hjaGFydHMgY29yZSBzY3JpcHRzIHRvIGZldGNoLlxyXG4gKiBAcGFyYW0ge0FycmF5LjxzdHJpbmc+fSBtb2R1bGVTY3JpcHRzIC0gSGlnaGNoYXJ0cyBtb2R1bGVzIHRvIGZldGNoLlxyXG4gKiBAcGFyYW0ge0FycmF5LjxzdHJpbmc+fSBjdXN0b21TY3JpcHRzIC0gQ3VzdG9tIHNjcmlwdCBwYXRocyB0byBmZXRjaCAoZnVsbFxyXG4gKiBVUkxzKS5cclxuICogQHBhcmFtIHtPYmplY3R9IHNlcnZlclByb3h5T3B0aW9ucyAtIE9iamVjdCBjb250YWluaW5nIGBzZXJ2ZXIucHJveHlgXHJcbiAqIG9wdGlvbnMuXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBmZXRjaGVkTW9kdWxlcyAtIEFuIG9iamVjdCB3aGljaCB0cmFja3Mgd2hpY2ggSGlnaGNoYXJ0c1xyXG4gKiBtb2R1bGVzIGhhdmUgYmVlbiBmZXRjaGVkLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7UHJvbWlzZTxzdHJpbmc+fSBBIFByb21pc2UgdGhhdCByZXNvbHZlcyB0byB0aGUgZmV0Y2hlZCBzY3JpcHRzXHJcbiAqIGNvbnRlbnQgam9pbmVkLlxyXG4gKlxyXG4gKiBAdGhyb3dzIHtFeHBvcnRFcnJvcn0gVGhyb3dzIGFuIGBFeHBvcnRFcnJvcmAgaWYgYW4gZXJyb3Igb2NjdXJzIHdoaWxlXHJcbiAqIHNldHRpbmcgYW4gSFRUUCBBZ2VudCBmb3IgcHJveHkuXHJcbiAqL1xyXG5hc3luYyBmdW5jdGlvbiBfZmV0Y2hTY3JpcHRzKFxyXG4gIGNvcmVTY3JpcHRzLFxyXG4gIG1vZHVsZVNjcmlwdHMsXHJcbiAgY3VzdG9tU2NyaXB0cyxcclxuICBzZXJ2ZXJQcm94eU9wdGlvbnMsXHJcbiAgZmV0Y2hlZE1vZHVsZXNcclxuKSB7XHJcbiAgLy8gQ29uZmlndXJlIHByb3h5IGlmIGV4aXN0c1xyXG4gIGxldCBwcm94eUFnZW50O1xyXG4gIGNvbnN0IHByb3h5SG9zdCA9IHNlcnZlclByb3h5T3B0aW9ucy5ob3N0O1xyXG4gIGNvbnN0IHByb3h5UG9ydCA9IHNlcnZlclByb3h5T3B0aW9ucy5wb3J0O1xyXG5cclxuICAvLyBUcnkgdG8gY3JlYXRlIGEgUHJveHkgQWdlbnRcclxuICBpZiAocHJveHlIb3N0ICYmIHByb3h5UG9ydCkge1xyXG4gICAgdHJ5IHtcclxuICAgICAgcHJveHlBZ2VudCA9IG5ldyBIdHRwc1Byb3h5QWdlbnQoe1xyXG4gICAgICAgIGhvc3Q6IHByb3h5SG9zdCxcclxuICAgICAgICBwb3J0OiBwcm94eVBvcnRcclxuICAgICAgfSk7XHJcbiAgICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoXHJcbiAgICAgICAgJ1tjYWNoZV0gQ291bGQgbm90IGNyZWF0ZSBhIFByb3h5IEFnZW50LicsXHJcbiAgICAgICAgNTAwXHJcbiAgICAgICkuc2V0RXJyb3IoZXJyb3IpO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgLy8gSWYgZXhpc3RzLCBhZGQgcHJveHkgYWdlbnQgdG8gcmVxdWVzdCBvcHRpb25zXHJcbiAgY29uc3QgcmVxdWVzdE9wdGlvbnMgPSBwcm94eUFnZW50XHJcbiAgICA/IHtcclxuICAgICAgICBhZ2VudDogcHJveHlBZ2VudCxcclxuICAgICAgICB0aW1lb3V0OiBzZXJ2ZXJQcm94eU9wdGlvbnMudGltZW91dFxyXG4gICAgICB9XHJcbiAgICA6IHt9O1xyXG5cclxuICBjb25zdCBhbGxGZXRjaFByb21pc2VzID0gW1xyXG4gICAgLi4uY29yZVNjcmlwdHMubWFwKChzY3JpcHQpID0+XHJcbiAgICAgIF9mZXRjaEFuZFByb2Nlc3NTY3JpcHQoYCR7c2NyaXB0fWAsIHJlcXVlc3RPcHRpb25zLCBmZXRjaGVkTW9kdWxlcywgdHJ1ZSlcclxuICAgICksXHJcbiAgICAuLi5tb2R1bGVTY3JpcHRzLm1hcCgoc2NyaXB0KSA9PlxyXG4gICAgICBfZmV0Y2hBbmRQcm9jZXNzU2NyaXB0KGAke3NjcmlwdH1gLCByZXF1ZXN0T3B0aW9ucywgZmV0Y2hlZE1vZHVsZXMpXHJcbiAgICApLFxyXG4gICAgLi4uY3VzdG9tU2NyaXB0cy5tYXAoKHNjcmlwdCkgPT5cclxuICAgICAgX2ZldGNoQW5kUHJvY2Vzc1NjcmlwdChgJHtzY3JpcHR9YCwgcmVxdWVzdE9wdGlvbnMpXHJcbiAgICApXHJcbiAgXTtcclxuXHJcbiAgY29uc3QgZmV0Y2hlZFNjcmlwdHMgPSBhd2FpdCBQcm9taXNlLmFsbChhbGxGZXRjaFByb21pc2VzKTtcclxuICByZXR1cm4gZmV0Y2hlZFNjcmlwdHMuam9pbignO1xcbicpO1xyXG59XHJcblxyXG4vKipcclxuICogVXBkYXRlcyB0aGUgbG9jYWwgY2FjaGUgd2l0aCBIaWdoY2hhcnRzIHNjcmlwdHMgYW5kIHRoZWlyIHZlcnNpb25zLlxyXG4gKlxyXG4gKiBAYXN5bmNcclxuICogQGZ1bmN0aW9uIF91cGRhdGVDYWNoZVxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gaGlnaGNoYXJ0c09wdGlvbnMgLSBPYmplY3QgY29udGFpbmluZyBgaGlnaGNoYXJ0c2Agb3B0aW9ucy5cclxuICogQHBhcmFtIHtPYmplY3R9IHNlcnZlclByb3h5T3B0aW9ucyAtIE9iamVjdCBjb250YWluaW5nIGBzZXJ2ZXIucHJveHlgXHJcbiAqIG9wdGlvbnMuXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSBzb3VyY2VQYXRoIC0gVGhlIHBhdGggdG8gdGhlIHNvdXJjZSBmaWxlIGluIHRoZSBjYWNoZS5cclxuICpcclxuICogQHJldHVybnMge1Byb21pc2U8T2JqZWN0Pn0gQSBQcm9taXNlIHRoYXQgcmVzb2x2ZXMgdG8gYW4gb2JqZWN0IHJlcHJlc2VudGluZ1xyXG4gKiB0aGUgZmV0Y2hlZCBtb2R1bGVzLlxyXG4gKlxyXG4gKiBAdGhyb3dzIHtFeHBvcnRFcnJvcn0gVGhyb3dzIGFuIGBFeHBvcnRFcnJvcmAgaWYgdGhlcmUgaXMgYW4gaXNzdWUgdXBkYXRpbmdcclxuICogdGhlIGxvY2FsIEhpZ2hjaGFydHMgY2FjaGUuXHJcbiAqL1xyXG5hc3luYyBmdW5jdGlvbiBfdXBkYXRlQ2FjaGUoaGlnaGNoYXJ0c09wdGlvbnMsIHNlcnZlclByb3h5T3B0aW9ucywgc291cmNlUGF0aCkge1xyXG4gIC8vIEdldCBIaWdoY2hhcnRzIHZlcnNpb24gZm9yIHNjcmlwdHNcclxuICBjb25zdCBoY1ZlcnNpb24gPVxyXG4gICAgaGlnaGNoYXJ0c09wdGlvbnMudmVyc2lvbiA9PT0gJ2xhdGVzdCdcclxuICAgICAgPyBudWxsXHJcbiAgICAgIDogYCR7aGlnaGNoYXJ0c09wdGlvbnMudmVyc2lvbn1gO1xyXG5cclxuICAvLyBHZXQgdGhlIENETiB1cmwgZm9yIHNjcmlwdHNcclxuICBjb25zdCBjZG5VcmwgPSBoaWdoY2hhcnRzT3B0aW9ucy5jZG5VcmwgfHwgY2FjaGUuY2RuVXJsO1xyXG5cclxuICB0cnkge1xyXG4gICAgY29uc3QgZmV0Y2hlZE1vZHVsZXMgPSB7fTtcclxuXHJcbiAgICBsb2coXHJcbiAgICAgIDMsXHJcbiAgICAgIGBbY2FjaGVdIFVwZGF0aW5nIGNhY2hlIHZlcnNpb24gdG8gSGlnaGNoYXJ0czogJHtoY1ZlcnNpb24gfHwgJ2xhdGVzdCd9LmBcclxuICAgICk7XHJcblxyXG4gICAgY2FjaGUuc291cmNlcyA9IGF3YWl0IF9mZXRjaFNjcmlwdHMoXHJcbiAgICAgIFtcclxuICAgICAgICAuLi5oaWdoY2hhcnRzT3B0aW9ucy5jb3JlU2NyaXB0cy5tYXAoKGMpID0+XHJcbiAgICAgICAgICBoY1ZlcnNpb24gPyBgJHtjZG5Vcmx9LyR7aGNWZXJzaW9ufS8ke2N9YCA6IGAke2NkblVybH0vJHtjfWBcclxuICAgICAgICApXHJcbiAgICAgIF0sXHJcbiAgICAgIFtcclxuICAgICAgICAuLi5oaWdoY2hhcnRzT3B0aW9ucy5tb2R1bGVTY3JpcHRzLm1hcCgobSkgPT5cclxuICAgICAgICAgIG0gPT09ICdtYXAnXHJcbiAgICAgICAgICAgID8gaGNWZXJzaW9uXHJcbiAgICAgICAgICAgICAgPyBgJHtjZG5Vcmx9L21hcHMvJHtoY1ZlcnNpb259L21vZHVsZXMvJHttfWBcclxuICAgICAgICAgICAgICA6IGAke2NkblVybH0vbWFwcy9tb2R1bGVzLyR7bX1gXHJcbiAgICAgICAgICAgIDogaGNWZXJzaW9uXHJcbiAgICAgICAgICAgICAgPyBgJHtjZG5Vcmx9LyR7aGNWZXJzaW9ufS9tb2R1bGVzLyR7bX1gXHJcbiAgICAgICAgICAgICAgOiBgJHtjZG5Vcmx9L21vZHVsZXMvJHttfWBcclxuICAgICAgICApLFxyXG4gICAgICAgIC4uLmhpZ2hjaGFydHNPcHRpb25zLmluZGljYXRvclNjcmlwdHMubWFwKChpKSA9PlxyXG4gICAgICAgICAgaGNWZXJzaW9uXHJcbiAgICAgICAgICAgID8gYCR7Y2RuVXJsfS9zdG9jay8ke2hjVmVyc2lvbn0vaW5kaWNhdG9ycy8ke2l9YFxyXG4gICAgICAgICAgICA6IGAke2NkblVybH0vc3RvY2svaW5kaWNhdG9ycy8ke2l9YFxyXG4gICAgICAgIClcclxuICAgICAgXSxcclxuICAgICAgaGlnaGNoYXJ0c09wdGlvbnMuY3VzdG9tU2NyaXB0cyxcclxuICAgICAgc2VydmVyUHJveHlPcHRpb25zLFxyXG4gICAgICBmZXRjaGVkTW9kdWxlc1xyXG4gICAgKTtcclxuXHJcbiAgICAvLyBFeHRyYWN0IGFuZCBzYXZlIHZlcnNpb24gb2YgY3VycmVudGx5IHVzZWQgSGlnaGNoYXJ0c1xyXG4gICAgY2FjaGUuaGNWZXJzaW9uID0gZXh0cmFjdFZlcnNpb24oY2FjaGUuc291cmNlcyk7XHJcblxyXG4gICAgLy8gU2F2ZSB0aGUgZmV0Y2hlZCBtb2R1bGVzIGludG8gY2FjaGVzJyBzb3VyY2UgSlNPTlxyXG4gICAgd3JpdGVGaWxlU3luYyhzb3VyY2VQYXRoLCBjYWNoZS5zb3VyY2VzKTtcclxuICAgIHJldHVybiBmZXRjaGVkTW9kdWxlcztcclxuICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgdGhyb3cgbmV3IEV4cG9ydEVycm9yKFxyXG4gICAgICAnW2NhY2hlXSBVbmFibGUgdG8gdXBkYXRlIHRoZSBsb2NhbCBIaWdoY2hhcnRzIGNhY2hlLicsXHJcbiAgICAgIDUwMFxyXG4gICAgKS5zZXRFcnJvcihlcnJvcik7XHJcbiAgfVxyXG59XHJcblxyXG5leHBvcnQgZGVmYXVsdCB7XHJcbiAgY2hlY2tBbmRVcGRhdGVDYWNoZSxcclxuICBnZXRIaWdoY2hhcnRzVmVyc2lvbixcclxuICB1cGRhdGVIaWdoY2hhcnRzVmVyc2lvbixcclxuICBleHRyYWN0VmVyc2lvbixcclxuICBleHRyYWN0TW9kdWxlTmFtZSxcclxuICBnZXRDYWNoZSxcclxuICBnZXRDYWNoZVBhdGhcclxufTtcclxuIiwiLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcclxuXHJcbkhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlclxyXG5cclxuQ29weXJpZ2h0IChjKSAyMDE2LTIwMjUsIEhpZ2hzb2Z0XHJcblxyXG5MaWNlbmNlZCB1bmRlciB0aGUgTUlUIGxpY2VuY2UuXHJcblxyXG5BZGRpdGlvbmFsbHkgYSB2YWxpZCBIaWdoY2hhcnRzIGxpY2Vuc2UgaXMgcmVxdWlyZWQgZm9yIHVzZS5cclxuXHJcblNlZSBMSUNFTlNFIGZpbGUgaW4gcm9vdCBmb3IgZGV0YWlscy5cclxuXHJcbioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXHJcblxyXG4vKipcclxuICogQG92ZXJ2aWV3IFByb3ZpZGVzIG1ldGhvZHMgZm9yIGluaXRpYWxpemluZyBIaWdoY2hhcnRzIHdpdGggY3VzdG9taXplZFxyXG4gKiBhbmltYXRpb24gc2V0dGluZ3MgYW5kIHRyaWdnZXJpbmcgdGhlIGNyZWF0aW9uIG9mIEhpZ2hjaGFydHMgY2hhcnRzIHdpdGhcclxuICogZXhwb3J0LXNwZWNpZmljIGNvbmZpZ3VyYXRpb25zIGluIHRoZSBwYWdlIGNvbnRleHQuIFN1cHBvcnRzIGR5bmFtaWMgb3B0aW9uXHJcbiAqIG1lcmdpbmcsIGN1c3RvbSBsb2dpYyBpbmplY3Rpb24sIGFuZCBjb250cm9sIG92ZXIgcmVuZGVyaW5nIGJlaGF2aW9ycy4gVXNlZFxyXG4gKiBieSB0aGUgUHVwcGV0ZWVyIHBhZ2UuXHJcbiAqL1xyXG5cclxuLyogZXNsaW50LWRpc2FibGUgbm8tdW5kZWYgKi9cclxuXHJcbi8qKlxyXG4gKiBTZXR0aW5nIHRoZSBgSGlnaGNoYXJ0cy5hbmltT2JqZWN0YCBmdW5jdGlvbi4gQ2FsbGVkIHdoZW4gaW5pdGluZyB0aGUgcGFnZS5cclxuICpcclxuICogQGZ1bmN0aW9uIHNldHVwSGlnaGNoYXJ0c1xyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIHNldHVwSGlnaGNoYXJ0cygpIHtcclxuICBIaWdoY2hhcnRzLmFuaW1PYmplY3QgPSBmdW5jdGlvbiAoKSB7XHJcbiAgICByZXR1cm4geyBkdXJhdGlvbjogMCB9O1xyXG4gIH07XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBDcmVhdGVzIHRoZSBhY3R1YWwgSGlnaGNoYXJ0cyBjaGFydCBvbiBhIHBhZ2UuXHJcbiAqXHJcbiAqIEBhc3luY1xyXG4gKiBAZnVuY3Rpb24gY3JlYXRlQ2hhcnRcclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IG9wdGlvbnMgLSBUaGUgYG9wdGlvbnNgIG9iamVjdCBjb250YWluaW5nIGNvbXBsZXRlIHNldFxyXG4gKiBvZiBvcHRpb25zLlxyXG4gKi9cclxuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIGNyZWF0ZUNoYXJ0KG9wdGlvbnMpIHtcclxuICAvLyBHZXQgcmVxdWlyZWQgZnVuY3Rpb25zXHJcbiAgY29uc3QgeyBnZXRPcHRpb25zLCBtZXJnZSwgc2V0T3B0aW9ucywgd3JhcCB9ID0gSGlnaGNoYXJ0cztcclxuXHJcbiAgLy8gQ3JlYXRlIGEgc2VwYXJhdGUgb2JqZWN0IGZvciBhIHBvdGVudGlhbCBgc2V0T3B0aW9uc2AgdXNhZ2VzIGluIG9yZGVyXHJcbiAgLy8gdG8gcHJldmVudCBmcm9tIHBvbGx1dGluZyBvdGhlciBleHBvcnRzIHRoYXQgY2FuIGhhcHBlbiBvbiB0aGUgc2FtZSBwYWdlXHJcbiAgSGlnaGNoYXJ0cy5zZXRPcHRpb25zT2JqID0gbWVyZ2UoZmFsc2UsIHt9LCBnZXRPcHRpb25zKCkpO1xyXG5cclxuICAvLyBOT1RFOiBJcyB0aGlzIHVzZWQgZm9yIGFueXRoaW5nIHVzZWZ1bD9cclxuICB3aW5kb3cuaXNSZW5kZXJDb21wbGV0ZSA9IGZhbHNlO1xyXG4gIHdyYXAoSGlnaGNoYXJ0cy5DaGFydC5wcm90b3R5cGUsICdpbml0JywgZnVuY3Rpb24gKHByb2NlZWQsIHVzZXJPcHRpb25zLCBjYikge1xyXG4gICAgLy8gT3ZlcnJpZGUgdXNlck9wdGlvbnMgd2l0aCBpbWFnZSBmcmllbmRseSBvcHRpb25zXHJcbiAgICB1c2VyT3B0aW9ucyA9IG1lcmdlKHVzZXJPcHRpb25zLCB7XHJcbiAgICAgIGV4cG9ydGluZzoge1xyXG4gICAgICAgIGVuYWJsZWQ6IGZhbHNlXHJcbiAgICAgIH0sXHJcbiAgICAgIHBsb3RPcHRpb25zOiB7XHJcbiAgICAgICAgc2VyaWVzOiB7XHJcbiAgICAgICAgICBsYWJlbDoge1xyXG4gICAgICAgICAgICBlbmFibGVkOiBmYWxzZVxyXG4gICAgICAgICAgfVxyXG4gICAgICAgIH1cclxuICAgICAgfSxcclxuICAgICAgLyogRXhwZWN0cyB0b29sdGlwIGluIHVzZXJPcHRpb25zIHdoZW4gZm9yRXhwb3J0IGlzIHRydWUuXHJcbiAgICAgICAgaHR0cHM6Ly9naXRodWIuY29tL2hpZ2hjaGFydHMvaGlnaGNoYXJ0cy9ibG9iLzNhZDQzMGEzNTNiODA1NmI5ZTc2NGFhNGU1Y2Q2ODI4YWE0NzlkYjIvanMvcGFydHMvQ2hhcnQuanMjTDI0MVxyXG4gICAgICAgICovXHJcbiAgICAgIHRvb2x0aXA6IHt9XHJcbiAgICB9KTtcclxuXHJcbiAgICAodXNlck9wdGlvbnMuc2VyaWVzIHx8IFtdKS5mb3JFYWNoKGZ1bmN0aW9uIChzZXJpZXMpIHtcclxuICAgICAgc2VyaWVzLmFuaW1hdGlvbiA9IGZhbHNlO1xyXG4gICAgfSk7XHJcblxyXG4gICAgLy8gQWRkIGZsYWcgdG8ga25vdyBpZiBjaGFydCByZW5kZXIgaGFzIGJlZW4gY2FsbGVkLlxyXG4gICAgaWYgKCF3aW5kb3cub25IaWdoY2hhcnRzUmVuZGVyKSB7XHJcbiAgICAgIHdpbmRvdy5vbkhpZ2hjaGFydHNSZW5kZXIgPSBIaWdoY2hhcnRzLmFkZEV2ZW50KHRoaXMsICdyZW5kZXInLCAoKSA9PiB7XHJcbiAgICAgICAgd2luZG93LmlzUmVuZGVyQ29tcGxldGUgPSB0cnVlO1xyXG4gICAgICB9KTtcclxuICAgIH1cclxuXHJcbiAgICBwcm9jZWVkLmFwcGx5KHRoaXMsIFt1c2VyT3B0aW9ucywgY2JdKTtcclxuICB9KTtcclxuXHJcbiAgd3JhcChIaWdoY2hhcnRzLlNlcmllcy5wcm90b3R5cGUsICdpbml0JywgZnVuY3Rpb24gKHByb2NlZWQsIGNoYXJ0LCBvcHRpb25zKSB7XHJcbiAgICBwcm9jZWVkLmFwcGx5KHRoaXMsIFtjaGFydCwgb3B0aW9uc10pO1xyXG4gIH0pO1xyXG5cclxuICAvLyBTb21lIG1hbmRhdG9yeSBhZGRpdGlvbmFsIGBjaGFydGAgYW5kIGBleHBvcnRpbmdgIG9wdGlvbnNcclxuICBjb25zdCBhZGRpdGlvbmFsT3B0aW9ucyA9IHtcclxuICAgIGNoYXJ0OiB7XHJcbiAgICAgIC8vIEJ5IGRlZmF1bHQgYW5pbWF0aW9uIGlzIGRpc2FibGVkXHJcbiAgICAgIGFuaW1hdGlvbjogZmFsc2UsXHJcbiAgICAgIC8vIEdldCB0aGUgcmlnaHQgc2l6ZSB2YWx1ZXNcclxuICAgICAgaGVpZ2h0OiBvcHRpb25zLmV4cG9ydC5oZWlnaHQsXHJcbiAgICAgIHdpZHRoOiBvcHRpb25zLmV4cG9ydC53aWR0aFxyXG4gICAgfSxcclxuICAgIGV4cG9ydGluZzoge1xyXG4gICAgICAvLyBObyBuZWVkIGZvciB0aGUgZXhwb3J0aW5nIGJ1dHRvblxyXG4gICAgICBlbmFibGVkOiBmYWxzZVxyXG4gICAgfVxyXG4gIH07XHJcblxyXG4gIC8vIEdldCB0aGUgaW5wdXQgdG8gZXhwb3J0IGZyb20gdGhlIGBpbnN0cmAgb3B0aW9uXHJcbiAgY29uc3QgdXNlck9wdGlvbnMgPSBuZXcgRnVuY3Rpb24oYHJldHVybiAke29wdGlvbnMuZXhwb3J0Lmluc3RyfWApKCk7XHJcblxyXG4gIC8vIEdldCB0aGUgYHRoZW1lT3B0aW9uc2Agb3B0aW9uXHJcbiAgY29uc3QgdGhlbWVPcHRpb25zID0gbmV3IEZ1bmN0aW9uKGByZXR1cm4gJHtvcHRpb25zLmV4cG9ydC50aGVtZU9wdGlvbnN9YCkoKTtcclxuXHJcbiAgLy8gR2V0IHRoZSBgZ2xvYmFsT3B0aW9uc2Agb3B0aW9uXHJcbiAgY29uc3QgZ2xvYmFsT3B0aW9ucyA9IG5ldyBGdW5jdGlvbihcclxuICAgIGByZXR1cm4gJHtvcHRpb25zLmV4cG9ydC5nbG9iYWxPcHRpb25zfWBcclxuICApKCk7XHJcblxyXG4gIC8vIE1lcmdlIHRoZSBmb2xsb3dpbmcgb3B0aW9ucyBvYmplY3RzIHRvIGNyZWF0ZSBmaW5hbCBvcHRpb25zXHJcbiAgY29uc3QgZmluYWxPcHRpb25zID0gbWVyZ2UoXHJcbiAgICBmYWxzZSxcclxuICAgIHRoZW1lT3B0aW9ucyxcclxuICAgIHVzZXJPcHRpb25zLFxyXG4gICAgLy8gUGxhY2VkIGl0IGhlcmUgaW5zdGVhZCBpbiB0aGUgaW5pdCBiZWNhdXNlIG9mIHRoZSBzaXplIGlzc3Vlc1xyXG4gICAgYWRkaXRpb25hbE9wdGlvbnNcclxuICApO1xyXG5cclxuICAvLyBQcmVwYXJlIHRoZSBgY2FsbGJhY2tgIG9wdGlvblxyXG4gIGNvbnN0IGZpbmFsQ2FsbGJhY2sgPSBvcHRpb25zLmN1c3RvbUxvZ2ljLmNhbGxiYWNrXHJcbiAgICA/IG5ldyBGdW5jdGlvbihgcmV0dXJuICR7b3B0aW9ucy5jdXN0b21Mb2dpYy5jYWxsYmFja31gKSgpXHJcbiAgICA6IG51bGw7XHJcblxyXG4gIC8vIFRyaWdnZXIgdGhlIGBjdXN0b21Db2RlYCBvcHRpb25cclxuICBpZiAob3B0aW9ucy5jdXN0b21Mb2dpYy5jdXN0b21Db2RlKSB7XHJcbiAgICBuZXcgRnVuY3Rpb24oJ29wdGlvbnMnLCBvcHRpb25zLmN1c3RvbUxvZ2ljLmN1c3RvbUNvZGUpKHVzZXJPcHRpb25zKTtcclxuICB9XHJcblxyXG4gIC8vIFNldCB0aGUgZ2xvYmFsIG9wdGlvbnMgaWYgZXhpc3RcclxuICBpZiAoZ2xvYmFsT3B0aW9ucykge1xyXG4gICAgc2V0T3B0aW9ucyhnbG9iYWxPcHRpb25zKTtcclxuICB9XHJcblxyXG4gIC8vIENhbGwgdGhlIGNoYXJ0IGNyZWF0aW9uXHJcbiAgSGlnaGNoYXJ0c1tvcHRpb25zLmV4cG9ydC5jb25zdHJdKCdjb250YWluZXInLCBmaW5hbE9wdGlvbnMsIGZpbmFsQ2FsbGJhY2spO1xyXG5cclxuICAvLyBHZXQgdGhlIGN1cnJlbnQgZ2xvYmFsIG9wdGlvbnNcclxuICBjb25zdCBkZWZhdWx0T3B0aW9ucyA9IGdldE9wdGlvbnMoKTtcclxuXHJcbiAgLy8gQ2xlYXIgaXQganVzdCBpbiBjYXNlIChlLmcuIHRoZSBgc2V0T3B0aW9uc2Agd2FzIHVzZWQgaW4gdGhlIGBjdXN0b21Db2RlYClcclxuICBmb3IgKGNvbnN0IHByb3AgaW4gZGVmYXVsdE9wdGlvbnMpIHtcclxuICAgIGlmICh0eXBlb2YgZGVmYXVsdE9wdGlvbnNbcHJvcF0gIT09ICdmdW5jdGlvbicpIHtcclxuICAgICAgZGVsZXRlIGRlZmF1bHRPcHRpb25zW3Byb3BdO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgLy8gU2V0IHRoZSBkZWZhdWx0IG9wdGlvbnMgYmFja1xyXG4gIHNldE9wdGlvbnMoSGlnaGNoYXJ0cy5zZXRPcHRpb25zT2JqKTtcclxuXHJcbiAgLy8gRW1wdHkgdGhlIGN1c3RvbSBnbG9iYWwgb3B0aW9ucyBvYmplY3RcclxuICBIaWdoY2hhcnRzLnNldE9wdGlvbnNPYmogPSB7fTtcclxufVxyXG5cclxuZXhwb3J0IGRlZmF1bHQge1xyXG4gIHNldHVwSGlnaGNoYXJ0cyxcclxuICBjcmVhdGVDaGFydFxyXG59O1xyXG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxyXG5cclxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXHJcblxyXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNSwgSGlnaHNvZnRcclxuXHJcbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cclxuXHJcbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxyXG5cclxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxyXG5cclxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cclxuXHJcbi8qKlxyXG4gKiBAb3ZlcnZpZXcgVGhpcyBtb2R1bGUgcHJvdmlkZXMgZnVuY3Rpb25zIGZvciBtYW5hZ2luZyBQdXBwZXRlZXIgYnJvd3NlclxyXG4gKiBpbnN0YW5jZSwgY3JlYXRpbmcgYW5kIGNsZWFyaW5nIHBhZ2VzLCBpbmplY3RpbmcgY3VzdG9tIHJlc291cmNlcyxcclxuICogYW5kIHNldHRpbmcgdXAgSGlnaGNoYXJ0cyBmb3Igc2VydmVyLXNpZGUgcmVuZGVyaW5nLiBUaGUgbW9kdWxlIGVuc3VyZXNcclxuICogdGhhdCByZXNvdXJjZXMgYXJlIGNvcnJlY3RseSBtYW5hZ2VkIGFuZCBjYW4gaGFuZGxlIGZhaWx1cmVzIGR1cmluZ1xyXG4gKiBvcGVyYXRpb25zIGxpa2UgbGF1bmNoaW5nIHRoZSBicm93c2VyIG9yIGNyZWF0aW5nIG5ldyBwYWdlcy5cclxuICovXHJcblxyXG5pbXBvcnQgeyByZWFkRmlsZVN5bmMgfSBmcm9tICdmcyc7XHJcbmltcG9ydCB7IGpvaW4gfSBmcm9tICdwYXRoJztcclxuXHJcbmltcG9ydCBwdXBwZXRlZXIgZnJvbSAncHVwcGV0ZWVyJztcclxuXHJcbmltcG9ydCB7IGdldENhY2hlUGF0aCB9IGZyb20gJy4vY2FjaGUuanMnO1xyXG5pbXBvcnQgeyBnZXRPcHRpb25zIH0gZnJvbSAnLi9jb25maWcuanMnO1xyXG5pbXBvcnQgeyBzZXR1cEhpZ2hjaGFydHMgfSBmcm9tICcuL2hpZ2hjaGFydHMuanMnO1xyXG5pbXBvcnQgeyBsb2csIGxvZ1dpdGhTdGFjayB9IGZyb20gJy4vbG9nZ2VyLmpzJztcclxuaW1wb3J0IHsgX19kaXJuYW1lLCBnZXRBYnNvbHV0ZVBhdGggfSBmcm9tICcuL3V0aWxzLmpzJztcclxuXHJcbmltcG9ydCBFeHBvcnRFcnJvciBmcm9tICcuL2Vycm9ycy9FeHBvcnRFcnJvci5qcyc7XHJcblxyXG4vLyBHZXQgdGhlIHRlbXBsYXRlIGZvciBwYWdlc1xyXG5jb25zdCB0ZW1wbGF0ZSA9IHJlYWRGaWxlU3luYyhcclxuICBqb2luKF9fZGlybmFtZSwgJ3RlbXBsYXRlcycsICd0ZW1wbGF0ZS5odG1sJyksXHJcbiAgJ3V0ZjgnXHJcbik7XHJcblxyXG4vLyBUbyBzYXZlIHRoZSBicm93c2VyXHJcbmxldCBicm93c2VyID0gbnVsbDtcclxuXHJcbi8qKlxyXG4gKiBSZXRyaWV2ZXMgdGhlIGV4aXN0aW5nIFB1cHBldGVlciBicm93c2VyIGluc3RhbmNlLlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gZ2V0QnJvd3NlclxyXG4gKlxyXG4gKiBAcmV0dXJucyB7T2JqZWN0fSBUaGUgUHVwcGV0ZWVyIGJyb3dzZXIgaW5zdGFuY2UuXHJcbiAqXHJcbiAqIEB0aHJvd3Mge0V4cG9ydEVycm9yfSBUaHJvd3MgYW4gYEV4cG9ydEVycm9yYCBpZiBubyB2YWxpZCBicm93c2VyXHJcbiAqIGhhcyBiZWVuIGNyZWF0ZWQuXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gZ2V0QnJvd3NlcigpIHtcclxuICBpZiAoIWJyb3dzZXIpIHtcclxuICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcignW2Jyb3dzZXJdIE5vIHZhbGlkIGJyb3dzZXIgaGFzIGJlZW4gY3JlYXRlZC4nLCA1MDApO1xyXG4gIH1cclxuICByZXR1cm4gYnJvd3NlcjtcclxufVxyXG5cclxuLyoqXHJcbiAqIENyZWF0ZXMgYSBQdXBwZXRlZXIgYnJvd3NlciBpbnN0YW5jZSB3aXRoIHRoZSBzcGVjaWZpZWQgYXJndW1lbnRzLlxyXG4gKlxyXG4gKiBAYXN5bmNcclxuICogQGZ1bmN0aW9uIGNyZWF0ZUJyb3dzZXJcclxuICpcclxuICogQHBhcmFtIHtBcnJheS48c3RyaW5nPn0gcHVwcGV0ZWVyQXJncyAtIEFkZGl0aW9uYWwgYXJndW1lbnRzIGZvciBQdXBwZXRlZXJcclxuICogbGF1bmNoLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7UHJvbWlzZTxPYmplY3Q+fSBBIFByb21pc2UgdGhhdCByZXNvbHZlcyB0byB0aGUgY3JlYXRlZCBQdXBwZXRlZXJcclxuICogYnJvd3NlciBpbnN0YW5jZS5cclxuICpcclxuICogQHRocm93cyB7RXhwb3J0RXJyb3J9IFRocm93cyBhbiBgRXhwb3J0RXJyb3JgIGlmIG1heCByZXRyaWVzIHRvIG9wZW5cclxuICogYSBicm93c2VyIGluc3RhbmNlIGFyZSByZWFjaGVkLCBvciBpZiBubyBicm93c2VyIGluc3RhbmNlIGlzIGZvdW5kIGFmdGVyXHJcbiAqIHJldHJpZXMuXHJcbiAqL1xyXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gY3JlYXRlQnJvd3NlcihwdXBwZXRlZXJBcmdzKSB7XHJcbiAgLy8gR2V0IGBkZWJ1Z2AgYW5kIGBvdGhlcmAgb3B0aW9uc1xyXG4gIGNvbnN0IHsgZGVidWcsIG90aGVyIH0gPSBnZXRPcHRpb25zKCk7XHJcblxyXG4gIC8vIEdldCB0aGUgYGRlYnVnYCBvcHRpb25zXHJcbiAgY29uc3QgeyBlbmFibGU6IGVuYWJsZWREZWJ1ZywgLi4uZGVidWdPcHRpb25zIH0gPSBkZWJ1ZztcclxuXHJcbiAgLy8gTGF1bmNoIG9wdGlvbnMgZm9yIHRoZSBicm93c2VyIGluc3RhbmNlXHJcbiAgY29uc3QgbGF1bmNoT3B0aW9ucyA9IHtcclxuICAgIGhlYWRsZXNzOiBvdGhlci5icm93c2VyU2hlbGxNb2RlID8gJ3NoZWxsJyA6IHRydWUsXHJcbiAgICB1c2VyRGF0YURpcjogJ3RtcCcsXHJcbiAgICBhcmdzOiBwdXBwZXRlZXJBcmdzIHx8IFtdLFxyXG4gICAgaGFuZGxlU0lHSU5UOiBmYWxzZSxcclxuICAgIGhhbmRsZVNJR1RFUk06IGZhbHNlLFxyXG4gICAgaGFuZGxlU0lHSFVQOiBmYWxzZSxcclxuICAgIHdhaXRGb3JJbml0aWFsUGFnZTogZmFsc2UsXHJcbiAgICBkZWZhdWx0Vmlld3BvcnQ6IG51bGwsXHJcbiAgICAuLi4oZW5hYmxlZERlYnVnICYmIGRlYnVnT3B0aW9ucylcclxuICB9O1xyXG5cclxuICAvLyBDcmVhdGUgYSBicm93c2VyXHJcbiAgaWYgKCFicm93c2VyKSB7XHJcbiAgICAvLyBBIGNvdW50ZXIgZm9yIHRoZSBicm93c2VyJ3MgbGF1bmNoIHJldHJpZXNcclxuICAgIGxldCB0cnlDb3VudCA9IDA7XHJcblxyXG4gICAgY29uc3Qgb3BlbiA9IGFzeW5jICgpID0+IHtcclxuICAgICAgdHJ5IHtcclxuICAgICAgICBsb2coXHJcbiAgICAgICAgICAzLFxyXG4gICAgICAgICAgYFticm93c2VyXSBBdHRlbXB0aW5nIHRvIGdldCBhIGJyb3dzZXIgaW5zdGFuY2UgKHRyeSAkeysrdHJ5Q291bnR9KS5gXHJcbiAgICAgICAgKTtcclxuXHJcbiAgICAgICAgLy8gTGF1bmNoIHRoZSBicm93c2VyXHJcbiAgICAgICAgYnJvd3NlciA9IGF3YWl0IHB1cHBldGVlci5sYXVuY2gobGF1bmNoT3B0aW9ucyk7XHJcbiAgICAgIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICAgICAgbG9nV2l0aFN0YWNrKFxyXG4gICAgICAgICAgMSxcclxuICAgICAgICAgIGVycm9yLFxyXG4gICAgICAgICAgJ1ticm93c2VyXSBGYWlsZWQgdG8gbGF1bmNoIGEgYnJvd3NlciBpbnN0YW5jZS4nXHJcbiAgICAgICAgKTtcclxuXHJcbiAgICAgICAgLy8gUmV0cnkgdG8gbGF1bmNoIGJyb3dzZXIgdW50aWwgcmVhY2hpbmcgbWF4IGF0dGVtcHRzXHJcbiAgICAgICAgaWYgKHRyeUNvdW50IDwgMjUpIHtcclxuICAgICAgICAgIGxvZygzLCBgW2Jyb3dzZXJdIFJldHJ5IHRvIG9wZW4gYSBicm93c2VyICgke3RyeUNvdW50fSBvdXQgb2YgMjUpLmApO1xyXG5cclxuICAgICAgICAgIC8vIFdhaXQgZm9yIGEgNCBzZWNvbmRzIGJlZm9yZSB0cnlpbmcgYWdhaW5cclxuICAgICAgICAgIGF3YWl0IG5ldyBQcm9taXNlKChyZXNwb25zZSkgPT4gc2V0VGltZW91dChyZXNwb25zZSwgNDAwMCkpO1xyXG4gICAgICAgICAgYXdhaXQgb3BlbigpO1xyXG4gICAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgICB0aHJvdyBlcnJvcjtcclxuICAgICAgICB9XHJcbiAgICAgIH1cclxuICAgIH07XHJcblxyXG4gICAgdHJ5IHtcclxuICAgICAgYXdhaXQgb3BlbigpO1xyXG5cclxuICAgICAgLy8gU2hlbGwgbW9kZSBpbmZvcm1cclxuICAgICAgaWYgKGxhdW5jaE9wdGlvbnMuaGVhZGxlc3MgPT09ICdzaGVsbCcpIHtcclxuICAgICAgICBsb2coMywgYFticm93c2VyXSBMYXVuY2hlZCBicm93c2VyIGluIHNoZWxsIG1vZGUuYCk7XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIC8vIERlYnVnIG1vZGUgaW5mb3JtXHJcbiAgICAgIGlmIChlbmFibGVkRGVidWcpIHtcclxuICAgICAgICBsb2coMywgYFticm93c2VyXSBMYXVuY2hlZCBicm93c2VyIGluIGRlYnVnIG1vZGUuYCk7XHJcbiAgICAgIH1cclxuICAgIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcihcclxuICAgICAgICAnW2Jyb3dzZXJdIE1heGltdW0gcmV0cmllcyB0byBvcGVuIGEgYnJvd3NlciBpbnN0YW5jZSByZWFjaGVkLicsXHJcbiAgICAgICAgNTAwXHJcbiAgICAgICkuc2V0RXJyb3IoZXJyb3IpO1xyXG4gICAgfVxyXG5cclxuICAgIGlmICghYnJvd3Nlcikge1xyXG4gICAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoJ1ticm93c2VyXSBDYW5ub3QgZmluZCBhIGJyb3dzZXIgdG8gb3Blbi4nLCA1MDApO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgLy8gUmV0dXJuIGEgYnJvd3NlciBpbnN0YW5jZVxyXG4gIHJldHVybiBicm93c2VyO1xyXG59XHJcblxyXG4vKipcclxuICogQ2xvc2VzIHRoZSBQdXBwZXRlZXIgYnJvd3NlciBpbnN0YW5jZSBpZiBpdCBpcyBjb25uZWN0ZWQuXHJcbiAqXHJcbiAqIEBhc3luY1xyXG4gKiBAZnVuY3Rpb24gY2xvc2VCcm93c2VyXHJcbiAqL1xyXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gY2xvc2VCcm93c2VyKCkge1xyXG4gIC8vIENsb3NlIHRoZSBicm93c2VyIHdoZW4gY29ubmVjdGVkXHJcbiAgaWYgKGJyb3dzZXIgJiYgYnJvd3Nlci5jb25uZWN0ZWQpIHtcclxuICAgIGF3YWl0IGJyb3dzZXIuY2xvc2UoKTtcclxuICB9XHJcbiAgYnJvd3NlciA9IG51bGw7XHJcbiAgbG9nKDQsICdbYnJvd3Nlcl0gQ2xvc2VkIHRoZSBicm93c2VyLicpO1xyXG59XHJcblxyXG4vKipcclxuICogQ3JlYXRlcyBhIG5ldyBQdXBwZXRlZXIgcGFnZSB3aXRoaW4gYW4gZXhpc3RpbmcgYnJvd3NlciBpbnN0YW5jZS5cclxuICogVGhlIGZ1bmN0aW9uIGNyZWF0ZXMgYSBuZXcgcGFnZSwgZGlzYWJsZXMgY2FjaGluZywgc2V0cyBjb250ZW50IHVzaW5nXHJcbiAqIHRoZSBgX3NldFBhZ2VDb250ZW50KClgLCBhbmQgcmV0dXJucyB0aGUgY3JlYXRlZCBQdXBwZXRlZXIgcGFnZS5cclxuICpcclxuICogQGFzeW5jXHJcbiAqIEBmdW5jdGlvbiBuZXdQYWdlXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBwb29sUmVzb3VyY2UgLSBUaGUgcG9vbCByZXNvdXJjZSB0aGF0IGNvbnRhaW5zIGBpZGAsXHJcbiAqIGB3b3JrQ291bnRgLCBhbmQgYHBhZ2VgLlxyXG4gKlxyXG4gKiBAdGhyb3dzIHtFeHBvcnRFcnJvcn0gVGhyb3dzIGFuIGBFeHBvcnRFcnJvcmAgaWYgbm8gdmFsaWQgYnJvd3NlclxyXG4gKiBoYXMgYmVlbiBjb25uZWN0ZWQgb3IgaWYgYSBwYWdlIGlzIGludmFsaWQgb3IgY2xvc2VkLlxyXG4gKi9cclxuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIG5ld1BhZ2UocG9vbFJlc291cmNlKSB7XHJcbiAgLy8gRXJyb3IgaW4gY2FzZSBvZiBubyBjb25uZWN0ZWQgYnJvd3NlclxyXG4gIGlmICghYnJvd3NlciB8fCAhYnJvd3Nlci5jb25uZWN0ZWQpIHtcclxuICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcihgW2Jyb3dzZXJdIEJyb3dzZXIgaXMgbm90IHlldCBjb25uZWN0ZWQuYCwgNTAwKTtcclxuICB9XHJcblxyXG4gIC8vIENyZWF0ZSBhIHBhZ2VcclxuICBwb29sUmVzb3VyY2UucGFnZSA9IGF3YWl0IGJyb3dzZXIubmV3UGFnZSgpO1xyXG5cclxuICAvLyBEaXNhYmxlIGNhY2hlXHJcbiAgYXdhaXQgcG9vbFJlc291cmNlLnBhZ2Uuc2V0Q2FjaGVFbmFibGVkKGZhbHNlKTtcclxuXHJcbiAgLy8gU2V0IHRoZSBjb250ZW50XHJcbiAgYXdhaXQgX3NldFBhZ2VDb250ZW50KHBvb2xSZXNvdXJjZS5wYWdlKTtcclxuXHJcbiAgLy8gU2V0IHBhZ2UgZXZlbnRzXHJcbiAgX3NldFBhZ2VFdmVudHMocG9vbFJlc291cmNlLnBhZ2UpO1xyXG5cclxuICAvLyBDaGVjayBpZiB0aGUgcGFnZSBpcyBjb3JyZWN0bHkgY3JlYXRlZFxyXG4gIGlmICghcG9vbFJlc291cmNlLnBhZ2UgfHwgcG9vbFJlc291cmNlLnBhZ2UuaXNDbG9zZWQoKSkge1xyXG4gICAgdGhyb3cgbmV3IEV4cG9ydEVycm9yKCdbYnJvd3Nlcl0gVGhlIHBhZ2UgaXMgaW52YWxpZCBvciBjbG9zZWQuJywgNDAwKTtcclxuICB9XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBDbGVhcnMgdGhlIGNvbnRlbnQgb2YgYSBQdXBwZXRlZXIgUGFnZSBiYXNlZCBvbiB0aGUgc3BlY2lmaWVkIG1vZGUuIExvZ3NcclxuICogdGhyb3duIGVycm9yIGlmIGNsZWFyaW5nIG9mIGEgcGFnZSdzIGNvbnRlbnQgZmFpbHMuXHJcbiAqXHJcbiAqIEBhc3luY1xyXG4gKiBAZnVuY3Rpb24gY2xlYXJQYWdlXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBwb29sUmVzb3VyY2UgLSBUaGUgcG9vbCByZXNvdXJjZSB0aGF0IGNvbnRhaW5zIHBhZ2UgYW5kIGlkLlxyXG4gKiBAcGFyYW0ge2Jvb2xlYW59IFtoYXJkUmVzZXQ9ZmFsc2VdIC0gQSBmbGFnIGluZGljYXRpbmcgdGhlIHR5cGUgb2YgY2xlYXJpbmdcclxuICogdG8gYmUgcGVyZm9ybWVkLiBJZiB0cnVlLCBuYXZpZ2F0ZXMgdG8gYGFib3V0OmJsYW5rYCBhbmQgcmVzZXRzIGNvbnRlbnRcclxuICogYW5kIHNjcmlwdHMuIElmIGZhbHNlLCBjbGVhcnMgdGhlIGJvZHkgY29udGVudCBieSBzZXR0aW5nIGEgcHJlZGVmaW5lZCBIVE1MXHJcbiAqIHN0cnVjdHVyZS4gVGhlIGRlZmF1bHQgdmFsdWUgaXMgZmFsc2UuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtQcm9taXNlPGJvb2xlYW4+fSBBIFByb21pc2UgdGhhdCByZXNvbHZlcyB0byB0cnVlIHdoZW4gcGFnZVxyXG4gKiBpcyBjb3JyZWN0bHkgY2xlYXJlZCBhbmQgZmFsc2Ugd2hlbiBpdCBpcyBub3QuXHJcbiAqL1xyXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gY2xlYXJQYWdlKHBvb2xSZXNvdXJjZSwgaGFyZFJlc2V0ID0gZmFsc2UpIHtcclxuICB0cnkge1xyXG4gICAgaWYgKHBvb2xSZXNvdXJjZS5wYWdlICYmICFwb29sUmVzb3VyY2UucGFnZS5pc0Nsb3NlZCgpKSB7XHJcbiAgICAgIGlmIChoYXJkUmVzZXQpIHtcclxuICAgICAgICAvLyBOYXZpZ2F0ZSB0byBgYWJvdXQ6YmxhbmtgXHJcbiAgICAgICAgYXdhaXQgcG9vbFJlc291cmNlLnBhZ2UuZ290bygnYWJvdXQ6YmxhbmsnLCB7XHJcbiAgICAgICAgICB3YWl0VW50aWw6ICdkb21jb250ZW50bG9hZGVkJ1xyXG4gICAgICAgIH0pO1xyXG5cclxuICAgICAgICAvLyBTZXQgdGhlIGNvbnRlbnQgYW5kIGFuZCBzY3JpcHRzIGFnYWluXHJcbiAgICAgICAgYXdhaXQgX3NldFBhZ2VDb250ZW50KHBvb2xSZXNvdXJjZS5wYWdlKTtcclxuICAgICAgfSBlbHNlIHtcclxuICAgICAgICAvLyBDbGVhciBib2R5IGNvbnRlbnRcclxuICAgICAgICBhd2FpdCBwb29sUmVzb3VyY2UucGFnZS5ldmFsdWF0ZSgoKSA9PiB7XHJcbiAgICAgICAgICBkb2N1bWVudC5ib2R5LmlubmVySFRNTCA9XHJcbiAgICAgICAgICAgICc8ZGl2IGlkPVwiY2hhcnQtY29udGFpbmVyXCI+PGRpdiBpZD1cImNvbnRhaW5lclwiPjwvZGl2PjwvZGl2Pic7XHJcbiAgICAgICAgfSk7XHJcbiAgICAgIH1cclxuICAgICAgcmV0dXJuIHRydWU7XHJcbiAgICB9XHJcbiAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgIGxvZ1dpdGhTdGFjayhcclxuICAgICAgMixcclxuICAgICAgZXJyb3IsXHJcbiAgICAgIGBbcG9vbF0gUG9vbCByZXNvdXJjZSBbJHtwb29sUmVzb3VyY2UuaWR9XSAtIENvbnRlbnQgb2YgdGhlIHBhZ2UgY291bGQgbm90IGJlIGNsZWFyZWQuYFxyXG4gICAgKTtcclxuXHJcbiAgICAvLyBTZXQgdGhlIGB3b3JrTGltaXRgIHRvIGV4Y2VlZGVkIGluIG9yZGVyIHRvIHJlY3JlYXRlIHRoZSByZXNvdXJjZVxyXG4gICAgcG9vbFJlc291cmNlLndvcmtDb3VudCA9IGdldE9wdGlvbnMoKS5wb29sLndvcmtMaW1pdCArIDE7XHJcbiAgfVxyXG4gIHJldHVybiBmYWxzZTtcclxufVxyXG5cclxuLyoqXHJcbiAqIEFkZHMgY3VzdG9tIEpTIGFuZCBDU1MgcmVzb3VyY2VzIHRvIGEgUHVwcGV0ZWVyIFBhZ2UgYmFzZWQgb24gdGhlIHNwZWNpZmllZFxyXG4gKiBvcHRpb25zLlxyXG4gKlxyXG4gKiBAYXN5bmNcclxuICogQGZ1bmN0aW9uIGFkZFBhZ2VSZXNvdXJjZXNcclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IHBhZ2UgLSBUaGUgUHVwcGV0ZWVyIHBhZ2Ugb2JqZWN0IHRvIHdoaWNoIHJlc291cmNlcyB3aWxsXHJcbiAqIGJlIGFkZGVkLlxyXG4gKiBAcGFyYW0ge09iamVjdH0gY3VzdG9tTG9naWNPcHRpb25zIC0gVGhlIG9iamVjdCBjb250YWluaW5nIGBjdXN0b21Mb2dpY2BcclxuICogb3B0aW9ucy5cclxuICpcclxuICogQHJldHVybnMge1Byb21pc2U8QXJyYXkuPE9iamVjdD4+fSBBIFByb21pc2UgdGhhdCByZXNvbHZlcyB0byBhbiBhcnJheVxyXG4gKiBvZiBpbmplY3RlZCByZXNvdXJjZXMuXHJcbiAqL1xyXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gYWRkUGFnZVJlc291cmNlcyhwYWdlLCBjdXN0b21Mb2dpY09wdGlvbnMpIHtcclxuICAvLyBJbmplY3RlZCByZXNvdXJjZXMgYXJyYXlcclxuICBjb25zdCBpbmplY3RlZFJlc291cmNlcyA9IFtdO1xyXG5cclxuICAvLyBVc2UgcmVzb3VyY2VzXHJcbiAgY29uc3QgcmVzb3VyY2VzID0gY3VzdG9tTG9naWNPcHRpb25zLnJlc291cmNlcztcclxuICBpZiAocmVzb3VyY2VzKSB7XHJcbiAgICBjb25zdCBpbmplY3RlZEpzID0gW107XHJcblxyXG4gICAgLy8gTG9hZCBjdXN0b20gSlMgY29kZVxyXG4gICAgaWYgKHJlc291cmNlcy5qcykge1xyXG4gICAgICBpbmplY3RlZEpzLnB1c2goe1xyXG4gICAgICAgIGNvbnRlbnQ6IHJlc291cmNlcy5qc1xyXG4gICAgICB9KTtcclxuICAgIH1cclxuXHJcbiAgICAvLyBMb2FkIHNjcmlwdHMgZnJvbSBhbGwgY3VzdG9tIGZpbGVzXHJcbiAgICBpZiAocmVzb3VyY2VzLmZpbGVzKSB7XHJcbiAgICAgIGZvciAoY29uc3QgZmlsZSBvZiByZXNvdXJjZXMuZmlsZXMpIHtcclxuICAgICAgICBjb25zdCBpc0xvY2FsID0gIWZpbGUuc3RhcnRzV2l0aCgnaHR0cCcpID8gdHJ1ZSA6IGZhbHNlO1xyXG5cclxuICAgICAgICAvLyBBZGQgZWFjaCBjdXN0b20gc2NyaXB0IGZyb20gcmVzb3VyY2VzJyBmaWxlc1xyXG4gICAgICAgIGluamVjdGVkSnMucHVzaChcclxuICAgICAgICAgIGlzTG9jYWxcclxuICAgICAgICAgICAgPyB7XHJcbiAgICAgICAgICAgICAgICBjb250ZW50OiByZWFkRmlsZVN5bmMoZ2V0QWJzb2x1dGVQYXRoKGZpbGUpLCAndXRmOCcpXHJcbiAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICA6IHtcclxuICAgICAgICAgICAgICAgIHVybDogZmlsZVxyXG4gICAgICAgICAgICAgIH1cclxuICAgICAgICApO1xyXG4gICAgICB9XHJcbiAgICB9XHJcblxyXG4gICAgZm9yIChjb25zdCBqc1Jlc291cmNlIG9mIGluamVjdGVkSnMpIHtcclxuICAgICAgdHJ5IHtcclxuICAgICAgICBpbmplY3RlZFJlc291cmNlcy5wdXNoKGF3YWl0IHBhZ2UuYWRkU2NyaXB0VGFnKGpzUmVzb3VyY2UpKTtcclxuICAgICAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICAgICBsb2dXaXRoU3RhY2soMiwgZXJyb3IsIGBbYnJvd3Nlcl0gVGhlIEpTIHJlc291cmNlIGNhbm5vdCBiZSBsb2FkZWQuYCk7XHJcbiAgICAgIH1cclxuICAgIH1cclxuICAgIGluamVjdGVkSnMubGVuZ3RoID0gMDtcclxuXHJcbiAgICAvLyBMb2FkIENTU1xyXG4gICAgY29uc3QgaW5qZWN0ZWRDc3MgPSBbXTtcclxuICAgIGlmIChyZXNvdXJjZXMuY3NzKSB7XHJcbiAgICAgIGxldCBjc3NJbXBvcnRzID0gcmVzb3VyY2VzLmNzcy5tYXRjaCgvQGltcG9ydFxccyooW147XSopOy9nKTtcclxuICAgICAgaWYgKGNzc0ltcG9ydHMpIHtcclxuICAgICAgICAvLyBIYW5kbGUgY3NzIHNlY3Rpb25cclxuICAgICAgICBmb3IgKGxldCBjc3NJbXBvcnRQYXRoIG9mIGNzc0ltcG9ydHMpIHtcclxuICAgICAgICAgIGlmIChjc3NJbXBvcnRQYXRoKSB7XHJcbiAgICAgICAgICAgIGNzc0ltcG9ydFBhdGggPSBjc3NJbXBvcnRQYXRoXHJcbiAgICAgICAgICAgICAgLnJlcGxhY2UoJ3VybCgnLCAnJylcclxuICAgICAgICAgICAgICAucmVwbGFjZSgnQGltcG9ydCcsICcnKVxyXG4gICAgICAgICAgICAgIC5yZXBsYWNlKC9cIi9nLCAnJylcclxuICAgICAgICAgICAgICAucmVwbGFjZSgvJy9nLCAnJylcclxuICAgICAgICAgICAgICAucmVwbGFjZSgvOy8sICcnKVxyXG4gICAgICAgICAgICAgIC5yZXBsYWNlKC9cXCkvZywgJycpXHJcbiAgICAgICAgICAgICAgLnRyaW0oKTtcclxuXHJcbiAgICAgICAgICAgIC8vIEFkZCBlYWNoIGN1c3RvbSBjc3MgZnJvbSByZXNvdXJjZXNcclxuICAgICAgICAgICAgaWYgKGNzc0ltcG9ydFBhdGguc3RhcnRzV2l0aCgnaHR0cCcpKSB7XHJcbiAgICAgICAgICAgICAgaW5qZWN0ZWRDc3MucHVzaCh7XHJcbiAgICAgICAgICAgICAgICB1cmw6IGNzc0ltcG9ydFBhdGhcclxuICAgICAgICAgICAgICB9KTtcclxuICAgICAgICAgICAgfSBlbHNlIGlmIChjdXN0b21Mb2dpY09wdGlvbnMuYWxsb3dGaWxlUmVzb3VyY2VzKSB7XHJcbiAgICAgICAgICAgICAgaW5qZWN0ZWRDc3MucHVzaCh7XHJcbiAgICAgICAgICAgICAgICBwYXRoOiBqb2luKF9fZGlybmFtZSwgY3NzSW1wb3J0UGF0aClcclxuICAgICAgICAgICAgICB9KTtcclxuICAgICAgICAgICAgfVxyXG4gICAgICAgICAgfVxyXG4gICAgICAgIH1cclxuICAgICAgfVxyXG5cclxuICAgICAgLy8gVGhlIHJlc3Qgb2YgdGhlIENTUyBzZWN0aW9uIHdpbGwgYmUgY29udGVudCBieSBub3dcclxuICAgICAgaW5qZWN0ZWRDc3MucHVzaCh7XHJcbiAgICAgICAgY29udGVudDogcmVzb3VyY2VzLmNzcy5yZXBsYWNlKC9AaW1wb3J0XFxzKihbXjtdKik7L2csICcnKSB8fCAnICdcclxuICAgICAgfSk7XHJcblxyXG4gICAgICBmb3IgKGNvbnN0IGNzc1Jlc291cmNlIG9mIGluamVjdGVkQ3NzKSB7XHJcbiAgICAgICAgdHJ5IHtcclxuICAgICAgICAgIGluamVjdGVkUmVzb3VyY2VzLnB1c2goYXdhaXQgcGFnZS5hZGRTdHlsZVRhZyhjc3NSZXNvdXJjZSkpO1xyXG4gICAgICAgIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICAgICAgICBsb2dXaXRoU3RhY2soXHJcbiAgICAgICAgICAgIDIsXHJcbiAgICAgICAgICAgIGVycm9yLFxyXG4gICAgICAgICAgICBgW2Jyb3dzZXJdIFRoZSBDU1MgcmVzb3VyY2UgY2Fubm90IGJlIGxvYWRlZC5gXHJcbiAgICAgICAgICApO1xyXG4gICAgICAgIH1cclxuICAgICAgfVxyXG4gICAgICBpbmplY3RlZENzcy5sZW5ndGggPSAwO1xyXG4gICAgfVxyXG4gIH1cclxuICByZXR1cm4gaW5qZWN0ZWRSZXNvdXJjZXM7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBDbGVhcnMgb3V0IGFsbCBzdGF0ZSBzZXQgb24gdGhlIHBhZ2Ugd2l0aCBgYWRkU2NyaXB0VGFnYCBhbmQgYGFkZFN0eWxlVGFnYC5cclxuICogUmVtb3ZlcyBpbmplY3RlZCByZXNvdXJjZXMgYW5kIHJlc2V0cyBDU1MgYW5kIHNjcmlwdCB0YWdzIG9uIHRoZSBwYWdlLlxyXG4gKiBBZGRpdGlvbmFsbHksIGl0IGRlc3Ryb3lzIHByZXZpb3VzbHkgZXhpc3RpbmcgY2hhcnRzLlxyXG4gKlxyXG4gKiBAYXN5bmNcclxuICogQGZ1bmN0aW9uIGNsZWFyUGFnZVJlc291cmNlc1xyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gcGFnZSAtIFRoZSBQdXBwZXRlZXIgcGFnZSBvYmplY3QgZnJvbSB3aGljaCByZXNvdXJjZXMgd2lsbFxyXG4gKiBiZSBjbGVhcmVkLlxyXG4gKiBAcGFyYW0ge0FycmF5LjxPYmplY3Q+fSBpbmplY3RlZFJlc291cmNlcyAtIEFycmF5IG9mIGluamVjdGVkIHJlc291cmNlc1xyXG4gKiB0byBiZSBjbGVhcmVkLlxyXG4gKi9cclxuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIGNsZWFyUGFnZVJlc291cmNlcyhwYWdlLCBpbmplY3RlZFJlc291cmNlcykge1xyXG4gIHRyeSB7XHJcbiAgICBmb3IgKGNvbnN0IHJlc291cmNlIG9mIGluamVjdGVkUmVzb3VyY2VzKSB7XHJcbiAgICAgIGF3YWl0IHJlc291cmNlLmRpc3Bvc2UoKTtcclxuICAgIH1cclxuXHJcbiAgICAvLyBEZXN0cm95IG9sZCBjaGFydHMgYWZ0ZXIgZXhwb3J0IGlzIGRvbmUgYW5kIHJlc2V0IGFsbCBDU1MgYW5kIHNjcmlwdCB0YWdzXHJcbiAgICBhd2FpdCBwYWdlLmV2YWx1YXRlKCgpID0+IHtcclxuICAgICAgLy8gV2UgYXJlIG5vdCBndWFyYW50ZWVkIHRoYXQgSGlnaGNoYXJ0cyBpcyBsb2FkZWQsIHdoZW4gZG9pbmcgU1ZHIGV4cG9ydHNcclxuICAgICAgaWYgKHR5cGVvZiBIaWdoY2hhcnRzICE9PSAndW5kZWZpbmVkJykge1xyXG4gICAgICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBuby11bmRlZlxyXG4gICAgICAgIGNvbnN0IG9sZENoYXJ0cyA9IEhpZ2hjaGFydHMuY2hhcnRzO1xyXG5cclxuICAgICAgICAvLyBDaGVjayBpbiBhbnkgYWxyZWFkeSBleGlzdGluZyBjaGFydHNcclxuICAgICAgICBpZiAoQXJyYXkuaXNBcnJheShvbGRDaGFydHMpICYmIG9sZENoYXJ0cy5sZW5ndGgpIHtcclxuICAgICAgICAgIC8vIERlc3Ryb3kgb2xkIGNoYXJ0c1xyXG4gICAgICAgICAgZm9yIChjb25zdCBvbGRDaGFydCBvZiBvbGRDaGFydHMpIHtcclxuICAgICAgICAgICAgb2xkQ2hhcnQgJiYgb2xkQ2hhcnQuZGVzdHJveSgpO1xyXG4gICAgICAgICAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgbm8tdW5kZWZcclxuICAgICAgICAgICAgSGlnaGNoYXJ0cy5jaGFydHMuc2hpZnQoKTtcclxuICAgICAgICAgIH1cclxuICAgICAgICB9XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBuby11bmRlZlxyXG4gICAgICBjb25zdCBbLi4uc2NyaXB0c1RvUmVtb3ZlXSA9IGRvY3VtZW50LmdldEVsZW1lbnRzQnlUYWdOYW1lKCdzY3JpcHQnKTtcclxuICAgICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIG5vLXVuZGVmXHJcbiAgICAgIGNvbnN0IFssIC4uLnN0eWxlc1RvUmVtb3ZlXSA9IGRvY3VtZW50LmdldEVsZW1lbnRzQnlUYWdOYW1lKCdzdHlsZScpO1xyXG4gICAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgbm8tdW5kZWZcclxuICAgICAgY29uc3QgWy4uLmxpbmtzVG9SZW1vdmVdID0gZG9jdW1lbnQuZ2V0RWxlbWVudHNCeVRhZ05hbWUoJ2xpbmsnKTtcclxuXHJcbiAgICAgIC8vIFJlbW92ZSB0YWdzXHJcbiAgICAgIGZvciAoY29uc3QgZWxlbWVudCBvZiBbXHJcbiAgICAgICAgLi4uc2NyaXB0c1RvUmVtb3ZlLFxyXG4gICAgICAgIC4uLnN0eWxlc1RvUmVtb3ZlLFxyXG4gICAgICAgIC4uLmxpbmtzVG9SZW1vdmVcclxuICAgICAgXSkge1xyXG4gICAgICAgIGVsZW1lbnQucmVtb3ZlKCk7XHJcbiAgICAgIH1cclxuICAgIH0pO1xyXG4gIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICBsb2dXaXRoU3RhY2soMiwgZXJyb3IsIGBbYnJvd3Nlcl0gQ291bGQgbm90IGNsZWFyIHBhZ2UncyByZXNvdXJjZXMuYCk7XHJcbiAgfVxyXG59XHJcblxyXG4vKipcclxuICogU2V0cyB0aGUgY29udGVudCBmb3IgYSBQdXBwZXRlZXIgUGFnZSB1c2luZyBhIHByZWRlZmluZWQgdGVtcGxhdGVcclxuICogYW5kIGFkZGl0aW9uYWwgc2NyaXB0cy5cclxuICpcclxuICogQGFzeW5jXHJcbiAqIEBmdW5jdGlvbiBfc2V0UGFnZUNvbnRlbnRcclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IHBhZ2UgLSBUaGUgUHVwcGV0ZWVyIHBhZ2Ugb2JqZWN0IHRvIHdoaWNoIHRoZSBjb250ZW50XHJcbiAqIGlzIGJlaW5nIHNldC5cclxuICovXHJcbmFzeW5jIGZ1bmN0aW9uIF9zZXRQYWdlQ29udGVudChwYWdlKSB7XHJcbiAgLy8gU2V0IHRoZSBpbml0aWFsIHBhZ2UgY29udGVudFxyXG4gIGF3YWl0IHBhZ2Uuc2V0Q29udGVudCh0ZW1wbGF0ZSwgeyB3YWl0VW50aWw6ICdkb21jb250ZW50bG9hZGVkJyB9KTtcclxuXHJcbiAgLy8gQWRkIGFsbCByZWdpc3RlcmVkIEhpZ2NoYXJ0cyBzY3JpcHRzLCBxdWl0ZSBkZW1hbmRpbmdcclxuICBhd2FpdCBwYWdlLmFkZFNjcmlwdFRhZyh7IHBhdGg6IGpvaW4oZ2V0Q2FjaGVQYXRoKCksICdzb3VyY2VzLmpzJykgfSk7XHJcblxyXG4gIC8vIFNldCB0aGUgaW5pdGlhbCBgYW5pbU9iamVjdGAgZm9yIEhpZ2hjaGFydHNcclxuICBhd2FpdCBwYWdlLmV2YWx1YXRlKHNldHVwSGlnaGNoYXJ0cyk7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBTZXQgZXZlbnRzIChsaWtlIGBwYWdlZXJyb3JgIGFuZCBgY29uc29sZWApIGZvciBhIFB1cHBldGVlciBQYWdlIGluIG9yZGVyXHJcbiAqIHRvIGNhdGNoIGFuZCBkaXNwbGF5IGVycm9ycyBhbmQgY29uc29sZSBsb2dzIGZyb20gdGhlIHdpbmRvdyBjb250ZXh0LlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gX3NldFBhZ2VFdmVudHNcclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IHBhZ2UgLSBUaGUgUHVwcGV0ZWVyIHBhZ2Ugb2JqZWN0IHRvIHdoaWNoIHRoZSBsaXN0ZW5lcnNcclxuICogYXJlIGJlaW5nIHNldC5cclxuICovXHJcbmZ1bmN0aW9uIF9zZXRQYWdlRXZlbnRzKHBhZ2UpIHtcclxuICAvLyBHZXQgYGRlYnVnYCBvcHRpb25zXHJcbiAgY29uc3QgeyBkZWJ1ZyB9ID0gZ2V0T3B0aW9ucygpO1xyXG5cclxuICAvLyBTZXQgdGhlIGBwYWdlZXJyb3JgIGxpc3RlbmVyXHJcbiAgcGFnZS5vbigncGFnZWVycm9yJywgYXN5bmMgKCkgPT4ge1xyXG4gICAgLy8gSXQgd291bGQgc2VlbSBsaWtlIHRoaXMgbWF5IGZpcmUgYXQgdGhlIHNhbWUgdGltZSBvciBzaG9ydGx5IGJlZm9yZVxyXG4gICAgLy8gYSBwYWdlIGlzIGNsb3NlZC5cclxuICAgIGlmIChwYWdlLmlzQ2xvc2VkKCkpIHtcclxuICAgICAgcmV0dXJuO1xyXG4gICAgfVxyXG4gIH0pO1xyXG5cclxuICAvLyBTZXQgdGhlIGBjb25zb2xlYCBsaXN0ZW5lciwgaWYgbmVlZGVkXHJcbiAgaWYgKGRlYnVnLmVuYWJsZSAmJiBkZWJ1Zy5saXN0ZW5Ub0NvbnNvbGUpIHtcclxuICAgIHBhZ2Uub24oJ2NvbnNvbGUnLCAobWVzc2FnZSkgPT4ge1xyXG4gICAgICBjb25zb2xlLmxvZyhgW2RlYnVnXSAke21lc3NhZ2UudGV4dCgpfWApO1xyXG4gICAgfSk7XHJcbiAgfVxyXG59XHJcblxyXG5leHBvcnQgZGVmYXVsdCB7XHJcbiAgZ2V0QnJvd3NlcixcclxuICBjcmVhdGVCcm93c2VyLFxyXG4gIGNsb3NlQnJvd3NlcixcclxuICBuZXdQYWdlLFxyXG4gIGNsZWFyUGFnZSxcclxuICBhZGRQYWdlUmVzb3VyY2VzLFxyXG4gIGNsZWFyUGFnZVJlc291cmNlc1xyXG59O1xyXG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxyXG5cclxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXHJcblxyXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNSwgSGlnaHNvZnRcclxuXHJcbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cclxuXHJcbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxyXG5cclxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxyXG5cclxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cclxuXHJcbi8qKlxyXG4gKiBUaGUgQ1NTIHRvIGJlIHVzZWQgb24gdGhlIGV4cG9ydGVkIHBhZ2UuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtzdHJpbmd9IFRoZSBDU1MgY29uZmlndXJhdGlvbi5cclxuICovXHJcbmV4cG9ydCBkZWZhdWx0ICgpID0+IGBcclxuXHJcbmh0bWwsIGJvZHkge1xyXG4gIG1hcmdpbjogMDtcclxuICBwYWRkaW5nOiAwO1xyXG4gIGJveC1zaXppbmc6IGJvcmRlci1ib3g7XHJcbn1cclxuXHJcbiN0YWJsZS1kaXYsICNzbGlkZXJzLCAjZGF0YXRhYmxlLCAjY29udHJvbHMsIC5sZC1yb3cge1xyXG4gIGRpc3BsYXk6IG5vbmU7XHJcbiAgaGVpZ2h0OiAwO1xyXG59XHJcblxyXG4jY2hhcnQtY29udGFpbmVyIHtcclxuICBib3gtc2l6aW5nOiBib3JkZXItYm94O1xyXG4gIG1hcmdpbjogMDtcclxuICBvdmVyZmxvdzogYXV0bztcclxuICBmb250LXNpemU6IDA7XHJcbn1cclxuXHJcbiNjaGFydC1jb250YWluZXIgPiBmaWd1cmUsIGRpdiB7XHJcbiAgbWFyZ2luLXRvcDogMCAhaW1wb3J0YW50O1xyXG4gIG1hcmdpbi1ib3R0b206IDAgIWltcG9ydGFudDtcclxufVxyXG5cclxuYDtcclxuIiwiLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcclxuXHJcbkhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlclxyXG5cclxuQ29weXJpZ2h0IChjKSAyMDE2LTIwMjUsIEhpZ2hzb2Z0XHJcblxyXG5MaWNlbmNlZCB1bmRlciB0aGUgTUlUIGxpY2VuY2UuXHJcblxyXG5BZGRpdGlvbmFsbHkgYSB2YWxpZCBIaWdoY2hhcnRzIGxpY2Vuc2UgaXMgcmVxdWlyZWQgZm9yIHVzZS5cclxuXHJcblNlZSBMSUNFTlNFIGZpbGUgaW4gcm9vdCBmb3IgZGV0YWlscy5cclxuXHJcbioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXHJcblxyXG5pbXBvcnQgY3NzVGVtcGxhdGUgZnJvbSAnLi9jc3MuanMnO1xyXG5cclxuLyoqXHJcbiAqIFRoZSBTVkcgdGVtcGxhdGUgdG8gdXNlIHdoZW4gbG9hZGluZyBTVkcgY29udGVudCB0byBiZSBleHBvcnRlZC5cclxuICpcclxuICogQHBhcmFtIHtzdHJpbmd9IHN2ZyAtIFRoZSBTVkcgaW5wdXQgY29udGVudCB0byBiZSBleHBvcnRlZC5cclxuICpcclxuICogQHJldHVybnMge3N0cmluZ30gVGhlIFNWRyB0ZW1wbGF0ZS5cclxuICovXHJcbmV4cG9ydCBkZWZhdWx0IChzdmcpID0+IGBcclxuPCFET0NUWVBFIGh0bWw+XHJcbjxodG1sIGxhbmc9J2VuLVVTJz5cclxuICA8aGVhZD5cclxuICAgIDxtZXRhIGh0dHAtZXF1aXY9XCJDb250ZW50LVR5cGVcIiBjb250ZW50PVwidGV4dC9odG1sOyBjaGFyc2V0PXV0Zi04XCI+XHJcbiAgICA8dGl0bGU+SGlnaGNoYXJ0cyBFeHBvcnQ8L3RpdGxlPlxyXG4gIDwvaGVhZD5cclxuICA8c3R5bGU+XHJcbiAgICAke2Nzc1RlbXBsYXRlKCl9XHJcbiAgPC9zdHlsZT5cclxuICA8Ym9keT5cclxuICAgIDxkaXYgaWQ9XCJjaGFydC1jb250YWluZXJcIj5cclxuICAgICAgJHtzdmd9XHJcbiAgICA8L2Rpdj5cclxuICA8L2JvZHk+XHJcbjwvaHRtbD5cclxuXHJcbmA7XHJcbiIsIi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXHJcblxyXG5IaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXJcclxuXHJcbkNvcHlyaWdodCAoYykgMjAxNi0yMDI1LCBIaWdoc29mdFxyXG5cclxuTGljZW5jZWQgdW5kZXIgdGhlIE1JVCBsaWNlbmNlLlxyXG5cclxuQWRkaXRpb25hbGx5IGEgdmFsaWQgSGlnaGNoYXJ0cyBsaWNlbnNlIGlzIHJlcXVpcmVkIGZvciB1c2UuXHJcblxyXG5TZWUgTElDRU5TRSBmaWxlIGluIHJvb3QgZm9yIGRldGFpbHMuXHJcblxyXG4qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xyXG5cclxuLyoqXHJcbiAqIEBvdmVydmlldyBUaGlzIG1vZHVsZSBoYW5kbGVzIGNoYXJ0IGV4cG9ydCBmdW5jdGlvbmFsaXR5IHVzaW5nIFB1cHBldGVlci5cclxuICogSXQgc3VwcG9ydHMgZXhwb3J0aW5nIGNoYXJ0cyBhcyBTVkcsIFBORywgSlBFRywgYW5kIFBERiBmb3JtYXRzLiBUaGUgbW9kdWxlXHJcbiAqIG1hbmFnZXMgcGFnZSByZXNvdXJjZXMsIHNldHMgdXAgdGhlIGV4cG9ydCBlbnZpcm9ubWVudCwgYW5kIHByb2Nlc3NlcyBjaGFydFxyXG4gKiBjb25maWd1cmF0aW9ucyBvciBTVkcgaW5wdXRzIGZvciByZW5kZXJpbmcuIEV4cG9ydHMgdG8gYSBjaGFydCBmcm9tIGEgcGFnZVxyXG4gKiB1c2luZyBQdXBwZXRlZXIuXHJcbiAqL1xyXG5cclxuaW1wb3J0IHsgYWRkUGFnZVJlc291cmNlcywgY2xlYXJQYWdlUmVzb3VyY2VzIH0gZnJvbSAnLi9icm93c2VyLmpzJztcclxuaW1wb3J0IHsgY3JlYXRlQ2hhcnQgfSBmcm9tICcuL2hpZ2hjaGFydHMuanMnO1xyXG5pbXBvcnQgeyBsb2cgfSBmcm9tICcuL2xvZ2dlci5qcyc7XHJcblxyXG5pbXBvcnQgc3ZnVGVtcGxhdGUgZnJvbSAnLi4vdGVtcGxhdGVzL3N2Z0V4cG9ydC9zdmdFeHBvcnQuanMnO1xyXG5cclxuaW1wb3J0IEV4cG9ydEVycm9yIGZyb20gJy4vZXJyb3JzL0V4cG9ydEVycm9yLmpzJztcclxuXHJcbi8qKlxyXG4gKiBFeHBvcnRzIHRvIGEgY2hhcnQgZnJvbSBhIHBhZ2UgdXNpbmcgUHVwcGV0ZWVyLlxyXG4gKlxyXG4gKiBAYXN5bmNcclxuICogQGZ1bmN0aW9uIHB1cHBldGVlckV4cG9ydFxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gcGFnZSAtIFB1cHBldGVlciBwYWdlIG9iamVjdC5cclxuICogQHBhcmFtIHtPYmplY3R9IG9wdGlvbnMgLSBUaGUgYG9wdGlvbnNgIG9iamVjdCBjb250YWluaW5nIGNvbXBsZXRlIHNldFxyXG4gKiBvZiBvcHRpb25zLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7UHJvbWlzZTwoc3RyaW5nfEJ1ZmZlcnxFeHBvcnRFcnJvcik+fSBBIFByb21pc2UgdGhhdCByZXNvbHZlc1xyXG4gKiB0byB0aGUgZXhwb3J0ZWQgZGF0YSBvciByZWplY3Rpbmcgd2l0aCBhbiBgRXhwb3J0RXJyb3JgLlxyXG4gKlxyXG4gKiBAdGhyb3dzIHtFeHBvcnRFcnJvcn0gVGhyb3dzIGFuIGBFeHBvcnRFcnJvcmAgaWYgZXhwb3J0IHRvIGFuIHVuc3VwcG9ydGVkXHJcbiAqIG91dHB1dCBmb3JtYXQgb2NjdXJzLlxyXG4gKi9cclxuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIHB1cHBldGVlckV4cG9ydChwYWdlLCBvcHRpb25zKSB7XHJcbiAgLy8gSW5qZWN0ZWQgcmVzb3VyY2VzIGFycmF5IChhZGRpdGlvbmFsIEpTIGFuZCBDU1MpXHJcbiAgY29uc3QgaW5qZWN0ZWRSZXNvdXJjZXMgPSBbXTtcclxuXHJcbiAgdHJ5IHtcclxuICAgIC8vIEdldCB0aGUgYGV4cG9ydGAgb3B0aW9uc1xyXG4gICAgY29uc3QgZXhwb3J0T3B0aW9ucyA9IG9wdGlvbnMuZXhwb3J0O1xyXG5cclxuICAgIGxldCBpc1NWRyA9IGZhbHNlO1xyXG4gICAgaWYgKGV4cG9ydE9wdGlvbnMuc3ZnKSB7XHJcbiAgICAgIGxvZyg0LCAnW2V4cG9ydF0gVHJlYXRpbmcgYXMgU1ZHIGlucHV0LicpO1xyXG5cclxuICAgICAgLy8gSWYgdGhlIGB0eXBlYCBpcyBhbHNvIFNWRywgcmV0dXJuIHRoZSBpbnB1dFxyXG4gICAgICBpZiAoZXhwb3J0T3B0aW9ucy50eXBlID09PSAnc3ZnJykge1xyXG4gICAgICAgIHJldHVybiBleHBvcnRPcHRpb25zLnN2ZztcclxuICAgICAgfVxyXG5cclxuICAgICAgLy8gTWFyayBhcyBTVkcgZXhwb3J0IGZvciB0aGUgbGF0ZXIgc2l6ZSBjb3JyZWN0aW9uc1xyXG4gICAgICBpc1NWRyA9IHRydWU7XHJcblxyXG4gICAgICAvLyBTVkcgZXhwb3J0XHJcbiAgICAgIGF3YWl0IF9zZXRBc1N2ZyhwYWdlLCBleHBvcnRPcHRpb25zLnN2Zyk7XHJcbiAgICB9IGVsc2Uge1xyXG4gICAgICBsb2coNCwgJ1tleHBvcnRdIFRyZWF0aW5nIGFzIEpTT04gY29uZmlnLicpO1xyXG5cclxuICAgICAgLy8gT3B0aW9ucyBleHBvcnRcclxuICAgICAgYXdhaXQgX3NldEFzT3B0aW9ucyhwYWdlLCBvcHRpb25zKTtcclxuICAgIH1cclxuXHJcbiAgICAvLyBLZWVwcyB0cmFjayBvZiBhbGwgcmVzb3VyY2VzIGFkZGVkIG9uIHRoZSBwYWdlIHdpdGggYWRkWFhYVGFnLiBldGNcclxuICAgIC8vIEl0J3MgVklUQUwgdGhhdCBhbGwgYWRkZWQgcmVzb3VyY2VzIGVuZHMgdXAgaGVyZSBzbyB3ZSBjYW4gY2xlYXIgdGhpbmdzXHJcbiAgICAvLyBvdXQgd2hlbiBkb2luZyBhIG5ldyBleHBvcnQgaW4gdGhlIHNhbWUgcGFnZSFcclxuICAgIGluamVjdGVkUmVzb3VyY2VzLnB1c2goXHJcbiAgICAgIC4uLihhd2FpdCBhZGRQYWdlUmVzb3VyY2VzKHBhZ2UsIG9wdGlvbnMuY3VzdG9tTG9naWMpKVxyXG4gICAgKTtcclxuXHJcbiAgICAvLyBHZXQgdGhlIHJlYWwgY2hhcnQgc2l6ZSBhbmQgc2V0IHRoZSB6b29tIGFjY29yZGluZ2x5XHJcbiAgICBjb25zdCBzaXplID0gaXNTVkdcclxuICAgICAgPyBhd2FpdCBwYWdlLmV2YWx1YXRlKChzY2FsZSkgPT4ge1xyXG4gICAgICAgICAgY29uc3Qgc3ZnRWxlbWVudCA9IGRvY3VtZW50LnF1ZXJ5U2VsZWN0b3IoXHJcbiAgICAgICAgICAgICcjY2hhcnQtY29udGFpbmVyIHN2ZzpmaXJzdC1vZi10eXBlJ1xyXG4gICAgICAgICAgKTtcclxuXHJcbiAgICAgICAgICAvLyBHZXQgdGhlIHZhbHVlcyBjb3JyZWN0bHkgc2NhbGVkXHJcbiAgICAgICAgICBjb25zdCBjaGFydEhlaWdodCA9IHN2Z0VsZW1lbnQuaGVpZ2h0LmJhc2VWYWwudmFsdWUgKiBzY2FsZTtcclxuICAgICAgICAgIGNvbnN0IGNoYXJ0V2lkdGggPSBzdmdFbGVtZW50LndpZHRoLmJhc2VWYWwudmFsdWUgKiBzY2FsZTtcclxuXHJcbiAgICAgICAgICAvLyBJbiBjYXNlIG9mIFNWRyB0aGUgem9vbSBtdXN0IGJlIHNldCBkaXJlY3RseSBmb3IgYm9keSBhcyBzY2FsZVxyXG4gICAgICAgICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIG5vLXVuZGVmXHJcbiAgICAgICAgICBkb2N1bWVudC5ib2R5LnN0eWxlLnpvb20gPSBzY2FsZTtcclxuXHJcbiAgICAgICAgICAvLyBTZXQgdGhlIG1hcmdpbiB0byAwcHhcclxuICAgICAgICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBuby11bmRlZlxyXG4gICAgICAgICAgZG9jdW1lbnQuYm9keS5zdHlsZS5tYXJnaW4gPSAnMHB4JztcclxuXHJcbiAgICAgICAgICByZXR1cm4ge1xyXG4gICAgICAgICAgICBjaGFydEhlaWdodCxcclxuICAgICAgICAgICAgY2hhcnRXaWR0aFxyXG4gICAgICAgICAgfTtcclxuICAgICAgICB9LCBwYXJzZUZsb2F0KGV4cG9ydE9wdGlvbnMuc2NhbGUpKVxyXG4gICAgICA6IGF3YWl0IHBhZ2UuZXZhbHVhdGUoKCkgPT4ge1xyXG4gICAgICAgICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIG5vLXVuZGVmXHJcbiAgICAgICAgICBjb25zdCB7IGNoYXJ0SGVpZ2h0LCBjaGFydFdpZHRoIH0gPSB3aW5kb3cuSGlnaGNoYXJ0cy5jaGFydHNbMF07XHJcblxyXG4gICAgICAgICAgLy8gTm8gbmVlZCBmb3Igc3VjaCBzY2FsZSBtYW5pcHVsYXRpb24gaW4gY2FzZSBvZiBvdGhlciB0eXBlc1xyXG4gICAgICAgICAgLy8gb2YgZXhwb3J0cy4gUmVzZXQgdGhlIHpvb20gZm9yIG90aGVyIGV4cG9ydHMgdGhhbiB0byBTVkdzXHJcbiAgICAgICAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgbm8tdW5kZWZcclxuICAgICAgICAgIGRvY3VtZW50LmJvZHkuc3R5bGUuem9vbSA9IDE7XHJcblxyXG4gICAgICAgICAgcmV0dXJuIHtcclxuICAgICAgICAgICAgY2hhcnRIZWlnaHQsXHJcbiAgICAgICAgICAgIGNoYXJ0V2lkdGhcclxuICAgICAgICAgIH07XHJcbiAgICAgICAgfSk7XHJcblxyXG4gICAgLy8gR2V0IHRoZSBjbGlwIHJlZ2lvbiBmb3IgdGhlIHBhZ2VcclxuICAgIGNvbnN0IHsgeCwgeSB9ID0gYXdhaXQgX2dldENsaXBSZWdpb24ocGFnZSk7XHJcblxyXG4gICAgLy8gU2V0IGZpbmFsIGBoZWlnaHRgIGZvciB2aWV3cG9ydFxyXG4gICAgY29uc3Qgdmlld3BvcnRIZWlnaHQgPSBNYXRoLmFicyhcclxuICAgICAgTWF0aC5jZWlsKHNpemUuY2hhcnRIZWlnaHQgfHwgZXhwb3J0T3B0aW9ucy5oZWlnaHQpXHJcbiAgICApO1xyXG5cclxuICAgIC8vIFNldCBmaW5hbCBgd2lkdGhgIGZvciB2aWV3cG9ydFxyXG4gICAgY29uc3Qgdmlld3BvcnRXaWR0aCA9IE1hdGguYWJzKFxyXG4gICAgICBNYXRoLmNlaWwoc2l6ZS5jaGFydFdpZHRoIHx8IGV4cG9ydE9wdGlvbnMud2lkdGgpXHJcbiAgICApO1xyXG5cclxuICAgIC8vIFNldCB0aGUgZmluYWwgdmlld3BvcnQgbm93IHRoYXQgd2UgaGF2ZSB0aGUgcmVhbCBoZWlnaHRcclxuICAgIGF3YWl0IHBhZ2Uuc2V0Vmlld3BvcnQoe1xyXG4gICAgICBoZWlnaHQ6IHZpZXdwb3J0SGVpZ2h0LFxyXG4gICAgICB3aWR0aDogdmlld3BvcnRXaWR0aCxcclxuICAgICAgZGV2aWNlU2NhbGVGYWN0b3I6IGlzU1ZHID8gMSA6IHBhcnNlRmxvYXQoZXhwb3J0T3B0aW9ucy5zY2FsZSlcclxuICAgIH0pO1xyXG5cclxuICAgIGxldCByZXN1bHQ7XHJcbiAgICAvLyBSYXN0ZXJpemF0aW9uIHByb2Nlc3NcclxuICAgIHN3aXRjaCAoZXhwb3J0T3B0aW9ucy50eXBlKSB7XHJcbiAgICAgIGNhc2UgJ3N2Zyc6XHJcbiAgICAgICAgcmVzdWx0ID0gYXdhaXQgX2NyZWF0ZVNWRyhwYWdlKTtcclxuICAgICAgICBicmVhaztcclxuICAgICAgY2FzZSAncG5nJzpcclxuICAgICAgY2FzZSAnanBlZyc6XHJcbiAgICAgICAgcmVzdWx0ID0gYXdhaXQgX2NyZWF0ZUltYWdlKFxyXG4gICAgICAgICAgcGFnZSxcclxuICAgICAgICAgIGV4cG9ydE9wdGlvbnMudHlwZSxcclxuICAgICAgICAgIHtcclxuICAgICAgICAgICAgd2lkdGg6IHZpZXdwb3J0V2lkdGgsXHJcbiAgICAgICAgICAgIGhlaWdodDogdmlld3BvcnRIZWlnaHQsXHJcbiAgICAgICAgICAgIHgsXHJcbiAgICAgICAgICAgIHlcclxuICAgICAgICAgIH0sXHJcbiAgICAgICAgICBleHBvcnRPcHRpb25zLnJhc3Rlcml6YXRpb25UaW1lb3V0XHJcbiAgICAgICAgKTtcclxuICAgICAgICBicmVhaztcclxuICAgICAgY2FzZSAncGRmJzpcclxuICAgICAgICByZXN1bHQgPSBhd2FpdCBfY3JlYXRlUERGKFxyXG4gICAgICAgICAgcGFnZSxcclxuICAgICAgICAgIHZpZXdwb3J0SGVpZ2h0LFxyXG4gICAgICAgICAgdmlld3BvcnRXaWR0aCxcclxuICAgICAgICAgIGV4cG9ydE9wdGlvbnMucmFzdGVyaXphdGlvblRpbWVvdXRcclxuICAgICAgICApO1xyXG4gICAgICAgIGJyZWFrO1xyXG4gICAgICBkZWZhdWx0OlxyXG4gICAgICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcihcclxuICAgICAgICAgIGBbZXhwb3J0XSBVbnN1cHBvcnRlZCBvdXRwdXQgZm9ybWF0OiAke2V4cG9ydE9wdGlvbnMudHlwZX0uYCxcclxuICAgICAgICAgIDQwMFxyXG4gICAgICAgICk7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gQ2xlYXIgcHJldmlvdXNseSBpbmplY3RlZCBKUyBhbmQgQ1NTIHJlc291cmNlc1xyXG4gICAgYXdhaXQgY2xlYXJQYWdlUmVzb3VyY2VzKHBhZ2UsIGluamVjdGVkUmVzb3VyY2VzKTtcclxuICAgIHJldHVybiByZXN1bHQ7XHJcbiAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgIGF3YWl0IGNsZWFyUGFnZVJlc291cmNlcyhwYWdlLCBpbmplY3RlZFJlc291cmNlcyk7XHJcbiAgICByZXR1cm4gZXJyb3I7XHJcbiAgfVxyXG59XHJcblxyXG4vKipcclxuICogU2V0cyB0aGUgc3BlY2lmaWVkIHBhZ2UncyBjb250ZW50IHdpdGggcHJvdmlkZWQgZXhwb3J0IGlucHV0IHdpdGhpblxyXG4gKiB0aGUgd2luZG93IGNvbnRleHQgdXNpbmcgdGhlIGBwYWdlLnNldENvbnRlbnRgIGZ1bmN0aW9uLlxyXG4gKlxyXG4gKiBAYXN5bmNcclxuICogQGZ1bmN0aW9uIF9zZXRBc1N2Z1xyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gcGFnZSAtIFB1cHBldGVlciBwYWdlIG9iamVjdC5cclxuICogQHBhcmFtIHtzdHJpbmd9IHN2ZyAtIFRoZSBTVkcgaW5wdXQgY29udGVudCB0byBiZSBleHBvcnRlZC5cclxuICpcclxuICogQHJldHVybnMge1Byb21pc2U8dm9pZD59IEEgUHJvbWlzZSB0aGF0IHJlc29sdmVzIGFmdGVyIHRoZSBjb250ZW50IGlzIHNldC5cclxuICovXHJcbmFzeW5jIGZ1bmN0aW9uIF9zZXRBc1N2ZyhwYWdlLCBzdmcpIHtcclxuICBhd2FpdCBwYWdlLnNldENvbnRlbnQoc3ZnVGVtcGxhdGUoc3ZnKSwge1xyXG4gICAgd2FpdFVudGlsOiAnZG9tY29udGVudGxvYWRlZCdcclxuICB9KTtcclxufVxyXG5cclxuLyoqXHJcbiAqIFNldHMgdGhlIG9wdGlvbnMgd2l0aCBzcGVjaWZpZWQgZXhwb3J0IGlucHV0IGFuZCBzaXplcyBhcyBjb25maWd1cmF0aW9uIGludG9cclxuICogdGhlIGBjcmVhdGVDaGFydGAgZnVuY3Rpb24gd2l0aGluIHRoZSB3aW5kb3cgY29udGV4dCB1c2luZ1xyXG4gKiB0aGUgYHBhZ2UuZXZhbHVhdGVgIGZ1bmN0aW9uLlxyXG4gKlxyXG4gKiBAYXN5bmNcclxuICogQGZ1bmN0aW9uIF9zZXRBc09wdGlvbnNcclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IHBhZ2UgLSBQdXBwZXRlZXIgcGFnZSBvYmplY3QuXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBvcHRpb25zIC0gVGhlIGBvcHRpb25zYCBvYmplY3QgY29udGFpbmluZyBjb21wbGV0ZSBzZXRcclxuICogb2Ygb3B0aW9ucy5cclxuICpcclxuICogQHJldHVybnMge1Byb21pc2U8dm9pZD59IEEgUHJvbWlzZSB0aGF0IHJlc29sdmVzIGFmdGVyIHRoZSBjb25maWd1cmF0aW9uXHJcbiAqIGlzIHNldC5cclxuICovXHJcbmFzeW5jIGZ1bmN0aW9uIF9zZXRBc09wdGlvbnMocGFnZSwgb3B0aW9ucykge1xyXG4gIGF3YWl0IHBhZ2UuZXZhbHVhdGUoY3JlYXRlQ2hhcnQsIG9wdGlvbnMpO1xyXG59XHJcblxyXG4vKipcclxuICogUmV0cmlldmVzIHRoZSBjbGlwcGluZyByZWdpb24gY29vcmRpbmF0ZXMgb2YgdGhlIHNwZWNpZmllZCBwYWdlIGVsZW1lbnRcclxuICogd2l0aCB0aGUgJ2NoYXJ0LWNvbnRhaW5lcicgaWQuXHJcbiAqXHJcbiAqIEBhc3luY1xyXG4gKiBAZnVuY3Rpb24gX2dldENsaXBSZWdpb25cclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IHBhZ2UgLSBQdXBwZXRlZXIgcGFnZSBvYmplY3QuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtQcm9taXNlPE9iamVjdD59IEEgUHJvbWlzZSB0aGF0IHJlc29sdmVzIHRvIGFuIG9iamVjdCBjb250YWluaW5nXHJcbiAqIGB4YCwgYHlgLCBgd2lkdGhgLCBhbmQgYGhlaWdodGAgcHJvcGVydGllcy5cclxuICovXHJcbmFzeW5jIGZ1bmN0aW9uIF9nZXRDbGlwUmVnaW9uKHBhZ2UpIHtcclxuICByZXR1cm4gcGFnZS4kZXZhbCgnI2NoYXJ0LWNvbnRhaW5lcicsIChlbGVtZW50KSA9PiB7XHJcbiAgICBjb25zdCB7IHgsIHksIHdpZHRoLCBoZWlnaHQgfSA9IGVsZW1lbnQuZ2V0Qm91bmRpbmdDbGllbnRSZWN0KCk7XHJcbiAgICByZXR1cm4ge1xyXG4gICAgICB4LFxyXG4gICAgICB5LFxyXG4gICAgICB3aWR0aCxcclxuICAgICAgaGVpZ2h0OiBNYXRoLnRydW5jKGhlaWdodCA+IDEgPyBoZWlnaHQgOiA1MDApXHJcbiAgICB9O1xyXG4gIH0pO1xyXG59XHJcblxyXG4vKipcclxuICogQ3JlYXRlcyBhbiBTVkcgYnkgZXZhbHVhdGluZyB0aGUgYG91dGVySFRNTGAgb2YgdGhlIGZpcnN0ICdzdmcnIGVsZW1lbnRcclxuICogaW5zaWRlIGFuIGVsZW1lbnQgd2l0aCB0aGUgaWQgJ2NvbnRhaW5lcicuXHJcbiAqXHJcbiAqIEBhc3luY1xyXG4gKiBAZnVuY3Rpb24gX2NyZWF0ZVNWR1xyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gcGFnZSAtIFB1cHBldGVlciBwYWdlIG9iamVjdC5cclxuICpcclxuICogQHJldHVybnMge1Byb21pc2U8c3RyaW5nPn0gQSBQcm9taXNlIHRoYXQgcmVzb2x2ZXMgdG8gdGhlIFNWRyBzdHJpbmcuXHJcbiAqL1xyXG5hc3luYyBmdW5jdGlvbiBfY3JlYXRlU1ZHKHBhZ2UpIHtcclxuICByZXR1cm4gcGFnZS4kZXZhbChcclxuICAgICcjY29udGFpbmVyIHN2ZzpmaXJzdC1vZi10eXBlJyxcclxuICAgIChlbGVtZW50KSA9PiBlbGVtZW50Lm91dGVySFRNTFxyXG4gICk7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBDcmVhdGVzIGFuIGltYWdlIHVzaW5nIFB1cHBldGVlcidzIHBhZ2UgYHNjcmVlbnNob3RgIGZ1bmN0aW9uYWxpdHkgd2l0aFxyXG4gKiBzcGVjaWZpZWQgb3B0aW9ucy5cclxuICpcclxuICogQGFzeW5jXHJcbiAqIEBmdW5jdGlvbiBfY3JlYXRlSW1hZ2VcclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IHBhZ2UgLSBQdXBwZXRlZXIgcGFnZSBvYmplY3QuXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSB0eXBlIC0gSW1hZ2UgdHlwZS5cclxuICogQHBhcmFtIHtPYmplY3R9IGNsaXAgLSBDbGlwcGluZyByZWdpb24gY29vcmRpbmF0ZXMuXHJcbiAqIEBwYXJhbSB7bnVtYmVyfSByYXN0ZXJpemF0aW9uVGltZW91dCAtIFRpbWVvdXQgZm9yIHJhc3Rlcml6YXRpb25cclxuICogaW4gbWlsbGlzZWNvbmRzLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7UHJvbWlzZTxCdWZmZXI+fSBBIFByb21pc2UgdGhhdCByZXNvbHZlcyB0byB0aGUgaW1hZ2UgYnVmZmVyXHJcbiAqIG9yIHJlamVjdGluZyB3aXRoIGFuIGBFeHBvcnRFcnJvcmAgZm9yIHRpbWVvdXQuXHJcbiAqL1xyXG5hc3luYyBmdW5jdGlvbiBfY3JlYXRlSW1hZ2UocGFnZSwgdHlwZSwgY2xpcCwgcmFzdGVyaXphdGlvblRpbWVvdXQpIHtcclxuICByZXR1cm4gUHJvbWlzZS5yYWNlKFtcclxuICAgIHBhZ2Uuc2NyZWVuc2hvdCh7XHJcbiAgICAgIHR5cGUsXHJcbiAgICAgIGNsaXAsXHJcbiAgICAgIGVuY29kaW5nOiAnYmFzZTY0JyxcclxuICAgICAgZnVsbFBhZ2U6IGZhbHNlLFxyXG4gICAgICBvcHRpbWl6ZUZvclNwZWVkOiB0cnVlLFxyXG4gICAgICBjYXB0dXJlQmV5b25kVmlld3BvcnQ6IHRydWUsXHJcbiAgICAgIC4uLih0eXBlICE9PSAncG5nJyA/IHsgcXVhbGl0eTogODAgfSA6IHt9KSxcclxuICAgICAgLy8gQWx3YXlzIHJlbmRlciBvbiBhIHRyYW5zcGFyZW50IHBhZ2UgaWYgdGhlIGV4cGVjdGVkIHR5cGUgZm9ybWF0IGlzIFBOR1xyXG4gICAgICBvbWl0QmFja2dyb3VuZDogdHlwZSA9PSAncG5nJyAvLyAjNDQ3LCAjNDYzXHJcbiAgICB9KSxcclxuICAgIG5ldyBQcm9taXNlKChfcmVzb2x2ZSwgcmVqZWN0KSA9PlxyXG4gICAgICBzZXRUaW1lb3V0KFxyXG4gICAgICAgICgpID0+IHJlamVjdChuZXcgRXhwb3J0RXJyb3IoJ1Jhc3Rlcml6YXRpb24gdGltZW91dCcsIDQwOCkpLFxyXG4gICAgICAgIHJhc3Rlcml6YXRpb25UaW1lb3V0IHx8IDE1MDBcclxuICAgICAgKVxyXG4gICAgKVxyXG4gIF0pO1xyXG59XHJcblxyXG4vKipcclxuICogQ3JlYXRlcyBhIFBERiB1c2luZyBQdXBwZXRlZXIncyBwYWdlIGBwZGZgIGZ1bmN0aW9uYWxpdHkgd2l0aCBzcGVjaWZpZWRcclxuICogb3B0aW9ucy5cclxuICpcclxuICogQGFzeW5jXHJcbiAqIEBmdW5jdGlvbiBfY3JlYXRlUERGXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBwYWdlIC0gUHVwcGV0ZWVyIHBhZ2Ugb2JqZWN0LlxyXG4gKiBAcGFyYW0ge251bWJlcn0gaGVpZ2h0IC0gUERGIGhlaWdodC5cclxuICogQHBhcmFtIHtudW1iZXJ9IHdpZHRoIC0gUERGIHdpZHRoLlxyXG4gKiBAcGFyYW0ge251bWJlcn0gcmFzdGVyaXphdGlvblRpbWVvdXQgLSBUaW1lb3V0IGZvciByYXN0ZXJpemF0aW9uXHJcbiAqIGluIG1pbGxpc2Vjb25kcy5cclxuICpcclxuICogQHJldHVybnMge1Byb21pc2U8QnVmZmVyPn0gQSBQcm9taXNlIHRoYXQgcmVzb2x2ZXMgdG8gdGhlIFBERiBidWZmZXIuXHJcbiAqL1xyXG5hc3luYyBmdW5jdGlvbiBfY3JlYXRlUERGKHBhZ2UsIGhlaWdodCwgd2lkdGgsIHJhc3Rlcml6YXRpb25UaW1lb3V0KSB7XHJcbiAgYXdhaXQgcGFnZS5lbXVsYXRlTWVkaWFUeXBlKCdzY3JlZW4nKTtcclxuICByZXR1cm4gcGFnZS5wZGYoe1xyXG4gICAgLy8gVGhpcyB3aWxsIHJlbW92ZSBhbiBleHRyYSBlbXB0eSBwYWdlIGluIFBERiBleHBvcnRzXHJcbiAgICBoZWlnaHQ6IGhlaWdodCArIDEsXHJcbiAgICB3aWR0aCxcclxuICAgIGVuY29kaW5nOiAnYmFzZTY0JyxcclxuICAgIHRpbWVvdXQ6IHJhc3Rlcml6YXRpb25UaW1lb3V0IHx8IDE1MDBcclxuICB9KTtcclxufVxyXG5cclxuZXhwb3J0IGRlZmF1bHQge1xyXG4gIHB1cHBldGVlckV4cG9ydFxyXG59O1xyXG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxyXG5cclxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXHJcblxyXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNSwgSGlnaHNvZnRcclxuXHJcbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cclxuXHJcbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxyXG5cclxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxyXG5cclxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cclxuXHJcbi8qKlxyXG4gKiBAb3ZlcnZpZXcgVGhpcyBtb2R1bGUgcHJvdmlkZXMgYSB3b3JrZXIgcG9vbCBpbXBsZW1lbnRhdGlvbiBmb3IgbWFuYWdpbmdcclxuICogdGhlIGJyb3dzZXIgaW5zdGFuY2UgYW5kIHBhZ2VzLCBzcGVjaWZpY2FsbHkgZGVzaWduZWQgZm9yIHVzZSB3aXRoXHJcbiAqIHRoZSBIaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXIuIEl0IG9wdGltaXplcyByZXNvdXJjZXMgdXNhZ2UgYW5kIHBlcmZvcm1hbmNlXHJcbiAqIGJ5IG1haW50YWluaW5nIGEgcG9vbCBvZiB3b3JrZXJzIHRoYXQgY2FuIGhhbmRsZSBjb25jdXJyZW50IGV4cG9ydCB0YXNrc1xyXG4gKiB1c2luZyBQdXBwZXRlZXIuXHJcbiAqL1xyXG5cclxuaW1wb3J0IHsgUG9vbCB9IGZyb20gJ3Rhcm4nO1xyXG5pbXBvcnQgeyB2NCBhcyB1dWlkIH0gZnJvbSAndXVpZCc7XHJcblxyXG5pbXBvcnQgeyBjcmVhdGVCcm93c2VyLCBjbG9zZUJyb3dzZXIsIG5ld1BhZ2UsIGNsZWFyUGFnZSB9IGZyb20gJy4vYnJvd3Nlci5qcyc7XHJcbmltcG9ydCB7IGdldE9wdGlvbnMgfSBmcm9tICcuL2NvbmZpZy5qcyc7XHJcbmltcG9ydCB7IHB1cHBldGVlckV4cG9ydCB9IGZyb20gJy4vZXhwb3J0LmpzJztcclxuaW1wb3J0IHsgbG9nLCBsb2dXaXRoU3RhY2sgfSBmcm9tICcuL2xvZ2dlci5qcyc7XHJcbmltcG9ydCB7IGdldE5ld0RhdGVUaW1lLCBtZWFzdXJlVGltZSB9IGZyb20gJy4vdXRpbHMuanMnO1xyXG5cclxuaW1wb3J0IEV4cG9ydEVycm9yIGZyb20gJy4vZXJyb3JzL0V4cG9ydEVycm9yLmpzJztcclxuXHJcbi8vIFRoZSBwb29sIGluc3RhbmNlXHJcbmxldCBwb29sID0gbnVsbDtcclxuXHJcbi8vIFBvb2wgc3RhdGlzdGljc1xyXG5jb25zdCBwb29sU3RhdHMgPSB7XHJcbiAgZXhwb3J0c0F0dGVtcHRlZDogMCxcclxuICBleHBvcnRzUGVyZm9ybWVkOiAwLFxyXG4gIGV4cG9ydHNEcm9wcGVkOiAwLFxyXG4gIGV4cG9ydHNGcm9tU3ZnOiAwLFxyXG4gIGV4cG9ydHNGcm9tT3B0aW9uczogMCxcclxuICBleHBvcnRzRnJvbVN2Z0F0dGVtcHRzOiAwLFxyXG4gIGV4cG9ydHNGcm9tT3B0aW9uc0F0dGVtcHRzOiAwLFxyXG4gIHRpbWVTcGVudDogMCxcclxuICB0aW1lU3BlbnRBdmVyYWdlOiAwXHJcbn07XHJcblxyXG4vKipcclxuICogSW5pdGlhbGl6ZXMgdGhlIGV4cG9ydCBwb29sIHdpdGggdGhlIHByb3ZpZGVkIGNvbmZpZ3VyYXRpb24sIGNyZWF0aW5nXHJcbiAqIGEgYnJvd3NlciBpbnN0YW5jZSBhbmQgc2V0dGluZyB1cCB3b3JrZXIgcmVzb3VyY2VzLlxyXG4gKlxyXG4gKiBAYXN5bmNcclxuICogQGZ1bmN0aW9uIGluaXRQb29sXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBbcG9vbE9wdGlvbnM9Z2V0T3B0aW9ucygpLnBvb2xdIC0gT2JqZWN0IGNvbnRhaW5pbmcgYHBvb2xgXHJcbiAqIG9wdGlvbnMuIFRoZSBkZWZhdWx0IHZhbHVlIGlzIHRoZSBnbG9iYWwgcG9vbCBvcHRpb25zIG9mIHRoZSBleHBvcnQgc2VydmVyXHJcbiAqIGluc3RhbmNlLlxyXG4gKiBAcGFyYW0ge0FycmF5LjxzdHJpbmc+fSBbcHVwcGV0ZWVyQXJncz1bXV0gLSBBZGRpdGlvbmFsIGFyZ3VtZW50c1xyXG4gKiBmb3IgUHVwcGV0ZWVyIGxhdW5jaC4gVGhlIGRlZmF1bHQgdmFsdWUgaXMgYW4gZW1wdHkgYXJyYXkuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtQcm9taXNlPHZvaWQ+fSBBIFByb21pc2UgdGhhdCByZXNvbHZlcyB0byBlbmRpbmcgdGhlIGZ1bmN0aW9uXHJcbiAqIGV4ZWN1dGlvbiB3aGVuIGFuIGFscmVhZHkgaW5pdGlhbGl6ZWQgcG9vbCBvZiByZXNvdXJjZXMgaXMgZm91bmQuXHJcbiAqXHJcbiAqIEB0aHJvd3Mge0V4cG9ydEVycm9yfSBUaHJvd3MgYW4gYEV4cG9ydEVycm9yYCBpZiBjb3VsZCBub3QgY3JlYXRlIHRoZSBwb29sXHJcbiAqIG9mIHdvcmtlcnMuXHJcbiAqL1xyXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gaW5pdFBvb2woXHJcbiAgcG9vbE9wdGlvbnMgPSBnZXRPcHRpb25zKCkucG9vbCxcclxuICBwdXBwZXRlZXJBcmdzID0gW11cclxuKSB7XHJcbiAgLy8gQ3JlYXRlIGEgYnJvd3NlciBpbnN0YW5jZSB3aXRoIHRoZSBwdXBwZXRlZXIgYXJndW1lbnRzXHJcbiAgYXdhaXQgY3JlYXRlQnJvd3NlcihwdXBwZXRlZXJBcmdzKTtcclxuXHJcbiAgdHJ5IHtcclxuICAgIGxvZyhcclxuICAgICAgMyxcclxuICAgICAgYFtwb29sXSBJbml0aWFsaXppbmcgcG9vbCB3aXRoIHdvcmtlcnM6IG1pbiAke3Bvb2xPcHRpb25zLm1pbldvcmtlcnN9LCBtYXggJHtwb29sT3B0aW9ucy5tYXhXb3JrZXJzfS5gXHJcbiAgICApO1xyXG5cclxuICAgIGlmIChwb29sKSB7XHJcbiAgICAgIGxvZyhcclxuICAgICAgICA0LFxyXG4gICAgICAgICdbcG9vbF0gQWxyZWFkeSBpbml0aWFsaXplZCwgcGxlYXNlIGtpbGwgaXQgYmVmb3JlIGNyZWF0aW5nIGEgbmV3IG9uZS4nXHJcbiAgICAgICk7XHJcbiAgICAgIHJldHVybjtcclxuICAgIH1cclxuXHJcbiAgICAvLyBLZWVwIGFuIGV5ZSBvbiBhIGNvcnJlY3QgbWluIGFuZCBtYXggd29ya2VycyBudW1iZXJcclxuICAgIGlmIChwb29sT3B0aW9ucy5taW5Xb3JrZXJzID4gcG9vbE9wdGlvbnMubWF4V29ya2Vycykge1xyXG4gICAgICBwb29sT3B0aW9ucy5taW5Xb3JrZXJzID0gcG9vbE9wdGlvbnMubWF4V29ya2VycztcclxuICAgIH1cclxuXHJcbiAgICAvLyBDcmVhdGUgYSBwb29sIGFsb25nIHdpdGggYSBtaW5pbWFsIG51bWJlciBvZiByZXNvdXJjZXNcclxuICAgIHBvb2wgPSBuZXcgUG9vbCh7XHJcbiAgICAgIC8vIEdldCB0aGUgYGNyZWF0ZWAsIGB2YWxpZGF0ZWAsIGFuZCBgZGVzdHJveWAgZnVuY3Rpb25zXHJcbiAgICAgIC4uLl9mYWN0b3J5KHBvb2xPcHRpb25zKSxcclxuICAgICAgbWluOiBwb29sT3B0aW9ucy5taW5Xb3JrZXJzLFxyXG4gICAgICBtYXg6IHBvb2xPcHRpb25zLm1heFdvcmtlcnMsXHJcbiAgICAgIGFjcXVpcmVUaW1lb3V0TWlsbGlzOiBwb29sT3B0aW9ucy5hY3F1aXJlVGltZW91dCxcclxuICAgICAgY3JlYXRlVGltZW91dE1pbGxpczogcG9vbE9wdGlvbnMuY3JlYXRlVGltZW91dCxcclxuICAgICAgZGVzdHJveVRpbWVvdXRNaWxsaXM6IHBvb2xPcHRpb25zLmRlc3Ryb3lUaW1lb3V0LFxyXG4gICAgICBpZGxlVGltZW91dE1pbGxpczogcG9vbE9wdGlvbnMuaWRsZVRpbWVvdXQsXHJcbiAgICAgIGNyZWF0ZVJldHJ5SW50ZXJ2YWxNaWxsaXM6IHBvb2xPcHRpb25zLmNyZWF0ZVJldHJ5SW50ZXJ2YWwsXHJcbiAgICAgIHJlYXBJbnRlcnZhbE1pbGxpczogcG9vbE9wdGlvbnMucmVhcGVySW50ZXJ2YWwsXHJcbiAgICAgIHByb3BhZ2F0ZUNyZWF0ZUVycm9yOiBmYWxzZVxyXG4gICAgfSk7XHJcblxyXG4gICAgLy8gU2V0IGV2ZW50c1xyXG4gICAgcG9vbC5vbigncmVsZWFzZScsIGFzeW5jIChyZXNvdXJjZSkgPT4ge1xyXG4gICAgICAvLyBDbGVhciBwYWdlXHJcbiAgICAgIGNvbnN0IGNsZWFyU3RhdHVzID0gYXdhaXQgY2xlYXJQYWdlKHJlc291cmNlLCBmYWxzZSk7XHJcbiAgICAgIGxvZyhcclxuICAgICAgICA0LFxyXG4gICAgICAgIGBbcG9vbF0gUG9vbCByZXNvdXJjZSBbJHtyZXNvdXJjZS5pZH1dIC0gUmVsZWFzaW5nIGEgd29ya2VyLiBDbGVhciBwYWdlIHN0YXR1czogJHtjbGVhclN0YXR1c30uYFxyXG4gICAgICApO1xyXG4gICAgfSk7XHJcblxyXG4gICAgcG9vbC5vbignZGVzdHJveVN1Y2Nlc3MnLCAoX2V2ZW50SWQsIHJlc291cmNlKSA9PiB7XHJcbiAgICAgIGxvZyhcclxuICAgICAgICA0LFxyXG4gICAgICAgIGBbcG9vbF0gUG9vbCByZXNvdXJjZSBbJHtyZXNvdXJjZS5pZH1dIC0gRGVzdHJveWVkIGEgd29ya2VyIHN1Y2Nlc3NmdWxseS5gXHJcbiAgICAgICk7XHJcbiAgICAgIHJlc291cmNlLnBhZ2UgPSBudWxsO1xyXG4gICAgfSk7XHJcblxyXG4gICAgY29uc3QgaW5pdGlhbFJlc291cmNlcyA9IFtdO1xyXG4gICAgLy8gQ3JlYXRlIGFuIGluaXRpYWwgbnVtYmVyIG9mIHJlc291cmNlc1xyXG4gICAgZm9yIChsZXQgaSA9IDA7IGkgPCBwb29sT3B0aW9ucy5taW5Xb3JrZXJzOyBpKyspIHtcclxuICAgICAgdHJ5IHtcclxuICAgICAgICBjb25zdCByZXNvdXJjZSA9IGF3YWl0IHBvb2wuYWNxdWlyZSgpLnByb21pc2U7XHJcbiAgICAgICAgaW5pdGlhbFJlc291cmNlcy5wdXNoKHJlc291cmNlKTtcclxuICAgICAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICAgICBsb2dXaXRoU3RhY2soMiwgZXJyb3IsICdbcG9vbF0gQ291bGQgbm90IGNyZWF0ZSBhbiBpbml0aWFsIHJlc291cmNlLicpO1xyXG4gICAgICB9XHJcbiAgICB9XHJcblxyXG4gICAgLy8gUmVsZWFzZSB0aGUgaW5pdGlhbCBudW1iZXIgb2YgcmVzb3VyY2VzIGJhY2sgdG8gdGhlIHBvb2xcclxuICAgIGluaXRpYWxSZXNvdXJjZXMuZm9yRWFjaCgocmVzb3VyY2UpID0+IHtcclxuICAgICAgcG9vbC5yZWxlYXNlKHJlc291cmNlKTtcclxuICAgIH0pO1xyXG5cclxuICAgIGxvZyhcclxuICAgICAgMyxcclxuICAgICAgYFtwb29sXSBUaGUgcG9vbCBpcyByZWFkeSR7aW5pdGlhbFJlc291cmNlcy5sZW5ndGggPyBgIHdpdGggJHtpbml0aWFsUmVzb3VyY2VzLmxlbmd0aH0gaW5pdGlhbCByZXNvdXJjZXMgd2FpdGluZy5gIDogJy4nfWBcclxuICAgICk7XHJcbiAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcihcclxuICAgICAgJ1twb29sXSBDb3VsZCBub3QgY29uZmlndXJlIGFuZCBjcmVhdGUgdGhlIHBvb2wgb2Ygd29ya2Vycy4nLFxyXG4gICAgICA1MDBcclxuICAgICkuc2V0RXJyb3IoZXJyb3IpO1xyXG4gIH1cclxufVxyXG5cclxuLyoqXHJcbiAqIEtpbGxzIGFsbCB3b3JrZXJzIGluIHRoZSBwb29sLCBkZXN0cm95cyB0aGUgcG9vbCwgYW5kIGNsb3NlcyB0aGUgYnJvd3NlclxyXG4gKiBpbnN0YW5jZS5cclxuICpcclxuICogQGFzeW5jXHJcbiAqIEBmdW5jdGlvbiBraWxsUG9vbFxyXG4gKlxyXG4gKiBAcmV0dXJucyB7UHJvbWlzZTx2b2lkPn0gQSBQcm9taXNlIHRoYXQgcmVzb2x2ZXMgYWZ0ZXIgdGhlIHdvcmtlcnMgYXJlXHJcbiAqIGtpbGxlZCwgdGhlIHBvb2wgaXMgZGVzdHJveWVkLCBhbmQgdGhlIGJyb3dzZXIgaXMgY2xvc2VkLlxyXG4gKi9cclxuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIGtpbGxQb29sKCkge1xyXG4gIGxvZygzLCAnW3Bvb2xdIEtpbGxpbmcgcG9vbCB3aXRoIGFsbCB3b3JrZXJzIGFuZCBjbG9zaW5nIGJyb3dzZXIuJyk7XHJcblxyXG4gIC8vIElmIHN0aWxsIGFsaXZlLCBkZXN0cm95IHRoZSBwb29sIG9mIHBhZ2VzIGJlZm9yZSBjbG9zaW5nIGEgYnJvd3NlclxyXG4gIGlmIChwb29sKSB7XHJcbiAgICAvLyBGcmVlIHVwIG5vdCByZWxlYXNlZCB3b3JrZXJzXHJcbiAgICBmb3IgKGNvbnN0IHdvcmtlciBvZiBwb29sLnVzZWQpIHtcclxuICAgICAgcG9vbC5yZWxlYXNlKHdvcmtlci5yZXNvdXJjZSk7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gRGVzdHJveSB0aGUgcG9vbCBpZiBpdCBpcyBzdGlsbCBhdmFpbGFibGVcclxuICAgIGlmICghcG9vbC5kZXN0cm95ZWQpIHtcclxuICAgICAgYXdhaXQgcG9vbC5kZXN0cm95KCk7XHJcbiAgICAgIGxvZyg0LCAnW3Bvb2xdIERlc3Ryb3llZCB0aGUgcG9vbCBvZiByZXNvdXJjZXMuJyk7XHJcbiAgICB9XHJcbiAgICBwb29sID0gbnVsbDtcclxuICB9XHJcblxyXG4gIC8vIENsb3NlIHRoZSBicm93c2VyIGluc3RhbmNlXHJcbiAgYXdhaXQgY2xvc2VCcm93c2VyKCk7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBQcm9jZXNzZXMgdGhlIGV4cG9ydCB3b3JrIHVzaW5nIGEgd29ya2VyIGZyb20gdGhlIHBvb2wuIEFjcXVpcmVzIGEgd29ya2VyXHJcbiAqIGhhbmRsZSBmcm9tIHRoZSBwb29sLCBwZXJmb3JtcyB0aGUgZXhwb3J0IHVzaW5nIHB1cHBldGVlciwgYW5kIHJlbGVhc2VzXHJcbiAqIHRoZSB3b3JrZXIgaGFuZGxlIGJhY2sgdG8gdGhlIHBvb2wuXHJcbiAqXHJcbiAqIEBhc3luY1xyXG4gKiBAZnVuY3Rpb24gcG9zdFdvcmtcclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IG9wdGlvbnMgLSBUaGUgYG9wdGlvbnNgIG9iamVjdCBjb250YWluaW5nIGNvbXBsZXRlIHNldFxyXG4gKiBvZiBvcHRpb25zLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7UHJvbWlzZTxPYmplY3Q+fSBBIFByb21pc2UgdGhhdCByZXNvbHZlcyB0byB0aGUgZXhwb3J0IHJlc3VsdFxyXG4gKiBhbmQgb3B0aW9ucy5cclxuICpcclxuICogQHRocm93cyB7RXhwb3J0RXJyb3J9IFRocm93cyBhbiBgRXhwb3J0RXJyb3JgIGlmIGFuIGVycm9yIG9jY3VycyBkdXJpbmdcclxuICogdGhlIGV4cG9ydCBwcm9jZXNzLlxyXG4gKi9cclxuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIHBvc3RXb3JrKG9wdGlvbnMpIHtcclxuICBsZXQgd29ya2VySGFuZGxlO1xyXG5cclxuICB0cnkge1xyXG4gICAgbG9nKDQsICdbcG9vbF0gV29yayByZWNlaXZlZCwgc3RhcnRpbmcgdG8gcHJvY2Vzcy4nKTtcclxuXHJcbiAgICAvLyBBbiBleHBvcnQgYXR0ZW1wdCBjb3VudGVkXHJcbiAgICArK3Bvb2xTdGF0cy5leHBvcnRzQXR0ZW1wdGVkO1xyXG5cclxuICAgIC8vIERpc3BsYXkgdGhlIHBvb2wgaW5mb3JtYXRpb24gaWYgbmVlZGVkXHJcbiAgICBpZiAoZ2V0T3B0aW9ucygpLnBvb2wuYmVuY2htYXJraW5nKSB7XHJcbiAgICAgIGdldFBvb2xJbmZvKCk7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gVGhyb3cgYW4gZXJyb3IgaW4gY2FzZSBvZiBsYWNraW5nIHRoZSBwb29sIGluc3RhbmNlXHJcbiAgICBpZiAoIXBvb2wpIHtcclxuICAgICAgdGhyb3cgbmV3IEV4cG9ydEVycm9yKFxyXG4gICAgICAgICdbcG9vbF0gV29yayByZWNlaXZlZCwgYnV0IHBvb2wgaGFzIG5vdCBiZWVuIHN0YXJ0ZWQuJyxcclxuICAgICAgICA1MDBcclxuICAgICAgKTtcclxuICAgIH1cclxuXHJcbiAgICAvLyBUaGUgYWNxdWlyZSBjb3VudGVyXHJcbiAgICBjb25zdCBhY3F1aXJlQ291bnRlciA9IG1lYXN1cmVUaW1lKCk7XHJcblxyXG4gICAgLy8gVHJ5IHRvIGFjcXVpcmUgdGhlIHdvcmtlciBhbG9uZyB3aXRoIHRoZSBpZCwgd29ya3MgY291bnQgYW5kIHBhZ2VcclxuICAgIHRyeSB7XHJcbiAgICAgIGxvZyg0LCAnW3Bvb2xdIEFjcXVpcmluZyBhIHdvcmtlciBoYW5kbGUuJyk7XHJcblxyXG4gICAgICAvLyBBY3F1aXJlIGEgcG9vbCByZXNvdXJjZVxyXG4gICAgICB3b3JrZXJIYW5kbGUgPSBhd2FpdCBwb29sLmFjcXVpcmUoKS5wcm9taXNlO1xyXG5cclxuICAgICAgLy8gQ2hlY2sgdGhlIHBhZ2UgYWNxdWlyZSB0aW1lXHJcbiAgICAgIGlmIChvcHRpb25zLnNlcnZlci5iZW5jaG1hcmtpbmcpIHtcclxuICAgICAgICBsb2coXHJcbiAgICAgICAgICA1LFxyXG4gICAgICAgICAgb3B0aW9ucy5fcmVxdWVzdElkXHJcbiAgICAgICAgICAgID8gYFtiZW5jaG1hcmtdIFJlcXVlc3QgWyR7b3B0aW9ucy5fcmVxdWVzdElkfV0gLSBgXHJcbiAgICAgICAgICAgIDogJ1tiZW5jaG1hcmtdICcsXHJcbiAgICAgICAgICBgQWNxdWlyaW5nIGEgd29ya2VyIGhhbmRsZSB0b29rICR7YWNxdWlyZUNvdW50ZXIoKX1tcy5gXHJcbiAgICAgICAgKTtcclxuICAgICAgfVxyXG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICAgdGhyb3cgbmV3IEV4cG9ydEVycm9yKFxyXG4gICAgICAgICdbcG9vbF0gJyArXHJcbiAgICAgICAgICAob3B0aW9ucy5fcmVxdWVzdElkID8gYFJlcXVlc3QgWyR7b3B0aW9ucy5fcmVxdWVzdElkfV0gLSBgIDogJycpICtcclxuICAgICAgICAgIGBFcnJvciBlbmNvdW50ZXJlZCB3aGVuIGFjcXVpcmluZyBhbiBhdmFpbGFibGUgZW50cnk6ICR7YWNxdWlyZUNvdW50ZXIoKX1tcy5gLFxyXG4gICAgICAgIDQwMFxyXG4gICAgICApLnNldEVycm9yKGVycm9yKTtcclxuICAgIH1cclxuICAgIGxvZyg0LCAnW3Bvb2xdIEFjcXVpcmVkIGEgd29ya2VyIGhhbmRsZS4nKTtcclxuXHJcbiAgICBpZiAoIXdvcmtlckhhbmRsZS5wYWdlKSB7XHJcbiAgICAgIC8vIFNldCB0aGUgYHdvcmtMaW1pdGAgdG8gZXhjZWVkZWQgaW4gb3JkZXIgdG8gcmVjcmVhdGUgdGhlIHJlc291cmNlXHJcbiAgICAgIHdvcmtlckhhbmRsZS53b3JrQ291bnQgPSBvcHRpb25zLnBvb2wud29ya0xpbWl0ICsgMTtcclxuICAgICAgdGhyb3cgbmV3IEV4cG9ydEVycm9yKFxyXG4gICAgICAgICdbcG9vbF0gUmVzb2x2ZWQgd29ya2VyIHBhZ2UgaXMgaW52YWxpZDogdGhlIHBvb2wgc2V0dXAgaXMgd29ua3kuJyxcclxuICAgICAgICA0MDBcclxuICAgICAgKTtcclxuICAgIH1cclxuXHJcbiAgICAvLyBTYXZlIHRoZSBzdGFydCB0aW1lXHJcbiAgICBjb25zdCB3b3JrU3RhcnQgPSBnZXROZXdEYXRlVGltZSgpO1xyXG5cclxuICAgIGxvZyhcclxuICAgICAgNCxcclxuICAgICAgYFtwb29sXSBQb29sIHJlc291cmNlIFske3dvcmtlckhhbmRsZS5pZH1dIC0gU3RhcnRpbmcgd29yayBvbiB0aGlzIHBvb2wgZW50cnkuYFxyXG4gICAgKTtcclxuXHJcbiAgICAvLyBQZXJmb3JtIGFuIGV4cG9ydCBvbiBhIHB1cHBldGVlciBsZXZlbFxyXG4gICAgY29uc3QgZXhwb3J0Q291bnRlciA9IG1lYXN1cmVUaW1lKCk7XHJcbiAgICBjb25zdCByZXN1bHQgPSBhd2FpdCBwdXBwZXRlZXJFeHBvcnQod29ya2VySGFuZGxlLnBhZ2UsIG9wdGlvbnMpO1xyXG5cclxuICAgIC8vIENoZWNrIGlmIGl0J3MgYW4gZXJyb3JcclxuICAgIGlmIChyZXN1bHQgaW5zdGFuY2VvZiBFcnJvcikge1xyXG4gICAgICAvLyBOT1RFOlxyXG4gICAgICAvLyBJZiB0aGVyZSdzIGEgcmFzdGVyaXphdGlvbiB0aW1lb3V0LCB3ZSB3YW50IG5lZWQgdG8gZmx1c2ggdGhlIHBhZ2UuXHJcbiAgICAgIC8vIFRoaXMgaXMgYmVjYXVzZSB0aGUgcGFnZSBtYXkgYmUgaW4gYSBzdGF0ZSB3aGVyZSBpdCdzIHdhaXRpbmcgZm9yXHJcbiAgICAgIC8vIHRoZSBzY3JlZW5zaG90IHRvIGZpbmlzaCBldmVuIHRob3VnaCB0aGUgdGltZW91dCBoYXMgb2NjdXJlZC5cclxuICAgICAgLy8gV2hpY2ggb2YgY291cnNlIGNhdXNlcyBhIGxvdCBvZiBpc3N1ZXMgd2l0aCB0aGUgZXZlbnQgc3lzdGVtLFxyXG4gICAgICAvLyBhbmQgcGFnZSBjb25zaXN0ZW5jeS5cclxuICAgICAgLy9cclxuICAgICAgLy8gTk9URTpcclxuICAgICAgLy8gT25seSBwYWdlLnNjcmVlbnNob3Qgd2lsbCB0aHJvdyB0aGlzLCB0aW1lb3V0cyBmb3IgUERGJ3MgYXJlXHJcbiAgICAgIC8vIGhhbmRsZWQgYnkgdGhlIHBhZ2UucGRmIGZ1bmN0aW9uIGl0c2VsZi5cclxuICAgICAgLy9cclxuICAgICAgLy8gLi4ueWVzLCB0aGlzIGlzIHVnbHkuXHJcbiAgICAgIGlmIChyZXN1bHQubWVzc2FnZSA9PT0gJ1Jhc3Rlcml6YXRpb24gdGltZW91dCcpIHtcclxuICAgICAgICAvLyBTZXQgdGhlIGB3b3JrTGltaXRgIHRvIGV4Y2VlZGVkIGluIG9yZGVyIHRvIHJlY3JlYXRlIHRoZSByZXNvdXJjZVxyXG4gICAgICAgIHdvcmtlckhhbmRsZS53b3JrQ291bnQgPSBvcHRpb25zLnBvb2wud29ya0xpbWl0ICsgMTtcclxuICAgICAgICB3b3JrZXJIYW5kbGUucGFnZSA9IG51bGw7XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIGlmIChcclxuICAgICAgICByZXN1bHQubmFtZSA9PT0gJ1RpbWVvdXRFcnJvcicgfHxcclxuICAgICAgICByZXN1bHQubWVzc2FnZSA9PT0gJ1Jhc3Rlcml6YXRpb24gdGltZW91dCdcclxuICAgICAgKSB7XHJcbiAgICAgICAgdGhyb3cgbmV3IEV4cG9ydEVycm9yKFxyXG4gICAgICAgICAgJ1twb29sXSAnICtcclxuICAgICAgICAgICAgKG9wdGlvbnMuX3JlcXVlc3RJZCA/IGBSZXF1ZXN0IFske29wdGlvbnMuX3JlcXVlc3RJZH1dIC0gYCA6ICcnKSArXHJcbiAgICAgICAgICAgICdSYXN0ZXJpemF0aW9uIHRpbWVvdXQ6IHlvdXIgY2hhcnQgbWF5IGJlIHRvbyBjb21wbGV4IG9yIGxhcmdlLCBhbmQgZmFpbGVkIHRvIHJlbmRlciB3aXRoaW4gdGhlIGFsbG90dGVkIHRpbWUuJ1xyXG4gICAgICAgICkuc2V0RXJyb3IocmVzdWx0KTtcclxuICAgICAgfSBlbHNlIHtcclxuICAgICAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoXHJcbiAgICAgICAgICAnW3Bvb2xdICcgK1xyXG4gICAgICAgICAgICAob3B0aW9ucy5fcmVxdWVzdElkID8gYFJlcXVlc3QgWyR7b3B0aW9ucy5fcmVxdWVzdElkfV0gLSBgIDogJycpICtcclxuICAgICAgICAgICAgYEVycm9yIGVuY291bnRlcmVkIGR1cmluZyBleHBvcnQ6ICR7ZXhwb3J0Q291bnRlcigpfW1zLmBcclxuICAgICAgICApLnNldEVycm9yKHJlc3VsdCk7XHJcbiAgICAgIH1cclxuICAgIH1cclxuXHJcbiAgICAvLyBDaGVjayB0aGUgUHVwcGV0ZWVyIGV4cG9ydCB0aW1lXHJcbiAgICBpZiAob3B0aW9ucy5zZXJ2ZXIuYmVuY2htYXJraW5nKSB7XHJcbiAgICAgIGxvZyhcclxuICAgICAgICA1LFxyXG4gICAgICAgIG9wdGlvbnMuX3JlcXVlc3RJZFxyXG4gICAgICAgICAgPyBgW2JlbmNobWFya10gUmVxdWVzdCBbJHtvcHRpb25zLl9yZXF1ZXN0SWR9XSAtIGBcclxuICAgICAgICAgIDogJ1tiZW5jaG1hcmtdICcsXHJcbiAgICAgICAgYEV4cG9ydGluZyBhIGNoYXJ0IHN1Y2Vzc2Z1bGx5IHRvb2sgJHtleHBvcnRDb3VudGVyKCl9bXMuYFxyXG4gICAgICApO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIFJlbGVhc2UgdGhlIHJlc291cmNlIGJhY2sgdG8gdGhlIHBvb2xcclxuICAgIHBvb2wucmVsZWFzZSh3b3JrZXJIYW5kbGUpO1xyXG5cclxuICAgIC8vIFVzZWQgZm9yIHN0YXRpc3RpY3MgaW4gYXZlcmFnZVRpbWUgYW5kIHByb2Nlc3NlZFdvcmtDb3VudCwgd2hpY2hcclxuICAgIC8vIGluIHR1cm4gaXMgdXNlZCBieSB0aGUgL2hlYWx0aCByb3V0ZS5cclxuICAgIGNvbnN0IHdvcmtFbmQgPSBnZXROZXdEYXRlVGltZSgpO1xyXG4gICAgY29uc3QgZXhwb3J0VGltZSA9IHdvcmtFbmQgLSB3b3JrU3RhcnQ7XHJcblxyXG4gICAgcG9vbFN0YXRzLnRpbWVTcGVudCArPSBleHBvcnRUaW1lO1xyXG4gICAgcG9vbFN0YXRzLnRpbWVTcGVudEF2ZXJhZ2UgPVxyXG4gICAgICBwb29sU3RhdHMudGltZVNwZW50IC8gKytwb29sU3RhdHMuZXhwb3J0c1BlcmZvcm1lZDtcclxuXHJcbiAgICBsb2coNCwgYFtwb29sXSBXb3JrIGNvbXBsZXRlZCBpbiAke2V4cG9ydFRpbWV9bXMuYCk7XHJcblxyXG4gICAgLy8gT3RoZXJ3aXNlIHJldHVybiB0aGUgcmVzdWx0XHJcbiAgICByZXR1cm4ge1xyXG4gICAgICByZXN1bHQsXHJcbiAgICAgIG9wdGlvbnNcclxuICAgIH07XHJcbiAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICsrcG9vbFN0YXRzLmV4cG9ydHNEcm9wcGVkO1xyXG5cclxuICAgIGlmICh3b3JrZXJIYW5kbGUpIHtcclxuICAgICAgcG9vbC5yZWxlYXNlKHdvcmtlckhhbmRsZSk7XHJcbiAgICB9XHJcblxyXG4gICAgdGhyb3cgZXJyb3I7XHJcbiAgfVxyXG59XHJcblxyXG4vKipcclxuICogUmV0cmlldmVzIHRoZSBjdXJyZW50IHBvb2wgaW5zdGFuY2UuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBnZXRQb29sXHJcbiAqXHJcbiAqIEByZXR1cm5zIHsoT2JqZWN0fG51bGwpfSBUaGUgY3VycmVudCBwb29sIGluc3RhbmNlIGlmIGluaXRpYWxpemVkLCBvciBudWxsXHJcbiAqIGlmIHRoZSBwb29sIGhhcyBub3QgYmVlbiBjcmVhdGVkLlxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIGdldFBvb2woKSB7XHJcbiAgcmV0dXJuIHBvb2w7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBHZXRzIHRoZSBzdGF0aXN0aWMgb2YgYSBwb29sIGluc3RhY2UgYWJvdXQgZXhwb3J0cy5cclxuICpcclxuICogQGZ1bmN0aW9uIGdldFBvb2xTdGF0c1xyXG4gKlxyXG4gKiBAcmV0dXJucyB7T2JqZWN0fSBUaGUgY3VycmVudCBwb29sIHN0YXRpc3RpY3MuXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gZ2V0UG9vbFN0YXRzKCkge1xyXG4gIHJldHVybiBwb29sU3RhdHM7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBSZXRyaWV2ZXMgcG9vbCBpbmZvcm1hdGlvbiBpbiBKU09OIGZvcm1hdCwgaW5jbHVkaW5nIG1pbmltdW0gYW5kIG1heGltdW1cclxuICogd29ya2VycywgYXZhaWxhYmxlIHdvcmtlcnMsIHdvcmtlcnMgaW4gdXNlLCBhbmQgcGVuZGluZyBhY3F1aXJlIHJlcXVlc3RzLlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gZ2V0UG9vbEluZm9KU09OXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtPYmplY3R9IFBvb2wgaW5mb3JtYXRpb24gaW4gSlNPTiBmb3JtYXQuXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gZ2V0UG9vbEluZm9KU09OKCkge1xyXG4gIHJldHVybiB7XHJcbiAgICBtaW46IHBvb2wubWluLFxyXG4gICAgbWF4OiBwb29sLm1heCxcclxuICAgIHVzZWQ6IHBvb2wubnVtVXNlZCgpLFxyXG4gICAgYXZhaWxhYmxlOiBwb29sLm51bUZyZWUoKSxcclxuICAgIGFsbENyZWF0ZWQ6IHBvb2wubnVtVXNlZCgpICsgcG9vbC5udW1GcmVlKCksXHJcbiAgICBwZW5kaW5nQWNxdWlyZXM6IHBvb2wubnVtUGVuZGluZ0FjcXVpcmVzKCksXHJcbiAgICBwZW5kaW5nQ3JlYXRlczogcG9vbC5udW1QZW5kaW5nQ3JlYXRlcygpLFxyXG4gICAgcGVuZGluZ1ZhbGlkYXRpb25zOiBwb29sLm51bVBlbmRpbmdWYWxpZGF0aW9ucygpLFxyXG4gICAgcGVuZGluZ0Rlc3Ryb3lzOiBwb29sLnBlbmRpbmdEZXN0cm95cy5sZW5ndGgsXHJcbiAgICBhYnNvbHV0ZUFsbDpcclxuICAgICAgcG9vbC5udW1Vc2VkKCkgK1xyXG4gICAgICBwb29sLm51bUZyZWUoKSArXHJcbiAgICAgIHBvb2wubnVtUGVuZGluZ0FjcXVpcmVzKCkgK1xyXG4gICAgICBwb29sLm51bVBlbmRpbmdDcmVhdGVzKCkgK1xyXG4gICAgICBwb29sLm51bVBlbmRpbmdWYWxpZGF0aW9ucygpICtcclxuICAgICAgcG9vbC5wZW5kaW5nRGVzdHJveXMubGVuZ3RoXHJcbiAgfTtcclxufVxyXG5cclxuLyoqXHJcbiAqIExvZ3MgaW5mb3JtYXRpb24gYWJvdXQgdGhlIGN1cnJlbnQgc3RhdGUgb2YgdGhlIHBvb2wsIGluY2x1ZGluZyB0aGUgbWluaW11bVxyXG4gKiBhbmQgbWF4aW11bSB3b3JrZXJzLCBhdmFpbGFibGUgd29ya2Vycywgd29ya2VycyBpbiB1c2UsIGFuZCBwZW5kaW5nIGFjcXVpcmVcclxuICogcmVxdWVzdHMuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBnZXRQb29sSW5mb1xyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIGdldFBvb2xJbmZvKCkge1xyXG4gIGNvbnN0IHtcclxuICAgIG1pbixcclxuICAgIG1heCxcclxuICAgIHVzZWQsXHJcbiAgICBhdmFpbGFibGUsXHJcbiAgICBhbGxDcmVhdGVkLFxyXG4gICAgcGVuZGluZ0FjcXVpcmVzLFxyXG4gICAgcGVuZGluZ0NyZWF0ZXMsXHJcbiAgICBwZW5kaW5nVmFsaWRhdGlvbnMsXHJcbiAgICBwZW5kaW5nRGVzdHJveXMsXHJcbiAgICBhYnNvbHV0ZUFsbFxyXG4gIH0gPSBnZXRQb29sSW5mb0pTT04oKTtcclxuXHJcbiAgbG9nKDUsIGBbcG9vbF0gVGhlIG1pbmltdW0gbnVtYmVyIG9mIHJlc291cmNlcyBhbGxvd2VkIGJ5IHBvb2w6ICR7bWlufS5gKTtcclxuICBsb2coNSwgYFtwb29sXSBUaGUgbWF4aW11bSBudW1iZXIgb2YgcmVzb3VyY2VzIGFsbG93ZWQgYnkgcG9vbDogJHttYXh9LmApO1xyXG4gIGxvZyg1LCBgW3Bvb2xdIFRoZSBudW1iZXIgb2YgdXNlZCByZXNvdXJjZXM6ICR7dXNlZH0uYCk7XHJcbiAgbG9nKDUsIGBbcG9vbF0gVGhlIG51bWJlciBvZiBmcmVlIHJlc291cmNlczogJHthdmFpbGFibGV9LmApO1xyXG4gIGxvZyhcclxuICAgIDUsXHJcbiAgICBgW3Bvb2xdIFRoZSBudW1iZXIgb2YgYWxsIGNyZWF0ZWQgKHVzZWQgYW5kIGZyZWUpIHJlc291cmNlczogJHthbGxDcmVhdGVkfS5gXHJcbiAgKTtcclxuICBsb2coXHJcbiAgICA1LFxyXG4gICAgYFtwb29sXSBUaGUgbnVtYmVyIG9mIHJlc291cmNlcyB3YWl0aW5nIHRvIGJlIGFjcXVpcmVkOiAke3BlbmRpbmdBY3F1aXJlc30uYFxyXG4gICk7XHJcbiAgbG9nKFxyXG4gICAgNSxcclxuICAgIGBbcG9vbF0gVGhlIG51bWJlciBvZiByZXNvdXJjZXMgd2FpdGluZyB0byBiZSBjcmVhdGVkOiAke3BlbmRpbmdDcmVhdGVzfS5gXHJcbiAgKTtcclxuICBsb2coXHJcbiAgICA1LFxyXG4gICAgYFtwb29sXSBUaGUgbnVtYmVyIG9mIHJlc291cmNlcyB3YWl0aW5nIHRvIGJlIHZhbGlkYXRlZDogJHtwZW5kaW5nVmFsaWRhdGlvbnN9LmBcclxuICApO1xyXG4gIGxvZyhcclxuICAgIDUsXHJcbiAgICBgW3Bvb2xdIFRoZSBudW1iZXIgb2YgcmVzb3VyY2VzIHdhaXRpbmcgdG8gYmUgZGVzdHJveWVkOiAke3BlbmRpbmdEZXN0cm95c30uYFxyXG4gICk7XHJcbiAgbG9nKDUsIGBbcG9vbF0gVGhlIG51bWJlciBvZiBhbGwgcmVzb3VyY2VzOiAke2Fic29sdXRlQWxsfS5gKTtcclxufVxyXG5cclxuLyoqXHJcbiAqIEZhY3RvcnkgZnVuY3Rpb24gdGhhdCByZXR1cm5zIGFuIG9iamVjdCB3aXRoIGBjcmVhdGVgLCBgdmFsaWRhdGVgLFxyXG4gKiBhbmQgYGRlc3Ryb3lgIGZ1bmN0aW9ucyBmb3IgdGhlIHBvb2wgaW5zdGFuY2UuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBfZmFjdG9yeVxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gcG9vbE9wdGlvbnMgLSBPYmplY3QgY29udGFpbmluZyBgcG9vbGAgb3B0aW9ucy5cclxuICovXHJcbmZ1bmN0aW9uIF9mYWN0b3J5KHBvb2xPcHRpb25zKSB7XHJcbiAgcmV0dXJuIHtcclxuICAgIC8qKlxyXG4gICAgICogQ3JlYXRlcyBhIG5ldyB3b3JrZXIgcGFnZSBmb3IgdGhlIGV4cG9ydCBwb29sLlxyXG4gICAgICpcclxuICAgICAqIEBhc3luY1xyXG4gICAgICogQGZ1bmN0aW9uIGNyZWF0ZVxyXG4gICAgICpcclxuICAgICAqIEByZXR1cm5zIHtQcm9taXNlPE9iamVjdD59IEEgUHJvbWlzZSB0aGF0IHJlc29sdmVzIHRvIGFuIG9iamVjdFxyXG4gICAgICogY29udGFpbmluZyB0aGUgd29ya2VyIElELCBhIHJlZmVyZW5jZSB0byB0aGUgYnJvd3NlciBwYWdlLCBhbmQgaW5pdGlhbFxyXG4gICAgICogd29yayBjb3VudC5cclxuICAgICAqXHJcbiAgICAgKiBAdGhyb3dzIHtFeHBvcnRFcnJvcn0gVGhyb3dzIGFuIGBFeHBvcnRFcnJvcmAgaWYgdGhlcmUgaXMgYW4gZXJyb3IgZHVyaW5nXHJcbiAgICAgKiB0aGUgY3JlYXRpb24gb2YgdGhlIG5ldyBwYWdlLlxyXG4gICAgICovXHJcbiAgICBjcmVhdGU6IGFzeW5jICgpID0+IHtcclxuICAgICAgLy8gSW5pdCB0aGUgcmVzb3VyY2Ugd2l0aCB1bmlxdWUgaWQgYW5kIHdvcmsgY291bnRcclxuICAgICAgY29uc3QgcG9vbFJlc291cmNlID0ge1xyXG4gICAgICAgIGlkOiB1dWlkKCksXHJcbiAgICAgICAgLy8gVHJ5IHRvIGRpc3RyaWJ1dGUgdGhlIGluaXRpYWwgd29yayBjb3VudFxyXG4gICAgICAgIHdvcmtDb3VudDogTWF0aC5yb3VuZChNYXRoLnJhbmRvbSgpICogKHBvb2xPcHRpb25zLndvcmtMaW1pdCAvIDIpKVxyXG4gICAgICB9O1xyXG5cclxuICAgICAgdHJ5IHtcclxuICAgICAgICAvLyBTdGFydCBtZWFzdXJpbmcgYSBwYWdlIGNyZWF0aW9uIHRpbWVcclxuICAgICAgICBjb25zdCBzdGFydERhdGUgPSBnZXROZXdEYXRlVGltZSgpO1xyXG5cclxuICAgICAgICAvLyBDcmVhdGUgYSBuZXcgcGFnZVxyXG4gICAgICAgIGF3YWl0IG5ld1BhZ2UocG9vbFJlc291cmNlKTtcclxuXHJcbiAgICAgICAgLy8gTWVhc3VyZSB0aGUgdGltZSBvZiBmdWxsIGNyZWF0aW9uIGFuZCBjb25maWd1cmF0aW9uIG9mIGEgcGFnZVxyXG4gICAgICAgIGxvZyhcclxuICAgICAgICAgIDMsXHJcbiAgICAgICAgICBgW3Bvb2xdIFBvb2wgcmVzb3VyY2UgWyR7cG9vbFJlc291cmNlLmlkfV0gLSBTdWNjZXNzZnVsbHkgY3JlYXRlZCBhIHdvcmtlciwgdG9vayAke1xyXG4gICAgICAgICAgICBnZXROZXdEYXRlVGltZSgpIC0gc3RhcnREYXRlXHJcbiAgICAgICAgICB9bXMuYFxyXG4gICAgICAgICk7XHJcblxyXG4gICAgICAgIC8vIFJldHVybiByZWFkeSBwb29sIHJlc291cmNlXHJcbiAgICAgICAgcmV0dXJuIHBvb2xSZXNvdXJjZTtcclxuICAgICAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICAgICBsb2coXHJcbiAgICAgICAgICAzLFxyXG4gICAgICAgICAgYFtwb29sXSBQb29sIHJlc291cmNlIFske3Bvb2xSZXNvdXJjZS5pZH1dIC0gRXJyb3IgZW5jb3VudGVyZWQgd2hlbiBjcmVhdGluZyBhIG5ldyBwYWdlLmBcclxuICAgICAgICApO1xyXG4gICAgICAgIHRocm93IGVycm9yO1xyXG4gICAgICB9XHJcbiAgICB9LFxyXG5cclxuICAgIC8qKlxyXG4gICAgICogVmFsaWRhdGVzIGEgd29ya2VyIHBhZ2UgaW4gdGhlIGV4cG9ydCBwb29sLCBjaGVja2luZyBpZiBpdCBoYXMgZXhjZWVkZWRcclxuICAgICAqIHRoZSB3b3JrIGxpbWl0LlxyXG4gICAgICpcclxuICAgICAqIEBhc3luY1xyXG4gICAgICogQGZ1bmN0aW9uIHZhbGlkYXRlXHJcbiAgICAgKlxyXG4gICAgICogQHBhcmFtIHtPYmplY3R9IHBvb2xSZXNvdXJjZSAtIFRoZSBoYW5kbGUgdG8gdGhlIHdvcmtlciwgY29udGFpbmluZ1xyXG4gICAgICogdGhlIHdvcmtlcidzIElELCBhIHJlZmVyZW5jZSB0byB0aGUgYnJvd3NlciBwYWdlLCBhbmQgd29yayBjb3VudC5cclxuICAgICAqXHJcbiAgICAgKiBAcmV0dXJucyB7UHJvbWlzZTxib29sZWFuPn0gQSBQcm9taXNlIHRoYXQgcmVzb2x2ZXMgdG8gdHJ1ZSBpZiB0aGUgd29ya2VyXHJcbiAgICAgKiBpcyB2YWxpZCBhbmQgd2l0aGluIHRoZSB3b3JrIGxpbWl0OyBvdGhlcndpc2UsIHRvIGZhbHNlLlxyXG4gICAgICovXHJcbiAgICB2YWxpZGF0ZTogYXN5bmMgKHBvb2xSZXNvdXJjZSkgPT4ge1xyXG4gICAgICAvLyBOT1RFOlxyXG4gICAgICAvLyBJbiBjZXJ0YWluIGNhc2VzIGFjcXVpcmluZyB0aHJvd3MgYSBUYXJnZXRDbG9zZUVycm9yLCB3aGljaCBtYXlcclxuICAgICAgLy8gYmUgY2F1c2VkIGJ5IHR3byB0aGluZ3M6XHJcbiAgICAgIC8vIC0gVGhlIHBhZ2UgaXMgY2xvc2VkIGFuZCBhdHRlbXB0ZWQgdG8gYmUgcmV1c2VkLlxyXG4gICAgICAvLyAtIExvc3QgY29udGFjdCB3aXRoIHRoZSBicm93c2VyLlxyXG4gICAgICAvL1xyXG4gICAgICAvLyBXaGF0IHdlJ3JlIHNlZWluZyBpbiBsb2dzIGlzIHRoYXQgc3VjY2Vzc2l2ZSBleHBvcnRzIHR5cGljYWxseVxyXG4gICAgICAvLyBzdWNjZWVkcywgYW5kIHRoZSBzZXJ2ZXIgcmVjb3ZlcnMsIGluZGljYXRpbmcgdGhhdCBpdCdzIGxpa2VseVxyXG4gICAgICAvLyB0aGUgZmlyc3QgY2FzZS4gVGhpcyBpcyBhbiBhdHRlbXB0IGF0IGFsbGlldmF0aW5nIHRoZSBpc3N1ZSBieVxyXG4gICAgICAvLyBzaW1wbHkgbm90IHZhbGlkYXRpbmcgdGhlIHdvcmtlciBpZiB0aGUgcGFnZSBpcyBudWxsIG9yIGNsb3NlZC5cclxuICAgICAgLy9cclxuICAgICAgLy8gVGhlIGFjdHVhbCByZXN1bHQgZnJvbSB3aGVuIHRoaXMgaGFwcGVuZWQsIHdhcyB0aGF0IGEgd29ya2VyIHdvdWxkXHJcbiAgICAgIC8vIGJlIGNvbXBsZXRlbHkgbG9ja2VkLCBzdG9wcGluZyBpdCBmcm9tIGJlaW5nIGFjcXVpcmVkIHVudGlsXHJcbiAgICAgIC8vIGl0cyB3b3JrIGNvdW50IHJlYWNoZWQgdGhlIGxpbWl0LlxyXG5cclxuICAgICAgLy8gQ2hlY2sgaWYgdGhlIGBwYWdlYCBpcyB2YWxpZFxyXG4gICAgICBpZiAoIXBvb2xSZXNvdXJjZS5wYWdlKSB7XHJcbiAgICAgICAgbG9nKFxyXG4gICAgICAgICAgMyxcclxuICAgICAgICAgIGBbcG9vbF0gUG9vbCByZXNvdXJjZSBbJHtwb29sUmVzb3VyY2UuaWR9XSAtIFZhbGlkYXRpb24gZmFpbGVkIChubyB2YWxpZCBwYWdlIGlzIGZvdW5kKS5gXHJcbiAgICAgICAgKTtcclxuICAgICAgICByZXR1cm4gZmFsc2U7XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIC8vIENoZWNrIGlmIHRoZSBgcGFnZWAgaXMgY2xvc2VkXHJcbiAgICAgIGlmIChwb29sUmVzb3VyY2UucGFnZS5pc0Nsb3NlZCgpKSB7XHJcbiAgICAgICAgbG9nKFxyXG4gICAgICAgICAgMyxcclxuICAgICAgICAgIGBbcG9vbF0gUG9vbCByZXNvdXJjZSBbJHtwb29sUmVzb3VyY2UuaWR9XSAtIFZhbGlkYXRpb24gZmFpbGVkIChwYWdlIGlzIGNsb3NlZCBvciBpbnZhbGlkKS5gXHJcbiAgICAgICAgKTtcclxuICAgICAgICByZXR1cm4gZmFsc2U7XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIC8vIENoZWNrIGlmIHRoZSBgbWFpbkZyYW1lYCBpcyBkZXRhY2hlZFxyXG4gICAgICBpZiAocG9vbFJlc291cmNlLnBhZ2UubWFpbkZyYW1lKCkuZGV0YWNoZWQpIHtcclxuICAgICAgICBsb2coXHJcbiAgICAgICAgICAzLFxyXG4gICAgICAgICAgYFtwb29sXSBQb29sIHJlc291cmNlIFske3Bvb2xSZXNvdXJjZS5pZH1dIC0gVmFsaWRhdGlvbiBmYWlsZWQgKHBhZ2UncyBmcmFtZSBpcyBkZXRhY2hlZCkuYFxyXG4gICAgICAgICk7XHJcbiAgICAgICAgcmV0dXJuIGZhbHNlO1xyXG4gICAgICB9XHJcblxyXG4gICAgICAvLyBDaGVjayBpZiB0aGUgYHdvcmtMaW1pdGAgaXMgZXhjZWVkZWRcclxuICAgICAgaWYgKFxyXG4gICAgICAgIHBvb2xPcHRpb25zLndvcmtMaW1pdCAmJlxyXG4gICAgICAgICsrcG9vbFJlc291cmNlLndvcmtDb3VudCA+IHBvb2xPcHRpb25zLndvcmtMaW1pdFxyXG4gICAgICApIHtcclxuICAgICAgICBsb2coXHJcbiAgICAgICAgICAzLFxyXG4gICAgICAgICAgYFtwb29sXSBQb29sIHJlc291cmNlIFske3Bvb2xSZXNvdXJjZS5pZH1dIC0gVmFsaWRhdGlvbiBmYWlsZWQgKGV4Y2VlZGVkIHRoZSAke3Bvb2xPcHRpb25zLndvcmtMaW1pdH0gd29ya3MgcGVyIHJlc291cmNlIGxpbWl0KS5gXHJcbiAgICAgICAgKTtcclxuICAgICAgICByZXR1cm4gZmFsc2U7XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIC8vIFRoZSBgcG9vbFJlc291cmNlYCBpcyB2YWxpZGF0ZWRcclxuICAgICAgcmV0dXJuIHRydWU7XHJcbiAgICB9LFxyXG5cclxuICAgIC8qKlxyXG4gICAgICogRGVzdHJveXMgYSB3b3JrZXIgZW50cnkgaW4gdGhlIGV4cG9ydCBwb29sLCBjbG9zaW5nIGl0cyBhc3NvY2lhdGVkIHBhZ2UuXHJcbiAgICAgKlxyXG4gICAgICogQGFzeW5jXHJcbiAgICAgKiBAZnVuY3Rpb24gZGVzdHJveVxyXG4gICAgICpcclxuICAgICAqIEBwYXJhbSB7T2JqZWN0fSBwb29sUmVzb3VyY2UgLSBUaGUgaGFuZGxlIHRvIHRoZSB3b3JrZXIsIGNvbnRhaW5pbmdcclxuICAgICAqIHRoZSB3b3JrZXIncyBJRCwgYSByZWZlcmVuY2UgdG8gdGhlIGJyb3dzZXIgcGFnZSwgYW5kIHdvcmsgY291bnQuXHJcbiAgICAgKi9cclxuICAgIGRlc3Ryb3k6IGFzeW5jIChwb29sUmVzb3VyY2UpID0+IHtcclxuICAgICAgbG9nKFxyXG4gICAgICAgIDMsXHJcbiAgICAgICAgYFtwb29sXSBQb29sIHJlc291cmNlIFske3Bvb2xSZXNvdXJjZS5pZH1dIC0gRGVzdHJveWluZyBhIHdvcmtlci5gXHJcbiAgICAgICk7XHJcblxyXG4gICAgICBpZiAocG9vbFJlc291cmNlLnBhZ2UgJiYgIXBvb2xSZXNvdXJjZS5wYWdlLmlzQ2xvc2VkKCkpIHtcclxuICAgICAgICB0cnkge1xyXG4gICAgICAgICAgLy8gUmVtb3ZlIGFsbCBhdHRhY2hlZCBldmVudCBsaXN0ZW5lcnMgZnJvbSB0aGUgcmVzb3VyY2VcclxuICAgICAgICAgIHBvb2xSZXNvdXJjZS5wYWdlLnJlbW92ZUFsbExpc3RlbmVycygncGFnZWVycm9yJyk7XHJcbiAgICAgICAgICBwb29sUmVzb3VyY2UucGFnZS5yZW1vdmVBbGxMaXN0ZW5lcnMoJ2NvbnNvbGUnKTtcclxuICAgICAgICAgIHBvb2xSZXNvdXJjZS5wYWdlLnJlbW92ZUFsbExpc3RlbmVycygnZnJhbWVkZXRhY2hlZCcpO1xyXG5cclxuICAgICAgICAgIC8vIFdlIG5lZWQgdG8gd2FpdCBhcm91bmQgZm9yIHRoaXNcclxuICAgICAgICAgIGF3YWl0IHBvb2xSZXNvdXJjZS5wYWdlLmNsb3NlKCk7XHJcbiAgICAgICAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICAgICAgIGxvZyhcclxuICAgICAgICAgICAgMyxcclxuICAgICAgICAgICAgYFtwb29sXSBQb29sIHJlc291cmNlIFske3Bvb2xSZXNvdXJjZS5pZH1dIC0gUGFnZSBjb3VsZCBub3QgYmUgY2xvc2VkIHVwb24gZGVzdHJveWluZy5gXHJcbiAgICAgICAgICApO1xyXG4gICAgICAgICAgdGhyb3cgZXJyb3I7XHJcbiAgICAgICAgfVxyXG4gICAgICB9XHJcbiAgICB9XHJcbiAgfTtcclxufVxyXG5cclxuZXhwb3J0IGRlZmF1bHQge1xyXG4gIGluaXRQb29sLFxyXG4gIGtpbGxQb29sLFxyXG4gIHBvc3RXb3JrLFxyXG4gIGdldFBvb2wsXHJcbiAgZ2V0UG9vbFN0YXRzLFxyXG4gIGdldFBvb2xJbmZvLFxyXG4gIGdldFBvb2xJbmZvSlNPTlxyXG59O1xyXG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxyXG5cclxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXHJcblxyXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNSwgSGlnaHNvZnRcclxuXHJcbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cclxuXHJcbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxyXG5cclxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxyXG5cclxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cclxuXHJcbi8qKlxyXG4gKiBAb3ZlcnZpZXcgVXNlZCB0byBzYW5pdGl6ZSB0aGUgc3RyaW5ncyBjb21pbmcgZnJvbSB0aGUgZXhwb3J0aW5nIG1vZHVsZVxyXG4gKiB0byBwcmV2ZW50IFhTUyBhdHRhY2tzICh3aXRoIHRoZSBET01QdXJpZnkgbGlicmFyeSkuXHJcbiAqL1xyXG5cclxuaW1wb3J0IERPTVB1cmlmeSBmcm9tICdkb21wdXJpZnknO1xyXG5pbXBvcnQgeyBKU0RPTSB9IGZyb20gJ2pzZG9tJztcclxuXHJcbi8qKlxyXG4gKiBTYW5pdGl6ZXMgYSBnaXZlbiBIVE1MIHN0cmluZyBieSByZW1vdmluZyA8c2NyaXB0PiB0YWdzLiBUaGlzIGZ1bmN0aW9uIHVzZXNcclxuICogYSByZWd1bGFyIGV4cHJlc3Npb24gdG8gZmluZCBhbmQgcmVtb3ZlIGFsbCBvY2N1cnJlbmNlcyBvZiA8c2NyaXB0Pjwvc2NyaXB0PlxyXG4gKiB0YWdzIGFuZCBhbnkgY29udGVudCB3aXRoaW4gdGhlbS5cclxuICpcclxuICogQGZ1bmN0aW9uIHNhbml0aXplXHJcbiAqXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSBpbnB1dCAtIFRoZSBIVE1MIHN0cmluZyB0byBiZSBzYW5pdGl6ZWQuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtzdHJpbmd9IFRoZSBzYW5pdGl6ZWQgSFRNTCBzdHJpbmcuXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gc2FuaXRpemUoaW5wdXQpIHtcclxuICAvLyBHZXQgdGhlIHZpcnR1YWwgRE9NXHJcbiAgY29uc3Qgd2luZG93ID0gbmV3IEpTRE9NKCcnKS53aW5kb3c7XHJcblxyXG4gIC8vIENyZWF0ZSBhIHB1cmlmeWluZyBpbnN0YW5jZVxyXG4gIGNvbnN0IHB1cmlmeSA9IERPTVB1cmlmeSh3aW5kb3cpO1xyXG5cclxuICAvLyBSZXR1cm4gc2FuaXRpemVkIGlucHV0XHJcbiAgcmV0dXJuIHB1cmlmeS5zYW5pdGl6ZShpbnB1dCwgeyBBRERfVEFHUzogWydmb3JlaWduT2JqZWN0J10gfSk7XHJcbn1cclxuXHJcbmV4cG9ydCBkZWZhdWx0IHtcclxuICBzYW5pdGl6ZVxyXG59O1xyXG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxyXG5cclxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXHJcblxyXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNSwgSGlnaHNvZnRcclxuXHJcbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cclxuXHJcbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxyXG5cclxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxyXG5cclxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cclxuXHJcbi8qKlxyXG4gKiBAb3ZlcnZpZXcgVGhpcyBtb2R1bGUgcHJvdmlkZXMgZnVuY3Rpb25zIHRvIHByZXBhcmUgZm9yIHRoZSBleHBvcnRpbmcgY2hhcnRzXHJcbiAqIGludG8gdmFyaW91cyBpbWFnZSBvdXRwdXQgZm9ybWF0cyBzdWNoIGFzIEpQRUcsIFBORywgUERGLCBhbmQgU1ZHcy5cclxuICogSXQgc3VwcG9ydHMgc2luZ2xlIGFuZCBiYXRjaCBleHBvcnQgb3BlcmF0aW9ucyBhbmQgYWxsb3dzIGN1c3RvbWl6YXRpb25cclxuICogdGhyb3VnaCBvcHRpb25zIHBhc3NlZCBmcm9tIGNvbmZpZ3VyYXRpb25zIG9yIEFQSXMuXHJcbiAqL1xyXG5cclxuaW1wb3J0IHsgcmVhZEZpbGVTeW5jLCB3cml0ZUZpbGVTeW5jIH0gZnJvbSAnZnMnO1xyXG5cclxuaW1wb3J0IHsgZ2V0T3B0aW9ucywgbWVyZ2VPcHRpb25zLCBpc0FsbG93ZWRDb25maWcgfSBmcm9tICcuL2NvbmZpZy5qcyc7XHJcbmltcG9ydCB7IGxvZywgbG9nV2l0aFN0YWNrLCBsb2dab2RJc3N1ZXMgfSBmcm9tICcuL2xvZ2dlci5qcyc7XHJcbmltcG9ydCB7IGtpbGxQb29sLCBwb3N0V29yaywgZ2V0UG9vbFN0YXRzIH0gZnJvbSAnLi9wb29sLmpzJztcclxuaW1wb3J0IHsgc2FuaXRpemUgfSBmcm9tICcuL3Nhbml0aXplLmpzJztcclxuaW1wb3J0IHtcclxuICBmaXhPdXRmaWxlLFxyXG4gIGZpeFR5cGUsXHJcbiAgZ2V0QWJzb2x1dGVQYXRoLFxyXG4gIGdldEJhc2U2NCxcclxuICByb3VuZE51bWJlcixcclxuICB3cmFwQXJvdW5kXHJcbn0gZnJvbSAnLi91dGlscy5qcyc7XHJcbmltcG9ydCB7IHN0cmljdFZhbGlkYXRlLCB2YWxpZGF0ZU9wdGlvbiB9IGZyb20gJy4vdmFsaWRhdGlvbi5qcyc7XHJcblxyXG5pbXBvcnQgRXhwb3J0RXJyb3IgZnJvbSAnLi9lcnJvcnMvRXhwb3J0RXJyb3IuanMnO1xyXG5cclxuLy8gVGhlIGdsb2JhbCBmbGFnIGZvciB0aGUgY29kZSBleGVjdXRpb24gcGVybWlzc2lvblxyXG5sZXQgYWxsb3dDb2RlRXhlY3V0aW9uID0gZmFsc2U7XHJcblxyXG4vKipcclxuICogU3RhcnRzIGEgc2luZ2xlIGV4cG9ydCBwcm9jZXNzIGJhc2VkIG9uIHRoZSBzcGVjaWZpZWQgb3B0aW9ucyBhbmQgc2F2ZXNcclxuICogdGhlIGltYWdlIGluIHRoZSBwcm92aWRlZCBvdXRmaWxlLlxyXG4gKlxyXG4gKiBAYXN5bmNcclxuICogQGZ1bmN0aW9uIHNpbmdsZUV4cG9ydFxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gb3B0aW9ucyAtIFRoZSBgb3B0aW9uc2Agb2JqZWN0LCB3aGljaCBtYXkgYmUgYSBwYXJ0aWFsXHJcbiAqIG9yIGNvbXBsZXRlIHNldCBvZiBvcHRpb25zLiBJdCBtdXN0IGNvbnRhaW4gYXQgbGVhc3Qgb25lIG9mIHRoZSBmb2xsb3dpbmdcclxuICogcHJvcGVydGllczogYGluZmlsZWAsIGBpbnN0cmAsIGBvcHRpb25zYCwgb3IgYHN2Z2AgdG8gZ2VuZXJhdGUgYSB2YWxpZCBpbWFnZS5cclxuICpcclxuICogQHJldHVybnMge1Byb21pc2U8dm9pZD59IEEgUHJvbWlzZSB0aGF0IHJlc29sdmVzIG9uY2UgdGhlIHNpbmdsZSBleHBvcnRcclxuICogcHJvY2VzcyBpcyBjb21wbGV0ZWQuXHJcbiAqXHJcbiAqIEB0aHJvd3Mge0V4cG9ydEVycm9yfSBUaHJvd3MgYW4gYEV4cG9ydEVycm9yYCBpZiBhbiBlcnJvciBvY2N1cnMgZHVyaW5nXHJcbiAqIHRoZSBzaW5nbGUgZXhwb3J0IHByb2Nlc3MuXHJcbiAqL1xyXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gc2luZ2xlRXhwb3J0KG9wdGlvbnMpIHtcclxuICAvLyBDaGVjayBpZiB0aGUgZXhwb3J0IG1ha2VzIHNlbnNlXHJcbiAgaWYgKG9wdGlvbnMgJiYgb3B0aW9ucy5leHBvcnQpIHtcclxuICAgIC8vIFBlcmZvcm0gYW4gZXhwb3J0XHJcbiAgICBhd2FpdCBzdGFydEV4cG9ydChvcHRpb25zLCBhc3luYyAoZXJyb3IsIGRhdGEpID0+IHtcclxuICAgICAgLy8gRXhpdCBwcm9jZXNzIHdoZW4gZXJyb3IgZXhpc3RzXHJcbiAgICAgIGlmIChlcnJvcikge1xyXG4gICAgICAgIHRocm93IGVycm9yO1xyXG4gICAgICB9XHJcblxyXG4gICAgICAvLyBHZXQgdGhlIGBiNjRgLCBgb3V0ZmlsZWAsIGFuZCBgdHlwZWAgZm9yIGEgY2hhcnRcclxuICAgICAgY29uc3QgeyBiNjQsIG91dGZpbGUsIHR5cGUgfSA9IGRhdGEub3B0aW9ucy5leHBvcnQ7XHJcblxyXG4gICAgICAvLyBTYXZlIHRoZSByZXN1bHRcclxuICAgICAgdHJ5IHtcclxuICAgICAgICBpZiAoYjY0KSB7XHJcbiAgICAgICAgICAvLyBBcyBhIEJhc2U2NCBzdHJpbmcgdG8gYSB0eHQgZmlsZVxyXG4gICAgICAgICAgd3JpdGVGaWxlU3luYyhcclxuICAgICAgICAgICAgYCR7b3V0ZmlsZS5zcGxpdCgnLicpLnNoaWZ0KCkgfHwgJ2NoYXJ0J30udHh0YCxcclxuICAgICAgICAgICAgZ2V0QmFzZTY0KGRhdGEucmVzdWx0LCB0eXBlKVxyXG4gICAgICAgICAgKTtcclxuICAgICAgICB9IGVsc2Uge1xyXG4gICAgICAgICAgLy8gQXMgYSBjb3JyZWN0IGltYWdlIGZvcm1hdFxyXG4gICAgICAgICAgd3JpdGVGaWxlU3luYyhcclxuICAgICAgICAgICAgb3V0ZmlsZSB8fCBgY2hhcnQuJHt0eXBlfWAsXHJcbiAgICAgICAgICAgIHR5cGUgIT09ICdzdmcnID8gQnVmZmVyLmZyb20oZGF0YS5yZXN1bHQsICdiYXNlNjQnKSA6IGRhdGEucmVzdWx0XHJcbiAgICAgICAgICApO1xyXG4gICAgICAgIH1cclxuICAgICAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoXHJcbiAgICAgICAgICAnW2NoYXJ0XSBFcnJvciB3aGlsZSBzYXZpbmcgYSBjaGFydC4nLFxyXG4gICAgICAgICAgNTAwXHJcbiAgICAgICAgKS5zZXRFcnJvcihlcnJvcik7XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIC8vIEtpbGwgcG9vbCBhbmQgY2xvc2UgYnJvd3NlciBhZnRlciBmaW5pc2hpbmcgc2luZ2xlIGV4cG9ydFxyXG4gICAgICBhd2FpdCBraWxsUG9vbCgpO1xyXG4gICAgfSk7XHJcbiAgfSBlbHNlIHtcclxuICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcihcclxuICAgICAgJ1tjaGFydF0gTm8gZXhwZWN0ZWQgYGV4cG9ydGAgb3B0aW9ucyB3ZXJlIGZvdW5kLiBQbGVhc2UgcHJvdmlkZSBvbmUgb2YgdGhlIGZvbGxvd2luZyBvcHRpb25zOiBgaW5maWxlYCwgYGluc3RyYCwgYG9wdGlvbnNgLCBvciBgc3ZnYCB0byBnZW5lcmF0ZSBhIHZhbGlkIGltYWdlLicsXHJcbiAgICAgIDQwMFxyXG4gICAgKTtcclxuICB9XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBTdGFydHMgYSBiYXRjaCBleHBvcnQgcHJvY2VzcyBmb3IgbXVsdGlwbGUgY2hhcnRzIGJhc2VkIG9uIHRoZSBpbmZvcm1hdGlvblxyXG4gKiBpbiB0aGUgYGJhdGNoYCBvcHRpb24uIFRoZSBgYmF0Y2hgIGlzIGEgc3RyaW5nIGluIHRoZSBmb2xsb3dpbmcgZm9ybWF0OlxyXG4gKiBcImluZmlsZTEuanNvbj1vdXRmaWxlMS5wbmc7aW5maWxlMi5qc29uPW91dGZpbGUyLnBuZzsuLi5cIi4gUmVzdWx0cyBhcmUgc2F2ZWRcclxuICogaW4gcHJvdmlkZWQgb3V0ZmlsZXMuXHJcbiAqXHJcbiAqIEBhc3luY1xyXG4gKiBAZnVuY3Rpb24gYmF0Y2hFeHBvcnRcclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IG9wdGlvbnMgLSBUaGUgYG9wdGlvbnNgIG9iamVjdCwgd2hpY2ggbWF5IGJlIGEgcGFydGlhbFxyXG4gKiBvciBjb21wbGV0ZSBzZXQgb2Ygb3B0aW9ucy4gSXQgbXVzdCBjb250YWluIHRoZSBgYmF0Y2hgIG9wdGlvbiB0byBnZW5lcmF0ZVxyXG4gKiB2YWxpZCBpbWFnZXMuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtQcm9taXNlPHZvaWQ+fSBBIFByb21pc2UgdGhhdCByZXNvbHZlcyBvbmNlIHRoZSBiYXRjaCBleHBvcnRcclxuICogcHJvY2Vzc2VzIGFyZSBjb21wbGV0ZWQuXHJcbiAqXHJcbiAqIEB0aHJvd3Mge0V4cG9ydEVycm9yfSBUaHJvd3MgYW4gYEV4cG9ydEVycm9yYCBpZiBhbiBlcnJvciBvY2N1cnMgZHVyaW5nXHJcbiAqIGFueSBvZiB0aGUgYmF0Y2ggZXhwb3J0IHByb2Nlc3MuXHJcbiAqL1xyXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gYmF0Y2hFeHBvcnQob3B0aW9ucykge1xyXG4gIC8vIENoZWNrIGlmIHRoZSBleHBvcnQgbWFrZXMgc2Vuc2VcclxuICBpZiAob3B0aW9ucyAmJiBvcHRpb25zLmV4cG9ydCAmJiBvcHRpb25zLmV4cG9ydC5iYXRjaCkge1xyXG4gICAgLy8gQW4gYXJyYXkgZm9yIGNvbGxlY3RpbmcgYmF0Y2ggZXhwb3J0c1xyXG4gICAgY29uc3QgYmF0Y2hGdW5jdGlvbnMgPSBbXTtcclxuXHJcbiAgICAvLyBTcGxpdCBhbmQgcGFpciB0aGUgYGJhdGNoYCBhcmd1bWVudHNcclxuICAgIGZvciAobGV0IHBhaXIgb2Ygb3B0aW9ucy5leHBvcnQuYmF0Y2guc3BsaXQoJzsnKSB8fCBbXSkge1xyXG4gICAgICBwYWlyID0gcGFpci5zcGxpdCgnPScpO1xyXG4gICAgICBpZiAocGFpci5sZW5ndGggPT09IDIpIHtcclxuICAgICAgICBiYXRjaEZ1bmN0aW9ucy5wdXNoKFxyXG4gICAgICAgICAgc3RhcnRFeHBvcnQoXHJcbiAgICAgICAgICAgIHtcclxuICAgICAgICAgICAgICAuLi5vcHRpb25zLFxyXG4gICAgICAgICAgICAgIGV4cG9ydDoge1xyXG4gICAgICAgICAgICAgICAgLi4ub3B0aW9ucy5leHBvcnQsXHJcbiAgICAgICAgICAgICAgICBpbmZpbGU6IHBhaXJbMF0sXHJcbiAgICAgICAgICAgICAgICBvdXRmaWxlOiBwYWlyWzFdXHJcbiAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICB9LFxyXG4gICAgICAgICAgICAoZXJyb3IsIGRhdGEpID0+IHtcclxuICAgICAgICAgICAgICAvLyBFeGl0IHByb2Nlc3Mgd2hlbiBlcnJvciBleGlzdHNcclxuICAgICAgICAgICAgICBpZiAoZXJyb3IpIHtcclxuICAgICAgICAgICAgICAgIHRocm93IGVycm9yO1xyXG4gICAgICAgICAgICAgIH1cclxuXHJcbiAgICAgICAgICAgICAgLy8gR2V0IHRoZSBgYjY0YCwgYG91dGZpbGVgLCBhbmQgYHR5cGVgIGZvciBhIGNoYXJ0XHJcbiAgICAgICAgICAgICAgY29uc3QgeyBiNjQsIG91dGZpbGUsIHR5cGUgfSA9IGRhdGEub3B0aW9ucy5leHBvcnQ7XHJcblxyXG4gICAgICAgICAgICAgIC8vIFNhdmUgdGhlIHJlc3VsdFxyXG4gICAgICAgICAgICAgIHRyeSB7XHJcbiAgICAgICAgICAgICAgICBpZiAoYjY0KSB7XHJcbiAgICAgICAgICAgICAgICAgIC8vIEFzIGEgQmFzZTY0IHN0cmluZyB0byBhIHR4dCBmaWxlXHJcbiAgICAgICAgICAgICAgICAgIHdyaXRlRmlsZVN5bmMoXHJcbiAgICAgICAgICAgICAgICAgICAgYCR7b3V0ZmlsZS5zcGxpdCgnLicpLnNoaWZ0KCkgfHwgJ2NoYXJ0J30udHh0YCxcclxuICAgICAgICAgICAgICAgICAgICBnZXRCYXNlNjQoZGF0YS5yZXN1bHQsIHR5cGUpXHJcbiAgICAgICAgICAgICAgICAgICk7XHJcbiAgICAgICAgICAgICAgICB9IGVsc2Uge1xyXG4gICAgICAgICAgICAgICAgICAvLyBBcyBhIGNvcnJlY3QgaW1hZ2UgZm9ybWF0XHJcbiAgICAgICAgICAgICAgICAgIHdyaXRlRmlsZVN5bmMoXHJcbiAgICAgICAgICAgICAgICAgICAgb3V0ZmlsZSxcclxuICAgICAgICAgICAgICAgICAgICB0eXBlICE9PSAnc3ZnJ1xyXG4gICAgICAgICAgICAgICAgICAgICAgPyBCdWZmZXIuZnJvbShkYXRhLnJlc3VsdCwgJ2Jhc2U2NCcpXHJcbiAgICAgICAgICAgICAgICAgICAgICA6IGRhdGEucmVzdWx0XHJcbiAgICAgICAgICAgICAgICAgICk7XHJcbiAgICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgICAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICAgICAgICAgICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcihcclxuICAgICAgICAgICAgICAgICAgJ1tjaGFydF0gRXJyb3Igd2hpbGUgc2F2aW5nIGEgY2hhcnQuJyxcclxuICAgICAgICAgICAgICAgICAgNTAwXHJcbiAgICAgICAgICAgICAgICApLnNldEVycm9yKGVycm9yKTtcclxuICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgIH1cclxuICAgICAgICAgIClcclxuICAgICAgICApO1xyXG4gICAgICB9IGVsc2Uge1xyXG4gICAgICAgIGxvZygyLCAnW2NoYXJ0XSBObyBjb3JyZWN0IHBhaXIgZm91bmQgZm9yIHRoZSBiYXRjaCBleHBvcnQuJyk7XHJcbiAgICAgIH1cclxuICAgIH1cclxuXHJcbiAgICAvLyBBd2FpdCBhbGwgZXhwb3J0cyBhcmUgZG9uZVxyXG4gICAgY29uc3QgYmF0Y2hSZXN1bHRzID0gYXdhaXQgUHJvbWlzZS5hbGxTZXR0bGVkKGJhdGNoRnVuY3Rpb25zKTtcclxuXHJcbiAgICAvLyBLaWxsIHBvb2wgYW5kIGNsb3NlIGJyb3dzZXIgYWZ0ZXIgZmluaXNoaW5nIGJhdGNoIGV4cG9ydFxyXG4gICAgYXdhaXQga2lsbFBvb2woKTtcclxuXHJcbiAgICAvLyBMb2cgZXJyb3JzIGlmIGZvdW5kXHJcbiAgICBiYXRjaFJlc3VsdHMuZm9yRWFjaCgocmVzdWx0LCBpbmRleCkgPT4ge1xyXG4gICAgICAvLyBMb2cgdGhlIGVycm9yIHdpdGggc3RhY2sgYWJvdXQgdGhlIHNwZWNpZmljIGJhdGNoIGV4cG9ydFxyXG4gICAgICBpZiAocmVzdWx0LnJlYXNvbikge1xyXG4gICAgICAgIGxvZ1dpdGhTdGFjayhcclxuICAgICAgICAgIDEsXHJcbiAgICAgICAgICByZXN1bHQucmVhc29uLFxyXG4gICAgICAgICAgYFtjaGFydF0gQmF0Y2ggZXhwb3J0IG51bWJlciAke2luZGV4ICsgMX0gY291bGQgbm90IGJlIGNvcnJlY3RseSBjb21wbGV0ZWQuYFxyXG4gICAgICAgICk7XHJcbiAgICAgIH1cclxuICAgIH0pO1xyXG4gIH0gZWxzZSB7XHJcbiAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoXHJcbiAgICAgICdbY2hhcnRdIE5vIGV4cGVjdGVkIGBleHBvcnRgIG9wdGlvbnMgd2VyZSBmb3VuZC4gUGxlYXNlIHByb3ZpZGUgdGhlIGBiYXRjaGAgb3B0aW9uIHRvIGdlbmVyYXRlIHZhbGlkIGltYWdlcy4nLFxyXG4gICAgICA0MDBcclxuICAgICk7XHJcbiAgfVxyXG59XHJcblxyXG4vKipcclxuICogU3RhcnRzIGFuIGV4cG9ydCBwcm9jZXNzLiBUaGUgYGN1c3RvbU9wdGlvbnNgIHBhcmFtZXRlciBpcyBhbiBvYmplY3QgdGhhdFxyXG4gKiBtYXkgYmUgcGFydGlhbCBvciBjb21wbGV0ZSBzZXQgb2Ygb3B0aW9ucy4gVGhlIGBlbmRDYWxsYmFja2AgaXMgY2FsbGVkIHdoZW5cclxuICogdGhlIGV4cG9ydCBpcyBjb21wbGV0ZWQsIHdpdGggdGhlIGBlcnJvcmAgb2JqZWN0IGFzIHRoZSBmaXJzdCBhcmd1bWVudFxyXG4gKiBhbmQgdGhlIGBkYXRhYCBvYmplY3QgYXMgdGhlIHNlY29uZCwgd2hpY2ggY29udGFpbnMgdGhlIEJhc2U2NCByZXByZXNlbnRhdGlvblxyXG4gKiBvZiB0aGUgY2hhcnQgaW4gdGhlIGByZXN1bHRgIHByb3BlcnR5IGFuZCB0aGUgZnVsbCBzZXQgb2YgZXhwb3J0IG9wdGlvbnNcclxuICogaW4gdGhlIGBvcHRpb25zYCBwcm9wZXJ0eS5cclxuICpcclxuICogQGFzeW5jXHJcbiAqIEBmdW5jdGlvbiBzdGFydEV4cG9ydFxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gY3VzdG9tT3B0aW9ucyAtIFRoZSBgY3VzdG9tT3B0aW9uc2Agb2JqZWN0LCB3aGljaCBtYXlcclxuICogYmUgYSBwYXJ0aWFsIG9yIGNvbXBsZXRlIHNldCBvZiBvcHRpb25zLiBJZiB0aGUgcHJvdmlkZWQgb3B0aW9ucyBhcmUgcGFydGlhbCxcclxuICogbWlzc2luZyB2YWx1ZXMgd2lsbCBiZSBtZXJnZWQgd2l0aCB0aGUgZGVmYXVsdCBnZW5lcmFsIG9wdGlvbnMsIHJldHJpZXZlZFxyXG4gKiB1c2luZyB0aGUgYGdldE9wdGlvbnNgIGZ1bmN0aW9uLlxyXG4gKiBAcGFyYW0ge0Z1bmN0aW9ufSBlbmRDYWxsYmFjayAtIFRoZSBjYWxsYmFjayBmdW5jdGlvbiB0byBiZSBpbnZva2VkIHVwb25cclxuICogZmluYWxpemluZyB3b3JrIG9yIHVwb24gZXJyb3Igb2NjdXJhbmNlIG9mIHRoZSBleHBvcnRpbmcgcHJvY2Vzcy4gVGhlIGZpcnN0XHJcbiAqIGFyZ3VtZW50IGlzIGBlcnJvcmAgb2JqZWN0IGFuZCB0aGUgYGRhdGFgIG9iamVjdCBpcyB0aGUgc2Vjb25kLCB0aGF0IGNvbnRhaW5zXHJcbiAqIHRoZSBCYXNlNjQgcmVwcmVzZW50YXRpb24gb2YgdGhlIGNoYXJ0IGluIHRoZSBgcmVzdWx0YCBwcm9wZXJ0eSBhbmQgdGhlIGZ1bGxcclxuICogc2V0IG9mIGV4cG9ydCBvcHRpb25zIGluIHRoZSBgb3B0aW9uc2AgcHJvcGVydHkuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtQcm9taXNlPHZvaWQ+fSBUaGlzIGZ1bmN0aW9uIGRvZXMgbm90IHJldHVybiBhIHZhbHVlIGRpcmVjdGx5LlxyXG4gKiBJbnN0ZWFkLCBpdCBjb21tdW5pY2F0ZXMgcmVzdWx0cyB2aWEgdGhlIGBlbmRDYWxsYmFja2AuXHJcbiAqXHJcbiAqIEB0aHJvd3Mge0V4cG9ydEVycm9yfSBUaHJvd3MgYW4gYEV4cG9ydEVycm9yYCBpZiB0aGVyZSBpcyBhIHByb2JsZW0gd2l0aFxyXG4gKiBwcm9jZXNzaW5nIGlucHV0IG9mIGFueSB0eXBlLiBUaGUgZXJyb3IgaXMgcGFzc2VkIGludG8gdGhlIGBlbmRDYWxsYmFja2BcclxuICogZnVuY3Rpb24gYW5kIHByb2Nlc3NlZCB0aGVyZS5cclxuICovXHJcbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBzdGFydEV4cG9ydChjdXN0b21PcHRpb25zLCBlbmRDYWxsYmFjaykge1xyXG4gIHRyeSB7XHJcbiAgICAvLyBTdGFydGluZyBleHBvcnRpbmcgcHJvY2VzcyBtZXNzYWdlXHJcbiAgICBsb2coNCwgJ1tjaGFydF0gU3RhcnRpbmcgdGhlIGV4cG9ydGluZyBwcm9jZXNzLicpO1xyXG5cclxuICAgIC8vIE1lcmdlIHRoZSBjdXN0b20gb3B0aW9ucyBpbnRvIGRlZmF1bHQgb25lc1xyXG4gICAgY29uc3Qgb3B0aW9ucyA9IG1lcmdlT3B0aW9ucyhnZXRPcHRpb25zKGZhbHNlKSwgY3VzdG9tT3B0aW9ucyk7XHJcblxyXG4gICAgLy8gR2V0IHRoZSBleHBvcnQgb3B0aW9uc1xyXG4gICAgY29uc3QgZXhwb3J0T3B0aW9ucyA9IG9wdGlvbnMuZXhwb3J0O1xyXG5cclxuICAgIC8vIEV4cG9ydCB1c2luZyBvcHRpb25zIGZyb20gdGhlIGZpbGUgYXMgYW4gaW5wdXRcclxuICAgIGlmIChleHBvcnRPcHRpb25zLmluZmlsZSAhPT0gbnVsbCkge1xyXG4gICAgICBsb2coNCwgJ1tjaGFydF0gQXR0ZW1wdGluZyB0byBleHBvcnQgZnJvbSBhIGZpbGUgaW5wdXQuJyk7XHJcblxyXG4gICAgICBsZXQgZmlsZUNvbnRlbnQ7XHJcbiAgICAgIHRyeSB7XHJcbiAgICAgICAgLy8gVHJ5IHRvIHJlYWQgdGhlIGZpbGUgdG8gZ2V0IHRoZSBzdHJpbmcgcmVwcmVzZW50YXRpb25cclxuICAgICAgICBmaWxlQ29udGVudCA9IHJlYWRGaWxlU3luYyhcclxuICAgICAgICAgIGdldEFic29sdXRlUGF0aChleHBvcnRPcHRpb25zLmluZmlsZSksXHJcbiAgICAgICAgICAndXRmOCdcclxuICAgICAgICApO1xyXG4gICAgICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcihcclxuICAgICAgICAgICdbY2hhcnRdIEVycm9yIGxvYWRpbmcgY29udGVudCBmcm9tIGEgZmlsZSBpbnB1dC4nLFxyXG4gICAgICAgICAgNDAwXHJcbiAgICAgICAgKS5zZXRFcnJvcihlcnJvcik7XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIC8vIENoZWNrIHRoZSBmaWxlJ3MgZXh0ZW5zaW9uXHJcbiAgICAgIGlmIChleHBvcnRPcHRpb25zLmluZmlsZS5lbmRzV2l0aCgnLnN2ZycpKSB7XHJcbiAgICAgICAgdHJ5IHtcclxuICAgICAgICAgIC8vIFNldCB0byB0aGUgYHN2Z2Agb3B0aW9uXHJcbiAgICAgICAgICBleHBvcnRPcHRpb25zLnN2ZyA9IHZhbGlkYXRlT3B0aW9uKCdzdmcnLCBmaWxlQ29udGVudCwgZmFsc2UpO1xyXG4gICAgICAgIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICAgICAgICBsb2dab2RJc3N1ZXMoXHJcbiAgICAgICAgICAgIDEsXHJcbiAgICAgICAgICAgIGVycm9yLmlzc3VlcyxcclxuICAgICAgICAgICAgJ1tjb25maWddIFRoZSBgc3ZnYCBvcHRpb24gdmFsaWRhdGlvbiBlcnJvcidcclxuICAgICAgICAgICk7XHJcbiAgICAgICAgICB0aHJvdyBlcnJvcjtcclxuICAgICAgICB9XHJcbiAgICAgIH0gZWxzZSBpZiAoZXhwb3J0T3B0aW9ucy5pbmZpbGUuZW5kc1dpdGgoJy5qc29uJykpIHtcclxuICAgICAgICB0cnkge1xyXG4gICAgICAgICAgLy8gU2V0IHRvIHRoZSBgaW5zdHJgIG9wdGlvblxyXG4gICAgICAgICAgZXhwb3J0T3B0aW9ucy5pbnN0ciA9IHZhbGlkYXRlT3B0aW9uKCdpbnN0cicsIGZpbGVDb250ZW50LCBmYWxzZSk7XHJcbiAgICAgICAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICAgICAgIGxvZ1pvZElzc3VlcyhcclxuICAgICAgICAgICAgMSxcclxuICAgICAgICAgICAgZXJyb3IuaXNzdWVzLFxyXG4gICAgICAgICAgICAnW2NvbmZpZ10gVGhlIGBpbnN0cmAgb3B0aW9uIHZhbGlkYXRpb24gZXJyb3InXHJcbiAgICAgICAgICApO1xyXG4gICAgICAgICAgdGhyb3cgZXJyb3I7XHJcbiAgICAgICAgfVxyXG4gICAgICB9IGVsc2Uge1xyXG4gICAgICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcihcclxuICAgICAgICAgICdbY2hhcnRdIEluY29ycmVjdCB2YWx1ZSBvZiB0aGUgYGluZmlsZWAgb3B0aW9uLicsXHJcbiAgICAgICAgICA0MDBcclxuICAgICAgICApO1xyXG4gICAgICB9XHJcbiAgICB9XHJcblxyXG4gICAgLy8gRXhwb3J0IHVzaW5nIFNWRyBhcyBhbiBpbnB1dFxyXG4gICAgaWYgKGV4cG9ydE9wdGlvbnMuc3ZnICE9PSBudWxsKSB7XHJcbiAgICAgIGxvZyg0LCAnW2NoYXJ0XSBBdHRlbXB0aW5nIHRvIGV4cG9ydCBmcm9tIGFuIFNWRyBpbnB1dC4nKTtcclxuXHJcbiAgICAgIC8vIFNWRyBleHBvcnRzIGF0dGVtcHRzIGNvdW50ZXJcclxuICAgICAgKytnZXRQb29sU3RhdHMoKS5leHBvcnRzRnJvbVN2Z0F0dGVtcHRzO1xyXG5cclxuICAgICAgLy8gRXhwb3J0IGZyb20gYW4gU1ZHIHN0cmluZ1xyXG4gICAgICBjb25zdCByZXN1bHQgPSBhd2FpdCBfZXhwb3J0RnJvbVN2ZyhcclxuICAgICAgICBzYW5pdGl6ZShleHBvcnRPcHRpb25zLnN2ZyksIC8vICMyMDlcclxuICAgICAgICBvcHRpb25zXHJcbiAgICAgICk7XHJcblxyXG4gICAgICAvLyBTVkcgZXhwb3J0cyBjb3VudGVyXHJcbiAgICAgICsrZ2V0UG9vbFN0YXRzKCkuZXhwb3J0c0Zyb21Tdmc7XHJcblxyXG4gICAgICAvLyBQYXNzIFNWRyBleHBvcnQgcmVzdWx0IHRvIHRoZSBlbmQgY2FsbGJhY2tcclxuICAgICAgcmV0dXJuIGVuZENhbGxiYWNrKG51bGwsIHJlc3VsdCk7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gRXhwb3J0IHVzaW5nIG9wdGlvbnMgYXMgYW4gaW5wdXRcclxuICAgIGlmIChleHBvcnRPcHRpb25zLmluc3RyICE9PSBudWxsIHx8IGV4cG9ydE9wdGlvbnMub3B0aW9ucyAhPT0gbnVsbCkge1xyXG4gICAgICBsb2coNCwgJ1tjaGFydF0gQXR0ZW1wdGluZyB0byBleHBvcnQgZnJvbSBvcHRpb25zIGlucHV0LicpO1xyXG5cclxuICAgICAgLy8gT3B0aW9ucyBleHBvcnRzIGF0dGVtcHRzIGNvdW50ZXJcclxuICAgICAgKytnZXRQb29sU3RhdHMoKS5leHBvcnRzRnJvbU9wdGlvbnNBdHRlbXB0cztcclxuXHJcbiAgICAgIC8vIEV4cG9ydCBmcm9tIG9wdGlvbnNcclxuICAgICAgY29uc3QgcmVzdWx0ID0gYXdhaXQgX2V4cG9ydEZyb21PcHRpb25zKFxyXG4gICAgICAgIGV4cG9ydE9wdGlvbnMuaW5zdHIgfHwgZXhwb3J0T3B0aW9ucy5vcHRpb25zLFxyXG4gICAgICAgIG9wdGlvbnNcclxuICAgICAgKTtcclxuXHJcbiAgICAgIC8vIE9wdGlvbnMgZXhwb3J0cyBjb3VudGVyXHJcbiAgICAgICsrZ2V0UG9vbFN0YXRzKCkuZXhwb3J0c0Zyb21PcHRpb25zO1xyXG5cclxuICAgICAgLy8gUGFzcyBvcHRpb25zIGV4cG9ydCByZXN1bHQgdG8gdGhlIGVuZCBjYWxsYmFja1xyXG4gICAgICByZXR1cm4gZW5kQ2FsbGJhY2sobnVsbCwgcmVzdWx0KTtcclxuICAgIH1cclxuXHJcbiAgICAvLyBObyBpbnB1dCBzcGVjaWZpZWQsIHBhc3MgYW4gZXJyb3IgbWVzc2FnZSB0byB0aGUgY2FsbGJhY2tcclxuICAgIHJldHVybiBlbmRDYWxsYmFjayhcclxuICAgICAgbmV3IEV4cG9ydEVycm9yKFxyXG4gICAgICAgIGBbY2hhcnRdIE5vIHZhbGlkIGlucHV0IHNwZWNpZmllZC4gQ2hlY2sgaWYgYXQgbGVhc3Qgb25lIG9mIHRoZSBmb2xsb3dpbmcgcGFyYW1ldGVycyBpcyBjb3JyZWN0bHkgc2V0OiAnaW5maWxlJywgJ2luc3RyJywgJ29wdGlvbnMnLCBvciAnc3ZnJy5gLFxyXG4gICAgICAgIDQwMFxyXG4gICAgICApXHJcbiAgICApO1xyXG4gIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICByZXR1cm4gZW5kQ2FsbGJhY2soZXJyb3IpO1xyXG4gIH1cclxufVxyXG5cclxuLyoqXHJcbiAqIFJldHJpZXZlcyBhbmQgcmV0dXJucyB0aGUgY3VycmVudCBzdGF0dXMgb2YgdGhlIGNvZGUgZXhlY3V0aW9uIHBlcm1pc3Npb24uXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBnZXRBbGxvd0NvZGVFeGVjdXRpb25cclxuICpcclxuICogQHJldHVybnMge2Jvb2xlYW59IFRoZSB2YWx1ZSBvZiB0aGUgZ2xvYmFsIGBhbGxvd0NvZGVFeGVjdXRpb25gIG9wdGlvbi5cclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiBnZXRBbGxvd0NvZGVFeGVjdXRpb24oKSB7XHJcbiAgcmV0dXJuIGFsbG93Q29kZUV4ZWN1dGlvbjtcclxufVxyXG5cclxuLyoqXHJcbiAqIFNldHMgdGhlIGNvZGUgZXhlY3V0aW9uIHBlcm1pc3Npb24gYmFzZWQgb24gdGhlIHByb3ZpZGVkIGJvb2xlYW4gdmFsdWUuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBzZXRBbGxvd0NvZGVFeGVjdXRpb25cclxuICpcclxuICogQHBhcmFtIHtib29sZWFufSB2YWx1ZSAtIFRoZSB2YWx1ZSB0byBiZSBhc3NpZ25lZCB0byB0aGUgZ2xvYmFsXHJcbiAqIGBhbGxvd0NvZGVFeGVjdXRpb25gIG9wdGlvbi5cclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiBzZXRBbGxvd0NvZGVFeGVjdXRpb24odmFsdWUpIHtcclxuICBhbGxvd0NvZGVFeGVjdXRpb24gPSB2YWx1ZTtcclxufVxyXG5cclxuLyoqXHJcbiAqIEV4cG9ydHMgZnJvbSBhbiBTVkcgYmFzZWQgaW5wdXQgd2l0aCB0aGUgcHJvdmlkZWQgb3B0aW9ucy5cclxuICpcclxuICogQGFzeW5jXHJcbiAqIEBmdW5jdGlvbiBfZXhwb3J0RnJvbVN2Z1xyXG4gKlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gaW5wdXRUb0V4cG9ydCAtIFRoZSBTVkcgYmFzZWQgaW5wdXQgdG8gYmUgZXhwb3J0ZWQuXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBvcHRpb25zIC0gVGhlIGBvcHRpb25zYCBvYmplY3QgY29udGFpbmluZyBjb21wbGV0ZSBzZXRcclxuICogb2Ygb3B0aW9ucy5cclxuICpcclxuICogQHJldHVybnMge1Byb21pc2U8dW5rbm93bj59IEEgUHJvbWlzZSB0aGF0IHJlc29sdmVzIHRvIGEgcmVzdWx0IG9mIHRoZSBleHBvcnRcclxuICogcHJvY2Vzcy5cclxuICpcclxuICogQHRocm93cyB7RXhwb3J0RXJyb3J9IFRocm93cyBhbiBgRXhwb3J0RXJyb3JgIGlmIHRoZXJlIGlzIG5vdCBhIGNvcnJlY3QgU1ZHXHJcbiAqIGlucHV0LlxyXG4gKi9cclxuYXN5bmMgZnVuY3Rpb24gX2V4cG9ydEZyb21TdmcoaW5wdXRUb0V4cG9ydCwgb3B0aW9ucykge1xyXG4gIC8vIENoZWNrIGlmIGl0IGlzIFNWR1xyXG4gIGlmIChcclxuICAgIHR5cGVvZiBpbnB1dFRvRXhwb3J0ID09PSAnc3RyaW5nJyAmJlxyXG4gICAgKGlucHV0VG9FeHBvcnQuaW5kZXhPZignPHN2ZycpID49IDAgfHwgaW5wdXRUb0V4cG9ydC5pbmRleE9mKCc8P3htbCcpID49IDApXHJcbiAgKSB7XHJcbiAgICBsb2coNCwgJ1tjaGFydF0gUGFyc2luZyBpbnB1dCBhcyBTVkcuJyk7XHJcblxyXG4gICAgLy8gU2V0IHRoZSBleHBvcnQgaW5wdXQgYXMgU1ZHXHJcbiAgICBvcHRpb25zLmV4cG9ydC5zdmcgPSBpbnB1dFRvRXhwb3J0O1xyXG5cclxuICAgIC8vIFJlc2V0IHRoZSByZXN0IG9mIHRoZSBleHBvcnQgaW5wdXQgb3B0aW9uc1xyXG4gICAgb3B0aW9ucy5leHBvcnQuaW5zdHIgPSBudWxsO1xyXG4gICAgb3B0aW9ucy5leHBvcnQub3B0aW9ucyA9IG51bGw7XHJcblxyXG4gICAgLy8gQ2FsbCB0aGUgZnVuY3Rpb24gd2l0aCBhbiBTVkcgc3RyaW5nIGFzIGFuIGV4cG9ydCBpbnB1dFxyXG4gICAgcmV0dXJuIF9wcmVwYXJlRXhwb3J0KG9wdGlvbnMpO1xyXG4gIH0gZWxzZSB7XHJcbiAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoJ1tjaGFydF0gTm90IGEgY29ycmVjdCBTVkcgaW5wdXQuJywgNDAwKTtcclxuICB9XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBFeHBvcnRzIGZyb20gYW4gb3B0aW9ucyBiYXNlZCBpbnB1dCB3aXRoIHRoZSBwcm92aWRlZCBvcHRpb25zLlxyXG4gKlxyXG4gKiBAYXN5bmNcclxuICogQGZ1bmN0aW9uIF9leHBvcnRGcm9tT3B0aW9uc1xyXG4gKlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gaW5wdXRUb0V4cG9ydCAtIFRoZSBvcHRpb25zIGJhc2VkIGlucHV0IHRvIGJlIGV4cG9ydGVkLlxyXG4gKiBAcGFyYW0ge09iamVjdH0gb3B0aW9ucyAtIFRoZSBgb3B0aW9uc2Agb2JqZWN0IGNvbnRhaW5pbmcgY29tcGxldGUgc2V0XHJcbiAqIG9mIG9wdGlvbnMuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtQcm9taXNlPHVua25vd24+fSBBIFByb21pc2UgdGhhdCByZXNvbHZlcyB0byBhIHJlc3VsdCBvZiB0aGUgZXhwb3J0XHJcbiAqIHByb2Nlc3MuXHJcbiAqXHJcbiAqIEB0aHJvd3Mge0V4cG9ydEVycm9yfSBUaHJvd3MgYW4gYEV4cG9ydEVycm9yYCBpZiB0aGVyZSBpcyBub3QgYSBjb3JyZWN0XHJcbiAqIGNoYXJ0IG9wdGlvbnMgaW5wdXQuXHJcbiAqL1xyXG5hc3luYyBmdW5jdGlvbiBfZXhwb3J0RnJvbU9wdGlvbnMoaW5wdXRUb0V4cG9ydCwgb3B0aW9ucykge1xyXG4gIGxvZyg0LCAnW2NoYXJ0XSBQYXJzaW5nIGlucHV0IGZyb20gb3B0aW9ucy4nKTtcclxuXHJcbiAgLy8gVHJ5IHRvIGNoZWNrLCB2YWxpZGF0ZSBhbmQgcGFyc2UgdG8gc3RyaW5naWZpZWQgb3B0aW9uc1xyXG4gIGNvbnN0IHN0cmluZ2lmaWVkT3B0aW9ucyA9IGlzQWxsb3dlZENvbmZpZyhcclxuICAgIGlucHV0VG9FeHBvcnQsXHJcbiAgICB0cnVlLFxyXG4gICAgb3B0aW9ucy5jdXN0b21Mb2dpYy5hbGxvd0NvZGVFeGVjdXRpb25cclxuICApO1xyXG5cclxuICAvLyBDaGVjayBpZiBhIGNvcnJlY3Qgc3RyaW5naWZpZWQgb3B0aW9uc1xyXG4gIGlmIChcclxuICAgIHN0cmluZ2lmaWVkT3B0aW9ucyA9PT0gbnVsbCB8fFxyXG4gICAgdHlwZW9mIHN0cmluZ2lmaWVkT3B0aW9ucyAhPT0gJ3N0cmluZycgfHxcclxuICAgICFzdHJpbmdpZmllZE9wdGlvbnMuc3RhcnRzV2l0aCgneycpIHx8XHJcbiAgICAhc3RyaW5naWZpZWRPcHRpb25zLmVuZHNXaXRoKCd9JylcclxuICApIHtcclxuICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcihcclxuICAgICAgJ1tjaGFydF0gSW52YWxpZCBjb25maWd1cmF0aW9uIHByb3ZpZGVkIC0gT25seSBvcHRpb25zIGNvbmZpZ3VyYXRpb25zIGFuZCBTVkcgYXJlIGFsbG93ZWQgZm9yIHRoaXMgc2VydmVyLiBJZiB0aGlzIGlzIHlvdXIgc2VydmVyLCBKYXZhU2NyaXB0IGN1c3RvbSBjb2RlIGNhbiBiZSBlbmFibGVkIGJ5IHN0YXJ0aW5nIHRoZSBzZXJ2ZXIgd2l0aCB0aGUgYGFsbG93Q29kZUV4ZWN1dGlvbmAgb3B0aW9ucyBzZXQgdG8gdHJ1ZS4nLFxyXG4gICAgICA0MDNcclxuICAgICk7XHJcbiAgfVxyXG5cclxuICAvLyBTZXQgdGhlIGV4cG9ydCBpbnB1dCBhcyBhIHN0cmluZ2lmaWVkIGNoYXJ0IG9wdGlvbnNcclxuICBvcHRpb25zLmV4cG9ydC5pbnN0ciA9IHN0cmluZ2lmaWVkT3B0aW9ucztcclxuXHJcbiAgLy8gUmVzZXQgdGhlIHJlc3Qgb2YgdGhlIGV4cG9ydCBpbnB1dCBvcHRpb25zXHJcbiAgb3B0aW9ucy5leHBvcnQuc3ZnID0gbnVsbDtcclxuXHJcbiAgLy8gQ2FsbCB0aGUgZnVuY3Rpb24gd2l0aCBhIHN0cmluZ2lmaWVkIGNoYXJ0IG9wdGlvbnNcclxuICByZXR1cm4gX3ByZXBhcmVFeHBvcnQob3B0aW9ucyk7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBGdW5jdGlvbiBmb3IgZmluYWxpemluZyBvcHRpb25zIGFuZCBjb25maWd1cmF0aW9ucyBiZWZvcmUgZXhwb3J0LlxyXG4gKlxyXG4gKiBAYXN5bmNcclxuICogQGZ1bmN0aW9uIF9wcmVwYXJlRXhwb3J0XHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBvcHRpb25zIC0gVGhlIGBvcHRpb25zYCBvYmplY3QgY29udGFpbmluZyBjb21wbGV0ZSBzZXRcclxuICogb2Ygb3B0aW9ucy5cclxuICpcclxuICogQHJldHVybnMge1Byb21pc2U8dW5rbm93bj59IEEgUHJvbWlzZSB0aGF0IHJlc29sdmVzIHRvIGEgcmVzdWx0IG9mIHRoZSBleHBvcnRcclxuICogcHJvY2Vzcy5cclxuICovXHJcbmFzeW5jIGZ1bmN0aW9uIF9wcmVwYXJlRXhwb3J0KG9wdGlvbnMpIHtcclxuICBjb25zdCB7IGV4cG9ydDogZXhwb3J0T3B0aW9ucywgY3VzdG9tTG9naWM6IGN1c3RvbUxvZ2ljT3B0aW9ucyB9ID0gb3B0aW9ucztcclxuXHJcbiAgLy8gUHJlcGFyZSB0aGUgYHR5cGVgIG9wdGlvblxyXG4gIGV4cG9ydE9wdGlvbnMudHlwZSA9IGZpeFR5cGUoZXhwb3J0T3B0aW9ucy50eXBlLCBleHBvcnRPcHRpb25zLm91dGZpbGUpO1xyXG5cclxuICAvLyBQcmVwYXJlIHRoZSBgb3V0ZmlsZWAgb3B0aW9uXHJcbiAgZXhwb3J0T3B0aW9ucy5vdXRmaWxlID0gZml4T3V0ZmlsZShleHBvcnRPcHRpb25zLnR5cGUsIGV4cG9ydE9wdGlvbnMub3V0ZmlsZSk7XHJcblxyXG4gIC8vIE5vdGlmeSBhYm91dCB0aGUgY3VzdG9tIGxvZ2ljIHVzYWdlIHN0YXR1c1xyXG4gIGxvZyhcclxuICAgIDMsXHJcbiAgICBgW2NoYXJ0XSBUaGUgY3VzdG9tIGxvZ2ljIGlzICR7Y3VzdG9tTG9naWNPcHRpb25zLmFsbG93Q29kZUV4ZWN1dGlvbiA/ICdhbGxvd2VkJyA6ICdkaXNhbGxvd2VkJ30uYFxyXG4gICk7XHJcblxyXG4gIC8vIFByZXBhcmUgdGhlIGN1c3RvbSBsb2dpYyBvcHRpb25zIChgY3VzdG9tQ29kZWAsIGBjYWxsYmFja2AsIGByZXNvdXJjZXNgKVxyXG4gIF9oYW5kbGVDdXN0b21Mb2dpYyhjdXN0b21Mb2dpY09wdGlvbnMsIGN1c3RvbUxvZ2ljT3B0aW9ucy5hbGxvd0NvZGVFeGVjdXRpb24pO1xyXG5cclxuICAvLyBQcmVwYXJlIHRoZSBgZ2xvYmFsT3B0aW9uc2AgYW5kIGB0aGVtZU9wdGlvbnNgIG9wdGlvbnNcclxuICBfaGFuZGxlR2xvYmFsQW5kVGhlbWUoXHJcbiAgICBleHBvcnRPcHRpb25zLFxyXG4gICAgY3VzdG9tTG9naWNPcHRpb25zLmFsbG93RmlsZVJlc291cmNlcyxcclxuICAgIGN1c3RvbUxvZ2ljT3B0aW9ucy5hbGxvd0NvZGVFeGVjdXRpb25cclxuICApO1xyXG5cclxuICAvLyBQcmVwYXJlIHRoZSBgaGVpZ2h0YCwgYHdpZHRoYCwgYW5kIGBzY2FsZWAgb3B0aW9uc1xyXG4gIG9wdGlvbnMuZXhwb3J0ID0ge1xyXG4gICAgLi4uZXhwb3J0T3B0aW9ucyxcclxuICAgIC4uLl9maW5kQ2hhcnRTaXplKGV4cG9ydE9wdGlvbnMpXHJcbiAgfTtcclxuXHJcbiAgLy8gVGhlIGxhc3Qgc3RyaWN0IHZhbGlkYXRpb24gb2Ygb3B0aW9ucyByaWdodCBiZWZvcmUgZXhwb3J0aW5nIHByb2Nlc3NcclxuICB0cnkge1xyXG4gICAgLy8gVmFsaWRhdGUgZmluYWwgb3B0aW9uc1xyXG4gICAgb3B0aW9ucyA9IHN0cmljdFZhbGlkYXRlKG9wdGlvbnMpO1xyXG4gIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICBsb2dab2RJc3N1ZXMoMSwgZXJyb3IuaXNzdWVzLCAnW2NvbmZpZ10gRmluYWwgb3B0aW9ucyB2YWxpZGF0aW9uIGVycm9yJyk7XHJcbiAgfVxyXG5cclxuICAvLyBQb3N0IHRoZSB3b3JrIHRvIHRoZSBwb29sXHJcbiAgcmV0dXJuIHBvc3RXb3JrKG9wdGlvbnMpO1xyXG59XHJcblxyXG4vKipcclxuICogQ2FsY3VsYXRlcyB0aGUgYGhlaWdodGAsIGB3aWR0aGAgYW5kIGBzY2FsZWAgZm9yIGNoYXJ0IGV4cG9ydHMgYmFzZWRcclxuICogb24gdGhlIHByb3ZpZGVkIGV4cG9ydCBvcHRpb25zLlxyXG4gKlxyXG4gKiBUaGUgZnVuY3Rpb24gcHJpb3JpdGl6ZXMgdmFsdWVzIGluIHRoZSBmb2xsb3dpbmcgb3JkZXI6XHJcbiAqIDEuIFRoZSBgaGVpZ2h0YCwgYHdpZHRoYCwgYHNjYWxlYCBmcm9tIHRoZSBgZXhwb3J0T3B0aW9uc2AuXHJcbiAqIDIuIE9wdGlvbnMgZnJvbSB0aGUgY2hhcnQgY29uZmlndXJhdGlvbiAoZnJvbSBgZXhwb3J0aW5nYCBhbmQgYGNoYXJ0YCkuXHJcbiAqIDMuIE9wdGlvbnMgZnJvbSB0aGUgZ2xvYmFsIG9wdGlvbnMgKGZyb20gYGV4cG9ydGluZ2AgYW5kIGBjaGFydGApLlxyXG4gKiA0LiBPcHRpb25zIGZyb20gdGhlIHRoZW1lIG9wdGlvbnMgKGZyb20gYGV4cG9ydGluZ2AgYW5kIGBjaGFydGAgc2VjdGlvbnMpLlxyXG4gKiA1LiBGYWxsYmFjayBkZWZhdWx0IHZhbHVlcyAoYGhlaWdodCA9IDQwMGAsIGB3aWR0aCA9IDYwMGAsIGBzY2FsZSA9IDFgKS5cclxuICpcclxuICogQGZ1bmN0aW9uIF9maW5kQ2hhcnRTaXplXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBleHBvcnRPcHRpb25zIC0gVGhlIG9iamVjdCBjb250YWluaW5nIGBleHBvcnRgIG9wdGlvbnMuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtPYmplY3R9IEFuIG9iamVjdCBjb250YWluaW5nIHRoZSBjYWxjdWxhdGVkIGBoZWlnaHRgLCBgd2lkdGhgXHJcbiAqIGFuZCBgc2NhbGVgIHZhbHVlcyBmb3IgdGhlIGNoYXJ0IGV4cG9ydC5cclxuICovXHJcbmZ1bmN0aW9uIF9maW5kQ2hhcnRTaXplKGV4cG9ydE9wdGlvbnMpIHtcclxuICAvLyBDaGVjayB0aGUgYG9wdGlvbnNgIGFuZCBgaW5zdHJgIGZvciBjaGFydCBhbmQgZXhwb3J0aW5nIHNlY3Rpb25zXHJcbiAgY29uc3QgeyBjaGFydDogb3B0aW9uc0NoYXJ0LCBleHBvcnRpbmc6IG9wdGlvbnNFeHBvcnRpbmcgfSA9XHJcbiAgICBleHBvcnRPcHRpb25zLm9wdGlvbnMgfHwgaXNBbGxvd2VkQ29uZmlnKGV4cG9ydE9wdGlvbnMuaW5zdHIpIHx8IGZhbHNlO1xyXG5cclxuICAvLyBDaGVjayB0aGUgYGdsb2JhbE9wdGlvbnNgIGZvciBjaGFydCBhbmQgZXhwb3J0aW5nIHNlY3Rpb25zXHJcbiAgY29uc3QgeyBjaGFydDogZ2xvYmFsT3B0aW9uc0NoYXJ0LCBleHBvcnRpbmc6IGdsb2JhbE9wdGlvbnNFeHBvcnRpbmcgfSA9XHJcbiAgICBpc0FsbG93ZWRDb25maWcoZXhwb3J0T3B0aW9ucy5nbG9iYWxPcHRpb25zKSB8fCBmYWxzZTtcclxuXHJcbiAgLy8gQ2hlY2sgdGhlIGB0aGVtZU9wdGlvbnNgIGZvciBjaGFydCBhbmQgZXhwb3J0aW5nIHNlY3Rpb25zXHJcbiAgY29uc3QgeyBjaGFydDogdGhlbWVPcHRpb25zQ2hhcnQsIGV4cG9ydGluZzogdGhlbWVPcHRpb25zRXhwb3J0aW5nIH0gPVxyXG4gICAgaXNBbGxvd2VkQ29uZmlnKGV4cG9ydE9wdGlvbnMudGhlbWVPcHRpb25zKSB8fCBmYWxzZTtcclxuXHJcbiAgLy8gRmluZCB0aGUgYHNjYWxlYCB2YWx1ZTpcclxuICAvLyAtIEl0IGNhbm5vdCBiZSBsb3dlciB0aGFuIDAuMVxyXG4gIC8vIC0gSXQgY2Fubm90IGJlIGhpZ2hlciB0aGFuIDUuMFxyXG4gIC8vIC0gSXQgbXVzdCBiZSByb3VuZGVkIHRvIDIgZGVjaW1hbCBwbGFjZXMgKGUuZy4gMC4yMzIzNCAtPiAwLjIzKVxyXG4gIGNvbnN0IHNjYWxlID0gcm91bmROdW1iZXIoXHJcbiAgICBNYXRoLm1heChcclxuICAgICAgMC4xLFxyXG4gICAgICBNYXRoLm1pbihcclxuICAgICAgICBleHBvcnRPcHRpb25zLnNjYWxlIHx8XHJcbiAgICAgICAgICBvcHRpb25zRXhwb3J0aW5nPy5zY2FsZSB8fFxyXG4gICAgICAgICAgZ2xvYmFsT3B0aW9uc0V4cG9ydGluZz8uc2NhbGUgfHxcclxuICAgICAgICAgIHRoZW1lT3B0aW9uc0V4cG9ydGluZz8uc2NhbGUgfHxcclxuICAgICAgICAgIGV4cG9ydE9wdGlvbnMuZGVmYXVsdFNjYWxlIHx8XHJcbiAgICAgICAgICAxLFxyXG4gICAgICAgIDUuMFxyXG4gICAgICApXHJcbiAgICApLFxyXG4gICAgMlxyXG4gICk7XHJcblxyXG4gIC8vIEZpbmQgdGhlIGBoZWlnaHRgIHZhbHVlXHJcbiAgY29uc3QgaGVpZ2h0ID1cclxuICAgIGV4cG9ydE9wdGlvbnMuaGVpZ2h0IHx8XHJcbiAgICBvcHRpb25zRXhwb3J0aW5nPy5zb3VyY2VIZWlnaHQgfHxcclxuICAgIG9wdGlvbnNDaGFydD8uaGVpZ2h0IHx8XHJcbiAgICBnbG9iYWxPcHRpb25zRXhwb3J0aW5nPy5zb3VyY2VIZWlnaHQgfHxcclxuICAgIGdsb2JhbE9wdGlvbnNDaGFydD8uaGVpZ2h0IHx8XHJcbiAgICB0aGVtZU9wdGlvbnNFeHBvcnRpbmc/LnNvdXJjZUhlaWdodCB8fFxyXG4gICAgdGhlbWVPcHRpb25zQ2hhcnQ/LmhlaWdodCB8fFxyXG4gICAgZXhwb3J0T3B0aW9ucy5kZWZhdWx0SGVpZ2h0IHx8XHJcbiAgICA0MDA7XHJcblxyXG4gIC8vIEZpbmQgdGhlIGB3aWR0aGAgdmFsdWVcclxuICBjb25zdCB3aWR0aCA9XHJcbiAgICBleHBvcnRPcHRpb25zLndpZHRoIHx8XHJcbiAgICBvcHRpb25zRXhwb3J0aW5nPy5zb3VyY2VXaWR0aCB8fFxyXG4gICAgb3B0aW9uc0NoYXJ0Py53aWR0aCB8fFxyXG4gICAgZ2xvYmFsT3B0aW9uc0V4cG9ydGluZz8uc291cmNlV2lkdGggfHxcclxuICAgIGdsb2JhbE9wdGlvbnNDaGFydD8ud2lkdGggfHxcclxuICAgIHRoZW1lT3B0aW9uc0V4cG9ydGluZz8uc291cmNlV2lkdGggfHxcclxuICAgIHRoZW1lT3B0aW9uc0NoYXJ0Py53aWR0aCB8fFxyXG4gICAgZXhwb3J0T3B0aW9ucy5kZWZhdWx0V2lkdGggfHxcclxuICAgIDYwMDtcclxuXHJcbiAgLy8gR2F0aGVyIGBoZWlnaHRgLCBgd2lkdGhgIGFuZCBgc2NhbGVgIGluZm9ybWF0aW9uIGluIG9uZSBvYmplY3RcclxuICBjb25zdCBzaXplID0geyBoZWlnaHQsIHdpZHRoLCBzY2FsZSB9O1xyXG5cclxuICAvLyBHZXQgcmlkIG9mIHBvdGVudGlhbCBgcHhgIGFuZCBgJWBcclxuICBmb3IgKGxldCBbcGFyYW0sIHZhbHVlXSBvZiBPYmplY3QuZW50cmllcyhzaXplKSkge1xyXG4gICAgc2l6ZVtwYXJhbV0gPVxyXG4gICAgICB0eXBlb2YgdmFsdWUgPT09ICdzdHJpbmcnID8gK3ZhbHVlLnJlcGxhY2UoL3B4fCUvZ2ksICcnKSA6IHZhbHVlO1xyXG4gIH1cclxuXHJcbiAgLy8gUmV0dXJuIHRoZSBzaXplIG9iamVjdFxyXG4gIHJldHVybiBzaXplO1xyXG59XHJcblxyXG4vKipcclxuICogSGFuZGxlcyB0aGUgZXhlY3V0aW9uIG9mIGN1c3RvbSBsb2dpYyBvcHRpb25zLCBpbmNsdWRpbmcgbG9hZGluZyBgcmVzb3VyY2VzYCxcclxuICogYGN1c3RvbUNvZGVgLCBhbmQgYGNhbGxiYWNrYC4gSWYgY29kZSBleGVjdXRpb24gaXMgYWxsb3dlZCwgaXQgcHJvY2Vzc2VzXHJcbiAqIHRoZSBjdXN0b20gbG9naWMgb3B0aW9ucyBhY2NvcmRpbmdseS4gSWYgY29kZSBleGVjdXRpb24gaXMgbm90IGFsbG93ZWQsXHJcbiAqIGl0IGRpc2FibGVzIHRoZSB1c2FnZSBvZiByZXNvdXJjZXMsIGN1c3RvbSBjb2RlIGFuZCBjYWxsYmFjay5cclxuICpcclxuICogQGZ1bmN0aW9uIF9oYW5kbGVDdXN0b21Mb2dpY1xyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gY3VzdG9tTG9naWNPcHRpb25zIC0gVGhlIG9iamVjdCBjb250YWluaW5nIGBjdXN0b21Mb2dpY2BcclxuICogb3B0aW9ucy5cclxuICogQHBhcmFtIHtib29sZWFufSBhbGxvd0NvZGVFeGVjdXRpb24gLSBBIGZsYWcgaW5kaWNhdGluZyB3aGV0aGVyIGNvZGVcclxuICogZXhlY3V0aW9uIGlzIGFsbG93ZWQuXHJcbiAqXHJcbiAqIEB0aHJvd3Mge0V4cG9ydEVycm9yfSBUaHJvd3MgYW4gYEV4cG9ydEVycm9yYCBpZiBjb2RlIGV4ZWN1dGlvblxyXG4gKiBpcyBub3QgYWxsb3dlZCBidXQgY3VzdG9tIGxvZ2ljIG9wdGlvbnMgYXJlIHN0aWxsIHByb3ZpZGVkLlxyXG4gKi9cclxuZnVuY3Rpb24gX2hhbmRsZUN1c3RvbUxvZ2ljKGN1c3RvbUxvZ2ljT3B0aW9ucywgYWxsb3dDb2RlRXhlY3V0aW9uKSB7XHJcbiAgLy8gSW4gY2FzZSBvZiBhbGxvd2luZyBjb2RlIGV4ZWN1dGlvblxyXG4gIGlmIChhbGxvd0NvZGVFeGVjdXRpb24pIHtcclxuICAgIC8vIFByb2Nlc3MgdGhlIGByZXNvdXJjZXNgIG9wdGlvblxyXG4gICAgaWYgKHR5cGVvZiBjdXN0b21Mb2dpY09wdGlvbnMucmVzb3VyY2VzID09PSAnc3RyaW5nJykge1xyXG4gICAgICAvLyBDdXN0b20gc3RyaW5naWZpZWQgcmVzb3VyY2VzXHJcbiAgICAgIGN1c3RvbUxvZ2ljT3B0aW9ucy5yZXNvdXJjZXMgPSBfaGFuZGxlUmVzb3VyY2VzKFxyXG4gICAgICAgIGN1c3RvbUxvZ2ljT3B0aW9ucy5yZXNvdXJjZXMsXHJcbiAgICAgICAgY3VzdG9tTG9naWNPcHRpb25zLmFsbG93RmlsZVJlc291cmNlcyxcclxuICAgICAgICB0cnVlXHJcbiAgICAgICk7XHJcbiAgICB9IGVsc2UgaWYgKCFjdXN0b21Mb2dpY09wdGlvbnMucmVzb3VyY2VzKSB7XHJcbiAgICAgIHRyeSB7XHJcbiAgICAgICAgLy8gTG9hZCB0aGUgZGVmYXVsdCBvbmVcclxuICAgICAgICBjdXN0b21Mb2dpY09wdGlvbnMucmVzb3VyY2VzID0gX2hhbmRsZVJlc291cmNlcyhcclxuICAgICAgICAgIHJlYWRGaWxlU3luYyhnZXRBYnNvbHV0ZVBhdGgoJ3Jlc291cmNlcy5qc29uJyksICd1dGY4JyksXHJcbiAgICAgICAgICBjdXN0b21Mb2dpY09wdGlvbnMuYWxsb3dGaWxlUmVzb3VyY2VzLFxyXG4gICAgICAgICAgdHJ1ZVxyXG4gICAgICAgICk7XHJcbiAgICAgIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICAgICAgbG9nKDIsICdbY2hhcnRdIFVuYWJsZSB0byBsb2FkIHRoZSBkZWZhdWx0IGByZXNvdXJjZXMuanNvbmAgZmlsZS4nKTtcclxuICAgICAgfVxyXG4gICAgfVxyXG5cclxuICAgIC8vIFByb2Nlc3MgdGhlIGBjdXN0b21Db2RlYCBvcHRpb25cclxuICAgIHRyeSB7XHJcbiAgICAgIC8vIFRyeSB0byBsb2FkIGN1c3RvbSBjb2RlIGFuZCB3cmFwIGFyb3VuZCBpdCBpbiBhIHNlbGYgaW52b2tpbmcgZnVuY3Rpb25cclxuICAgICAgY3VzdG9tTG9naWNPcHRpb25zLmN1c3RvbUNvZGUgPSB3cmFwQXJvdW5kKFxyXG4gICAgICAgIGN1c3RvbUxvZ2ljT3B0aW9ucy5jdXN0b21Db2RlLFxyXG4gICAgICAgIGN1c3RvbUxvZ2ljT3B0aW9ucy5hbGxvd0ZpbGVSZXNvdXJjZXNcclxuICAgICAgKTtcclxuICAgIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICAgIGxvZ1dpdGhTdGFjaygyLCBlcnJvciwgJ1tjaGFydF0gVGhlIGBjdXN0b21Db2RlYCBjYW5ub3QgYmUgbG9hZGVkLicpO1xyXG5cclxuICAgICAgLy8gSW4gY2FzZSBvZiBhbiBlcnJvciwgc2V0IHRoZSBvcHRpb24gd2l0aCBudWxsXHJcbiAgICAgIGN1c3RvbUxvZ2ljT3B0aW9ucy5jdXN0b21Db2RlID0gbnVsbDtcclxuICAgIH1cclxuXHJcbiAgICAvLyBQcm9jZXNzIHRoZSBgY2FsbGJhY2tgIG9wdGlvblxyXG4gICAgdHJ5IHtcclxuICAgICAgLy8gVHJ5IHRvIGxvYWQgY2FsbGJhY2sgZnVuY3Rpb25cclxuICAgICAgY3VzdG9tTG9naWNPcHRpb25zLmNhbGxiYWNrID0gd3JhcEFyb3VuZChcclxuICAgICAgICBjdXN0b21Mb2dpY09wdGlvbnMuY2FsbGJhY2ssXHJcbiAgICAgICAgY3VzdG9tTG9naWNPcHRpb25zLmFsbG93RmlsZVJlc291cmNlcyxcclxuICAgICAgICB0cnVlXHJcbiAgICAgICk7XHJcbiAgICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgICBsb2dXaXRoU3RhY2soMiwgZXJyb3IsICdbY2hhcnRdIFRoZSBgY2FsbGJhY2tgIGNhbm5vdCBiZSBsb2FkZWQuJyk7XHJcblxyXG4gICAgICAvLyBJbiBjYXNlIG9mIGFuIGVycm9yLCBzZXQgdGhlIG9wdGlvbiB3aXRoIG51bGxcclxuICAgICAgY3VzdG9tTG9naWNPcHRpb25zLmNhbGxiYWNrID0gbnVsbDtcclxuICAgIH1cclxuXHJcbiAgICAvLyBDaGVjayBpZiB0aGVyZSBpcyB0aGUgYGN1c3RvbUNvZGVgIHByZXNlbnRcclxuICAgIGlmIChbbnVsbCwgdW5kZWZpbmVkXS5pbmNsdWRlcyhjdXN0b21Mb2dpY09wdGlvbnMuY3VzdG9tQ29kZSkpIHtcclxuICAgICAgbG9nKDMsICdbY2hhcnRdIE5vIHZhbHVlIGZvciB0aGUgYGN1c3RvbUNvZGVgIG9wdGlvbiBmb3VuZC4nKTtcclxuICAgIH1cclxuXHJcbiAgICAvLyBDaGVjayBpZiB0aGVyZSBpcyB0aGUgYGNhbGxiYWNrYCBwcmVzZW50XHJcbiAgICBpZiAoW251bGwsIHVuZGVmaW5lZF0uaW5jbHVkZXMoY3VzdG9tTG9naWNPcHRpb25zLmNhbGxiYWNrKSkge1xyXG4gICAgICBsb2coMywgJ1tjaGFydF0gTm8gdmFsdWUgZm9yIHRoZSBgY2FsbGJhY2tgIG9wdGlvbiBmb3VuZC4nKTtcclxuICAgIH1cclxuXHJcbiAgICAvLyBDaGVjayBpZiB0aGVyZSBpcyB0aGUgYHJlc291cmNlc2AgcHJlc2VudFxyXG4gICAgaWYgKFtudWxsLCB1bmRlZmluZWRdLmluY2x1ZGVzKGN1c3RvbUxvZ2ljT3B0aW9ucy5yZXNvdXJjZXMpKSB7XHJcbiAgICAgIGxvZygzLCAnW2NoYXJ0XSBObyB2YWx1ZSBmb3IgdGhlIGByZXNvdXJjZXNgIG9wdGlvbiBmb3VuZC4nKTtcclxuICAgIH1cclxuICB9IGVsc2Uge1xyXG4gICAgLy8gSWYgdGhlIGBhbGxvd0NvZGVFeGVjdXRpb25gIGZsYWcgaXMgc2V0IHRvIGZhbHNlLCB3ZSBzaG91bGQgcmVmdXNlXHJcbiAgICAvLyB0aGUgdXNhZ2Ugb2YgdGhlIGBjYWxsYmFja2AsIGByZXNvdXJjZXNgLCBhbmQgYGN1c3RvbUNvZGVgIG9wdGlvbnMuXHJcbiAgICAvLyBBZGRpdGlvbmFsbHksIHRoZSB3b3JrZXIgd2lsbCByZWZ1c2UgdG8gcnVuIGFyYml0cmFyeSBKYXZhU2NyaXB0LlxyXG4gICAgaWYgKFxyXG4gICAgICBjdXN0b21Mb2dpY09wdGlvbnMuY2FsbGJhY2sgfHxcclxuICAgICAgY3VzdG9tTG9naWNPcHRpb25zLnJlc291cmNlcyB8fFxyXG4gICAgICBjdXN0b21Mb2dpY09wdGlvbnMuY3VzdG9tQ29kZVxyXG4gICAgKSB7XHJcbiAgICAgIC8vIFJlc2V0IGFsbCBjdXN0b20gY29kZSBvcHRpb25zXHJcbiAgICAgIGN1c3RvbUxvZ2ljT3B0aW9ucy5jYWxsYmFjayA9IG51bGw7XHJcbiAgICAgIGN1c3RvbUxvZ2ljT3B0aW9ucy5yZXNvdXJjZXMgPSBudWxsO1xyXG4gICAgICBjdXN0b21Mb2dpY09wdGlvbnMuY3VzdG9tQ29kZSA9IG51bGw7XHJcblxyXG4gICAgICAvLyBTZW5kIGEgbWVzc2FnZSBzYXlpbmcgdGhhdCB0aGUgZXhwb3J0ZXIgZG9lcyBub3Qgc3VwcG9ydCB0aGVzZSBzZXR0aW5nc1xyXG4gICAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoXHJcbiAgICAgICAgYFtjaGFydF0gVGhlICdjYWxsYmFjaycsICdyZXNvdXJjZXMnLCBhbmQgJ2N1c3RvbUNvZGUnIG9wdGlvbnMgaGF2ZSBiZWVuIGRpc2FibGVkIGZvciB0aGlzIHNlcnZlci5gLFxyXG4gICAgICAgIDQwM1xyXG4gICAgICApO1xyXG4gICAgfVxyXG4gIH1cclxufVxyXG5cclxuLyoqXHJcbiAqIEhhbmRsZXMgYW5kIHZhbGlkYXRlcyByZXNvdXJjZXMgZnJvbSB0aGUgYHJlc291cmNlc2Agb3B0aW9uIGZvciBleHBvcnQuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBfaGFuZGxlUmVzb3VyY2VzXHJcbiAqXHJcbiAqIEBwYXJhbSB7KE9iamVjdHxzdHJpbmd8bnVsbCl9IFtyZXNvdXJjZXM9bnVsbF0gLSBUaGUgcmVzb3VyY2VzIHRvIGJlIGhhbmRsZWQuXHJcbiAqIENhbiBiZSBlaXRoZXIgYSBKU09OIG9iamVjdCwgc3RyaW5naWZpZWQgSlNPTiwgYSBwYXRoIHRvIGEgSlNPTiBmaWxlLFxyXG4gKiBvciBudWxsLiBUaGUgZGVmYXVsdCB2YWx1ZSBpcyBudWxsLlxyXG4gKiBAcGFyYW0ge2Jvb2xlYW59IGFsbG93RmlsZVJlc291cmNlcyAtIEEgZmxhZyBpbmRpY2F0aW5nIHdoZXRoZXIgbG9hZGluZ1xyXG4gKiByZXNvdXJjZXMgZnJvbSBmaWxlcyBpcyBhbGxvd2VkLlxyXG4gKiBAcGFyYW0ge2Jvb2xlYW59IGFsbG93Q29kZUV4ZWN1dGlvbiAtIEEgZmxhZyBpbmRpY2F0aW5nIHdoZXRoZXIgY29kZVxyXG4gKiBleGVjdXRpb24gaXMgYWxsb3dlZC5cclxuICpcclxuICogQHJldHVybnMgeyhPYmplY3R8bnVsbCl9IFRoZSBoYW5kbGVkIHJlc291cmNlcyBvciBudWxsIGlmIG5vIHZhbGlkIHJlc291cmNlc1xyXG4gKiBhcmUgZm91bmQuXHJcbiAqL1xyXG5mdW5jdGlvbiBfaGFuZGxlUmVzb3VyY2VzKFxyXG4gIHJlc291cmNlcyA9IG51bGwsXHJcbiAgYWxsb3dGaWxlUmVzb3VyY2VzLFxyXG4gIGFsbG93Q29kZUV4ZWN1dGlvblxyXG4pIHtcclxuICAvLyBMaXN0IG9mIGFsbG93ZWQgc2VjdGlvbnMgaW4gdGhlIHJlc291cmNlcyBKU09OXHJcbiAgY29uc3QgYWxsb3dlZFByb3BzID0gWydqcycsICdjc3MnLCAnZmlsZXMnXTtcclxuXHJcbiAgbGV0IGhhbmRsZWRSZXNvdXJjZXMgPSByZXNvdXJjZXM7XHJcbiAgbGV0IGNvcnJlY3RSZXNvdXJjZXMgPSBmYWxzZTtcclxuXHJcbiAgLy8gVHJ5IHRvIGxvYWQgcmVzb3VyY2VzIGZyb20gYSBmaWxlXHJcbiAgaWYgKGFsbG93RmlsZVJlc291cmNlcyAmJiByZXNvdXJjZXMuZW5kc1dpdGgoJy5qc29uJykpIHtcclxuICAgIHRyeSB7XHJcbiAgICAgIGhhbmRsZWRSZXNvdXJjZXMgPSBpc0FsbG93ZWRDb25maWcoXHJcbiAgICAgICAgcmVhZEZpbGVTeW5jKGdldEFic29sdXRlUGF0aChyZXNvdXJjZXMpLCAndXRmOCcpLFxyXG4gICAgICAgIGZhbHNlLFxyXG4gICAgICAgIGFsbG93Q29kZUV4ZWN1dGlvblxyXG4gICAgICApO1xyXG4gICAgfSBjYXRjaCB7XHJcbiAgICAgIHJldHVybiBudWxsO1xyXG4gICAgfVxyXG4gIH0gZWxzZSB7XHJcbiAgICAvLyBUcnkgdG8gZ2V0IEpTT05cclxuICAgIGhhbmRsZWRSZXNvdXJjZXMgPSBpc0FsbG93ZWRDb25maWcocmVzb3VyY2VzLCBmYWxzZSwgYWxsb3dDb2RlRXhlY3V0aW9uKTtcclxuXHJcbiAgICAvLyBHZXQgcmlkIG9mIHRoZSBmaWxlcyBzZWN0aW9uXHJcbiAgICBpZiAoaGFuZGxlZFJlc291cmNlcyAmJiAhYWxsb3dGaWxlUmVzb3VyY2VzKSB7XHJcbiAgICAgIGRlbGV0ZSBoYW5kbGVkUmVzb3VyY2VzLmZpbGVzO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgLy8gRmlsdGVyIGZyb20gdW5uZWNlc3NhcnkgcHJvcGVydGllc1xyXG4gIGZvciAoY29uc3QgcHJvcE5hbWUgaW4gaGFuZGxlZFJlc291cmNlcykge1xyXG4gICAgaWYgKCFhbGxvd2VkUHJvcHMuaW5jbHVkZXMocHJvcE5hbWUpKSB7XHJcbiAgICAgIGRlbGV0ZSBoYW5kbGVkUmVzb3VyY2VzW3Byb3BOYW1lXTtcclxuICAgIH0gZWxzZSBpZiAoIWNvcnJlY3RSZXNvdXJjZXMpIHtcclxuICAgICAgY29ycmVjdFJlc291cmNlcyA9IHRydWU7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICAvLyBDaGVjayBpZiBhdCBsZWFzdCBvbmUgb2YgYWxsb3dlZCBwcm9wZXJ0aWVzIGlzIHByZXNlbnRcclxuICBpZiAoIWNvcnJlY3RSZXNvdXJjZXMpIHtcclxuICAgIHJldHVybiBudWxsO1xyXG4gIH1cclxuXHJcbiAgLy8gSGFuZGxlIGZpbGVzIHNlY3Rpb25cclxuICBpZiAoaGFuZGxlZFJlc291cmNlcy5maWxlcykge1xyXG4gICAgaGFuZGxlZFJlc291cmNlcy5maWxlcyA9IGhhbmRsZWRSZXNvdXJjZXMuZmlsZXMubWFwKChpdGVtKSA9PiBpdGVtLnRyaW0oKSk7XHJcbiAgICBpZiAoIWhhbmRsZWRSZXNvdXJjZXMuZmlsZXMgfHwgaGFuZGxlZFJlc291cmNlcy5maWxlcy5sZW5ndGggPD0gMCkge1xyXG4gICAgICBkZWxldGUgaGFuZGxlZFJlc291cmNlcy5maWxlcztcclxuICAgIH1cclxuICB9XHJcblxyXG4gIC8vIFJldHVybiByZXNvdXJjZXNcclxuICByZXR1cm4gaGFuZGxlZFJlc291cmNlcztcclxufVxyXG5cclxuLyoqXHJcbiAqIEhhbmRsZXMgdGhlIGxvYWRpbmcgYW5kIHZhbGlkYXRpb24gb2YgdGhlIGBnbG9iYWxPcHRpb25zYCBhbmQgYHRoZW1lT3B0aW9uc2BcclxuICogaW4gdGhlIGV4cG9ydCBvcHRpb25zLiBJZiB0aGUgb3B0aW9uIGlzIGEgc3RyaW5nIGFuZCByZWZlcmVuY2VzIGEgSlNPTiBmaWxlXHJcbiAqICh3aGVuIHRoZSBgYWxsb3dGaWxlUmVzb3VyY2VzYCBpcyB0cnVlKSwgaXQgcmVhZHMgYW5kIHBhcnNlcyB0aGUgZmlsZS5cclxuICogT3RoZXJ3aXNlLCBpdCBhdHRlbXB0cyB0byBwYXJzZSB0aGUgc3RyaW5nIG9yIG9iamVjdCBhcyBKU09OLiBJZiBhbnkgZXJyb3JzXHJcbiAqIG9jY3VyIGR1cmluZyB0aGlzIHByb2Nlc3MsIHRoZSBvcHRpb24gaXMgc2V0IHRvIG51bGwuIElmIHRoZXJlIGlzIGFuIGVycm9yXHJcbiAqIGxvYWRpbmcgb3IgcGFyc2luZyB0aGUgYGdsb2JhbE9wdGlvbnNgIG9yIGB0aGVtZU9wdGlvbnNgLCB0aGUgZXJyb3IgaXMgbG9nZ2VkXHJcbiAqIGFuZCB0aGUgb3B0aW9uIGlzIHNldCB0byBudWxsLlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gX2hhbmRsZUdsb2JhbEFuZFRoZW1lXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBleHBvcnRPcHRpb25zIC0gVGhlIG9iamVjdCBjb250YWluaW5nIGBleHBvcnRgIG9wdGlvbnMuXHJcbiAqIEBwYXJhbSB7Ym9vbGVhbn0gYWxsb3dGaWxlUmVzb3VyY2VzIC0gQSBmbGFnIGluZGljYXRpbmcgd2hldGhlciBsb2FkaW5nXHJcbiAqIHJlc291cmNlcyBmcm9tIGZpbGVzIGlzIGFsbG93ZWQuXHJcbiAqIEBwYXJhbSB7Ym9vbGVhbn0gYWxsb3dDb2RlRXhlY3V0aW9uIC0gQSBmbGFnIGluZGljYXRpbmcgd2hldGhlciBjb2RlXHJcbiAqIGV4ZWN1dGlvbiBpcyBhbGxvd2VkLlxyXG4gKi9cclxuZnVuY3Rpb24gX2hhbmRsZUdsb2JhbEFuZFRoZW1lKFxyXG4gIGV4cG9ydE9wdGlvbnMsXHJcbiAgYWxsb3dGaWxlUmVzb3VyY2VzLFxyXG4gIGFsbG93Q29kZUV4ZWN1dGlvblxyXG4pIHtcclxuICAvLyBDaGVjayB0aGUgYGdsb2JhbE9wdGlvbnNgIGFuZCBgdGhlbWVPcHRpb25zYCBvcHRpb25zXHJcbiAgWydnbG9iYWxPcHRpb25zJywgJ3RoZW1lT3B0aW9ucyddLmZvckVhY2goKG9wdGlvbnNOYW1lKSA9PiB7XHJcbiAgICB0cnkge1xyXG4gICAgICAvLyBDaGVjayBpZiB0aGUgb3B0aW9uIGV4aXN0c1xyXG4gICAgICBpZiAoZXhwb3J0T3B0aW9uc1tvcHRpb25zTmFtZV0pIHtcclxuICAgICAgICAvLyBDaGVjayBpZiBpdCBpcyBhIHN0cmluZyBhbmQgYSBmaWxlIG5hbWUgd2l0aCB0aGUgYC5qc29uYCBleHRlbnNpb25cclxuICAgICAgICBpZiAoXHJcbiAgICAgICAgICBhbGxvd0ZpbGVSZXNvdXJjZXMgJiZcclxuICAgICAgICAgIHR5cGVvZiBleHBvcnRPcHRpb25zW29wdGlvbnNOYW1lXSA9PT0gJ3N0cmluZycgJiZcclxuICAgICAgICAgIGV4cG9ydE9wdGlvbnNbb3B0aW9uc05hbWVdLmVuZHNXaXRoKCcuanNvbicpXHJcbiAgICAgICAgKSB7XHJcbiAgICAgICAgICAvLyBDaGVjayBpZiB0aGUgZmlsZSBjb250ZW50IGNhbiBiZSBhIGNvbmZpZywgYW5kIHNhdmUgaXQgYXMgYSBzdHJpbmdcclxuICAgICAgICAgIGV4cG9ydE9wdGlvbnNbb3B0aW9uc05hbWVdID0gaXNBbGxvd2VkQ29uZmlnKFxyXG4gICAgICAgICAgICByZWFkRmlsZVN5bmMoZ2V0QWJzb2x1dGVQYXRoKGV4cG9ydE9wdGlvbnNbb3B0aW9uc05hbWVdKSwgJ3V0ZjgnKSxcclxuICAgICAgICAgICAgdHJ1ZSxcclxuICAgICAgICAgICAgYWxsb3dDb2RlRXhlY3V0aW9uXHJcbiAgICAgICAgICApO1xyXG4gICAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgICAvLyBDaGVjayBpZiB0aGUgdmFsdWUgY2FuIGJlIGEgY29uZmlnLCBhbmQgc2F2ZSBpdCBhcyBhIHN0cmluZ1xyXG4gICAgICAgICAgZXhwb3J0T3B0aW9uc1tvcHRpb25zTmFtZV0gPSBpc0FsbG93ZWRDb25maWcoXHJcbiAgICAgICAgICAgIGV4cG9ydE9wdGlvbnNbb3B0aW9uc05hbWVdLFxyXG4gICAgICAgICAgICB0cnVlLFxyXG4gICAgICAgICAgICBhbGxvd0NvZGVFeGVjdXRpb25cclxuICAgICAgICAgICk7XHJcbiAgICAgICAgfVxyXG4gICAgICB9XHJcbiAgICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgICBsb2dXaXRoU3RhY2soXHJcbiAgICAgICAgMixcclxuICAgICAgICBlcnJvcixcclxuICAgICAgICBgW2NoYXJ0XSBUaGUgXFxgJHtvcHRpb25zTmFtZX1cXGAgY2Fubm90IGJlIGxvYWRlZC5gXHJcbiAgICAgICk7XHJcblxyXG4gICAgICAvLyBJbiBjYXNlIG9mIGFuIGVycm9yLCBzZXQgdGhlIG9wdGlvbiB3aXRoIG51bGxcclxuICAgICAgZXhwb3J0T3B0aW9uc1tvcHRpb25zTmFtZV0gPSBudWxsO1xyXG4gICAgfVxyXG4gIH0pO1xyXG5cclxuICAvLyBDaGVjayBpZiB0aGVyZSBpcyB0aGUgYGdsb2JhbE9wdGlvbnNgIHByZXNlbnRcclxuICBpZiAoW251bGwsIHVuZGVmaW5lZF0uaW5jbHVkZXMoZXhwb3J0T3B0aW9ucy5nbG9iYWxPcHRpb25zKSkge1xyXG4gICAgbG9nKDMsICdbY2hhcnRdIE5vIHZhbHVlIGZvciB0aGUgYGdsb2JhbE9wdGlvbnNgIG9wdGlvbiBmb3VuZC4nKTtcclxuICB9XHJcblxyXG4gIC8vIENoZWNrIGlmIHRoZXJlIGlzIHRoZSBgdGhlbWVPcHRpb25zYCBwcmVzZW50XHJcbiAgaWYgKFtudWxsLCB1bmRlZmluZWRdLmluY2x1ZGVzKGV4cG9ydE9wdGlvbnMudGhlbWVPcHRpb25zKSkge1xyXG4gICAgbG9nKDMsICdbY2hhcnRdIE5vIHZhbHVlIGZvciB0aGUgYHRoZW1lT3B0aW9uc2Agb3B0aW9uIGZvdW5kLicpO1xyXG4gIH1cclxufVxyXG5cclxuZXhwb3J0IGRlZmF1bHQge1xyXG4gIHN0YXJ0RXhwb3J0LFxyXG4gIHNpbmdsZUV4cG9ydCxcclxuICBiYXRjaEV4cG9ydCxcclxuICBnZXRBbGxvd0NvZGVFeGVjdXRpb24sXHJcbiAgc2V0QWxsb3dDb2RlRXhlY3V0aW9uXHJcbn07XHJcbiIsIi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXHJcblxyXG5IaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXJcclxuXHJcbkNvcHlyaWdodCAoYykgMjAxNi0yMDI1LCBIaWdoc29mdFxyXG5cclxuTGljZW5jZWQgdW5kZXIgdGhlIE1JVCBsaWNlbmNlLlxyXG5cclxuQWRkaXRpb25hbGx5IGEgdmFsaWQgSGlnaGNoYXJ0cyBsaWNlbnNlIGlzIHJlcXVpcmVkIGZvciB1c2UuXHJcblxyXG5TZWUgTElDRU5TRSBmaWxlIGluIHJvb3QgZm9yIGRldGFpbHMuXHJcblxyXG4qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xyXG5cclxuLyoqXHJcbiAqIEBvdmVydmlldyBUaGlzIG1vZHVsZSBwcm92aWRlcyB1dGlsaXR5IGZ1bmN0aW9ucyBmb3IgbWFuYWdpbmcgaW50ZXJ2YWxzXHJcbiAqIGFuZCB0aW1lb3V0cyBpbiBhIGNlbnRyYWxpemVkIG1hbm5lci4gSXQgbWFpbnRhaW5zIGEgcmVnaXN0cnkgb2YgYWxsIGFjdGl2ZVxyXG4gKiB0aW1lcnMgYW5kIGFsbG93cyBmb3IgdGhlaXIgZWZmaWNpZW50IGNsZWFudXAgd2hlbiBuZWVkZWQuIFRoaXMgY2FuIGJlIHVzZWZ1bFxyXG4gKiBpbiBhcHBsaWNhdGlvbnMgd2hlcmUgcHJvcGVyIHJlc291cmNlIG1hbmFnZW1lbnQgYW5kIGNsZWFuIHNodXRkb3duIG9mIHRpbWVyc1xyXG4gKiBhcmUgY3JpdGljYWwgdG8gYXZvaWQgbWVtb3J5IGxlYWtzIG9yIHVuaW50ZW5kZWQgYmVoYXZpb3IuXHJcbiAqL1xyXG5cclxuaW1wb3J0IHsgbG9nIH0gZnJvbSAnLi9sb2dnZXIuanMnO1xyXG5cclxuLy8gQXJyYXkgdGhhdCBjb250YWlucyBpZHMgb2YgYWxsIG9uZ29pbmcgaW50ZXJ2YWxzIGFuZCB0aW1lb3V0c1xyXG5jb25zdCB0aW1lcklkcyA9IFtdO1xyXG5cclxuLyoqXHJcbiAqIEFkZHMgaWQgb2YgdGhlIGBzZXRJbnRlcnZhbGAgb3IgYHNldFRpbWVvdXRgIGFuZCB0byB0aGUgYHRpbWVySWRzYCBhcnJheS5cclxuICpcclxuICogQGZ1bmN0aW9uIGFkZFRpbWVyXHJcbiAqXHJcbiAqIEBwYXJhbSB7Tm9kZUpTLlRpbWVvdXR9IGlkIC0gSWQgb2YgYW4gaW50ZXJ2YWwgb3IgYSB0aW1lb3V0LlxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIGFkZFRpbWVyKGlkKSB7XHJcbiAgdGltZXJJZHMucHVzaChpZCk7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBDbGVhcnMgYWxsIG9mIG9uZ29pbmcgaW50ZXJ2YWxzIGFuZCB0aW1lb3V0cyBieSBpZHMgZ2F0aGVyZWRcclxuICogaW4gdGhlIGB0aW1lcklkc2AgYXJyYXkuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBjbGVhckFsbFRpbWVyc1xyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIGNsZWFyQWxsVGltZXJzKCkge1xyXG4gIGxvZyg0LCBgW3RpbWVyXSBDbGVhcmluZyBhbGwgcmVnaXN0ZXJlZCBpbnRlcnZhbHMgYW5kIHRpbWVvdXRzLmApO1xyXG4gIGZvciAoY29uc3QgaWQgb2YgdGltZXJJZHMpIHtcclxuICAgIGNsZWFySW50ZXJ2YWwoaWQpO1xyXG4gICAgY2xlYXJUaW1lb3V0KGlkKTtcclxuICB9XHJcbn1cclxuXHJcbmV4cG9ydCBkZWZhdWx0IHtcclxuICBhZGRUaW1lcixcclxuICBjbGVhckFsbFRpbWVyc1xyXG59O1xyXG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxyXG5cclxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXHJcblxyXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNSwgSGlnaHNvZnRcclxuXHJcbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cclxuXHJcbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxyXG5cclxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxyXG5cclxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cclxuXHJcbi8qKlxyXG4gKiBAb3ZlcnZpZXcgUHJvdmlkZXMgbWlkZGxld2FyZSBmdW5jdGlvbnMgZm9yIGxvZ2dpbmcgZXJyb3JzIHdpdGggc3RhY2sgdHJhY2VzXHJcbiAqIGFuZCBoYW5kbGluZyBlcnJvciByZXNwb25zZXMgaW4gYW4gRXhwcmVzcyBhcHBsaWNhdGlvbi5cclxuICovXHJcblxyXG5pbXBvcnQgeyBnZXRPcHRpb25zIH0gZnJvbSAnLi4vLi4vY29uZmlnLmpzJztcclxuaW1wb3J0IHsgbG9nV2l0aFN0YWNrIH0gZnJvbSAnLi4vLi4vbG9nZ2VyLmpzJztcclxuXHJcbi8qKlxyXG4gKiBNaWRkbGV3YXJlIGZvciBsb2dnaW5nIGVycm9ycyB3aXRoIHN0YWNrIHRyYWNlIGFuZCBoYW5kbGluZyBlcnJvciByZXNwb25zZS5cclxuICpcclxuICogQGZ1bmN0aW9uIGxvZ0Vycm9yTWlkZGxld2FyZVxyXG4gKlxyXG4gKiBAcGFyYW0ge0Vycm9yfSBlcnJvciAtIFRoZSBlcnJvciBvYmplY3QuXHJcbiAqIEBwYXJhbSB7RXhwcmVzcy5SZXF1ZXN0fSByZXF1ZXN0IC0gVGhlIEV4cHJlc3MgcmVxdWVzdCBvYmplY3QuXHJcbiAqIEBwYXJhbSB7RXhwcmVzcy5SZXNwb25zZX0gcmVzcG9uc2UgLSBUaGUgRXhwcmVzcyByZXNwb25zZSBvYmplY3QuXHJcbiAqIEBwYXJhbSB7RnVuY3Rpb259IG5leHQgLSBUaGUgbmV4dCBtaWRkbGV3YXJlIGZ1bmN0aW9uLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7dW5kZWZpbmVkfSBUaGUgY2FsbCB0byB0aGUgbmV4dCBtaWRkbGV3YXJlIGZ1bmN0aW9uIHdpdGhcclxuICogdGhlIHBhc3NlZCBlcnJvci5cclxuICovXHJcbmZ1bmN0aW9uIGxvZ0Vycm9yTWlkZGxld2FyZShlcnJvciwgcmVxdWVzdCwgcmVzcG9uc2UsIG5leHQpIHtcclxuICAvLyBEaXNwbGF5IHRoZSBlcnJvciB3aXRoIHN0YWNrIGluIGEgY29ycmVjdCBmb3JtYXRcclxuICBsb2dXaXRoU3RhY2soMSwgZXJyb3IpO1xyXG5cclxuICAvLyBEZWxldGUgdGhlIHN0YWNrIGZvciB0aGUgZW52aXJvbm1lbnQgb3RoZXIgdGhhbiB0aGUgZGV2ZWxvcG1lbnRcclxuICBpZiAoZ2V0T3B0aW9ucygpLm90aGVyLm5vZGVFbnYgIT09ICdkZXZlbG9wbWVudCcpIHtcclxuICAgIGRlbGV0ZSBlcnJvci5zdGFjaztcclxuICB9XHJcblxyXG4gIC8vIENhbGwgdGhlIGByZXR1cm5FcnJvck1pZGRsZXdhcmVgIG1pZGRsZXdhcmVcclxuICByZXR1cm4gbmV4dChlcnJvcik7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBNaWRkbGV3YXJlIGZvciByZXR1cm5pbmcgZXJyb3IgcmVzcG9uc2UuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiByZXR1cm5FcnJvck1pZGRsZXdhcmVcclxuICpcclxuICogQHBhcmFtIHtFcnJvcn0gZXJyb3IgLSBUaGUgZXJyb3Igb2JqZWN0LlxyXG4gKiBAcGFyYW0ge0V4cHJlc3MuUmVxdWVzdH0gcmVxdWVzdCAtIFRoZSBFeHByZXNzIHJlcXVlc3Qgb2JqZWN0LlxyXG4gKiBAcGFyYW0ge0V4cHJlc3MuUmVzcG9uc2V9IHJlc3BvbnNlIC0gVGhlIEV4cHJlc3MgcmVzcG9uc2Ugb2JqZWN0LlxyXG4gKiBAcGFyYW0ge0Z1bmN0aW9ufSBuZXh0IC0gVGhlIG5leHQgbWlkZGxld2FyZSBmdW5jdGlvbi5cclxuICovXHJcbmZ1bmN0aW9uIHJldHVybkVycm9yTWlkZGxld2FyZShlcnJvciwgcmVxdWVzdCwgcmVzcG9uc2UsIG5leHQpIHtcclxuICAvLyBHYXRoZXIgYWxsIHJlcXVpZWQgaW5mb3JtYXRpb24gZm9yIHRoZSByZXNwb25zZVxyXG4gIGNvbnN0IHsgbWVzc2FnZSwgc3RhY2sgfSA9IGVycm9yO1xyXG5cclxuICAvLyBVc2UgdGhlIGVycm9yJ3Mgc3RhdHVzIGNvZGUgb3IgdGhlIGRlZmF1bHQgNDAwXHJcbiAgY29uc3Qgc3RhdHVzQ29kZSA9IGVycm9yLnN0YXR1c0NvZGUgfHwgNDAwO1xyXG5cclxuICAvLyBTZXQgYW5kIHJldHVybiByZXNwb25zZVxyXG4gIHJlc3BvbnNlLnN0YXR1cyhzdGF0dXNDb2RlKS5qc29uKHsgc3RhdHVzQ29kZSwgbWVzc2FnZSwgc3RhY2sgfSk7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBBZGRzIHRoZSBlcnJvciBtaWRkbGV3YXJlcyB0byB0aGUgcGFzc2VkIGV4cHJlc3MgYXBwIGluc3RhbmNlLlxyXG4gKlxyXG4gKiBAcGFyYW0ge0V4cHJlc3N9IGFwcCAtIFRoZSBFeHByZXNzIGFwcCBpbnN0YW5jZS5cclxuICovXHJcbmV4cG9ydCBkZWZhdWx0IGZ1bmN0aW9uIGVycm9yTWlkZGxld2FyZShhcHApIHtcclxuICAvLyBBZGQgbG9nIGVycm9yIG1pZGRsZXdhcmVcclxuICBhcHAudXNlKGxvZ0Vycm9yTWlkZGxld2FyZSk7XHJcblxyXG4gIC8vIEFkZCBzZXQgc3RhdHVzIGFuZCByZXR1cm4gZXJyb3IgbWlkZGxld2FyZVxyXG4gIGFwcC51c2UocmV0dXJuRXJyb3JNaWRkbGV3YXJlKTtcclxufVxyXG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxyXG5cclxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXHJcblxyXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNSwgSGlnaHNvZnRcclxuXHJcbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cclxuXHJcbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxyXG5cclxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxyXG5cclxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cclxuXHJcbi8qKlxyXG4gKiBAb3ZlcnZpZXcgUHJvdmlkZXMgbWlkZGxld2FyZSBmdW5jdGlvbnMgZm9yIGNvbmZpZ3VyaW5nIGFuZCBlbmFibGluZyByYXRlXHJcbiAqIGxpbWl0aW5nIGluIGFuIEV4cHJlc3MgYXBwbGljYXRpb24uXHJcbiAqL1xyXG5cclxuaW1wb3J0IHJhdGVMaW1pdCBmcm9tICdleHByZXNzLXJhdGUtbGltaXQnO1xyXG5cclxuaW1wb3J0IHsgZ2V0T3B0aW9ucyB9IGZyb20gJy4uLy4uL2NvbmZpZy5qcyc7XHJcbmltcG9ydCB7IGxvZyB9IGZyb20gJy4uLy4uL2xvZ2dlci5qcyc7XHJcblxyXG5pbXBvcnQgRXhwb3J0RXJyb3IgZnJvbSAnLi4vLi4vZXJyb3JzL0V4cG9ydEVycm9yLmpzJztcclxuXHJcbi8qKlxyXG4gKiBNaWRkbGV3YXJlIGZvciBlbmFibGluZyByYXRlIGxpbWl0aW5nIG9uIHRoZSBzcGVjaWZpZWQgRXhwcmVzcyBhcHAuXHJcbiAqXHJcbiAqIEBwYXJhbSB7RXhwcmVzc30gYXBwIC0gVGhlIEV4cHJlc3MgYXBwIGluc3RhbmNlLlxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gW3JhdGVMaW1pdGluZ09wdGlvbnM9Z2V0T3B0aW9ucygpLnNlcnZlci5yYXRlTGltaXRpbmddIC1cclxuICogT2JqZWN0IGNvbnRhaW5pbmcgYHJhdGVMaW1pdGluZ2Agb3B0aW9ucy4gVGhlIGRlZmF1bHQgdmFsdWUgaXMgdGhlIGdsb2JhbFxyXG4gKiByYXRlIGxpbWl0aW5nIG9wdGlvbnMgb2YgdGhlIGV4cG9ydCBzZXJ2ZXIgaW5zdGFuY2UuXHJcbiAqXHJcbiAqIEB0aHJvd3Mge0V4cG9ydEVycm9yfSBUaHJvd3MgYW4gYEV4cG9ydEVycm9yYCBpZiBjb3VsZCBub3QgY29uZmlndXJlIGFuZCBzZXRcclxuICogdGhlIHJhdGUgbGltaXRpbmcgb3B0aW9ucy5cclxuICovXHJcbmV4cG9ydCBkZWZhdWx0IGZ1bmN0aW9uIHJhdGVMaW1pdGluZ01pZGRsZXdhcmUoXHJcbiAgYXBwLFxyXG4gIHJhdGVMaW1pdGluZ09wdGlvbnMgPSBnZXRPcHRpb25zKCkuc2VydmVyLnJhdGVMaW1pdGluZ1xyXG4pIHtcclxuICB0cnkge1xyXG4gICAgLy8gQ2hlY2sgaWYgdGhlIHJhdGUgbGltaXRpbmcgaXMgZW5hYmxlZFxyXG4gICAgaWYgKHJhdGVMaW1pdGluZ09wdGlvbnMuZW5hYmxlKSB7XHJcbiAgICAgIGNvbnN0IG1zZyA9XHJcbiAgICAgICAgJ1RvbyBtYW55IHJlcXVlc3RzLCB5b3UgaGF2ZSBiZWVuIHJhdGUgbGltaXRlZC4gUGxlYXNlIHRyeSBhZ2FpbiBsYXRlci4nO1xyXG5cclxuICAgICAgLy8gT3B0aW9ucyBmb3IgdGhlIHJhdGUgbGltaXRlclxyXG4gICAgICBjb25zdCByYXRlT3B0aW9ucyA9IHtcclxuICAgICAgICBtYXg6IHJhdGVMaW1pdGluZ09wdGlvbnMubWF4UmVxdWVzdHMgfHwgMzAsXHJcbiAgICAgICAgd2luZG93OiByYXRlTGltaXRpbmdPcHRpb25zLndpbmRvdyB8fCAxLFxyXG4gICAgICAgIGRlbGF5OiByYXRlTGltaXRpbmdPcHRpb25zLmRlbGF5IHx8IDAsXHJcbiAgICAgICAgdHJ1c3RQcm94eTogcmF0ZUxpbWl0aW5nT3B0aW9ucy50cnVzdFByb3h5IHx8IGZhbHNlLFxyXG4gICAgICAgIHNraXBLZXk6IHJhdGVMaW1pdGluZ09wdGlvbnMuc2tpcEtleSB8fCBmYWxzZSxcclxuICAgICAgICBza2lwVG9rZW46IHJhdGVMaW1pdGluZ09wdGlvbnMuc2tpcFRva2VuIHx8IGZhbHNlXHJcbiAgICAgIH07XHJcblxyXG4gICAgICAvLyBTZXQgaWYgYmVoaW5kIGEgcHJveHlcclxuICAgICAgaWYgKHJhdGVPcHRpb25zLnRydXN0UHJveHkpIHtcclxuICAgICAgICBhcHAuZW5hYmxlKCd0cnVzdCBwcm94eScpO1xyXG4gICAgICB9XHJcblxyXG4gICAgICAvLyBDcmVhdGUgYSBsaW1pdGVyXHJcbiAgICAgIGNvbnN0IGxpbWl0ZXIgPSByYXRlTGltaXQoe1xyXG4gICAgICAgIHdpbmRvd01zOiByYXRlT3B0aW9ucy53aW5kb3cgKiA2MCAqIDEwMDAsXHJcbiAgICAgICAgLy8gTGltaXQgZWFjaCBJUCB0byAxMDAgcmVxdWVzdHMgcGVyIHdpbmRvd01zXHJcbiAgICAgICAgbWF4OiByYXRlT3B0aW9ucy5tYXgsXHJcbiAgICAgICAgLy8gRGlzYWJsZSBkZWxheWluZywgZnVsbCBzcGVlZCB1bnRpbCB0aGUgbWF4IGxpbWl0IGlzIHJlYWNoZWRcclxuICAgICAgICBkZWxheU1zOiByYXRlT3B0aW9ucy5kZWxheSxcclxuICAgICAgICBoYW5kbGVyOiAocmVxdWVzdCwgcmVzcG9uc2UpID0+IHtcclxuICAgICAgICAgIHJlc3BvbnNlLmZvcm1hdCh7XHJcbiAgICAgICAgICAgIGpzb246ICgpID0+IHtcclxuICAgICAgICAgICAgICByZXNwb25zZS5zdGF0dXMoNDI5KS5zZW5kKHsgbWVzc2FnZTogbXNnIH0pO1xyXG4gICAgICAgICAgICB9LFxyXG4gICAgICAgICAgICBkZWZhdWx0OiAoKSA9PiB7XHJcbiAgICAgICAgICAgICAgcmVzcG9uc2Uuc3RhdHVzKDQyOSkuc2VuZChtc2cpO1xyXG4gICAgICAgICAgICB9XHJcbiAgICAgICAgICB9KTtcclxuICAgICAgICB9LFxyXG4gICAgICAgIHNraXA6IChyZXF1ZXN0KSA9PiB7XHJcbiAgICAgICAgICAvLyBBbGxvdyBieXBhc3NpbmcgdGhlIGxpbWl0ZXIgaWYgYSB2YWxpZCBrZXkvdG9rZW4gaGFzIGJlZW4gc2VudFxyXG4gICAgICAgICAgaWYgKFxyXG4gICAgICAgICAgICByYXRlT3B0aW9ucy5za2lwS2V5ICE9PSBmYWxzZSAmJlxyXG4gICAgICAgICAgICByYXRlT3B0aW9ucy5za2lwVG9rZW4gIT09IGZhbHNlICYmXHJcbiAgICAgICAgICAgIHJlcXVlc3QucXVlcnkua2V5ID09PSByYXRlT3B0aW9ucy5za2lwS2V5ICYmXHJcbiAgICAgICAgICAgIHJlcXVlc3QucXVlcnkuYWNjZXNzX3Rva2VuID09PSByYXRlT3B0aW9ucy5za2lwVG9rZW5cclxuICAgICAgICAgICkge1xyXG4gICAgICAgICAgICBsb2coNCwgJ1tyYXRlIGxpbWl0aW5nXSBTa2lwcGluZyByYXRlIGxpbWl0ZXIuJyk7XHJcbiAgICAgICAgICAgIHJldHVybiB0cnVlO1xyXG4gICAgICAgICAgfVxyXG4gICAgICAgICAgcmV0dXJuIGZhbHNlO1xyXG4gICAgICAgIH1cclxuICAgICAgfSk7XHJcblxyXG4gICAgICAvLyBVc2UgYSBsaW1pdGVyIGFzIGEgbWlkZGxld2FyZVxyXG4gICAgICBhcHAudXNlKGxpbWl0ZXIpO1xyXG5cclxuICAgICAgbG9nKFxyXG4gICAgICAgIDMsXHJcbiAgICAgICAgYFtyYXRlIGxpbWl0aW5nXSBFbmFibGVkIHJhdGUgbGltaXRpbmcgd2l0aCAke3JhdGVPcHRpb25zLm1heH0gcmVxdWVzdHMgcGVyICR7cmF0ZU9wdGlvbnMud2luZG93fSBtaW51dGUgZm9yIGVhY2ggSVAsIHRydXN0aW5nIHByb3h5OiAke3JhdGVPcHRpb25zLnRydXN0UHJveHl9LmBcclxuICAgICAgKTtcclxuICAgIH1cclxuICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgdGhyb3cgbmV3IEV4cG9ydEVycm9yKFxyXG4gICAgICAnW3JhdGUgbGltaXRpbmddIENvdWxkIG5vdCBjb25maWd1cmUgYW5kIHNldCB0aGUgcmF0ZSBsaW1pdGluZyBvcHRpb25zLicsXHJcbiAgICAgIDUwMFxyXG4gICAgKS5zZXRFcnJvcihlcnJvcik7XHJcbiAgfVxyXG59XHJcbiIsIi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXHJcblxyXG5IaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXJcclxuXHJcbkNvcHlyaWdodCAoYykgMjAxNi0yMDI1LCBIaWdoc29mdFxyXG5cclxuTGljZW5jZWQgdW5kZXIgdGhlIE1JVCBsaWNlbmNlLlxyXG5cclxuQWRkaXRpb25hbGx5IGEgdmFsaWQgSGlnaGNoYXJ0cyBsaWNlbnNlIGlzIHJlcXVpcmVkIGZvciB1c2UuXHJcblxyXG5TZWUgTElDRU5TRSBmaWxlIGluIHJvb3QgZm9yIGRldGFpbHMuXHJcblxyXG4qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xyXG5cclxuaW1wb3J0IEV4cG9ydEVycm9yIGZyb20gJy4vRXhwb3J0RXJyb3IuanMnO1xyXG5cclxuLyoqXHJcbiAqIEEgY3VzdG9tIEhUVFAgZXJyb3IgY2xhc3MgdGhhdCBleHRlbmRzIHRoZSBgRXhwb3J0RXJyb3JgLiBVc2VkIHRvIGhhbmRsZVxyXG4gKiBlcnJvcnMgd2l0aCBIVFRQIHN0YXR1cyBjb2Rlcy5cclxuICovXHJcbmNsYXNzIEh0dHBFcnJvciBleHRlbmRzIEV4cG9ydEVycm9yIHtcclxuICAvKipcclxuICAgKiBDcmVhdGVzIGFuIGluc3RhbmNlIG9mIHRoZSBgSHR0cEVycm9yYC5cclxuICAgKlxyXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBtZXNzYWdlIC0gVGhlIGVycm9yIG1lc3NhZ2UgdG8gYmUgZGlzcGxheWVkLlxyXG4gICAqIEBwYXJhbSB7bnVtYmVyfSBzdGF0dXNDb2RlIC0gT3B0aW9uYWwgSFRUUCBzdGF0dXMgY29kZSBhc3NvY2lhdGVkXHJcbiAgICogd2l0aCB0aGUgZXJyb3IgKGUuZy4sIDQwMCwgNTAwKS5cclxuICAgKi9cclxuICBjb25zdHJ1Y3RvcihtZXNzYWdlLCBzdGF0dXNDb2RlKSB7XHJcbiAgICBzdXBlcihtZXNzYWdlLCBzdGF0dXNDb2RlKTtcclxuICB9XHJcblxyXG4gIC8qKlxyXG4gICAqIFNldHMgb3IgdXBkYXRlcyB0aGUgSFRUUCBzdGF0dXMgY29kZSBmb3IgdGhlIGVycm9yLlxyXG4gICAqXHJcbiAgICogQHBhcmFtIHtudW1iZXJ9IHN0YXR1c0NvZGUgLSBUaGUgSFRUUCBzdGF0dXMgY29kZSB0byBhc3NpZ24gdG8gdGhlIGVycm9yLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge0h0dHBFcnJvcn0gVGhlIHVwZGF0ZWQgaW5zdGFuY2Ugb2YgdGhlIGBIdHRwRXJyb3JgIGNsYXNzLlxyXG4gICAqL1xyXG4gIHNldFN0YXR1cyhzdGF0dXNDb2RlKSB7XHJcbiAgICB0aGlzLnN0YXR1c0NvZGUgPSBzdGF0dXNDb2RlO1xyXG5cclxuICAgIHJldHVybiB0aGlzO1xyXG4gIH1cclxufVxyXG5cclxuZXhwb3J0IGRlZmF1bHQgSHR0cEVycm9yO1xyXG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxyXG5cclxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXHJcblxyXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNSwgSGlnaHNvZnRcclxuXHJcbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cclxuXHJcbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxyXG5cclxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxyXG5cclxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cclxuXHJcbi8qKlxyXG4gKiBAb3ZlcnZpZXcgUHJvdmlkZXMgbWlkZGxld2FyZSBmdW5jdGlvbnMgZm9yIHZhbGlkYXRpbmcgaW5jb21pbmcgSFRUUCByZXF1ZXN0c1xyXG4gKiBpbiBhbiBFeHByZXNzIGFwcGxpY2F0aW9uLiBUaGlzIG1vZHVsZSBlbnN1cmVzIHRoYXQgcmVxdWVzdHMgY29udGFpblxyXG4gKiBhcHByb3ByaWF0ZSBjb250ZW50IHR5cGVzIGFuZCB2YWxpZCByZXF1ZXN0IGJvZGllcywgaW5jbHVkaW5nIHByb3BlciBKU09OXHJcbiAqIHN0cnVjdHVyZXMgYW5kIGNoYXJ0IGRhdGEgZm9yIGV4cG9ydHMuIEl0IGNoZWNrcyBmb3IgcG90ZW50aWFsIGlzc3VlcyBzdWNoXHJcbiAqIGFzIG1pc3Npbmcgb3IgbWFsZm9ybWVkIGRhdGEsIHByaXZhdGUgcmFuZ2UgVVJMcyBpbiBTVkcgcGF5bG9hZHMsIGFuZCBhbGxvd3NcclxuICogZm9yIGZsZXhpYmxlIG9wdGlvbnMgdmFsaWRhdGlvbi4gVGhlIG1pZGRsZXdhcmUgbG9ncyBkZXRhaWxlZCBpbmZvcm1hdGlvblxyXG4gKiBhbmQgaGFuZGxlcyBlcnJvcnMgcmVsYXRlZCB0byBpbmNvcnJlY3QgcGF5bG9hZHMsIGNoYXJ0IGRhdGEsIGFuZCBwcml2YXRlIFVSTFxyXG4gKiB1c2FnZS5cclxuICovXHJcblxyXG5pbXBvcnQgeyB2NCBhcyB1dWlkIH0gZnJvbSAndXVpZCc7XHJcblxyXG5pbXBvcnQgeyBnZXRBbGxvd0NvZGVFeGVjdXRpb24gfSBmcm9tICcuLi8uLi9jaGFydC5qcyc7XHJcbmltcG9ydCB7IGlzQWxsb3dlZENvbmZpZyB9IGZyb20gJy4uLy4uL2NvbmZpZy5qcyc7XHJcbmltcG9ydCB7IGxvZywgbG9nWm9kSXNzdWVzIH0gZnJvbSAnLi4vLi4vbG9nZ2VyLmpzJztcclxuaW1wb3J0IHtcclxuICBmaXhDb25zdHIsXHJcbiAgZml4VHlwZSxcclxuICBpc09iamVjdEVtcHR5LFxyXG4gIGlzUHJpdmF0ZVJhbmdlVXJsRm91bmRcclxufSBmcm9tICcuLi8uLi91dGlscy5qcyc7XHJcbmltcG9ydCB7IGxvb3NlVmFsaWRhdGUgfSBmcm9tICcuLi8uLi92YWxpZGF0aW9uLmpzJztcclxuXHJcbmltcG9ydCBIdHRwRXJyb3IgZnJvbSAnLi4vLi4vZXJyb3JzL0h0dHBFcnJvci5qcyc7XHJcblxyXG4vKipcclxuICogTWlkZGxld2FyZSBmb3IgdmFsaWRhdGluZyB0aGUgY29udGVudC10eXBlIGhlYWRlci5cclxuICpcclxuICogQGZ1bmN0aW9uIGNvbnRlbnRUeXBlTWlkZGxld2FyZVxyXG4gKlxyXG4gKiBAcGFyYW0ge0V4cHJlc3MuUmVxdWVzdH0gcmVxdWVzdCAtIFRoZSBFeHByZXNzIHJlcXVlc3Qgb2JqZWN0LlxyXG4gKiBAcGFyYW0ge0V4cHJlc3MuUmVzcG9uc2V9IHJlc3BvbnNlIC0gVGhlIEV4cHJlc3MgcmVzcG9uc2Ugb2JqZWN0LlxyXG4gKiBAcGFyYW0ge0Z1bmN0aW9ufSBuZXh0IC0gVGhlIG5leHQgbWlkZGxld2FyZSBmdW5jdGlvbi5cclxuICpcclxuICogQHJldHVybnMge3VuZGVmaW5lZH0gVGhlIGNhbGwgdG8gdGhlIG5leHQgbWlkZGxld2FyZSBmdW5jdGlvbi5cclxuICpcclxuICogQHRocm93cyB7SHR0cEVycm9yfSBUaHJvd3MgYW4gYEh0dHBFcnJvcmAgaWYgdGhlIGNvbnRlbnQtdHlwZVxyXG4gKiBpcyBub3QgY29ycmVjdC5cclxuICovXHJcbmZ1bmN0aW9uIGNvbnRlbnRUeXBlTWlkZGxld2FyZShyZXF1ZXN0LCByZXNwb25zZSwgbmV4dCkge1xyXG4gIHRyeSB7XHJcbiAgICAvLyBHZXQgdGhlIGNvbnRlbnQgdHlwZSBoZWFkZXJcclxuICAgIGNvbnN0IGNvbnRlbnRUeXBlID0gcmVxdWVzdC5oZWFkZXJzWydjb250ZW50LXR5cGUnXSB8fCAnJztcclxuXHJcbiAgICAvLyBBbGxvdyBvbmx5IEpTT04sIFVSTC1lbmNvZGVkIGFuZCBmb3JtIGRhdGEgd2l0aG91dCBmaWxlcyB0eXBlcyBvZiBkYXRhXHJcbiAgICBpZiAoXHJcbiAgICAgICFjb250ZW50VHlwZS5pbmNsdWRlcygnYXBwbGljYXRpb24vanNvbicpICYmXHJcbiAgICAgICFjb250ZW50VHlwZS5pbmNsdWRlcygnYXBwbGljYXRpb24veC13d3ctZm9ybS11cmxlbmNvZGVkJykgJiZcclxuICAgICAgIWNvbnRlbnRUeXBlLmluY2x1ZGVzKCdtdWx0aXBhcnQvZm9ybS1kYXRhJylcclxuICAgICkge1xyXG4gICAgICB0aHJvdyBuZXcgSHR0cEVycm9yKFxyXG4gICAgICAgICdbdmFsaWRhdGlvbl0gQ29udGVudC1UeXBlIG11c3QgYmUgYXBwbGljYXRpb24vanNvbiwgYXBwbGljYXRpb24veC13d3ctZm9ybS11cmxlbmNvZGVkLCBvciBtdWx0aXBhcnQvZm9ybS1kYXRhLicsXHJcbiAgICAgICAgNDE1XHJcbiAgICAgICk7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gQ2FsbCB0aGUgYHJlcXVlc3RCb2R5TWlkZGxld2FyZWAgbWlkZGxld2FyZVxyXG4gICAgcmV0dXJuIG5leHQoKTtcclxuICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgcmV0dXJuIG5leHQoZXJyb3IpO1xyXG4gIH1cclxufVxyXG5cclxuLyoqXHJcbiAqIE1pZGRsZXdhcmUgZm9yIHZhbGlkYXRpbmcgdGhlIHJlcXVlc3QncyBib2R5LlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gcmVxdWVzdEJvZHlNaWRkbGV3YXJlXHJcbiAqXHJcbiAqIEBwYXJhbSB7RXhwcmVzcy5SZXF1ZXN0fSByZXF1ZXN0IC0gVGhlIEV4cHJlc3MgcmVxdWVzdCBvYmplY3QuXHJcbiAqIEBwYXJhbSB7RXhwcmVzcy5SZXNwb25zZX0gcmVzcG9uc2UgLSBUaGUgRXhwcmVzcyByZXNwb25zZSBvYmplY3QuXHJcbiAqIEBwYXJhbSB7RnVuY3Rpb259IG5leHQgLSBUaGUgbmV4dCBtaWRkbGV3YXJlIGZ1bmN0aW9uLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7dW5kZWZpbmVkfSBUaGUgY2FsbCB0byB0aGUgbmV4dCBtaWRkbGV3YXJlIGZ1bmN0aW9uLlxyXG4gKlxyXG4gKiBAdGhyb3dzIHtIdHRwRXJyb3J9IFRocm93cyBhbiBgSHR0cEVycm9yYCBpZiB0aGUgYm9keSBpcyBub3QgY29ycmVjdC5cclxuICogQHRocm93cyB7SHR0cEVycm9yfSBUaHJvd3MgYW4gYEh0dHBFcnJvcmAgaWYgdGhlIGNoYXJ0IGRhdGEgZnJvbSB0aGUgYm9keVxyXG4gKiBpcyBub3QgY29ycmVjdC5cclxuICogQHRocm93cyB7SHR0cEVycm9yfSBUaHJvd3MgYW4gYEh0dHBFcnJvcmAgaW4gY2FzZSBvZiB0aGUgcHJpdmF0ZSByYW5nZSB1cmxcclxuICogZXJyb3IuXHJcbiAqL1xyXG5mdW5jdGlvbiByZXF1ZXN0Qm9keU1pZGRsZXdhcmUocmVxdWVzdCwgcmVzcG9uc2UsIG5leHQpIHtcclxuICB0cnkge1xyXG4gICAgLy8gR2V0IHRoZSByZXF1ZXN0IGJvZHlcclxuICAgIGNvbnN0IGJvZHkgPSByZXF1ZXN0LmJvZHk7XHJcblxyXG4gICAgLy8gQ3JlYXRlIGEgdW5pcXVlIElEIGZvciBhIHJlcXVlc3RcclxuICAgIGNvbnN0IHJlcXVlc3RJZCA9IHV1aWQoKS5yZXBsYWNlKC8tL2csICcnKTtcclxuXHJcbiAgICAvLyBUaHJvdyBhbiBlcnJvciBpZiB0aGVyZSBpcyBubyBjb3JyZWN0IGJvZHlcclxuICAgIGlmICghYm9keSB8fCBpc09iamVjdEVtcHR5KGJvZHkpKSB7XHJcbiAgICAgIGxvZyhcclxuICAgICAgICAyLFxyXG4gICAgICAgIGBbdmFsaWRhdGlvbl0gUmVxdWVzdCBbJHtyZXF1ZXN0SWR9XSAtIFRoZSByZXF1ZXN0IGZyb20gJHtcclxuICAgICAgICAgIHJlcXVlc3QuaGVhZGVyc1sneC1mb3J3YXJkZWQtZm9yJ10gfHwgcmVxdWVzdC5jb25uZWN0aW9uLnJlbW90ZUFkZHJlc3NcclxuICAgICAgICB9IHdhcyBpbmNvcnJlY3QuIFJlY2VpdmVkIHBheWxvYWQgaXMgZW1wdHkuYFxyXG4gICAgICApO1xyXG5cclxuICAgICAgdGhyb3cgbmV3IEh0dHBFcnJvcihcclxuICAgICAgICBcIlt2YWxpZGF0aW9uXSBUaGUgcmVxdWVzdCBib2R5IGlzIHJlcXVpcmVkLiBQbGVhc2UgZW5zdXJlIHRoYXQgeW91ciBDb250ZW50LVR5cGUgaGVhZGVyIGlzIGNvcnJlY3QuIEFjY2VwdGVkIHR5cGVzIGFyZSAnYXBwbGljYXRpb24vanNvbicgYW5kICdtdWx0aXBhcnQvZm9ybS1kYXRhJy5cIixcclxuICAgICAgICA0MDBcclxuICAgICAgKTtcclxuICAgIH1cclxuXHJcbiAgICAvLyBHZXQgdGhlIGBhbGxvd0NvZGVFeGVjdXRpb25gIG9wdGlvbiBmb3IgdGhlIHNlcnZlclxyXG4gICAgY29uc3QgYWxsb3dDb2RlRXhlY3V0aW9uID0gZ2V0QWxsb3dDb2RlRXhlY3V0aW9uKCk7XHJcblxyXG4gICAgLy8gRmluZCBhIGNvcnJlY3QgY2hhcnQgb3B0aW9uc1xyXG4gICAgY29uc3QgaW5zdHIgPSBpc0FsbG93ZWRDb25maWcoXHJcbiAgICAgIC8vIFVzZSBvbmUgb2YgdGhlIGJlbG93XHJcbiAgICAgIGJvZHkuaW5zdHIgfHwgYm9keS5vcHRpb25zIHx8IGJvZHkuaW5maWxlIHx8IGJvZHkuZGF0YSxcclxuICAgICAgLy8gU3RyaW5naWZ5IG9wdGlvbnNcclxuICAgICAgdHJ1ZSxcclxuICAgICAgLy8gQWxsb3cgb3IgZGlzYWxsb3cgZnVuY3Rpb25zXHJcbiAgICAgIGFsbG93Q29kZUV4ZWN1dGlvblxyXG4gICAgKTtcclxuXHJcbiAgICAvLyBUaHJvdyBhbiBlcnJvciBpZiB0aGVyZSBpcyBubyBjb3JyZWN0IGNoYXJ0IGRhdGFcclxuICAgIGlmIChpbnN0ciA9PT0gbnVsbCAmJiAhYm9keS5zdmcpIHtcclxuICAgICAgbG9nKFxyXG4gICAgICAgIDIsXHJcbiAgICAgICAgYFt2YWxpZGF0aW9uXSBSZXF1ZXN0IFske3JlcXVlc3RJZH1dIC0gVGhlIHJlcXVlc3QgZnJvbSAke1xyXG4gICAgICAgICAgcmVxdWVzdC5oZWFkZXJzWyd4LWZvcndhcmRlZC1mb3InXSB8fCByZXF1ZXN0LmNvbm5lY3Rpb24ucmVtb3RlQWRkcmVzc1xyXG4gICAgICAgIH0gd2FzIGluY29ycmVjdC4gUmVjZWl2ZWQgcGF5bG9hZCBpcyBtaXNzaW5nIGNvcnJlY3QgY2hhcnQgZGF0YSBmb3IgZXhwb3J0OiAke0pTT04uc3RyaW5naWZ5KGJvZHkpfS5gXHJcbiAgICAgICk7XHJcblxyXG4gICAgICB0aHJvdyBuZXcgSHR0cEVycm9yKFxyXG4gICAgICAgIFwiW3ZhbGlkYXRpb25dIE5vIGNvcnJlY3QgY2hhcnQgZGF0YSBmb3VuZC4gRW5zdXJlIHRoYXQgeW91IGFyZSB1c2luZyBlaXRoZXIgYXBwbGljYXRpb24vanNvbiBvciBtdWx0aXBhcnQvZm9ybS1kYXRhIGhlYWRlcnMuIElmIHNlbmRpbmcgSlNPTiwgbWFrZSBzdXJlIHRoZSBjaGFydCBkYXRhIGlzIGluIHRoZSAnaW5maWxlJywgJ29wdGlvbnMnLCBvciAnZGF0YScgYXR0cmlidXRlLiBJZiBzZW5kaW5nIFNWRywgZW5zdXJlIGl0IGlzIGluIHRoZSAnc3ZnJyBhdHRyaWJ1dGUuXCIsXHJcbiAgICAgICAgNDAwXHJcbiAgICAgICk7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gVGhyb3cgYW4gZXJyb3IgaWYgdGVzdCBvZiB4bGluazpocmVmIGVsZW1lbnRzIGZyb20gcGF5bG9hZCdzIFNWRyBmYWlsc1xyXG4gICAgaWYgKGJvZHkuc3ZnICYmIGlzUHJpdmF0ZVJhbmdlVXJsRm91bmQoYm9keS5zdmcpKSB7XHJcbiAgICAgIHRocm93IG5ldyBIdHRwRXJyb3IoXHJcbiAgICAgICAgXCJbdmFsaWRhdGlvbl0gU1ZHIHBvdGVudGlhbGx5IGNvbnRhaW4gYXQgbGVhc3Qgb25lIGZvcmJpZGRlbiBVUkwgaW4gJ3hsaW5rOmhyZWYnIGVsZW1lbnQuIFBsZWFzZSByZXZpZXcgdGhlIFNWRyBjb250ZW50IGFuZCBlbnN1cmUgdGhhdCBhbGwgcmVmZXJlbmNlZCBVUkxzIGNvbXBseSB3aXRoIHNlY3VyaXR5IHBvbGljaWVzLlwiLFxyXG4gICAgICAgIDQwMFxyXG4gICAgICApO1xyXG4gICAgfVxyXG5cclxuICAgIHRyeSB7XHJcbiAgICAgIC8vIFZhbGlkYXRlIG9wdGlvbnMgZnJvbSB0aGUgYm9keSBhbmQgc3RvcmUgcGFyc2VkIHN0cnVjdHVyZSBpbiB0aGUgcmVxdWVzdFxyXG4gICAgICByZXF1ZXN0LnZhbGlkYXRlZE9wdGlvbnMgPSBsb29zZVZhbGlkYXRlKHtcclxuICAgICAgICAvLyBTZXQgdGhlIGNyZWF0ZWQgSUQgYXMgYSBgX3JlcXVlc3RJZGAgcHJvcGVydHkgaW4gdGhlIHZhbGlkYXRlZCBvcHRpb25zXHJcbiAgICAgICAgX3JlcXVlc3RJZDogcmVxdWVzdElkLFxyXG4gICAgICAgIGV4cG9ydDoge1xyXG4gICAgICAgICAgaW5zdHIsXHJcbiAgICAgICAgICBzdmc6IGJvZHkuc3ZnLFxyXG4gICAgICAgICAgb3V0ZmlsZTpcclxuICAgICAgICAgICAgYm9keS5vdXRmaWxlIHx8XHJcbiAgICAgICAgICAgIGAke3JlcXVlc3QucGFyYW1zLmZpbGVuYW1lIHx8ICdjaGFydCd9LiR7Zml4VHlwZShib2R5LnR5cGUpfWAsXHJcbiAgICAgICAgICB0eXBlOiBmaXhUeXBlKGJvZHkudHlwZSwgYm9keS5vdXRmaWxlKSxcclxuICAgICAgICAgIGNvbnN0cjogZml4Q29uc3RyKGJvZHkuY29uc3RyKSxcclxuICAgICAgICAgIGI2NDogYm9keS5iNjQsXHJcbiAgICAgICAgICBub0Rvd25sb2FkOiBib2R5Lm5vRG93bmxvYWQsXHJcbiAgICAgICAgICBoZWlnaHQ6IGJvZHkuaGVpZ2h0LFxyXG4gICAgICAgICAgd2lkdGg6IGJvZHkud2lkdGgsXHJcbiAgICAgICAgICBzY2FsZTogYm9keS5zY2FsZSxcclxuICAgICAgICAgIGdsb2JhbE9wdGlvbnM6IGlzQWxsb3dlZENvbmZpZyhcclxuICAgICAgICAgICAgYm9keS5nbG9iYWxPcHRpb25zLFxyXG4gICAgICAgICAgICB0cnVlLFxyXG4gICAgICAgICAgICBhbGxvd0NvZGVFeGVjdXRpb25cclxuICAgICAgICAgICksXHJcbiAgICAgICAgICB0aGVtZU9wdGlvbnM6IGlzQWxsb3dlZENvbmZpZyhcclxuICAgICAgICAgICAgYm9keS50aGVtZU9wdGlvbnMsXHJcbiAgICAgICAgICAgIHRydWUsXHJcbiAgICAgICAgICAgIGFsbG93Q29kZUV4ZWN1dGlvblxyXG4gICAgICAgICAgKVxyXG4gICAgICAgIH0sXHJcbiAgICAgICAgY3VzdG9tTG9naWM6IHtcclxuICAgICAgICAgIGFsbG93Q29kZUV4ZWN1dGlvbixcclxuICAgICAgICAgIGFsbG93RmlsZVJlc291cmNlczogZmFsc2UsXHJcbiAgICAgICAgICBjdXN0b21Db2RlOiBib2R5LmN1c3RvbUNvZGUsXHJcbiAgICAgICAgICBjYWxsYmFjazogYm9keS5jYWxsYmFjayxcclxuICAgICAgICAgIHJlc291cmNlczogaXNBbGxvd2VkQ29uZmlnKGJvZHkucmVzb3VyY2VzLCB0cnVlLCBhbGxvd0NvZGVFeGVjdXRpb24pXHJcbiAgICAgICAgfVxyXG4gICAgICB9KTtcclxuICAgIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICAgIGxvZ1pvZElzc3VlcyhcclxuICAgICAgICAxLFxyXG4gICAgICAgIGVycm9yLmlzc3VlcyxcclxuICAgICAgICAnW2NvbmZpZ10gUmVxdWVzdCBvcHRpb25zIHZhbGlkYXRpb24gZXJyb3InXHJcbiAgICAgICk7XHJcblxyXG4gICAgICB0aHJvdyBuZXcgSHR0cEVycm9yKFxyXG4gICAgICAgICdUaGUgcHJvdmlkZWQgb3B0aW9ucyBhcmUgbm90IGNvcnJlY3QuIFBsZWFzZSBjaGVjayBpZiB5b3VyIGRhdGEgaXMgb2YgdGhlIGNvcnJlY3QgdHlwZXMuJyxcclxuICAgICAgICA0MDBcclxuICAgICAgKTtcclxuICAgIH1cclxuXHJcbiAgICAvLyBDYWxsIHRoZSBuZXh0IG1pZGRsZXdhcmVcclxuICAgIHJldHVybiBuZXh0KCk7XHJcbiAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgIHJldHVybiBuZXh0KGVycm9yKTtcclxuICB9XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBBZGRzIHRoZSB2YWxpZGF0aW9uIG1pZGRsZXdhcmVzIHRvIHRoZSBwYXNzZWQgZXhwcmVzcyBhcHAgaW5zdGFuY2UuXHJcbiAqXHJcbiAqIEBwYXJhbSB7RXhwcmVzc30gYXBwIC0gVGhlIEV4cHJlc3MgYXBwIGluc3RhbmNlLlxyXG4gKi9cclxuZXhwb3J0IGRlZmF1bHQgZnVuY3Rpb24gdmFsaWRhdGlvbk1pZGRsZXdhcmUoYXBwKSB7XHJcbiAgLy8gQWRkIGNvbnRlbnQgdHlwZSB2YWxpZGF0aW9uIG1pZGRsZXdhcmVcclxuICBhcHAucG9zdChbJy8nLCAnLzpmaWxlbmFtZSddLCBjb250ZW50VHlwZU1pZGRsZXdhcmUpO1xyXG5cclxuICAvLyBBZGQgcmVxdWVzdCBib2R5IHJlcXVlc3QgdmFsaWRhdGlvbiBtaWRkbGV3YXJlXHJcbiAgYXBwLnBvc3QoWycvJywgJy86ZmlsZW5hbWUnXSwgcmVxdWVzdEJvZHlNaWRkbGV3YXJlKTtcclxufVxyXG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxyXG5cclxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXHJcblxyXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNSwgSGlnaHNvZnRcclxuXHJcbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cclxuXHJcbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxyXG5cclxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxyXG5cclxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cclxuXHJcbi8qKlxyXG4gKiBAb3ZlcnZpZXcgRGVmaW5lcyB0aGUgZXhwb3J0IHJvdXRlcyBhbmQgbG9naWMgZm9yIGhhbmRsaW5nIGNoYXJ0IGV4cG9ydFxyXG4gKiByZXF1ZXN0cyBpbiBhbiBFeHByZXNzIHNlcnZlci4gVGhpcyBtb2R1bGUgcHJvY2Vzc2VzIGluY29taW5nIHJlcXVlc3RzXHJcbiAqIHRvIGV4cG9ydCBjaGFydHMgaW4gdmFyaW91cyBmb3JtYXRzIChlLmcuIEpQRUcsIFBORywgUERGLCBTVkcpLiBJdCBpbnRlZ3JhdGVzXHJcbiAqIHdpdGggSGlnaGNoYXJ0cycgY29yZSBmdW5jdGlvbmFsaXRpZXMgYW5kIHN1cHBvcnRzIGJvdGggaW1tZWRpYXRlIGRvd25sb2FkXHJcbiAqIHJlc3BvbnNlcyBhbmQgQmFzZTY0LWVuY29kZWQgY29udGVudCByZXR1cm5zLiBUaGUgY29kZSBhbHNvIGZlYXR1cmVzXHJcbiAqIGJlbmNobWFya2luZyBmb3IgcGVyZm9ybWFuY2UgbW9uaXRvcmluZy5cclxuICovXHJcblxyXG5pbXBvcnQgeyBzdGFydEV4cG9ydCB9IGZyb20gJy4uLy4uL2NoYXJ0LmpzJztcclxuaW1wb3J0IHsgbG9nIH0gZnJvbSAnLi4vLi4vbG9nZ2VyLmpzJztcclxuaW1wb3J0IHsgZ2V0QmFzZTY0LCBtZWFzdXJlVGltZSB9IGZyb20gJy4uLy4uL3V0aWxzLmpzJztcclxuXHJcbmltcG9ydCBIdHRwRXJyb3IgZnJvbSAnLi4vLi4vZXJyb3JzL0h0dHBFcnJvci5qcyc7XHJcblxyXG4vLyBSZXZlcnNlZCBNSU1FIHR5cGVzXHJcbmNvbnN0IHJldmVyc2VkTWltZSA9IHtcclxuICBwbmc6ICdpbWFnZS9wbmcnLFxyXG4gIGpwZWc6ICdpbWFnZS9qcGVnJyxcclxuICBnaWY6ICdpbWFnZS9naWYnLFxyXG4gIHBkZjogJ2FwcGxpY2F0aW9uL3BkZicsXHJcbiAgc3ZnOiAnaW1hZ2Uvc3ZnK3htbCdcclxufTtcclxuXHJcbi8qKlxyXG4gKiBIYW5kbGVzIHRoZSBleHBvcnQgcmVxdWVzdHMgZnJvbSB0aGUgY2xpZW50LlxyXG4gKlxyXG4gKiBAYXN5bmNcclxuICogQGZ1bmN0aW9uIHJlcXVlc3RFeHBvcnRcclxuICpcclxuICogQHBhcmFtIHtFeHByZXNzLlJlcXVlc3R9IHJlcXVlc3QgLSBUaGUgRXhwcmVzcyByZXF1ZXN0IG9iamVjdC5cclxuICogQHBhcmFtIHtFeHByZXNzLlJlc3BvbnNlfSByZXNwb25zZSAtIFRoZSBFeHByZXNzIHJlc3BvbnNlIG9iamVjdC5cclxuICogQHBhcmFtIHtGdW5jdGlvbn0gbmV4dCAtIFRoZSBuZXh0IG1pZGRsZXdhcmUgZnVuY3Rpb24uXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtQcm9taXNlPHZvaWQ+fSBBIFByb21pc2UgdGhhdCByZXNvbHZlcyBvbmNlIHRoZSBleHBvcnQgcHJvY2Vzc1xyXG4gKiBpcyBjb21wbGV0ZS5cclxuICovXHJcbmFzeW5jIGZ1bmN0aW9uIHJlcXVlc3RFeHBvcnQocmVxdWVzdCwgcmVzcG9uc2UsIG5leHQpIHtcclxuICB0cnkge1xyXG4gICAgLy8gU3RhcnQgY291bnRpbmcgdGltZSBmb3IgYSByZXF1ZXN0XHJcbiAgICBjb25zdCByZXF1ZXN0Q291bnRlciA9IG1lYXN1cmVUaW1lKCk7XHJcblxyXG4gICAgLy8gSW4gY2FzZSB0aGUgY29ubmVjdGlvbiBpcyBjbG9zZWQsIGZvcmNlIHRvIGFib3J0IGZ1cnRoZXIgYWN0aW9uc1xyXG4gICAgbGV0IGNvbm5lY3Rpb25BYm9ydGVkID0gZmFsc2U7XHJcbiAgICByZXF1ZXN0LnNvY2tldC5vbignY2xvc2UnLCAoaGFkRXJyb3JzKSA9PiB7XHJcbiAgICAgIGlmIChoYWRFcnJvcnMpIHtcclxuICAgICAgICBjb25uZWN0aW9uQWJvcnRlZCA9IHRydWU7XHJcbiAgICAgIH1cclxuICAgIH0pO1xyXG5cclxuICAgIC8vIEdldCB0aGUgb3B0aW9ucyBwcmV2aW91c2x5IHZhbGlkYXRlZCBpbiB0aGUgdmFsaWRhdGlvbiBtaWRkbGV3YXJlXHJcbiAgICBjb25zdCByZXF1ZXN0T3B0aW9ucyA9IHJlcXVlc3QudmFsaWRhdGVkT3B0aW9ucztcclxuXHJcbiAgICAvLyBHZXQgdGhlIHJlcXVlc3QgaWRcclxuICAgIGNvbnN0IHJlcXVlc3RJZCA9IHJlcXVlc3RPcHRpb25zLl9yZXF1ZXN0SWQ7XHJcblxyXG4gICAgLy8gSW5mbyBhYm91dCBhbiBpbmNvbWluZyByZXF1ZXN0IHdpdGggY29ycmVjdCBkYXRhXHJcbiAgICBsb2coNCwgYFtleHBvcnRdIEdvdCBhbiBpbmNvbWluZyBIVFRQIHJlcXVlc3Qgd2l0aCBJRCAke3JlcXVlc3RJZH0uYCk7XHJcblxyXG4gICAgLy8gU3RhcnQgdGhlIGV4cG9ydCBwcm9jZXNzXHJcbiAgICBhd2FpdCBzdGFydEV4cG9ydChyZXF1ZXN0T3B0aW9ucywgKGVycm9yLCBkYXRhKSA9PiB7XHJcbiAgICAgIC8vIFJlbW92ZSB0aGUgY2xvc2UgZXZlbnQgZnJvbSB0aGUgc29ja2V0XHJcbiAgICAgIHJlcXVlc3Quc29ja2V0LnJlbW92ZUFsbExpc3RlbmVycygnY2xvc2UnKTtcclxuXHJcbiAgICAgIC8vIElmIHRoZSBjb25uZWN0aW9uIHdhcyBjbG9zZWQsIGRvIG5vdGhpbmdcclxuICAgICAgaWYgKGNvbm5lY3Rpb25BYm9ydGVkKSB7XHJcbiAgICAgICAgbG9nKFxyXG4gICAgICAgICAgMyxcclxuICAgICAgICAgIGBbZXhwb3J0XSBSZXF1ZXN0IFske3JlcXVlc3RJZH1dIC0gVGhlIGNsaWVudCBjbG9zZWQgdGhlIGNvbm5lY3Rpb24gYmVmb3JlIHRoZSBjaGFydCBmaW5pc2hlZCBwcm9jZXNzaW5nLmBcclxuICAgICAgICApO1xyXG4gICAgICAgIHJldHVybjtcclxuICAgICAgfVxyXG5cclxuICAgICAgLy8gSWYgZXJyb3IsIGxvZyBpdCBhbmQgc2VuZCBpdCB0byB0aGUgZXJyb3IgbWlkZGxld2FyZVxyXG4gICAgICBpZiAoZXJyb3IpIHtcclxuICAgICAgICB0aHJvdyBlcnJvcjtcclxuICAgICAgfVxyXG5cclxuICAgICAgLy8gSWYgZGF0YSBpcyBtaXNzaW5nLCBsb2cgdGhlIG1lc3NhZ2UgYW5kIHNlbmQgaXQgdG8gdGhlIGVycm9yIG1pZGRsZXdhcmVcclxuICAgICAgaWYgKCFkYXRhIHx8ICFkYXRhLnJlc3VsdCkge1xyXG4gICAgICAgIGxvZyhcclxuICAgICAgICAgIDIsXHJcbiAgICAgICAgICBgW2V4cG9ydF0gUmVxdWVzdCBbJHtyZXF1ZXN0SWR9XSAtIFJlcXVlc3QgZnJvbSAke1xyXG4gICAgICAgICAgICByZXF1ZXN0LmhlYWRlcnNbJ3gtZm9yd2FyZGVkLWZvciddIHx8XHJcbiAgICAgICAgICAgIHJlcXVlc3QuY29ubmVjdGlvbi5yZW1vdGVBZGRyZXNzXHJcbiAgICAgICAgICB9IHdhcyBpbmNvcnJlY3QuIFJlY2VpdmVkIHJlc3VsdCBpcyAke2RhdGEucmVzdWx0fS5gXHJcbiAgICAgICAgKTtcclxuXHJcbiAgICAgICAgdGhyb3cgbmV3IEh0dHBFcnJvcihcclxuICAgICAgICAgICdbZXhwb3J0XSBVbmV4cGVjdGVkIHJldHVybiBvZiB0aGUgZXhwb3J0IHJlc3VsdCBmcm9tIHRoZSBjaGFydCBnZW5lcmF0aW9uLiBQbGVhc2UgY2hlY2sgeW91ciByZXF1ZXN0IGRhdGEuJyxcclxuICAgICAgICAgIDQwMFxyXG4gICAgICAgICk7XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIC8vIFJldHVybiB0aGUgcmVzdWx0IGluIGFuIGFwcHJvcHJpYXRlIGZvcm1hdFxyXG4gICAgICBpZiAoZGF0YS5yZXN1bHQpIHtcclxuICAgICAgICBsb2coXHJcbiAgICAgICAgICAzLFxyXG4gICAgICAgICAgYFtleHBvcnRdIFJlcXVlc3QgWyR7cmVxdWVzdElkfV0gLSBUaGUgd2hvbGUgZXhwb3J0aW5nIHByb2Nlc3MgdG9vayAke3JlcXVlc3RDb3VudGVyKCl9bXMuYFxyXG4gICAgICAgICk7XHJcblxyXG4gICAgICAgIC8vIEdldCB0aGUgYHR5cGVgLCBgYjY0YCwgYG5vRG93bmxvYWRgLCBhbmQgYG91dGZpbGVgIGZyb20gb3B0aW9uc1xyXG4gICAgICAgIGNvbnN0IHsgdHlwZSwgYjY0LCBub0Rvd25sb2FkLCBvdXRmaWxlIH0gPSBkYXRhLm9wdGlvbnMuZXhwb3J0O1xyXG5cclxuICAgICAgICAvLyBJZiBvbmx5IEJhc2U2NCBpcyByZXF1aXJlZCwgcmV0dXJuIGl0XHJcbiAgICAgICAgaWYgKGI2NCkge1xyXG4gICAgICAgICAgcmV0dXJuIHJlc3BvbnNlLnNlbmQoZ2V0QmFzZTY0KGRhdGEucmVzdWx0LCB0eXBlKSk7XHJcbiAgICAgICAgfVxyXG5cclxuICAgICAgICAvLyBTZXQgY29ycmVjdCBjb250ZW50IHR5cGVcclxuICAgICAgICByZXNwb25zZS5oZWFkZXIoJ0NvbnRlbnQtVHlwZScsIHJldmVyc2VkTWltZVt0eXBlXSB8fCAnaW1hZ2UvcG5nJyk7XHJcblxyXG4gICAgICAgIC8vIERlY2lkZSB3aGV0aGVyIHRvIGRvd25sb2FkIG9yIG5vdCBjaGFydCBmaWxlXHJcbiAgICAgICAgaWYgKCFub0Rvd25sb2FkKSB7XHJcbiAgICAgICAgICByZXNwb25zZS5hdHRhY2htZW50KG91dGZpbGUpO1xyXG4gICAgICAgIH1cclxuXHJcbiAgICAgICAgLy8gSWYgU1ZHLCByZXR1cm4gcGxhaW4gY29udGVudCwgb3RoZXJ3aXNlIGEgYjY0IHN0cmluZyBmcm9tIGEgYnVmZmVyXHJcbiAgICAgICAgcmV0dXJuIHR5cGUgPT09ICdzdmcnXHJcbiAgICAgICAgICA/IHJlc3BvbnNlLnNlbmQoZGF0YS5yZXN1bHQpXHJcbiAgICAgICAgICA6IHJlc3BvbnNlLnNlbmQoQnVmZmVyLmZyb20oZGF0YS5yZXN1bHQsICdiYXNlNjQnKSk7XHJcbiAgICAgIH1cclxuICAgIH0pO1xyXG4gIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICByZXR1cm4gbmV4dChlcnJvcik7XHJcbiAgfVxyXG59XHJcblxyXG4vKipcclxuICogQWRkcyB0aGUgYGV4cG9ydGAgcm91dGVzLlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gZXhwb3J0Um91dGVzXHJcbiAqXHJcbiAqIEBwYXJhbSB7RXhwcmVzc30gYXBwIC0gVGhlIEV4cHJlc3MgYXBwIGluc3RhbmNlLlxyXG4gKi9cclxuZXhwb3J0IGRlZmF1bHQgZnVuY3Rpb24gZXhwb3J0Um91dGVzKGFwcCkge1xyXG4gIC8qKlxyXG4gICAqIEFkZHMgdGhlIFBPU1QgJy8nIC0gQSByb3V0ZSBmb3IgaGFuZGxpbmcgUE9TVCByZXF1ZXN0cyBhdCB0aGUgcm9vdFxyXG4gICAqIGVuZHBvaW50LlxyXG4gICAqL1xyXG4gIGFwcC5wb3N0KCcvJywgcmVxdWVzdEV4cG9ydCk7XHJcblxyXG4gIC8qKlxyXG4gICAqIEFkZHMgdGhlIFBPU1QgJy86ZmlsZW5hbWUnIC0gQSByb3V0ZSBmb3IgaGFuZGxpbmcgUE9TVCByZXF1ZXN0cyB3aXRoXHJcbiAgICogYSBzcGVjaWZpZWQgZmlsZW5hbWUgcGFyYW1ldGVyLlxyXG4gICAqL1xyXG4gIGFwcC5wb3N0KCcvOmZpbGVuYW1lJywgcmVxdWVzdEV4cG9ydCk7XHJcbn1cclxuIiwiLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcclxuXHJcbkhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlclxyXG5cclxuQ29weXJpZ2h0IChjKSAyMDE2LTIwMjUsIEhpZ2hzb2Z0XHJcblxyXG5MaWNlbmNlZCB1bmRlciB0aGUgTUlUIGxpY2VuY2UuXHJcblxyXG5BZGRpdGlvbmFsbHkgYSB2YWxpZCBIaWdoY2hhcnRzIGxpY2Vuc2UgaXMgcmVxdWlyZWQgZm9yIHVzZS5cclxuXHJcblNlZSBMSUNFTlNFIGZpbGUgaW4gcm9vdCBmb3IgZGV0YWlscy5cclxuXHJcbioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXHJcblxyXG4vKipcclxuICogQG92ZXJ2aWV3IERlZmluZXMgYW4gRXhwcmVzcyByb3V0ZSBmb3Igc2VydmVyIGhlYWx0aCBtb25pdG9yaW5nLCBpbmNsdWRpbmdcclxuICogdXB0aW1lLCBzdWNjZXNzIHJhdGVzLCBhbmQgb3RoZXIgc2VydmVyIHN0YXRpc3RpY3MuXHJcbiAqL1xyXG5cclxuaW1wb3J0IHsgcmVhZEZpbGVTeW5jIH0gZnJvbSAnZnMnO1xyXG5pbXBvcnQgeyBqb2luIH0gZnJvbSAncGF0aCc7XHJcblxyXG5pbXBvcnQgeyBnZXRIaWdoY2hhcnRzVmVyc2lvbiB9IGZyb20gJy4uLy4uL2NhY2hlLmpzJztcclxuaW1wb3J0IHsgbG9nIH0gZnJvbSAnLi4vLi4vbG9nZ2VyLmpzJztcclxuaW1wb3J0IHsgZ2V0UG9vbFN0YXRzLCBnZXRQb29sSW5mb0pTT04gfSBmcm9tICcuLi8uLi9wb29sLmpzJztcclxuaW1wb3J0IHsgYWRkVGltZXIgfSBmcm9tICcuLi8uLi90aW1lci5qcyc7XHJcbmltcG9ydCB7IF9fZGlybmFtZSwgZ2V0TmV3RGF0ZVRpbWUgfSBmcm9tICcuLi8uLi91dGlscy5qcyc7XHJcblxyXG4vLyBTZXQgdGhlIHN0YXJ0IGRhdGUgb2YgdGhlIHNlcnZlclxyXG5jb25zdCBzZXJ2ZXJTdGFydFRpbWUgPSBuZXcgRGF0ZSgpO1xyXG5cclxuLy8gR2V0IHRoZSBgcGFja2FnZS5qc29uYCBjb250ZW50XHJcbmNvbnN0IHBhY2thZ2VGaWxlID0gSlNPTi5wYXJzZShyZWFkRmlsZVN5bmMoam9pbihfX2Rpcm5hbWUsICdwYWNrYWdlLmpzb24nKSkpO1xyXG5cclxuLy8gQW4gYXJyYXkgZm9yIHN1Y2Nlc3MgcmF0ZSByYXRpb3NcclxuY29uc3Qgc3VjY2Vzc1JhdGVzID0gW107XHJcblxyXG4vLyBSZWNvcmQgZXZlcnkgbWludXRlXHJcbmNvbnN0IHJlY29yZEludGVydmFsID0gNjAgKiAxMDAwO1xyXG5cclxuLy8gMzAgbWludXRlc1xyXG5jb25zdCB3aW5kb3dTaXplID0gMzA7XHJcblxyXG4vKipcclxuICogQ2FsY3VsYXRlcyBtb3ZpbmcgYXZlcmFnZSBpbmRpY2F0b3IgYmFzZWQgb24gdGhlIGRhdGEgZnJvbSB0aGUgYHN1Y2Nlc3NSYXRlc2BcclxuICogYXJyYXkuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBfY2FsY3VsYXRlTW92aW5nQXZlcmFnZVxyXG4gKlxyXG4gKiBAcmV0dXJucyB7bnVtYmVyfSBBIG1vdmluZyBhdmVyYWdlIGZvciBzdWNjZXNzIHJhdGlvIG9mIHRoZSBzZXJ2ZXIgZXhwb3J0cy5cclxuICovXHJcbmZ1bmN0aW9uIF9jYWxjdWxhdGVNb3ZpbmdBdmVyYWdlKCkge1xyXG4gIHJldHVybiBzdWNjZXNzUmF0ZXMucmVkdWNlKChhLCBiKSA9PiBhICsgYiwgMCkgLyBzdWNjZXNzUmF0ZXMubGVuZ3RoO1xyXG59XHJcblxyXG4vKipcclxuICogU3RhcnRzIHRoZSBpbnRlcnZhbCByZXNwb25zaWJsZSBmb3IgY2FsY3VsYXRpbmcgY3VycmVudCBzdWNjZXNzIHJhdGUgcmF0aW9cclxuICogYW5kIGNvbGxlY3RzIHJlY29yZHMgdG8gdGhlIGBzdWNjZXNzUmF0ZXNgIGFycmF5LlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gX3N0YXJ0U3VjY2Vzc1JhdGVcclxuICpcclxuICogQHJldHVybnMge05vZGVKUy5UaW1lb3V0fSBJZCBvZiBhbiBpbnRlcnZhbC5cclxuICovXHJcbmZ1bmN0aW9uIF9zdGFydFN1Y2Nlc3NSYXRlKCkge1xyXG4gIHJldHVybiBzZXRJbnRlcnZhbCgoKSA9PiB7XHJcbiAgICBjb25zdCBzdGF0cyA9IGdldFBvb2xTdGF0cygpO1xyXG4gICAgY29uc3Qgc3VjY2Vzc1JhdGlvID1cclxuICAgICAgc3RhdHMuZXhwb3J0c0F0dGVtcHRlZCA9PT0gMFxyXG4gICAgICAgID8gMVxyXG4gICAgICAgIDogKHN0YXRzLmV4cG9ydHNQZXJmb3JtZWQgLyBzdGF0cy5leHBvcnRzQXR0ZW1wdGVkKSAqIDEwMDtcclxuXHJcbiAgICBzdWNjZXNzUmF0ZXMucHVzaChzdWNjZXNzUmF0aW8pO1xyXG4gICAgaWYgKHN1Y2Nlc3NSYXRlcy5sZW5ndGggPiB3aW5kb3dTaXplKSB7XHJcbiAgICAgIHN1Y2Nlc3NSYXRlcy5zaGlmdCgpO1xyXG4gICAgfVxyXG4gIH0sIHJlY29yZEludGVydmFsKTtcclxufVxyXG5cclxuLyoqXHJcbiAqIEFkZHMgdGhlIGBoZWFsdGhgIHJvdXRlcy5cclxuICpcclxuICogQGZ1bmN0aW9uIGhlYWx0aFJvdXRlc1xyXG4gKlxyXG4gKiBAcGFyYW0ge0V4cHJlc3N9IGFwcCAtIFRoZSBFeHByZXNzIGFwcCBpbnN0YW5jZS5cclxuICovXHJcbmV4cG9ydCBkZWZhdWx0IGZ1bmN0aW9uIGhlYWx0aFJvdXRlcyhhcHApIHtcclxuICAvLyBTdGFydCBwcm9jZXNzaW5nIHN1Y2Nlc3MgcmF0ZSByYXRpbyBpbnRlcnZhbCBhbmQgc2F2ZSBpdHMgaWQgdG8gdGhlIGFycmF5XHJcbiAgLy8gZm9yIHRoZSBncmFjZWZ1bCBjbGVhcmluZyBvbiBzaHV0ZG93biB3aXRoIGluamVjdGVkIGBhZGRUaW1lcmAgZnVudGlvblxyXG4gIGFkZFRpbWVyKF9zdGFydFN1Y2Nlc3NSYXRlKCkpO1xyXG5cclxuICAvKipcclxuICAgKiBBZGRzIHRoZSBHRVQgJy9oZWFsdGgnIC0gQSByb3V0ZSBmb3IgZ2V0dGluZyB0aGUgYmFzaWMgc3RhdHMgb2YgdGhlIHNlcnZlci5cclxuICAgKi9cclxuICBhcHAuZ2V0KCcvaGVhbHRoJywgKHJlcXVlc3QsIHJlc3BvbnNlLCBuZXh0KSA9PiB7XHJcbiAgICB0cnkge1xyXG4gICAgICBsb2coNCwgJ1toZWFsdGhdIFJldHVybmluZyBzZXJ2ZXIgaGVhbHRoLicpO1xyXG5cclxuICAgICAgY29uc3Qgc3RhdHMgPSBnZXRQb29sU3RhdHMoKTtcclxuICAgICAgY29uc3QgcGVyaW9kID0gc3VjY2Vzc1JhdGVzLmxlbmd0aDtcclxuICAgICAgY29uc3QgbW92aW5nQXZlcmFnZSA9IF9jYWxjdWxhdGVNb3ZpbmdBdmVyYWdlKCk7XHJcblxyXG4gICAgICAvLyBTZW5kIHRoZSBzZXJ2ZXIncyBzdGF0aXN0aWNzXHJcbiAgICAgIHJlc3BvbnNlLnNlbmQoe1xyXG4gICAgICAgIC8vIFN0YXR1cyBhbmQgdGltZXNcclxuICAgICAgICBzdGF0dXM6ICdPSycsXHJcbiAgICAgICAgYm9vdFRpbWU6IHNlcnZlclN0YXJ0VGltZSxcclxuICAgICAgICB1cHRpbWU6IGAke01hdGguZmxvb3IoKGdldE5ld0RhdGVUaW1lKCkgLSBzZXJ2ZXJTdGFydFRpbWUuZ2V0VGltZSgpKSAvIDEwMDAgLyA2MCl9IG1pbnV0ZXNgLFxyXG5cclxuICAgICAgICAvLyBWZXJzaW9uc1xyXG4gICAgICAgIHNlcnZlclZlcnNpb246IHBhY2thZ2VGaWxlLnZlcnNpb24sXHJcbiAgICAgICAgaGlnaGNoYXJ0c1ZlcnNpb246IGdldEhpZ2hjaGFydHNWZXJzaW9uKCksXHJcblxyXG4gICAgICAgIC8vIEV4cG9ydHNcclxuICAgICAgICBhdmVyYWdlRXhwb3J0VGltZTogc3RhdHMudGltZVNwZW50QXZlcmFnZSxcclxuICAgICAgICBhdHRlbXB0ZWRFeHBvcnRzOiBzdGF0cy5leHBvcnRzQXR0ZW1wdGVkLFxyXG4gICAgICAgIHBlcmZvcm1lZEV4cG9ydHM6IHN0YXRzLmV4cG9ydHNQZXJmb3JtZWQsXHJcbiAgICAgICAgZmFpbGVkRXhwb3J0czogc3RhdHMuZXhwb3J0c0Ryb3BwZWQsXHJcbiAgICAgICAgc3VjZXNzUmF0aW86IChzdGF0cy5leHBvcnRzUGVyZm9ybWVkIC8gc3RhdHMuZXhwb3J0c0F0dGVtcHRlZCkgKiAxMDAsXHJcblxyXG4gICAgICAgIC8vIFBvb2xcclxuICAgICAgICBwb29sOiBnZXRQb29sSW5mb0pTT04oKSxcclxuXHJcbiAgICAgICAgLy8gTW92aW5nIGF2ZXJhZ2VcclxuICAgICAgICBwZXJpb2QsXHJcbiAgICAgICAgbW92aW5nQXZlcmFnZSxcclxuICAgICAgICBtZXNzYWdlOlxyXG4gICAgICAgICAgaXNOYU4obW92aW5nQXZlcmFnZSkgfHwgIXN1Y2Nlc3NSYXRlcy5sZW5ndGhcclxuICAgICAgICAgICAgPyAnVG9vIGVhcmx5IHRvIHJlcG9ydC4gTm8gZXhwb3J0cyBtYWRlIHlldC4gUGxlYXNlIGNoZWNrIGJhY2sgc29vbi4nXHJcbiAgICAgICAgICAgIDogYExhc3QgJHtwZXJpb2R9IG1pbnV0ZXMgaGFkIGEgc3VjY2VzcyByYXRlIG9mICR7bW92aW5nQXZlcmFnZS50b0ZpeGVkKDIpfSUuYCxcclxuXHJcbiAgICAgICAgLy8gU1ZHIGFuZCBKU09OIGV4cG9ydHNcclxuICAgICAgICBzdmdFeHBvcnRzOiBzdGF0cy5leHBvcnRzRnJvbVN2ZyxcclxuICAgICAgICBqc29uRXhwb3J0czogc3RhdHMuZXhwb3J0c0Zyb21PcHRpb25zLFxyXG4gICAgICAgIHN2Z0V4cG9ydHNBdHRlbXB0czogc3RhdHMuZXhwb3J0c0Zyb21TdmdBdHRlbXB0cyxcclxuICAgICAgICBqc29uRXhwb3J0c0F0dGVtcHRzOiBzdGF0cy5leHBvcnRzRnJvbU9wdGlvbnNBdHRlbXB0c1xyXG4gICAgICB9KTtcclxuICAgIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICAgIHJldHVybiBuZXh0KGVycm9yKTtcclxuICAgIH1cclxuICB9KTtcclxufVxyXG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxyXG5cclxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXHJcblxyXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNSwgSGlnaHNvZnRcclxuXHJcbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cclxuXHJcbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxyXG5cclxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxyXG5cclxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cclxuXHJcbi8qKlxyXG4gKiBAb3ZlcnZpZXcgRGVmaW5lcyBhbiBFeHByZXNzIHJvdXRlIGZvciBzZXJ2aW5nIHRoZSBVSSBmb3IgdGhlIGV4cG9ydCBzZXJ2ZXJcclxuICogd2hlbiBlbmFibGVkLlxyXG4gKi9cclxuXHJcbmltcG9ydCB7IGpvaW4gfSBmcm9tICdwYXRoJztcclxuXHJcbmltcG9ydCB7IGdldE9wdGlvbnMgfSBmcm9tICcuLi8uLi9jb25maWcuanMnO1xyXG5pbXBvcnQgeyBfX2Rpcm5hbWUgfSBmcm9tICcuLi8uLi91dGlscy5qcyc7XHJcblxyXG4vKipcclxuICogQWRkcyB0aGUgYHVpYCByb3V0ZXMuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiB1aVJvdXRlc1xyXG4gKlxyXG4gKiBAcGFyYW0ge0V4cHJlc3N9IGFwcCAtIFRoZSBFeHByZXNzIGFwcCBpbnN0YW5jZS5cclxuICovXHJcbmV4cG9ydCBkZWZhdWx0IGZ1bmN0aW9uIHVpUm91dGVzKGFwcCkge1xyXG4gIC8qKlxyXG4gICAqIEFkZHMgdGhlIEdFVCAnLycgLSBBIHJvdXRlIGZvciBhIFVJIHdoZW4gZW5hYmxlZCBvbiB0aGUgZXhwb3J0IHNlcnZlci5cclxuICAgKi9cclxuICBhcHAuZ2V0KGdldE9wdGlvbnMoKS51aS5yb3V0ZSB8fCAnLycsIChyZXF1ZXN0LCByZXNwb25zZSwgbmV4dCkgPT4ge1xyXG4gICAgdHJ5IHtcclxuICAgICAgcmVzcG9uc2Uuc2VuZEZpbGUoam9pbihfX2Rpcm5hbWUsICdwdWJsaWMnLCAnaW5kZXguaHRtbCcpLCB7XHJcbiAgICAgICAgYWNjZXB0UmFuZ2VzOiBmYWxzZVxyXG4gICAgICB9KTtcclxuICAgIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICAgIHJldHVybiBuZXh0KGVycm9yKTtcclxuICAgIH1cclxuICB9KTtcclxufVxyXG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxyXG5cclxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXHJcblxyXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNSwgSGlnaHNvZnRcclxuXHJcbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cclxuXHJcbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxyXG5cclxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxyXG5cclxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cclxuXHJcbi8qKlxyXG4gKiBAb3ZlcnZpZXcgRGVmaW5lcyBhbiBFeHByZXNzIHJvdXRlIGZvciB1cGRhdGluZyB0aGUgSGlnaGNoYXJ0cyB2ZXJzaW9uXHJcbiAqIG9uIHRoZSBzZXJ2ZXIsIHdpdGggYXV0aGVudGljYXRpb24gYW5kIHZhbGlkYXRpb24uXHJcbiAqL1xyXG5cclxuaW1wb3J0IHsgdXBkYXRlSGlnaGNoYXJ0c1ZlcnNpb24sIGdldEhpZ2hjaGFydHNWZXJzaW9uIH0gZnJvbSAnLi4vLi4vY2FjaGUuanMnO1xyXG5pbXBvcnQgeyBlbnZzIH0gZnJvbSAnLi4vLi4vdmFsaWRhdGlvbi5qcyc7XHJcblxyXG5pbXBvcnQgSHR0cEVycm9yIGZyb20gJy4uLy4uL2Vycm9ycy9IdHRwRXJyb3IuanMnO1xyXG5cclxuLyoqXHJcbiAqIEFkZHMgdGhlIGB2ZXJzaW9uX2NoYW5nZWAgcm91dGVzLlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gdmVyc2lvbkNoYW5nZVJvdXRlc1xyXG4gKlxyXG4gKiBAcGFyYW0ge0V4cHJlc3N9IGFwcCAtIFRoZSBFeHByZXNzIGFwcCBpbnN0YW5jZS5cclxuICovXHJcbmV4cG9ydCBkZWZhdWx0IGZ1bmN0aW9uIHZlcnNpb25DaGFuZ2VSb3V0ZXMoYXBwKSB7XHJcbiAgLyoqXHJcbiAgICogQWRkcyB0aGUgUE9TVCAnL3ZlcnNpb25fY2hhbmdlLzpuZXdWZXJzaW9uJyAtIEEgcm91dGUgZm9yIGNoYW5naW5nXHJcbiAgICogdGhlIEhpZ2hjaGFydHMgdmVyc2lvbiBvbiB0aGUgc2VydmVyLlxyXG4gICAqL1xyXG4gIGFwcC5wb3N0KCcvdmVyc2lvbl9jaGFuZ2UvOm5ld1ZlcnNpb24nLCBhc3luYyAocmVxdWVzdCwgcmVzcG9uc2UsIG5leHQpID0+IHtcclxuICAgIHRyeSB7XHJcbiAgICAgIC8vIEdldCB0aGUgdG9rZW4gZGlyZWN0bHkgZnJvbSBlbnZzXHJcbiAgICAgIGNvbnN0IGFkbWluVG9rZW4gPSBlbnZzLkhJR0hDSEFSVFNfQURNSU5fVE9LRU47XHJcblxyXG4gICAgICAvLyBDaGVjayB0aGUgZXhpc3RlbmNlIG9mIHRoZSB0b2tlblxyXG4gICAgICBpZiAoIWFkbWluVG9rZW4gfHwgIWFkbWluVG9rZW4ubGVuZ3RoKSB7XHJcbiAgICAgICAgdGhyb3cgbmV3IEh0dHBFcnJvcihcclxuICAgICAgICAgICdbdmVyc2lvbl0gVGhlIHNlcnZlciBpcyBub3QgY29uZmlndXJlZCB0byBwZXJmb3JtIHJ1bi10aW1lIHZlcnNpb24gY2hhbmdlczogSElHSENIQVJUU19BRE1JTl9UT0tFTiBpcyBub3Qgc2V0LicsXHJcbiAgICAgICAgICA0MDFcclxuICAgICAgICApO1xyXG4gICAgICB9XHJcblxyXG4gICAgICAvLyBHZXQgdGhlIHRva2VuIGZyb20gdGhlIGhjLWF1dGggaGVhZGVyXHJcbiAgICAgIGNvbnN0IHRva2VuID0gcmVxdWVzdC5nZXQoJ2hjLWF1dGgnKTtcclxuXHJcbiAgICAgIC8vIENoZWNrIGlmIHRoZSBoYy1hdXRoIGhlYWRlciBjb250YWluIGEgY29ycmVjdCB0b2tlblxyXG4gICAgICBpZiAoIXRva2VuIHx8IHRva2VuICE9PSBhZG1pblRva2VuKSB7XHJcbiAgICAgICAgdGhyb3cgbmV3IEh0dHBFcnJvcihcclxuICAgICAgICAgICdbdmVyc2lvbl0gSW52YWxpZCBvciBtaXNzaW5nIHRva2VuOiBTZXQgdGhlIHRva2VuIGluIHRoZSBoYy1hdXRoIGhlYWRlci4nLFxyXG4gICAgICAgICAgNDAxXHJcbiAgICAgICAgKTtcclxuICAgICAgfVxyXG5cclxuICAgICAgLy8gQ29tcGFyZSB2ZXJzaW9uc1xyXG4gICAgICBjb25zdCBuZXdWZXJzaW9uID0gcmVxdWVzdC5wYXJhbXMubmV3VmVyc2lvbjtcclxuICAgICAgaWYgKG5ld1ZlcnNpb24pIHtcclxuICAgICAgICB0cnkge1xyXG4gICAgICAgICAgLy8gVXBkYXRlIHZlcnNpb25cclxuICAgICAgICAgIGF3YWl0IHVwZGF0ZUhpZ2hjaGFydHNWZXJzaW9uKG5ld1ZlcnNpb24pO1xyXG4gICAgICAgIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICAgICAgICB0aHJvdyBuZXcgSHR0cEVycm9yKFxyXG4gICAgICAgICAgICBgW3ZlcnNpb25dIFZlcnNpb24gY2hhbmdlOiAke2Vycm9yLm1lc3NhZ2V9YCxcclxuICAgICAgICAgICAgNDAwXHJcbiAgICAgICAgICApLnNldEVycm9yKGVycm9yKTtcclxuICAgICAgICB9XHJcblxyXG4gICAgICAgIC8vIFN1Y2Nlc3NcclxuICAgICAgICByZXNwb25zZS5zdGF0dXMoMjAwKS5zZW5kKHtcclxuICAgICAgICAgIHN0YXR1c0NvZGU6IDIwMCxcclxuICAgICAgICAgIGhpZ2hjaGFydHNWZXJzaW9uOiBnZXRIaWdoY2hhcnRzVmVyc2lvbigpLFxyXG4gICAgICAgICAgbWVzc2FnZTogYFN1Y2Nlc3NmdWxseSB1cGRhdGVkIEhpZ2hjaGFydHMgdG8gdmVyc2lvbjogJHtuZXdWZXJzaW9ufS5gXHJcbiAgICAgICAgfSk7XHJcbiAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgLy8gTm8gdmVyc2lvbiBzcGVjaWZpZWRcclxuICAgICAgICB0aHJvdyBuZXcgSHR0cEVycm9yKCdbdmVyc2lvbl0gTm8gbmV3IHZlcnNpb24gc3VwcGxpZWQuJywgNDAwKTtcclxuICAgICAgfVxyXG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICAgcmV0dXJuIG5leHQoZXJyb3IpO1xyXG4gICAgfVxyXG4gIH0pO1xyXG59XHJcbiIsIi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXHJcblxyXG5IaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXJcclxuXHJcbkNvcHlyaWdodCAoYykgMjAxNi0yMDI1LCBIaWdoc29mdFxyXG5cclxuTGljZW5jZWQgdW5kZXIgdGhlIE1JVCBsaWNlbmNlLlxyXG5cclxuQWRkaXRpb25hbGx5IGEgdmFsaWQgSGlnaGNoYXJ0cyBsaWNlbnNlIGlzIHJlcXVpcmVkIGZvciB1c2UuXHJcblxyXG5TZWUgTElDRU5TRSBmaWxlIGluIHJvb3QgZm9yIGRldGFpbHMuXHJcblxyXG4qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xyXG5cclxuLyoqXHJcbiAqIEBvdmVydmlldyBBIG1vZHVsZSB0aGF0IHNldHMgdXAgYW5kIG1hbmFnZXMgSFRUUCBhbmQgSFRUUFMgc2VydmVyc1xyXG4gKiBmb3IgdGhlIEhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlci4gSXQgaGFuZGxlcyBzZXJ2ZXIgaW5pdGlhbGl6YXRpb24sXHJcbiAqIGNvbmZpZ3VyYXRpb24sIGVycm9yIGhhbmRsaW5nLCBtaWRkbGV3YXJlIHNldHVwLCByb3V0ZSBkZWZpbml0aW9uLCBhbmQgcmF0ZVxyXG4gKiBsaW1pdGluZy4gVGhlIG1vZHVsZSBleHBvcnRzIGZ1bmN0aW9ucyB0byBzdGFydCwgc3RvcCwgYW5kIG1hbmFnZSBzZXJ2ZXJcclxuICogaW5zdGFuY2VzLCBhcyB3ZWxsIGFzIHV0aWxpdHkgZnVuY3Rpb25zIGZvciBkZWZpbmluZyByb3V0ZXMgYW5kIGF0dGFjaGluZ1xyXG4gKiBtaWRkbGV3YXJlcy5cclxuICovXHJcblxyXG5pbXBvcnQgeyByZWFkRmlsZSB9IGZyb20gJ2ZzL3Byb21pc2VzJztcclxuaW1wb3J0IHsgam9pbiB9IGZyb20gJ3BhdGgnO1xyXG5cclxuaW1wb3J0IGNvcnMgZnJvbSAnY29ycyc7XHJcbmltcG9ydCBleHByZXNzIGZyb20gJ2V4cHJlc3MnO1xyXG5pbXBvcnQgaHR0cCBmcm9tICdodHRwJztcclxuaW1wb3J0IGh0dHBzIGZyb20gJ2h0dHBzJztcclxuaW1wb3J0IG11bHRlciBmcm9tICdtdWx0ZXInO1xyXG5cclxuaW1wb3J0IHsgZ2V0T3B0aW9ucyB9IGZyb20gJy4uL2NvbmZpZy5qcyc7XHJcbmltcG9ydCB7IGxvZywgbG9nV2l0aFN0YWNrIH0gZnJvbSAnLi4vbG9nZ2VyLmpzJztcclxuaW1wb3J0IHsgX19kaXJuYW1lLCBnZXRBYnNvbHV0ZVBhdGggfSBmcm9tICcuLi91dGlscy5qcyc7XHJcblxyXG5pbXBvcnQgZXJyb3JNaWRkbGV3YXJlIGZyb20gJy4vbWlkZGxld2FyZXMvZXJyb3IuanMnO1xyXG5pbXBvcnQgcmF0ZUxpbWl0aW5nTWlkZGxld2FyZSBmcm9tICcuL21pZGRsZXdhcmVzL3JhdGVMaW1pdGluZy5qcyc7XHJcbmltcG9ydCB2YWxpZGF0aW9uTWlkZGxld2FyZSBmcm9tICcuL21pZGRsZXdhcmVzL3ZhbGlkYXRpb24uanMnO1xyXG5cclxuaW1wb3J0IGV4cG9ydFJvdXRlcyBmcm9tICcuL3JvdXRlcy9leHBvcnQuanMnO1xyXG5pbXBvcnQgaGVhbHRoUm91dGVzIGZyb20gJy4vcm91dGVzL2hlYWx0aC5qcyc7XHJcbmltcG9ydCB1aVJvdXRlcyBmcm9tICcuL3JvdXRlcy91aS5qcyc7XHJcbmltcG9ydCB2ZXJzaW9uQ2hhbmdlUm91dGVzIGZyb20gJy4vcm91dGVzL3ZlcnNpb25DaGFuZ2UuanMnO1xyXG5cclxuaW1wb3J0IEV4cG9ydEVycm9yIGZyb20gJy4uL2Vycm9ycy9FeHBvcnRFcnJvci5qcyc7XHJcblxyXG4vLyBBcnJheSBvZiBhbiBhY3RpdmUgc2VydmVyc1xyXG5jb25zdCBhY3RpdmVTZXJ2ZXJzID0gbmV3IE1hcCgpO1xyXG5cclxuLy8gQ3JlYXRlIGV4cHJlc3MgYXBwXHJcbmNvbnN0IGFwcCA9IGV4cHJlc3MoKTtcclxuXHJcbi8qKlxyXG4gKiBTdGFydHMgSFRUUCBvci9hbmQgSFRUUFMgc2VydmVyIGJhc2VkIG9uIHRoZSBwcm92aWRlZCBjb25maWd1cmF0aW9uLlxyXG4gKiBUaGUgYHNlcnZlck9wdGlvbnNgIG9iamVjdCBjb250YWlucyBhbGwgc2VydmVyIHJlbGF0ZWQgcHJvcGVydGllcyAoc2VlXHJcbiAqIHRoZSBgc2VydmVyYCBzZWN0aW9uIGluIHRoZSBgbGliL3NjaGVtYXMvY29uZmlnLmpzYCBmaWxlIGZvciBhIHJlZmVyZW5jZSkuXHJcbiAqXHJcbiAqIEBhc3luY1xyXG4gKiBAZnVuY3Rpb24gc3RhcnRTZXJ2ZXJcclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IFtzZXJ2ZXJPcHRpb25zPWdldE9wdGlvbnMoKS5zZXJ2ZXJdIC0gT2JqZWN0IGNvbnRhaW5pbmdcclxuICogYHNlcnZlcmAgb3B0aW9ucy4gVGhlIGRlZmF1bHQgdmFsdWUgaXMgdGhlIGdsb2JhbCBzZXJ2ZXIgb3B0aW9uc1xyXG4gKiBvZiB0aGUgZXhwb3J0IHNlcnZlciBpbnN0YW5jZS5cclxuICpcclxuICogQHJldHVybnMge1Byb21pc2U8dm9pZD59IEEgUHJvbWlzZSB0aGF0IHJlc29sdmVzIHRvIGVuZGluZyB0aGUgZnVuY3Rpb25cclxuICogZXhlY3V0aW9uIHdoZW4gdGhlIHNlcnZlciBzaG91bGQgbm90IGJlIGVuYWJsZWQgb3Igd2hlbiBubyB2YWxpZCBFeHByZXNzIGFwcFxyXG4gKiBpcyBmb3VuZC5cclxuICpcclxuICogQHRocm93cyB7RXhwb3J0RXJyb3J9IFRocm93cyBhbiBgRXhwb3J0RXJyb3JgIGlmIHRoZSBzZXJ2ZXIgY2Fubm90XHJcbiAqIGJlIGNvbmZpZ3VyZWQgYW5kIHN0YXJ0ZWQuXHJcbiAqL1xyXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gc3RhcnRTZXJ2ZXIoc2VydmVyT3B0aW9ucyA9IGdldE9wdGlvbnMoKS5zZXJ2ZXIpIHtcclxuICB0cnkge1xyXG4gICAgLy8gU3RvcCBpZiBub3QgZW5hYmxlZFxyXG4gICAgaWYgKCFzZXJ2ZXJPcHRpb25zLmVuYWJsZSB8fCAhYXBwKSB7XHJcbiAgICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcihcclxuICAgICAgICAnW3NlcnZlcl0gU2VydmVyIGNhbm5vdCBiZSBzdGFydGVkIChub3QgZW5hYmxlZCBvciBubyBjb3JyZWN0IEV4cHJlc3MgYXBwIGZvdW5kKS4nLFxyXG4gICAgICAgIDUwMFxyXG4gICAgICApO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIFRvbyBiaWcgbGltaXRzIGxlYWQgdG8gdGltZW91dHMgaW4gdGhlIGV4cG9ydCBwcm9jZXNzIHdoZW5cclxuICAgIC8vIHRoZSByYXN0ZXJpemF0aW9uIHRpbWVvdXQgaXMgc2V0IHRvbyBsb3dcclxuICAgIGNvbnN0IHVwbG9hZExpbWl0Qnl0ZXMgPSBzZXJ2ZXJPcHRpb25zLnVwbG9hZExpbWl0ICogMTAyNCAqIDEwMjQ7XHJcblxyXG4gICAgLy8gTWVtb3J5IHN0b3JhZ2UgZm9yIG11bHRlciBwYWNrYWdlXHJcbiAgICBjb25zdCBzdG9yYWdlID0gbXVsdGVyLm1lbW9yeVN0b3JhZ2UoKTtcclxuXHJcbiAgICAvLyBFbmFibGUgcGFyc2luZyBvZiBmb3JtIGRhdGEgKGZpbGVzKSB3aXRoIG11bHRlciBwYWNrYWdlXHJcbiAgICBjb25zdCB1cGxvYWQgPSBtdWx0ZXIoe1xyXG4gICAgICBzdG9yYWdlLFxyXG4gICAgICBsaW1pdHM6IHtcclxuICAgICAgICBmaWVsZFNpemU6IHVwbG9hZExpbWl0Qnl0ZXNcclxuICAgICAgfVxyXG4gICAgfSk7XHJcblxyXG4gICAgLy8gRGlzYWJsZSB0aGUgWC1Qb3dlcmVkLUJ5IGhlYWRlclxyXG4gICAgYXBwLmRpc2FibGUoJ3gtcG93ZXJlZC1ieScpO1xyXG5cclxuICAgIC8vIEVuYWJsZSBDT1JTIHN1cHBvcnRcclxuICAgIGFwcC51c2UoXHJcbiAgICAgIGNvcnMoe1xyXG4gICAgICAgIG1ldGhvZHM6IFsnUE9TVCcsICdHRVQnLCAnT1BUSU9OUyddXHJcbiAgICAgIH0pXHJcbiAgICApO1xyXG5cclxuICAgIC8vIEdldHRpbmcgYSBsb3Qgb2YgYFJhbmdlTm90U2F0aXNmaWFibGVFcnJvcmAgZXhjZXB0aW9ucyAoZXZlbiB0aG91Z2ggdGhpc1xyXG4gICAgLy8gaXMgYSBkZXByZWNhdGVkIG9wdGlvbnMsIGxldCdzIHRyeSB0byBzZXQgaXQgdG8gZmFsc2UpXHJcbiAgICBhcHAudXNlKChyZXF1ZXN0LCByZXNwb25zZSwgbmV4dCkgPT4ge1xyXG4gICAgICByZXNwb25zZS5zZXQoJ0FjY2VwdC1SYW5nZXMnLCAnbm9uZScpO1xyXG4gICAgICBuZXh0KCk7XHJcbiAgICB9KTtcclxuXHJcbiAgICAvLyBFbmFibGUgYm9keSBwYXJzZXIgZm9yIEpTT04gZGF0YVxyXG4gICAgYXBwLnVzZShcclxuICAgICAgZXhwcmVzcy5qc29uKHtcclxuICAgICAgICBsaW1pdDogdXBsb2FkTGltaXRCeXRlc1xyXG4gICAgICB9KVxyXG4gICAgKTtcclxuXHJcbiAgICAvLyBFbmFibGUgYm9keSBwYXJzZXIgZm9yIFVSTC1lbmNvZGVkIGZvcm0gZGF0YVxyXG4gICAgYXBwLnVzZShcclxuICAgICAgZXhwcmVzcy51cmxlbmNvZGVkKHtcclxuICAgICAgICBleHRlbmRlZDogdHJ1ZSxcclxuICAgICAgICBsaW1pdDogdXBsb2FkTGltaXRCeXRlc1xyXG4gICAgICB9KVxyXG4gICAgKTtcclxuXHJcbiAgICAvLyBVc2Ugb25seSBub24tZmlsZSBtdWx0aXBhcnQgZm9ybSBmaWVsZHNcclxuICAgIGFwcC51c2UodXBsb2FkLm5vbmUoKSk7XHJcblxyXG4gICAgLy8gU2V0IHVwIHN0YXRpYyBmb2xkZXIncyByb3V0ZVxyXG4gICAgYXBwLnVzZShleHByZXNzLnN0YXRpYyhqb2luKF9fZGlybmFtZSwgJ3B1YmxpYycpKSk7XHJcblxyXG4gICAgLy8gTGlzdGVuIEhUVFAgc2VydmVyXHJcbiAgICBpZiAoIXNlcnZlck9wdGlvbnMuc3NsLmZvcmNlKSB7XHJcbiAgICAgIC8vIE1haW4gc2VydmVyIGluc3RhbmNlIChIVFRQKVxyXG4gICAgICBjb25zdCBodHRwU2VydmVyID0gaHR0cC5jcmVhdGVTZXJ2ZXIoYXBwKTtcclxuXHJcbiAgICAgIC8vIEF0dGFjaCBlcnJvciBoYW5kbGVycyBhbmQgbGlzdGVuIHRvIHRoZSBzZXJ2ZXJcclxuICAgICAgX2F0dGFjaFNlcnZlckVycm9ySGFuZGxlcnMoaHR0cFNlcnZlcik7XHJcblxyXG4gICAgICAvLyBMaXN0ZW5cclxuICAgICAgaHR0cFNlcnZlci5saXN0ZW4oc2VydmVyT3B0aW9ucy5wb3J0LCBzZXJ2ZXJPcHRpb25zLmhvc3QsICgpID0+IHtcclxuICAgICAgICAvLyBTYXZlIHRoZSByZWZlcmVuY2UgdG8gSFRUUCBzZXJ2ZXJcclxuICAgICAgICBhY3RpdmVTZXJ2ZXJzLnNldChzZXJ2ZXJPcHRpb25zLnBvcnQsIGh0dHBTZXJ2ZXIpO1xyXG5cclxuICAgICAgICBsb2coXHJcbiAgICAgICAgICAzLFxyXG4gICAgICAgICAgYFtzZXJ2ZXJdIFN0YXJ0ZWQgSFRUUCBzZXJ2ZXIgb24gJHtzZXJ2ZXJPcHRpb25zLmhvc3R9OiR7c2VydmVyT3B0aW9ucy5wb3J0fS5gXHJcbiAgICAgICAgKTtcclxuICAgICAgfSk7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gTGlzdGVuIEhUVFBTIHNlcnZlclxyXG4gICAgaWYgKHNlcnZlck9wdGlvbnMuc3NsLmVuYWJsZSkge1xyXG4gICAgICAvLyBTZXQgdXAgYW4gU1NMIHNlcnZlciBhbHNvXHJcbiAgICAgIGxldCBrZXksIGNlcnQ7XHJcblxyXG4gICAgICB0cnkge1xyXG4gICAgICAgIC8vIEdldCB0aGUgU1NMIGtleVxyXG4gICAgICAgIGtleSA9IGF3YWl0IHJlYWRGaWxlKFxyXG4gICAgICAgICAgam9pbihnZXRBYnNvbHV0ZVBhdGgoc2VydmVyT3B0aW9ucy5zc2wuY2VydFBhdGgpLCAnc2VydmVyLmtleScpLFxyXG4gICAgICAgICAgJ3V0ZjgnXHJcbiAgICAgICAgKTtcclxuXHJcbiAgICAgICAgLy8gR2V0IHRoZSBTU0wgY2VydGlmaWNhdGVcclxuICAgICAgICBjZXJ0ID0gYXdhaXQgcmVhZEZpbGUoXHJcbiAgICAgICAgICBqb2luKGdldEFic29sdXRlUGF0aChzZXJ2ZXJPcHRpb25zLnNzbC5jZXJ0UGF0aCksICdzZXJ2ZXIuY3J0JyksXHJcbiAgICAgICAgICAndXRmOCdcclxuICAgICAgICApO1xyXG4gICAgICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgICAgIGxvZyhcclxuICAgICAgICAgIDIsXHJcbiAgICAgICAgICBgW3NlcnZlcl0gVW5hYmxlIHRvIGxvYWQga2V5L2NlcnRpZmljYXRlIGZyb20gdGhlICcke3NlcnZlck9wdGlvbnMuc3NsLmNlcnRQYXRofScgcGF0aC4gQ291bGQgbm90IHJ1biBzZWN1cmVkIGxheWVyIHNlcnZlci5gXHJcbiAgICAgICAgKTtcclxuICAgICAgfVxyXG5cclxuICAgICAgaWYgKGtleSAmJiBjZXJ0KSB7XHJcbiAgICAgICAgLy8gTWFpbiBzZXJ2ZXIgaW5zdGFuY2UgKEhUVFBTKVxyXG4gICAgICAgIGNvbnN0IGh0dHBzU2VydmVyID0gaHR0cHMuY3JlYXRlU2VydmVyKHsga2V5LCBjZXJ0IH0sIGFwcCk7XHJcblxyXG4gICAgICAgIC8vIEF0dGFjaCBlcnJvciBoYW5kbGVycyBhbmQgbGlzdGVuIHRvIHRoZSBzZXJ2ZXJcclxuICAgICAgICBfYXR0YWNoU2VydmVyRXJyb3JIYW5kbGVycyhodHRwc1NlcnZlcik7XHJcblxyXG4gICAgICAgIC8vIExpc3RlblxyXG4gICAgICAgIGh0dHBzU2VydmVyLmxpc3RlbihzZXJ2ZXJPcHRpb25zLnNzbC5wb3J0LCBzZXJ2ZXJPcHRpb25zLmhvc3QsICgpID0+IHtcclxuICAgICAgICAgIC8vIFNhdmUgdGhlIHJlZmVyZW5jZSB0byBIVFRQUyBzZXJ2ZXJcclxuICAgICAgICAgIGFjdGl2ZVNlcnZlcnMuc2V0KHNlcnZlck9wdGlvbnMuc3NsLnBvcnQsIGh0dHBzU2VydmVyKTtcclxuXHJcbiAgICAgICAgICBsb2coXHJcbiAgICAgICAgICAgIDMsXHJcbiAgICAgICAgICAgIGBbc2VydmVyXSBTdGFydGVkIEhUVFBTIHNlcnZlciBvbiAke3NlcnZlck9wdGlvbnMuaG9zdH06JHtzZXJ2ZXJPcHRpb25zLnNzbC5wb3J0fS5gXHJcbiAgICAgICAgICApO1xyXG4gICAgICAgIH0pO1xyXG4gICAgICB9XHJcbiAgICB9XHJcblxyXG4gICAgLy8gU2V0IHVwIHRoZSByYXRlIGxpbWl0ZXJcclxuICAgIHJhdGVMaW1pdGluZ01pZGRsZXdhcmUoYXBwLCBzZXJ2ZXJPcHRpb25zLnJhdGVMaW1pdGluZyk7XHJcblxyXG4gICAgLy8gU2V0IHVwIHRoZSB2YWxpZGF0aW9uIGhhbmRsZXJcclxuICAgIHZhbGlkYXRpb25NaWRkbGV3YXJlKGFwcCk7XHJcblxyXG4gICAgLy8gU2V0IHVwIHJvdXRlc1xyXG4gICAgaGVhbHRoUm91dGVzKGFwcCk7XHJcbiAgICBleHBvcnRSb3V0ZXMoYXBwKTtcclxuICAgIHVpUm91dGVzKGFwcCk7XHJcbiAgICB2ZXJzaW9uQ2hhbmdlUm91dGVzKGFwcCk7XHJcblxyXG4gICAgLy8gU2V0IHVwIHRoZSBjZW50cmFsaXplZCBlcnJvciBoYW5kbGVyXHJcbiAgICBlcnJvck1pZGRsZXdhcmUoYXBwKTtcclxuICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgdGhyb3cgbmV3IEV4cG9ydEVycm9yKFxyXG4gICAgICAnW3NlcnZlcl0gQ291bGQgbm90IGNvbmZpZ3VyZSBhbmQgc3RhcnQgdGhlIHNlcnZlci4nLFxyXG4gICAgICA1MDBcclxuICAgICkuc2V0RXJyb3IoZXJyb3IpO1xyXG4gIH1cclxufVxyXG5cclxuLyoqXHJcbiAqIENsb3NlcyBhbGwgc2VydmVycyBhc3NvY2lhdGVkIHdpdGggRXhwcmVzcyBhcHAgaW5zdGFuY2UuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBjbG9zZVNlcnZlcnNcclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiBjbG9zZVNlcnZlcnMoKSB7XHJcbiAgLy8gQ2hlY2sgaWYgdGhlcmUgYXJlIHNlcnZlcnMgd29ya2luZ1xyXG4gIGlmIChhY3RpdmVTZXJ2ZXJzLnNpemUgPiAwKSB7XHJcbiAgICBsb2coNCwgYFtzZXJ2ZXJdIENsb3NpbmcgYWxsIHNlcnZlcnMuYCk7XHJcblxyXG4gICAgLy8gQ2xvc2UgZWFjaCBvbmUgb2Ygc2VydmVyc1xyXG4gICAgZm9yIChjb25zdCBbcG9ydCwgc2VydmVyXSBvZiBhY3RpdmVTZXJ2ZXJzKSB7XHJcbiAgICAgIHNlcnZlci5jbG9zZSgoKSA9PiB7XHJcbiAgICAgICAgYWN0aXZlU2VydmVycy5kZWxldGUocG9ydCk7XHJcbiAgICAgICAgbG9nKDQsIGBbc2VydmVyXSBDbG9zZWQgc2VydmVyIG9uIHBvcnQ6ICR7cG9ydH0uYCk7XHJcbiAgICAgIH0pO1xyXG4gICAgfVxyXG4gIH1cclxufVxyXG5cclxuLyoqXHJcbiAqIEdldCBhbGwgc2VydmVycyBhc3NvY2lhdGVkIHdpdGggRXhwcmVzcyBhcHAgaW5zdGFuY2UuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBnZXRTZXJ2ZXJzXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtBcnJheS48T2JqZWN0Pn0gU2VydmVycyBhc3NvY2lhdGVkIHdpdGggRXhwcmVzcyBhcHAgaW5zdGFuY2UuXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gZ2V0U2VydmVycygpIHtcclxuICByZXR1cm4gYWN0aXZlU2VydmVycztcclxufVxyXG5cclxuLyoqXHJcbiAqIEdldCB0aGUgRXhwcmVzcyBpbnN0YW5jZS5cclxuICpcclxuICogQGZ1bmN0aW9uIGdldEV4cHJlc3NcclxuICpcclxuICogQHJldHVybnMge0V4cHJlc3N9IFRoZSBFeHByZXNzIGluc3RhbmNlLlxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIGdldEV4cHJlc3MoKSB7XHJcbiAgcmV0dXJuIGV4cHJlc3M7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBHZXQgdGhlIEV4cHJlc3MgYXBwIGluc3RhbmNlLlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gZ2V0QXBwXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtFeHByZXNzfSBUaGUgRXhwcmVzcyBhcHAgaW5zdGFuY2UuXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gZ2V0QXBwKCkge1xyXG4gIHJldHVybiBhcHA7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBFbmFibGUgcmF0ZSBsaW1pdGluZyBmb3IgdGhlIHNlcnZlci5cclxuICpcclxuICogQGZ1bmN0aW9uIGVuYWJsZVJhdGVMaW1pdGluZ1xyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gcmF0ZUxpbWl0aW5nT3B0aW9ucyAtIE9iamVjdCBjb250YWluaW5nIGByYXRlTGltaXRpbmdgXHJcbiAqIG9wdGlvbnMuXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gZW5hYmxlUmF0ZUxpbWl0aW5nKHJhdGVMaW1pdGluZ09wdGlvbnMpIHtcclxuICByYXRlTGltaXRpbmdNaWRkbGV3YXJlKGFwcCwgcmF0ZUxpbWl0aW5nT3B0aW9ucyk7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBBcHBseSBtaWRkbGV3YXJlKHMpIHRvIGEgc3BlY2lmaWMgcGF0aC5cclxuICpcclxuICogQGZ1bmN0aW9uIHVzZVxyXG4gKlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gcGF0aCAtIFRoZSBwYXRoIHRvIHdoaWNoIHRoZSBtaWRkbGV3YXJlKHMpIHNob3VsZCBiZSBhcHBsaWVkLlxyXG4gKiBAcGFyYW0gey4uLkZ1bmN0aW9ufSBtaWRkbGV3YXJlcyAtIFRoZSBtaWRkbGV3YXJlIGZ1bmN0aW9uKHMpIHRvIGJlIGFwcGxpZWQuXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gdXNlKHBhdGgsIC4uLm1pZGRsZXdhcmVzKSB7XHJcbiAgYXBwLnVzZShwYXRoLCAuLi5taWRkbGV3YXJlcyk7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBTZXQgdXAgYSByb3V0ZSB3aXRoIEdFVCBtZXRob2QgYW5kIGFwcGx5IG1pZGRsZXdhcmUocykuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBnZXRcclxuICpcclxuICogQHBhcmFtIHtzdHJpbmd9IHBhdGggLSBUaGUgcGF0aCB0byB3aGljaCB0aGUgbWlkZGxld2FyZShzKSBzaG91bGQgYmUgYXBwbGllZC5cclxuICogQHBhcmFtIHsuLi5GdW5jdGlvbn0gbWlkZGxld2FyZXMgLSBUaGUgbWlkZGxld2FyZSBmdW5jdGlvbihzKSB0byBiZSBhcHBsaWVkLlxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIGdldChwYXRoLCAuLi5taWRkbGV3YXJlcykge1xyXG4gIGFwcC5nZXQocGF0aCwgLi4ubWlkZGxld2FyZXMpO1xyXG59XHJcblxyXG4vKipcclxuICogU2V0IHVwIGEgcm91dGUgd2l0aCBQT1NUIG1ldGhvZCBhbmQgYXBwbHkgbWlkZGxld2FyZShzKS5cclxuICpcclxuICogQGZ1bmN0aW9uIHBvc3RcclxuICpcclxuICogQHBhcmFtIHtzdHJpbmd9IHBhdGggLSBUaGUgcGF0aCB0byB3aGljaCB0aGUgbWlkZGxld2FyZShzKSBzaG91bGQgYmUgYXBwbGllZC5cclxuICogQHBhcmFtIHsuLi5GdW5jdGlvbn0gbWlkZGxld2FyZXMgLSBUaGUgbWlkZGxld2FyZSBmdW5jdGlvbihzKSB0byBiZSBhcHBsaWVkLlxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIHBvc3QocGF0aCwgLi4ubWlkZGxld2FyZXMpIHtcclxuICBhcHAucG9zdChwYXRoLCAuLi5taWRkbGV3YXJlcyk7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBBdHRhY2ggZXJyb3IgaGFuZGxlcnMgdG8gdGhlIHNlcnZlci5cclxuICpcclxuICogQGZ1bmN0aW9uIF9hdHRhY2hTZXJ2ZXJFcnJvckhhbmRsZXJzXHJcbiAqXHJcbiAqIEBwYXJhbSB7KGh0dHAuU2VydmVyfGh0dHBzLlNlcnZlcil9IHNlcnZlciAtIFRoZSBIVFRQL0hUVFBTIHNlcnZlciBpbnN0YW5jZS5cclxuICovXHJcbmZ1bmN0aW9uIF9hdHRhY2hTZXJ2ZXJFcnJvckhhbmRsZXJzKHNlcnZlcikge1xyXG4gIHNlcnZlci5vbignY2xpZW50RXJyb3InLCAoZXJyb3IsIHNvY2tldCkgPT4ge1xyXG4gICAgbG9nV2l0aFN0YWNrKFxyXG4gICAgICAxLFxyXG4gICAgICBlcnJvcixcclxuICAgICAgYFtzZXJ2ZXJdIENsaWVudCBlcnJvcjogJHtlcnJvci5tZXNzYWdlfSwgZGVzdHJveWluZyBzb2NrZXQuYFxyXG4gICAgKTtcclxuICAgIHNvY2tldC5kZXN0cm95KCk7XHJcbiAgfSk7XHJcblxyXG4gIHNlcnZlci5vbignZXJyb3InLCAoZXJyb3IpID0+IHtcclxuICAgIGxvZ1dpdGhTdGFjaygxLCBlcnJvciwgYFtzZXJ2ZXJdIFNlcnZlciBlcnJvcjogJHtlcnJvci5tZXNzYWdlfWApO1xyXG4gIH0pO1xyXG5cclxuICBzZXJ2ZXIub24oJ2Nvbm5lY3Rpb24nLCAoc29ja2V0KSA9PiB7XHJcbiAgICBzb2NrZXQub24oJ2Vycm9yJywgKGVycm9yKSA9PiB7XHJcbiAgICAgIGxvZ1dpdGhTdGFjaygxLCBlcnJvciwgYFtzZXJ2ZXJdIFNvY2tldCBlcnJvcjogJHtlcnJvci5tZXNzYWdlfWApO1xyXG4gICAgfSk7XHJcbiAgfSk7XHJcbn1cclxuXHJcbmV4cG9ydCBkZWZhdWx0IHtcclxuICBzdGFydFNlcnZlcixcclxuICBjbG9zZVNlcnZlcnMsXHJcbiAgZ2V0U2VydmVycyxcclxuICBnZXRFeHByZXNzLFxyXG4gIGdldEFwcCxcclxuICBlbmFibGVSYXRlTGltaXRpbmcsXHJcbiAgdXNlLFxyXG4gIGdldCxcclxuICBwb3N0XHJcbn07XHJcbiIsIi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXHJcblxyXG5IaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXJcclxuXHJcbkNvcHlyaWdodCAoYykgMjAxNi0yMDI1LCBIaWdoc29mdFxyXG5cclxuTGljZW5jZWQgdW5kZXIgdGhlIE1JVCBsaWNlbmNlLlxyXG5cclxuQWRkaXRpb25hbGx5IGEgdmFsaWQgSGlnaGNoYXJ0cyBsaWNlbnNlIGlzIHJlcXVpcmVkIGZvciB1c2UuXHJcblxyXG5TZWUgTElDRU5TRSBmaWxlIGluIHJvb3QgZm9yIGRldGFpbHMuXHJcblxyXG4qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xyXG5cclxuLyoqXHJcbiAqIEBvdmVydmlldyBIYW5kbGVzIGdyYWNlZnVsIHNodXRkb3duIG9mIHRoZSBIaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXIsIGVuc3VyaW5nXHJcbiAqIHByb3BlciBjbGVhbnVwIG9mIHJlc291cmNlcyBzdWNoIGFzIGJyb3dzZXIsIHBhZ2VzLCBzZXJ2ZXJzLCBhbmQgdGltZXJzLlxyXG4gKi9cclxuXHJcbmltcG9ydCB7IGtpbGxQb29sIH0gZnJvbSAnLi9wb29sLmpzJztcclxuaW1wb3J0IHsgY2xlYXJBbGxUaW1lcnMgfSBmcm9tICcuL3RpbWVyLmpzJztcclxuaW1wb3J0IHsgY2xvc2VTZXJ2ZXJzIH0gZnJvbSAnLi9zZXJ2ZXIvc2VydmVyLmpzJztcclxuXHJcbi8qKlxyXG4gKiBDbGVhbnMgdXAgZnVuY3Rpb24gdG8gdHJpZ2dlciBiZWZvcmUgZW5kaW5nIHByb2Nlc3MgZm9yIHRoZSBncmFjZWZ1bFxyXG4gKiBzaHV0ZG93bi5cclxuICpcclxuICogQGZ1bmN0aW9uIHNodXRkb3duQ2xlYW5VcFxyXG4gKlxyXG4gKiBAcGFyYW0ge251bWJlcn0gZXhpdENvZGUgLSBBbiBleGl0IGNvZGUgZm9yIHRoZSBgcHJvY2Vzcy5leGl0KClgIGZ1bmN0aW9uLlxyXG4gKi9cclxuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIHNodXRkb3duQ2xlYW5VcChleGl0Q29kZSkge1xyXG4gIC8vIEF3YWl0IGZyZWVpbmcgYWxsIHJlc291cmNlc1xyXG4gIGF3YWl0IFByb21pc2UuYWxsU2V0dGxlZChbXHJcbiAgICAvLyBDbGVhciBhbGwgb25nb2luZyBpbnRlcnZhbHNcclxuICAgIGNsZWFyQWxsVGltZXJzKCksXHJcblxyXG4gICAgLy8gR2V0IGF2YWlsYWJsZSBzZXJ2ZXIgaW5zdGFuY2VzIChIVFRQL0hUVFBTKSBhbmQgY2xvc2UgdGhlbVxyXG4gICAgY2xvc2VTZXJ2ZXJzKCksXHJcblxyXG4gICAgLy8gQ2xvc2UgYW4gYWN0aXZlIHBvb2wgYWxvbmcgd2l0aCBpdHMgd29ya2VycyBhbmQgdGhlIGJyb3dzZXIgaW5zdGFuY2VcclxuICAgIGtpbGxQb29sKClcclxuICBdKTtcclxuXHJcbiAgLy8gRXhpdCBwcm9jZXNzIHdpdGggYSBjb3JyZWN0IGNvZGVcclxuICBwcm9jZXNzLmV4aXQoZXhpdENvZGUpO1xyXG59XHJcblxyXG5leHBvcnQgZGVmYXVsdCB7XHJcbiAgc2h1dGRvd25DbGVhblVwXHJcbn07XHJcbiIsIi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXHJcblxyXG5IaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXJcclxuXHJcbkNvcHlyaWdodCAoYykgMjAxNi0yMDI1LCBIaWdoc29mdFxyXG5cclxuTGljZW5jZWQgdW5kZXIgdGhlIE1JVCBsaWNlbmNlLlxyXG5cclxuQWRkaXRpb25hbGx5IGEgdmFsaWQgSGlnaGNoYXJ0cyBsaWNlbnNlIGlzIHJlcXVpcmVkIGZvciB1c2UuXHJcblxyXG5TZWUgTElDRU5TRSBmaWxlIGluIHJvb3QgZm9yIGRldGFpbHMuXHJcblxyXG4qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xyXG5cclxuLyoqXHJcbiAqIEBvdmVydmlldyBDb3JlIG1vZHVsZSBmb3IgaW5pdGlhbGl6aW5nIGFuZCBtYW5hZ2luZyB0aGUgSGlnaGNoYXJ0cyBFeHBvcnRcclxuICogU2VydmVyLiBQcm92aWRlcyBmdW5jdGlvbmFsaXRpZXMgZm9yIGNvbmZpZ3VyaW5nIGV4cG9ydHMsIHNldHRpbmcgdXAgc2VydmVyXHJcbiAqIG9wZXJhdGlvbnMsIGxvZ2dpbmcsIHNjcmlwdHMgY2FjaGluZywgcmVzb3VyY2UgcG9vbGluZywgYW5kIGdyYWNlZnVsIHByb2Nlc3NcclxuICogY2xlYW51cC5cclxuICovXHJcblxyXG5pbXBvcnQgJ2NvbG9ycyc7XHJcblxyXG5pbXBvcnQgeyBjaGVja0FuZFVwZGF0ZUNhY2hlIH0gZnJvbSAnLi9jYWNoZS5qcyc7XHJcbmltcG9ydCB7XHJcbiAgc2luZ2xlRXhwb3J0LFxyXG4gIGJhdGNoRXhwb3J0LFxyXG4gIHN0YXJ0RXhwb3J0LFxyXG4gIHNldEFsbG93Q29kZUV4ZWN1dGlvblxyXG59IGZyb20gJy4vY2hhcnQuanMnO1xyXG5pbXBvcnQge1xyXG4gIGdldE9wdGlvbnMsXHJcbiAgc2V0T3B0aW9ucyxcclxuICBtZXJnZU9wdGlvbnMsXHJcbiAgbWFwVG9OZXdPcHRpb25zXHJcbn0gZnJvbSAnLi9jb25maWcuanMnO1xyXG5pbXBvcnQge1xyXG4gIGxvZyxcclxuICBsb2dXaXRoU3RhY2ssXHJcbiAgbG9nWm9kSXNzdWVzLFxyXG4gIGluaXRMb2dnaW5nLFxyXG4gIHNldExvZ0xldmVsLFxyXG4gIGVuYWJsZUNvbnNvbGVMb2dnaW5nLFxyXG4gIGVuYWJsZUZpbGVMb2dnaW5nXHJcbn0gZnJvbSAnLi9sb2dnZXIuanMnO1xyXG5pbXBvcnQgeyBpbml0UG9vbCwga2lsbFBvb2wgfSBmcm9tICcuL3Bvb2wuanMnO1xyXG5pbXBvcnQgeyBzaHV0ZG93bkNsZWFuVXAgfSBmcm9tICcuL3Jlc291cmNlUmVsZWFzZS5qcyc7XHJcbmltcG9ydCBzZXJ2ZXIsIHsgc3RhcnRTZXJ2ZXIgfSBmcm9tICcuL3NlcnZlci9zZXJ2ZXIuanMnO1xyXG5cclxuLyoqXHJcbiAqIEluaXRpYWxpemVzIHRoZSBleHBvcnQgcHJvY2Vzcy4gVGFza3Mgc3VjaCBhcyBjb25maWd1cmluZyBsb2dnaW5nLCBjaGVja2luZ1xyXG4gKiB0aGUgY2FjaGUgYW5kIHNvdXJjZXMsIGFuZCBpbml0aWFsaXppbmcgdGhlIHJlc291cmNlIHBvb2wgb2NjdXIgZHVyaW5nIHRoaXNcclxuICogc3RhZ2UuIFRoaXMgZnVuY3Rpb24gbXVzdCBiZSBjYWxsZWQgYmVmb3JlIGF0dGVtcHRpbmcgdG8gZXhwb3J0IGNoYXJ0cyBvciBzZXRcclxuICogdXAgYSBzZXJ2ZXIuXHJcbiAqXHJcbiAqIEBhc3luY1xyXG4gKiBAZnVuY3Rpb24gaW5pdEV4cG9ydFxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gY3VzdG9tT3B0aW9ucyAtIFRoZSBgY3VzdG9tT3B0aW9uc2Agb2JqZWN0LCB3aGljaCBtYXlcclxuICogYmUgYSBwYXJ0aWFsIG9yIGNvbXBsZXRlIHNldCBvZiBvcHRpb25zLiBJZiB0aGUgcHJvdmlkZWQgb3B0aW9ucyBhcmUgcGFydGlhbCxcclxuICogbWlzc2luZyB2YWx1ZXMgd2lsbCBiZSBtZXJnZWQgd2l0aCB0aGUgZGVmYXVsdCBnZW5lcmFsIG9wdGlvbnMsIHJldHJpZXZlZFxyXG4gKiB1c2luZyB0aGUgYGdldE9wdGlvbnNgIGZ1bmN0aW9uLlxyXG4gKi9cclxuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIGluaXRFeHBvcnQoY3VzdG9tT3B0aW9ucykge1xyXG4gIC8vIEdldCB0aGUgZ2xvYmFsIG9wdGlvbnMgb2JqZWN0IGNvcHkgYW5kIGV4dGVuZCBpdCB3aXRoIHRoZSBpbmNvbWluZyBvcHRpb25zXHJcbiAgY29uc3Qgb3B0aW9ucyA9IG1lcmdlT3B0aW9ucyhnZXRPcHRpb25zKGZhbHNlKSwgY3VzdG9tT3B0aW9ucyk7XHJcblxyXG4gIC8vIFNldCB0aGUgYGFsbG93Q29kZUV4ZWN1dGlvbmAgcGVyIGV4cG9ydCBtb2R1bGUgc2NvcGVcclxuICBzZXRBbGxvd0NvZGVFeGVjdXRpb24ob3B0aW9ucy5jdXN0b21Mb2dpYy5hbGxvd0NvZGVFeGVjdXRpb24pO1xyXG5cclxuICAvLyBJbml0IHRoZSBsb2dnaW5nXHJcbiAgaW5pdExvZ2dpbmcob3B0aW9ucy5sb2dnaW5nKTtcclxuXHJcbiAgLy8gQXR0YWNoIHByb2Nlc3MnIGV4aXQgbGlzdGVuZXJzXHJcbiAgaWYgKG9wdGlvbnMub3RoZXIubGlzdGVuVG9Qcm9jZXNzRXhpdHMpIHtcclxuICAgIF9hdHRhY2hQcm9jZXNzRXhpdExpc3RlbmVycygpO1xyXG4gIH1cclxuXHJcbiAgLy8gQ2hlY2sgaWYgY2FjaGUgbmVlZHMgdG8gYmUgdXBkYXRlZFxyXG4gIGF3YWl0IGNoZWNrQW5kVXBkYXRlQ2FjaGUob3B0aW9ucy5oaWdoY2hhcnRzLCBvcHRpb25zLnNlcnZlci5wcm94eSk7XHJcblxyXG4gIC8vIEluaXQgdGhlIHBvb2xcclxuICBhd2FpdCBpbml0UG9vbChvcHRpb25zLnBvb2wsIG9wdGlvbnMucHVwcGV0ZWVyLmFyZ3MpO1xyXG59XHJcblxyXG4vKipcclxuICogQXR0YWNoZXMgZXhpdCBsaXN0ZW5lcnMgdG8gdGhlIHByb2Nlc3MsIGVuc3VyaW5nIHByb3BlciBjbGVhbnVwIG9mIHJlc291cmNlc1xyXG4gKiBhbmQgdGVybWluYXRpb24gb24gZXhpdCBzaWduYWxzLiBIYW5kbGVzICdleGl0JywgJ1NJR0lOVCcsICdTSUdURVJNJ1xyXG4gKiBhbmQgJ3VuY2F1Z2h0RXhjZXB0aW9uJyBldmVudHMuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBfYXR0YWNoUHJvY2Vzc0V4aXRMaXN0ZW5lcnNcclxuICovXHJcbmZ1bmN0aW9uIF9hdHRhY2hQcm9jZXNzRXhpdExpc3RlbmVycygpIHtcclxuICBsb2coMywgJ1twcm9jZXNzXSBBdHRhY2hpbmcgZXhpdCBsaXN0ZW5lcnMgdG8gdGhlIHByb2Nlc3MuJyk7XHJcblxyXG4gIC8vIEhhbmRsZXIgZm9yIHRoZSAnZXhpdCdcclxuICBwcm9jZXNzLm9uKCdleGl0JywgKGNvZGUpID0+IHtcclxuICAgIGxvZyg0LCBgW3Byb2Nlc3NdIFByb2Nlc3MgZXhpdGVkIHdpdGggY29kZSAke2NvZGV9LmApO1xyXG4gIH0pO1xyXG5cclxuICAvLyBIYW5kbGVyIGZvciB0aGUgJ1NJR0lOVCdcclxuICBwcm9jZXNzLm9uKCdTSUdJTlQnLCBhc3luYyAobmFtZSwgY29kZSkgPT4ge1xyXG4gICAgbG9nKDQsIGBbcHJvY2Vzc10gVGhlICR7bmFtZX0gZXZlbnQgd2l0aCBjb2RlOiAke2NvZGV9LmApO1xyXG4gICAgYXdhaXQgc2h1dGRvd25DbGVhblVwKDApO1xyXG4gIH0pO1xyXG5cclxuICAvLyBIYW5kbGVyIGZvciB0aGUgJ1NJR1RFUk0nXHJcbiAgcHJvY2Vzcy5vbignU0lHVEVSTScsIGFzeW5jIChuYW1lLCBjb2RlKSA9PiB7XHJcbiAgICBsb2coNCwgYFtwcm9jZXNzXSBUaGUgJHtuYW1lfSBldmVudCB3aXRoIGNvZGU6ICR7Y29kZX0uYCk7XHJcbiAgICBhd2FpdCBzaHV0ZG93bkNsZWFuVXAoMCk7XHJcbiAgfSk7XHJcblxyXG4gIC8vIEhhbmRsZXIgZm9yIHRoZSAnU0lHSFVQJ1xyXG4gIHByb2Nlc3Mub24oJ1NJR0hVUCcsIGFzeW5jIChuYW1lLCBjb2RlKSA9PiB7XHJcbiAgICBsb2coNCwgYFtwcm9jZXNzXSBUaGUgJHtuYW1lfSBldmVudCB3aXRoIGNvZGU6ICR7Y29kZX0uYCk7XHJcbiAgICBhd2FpdCBzaHV0ZG93bkNsZWFuVXAoMCk7XHJcbiAgfSk7XHJcblxyXG4gIC8vIEhhbmRsZXIgZm9yIHRoZSAndW5jYXVnaHRFeGNlcHRpb24nXHJcbiAgcHJvY2Vzcy5vbigndW5jYXVnaHRFeGNlcHRpb24nLCBhc3luYyAoZXJyb3IsIG5hbWUpID0+IHtcclxuICAgIGxvZ1dpdGhTdGFjaygxLCBlcnJvciwgYFtwcm9jZXNzXSBUaGUgJHtuYW1lfSBlcnJvci5gKTtcclxuICAgIGF3YWl0IHNodXRkb3duQ2xlYW5VcCgxKTtcclxuICB9KTtcclxufVxyXG5cclxuZXhwb3J0IGRlZmF1bHQge1xyXG4gIC8vIFNlcnZlclxyXG4gIHNlcnZlcixcclxuICBzdGFydFNlcnZlcixcclxuXHJcbiAgLy8gT3B0aW9uc1xyXG4gIGdldE9wdGlvbnMsXHJcbiAgc2V0T3B0aW9ucyxcclxuICBtZXJnZU9wdGlvbnMsXHJcbiAgbWFwVG9OZXdPcHRpb25zLFxyXG5cclxuICAvLyBFeHBvcnRpbmdcclxuICBpbml0RXhwb3J0LFxyXG4gIHNpbmdsZUV4cG9ydCxcclxuICBiYXRjaEV4cG9ydCxcclxuICBzdGFydEV4cG9ydCxcclxuXHJcbiAgLy8gQ2FjaGVcclxuICBjaGVja0FuZFVwZGF0ZUNhY2hlLFxyXG5cclxuICAvLyBQb29sXHJcbiAgaW5pdFBvb2wsXHJcbiAga2lsbFBvb2wsXHJcblxyXG4gIC8vIExvZ3NcclxuICBsb2csXHJcbiAgbG9nV2l0aFN0YWNrLFxyXG4gIGxvZ1pvZElzc3VlcyxcclxuICBzZXRMb2dMZXZlbCxcclxuICBlbmFibGVDb25zb2xlTG9nZ2luZyxcclxuICBlbmFibGVGaWxlTG9nZ2luZyxcclxuXHJcbiAgLy8gVXRpbHNcclxuICBzaHV0ZG93bkNsZWFuVXBcclxufTtcclxuIl0sIm5hbWVzIjpbIl9fZGlybmFtZSIsImZpbGVVUkxUb1BhdGgiLCJVUkwiLCJkb2N1bWVudCIsInJlcXVpcmUiLCJwYXRoVG9GaWxlVVJMIiwiX19maWxlbmFtZSIsImhyZWYiLCJfZG9jdW1lbnRDdXJyZW50U2NyaXB0IiwidGFnTmFtZSIsInRvVXBwZXJDYXNlIiwic3JjIiwiYmFzZVVSSSIsImRlZXBDb3B5Iiwib2JqQXJyIiwib2JqQXJyQ29weSIsIkFycmF5IiwiaXNBcnJheSIsImtleSIsIk9iamVjdCIsInByb3RvdHlwZSIsImhhc093blByb3BlcnR5IiwiY2FsbCIsImZpeENvbnN0ciIsImNvbnN0ciIsImZpeGVkQ29uc3RyIiwidG9Mb3dlckNhc2UiLCJyZXBsYWNlIiwiaW5jbHVkZXMiLCJmaXhPdXRmaWxlIiwidHlwZSIsIm91dGZpbGUiLCJnZXRBYnNvbHV0ZVBhdGgiLCJzcGxpdCIsInNoaWZ0IiwiZml4VHlwZSIsIm1pbWVUeXBlcyIsImZvcm1hdHMiLCJ2YWx1ZXMiLCJvdXRUeXBlIiwicG9wIiwiZmluZCIsInQiLCJwYXRoIiwiaXNBYnNvbHV0ZSIsImpvaW4iLCJnZXRCYXNlNjQiLCJpbnB1dCIsIkJ1ZmZlciIsImZyb20iLCJ0b1N0cmluZyIsImdldE5ld0RhdGUiLCJEYXRlIiwidHJpbSIsImdldE5ld0RhdGVUaW1lIiwiZ2V0VGltZSIsImlzT2JqZWN0IiwiaXRlbSIsImlzT2JqZWN0RW1wdHkiLCJrZXlzIiwibGVuZ3RoIiwiaXNQcml2YXRlUmFuZ2VVcmxGb3VuZCIsInNvbWUiLCJwYXR0ZXJuIiwidGVzdCIsIm1lYXN1cmVUaW1lIiwic3RhcnQiLCJwcm9jZXNzIiwiaHJ0aW1lIiwiYmlnaW50IiwiTnVtYmVyIiwicm91bmROdW1iZXIiLCJ2YWx1ZSIsInByZWNpc2lvbiIsIm11bHRpcGxpZXIiLCJNYXRoIiwicG93Iiwicm91bmQiLCJ3cmFwQXJvdW5kIiwiY3VzdG9tQ29kZSIsImFsbG93RmlsZVJlc291cmNlcyIsImlzQ2FsbGJhY2siLCJlbmRzV2l0aCIsInJlYWRGaWxlU3luYyIsInN0YXJ0c1dpdGgiLCJjb2xvcnMiLCJsb2dnaW5nIiwidG9Db25zb2xlIiwidG9GaWxlIiwicGF0aENyZWF0ZWQiLCJwYXRoVG9Mb2ciLCJsZXZlbHNEZXNjIiwidGl0bGUiLCJjb2xvciIsImxvZyIsImFyZ3MiLCJuZXdMZXZlbCIsInRleHRzIiwibGV2ZWwiLCJwcmVmaXgiLCJfbG9nVG9GaWxlIiwiY29uc29sZSIsImFwcGx5IiwidW5kZWZpbmVkIiwiY29uY2F0IiwibG9nV2l0aFN0YWNrIiwiZXJyb3IiLCJjdXN0b21NZXNzYWdlIiwibWFpbk1lc3NhZ2UiLCJtZXNzYWdlIiwic3RhY2tNZXNzYWdlIiwic3RhY2siLCJwdXNoIiwibG9nWm9kSXNzdWVzIiwiaXNzdWVzIiwibWFwIiwiaXNzdWUiLCJpbml0TG9nZ2luZyIsImxvZ2dpbmdPcHRpb25zIiwiZGVzdCIsImZpbGUiLCJzZXRMb2dMZXZlbCIsImVuYWJsZUNvbnNvbGVMb2dnaW5nIiwiZW5hYmxlRmlsZUxvZ2dpbmciLCJleGlzdHNTeW5jIiwibWtkaXJTeW5jIiwiYXBwZW5kRmlsZSIsImRlZmF1bHRDb25maWciLCJwdXBwZXRlZXIiLCJ0eXBlcyIsImVudkxpbmsiLCJjbGlOYW1lIiwiZGVzY3JpcHRpb24iLCJwcm9tcHRPcHRpb25zIiwic2VwYXJhdG9yIiwiaGlnaGNoYXJ0cyIsInZlcnNpb24iLCJjZG5VcmwiLCJmb3JjZUZldGNoIiwiY2FjaGVQYXRoIiwiY29yZVNjcmlwdHMiLCJpbnN0cnVjdGlvbnMiLCJtb2R1bGVTY3JpcHRzIiwiaW5kaWNhdG9yU2NyaXB0cyIsImN1c3RvbVNjcmlwdHMiLCJleHBvcnQiLCJpbmZpbGUiLCJpbnN0ciIsIm9wdGlvbnMiLCJzdmciLCJiYXRjaCIsImhpbnQiLCJjaG9pY2VzIiwiYjY0Iiwibm9Eb3dubG9hZCIsImhlaWdodCIsIndpZHRoIiwic2NhbGUiLCJkZWZhdWx0SGVpZ2h0IiwiZGVmYXVsdFdpZHRoIiwiZGVmYXVsdFNjYWxlIiwibWluIiwibWF4IiwiZ2xvYmFsT3B0aW9ucyIsInRoZW1lT3B0aW9ucyIsInJhc3Rlcml6YXRpb25UaW1lb3V0IiwiY3VzdG9tTG9naWMiLCJhbGxvd0NvZGVFeGVjdXRpb24iLCJjYWxsYmFjayIsInJlc291cmNlcyIsImxvYWRDb25maWciLCJsZWdhY3lOYW1lIiwiY3JlYXRlQ29uZmlnIiwic2VydmVyIiwiZW5hYmxlIiwiaG9zdCIsInBvcnQiLCJ1cGxvYWRMaW1pdCIsImJlbmNobWFya2luZyIsInByb3h5IiwidGltZW91dCIsInJhdGVMaW1pdGluZyIsIm1heFJlcXVlc3RzIiwid2luZG93IiwiZGVsYXkiLCJ0cnVzdFByb3h5Iiwic2tpcEtleSIsInNraXBUb2tlbiIsInNzbCIsImZvcmNlIiwiY2VydFBhdGgiLCJwb29sIiwibWluV29ya2VycyIsIm1heFdvcmtlcnMiLCJ3b3JrTGltaXQiLCJhY3F1aXJlVGltZW91dCIsImNyZWF0ZVRpbWVvdXQiLCJkZXN0cm95VGltZW91dCIsImlkbGVUaW1lb3V0IiwiY3JlYXRlUmV0cnlJbnRlcnZhbCIsInJlYXBlckludGVydmFsIiwidWkiLCJyb3V0ZSIsIm90aGVyIiwibm9kZUVudiIsImxpc3RlblRvUHJvY2Vzc0V4aXRzIiwibm9Mb2dvIiwiaGFyZFJlc2V0UGFnZSIsImJyb3dzZXJTaGVsbE1vZGUiLCJkZWJ1ZyIsImhlYWRsZXNzIiwiZGV2dG9vbHMiLCJsaXN0ZW5Ub0NvbnNvbGUiLCJkdW1waW8iLCJzbG93TW8iLCJkZWJ1Z2dpbmdQb3J0IiwibmVzdGVkUHJvcHMiLCJfY3JlYXRlTmVzdGVkUHJvcHMiLCJhYnNvbHV0ZVByb3BzIiwiX2NyZWF0ZUFic29sdXRlUHJvcHMiLCJjb25maWciLCJwcm9wQ2hhaW4iLCJmb3JFYWNoIiwiZW50cnkiLCJzdWJzdHJpbmciLCJkb3RlbnYiLCJ6Iiwic2V0RXJyb3JNYXAiLCJfY3VzdG9tRXJyb3JNYXAiLCJ2IiwiYm9vbGVhbiIsInN0cmljdENoZWNrIiwidW5pb24iLCJlbnVtIiwidHJhbnNmb3JtIiwibnVsbGFibGUiLCJzdHJpbmciLCJyZWZpbmUiLCJwYXJhbXMiLCJlcnJvck1lc3NhZ2UiLCJzdHJpbmdBcnJheSIsImZpbHRlckNhbGxiYWNrIiwiYXJyYXlTY2hlbWEiLCJhcnJheSIsInN0cmluZ1NjaGVtYSIsInNsaWNlIiwidHJhbnNmb3JtQ2FsbGJhY2siLCJmaWx0ZXIiLCJwb3NpdGl2ZU51bSIsIm51bWJlciIsInBvc2l0aXZlIiwiaXNOYU4iLCJub25OZWdhdGl2ZU51bSIsIm5vbm5lZ2F0aXZlIiwicHJlZml4ZXMiLCJjaGFydENvbmZpZyIsImluZGV4T2YiLCJvYmplY3QiLCJwYXNzdGhyb3VnaCIsImFkZGl0aW9uYWxPcHRpb25zIiwiYWRtaW5Ub2tlbiIsImd0ZSIsImx0ZSIsInRoaXMiLCJvYmplY3RTY2hlbWEiLCJqcyIsImNzcyIsImZpbGVzIiwicGFydGlhbCIsInN0cmluZ1NjaGVtYTEiLCJzdHJpbmdTY2hlbWEyIiwiZW5hYmxlU2VydmVyIiwic2VydmVyQmVuY2htYXJraW5nIiwicHJveHlIb3N0IiwicHJveHlQb3J0IiwicHJveHlUaW1lb3V0IiwiZW5hYmxlUmF0ZUxpbWl0aW5nIiwiZW5hYmxlU3NsIiwic3NsRm9yY2UiLCJzc2xQb3J0Iiwic3NsQ2VydFBhdGgiLCJwb29sQmVuY2htYXJraW5nIiwicmVzb3VyY2VzSW50ZXJ2YWwiLCJsb2dMZXZlbCIsImludCIsImlzSW50ZWdlciIsImxvZ0ZpbGUiLCJsb2dEZXN0IiwibG9nVG9Db25zb2xlIiwibG9nVG9GaWxlIiwiZW5hYmxlVWkiLCJ1aVJvdXRlIiwiZW5hYmxlRGVidWciLCJyZXF1ZXN0SWQiLCJ1dWlkIiwiUHVwcGV0ZWVyU2NoZW1hIiwiSGlnaGNoYXJ0c1NjaGVtYSIsIkV4cG9ydFNjaGVtYSIsIkN1c3RvbUxvZ2ljU2NoZW1hIiwiUHJveHlTY2hlbWEiLCJSYXRlTGltaXRpbmdTY2hlbWEiLCJTc2xTY2hlbWEiLCJTZXJ2ZXJTY2hlbWEiLCJvcHRpb25hbCIsIlBvb2xTY2hlbWEiLCJMb2dnaW5nU2NoZW1hIiwiVWlTY2hlbWEiLCJPdGhlclNjaGVtYSIsIkRlYnVnU2NoZW1hIiwiU3RyaWN0Q29uZmlnU2NoZW1hIiwiTG9vc2VDb25maWdTY2hlbWEiLCJFbnZTY2hlbWEiLCJQVVBQRVRFRVJfQVJHUyIsIkhJR0hDSEFSVFNfVkVSU0lPTiIsIkhJR0hDSEFSVFNfQ0ROX1VSTCIsIkhJR0hDSEFSVFNfRk9SQ0VfRkVUQ0giLCJISUdIQ0hBUlRTX0NBQ0hFX1BBVEgiLCJISUdIQ0hBUlRTX0FETUlOX1RPS0VOIiwiSElHSENIQVJUU19DT1JFX1NDUklQVFMiLCJISUdIQ0hBUlRTX01PRFVMRV9TQ1JJUFRTIiwiSElHSENIQVJUU19JTkRJQ0FUT1JfU0NSSVBUUyIsIkhJR0hDSEFSVFNfQ1VTVE9NX1NDUklQVFMiLCJFWFBPUlRfSU5GSUxFIiwiRVhQT1JUX0lOU1RSIiwiRVhQT1JUX09QVElPTlMiLCJFWFBPUlRfU1ZHIiwiRVhQT1JUX0JBVENIIiwiRVhQT1JUX09VVEZJTEUiLCJFWFBPUlRfVFlQRSIsIkVYUE9SVF9DT05TVFIiLCJFWFBPUlRfQjY0IiwiRVhQT1JUX05PX0RPV05MT0FEIiwiRVhQT1JUX0hFSUdIVCIsIkVYUE9SVF9XSURUSCIsIkVYUE9SVF9TQ0FMRSIsIkVYUE9SVF9ERUZBVUxUX0hFSUdIVCIsIkVYUE9SVF9ERUZBVUxUX1dJRFRIIiwiRVhQT1JUX0RFRkFVTFRfU0NBTEUiLCJFWFBPUlRfR0xPQkFMX09QVElPTlMiLCJFWFBPUlRfVEhFTUVfT1BUSU9OUyIsIkVYUE9SVF9SQVNURVJJWkFUSU9OX1RJTUVPVVQiLCJDVVNUT01fTE9HSUNfQUxMT1dfQ09ERV9FWEVDVVRJT04iLCJDVVNUT01fTE9HSUNfQUxMT1dfRklMRV9SRVNPVVJDRVMiLCJDVVNUT01fTE9HSUNfQ1VTVE9NX0NPREUiLCJDVVNUT01fTE9HSUNfQ0FMTEJBQ0siLCJDVVNUT01fTE9HSUNfUkVTT1VSQ0VTIiwiQ1VTVE9NX0xPR0lDX0xPQURfQ09ORklHIiwiQ1VTVE9NX0xPR0lDX0NSRUFURV9DT05GSUciLCJTRVJWRVJfRU5BQkxFIiwiU0VSVkVSX0hPU1QiLCJTRVJWRVJfUE9SVCIsIlNFUlZFUl9VUExPQURfTElNSVQiLCJTRVJWRVJfQkVOQ0hNQVJLSU5HIiwiU0VSVkVSX1BST1hZX0hPU1QiLCJTRVJWRVJfUFJPWFlfUE9SVCIsIlNFUlZFUl9QUk9YWV9USU1FT1VUIiwiU0VSVkVSX1JBVEVfTElNSVRJTkdfRU5BQkxFIiwiU0VSVkVSX1JBVEVfTElNSVRJTkdfTUFYX1JFUVVFU1RTIiwiU0VSVkVSX1JBVEVfTElNSVRJTkdfV0lORE9XIiwiU0VSVkVSX1JBVEVfTElNSVRJTkdfREVMQVkiLCJTRVJWRVJfUkFURV9MSU1JVElOR19UUlVTVF9QUk9YWSIsIlNFUlZFUl9SQVRFX0xJTUlUSU5HX1NLSVBfS0VZIiwiU0VSVkVSX1JBVEVfTElNSVRJTkdfU0tJUF9UT0tFTiIsIlNFUlZFUl9TU0xfRU5BQkxFIiwiU0VSVkVSX1NTTF9GT1JDRSIsIlNFUlZFUl9TU0xfUE9SVCIsIlNFUlZFUl9TU0xfQ0VSVF9QQVRIIiwiUE9PTF9NSU5fV09SS0VSUyIsIlBPT0xfTUFYX1dPUktFUlMiLCJQT09MX1dPUktfTElNSVQiLCJQT09MX0FDUVVJUkVfVElNRU9VVCIsIlBPT0xfQ1JFQVRFX1RJTUVPVVQiLCJQT09MX0RFU1RST1lfVElNRU9VVCIsIlBPT0xfSURMRV9USU1FT1VUIiwiUE9PTF9DUkVBVEVfUkVUUllfSU5URVJWQUwiLCJQT09MX1JFQVBFUl9JTlRFUlZBTCIsIlBPT0xfQkVOQ0hNQVJLSU5HIiwiTE9HR0lOR19MRVZFTCIsIkxPR0dJTkdfRklMRSIsIkxPR0dJTkdfREVTVCIsIkxPR0dJTkdfVE9fQ09OU09MRSIsIkxPR0dJTkdfVE9fRklMRSIsIlVJX0VOQUJMRSIsIlVJX1JPVVRFIiwiT1RIRVJfTk9ERV9FTlYiLCJPVEhFUl9MSVNURU5fVE9fUFJPQ0VTU19FWElUUyIsIk9USEVSX05PX0xPR08iLCJPVEhFUl9IQVJEX1JFU0VUX1BBR0UiLCJPVEhFUl9CUk9XU0VSX1NIRUxMX01PREUiLCJERUJVR19FTkFCTEUiLCJERUJVR19IRUFETEVTUyIsIkRFQlVHX0RFVlRPT0xTIiwiREVCVUdfTElTVEVOX1RPX0NPTlNPTEUiLCJERUJVR19EVU1QSU8iLCJERUJVR19TTE9XX01PIiwiREVCVUdfREVCVUdHSU5HX1BPUlQiLCJlbnZzIiwicGFyc2UiLCJlbnYiLCJzdHJpY3RWYWxpZGF0ZSIsImNvbmZpZ09wdGlvbnMiLCJsb29zZVZhbGlkYXRlIiwidmFsaWRhdGVPcHRpb24iLCJuYW1lIiwib3B0aW9uIiwiY29udGV4dCIsInByb3BlcnR5TmFtZSIsInByb3BlcnR5SW5mbyIsImNvZGUiLCJab2RJc3N1ZUNvZGUiLCJpbnZhbGlkX3R5cGUiLCJyZWNlaXZlZCIsIlpvZFBhcnNlZFR5cGUiLCJkZWZhdWx0RXJyb3IiLCJjdXN0b20iLCJkYXRhIiwiaW52YWxpZF91bmlvbiIsInVuaW9uRXJyb3JzIiwiaW5kZXgiLCJfaW5pdEdsb2JhbE9wdGlvbnMiLCJnZXRPcHRpb25zIiwiZ2V0UmVmZXJlbmNlIiwic2V0T3B0aW9ucyIsImN1c3RvbU9wdGlvbnMiLCJjbGlBcmdzIiwibW9kaWZ5R2xvYmFsIiwiY2xpT3B0aW9ucyIsIl9sb2FkQ29uZmlnRmlsZSIsIl9wYWlyQXJndW1lbnRWYWx1ZSIsImdlbmVyYWxPcHRpb25zIiwiX3VwZGF0ZU9wdGlvbnMiLCJtZXJnZU9wdGlvbnMiLCJvcmlnaW5hbE9wdGlvbnMiLCJuZXdPcHRpb25zIiwiZW50cmllcyIsIm1hcFRvTmV3T3B0aW9ucyIsIm9sZE9wdGlvbnMiLCJwcm9wZXJ0aWVzQ2hhaW4iLCJyZWR1Y2UiLCJvYmoiLCJwcm9wIiwiaXNBbGxvd2VkQ29uZmlnIiwiYWxsb3dGdW5jdGlvbnMiLCJvYmplY3RDb25maWciLCJldmFsIiwiSlNPTiIsInN0cmluZ2lmaWVkT3B0aW9ucyIsIl9vcHRpb25zU3RyaW5naWZ5IiwicGFyc2VkT3B0aW9ucyIsIl8iLCJjb25maWdPcHQiLCJjdXN0b21PcHQiLCJjbGlPcHQiLCJjb25maWdWYWwiLCJjdXN0b21WYWwiLCJjbGlWYWwiLCJlbnZWYWwiLCJzdHJpbmdpZnlGdW5jdGlvbnMiLCJzdHJpbmdpZnkiLCJyZXBsYWNlQWxsIiwiRXJyb3IiLCJjb25maWdJbmRleCIsImZpbmRJbmRleCIsImFyZyIsImNvbmZpZ0ZpbGVOYW1lIiwiaSIsImFzeW5jIiwiZmV0Y2giLCJ1cmwiLCJyZXF1ZXN0T3B0aW9ucyIsIlByb21pc2UiLCJyZXNvbHZlIiwicmVqZWN0IiwiX2dldFByb3RvY29sTW9kdWxlIiwiZ2V0IiwicmVzcG9uc2UiLCJyZXNwb25zZURhdGEiLCJvbiIsImNodW5rIiwidGV4dCIsImh0dHBzIiwiaHR0cCIsIkV4cG9ydEVycm9yIiwiY29uc3RydWN0b3IiLCJzdGF0dXNDb2RlIiwic3VwZXIiLCJzZXRFcnJvciIsImNhY2hlIiwiYWN0aXZlTWFuaWZlc3QiLCJzb3VyY2VzIiwiaGNWZXJzaW9uIiwiY2hlY2tBbmRVcGRhdGVDYWNoZSIsImhpZ2hjaGFydHNPcHRpb25zIiwic2VydmVyUHJveHlPcHRpb25zIiwiZmV0Y2hlZE1vZHVsZXMiLCJnZXRDYWNoZVBhdGgiLCJtYW5pZmVzdFBhdGgiLCJzb3VyY2VQYXRoIiwicmVjdXJzaXZlIiwiX3VwZGF0ZUNhY2hlIiwicmVxdWVzdFVwZGF0ZSIsIm1hbmlmZXN0IiwibW9kdWxlcyIsIm1vZHVsZU1hcCIsIm0iLCJudW1iZXJPZk1vZHVsZXMiLCJtb2R1bGVOYW1lIiwiZXh0cmFjdFZlcnNpb24iLCJfc2F2ZUNvbmZpZ1RvTWFuaWZlc3QiLCJnZXRIaWdoY2hhcnRzVmVyc2lvbiIsInVwZGF0ZUhpZ2hjaGFydHNWZXJzaW9uIiwibmV3VmVyc2lvbiIsImNhY2hlU291cmNlcyIsImV4dHJhY3RNb2R1bGVOYW1lIiwic2NyaXB0UGF0aCIsIl9mZXRjaEFuZFByb2Nlc3NTY3JpcHQiLCJzY3JpcHQiLCJzaG91bGRUaHJvd0Vycm9yIiwibmV3TWFuaWZlc3QiLCJ3cml0ZUZpbGVTeW5jIiwiX2ZldGNoU2NyaXB0cyIsInByb3h5QWdlbnQiLCJIdHRwc1Byb3h5QWdlbnQiLCJhZ2VudCIsImFsbEZldGNoUHJvbWlzZXMiLCJhbGwiLCJjIiwic2V0dXBIaWdoY2hhcnRzIiwiSGlnaGNoYXJ0cyIsImFuaW1PYmplY3QiLCJkdXJhdGlvbiIsImNyZWF0ZUNoYXJ0IiwibWVyZ2UiLCJ3cmFwIiwic2V0T3B0aW9uc09iaiIsImlzUmVuZGVyQ29tcGxldGUiLCJDaGFydCIsInByb2NlZWQiLCJ1c2VyT3B0aW9ucyIsImNiIiwiZXhwb3J0aW5nIiwiZW5hYmxlZCIsInBsb3RPcHRpb25zIiwic2VyaWVzIiwibGFiZWwiLCJ0b29sdGlwIiwiYW5pbWF0aW9uIiwib25IaWdoY2hhcnRzUmVuZGVyIiwiYWRkRXZlbnQiLCJTZXJpZXMiLCJjaGFydCIsIkZ1bmN0aW9uIiwiZmluYWxPcHRpb25zIiwiZmluYWxDYWxsYmFjayIsImRlZmF1bHRPcHRpb25zIiwidGVtcGxhdGUiLCJicm93c2VyIiwiY3JlYXRlQnJvd3NlciIsInB1cHBldGVlckFyZ3MiLCJlbmFibGVkRGVidWciLCJkZWJ1Z09wdGlvbnMiLCJsYXVuY2hPcHRpb25zIiwidXNlckRhdGFEaXIiLCJoYW5kbGVTSUdJTlQiLCJoYW5kbGVTSUdURVJNIiwiaGFuZGxlU0lHSFVQIiwid2FpdEZvckluaXRpYWxQYWdlIiwiZGVmYXVsdFZpZXdwb3J0IiwidHJ5Q291bnQiLCJvcGVuIiwibGF1bmNoIiwic2V0VGltZW91dCIsImNsb3NlQnJvd3NlciIsImNvbm5lY3RlZCIsImNsb3NlIiwibmV3UGFnZSIsInBvb2xSZXNvdXJjZSIsInBhZ2UiLCJzZXRDYWNoZUVuYWJsZWQiLCJfc2V0UGFnZUNvbnRlbnQiLCJfc2V0UGFnZUV2ZW50cyIsImlzQ2xvc2VkIiwiY2xlYXJQYWdlIiwiaGFyZFJlc2V0IiwiZ290byIsIndhaXRVbnRpbCIsImV2YWx1YXRlIiwiYm9keSIsImlubmVySFRNTCIsImlkIiwid29ya0NvdW50IiwiYWRkUGFnZVJlc291cmNlcyIsImN1c3RvbUxvZ2ljT3B0aW9ucyIsImluamVjdGVkUmVzb3VyY2VzIiwiaW5qZWN0ZWRKcyIsImNvbnRlbnQiLCJpc0xvY2FsIiwianNSZXNvdXJjZSIsImFkZFNjcmlwdFRhZyIsImluamVjdGVkQ3NzIiwiY3NzSW1wb3J0cyIsIm1hdGNoIiwiY3NzSW1wb3J0UGF0aCIsImNzc1Jlc291cmNlIiwiYWRkU3R5bGVUYWciLCJjbGVhclBhZ2VSZXNvdXJjZXMiLCJyZXNvdXJjZSIsImRpc3Bvc2UiLCJvbGRDaGFydHMiLCJjaGFydHMiLCJvbGRDaGFydCIsImRlc3Ryb3kiLCJzY3JpcHRzVG9SZW1vdmUiLCJnZXRFbGVtZW50c0J5VGFnTmFtZSIsInN0eWxlc1RvUmVtb3ZlIiwibGlua3NUb1JlbW92ZSIsImVsZW1lbnQiLCJyZW1vdmUiLCJzZXRDb250ZW50IiwiY3NzVGVtcGxhdGUiLCJzdmdUZW1wbGF0ZSIsInB1cHBldGVlckV4cG9ydCIsImV4cG9ydE9wdGlvbnMiLCJpc1NWRyIsIl9zZXRBc1N2ZyIsIl9zZXRBc09wdGlvbnMiLCJzaXplIiwic3ZnRWxlbWVudCIsInF1ZXJ5U2VsZWN0b3IiLCJjaGFydEhlaWdodCIsImJhc2VWYWwiLCJjaGFydFdpZHRoIiwic3R5bGUiLCJ6b29tIiwibWFyZ2luIiwicGFyc2VGbG9hdCIsIngiLCJ5IiwiX2dldENsaXBSZWdpb24iLCJ2aWV3cG9ydEhlaWdodCIsImFicyIsImNlaWwiLCJ2aWV3cG9ydFdpZHRoIiwicmVzdWx0Iiwic2V0Vmlld3BvcnQiLCJkZXZpY2VTY2FsZUZhY3RvciIsIl9jcmVhdGVTVkciLCJfY3JlYXRlSW1hZ2UiLCJfY3JlYXRlUERGIiwiJGV2YWwiLCJnZXRCb3VuZGluZ0NsaWVudFJlY3QiLCJ0cnVuYyIsIm91dGVySFRNTCIsImNsaXAiLCJyYWNlIiwic2NyZWVuc2hvdCIsImVuY29kaW5nIiwiZnVsbFBhZ2UiLCJvcHRpbWl6ZUZvclNwZWVkIiwiY2FwdHVyZUJleW9uZFZpZXdwb3J0IiwicXVhbGl0eSIsIm9taXRCYWNrZ3JvdW5kIiwiX3Jlc29sdmUiLCJlbXVsYXRlTWVkaWFUeXBlIiwicGRmIiwicG9vbFN0YXRzIiwiZXhwb3J0c0F0dGVtcHRlZCIsImV4cG9ydHNQZXJmb3JtZWQiLCJleHBvcnRzRHJvcHBlZCIsImV4cG9ydHNGcm9tU3ZnIiwiZXhwb3J0c0Zyb21PcHRpb25zIiwiZXhwb3J0c0Zyb21TdmdBdHRlbXB0cyIsImV4cG9ydHNGcm9tT3B0aW9uc0F0dGVtcHRzIiwidGltZVNwZW50IiwidGltZVNwZW50QXZlcmFnZSIsImluaXRQb29sIiwicG9vbE9wdGlvbnMiLCJQb29sIiwiX2ZhY3RvcnkiLCJhY3F1aXJlVGltZW91dE1pbGxpcyIsImNyZWF0ZVRpbWVvdXRNaWxsaXMiLCJkZXN0cm95VGltZW91dE1pbGxpcyIsImlkbGVUaW1lb3V0TWlsbGlzIiwiY3JlYXRlUmV0cnlJbnRlcnZhbE1pbGxpcyIsInJlYXBJbnRlcnZhbE1pbGxpcyIsInByb3BhZ2F0ZUNyZWF0ZUVycm9yIiwiY2xlYXJTdGF0dXMiLCJfZXZlbnRJZCIsImluaXRpYWxSZXNvdXJjZXMiLCJhY3F1aXJlIiwicHJvbWlzZSIsInJlbGVhc2UiLCJraWxsUG9vbCIsIndvcmtlciIsInVzZWQiLCJkZXN0cm95ZWQiLCJwb3N0V29yayIsIndvcmtlckhhbmRsZSIsImdldFBvb2xJbmZvIiwiYWNxdWlyZUNvdW50ZXIiLCJfcmVxdWVzdElkIiwid29ya1N0YXJ0IiwiZXhwb3J0Q291bnRlciIsImV4cG9ydFRpbWUiLCJnZXRQb29sU3RhdHMiLCJnZXRQb29sSW5mb0pTT04iLCJudW1Vc2VkIiwiYXZhaWxhYmxlIiwibnVtRnJlZSIsImFsbENyZWF0ZWQiLCJwZW5kaW5nQWNxdWlyZXMiLCJudW1QZW5kaW5nQWNxdWlyZXMiLCJwZW5kaW5nQ3JlYXRlcyIsIm51bVBlbmRpbmdDcmVhdGVzIiwicGVuZGluZ1ZhbGlkYXRpb25zIiwibnVtUGVuZGluZ1ZhbGlkYXRpb25zIiwicGVuZGluZ0Rlc3Ryb3lzIiwiYWJzb2x1dGVBbGwiLCJjcmVhdGUiLCJyYW5kb20iLCJzdGFydERhdGUiLCJ2YWxpZGF0ZSIsIm1haW5GcmFtZSIsImRldGFjaGVkIiwicmVtb3ZlQWxsTGlzdGVuZXJzIiwic2FuaXRpemUiLCJKU0RPTSIsIkRPTVB1cmlmeSIsIkFERF9UQUdTIiwic2luZ2xlRXhwb3J0Iiwic3RhcnRFeHBvcnQiLCJiYXRjaEV4cG9ydCIsImJhdGNoRnVuY3Rpb25zIiwicGFpciIsImJhdGNoUmVzdWx0cyIsImFsbFNldHRsZWQiLCJyZWFzb24iLCJlbmRDYWxsYmFjayIsImZpbGVDb250ZW50IiwiX2V4cG9ydEZyb21TdmciLCJfZXhwb3J0RnJvbU9wdGlvbnMiLCJnZXRBbGxvd0NvZGVFeGVjdXRpb24iLCJzZXRBbGxvd0NvZGVFeGVjdXRpb24iLCJpbnB1dFRvRXhwb3J0IiwiX3ByZXBhcmVFeHBvcnQiLCJfaGFuZGxlQ3VzdG9tTG9naWMiLCJfaGFuZGxlR2xvYmFsQW5kVGhlbWUiLCJfZmluZENoYXJ0U2l6ZSIsIm9wdGlvbnNDaGFydCIsIm9wdGlvbnNFeHBvcnRpbmciLCJnbG9iYWxPcHRpb25zQ2hhcnQiLCJnbG9iYWxPcHRpb25zRXhwb3J0aW5nIiwidGhlbWVPcHRpb25zQ2hhcnQiLCJ0aGVtZU9wdGlvbnNFeHBvcnRpbmciLCJzb3VyY2VIZWlnaHQiLCJzb3VyY2VXaWR0aCIsInBhcmFtIiwiX2hhbmRsZVJlc291cmNlcyIsImFsbG93ZWRQcm9wcyIsImhhbmRsZWRSZXNvdXJjZXMiLCJjb3JyZWN0UmVzb3VyY2VzIiwicHJvcE5hbWUiLCJvcHRpb25zTmFtZSIsInRpbWVySWRzIiwiYWRkVGltZXIiLCJjbGVhckFsbFRpbWVycyIsImNsZWFySW50ZXJ2YWwiLCJjbGVhclRpbWVvdXQiLCJsb2dFcnJvck1pZGRsZXdhcmUiLCJyZXF1ZXN0IiwibmV4dCIsInJldHVybkVycm9yTWlkZGxld2FyZSIsInN0YXR1cyIsImpzb24iLCJlcnJvck1pZGRsZXdhcmUiLCJhcHAiLCJ1c2UiLCJyYXRlTGltaXRpbmdNaWRkbGV3YXJlIiwicmF0ZUxpbWl0aW5nT3B0aW9ucyIsIm1zZyIsInJhdGVPcHRpb25zIiwibGltaXRlciIsInJhdGVMaW1pdCIsIndpbmRvd01zIiwiZGVsYXlNcyIsImhhbmRsZXIiLCJmb3JtYXQiLCJzZW5kIiwiZGVmYXVsdCIsInNraXAiLCJxdWVyeSIsImFjY2Vzc190b2tlbiIsIkh0dHBFcnJvciIsInNldFN0YXR1cyIsImNvbnRlbnRUeXBlTWlkZGxld2FyZSIsImNvbnRlbnRUeXBlIiwiaGVhZGVycyIsInJlcXVlc3RCb2R5TWlkZGxld2FyZSIsImNvbm5lY3Rpb24iLCJyZW1vdGVBZGRyZXNzIiwidmFsaWRhdGVkT3B0aW9ucyIsImZpbGVuYW1lIiwidmFsaWRhdGlvbk1pZGRsZXdhcmUiLCJwb3N0IiwicmV2ZXJzZWRNaW1lIiwicG5nIiwianBlZyIsImdpZiIsInJlcXVlc3RFeHBvcnQiLCJyZXF1ZXN0Q291bnRlciIsImNvbm5lY3Rpb25BYm9ydGVkIiwic29ja2V0IiwiaGFkRXJyb3JzIiwiaGVhZGVyIiwiYXR0YWNobWVudCIsImV4cG9ydFJvdXRlcyIsInNlcnZlclN0YXJ0VGltZSIsInBhY2thZ2VGaWxlIiwic3VjY2Vzc1JhdGVzIiwicmVjb3JkSW50ZXJ2YWwiLCJ3aW5kb3dTaXplIiwiX2NhbGN1bGF0ZU1vdmluZ0F2ZXJhZ2UiLCJhIiwiYiIsIl9zdGFydFN1Y2Nlc3NSYXRlIiwic2V0SW50ZXJ2YWwiLCJzdGF0cyIsInN1Y2Nlc3NSYXRpbyIsImhlYWx0aFJvdXRlcyIsInBlcmlvZCIsIm1vdmluZ0F2ZXJhZ2UiLCJib290VGltZSIsInVwdGltZSIsImZsb29yIiwic2VydmVyVmVyc2lvbiIsImhpZ2hjaGFydHNWZXJzaW9uIiwiYXZlcmFnZUV4cG9ydFRpbWUiLCJhdHRlbXB0ZWRFeHBvcnRzIiwicGVyZm9ybWVkRXhwb3J0cyIsImZhaWxlZEV4cG9ydHMiLCJzdWNlc3NSYXRpbyIsInRvRml4ZWQiLCJzdmdFeHBvcnRzIiwianNvbkV4cG9ydHMiLCJzdmdFeHBvcnRzQXR0ZW1wdHMiLCJqc29uRXhwb3J0c0F0dGVtcHRzIiwidWlSb3V0ZXMiLCJzZW5kRmlsZSIsImFjY2VwdFJhbmdlcyIsInZlcnNpb25DaGFuZ2VSb3V0ZXMiLCJ0b2tlbiIsImFjdGl2ZVNlcnZlcnMiLCJNYXAiLCJleHByZXNzIiwic3RhcnRTZXJ2ZXIiLCJzZXJ2ZXJPcHRpb25zIiwidXBsb2FkTGltaXRCeXRlcyIsInN0b3JhZ2UiLCJtdWx0ZXIiLCJtZW1vcnlTdG9yYWdlIiwidXBsb2FkIiwibGltaXRzIiwiZmllbGRTaXplIiwiZGlzYWJsZSIsImNvcnMiLCJtZXRob2RzIiwic2V0IiwibGltaXQiLCJ1cmxlbmNvZGVkIiwiZXh0ZW5kZWQiLCJub25lIiwic3RhdGljIiwiaHR0cFNlcnZlciIsImNyZWF0ZVNlcnZlciIsIl9hdHRhY2hTZXJ2ZXJFcnJvckhhbmRsZXJzIiwibGlzdGVuIiwiY2VydCIsInJlYWRGaWxlIiwiaHR0cHNTZXJ2ZXIiLCJjbG9zZVNlcnZlcnMiLCJkZWxldGUiLCJnZXRTZXJ2ZXJzIiwiZ2V0RXhwcmVzcyIsImdldEFwcCIsIm1pZGRsZXdhcmVzIiwic2h1dGRvd25DbGVhblVwIiwiZXhpdENvZGUiLCJleGl0IiwiaW5pdEV4cG9ydCIsIl9hdHRhY2hQcm9jZXNzRXhpdExpc3RlbmVycyJdLCJtYXBwaW5ncyI6InduQkEyQk8sTUFBTUEsWUFBWUMsSUFBYUEsY0FBQyxJQUFJQyxJQUFJLE9BQVEsb0JBQUFDLFNBQUFDLFFBQUEsT0FBQUMsY0FBQUMsWUFBQUMsS0FBQUMsd0JBQUEsV0FBQUEsdUJBQUFDLFFBQUFDLGVBQUFGLHVCQUFBRyxLQUFBLElBQUFULElBQUEsWUFBQUMsU0FBQVMsU0FBQUwsT0ErQmhELFNBQVNNLFNBQVNDLEdBRXZCLEdBQWUsT0FBWEEsR0FBcUMsaUJBQVhBLEVBQzVCLE9BQU9BLEVBSVQsTUFBTUMsRUFBYUMsTUFBTUMsUUFBUUgsR0FBVSxHQUFLLEdBR2hELElBQUssTUFBTUksS0FBT0osRUFDWkssT0FBT0MsVUFBVUMsZUFBZUMsS0FBS1IsRUFBUUksS0FDL0NILEVBQVdHLEdBQU9MLFNBQVNDLEVBQU9JLEtBS3RDLE9BQU9ILENBQ1QsQ0EyRE8sU0FBU1EsVUFBVUMsR0FDeEIsSUFFRSxNQUFNQyxFQUFjLEdBQUdELEVBQU9FLGNBQWNDLFFBQVEsUUFBUyxXQVE3RCxNQUxvQixVQUFoQkYsR0FDRkEsRUFBWUMsY0FJUCxDQUFDLFFBQVMsYUFBYyxXQUFZLGNBQWNFLFNBQ3ZESCxHQUVFQSxFQUNBLE9BQ1IsQ0FBSSxNQUVBLE1BQU8sT0FDUixDQUNILENBWU8sU0FBU0ksV0FBV0MsRUFBTUMsR0FPL0IsTUFBTyxHQUxVQyxnQkFBZ0JELEdBQVcsU0FDekNFLE1BQU0sS0FDTkMsV0FHbUJKLEdBQ3hCLENBYU8sU0FBU0ssUUFBUUwsRUFBTUMsRUFBVSxNQUV0QyxNQUFNSyxFQUFZLENBQ2hCLFlBQWEsTUFDYixhQUFjLE9BQ2Qsa0JBQW1CLE1BQ25CLGdCQUFpQixPQUliQyxFQUFVbEIsT0FBT21CLE9BQU9GLEdBRzlCLEdBQUlMLEVBQVMsQ0FDWCxNQUFNUSxFQUFVUixFQUFRRSxNQUFNLEtBQUtPLE1BR25CLFFBQVpELEVBQ0ZULEVBQU8sT0FDRU8sRUFBUVQsU0FBU1csSUFBWVQsSUFBU1MsSUFDL0NULEVBQU9TLEVBRVYsQ0FHRCxPQUFPSCxFQUFVTixJQUFTTyxFQUFRSSxNQUFNQyxHQUFNQSxJQUFNWixLQUFTLEtBQy9ELENBWU8sU0FBU0UsZ0JBQWdCVyxHQUM5QixPQUFPQyxLQUFBQSxXQUFXRCxHQUFRQSxFQUFPRSxLQUFBQSxLQUFLN0MsWUFBVzJDLEVBQ25ELENBWU8sU0FBU0csVUFBVUMsRUFBT2pCLEdBRS9CLE1BQWEsUUFBVEEsR0FBMEIsT0FBUkEsRUFDYmtCLE9BQU9DLEtBQUtGLEVBQU8sUUFBUUcsU0FBUyxVQUl0Q0gsQ0FDVCxDQU9PLFNBQVNJLGFBRWQsT0FBTyxJQUFJQyxNQUFPRixXQUFXakIsTUFBTSxLQUFLLEdBQUdvQixNQUM3QyxDQU9PLFNBQVNDLGlCQUNkLE9BQU8sSUFBSUYsTUFBT0csU0FDcEIsQ0FXTyxTQUFTQyxTQUFTQyxHQUN2QixNQUFnRCxvQkFBekN0QyxPQUFPQyxVQUFVOEIsU0FBUzVCLEtBQUttQyxFQUN4QyxDQVdPLFNBQVNDLGNBQWNELEdBQzVCLE1BQ2tCLGlCQUFUQSxJQUNOekMsTUFBTUMsUUFBUXdDLElBQ04sT0FBVEEsR0FDNkIsSUFBN0J0QyxPQUFPd0MsS0FBS0YsR0FBTUcsTUFFdEIsQ0FXTyxTQUFTQyx1QkFBdUJKLEdBU3JDLE1BUnNCLENBQ3BCLG1EQUNBLHVFQUNBLHdFQUNBLHVGQUNBLHFFQUdtQkssTUFBTUMsR0FBWUEsRUFBUUMsS0FBS1AsSUFDdEQsQ0FTTyxTQUFTUSxjQUNkLE1BQU1DLEVBQVFDLFFBQVFDLE9BQU9DLFNBQzdCLE1BQU8sSUFBTUMsT0FBT0gsUUFBUUMsT0FBT0MsU0FBV0gsR0FBUyxHQUN6RCxDQVlPLFNBQVNLLFlBQVlDLEVBQU9DLEVBQVksR0FDN0MsTUFBTUMsRUFBYUMsS0FBS0MsSUFBSSxHQUFJSCxHQUFhLEdBQzdDLE9BQU9FLEtBQUtFLE9BQU9MLEVBQVFFLEdBQWNBLENBQzNDLENBNkJPLFNBQVNJLFdBQVdDLEVBQVlDLEVBQW9CQyxHQUFhLEdBQ3RFLEdBQUlGLEdBQW9DLGlCQUFmQSxFQUd2QixPQUZBQSxFQUFhQSxFQUFXMUIsUUFFVDZCLFNBQVMsT0FFZkYsRUFDSEYsV0FDRUssR0FBQUEsYUFBYW5ELGdCQUFnQitDLEdBQWEsUUFDMUNDLEVBQ0FDLEdBRUYsTUFFSEEsSUFDQUYsRUFBV0ssV0FBVyxlQUNyQkwsRUFBV0ssV0FBVyxnQkFDdEJMLEVBQVdLLFdBQVcsU0FDdEJMLEVBQVdLLFdBQVcsVUFHakIsSUFBSUwsT0FJTkEsRUFBV3BELFFBQVEsS0FBTSxHQUVwQyxDQ3ZYQSxNQUFNMEQsT0FBUyxDQUFDLE1BQU8sU0FBVSxPQUFRLE9BQVEsU0FHM0NDLFFBQVUsQ0FFZEMsV0FBVyxFQUNYQyxRQUFRLEVBQ1JDLGFBQWEsRUFFYkMsVUFBVyxHQUVYQyxXQUFZLENBQ1YsQ0FDRUMsTUFBTyxRQUNQQyxNQUFPUixPQUFPLElBRWhCLENBQ0VPLE1BQU8sVUFDUEMsTUFBT1IsT0FBTyxJQUVoQixDQUNFTyxNQUFPLFNBQ1BDLE1BQU9SLE9BQU8sSUFFaEIsQ0FDRU8sTUFBTyxVQUNQQyxNQUFPUixPQUFPLElBRWhCLENBQ0VPLE1BQU8sWUFDUEMsTUFBT1IsT0FBTyxNQWtCYixTQUFTUyxPQUFPQyxHQUNyQixNQUFPQyxLQUFhQyxHQUFTRixHQUd2QkosV0FBRUEsRUFBVU8sTUFBRUEsR0FBVVosUUFHOUIsR0FDZSxJQUFiVSxJQUNjLElBQWJBLEdBQWtCQSxFQUFXRSxHQUFTQSxFQUFRUCxFQUFXL0IsUUFFMUQsT0FJRixNQUFNdUMsRUFBUyxHQUFHaEQsaUJBQWlCd0MsRUFBV0ssRUFBVyxHQUFHSixXQUd4RE4sUUFBUUUsUUFDVlksV0FBV0gsRUFBT0UsR0FJaEJiLFFBQVFDLFdBQ1ZjLFFBQVFQLElBQUlRLFdBQ1ZDLEVBQ0EsQ0FBQ0osRUFBT2pELFdBQVdvQyxRQUFRSyxXQUFXSyxFQUFXLEdBQUdILFFBQVFXLE9BQU9QLEdBR3pFLENBZ0JPLFNBQVNRLGFBQWFULEVBQVVVLEVBQU9DLEdBRTVDLE1BQU1DLEVBQWNELEdBQWlCRCxFQUFNRyxTQUdyQ1gsTUFBRUEsRUFBS1AsV0FBRUEsR0FBZUwsUUFHOUIsR0FBaUIsSUFBYlUsR0FBa0JBLEVBQVdFLEdBQVNBLEVBQVFQLEVBQVcvQixPQUMzRCxPQUlGLE1BQU11QyxFQUFTLEdBQUdoRCxpQkFBaUJ3QyxFQUFXSyxFQUFXLEdBQUdKLFdBR3REa0IsRUFBZUosRUFBTUssTUFHckJkLEVBQVEsQ0FBQ1csR0FDWEUsR0FDRmIsRUFBTWUsS0FBSyxLQUFNRixHQUlmeEIsUUFBUUUsUUFDVlksV0FBV0gsRUFBT0UsR0FJaEJiLFFBQVFDLFdBQ1ZjLFFBQVFQLElBQUlRLFdBQ1ZDLEVBQ0EsQ0FBQ0osRUFBT2pELFdBQVdvQyxRQUFRSyxXQUFXSyxFQUFXLEdBQUdILFFBQVFXLE9BQU8sQ0FDakVQLEVBQU0vRCxRQUFRbUQsT0FBT1csRUFBVyxPQUM3QkMsSUFJWCxDQWFPLFNBQVNnQixhQUFhakIsRUFBVWtCLEVBQVMsR0FBSVAsR0FDbERGLGFBQ0VULEVBQ0EsS0FDQSxDQUNFLEdBQUdXLDJDQUNBTyxFQUFPQyxLQUFLQyxHQUFVLEtBQUtBLEVBQU1QLGFBQ3BDaEUsS0FBSyxNQUVYLENBU08sU0FBU3dFLFlBQVlDLEdBRTFCLE1BQU1wQixNQUFFQSxFQUFLcUIsS0FBRUEsRUFBSUMsS0FBRUEsRUFBSWpDLFVBQUVBLEVBQVNDLE9BQUVBLEdBQVc4QixFQUdqREcsWUFBWXZCLEdBR1p3QixxQkFBcUJuQyxHQUdyQm9DLGtCQUFrQkosRUFBTUMsRUFBTWhDLEVBQ2hDLENBVU8sU0FBU2lDLFlBQVl2QixHQUN0QkEsR0FBUyxHQUFLQSxHQUFTWixRQUFRSyxXQUFXL0IsU0FDNUMwQixRQUFRWSxNQUFRQSxFQUVwQixDQVNPLFNBQVN3QixxQkFBcUJuQyxHQUVuQ0QsUUFBUUMsVUFBWUEsQ0FDdEIsQ0FXTyxTQUFTb0Msa0JBQWtCSixFQUFNQyxFQUFNaEMsR0FFNUNGLFFBQVFFLE9BQVNBLEVBR2JBLElBQ0ZGLFFBQVFpQyxLQUFPQSxFQUNmakMsUUFBUWtDLEtBQU9BLEVBRW5CLENBWUEsU0FBU3BCLFdBQVdILEVBQU9FLEdBQ3BCYixRQUFRRyxlQUVWbUMsY0FBVzVGLGdCQUFnQnNELFFBQVFpQyxRQUNsQ00sR0FBQUEsVUFBVTdGLGdCQUFnQnNELFFBQVFpQyxPQUdwQ2pDLFFBQVFJLFVBQVkxRCxnQkFBZ0JhLEtBQUlBLEtBQUN5QyxRQUFRaUMsS0FBTWpDLFFBQVFrQyxPQUkvRGxDLFFBQVFHLGFBQWMsR0FJeEJxQyxHQUFVQSxXQUNSeEMsUUFBUUksVUFDUixDQUFDUyxHQUFRSyxPQUFPUCxHQUFPcEQsS0FBSyxLQUFPLE1BQ2xDNkQsSUFDS0EsR0FBU3BCLFFBQVFFLFFBQVVGLFFBQVFHLGNBQ3JDSCxRQUFRRSxRQUFTLEVBQ2pCRixRQUFRRyxhQUFjLEVBQ3RCZ0IsYUFBYSxFQUFHQyxFQUFPLHlDQUN4QixHQUdQLENDM1BPLE1BQU1xQixjQUFnQixDQUMzQkMsVUFBVyxDQUNUakMsS0FBTSxDQUNKdkIsTUFBTyxDQUNMLG1DQUNBLGtCQUNBLDBDQUNBLDJCQUNBLGtDQUNBLGtDQUNBLHdDQUNBLDJDQUNBLHFCQUNBLDRCQUNBLDJDQUNBLHVEQUNBLDZCQUNBLHlCQUNBLDBCQUNBLCtCQUNBLHVCQUNBLHVGQUNBLHlCQUNBLG9DQUNBLG9CQUNBLDBCQUNBLDhDQUNBLDJCQUNBLDBCQUNBLDZCQUNBLG1DQUNBLHdDQUNBLG1DQUNBLDJCQUNBLGtDQUNBLHVCQUNBLGlCQUNBLHlCQUNBLDhCQUNBLG9CQUNBLDJCQUNBLGVBQ0EsNkJBQ0EsaUJBQ0EsYUFDQSxlQUNBLHNCQUNBLGNBQ0EseUJBQ0Esb0JBQ0EsdUJBRUZ5RCxNQUFPLENBQUMsWUFDUkMsUUFBUyxpQkFDVEMsUUFBUyxnQkFDVEMsWUFBYSwrQkFDYkMsY0FBZSxDQUNidkcsS0FBTSxPQUNOd0csVUFBVyxPQUlqQkMsV0FBWSxDQUNWQyxRQUFTLENBQ1BoRSxNQUFPLFNBQ1B5RCxNQUFPLENBQUMsVUFDUkMsUUFBUyxxQkFDVEUsWUFBYSxxQkFDYkMsY0FBZSxDQUNidkcsS0FBTSxTQUdWMkcsT0FBUSxDQUNOakUsTUFBTyw4QkFDUHlELE1BQU8sQ0FBQyxVQUNSQyxRQUFTLHFCQUNURSxZQUFhLGlDQUNiQyxjQUFlLENBQ2J2RyxLQUFNLFNBR1Y0RyxXQUFZLENBQ1ZsRSxPQUFPLEVBQ1B5RCxNQUFPLENBQUMsV0FDUkMsUUFBUyx5QkFDVEUsWUFBYSxrREFDYkMsY0FBZSxDQUNidkcsS0FBTSxXQUdWNkcsVUFBVyxDQUNUbkUsTUFBTyxTQUNQeUQsTUFBTyxDQUFDLFVBQ1JDLFFBQVMsd0JBQ1RFLFlBQWEsK0NBQ2JDLGNBQWUsQ0FDYnZHLEtBQU0sU0FHVjhHLFlBQWEsQ0FDWHBFLE1BQU8sQ0FBQyxhQUFjLGtCQUFtQixpQkFDekN5RCxNQUFPLENBQUMsWUFDUkMsUUFBUywwQkFDVEUsWUFBYSxtQ0FDYkMsY0FBZSxDQUNidkcsS0FBTSxjQUNOK0csYUFBYywwREFHbEJDLGNBQWUsQ0FDYnRFLE1BQU8sQ0FDTCxRQUNBLE1BQ0EsUUFDQSxZQUNBLHVCQUNBLGdCQUVBLGVBQ0EsUUFDQSxPQUNBLGFBQ0EsbUJBQ0EsZUFDQSxjQUNBLFVBQ0EsVUFDQSxjQUNBLFdBQ0EsVUFDQSxZQUNBLGNBQ0EsWUFDQSxzQkFDQSxTQUNBLFNBQ0EsV0FDQSxhQUNBLFlBQ0EsZUFDQSx5QkFDQSxTQUNBLGVBQ0EsWUFDQSxrQkFDQSxTQUNBLGNBQ0EsbUJBQ0EsZUFDQSxrQkFDQSxjQUNBLGVBRUEsY0FDQSxXQUNBLGVBQ0EsV0FDQSxTQUNBLE9BQ0EsV0FDQSxZQUNBLFNBQ0EscUJBQ0EsYUFDQSxXQUNBLFdBQ0EsV0FDQSxXQUNBLGVBQ0EsVUFDQSxrQkFDQSxvQkFDQSxhQUNBLFVBQ0EsY0FDQSxZQUNBLFlBRUZ5RCxNQUFPLENBQUMsWUFDUkMsUUFBUyw0QkFDVEUsWUFBYSxxQ0FDYkMsY0FBZSxDQUNidkcsS0FBTSxjQUNOK0csYUFBYywwREFHbEJFLGlCQUFrQixDQUNoQnZFLE1BQU8sQ0FBQyxrQkFDUnlELE1BQU8sQ0FBQyxZQUNSQyxRQUFTLCtCQUNURSxZQUFhLHdDQUNiQyxjQUFlLENBQ2J2RyxLQUFNLGNBQ04rRyxhQUFjLDBEQUdsQkcsY0FBZSxDQUNieEUsTUFBTyxDQUNMLHdFQUNBLGtHQUVGeUQsTUFBTyxDQUFDLFlBQ1JDLFFBQVMsNEJBQ1RFLFlBQWEscURBQ2JDLGNBQWUsQ0FDYnZHLEtBQU0sT0FDTndHLFVBQVcsT0FJakJXLE9BQVEsQ0FDTkMsT0FBUSxDQUNOMUUsTUFBTyxLQUNQeUQsTUFBTyxDQUFDLFNBQVUsUUFDbEJDLFFBQVMsZ0JBQ1RFLFlBQ0UsK0RBQ0ZDLGNBQWUsQ0FDYnZHLEtBQU0sU0FHVnFILE1BQU8sQ0FDTDNFLE1BQU8sS0FDUHlELE1BQU8sQ0FBQyxTQUFVLFFBQ2xCQyxRQUFTLGVBQ1RFLFlBQ0UsbUVBQ0ZDLGNBQWUsQ0FDYnZHLEtBQU0sU0FHVnNILFFBQVMsQ0FDUDVFLE1BQU8sS0FDUHlELE1BQU8sQ0FBQyxTQUFVLFFBQ2xCQyxRQUFTLGlCQUNURSxZQUFhLCtCQUNiQyxjQUFlLENBQ2J2RyxLQUFNLFNBR1Z1SCxJQUFLLENBQ0g3RSxNQUFPLEtBQ1B5RCxNQUFPLENBQUMsU0FBVSxRQUNsQkMsUUFBUyxhQUNURSxZQUFhLG1EQUNiQyxjQUFlLENBQ2J2RyxLQUFNLFNBR1Z3SCxNQUFPLENBQ0w5RSxNQUFPLEtBQ1B5RCxNQUFPLENBQUMsU0FBVSxRQUNsQkMsUUFBUyxlQUNURSxZQUNFLGdFQUNGQyxjQUFlLENBQ2J2RyxLQUFNLFNBR1ZDLFFBQVMsQ0FDUHlDLE1BQU8sS0FDUHlELE1BQU8sQ0FBQyxTQUFVLFFBQ2xCQyxRQUFTLGlCQUNURSxZQUNFLHFGQUNGQyxjQUFlLENBQ2J2RyxLQUFNLFNBR1ZBLEtBQU0sQ0FDSjBDLE1BQU8sTUFDUHlELE1BQU8sQ0FBQyxVQUNSQyxRQUFTLGNBQ1RFLFlBQWEsb0RBQ2JDLGNBQWUsQ0FDYnZHLEtBQU0sU0FDTnlILEtBQU0sZUFDTkMsUUFBUyxDQUFDLE1BQU8sT0FBUSxNQUFPLFNBR3BDaEksT0FBUSxDQUNOZ0QsTUFBTyxRQUNQeUQsTUFBTyxDQUFDLFVBQ1JDLFFBQVMsZ0JBQ1RFLFlBQ0UsdUVBQ0ZDLGNBQWUsQ0FDYnZHLEtBQU0sU0FDTnlILEtBQU0saUJBQ05DLFFBQVMsQ0FBQyxRQUFTLGFBQWMsV0FBWSxnQkFHakRDLElBQUssQ0FDSGpGLE9BQU8sRUFDUHlELE1BQU8sQ0FBQyxXQUNSQyxRQUFTLGFBQ1RFLFlBQ0Usb0ZBQ0ZDLGNBQWUsQ0FDYnZHLEtBQU0sV0FHVjRILFdBQVksQ0FDVmxGLE9BQU8sRUFDUHlELE1BQU8sQ0FBQyxXQUNSQyxRQUFTLHFCQUNURSxZQUNFLDBFQUNGQyxjQUFlLENBQ2J2RyxLQUFNLFdBR1Y2SCxPQUFRLENBQ05uRixNQUFPLEtBQ1B5RCxNQUFPLENBQUMsU0FBVSxRQUNsQkMsUUFBUyxnQkFDVEUsWUFBYSx5REFDYkMsY0FBZSxDQUNidkcsS0FBTSxXQUdWOEgsTUFBTyxDQUNMcEYsTUFBTyxLQUNQeUQsTUFBTyxDQUFDLFNBQVUsUUFDbEJDLFFBQVMsZUFDVEUsWUFBYSx3REFDYkMsY0FBZSxDQUNidkcsS0FBTSxXQUdWK0gsTUFBTyxDQUNMckYsTUFBTyxLQUNQeUQsTUFBTyxDQUFDLFNBQVUsUUFDbEJDLFFBQVMsZUFDVEUsWUFDRSxnRkFDRkMsY0FBZSxDQUNidkcsS0FBTSxXQUdWZ0ksY0FBZSxDQUNidEYsTUFBTyxJQUNQeUQsTUFBTyxDQUFDLFVBQ1JDLFFBQVMsd0JBQ1RFLFlBQWEsa0RBQ2JDLGNBQWUsQ0FDYnZHLEtBQU0sV0FHVmlJLGFBQWMsQ0FDWnZGLE1BQU8sSUFDUHlELE1BQU8sQ0FBQyxVQUNSQyxRQUFTLHVCQUNURSxZQUFhLGlEQUNiQyxjQUFlLENBQ2J2RyxLQUFNLFdBR1ZrSSxhQUFjLENBQ1p4RixNQUFPLEVBQ1B5RCxNQUFPLENBQUMsVUFDUkMsUUFBUyx1QkFDVEUsWUFDRSx5RUFDRkMsY0FBZSxDQUNidkcsS0FBTSxTQUNObUksSUFBSyxHQUNMQyxJQUFLLElBR1RDLGNBQWUsQ0FDYjNGLE1BQU8sS0FDUHlELE1BQU8sQ0FBQyxTQUFVLFNBQVUsUUFDNUJDLFFBQVMsd0JBQ1RFLFlBQ0UsbUZBQ0ZDLGNBQWUsQ0FDYnZHLEtBQU0sU0FHVnNJLGFBQWMsQ0FDWjVGLE1BQU8sS0FDUHlELE1BQU8sQ0FBQyxTQUFVLFNBQVUsUUFDNUJDLFFBQVMsdUJBQ1RFLFlBQ0Usa0ZBQ0ZDLGNBQWUsQ0FDYnZHLEtBQU0sU0FHVnVJLHFCQUFzQixDQUNwQjdGLE1BQU8sS0FDUHlELE1BQU8sQ0FBQyxVQUNSQyxRQUFTLCtCQUNURSxZQUFhLDZDQUNiQyxjQUFlLENBQ2J2RyxLQUFNLFlBSVp3SSxZQUFhLENBQ1hDLG1CQUFvQixDQUNsQi9GLE9BQU8sRUFDUHlELE1BQU8sQ0FBQyxXQUNSQyxRQUFTLG9DQUNURSxZQUNFLG1FQUNGQyxjQUFlLENBQ2J2RyxLQUFNLFdBR1ZrRCxtQkFBb0IsQ0FDbEJSLE9BQU8sRUFDUHlELE1BQU8sQ0FBQyxXQUNSQyxRQUFTLG9DQUNURSxZQUNFLGtGQUNGQyxjQUFlLENBQ2J2RyxLQUFNLFdBR1ZpRCxXQUFZLENBQ1ZQLE1BQU8sS0FDUHlELE1BQU8sQ0FBQyxTQUFVLFFBQ2xCQyxRQUFTLDJCQUNURSxZQUNFLHVIQUNGQyxjQUFlLENBQ2J2RyxLQUFNLFNBR1YwSSxTQUFVLENBQ1JoRyxNQUFPLEtBQ1B5RCxNQUFPLENBQUMsU0FBVSxRQUNsQkMsUUFBUyx3QkFDVEUsWUFDRSxrRkFDRkMsY0FBZSxDQUNidkcsS0FBTSxTQUdWMkksVUFBVyxDQUNUakcsTUFBTyxLQUNQeUQsTUFBTyxDQUFDLFNBQVUsU0FBVSxRQUM1QkMsUUFBUyx5QkFDVEUsWUFDRSxzR0FDRkMsY0FBZSxDQUNidkcsS0FBTSxTQUdWNEksV0FBWSxDQUNWbEcsTUFBTyxLQUNQeUQsTUFBTyxDQUFDLFNBQVUsUUFDbEJDLFFBQVMsMkJBQ1R5QyxXQUFZLFdBQ1p2QyxZQUFhLCtDQUNiQyxjQUFlLENBQ2J2RyxLQUFNLFNBR1Y4SSxhQUFjLENBQ1pwRyxNQUFPLEtBQ1B5RCxNQUFPLENBQUMsU0FBVSxRQUNsQkMsUUFBUyw2QkFDVEUsWUFDRSwrREFDRkMsY0FBZSxDQUNidkcsS0FBTSxVQUlaK0ksT0FBUSxDQUNOQyxPQUFRLENBQ050RyxPQUFPLEVBQ1B5RCxNQUFPLENBQUMsV0FDUkMsUUFBUyxnQkFDVEMsUUFBUyxlQUNUQyxZQUFhLDhCQUNiQyxjQUFlLENBQ2J2RyxLQUFNLFdBR1ZpSixLQUFNLENBQ0p2RyxNQUFPLFVBQ1B5RCxNQUFPLENBQUMsVUFDUkMsUUFBUyxjQUNURSxZQUFhLHlCQUNiQyxjQUFlLENBQ2J2RyxLQUFNLFNBR1ZrSixLQUFNLENBQ0p4RyxNQUFPLEtBQ1B5RCxNQUFPLENBQUMsVUFDUkMsUUFBUyxjQUNURSxZQUFhLDZCQUNiQyxjQUFlLENBQ2J2RyxLQUFNLFdBR1ZtSixZQUFhLENBQ1h6RyxNQUFPLEVBQ1B5RCxNQUFPLENBQUMsVUFDUkMsUUFBUyxzQkFDVEUsWUFBYSxrQ0FDYkMsY0FBZSxDQUNidkcsS0FBTSxXQUdWb0osYUFBYyxDQUNaMUcsT0FBTyxFQUNQeUQsTUFBTyxDQUFDLFdBQ1JDLFFBQVMsc0JBQ1RDLFFBQVMscUJBQ1RDLFlBQ0UsMEVBQ0ZDLGNBQWUsQ0FDYnZHLEtBQU0sV0FHVnFKLE1BQU8sQ0FDTEosS0FBTSxDQUNKdkcsTUFBTyxLQUNQeUQsTUFBTyxDQUFDLFNBQVUsUUFDbEJDLFFBQVMsb0JBQ1RDLFFBQVMsWUFDVEMsWUFBYSwwQ0FDYkMsY0FBZSxDQUNidkcsS0FBTSxTQUdWa0osS0FBTSxDQUNKeEcsTUFBTyxLQUNQeUQsTUFBTyxDQUFDLFNBQVUsUUFDbEJDLFFBQVMsb0JBQ1RDLFFBQVMsWUFDVEMsWUFBYSwwQ0FDYkMsY0FBZSxDQUNidkcsS0FBTSxXQUdWc0osUUFBUyxDQUNQNUcsTUFBTyxJQUNQeUQsTUFBTyxDQUFDLFVBQ1JDLFFBQVMsdUJBQ1RDLFFBQVMsZUFDVEMsWUFDRSw4REFDRkMsY0FBZSxDQUNidkcsS0FBTSxZQUladUosYUFBYyxDQUNaUCxPQUFRLENBQ050RyxPQUFPLEVBQ1B5RCxNQUFPLENBQUMsV0FDUkMsUUFBUyw4QkFDVEMsUUFBUyxxQkFDVEMsWUFBYSxrREFDYkMsY0FBZSxDQUNidkcsS0FBTSxXQUdWd0osWUFBYSxDQUNYOUcsTUFBTyxHQUNQeUQsTUFBTyxDQUFDLFVBQ1JDLFFBQVMsb0NBQ1R5QyxXQUFZLFlBQ1p2QyxZQUFhLGdEQUNiQyxjQUFlLENBQ2J2RyxLQUFNLFdBR1Z5SixPQUFRLENBQ04vRyxNQUFPLEVBQ1B5RCxNQUFPLENBQUMsVUFDUkMsUUFBUyw4QkFDVEUsWUFBYSwyQ0FDYkMsY0FBZSxDQUNidkcsS0FBTSxXQUdWMEosTUFBTyxDQUNMaEgsTUFBTyxFQUNQeUQsTUFBTyxDQUFDLFVBQ1JDLFFBQVMsNkJBQ1RFLFlBQ0UsdUVBQ0ZDLGNBQWUsQ0FDYnZHLEtBQU0sV0FHVjJKLFdBQVksQ0FDVmpILE9BQU8sRUFDUHlELE1BQU8sQ0FBQyxXQUNSQyxRQUFTLG1DQUNURSxZQUFhLHNEQUNiQyxjQUFlLENBQ2J2RyxLQUFNLFdBR1Y0SixRQUFTLENBQ1BsSCxNQUFPLEtBQ1B5RCxNQUFPLENBQUMsU0FBVSxRQUNsQkMsUUFBUyxnQ0FDVEUsWUFBYSx3REFDYkMsY0FBZSxDQUNidkcsS0FBTSxTQUdWNkosVUFBVyxDQUNUbkgsTUFBTyxLQUNQeUQsTUFBTyxDQUFDLFNBQVUsUUFDbEJDLFFBQVMsa0NBQ1RFLFlBQWEsd0RBQ2JDLGNBQWUsQ0FDYnZHLEtBQU0sVUFJWjhKLElBQUssQ0FDSGQsT0FBUSxDQUNOdEcsT0FBTyxFQUNQeUQsTUFBTyxDQUFDLFdBQ1JDLFFBQVMsb0JBQ1RDLFFBQVMsWUFDVEMsWUFBYSxtQ0FDYkMsY0FBZSxDQUNidkcsS0FBTSxXQUdWK0osTUFBTyxDQUNMckgsT0FBTyxFQUNQeUQsTUFBTyxDQUFDLFdBQ1JDLFFBQVMsbUJBQ1RDLFFBQVMsV0FDVHdDLFdBQVksVUFDWnZDLFlBQWEsZ0RBQ2JDLGNBQWUsQ0FDYnZHLEtBQU0sV0FHVmtKLEtBQU0sQ0FDSnhHLE1BQU8sSUFDUHlELE1BQU8sQ0FBQyxVQUNSQyxRQUFTLGtCQUNUQyxRQUFTLFVBQ1RDLFlBQWEsMEJBQ2JDLGNBQWUsQ0FDYnZHLEtBQU0sV0FHVmdLLFNBQVUsQ0FDUnRILE1BQU8sS0FDUHlELE1BQU8sQ0FBQyxTQUFVLFFBQ2xCQyxRQUFTLHVCQUNUQyxRQUFTLGNBQ1R3QyxXQUFZLFVBQ1p2QyxZQUFhLHVDQUNiQyxjQUFlLENBQ2J2RyxLQUFNLFdBS2RpSyxLQUFNLENBQ0pDLFdBQVksQ0FDVnhILE1BQU8sRUFDUHlELE1BQU8sQ0FBQyxVQUNSQyxRQUFTLG1CQUNURSxZQUFhLHNEQUNiQyxjQUFlLENBQ2J2RyxLQUFNLFdBR1ZtSyxXQUFZLENBQ1Z6SCxNQUFPLEVBQ1B5RCxNQUFPLENBQUMsVUFDUkMsUUFBUyxtQkFDVHlDLFdBQVksVUFDWnZDLFlBQWEsMENBQ2JDLGNBQWUsQ0FDYnZHLEtBQU0sV0FHVm9LLFVBQVcsQ0FDVDFILE1BQU8sR0FDUHlELE1BQU8sQ0FBQyxVQUNSQyxRQUFTLGtCQUNURSxZQUFhLHdEQUNiQyxjQUFlLENBQ2J2RyxLQUFNLFdBR1ZxSyxlQUFnQixDQUNkM0gsTUFBTyxJQUNQeUQsTUFBTyxDQUFDLFVBQ1JDLFFBQVMsdUJBQ1RFLFlBQWEsbURBQ2JDLGNBQWUsQ0FDYnZHLEtBQU0sV0FHVnNLLGNBQWUsQ0FDYjVILE1BQU8sSUFDUHlELE1BQU8sQ0FBQyxVQUNSQyxRQUFTLHNCQUNURSxZQUFhLGtEQUNiQyxjQUFlLENBQ2J2RyxLQUFNLFdBR1Z1SyxlQUFnQixDQUNkN0gsTUFBTyxJQUNQeUQsTUFBTyxDQUFDLFVBQ1JDLFFBQVMsdUJBQ1RFLFlBQWEsb0RBQ2JDLGNBQWUsQ0FDYnZHLEtBQU0sV0FHVndLLFlBQWEsQ0FDWDlILE1BQU8sSUFDUHlELE1BQU8sQ0FBQyxVQUNSQyxRQUFTLG9CQUNURSxZQUFhLHdEQUNiQyxjQUFlLENBQ2J2RyxLQUFNLFdBR1Z5SyxvQkFBcUIsQ0FDbkIvSCxNQUFPLElBQ1B5RCxNQUFPLENBQUMsVUFDUkMsUUFBUyw2QkFDVEUsWUFDRSx3RUFDRkMsY0FBZSxDQUNidkcsS0FBTSxXQUdWMEssZUFBZ0IsQ0FDZGhJLE1BQU8sSUFDUHlELE1BQU8sQ0FBQyxVQUNSQyxRQUFTLHVCQUNURSxZQUNFLCtEQUNGQyxjQUFlLENBQ2J2RyxLQUFNLFdBR1ZvSixhQUFjLENBQ1oxRyxPQUFPLEVBQ1B5RCxNQUFPLENBQUMsV0FDUkMsUUFBUyxvQkFDVEMsUUFBUyxtQkFDVEMsWUFBYSw2Q0FDYkMsY0FBZSxDQUNidkcsS0FBTSxZQUlad0QsUUFBUyxDQUNQWSxNQUFPLENBQ0wxQixNQUFPLEVBQ1B5RCxNQUFPLENBQUMsVUFDUkMsUUFBUyxnQkFDVEMsUUFBUyxXQUNUQyxZQUFhLDBCQUNiQyxjQUFlLENBQ2J2RyxLQUFNLFNBQ04rQyxNQUFPLEVBQ1BvRixJQUFLLEVBQ0xDLElBQUssSUFHVDFDLEtBQU0sQ0FDSmhELE1BQU8sK0JBQ1B5RCxNQUFPLENBQUMsVUFDUkMsUUFBUyxlQUNUQyxRQUFTLFVBQ1RDLFlBQ0UsOERBQ0ZDLGNBQWUsQ0FDYnZHLEtBQU0sU0FHVnlGLEtBQU0sQ0FDSi9DLE1BQU8sTUFDUHlELE1BQU8sQ0FBQyxVQUNSQyxRQUFTLGVBQ1RDLFFBQVMsVUFDVEMsWUFBYSwwREFDYkMsY0FBZSxDQUNidkcsS0FBTSxTQUdWeUQsVUFBVyxDQUNUZixPQUFPLEVBQ1B5RCxNQUFPLENBQUMsV0FDUkMsUUFBUyxxQkFDVEMsUUFBUyxlQUNUQyxZQUFhLHNDQUNiQyxjQUFlLENBQ2J2RyxLQUFNLFdBR1YwRCxPQUFRLENBQ05oQixPQUFPLEVBQ1B5RCxNQUFPLENBQUMsV0FDUkMsUUFBUyxrQkFDVEMsUUFBUyxZQUNUQyxZQUFhLHdDQUNiQyxjQUFlLENBQ2J2RyxLQUFNLFlBSVoySyxHQUFJLENBQ0YzQixPQUFRLENBQ050RyxPQUFPLEVBQ1B5RCxNQUFPLENBQUMsV0FDUkMsUUFBUyxZQUNUQyxRQUFTLFdBQ1RDLFlBQWEsbURBQ2JDLGNBQWUsQ0FDYnZHLEtBQU0sV0FHVjRLLE1BQU8sQ0FDTGxJLE1BQU8sSUFDUHlELE1BQU8sQ0FBQyxVQUNSQyxRQUFTLFdBQ1RDLFFBQVMsVUFDVEMsWUFBYSxnQ0FDYkMsY0FBZSxDQUNidkcsS0FBTSxVQUlaNkssTUFBTyxDQUNMQyxRQUFTLENBQ1BwSSxNQUFPLGFBQ1B5RCxNQUFPLENBQUMsVUFDUkMsUUFBUyxpQkFDVEUsWUFBYSwrQkFDYkMsY0FBZSxDQUNidkcsS0FBTSxTQUdWK0sscUJBQXNCLENBQ3BCckksT0FBTyxFQUNQeUQsTUFBTyxDQUFDLFdBQ1JDLFFBQVMsZ0NBQ1RFLFlBQWEsaURBQ2JDLGNBQWUsQ0FDYnZHLEtBQU0sV0FHVmdMLE9BQVEsQ0FDTnRJLE9BQU8sRUFDUHlELE1BQU8sQ0FBQyxXQUNSQyxRQUFTLGdCQUNURSxZQUFhLCtDQUNiQyxjQUFlLENBQ2J2RyxLQUFNLFdBR1ZpTCxjQUFlLENBQ2J2SSxPQUFPLEVBQ1B5RCxNQUFPLENBQUMsV0FDUkMsUUFBUyx3QkFDVEUsWUFBYSxvREFDYkMsY0FBZSxDQUNidkcsS0FBTSxXQUdWa0wsaUJBQWtCLENBQ2hCeEksT0FBTyxFQUNQeUQsTUFBTyxDQUFDLFdBQ1JDLFFBQVMsMkJBQ1RFLFlBQWEseURBQ2JDLGNBQWUsQ0FDYnZHLEtBQU0sWUFJWm1MLE1BQU8sQ0FDTG5DLE9BQVEsQ0FDTnRHLE9BQU8sRUFDUHlELE1BQU8sQ0FBQyxXQUNSQyxRQUFTLGVBQ1RDLFFBQVMsY0FDVEMsWUFBYSw0REFDYkMsY0FBZSxDQUNidkcsS0FBTSxXQUdWb0wsU0FBVSxDQUNSMUksT0FBTyxFQUNQeUQsTUFBTyxDQUFDLFdBQ1JDLFFBQVMsaUJBQ1RFLFlBQ0UsNkVBQ0ZDLGNBQWUsQ0FDYnZHLEtBQU0sV0FHVnFMLFNBQVUsQ0FDUjNJLE9BQU8sRUFDUHlELE1BQU8sQ0FBQyxXQUNSQyxRQUFTLGlCQUNURSxZQUFhLCtDQUNiQyxjQUFlLENBQ2J2RyxLQUFNLFdBR1ZzTCxnQkFBaUIsQ0FDZjVJLE9BQU8sRUFDUHlELE1BQU8sQ0FBQyxXQUNSQyxRQUFTLDBCQUNURSxZQUNFLHFFQUNGQyxjQUFlLENBQ2J2RyxLQUFNLFdBR1Z1TCxPQUFRLENBQ043SSxPQUFPLEVBQ1B5RCxNQUFPLENBQUMsV0FDUkMsUUFBUyxlQUNURSxZQUNFLGtGQUNGQyxjQUFlLENBQ2J2RyxLQUFNLFdBR1Z3TCxPQUFRLENBQ045SSxNQUFPLEVBQ1B5RCxNQUFPLENBQUMsVUFDUkMsUUFBUyxnQkFDVEUsWUFBYSw0REFDYkMsY0FBZSxDQUNidkcsS0FBTSxXQUdWeUwsY0FBZSxDQUNiL0ksTUFBTyxLQUNQeUQsTUFBTyxDQUFDLFVBQ1JDLFFBQVMsdUJBQ1RFLFlBQWEsMEJBQ2JDLGNBQWUsQ0FDYnZHLEtBQU0sYUFPRDBMLFlBQWNDLG1CQUFtQjFGLGVBR2pDMkYsY0FBZ0JDLHFCQUFxQjVGLGVBb0JsRCxTQUFTMEYsbUJBQW1CRyxFQUFRSixFQUFjLENBQUEsRUFBSUssRUFBWSxJQXFCaEUsT0FwQkExTSxPQUFPd0MsS0FBS2lLLEdBQVFFLFNBQVM1TSxJQUUzQixNQUFNNk0sRUFBUUgsRUFBTzFNLFFBR00sSUFBaEI2TSxFQUFNdkosTUFFZmlKLG1CQUFtQk0sRUFBT1AsRUFBYSxHQUFHSyxLQUFhM00sTUFHdkRzTSxFQUFZTyxFQUFNNUYsU0FBV2pILEdBQU8sR0FBRzJNLEtBQWEzTSxJQUFNOE0sVUFBVSxRQUczQ3pILElBQXJCd0gsRUFBTXBELGFBQ1I2QyxFQUFZTyxFQUFNcEQsWUFBYyxHQUFHa0QsS0FBYTNNLElBQU04TSxVQUFVLElBRW5FLElBSUlSLENBQ1QsQ0FpQkEsU0FBU0cscUJBQXFCQyxFQUFRRixFQUFnQixJQWtCcEQsT0FqQkF2TSxPQUFPd0MsS0FBS2lLLEdBQVFFLFNBQVM1TSxJQUUzQixNQUFNNk0sRUFBUUgsRUFBTzFNLFFBR00sSUFBaEI2TSxFQUFNOUYsTUFFZjBGLHFCQUFxQkksRUFBT0wsR0FHeEJLLEVBQU05RixNQUFNckcsU0FBUyxXQUN2QjhMLEVBQWMxRyxLQUFLOUYsRUFFdEIsSUFJSXdNLENBQ1QsQ0NuaENBTyxPQUFPTCxTQUdQLE1BQU1oRixZQUFFQSxZQUFXRSxjQUFFQSxjQUFhQyxpQkFBRUEsa0JBQ2xDaEIsY0FBY1EsV0FHaEIyRixJQUFBQSxFQUFFQyxZQUFZQyxpQkFXZCxNQUFNQyxFQUFJLENBd0JSQyxRQUFRQyxHQUNDQSxFQUNITCxJQUFBQSxFQUFFSSxVQUNGSixJQUFDQSxFQUNFTSxNQUFNLENBQ0xOLElBQUNBLEVBQ0VPLEtBQUssQ0FBQyxPQUFRLFFBQVMsWUFBYSxPQUFRLEtBQzVDQyxXQUFXbEssR0FDVCxDQUFDLFlBQWEsT0FBUSxJQUFJNUMsU0FBUzRDLEdBRWhDLEtBRFUsU0FBVkEsSUFHUjBKLElBQUFBLEVBQUVJLFlBRUhLLFdBdUJUQyxPQUFPTCxHQUNFQSxFQUNITCxJQUFDQSxFQUNFVSxTQUNBdkwsT0FDQXdMLFFBQ0VySyxJQUFXLENBQUMsUUFBUyxZQUFhLE9BQVEsSUFBSTVDLFNBQVM0QyxJQUN4RCxDQUNFc0ssT0FBUSxDQUNOQyxhQUFjLDJDQUl0QmIsSUFBQ0EsRUFDRVUsU0FDQXZMLE9BQ0FxTCxXQUFXbEssR0FDVCxDQUFDLFFBQVMsWUFBYSxPQUFRLElBQUk1QyxTQUFTNEMsR0FBaUIsS0FBUkEsSUFFdkRtSyxXQTBCVEYsS0FBSSxDQUFDbk0sRUFBUWlNLElBQ0pBLEVBQ0hMLElBQUFBLEVBQUVPLEtBQUssSUFBSW5NLElBQ1g0TCxJQUFDQSxFQUNFTyxLQUFLLElBQUluTSxFQUFRLFlBQWEsT0FBUSxLQUN0Q29NLFdBQVdsSyxHQUNULENBQUMsWUFBYSxPQUFRLElBQUk1QyxTQUFTNEMsR0FBaUIsS0FBUkEsSUFFOUNtSyxXQTRCVCxXQUFBSyxDQUFZQyxFQUFnQjNHLEVBQVdpRyxHQUNyQyxNQUFNVyxFQUFjaEIsSUFBQUEsRUFBRVUsU0FBU3ZMLE9BQU84TCxRQUNoQ0MsRUFBZWxCLElBQUNBLEVBQ25CVSxTQUNBdkwsT0FDQXFMLFdBQVdsSyxJQUNOQSxFQUFNWSxXQUFXLE9BQ25CWixFQUFRQSxFQUFNNkssTUFBTSxJQUVsQjdLLEVBQU1VLFNBQVMsT0FDakJWLEVBQVFBLEVBQU02SyxNQUFNLEdBQUksSUFFbkI3SyxFQUFNdkMsTUFBTXFHLE1BR2pCZ0gsRUFBcUI5SyxHQUN6QkEsRUFBTTJDLEtBQUszQyxHQUFVQSxFQUFNbkIsU0FBUWtNLE9BQU9OLEdBRTVDLE9BQU9WLEVBQ0hXLEVBQVlSLFVBQVVZLEdBQ3RCcEIsSUFBQ0EsRUFDRU0sTUFBTSxDQUFDWSxFQUFjRixJQUNyQlIsVUFBVVksR0FDVlosV0FBV2xLLEdBQVdBLEVBQU1aLE9BQVNZLEVBQVEsT0FDN0NtSyxVQUNSLEVBd0JEYSxZQUFZakIsR0FDSEEsRUFDSEwsTUFBRXVCLFNBQVNDLFdBQ1h4QixJQUFDQSxFQUNFTSxNQUFNLENBQ0xOLElBQUNBLEVBQ0VVLFNBQ0F2TCxPQUNBd0wsUUFDRXJLLElBQ0dtTCxNQUFNckwsT0FBT0UsS0FBV0YsT0FBT0UsR0FBUyxHQUMxQyxDQUFDLFlBQWEsT0FBUSxJQUFJNUMsU0FBUzRDLElBQ3JDLENBQ0VzSyxPQUFRLENBQ05DLGFBQWMsNENBSW5CTCxXQUFXbEssR0FDVCxDQUFDLFlBQWEsT0FBUSxJQUFJNUMsU0FBUzRDLEdBRWhDLEtBREFGLE9BQU9FLEtBR2YwSixNQUFFdUIsU0FBU0MsYUFFWmYsV0EwQlRpQixlQUFlckIsR0FDTkEsRUFDSEwsTUFBRXVCLFNBQVNJLGNBQ1gzQixJQUFDQSxFQUNFTSxNQUFNLENBQ0xOLElBQUNBLEVBQ0VVLFNBQ0F2TCxPQUNBd0wsUUFDRXJLLElBQ0dtTCxNQUFNckwsT0FBT0UsS0FBV0YsT0FBT0UsSUFBVSxHQUMzQyxDQUFDLFlBQWEsT0FBUSxJQUFJNUMsU0FBUzRDLElBQ3JDLENBQ0VzSyxPQUFRLENBQ05DLGFBQWMsZ0RBSW5CTCxXQUFXbEssR0FDVCxDQUFDLFlBQWEsT0FBUSxJQUFJNUMsU0FBUzRDLEdBRWhDLEtBREFGLE9BQU9FLEtBR2YwSixNQUFFdUIsU0FBU0ksZ0JBRVpsQixXQThCVHZKLFdBQVUsQ0FBQzBLLEVBQVV2QixJQUNaQSxFQUNITCxJQUFDQSxFQUNFVSxTQUNBdkwsT0FDQXdMLFFBQ0VySyxHQUFVc0wsRUFBU2hNLE1BQU1xQyxHQUFXM0IsRUFBTVksV0FBV2UsTUFDdEQsQ0FDRTJJLE9BQVEsQ0FDTkMsYUFBYywrQ0FBK0NlLEVBQVNqTixLQUFLLFdBSW5GcUwsSUFBQ0EsRUFDRVUsU0FDQXZMLE9BQ0F3TCxRQUNFckssR0FDQ3NMLEVBQVNoTSxNQUFNcUMsR0FBVzNCLEVBQU1ZLFdBQVdlLE1BQzNDLENBQUMsWUFBYSxPQUFRLElBQUl2RSxTQUFTNEMsSUFDckMsQ0FDRXNLLE9BQVEsQ0FDTkMsYUFBYywrQ0FBK0NlLEVBQVNqTixLQUFLLFdBSWhGNkwsV0FBV2xLLEdBQ1QsQ0FBQyxZQUFhLE9BQVEsSUFBSTVDLFNBQVM0QyxHQUFpQixLQUFSQSxJQUU5Q21LLFdBZ0JUb0IsWUFBVyxJQUNGN0IsSUFBQ0EsRUFDTE0sTUFBTSxDQUNMTixJQUFDQSxFQUNFVSxTQUNBdkwsT0FDQXdMLFFBQ0VySyxHQUNDQSxFQUFNd0wsUUFBUSxTQUFXLEdBQ3pCeEwsRUFBTXdMLFFBQVEsVUFBWSxHQUN6QnhMLEVBQU1ZLFdBQVcsTUFBUVosRUFBTVUsU0FBUyxNQUN6QyxDQUFDLFlBQWEsT0FBUSxJQUFJdEQsU0FBUzRDLElBQ3JDLENBQ0VzSyxPQUFRLENBQ05DLGFBQWMscUdBSW5CTCxXQUFXbEssR0FDVCxDQUFDLFlBQWEsT0FBUSxJQUFJNUMsU0FBUzRDLEdBQWlCLEtBQVJBLElBRWpEMEosSUFBQUEsRUFBRStCLE9BQU8sSUFBSUMsZ0JBRWR2QixXQWlCTHdCLGtCQUFpQixJQUNSakMsSUFBQ0EsRUFDTE0sTUFBTSxDQUNMTixJQUFDQSxFQUNFVSxTQUNBdkwsT0FDQXdMLFFBQ0VySyxHQUNFQSxFQUFNWixRQUFVLEdBQUtZLEVBQU1VLFNBQVMsVUFDcENWLEVBQU1ZLFdBQVcsTUFBUVosRUFBTVUsU0FBUyxNQUN6QyxDQUFDLFlBQWEsT0FBUSxJQUFJdEQsU0FBUzRDLElBQ3JDLENBQ0VzSyxPQUFRLENBQ05DLGFBQWMsNEZBSW5CTCxXQUFXbEssR0FDVCxDQUFDLFlBQWEsT0FBUSxJQUFJNUMsU0FBUzRDLEdBQWlCLEtBQVJBLElBRWpEMEosSUFBQUEsRUFBRStCLE9BQU8sSUFBSUMsZ0JBRWR2QixZQWFEZixPQUFTLENBZWI3SCxLQUFLd0ksR0FDSUYsRUFBRVcsYUFDTnhLLElBQVcsQ0FBQyxRQUFTLFlBQWEsT0FBUSxJQUFJNUMsU0FBUzRDLElBQ3hELElBQ0ErSixHQTJCSi9GLFFBQVErRixHQUNDQSxFQUNITCxJQUFDQSxFQUNFVSxTQUNBdkwsT0FDQXdMLFFBQVFySyxHQUFVLHFDQUFxQ1IsS0FBS1EsSUFBUSxDQUNuRXNLLE9BQVEsQ0FDTkMsYUFDRSwwRUFHUmIsSUFBQ0EsRUFDRVUsU0FDQXZMLE9BQ0F3TCxRQUNFckssR0FDQyxxQ0FBcUNSLEtBQUtRLElBQzFDLENBQUMsWUFBYSxPQUFRLElBQUk1QyxTQUFTNEMsSUFDckMsQ0FDRXNLLE9BQVEsQ0FDTkMsYUFDRSwwRUFJUEwsV0FBV2xLLEdBQ1QsQ0FBQyxZQUFhLE9BQVEsSUFBSTVDLFNBQVM0QyxHQUFpQixLQUFSQSxJQUU5Q21LLFdBaUJUbEcsT0FBTzhGLEdBQ0VGLEVBQUVqSixXQUFXLENBQUMsVUFBVyxZQUFhbUosR0FpQi9DN0YsV0FBVzZGLEdBQ0ZGLEVBQUVDLFFBQVFDLEdBaUJuQjVGLFVBQVU0RixHQUNERixFQUFFTyxPQUFPTCxHQWlCbEI2QixXQUFXN0IsR0FDRkYsRUFBRU8sT0FBT0wsR0FpQmxCM0YsWUFBWTJGLEdBQ0hGLEVBQUVXLGFBQ054SyxHQUFVb0UsWUFBWXBFLE1BQU01QyxTQUFTNEMsSUFDdEMsSUFDQStKLEdBa0JKekYsY0FBY3lGLEdBQ0xGLEVBQUVXLGFBQ054SyxHQUFVc0UsY0FBY3RFLE1BQU01QyxTQUFTNEMsSUFDeEMsSUFDQStKLEdBa0JKeEYsaUJBQWlCd0YsR0FDUkYsRUFBRVcsYUFDTnhLLEdBQVV1RSxpQkFBaUJ2RSxNQUFNNUMsU0FBUzRDLElBQzNDLElBQ0ErSixHQWtCSnZGLGNBQWN1RixHQUNMRixFQUFFVyxhQUNOeEssR0FBVUEsRUFBTVksV0FBVyxhQUFlWixFQUFNWSxXQUFXLFlBQzVELElBQ0FtSixHQTJCSnJGLE9BQU9xRixHQUNFQSxFQUNITCxJQUFDQSxFQUNFVSxTQUNBdkwsT0FDQXdMLFFBQ0VySyxHQUNFQSxFQUFNWixRQUFVLEdBQUtZLEVBQU1VLFNBQVMsVUFDcENWLEVBQU1aLFFBQVUsR0FBS1ksRUFBTVUsU0FBUyxTQUN2QyxDQUNFNEosT0FBUSxDQUNOQyxhQUFjLDZEQUluQkosV0FDSFQsSUFBQ0EsRUFDRVUsU0FDQXZMLE9BQ0F3TCxRQUNFckssR0FDRUEsRUFBTVosUUFBVSxHQUFLWSxFQUFNVSxTQUFTLFVBQ3BDVixFQUFNWixRQUFVLEdBQUtZLEVBQU1VLFNBQVMsU0FDckMsQ0FBQyxZQUFhLE9BQVEsSUFBSXRELFNBQVM0QyxJQUNyQyxDQUNFc0ssT0FBUSxDQUNOQyxhQUFjLDZEQUluQkwsV0FBV2xLLEdBQ1QsQ0FBQyxZQUFhLE9BQVEsSUFBSTVDLFNBQVM0QyxHQUFpQixLQUFSQSxJQUU5Q21LLFdBYVR4RixNQUFLLElBQ0lrRixFQUFFMEIsY0FhWDNHLFFBQU8sSUFDRWlGLEVBQUUwQixjQWlCWDFHLElBQUcsSUFDTTZFLElBQUNBLEVBQ0xVLFNBQ0F2TCxPQUNBd0wsUUFDRXJLLEdBQ0NBLEVBQU13TCxRQUFRLFNBQVcsR0FDekJ4TCxFQUFNd0wsUUFBUSxVQUFZLEdBQzFCLENBQUMsUUFBUyxZQUFhLE9BQVEsSUFBSXBPLFNBQVM0QyxJQUM5QyxDQUNFc0ssT0FBUSxDQUNOQyxhQUFjLGdFQUluQkwsV0FBV2xLLEdBQ1QsQ0FBQyxRQUFTLFlBQWEsT0FBUSxJQUFJNUMsU0FBUzRDLEdBQWlCLEtBQVJBLElBRXZEbUssV0EwQkw1TSxRQUFRd00sR0FDQ0EsRUFDSEwsSUFBQ0EsRUFDRVUsU0FDQXZMLE9BQ0F3TCxRQUNFckssR0FDRUEsRUFBTVosUUFBVSxHQUFLWSxFQUFNVSxTQUFTLFVBQ3BDVixFQUFNWixRQUFVLElBQ2RZLEVBQU1VLFNBQVMsU0FDZFYsRUFBTVUsU0FBUyxTQUNmVixFQUFNVSxTQUFTLFNBQ2ZWLEVBQU1VLFNBQVMsVUFDckIsQ0FDRTRKLE9BQVEsQ0FDTkMsYUFBYyxnRkFJbkJKLFdBQ0hULElBQUNBLEVBQ0VVLFNBQ0F2TCxPQUNBd0wsUUFDRXJLLEdBQ0VBLEVBQU1aLFFBQVUsR0FBS1ksRUFBTVUsU0FBUyxVQUNwQ1YsRUFBTVosUUFBVSxJQUNkWSxFQUFNVSxTQUFTLFNBQ2RWLEVBQU1VLFNBQVMsU0FDZlYsRUFBTVUsU0FBUyxTQUNmVixFQUFNVSxTQUFTLFVBQ25CLENBQUMsWUFBYSxPQUFRLElBQUl0RCxTQUFTNEMsSUFDckMsQ0FDRXNLLE9BQVEsQ0FDTkMsYUFBYyxnRkFJbkJMLFdBQVdsSyxHQUNULENBQUMsWUFBYSxPQUFRLElBQUk1QyxTQUFTNEMsR0FBaUIsS0FBUkEsSUFFOUNtSyxXQWlCVDdNLEtBQUt5TSxHQUNJRixFQUFFSSxLQUFLLENBQUMsT0FBUSxNQUFPLE1BQU8sTUFBTyxPQUFRRixHQWlCdEQvTSxPQUFPK00sR0FDRUYsRUFBRUksS0FDUCxDQUFDLFFBQVMsYUFBYyxXQUFZLGNBQ3BDRixHQWlCSjlFLElBQUk4RSxHQUNLRixFQUFFQyxRQUFRQyxHQWlCbkI3RSxXQUFXNkUsR0FDRkYsRUFBRUMsUUFBUUMsR0FpQm5CekUsY0FBY3lFLEdBQ0xGLEVBQUVtQixZQUFZakIsR0FpQnZCeEUsYUFBYXdFLEdBQ0pGLEVBQUVtQixZQUFZakIsR0F3QnZCdkUsYUFBYXVFLEdBQ0pBLEVBQ0hMLElBQUNBLEVBQUN1QixTQUFTWSxJQUFJLElBQUtDLElBQUksR0FDeEJwQyxJQUFDQSxFQUNFTSxNQUFNLENBQ0xOLElBQUNBLEVBQ0VVLFNBQ0F2TCxPQUNBd0wsUUFDRXJLLElBQ0dtTCxNQUFNckwsT0FBT0UsTUFDSCxJQUFWQSxJQUNDQSxFQUFNWSxXQUFXLE1BQ2xCZCxPQUFPRSxJQUFVLElBQ2pCRixPQUFPRSxJQUFVLEdBQ25CLENBQUMsWUFBYSxPQUFRLElBQUk1QyxTQUFTNEMsSUFDckMsQ0FDRXNLLE9BQVEsQ0FDTkMsYUFBYyxrREFJbkJMLFdBQVdsSyxHQUNULENBQUMsWUFBYSxPQUFRLElBQUk1QyxTQUFTNEMsR0FFaEMsS0FEQUYsT0FBT0UsS0FHZjBKLElBQUNBLEVBQUN1QixTQUFTWSxJQUFJLElBQUtDLElBQUksS0FFekIzQixXQWtCVCxNQUFBaEYsQ0FBTzRFLEdBQ0wsT0FBT2dDLEtBQUt6RyxjQUFjeUUsR0FBYUksVUFDeEMsRUFpQkQsS0FBQS9FLENBQU0yRSxHQUNKLE9BQU9nQyxLQUFLeEcsYUFBYXdFLEdBQWFJLFVBQ3ZDLEVBaUJELEtBQUE5RSxDQUFNMEUsR0FDSixPQUFPZ0MsS0FBS3ZHLGFBQWF1RSxHQUFhSSxVQUN2QyxFQWFEeEUsY0FBYSxJQUNKa0UsRUFBRThCLG9CQWNYL0YsYUFBWSxJQUNIaUUsRUFBRThCLG9CQWlCWDdHLE1BQU1pRixHQUNHRixFQUFFTyxPQUFPTCxHQWtCbEJsRSxxQkFBcUJrRSxHQUNaRixFQUFFdUIsZUFBZXJCLEdBaUIxQmhFLG1CQUFtQmdFLEdBQ1ZGLEVBQUVDLFFBQVFDLEdBaUJuQnZKLG1CQUFtQnVKLEdBQ1ZGLEVBQUVDLFFBQVFDLEdBaUJuQnhKLFdBQVd3SixHQUNGRixFQUFFTyxPQUFPTCxHQWlCbEIvRCxTQUFTK0QsR0FDQUYsRUFBRU8sT0FBT0wsR0E0QmxCLFNBQUE5RCxDQUFVOEQsR0FDUixNQUFNaUMsRUFBZXRDLElBQUNBLEVBQ25CK0IsT0FBTyxDQUNOUSxHQUFJcEMsRUFBRU8sUUFBTyxHQUNiOEIsSUFBS3JDLEVBQUVPLFFBQU8sR0FDZCtCLE1BQU90QyxFQUNKVyxhQUNFeEssSUFBVyxDQUFDLFlBQWEsT0FBUSxJQUFJNUMsU0FBUzRDLElBQy9DLEtBQ0EsR0FFRG1LLGFBRUppQyxVQUVHQyxFQUFnQjNDLElBQUNBLEVBQ3BCVSxTQUNBdkwsT0FDQXdMLFFBQ0VySyxHQUNFQSxFQUFNWSxXQUFXLE1BQVFaLEVBQU1VLFNBQVMsTUFDeENWLEVBQU1aLFFBQVUsR0FBS1ksRUFBTVUsU0FBUyxVQUN2QyxDQUNFNEosT0FBUSxDQUNOQyxhQUFjLHNFQUtoQitCLEVBQWdCNUMsSUFBQ0EsRUFDcEJVLFNBQ0F2TCxPQUNBd0wsUUFDRXJLLEdBQ0VBLEVBQU1ZLFdBQVcsTUFBUVosRUFBTVUsU0FBUyxNQUN4Q1YsRUFBTVosUUFBVSxHQUFLWSxFQUFNVSxTQUFTLFVBQ3JDLENBQUMsWUFBYSxPQUFRLElBQUl0RCxTQUFTNEMsSUFDckMsQ0FDRXNLLE9BQVEsQ0FDTkMsYUFBYyx1REFJbkJMLFdBQVdsSyxHQUNULENBQUMsWUFBYSxPQUFRLElBQUk1QyxTQUFTNEMsR0FBaUIsS0FBUkEsSUFHakQsT0FBTytKLEVBQ0hMLElBQUNBLEVBQUNNLE1BQU0sQ0FBQ2dDLEVBQWNLLElBQWdCbEMsV0FDdkNULElBQUNBLEVBQUNNLE1BQU0sQ0FBQ2dDLEVBQWNNLElBQWdCbkMsVUFDNUMsRUFpQkRqRSxXQUFXNkQsR0FDRkYsRUFDSk8sT0FBT0wsR0FDUE0sUUFDRXJLLEdBQ1csT0FBVkEsR0FBbUJBLEVBQU1aLFFBQVUsR0FBS1ksRUFBTVUsU0FBUyxVQUN6RCxDQUNFNEosT0FBUSxDQUNOQyxhQUFjLHNEQW9CeEIsWUFBQW5FLENBQWEyRCxHQUNYLE9BQU9nQyxLQUFLN0YsV0FBVzZELEVBQ3hCLEVBZ0JEd0MsYUFBYXhDLEdBQ0pGLEVBQUVDLFFBQVFDLEdBaUJuQnhELEtBQUt3RCxHQUNJRixFQUFFTyxPQUFPTCxHQWtCbEJ2RCxLQUFLdUQsR0FDSUYsRUFBRXVCLGVBQWVyQixHQWlCMUJ0RCxZQUFZc0QsR0FDSEYsRUFBRW1CLFlBQVlqQixHQWlCdkJ5QyxtQkFBbUJ6QyxHQUNWRixFQUFFQyxRQUFRQyxHQWlCbkIwQyxVQUFVMUMsR0FDREYsRUFBRU8sT0FBT0wsR0FrQmxCMkMsVUFBVTNDLEdBQ0RGLEVBQUV1QixlQUFlckIsR0FBYUksV0FrQnZDd0MsYUFBYTVDLEdBQ0pGLEVBQUV1QixlQUFlckIsR0FpQjFCNkMsbUJBQW1CN0MsR0FDVkYsRUFBRUMsUUFBUUMsR0FrQm5CakQsWUFBWWlELEdBQ0hGLEVBQUV1QixlQUFlckIsR0FrQjFCaEQsT0FBT2dELEdBQ0VGLEVBQUV1QixlQUFlckIsR0FrQjFCL0MsTUFBTStDLEdBQ0dGLEVBQUV1QixlQUFlckIsR0FpQjFCOUMsV0FBVzhDLEdBQ0ZGLEVBQUVDLFFBQVFDLEdBaUJuQjdDLFFBQVE2QyxHQUNDRixFQUFFTyxPQUFPTCxHQWlCbEI1QyxVQUFVNEMsR0FDREYsRUFBRU8sT0FBT0wsR0FpQmxCOEMsVUFBVTlDLEdBQ0RGLEVBQUVDLFFBQVFDLEdBaUJuQitDLFNBQVMvQyxHQUNBRixFQUFFQyxRQUFRQyxHQWtCbkJnRCxRQUFRaEQsR0FDQ0YsRUFBRXVCLGVBQWVyQixHQWlCMUJpRCxZQUFZakQsR0FDSEYsRUFBRU8sT0FBT0wsR0FpQmxCdkMsV0FBV3VDLEdBQ0ZGLEVBQUVtQixZQUFZakIsR0FpQnZCdEMsV0FBV3NDLEdBQ0ZGLEVBQUVtQixZQUFZakIsR0FpQnZCckMsVUFBVXFDLEdBQ0RGLEVBQUVtQixZQUFZakIsR0FrQnZCcEMsZUFBZW9DLEdBQ05GLEVBQUV1QixlQUFlckIsR0FrQjFCbkMsY0FBY21DLEdBQ0xGLEVBQUV1QixlQUFlckIsR0FrQjFCbEMsZUFBZWtDLEdBQ05GLEVBQUV1QixlQUFlckIsR0FrQjFCakMsWUFBWWlDLEdBQ0hGLEVBQUV1QixlQUFlckIsR0FrQjFCaEMsb0JBQW9CZ0MsR0FDWEYsRUFBRXVCLGVBQWVyQixHQWtCMUIvQixlQUFlK0IsR0FDTkYsRUFBRXVCLGVBQWVyQixHQWlCMUJrRCxpQkFBaUJsRCxHQUNSRixFQUFFQyxRQUFRQyxHQWtCbkJtRCxrQkFBa0JuRCxHQUNURixFQUFFdUIsZUFBZXJCLEdBd0IxQm9ELFNBQVNwRCxHQUNBQSxFQUNITCxNQUFFdUIsU0FBU21DLE1BQU12QixJQUFJLEdBQUdDLElBQUksR0FDNUJwQyxJQUFDQSxFQUNFTSxNQUFNLENBQ0xOLElBQUNBLEVBQ0VVLFNBQ0F2TCxPQUNBd0wsUUFDRXJLLElBQ0dtTCxNQUFNckwsT0FBT0UsTUFDSCxJQUFWQSxJQUNDQSxFQUFNWSxXQUFXLE1BQ2xCZCxPQUFPdU4sVUFBVXZOLE9BQU9FLEtBQ3hCRixPQUFPRSxJQUFVLEdBQ2pCRixPQUFPRSxJQUFVLEdBQ25CLENBQUMsWUFBYSxPQUFRLElBQUk1QyxTQUFTNEMsSUFDckMsQ0FDRXNLLE9BQVEsQ0FDTkMsYUFBYyw4Q0FJbkJMLFdBQVdsSyxHQUNULENBQUMsWUFBYSxPQUFRLElBQUk1QyxTQUFTNEMsR0FFaEMsS0FEQUYsT0FBT0UsS0FHZjBKLE1BQUV1QixTQUFTbUMsTUFBTXZCLElBQUksR0FBR0MsSUFBSSxLQUU3QjNCLFdBa0JUbUQsUUFBUXZELEdBQ0NGLEVBQ0pPLE9BQU9MLEdBQ1BNLFFBQ0VySyxHQUNXLE9BQVZBLEdBQW1CQSxFQUFNWixRQUFVLEdBQUtZLEVBQU1VLFNBQVMsU0FDekQsQ0FDRTRKLE9BQVEsQ0FDTkMsYUFBYyxzREFvQnhCZ0QsUUFBUXhELEdBQ0NGLEVBQUVPLE9BQU9MLEdBaUJsQnlELGFBQWF6RCxHQUNKRixFQUFFQyxRQUFRQyxHQWlCbkIwRCxVQUFVMUQsR0FDREYsRUFBRUMsUUFBUUMsR0FpQm5CMkQsU0FBUzNELEdBQ0FGLEVBQUVDLFFBQVFDLEdBaUJuQjRELFFBQVE1RCxHQUNDRixFQUFFakosV0FBVyxDQUFDLEtBQU1tSixHQWlCN0IzQixRQUFRMkIsR0FDQ0YsRUFBRUksS0FBSyxDQUFDLGNBQWUsYUFBYyxRQUFTRixHQWlCdkQxQixxQkFBcUIwQixHQUNaRixFQUFFQyxRQUFRQyxHQWlCbkJ6QixPQUFPeUIsR0FDRUYsRUFBRUMsUUFBUUMsR0FpQm5CeEIsY0FBY3dCLEdBQ0xGLEVBQUVDLFFBQVFDLEdBaUJuQnZCLGlCQUFpQnVCLEdBQ1JGLEVBQUVDLFFBQVFDLEdBaUJuQjZELFlBQVk3RCxHQUNIRixFQUFFQyxRQUFRQyxHQWlCbkJyQixTQUFTcUIsR0FDQUYsRUFBRUMsUUFBUUMsR0FpQm5CcEIsU0FBU29CLEdBQ0FGLEVBQUVDLFFBQVFDLEdBaUJuQm5CLGdCQUFnQm1CLEdBQ1BGLEVBQUVDLFFBQVFDLEdBaUJuQmxCLE9BQU9rQixHQUNFRixFQUFFQyxRQUFRQyxHQWtCbkJqQixPQUFPaUIsR0FDRUYsRUFBRXVCLGVBQWVyQixHQWtCMUJoQixjQUFjZ0IsR0FDTEYsRUFBRXVCLGVBQWVyQixHQWtCMUI4RCxVQUFTLElBRUxuRSxJQUFDQSxFQUNFVSxTQUVBMEQsS0FBSyxDQUFFekwsUUFBUyx5Q0FDaEI4SCxZQU1INEQsZ0JBQW1CaEUsR0FDdkJMLElBQUNBLEVBQ0UrQixPQUFPLENBQ05sSyxLQUFNNkgsT0FBTzdILEtBQUt3SSxLQUVuQnFDLFVBR0M0QixpQkFBb0JqRSxHQUN4QkwsSUFBQ0EsRUFDRStCLE9BQU8sQ0FDTnpILFFBQVNvRixPQUFPcEYsUUFBUStGLEdBQ3hCOUYsT0FBUW1GLE9BQU9uRixPQUFPOEYsR0FDdEI3RixXQUFZa0YsT0FBT2xGLFdBQVc2RixHQUM5QjVGLFVBQVdpRixPQUFPakYsVUFBVTRGLEdBQzVCM0YsWUFBYWdGLE9BQU9oRixZQUFZMkYsR0FDaEN6RixjQUFlOEUsT0FBTzlFLGNBQWN5RixHQUNwQ3hGLGlCQUFrQjZFLE9BQU83RSxpQkFBaUJ3RixHQUMxQ3ZGLGNBQWU0RSxPQUFPNUUsY0FBY3VGLEtBRXJDcUMsVUFHQzZCLGFBQWdCbEUsR0FDcEJMLElBQUNBLEVBQ0UrQixPQUFPLENBQ04vRyxPQUFRMEUsT0FBTzFFLE9BQU9xRixHQUN0QnBGLE1BQU95RSxPQUFPekUsUUFDZEMsUUFBU3dFLE9BQU94RSxVQUNoQkMsSUFBS3VFLE9BQU92RSxNQUNadEgsUUFBUzZMLE9BQU83TCxRQUFRd00sR0FDeEJ6TSxLQUFNOEwsT0FBTzlMLEtBQUt5TSxHQUNsQi9NLE9BQVFvTSxPQUFPcE0sT0FBTytNLEdBQ3RCOUUsSUFBS21FLE9BQU9uRSxJQUFJOEUsR0FDaEI3RSxXQUFZa0UsT0FBT2xFLFdBQVc2RSxHQUM5QnpFLGNBQWU4RCxPQUFPOUQsY0FBY3lFLEdBQ3BDeEUsYUFBYzZELE9BQU83RCxhQUFhd0UsR0FDbEN2RSxhQUFjNEQsT0FBTzVELGFBQWF1RSxHQUNsQzVFLE9BQVFpRSxPQUFPakUsT0FBTzRFLEdBQ3RCM0UsTUFBT2dFLE9BQU9oRSxNQUFNMkUsR0FDcEIxRSxNQUFPK0QsT0FBTy9ELE1BQU0wRSxHQUNwQnBFLGNBQWV5RCxPQUFPekQsZ0JBQ3RCQyxhQUFjd0QsT0FBT3hELGVBQ3JCZCxNQUFPc0UsT0FBT3RFLE9BQU0sR0FDcEJlLHFCQUFzQnVELE9BQU92RCxxQkFBcUJrRSxLQUVuRHFDLFVBR0M4QixrQkFBcUJuRSxHQUN6QkwsSUFBQ0EsRUFDRStCLE9BQU8sQ0FDTjFGLG1CQUFvQnFELE9BQU9yRCxtQkFBbUJnRSxHQUM5Q3ZKLG1CQUFvQjRJLE9BQU81SSxtQkFBbUJ1SixHQUM5Q3hKLFdBQVk2SSxPQUFPN0ksWUFBVyxHQUM5QnlGLFNBQVVvRCxPQUFPcEQsVUFBUyxHQUMxQkMsVUFBV21ELE9BQU9uRCxVQUFVOEQsR0FDNUI3RCxXQUFZa0QsT0FBT2xELFlBQVcsR0FDOUJFLGFBQWNnRCxPQUFPaEQsY0FBYSxLQUVuQ2dHLFVBR0MrQixZQUFlcEUsR0FDbkJMLElBQUNBLEVBQ0UrQixPQUFPLENBQ05sRixLQUFNNkMsT0FBT3FELFdBQVUsR0FDdkJqRyxLQUFNNEMsT0FBT3NELFVBQVUzQyxHQUN2Qm5ELFFBQVN3QyxPQUFPdUQsYUFBYTVDLEtBRTlCcUMsVUFHQ2dDLG1CQUFzQnJFLEdBQzFCTCxJQUFDQSxFQUNFK0IsT0FBTyxDQUNObkYsT0FBUThDLE9BQU93RCxtQkFBbUI3QyxHQUNsQ2pELFlBQWFzQyxPQUFPdEMsWUFBWWlELEdBQ2hDaEQsT0FBUXFDLE9BQU9yQyxPQUFPZ0QsR0FDdEIvQyxNQUFPb0MsT0FBT3BDLE1BQU0rQyxHQUNwQjlDLFdBQVltQyxPQUFPbkMsV0FBVzhDLEdBQzlCN0MsUUFBU2tDLE9BQU9sQyxTQUFRLEdBQ3hCQyxVQUFXaUMsT0FBT2pDLFdBQVUsS0FFN0JpRixVQUdDaUMsVUFBYXRFLEdBQ2pCTCxJQUFDQSxFQUNFK0IsT0FBTyxDQUNObkYsT0FBUThDLE9BQU95RCxVQUFVOUMsR0FDekIxQyxNQUFPK0IsT0FBTzBELFNBQVMvQyxHQUN2QnZELEtBQU00QyxPQUFPMkQsUUFBUWhELEdBQ3JCekMsU0FBVThCLE9BQU80RCxhQUFZLEtBRTlCWixVQUdDa0MsYUFBZ0J2RSxHQUNwQkwsSUFBQUEsRUFBRStCLE9BQU8sQ0FDUG5GLE9BQVE4QyxPQUFPbUQsYUFBYXhDLEdBQWF3RSxXQUN6Q2hJLEtBQU02QyxPQUFPN0MsS0FBS3dELEdBQWF3RSxXQUMvQi9ILEtBQU00QyxPQUFPNUMsS0FBS3VELEdBQWF3RSxXQUMvQjdILGFBQWMwQyxPQUFPb0QsbUJBQW1CekMsR0FBYXdFLFdBQ3JENUgsTUFBT3dILFlBQVlwRSxHQUFhd0UsV0FDaEMxSCxhQUFjdUgsbUJBQW1CckUsR0FBYXdFLFdBQzlDbkgsSUFBS2lILFVBQVV0RSxHQUFhd0UsYUFJMUJDLFdBQWN6RSxHQUNsQkwsSUFBQ0EsRUFDRStCLE9BQU8sQ0FDTmpFLFdBQVk0QixPQUFPNUIsV0FBV3VDLEdBQzlCdEMsV0FBWTJCLE9BQU8zQixXQUFXc0MsR0FDOUJyQyxVQUFXMEIsT0FBTzFCLFVBQVVxQyxHQUM1QnBDLGVBQWdCeUIsT0FBT3pCLGVBQWVvQyxHQUN0Q25DLGNBQWV3QixPQUFPeEIsY0FBY21DLEdBQ3BDbEMsZUFBZ0J1QixPQUFPdkIsZUFBZWtDLEdBQ3RDakMsWUFBYXNCLE9BQU90QixZQUFZaUMsR0FDaENoQyxvQkFBcUJxQixPQUFPckIsb0JBQW9CZ0MsR0FDaEQvQixlQUFnQm9CLE9BQU9wQixlQUFlK0IsR0FDdENyRCxhQUFjMEMsT0FBTzZELGlCQUFpQmxELEtBRXZDcUMsVUFHQ3FDLGNBQWlCMUUsR0FDckJMLElBQUNBLEVBQ0UrQixPQUFPLENBQ04vSixNQUFPMEgsT0FBTytELFNBQVNwRCxHQUN2Qi9HLEtBQU1vRyxPQUFPa0UsUUFBUXZELEdBQ3JCaEgsS0FBTXFHLE9BQU9tRSxRQUFReEQsR0FDckJoSixVQUFXcUksT0FBT29FLGFBQWF6RCxHQUMvQi9JLE9BQVFvSSxPQUFPcUUsVUFBVTFELEtBRTFCcUMsVUFHQ3NDLFNBQVkzRSxHQUNoQkwsSUFBQ0EsRUFDRStCLE9BQU8sQ0FDTm5GLE9BQVE4QyxPQUFPc0UsU0FBUzNELEdBQ3hCN0IsTUFBT2tCLE9BQU91RSxRQUFRNUQsS0FFdkJxQyxVQUdDdUMsWUFBZTVFLEdBQ25CTCxJQUFDQSxFQUNFK0IsT0FBTyxDQUNOckQsUUFBU2dCLE9BQU9oQixRQUFRMkIsR0FDeEIxQixxQkFBc0JlLE9BQU9mLHFCQUFxQjBCLEdBQ2xEekIsT0FBUWMsT0FBT2QsT0FBT3lCLEdBQ3RCeEIsY0FBZWEsT0FBT2IsY0FBY3dCLEdBQ3BDdkIsaUJBQWtCWSxPQUFPWixpQkFBaUJ1QixLQUUzQ3FDLFVBR0N3QyxZQUFlN0UsR0FDbkJMLElBQUNBLEVBQ0UrQixPQUFPLENBQ05uRixPQUFROEMsT0FBT3dFLFlBQVk3RCxHQUMzQnJCLFNBQVVVLE9BQU9WLFNBQVNxQixHQUMxQnBCLFNBQVVTLE9BQU9ULFNBQVNvQixHQUMxQm5CLGdCQUFpQlEsT0FBT1IsZ0JBQWdCbUIsR0FDeENsQixPQUFRTyxPQUFPUCxPQUFPa0IsR0FDdEJqQixPQUFRTSxPQUFPTixPQUFPaUIsR0FDdEJoQixjQUFlSyxPQUFPTCxjQUFjZ0IsS0FFckNxQyxVQWFReUMsbUJBQXFCbkYsSUFBQ0EsRUFBQytCLE9BQU8sQ0FDekNqSSxVQUFXdUssaUJBQWdCLEdBQzNCaEssV0FBWWlLLGtCQUFpQixHQUM3QnZKLE9BQVF3SixjQUFhLEdBQ3JCbkksWUFBYW9JLG1CQUFrQixHQUMvQjdILE9BQVFpSSxjQUFhLEdBQ3JCL0csS0FBTWlILFlBQVcsR0FDakIxTixRQUFTMk4sZUFBYyxHQUN2QnhHLEdBQUl5RyxVQUFTLEdBQ2J2RyxNQUFPd0csYUFBWSxHQUNuQmxHLE1BQU9tRyxhQUFZLEtBS1JFLGtCQUFvQnBGLElBQUNBLEVBQUMrQixPQUFPLENBQ3hDakksVUFBV3VLLGlCQUFnQixHQUMzQmhLLFdBQVlpSyxrQkFBaUIsR0FDN0J2SixPQUFRd0osY0FBYSxHQUNyQm5JLFlBQWFvSSxtQkFBa0IsR0FDL0I3SCxPQUFRaUksY0FBYSxHQUNyQi9HLEtBQU1pSCxZQUFXLEdBQ2pCMU4sUUFBUzJOLGVBQWMsR0FDdkJ4RyxHQUFJeUcsVUFBUyxHQUNidkcsTUFBT3dHLGFBQVksR0FDbkJsRyxNQUFPbUcsYUFBWSxLQUtSRyxVQUFZckYsSUFBQ0EsRUFBQytCLE9BQU8sQ0FFaEN1RCxlQUFnQjVGLE9BQU83SCxNQUFLLEdBRzVCME4sbUJBQW9CN0YsT0FBT3BGLFNBQVEsR0FDbkNrTCxtQkFBb0I5RixPQUFPbkYsUUFBTyxHQUNsQ2tMLHVCQUF3Qi9GLE9BQU9sRixZQUFXLEdBQzFDa0wsc0JBQXVCaEcsT0FBT2pGLFdBQVUsR0FDeENrTCx1QkFBd0JqRyxPQUFPd0MsWUFBVyxHQUMxQzBELHdCQUF5QmxHLE9BQU9oRixhQUFZLEdBQzVDbUwsMEJBQTJCbkcsT0FBTzlFLGVBQWMsR0FDaERrTCw2QkFBOEJwRyxPQUFPN0Usa0JBQWlCLEdBQ3REa0wsMEJBQTJCckcsT0FBTzVFLGVBQWMsR0FHaERrTCxjQUFldEcsT0FBTzFFLFFBQU8sR0FDN0JpTCxhQUFjdkcsT0FBT3pFLFFBQ3JCaUwsZUFBZ0J4RyxPQUFPeEUsVUFDdkJpTCxXQUFZekcsT0FBT3ZFLE1BQ25CaUwsYUFBYzFHLE9BQU90RSxPQUFNLEdBQzNCaUwsZUFBZ0IzRyxPQUFPN0wsU0FBUSxHQUMvQnlTLFlBQWE1RyxPQUFPOUwsTUFBSyxHQUN6QjJTLGNBQWU3RyxPQUFPcE0sUUFBTyxHQUM3QmtULFdBQVk5RyxPQUFPbkUsS0FBSSxHQUN2QmtMLG1CQUFvQi9HLE9BQU9sRSxZQUFXLEdBQ3RDa0wsY0FBZWhILE9BQU9qRSxRQUFPLEdBQzdCa0wsYUFBY2pILE9BQU9oRSxPQUFNLEdBQzNCa0wsYUFBY2xILE9BQU8vRCxPQUFNLEdBQzNCa0wsc0JBQXVCbkgsT0FBTzlELGVBQWMsR0FDNUNrTCxxQkFBc0JwSCxPQUFPN0QsY0FBYSxHQUMxQ2tMLHFCQUFzQnJILE9BQU81RCxjQUFhLEdBQzFDa0wsc0JBQXVCdEgsT0FBT3pELGdCQUM5QmdMLHFCQUFzQnZILE9BQU94RCxlQUM3QmdMLDZCQUE4QnhILE9BQU92RCxzQkFBcUIsR0FHMURnTCxrQ0FBbUN6SCxPQUFPckQsb0JBQW1CLEdBQzdEK0ssa0NBQW1DMUgsT0FBTzVJLG9CQUFtQixHQUM3RHVRLHlCQUEwQjNILE9BQU83SSxZQUFXLEdBQzVDeVEsc0JBQXVCNUgsT0FBT3BELFVBQVMsR0FDdkNpTCx1QkFBd0I3SCxPQUFPbkQsV0FBVSxHQUN6Q2lMLHlCQUEwQjlILE9BQU9sRCxZQUFXLEdBQzVDaUwsMkJBQTRCL0gsT0FBT2hELGNBQWEsR0FHaERnTCxjQUFlaEksT0FBT21ELGNBQWEsR0FDbkM4RSxZQUFhakksT0FBTzdDLE1BQUssR0FDekIrSyxZQUFhbEksT0FBTzVDLE1BQUssR0FDekIrSyxvQkFBcUJuSSxPQUFPM0MsYUFBWSxHQUN4QytLLG9CQUFxQnBJLE9BQU9vRCxvQkFBbUIsR0FHL0NpRixrQkFBbUJySSxPQUFPcUQsV0FBVSxHQUNwQ2lGLGtCQUFtQnRJLE9BQU9zRCxXQUFVLEdBQ3BDaUYscUJBQXNCdkksT0FBT3VELGNBQWEsR0FHMUNpRiw0QkFBNkJ4SSxPQUFPd0Qsb0JBQW1CLEdBQ3ZEaUYsa0NBQW1DekksT0FBT3RDLGFBQVksR0FDdERnTCw0QkFBNkIxSSxPQUFPckMsUUFBTyxHQUMzQ2dMLDJCQUE0QjNJLE9BQU9wQyxPQUFNLEdBQ3pDZ0wsaUNBQWtDNUksT0FBT25DLFlBQVcsR0FDcERnTCw4QkFBK0I3SSxPQUFPbEMsU0FBUSxHQUM5Q2dMLGdDQUFpQzlJLE9BQU9qQyxXQUFVLEdBR2xEZ0wsa0JBQW1CL0ksT0FBT3lELFdBQVUsR0FDcEN1RixpQkFBa0JoSixPQUFPMEQsVUFBUyxHQUNsQ3VGLGdCQUFpQmpKLE9BQU8yRCxTQUFRLEdBQ2hDdUYscUJBQXNCbEosT0FBTzRELGFBQVksR0FHekN1RixpQkFBa0JuSixPQUFPNUIsWUFBVyxHQUNwQ2dMLGlCQUFrQnBKLE9BQU8zQixZQUFXLEdBQ3BDZ0wsZ0JBQWlCckosT0FBTzFCLFdBQVUsR0FDbENnTCxxQkFBc0J0SixPQUFPekIsZ0JBQWUsR0FDNUNnTCxvQkFBcUJ2SixPQUFPeEIsZUFBYyxHQUMxQ2dMLHFCQUFzQnhKLE9BQU92QixnQkFBZSxHQUM1Q2dMLGtCQUFtQnpKLE9BQU90QixhQUFZLEdBQ3RDZ0wsMkJBQTRCMUosT0FBT3JCLHFCQUFvQixHQUN2RGdMLHFCQUFzQjNKLE9BQU9wQixnQkFBZSxHQUM1Q2dMLGtCQUFtQjVKLE9BQU82RCxrQkFBaUIsR0FHM0NnRyxjQUFlN0osT0FBTytELFVBQVMsR0FDL0IrRixhQUFjOUosT0FBT2tFLFNBQVEsR0FDN0I2RixhQUFjL0osT0FBT21FLFNBQVEsR0FDN0I2RixtQkFBb0JoSyxPQUFPb0UsY0FBYSxHQUN4QzZGLGdCQUFpQmpLLE9BQU9xRSxXQUFVLEdBR2xDNkYsVUFBV2xLLE9BQU9zRSxVQUFTLEdBQzNCNkYsU0FBVW5LLE9BQU91RSxTQUFRLEdBR3pCNkYsZUFBZ0JwSyxPQUFPaEIsU0FBUSxHQUMvQnFMLDhCQUErQnJLLE9BQU9mLHNCQUFxQixHQUMzRHFMLGNBQWV0SyxPQUFPZCxRQUFPLEdBQzdCcUwsc0JBQXVCdkssT0FBT2IsZUFBYyxHQUM1Q3FMLHlCQUEwQnhLLE9BQU9aLGtCQUFpQixHQUdsRHFMLGFBQWN6SyxPQUFPd0UsYUFBWSxHQUNqQ2tHLGVBQWdCMUssT0FBT1YsVUFBUyxHQUNoQ3FMLGVBQWdCM0ssT0FBT1QsVUFBUyxHQUNoQ3FMLHdCQUF5QjVLLE9BQU9SLGlCQUFnQixHQUNoRHFMLGFBQWM3SyxPQUFPUCxRQUFPLEdBQzVCcUwsY0FBZTlLLE9BQU9OLFFBQU8sR0FDN0JxTCxxQkFBc0IvSyxPQUFPTCxlQUFjLEtBV2hDcUwsS0FBT3JGLFVBQVUzQyxVQUFVaUksTUFBTTFVLFFBQVEyVSxLQVcvQyxTQUFTQyxlQUFlQyxHQUM3QixPQUFPM0YsbUJBQW1CekMsVUFBVWlJLE1BQU1HLEVBQzVDLENBV08sU0FBU0MsY0FBY0QsR0FDNUIsT0FBTzFGLGtCQUFrQjFDLFVBQVVpSSxNQUFNRyxFQUMzQyxDQWVPLFNBQVNFLGVBQWVDLEVBQU1DLEVBQVE3SyxHQUMzQyxPQUFPWCxPQUFPdUwsR0FBTTVLLEdBQWFzSyxNQUFNTyxFQUN6QyxDQThCQSxTQUFTaEwsZ0JBQWdCaEgsRUFBT2lTLEdBRTlCLE1BQU1DLEVBQWVsUyxFQUFNekUsS0FBS0UsS0FBSyxLQUcvQjBXLEVBQWUseUJBQXlCRCxJQUc5QyxHQUFJbFMsRUFBTW9TLE9BQVN0TCxNQUFFdUwsYUFBYUMsYUFFaEMsT0FBSXRTLEVBQU11UyxXQUFhekwsTUFBRTBMLGNBQWNyVCxVQUM5QixDQUNMTSxRQUFTLEdBQUcwUyw4QkFLVCxDQUNMMVMsUUFBUyxHQUFHMFMscUJBQWdDRixFQUFRUSxpQkFLeEQsR0FBSXpTLEVBQU1vUyxPQUFTdEwsTUFBRXVMLGFBQWFLLFFBRTVCMVMsRUFBTTBILFFBQVFDLGFBQ2hCLE1BQU8sQ0FDTGxJLFFBQVMsR0FBRzBTLE9BQWtCblMsRUFBTTBILFFBQVFDLDJCQUEyQnNLLEVBQVFVLFVBTXJGLEdBQUkzUyxFQUFNb1MsT0FBU3RMLE1BQUV1TCxhQUFhTyxjQUFlLENBRS9DLElBQUluVCxFQUFVLG9DQUFvQ3lTLE9BWWxELE9BVEFsUyxFQUFNNlMsWUFBWW5NLFNBQVN0SixJQUN6QixNQUFNMFYsRUFBUTFWLEVBQU0wQyxPQUFPLEdBQUdMLFFBQVFtSixRQUFRLEtBQzlDbkosSUFDYSxJQUFYcVQsRUFDSSxHQUFHMVYsRUFBTTBDLE9BQU8sR0FBR0wsWUFBWW1ILFVBQVVrTSxHQUN6QyxHQUFHMVYsRUFBTTBDLE9BQU8sR0FBR0wsV0FBVyxJQUkvQixDQUNMQSxVQUVILENBR0QsTUFBTyxDQUNMQSxRQUFTLEdBQUcwUyxPQUFrQkYsRUFBUVEsZ0JBRTFDLENDN3RGQSxNQUFNMVAsY0FBZ0JnUSxtQkFBbUJwUyxlQWVsQyxTQUFTcVMsV0FBV0MsR0FBZSxHQUN4QyxPQUFPQSxFQUFlbFEsY0FBZ0J0SixTQUFTc0osY0FDakQsQ0E4Qk8sU0FBU21RLFdBQ2RDLEVBQWdCLENBQUUsRUFDbEJDLEVBQVUsR0FDVkMsR0FBZSxHQUdmLElBQUl6QixFQUFnQixDQUFBLEVBR2hCMEIsRUFBYSxDQUFBLEVBR2pCLEdBQUlGLEVBQVE1VyxPQUNWLElBRUVvVixFQUFnQkQsZUFBZTRCLGdCQUFnQkgsR0FDaEQsQ0FBQyxNQUFPOVQsR0FDUE8sYUFDRSxFQUNBUCxFQUFNUSxPQUNOLGdEQUVILENBSUgsR0FBSXFULEdBQXVELElBQXRDcFosT0FBT3dDLEtBQUs0VyxHQUFlM1csT0FDOUMsSUFFRTJXLEVBQWdCeEIsZUFBZXdCLEVBQ2hDLENBQUMsTUFBTzdULEdBQ1BPLGFBQWEsRUFBR1AsRUFBTVEsT0FBUSwyQ0FDL0IsQ0FJSCxHQUFJc1QsRUFBUTVXLE9BQ1YsSUFFRThXLEVBQWF6QixjQUFjMkIsbUJBQW1CcE4sWUFBYWdOLEdBQzVELENBQUMsTUFBTzlULEdBQ1BPLGFBQWEsRUFBR1AsRUFBTVEsT0FBUSx3Q0FDL0IsQ0FJSCxNQUFNMlQsRUFBaUJULFdBQVdLLEdBWWxDLE9BVEFLLGVBQ0UvUyxjQUNBOFMsRUFDQTdCLEVBQ0F1QixFQUNBRyxHQUlLRyxDQUNULENBWU8sU0FBU0UsYUFBYUMsRUFBaUJDLEdBRTVDLEdBQUl6WCxTQUFTeVgsR0FDWCxJQUFLLE1BQU8vWixFQUFLc0QsS0FBVXJELE9BQU8rWixRQUFRRCxHQUN4Q0QsRUFBZ0I5WixHQUNkc0MsU0FBU2dCLEtBQ1JrSixjQUFjOUwsU0FBU1YsU0FDQ3FGLElBQXpCeVUsRUFBZ0I5WixHQUNaNlosYUFBYUMsRUFBZ0I5WixHQUFNc0QsUUFDekIrQixJQUFWL0IsRUFDRUEsRUFDQXdXLEVBQWdCOVosR0FLNUIsT0FBTzhaLENBQ1QsQ0FrQk8sU0FBU0csZ0JBQWdCQyxHQUU5QixNQUFNSCxFQUFhLENBQUEsRUFHbkIsR0FBbUQsb0JBQS9DOVosT0FBT0MsVUFBVThCLFNBQVM1QixLQUFLOFosR0FFakMsSUFBSyxNQUFPbGEsRUFBS3NELEtBQVVyRCxPQUFPK1osUUFBUUUsR0FBYSxDQUVyRCxNQUFNQyxFQUFrQjdOLFlBQVl0TSxHQUNoQ3NNLFlBQVl0TSxHQUFLZSxNQUFNLEtBQ3ZCLEdBSUpvWixFQUFnQkMsUUFDZCxDQUFDQyxFQUFLQyxFQUFNdEIsSUFDVHFCLEVBQUlDLEdBQ0hILEVBQWdCelgsT0FBUyxJQUFNc1csRUFBUTFWLEVBQVErVyxFQUFJQyxJQUFTLElBQ2hFUCxFQUVILENBSUgsT0FBT0EsQ0FDVCxDQW9CTyxTQUFTUSxnQkFDZDdOLE9BQ0ExSyxVQUFXLEVBQ1h3WSxnQkFBaUIsR0FFakIsSUFFRSxJQUFLbFksU0FBU29LLFNBQTZCLGlCQUFYQSxPQUU5QixPQUFPLEtBSVQsTUFBTStOLGFBQ2MsaUJBQVgvTixPQUNIOE4sZUFDRUUsS0FBSyxJQUFJaE8sV0FDVGlPLEtBQUtoRCxNQUFNakwsUUFDYkEsT0FHQWtPLG1CQUFxQkMsa0JBQ3pCSixhQUNBRCxnQkFDQSxHQUlJTSxjQUFnQk4sZUFDbEJHLEtBQUtoRCxNQUNIa0Qsa0JBQWtCSixhQUFjRCxnQkFBZ0IsSUFDaEQsQ0FBQ08sRUFBR3pYLFFBQ2UsaUJBQVZBLE9BQXNCQSxNQUFNWSxXQUFXLFlBQzFDd1csS0FBSyxJQUFJcFgsVUFDVEEsUUFFUnFYLEtBQUtoRCxNQUFNaUQsb0JBR2YsT0FBTzVZLFNBQVc0WSxtQkFBcUJFLGFBQ3hDLENBQUMsTUFBT3RWLEdBRVAsT0FBTyxJQUNSLENBQ0gsQ0FzRkEsU0FBU3lULG1CQUFtQnZNLEdBQzFCLE1BQU14RSxFQUFVLENBQUEsRUFHaEIsSUFBSyxNQUFPK1AsRUFBTTFWLEtBQVN0QyxPQUFPK1osUUFBUXROLEdBQ3hDeEUsRUFBUStQLEdBQVFoWSxPQUFPQyxVQUFVQyxlQUFlQyxLQUFLbUMsRUFBTSxTQUN2REEsRUFBS2UsTUFDTDJWLG1CQUFtQjFXLEdBSXpCLE9BQU8yRixDQUNULENBdUJBLFNBQVMwUixlQUFlbE4sRUFBUXhFLEVBQVM4UyxFQUFXQyxFQUFXQyxHQUM3RGpiLE9BQU93QyxLQUFLaUssR0FBUUUsU0FBUzVNLElBRTNCLE1BQU02TSxFQUFRSCxFQUFPMU0sR0FHZm1iLEVBQVlILEdBQWFBLEVBQVVoYixHQUNuQ29iLEVBQVlILEdBQWFBLEVBQVVqYixHQUNuQ3FiLEVBQVNILEdBQVVBLEVBQU9sYixHQUdoQyxRQUEyQixJQUFoQjZNLEVBQU12SixNQUNmc1csZUFBZS9NLEVBQU8zRSxFQUFRbEksR0FBTW1iLEVBQVdDLEVBQVdDLE9BQ3JELENBRURGLFVBQ0ZqVCxFQUFRbEksR0FBT21iLEdBSWpCLE1BQU1HLEVBQVM1RCxLQUFLN0ssRUFBTTdGLFNBQ3RCNkYsRUFBTTdGLFdBQVcwUSxNQUFqQjdLLE1BQXlCeU8sSUFDM0JwVCxFQUFRbEksR0FBT3NiLEdBSWJGLFVBQ0ZsVCxFQUFRbEksR0FBT29iLEdBSWJDLFVBQ0ZuVCxFQUFRbEksR0FBT3FiLEVBRWxCLElBRUwsQ0FzQk8sU0FBU1Isa0JBQWtCM1MsRUFBU3NTLEVBQWdCZSxHQWlDekQsT0FBT1osS0FBS2EsVUFBVXRULEdBaENHLENBQUM2UyxFQUFHelgsS0FPM0IsR0FMcUIsaUJBQVZBLElBQ1RBLEVBQVFBLEVBQU1uQixRQUtHLG1CQUFWbUIsR0FDVyxpQkFBVkEsR0FDTkEsRUFBTVksV0FBVyxhQUNqQlosRUFBTVUsU0FBUyxLQUNqQixDQUVBLEdBQUl3VyxFQUVGLE9BQU9lLEVBRUgsWUFBWWpZLEVBQVEsSUFBSW1ZLFdBQVcsT0FBUSxlQUUzQyxXQUFXblksRUFBUSxJQUFJbVksV0FBVyxPQUFRLGNBRzlDLE1BQU0sSUFBSUMsS0FFYixDQUdELE9BQU9wWSxDQUFLLElBSW1DbVksV0FDL0NGLEVBQXFCLHlCQUEyQixxQkFDaEQsR0FFSixDQWVBLFNBQVM5QixnQkFBZ0JILEdBRXZCLE1BQU1xQyxFQUFjckMsRUFBUXNDLFdBQ3pCQyxHQUFrQyxlQUExQkEsRUFBSXBiLFFBQVEsS0FBTSxNQUl2QnFiLEVBQWlCSCxHQUFlLEdBQUtyQyxFQUFRcUMsRUFBYyxHQUdqRSxHQUFJRyxFQUNGLElBRUUsT0FBT25CLEtBQUtoRCxNQUFNMVQsR0FBQUEsYUFBYW5ELGdCQUFnQmdiLElBQ2hELENBQUMsTUFBT3RXLEdBQ1BELGFBQ0UsRUFDQUMsRUFDQSxzREFBc0RzVyxVQUV6RCxDQUlILE1BQU8sRUFDVCxDQWtCQSxTQUFTcEMsbUJBQW1CcE4sRUFBYWdOLEdBRXZDLE1BQU1FLEVBQWEsQ0FBQSxFQUduQixJQUFLLElBQUl1QyxFQUFJLEVBQUdBLEVBQUl6QyxFQUFRNVcsT0FBUXFaLElBQUssQ0FDdkMsTUFBTTdELEVBQVNvQixFQUFReUMsR0FBR3RiLFFBQVEsS0FBTSxJQUdsQzBaLEVBQWtCN04sRUFBWTRMLEdBQ2hDNUwsRUFBWTRMLEdBQVFuWCxNQUFNLEtBQzFCLEdBR0pvWixFQUFnQkMsUUFBTyxDQUFDQyxFQUFLQyxFQUFNdEIsS0FDakMsR0FBSW1CLEVBQWdCelgsT0FBUyxJQUFNc1csRUFBTyxDQUN4QyxNQUFNMVYsRUFBUWdXLElBQVV5QyxHQUNuQnpZLEdBQ0hzQixJQUNFLEVBQ0EseUNBQXlDc1QseUNBRzdDbUMsRUFBSUMsR0FBUWhYLEdBQVMsSUFDdEIsV0FBd0IrQixJQUFkZ1YsRUFBSUMsS0FDYkQsRUFBSUMsR0FBUSxJQUVkLE9BQU9ELEVBQUlDLEVBQUssR0FDZmQsRUFDSixDQUdELE9BQU9BLENBQ1QsQ0NoaUJPd0MsZUFBZUMsTUFBTUMsRUFBS0MsRUFBaUIsSUFDaEQsT0FBTyxJQUFJQyxTQUFRLENBQUNDLEVBQVNDLEtBQzNCQyxtQkFBbUJMLEdBQ2hCTSxJQUFJTixFQUFLQyxHQUFpQk0sSUFDekIsSUFBSUMsRUFBZSxHQUduQkQsRUFBU0UsR0FBRyxRQUFTQyxJQUNuQkYsR0FBZ0JFLENBQUssSUFJdkJILEVBQVNFLEdBQUcsT0FBTyxLQUNaRCxHQUNISixFQUFPLHFDQUVURyxFQUFTSSxLQUFPSCxFQUNoQkwsRUFBUUksRUFBUyxHQUNqQixJQUVIRSxHQUFHLFNBQVVuWCxJQUNaOFcsRUFBTzlXLEVBQU0sR0FDYixHQUVSLENBd0VBLFNBQVMrVyxtQkFBbUJMLEdBQzFCLE9BQU9BLEVBQUloWSxXQUFXLFNBQVc0WSxNQUFRQyxJQUMzQyxDQ3BIQSxNQUFNQyxvQkFBb0J0QixNQVF4QixXQUFBdUIsQ0FBWXRYLEVBQVN1WCxHQUNuQkMsUUFFQTlOLEtBQUsxSixRQUFVQSxFQUNmMEosS0FBS3pKLGFBQWVELEVBRWhCdVgsSUFDRjdOLEtBQUs2TixXQUFhQSxFQUVyQixDQVVELFFBQUFFLENBQVM1WCxHQWdCUCxPQWZBNkosS0FBSzdKLE1BQVFBLEVBRVRBLEVBQU15UyxPQUNSNUksS0FBSzRJLEtBQU96UyxFQUFNeVMsTUFHaEJ6UyxFQUFNMFgsYUFDUjdOLEtBQUs2TixXQUFhMVgsRUFBTTBYLFlBR3RCMVgsRUFBTUssUUFDUndKLEtBQUt6SixhQUFlSixFQUFNRyxRQUMxQjBKLEtBQUt4SixNQUFRTCxFQUFNSyxPQUdkd0osSUFDUixFQzNCSCxNQUFNZ08sTUFBUSxDQUNaOVYsT0FBUSw4QkFDUitWLGVBQWdCLENBQUUsRUFDbEJDLFFBQVMsR0FDVEMsVUFBVyxJQWNOeEIsZUFBZXlCLG9CQUNwQkMsRUFDQUMsR0FFQSxJQUFJQyxFQUdKLE1BQU1uVyxFQUFZb1csZUFHWkMsRUFBZW5jLEtBQUFBLEtBQUs4RixFQUFXLGlCQUMvQnNXLEVBQWFwYyxLQUFBQSxLQUFLOEYsRUFBVyxjQU9uQyxJQUpDZixHQUFVQSxXQUFDZSxJQUFjZCxHQUFTQSxVQUFDYyxFQUFXLENBQUV1VyxXQUFXLEtBSXZEdFgsR0FBQUEsV0FBV29YLElBQWlCSixFQUFrQmxXLFdBQ2pENUMsSUFBSSxFQUFHLHlEQUNQZ1osUUFBdUJLLGFBQ3JCUCxFQUNBQyxFQUNBSSxPQUVHLENBQ0wsSUFBSUcsR0FBZ0IsRUFHcEIsTUFBTUMsRUFBV3hELEtBQUtoRCxNQUFNMVQsR0FBQUEsYUFBYTZaLElBSXpDLEdBQUlLLEVBQVNDLFNBQVd0ZSxNQUFNQyxRQUFRb2UsRUFBU0MsU0FBVSxDQUN2RCxNQUFNQyxFQUFZLENBQUEsRUFDbEJGLEVBQVNDLFFBQVF4UixTQUFTMFIsR0FBT0QsRUFBVUMsR0FBSyxJQUNoREgsRUFBU0MsUUFBVUMsQ0FDcEIsQ0FHRCxNQUFNM1csWUFBRUEsRUFBV0UsY0FBRUEsRUFBYUMsaUJBQUVBLEdBQXFCNlYsRUFDbkRhLEVBQ0o3VyxFQUFZaEYsT0FBU2tGLEVBQWNsRixPQUFTbUYsRUFBaUJuRixPQUszRHliLEVBQVM3VyxVQUFZb1csRUFBa0JwVyxTQUN6QzFDLElBQ0UsRUFDQSx5RUFFRnNaLEdBQWdCLEdBQ1BqZSxPQUFPd0MsS0FBSzBiLEVBQVNDLFNBQVcsSUFBSTFiLFNBQVc2YixHQUN4RDNaLElBQ0UsRUFDQSwrRUFFRnNaLEdBQWdCLEdBR2hCQSxHQUFpQnRXLEdBQWlCLElBQUloRixNQUFNNGIsSUFDMUMsSUFBS0wsRUFBU0MsUUFBUUksR0FLcEIsT0FKQTVaLElBQ0UsRUFDQSxlQUFlNFosaURBRVYsQ0FDUixJQUtETixFQUNGTixRQUF1QkssYUFDckJQLEVBQ0FDLEVBQ0FJLElBR0ZuWixJQUFJLEVBQUcsdURBR1B5WSxNQUFNRSxRQUFVdFosR0FBQUEsYUFBYThaLEVBQVksUUFHekNILEVBQWlCTyxFQUFTQyxRQUcxQmYsTUFBTUcsVUFBWWlCLGVBQWVwQixNQUFNRSxTQUUxQyxPQUlLbUIsc0JBQXNCaEIsRUFBbUJFLEVBQ2pELENBU08sU0FBU2UsdUJBQ2QsT0FBT3RCLE1BQU1HLFNBQ2YsQ0FXT3hCLGVBQWU0Qyx3QkFBd0JDLEdBRTVDLE1BQU0zVyxFQUFVZ1IsYUFHaEJoUixFQUFRYixXQUFXQyxRQUFVdVgsUUFHdkJwQixvQkFBb0J2VixFQUFRYixXQUFZYSxFQUFReUIsT0FBT00sTUFDL0QsQ0FXTyxTQUFTd1UsZUFBZUssR0FDN0IsT0FBT0EsRUFDSmhTLFVBQVUsRUFBR2dTLEVBQWFoUSxRQUFRLE9BQ2xDck8sUUFBUSxLQUFNLElBQ2RBLFFBQVEsS0FBTSxJQUNkQSxRQUFRLE1BQU8sSUFDZjBCLE1BQ0wsQ0FZTyxTQUFTNGMsa0JBQWtCQyxHQUNoQyxPQUFPQSxFQUFXdmUsUUFDaEIscUVBQ0EsR0FFSixDQW9CTyxTQUFTb2QsZUFDZCxPQUFPL2MsZ0JBQWdCb1ksYUFBYTdSLFdBQVdJLFVBQ2pELENBdUJBdVUsZUFBZWlELHVCQUNiQyxFQUNBL0MsRUFDQXlCLEVBQ0F1QixHQUFtQixHQUdmRCxFQUFPbGIsU0FBUyxTQUNsQmtiLEVBQVNBLEVBQU9wUyxVQUFVLEVBQUdvUyxFQUFPeGMsT0FBUyxJQUUvQ2tDLElBQUksRUFBRyw2QkFBNkJzYSxRQUdwQyxNQUFNekMsUUFBaUJSLE1BQU0sR0FBR2lELE9BQWEvQyxHQUc3QyxHQUE0QixNQUF4Qk0sRUFBU1MsWUFBOEMsaUJBQWpCVCxFQUFTSSxLQUFrQixDQUNuRSxHQUFJZSxFQUFnQixDQUVsQkEsRUFEbUJtQixrQkFBa0JHLElBQ1IsQ0FDOUIsQ0FDRCxPQUFPekMsRUFBU0ksSUFDakIsQ0FHRCxHQUFJc0MsRUFDRixNQUFNLElBQUluQyxZQUNSLCtCQUErQmtDLDJFQUFnRnpDLEVBQVNTLGVBQ3hILEtBQ0FFLFNBQVNYLEdBRVg3WCxJQUNFLEVBQ0EsK0JBQStCc2EsNkRBR3JDLENBZ0JBbEQsZUFBZTBDLHNCQUFzQmhCLEVBQW1CRSxFQUFpQixJQUN2RSxNQUFNd0IsRUFBYyxDQUNsQjlYLFFBQVNvVyxFQUFrQnBXLFFBQzNCOFcsUUFBU1IsR0FJWFAsTUFBTUMsZUFBaUI4QixFQUV2QnhhLElBQUksRUFBRyxtQ0FDUCxJQUNFeWEsR0FBYUEsY0FDWDFkLFVBQUtrYyxlQUFnQixpQkFDckJsRCxLQUFLYSxVQUFVNEQsR0FDZixPQUVILENBQUMsTUFBTzVaLEdBQ1AsTUFBTSxJQUFJd1gsWUFDUiw0Q0FDQSxLQUNBSSxTQUFTNVgsRUFDWixDQUNILENBdUJBd1csZUFBZXNELGNBQ2I1WCxFQUNBRSxFQUNBRSxFQUNBNlYsRUFDQUMsR0FHQSxJQUFJMkIsRUFDSixNQUFNeFAsRUFBWTROLEVBQW1COVQsS0FDL0JtRyxFQUFZMk4sRUFBbUI3VCxLQUdyQyxHQUFJaUcsR0FBYUMsRUFDZixJQUNFdVAsRUFBYSxJQUFJQyxnQkFBQUEsZ0JBQWdCLENBQy9CM1YsS0FBTWtHLEVBQ05qRyxLQUFNa0csR0FFVCxDQUFDLE1BQU94SyxHQUNQLE1BQU0sSUFBSXdYLFlBQ1IsMENBQ0EsS0FDQUksU0FBUzVYLEVBQ1osQ0FJSCxNQUFNMlcsRUFBaUJvRCxFQUNuQixDQUNFRSxNQUFPRixFQUNQclYsUUFBU3lULEVBQW1CelQsU0FFOUIsR0FFRXdWLEVBQW1CLElBQ3BCaFksRUFBWXpCLEtBQUtpWixHQUNsQkQsdUJBQXVCLEdBQUdDLElBQVUvQyxFQUFnQnlCLEdBQWdCLFFBRW5FaFcsRUFBYzNCLEtBQUtpWixHQUNwQkQsdUJBQXVCLEdBQUdDLElBQVUvQyxFQUFnQnlCLFFBRW5EOVYsRUFBYzdCLEtBQUtpWixHQUNwQkQsdUJBQXVCLEdBQUdDLElBQVUvQyxNQUt4QyxhQUQ2QkMsUUFBUXVELElBQUlELElBQ25CL2QsS0FBSyxNQUM3QixDQW1CQXFhLGVBQWVpQyxhQUFhUCxFQUFtQkMsRUFBb0JJLEdBRWpFLE1BQU1QLEVBQzBCLFdBQTlCRSxFQUFrQnBXLFFBQ2QsS0FDQSxHQUFHb1csRUFBa0JwVyxVQUdyQkMsRUFBU21XLEVBQWtCblcsUUFBVThWLE1BQU05VixPQUVqRCxJQUNFLE1BQU1xVyxFQUFpQixDQUFBLEVBdUN2QixPQXJDQWhaLElBQ0UsRUFDQSxpREFBaUQ0WSxHQUFhLGFBR2hFSCxNQUFNRSxjQUFnQitCLGNBQ3BCLElBQ0s1QixFQUFrQmhXLFlBQVl6QixLQUFLMlosR0FDcENwQyxFQUFZLEdBQUdqVyxLQUFVaVcsS0FBYW9DLElBQU0sR0FBR3JZLEtBQVVxWSxPQUc3RCxJQUNLbEMsRUFBa0I5VixjQUFjM0IsS0FBS3FZLEdBQ2hDLFFBQU5BLEVBQ0lkLEVBQ0UsR0FBR2pXLFVBQWVpVyxhQUFxQmMsSUFDdkMsR0FBRy9XLGtCQUF1QitXLElBQzVCZCxFQUNFLEdBQUdqVyxLQUFVaVcsYUFBcUJjLElBQ2xDLEdBQUcvVyxhQUFrQitXLFNBRTFCWixFQUFrQjdWLGlCQUFpQjVCLEtBQUs4VixHQUN6Q3lCLEVBQ0ksR0FBR2pXLFdBQWdCaVcsZ0JBQXdCekIsSUFDM0MsR0FBR3hVLHNCQUEyQndVLE9BR3RDMkIsRUFBa0I1VixjQUNsQjZWLEVBQ0FDLEdBSUZQLE1BQU1HLFVBQVlpQixlQUFlcEIsTUFBTUUsU0FHdkM4QixHQUFBQSxjQUFjdEIsRUFBWVYsTUFBTUUsU0FDekJLLENBQ1IsQ0FBQyxNQUFPcFksR0FDUCxNQUFNLElBQUl3WCxZQUNSLHVEQUNBLEtBQ0FJLFNBQVM1WCxFQUNaLENBQ0gsQ0N0Y08sU0FBU3FhLGtCQUNkQyxXQUFXQyxXQUFhLFdBQ3RCLE1BQU8sQ0FBRUMsU0FBVSxFQUN2QixDQUNBLENBV09oRSxlQUFlaUUsWUFBWS9YLEdBRWhDLE1BQU1nUixXQUFFQSxFQUFVZ0gsTUFBRUEsRUFBSzlHLFdBQUVBLEVBQVUrRyxLQUFFQSxHQUFTTCxXQUloREEsV0FBV00sY0FBZ0JGLEdBQU0sRUFBTyxDQUFFLEVBQUVoSCxLQUc1QzdPLE9BQU9nVyxrQkFBbUIsRUFDMUJGLEVBQUtMLFdBQVdRLE1BQU1wZ0IsVUFBVyxRQUFRLFNBQVVxZ0IsRUFBU0MsRUFBYUMsS0FFdkVELEVBQWNOLEVBQU1NLEVBQWEsQ0FDL0JFLFVBQVcsQ0FDVEMsU0FBUyxHQUVYQyxZQUFhLENBQ1hDLE9BQVEsQ0FDTkMsTUFBTyxDQUNMSCxTQUFTLEtBT2ZJLFFBQVMsQ0FBRSxLQUdBRixRQUFVLElBQUlqVSxTQUFRLFNBQVVpVSxHQUMzQ0EsRUFBT0csV0FBWSxDQUN6QixJQUdTM1csT0FBTzRXLHFCQUNWNVcsT0FBTzRXLG1CQUFxQm5CLFdBQVdvQixTQUFTN1IsS0FBTSxVQUFVLEtBQzlEaEYsT0FBT2dXLGtCQUFtQixDQUFJLEtBSWxDRSxFQUFRbmIsTUFBTWlLLEtBQU0sQ0FBQ21SLEVBQWFDLEdBQ3RDLElBRUVOLEVBQUtMLFdBQVdxQixPQUFPamhCLFVBQVcsUUFBUSxTQUFVcWdCLEVBQVNhLEVBQU9sWixHQUNsRXFZLEVBQVFuYixNQUFNaUssS0FBTSxDQUFDK1IsRUFBT2xaLEdBQ2hDLElBR0UsTUFBTStHLEVBQW9CLENBQ3hCbVMsTUFBTyxDQUVMSixXQUFXLEVBRVh2WSxPQUFRUCxFQUFRSCxPQUFPVSxPQUN2QkMsTUFBT1IsRUFBUUgsT0FBT1csT0FFeEJnWSxVQUFXLENBRVRDLFNBQVMsSUFLUEgsRUFBYyxJQUFJYSxTQUFTLFVBQVVuWixFQUFRSCxPQUFPRSxRQUF0QyxHQUdkaUIsRUFBZSxJQUFJbVksU0FBUyxVQUFVblosRUFBUUgsT0FBT21CLGVBQXRDLEdBR2ZELEVBQWdCLElBQUlvWSxTQUN4QixVQUFVblosRUFBUUgsT0FBT2tCLGdCQURMLEdBS2hCcVksRUFBZXBCLEdBQ25CLEVBQ0FoWCxFQUNBc1gsRUFFQXZSLEdBSUlzUyxFQUFnQnJaLEVBQVFrQixZQUFZRSxTQUN0QyxJQUFJK1gsU0FBUyxVQUFVblosRUFBUWtCLFlBQVlFLFdBQTNDLEdBQ0EsS0FHQXBCLEVBQVFrQixZQUFZdkYsWUFDdEIsSUFBSXdkLFNBQVMsVUFBV25aLEVBQVFrQixZQUFZdkYsV0FBNUMsQ0FBd0QyYyxHQUl0RHZYLEdBQ0ZtUSxFQUFXblEsR0FJYjZXLFdBQVc1WCxFQUFRSCxPQUFPekgsUUFBUSxZQUFhZ2hCLEVBQWNDLEdBRzdELE1BQU1DLEVBQWlCdEksSUFHdkIsSUFBSyxNQUFNb0IsS0FBUWtILEVBQ21CLG1CQUF6QkEsRUFBZWxILFdBQ2pCa0gsRUFBZWxILEdBSzFCbEIsRUFBVzBHLFdBQVdNLGVBR3RCTixXQUFXTSxjQUFnQixFQUM3QixDQzNIQSxNQUFNcUIsU0FBV3hkLEdBQVlBLGFBQzNCdEMsVUFBSzdDLFlBQVcsWUFBYSxpQkFDN0IsUUFJRixJQUFJNGlCLFFBQVUsS0FtQ1AxRixlQUFlMkYsY0FBY0MsR0FFbEMsTUFBTTdWLE1BQUVBLEVBQUtOLE1BQUVBLEdBQVV5TixjQUdqQnRQLE9BQVFpWSxLQUFpQkMsR0FBaUIvVixFQUc1Q2dXLEVBQWdCLENBQ3BCL1YsVUFBVVAsRUFBTUssa0JBQW1CLFFBQ25Da1csWUFBYSxNQUNibmQsS0FBTStjLEdBQWlCLEdBQ3ZCSyxjQUFjLEVBQ2RDLGVBQWUsRUFDZkMsY0FBYyxFQUNkQyxvQkFBb0IsRUFDcEJDLGdCQUFpQixRQUNiUixHQUFnQkMsR0FJdEIsSUFBS0osUUFBUyxDQUVaLElBQUlZLEVBQVcsRUFFZixNQUFNQyxFQUFPdkcsVUFDWCxJQUNFcFgsSUFDRSxFQUNBLHlEQUF5RDBkLE9BSTNEWixjQUFnQjVhLFVBQVUwYixPQUFPVCxFQUNsQyxDQUFDLE1BQU92YyxHQVFQLEdBUEFELGFBQ0UsRUFDQUMsRUFDQSxvREFJRThjLEVBQVcsSUFPYixNQUFNOWMsRUFOTlosSUFBSSxFQUFHLHNDQUFzQzBkLHVCQUd2QyxJQUFJbEcsU0FBU0ssR0FBYWdHLFdBQVdoRyxFQUFVLGFBQy9DOEYsR0FJVCxHQUdILFVBQ1FBLElBR3lCLFVBQTNCUixFQUFjL1YsVUFDaEJwSCxJQUFJLEVBQUcsNkNBSUxpZCxHQUNGamQsSUFBSSxFQUFHLDRDQUVWLENBQUMsTUFBT1ksR0FDUCxNQUFNLElBQUl3WCxZQUNSLGdFQUNBLEtBQ0FJLFNBQVM1WCxFQUNaLENBRUQsSUFBS2tjLFFBQ0gsTUFBTSxJQUFJMUUsWUFBWSwyQ0FBNEMsSUFFckUsQ0FHRCxPQUFPMEUsT0FDVCxDQVFPMUYsZUFBZTBHLGVBRWhCaEIsU0FBV0EsUUFBUWlCLGlCQUNmakIsUUFBUWtCLFFBRWhCbEIsUUFBVSxLQUNWOWMsSUFBSSxFQUFHLGdDQUNULENBZ0JPb1gsZUFBZTZHLFFBQVFDLEdBRTVCLElBQUtwQixVQUFZQSxRQUFRaUIsVUFDdkIsTUFBTSxJQUFJM0YsWUFBWSwwQ0FBMkMsS0FnQm5FLEdBWkE4RixFQUFhQyxXQUFhckIsUUFBUW1CLGdCQUc1QkMsRUFBYUMsS0FBS0MsaUJBQWdCLFNBR2xDQyxnQkFBZ0JILEVBQWFDLE1BR25DRyxlQUFlSixFQUFhQyxPQUd2QkQsRUFBYUMsTUFBUUQsRUFBYUMsS0FBS0ksV0FDMUMsTUFBTSxJQUFJbkcsWUFBWSwyQ0FBNEMsSUFFdEUsQ0FrQk9oQixlQUFlb0gsVUFBVU4sRUFBY08sR0FBWSxHQUN4RCxJQUNFLEdBQUlQLEVBQWFDLE9BQVNELEVBQWFDLEtBQUtJLFdBZ0IxQyxPQWZJRSxTQUVJUCxFQUFhQyxLQUFLTyxLQUFLLGNBQWUsQ0FDMUNDLFVBQVcsMkJBSVBOLGdCQUFnQkgsRUFBYUMsYUFHN0JELEVBQWFDLEtBQUtTLFVBQVMsS0FDL0J2a0IsU0FBU3drQixLQUFLQyxVQUNaLDREQUE0RCxLQUczRCxDQUVWLENBQUMsTUFBT2xlLEdBQ1BELGFBQ0UsRUFDQUMsRUFDQSx5QkFBeUJzZCxFQUFhYSxtREFJeENiLEVBQWFjLFVBQVkxSyxhQUFhck8sS0FBS0csVUFBWSxDQUN4RCxDQUNELE9BQU8sQ0FDVCxDQWlCT2dSLGVBQWU2SCxpQkFBaUJkLEVBQU1lLEdBRTNDLE1BQU1DLEVBQW9CLEdBR3BCeGEsRUFBWXVhLEVBQW1CdmEsVUFDckMsR0FBSUEsRUFBVyxDQUNiLE1BQU15YSxFQUFhLEdBVW5CLEdBUEl6YSxFQUFVZ0csSUFDWnlVLEVBQVdsZSxLQUFLLENBQ2RtZSxRQUFTMWEsRUFBVWdHLEtBS25CaEcsRUFBVWtHLE1BQ1osSUFBSyxNQUFNbkosS0FBUWlELEVBQVVrRyxNQUFPLENBQ2xDLE1BQU15VSxHQUFXNWQsRUFBS3BDLFdBQVcsUUFHakM4ZixFQUFXbGUsS0FDVG9lLEVBQ0ksQ0FDRUQsUUFBU2hnQixHQUFBQSxhQUFhbkQsZ0JBQWdCd0YsR0FBTyxTQUUvQyxDQUNFNFYsSUFBSzVWLEdBR2QsQ0FHSCxJQUFLLE1BQU02ZCxLQUFjSCxFQUN2QixJQUNFRCxFQUFrQmplLFdBQVdpZCxFQUFLcUIsYUFBYUQsR0FDaEQsQ0FBQyxNQUFPM2UsR0FDUEQsYUFBYSxFQUFHQyxFQUFPLDhDQUN4QixDQUVId2UsRUFBV3RoQixPQUFTLEVBR3BCLE1BQU0yaEIsRUFBYyxHQUNwQixHQUFJOWEsRUFBVWlHLElBQUssQ0FDakIsSUFBSThVLEVBQWEvYSxFQUFVaUcsSUFBSStVLE1BQU0sdUJBQ3JDLEdBQUlELEVBRUYsSUFBSyxJQUFJRSxLQUFpQkYsRUFDcEJFLElBQ0ZBLEVBQWdCQSxFQUNiL2pCLFFBQVEsT0FBUSxJQUNoQkEsUUFBUSxVQUFXLElBQ25CQSxRQUFRLEtBQU0sSUFDZEEsUUFBUSxLQUFNLElBQ2RBLFFBQVEsSUFBSyxJQUNiQSxRQUFRLE1BQU8sSUFDZjBCLE9BR0NxaUIsRUFBY3RnQixXQUFXLFFBQzNCbWdCLEVBQVl2ZSxLQUFLLENBQ2ZvVyxJQUFLc0ksSUFFRVYsRUFBbUJoZ0Isb0JBQzVCdWdCLEVBQVl2ZSxLQUFLLENBQ2ZyRSxLQUFNRSxLQUFBQSxLQUFLN0MsWUFBVzBsQixNQVFoQ0gsRUFBWXZlLEtBQUssQ0FDZm1lLFFBQVMxYSxFQUFVaUcsSUFBSS9PLFFBQVEsc0JBQXVCLEtBQU8sTUFHL0QsSUFBSyxNQUFNZ2tCLEtBQWVKLEVBQ3hCLElBQ0VOLEVBQWtCamUsV0FBV2lkLEVBQUsyQixZQUFZRCxHQUMvQyxDQUFDLE1BQU9qZixHQUNQRCxhQUNFLEVBQ0FDLEVBQ0EsK0NBRUgsQ0FFSDZlLEVBQVkzaEIsT0FBUyxDQUN0QixDQUNGLENBQ0QsT0FBT3FoQixDQUNULENBZU8vSCxlQUFlMkksbUJBQW1CNUIsRUFBTWdCLEdBQzdDLElBQ0UsSUFBSyxNQUFNYSxLQUFZYixRQUNmYSxFQUFTQyxnQkFJWDlCLEVBQUtTLFVBQVMsS0FFbEIsR0FBMEIsb0JBQWYxRCxXQUE0QixDQUVyQyxNQUFNZ0YsRUFBWWhGLFdBQVdpRixPQUc3QixHQUFJamxCLE1BQU1DLFFBQVEra0IsSUFBY0EsRUFBVXBpQixPQUV4QyxJQUFLLE1BQU1zaUIsS0FBWUYsRUFDckJFLEdBQVlBLEVBQVNDLFVBRXJCbkYsV0FBV2lGLE9BQU8vakIsT0FHdkIsQ0FHRCxTQUFVa2tCLEdBQW1Cam1CLFNBQVNrbUIscUJBQXFCLFdBRXJELElBQU1DLEdBQWtCbm1CLFNBQVNrbUIscUJBQXFCLGFBRWxERSxHQUFpQnBtQixTQUFTa21CLHFCQUFxQixRQUd6RCxJQUFLLE1BQU1HLElBQVcsSUFDakJKLEtBQ0FFLEtBQ0FDLEdBRUhDLEVBQVFDLFFBQ1QsR0FFSixDQUFDLE1BQU8vZixHQUNQRCxhQUFhLEVBQUdDLEVBQU8sOENBQ3hCLENBQ0gsQ0FZQXdXLGVBQWVpSCxnQkFBZ0JGLFNBRXZCQSxFQUFLeUMsV0FBVy9ELFNBQVUsQ0FBRThCLFVBQVcsMkJBR3ZDUixFQUFLcUIsYUFBYSxDQUFFM2lCLEtBQU1FLEtBQUlBLEtBQUNrYyxlQUFnQixzQkFHL0NrRixFQUFLUyxTQUFTM0QsZ0JBQ3RCLENBV0EsU0FBU3FELGVBQWVILEdBRXRCLE1BQU1oWCxNQUFFQSxHQUFVbU4sYUFHbEI2SixFQUFLcEcsR0FBRyxhQUFhWCxVQUdmK0csRUFBS0ksVUFFUixJQUlDcFgsRUFBTW5DLFFBQVVtQyxFQUFNRyxpQkFDeEI2VyxFQUFLcEcsR0FBRyxXQUFZaFgsSUFDbEJSLFFBQVFQLElBQUksV0FBV2UsRUFBUWtYLFNBQVMsR0FHOUMsQ0M1Y0EsSUFBQTRJLFlBQWUsSUFBTSx5WENJTkMsWUFBQ3ZkLEdBQVEsOExBUWxCc2QsOEVBSUV0ZCx3Q0NXRDZULGVBQWUySixnQkFBZ0I1QyxFQUFNN2EsR0FFMUMsTUFBTTZiLEVBQW9CLEdBRTFCLElBRUUsTUFBTTZCLEVBQWdCMWQsRUFBUUgsT0FFOUIsSUFBSThkLEdBQVEsRUFDWixHQUFJRCxFQUFjemQsSUFBSyxDQUlyQixHQUhBdkQsSUFBSSxFQUFHLG1DQUdvQixRQUF2QmdoQixFQUFjaGxCLEtBQ2hCLE9BQU9nbEIsRUFBY3pkLElBSXZCMGQsR0FBUSxRQUdGQyxVQUFVL0MsRUFBTTZDLEVBQWN6ZCxJQUMxQyxNQUNNdkQsSUFBSSxFQUFHLDJDQUdEbWhCLGNBQWNoRCxFQUFNN2EsR0FNNUI2YixFQUFrQmplLGNBQ04rZCxpQkFBaUJkLEVBQU03YSxFQUFRa0IsY0FJM0MsTUFBTTRjLEVBQU9ILFFBQ0g5QyxFQUFLUyxVQUFVN2EsSUFDbkIsTUFBTXNkLEVBQWFobkIsU0FBU2luQixjQUMxQixzQ0FJSUMsRUFBY0YsRUFBV3hkLE9BQU8yZCxRQUFROWlCLE1BQVFxRixFQUNoRDBkLEVBQWFKLEVBQVd2ZCxNQUFNMGQsUUFBUTlpQixNQUFRcUYsRUFVcEQsT0FOQTFKLFNBQVN3a0IsS0FBSzZDLE1BQU1DLEtBQU81ZCxFQUkzQjFKLFNBQVN3a0IsS0FBSzZDLE1BQU1FLE9BQVMsTUFFdEIsQ0FDTEwsY0FDQUUsYUFDRCxHQUNBSSxXQUFXYixFQUFjamQsY0FDdEJvYSxFQUFLUyxVQUFTLEtBRWxCLE1BQU0yQyxZQUFFQSxFQUFXRSxXQUFFQSxHQUFlaGMsT0FBT3lWLFdBQVdpRixPQUFPLEdBTzdELE9BRkE5bEIsU0FBU3drQixLQUFLNkMsTUFBTUMsS0FBTyxFQUVwQixDQUNMSixjQUNBRSxhQUNELEtBSURLLEVBQUVBLEVBQUNDLEVBQUVBLFNBQVlDLGVBQWU3RCxHQUdoQzhELEVBQWlCcGpCLEtBQUtxakIsSUFDMUJyakIsS0FBS3NqQixLQUFLZixFQUFLRyxhQUFlUCxFQUFjbmQsU0FJeEN1ZSxFQUFnQnZqQixLQUFLcWpCLElBQ3pCcmpCLEtBQUtzakIsS0FBS2YsRUFBS0ssWUFBY1QsRUFBY2xkLFFBVTdDLElBQUl1ZSxFQUVKLGFBUk1sRSxFQUFLbUUsWUFBWSxDQUNyQnplLE9BQVFvZSxFQUNSbmUsTUFBT3NlLEVBQ1BHLGtCQUFtQnRCLEVBQVEsRUFBSVksV0FBV2IsRUFBY2pkLFNBS2xEaWQsRUFBY2hsQixNQUNwQixJQUFLLE1BQ0hxbUIsUUFBZUcsV0FBV3JFLEdBQzFCLE1BQ0YsSUFBSyxNQUNMLElBQUssT0FDSGtFLFFBQWVJLGFBQ2J0RSxFQUNBNkMsRUFBY2hsQixLQUNkLENBQ0U4SCxNQUFPc2UsRUFDUHZlLE9BQVFvZSxFQUNSSCxJQUNBQyxLQUVGZixFQUFjemMsc0JBRWhCLE1BQ0YsSUFBSyxNQUNIOGQsUUFBZUssV0FDYnZFLEVBQ0E4RCxFQUNBRyxFQUNBcEIsRUFBY3pjLHNCQUVoQixNQUNGLFFBQ0UsTUFBTSxJQUFJNlQsWUFDUix1Q0FBdUM0SSxFQUFjaGxCLFFBQ3JELEtBTU4sYUFETStqQixtQkFBbUI1QixFQUFNZ0IsR0FDeEJrRCxDQUNSLENBQUMsTUFBT3poQixHQUVQLGFBRE1tZixtQkFBbUI1QixFQUFNZ0IsR0FDeEJ2ZSxDQUNSLENBQ0gsQ0FjQXdXLGVBQWU4SixVQUFVL0MsRUFBTTVhLFNBQ3ZCNGEsRUFBS3lDLFdBQVdFLFlBQVl2ZCxHQUFNLENBQ3RDb2IsVUFBVyxvQkFFZixDQWlCQXZILGVBQWUrSixjQUFjaEQsRUFBTTdhLFNBQzNCNmEsRUFBS1MsU0FBU3ZELFlBQWEvWCxFQUNuQyxDQWNBOFQsZUFBZTRLLGVBQWU3RCxHQUM1QixPQUFPQSxFQUFLd0UsTUFBTSxvQkFBcUJqQyxJQUNyQyxNQUFNb0IsRUFBRUEsRUFBQ0MsRUFBRUEsRUFBQ2plLE1BQUVBLEVBQUtELE9BQUVBLEdBQVc2YyxFQUFRa0Msd0JBQ3hDLE1BQU8sQ0FDTGQsSUFDQUMsSUFDQWplLFFBQ0FELE9BQVFoRixLQUFLZ2tCLE1BQU1oZixFQUFTLEVBQUlBLEVBQVMsS0FDMUMsR0FFTCxDQWFBdVQsZUFBZW9MLFdBQVdyRSxHQUN4QixPQUFPQSxFQUFLd0UsTUFDVixnQ0FDQ2pDLEdBQVlBLEVBQVFvQyxXQUV6QixDQWtCQTFMLGVBQWVxTCxhQUFhdEUsRUFBTW5pQixFQUFNK21CLEVBQU14ZSxHQUM1QyxPQUFPaVQsUUFBUXdMLEtBQUssQ0FDbEI3RSxFQUFLOEUsV0FBVyxDQUNkam5CLE9BQ0ErbUIsT0FDQUcsU0FBVSxTQUNWQyxVQUFVLEVBQ1ZDLGtCQUFrQixFQUNsQkMsdUJBQXVCLEtBQ1YsUUFBVHJuQixFQUFpQixDQUFFc25CLFFBQVMsSUFBTyxDQUFBLEVBRXZDQyxlQUF3QixPQUFSdm5CLElBRWxCLElBQUl3YixTQUFRLENBQUNnTSxFQUFVOUwsSUFDckJtRyxZQUNFLElBQU1uRyxFQUFPLElBQUlVLFlBQVksd0JBQXlCLE9BQ3REN1QsR0FBd0IsU0FJaEMsQ0FpQkE2UyxlQUFlc0wsV0FBV3ZFLEVBQU10YSxFQUFRQyxFQUFPUyxHQUU3QyxhQURNNFosRUFBS3NGLGlCQUFpQixVQUNyQnRGLEVBQUt1RixJQUFJLENBRWQ3ZixPQUFRQSxFQUFTLEVBQ2pCQyxRQUNBb2YsU0FBVSxTQUNWNWQsUUFBU2YsR0FBd0IsTUFFckMsQ0NwU0EsSUFBSTBCLEtBQU8sS0FHWCxNQUFNMGQsVUFBWSxDQUNoQkMsaUJBQWtCLEVBQ2xCQyxpQkFBa0IsRUFDbEJDLGVBQWdCLEVBQ2hCQyxlQUFnQixFQUNoQkMsbUJBQW9CLEVBQ3BCQyx1QkFBd0IsRUFDeEJDLDJCQUE0QixFQUM1QkMsVUFBVyxFQUNYQyxpQkFBa0IsR0FzQmJoTixlQUFlaU4sU0FDcEJDLEVBQWNoUSxhQUFhck8sS0FDM0IrVyxFQUFnQixVQUdWRCxjQUFjQyxHQUVwQixJQU1FLEdBTEFoZCxJQUNFLEVBQ0EsOENBQThDc2tCLEVBQVlwZSxtQkFBbUJvZSxFQUFZbmUsZUFHdkZGLEtBS0YsWUFKQWpHLElBQ0UsRUFDQSx5RUFNQXNrQixFQUFZcGUsV0FBYW9lLEVBQVluZSxhQUN2Q21lLEVBQVlwZSxXQUFhb2UsRUFBWW5lLFlBSXZDRixLQUFPLElBQUlzZSxLQUFBQSxLQUFLLElBRVhDLFNBQVNGLEdBQ1puZ0IsSUFBS21nQixFQUFZcGUsV0FDakI5QixJQUFLa2dCLEVBQVluZSxXQUNqQnNlLHFCQUFzQkgsRUFBWWplLGVBQ2xDcWUsb0JBQXFCSixFQUFZaGUsY0FDakNxZSxxQkFBc0JMLEVBQVkvZCxlQUNsQ3FlLGtCQUFtQk4sRUFBWTlkLFlBQy9CcWUsMEJBQTJCUCxFQUFZN2Qsb0JBQ3ZDcWUsbUJBQW9CUixFQUFZNWQsZUFDaENxZSxzQkFBc0IsSUFJeEI5ZSxLQUFLOFIsR0FBRyxXQUFXWCxNQUFPNEksSUFFeEIsTUFBTWdGLFFBQW9CeEcsVUFBVXdCLEdBQVUsR0FDOUNoZ0IsSUFDRSxFQUNBLHlCQUF5QmdnQixFQUFTakIsZ0RBQWdEaUcsS0FDbkYsSUFHSC9lLEtBQUs4UixHQUFHLGtCQUFrQixDQUFDa04sRUFBVWpGLEtBQ25DaGdCLElBQ0UsRUFDQSx5QkFBeUJnZ0IsRUFBU2pCLDBDQUVwQ2lCLEVBQVM3QixLQUFPLElBQUksSUFHdEIsTUFBTStHLEVBQW1CLEdBRXpCLElBQUssSUFBSS9OLEVBQUksRUFBR0EsRUFBSW1OLEVBQVlwZSxXQUFZaVIsSUFDMUMsSUFDRSxNQUFNNkksUUFBaUIvWixLQUFLa2YsVUFBVUMsUUFDdENGLEVBQWlCaGtCLEtBQUs4ZSxFQUN2QixDQUFDLE1BQU9wZixHQUNQRCxhQUFhLEVBQUdDLEVBQU8sK0NBQ3hCLENBSUhza0IsRUFBaUJsZCxTQUFTZ1ksSUFDeEIvWixLQUFLb2YsUUFBUXJGLEVBQVMsSUFHeEJoZ0IsSUFDRSxFQUNBLDRCQUEyQmtsQixFQUFpQnBuQixPQUFTLFNBQVNvbkIsRUFBaUJwbkIsb0NBQXNDLEtBRXhILENBQUMsTUFBTzhDLEdBQ1AsTUFBTSxJQUFJd1gsWUFDUiw2REFDQSxLQUNBSSxTQUFTNVgsRUFDWixDQUNILENBWU93VyxlQUFla08sV0FJcEIsR0FIQXRsQixJQUFJLEVBQUcsNkRBR0hpRyxLQUFNLENBRVIsSUFBSyxNQUFNc2YsS0FBVXRmLEtBQUt1ZixLQUN4QnZmLEtBQUtvZixRQUFRRSxFQUFPdkYsVUFJakIvWixLQUFLd2Ysa0JBQ0Z4ZixLQUFLb2EsVUFDWHJnQixJQUFJLEVBQUcsNENBRVRpRyxLQUFPLElBQ1IsT0FHSzZYLGNBQ1IsQ0FtQk8xRyxlQUFlc08sU0FBU3BpQixHQUM3QixJQUFJcWlCLEVBRUosSUFZRSxHQVhBM2xCLElBQUksRUFBRyxnREFHTDJqQixVQUFVQyxpQkFHUnRQLGFBQWFyTyxLQUFLYixjQUNwQndnQixlQUlHM2YsS0FDSCxNQUFNLElBQUltUyxZQUNSLHVEQUNBLEtBS0osTUFBTXlOLEVBQWlCMW5CLGNBR3ZCLElBQ0U2QixJQUFJLEVBQUcscUNBR1AybEIsUUFBcUIxZixLQUFLa2YsVUFBVUMsUUFHaEM5aEIsRUFBUXlCLE9BQU9LLGNBQ2pCcEYsSUFDRSxFQUNBc0QsRUFBUXdpQixXQUNKLHdCQUF3QnhpQixFQUFRd2lCLGlCQUNoQyxlQUNKLGtDQUFrQ0QsU0FHdkMsQ0FBQyxNQUFPamxCLEdBQ1AsTUFBTSxJQUFJd1gsWUFDUixXQUNHOVUsRUFBUXdpQixXQUFhLFlBQVl4aUIsRUFBUXdpQixpQkFBbUIsSUFDN0Qsd0RBQXdERCxTQUMxRCxLQUNBck4sU0FBUzVYLEVBQ1osQ0FHRCxHQUZBWixJQUFJLEVBQUcscUNBRUYybEIsRUFBYXhILEtBR2hCLE1BREF3SCxFQUFhM0csVUFBWTFiLEVBQVEyQyxLQUFLRyxVQUFZLEVBQzVDLElBQUlnUyxZQUNSLG1FQUNBLEtBS0osTUFBTTJOLEVBQVl2b0IsaUJBRWxCd0MsSUFDRSxFQUNBLHlCQUF5QjJsQixFQUFhNUcsMkNBSXhDLE1BQU1pSCxFQUFnQjduQixjQUNoQmtrQixRQUFldEIsZ0JBQWdCNEUsRUFBYXhILEtBQU03YSxHQUd4RCxHQUFJK2UsYUFBa0J2TCxNQW1CcEIsS0FOdUIsMEJBQW5CdUwsRUFBT3RoQixVQUVUNGtCLEVBQWEzRyxVQUFZMWIsRUFBUTJDLEtBQUtHLFVBQVksRUFDbER1ZixFQUFheEgsS0FBTyxNQUlKLGlCQUFoQmtFLEVBQU9oUCxNQUNZLDBCQUFuQmdQLEVBQU90aEIsUUFFRCxJQUFJcVgsWUFDUixXQUNHOVUsRUFBUXdpQixXQUFhLFlBQVl4aUIsRUFBUXdpQixpQkFBbUIsSUFDN0QsaUhBQ0Z0TixTQUFTNkosR0FFTCxJQUFJakssWUFDUixXQUNHOVUsRUFBUXdpQixXQUFhLFlBQVl4aUIsRUFBUXdpQixpQkFBbUIsSUFDN0Qsb0NBQW9DRSxVQUN0Q3hOLFNBQVM2SixHQUtYL2UsRUFBUXlCLE9BQU9LLGNBQ2pCcEYsSUFDRSxFQUNBc0QsRUFBUXdpQixXQUNKLHdCQUF3QnhpQixFQUFRd2lCLGlCQUNoQyxlQUNKLHNDQUFzQ0UsVUFLMUMvZixLQUFLb2YsUUFBUU0sR0FJYixNQUNNTSxFQURVem9CLGlCQUNhdW9CLEVBUzdCLE9BUEFwQyxVQUFVUSxXQUFhOEIsRUFDdkJ0QyxVQUFVUyxpQkFDUlQsVUFBVVEsWUFBY1IsVUFBVUUsaUJBRXBDN2pCLElBQUksRUFBRyw0QkFBNEJpbUIsUUFHNUIsQ0FDTDVELFNBQ0EvZSxVQUVILENBQUMsTUFBTzFDLEdBT1AsT0FORStpQixVQUFVRyxlQUVSNkIsR0FDRjFmLEtBQUtvZixRQUFRTSxHQUdUL2tCLENBQ1AsQ0FDSCxDQXFCTyxTQUFTc2xCLGVBQ2QsT0FBT3ZDLFNBQ1QsQ0FVTyxTQUFTd0Msa0JBQ2QsTUFBTyxDQUNMaGlCLElBQUs4QixLQUFLOUIsSUFDVkMsSUFBSzZCLEtBQUs3QixJQUNWb2hCLEtBQU12ZixLQUFLbWdCLFVBQ1hDLFVBQVdwZ0IsS0FBS3FnQixVQUNoQkMsV0FBWXRnQixLQUFLbWdCLFVBQVluZ0IsS0FBS3FnQixVQUNsQ0UsZ0JBQWlCdmdCLEtBQUt3Z0IscUJBQ3RCQyxlQUFnQnpnQixLQUFLMGdCLG9CQUNyQkMsbUJBQW9CM2dCLEtBQUs0Z0Isd0JBQ3pCQyxnQkFBaUI3Z0IsS0FBSzZnQixnQkFBZ0JocEIsT0FDdENpcEIsWUFDRTlnQixLQUFLbWdCLFVBQ0xuZ0IsS0FBS3FnQixVQUNMcmdCLEtBQUt3Z0IscUJBQ0x4Z0IsS0FBSzBnQixvQkFDTDFnQixLQUFLNGdCLHdCQUNMNWdCLEtBQUs2Z0IsZ0JBQWdCaHBCLE9BRTNCLENBU08sU0FBUzhuQixjQUNkLE1BQU16aEIsSUFDSkEsRUFBR0MsSUFDSEEsRUFBR29oQixLQUNIQSxFQUFJYSxVQUNKQSxFQUFTRSxXQUNUQSxFQUFVQyxnQkFDVkEsRUFBZUUsZUFDZkEsRUFBY0UsbUJBQ2RBLEVBQWtCRSxnQkFDbEJBLEVBQWVDLFlBQ2ZBLEdBQ0VaLGtCQUVKbm1CLElBQUksRUFBRywyREFBMkRtRSxNQUNsRW5FLElBQUksRUFBRywyREFBMkRvRSxNQUNsRXBFLElBQUksRUFBRyx3Q0FBd0N3bEIsTUFDL0N4bEIsSUFBSSxFQUFHLHdDQUF3Q3FtQixNQUMvQ3JtQixJQUNFLEVBQ0EsK0RBQStEdW1CLE1BRWpFdm1CLElBQ0UsRUFDQSwwREFBMER3bUIsTUFFNUR4bUIsSUFDRSxFQUNBLHlEQUF5RDBtQixNQUUzRDFtQixJQUNFLEVBQ0EsMkRBQTJENG1CLE1BRTdENW1CLElBQ0UsRUFDQSwyREFBMkQ4bUIsTUFFN0Q5bUIsSUFBSSxFQUFHLHVDQUF1QyttQixLQUNoRCxDQVVBLFNBQVN2QyxTQUFTRixHQUNoQixNQUFPLENBY0wwQyxPQUFRNVAsVUFFTixNQUFNOEcsRUFBZSxDQUNuQmEsR0FBSXZTLEtBQUFBLEtBRUp3UyxVQUFXbmdCLEtBQUtFLE1BQU1GLEtBQUtvb0IsVUFBWTNDLEVBQVlsZSxVQUFZLEtBR2pFLElBRUUsTUFBTThnQixFQUFZMXBCLGlCQWNsQixhQVhNeWdCLFFBQVFDLEdBR2RsZSxJQUNFLEVBQ0EseUJBQXlCa2UsRUFBYWEsNkNBQ3BDdmhCLGlCQUFtQjBwQixRQUtoQmhKLENBQ1IsQ0FBQyxNQUFPdGQsR0FLUCxNQUpBWixJQUNFLEVBQ0EseUJBQXlCa2UsRUFBYWEscURBRWxDbmUsQ0FDUCxHQWdCSHVtQixTQUFVL1AsTUFBTzhHLEdBaUJWQSxFQUFhQyxLQVNkRCxFQUFhQyxLQUFLSSxZQUNwQnZlLElBQ0UsRUFDQSx5QkFBeUJrZSxFQUFhYSx5REFFakMsR0FJTGIsRUFBYUMsS0FBS2lKLFlBQVlDLFVBQ2hDcm5CLElBQ0UsRUFDQSx5QkFBeUJrZSxFQUFhYSx3REFFakMsS0FLUHVGLEVBQVlsZSxhQUNWOFgsRUFBYWMsVUFBWXNGLEVBQVlsZSxhQUV2Q3BHLElBQ0UsRUFDQSx5QkFBeUJrZSxFQUFhYSx5Q0FBeUN1RixFQUFZbGUseUNBRXRGLElBbENQcEcsSUFDRSxFQUNBLHlCQUF5QmtlLEVBQWFhLHNEQUVqQyxHQThDWHNCLFFBQVNqSixNQUFPOEcsSUFNZCxHQUxBbGUsSUFDRSxFQUNBLHlCQUF5QmtlLEVBQWFhLDhCQUdwQ2IsRUFBYUMsT0FBU0QsRUFBYUMsS0FBS0ksV0FDMUMsSUFFRUwsRUFBYUMsS0FBS21KLG1CQUFtQixhQUNyQ3BKLEVBQWFDLEtBQUttSixtQkFBbUIsV0FDckNwSixFQUFhQyxLQUFLbUosbUJBQW1CLHVCQUcvQnBKLEVBQWFDLEtBQUtILE9BQ3pCLENBQUMsTUFBT3BkLEdBS1AsTUFKQVosSUFDRSxFQUNBLHlCQUF5QmtlLEVBQWFhLG1EQUVsQ25lLENBQ1AsQ0FDRixFQUdQLENDMWtCTyxTQUFTMm1CLFNBQVN0cUIsR0FFdkIsTUFBTXdJLEVBQVMsSUFBSStoQixNQUFBQSxNQUFNLElBQUkvaEIsT0FNN0IsT0FIZWdpQixVQUFVaGlCLEdBR1g4aEIsU0FBU3RxQixFQUFPLENBQUV5cUIsU0FBVSxDQUFDLGtCQUM3QyxDQ0ZBLElBQUlqakIsb0JBQXFCLEVBbUJsQjJTLGVBQWV1USxhQUFhcmtCLEdBRWpDLElBQUlBLElBQVdBLEVBQVFILE9BcUNyQixNQUFNLElBQUlpVixZQUNSLGtLQUNBLFdBckNJd1AsWUFBWXRrQixHQUFTOFQsTUFBT3hXLEVBQU9xVCxLQUV2QyxHQUFJclQsRUFDRixNQUFNQSxFQUlSLE1BQU0rQyxJQUFFQSxFQUFHMUgsUUFBRUEsRUFBT0QsS0FBRUEsR0FBU2lZLEVBQUszUSxRQUFRSCxPQUc1QyxJQUNNUSxFQUVGOFcsR0FBYUEsY0FDWCxHQUFHeGUsRUFBUUUsTUFBTSxLQUFLQyxTQUFXLGNBQ2pDWSxVQUFVaVgsRUFBS29PLE9BQVFybUIsSUFJekJ5ZSxHQUFhQSxjQUNYeGUsR0FBVyxTQUFTRCxJQUNYLFFBQVRBLEVBQWlCa0IsT0FBT0MsS0FBSzhXLEVBQUtvTyxPQUFRLFVBQVlwTyxFQUFLb08sT0FHaEUsQ0FBQyxNQUFPemhCLEdBQ1AsTUFBTSxJQUFJd1gsWUFDUixzQ0FDQSxLQUNBSSxTQUFTNVgsRUFDWixPQUdLMGtCLFVBQVUsR0FRdEIsQ0FxQk9sTyxlQUFleVEsWUFBWXZrQixHQUVoQyxLQUFJQSxHQUFXQSxFQUFRSCxRQUFVRyxFQUFRSCxPQUFPSyxPQTRFOUMsTUFBTSxJQUFJNFUsWUFDUiwrR0FDQSxLQTlFbUQsQ0FFckQsTUFBTTBQLEVBQWlCLEdBR3ZCLElBQUssSUFBSUMsS0FBUXprQixFQUFRSCxPQUFPSyxNQUFNckgsTUFBTSxNQUFRLEdBQ2xENHJCLEVBQU9BLEVBQUs1ckIsTUFBTSxLQUNFLElBQWhCNHJCLEVBQUtqcUIsT0FDUGdxQixFQUFlNW1CLEtBQ2IwbUIsWUFDRSxJQUNLdGtCLEVBQ0hILE9BQVEsSUFDSEcsRUFBUUgsT0FDWEMsT0FBUTJrQixFQUFLLEdBQ2I5ckIsUUFBUzhyQixFQUFLLE1BR2xCLENBQUNubkIsRUFBT3FULEtBRU4sR0FBSXJULEVBQ0YsTUFBTUEsRUFJUixNQUFNK0MsSUFBRUEsRUFBRzFILFFBQUVBLEVBQU9ELEtBQUVBLEdBQVNpWSxFQUFLM1EsUUFBUUgsT0FHNUMsSUFDTVEsRUFFRjhXLEdBQWFBLGNBQ1gsR0FBR3hlLEVBQVFFLE1BQU0sS0FBS0MsU0FBVyxjQUNqQ1ksVUFBVWlYLEVBQUtvTyxPQUFRcm1CLElBSXpCeWUsR0FBYUEsY0FDWHhlLEVBQ1MsUUFBVEQsRUFDSWtCLE9BQU9DLEtBQUs4VyxFQUFLb08sT0FBUSxVQUN6QnBPLEVBQUtvTyxPQUdkLENBQUMsTUFBT3poQixHQUNQLE1BQU0sSUFBSXdYLFlBQ1Isc0NBQ0EsS0FDQUksU0FBUzVYLEVBQ1osTUFLUFosSUFBSSxFQUFHLHVEQUtYLE1BQU1nb0IsUUFBcUJ4USxRQUFReVEsV0FBV0gsU0FHeEN4QyxXQUdOMEMsRUFBYWhnQixTQUFRLENBQUNxYSxFQUFRak8sS0FFeEJpTyxFQUFPNkYsUUFDVHZuQixhQUNFLEVBQ0EwaEIsRUFBTzZGLE9BQ1AsK0JBQStCOVQsRUFBUSxzQ0FFMUMsR0FFUCxDQU1BLENBOEJPZ0QsZUFBZXdRLFlBQVluVCxFQUFlMFQsR0FDL0MsSUFFRW5vQixJQUFJLEVBQUcsMkNBR1AsTUFBTXNELEVBQVUyUixhQUFhWCxZQUFXLEdBQVFHLEdBRzFDdU0sRUFBZ0IxZCxFQUFRSCxPQUc5QixHQUE2QixPQUF6QjZkLEVBQWM1ZCxPQUFpQixDQUdqQyxJQUFJZ2xCLEVBRkpwb0IsSUFBSSxFQUFHLG1EQUdQLElBRUVvb0IsRUFBYy9vQixHQUFZQSxhQUN4Qm5ELGdCQUFnQjhrQixFQUFjNWQsUUFDOUIsT0FFSCxDQUFDLE1BQU94QyxHQUNQLE1BQU0sSUFBSXdYLFlBQ1IsbURBQ0EsS0FDQUksU0FBUzVYLEVBQ1osQ0FHRCxHQUFJb2dCLEVBQWM1ZCxPQUFPaEUsU0FBUyxRQUNoQyxJQUVFNGhCLEVBQWN6ZCxJQUFNNlAsZUFBZSxNQUFPZ1YsR0FBYSxFQUN4RCxDQUFDLE1BQU94bkIsR0FNUCxNQUxBTyxhQUNFLEVBQ0FQLEVBQU1RLE9BQ04sOENBRUlSLENBQ1AsS0FDSSxLQUFJb2dCLEVBQWM1ZCxPQUFPaEUsU0FBUyxTQWF2QyxNQUFNLElBQUlnWixZQUNSLGtEQUNBLEtBZEYsSUFFRTRJLEVBQWMzZCxNQUFRK1AsZUFBZSxRQUFTZ1YsR0FBYSxFQUM1RCxDQUFDLE1BQU94bkIsR0FNUCxNQUxBTyxhQUNFLEVBQ0FQLEVBQU1RLE9BQ04sZ0RBRUlSLENBQ1AsQ0FNRixDQUNGLENBR0QsR0FBMEIsT0FBdEJvZ0IsRUFBY3pkLElBQWMsQ0FDOUJ2RCxJQUFJLEVBQUcscURBR0xrbUIsZUFBZWpDLHVCQUdqQixNQUFNNUIsUUFBZWdHLGVBQ25CZCxTQUFTdkcsRUFBY3pkLEtBQ3ZCRCxHQU9GLFFBSEU0aUIsZUFBZW5DLGVBR1ZvRSxFQUFZLEtBQU05RixFQUMxQixDQUdELEdBQTRCLE9BQXhCckIsRUFBYzNkLE9BQTRDLE9BQTFCMmQsRUFBYzFkLFFBQWtCLENBQ2xFdEQsSUFBSSxFQUFHLHNEQUdMa21CLGVBQWVoQywyQkFHakIsTUFBTTdCLFFBQWVpRyxtQkFDbkJ0SCxFQUFjM2QsT0FBUzJkLEVBQWMxZCxRQUNyQ0EsR0FPRixRQUhFNGlCLGVBQWVsQyxtQkFHVm1FLEVBQVksS0FBTTlGLEVBQzFCLENBR0QsT0FBTzhGLEVBQ0wsSUFBSS9QLFlBQ0YsZ0pBQ0EsS0FHTCxDQUFDLE1BQU94WCxHQUNQLE9BQU91bkIsRUFBWXZuQixFQUNwQixDQUNILENBU08sU0FBUzJuQix3QkFDZCxPQUFPOWpCLGtCQUNULENBVU8sU0FBUytqQixzQkFBc0I5cEIsR0FDcEMrRixtQkFBcUIvRixDQUN2QixDQWtCQTBZLGVBQWVpUixlQUFlSSxFQUFlbmxCLEdBRTNDLEdBQzJCLGlCQUFsQm1sQixJQUNOQSxFQUFjdmUsUUFBUSxTQUFXLEdBQUt1ZSxFQUFjdmUsUUFBUSxVQUFZLEdBWXpFLE9BVkFsSyxJQUFJLEVBQUcsaUNBR1BzRCxFQUFRSCxPQUFPSSxJQUFNa2xCLEVBR3JCbmxCLEVBQVFILE9BQU9FLE1BQVEsS0FDdkJDLEVBQVFILE9BQU9HLFFBQVUsS0FHbEJvbEIsZUFBZXBsQixHQUV0QixNQUFNLElBQUk4VSxZQUFZLG1DQUFvQyxJQUU5RCxDQWtCQWhCLGVBQWVrUixtQkFBbUJHLEVBQWVubEIsR0FDL0N0RCxJQUFJLEVBQUcsdUNBR1AsTUFBTWdXLEVBQXFCTCxnQkFDekI4UyxHQUNBLEVBQ0FubEIsRUFBUWtCLFlBQVlDLG9CQUl0QixHQUN5QixPQUF2QnVSLEdBQzhCLGlCQUF2QkEsSUFDTkEsRUFBbUIxVyxXQUFXLE9BQzlCMFcsRUFBbUI1VyxTQUFTLEtBRTdCLE1BQU0sSUFBSWdaLFlBQ1Isb1BBQ0EsS0FXSixPQU5BOVUsRUFBUUgsT0FBT0UsTUFBUTJTLEVBR3ZCMVMsRUFBUUgsT0FBT0ksSUFBTSxLQUdkbWxCLGVBQWVwbEIsRUFDeEIsQ0FjQThULGVBQWVzUixlQUFlcGxCLEdBQzVCLE1BQVFILE9BQVE2ZCxFQUFleGMsWUFBYTBhLEdBQXVCNWIsRUFHbkUwZCxFQUFjaGxCLEtBQU9LLFFBQVEya0IsRUFBY2hsQixLQUFNZ2xCLEVBQWMva0IsU0FHL0Qra0IsRUFBYy9rQixRQUFVRixXQUFXaWxCLEVBQWNobEIsS0FBTWdsQixFQUFjL2tCLFNBR3JFK0QsSUFDRSxFQUNBLCtCQUErQmtmLEVBQW1CemEsbUJBQXFCLFVBQVksaUJBSXJGa2tCLG1CQUFtQnpKLEVBQW9CQSxFQUFtQnphLG9CQUcxRG1rQixzQkFDRTVILEVBQ0E5QixFQUFtQmhnQixtQkFDbkJnZ0IsRUFBbUJ6YSxvQkFJckJuQixFQUFRSCxPQUFTLElBQ1o2ZCxLQUNBNkgsZUFBZTdILElBSXBCLElBRUUxZCxFQUFVMlAsZUFBZTNQLEVBQzFCLENBQUMsTUFBTzFDLEdBQ1BPLGFBQWEsRUFBR1AsRUFBTVEsT0FBUSwwQ0FDL0IsQ0FHRCxPQUFPc2tCLFNBQVNwaUIsRUFDbEIsQ0FvQkEsU0FBU3VsQixlQUFlN0gsR0FFdEIsTUFBUXhFLE1BQU9zTSxFQUFjaE4sVUFBV2lOLEdBQ3RDL0gsRUFBYzFkLFNBQVdxUyxnQkFBZ0JxTCxFQUFjM2QsU0FBVSxHQUczRG1aLE1BQU93TSxFQUFvQmxOLFVBQVdtTixHQUM1Q3RULGdCQUFnQnFMLEVBQWMzYyxpQkFBa0IsR0FHMUNtWSxNQUFPME0sRUFBbUJwTixVQUFXcU4sR0FDM0N4VCxnQkFBZ0JxTCxFQUFjMWMsZ0JBQWlCLEVBTTNDUCxFQUFRdEYsWUFDWkksS0FBS3VGLElBQ0gsR0FDQXZGLEtBQUtzRixJQUNINmMsRUFBY2pkLE9BQ1pnbEIsR0FBa0JobEIsT0FDbEJrbEIsR0FBd0JsbEIsT0FDeEJvbEIsR0FBdUJwbEIsT0FDdkJpZCxFQUFjOWMsY0FDZCxFQUNGLElBR0osR0E0QklrZCxFQUFPLENBQUV2ZCxPQXZCYm1kLEVBQWNuZCxRQUNka2xCLEdBQWtCSyxjQUNsQk4sR0FBY2psQixRQUNkb2xCLEdBQXdCRyxjQUN4QkosR0FBb0JubEIsUUFDcEJzbEIsR0FBdUJDLGNBQ3ZCRixHQUFtQnJsQixRQUNuQm1kLEVBQWNoZCxlQUNkLElBZXFCRixNQVhyQmtkLEVBQWNsZCxPQUNkaWxCLEdBQWtCTSxhQUNsQlAsR0FBY2hsQixPQUNkbWxCLEdBQXdCSSxhQUN4QkwsR0FBb0JsbEIsT0FDcEJxbEIsR0FBdUJFLGFBQ3ZCSCxHQUFtQnBsQixPQUNuQmtkLEVBQWMvYyxjQUNkLElBRzRCRixTQUc5QixJQUFLLElBQUt1bEIsRUFBTzVxQixLQUFVckQsT0FBTytaLFFBQVFnTSxHQUN4Q0EsRUFBS2tJLEdBQ2MsaUJBQVY1cUIsR0FBc0JBLEVBQU03QyxRQUFRLFNBQVUsSUFBTTZDLEVBSS9ELE9BQU8waUIsQ0FDVCxDQWtCQSxTQUFTdUgsbUJBQW1CekosRUFBb0J6YSxHQUU5QyxHQUFJQSxFQUFvQixDQUV0QixHQUE0QyxpQkFBakN5YSxFQUFtQnZhLFVBRTVCdWEsRUFBbUJ2YSxVQUFZNGtCLGlCQUM3QnJLLEVBQW1CdmEsVUFDbkJ1YSxFQUFtQmhnQixvQkFDbkIsUUFFRyxJQUFLZ2dCLEVBQW1CdmEsVUFDN0IsSUFFRXVhLEVBQW1CdmEsVUFBWTRrQixpQkFDN0JscUIsR0FBQUEsYUFBYW5ELGdCQUFnQixrQkFBbUIsUUFDaERnakIsRUFBbUJoZ0Isb0JBQ25CLEVBRUgsQ0FBQyxNQUFPMEIsR0FDUFosSUFBSSxFQUFHLDREQUNSLENBSUgsSUFFRWtmLEVBQW1CamdCLFdBQWFELFdBQzlCa2dCLEVBQW1CamdCLFdBQ25CaWdCLEVBQW1CaGdCLG1CQUV0QixDQUFDLE1BQU8wQixHQUNQRCxhQUFhLEVBQUdDLEVBQU8sOENBR3ZCc2UsRUFBbUJqZ0IsV0FBYSxJQUNqQyxDQUdELElBRUVpZ0IsRUFBbUJ4YSxTQUFXMUYsV0FDNUJrZ0IsRUFBbUJ4YSxTQUNuQndhLEVBQW1CaGdCLG9CQUNuQixFQUVILENBQUMsTUFBTzBCLEdBQ1BELGFBQWEsRUFBR0MsRUFBTyw0Q0FHdkJzZSxFQUFtQnhhLFNBQVcsSUFDL0IsQ0FHRyxDQUFDLFVBQU1qRSxHQUFXM0UsU0FBU29qQixFQUFtQmpnQixhQUNoRGUsSUFBSSxFQUFHLHVEQUlMLENBQUMsVUFBTVMsR0FBVzNFLFNBQVNvakIsRUFBbUJ4YSxXQUNoRDFFLElBQUksRUFBRyxxREFJTCxDQUFDLFVBQU1TLEdBQVczRSxTQUFTb2pCLEVBQW1CdmEsWUFDaEQzRSxJQUFJLEVBQUcscURBRWIsTUFJSSxHQUNFa2YsRUFBbUJ4YSxVQUNuQndhLEVBQW1CdmEsV0FDbkJ1YSxFQUFtQmpnQixXQVFuQixNQUxBaWdCLEVBQW1CeGEsU0FBVyxLQUM5QndhLEVBQW1CdmEsVUFBWSxLQUMvQnVhLEVBQW1CamdCLFdBQWEsS0FHMUIsSUFBSW1aLFlBQ1Isb0dBQ0EsSUFJUixDQWtCQSxTQUFTbVIsaUJBQ1A1a0IsRUFBWSxLQUNaekYsRUFDQXVGLEdBR0EsTUFBTStrQixFQUFlLENBQUMsS0FBTSxNQUFPLFNBRW5DLElBQUlDLEVBQW1COWtCLEVBQ25CK2tCLEdBQW1CLEVBR3ZCLEdBQUl4cUIsR0FBc0J5RixFQUFVdkYsU0FBUyxTQUMzQyxJQUNFcXFCLEVBQW1COVQsZ0JBQ2pCdFcsR0FBQUEsYUFBYW5ELGdCQUFnQnlJLEdBQVksU0FDekMsRUFDQUYsRUFFUixDQUFNLE1BQ0EsT0FBTyxJQUNSLE1BR0RnbEIsRUFBbUI5VCxnQkFBZ0JoUixHQUFXLEVBQU9GLEdBR2pEZ2xCLElBQXFCdnFCLFVBQ2hCdXFCLEVBQWlCNWUsTUFLNUIsSUFBSyxNQUFNOGUsS0FBWUYsRUFDaEJELEVBQWExdEIsU0FBUzZ0QixHQUVmRCxJQUNWQSxHQUFtQixVQUZaRCxFQUFpQkUsR0FPNUIsT0FBS0QsR0FLREQsRUFBaUI1ZSxRQUNuQjRlLEVBQWlCNWUsTUFBUTRlLEVBQWlCNWUsTUFBTXhKLEtBQUsxRCxHQUFTQSxFQUFLSixXQUM5RGtzQixFQUFpQjVlLE9BQVM0ZSxFQUFpQjVlLE1BQU0vTSxRQUFVLFdBQ3ZEMnJCLEVBQWlCNWUsT0FLckI0ZSxHQVpFLElBYVgsQ0FtQkEsU0FBU2Isc0JBQ1A1SCxFQUNBOWhCLEVBQ0F1RixHQUdBLENBQUMsZ0JBQWlCLGdCQUFnQnVELFNBQVM0aEIsSUFDekMsSUFFTTVJLEVBQWM0SSxLQUdkMXFCLEdBQ3NDLGlCQUEvQjhoQixFQUFjNEksSUFDckI1SSxFQUFjNEksR0FBYXhxQixTQUFTLFNBR3BDNGhCLEVBQWM0SSxHQUFlalUsZ0JBQzNCdFcsR0FBQUEsYUFBYW5ELGdCQUFnQjhrQixFQUFjNEksSUFBZSxTQUMxRCxFQUNBbmxCLEdBSUZ1YyxFQUFjNEksR0FBZWpVLGdCQUMzQnFMLEVBQWM0SSxJQUNkLEVBQ0FubEIsR0FJUCxDQUFDLE1BQU83RCxHQUNQRCxhQUNFLEVBQ0FDLEVBQ0EsaUJBQWlCZ3BCLHlCQUluQjVJLEVBQWM0SSxHQUFlLElBQzlCLEtBSUMsQ0FBQyxVQUFNbnBCLEdBQVczRSxTQUFTa2xCLEVBQWMzYyxnQkFDM0NyRSxJQUFJLEVBQUcsMERBSUwsQ0FBQyxVQUFNUyxHQUFXM0UsU0FBU2tsQixFQUFjMWMsZUFDM0N0RSxJQUFJLEVBQUcsd0RBRVgsQ0M1ekJBLE1BQU02cEIsU0FBVyxHQVNWLFNBQVNDLFNBQVMvSyxHQUN2QjhLLFNBQVMzb0IsS0FBSzZkLEVBQ2hCLENBUU8sU0FBU2dMLGlCQUNkL3BCLElBQUksRUFBRywyREFDUCxJQUFLLE1BQU0rZSxLQUFNOEssU0FDZkcsY0FBY2pMLEdBQ2RrTCxhQUFhbEwsRUFFakIsQ0NmQSxTQUFTbUwsbUJBQW1CdHBCLEVBQU91cEIsRUFBU3RTLEVBQVV1UyxHQVVwRCxPQVJBenBCLGFBQWEsRUFBR0MsR0FHbUIsZ0JBQS9CMFQsYUFBYXpOLE1BQU1DLGdCQUNkbEcsRUFBTUssTUFJUm1wQixFQUFLeHBCLEVBQ2QsQ0FZQSxTQUFTeXBCLHNCQUFzQnpwQixFQUFPdXBCLEVBQVN0UyxFQUFVdVMsR0FFdkQsTUFBTXJwQixRQUFFQSxFQUFPRSxNQUFFQSxHQUFVTCxFQUdyQjBYLEVBQWExWCxFQUFNMFgsWUFBYyxJQUd2Q1QsRUFBU3lTLE9BQU9oUyxHQUFZaVMsS0FBSyxDQUFFalMsYUFBWXZYLFVBQVNFLFNBQzFELENBT2UsU0FBU3VwQixnQkFBZ0JDLEdBRXRDQSxFQUFJQyxJQUFJUixvQkFHUk8sRUFBSUMsSUFBSUwsc0JBQ1YsQ0MxQ2UsU0FBU00sdUJBQ3RCRixFQUNBRyxFQUFzQnRXLGFBQWF2UCxPQUFPUSxjQUUxQyxJQUVFLEdBQUlxbEIsRUFBb0I1bEIsT0FBUSxDQUM5QixNQUFNNmxCLEVBQ0oseUVBR0lDLEVBQWMsQ0FDbEIxbUIsSUFBS3dtQixFQUFvQnBsQixhQUFlLEdBQ3hDQyxPQUFRbWxCLEVBQW9CbmxCLFFBQVUsRUFDdENDLE1BQU9rbEIsRUFBb0JsbEIsT0FBUyxFQUNwQ0MsV0FBWWlsQixFQUFvQmpsQixhQUFjLEVBQzlDQyxRQUFTZ2xCLEVBQW9CaGxCLFVBQVcsRUFDeENDLFVBQVcra0IsRUFBb0Iva0IsWUFBYSxHQUkxQ2lsQixFQUFZbmxCLFlBQ2Q4a0IsRUFBSXpsQixPQUFPLGVBSWIsTUFBTStsQixFQUFVQyxVQUFVLENBQ3hCQyxTQUErQixHQUFyQkgsRUFBWXJsQixPQUFjLElBRXBDckIsSUFBSzBtQixFQUFZMW1CLElBRWpCOG1CLFFBQVNKLEVBQVlwbEIsTUFDckJ5bEIsUUFBUyxDQUFDaEIsRUFBU3RTLEtBQ2pCQSxFQUFTdVQsT0FBTyxDQUNkYixLQUFNLEtBQ0oxUyxFQUFTeVMsT0FBTyxLQUFLZSxLQUFLLENBQUV0cUIsUUFBUzhwQixHQUFNLEVBRTdDUyxRQUFTLEtBQ1B6VCxFQUFTeVMsT0FBTyxLQUFLZSxLQUFLUixFQUFJLEdBRWhDLEVBRUpVLEtBQU9wQixJQUdxQixJQUF4QlcsRUFBWWxsQixVQUNjLElBQTFCa2xCLEVBQVlqbEIsV0FDWnNrQixFQUFRcUIsTUFBTXB3QixNQUFRMHZCLEVBQVlsbEIsU0FDbEN1a0IsRUFBUXFCLE1BQU1DLGVBQWlCWCxFQUFZamxCLFlBRTNDN0YsSUFBSSxFQUFHLDJDQUNBLEtBT2J5cUIsRUFBSUMsSUFBSUssR0FFUi9xQixJQUNFLEVBQ0EsOENBQThDOHFCLEVBQVkxbUIsb0JBQW9CMG1CLEVBQVlybEIsOENBQThDcWxCLEVBQVlubEIsY0FFdkosQ0FDRixDQUFDLE1BQU8vRSxHQUNQLE1BQU0sSUFBSXdYLFlBQ1IseUVBQ0EsS0FDQUksU0FBUzVYLEVBQ1osQ0FDSCxDQ3pGQSxNQUFNOHFCLGtCQUFrQnRULFlBUXRCLFdBQUFDLENBQVl0WCxFQUFTdVgsR0FDbkJDLE1BQU14WCxFQUFTdVgsRUFDaEIsQ0FTRCxTQUFBcVQsQ0FBVXJULEdBR1IsT0FGQTdOLEtBQUs2TixXQUFhQSxFQUVYN04sSUFDUixFQ1dILFNBQVNtaEIsc0JBQXNCekIsRUFBU3RTLEVBQVV1UyxHQUNoRCxJQUVFLE1BQU15QixFQUFjMUIsRUFBUTJCLFFBQVEsaUJBQW1CLEdBR3ZELElBQ0dELEVBQVkvdkIsU0FBUyxzQkFDckIrdkIsRUFBWS92QixTQUFTLHVDQUNyQit2QixFQUFZL3ZCLFNBQVMsdUJBRXRCLE1BQU0sSUFBSTR2QixVQUNSLGlIQUNBLEtBS0osT0FBT3RCLEdBQ1IsQ0FBQyxNQUFPeHBCLEdBQ1AsT0FBT3dwQixFQUFLeHBCLEVBQ2IsQ0FDSCxDQW1CQSxTQUFTbXJCLHNCQUFzQjVCLEVBQVN0UyxFQUFVdVMsR0FDaEQsSUFFRSxNQUFNdkwsRUFBT3NMLEVBQVF0TCxLQUdmdFMsRUFBWUMsS0FBQUEsS0FBTzNRLFFBQVEsS0FBTSxJQUd2QyxJQUFLZ2pCLEdBQVFqaEIsY0FBY2loQixHQVF6QixNQVBBN2UsSUFDRSxFQUNBLHlCQUF5QnVNLHlCQUN2QjRkLEVBQVEyQixRQUFRLG9CQUFzQjNCLEVBQVE2QixXQUFXQywyREFJdkQsSUFBSVAsVUFDUixzS0FDQSxLQUtKLE1BQU1qbkIsRUFBcUI4akIsd0JBR3JCbGxCLEVBQVFzUyxnQkFFWmtKLEVBQUt4YixPQUFTd2IsRUFBS3ZiLFNBQVd1YixFQUFLemIsUUFBVXliLEVBQUs1SyxNQUVsRCxFQUVBeFAsR0FJRixHQUFjLE9BQVZwQixJQUFtQndiLEVBQUt0YixJQVExQixNQVBBdkQsSUFDRSxFQUNBLHlCQUF5QnVNLHlCQUN2QjRkLEVBQVEyQixRQUFRLG9CQUFzQjNCLEVBQVE2QixXQUFXQywyRkFDbUJsVyxLQUFLYSxVQUFVaUksT0FHekYsSUFBSTZNLFVBQ1IsaVJBQ0EsS0FLSixHQUFJN00sRUFBS3RiLEtBQU94Rix1QkFBdUI4Z0IsRUFBS3RiLEtBQzFDLE1BQU0sSUFBSW1vQixVQUNSLDRMQUNBLEtBSUosSUFFRXZCLEVBQVErQixpQkFBbUIvWSxjQUFjLENBRXZDMlMsV0FBWXZaLEVBQ1pwSixPQUFRLENBQ05FLFFBQ0FFLElBQUtzYixFQUFLdGIsSUFDVnRILFFBQ0U0aUIsRUFBSzVpQixTQUNMLEdBQUdrdUIsRUFBUW5oQixPQUFPbWpCLFVBQVksV0FBVzl2QixRQUFRd2lCLEVBQUs3aUIsUUFDeERBLEtBQU1LLFFBQVF3aUIsRUFBSzdpQixLQUFNNmlCLEVBQUs1aUIsU0FDOUJQLE9BQVFELFVBQVVvakIsRUFBS25qQixRQUN2QmlJLElBQUtrYixFQUFLbGIsSUFDVkMsV0FBWWliLEVBQUtqYixXQUNqQkMsT0FBUWdiLEVBQUtoYixPQUNiQyxNQUFPK2EsRUFBSy9hLE1BQ1pDLE1BQU84YSxFQUFLOWEsTUFDWk0sY0FBZXNSLGdCQUNia0osRUFBS3hhLGVBQ0wsRUFDQUksR0FFRkgsYUFBY3FSLGdCQUNaa0osRUFBS3ZhLGNBQ0wsRUFDQUcsSUFHSkQsWUFBYSxDQUNYQyxxQkFDQXZGLG9CQUFvQixFQUNwQkQsV0FBWTRmLEVBQUs1ZixXQUNqQnlGLFNBQVVtYSxFQUFLbmEsU0FDZkMsVUFBV2dSLGdCQUFnQmtKLEVBQUtsYSxXQUFXLEVBQU1GLEtBR3RELENBQUMsTUFBTzdELEdBT1AsTUFOQU8sYUFDRSxFQUNBUCxFQUFNUSxPQUNOLDZDQUdJLElBQUlzcUIsVUFDUiwyRkFDQSxJQUVILENBR0QsT0FBT3RCLEdBQ1IsQ0FBQyxNQUFPeHBCLEdBQ1AsT0FBT3dwQixFQUFLeHBCLEVBQ2IsQ0FDSCxDQU9lLFNBQVN3ckIscUJBQXFCM0IsR0FFM0NBLEVBQUk0QixLQUFLLENBQUMsSUFBSyxjQUFlVCx1QkFHOUJuQixFQUFJNEIsS0FBSyxDQUFDLElBQUssY0FBZU4sc0JBQ2hDLENDaE1BLE1BQU1PLGFBQWUsQ0FDbkJDLElBQUssWUFDTEMsS0FBTSxhQUNOQyxJQUFLLFlBQ0wvSSxJQUFLLGtCQUNMbmdCLElBQUssaUJBZ0JQNlQsZUFBZXNWLGNBQWN2QyxFQUFTdFMsRUFBVXVTLEdBQzlDLElBRUUsTUFBTXVDLEVBQWlCeHVCLGNBR3ZCLElBQUl5dUIsR0FBb0IsRUFDeEJ6QyxFQUFRMEMsT0FBTzlVLEdBQUcsU0FBVStVLElBQ3RCQSxJQUNGRixHQUFvQixFQUNyQixJQUlILE1BQU1yVixFQUFpQjRTLEVBQVErQixpQkFHekIzZixFQUFZZ0wsRUFBZXVPLFdBR2pDOWxCLElBQUksRUFBRyxpREFBaUR1TSxZQUdsRHFiLFlBQVlyUSxHQUFnQixDQUFDM1csRUFBT3FULEtBS3hDLEdBSEFrVyxFQUFRMEMsT0FBT3ZGLG1CQUFtQixTQUc5QnNGLEVBQ0Y1c0IsSUFDRSxFQUNBLHFCQUFxQnVNLG1GQUh6QixDQVNBLEdBQUkzTCxFQUNGLE1BQU1BLEVBSVIsSUFBS3FULElBQVNBLEVBQUtvTyxPQVNqQixNQVJBcmlCLElBQ0UsRUFDQSxxQkFBcUJ1TSxxQkFDbkI0ZCxFQUFRMkIsUUFBUSxvQkFDaEIzQixFQUFRNkIsV0FBV0MsbURBQ2lCaFksRUFBS29PLFdBR3ZDLElBQUlxSixVQUNSLDZHQUNBLEtBS0osR0FBSXpYLEVBQUtvTyxPQUFRLENBQ2ZyaUIsSUFDRSxFQUNBLHFCQUFxQnVNLHlDQUFpRG9nQixVQUl4RSxNQUFNM3dCLEtBQUVBLEVBQUkySCxJQUFFQSxFQUFHQyxXQUFFQSxFQUFVM0gsUUFBRUEsR0FBWWdZLEVBQUszUSxRQUFRSCxPQUd4RCxPQUFJUSxFQUNLa1UsRUFBU3dULEtBQUtydUIsVUFBVWlYLEVBQUtvTyxPQUFRcm1CLEtBSTlDNmIsRUFBU2tWLE9BQU8sZUFBZ0JULGFBQWF0d0IsSUFBUyxhQUdqRDRILEdBQ0hpVSxFQUFTbVYsV0FBVy93QixHQUlOLFFBQVRELEVBQ0g2YixFQUFTd1QsS0FBS3BYLEVBQUtvTyxRQUNuQnhLLEVBQVN3VCxLQUFLbnVCLE9BQU9DLEtBQUs4VyxFQUFLb08sT0FBUSxXQUM1QyxDQWxEQSxDQWtEQSxHQUVKLENBQUMsTUFBT3poQixHQUNQLE9BQU93cEIsRUFBS3hwQixFQUNiLENBQ0gsQ0FTZSxTQUFTcXNCLGFBQWF4QyxHQUtuQ0EsRUFBSTRCLEtBQUssSUFBS0ssZUFNZGpDLEVBQUk0QixLQUFLLGFBQWNLLGNBQ3pCLENDcElBLE1BQU1RLGdCQUFrQixJQUFJNXZCLEtBR3RCNnZCLFlBQWNwWCxLQUFLaEQsTUFBTTFULEdBQVlBLGFBQUN0QyxLQUFJQSxLQUFDN0MsWUFBVyxrQkFHdERrekIsYUFBZSxHQUdmQyxlQUFpQixJQUdqQkMsV0FBYSxHQVVuQixTQUFTQywwQkFDUCxPQUFPSCxhQUFhNVgsUUFBTyxDQUFDZ1ksRUFBR0MsSUFBTUQsRUFBSUMsR0FBRyxHQUFLTCxhQUFhdHZCLE1BQ2hFLENBVUEsU0FBUzR2QixvQkFDUCxPQUFPQyxhQUFZLEtBQ2pCLE1BQU1DLEVBQVExSCxlQUNSMkgsRUFDdUIsSUFBM0JELEVBQU1oSyxpQkFDRixFQUNDZ0ssRUFBTS9KLGlCQUFtQitKLEVBQU1oSyxpQkFBb0IsSUFFMUR3SixhQUFhbHNCLEtBQUsyc0IsR0FDZFQsYUFBYXR2QixPQUFTd3ZCLFlBQ3hCRixhQUFhaHhCLE9BQ2QsR0FDQWl4QixlQUNMLENBU2UsU0FBU1MsYUFBYXJELEdBR25DWCxTQUFTNEQscUJBS1RqRCxFQUFJN1MsSUFBSSxXQUFXLENBQUN1UyxFQUFTdFMsRUFBVXVTLEtBQ3JDLElBQ0VwcUIsSUFBSSxFQUFHLHFDQUVQLE1BQU00dEIsRUFBUTFILGVBQ1I2SCxFQUFTWCxhQUFhdHZCLE9BQ3RCa3dCLEVBQWdCVCwwQkFHdEIxVixFQUFTd1QsS0FBSyxDQUVaZixPQUFRLEtBQ1IyRCxTQUFVZixnQkFDVmdCLE9BQVEsR0FBR3J2QixLQUFLc3ZCLE9BQU8zd0IsaUJBQW1CMHZCLGdCQUFnQnp2QixXQUFhLElBQU8sY0FHOUUyd0IsY0FBZWpCLFlBQVl6cUIsUUFDM0IyckIsa0JBQW1CdFUsdUJBR25CdVUsa0JBQW1CVixFQUFNeEosaUJBQ3pCbUssaUJBQWtCWCxFQUFNaEssaUJBQ3hCNEssaUJBQWtCWixFQUFNL0osaUJBQ3hCNEssY0FBZWIsRUFBTTlKLGVBQ3JCNEssWUFBY2QsRUFBTS9KLGlCQUFtQitKLEVBQU1oSyxpQkFBb0IsSUFHakUzZCxLQUFNa2dCLGtCQUdONEgsU0FDQUMsZ0JBQ0FqdEIsUUFDRThJLE1BQU1ta0IsS0FBbUJaLGFBQWF0dkIsT0FDbEMsb0VBQ0EsUUFBUWl3QixtQ0FBd0NDLEVBQWNXLFFBQVEsT0FHNUVDLFdBQVloQixFQUFNN0osZUFDbEI4SyxZQUFhakIsRUFBTTVKLG1CQUNuQjhLLG1CQUFvQmxCLEVBQU0zSix1QkFDMUI4SyxvQkFBcUJuQixFQUFNMUosNEJBRTlCLENBQUMsTUFBT3RqQixHQUNQLE9BQU93cEIsRUFBS3hwQixFQUNiLElBRUwsQ0M3R2UsU0FBU291QixTQUFTdkUsR0FJL0JBLEVBQUk3UyxJQUFJdEQsYUFBYTNOLEdBQUdDLE9BQVMsS0FBSyxDQUFDdWpCLEVBQVN0UyxFQUFVdVMsS0FDeEQsSUFDRXZTLEVBQVNvWCxTQUFTbHlCLEtBQUlBLEtBQUM3QyxZQUFXLFNBQVUsY0FBZSxDQUN6RGcxQixjQUFjLEdBRWpCLENBQUMsTUFBT3R1QixHQUNQLE9BQU93cEIsRUFBS3hwQixFQUNiLElBRUwsQ0NiZSxTQUFTdXVCLG9CQUFvQjFFLEdBSzFDQSxFQUFJNEIsS0FBSywrQkFBK0JqVixNQUFPK1MsRUFBU3RTLEVBQVV1UyxLQUNoRSxJQUVFLE1BQU05ZixFQUFhd0ksS0FBSy9FLHVCQUd4QixJQUFLekQsSUFBZUEsRUFBV3hNLE9BQzdCLE1BQU0sSUFBSTR0QixVQUNSLGlIQUNBLEtBS0osTUFBTTBELEVBQVFqRixFQUFRdlMsSUFBSSxXQUcxQixJQUFLd1gsR0FBU0EsSUFBVTlrQixFQUN0QixNQUFNLElBQUlvaEIsVUFDUiwyRUFDQSxLQUtKLE1BQU16UixFQUFha1EsRUFBUW5oQixPQUFPaVIsV0FDbEMsSUFBSUEsRUFtQkYsTUFBTSxJQUFJeVIsVUFBVSxxQ0FBc0MsS0FsQjFELFVBRVExUix3QkFBd0JDLEVBQy9CLENBQUMsTUFBT3JaLEdBQ1AsTUFBTSxJQUFJOHFCLFVBQ1IsNkJBQTZCOXFCLEVBQU1HLFVBQ25DLEtBQ0F5WCxTQUFTNVgsRUFDWixDQUdEaVgsRUFBU3lTLE9BQU8sS0FBS2UsS0FBSyxDQUN4Qi9TLFdBQVksSUFDWitWLGtCQUFtQnRVLHVCQUNuQmhaLFFBQVMsK0NBQStDa1osTUFNN0QsQ0FBQyxNQUFPclosR0FDUCxPQUFPd3BCLEVBQUt4cEIsRUFDYixJQUVMLENDdkNBLE1BQU15dUIsY0FBZ0IsSUFBSUMsSUFHcEI3RSxJQUFNOEUsVUFxQkxuWSxlQUFlb1ksWUFBWUMsRUFBZ0JuYixhQUFhdlAsUUFDN0QsSUFFRSxJQUFLMHFCLEVBQWN6cUIsU0FBV3lsQixJQUM1QixNQUFNLElBQUlyUyxZQUNSLG1GQUNBLEtBTUosTUFBTXNYLEVBQStDLEtBQTVCRCxFQUFjdHFCLFlBQXFCLEtBR3REd3FCLEVBQVVDLE9BQU9DLGdCQUdqQkMsRUFBU0YsT0FBTyxDQUNwQkQsVUFDQUksT0FBUSxDQUNOQyxVQUFXTixLQTJDZixHQXRDQWpGLElBQUl3RixRQUFRLGdCQUdaeEYsSUFBSUMsSUFDRndGLEtBQUssQ0FDSEMsUUFBUyxDQUFDLE9BQVEsTUFBTyxjQU03QjFGLElBQUlDLEtBQUksQ0FBQ1AsRUFBU3RTLEVBQVV1UyxLQUMxQnZTLEVBQVN1WSxJQUFJLGdCQUFpQixRQUM5QmhHLEdBQU0sSUFJUkssSUFBSUMsSUFDRjZFLFFBQVFoRixLQUFLLENBQ1g4RixNQUFPWCxLQUtYakYsSUFBSUMsSUFDRjZFLFFBQVFlLFdBQVcsQ0FDakJDLFVBQVUsRUFDVkYsTUFBT1gsS0FLWGpGLElBQUlDLElBQUlvRixFQUFPVSxRQUdmL0YsSUFBSUMsSUFBSTZFLFFBQVFrQixPQUFPMXpCLEtBQUlBLEtBQUM3QyxZQUFXLGFBR2xDdTFCLEVBQWMzcEIsSUFBSUMsTUFBTyxDQUU1QixNQUFNMnFCLEVBQWF2WSxLQUFLd1ksYUFBYWxHLEtBR3JDbUcsMkJBQTJCRixHQUczQkEsRUFBV0csT0FBT3BCLEVBQWN2cUIsS0FBTXVxQixFQUFjeHFCLE1BQU0sS0FFeERvcUIsY0FBY2UsSUFBSVgsRUFBY3ZxQixLQUFNd3JCLEdBRXRDMXdCLElBQ0UsRUFDQSxtQ0FBbUN5dkIsRUFBY3hxQixRQUFRd3FCLEVBQWN2cUIsUUFDeEUsR0FFSixDQUdELEdBQUl1cUIsRUFBYzNwQixJQUFJZCxPQUFRLENBRTVCLElBQUk1SixFQUFLMDFCLEVBRVQsSUFFRTExQixRQUFZMjFCLFNBQVFBLFNBQ2xCaDBCLEtBQUlBLEtBQUNiLGdCQUFnQnV6QixFQUFjM3BCLElBQUlFLFVBQVcsY0FDbEQsUUFJRjhxQixRQUFhQyxTQUFRQSxTQUNuQmgwQixLQUFJQSxLQUFDYixnQkFBZ0J1ekIsRUFBYzNwQixJQUFJRSxVQUFXLGNBQ2xELE9BRUgsQ0FBQyxNQUFPcEYsR0FDUFosSUFDRSxFQUNBLHFEQUFxRHl2QixFQUFjM3BCLElBQUlFLHNEQUUxRSxDQUVELEdBQUk1SyxHQUFPMDFCLEVBQU0sQ0FFZixNQUFNRSxFQUFjOVksTUFBTXlZLGFBQWEsQ0FBRXYxQixNQUFLMDFCLFFBQVFyRyxLQUd0RG1HLDJCQUEyQkksR0FHM0JBLEVBQVlILE9BQU9wQixFQUFjM3BCLElBQUlaLEtBQU11cUIsRUFBY3hxQixNQUFNLEtBRTdEb3FCLGNBQWNlLElBQUlYLEVBQWMzcEIsSUFBSVosS0FBTThyQixHQUUxQ2h4QixJQUNFLEVBQ0Esb0NBQW9DeXZCLEVBQWN4cUIsUUFBUXdxQixFQUFjM3BCLElBQUlaLFFBQzdFLEdBRUosQ0FDRixDQUdEeWxCLHVCQUF1QkYsSUFBS2dGLEVBQWNscUIsY0FHMUM2bUIscUJBQXFCM0IsS0FHckJxRCxhQUFhckQsS0FDYndDLGFBQWF4QyxLQUNidUUsU0FBU3ZFLEtBQ1QwRSxvQkFBb0IxRSxLQUdwQkQsZ0JBQWdCQyxJQUNqQixDQUFDLE1BQU83cEIsR0FDUCxNQUFNLElBQUl3WCxZQUNSLHFEQUNBLEtBQ0FJLFNBQVM1WCxFQUNaLENBQ0gsQ0FPTyxTQUFTcXdCLGVBRWQsR0FBSTVCLGNBQWNqTyxLQUFPLEVBQUcsQ0FDMUJwaEIsSUFBSSxFQUFHLGlDQUdQLElBQUssTUFBT2tGLEVBQU1ILEtBQVdzcUIsY0FDM0J0cUIsRUFBT2laLE9BQU0sS0FDWHFSLGNBQWM2QixPQUFPaHNCLEdBQ3JCbEYsSUFBSSxFQUFHLG1DQUFtQ2tGLEtBQVEsR0FHdkQsQ0FDSCxDQVNPLFNBQVNpc0IsYUFDZCxPQUFPOUIsYUFDVCxDQVNPLFNBQVMrQixhQUNkLE9BQU83QixPQUNULENBU08sU0FBUzhCLFNBQ2QsT0FBTzVHLEdBQ1QsQ0FVTyxTQUFTbmYsbUJBQW1Cc2YsR0FDakNELHVCQUF1QkYsSUFBS0csRUFDOUIsQ0FVTyxTQUFTRixJQUFJN3RCLEtBQVN5MEIsR0FDM0I3RyxJQUFJQyxJQUFJN3RCLEtBQVN5MEIsRUFDbkIsQ0FVTyxTQUFTMVosSUFBSS9hLEtBQVN5MEIsR0FDM0I3RyxJQUFJN1MsSUFBSS9hLEtBQVN5MEIsRUFDbkIsQ0FVTyxTQUFTakYsS0FBS3h2QixLQUFTeTBCLEdBQzVCN0csSUFBSTRCLEtBQUt4dkIsS0FBU3kwQixFQUNwQixDQVNBLFNBQVNWLDJCQUEyQjdyQixHQUNsQ0EsRUFBT2dULEdBQUcsZUFBZSxDQUFDblgsRUFBT2lzQixLQUMvQmxzQixhQUNFLEVBQ0FDLEVBQ0EsMEJBQTBCQSxFQUFNRywrQkFFbEM4ckIsRUFBT3hNLFNBQVMsSUFHbEJ0YixFQUFPZ1QsR0FBRyxTQUFVblgsSUFDbEJELGFBQWEsRUFBR0MsRUFBTywwQkFBMEJBLEVBQU1HLFVBQVUsSUFHbkVnRSxFQUFPZ1QsR0FBRyxjQUFlOFUsSUFDdkJBLEVBQU85VSxHQUFHLFNBQVVuWCxJQUNsQkQsYUFBYSxFQUFHQyxFQUFPLDBCQUEwQkEsRUFBTUcsVUFBVSxHQUNqRSxHQUVOLENBRUEsSUFBZWdFLE9BQUEsQ0FDYnlxQix3QkFDQXlCLDBCQUNBRSxzQkFDQUMsc0JBQ0FDLGNBQ0EvbEIsc0NBQ0FvZixRQUNBOVMsUUFDQXlVLFdDeFVLalYsZUFBZW1hLGdCQUFnQkMsU0FFOUJoYSxRQUFReVEsV0FBVyxDQUV2QjhCLGlCQUdBa0gsZUFHQTNMLGFBSUZqbkIsUUFBUW96QixLQUFLRCxFQUNmLENDaUJPcGEsZUFBZXNhLFdBQVdqZCxHQUUvQixNQUFNblIsRUFBVTJSLGFBQWFYLFlBQVcsR0FBUUcsR0FHaEQrVCxzQkFBc0JsbEIsRUFBUWtCLFlBQVlDLG9CQUcxQ2xELFlBQVkrQixFQUFROUQsU0FHaEI4RCxFQUFRdUQsTUFBTUUsc0JBQ2hCNHFCLG9DQUlJOVksb0JBQW9CdlYsRUFBUWIsV0FBWWEsRUFBUXlCLE9BQU9NLGFBR3ZEZ2YsU0FBUy9nQixFQUFRMkMsS0FBTTNDLEVBQVFwQixVQUFVakMsS0FDakQsQ0FTQSxTQUFTMHhCLDhCQUNQM3hCLElBQUksRUFBRyxzREFHUDNCLFFBQVEwWixHQUFHLFFBQVNyRSxJQUNsQjFULElBQUksRUFBRyxzQ0FBc0MwVCxLQUFRLElBSXZEclYsUUFBUTBaLEdBQUcsVUFBVVgsTUFBTy9ELEVBQU1LLEtBQ2hDMVQsSUFBSSxFQUFHLGlCQUFpQnFULHNCQUF5QkssWUFDM0M2ZCxnQkFBZ0IsRUFBRSxJQUkxQmx6QixRQUFRMFosR0FBRyxXQUFXWCxNQUFPL0QsRUFBTUssS0FDakMxVCxJQUFJLEVBQUcsaUJBQWlCcVQsc0JBQXlCSyxZQUMzQzZkLGdCQUFnQixFQUFFLElBSTFCbHpCLFFBQVEwWixHQUFHLFVBQVVYLE1BQU8vRCxFQUFNSyxLQUNoQzFULElBQUksRUFBRyxpQkFBaUJxVCxzQkFBeUJLLFlBQzNDNmQsZ0JBQWdCLEVBQUUsSUFJMUJsekIsUUFBUTBaLEdBQUcscUJBQXFCWCxNQUFPeFcsRUFBT3lTLEtBQzVDMVMsYUFBYSxFQUFHQyxFQUFPLGlCQUFpQnlTLGtCQUNsQ2tlLGdCQUFnQixFQUFFLEdBRTVCLENBRUEsSUFBZW5kLE1BQUEsQ0FFYnJQLGNBQ0F5cUIsd0JBR0FsYixzQkFDQUUsc0JBQ0FTLDBCQUNBSSxnQ0FHQXFjLHNCQUNBL0osMEJBQ0FFLHdCQUNBRCx3QkFHQS9PLHdDQUdBd0wsa0JBQ0FpQixrQkFHQXRsQixRQUNBVywwQkFDQVEsMEJBQ0FRLHdCQUNBQywwQ0FDQUMsb0NBR0EwdkIifQ== diff --git a/dist/index.esm.js b/dist/index.esm.js index 4d431f23..da49e7bb 100644 --- a/dist/index.esm.js +++ b/dist/index.esm.js @@ -1,2 +1,2 @@ -import"colors";import{readFileSync,existsSync,mkdirSync,appendFile,writeFileSync}from"fs";import{isAbsolute,join}from"path";import{HttpsProxyAgent}from"https-proxy-agent";import{fileURLToPath}from"url";import dotenv from"dotenv";import{z}from"zod";import http from"http";import https from"https";import{Pool}from"tarn";import{v4}from"uuid";import puppeteer from"puppeteer";import DOMPurify from"dompurify";import{JSDOM}from"jsdom";import{readFile}from"fs/promises";import cors from"cors";import express from"express";import multer from"multer";import rateLimit from"express-rate-limit";const __dirname=fileURLToPath(new URL("../.",import.meta.url));function deepCopy(e){if(null===e||"object"!=typeof e)return e;const t=Array.isArray(e)?[]:{};for(const o in e)Object.prototype.hasOwnProperty.call(e,o)&&(t[o]=deepCopy(e[o]));return t}function fixConstr(e){try{const t=`${e.toLowerCase().replace("chart","")}Chart`;return"Chart"===t&&t.toLowerCase(),["chart","stockChart","mapChart","ganttChart"].includes(t)?t:"chart"}catch{return"chart"}}function fixOutfile(e,t){return`${getAbsolutePath(t||"chart").split(".").shift()}.${e}`}function fixType(e,t=null){const o={"image/png":"png","image/jpeg":"jpeg","application/pdf":"pdf","image/svg+xml":"svg"},r=Object.values(o);if(t){const o=t.split(".").pop();"jpg"===o?e="jpeg":r.includes(o)&&e!==o&&(e=o)}return o[e]||r.find((t=>t===e))||"png"}function getAbsolutePath(e){return isAbsolute(e)?e:join(__dirname,e)}function getBase64(e,t){return"pdf"===t||"svg"==t?Buffer.from(e,"utf8").toString("base64"):e}function getNewDate(){return(new Date).toString().split("(")[0].trim()}function getNewDateTime(){return(new Date).getTime()}function isObject(e){return"[object Object]"===Object.prototype.toString.call(e)}function isObjectEmpty(e){return"object"==typeof e&&!Array.isArray(e)&&null!==e&&0===Object.keys(e).length}function isPrivateRangeUrlFound(e){return[/xlink:href="(?:http:\/\/|https:\/\/)?localhost\b/,/xlink:href="(?:http:\/\/|https:\/\/)?10\.\d{1,3}\.\d{1,3}\.\d{1,3}\b/,/xlink:href="(?:http:\/\/|https:\/\/)?127\.\d{1,3}\.\d{1,3}\.\d{1,3}\b/,/xlink:href="(?:http:\/\/|https:\/\/)?172\.(1[6-9]|2[0-9]|3[0-1])\.\d{1,3}\.\d{1,3}\b/,/xlink:href="(?:http:\/\/|https:\/\/)?192\.168\.\d{1,3}\.\d{1,3}\b/].some((t=>t.test(e)))}function measureTime(){const e=process.hrtime.bigint();return()=>Number(process.hrtime.bigint()-e)/1e6}function roundNumber(e,t=1){const o=Math.pow(10,t||0);return Math.round(+e*o)/o}function wrapAround(e,t,o=!1){if(e&&"string"==typeof e)return(e=e.trim()).endsWith(".js")?t?wrapAround(readFileSync(getAbsolutePath(e),"utf8"),t,o):null:!o&&(e.startsWith("function()")||e.startsWith("function ()")||e.startsWith("()=>")||e.startsWith("() =>"))?`(${e})()`:e.replace(/;$/,"")}const colors=["red","yellow","blue","gray","green"],logging={toConsole:!0,toFile:!1,pathCreated:!1,pathToLog:"",levelsDesc:[{title:"error",color:colors[0]},{title:"warning",color:colors[1]},{title:"notice",color:colors[2]},{title:"verbose",color:colors[3]},{title:"benchmark",color:colors[4]}]};function log(...e){const[t,...o]=e,{levelsDesc:r,level:n}=logging;if(5!==t&&(0===t||t>n||n>r.length))return;const i=`${getNewDate()} [${r[t-1].title}] -`;logging.toFile&&_logToFile(o,i),logging.toConsole&&console.log.apply(void 0,[i.toString()[logging.levelsDesc[t-1].color]].concat(o))}function logWithStack(e,t,o){const r=o||t.message,{level:n,levelsDesc:i}=logging;if(0===e||e>n||n>i.length)return;const s=`${getNewDate()} [${i[e-1].title}] -`,a=t.stack,l=[r];a&&l.push("\n",a),logging.toFile&&_logToFile(l,s),logging.toConsole&&console.log.apply(void 0,[s.toString()[logging.levelsDesc[e-1].color]].concat([l.shift()[colors[e-1]],...l]))}function initLogging(e){const{level:t,dest:o,file:r,toConsole:n,toFile:i}=e;setLogLevel(t),enableConsoleLogging(n),enableFileLogging(o,r,i)}function setLogLevel(e){e>=0&&e<=logging.levelsDesc.length&&(logging.level=e)}function enableConsoleLogging(e){logging.toConsole=e}function enableFileLogging(e,t,o){logging.toFile=o,o&&(logging.dest=e,logging.file=t)}function _logToFile(e,t){logging.pathCreated||(!existsSync(getAbsolutePath(logging.dest))&&mkdirSync(getAbsolutePath(logging.dest)),logging.pathToLog=getAbsolutePath(join(logging.dest,logging.file)),logging.pathCreated=!0),appendFile(logging.pathToLog,[t].concat(e).join(" ")+"\n",(e=>{e&&logging.toFile&&logging.pathCreated&&(logging.toFile=!1,logging.pathCreated=!1,logWithStack(2,e,"[logger] Unable to write to log file."))}))}const defaultConfig={puppeteer:{args:{value:["--allow-running-insecure-content","--ash-no-nudges","--autoplay-policy=user-gesture-required","--block-new-web-contents","--disable-accelerated-2d-canvas","--disable-background-networking","--disable-background-timer-throttling","--disable-backgrounding-occluded-windows","--disable-breakpad","--disable-checker-imaging","--disable-client-side-phishing-detection","--disable-component-extensions-with-background-pages","--disable-component-update","--disable-default-apps","--disable-dev-shm-usage","--disable-domain-reliability","--disable-extensions","--disable-features=CalculateNativeWinOcclusion,InterestFeedContentSuggestions,WebOTP","--disable-hang-monitor","--disable-ipc-flooding-protection","--disable-logging","--disable-notifications","--disable-offer-store-unmasked-wallet-cards","--disable-popup-blocking","--disable-print-preview","--disable-prompt-on-repost","--disable-renderer-backgrounding","--disable-search-engine-choice-screen","--disable-session-crashed-bubble","--disable-setuid-sandbox","--disable-site-isolation-trials","--disable-speech-api","--disable-sync","--enable-unsafe-webgpu","--hide-crash-restore-bubble","--hide-scrollbars","--metrics-recording-only","--mute-audio","--no-default-browser-check","--no-first-run","--no-pings","--no-sandbox","--no-startup-window","--no-zygote","--password-store=basic","--process-per-tab","--use-mock-keychain"],types:["string[]"],envLink:"PUPPETEER_ARGS",cliName:"puppeteerArgs",description:"Array of Puppeteer arguments",promptOptions:{type:"list",separator:";"}}},highcharts:{version:{value:"latest",types:["string"],envLink:"HIGHCHARTS_VERSION",description:"Highcharts version",promptOptions:{type:"text"}},cdnUrl:{value:"https://code.highcharts.com",types:["string"],envLink:"HIGHCHARTS_CDN_URL",description:"CDN URL for Highcharts scripts",promptOptions:{type:"text"}},forceFetch:{value:!1,types:["boolean"],envLink:"HIGHCHARTS_FORCE_FETCH",description:"Flag to refetch scripts after each server rerun",promptOptions:{type:"toggle"}},cachePath:{value:".cache",types:["string"],envLink:"HIGHCHARTS_CACHE_PATH",description:"Directory path for cached Highcharts scripts",promptOptions:{type:"text"}},coreScripts:{value:["highcharts","highcharts-more","highcharts-3d"],types:["string[]"],envLink:"HIGHCHARTS_CORE_SCRIPTS",description:"Highcharts core scripts to fetch",promptOptions:{type:"multiselect",instructions:"Space: Select specific, A: Select all, Enter: Confirm"}},moduleScripts:{value:["stock","map","gantt","exporting","parallel-coordinates","accessibility","boost-canvas","boost","data","data-tools","draggable-points","static-scale","broken-axis","heatmap","tilemap","tiledwebmap","timeline","treemap","treegraph","item-series","drilldown","histogram-bellcurve","bullet","funnel","funnel3d","geoheatmap","pyramid3d","networkgraph","overlapping-datalabels","pareto","pattern-fill","pictorial","price-indicator","sankey","arc-diagram","dependency-wheel","series-label","series-on-point","solid-gauge","sonification","streamgraph","sunburst","variable-pie","variwide","vector","venn","windbarb","wordcloud","xrange","no-data-to-display","drag-panes","debugger","dumbbell","lollipop","cylinder","organization","dotplot","marker-clusters","hollowcandlestick","heikinashi","flowmap","export-data","navigator","textpath"],types:["string[]"],envLink:"HIGHCHARTS_MODULE_SCRIPTS",description:"Highcharts module scripts to fetch",promptOptions:{type:"multiselect",instructions:"Space: Select specific, A: Select all, Enter: Confirm"}},indicatorScripts:{value:["indicators-all"],types:["string[]"],envLink:"HIGHCHARTS_INDICATOR_SCRIPTS",description:"Highcharts indicator scripts to fetch",promptOptions:{type:"multiselect",instructions:"Space: Select specific, A: Select all, Enter: Confirm"}},customScripts:{value:["https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.30.1/moment.min.js","https://cdnjs.cloudflare.com/ajax/libs/moment-timezone/0.5.45/moment-timezone-with-data.min.js"],types:["string[]"],envLink:"HIGHCHARTS_CUSTOM_SCRIPTS",description:"Additional custom scripts or dependencies to fetch",promptOptions:{type:"list",separator:";"}}},export:{infile:{value:null,types:["string","null"],envLink:"EXPORT_INFILE",description:"Input filename with type, formatted correctly as JSON or SVG",promptOptions:{type:"text"}},instr:{value:null,types:["string","null"],envLink:"EXPORT_INSTR",description:"Overrides the `infile` with JSON, stringified JSON, or SVG input",promptOptions:{type:"text"}},options:{value:null,types:["Object","null"],envLink:"EXPORT_OPTIONS",description:"Alias for the `instr` option",promptOptions:{type:"text"}},svg:{value:null,types:["string","null"],envLink:"EXPORT_SVG",description:"SVG string representation of the chart to render",promptOptions:{type:"text"}},batch:{value:null,types:["string","null"],envLink:"EXPORT_BATCH",description:'Batch job string with input/output pairs: "in=out;in=out;..."',promptOptions:{type:"text"}},outfile:{value:null,types:["string","null"],envLink:"EXPORT_OUTFILE",description:"Output filename with type. Can be jpeg, png, pdf, or svg and ignores `type` option",promptOptions:{type:"text"}},type:{value:"png",types:["string"],envLink:"EXPORT_TYPE",description:"File export format. Can be jpeg, png, pdf, or svg",promptOptions:{type:"select",hint:"Default: png",choices:["png","jpeg","pdf","svg"]}},constr:{value:"chart",types:["string"],envLink:"EXPORT_CONSTR",description:"Chart constructor. Can be chart, stockChart, mapChart, or ganttChart",promptOptions:{type:"select",hint:"Default: chart",choices:["chart","stockChart","mapChart","ganttChart"]}},b64:{value:!1,types:["boolean"],envLink:"EXPORT_B64",description:"Whether or not to the chart should be received in Base64 format instead of binary",promptOptions:{type:"toggle"}},noDownload:{value:!1,types:["boolean"],envLink:"EXPORT_NO_DOWNLOAD",description:"Whether or not to include or exclude attachment headers in the response",promptOptions:{type:"toggle"}},height:{value:null,types:["number","null"],envLink:"EXPORT_HEIGHT",description:"Height of the exported chart, overrides chart settings",promptOptions:{type:"number"}},width:{value:null,types:["number","null"],envLink:"EXPORT_WIDTH",description:"Width of the exported chart, overrides chart settings",promptOptions:{type:"number"}},scale:{value:null,types:["number","null"],envLink:"EXPORT_SCALE",description:"Scale of the exported chart, overrides chart settings. Ranges from 0.1 to 5.0",promptOptions:{type:"number"}},defaultHeight:{value:400,types:["number"],envLink:"EXPORT_DEFAULT_HEIGHT",description:"Default height of the exported chart if not set",promptOptions:{type:"number"}},defaultWidth:{value:600,types:["number"],envLink:"EXPORT_DEFAULT_WIDTH",description:"Default width of the exported chart if not set",promptOptions:{type:"number"}},defaultScale:{value:1,types:["number"],envLink:"EXPORT_DEFAULT_SCALE",description:"Default scale of the exported chart if not set. Ranges from 0.1 to 5.0",promptOptions:{type:"number",min:.1,max:5}},globalOptions:{value:null,types:["Object","string","null"],envLink:"EXPORT_GLOBAL_OPTIONS",description:"JSON, stringified JSON or filename with global options for Highcharts.setOptions",promptOptions:{type:"text"}},themeOptions:{value:null,types:["Object","string","null"],envLink:"EXPORT_THEME_OPTIONS",description:"JSON, stringified JSON or filename with theme options for Highcharts.setOptions",promptOptions:{type:"text"}},rasterizationTimeout:{value:1500,types:["number"],envLink:"EXPORT_RASTERIZATION_TIMEOUT",description:"Milliseconds to wait for webpage rendering",promptOptions:{type:"number"}}},customLogic:{allowCodeExecution:{value:!1,types:["boolean"],envLink:"CUSTOM_LOGIC_ALLOW_CODE_EXECUTION",description:"Allows or disallows execution of arbitrary code during exporting",promptOptions:{type:"toggle"}},allowFileResources:{value:!1,types:["boolean"],envLink:"CUSTOM_LOGIC_ALLOW_FILE_RESOURCES",description:"Allows or disallows injection of filesystem resources (disabled in server mode)",promptOptions:{type:"toggle"}},customCode:{value:null,types:["string","null"],envLink:"CUSTOM_LOGIC_CUSTOM_CODE",description:"Custom code to execute before chart initialization. Can be a function, code wrapped in a function, or a .js filename",promptOptions:{type:"text"}},callback:{value:null,types:["string","null"],envLink:"CUSTOM_LOGIC_CALLBACK",description:"JavaScript code to run during construction. Can be a function or a .js filename",promptOptions:{type:"text"}},resources:{value:null,types:["Object","string","null"],envLink:"CUSTOM_LOGIC_RESOURCES",description:"Additional resources as JSON, stringified JSON, or filename, containing files, js, and css sections",promptOptions:{type:"text"}},loadConfig:{value:null,types:["string","null"],envLink:"CUSTOM_LOGIC_LOAD_CONFIG",legacyName:"fromFile",description:"File with a pre-defined configuration to use",promptOptions:{type:"text"}},createConfig:{value:null,types:["string","null"],envLink:"CUSTOM_LOGIC_CREATE_CONFIG",description:"Prompt-based option setting, saved to a provided config file",promptOptions:{type:"text"}}},server:{enable:{value:!1,types:["boolean"],envLink:"SERVER_ENABLE",cliName:"enableServer",description:"Starts the server when true",promptOptions:{type:"toggle"}},host:{value:"0.0.0.0",types:["string"],envLink:"SERVER_HOST",description:"Hostname of the server",promptOptions:{type:"text"}},port:{value:7801,types:["number"],envLink:"SERVER_PORT",description:"Port number for the server",promptOptions:{type:"number"}},uploadLimit:{value:3,types:["number"],envLink:"SERVER_UPLOAD_LIMIT",description:"Maximum request body size in MB",promptOptions:{type:"number"}},benchmarking:{value:!1,types:["boolean"],envLink:"SERVER_BENCHMARKING",cliName:"serverBenchmarking",description:"Displays or not action durations in milliseconds during server requests",promptOptions:{type:"toggle"}},proxy:{host:{value:null,types:["string","null"],envLink:"SERVER_PROXY_HOST",cliName:"proxyHost",description:"Host of the proxy server, if applicable",promptOptions:{type:"text"}},port:{value:null,types:["number","null"],envLink:"SERVER_PROXY_PORT",cliName:"proxyPort",description:"Port of the proxy server, if applicable",promptOptions:{type:"number"}},timeout:{value:5e3,types:["number"],envLink:"SERVER_PROXY_TIMEOUT",cliName:"proxyTimeout",description:"Timeout in milliseconds for the proxy server, if applicable",promptOptions:{type:"number"}}},rateLimiting:{enable:{value:!1,types:["boolean"],envLink:"SERVER_RATE_LIMITING_ENABLE",cliName:"enableRateLimiting",description:"Enables or disables rate limiting on the server",promptOptions:{type:"toggle"}},maxRequests:{value:10,types:["number"],envLink:"SERVER_RATE_LIMITING_MAX_REQUESTS",legacyName:"rateLimit",description:"Maximum number of requests allowed per minute",promptOptions:{type:"number"}},window:{value:1,types:["number"],envLink:"SERVER_RATE_LIMITING_WINDOW",description:"Time window in minutes for rate limiting",promptOptions:{type:"number"}},delay:{value:0,types:["number"],envLink:"SERVER_RATE_LIMITING_DELAY",description:"Delay duration between successive requests before reaching the limit",promptOptions:{type:"number"}},trustProxy:{value:!1,types:["boolean"],envLink:"SERVER_RATE_LIMITING_TRUST_PROXY",description:"Set to true if the server is behind a load balancer",promptOptions:{type:"toggle"}},skipKey:{value:null,types:["string","null"],envLink:"SERVER_RATE_LIMITING_SKIP_KEY",description:"Key to bypass the rate limiter, used with `skipToken`",promptOptions:{type:"text"}},skipToken:{value:null,types:["string","null"],envLink:"SERVER_RATE_LIMITING_SKIP_TOKEN",description:"Token to bypass the rate limiter, used with `skipKey`",promptOptions:{type:"text"}}},ssl:{enable:{value:!1,types:["boolean"],envLink:"SERVER_SSL_ENABLE",cliName:"enableSsl",description:"Enables or disables SSL protocol",promptOptions:{type:"toggle"}},force:{value:!1,types:["boolean"],envLink:"SERVER_SSL_FORCE",cliName:"sslForce",legacyName:"sslOnly",description:"Forces the server to use HTTPS only when true",promptOptions:{type:"toggle"}},port:{value:443,types:["number"],envLink:"SERVER_SSL_PORT",cliName:"sslPort",description:"Port for the SSL server",promptOptions:{type:"number"}},certPath:{value:null,types:["string","null"],envLink:"SERVER_SSL_CERT_PATH",cliName:"sslCertPath",legacyName:"sslPath",description:"Path to the SSL certificate/key file",promptOptions:{type:"text"}}}},pool:{minWorkers:{value:4,types:["number"],envLink:"POOL_MIN_WORKERS",description:"Minimum and initial number of pool workers to spawn",promptOptions:{type:"number"}},maxWorkers:{value:8,types:["number"],envLink:"POOL_MAX_WORKERS",legacyName:"workers",description:"Maximum number of pool workers to spawn",promptOptions:{type:"number"}},workLimit:{value:40,types:["number"],envLink:"POOL_WORK_LIMIT",description:"Number of tasks a worker can handle before restarting",promptOptions:{type:"number"}},acquireTimeout:{value:5e3,types:["number"],envLink:"POOL_ACQUIRE_TIMEOUT",description:"Timeout in milliseconds for acquiring a resource",promptOptions:{type:"number"}},createTimeout:{value:5e3,types:["number"],envLink:"POOL_CREATE_TIMEOUT",description:"Timeout in milliseconds for creating a resource",promptOptions:{type:"number"}},destroyTimeout:{value:5e3,types:["number"],envLink:"POOL_DESTROY_TIMEOUT",description:"Timeout in milliseconds for destroying a resource",promptOptions:{type:"number"}},idleTimeout:{value:3e4,types:["number"],envLink:"POOL_IDLE_TIMEOUT",description:"Timeout in milliseconds for destroying idle resources",promptOptions:{type:"number"}},createRetryInterval:{value:200,types:["number"],envLink:"POOL_CREATE_RETRY_INTERVAL",description:"Interval in milliseconds before retrying resource creation on failure",promptOptions:{type:"number"}},reaperInterval:{value:1e3,types:["number"],envLink:"POOL_REAPER_INTERVAL",description:"Interval in milliseconds to check and destroy idle resources",promptOptions:{type:"number"}},benchmarking:{value:!1,types:["boolean"],envLink:"POOL_BENCHMARKING",cliName:"poolBenchmarking",description:"Shows statistics for the pool of resources",promptOptions:{type:"toggle"}}},logging:{level:{value:4,types:["number"],envLink:"LOGGING_LEVEL",cliName:"logLevel",description:"Logging verbosity level",promptOptions:{type:"number",round:0,min:0,max:5}},file:{value:"highcharts-export-server.log",types:["string"],envLink:"LOGGING_FILE",cliName:"logFile",description:"Log file name. Requires `logToFile` and `logDest` to be set",promptOptions:{type:"text"}},dest:{value:"log",types:["string"],envLink:"LOGGING_DEST",cliName:"logDest",description:"Path to store log files. Requires `logToFile` to be set",promptOptions:{type:"text"}},toConsole:{value:!0,types:["boolean"],envLink:"LOGGING_TO_CONSOLE",cliName:"logToConsole",description:"Enables or disables console logging",promptOptions:{type:"toggle"}},toFile:{value:!0,types:["boolean"],envLink:"LOGGING_TO_FILE",cliName:"logToFile",description:"Enables or disables logging to a file",promptOptions:{type:"toggle"}}},ui:{enable:{value:!1,types:["boolean"],envLink:"UI_ENABLE",cliName:"enableUi",description:"Enables or disables the UI for the export server",promptOptions:{type:"toggle"}},route:{value:"/",types:["string"],envLink:"UI_ROUTE",cliName:"uiRoute",description:"The endpoint route for the UI",promptOptions:{type:"text"}}},other:{nodeEnv:{value:"production",types:["string"],envLink:"OTHER_NODE_ENV",description:"The Node.js environment type",promptOptions:{type:"text"}},listenToProcessExits:{value:!0,types:["boolean"],envLink:"OTHER_LISTEN_TO_PROCESS_EXITS",description:"Whether or not to attach process.exit handlers",promptOptions:{type:"toggle"}},noLogo:{value:!1,types:["boolean"],envLink:"OTHER_NO_LOGO",description:"Display or skip printing the logo on startup",promptOptions:{type:"toggle"}},hardResetPage:{value:!1,types:["boolean"],envLink:"OTHER_HARD_RESET_PAGE",description:"Whether or not to reset the page content entirely",promptOptions:{type:"toggle"}},browserShellMode:{value:!0,types:["boolean"],envLink:"OTHER_BROWSER_SHELL_MODE",description:"Whether or not to set the browser to run in shell mode",promptOptions:{type:"toggle"}}},debug:{enable:{value:!1,types:["boolean"],envLink:"DEBUG_ENABLE",cliName:"enableDebug",description:"Enables or disables debug mode for the underlying browser",promptOptions:{type:"toggle"}},headless:{value:!1,types:["boolean"],envLink:"DEBUG_HEADLESS",description:"Whether or not to set the browser to run in headless mode during debugging",promptOptions:{type:"toggle"}},devtools:{value:!1,types:["boolean"],envLink:"DEBUG_DEVTOOLS",description:"Enables or disables DevTools in headful mode",promptOptions:{type:"toggle"}},listenToConsole:{value:!1,types:["boolean"],envLink:"DEBUG_LISTEN_TO_CONSOLE",description:"Enables or disables listening to console messages from the browser",promptOptions:{type:"toggle"}},dumpio:{value:!1,types:["boolean"],envLink:"DEBUG_DUMPIO",description:"Redirects or not browser stdout and stderr to process.stdout and process.stderr",promptOptions:{type:"toggle"}},slowMo:{value:0,types:["number"],envLink:"DEBUG_SLOW_MO",description:"Delays Puppeteer operations by the specified milliseconds",promptOptions:{type:"number"}},debuggingPort:{value:9222,types:["number"],envLink:"DEBUG_DEBUGGING_PORT",description:"Port used for debugging",promptOptions:{type:"number"}}}},nestedProps=_createNestedProps(defaultConfig),absoluteProps=_createAbsoluteProps(defaultConfig);function _createNestedProps(e,t={},o=""){return Object.keys(e).forEach((r=>{const n=e[r];void 0===n.value?_createNestedProps(n,t,`${o}.${r}`):(t[n.cliName||r]=`${o}.${r}`.substring(1),void 0!==n.legacyName&&(t[n.legacyName]=`${o}.${r}`.substring(1)))})),t}function _createAbsoluteProps(e,t=[]){return Object.keys(e).forEach((o=>{const r=e[o];void 0===r.types?_createAbsoluteProps(r,t):r.types.includes("Object")&&t.push(o)})),t}dotenv.config();const v={array:e=>z.string().transform((t=>t.split(",").map((e=>e.trim())).filter((t=>e.includes(t))))).transform((e=>e.length?e:void 0)),boolean:()=>z.enum(["true","false",""]).transform((e=>""!==e?"true"===e:void 0)),enum:e=>z.enum([...e,""]).transform((e=>""!==e?e:void 0)),string:()=>z.string().trim().refine((e=>!["false","undefined","null","NaN"].includes(e)||""===e),(e=>({message:`The string contains forbidden values, received '${e}'`}))).transform((e=>""!==e?e:void 0)),positiveNum:()=>z.string().trim().refine((e=>""===e||!isNaN(parseFloat(e))&&parseFloat(e)>0),(e=>({message:`The value must be numeric and positive, received '${e}'`}))).transform((e=>""!==e?parseFloat(e):void 0)),nonNegativeNum:()=>z.string().trim().refine((e=>""===e||!isNaN(parseFloat(e))&&parseFloat(e)>=0),(e=>({message:`The value must be numeric and non-negative, received '${e}'`}))).transform((e=>""!==e?parseFloat(e):void 0))},Config=z.object({PUPPETEER_ARGS:v.string(),HIGHCHARTS_VERSION:z.string().trim().refine((e=>/^(latest|\d+(\.\d+){0,2})$/.test(e)||""===e),(e=>({message:`HIGHCHARTS_VERSION must be 'latest', a major version, or in the form XX.YY.ZZ, received '${e}'`}))).transform((e=>""!==e?e:void 0)),HIGHCHARTS_CDN_URL:z.string().trim().refine((e=>e.startsWith("https://")||e.startsWith("http://")||""===e),(e=>({message:`Invalid value for HIGHCHARTS_CDN_URL. It should start with http:// or https://, received '${e}'`}))).transform((e=>""!==e?e:void 0)),HIGHCHARTS_FORCE_FETCH:v.boolean(),HIGHCHARTS_CACHE_PATH:v.string(),HIGHCHARTS_ADMIN_TOKEN:v.string(),HIGHCHARTS_CORE_SCRIPTS:v.array(defaultConfig.highcharts.coreScripts.value),HIGHCHARTS_MODULE_SCRIPTS:v.array(defaultConfig.highcharts.moduleScripts.value),HIGHCHARTS_INDICATOR_SCRIPTS:v.array(defaultConfig.highcharts.indicatorScripts.value),HIGHCHARTS_CUSTOM_SCRIPTS:v.array(defaultConfig.highcharts.customScripts.value),EXPORT_INFILE:v.string(),EXPORT_INSTR:v.string(),EXPORT_OPTIONS:v.string(),EXPORT_SVG:v.string(),EXPORT_BATCH:v.string(),EXPORT_OUTFILE:v.string(),EXPORT_TYPE:v.enum(["jpeg","png","pdf","svg"]),EXPORT_CONSTR:v.enum(["chart","stockChart","mapChart","ganttChart"]),EXPORT_B64:v.boolean(),EXPORT_NO_DOWNLOAD:v.boolean(),EXPORT_HEIGHT:v.positiveNum(),EXPORT_WIDTH:v.positiveNum(),EXPORT_SCALE:v.positiveNum(),EXPORT_DEFAULT_HEIGHT:v.positiveNum(),EXPORT_DEFAULT_WIDTH:v.positiveNum(),EXPORT_DEFAULT_SCALE:v.positiveNum(),EXPORT_GLOBAL_OPTIONS:v.string(),EXPORT_THEME_OPTIONS:v.string(),EXPORT_RASTERIZATION_TIMEOUT:v.nonNegativeNum(),CUSTOM_LOGIC_ALLOW_CODE_EXECUTION:v.boolean(),CUSTOM_LOGIC_ALLOW_FILE_RESOURCES:v.boolean(),CUSTOM_LOGIC_CUSTOM_CODE:v.string(),CUSTOM_LOGIC_CALLBACK:v.string(),CUSTOM_LOGIC_RESOURCES:v.string(),CUSTOM_LOGIC_LOAD_CONFIG:v.string(),CUSTOM_LOGIC_CREATE_CONFIG:v.string(),SERVER_ENABLE:v.boolean(),SERVER_HOST:v.string(),SERVER_PORT:v.positiveNum(),SERVER_UPLOAD_LIMIT:v.positiveNum(),SERVER_BENCHMARKING:v.boolean(),SERVER_PROXY_HOST:v.string(),SERVER_PROXY_PORT:v.positiveNum(),SERVER_PROXY_TIMEOUT:v.nonNegativeNum(),SERVER_RATE_LIMITING_ENABLE:v.boolean(),SERVER_RATE_LIMITING_MAX_REQUESTS:v.nonNegativeNum(),SERVER_RATE_LIMITING_WINDOW:v.nonNegativeNum(),SERVER_RATE_LIMITING_DELAY:v.nonNegativeNum(),SERVER_RATE_LIMITING_TRUST_PROXY:v.boolean(),SERVER_RATE_LIMITING_SKIP_KEY:v.string(),SERVER_RATE_LIMITING_SKIP_TOKEN:v.string(),SERVER_SSL_ENABLE:v.boolean(),SERVER_SSL_FORCE:v.boolean(),SERVER_SSL_PORT:v.positiveNum(),SERVER_SSL_CERT_PATH:v.string(),POOL_MIN_WORKERS:v.nonNegativeNum(),POOL_MAX_WORKERS:v.nonNegativeNum(),POOL_WORK_LIMIT:v.positiveNum(),POOL_ACQUIRE_TIMEOUT:v.nonNegativeNum(),POOL_CREATE_TIMEOUT:v.nonNegativeNum(),POOL_DESTROY_TIMEOUT:v.nonNegativeNum(),POOL_IDLE_TIMEOUT:v.nonNegativeNum(),POOL_CREATE_RETRY_INTERVAL:v.nonNegativeNum(),POOL_REAPER_INTERVAL:v.nonNegativeNum(),POOL_BENCHMARKING:v.boolean(),LOGGING_LEVEL:z.string().trim().refine((e=>""===e||!isNaN(parseFloat(e))&&parseFloat(e)>=0&&parseFloat(e)<=5),(e=>({message:`Invalid value for LOGGING_LEVEL. We only accept values from 0 to 5 as logging levels, received '${e}'`}))).transform((e=>""!==e?parseFloat(e):void 0)),LOGGING_FILE:v.string(),LOGGING_DEST:v.string(),LOGGING_TO_CONSOLE:v.boolean(),LOGGING_TO_FILE:v.boolean(),UI_ENABLE:v.boolean(),UI_ROUTE:v.string(),OTHER_NODE_ENV:v.enum(["development","production","test"]),OTHER_LISTEN_TO_PROCESS_EXITS:v.boolean(),OTHER_NO_LOGO:v.boolean(),OTHER_HARD_RESET_PAGE:v.boolean(),OTHER_BROWSER_SHELL_MODE:v.boolean(),DEBUG_ENABLE:v.boolean(),DEBUG_HEADLESS:v.boolean(),DEBUG_DEVTOOLS:v.boolean(),DEBUG_LISTEN_TO_CONSOLE:v.boolean(),DEBUG_DUMPIO:v.boolean(),DEBUG_SLOW_MO:v.nonNegativeNum(),DEBUG_DEBUGGING_PORT:v.positiveNum()}),envs=Config.partial().parse(process.env),globalOptions=_initGlobalOptions(defaultConfig);function getOptions(e=!0){return e?globalOptions:deepCopy(globalOptions)}function setOptions(e={},t=[],o=!1){let r={},n={};t.length&&(r=_loadConfigFile(t),n=_pairArgumentValue(nestedProps,t));const i=getOptions(o);return _updateOptions(defaultConfig,i,r,e,n),i}function mergeOptions(e,t){if(isObject(t))for(const[o,r]of Object.entries(t))e[o]=isObject(r)&&!absoluteProps.includes(o)&&void 0!==e[o]?mergeOptions(e[o],r):void 0!==r?r:e[o];return e}function mapToNewOptions(e){const t={};if("[object Object]"===Object.prototype.toString.call(e))for(const[o,r]of Object.entries(e)){const e=nestedProps[o]?nestedProps[o].split("."):[];e.reduce(((t,o,n)=>t[o]=e.length-1===n?r:t[o]||{}),t)}return t}function isAllowedConfig(config,toString=!1,allowFunctions=!1){try{if(!isObject(config)&&"string"!=typeof config)return null;const objectConfig="string"==typeof config?allowFunctions?eval(`(${config})`):JSON.parse(config):config,stringifiedOptions=_optionsStringify(objectConfig,allowFunctions,!1),parsedOptions=allowFunctions?JSON.parse(_optionsStringify(objectConfig,allowFunctions,!0),((_,value)=>"string"==typeof value&&value.startsWith("function")?eval(`(${value})`):value)):JSON.parse(stringifiedOptions);return toString?stringifiedOptions:parsedOptions}catch(e){return null}}function _initGlobalOptions(e){const t={};for(const[o,r]of Object.entries(e))t[o]=Object.prototype.hasOwnProperty.call(r,"value")?r.value:_initGlobalOptions(r);return t}function _updateOptions(e,t,o,r,n){Object.keys(e).forEach((i=>{const s=e[i],a=o&&o[i],l=r&&r[i],c=n&&n[i];if(void 0===s.value)_updateOptions(s,t[i],a,l,c);else{null!=a&&(t[i]=a);const e=envs[s.envLink];s.envLink in envs&&null!=e&&(t[i]=e),null!=l&&(t[i]=l),null!=c&&(t[i]=c)}}))}function _optionsStringify(e,t,o){return JSON.stringify(e,((e,r)=>{if("string"==typeof r&&(r=r.trim()),"function"==typeof r||"string"==typeof r&&r.startsWith("function")&&r.endsWith("}")){if(t)return o?`"EXP_FUN${(r+"").replaceAll(/\s+/g," ")}EXP_FUN"`:`EXP_FUN${(r+"").replaceAll(/\s+/g," ")}EXP_FUN`;throw new Error}return r})).replaceAll(o?/\\"EXP_FUN|EXP_FUN\\"/g:/"EXP_FUN|EXP_FUN"/g,"")}function _loadConfigFile(e){const t=e.findIndex((e=>"loadConfig"===e.replace(/-/g,""))),o=t>-1&&e[t+1];if(o)try{return JSON.parse(readFileSync(getAbsolutePath(o)))}catch(e){logWithStack(2,e,`[config] Unable to load the configuration from the ${o} file.`)}return{}}function _pairArgumentValue(e,t){const o={};for(let r=0;r{if(i.length-1===s){const i=t[++r];i||log(2,`[config] Missing value for the CLI '--${n}' argument. Using the default value.`),e[o]=i||null}else void 0===e[o]&&(e[o]={});return e[o]}),o)}return o}async function fetch(e,t={}){return new Promise(((o,r)=>{_getProtocolModule(e).get(e,t,(e=>{let t="";e.on("data",(e=>{t+=e})),e.on("end",(()=>{t||r("Nothing was fetched from the URL."),e.text=t,o(e)}))})).on("error",(e=>{r(e)}))}))}function _getProtocolModule(e){return e.startsWith("https")?https:http}class ExportError extends Error{constructor(e,t){super(),this.message=e,this.stackMessage=e,t&&(this.statusCode=t)}setError(e){return this.error=e,e.name&&(this.name=e.name),e.statusCode&&(this.statusCode=e.statusCode),e.stack&&(this.stackMessage=e.message,this.stack=e.stack),this}}const cache={cdnUrl:"https://code.highcharts.com",activeManifest:{},sources:"",hcVersion:""};async function checkAndUpdateCache(e,t){let o;const r=getCachePath(),n=join(r,"manifest.json"),i=join(r,"sources.js");if(!existsSync(r)&&mkdirSync(r,{recursive:!0}),!existsSync(n)||e.forceFetch)log(3,"[cache] Fetching and caching Highcharts dependencies."),o=await _updateCache(e,t,i);else{let r=!1;const s=JSON.parse(readFileSync(n));if(s.modules&&Array.isArray(s.modules)){const e={};s.modules.forEach((t=>e[t]=1)),s.modules=e}const{coreScripts:a,moduleScripts:l,indicatorScripts:c}=e,p=a.length+l.length+c.length;s.version!==e.version?(log(2,"[cache] A Highcharts version mismatch in the cache, need to re-fetch."),r=!0):Object.keys(s.modules||{}).length!==p?(log(2,"[cache] The cache and the requested modules do not match, need to re-fetch."),r=!0):r=(l||[]).some((e=>{if(!s.modules[e])return log(2,`[cache] The ${e} is missing in the cache, need to re-fetch.`),!0})),r?o=await _updateCache(e,t,i):(log(3,"[cache] Dependency cache is up to date, proceeding."),cache.sources=readFileSync(i,"utf8"),o=s.modules,cache.hcVersion=extractVersion(cache.sources))}await _saveConfigToManifest(e,o)}function getHighchartsVersion(){return cache.hcVersion}async function updateHighchartsVersion(e){const t=getOptions();t.highcharts.version=e,await checkAndUpdateCache(t.highcharts,t.server.proxy)}function extractVersion(e){return e.substring(0,e.indexOf("*/")).replace("/*","").replace("*/","").replace(/\n/g,"").trim()}function extractModuleName(e){return e.replace(/(.*)\/|(.*)modules\/|stock\/(.*)indicators\/|maps\/(.*)modules\//gi,"")}function getCachePath(){return getAbsolutePath(getOptions().highcharts.cachePath)}async function _fetchAndProcessScript(e,t,o,r=!1){e.endsWith(".js")&&(e=e.substring(0,e.length-3)),log(4,`[cache] Fetching script - ${e}.js`);const n=await fetch(`${e}.js`,t);if(200===n.statusCode&&"string"==typeof n.text){if(o){o[extractModuleName(e)]=1}return n.text}if(r)throw new ExportError(`[cache] Could not fetch the ${e}.js. The script might not exist in the requested version (status code: ${n.statusCode}).`,404).setError(n);log(2,`[cache] Could not fetch the ${e}.js. The script might not exist in the requested version.`)}async function _saveConfigToManifest(e,t={}){const o={version:e.version,modules:t};cache.activeManifest=o,log(3,"[cache] Writing a new manifest.");try{writeFileSync(join(getCachePath(),"manifest.json"),JSON.stringify(o),"utf8")}catch(e){throw new ExportError("[cache] Error writing the cache manifest.",500).setError(e)}}async function _fetchScripts(e,t,o,r,n){let i;const s=r.host,a=r.port;if(s&&a)try{i=new HttpsProxyAgent({host:s,port:a})}catch(e){throw new ExportError("[cache] Could not create a Proxy Agent.",500).setError(e)}const l=i?{agent:i,timeout:r.timeout}:{},c=[...e.map((e=>_fetchAndProcessScript(`${e}`,l,n,!0))),...t.map((e=>_fetchAndProcessScript(`${e}`,l,n))),...o.map((e=>_fetchAndProcessScript(`${e}`,l)))];return(await Promise.all(c)).join(";\n")}async function _updateCache(e,t,o){const r="latest"===e.version?null:`${e.version}`,n=e.cdnUrl||cache.cdnUrl;try{const i={};return log(3,`[cache] Updating cache version to Highcharts: ${r||"latest"}.`),cache.sources=await _fetchScripts([...e.coreScripts.map((e=>r?`${n}/${r}/${e}`:`${n}/${e}`))],[...e.moduleScripts.map((e=>"map"===e?r?`${n}/maps/${r}/modules/${e}`:`${n}/maps/modules/${e}`:r?`${n}/${r}/modules/${e}`:`${n}/modules/${e}`)),...e.indicatorScripts.map((e=>r?`${n}/stock/${r}/indicators/${e}`:`${n}/stock/indicators/${e}`))],e.customScripts,t,i),cache.hcVersion=extractVersion(cache.sources),writeFileSync(o,cache.sources),i}catch(e){throw new ExportError("[cache] Unable to update the local Highcharts cache.",500).setError(e)}}function setupHighcharts(){Highcharts.animObject=function(){return{duration:0}}}async function createChart(e){const{getOptions:t,merge:o,setOptions:r,wrap:n}=Highcharts;Highcharts.setOptionsObj=o(!1,{},t()),window.isRenderComplete=!1,n(Highcharts.Chart.prototype,"init",(function(e,t,r){((t=o(t,{exporting:{enabled:!1},plotOptions:{series:{label:{enabled:!1}}},tooltip:{}})).series||[]).forEach((function(e){e.animation=!1})),window.onHighchartsRender||(window.onHighchartsRender=Highcharts.addEvent(this,"render",(()=>{window.isRenderComplete=!0}))),e.apply(this,[t,r])})),n(Highcharts.Series.prototype,"init",(function(e,t,o){e.apply(this,[t,o])}));const i={chart:{animation:!1,height:e.export.height,width:e.export.width},exporting:{enabled:!1}},s=new Function(`return ${e.export.instr}`)(),a=new Function(`return ${e.export.themeOptions}`)(),l=new Function(`return ${e.export.globalOptions}`)(),c=o(!1,a,s,i),p=e.customLogic.callback?new Function(`return ${e.customLogic.callback}`)():null;e.customLogic.customCode&&new Function("options",e.customLogic.customCode)(s),l&&r(l),Highcharts[e.export.constr]("container",c,p);const u=t();for(const e in u)"function"!=typeof u[e]&&delete u[e];r(Highcharts.setOptionsObj),Highcharts.setOptionsObj={}}const template=readFileSync(join(__dirname,"templates","template.html"),"utf8");let browser=null;async function createBrowser(e){const{debug:t,other:o}=getOptions(),{enable:r,...n}=t,i={headless:!o.browserShellMode||"shell",userDataDir:"tmp",args:e||[],handleSIGINT:!1,handleSIGTERM:!1,handleSIGHUP:!1,waitForInitialPage:!1,defaultViewport:null,...r&&n};if(!browser){let e=0;const t=async()=>{try{log(3,`[browser] Attempting to get a browser instance (try ${++e}).`),browser=await puppeteer.launch(i)}catch(o){if(logWithStack(1,o,"[browser] Failed to launch a browser instance."),!(e<25))throw o;log(3,`[browser] Retry to open a browser (${e} out of 25).`),await new Promise((e=>setTimeout(e,4e3))),await t()}};try{await t(),"shell"===i.headless&&log(3,"[browser] Launched browser in shell mode."),r&&log(3,"[browser] Launched browser in debug mode.")}catch(e){throw new ExportError("[browser] Maximum retries to open a browser instance reached.",500).setError(e)}if(!browser)throw new ExportError("[browser] Cannot find a browser to open.",500)}return browser}async function closeBrowser(){browser&&browser.connected&&await browser.close(),browser=null,log(4,"[browser] Closed the browser.")}async function newPage(e){if(!browser||!browser.connected)throw new ExportError("[browser] Browser is not yet connected.",500);if(e.page=await browser.newPage(),await e.page.setCacheEnabled(!1),await _setPageContent(e.page),_setPageEvents(e.page),!e.page||e.page.isClosed())throw new ExportError("[browser] The page is invalid or closed.",400)}async function clearPage(e,t=!1){try{if(e.page&&!e.page.isClosed())return t?(await e.page.goto("about:blank",{waitUntil:"domcontentloaded"}),await _setPageContent(e.page)):await e.page.evaluate((()=>{document.body.innerHTML='
'})),!0}catch(t){logWithStack(2,t,`[pool] Pool resource [${e.id}] - Content of the page could not be cleared.`),e.workCount=getOptions().pool.workLimit+1}return!1}async function addPageResources(e,t){const o=[],r=t.resources;if(r){const n=[];if(r.js&&n.push({content:r.js}),r.files)for(const e of r.files){const t=!e.startsWith("http");n.push(t?{content:readFileSync(getAbsolutePath(e),"utf8")}:{url:e})}for(const t of n)try{o.push(await e.addScriptTag(t))}catch(e){logWithStack(2,e,"[browser] The JS resource cannot be loaded.")}n.length=0;const i=[];if(r.css){let n=r.css.match(/@import\s*([^;]*);/g);if(n)for(let e of n)e&&(e=e.replace("url(","").replace("@import","").replace(/"/g,"").replace(/'/g,"").replace(/;/,"").replace(/\)/g,"").trim(),e.startsWith("http")?i.push({url:e}):t.allowFileResources&&i.push({path:join(__dirname,e)}));i.push({content:r.css.replace(/@import\s*([^;]*);/g,"")||" "});for(const t of i)try{o.push(await e.addStyleTag(t))}catch(e){logWithStack(2,e,"[browser] The CSS resource cannot be loaded.")}i.length=0}}return o}async function clearPageResources(e,t){try{for(const e of t)await e.dispose();await e.evaluate((()=>{if("undefined"!=typeof Highcharts){const e=Highcharts.charts;if(Array.isArray(e)&&e.length)for(const t of e)t&&t.destroy(),Highcharts.charts.shift()}const[...e]=document.getElementsByTagName("script"),[,...t]=document.getElementsByTagName("style"),[...o]=document.getElementsByTagName("link");for(const r of[...e,...t,...o])r.remove()}))}catch(e){logWithStack(2,e,"[browser] Could not clear page's resources.")}}async function _setPageContent(e){await e.setContent(template,{waitUntil:"domcontentloaded"}),await e.addScriptTag({path:join(getCachePath(),"sources.js")}),await e.evaluate(setupHighcharts)}function _setPageEvents(e){const{debug:t}=getOptions();e.on("pageerror",(async()=>{e.isClosed()})),t.enable&&t.listenToConsole&&e.on("console",(e=>{console.log(`[debug] ${e.text()}`)}))}var cssTemplate=()=>"\n\nhtml, body {\n margin: 0;\n padding: 0;\n box-sizing: border-box;\n}\n\n#table-div, #sliders, #datatable, #controls, .ld-row {\n display: none;\n height: 0;\n}\n\n#chart-container {\n box-sizing: border-box;\n margin: 0;\n overflow: auto;\n font-size: 0;\n}\n\n#chart-container > figure, div {\n margin-top: 0 !important;\n margin-bottom: 0 !important;\n}\n\n",svgTemplate=e=>`\n\n\n \n \n Highcharts Export\n \n \n \n
\n ${e}\n
\n \n\n\n`;async function puppeteerExport(e,t){const o=[];try{const r=t.export;let n=!1;if(r.svg){if(log(4,"[export] Treating as SVG input."),"svg"===r.type)return r.svg;n=!0,await _setAsSvg(e,r.svg)}else log(4,"[export] Treating as JSON config."),await _setAsOptions(e,t);o.push(...await addPageResources(e,t.customLogic));const i=n?await e.evaluate((e=>{const t=document.querySelector("#chart-container svg:first-of-type"),o=t.height.baseVal.value*e,r=t.width.baseVal.value*e;return document.body.style.zoom=e,document.body.style.margin="0px",{chartHeight:o,chartWidth:r}}),parseFloat(r.scale)):await e.evaluate((()=>{const{chartHeight:e,chartWidth:t}=window.Highcharts.charts[0];return document.body.style.zoom=1,{chartHeight:e,chartWidth:t}})),{x:s,y:a}=await _getClipRegion(e),l=Math.abs(Math.ceil(i.chartHeight||r.height)),c=Math.abs(Math.ceil(i.chartWidth||r.width));let p;switch(await e.setViewport({height:l,width:c,deviceScaleFactor:n?1:parseFloat(r.scale)}),r.type){case"svg":p=await _createSVG(e);break;case"png":case"jpeg":p=await _createImage(e,r.type,{width:c,height:l,x:s,y:a},r.rasterizationTimeout);break;case"pdf":p=await _createPDF(e,l,c,r.rasterizationTimeout);break;default:throw new ExportError(`[export] Unsupported output format: ${r.type}.`,400)}return await clearPageResources(e,o),p}catch(t){return await clearPageResources(e,o),t}}async function _setAsSvg(e,t){await e.setContent(svgTemplate(t),{waitUntil:"domcontentloaded"})}async function _setAsOptions(e,t){await e.evaluate(createChart,t)}async function _getClipRegion(e){return e.$eval("#chart-container",(e=>{const{x:t,y:o,width:r,height:n}=e.getBoundingClientRect();return{x:t,y:o,width:r,height:Math.trunc(n>1?n:500)}}))}async function _createSVG(e){return e.$eval("#container svg:first-of-type",(e=>e.outerHTML))}async function _createImage(e,t,o,r){return Promise.race([e.screenshot({type:t,clip:o,encoding:"base64",fullPage:!1,optimizeForSpeed:!0,captureBeyondViewport:!0,..."png"!==t?{quality:80}:{},omitBackground:"png"==t}),new Promise(((e,t)=>setTimeout((()=>t(new ExportError("Rasterization timeout",408))),r||1500)))])}async function _createPDF(e,t,o,r){return await e.emulateMediaType("screen"),e.pdf({height:t+1,width:o,encoding:"base64",timeout:r||1500})}let pool=null;const poolStats={exportsAttempted:0,exportsPerformed:0,exportsDropped:0,exportsFromSvg:0,exportsFromOptions:0,exportsFromSvgAttempts:0,exportsFromOptionsAttempts:0,timeSpent:0,timeSpentAverage:0};async function initPool(e=getOptions().pool,t=[]){await createBrowser(t);try{if(log(3,`[pool] Initializing pool with workers: min ${e.minWorkers}, max ${e.maxWorkers}.`),pool)return void log(4,"[pool] Already initialized, please kill it before creating a new one.");e.minWorkers>e.maxWorkers&&(e.minWorkers=e.maxWorkers),pool=new Pool({..._factory(e),min:e.minWorkers,max:e.maxWorkers,acquireTimeoutMillis:e.acquireTimeout,createTimeoutMillis:e.createTimeout,destroyTimeoutMillis:e.destroyTimeout,idleTimeoutMillis:e.idleTimeout,createRetryIntervalMillis:e.createRetryInterval,reapIntervalMillis:e.reaperInterval,propagateCreateError:!1}),pool.on("release",(async e=>{const t=await clearPage(e,!1);log(4,`[pool] Pool resource [${e.id}] - Releasing a worker. Clear page status: ${t}.`)})),pool.on("destroySuccess",((e,t)=>{log(4,`[pool] Pool resource [${t.id}] - Destroyed a worker successfully.`),t.page=null}));const t=[];for(let o=0;o{pool.release(e)})),log(3,"[pool] The pool is ready"+(t.length?` with ${t.length} initial resources waiting.`:"."))}catch(e){throw new ExportError("[pool] Could not configure and create the pool of workers.",500).setError(e)}}async function killPool(){if(log(3,"[pool] Killing pool with all workers and closing browser."),pool){for(const e of pool.used)pool.release(e.resource);pool.destroyed||(await pool.destroy(),log(4,"[pool] Destroyed the pool of resources.")),pool=null}await closeBrowser()}async function postWork(e){let t;try{if(log(4,"[pool] Work received, starting to process."),++poolStats.exportsAttempted,getOptions().pool.benchmarking&&getPoolInfo(),!pool)throw new ExportError("[pool] Work received, but pool has not been started.",500);const o=measureTime();try{log(4,"[pool] Acquiring a worker handle."),t=await pool.acquire().promise,e.server.benchmarking&&log(5,e._requestId?`[benchmark] Request [${e._requestId}] - `:"[benchmark] ",`Acquiring a worker handle took ${o()}ms.`)}catch(t){throw new ExportError("[pool] "+(e._requestId?`Request [${e._requestId}] - `:"")+`Error encountered when acquiring an available entry: ${o()}ms.`,400).setError(t)}if(log(4,"[pool] Acquired a worker handle."),!t.page)throw t.workCount=e.pool.workLimit+1,new ExportError("[pool] Resolved worker page is invalid: the pool setup is wonky.",400);const r=getNewDateTime();log(4,`[pool] Pool resource [${t.id}] - Starting work on this pool entry.`);const n=measureTime(),i=await puppeteerExport(t.page,e);if(i instanceof Error)throw"Rasterization timeout"===i.message&&(t.workCount=e.pool.workLimit+1,t.page=null),"TimeoutError"===i.name||"Rasterization timeout"===i.message?new ExportError("[pool] "+(e._requestId?`Request [${e._requestId}] - `:"")+"Rasterization timeout: your chart may be too complex or large, and failed to render within the allotted time.").setError(i):new ExportError("[pool] "+(e._requestId?`Request [${e._requestId}] - `:"")+`Error encountered during export: ${n()}ms.`).setError(i);e.server.benchmarking&&log(5,e._requestId?`[benchmark] Request [${e._requestId}] - `:"[benchmark] ",`Exporting a chart sucessfully took ${n()}ms.`),pool.release(t);const s=getNewDateTime()-r;return poolStats.timeSpent+=s,poolStats.timeSpentAverage=poolStats.timeSpent/++poolStats.exportsPerformed,log(4,`[pool] Work completed in ${s}ms.`),{result:i,options:e}}catch(e){throw++poolStats.exportsDropped,t&&pool.release(t),e}}function getPoolStats(){return poolStats}function getPoolInfoJSON(){return{min:pool.min,max:pool.max,used:pool.numUsed(),available:pool.numFree(),allCreated:pool.numUsed()+pool.numFree(),pendingAcquires:pool.numPendingAcquires(),pendingCreates:pool.numPendingCreates(),pendingValidations:pool.numPendingValidations(),pendingDestroys:pool.pendingDestroys.length,absoluteAll:pool.numUsed()+pool.numFree()+pool.numPendingAcquires()+pool.numPendingCreates()+pool.numPendingValidations()+pool.pendingDestroys.length}}function getPoolInfo(){const{min:e,max:t,used:o,available:r,allCreated:n,pendingAcquires:i,pendingCreates:s,pendingValidations:a,pendingDestroys:l,absoluteAll:c}=getPoolInfoJSON();log(5,`[pool] The minimum number of resources allowed by pool: ${e}.`),log(5,`[pool] The maximum number of resources allowed by pool: ${t}.`),log(5,`[pool] The number of used resources: ${o}.`),log(5,`[pool] The number of free resources: ${r}.`),log(5,`[pool] The number of all created (used and free) resources: ${n}.`),log(5,`[pool] The number of resources waiting to be acquired: ${i}.`),log(5,`[pool] The number of resources waiting to be created: ${s}.`),log(5,`[pool] The number of resources waiting to be validated: ${a}.`),log(5,`[pool] The number of resources waiting to be destroyed: ${l}.`),log(5,`[pool] The number of all resources: ${c}.`)}function _factory(e){return{create:async()=>{const t={id:v4(),workCount:Math.round(Math.random()*(e.workLimit/2))};try{const e=getNewDateTime();return await newPage(t),log(3,`[pool] Pool resource [${t.id}] - Successfully created a worker, took ${getNewDateTime()-e}ms.`),t}catch(e){throw log(3,`[pool] Pool resource [${t.id}] - Error encountered when creating a new page.`),e}},validate:async t=>t.page?t.page.isClosed()?(log(3,`[pool] Pool resource [${t.id}] - Validation failed (page is closed or invalid).`),!1):t.page.mainFrame().detached?(log(3,`[pool] Pool resource [${t.id}] - Validation failed (page's frame is detached).`),!1):!(e.workLimit&&++t.workCount>e.workLimit)||(log(3,`[pool] Pool resource [${t.id}] - Validation failed (exceeded the ${e.workLimit} works per resource limit).`),!1):(log(3,`[pool] Pool resource [${t.id}] - Validation failed (no valid page is found).`),!1),destroy:async e=>{if(log(3,`[pool] Pool resource [${e.id}] - Destroying a worker.`),e.page&&!e.page.isClosed())try{e.page.removeAllListeners("pageerror"),e.page.removeAllListeners("console"),e.page.removeAllListeners("framedetached"),await e.page.close()}catch(t){throw log(3,`[pool] Pool resource [${e.id}] - Page could not be closed upon destroying.`),t}}}}function sanitize(e){const t=new JSDOM("").window;return DOMPurify(t).sanitize(e,{ADD_TAGS:["foreignObject"]})}let allowCodeExecution=!1;async function singleExport(e){if(!e||!e.export)throw new ExportError("[chart] No expected `export` options were found. Please provide one of the following options: `infile`, `instr`, `options`, or `svg` to generate a valid image.",400);await startExport(e,(async(e,t)=>{if(e)throw e;const{b64:o,outfile:r,type:n}=t.options.export;try{o?writeFileSync(`${r.split(".").shift()||"chart"}.txt`,getBase64(t.result,n)):writeFileSync(r||`chart.${n}`,"svg"!==n?Buffer.from(t.result,"base64"):t.result)}catch(e){throw new ExportError("[chart] Error while saving a chart.",500).setError(e)}await killPool()}))}async function batchExport(e){if(!(e&&e.export&&e.export.batch))throw new ExportError("[chart] No expected `export` options were found. Please provide the `batch` option to generate valid images.",400);{const t=[];for(let o of e.export.batch.split(";")||[])o=o.split("="),2===o.length?t.push(startExport({...e,export:{...e.export,infile:o[0],outfile:o[1]}},((e,t)=>{if(e)throw e;const{b64:o,outfile:r,type:n}=t.options.export;try{o?writeFileSync(`${r.split(".").shift()||"chart"}.txt`,getBase64(t.result,n)):writeFileSync(r,"svg"!==n?Buffer.from(t.result,"base64"):t.result)}catch(e){throw new ExportError("[chart] Error while saving a chart.",500).setError(e)}}))):log(2,"[chart] No correct pair found for the batch export.");const o=await Promise.allSettled(t);await killPool(),o.forEach(((e,t)=>{e.reason&&logWithStack(1,e.reason,`[chart] Batch export number ${t+1} could not be correctly completed.`)}))}}async function startExport(e,t){try{log(4,"[chart] Starting the exporting process.");const o=mergeOptions(getOptions(!1),e),r=o.export;if(null!==r.infile){let e;log(4,"[chart] Attempting to export from a file input.");try{e=readFileSync(getAbsolutePath(r.infile),"utf8")}catch(e){throw new ExportError("[chart] Error loading content from a file input.",400).setError(e)}if(r.infile.endsWith(".svg"))r.svg=e;else{if(!r.infile.endsWith(".json"))throw new ExportError("[chart] Incorrect value of the `infile` option.",400);r.instr=e}}if(null!==r.svg){log(4,"[chart] Attempting to export from an SVG input."),++getPoolStats().exportsFromSvgAttempts;const e=await _exportFromSvg(sanitize(r.svg),o);return++getPoolStats().exportsFromSvg,t(null,e)}if(null!==r.instr||null!==r.options){log(4,"[chart] Attempting to export from options input."),++getPoolStats().exportsFromOptionsAttempts;const e=await _exportFromOptions(r.instr||r.options,o);return++getPoolStats().exportsFromOptions,t(null,e)}return t(new ExportError("[chart] No valid input specified. Check if at least one of the following parameters is correctly set: 'infile', 'instr', 'options', or 'svg'.",400))}catch(e){return t(e)}}function getAllowCodeExecution(){return allowCodeExecution}function setAllowCodeExecution(e){allowCodeExecution=e}async function _exportFromSvg(e,t){if("string"==typeof e&&(e.indexOf("=0||e.indexOf("=0))return log(4,"[chart] Parsing input as SVG."),t.export.svg=e,t.export.instr=null,t.export.options=null,_prepareExport(t);throw new ExportError("[chart] Not a correct SVG input.",400)}async function _exportFromOptions(e,t){log(4,"[chart] Parsing input from options.");const o=isAllowedConfig(e,!0,t.customLogic.allowCodeExecution);if(null===o||"string"!=typeof o||!o.startsWith("{")||!o.endsWith("}"))throw new ExportError("[chart] Invalid configuration provided - Only options configurations and SVG are allowed for this server. If this is your server, JavaScript custom code can be enabled by starting the server with the `allowCodeExecution` options set to true.",403);return t.export.instr=o,t.export.svg=null,_prepareExport(t)}async function _prepareExport(e){const{export:t,customLogic:o}=e;return t.type=fixType(t.type,t.outfile),t.outfile=fixOutfile(t.type,t.outfile),log(3,`[chart] The custom logic is ${o.allowCodeExecution?"allowed":"disallowed"}.`),_handleCustomLogic(o,o.allowCodeExecution),_handleGlobalAndTheme(t,o.allowFileResources,o.allowCodeExecution),e.export={...t,..._findChartSize(t)},postWork(e)}function _findChartSize(e){const{chart:t,exporting:o}=e.options||isAllowedConfig(e.instr)||!1,{chart:r,exporting:n}=isAllowedConfig(e.globalOptions)||!1,{chart:i,exporting:s}=isAllowedConfig(e.themeOptions)||!1,a=roundNumber(Math.max(.1,Math.min(e.scale||o?.scale||n?.scale||s?.scale||e.defaultScale||1,5)),2),l={height:e.height||o?.sourceHeight||t?.height||n?.sourceHeight||r?.height||s?.sourceHeight||i?.height||e.defaultHeight||400,width:e.width||o?.sourceWidth||t?.width||n?.sourceWidth||r?.width||s?.sourceWidth||i?.width||e.defaultWidth||600,scale:a};for(let[e,t]of Object.entries(l))l[e]="string"==typeof t?+t.replace(/px|%/gi,""):t;return l}function _handleCustomLogic(e,t){if(t){if("string"==typeof e.resources)e.resources=_handleResources(e.resources,e.allowFileResources,!0);else if(!e.resources)try{e.resources=_handleResources(readFileSync(getAbsolutePath("resources.json"),"utf8"),e.allowFileResources,!0)}catch(e){log(2,"[chart] Unable to load the default `resources.json` file.")}try{e.customCode=wrapAround(e.customCode,e.allowFileResources)}catch(t){logWithStack(2,t,"[chart] The `customCode` cannot be loaded."),e.customCode=null}try{e.callback=wrapAround(e.callback,e.allowFileResources,!0)}catch(t){logWithStack(2,t,"[chart] The `callback` cannot be loaded."),e.callback=null}[null,void 0].includes(e.customCode)&&log(3,"[chart] No value for the `customCode` option found."),[null,void 0].includes(e.callback)&&log(3,"[chart] No value for the `callback` option found."),[null,void 0].includes(e.resources)&&log(3,"[chart] No value for the `resources` option found.")}else if(e.callback||e.resources||e.customCode)throw e.callback=null,e.resources=null,e.customCode=null,new ExportError("[chart] The 'callback', 'resources', and 'customCode' options have been disabled for this server.",403)}function _handleResources(e=null,t,o){const r=["js","css","files"];let n=e,i=!1;if(t&&e.endsWith(".json"))try{n=isAllowedConfig(readFileSync(getAbsolutePath(e),"utf8"),!1,o)}catch{return null}else n=isAllowedConfig(e,!1,o),n&&!t&&delete n.files;for(const e in n)r.includes(e)?i||(i=!0):delete n[e];return i?(n.files&&(n.files=n.files.map((e=>e.trim())),(!n.files||n.files.length<=0)&&delete n.files),n):null}function _handleGlobalAndTheme(e,t,o){["globalOptions","themeOptions"].forEach((r=>{try{e[r]&&(t&&"string"==typeof e[r]&&e[r].endsWith(".json")?e[r]=isAllowedConfig(readFileSync(getAbsolutePath(e[r]),"utf8"),!0,o):e[r]=isAllowedConfig(e[r],!0,o))}catch(t){logWithStack(2,t,`[chart] The \`${r}\` cannot be loaded.`),e[r]=null}})),[null,void 0].includes(e.globalOptions)&&log(3,"[chart] No value for the `globalOptions` option found."),[null,void 0].includes(e.themeOptions)&&log(3,"[chart] No value for the `themeOptions` option found.")}const timerIds=[];function addTimer(e){timerIds.push(e)}function clearAllTimers(){log(4,"[timer] Clearing all registered intervals and timeouts.");for(const e of timerIds)clearInterval(e),clearTimeout(e)}function logErrorMiddleware(e,t,o,r){return logWithStack(1,e),"development"!==getOptions().other.nodeEnv&&delete e.stack,r(e)}function returnErrorMiddleware(e,t,o,r){const{message:n,stack:i}=e,s=e.statusCode||400;o.status(s).json({statusCode:s,message:n,stack:i})}function errorMiddleware(e){e.use(logErrorMiddleware),e.use(returnErrorMiddleware)}function rateLimitingMiddleware(e,t=getOptions().server.rateLimiting){try{if(t.enable){const o="Too many requests, you have been rate limited. Please try again later.",r={max:t.maxRequests||30,window:t.window||1,delay:t.delay||0,trustProxy:t.trustProxy||!1,skipKey:t.skipKey||!1,skipToken:t.skipToken||!1};r.trustProxy&&e.enable("trust proxy");const n=rateLimit({windowMs:60*r.window*1e3,max:r.max,delayMs:r.delay,handler:(e,t)=>{t.format({json:()=>{t.status(429).send({message:o})},default:()=>{t.status(429).send(o)}})},skip:e=>!1!==r.skipKey&&!1!==r.skipToken&&e.query.key===r.skipKey&&e.query.access_token===r.skipToken&&(log(4,"[rate limiting] Skipping rate limiter."),!0)});e.use(n),log(3,`[rate limiting] Enabled rate limiting with ${r.max} requests per ${r.window} minute for each IP, trusting proxy: ${r.trustProxy}.`)}}catch(e){throw new ExportError("[rate limiting] Could not configure and set the rate limiting options.",500).setError(e)}}class HttpError extends ExportError{constructor(e,t){super(e,t)}setStatus(e){return this.statusCode=e,this}}function contentTypeMiddleware(e,t,o){try{const t=e.headers["content-type"]||"";if(!t.includes("application/json")&&!t.includes("application/x-www-form-urlencoded")&&!t.includes("multipart/form-data"))throw new HttpError("[validation] Content-Type must be application/json, application/x-www-form-urlencoded, or multipart/form-data.",415);return o()}catch(e){return o(e)}}function requestBodyMiddleware(e,t,o){try{const t=e.body,r=v4().replace(/-/g,"");if(!t||isObjectEmpty(t))throw log(2,`[validation] Request [${r}] - The request from ${e.headers["x-forwarded-for"]||e.connection.remoteAddress} was incorrect. Received payload is empty.`),new HttpError("[validation] The request body is required. Please ensure that your Content-Type header is correct. Accepted types are 'application/json' and 'multipart/form-data'.",400);const n=getAllowCodeExecution(),i=isAllowedConfig(t.instr||t.options||t.infile||t.data,!0,n);if(null===i&&!t.svg)throw log(2,`[validation] Request [${r}] - The request from ${e.headers["x-forwarded-for"]||e.connection.remoteAddress} was incorrect. Received payload is missing correct chart data for export: ${JSON.stringify(t)}.`),new HttpError("[validation] No correct chart data found. Ensure that you are using either application/json or multipart/form-data headers. If sending JSON, make sure the chart data is in the 'infile', 'options', or 'data' attribute. If sending SVG, ensure it is in the 'svg' attribute.",400);if(t.svg&&isPrivateRangeUrlFound(t.svg))throw new HttpError("[validation] SVG potentially contain at least one forbidden URL in 'xlink:href' element. Please review the SVG content and ensure that all referenced URLs comply with security policies.",400);return e.validatedOptions={_requestId:r,export:{instr:i,svg:t.svg,outfile:t.outfile||`${e.params.filename||"chart"}.${fixType(t.type)}`,type:fixType(t.type,t.outfile),constr:fixConstr(t.constr),b64:t.b64,noDownload:t.noDownload,height:t.height,width:t.width,scale:t.scale,globalOptions:isAllowedConfig(t.globalOptions,!0,n),themeOptions:isAllowedConfig(t.themeOptions,!0,n)},customLogic:{allowCodeExecution:n,allowFileResources:!1,customCode:t.customCode,callback:t.callback,resources:isAllowedConfig(t.resources,!0,n)}},o()}catch(e){return o(e)}}function validationMiddleware(e){e.post(["/","/:filename"],contentTypeMiddleware),e.post(["/","/:filename"],requestBodyMiddleware)}const reversedMime={png:"image/png",jpeg:"image/jpeg",gif:"image/gif",pdf:"application/pdf",svg:"image/svg+xml"};async function requestExport(e,t,o){try{const o=measureTime();let r=!1;e.socket.on("close",(e=>{e&&(r=!0)}));const n=e.validatedOptions,i=n._requestId;log(4,`[export] Got an incoming HTTP request with ID ${i}.`),await startExport(n,((n,s)=>{if(e.socket.removeAllListeners("close"),r)log(3,`[export] Request [${i}] - The client closed the connection before the chart finished processing.`);else{if(n)throw n;if(!s||!s.result)throw log(2,`[export] Request [${i}] - Request from ${e.headers["x-forwarded-for"]||e.connection.remoteAddress} was incorrect. Received result is ${s.result}.`),new HttpError("[export] Unexpected return of the export result from the chart generation. Please check your request data.",400);if(s.result){log(3,`[export] Request [${i}] - The whole exporting process took ${o()}ms.`);const{type:e,b64:r,noDownload:n,outfile:a}=s.options.export;return r?t.send(getBase64(s.result,e)):(t.header("Content-Type",reversedMime[e]||"image/png"),n||t.attachment(a),"svg"===e?t.send(s.result):t.send(Buffer.from(s.result,"base64")))}}}))}catch(e){return o(e)}}function exportRoutes(e){e.post("/",requestExport),e.post("/:filename",requestExport)}const serverStartTime=new Date,packageFile=JSON.parse(readFileSync(join(__dirname,"package.json"))),successRates=[],recordInterval=6e4,windowSize=30;function _calculateMovingAverage(){return successRates.reduce(((e,t)=>e+t),0)/successRates.length}function _startSuccessRate(){return setInterval((()=>{const e=getPoolStats(),t=0===e.exportsAttempted?1:e.exportsPerformed/e.exportsAttempted*100;successRates.push(t),successRates.length>windowSize&&successRates.shift()}),recordInterval)}function healthRoutes(e){addTimer(_startSuccessRate()),e.get("/health",((e,t,o)=>{try{log(4,"[health] Returning server health.");const e=getPoolStats(),o=successRates.length,r=_calculateMovingAverage();t.send({status:"OK",bootTime:serverStartTime,uptime:`${Math.floor((getNewDateTime()-serverStartTime.getTime())/1e3/60)} minutes`,serverVersion:packageFile.version,highchartsVersion:getHighchartsVersion(),averageExportTime:e.timeSpentAverage,attemptedExports:e.exportsAttempted,performedExports:e.exportsPerformed,failedExports:e.exportsDropped,sucessRatio:e.exportsPerformed/e.exportsAttempted*100,pool:getPoolInfoJSON(),period:o,movingAverage:r,message:isNaN(r)||!successRates.length?"Too early to report. No exports made yet. Please check back soon.":`Last ${o} minutes had a success rate of ${r.toFixed(2)}%.`,svgExports:e.exportsFromSvg,jsonExports:e.exportsFromOptions,svgExportsAttempts:e.exportsFromSvgAttempts,jsonExportsAttempts:e.exportsFromOptionsAttempts})}catch(e){return o(e)}}))}function uiRoutes(e){e.get(getOptions().ui.route||"/",((e,t,o)=>{try{t.sendFile(join(__dirname,"public","index.html"),{acceptRanges:!1})}catch(e){return o(e)}}))}function versionChangeRoutes(e){e.post("/version_change/:newVersion",(async(e,t,o)=>{try{const o=envs.HIGHCHARTS_ADMIN_TOKEN;if(!o||!o.length)throw new HttpError("[version] The server is not configured to perform run-time version changes: HIGHCHARTS_ADMIN_TOKEN is not set.",401);const r=e.get("hc-auth");if(!r||r!==o)throw new HttpError("[version] Invalid or missing token: Set the token in the hc-auth header.",401);const n=e.params.newVersion;if(!n)throw new HttpError("[version] No new version supplied.",400);try{await updateHighchartsVersion(n)}catch(e){throw new HttpError(`[version] Version change: ${e.message}`,400).setError(e)}t.status(200).send({statusCode:200,highchartsVersion:getHighchartsVersion(),message:`Successfully updated Highcharts to version: ${n}.`})}catch(e){return o(e)}}))}const activeServers=new Map,app=express();async function startServer(e=getOptions().server){try{if(!e.enable||!app)throw new ExportError("[server] Server cannot be started (not enabled or no correct Express app found).",500);const t=1024*e.uploadLimit*1024,o=multer.memoryStorage(),r=multer({storage:o,limits:{fieldSize:t}});if(app.disable("x-powered-by"),app.use(cors({methods:["POST","GET","OPTIONS"]})),app.use(((e,t,o)=>{t.set("Accept-Ranges","none"),o()})),app.use(express.json({limit:t})),app.use(express.urlencoded({extended:!0,limit:t})),app.use(r.none()),app.use(express.static(join(__dirname,"public"))),!e.ssl.force){const t=http.createServer(app);_attachServerErrorHandlers(t),t.listen(e.port,e.host,(()=>{activeServers.set(e.port,t),log(3,`[server] Started HTTP server on ${e.host}:${e.port}.`)}))}if(e.ssl.enable){let t,o;try{t=await readFile(join(getAbsolutePath(e.ssl.certPath),"server.key"),"utf8"),o=await readFile(join(getAbsolutePath(e.ssl.certPath),"server.crt"),"utf8")}catch(t){log(2,`[server] Unable to load key/certificate from the '${e.ssl.certPath}' path. Could not run secured layer server.`)}if(t&&o){const r=https.createServer({key:t,cert:o},app);_attachServerErrorHandlers(r),r.listen(e.ssl.port,e.host,(()=>{activeServers.set(e.ssl.port,r),log(3,`[server] Started HTTPS server on ${e.host}:${e.ssl.port}.`)}))}}rateLimitingMiddleware(app,e.rateLimiting),validationMiddleware(app),healthRoutes(app),exportRoutes(app),uiRoutes(app),versionChangeRoutes(app),errorMiddleware(app)}catch(e){throw new ExportError("[server] Could not configure and start the server.",500).setError(e)}}function closeServers(){if(activeServers.size>0){log(4,"[server] Closing all servers.");for(const[e,t]of activeServers)t.close((()=>{activeServers.delete(e),log(4,`[server] Closed server on port: ${e}.`)}))}}function getServers(){return activeServers}function getExpress(){return express}function getApp(){return app}function enableRateLimiting(e){rateLimitingMiddleware(app,e)}function use(e,...t){app.use(e,...t)}function get(e,...t){app.get(e,...t)}function post(e,...t){app.post(e,...t)}function _attachServerErrorHandlers(e){e.on("clientError",((e,t)=>{logWithStack(1,e,`[server] Client error: ${e.message}, destroying socket.`),t.destroy()})),e.on("error",(e=>{logWithStack(1,e,`[server] Server error: ${e.message}`)})),e.on("connection",(e=>{e.on("error",(e=>{logWithStack(1,e,`[server] Socket error: ${e.message}`)}))}))}var server={startServer:startServer,closeServers:closeServers,getServers:getServers,getExpress:getExpress,getApp:getApp,enableRateLimiting:enableRateLimiting,use:use,get:get,post:post};async function shutdownCleanUp(e){await Promise.allSettled([clearAllTimers(),closeServers(),killPool()]),process.exit(e)}async function initExport(e){const t=mergeOptions(getOptions(!1),e);setAllowCodeExecution(t.customLogic.allowCodeExecution),initLogging(t.logging),t.other.listenToProcessExits&&_attachProcessExitListeners(),await checkAndUpdateCache(t.highcharts,t.server.proxy),await initPool(t.pool,t.puppeteer.args)}function _attachProcessExitListeners(){log(3,"[process] Attaching exit listeners to the process."),process.on("exit",(e=>{log(4,`[process] Process exited with code ${e}.`)})),process.on("SIGINT",(async(e,t)=>{log(4,`[process] The ${e} event with code: ${t}.`),await shutdownCleanUp(0)})),process.on("SIGTERM",(async(e,t)=>{log(4,`[process] The ${e} event with code: ${t}.`),await shutdownCleanUp(0)})),process.on("SIGHUP",(async(e,t)=>{log(4,`[process] The ${e} event with code: ${t}.`),await shutdownCleanUp(0)})),process.on("uncaughtException",(async(e,t)=>{logWithStack(1,e,`[process] The ${t} error.`),await shutdownCleanUp(1)}))}var index={server:server,startServer:startServer,getOptions:getOptions,setOptions:setOptions,mergeOptions:mergeOptions,mapToNewOptions:mapToNewOptions,initExport:initExport,singleExport:singleExport,batchExport:batchExport,startExport:startExport,checkAndUpdateCache:checkAndUpdateCache,initPool:initPool,killPool:killPool,log:log,logWithStack:logWithStack,setLogLevel:setLogLevel,enableConsoleLogging:enableConsoleLogging,enableFileLogging:enableFileLogging,shutdownCleanUp:shutdownCleanUp};export{index as default,initExport}; +import"colors";import{readFileSync,existsSync,mkdirSync,appendFile,writeFileSync}from"fs";import{isAbsolute,join}from"path";import{HttpsProxyAgent}from"https-proxy-agent";import{fileURLToPath}from"url";import dotenv from"dotenv";import{z}from"zod";import http from"http";import https from"https";import{Pool}from"tarn";import{v4}from"uuid";import puppeteer from"puppeteer";import DOMPurify from"dompurify";import{JSDOM}from"jsdom";import{readFile}from"fs/promises";import cors from"cors";import express from"express";import multer from"multer";import rateLimit from"express-rate-limit";const __dirname=fileURLToPath(new URL("../.",import.meta.url));function deepCopy(e){if(null===e||"object"!=typeof e)return e;const t=Array.isArray(e)?[]:{};for(const o in e)Object.prototype.hasOwnProperty.call(e,o)&&(t[o]=deepCopy(e[o]));return t}function fixConstr(e){try{const t=`${e.toLowerCase().replace("chart","")}Chart`;return"Chart"===t&&t.toLowerCase(),["chart","stockChart","mapChart","ganttChart"].includes(t)?t:"chart"}catch{return"chart"}}function fixOutfile(e,t){return`${getAbsolutePath(t||"chart").split(".").shift()}.${e}`}function fixType(e,t=null){const o={"image/png":"png","image/jpeg":"jpeg","application/pdf":"pdf","image/svg+xml":"svg"},n=Object.values(o);if(t){const o=t.split(".").pop();"jpg"===o?e="jpeg":n.includes(o)&&e!==o&&(e=o)}return o[e]||n.find((t=>t===e))||"png"}function getAbsolutePath(e){return isAbsolute(e)?e:join(__dirname,e)}function getBase64(e,t){return"pdf"===t||"svg"==t?Buffer.from(e,"utf8").toString("base64"):e}function getNewDate(){return(new Date).toString().split("(")[0].trim()}function getNewDateTime(){return(new Date).getTime()}function isObject(e){return"[object Object]"===Object.prototype.toString.call(e)}function isObjectEmpty(e){return"object"==typeof e&&!Array.isArray(e)&&null!==e&&0===Object.keys(e).length}function isPrivateRangeUrlFound(e){return[/xlink:href="(?:http:\/\/|https:\/\/)?localhost\b/,/xlink:href="(?:http:\/\/|https:\/\/)?10\.\d{1,3}\.\d{1,3}\.\d{1,3}\b/,/xlink:href="(?:http:\/\/|https:\/\/)?127\.\d{1,3}\.\d{1,3}\.\d{1,3}\b/,/xlink:href="(?:http:\/\/|https:\/\/)?172\.(1[6-9]|2[0-9]|3[0-1])\.\d{1,3}\.\d{1,3}\b/,/xlink:href="(?:http:\/\/|https:\/\/)?192\.168\.\d{1,3}\.\d{1,3}\b/].some((t=>t.test(e)))}function measureTime(){const e=process.hrtime.bigint();return()=>Number(process.hrtime.bigint()-e)/1e6}function roundNumber(e,t=1){const o=Math.pow(10,t||0);return Math.round(+e*o)/o}function wrapAround(e,t,o=!1){if(e&&"string"==typeof e)return(e=e.trim()).endsWith(".js")?t?wrapAround(readFileSync(getAbsolutePath(e),"utf8"),t,o):null:!o&&(e.startsWith("function()")||e.startsWith("function ()")||e.startsWith("()=>")||e.startsWith("() =>"))?`(${e})()`:e.replace(/;$/,"")}const colors=["red","yellow","blue","gray","green"],logging={toConsole:!0,toFile:!1,pathCreated:!1,pathToLog:"",levelsDesc:[{title:"error",color:colors[0]},{title:"warning",color:colors[1]},{title:"notice",color:colors[2]},{title:"verbose",color:colors[3]},{title:"benchmark",color:colors[4]}]};function log(...e){const[t,...o]=e,{levelsDesc:n,level:r}=logging;if(5!==t&&(0===t||t>r||r>n.length))return;const i=`${getNewDate()} [${n[t-1].title}] -`;logging.toFile&&_logToFile(o,i),logging.toConsole&&console.log.apply(void 0,[i.toString()[logging.levelsDesc[t-1].color]].concat(o))}function logWithStack(e,t,o){const n=o||t.message,{level:r,levelsDesc:i}=logging;if(0===e||e>r||r>i.length)return;const s=`${getNewDate()} [${i[e-1].title}] -`,a=t.stack,l=[n];a&&l.push("\n",a),logging.toFile&&_logToFile(l,s),logging.toConsole&&console.log.apply(void 0,[s.toString()[logging.levelsDesc[e-1].color]].concat([l.shift()[colors[e-1]],...l]))}function logZodIssues(e,t=[],o){logWithStack(e,null,[`${o} - the following Zod issues occured:`,...t.map((e=>`- ${e.message}`))].join("\n"))}function initLogging(e){const{level:t,dest:o,file:n,toConsole:r,toFile:i}=e;setLogLevel(t),enableConsoleLogging(r),enableFileLogging(o,n,i)}function setLogLevel(e){e>=0&&e<=logging.levelsDesc.length&&(logging.level=e)}function enableConsoleLogging(e){logging.toConsole=e}function enableFileLogging(e,t,o){logging.toFile=o,o&&(logging.dest=e,logging.file=t)}function _logToFile(e,t){logging.pathCreated||(!existsSync(getAbsolutePath(logging.dest))&&mkdirSync(getAbsolutePath(logging.dest)),logging.pathToLog=getAbsolutePath(join(logging.dest,logging.file)),logging.pathCreated=!0),appendFile(logging.pathToLog,[t].concat(e).join(" ")+"\n",(e=>{e&&logging.toFile&&logging.pathCreated&&(logging.toFile=!1,logging.pathCreated=!1,logWithStack(2,e,"[logger] Unable to write to log file."))}))}const defaultConfig={puppeteer:{args:{value:["--allow-running-insecure-content","--ash-no-nudges","--autoplay-policy=user-gesture-required","--block-new-web-contents","--disable-accelerated-2d-canvas","--disable-background-networking","--disable-background-timer-throttling","--disable-backgrounding-occluded-windows","--disable-breakpad","--disable-checker-imaging","--disable-client-side-phishing-detection","--disable-component-extensions-with-background-pages","--disable-component-update","--disable-default-apps","--disable-dev-shm-usage","--disable-domain-reliability","--disable-extensions","--disable-features=CalculateNativeWinOcclusion,InterestFeedContentSuggestions,WebOTP","--disable-hang-monitor","--disable-ipc-flooding-protection","--disable-logging","--disable-notifications","--disable-offer-store-unmasked-wallet-cards","--disable-popup-blocking","--disable-print-preview","--disable-prompt-on-repost","--disable-renderer-backgrounding","--disable-search-engine-choice-screen","--disable-session-crashed-bubble","--disable-setuid-sandbox","--disable-site-isolation-trials","--disable-speech-api","--disable-sync","--enable-unsafe-webgpu","--hide-crash-restore-bubble","--hide-scrollbars","--metrics-recording-only","--mute-audio","--no-default-browser-check","--no-first-run","--no-pings","--no-sandbox","--no-startup-window","--no-zygote","--password-store=basic","--process-per-tab","--use-mock-keychain"],types:["string[]"],envLink:"PUPPETEER_ARGS",cliName:"puppeteerArgs",description:"Array of Puppeteer arguments",promptOptions:{type:"list",separator:";"}}},highcharts:{version:{value:"latest",types:["string"],envLink:"HIGHCHARTS_VERSION",description:"Highcharts version",promptOptions:{type:"text"}},cdnUrl:{value:"https://code.highcharts.com",types:["string"],envLink:"HIGHCHARTS_CDN_URL",description:"CDN URL for Highcharts scripts",promptOptions:{type:"text"}},forceFetch:{value:!1,types:["boolean"],envLink:"HIGHCHARTS_FORCE_FETCH",description:"Flag to refetch scripts after each server rerun",promptOptions:{type:"toggle"}},cachePath:{value:".cache",types:["string"],envLink:"HIGHCHARTS_CACHE_PATH",description:"Directory path for cached Highcharts scripts",promptOptions:{type:"text"}},coreScripts:{value:["highcharts","highcharts-more","highcharts-3d"],types:["string[]"],envLink:"HIGHCHARTS_CORE_SCRIPTS",description:"Highcharts core scripts to fetch",promptOptions:{type:"multiselect",instructions:"Space: Select specific, A: Select all, Enter: Confirm"}},moduleScripts:{value:["stock","map","gantt","exporting","parallel-coordinates","accessibility","boost-canvas","boost","data","data-tools","draggable-points","static-scale","broken-axis","heatmap","tilemap","tiledwebmap","timeline","treemap","treegraph","item-series","drilldown","histogram-bellcurve","bullet","funnel","funnel3d","geoheatmap","pyramid3d","networkgraph","overlapping-datalabels","pareto","pattern-fill","pictorial","price-indicator","sankey","arc-diagram","dependency-wheel","series-label","series-on-point","solid-gauge","sonification","streamgraph","sunburst","variable-pie","variwide","vector","venn","windbarb","wordcloud","xrange","no-data-to-display","drag-panes","debugger","dumbbell","lollipop","cylinder","organization","dotplot","marker-clusters","hollowcandlestick","heikinashi","flowmap","export-data","navigator","textpath"],types:["string[]"],envLink:"HIGHCHARTS_MODULE_SCRIPTS",description:"Highcharts module scripts to fetch",promptOptions:{type:"multiselect",instructions:"Space: Select specific, A: Select all, Enter: Confirm"}},indicatorScripts:{value:["indicators-all"],types:["string[]"],envLink:"HIGHCHARTS_INDICATOR_SCRIPTS",description:"Highcharts indicator scripts to fetch",promptOptions:{type:"multiselect",instructions:"Space: Select specific, A: Select all, Enter: Confirm"}},customScripts:{value:["https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.30.1/moment.min.js","https://cdnjs.cloudflare.com/ajax/libs/moment-timezone/0.5.45/moment-timezone-with-data.min.js"],types:["string[]"],envLink:"HIGHCHARTS_CUSTOM_SCRIPTS",description:"Additional custom scripts or dependencies to fetch",promptOptions:{type:"list",separator:";"}}},export:{infile:{value:null,types:["string","null"],envLink:"EXPORT_INFILE",description:"Input filename with type, formatted correctly as JSON or SVG",promptOptions:{type:"text"}},instr:{value:null,types:["string","null"],envLink:"EXPORT_INSTR",description:"Overrides the `infile` with JSON, stringified JSON, or SVG input",promptOptions:{type:"text"}},options:{value:null,types:["Object","null"],envLink:"EXPORT_OPTIONS",description:"Alias for the `instr` option",promptOptions:{type:"text"}},svg:{value:null,types:["string","null"],envLink:"EXPORT_SVG",description:"SVG string representation of the chart to render",promptOptions:{type:"text"}},batch:{value:null,types:["string","null"],envLink:"EXPORT_BATCH",description:'Batch job string with input/output pairs: "in=out;in=out;..."',promptOptions:{type:"text"}},outfile:{value:null,types:["string","null"],envLink:"EXPORT_OUTFILE",description:"Output filename with type. Can be jpeg, png, pdf, or svg and ignores `type` option",promptOptions:{type:"text"}},type:{value:"png",types:["string"],envLink:"EXPORT_TYPE",description:"File export format. Can be jpeg, png, pdf, or svg",promptOptions:{type:"select",hint:"Default: png",choices:["png","jpeg","pdf","svg"]}},constr:{value:"chart",types:["string"],envLink:"EXPORT_CONSTR",description:"Chart constructor. Can be chart, stockChart, mapChart, or ganttChart",promptOptions:{type:"select",hint:"Default: chart",choices:["chart","stockChart","mapChart","ganttChart"]}},b64:{value:!1,types:["boolean"],envLink:"EXPORT_B64",description:"Whether or not to the chart should be received in Base64 format instead of binary",promptOptions:{type:"toggle"}},noDownload:{value:!1,types:["boolean"],envLink:"EXPORT_NO_DOWNLOAD",description:"Whether or not to include or exclude attachment headers in the response",promptOptions:{type:"toggle"}},height:{value:null,types:["number","null"],envLink:"EXPORT_HEIGHT",description:"Height of the exported chart, overrides chart settings",promptOptions:{type:"number"}},width:{value:null,types:["number","null"],envLink:"EXPORT_WIDTH",description:"Width of the exported chart, overrides chart settings",promptOptions:{type:"number"}},scale:{value:null,types:["number","null"],envLink:"EXPORT_SCALE",description:"Scale of the exported chart, overrides chart settings. Ranges from 0.1 to 5.0",promptOptions:{type:"number"}},defaultHeight:{value:400,types:["number"],envLink:"EXPORT_DEFAULT_HEIGHT",description:"Default height of the exported chart if not set",promptOptions:{type:"number"}},defaultWidth:{value:600,types:["number"],envLink:"EXPORT_DEFAULT_WIDTH",description:"Default width of the exported chart if not set",promptOptions:{type:"number"}},defaultScale:{value:1,types:["number"],envLink:"EXPORT_DEFAULT_SCALE",description:"Default scale of the exported chart if not set. Ranges from 0.1 to 5.0",promptOptions:{type:"number",min:.1,max:5}},globalOptions:{value:null,types:["Object","string","null"],envLink:"EXPORT_GLOBAL_OPTIONS",description:"JSON, stringified JSON or filename with global options for Highcharts.setOptions",promptOptions:{type:"text"}},themeOptions:{value:null,types:["Object","string","null"],envLink:"EXPORT_THEME_OPTIONS",description:"JSON, stringified JSON or filename with theme options for Highcharts.setOptions",promptOptions:{type:"text"}},rasterizationTimeout:{value:1500,types:["number"],envLink:"EXPORT_RASTERIZATION_TIMEOUT",description:"Milliseconds to wait for webpage rendering",promptOptions:{type:"number"}}},customLogic:{allowCodeExecution:{value:!1,types:["boolean"],envLink:"CUSTOM_LOGIC_ALLOW_CODE_EXECUTION",description:"Allows or disallows execution of arbitrary code during exporting",promptOptions:{type:"toggle"}},allowFileResources:{value:!1,types:["boolean"],envLink:"CUSTOM_LOGIC_ALLOW_FILE_RESOURCES",description:"Allows or disallows injection of filesystem resources (disabled in server mode)",promptOptions:{type:"toggle"}},customCode:{value:null,types:["string","null"],envLink:"CUSTOM_LOGIC_CUSTOM_CODE",description:"Custom code to execute before chart initialization. Can be a function, code wrapped in a function, or a .js filename",promptOptions:{type:"text"}},callback:{value:null,types:["string","null"],envLink:"CUSTOM_LOGIC_CALLBACK",description:"JavaScript code to run during construction. Can be a function or a .js filename",promptOptions:{type:"text"}},resources:{value:null,types:["Object","string","null"],envLink:"CUSTOM_LOGIC_RESOURCES",description:"Additional resources as JSON, stringified JSON, or filename, containing files, js, and css sections",promptOptions:{type:"text"}},loadConfig:{value:null,types:["string","null"],envLink:"CUSTOM_LOGIC_LOAD_CONFIG",legacyName:"fromFile",description:"File with a pre-defined configuration to use",promptOptions:{type:"text"}},createConfig:{value:null,types:["string","null"],envLink:"CUSTOM_LOGIC_CREATE_CONFIG",description:"Prompt-based option setting, saved to a provided config file",promptOptions:{type:"text"}}},server:{enable:{value:!1,types:["boolean"],envLink:"SERVER_ENABLE",cliName:"enableServer",description:"Starts the server when true",promptOptions:{type:"toggle"}},host:{value:"0.0.0.0",types:["string"],envLink:"SERVER_HOST",description:"Hostname of the server",promptOptions:{type:"text"}},port:{value:7801,types:["number"],envLink:"SERVER_PORT",description:"Port number for the server",promptOptions:{type:"number"}},uploadLimit:{value:3,types:["number"],envLink:"SERVER_UPLOAD_LIMIT",description:"Maximum request body size in MB",promptOptions:{type:"number"}},benchmarking:{value:!1,types:["boolean"],envLink:"SERVER_BENCHMARKING",cliName:"serverBenchmarking",description:"Displays or not action durations in milliseconds during server requests",promptOptions:{type:"toggle"}},proxy:{host:{value:null,types:["string","null"],envLink:"SERVER_PROXY_HOST",cliName:"proxyHost",description:"Host of the proxy server, if applicable",promptOptions:{type:"text"}},port:{value:null,types:["number","null"],envLink:"SERVER_PROXY_PORT",cliName:"proxyPort",description:"Port of the proxy server, if applicable",promptOptions:{type:"number"}},timeout:{value:5e3,types:["number"],envLink:"SERVER_PROXY_TIMEOUT",cliName:"proxyTimeout",description:"Timeout in milliseconds for the proxy server, if applicable",promptOptions:{type:"number"}}},rateLimiting:{enable:{value:!1,types:["boolean"],envLink:"SERVER_RATE_LIMITING_ENABLE",cliName:"enableRateLimiting",description:"Enables or disables rate limiting on the server",promptOptions:{type:"toggle"}},maxRequests:{value:10,types:["number"],envLink:"SERVER_RATE_LIMITING_MAX_REQUESTS",legacyName:"rateLimit",description:"Maximum number of requests allowed per minute",promptOptions:{type:"number"}},window:{value:1,types:["number"],envLink:"SERVER_RATE_LIMITING_WINDOW",description:"Time window in minutes for rate limiting",promptOptions:{type:"number"}},delay:{value:0,types:["number"],envLink:"SERVER_RATE_LIMITING_DELAY",description:"Delay duration between successive requests before reaching the limit",promptOptions:{type:"number"}},trustProxy:{value:!1,types:["boolean"],envLink:"SERVER_RATE_LIMITING_TRUST_PROXY",description:"Set to true if the server is behind a load balancer",promptOptions:{type:"toggle"}},skipKey:{value:null,types:["string","null"],envLink:"SERVER_RATE_LIMITING_SKIP_KEY",description:"Key to bypass the rate limiter, used with `skipToken`",promptOptions:{type:"text"}},skipToken:{value:null,types:["string","null"],envLink:"SERVER_RATE_LIMITING_SKIP_TOKEN",description:"Token to bypass the rate limiter, used with `skipKey`",promptOptions:{type:"text"}}},ssl:{enable:{value:!1,types:["boolean"],envLink:"SERVER_SSL_ENABLE",cliName:"enableSsl",description:"Enables or disables SSL protocol",promptOptions:{type:"toggle"}},force:{value:!1,types:["boolean"],envLink:"SERVER_SSL_FORCE",cliName:"sslForce",legacyName:"sslOnly",description:"Forces the server to use HTTPS only when true",promptOptions:{type:"toggle"}},port:{value:443,types:["number"],envLink:"SERVER_SSL_PORT",cliName:"sslPort",description:"Port for the SSL server",promptOptions:{type:"number"}},certPath:{value:null,types:["string","null"],envLink:"SERVER_SSL_CERT_PATH",cliName:"sslCertPath",legacyName:"sslPath",description:"Path to the SSL certificate/key file",promptOptions:{type:"text"}}}},pool:{minWorkers:{value:4,types:["number"],envLink:"POOL_MIN_WORKERS",description:"Minimum and initial number of pool workers to spawn",promptOptions:{type:"number"}},maxWorkers:{value:8,types:["number"],envLink:"POOL_MAX_WORKERS",legacyName:"workers",description:"Maximum number of pool workers to spawn",promptOptions:{type:"number"}},workLimit:{value:40,types:["number"],envLink:"POOL_WORK_LIMIT",description:"Number of tasks a worker can handle before restarting",promptOptions:{type:"number"}},acquireTimeout:{value:5e3,types:["number"],envLink:"POOL_ACQUIRE_TIMEOUT",description:"Timeout in milliseconds for acquiring a resource",promptOptions:{type:"number"}},createTimeout:{value:5e3,types:["number"],envLink:"POOL_CREATE_TIMEOUT",description:"Timeout in milliseconds for creating a resource",promptOptions:{type:"number"}},destroyTimeout:{value:5e3,types:["number"],envLink:"POOL_DESTROY_TIMEOUT",description:"Timeout in milliseconds for destroying a resource",promptOptions:{type:"number"}},idleTimeout:{value:3e4,types:["number"],envLink:"POOL_IDLE_TIMEOUT",description:"Timeout in milliseconds for destroying idle resources",promptOptions:{type:"number"}},createRetryInterval:{value:200,types:["number"],envLink:"POOL_CREATE_RETRY_INTERVAL",description:"Interval in milliseconds before retrying resource creation on failure",promptOptions:{type:"number"}},reaperInterval:{value:1e3,types:["number"],envLink:"POOL_REAPER_INTERVAL",description:"Interval in milliseconds to check and destroy idle resources",promptOptions:{type:"number"}},benchmarking:{value:!1,types:["boolean"],envLink:"POOL_BENCHMARKING",cliName:"poolBenchmarking",description:"Shows statistics for the pool of resources",promptOptions:{type:"toggle"}}},logging:{level:{value:4,types:["number"],envLink:"LOGGING_LEVEL",cliName:"logLevel",description:"Logging verbosity level",promptOptions:{type:"number",round:0,min:0,max:5}},file:{value:"highcharts-export-server.log",types:["string"],envLink:"LOGGING_FILE",cliName:"logFile",description:"Log file name. Requires `logToFile` and `logDest` to be set",promptOptions:{type:"text"}},dest:{value:"log",types:["string"],envLink:"LOGGING_DEST",cliName:"logDest",description:"Path to store log files. Requires `logToFile` to be set",promptOptions:{type:"text"}},toConsole:{value:!0,types:["boolean"],envLink:"LOGGING_TO_CONSOLE",cliName:"logToConsole",description:"Enables or disables console logging",promptOptions:{type:"toggle"}},toFile:{value:!0,types:["boolean"],envLink:"LOGGING_TO_FILE",cliName:"logToFile",description:"Enables or disables logging to a file",promptOptions:{type:"toggle"}}},ui:{enable:{value:!1,types:["boolean"],envLink:"UI_ENABLE",cliName:"enableUi",description:"Enables or disables the UI for the export server",promptOptions:{type:"toggle"}},route:{value:"/",types:["string"],envLink:"UI_ROUTE",cliName:"uiRoute",description:"The endpoint route for the UI",promptOptions:{type:"text"}}},other:{nodeEnv:{value:"production",types:["string"],envLink:"OTHER_NODE_ENV",description:"The Node.js environment type",promptOptions:{type:"text"}},listenToProcessExits:{value:!0,types:["boolean"],envLink:"OTHER_LISTEN_TO_PROCESS_EXITS",description:"Whether or not to attach process.exit handlers",promptOptions:{type:"toggle"}},noLogo:{value:!1,types:["boolean"],envLink:"OTHER_NO_LOGO",description:"Display or skip printing the logo on startup",promptOptions:{type:"toggle"}},hardResetPage:{value:!1,types:["boolean"],envLink:"OTHER_HARD_RESET_PAGE",description:"Whether or not to reset the page content entirely",promptOptions:{type:"toggle"}},browserShellMode:{value:!0,types:["boolean"],envLink:"OTHER_BROWSER_SHELL_MODE",description:"Whether or not to set the browser to run in shell mode",promptOptions:{type:"toggle"}}},debug:{enable:{value:!1,types:["boolean"],envLink:"DEBUG_ENABLE",cliName:"enableDebug",description:"Enables or disables debug mode for the underlying browser",promptOptions:{type:"toggle"}},headless:{value:!1,types:["boolean"],envLink:"DEBUG_HEADLESS",description:"Whether or not to set the browser to run in headless mode during debugging",promptOptions:{type:"toggle"}},devtools:{value:!1,types:["boolean"],envLink:"DEBUG_DEVTOOLS",description:"Enables or disables DevTools in headful mode",promptOptions:{type:"toggle"}},listenToConsole:{value:!1,types:["boolean"],envLink:"DEBUG_LISTEN_TO_CONSOLE",description:"Enables or disables listening to console messages from the browser",promptOptions:{type:"toggle"}},dumpio:{value:!1,types:["boolean"],envLink:"DEBUG_DUMPIO",description:"Redirects or not browser stdout and stderr to process.stdout and process.stderr",promptOptions:{type:"toggle"}},slowMo:{value:0,types:["number"],envLink:"DEBUG_SLOW_MO",description:"Delays Puppeteer operations by the specified milliseconds",promptOptions:{type:"number"}},debuggingPort:{value:9222,types:["number"],envLink:"DEBUG_DEBUGGING_PORT",description:"Port used for debugging",promptOptions:{type:"number"}}}},nestedProps=_createNestedProps(defaultConfig),absoluteProps=_createAbsoluteProps(defaultConfig);function _createNestedProps(e,t={},o=""){return Object.keys(e).forEach((n=>{const r=e[n];void 0===r.value?_createNestedProps(r,t,`${o}.${n}`):(t[r.cliName||n]=`${o}.${n}`.substring(1),void 0!==r.legacyName&&(t[r.legacyName]=`${o}.${n}`.substring(1)))})),t}function _createAbsoluteProps(e,t=[]){return Object.keys(e).forEach((o=>{const n=e[o];void 0===n.types?_createAbsoluteProps(n,t):n.types.includes("Object")&&t.push(o)})),t}dotenv.config();const{coreScripts:coreScripts,moduleScripts:moduleScripts,indicatorScripts:indicatorScripts}=defaultConfig.highcharts;z.setErrorMap(_customErrorMap);const v={boolean:e=>e?z.boolean():z.union([z.enum(["true","false","undefined","null",""]).transform((e=>["undefined","null",""].includes(e)?null:"true"===e)),z.boolean()]).nullable(),string:e=>e?z.string().trim().refine((e=>!["false","undefined","null",""].includes(e)),{params:{errorMessage:"The string contains a forbidden value"}}):z.string().trim().transform((e=>["false","undefined","null",""].includes(e)?null:e)).nullable(),enum:(e,t)=>t?z.enum([...e]):z.enum([...e,"undefined","null",""]).transform((e=>["undefined","null",""].includes(e)?null:e)).nullable(),stringArray(e,t,o){const n=z.string().trim().array(),r=z.string().trim().transform((e=>(e.startsWith("[")&&(e=e.slice(1)),e.endsWith("]")&&(e=e.slice(0,-1)),e.split(t)))),i=t=>t.map((e=>e.trim())).filter(e);return o?n.transform(i):z.union([r,n]).transform(i).transform((e=>e.length?e:null)).nullable()},positiveNum:e=>e?z.number().positive():z.union([z.string().trim().refine((e=>!isNaN(Number(e))&&Number(e)>0||["undefined","null",""].includes(e)),{params:{errorMessage:"The value must be numeric and positive"}}).transform((e=>["undefined","null",""].includes(e)?null:Number(e))),z.number().positive()]).nullable(),nonNegativeNum:e=>e?z.number().nonnegative():z.union([z.string().trim().refine((e=>!isNaN(Number(e))&&Number(e)>=0||["undefined","null",""].includes(e)),{params:{errorMessage:"The value must be numeric and non-negative"}}).transform((e=>["undefined","null",""].includes(e)?null:Number(e))),z.number().nonnegative()]).nullable(),startsWith:(e,t)=>t?z.string().trim().refine((t=>e.some((e=>t.startsWith(e)))),{params:{errorMessage:`The value must be a string that starts with ${e.join(", ")}`}}):z.string().trim().refine((t=>e.some((e=>t.startsWith(e)))||["undefined","null",""].includes(t)),{params:{errorMessage:`The value must be a string that starts with ${e.join(", ")}`}}).transform((e=>["undefined","null",""].includes(e)?null:e)).nullable(),chartConfig:()=>z.union([z.string().trim().refine((e=>e.indexOf("=0||e.indexOf("=0||e.startsWith("{")&&e.endsWith("}")||["undefined","null",""].includes(e)),{params:{errorMessage:"The value must be a string that contains '["undefined","null",""].includes(e)?null:e)),z.object({}).passthrough()]).nullable(),additionalOptions:()=>z.union([z.string().trim().refine((e=>e.length>=6&&e.endsWith(".json")||e.startsWith("{")&&e.endsWith("}")||["undefined","null",""].includes(e)),{params:{errorMessage:"The value must be a string that ends with '.json' or starts with '{' and ends with '}'"}}).transform((e=>["undefined","null",""].includes(e)?null:e)),z.object({}).passthrough()]).nullable()},config={args:e=>v.stringArray((e=>!["false","undefined","null",""].includes(e)),";",e),version:e=>e?z.string().trim().refine((e=>/^(latest|\d{1,2}(\.\d{1,2}){0,2})$/.test(e)),{params:{errorMessage:"The value must be 'latest', a major version, or in the form XX.YY.ZZ"}}):z.string().trim().refine((e=>/^(latest|\d{1,2}(\.\d{1,2}){0,2})$/.test(e)||["undefined","null",""].includes(e)),{params:{errorMessage:"The value must be 'latest', a major version, or in the form XX.YY.ZZ"}}).transform((e=>["undefined","null",""].includes(e)?null:e)).nullable(),cdnUrl:e=>v.startsWith(["http://","https://"],e),forceFetch:e=>v.boolean(e),cachePath:e=>v.string(e),adminToken:e=>v.string(e),coreScripts:e=>v.stringArray((e=>coreScripts.value.includes(e)),",",e),moduleScripts:e=>v.stringArray((e=>moduleScripts.value.includes(e)),",",e),indicatorScripts:e=>v.stringArray((e=>indicatorScripts.value.includes(e)),",",e),customScripts:e=>v.stringArray((e=>e.startsWith("https://")||e.startsWith("http://")),",",e),infile:e=>e?z.string().trim().refine((e=>e.length>=6&&e.endsWith(".json")||e.length>=5&&e.endsWith(".svg")),{params:{errorMessage:"The value must be a string that ends with .json or .svg"}}).nullable():z.string().trim().refine((e=>e.length>=6&&e.endsWith(".json")||e.length>=5&&e.endsWith(".svg")||["undefined","null",""].includes(e)),{params:{errorMessage:"The value must be a string that ends with .json or .svg"}}).transform((e=>["undefined","null",""].includes(e)?null:e)).nullable(),instr:()=>v.chartConfig(),options:()=>v.chartConfig(),svg:()=>z.string().trim().refine((e=>e.indexOf("=0||e.indexOf("=0||["false","undefined","null",""].includes(e)),{params:{errorMessage:"The value must be a string that contains '["false","undefined","null",""].includes(e)?null:e)).nullable(),outfile:e=>e?z.string().trim().refine((e=>e.length>=6&&e.endsWith(".jpeg")||e.length>=5&&(e.endsWith(".jpg")||e.endsWith(".png")||e.endsWith(".pdf")||e.endsWith(".svg"))),{params:{errorMessage:"The value must be a string that ends with .jpeg, .jpg, .png, .pdf, or .svg"}}).nullable():z.string().trim().refine((e=>e.length>=6&&e.endsWith(".jpeg")||e.length>=5&&(e.endsWith(".jpg")||e.endsWith(".png")||e.endsWith(".pdf")||e.endsWith(".svg"))||["undefined","null",""].includes(e)),{params:{errorMessage:"The value must be a string that ends with .jpeg, .jpg, .png, .pdf, or .svg"}}).transform((e=>["undefined","null",""].includes(e)?null:e)).nullable(),type:e=>v.enum(["jpeg","jpg","png","pdf","svg"],e),constr:e=>v.enum(["chart","stockChart","mapChart","ganttChart"],e),b64:e=>v.boolean(e),noDownload:e=>v.boolean(e),defaultHeight:e=>v.positiveNum(e),defaultWidth:e=>v.positiveNum(e),defaultScale:e=>e?z.number().gte(.1).lte(5):z.union([z.string().trim().refine((e=>!isNaN(Number(e))&&!0!==e&&!e.startsWith("[")&&Number(e)>=.1&&Number(e)<=5||["undefined","null",""].includes(e)),{params:{errorMessage:"The value must be within a 0.1 and 5.0 range"}}).transform((e=>["undefined","null",""].includes(e)?null:Number(e))),z.number().gte(.1).lte(5)]).nullable(),height(e){return this.defaultHeight(e).nullable()},width(e){return this.defaultWidth(e).nullable()},scale(e){return this.defaultScale(e).nullable()},globalOptions:()=>v.additionalOptions(),themeOptions:()=>v.additionalOptions(),batch:e=>v.string(e),rasterizationTimeout:e=>v.nonNegativeNum(e),allowCodeExecution:e=>v.boolean(e),allowFileResources:e=>v.boolean(e),customCode:e=>v.string(e),callback:e=>v.string(e),resources(e){const t=z.object({js:v.string(!1),css:v.string(!1),files:v.stringArray((e=>!["undefined","null",""].includes(e)),",",!0).nullable()}).partial(),o=z.string().trim().refine((e=>e.startsWith("{")&&e.endsWith("}")||e.length>=6&&e.endsWith(".json")),{params:{errorMessage:"The value must be a string that starts with '{' and ends with '}"}}),n=z.string().trim().refine((e=>e.startsWith("{")&&e.endsWith("}")||e.length>=6&&e.endsWith(".json")||["undefined","null",""].includes(e)),{params:{errorMessage:"The value must be a string that ends with '.json'"}}).transform((e=>["undefined","null",""].includes(e)?null:e));return e?z.union([t,o]).nullable():z.union([t,n]).nullable()},loadConfig:e=>v.string(e).refine((e=>null===e||e.length>=6&&e.endsWith(".json")),{params:{errorMessage:"The value must be a string that ends with .json "}}),createConfig(e){return this.loadConfig(e)},enableServer:e=>v.boolean(e),host:e=>v.string(e),port:e=>v.nonNegativeNum(e),uploadLimit:e=>v.positiveNum(e),serverBenchmarking:e=>v.boolean(e),proxyHost:e=>v.string(e),proxyPort:e=>v.nonNegativeNum(e).nullable(),proxyTimeout:e=>v.nonNegativeNum(e),enableRateLimiting:e=>v.boolean(e),maxRequests:e=>v.nonNegativeNum(e),window:e=>v.nonNegativeNum(e),delay:e=>v.nonNegativeNum(e),trustProxy:e=>v.boolean(e),skipKey:e=>v.string(e),skipToken:e=>v.string(e),enableSsl:e=>v.boolean(e),sslForce:e=>v.boolean(e),sslPort:e=>v.nonNegativeNum(e),sslCertPath:e=>v.string(e),minWorkers:e=>v.positiveNum(e),maxWorkers:e=>v.positiveNum(e),workLimit:e=>v.positiveNum(e),acquireTimeout:e=>v.nonNegativeNum(e),createTimeout:e=>v.nonNegativeNum(e),destroyTimeout:e=>v.nonNegativeNum(e),idleTimeout:e=>v.nonNegativeNum(e),createRetryInterval:e=>v.nonNegativeNum(e),reaperInterval:e=>v.nonNegativeNum(e),poolBenchmarking:e=>v.boolean(e),resourcesInterval:e=>v.nonNegativeNum(e),logLevel:e=>e?z.number().int().gte(0).lte(5):z.union([z.string().trim().refine((e=>!isNaN(Number(e))&&!0!==e&&!e.startsWith("[")&&Number.isInteger(Number(e))&&Number(e)>=0&&Number(e)<=5||["undefined","null",""].includes(e)),{params:{errorMessage:"The value must be within a 0 and 5 range"}}).transform((e=>["undefined","null",""].includes(e)?null:Number(e))),z.number().int().gte(0).lte(5)]).nullable(),logFile:e=>v.string(e).refine((e=>null===e||e.length>=5&&e.endsWith(".log")),{params:{errorMessage:"The value must be a string that ends with '.log'"}}),logDest:e=>v.string(e),logToConsole:e=>v.boolean(e),logToFile:e=>v.boolean(e),enableUi:e=>v.boolean(e),uiRoute:e=>v.startsWith(["/"],e),nodeEnv:e=>v.enum(["development","production","test"],e),listenToProcessExits:e=>v.boolean(e),noLogo:e=>v.boolean(e),hardResetPage:e=>v.boolean(e),browserShellMode:e=>v.boolean(e),enableDebug:e=>v.boolean(e),headless:e=>v.boolean(e),devtools:e=>v.boolean(e),listenToConsole:e=>v.boolean(e),dumpio:e=>v.boolean(e),slowMo:e=>v.nonNegativeNum(e),debuggingPort:e=>v.nonNegativeNum(e),requestId:()=>z.string().uuid({message:"The value must be a stringified UUID"}).nullable()},PuppeteerSchema=e=>z.object({args:config.args(e)}).partial(),HighchartsSchema=e=>z.object({version:config.version(e),cdnUrl:config.cdnUrl(e),forceFetch:config.forceFetch(e),cachePath:config.cachePath(e),coreScripts:config.coreScripts(e),moduleScripts:config.moduleScripts(e),indicatorScripts:config.indicatorScripts(e),customScripts:config.customScripts(e)}).partial(),ExportSchema=e=>z.object({infile:config.infile(e),instr:config.instr(),options:config.options(),svg:config.svg(),outfile:config.outfile(e),type:config.type(e),constr:config.constr(e),b64:config.b64(e),noDownload:config.noDownload(e),defaultHeight:config.defaultHeight(e),defaultWidth:config.defaultWidth(e),defaultScale:config.defaultScale(e),height:config.height(e),width:config.width(e),scale:config.scale(e),globalOptions:config.globalOptions(),themeOptions:config.themeOptions(),batch:config.batch(!1),rasterizationTimeout:config.rasterizationTimeout(e)}).partial(),CustomLogicSchema=e=>z.object({allowCodeExecution:config.allowCodeExecution(e),allowFileResources:config.allowFileResources(e),customCode:config.customCode(!1),callback:config.callback(!1),resources:config.resources(e),loadConfig:config.loadConfig(!1),createConfig:config.createConfig(!1)}).partial(),ProxySchema=e=>z.object({host:config.proxyHost(!1),port:config.proxyPort(e),timeout:config.proxyTimeout(e)}).partial(),RateLimitingSchema=e=>z.object({enable:config.enableRateLimiting(e),maxRequests:config.maxRequests(e),window:config.window(e),delay:config.delay(e),trustProxy:config.trustProxy(e),skipKey:config.skipKey(!1),skipToken:config.skipToken(!1)}).partial(),SslSchema=e=>z.object({enable:config.enableSsl(e),force:config.sslForce(e),port:config.sslPort(e),certPath:config.sslCertPath(!1)}).partial(),ServerSchema=e=>z.object({enable:config.enableServer(e).optional(),host:config.host(e).optional(),port:config.port(e).optional(),benchmarking:config.serverBenchmarking(e).optional(),proxy:ProxySchema(e).optional(),rateLimiting:RateLimitingSchema(e).optional(),ssl:SslSchema(e).optional()}),PoolSchema=e=>z.object({minWorkers:config.minWorkers(e),maxWorkers:config.maxWorkers(e),workLimit:config.workLimit(e),acquireTimeout:config.acquireTimeout(e),createTimeout:config.createTimeout(e),destroyTimeout:config.destroyTimeout(e),idleTimeout:config.idleTimeout(e),createRetryInterval:config.createRetryInterval(e),reaperInterval:config.reaperInterval(e),benchmarking:config.poolBenchmarking(e)}).partial(),LoggingSchema=e=>z.object({level:config.logLevel(e),file:config.logFile(e),dest:config.logDest(e),toConsole:config.logToConsole(e),toFile:config.logToFile(e)}).partial(),UiSchema=e=>z.object({enable:config.enableUi(e),route:config.uiRoute(e)}).partial(),OtherSchema=e=>z.object({nodeEnv:config.nodeEnv(e),listenToProcessExits:config.listenToProcessExits(e),noLogo:config.noLogo(e),hardResetPage:config.hardResetPage(e),browserShellMode:config.browserShellMode(e)}).partial(),DebugSchema=e=>z.object({enable:config.enableDebug(e),headless:config.headless(e),devtools:config.devtools(e),listenToConsole:config.listenToConsole(e),dumpio:config.dumpio(e),slowMo:config.slowMo(e),debuggingPort:config.debuggingPort(e)}).partial(),StrictConfigSchema=z.object({puppeteer:PuppeteerSchema(!0),highcharts:HighchartsSchema(!0),export:ExportSchema(!0),customLogic:CustomLogicSchema(!0),server:ServerSchema(!0),pool:PoolSchema(!0),logging:LoggingSchema(!0),ui:UiSchema(!0),other:OtherSchema(!0),debug:DebugSchema(!0)}),LooseConfigSchema=z.object({puppeteer:PuppeteerSchema(!1),highcharts:HighchartsSchema(!1),export:ExportSchema(!1),customLogic:CustomLogicSchema(!1),server:ServerSchema(!1),pool:PoolSchema(!1),logging:LoggingSchema(!1),ui:UiSchema(!1),other:OtherSchema(!1),debug:DebugSchema(!1)}),EnvSchema=z.object({PUPPETEER_ARGS:config.args(!1),HIGHCHARTS_VERSION:config.version(!1),HIGHCHARTS_CDN_URL:config.cdnUrl(!1),HIGHCHARTS_FORCE_FETCH:config.forceFetch(!1),HIGHCHARTS_CACHE_PATH:config.cachePath(!1),HIGHCHARTS_ADMIN_TOKEN:config.adminToken(!1),HIGHCHARTS_CORE_SCRIPTS:config.coreScripts(!1),HIGHCHARTS_MODULE_SCRIPTS:config.moduleScripts(!1),HIGHCHARTS_INDICATOR_SCRIPTS:config.indicatorScripts(!1),HIGHCHARTS_CUSTOM_SCRIPTS:config.customScripts(!1),EXPORT_INFILE:config.infile(!1),EXPORT_INSTR:config.instr(),EXPORT_OPTIONS:config.options(),EXPORT_SVG:config.svg(),EXPORT_BATCH:config.batch(!1),EXPORT_OUTFILE:config.outfile(!1),EXPORT_TYPE:config.type(!1),EXPORT_CONSTR:config.constr(!1),EXPORT_B64:config.b64(!1),EXPORT_NO_DOWNLOAD:config.noDownload(!1),EXPORT_HEIGHT:config.height(!1),EXPORT_WIDTH:config.width(!1),EXPORT_SCALE:config.scale(!1),EXPORT_DEFAULT_HEIGHT:config.defaultHeight(!1),EXPORT_DEFAULT_WIDTH:config.defaultWidth(!1),EXPORT_DEFAULT_SCALE:config.defaultScale(!1),EXPORT_GLOBAL_OPTIONS:config.globalOptions(),EXPORT_THEME_OPTIONS:config.themeOptions(),EXPORT_RASTERIZATION_TIMEOUT:config.rasterizationTimeout(!1),CUSTOM_LOGIC_ALLOW_CODE_EXECUTION:config.allowCodeExecution(!1),CUSTOM_LOGIC_ALLOW_FILE_RESOURCES:config.allowFileResources(!1),CUSTOM_LOGIC_CUSTOM_CODE:config.customCode(!1),CUSTOM_LOGIC_CALLBACK:config.callback(!1),CUSTOM_LOGIC_RESOURCES:config.resources(!1),CUSTOM_LOGIC_LOAD_CONFIG:config.loadConfig(!1),CUSTOM_LOGIC_CREATE_CONFIG:config.createConfig(!1),SERVER_ENABLE:config.enableServer(!1),SERVER_HOST:config.host(!1),SERVER_PORT:config.port(!1),SERVER_UPLOAD_LIMIT:config.uploadLimit(!1),SERVER_BENCHMARKING:config.serverBenchmarking(!1),SERVER_PROXY_HOST:config.proxyHost(!1),SERVER_PROXY_PORT:config.proxyPort(!1),SERVER_PROXY_TIMEOUT:config.proxyTimeout(!1),SERVER_RATE_LIMITING_ENABLE:config.enableRateLimiting(!1),SERVER_RATE_LIMITING_MAX_REQUESTS:config.maxRequests(!1),SERVER_RATE_LIMITING_WINDOW:config.window(!1),SERVER_RATE_LIMITING_DELAY:config.delay(!1),SERVER_RATE_LIMITING_TRUST_PROXY:config.trustProxy(!1),SERVER_RATE_LIMITING_SKIP_KEY:config.skipKey(!1),SERVER_RATE_LIMITING_SKIP_TOKEN:config.skipToken(!1),SERVER_SSL_ENABLE:config.enableSsl(!1),SERVER_SSL_FORCE:config.sslForce(!1),SERVER_SSL_PORT:config.sslPort(!1),SERVER_SSL_CERT_PATH:config.sslCertPath(!1),POOL_MIN_WORKERS:config.minWorkers(!1),POOL_MAX_WORKERS:config.maxWorkers(!1),POOL_WORK_LIMIT:config.workLimit(!1),POOL_ACQUIRE_TIMEOUT:config.acquireTimeout(!1),POOL_CREATE_TIMEOUT:config.createTimeout(!1),POOL_DESTROY_TIMEOUT:config.destroyTimeout(!1),POOL_IDLE_TIMEOUT:config.idleTimeout(!1),POOL_CREATE_RETRY_INTERVAL:config.createRetryInterval(!1),POOL_REAPER_INTERVAL:config.reaperInterval(!1),POOL_BENCHMARKING:config.poolBenchmarking(!1),LOGGING_LEVEL:config.logLevel(!1),LOGGING_FILE:config.logFile(!1),LOGGING_DEST:config.logDest(!1),LOGGING_TO_CONSOLE:config.logToConsole(!1),LOGGING_TO_FILE:config.logToFile(!1),UI_ENABLE:config.enableUi(!1),UI_ROUTE:config.uiRoute(!1),OTHER_NODE_ENV:config.nodeEnv(!1),OTHER_LISTEN_TO_PROCESS_EXITS:config.listenToProcessExits(!1),OTHER_NO_LOGO:config.noLogo(!1),OTHER_HARD_RESET_PAGE:config.hardResetPage(!1),OTHER_BROWSER_SHELL_MODE:config.browserShellMode(!1),DEBUG_ENABLE:config.enableDebug(!1),DEBUG_HEADLESS:config.headless(!1),DEBUG_DEVTOOLS:config.devtools(!1),DEBUG_LISTEN_TO_CONSOLE:config.listenToConsole(!1),DEBUG_DUMPIO:config.dumpio(!1),DEBUG_SLOW_MO:config.slowMo(!1),DEBUG_DEBUGGING_PORT:config.debuggingPort(!1)}),envs=EnvSchema.partial().parse(process.env);function strictValidate(e){return StrictConfigSchema.partial().parse(e)}function looseValidate(e){return LooseConfigSchema.partial().parse(e)}function validateOption(e,t,o){return config[e](o).parse(t)}function _customErrorMap(e,t){const o=e.path.join("."),n=`Invalid value for the ${o}`;if(e.code===z.ZodIssueCode.invalid_type)return e.received===z.ZodParsedType.undefined?{message:`${n} - No value was provided.`}:{message:`${n} - Invalid type. ${t.defaultError}.`};if(e.code===z.ZodIssueCode.custom&&e.params?.errorMessage)return{message:`${n} - ${e.params?.errorMessage}, received '${t.data}'.`};if(e.code===z.ZodIssueCode.invalid_union){let t=`Multiple errors occurred for the ${o}:\n`;return e.unionErrors.forEach((e=>{const o=e.issues[0].message.indexOf("-");t+=-1!==o?`${e.issues[0].message}\n`.substring(o):`${e.issues[0].message}\n`})),{message:t}}return{message:`${n} - ${t.defaultError}.`}}const globalOptions=_initGlobalOptions(defaultConfig);function getOptions(e=!0){return e?globalOptions:deepCopy(globalOptions)}function setOptions(e={},t=[],o=!1){let n={},r={};if(t.length)try{n=strictValidate(_loadConfigFile(t))}catch(e){logZodIssues(1,e.issues,"[config] Custom JSON options validation error")}if(e&&0!==Object.keys(e).length)try{e=strictValidate(e)}catch(e){logZodIssues(1,e.issues,"[config] Custom options validation error")}if(t.length)try{r=looseValidate(_pairArgumentValue(nestedProps,t))}catch(e){logZodIssues(1,e.issues,"[config] CLI options validation error")}const i=getOptions(o);return _updateOptions(defaultConfig,i,n,e,r),i}function mergeOptions(e,t){if(isObject(t))for(const[o,n]of Object.entries(t))e[o]=isObject(n)&&!absoluteProps.includes(o)&&void 0!==e[o]?mergeOptions(e[o],n):void 0!==n?n:e[o];return e}function mapToNewOptions(e){const t={};if("[object Object]"===Object.prototype.toString.call(e))for(const[o,n]of Object.entries(e)){const e=nestedProps[o]?nestedProps[o].split("."):[];e.reduce(((t,o,r)=>t[o]=e.length-1===r?n:t[o]||{}),t)}return t}function isAllowedConfig(config,toString=!1,allowFunctions=!1){try{if(!isObject(config)&&"string"!=typeof config)return null;const objectConfig="string"==typeof config?allowFunctions?eval(`(${config})`):JSON.parse(config):config,stringifiedOptions=_optionsStringify(objectConfig,allowFunctions,!1),parsedOptions=allowFunctions?JSON.parse(_optionsStringify(objectConfig,allowFunctions,!0),((_,value)=>"string"==typeof value&&value.startsWith("function")?eval(`(${value})`):value)):JSON.parse(stringifiedOptions);return toString?stringifiedOptions:parsedOptions}catch(e){return null}}function _initGlobalOptions(e){const t={};for(const[o,n]of Object.entries(e))t[o]=Object.prototype.hasOwnProperty.call(n,"value")?n.value:_initGlobalOptions(n);return t}function _updateOptions(e,t,o,n,r){Object.keys(e).forEach((i=>{const s=e[i],a=o&&o[i],l=n&&n[i],c=r&&r[i];if(void 0===s.value)_updateOptions(s,t[i],a,l,c);else{null!=a&&(t[i]=a);const e=envs[s.envLink];s.envLink in envs&&null!=e&&(t[i]=e),null!=l&&(t[i]=l),null!=c&&(t[i]=c)}}))}function _optionsStringify(e,t,o){return JSON.stringify(e,((e,n)=>{if("string"==typeof n&&(n=n.trim()),"function"==typeof n||"string"==typeof n&&n.startsWith("function")&&n.endsWith("}")){if(t)return o?`"EXP_FUN${(n+"").replaceAll(/\s+/g," ")}EXP_FUN"`:`EXP_FUN${(n+"").replaceAll(/\s+/g," ")}EXP_FUN`;throw new Error}return n})).replaceAll(o?/\\"EXP_FUN|EXP_FUN\\"/g:/"EXP_FUN|EXP_FUN"/g,"")}function _loadConfigFile(e){const t=e.findIndex((e=>"loadConfig"===e.replace(/-/g,""))),o=t>-1&&e[t+1];if(o)try{return JSON.parse(readFileSync(getAbsolutePath(o)))}catch(e){logWithStack(2,e,`[config] Unable to load the configuration from the ${o} file.`)}return{}}function _pairArgumentValue(e,t){const o={};for(let n=0;n{if(i.length-1===s){const i=t[++n];i||log(2,`[config] Missing value for the CLI '--${r}' argument. Using the default value.`),e[o]=i||null}else void 0===e[o]&&(e[o]={});return e[o]}),o)}return o}async function fetch(e,t={}){return new Promise(((o,n)=>{_getProtocolModule(e).get(e,t,(e=>{let t="";e.on("data",(e=>{t+=e})),e.on("end",(()=>{t||n("Nothing was fetched from the URL."),e.text=t,o(e)}))})).on("error",(e=>{n(e)}))}))}function _getProtocolModule(e){return e.startsWith("https")?https:http}class ExportError extends Error{constructor(e,t){super(),this.message=e,this.stackMessage=e,t&&(this.statusCode=t)}setError(e){return this.error=e,e.name&&(this.name=e.name),e.statusCode&&(this.statusCode=e.statusCode),e.stack&&(this.stackMessage=e.message,this.stack=e.stack),this}}const cache={cdnUrl:"https://code.highcharts.com",activeManifest:{},sources:"",hcVersion:""};async function checkAndUpdateCache(e,t){let o;const n=getCachePath(),r=join(n,"manifest.json"),i=join(n,"sources.js");if(!existsSync(n)&&mkdirSync(n,{recursive:!0}),!existsSync(r)||e.forceFetch)log(3,"[cache] Fetching and caching Highcharts dependencies."),o=await _updateCache(e,t,i);else{let n=!1;const s=JSON.parse(readFileSync(r));if(s.modules&&Array.isArray(s.modules)){const e={};s.modules.forEach((t=>e[t]=1)),s.modules=e}const{coreScripts:a,moduleScripts:l,indicatorScripts:c}=e,p=a.length+l.length+c.length;s.version!==e.version?(log(2,"[cache] A Highcharts version mismatch in the cache, need to re-fetch."),n=!0):Object.keys(s.modules||{}).length!==p?(log(2,"[cache] The cache and the requested modules do not match, need to re-fetch."),n=!0):n=(l||[]).some((e=>{if(!s.modules[e])return log(2,`[cache] The ${e} is missing in the cache, need to re-fetch.`),!0})),n?o=await _updateCache(e,t,i):(log(3,"[cache] Dependency cache is up to date, proceeding."),cache.sources=readFileSync(i,"utf8"),o=s.modules,cache.hcVersion=extractVersion(cache.sources))}await _saveConfigToManifest(e,o)}function getHighchartsVersion(){return cache.hcVersion}async function updateHighchartsVersion(e){const t=getOptions();t.highcharts.version=e,await checkAndUpdateCache(t.highcharts,t.server.proxy)}function extractVersion(e){return e.substring(0,e.indexOf("*/")).replace("/*","").replace("*/","").replace(/\n/g,"").trim()}function extractModuleName(e){return e.replace(/(.*)\/|(.*)modules\/|stock\/(.*)indicators\/|maps\/(.*)modules\//gi,"")}function getCachePath(){return getAbsolutePath(getOptions().highcharts.cachePath)}async function _fetchAndProcessScript(e,t,o,n=!1){e.endsWith(".js")&&(e=e.substring(0,e.length-3)),log(4,`[cache] Fetching script - ${e}.js`);const r=await fetch(`${e}.js`,t);if(200===r.statusCode&&"string"==typeof r.text){if(o){o[extractModuleName(e)]=1}return r.text}if(n)throw new ExportError(`[cache] Could not fetch the ${e}.js. The script might not exist in the requested version (status code: ${r.statusCode}).`,404).setError(r);log(2,`[cache] Could not fetch the ${e}.js. The script might not exist in the requested version.`)}async function _saveConfigToManifest(e,t={}){const o={version:e.version,modules:t};cache.activeManifest=o,log(3,"[cache] Writing a new manifest.");try{writeFileSync(join(getCachePath(),"manifest.json"),JSON.stringify(o),"utf8")}catch(e){throw new ExportError("[cache] Error writing the cache manifest.",500).setError(e)}}async function _fetchScripts(e,t,o,n,r){let i;const s=n.host,a=n.port;if(s&&a)try{i=new HttpsProxyAgent({host:s,port:a})}catch(e){throw new ExportError("[cache] Could not create a Proxy Agent.",500).setError(e)}const l=i?{agent:i,timeout:n.timeout}:{},c=[...e.map((e=>_fetchAndProcessScript(`${e}`,l,r,!0))),...t.map((e=>_fetchAndProcessScript(`${e}`,l,r))),...o.map((e=>_fetchAndProcessScript(`${e}`,l)))];return(await Promise.all(c)).join(";\n")}async function _updateCache(e,t,o){const n="latest"===e.version?null:`${e.version}`,r=e.cdnUrl||cache.cdnUrl;try{const i={};return log(3,`[cache] Updating cache version to Highcharts: ${n||"latest"}.`),cache.sources=await _fetchScripts([...e.coreScripts.map((e=>n?`${r}/${n}/${e}`:`${r}/${e}`))],[...e.moduleScripts.map((e=>"map"===e?n?`${r}/maps/${n}/modules/${e}`:`${r}/maps/modules/${e}`:n?`${r}/${n}/modules/${e}`:`${r}/modules/${e}`)),...e.indicatorScripts.map((e=>n?`${r}/stock/${n}/indicators/${e}`:`${r}/stock/indicators/${e}`))],e.customScripts,t,i),cache.hcVersion=extractVersion(cache.sources),writeFileSync(o,cache.sources),i}catch(e){throw new ExportError("[cache] Unable to update the local Highcharts cache.",500).setError(e)}}function setupHighcharts(){Highcharts.animObject=function(){return{duration:0}}}async function createChart(e){const{getOptions:t,merge:o,setOptions:n,wrap:r}=Highcharts;Highcharts.setOptionsObj=o(!1,{},t()),window.isRenderComplete=!1,r(Highcharts.Chart.prototype,"init",(function(e,t,n){((t=o(t,{exporting:{enabled:!1},plotOptions:{series:{label:{enabled:!1}}},tooltip:{}})).series||[]).forEach((function(e){e.animation=!1})),window.onHighchartsRender||(window.onHighchartsRender=Highcharts.addEvent(this,"render",(()=>{window.isRenderComplete=!0}))),e.apply(this,[t,n])})),r(Highcharts.Series.prototype,"init",(function(e,t,o){e.apply(this,[t,o])}));const i={chart:{animation:!1,height:e.export.height,width:e.export.width},exporting:{enabled:!1}},s=new Function(`return ${e.export.instr}`)(),a=new Function(`return ${e.export.themeOptions}`)(),l=new Function(`return ${e.export.globalOptions}`)(),c=o(!1,a,s,i),p=e.customLogic.callback?new Function(`return ${e.customLogic.callback}`)():null;e.customLogic.customCode&&new Function("options",e.customLogic.customCode)(s),l&&n(l),Highcharts[e.export.constr]("container",c,p);const u=t();for(const e in u)"function"!=typeof u[e]&&delete u[e];n(Highcharts.setOptionsObj),Highcharts.setOptionsObj={}}const template=readFileSync(join(__dirname,"templates","template.html"),"utf8");let browser=null;async function createBrowser(e){const{debug:t,other:o}=getOptions(),{enable:n,...r}=t,i={headless:!o.browserShellMode||"shell",userDataDir:"tmp",args:e||[],handleSIGINT:!1,handleSIGTERM:!1,handleSIGHUP:!1,waitForInitialPage:!1,defaultViewport:null,...n&&r};if(!browser){let e=0;const t=async()=>{try{log(3,`[browser] Attempting to get a browser instance (try ${++e}).`),browser=await puppeteer.launch(i)}catch(o){if(logWithStack(1,o,"[browser] Failed to launch a browser instance."),!(e<25))throw o;log(3,`[browser] Retry to open a browser (${e} out of 25).`),await new Promise((e=>setTimeout(e,4e3))),await t()}};try{await t(),"shell"===i.headless&&log(3,"[browser] Launched browser in shell mode."),n&&log(3,"[browser] Launched browser in debug mode.")}catch(e){throw new ExportError("[browser] Maximum retries to open a browser instance reached.",500).setError(e)}if(!browser)throw new ExportError("[browser] Cannot find a browser to open.",500)}return browser}async function closeBrowser(){browser&&browser.connected&&await browser.close(),browser=null,log(4,"[browser] Closed the browser.")}async function newPage(e){if(!browser||!browser.connected)throw new ExportError("[browser] Browser is not yet connected.",500);if(e.page=await browser.newPage(),await e.page.setCacheEnabled(!1),await _setPageContent(e.page),_setPageEvents(e.page),!e.page||e.page.isClosed())throw new ExportError("[browser] The page is invalid or closed.",400)}async function clearPage(e,t=!1){try{if(e.page&&!e.page.isClosed())return t?(await e.page.goto("about:blank",{waitUntil:"domcontentloaded"}),await _setPageContent(e.page)):await e.page.evaluate((()=>{document.body.innerHTML='
'})),!0}catch(t){logWithStack(2,t,`[pool] Pool resource [${e.id}] - Content of the page could not be cleared.`),e.workCount=getOptions().pool.workLimit+1}return!1}async function addPageResources(e,t){const o=[],n=t.resources;if(n){const r=[];if(n.js&&r.push({content:n.js}),n.files)for(const e of n.files){const t=!e.startsWith("http");r.push(t?{content:readFileSync(getAbsolutePath(e),"utf8")}:{url:e})}for(const t of r)try{o.push(await e.addScriptTag(t))}catch(e){logWithStack(2,e,"[browser] The JS resource cannot be loaded.")}r.length=0;const i=[];if(n.css){let r=n.css.match(/@import\s*([^;]*);/g);if(r)for(let e of r)e&&(e=e.replace("url(","").replace("@import","").replace(/"/g,"").replace(/'/g,"").replace(/;/,"").replace(/\)/g,"").trim(),e.startsWith("http")?i.push({url:e}):t.allowFileResources&&i.push({path:join(__dirname,e)}));i.push({content:n.css.replace(/@import\s*([^;]*);/g,"")||" "});for(const t of i)try{o.push(await e.addStyleTag(t))}catch(e){logWithStack(2,e,"[browser] The CSS resource cannot be loaded.")}i.length=0}}return o}async function clearPageResources(e,t){try{for(const e of t)await e.dispose();await e.evaluate((()=>{if("undefined"!=typeof Highcharts){const e=Highcharts.charts;if(Array.isArray(e)&&e.length)for(const t of e)t&&t.destroy(),Highcharts.charts.shift()}const[...e]=document.getElementsByTagName("script"),[,...t]=document.getElementsByTagName("style"),[...o]=document.getElementsByTagName("link");for(const n of[...e,...t,...o])n.remove()}))}catch(e){logWithStack(2,e,"[browser] Could not clear page's resources.")}}async function _setPageContent(e){await e.setContent(template,{waitUntil:"domcontentloaded"}),await e.addScriptTag({path:join(getCachePath(),"sources.js")}),await e.evaluate(setupHighcharts)}function _setPageEvents(e){const{debug:t}=getOptions();e.on("pageerror",(async()=>{e.isClosed()})),t.enable&&t.listenToConsole&&e.on("console",(e=>{console.log(`[debug] ${e.text()}`)}))}var cssTemplate=()=>"\n\nhtml, body {\n margin: 0;\n padding: 0;\n box-sizing: border-box;\n}\n\n#table-div, #sliders, #datatable, #controls, .ld-row {\n display: none;\n height: 0;\n}\n\n#chart-container {\n box-sizing: border-box;\n margin: 0;\n overflow: auto;\n font-size: 0;\n}\n\n#chart-container > figure, div {\n margin-top: 0 !important;\n margin-bottom: 0 !important;\n}\n\n",svgTemplate=e=>`\n\n\n \n \n Highcharts Export\n \n \n \n
\n ${e}\n
\n \n\n\n`;async function puppeteerExport(e,t){const o=[];try{const n=t.export;let r=!1;if(n.svg){if(log(4,"[export] Treating as SVG input."),"svg"===n.type)return n.svg;r=!0,await _setAsSvg(e,n.svg)}else log(4,"[export] Treating as JSON config."),await _setAsOptions(e,t);o.push(...await addPageResources(e,t.customLogic));const i=r?await e.evaluate((e=>{const t=document.querySelector("#chart-container svg:first-of-type"),o=t.height.baseVal.value*e,n=t.width.baseVal.value*e;return document.body.style.zoom=e,document.body.style.margin="0px",{chartHeight:o,chartWidth:n}}),parseFloat(n.scale)):await e.evaluate((()=>{const{chartHeight:e,chartWidth:t}=window.Highcharts.charts[0];return document.body.style.zoom=1,{chartHeight:e,chartWidth:t}})),{x:s,y:a}=await _getClipRegion(e),l=Math.abs(Math.ceil(i.chartHeight||n.height)),c=Math.abs(Math.ceil(i.chartWidth||n.width));let p;switch(await e.setViewport({height:l,width:c,deviceScaleFactor:r?1:parseFloat(n.scale)}),n.type){case"svg":p=await _createSVG(e);break;case"png":case"jpeg":p=await _createImage(e,n.type,{width:c,height:l,x:s,y:a},n.rasterizationTimeout);break;case"pdf":p=await _createPDF(e,l,c,n.rasterizationTimeout);break;default:throw new ExportError(`[export] Unsupported output format: ${n.type}.`,400)}return await clearPageResources(e,o),p}catch(t){return await clearPageResources(e,o),t}}async function _setAsSvg(e,t){await e.setContent(svgTemplate(t),{waitUntil:"domcontentloaded"})}async function _setAsOptions(e,t){await e.evaluate(createChart,t)}async function _getClipRegion(e){return e.$eval("#chart-container",(e=>{const{x:t,y:o,width:n,height:r}=e.getBoundingClientRect();return{x:t,y:o,width:n,height:Math.trunc(r>1?r:500)}}))}async function _createSVG(e){return e.$eval("#container svg:first-of-type",(e=>e.outerHTML))}async function _createImage(e,t,o,n){return Promise.race([e.screenshot({type:t,clip:o,encoding:"base64",fullPage:!1,optimizeForSpeed:!0,captureBeyondViewport:!0,..."png"!==t?{quality:80}:{},omitBackground:"png"==t}),new Promise(((e,t)=>setTimeout((()=>t(new ExportError("Rasterization timeout",408))),n||1500)))])}async function _createPDF(e,t,o,n){return await e.emulateMediaType("screen"),e.pdf({height:t+1,width:o,encoding:"base64",timeout:n||1500})}let pool=null;const poolStats={exportsAttempted:0,exportsPerformed:0,exportsDropped:0,exportsFromSvg:0,exportsFromOptions:0,exportsFromSvgAttempts:0,exportsFromOptionsAttempts:0,timeSpent:0,timeSpentAverage:0};async function initPool(e=getOptions().pool,t=[]){await createBrowser(t);try{if(log(3,`[pool] Initializing pool with workers: min ${e.minWorkers}, max ${e.maxWorkers}.`),pool)return void log(4,"[pool] Already initialized, please kill it before creating a new one.");e.minWorkers>e.maxWorkers&&(e.minWorkers=e.maxWorkers),pool=new Pool({..._factory(e),min:e.minWorkers,max:e.maxWorkers,acquireTimeoutMillis:e.acquireTimeout,createTimeoutMillis:e.createTimeout,destroyTimeoutMillis:e.destroyTimeout,idleTimeoutMillis:e.idleTimeout,createRetryIntervalMillis:e.createRetryInterval,reapIntervalMillis:e.reaperInterval,propagateCreateError:!1}),pool.on("release",(async e=>{const t=await clearPage(e,!1);log(4,`[pool] Pool resource [${e.id}] - Releasing a worker. Clear page status: ${t}.`)})),pool.on("destroySuccess",((e,t)=>{log(4,`[pool] Pool resource [${t.id}] - Destroyed a worker successfully.`),t.page=null}));const t=[];for(let o=0;o{pool.release(e)})),log(3,"[pool] The pool is ready"+(t.length?` with ${t.length} initial resources waiting.`:"."))}catch(e){throw new ExportError("[pool] Could not configure and create the pool of workers.",500).setError(e)}}async function killPool(){if(log(3,"[pool] Killing pool with all workers and closing browser."),pool){for(const e of pool.used)pool.release(e.resource);pool.destroyed||(await pool.destroy(),log(4,"[pool] Destroyed the pool of resources.")),pool=null}await closeBrowser()}async function postWork(e){let t;try{if(log(4,"[pool] Work received, starting to process."),++poolStats.exportsAttempted,getOptions().pool.benchmarking&&getPoolInfo(),!pool)throw new ExportError("[pool] Work received, but pool has not been started.",500);const o=measureTime();try{log(4,"[pool] Acquiring a worker handle."),t=await pool.acquire().promise,e.server.benchmarking&&log(5,e._requestId?`[benchmark] Request [${e._requestId}] - `:"[benchmark] ",`Acquiring a worker handle took ${o()}ms.`)}catch(t){throw new ExportError("[pool] "+(e._requestId?`Request [${e._requestId}] - `:"")+`Error encountered when acquiring an available entry: ${o()}ms.`,400).setError(t)}if(log(4,"[pool] Acquired a worker handle."),!t.page)throw t.workCount=e.pool.workLimit+1,new ExportError("[pool] Resolved worker page is invalid: the pool setup is wonky.",400);const n=getNewDateTime();log(4,`[pool] Pool resource [${t.id}] - Starting work on this pool entry.`);const r=measureTime(),i=await puppeteerExport(t.page,e);if(i instanceof Error)throw"Rasterization timeout"===i.message&&(t.workCount=e.pool.workLimit+1,t.page=null),"TimeoutError"===i.name||"Rasterization timeout"===i.message?new ExportError("[pool] "+(e._requestId?`Request [${e._requestId}] - `:"")+"Rasterization timeout: your chart may be too complex or large, and failed to render within the allotted time.").setError(i):new ExportError("[pool] "+(e._requestId?`Request [${e._requestId}] - `:"")+`Error encountered during export: ${r()}ms.`).setError(i);e.server.benchmarking&&log(5,e._requestId?`[benchmark] Request [${e._requestId}] - `:"[benchmark] ",`Exporting a chart sucessfully took ${r()}ms.`),pool.release(t);const s=getNewDateTime()-n;return poolStats.timeSpent+=s,poolStats.timeSpentAverage=poolStats.timeSpent/++poolStats.exportsPerformed,log(4,`[pool] Work completed in ${s}ms.`),{result:i,options:e}}catch(e){throw++poolStats.exportsDropped,t&&pool.release(t),e}}function getPoolStats(){return poolStats}function getPoolInfoJSON(){return{min:pool.min,max:pool.max,used:pool.numUsed(),available:pool.numFree(),allCreated:pool.numUsed()+pool.numFree(),pendingAcquires:pool.numPendingAcquires(),pendingCreates:pool.numPendingCreates(),pendingValidations:pool.numPendingValidations(),pendingDestroys:pool.pendingDestroys.length,absoluteAll:pool.numUsed()+pool.numFree()+pool.numPendingAcquires()+pool.numPendingCreates()+pool.numPendingValidations()+pool.pendingDestroys.length}}function getPoolInfo(){const{min:e,max:t,used:o,available:n,allCreated:r,pendingAcquires:i,pendingCreates:s,pendingValidations:a,pendingDestroys:l,absoluteAll:c}=getPoolInfoJSON();log(5,`[pool] The minimum number of resources allowed by pool: ${e}.`),log(5,`[pool] The maximum number of resources allowed by pool: ${t}.`),log(5,`[pool] The number of used resources: ${o}.`),log(5,`[pool] The number of free resources: ${n}.`),log(5,`[pool] The number of all created (used and free) resources: ${r}.`),log(5,`[pool] The number of resources waiting to be acquired: ${i}.`),log(5,`[pool] The number of resources waiting to be created: ${s}.`),log(5,`[pool] The number of resources waiting to be validated: ${a}.`),log(5,`[pool] The number of resources waiting to be destroyed: ${l}.`),log(5,`[pool] The number of all resources: ${c}.`)}function _factory(e){return{create:async()=>{const t={id:v4(),workCount:Math.round(Math.random()*(e.workLimit/2))};try{const e=getNewDateTime();return await newPage(t),log(3,`[pool] Pool resource [${t.id}] - Successfully created a worker, took ${getNewDateTime()-e}ms.`),t}catch(e){throw log(3,`[pool] Pool resource [${t.id}] - Error encountered when creating a new page.`),e}},validate:async t=>t.page?t.page.isClosed()?(log(3,`[pool] Pool resource [${t.id}] - Validation failed (page is closed or invalid).`),!1):t.page.mainFrame().detached?(log(3,`[pool] Pool resource [${t.id}] - Validation failed (page's frame is detached).`),!1):!(e.workLimit&&++t.workCount>e.workLimit)||(log(3,`[pool] Pool resource [${t.id}] - Validation failed (exceeded the ${e.workLimit} works per resource limit).`),!1):(log(3,`[pool] Pool resource [${t.id}] - Validation failed (no valid page is found).`),!1),destroy:async e=>{if(log(3,`[pool] Pool resource [${e.id}] - Destroying a worker.`),e.page&&!e.page.isClosed())try{e.page.removeAllListeners("pageerror"),e.page.removeAllListeners("console"),e.page.removeAllListeners("framedetached"),await e.page.close()}catch(t){throw log(3,`[pool] Pool resource [${e.id}] - Page could not be closed upon destroying.`),t}}}}function sanitize(e){const t=new JSDOM("").window;return DOMPurify(t).sanitize(e,{ADD_TAGS:["foreignObject"]})}let allowCodeExecution=!1;async function singleExport(e){if(!e||!e.export)throw new ExportError("[chart] No expected `export` options were found. Please provide one of the following options: `infile`, `instr`, `options`, or `svg` to generate a valid image.",400);await startExport(e,(async(e,t)=>{if(e)throw e;const{b64:o,outfile:n,type:r}=t.options.export;try{o?writeFileSync(`${n.split(".").shift()||"chart"}.txt`,getBase64(t.result,r)):writeFileSync(n||`chart.${r}`,"svg"!==r?Buffer.from(t.result,"base64"):t.result)}catch(e){throw new ExportError("[chart] Error while saving a chart.",500).setError(e)}await killPool()}))}async function batchExport(e){if(!(e&&e.export&&e.export.batch))throw new ExportError("[chart] No expected `export` options were found. Please provide the `batch` option to generate valid images.",400);{const t=[];for(let o of e.export.batch.split(";")||[])o=o.split("="),2===o.length?t.push(startExport({...e,export:{...e.export,infile:o[0],outfile:o[1]}},((e,t)=>{if(e)throw e;const{b64:o,outfile:n,type:r}=t.options.export;try{o?writeFileSync(`${n.split(".").shift()||"chart"}.txt`,getBase64(t.result,r)):writeFileSync(n,"svg"!==r?Buffer.from(t.result,"base64"):t.result)}catch(e){throw new ExportError("[chart] Error while saving a chart.",500).setError(e)}}))):log(2,"[chart] No correct pair found for the batch export.");const o=await Promise.allSettled(t);await killPool(),o.forEach(((e,t)=>{e.reason&&logWithStack(1,e.reason,`[chart] Batch export number ${t+1} could not be correctly completed.`)}))}}async function startExport(e,t){try{log(4,"[chart] Starting the exporting process.");const o=mergeOptions(getOptions(!1),e),n=o.export;if(null!==n.infile){let e;log(4,"[chart] Attempting to export from a file input.");try{e=readFileSync(getAbsolutePath(n.infile),"utf8")}catch(e){throw new ExportError("[chart] Error loading content from a file input.",400).setError(e)}if(n.infile.endsWith(".svg"))try{n.svg=validateOption("svg",e,!1)}catch(e){throw logZodIssues(1,e.issues,"[config] The `svg` option validation error"),e}else{if(!n.infile.endsWith(".json"))throw new ExportError("[chart] Incorrect value of the `infile` option.",400);try{n.instr=validateOption("instr",e,!1)}catch(e){throw logZodIssues(1,e.issues,"[config] The `instr` option validation error"),e}}}if(null!==n.svg){log(4,"[chart] Attempting to export from an SVG input."),++getPoolStats().exportsFromSvgAttempts;const e=await _exportFromSvg(sanitize(n.svg),o);return++getPoolStats().exportsFromSvg,t(null,e)}if(null!==n.instr||null!==n.options){log(4,"[chart] Attempting to export from options input."),++getPoolStats().exportsFromOptionsAttempts;const e=await _exportFromOptions(n.instr||n.options,o);return++getPoolStats().exportsFromOptions,t(null,e)}return t(new ExportError("[chart] No valid input specified. Check if at least one of the following parameters is correctly set: 'infile', 'instr', 'options', or 'svg'.",400))}catch(e){return t(e)}}function getAllowCodeExecution(){return allowCodeExecution}function setAllowCodeExecution(e){allowCodeExecution=e}async function _exportFromSvg(e,t){if("string"==typeof e&&(e.indexOf("=0||e.indexOf("=0))return log(4,"[chart] Parsing input as SVG."),t.export.svg=e,t.export.instr=null,t.export.options=null,_prepareExport(t);throw new ExportError("[chart] Not a correct SVG input.",400)}async function _exportFromOptions(e,t){log(4,"[chart] Parsing input from options.");const o=isAllowedConfig(e,!0,t.customLogic.allowCodeExecution);if(null===o||"string"!=typeof o||!o.startsWith("{")||!o.endsWith("}"))throw new ExportError("[chart] Invalid configuration provided - Only options configurations and SVG are allowed for this server. If this is your server, JavaScript custom code can be enabled by starting the server with the `allowCodeExecution` options set to true.",403);return t.export.instr=o,t.export.svg=null,_prepareExport(t)}async function _prepareExport(e){const{export:t,customLogic:o}=e;t.type=fixType(t.type,t.outfile),t.outfile=fixOutfile(t.type,t.outfile),log(3,`[chart] The custom logic is ${o.allowCodeExecution?"allowed":"disallowed"}.`),_handleCustomLogic(o,o.allowCodeExecution),_handleGlobalAndTheme(t,o.allowFileResources,o.allowCodeExecution),e.export={...t,..._findChartSize(t)};try{e=strictValidate(e)}catch(e){logZodIssues(1,e.issues,"[config] Final options validation error")}return postWork(e)}function _findChartSize(e){const{chart:t,exporting:o}=e.options||isAllowedConfig(e.instr)||!1,{chart:n,exporting:r}=isAllowedConfig(e.globalOptions)||!1,{chart:i,exporting:s}=isAllowedConfig(e.themeOptions)||!1,a=roundNumber(Math.max(.1,Math.min(e.scale||o?.scale||r?.scale||s?.scale||e.defaultScale||1,5)),2),l={height:e.height||o?.sourceHeight||t?.height||r?.sourceHeight||n?.height||s?.sourceHeight||i?.height||e.defaultHeight||400,width:e.width||o?.sourceWidth||t?.width||r?.sourceWidth||n?.width||s?.sourceWidth||i?.width||e.defaultWidth||600,scale:a};for(let[e,t]of Object.entries(l))l[e]="string"==typeof t?+t.replace(/px|%/gi,""):t;return l}function _handleCustomLogic(e,t){if(t){if("string"==typeof e.resources)e.resources=_handleResources(e.resources,e.allowFileResources,!0);else if(!e.resources)try{e.resources=_handleResources(readFileSync(getAbsolutePath("resources.json"),"utf8"),e.allowFileResources,!0)}catch(e){log(2,"[chart] Unable to load the default `resources.json` file.")}try{e.customCode=wrapAround(e.customCode,e.allowFileResources)}catch(t){logWithStack(2,t,"[chart] The `customCode` cannot be loaded."),e.customCode=null}try{e.callback=wrapAround(e.callback,e.allowFileResources,!0)}catch(t){logWithStack(2,t,"[chart] The `callback` cannot be loaded."),e.callback=null}[null,void 0].includes(e.customCode)&&log(3,"[chart] No value for the `customCode` option found."),[null,void 0].includes(e.callback)&&log(3,"[chart] No value for the `callback` option found."),[null,void 0].includes(e.resources)&&log(3,"[chart] No value for the `resources` option found.")}else if(e.callback||e.resources||e.customCode)throw e.callback=null,e.resources=null,e.customCode=null,new ExportError("[chart] The 'callback', 'resources', and 'customCode' options have been disabled for this server.",403)}function _handleResources(e=null,t,o){const n=["js","css","files"];let r=e,i=!1;if(t&&e.endsWith(".json"))try{r=isAllowedConfig(readFileSync(getAbsolutePath(e),"utf8"),!1,o)}catch{return null}else r=isAllowedConfig(e,!1,o),r&&!t&&delete r.files;for(const e in r)n.includes(e)?i||(i=!0):delete r[e];return i?(r.files&&(r.files=r.files.map((e=>e.trim())),(!r.files||r.files.length<=0)&&delete r.files),r):null}function _handleGlobalAndTheme(e,t,o){["globalOptions","themeOptions"].forEach((n=>{try{e[n]&&(t&&"string"==typeof e[n]&&e[n].endsWith(".json")?e[n]=isAllowedConfig(readFileSync(getAbsolutePath(e[n]),"utf8"),!0,o):e[n]=isAllowedConfig(e[n],!0,o))}catch(t){logWithStack(2,t,`[chart] The \`${n}\` cannot be loaded.`),e[n]=null}})),[null,void 0].includes(e.globalOptions)&&log(3,"[chart] No value for the `globalOptions` option found."),[null,void 0].includes(e.themeOptions)&&log(3,"[chart] No value for the `themeOptions` option found.")}const timerIds=[];function addTimer(e){timerIds.push(e)}function clearAllTimers(){log(4,"[timer] Clearing all registered intervals and timeouts.");for(const e of timerIds)clearInterval(e),clearTimeout(e)}function logErrorMiddleware(e,t,o,n){return logWithStack(1,e),"development"!==getOptions().other.nodeEnv&&delete e.stack,n(e)}function returnErrorMiddleware(e,t,o,n){const{message:r,stack:i}=e,s=e.statusCode||400;o.status(s).json({statusCode:s,message:r,stack:i})}function errorMiddleware(e){e.use(logErrorMiddleware),e.use(returnErrorMiddleware)}function rateLimitingMiddleware(e,t=getOptions().server.rateLimiting){try{if(t.enable){const o="Too many requests, you have been rate limited. Please try again later.",n={max:t.maxRequests||30,window:t.window||1,delay:t.delay||0,trustProxy:t.trustProxy||!1,skipKey:t.skipKey||!1,skipToken:t.skipToken||!1};n.trustProxy&&e.enable("trust proxy");const r=rateLimit({windowMs:60*n.window*1e3,max:n.max,delayMs:n.delay,handler:(e,t)=>{t.format({json:()=>{t.status(429).send({message:o})},default:()=>{t.status(429).send(o)}})},skip:e=>!1!==n.skipKey&&!1!==n.skipToken&&e.query.key===n.skipKey&&e.query.access_token===n.skipToken&&(log(4,"[rate limiting] Skipping rate limiter."),!0)});e.use(r),log(3,`[rate limiting] Enabled rate limiting with ${n.max} requests per ${n.window} minute for each IP, trusting proxy: ${n.trustProxy}.`)}}catch(e){throw new ExportError("[rate limiting] Could not configure and set the rate limiting options.",500).setError(e)}}class HttpError extends ExportError{constructor(e,t){super(e,t)}setStatus(e){return this.statusCode=e,this}}function contentTypeMiddleware(e,t,o){try{const t=e.headers["content-type"]||"";if(!t.includes("application/json")&&!t.includes("application/x-www-form-urlencoded")&&!t.includes("multipart/form-data"))throw new HttpError("[validation] Content-Type must be application/json, application/x-www-form-urlencoded, or multipart/form-data.",415);return o()}catch(e){return o(e)}}function requestBodyMiddleware(e,t,o){try{const t=e.body,n=v4().replace(/-/g,"");if(!t||isObjectEmpty(t))throw log(2,`[validation] Request [${n}] - The request from ${e.headers["x-forwarded-for"]||e.connection.remoteAddress} was incorrect. Received payload is empty.`),new HttpError("[validation] The request body is required. Please ensure that your Content-Type header is correct. Accepted types are 'application/json' and 'multipart/form-data'.",400);const r=getAllowCodeExecution(),i=isAllowedConfig(t.instr||t.options||t.infile||t.data,!0,r);if(null===i&&!t.svg)throw log(2,`[validation] Request [${n}] - The request from ${e.headers["x-forwarded-for"]||e.connection.remoteAddress} was incorrect. Received payload is missing correct chart data for export: ${JSON.stringify(t)}.`),new HttpError("[validation] No correct chart data found. Ensure that you are using either application/json or multipart/form-data headers. If sending JSON, make sure the chart data is in the 'infile', 'options', or 'data' attribute. If sending SVG, ensure it is in the 'svg' attribute.",400);if(t.svg&&isPrivateRangeUrlFound(t.svg))throw new HttpError("[validation] SVG potentially contain at least one forbidden URL in 'xlink:href' element. Please review the SVG content and ensure that all referenced URLs comply with security policies.",400);try{e.validatedOptions=looseValidate({_requestId:n,export:{instr:i,svg:t.svg,outfile:t.outfile||`${e.params.filename||"chart"}.${fixType(t.type)}`,type:fixType(t.type,t.outfile),constr:fixConstr(t.constr),b64:t.b64,noDownload:t.noDownload,height:t.height,width:t.width,scale:t.scale,globalOptions:isAllowedConfig(t.globalOptions,!0,r),themeOptions:isAllowedConfig(t.themeOptions,!0,r)},customLogic:{allowCodeExecution:r,allowFileResources:!1,customCode:t.customCode,callback:t.callback,resources:isAllowedConfig(t.resources,!0,r)}})}catch(e){throw logZodIssues(1,e.issues,"[config] Request options validation error"),new HttpError("The provided options are not correct. Please check if your data is of the correct types.",400)}return o()}catch(e){return o(e)}}function validationMiddleware(e){e.post(["/","/:filename"],contentTypeMiddleware),e.post(["/","/:filename"],requestBodyMiddleware)}const reversedMime={png:"image/png",jpeg:"image/jpeg",gif:"image/gif",pdf:"application/pdf",svg:"image/svg+xml"};async function requestExport(e,t,o){try{const o=measureTime();let n=!1;e.socket.on("close",(e=>{e&&(n=!0)}));const r=e.validatedOptions,i=r._requestId;log(4,`[export] Got an incoming HTTP request with ID ${i}.`),await startExport(r,((r,s)=>{if(e.socket.removeAllListeners("close"),n)log(3,`[export] Request [${i}] - The client closed the connection before the chart finished processing.`);else{if(r)throw r;if(!s||!s.result)throw log(2,`[export] Request [${i}] - Request from ${e.headers["x-forwarded-for"]||e.connection.remoteAddress} was incorrect. Received result is ${s.result}.`),new HttpError("[export] Unexpected return of the export result from the chart generation. Please check your request data.",400);if(s.result){log(3,`[export] Request [${i}] - The whole exporting process took ${o()}ms.`);const{type:e,b64:n,noDownload:r,outfile:a}=s.options.export;return n?t.send(getBase64(s.result,e)):(t.header("Content-Type",reversedMime[e]||"image/png"),r||t.attachment(a),"svg"===e?t.send(s.result):t.send(Buffer.from(s.result,"base64")))}}}))}catch(e){return o(e)}}function exportRoutes(e){e.post("/",requestExport),e.post("/:filename",requestExport)}const serverStartTime=new Date,packageFile=JSON.parse(readFileSync(join(__dirname,"package.json"))),successRates=[],recordInterval=6e4,windowSize=30;function _calculateMovingAverage(){return successRates.reduce(((e,t)=>e+t),0)/successRates.length}function _startSuccessRate(){return setInterval((()=>{const e=getPoolStats(),t=0===e.exportsAttempted?1:e.exportsPerformed/e.exportsAttempted*100;successRates.push(t),successRates.length>windowSize&&successRates.shift()}),recordInterval)}function healthRoutes(e){addTimer(_startSuccessRate()),e.get("/health",((e,t,o)=>{try{log(4,"[health] Returning server health.");const e=getPoolStats(),o=successRates.length,n=_calculateMovingAverage();t.send({status:"OK",bootTime:serverStartTime,uptime:`${Math.floor((getNewDateTime()-serverStartTime.getTime())/1e3/60)} minutes`,serverVersion:packageFile.version,highchartsVersion:getHighchartsVersion(),averageExportTime:e.timeSpentAverage,attemptedExports:e.exportsAttempted,performedExports:e.exportsPerformed,failedExports:e.exportsDropped,sucessRatio:e.exportsPerformed/e.exportsAttempted*100,pool:getPoolInfoJSON(),period:o,movingAverage:n,message:isNaN(n)||!successRates.length?"Too early to report. No exports made yet. Please check back soon.":`Last ${o} minutes had a success rate of ${n.toFixed(2)}%.`,svgExports:e.exportsFromSvg,jsonExports:e.exportsFromOptions,svgExportsAttempts:e.exportsFromSvgAttempts,jsonExportsAttempts:e.exportsFromOptionsAttempts})}catch(e){return o(e)}}))}function uiRoutes(e){e.get(getOptions().ui.route||"/",((e,t,o)=>{try{t.sendFile(join(__dirname,"public","index.html"),{acceptRanges:!1})}catch(e){return o(e)}}))}function versionChangeRoutes(e){e.post("/version_change/:newVersion",(async(e,t,o)=>{try{const o=envs.HIGHCHARTS_ADMIN_TOKEN;if(!o||!o.length)throw new HttpError("[version] The server is not configured to perform run-time version changes: HIGHCHARTS_ADMIN_TOKEN is not set.",401);const n=e.get("hc-auth");if(!n||n!==o)throw new HttpError("[version] Invalid or missing token: Set the token in the hc-auth header.",401);const r=e.params.newVersion;if(!r)throw new HttpError("[version] No new version supplied.",400);try{await updateHighchartsVersion(r)}catch(e){throw new HttpError(`[version] Version change: ${e.message}`,400).setError(e)}t.status(200).send({statusCode:200,highchartsVersion:getHighchartsVersion(),message:`Successfully updated Highcharts to version: ${r}.`})}catch(e){return o(e)}}))}const activeServers=new Map,app=express();async function startServer(e=getOptions().server){try{if(!e.enable||!app)throw new ExportError("[server] Server cannot be started (not enabled or no correct Express app found).",500);const t=1024*e.uploadLimit*1024,o=multer.memoryStorage(),n=multer({storage:o,limits:{fieldSize:t}});if(app.disable("x-powered-by"),app.use(cors({methods:["POST","GET","OPTIONS"]})),app.use(((e,t,o)=>{t.set("Accept-Ranges","none"),o()})),app.use(express.json({limit:t})),app.use(express.urlencoded({extended:!0,limit:t})),app.use(n.none()),app.use(express.static(join(__dirname,"public"))),!e.ssl.force){const t=http.createServer(app);_attachServerErrorHandlers(t),t.listen(e.port,e.host,(()=>{activeServers.set(e.port,t),log(3,`[server] Started HTTP server on ${e.host}:${e.port}.`)}))}if(e.ssl.enable){let t,o;try{t=await readFile(join(getAbsolutePath(e.ssl.certPath),"server.key"),"utf8"),o=await readFile(join(getAbsolutePath(e.ssl.certPath),"server.crt"),"utf8")}catch(t){log(2,`[server] Unable to load key/certificate from the '${e.ssl.certPath}' path. Could not run secured layer server.`)}if(t&&o){const n=https.createServer({key:t,cert:o},app);_attachServerErrorHandlers(n),n.listen(e.ssl.port,e.host,(()=>{activeServers.set(e.ssl.port,n),log(3,`[server] Started HTTPS server on ${e.host}:${e.ssl.port}.`)}))}}rateLimitingMiddleware(app,e.rateLimiting),validationMiddleware(app),healthRoutes(app),exportRoutes(app),uiRoutes(app),versionChangeRoutes(app),errorMiddleware(app)}catch(e){throw new ExportError("[server] Could not configure and start the server.",500).setError(e)}}function closeServers(){if(activeServers.size>0){log(4,"[server] Closing all servers.");for(const[e,t]of activeServers)t.close((()=>{activeServers.delete(e),log(4,`[server] Closed server on port: ${e}.`)}))}}function getServers(){return activeServers}function getExpress(){return express}function getApp(){return app}function enableRateLimiting(e){rateLimitingMiddleware(app,e)}function use(e,...t){app.use(e,...t)}function get(e,...t){app.get(e,...t)}function post(e,...t){app.post(e,...t)}function _attachServerErrorHandlers(e){e.on("clientError",((e,t)=>{logWithStack(1,e,`[server] Client error: ${e.message}, destroying socket.`),t.destroy()})),e.on("error",(e=>{logWithStack(1,e,`[server] Server error: ${e.message}`)})),e.on("connection",(e=>{e.on("error",(e=>{logWithStack(1,e,`[server] Socket error: ${e.message}`)}))}))}var server={startServer:startServer,closeServers:closeServers,getServers:getServers,getExpress:getExpress,getApp:getApp,enableRateLimiting:enableRateLimiting,use:use,get:get,post:post};async function shutdownCleanUp(e){await Promise.allSettled([clearAllTimers(),closeServers(),killPool()]),process.exit(e)}async function initExport(e){const t=mergeOptions(getOptions(!1),e);setAllowCodeExecution(t.customLogic.allowCodeExecution),initLogging(t.logging),t.other.listenToProcessExits&&_attachProcessExitListeners(),await checkAndUpdateCache(t.highcharts,t.server.proxy),await initPool(t.pool,t.puppeteer.args)}function _attachProcessExitListeners(){log(3,"[process] Attaching exit listeners to the process."),process.on("exit",(e=>{log(4,`[process] Process exited with code ${e}.`)})),process.on("SIGINT",(async(e,t)=>{log(4,`[process] The ${e} event with code: ${t}.`),await shutdownCleanUp(0)})),process.on("SIGTERM",(async(e,t)=>{log(4,`[process] The ${e} event with code: ${t}.`),await shutdownCleanUp(0)})),process.on("SIGHUP",(async(e,t)=>{log(4,`[process] The ${e} event with code: ${t}.`),await shutdownCleanUp(0)})),process.on("uncaughtException",(async(e,t)=>{logWithStack(1,e,`[process] The ${t} error.`),await shutdownCleanUp(1)}))}var index={server:server,startServer:startServer,getOptions:getOptions,setOptions:setOptions,mergeOptions:mergeOptions,mapToNewOptions:mapToNewOptions,initExport:initExport,singleExport:singleExport,batchExport:batchExport,startExport:startExport,checkAndUpdateCache:checkAndUpdateCache,initPool:initPool,killPool:killPool,log:log,logWithStack:logWithStack,logZodIssues:logZodIssues,setLogLevel:setLogLevel,enableConsoleLogging:enableConsoleLogging,enableFileLogging:enableFileLogging,shutdownCleanUp:shutdownCleanUp};export{index as default,initExport}; //# sourceMappingURL=index.esm.js.map diff --git a/dist/index.esm.js.map b/dist/index.esm.js.map index 6ba656dd..75408356 100644 --- a/dist/index.esm.js.map +++ b/dist/index.esm.js.map @@ -1 +1 @@ -{"version":3,"file":"index.esm.js","sources":["../lib/utils.js","../lib/logger.js","../lib/schemas/config.js","../lib/envs.js","../lib/config.js","../lib/fetch.js","../lib/errors/ExportError.js","../lib/cache.js","../lib/highcharts.js","../lib/browser.js","../templates/svgExport/css.js","../templates/svgExport/svgExport.js","../lib/export.js","../lib/pool.js","../lib/sanitize.js","../lib/chart.js","../lib/timer.js","../lib/server/middlewares/error.js","../lib/server/middlewares/rateLimiting.js","../lib/errors/HttpError.js","../lib/server/middlewares/validation.js","../lib/server/routes/export.js","../lib/server/routes/health.js","../lib/server/routes/ui.js","../lib/server/routes/versionChange.js","../lib/server/server.js","../lib/resourceRelease.js","../lib/index.js"],"sourcesContent":["/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * @overview The Highcharts Export Server utility module provides\r\n * a comprehensive set of helper functions and constants designed to streamline\r\n * and enhance various operations required for Highcharts export tasks.\r\n */\r\n\r\nimport { readFileSync } from 'fs';\r\nimport { isAbsolute, join } from 'path';\r\nimport { fileURLToPath } from 'url';\r\n\r\nconst MAX_BACKOFF_ATTEMPTS = 6;\r\n\r\n// The directory path\r\nexport const __dirname = fileURLToPath(new URL('../.', import.meta.url));\r\n\r\n/**\r\n * Clears and standardizes text by replacing multiple consecutive whitespace\r\n * characters with a single space and trimming any leading or trailing\r\n * whitespace.\r\n *\r\n * @function clearText\r\n *\r\n * @param {string} text - The input text to be cleared.\r\n * @param {RegExp} [rule=/\\s\\s+/g] - The regular expression rule to match\r\n * multiple consecutive whitespace characters. The default value\r\n * is the '/\\s\\s+/g' RegExp.\r\n * @param {string} [replacer=' '] - The string used to replace multiple\r\n * consecutive whitespace characters. The default value is the ' ' string.\r\n *\r\n * @returns {string} The cleared and standardized text.\r\n */\r\nexport function clearText(text, rule = /\\s\\s+/g, replacer = ' ') {\r\n return text.replaceAll(rule, replacer).trim();\r\n}\r\n\r\n/**\r\n * Creates a deep copy of the given object or array.\r\n *\r\n * @function deepCopy\r\n *\r\n * @param {(Object|Array)} objArr - The object or array to be deeply copied.\r\n *\r\n * @returns {(Object|Array)} The deep copy of the provided object or array.\r\n */\r\nexport function deepCopy(objArr) {\r\n // If the `objArr` is null or not of the `object` type, return it\r\n if (objArr === null || typeof objArr !== 'object') {\r\n return objArr;\r\n }\r\n\r\n // Prepare either a new array or a new object\r\n const objArrCopy = Array.isArray(objArr) ? [] : {};\r\n\r\n // Recursively copy each property\r\n for (const key in objArr) {\r\n if (Object.prototype.hasOwnProperty.call(objArr, key)) {\r\n objArrCopy[key] = deepCopy(objArr[key]);\r\n }\r\n }\r\n\r\n // Return the copied object\r\n return objArrCopy;\r\n}\r\n\r\n/**\r\n * Implements an exponential backoff strategy for retrying a function until\r\n * a certain number of attempts are reached.\r\n *\r\n * @async\r\n * @function expBackoff\r\n *\r\n * @param {Function} fn - The function to be retried.\r\n * @param {number} [attempt=0] - The current attempt number. The default value\r\n * is 0.\r\n * @param {...unknown} args - Arguments to be passed to the function.\r\n *\r\n * @returns {Promise} A Promise that resolves to the result\r\n * of the function if successful.\r\n *\r\n * @throws {Error} Throws an `Error` if the maximum number of attempts\r\n * is reached.\r\n */\r\nexport async function expBackoff(fn, attempt = 0, ...args) {\r\n try {\r\n // Try to call the function\r\n return await fn(...args);\r\n } catch (error) {\r\n // Calculate delay in ms\r\n const delayInMs = 2 ** attempt * 1000;\r\n\r\n // If the attempt exceeds the maximum attempts of repeat, throw an error\r\n if (++attempt >= MAX_BACKOFF_ATTEMPTS) {\r\n throw error;\r\n }\r\n\r\n // Wait given amount of time\r\n await new Promise((response) => setTimeout(response, delayInMs));\r\n\r\n /// TO DO: Correct\r\n // // Information about the resource timeout\r\n // log(\r\n // 3,\r\n // `[utils] Waited ${delayInMs}ms until next call for the resource of ID: ${args[0]}.`\r\n // );\r\n\r\n // Try again\r\n return expBackoff(fn, attempt, ...args);\r\n }\r\n}\r\n\r\n/**\r\n * Adjusts the constructor name by transforming and normalizing it based\r\n * on common chart types.\r\n *\r\n * @function fixConstr\r\n *\r\n * @param {string} constr - The original constructor name to be fixed.\r\n *\r\n * @returns {string} The corrected constructor name, or 'chart' if the input\r\n * is not recognized.\r\n */\r\nexport function fixConstr(constr) {\r\n try {\r\n // Fix the constructor by lowering casing\r\n const fixedConstr = `${constr.toLowerCase().replace('chart', '')}Chart`;\r\n\r\n // Handle the case where the result is just 'Chart'\r\n if (fixedConstr === 'Chart') {\r\n fixedConstr.toLowerCase();\r\n }\r\n\r\n // Return the corrected constructor, otherwise default to 'chart'\r\n return ['chart', 'stockChart', 'mapChart', 'ganttChart'].includes(\r\n fixedConstr\r\n )\r\n ? fixedConstr\r\n : 'chart';\r\n } catch {\r\n // Default to 'chart' in case of any error\r\n return 'chart';\r\n }\r\n}\r\n\r\n/**\r\n * Fixes the outfile based on provided type.\r\n *\r\n * @function fixOutfile\r\n *\r\n * @param {string} type - The original export type.\r\n * @param {string} outfile - The file path or name.\r\n *\r\n * @returns {string} The corrected outfile.\r\n */\r\nexport function fixOutfile(type, outfile) {\r\n // Get the file name from the `outfile` option\r\n const fileName = getAbsolutePath(outfile || 'chart')\r\n .split('.')\r\n .shift();\r\n\r\n // Return a correct outfile\r\n return `${fileName}.${type}`;\r\n}\r\n\r\n/**\r\n * Fixes the export type based on MIME types and file extensions.\r\n *\r\n * @function fixType\r\n *\r\n * @param {string} type - The original export type.\r\n * @param {string} [outfile=null] - The file path or name. The default value\r\n * is null.\r\n *\r\n * @returns {string} The corrected export type.\r\n */\r\nexport function fixType(type, outfile = null) {\r\n // MIME types\r\n const mimeTypes = {\r\n 'image/png': 'png',\r\n 'image/jpeg': 'jpeg',\r\n 'application/pdf': 'pdf',\r\n 'image/svg+xml': 'svg'\r\n };\r\n\r\n // Get formats\r\n const formats = Object.values(mimeTypes);\r\n\r\n // Check if type and outfile's extensions are the same\r\n if (outfile) {\r\n const outType = outfile.split('.').pop();\r\n\r\n // Support the JPG type\r\n if (outType === 'jpg') {\r\n type = 'jpeg';\r\n } else if (formats.includes(outType) && type !== outType) {\r\n type = outType;\r\n }\r\n }\r\n\r\n // Return a correct type\r\n return mimeTypes[type] || formats.find((t) => t === type) || 'png';\r\n}\r\n\r\n/**\r\n * Checks if the given path is relative or absolute and returns the corrected,\r\n * absolute path.\r\n *\r\n * @function isAbsolutePath\r\n *\r\n * @param {string} path - The path to be checked on.\r\n *\r\n * @returns {string} The absolute path.\r\n */\r\nexport function getAbsolutePath(path) {\r\n return isAbsolute(path) ? path : join(__dirname, path);\r\n}\r\n\r\n/**\r\n * Converts input data to a Base64 string based on the export type.\r\n *\r\n * @function getBase64\r\n *\r\n * @param {string} input - The input to be transformed to Base64 format.\r\n * @param {string} type - The original export type.\r\n *\r\n * @returns {string} The Base64 string representation of the input.\r\n */\r\nexport function getBase64(input, type) {\r\n // For pdf and svg types the input must be transformed to Base64 from a buffer\r\n if (type === 'pdf' || type == 'svg') {\r\n return Buffer.from(input, 'utf8').toString('base64');\r\n }\r\n\r\n // For png and jpeg input is already a Base64 string\r\n return input;\r\n}\r\n\r\n/**\r\n * Returns stringified date without the GMT text information.\r\n *\r\n * @function getNewDate\r\n */\r\nexport function getNewDate() {\r\n // Get rid of the GMT text information\r\n return new Date().toString().split('(')[0].trim();\r\n}\r\n\r\n/**\r\n * Returns the stored time value in milliseconds.\r\n *\r\n * @function getNewDateTime\r\n */\r\nexport function getNewDateTime() {\r\n return new Date().getTime();\r\n}\r\n\r\n/**\r\n * Checks if the given item is an object.\r\n *\r\n * @function isObject\r\n *\r\n * @param {unknown} item - The item to be checked.\r\n *\r\n * @returns {boolean} True if the item is an object, false otherwise.\r\n */\r\nexport function isObject(item) {\r\n return Object.prototype.toString.call(item) === '[object Object]';\r\n}\r\n\r\n/**\r\n * Checks if the given object is empty.\r\n *\r\n * @function isObjectEmpty\r\n *\r\n * @param {Object} item - The object to be checked.\r\n *\r\n * @returns {boolean} True if the object is empty, false otherwise.\r\n */\r\nexport function isObjectEmpty(item) {\r\n return (\r\n typeof item === 'object' &&\r\n !Array.isArray(item) &&\r\n item !== null &&\r\n Object.keys(item).length === 0\r\n );\r\n}\r\n\r\n/**\r\n * Checks if a private IP range URL is found in the given string.\r\n *\r\n * @function isPrivateRangeUrlFound\r\n *\r\n * @param {string} item - The string to be checked for a private IP range URL.\r\n *\r\n * @returns {boolean} True if a private IP range URL is found, false otherwise.\r\n */\r\nexport function isPrivateRangeUrlFound(item) {\r\n const regexPatterns = [\r\n /xlink:href=\"(?:http:\\/\\/|https:\\/\\/)?localhost\\b/,\r\n /xlink:href=\"(?:http:\\/\\/|https:\\/\\/)?10\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\b/,\r\n /xlink:href=\"(?:http:\\/\\/|https:\\/\\/)?127\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\b/,\r\n /xlink:href=\"(?:http:\\/\\/|https:\\/\\/)?172\\.(1[6-9]|2[0-9]|3[0-1])\\.\\d{1,3}\\.\\d{1,3}\\b/,\r\n /xlink:href=\"(?:http:\\/\\/|https:\\/\\/)?192\\.168\\.\\d{1,3}\\.\\d{1,3}\\b/\r\n ];\r\n\r\n return regexPatterns.some((pattern) => pattern.test(item));\r\n}\r\n\r\n/**\r\n * Utility to measure elapsed time using the Node.js `process.hrtime()` method.\r\n *\r\n * @function measureTime\r\n *\r\n * @returns {Function} A function to calculate the elapsed time in milliseconds.\r\n */\r\nexport function measureTime() {\r\n const start = process.hrtime.bigint();\r\n return () => Number(process.hrtime.bigint() - start) / 1000000;\r\n}\r\n\r\n/**\r\n * Rounds a number to the specified precision.\r\n *\r\n * @function roundNumber\r\n *\r\n * @param {number} value - The number to be rounded.\r\n * @param {number} precision - The number of decimal places to round to.\r\n *\r\n * @returns {number} The rounded number.\r\n */\r\nexport function roundNumber(value, precision = 1) {\r\n const multiplier = Math.pow(10, precision || 0);\r\n return Math.round(+value * multiplier) / multiplier;\r\n}\r\n\r\n/**\r\n * Converts a value to a boolean.\r\n *\r\n * @function toBoolean\r\n *\r\n * @param {unknown} item - The value to be converted to a boolean.\r\n *\r\n * @returns {boolean} The boolean representation of the input value.\r\n */\r\nexport function toBoolean(item) {\r\n return ['false', 'undefined', 'null', 'NaN', '0', ''].includes(item)\r\n ? false\r\n : !!item;\r\n}\r\n\r\n/**\r\n * Wraps custom code to execute it safely.\r\n *\r\n * @function wrapAround\r\n *\r\n * @param {string} customCode - The custom code to be wrapped.\r\n * @param {boolean} allowFileResources - Flag to allow loading code from a file.\r\n * @param {boolean} [isCallback=false] - Flag that indicates the returned code\r\n * must be in a callback format.\r\n *\r\n * @returns {(string|null)} The wrapped custom code or null if wrapping fails.\r\n */\r\nexport function wrapAround(customCode, allowFileResources, isCallback = false) {\r\n if (customCode && typeof customCode === 'string') {\r\n customCode = customCode.trim();\r\n\r\n if (customCode.endsWith('.js')) {\r\n // Load a file if the file resources are allowed\r\n return allowFileResources\r\n ? wrapAround(\r\n readFileSync(getAbsolutePath(customCode), 'utf8'),\r\n allowFileResources,\r\n isCallback\r\n )\r\n : null;\r\n } else if (\r\n !isCallback &&\r\n (customCode.startsWith('function()') ||\r\n customCode.startsWith('function ()') ||\r\n customCode.startsWith('()=>') ||\r\n customCode.startsWith('() =>'))\r\n ) {\r\n // Treat a function as a self-invoking expression\r\n return `(${customCode})()`;\r\n }\r\n\r\n // Or return as a stringified code\r\n return customCode.replace(/;$/, '');\r\n }\r\n}\r\n\r\nexport default {\r\n __dirname,\r\n clearText,\r\n deepCopy,\r\n expBackoff,\r\n fixConstr,\r\n fixOutfile,\r\n fixType,\r\n getAbsolutePath,\r\n getBase64,\r\n getNewDate,\r\n getNewDateTime,\r\n isObject,\r\n isObjectEmpty,\r\n isPrivateRangeUrlFound,\r\n measureTime,\r\n roundNumber,\r\n toBoolean,\r\n wrapAround\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * @overview A module for managing logging functionality with customizable\r\n * log levels, console and file logging options, and error handling support.\r\n * The module also ensures that file-based logs are stored in a structured\r\n * directory, creating the necessary paths automatically if they do not exist.\r\n */\r\n\r\nimport { appendFile, existsSync, mkdirSync } from 'fs';\r\nimport { join } from 'path';\r\n\r\nimport { getAbsolutePath, getNewDate } from './utils.js';\r\n\r\n// The available colors\r\nconst colors = ['red', 'yellow', 'blue', 'gray', 'green'];\r\n\r\n// The default logging config\r\nconst logging = {\r\n // Flags for logging status\r\n toConsole: true,\r\n toFile: false,\r\n pathCreated: false,\r\n // Full path to the log file\r\n pathToLog: '',\r\n // Log levels\r\n levelsDesc: [\r\n {\r\n title: 'error',\r\n color: colors[0]\r\n },\r\n {\r\n title: 'warning',\r\n color: colors[1]\r\n },\r\n {\r\n title: 'notice',\r\n color: colors[2]\r\n },\r\n {\r\n title: 'verbose',\r\n color: colors[3]\r\n },\r\n {\r\n title: 'benchmark',\r\n color: colors[4]\r\n }\r\n ]\r\n};\r\n\r\n/**\r\n * Logs a message. Accepts a variable amount of arguments. Arguments after\r\n * the `level` will be passed directly to `console.log`, and/or will be joined\r\n * and appended to the log file.\r\n *\r\n * @function log\r\n *\r\n * @param {...unknown} args - An array of arguments where the first is the log\r\n * level and the rest are strings to build a message with.\r\n *\r\n * @returns {void} Ends the function execution when attempting to log\r\n * information at a higher level than what is allowed.\r\n */\r\nexport function log(...args) {\r\n const [newLevel, ...texts] = args;\r\n\r\n // Current logging options\r\n const { levelsDesc, level } = logging;\r\n\r\n // Check if the log level is within a correct range or is it a benchmark log\r\n if (\r\n newLevel !== 5 &&\r\n (newLevel === 0 || newLevel > level || level > levelsDesc.length)\r\n ) {\r\n return;\r\n }\r\n\r\n // Create a message's prefix\r\n const prefix = `${getNewDate()} [${levelsDesc[newLevel - 1].title}] -`;\r\n\r\n // Log to file\r\n if (logging.toFile) {\r\n _logToFile(texts, prefix);\r\n }\r\n\r\n // Log to console\r\n if (logging.toConsole) {\r\n console.log.apply(\r\n undefined,\r\n [prefix.toString()[logging.levelsDesc[newLevel - 1].color]].concat(texts)\r\n );\r\n }\r\n}\r\n\r\n/**\r\n * Logs an error message with its stack trace. Optionally, a custom message\r\n * can be provided.\r\n *\r\n * @function logWithStack\r\n *\r\n * @param {number} newLevel - The log level.\r\n * @param {Error} error - The error object.\r\n * @param {string} customMessage - An optional custom message to be logged\r\n * along with the error.\r\n *\r\n * @returns {void} Ends the function execution when attempting to log\r\n * information at a higher level than what is allowed.\r\n */\r\nexport function logWithStack(newLevel, error, customMessage) {\r\n // Get the main message\r\n const mainMessage = customMessage || error.message;\r\n\r\n // Current logging options\r\n const { level, levelsDesc } = logging;\r\n\r\n // Check if the log level is within a correct range\r\n if (newLevel === 0 || newLevel > level || level > levelsDesc.length) {\r\n return;\r\n }\r\n\r\n // Create a message's prefix\r\n const prefix = `${getNewDate()} [${levelsDesc[newLevel - 1].title}] -`;\r\n\r\n // Add the whole stack message\r\n const stackMessage = error.stack;\r\n\r\n // Combine custom message or error message with error stack message, if exists\r\n const texts = [mainMessage];\r\n if (stackMessage) {\r\n texts.push('\\n', stackMessage);\r\n }\r\n\r\n // Log to file\r\n if (logging.toFile) {\r\n _logToFile(texts, prefix);\r\n }\r\n\r\n // Log to console\r\n if (logging.toConsole) {\r\n console.log.apply(\r\n undefined,\r\n [prefix.toString()[logging.levelsDesc[newLevel - 1].color]].concat([\r\n texts.shift()[colors[newLevel - 1]],\r\n ...texts\r\n ])\r\n );\r\n }\r\n}\r\n\r\n/**\r\n * Initializes logging with the specified logging configuration.\r\n *\r\n * @function initLogging\r\n *\r\n * @param {Object} loggingOptions - Object containing `logging` options.\r\n */\r\nexport function initLogging(loggingOptions) {\r\n // Get options from the `loggingOptions` object\r\n const { level, dest, file, toConsole, toFile } = loggingOptions;\r\n\r\n // Set the logging level\r\n setLogLevel(level);\r\n\r\n // Set the console logging\r\n enableConsoleLogging(toConsole);\r\n\r\n // Set the file logging\r\n enableFileLogging(dest, file, toFile);\r\n}\r\n\r\n/**\r\n * Sets the log level to the specified value. Log levels are (0 = no logging,\r\n * 1 = error, 2 = warning, 3 = notice, 4 = verbose, or 5 = benchmark).\r\n *\r\n * @function setLogLevel\r\n *\r\n * @param {number} level - The log level to be set.\r\n */\r\nexport function setLogLevel(level) {\r\n if (level >= 0 && level <= logging.levelsDesc.length) {\r\n logging.level = level;\r\n }\r\n}\r\n\r\n/**\r\n * Enables console logging.\r\n *\r\n * @function enableConsoleLogging\r\n *\r\n * @param {boolean} toConsole - The flag for setting the logging to the console.\r\n */\r\nexport function enableConsoleLogging(toConsole) {\r\n // Update options for the console logging\r\n logging.toConsole = toConsole;\r\n}\r\n\r\n/**\r\n * Enables file logging with the specified destination and log file.\r\n *\r\n * @function enableFileLogging\r\n *\r\n * @param {string} dest - The destination path for the log file.\r\n * @param {string} file - The log file name.\r\n * @param {boolean} toFile - The flag for setting the logging to a file.\r\n */\r\nexport function enableFileLogging(dest, file, toFile) {\r\n // Update options for the file logging\r\n logging.toFile = toFile;\r\n\r\n // Set the `dest` and `file` only if the file logging is enabled\r\n if (toFile) {\r\n logging.dest = dest;\r\n logging.file = file;\r\n }\r\n}\r\n\r\n/**\r\n * Logs the provided texts to a file, if file logging is enabled. It creates\r\n * the necessary directory structure if not already created and appends\r\n * the content, including an optional prefix, to the specified log file.\r\n *\r\n * @function _logToFile\r\n *\r\n * @param {Array.} texts - An array of texts to be logged.\r\n * @param {string} prefix - An optional prefix to be added to each log entry.\r\n */\r\nfunction _logToFile(texts, prefix) {\r\n if (!logging.pathCreated) {\r\n // Create if does not exist\r\n !existsSync(getAbsolutePath(logging.dest)) &&\r\n mkdirSync(getAbsolutePath(logging.dest));\r\n\r\n // Create the full path\r\n logging.pathToLog = getAbsolutePath(join(logging.dest, logging.file));\r\n\r\n // We now assume the path is available, e.g. it's the responsibility\r\n // of the user to create the path with the correct access rights.\r\n logging.pathCreated = true;\r\n }\r\n\r\n // Add the content to a file\r\n appendFile(\r\n logging.pathToLog,\r\n [prefix].concat(texts).join(' ') + '\\n',\r\n (error) => {\r\n if (error && logging.toFile && logging.pathCreated) {\r\n logging.toFile = false;\r\n logging.pathCreated = false;\r\n logWithStack(2, error, `[logger] Unable to write to log file.`);\r\n }\r\n }\r\n );\r\n}\r\n\r\nexport default {\r\n log,\r\n logWithStack,\r\n initLogging,\r\n setLogLevel,\r\n enableConsoleLogging,\r\n enableFileLogging\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * @overview Configuration management module for the Highcharts Export Server.\r\n * Provides default configurations that support environment variables, CLI\r\n * arguments, and interactive prompts for customization of options and features.\r\n * Additionally, it maps legacy options to modern structures, generates nested\r\n * argument mappings, and displays CLI usage information.\r\n */\r\n\r\n/**\r\n * The configuration object containing all available options, organized\r\n * by sections.\r\n *\r\n * This object includes:\r\n * - Default values for each option\r\n * - Data types for validation\r\n * - Names of corresponding environment variables\r\n * - Descriptions of each property\r\n * - Information used for prompts in interactive configuration\r\n * - [Optional] Corresponding CLI argument names for CLI usage\r\n * - [Optional] Legacy names from the previous PhantomJS-based server\r\n */\r\nexport const defaultConfig = {\r\n puppeteer: {\r\n args: {\r\n value: [\r\n '--allow-running-insecure-content',\r\n '--ash-no-nudges',\r\n '--autoplay-policy=user-gesture-required',\r\n '--block-new-web-contents',\r\n '--disable-accelerated-2d-canvas',\r\n '--disable-background-networking',\r\n '--disable-background-timer-throttling',\r\n '--disable-backgrounding-occluded-windows',\r\n '--disable-breakpad',\r\n '--disable-checker-imaging',\r\n '--disable-client-side-phishing-detection',\r\n '--disable-component-extensions-with-background-pages',\r\n '--disable-component-update',\r\n '--disable-default-apps',\r\n '--disable-dev-shm-usage',\r\n '--disable-domain-reliability',\r\n '--disable-extensions',\r\n '--disable-features=CalculateNativeWinOcclusion,InterestFeedContentSuggestions,WebOTP',\r\n '--disable-hang-monitor',\r\n '--disable-ipc-flooding-protection',\r\n '--disable-logging',\r\n '--disable-notifications',\r\n '--disable-offer-store-unmasked-wallet-cards',\r\n '--disable-popup-blocking',\r\n '--disable-print-preview',\r\n '--disable-prompt-on-repost',\r\n '--disable-renderer-backgrounding',\r\n '--disable-search-engine-choice-screen',\r\n '--disable-session-crashed-bubble',\r\n '--disable-setuid-sandbox',\r\n '--disable-site-isolation-trials',\r\n '--disable-speech-api',\r\n '--disable-sync',\r\n '--enable-unsafe-webgpu',\r\n '--hide-crash-restore-bubble',\r\n '--hide-scrollbars',\r\n '--metrics-recording-only',\r\n '--mute-audio',\r\n '--no-default-browser-check',\r\n '--no-first-run',\r\n '--no-pings',\r\n '--no-sandbox',\r\n '--no-startup-window',\r\n '--no-zygote',\r\n '--password-store=basic',\r\n '--process-per-tab',\r\n '--use-mock-keychain'\r\n ],\r\n types: ['string[]'],\r\n envLink: 'PUPPETEER_ARGS',\r\n cliName: 'puppeteerArgs',\r\n description: 'Array of Puppeteer arguments',\r\n promptOptions: {\r\n type: 'list',\r\n separator: ';'\r\n }\r\n }\r\n },\r\n highcharts: {\r\n version: {\r\n value: 'latest',\r\n types: ['string'],\r\n envLink: 'HIGHCHARTS_VERSION',\r\n description: 'Highcharts version',\r\n promptOptions: {\r\n type: 'text'\r\n }\r\n },\r\n cdnUrl: {\r\n value: 'https://code.highcharts.com',\r\n types: ['string'],\r\n envLink: 'HIGHCHARTS_CDN_URL',\r\n description: 'CDN URL for Highcharts scripts',\r\n promptOptions: {\r\n type: 'text'\r\n }\r\n },\r\n forceFetch: {\r\n value: false,\r\n types: ['boolean'],\r\n envLink: 'HIGHCHARTS_FORCE_FETCH',\r\n description: 'Flag to refetch scripts after each server rerun',\r\n promptOptions: {\r\n type: 'toggle'\r\n }\r\n },\r\n cachePath: {\r\n value: '.cache',\r\n types: ['string'],\r\n envLink: 'HIGHCHARTS_CACHE_PATH',\r\n description: 'Directory path for cached Highcharts scripts',\r\n promptOptions: {\r\n type: 'text'\r\n }\r\n },\r\n coreScripts: {\r\n value: ['highcharts', 'highcharts-more', 'highcharts-3d'],\r\n types: ['string[]'],\r\n envLink: 'HIGHCHARTS_CORE_SCRIPTS',\r\n description: 'Highcharts core scripts to fetch',\r\n promptOptions: {\r\n type: 'multiselect',\r\n instructions: 'Space: Select specific, A: Select all, Enter: Confirm'\r\n }\r\n },\r\n moduleScripts: {\r\n value: [\r\n 'stock',\r\n 'map',\r\n 'gantt',\r\n 'exporting',\r\n 'parallel-coordinates',\r\n 'accessibility',\r\n // 'annotations-advanced',\r\n 'boost-canvas',\r\n 'boost',\r\n 'data',\r\n 'data-tools',\r\n 'draggable-points',\r\n 'static-scale',\r\n 'broken-axis',\r\n 'heatmap',\r\n 'tilemap',\r\n 'tiledwebmap',\r\n 'timeline',\r\n 'treemap',\r\n 'treegraph',\r\n 'item-series',\r\n 'drilldown',\r\n 'histogram-bellcurve',\r\n 'bullet',\r\n 'funnel',\r\n 'funnel3d',\r\n 'geoheatmap',\r\n 'pyramid3d',\r\n 'networkgraph',\r\n 'overlapping-datalabels',\r\n 'pareto',\r\n 'pattern-fill',\r\n 'pictorial',\r\n 'price-indicator',\r\n 'sankey',\r\n 'arc-diagram',\r\n 'dependency-wheel',\r\n 'series-label',\r\n 'series-on-point',\r\n 'solid-gauge',\r\n 'sonification',\r\n // 'stock-tools',\r\n 'streamgraph',\r\n 'sunburst',\r\n 'variable-pie',\r\n 'variwide',\r\n 'vector',\r\n 'venn',\r\n 'windbarb',\r\n 'wordcloud',\r\n 'xrange',\r\n 'no-data-to-display',\r\n 'drag-panes',\r\n 'debugger',\r\n 'dumbbell',\r\n 'lollipop',\r\n 'cylinder',\r\n 'organization',\r\n 'dotplot',\r\n 'marker-clusters',\r\n 'hollowcandlestick',\r\n 'heikinashi',\r\n 'flowmap',\r\n 'export-data',\r\n 'navigator',\r\n 'textpath'\r\n ],\r\n types: ['string[]'],\r\n envLink: 'HIGHCHARTS_MODULE_SCRIPTS',\r\n description: 'Highcharts module scripts to fetch',\r\n promptOptions: {\r\n type: 'multiselect',\r\n instructions: 'Space: Select specific, A: Select all, Enter: Confirm'\r\n }\r\n },\r\n indicatorScripts: {\r\n value: ['indicators-all'],\r\n types: ['string[]'],\r\n envLink: 'HIGHCHARTS_INDICATOR_SCRIPTS',\r\n description: 'Highcharts indicator scripts to fetch',\r\n promptOptions: {\r\n type: 'multiselect',\r\n instructions: 'Space: Select specific, A: Select all, Enter: Confirm'\r\n }\r\n },\r\n customScripts: {\r\n value: [\r\n 'https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.30.1/moment.min.js',\r\n 'https://cdnjs.cloudflare.com/ajax/libs/moment-timezone/0.5.45/moment-timezone-with-data.min.js'\r\n ],\r\n types: ['string[]'],\r\n envLink: 'HIGHCHARTS_CUSTOM_SCRIPTS',\r\n description: 'Additional custom scripts or dependencies to fetch',\r\n promptOptions: {\r\n type: 'list',\r\n separator: ';'\r\n }\r\n }\r\n },\r\n export: {\r\n infile: {\r\n value: null,\r\n types: ['string', 'null'],\r\n envLink: 'EXPORT_INFILE',\r\n description:\r\n 'Input filename with type, formatted correctly as JSON or SVG',\r\n promptOptions: {\r\n type: 'text'\r\n }\r\n },\r\n instr: {\r\n value: null,\r\n types: ['string', 'null'],\r\n envLink: 'EXPORT_INSTR',\r\n description:\r\n 'Overrides the `infile` with JSON, stringified JSON, or SVG input',\r\n promptOptions: {\r\n type: 'text'\r\n }\r\n },\r\n options: {\r\n value: null,\r\n types: ['Object', 'null'],\r\n envLink: 'EXPORT_OPTIONS',\r\n description: 'Alias for the `instr` option',\r\n promptOptions: {\r\n type: 'text'\r\n }\r\n },\r\n svg: {\r\n value: null,\r\n types: ['string', 'null'],\r\n envLink: 'EXPORT_SVG',\r\n description: 'SVG string representation of the chart to render',\r\n promptOptions: {\r\n type: 'text'\r\n }\r\n },\r\n batch: {\r\n value: null,\r\n types: ['string', 'null'],\r\n envLink: 'EXPORT_BATCH',\r\n description:\r\n 'Batch job string with input/output pairs: \"in=out;in=out;...\"',\r\n promptOptions: {\r\n type: 'text'\r\n }\r\n },\r\n outfile: {\r\n value: null,\r\n types: ['string', 'null'],\r\n envLink: 'EXPORT_OUTFILE',\r\n description:\r\n 'Output filename with type. Can be jpeg, png, pdf, or svg and ignores `type` option',\r\n promptOptions: {\r\n type: 'text'\r\n }\r\n },\r\n type: {\r\n value: 'png',\r\n types: ['string'],\r\n envLink: 'EXPORT_TYPE',\r\n description: 'File export format. Can be jpeg, png, pdf, or svg',\r\n promptOptions: {\r\n type: 'select',\r\n hint: 'Default: png',\r\n choices: ['png', 'jpeg', 'pdf', 'svg']\r\n }\r\n },\r\n constr: {\r\n value: 'chart',\r\n types: ['string'],\r\n envLink: 'EXPORT_CONSTR',\r\n description:\r\n 'Chart constructor. Can be chart, stockChart, mapChart, or ganttChart',\r\n promptOptions: {\r\n type: 'select',\r\n hint: 'Default: chart',\r\n choices: ['chart', 'stockChart', 'mapChart', 'ganttChart']\r\n }\r\n },\r\n b64: {\r\n value: false,\r\n types: ['boolean'],\r\n envLink: 'EXPORT_B64',\r\n description:\r\n 'Whether or not to the chart should be received in Base64 format instead of binary',\r\n promptOptions: {\r\n type: 'toggle'\r\n }\r\n },\r\n noDownload: {\r\n value: false,\r\n types: ['boolean'],\r\n envLink: 'EXPORT_NO_DOWNLOAD',\r\n description:\r\n 'Whether or not to include or exclude attachment headers in the response',\r\n promptOptions: {\r\n type: 'toggle'\r\n }\r\n },\r\n height: {\r\n value: null,\r\n types: ['number', 'null'],\r\n envLink: 'EXPORT_HEIGHT',\r\n description: 'Height of the exported chart, overrides chart settings',\r\n promptOptions: {\r\n type: 'number'\r\n }\r\n },\r\n width: {\r\n value: null,\r\n types: ['number', 'null'],\r\n envLink: 'EXPORT_WIDTH',\r\n description: 'Width of the exported chart, overrides chart settings',\r\n promptOptions: {\r\n type: 'number'\r\n }\r\n },\r\n scale: {\r\n value: null,\r\n types: ['number', 'null'],\r\n envLink: 'EXPORT_SCALE',\r\n description:\r\n 'Scale of the exported chart, overrides chart settings. Ranges from 0.1 to 5.0',\r\n promptOptions: {\r\n type: 'number'\r\n }\r\n },\r\n defaultHeight: {\r\n value: 400,\r\n types: ['number'],\r\n envLink: 'EXPORT_DEFAULT_HEIGHT',\r\n description: 'Default height of the exported chart if not set',\r\n promptOptions: {\r\n type: 'number'\r\n }\r\n },\r\n defaultWidth: {\r\n value: 600,\r\n types: ['number'],\r\n envLink: 'EXPORT_DEFAULT_WIDTH',\r\n description: 'Default width of the exported chart if not set',\r\n promptOptions: {\r\n type: 'number'\r\n }\r\n },\r\n defaultScale: {\r\n value: 1,\r\n types: ['number'],\r\n envLink: 'EXPORT_DEFAULT_SCALE',\r\n description:\r\n 'Default scale of the exported chart if not set. Ranges from 0.1 to 5.0',\r\n promptOptions: {\r\n type: 'number',\r\n min: 0.1,\r\n max: 5\r\n }\r\n },\r\n globalOptions: {\r\n value: null,\r\n types: ['Object', 'string', 'null'],\r\n envLink: 'EXPORT_GLOBAL_OPTIONS',\r\n description:\r\n 'JSON, stringified JSON or filename with global options for Highcharts.setOptions',\r\n promptOptions: {\r\n type: 'text'\r\n }\r\n },\r\n themeOptions: {\r\n value: null,\r\n types: ['Object', 'string', 'null'],\r\n envLink: 'EXPORT_THEME_OPTIONS',\r\n description:\r\n 'JSON, stringified JSON or filename with theme options for Highcharts.setOptions',\r\n promptOptions: {\r\n type: 'text'\r\n }\r\n },\r\n rasterizationTimeout: {\r\n value: 1500,\r\n types: ['number'],\r\n envLink: 'EXPORT_RASTERIZATION_TIMEOUT',\r\n description: 'Milliseconds to wait for webpage rendering',\r\n promptOptions: {\r\n type: 'number'\r\n }\r\n }\r\n },\r\n customLogic: {\r\n allowCodeExecution: {\r\n value: false,\r\n types: ['boolean'],\r\n envLink: 'CUSTOM_LOGIC_ALLOW_CODE_EXECUTION',\r\n description:\r\n 'Allows or disallows execution of arbitrary code during exporting',\r\n promptOptions: {\r\n type: 'toggle'\r\n }\r\n },\r\n allowFileResources: {\r\n value: false,\r\n types: ['boolean'],\r\n envLink: 'CUSTOM_LOGIC_ALLOW_FILE_RESOURCES',\r\n description:\r\n 'Allows or disallows injection of filesystem resources (disabled in server mode)',\r\n promptOptions: {\r\n type: 'toggle'\r\n }\r\n },\r\n customCode: {\r\n value: null,\r\n types: ['string', 'null'],\r\n envLink: 'CUSTOM_LOGIC_CUSTOM_CODE',\r\n description:\r\n 'Custom code to execute before chart initialization. Can be a function, code wrapped in a function, or a .js filename',\r\n promptOptions: {\r\n type: 'text'\r\n }\r\n },\r\n callback: {\r\n value: null,\r\n types: ['string', 'null'],\r\n envLink: 'CUSTOM_LOGIC_CALLBACK',\r\n description:\r\n 'JavaScript code to run during construction. Can be a function or a .js filename',\r\n promptOptions: {\r\n type: 'text'\r\n }\r\n },\r\n resources: {\r\n value: null,\r\n types: ['Object', 'string', 'null'],\r\n envLink: 'CUSTOM_LOGIC_RESOURCES',\r\n description:\r\n 'Additional resources as JSON, stringified JSON, or filename, containing files, js, and css sections',\r\n promptOptions: {\r\n type: 'text'\r\n }\r\n },\r\n loadConfig: {\r\n value: null,\r\n types: ['string', 'null'],\r\n envLink: 'CUSTOM_LOGIC_LOAD_CONFIG',\r\n legacyName: 'fromFile',\r\n description: 'File with a pre-defined configuration to use',\r\n promptOptions: {\r\n type: 'text'\r\n }\r\n },\r\n createConfig: {\r\n value: null,\r\n types: ['string', 'null'],\r\n envLink: 'CUSTOM_LOGIC_CREATE_CONFIG',\r\n description:\r\n 'Prompt-based option setting, saved to a provided config file',\r\n promptOptions: {\r\n type: 'text'\r\n }\r\n }\r\n },\r\n server: {\r\n enable: {\r\n value: false,\r\n types: ['boolean'],\r\n envLink: 'SERVER_ENABLE',\r\n cliName: 'enableServer',\r\n description: 'Starts the server when true',\r\n promptOptions: {\r\n type: 'toggle'\r\n }\r\n },\r\n host: {\r\n value: '0.0.0.0',\r\n types: ['string'],\r\n envLink: 'SERVER_HOST',\r\n description: 'Hostname of the server',\r\n promptOptions: {\r\n type: 'text'\r\n }\r\n },\r\n port: {\r\n value: 7801,\r\n types: ['number'],\r\n envLink: 'SERVER_PORT',\r\n description: 'Port number for the server',\r\n promptOptions: {\r\n type: 'number'\r\n }\r\n },\r\n uploadLimit: {\r\n value: 3,\r\n types: ['number'],\r\n envLink: 'SERVER_UPLOAD_LIMIT',\r\n description: 'Maximum request body size in MB',\r\n promptOptions: {\r\n type: 'number'\r\n }\r\n },\r\n benchmarking: {\r\n value: false,\r\n types: ['boolean'],\r\n envLink: 'SERVER_BENCHMARKING',\r\n cliName: 'serverBenchmarking',\r\n description:\r\n 'Displays or not action durations in milliseconds during server requests',\r\n promptOptions: {\r\n type: 'toggle'\r\n }\r\n },\r\n proxy: {\r\n host: {\r\n value: null,\r\n types: ['string', 'null'],\r\n envLink: 'SERVER_PROXY_HOST',\r\n cliName: 'proxyHost',\r\n description: 'Host of the proxy server, if applicable',\r\n promptOptions: {\r\n type: 'text'\r\n }\r\n },\r\n port: {\r\n value: null,\r\n types: ['number', 'null'],\r\n envLink: 'SERVER_PROXY_PORT',\r\n cliName: 'proxyPort',\r\n description: 'Port of the proxy server, if applicable',\r\n promptOptions: {\r\n type: 'number'\r\n }\r\n },\r\n timeout: {\r\n value: 5000,\r\n types: ['number'],\r\n envLink: 'SERVER_PROXY_TIMEOUT',\r\n cliName: 'proxyTimeout',\r\n description:\r\n 'Timeout in milliseconds for the proxy server, if applicable',\r\n promptOptions: {\r\n type: 'number'\r\n }\r\n }\r\n },\r\n rateLimiting: {\r\n enable: {\r\n value: false,\r\n types: ['boolean'],\r\n envLink: 'SERVER_RATE_LIMITING_ENABLE',\r\n cliName: 'enableRateLimiting',\r\n description: 'Enables or disables rate limiting on the server',\r\n promptOptions: {\r\n type: 'toggle'\r\n }\r\n },\r\n maxRequests: {\r\n value: 10,\r\n types: ['number'],\r\n envLink: 'SERVER_RATE_LIMITING_MAX_REQUESTS',\r\n legacyName: 'rateLimit',\r\n description: 'Maximum number of requests allowed per minute',\r\n promptOptions: {\r\n type: 'number'\r\n }\r\n },\r\n window: {\r\n value: 1,\r\n types: ['number'],\r\n envLink: 'SERVER_RATE_LIMITING_WINDOW',\r\n description: 'Time window in minutes for rate limiting',\r\n promptOptions: {\r\n type: 'number'\r\n }\r\n },\r\n delay: {\r\n value: 0,\r\n types: ['number'],\r\n envLink: 'SERVER_RATE_LIMITING_DELAY',\r\n description:\r\n 'Delay duration between successive requests before reaching the limit',\r\n promptOptions: {\r\n type: 'number'\r\n }\r\n },\r\n trustProxy: {\r\n value: false,\r\n types: ['boolean'],\r\n envLink: 'SERVER_RATE_LIMITING_TRUST_PROXY',\r\n description: 'Set to true if the server is behind a load balancer',\r\n promptOptions: {\r\n type: 'toggle'\r\n }\r\n },\r\n skipKey: {\r\n value: null,\r\n types: ['string', 'null'],\r\n envLink: 'SERVER_RATE_LIMITING_SKIP_KEY',\r\n description: 'Key to bypass the rate limiter, used with `skipToken`',\r\n promptOptions: {\r\n type: 'text'\r\n }\r\n },\r\n skipToken: {\r\n value: null,\r\n types: ['string', 'null'],\r\n envLink: 'SERVER_RATE_LIMITING_SKIP_TOKEN',\r\n description: 'Token to bypass the rate limiter, used with `skipKey`',\r\n promptOptions: {\r\n type: 'text'\r\n }\r\n }\r\n },\r\n ssl: {\r\n enable: {\r\n value: false,\r\n types: ['boolean'],\r\n envLink: 'SERVER_SSL_ENABLE',\r\n cliName: 'enableSsl',\r\n description: 'Enables or disables SSL protocol',\r\n promptOptions: {\r\n type: 'toggle'\r\n }\r\n },\r\n force: {\r\n value: false,\r\n types: ['boolean'],\r\n envLink: 'SERVER_SSL_FORCE',\r\n cliName: 'sslForce',\r\n legacyName: 'sslOnly',\r\n description: 'Forces the server to use HTTPS only when true',\r\n promptOptions: {\r\n type: 'toggle'\r\n }\r\n },\r\n port: {\r\n value: 443,\r\n types: ['number'],\r\n envLink: 'SERVER_SSL_PORT',\r\n cliName: 'sslPort',\r\n description: 'Port for the SSL server',\r\n promptOptions: {\r\n type: 'number'\r\n }\r\n },\r\n certPath: {\r\n value: null,\r\n types: ['string', 'null'],\r\n envLink: 'SERVER_SSL_CERT_PATH',\r\n cliName: 'sslCertPath',\r\n legacyName: 'sslPath',\r\n description: 'Path to the SSL certificate/key file',\r\n promptOptions: {\r\n type: 'text'\r\n }\r\n }\r\n }\r\n },\r\n pool: {\r\n minWorkers: {\r\n value: 4,\r\n types: ['number'],\r\n envLink: 'POOL_MIN_WORKERS',\r\n description: 'Minimum and initial number of pool workers to spawn',\r\n promptOptions: {\r\n type: 'number'\r\n }\r\n },\r\n maxWorkers: {\r\n value: 8,\r\n types: ['number'],\r\n envLink: 'POOL_MAX_WORKERS',\r\n legacyName: 'workers',\r\n description: 'Maximum number of pool workers to spawn',\r\n promptOptions: {\r\n type: 'number'\r\n }\r\n },\r\n workLimit: {\r\n value: 40,\r\n types: ['number'],\r\n envLink: 'POOL_WORK_LIMIT',\r\n description: 'Number of tasks a worker can handle before restarting',\r\n promptOptions: {\r\n type: 'number'\r\n }\r\n },\r\n acquireTimeout: {\r\n value: 5000,\r\n types: ['number'],\r\n envLink: 'POOL_ACQUIRE_TIMEOUT',\r\n description: 'Timeout in milliseconds for acquiring a resource',\r\n promptOptions: {\r\n type: 'number'\r\n }\r\n },\r\n createTimeout: {\r\n value: 5000,\r\n types: ['number'],\r\n envLink: 'POOL_CREATE_TIMEOUT',\r\n description: 'Timeout in milliseconds for creating a resource',\r\n promptOptions: {\r\n type: 'number'\r\n }\r\n },\r\n destroyTimeout: {\r\n value: 5000,\r\n types: ['number'],\r\n envLink: 'POOL_DESTROY_TIMEOUT',\r\n description: 'Timeout in milliseconds for destroying a resource',\r\n promptOptions: {\r\n type: 'number'\r\n }\r\n },\r\n idleTimeout: {\r\n value: 30000,\r\n types: ['number'],\r\n envLink: 'POOL_IDLE_TIMEOUT',\r\n description: 'Timeout in milliseconds for destroying idle resources',\r\n promptOptions: {\r\n type: 'number'\r\n }\r\n },\r\n createRetryInterval: {\r\n value: 200,\r\n types: ['number'],\r\n envLink: 'POOL_CREATE_RETRY_INTERVAL',\r\n description:\r\n 'Interval in milliseconds before retrying resource creation on failure',\r\n promptOptions: {\r\n type: 'number'\r\n }\r\n },\r\n reaperInterval: {\r\n value: 1000,\r\n types: ['number'],\r\n envLink: 'POOL_REAPER_INTERVAL',\r\n description:\r\n 'Interval in milliseconds to check and destroy idle resources',\r\n promptOptions: {\r\n type: 'number'\r\n }\r\n },\r\n benchmarking: {\r\n value: false,\r\n types: ['boolean'],\r\n envLink: 'POOL_BENCHMARKING',\r\n cliName: 'poolBenchmarking',\r\n description: 'Shows statistics for the pool of resources',\r\n promptOptions: {\r\n type: 'toggle'\r\n }\r\n }\r\n },\r\n logging: {\r\n level: {\r\n value: 4,\r\n types: ['number'],\r\n envLink: 'LOGGING_LEVEL',\r\n cliName: 'logLevel',\r\n description: 'Logging verbosity level',\r\n promptOptions: {\r\n type: 'number',\r\n round: 0,\r\n min: 0,\r\n max: 5\r\n }\r\n },\r\n file: {\r\n value: 'highcharts-export-server.log',\r\n types: ['string'],\r\n envLink: 'LOGGING_FILE',\r\n cliName: 'logFile',\r\n description:\r\n 'Log file name. Requires `logToFile` and `logDest` to be set',\r\n promptOptions: {\r\n type: 'text'\r\n }\r\n },\r\n dest: {\r\n value: 'log',\r\n types: ['string'],\r\n envLink: 'LOGGING_DEST',\r\n cliName: 'logDest',\r\n description: 'Path to store log files. Requires `logToFile` to be set',\r\n promptOptions: {\r\n type: 'text'\r\n }\r\n },\r\n toConsole: {\r\n value: true,\r\n types: ['boolean'],\r\n envLink: 'LOGGING_TO_CONSOLE',\r\n cliName: 'logToConsole',\r\n description: 'Enables or disables console logging',\r\n promptOptions: {\r\n type: 'toggle'\r\n }\r\n },\r\n toFile: {\r\n value: true,\r\n types: ['boolean'],\r\n envLink: 'LOGGING_TO_FILE',\r\n cliName: 'logToFile',\r\n description: 'Enables or disables logging to a file',\r\n promptOptions: {\r\n type: 'toggle'\r\n }\r\n }\r\n },\r\n ui: {\r\n enable: {\r\n value: false,\r\n types: ['boolean'],\r\n envLink: 'UI_ENABLE',\r\n cliName: 'enableUi',\r\n description: 'Enables or disables the UI for the export server',\r\n promptOptions: {\r\n type: 'toggle'\r\n }\r\n },\r\n route: {\r\n value: '/',\r\n types: ['string'],\r\n envLink: 'UI_ROUTE',\r\n cliName: 'uiRoute',\r\n description: 'The endpoint route for the UI',\r\n promptOptions: {\r\n type: 'text'\r\n }\r\n }\r\n },\r\n other: {\r\n nodeEnv: {\r\n value: 'production',\r\n types: ['string'],\r\n envLink: 'OTHER_NODE_ENV',\r\n description: 'The Node.js environment type',\r\n promptOptions: {\r\n type: 'text'\r\n }\r\n },\r\n listenToProcessExits: {\r\n value: true,\r\n types: ['boolean'],\r\n envLink: 'OTHER_LISTEN_TO_PROCESS_EXITS',\r\n description: 'Whether or not to attach process.exit handlers',\r\n promptOptions: {\r\n type: 'toggle'\r\n }\r\n },\r\n noLogo: {\r\n value: false,\r\n types: ['boolean'],\r\n envLink: 'OTHER_NO_LOGO',\r\n description: 'Display or skip printing the logo on startup',\r\n promptOptions: {\r\n type: 'toggle'\r\n }\r\n },\r\n hardResetPage: {\r\n value: false,\r\n types: ['boolean'],\r\n envLink: 'OTHER_HARD_RESET_PAGE',\r\n description: 'Whether or not to reset the page content entirely',\r\n promptOptions: {\r\n type: 'toggle'\r\n }\r\n },\r\n browserShellMode: {\r\n value: true,\r\n types: ['boolean'],\r\n envLink: 'OTHER_BROWSER_SHELL_MODE',\r\n description: 'Whether or not to set the browser to run in shell mode',\r\n promptOptions: {\r\n type: 'toggle'\r\n }\r\n }\r\n },\r\n debug: {\r\n enable: {\r\n value: false,\r\n types: ['boolean'],\r\n envLink: 'DEBUG_ENABLE',\r\n cliName: 'enableDebug',\r\n description: 'Enables or disables debug mode for the underlying browser',\r\n promptOptions: {\r\n type: 'toggle'\r\n }\r\n },\r\n headless: {\r\n value: false,\r\n types: ['boolean'],\r\n envLink: 'DEBUG_HEADLESS',\r\n description:\r\n 'Whether or not to set the browser to run in headless mode during debugging',\r\n promptOptions: {\r\n type: 'toggle'\r\n }\r\n },\r\n devtools: {\r\n value: false,\r\n types: ['boolean'],\r\n envLink: 'DEBUG_DEVTOOLS',\r\n description: 'Enables or disables DevTools in headful mode',\r\n promptOptions: {\r\n type: 'toggle'\r\n }\r\n },\r\n listenToConsole: {\r\n value: false,\r\n types: ['boolean'],\r\n envLink: 'DEBUG_LISTEN_TO_CONSOLE',\r\n description:\r\n 'Enables or disables listening to console messages from the browser',\r\n promptOptions: {\r\n type: 'toggle'\r\n }\r\n },\r\n dumpio: {\r\n value: false,\r\n types: ['boolean'],\r\n envLink: 'DEBUG_DUMPIO',\r\n description:\r\n 'Redirects or not browser stdout and stderr to process.stdout and process.stderr',\r\n promptOptions: {\r\n type: 'toggle'\r\n }\r\n },\r\n slowMo: {\r\n value: 0,\r\n types: ['number'],\r\n envLink: 'DEBUG_SLOW_MO',\r\n description: 'Delays Puppeteer operations by the specified milliseconds',\r\n promptOptions: {\r\n type: 'number'\r\n }\r\n },\r\n debuggingPort: {\r\n value: 9222,\r\n types: ['number'],\r\n envLink: 'DEBUG_DEBUGGING_PORT',\r\n description: 'Port used for debugging',\r\n promptOptions: {\r\n type: 'number'\r\n }\r\n }\r\n }\r\n};\r\n\r\n// Properties nesting level of all options\r\nexport const nestedProps = _createNestedProps(defaultConfig);\r\n\r\n// Properties names that should not be recursively merged\r\nexport const absoluteProps = _createAbsoluteProps(defaultConfig);\r\n\r\n/**\r\n * Recursively generates a mapping of nested argument chains from a nested\r\n * config object. This function traverses a nested object and creates a mapping\r\n * where each key is an argument name (either from `cliName`, `legacyName`,\r\n * or the original key) and each value is a string representing the chain\r\n * of nested properties leading to that argument.\r\n *\r\n * @function _createNestedProps\r\n *\r\n * @param {Object} config - The configuration object.\r\n * @param {Object} [nestedProps={}] - The accumulator object for storing\r\n * the resulting arguments chains. The default value is an empty object.\r\n * @param {string} [propChain=''] - The current chain of nested properties,\r\n * used internally during recursion. The default value is an empty string.\r\n *\r\n * @returns {Object} An object mapping argument names to their corresponding\r\n * nested property chains.\r\n */\r\nfunction _createNestedProps(config, nestedProps = {}, propChain = '') {\r\n Object.keys(config).forEach((key) => {\r\n // Get the specific section\r\n const entry = config[key];\r\n\r\n // Check if there is still more depth to traverse\r\n if (typeof entry.value === 'undefined') {\r\n // Recurse into deeper levels of nested arguments\r\n _createNestedProps(entry, nestedProps, `${propChain}.${key}`);\r\n } else {\r\n // Create the chain of nested arguments\r\n nestedProps[entry.cliName || key] = `${propChain}.${key}`.substring(1);\r\n\r\n // Support for the legacy, PhantomJS properties names\r\n if (entry.legacyName !== undefined) {\r\n nestedProps[entry.legacyName] = `${propChain}.${key}`.substring(1);\r\n }\r\n }\r\n });\r\n\r\n // Return the object with nested argument chains\r\n return nestedProps;\r\n}\r\n\r\n/**\r\n * Recursively gathers the names of properties from a configuration object that\r\n * can be treated as absolute properties. These properties have values that\r\n * are objects and do not contain further nested depth when merging an object\r\n * containing these options.\r\n *\r\n * @function _createAbsoluteProps\r\n *\r\n * @param {Object} config - The configuration object.\r\n * @param {Array.} [absoluteProps=[]] - An array to collect the names\r\n * of absolute properties. The default value is an empty array.\r\n *\r\n * @returns {Array.} An array containing the names of absolute\r\n * properties.\r\n */\r\nfunction _createAbsoluteProps(config, absoluteProps = []) {\r\n Object.keys(config).forEach((key) => {\r\n // Get the specific section\r\n const entry = config[key];\r\n\r\n // Check if there is still more depth to traverse\r\n if (typeof entry.types === 'undefined') {\r\n // Recurse into deeper levels\r\n _createAbsoluteProps(entry, absoluteProps);\r\n } else {\r\n // If the option can be an object, save its type in the array\r\n if (entry.types.includes('Object')) {\r\n absoluteProps.push(key);\r\n }\r\n }\r\n });\r\n\r\n // Return the array with the names of absolute properties\r\n return absoluteProps;\r\n}\r\n\r\nexport default {\r\n defaultConfig,\r\n nestedProps,\r\n absoluteProps\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * @overview This file is responsible for parsing the environment variables\r\n * with the 'zod' library. The parsed environment variables are then exported\r\n * to be used in the application as `envs`. We should not use the `process.env`\r\n * directly in the application as these would not be parsed properly.\r\n *\r\n * The environment variables are parsed and validated only once when\r\n * the application starts. We should write a custom validator or a transformer\r\n * for each of the options.\r\n */\r\n\r\nimport dotenv from 'dotenv';\r\nimport { z } from 'zod';\r\n\r\nimport { defaultConfig } from './schemas/config.js';\r\n\r\n// Load .env into environment variables\r\ndotenv.config();\r\n\r\n// Object with custom validators and transformers, to avoid repetition\r\n// in the Config object\r\nconst v = {\r\n // Splits string value into elements in an array, trims every element, checks\r\n // if an array is correct, if it is empty, and if it is, returns undefined\r\n array: (filterArray) =>\r\n z\r\n .string()\r\n .transform((value) =>\r\n value\r\n .split(',')\r\n .map((value) => value.trim())\r\n .filter((value) => filterArray.includes(value))\r\n )\r\n .transform((value) => (value.length ? value : undefined)),\r\n\r\n // Allows only true, false and correctly parse the value to boolean\r\n // or no value in which case the returned value will be undefined\r\n boolean: () =>\r\n z\r\n .enum(['true', 'false', ''])\r\n .transform((value) => (value !== '' ? value === 'true' : undefined)),\r\n\r\n // Allows passed values or no value in which case the returned value will\r\n // be undefined\r\n enum: (values) =>\r\n z\r\n .enum([...values, ''])\r\n .transform((value) => (value !== '' ? value : undefined)),\r\n\r\n // Trims the string value and checks if it is empty or contains stringified\r\n // values such as false, undefined, null, NaN, if it does, returns undefined\r\n string: () =>\r\n z\r\n .string()\r\n .trim()\r\n .refine(\r\n (value) =>\r\n !['false', 'undefined', 'null', 'NaN'].includes(value) ||\r\n value === '',\r\n (value) => ({\r\n message: `The string contains forbidden values, received '${value}'`\r\n })\r\n )\r\n .transform((value) => (value !== '' ? value : undefined)),\r\n\r\n // Allows positive numbers or no value in which case the returned value will\r\n // be undefined\r\n positiveNum: () =>\r\n z\r\n .string()\r\n .trim()\r\n .refine(\r\n (value) =>\r\n value === '' || (!isNaN(parseFloat(value)) && parseFloat(value) > 0),\r\n (value) => ({\r\n message: `The value must be numeric and positive, received '${value}'`\r\n })\r\n )\r\n .transform((value) => (value !== '' ? parseFloat(value) : undefined)),\r\n\r\n // Allows non-negative numbers or no value in which case the returned value\r\n // will be undefined\r\n nonNegativeNum: () =>\r\n z\r\n .string()\r\n .trim()\r\n .refine(\r\n (value) =>\r\n value === '' || (!isNaN(parseFloat(value)) && parseFloat(value) >= 0),\r\n (value) => ({\r\n message: `The value must be numeric and non-negative, received '${value}'`\r\n })\r\n )\r\n .transform((value) => (value !== '' ? parseFloat(value) : undefined))\r\n};\r\n\r\nexport const Config = z.object({\r\n // puppeteer\r\n PUPPETEER_ARGS: v.string(),\r\n\r\n // highcharts\r\n HIGHCHARTS_VERSION: z\r\n .string()\r\n .trim()\r\n .refine(\r\n (value) => /^(latest|\\d+(\\.\\d+){0,2})$/.test(value) || value === '',\r\n (value) => ({\r\n message: `HIGHCHARTS_VERSION must be 'latest', a major version, or in the form XX.YY.ZZ, received '${value}'`\r\n })\r\n )\r\n .transform((value) => (value !== '' ? value : undefined)),\r\n HIGHCHARTS_CDN_URL: z\r\n .string()\r\n .trim()\r\n .refine(\r\n (value) =>\r\n value.startsWith('https://') ||\r\n value.startsWith('http://') ||\r\n value === '',\r\n (value) => ({\r\n message: `Invalid value for HIGHCHARTS_CDN_URL. It should start with http:// or https://, received '${value}'`\r\n })\r\n )\r\n .transform((value) => (value !== '' ? value : undefined)),\r\n HIGHCHARTS_FORCE_FETCH: v.boolean(),\r\n HIGHCHARTS_CACHE_PATH: v.string(),\r\n HIGHCHARTS_ADMIN_TOKEN: v.string(),\r\n HIGHCHARTS_CORE_SCRIPTS: v.array(defaultConfig.highcharts.coreScripts.value),\r\n HIGHCHARTS_MODULE_SCRIPTS: v.array(\r\n defaultConfig.highcharts.moduleScripts.value\r\n ),\r\n HIGHCHARTS_INDICATOR_SCRIPTS: v.array(\r\n defaultConfig.highcharts.indicatorScripts.value\r\n ),\r\n HIGHCHARTS_CUSTOM_SCRIPTS: v.array(\r\n defaultConfig.highcharts.customScripts.value\r\n ),\r\n\r\n // export\r\n EXPORT_INFILE: v.string(),\r\n EXPORT_INSTR: v.string(),\r\n EXPORT_OPTIONS: v.string(),\r\n EXPORT_SVG: v.string(),\r\n EXPORT_BATCH: v.string(),\r\n EXPORT_OUTFILE: v.string(),\r\n EXPORT_TYPE: v.enum(['jpeg', 'png', 'pdf', 'svg']),\r\n EXPORT_CONSTR: v.enum(['chart', 'stockChart', 'mapChart', 'ganttChart']),\r\n EXPORT_B64: v.boolean(),\r\n EXPORT_NO_DOWNLOAD: v.boolean(),\r\n EXPORT_HEIGHT: v.positiveNum(),\r\n EXPORT_WIDTH: v.positiveNum(),\r\n EXPORT_SCALE: v.positiveNum(),\r\n EXPORT_DEFAULT_HEIGHT: v.positiveNum(),\r\n EXPORT_DEFAULT_WIDTH: v.positiveNum(),\r\n EXPORT_DEFAULT_SCALE: v.positiveNum(),\r\n EXPORT_GLOBAL_OPTIONS: v.string(),\r\n EXPORT_THEME_OPTIONS: v.string(),\r\n EXPORT_RASTERIZATION_TIMEOUT: v.nonNegativeNum(),\r\n\r\n // custom\r\n CUSTOM_LOGIC_ALLOW_CODE_EXECUTION: v.boolean(),\r\n CUSTOM_LOGIC_ALLOW_FILE_RESOURCES: v.boolean(),\r\n CUSTOM_LOGIC_CUSTOM_CODE: v.string(),\r\n CUSTOM_LOGIC_CALLBACK: v.string(),\r\n CUSTOM_LOGIC_RESOURCES: v.string(),\r\n CUSTOM_LOGIC_LOAD_CONFIG: v.string(),\r\n CUSTOM_LOGIC_CREATE_CONFIG: v.string(),\r\n\r\n // server\r\n SERVER_ENABLE: v.boolean(),\r\n SERVER_HOST: v.string(),\r\n SERVER_PORT: v.positiveNum(),\r\n SERVER_UPLOAD_LIMIT: v.positiveNum(),\r\n SERVER_BENCHMARKING: v.boolean(),\r\n\r\n // server proxy\r\n SERVER_PROXY_HOST: v.string(),\r\n SERVER_PROXY_PORT: v.positiveNum(),\r\n SERVER_PROXY_TIMEOUT: v.nonNegativeNum(),\r\n\r\n // server rate limiting\r\n SERVER_RATE_LIMITING_ENABLE: v.boolean(),\r\n SERVER_RATE_LIMITING_MAX_REQUESTS: v.nonNegativeNum(),\r\n SERVER_RATE_LIMITING_WINDOW: v.nonNegativeNum(),\r\n SERVER_RATE_LIMITING_DELAY: v.nonNegativeNum(),\r\n SERVER_RATE_LIMITING_TRUST_PROXY: v.boolean(),\r\n SERVER_RATE_LIMITING_SKIP_KEY: v.string(),\r\n SERVER_RATE_LIMITING_SKIP_TOKEN: v.string(),\r\n\r\n // server ssl\r\n SERVER_SSL_ENABLE: v.boolean(),\r\n SERVER_SSL_FORCE: v.boolean(),\r\n SERVER_SSL_PORT: v.positiveNum(),\r\n SERVER_SSL_CERT_PATH: v.string(),\r\n\r\n // pool\r\n POOL_MIN_WORKERS: v.nonNegativeNum(),\r\n POOL_MAX_WORKERS: v.nonNegativeNum(),\r\n POOL_WORK_LIMIT: v.positiveNum(),\r\n POOL_ACQUIRE_TIMEOUT: v.nonNegativeNum(),\r\n POOL_CREATE_TIMEOUT: v.nonNegativeNum(),\r\n POOL_DESTROY_TIMEOUT: v.nonNegativeNum(),\r\n POOL_IDLE_TIMEOUT: v.nonNegativeNum(),\r\n POOL_CREATE_RETRY_INTERVAL: v.nonNegativeNum(),\r\n POOL_REAPER_INTERVAL: v.nonNegativeNum(),\r\n POOL_BENCHMARKING: v.boolean(),\r\n\r\n // logger\r\n LOGGING_LEVEL: z\r\n .string()\r\n .trim()\r\n .refine(\r\n (value) =>\r\n value === '' ||\r\n (!isNaN(parseFloat(value)) &&\r\n parseFloat(value) >= 0 &&\r\n parseFloat(value) <= 5),\r\n (value) => ({\r\n message: `Invalid value for LOGGING_LEVEL. We only accept values from 0 to 5 as logging levels, received '${value}'`\r\n })\r\n )\r\n .transform((value) => (value !== '' ? parseFloat(value) : undefined)),\r\n LOGGING_FILE: v.string(),\r\n LOGGING_DEST: v.string(),\r\n LOGGING_TO_CONSOLE: v.boolean(),\r\n LOGGING_TO_FILE: v.boolean(),\r\n\r\n // ui\r\n UI_ENABLE: v.boolean(),\r\n UI_ROUTE: v.string(),\r\n\r\n // other\r\n OTHER_NODE_ENV: v.enum(['development', 'production', 'test']),\r\n OTHER_LISTEN_TO_PROCESS_EXITS: v.boolean(),\r\n OTHER_NO_LOGO: v.boolean(),\r\n OTHER_HARD_RESET_PAGE: v.boolean(),\r\n OTHER_BROWSER_SHELL_MODE: v.boolean(),\r\n\r\n // debugger\r\n DEBUG_ENABLE: v.boolean(),\r\n DEBUG_HEADLESS: v.boolean(),\r\n DEBUG_DEVTOOLS: v.boolean(),\r\n DEBUG_LISTEN_TO_CONSOLE: v.boolean(),\r\n DEBUG_DUMPIO: v.boolean(),\r\n DEBUG_SLOW_MO: v.nonNegativeNum(),\r\n DEBUG_DEBUGGING_PORT: v.positiveNum()\r\n});\r\n\r\nexport const envs = Config.partial().parse(process.env);\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * @overview Manages configuration for the Highcharts Export Server by loading\r\n * and merging options from multiple sources, such as default settings,\r\n * environment variables, user-provided options, and command-line arguments.\r\n * Ensures the global options are up-to-date with the highest priority values.\r\n * Provides functions for accessing and updating configuration.\r\n */\r\n\r\nimport { readFileSync } from 'fs';\r\nimport { join } from 'path';\r\n\r\nimport { log, logWithStack } from './logger.js';\r\nimport { envs } from './envs.js';\r\nimport { __dirname, isObject, deepCopy, getAbsolutePath } from './utils.js';\r\nimport { defaultConfig, nestedProps, absoluteProps } from './schemas/config.js';\r\n\r\n// Sets the global options with initial values from the default config\r\nconst globalOptions = _initGlobalOptions(defaultConfig);\r\n\r\n/**\r\n * Gets the reference to the global options of the server instance object\r\n * or its copy.\r\n *\r\n * @function getOptions\r\n *\r\n * @param {boolean} [getReference=true] - Optional parameter to decide whether\r\n * to return the reference to the global options of the server instance object\r\n * or return a copy of it. The default value is true.\r\n *\r\n * @returns {Object} The reference to the global options of the server instance\r\n * object or its copy.\r\n */\r\nexport function getOptions(getReference = true) {\r\n return getReference ? globalOptions : deepCopy(globalOptions);\r\n}\r\n\r\n/**\r\n * Sets the global options of the export server instance, keeping the principle\r\n * of the options load priority from all available sources. It accepts optional\r\n * `customOptions` object and `cliArgs` array with arguments from the CLI. These\r\n * options will be validated and applied if provided.\r\n *\r\n * The priority order of setting values is:\r\n *\r\n * 1. Options from the `lib/schemas/config.js` file (default values).\r\n * 2. Options from a custom JSON file (loaded by the `loadConfig` option).\r\n * 3. Options from the environment variables (the `.env` file).\r\n * 4. Options from the first parameter (by default an empty object).\r\n * 5. Options from the CLI.\r\n *\r\n * @function setOptions\r\n *\r\n * @param {Object} [customOptions={}] - Optional custom options for additional\r\n * configuration. The default value is an empty object.\r\n * @param {Array.} [cliArgs=[]] - Optional command line arguments\r\n * for additional configuration. The default value is an empty array.\r\n * @param {boolean} [modifyGlobal=false] - Optional parameter to decide\r\n * whether to update and return the reference to the global options\r\n * of the server instance object or return a copy of it. The default value\r\n * is false.\r\n *\r\n * @returns {Object} The updated general options object, reflecting the merged\r\n * configuration from all available sources.\r\n */\r\nexport function setOptions(\r\n customOptions = {},\r\n cliArgs = [],\r\n modifyGlobal = false\r\n) {\r\n // Object for options loaded via the `loadConfig` option\r\n let configOptions = {};\r\n\r\n // Object for options from the CLI\r\n let cliOptions = {};\r\n\r\n // Only for the CLI usage\r\n if (cliArgs.length) {\r\n // Get options from the custom JSON loaded via the `loadConfig`\r\n configOptions = _loadConfigFile(cliArgs);\r\n\r\n // Get options from the CLI\r\n cliOptions = _pairArgumentValue(nestedProps, cliArgs);\r\n }\r\n\r\n // Get the reference to the global options object or a copy of the object\r\n const generalOptions = getOptions(modifyGlobal);\r\n\r\n // Update values of the general options with values from each source possible\r\n _updateOptions(\r\n defaultConfig,\r\n generalOptions,\r\n configOptions,\r\n customOptions,\r\n cliOptions\r\n );\r\n\r\n // Return options\r\n return generalOptions;\r\n}\r\n\r\n/**\r\n * Merges two sets of configuration options, considering absolute properties.\r\n *\r\n * @function mergeOptions\r\n *\r\n * @param {Object} originalOptions - Original configuration options.\r\n * @param {Object} newOptions - New configuration options to be merged.\r\n *\r\n * @returns {Object} Merged configuration options.\r\n */\r\nexport function mergeOptions(originalOptions, newOptions) {\r\n // Check if the `newOptions` is a correct object\r\n if (isObject(newOptions)) {\r\n for (const [key, value] of Object.entries(newOptions)) {\r\n originalOptions[key] =\r\n isObject(value) &&\r\n !absoluteProps.includes(key) &&\r\n originalOptions[key] !== undefined\r\n ? mergeOptions(originalOptions[key], value)\r\n : value !== undefined\r\n ? value\r\n : originalOptions[key];\r\n }\r\n }\r\n\r\n // Return the result options\r\n return originalOptions;\r\n}\r\n\r\n/**\r\n * Maps old-structured configuration options (PhantomJS) to a new format\r\n * (Puppeteer). This function converts flat, old-structured options into\r\n * a new, nested configuration format based on a predefined mapping\r\n * (`nestedProps`). The new format is used for Puppeteer, while the old format\r\n * was used for PhantomJS.\r\n *\r\n * @function mapToNewOptions\r\n *\r\n * @param {Object} oldOptions - The old, flat configuration options\r\n * to be converted.\r\n *\r\n * @returns {Object} A new object containing options structured according\r\n * to the mapping defined in `nestedProps` or an empty object if the provided\r\n * `oldOptions` is not a correct object.\r\n */\r\nexport function mapToNewOptions(oldOptions) {\r\n // An object for the new structured options\r\n const newOptions = {};\r\n\r\n // Check if provided value is a correct object\r\n if (Object.prototype.toString.call(oldOptions) === '[object Object]') {\r\n // Iterate over each key-value pair in the old-structured options\r\n for (const [key, value] of Object.entries(oldOptions)) {\r\n // If there is a nested mapping, split it into a properties chain\r\n const propertiesChain = nestedProps[key]\r\n ? nestedProps[key].split('.')\r\n : [];\r\n\r\n // If it is the last property in the chain, assign the value, otherwise,\r\n // create or reuse the nested object\r\n propertiesChain.reduce(\r\n (obj, prop, index) =>\r\n (obj[prop] =\r\n propertiesChain.length - 1 === index ? value : obj[prop] || {}),\r\n newOptions\r\n );\r\n }\r\n }\r\n\r\n // Return the new, structured options object\r\n return newOptions;\r\n}\r\n\r\n/**\r\n * Validates, parses, and checks if the provided config is allowed set\r\n * of options.\r\n *\r\n * @function isAllowedConfig\r\n *\r\n * @param {unknown} config - The config to be validated and parsed as a set\r\n * of options. Must be either an object or a string.\r\n * @param {boolean} [toString=false] - Whether to return a stringified version\r\n * of the parsed config. The default value is false.\r\n * @param {boolean} [allowFunctions=false] - Whether to allow functions\r\n * in the parsed config. If true, functions are preserved. Otherwise, when\r\n * a function is found, null is returned. The default value is false.\r\n *\r\n * @returns {(Object|string|null)} Returns a parsed set of options object,\r\n * a stringified set of options object if the `toString` is true, and null\r\n * if the config is not a valid set of options or parsing fails.\r\n */\r\nexport function isAllowedConfig(\r\n config,\r\n toString = false,\r\n allowFunctions = false\r\n) {\r\n try {\r\n // Accept only objects and strings\r\n if (!isObject(config) && typeof config !== 'string') {\r\n // Return null if any other type\r\n return null;\r\n }\r\n\r\n // Get the object representation of the original config\r\n const objectConfig =\r\n typeof config === 'string'\r\n ? allowFunctions\r\n ? eval(`(${config})`)\r\n : JSON.parse(config)\r\n : config;\r\n\r\n // Preserve or remove potential functions based on the `allowFunctions` flag\r\n const stringifiedOptions = _optionsStringify(\r\n objectConfig,\r\n allowFunctions,\r\n false\r\n );\r\n\r\n // Parse the config to check if it is valid set of options\r\n const parsedOptions = allowFunctions\r\n ? JSON.parse(\r\n _optionsStringify(objectConfig, allowFunctions, true),\r\n (_, value) =>\r\n typeof value === 'string' && value.startsWith('function')\r\n ? eval(`(${value})`)\r\n : value\r\n )\r\n : JSON.parse(stringifiedOptions);\r\n\r\n // Return stringified or object options based on the `toString` flag\r\n return toString ? stringifiedOptions : parsedOptions;\r\n } catch (error) {\r\n // Return null if parsing fails\r\n return null;\r\n }\r\n}\r\n\r\n/**\r\n * Prints the Highcharts Export Server logo, version, and license information.\r\n *\r\n * @function printLicense\r\n */\r\nexport function printLicense() {\r\n // Print the logo and version information\r\n printVersion();\r\n\r\n // Print the license information\r\n console.log(\r\n 'This software requires a valid Highcharts license for commercial use.\\n'\r\n .yellow,\r\n '\\nFor a full list of CLI options, type:',\r\n '\\nhighcharts-export-server --help\\n'.green,\r\n '\\nIf you do not have a license, one can be obtained here:',\r\n '\\nhttps://shop.highsoft.com/\\n'.green,\r\n '\\nTo customize your installation, please refer to the README file at:',\r\n '\\nhttps://github.com/highcharts/node-export-server#readme\\n'.green\r\n );\r\n}\r\n\r\n/**\r\n * Prints usage information for CLI arguments, displaying available options\r\n * and their descriptions. It can list properties recursively if categories\r\n * contain nested options.\r\n *\r\n * @function printUsage\r\n */\r\nexport function printUsage() {\r\n // Display README and general usage information\r\n console.log(\r\n '\\nUsage of CLI arguments:'.bold,\r\n '\\n-----------------------',\r\n `\\nFor more detailed information, visit the README file at: ${'https://github.com/highcharts/node-export-server#readme'.green}.\\n`\r\n );\r\n\r\n // Iterate through each category in the `defaultConfig` and display usage info\r\n Object.keys(defaultConfig).forEach((category) => {\r\n console.log(`${category.toUpperCase()}`.bold.red);\r\n _cycleCategories(defaultConfig[category]);\r\n console.log('');\r\n });\r\n}\r\n\r\n/**\r\n * Prints the Highcharts Export Server logo or text with the version\r\n * information.\r\n *\r\n * @function printVersion\r\n *\r\n * @param {boolean} [noLogo=false] - If true, only prints text with the version\r\n * information, without the logo. The default value is false.\r\n */\r\nexport function printVersion(noLogo = false) {\r\n // Get package version either from `.env` or from `package.json`\r\n const packageVersion = JSON.parse(\r\n readFileSync(join(__dirname, 'package.json'))\r\n ).version;\r\n\r\n // Print text only\r\n if (noLogo) {\r\n console.log(`Highcharts Export Server v${packageVersion}`);\r\n } else {\r\n // Print the logo\r\n console.log(\r\n readFileSync(join(__dirname, 'msg', 'startup.msg')).toString().bold\r\n .yellow,\r\n `v${packageVersion}\\n`.bold\r\n );\r\n }\r\n}\r\n\r\n/**\r\n * Initializes and returns global options object based on provided\r\n * configuration, setting values from nested properties recursively.\r\n *\r\n * @function _initGlobalOptions\r\n *\r\n * @param {Object} config - The configuration object to be used for initializing\r\n * options.\r\n *\r\n * @returns {Object} Initialized options object.\r\n */\r\nfunction _initGlobalOptions(config) {\r\n const options = {};\r\n\r\n // Start initializing the `options` object recursively\r\n for (const [name, item] of Object.entries(config)) {\r\n options[name] = Object.prototype.hasOwnProperty.call(item, 'value')\r\n ? item.value\r\n : _initGlobalOptions(item);\r\n }\r\n\r\n // Return the created `options` object\r\n return options;\r\n}\r\n\r\n/**\r\n * Updates options object with values from various sources, following a specific\r\n * prioritization order. The function checks for values in the following order\r\n * of precedence: the `loadConfig` configuration options, environment variables,\r\n * custom options, and CLI options.\r\n *\r\n * @function _updateOptions\r\n *\r\n * @param {Object} config - The configuration object, which includes the initial\r\n * settings and metadata for each option. This object is used to determine\r\n * the structure and default values for the options.\r\n * @param {Object} options - The options object that will be updated with values\r\n * from other sources.\r\n * @param {Object} configOpt - The configuration options object, loaded with\r\n * the `loadConfig` option, which may provide values to override defaults.\r\n * @param {Object} customOpt - The custom options object, typically containing\r\n * additional and user-defined values, which may override configuration options.\r\n * @param {Object} cliOpt - The CLI options object, which may include values\r\n * provided through command-line arguments and has the highest precedence among\r\n * options.\r\n */\r\nfunction _updateOptions(config, options, configOpt, customOpt, cliOpt) {\r\n Object.keys(config).forEach((key) => {\r\n // Get the config entry of a specific option\r\n const entry = config[key];\r\n\r\n // Gather values for the options from every possible source, if exists\r\n const configVal = configOpt && configOpt[key];\r\n const customVal = customOpt && customOpt[key];\r\n const cliVal = cliOpt && cliOpt[key];\r\n\r\n // If the value not found, need to go deeper\r\n if (typeof entry.value === 'undefined') {\r\n _updateOptions(entry, options[key], configVal, customVal, cliVal);\r\n } else {\r\n // If a value from custom JSON options exists, it take precedence\r\n if (configVal !== undefined && configVal !== null) {\r\n options[key] = configVal;\r\n }\r\n\r\n // If a value from environment variables exists, it take precedence\r\n const envVal = envs[entry.envLink];\r\n if (entry.envLink in envs && envVal !== undefined && envVal !== null) {\r\n options[key] = envVal;\r\n }\r\n\r\n // If a value from user options exists, it take precedence\r\n if (customVal !== undefined && customVal !== null) {\r\n options[key] = customVal;\r\n }\r\n\r\n // If a value from CLI options exists, it take precedence\r\n if (cliVal !== undefined && cliVal !== null) {\r\n options[key] = cliVal;\r\n }\r\n }\r\n });\r\n}\r\n\r\n/**\r\n * Converts the provided options object to a JSON-formatted string\r\n * with the option to preserve functions. In order for a function\r\n * to be preserved, it needs to follow the format `function (...) {...}`.\r\n * Such a function can also be stringified.\r\n *\r\n * @function _optionsStringify\r\n *\r\n * @param {Object} options - The options object to be converted to a string.\r\n * @param {boolean} allowFunctions - If set to true, functions are preserved\r\n * in the output. Otherwise an error is thrown.\r\n * @param {boolean} stringifyFunctions - If set to true, functions are saved\r\n * as strings. The `allowFunctions` must be set to true as well for this to take\r\n * an effect.\r\n *\r\n * @returns {string} The JSON-formatted string representing the options.\r\n *\r\n * @throws {Error} Throws an `Error` when functions are not allowed but are\r\n * found in provided options object.\r\n */\r\nexport function _optionsStringify(options, allowFunctions, stringifyFunctions) {\r\n const replacerCallback = (_, value) => {\r\n // Trim string values\r\n if (typeof value === 'string') {\r\n value = value.trim();\r\n }\r\n\r\n // If value is a function or stringified function\r\n if (\r\n typeof value === 'function' ||\r\n (typeof value === 'string' &&\r\n value.startsWith('function') &&\r\n value.endsWith('}'))\r\n ) {\r\n // If allowFunctions is set to true, preserve functions\r\n if (allowFunctions) {\r\n // Based on the `stringifyFunctions` options, set function values\r\n return stringifyFunctions\r\n ? // As stringified functions\r\n `\"EXP_FUN${(value + '').replaceAll(/\\s+/g, ' ')}EXP_FUN\"`\r\n : // As functions\r\n `EXP_FUN${(value + '').replaceAll(/\\s+/g, ' ')}EXP_FUN`;\r\n } else {\r\n // Throw an error otherwise\r\n throw new Error();\r\n }\r\n }\r\n\r\n // In all other cases, simply return the value\r\n return value;\r\n };\r\n\r\n // Stringify options and if required, replace special functions marks\r\n return JSON.stringify(options, replacerCallback).replaceAll(\r\n stringifyFunctions ? /\\\\\"EXP_FUN|EXP_FUN\\\\\"/g : /\"EXP_FUN|EXP_FUN\"/g,\r\n ''\r\n );\r\n}\r\n\r\n/**\r\n * Loads additional configuration from a specified file provided via\r\n * the `loadConfig` option in the command-line arguments.\r\n *\r\n * @function _loadConfigFile\r\n *\r\n * @param {Array.} cliArgs - Command-line arguments to search\r\n * for the `loadConfig` option and the corresponding file path.\r\n *\r\n * @returns {Object} The additional configuration loaded from the specified\r\n * file, or an empty object if the file is not found, invalid, or an error\r\n * occurs.\r\n */\r\nfunction _loadConfigFile(cliArgs) {\r\n // Check if the `loadConfig` option was used\r\n const configIndex = cliArgs.findIndex(\r\n (arg) => arg.replace(/-/g, '') === 'loadConfig'\r\n );\r\n\r\n // Get the `loadConfig` option value\r\n const configFileName = configIndex > -1 && cliArgs[configIndex + 1];\r\n\r\n // Check if the `loadConfig` is present and has a correct value\r\n if (configFileName) {\r\n try {\r\n // Load an optional custom JSON config file\r\n return JSON.parse(readFileSync(getAbsolutePath(configFileName)));\r\n } catch (error) {\r\n logWithStack(\r\n 2,\r\n error,\r\n `[config] Unable to load the configuration from the ${configFileName} file.`\r\n );\r\n }\r\n }\r\n\r\n // No additional options to return\r\n return {};\r\n}\r\n\r\n/**\r\n * Parses command-line arguments and pairs each argument with its corresponding\r\n * option in the configuration. The values are structured into a nested options\r\n * object, based on predefined mappings.\r\n *\r\n * @function _pairArgumentValue\r\n *\r\n * @param {Array.} nestedProps - An array of nesting level for all\r\n * options.\r\n * @param {Array.} cliArgs - An array of command-line arguments\r\n * containing options and their associated values.\r\n *\r\n * @returns {Object} An updated options object where each option from\r\n * the command-line is paired with its value, structured into nested objects\r\n * as defined.\r\n */\r\nfunction _pairArgumentValue(nestedProps, cliArgs) {\r\n // An empty object to collect and structurize data from the args\r\n const cliOptions = {};\r\n\r\n // Cycle through all CLI args and filter them\r\n for (let i = 0; i < cliArgs.length; i++) {\r\n const option = cliArgs[i].replace(/-/g, '');\r\n\r\n // Find the right place for property's value\r\n const propertiesChain = nestedProps[option]\r\n ? nestedProps[option].split('.')\r\n : [];\r\n\r\n // Create options object with values from CLI for later parsing and merging\r\n propertiesChain.reduce((obj, prop, index) => {\r\n if (propertiesChain.length - 1 === index) {\r\n const value = cliArgs[++i];\r\n if (!value) {\r\n log(\r\n 2,\r\n `[config] Missing value for the CLI '--${option}' argument. Using the default value.`\r\n );\r\n }\r\n obj[prop] = value || null;\r\n } else if (obj[prop] === undefined) {\r\n obj[prop] = {};\r\n }\r\n return obj[prop];\r\n }, cliOptions);\r\n }\r\n\r\n // Return parsed CLI options\r\n return cliOptions;\r\n}\r\n\r\n/**\r\n * Recursively traverses the options object to print the usage information\r\n * for each option category and individual option.\r\n *\r\n * @function _cycleCategories\r\n *\r\n * @param {Object} options - The options object containing CLI options.\r\n * It may include nested categories and individual options.\r\n */\r\nfunction _cycleCategories(options) {\r\n for (const [name, option] of Object.entries(options)) {\r\n // If the current entry is a category and not a leaf option, recurse into it\r\n if (!Object.prototype.hasOwnProperty.call(option, 'value')) {\r\n _cycleCategories(option);\r\n } else {\r\n // Prepare description\r\n const descName = ` --${option.cliName || name}`;\r\n\r\n // Get the value\r\n let optionValue = option.value;\r\n\r\n // Prepare value for option that is not null and is array of strings\r\n if (optionValue !== null && option.types.includes('string[]')) {\r\n optionValue =\r\n '[' + optionValue.map((item) => `'${item}'`).join(', ') + ']';\r\n }\r\n\r\n // Prepare value for option that is not null and is a string\r\n if (optionValue !== null && option.types.includes('string')) {\r\n optionValue = `'${optionValue}'`;\r\n }\r\n\r\n // Display correctly aligned messages\r\n console.log(\r\n descName.green,\r\n `${('<' + option.types.join('|') + '>').yellow}`,\r\n `${String(optionValue).bold}`.blue,\r\n `- ${option.description}.`\r\n );\r\n }\r\n }\r\n}\r\n\r\nexport default {\r\n getOptions,\r\n setOptions,\r\n mergeOptions,\r\n mapToNewOptions,\r\n isAllowedConfig,\r\n printLicense,\r\n printUsage,\r\n printVersion\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * @overview HTTP utility module for fetching and posting data. Supports both\r\n * HTTP and HTTPS protocols, providing methods to make GET and POST requests\r\n * with customizable options. Includes protocol determination based on URL\r\n * and augments response objects with a 'text' property for easier data access.\r\n */\r\n\r\nimport http from 'http';\r\nimport https from 'https';\r\n\r\n/**\r\n * Fetches data from the specified URL using either HTTP or HTTPS protocol.\r\n *\r\n * @async\r\n * @function fetch\r\n *\r\n * @param {string} url - The URL to fetch data from.\r\n * @param {Object} [requestOptions={}] - Options for the HTTP/HTTPS request.\r\n * The default value is an empty object.\r\n *\r\n * @returns {Promise} A Promise that resolves to the HTTP/HTTPS response\r\n * object with added 'text' property or rejecting with an error.\r\n */\r\nexport async function fetch(url, requestOptions = {}) {\r\n return new Promise((resolve, reject) => {\r\n _getProtocolModule(url)\r\n .get(url, requestOptions, (response) => {\r\n let responseData = '';\r\n\r\n // A chunk of data has been received\r\n response.on('data', (chunk) => {\r\n responseData += chunk;\r\n });\r\n\r\n // The whole response has been received\r\n response.on('end', () => {\r\n if (!responseData) {\r\n reject('Nothing was fetched from the URL.');\r\n }\r\n response.text = responseData;\r\n resolve(response);\r\n });\r\n })\r\n .on('error', (error) => {\r\n reject(error);\r\n });\r\n });\r\n}\r\n\r\n/**\r\n * Sends a POST request to the specified URL with the provided JSON body using\r\n * either HTTP or HTTPS protocol.\r\n *\r\n * @async\r\n * @function post\r\n *\r\n * @param {string} url - The URL to send the POST request to.\r\n * @param {Object} [body={}] - The JSON body to include in the POST request.\r\n * The default value is an empty object.\r\n * @param {Object} [requestOptions={}] - Options for the HTTP/HTTPS request.\r\n * The default value is an empty object.\r\n *\r\n * @returns {Promise} A Promise that resolves to the HTTP/HTTPS response\r\n * object with added 'text' property or rejecting with an error.\r\n */\r\nexport async function post(url, body = {}, requestOptions = {}) {\r\n return new Promise((resolve, reject) => {\r\n const data = JSON.stringify(body);\r\n\r\n // Set default headers and merge with requestOptions\r\n const options = Object.assign(\r\n {\r\n method: 'POST',\r\n headers: {\r\n 'Content-Type': 'application/json',\r\n 'Content-Length': data.length\r\n }\r\n },\r\n requestOptions\r\n );\r\n\r\n const request = _getProtocolModule(url)\r\n .request(url, options, (response) => {\r\n let responseData = '';\r\n\r\n // A chunk of data has been received\r\n response.on('data', (chunk) => {\r\n responseData += chunk;\r\n });\r\n\r\n // The whole response has been received\r\n response.on('end', () => {\r\n try {\r\n response.text = responseData;\r\n resolve(response);\r\n } catch (error) {\r\n reject(error);\r\n }\r\n });\r\n })\r\n .on('error', (error) => {\r\n reject(error);\r\n });\r\n\r\n // Write the request body and end the request\r\n request.write(data);\r\n request.end();\r\n });\r\n}\r\n\r\n/**\r\n * Returns the HTTP or HTTPS protocol module based on the provided URL.\r\n *\r\n * @function _getProtocolModule\r\n *\r\n * @param {string} url - The URL to determine the protocol.\r\n *\r\n * @returns {Object} The HTTP or HTTPS protocol module (http or https).\r\n */\r\nfunction _getProtocolModule(url) {\r\n return url.startsWith('https') ? https : http;\r\n}\r\n\r\nexport default {\r\n fetch,\r\n post\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * A custom error class for handling export-related errors. Extends the native\r\n * `Error` class to include additional properties like status code and stack\r\n * trace details.\r\n */\r\nclass ExportError extends Error {\r\n /**\r\n * Creates an instance of the `ExportError`.\r\n *\r\n * @param {string} message - The error message to be displayed.\r\n * @param {number} statusCode - Optional HTTP status code associated\r\n * with the error (e.g., 400, 500).\r\n */\r\n constructor(message, statusCode) {\r\n super();\r\n\r\n this.message = message;\r\n this.stackMessage = message;\r\n\r\n if (statusCode) {\r\n this.statusCode = statusCode;\r\n }\r\n }\r\n\r\n /**\r\n * Sets additional error details based on an existing error object.\r\n *\r\n * @param {Error} error - An error object containing details to populate\r\n * the `ExportError` instance.\r\n *\r\n * @returns {ExportError} The updated instance of the `ExportError` class.\r\n */\r\n setError(error) {\r\n this.error = error;\r\n\r\n if (error.name) {\r\n this.name = error.name;\r\n }\r\n\r\n if (error.statusCode) {\r\n this.statusCode = error.statusCode;\r\n }\r\n\r\n if (error.stack) {\r\n this.stackMessage = error.message;\r\n this.stack = error.stack;\r\n }\r\n\r\n return this;\r\n }\r\n}\r\n\r\nexport default ExportError;\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * @overview The cache manager is responsible for handling and managing\r\n * the Highcharts library along with its dependencies. It ensures that these\r\n * resources are stored and retrieved efficiently to optimize performance\r\n * and reduce redundant network requests. The cache is stored in the `.cache`\r\n * directory by default, which serves as a dedicated folder for keeping cached\r\n * files.\r\n */\r\n\r\nimport { existsSync, mkdirSync, readFileSync, writeFileSync } from 'fs';\r\nimport { join } from 'path';\r\n\r\nimport { HttpsProxyAgent } from 'https-proxy-agent';\r\n\r\nimport { getOptions } from './config.js';\r\nimport { fetch } from './fetch.js';\r\nimport { log } from './logger.js';\r\nimport { __dirname, getAbsolutePath } from './utils.js';\r\n\r\nimport ExportError from './errors/ExportError.js';\r\n\r\n// The initial cache template\r\nconst cache = {\r\n cdnUrl: 'https://code.highcharts.com',\r\n activeManifest: {},\r\n sources: '',\r\n hcVersion: ''\r\n};\r\n\r\n/**\r\n * Checks the cache for Highcharts dependencies, updates the cache if needed,\r\n * and loads the sources.\r\n *\r\n * @async\r\n * @function checkAndUpdateCache\r\n *\r\n * @param {Object} highchartsOptions - Object containing `highcharts` options.\r\n * @param {Object} serverProxyOptions - Object containing `server.proxy`\r\n * options.\r\n */\r\nexport async function checkAndUpdateCache(\r\n highchartsOptions,\r\n serverProxyOptions\r\n) {\r\n let fetchedModules;\r\n\r\n // Get the cache path\r\n const cachePath = getCachePath();\r\n\r\n // Prepare paths to manifest and sources from the cache folder\r\n const manifestPath = join(cachePath, 'manifest.json');\r\n const sourcePath = join(cachePath, 'sources.js');\r\n\r\n // Create the cache destination if it doesn't exist already\r\n !existsSync(cachePath) && mkdirSync(cachePath, { recursive: true });\r\n\r\n // Fetch all the scripts either if the `manifest.json` does not exist\r\n // or if the `forceFetch` option is enabled\r\n if (!existsSync(manifestPath) || highchartsOptions.forceFetch) {\r\n log(3, '[cache] Fetching and caching Highcharts dependencies.');\r\n fetchedModules = await _updateCache(\r\n highchartsOptions,\r\n serverProxyOptions,\r\n sourcePath\r\n );\r\n } else {\r\n let requestUpdate = false;\r\n\r\n // Read the manifest JSON\r\n const manifest = JSON.parse(readFileSync(manifestPath));\r\n\r\n // Check if the modules is an array, if so, we rewrite it to a map to make\r\n // it easier to resolve modules.\r\n if (manifest.modules && Array.isArray(manifest.modules)) {\r\n const moduleMap = {};\r\n manifest.modules.forEach((m) => (moduleMap[m] = 1));\r\n manifest.modules = moduleMap;\r\n }\r\n\r\n // Get the actual number of scripts to be fetched\r\n const { coreScripts, moduleScripts, indicatorScripts } = highchartsOptions;\r\n const numberOfModules =\r\n coreScripts.length + moduleScripts.length + indicatorScripts.length;\r\n\r\n // Compare the loaded highcharts config with the contents in cache.\r\n // If there are changes, fetch requested modules and products,\r\n // and bake them into a giant blob. Save the blob.\r\n if (manifest.version !== highchartsOptions.version) {\r\n log(\r\n 2,\r\n '[cache] A Highcharts version mismatch in the cache, need to re-fetch.'\r\n );\r\n requestUpdate = true;\r\n } else if (Object.keys(manifest.modules || {}).length !== numberOfModules) {\r\n log(\r\n 2,\r\n '[cache] The cache and the requested modules do not match, need to re-fetch.'\r\n );\r\n requestUpdate = true;\r\n } else {\r\n // Check each module, if anything is missing refetch everything\r\n requestUpdate = (moduleScripts || []).some((moduleName) => {\r\n if (!manifest.modules[moduleName]) {\r\n log(\r\n 2,\r\n `[cache] The ${moduleName} is missing in the cache, need to re-fetch.`\r\n );\r\n return true;\r\n }\r\n });\r\n }\r\n\r\n // Update cache if needed\r\n if (requestUpdate) {\r\n fetchedModules = await _updateCache(\r\n highchartsOptions,\r\n serverProxyOptions,\r\n sourcePath\r\n );\r\n } else {\r\n log(3, '[cache] Dependency cache is up to date, proceeding.');\r\n\r\n // Load the sources\r\n cache.sources = readFileSync(sourcePath, 'utf8');\r\n\r\n // Get current modules map\r\n fetchedModules = manifest.modules;\r\n\r\n // Extract and save version of currently used Highcharts\r\n cache.hcVersion = extractVersion(cache.sources);\r\n }\r\n }\r\n\r\n // Finally, save the new manifest, which is basically our current config\r\n // in a slightly different format\r\n await _saveConfigToManifest(highchartsOptions, fetchedModules);\r\n}\r\n\r\n/**\r\n * Gets the version of Highcharts from the cache.\r\n *\r\n * @function getHighchartsVersion\r\n *\r\n * @returns {string} The cached Highcharts version.\r\n */\r\nexport function getHighchartsVersion() {\r\n return cache.hcVersion;\r\n}\r\n\r\n/**\r\n * Updates the Highcharts version in the applied configuration and checks\r\n * the cache for the new version.\r\n *\r\n * @async\r\n * @function updateHighchartsVersion\r\n *\r\n * @param {string} newVersion - The new Highcharts version to be applied.\r\n */\r\nexport async function updateHighchartsVersion(newVersion) {\r\n // Get the reference to the global options to update to the new version\r\n const options = getOptions();\r\n\r\n // Set to the new version\r\n options.highcharts.version = newVersion;\r\n\r\n // Check if cache needs to be updated\r\n await checkAndUpdateCache(options.highcharts, options.server.proxy);\r\n}\r\n\r\n/**\r\n * Extracts Highcharts version from the cache's sources string.\r\n *\r\n * @function extractVersion\r\n *\r\n * @param {Object} cacheSources - The cache sources object.\r\n *\r\n * @returns {string} The extracted Highcharts version.\r\n */\r\nexport function extractVersion(cacheSources) {\r\n return cacheSources\r\n .substring(0, cacheSources.indexOf('*/'))\r\n .replace('/*', '')\r\n .replace('*/', '')\r\n .replace(/\\n/g, '')\r\n .trim();\r\n}\r\n\r\n/**\r\n * Extracts the Highcharts module name based on the scriptPath.\r\n *\r\n * @function extractModuleName\r\n *\r\n * @param {string} scriptPath - The path of the script from which the module\r\n * name will be extracted.\r\n *\r\n * @returns {string} The extracted module name.\r\n */\r\nexport function extractModuleName(scriptPath) {\r\n return scriptPath.replace(\r\n /(.*)\\/|(.*)modules\\/|stock\\/(.*)indicators\\/|maps\\/(.*)modules\\//gi,\r\n ''\r\n );\r\n}\r\n\r\n/**\r\n * Retrieves the current cache object.\r\n *\r\n * @function getCache\r\n *\r\n * @returns {Object} The cache object containing various cached data.\r\n */\r\nexport function getCache() {\r\n return cache;\r\n}\r\n\r\n/**\r\n * Gets the cache path for Highcharts.\r\n *\r\n * @function getCachePath\r\n *\r\n * @returns {string} The absolute path to the cache directory for Highcharts.\r\n */\r\nexport function getCachePath() {\r\n return getAbsolutePath(getOptions().highcharts.cachePath); // #562\r\n}\r\n\r\n/**\r\n * Fetches a single script and updates the `fetchedModules` accordingly.\r\n *\r\n * @async\r\n * @function _fetchAndProcessScript\r\n *\r\n * @param {string} script - A path to script to get.\r\n * @param {Object} requestOptions - Additional options for the proxy agent\r\n * to use for a request.\r\n * @param {Object} fetchedModules - An object which tracks which Highcharts\r\n * modules have been fetched.\r\n * @param {boolean} [shouldThrowError=false] - A flag to indicate if the error\r\n * should be thrown. This should be used only for the core scripts. The default\r\n * value is false.\r\n *\r\n * @returns {Promise} A Promise that resolves to the text representation\r\n * of the fetched script.\r\n *\r\n * @throws {ExportError} Throws an `ExportError` if there is a problem\r\n * with fetching the script.\r\n */\r\nasync function _fetchAndProcessScript(\r\n script,\r\n requestOptions,\r\n fetchedModules,\r\n shouldThrowError = false\r\n) {\r\n // Get rid of the .js from the custom strings\r\n if (script.endsWith('.js')) {\r\n script = script.substring(0, script.length - 3);\r\n }\r\n log(4, `[cache] Fetching script - ${script}.js`);\r\n\r\n // Fetch the script\r\n const response = await fetch(`${script}.js`, requestOptions);\r\n\r\n // If OK, return its text representation\r\n if (response.statusCode === 200 && typeof response.text == 'string') {\r\n if (fetchedModules) {\r\n const moduleName = extractModuleName(script);\r\n fetchedModules[moduleName] = 1;\r\n }\r\n return response.text;\r\n }\r\n\r\n // Based on the `shouldThrowError` flag, decide how to serve error message\r\n if (shouldThrowError) {\r\n throw new ExportError(\r\n `[cache] Could not fetch the ${script}.js. The script might not exist in the requested version (status code: ${response.statusCode}).`,\r\n 404\r\n ).setError(response);\r\n } else {\r\n log(\r\n 2,\r\n `[cache] Could not fetch the ${script}.js. The script might not exist in the requested version.`\r\n );\r\n }\r\n}\r\n\r\n/**\r\n * Saves the provided configuration and fetched modules to the cache manifest\r\n * file.\r\n *\r\n * @async\r\n * @function _saveConfigToManifest\r\n *\r\n * @param {Object} highchartsOptions - Object containing `highcharts` options.\r\n * @param {Object} [fetchedModules={}] - An object which tracks which Highcharts\r\n * modules have been fetched. The default value is an empty object.\r\n *\r\n * @throws {ExportError} Throws an `ExportError` if an error occurs while\r\n * writing the cache manifest.\r\n */\r\nasync function _saveConfigToManifest(highchartsOptions, fetchedModules = {}) {\r\n const newManifest = {\r\n version: highchartsOptions.version,\r\n modules: fetchedModules\r\n };\r\n\r\n // Update cache object with the current modules\r\n cache.activeManifest = newManifest;\r\n\r\n log(3, '[cache] Writing a new manifest.');\r\n try {\r\n writeFileSync(\r\n join(getCachePath(), 'manifest.json'),\r\n JSON.stringify(newManifest),\r\n 'utf8'\r\n );\r\n } catch (error) {\r\n throw new ExportError(\r\n '[cache] Error writing the cache manifest.',\r\n 500\r\n ).setError(error);\r\n }\r\n}\r\n\r\n/**\r\n * Fetches Highcharts `scripts` and `customScripts` from the given CDNs.\r\n *\r\n * @async\r\n * @function _fetchScripts\r\n *\r\n * @param {Array.} coreScripts - Highcharts core scripts to fetch.\r\n * @param {Array.} moduleScripts - Highcharts modules to fetch.\r\n * @param {Array.} customScripts - Custom script paths to fetch (full\r\n * URLs).\r\n * @param {Object} serverProxyOptions - Object containing `server.proxy`\r\n * options.\r\n * @param {Object} fetchedModules - An object which tracks which Highcharts\r\n * modules have been fetched.\r\n *\r\n * @returns {Promise} A Promise that resolves to the fetched scripts\r\n * content joined.\r\n *\r\n * @throws {ExportError} Throws an `ExportError` if an error occurs while\r\n * setting an HTTP Agent for proxy.\r\n */\r\nasync function _fetchScripts(\r\n coreScripts,\r\n moduleScripts,\r\n customScripts,\r\n serverProxyOptions,\r\n fetchedModules\r\n) {\r\n // Configure proxy if exists\r\n let proxyAgent;\r\n const proxyHost = serverProxyOptions.host;\r\n const proxyPort = serverProxyOptions.port;\r\n\r\n // Try to create a Proxy Agent\r\n if (proxyHost && proxyPort) {\r\n try {\r\n proxyAgent = new HttpsProxyAgent({\r\n host: proxyHost,\r\n port: proxyPort\r\n });\r\n } catch (error) {\r\n throw new ExportError(\r\n '[cache] Could not create a Proxy Agent.',\r\n 500\r\n ).setError(error);\r\n }\r\n }\r\n\r\n // If exists, add proxy agent to request options\r\n const requestOptions = proxyAgent\r\n ? {\r\n agent: proxyAgent,\r\n timeout: serverProxyOptions.timeout\r\n }\r\n : {};\r\n\r\n const allFetchPromises = [\r\n ...coreScripts.map((script) =>\r\n _fetchAndProcessScript(`${script}`, requestOptions, fetchedModules, true)\r\n ),\r\n ...moduleScripts.map((script) =>\r\n _fetchAndProcessScript(`${script}`, requestOptions, fetchedModules)\r\n ),\r\n ...customScripts.map((script) =>\r\n _fetchAndProcessScript(`${script}`, requestOptions)\r\n )\r\n ];\r\n\r\n const fetchedScripts = await Promise.all(allFetchPromises);\r\n return fetchedScripts.join(';\\n');\r\n}\r\n\r\n/**\r\n * Updates the local cache with Highcharts scripts and their versions.\r\n *\r\n * @async\r\n * @function _updateCache\r\n *\r\n * @param {Object} highchartsOptions - Object containing `highcharts` options.\r\n * @param {Object} serverProxyOptions - Object containing `server.proxy`\r\n * options.\r\n * @param {string} sourcePath - The path to the source file in the cache.\r\n *\r\n * @returns {Promise} A Promise that resolves to an object representing\r\n * the fetched modules.\r\n *\r\n * @throws {ExportError} Throws an `ExportError` if there is an issue updating\r\n * the local Highcharts cache.\r\n */\r\nasync function _updateCache(highchartsOptions, serverProxyOptions, sourcePath) {\r\n // Get Highcharts version for scripts\r\n const hcVersion =\r\n highchartsOptions.version === 'latest'\r\n ? null\r\n : `${highchartsOptions.version}`;\r\n\r\n // Get the CDN url for scripts\r\n const cdnUrl = highchartsOptions.cdnUrl || cache.cdnUrl;\r\n\r\n try {\r\n const fetchedModules = {};\r\n\r\n log(\r\n 3,\r\n `[cache] Updating cache version to Highcharts: ${hcVersion || 'latest'}.`\r\n );\r\n\r\n cache.sources = await _fetchScripts(\r\n [\r\n ...highchartsOptions.coreScripts.map((c) =>\r\n hcVersion ? `${cdnUrl}/${hcVersion}/${c}` : `${cdnUrl}/${c}`\r\n )\r\n ],\r\n [\r\n ...highchartsOptions.moduleScripts.map((m) =>\r\n m === 'map'\r\n ? hcVersion\r\n ? `${cdnUrl}/maps/${hcVersion}/modules/${m}`\r\n : `${cdnUrl}/maps/modules/${m}`\r\n : hcVersion\r\n ? `${cdnUrl}/${hcVersion}/modules/${m}`\r\n : `${cdnUrl}/modules/${m}`\r\n ),\r\n ...highchartsOptions.indicatorScripts.map((i) =>\r\n hcVersion\r\n ? `${cdnUrl}/stock/${hcVersion}/indicators/${i}`\r\n : `${cdnUrl}/stock/indicators/${i}`\r\n )\r\n ],\r\n highchartsOptions.customScripts,\r\n serverProxyOptions,\r\n fetchedModules\r\n );\r\n\r\n // Extract and save version of currently used Highcharts\r\n cache.hcVersion = extractVersion(cache.sources);\r\n\r\n // Save the fetched modules into caches' source JSON\r\n writeFileSync(sourcePath, cache.sources);\r\n return fetchedModules;\r\n } catch (error) {\r\n throw new ExportError(\r\n '[cache] Unable to update the local Highcharts cache.',\r\n 500\r\n ).setError(error);\r\n }\r\n}\r\n\r\nexport default {\r\n checkAndUpdateCache,\r\n getHighchartsVersion,\r\n updateHighchartsVersion,\r\n extractVersion,\r\n extractModuleName,\r\n getCache,\r\n getCachePath\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * @overview Provides methods for initializing Highcharts with customized\r\n * animation settings and triggering the creation of Highcharts charts with\r\n * export-specific configurations in the page context. Supports dynamic option\r\n * merging, custom logic injection, and control over rendering behaviors. Used\r\n * by the Puppeteer page.\r\n */\r\n\r\n/* eslint-disable no-undef */\r\n\r\n/**\r\n * Setting the `Highcharts.animObject` function. Called when initing the page.\r\n *\r\n * @function setupHighcharts\r\n */\r\nexport function setupHighcharts() {\r\n Highcharts.animObject = function () {\r\n return { duration: 0 };\r\n };\r\n}\r\n\r\n/**\r\n * Creates the actual Highcharts chart on a page.\r\n *\r\n * @async\r\n * @function createChart\r\n *\r\n * @param {Object} options - The `options` object containing complete set\r\n * of options.\r\n */\r\nexport async function createChart(options) {\r\n // Get required functions\r\n const { getOptions, merge, setOptions, wrap } = Highcharts;\r\n\r\n // Create a separate object for a potential `setOptions` usages in order\r\n // to prevent from polluting other exports that can happen on the same page\r\n Highcharts.setOptionsObj = merge(false, {}, getOptions());\r\n\r\n // NOTE: Is this used for anything useful?\r\n window.isRenderComplete = false;\r\n wrap(Highcharts.Chart.prototype, 'init', function (proceed, userOptions, cb) {\r\n // Override userOptions with image friendly options\r\n userOptions = merge(userOptions, {\r\n exporting: {\r\n enabled: false\r\n },\r\n plotOptions: {\r\n series: {\r\n label: {\r\n enabled: false\r\n }\r\n }\r\n },\r\n /* Expects tooltip in userOptions when forExport is true.\r\n https://github.com/highcharts/highcharts/blob/3ad430a353b8056b9e764aa4e5cd6828aa479db2/js/parts/Chart.js#L241\r\n */\r\n tooltip: {}\r\n });\r\n\r\n (userOptions.series || []).forEach(function (series) {\r\n series.animation = false;\r\n });\r\n\r\n // Add flag to know if chart render has been called.\r\n if (!window.onHighchartsRender) {\r\n window.onHighchartsRender = Highcharts.addEvent(this, 'render', () => {\r\n window.isRenderComplete = true;\r\n });\r\n }\r\n\r\n proceed.apply(this, [userOptions, cb]);\r\n });\r\n\r\n wrap(Highcharts.Series.prototype, 'init', function (proceed, chart, options) {\r\n proceed.apply(this, [chart, options]);\r\n });\r\n\r\n // Some mandatory additional `chart` and `exporting` options\r\n const additionalOptions = {\r\n chart: {\r\n // By default animation is disabled\r\n animation: false,\r\n // Get the right size values\r\n height: options.export.height,\r\n width: options.export.width\r\n },\r\n exporting: {\r\n // No need for the exporting button\r\n enabled: false\r\n }\r\n };\r\n\r\n // Get the input to export from the `instr` option\r\n const userOptions = new Function(`return ${options.export.instr}`)();\r\n\r\n // Get the `themeOptions` option\r\n const themeOptions = new Function(`return ${options.export.themeOptions}`)();\r\n\r\n // Get the `globalOptions` option\r\n const globalOptions = new Function(\r\n `return ${options.export.globalOptions}`\r\n )();\r\n\r\n // Merge the following options objects to create final options\r\n const finalOptions = merge(\r\n false,\r\n themeOptions,\r\n userOptions,\r\n // Placed it here instead in the init because of the size issues\r\n additionalOptions\r\n );\r\n\r\n // Prepare the `callback` option\r\n const finalCallback = options.customLogic.callback\r\n ? new Function(`return ${options.customLogic.callback}`)()\r\n : null;\r\n\r\n // Trigger the `customCode` option\r\n if (options.customLogic.customCode) {\r\n new Function('options', options.customLogic.customCode)(userOptions);\r\n }\r\n\r\n // Set the global options if exist\r\n if (globalOptions) {\r\n setOptions(globalOptions);\r\n }\r\n\r\n // Call the chart creation\r\n Highcharts[options.export.constr]('container', finalOptions, finalCallback);\r\n\r\n // Get the current global options\r\n const defaultOptions = getOptions();\r\n\r\n // Clear it just in case (e.g. the `setOptions` was used in the `customCode`)\r\n for (const prop in defaultOptions) {\r\n if (typeof defaultOptions[prop] !== 'function') {\r\n delete defaultOptions[prop];\r\n }\r\n }\r\n\r\n // Set the default options back\r\n setOptions(Highcharts.setOptionsObj);\r\n\r\n // Empty the custom global options object\r\n Highcharts.setOptionsObj = {};\r\n}\r\n\r\nexport default {\r\n setupHighcharts,\r\n createChart\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * @overview This module provides functions for managing Puppeteer browser\r\n * instance, creating and clearing pages, injecting custom resources,\r\n * and setting up Highcharts for server-side rendering. The module ensures\r\n * that resources are correctly managed and can handle failures during\r\n * operations like launching the browser or creating new pages.\r\n */\r\n\r\nimport { readFileSync } from 'fs';\r\nimport { join } from 'path';\r\n\r\nimport puppeteer from 'puppeteer';\r\n\r\nimport { getCachePath } from './cache.js';\r\nimport { getOptions } from './config.js';\r\nimport { setupHighcharts } from './highcharts.js';\r\nimport { log, logWithStack } from './logger.js';\r\nimport { __dirname, getAbsolutePath } from './utils.js';\r\n\r\nimport ExportError from './errors/ExportError.js';\r\n\r\n// Get the template for pages\r\nconst template = readFileSync(\r\n join(__dirname, 'templates', 'template.html'),\r\n 'utf8'\r\n);\r\n\r\n// To save the browser\r\nlet browser = null;\r\n\r\n/**\r\n * Retrieves the existing Puppeteer browser instance.\r\n *\r\n * @function getBrowser\r\n *\r\n * @returns {Object} The Puppeteer browser instance.\r\n *\r\n * @throws {ExportError} Throws an `ExportError` if no valid browser\r\n * has been created.\r\n */\r\nexport function getBrowser() {\r\n if (!browser) {\r\n throw new ExportError('[browser] No valid browser has been created.', 500);\r\n }\r\n return browser;\r\n}\r\n\r\n/**\r\n * Creates a Puppeteer browser instance with the specified arguments.\r\n *\r\n * @async\r\n * @function createBrowser\r\n *\r\n * @param {Array.} puppeteerArgs - Additional arguments for Puppeteer\r\n * launch.\r\n *\r\n * @returns {Promise} A Promise that resolves to the created Puppeteer\r\n * browser instance.\r\n *\r\n * @throws {ExportError} Throws an `ExportError` if max retries to open\r\n * a browser instance are reached, or if no browser instance is found after\r\n * retries.\r\n */\r\nexport async function createBrowser(puppeteerArgs) {\r\n // Get `debug` and `other` options\r\n const { debug, other } = getOptions();\r\n\r\n // Get the `debug` options\r\n const { enable: enabledDebug, ...debugOptions } = debug;\r\n\r\n // Launch options for the browser instance\r\n const launchOptions = {\r\n headless: other.browserShellMode ? 'shell' : true,\r\n userDataDir: 'tmp',\r\n args: puppeteerArgs || [],\r\n handleSIGINT: false,\r\n handleSIGTERM: false,\r\n handleSIGHUP: false,\r\n waitForInitialPage: false,\r\n defaultViewport: null,\r\n ...(enabledDebug && debugOptions)\r\n };\r\n\r\n // Create a browser\r\n if (!browser) {\r\n // A counter for the browser's launch retries\r\n let tryCount = 0;\r\n\r\n const open = async () => {\r\n try {\r\n log(\r\n 3,\r\n `[browser] Attempting to get a browser instance (try ${++tryCount}).`\r\n );\r\n\r\n // Launch the browser\r\n browser = await puppeteer.launch(launchOptions);\r\n } catch (error) {\r\n logWithStack(\r\n 1,\r\n error,\r\n '[browser] Failed to launch a browser instance.'\r\n );\r\n\r\n // Retry to launch browser until reaching max attempts\r\n if (tryCount < 25) {\r\n log(3, `[browser] Retry to open a browser (${tryCount} out of 25).`);\r\n\r\n // Wait for a 4 seconds before trying again\r\n await new Promise((response) => setTimeout(response, 4000));\r\n await open();\r\n } else {\r\n throw error;\r\n }\r\n }\r\n };\r\n\r\n try {\r\n await open();\r\n\r\n // Shell mode inform\r\n if (launchOptions.headless === 'shell') {\r\n log(3, `[browser] Launched browser in shell mode.`);\r\n }\r\n\r\n // Debug mode inform\r\n if (enabledDebug) {\r\n log(3, `[browser] Launched browser in debug mode.`);\r\n }\r\n } catch (error) {\r\n throw new ExportError(\r\n '[browser] Maximum retries to open a browser instance reached.',\r\n 500\r\n ).setError(error);\r\n }\r\n\r\n if (!browser) {\r\n throw new ExportError('[browser] Cannot find a browser to open.', 500);\r\n }\r\n }\r\n\r\n // Return a browser instance\r\n return browser;\r\n}\r\n\r\n/**\r\n * Closes the Puppeteer browser instance if it is connected.\r\n *\r\n * @async\r\n * @function closeBrowser\r\n */\r\nexport async function closeBrowser() {\r\n // Close the browser when connected\r\n if (browser && browser.connected) {\r\n await browser.close();\r\n }\r\n browser = null;\r\n log(4, '[browser] Closed the browser.');\r\n}\r\n\r\n/**\r\n * Creates a new Puppeteer page within an existing browser instance.\r\n * The function creates a new page, disables caching, sets content using\r\n * the `_setPageContent()`, and returns the created Puppeteer page.\r\n *\r\n * @async\r\n * @function newPage\r\n *\r\n * @param {Object} poolResource - The pool resource that contains `id`,\r\n * `workCount`, and `page`.\r\n *\r\n * @throws {ExportError} Throws an `ExportError` if no valid browser\r\n * has been connected or if a page is invalid or closed.\r\n */\r\nexport async function newPage(poolResource) {\r\n // Error in case of no connected browser\r\n if (!browser || !browser.connected) {\r\n throw new ExportError(`[browser] Browser is not yet connected.`, 500);\r\n }\r\n\r\n // Create a page\r\n poolResource.page = await browser.newPage();\r\n\r\n // Disable cache\r\n await poolResource.page.setCacheEnabled(false);\r\n\r\n // Set the content\r\n await _setPageContent(poolResource.page);\r\n\r\n // Set page events\r\n _setPageEvents(poolResource.page);\r\n\r\n // Check if the page is correctly created\r\n if (!poolResource.page || poolResource.page.isClosed()) {\r\n throw new ExportError('[browser] The page is invalid or closed.', 400);\r\n }\r\n}\r\n\r\n/**\r\n * Clears the content of a Puppeteer Page based on the specified mode. Logs\r\n * thrown error if clearing of a page's content fails.\r\n *\r\n * @async\r\n * @function clearPage\r\n *\r\n * @param {Object} poolResource - The pool resource that contains page and id.\r\n * @param {boolean} [hardReset=false] - A flag indicating the type of clearing\r\n * to be performed. If true, navigates to `about:blank` and resets content\r\n * and scripts. If false, clears the body content by setting a predefined HTML\r\n * structure. The default value is false.\r\n *\r\n * @returns {Promise} A Promise that resolves to true when page\r\n * is correctly cleared and false when it is not.\r\n */\r\nexport async function clearPage(poolResource, hardReset = false) {\r\n try {\r\n if (poolResource.page && !poolResource.page.isClosed()) {\r\n if (hardReset) {\r\n // Navigate to `about:blank`\r\n await poolResource.page.goto('about:blank', {\r\n waitUntil: 'domcontentloaded'\r\n });\r\n\r\n // Set the content and and scripts again\r\n await _setPageContent(poolResource.page);\r\n } else {\r\n // Clear body content\r\n await poolResource.page.evaluate(() => {\r\n document.body.innerHTML =\r\n '
';\r\n });\r\n }\r\n return true;\r\n }\r\n } catch (error) {\r\n logWithStack(\r\n 2,\r\n error,\r\n `[pool] Pool resource [${poolResource.id}] - Content of the page could not be cleared.`\r\n );\r\n\r\n // Set the `workLimit` to exceeded in order to recreate the resource\r\n poolResource.workCount = getOptions().pool.workLimit + 1;\r\n }\r\n return false;\r\n}\r\n\r\n/**\r\n * Adds custom JS and CSS resources to a Puppeteer Page based on the specified\r\n * options.\r\n *\r\n * @async\r\n * @function addPageResources\r\n *\r\n * @param {Object} page - The Puppeteer page object to which resources will\r\n * be added.\r\n * @param {Object} customLogicOptions - The object containing `customLogic`\r\n * options.\r\n *\r\n * @returns {Promise>} A Promise that resolves to an array\r\n * of injected resources.\r\n */\r\nexport async function addPageResources(page, customLogicOptions) {\r\n // Injected resources array\r\n const injectedResources = [];\r\n\r\n // Use resources\r\n const resources = customLogicOptions.resources;\r\n if (resources) {\r\n const injectedJs = [];\r\n\r\n // Load custom JS code\r\n if (resources.js) {\r\n injectedJs.push({\r\n content: resources.js\r\n });\r\n }\r\n\r\n // Load scripts from all custom files\r\n if (resources.files) {\r\n for (const file of resources.files) {\r\n const isLocal = !file.startsWith('http') ? true : false;\r\n\r\n // Add each custom script from resources' files\r\n injectedJs.push(\r\n isLocal\r\n ? {\r\n content: readFileSync(getAbsolutePath(file), 'utf8')\r\n }\r\n : {\r\n url: file\r\n }\r\n );\r\n }\r\n }\r\n\r\n for (const jsResource of injectedJs) {\r\n try {\r\n injectedResources.push(await page.addScriptTag(jsResource));\r\n } catch (error) {\r\n logWithStack(2, error, `[browser] The JS resource cannot be loaded.`);\r\n }\r\n }\r\n injectedJs.length = 0;\r\n\r\n // Load CSS\r\n const injectedCss = [];\r\n if (resources.css) {\r\n let cssImports = resources.css.match(/@import\\s*([^;]*);/g);\r\n if (cssImports) {\r\n // Handle css section\r\n for (let cssImportPath of cssImports) {\r\n if (cssImportPath) {\r\n cssImportPath = cssImportPath\r\n .replace('url(', '')\r\n .replace('@import', '')\r\n .replace(/\"/g, '')\r\n .replace(/'/g, '')\r\n .replace(/;/, '')\r\n .replace(/\\)/g, '')\r\n .trim();\r\n\r\n // Add each custom css from resources\r\n if (cssImportPath.startsWith('http')) {\r\n injectedCss.push({\r\n url: cssImportPath\r\n });\r\n } else if (customLogicOptions.allowFileResources) {\r\n injectedCss.push({\r\n path: join(__dirname, cssImportPath)\r\n });\r\n }\r\n }\r\n }\r\n }\r\n\r\n // The rest of the CSS section will be content by now\r\n injectedCss.push({\r\n content: resources.css.replace(/@import\\s*([^;]*);/g, '') || ' '\r\n });\r\n\r\n for (const cssResource of injectedCss) {\r\n try {\r\n injectedResources.push(await page.addStyleTag(cssResource));\r\n } catch (error) {\r\n logWithStack(\r\n 2,\r\n error,\r\n `[browser] The CSS resource cannot be loaded.`\r\n );\r\n }\r\n }\r\n injectedCss.length = 0;\r\n }\r\n }\r\n return injectedResources;\r\n}\r\n\r\n/**\r\n * Clears out all state set on the page with `addScriptTag` and `addStyleTag`.\r\n * Removes injected resources and resets CSS and script tags on the page.\r\n * Additionally, it destroys previously existing charts.\r\n *\r\n * @async\r\n * @function clearPageResources\r\n *\r\n * @param {Object} page - The Puppeteer page object from which resources will\r\n * be cleared.\r\n * @param {Array.} injectedResources - Array of injected resources\r\n * to be cleared.\r\n */\r\nexport async function clearPageResources(page, injectedResources) {\r\n try {\r\n for (const resource of injectedResources) {\r\n await resource.dispose();\r\n }\r\n\r\n // Destroy old charts after export is done and reset all CSS and script tags\r\n await page.evaluate(() => {\r\n // We are not guaranteed that Highcharts is loaded, when doing SVG exports\r\n if (typeof Highcharts !== 'undefined') {\r\n // eslint-disable-next-line no-undef\r\n const oldCharts = Highcharts.charts;\r\n\r\n // Check in any already existing charts\r\n if (Array.isArray(oldCharts) && oldCharts.length) {\r\n // Destroy old charts\r\n for (const oldChart of oldCharts) {\r\n oldChart && oldChart.destroy();\r\n // eslint-disable-next-line no-undef\r\n Highcharts.charts.shift();\r\n }\r\n }\r\n }\r\n\r\n // eslint-disable-next-line no-undef\r\n const [...scriptsToRemove] = document.getElementsByTagName('script');\r\n // eslint-disable-next-line no-undef\r\n const [, ...stylesToRemove] = document.getElementsByTagName('style');\r\n // eslint-disable-next-line no-undef\r\n const [...linksToRemove] = document.getElementsByTagName('link');\r\n\r\n // Remove tags\r\n for (const element of [\r\n ...scriptsToRemove,\r\n ...stylesToRemove,\r\n ...linksToRemove\r\n ]) {\r\n element.remove();\r\n }\r\n });\r\n } catch (error) {\r\n logWithStack(2, error, `[browser] Could not clear page's resources.`);\r\n }\r\n}\r\n\r\n/**\r\n * Sets the content for a Puppeteer Page using a predefined template\r\n * and additional scripts.\r\n *\r\n * @async\r\n * @function _setPageContent\r\n *\r\n * @param {Object} page - The Puppeteer page object to which the content\r\n * is being set.\r\n */\r\nasync function _setPageContent(page) {\r\n // Set the initial page content\r\n await page.setContent(template, { waitUntil: 'domcontentloaded' });\r\n\r\n // Add all registered Higcharts scripts, quite demanding\r\n await page.addScriptTag({ path: join(getCachePath(), 'sources.js') });\r\n\r\n // Set the initial `animObject` for Highcharts\r\n await page.evaluate(setupHighcharts);\r\n}\r\n\r\n/**\r\n * Set events (like `pageerror` and `console`) for a Puppeteer Page in order\r\n * to catch and display errors and console logs from the window context.\r\n *\r\n * @function _setPageEvents\r\n *\r\n * @param {Object} page - The Puppeteer page object to which the listeners\r\n * are being set.\r\n */\r\nfunction _setPageEvents(page) {\r\n // Get `debug` options\r\n const { debug } = getOptions();\r\n\r\n // Set the `pageerror` listener\r\n page.on('pageerror', async () => {\r\n // It would seem like this may fire at the same time or shortly before\r\n // a page is closed.\r\n if (page.isClosed()) {\r\n return;\r\n }\r\n });\r\n\r\n // Set the `console` listener, if needed\r\n if (debug.enable && debug.listenToConsole) {\r\n page.on('console', (message) => {\r\n console.log(`[debug] ${message.text()}`);\r\n });\r\n }\r\n}\r\n\r\nexport default {\r\n getBrowser,\r\n createBrowser,\r\n closeBrowser,\r\n newPage,\r\n clearPage,\r\n addPageResources,\r\n clearPageResources\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * The CSS to be used on the exported page.\r\n *\r\n * @returns {string} The CSS configuration.\r\n */\r\nexport default () => `\r\n\r\nhtml, body {\r\n margin: 0;\r\n padding: 0;\r\n box-sizing: border-box;\r\n}\r\n\r\n#table-div, #sliders, #datatable, #controls, .ld-row {\r\n display: none;\r\n height: 0;\r\n}\r\n\r\n#chart-container {\r\n box-sizing: border-box;\r\n margin: 0;\r\n overflow: auto;\r\n font-size: 0;\r\n}\r\n\r\n#chart-container > figure, div {\r\n margin-top: 0 !important;\r\n margin-bottom: 0 !important;\r\n}\r\n\r\n`;\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\nimport cssTemplate from './css.js';\r\n\r\n/**\r\n * The SVG template to use when loading SVG content to be exported.\r\n *\r\n * @param {string} svg - The SVG input content to be exported.\r\n *\r\n * @returns {string} The SVG template.\r\n */\r\nexport default (svg) => `\r\n\r\n\r\n \r\n \r\n Highcharts Export\r\n \r\n \r\n \r\n
\r\n ${svg}\r\n
\r\n \r\n\r\n\r\n`;\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * @overview This module handles chart export functionality using Puppeteer.\r\n * It supports exporting charts as SVG, PNG, JPEG, and PDF formats. The module\r\n * manages page resources, sets up the export environment, and processes chart\r\n * configurations or SVG inputs for rendering. Exports to a chart from a page\r\n * using Puppeteer.\r\n */\r\n\r\nimport { addPageResources, clearPageResources } from './browser.js';\r\nimport { createChart } from './highcharts.js';\r\nimport { log } from './logger.js';\r\n\r\nimport svgTemplate from '../templates/svgExport/svgExport.js';\r\n\r\nimport ExportError from './errors/ExportError.js';\r\n\r\n/**\r\n * Exports to a chart from a page using Puppeteer.\r\n *\r\n * @async\r\n * @function puppeteerExport\r\n *\r\n * @param {Object} page - Puppeteer page object.\r\n * @param {Object} options - The `options` object containing complete set\r\n * of options.\r\n *\r\n * @returns {Promise<(string|Buffer|ExportError)>} A Promise that resolves\r\n * to the exported data or rejecting with an `ExportError`.\r\n *\r\n * @throws {ExportError} Throws an `ExportError` if export to an unsupported\r\n * output format occurs.\r\n */\r\nexport async function puppeteerExport(page, options) {\r\n // Injected resources array (additional JS and CSS)\r\n const injectedResources = [];\r\n\r\n try {\r\n // Get the `export` options\r\n const exportOptions = options.export;\r\n\r\n let isSVG = false;\r\n if (exportOptions.svg) {\r\n log(4, '[export] Treating as SVG input.');\r\n\r\n // If the `type` is also SVG, return the input\r\n if (exportOptions.type === 'svg') {\r\n return exportOptions.svg;\r\n }\r\n\r\n // Mark as SVG export for the later size corrections\r\n isSVG = true;\r\n\r\n // SVG export\r\n await _setAsSvg(page, exportOptions.svg);\r\n } else {\r\n log(4, '[export] Treating as JSON config.');\r\n\r\n // Options export\r\n await _setAsOptions(page, options);\r\n }\r\n\r\n // Keeps track of all resources added on the page with addXXXTag. etc\r\n // It's VITAL that all added resources ends up here so we can clear things\r\n // out when doing a new export in the same page!\r\n injectedResources.push(\r\n ...(await addPageResources(page, options.customLogic))\r\n );\r\n\r\n // Get the real chart size and set the zoom accordingly\r\n const size = isSVG\r\n ? await page.evaluate((scale) => {\r\n const svgElement = document.querySelector(\r\n '#chart-container svg:first-of-type'\r\n );\r\n\r\n // Get the values correctly scaled\r\n const chartHeight = svgElement.height.baseVal.value * scale;\r\n const chartWidth = svgElement.width.baseVal.value * scale;\r\n\r\n // In case of SVG the zoom must be set directly for body as scale\r\n // eslint-disable-next-line no-undef\r\n document.body.style.zoom = scale;\r\n\r\n // Set the margin to 0px\r\n // eslint-disable-next-line no-undef\r\n document.body.style.margin = '0px';\r\n\r\n return {\r\n chartHeight,\r\n chartWidth\r\n };\r\n }, parseFloat(exportOptions.scale))\r\n : await page.evaluate(() => {\r\n // eslint-disable-next-line no-undef\r\n const { chartHeight, chartWidth } = window.Highcharts.charts[0];\r\n\r\n // No need for such scale manipulation in case of other types\r\n // of exports. Reset the zoom for other exports than to SVGs\r\n // eslint-disable-next-line no-undef\r\n document.body.style.zoom = 1;\r\n\r\n return {\r\n chartHeight,\r\n chartWidth\r\n };\r\n });\r\n\r\n // Get the clip region for the page\r\n const { x, y } = await _getClipRegion(page);\r\n\r\n // Set final `height` for viewport\r\n const viewportHeight = Math.abs(\r\n Math.ceil(size.chartHeight || exportOptions.height)\r\n );\r\n\r\n // Set final `width` for viewport\r\n const viewportWidth = Math.abs(\r\n Math.ceil(size.chartWidth || exportOptions.width)\r\n );\r\n\r\n // Set the final viewport now that we have the real height\r\n await page.setViewport({\r\n height: viewportHeight,\r\n width: viewportWidth,\r\n deviceScaleFactor: isSVG ? 1 : parseFloat(exportOptions.scale)\r\n });\r\n\r\n let result;\r\n // Rasterization process\r\n switch (exportOptions.type) {\r\n case 'svg':\r\n result = await _createSVG(page);\r\n break;\r\n case 'png':\r\n case 'jpeg':\r\n result = await _createImage(\r\n page,\r\n exportOptions.type,\r\n {\r\n width: viewportWidth,\r\n height: viewportHeight,\r\n x,\r\n y\r\n },\r\n exportOptions.rasterizationTimeout\r\n );\r\n break;\r\n case 'pdf':\r\n result = await _createPDF(\r\n page,\r\n viewportHeight,\r\n viewportWidth,\r\n exportOptions.rasterizationTimeout\r\n );\r\n break;\r\n default:\r\n throw new ExportError(\r\n `[export] Unsupported output format: ${exportOptions.type}.`,\r\n 400\r\n );\r\n }\r\n\r\n // Clear previously injected JS and CSS resources\r\n await clearPageResources(page, injectedResources);\r\n return result;\r\n } catch (error) {\r\n await clearPageResources(page, injectedResources);\r\n return error;\r\n }\r\n}\r\n\r\n/**\r\n * Sets the specified page's content with provided export input within\r\n * the window context using the `page.setContent` function.\r\n *\r\n * @async\r\n * @function _setAsSvg\r\n *\r\n * @param {Object} page - Puppeteer page object.\r\n * @param {string} svg - The SVG input content to be exported.\r\n *\r\n * @returns {Promise} A Promise that resolves after the content is set.\r\n */\r\nasync function _setAsSvg(page, svg) {\r\n await page.setContent(svgTemplate(svg), {\r\n waitUntil: 'domcontentloaded'\r\n });\r\n}\r\n\r\n/**\r\n * Sets the options with specified export input and sizes as configuration into\r\n * the `createChart` function within the window context using\r\n * the `page.evaluate` function.\r\n *\r\n * @async\r\n * @function _setAsOptions\r\n *\r\n * @param {Object} page - Puppeteer page object.\r\n * @param {Object} options - The `options` object containing complete set\r\n * of options.\r\n *\r\n * @returns {Promise} A Promise that resolves after the configuration\r\n * is set.\r\n */\r\nasync function _setAsOptions(page, options) {\r\n await page.evaluate(createChart, options);\r\n}\r\n\r\n/**\r\n * Retrieves the clipping region coordinates of the specified page element\r\n * with the 'chart-container' id.\r\n *\r\n * @async\r\n * @function _getClipRegion\r\n *\r\n * @param {Object} page - Puppeteer page object.\r\n *\r\n * @returns {Promise} A Promise that resolves to an object containing\r\n * `x`, `y`, `width`, and `height` properties.\r\n */\r\nasync function _getClipRegion(page) {\r\n return page.$eval('#chart-container', (element) => {\r\n const { x, y, width, height } = element.getBoundingClientRect();\r\n return {\r\n x,\r\n y,\r\n width,\r\n height: Math.trunc(height > 1 ? height : 500)\r\n };\r\n });\r\n}\r\n\r\n/**\r\n * Creates an SVG by evaluating the `outerHTML` of the first 'svg' element\r\n * inside an element with the id 'container'.\r\n *\r\n * @async\r\n * @function _createSVG\r\n *\r\n * @param {Object} page - Puppeteer page object.\r\n *\r\n * @returns {Promise} A Promise that resolves to the SVG string.\r\n */\r\nasync function _createSVG(page) {\r\n return page.$eval(\r\n '#container svg:first-of-type',\r\n (element) => element.outerHTML\r\n );\r\n}\r\n\r\n/**\r\n * Creates an image using Puppeteer's page `screenshot` functionality with\r\n * specified options.\r\n *\r\n * @async\r\n * @function _createImage\r\n *\r\n * @param {Object} page - Puppeteer page object.\r\n * @param {string} type - Image type.\r\n * @param {Object} clip - Clipping region coordinates.\r\n * @param {number} rasterizationTimeout - Timeout for rasterization\r\n * in milliseconds.\r\n *\r\n * @returns {Promise} A Promise that resolves to the image buffer\r\n * or rejecting with an `ExportError` for timeout.\r\n */\r\nasync function _createImage(page, type, clip, rasterizationTimeout) {\r\n return Promise.race([\r\n page.screenshot({\r\n type,\r\n clip,\r\n encoding: 'base64',\r\n fullPage: false,\r\n optimizeForSpeed: true,\r\n captureBeyondViewport: true,\r\n ...(type !== 'png' ? { quality: 80 } : {}),\r\n // Always render on a transparent page if the expected type format is PNG\r\n omitBackground: type == 'png' // #447, #463\r\n }),\r\n new Promise((_resolve, reject) =>\r\n setTimeout(\r\n () => reject(new ExportError('Rasterization timeout', 408)),\r\n rasterizationTimeout || 1500\r\n )\r\n )\r\n ]);\r\n}\r\n\r\n/**\r\n * Creates a PDF using Puppeteer's page `pdf` functionality with specified\r\n * options.\r\n *\r\n * @async\r\n * @function _createPDF\r\n *\r\n * @param {Object} page - Puppeteer page object.\r\n * @param {number} height - PDF height.\r\n * @param {number} width - PDF width.\r\n * @param {number} rasterizationTimeout - Timeout for rasterization\r\n * in milliseconds.\r\n *\r\n * @returns {Promise} A Promise that resolves to the PDF buffer.\r\n */\r\nasync function _createPDF(page, height, width, rasterizationTimeout) {\r\n await page.emulateMediaType('screen');\r\n return page.pdf({\r\n // This will remove an extra empty page in PDF exports\r\n height: height + 1,\r\n width,\r\n encoding: 'base64',\r\n timeout: rasterizationTimeout || 1500\r\n });\r\n}\r\n\r\nexport default {\r\n puppeteerExport\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * @overview This module provides a worker pool implementation for managing\r\n * the browser instance and pages, specifically designed for use with\r\n * the Highcharts Export Server. It optimizes resources usage and performance\r\n * by maintaining a pool of workers that can handle concurrent export tasks\r\n * using Puppeteer.\r\n */\r\n\r\nimport { Pool } from 'tarn';\r\nimport { v4 as uuid } from 'uuid';\r\n\r\nimport { createBrowser, closeBrowser, newPage, clearPage } from './browser.js';\r\nimport { getOptions } from './config.js';\r\nimport { puppeteerExport } from './export.js';\r\nimport { log, logWithStack } from './logger.js';\r\nimport { getNewDateTime, measureTime } from './utils.js';\r\n\r\nimport ExportError from './errors/ExportError.js';\r\n\r\n// The pool instance\r\nlet pool = null;\r\n\r\n// Pool statistics\r\nconst poolStats = {\r\n exportsAttempted: 0,\r\n exportsPerformed: 0,\r\n exportsDropped: 0,\r\n exportsFromSvg: 0,\r\n exportsFromOptions: 0,\r\n exportsFromSvgAttempts: 0,\r\n exportsFromOptionsAttempts: 0,\r\n timeSpent: 0,\r\n timeSpentAverage: 0\r\n};\r\n\r\n/**\r\n * Initializes the export pool with the provided configuration, creating\r\n * a browser instance and setting up worker resources.\r\n *\r\n * @async\r\n * @function initPool\r\n *\r\n * @param {Object} [poolOptions=getOptions().pool] - Object containing `pool`\r\n * options. The default value is the global pool options of the export server\r\n * instance.\r\n * @param {Array.} [puppeteerArgs=[]] - Additional arguments\r\n * for Puppeteer launch. The default value is an empty array.\r\n *\r\n * @returns {Promise} A Promise that resolves to ending the function\r\n * execution when an already initialized pool of resources is found.\r\n *\r\n * @throws {ExportError} Throws an `ExportError` if could not create the pool\r\n * of workers.\r\n */\r\nexport async function initPool(\r\n poolOptions = getOptions().pool,\r\n puppeteerArgs = []\r\n) {\r\n // Create a browser instance with the puppeteer arguments\r\n await createBrowser(puppeteerArgs);\r\n\r\n try {\r\n log(\r\n 3,\r\n `[pool] Initializing pool with workers: min ${poolOptions.minWorkers}, max ${poolOptions.maxWorkers}.`\r\n );\r\n\r\n if (pool) {\r\n log(\r\n 4,\r\n '[pool] Already initialized, please kill it before creating a new one.'\r\n );\r\n return;\r\n }\r\n\r\n // Keep an eye on a correct min and max workers number\r\n if (poolOptions.minWorkers > poolOptions.maxWorkers) {\r\n poolOptions.minWorkers = poolOptions.maxWorkers;\r\n }\r\n\r\n // Create a pool along with a minimal number of resources\r\n pool = new Pool({\r\n // Get the `create`, `validate`, and `destroy` functions\r\n ..._factory(poolOptions),\r\n min: poolOptions.minWorkers,\r\n max: poolOptions.maxWorkers,\r\n acquireTimeoutMillis: poolOptions.acquireTimeout,\r\n createTimeoutMillis: poolOptions.createTimeout,\r\n destroyTimeoutMillis: poolOptions.destroyTimeout,\r\n idleTimeoutMillis: poolOptions.idleTimeout,\r\n createRetryIntervalMillis: poolOptions.createRetryInterval,\r\n reapIntervalMillis: poolOptions.reaperInterval,\r\n propagateCreateError: false\r\n });\r\n\r\n // Set events\r\n pool.on('release', async (resource) => {\r\n // Clear page\r\n const clearStatus = await clearPage(resource, false);\r\n log(\r\n 4,\r\n `[pool] Pool resource [${resource.id}] - Releasing a worker. Clear page status: ${clearStatus}.`\r\n );\r\n });\r\n\r\n pool.on('destroySuccess', (_eventId, resource) => {\r\n log(\r\n 4,\r\n `[pool] Pool resource [${resource.id}] - Destroyed a worker successfully.`\r\n );\r\n resource.page = null;\r\n });\r\n\r\n const initialResources = [];\r\n // Create an initial number of resources\r\n for (let i = 0; i < poolOptions.minWorkers; i++) {\r\n try {\r\n const resource = await pool.acquire().promise;\r\n initialResources.push(resource);\r\n } catch (error) {\r\n logWithStack(2, error, '[pool] Could not create an initial resource.');\r\n }\r\n }\r\n\r\n // Release the initial number of resources back to the pool\r\n initialResources.forEach((resource) => {\r\n pool.release(resource);\r\n });\r\n\r\n log(\r\n 3,\r\n `[pool] The pool is ready${initialResources.length ? ` with ${initialResources.length} initial resources waiting.` : '.'}`\r\n );\r\n } catch (error) {\r\n throw new ExportError(\r\n '[pool] Could not configure and create the pool of workers.',\r\n 500\r\n ).setError(error);\r\n }\r\n}\r\n\r\n/**\r\n * Kills all workers in the pool, destroys the pool, and closes the browser\r\n * instance.\r\n *\r\n * @async\r\n * @function killPool\r\n *\r\n * @returns {Promise} A Promise that resolves after the workers are\r\n * killed, the pool is destroyed, and the browser is closed.\r\n */\r\nexport async function killPool() {\r\n log(3, '[pool] Killing pool with all workers and closing browser.');\r\n\r\n // If still alive, destroy the pool of pages before closing a browser\r\n if (pool) {\r\n // Free up not released workers\r\n for (const worker of pool.used) {\r\n pool.release(worker.resource);\r\n }\r\n\r\n // Destroy the pool if it is still available\r\n if (!pool.destroyed) {\r\n await pool.destroy();\r\n log(4, '[pool] Destroyed the pool of resources.');\r\n }\r\n pool = null;\r\n }\r\n\r\n // Close the browser instance\r\n await closeBrowser();\r\n}\r\n\r\n/**\r\n * Processes the export work using a worker from the pool. Acquires a worker\r\n * handle from the pool, performs the export using puppeteer, and releases\r\n * the worker handle back to the pool.\r\n *\r\n * @async\r\n * @function postWork\r\n *\r\n * @param {Object} options - The `options` object containing complete set\r\n * of options.\r\n *\r\n * @returns {Promise} A Promise that resolves to the export result\r\n * and options.\r\n *\r\n * @throws {ExportError} Throws an `ExportError` if an error occurs during\r\n * the export process.\r\n */\r\nexport async function postWork(options) {\r\n let workerHandle;\r\n\r\n try {\r\n log(4, '[pool] Work received, starting to process.');\r\n\r\n // An export attempt counted\r\n ++poolStats.exportsAttempted;\r\n\r\n // Display the pool information if needed\r\n if (getOptions().pool.benchmarking) {\r\n getPoolInfo();\r\n }\r\n\r\n // Throw an error in case of lacking the pool instance\r\n if (!pool) {\r\n throw new ExportError(\r\n '[pool] Work received, but pool has not been started.',\r\n 500\r\n );\r\n }\r\n\r\n // The acquire counter\r\n const acquireCounter = measureTime();\r\n\r\n // Try to acquire the worker along with the id, works count and page\r\n try {\r\n log(4, '[pool] Acquiring a worker handle.');\r\n\r\n // Acquire a pool resource\r\n workerHandle = await pool.acquire().promise;\r\n\r\n // Check the page acquire time\r\n if (options.server.benchmarking) {\r\n log(\r\n 5,\r\n options._requestId\r\n ? `[benchmark] Request [${options._requestId}] - `\r\n : '[benchmark] ',\r\n `Acquiring a worker handle took ${acquireCounter()}ms.`\r\n );\r\n }\r\n } catch (error) {\r\n throw new ExportError(\r\n '[pool] ' +\r\n (options._requestId ? `Request [${options._requestId}] - ` : '') +\r\n `Error encountered when acquiring an available entry: ${acquireCounter()}ms.`,\r\n 400\r\n ).setError(error);\r\n }\r\n log(4, '[pool] Acquired a worker handle.');\r\n\r\n if (!workerHandle.page) {\r\n // Set the `workLimit` to exceeded in order to recreate the resource\r\n workerHandle.workCount = options.pool.workLimit + 1;\r\n throw new ExportError(\r\n '[pool] Resolved worker page is invalid: the pool setup is wonky.',\r\n 400\r\n );\r\n }\r\n\r\n // Save the start time\r\n const workStart = getNewDateTime();\r\n\r\n log(\r\n 4,\r\n `[pool] Pool resource [${workerHandle.id}] - Starting work on this pool entry.`\r\n );\r\n\r\n // Perform an export on a puppeteer level\r\n const exportCounter = measureTime();\r\n const result = await puppeteerExport(workerHandle.page, options);\r\n\r\n // Check if it's an error\r\n if (result instanceof Error) {\r\n // NOTE:\r\n // If there's a rasterization timeout, we want need to flush the page.\r\n // This is because the page may be in a state where it's waiting for\r\n // the screenshot to finish even though the timeout has occured.\r\n // Which of course causes a lot of issues with the event system,\r\n // and page consistency.\r\n //\r\n // NOTE:\r\n // Only page.screenshot will throw this, timeouts for PDF's are\r\n // handled by the page.pdf function itself.\r\n //\r\n // ...yes, this is ugly.\r\n if (result.message === 'Rasterization timeout') {\r\n // Set the `workLimit` to exceeded in order to recreate the resource\r\n workerHandle.workCount = options.pool.workLimit + 1;\r\n workerHandle.page = null;\r\n }\r\n\r\n if (\r\n result.name === 'TimeoutError' ||\r\n result.message === 'Rasterization timeout'\r\n ) {\r\n throw new ExportError(\r\n '[pool] ' +\r\n (options._requestId ? `Request [${options._requestId}] - ` : '') +\r\n 'Rasterization timeout: your chart may be too complex or large, and failed to render within the allotted time.'\r\n ).setError(result);\r\n } else {\r\n throw new ExportError(\r\n '[pool] ' +\r\n (options._requestId ? `Request [${options._requestId}] - ` : '') +\r\n `Error encountered during export: ${exportCounter()}ms.`\r\n ).setError(result);\r\n }\r\n }\r\n\r\n // Check the Puppeteer export time\r\n if (options.server.benchmarking) {\r\n log(\r\n 5,\r\n options._requestId\r\n ? `[benchmark] Request [${options._requestId}] - `\r\n : '[benchmark] ',\r\n `Exporting a chart sucessfully took ${exportCounter()}ms.`\r\n );\r\n }\r\n\r\n // Release the resource back to the pool\r\n pool.release(workerHandle);\r\n\r\n // Used for statistics in averageTime and processedWorkCount, which\r\n // in turn is used by the /health route.\r\n const workEnd = getNewDateTime();\r\n const exportTime = workEnd - workStart;\r\n\r\n poolStats.timeSpent += exportTime;\r\n poolStats.timeSpentAverage =\r\n poolStats.timeSpent / ++poolStats.exportsPerformed;\r\n\r\n log(4, `[pool] Work completed in ${exportTime}ms.`);\r\n\r\n // Otherwise return the result\r\n return {\r\n result,\r\n options\r\n };\r\n } catch (error) {\r\n ++poolStats.exportsDropped;\r\n\r\n if (workerHandle) {\r\n pool.release(workerHandle);\r\n }\r\n\r\n throw error;\r\n }\r\n}\r\n\r\n/**\r\n * Retrieves the current pool instance.\r\n *\r\n * @function getPool\r\n *\r\n * @returns {(Object|null)} The current pool instance if initialized, or null\r\n * if the pool has not been created.\r\n */\r\nexport function getPool() {\r\n return pool;\r\n}\r\n\r\n/**\r\n * Gets the statistic of a pool instace about exports.\r\n *\r\n * @function getPoolStats\r\n *\r\n * @returns {Object} The current pool statistics.\r\n */\r\nexport function getPoolStats() {\r\n return poolStats;\r\n}\r\n\r\n/**\r\n * Retrieves pool information in JSON format, including minimum and maximum\r\n * workers, available workers, workers in use, and pending acquire requests.\r\n *\r\n * @function getPoolInfoJSON\r\n *\r\n * @returns {Object} Pool information in JSON format.\r\n */\r\nexport function getPoolInfoJSON() {\r\n return {\r\n min: pool.min,\r\n max: pool.max,\r\n used: pool.numUsed(),\r\n available: pool.numFree(),\r\n allCreated: pool.numUsed() + pool.numFree(),\r\n pendingAcquires: pool.numPendingAcquires(),\r\n pendingCreates: pool.numPendingCreates(),\r\n pendingValidations: pool.numPendingValidations(),\r\n pendingDestroys: pool.pendingDestroys.length,\r\n absoluteAll:\r\n pool.numUsed() +\r\n pool.numFree() +\r\n pool.numPendingAcquires() +\r\n pool.numPendingCreates() +\r\n pool.numPendingValidations() +\r\n pool.pendingDestroys.length\r\n };\r\n}\r\n\r\n/**\r\n * Logs information about the current state of the pool, including the minimum\r\n * and maximum workers, available workers, workers in use, and pending acquire\r\n * requests.\r\n *\r\n * @function getPoolInfo\r\n */\r\nexport function getPoolInfo() {\r\n const {\r\n min,\r\n max,\r\n used,\r\n available,\r\n allCreated,\r\n pendingAcquires,\r\n pendingCreates,\r\n pendingValidations,\r\n pendingDestroys,\r\n absoluteAll\r\n } = getPoolInfoJSON();\r\n\r\n log(5, `[pool] The minimum number of resources allowed by pool: ${min}.`);\r\n log(5, `[pool] The maximum number of resources allowed by pool: ${max}.`);\r\n log(5, `[pool] The number of used resources: ${used}.`);\r\n log(5, `[pool] The number of free resources: ${available}.`);\r\n log(\r\n 5,\r\n `[pool] The number of all created (used and free) resources: ${allCreated}.`\r\n );\r\n log(\r\n 5,\r\n `[pool] The number of resources waiting to be acquired: ${pendingAcquires}.`\r\n );\r\n log(\r\n 5,\r\n `[pool] The number of resources waiting to be created: ${pendingCreates}.`\r\n );\r\n log(\r\n 5,\r\n `[pool] The number of resources waiting to be validated: ${pendingValidations}.`\r\n );\r\n log(\r\n 5,\r\n `[pool] The number of resources waiting to be destroyed: ${pendingDestroys}.`\r\n );\r\n log(5, `[pool] The number of all resources: ${absoluteAll}.`);\r\n}\r\n\r\n/**\r\n * Factory function that returns an object with `create`, `validate`,\r\n * and `destroy` functions for the pool instance.\r\n *\r\n * @function _factory\r\n *\r\n * @param {Object} poolOptions - Object containing `pool` options.\r\n */\r\nfunction _factory(poolOptions) {\r\n return {\r\n /**\r\n * Creates a new worker page for the export pool.\r\n *\r\n * @async\r\n * @function create\r\n *\r\n * @returns {Promise} A Promise that resolves to an object\r\n * containing the worker ID, a reference to the browser page, and initial\r\n * work count.\r\n *\r\n * @throws {ExportError} Throws an `ExportError` if there is an error during\r\n * the creation of the new page.\r\n */\r\n create: async () => {\r\n // Init the resource with unique id and work count\r\n const poolResource = {\r\n id: uuid(),\r\n // Try to distribute the initial work count\r\n workCount: Math.round(Math.random() * (poolOptions.workLimit / 2))\r\n };\r\n\r\n try {\r\n // Start measuring a page creation time\r\n const startDate = getNewDateTime();\r\n\r\n // Create a new page\r\n await newPage(poolResource);\r\n\r\n // Measure the time of full creation and configuration of a page\r\n log(\r\n 3,\r\n `[pool] Pool resource [${poolResource.id}] - Successfully created a worker, took ${\r\n getNewDateTime() - startDate\r\n }ms.`\r\n );\r\n\r\n // Return ready pool resource\r\n return poolResource;\r\n } catch (error) {\r\n log(\r\n 3,\r\n `[pool] Pool resource [${poolResource.id}] - Error encountered when creating a new page.`\r\n );\r\n throw error;\r\n }\r\n },\r\n\r\n /**\r\n * Validates a worker page in the export pool, checking if it has exceeded\r\n * the work limit.\r\n *\r\n * @async\r\n * @function validate\r\n *\r\n * @param {Object} poolResource - The handle to the worker, containing\r\n * the worker's ID, a reference to the browser page, and work count.\r\n *\r\n * @returns {Promise} A Promise that resolves to true if the worker\r\n * is valid and within the work limit; otherwise, to false.\r\n */\r\n validate: async (poolResource) => {\r\n // NOTE:\r\n // In certain cases acquiring throws a TargetCloseError, which may\r\n // be caused by two things:\r\n // - The page is closed and attempted to be reused.\r\n // - Lost contact with the browser.\r\n //\r\n // What we're seeing in logs is that successive exports typically\r\n // succeeds, and the server recovers, indicating that it's likely\r\n // the first case. This is an attempt at allievating the issue by\r\n // simply not validating the worker if the page is null or closed.\r\n //\r\n // The actual result from when this happened, was that a worker would\r\n // be completely locked, stopping it from being acquired until\r\n // its work count reached the limit.\r\n\r\n // Check if the `page` is valid\r\n if (!poolResource.page) {\r\n log(\r\n 3,\r\n `[pool] Pool resource [${poolResource.id}] - Validation failed (no valid page is found).`\r\n );\r\n return false;\r\n }\r\n\r\n // Check if the `page` is closed\r\n if (poolResource.page.isClosed()) {\r\n log(\r\n 3,\r\n `[pool] Pool resource [${poolResource.id}] - Validation failed (page is closed or invalid).`\r\n );\r\n return false;\r\n }\r\n\r\n // Check if the `mainFrame` is detached\r\n if (poolResource.page.mainFrame().detached) {\r\n log(\r\n 3,\r\n `[pool] Pool resource [${poolResource.id}] - Validation failed (page's frame is detached).`\r\n );\r\n return false;\r\n }\r\n\r\n // Check if the `workLimit` is exceeded\r\n if (\r\n poolOptions.workLimit &&\r\n ++poolResource.workCount > poolOptions.workLimit\r\n ) {\r\n log(\r\n 3,\r\n `[pool] Pool resource [${poolResource.id}] - Validation failed (exceeded the ${poolOptions.workLimit} works per resource limit).`\r\n );\r\n return false;\r\n }\r\n\r\n // The `poolResource` is validated\r\n return true;\r\n },\r\n\r\n /**\r\n * Destroys a worker entry in the export pool, closing its associated page.\r\n *\r\n * @async\r\n * @function destroy\r\n *\r\n * @param {Object} poolResource - The handle to the worker, containing\r\n * the worker's ID, a reference to the browser page, and work count.\r\n */\r\n destroy: async (poolResource) => {\r\n log(\r\n 3,\r\n `[pool] Pool resource [${poolResource.id}] - Destroying a worker.`\r\n );\r\n\r\n if (poolResource.page && !poolResource.page.isClosed()) {\r\n try {\r\n // Remove all attached event listeners from the resource\r\n poolResource.page.removeAllListeners('pageerror');\r\n poolResource.page.removeAllListeners('console');\r\n poolResource.page.removeAllListeners('framedetached');\r\n\r\n // We need to wait around for this\r\n await poolResource.page.close();\r\n } catch (error) {\r\n log(\r\n 3,\r\n `[pool] Pool resource [${poolResource.id}] - Page could not be closed upon destroying.`\r\n );\r\n throw error;\r\n }\r\n }\r\n }\r\n };\r\n}\r\n\r\nexport default {\r\n initPool,\r\n killPool,\r\n postWork,\r\n getPool,\r\n getPoolStats,\r\n getPoolInfo,\r\n getPoolInfoJSON\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * @overview Used to sanitize the strings coming from the exporting module\r\n * to prevent XSS attacks (with the DOMPurify library).\r\n */\r\n\r\nimport DOMPurify from 'dompurify';\r\nimport { JSDOM } from 'jsdom';\r\n\r\n/**\r\n * Sanitizes a given HTML string by removing \r\n * tags and any content within them.\r\n *\r\n * @function sanitize\r\n *\r\n * @param {string} input - The HTML string to be sanitized.\r\n *\r\n * @returns {string} The sanitized HTML string.\r\n */\r\nexport function sanitize(input) {\r\n // Get the virtual DOM\r\n const window = new JSDOM('').window;\r\n\r\n // Create a purifying instance\r\n const purify = DOMPurify(window);\r\n\r\n // Return sanitized input\r\n return purify.sanitize(input, { ADD_TAGS: ['foreignObject'] });\r\n}\r\n\r\nexport default {\r\n sanitize\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * @overview This module provides functions to prepare for the exporting charts\r\n * into various image output formats such as JPEG, PNG, PDF, and SVGs.\r\n * It supports single and batch export operations and allows customization\r\n * through options passed from configurations or APIs.\r\n */\r\n\r\nimport { readFileSync, writeFileSync } from 'fs';\r\n\r\nimport { getOptions, mergeOptions, isAllowedConfig } from './config.js';\r\nimport { log, logWithStack } from './logger.js';\r\nimport { killPool, postWork, getPoolStats } from './pool.js';\r\nimport { sanitize } from './sanitize.js';\r\nimport {\r\n fixOutfile,\r\n fixType,\r\n getAbsolutePath,\r\n getBase64,\r\n roundNumber,\r\n wrapAround\r\n} from './utils.js';\r\n\r\nimport ExportError from './errors/ExportError.js';\r\n\r\n// The global flag for the code execution permission\r\nlet allowCodeExecution = false;\r\n\r\n/**\r\n * Starts a single export process based on the specified options and saves\r\n * the image in the provided outfile.\r\n *\r\n * @async\r\n * @function singleExport\r\n *\r\n * @param {Object} options - The `options` object, which may be a partial\r\n * or complete set of options. It must contain at least one of the following\r\n * properties: `infile`, `instr`, `options`, or `svg` to generate a valid image.\r\n *\r\n * @returns {Promise} A Promise that resolves once the single export\r\n * process is completed.\r\n *\r\n * @throws {ExportError} Throws an `ExportError` if an error occurs during\r\n * the single export process.\r\n */\r\nexport async function singleExport(options) {\r\n // Check if the export makes sense\r\n if (options && options.export) {\r\n // Perform an export\r\n await startExport(options, async (error, data) => {\r\n // Exit process when error exists\r\n if (error) {\r\n throw error;\r\n }\r\n\r\n // Get the `b64`, `outfile`, and `type` for a chart\r\n const { b64, outfile, type } = data.options.export;\r\n\r\n // Save the result\r\n try {\r\n if (b64) {\r\n // As a Base64 string to a txt file\r\n writeFileSync(\r\n `${outfile.split('.').shift() || 'chart'}.txt`,\r\n getBase64(data.result, type)\r\n );\r\n } else {\r\n // As a correct image format\r\n writeFileSync(\r\n outfile || `chart.${type}`,\r\n type !== 'svg' ? Buffer.from(data.result, 'base64') : data.result\r\n );\r\n }\r\n } catch (error) {\r\n throw new ExportError(\r\n '[chart] Error while saving a chart.',\r\n 500\r\n ).setError(error);\r\n }\r\n\r\n // Kill pool and close browser after finishing single export\r\n await killPool();\r\n });\r\n } else {\r\n throw new ExportError(\r\n '[chart] No expected `export` options were found. Please provide one of the following options: `infile`, `instr`, `options`, or `svg` to generate a valid image.',\r\n 400\r\n );\r\n }\r\n}\r\n\r\n/**\r\n * Starts a batch export process for multiple charts based on the information\r\n * in the `batch` option. The `batch` is a string in the following format:\r\n * \"infile1.json=outfile1.png;infile2.json=outfile2.png;...\". Results are saved\r\n * in provided outfiles.\r\n *\r\n * @async\r\n * @function batchExport\r\n *\r\n * @param {Object} options - The `options` object, which may be a partial\r\n * or complete set of options. It must contain the `batch` option to generate\r\n * valid images.\r\n *\r\n * @returns {Promise} A Promise that resolves once the batch export\r\n * processes are completed.\r\n *\r\n * @throws {ExportError} Throws an `ExportError` if an error occurs during\r\n * any of the batch export process.\r\n */\r\nexport async function batchExport(options) {\r\n // Check if the export makes sense\r\n if (options && options.export && options.export.batch) {\r\n // An array for collecting batch exports\r\n const batchFunctions = [];\r\n\r\n // Split and pair the `batch` arguments\r\n for (let pair of options.export.batch.split(';') || []) {\r\n pair = pair.split('=');\r\n if (pair.length === 2) {\r\n batchFunctions.push(\r\n startExport(\r\n {\r\n ...options,\r\n export: {\r\n ...options.export,\r\n infile: pair[0],\r\n outfile: pair[1]\r\n }\r\n },\r\n (error, data) => {\r\n // Exit process when error exists\r\n if (error) {\r\n throw error;\r\n }\r\n\r\n // Get the `b64`, `outfile`, and `type` for a chart\r\n const { b64, outfile, type } = data.options.export;\r\n\r\n // Save the result\r\n try {\r\n if (b64) {\r\n // As a Base64 string to a txt file\r\n writeFileSync(\r\n `${outfile.split('.').shift() || 'chart'}.txt`,\r\n getBase64(data.result, type)\r\n );\r\n } else {\r\n // As a correct image format\r\n writeFileSync(\r\n outfile,\r\n type !== 'svg'\r\n ? Buffer.from(data.result, 'base64')\r\n : data.result\r\n );\r\n }\r\n } catch (error) {\r\n throw new ExportError(\r\n '[chart] Error while saving a chart.',\r\n 500\r\n ).setError(error);\r\n }\r\n }\r\n )\r\n );\r\n } else {\r\n log(2, '[chart] No correct pair found for the batch export.');\r\n }\r\n }\r\n\r\n // Await all exports are done\r\n const batchResults = await Promise.allSettled(batchFunctions);\r\n\r\n // Kill pool and close browser after finishing batch export\r\n await killPool();\r\n\r\n // Log errors if found\r\n batchResults.forEach((result, index) => {\r\n // Log the error with stack about the specific batch export\r\n if (result.reason) {\r\n logWithStack(\r\n 1,\r\n result.reason,\r\n `[chart] Batch export number ${index + 1} could not be correctly completed.`\r\n );\r\n }\r\n });\r\n } else {\r\n throw new ExportError(\r\n '[chart] No expected `export` options were found. Please provide the `batch` option to generate valid images.',\r\n 400\r\n );\r\n }\r\n}\r\n\r\n/**\r\n * Starts an export process. The `customOptions` parameter is an object that\r\n * may be partial or complete set of options. The `endCallback` is called when\r\n * the export is completed, with the `error` object as the first argument\r\n * and the `data` object as the second, which contains the Base64 representation\r\n * of the chart in the `result` property and the full set of export options\r\n * in the `options` property.\r\n *\r\n * @async\r\n * @function startExport\r\n *\r\n * @param {Object} customOptions - The `customOptions` object, which may\r\n * be a partial or complete set of options. If the provided options are partial,\r\n * missing values will be merged with the default general options, retrieved\r\n * using the `getOptions` function.\r\n * @param {Function} endCallback - The callback function to be invoked upon\r\n * finalizing work or upon error occurance of the exporting process. The first\r\n * argument is `error` object and the `data` object is the second, that contains\r\n * the Base64 representation of the chart in the `result` property and the full\r\n * set of export options in the `options` property.\r\n *\r\n * @returns {Promise} This function does not return a value directly.\r\n * Instead, it communicates results via the `endCallback`.\r\n *\r\n * @throws {ExportError} Throws an `ExportError` if there is a problem with\r\n * processing input of any type. The error is passed into the `endCallback`\r\n * function and processed there.\r\n */\r\nexport async function startExport(customOptions, endCallback) {\r\n try {\r\n // Starting exporting process message\r\n log(4, '[chart] Starting the exporting process.');\r\n\r\n // Merge the custom options into default ones\r\n const options = mergeOptions(getOptions(false), customOptions);\r\n\r\n // Get the export options\r\n const exportOptions = options.export;\r\n\r\n // Export using options from the file as an input\r\n if (exportOptions.infile !== null) {\r\n log(4, '[chart] Attempting to export from a file input.');\r\n\r\n let fileContent;\r\n try {\r\n // Try to read the file to get the string representation\r\n fileContent = readFileSync(\r\n getAbsolutePath(exportOptions.infile),\r\n 'utf8'\r\n );\r\n } catch (error) {\r\n throw new ExportError(\r\n '[chart] Error loading content from a file input.',\r\n 400\r\n ).setError(error);\r\n }\r\n\r\n // Check the file's extension\r\n if (exportOptions.infile.endsWith('.svg')) {\r\n // Set to the `svg` option\r\n exportOptions.svg = fileContent;\r\n } else if (exportOptions.infile.endsWith('.json')) {\r\n // Set to the `instr` option\r\n exportOptions.instr = fileContent;\r\n } else {\r\n throw new ExportError(\r\n '[chart] Incorrect value of the `infile` option.',\r\n 400\r\n );\r\n }\r\n }\r\n\r\n // Export using SVG as an input\r\n if (exportOptions.svg !== null) {\r\n log(4, '[chart] Attempting to export from an SVG input.');\r\n\r\n // SVG exports attempts counter\r\n ++getPoolStats().exportsFromSvgAttempts;\r\n\r\n // Export from an SVG string\r\n const result = await _exportFromSvg(\r\n sanitize(exportOptions.svg), // #209\r\n options\r\n );\r\n\r\n // SVG exports counter\r\n ++getPoolStats().exportsFromSvg;\r\n\r\n // Pass SVG export result to the end callback\r\n return endCallback(null, result);\r\n }\r\n\r\n // Export using options as an input\r\n if (exportOptions.instr !== null || exportOptions.options !== null) {\r\n log(4, '[chart] Attempting to export from options input.');\r\n\r\n // Options exports attempts counter\r\n ++getPoolStats().exportsFromOptionsAttempts;\r\n\r\n // Export from options\r\n const result = await _exportFromOptions(\r\n exportOptions.instr || exportOptions.options,\r\n options\r\n );\r\n\r\n // Options exports counter\r\n ++getPoolStats().exportsFromOptions;\r\n\r\n // Pass options export result to the end callback\r\n return endCallback(null, result);\r\n }\r\n\r\n // No input specified, pass an error message to the callback\r\n return endCallback(\r\n new ExportError(\r\n `[chart] No valid input specified. Check if at least one of the following parameters is correctly set: 'infile', 'instr', 'options', or 'svg'.`,\r\n 400\r\n )\r\n );\r\n } catch (error) {\r\n return endCallback(error);\r\n }\r\n}\r\n\r\n/**\r\n * Retrieves and returns the current status of the code execution permission.\r\n *\r\n * @function getAllowCodeExecution\r\n *\r\n * @returns {boolean} The value of the global `allowCodeExecution` option.\r\n */\r\nexport function getAllowCodeExecution() {\r\n return allowCodeExecution;\r\n}\r\n\r\n/**\r\n * Sets the code execution permission based on the provided boolean value.\r\n *\r\n * @function setAllowCodeExecution\r\n *\r\n * @param {boolean} value - The value to be assigned to the global\r\n * `allowCodeExecution` option.\r\n */\r\nexport function setAllowCodeExecution(value) {\r\n allowCodeExecution = value;\r\n}\r\n\r\n/**\r\n * Exports from an SVG based input with the provided options.\r\n *\r\n * @async\r\n * @function _exportFromSvg\r\n *\r\n * @param {string} inputToExport - The SVG based input to be exported.\r\n * @param {Object} options - The `options` object containing complete set\r\n * of options.\r\n *\r\n * @returns {Promise} A Promise that resolves to a result of the export\r\n * process.\r\n *\r\n * @throws {ExportError} Throws an `ExportError` if there is not a correct SVG\r\n * input.\r\n */\r\nasync function _exportFromSvg(inputToExport, options) {\r\n // Check if it is SVG\r\n if (\r\n typeof inputToExport === 'string' &&\r\n (inputToExport.indexOf('= 0 || inputToExport.indexOf('= 0)\r\n ) {\r\n log(4, '[chart] Parsing input as SVG.');\r\n\r\n // Set the export input as SVG\r\n options.export.svg = inputToExport;\r\n\r\n // Reset the rest of the export input options\r\n options.export.instr = null;\r\n options.export.options = null;\r\n\r\n // Call the function with an SVG string as an export input\r\n return _prepareExport(options);\r\n } else {\r\n throw new ExportError('[chart] Not a correct SVG input.', 400);\r\n }\r\n}\r\n\r\n/**\r\n * Exports from an options based input with the provided options.\r\n *\r\n * @async\r\n * @function _exportFromOptions\r\n *\r\n * @param {string} inputToExport - The options based input to be exported.\r\n * @param {Object} options - The `options` object containing complete set\r\n * of options.\r\n *\r\n * @returns {Promise} A Promise that resolves to a result of the export\r\n * process.\r\n *\r\n * @throws {ExportError} Throws an `ExportError` if there is not a correct\r\n * chart options input.\r\n */\r\nasync function _exportFromOptions(inputToExport, options) {\r\n log(4, '[chart] Parsing input from options.');\r\n\r\n // Try to check, validate and parse to stringified options\r\n const stringifiedOptions = isAllowedConfig(\r\n inputToExport,\r\n true,\r\n options.customLogic.allowCodeExecution\r\n );\r\n\r\n // Check if a correct stringified options\r\n if (\r\n stringifiedOptions === null ||\r\n typeof stringifiedOptions !== 'string' ||\r\n !stringifiedOptions.startsWith('{') ||\r\n !stringifiedOptions.endsWith('}')\r\n ) {\r\n throw new ExportError(\r\n '[chart] Invalid configuration provided - Only options configurations and SVG are allowed for this server. If this is your server, JavaScript custom code can be enabled by starting the server with the `allowCodeExecution` options set to true.',\r\n 403\r\n );\r\n }\r\n\r\n // Set the export input as a stringified chart options\r\n options.export.instr = stringifiedOptions;\r\n\r\n // Reset the rest of the export input options\r\n options.export.svg = null;\r\n\r\n // Call the function with a stringified chart options\r\n return _prepareExport(options);\r\n}\r\n\r\n/**\r\n * Function for finalizing options and configurations before export.\r\n *\r\n * @async\r\n * @function _prepareExport\r\n *\r\n * @param {Object} options - The `options` object containing complete set\r\n * of options.\r\n *\r\n * @returns {Promise} A Promise that resolves to a result of the export\r\n * process.\r\n */\r\nasync function _prepareExport(options) {\r\n const { export: exportOptions, customLogic: customLogicOptions } = options;\r\n\r\n // Prepare the `type` option\r\n exportOptions.type = fixType(exportOptions.type, exportOptions.outfile);\r\n\r\n // Prepare the `outfile` option\r\n exportOptions.outfile = fixOutfile(exportOptions.type, exportOptions.outfile);\r\n\r\n // Notify about the custom logic usage status\r\n log(\r\n 3,\r\n `[chart] The custom logic is ${customLogicOptions.allowCodeExecution ? 'allowed' : 'disallowed'}.`\r\n );\r\n\r\n // Prepare the custom logic options (`customCode`, `callback`, `resources`)\r\n _handleCustomLogic(customLogicOptions, customLogicOptions.allowCodeExecution);\r\n\r\n // Prepare the `globalOptions` and `themeOptions` options\r\n _handleGlobalAndTheme(\r\n exportOptions,\r\n customLogicOptions.allowFileResources,\r\n customLogicOptions.allowCodeExecution\r\n );\r\n\r\n // Prepare the `height`, `width`, and `scale` options\r\n options.export = {\r\n ...exportOptions,\r\n ..._findChartSize(exportOptions)\r\n };\r\n\r\n // Post the work to the pool\r\n return postWork(options);\r\n}\r\n\r\n/**\r\n * Calculates the `height`, `width` and `scale` for chart exports based\r\n * on the provided export options.\r\n *\r\n * The function prioritizes values in the following order:\r\n * 1. The `height`, `width`, `scale` from the `exportOptions`.\r\n * 2. Options from the chart configuration (from `exporting` and `chart`).\r\n * 3. Options from the global options (from `exporting` and `chart`).\r\n * 4. Options from the theme options (from `exporting` and `chart` sections).\r\n * 5. Fallback default values (`height = 400`, `width = 600`, `scale = 1`).\r\n *\r\n * @function _findChartSize\r\n *\r\n * @param {Object} exportOptions - The object containing `export` options.\r\n *\r\n * @returns {Object} An object containing the calculated `height`, `width`\r\n * and `scale` values for the chart export.\r\n */\r\nfunction _findChartSize(exportOptions) {\r\n // Check the `options` and `instr` for chart and exporting sections\r\n const { chart: optionsChart, exporting: optionsExporting } =\r\n exportOptions.options || isAllowedConfig(exportOptions.instr) || false;\r\n\r\n // Check the `globalOptions` for chart and exporting sections\r\n const { chart: globalOptionsChart, exporting: globalOptionsExporting } =\r\n isAllowedConfig(exportOptions.globalOptions) || false;\r\n\r\n // Check the `themeOptions` for chart and exporting sections\r\n const { chart: themeOptionsChart, exporting: themeOptionsExporting } =\r\n isAllowedConfig(exportOptions.themeOptions) || false;\r\n\r\n // Find the `scale` value:\r\n // - It cannot be lower than 0.1\r\n // - It cannot be higher than 5.0\r\n // - It must be rounded to 2 decimal places (e.g. 0.23234 -> 0.23)\r\n const scale = roundNumber(\r\n Math.max(\r\n 0.1,\r\n Math.min(\r\n exportOptions.scale ||\r\n optionsExporting?.scale ||\r\n globalOptionsExporting?.scale ||\r\n themeOptionsExporting?.scale ||\r\n exportOptions.defaultScale ||\r\n 1,\r\n 5.0\r\n )\r\n ),\r\n 2\r\n );\r\n\r\n // Find the `height` value\r\n const height =\r\n exportOptions.height ||\r\n optionsExporting?.sourceHeight ||\r\n optionsChart?.height ||\r\n globalOptionsExporting?.sourceHeight ||\r\n globalOptionsChart?.height ||\r\n themeOptionsExporting?.sourceHeight ||\r\n themeOptionsChart?.height ||\r\n exportOptions.defaultHeight ||\r\n 400;\r\n\r\n // Find the `width` value\r\n const width =\r\n exportOptions.width ||\r\n optionsExporting?.sourceWidth ||\r\n optionsChart?.width ||\r\n globalOptionsExporting?.sourceWidth ||\r\n globalOptionsChart?.width ||\r\n themeOptionsExporting?.sourceWidth ||\r\n themeOptionsChart?.width ||\r\n exportOptions.defaultWidth ||\r\n 600;\r\n\r\n // Gather `height`, `width` and `scale` information in one object\r\n const size = { height, width, scale };\r\n\r\n // Get rid of potential `px` and `%`\r\n for (let [param, value] of Object.entries(size)) {\r\n size[param] =\r\n typeof value === 'string' ? +value.replace(/px|%/gi, '') : value;\r\n }\r\n\r\n // Return the size object\r\n return size;\r\n}\r\n\r\n/**\r\n * Handles the execution of custom logic options, including loading `resources`,\r\n * `customCode`, and `callback`. If code execution is allowed, it processes\r\n * the custom logic options accordingly. If code execution is not allowed,\r\n * it disables the usage of resources, custom code and callback.\r\n *\r\n * @function _handleCustomLogic\r\n *\r\n * @param {Object} customLogicOptions - The object containing `customLogic`\r\n * options.\r\n * @param {boolean} allowCodeExecution - A flag indicating whether code\r\n * execution is allowed.\r\n *\r\n * @throws {ExportError} Throws an `ExportError` if code execution\r\n * is not allowed but custom logic options are still provided.\r\n */\r\nfunction _handleCustomLogic(customLogicOptions, allowCodeExecution) {\r\n // In case of allowing code execution\r\n if (allowCodeExecution) {\r\n // Process the `resources` option\r\n if (typeof customLogicOptions.resources === 'string') {\r\n // Custom stringified resources\r\n customLogicOptions.resources = _handleResources(\r\n customLogicOptions.resources,\r\n customLogicOptions.allowFileResources,\r\n true\r\n );\r\n } else if (!customLogicOptions.resources) {\r\n try {\r\n // Load the default one\r\n customLogicOptions.resources = _handleResources(\r\n readFileSync(getAbsolutePath('resources.json'), 'utf8'),\r\n customLogicOptions.allowFileResources,\r\n true\r\n );\r\n } catch (error) {\r\n log(2, '[chart] Unable to load the default `resources.json` file.');\r\n }\r\n }\r\n\r\n // Process the `customCode` option\r\n try {\r\n // Try to load custom code and wrap around it in a self invoking function\r\n customLogicOptions.customCode = wrapAround(\r\n customLogicOptions.customCode,\r\n customLogicOptions.allowFileResources\r\n );\r\n } catch (error) {\r\n logWithStack(2, error, '[chart] The `customCode` cannot be loaded.');\r\n\r\n // In case of an error, set the option with null\r\n customLogicOptions.customCode = null;\r\n }\r\n\r\n // Process the `callback` option\r\n try {\r\n // Try to load callback function\r\n customLogicOptions.callback = wrapAround(\r\n customLogicOptions.callback,\r\n customLogicOptions.allowFileResources,\r\n true\r\n );\r\n } catch (error) {\r\n logWithStack(2, error, '[chart] The `callback` cannot be loaded.');\r\n\r\n // In case of an error, set the option with null\r\n customLogicOptions.callback = null;\r\n }\r\n\r\n // Check if there is the `customCode` present\r\n if ([null, undefined].includes(customLogicOptions.customCode)) {\r\n log(3, '[chart] No value for the `customCode` option found.');\r\n }\r\n\r\n // Check if there is the `callback` present\r\n if ([null, undefined].includes(customLogicOptions.callback)) {\r\n log(3, '[chart] No value for the `callback` option found.');\r\n }\r\n\r\n // Check if there is the `resources` present\r\n if ([null, undefined].includes(customLogicOptions.resources)) {\r\n log(3, '[chart] No value for the `resources` option found.');\r\n }\r\n } else {\r\n // If the `allowCodeExecution` flag is set to false, we should refuse\r\n // the usage of the `callback`, `resources`, and `customCode` options.\r\n // Additionally, the worker will refuse to run arbitrary JavaScript.\r\n if (\r\n customLogicOptions.callback ||\r\n customLogicOptions.resources ||\r\n customLogicOptions.customCode\r\n ) {\r\n // Reset all custom code options\r\n customLogicOptions.callback = null;\r\n customLogicOptions.resources = null;\r\n customLogicOptions.customCode = null;\r\n\r\n // Send a message saying that the exporter does not support these settings\r\n throw new ExportError(\r\n `[chart] The 'callback', 'resources', and 'customCode' options have been disabled for this server.`,\r\n 403\r\n );\r\n }\r\n }\r\n}\r\n\r\n/**\r\n * Handles and validates resources from the `resources` option for export.\r\n *\r\n * @function _handleResources\r\n *\r\n * @param {(Object|string|null)} [resources=null] - The resources to be handled.\r\n * Can be either a JSON object, stringified JSON, a path to a JSON file,\r\n * or null. The default value is null.\r\n * @param {boolean} allowFileResources - A flag indicating whether loading\r\n * resources from files is allowed.\r\n * @param {boolean} allowCodeExecution - A flag indicating whether code\r\n * execution is allowed.\r\n *\r\n * @returns {(Object|null)} The handled resources or null if no valid resources\r\n * are found.\r\n */\r\nfunction _handleResources(\r\n resources = null,\r\n allowFileResources,\r\n allowCodeExecution\r\n) {\r\n // List of allowed sections in the resources JSON\r\n const allowedProps = ['js', 'css', 'files'];\r\n\r\n let handledResources = resources;\r\n let correctResources = false;\r\n\r\n // Try to load resources from a file\r\n if (allowFileResources && resources.endsWith('.json')) {\r\n try {\r\n handledResources = isAllowedConfig(\r\n readFileSync(getAbsolutePath(resources), 'utf8'),\r\n false,\r\n allowCodeExecution\r\n );\r\n } catch {\r\n return null;\r\n }\r\n } else {\r\n // Try to get JSON\r\n handledResources = isAllowedConfig(resources, false, allowCodeExecution);\r\n\r\n // Get rid of the files section\r\n if (handledResources && !allowFileResources) {\r\n delete handledResources.files;\r\n }\r\n }\r\n\r\n // Filter from unnecessary properties\r\n for (const propName in handledResources) {\r\n if (!allowedProps.includes(propName)) {\r\n delete handledResources[propName];\r\n } else if (!correctResources) {\r\n correctResources = true;\r\n }\r\n }\r\n\r\n // Check if at least one of allowed properties is present\r\n if (!correctResources) {\r\n return null;\r\n }\r\n\r\n // Handle files section\r\n if (handledResources.files) {\r\n handledResources.files = handledResources.files.map((item) => item.trim());\r\n if (!handledResources.files || handledResources.files.length <= 0) {\r\n delete handledResources.files;\r\n }\r\n }\r\n\r\n // Return resources\r\n return handledResources;\r\n}\r\n\r\n/**\r\n * Handles the loading and validation of the `globalOptions` and `themeOptions`\r\n * in the export options. If the option is a string and references a JSON file\r\n * (when the `allowFileResources` is true), it reads and parses the file.\r\n * Otherwise, it attempts to parse the string or object as JSON. If any errors\r\n * occur during this process, the option is set to null. If there is an error\r\n * loading or parsing the `globalOptions` or `themeOptions`, the error is logged\r\n * and the option is set to null.\r\n *\r\n * @function _handleGlobalAndTheme\r\n *\r\n * @param {Object} exportOptions - The object containing `export` options.\r\n * @param {boolean} allowFileResources - A flag indicating whether loading\r\n * resources from files is allowed.\r\n * @param {boolean} allowCodeExecution - A flag indicating whether code\r\n * execution is allowed.\r\n */\r\nfunction _handleGlobalAndTheme(\r\n exportOptions,\r\n allowFileResources,\r\n allowCodeExecution\r\n) {\r\n // Check the `globalOptions` and `themeOptions` options\r\n ['globalOptions', 'themeOptions'].forEach((optionsName) => {\r\n try {\r\n // Check if the option exists\r\n if (exportOptions[optionsName]) {\r\n // Check if it is a string and a file name with the `.json` extension\r\n if (\r\n allowFileResources &&\r\n typeof exportOptions[optionsName] === 'string' &&\r\n exportOptions[optionsName].endsWith('.json')\r\n ) {\r\n // Check if the file content can be a config, and save it as a string\r\n exportOptions[optionsName] = isAllowedConfig(\r\n readFileSync(getAbsolutePath(exportOptions[optionsName]), 'utf8'),\r\n true,\r\n allowCodeExecution\r\n );\r\n } else {\r\n // Check if the value can be a config, and save it as a string\r\n exportOptions[optionsName] = isAllowedConfig(\r\n exportOptions[optionsName],\r\n true,\r\n allowCodeExecution\r\n );\r\n }\r\n }\r\n } catch (error) {\r\n logWithStack(\r\n 2,\r\n error,\r\n `[chart] The \\`${optionsName}\\` cannot be loaded.`\r\n );\r\n\r\n // In case of an error, set the option with null\r\n exportOptions[optionsName] = null;\r\n }\r\n });\r\n\r\n // Check if there is the `globalOptions` present\r\n if ([null, undefined].includes(exportOptions.globalOptions)) {\r\n log(3, '[chart] No value for the `globalOptions` option found.');\r\n }\r\n\r\n // Check if there is the `themeOptions` present\r\n if ([null, undefined].includes(exportOptions.themeOptions)) {\r\n log(3, '[chart] No value for the `themeOptions` option found.');\r\n }\r\n}\r\n\r\nexport default {\r\n startExport,\r\n singleExport,\r\n batchExport,\r\n getAllowCodeExecution,\r\n setAllowCodeExecution\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * @overview This module provides utility functions for managing intervals\r\n * and timeouts in a centralized manner. It maintains a registry of all active\r\n * timers and allows for their efficient cleanup when needed. This can be useful\r\n * in applications where proper resource management and clean shutdown of timers\r\n * are critical to avoid memory leaks or unintended behavior.\r\n */\r\n\r\nimport { log } from './logger.js';\r\n\r\n// Array that contains ids of all ongoing intervals and timeouts\r\nconst timerIds = [];\r\n\r\n/**\r\n * Adds id of the `setInterval` or `setTimeout` and to the `timerIds` array.\r\n *\r\n * @function addTimer\r\n *\r\n * @param {NodeJS.Timeout} id - Id of an interval or a timeout.\r\n */\r\nexport function addTimer(id) {\r\n timerIds.push(id);\r\n}\r\n\r\n/**\r\n * Clears all of ongoing intervals and timeouts by ids gathered\r\n * in the `timerIds` array.\r\n *\r\n * @function clearAllTimers\r\n */\r\nexport function clearAllTimers() {\r\n log(4, `[timer] Clearing all registered intervals and timeouts.`);\r\n for (const id of timerIds) {\r\n clearInterval(id);\r\n clearTimeout(id);\r\n }\r\n}\r\n\r\nexport default {\r\n addTimer,\r\n clearAllTimers\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * @overview Provides middleware functions for logging errors with stack traces\r\n * and handling error responses in an Express application.\r\n */\r\n\r\nimport { getOptions } from '../../config.js';\r\nimport { logWithStack } from '../../logger.js';\r\n\r\n/**\r\n * Middleware for logging errors with stack trace and handling error response.\r\n *\r\n * @function logErrorMiddleware\r\n *\r\n * @param {Error} error - The error object.\r\n * @param {Express.Request} request - The Express request object.\r\n * @param {Express.Response} response - The Express response object.\r\n * @param {Function} next - The next middleware function.\r\n *\r\n * @returns {undefined} The call to the next middleware function with\r\n * the passed error.\r\n */\r\nfunction logErrorMiddleware(error, request, response, next) {\r\n // Display the error with stack in a correct format\r\n logWithStack(1, error);\r\n\r\n // Delete the stack for the environment other than the development\r\n if (getOptions().other.nodeEnv !== 'development') {\r\n delete error.stack;\r\n }\r\n\r\n // Call the `returnErrorMiddleware` middleware\r\n return next(error);\r\n}\r\n\r\n/**\r\n * Middleware for returning error response.\r\n *\r\n * @function returnErrorMiddleware\r\n *\r\n * @param {Error} error - The error object.\r\n * @param {Express.Request} request - The Express request object.\r\n * @param {Express.Response} response - The Express response object.\r\n * @param {Function} next - The next middleware function.\r\n */\r\nfunction returnErrorMiddleware(error, request, response, next) {\r\n // Gather all requied information for the response\r\n const { message, stack } = error;\r\n\r\n // Use the error's status code or the default 400\r\n const statusCode = error.statusCode || 400;\r\n\r\n // Set and return response\r\n response.status(statusCode).json({ statusCode, message, stack });\r\n}\r\n\r\n/**\r\n * Adds the error middlewares to the passed express app instance.\r\n *\r\n * @param {Express} app - The Express app instance.\r\n */\r\nexport default function errorMiddleware(app) {\r\n // Add log error middleware\r\n app.use(logErrorMiddleware);\r\n\r\n // Add set status and return error middleware\r\n app.use(returnErrorMiddleware);\r\n}\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * @overview Provides middleware functions for configuring and enabling rate\r\n * limiting in an Express application.\r\n */\r\n\r\nimport rateLimit from 'express-rate-limit';\r\n\r\nimport { getOptions } from '../../config.js';\r\nimport { log } from '../../logger.js';\r\n\r\nimport ExportError from '../../errors/ExportError.js';\r\n\r\n/**\r\n * Middleware for enabling rate limiting on the specified Express app.\r\n *\r\n * @param {Express} app - The Express app instance.\r\n *\r\n * @param {Object} [rateLimitingOptions=getOptions().server.rateLimiting] -\r\n * Object containing `rateLimiting` options. The default value is the global\r\n * rate limiting options of the export server instance.\r\n *\r\n * @throws {ExportError} Throws an `ExportError` if could not configure and set\r\n * the rate limiting options.\r\n */\r\nexport default function rateLimitingMiddleware(\r\n app,\r\n rateLimitingOptions = getOptions().server.rateLimiting\r\n) {\r\n try {\r\n // Check if the rate limiting is enabled\r\n if (rateLimitingOptions.enable) {\r\n const msg =\r\n 'Too many requests, you have been rate limited. Please try again later.';\r\n\r\n // Options for the rate limiter\r\n const rateOptions = {\r\n max: rateLimitingOptions.maxRequests || 30,\r\n window: rateLimitingOptions.window || 1,\r\n delay: rateLimitingOptions.delay || 0,\r\n trustProxy: rateLimitingOptions.trustProxy || false,\r\n skipKey: rateLimitingOptions.skipKey || false,\r\n skipToken: rateLimitingOptions.skipToken || false\r\n };\r\n\r\n // Set if behind a proxy\r\n if (rateOptions.trustProxy) {\r\n app.enable('trust proxy');\r\n }\r\n\r\n // Create a limiter\r\n const limiter = rateLimit({\r\n windowMs: rateOptions.window * 60 * 1000,\r\n // Limit each IP to 100 requests per windowMs\r\n max: rateOptions.max,\r\n // Disable delaying, full speed until the max limit is reached\r\n delayMs: rateOptions.delay,\r\n handler: (request, response) => {\r\n response.format({\r\n json: () => {\r\n response.status(429).send({ message: msg });\r\n },\r\n default: () => {\r\n response.status(429).send(msg);\r\n }\r\n });\r\n },\r\n skip: (request) => {\r\n // Allow bypassing the limiter if a valid key/token has been sent\r\n if (\r\n rateOptions.skipKey !== false &&\r\n rateOptions.skipToken !== false &&\r\n request.query.key === rateOptions.skipKey &&\r\n request.query.access_token === rateOptions.skipToken\r\n ) {\r\n log(4, '[rate limiting] Skipping rate limiter.');\r\n return true;\r\n }\r\n return false;\r\n }\r\n });\r\n\r\n // Use a limiter as a middleware\r\n app.use(limiter);\r\n\r\n log(\r\n 3,\r\n `[rate limiting] Enabled rate limiting with ${rateOptions.max} requests per ${rateOptions.window} minute for each IP, trusting proxy: ${rateOptions.trustProxy}.`\r\n );\r\n }\r\n } catch (error) {\r\n throw new ExportError(\r\n '[rate limiting] Could not configure and set the rate limiting options.',\r\n 500\r\n ).setError(error);\r\n }\r\n}\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\nimport ExportError from './ExportError.js';\r\n\r\n/**\r\n * A custom HTTP error class that extends the `ExportError`. Used to handle\r\n * errors with HTTP status codes.\r\n */\r\nclass HttpError extends ExportError {\r\n /**\r\n * Creates an instance of the `HttpError`.\r\n *\r\n * @param {string} message - The error message to be displayed.\r\n * @param {number} statusCode - Optional HTTP status code associated\r\n * with the error (e.g., 400, 500).\r\n */\r\n constructor(message, statusCode) {\r\n super(message, statusCode);\r\n }\r\n\r\n /**\r\n * Sets or updates the HTTP status code for the error.\r\n *\r\n * @param {number} statusCode - The HTTP status code to assign to the error.\r\n *\r\n * @returns {HttpError} The updated instance of the `HttpError` class.\r\n */\r\n setStatus(statusCode) {\r\n this.statusCode = statusCode;\r\n\r\n return this;\r\n }\r\n}\r\n\r\nexport default HttpError;\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * @overview Provides middleware functions for validating incoming HTTP requests\r\n * in an Express application. This module ensures that requests contain\r\n * appropriate content types and valid request bodies, including proper JSON\r\n * structures and chart data for exports. It checks for potential issues such\r\n * as missing or malformed data, private range URLs in SVG payloads, and allows\r\n * for flexible options validation. The middleware logs detailed information\r\n * and handles errors related to incorrect payloads, chart data, and private URL\r\n * usage.\r\n */\r\n\r\nimport { v4 as uuid } from 'uuid';\r\n\r\nimport { getAllowCodeExecution } from '../../chart.js';\r\nimport { isAllowedConfig } from '../../config.js';\r\nimport { log } from '../../logger.js';\r\nimport {\r\n fixConstr,\r\n fixType,\r\n isObjectEmpty,\r\n isPrivateRangeUrlFound\r\n} from '../../utils.js';\r\n\r\nimport HttpError from '../../errors/HttpError.js';\r\n\r\n/**\r\n * Middleware for validating the content-type header.\r\n *\r\n * @function contentTypeMiddleware\r\n *\r\n * @param {Express.Request} request - The Express request object.\r\n * @param {Express.Response} response - The Express response object.\r\n * @param {Function} next - The next middleware function.\r\n *\r\n * @returns {undefined} The call to the next middleware function.\r\n *\r\n * @throws {HttpError} Throws an `HttpError` if the content-type\r\n * is not correct.\r\n */\r\nfunction contentTypeMiddleware(request, response, next) {\r\n try {\r\n // Get the content type header\r\n const contentType = request.headers['content-type'] || '';\r\n\r\n // Allow only JSON, URL-encoded and form data without files types of data\r\n if (\r\n !contentType.includes('application/json') &&\r\n !contentType.includes('application/x-www-form-urlencoded') &&\r\n !contentType.includes('multipart/form-data')\r\n ) {\r\n throw new HttpError(\r\n '[validation] Content-Type must be application/json, application/x-www-form-urlencoded, or multipart/form-data.',\r\n 415\r\n );\r\n }\r\n\r\n // Call the `requestBodyMiddleware` middleware\r\n return next();\r\n } catch (error) {\r\n return next(error);\r\n }\r\n}\r\n\r\n/**\r\n * Middleware for validating the request's body.\r\n *\r\n * @function requestBodyMiddleware\r\n *\r\n * @param {Express.Request} request - The Express request object.\r\n * @param {Express.Response} response - The Express response object.\r\n * @param {Function} next - The next middleware function.\r\n *\r\n * @returns {undefined} The call to the next middleware function.\r\n *\r\n * @throws {HttpError} Throws an `HttpError` if the body is not correct.\r\n * @throws {HttpError} Throws an `HttpError` if the chart data from the body\r\n * is not correct.\r\n * @throws {HttpError} Throws an `HttpError` in case of the private range url\r\n * error.\r\n */\r\nfunction requestBodyMiddleware(request, response, next) {\r\n try {\r\n // Get the request body\r\n const body = request.body;\r\n\r\n // Create a unique ID for a request\r\n const requestId = uuid().replace(/-/g, '');\r\n\r\n // Throw an error if there is no correct body\r\n if (!body || isObjectEmpty(body)) {\r\n log(\r\n 2,\r\n `[validation] Request [${requestId}] - The request from ${\r\n request.headers['x-forwarded-for'] || request.connection.remoteAddress\r\n } was incorrect. Received payload is empty.`\r\n );\r\n\r\n throw new HttpError(\r\n \"[validation] The request body is required. Please ensure that your Content-Type header is correct. Accepted types are 'application/json' and 'multipart/form-data'.\",\r\n 400\r\n );\r\n }\r\n\r\n // Get the allowCodeExecution option for the server\r\n const allowCodeExecution = getAllowCodeExecution();\r\n\r\n // Find a correct chart options\r\n const instr = isAllowedConfig(\r\n // Use one of the below\r\n body.instr || body.options || body.infile || body.data,\r\n // Stringify options\r\n true,\r\n // Allow or disallow functions\r\n allowCodeExecution\r\n );\r\n\r\n // Throw an error if there is no correct chart data\r\n if (instr === null && !body.svg) {\r\n log(\r\n 2,\r\n `[validation] Request [${requestId}] - The request from ${\r\n request.headers['x-forwarded-for'] || request.connection.remoteAddress\r\n } was incorrect. Received payload is missing correct chart data for export: ${JSON.stringify(body)}.`\r\n );\r\n\r\n throw new HttpError(\r\n \"[validation] No correct chart data found. Ensure that you are using either application/json or multipart/form-data headers. If sending JSON, make sure the chart data is in the 'infile', 'options', or 'data' attribute. If sending SVG, ensure it is in the 'svg' attribute.\",\r\n 400\r\n );\r\n }\r\n\r\n // Throw an error if test of xlink:href elements from payload's SVG fails\r\n if (body.svg && isPrivateRangeUrlFound(body.svg)) {\r\n throw new HttpError(\r\n \"[validation] SVG potentially contain at least one forbidden URL in 'xlink:href' element. Please review the SVG content and ensure that all referenced URLs comply with security policies.\",\r\n 400\r\n );\r\n }\r\n\r\n // Get options from the body and store parsed structure in the request\r\n request.validatedOptions = {\r\n // Set the created ID as a `_requestId` property in the validated options\r\n _requestId: requestId,\r\n export: {\r\n instr,\r\n svg: body.svg,\r\n outfile:\r\n body.outfile ||\r\n `${request.params.filename || 'chart'}.${fixType(body.type)}`,\r\n type: fixType(body.type, body.outfile),\r\n constr: fixConstr(body.constr),\r\n b64: body.b64,\r\n noDownload: body.noDownload,\r\n height: body.height,\r\n width: body.width,\r\n scale: body.scale,\r\n globalOptions: isAllowedConfig(\r\n body.globalOptions,\r\n true,\r\n allowCodeExecution\r\n ),\r\n themeOptions: isAllowedConfig(\r\n body.themeOptions,\r\n true,\r\n allowCodeExecution\r\n )\r\n },\r\n customLogic: {\r\n allowCodeExecution,\r\n allowFileResources: false,\r\n customCode: body.customCode,\r\n callback: body.callback,\r\n resources: isAllowedConfig(body.resources, true, allowCodeExecution)\r\n }\r\n };\r\n\r\n // Call the next middleware\r\n return next();\r\n } catch (error) {\r\n return next(error);\r\n }\r\n}\r\n\r\n/**\r\n * Adds the validation middlewares to the passed express app instance.\r\n *\r\n * @param {Express} app - The Express app instance.\r\n */\r\nexport default function validationMiddleware(app) {\r\n // Add content type validation middleware\r\n app.post(['/', '/:filename'], contentTypeMiddleware);\r\n\r\n // Add request body request validation middleware\r\n app.post(['/', '/:filename'], requestBodyMiddleware);\r\n}\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * @overview Defines the export routes and logic for handling chart export\r\n * requests in an Express server. This module processes incoming requests\r\n * to export charts in various formats (e.g. JPEG, PNG, PDF, SVG). It integrates\r\n * with Highcharts' core functionalities and supports both immediate download\r\n * responses and Base64-encoded content returns. The code also features\r\n * benchmarking for performance monitoring.\r\n */\r\n\r\nimport { startExport } from '../../chart.js';\r\nimport { log } from '../../logger.js';\r\nimport { getBase64, measureTime } from '../../utils.js';\r\n\r\nimport HttpError from '../../errors/HttpError.js';\r\n\r\n// Reversed MIME types\r\nconst reversedMime = {\r\n png: 'image/png',\r\n jpeg: 'image/jpeg',\r\n gif: 'image/gif',\r\n pdf: 'application/pdf',\r\n svg: 'image/svg+xml'\r\n};\r\n\r\n/**\r\n * Handles the export requests from the client.\r\n *\r\n * @async\r\n * @function requestExport\r\n *\r\n * @param {Express.Request} request - The Express request object.\r\n * @param {Express.Response} response - The Express response object.\r\n * @param {Function} next - The next middleware function.\r\n *\r\n * @returns {Promise} A Promise that resolves once the export process\r\n * is complete.\r\n */\r\nasync function requestExport(request, response, next) {\r\n try {\r\n // Start counting time for a request\r\n const requestCounter = measureTime();\r\n\r\n // In case the connection is closed, force to abort further actions\r\n let connectionAborted = false;\r\n request.socket.on('close', (hadErrors) => {\r\n if (hadErrors) {\r\n connectionAborted = true;\r\n }\r\n });\r\n\r\n // Get the options previously validated in the validation middleware\r\n const requestOptions = request.validatedOptions;\r\n\r\n // Get the request id\r\n const requestId = requestOptions._requestId;\r\n\r\n // Info about an incoming request with correct data\r\n log(4, `[export] Got an incoming HTTP request with ID ${requestId}.`);\r\n\r\n // Start the export process\r\n await startExport(requestOptions, (error, data) => {\r\n // Remove the close event from the socket\r\n request.socket.removeAllListeners('close');\r\n\r\n // If the connection was closed, do nothing\r\n if (connectionAborted) {\r\n log(\r\n 3,\r\n `[export] Request [${requestId}] - The client closed the connection before the chart finished processing.`\r\n );\r\n return;\r\n }\r\n\r\n // If error, log it and send it to the error middleware\r\n if (error) {\r\n throw error;\r\n }\r\n\r\n // If data is missing, log the message and send it to the error middleware\r\n if (!data || !data.result) {\r\n log(\r\n 2,\r\n `[export] Request [${requestId}] - Request from ${\r\n request.headers['x-forwarded-for'] ||\r\n request.connection.remoteAddress\r\n } was incorrect. Received result is ${data.result}.`\r\n );\r\n\r\n throw new HttpError(\r\n '[export] Unexpected return of the export result from the chart generation. Please check your request data.',\r\n 400\r\n );\r\n }\r\n\r\n // Return the result in an appropriate format\r\n if (data.result) {\r\n log(\r\n 3,\r\n `[export] Request [${requestId}] - The whole exporting process took ${requestCounter()}ms.`\r\n );\r\n\r\n // Get the `type`, `b64`, `noDownload`, and `outfile` from options\r\n const { type, b64, noDownload, outfile } = data.options.export;\r\n\r\n // If only Base64 is required, return it\r\n if (b64) {\r\n return response.send(getBase64(data.result, type));\r\n }\r\n\r\n // Set correct content type\r\n response.header('Content-Type', reversedMime[type] || 'image/png');\r\n\r\n // Decide whether to download or not chart file\r\n if (!noDownload) {\r\n response.attachment(outfile);\r\n }\r\n\r\n // If SVG, return plain content, otherwise a b64 string from a buffer\r\n return type === 'svg'\r\n ? response.send(data.result)\r\n : response.send(Buffer.from(data.result, 'base64'));\r\n }\r\n });\r\n } catch (error) {\r\n return next(error);\r\n }\r\n}\r\n\r\n/**\r\n * Adds the `export` routes.\r\n *\r\n * @function exportRoutes\r\n *\r\n * @param {Express} app - The Express app instance.\r\n */\r\nexport default function exportRoutes(app) {\r\n /**\r\n * Adds the POST '/' - A route for handling POST requests at the root\r\n * endpoint.\r\n */\r\n app.post('/', requestExport);\r\n\r\n /**\r\n * Adds the POST '/:filename' - A route for handling POST requests with\r\n * a specified filename parameter.\r\n */\r\n app.post('/:filename', requestExport);\r\n}\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * @overview Defines an Express route for server health monitoring, including\r\n * uptime, success rates, and other server statistics.\r\n */\r\n\r\nimport { readFileSync } from 'fs';\r\nimport { join } from 'path';\r\n\r\nimport { getHighchartsVersion } from '../../cache.js';\r\nimport { log } from '../../logger.js';\r\nimport { getPoolStats, getPoolInfoJSON } from '../../pool.js';\r\nimport { addTimer } from '../../timer.js';\r\nimport { __dirname, getNewDateTime } from '../../utils.js';\r\n\r\n// Set the start date of the server\r\nconst serverStartTime = new Date();\r\n\r\n// Get the `package.json` content\r\nconst packageFile = JSON.parse(readFileSync(join(__dirname, 'package.json')));\r\n\r\n// An array for success rate ratios\r\nconst successRates = [];\r\n\r\n// Record every minute\r\nconst recordInterval = 60 * 1000;\r\n\r\n// 30 minutes\r\nconst windowSize = 30;\r\n\r\n/**\r\n * Calculates moving average indicator based on the data from the `successRates`\r\n * array.\r\n *\r\n * @function _calculateMovingAverage\r\n *\r\n * @returns {number} A moving average for success ratio of the server exports.\r\n */\r\nfunction _calculateMovingAverage() {\r\n return successRates.reduce((a, b) => a + b, 0) / successRates.length;\r\n}\r\n\r\n/**\r\n * Starts the interval responsible for calculating current success rate ratio\r\n * and collects records to the `successRates` array.\r\n *\r\n * @function _startSuccessRate\r\n *\r\n * @returns {NodeJS.Timeout} Id of an interval.\r\n */\r\nfunction _startSuccessRate() {\r\n return setInterval(() => {\r\n const stats = getPoolStats();\r\n const successRatio =\r\n stats.exportsAttempted === 0\r\n ? 1\r\n : (stats.exportsPerformed / stats.exportsAttempted) * 100;\r\n\r\n successRates.push(successRatio);\r\n if (successRates.length > windowSize) {\r\n successRates.shift();\r\n }\r\n }, recordInterval);\r\n}\r\n\r\n/**\r\n * Adds the `health` routes.\r\n *\r\n * @function healthRoutes\r\n *\r\n * @param {Express} app - The Express app instance.\r\n */\r\nexport default function healthRoutes(app) {\r\n // Start processing success rate ratio interval and save its id to the array\r\n // for the graceful clearing on shutdown with injected `addTimer` funtion\r\n addTimer(_startSuccessRate());\r\n\r\n /**\r\n * Adds the GET '/health' - A route for getting the basic stats of the server.\r\n */\r\n app.get('/health', (request, response, next) => {\r\n try {\r\n log(4, '[health] Returning server health.');\r\n\r\n const stats = getPoolStats();\r\n const period = successRates.length;\r\n const movingAverage = _calculateMovingAverage();\r\n\r\n // Send the server's statistics\r\n response.send({\r\n // Status and times\r\n status: 'OK',\r\n bootTime: serverStartTime,\r\n uptime: `${Math.floor((getNewDateTime() - serverStartTime.getTime()) / 1000 / 60)} minutes`,\r\n\r\n // Versions\r\n serverVersion: packageFile.version,\r\n highchartsVersion: getHighchartsVersion(),\r\n\r\n // Exports\r\n averageExportTime: stats.timeSpentAverage,\r\n attemptedExports: stats.exportsAttempted,\r\n performedExports: stats.exportsPerformed,\r\n failedExports: stats.exportsDropped,\r\n sucessRatio: (stats.exportsPerformed / stats.exportsAttempted) * 100,\r\n\r\n // Pool\r\n pool: getPoolInfoJSON(),\r\n\r\n // Moving average\r\n period,\r\n movingAverage,\r\n message:\r\n isNaN(movingAverage) || !successRates.length\r\n ? 'Too early to report. No exports made yet. Please check back soon.'\r\n : `Last ${period} minutes had a success rate of ${movingAverage.toFixed(2)}%.`,\r\n\r\n // SVG and JSON exports\r\n svgExports: stats.exportsFromSvg,\r\n jsonExports: stats.exportsFromOptions,\r\n svgExportsAttempts: stats.exportsFromSvgAttempts,\r\n jsonExportsAttempts: stats.exportsFromOptionsAttempts\r\n });\r\n } catch (error) {\r\n return next(error);\r\n }\r\n });\r\n}\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * @overview Defines an Express route for serving the UI for the export server\r\n * when enabled.\r\n */\r\n\r\nimport { join } from 'path';\r\n\r\nimport { getOptions } from '../../config.js';\r\nimport { __dirname } from '../../utils.js';\r\n\r\n/**\r\n * Adds the `ui` routes.\r\n *\r\n * @function uiRoutes\r\n *\r\n * @param {Express} app - The Express app instance.\r\n */\r\nexport default function uiRoutes(app) {\r\n /**\r\n * Adds the GET '/' - A route for a UI when enabled on the export server.\r\n */\r\n app.get(getOptions().ui.route || '/', (request, response, next) => {\r\n try {\r\n response.sendFile(join(__dirname, 'public', 'index.html'), {\r\n acceptRanges: false\r\n });\r\n } catch (error) {\r\n return next(error);\r\n }\r\n });\r\n}\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * @overview Defines an Express route for updating the Highcharts version\r\n * on the server, with authentication and validation.\r\n */\r\n\r\nimport { updateHighchartsVersion, getHighchartsVersion } from '../../cache.js';\r\nimport { envs } from '../../envs.js';\r\n\r\nimport HttpError from '../../errors/HttpError.js';\r\n\r\n/**\r\n * Adds the `version_change` routes.\r\n *\r\n * @function versionChangeRoutes\r\n *\r\n * @param {Express} app - The Express app instance.\r\n */\r\nexport default function versionChangeRoutes(app) {\r\n /**\r\n * Adds the POST '/version_change/:newVersion' - A route for changing\r\n * the Highcharts version on the server.\r\n */\r\n app.post('/version_change/:newVersion', async (request, response, next) => {\r\n try {\r\n // Get the token directly from envs\r\n const adminToken = envs.HIGHCHARTS_ADMIN_TOKEN;\r\n\r\n // Check the existence of the token\r\n if (!adminToken || !adminToken.length) {\r\n throw new HttpError(\r\n '[version] The server is not configured to perform run-time version changes: HIGHCHARTS_ADMIN_TOKEN is not set.',\r\n 401\r\n );\r\n }\r\n\r\n // Get the token from the hc-auth header\r\n const token = request.get('hc-auth');\r\n\r\n // Check if the hc-auth header contain a correct token\r\n if (!token || token !== adminToken) {\r\n throw new HttpError(\r\n '[version] Invalid or missing token: Set the token in the hc-auth header.',\r\n 401\r\n );\r\n }\r\n\r\n // Compare versions\r\n const newVersion = request.params.newVersion;\r\n if (newVersion) {\r\n try {\r\n // Update version\r\n await updateHighchartsVersion(newVersion);\r\n } catch (error) {\r\n throw new HttpError(\r\n `[version] Version change: ${error.message}`,\r\n 400\r\n ).setError(error);\r\n }\r\n\r\n // Success\r\n response.status(200).send({\r\n statusCode: 200,\r\n highchartsVersion: getHighchartsVersion(),\r\n message: `Successfully updated Highcharts to version: ${newVersion}.`\r\n });\r\n } else {\r\n // No version specified\r\n throw new HttpError('[version] No new version supplied.', 400);\r\n }\r\n } catch (error) {\r\n return next(error);\r\n }\r\n });\r\n}\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * @overview A module that sets up and manages HTTP and HTTPS servers\r\n * for the Highcharts Export Server. It handles server initialization,\r\n * configuration, error handling, middleware setup, route definition, and rate\r\n * limiting. The module exports functions to start, stop, and manage server\r\n * instances, as well as utility functions for defining routes and attaching\r\n * middlewares.\r\n */\r\n\r\nimport { readFile } from 'fs/promises';\r\nimport { join } from 'path';\r\n\r\nimport cors from 'cors';\r\nimport express from 'express';\r\nimport http from 'http';\r\nimport https from 'https';\r\nimport multer from 'multer';\r\n\r\nimport { getOptions } from '../config.js';\r\nimport { log, logWithStack } from '../logger.js';\r\nimport { __dirname, getAbsolutePath } from '../utils.js';\r\n\r\nimport errorMiddleware from './middlewares/error.js';\r\nimport rateLimitingMiddleware from './middlewares/rateLimiting.js';\r\nimport validationMiddleware from './middlewares/validation.js';\r\n\r\nimport exportRoutes from './routes/export.js';\r\nimport healthRoutes from './routes/health.js';\r\nimport uiRoutes from './routes/ui.js';\r\nimport versionChangeRoutes from './routes/versionChange.js';\r\n\r\nimport ExportError from '../errors/ExportError.js';\r\n\r\n// Array of an active servers\r\nconst activeServers = new Map();\r\n\r\n// Create express app\r\nconst app = express();\r\n\r\n/**\r\n * Starts HTTP or/and HTTPS server based on the provided configuration.\r\n * The `serverOptions` object contains all server related properties (see\r\n * the `server` section in the `lib/schemas/config.js` file for a reference).\r\n *\r\n * @async\r\n * @function startServer\r\n *\r\n * @param {Object} [serverOptions=getOptions().server] - Object containing\r\n * `server` options. The default value is the global server options\r\n * of the export server instance.\r\n *\r\n * @returns {Promise} A Promise that resolves to ending the function\r\n * execution when the server should not be enabled or when no valid Express app\r\n * is found.\r\n *\r\n * @throws {ExportError} Throws an `ExportError` if the server cannot\r\n * be configured and started.\r\n */\r\nexport async function startServer(serverOptions = getOptions().server) {\r\n try {\r\n // Stop if not enabled\r\n if (!serverOptions.enable || !app) {\r\n throw new ExportError(\r\n '[server] Server cannot be started (not enabled or no correct Express app found).',\r\n 500\r\n );\r\n }\r\n\r\n // Too big limits lead to timeouts in the export process when\r\n // the rasterization timeout is set too low\r\n const uploadLimitBytes = serverOptions.uploadLimit * 1024 * 1024;\r\n\r\n // Memory storage for multer package\r\n const storage = multer.memoryStorage();\r\n\r\n // Enable parsing of form data (files) with multer package\r\n const upload = multer({\r\n storage,\r\n limits: {\r\n fieldSize: uploadLimitBytes\r\n }\r\n });\r\n\r\n // Disable the X-Powered-By header\r\n app.disable('x-powered-by');\r\n\r\n // Enable CORS support\r\n app.use(\r\n cors({\r\n methods: ['POST', 'GET', 'OPTIONS']\r\n })\r\n );\r\n\r\n // Getting a lot of `RangeNotSatisfiableError` exceptions (even though this\r\n // is a deprecated options, let's try to set it to false)\r\n app.use((request, response, next) => {\r\n response.set('Accept-Ranges', 'none');\r\n next();\r\n });\r\n\r\n // Enable body parser for JSON data\r\n app.use(\r\n express.json({\r\n limit: uploadLimitBytes\r\n })\r\n );\r\n\r\n // Enable body parser for URL-encoded form data\r\n app.use(\r\n express.urlencoded({\r\n extended: true,\r\n limit: uploadLimitBytes\r\n })\r\n );\r\n\r\n // Use only non-file multipart form fields\r\n app.use(upload.none());\r\n\r\n // Set up static folder's route\r\n app.use(express.static(join(__dirname, 'public')));\r\n\r\n // Listen HTTP server\r\n if (!serverOptions.ssl.force) {\r\n // Main server instance (HTTP)\r\n const httpServer = http.createServer(app);\r\n\r\n // Attach error handlers and listen to the server\r\n _attachServerErrorHandlers(httpServer);\r\n\r\n // Listen\r\n httpServer.listen(serverOptions.port, serverOptions.host, () => {\r\n // Save the reference to HTTP server\r\n activeServers.set(serverOptions.port, httpServer);\r\n\r\n log(\r\n 3,\r\n `[server] Started HTTP server on ${serverOptions.host}:${serverOptions.port}.`\r\n );\r\n });\r\n }\r\n\r\n // Listen HTTPS server\r\n if (serverOptions.ssl.enable) {\r\n // Set up an SSL server also\r\n let key, cert;\r\n\r\n try {\r\n // Get the SSL key\r\n key = await readFile(\r\n join(getAbsolutePath(serverOptions.ssl.certPath), 'server.key'),\r\n 'utf8'\r\n );\r\n\r\n // Get the SSL certificate\r\n cert = await readFile(\r\n join(getAbsolutePath(serverOptions.ssl.certPath), 'server.crt'),\r\n 'utf8'\r\n );\r\n } catch (error) {\r\n log(\r\n 2,\r\n `[server] Unable to load key/certificate from the '${serverOptions.ssl.certPath}' path. Could not run secured layer server.`\r\n );\r\n }\r\n\r\n if (key && cert) {\r\n // Main server instance (HTTPS)\r\n const httpsServer = https.createServer({ key, cert }, app);\r\n\r\n // Attach error handlers and listen to the server\r\n _attachServerErrorHandlers(httpsServer);\r\n\r\n // Listen\r\n httpsServer.listen(serverOptions.ssl.port, serverOptions.host, () => {\r\n // Save the reference to HTTPS server\r\n activeServers.set(serverOptions.ssl.port, httpsServer);\r\n\r\n log(\r\n 3,\r\n `[server] Started HTTPS server on ${serverOptions.host}:${serverOptions.ssl.port}.`\r\n );\r\n });\r\n }\r\n }\r\n\r\n // Set up the rate limiter\r\n rateLimitingMiddleware(app, serverOptions.rateLimiting);\r\n\r\n // Set up the validation handler\r\n validationMiddleware(app);\r\n\r\n // Set up routes\r\n healthRoutes(app);\r\n exportRoutes(app);\r\n uiRoutes(app);\r\n versionChangeRoutes(app);\r\n\r\n // Set up the centralized error handler\r\n errorMiddleware(app);\r\n } catch (error) {\r\n throw new ExportError(\r\n '[server] Could not configure and start the server.',\r\n 500\r\n ).setError(error);\r\n }\r\n}\r\n\r\n/**\r\n * Closes all servers associated with Express app instance.\r\n *\r\n * @function closeServers\r\n */\r\nexport function closeServers() {\r\n // Check if there are servers working\r\n if (activeServers.size > 0) {\r\n log(4, `[server] Closing all servers.`);\r\n\r\n // Close each one of servers\r\n for (const [port, server] of activeServers) {\r\n server.close(() => {\r\n activeServers.delete(port);\r\n log(4, `[server] Closed server on port: ${port}.`);\r\n });\r\n }\r\n }\r\n}\r\n\r\n/**\r\n * Get all servers associated with Express app instance.\r\n *\r\n * @function getServers\r\n *\r\n * @returns {Array.} Servers associated with Express app instance.\r\n */\r\nexport function getServers() {\r\n return activeServers;\r\n}\r\n\r\n/**\r\n * Get the Express instance.\r\n *\r\n * @function getExpress\r\n *\r\n * @returns {Express} The Express instance.\r\n */\r\nexport function getExpress() {\r\n return express;\r\n}\r\n\r\n/**\r\n * Get the Express app instance.\r\n *\r\n * @function getApp\r\n *\r\n * @returns {Express} The Express app instance.\r\n */\r\nexport function getApp() {\r\n return app;\r\n}\r\n\r\n/**\r\n * Enable rate limiting for the server.\r\n *\r\n * @function enableRateLimiting\r\n *\r\n * @param {Object} rateLimitingOptions - Object containing `rateLimiting`\r\n * options.\r\n */\r\nexport function enableRateLimiting(rateLimitingOptions) {\r\n rateLimitingMiddleware(app, rateLimitingOptions);\r\n}\r\n\r\n/**\r\n * Apply middleware(s) to a specific path.\r\n *\r\n * @function use\r\n *\r\n * @param {string} path - The path to which the middleware(s) should be applied.\r\n * @param {...Function} middlewares - The middleware function(s) to be applied.\r\n */\r\nexport function use(path, ...middlewares) {\r\n app.use(path, ...middlewares);\r\n}\r\n\r\n/**\r\n * Set up a route with GET method and apply middleware(s).\r\n *\r\n * @function get\r\n *\r\n * @param {string} path - The path to which the middleware(s) should be applied.\r\n * @param {...Function} middlewares - The middleware function(s) to be applied.\r\n */\r\nexport function get(path, ...middlewares) {\r\n app.get(path, ...middlewares);\r\n}\r\n\r\n/**\r\n * Set up a route with POST method and apply middleware(s).\r\n *\r\n * @function post\r\n *\r\n * @param {string} path - The path to which the middleware(s) should be applied.\r\n * @param {...Function} middlewares - The middleware function(s) to be applied.\r\n */\r\nexport function post(path, ...middlewares) {\r\n app.post(path, ...middlewares);\r\n}\r\n\r\n/**\r\n * Attach error handlers to the server.\r\n *\r\n * @function _attachServerErrorHandlers\r\n *\r\n * @param {(http.Server|https.Server)} server - The HTTP/HTTPS server instance.\r\n */\r\nfunction _attachServerErrorHandlers(server) {\r\n server.on('clientError', (error, socket) => {\r\n logWithStack(\r\n 1,\r\n error,\r\n `[server] Client error: ${error.message}, destroying socket.`\r\n );\r\n socket.destroy();\r\n });\r\n\r\n server.on('error', (error) => {\r\n logWithStack(1, error, `[server] Server error: ${error.message}`);\r\n });\r\n\r\n server.on('connection', (socket) => {\r\n socket.on('error', (error) => {\r\n logWithStack(1, error, `[server] Socket error: ${error.message}`);\r\n });\r\n });\r\n}\r\n\r\nexport default {\r\n startServer,\r\n closeServers,\r\n getServers,\r\n getExpress,\r\n getApp,\r\n enableRateLimiting,\r\n use,\r\n get,\r\n post\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * @overview Handles graceful shutdown of the Highcharts Export Server, ensuring\r\n * proper cleanup of resources such as browser, pages, servers, and timers.\r\n */\r\n\r\nimport { killPool } from './pool.js';\r\nimport { clearAllTimers } from './timer.js';\r\nimport { closeServers } from './server/server.js';\r\n\r\n/**\r\n * Cleans up function to trigger before ending process for the graceful\r\n * shutdown.\r\n *\r\n * @function shutdownCleanUp\r\n *\r\n * @param {number} exitCode - An exit code for the `process.exit()` function.\r\n */\r\nexport async function shutdownCleanUp(exitCode) {\r\n // Await freeing all resources\r\n await Promise.allSettled([\r\n // Clear all ongoing intervals\r\n clearAllTimers(),\r\n\r\n // Get available server instances (HTTP/HTTPS) and close them\r\n closeServers(),\r\n\r\n // Close an active pool along with its workers and the browser instance\r\n killPool()\r\n ]);\r\n\r\n // Exit process with a correct code\r\n process.exit(exitCode);\r\n}\r\n\r\nexport default {\r\n shutdownCleanUp\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * @overview Core module for initializing and managing the Highcharts Export\r\n * Server. Provides functionalities for configuring exports, setting up server\r\n * operations, logging, scripts caching, resource pooling, and graceful process\r\n * cleanup.\r\n */\r\n\r\nimport 'colors';\r\n\r\nimport { checkAndUpdateCache } from './cache.js';\r\nimport {\r\n singleExport,\r\n batchExport,\r\n startExport,\r\n setAllowCodeExecution\r\n} from './chart.js';\r\nimport {\r\n getOptions,\r\n setOptions,\r\n mergeOptions,\r\n mapToNewOptions\r\n} from './config.js';\r\nimport {\r\n log,\r\n logWithStack,\r\n initLogging,\r\n setLogLevel,\r\n enableConsoleLogging,\r\n enableFileLogging\r\n} from './logger.js';\r\nimport { initPool, killPool } from './pool.js';\r\nimport { shutdownCleanUp } from './resourceRelease.js';\r\nimport server, { startServer } from './server/server.js';\r\n\r\n/**\r\n * Initializes the export process. Tasks such as configuring logging, checking\r\n * the cache and sources, and initializing the resource pool occur during this\r\n * stage. This function must be called before attempting to export charts or set\r\n * up a server.\r\n *\r\n * @async\r\n * @function initExport\r\n *\r\n * @param {Object} customOptions - The `customOptions` object, which may\r\n * be a partial or complete set of options. If the provided options are partial,\r\n * missing values will be merged with the default general options, retrieved\r\n * using the `getOptions` function.\r\n */\r\nexport async function initExport(customOptions) {\r\n // Get the global options object copy and extend it with the incoming options\r\n const options = mergeOptions(getOptions(false), customOptions);\r\n\r\n // Set the `allowCodeExecution` per export module scope\r\n setAllowCodeExecution(options.customLogic.allowCodeExecution);\r\n\r\n // Init the logging\r\n initLogging(options.logging);\r\n\r\n // Attach process' exit listeners\r\n if (options.other.listenToProcessExits) {\r\n _attachProcessExitListeners();\r\n }\r\n\r\n // Check if cache needs to be updated\r\n await checkAndUpdateCache(options.highcharts, options.server.proxy);\r\n\r\n // Init the pool\r\n await initPool(options.pool, options.puppeteer.args);\r\n}\r\n\r\n/**\r\n * Attaches exit listeners to the process, ensuring proper cleanup of resources\r\n * and termination on exit signals. Handles 'exit', 'SIGINT', 'SIGTERM'\r\n * and 'uncaughtException' events.\r\n *\r\n * @function _attachProcessExitListeners\r\n */\r\nfunction _attachProcessExitListeners() {\r\n log(3, '[process] Attaching exit listeners to the process.');\r\n\r\n // Handler for the 'exit'\r\n process.on('exit', (code) => {\r\n log(4, `[process] Process exited with code ${code}.`);\r\n });\r\n\r\n // Handler for the 'SIGINT'\r\n process.on('SIGINT', async (name, code) => {\r\n log(4, `[process] The ${name} event with code: ${code}.`);\r\n await shutdownCleanUp(0);\r\n });\r\n\r\n // Handler for the 'SIGTERM'\r\n process.on('SIGTERM', async (name, code) => {\r\n log(4, `[process] The ${name} event with code: ${code}.`);\r\n await shutdownCleanUp(0);\r\n });\r\n\r\n // Handler for the 'SIGHUP'\r\n process.on('SIGHUP', async (name, code) => {\r\n log(4, `[process] The ${name} event with code: ${code}.`);\r\n await shutdownCleanUp(0);\r\n });\r\n\r\n // Handler for the 'uncaughtException'\r\n process.on('uncaughtException', async (error, name) => {\r\n logWithStack(1, error, `[process] The ${name} error.`);\r\n await shutdownCleanUp(1);\r\n });\r\n}\r\n\r\nexport default {\r\n // Server\r\n server,\r\n startServer,\r\n\r\n // Options\r\n getOptions,\r\n setOptions,\r\n mergeOptions,\r\n mapToNewOptions,\r\n\r\n // Exporting\r\n initExport,\r\n singleExport,\r\n batchExport,\r\n startExport,\r\n\r\n // Cache\r\n checkAndUpdateCache,\r\n\r\n // Pool\r\n initPool,\r\n killPool,\r\n\r\n // Logs\r\n log,\r\n logWithStack,\r\n setLogLevel,\r\n enableConsoleLogging,\r\n enableFileLogging,\r\n\r\n // Utils\r\n shutdownCleanUp\r\n};\r\n"],"names":["__dirname","fileURLToPath","URL","url","deepCopy","objArr","objArrCopy","Array","isArray","key","Object","prototype","hasOwnProperty","call","fixConstr","constr","fixedConstr","toLowerCase","replace","includes","fixOutfile","type","outfile","getAbsolutePath","split","shift","fixType","mimeTypes","formats","values","outType","pop","find","t","path","isAbsolute","join","getBase64","input","Buffer","from","toString","getNewDate","Date","trim","getNewDateTime","getTime","isObject","item","isObjectEmpty","keys","length","isPrivateRangeUrlFound","some","pattern","test","measureTime","start","process","hrtime","bigint","Number","roundNumber","value","precision","multiplier","Math","pow","round","wrapAround","customCode","allowFileResources","isCallback","endsWith","readFileSync","startsWith","colors","logging","toConsole","toFile","pathCreated","pathToLog","levelsDesc","title","color","log","args","newLevel","texts","level","prefix","_logToFile","console","apply","undefined","concat","logWithStack","error","customMessage","mainMessage","message","stackMessage","stack","push","initLogging","loggingOptions","dest","file","setLogLevel","enableConsoleLogging","enableFileLogging","existsSync","mkdirSync","appendFile","defaultConfig","puppeteer","types","envLink","cliName","description","promptOptions","separator","highcharts","version","cdnUrl","forceFetch","cachePath","coreScripts","instructions","moduleScripts","indicatorScripts","customScripts","export","infile","instr","options","svg","batch","hint","choices","b64","noDownload","height","width","scale","defaultHeight","defaultWidth","defaultScale","min","max","globalOptions","themeOptions","rasterizationTimeout","customLogic","allowCodeExecution","callback","resources","loadConfig","legacyName","createConfig","server","enable","host","port","uploadLimit","benchmarking","proxy","timeout","rateLimiting","maxRequests","window","delay","trustProxy","skipKey","skipToken","ssl","force","certPath","pool","minWorkers","maxWorkers","workLimit","acquireTimeout","createTimeout","destroyTimeout","idleTimeout","createRetryInterval","reaperInterval","ui","route","other","nodeEnv","listenToProcessExits","noLogo","hardResetPage","browserShellMode","debug","headless","devtools","listenToConsole","dumpio","slowMo","debuggingPort","nestedProps","_createNestedProps","absoluteProps","_createAbsoluteProps","config","propChain","forEach","entry","substring","dotenv","v","array","filterArray","z","string","transform","map","filter","boolean","enum","refine","positiveNum","isNaN","parseFloat","nonNegativeNum","Config","object","PUPPETEER_ARGS","HIGHCHARTS_VERSION","HIGHCHARTS_CDN_URL","HIGHCHARTS_FORCE_FETCH","HIGHCHARTS_CACHE_PATH","HIGHCHARTS_ADMIN_TOKEN","HIGHCHARTS_CORE_SCRIPTS","HIGHCHARTS_MODULE_SCRIPTS","HIGHCHARTS_INDICATOR_SCRIPTS","HIGHCHARTS_CUSTOM_SCRIPTS","EXPORT_INFILE","EXPORT_INSTR","EXPORT_OPTIONS","EXPORT_SVG","EXPORT_BATCH","EXPORT_OUTFILE","EXPORT_TYPE","EXPORT_CONSTR","EXPORT_B64","EXPORT_NO_DOWNLOAD","EXPORT_HEIGHT","EXPORT_WIDTH","EXPORT_SCALE","EXPORT_DEFAULT_HEIGHT","EXPORT_DEFAULT_WIDTH","EXPORT_DEFAULT_SCALE","EXPORT_GLOBAL_OPTIONS","EXPORT_THEME_OPTIONS","EXPORT_RASTERIZATION_TIMEOUT","CUSTOM_LOGIC_ALLOW_CODE_EXECUTION","CUSTOM_LOGIC_ALLOW_FILE_RESOURCES","CUSTOM_LOGIC_CUSTOM_CODE","CUSTOM_LOGIC_CALLBACK","CUSTOM_LOGIC_RESOURCES","CUSTOM_LOGIC_LOAD_CONFIG","CUSTOM_LOGIC_CREATE_CONFIG","SERVER_ENABLE","SERVER_HOST","SERVER_PORT","SERVER_UPLOAD_LIMIT","SERVER_BENCHMARKING","SERVER_PROXY_HOST","SERVER_PROXY_PORT","SERVER_PROXY_TIMEOUT","SERVER_RATE_LIMITING_ENABLE","SERVER_RATE_LIMITING_MAX_REQUESTS","SERVER_RATE_LIMITING_WINDOW","SERVER_RATE_LIMITING_DELAY","SERVER_RATE_LIMITING_TRUST_PROXY","SERVER_RATE_LIMITING_SKIP_KEY","SERVER_RATE_LIMITING_SKIP_TOKEN","SERVER_SSL_ENABLE","SERVER_SSL_FORCE","SERVER_SSL_PORT","SERVER_SSL_CERT_PATH","POOL_MIN_WORKERS","POOL_MAX_WORKERS","POOL_WORK_LIMIT","POOL_ACQUIRE_TIMEOUT","POOL_CREATE_TIMEOUT","POOL_DESTROY_TIMEOUT","POOL_IDLE_TIMEOUT","POOL_CREATE_RETRY_INTERVAL","POOL_REAPER_INTERVAL","POOL_BENCHMARKING","LOGGING_LEVEL","LOGGING_FILE","LOGGING_DEST","LOGGING_TO_CONSOLE","LOGGING_TO_FILE","UI_ENABLE","UI_ROUTE","OTHER_NODE_ENV","OTHER_LISTEN_TO_PROCESS_EXITS","OTHER_NO_LOGO","OTHER_HARD_RESET_PAGE","OTHER_BROWSER_SHELL_MODE","DEBUG_ENABLE","DEBUG_HEADLESS","DEBUG_DEVTOOLS","DEBUG_LISTEN_TO_CONSOLE","DEBUG_DUMPIO","DEBUG_SLOW_MO","DEBUG_DEBUGGING_PORT","envs","partial","parse","env","_initGlobalOptions","getOptions","getReference","setOptions","customOptions","cliArgs","modifyGlobal","configOptions","cliOptions","_loadConfigFile","_pairArgumentValue","generalOptions","_updateOptions","mergeOptions","originalOptions","newOptions","entries","mapToNewOptions","oldOptions","propertiesChain","reduce","obj","prop","index","isAllowedConfig","allowFunctions","objectConfig","eval","JSON","stringifiedOptions","_optionsStringify","parsedOptions","_","name","configOpt","customOpt","cliOpt","configVal","customVal","cliVal","envVal","stringifyFunctions","stringify","replaceAll","Error","configIndex","findIndex","arg","configFileName","i","option","async","fetch","requestOptions","Promise","resolve","reject","_getProtocolModule","get","response","responseData","on","chunk","text","https","http","ExportError","constructor","statusCode","super","this","setError","cache","activeManifest","sources","hcVersion","checkAndUpdateCache","highchartsOptions","serverProxyOptions","fetchedModules","getCachePath","manifestPath","sourcePath","recursive","_updateCache","requestUpdate","manifest","modules","moduleMap","m","numberOfModules","moduleName","extractVersion","_saveConfigToManifest","getHighchartsVersion","updateHighchartsVersion","newVersion","cacheSources","indexOf","extractModuleName","scriptPath","_fetchAndProcessScript","script","shouldThrowError","newManifest","writeFileSync","_fetchScripts","proxyAgent","proxyHost","proxyPort","HttpsProxyAgent","agent","allFetchPromises","all","c","setupHighcharts","Highcharts","animObject","duration","createChart","merge","wrap","setOptionsObj","isRenderComplete","Chart","proceed","userOptions","cb","exporting","enabled","plotOptions","series","label","tooltip","animation","onHighchartsRender","addEvent","Series","chart","additionalOptions","Function","finalOptions","finalCallback","defaultOptions","template","browser","createBrowser","puppeteerArgs","enabledDebug","debugOptions","launchOptions","userDataDir","handleSIGINT","handleSIGTERM","handleSIGHUP","waitForInitialPage","defaultViewport","tryCount","open","launch","setTimeout","closeBrowser","connected","close","newPage","poolResource","page","setCacheEnabled","_setPageContent","_setPageEvents","isClosed","clearPage","hardReset","goto","waitUntil","evaluate","document","body","innerHTML","id","workCount","addPageResources","customLogicOptions","injectedResources","injectedJs","js","content","files","isLocal","jsResource","addScriptTag","injectedCss","css","cssImports","match","cssImportPath","cssResource","addStyleTag","clearPageResources","resource","dispose","oldCharts","charts","oldChart","destroy","scriptsToRemove","getElementsByTagName","stylesToRemove","linksToRemove","element","remove","setContent","cssTemplate","svgTemplate","puppeteerExport","exportOptions","isSVG","_setAsSvg","_setAsOptions","size","svgElement","querySelector","chartHeight","baseVal","chartWidth","style","zoom","margin","x","y","_getClipRegion","viewportHeight","abs","ceil","viewportWidth","result","setViewport","deviceScaleFactor","_createSVG","_createImage","_createPDF","$eval","getBoundingClientRect","trunc","outerHTML","clip","race","screenshot","encoding","fullPage","optimizeForSpeed","captureBeyondViewport","quality","omitBackground","_resolve","emulateMediaType","pdf","poolStats","exportsAttempted","exportsPerformed","exportsDropped","exportsFromSvg","exportsFromOptions","exportsFromSvgAttempts","exportsFromOptionsAttempts","timeSpent","timeSpentAverage","initPool","poolOptions","Pool","_factory","acquireTimeoutMillis","createTimeoutMillis","destroyTimeoutMillis","idleTimeoutMillis","createRetryIntervalMillis","reapIntervalMillis","propagateCreateError","clearStatus","_eventId","initialResources","acquire","promise","release","killPool","worker","used","destroyed","postWork","workerHandle","getPoolInfo","acquireCounter","_requestId","workStart","exportCounter","exportTime","getPoolStats","getPoolInfoJSON","numUsed","available","numFree","allCreated","pendingAcquires","numPendingAcquires","pendingCreates","numPendingCreates","pendingValidations","numPendingValidations","pendingDestroys","absoluteAll","create","uuid","random","startDate","validate","mainFrame","detached","removeAllListeners","sanitize","JSDOM","DOMPurify","ADD_TAGS","singleExport","startExport","data","batchExport","batchFunctions","pair","batchResults","allSettled","reason","endCallback","fileContent","_exportFromSvg","_exportFromOptions","getAllowCodeExecution","setAllowCodeExecution","inputToExport","_prepareExport","_handleCustomLogic","_handleGlobalAndTheme","_findChartSize","optionsChart","optionsExporting","globalOptionsChart","globalOptionsExporting","themeOptionsChart","themeOptionsExporting","sourceHeight","sourceWidth","param","_handleResources","allowedProps","handledResources","correctResources","propName","optionsName","timerIds","addTimer","clearAllTimers","clearInterval","clearTimeout","logErrorMiddleware","request","next","returnErrorMiddleware","status","json","errorMiddleware","app","use","rateLimitingMiddleware","rateLimitingOptions","msg","rateOptions","limiter","rateLimit","windowMs","delayMs","handler","format","send","default","skip","query","access_token","HttpError","setStatus","contentTypeMiddleware","contentType","headers","requestBodyMiddleware","requestId","connection","remoteAddress","validatedOptions","params","filename","validationMiddleware","post","reversedMime","png","jpeg","gif","requestExport","requestCounter","connectionAborted","socket","hadErrors","header","attachment","exportRoutes","serverStartTime","packageFile","successRates","recordInterval","windowSize","_calculateMovingAverage","a","b","_startSuccessRate","setInterval","stats","successRatio","healthRoutes","period","movingAverage","bootTime","uptime","floor","serverVersion","highchartsVersion","averageExportTime","attemptedExports","performedExports","failedExports","sucessRatio","toFixed","svgExports","jsonExports","svgExportsAttempts","jsonExportsAttempts","uiRoutes","sendFile","acceptRanges","versionChangeRoutes","adminToken","token","activeServers","Map","express","startServer","serverOptions","uploadLimitBytes","storage","multer","memoryStorage","upload","limits","fieldSize","disable","cors","methods","set","limit","urlencoded","extended","none","static","httpServer","createServer","_attachServerErrorHandlers","listen","cert","readFile","httpsServer","closeServers","delete","getServers","getExpress","getApp","enableRateLimiting","middlewares","shutdownCleanUp","exitCode","exit","initExport","_attachProcessExitListeners","code"],"mappings":"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B,GAGP,CCrOO,MAAMiB,cAAgB,CAC3BC,UAAW,CACT7B,KAAM,CACJvB,MAAO,CACL,mCACA,kBACA,0CACA,2BACA,kCACA,kCACA,wCACA,2CACA,qBACA,4BACA,2CACA,uDACA,6BACA,yBACA,0BACA,+BACA,uBACA,uFACA,yBACA,oCACA,oBACA,0BACA,8CACA,2BACA,0BACA,6BACA,mCACA,wCACA,mCACA,2BACA,kCACA,uBACA,iBACA,yBACA,8BACA,oBACA,2BACA,eACA,6BACA,iBACA,aACA,eACA,sBACA,cACA,yBACA,oBACA,uBAEFqD,MAAO,CAAC,YACRC,QAAS,iBACTC,QAAS,gBACTC,YAAa,+BACbC,cAAe,CACbnG,KAAM,OACNoG,UAAW,OAIjBC,WAAY,CACVC,QAAS,CACP5D,MAAO,SACPqD,MAAO,CAAC,UACRC,QAAS,qBACTE,YAAa,qBACbC,cAAe,CACbnG,KAAM,SAGVuG,OAAQ,CACN7D,MAAO,8BACPqD,MAAO,CAAC,UACRC,QAAS,qBACTE,YAAa,iCACbC,cAAe,CACbnG,KAAM,SAGVwG,WAAY,CACV9D,OAAO,EACPqD,MAAO,CAAC,WACRC,QAAS,yBACTE,YAAa,kDACbC,cAAe,CACbnG,KAAM,WAGVyG,UAAW,CACT/D,MAAO,SACPqD,MAAO,CAAC,UACRC,QAAS,wBACTE,YAAa,+CACbC,cAAe,CACbnG,KAAM,SAGV0G,YAAa,CACXhE,MAAO,CAAC,aAAc,kBAAmB,iBACzCqD,MAAO,CAAC,YACRC,QAAS,0BACTE,YAAa,mCACbC,cAAe,CACbnG,KAAM,cACN2G,aAAc,0DAGlBC,cAAe,CACblE,MAAO,CACL,QACA,MACA,QACA,YACA,uBACA,gBAEA,eACA,QACA,OACA,aACA,mBACA,eACA,cACA,UACA,UACA,cACA,WACA,UACA,YACA,cACA,YACA,sBACA,SACA,SACA,WACA,aACA,YACA,eACA,yBACA,SACA,eACA,YACA,kBACA,SACA,cACA,mBACA,eACA,kBACA,cACA,eAEA,cACA,WACA,eACA,WACA,SACA,OACA,WACA,YACA,SACA,qBACA,aACA,WACA,WACA,WACA,WACA,eACA,UACA,kBACA,oBACA,aACA,UACA,cACA,YACA,YAEFqD,MAAO,CAAC,YACRC,QAAS,4BACTE,YAAa,qCACbC,cAAe,CACbnG,KAAM,cACN2G,aAAc,0DAGlBE,iBAAkB,CAChBnE,MAAO,CAAC,kBACRqD,MAAO,CAAC,YACRC,QAAS,+BACTE,YAAa,wCACbC,cAAe,CACbnG,KAAM,cACN2G,aAAc,0DAGlBG,cAAe,CACbpE,MAAO,CACL,wEACA,kGAEFqD,MAAO,CAAC,YACRC,QAAS,4BACTE,YAAa,qDACbC,cAAe,CACbnG,KAAM,OACNoG,UAAW,OAIjBW,OAAQ,CACNC,OAAQ,CACNtE,MAAO,KACPqD,MAAO,CAAC,SAAU,QAClBC,QAAS,gBACTE,YACE,+DACFC,cAAe,CACbnG,KAAM,SAGViH,MAAO,CACLvE,MAAO,KACPqD,MAAO,CAAC,SAAU,QAClBC,QAAS,eACTE,YACE,mEACFC,cAAe,CACbnG,KAAM,SAGVkH,QAAS,CACPxE,MAAO,KACPqD,MAAO,CAAC,SAAU,QAClBC,QAAS,iBACTE,YAAa,+BACbC,cAAe,CACbnG,KAAM,SAGVmH,IAAK,CACHzE,MAAO,KACPqD,MAAO,CAAC,SAAU,QAClBC,QAAS,aACTE,YAAa,mDACbC,cAAe,CACbnG,KAAM,SAGVoH,MAAO,CACL1E,MAAO,KACPqD,MAAO,CAAC,SAAU,QAClBC,QAAS,eACTE,YACE,gEACFC,cAAe,CACbnG,KAAM,SAGVC,QAAS,CACPyC,MAAO,KACPqD,MAAO,CAAC,SAAU,QAClBC,QAAS,iBACTE,YACE,qFACFC,cAAe,CACbnG,KAAM,SAGVA,KAAM,CACJ0C,MAAO,MACPqD,MAAO,CAAC,UACRC,QAAS,cACTE,YAAa,oDACbC,cAAe,CACbnG,KAAM,SACNqH,KAAM,eACNC,QAAS,CAAC,MAAO,OAAQ,MAAO,SAGpC5H,OAAQ,CACNgD,MAAO,QACPqD,MAAO,CAAC,UACRC,QAAS,gBACTE,YACE,uEACFC,cAAe,CACbnG,KAAM,SACNqH,KAAM,iBACNC,QAAS,CAAC,QAAS,aAAc,WAAY,gBAGjDC,IAAK,CACH7E,OAAO,EACPqD,MAAO,CAAC,WACRC,QAAS,aACTE,YACE,oFACFC,cAAe,CACbnG,KAAM,WAGVwH,WAAY,CACV9E,OAAO,EACPqD,MAAO,CAAC,WACRC,QAAS,qBACTE,YACE,0EACFC,cAAe,CACbnG,KAAM,WAGVyH,OAAQ,CACN/E,MAAO,KACPqD,MAAO,CAAC,SAAU,QAClBC,QAAS,gBACTE,YAAa,yDACbC,cAAe,CACbnG,KAAM,WAGV0H,MAAO,CACLhF,MAAO,KACPqD,MAAO,CAAC,SAAU,QAClBC,QAAS,eACTE,YAAa,wDACbC,cAAe,CACbnG,KAAM,WAGV2H,MAAO,CACLjF,MAAO,KACPqD,MAAO,CAAC,SAAU,QAClBC,QAAS,eACTE,YACE,gFACFC,cAAe,CACbnG,KAAM,WAGV4H,cAAe,CACblF,MAAO,IACPqD,MAAO,CAAC,UACRC,QAAS,wBACTE,YAAa,kDACbC,cAAe,CACbnG,KAAM,WAGV6H,aAAc,CACZnF,MAAO,IACPqD,MAAO,CAAC,UACRC,QAAS,uBACTE,YAAa,iDACbC,cAAe,CACbnG,KAAM,WAGV8H,aAAc,CACZpF,MAAO,EACPqD,MAAO,CAAC,UACRC,QAAS,uBACTE,YACE,yEACFC,cAAe,CACbnG,KAAM,SACN+H,IAAK,GACLC,IAAK,IAGTC,cAAe,CACbvF,MAAO,KACPqD,MAAO,CAAC,SAAU,SAAU,QAC5BC,QAAS,wBACTE,YACE,mFACFC,cAAe,CACbnG,KAAM,SAGVkI,aAAc,CACZxF,MAAO,KACPqD,MAAO,CAAC,SAAU,SAAU,QAC5BC,QAAS,uBACTE,YACE,kFACFC,cAAe,CACbnG,KAAM,SAGVmI,qBAAsB,CACpBzF,MAAO,KACPqD,MAAO,CAAC,UACRC,QAAS,+BACTE,YAAa,6CACbC,cAAe,CACbnG,KAAM,YAIZoI,YAAa,CACXC,mBAAoB,CAClB3F,OAAO,EACPqD,MAAO,CAAC,WACRC,QAAS,oCACTE,YACE,mEACFC,cAAe,CACbnG,KAAM,WAGVkD,mBAAoB,CAClBR,OAAO,EACPqD,MAAO,CAAC,WACRC,QAAS,oCACTE,YACE,kFACFC,cAAe,CACbnG,KAAM,WAGViD,WAAY,CACVP,MAAO,KACPqD,MAAO,CAAC,SAAU,QAClBC,QAAS,2BACTE,YACE,uHACFC,cAAe,CACbnG,KAAM,SAGVsI,SAAU,CACR5F,MAAO,KACPqD,MAAO,CAAC,SAAU,QAClBC,QAAS,wBACTE,YACE,kFACFC,cAAe,CACbnG,KAAM,SAGVuI,UAAW,CACT7F,MAAO,KACPqD,MAAO,CAAC,SAAU,SAAU,QAC5BC,QAAS,yBACTE,YACE,sGACFC,cAAe,CACbnG,KAAM,SAGVwI,WAAY,CACV9F,MAAO,KACPqD,MAAO,CAAC,SAAU,QAClBC,QAAS,2BACTyC,WAAY,WACZvC,YAAa,+CACbC,cAAe,CACbnG,KAAM,SAGV0I,aAAc,CACZhG,MAAO,KACPqD,MAAO,CAAC,SAAU,QAClBC,QAAS,6BACTE,YACE,+DACFC,cAAe,CACbnG,KAAM,UAIZ2I,OAAQ,CACNC,OAAQ,CACNlG,OAAO,EACPqD,MAAO,CAAC,WACRC,QAAS,gBACTC,QAAS,eACTC,YAAa,8BACbC,cAAe,CACbnG,KAAM,WAGV6I,KAAM,CACJnG,MAAO,UACPqD,MAAO,CAAC,UACRC,QAAS,cACTE,YAAa,yBACbC,cAAe,CACbnG,KAAM,SAGV8I,KAAM,CACJpG,MAAO,KACPqD,MAAO,CAAC,UACRC,QAAS,cACTE,YAAa,6BACbC,cAAe,CACbnG,KAAM,WAGV+I,YAAa,CACXrG,MAAO,EACPqD,MAAO,CAAC,UACRC,QAAS,sBACTE,YAAa,kCACbC,cAAe,CACbnG,KAAM,WAGVgJ,aAAc,CACZtG,OAAO,EACPqD,MAAO,CAAC,WACRC,QAAS,sBACTC,QAAS,qBACTC,YACE,0EACFC,cAAe,CACbnG,KAAM,WAGViJ,MAAO,CACLJ,KAAM,CACJnG,MAAO,KACPqD,MAAO,CAAC,SAAU,QAClBC,QAAS,oBACTC,QAAS,YACTC,YAAa,0CACbC,cAAe,CACbnG,KAAM,SAGV8I,KAAM,CACJpG,MAAO,KACPqD,MAAO,CAAC,SAAU,QAClBC,QAAS,oBACTC,QAAS,YACTC,YAAa,0CACbC,cAAe,CACbnG,KAAM,WAGVkJ,QAAS,CACPxG,MAAO,IACPqD,MAAO,CAAC,UACRC,QAAS,uBACTC,QAAS,eACTC,YACE,8DACFC,cAAe,CACbnG,KAAM,YAIZmJ,aAAc,CACZP,OAAQ,CACNlG,OAAO,EACPqD,MAAO,CAAC,WACRC,QAAS,8BACTC,QAAS,qBACTC,YAAa,kDACbC,cAAe,CACbnG,KAAM,WAGVoJ,YAAa,CACX1G,MAAO,GACPqD,MAAO,CAAC,UACRC,QAAS,oCACTyC,WAAY,YACZvC,YAAa,gDACbC,cAAe,CACbnG,KAAM,WAGVqJ,OAAQ,CACN3G,MAAO,EACPqD,MAAO,CAAC,UACRC,QAAS,8BACTE,YAAa,2CACbC,cAAe,CACbnG,KAAM,WAGVsJ,MAAO,CACL5G,MAAO,EACPqD,MAAO,CAAC,UACRC,QAAS,6BACTE,YACE,uEACFC,cAAe,CACbnG,KAAM,WAGVuJ,WAAY,CACV7G,OAAO,EACPqD,MAAO,CAAC,WACRC,QAAS,mCACTE,YAAa,sDACbC,cAAe,CACbnG,KAAM,WAGVwJ,QAAS,CACP9G,MAAO,KACPqD,MAAO,CAAC,SAAU,QAClBC,QAAS,gCACTE,YAAa,wDACbC,cAAe,CACbnG,KAAM,SAGVyJ,UAAW,CACT/G,MAAO,KACPqD,MAAO,CAAC,SAAU,QAClBC,QAAS,kCACTE,YAAa,wDACbC,cAAe,CACbnG,KAAM,UAIZ0J,IAAK,CACHd,OAAQ,CACNlG,OAAO,EACPqD,MAAO,CAAC,WACRC,QAAS,oBACTC,QAAS,YACTC,YAAa,mCACbC,cAAe,CACbnG,KAAM,WAGV2J,MAAO,CACLjH,OAAO,EACPqD,MAAO,CAAC,WACRC,QAAS,mBACTC,QAAS,WACTwC,WAAY,UACZvC,YAAa,gDACbC,cAAe,CACbnG,KAAM,WAGV8I,KAAM,CACJpG,MAAO,IACPqD,MAAO,CAAC,UACRC,QAAS,kBACTC,QAAS,UACTC,YAAa,0BACbC,cAAe,CACbnG,KAAM,WAGV4J,SAAU,CACRlH,MAAO,KACPqD,MAAO,CAAC,SAAU,QAClBC,QAAS,uBACTC,QAAS,cACTwC,WAAY,UACZvC,YAAa,uCACbC,cAAe,CACbnG,KAAM,WAKd6J,KAAM,CACJC,WAAY,CACVpH,MAAO,EACPqD,MAAO,CAAC,UACRC,QAAS,mBACTE,YAAa,sDACbC,cAAe,CACbnG,KAAM,WAGV+J,WAAY,CACVrH,MAAO,EACPqD,MAAO,CAAC,UACRC,QAAS,mBACTyC,WAAY,UACZvC,YAAa,0CACbC,cAAe,CACbnG,KAAM,WAGVgK,UAAW,CACTtH,MAAO,GACPqD,MAAO,CAAC,UACRC,QAAS,kBACTE,YAAa,wDACbC,cAAe,CACbnG,KAAM,WAGViK,eAAgB,CACdvH,MAAO,IACPqD,MAAO,CAAC,UACRC,QAAS,uBACTE,YAAa,mDACbC,cAAe,CACbnG,KAAM,WAGVkK,cAAe,CACbxH,MAAO,IACPqD,MAAO,CAAC,UACRC,QAAS,sBACTE,YAAa,kDACbC,cAAe,CACbnG,KAAM,WAGVmK,eAAgB,CACdzH,MAAO,IACPqD,MAAO,CAAC,UACRC,QAAS,uBACTE,YAAa,oDACbC,cAAe,CACbnG,KAAM,WAGVoK,YAAa,CACX1H,MAAO,IACPqD,MAAO,CAAC,UACRC,QAAS,oBACTE,YAAa,wDACbC,cAAe,CACbnG,KAAM,WAGVqK,oBAAqB,CACnB3H,MAAO,IACPqD,MAAO,CAAC,UACRC,QAAS,6BACTE,YACE,wEACFC,cAAe,CACbnG,KAAM,WAGVsK,eAAgB,CACd5H,MAAO,IACPqD,MAAO,CAAC,UACRC,QAAS,uBACTE,YACE,+DACFC,cAAe,CACbnG,KAAM,WAGVgJ,aAAc,CACZtG,OAAO,EACPqD,MAAO,CAAC,WACRC,QAAS,oBACTC,QAAS,mBACTC,YAAa,6CACbC,cAAe,CACbnG,KAAM,YAIZwD,QAAS,CACPY,MAAO,CACL1B,MAAO,EACPqD,MAAO,CAAC,UACRC,QAAS,gBACTC,QAAS,WACTC,YAAa,0BACbC,cAAe,CACbnG,KAAM,SACN+C,MAAO,EACPgF,IAAK,EACLC,IAAK,IAGT1C,KAAM,CACJ5C,MAAO,+BACPqD,MAAO,CAAC,UACRC,QAAS,eACTC,QAAS,UACTC,YACE,8DACFC,cAAe,CACbnG,KAAM,SAGVqF,KAAM,CACJ3C,MAAO,MACPqD,MAAO,CAAC,UACRC,QAAS,eACTC,QAAS,UACTC,YAAa,0DACbC,cAAe,CACbnG,KAAM,SAGVyD,UAAW,CACTf,OAAO,EACPqD,MAAO,CAAC,WACRC,QAAS,qBACTC,QAAS,eACTC,YAAa,sCACbC,cAAe,CACbnG,KAAM,WAGV0D,OAAQ,CACNhB,OAAO,EACPqD,MAAO,CAAC,WACRC,QAAS,kBACTC,QAAS,YACTC,YAAa,wCACbC,cAAe,CACbnG,KAAM,YAIZuK,GAAI,CACF3B,OAAQ,CACNlG,OAAO,EACPqD,MAAO,CAAC,WACRC,QAAS,YACTC,QAAS,WACTC,YAAa,mDACbC,cAAe,CACbnG,KAAM,WAGVwK,MAAO,CACL9H,MAAO,IACPqD,MAAO,CAAC,UACRC,QAAS,WACTC,QAAS,UACTC,YAAa,gCACbC,cAAe,CACbnG,KAAM,UAIZyK,MAAO,CACLC,QAAS,CACPhI,MAAO,aACPqD,MAAO,CAAC,UACRC,QAAS,iBACTE,YAAa,+BACbC,cAAe,CACbnG,KAAM,SAGV2K,qBAAsB,CACpBjI,OAAO,EACPqD,MAAO,CAAC,WACRC,QAAS,gCACTE,YAAa,iDACbC,cAAe,CACbnG,KAAM,WAGV4K,OAAQ,CACNlI,OAAO,EACPqD,MAAO,CAAC,WACRC,QAAS,gBACTE,YAAa,+CACbC,cAAe,CACbnG,KAAM,WAGV6K,cAAe,CACbnI,OAAO,EACPqD,MAAO,CAAC,WACRC,QAAS,wBACTE,YAAa,oDACbC,cAAe,CACbnG,KAAM,WAGV8K,iBAAkB,CAChBpI,OAAO,EACPqD,MAAO,CAAC,WACRC,QAAS,2BACTE,YAAa,yDACbC,cAAe,CACbnG,KAAM,YAIZ+K,MAAO,CACLnC,OAAQ,CACNlG,OAAO,EACPqD,MAAO,CAAC,WACRC,QAAS,eACTC,QAAS,cACTC,YAAa,4DACbC,cAAe,CACbnG,KAAM,WAGVgL,SAAU,CACRtI,OAAO,EACPqD,MAAO,CAAC,WACRC,QAAS,iBACTE,YACE,6EACFC,cAAe,CACbnG,KAAM,WAGViL,SAAU,CACRvI,OAAO,EACPqD,MAAO,CAAC,WACRC,QAAS,iBACTE,YAAa,+CACbC,cAAe,CACbnG,KAAM,WAGVkL,gBAAiB,CACfxI,OAAO,EACPqD,MAAO,CAAC,WACRC,QAAS,0BACTE,YACE,qEACFC,cAAe,CACbnG,KAAM,WAGVmL,OAAQ,CACNzI,OAAO,EACPqD,MAAO,CAAC,WACRC,QAAS,eACTE,YACE,kFACFC,cAAe,CACbnG,KAAM,WAGVoL,OAAQ,CACN1I,MAAO,EACPqD,MAAO,CAAC,UACRC,QAAS,gBACTE,YAAa,4DACbC,cAAe,CACbnG,KAAM,WAGVqL,cAAe,CACb3I,MAAO,KACPqD,MAAO,CAAC,UACRC,QAAS,uBACTE,YAAa,0BACbC,cAAe,CACbnG,KAAM,aAODsL,YAAcC,mBAAmB1F,eAGjC2F,cAAgBC,qBAAqB5F,eAoBlD,SAAS0F,mBAAmBG,EAAQJ,EAAc,CAAA,EAAIK,EAAY,IAqBhE,OApBAtM,OAAOwC,KAAK6J,GAAQE,SAASxM,IAE3B,MAAMyM,EAAQH,EAAOtM,QAGM,IAAhByM,EAAMnJ,MAEf6I,mBAAmBM,EAAOP,EAAa,GAAGK,KAAavM,MAGvDkM,EAAYO,EAAM5F,SAAW7G,GAAO,GAAGuM,KAAavM,IAAM0M,UAAU,QAG3CrH,IAArBoH,EAAMpD,aACR6C,EAAYO,EAAMpD,YAAc,GAAGkD,KAAavM,IAAM0M,UAAU,IAEnE,IAIIR,CACT,CAiBA,SAASG,qBAAqBC,EAAQF,EAAgB,IAkBpD,OAjBAnM,OAAOwC,KAAK6J,GAAQE,SAASxM,IAE3B,MAAMyM,EAAQH,EAAOtM,QAGM,IAAhByM,EAAM9F,MAEf0F,qBAAqBI,EAAOL,GAGxBK,EAAM9F,MAAMjG,SAAS,WACvB0L,EAActG,KAAK9F,EAEtB,IAIIoM,CACT,CCrhCAO,OAAOL,SAIP,MAAMM,EAAI,CAGRC,MAAQC,GACNC,EACGC,SACAC,WAAW3J,GACVA,EACGvC,MAAM,KACNmM,KAAK5J,GAAUA,EAAMnB,SACrBgL,QAAQ7J,GAAUwJ,EAAYpM,SAAS4C,OAE3C2J,WAAW3J,GAAWA,EAAMZ,OAASY,OAAQ+B,IAIlD+H,QAAS,IACPL,EACGM,KAAK,CAAC,OAAQ,QAAS,KACvBJ,WAAW3J,GAAqB,KAAVA,EAAyB,SAAVA,OAAmB+B,IAI7DgI,KAAOjM,GACL2L,EACGM,KAAK,IAAIjM,EAAQ,KACjB6L,WAAW3J,GAAqB,KAAVA,EAAeA,OAAQ+B,IAIlD2H,OAAQ,IACND,EACGC,SACA7K,OACAmL,QACEhK,IACE,CAAC,QAAS,YAAa,OAAQ,OAAO5C,SAAS4C,IACtC,KAAVA,IACDA,IAAW,CACVqC,QAAS,mDAAmDrC,SAG/D2J,WAAW3J,GAAqB,KAAVA,EAAeA,OAAQ+B,IAIlDkI,YAAa,IACXR,EACGC,SACA7K,OACAmL,QACEhK,GACW,KAAVA,IAAkBkK,MAAMC,WAAWnK,KAAWmK,WAAWnK,GAAS,IACnEA,IAAW,CACVqC,QAAS,qDAAqDrC,SAGjE2J,WAAW3J,GAAqB,KAAVA,EAAemK,WAAWnK,QAAS+B,IAI9DqI,eAAgB,IACdX,EACGC,SACA7K,OACAmL,QACEhK,GACW,KAAVA,IAAkBkK,MAAMC,WAAWnK,KAAWmK,WAAWnK,IAAU,IACpEA,IAAW,CACVqC,QAAS,yDAAyDrC,SAGrE2J,WAAW3J,GAAqB,KAAVA,EAAemK,WAAWnK,QAAS+B,KAGnDsI,OAASZ,EAAEa,OAAO,CAE7BC,eAAgBjB,EAAEI,SAGlBc,mBAAoBf,EACjBC,SACA7K,OACAmL,QACEhK,GAAU,6BAA6BR,KAAKQ,IAAoB,KAAVA,IACtDA,IAAW,CACVqC,QAAS,4FAA4FrC,SAGxG2J,WAAW3J,GAAqB,KAAVA,EAAeA,OAAQ+B,IAChD0I,mBAAoBhB,EACjBC,SACA7K,OACAmL,QACEhK,GACCA,EAAMY,WAAW,aACjBZ,EAAMY,WAAW,YACP,KAAVZ,IACDA,IAAW,CACVqC,QAAS,6FAA6FrC,SAGzG2J,WAAW3J,GAAqB,KAAVA,EAAeA,OAAQ+B,IAChD2I,uBAAwBpB,EAAEQ,UAC1Ba,sBAAuBrB,EAAEI,SACzBkB,uBAAwBtB,EAAEI,SAC1BmB,wBAAyBvB,EAAEC,MAAMpG,cAAcQ,WAAWK,YAAYhE,OACtE8K,0BAA2BxB,EAAEC,MAC3BpG,cAAcQ,WAAWO,cAAclE,OAEzC+K,6BAA8BzB,EAAEC,MAC9BpG,cAAcQ,WAAWQ,iBAAiBnE,OAE5CgL,0BAA2B1B,EAAEC,MAC3BpG,cAAcQ,WAAWS,cAAcpE,OAIzCiL,cAAe3B,EAAEI,SACjBwB,aAAc5B,EAAEI,SAChByB,eAAgB7B,EAAEI,SAClB0B,WAAY9B,EAAEI,SACd2B,aAAc/B,EAAEI,SAChB4B,eAAgBhC,EAAEI,SAClB6B,YAAajC,EAAES,KAAK,CAAC,OAAQ,MAAO,MAAO,QAC3CyB,cAAelC,EAAES,KAAK,CAAC,QAAS,aAAc,WAAY,eAC1D0B,WAAYnC,EAAEQ,UACd4B,mBAAoBpC,EAAEQ,UACtB6B,cAAerC,EAAEW,cACjB2B,aAActC,EAAEW,cAChB4B,aAAcvC,EAAEW,cAChB6B,sBAAuBxC,EAAEW,cACzB8B,qBAAsBzC,EAAEW,cACxB+B,qBAAsB1C,EAAEW,cACxBgC,sBAAuB3C,EAAEI,SACzBwC,qBAAsB5C,EAAEI,SACxByC,6BAA8B7C,EAAEc,iBAGhCgC,kCAAmC9C,EAAEQ,UACrCuC,kCAAmC/C,EAAEQ,UACrCwC,yBAA0BhD,EAAEI,SAC5B6C,sBAAuBjD,EAAEI,SACzB8C,uBAAwBlD,EAAEI,SAC1B+C,yBAA0BnD,EAAEI,SAC5BgD,2BAA4BpD,EAAEI,SAG9BiD,cAAerD,EAAEQ,UACjB8C,YAAatD,EAAEI,SACfmD,YAAavD,EAAEW,cACf6C,oBAAqBxD,EAAEW,cACvB8C,oBAAqBzD,EAAEQ,UAGvBkD,kBAAmB1D,EAAEI,SACrBuD,kBAAmB3D,EAAEW,cACrBiD,qBAAsB5D,EAAEc,iBAGxB+C,4BAA6B7D,EAAEQ,UAC/BsD,kCAAmC9D,EAAEc,iBACrCiD,4BAA6B/D,EAAEc,iBAC/BkD,2BAA4BhE,EAAEc,iBAC9BmD,iCAAkCjE,EAAEQ,UACpC0D,8BAA+BlE,EAAEI,SACjC+D,gCAAiCnE,EAAEI,SAGnCgE,kBAAmBpE,EAAEQ,UACrB6D,iBAAkBrE,EAAEQ,UACpB8D,gBAAiBtE,EAAEW,cACnB4D,qBAAsBvE,EAAEI,SAGxBoE,iBAAkBxE,EAAEc,iBACpB2D,iBAAkBzE,EAAEc,iBACpB4D,gBAAiB1E,EAAEW,cACnBgE,qBAAsB3E,EAAEc,iBACxB8D,oBAAqB5E,EAAEc,iBACvB+D,qBAAsB7E,EAAEc,iBACxBgE,kBAAmB9E,EAAEc,iBACrBiE,2BAA4B/E,EAAEc,iBAC9BkE,qBAAsBhF,EAAEc,iBACxBmE,kBAAmBjF,EAAEQ,UAGrB0E,cAAe/E,EACZC,SACA7K,OACAmL,QACEhK,GACW,KAAVA,IACEkK,MAAMC,WAAWnK,KACjBmK,WAAWnK,IAAU,GACrBmK,WAAWnK,IAAU,IACxBA,IAAW,CACVqC,QAAS,mGAAmGrC,SAG/G2J,WAAW3J,GAAqB,KAAVA,EAAemK,WAAWnK,QAAS+B,IAC5D0M,aAAcnF,EAAEI,SAChBgF,aAAcpF,EAAEI,SAChBiF,mBAAoBrF,EAAEQ,UACtB8E,gBAAiBtF,EAAEQ,UAGnB+E,UAAWvF,EAAEQ,UACbgF,SAAUxF,EAAEI,SAGZqF,eAAgBzF,EAAES,KAAK,CAAC,cAAe,aAAc,SACrDiF,8BAA+B1F,EAAEQ,UACjCmF,cAAe3F,EAAEQ,UACjBoF,sBAAuB5F,EAAEQ,UACzBqF,yBAA0B7F,EAAEQ,UAG5BsF,aAAc9F,EAAEQ,UAChBuF,eAAgB/F,EAAEQ,UAClBwF,eAAgBhG,EAAEQ,UAClByF,wBAAyBjG,EAAEQ,UAC3B0F,aAAclG,EAAEQ,UAChB2F,cAAenG,EAAEc,iBACjBsF,qBAAsBpG,EAAEW,gBAGb0F,KAAOtF,OAAOuF,UAAUC,MAAMlQ,QAAQmQ,KCvO7CvK,cAAgBwK,mBAAmB5M,eAelC,SAAS6M,WAAWC,GAAe,GACxC,OAAOA,EAAe1K,cAAgBlJ,SAASkJ,cACjD,CA8BO,SAAS2K,WACdC,EAAgB,CAAE,EAClBC,EAAU,GACVC,GAAe,GAGf,IAAIC,EAAgB,CAAA,EAGhBC,EAAa,CAAA,EAGbH,EAAQhR,SAEVkR,EAAgBE,gBAAgBJ,GAGhCG,EAAaE,mBAAmB7H,YAAawH,IAI/C,MAAMM,EAAiBV,WAAWK,GAYlC,OATAM,eACExN,cACAuN,EACAJ,EACAH,EACAI,GAIKG,CACT,CAYO,SAASE,aAAaC,EAAiBC,GAE5C,GAAI9R,SAAS8R,GACX,IAAK,MAAOpU,EAAKsD,KAAUrD,OAAOoU,QAAQD,GACxCD,EAAgBnU,GACdsC,SAASgB,KACR8I,cAAc1L,SAASV,SACCqF,IAAzB8O,EAAgBnU,GACZkU,aAAaC,EAAgBnU,GAAMsD,QACzB+B,IAAV/B,EACEA,EACA6Q,EAAgBnU,GAK5B,OAAOmU,CACT,CAkBO,SAASG,gBAAgBC,GAE9B,MAAMH,EAAa,CAAA,EAGnB,GAAmD,oBAA/CnU,OAAOC,UAAU8B,SAAS5B,KAAKmU,GAEjC,IAAK,MAAOvU,EAAKsD,KAAUrD,OAAOoU,QAAQE,GAAa,CAErD,MAAMC,EAAkBtI,YAAYlM,GAChCkM,YAAYlM,GAAKe,MAAM,KACvB,GAIJyT,EAAgBC,QACd,CAACC,EAAKC,EAAMC,IACTF,EAAIC,GACHH,EAAgB9R,OAAS,IAAMkS,EAAQtR,EAAQoR,EAAIC,IAAS,IAChEP,EAEH,CAIH,OAAOA,CACT,CAoBO,SAASS,gBACdvI,OACAtK,UAAW,EACX8S,gBAAiB,GAEjB,IAEE,IAAKxS,SAASgK,SAA6B,iBAAXA,OAE9B,OAAO,KAIT,MAAMyI,aACc,iBAAXzI,OACHwI,eACEE,KAAK,IAAI1I,WACT2I,KAAK9B,MAAM7G,QACbA,OAGA4I,mBAAqBC,kBACzBJ,aACAD,gBACA,GAIIM,cAAgBN,eAClBG,KAAK9B,MACHgC,kBAAkBJ,aAAcD,gBAAgB,IAChD,CAACO,EAAG/R,QACe,iBAAVA,OAAsBA,MAAMY,WAAW,YAC1C8Q,KAAK,IAAI1R,UACTA,QAER2R,KAAK9B,MAAM+B,oBAGf,OAAOlT,SAAWkT,mBAAqBE,aACxC,CAAC,MAAO5P,GAEP,OAAO,IACR,CACH,CAsFA,SAAS6N,mBAAmB/G,GAC1B,MAAMxE,EAAU,CAAA,EAGhB,IAAK,MAAOwN,EAAM/S,KAAStC,OAAOoU,QAAQ/H,GACxCxE,EAAQwN,GAAQrV,OAAOC,UAAUC,eAAeC,KAAKmC,EAAM,SACvDA,EAAKe,MACL+P,mBAAmB9Q,GAIzB,OAAOuF,CACT,CAuBA,SAASmM,eAAe3H,EAAQxE,EAASyN,EAAWC,EAAWC,GAC7DxV,OAAOwC,KAAK6J,GAAQE,SAASxM,IAE3B,MAAMyM,EAAQH,EAAOtM,GAGf0V,EAAYH,GAAaA,EAAUvV,GACnC2V,EAAYH,GAAaA,EAAUxV,GACnC4V,EAASH,GAAUA,EAAOzV,GAGhC,QAA2B,IAAhByM,EAAMnJ,MACf2Q,eAAexH,EAAO3E,EAAQ9H,GAAM0V,EAAWC,EAAWC,OACrD,CAEDF,UACF5N,EAAQ9H,GAAO0V,GAIjB,MAAMG,EAAS5C,KAAKxG,EAAM7F,SACtB6F,EAAM7F,WAAWqM,MAAjBxG,MAAyBoJ,IAC3B/N,EAAQ9H,GAAO6V,GAIbF,UACF7N,EAAQ9H,GAAO2V,GAIbC,UACF9N,EAAQ9H,GAAO4V,EAElB,IAEL,CAsBO,SAAST,kBAAkBrN,EAASgN,EAAgBgB,GAiCzD,OAAOb,KAAKc,UAAUjO,GAhCG,CAACuN,EAAG/R,KAO3B,GALqB,iBAAVA,IACTA,EAAQA,EAAMnB,QAKG,mBAAVmB,GACW,iBAAVA,GACNA,EAAMY,WAAW,aACjBZ,EAAMU,SAAS,KACjB,CAEA,GAAI8Q,EAEF,OAAOgB,EAEH,YAAYxS,EAAQ,IAAI0S,WAAW,OAAQ,eAE3C,WAAW1S,EAAQ,IAAI0S,WAAW,OAAQ,cAG9C,MAAM,IAAIC,KAEb,CAGD,OAAO3S,CAAK,IAImC0S,WAC/CF,EAAqB,yBAA2B,qBAChD,GAEJ,CAeA,SAAShC,gBAAgBJ,GAEvB,MAAMwC,EAAcxC,EAAQyC,WACzBC,GAAkC,eAA1BA,EAAI3V,QAAQ,KAAM,MAIvB4V,EAAiBH,GAAe,GAAKxC,EAAQwC,EAAc,GAGjE,GAAIG,EACF,IAEE,OAAOpB,KAAK9B,MAAMlP,aAAanD,gBAAgBuV,IAChD,CAAC,MAAO7Q,GACPD,aACE,EACAC,EACA,sDAAsD6Q,UAEzD,CAIH,MAAO,EACT,CAkBA,SAAStC,mBAAmB7H,EAAawH,GAEvC,MAAMG,EAAa,CAAA,EAGnB,IAAK,IAAIyC,EAAI,EAAGA,EAAI5C,EAAQhR,OAAQ4T,IAAK,CACvC,MAAMC,EAAS7C,EAAQ4C,GAAG7V,QAAQ,KAAM,IAGlC+T,EAAkBtI,EAAYqK,GAChCrK,EAAYqK,GAAQxV,MAAM,KAC1B,GAGJyT,EAAgBC,QAAO,CAACC,EAAKC,EAAMC,KACjC,GAAIJ,EAAgB9R,OAAS,IAAMkS,EAAO,CACxC,MAAMtR,EAAQoQ,IAAU4C,GACnBhT,GACHsB,IACE,EACA,yCAAyC2R,yCAG7C7B,EAAIC,GAAQrR,GAAS,IACtB,WAAwB+B,IAAdqP,EAAIC,KACbD,EAAIC,GAAQ,IAEd,OAAOD,EAAIC,EAAK,GACfd,EACJ,CAGD,OAAOA,CACT,CCvgBO2C,eAAeC,MAAM/W,EAAKgX,EAAiB,IAChD,OAAO,IAAIC,SAAQ,CAACC,EAASC,KAC3BC,mBAAmBpX,GAChBqX,IAAIrX,EAAKgX,GAAiBM,IACzB,IAAIC,EAAe,GAGnBD,EAASE,GAAG,QAASC,IACnBF,GAAgBE,CAAK,IAIvBH,EAASE,GAAG,OAAO,KACZD,GACHJ,EAAO,qCAETG,EAASI,KAAOH,EAChBL,EAAQI,EAAS,GACjB,IAEHE,GAAG,SAAU1R,IACZqR,EAAOrR,EAAM,GACb,GAER,CAwEA,SAASsR,mBAAmBpX,GAC1B,OAAOA,EAAIwE,WAAW,SAAWmT,MAAQC,IAC3C,CCpHA,MAAMC,oBAAoBtB,MAQxB,WAAAuB,CAAY7R,EAAS8R,GACnBC,QAEAC,KAAKhS,QAAUA,EACfgS,KAAK/R,aAAeD,EAEhB8R,IACFE,KAAKF,WAAaA,EAErB,CAUD,QAAAG,CAASpS,GAgBP,OAfAmS,KAAKnS,MAAQA,EAETA,EAAM8P,OACRqC,KAAKrC,KAAO9P,EAAM8P,MAGhB9P,EAAMiS,aACRE,KAAKF,WAAajS,EAAMiS,YAGtBjS,EAAMK,QACR8R,KAAK/R,aAAeJ,EAAMG,QAC1BgS,KAAK9R,MAAQL,EAAMK,OAGd8R,IACR,EC3BH,MAAME,MAAQ,CACZ1Q,OAAQ,8BACR2Q,eAAgB,CAAE,EAClBC,QAAS,GACTC,UAAW,IAcNxB,eAAeyB,oBACpBC,EACAC,GAEA,IAAIC,EAGJ,MAAM/Q,EAAYgR,eAGZC,EAAe3W,KAAK0F,EAAW,iBAC/BkR,EAAa5W,KAAK0F,EAAW,cAOnC,IAJCf,WAAWe,IAAcd,UAAUc,EAAW,CAAEmR,WAAW,KAIvDlS,WAAWgS,IAAiBJ,EAAkB9Q,WACjDxC,IAAI,EAAG,yDACPwT,QAAuBK,aACrBP,EACAC,EACAI,OAEG,CACL,IAAIG,GAAgB,EAGpB,MAAMC,EAAW1D,KAAK9B,MAAMlP,aAAaqU,IAIzC,GAAIK,EAASC,SAAW9Y,MAAMC,QAAQ4Y,EAASC,SAAU,CACvD,MAAMC,EAAY,CAAA,EAClBF,EAASC,QAAQpM,SAASsM,GAAOD,EAAUC,GAAK,IAChDH,EAASC,QAAUC,CACpB,CAGD,MAAMvR,YAAEA,EAAWE,cAAEA,EAAaC,iBAAEA,GAAqByQ,EACnDa,EACJzR,EAAY5E,OAAS8E,EAAc9E,OAAS+E,EAAiB/E,OAK3DiW,EAASzR,UAAYgR,EAAkBhR,SACzCtC,IACE,EACA,yEAEF8T,GAAgB,GACPzY,OAAOwC,KAAKkW,EAASC,SAAW,IAAIlW,SAAWqW,GACxDnU,IACE,EACA,+EAEF8T,GAAgB,GAGhBA,GAAiBlR,GAAiB,IAAI5E,MAAMoW,IAC1C,IAAKL,EAASC,QAAQI,GAKpB,OAJApU,IACE,EACA,eAAeoU,iDAEV,CACR,IAKDN,EACFN,QAAuBK,aACrBP,EACAC,EACAI,IAGF3T,IAAI,EAAG,uDAGPiT,MAAME,QAAU9T,aAAasU,EAAY,QAGzCH,EAAiBO,EAASC,QAG1Bf,MAAMG,UAAYiB,eAAepB,MAAME,SAE1C,OAIKmB,sBAAsBhB,EAAmBE,EACjD,CASO,SAASe,uBACd,OAAOtB,MAAMG,SACf,CAWOxB,eAAe4C,wBAAwBC,GAE5C,MAAMvR,EAAUwL,aAGhBxL,EAAQb,WAAWC,QAAUmS,QAGvBpB,oBAAoBnQ,EAAQb,WAAYa,EAAQyB,OAAOM,MAC/D,CAWO,SAASoP,eAAeK,GAC7B,OAAOA,EACJ5M,UAAU,EAAG4M,EAAaC,QAAQ,OAClC9Y,QAAQ,KAAM,IACdA,QAAQ,KAAM,IACdA,QAAQ,MAAO,IACf0B,MACL,CAYO,SAASqX,kBAAkBC,GAChC,OAAOA,EAAWhZ,QAChB,qEACA,GAEJ,CAoBO,SAAS4X,eACd,OAAOvX,gBAAgBwS,aAAarM,WAAWI,UACjD,CAuBAmP,eAAekD,uBACbC,EACAjD,EACA0B,EACAwB,GAAmB,GAGfD,EAAO3V,SAAS,SAClB2V,EAASA,EAAOjN,UAAU,EAAGiN,EAAOjX,OAAS,IAE/CkC,IAAI,EAAG,6BAA6B+U,QAGpC,MAAM3C,QAAiBP,MAAM,GAAGkD,OAAajD,GAG7C,GAA4B,MAAxBM,EAASS,YAA8C,iBAAjBT,EAASI,KAAkB,CACnE,GAAIgB,EAAgB,CAElBA,EADmBoB,kBAAkBG,IACR,CAC9B,CACD,OAAO3C,EAASI,IACjB,CAGD,GAAIwC,EACF,MAAM,IAAIrC,YACR,+BAA+BoC,2EAAgF3C,EAASS,eACxH,KACAG,SAASZ,GAEXpS,IACE,EACA,+BAA+B+U,6DAGrC,CAgBAnD,eAAe0C,sBAAsBhB,EAAmBE,EAAiB,IACvE,MAAMyB,EAAc,CAClB3S,QAASgR,EAAkBhR,QAC3B0R,QAASR,GAIXP,MAAMC,eAAiB+B,EAEvBjV,IAAI,EAAG,mCACP,IACEkV,cACEnY,KAAK0W,eAAgB,iBACrBpD,KAAKc,UAAU8D,GACf,OAEH,CAAC,MAAOrU,GACP,MAAM,IAAI+R,YACR,4CACA,KACAK,SAASpS,EACZ,CACH,CAuBAgR,eAAeuD,cACbzS,EACAE,EACAE,EACAyQ,EACAC,GAGA,IAAI4B,EACJ,MAAMC,EAAY9B,EAAmB1O,KAC/ByQ,EAAY/B,EAAmBzO,KAGrC,GAAIuQ,GAAaC,EACf,IACEF,EAAa,IAAIG,gBAAgB,CAC/B1Q,KAAMwQ,EACNvQ,KAAMwQ,GAET,CAAC,MAAO1U,GACP,MAAM,IAAI+R,YACR,0CACA,KACAK,SAASpS,EACZ,CAIH,MAAMkR,EAAiBsD,EACnB,CACEI,MAAOJ,EACPlQ,QAASqO,EAAmBrO,SAE9B,GAEEuQ,EAAmB,IACpB/S,EAAY4F,KAAKyM,GAClBD,uBAAuB,GAAGC,IAAUjD,EAAgB0B,GAAgB,QAEnE5Q,EAAc0F,KAAKyM,GACpBD,uBAAuB,GAAGC,IAAUjD,EAAgB0B,QAEnD1Q,EAAcwF,KAAKyM,GACpBD,uBAAuB,GAAGC,IAAUjD,MAKxC,aAD6BC,QAAQ2D,IAAID,IACnB1Y,KAAK,MAC7B,CAmBA6U,eAAeiC,aAAaP,EAAmBC,EAAoBI,GAEjE,MAAMP,EAC0B,WAA9BE,EAAkBhR,QACd,KACA,GAAGgR,EAAkBhR,UAGrBC,EAAS+Q,EAAkB/Q,QAAU0Q,MAAM1Q,OAEjD,IACE,MAAMiR,EAAiB,CAAA,EAuCvB,OArCAxT,IACE,EACA,iDAAiDoT,GAAa,aAGhEH,MAAME,cAAgBgC,cACpB,IACK7B,EAAkB5Q,YAAY4F,KAAKqN,GACpCvC,EAAY,GAAG7Q,KAAU6Q,KAAauC,IAAM,GAAGpT,KAAUoT,OAG7D,IACKrC,EAAkB1Q,cAAc0F,KAAK4L,GAChC,QAANA,EACId,EACE,GAAG7Q,UAAe6Q,aAAqBc,IACvC,GAAG3R,kBAAuB2R,IAC5Bd,EACE,GAAG7Q,KAAU6Q,aAAqBc,IAClC,GAAG3R,aAAkB2R,SAE1BZ,EAAkBzQ,iBAAiByF,KAAKoJ,GACzC0B,EACI,GAAG7Q,WAAgB6Q,gBAAwB1B,IAC3C,GAAGnP,sBAA2BmP,OAGtC4B,EAAkBxQ,cAClByQ,EACAC,GAIFP,MAAMG,UAAYiB,eAAepB,MAAME,SAGvC+B,cAAcvB,EAAYV,MAAME,SACzBK,CACR,CAAC,MAAO5S,GACP,MAAM,IAAI+R,YACR,uDACA,KACAK,SAASpS,EACZ,CACH,CCtcO,SAASgV,kBACdC,WAAWC,WAAa,WACtB,MAAO,CAAEC,SAAU,EACvB,CACA,CAWOnE,eAAeoE,YAAY9S,GAEhC,MAAMwL,WAAEA,EAAUuH,MAAEA,EAAKrH,WAAEA,EAAUsH,KAAEA,GAASL,WAIhDA,WAAWM,cAAgBF,GAAM,EAAO,CAAE,EAAEvH,KAG5CrJ,OAAO+Q,kBAAmB,EAC1BF,EAAKL,WAAWQ,MAAM/a,UAAW,QAAQ,SAAUgb,EAASC,EAAaC,KAEvED,EAAcN,EAAMM,EAAa,CAC/BE,UAAW,CACTC,SAAS,GAEXC,YAAa,CACXC,OAAQ,CACNC,MAAO,CACLH,SAAS,KAOfI,QAAS,CAAE,KAGAF,QAAU,IAAIhP,SAAQ,SAAUgP,GAC3CA,EAAOG,WAAY,CACzB,IAGS1R,OAAO2R,qBACV3R,OAAO2R,mBAAqBnB,WAAWoB,SAASlE,KAAM,UAAU,KAC9D1N,OAAO+Q,kBAAmB,CAAI,KAIlCE,EAAQ9V,MAAMuS,KAAM,CAACwD,EAAaC,GACtC,IAEEN,EAAKL,WAAWqB,OAAO5b,UAAW,QAAQ,SAAUgb,EAASa,EAAOjU,GAClEoT,EAAQ9V,MAAMuS,KAAM,CAACoE,EAAOjU,GAChC,IAGE,MAAMkU,EAAoB,CACxBD,MAAO,CAELJ,WAAW,EAEXtT,OAAQP,EAAQH,OAAOU,OACvBC,MAAOR,EAAQH,OAAOW,OAExB+S,UAAW,CAETC,SAAS,IAKPH,EAAc,IAAIc,SAAS,UAAUnU,EAAQH,OAAOE,QAAtC,GAGdiB,EAAe,IAAImT,SAAS,UAAUnU,EAAQH,OAAOmB,eAAtC,GAGfD,EAAgB,IAAIoT,SACxB,UAAUnU,EAAQH,OAAOkB,gBADL,GAKhBqT,EAAerB,GACnB,EACA/R,EACAqS,EAEAa,GAIIG,EAAgBrU,EAAQkB,YAAYE,SACtC,IAAI+S,SAAS,UAAUnU,EAAQkB,YAAYE,WAA3C,GACA,KAGApB,EAAQkB,YAAYnF,YACtB,IAAIoY,SAAS,UAAWnU,EAAQkB,YAAYnF,WAA5C,CAAwDsX,GAItDtS,GACF2K,EAAW3K,GAIb4R,WAAW3S,EAAQH,OAAOrH,QAAQ,YAAa4b,EAAcC,GAG7D,MAAMC,EAAiB9I,IAGvB,IAAK,MAAMqB,KAAQyH,EACmB,mBAAzBA,EAAezH,WACjByH,EAAezH,GAK1BnB,EAAWiH,WAAWM,eAGtBN,WAAWM,cAAgB,EAC7B,CC3HA,MAAMsB,SAAWpY,aACftC,KAAKpC,UAAW,YAAa,iBAC7B,QAIF,IAAI+c,QAAU,KAmCP9F,eAAe+F,cAAcC,GAElC,MAAM7Q,MAAEA,EAAKN,MAAEA,GAAUiI,cAGjB9J,OAAQiT,KAAiBC,GAAiB/Q,EAG5CgR,EAAgB,CACpB/Q,UAAUP,EAAMK,kBAAmB,QACnCkR,YAAa,MACb/X,KAAM2X,GAAiB,GACvBK,cAAc,EACdC,eAAe,EACfC,cAAc,EACdC,oBAAoB,EACpBC,gBAAiB,QACbR,GAAgBC,GAItB,IAAKJ,QAAS,CAEZ,IAAIY,EAAW,EAEf,MAAMC,EAAO3G,UACX,IACE5R,IACE,EACA,yDAAyDsY,OAI3DZ,cAAgB5V,UAAU0W,OAAOT,EAClC,CAAC,MAAOnX,GAQP,GAPAD,aACE,EACAC,EACA,oDAIE0X,EAAW,IAOb,MAAM1X,EANNZ,IAAI,EAAG,sCAAsCsY,uBAGvC,IAAIvG,SAASK,GAAaqG,WAAWrG,EAAU,aAC/CmG,GAIT,GAGH,UACQA,IAGyB,UAA3BR,EAAc/Q,UAChBhH,IAAI,EAAG,6CAIL6X,GACF7X,IAAI,EAAG,4CAEV,CAAC,MAAOY,GACP,MAAM,IAAI+R,YACR,gEACA,KACAK,SAASpS,EACZ,CAED,IAAK8W,QACH,MAAM,IAAI/E,YAAY,2CAA4C,IAErE,CAGD,OAAO+E,OACT,CAQO9F,eAAe8G,eAEhBhB,SAAWA,QAAQiB,iBACfjB,QAAQkB,QAEhBlB,QAAU,KACV1X,IAAI,EAAG,gCACT,CAgBO4R,eAAeiH,QAAQC,GAE5B,IAAKpB,UAAYA,QAAQiB,UACvB,MAAM,IAAIhG,YAAY,0CAA2C,KAgBnE,GAZAmG,EAAaC,WAAarB,QAAQmB,gBAG5BC,EAAaC,KAAKC,iBAAgB,SAGlCC,gBAAgBH,EAAaC,MAGnCG,eAAeJ,EAAaC,OAGvBD,EAAaC,MAAQD,EAAaC,KAAKI,WAC1C,MAAM,IAAIxG,YAAY,2CAA4C,IAEtE,CAkBOf,eAAewH,UAAUN,EAAcO,GAAY,GACxD,IACE,GAAIP,EAAaC,OAASD,EAAaC,KAAKI,WAgB1C,OAfIE,SAEIP,EAAaC,KAAKO,KAAK,cAAe,CAC1CC,UAAW,2BAIPN,gBAAgBH,EAAaC,aAG7BD,EAAaC,KAAKS,UAAS,KAC/BC,SAASC,KAAKC,UACZ,4DAA4D,KAG3D,CAEV,CAAC,MAAO/Y,GACPD,aACE,EACAC,EACA,yBAAyBkY,EAAac,mDAIxCd,EAAae,UAAYnL,aAAa7I,KAAKG,UAAY,CACxD,CACD,OAAO,CACT,CAiBO4L,eAAekI,iBAAiBf,EAAMgB,GAE3C,MAAMC,EAAoB,GAGpBzV,EAAYwV,EAAmBxV,UACrC,GAAIA,EAAW,CACb,MAAM0V,EAAa,GAUnB,GAPI1V,EAAU2V,IACZD,EAAW/Y,KAAK,CACdiZ,QAAS5V,EAAU2V,KAKnB3V,EAAU6V,MACZ,IAAK,MAAM9Y,KAAQiD,EAAU6V,MAAO,CAClC,MAAMC,GAAW/Y,EAAKhC,WAAW,QAGjC2a,EAAW/Y,KACTmZ,EACI,CACEF,QAAS9a,aAAanD,gBAAgBoF,GAAO,SAE/C,CACExG,IAAKwG,GAGd,CAGH,IAAK,MAAMgZ,KAAcL,EACvB,IACED,EAAkB9Y,WAAW6X,EAAKwB,aAAaD,GAChD,CAAC,MAAO1Z,GACPD,aAAa,EAAGC,EAAO,8CACxB,CAEHqZ,EAAWnc,OAAS,EAGpB,MAAM0c,EAAc,GACpB,GAAIjW,EAAUkW,IAAK,CACjB,IAAIC,EAAanW,EAAUkW,IAAIE,MAAM,uBACrC,GAAID,EAEF,IAAK,IAAIE,KAAiBF,EACpBE,IACFA,EAAgBA,EACb/e,QAAQ,OAAQ,IAChBA,QAAQ,UAAW,IACnBA,QAAQ,KAAM,IACdA,QAAQ,KAAM,IACdA,QAAQ,IAAK,IACbA,QAAQ,MAAO,IACf0B,OAGCqd,EAActb,WAAW,QAC3Bkb,EAAYtZ,KAAK,CACfpG,IAAK8f,IAEEb,EAAmB7a,oBAC5Bsb,EAAYtZ,KAAK,CACfrE,KAAME,KAAKpC,UAAWigB,MAQhCJ,EAAYtZ,KAAK,CACfiZ,QAAS5V,EAAUkW,IAAI5e,QAAQ,sBAAuB,KAAO,MAG/D,IAAK,MAAMgf,KAAeL,EACxB,IACER,EAAkB9Y,WAAW6X,EAAK+B,YAAYD,GAC/C,CAAC,MAAOja,GACPD,aACE,EACAC,EACA,+CAEH,CAEH4Z,EAAY1c,OAAS,CACtB,CACF,CACD,OAAOkc,CACT,CAeOpI,eAAemJ,mBAAmBhC,EAAMiB,GAC7C,IACE,IAAK,MAAMgB,KAAYhB,QACfgB,EAASC,gBAIXlC,EAAKS,UAAS,KAElB,GAA0B,oBAAf3D,WAA4B,CAErC,MAAMqF,EAAYrF,WAAWsF,OAG7B,GAAIjgB,MAAMC,QAAQ+f,IAAcA,EAAUpd,OAExC,IAAK,MAAMsd,KAAYF,EACrBE,GAAYA,EAASC,UAErBxF,WAAWsF,OAAO/e,OAGvB,CAGD,SAAUkf,GAAmB7B,SAAS8B,qBAAqB,WAErD,IAAMC,GAAkB/B,SAAS8B,qBAAqB,aAElDE,GAAiBhC,SAAS8B,qBAAqB,QAGzD,IAAK,MAAMG,IAAW,IACjBJ,KACAE,KACAC,GAEHC,EAAQC,QACT,GAEJ,CAAC,MAAO/a,GACPD,aAAa,EAAGC,EAAO,8CACxB,CACH,CAYAgR,eAAeqH,gBAAgBF,SAEvBA,EAAK6C,WAAWnE,SAAU,CAAE8B,UAAW,2BAGvCR,EAAKwB,aAAa,CAAE1d,KAAME,KAAK0W,eAAgB,sBAG/CsF,EAAKS,SAAS5D,gBACtB,CAWA,SAASsD,eAAeH,GAEtB,MAAMhS,MAAEA,GAAU2H,aAGlBqK,EAAKzG,GAAG,aAAaV,UAGfmH,EAAKI,UAER,IAICpS,EAAMnC,QAAUmC,EAAMG,iBACxB6R,EAAKzG,GAAG,WAAYvR,IAClBR,QAAQP,IAAI,WAAWe,EAAQyR,SAAS,GAG9C,CC5cA,IAAAqJ,YAAe,IAAM,yXCINC,YAAC3Y,GAAQ,8LAQlB0Y,8EAIE1Y,wCCWDyO,eAAemK,gBAAgBhD,EAAM7V,GAE1C,MAAM8W,EAAoB,GAE1B,IAEE,MAAMgC,EAAgB9Y,EAAQH,OAE9B,IAAIkZ,GAAQ,EACZ,GAAID,EAAc7Y,IAAK,CAIrB,GAHAnD,IAAI,EAAG,mCAGoB,QAAvBgc,EAAchgB,KAChB,OAAOggB,EAAc7Y,IAIvB8Y,GAAQ,QAGFC,UAAUnD,EAAMiD,EAAc7Y,IAC1C,MACMnD,IAAI,EAAG,2CAGDmc,cAAcpD,EAAM7V,GAM5B8W,EAAkB9Y,cACN4Y,iBAAiBf,EAAM7V,EAAQkB,cAI3C,MAAMgY,EAAOH,QACHlD,EAAKS,UAAU7V,IACnB,MAAM0Y,EAAa5C,SAAS6C,cAC1B,sCAIIC,EAAcF,EAAW5Y,OAAO+Y,QAAQ9d,MAAQiF,EAChD8Y,EAAaJ,EAAW3Y,MAAM8Y,QAAQ9d,MAAQiF,EAUpD,OANA8V,SAASC,KAAKgD,MAAMC,KAAOhZ,EAI3B8V,SAASC,KAAKgD,MAAME,OAAS,MAEtB,CACLL,cACAE,aACD,GACA5T,WAAWmT,EAAcrY,cACtBoV,EAAKS,UAAS,KAElB,MAAM+C,YAAEA,EAAWE,WAAEA,GAAepX,OAAOwQ,WAAWsF,OAAO,GAO7D,OAFA1B,SAASC,KAAKgD,MAAMC,KAAO,EAEpB,CACLJ,cACAE,aACD,KAIDI,EAAEA,EAACC,EAAEA,SAAYC,eAAehE,GAGhCiE,EAAiBne,KAAKoe,IAC1Bpe,KAAKqe,KAAKd,EAAKG,aAAeP,EAAcvY,SAIxC0Z,EAAgBte,KAAKoe,IACzBpe,KAAKqe,KAAKd,EAAKK,YAAcT,EAActY,QAU7C,IAAI0Z,EAEJ,aARMrE,EAAKsE,YAAY,CACrB5Z,OAAQuZ,EACRtZ,MAAOyZ,EACPG,kBAAmBrB,EAAQ,EAAIpT,WAAWmT,EAAcrY,SAKlDqY,EAAchgB,MACpB,IAAK,MACHohB,QAAeG,WAAWxE,GAC1B,MACF,IAAK,MACL,IAAK,OACHqE,QAAeI,aACbzE,EACAiD,EAAchgB,KACd,CACE0H,MAAOyZ,EACP1Z,OAAQuZ,EACRH,IACAC,KAEFd,EAAc7X,sBAEhB,MACF,IAAK,MACHiZ,QAAeK,WACb1E,EACAiE,EACAG,EACAnB,EAAc7X,sBAEhB,MACF,QACE,MAAM,IAAIwO,YACR,uCAAuCqJ,EAAchgB,QACrD,KAMN,aADM+e,mBAAmBhC,EAAMiB,GACxBoD,CACR,CAAC,MAAOxc,GAEP,aADMma,mBAAmBhC,EAAMiB,GACxBpZ,CACR,CACH,CAcAgR,eAAesK,UAAUnD,EAAM5V,SACvB4V,EAAK6C,WAAWE,YAAY3Y,GAAM,CACtCoW,UAAW,oBAEf,CAiBA3H,eAAeuK,cAAcpD,EAAM7V,SAC3B6V,EAAKS,SAASxD,YAAa9S,EACnC,CAcA0O,eAAemL,eAAehE,GAC5B,OAAOA,EAAK2E,MAAM,oBAAqBhC,IACrC,MAAMmB,EAAEA,EAACC,EAAEA,EAACpZ,MAAEA,EAAKD,OAAEA,GAAWiY,EAAQiC,wBACxC,MAAO,CACLd,IACAC,IACApZ,QACAD,OAAQ5E,KAAK+e,MAAMna,EAAS,EAAIA,EAAS,KAC1C,GAEL,CAaAmO,eAAe2L,WAAWxE,GACxB,OAAOA,EAAK2E,MACV,gCACChC,GAAYA,EAAQmC,WAEzB,CAkBAjM,eAAe4L,aAAazE,EAAM/c,EAAM8hB,EAAM3Z,GAC5C,OAAO4N,QAAQgM,KAAK,CAClBhF,EAAKiF,WAAW,CACdhiB,OACA8hB,OACAG,SAAU,SACVC,UAAU,EACVC,kBAAkB,EAClBC,uBAAuB,KACV,QAATpiB,EAAiB,CAAEqiB,QAAS,IAAO,CAAA,EAEvCC,eAAwB,OAARtiB,IAElB,IAAI+V,SAAQ,CAACwM,EAAUtM,IACrBwG,YACE,IAAMxG,EAAO,IAAIU,YAAY,wBAAyB,OACtDxO,GAAwB,SAIhC,CAiBAyN,eAAe6L,WAAW1E,EAAMtV,EAAQC,EAAOS,GAE7C,aADM4U,EAAKyF,iBAAiB,UACrBzF,EAAK0F,IAAI,CAEdhb,OAAQA,EAAS,EACjBC,QACAua,SAAU,SACV/Y,QAASf,GAAwB,MAErC,CCpSA,IAAI0B,KAAO,KAGX,MAAM6Y,UAAY,CAChBC,iBAAkB,EAClBC,iBAAkB,EAClBC,eAAgB,EAChBC,eAAgB,EAChBC,mBAAoB,EACpBC,uBAAwB,EACxBC,2BAA4B,EAC5BC,UAAW,EACXC,iBAAkB,GAsBbvN,eAAewN,SACpBC,EAAc3Q,aAAa7I,KAC3B+R,EAAgB,UAGVD,cAAcC,GAEpB,IAME,GALA5X,IACE,EACA,8CAA8Cqf,EAAYvZ,mBAAmBuZ,EAAYtZ,eAGvFF,KAKF,YAJA7F,IACE,EACA,yEAMAqf,EAAYvZ,WAAauZ,EAAYtZ,aACvCsZ,EAAYvZ,WAAauZ,EAAYtZ,YAIvCF,KAAO,IAAIyZ,KAAK,IAEXC,SAASF,GACZtb,IAAKsb,EAAYvZ,WACjB9B,IAAKqb,EAAYtZ,WACjByZ,qBAAsBH,EAAYpZ,eAClCwZ,oBAAqBJ,EAAYnZ,cACjCwZ,qBAAsBL,EAAYlZ,eAClCwZ,kBAAmBN,EAAYjZ,YAC/BwZ,0BAA2BP,EAAYhZ,oBACvCwZ,mBAAoBR,EAAY/Y,eAChCwZ,sBAAsB,IAIxBja,KAAKyM,GAAG,WAAWV,MAAOoJ,IAExB,MAAM+E,QAAoB3G,UAAU4B,GAAU,GAC9Chb,IACE,EACA,yBAAyBgb,EAASpB,gDAAgDmG,KACnF,IAGHla,KAAKyM,GAAG,kBAAkB,CAAC0N,EAAUhF,KACnChb,IACE,EACA,yBAAyBgb,EAASpB,0CAEpCoB,EAASjC,KAAO,IAAI,IAGtB,MAAMkH,EAAmB,GAEzB,IAAK,IAAIvO,EAAI,EAAGA,EAAI2N,EAAYvZ,WAAY4L,IAC1C,IACE,MAAMsJ,QAAiBnV,KAAKqa,UAAUC,QACtCF,EAAiB/e,KAAK8Z,EACvB,CAAC,MAAOpa,GACPD,aAAa,EAAGC,EAAO,+CACxB,CAIHqf,EAAiBrY,SAASoT,IACxBnV,KAAKua,QAAQpF,EAAS,IAGxBhb,IACE,EACA,4BAA2BigB,EAAiBniB,OAAS,SAASmiB,EAAiBniB,oCAAsC,KAExH,CAAC,MAAO8C,GACP,MAAM,IAAI+R,YACR,6DACA,KACAK,SAASpS,EACZ,CACH,CAYOgR,eAAeyO,WAIpB,GAHArgB,IAAI,EAAG,6DAGH6F,KAAM,CAER,IAAK,MAAMya,KAAUza,KAAK0a,KACxB1a,KAAKua,QAAQE,EAAOtF,UAIjBnV,KAAK2a,kBACF3a,KAAKwV,UACXrb,IAAI,EAAG,4CAET6F,KAAO,IACR,OAGK6S,cACR,CAmBO9G,eAAe6O,SAASvd,GAC7B,IAAIwd,EAEJ,IAYE,GAXA1gB,IAAI,EAAG,gDAGL0e,UAAUC,iBAGRjQ,aAAa7I,KAAKb,cACpB2b,eAIG9a,KACH,MAAM,IAAI8M,YACR,uDACA,KAKJ,MAAMiO,EAAiBziB,cAGvB,IACE6B,IAAI,EAAG,qCAGP0gB,QAAqB7a,KAAKqa,UAAUC,QAGhCjd,EAAQyB,OAAOK,cACjBhF,IACE,EACAkD,EAAQ2d,WACJ,wBAAwB3d,EAAQ2d,iBAChC,eACJ,kCAAkCD,SAGvC,CAAC,MAAOhgB,GACP,MAAM,IAAI+R,YACR,WACGzP,EAAQ2d,WAAa,YAAY3d,EAAQ2d,iBAAmB,IAC7D,wDAAwDD,SAC1D,KACA5N,SAASpS,EACZ,CAGD,GAFAZ,IAAI,EAAG,qCAEF0gB,EAAa3H,KAGhB,MADA2H,EAAa7G,UAAY3W,EAAQ2C,KAAKG,UAAY,EAC5C,IAAI2M,YACR,mEACA,KAKJ,MAAMmO,EAAYtjB,iBAElBwC,IACE,EACA,yBAAyB0gB,EAAa9G,2CAIxC,MAAMmH,EAAgB5iB,cAChBif,QAAerB,gBAAgB2E,EAAa3H,KAAM7V,GAGxD,GAAIka,aAAkB/L,MAmBpB,KANuB,0BAAnB+L,EAAOrc,UAET2f,EAAa7G,UAAY3W,EAAQ2C,KAAKG,UAAY,EAClD0a,EAAa3H,KAAO,MAIJ,iBAAhBqE,EAAO1M,MACY,0BAAnB0M,EAAOrc,QAED,IAAI4R,YACR,WACGzP,EAAQ2d,WAAa,YAAY3d,EAAQ2d,iBAAmB,IAC7D,iHACF7N,SAASoK,GAEL,IAAIzK,YACR,WACGzP,EAAQ2d,WAAa,YAAY3d,EAAQ2d,iBAAmB,IAC7D,oCAAoCE,UACtC/N,SAASoK,GAKXla,EAAQyB,OAAOK,cACjBhF,IACE,EACAkD,EAAQ2d,WACJ,wBAAwB3d,EAAQ2d,iBAChC,eACJ,sCAAsCE,UAK1Clb,KAAKua,QAAQM,GAIb,MACMM,EADUxjB,iBACasjB,EAS7B,OAPApC,UAAUQ,WAAa8B,EACvBtC,UAAUS,iBACRT,UAAUQ,YAAcR,UAAUE,iBAEpC5e,IAAI,EAAG,4BAA4BghB,QAG5B,CACL5D,SACAla,UAEH,CAAC,MAAOtC,GAOP,OANE8d,UAAUG,eAER6B,GACF7a,KAAKua,QAAQM,GAGT9f,CACP,CACH,CAqBO,SAASqgB,eACd,OAAOvC,SACT,CAUO,SAASwC,kBACd,MAAO,CACLnd,IAAK8B,KAAK9B,IACVC,IAAK6B,KAAK7B,IACVuc,KAAM1a,KAAKsb,UACXC,UAAWvb,KAAKwb,UAChBC,WAAYzb,KAAKsb,UAAYtb,KAAKwb,UAClCE,gBAAiB1b,KAAK2b,qBACtBC,eAAgB5b,KAAK6b,oBACrBC,mBAAoB9b,KAAK+b,wBACzBC,gBAAiBhc,KAAKgc,gBAAgB/jB,OACtCgkB,YACEjc,KAAKsb,UACLtb,KAAKwb,UACLxb,KAAK2b,qBACL3b,KAAK6b,oBACL7b,KAAK+b,wBACL/b,KAAKgc,gBAAgB/jB,OAE3B,CASO,SAAS6iB,cACd,MAAM5c,IACJA,EAAGC,IACHA,EAAGuc,KACHA,EAAIa,UACJA,EAASE,WACTA,EAAUC,gBACVA,EAAeE,eACfA,EAAcE,mBACdA,EAAkBE,gBAClBA,EAAeC,YACfA,GACEZ,kBAEJlhB,IAAI,EAAG,2DAA2D+D,MAClE/D,IAAI,EAAG,2DAA2DgE,MAClEhE,IAAI,EAAG,wCAAwCugB,MAC/CvgB,IAAI,EAAG,wCAAwCohB,MAC/CphB,IACE,EACA,+DAA+DshB,MAEjEthB,IACE,EACA,0DAA0DuhB,MAE5DvhB,IACE,EACA,yDAAyDyhB,MAE3DzhB,IACE,EACA,2DAA2D2hB,MAE7D3hB,IACE,EACA,2DAA2D6hB,MAE7D7hB,IAAI,EAAG,uCAAuC8hB,KAChD,CAUA,SAASvC,SAASF,GAChB,MAAO,CAcL0C,OAAQnQ,UAEN,MAAMkH,EAAe,CACnBc,GAAIoI,KAEJnI,UAAWhb,KAAKE,MAAMF,KAAKojB,UAAY5C,EAAYrZ,UAAY,KAGjE,IAEE,MAAMkc,EAAY1kB,iBAclB,aAXMqb,QAAQC,GAGd9Y,IACE,EACA,yBAAyB8Y,EAAac,6CACpCpc,iBAAmB0kB,QAKhBpJ,CACR,CAAC,MAAOlY,GAKP,MAJAZ,IACE,EACA,yBAAyB8Y,EAAac,qDAElChZ,CACP,GAgBHuhB,SAAUvQ,MAAOkH,GAiBVA,EAAaC,KASdD,EAAaC,KAAKI,YACpBnZ,IACE,EACA,yBAAyB8Y,EAAac,yDAEjC,GAILd,EAAaC,KAAKqJ,YAAYC,UAChCriB,IACE,EACA,yBAAyB8Y,EAAac,wDAEjC,KAKPyF,EAAYrZ,aACV8S,EAAae,UAAYwF,EAAYrZ,aAEvChG,IACE,EACA,yBAAyB8Y,EAAac,yCAAyCyF,EAAYrZ,yCAEtF,IAlCPhG,IACE,EACA,yBAAyB8Y,EAAac,sDAEjC,GA8CXyB,QAASzJ,MAAOkH,IAMd,GALA9Y,IACE,EACA,yBAAyB8Y,EAAac,8BAGpCd,EAAaC,OAASD,EAAaC,KAAKI,WAC1C,IAEEL,EAAaC,KAAKuJ,mBAAmB,aACrCxJ,EAAaC,KAAKuJ,mBAAmB,WACrCxJ,EAAaC,KAAKuJ,mBAAmB,uBAG/BxJ,EAAaC,KAAKH,OACzB,CAAC,MAAOhY,GAKP,MAJAZ,IACE,EACA,yBAAyB8Y,EAAac,mDAElChZ,CACP,CACF,EAGP,CC1kBO,SAAS2hB,SAAStlB,GAEvB,MAAMoI,EAAS,IAAImd,MAAM,IAAInd,OAM7B,OAHeod,UAAUpd,GAGXkd,SAAStlB,EAAO,CAAEylB,SAAU,CAAC,kBAC7C,CCHA,IAAIre,oBAAqB,EAmBlBuN,eAAe+Q,aAAazf,GAEjC,IAAIA,IAAWA,EAAQH,OAqCrB,MAAM,IAAI4P,YACR,kKACA,WArCIiQ,YAAY1f,GAAS0O,MAAOhR,EAAOiiB,KAEvC,GAAIjiB,EACF,MAAMA,EAIR,MAAM2C,IAAEA,EAAGtH,QAAEA,EAAOD,KAAEA,GAAS6mB,EAAK3f,QAAQH,OAG5C,IACMQ,EAEF2R,cACE,GAAGjZ,EAAQE,MAAM,KAAKC,SAAW,cACjCY,UAAU6lB,EAAKzF,OAAQphB,IAIzBkZ,cACEjZ,GAAW,SAASD,IACX,QAATA,EAAiBkB,OAAOC,KAAK0lB,EAAKzF,OAAQ,UAAYyF,EAAKzF,OAGhE,CAAC,MAAOxc,GACP,MAAM,IAAI+R,YACR,sCACA,KACAK,SAASpS,EACZ,OAGKyf,UAAU,GAQtB,CAqBOzO,eAAekR,YAAY5f,GAEhC,KAAIA,GAAWA,EAAQH,QAAUG,EAAQH,OAAOK,OA4E9C,MAAM,IAAIuP,YACR,+GACA,KA9EmD,CAErD,MAAMoQ,EAAiB,GAGvB,IAAK,IAAIC,KAAQ9f,EAAQH,OAAOK,MAAMjH,MAAM,MAAQ,GAClD6mB,EAAOA,EAAK7mB,MAAM,KACE,IAAhB6mB,EAAKllB,OACPilB,EAAe7hB,KACb0hB,YACE,IACK1f,EACHH,OAAQ,IACHG,EAAQH,OACXC,OAAQggB,EAAK,GACb/mB,QAAS+mB,EAAK,MAGlB,CAACpiB,EAAOiiB,KAEN,GAAIjiB,EACF,MAAMA,EAIR,MAAM2C,IAAEA,EAAGtH,QAAEA,EAAOD,KAAEA,GAAS6mB,EAAK3f,QAAQH,OAG5C,IACMQ,EAEF2R,cACE,GAAGjZ,EAAQE,MAAM,KAAKC,SAAW,cACjCY,UAAU6lB,EAAKzF,OAAQphB,IAIzBkZ,cACEjZ,EACS,QAATD,EACIkB,OAAOC,KAAK0lB,EAAKzF,OAAQ,UACzByF,EAAKzF,OAGd,CAAC,MAAOxc,GACP,MAAM,IAAI+R,YACR,sCACA,KACAK,SAASpS,EACZ,MAKPZ,IAAI,EAAG,uDAKX,MAAMijB,QAAqBlR,QAAQmR,WAAWH,SAGxC1C,WAGN4C,EAAarb,SAAQ,CAACwV,EAAQpN,KAExBoN,EAAO+F,QACTxiB,aACE,EACAyc,EAAO+F,OACP,+BAA+BnT,EAAQ,sCAE1C,GAEP,CAMA,CA8BO4B,eAAegR,YAAY/T,EAAeuU,GAC/C,IAEEpjB,IAAI,EAAG,2CAGP,MAAMkD,EAAUoM,aAAaZ,YAAW,GAAQG,GAG1CmN,EAAgB9Y,EAAQH,OAG9B,GAA6B,OAAzBiZ,EAAchZ,OAAiB,CAGjC,IAAIqgB,EAFJrjB,IAAI,EAAG,mDAGP,IAEEqjB,EAAchkB,aACZnD,gBAAgB8f,EAAchZ,QAC9B,OAEH,CAAC,MAAOpC,GACP,MAAM,IAAI+R,YACR,mDACA,KACAK,SAASpS,EACZ,CAGD,GAAIob,EAAchZ,OAAO5D,SAAS,QAEhC4c,EAAc7Y,IAAMkgB,MACf,KAAIrH,EAAchZ,OAAO5D,SAAS,SAIvC,MAAM,IAAIuT,YACR,kDACA,KAJFqJ,EAAc/Y,MAAQogB,CAMvB,CACF,CAGD,GAA0B,OAAtBrH,EAAc7Y,IAAc,CAC9BnD,IAAI,EAAG,qDAGLihB,eAAejC,uBAGjB,MAAM5B,QAAekG,eACnBf,SAASvG,EAAc7Y,KACvBD,GAOF,QAHE+d,eAAenC,eAGVsE,EAAY,KAAMhG,EAC1B,CAGD,GAA4B,OAAxBpB,EAAc/Y,OAA4C,OAA1B+Y,EAAc9Y,QAAkB,CAClElD,IAAI,EAAG,sDAGLihB,eAAehC,2BAGjB,MAAM7B,QAAemG,mBACnBvH,EAAc/Y,OAAS+Y,EAAc9Y,QACrCA,GAOF,QAHE+d,eAAelC,mBAGVqE,EAAY,KAAMhG,EAC1B,CAGD,OAAOgG,EACL,IAAIzQ,YACF,gJACA,KAGL,CAAC,MAAO/R,GACP,OAAOwiB,EAAYxiB,EACpB,CACH,CASO,SAAS4iB,wBACd,OAAOnf,kBACT,CAUO,SAASof,sBAAsB/kB,GACpC2F,mBAAqB3F,CACvB,CAkBAkT,eAAe0R,eAAeI,EAAexgB,GAE3C,GAC2B,iBAAlBwgB,IACNA,EAAc/O,QAAQ,SAAW,GAAK+O,EAAc/O,QAAQ,UAAY,GAYzE,OAVA3U,IAAI,EAAG,iCAGPkD,EAAQH,OAAOI,IAAMugB,EAGrBxgB,EAAQH,OAAOE,MAAQ,KACvBC,EAAQH,OAAOG,QAAU,KAGlBygB,eAAezgB,GAEtB,MAAM,IAAIyP,YAAY,mCAAoC,IAE9D,CAkBAf,eAAe2R,mBAAmBG,EAAexgB,GAC/ClD,IAAI,EAAG,uCAGP,MAAMsQ,EAAqBL,gBACzByT,GACA,EACAxgB,EAAQkB,YAAYC,oBAItB,GACyB,OAAvBiM,GAC8B,iBAAvBA,IACNA,EAAmBhR,WAAW,OAC9BgR,EAAmBlR,SAAS,KAE7B,MAAM,IAAIuT,YACR,oPACA,KAWJ,OANAzP,EAAQH,OAAOE,MAAQqN,EAGvBpN,EAAQH,OAAOI,IAAM,KAGdwgB,eAAezgB,EACxB,CAcA0O,eAAe+R,eAAezgB,GAC5B,MAAQH,OAAQiZ,EAAe5X,YAAa2V,GAAuB7W,EA+BnE,OA5BA8Y,EAAchgB,KAAOK,QAAQ2f,EAAchgB,KAAMggB,EAAc/f,SAG/D+f,EAAc/f,QAAUF,WAAWigB,EAAchgB,KAAMggB,EAAc/f,SAGrE+D,IACE,EACA,+BAA+B+Z,EAAmB1V,mBAAqB,UAAY,iBAIrFuf,mBAAmB7J,EAAoBA,EAAmB1V,oBAG1Dwf,sBACE7H,EACAjC,EAAmB7a,mBACnB6a,EAAmB1V,oBAIrBnB,EAAQH,OAAS,IACZiZ,KACA8H,eAAe9H,IAIbyE,SAASvd,EAClB,CAoBA,SAAS4gB,eAAe9H,GAEtB,MAAQ7E,MAAO4M,EAActN,UAAWuN,GACtChI,EAAc9Y,SAAW+M,gBAAgB+L,EAAc/Y,SAAU,GAG3DkU,MAAO8M,EAAoBxN,UAAWyN,GAC5CjU,gBAAgB+L,EAAc/X,iBAAkB,GAG1CkT,MAAOgN,EAAmB1N,UAAW2N,GAC3CnU,gBAAgB+L,EAAc9X,gBAAiB,EAM3CP,EAAQlF,YACZI,KAAKmF,IACH,GACAnF,KAAKkF,IACHiY,EAAcrY,OACZqgB,GAAkBrgB,OAClBugB,GAAwBvgB,OACxBygB,GAAuBzgB,OACvBqY,EAAclY,cACd,EACF,IAGJ,GA4BIsY,EAAO,CAAE3Y,OAvBbuY,EAAcvY,QACdugB,GAAkBK,cAClBN,GAActgB,QACdygB,GAAwBG,cACxBJ,GAAoBxgB,QACpB2gB,GAAuBC,cACvBF,GAAmB1gB,QACnBuY,EAAcpY,eACd,IAeqBF,MAXrBsY,EAActY,OACdsgB,GAAkBM,aAClBP,GAAcrgB,OACdwgB,GAAwBI,aACxBL,GAAoBvgB,OACpB0gB,GAAuBE,aACvBH,GAAmBzgB,OACnBsY,EAAcnY,cACd,IAG4BF,SAG9B,IAAK,IAAK4gB,EAAO7lB,KAAUrD,OAAOoU,QAAQ2M,GACxCA,EAAKmI,GACc,iBAAV7lB,GAAsBA,EAAM7C,QAAQ,SAAU,IAAM6C,EAI/D,OAAO0d,CACT,CAkBA,SAASwH,mBAAmB7J,EAAoB1V,GAE9C,GAAIA,EAAoB,CAEtB,GAA4C,iBAAjC0V,EAAmBxV,UAE5BwV,EAAmBxV,UAAYigB,iBAC7BzK,EAAmBxV,UACnBwV,EAAmB7a,oBACnB,QAEG,IAAK6a,EAAmBxV,UAC7B,IAEEwV,EAAmBxV,UAAYigB,iBAC7BnlB,aAAanD,gBAAgB,kBAAmB,QAChD6d,EAAmB7a,oBACnB,EAEH,CAAC,MAAO0B,GACPZ,IAAI,EAAG,4DACR,CAIH,IAEE+Z,EAAmB9a,WAAaD,WAC9B+a,EAAmB9a,WACnB8a,EAAmB7a,mBAEtB,CAAC,MAAO0B,GACPD,aAAa,EAAGC,EAAO,8CAGvBmZ,EAAmB9a,WAAa,IACjC,CAGD,IAEE8a,EAAmBzV,SAAWtF,WAC5B+a,EAAmBzV,SACnByV,EAAmB7a,oBACnB,EAEH,CAAC,MAAO0B,GACPD,aAAa,EAAGC,EAAO,4CAGvBmZ,EAAmBzV,SAAW,IAC/B,CAGG,CAAC,UAAM7D,GAAW3E,SAASie,EAAmB9a,aAChDe,IAAI,EAAG,uDAIL,CAAC,UAAMS,GAAW3E,SAASie,EAAmBzV,WAChDtE,IAAI,EAAG,qDAIL,CAAC,UAAMS,GAAW3E,SAASie,EAAmBxV,YAChDvE,IAAI,EAAG,qDAEb,MAII,GACE+Z,EAAmBzV,UACnByV,EAAmBxV,WACnBwV,EAAmB9a,WAQnB,MALA8a,EAAmBzV,SAAW,KAC9ByV,EAAmBxV,UAAY,KAC/BwV,EAAmB9a,WAAa,KAG1B,IAAI0T,YACR,oGACA,IAIR,CAkBA,SAAS6R,iBACPjgB,EAAY,KACZrF,EACAmF,GAGA,MAAMogB,EAAe,CAAC,KAAM,MAAO,SAEnC,IAAIC,EAAmBngB,EACnBogB,GAAmB,EAGvB,GAAIzlB,GAAsBqF,EAAUnF,SAAS,SAC3C,IACEslB,EAAmBzU,gBACjB5Q,aAAanD,gBAAgBqI,GAAY,SACzC,EACAF,EAER,CAAM,MACA,OAAO,IACR,MAGDqgB,EAAmBzU,gBAAgB1L,GAAW,EAAOF,GAGjDqgB,IAAqBxlB,UAChBwlB,EAAiBtK,MAK5B,IAAK,MAAMwK,KAAYF,EAChBD,EAAa3oB,SAAS8oB,GAEfD,IACVA,GAAmB,UAFZD,EAAiBE,GAO5B,OAAKD,GAKDD,EAAiBtK,QACnBsK,EAAiBtK,MAAQsK,EAAiBtK,MAAM9R,KAAK3K,GAASA,EAAKJ,WAC9DmnB,EAAiBtK,OAASsK,EAAiBtK,MAAMtc,QAAU,WACvD4mB,EAAiBtK,OAKrBsK,GAZE,IAaX,CAmBA,SAASb,sBACP7H,EACA9c,EACAmF,GAGA,CAAC,gBAAiB,gBAAgBuD,SAASid,IACzC,IAEM7I,EAAc6I,KAGd3lB,GACsC,iBAA/B8c,EAAc6I,IACrB7I,EAAc6I,GAAazlB,SAAS,SAGpC4c,EAAc6I,GAAe5U,gBAC3B5Q,aAAanD,gBAAgB8f,EAAc6I,IAAe,SAC1D,EACAxgB,GAIF2X,EAAc6I,GAAe5U,gBAC3B+L,EAAc6I,IACd,EACAxgB,GAIP,CAAC,MAAOzD,GACPD,aACE,EACAC,EACA,iBAAiBikB,yBAInB7I,EAAc6I,GAAe,IAC9B,KAIC,CAAC,UAAMpkB,GAAW3E,SAASkgB,EAAc/X,gBAC3CjE,IAAI,EAAG,0DAIL,CAAC,UAAMS,GAAW3E,SAASkgB,EAAc9X,eAC3ClE,IAAI,EAAG,wDAEX,CCjyBA,MAAM8kB,SAAW,GASV,SAASC,SAASnL,GACvBkL,SAAS5jB,KAAK0Y,EAChB,CAQO,SAASoL,iBACdhlB,IAAI,EAAG,2DACP,IAAK,MAAM4Z,KAAMkL,SACfG,cAAcrL,GACdsL,aAAatL,EAEjB,CCfA,SAASuL,mBAAmBvkB,EAAOwkB,EAAShT,EAAUiT,GAUpD,OARA1kB,aAAa,EAAGC,GAGmB,gBAA/B8N,aAAajI,MAAMC,gBACd9F,EAAMK,MAIRokB,EAAKzkB,EACd,CAYA,SAAS0kB,sBAAsB1kB,EAAOwkB,EAAShT,EAAUiT,GAEvD,MAAMtkB,QAAEA,EAAOE,MAAEA,GAAUL,EAGrBiS,EAAajS,EAAMiS,YAAc,IAGvCT,EAASmT,OAAO1S,GAAY2S,KAAK,CAAE3S,aAAY9R,UAASE,SAC1D,CAOe,SAASwkB,gBAAgBC,GAEtCA,EAAIC,IAAIR,oBAGRO,EAAIC,IAAIL,sBACV,CC1Ce,SAASM,uBACtBF,EACAG,EAAsBnX,aAAa/J,OAAOQ,cAE1C,IAEE,GAAI0gB,EAAoBjhB,OAAQ,CAC9B,MAAMkhB,EACJ,yEAGIC,EAAc,CAClB/hB,IAAK6hB,EAAoBzgB,aAAe,GACxCC,OAAQwgB,EAAoBxgB,QAAU,EACtCC,MAAOugB,EAAoBvgB,OAAS,EACpCC,WAAYsgB,EAAoBtgB,aAAc,EAC9CC,QAASqgB,EAAoBrgB,UAAW,EACxCC,UAAWogB,EAAoBpgB,YAAa,GAI1CsgB,EAAYxgB,YACdmgB,EAAI9gB,OAAO,eAIb,MAAMohB,EAAUC,UAAU,CACxBC,SAA+B,GAArBH,EAAY1gB,OAAc,IAEpCrB,IAAK+hB,EAAY/hB,IAEjBmiB,QAASJ,EAAYzgB,MACrB8gB,QAAS,CAAChB,EAAShT,KACjBA,EAASiU,OAAO,CACdb,KAAM,KACJpT,EAASmT,OAAO,KAAKe,KAAK,CAAEvlB,QAAS+kB,GAAM,EAE7CS,QAAS,KACPnU,EAASmT,OAAO,KAAKe,KAAKR,EAAI,GAEhC,EAEJU,KAAOpB,IAGqB,IAAxBW,EAAYvgB,UACc,IAA1BugB,EAAYtgB,WACZ2f,EAAQqB,MAAMrrB,MAAQ2qB,EAAYvgB,SAClC4f,EAAQqB,MAAMC,eAAiBX,EAAYtgB,YAE3CzF,IAAI,EAAG,2CACA,KAOb0lB,EAAIC,IAAIK,GAERhmB,IACE,EACA,8CAA8C+lB,EAAY/hB,oBAAoB+hB,EAAY1gB,8CAA8C0gB,EAAYxgB,cAEvJ,CACF,CAAC,MAAO3E,GACP,MAAM,IAAI+R,YACR,yEACA,KACAK,SAASpS,EACZ,CACH,CCzFA,MAAM+lB,kBAAkBhU,YAQtB,WAAAC,CAAY7R,EAAS8R,GACnBC,MAAM/R,EAAS8R,EAChB,CASD,SAAA+T,CAAU/T,GAGR,OAFAE,KAAKF,WAAaA,EAEXE,IACR,ECUH,SAAS8T,sBAAsBzB,EAAShT,EAAUiT,GAChD,IAEE,MAAMyB,EAAc1B,EAAQ2B,QAAQ,iBAAmB,GAGvD,IACGD,EAAYhrB,SAAS,sBACrBgrB,EAAYhrB,SAAS,uCACrBgrB,EAAYhrB,SAAS,uBAEtB,MAAM,IAAI6qB,UACR,iHACA,KAKJ,OAAOtB,GACR,CAAC,MAAOzkB,GACP,OAAOykB,EAAKzkB,EACb,CACH,CAmBA,SAASomB,sBAAsB5B,EAAShT,EAAUiT,GAChD,IAEE,MAAM3L,EAAO0L,EAAQ1L,KAGfuN,EAAYjF,KAAOnmB,QAAQ,KAAM,IAGvC,IAAK6d,GAAQ9b,cAAc8b,GAQzB,MAPA1Z,IACE,EACA,yBAAyBinB,yBACvB7B,EAAQ2B,QAAQ,oBAAsB3B,EAAQ8B,WAAWC,2DAIvD,IAAIR,UACR,sKACA,KAKJ,MAAMtiB,EAAqBmf,wBAGrBvgB,EAAQgN,gBAEZyJ,EAAKzW,OAASyW,EAAKxW,SAAWwW,EAAK1W,QAAU0W,EAAKmJ,MAElD,EAEAxe,GAIF,GAAc,OAAVpB,IAAmByW,EAAKvW,IAQ1B,MAPAnD,IACE,EACA,yBAAyBinB,yBACvB7B,EAAQ2B,QAAQ,oBAAsB3B,EAAQ8B,WAAWC,2FACmB9W,KAAKc,UAAUuI,OAGzF,IAAIiN,UACR,iRACA,KAKJ,GAAIjN,EAAKvW,KAAOpF,uBAAuB2b,EAAKvW,KAC1C,MAAM,IAAIwjB,UACR,4LACA,KA0CJ,OArCAvB,EAAQgC,iBAAmB,CAEzBvG,WAAYoG,EACZlkB,OAAQ,CACNE,QACAE,IAAKuW,EAAKvW,IACVlH,QACEyd,EAAKzd,SACL,GAAGmpB,EAAQiC,OAAOC,UAAY,WAAWjrB,QAAQqd,EAAK1d,QACxDA,KAAMK,QAAQqd,EAAK1d,KAAM0d,EAAKzd,SAC9BP,OAAQD,UAAUie,EAAKhe,QACvB6H,IAAKmW,EAAKnW,IACVC,WAAYkW,EAAKlW,WACjBC,OAAQiW,EAAKjW,OACbC,MAAOgW,EAAKhW,MACZC,MAAO+V,EAAK/V,MACZM,cAAegM,gBACbyJ,EAAKzV,eACL,EACAI,GAEFH,aAAc+L,gBACZyJ,EAAKxV,cACL,EACAG,IAGJD,YAAa,CACXC,qBACAnF,oBAAoB,EACpBD,WAAYya,EAAKza,WACjBqF,SAAUoV,EAAKpV,SACfC,UAAW0L,gBAAgByJ,EAAKnV,WAAW,EAAMF,KAK9CghB,GACR,CAAC,MAAOzkB,GACP,OAAOykB,EAAKzkB,EACb,CACH,CAOe,SAAS2mB,qBAAqB7B,GAE3CA,EAAI8B,KAAK,CAAC,IAAK,cAAeX,uBAG9BnB,EAAI8B,KAAK,CAAC,IAAK,cAAeR,sBAChC,CClLA,MAAMS,aAAe,CACnBC,IAAK,YACLC,KAAM,aACNC,IAAK,YACLnJ,IAAK,kBACLtb,IAAK,iBAgBPyO,eAAeiW,cAAczC,EAAShT,EAAUiT,GAC9C,IAEE,MAAMyC,EAAiB3pB,cAGvB,IAAI4pB,GAAoB,EACxB3C,EAAQ4C,OAAO1V,GAAG,SAAU2V,IACtBA,IACFF,GAAoB,EACrB,IAIH,MAAMjW,EAAiBsT,EAAQgC,iBAGzBH,EAAYnV,EAAe+O,WAGjC7gB,IAAI,EAAG,iDAAiDinB,YAGlDrE,YAAY9Q,GAAgB,CAAClR,EAAOiiB,KAKxC,GAHAuC,EAAQ4C,OAAO1F,mBAAmB,SAG9ByF,EACF/nB,IACE,EACA,qBAAqBinB,mFAHzB,CASA,GAAIrmB,EACF,MAAMA,EAIR,IAAKiiB,IAASA,EAAKzF,OASjB,MARApd,IACE,EACA,qBAAqBinB,qBACnB7B,EAAQ2B,QAAQ,oBAChB3B,EAAQ8B,WAAWC,mDACiBtE,EAAKzF,WAGvC,IAAIuJ,UACR,6GACA,KAKJ,GAAI9D,EAAKzF,OAAQ,CACfpd,IACE,EACA,qBAAqBinB,yCAAiDa,UAIxE,MAAM9rB,KAAEA,EAAIuH,IAAEA,EAAGC,WAAEA,EAAUvH,QAAEA,GAAY4mB,EAAK3f,QAAQH,OAGxD,OAAIQ,EACK6O,EAASkU,KAAKtpB,UAAU6lB,EAAKzF,OAAQphB,KAI9CoW,EAAS8V,OAAO,eAAgBT,aAAazrB,IAAS,aAGjDwH,GACH4O,EAAS+V,WAAWlsB,GAIN,QAATD,EACHoW,EAASkU,KAAKzD,EAAKzF,QACnBhL,EAASkU,KAAKppB,OAAOC,KAAK0lB,EAAKzF,OAAQ,WAC5C,CAlDA,CAkDA,GAEJ,CAAC,MAAOxc,GACP,OAAOykB,EAAKzkB,EACb,CACH,CASe,SAASwnB,aAAa1C,GAKnCA,EAAI8B,KAAK,IAAKK,eAMdnC,EAAI8B,KAAK,aAAcK,cACzB,CCpIA,MAAMQ,gBAAkB,IAAI/qB,KAGtBgrB,YAAcjY,KAAK9B,MAAMlP,aAAatC,KAAKpC,UAAW,kBAGtD4tB,aAAe,GAGfC,eAAiB,IAGjBC,WAAa,GAUnB,SAASC,0BACP,OAAOH,aAAa1Y,QAAO,CAAC8Y,EAAGC,IAAMD,EAAIC,GAAG,GAAKL,aAAazqB,MAChE,CAUA,SAAS+qB,oBACP,OAAOC,aAAY,KACjB,MAAMC,EAAQ9H,eACR+H,EACuB,IAA3BD,EAAMpK,iBACF,EACCoK,EAAMnK,iBAAmBmK,EAAMpK,iBAAoB,IAE1D4J,aAAarnB,KAAK8nB,GACdT,aAAazqB,OAAS2qB,YACxBF,aAAansB,OACd,GACAosB,eACL,CASe,SAASS,aAAavD,GAGnCX,SAAS8D,qBAKTnD,EAAIvT,IAAI,WAAW,CAACiT,EAAShT,EAAUiT,KACrC,IACErlB,IAAI,EAAG,qCAEP,MAAM+oB,EAAQ9H,eACRiI,EAASX,aAAazqB,OACtBqrB,EAAgBT,0BAGtBtW,EAASkU,KAAK,CAEZf,OAAQ,KACR6D,SAAUf,gBACVgB,OAAQ,GAAGxqB,KAAKyqB,OAAO9rB,iBAAmB6qB,gBAAgB5qB,WAAa,IAAO,cAG9E8rB,cAAejB,YAAYhmB,QAC3BknB,kBAAmBjV,uBAGnBkV,kBAAmBV,EAAM5J,iBACzBuK,iBAAkBX,EAAMpK,iBACxBgL,iBAAkBZ,EAAMnK,iBACxBgL,cAAeb,EAAMlK,eACrBgL,YAAcd,EAAMnK,iBAAmBmK,EAAMpK,iBAAoB,IAGjE9Y,KAAMqb,kBAGNgI,SACAC,gBACApoB,QACE6H,MAAMugB,KAAmBZ,aAAazqB,OAClC,oEACA,QAAQorB,mCAAwCC,EAAcW,QAAQ,OAG5EC,WAAYhB,EAAMjK,eAClBkL,YAAajB,EAAMhK,mBACnBkL,mBAAoBlB,EAAM/J,uBAC1BkL,oBAAqBnB,EAAM9J,4BAE9B,CAAC,MAAOre,GACP,OAAOykB,EAAKzkB,EACb,IAEL,CC7Ge,SAASupB,SAASzE,GAI/BA,EAAIvT,IAAIzD,aAAanI,GAAGC,OAAS,KAAK,CAAC4e,EAAShT,EAAUiT,KACxD,IACEjT,EAASgY,SAASrtB,KAAKpC,UAAW,SAAU,cAAe,CACzD0vB,cAAc,GAEjB,CAAC,MAAOzpB,GACP,OAAOykB,EAAKzkB,EACb,IAEL,CCbe,SAAS0pB,oBAAoB5E,GAK1CA,EAAI8B,KAAK,+BAA+B5V,MAAOwT,EAAShT,EAAUiT,KAChE,IAEE,MAAMkF,EAAalc,KAAK/E,uBAGxB,IAAKihB,IAAeA,EAAWzsB,OAC7B,MAAM,IAAI6oB,UACR,iHACA,KAKJ,MAAM6D,EAAQpF,EAAQjT,IAAI,WAG1B,IAAKqY,GAASA,IAAUD,EACtB,MAAM,IAAI5D,UACR,2EACA,KAKJ,MAAMlS,EAAa2Q,EAAQiC,OAAO5S,WAClC,IAAIA,EAmBF,MAAM,IAAIkS,UAAU,qCAAsC,KAlB1D,UAEQnS,wBAAwBC,EAC/B,CAAC,MAAO7T,GACP,MAAM,IAAI+lB,UACR,6BAA6B/lB,EAAMG,UACnC,KACAiS,SAASpS,EACZ,CAGDwR,EAASmT,OAAO,KAAKe,KAAK,CACxBzT,WAAY,IACZ2W,kBAAmBjV,uBACnBxT,QAAS,+CAA+C0T,MAM7D,CAAC,MAAO7T,GACP,OAAOykB,EAAKzkB,EACb,IAEL,CCvCA,MAAM6pB,cAAgB,IAAIC,IAGpBhF,IAAMiF,UAqBL/Y,eAAegZ,YAAYC,EAAgBnc,aAAa/J,QAC7D,IAEE,IAAKkmB,EAAcjmB,SAAW8gB,IAC5B,MAAM,IAAI/S,YACR,mFACA,KAMJ,MAAMmY,EAA+C,KAA5BD,EAAc9lB,YAAqB,KAGtDgmB,EAAUC,OAAOC,gBAGjBC,EAASF,OAAO,CACpBD,UACAI,OAAQ,CACNC,UAAWN,KA2Cf,GAtCApF,IAAI2F,QAAQ,gBAGZ3F,IAAIC,IACF2F,KAAK,CACHC,QAAS,CAAC,OAAQ,MAAO,cAM7B7F,IAAIC,KAAI,CAACP,EAAShT,EAAUiT,KAC1BjT,EAASoZ,IAAI,gBAAiB,QAC9BnG,GAAM,IAIRK,IAAIC,IACFgF,QAAQnF,KAAK,CACXiG,MAAOX,KAKXpF,IAAIC,IACFgF,QAAQe,WAAW,CACjBC,UAAU,EACVF,MAAOX,KAKXpF,IAAIC,IAAIuF,EAAOU,QAGflG,IAAIC,IAAIgF,QAAQkB,OAAO9uB,KAAKpC,UAAW,aAGlCkwB,EAAcnlB,IAAIC,MAAO,CAE5B,MAAMmmB,EAAapZ,KAAKqZ,aAAarG,KAGrCsG,2BAA2BF,GAG3BA,EAAWG,OAAOpB,EAAc/lB,KAAM+lB,EAAchmB,MAAM,KAExD4lB,cAAce,IAAIX,EAAc/lB,KAAMgnB,GAEtC9rB,IACE,EACA,mCAAmC6qB,EAAchmB,QAAQgmB,EAAc/lB,QACxE,GAEJ,CAGD,GAAI+lB,EAAcnlB,IAAId,OAAQ,CAE5B,IAAIxJ,EAAK8wB,EAET,IAEE9wB,QAAY+wB,SACVpvB,KAAKb,gBAAgB2uB,EAAcnlB,IAAIE,UAAW,cAClD,QAIFsmB,QAAaC,SACXpvB,KAAKb,gBAAgB2uB,EAAcnlB,IAAIE,UAAW,cAClD,OAEH,CAAC,MAAOhF,GACPZ,IACE,EACA,qDAAqD6qB,EAAcnlB,IAAIE,sDAE1E,CAED,GAAIxK,GAAO8wB,EAAM,CAEf,MAAME,EAAc3Z,MAAMsZ,aAAa,CAAE3wB,MAAK8wB,QAAQxG,KAGtDsG,2BAA2BI,GAG3BA,EAAYH,OAAOpB,EAAcnlB,IAAIZ,KAAM+lB,EAAchmB,MAAM,KAE7D4lB,cAAce,IAAIX,EAAcnlB,IAAIZ,KAAMsnB,GAE1CpsB,IACE,EACA,oCAAoC6qB,EAAchmB,QAAQgmB,EAAcnlB,IAAIZ,QAC7E,GAEJ,CACF,CAGD8gB,uBAAuBF,IAAKmF,EAAc1lB,cAG1CoiB,qBAAqB7B,KAGrBuD,aAAavD,KACb0C,aAAa1C,KACbyE,SAASzE,KACT4E,oBAAoB5E,KAGpBD,gBAAgBC,IACjB,CAAC,MAAO9kB,GACP,MAAM,IAAI+R,YACR,qDACA,KACAK,SAASpS,EACZ,CACH,CAOO,SAASyrB,eAEd,GAAI5B,cAAcrO,KAAO,EAAG,CAC1Bpc,IAAI,EAAG,iCAGP,IAAK,MAAO8E,EAAMH,KAAW8lB,cAC3B9lB,EAAOiU,OAAM,KACX6R,cAAc6B,OAAOxnB,GACrB9E,IAAI,EAAG,mCAAmC8E,KAAQ,GAGvD,CACH,CASO,SAASynB,aACd,OAAO9B,aACT,CASO,SAAS+B,aACd,OAAO7B,OACT,CASO,SAAS8B,SACd,OAAO/G,GACT,CAUO,SAASgH,mBAAmB7G,GACjCD,uBAAuBF,IAAKG,EAC9B,CAUO,SAASF,IAAI9oB,KAAS8vB,GAC3BjH,IAAIC,IAAI9oB,KAAS8vB,EACnB,CAUO,SAASxa,IAAItV,KAAS8vB,GAC3BjH,IAAIvT,IAAItV,KAAS8vB,EACnB,CAUO,SAASnF,KAAK3qB,KAAS8vB,GAC5BjH,IAAI8B,KAAK3qB,KAAS8vB,EACpB,CASA,SAASX,2BAA2BrnB,GAClCA,EAAO2N,GAAG,eAAe,CAAC1R,EAAOonB,KAC/BrnB,aACE,EACAC,EACA,0BAA0BA,EAAMG,+BAElCinB,EAAO3M,SAAS,IAGlB1W,EAAO2N,GAAG,SAAU1R,IAClBD,aAAa,EAAGC,EAAO,0BAA0BA,EAAMG,UAAU,IAGnE4D,EAAO2N,GAAG,cAAe0V,IACvBA,EAAO1V,GAAG,SAAU1R,IAClBD,aAAa,EAAGC,EAAO,0BAA0BA,EAAMG,UAAU,GACjE,GAEN,CAEA,IAAe4D,OAAA,CACbimB,wBACAyB,0BACAE,sBACAC,sBACAC,cACAC,sCACA/G,QACAxT,QACAqV,WCxUK5V,eAAegb,gBAAgBC,SAE9B9a,QAAQmR,WAAW,CAEvB8B,iBAGAqH,eAGAhM,aAIFhiB,QAAQyuB,KAAKD,EACf,CCgBOjb,eAAemb,WAAWle,GAE/B,MAAM3L,EAAUoM,aAAaZ,YAAW,GAAQG,GAGhD4U,sBAAsBvgB,EAAQkB,YAAYC,oBAG1ClD,YAAY+B,EAAQ1D,SAGhB0D,EAAQuD,MAAME,sBAChBqmB,oCAII3Z,oBAAoBnQ,EAAQb,WAAYa,EAAQyB,OAAOM,aAGvDma,SAASlc,EAAQ2C,KAAM3C,EAAQpB,UAAU7B,KACjD,CASA,SAAS+sB,8BACPhtB,IAAI,EAAG,sDAGP3B,QAAQiU,GAAG,QAAS2a,IAClBjtB,IAAI,EAAG,sCAAsCitB,KAAQ,IAIvD5uB,QAAQiU,GAAG,UAAUV,MAAOlB,EAAMuc,KAChCjtB,IAAI,EAAG,iBAAiB0Q,sBAAyBuc,YAC3CL,gBAAgB,EAAE,IAI1BvuB,QAAQiU,GAAG,WAAWV,MAAOlB,EAAMuc,KACjCjtB,IAAI,EAAG,iBAAiB0Q,sBAAyBuc,YAC3CL,gBAAgB,EAAE,IAI1BvuB,QAAQiU,GAAG,UAAUV,MAAOlB,EAAMuc,KAChCjtB,IAAI,EAAG,iBAAiB0Q,sBAAyBuc,YAC3CL,gBAAgB,EAAE,IAI1BvuB,QAAQiU,GAAG,qBAAqBV,MAAOhR,EAAO8P,KAC5C/P,aAAa,EAAGC,EAAO,iBAAiB8P,kBAClCkc,gBAAgB,EAAE,GAE5B,CAEA,IAAe5c,MAAA,CAEbrL,cACAimB,wBAGAlc,sBACAE,sBACAU,0BACAI,gCAGAqd,sBACApK,0BACAG,wBACAF,wBAGAvP,wCAGA+L,kBACAiB,kBAGArgB,QACAW,0BACAY,wBACAC,0CACAC,oCAGAmrB"} \ No newline at end of file +{"version":3,"file":"index.esm.js","sources":["../lib/utils.js","../lib/logger.js","../lib/schemas/config.js","../lib/validation.js","../lib/config.js","../lib/fetch.js","../lib/errors/ExportError.js","../lib/cache.js","../lib/highcharts.js","../lib/browser.js","../templates/svgExport/css.js","../templates/svgExport/svgExport.js","../lib/export.js","../lib/pool.js","../lib/sanitize.js","../lib/chart.js","../lib/timer.js","../lib/server/middlewares/error.js","../lib/server/middlewares/rateLimiting.js","../lib/errors/HttpError.js","../lib/server/middlewares/validation.js","../lib/server/routes/export.js","../lib/server/routes/health.js","../lib/server/routes/ui.js","../lib/server/routes/versionChange.js","../lib/server/server.js","../lib/resourceRelease.js","../lib/index.js"],"sourcesContent":["/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * @overview The Highcharts Export Server utility module provides\r\n * a comprehensive set of helper functions and constants designed to streamline\r\n * and enhance various operations required for Highcharts export tasks.\r\n */\r\n\r\nimport { readFileSync } from 'fs';\r\nimport { isAbsolute, join } from 'path';\r\nimport { fileURLToPath } from 'url';\r\n\r\nconst MAX_BACKOFF_ATTEMPTS = 6;\r\n\r\n// The directory path\r\nexport const __dirname = fileURLToPath(new URL('../.', import.meta.url));\r\n\r\n/**\r\n * Clears and standardizes text by replacing multiple consecutive whitespace\r\n * characters with a single space and trimming any leading or trailing\r\n * whitespace.\r\n *\r\n * @function clearText\r\n *\r\n * @param {string} text - The input text to be cleared.\r\n * @param {RegExp} [rule=/\\s\\s+/g] - The regular expression rule to match\r\n * multiple consecutive whitespace characters. The default value\r\n * is the '/\\s\\s+/g' RegExp.\r\n * @param {string} [replacer=' '] - The string used to replace multiple\r\n * consecutive whitespace characters. The default value is the ' ' string.\r\n *\r\n * @returns {string} The cleared and standardized text.\r\n */\r\nexport function clearText(text, rule = /\\s\\s+/g, replacer = ' ') {\r\n return text.replaceAll(rule, replacer).trim();\r\n}\r\n\r\n/**\r\n * Creates a deep copy of the given object or array.\r\n *\r\n * @function deepCopy\r\n *\r\n * @param {(Object|Array)} objArr - The object or array to be deeply copied.\r\n *\r\n * @returns {(Object|Array)} The deep copy of the provided object or array.\r\n */\r\nexport function deepCopy(objArr) {\r\n // If the `objArr` is null or not of the `object` type, return it\r\n if (objArr === null || typeof objArr !== 'object') {\r\n return objArr;\r\n }\r\n\r\n // Prepare either a new array or a new object\r\n const objArrCopy = Array.isArray(objArr) ? [] : {};\r\n\r\n // Recursively copy each property\r\n for (const key in objArr) {\r\n if (Object.prototype.hasOwnProperty.call(objArr, key)) {\r\n objArrCopy[key] = deepCopy(objArr[key]);\r\n }\r\n }\r\n\r\n // Return the copied object\r\n return objArrCopy;\r\n}\r\n\r\n/**\r\n * Implements an exponential backoff strategy for retrying a function until\r\n * a certain number of attempts are reached.\r\n *\r\n * @async\r\n * @function expBackoff\r\n *\r\n * @param {Function} fn - The function to be retried.\r\n * @param {number} [attempt=0] - The current attempt number. The default value\r\n * is 0.\r\n * @param {...unknown} args - Arguments to be passed to the function.\r\n *\r\n * @returns {Promise} A Promise that resolves to the result\r\n * of the function if successful.\r\n *\r\n * @throws {Error} Throws an `Error` if the maximum number of attempts\r\n * is reached.\r\n */\r\nexport async function expBackoff(fn, attempt = 0, ...args) {\r\n try {\r\n // Try to call the function\r\n return await fn(...args);\r\n } catch (error) {\r\n // Calculate delay in ms\r\n const delayInMs = 2 ** attempt * 1000;\r\n\r\n // If the attempt exceeds the maximum attempts of repeat, throw an error\r\n if (++attempt >= MAX_BACKOFF_ATTEMPTS) {\r\n throw error;\r\n }\r\n\r\n // Wait given amount of time\r\n await new Promise((response) => setTimeout(response, delayInMs));\r\n\r\n /// TO DO: Correct\r\n // // Information about the resource timeout\r\n // log(\r\n // 3,\r\n // `[utils] Waited ${delayInMs}ms until next call for the resource of ID: ${args[0]}.`\r\n // );\r\n\r\n // Try again\r\n return expBackoff(fn, attempt, ...args);\r\n }\r\n}\r\n\r\n/**\r\n * Adjusts the constructor name by transforming and normalizing it based\r\n * on common chart types.\r\n *\r\n * @function fixConstr\r\n *\r\n * @param {string} constr - The original constructor name to be fixed.\r\n *\r\n * @returns {string} The corrected constructor name, or 'chart' if the input\r\n * is not recognized.\r\n */\r\nexport function fixConstr(constr) {\r\n try {\r\n // Fix the constructor by lowering casing\r\n const fixedConstr = `${constr.toLowerCase().replace('chart', '')}Chart`;\r\n\r\n // Handle the case where the result is just 'Chart'\r\n if (fixedConstr === 'Chart') {\r\n fixedConstr.toLowerCase();\r\n }\r\n\r\n // Return the corrected constructor, otherwise default to 'chart'\r\n return ['chart', 'stockChart', 'mapChart', 'ganttChart'].includes(\r\n fixedConstr\r\n )\r\n ? fixedConstr\r\n : 'chart';\r\n } catch {\r\n // Default to 'chart' in case of any error\r\n return 'chart';\r\n }\r\n}\r\n\r\n/**\r\n * Fixes the outfile based on provided type.\r\n *\r\n * @function fixOutfile\r\n *\r\n * @param {string} type - The original export type.\r\n * @param {string} outfile - The file path or name.\r\n *\r\n * @returns {string} The corrected outfile.\r\n */\r\nexport function fixOutfile(type, outfile) {\r\n // Get the file name from the `outfile` option\r\n const fileName = getAbsolutePath(outfile || 'chart')\r\n .split('.')\r\n .shift();\r\n\r\n // Return a correct outfile\r\n return `${fileName}.${type}`;\r\n}\r\n\r\n/**\r\n * Fixes the export type based on MIME types and file extensions.\r\n *\r\n * @function fixType\r\n *\r\n * @param {string} type - The original export type.\r\n * @param {string} [outfile=null] - The file path or name. The default value\r\n * is null.\r\n *\r\n * @returns {string} The corrected export type.\r\n */\r\nexport function fixType(type, outfile = null) {\r\n // MIME types\r\n const mimeTypes = {\r\n 'image/png': 'png',\r\n 'image/jpeg': 'jpeg',\r\n 'application/pdf': 'pdf',\r\n 'image/svg+xml': 'svg'\r\n };\r\n\r\n // Get formats\r\n const formats = Object.values(mimeTypes);\r\n\r\n // Check if type and outfile's extensions are the same\r\n if (outfile) {\r\n const outType = outfile.split('.').pop();\r\n\r\n // Support the JPG type\r\n if (outType === 'jpg') {\r\n type = 'jpeg';\r\n } else if (formats.includes(outType) && type !== outType) {\r\n type = outType;\r\n }\r\n }\r\n\r\n // Return a correct type\r\n return mimeTypes[type] || formats.find((t) => t === type) || 'png';\r\n}\r\n\r\n/**\r\n * Checks if the given path is relative or absolute and returns the corrected,\r\n * absolute path.\r\n *\r\n * @function isAbsolutePath\r\n *\r\n * @param {string} path - The path to be checked on.\r\n *\r\n * @returns {string} The absolute path.\r\n */\r\nexport function getAbsolutePath(path) {\r\n return isAbsolute(path) ? path : join(__dirname, path);\r\n}\r\n\r\n/**\r\n * Converts input data to a Base64 string based on the export type.\r\n *\r\n * @function getBase64\r\n *\r\n * @param {string} input - The input to be transformed to Base64 format.\r\n * @param {string} type - The original export type.\r\n *\r\n * @returns {string} The Base64 string representation of the input.\r\n */\r\nexport function getBase64(input, type) {\r\n // For pdf and svg types the input must be transformed to Base64 from a buffer\r\n if (type === 'pdf' || type == 'svg') {\r\n return Buffer.from(input, 'utf8').toString('base64');\r\n }\r\n\r\n // For png and jpeg input is already a Base64 string\r\n return input;\r\n}\r\n\r\n/**\r\n * Returns stringified date without the GMT text information.\r\n *\r\n * @function getNewDate\r\n */\r\nexport function getNewDate() {\r\n // Get rid of the GMT text information\r\n return new Date().toString().split('(')[0].trim();\r\n}\r\n\r\n/**\r\n * Returns the stored time value in milliseconds.\r\n *\r\n * @function getNewDateTime\r\n */\r\nexport function getNewDateTime() {\r\n return new Date().getTime();\r\n}\r\n\r\n/**\r\n * Checks if the given item is an object.\r\n *\r\n * @function isObject\r\n *\r\n * @param {unknown} item - The item to be checked.\r\n *\r\n * @returns {boolean} True if the item is an object, false otherwise.\r\n */\r\nexport function isObject(item) {\r\n return Object.prototype.toString.call(item) === '[object Object]';\r\n}\r\n\r\n/**\r\n * Checks if the given object is empty.\r\n *\r\n * @function isObjectEmpty\r\n *\r\n * @param {Object} item - The object to be checked.\r\n *\r\n * @returns {boolean} True if the object is empty, false otherwise.\r\n */\r\nexport function isObjectEmpty(item) {\r\n return (\r\n typeof item === 'object' &&\r\n !Array.isArray(item) &&\r\n item !== null &&\r\n Object.keys(item).length === 0\r\n );\r\n}\r\n\r\n/**\r\n * Checks if a private IP range URL is found in the given string.\r\n *\r\n * @function isPrivateRangeUrlFound\r\n *\r\n * @param {string} item - The string to be checked for a private IP range URL.\r\n *\r\n * @returns {boolean} True if a private IP range URL is found, false otherwise.\r\n */\r\nexport function isPrivateRangeUrlFound(item) {\r\n const regexPatterns = [\r\n /xlink:href=\"(?:http:\\/\\/|https:\\/\\/)?localhost\\b/,\r\n /xlink:href=\"(?:http:\\/\\/|https:\\/\\/)?10\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\b/,\r\n /xlink:href=\"(?:http:\\/\\/|https:\\/\\/)?127\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\b/,\r\n /xlink:href=\"(?:http:\\/\\/|https:\\/\\/)?172\\.(1[6-9]|2[0-9]|3[0-1])\\.\\d{1,3}\\.\\d{1,3}\\b/,\r\n /xlink:href=\"(?:http:\\/\\/|https:\\/\\/)?192\\.168\\.\\d{1,3}\\.\\d{1,3}\\b/\r\n ];\r\n\r\n return regexPatterns.some((pattern) => pattern.test(item));\r\n}\r\n\r\n/**\r\n * Utility to measure elapsed time using the Node.js `process.hrtime()` method.\r\n *\r\n * @function measureTime\r\n *\r\n * @returns {Function} A function to calculate the elapsed time in milliseconds.\r\n */\r\nexport function measureTime() {\r\n const start = process.hrtime.bigint();\r\n return () => Number(process.hrtime.bigint() - start) / 1000000;\r\n}\r\n\r\n/**\r\n * Rounds a number to the specified precision.\r\n *\r\n * @function roundNumber\r\n *\r\n * @param {number} value - The number to be rounded.\r\n * @param {number} precision - The number of decimal places to round to.\r\n *\r\n * @returns {number} The rounded number.\r\n */\r\nexport function roundNumber(value, precision = 1) {\r\n const multiplier = Math.pow(10, precision || 0);\r\n return Math.round(+value * multiplier) / multiplier;\r\n}\r\n\r\n/**\r\n * Converts a value to a boolean.\r\n *\r\n * @function toBoolean\r\n *\r\n * @param {unknown} item - The value to be converted to a boolean.\r\n *\r\n * @returns {boolean} The boolean representation of the input value.\r\n */\r\nexport function toBoolean(item) {\r\n return ['false', 'undefined', 'null', 'NaN', '0', ''].includes(item)\r\n ? false\r\n : !!item;\r\n}\r\n\r\n/**\r\n * Wraps custom code to execute it safely.\r\n *\r\n * @function wrapAround\r\n *\r\n * @param {string} customCode - The custom code to be wrapped.\r\n * @param {boolean} allowFileResources - Flag to allow loading code from a file.\r\n * @param {boolean} [isCallback=false] - Flag that indicates the returned code\r\n * must be in a callback format.\r\n *\r\n * @returns {(string|null)} The wrapped custom code or null if wrapping fails.\r\n */\r\nexport function wrapAround(customCode, allowFileResources, isCallback = false) {\r\n if (customCode && typeof customCode === 'string') {\r\n customCode = customCode.trim();\r\n\r\n if (customCode.endsWith('.js')) {\r\n // Load a file if the file resources are allowed\r\n return allowFileResources\r\n ? wrapAround(\r\n readFileSync(getAbsolutePath(customCode), 'utf8'),\r\n allowFileResources,\r\n isCallback\r\n )\r\n : null;\r\n } else if (\r\n !isCallback &&\r\n (customCode.startsWith('function()') ||\r\n customCode.startsWith('function ()') ||\r\n customCode.startsWith('()=>') ||\r\n customCode.startsWith('() =>'))\r\n ) {\r\n // Treat a function as a self-invoking expression\r\n return `(${customCode})()`;\r\n }\r\n\r\n // Or return as a stringified code\r\n return customCode.replace(/;$/, '');\r\n }\r\n}\r\n\r\nexport default {\r\n __dirname,\r\n clearText,\r\n deepCopy,\r\n expBackoff,\r\n fixConstr,\r\n fixOutfile,\r\n fixType,\r\n getAbsolutePath,\r\n getBase64,\r\n getNewDate,\r\n getNewDateTime,\r\n isObject,\r\n isObjectEmpty,\r\n isPrivateRangeUrlFound,\r\n measureTime,\r\n roundNumber,\r\n toBoolean,\r\n wrapAround\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * @overview A module for managing logging functionality with customizable\r\n * log levels, console and file logging options, and error handling support.\r\n * The module also ensures that file-based logs are stored in a structured\r\n * directory, creating the necessary paths automatically if they do not exist.\r\n */\r\n\r\nimport { appendFile, existsSync, mkdirSync } from 'fs';\r\nimport { join } from 'path';\r\n\r\nimport { getAbsolutePath, getNewDate } from './utils.js';\r\n\r\n// The available colors\r\nconst colors = ['red', 'yellow', 'blue', 'gray', 'green'];\r\n\r\n// The default logging config\r\nconst logging = {\r\n // Flags for logging status\r\n toConsole: true,\r\n toFile: false,\r\n pathCreated: false,\r\n // Full path to the log file\r\n pathToLog: '',\r\n // Log levels\r\n levelsDesc: [\r\n {\r\n title: 'error',\r\n color: colors[0]\r\n },\r\n {\r\n title: 'warning',\r\n color: colors[1]\r\n },\r\n {\r\n title: 'notice',\r\n color: colors[2]\r\n },\r\n {\r\n title: 'verbose',\r\n color: colors[3]\r\n },\r\n {\r\n title: 'benchmark',\r\n color: colors[4]\r\n }\r\n ]\r\n};\r\n\r\n/**\r\n * Logs a message. Accepts a variable amount of arguments. Arguments after\r\n * the `level` will be passed directly to `console.log`, and/or will be joined\r\n * and appended to the log file.\r\n *\r\n * @function log\r\n *\r\n * @param {...unknown} args - An array of arguments where the first is the log\r\n * level and the rest are strings to build a message with.\r\n *\r\n * @returns {void} Ends the function execution when attempting to log\r\n * information at a higher level than what is allowed.\r\n */\r\nexport function log(...args) {\r\n const [newLevel, ...texts] = args;\r\n\r\n // Current logging options\r\n const { levelsDesc, level } = logging;\r\n\r\n // Check if the log level is within a correct range or is it a benchmark log\r\n if (\r\n newLevel !== 5 &&\r\n (newLevel === 0 || newLevel > level || level > levelsDesc.length)\r\n ) {\r\n return;\r\n }\r\n\r\n // Create a message's prefix\r\n const prefix = `${getNewDate()} [${levelsDesc[newLevel - 1].title}] -`;\r\n\r\n // Log to file\r\n if (logging.toFile) {\r\n _logToFile(texts, prefix);\r\n }\r\n\r\n // Log to console\r\n if (logging.toConsole) {\r\n console.log.apply(\r\n undefined,\r\n [prefix.toString()[logging.levelsDesc[newLevel - 1].color]].concat(texts)\r\n );\r\n }\r\n}\r\n\r\n/**\r\n * Logs an error message with its stack trace. Optionally, a custom message\r\n * can be provided.\r\n *\r\n * @function logWithStack\r\n *\r\n * @param {number} newLevel - The log level.\r\n * @param {Error} error - The error object.\r\n * @param {string} customMessage - An optional custom message to be logged\r\n * along with the error.\r\n *\r\n * @returns {void} Ends the function execution when attempting to log\r\n * information at a higher level than what is allowed.\r\n */\r\nexport function logWithStack(newLevel, error, customMessage) {\r\n // Get the main message\r\n const mainMessage = customMessage || error.message;\r\n\r\n // Current logging options\r\n const { level, levelsDesc } = logging;\r\n\r\n // Check if the log level is within a correct range\r\n if (newLevel === 0 || newLevel > level || level > levelsDesc.length) {\r\n return;\r\n }\r\n\r\n // Create a message's prefix\r\n const prefix = `${getNewDate()} [${levelsDesc[newLevel - 1].title}] -`;\r\n\r\n // Add the whole stack message\r\n const stackMessage = error.stack;\r\n\r\n // Combine custom message or error message with error stack message, if exists\r\n const texts = [mainMessage];\r\n if (stackMessage) {\r\n texts.push('\\n', stackMessage);\r\n }\r\n\r\n // Log to file\r\n if (logging.toFile) {\r\n _logToFile(texts, prefix);\r\n }\r\n\r\n // Log to console\r\n if (logging.toConsole) {\r\n console.log.apply(\r\n undefined,\r\n [prefix.toString()[logging.levelsDesc[newLevel - 1].color]].concat([\r\n texts.shift()[colors[newLevel - 1]],\r\n ...texts\r\n ])\r\n );\r\n }\r\n}\r\n\r\n/**\r\n * Logs an error message about Zod issues with the validation. Optionally,\r\n * a custom message can be provided.\r\n *\r\n * @function logZodIssues\r\n *\r\n * @param {number} newLevel - The log level.\r\n * @param {Error[]} issues - The array of Zod issues.\r\n * @param {string} customMessage - An optional custom message to be logged\r\n * along with the error.\r\n */\r\nexport function logZodIssues(newLevel, issues = [], customMessage) {\r\n logWithStack(\r\n newLevel,\r\n null,\r\n [\r\n `${customMessage} - the following Zod issues occured:`,\r\n ...issues.map((issue) => `- ${issue.message}`)\r\n ].join('\\n')\r\n );\r\n}\r\n\r\n/**\r\n * Initializes logging with the specified logging configuration.\r\n *\r\n * @function initLogging\r\n *\r\n * @param {Object} loggingOptions - Object containing `logging` options.\r\n */\r\nexport function initLogging(loggingOptions) {\r\n // Get options from the `loggingOptions` object\r\n const { level, dest, file, toConsole, toFile } = loggingOptions;\r\n\r\n // Set the logging level\r\n setLogLevel(level);\r\n\r\n // Set the console logging\r\n enableConsoleLogging(toConsole);\r\n\r\n // Set the file logging\r\n enableFileLogging(dest, file, toFile);\r\n}\r\n\r\n/**\r\n * Sets the log level to the specified value. Log levels are (0 = no logging,\r\n * 1 = error, 2 = warning, 3 = notice, 4 = verbose, or 5 = benchmark).\r\n *\r\n * @function setLogLevel\r\n *\r\n * @param {number} level - The log level to be set.\r\n */\r\nexport function setLogLevel(level) {\r\n if (level >= 0 && level <= logging.levelsDesc.length) {\r\n logging.level = level;\r\n }\r\n}\r\n\r\n/**\r\n * Enables console logging.\r\n *\r\n * @function enableConsoleLogging\r\n *\r\n * @param {boolean} toConsole - The flag for setting the logging to the console.\r\n */\r\nexport function enableConsoleLogging(toConsole) {\r\n // Update options for the console logging\r\n logging.toConsole = toConsole;\r\n}\r\n\r\n/**\r\n * Enables file logging with the specified destination and log file.\r\n *\r\n * @function enableFileLogging\r\n *\r\n * @param {string} dest - The destination path for the log file.\r\n * @param {string} file - The log file name.\r\n * @param {boolean} toFile - The flag for setting the logging to a file.\r\n */\r\nexport function enableFileLogging(dest, file, toFile) {\r\n // Update options for the file logging\r\n logging.toFile = toFile;\r\n\r\n // Set the `dest` and `file` only if the file logging is enabled\r\n if (toFile) {\r\n logging.dest = dest;\r\n logging.file = file;\r\n }\r\n}\r\n\r\n/**\r\n * Logs the provided texts to a file, if file logging is enabled. It creates\r\n * the necessary directory structure if not already created and appends\r\n * the content, including an optional prefix, to the specified log file.\r\n *\r\n * @function _logToFile\r\n *\r\n * @param {Array.} texts - An array of texts to be logged.\r\n * @param {string} prefix - An optional prefix to be added to each log entry.\r\n */\r\nfunction _logToFile(texts, prefix) {\r\n if (!logging.pathCreated) {\r\n // Create if does not exist\r\n !existsSync(getAbsolutePath(logging.dest)) &&\r\n mkdirSync(getAbsolutePath(logging.dest));\r\n\r\n // Create the full path\r\n logging.pathToLog = getAbsolutePath(join(logging.dest, logging.file));\r\n\r\n // We now assume the path is available, e.g. it's the responsibility\r\n // of the user to create the path with the correct access rights.\r\n logging.pathCreated = true;\r\n }\r\n\r\n // Add the content to a file\r\n appendFile(\r\n logging.pathToLog,\r\n [prefix].concat(texts).join(' ') + '\\n',\r\n (error) => {\r\n if (error && logging.toFile && logging.pathCreated) {\r\n logging.toFile = false;\r\n logging.pathCreated = false;\r\n logWithStack(2, error, `[logger] Unable to write to log file.`);\r\n }\r\n }\r\n );\r\n}\r\n\r\nexport default {\r\n log,\r\n logWithStack,\r\n logZodIssues,\r\n initLogging,\r\n setLogLevel,\r\n enableConsoleLogging,\r\n enableFileLogging\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * @overview Configuration management module for the Highcharts Export Server.\r\n * Provides default configurations that support environment variables, CLI\r\n * arguments, and interactive prompts for customization of options and features.\r\n * Additionally, it maps legacy options to modern structures, generates nested\r\n * argument mappings, and displays CLI usage information.\r\n */\r\n\r\n/**\r\n * The configuration object containing all available options, organized\r\n * by sections.\r\n *\r\n * This object includes:\r\n * - Default values for each option\r\n * - Data types for validation\r\n * - Names of corresponding environment variables\r\n * - Descriptions of each property\r\n * - Information used for prompts in interactive configuration\r\n * - [Optional] Corresponding CLI argument names for CLI usage\r\n * - [Optional] Legacy names from the previous PhantomJS-based server\r\n */\r\nexport const defaultConfig = {\r\n puppeteer: {\r\n args: {\r\n value: [\r\n '--allow-running-insecure-content',\r\n '--ash-no-nudges',\r\n '--autoplay-policy=user-gesture-required',\r\n '--block-new-web-contents',\r\n '--disable-accelerated-2d-canvas',\r\n '--disable-background-networking',\r\n '--disable-background-timer-throttling',\r\n '--disable-backgrounding-occluded-windows',\r\n '--disable-breakpad',\r\n '--disable-checker-imaging',\r\n '--disable-client-side-phishing-detection',\r\n '--disable-component-extensions-with-background-pages',\r\n '--disable-component-update',\r\n '--disable-default-apps',\r\n '--disable-dev-shm-usage',\r\n '--disable-domain-reliability',\r\n '--disable-extensions',\r\n '--disable-features=CalculateNativeWinOcclusion,InterestFeedContentSuggestions,WebOTP',\r\n '--disable-hang-monitor',\r\n '--disable-ipc-flooding-protection',\r\n '--disable-logging',\r\n '--disable-notifications',\r\n '--disable-offer-store-unmasked-wallet-cards',\r\n '--disable-popup-blocking',\r\n '--disable-print-preview',\r\n '--disable-prompt-on-repost',\r\n '--disable-renderer-backgrounding',\r\n '--disable-search-engine-choice-screen',\r\n '--disable-session-crashed-bubble',\r\n '--disable-setuid-sandbox',\r\n '--disable-site-isolation-trials',\r\n '--disable-speech-api',\r\n '--disable-sync',\r\n '--enable-unsafe-webgpu',\r\n '--hide-crash-restore-bubble',\r\n '--hide-scrollbars',\r\n '--metrics-recording-only',\r\n '--mute-audio',\r\n '--no-default-browser-check',\r\n '--no-first-run',\r\n '--no-pings',\r\n '--no-sandbox',\r\n '--no-startup-window',\r\n '--no-zygote',\r\n '--password-store=basic',\r\n '--process-per-tab',\r\n '--use-mock-keychain'\r\n ],\r\n types: ['string[]'],\r\n envLink: 'PUPPETEER_ARGS',\r\n cliName: 'puppeteerArgs',\r\n description: 'Array of Puppeteer arguments',\r\n promptOptions: {\r\n type: 'list',\r\n separator: ';'\r\n }\r\n }\r\n },\r\n highcharts: {\r\n version: {\r\n value: 'latest',\r\n types: ['string'],\r\n envLink: 'HIGHCHARTS_VERSION',\r\n description: 'Highcharts version',\r\n promptOptions: {\r\n type: 'text'\r\n }\r\n },\r\n cdnUrl: {\r\n value: 'https://code.highcharts.com',\r\n types: ['string'],\r\n envLink: 'HIGHCHARTS_CDN_URL',\r\n description: 'CDN URL for Highcharts scripts',\r\n promptOptions: {\r\n type: 'text'\r\n }\r\n },\r\n forceFetch: {\r\n value: false,\r\n types: ['boolean'],\r\n envLink: 'HIGHCHARTS_FORCE_FETCH',\r\n description: 'Flag to refetch scripts after each server rerun',\r\n promptOptions: {\r\n type: 'toggle'\r\n }\r\n },\r\n cachePath: {\r\n value: '.cache',\r\n types: ['string'],\r\n envLink: 'HIGHCHARTS_CACHE_PATH',\r\n description: 'Directory path for cached Highcharts scripts',\r\n promptOptions: {\r\n type: 'text'\r\n }\r\n },\r\n coreScripts: {\r\n value: ['highcharts', 'highcharts-more', 'highcharts-3d'],\r\n types: ['string[]'],\r\n envLink: 'HIGHCHARTS_CORE_SCRIPTS',\r\n description: 'Highcharts core scripts to fetch',\r\n promptOptions: {\r\n type: 'multiselect',\r\n instructions: 'Space: Select specific, A: Select all, Enter: Confirm'\r\n }\r\n },\r\n moduleScripts: {\r\n value: [\r\n 'stock',\r\n 'map',\r\n 'gantt',\r\n 'exporting',\r\n 'parallel-coordinates',\r\n 'accessibility',\r\n // 'annotations-advanced',\r\n 'boost-canvas',\r\n 'boost',\r\n 'data',\r\n 'data-tools',\r\n 'draggable-points',\r\n 'static-scale',\r\n 'broken-axis',\r\n 'heatmap',\r\n 'tilemap',\r\n 'tiledwebmap',\r\n 'timeline',\r\n 'treemap',\r\n 'treegraph',\r\n 'item-series',\r\n 'drilldown',\r\n 'histogram-bellcurve',\r\n 'bullet',\r\n 'funnel',\r\n 'funnel3d',\r\n 'geoheatmap',\r\n 'pyramid3d',\r\n 'networkgraph',\r\n 'overlapping-datalabels',\r\n 'pareto',\r\n 'pattern-fill',\r\n 'pictorial',\r\n 'price-indicator',\r\n 'sankey',\r\n 'arc-diagram',\r\n 'dependency-wheel',\r\n 'series-label',\r\n 'series-on-point',\r\n 'solid-gauge',\r\n 'sonification',\r\n // 'stock-tools',\r\n 'streamgraph',\r\n 'sunburst',\r\n 'variable-pie',\r\n 'variwide',\r\n 'vector',\r\n 'venn',\r\n 'windbarb',\r\n 'wordcloud',\r\n 'xrange',\r\n 'no-data-to-display',\r\n 'drag-panes',\r\n 'debugger',\r\n 'dumbbell',\r\n 'lollipop',\r\n 'cylinder',\r\n 'organization',\r\n 'dotplot',\r\n 'marker-clusters',\r\n 'hollowcandlestick',\r\n 'heikinashi',\r\n 'flowmap',\r\n 'export-data',\r\n 'navigator',\r\n 'textpath'\r\n ],\r\n types: ['string[]'],\r\n envLink: 'HIGHCHARTS_MODULE_SCRIPTS',\r\n description: 'Highcharts module scripts to fetch',\r\n promptOptions: {\r\n type: 'multiselect',\r\n instructions: 'Space: Select specific, A: Select all, Enter: Confirm'\r\n }\r\n },\r\n indicatorScripts: {\r\n value: ['indicators-all'],\r\n types: ['string[]'],\r\n envLink: 'HIGHCHARTS_INDICATOR_SCRIPTS',\r\n description: 'Highcharts indicator scripts to fetch',\r\n promptOptions: {\r\n type: 'multiselect',\r\n instructions: 'Space: Select specific, A: Select all, Enter: Confirm'\r\n }\r\n },\r\n customScripts: {\r\n value: [\r\n 'https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.30.1/moment.min.js',\r\n 'https://cdnjs.cloudflare.com/ajax/libs/moment-timezone/0.5.45/moment-timezone-with-data.min.js'\r\n ],\r\n types: ['string[]'],\r\n envLink: 'HIGHCHARTS_CUSTOM_SCRIPTS',\r\n description: 'Additional custom scripts or dependencies to fetch',\r\n promptOptions: {\r\n type: 'list',\r\n separator: ';'\r\n }\r\n }\r\n },\r\n export: {\r\n infile: {\r\n value: null,\r\n types: ['string', 'null'],\r\n envLink: 'EXPORT_INFILE',\r\n description:\r\n 'Input filename with type, formatted correctly as JSON or SVG',\r\n promptOptions: {\r\n type: 'text'\r\n }\r\n },\r\n instr: {\r\n value: null,\r\n types: ['string', 'null'],\r\n envLink: 'EXPORT_INSTR',\r\n description:\r\n 'Overrides the `infile` with JSON, stringified JSON, or SVG input',\r\n promptOptions: {\r\n type: 'text'\r\n }\r\n },\r\n options: {\r\n value: null,\r\n types: ['Object', 'null'],\r\n envLink: 'EXPORT_OPTIONS',\r\n description: 'Alias for the `instr` option',\r\n promptOptions: {\r\n type: 'text'\r\n }\r\n },\r\n svg: {\r\n value: null,\r\n types: ['string', 'null'],\r\n envLink: 'EXPORT_SVG',\r\n description: 'SVG string representation of the chart to render',\r\n promptOptions: {\r\n type: 'text'\r\n }\r\n },\r\n batch: {\r\n value: null,\r\n types: ['string', 'null'],\r\n envLink: 'EXPORT_BATCH',\r\n description:\r\n 'Batch job string with input/output pairs: \"in=out;in=out;...\"',\r\n promptOptions: {\r\n type: 'text'\r\n }\r\n },\r\n outfile: {\r\n value: null,\r\n types: ['string', 'null'],\r\n envLink: 'EXPORT_OUTFILE',\r\n description:\r\n 'Output filename with type. Can be jpeg, png, pdf, or svg and ignores `type` option',\r\n promptOptions: {\r\n type: 'text'\r\n }\r\n },\r\n type: {\r\n value: 'png',\r\n types: ['string'],\r\n envLink: 'EXPORT_TYPE',\r\n description: 'File export format. Can be jpeg, png, pdf, or svg',\r\n promptOptions: {\r\n type: 'select',\r\n hint: 'Default: png',\r\n choices: ['png', 'jpeg', 'pdf', 'svg']\r\n }\r\n },\r\n constr: {\r\n value: 'chart',\r\n types: ['string'],\r\n envLink: 'EXPORT_CONSTR',\r\n description:\r\n 'Chart constructor. Can be chart, stockChart, mapChart, or ganttChart',\r\n promptOptions: {\r\n type: 'select',\r\n hint: 'Default: chart',\r\n choices: ['chart', 'stockChart', 'mapChart', 'ganttChart']\r\n }\r\n },\r\n b64: {\r\n value: false,\r\n types: ['boolean'],\r\n envLink: 'EXPORT_B64',\r\n description:\r\n 'Whether or not to the chart should be received in Base64 format instead of binary',\r\n promptOptions: {\r\n type: 'toggle'\r\n }\r\n },\r\n noDownload: {\r\n value: false,\r\n types: ['boolean'],\r\n envLink: 'EXPORT_NO_DOWNLOAD',\r\n description:\r\n 'Whether or not to include or exclude attachment headers in the response',\r\n promptOptions: {\r\n type: 'toggle'\r\n }\r\n },\r\n height: {\r\n value: null,\r\n types: ['number', 'null'],\r\n envLink: 'EXPORT_HEIGHT',\r\n description: 'Height of the exported chart, overrides chart settings',\r\n promptOptions: {\r\n type: 'number'\r\n }\r\n },\r\n width: {\r\n value: null,\r\n types: ['number', 'null'],\r\n envLink: 'EXPORT_WIDTH',\r\n description: 'Width of the exported chart, overrides chart settings',\r\n promptOptions: {\r\n type: 'number'\r\n }\r\n },\r\n scale: {\r\n value: null,\r\n types: ['number', 'null'],\r\n envLink: 'EXPORT_SCALE',\r\n description:\r\n 'Scale of the exported chart, overrides chart settings. Ranges from 0.1 to 5.0',\r\n promptOptions: {\r\n type: 'number'\r\n }\r\n },\r\n defaultHeight: {\r\n value: 400,\r\n types: ['number'],\r\n envLink: 'EXPORT_DEFAULT_HEIGHT',\r\n description: 'Default height of the exported chart if not set',\r\n promptOptions: {\r\n type: 'number'\r\n }\r\n },\r\n defaultWidth: {\r\n value: 600,\r\n types: ['number'],\r\n envLink: 'EXPORT_DEFAULT_WIDTH',\r\n description: 'Default width of the exported chart if not set',\r\n promptOptions: {\r\n type: 'number'\r\n }\r\n },\r\n defaultScale: {\r\n value: 1,\r\n types: ['number'],\r\n envLink: 'EXPORT_DEFAULT_SCALE',\r\n description:\r\n 'Default scale of the exported chart if not set. Ranges from 0.1 to 5.0',\r\n promptOptions: {\r\n type: 'number',\r\n min: 0.1,\r\n max: 5\r\n }\r\n },\r\n globalOptions: {\r\n value: null,\r\n types: ['Object', 'string', 'null'],\r\n envLink: 'EXPORT_GLOBAL_OPTIONS',\r\n description:\r\n 'JSON, stringified JSON or filename with global options for Highcharts.setOptions',\r\n promptOptions: {\r\n type: 'text'\r\n }\r\n },\r\n themeOptions: {\r\n value: null,\r\n types: ['Object', 'string', 'null'],\r\n envLink: 'EXPORT_THEME_OPTIONS',\r\n description:\r\n 'JSON, stringified JSON or filename with theme options for Highcharts.setOptions',\r\n promptOptions: {\r\n type: 'text'\r\n }\r\n },\r\n rasterizationTimeout: {\r\n value: 1500,\r\n types: ['number'],\r\n envLink: 'EXPORT_RASTERIZATION_TIMEOUT',\r\n description: 'Milliseconds to wait for webpage rendering',\r\n promptOptions: {\r\n type: 'number'\r\n }\r\n }\r\n },\r\n customLogic: {\r\n allowCodeExecution: {\r\n value: false,\r\n types: ['boolean'],\r\n envLink: 'CUSTOM_LOGIC_ALLOW_CODE_EXECUTION',\r\n description:\r\n 'Allows or disallows execution of arbitrary code during exporting',\r\n promptOptions: {\r\n type: 'toggle'\r\n }\r\n },\r\n allowFileResources: {\r\n value: false,\r\n types: ['boolean'],\r\n envLink: 'CUSTOM_LOGIC_ALLOW_FILE_RESOURCES',\r\n description:\r\n 'Allows or disallows injection of filesystem resources (disabled in server mode)',\r\n promptOptions: {\r\n type: 'toggle'\r\n }\r\n },\r\n customCode: {\r\n value: null,\r\n types: ['string', 'null'],\r\n envLink: 'CUSTOM_LOGIC_CUSTOM_CODE',\r\n description:\r\n 'Custom code to execute before chart initialization. Can be a function, code wrapped in a function, or a .js filename',\r\n promptOptions: {\r\n type: 'text'\r\n }\r\n },\r\n callback: {\r\n value: null,\r\n types: ['string', 'null'],\r\n envLink: 'CUSTOM_LOGIC_CALLBACK',\r\n description:\r\n 'JavaScript code to run during construction. Can be a function or a .js filename',\r\n promptOptions: {\r\n type: 'text'\r\n }\r\n },\r\n resources: {\r\n value: null,\r\n types: ['Object', 'string', 'null'],\r\n envLink: 'CUSTOM_LOGIC_RESOURCES',\r\n description:\r\n 'Additional resources as JSON, stringified JSON, or filename, containing files, js, and css sections',\r\n promptOptions: {\r\n type: 'text'\r\n }\r\n },\r\n loadConfig: {\r\n value: null,\r\n types: ['string', 'null'],\r\n envLink: 'CUSTOM_LOGIC_LOAD_CONFIG',\r\n legacyName: 'fromFile',\r\n description: 'File with a pre-defined configuration to use',\r\n promptOptions: {\r\n type: 'text'\r\n }\r\n },\r\n createConfig: {\r\n value: null,\r\n types: ['string', 'null'],\r\n envLink: 'CUSTOM_LOGIC_CREATE_CONFIG',\r\n description:\r\n 'Prompt-based option setting, saved to a provided config file',\r\n promptOptions: {\r\n type: 'text'\r\n }\r\n }\r\n },\r\n server: {\r\n enable: {\r\n value: false,\r\n types: ['boolean'],\r\n envLink: 'SERVER_ENABLE',\r\n cliName: 'enableServer',\r\n description: 'Starts the server when true',\r\n promptOptions: {\r\n type: 'toggle'\r\n }\r\n },\r\n host: {\r\n value: '0.0.0.0',\r\n types: ['string'],\r\n envLink: 'SERVER_HOST',\r\n description: 'Hostname of the server',\r\n promptOptions: {\r\n type: 'text'\r\n }\r\n },\r\n port: {\r\n value: 7801,\r\n types: ['number'],\r\n envLink: 'SERVER_PORT',\r\n description: 'Port number for the server',\r\n promptOptions: {\r\n type: 'number'\r\n }\r\n },\r\n uploadLimit: {\r\n value: 3,\r\n types: ['number'],\r\n envLink: 'SERVER_UPLOAD_LIMIT',\r\n description: 'Maximum request body size in MB',\r\n promptOptions: {\r\n type: 'number'\r\n }\r\n },\r\n benchmarking: {\r\n value: false,\r\n types: ['boolean'],\r\n envLink: 'SERVER_BENCHMARKING',\r\n cliName: 'serverBenchmarking',\r\n description:\r\n 'Displays or not action durations in milliseconds during server requests',\r\n promptOptions: {\r\n type: 'toggle'\r\n }\r\n },\r\n proxy: {\r\n host: {\r\n value: null,\r\n types: ['string', 'null'],\r\n envLink: 'SERVER_PROXY_HOST',\r\n cliName: 'proxyHost',\r\n description: 'Host of the proxy server, if applicable',\r\n promptOptions: {\r\n type: 'text'\r\n }\r\n },\r\n port: {\r\n value: null,\r\n types: ['number', 'null'],\r\n envLink: 'SERVER_PROXY_PORT',\r\n cliName: 'proxyPort',\r\n description: 'Port of the proxy server, if applicable',\r\n promptOptions: {\r\n type: 'number'\r\n }\r\n },\r\n timeout: {\r\n value: 5000,\r\n types: ['number'],\r\n envLink: 'SERVER_PROXY_TIMEOUT',\r\n cliName: 'proxyTimeout',\r\n description:\r\n 'Timeout in milliseconds for the proxy server, if applicable',\r\n promptOptions: {\r\n type: 'number'\r\n }\r\n }\r\n },\r\n rateLimiting: {\r\n enable: {\r\n value: false,\r\n types: ['boolean'],\r\n envLink: 'SERVER_RATE_LIMITING_ENABLE',\r\n cliName: 'enableRateLimiting',\r\n description: 'Enables or disables rate limiting on the server',\r\n promptOptions: {\r\n type: 'toggle'\r\n }\r\n },\r\n maxRequests: {\r\n value: 10,\r\n types: ['number'],\r\n envLink: 'SERVER_RATE_LIMITING_MAX_REQUESTS',\r\n legacyName: 'rateLimit',\r\n description: 'Maximum number of requests allowed per minute',\r\n promptOptions: {\r\n type: 'number'\r\n }\r\n },\r\n window: {\r\n value: 1,\r\n types: ['number'],\r\n envLink: 'SERVER_RATE_LIMITING_WINDOW',\r\n description: 'Time window in minutes for rate limiting',\r\n promptOptions: {\r\n type: 'number'\r\n }\r\n },\r\n delay: {\r\n value: 0,\r\n types: ['number'],\r\n envLink: 'SERVER_RATE_LIMITING_DELAY',\r\n description:\r\n 'Delay duration between successive requests before reaching the limit',\r\n promptOptions: {\r\n type: 'number'\r\n }\r\n },\r\n trustProxy: {\r\n value: false,\r\n types: ['boolean'],\r\n envLink: 'SERVER_RATE_LIMITING_TRUST_PROXY',\r\n description: 'Set to true if the server is behind a load balancer',\r\n promptOptions: {\r\n type: 'toggle'\r\n }\r\n },\r\n skipKey: {\r\n value: null,\r\n types: ['string', 'null'],\r\n envLink: 'SERVER_RATE_LIMITING_SKIP_KEY',\r\n description: 'Key to bypass the rate limiter, used with `skipToken`',\r\n promptOptions: {\r\n type: 'text'\r\n }\r\n },\r\n skipToken: {\r\n value: null,\r\n types: ['string', 'null'],\r\n envLink: 'SERVER_RATE_LIMITING_SKIP_TOKEN',\r\n description: 'Token to bypass the rate limiter, used with `skipKey`',\r\n promptOptions: {\r\n type: 'text'\r\n }\r\n }\r\n },\r\n ssl: {\r\n enable: {\r\n value: false,\r\n types: ['boolean'],\r\n envLink: 'SERVER_SSL_ENABLE',\r\n cliName: 'enableSsl',\r\n description: 'Enables or disables SSL protocol',\r\n promptOptions: {\r\n type: 'toggle'\r\n }\r\n },\r\n force: {\r\n value: false,\r\n types: ['boolean'],\r\n envLink: 'SERVER_SSL_FORCE',\r\n cliName: 'sslForce',\r\n legacyName: 'sslOnly',\r\n description: 'Forces the server to use HTTPS only when true',\r\n promptOptions: {\r\n type: 'toggle'\r\n }\r\n },\r\n port: {\r\n value: 443,\r\n types: ['number'],\r\n envLink: 'SERVER_SSL_PORT',\r\n cliName: 'sslPort',\r\n description: 'Port for the SSL server',\r\n promptOptions: {\r\n type: 'number'\r\n }\r\n },\r\n certPath: {\r\n value: null,\r\n types: ['string', 'null'],\r\n envLink: 'SERVER_SSL_CERT_PATH',\r\n cliName: 'sslCertPath',\r\n legacyName: 'sslPath',\r\n description: 'Path to the SSL certificate/key file',\r\n promptOptions: {\r\n type: 'text'\r\n }\r\n }\r\n }\r\n },\r\n pool: {\r\n minWorkers: {\r\n value: 4,\r\n types: ['number'],\r\n envLink: 'POOL_MIN_WORKERS',\r\n description: 'Minimum and initial number of pool workers to spawn',\r\n promptOptions: {\r\n type: 'number'\r\n }\r\n },\r\n maxWorkers: {\r\n value: 8,\r\n types: ['number'],\r\n envLink: 'POOL_MAX_WORKERS',\r\n legacyName: 'workers',\r\n description: 'Maximum number of pool workers to spawn',\r\n promptOptions: {\r\n type: 'number'\r\n }\r\n },\r\n workLimit: {\r\n value: 40,\r\n types: ['number'],\r\n envLink: 'POOL_WORK_LIMIT',\r\n description: 'Number of tasks a worker can handle before restarting',\r\n promptOptions: {\r\n type: 'number'\r\n }\r\n },\r\n acquireTimeout: {\r\n value: 5000,\r\n types: ['number'],\r\n envLink: 'POOL_ACQUIRE_TIMEOUT',\r\n description: 'Timeout in milliseconds for acquiring a resource',\r\n promptOptions: {\r\n type: 'number'\r\n }\r\n },\r\n createTimeout: {\r\n value: 5000,\r\n types: ['number'],\r\n envLink: 'POOL_CREATE_TIMEOUT',\r\n description: 'Timeout in milliseconds for creating a resource',\r\n promptOptions: {\r\n type: 'number'\r\n }\r\n },\r\n destroyTimeout: {\r\n value: 5000,\r\n types: ['number'],\r\n envLink: 'POOL_DESTROY_TIMEOUT',\r\n description: 'Timeout in milliseconds for destroying a resource',\r\n promptOptions: {\r\n type: 'number'\r\n }\r\n },\r\n idleTimeout: {\r\n value: 30000,\r\n types: ['number'],\r\n envLink: 'POOL_IDLE_TIMEOUT',\r\n description: 'Timeout in milliseconds for destroying idle resources',\r\n promptOptions: {\r\n type: 'number'\r\n }\r\n },\r\n createRetryInterval: {\r\n value: 200,\r\n types: ['number'],\r\n envLink: 'POOL_CREATE_RETRY_INTERVAL',\r\n description:\r\n 'Interval in milliseconds before retrying resource creation on failure',\r\n promptOptions: {\r\n type: 'number'\r\n }\r\n },\r\n reaperInterval: {\r\n value: 1000,\r\n types: ['number'],\r\n envLink: 'POOL_REAPER_INTERVAL',\r\n description:\r\n 'Interval in milliseconds to check and destroy idle resources',\r\n promptOptions: {\r\n type: 'number'\r\n }\r\n },\r\n benchmarking: {\r\n value: false,\r\n types: ['boolean'],\r\n envLink: 'POOL_BENCHMARKING',\r\n cliName: 'poolBenchmarking',\r\n description: 'Shows statistics for the pool of resources',\r\n promptOptions: {\r\n type: 'toggle'\r\n }\r\n }\r\n },\r\n logging: {\r\n level: {\r\n value: 4,\r\n types: ['number'],\r\n envLink: 'LOGGING_LEVEL',\r\n cliName: 'logLevel',\r\n description: 'Logging verbosity level',\r\n promptOptions: {\r\n type: 'number',\r\n round: 0,\r\n min: 0,\r\n max: 5\r\n }\r\n },\r\n file: {\r\n value: 'highcharts-export-server.log',\r\n types: ['string'],\r\n envLink: 'LOGGING_FILE',\r\n cliName: 'logFile',\r\n description:\r\n 'Log file name. Requires `logToFile` and `logDest` to be set',\r\n promptOptions: {\r\n type: 'text'\r\n }\r\n },\r\n dest: {\r\n value: 'log',\r\n types: ['string'],\r\n envLink: 'LOGGING_DEST',\r\n cliName: 'logDest',\r\n description: 'Path to store log files. Requires `logToFile` to be set',\r\n promptOptions: {\r\n type: 'text'\r\n }\r\n },\r\n toConsole: {\r\n value: true,\r\n types: ['boolean'],\r\n envLink: 'LOGGING_TO_CONSOLE',\r\n cliName: 'logToConsole',\r\n description: 'Enables or disables console logging',\r\n promptOptions: {\r\n type: 'toggle'\r\n }\r\n },\r\n toFile: {\r\n value: true,\r\n types: ['boolean'],\r\n envLink: 'LOGGING_TO_FILE',\r\n cliName: 'logToFile',\r\n description: 'Enables or disables logging to a file',\r\n promptOptions: {\r\n type: 'toggle'\r\n }\r\n }\r\n },\r\n ui: {\r\n enable: {\r\n value: false,\r\n types: ['boolean'],\r\n envLink: 'UI_ENABLE',\r\n cliName: 'enableUi',\r\n description: 'Enables or disables the UI for the export server',\r\n promptOptions: {\r\n type: 'toggle'\r\n }\r\n },\r\n route: {\r\n value: '/',\r\n types: ['string'],\r\n envLink: 'UI_ROUTE',\r\n cliName: 'uiRoute',\r\n description: 'The endpoint route for the UI',\r\n promptOptions: {\r\n type: 'text'\r\n }\r\n }\r\n },\r\n other: {\r\n nodeEnv: {\r\n value: 'production',\r\n types: ['string'],\r\n envLink: 'OTHER_NODE_ENV',\r\n description: 'The Node.js environment type',\r\n promptOptions: {\r\n type: 'text'\r\n }\r\n },\r\n listenToProcessExits: {\r\n value: true,\r\n types: ['boolean'],\r\n envLink: 'OTHER_LISTEN_TO_PROCESS_EXITS',\r\n description: 'Whether or not to attach process.exit handlers',\r\n promptOptions: {\r\n type: 'toggle'\r\n }\r\n },\r\n noLogo: {\r\n value: false,\r\n types: ['boolean'],\r\n envLink: 'OTHER_NO_LOGO',\r\n description: 'Display or skip printing the logo on startup',\r\n promptOptions: {\r\n type: 'toggle'\r\n }\r\n },\r\n hardResetPage: {\r\n value: false,\r\n types: ['boolean'],\r\n envLink: 'OTHER_HARD_RESET_PAGE',\r\n description: 'Whether or not to reset the page content entirely',\r\n promptOptions: {\r\n type: 'toggle'\r\n }\r\n },\r\n browserShellMode: {\r\n value: true,\r\n types: ['boolean'],\r\n envLink: 'OTHER_BROWSER_SHELL_MODE',\r\n description: 'Whether or not to set the browser to run in shell mode',\r\n promptOptions: {\r\n type: 'toggle'\r\n }\r\n }\r\n },\r\n debug: {\r\n enable: {\r\n value: false,\r\n types: ['boolean'],\r\n envLink: 'DEBUG_ENABLE',\r\n cliName: 'enableDebug',\r\n description: 'Enables or disables debug mode for the underlying browser',\r\n promptOptions: {\r\n type: 'toggle'\r\n }\r\n },\r\n headless: {\r\n value: false,\r\n types: ['boolean'],\r\n envLink: 'DEBUG_HEADLESS',\r\n description:\r\n 'Whether or not to set the browser to run in headless mode during debugging',\r\n promptOptions: {\r\n type: 'toggle'\r\n }\r\n },\r\n devtools: {\r\n value: false,\r\n types: ['boolean'],\r\n envLink: 'DEBUG_DEVTOOLS',\r\n description: 'Enables or disables DevTools in headful mode',\r\n promptOptions: {\r\n type: 'toggle'\r\n }\r\n },\r\n listenToConsole: {\r\n value: false,\r\n types: ['boolean'],\r\n envLink: 'DEBUG_LISTEN_TO_CONSOLE',\r\n description:\r\n 'Enables or disables listening to console messages from the browser',\r\n promptOptions: {\r\n type: 'toggle'\r\n }\r\n },\r\n dumpio: {\r\n value: false,\r\n types: ['boolean'],\r\n envLink: 'DEBUG_DUMPIO',\r\n description:\r\n 'Redirects or not browser stdout and stderr to process.stdout and process.stderr',\r\n promptOptions: {\r\n type: 'toggle'\r\n }\r\n },\r\n slowMo: {\r\n value: 0,\r\n types: ['number'],\r\n envLink: 'DEBUG_SLOW_MO',\r\n description: 'Delays Puppeteer operations by the specified milliseconds',\r\n promptOptions: {\r\n type: 'number'\r\n }\r\n },\r\n debuggingPort: {\r\n value: 9222,\r\n types: ['number'],\r\n envLink: 'DEBUG_DEBUGGING_PORT',\r\n description: 'Port used for debugging',\r\n promptOptions: {\r\n type: 'number'\r\n }\r\n }\r\n }\r\n};\r\n\r\n// Properties nesting level of all options\r\nexport const nestedProps = _createNestedProps(defaultConfig);\r\n\r\n// Properties names that should not be recursively merged\r\nexport const absoluteProps = _createAbsoluteProps(defaultConfig);\r\n\r\n/**\r\n * Recursively generates a mapping of nested argument chains from a nested\r\n * config object. This function traverses a nested object and creates a mapping\r\n * where each key is an argument name (either from `cliName`, `legacyName`,\r\n * or the original key) and each value is a string representing the chain\r\n * of nested properties leading to that argument.\r\n *\r\n * @function _createNestedProps\r\n *\r\n * @param {Object} config - The configuration object.\r\n * @param {Object} [nestedProps={}] - The accumulator object for storing\r\n * the resulting arguments chains. The default value is an empty object.\r\n * @param {string} [propChain=''] - The current chain of nested properties,\r\n * used internally during recursion. The default value is an empty string.\r\n *\r\n * @returns {Object} An object mapping argument names to their corresponding\r\n * nested property chains.\r\n */\r\nfunction _createNestedProps(config, nestedProps = {}, propChain = '') {\r\n Object.keys(config).forEach((key) => {\r\n // Get the specific section\r\n const entry = config[key];\r\n\r\n // Check if there is still more depth to traverse\r\n if (typeof entry.value === 'undefined') {\r\n // Recurse into deeper levels of nested arguments\r\n _createNestedProps(entry, nestedProps, `${propChain}.${key}`);\r\n } else {\r\n // Create the chain of nested arguments\r\n nestedProps[entry.cliName || key] = `${propChain}.${key}`.substring(1);\r\n\r\n // Support for the legacy, PhantomJS properties names\r\n if (entry.legacyName !== undefined) {\r\n nestedProps[entry.legacyName] = `${propChain}.${key}`.substring(1);\r\n }\r\n }\r\n });\r\n\r\n // Return the object with nested argument chains\r\n return nestedProps;\r\n}\r\n\r\n/**\r\n * Recursively gathers the names of properties from a configuration object that\r\n * can be treated as absolute properties. These properties have values that\r\n * are objects and do not contain further nested depth when merging an object\r\n * containing these options.\r\n *\r\n * @function _createAbsoluteProps\r\n *\r\n * @param {Object} config - The configuration object.\r\n * @param {Array.} [absoluteProps=[]] - An array to collect the names\r\n * of absolute properties. The default value is an empty array.\r\n *\r\n * @returns {Array.} An array containing the names of absolute\r\n * properties.\r\n */\r\nfunction _createAbsoluteProps(config, absoluteProps = []) {\r\n Object.keys(config).forEach((key) => {\r\n // Get the specific section\r\n const entry = config[key];\r\n\r\n // Check if there is still more depth to traverse\r\n if (typeof entry.types === 'undefined') {\r\n // Recurse into deeper levels\r\n _createAbsoluteProps(entry, absoluteProps);\r\n } else {\r\n // If the option can be an object, save its type in the array\r\n if (entry.types.includes('Object')) {\r\n absoluteProps.push(key);\r\n }\r\n }\r\n });\r\n\r\n // Return the array with the names of absolute properties\r\n return absoluteProps;\r\n}\r\n\r\nexport default {\r\n defaultConfig,\r\n nestedProps,\r\n absoluteProps\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * @overview This file handles parsing and validating options from multiple\r\n * sources (the config file, custom JSON, environment variables, CLI arguments,\r\n * and request payload) using the 'zod' library.\r\n *\r\n * Environment variables are parsed and validated only once at application\r\n * startup, and the validated results are exported as `envs` for use throughout\r\n * the application.\r\n *\r\n * Options from other sources, however, are parsed and validated on demand,\r\n * each time an export is attempted.\r\n */\r\n\r\nimport dotenv from 'dotenv';\r\nimport { z } from 'zod';\r\n\r\nimport { defaultConfig } from './schemas/config.js';\r\n\r\n// Load the .env into environment variables\r\ndotenv.config();\r\n\r\n// Get scripts names of each category from the default config\r\nconst { coreScripts, moduleScripts, indicatorScripts } =\r\n defaultConfig.highcharts;\r\n\r\n// Sets the custom error map globally\r\nz.setErrorMap(_customErrorMap);\r\n\r\n/**\r\n * Object containing custom general validators and parsers to avoid repetition\r\n * in schema objects. All validators apply to values from various sources,\r\n * including the default config file, a custom JSON file loaded with the option\r\n * called `loadConfig`, the .env file, CLI arguments, and the request payload.\r\n * The `strictCheck` flag enables stricter validation and parsing rules. This\r\n * flag is set to false for values that come from the .env file or CLI arguments\r\n * because they are provided as strings and need to be parsed accordingly first.\r\n */\r\nconst v = {\r\n /**\r\n * The `boolean` validator that returns a Zod schema with an optional stricter\r\n * check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures that:\r\n *\r\n * - When `strictCheck` is true, the schema will accept values are true\r\n * and false and the schema will validate against the default boolean\r\n * validator.\r\n *\r\n * - When `strictCheck` is false, the schema will accept values are true,\r\n * false, null, 'true', 'false', 'undefined', 'null', and ''. The strings\r\n * 'undefined', 'null', and '' will be transformed to null, the string 'true'\r\n * will be transformed to the boolean value true, and 'false' will\r\n * be transformed to the boolean value false.\r\n *\r\n * @function boolean\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating boolean values.\r\n */\r\n boolean(strictCheck) {\r\n return strictCheck\r\n ? z.boolean()\r\n : z\r\n .union([\r\n z\r\n .enum(['true', 'false', 'undefined', 'null', ''])\r\n .transform((value) =>\r\n !['undefined', 'null', ''].includes(value)\r\n ? value === 'true'\r\n : null\r\n ),\r\n z.boolean()\r\n ])\r\n .nullable();\r\n },\r\n\r\n /**\r\n * The `string` validator that returns a Zod schema with an optional stricter\r\n * check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures that:\r\n *\r\n * - When `strictCheck` is true, the schema will accept trimmed strings except\r\n * the forbidden values: 'false', 'undefined', 'null', and ''.\r\n *\r\n * - When `strictCheck` is false, the schema will accept trimmed strings\r\n * and null. The forbidden values: 'false', 'undefined', 'null', and '' will\r\n * be transformed to null.\r\n *\r\n * @function string\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating string values.\r\n */\r\n string(strictCheck) {\r\n return strictCheck\r\n ? z\r\n .string()\r\n .trim()\r\n .refine(\r\n (value) => !['false', 'undefined', 'null', ''].includes(value),\r\n {\r\n params: {\r\n errorMessage: `The string contains a forbidden value`\r\n }\r\n }\r\n )\r\n : z\r\n .string()\r\n .trim()\r\n .transform((value) =>\r\n !['false', 'undefined', 'null', ''].includes(value) ? value : null\r\n )\r\n .nullable();\r\n },\r\n\r\n /**\r\n * The `enum` validator that returns a Zod schema with an optional stricter\r\n * check based on the `strictCheck` parameter.\r\n *\r\n * The schema will validate against the provided `values` array.\r\n *\r\n * The validation schema ensures that:\r\n *\r\n * - When `strictCheck` is true, the schema will validate against the `values`\r\n * array with the default enum validator.\r\n *\r\n * - When `strictCheck` is false, the schema will accept also null,\r\n * 'undefined', 'null', and '', which will be transformed to null.\r\n *\r\n * @function enum\r\n *\r\n * @param {Array.} values - An array of valid string values\r\n * for the enum.\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating enum values.\r\n */\r\n enum(values, strictCheck) {\r\n return strictCheck\r\n ? z.enum([...values])\r\n : z\r\n .enum([...values, 'undefined', 'null', ''])\r\n .transform((value) =>\r\n !['undefined', 'null', ''].includes(value) ? value : null\r\n )\r\n .nullable();\r\n },\r\n\r\n /**\r\n * The `stringArray` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures that:\r\n *\r\n * - When `strictCheck` is true, the schema will accept an array of trimmed\r\n * string values filtered by the logic provided through the `filterCallback`.\r\n *\r\n * - When `strictCheck` is false, the schema will accept null and trimmed\r\n * string values which will be splitted into an array of strings and filtered\r\n * from the '[' and ']' characters and by the logic provided through\r\n * the `filterCallback`. If the array is empty, it will be transformed\r\n * to null.\r\n *\r\n * @function stringArray\r\n *\r\n * @param {function} filterCallback - The filter callback.\r\n * @param {string} separator - The separator for spliting a string.\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating array of string\r\n * values.\r\n */\r\n stringArray(filterCallback, separator, strictCheck) {\r\n const arraySchema = z.string().trim().array();\r\n const stringSchema = z\r\n .string()\r\n .trim()\r\n .transform((value) => {\r\n if (value.startsWith('[')) {\r\n value = value.slice(1);\r\n }\r\n if (value.endsWith(']')) {\r\n value = value.slice(0, -1);\r\n }\r\n return value.split(separator);\r\n });\r\n\r\n const transformCallback = (value) =>\r\n value.map((value) => value.trim()).filter(filterCallback);\r\n\r\n return strictCheck\r\n ? arraySchema.transform(transformCallback)\r\n : z\r\n .union([stringSchema, arraySchema])\r\n .transform(transformCallback)\r\n .transform((value) => (value.length ? value : null))\r\n .nullable();\r\n },\r\n\r\n /**\r\n * The `positiveNum` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures that:\r\n *\r\n * - When `strictCheck` is true, the schema will accept positive number values\r\n * and validate against the default positive number validator.\r\n *\r\n * - When `strictCheck` is false, the schema will accept positive number\r\n * values, null, and trimmed string values that can either be 'undefined',\r\n * 'null', '', or represent a positive number. It will transform the string\r\n * to a positive number, or to null if it is 'undefined', 'null', or ''.\r\n *\r\n * @function positiveNum\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating positive number\r\n * values.\r\n */\r\n positiveNum(strictCheck) {\r\n return strictCheck\r\n ? z.number().positive()\r\n : z\r\n .union([\r\n z\r\n .string()\r\n .trim()\r\n .refine(\r\n (value) =>\r\n (!isNaN(Number(value)) && Number(value) > 0) ||\r\n ['undefined', 'null', ''].includes(value),\r\n {\r\n params: {\r\n errorMessage: `The value must be numeric and positive`\r\n }\r\n }\r\n )\r\n .transform((value) =>\r\n !['undefined', 'null', ''].includes(value)\r\n ? Number(value)\r\n : null\r\n ),\r\n z.number().positive()\r\n ])\r\n .nullable();\r\n },\r\n\r\n /**\r\n * The `nonNegativeNum` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures that:\r\n *\r\n * - When `strictCheck` is true, the schema will accept non-negative number\r\n * values and validate against the default non-negative number validator.\r\n *\r\n * - When `strictCheck` is false, the schema will accept non-negative number\r\n * values, null, and trimmed string values that can either be 'undefined',\r\n * 'null', '', or represent a non-negative number. It will transform\r\n * the string to a non-negative number, or to null if it is 'undefined',\r\n * 'null', or ''.\r\n *\r\n * @function nonNegativeNum\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating non-negative\r\n * number values.\r\n */\r\n nonNegativeNum(strictCheck) {\r\n return strictCheck\r\n ? z.number().nonnegative()\r\n : z\r\n .union([\r\n z\r\n .string()\r\n .trim()\r\n .refine(\r\n (value) =>\r\n (!isNaN(Number(value)) && Number(value) >= 0) ||\r\n ['undefined', 'null', ''].includes(value),\r\n {\r\n params: {\r\n errorMessage: `The value must be numeric and non-negative`\r\n }\r\n }\r\n )\r\n .transform((value) =>\r\n !['undefined', 'null', ''].includes(value)\r\n ? Number(value)\r\n : null\r\n ),\r\n z.number().nonnegative()\r\n ])\r\n .nullable();\r\n },\r\n\r\n /**\r\n * The `startsWith` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The schema will validate against the provided `prefixes` array to check\r\n * whether a string value starts with any of the values provided\r\n * in the `prefixes` array.\r\n *\r\n * The validation schema ensures that:\r\n *\r\n * - When `strictCheck` is true, the schema will accept trimmed string values\r\n * that start with values from the prefixes array.\r\n *\r\n * - When `strictCheck` is false, the schema will accept trimmed string values\r\n * that start with values from the prefixes array, null, 'undefined', 'null',\r\n * and '' where the schema will transform them to null.\r\n *\r\n * @function startsWith\r\n *\r\n * @param {Array.} prefixes - An array of prefixes to validate\r\n * the string against.\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating strings that\r\n * starts with values.\r\n */\r\n startsWith(prefixes, strictCheck) {\r\n return strictCheck\r\n ? z\r\n .string()\r\n .trim()\r\n .refine(\r\n (value) => prefixes.some((prefix) => value.startsWith(prefix)),\r\n {\r\n params: {\r\n errorMessage: `The value must be a string that starts with ${prefixes.join(', ')}`\r\n }\r\n }\r\n )\r\n : z\r\n .string()\r\n .trim()\r\n .refine(\r\n (value) =>\r\n prefixes.some((prefix) => value.startsWith(prefix)) ||\r\n ['undefined', 'null', ''].includes(value),\r\n {\r\n params: {\r\n errorMessage: `The value must be a string that starts with ${prefixes.join(', ')}`\r\n }\r\n }\r\n )\r\n .transform((value) =>\r\n !['undefined', 'null', ''].includes(value) ? value : null\r\n )\r\n .nullable();\r\n },\r\n\r\n /**\r\n * The `chartConfig` validator that returns a Zod schema.\r\n *\r\n * The validation schema ensures that the schema will accept object values\r\n * or trimmed string values that contain '\r\n value.indexOf('= 0 ||\r\n value.indexOf('= 0 ||\r\n (value.startsWith('{') && value.endsWith('}')) ||\r\n ['undefined', 'null', ''].includes(value),\r\n {\r\n params: {\r\n errorMessage: `The value must be a string that contains '\r\n !['undefined', 'null', ''].includes(value) ? value : null\r\n ),\r\n z.object({}).passthrough()\r\n ])\r\n .nullable();\r\n },\r\n\r\n /**\r\n * The `additionalOptions` validator that returns a Zod schema.\r\n *\r\n * The validation schema ensures that the schema will accept object values\r\n * or trimmed string values that end with '.json' and are at least one\r\n * character long excluding the extension, start with the '{' and end\r\n * with the '}', and null. The 'undefined', 'null', and '' values will\r\n * be transformed to null.\r\n *\r\n * @function additionalOptions\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating additional chart\r\n * options value.\r\n */\r\n additionalOptions() {\r\n return z\r\n .union([\r\n z\r\n .string()\r\n .trim()\r\n .refine(\r\n (value) =>\r\n (value.length >= 6 && value.endsWith('.json')) ||\r\n (value.startsWith('{') && value.endsWith('}')) ||\r\n ['undefined', 'null', ''].includes(value),\r\n {\r\n params: {\r\n errorMessage: `The value must be a string that ends with '.json' or starts with '{' and ends with '}'`\r\n }\r\n }\r\n )\r\n .transform((value) =>\r\n !['undefined', 'null', ''].includes(value) ? value : null\r\n ),\r\n z.object({}).passthrough()\r\n ])\r\n .nullable();\r\n }\r\n};\r\n\r\n/**\r\n * Object containing custom config validators and parsers to avoid repetition\r\n * in schema objects. All validators apply to values from various sources,\r\n * including the default config file, a custom JSON file loaded with the option\r\n * called `loadConfig`, the .env file, CLI arguments, and the request payload.\r\n * The `strictCheck` flag enables stricter validation and parsing rules. This\r\n * flag is set to false for values that come from the .env file or CLI arguments\r\n * because they are provided as strings and need to be parsed accordingly first.\r\n */\r\nconst config = {\r\n /**\r\n * The `args` validator that returns a Zod schema with an optional stricter\r\n * check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `stringArray` validator.\r\n *\r\n * @function args\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `args`\r\n * option.\r\n */\r\n args(strictCheck) {\r\n return v.stringArray(\r\n (value) => !['false', 'undefined', 'null', ''].includes(value),\r\n ';',\r\n strictCheck\r\n );\r\n },\r\n\r\n /**\r\n * The `version` validator that returns a Zod schema with an optional stricter\r\n * check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures that:\r\n *\r\n * - When `strictCheck` is true, the schema will accept trimmed string values\r\n * that are a RegExp-based that allows to be 'latest', or in the format XX,\r\n * XX.YY, or XX.YY.ZZ, where XX, YY, and ZZ are numeric for the Highcharts\r\n * version option.\r\n *\r\n * - When `strictCheck` is false, the schema will accept also null,\r\n * 'undefined', 'null', or '' and in all cases the schema will transform them\r\n * to null.\r\n *\r\n * @function version\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `version`\r\n * option.\r\n */\r\n version(strictCheck) {\r\n return strictCheck\r\n ? z\r\n .string()\r\n .trim()\r\n .refine((value) => /^(latest|\\d{1,2}(\\.\\d{1,2}){0,2})$/.test(value), {\r\n params: {\r\n errorMessage:\r\n \"The value must be 'latest', a major version, or in the form XX.YY.ZZ\"\r\n }\r\n })\r\n : z\r\n .string()\r\n .trim()\r\n .refine(\r\n (value) =>\r\n /^(latest|\\d{1,2}(\\.\\d{1,2}){0,2})$/.test(value) ||\r\n ['undefined', 'null', ''].includes(value),\r\n {\r\n params: {\r\n errorMessage:\r\n \"The value must be 'latest', a major version, or in the form XX.YY.ZZ\"\r\n }\r\n }\r\n )\r\n .transform((value) =>\r\n !['undefined', 'null', ''].includes(value) ? value : null\r\n )\r\n .nullable();\r\n },\r\n\r\n /**\r\n * The `cdnUrl` validator that returns a Zod schema with an optional stricter\r\n * check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `startsWith` validator.\r\n *\r\n * @function cdnUrl\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `cdnUrl`\r\n * option.\r\n */\r\n cdnUrl(strictCheck) {\r\n return v.startsWith(['http://', 'https://'], strictCheck);\r\n },\r\n\r\n /**\r\n * The `forceFetch` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `boolean` validator.\r\n *\r\n * @function forceFetch\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `forceFetch`\r\n * option.\r\n */\r\n forceFetch(strictCheck) {\r\n return v.boolean(strictCheck);\r\n },\r\n\r\n /**\r\n * The `cachePath` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `string` validator.\r\n *\r\n * @function cachePath\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `cachePath`\r\n * option.\r\n */\r\n cachePath(strictCheck) {\r\n return v.string(strictCheck);\r\n },\r\n\r\n /**\r\n * The `adminToken` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `string` validator.\r\n *\r\n * @function adminToken\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `adminToken`\r\n * option.\r\n */\r\n adminToken(strictCheck) {\r\n return v.string(strictCheck);\r\n },\r\n\r\n /**\r\n * The `coreScripts` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `stringArray` validator.\r\n *\r\n * @function coreScripts\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `coreScripts`\r\n * option.\r\n */\r\n coreScripts(strictCheck) {\r\n return v.stringArray(\r\n (value) => coreScripts.value.includes(value),\r\n ',',\r\n strictCheck\r\n );\r\n },\r\n\r\n /**\r\n * The `moduleScripts` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `stringArray` validator.\r\n *\r\n * @function moduleScripts\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating\r\n * the `moduleScripts` option.\r\n */\r\n moduleScripts(strictCheck) {\r\n return v.stringArray(\r\n (value) => moduleScripts.value.includes(value),\r\n ',',\r\n strictCheck\r\n );\r\n },\r\n\r\n /**\r\n * The `indicatorScripts` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `stringArray` validator.\r\n *\r\n * @function indicatorScripts\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating\r\n * the `indicatorScripts` option.\r\n */\r\n indicatorScripts(strictCheck) {\r\n return v.stringArray(\r\n (value) => indicatorScripts.value.includes(value),\r\n ',',\r\n strictCheck\r\n );\r\n },\r\n\r\n /**\r\n * The `customScripts` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `stringArray` validator.\r\n *\r\n * @function customScripts\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating\r\n * the `customScripts` option.\r\n */\r\n customScripts(strictCheck) {\r\n return v.stringArray(\r\n (value) => value.startsWith('https://') || value.startsWith('http://'),\r\n ',',\r\n strictCheck\r\n );\r\n },\r\n\r\n /**\r\n * The `infile` validator that returns a Zod schema with an optional stricter\r\n * check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures that:\r\n *\r\n * - When `strictCheck` is true, the schema will accept trimmed string values\r\n * that end with '.json' or '.svg', are at least one character long excluding\r\n * the extension, or null.\r\n *\r\n * - When `strictCheck` is false, the schema will accept trimmed string values\r\n * that end with '.json' or '.svg', are at least one character long excluding\r\n * the extension and will be null if the provided value is null, 'undefined',\r\n * 'null', or ''.\r\n *\r\n * @function infile\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `infile`\r\n * option.\r\n */\r\n infile(strictCheck) {\r\n return strictCheck\r\n ? z\r\n .string()\r\n .trim()\r\n .refine(\r\n (value) =>\r\n (value.length >= 6 && value.endsWith('.json')) ||\r\n (value.length >= 5 && value.endsWith('.svg')),\r\n {\r\n params: {\r\n errorMessage: `The value must be a string that ends with .json or .svg`\r\n }\r\n }\r\n )\r\n .nullable()\r\n : z\r\n .string()\r\n .trim()\r\n .refine(\r\n (value) =>\r\n (value.length >= 6 && value.endsWith('.json')) ||\r\n (value.length >= 5 && value.endsWith('.svg')) ||\r\n ['undefined', 'null', ''].includes(value),\r\n {\r\n params: {\r\n errorMessage: `The value must be a string that ends with .json or .svg`\r\n }\r\n }\r\n )\r\n .transform((value) =>\r\n !['undefined', 'null', ''].includes(value) ? value : null\r\n )\r\n .nullable();\r\n },\r\n\r\n /**\r\n * The `instr` validator that returns a Zod schema.\r\n *\r\n * The validation schema ensures the same work as the `options` validator.\r\n *\r\n * @function instr\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `instr`\r\n * option.\r\n */\r\n instr() {\r\n return v.chartConfig();\r\n },\r\n\r\n /**\r\n * The `options` validator that returns a Zod schema.\r\n *\r\n * The validation schema ensures the same work as the `options` validator.\r\n *\r\n * @function options\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `options`\r\n * option.\r\n */\r\n options() {\r\n return v.chartConfig();\r\n },\r\n\r\n /**\r\n * The `svg` validator that returns a Zod schema.\r\n *\r\n * The validation schema ensures that the schema will accept object values\r\n * or trimmed string values that contain '\r\n value.indexOf('= 0 ||\r\n value.indexOf('= 0 ||\r\n ['false', 'undefined', 'null', ''].includes(value),\r\n {\r\n params: {\r\n errorMessage: `The value must be a string that contains '\r\n !['false', 'undefined', 'null', ''].includes(value) ? value : null\r\n )\r\n .nullable();\r\n },\r\n\r\n /**\r\n * The `outfile` validator that returns a Zod schema with an optional stricter\r\n * check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures that:\r\n *\r\n * - When `strictCheck` is true, the schema will accept trimmed string values\r\n * that end with '.jpeg', '.jpg', '.png', '.pdf', or '.svg', are at least one\r\n * character long excluding the extension, or null.\r\n *\r\n * - When `strictCheck` is false, the schema will accept trimmed string values\r\n * that end with '.jpeg', '.jpg', '.png', '.pdf', or '.svg', are at least one\r\n * character long excluding the extension and will be null if the provided\r\n * value is null, 'undefined', 'null', or ''.\r\n *\r\n * @function outfile\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `outfile`\r\n * option.\r\n */\r\n outfile(strictCheck) {\r\n return strictCheck\r\n ? z\r\n .string()\r\n .trim()\r\n .refine(\r\n (value) =>\r\n (value.length >= 6 && value.endsWith('.jpeg')) ||\r\n (value.length >= 5 &&\r\n (value.endsWith('.jpg') ||\r\n value.endsWith('.png') ||\r\n value.endsWith('.pdf') ||\r\n value.endsWith('.svg'))),\r\n {\r\n params: {\r\n errorMessage: `The value must be a string that ends with .jpeg, .jpg, .png, .pdf, or .svg`\r\n }\r\n }\r\n )\r\n .nullable()\r\n : z\r\n .string()\r\n .trim()\r\n .refine(\r\n (value) =>\r\n (value.length >= 6 && value.endsWith('.jpeg')) ||\r\n (value.length >= 5 &&\r\n (value.endsWith('.jpg') ||\r\n value.endsWith('.png') ||\r\n value.endsWith('.pdf') ||\r\n value.endsWith('.svg'))) ||\r\n ['undefined', 'null', ''].includes(value),\r\n {\r\n params: {\r\n errorMessage: `The value must be a string that ends with .jpeg, .jpg, .png, .pdf, or .svg`\r\n }\r\n }\r\n )\r\n .transform((value) =>\r\n !['undefined', 'null', ''].includes(value) ? value : null\r\n )\r\n .nullable();\r\n },\r\n\r\n /**\r\n * The `type` validator that returns a Zod schema with an optional stricter\r\n * check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `enum` validator.\r\n *\r\n * @function type\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `type`\r\n * option.\r\n */\r\n type(strictCheck) {\r\n return v.enum(['jpeg', 'jpg', 'png', 'pdf', 'svg'], strictCheck);\r\n },\r\n\r\n /**\r\n * The `constr` validator that returns a Zod schema with an optional stricter\r\n * check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `enum` validator.\r\n *\r\n * @function constr\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `constr`\r\n * option.\r\n */\r\n constr(strictCheck) {\r\n return v.enum(\r\n ['chart', 'stockChart', 'mapChart', 'ganttChart'],\r\n strictCheck\r\n );\r\n },\r\n\r\n /**\r\n * The `b64` validator that returns a Zod schema with an optional stricter\r\n * check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `boolean` validator.\r\n *\r\n * @function b64\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `b64` option.\r\n */\r\n b64(strictCheck) {\r\n return v.boolean(strictCheck);\r\n },\r\n\r\n /**\r\n * The `noDownload` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `boolean` validator.\r\n *\r\n * @function noDownload\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `noDownload`\r\n * option.\r\n */\r\n noDownload(strictCheck) {\r\n return v.boolean(strictCheck);\r\n },\r\n\r\n /**\r\n * The `defaultHeight` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `positiveNum` validator.\r\n *\r\n * @function defaultHeight\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating\r\n * the `defaultHeight` option.\r\n */\r\n defaultHeight(strictCheck) {\r\n return v.positiveNum(strictCheck);\r\n },\r\n\r\n /**\r\n * The `defaultWidth` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `positiveNum` validator.\r\n *\r\n * @function defaultWidth\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating\r\n * the `defaultWidth` option.\r\n */\r\n defaultWidth(strictCheck) {\r\n return v.positiveNum(strictCheck);\r\n },\r\n\r\n /**\r\n * The `defaultScale` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures that:\r\n *\r\n * - When `strictCheck` is true, the schema will accept number values that\r\n * are between 0.1 and 5 (inclusive).\r\n *\r\n * - When `strictCheck` is false, the schema will accept number values\r\n * and stringified number values that are between 0.1 and 5 (inclusive), null,\r\n * 'undefined', 'null', and '' which will be transformed to null.\r\n *\r\n * @function defaultScale\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating\r\n * the `defaultScale` option.\r\n */\r\n defaultScale(strictCheck) {\r\n return strictCheck\r\n ? z.number().gte(0.1).lte(5)\r\n : z\r\n .union([\r\n z\r\n .string()\r\n .trim()\r\n .refine(\r\n (value) =>\r\n (!isNaN(Number(value)) &&\r\n value !== true &&\r\n !value.startsWith('[') &&\r\n Number(value) >= 0.1 &&\r\n Number(value) <= 5) ||\r\n ['undefined', 'null', ''].includes(value),\r\n {\r\n params: {\r\n errorMessage: 'The value must be within a 0.1 and 5.0 range'\r\n }\r\n }\r\n )\r\n .transform((value) =>\r\n !['undefined', 'null', ''].includes(value)\r\n ? Number(value)\r\n : null\r\n ),\r\n z.number().gte(0.1).lte(5)\r\n ])\r\n .nullable();\r\n },\r\n\r\n /**\r\n * The `height` validator that returns a Zod schema with an optional stricter\r\n * check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as a nullable `defaultHeight`\r\n * validator.\r\n *\r\n * @function height\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `height`\r\n * option.\r\n */\r\n height(strictCheck) {\r\n return this.defaultHeight(strictCheck).nullable();\r\n },\r\n\r\n /**\r\n * The `width` validator that returns a Zod schema with an optional stricter\r\n * check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as a nullable `defaultWidth`\r\n * validator.\r\n *\r\n * @function width\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `width`\r\n * option.\r\n */\r\n width(strictCheck) {\r\n return this.defaultWidth(strictCheck).nullable();\r\n },\r\n\r\n /**\r\n * The `scale` validator that returns a Zod schema with an optional stricter\r\n * check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as a nullable `defaultScale`\r\n * validator.\r\n *\r\n * @function scale\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `scale`\r\n * option.\r\n */\r\n scale(strictCheck) {\r\n return this.defaultScale(strictCheck).nullable();\r\n },\r\n\r\n /**\r\n * The `globalOptions` validator that returns a Zod schema.\r\n *\r\n * The validation schema ensures the same work as the `additionalOptions`\r\n * validator.\r\n *\r\n * @function globalOptions\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating\r\n * the `globalOptions` option.\r\n */\r\n globalOptions() {\r\n return v.additionalOptions();\r\n },\r\n\r\n /**\r\n * The `themeOptions` validator that returns a Zod schema.\r\n *\r\n * The validation schema ensures the same work as the `additionalOptions`\r\n * validator.\r\n *\r\n * @function themeOptions\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating\r\n * the `themeOptions` option.\r\n */\r\n themeOptions() {\r\n return v.additionalOptions();\r\n },\r\n\r\n /**\r\n * The `batch` validator that returns a Zod schema with an optional stricter\r\n * check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `string` validator.\r\n *\r\n * @function batch\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `batch`\r\n * option.\r\n */\r\n batch(strictCheck) {\r\n return v.string(strictCheck);\r\n },\r\n\r\n /**\r\n * The `rasterizationTimeout` validator that returns a Zod schema with\r\n * an optional stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `nonNegativeNum`\r\n * validator.\r\n *\r\n * @function rasterizationTimeout\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating\r\n * the `rasterizationTimeout` option.\r\n */\r\n rasterizationTimeout(strictCheck) {\r\n return v.nonNegativeNum(strictCheck);\r\n },\r\n\r\n /**\r\n * The `allowCodeExecution` validator that returns a Zod schema with\r\n * an optional stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `boolean` validator.\r\n *\r\n * @function allowCodeExecution\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating\r\n * the `allowCodeExecution` option.\r\n */\r\n allowCodeExecution(strictCheck) {\r\n return v.boolean(strictCheck);\r\n },\r\n\r\n /**\r\n * The `allowFileResources` validator that returns a Zod schema with\r\n * an optional stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `boolean` validator.\r\n *\r\n * @function allowFileResources\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating\r\n * the `allowFileResources` option.\r\n */\r\n allowFileResources(strictCheck) {\r\n return v.boolean(strictCheck);\r\n },\r\n\r\n /**\r\n * The `customCode` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `string` validator.\r\n *\r\n * @function customCode\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `customCode`\r\n * option.\r\n */\r\n customCode(strictCheck) {\r\n return v.string(strictCheck);\r\n },\r\n\r\n /**\r\n * The `callback` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `string` validator.\r\n *\r\n * @function callback\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `callback`\r\n * option.\r\n */\r\n callback(strictCheck) {\r\n return v.string(strictCheck);\r\n },\r\n\r\n /**\r\n * The `resources` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures that:\r\n *\r\n * - When `strictCheck` is true, the schema will accept a partial object\r\n * with allowed properties `js`, `css`, and `files` where each of the allowed\r\n * properties can be null, stringified version of the object, string that ends\r\n * with the '.json', and null.\r\n *\r\n * - When `strictCheck` is false, the schema will accept a stringified version\r\n * of a partial object with allowed properties `js`, `css`, and `files` where\r\n * each of the allowed properties can be null, string that ends with the\r\n * '.json', and will be null if the provided value is 'undefined', 'null'\r\n * or ''.\r\n *\r\n * @function resources\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `resources`\r\n * option.\r\n */\r\n resources(strictCheck) {\r\n const objectSchema = z\r\n .object({\r\n js: v.string(false),\r\n css: v.string(false),\r\n files: v\r\n .stringArray(\r\n (value) => !['undefined', 'null', ''].includes(value),\r\n ',',\r\n true\r\n )\r\n .nullable()\r\n })\r\n .partial();\r\n\r\n const stringSchema1 = z\r\n .string()\r\n .trim()\r\n .refine(\r\n (value) =>\r\n (value.startsWith('{') && value.endsWith('}')) ||\r\n (value.length >= 6 && value.endsWith('.json')),\r\n {\r\n params: {\r\n errorMessage: `The value must be a string that starts with '{' and ends with '}`\r\n }\r\n }\r\n );\r\n\r\n const stringSchema2 = z\r\n .string()\r\n .trim()\r\n .refine(\r\n (value) =>\r\n (value.startsWith('{') && value.endsWith('}')) ||\r\n (value.length >= 6 && value.endsWith('.json')) ||\r\n ['undefined', 'null', ''].includes(value),\r\n {\r\n params: {\r\n errorMessage: `The value must be a string that ends with '.json'`\r\n }\r\n }\r\n )\r\n .transform((value) =>\r\n !['undefined', 'null', ''].includes(value) ? value : null\r\n );\r\n\r\n return strictCheck\r\n ? z.union([objectSchema, stringSchema1]).nullable()\r\n : z.union([objectSchema, stringSchema2]).nullable();\r\n },\r\n\r\n /**\r\n * The `loadConfig` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `string` validator.\r\n * Additionally, it must be a string that ends with '.json'.\r\n *\r\n * @function loadConfig\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `loadConfig`\r\n * option.\r\n */\r\n loadConfig(strictCheck) {\r\n return v\r\n .string(strictCheck)\r\n .refine(\r\n (value) =>\r\n value === null || (value.length >= 6 && value.endsWith('.json')),\r\n {\r\n params: {\r\n errorMessage: `The value must be a string that ends with .json `\r\n }\r\n }\r\n );\r\n },\r\n\r\n /**\r\n * The `createConfig` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `loadConfig` validator.\r\n *\r\n * @function createConfig\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating\r\n * the `createConfig` option.\r\n */\r\n createConfig(strictCheck) {\r\n return this.loadConfig(strictCheck);\r\n },\r\n\r\n /**\r\n * The `enableServer` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `boolean` validator.\r\n *\r\n * @function enableServer\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating\r\n * the `enableServer` option.\r\n */\r\n enableServer(strictCheck) {\r\n return v.boolean(strictCheck);\r\n },\r\n\r\n /**\r\n * The `host` validator that returns a Zod schema with an optional stricter\r\n * check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `string` validator.\r\n *\r\n * @function host\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `host`\r\n * option.\r\n */\r\n host(strictCheck) {\r\n return v.string(strictCheck);\r\n },\r\n\r\n /**\r\n * The `port` validator that returns a Zod schema with an optional stricter\r\n * check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `nonNegativeNum`\r\n * validator.\r\n *\r\n * @function port\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `port`\r\n * option.\r\n */\r\n port(strictCheck) {\r\n return v.nonNegativeNum(strictCheck);\r\n },\r\n\r\n /**\r\n * The `uploadLimit` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `positiveNum` validator.\r\n *\r\n * @function uploadLimit\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `uploadLimit`\r\n * option.\r\n */\r\n uploadLimit(strictCheck) {\r\n return v.positiveNum(strictCheck);\r\n },\r\n\r\n /**\r\n * The `serverBenchmarking` validator that returns a Zod schema with\r\n * an optional stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `boolean` validator.\r\n *\r\n * @function serverBenchmarking\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating\r\n * the `serverBenchmarking` option.\r\n */\r\n serverBenchmarking(strictCheck) {\r\n return v.boolean(strictCheck);\r\n },\r\n\r\n /**\r\n * The `proxyHost` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `string` validator.\r\n *\r\n * @function proxyHost\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `proxyHost`\r\n * option.\r\n */\r\n proxyHost(strictCheck) {\r\n return v.string(strictCheck);\r\n },\r\n\r\n /**\r\n * The `proxyPort` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as a nullable `nonNegativeNum`\r\n * validator.\r\n *\r\n * @function proxyPort\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `proxyPort`\r\n * option.\r\n */\r\n proxyPort(strictCheck) {\r\n return v.nonNegativeNum(strictCheck).nullable();\r\n },\r\n\r\n /**\r\n * The `proxyTimeout` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `nonNegativeNum`\r\n * validator.\r\n *\r\n * @function proxyTimeout\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating\r\n * the `proxyTimeout` option.\r\n */\r\n proxyTimeout(strictCheck) {\r\n return v.nonNegativeNum(strictCheck);\r\n },\r\n\r\n /**\r\n * The `enableRateLimiting` validator that returns a Zod schema with\r\n * an optional stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `boolean` validator.\r\n *\r\n * @function enableRateLimiting\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating\r\n * the `enableRateLimiting` option.\r\n */\r\n enableRateLimiting(strictCheck) {\r\n return v.boolean(strictCheck);\r\n },\r\n\r\n /**\r\n * The `maxRequests` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `nonNegativeNum`\r\n * validator.\r\n *\r\n * @function maxRequests\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `maxRequests`\r\n * option.\r\n */\r\n maxRequests(strictCheck) {\r\n return v.nonNegativeNum(strictCheck);\r\n },\r\n\r\n /**\r\n * The `window` validator that returns a Zod schema with an optional stricter\r\n * check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `nonNegativeNum`\r\n * validator.\r\n *\r\n * @function window\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `window`\r\n * option.\r\n */\r\n window(strictCheck) {\r\n return v.nonNegativeNum(strictCheck);\r\n },\r\n\r\n /**\r\n * The `delay` validator that returns a Zod schema with an optional stricter\r\n * check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `nonNegativeNum`\r\n * validator.\r\n *\r\n * @function delay\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `delay`\r\n * option.\r\n */\r\n delay(strictCheck) {\r\n return v.nonNegativeNum(strictCheck);\r\n },\r\n\r\n /**\r\n * The `trustProxy` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `boolean` validator.\r\n *\r\n * @function trustProxy\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `trustProxy`\r\n * option.\r\n */\r\n trustProxy(strictCheck) {\r\n return v.boolean(strictCheck);\r\n },\r\n\r\n /**\r\n * The `skipKey` validator that returns a Zod schema with an optional stricter\r\n * check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `string` validator.\r\n *\r\n * @function skipKey\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `skipKey`\r\n * option.\r\n */\r\n skipKey(strictCheck) {\r\n return v.string(strictCheck);\r\n },\r\n\r\n /**\r\n * The `skipToken` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `string` validator.\r\n *\r\n * @function skipToken\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `skipToken`\r\n * option.\r\n */\r\n skipToken(strictCheck) {\r\n return v.string(strictCheck);\r\n },\r\n\r\n /**\r\n * The `enableSsl` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `boolean` validator.\r\n *\r\n * @function enableSsl\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `enableSsl`\r\n * option.\r\n */\r\n enableSsl(strictCheck) {\r\n return v.boolean(strictCheck);\r\n },\r\n\r\n /**\r\n * The `sslForce` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `boolean` validator.\r\n *\r\n * @function sslForce\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `sslForce`\r\n * option.\r\n */\r\n sslForce(strictCheck) {\r\n return v.boolean(strictCheck);\r\n },\r\n\r\n /**\r\n * The `sslPort` validator that returns a Zod schema with an optional stricter\r\n * check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `nonNegativeNum`\r\n * validator.\r\n *\r\n * @function sslPort\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `sslPort`\r\n * option.\r\n */\r\n sslPort(strictCheck) {\r\n return v.nonNegativeNum(strictCheck);\r\n },\r\n\r\n /**\r\n * The `sslCertPath` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `string` validator.\r\n *\r\n * @function sslCertPath\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `sslCertPath`\r\n * option.\r\n */\r\n sslCertPath(strictCheck) {\r\n return v.string(strictCheck);\r\n },\r\n\r\n /**\r\n * The `minWorkers` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `positiveNum` validator.\r\n *\r\n * @function minWorkers\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `minWorkers`\r\n * option.\r\n */\r\n minWorkers(strictCheck) {\r\n return v.positiveNum(strictCheck);\r\n },\r\n\r\n /**\r\n * The `maxWorkers` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `positiveNum` validator.\r\n *\r\n * @function maxWorkers\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `maxWorkers`\r\n * option.\r\n */\r\n maxWorkers(strictCheck) {\r\n return v.positiveNum(strictCheck);\r\n },\r\n\r\n /**\r\n * The `workLimit` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `positiveNum` validator.\r\n *\r\n * @function workLimit\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `workLimit`\r\n * option.\r\n */\r\n workLimit(strictCheck) {\r\n return v.positiveNum(strictCheck);\r\n },\r\n\r\n /**\r\n * The `acquireTimeout` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `nonNegativeNum`\r\n * validator.\r\n *\r\n * @function acquireTimeout\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating\r\n * the `acquireTimeout` option.\r\n */\r\n acquireTimeout(strictCheck) {\r\n return v.nonNegativeNum(strictCheck);\r\n },\r\n\r\n /**\r\n * The `createTimeout` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `nonNegativeNum`\r\n * validator.\r\n *\r\n * @function createTimeout\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating\r\n * the `createTimeout` option.\r\n */\r\n createTimeout(strictCheck) {\r\n return v.nonNegativeNum(strictCheck);\r\n },\r\n\r\n /**\r\n * The `destroyTimeout` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `nonNegativeNum`\r\n * validator.\r\n *\r\n * @function destroyTimeout\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating\r\n * the `destroyTimeout` option.\r\n */\r\n destroyTimeout(strictCheck) {\r\n return v.nonNegativeNum(strictCheck);\r\n },\r\n\r\n /**\r\n * The `idleTimeout` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `nonNegativeNum`\r\n * validator.\r\n *\r\n * @function idleTimeout\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating\r\n * the `idleTimeout` option.\r\n */\r\n idleTimeout(strictCheck) {\r\n return v.nonNegativeNum(strictCheck);\r\n },\r\n\r\n /**\r\n * The `createRetryInterval` validator that returns a Zod schema with\r\n * an optional stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `nonNegativeNum`\r\n * validator.\r\n *\r\n * @function createRetryInterval\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating\r\n * the `createRetryInterval` option.\r\n */\r\n createRetryInterval(strictCheck) {\r\n return v.nonNegativeNum(strictCheck);\r\n },\r\n\r\n /**\r\n * The `reaperInterval` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `nonNegativeNum`\r\n * validator.\r\n *\r\n * @function reaperInterval\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating\r\n * the `reaperInterval` option.\r\n */\r\n reaperInterval(strictCheck) {\r\n return v.nonNegativeNum(strictCheck);\r\n },\r\n\r\n /**\r\n * The `poolBenchmarking` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `boolean` validator.\r\n *\r\n * @function poolBenchmarking\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating\r\n * the `poolBenchmarking` option.\r\n */\r\n poolBenchmarking(strictCheck) {\r\n return v.boolean(strictCheck);\r\n },\r\n\r\n /**\r\n * The `resourcesInterval` validator that returns a Zod schema with\r\n * an optional stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `nonNegativeNum`\r\n * validator.\r\n *\r\n * @function resourcesInterval\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating\r\n * the `resourcesInterval` option.\r\n */\r\n resourcesInterval(strictCheck) {\r\n return v.nonNegativeNum(strictCheck);\r\n },\r\n\r\n /**\r\n * The `logLevel` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures that:\r\n *\r\n * - When `strictCheck` is true, the schema will accept integer number values\r\n * that are between 0 and 5 (inclusive).\r\n *\r\n * - When `strictCheck` is false, the schema will accept integer number values\r\n * and stringified integer number values that are between 1 and 5 (inclusive),\r\n * null, 'undefined', 'null', and '' which will be transformed to null.\r\n *\r\n * @function logLevel\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `logLevel`\r\n * option.\r\n */\r\n logLevel(strictCheck) {\r\n return strictCheck\r\n ? z.number().int().gte(0).lte(5)\r\n : z\r\n .union([\r\n z\r\n .string()\r\n .trim()\r\n .refine(\r\n (value) =>\r\n (!isNaN(Number(value)) &&\r\n value !== true &&\r\n !value.startsWith('[') &&\r\n Number.isInteger(Number(value)) &&\r\n Number(value) >= 0 &&\r\n Number(value) <= 5) ||\r\n ['undefined', 'null', ''].includes(value),\r\n {\r\n params: {\r\n errorMessage: 'The value must be within a 0 and 5 range'\r\n }\r\n }\r\n )\r\n .transform((value) =>\r\n !['undefined', 'null', ''].includes(value)\r\n ? Number(value)\r\n : null\r\n ),\r\n z.number().int().gte(0).lte(5)\r\n ])\r\n .nullable();\r\n },\r\n\r\n /**\r\n * The `logFile` validator that returns a Zod schema with an optional stricter\r\n * check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `string` validator.\r\n * Additionally, it must be a string that ends with '.log'.\r\n *\r\n * @function logFile\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `logFile`\r\n * option.\r\n */\r\n logFile(strictCheck) {\r\n return v\r\n .string(strictCheck)\r\n .refine(\r\n (value) =>\r\n value === null || (value.length >= 5 && value.endsWith('.log')),\r\n {\r\n params: {\r\n errorMessage: `The value must be a string that ends with '.log'`\r\n }\r\n }\r\n );\r\n },\r\n\r\n /**\r\n * The `logDest` validator that returns a Zod schema with an optional stricter\r\n * check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `string` validator.\r\n *\r\n * @function logDest\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `logDest`\r\n * option.\r\n */\r\n logDest(strictCheck) {\r\n return v.string(strictCheck);\r\n },\r\n\r\n /**\r\n * The `logToConsole` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `boolean` validator.\r\n *\r\n * @function logToConsole\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating\r\n * the `logToConsole` option.\r\n */\r\n logToConsole(strictCheck) {\r\n return v.boolean(strictCheck);\r\n },\r\n\r\n /**\r\n * The `logToFile` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `boolean` validator.\r\n *\r\n * @function logToFile\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `logToFile`\r\n * option.\r\n */\r\n logToFile(strictCheck) {\r\n return v.boolean(strictCheck);\r\n },\r\n\r\n /**\r\n * The `enableUi` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `boolean` validator.\r\n *\r\n * @function enableUi\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `enableUi`\r\n * option.\r\n */\r\n enableUi(strictCheck) {\r\n return v.boolean(strictCheck);\r\n },\r\n\r\n /**\r\n * The `uiRoute` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `startsWith` validator.\r\n *\r\n * @function uiRoute\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `uiRoute`\r\n * option.\r\n */\r\n uiRoute(strictCheck) {\r\n return v.startsWith(['/'], strictCheck);\r\n },\r\n\r\n /**\r\n * The `nodeEnv` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `enum` validator.\r\n *\r\n * @function nodeEnv\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `nodeEnv`\r\n * option.\r\n */\r\n nodeEnv(strictCheck) {\r\n return v.enum(['development', 'production', 'test'], strictCheck);\r\n },\r\n\r\n /**\r\n * The `listenToProcessExits` validator that returns a Zod schema with\r\n * an optional stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `boolean` validator.\r\n *\r\n * @function listenToProcessExits\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating\r\n * the `listenToProcessExits` option.\r\n */\r\n listenToProcessExits(strictCheck) {\r\n return v.boolean(strictCheck);\r\n },\r\n\r\n /**\r\n * The `noLogo` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `boolean` validator.\r\n *\r\n * @function noLogo\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `noLogo`\r\n * option.\r\n */\r\n noLogo(strictCheck) {\r\n return v.boolean(strictCheck);\r\n },\r\n\r\n /**\r\n * The `hardResetPage` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `boolean` validator.\r\n *\r\n * @function hardResetPage\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating\r\n * the `hardResetPage` option.\r\n */\r\n hardResetPage(strictCheck) {\r\n return v.boolean(strictCheck);\r\n },\r\n\r\n /**\r\n * The `browserShellMode` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `boolean` validator.\r\n *\r\n * @function browserShellMode\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating\r\n * the `browserShellMode` option.\r\n */\r\n browserShellMode(strictCheck) {\r\n return v.boolean(strictCheck);\r\n },\r\n\r\n /**\r\n * The `enableDebug` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `boolean` validator.\r\n *\r\n * @function enableDebug\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `enableDebug`\r\n * option.\r\n */\r\n enableDebug(strictCheck) {\r\n return v.boolean(strictCheck);\r\n },\r\n\r\n /**\r\n * The `headless` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `boolean` validator.\r\n *\r\n * @function headless\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `headless`\r\n * option.\r\n */\r\n headless(strictCheck) {\r\n return v.boolean(strictCheck);\r\n },\r\n\r\n /**\r\n * The `devtools` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `boolean` validator.\r\n *\r\n * @function devtools\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `devtools`\r\n * option.\r\n */\r\n devtools(strictCheck) {\r\n return v.boolean(strictCheck);\r\n },\r\n\r\n /**\r\n * The `listenToConsole` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `boolean` validator.\r\n *\r\n * @function listenToConsole\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating\r\n * the `listenToConsole` option.\r\n */\r\n listenToConsole(strictCheck) {\r\n return v.boolean(strictCheck);\r\n },\r\n\r\n /**\r\n * The `dumpio` validator that returns a Zod schema with an optional stricter\r\n * check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `boolean` validator.\r\n *\r\n * @function dumpio\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `dumpio`\r\n * option.\r\n */\r\n dumpio(strictCheck) {\r\n return v.boolean(strictCheck);\r\n },\r\n\r\n /**\r\n * The `slowMo` validator that returns a Zod schema with an optional stricter\r\n * check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `nonNegativeNum`\r\n * validator.\r\n *\r\n * @function slowMo\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `slowMo`\r\n * option.\r\n */\r\n slowMo(strictCheck) {\r\n return v.nonNegativeNum(strictCheck);\r\n },\r\n\r\n /**\r\n * The `debuggingPort` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `nonNegativeNum`\r\n * validator.\r\n *\r\n * @function debuggingPort\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating\r\n * the `debuggingPort` option.\r\n */\r\n debuggingPort(strictCheck) {\r\n return v.nonNegativeNum(strictCheck);\r\n },\r\n\r\n /**\r\n * The `requestId` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `string` validator.\r\n * Additionally, it must be a stringified UUID or can be null.\r\n *\r\n * @function requestId\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `requestId`\r\n * option.\r\n */\r\n requestId() {\r\n return (\r\n z\r\n .string()\r\n /// TO DO: Correct\r\n .uuid({ message: 'The value must be a stringified UUID' })\r\n .nullable()\r\n );\r\n }\r\n};\r\n\r\n// Schema for the puppeteer section of options\r\nconst PuppeteerSchema = (strictCheck) =>\r\n z\r\n .object({\r\n args: config.args(strictCheck)\r\n })\r\n .partial();\r\n\r\n// Schema for the highcharts section of options\r\nconst HighchartsSchema = (strictCheck) =>\r\n z\r\n .object({\r\n version: config.version(strictCheck),\r\n cdnUrl: config.cdnUrl(strictCheck),\r\n forceFetch: config.forceFetch(strictCheck),\r\n cachePath: config.cachePath(strictCheck),\r\n coreScripts: config.coreScripts(strictCheck),\r\n moduleScripts: config.moduleScripts(strictCheck),\r\n indicatorScripts: config.indicatorScripts(strictCheck),\r\n customScripts: config.customScripts(strictCheck)\r\n })\r\n .partial();\r\n\r\n// Schema for the export section of options\r\nconst ExportSchema = (strictCheck) =>\r\n z\r\n .object({\r\n infile: config.infile(strictCheck),\r\n instr: config.instr(),\r\n options: config.options(),\r\n svg: config.svg(),\r\n outfile: config.outfile(strictCheck),\r\n type: config.type(strictCheck),\r\n constr: config.constr(strictCheck),\r\n b64: config.b64(strictCheck),\r\n noDownload: config.noDownload(strictCheck),\r\n defaultHeight: config.defaultHeight(strictCheck),\r\n defaultWidth: config.defaultWidth(strictCheck),\r\n defaultScale: config.defaultScale(strictCheck),\r\n height: config.height(strictCheck),\r\n width: config.width(strictCheck),\r\n scale: config.scale(strictCheck),\r\n globalOptions: config.globalOptions(),\r\n themeOptions: config.themeOptions(),\r\n batch: config.batch(false),\r\n rasterizationTimeout: config.rasterizationTimeout(strictCheck)\r\n })\r\n .partial();\r\n\r\n// Schema for the customLogic section of options\r\nconst CustomLogicSchema = (strictCheck) =>\r\n z\r\n .object({\r\n allowCodeExecution: config.allowCodeExecution(strictCheck),\r\n allowFileResources: config.allowFileResources(strictCheck),\r\n customCode: config.customCode(false),\r\n callback: config.callback(false),\r\n resources: config.resources(strictCheck),\r\n loadConfig: config.loadConfig(false),\r\n createConfig: config.createConfig(false)\r\n })\r\n .partial();\r\n\r\n// Schema for the server.proxy section of options\r\nconst ProxySchema = (strictCheck) =>\r\n z\r\n .object({\r\n host: config.proxyHost(false),\r\n port: config.proxyPort(strictCheck),\r\n timeout: config.proxyTimeout(strictCheck)\r\n })\r\n .partial();\r\n\r\n// Schema for the server.rateLimiting section of options\r\nconst RateLimitingSchema = (strictCheck) =>\r\n z\r\n .object({\r\n enable: config.enableRateLimiting(strictCheck),\r\n maxRequests: config.maxRequests(strictCheck),\r\n window: config.window(strictCheck),\r\n delay: config.delay(strictCheck),\r\n trustProxy: config.trustProxy(strictCheck),\r\n skipKey: config.skipKey(false),\r\n skipToken: config.skipToken(false)\r\n })\r\n .partial();\r\n\r\n// Schema for the server.ssl section of options\r\nconst SslSchema = (strictCheck) =>\r\n z\r\n .object({\r\n enable: config.enableSsl(strictCheck),\r\n force: config.sslForce(strictCheck),\r\n port: config.sslPort(strictCheck),\r\n certPath: config.sslCertPath(false)\r\n })\r\n .partial();\r\n\r\n// Schema for the server section of options\r\nconst ServerSchema = (strictCheck) =>\r\n z.object({\r\n enable: config.enableServer(strictCheck).optional(),\r\n host: config.host(strictCheck).optional(),\r\n port: config.port(strictCheck).optional(),\r\n benchmarking: config.serverBenchmarking(strictCheck).optional(),\r\n proxy: ProxySchema(strictCheck).optional(),\r\n rateLimiting: RateLimitingSchema(strictCheck).optional(),\r\n ssl: SslSchema(strictCheck).optional()\r\n });\r\n\r\n// Schema for the pool section of options\r\nconst PoolSchema = (strictCheck) =>\r\n z\r\n .object({\r\n minWorkers: config.minWorkers(strictCheck),\r\n maxWorkers: config.maxWorkers(strictCheck),\r\n workLimit: config.workLimit(strictCheck),\r\n acquireTimeout: config.acquireTimeout(strictCheck),\r\n createTimeout: config.createTimeout(strictCheck),\r\n destroyTimeout: config.destroyTimeout(strictCheck),\r\n idleTimeout: config.idleTimeout(strictCheck),\r\n createRetryInterval: config.createRetryInterval(strictCheck),\r\n reaperInterval: config.reaperInterval(strictCheck),\r\n benchmarking: config.poolBenchmarking(strictCheck)\r\n })\r\n .partial();\r\n\r\n// Schema for the logging section of options\r\nconst LoggingSchema = (strictCheck) =>\r\n z\r\n .object({\r\n level: config.logLevel(strictCheck),\r\n file: config.logFile(strictCheck),\r\n dest: config.logDest(strictCheck),\r\n toConsole: config.logToConsole(strictCheck),\r\n toFile: config.logToFile(strictCheck)\r\n })\r\n .partial();\r\n\r\n// Schema for the ui section of options\r\nconst UiSchema = (strictCheck) =>\r\n z\r\n .object({\r\n enable: config.enableUi(strictCheck),\r\n route: config.uiRoute(strictCheck)\r\n })\r\n .partial();\r\n\r\n// Schema for the other section of options\r\nconst OtherSchema = (strictCheck) =>\r\n z\r\n .object({\r\n nodeEnv: config.nodeEnv(strictCheck),\r\n listenToProcessExits: config.listenToProcessExits(strictCheck),\r\n noLogo: config.noLogo(strictCheck),\r\n hardResetPage: config.hardResetPage(strictCheck),\r\n browserShellMode: config.browserShellMode(strictCheck)\r\n })\r\n .partial();\r\n\r\n// Schema for the debug section of options\r\nconst DebugSchema = (strictCheck) =>\r\n z\r\n .object({\r\n enable: config.enableDebug(strictCheck),\r\n headless: config.headless(strictCheck),\r\n devtools: config.devtools(strictCheck),\r\n listenToConsole: config.listenToConsole(strictCheck),\r\n dumpio: config.dumpio(strictCheck),\r\n slowMo: config.slowMo(strictCheck),\r\n debuggingPort: config.debuggingPort(strictCheck)\r\n })\r\n .partial();\r\n\r\n////\r\n// // Schema for the payload section of options\r\n// const PayloadSchema = () =>\r\n// z\r\n// .object({\r\n// requestId: config.requestId()\r\n// })\r\n// .partial();\r\n////\r\n\r\n// Strict schema for the config\r\nexport const StrictConfigSchema = z.object({\r\n puppeteer: PuppeteerSchema(true),\r\n highcharts: HighchartsSchema(true),\r\n export: ExportSchema(true),\r\n customLogic: CustomLogicSchema(true),\r\n server: ServerSchema(true),\r\n pool: PoolSchema(true),\r\n logging: LoggingSchema(true),\r\n ui: UiSchema(true),\r\n other: OtherSchema(true),\r\n debug: DebugSchema(true)\r\n //// payload: PayloadSchema()\r\n});\r\n\r\n// Loose schema for the config\r\nexport const LooseConfigSchema = z.object({\r\n puppeteer: PuppeteerSchema(false),\r\n highcharts: HighchartsSchema(false),\r\n export: ExportSchema(false),\r\n customLogic: CustomLogicSchema(false),\r\n server: ServerSchema(false),\r\n pool: PoolSchema(false),\r\n logging: LoggingSchema(false),\r\n ui: UiSchema(false),\r\n other: OtherSchema(false),\r\n debug: DebugSchema(false)\r\n //// payload: PayloadSchema()\r\n});\r\n\r\n// Schema for the environment variables config\r\nexport const EnvSchema = z.object({\r\n // puppeteer\r\n PUPPETEER_ARGS: config.args(false),\r\n\r\n // highcharts\r\n HIGHCHARTS_VERSION: config.version(false),\r\n HIGHCHARTS_CDN_URL: config.cdnUrl(false),\r\n HIGHCHARTS_FORCE_FETCH: config.forceFetch(false),\r\n HIGHCHARTS_CACHE_PATH: config.cachePath(false),\r\n HIGHCHARTS_ADMIN_TOKEN: config.adminToken(false),\r\n HIGHCHARTS_CORE_SCRIPTS: config.coreScripts(false),\r\n HIGHCHARTS_MODULE_SCRIPTS: config.moduleScripts(false),\r\n HIGHCHARTS_INDICATOR_SCRIPTS: config.indicatorScripts(false),\r\n HIGHCHARTS_CUSTOM_SCRIPTS: config.customScripts(false),\r\n\r\n // export\r\n EXPORT_INFILE: config.infile(false),\r\n EXPORT_INSTR: config.instr(),\r\n EXPORT_OPTIONS: config.options(),\r\n EXPORT_SVG: config.svg(),\r\n EXPORT_BATCH: config.batch(false),\r\n EXPORT_OUTFILE: config.outfile(false),\r\n EXPORT_TYPE: config.type(false),\r\n EXPORT_CONSTR: config.constr(false),\r\n EXPORT_B64: config.b64(false),\r\n EXPORT_NO_DOWNLOAD: config.noDownload(false),\r\n EXPORT_HEIGHT: config.height(false),\r\n EXPORT_WIDTH: config.width(false),\r\n EXPORT_SCALE: config.scale(false),\r\n EXPORT_DEFAULT_HEIGHT: config.defaultHeight(false),\r\n EXPORT_DEFAULT_WIDTH: config.defaultWidth(false),\r\n EXPORT_DEFAULT_SCALE: config.defaultScale(false),\r\n EXPORT_GLOBAL_OPTIONS: config.globalOptions(),\r\n EXPORT_THEME_OPTIONS: config.themeOptions(),\r\n EXPORT_RASTERIZATION_TIMEOUT: config.rasterizationTimeout(false),\r\n\r\n // custom\r\n CUSTOM_LOGIC_ALLOW_CODE_EXECUTION: config.allowCodeExecution(false),\r\n CUSTOM_LOGIC_ALLOW_FILE_RESOURCES: config.allowFileResources(false),\r\n CUSTOM_LOGIC_CUSTOM_CODE: config.customCode(false),\r\n CUSTOM_LOGIC_CALLBACK: config.callback(false),\r\n CUSTOM_LOGIC_RESOURCES: config.resources(false),\r\n CUSTOM_LOGIC_LOAD_CONFIG: config.loadConfig(false),\r\n CUSTOM_LOGIC_CREATE_CONFIG: config.createConfig(false),\r\n\r\n // server\r\n SERVER_ENABLE: config.enableServer(false),\r\n SERVER_HOST: config.host(false),\r\n SERVER_PORT: config.port(false),\r\n SERVER_UPLOAD_LIMIT: config.uploadLimit(false),\r\n SERVER_BENCHMARKING: config.serverBenchmarking(false),\r\n\r\n // server proxy\r\n SERVER_PROXY_HOST: config.proxyHost(false),\r\n SERVER_PROXY_PORT: config.proxyPort(false),\r\n SERVER_PROXY_TIMEOUT: config.proxyTimeout(false),\r\n\r\n // server rate limiting\r\n SERVER_RATE_LIMITING_ENABLE: config.enableRateLimiting(false),\r\n SERVER_RATE_LIMITING_MAX_REQUESTS: config.maxRequests(false),\r\n SERVER_RATE_LIMITING_WINDOW: config.window(false),\r\n SERVER_RATE_LIMITING_DELAY: config.delay(false),\r\n SERVER_RATE_LIMITING_TRUST_PROXY: config.trustProxy(false),\r\n SERVER_RATE_LIMITING_SKIP_KEY: config.skipKey(false),\r\n SERVER_RATE_LIMITING_SKIP_TOKEN: config.skipToken(false),\r\n\r\n // server ssl\r\n SERVER_SSL_ENABLE: config.enableSsl(false),\r\n SERVER_SSL_FORCE: config.sslForce(false),\r\n SERVER_SSL_PORT: config.sslPort(false),\r\n SERVER_SSL_CERT_PATH: config.sslCertPath(false),\r\n\r\n // pool\r\n POOL_MIN_WORKERS: config.minWorkers(false),\r\n POOL_MAX_WORKERS: config.maxWorkers(false),\r\n POOL_WORK_LIMIT: config.workLimit(false),\r\n POOL_ACQUIRE_TIMEOUT: config.acquireTimeout(false),\r\n POOL_CREATE_TIMEOUT: config.createTimeout(false),\r\n POOL_DESTROY_TIMEOUT: config.destroyTimeout(false),\r\n POOL_IDLE_TIMEOUT: config.idleTimeout(false),\r\n POOL_CREATE_RETRY_INTERVAL: config.createRetryInterval(false),\r\n POOL_REAPER_INTERVAL: config.reaperInterval(false),\r\n POOL_BENCHMARKING: config.poolBenchmarking(false),\r\n\r\n // logging\r\n LOGGING_LEVEL: config.logLevel(false),\r\n LOGGING_FILE: config.logFile(false),\r\n LOGGING_DEST: config.logDest(false),\r\n LOGGING_TO_CONSOLE: config.logToConsole(false),\r\n LOGGING_TO_FILE: config.logToFile(false),\r\n\r\n // ui\r\n UI_ENABLE: config.enableUi(false),\r\n UI_ROUTE: config.uiRoute(false),\r\n\r\n // other\r\n OTHER_NODE_ENV: config.nodeEnv(false),\r\n OTHER_LISTEN_TO_PROCESS_EXITS: config.listenToProcessExits(false),\r\n OTHER_NO_LOGO: config.noLogo(false),\r\n OTHER_HARD_RESET_PAGE: config.hardResetPage(false),\r\n OTHER_BROWSER_SHELL_MODE: config.browserShellMode(false),\r\n\r\n // debugger\r\n DEBUG_ENABLE: config.enableDebug(false),\r\n DEBUG_HEADLESS: config.headless(false),\r\n DEBUG_DEVTOOLS: config.devtools(false),\r\n DEBUG_LISTEN_TO_CONSOLE: config.listenToConsole(false),\r\n DEBUG_DUMPIO: config.dumpio(false),\r\n DEBUG_SLOW_MO: config.slowMo(false),\r\n DEBUG_DEBUGGING_PORT: config.debuggingPort(false)\r\n});\r\n\r\n/**\r\n * Validates the environment variables options using the EnvSchema.\r\n *\r\n * @param {Object} process.env - The configuration options from environment\r\n * variables file to validate.\r\n *\r\n * @returns {Object} The parsed and validated environment variables.\r\n */\r\nexport const envs = EnvSchema.partial().parse(process.env);\r\n\r\n/**\r\n * Validates the configuration options using the `StrictConfigSchema`.\r\n *\r\n * @function strictValidate\r\n *\r\n * @param {Object} configOptions - The configuration options to validate.\r\n *\r\n * @returns {Object} The parsed and validated configuration options.\r\n */\r\nexport function strictValidate(configOptions) {\r\n return StrictConfigSchema.partial().parse(configOptions);\r\n}\r\n\r\n/**\r\n * Validates the configuration options using the `LooseConfigSchema`.\r\n *\r\n * @function looseValidate\r\n *\r\n * @param {Object} configOptions - The configuration options to validate.\r\n *\r\n * @returns {Object} The parsed and validated configuration options.\r\n */\r\nexport function looseValidate(configOptions) {\r\n return LooseConfigSchema.partial().parse(configOptions);\r\n}\r\n\r\n/**\r\n * Validates a provided option using the specific validator from the config\r\n * object.\r\n *\r\n * @function validateOption\r\n *\r\n * @param {string} name - The name of an option to validate.\r\n * @param {any} option - The option to validate.\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {any} The parsed and validated option value.\r\n */\r\nexport function validateOption(name, option, strictCheck) {\r\n return config[name](strictCheck).parse(option);\r\n}\r\n\r\n/**\r\n * Custom error mapping function for Zod schema validation.\r\n *\r\n * This function customizes the error messages produced by Zod schema\r\n * validation, providing more specific and user-friendly feedback based on the\r\n * issue type and context.\r\n *\r\n * The function modifies the error messages as follows:\r\n *\r\n * - For missing required values (undefined), it returns a message indicating\r\n * that no value was provided for the specific property.\r\n *\r\n * - For custom validation errors, if a custom error message is provided in the\r\n * issue parameters, it includes this message along with the invalid data\r\n * received.\r\n *\r\n * - For all other errors, it appends property-specific information to the\r\n * default error message provided by Zod.\r\n *\r\n * @function _customErrorMap\r\n *\r\n * @param {z.ZodIssue} issue - The issue object representing the validation\r\n * error.\r\n * @param {Object} context - The context object providing additional information\r\n * about the validation error.\r\n *\r\n * @returns {Object} An object containing the customized error message.\r\n */\r\nfunction _customErrorMap(issue, context) {\r\n // Get the chain of properties which error directly refers to\r\n const propertyName = issue.path.join('.');\r\n\r\n // Create the first part of the message about the property information\r\n const propertyInfo = `Invalid value for the ${propertyName}`;\r\n\r\n // Modified message for the invalid type\r\n if (issue.code === z.ZodIssueCode.invalid_type) {\r\n // Modified message for the required values\r\n if (issue.received === z.ZodParsedType.undefined) {\r\n return {\r\n message: `${propertyInfo} - No value was provided.`\r\n };\r\n }\r\n\r\n // Modified message for the specific invalid type when values exist\r\n return {\r\n message: `${propertyInfo} - Invalid type. ${context.defaultError}.`\r\n };\r\n }\r\n\r\n // Modified message for the custom validation\r\n if (issue.code === z.ZodIssueCode.custom) {\r\n // If the custom message for error exist, include it\r\n if (issue.params?.errorMessage) {\r\n return {\r\n message: `${propertyInfo} - ${issue.params?.errorMessage}, received '${context.data}'.`\r\n };\r\n }\r\n }\r\n\r\n // Modified message for the invalid union error\r\n if (issue.code === z.ZodIssueCode.invalid_union) {\r\n // Create the first part of the message about the multiple errors\r\n let message = `Multiple errors occurred for the ${propertyName}:\\n`;\r\n\r\n // Cycle through all errors and create a correct message\r\n issue.unionErrors.forEach((value) => {\r\n const index = value.issues[0].message.indexOf('-');\r\n message +=\r\n index !== -1\r\n ? `${value.issues[0].message}\\n`.substring(index)\r\n : `${value.issues[0].message}\\n`;\r\n });\r\n\r\n // Return the final message for the invalid union error\r\n return {\r\n message\r\n };\r\n }\r\n\r\n // Return the default error message, extended by the info about the property\r\n return {\r\n message: `${propertyInfo} - ${context.defaultError}.`\r\n };\r\n}\r\n\r\nexport default {\r\n StrictConfigSchema,\r\n LooseConfigSchema,\r\n EnvSchema,\r\n envs,\r\n strictValidate,\r\n looseValidate,\r\n validateOption\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * @overview Manages configuration for the Highcharts Export Server by loading\r\n * and merging options from multiple sources, such as default settings,\r\n * environment variables, user-provided options, and command-line arguments.\r\n * Ensures the global options are up-to-date with the highest priority values.\r\n * Provides functions for accessing and updating configuration.\r\n */\r\n\r\nimport { readFileSync } from 'fs';\r\nimport { join } from 'path';\r\n\r\nimport { log, logWithStack, logZodIssues } from './logger.js';\r\nimport { __dirname, isObject, deepCopy, getAbsolutePath } from './utils.js';\r\nimport { envs, looseValidate, strictValidate } from './validation.js';\r\nimport { defaultConfig, nestedProps, absoluteProps } from './schemas/config.js';\r\n\r\n// Sets the global options with initial values from the default config\r\nconst globalOptions = _initGlobalOptions(defaultConfig);\r\n\r\n/**\r\n * Gets the reference to the global options of the server instance object\r\n * or its copy.\r\n *\r\n * @function getOptions\r\n *\r\n * @param {boolean} [getReference=true] - Optional parameter to decide whether\r\n * to return the reference to the global options of the server instance object\r\n * or return a copy of it. The default value is true.\r\n *\r\n * @returns {Object} The reference to the global options of the server instance\r\n * object or its copy.\r\n */\r\nexport function getOptions(getReference = true) {\r\n return getReference ? globalOptions : deepCopy(globalOptions);\r\n}\r\n\r\n/**\r\n * Sets the global options of the export server instance, keeping the principle\r\n * of the options load priority from all available sources. It accepts optional\r\n * `customOptions` object and `cliArgs` array with arguments from the CLI. These\r\n * options will be validated and applied if provided.\r\n *\r\n * The priority order of setting values is:\r\n *\r\n * 1. Options from the `lib/schemas/config.js` file (default values).\r\n * 2. Options from a custom JSON file (loaded by the `loadConfig` option).\r\n * 3. Options from the environment variables (the `.env` file).\r\n * 4. Options from the first parameter (by default an empty object).\r\n * 5. Options from the CLI.\r\n *\r\n * @function setOptions\r\n *\r\n * @param {Object} [customOptions={}] - Optional custom options for additional\r\n * configuration. The default value is an empty object.\r\n * @param {Array.} [cliArgs=[]] - Optional command line arguments\r\n * for additional configuration. The default value is an empty array.\r\n * @param {boolean} [modifyGlobal=false] - Optional parameter to decide\r\n * whether to update and return the reference to the global options\r\n * of the server instance object or return a copy of it. The default value\r\n * is false.\r\n *\r\n * @returns {Object} The updated general options object, reflecting the merged\r\n * configuration from all available sources.\r\n */\r\nexport function setOptions(\r\n customOptions = {},\r\n cliArgs = [],\r\n modifyGlobal = false\r\n) {\r\n // Object for options loaded via the `loadConfig` option\r\n let configOptions = {};\r\n\r\n // Object for options from the CLI\r\n let cliOptions = {};\r\n\r\n // Only for the CLI usage\r\n if (cliArgs.length) {\r\n try {\r\n // Validate options from the custom JSON loaded via the `loadConfig`\r\n configOptions = strictValidate(_loadConfigFile(cliArgs));\r\n } catch (error) {\r\n logZodIssues(\r\n 1,\r\n error.issues,\r\n '[config] Custom JSON options validation error'\r\n );\r\n }\r\n }\r\n\r\n // Apply custom options if there are any\r\n if (customOptions && Object.keys(customOptions).length !== 0) {\r\n try {\r\n // Validate custom options provided by the user\r\n customOptions = strictValidate(customOptions);\r\n } catch (error) {\r\n logZodIssues(1, error.issues, '[config] Custom options validation error');\r\n }\r\n }\r\n\r\n // Only for the CLI usage\r\n if (cliArgs.length) {\r\n try {\r\n // Validate options from the CLI\r\n cliOptions = looseValidate(_pairArgumentValue(nestedProps, cliArgs));\r\n } catch (error) {\r\n logZodIssues(1, error.issues, '[config] CLI options validation error');\r\n }\r\n }\r\n\r\n // Get the reference to the global options object or a copy of the object\r\n const generalOptions = getOptions(modifyGlobal);\r\n\r\n // Update values of the general options with values from each source possible\r\n _updateOptions(\r\n defaultConfig,\r\n generalOptions,\r\n configOptions,\r\n customOptions,\r\n cliOptions\r\n );\r\n\r\n // Return options\r\n return generalOptions;\r\n}\r\n\r\n/**\r\n * Merges two sets of configuration options, considering absolute properties.\r\n *\r\n * @function mergeOptions\r\n *\r\n * @param {Object} originalOptions - Original configuration options.\r\n * @param {Object} newOptions - New configuration options to be merged.\r\n *\r\n * @returns {Object} Merged configuration options.\r\n */\r\nexport function mergeOptions(originalOptions, newOptions) {\r\n // Check if the `newOptions` is a correct object\r\n if (isObject(newOptions)) {\r\n for (const [key, value] of Object.entries(newOptions)) {\r\n originalOptions[key] =\r\n isObject(value) &&\r\n !absoluteProps.includes(key) &&\r\n originalOptions[key] !== undefined\r\n ? mergeOptions(originalOptions[key], value)\r\n : value !== undefined\r\n ? value\r\n : originalOptions[key];\r\n }\r\n }\r\n\r\n // Return the result options\r\n return originalOptions;\r\n}\r\n\r\n/**\r\n * Maps old-structured configuration options (PhantomJS) to a new format\r\n * (Puppeteer). This function converts flat, old-structured options into\r\n * a new, nested configuration format based on a predefined mapping\r\n * (`nestedProps`). The new format is used for Puppeteer, while the old format\r\n * was used for PhantomJS.\r\n *\r\n * @function mapToNewOptions\r\n *\r\n * @param {Object} oldOptions - The old, flat configuration options\r\n * to be converted.\r\n *\r\n * @returns {Object} A new object containing options structured according\r\n * to the mapping defined in `nestedProps` or an empty object if the provided\r\n * `oldOptions` is not a correct object.\r\n */\r\nexport function mapToNewOptions(oldOptions) {\r\n // An object for the new structured options\r\n const newOptions = {};\r\n\r\n // Check if provided value is a correct object\r\n if (Object.prototype.toString.call(oldOptions) === '[object Object]') {\r\n // Iterate over each key-value pair in the old-structured options\r\n for (const [key, value] of Object.entries(oldOptions)) {\r\n // If there is a nested mapping, split it into a properties chain\r\n const propertiesChain = nestedProps[key]\r\n ? nestedProps[key].split('.')\r\n : [];\r\n\r\n // If it is the last property in the chain, assign the value, otherwise,\r\n // create or reuse the nested object\r\n propertiesChain.reduce(\r\n (obj, prop, index) =>\r\n (obj[prop] =\r\n propertiesChain.length - 1 === index ? value : obj[prop] || {}),\r\n newOptions\r\n );\r\n }\r\n }\r\n\r\n // Return the new, structured options object\r\n return newOptions;\r\n}\r\n\r\n/**\r\n * Validates, parses, and checks if the provided config is allowed set\r\n * of options.\r\n *\r\n * @function isAllowedConfig\r\n *\r\n * @param {unknown} config - The config to be validated and parsed as a set\r\n * of options. Must be either an object or a string.\r\n * @param {boolean} [toString=false] - Whether to return a stringified version\r\n * of the parsed config. The default value is false.\r\n * @param {boolean} [allowFunctions=false] - Whether to allow functions\r\n * in the parsed config. If true, functions are preserved. Otherwise, when\r\n * a function is found, null is returned. The default value is false.\r\n *\r\n * @returns {(Object|string|null)} Returns a parsed set of options object,\r\n * a stringified set of options object if the `toString` is true, and null\r\n * if the config is not a valid set of options or parsing fails.\r\n */\r\nexport function isAllowedConfig(\r\n config,\r\n toString = false,\r\n allowFunctions = false\r\n) {\r\n try {\r\n // Accept only objects and strings\r\n if (!isObject(config) && typeof config !== 'string') {\r\n // Return null if any other type\r\n return null;\r\n }\r\n\r\n // Get the object representation of the original config\r\n const objectConfig =\r\n typeof config === 'string'\r\n ? allowFunctions\r\n ? eval(`(${config})`)\r\n : JSON.parse(config)\r\n : config;\r\n\r\n // Preserve or remove potential functions based on the `allowFunctions` flag\r\n const stringifiedOptions = _optionsStringify(\r\n objectConfig,\r\n allowFunctions,\r\n false\r\n );\r\n\r\n // Parse the config to check if it is valid set of options\r\n const parsedOptions = allowFunctions\r\n ? JSON.parse(\r\n _optionsStringify(objectConfig, allowFunctions, true),\r\n (_, value) =>\r\n typeof value === 'string' && value.startsWith('function')\r\n ? eval(`(${value})`)\r\n : value\r\n )\r\n : JSON.parse(stringifiedOptions);\r\n\r\n // Return stringified or object options based on the `toString` flag\r\n return toString ? stringifiedOptions : parsedOptions;\r\n } catch (error) {\r\n // Return null if parsing fails\r\n return null;\r\n }\r\n}\r\n\r\n/**\r\n * Prints the Highcharts Export Server logo, version, and license information.\r\n *\r\n * @function printLicense\r\n */\r\nexport function printLicense() {\r\n // Print the logo and version information\r\n printVersion();\r\n\r\n // Print the license information\r\n console.log(\r\n 'This software requires a valid Highcharts license for commercial use.\\n'\r\n .yellow,\r\n '\\nFor a full list of CLI options, type:',\r\n '\\nhighcharts-export-server --help\\n'.green,\r\n '\\nIf you do not have a license, one can be obtained here:',\r\n '\\nhttps://shop.highsoft.com/\\n'.green,\r\n '\\nTo customize your installation, please refer to the README file at:',\r\n '\\nhttps://github.com/highcharts/node-export-server#readme\\n'.green\r\n );\r\n}\r\n\r\n/**\r\n * Prints usage information for CLI arguments, displaying available options\r\n * and their descriptions. It can list properties recursively if categories\r\n * contain nested options.\r\n *\r\n * @function printUsage\r\n */\r\nexport function printUsage() {\r\n // Display README and general usage information\r\n console.log(\r\n '\\nUsage of CLI arguments:'.bold,\r\n '\\n-----------------------',\r\n `\\nFor more detailed information, visit the README file at: ${'https://github.com/highcharts/node-export-server#readme'.green}.\\n`\r\n );\r\n\r\n // Iterate through each category in the `defaultConfig` and display usage info\r\n Object.keys(defaultConfig).forEach((category) => {\r\n console.log(`${category.toUpperCase()}`.bold.red);\r\n _cycleCategories(defaultConfig[category]);\r\n console.log('');\r\n });\r\n}\r\n\r\n/**\r\n * Prints the Highcharts Export Server logo or text with the version\r\n * information.\r\n *\r\n * @function printVersion\r\n *\r\n * @param {boolean} [noLogo=false] - If true, only prints text with the version\r\n * information, without the logo. The default value is false.\r\n */\r\nexport function printVersion(noLogo = false) {\r\n // Get package version either from `.env` or from `package.json`\r\n const packageVersion = JSON.parse(\r\n readFileSync(join(__dirname, 'package.json'))\r\n ).version;\r\n\r\n // Print text only\r\n if (noLogo) {\r\n console.log(`Highcharts Export Server v${packageVersion}`);\r\n } else {\r\n // Print the logo\r\n console.log(\r\n readFileSync(join(__dirname, 'msg', 'startup.msg')).toString().bold\r\n .yellow,\r\n `v${packageVersion}\\n`.bold\r\n );\r\n }\r\n}\r\n\r\n/**\r\n * Initializes and returns global options object based on provided\r\n * configuration, setting values from nested properties recursively.\r\n *\r\n * @function _initGlobalOptions\r\n *\r\n * @param {Object} config - The configuration object to be used for initializing\r\n * options.\r\n *\r\n * @returns {Object} Initialized options object.\r\n */\r\nfunction _initGlobalOptions(config) {\r\n const options = {};\r\n\r\n // Start initializing the `options` object recursively\r\n for (const [name, item] of Object.entries(config)) {\r\n options[name] = Object.prototype.hasOwnProperty.call(item, 'value')\r\n ? item.value\r\n : _initGlobalOptions(item);\r\n }\r\n\r\n // Return the created `options` object\r\n return options;\r\n}\r\n\r\n/**\r\n * Updates options object with values from various sources, following a specific\r\n * prioritization order. The function checks for values in the following order\r\n * of precedence: the `loadConfig` configuration options, environment variables,\r\n * custom options, and CLI options.\r\n *\r\n * @function _updateOptions\r\n *\r\n * @param {Object} config - The configuration object, which includes the initial\r\n * settings and metadata for each option. This object is used to determine\r\n * the structure and default values for the options.\r\n * @param {Object} options - The options object that will be updated with values\r\n * from other sources.\r\n * @param {Object} configOpt - The configuration options object, loaded with\r\n * the `loadConfig` option, which may provide values to override defaults.\r\n * @param {Object} customOpt - The custom options object, typically containing\r\n * additional and user-defined values, which may override configuration options.\r\n * @param {Object} cliOpt - The CLI options object, which may include values\r\n * provided through command-line arguments and has the highest precedence among\r\n * options.\r\n */\r\nfunction _updateOptions(config, options, configOpt, customOpt, cliOpt) {\r\n Object.keys(config).forEach((key) => {\r\n // Get the config entry of a specific option\r\n const entry = config[key];\r\n\r\n // Gather values for the options from every possible source, if exists\r\n const configVal = configOpt && configOpt[key];\r\n const customVal = customOpt && customOpt[key];\r\n const cliVal = cliOpt && cliOpt[key];\r\n\r\n // If the value not found, need to go deeper\r\n if (typeof entry.value === 'undefined') {\r\n _updateOptions(entry, options[key], configVal, customVal, cliVal);\r\n } else {\r\n // If a value from custom JSON options exists, it take precedence\r\n if (configVal !== undefined && configVal !== null) {\r\n options[key] = configVal;\r\n }\r\n\r\n // If a value from environment variables exists, it take precedence\r\n const envVal = envs[entry.envLink];\r\n if (entry.envLink in envs && envVal !== undefined && envVal !== null) {\r\n options[key] = envVal;\r\n }\r\n\r\n // If a value from user options exists, it take precedence\r\n if (customVal !== undefined && customVal !== null) {\r\n options[key] = customVal;\r\n }\r\n\r\n // If a value from CLI options exists, it take precedence\r\n if (cliVal !== undefined && cliVal !== null) {\r\n options[key] = cliVal;\r\n }\r\n }\r\n });\r\n}\r\n\r\n/**\r\n * Converts the provided options object to a JSON-formatted string\r\n * with the option to preserve functions. In order for a function\r\n * to be preserved, it needs to follow the format `function (...) {...}`.\r\n * Such a function can also be stringified.\r\n *\r\n * @function _optionsStringify\r\n *\r\n * @param {Object} options - The options object to be converted to a string.\r\n * @param {boolean} allowFunctions - If set to true, functions are preserved\r\n * in the output. Otherwise an error is thrown.\r\n * @param {boolean} stringifyFunctions - If set to true, functions are saved\r\n * as strings. The `allowFunctions` must be set to true as well for this to take\r\n * an effect.\r\n *\r\n * @returns {string} The JSON-formatted string representing the options.\r\n *\r\n * @throws {Error} Throws an `Error` when functions are not allowed but are\r\n * found in provided options object.\r\n */\r\nexport function _optionsStringify(options, allowFunctions, stringifyFunctions) {\r\n const replacerCallback = (_, value) => {\r\n // Trim string values\r\n if (typeof value === 'string') {\r\n value = value.trim();\r\n }\r\n\r\n // If value is a function or stringified function\r\n if (\r\n typeof value === 'function' ||\r\n (typeof value === 'string' &&\r\n value.startsWith('function') &&\r\n value.endsWith('}'))\r\n ) {\r\n // If allowFunctions is set to true, preserve functions\r\n if (allowFunctions) {\r\n // Based on the `stringifyFunctions` options, set function values\r\n return stringifyFunctions\r\n ? // As stringified functions\r\n `\"EXP_FUN${(value + '').replaceAll(/\\s+/g, ' ')}EXP_FUN\"`\r\n : // As functions\r\n `EXP_FUN${(value + '').replaceAll(/\\s+/g, ' ')}EXP_FUN`;\r\n } else {\r\n // Throw an error otherwise\r\n throw new Error();\r\n }\r\n }\r\n\r\n // In all other cases, simply return the value\r\n return value;\r\n };\r\n\r\n // Stringify options and if required, replace special functions marks\r\n return JSON.stringify(options, replacerCallback).replaceAll(\r\n stringifyFunctions ? /\\\\\"EXP_FUN|EXP_FUN\\\\\"/g : /\"EXP_FUN|EXP_FUN\"/g,\r\n ''\r\n );\r\n}\r\n\r\n/**\r\n * Loads additional configuration from a specified file provided via\r\n * the `loadConfig` option in the command-line arguments.\r\n *\r\n * @function _loadConfigFile\r\n *\r\n * @param {Array.} cliArgs - Command-line arguments to search\r\n * for the `loadConfig` option and the corresponding file path.\r\n *\r\n * @returns {Object} The additional configuration loaded from the specified\r\n * file, or an empty object if the file is not found, invalid, or an error\r\n * occurs.\r\n */\r\nfunction _loadConfigFile(cliArgs) {\r\n // Check if the `loadConfig` option was used\r\n const configIndex = cliArgs.findIndex(\r\n (arg) => arg.replace(/-/g, '') === 'loadConfig'\r\n );\r\n\r\n // Get the `loadConfig` option value\r\n const configFileName = configIndex > -1 && cliArgs[configIndex + 1];\r\n\r\n // Check if the `loadConfig` is present and has a correct value\r\n if (configFileName) {\r\n try {\r\n // Load an optional custom JSON config file\r\n return JSON.parse(readFileSync(getAbsolutePath(configFileName)));\r\n } catch (error) {\r\n logWithStack(\r\n 2,\r\n error,\r\n `[config] Unable to load the configuration from the ${configFileName} file.`\r\n );\r\n }\r\n }\r\n\r\n // No additional options to return\r\n return {};\r\n}\r\n\r\n/**\r\n * Parses command-line arguments and pairs each argument with its corresponding\r\n * option in the configuration. The values are structured into a nested options\r\n * object, based on predefined mappings.\r\n *\r\n * @function _pairArgumentValue\r\n *\r\n * @param {Array.} nestedProps - An array of nesting level for all\r\n * options.\r\n * @param {Array.} cliArgs - An array of command-line arguments\r\n * containing options and their associated values.\r\n *\r\n * @returns {Object} An updated options object where each option from\r\n * the command-line is paired with its value, structured into nested objects\r\n * as defined.\r\n */\r\nfunction _pairArgumentValue(nestedProps, cliArgs) {\r\n // An empty object to collect and structurize data from the args\r\n const cliOptions = {};\r\n\r\n // Cycle through all CLI args and filter them\r\n for (let i = 0; i < cliArgs.length; i++) {\r\n const option = cliArgs[i].replace(/-/g, '');\r\n\r\n // Find the right place for property's value\r\n const propertiesChain = nestedProps[option]\r\n ? nestedProps[option].split('.')\r\n : [];\r\n\r\n // Create options object with values from CLI for later parsing and merging\r\n propertiesChain.reduce((obj, prop, index) => {\r\n if (propertiesChain.length - 1 === index) {\r\n const value = cliArgs[++i];\r\n if (!value) {\r\n log(\r\n 2,\r\n `[config] Missing value for the CLI '--${option}' argument. Using the default value.`\r\n );\r\n }\r\n obj[prop] = value || null;\r\n } else if (obj[prop] === undefined) {\r\n obj[prop] = {};\r\n }\r\n return obj[prop];\r\n }, cliOptions);\r\n }\r\n\r\n // Return parsed CLI options\r\n return cliOptions;\r\n}\r\n\r\n/**\r\n * Recursively traverses the options object to print the usage information\r\n * for each option category and individual option.\r\n *\r\n * @function _cycleCategories\r\n *\r\n * @param {Object} options - The options object containing CLI options.\r\n * It may include nested categories and individual options.\r\n */\r\nfunction _cycleCategories(options) {\r\n for (const [name, option] of Object.entries(options)) {\r\n // If the current entry is a category and not a leaf option, recurse into it\r\n if (!Object.prototype.hasOwnProperty.call(option, 'value')) {\r\n _cycleCategories(option);\r\n } else {\r\n // Prepare description\r\n const descName = ` --${option.cliName || name}`;\r\n\r\n // Get the value\r\n let optionValue = option.value;\r\n\r\n // Prepare value for option that is not null and is array of strings\r\n if (optionValue !== null && option.types.includes('string[]')) {\r\n optionValue =\r\n '[' + optionValue.map((item) => `'${item}'`).join(', ') + ']';\r\n }\r\n\r\n // Prepare value for option that is not null and is a string\r\n if (optionValue !== null && option.types.includes('string')) {\r\n optionValue = `'${optionValue}'`;\r\n }\r\n\r\n // Display correctly aligned messages\r\n console.log(\r\n descName.green,\r\n `${('<' + option.types.join('|') + '>').yellow}`,\r\n `${String(optionValue).bold}`.blue,\r\n `- ${option.description}.`\r\n );\r\n }\r\n }\r\n}\r\n\r\nexport default {\r\n getOptions,\r\n setOptions,\r\n mergeOptions,\r\n mapToNewOptions,\r\n isAllowedConfig,\r\n printLicense,\r\n printUsage,\r\n printVersion\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * @overview HTTP utility module for fetching and posting data. Supports both\r\n * HTTP and HTTPS protocols, providing methods to make GET and POST requests\r\n * with customizable options. Includes protocol determination based on URL\r\n * and augments response objects with a 'text' property for easier data access.\r\n */\r\n\r\nimport http from 'http';\r\nimport https from 'https';\r\n\r\n/**\r\n * Fetches data from the specified URL using either HTTP or HTTPS protocol.\r\n *\r\n * @async\r\n * @function fetch\r\n *\r\n * @param {string} url - The URL to fetch data from.\r\n * @param {Object} [requestOptions={}] - Options for the HTTP/HTTPS request.\r\n * The default value is an empty object.\r\n *\r\n * @returns {Promise} A Promise that resolves to the HTTP/HTTPS response\r\n * object with added 'text' property or rejecting with an error.\r\n */\r\nexport async function fetch(url, requestOptions = {}) {\r\n return new Promise((resolve, reject) => {\r\n _getProtocolModule(url)\r\n .get(url, requestOptions, (response) => {\r\n let responseData = '';\r\n\r\n // A chunk of data has been received\r\n response.on('data', (chunk) => {\r\n responseData += chunk;\r\n });\r\n\r\n // The whole response has been received\r\n response.on('end', () => {\r\n if (!responseData) {\r\n reject('Nothing was fetched from the URL.');\r\n }\r\n response.text = responseData;\r\n resolve(response);\r\n });\r\n })\r\n .on('error', (error) => {\r\n reject(error);\r\n });\r\n });\r\n}\r\n\r\n/**\r\n * Sends a POST request to the specified URL with the provided JSON body using\r\n * either HTTP or HTTPS protocol.\r\n *\r\n * @async\r\n * @function post\r\n *\r\n * @param {string} url - The URL to send the POST request to.\r\n * @param {Object} [body={}] - The JSON body to include in the POST request.\r\n * The default value is an empty object.\r\n * @param {Object} [requestOptions={}] - Options for the HTTP/HTTPS request.\r\n * The default value is an empty object.\r\n *\r\n * @returns {Promise} A Promise that resolves to the HTTP/HTTPS response\r\n * object with added 'text' property or rejecting with an error.\r\n */\r\nexport async function post(url, body = {}, requestOptions = {}) {\r\n return new Promise((resolve, reject) => {\r\n const data = JSON.stringify(body);\r\n\r\n // Set default headers and merge with requestOptions\r\n const options = Object.assign(\r\n {\r\n method: 'POST',\r\n headers: {\r\n 'Content-Type': 'application/json',\r\n 'Content-Length': data.length\r\n }\r\n },\r\n requestOptions\r\n );\r\n\r\n const request = _getProtocolModule(url)\r\n .request(url, options, (response) => {\r\n let responseData = '';\r\n\r\n // A chunk of data has been received\r\n response.on('data', (chunk) => {\r\n responseData += chunk;\r\n });\r\n\r\n // The whole response has been received\r\n response.on('end', () => {\r\n try {\r\n response.text = responseData;\r\n resolve(response);\r\n } catch (error) {\r\n reject(error);\r\n }\r\n });\r\n })\r\n .on('error', (error) => {\r\n reject(error);\r\n });\r\n\r\n // Write the request body and end the request\r\n request.write(data);\r\n request.end();\r\n });\r\n}\r\n\r\n/**\r\n * Returns the HTTP or HTTPS protocol module based on the provided URL.\r\n *\r\n * @function _getProtocolModule\r\n *\r\n * @param {string} url - The URL to determine the protocol.\r\n *\r\n * @returns {Object} The HTTP or HTTPS protocol module (http or https).\r\n */\r\nfunction _getProtocolModule(url) {\r\n return url.startsWith('https') ? https : http;\r\n}\r\n\r\nexport default {\r\n fetch,\r\n post\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * A custom error class for handling export-related errors. Extends the native\r\n * `Error` class to include additional properties like status code and stack\r\n * trace details.\r\n */\r\nclass ExportError extends Error {\r\n /**\r\n * Creates an instance of the `ExportError`.\r\n *\r\n * @param {string} message - The error message to be displayed.\r\n * @param {number} statusCode - Optional HTTP status code associated\r\n * with the error (e.g., 400, 500).\r\n */\r\n constructor(message, statusCode) {\r\n super();\r\n\r\n this.message = message;\r\n this.stackMessage = message;\r\n\r\n if (statusCode) {\r\n this.statusCode = statusCode;\r\n }\r\n }\r\n\r\n /**\r\n * Sets additional error details based on an existing error object.\r\n *\r\n * @param {Error} error - An error object containing details to populate\r\n * the `ExportError` instance.\r\n *\r\n * @returns {ExportError} The updated instance of the `ExportError` class.\r\n */\r\n setError(error) {\r\n this.error = error;\r\n\r\n if (error.name) {\r\n this.name = error.name;\r\n }\r\n\r\n if (error.statusCode) {\r\n this.statusCode = error.statusCode;\r\n }\r\n\r\n if (error.stack) {\r\n this.stackMessage = error.message;\r\n this.stack = error.stack;\r\n }\r\n\r\n return this;\r\n }\r\n}\r\n\r\nexport default ExportError;\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * @overview The cache manager is responsible for handling and managing\r\n * the Highcharts library along with its dependencies. It ensures that these\r\n * resources are stored and retrieved efficiently to optimize performance\r\n * and reduce redundant network requests. The cache is stored in the `.cache`\r\n * directory by default, which serves as a dedicated folder for keeping cached\r\n * files.\r\n */\r\n\r\nimport { existsSync, mkdirSync, readFileSync, writeFileSync } from 'fs';\r\nimport { join } from 'path';\r\n\r\nimport { HttpsProxyAgent } from 'https-proxy-agent';\r\n\r\nimport { getOptions } from './config.js';\r\nimport { fetch } from './fetch.js';\r\nimport { log } from './logger.js';\r\nimport { __dirname, getAbsolutePath } from './utils.js';\r\n\r\nimport ExportError from './errors/ExportError.js';\r\n\r\n// The initial cache template\r\nconst cache = {\r\n cdnUrl: 'https://code.highcharts.com',\r\n activeManifest: {},\r\n sources: '',\r\n hcVersion: ''\r\n};\r\n\r\n/**\r\n * Checks the cache for Highcharts dependencies, updates the cache if needed,\r\n * and loads the sources.\r\n *\r\n * @async\r\n * @function checkAndUpdateCache\r\n *\r\n * @param {Object} highchartsOptions - Object containing `highcharts` options.\r\n * @param {Object} serverProxyOptions - Object containing `server.proxy`\r\n * options.\r\n */\r\nexport async function checkAndUpdateCache(\r\n highchartsOptions,\r\n serverProxyOptions\r\n) {\r\n let fetchedModules;\r\n\r\n // Get the cache path\r\n const cachePath = getCachePath();\r\n\r\n // Prepare paths to manifest and sources from the cache folder\r\n const manifestPath = join(cachePath, 'manifest.json');\r\n const sourcePath = join(cachePath, 'sources.js');\r\n\r\n // Create the cache destination if it doesn't exist already\r\n !existsSync(cachePath) && mkdirSync(cachePath, { recursive: true });\r\n\r\n // Fetch all the scripts either if the `manifest.json` does not exist\r\n // or if the `forceFetch` option is enabled\r\n if (!existsSync(manifestPath) || highchartsOptions.forceFetch) {\r\n log(3, '[cache] Fetching and caching Highcharts dependencies.');\r\n fetchedModules = await _updateCache(\r\n highchartsOptions,\r\n serverProxyOptions,\r\n sourcePath\r\n );\r\n } else {\r\n let requestUpdate = false;\r\n\r\n // Read the manifest JSON\r\n const manifest = JSON.parse(readFileSync(manifestPath));\r\n\r\n // Check if the modules is an array, if so, we rewrite it to a map to make\r\n // it easier to resolve modules.\r\n if (manifest.modules && Array.isArray(manifest.modules)) {\r\n const moduleMap = {};\r\n manifest.modules.forEach((m) => (moduleMap[m] = 1));\r\n manifest.modules = moduleMap;\r\n }\r\n\r\n // Get the actual number of scripts to be fetched\r\n const { coreScripts, moduleScripts, indicatorScripts } = highchartsOptions;\r\n const numberOfModules =\r\n coreScripts.length + moduleScripts.length + indicatorScripts.length;\r\n\r\n // Compare the loaded highcharts config with the contents in cache.\r\n // If there are changes, fetch requested modules and products,\r\n // and bake them into a giant blob. Save the blob.\r\n if (manifest.version !== highchartsOptions.version) {\r\n log(\r\n 2,\r\n '[cache] A Highcharts version mismatch in the cache, need to re-fetch.'\r\n );\r\n requestUpdate = true;\r\n } else if (Object.keys(manifest.modules || {}).length !== numberOfModules) {\r\n log(\r\n 2,\r\n '[cache] The cache and the requested modules do not match, need to re-fetch.'\r\n );\r\n requestUpdate = true;\r\n } else {\r\n // Check each module, if anything is missing refetch everything\r\n requestUpdate = (moduleScripts || []).some((moduleName) => {\r\n if (!manifest.modules[moduleName]) {\r\n log(\r\n 2,\r\n `[cache] The ${moduleName} is missing in the cache, need to re-fetch.`\r\n );\r\n return true;\r\n }\r\n });\r\n }\r\n\r\n // Update cache if needed\r\n if (requestUpdate) {\r\n fetchedModules = await _updateCache(\r\n highchartsOptions,\r\n serverProxyOptions,\r\n sourcePath\r\n );\r\n } else {\r\n log(3, '[cache] Dependency cache is up to date, proceeding.');\r\n\r\n // Load the sources\r\n cache.sources = readFileSync(sourcePath, 'utf8');\r\n\r\n // Get current modules map\r\n fetchedModules = manifest.modules;\r\n\r\n // Extract and save version of currently used Highcharts\r\n cache.hcVersion = extractVersion(cache.sources);\r\n }\r\n }\r\n\r\n // Finally, save the new manifest, which is basically our current config\r\n // in a slightly different format\r\n await _saveConfigToManifest(highchartsOptions, fetchedModules);\r\n}\r\n\r\n/**\r\n * Gets the version of Highcharts from the cache.\r\n *\r\n * @function getHighchartsVersion\r\n *\r\n * @returns {string} The cached Highcharts version.\r\n */\r\nexport function getHighchartsVersion() {\r\n return cache.hcVersion;\r\n}\r\n\r\n/**\r\n * Updates the Highcharts version in the applied configuration and checks\r\n * the cache for the new version.\r\n *\r\n * @async\r\n * @function updateHighchartsVersion\r\n *\r\n * @param {string} newVersion - The new Highcharts version to be applied.\r\n */\r\nexport async function updateHighchartsVersion(newVersion) {\r\n // Get the reference to the global options to update to the new version\r\n const options = getOptions();\r\n\r\n // Set to the new version\r\n options.highcharts.version = newVersion;\r\n\r\n // Check if cache needs to be updated\r\n await checkAndUpdateCache(options.highcharts, options.server.proxy);\r\n}\r\n\r\n/**\r\n * Extracts Highcharts version from the cache's sources string.\r\n *\r\n * @function extractVersion\r\n *\r\n * @param {Object} cacheSources - The cache sources object.\r\n *\r\n * @returns {string} The extracted Highcharts version.\r\n */\r\nexport function extractVersion(cacheSources) {\r\n return cacheSources\r\n .substring(0, cacheSources.indexOf('*/'))\r\n .replace('/*', '')\r\n .replace('*/', '')\r\n .replace(/\\n/g, '')\r\n .trim();\r\n}\r\n\r\n/**\r\n * Extracts the Highcharts module name based on the scriptPath.\r\n *\r\n * @function extractModuleName\r\n *\r\n * @param {string} scriptPath - The path of the script from which the module\r\n * name will be extracted.\r\n *\r\n * @returns {string} The extracted module name.\r\n */\r\nexport function extractModuleName(scriptPath) {\r\n return scriptPath.replace(\r\n /(.*)\\/|(.*)modules\\/|stock\\/(.*)indicators\\/|maps\\/(.*)modules\\//gi,\r\n ''\r\n );\r\n}\r\n\r\n/**\r\n * Retrieves the current cache object.\r\n *\r\n * @function getCache\r\n *\r\n * @returns {Object} The cache object containing various cached data.\r\n */\r\nexport function getCache() {\r\n return cache;\r\n}\r\n\r\n/**\r\n * Gets the cache path for Highcharts.\r\n *\r\n * @function getCachePath\r\n *\r\n * @returns {string} The absolute path to the cache directory for Highcharts.\r\n */\r\nexport function getCachePath() {\r\n return getAbsolutePath(getOptions().highcharts.cachePath); // #562\r\n}\r\n\r\n/**\r\n * Fetches a single script and updates the `fetchedModules` accordingly.\r\n *\r\n * @async\r\n * @function _fetchAndProcessScript\r\n *\r\n * @param {string} script - A path to script to get.\r\n * @param {Object} requestOptions - Additional options for the proxy agent\r\n * to use for a request.\r\n * @param {Object} fetchedModules - An object which tracks which Highcharts\r\n * modules have been fetched.\r\n * @param {boolean} [shouldThrowError=false] - A flag to indicate if the error\r\n * should be thrown. This should be used only for the core scripts. The default\r\n * value is false.\r\n *\r\n * @returns {Promise} A Promise that resolves to the text representation\r\n * of the fetched script.\r\n *\r\n * @throws {ExportError} Throws an `ExportError` if there is a problem\r\n * with fetching the script.\r\n */\r\nasync function _fetchAndProcessScript(\r\n script,\r\n requestOptions,\r\n fetchedModules,\r\n shouldThrowError = false\r\n) {\r\n // Get rid of the .js from the custom strings\r\n if (script.endsWith('.js')) {\r\n script = script.substring(0, script.length - 3);\r\n }\r\n log(4, `[cache] Fetching script - ${script}.js`);\r\n\r\n // Fetch the script\r\n const response = await fetch(`${script}.js`, requestOptions);\r\n\r\n // If OK, return its text representation\r\n if (response.statusCode === 200 && typeof response.text == 'string') {\r\n if (fetchedModules) {\r\n const moduleName = extractModuleName(script);\r\n fetchedModules[moduleName] = 1;\r\n }\r\n return response.text;\r\n }\r\n\r\n // Based on the `shouldThrowError` flag, decide how to serve error message\r\n if (shouldThrowError) {\r\n throw new ExportError(\r\n `[cache] Could not fetch the ${script}.js. The script might not exist in the requested version (status code: ${response.statusCode}).`,\r\n 404\r\n ).setError(response);\r\n } else {\r\n log(\r\n 2,\r\n `[cache] Could not fetch the ${script}.js. The script might not exist in the requested version.`\r\n );\r\n }\r\n}\r\n\r\n/**\r\n * Saves the provided configuration and fetched modules to the cache manifest\r\n * file.\r\n *\r\n * @async\r\n * @function _saveConfigToManifest\r\n *\r\n * @param {Object} highchartsOptions - Object containing `highcharts` options.\r\n * @param {Object} [fetchedModules={}] - An object which tracks which Highcharts\r\n * modules have been fetched. The default value is an empty object.\r\n *\r\n * @throws {ExportError} Throws an `ExportError` if an error occurs while\r\n * writing the cache manifest.\r\n */\r\nasync function _saveConfigToManifest(highchartsOptions, fetchedModules = {}) {\r\n const newManifest = {\r\n version: highchartsOptions.version,\r\n modules: fetchedModules\r\n };\r\n\r\n // Update cache object with the current modules\r\n cache.activeManifest = newManifest;\r\n\r\n log(3, '[cache] Writing a new manifest.');\r\n try {\r\n writeFileSync(\r\n join(getCachePath(), 'manifest.json'),\r\n JSON.stringify(newManifest),\r\n 'utf8'\r\n );\r\n } catch (error) {\r\n throw new ExportError(\r\n '[cache] Error writing the cache manifest.',\r\n 500\r\n ).setError(error);\r\n }\r\n}\r\n\r\n/**\r\n * Fetches Highcharts `scripts` and `customScripts` from the given CDNs.\r\n *\r\n * @async\r\n * @function _fetchScripts\r\n *\r\n * @param {Array.} coreScripts - Highcharts core scripts to fetch.\r\n * @param {Array.} moduleScripts - Highcharts modules to fetch.\r\n * @param {Array.} customScripts - Custom script paths to fetch (full\r\n * URLs).\r\n * @param {Object} serverProxyOptions - Object containing `server.proxy`\r\n * options.\r\n * @param {Object} fetchedModules - An object which tracks which Highcharts\r\n * modules have been fetched.\r\n *\r\n * @returns {Promise} A Promise that resolves to the fetched scripts\r\n * content joined.\r\n *\r\n * @throws {ExportError} Throws an `ExportError` if an error occurs while\r\n * setting an HTTP Agent for proxy.\r\n */\r\nasync function _fetchScripts(\r\n coreScripts,\r\n moduleScripts,\r\n customScripts,\r\n serverProxyOptions,\r\n fetchedModules\r\n) {\r\n // Configure proxy if exists\r\n let proxyAgent;\r\n const proxyHost = serverProxyOptions.host;\r\n const proxyPort = serverProxyOptions.port;\r\n\r\n // Try to create a Proxy Agent\r\n if (proxyHost && proxyPort) {\r\n try {\r\n proxyAgent = new HttpsProxyAgent({\r\n host: proxyHost,\r\n port: proxyPort\r\n });\r\n } catch (error) {\r\n throw new ExportError(\r\n '[cache] Could not create a Proxy Agent.',\r\n 500\r\n ).setError(error);\r\n }\r\n }\r\n\r\n // If exists, add proxy agent to request options\r\n const requestOptions = proxyAgent\r\n ? {\r\n agent: proxyAgent,\r\n timeout: serverProxyOptions.timeout\r\n }\r\n : {};\r\n\r\n const allFetchPromises = [\r\n ...coreScripts.map((script) =>\r\n _fetchAndProcessScript(`${script}`, requestOptions, fetchedModules, true)\r\n ),\r\n ...moduleScripts.map((script) =>\r\n _fetchAndProcessScript(`${script}`, requestOptions, fetchedModules)\r\n ),\r\n ...customScripts.map((script) =>\r\n _fetchAndProcessScript(`${script}`, requestOptions)\r\n )\r\n ];\r\n\r\n const fetchedScripts = await Promise.all(allFetchPromises);\r\n return fetchedScripts.join(';\\n');\r\n}\r\n\r\n/**\r\n * Updates the local cache with Highcharts scripts and their versions.\r\n *\r\n * @async\r\n * @function _updateCache\r\n *\r\n * @param {Object} highchartsOptions - Object containing `highcharts` options.\r\n * @param {Object} serverProxyOptions - Object containing `server.proxy`\r\n * options.\r\n * @param {string} sourcePath - The path to the source file in the cache.\r\n *\r\n * @returns {Promise} A Promise that resolves to an object representing\r\n * the fetched modules.\r\n *\r\n * @throws {ExportError} Throws an `ExportError` if there is an issue updating\r\n * the local Highcharts cache.\r\n */\r\nasync function _updateCache(highchartsOptions, serverProxyOptions, sourcePath) {\r\n // Get Highcharts version for scripts\r\n const hcVersion =\r\n highchartsOptions.version === 'latest'\r\n ? null\r\n : `${highchartsOptions.version}`;\r\n\r\n // Get the CDN url for scripts\r\n const cdnUrl = highchartsOptions.cdnUrl || cache.cdnUrl;\r\n\r\n try {\r\n const fetchedModules = {};\r\n\r\n log(\r\n 3,\r\n `[cache] Updating cache version to Highcharts: ${hcVersion || 'latest'}.`\r\n );\r\n\r\n cache.sources = await _fetchScripts(\r\n [\r\n ...highchartsOptions.coreScripts.map((c) =>\r\n hcVersion ? `${cdnUrl}/${hcVersion}/${c}` : `${cdnUrl}/${c}`\r\n )\r\n ],\r\n [\r\n ...highchartsOptions.moduleScripts.map((m) =>\r\n m === 'map'\r\n ? hcVersion\r\n ? `${cdnUrl}/maps/${hcVersion}/modules/${m}`\r\n : `${cdnUrl}/maps/modules/${m}`\r\n : hcVersion\r\n ? `${cdnUrl}/${hcVersion}/modules/${m}`\r\n : `${cdnUrl}/modules/${m}`\r\n ),\r\n ...highchartsOptions.indicatorScripts.map((i) =>\r\n hcVersion\r\n ? `${cdnUrl}/stock/${hcVersion}/indicators/${i}`\r\n : `${cdnUrl}/stock/indicators/${i}`\r\n )\r\n ],\r\n highchartsOptions.customScripts,\r\n serverProxyOptions,\r\n fetchedModules\r\n );\r\n\r\n // Extract and save version of currently used Highcharts\r\n cache.hcVersion = extractVersion(cache.sources);\r\n\r\n // Save the fetched modules into caches' source JSON\r\n writeFileSync(sourcePath, cache.sources);\r\n return fetchedModules;\r\n } catch (error) {\r\n throw new ExportError(\r\n '[cache] Unable to update the local Highcharts cache.',\r\n 500\r\n ).setError(error);\r\n }\r\n}\r\n\r\nexport default {\r\n checkAndUpdateCache,\r\n getHighchartsVersion,\r\n updateHighchartsVersion,\r\n extractVersion,\r\n extractModuleName,\r\n getCache,\r\n getCachePath\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * @overview Provides methods for initializing Highcharts with customized\r\n * animation settings and triggering the creation of Highcharts charts with\r\n * export-specific configurations in the page context. Supports dynamic option\r\n * merging, custom logic injection, and control over rendering behaviors. Used\r\n * by the Puppeteer page.\r\n */\r\n\r\n/* eslint-disable no-undef */\r\n\r\n/**\r\n * Setting the `Highcharts.animObject` function. Called when initing the page.\r\n *\r\n * @function setupHighcharts\r\n */\r\nexport function setupHighcharts() {\r\n Highcharts.animObject = function () {\r\n return { duration: 0 };\r\n };\r\n}\r\n\r\n/**\r\n * Creates the actual Highcharts chart on a page.\r\n *\r\n * @async\r\n * @function createChart\r\n *\r\n * @param {Object} options - The `options` object containing complete set\r\n * of options.\r\n */\r\nexport async function createChart(options) {\r\n // Get required functions\r\n const { getOptions, merge, setOptions, wrap } = Highcharts;\r\n\r\n // Create a separate object for a potential `setOptions` usages in order\r\n // to prevent from polluting other exports that can happen on the same page\r\n Highcharts.setOptionsObj = merge(false, {}, getOptions());\r\n\r\n // NOTE: Is this used for anything useful?\r\n window.isRenderComplete = false;\r\n wrap(Highcharts.Chart.prototype, 'init', function (proceed, userOptions, cb) {\r\n // Override userOptions with image friendly options\r\n userOptions = merge(userOptions, {\r\n exporting: {\r\n enabled: false\r\n },\r\n plotOptions: {\r\n series: {\r\n label: {\r\n enabled: false\r\n }\r\n }\r\n },\r\n /* Expects tooltip in userOptions when forExport is true.\r\n https://github.com/highcharts/highcharts/blob/3ad430a353b8056b9e764aa4e5cd6828aa479db2/js/parts/Chart.js#L241\r\n */\r\n tooltip: {}\r\n });\r\n\r\n (userOptions.series || []).forEach(function (series) {\r\n series.animation = false;\r\n });\r\n\r\n // Add flag to know if chart render has been called.\r\n if (!window.onHighchartsRender) {\r\n window.onHighchartsRender = Highcharts.addEvent(this, 'render', () => {\r\n window.isRenderComplete = true;\r\n });\r\n }\r\n\r\n proceed.apply(this, [userOptions, cb]);\r\n });\r\n\r\n wrap(Highcharts.Series.prototype, 'init', function (proceed, chart, options) {\r\n proceed.apply(this, [chart, options]);\r\n });\r\n\r\n // Some mandatory additional `chart` and `exporting` options\r\n const additionalOptions = {\r\n chart: {\r\n // By default animation is disabled\r\n animation: false,\r\n // Get the right size values\r\n height: options.export.height,\r\n width: options.export.width\r\n },\r\n exporting: {\r\n // No need for the exporting button\r\n enabled: false\r\n }\r\n };\r\n\r\n // Get the input to export from the `instr` option\r\n const userOptions = new Function(`return ${options.export.instr}`)();\r\n\r\n // Get the `themeOptions` option\r\n const themeOptions = new Function(`return ${options.export.themeOptions}`)();\r\n\r\n // Get the `globalOptions` option\r\n const globalOptions = new Function(\r\n `return ${options.export.globalOptions}`\r\n )();\r\n\r\n // Merge the following options objects to create final options\r\n const finalOptions = merge(\r\n false,\r\n themeOptions,\r\n userOptions,\r\n // Placed it here instead in the init because of the size issues\r\n additionalOptions\r\n );\r\n\r\n // Prepare the `callback` option\r\n const finalCallback = options.customLogic.callback\r\n ? new Function(`return ${options.customLogic.callback}`)()\r\n : null;\r\n\r\n // Trigger the `customCode` option\r\n if (options.customLogic.customCode) {\r\n new Function('options', options.customLogic.customCode)(userOptions);\r\n }\r\n\r\n // Set the global options if exist\r\n if (globalOptions) {\r\n setOptions(globalOptions);\r\n }\r\n\r\n // Call the chart creation\r\n Highcharts[options.export.constr]('container', finalOptions, finalCallback);\r\n\r\n // Get the current global options\r\n const defaultOptions = getOptions();\r\n\r\n // Clear it just in case (e.g. the `setOptions` was used in the `customCode`)\r\n for (const prop in defaultOptions) {\r\n if (typeof defaultOptions[prop] !== 'function') {\r\n delete defaultOptions[prop];\r\n }\r\n }\r\n\r\n // Set the default options back\r\n setOptions(Highcharts.setOptionsObj);\r\n\r\n // Empty the custom global options object\r\n Highcharts.setOptionsObj = {};\r\n}\r\n\r\nexport default {\r\n setupHighcharts,\r\n createChart\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * @overview This module provides functions for managing Puppeteer browser\r\n * instance, creating and clearing pages, injecting custom resources,\r\n * and setting up Highcharts for server-side rendering. The module ensures\r\n * that resources are correctly managed and can handle failures during\r\n * operations like launching the browser or creating new pages.\r\n */\r\n\r\nimport { readFileSync } from 'fs';\r\nimport { join } from 'path';\r\n\r\nimport puppeteer from 'puppeteer';\r\n\r\nimport { getCachePath } from './cache.js';\r\nimport { getOptions } from './config.js';\r\nimport { setupHighcharts } from './highcharts.js';\r\nimport { log, logWithStack } from './logger.js';\r\nimport { __dirname, getAbsolutePath } from './utils.js';\r\n\r\nimport ExportError from './errors/ExportError.js';\r\n\r\n// Get the template for pages\r\nconst template = readFileSync(\r\n join(__dirname, 'templates', 'template.html'),\r\n 'utf8'\r\n);\r\n\r\n// To save the browser\r\nlet browser = null;\r\n\r\n/**\r\n * Retrieves the existing Puppeteer browser instance.\r\n *\r\n * @function getBrowser\r\n *\r\n * @returns {Object} The Puppeteer browser instance.\r\n *\r\n * @throws {ExportError} Throws an `ExportError` if no valid browser\r\n * has been created.\r\n */\r\nexport function getBrowser() {\r\n if (!browser) {\r\n throw new ExportError('[browser] No valid browser has been created.', 500);\r\n }\r\n return browser;\r\n}\r\n\r\n/**\r\n * Creates a Puppeteer browser instance with the specified arguments.\r\n *\r\n * @async\r\n * @function createBrowser\r\n *\r\n * @param {Array.} puppeteerArgs - Additional arguments for Puppeteer\r\n * launch.\r\n *\r\n * @returns {Promise} A Promise that resolves to the created Puppeteer\r\n * browser instance.\r\n *\r\n * @throws {ExportError} Throws an `ExportError` if max retries to open\r\n * a browser instance are reached, or if no browser instance is found after\r\n * retries.\r\n */\r\nexport async function createBrowser(puppeteerArgs) {\r\n // Get `debug` and `other` options\r\n const { debug, other } = getOptions();\r\n\r\n // Get the `debug` options\r\n const { enable: enabledDebug, ...debugOptions } = debug;\r\n\r\n // Launch options for the browser instance\r\n const launchOptions = {\r\n headless: other.browserShellMode ? 'shell' : true,\r\n userDataDir: 'tmp',\r\n args: puppeteerArgs || [],\r\n handleSIGINT: false,\r\n handleSIGTERM: false,\r\n handleSIGHUP: false,\r\n waitForInitialPage: false,\r\n defaultViewport: null,\r\n ...(enabledDebug && debugOptions)\r\n };\r\n\r\n // Create a browser\r\n if (!browser) {\r\n // A counter for the browser's launch retries\r\n let tryCount = 0;\r\n\r\n const open = async () => {\r\n try {\r\n log(\r\n 3,\r\n `[browser] Attempting to get a browser instance (try ${++tryCount}).`\r\n );\r\n\r\n // Launch the browser\r\n browser = await puppeteer.launch(launchOptions);\r\n } catch (error) {\r\n logWithStack(\r\n 1,\r\n error,\r\n '[browser] Failed to launch a browser instance.'\r\n );\r\n\r\n // Retry to launch browser until reaching max attempts\r\n if (tryCount < 25) {\r\n log(3, `[browser] Retry to open a browser (${tryCount} out of 25).`);\r\n\r\n // Wait for a 4 seconds before trying again\r\n await new Promise((response) => setTimeout(response, 4000));\r\n await open();\r\n } else {\r\n throw error;\r\n }\r\n }\r\n };\r\n\r\n try {\r\n await open();\r\n\r\n // Shell mode inform\r\n if (launchOptions.headless === 'shell') {\r\n log(3, `[browser] Launched browser in shell mode.`);\r\n }\r\n\r\n // Debug mode inform\r\n if (enabledDebug) {\r\n log(3, `[browser] Launched browser in debug mode.`);\r\n }\r\n } catch (error) {\r\n throw new ExportError(\r\n '[browser] Maximum retries to open a browser instance reached.',\r\n 500\r\n ).setError(error);\r\n }\r\n\r\n if (!browser) {\r\n throw new ExportError('[browser] Cannot find a browser to open.', 500);\r\n }\r\n }\r\n\r\n // Return a browser instance\r\n return browser;\r\n}\r\n\r\n/**\r\n * Closes the Puppeteer browser instance if it is connected.\r\n *\r\n * @async\r\n * @function closeBrowser\r\n */\r\nexport async function closeBrowser() {\r\n // Close the browser when connected\r\n if (browser && browser.connected) {\r\n await browser.close();\r\n }\r\n browser = null;\r\n log(4, '[browser] Closed the browser.');\r\n}\r\n\r\n/**\r\n * Creates a new Puppeteer page within an existing browser instance.\r\n * The function creates a new page, disables caching, sets content using\r\n * the `_setPageContent()`, and returns the created Puppeteer page.\r\n *\r\n * @async\r\n * @function newPage\r\n *\r\n * @param {Object} poolResource - The pool resource that contains `id`,\r\n * `workCount`, and `page`.\r\n *\r\n * @throws {ExportError} Throws an `ExportError` if no valid browser\r\n * has been connected or if a page is invalid or closed.\r\n */\r\nexport async function newPage(poolResource) {\r\n // Error in case of no connected browser\r\n if (!browser || !browser.connected) {\r\n throw new ExportError(`[browser] Browser is not yet connected.`, 500);\r\n }\r\n\r\n // Create a page\r\n poolResource.page = await browser.newPage();\r\n\r\n // Disable cache\r\n await poolResource.page.setCacheEnabled(false);\r\n\r\n // Set the content\r\n await _setPageContent(poolResource.page);\r\n\r\n // Set page events\r\n _setPageEvents(poolResource.page);\r\n\r\n // Check if the page is correctly created\r\n if (!poolResource.page || poolResource.page.isClosed()) {\r\n throw new ExportError('[browser] The page is invalid or closed.', 400);\r\n }\r\n}\r\n\r\n/**\r\n * Clears the content of a Puppeteer Page based on the specified mode. Logs\r\n * thrown error if clearing of a page's content fails.\r\n *\r\n * @async\r\n * @function clearPage\r\n *\r\n * @param {Object} poolResource - The pool resource that contains page and id.\r\n * @param {boolean} [hardReset=false] - A flag indicating the type of clearing\r\n * to be performed. If true, navigates to `about:blank` and resets content\r\n * and scripts. If false, clears the body content by setting a predefined HTML\r\n * structure. The default value is false.\r\n *\r\n * @returns {Promise} A Promise that resolves to true when page\r\n * is correctly cleared and false when it is not.\r\n */\r\nexport async function clearPage(poolResource, hardReset = false) {\r\n try {\r\n if (poolResource.page && !poolResource.page.isClosed()) {\r\n if (hardReset) {\r\n // Navigate to `about:blank`\r\n await poolResource.page.goto('about:blank', {\r\n waitUntil: 'domcontentloaded'\r\n });\r\n\r\n // Set the content and and scripts again\r\n await _setPageContent(poolResource.page);\r\n } else {\r\n // Clear body content\r\n await poolResource.page.evaluate(() => {\r\n document.body.innerHTML =\r\n '
';\r\n });\r\n }\r\n return true;\r\n }\r\n } catch (error) {\r\n logWithStack(\r\n 2,\r\n error,\r\n `[pool] Pool resource [${poolResource.id}] - Content of the page could not be cleared.`\r\n );\r\n\r\n // Set the `workLimit` to exceeded in order to recreate the resource\r\n poolResource.workCount = getOptions().pool.workLimit + 1;\r\n }\r\n return false;\r\n}\r\n\r\n/**\r\n * Adds custom JS and CSS resources to a Puppeteer Page based on the specified\r\n * options.\r\n *\r\n * @async\r\n * @function addPageResources\r\n *\r\n * @param {Object} page - The Puppeteer page object to which resources will\r\n * be added.\r\n * @param {Object} customLogicOptions - The object containing `customLogic`\r\n * options.\r\n *\r\n * @returns {Promise>} A Promise that resolves to an array\r\n * of injected resources.\r\n */\r\nexport async function addPageResources(page, customLogicOptions) {\r\n // Injected resources array\r\n const injectedResources = [];\r\n\r\n // Use resources\r\n const resources = customLogicOptions.resources;\r\n if (resources) {\r\n const injectedJs = [];\r\n\r\n // Load custom JS code\r\n if (resources.js) {\r\n injectedJs.push({\r\n content: resources.js\r\n });\r\n }\r\n\r\n // Load scripts from all custom files\r\n if (resources.files) {\r\n for (const file of resources.files) {\r\n const isLocal = !file.startsWith('http') ? true : false;\r\n\r\n // Add each custom script from resources' files\r\n injectedJs.push(\r\n isLocal\r\n ? {\r\n content: readFileSync(getAbsolutePath(file), 'utf8')\r\n }\r\n : {\r\n url: file\r\n }\r\n );\r\n }\r\n }\r\n\r\n for (const jsResource of injectedJs) {\r\n try {\r\n injectedResources.push(await page.addScriptTag(jsResource));\r\n } catch (error) {\r\n logWithStack(2, error, `[browser] The JS resource cannot be loaded.`);\r\n }\r\n }\r\n injectedJs.length = 0;\r\n\r\n // Load CSS\r\n const injectedCss = [];\r\n if (resources.css) {\r\n let cssImports = resources.css.match(/@import\\s*([^;]*);/g);\r\n if (cssImports) {\r\n // Handle css section\r\n for (let cssImportPath of cssImports) {\r\n if (cssImportPath) {\r\n cssImportPath = cssImportPath\r\n .replace('url(', '')\r\n .replace('@import', '')\r\n .replace(/\"/g, '')\r\n .replace(/'/g, '')\r\n .replace(/;/, '')\r\n .replace(/\\)/g, '')\r\n .trim();\r\n\r\n // Add each custom css from resources\r\n if (cssImportPath.startsWith('http')) {\r\n injectedCss.push({\r\n url: cssImportPath\r\n });\r\n } else if (customLogicOptions.allowFileResources) {\r\n injectedCss.push({\r\n path: join(__dirname, cssImportPath)\r\n });\r\n }\r\n }\r\n }\r\n }\r\n\r\n // The rest of the CSS section will be content by now\r\n injectedCss.push({\r\n content: resources.css.replace(/@import\\s*([^;]*);/g, '') || ' '\r\n });\r\n\r\n for (const cssResource of injectedCss) {\r\n try {\r\n injectedResources.push(await page.addStyleTag(cssResource));\r\n } catch (error) {\r\n logWithStack(\r\n 2,\r\n error,\r\n `[browser] The CSS resource cannot be loaded.`\r\n );\r\n }\r\n }\r\n injectedCss.length = 0;\r\n }\r\n }\r\n return injectedResources;\r\n}\r\n\r\n/**\r\n * Clears out all state set on the page with `addScriptTag` and `addStyleTag`.\r\n * Removes injected resources and resets CSS and script tags on the page.\r\n * Additionally, it destroys previously existing charts.\r\n *\r\n * @async\r\n * @function clearPageResources\r\n *\r\n * @param {Object} page - The Puppeteer page object from which resources will\r\n * be cleared.\r\n * @param {Array.} injectedResources - Array of injected resources\r\n * to be cleared.\r\n */\r\nexport async function clearPageResources(page, injectedResources) {\r\n try {\r\n for (const resource of injectedResources) {\r\n await resource.dispose();\r\n }\r\n\r\n // Destroy old charts after export is done and reset all CSS and script tags\r\n await page.evaluate(() => {\r\n // We are not guaranteed that Highcharts is loaded, when doing SVG exports\r\n if (typeof Highcharts !== 'undefined') {\r\n // eslint-disable-next-line no-undef\r\n const oldCharts = Highcharts.charts;\r\n\r\n // Check in any already existing charts\r\n if (Array.isArray(oldCharts) && oldCharts.length) {\r\n // Destroy old charts\r\n for (const oldChart of oldCharts) {\r\n oldChart && oldChart.destroy();\r\n // eslint-disable-next-line no-undef\r\n Highcharts.charts.shift();\r\n }\r\n }\r\n }\r\n\r\n // eslint-disable-next-line no-undef\r\n const [...scriptsToRemove] = document.getElementsByTagName('script');\r\n // eslint-disable-next-line no-undef\r\n const [, ...stylesToRemove] = document.getElementsByTagName('style');\r\n // eslint-disable-next-line no-undef\r\n const [...linksToRemove] = document.getElementsByTagName('link');\r\n\r\n // Remove tags\r\n for (const element of [\r\n ...scriptsToRemove,\r\n ...stylesToRemove,\r\n ...linksToRemove\r\n ]) {\r\n element.remove();\r\n }\r\n });\r\n } catch (error) {\r\n logWithStack(2, error, `[browser] Could not clear page's resources.`);\r\n }\r\n}\r\n\r\n/**\r\n * Sets the content for a Puppeteer Page using a predefined template\r\n * and additional scripts.\r\n *\r\n * @async\r\n * @function _setPageContent\r\n *\r\n * @param {Object} page - The Puppeteer page object to which the content\r\n * is being set.\r\n */\r\nasync function _setPageContent(page) {\r\n // Set the initial page content\r\n await page.setContent(template, { waitUntil: 'domcontentloaded' });\r\n\r\n // Add all registered Higcharts scripts, quite demanding\r\n await page.addScriptTag({ path: join(getCachePath(), 'sources.js') });\r\n\r\n // Set the initial `animObject` for Highcharts\r\n await page.evaluate(setupHighcharts);\r\n}\r\n\r\n/**\r\n * Set events (like `pageerror` and `console`) for a Puppeteer Page in order\r\n * to catch and display errors and console logs from the window context.\r\n *\r\n * @function _setPageEvents\r\n *\r\n * @param {Object} page - The Puppeteer page object to which the listeners\r\n * are being set.\r\n */\r\nfunction _setPageEvents(page) {\r\n // Get `debug` options\r\n const { debug } = getOptions();\r\n\r\n // Set the `pageerror` listener\r\n page.on('pageerror', async () => {\r\n // It would seem like this may fire at the same time or shortly before\r\n // a page is closed.\r\n if (page.isClosed()) {\r\n return;\r\n }\r\n });\r\n\r\n // Set the `console` listener, if needed\r\n if (debug.enable && debug.listenToConsole) {\r\n page.on('console', (message) => {\r\n console.log(`[debug] ${message.text()}`);\r\n });\r\n }\r\n}\r\n\r\nexport default {\r\n getBrowser,\r\n createBrowser,\r\n closeBrowser,\r\n newPage,\r\n clearPage,\r\n addPageResources,\r\n clearPageResources\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * The CSS to be used on the exported page.\r\n *\r\n * @returns {string} The CSS configuration.\r\n */\r\nexport default () => `\r\n\r\nhtml, body {\r\n margin: 0;\r\n padding: 0;\r\n box-sizing: border-box;\r\n}\r\n\r\n#table-div, #sliders, #datatable, #controls, .ld-row {\r\n display: none;\r\n height: 0;\r\n}\r\n\r\n#chart-container {\r\n box-sizing: border-box;\r\n margin: 0;\r\n overflow: auto;\r\n font-size: 0;\r\n}\r\n\r\n#chart-container > figure, div {\r\n margin-top: 0 !important;\r\n margin-bottom: 0 !important;\r\n}\r\n\r\n`;\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\nimport cssTemplate from './css.js';\r\n\r\n/**\r\n * The SVG template to use when loading SVG content to be exported.\r\n *\r\n * @param {string} svg - The SVG input content to be exported.\r\n *\r\n * @returns {string} The SVG template.\r\n */\r\nexport default (svg) => `\r\n\r\n\r\n \r\n \r\n Highcharts Export\r\n \r\n \r\n \r\n
\r\n ${svg}\r\n
\r\n \r\n\r\n\r\n`;\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * @overview This module handles chart export functionality using Puppeteer.\r\n * It supports exporting charts as SVG, PNG, JPEG, and PDF formats. The module\r\n * manages page resources, sets up the export environment, and processes chart\r\n * configurations or SVG inputs for rendering. Exports to a chart from a page\r\n * using Puppeteer.\r\n */\r\n\r\nimport { addPageResources, clearPageResources } from './browser.js';\r\nimport { createChart } from './highcharts.js';\r\nimport { log } from './logger.js';\r\n\r\nimport svgTemplate from '../templates/svgExport/svgExport.js';\r\n\r\nimport ExportError from './errors/ExportError.js';\r\n\r\n/**\r\n * Exports to a chart from a page using Puppeteer.\r\n *\r\n * @async\r\n * @function puppeteerExport\r\n *\r\n * @param {Object} page - Puppeteer page object.\r\n * @param {Object} options - The `options` object containing complete set\r\n * of options.\r\n *\r\n * @returns {Promise<(string|Buffer|ExportError)>} A Promise that resolves\r\n * to the exported data or rejecting with an `ExportError`.\r\n *\r\n * @throws {ExportError} Throws an `ExportError` if export to an unsupported\r\n * output format occurs.\r\n */\r\nexport async function puppeteerExport(page, options) {\r\n // Injected resources array (additional JS and CSS)\r\n const injectedResources = [];\r\n\r\n try {\r\n // Get the `export` options\r\n const exportOptions = options.export;\r\n\r\n let isSVG = false;\r\n if (exportOptions.svg) {\r\n log(4, '[export] Treating as SVG input.');\r\n\r\n // If the `type` is also SVG, return the input\r\n if (exportOptions.type === 'svg') {\r\n return exportOptions.svg;\r\n }\r\n\r\n // Mark as SVG export for the later size corrections\r\n isSVG = true;\r\n\r\n // SVG export\r\n await _setAsSvg(page, exportOptions.svg);\r\n } else {\r\n log(4, '[export] Treating as JSON config.');\r\n\r\n // Options export\r\n await _setAsOptions(page, options);\r\n }\r\n\r\n // Keeps track of all resources added on the page with addXXXTag. etc\r\n // It's VITAL that all added resources ends up here so we can clear things\r\n // out when doing a new export in the same page!\r\n injectedResources.push(\r\n ...(await addPageResources(page, options.customLogic))\r\n );\r\n\r\n // Get the real chart size and set the zoom accordingly\r\n const size = isSVG\r\n ? await page.evaluate((scale) => {\r\n const svgElement = document.querySelector(\r\n '#chart-container svg:first-of-type'\r\n );\r\n\r\n // Get the values correctly scaled\r\n const chartHeight = svgElement.height.baseVal.value * scale;\r\n const chartWidth = svgElement.width.baseVal.value * scale;\r\n\r\n // In case of SVG the zoom must be set directly for body as scale\r\n // eslint-disable-next-line no-undef\r\n document.body.style.zoom = scale;\r\n\r\n // Set the margin to 0px\r\n // eslint-disable-next-line no-undef\r\n document.body.style.margin = '0px';\r\n\r\n return {\r\n chartHeight,\r\n chartWidth\r\n };\r\n }, parseFloat(exportOptions.scale))\r\n : await page.evaluate(() => {\r\n // eslint-disable-next-line no-undef\r\n const { chartHeight, chartWidth } = window.Highcharts.charts[0];\r\n\r\n // No need for such scale manipulation in case of other types\r\n // of exports. Reset the zoom for other exports than to SVGs\r\n // eslint-disable-next-line no-undef\r\n document.body.style.zoom = 1;\r\n\r\n return {\r\n chartHeight,\r\n chartWidth\r\n };\r\n });\r\n\r\n // Get the clip region for the page\r\n const { x, y } = await _getClipRegion(page);\r\n\r\n // Set final `height` for viewport\r\n const viewportHeight = Math.abs(\r\n Math.ceil(size.chartHeight || exportOptions.height)\r\n );\r\n\r\n // Set final `width` for viewport\r\n const viewportWidth = Math.abs(\r\n Math.ceil(size.chartWidth || exportOptions.width)\r\n );\r\n\r\n // Set the final viewport now that we have the real height\r\n await page.setViewport({\r\n height: viewportHeight,\r\n width: viewportWidth,\r\n deviceScaleFactor: isSVG ? 1 : parseFloat(exportOptions.scale)\r\n });\r\n\r\n let result;\r\n // Rasterization process\r\n switch (exportOptions.type) {\r\n case 'svg':\r\n result = await _createSVG(page);\r\n break;\r\n case 'png':\r\n case 'jpeg':\r\n result = await _createImage(\r\n page,\r\n exportOptions.type,\r\n {\r\n width: viewportWidth,\r\n height: viewportHeight,\r\n x,\r\n y\r\n },\r\n exportOptions.rasterizationTimeout\r\n );\r\n break;\r\n case 'pdf':\r\n result = await _createPDF(\r\n page,\r\n viewportHeight,\r\n viewportWidth,\r\n exportOptions.rasterizationTimeout\r\n );\r\n break;\r\n default:\r\n throw new ExportError(\r\n `[export] Unsupported output format: ${exportOptions.type}.`,\r\n 400\r\n );\r\n }\r\n\r\n // Clear previously injected JS and CSS resources\r\n await clearPageResources(page, injectedResources);\r\n return result;\r\n } catch (error) {\r\n await clearPageResources(page, injectedResources);\r\n return error;\r\n }\r\n}\r\n\r\n/**\r\n * Sets the specified page's content with provided export input within\r\n * the window context using the `page.setContent` function.\r\n *\r\n * @async\r\n * @function _setAsSvg\r\n *\r\n * @param {Object} page - Puppeteer page object.\r\n * @param {string} svg - The SVG input content to be exported.\r\n *\r\n * @returns {Promise} A Promise that resolves after the content is set.\r\n */\r\nasync function _setAsSvg(page, svg) {\r\n await page.setContent(svgTemplate(svg), {\r\n waitUntil: 'domcontentloaded'\r\n });\r\n}\r\n\r\n/**\r\n * Sets the options with specified export input and sizes as configuration into\r\n * the `createChart` function within the window context using\r\n * the `page.evaluate` function.\r\n *\r\n * @async\r\n * @function _setAsOptions\r\n *\r\n * @param {Object} page - Puppeteer page object.\r\n * @param {Object} options - The `options` object containing complete set\r\n * of options.\r\n *\r\n * @returns {Promise} A Promise that resolves after the configuration\r\n * is set.\r\n */\r\nasync function _setAsOptions(page, options) {\r\n await page.evaluate(createChart, options);\r\n}\r\n\r\n/**\r\n * Retrieves the clipping region coordinates of the specified page element\r\n * with the 'chart-container' id.\r\n *\r\n * @async\r\n * @function _getClipRegion\r\n *\r\n * @param {Object} page - Puppeteer page object.\r\n *\r\n * @returns {Promise} A Promise that resolves to an object containing\r\n * `x`, `y`, `width`, and `height` properties.\r\n */\r\nasync function _getClipRegion(page) {\r\n return page.$eval('#chart-container', (element) => {\r\n const { x, y, width, height } = element.getBoundingClientRect();\r\n return {\r\n x,\r\n y,\r\n width,\r\n height: Math.trunc(height > 1 ? height : 500)\r\n };\r\n });\r\n}\r\n\r\n/**\r\n * Creates an SVG by evaluating the `outerHTML` of the first 'svg' element\r\n * inside an element with the id 'container'.\r\n *\r\n * @async\r\n * @function _createSVG\r\n *\r\n * @param {Object} page - Puppeteer page object.\r\n *\r\n * @returns {Promise} A Promise that resolves to the SVG string.\r\n */\r\nasync function _createSVG(page) {\r\n return page.$eval(\r\n '#container svg:first-of-type',\r\n (element) => element.outerHTML\r\n );\r\n}\r\n\r\n/**\r\n * Creates an image using Puppeteer's page `screenshot` functionality with\r\n * specified options.\r\n *\r\n * @async\r\n * @function _createImage\r\n *\r\n * @param {Object} page - Puppeteer page object.\r\n * @param {string} type - Image type.\r\n * @param {Object} clip - Clipping region coordinates.\r\n * @param {number} rasterizationTimeout - Timeout for rasterization\r\n * in milliseconds.\r\n *\r\n * @returns {Promise} A Promise that resolves to the image buffer\r\n * or rejecting with an `ExportError` for timeout.\r\n */\r\nasync function _createImage(page, type, clip, rasterizationTimeout) {\r\n return Promise.race([\r\n page.screenshot({\r\n type,\r\n clip,\r\n encoding: 'base64',\r\n fullPage: false,\r\n optimizeForSpeed: true,\r\n captureBeyondViewport: true,\r\n ...(type !== 'png' ? { quality: 80 } : {}),\r\n // Always render on a transparent page if the expected type format is PNG\r\n omitBackground: type == 'png' // #447, #463\r\n }),\r\n new Promise((_resolve, reject) =>\r\n setTimeout(\r\n () => reject(new ExportError('Rasterization timeout', 408)),\r\n rasterizationTimeout || 1500\r\n )\r\n )\r\n ]);\r\n}\r\n\r\n/**\r\n * Creates a PDF using Puppeteer's page `pdf` functionality with specified\r\n * options.\r\n *\r\n * @async\r\n * @function _createPDF\r\n *\r\n * @param {Object} page - Puppeteer page object.\r\n * @param {number} height - PDF height.\r\n * @param {number} width - PDF width.\r\n * @param {number} rasterizationTimeout - Timeout for rasterization\r\n * in milliseconds.\r\n *\r\n * @returns {Promise} A Promise that resolves to the PDF buffer.\r\n */\r\nasync function _createPDF(page, height, width, rasterizationTimeout) {\r\n await page.emulateMediaType('screen');\r\n return page.pdf({\r\n // This will remove an extra empty page in PDF exports\r\n height: height + 1,\r\n width,\r\n encoding: 'base64',\r\n timeout: rasterizationTimeout || 1500\r\n });\r\n}\r\n\r\nexport default {\r\n puppeteerExport\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * @overview This module provides a worker pool implementation for managing\r\n * the browser instance and pages, specifically designed for use with\r\n * the Highcharts Export Server. It optimizes resources usage and performance\r\n * by maintaining a pool of workers that can handle concurrent export tasks\r\n * using Puppeteer.\r\n */\r\n\r\nimport { Pool } from 'tarn';\r\nimport { v4 as uuid } from 'uuid';\r\n\r\nimport { createBrowser, closeBrowser, newPage, clearPage } from './browser.js';\r\nimport { getOptions } from './config.js';\r\nimport { puppeteerExport } from './export.js';\r\nimport { log, logWithStack } from './logger.js';\r\nimport { getNewDateTime, measureTime } from './utils.js';\r\n\r\nimport ExportError from './errors/ExportError.js';\r\n\r\n// The pool instance\r\nlet pool = null;\r\n\r\n// Pool statistics\r\nconst poolStats = {\r\n exportsAttempted: 0,\r\n exportsPerformed: 0,\r\n exportsDropped: 0,\r\n exportsFromSvg: 0,\r\n exportsFromOptions: 0,\r\n exportsFromSvgAttempts: 0,\r\n exportsFromOptionsAttempts: 0,\r\n timeSpent: 0,\r\n timeSpentAverage: 0\r\n};\r\n\r\n/**\r\n * Initializes the export pool with the provided configuration, creating\r\n * a browser instance and setting up worker resources.\r\n *\r\n * @async\r\n * @function initPool\r\n *\r\n * @param {Object} [poolOptions=getOptions().pool] - Object containing `pool`\r\n * options. The default value is the global pool options of the export server\r\n * instance.\r\n * @param {Array.} [puppeteerArgs=[]] - Additional arguments\r\n * for Puppeteer launch. The default value is an empty array.\r\n *\r\n * @returns {Promise} A Promise that resolves to ending the function\r\n * execution when an already initialized pool of resources is found.\r\n *\r\n * @throws {ExportError} Throws an `ExportError` if could not create the pool\r\n * of workers.\r\n */\r\nexport async function initPool(\r\n poolOptions = getOptions().pool,\r\n puppeteerArgs = []\r\n) {\r\n // Create a browser instance with the puppeteer arguments\r\n await createBrowser(puppeteerArgs);\r\n\r\n try {\r\n log(\r\n 3,\r\n `[pool] Initializing pool with workers: min ${poolOptions.minWorkers}, max ${poolOptions.maxWorkers}.`\r\n );\r\n\r\n if (pool) {\r\n log(\r\n 4,\r\n '[pool] Already initialized, please kill it before creating a new one.'\r\n );\r\n return;\r\n }\r\n\r\n // Keep an eye on a correct min and max workers number\r\n if (poolOptions.minWorkers > poolOptions.maxWorkers) {\r\n poolOptions.minWorkers = poolOptions.maxWorkers;\r\n }\r\n\r\n // Create a pool along with a minimal number of resources\r\n pool = new Pool({\r\n // Get the `create`, `validate`, and `destroy` functions\r\n ..._factory(poolOptions),\r\n min: poolOptions.minWorkers,\r\n max: poolOptions.maxWorkers,\r\n acquireTimeoutMillis: poolOptions.acquireTimeout,\r\n createTimeoutMillis: poolOptions.createTimeout,\r\n destroyTimeoutMillis: poolOptions.destroyTimeout,\r\n idleTimeoutMillis: poolOptions.idleTimeout,\r\n createRetryIntervalMillis: poolOptions.createRetryInterval,\r\n reapIntervalMillis: poolOptions.reaperInterval,\r\n propagateCreateError: false\r\n });\r\n\r\n // Set events\r\n pool.on('release', async (resource) => {\r\n // Clear page\r\n const clearStatus = await clearPage(resource, false);\r\n log(\r\n 4,\r\n `[pool] Pool resource [${resource.id}] - Releasing a worker. Clear page status: ${clearStatus}.`\r\n );\r\n });\r\n\r\n pool.on('destroySuccess', (_eventId, resource) => {\r\n log(\r\n 4,\r\n `[pool] Pool resource [${resource.id}] - Destroyed a worker successfully.`\r\n );\r\n resource.page = null;\r\n });\r\n\r\n const initialResources = [];\r\n // Create an initial number of resources\r\n for (let i = 0; i < poolOptions.minWorkers; i++) {\r\n try {\r\n const resource = await pool.acquire().promise;\r\n initialResources.push(resource);\r\n } catch (error) {\r\n logWithStack(2, error, '[pool] Could not create an initial resource.');\r\n }\r\n }\r\n\r\n // Release the initial number of resources back to the pool\r\n initialResources.forEach((resource) => {\r\n pool.release(resource);\r\n });\r\n\r\n log(\r\n 3,\r\n `[pool] The pool is ready${initialResources.length ? ` with ${initialResources.length} initial resources waiting.` : '.'}`\r\n );\r\n } catch (error) {\r\n throw new ExportError(\r\n '[pool] Could not configure and create the pool of workers.',\r\n 500\r\n ).setError(error);\r\n }\r\n}\r\n\r\n/**\r\n * Kills all workers in the pool, destroys the pool, and closes the browser\r\n * instance.\r\n *\r\n * @async\r\n * @function killPool\r\n *\r\n * @returns {Promise} A Promise that resolves after the workers are\r\n * killed, the pool is destroyed, and the browser is closed.\r\n */\r\nexport async function killPool() {\r\n log(3, '[pool] Killing pool with all workers and closing browser.');\r\n\r\n // If still alive, destroy the pool of pages before closing a browser\r\n if (pool) {\r\n // Free up not released workers\r\n for (const worker of pool.used) {\r\n pool.release(worker.resource);\r\n }\r\n\r\n // Destroy the pool if it is still available\r\n if (!pool.destroyed) {\r\n await pool.destroy();\r\n log(4, '[pool] Destroyed the pool of resources.');\r\n }\r\n pool = null;\r\n }\r\n\r\n // Close the browser instance\r\n await closeBrowser();\r\n}\r\n\r\n/**\r\n * Processes the export work using a worker from the pool. Acquires a worker\r\n * handle from the pool, performs the export using puppeteer, and releases\r\n * the worker handle back to the pool.\r\n *\r\n * @async\r\n * @function postWork\r\n *\r\n * @param {Object} options - The `options` object containing complete set\r\n * of options.\r\n *\r\n * @returns {Promise} A Promise that resolves to the export result\r\n * and options.\r\n *\r\n * @throws {ExportError} Throws an `ExportError` if an error occurs during\r\n * the export process.\r\n */\r\nexport async function postWork(options) {\r\n let workerHandle;\r\n\r\n try {\r\n log(4, '[pool] Work received, starting to process.');\r\n\r\n // An export attempt counted\r\n ++poolStats.exportsAttempted;\r\n\r\n // Display the pool information if needed\r\n if (getOptions().pool.benchmarking) {\r\n getPoolInfo();\r\n }\r\n\r\n // Throw an error in case of lacking the pool instance\r\n if (!pool) {\r\n throw new ExportError(\r\n '[pool] Work received, but pool has not been started.',\r\n 500\r\n );\r\n }\r\n\r\n // The acquire counter\r\n const acquireCounter = measureTime();\r\n\r\n // Try to acquire the worker along with the id, works count and page\r\n try {\r\n log(4, '[pool] Acquiring a worker handle.');\r\n\r\n // Acquire a pool resource\r\n workerHandle = await pool.acquire().promise;\r\n\r\n // Check the page acquire time\r\n if (options.server.benchmarking) {\r\n log(\r\n 5,\r\n options._requestId\r\n ? `[benchmark] Request [${options._requestId}] - `\r\n : '[benchmark] ',\r\n `Acquiring a worker handle took ${acquireCounter()}ms.`\r\n );\r\n }\r\n } catch (error) {\r\n throw new ExportError(\r\n '[pool] ' +\r\n (options._requestId ? `Request [${options._requestId}] - ` : '') +\r\n `Error encountered when acquiring an available entry: ${acquireCounter()}ms.`,\r\n 400\r\n ).setError(error);\r\n }\r\n log(4, '[pool] Acquired a worker handle.');\r\n\r\n if (!workerHandle.page) {\r\n // Set the `workLimit` to exceeded in order to recreate the resource\r\n workerHandle.workCount = options.pool.workLimit + 1;\r\n throw new ExportError(\r\n '[pool] Resolved worker page is invalid: the pool setup is wonky.',\r\n 400\r\n );\r\n }\r\n\r\n // Save the start time\r\n const workStart = getNewDateTime();\r\n\r\n log(\r\n 4,\r\n `[pool] Pool resource [${workerHandle.id}] - Starting work on this pool entry.`\r\n );\r\n\r\n // Perform an export on a puppeteer level\r\n const exportCounter = measureTime();\r\n const result = await puppeteerExport(workerHandle.page, options);\r\n\r\n // Check if it's an error\r\n if (result instanceof Error) {\r\n // NOTE:\r\n // If there's a rasterization timeout, we want need to flush the page.\r\n // This is because the page may be in a state where it's waiting for\r\n // the screenshot to finish even though the timeout has occured.\r\n // Which of course causes a lot of issues with the event system,\r\n // and page consistency.\r\n //\r\n // NOTE:\r\n // Only page.screenshot will throw this, timeouts for PDF's are\r\n // handled by the page.pdf function itself.\r\n //\r\n // ...yes, this is ugly.\r\n if (result.message === 'Rasterization timeout') {\r\n // Set the `workLimit` to exceeded in order to recreate the resource\r\n workerHandle.workCount = options.pool.workLimit + 1;\r\n workerHandle.page = null;\r\n }\r\n\r\n if (\r\n result.name === 'TimeoutError' ||\r\n result.message === 'Rasterization timeout'\r\n ) {\r\n throw new ExportError(\r\n '[pool] ' +\r\n (options._requestId ? `Request [${options._requestId}] - ` : '') +\r\n 'Rasterization timeout: your chart may be too complex or large, and failed to render within the allotted time.'\r\n ).setError(result);\r\n } else {\r\n throw new ExportError(\r\n '[pool] ' +\r\n (options._requestId ? `Request [${options._requestId}] - ` : '') +\r\n `Error encountered during export: ${exportCounter()}ms.`\r\n ).setError(result);\r\n }\r\n }\r\n\r\n // Check the Puppeteer export time\r\n if (options.server.benchmarking) {\r\n log(\r\n 5,\r\n options._requestId\r\n ? `[benchmark] Request [${options._requestId}] - `\r\n : '[benchmark] ',\r\n `Exporting a chart sucessfully took ${exportCounter()}ms.`\r\n );\r\n }\r\n\r\n // Release the resource back to the pool\r\n pool.release(workerHandle);\r\n\r\n // Used for statistics in averageTime and processedWorkCount, which\r\n // in turn is used by the /health route.\r\n const workEnd = getNewDateTime();\r\n const exportTime = workEnd - workStart;\r\n\r\n poolStats.timeSpent += exportTime;\r\n poolStats.timeSpentAverage =\r\n poolStats.timeSpent / ++poolStats.exportsPerformed;\r\n\r\n log(4, `[pool] Work completed in ${exportTime}ms.`);\r\n\r\n // Otherwise return the result\r\n return {\r\n result,\r\n options\r\n };\r\n } catch (error) {\r\n ++poolStats.exportsDropped;\r\n\r\n if (workerHandle) {\r\n pool.release(workerHandle);\r\n }\r\n\r\n throw error;\r\n }\r\n}\r\n\r\n/**\r\n * Retrieves the current pool instance.\r\n *\r\n * @function getPool\r\n *\r\n * @returns {(Object|null)} The current pool instance if initialized, or null\r\n * if the pool has not been created.\r\n */\r\nexport function getPool() {\r\n return pool;\r\n}\r\n\r\n/**\r\n * Gets the statistic of a pool instace about exports.\r\n *\r\n * @function getPoolStats\r\n *\r\n * @returns {Object} The current pool statistics.\r\n */\r\nexport function getPoolStats() {\r\n return poolStats;\r\n}\r\n\r\n/**\r\n * Retrieves pool information in JSON format, including minimum and maximum\r\n * workers, available workers, workers in use, and pending acquire requests.\r\n *\r\n * @function getPoolInfoJSON\r\n *\r\n * @returns {Object} Pool information in JSON format.\r\n */\r\nexport function getPoolInfoJSON() {\r\n return {\r\n min: pool.min,\r\n max: pool.max,\r\n used: pool.numUsed(),\r\n available: pool.numFree(),\r\n allCreated: pool.numUsed() + pool.numFree(),\r\n pendingAcquires: pool.numPendingAcquires(),\r\n pendingCreates: pool.numPendingCreates(),\r\n pendingValidations: pool.numPendingValidations(),\r\n pendingDestroys: pool.pendingDestroys.length,\r\n absoluteAll:\r\n pool.numUsed() +\r\n pool.numFree() +\r\n pool.numPendingAcquires() +\r\n pool.numPendingCreates() +\r\n pool.numPendingValidations() +\r\n pool.pendingDestroys.length\r\n };\r\n}\r\n\r\n/**\r\n * Logs information about the current state of the pool, including the minimum\r\n * and maximum workers, available workers, workers in use, and pending acquire\r\n * requests.\r\n *\r\n * @function getPoolInfo\r\n */\r\nexport function getPoolInfo() {\r\n const {\r\n min,\r\n max,\r\n used,\r\n available,\r\n allCreated,\r\n pendingAcquires,\r\n pendingCreates,\r\n pendingValidations,\r\n pendingDestroys,\r\n absoluteAll\r\n } = getPoolInfoJSON();\r\n\r\n log(5, `[pool] The minimum number of resources allowed by pool: ${min}.`);\r\n log(5, `[pool] The maximum number of resources allowed by pool: ${max}.`);\r\n log(5, `[pool] The number of used resources: ${used}.`);\r\n log(5, `[pool] The number of free resources: ${available}.`);\r\n log(\r\n 5,\r\n `[pool] The number of all created (used and free) resources: ${allCreated}.`\r\n );\r\n log(\r\n 5,\r\n `[pool] The number of resources waiting to be acquired: ${pendingAcquires}.`\r\n );\r\n log(\r\n 5,\r\n `[pool] The number of resources waiting to be created: ${pendingCreates}.`\r\n );\r\n log(\r\n 5,\r\n `[pool] The number of resources waiting to be validated: ${pendingValidations}.`\r\n );\r\n log(\r\n 5,\r\n `[pool] The number of resources waiting to be destroyed: ${pendingDestroys}.`\r\n );\r\n log(5, `[pool] The number of all resources: ${absoluteAll}.`);\r\n}\r\n\r\n/**\r\n * Factory function that returns an object with `create`, `validate`,\r\n * and `destroy` functions for the pool instance.\r\n *\r\n * @function _factory\r\n *\r\n * @param {Object} poolOptions - Object containing `pool` options.\r\n */\r\nfunction _factory(poolOptions) {\r\n return {\r\n /**\r\n * Creates a new worker page for the export pool.\r\n *\r\n * @async\r\n * @function create\r\n *\r\n * @returns {Promise} A Promise that resolves to an object\r\n * containing the worker ID, a reference to the browser page, and initial\r\n * work count.\r\n *\r\n * @throws {ExportError} Throws an `ExportError` if there is an error during\r\n * the creation of the new page.\r\n */\r\n create: async () => {\r\n // Init the resource with unique id and work count\r\n const poolResource = {\r\n id: uuid(),\r\n // Try to distribute the initial work count\r\n workCount: Math.round(Math.random() * (poolOptions.workLimit / 2))\r\n };\r\n\r\n try {\r\n // Start measuring a page creation time\r\n const startDate = getNewDateTime();\r\n\r\n // Create a new page\r\n await newPage(poolResource);\r\n\r\n // Measure the time of full creation and configuration of a page\r\n log(\r\n 3,\r\n `[pool] Pool resource [${poolResource.id}] - Successfully created a worker, took ${\r\n getNewDateTime() - startDate\r\n }ms.`\r\n );\r\n\r\n // Return ready pool resource\r\n return poolResource;\r\n } catch (error) {\r\n log(\r\n 3,\r\n `[pool] Pool resource [${poolResource.id}] - Error encountered when creating a new page.`\r\n );\r\n throw error;\r\n }\r\n },\r\n\r\n /**\r\n * Validates a worker page in the export pool, checking if it has exceeded\r\n * the work limit.\r\n *\r\n * @async\r\n * @function validate\r\n *\r\n * @param {Object} poolResource - The handle to the worker, containing\r\n * the worker's ID, a reference to the browser page, and work count.\r\n *\r\n * @returns {Promise} A Promise that resolves to true if the worker\r\n * is valid and within the work limit; otherwise, to false.\r\n */\r\n validate: async (poolResource) => {\r\n // NOTE:\r\n // In certain cases acquiring throws a TargetCloseError, which may\r\n // be caused by two things:\r\n // - The page is closed and attempted to be reused.\r\n // - Lost contact with the browser.\r\n //\r\n // What we're seeing in logs is that successive exports typically\r\n // succeeds, and the server recovers, indicating that it's likely\r\n // the first case. This is an attempt at allievating the issue by\r\n // simply not validating the worker if the page is null or closed.\r\n //\r\n // The actual result from when this happened, was that a worker would\r\n // be completely locked, stopping it from being acquired until\r\n // its work count reached the limit.\r\n\r\n // Check if the `page` is valid\r\n if (!poolResource.page) {\r\n log(\r\n 3,\r\n `[pool] Pool resource [${poolResource.id}] - Validation failed (no valid page is found).`\r\n );\r\n return false;\r\n }\r\n\r\n // Check if the `page` is closed\r\n if (poolResource.page.isClosed()) {\r\n log(\r\n 3,\r\n `[pool] Pool resource [${poolResource.id}] - Validation failed (page is closed or invalid).`\r\n );\r\n return false;\r\n }\r\n\r\n // Check if the `mainFrame` is detached\r\n if (poolResource.page.mainFrame().detached) {\r\n log(\r\n 3,\r\n `[pool] Pool resource [${poolResource.id}] - Validation failed (page's frame is detached).`\r\n );\r\n return false;\r\n }\r\n\r\n // Check if the `workLimit` is exceeded\r\n if (\r\n poolOptions.workLimit &&\r\n ++poolResource.workCount > poolOptions.workLimit\r\n ) {\r\n log(\r\n 3,\r\n `[pool] Pool resource [${poolResource.id}] - Validation failed (exceeded the ${poolOptions.workLimit} works per resource limit).`\r\n );\r\n return false;\r\n }\r\n\r\n // The `poolResource` is validated\r\n return true;\r\n },\r\n\r\n /**\r\n * Destroys a worker entry in the export pool, closing its associated page.\r\n *\r\n * @async\r\n * @function destroy\r\n *\r\n * @param {Object} poolResource - The handle to the worker, containing\r\n * the worker's ID, a reference to the browser page, and work count.\r\n */\r\n destroy: async (poolResource) => {\r\n log(\r\n 3,\r\n `[pool] Pool resource [${poolResource.id}] - Destroying a worker.`\r\n );\r\n\r\n if (poolResource.page && !poolResource.page.isClosed()) {\r\n try {\r\n // Remove all attached event listeners from the resource\r\n poolResource.page.removeAllListeners('pageerror');\r\n poolResource.page.removeAllListeners('console');\r\n poolResource.page.removeAllListeners('framedetached');\r\n\r\n // We need to wait around for this\r\n await poolResource.page.close();\r\n } catch (error) {\r\n log(\r\n 3,\r\n `[pool] Pool resource [${poolResource.id}] - Page could not be closed upon destroying.`\r\n );\r\n throw error;\r\n }\r\n }\r\n }\r\n };\r\n}\r\n\r\nexport default {\r\n initPool,\r\n killPool,\r\n postWork,\r\n getPool,\r\n getPoolStats,\r\n getPoolInfo,\r\n getPoolInfoJSON\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * @overview Used to sanitize the strings coming from the exporting module\r\n * to prevent XSS attacks (with the DOMPurify library).\r\n */\r\n\r\nimport DOMPurify from 'dompurify';\r\nimport { JSDOM } from 'jsdom';\r\n\r\n/**\r\n * Sanitizes a given HTML string by removing \r\n * tags and any content within them.\r\n *\r\n * @function sanitize\r\n *\r\n * @param {string} input - The HTML string to be sanitized.\r\n *\r\n * @returns {string} The sanitized HTML string.\r\n */\r\nexport function sanitize(input) {\r\n // Get the virtual DOM\r\n const window = new JSDOM('').window;\r\n\r\n // Create a purifying instance\r\n const purify = DOMPurify(window);\r\n\r\n // Return sanitized input\r\n return purify.sanitize(input, { ADD_TAGS: ['foreignObject'] });\r\n}\r\n\r\nexport default {\r\n sanitize\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * @overview This module provides functions to prepare for the exporting charts\r\n * into various image output formats such as JPEG, PNG, PDF, and SVGs.\r\n * It supports single and batch export operations and allows customization\r\n * through options passed from configurations or APIs.\r\n */\r\n\r\nimport { readFileSync, writeFileSync } from 'fs';\r\n\r\nimport { getOptions, mergeOptions, isAllowedConfig } from './config.js';\r\nimport { log, logWithStack, logZodIssues } from './logger.js';\r\nimport { killPool, postWork, getPoolStats } from './pool.js';\r\nimport { sanitize } from './sanitize.js';\r\nimport {\r\n fixOutfile,\r\n fixType,\r\n getAbsolutePath,\r\n getBase64,\r\n roundNumber,\r\n wrapAround\r\n} from './utils.js';\r\nimport { strictValidate, validateOption } from './validation.js';\r\n\r\nimport ExportError from './errors/ExportError.js';\r\n\r\n// The global flag for the code execution permission\r\nlet allowCodeExecution = false;\r\n\r\n/**\r\n * Starts a single export process based on the specified options and saves\r\n * the image in the provided outfile.\r\n *\r\n * @async\r\n * @function singleExport\r\n *\r\n * @param {Object} options - The `options` object, which may be a partial\r\n * or complete set of options. It must contain at least one of the following\r\n * properties: `infile`, `instr`, `options`, or `svg` to generate a valid image.\r\n *\r\n * @returns {Promise} A Promise that resolves once the single export\r\n * process is completed.\r\n *\r\n * @throws {ExportError} Throws an `ExportError` if an error occurs during\r\n * the single export process.\r\n */\r\nexport async function singleExport(options) {\r\n // Check if the export makes sense\r\n if (options && options.export) {\r\n // Perform an export\r\n await startExport(options, async (error, data) => {\r\n // Exit process when error exists\r\n if (error) {\r\n throw error;\r\n }\r\n\r\n // Get the `b64`, `outfile`, and `type` for a chart\r\n const { b64, outfile, type } = data.options.export;\r\n\r\n // Save the result\r\n try {\r\n if (b64) {\r\n // As a Base64 string to a txt file\r\n writeFileSync(\r\n `${outfile.split('.').shift() || 'chart'}.txt`,\r\n getBase64(data.result, type)\r\n );\r\n } else {\r\n // As a correct image format\r\n writeFileSync(\r\n outfile || `chart.${type}`,\r\n type !== 'svg' ? Buffer.from(data.result, 'base64') : data.result\r\n );\r\n }\r\n } catch (error) {\r\n throw new ExportError(\r\n '[chart] Error while saving a chart.',\r\n 500\r\n ).setError(error);\r\n }\r\n\r\n // Kill pool and close browser after finishing single export\r\n await killPool();\r\n });\r\n } else {\r\n throw new ExportError(\r\n '[chart] No expected `export` options were found. Please provide one of the following options: `infile`, `instr`, `options`, or `svg` to generate a valid image.',\r\n 400\r\n );\r\n }\r\n}\r\n\r\n/**\r\n * Starts a batch export process for multiple charts based on the information\r\n * in the `batch` option. The `batch` is a string in the following format:\r\n * \"infile1.json=outfile1.png;infile2.json=outfile2.png;...\". Results are saved\r\n * in provided outfiles.\r\n *\r\n * @async\r\n * @function batchExport\r\n *\r\n * @param {Object} options - The `options` object, which may be a partial\r\n * or complete set of options. It must contain the `batch` option to generate\r\n * valid images.\r\n *\r\n * @returns {Promise} A Promise that resolves once the batch export\r\n * processes are completed.\r\n *\r\n * @throws {ExportError} Throws an `ExportError` if an error occurs during\r\n * any of the batch export process.\r\n */\r\nexport async function batchExport(options) {\r\n // Check if the export makes sense\r\n if (options && options.export && options.export.batch) {\r\n // An array for collecting batch exports\r\n const batchFunctions = [];\r\n\r\n // Split and pair the `batch` arguments\r\n for (let pair of options.export.batch.split(';') || []) {\r\n pair = pair.split('=');\r\n if (pair.length === 2) {\r\n batchFunctions.push(\r\n startExport(\r\n {\r\n ...options,\r\n export: {\r\n ...options.export,\r\n infile: pair[0],\r\n outfile: pair[1]\r\n }\r\n },\r\n (error, data) => {\r\n // Exit process when error exists\r\n if (error) {\r\n throw error;\r\n }\r\n\r\n // Get the `b64`, `outfile`, and `type` for a chart\r\n const { b64, outfile, type } = data.options.export;\r\n\r\n // Save the result\r\n try {\r\n if (b64) {\r\n // As a Base64 string to a txt file\r\n writeFileSync(\r\n `${outfile.split('.').shift() || 'chart'}.txt`,\r\n getBase64(data.result, type)\r\n );\r\n } else {\r\n // As a correct image format\r\n writeFileSync(\r\n outfile,\r\n type !== 'svg'\r\n ? Buffer.from(data.result, 'base64')\r\n : data.result\r\n );\r\n }\r\n } catch (error) {\r\n throw new ExportError(\r\n '[chart] Error while saving a chart.',\r\n 500\r\n ).setError(error);\r\n }\r\n }\r\n )\r\n );\r\n } else {\r\n log(2, '[chart] No correct pair found for the batch export.');\r\n }\r\n }\r\n\r\n // Await all exports are done\r\n const batchResults = await Promise.allSettled(batchFunctions);\r\n\r\n // Kill pool and close browser after finishing batch export\r\n await killPool();\r\n\r\n // Log errors if found\r\n batchResults.forEach((result, index) => {\r\n // Log the error with stack about the specific batch export\r\n if (result.reason) {\r\n logWithStack(\r\n 1,\r\n result.reason,\r\n `[chart] Batch export number ${index + 1} could not be correctly completed.`\r\n );\r\n }\r\n });\r\n } else {\r\n throw new ExportError(\r\n '[chart] No expected `export` options were found. Please provide the `batch` option to generate valid images.',\r\n 400\r\n );\r\n }\r\n}\r\n\r\n/**\r\n * Starts an export process. The `customOptions` parameter is an object that\r\n * may be partial or complete set of options. The `endCallback` is called when\r\n * the export is completed, with the `error` object as the first argument\r\n * and the `data` object as the second, which contains the Base64 representation\r\n * of the chart in the `result` property and the full set of export options\r\n * in the `options` property.\r\n *\r\n * @async\r\n * @function startExport\r\n *\r\n * @param {Object} customOptions - The `customOptions` object, which may\r\n * be a partial or complete set of options. If the provided options are partial,\r\n * missing values will be merged with the default general options, retrieved\r\n * using the `getOptions` function.\r\n * @param {Function} endCallback - The callback function to be invoked upon\r\n * finalizing work or upon error occurance of the exporting process. The first\r\n * argument is `error` object and the `data` object is the second, that contains\r\n * the Base64 representation of the chart in the `result` property and the full\r\n * set of export options in the `options` property.\r\n *\r\n * @returns {Promise} This function does not return a value directly.\r\n * Instead, it communicates results via the `endCallback`.\r\n *\r\n * @throws {ExportError} Throws an `ExportError` if there is a problem with\r\n * processing input of any type. The error is passed into the `endCallback`\r\n * function and processed there.\r\n */\r\nexport async function startExport(customOptions, endCallback) {\r\n try {\r\n // Starting exporting process message\r\n log(4, '[chart] Starting the exporting process.');\r\n\r\n // Merge the custom options into default ones\r\n const options = mergeOptions(getOptions(false), customOptions);\r\n\r\n // Get the export options\r\n const exportOptions = options.export;\r\n\r\n // Export using options from the file as an input\r\n if (exportOptions.infile !== null) {\r\n log(4, '[chart] Attempting to export from a file input.');\r\n\r\n let fileContent;\r\n try {\r\n // Try to read the file to get the string representation\r\n fileContent = readFileSync(\r\n getAbsolutePath(exportOptions.infile),\r\n 'utf8'\r\n );\r\n } catch (error) {\r\n throw new ExportError(\r\n '[chart] Error loading content from a file input.',\r\n 400\r\n ).setError(error);\r\n }\r\n\r\n // Check the file's extension\r\n if (exportOptions.infile.endsWith('.svg')) {\r\n try {\r\n // Set to the `svg` option\r\n exportOptions.svg = validateOption('svg', fileContent, false);\r\n } catch (error) {\r\n logZodIssues(\r\n 1,\r\n error.issues,\r\n '[config] The `svg` option validation error'\r\n );\r\n throw error;\r\n }\r\n } else if (exportOptions.infile.endsWith('.json')) {\r\n try {\r\n // Set to the `instr` option\r\n exportOptions.instr = validateOption('instr', fileContent, false);\r\n } catch (error) {\r\n logZodIssues(\r\n 1,\r\n error.issues,\r\n '[config] The `instr` option validation error'\r\n );\r\n throw error;\r\n }\r\n } else {\r\n throw new ExportError(\r\n '[chart] Incorrect value of the `infile` option.',\r\n 400\r\n );\r\n }\r\n }\r\n\r\n // Export using SVG as an input\r\n if (exportOptions.svg !== null) {\r\n log(4, '[chart] Attempting to export from an SVG input.');\r\n\r\n // SVG exports attempts counter\r\n ++getPoolStats().exportsFromSvgAttempts;\r\n\r\n // Export from an SVG string\r\n const result = await _exportFromSvg(\r\n sanitize(exportOptions.svg), // #209\r\n options\r\n );\r\n\r\n // SVG exports counter\r\n ++getPoolStats().exportsFromSvg;\r\n\r\n // Pass SVG export result to the end callback\r\n return endCallback(null, result);\r\n }\r\n\r\n // Export using options as an input\r\n if (exportOptions.instr !== null || exportOptions.options !== null) {\r\n log(4, '[chart] Attempting to export from options input.');\r\n\r\n // Options exports attempts counter\r\n ++getPoolStats().exportsFromOptionsAttempts;\r\n\r\n // Export from options\r\n const result = await _exportFromOptions(\r\n exportOptions.instr || exportOptions.options,\r\n options\r\n );\r\n\r\n // Options exports counter\r\n ++getPoolStats().exportsFromOptions;\r\n\r\n // Pass options export result to the end callback\r\n return endCallback(null, result);\r\n }\r\n\r\n // No input specified, pass an error message to the callback\r\n return endCallback(\r\n new ExportError(\r\n `[chart] No valid input specified. Check if at least one of the following parameters is correctly set: 'infile', 'instr', 'options', or 'svg'.`,\r\n 400\r\n )\r\n );\r\n } catch (error) {\r\n return endCallback(error);\r\n }\r\n}\r\n\r\n/**\r\n * Retrieves and returns the current status of the code execution permission.\r\n *\r\n * @function getAllowCodeExecution\r\n *\r\n * @returns {boolean} The value of the global `allowCodeExecution` option.\r\n */\r\nexport function getAllowCodeExecution() {\r\n return allowCodeExecution;\r\n}\r\n\r\n/**\r\n * Sets the code execution permission based on the provided boolean value.\r\n *\r\n * @function setAllowCodeExecution\r\n *\r\n * @param {boolean} value - The value to be assigned to the global\r\n * `allowCodeExecution` option.\r\n */\r\nexport function setAllowCodeExecution(value) {\r\n allowCodeExecution = value;\r\n}\r\n\r\n/**\r\n * Exports from an SVG based input with the provided options.\r\n *\r\n * @async\r\n * @function _exportFromSvg\r\n *\r\n * @param {string} inputToExport - The SVG based input to be exported.\r\n * @param {Object} options - The `options` object containing complete set\r\n * of options.\r\n *\r\n * @returns {Promise} A Promise that resolves to a result of the export\r\n * process.\r\n *\r\n * @throws {ExportError} Throws an `ExportError` if there is not a correct SVG\r\n * input.\r\n */\r\nasync function _exportFromSvg(inputToExport, options) {\r\n // Check if it is SVG\r\n if (\r\n typeof inputToExport === 'string' &&\r\n (inputToExport.indexOf('= 0 || inputToExport.indexOf('= 0)\r\n ) {\r\n log(4, '[chart] Parsing input as SVG.');\r\n\r\n // Set the export input as SVG\r\n options.export.svg = inputToExport;\r\n\r\n // Reset the rest of the export input options\r\n options.export.instr = null;\r\n options.export.options = null;\r\n\r\n // Call the function with an SVG string as an export input\r\n return _prepareExport(options);\r\n } else {\r\n throw new ExportError('[chart] Not a correct SVG input.', 400);\r\n }\r\n}\r\n\r\n/**\r\n * Exports from an options based input with the provided options.\r\n *\r\n * @async\r\n * @function _exportFromOptions\r\n *\r\n * @param {string} inputToExport - The options based input to be exported.\r\n * @param {Object} options - The `options` object containing complete set\r\n * of options.\r\n *\r\n * @returns {Promise} A Promise that resolves to a result of the export\r\n * process.\r\n *\r\n * @throws {ExportError} Throws an `ExportError` if there is not a correct\r\n * chart options input.\r\n */\r\nasync function _exportFromOptions(inputToExport, options) {\r\n log(4, '[chart] Parsing input from options.');\r\n\r\n // Try to check, validate and parse to stringified options\r\n const stringifiedOptions = isAllowedConfig(\r\n inputToExport,\r\n true,\r\n options.customLogic.allowCodeExecution\r\n );\r\n\r\n // Check if a correct stringified options\r\n if (\r\n stringifiedOptions === null ||\r\n typeof stringifiedOptions !== 'string' ||\r\n !stringifiedOptions.startsWith('{') ||\r\n !stringifiedOptions.endsWith('}')\r\n ) {\r\n throw new ExportError(\r\n '[chart] Invalid configuration provided - Only options configurations and SVG are allowed for this server. If this is your server, JavaScript custom code can be enabled by starting the server with the `allowCodeExecution` options set to true.',\r\n 403\r\n );\r\n }\r\n\r\n // Set the export input as a stringified chart options\r\n options.export.instr = stringifiedOptions;\r\n\r\n // Reset the rest of the export input options\r\n options.export.svg = null;\r\n\r\n // Call the function with a stringified chart options\r\n return _prepareExport(options);\r\n}\r\n\r\n/**\r\n * Function for finalizing options and configurations before export.\r\n *\r\n * @async\r\n * @function _prepareExport\r\n *\r\n * @param {Object} options - The `options` object containing complete set\r\n * of options.\r\n *\r\n * @returns {Promise} A Promise that resolves to a result of the export\r\n * process.\r\n */\r\nasync function _prepareExport(options) {\r\n const { export: exportOptions, customLogic: customLogicOptions } = options;\r\n\r\n // Prepare the `type` option\r\n exportOptions.type = fixType(exportOptions.type, exportOptions.outfile);\r\n\r\n // Prepare the `outfile` option\r\n exportOptions.outfile = fixOutfile(exportOptions.type, exportOptions.outfile);\r\n\r\n // Notify about the custom logic usage status\r\n log(\r\n 3,\r\n `[chart] The custom logic is ${customLogicOptions.allowCodeExecution ? 'allowed' : 'disallowed'}.`\r\n );\r\n\r\n // Prepare the custom logic options (`customCode`, `callback`, `resources`)\r\n _handleCustomLogic(customLogicOptions, customLogicOptions.allowCodeExecution);\r\n\r\n // Prepare the `globalOptions` and `themeOptions` options\r\n _handleGlobalAndTheme(\r\n exportOptions,\r\n customLogicOptions.allowFileResources,\r\n customLogicOptions.allowCodeExecution\r\n );\r\n\r\n // Prepare the `height`, `width`, and `scale` options\r\n options.export = {\r\n ...exportOptions,\r\n ..._findChartSize(exportOptions)\r\n };\r\n\r\n // The last strict validation of options right before exporting process\r\n try {\r\n // Validate final options\r\n options = strictValidate(options);\r\n } catch (error) {\r\n logZodIssues(1, error.issues, '[config] Final options validation error');\r\n }\r\n\r\n // Post the work to the pool\r\n return postWork(options);\r\n}\r\n\r\n/**\r\n * Calculates the `height`, `width` and `scale` for chart exports based\r\n * on the provided export options.\r\n *\r\n * The function prioritizes values in the following order:\r\n * 1. The `height`, `width`, `scale` from the `exportOptions`.\r\n * 2. Options from the chart configuration (from `exporting` and `chart`).\r\n * 3. Options from the global options (from `exporting` and `chart`).\r\n * 4. Options from the theme options (from `exporting` and `chart` sections).\r\n * 5. Fallback default values (`height = 400`, `width = 600`, `scale = 1`).\r\n *\r\n * @function _findChartSize\r\n *\r\n * @param {Object} exportOptions - The object containing `export` options.\r\n *\r\n * @returns {Object} An object containing the calculated `height`, `width`\r\n * and `scale` values for the chart export.\r\n */\r\nfunction _findChartSize(exportOptions) {\r\n // Check the `options` and `instr` for chart and exporting sections\r\n const { chart: optionsChart, exporting: optionsExporting } =\r\n exportOptions.options || isAllowedConfig(exportOptions.instr) || false;\r\n\r\n // Check the `globalOptions` for chart and exporting sections\r\n const { chart: globalOptionsChart, exporting: globalOptionsExporting } =\r\n isAllowedConfig(exportOptions.globalOptions) || false;\r\n\r\n // Check the `themeOptions` for chart and exporting sections\r\n const { chart: themeOptionsChart, exporting: themeOptionsExporting } =\r\n isAllowedConfig(exportOptions.themeOptions) || false;\r\n\r\n // Find the `scale` value:\r\n // - It cannot be lower than 0.1\r\n // - It cannot be higher than 5.0\r\n // - It must be rounded to 2 decimal places (e.g. 0.23234 -> 0.23)\r\n const scale = roundNumber(\r\n Math.max(\r\n 0.1,\r\n Math.min(\r\n exportOptions.scale ||\r\n optionsExporting?.scale ||\r\n globalOptionsExporting?.scale ||\r\n themeOptionsExporting?.scale ||\r\n exportOptions.defaultScale ||\r\n 1,\r\n 5.0\r\n )\r\n ),\r\n 2\r\n );\r\n\r\n // Find the `height` value\r\n const height =\r\n exportOptions.height ||\r\n optionsExporting?.sourceHeight ||\r\n optionsChart?.height ||\r\n globalOptionsExporting?.sourceHeight ||\r\n globalOptionsChart?.height ||\r\n themeOptionsExporting?.sourceHeight ||\r\n themeOptionsChart?.height ||\r\n exportOptions.defaultHeight ||\r\n 400;\r\n\r\n // Find the `width` value\r\n const width =\r\n exportOptions.width ||\r\n optionsExporting?.sourceWidth ||\r\n optionsChart?.width ||\r\n globalOptionsExporting?.sourceWidth ||\r\n globalOptionsChart?.width ||\r\n themeOptionsExporting?.sourceWidth ||\r\n themeOptionsChart?.width ||\r\n exportOptions.defaultWidth ||\r\n 600;\r\n\r\n // Gather `height`, `width` and `scale` information in one object\r\n const size = { height, width, scale };\r\n\r\n // Get rid of potential `px` and `%`\r\n for (let [param, value] of Object.entries(size)) {\r\n size[param] =\r\n typeof value === 'string' ? +value.replace(/px|%/gi, '') : value;\r\n }\r\n\r\n // Return the size object\r\n return size;\r\n}\r\n\r\n/**\r\n * Handles the execution of custom logic options, including loading `resources`,\r\n * `customCode`, and `callback`. If code execution is allowed, it processes\r\n * the custom logic options accordingly. If code execution is not allowed,\r\n * it disables the usage of resources, custom code and callback.\r\n *\r\n * @function _handleCustomLogic\r\n *\r\n * @param {Object} customLogicOptions - The object containing `customLogic`\r\n * options.\r\n * @param {boolean} allowCodeExecution - A flag indicating whether code\r\n * execution is allowed.\r\n *\r\n * @throws {ExportError} Throws an `ExportError` if code execution\r\n * is not allowed but custom logic options are still provided.\r\n */\r\nfunction _handleCustomLogic(customLogicOptions, allowCodeExecution) {\r\n // In case of allowing code execution\r\n if (allowCodeExecution) {\r\n // Process the `resources` option\r\n if (typeof customLogicOptions.resources === 'string') {\r\n // Custom stringified resources\r\n customLogicOptions.resources = _handleResources(\r\n customLogicOptions.resources,\r\n customLogicOptions.allowFileResources,\r\n true\r\n );\r\n } else if (!customLogicOptions.resources) {\r\n try {\r\n // Load the default one\r\n customLogicOptions.resources = _handleResources(\r\n readFileSync(getAbsolutePath('resources.json'), 'utf8'),\r\n customLogicOptions.allowFileResources,\r\n true\r\n );\r\n } catch (error) {\r\n log(2, '[chart] Unable to load the default `resources.json` file.');\r\n }\r\n }\r\n\r\n // Process the `customCode` option\r\n try {\r\n // Try to load custom code and wrap around it in a self invoking function\r\n customLogicOptions.customCode = wrapAround(\r\n customLogicOptions.customCode,\r\n customLogicOptions.allowFileResources\r\n );\r\n } catch (error) {\r\n logWithStack(2, error, '[chart] The `customCode` cannot be loaded.');\r\n\r\n // In case of an error, set the option with null\r\n customLogicOptions.customCode = null;\r\n }\r\n\r\n // Process the `callback` option\r\n try {\r\n // Try to load callback function\r\n customLogicOptions.callback = wrapAround(\r\n customLogicOptions.callback,\r\n customLogicOptions.allowFileResources,\r\n true\r\n );\r\n } catch (error) {\r\n logWithStack(2, error, '[chart] The `callback` cannot be loaded.');\r\n\r\n // In case of an error, set the option with null\r\n customLogicOptions.callback = null;\r\n }\r\n\r\n // Check if there is the `customCode` present\r\n if ([null, undefined].includes(customLogicOptions.customCode)) {\r\n log(3, '[chart] No value for the `customCode` option found.');\r\n }\r\n\r\n // Check if there is the `callback` present\r\n if ([null, undefined].includes(customLogicOptions.callback)) {\r\n log(3, '[chart] No value for the `callback` option found.');\r\n }\r\n\r\n // Check if there is the `resources` present\r\n if ([null, undefined].includes(customLogicOptions.resources)) {\r\n log(3, '[chart] No value for the `resources` option found.');\r\n }\r\n } else {\r\n // If the `allowCodeExecution` flag is set to false, we should refuse\r\n // the usage of the `callback`, `resources`, and `customCode` options.\r\n // Additionally, the worker will refuse to run arbitrary JavaScript.\r\n if (\r\n customLogicOptions.callback ||\r\n customLogicOptions.resources ||\r\n customLogicOptions.customCode\r\n ) {\r\n // Reset all custom code options\r\n customLogicOptions.callback = null;\r\n customLogicOptions.resources = null;\r\n customLogicOptions.customCode = null;\r\n\r\n // Send a message saying that the exporter does not support these settings\r\n throw new ExportError(\r\n `[chart] The 'callback', 'resources', and 'customCode' options have been disabled for this server.`,\r\n 403\r\n );\r\n }\r\n }\r\n}\r\n\r\n/**\r\n * Handles and validates resources from the `resources` option for export.\r\n *\r\n * @function _handleResources\r\n *\r\n * @param {(Object|string|null)} [resources=null] - The resources to be handled.\r\n * Can be either a JSON object, stringified JSON, a path to a JSON file,\r\n * or null. The default value is null.\r\n * @param {boolean} allowFileResources - A flag indicating whether loading\r\n * resources from files is allowed.\r\n * @param {boolean} allowCodeExecution - A flag indicating whether code\r\n * execution is allowed.\r\n *\r\n * @returns {(Object|null)} The handled resources or null if no valid resources\r\n * are found.\r\n */\r\nfunction _handleResources(\r\n resources = null,\r\n allowFileResources,\r\n allowCodeExecution\r\n) {\r\n // List of allowed sections in the resources JSON\r\n const allowedProps = ['js', 'css', 'files'];\r\n\r\n let handledResources = resources;\r\n let correctResources = false;\r\n\r\n // Try to load resources from a file\r\n if (allowFileResources && resources.endsWith('.json')) {\r\n try {\r\n handledResources = isAllowedConfig(\r\n readFileSync(getAbsolutePath(resources), 'utf8'),\r\n false,\r\n allowCodeExecution\r\n );\r\n } catch {\r\n return null;\r\n }\r\n } else {\r\n // Try to get JSON\r\n handledResources = isAllowedConfig(resources, false, allowCodeExecution);\r\n\r\n // Get rid of the files section\r\n if (handledResources && !allowFileResources) {\r\n delete handledResources.files;\r\n }\r\n }\r\n\r\n // Filter from unnecessary properties\r\n for (const propName in handledResources) {\r\n if (!allowedProps.includes(propName)) {\r\n delete handledResources[propName];\r\n } else if (!correctResources) {\r\n correctResources = true;\r\n }\r\n }\r\n\r\n // Check if at least one of allowed properties is present\r\n if (!correctResources) {\r\n return null;\r\n }\r\n\r\n // Handle files section\r\n if (handledResources.files) {\r\n handledResources.files = handledResources.files.map((item) => item.trim());\r\n if (!handledResources.files || handledResources.files.length <= 0) {\r\n delete handledResources.files;\r\n }\r\n }\r\n\r\n // Return resources\r\n return handledResources;\r\n}\r\n\r\n/**\r\n * Handles the loading and validation of the `globalOptions` and `themeOptions`\r\n * in the export options. If the option is a string and references a JSON file\r\n * (when the `allowFileResources` is true), it reads and parses the file.\r\n * Otherwise, it attempts to parse the string or object as JSON. If any errors\r\n * occur during this process, the option is set to null. If there is an error\r\n * loading or parsing the `globalOptions` or `themeOptions`, the error is logged\r\n * and the option is set to null.\r\n *\r\n * @function _handleGlobalAndTheme\r\n *\r\n * @param {Object} exportOptions - The object containing `export` options.\r\n * @param {boolean} allowFileResources - A flag indicating whether loading\r\n * resources from files is allowed.\r\n * @param {boolean} allowCodeExecution - A flag indicating whether code\r\n * execution is allowed.\r\n */\r\nfunction _handleGlobalAndTheme(\r\n exportOptions,\r\n allowFileResources,\r\n allowCodeExecution\r\n) {\r\n // Check the `globalOptions` and `themeOptions` options\r\n ['globalOptions', 'themeOptions'].forEach((optionsName) => {\r\n try {\r\n // Check if the option exists\r\n if (exportOptions[optionsName]) {\r\n // Check if it is a string and a file name with the `.json` extension\r\n if (\r\n allowFileResources &&\r\n typeof exportOptions[optionsName] === 'string' &&\r\n exportOptions[optionsName].endsWith('.json')\r\n ) {\r\n // Check if the file content can be a config, and save it as a string\r\n exportOptions[optionsName] = isAllowedConfig(\r\n readFileSync(getAbsolutePath(exportOptions[optionsName]), 'utf8'),\r\n true,\r\n allowCodeExecution\r\n );\r\n } else {\r\n // Check if the value can be a config, and save it as a string\r\n exportOptions[optionsName] = isAllowedConfig(\r\n exportOptions[optionsName],\r\n true,\r\n allowCodeExecution\r\n );\r\n }\r\n }\r\n } catch (error) {\r\n logWithStack(\r\n 2,\r\n error,\r\n `[chart] The \\`${optionsName}\\` cannot be loaded.`\r\n );\r\n\r\n // In case of an error, set the option with null\r\n exportOptions[optionsName] = null;\r\n }\r\n });\r\n\r\n // Check if there is the `globalOptions` present\r\n if ([null, undefined].includes(exportOptions.globalOptions)) {\r\n log(3, '[chart] No value for the `globalOptions` option found.');\r\n }\r\n\r\n // Check if there is the `themeOptions` present\r\n if ([null, undefined].includes(exportOptions.themeOptions)) {\r\n log(3, '[chart] No value for the `themeOptions` option found.');\r\n }\r\n}\r\n\r\nexport default {\r\n startExport,\r\n singleExport,\r\n batchExport,\r\n getAllowCodeExecution,\r\n setAllowCodeExecution\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * @overview This module provides utility functions for managing intervals\r\n * and timeouts in a centralized manner. It maintains a registry of all active\r\n * timers and allows for their efficient cleanup when needed. This can be useful\r\n * in applications where proper resource management and clean shutdown of timers\r\n * are critical to avoid memory leaks or unintended behavior.\r\n */\r\n\r\nimport { log } from './logger.js';\r\n\r\n// Array that contains ids of all ongoing intervals and timeouts\r\nconst timerIds = [];\r\n\r\n/**\r\n * Adds id of the `setInterval` or `setTimeout` and to the `timerIds` array.\r\n *\r\n * @function addTimer\r\n *\r\n * @param {NodeJS.Timeout} id - Id of an interval or a timeout.\r\n */\r\nexport function addTimer(id) {\r\n timerIds.push(id);\r\n}\r\n\r\n/**\r\n * Clears all of ongoing intervals and timeouts by ids gathered\r\n * in the `timerIds` array.\r\n *\r\n * @function clearAllTimers\r\n */\r\nexport function clearAllTimers() {\r\n log(4, `[timer] Clearing all registered intervals and timeouts.`);\r\n for (const id of timerIds) {\r\n clearInterval(id);\r\n clearTimeout(id);\r\n }\r\n}\r\n\r\nexport default {\r\n addTimer,\r\n clearAllTimers\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * @overview Provides middleware functions for logging errors with stack traces\r\n * and handling error responses in an Express application.\r\n */\r\n\r\nimport { getOptions } from '../../config.js';\r\nimport { logWithStack } from '../../logger.js';\r\n\r\n/**\r\n * Middleware for logging errors with stack trace and handling error response.\r\n *\r\n * @function logErrorMiddleware\r\n *\r\n * @param {Error} error - The error object.\r\n * @param {Express.Request} request - The Express request object.\r\n * @param {Express.Response} response - The Express response object.\r\n * @param {Function} next - The next middleware function.\r\n *\r\n * @returns {undefined} The call to the next middleware function with\r\n * the passed error.\r\n */\r\nfunction logErrorMiddleware(error, request, response, next) {\r\n // Display the error with stack in a correct format\r\n logWithStack(1, error);\r\n\r\n // Delete the stack for the environment other than the development\r\n if (getOptions().other.nodeEnv !== 'development') {\r\n delete error.stack;\r\n }\r\n\r\n // Call the `returnErrorMiddleware` middleware\r\n return next(error);\r\n}\r\n\r\n/**\r\n * Middleware for returning error response.\r\n *\r\n * @function returnErrorMiddleware\r\n *\r\n * @param {Error} error - The error object.\r\n * @param {Express.Request} request - The Express request object.\r\n * @param {Express.Response} response - The Express response object.\r\n * @param {Function} next - The next middleware function.\r\n */\r\nfunction returnErrorMiddleware(error, request, response, next) {\r\n // Gather all requied information for the response\r\n const { message, stack } = error;\r\n\r\n // Use the error's status code or the default 400\r\n const statusCode = error.statusCode || 400;\r\n\r\n // Set and return response\r\n response.status(statusCode).json({ statusCode, message, stack });\r\n}\r\n\r\n/**\r\n * Adds the error middlewares to the passed express app instance.\r\n *\r\n * @param {Express} app - The Express app instance.\r\n */\r\nexport default function errorMiddleware(app) {\r\n // Add log error middleware\r\n app.use(logErrorMiddleware);\r\n\r\n // Add set status and return error middleware\r\n app.use(returnErrorMiddleware);\r\n}\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * @overview Provides middleware functions for configuring and enabling rate\r\n * limiting in an Express application.\r\n */\r\n\r\nimport rateLimit from 'express-rate-limit';\r\n\r\nimport { getOptions } from '../../config.js';\r\nimport { log } from '../../logger.js';\r\n\r\nimport ExportError from '../../errors/ExportError.js';\r\n\r\n/**\r\n * Middleware for enabling rate limiting on the specified Express app.\r\n *\r\n * @param {Express} app - The Express app instance.\r\n *\r\n * @param {Object} [rateLimitingOptions=getOptions().server.rateLimiting] -\r\n * Object containing `rateLimiting` options. The default value is the global\r\n * rate limiting options of the export server instance.\r\n *\r\n * @throws {ExportError} Throws an `ExportError` if could not configure and set\r\n * the rate limiting options.\r\n */\r\nexport default function rateLimitingMiddleware(\r\n app,\r\n rateLimitingOptions = getOptions().server.rateLimiting\r\n) {\r\n try {\r\n // Check if the rate limiting is enabled\r\n if (rateLimitingOptions.enable) {\r\n const msg =\r\n 'Too many requests, you have been rate limited. Please try again later.';\r\n\r\n // Options for the rate limiter\r\n const rateOptions = {\r\n max: rateLimitingOptions.maxRequests || 30,\r\n window: rateLimitingOptions.window || 1,\r\n delay: rateLimitingOptions.delay || 0,\r\n trustProxy: rateLimitingOptions.trustProxy || false,\r\n skipKey: rateLimitingOptions.skipKey || false,\r\n skipToken: rateLimitingOptions.skipToken || false\r\n };\r\n\r\n // Set if behind a proxy\r\n if (rateOptions.trustProxy) {\r\n app.enable('trust proxy');\r\n }\r\n\r\n // Create a limiter\r\n const limiter = rateLimit({\r\n windowMs: rateOptions.window * 60 * 1000,\r\n // Limit each IP to 100 requests per windowMs\r\n max: rateOptions.max,\r\n // Disable delaying, full speed until the max limit is reached\r\n delayMs: rateOptions.delay,\r\n handler: (request, response) => {\r\n response.format({\r\n json: () => {\r\n response.status(429).send({ message: msg });\r\n },\r\n default: () => {\r\n response.status(429).send(msg);\r\n }\r\n });\r\n },\r\n skip: (request) => {\r\n // Allow bypassing the limiter if a valid key/token has been sent\r\n if (\r\n rateOptions.skipKey !== false &&\r\n rateOptions.skipToken !== false &&\r\n request.query.key === rateOptions.skipKey &&\r\n request.query.access_token === rateOptions.skipToken\r\n ) {\r\n log(4, '[rate limiting] Skipping rate limiter.');\r\n return true;\r\n }\r\n return false;\r\n }\r\n });\r\n\r\n // Use a limiter as a middleware\r\n app.use(limiter);\r\n\r\n log(\r\n 3,\r\n `[rate limiting] Enabled rate limiting with ${rateOptions.max} requests per ${rateOptions.window} minute for each IP, trusting proxy: ${rateOptions.trustProxy}.`\r\n );\r\n }\r\n } catch (error) {\r\n throw new ExportError(\r\n '[rate limiting] Could not configure and set the rate limiting options.',\r\n 500\r\n ).setError(error);\r\n }\r\n}\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\nimport ExportError from './ExportError.js';\r\n\r\n/**\r\n * A custom HTTP error class that extends the `ExportError`. Used to handle\r\n * errors with HTTP status codes.\r\n */\r\nclass HttpError extends ExportError {\r\n /**\r\n * Creates an instance of the `HttpError`.\r\n *\r\n * @param {string} message - The error message to be displayed.\r\n * @param {number} statusCode - Optional HTTP status code associated\r\n * with the error (e.g., 400, 500).\r\n */\r\n constructor(message, statusCode) {\r\n super(message, statusCode);\r\n }\r\n\r\n /**\r\n * Sets or updates the HTTP status code for the error.\r\n *\r\n * @param {number} statusCode - The HTTP status code to assign to the error.\r\n *\r\n * @returns {HttpError} The updated instance of the `HttpError` class.\r\n */\r\n setStatus(statusCode) {\r\n this.statusCode = statusCode;\r\n\r\n return this;\r\n }\r\n}\r\n\r\nexport default HttpError;\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * @overview Provides middleware functions for validating incoming HTTP requests\r\n * in an Express application. This module ensures that requests contain\r\n * appropriate content types and valid request bodies, including proper JSON\r\n * structures and chart data for exports. It checks for potential issues such\r\n * as missing or malformed data, private range URLs in SVG payloads, and allows\r\n * for flexible options validation. The middleware logs detailed information\r\n * and handles errors related to incorrect payloads, chart data, and private URL\r\n * usage.\r\n */\r\n\r\nimport { v4 as uuid } from 'uuid';\r\n\r\nimport { getAllowCodeExecution } from '../../chart.js';\r\nimport { isAllowedConfig } from '../../config.js';\r\nimport { log, logZodIssues } from '../../logger.js';\r\nimport {\r\n fixConstr,\r\n fixType,\r\n isObjectEmpty,\r\n isPrivateRangeUrlFound\r\n} from '../../utils.js';\r\nimport { looseValidate } from '../../validation.js';\r\n\r\nimport HttpError from '../../errors/HttpError.js';\r\n\r\n/**\r\n * Middleware for validating the content-type header.\r\n *\r\n * @function contentTypeMiddleware\r\n *\r\n * @param {Express.Request} request - The Express request object.\r\n * @param {Express.Response} response - The Express response object.\r\n * @param {Function} next - The next middleware function.\r\n *\r\n * @returns {undefined} The call to the next middleware function.\r\n *\r\n * @throws {HttpError} Throws an `HttpError` if the content-type\r\n * is not correct.\r\n */\r\nfunction contentTypeMiddleware(request, response, next) {\r\n try {\r\n // Get the content type header\r\n const contentType = request.headers['content-type'] || '';\r\n\r\n // Allow only JSON, URL-encoded and form data without files types of data\r\n if (\r\n !contentType.includes('application/json') &&\r\n !contentType.includes('application/x-www-form-urlencoded') &&\r\n !contentType.includes('multipart/form-data')\r\n ) {\r\n throw new HttpError(\r\n '[validation] Content-Type must be application/json, application/x-www-form-urlencoded, or multipart/form-data.',\r\n 415\r\n );\r\n }\r\n\r\n // Call the `requestBodyMiddleware` middleware\r\n return next();\r\n } catch (error) {\r\n return next(error);\r\n }\r\n}\r\n\r\n/**\r\n * Middleware for validating the request's body.\r\n *\r\n * @function requestBodyMiddleware\r\n *\r\n * @param {Express.Request} request - The Express request object.\r\n * @param {Express.Response} response - The Express response object.\r\n * @param {Function} next - The next middleware function.\r\n *\r\n * @returns {undefined} The call to the next middleware function.\r\n *\r\n * @throws {HttpError} Throws an `HttpError` if the body is not correct.\r\n * @throws {HttpError} Throws an `HttpError` if the chart data from the body\r\n * is not correct.\r\n * @throws {HttpError} Throws an `HttpError` in case of the private range url\r\n * error.\r\n */\r\nfunction requestBodyMiddleware(request, response, next) {\r\n try {\r\n // Get the request body\r\n const body = request.body;\r\n\r\n // Create a unique ID for a request\r\n const requestId = uuid().replace(/-/g, '');\r\n\r\n // Throw an error if there is no correct body\r\n if (!body || isObjectEmpty(body)) {\r\n log(\r\n 2,\r\n `[validation] Request [${requestId}] - The request from ${\r\n request.headers['x-forwarded-for'] || request.connection.remoteAddress\r\n } was incorrect. Received payload is empty.`\r\n );\r\n\r\n throw new HttpError(\r\n \"[validation] The request body is required. Please ensure that your Content-Type header is correct. Accepted types are 'application/json' and 'multipart/form-data'.\",\r\n 400\r\n );\r\n }\r\n\r\n // Get the `allowCodeExecution` option for the server\r\n const allowCodeExecution = getAllowCodeExecution();\r\n\r\n // Find a correct chart options\r\n const instr = isAllowedConfig(\r\n // Use one of the below\r\n body.instr || body.options || body.infile || body.data,\r\n // Stringify options\r\n true,\r\n // Allow or disallow functions\r\n allowCodeExecution\r\n );\r\n\r\n // Throw an error if there is no correct chart data\r\n if (instr === null && !body.svg) {\r\n log(\r\n 2,\r\n `[validation] Request [${requestId}] - The request from ${\r\n request.headers['x-forwarded-for'] || request.connection.remoteAddress\r\n } was incorrect. Received payload is missing correct chart data for export: ${JSON.stringify(body)}.`\r\n );\r\n\r\n throw new HttpError(\r\n \"[validation] No correct chart data found. Ensure that you are using either application/json or multipart/form-data headers. If sending JSON, make sure the chart data is in the 'infile', 'options', or 'data' attribute. If sending SVG, ensure it is in the 'svg' attribute.\",\r\n 400\r\n );\r\n }\r\n\r\n // Throw an error if test of xlink:href elements from payload's SVG fails\r\n if (body.svg && isPrivateRangeUrlFound(body.svg)) {\r\n throw new HttpError(\r\n \"[validation] SVG potentially contain at least one forbidden URL in 'xlink:href' element. Please review the SVG content and ensure that all referenced URLs comply with security policies.\",\r\n 400\r\n );\r\n }\r\n\r\n try {\r\n // Validate options from the body and store parsed structure in the request\r\n request.validatedOptions = looseValidate({\r\n // Set the created ID as a `_requestId` property in the validated options\r\n _requestId: requestId,\r\n export: {\r\n instr,\r\n svg: body.svg,\r\n outfile:\r\n body.outfile ||\r\n `${request.params.filename || 'chart'}.${fixType(body.type)}`,\r\n type: fixType(body.type, body.outfile),\r\n constr: fixConstr(body.constr),\r\n b64: body.b64,\r\n noDownload: body.noDownload,\r\n height: body.height,\r\n width: body.width,\r\n scale: body.scale,\r\n globalOptions: isAllowedConfig(\r\n body.globalOptions,\r\n true,\r\n allowCodeExecution\r\n ),\r\n themeOptions: isAllowedConfig(\r\n body.themeOptions,\r\n true,\r\n allowCodeExecution\r\n )\r\n },\r\n customLogic: {\r\n allowCodeExecution,\r\n allowFileResources: false,\r\n customCode: body.customCode,\r\n callback: body.callback,\r\n resources: isAllowedConfig(body.resources, true, allowCodeExecution)\r\n }\r\n });\r\n } catch (error) {\r\n logZodIssues(\r\n 1,\r\n error.issues,\r\n '[config] Request options validation error'\r\n );\r\n\r\n throw new HttpError(\r\n 'The provided options are not correct. Please check if your data is of the correct types.',\r\n 400\r\n );\r\n }\r\n\r\n // Call the next middleware\r\n return next();\r\n } catch (error) {\r\n return next(error);\r\n }\r\n}\r\n\r\n/**\r\n * Adds the validation middlewares to the passed express app instance.\r\n *\r\n * @param {Express} app - The Express app instance.\r\n */\r\nexport default function validationMiddleware(app) {\r\n // Add content type validation middleware\r\n app.post(['/', '/:filename'], contentTypeMiddleware);\r\n\r\n // Add request body request validation middleware\r\n app.post(['/', '/:filename'], requestBodyMiddleware);\r\n}\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * @overview Defines the export routes and logic for handling chart export\r\n * requests in an Express server. This module processes incoming requests\r\n * to export charts in various formats (e.g. JPEG, PNG, PDF, SVG). It integrates\r\n * with Highcharts' core functionalities and supports both immediate download\r\n * responses and Base64-encoded content returns. The code also features\r\n * benchmarking for performance monitoring.\r\n */\r\n\r\nimport { startExport } from '../../chart.js';\r\nimport { log } from '../../logger.js';\r\nimport { getBase64, measureTime } from '../../utils.js';\r\n\r\nimport HttpError from '../../errors/HttpError.js';\r\n\r\n// Reversed MIME types\r\nconst reversedMime = {\r\n png: 'image/png',\r\n jpeg: 'image/jpeg',\r\n gif: 'image/gif',\r\n pdf: 'application/pdf',\r\n svg: 'image/svg+xml'\r\n};\r\n\r\n/**\r\n * Handles the export requests from the client.\r\n *\r\n * @async\r\n * @function requestExport\r\n *\r\n * @param {Express.Request} request - The Express request object.\r\n * @param {Express.Response} response - The Express response object.\r\n * @param {Function} next - The next middleware function.\r\n *\r\n * @returns {Promise} A Promise that resolves once the export process\r\n * is complete.\r\n */\r\nasync function requestExport(request, response, next) {\r\n try {\r\n // Start counting time for a request\r\n const requestCounter = measureTime();\r\n\r\n // In case the connection is closed, force to abort further actions\r\n let connectionAborted = false;\r\n request.socket.on('close', (hadErrors) => {\r\n if (hadErrors) {\r\n connectionAborted = true;\r\n }\r\n });\r\n\r\n // Get the options previously validated in the validation middleware\r\n const requestOptions = request.validatedOptions;\r\n\r\n // Get the request id\r\n const requestId = requestOptions._requestId;\r\n\r\n // Info about an incoming request with correct data\r\n log(4, `[export] Got an incoming HTTP request with ID ${requestId}.`);\r\n\r\n // Start the export process\r\n await startExport(requestOptions, (error, data) => {\r\n // Remove the close event from the socket\r\n request.socket.removeAllListeners('close');\r\n\r\n // If the connection was closed, do nothing\r\n if (connectionAborted) {\r\n log(\r\n 3,\r\n `[export] Request [${requestId}] - The client closed the connection before the chart finished processing.`\r\n );\r\n return;\r\n }\r\n\r\n // If error, log it and send it to the error middleware\r\n if (error) {\r\n throw error;\r\n }\r\n\r\n // If data is missing, log the message and send it to the error middleware\r\n if (!data || !data.result) {\r\n log(\r\n 2,\r\n `[export] Request [${requestId}] - Request from ${\r\n request.headers['x-forwarded-for'] ||\r\n request.connection.remoteAddress\r\n } was incorrect. Received result is ${data.result}.`\r\n );\r\n\r\n throw new HttpError(\r\n '[export] Unexpected return of the export result from the chart generation. Please check your request data.',\r\n 400\r\n );\r\n }\r\n\r\n // Return the result in an appropriate format\r\n if (data.result) {\r\n log(\r\n 3,\r\n `[export] Request [${requestId}] - The whole exporting process took ${requestCounter()}ms.`\r\n );\r\n\r\n // Get the `type`, `b64`, `noDownload`, and `outfile` from options\r\n const { type, b64, noDownload, outfile } = data.options.export;\r\n\r\n // If only Base64 is required, return it\r\n if (b64) {\r\n return response.send(getBase64(data.result, type));\r\n }\r\n\r\n // Set correct content type\r\n response.header('Content-Type', reversedMime[type] || 'image/png');\r\n\r\n // Decide whether to download or not chart file\r\n if (!noDownload) {\r\n response.attachment(outfile);\r\n }\r\n\r\n // If SVG, return plain content, otherwise a b64 string from a buffer\r\n return type === 'svg'\r\n ? response.send(data.result)\r\n : response.send(Buffer.from(data.result, 'base64'));\r\n }\r\n });\r\n } catch (error) {\r\n return next(error);\r\n }\r\n}\r\n\r\n/**\r\n * Adds the `export` routes.\r\n *\r\n * @function exportRoutes\r\n *\r\n * @param {Express} app - The Express app instance.\r\n */\r\nexport default function exportRoutes(app) {\r\n /**\r\n * Adds the POST '/' - A route for handling POST requests at the root\r\n * endpoint.\r\n */\r\n app.post('/', requestExport);\r\n\r\n /**\r\n * Adds the POST '/:filename' - A route for handling POST requests with\r\n * a specified filename parameter.\r\n */\r\n app.post('/:filename', requestExport);\r\n}\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * @overview Defines an Express route for server health monitoring, including\r\n * uptime, success rates, and other server statistics.\r\n */\r\n\r\nimport { readFileSync } from 'fs';\r\nimport { join } from 'path';\r\n\r\nimport { getHighchartsVersion } from '../../cache.js';\r\nimport { log } from '../../logger.js';\r\nimport { getPoolStats, getPoolInfoJSON } from '../../pool.js';\r\nimport { addTimer } from '../../timer.js';\r\nimport { __dirname, getNewDateTime } from '../../utils.js';\r\n\r\n// Set the start date of the server\r\nconst serverStartTime = new Date();\r\n\r\n// Get the `package.json` content\r\nconst packageFile = JSON.parse(readFileSync(join(__dirname, 'package.json')));\r\n\r\n// An array for success rate ratios\r\nconst successRates = [];\r\n\r\n// Record every minute\r\nconst recordInterval = 60 * 1000;\r\n\r\n// 30 minutes\r\nconst windowSize = 30;\r\n\r\n/**\r\n * Calculates moving average indicator based on the data from the `successRates`\r\n * array.\r\n *\r\n * @function _calculateMovingAverage\r\n *\r\n * @returns {number} A moving average for success ratio of the server exports.\r\n */\r\nfunction _calculateMovingAverage() {\r\n return successRates.reduce((a, b) => a + b, 0) / successRates.length;\r\n}\r\n\r\n/**\r\n * Starts the interval responsible for calculating current success rate ratio\r\n * and collects records to the `successRates` array.\r\n *\r\n * @function _startSuccessRate\r\n *\r\n * @returns {NodeJS.Timeout} Id of an interval.\r\n */\r\nfunction _startSuccessRate() {\r\n return setInterval(() => {\r\n const stats = getPoolStats();\r\n const successRatio =\r\n stats.exportsAttempted === 0\r\n ? 1\r\n : (stats.exportsPerformed / stats.exportsAttempted) * 100;\r\n\r\n successRates.push(successRatio);\r\n if (successRates.length > windowSize) {\r\n successRates.shift();\r\n }\r\n }, recordInterval);\r\n}\r\n\r\n/**\r\n * Adds the `health` routes.\r\n *\r\n * @function healthRoutes\r\n *\r\n * @param {Express} app - The Express app instance.\r\n */\r\nexport default function healthRoutes(app) {\r\n // Start processing success rate ratio interval and save its id to the array\r\n // for the graceful clearing on shutdown with injected `addTimer` funtion\r\n addTimer(_startSuccessRate());\r\n\r\n /**\r\n * Adds the GET '/health' - A route for getting the basic stats of the server.\r\n */\r\n app.get('/health', (request, response, next) => {\r\n try {\r\n log(4, '[health] Returning server health.');\r\n\r\n const stats = getPoolStats();\r\n const period = successRates.length;\r\n const movingAverage = _calculateMovingAverage();\r\n\r\n // Send the server's statistics\r\n response.send({\r\n // Status and times\r\n status: 'OK',\r\n bootTime: serverStartTime,\r\n uptime: `${Math.floor((getNewDateTime() - serverStartTime.getTime()) / 1000 / 60)} minutes`,\r\n\r\n // Versions\r\n serverVersion: packageFile.version,\r\n highchartsVersion: getHighchartsVersion(),\r\n\r\n // Exports\r\n averageExportTime: stats.timeSpentAverage,\r\n attemptedExports: stats.exportsAttempted,\r\n performedExports: stats.exportsPerformed,\r\n failedExports: stats.exportsDropped,\r\n sucessRatio: (stats.exportsPerformed / stats.exportsAttempted) * 100,\r\n\r\n // Pool\r\n pool: getPoolInfoJSON(),\r\n\r\n // Moving average\r\n period,\r\n movingAverage,\r\n message:\r\n isNaN(movingAverage) || !successRates.length\r\n ? 'Too early to report. No exports made yet. Please check back soon.'\r\n : `Last ${period} minutes had a success rate of ${movingAverage.toFixed(2)}%.`,\r\n\r\n // SVG and JSON exports\r\n svgExports: stats.exportsFromSvg,\r\n jsonExports: stats.exportsFromOptions,\r\n svgExportsAttempts: stats.exportsFromSvgAttempts,\r\n jsonExportsAttempts: stats.exportsFromOptionsAttempts\r\n });\r\n } catch (error) {\r\n return next(error);\r\n }\r\n });\r\n}\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * @overview Defines an Express route for serving the UI for the export server\r\n * when enabled.\r\n */\r\n\r\nimport { join } from 'path';\r\n\r\nimport { getOptions } from '../../config.js';\r\nimport { __dirname } from '../../utils.js';\r\n\r\n/**\r\n * Adds the `ui` routes.\r\n *\r\n * @function uiRoutes\r\n *\r\n * @param {Express} app - The Express app instance.\r\n */\r\nexport default function uiRoutes(app) {\r\n /**\r\n * Adds the GET '/' - A route for a UI when enabled on the export server.\r\n */\r\n app.get(getOptions().ui.route || '/', (request, response, next) => {\r\n try {\r\n response.sendFile(join(__dirname, 'public', 'index.html'), {\r\n acceptRanges: false\r\n });\r\n } catch (error) {\r\n return next(error);\r\n }\r\n });\r\n}\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * @overview Defines an Express route for updating the Highcharts version\r\n * on the server, with authentication and validation.\r\n */\r\n\r\nimport { updateHighchartsVersion, getHighchartsVersion } from '../../cache.js';\r\nimport { envs } from '../../validation.js';\r\n\r\nimport HttpError from '../../errors/HttpError.js';\r\n\r\n/**\r\n * Adds the `version_change` routes.\r\n *\r\n * @function versionChangeRoutes\r\n *\r\n * @param {Express} app - The Express app instance.\r\n */\r\nexport default function versionChangeRoutes(app) {\r\n /**\r\n * Adds the POST '/version_change/:newVersion' - A route for changing\r\n * the Highcharts version on the server.\r\n */\r\n app.post('/version_change/:newVersion', async (request, response, next) => {\r\n try {\r\n // Get the token directly from envs\r\n const adminToken = envs.HIGHCHARTS_ADMIN_TOKEN;\r\n\r\n // Check the existence of the token\r\n if (!adminToken || !adminToken.length) {\r\n throw new HttpError(\r\n '[version] The server is not configured to perform run-time version changes: HIGHCHARTS_ADMIN_TOKEN is not set.',\r\n 401\r\n );\r\n }\r\n\r\n // Get the token from the hc-auth header\r\n const token = request.get('hc-auth');\r\n\r\n // Check if the hc-auth header contain a correct token\r\n if (!token || token !== adminToken) {\r\n throw new HttpError(\r\n '[version] Invalid or missing token: Set the token in the hc-auth header.',\r\n 401\r\n );\r\n }\r\n\r\n // Compare versions\r\n const newVersion = request.params.newVersion;\r\n if (newVersion) {\r\n try {\r\n // Update version\r\n await updateHighchartsVersion(newVersion);\r\n } catch (error) {\r\n throw new HttpError(\r\n `[version] Version change: ${error.message}`,\r\n 400\r\n ).setError(error);\r\n }\r\n\r\n // Success\r\n response.status(200).send({\r\n statusCode: 200,\r\n highchartsVersion: getHighchartsVersion(),\r\n message: `Successfully updated Highcharts to version: ${newVersion}.`\r\n });\r\n } else {\r\n // No version specified\r\n throw new HttpError('[version] No new version supplied.', 400);\r\n }\r\n } catch (error) {\r\n return next(error);\r\n }\r\n });\r\n}\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * @overview A module that sets up and manages HTTP and HTTPS servers\r\n * for the Highcharts Export Server. It handles server initialization,\r\n * configuration, error handling, middleware setup, route definition, and rate\r\n * limiting. The module exports functions to start, stop, and manage server\r\n * instances, as well as utility functions for defining routes and attaching\r\n * middlewares.\r\n */\r\n\r\nimport { readFile } from 'fs/promises';\r\nimport { join } from 'path';\r\n\r\nimport cors from 'cors';\r\nimport express from 'express';\r\nimport http from 'http';\r\nimport https from 'https';\r\nimport multer from 'multer';\r\n\r\nimport { getOptions } from '../config.js';\r\nimport { log, logWithStack } from '../logger.js';\r\nimport { __dirname, getAbsolutePath } from '../utils.js';\r\n\r\nimport errorMiddleware from './middlewares/error.js';\r\nimport rateLimitingMiddleware from './middlewares/rateLimiting.js';\r\nimport validationMiddleware from './middlewares/validation.js';\r\n\r\nimport exportRoutes from './routes/export.js';\r\nimport healthRoutes from './routes/health.js';\r\nimport uiRoutes from './routes/ui.js';\r\nimport versionChangeRoutes from './routes/versionChange.js';\r\n\r\nimport ExportError from '../errors/ExportError.js';\r\n\r\n// Array of an active servers\r\nconst activeServers = new Map();\r\n\r\n// Create express app\r\nconst app = express();\r\n\r\n/**\r\n * Starts HTTP or/and HTTPS server based on the provided configuration.\r\n * The `serverOptions` object contains all server related properties (see\r\n * the `server` section in the `lib/schemas/config.js` file for a reference).\r\n *\r\n * @async\r\n * @function startServer\r\n *\r\n * @param {Object} [serverOptions=getOptions().server] - Object containing\r\n * `server` options. The default value is the global server options\r\n * of the export server instance.\r\n *\r\n * @returns {Promise} A Promise that resolves to ending the function\r\n * execution when the server should not be enabled or when no valid Express app\r\n * is found.\r\n *\r\n * @throws {ExportError} Throws an `ExportError` if the server cannot\r\n * be configured and started.\r\n */\r\nexport async function startServer(serverOptions = getOptions().server) {\r\n try {\r\n // Stop if not enabled\r\n if (!serverOptions.enable || !app) {\r\n throw new ExportError(\r\n '[server] Server cannot be started (not enabled or no correct Express app found).',\r\n 500\r\n );\r\n }\r\n\r\n // Too big limits lead to timeouts in the export process when\r\n // the rasterization timeout is set too low\r\n const uploadLimitBytes = serverOptions.uploadLimit * 1024 * 1024;\r\n\r\n // Memory storage for multer package\r\n const storage = multer.memoryStorage();\r\n\r\n // Enable parsing of form data (files) with multer package\r\n const upload = multer({\r\n storage,\r\n limits: {\r\n fieldSize: uploadLimitBytes\r\n }\r\n });\r\n\r\n // Disable the X-Powered-By header\r\n app.disable('x-powered-by');\r\n\r\n // Enable CORS support\r\n app.use(\r\n cors({\r\n methods: ['POST', 'GET', 'OPTIONS']\r\n })\r\n );\r\n\r\n // Getting a lot of `RangeNotSatisfiableError` exceptions (even though this\r\n // is a deprecated options, let's try to set it to false)\r\n app.use((request, response, next) => {\r\n response.set('Accept-Ranges', 'none');\r\n next();\r\n });\r\n\r\n // Enable body parser for JSON data\r\n app.use(\r\n express.json({\r\n limit: uploadLimitBytes\r\n })\r\n );\r\n\r\n // Enable body parser for URL-encoded form data\r\n app.use(\r\n express.urlencoded({\r\n extended: true,\r\n limit: uploadLimitBytes\r\n })\r\n );\r\n\r\n // Use only non-file multipart form fields\r\n app.use(upload.none());\r\n\r\n // Set up static folder's route\r\n app.use(express.static(join(__dirname, 'public')));\r\n\r\n // Listen HTTP server\r\n if (!serverOptions.ssl.force) {\r\n // Main server instance (HTTP)\r\n const httpServer = http.createServer(app);\r\n\r\n // Attach error handlers and listen to the server\r\n _attachServerErrorHandlers(httpServer);\r\n\r\n // Listen\r\n httpServer.listen(serverOptions.port, serverOptions.host, () => {\r\n // Save the reference to HTTP server\r\n activeServers.set(serverOptions.port, httpServer);\r\n\r\n log(\r\n 3,\r\n `[server] Started HTTP server on ${serverOptions.host}:${serverOptions.port}.`\r\n );\r\n });\r\n }\r\n\r\n // Listen HTTPS server\r\n if (serverOptions.ssl.enable) {\r\n // Set up an SSL server also\r\n let key, cert;\r\n\r\n try {\r\n // Get the SSL key\r\n key = await readFile(\r\n join(getAbsolutePath(serverOptions.ssl.certPath), 'server.key'),\r\n 'utf8'\r\n );\r\n\r\n // Get the SSL certificate\r\n cert = await readFile(\r\n join(getAbsolutePath(serverOptions.ssl.certPath), 'server.crt'),\r\n 'utf8'\r\n );\r\n } catch (error) {\r\n log(\r\n 2,\r\n `[server] Unable to load key/certificate from the '${serverOptions.ssl.certPath}' path. Could not run secured layer server.`\r\n );\r\n }\r\n\r\n if (key && cert) {\r\n // Main server instance (HTTPS)\r\n const httpsServer = https.createServer({ key, cert }, app);\r\n\r\n // Attach error handlers and listen to the server\r\n _attachServerErrorHandlers(httpsServer);\r\n\r\n // Listen\r\n httpsServer.listen(serverOptions.ssl.port, serverOptions.host, () => {\r\n // Save the reference to HTTPS server\r\n activeServers.set(serverOptions.ssl.port, httpsServer);\r\n\r\n log(\r\n 3,\r\n `[server] Started HTTPS server on ${serverOptions.host}:${serverOptions.ssl.port}.`\r\n );\r\n });\r\n }\r\n }\r\n\r\n // Set up the rate limiter\r\n rateLimitingMiddleware(app, serverOptions.rateLimiting);\r\n\r\n // Set up the validation handler\r\n validationMiddleware(app);\r\n\r\n // Set up routes\r\n healthRoutes(app);\r\n exportRoutes(app);\r\n uiRoutes(app);\r\n versionChangeRoutes(app);\r\n\r\n // Set up the centralized error handler\r\n errorMiddleware(app);\r\n } catch (error) {\r\n throw new ExportError(\r\n '[server] Could not configure and start the server.',\r\n 500\r\n ).setError(error);\r\n }\r\n}\r\n\r\n/**\r\n * Closes all servers associated with Express app instance.\r\n *\r\n * @function closeServers\r\n */\r\nexport function closeServers() {\r\n // Check if there are servers working\r\n if (activeServers.size > 0) {\r\n log(4, `[server] Closing all servers.`);\r\n\r\n // Close each one of servers\r\n for (const [port, server] of activeServers) {\r\n server.close(() => {\r\n activeServers.delete(port);\r\n log(4, `[server] Closed server on port: ${port}.`);\r\n });\r\n }\r\n }\r\n}\r\n\r\n/**\r\n * Get all servers associated with Express app instance.\r\n *\r\n * @function getServers\r\n *\r\n * @returns {Array.} Servers associated with Express app instance.\r\n */\r\nexport function getServers() {\r\n return activeServers;\r\n}\r\n\r\n/**\r\n * Get the Express instance.\r\n *\r\n * @function getExpress\r\n *\r\n * @returns {Express} The Express instance.\r\n */\r\nexport function getExpress() {\r\n return express;\r\n}\r\n\r\n/**\r\n * Get the Express app instance.\r\n *\r\n * @function getApp\r\n *\r\n * @returns {Express} The Express app instance.\r\n */\r\nexport function getApp() {\r\n return app;\r\n}\r\n\r\n/**\r\n * Enable rate limiting for the server.\r\n *\r\n * @function enableRateLimiting\r\n *\r\n * @param {Object} rateLimitingOptions - Object containing `rateLimiting`\r\n * options.\r\n */\r\nexport function enableRateLimiting(rateLimitingOptions) {\r\n rateLimitingMiddleware(app, rateLimitingOptions);\r\n}\r\n\r\n/**\r\n * Apply middleware(s) to a specific path.\r\n *\r\n * @function use\r\n *\r\n * @param {string} path - The path to which the middleware(s) should be applied.\r\n * @param {...Function} middlewares - The middleware function(s) to be applied.\r\n */\r\nexport function use(path, ...middlewares) {\r\n app.use(path, ...middlewares);\r\n}\r\n\r\n/**\r\n * Set up a route with GET method and apply middleware(s).\r\n *\r\n * @function get\r\n *\r\n * @param {string} path - The path to which the middleware(s) should be applied.\r\n * @param {...Function} middlewares - The middleware function(s) to be applied.\r\n */\r\nexport function get(path, ...middlewares) {\r\n app.get(path, ...middlewares);\r\n}\r\n\r\n/**\r\n * Set up a route with POST method and apply middleware(s).\r\n *\r\n * @function post\r\n *\r\n * @param {string} path - The path to which the middleware(s) should be applied.\r\n * @param {...Function} middlewares - The middleware function(s) to be applied.\r\n */\r\nexport function post(path, ...middlewares) {\r\n app.post(path, ...middlewares);\r\n}\r\n\r\n/**\r\n * Attach error handlers to the server.\r\n *\r\n * @function _attachServerErrorHandlers\r\n *\r\n * @param {(http.Server|https.Server)} server - The HTTP/HTTPS server instance.\r\n */\r\nfunction _attachServerErrorHandlers(server) {\r\n server.on('clientError', (error, socket) => {\r\n logWithStack(\r\n 1,\r\n error,\r\n `[server] Client error: ${error.message}, destroying socket.`\r\n );\r\n socket.destroy();\r\n });\r\n\r\n server.on('error', (error) => {\r\n logWithStack(1, error, `[server] Server error: ${error.message}`);\r\n });\r\n\r\n server.on('connection', (socket) => {\r\n socket.on('error', (error) => {\r\n logWithStack(1, error, `[server] Socket error: ${error.message}`);\r\n });\r\n });\r\n}\r\n\r\nexport default {\r\n startServer,\r\n closeServers,\r\n getServers,\r\n getExpress,\r\n getApp,\r\n enableRateLimiting,\r\n use,\r\n get,\r\n post\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * @overview Handles graceful shutdown of the Highcharts Export Server, ensuring\r\n * proper cleanup of resources such as browser, pages, servers, and timers.\r\n */\r\n\r\nimport { killPool } from './pool.js';\r\nimport { clearAllTimers } from './timer.js';\r\nimport { closeServers } from './server/server.js';\r\n\r\n/**\r\n * Cleans up function to trigger before ending process for the graceful\r\n * shutdown.\r\n *\r\n * @function shutdownCleanUp\r\n *\r\n * @param {number} exitCode - An exit code for the `process.exit()` function.\r\n */\r\nexport async function shutdownCleanUp(exitCode) {\r\n // Await freeing all resources\r\n await Promise.allSettled([\r\n // Clear all ongoing intervals\r\n clearAllTimers(),\r\n\r\n // Get available server instances (HTTP/HTTPS) and close them\r\n closeServers(),\r\n\r\n // Close an active pool along with its workers and the browser instance\r\n killPool()\r\n ]);\r\n\r\n // Exit process with a correct code\r\n process.exit(exitCode);\r\n}\r\n\r\nexport default {\r\n shutdownCleanUp\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * @overview Core module for initializing and managing the Highcharts Export\r\n * Server. Provides functionalities for configuring exports, setting up server\r\n * operations, logging, scripts caching, resource pooling, and graceful process\r\n * cleanup.\r\n */\r\n\r\nimport 'colors';\r\n\r\nimport { checkAndUpdateCache } from './cache.js';\r\nimport {\r\n singleExport,\r\n batchExport,\r\n startExport,\r\n setAllowCodeExecution\r\n} from './chart.js';\r\nimport {\r\n getOptions,\r\n setOptions,\r\n mergeOptions,\r\n mapToNewOptions\r\n} from './config.js';\r\nimport {\r\n log,\r\n logWithStack,\r\n logZodIssues,\r\n initLogging,\r\n setLogLevel,\r\n enableConsoleLogging,\r\n enableFileLogging\r\n} from './logger.js';\r\nimport { initPool, killPool } from './pool.js';\r\nimport { shutdownCleanUp } from './resourceRelease.js';\r\nimport server, { startServer } from './server/server.js';\r\n\r\n/**\r\n * Initializes the export process. Tasks such as configuring logging, checking\r\n * the cache and sources, and initializing the resource pool occur during this\r\n * stage. This function must be called before attempting to export charts or set\r\n * up a server.\r\n *\r\n * @async\r\n * @function initExport\r\n *\r\n * @param {Object} customOptions - The `customOptions` object, which may\r\n * be a partial or complete set of options. If the provided options are partial,\r\n * missing values will be merged with the default general options, retrieved\r\n * using the `getOptions` function.\r\n */\r\nexport async function initExport(customOptions) {\r\n // Get the global options object copy and extend it with the incoming options\r\n const options = mergeOptions(getOptions(false), customOptions);\r\n\r\n // Set the `allowCodeExecution` per export module scope\r\n setAllowCodeExecution(options.customLogic.allowCodeExecution);\r\n\r\n // Init the logging\r\n initLogging(options.logging);\r\n\r\n // Attach process' exit listeners\r\n if (options.other.listenToProcessExits) {\r\n _attachProcessExitListeners();\r\n }\r\n\r\n // Check if cache needs to be updated\r\n await checkAndUpdateCache(options.highcharts, options.server.proxy);\r\n\r\n // Init the pool\r\n await initPool(options.pool, options.puppeteer.args);\r\n}\r\n\r\n/**\r\n * Attaches exit listeners to the process, ensuring proper cleanup of resources\r\n * and termination on exit signals. Handles 'exit', 'SIGINT', 'SIGTERM'\r\n * and 'uncaughtException' events.\r\n *\r\n * @function _attachProcessExitListeners\r\n */\r\nfunction _attachProcessExitListeners() {\r\n log(3, '[process] Attaching exit listeners to the process.');\r\n\r\n // Handler for the 'exit'\r\n process.on('exit', (code) => {\r\n log(4, `[process] Process exited with code ${code}.`);\r\n });\r\n\r\n // Handler for the 'SIGINT'\r\n process.on('SIGINT', async (name, code) => {\r\n log(4, `[process] The ${name} event with code: ${code}.`);\r\n await shutdownCleanUp(0);\r\n });\r\n\r\n // Handler for the 'SIGTERM'\r\n process.on('SIGTERM', async (name, code) => {\r\n log(4, `[process] The ${name} event with code: ${code}.`);\r\n await shutdownCleanUp(0);\r\n });\r\n\r\n // Handler for the 'SIGHUP'\r\n process.on('SIGHUP', async (name, code) => {\r\n log(4, `[process] The ${name} event with code: ${code}.`);\r\n await shutdownCleanUp(0);\r\n });\r\n\r\n // Handler for the 'uncaughtException'\r\n process.on('uncaughtException', async (error, name) => {\r\n logWithStack(1, error, `[process] The ${name} error.`);\r\n await shutdownCleanUp(1);\r\n });\r\n}\r\n\r\nexport default {\r\n // Server\r\n server,\r\n startServer,\r\n\r\n // Options\r\n getOptions,\r\n setOptions,\r\n mergeOptions,\r\n mapToNewOptions,\r\n\r\n // Exporting\r\n initExport,\r\n singleExport,\r\n batchExport,\r\n startExport,\r\n\r\n // Cache\r\n checkAndUpdateCache,\r\n\r\n // Pool\r\n initPool,\r\n killPool,\r\n\r\n // Logs\r\n log,\r\n logWithStack,\r\n logZodIssues,\r\n setLogLevel,\r\n enableConsoleLogging,\r\n enableFileLogging,\r\n\r\n // Utils\r\n shutdownCleanUp\r\n};\r\n"],"names":["__dirname","fileURLToPath","URL","url","deepCopy","objArr","objArrCopy","Array","isArray","key","Object","prototype","hasOwnProperty","call","fixConstr","constr","fixedConstr","toLowerCase","replace","includes","fixOutfile","type","outfile","getAbsolutePath","split","shift","fixType","mimeTypes","formats","values","outType","pop","find","t","path","isAbsolute","join","getBase64","input","Buffer","from","toString","getNewDate","Date","trim","getNewDateTime","getTime","isObject","item","isObjectEmpty","keys","length","isPrivateRangeUrlFound","some","pattern","test","measureTime","start","process","hrtime","bigint","Number","roundNumber","value","precision","multiplier","Math","pow","round","wrapAround","customCode","allowFileResources","isCallback","endsWith","readFileSync","startsWith","colors","logging","toConsole","toFile","pathCreated","pathToLog","levelsDesc","title","color","log","args","newLevel","texts","level","prefix","_logToFile","console","apply","undefined","concat","logWithStack","error","customMessage","mainMessage","message","stackMessage","stack","push","logZodIssues","issues","map","issue","initLogging","loggingOptions","dest","file","setLogLevel","enableConsoleLogging","enableFileLogging","existsSync","mkdirSync","appendFile","defaultConfig","puppeteer","types","envLink","cliName","description","promptOptions","separator","highcharts","version","cdnUrl","forceFetch","cachePath","coreScripts","instructions","moduleScripts","indicatorScripts","customScripts","export","infile","instr","options","svg","batch","hint","choices","b64","noDownload","height","width","scale","defaultHeight","defaultWidth","defaultScale","min","max","globalOptions","themeOptions","rasterizationTimeout","customLogic","allowCodeExecution","callback","resources","loadConfig","legacyName","createConfig","server","enable","host","port","uploadLimit","benchmarking","proxy","timeout","rateLimiting","maxRequests","window","delay","trustProxy","skipKey","skipToken","ssl","force","certPath","pool","minWorkers","maxWorkers","workLimit","acquireTimeout","createTimeout","destroyTimeout","idleTimeout","createRetryInterval","reaperInterval","ui","route","other","nodeEnv","listenToProcessExits","noLogo","hardResetPage","browserShellMode","debug","headless","devtools","listenToConsole","dumpio","slowMo","debuggingPort","nestedProps","_createNestedProps","absoluteProps","_createAbsoluteProps","config","propChain","forEach","entry","substring","dotenv","z","setErrorMap","_customErrorMap","v","boolean","strictCheck","union","enum","transform","nullable","string","refine","params","errorMessage","stringArray","filterCallback","arraySchema","array","stringSchema","slice","transformCallback","filter","positiveNum","number","positive","isNaN","nonNegativeNum","nonnegative","prefixes","chartConfig","indexOf","object","passthrough","additionalOptions","adminToken","gte","lte","this","objectSchema","js","css","files","partial","stringSchema1","stringSchema2","enableServer","serverBenchmarking","proxyHost","proxyPort","proxyTimeout","enableRateLimiting","enableSsl","sslForce","sslPort","sslCertPath","poolBenchmarking","resourcesInterval","logLevel","int","isInteger","logFile","logDest","logToConsole","logToFile","enableUi","uiRoute","enableDebug","requestId","uuid","PuppeteerSchema","HighchartsSchema","ExportSchema","CustomLogicSchema","ProxySchema","RateLimitingSchema","SslSchema","ServerSchema","optional","PoolSchema","LoggingSchema","UiSchema","OtherSchema","DebugSchema","StrictConfigSchema","LooseConfigSchema","EnvSchema","PUPPETEER_ARGS","HIGHCHARTS_VERSION","HIGHCHARTS_CDN_URL","HIGHCHARTS_FORCE_FETCH","HIGHCHARTS_CACHE_PATH","HIGHCHARTS_ADMIN_TOKEN","HIGHCHARTS_CORE_SCRIPTS","HIGHCHARTS_MODULE_SCRIPTS","HIGHCHARTS_INDICATOR_SCRIPTS","HIGHCHARTS_CUSTOM_SCRIPTS","EXPORT_INFILE","EXPORT_INSTR","EXPORT_OPTIONS","EXPORT_SVG","EXPORT_BATCH","EXPORT_OUTFILE","EXPORT_TYPE","EXPORT_CONSTR","EXPORT_B64","EXPORT_NO_DOWNLOAD","EXPORT_HEIGHT","EXPORT_WIDTH","EXPORT_SCALE","EXPORT_DEFAULT_HEIGHT","EXPORT_DEFAULT_WIDTH","EXPORT_DEFAULT_SCALE","EXPORT_GLOBAL_OPTIONS","EXPORT_THEME_OPTIONS","EXPORT_RASTERIZATION_TIMEOUT","CUSTOM_LOGIC_ALLOW_CODE_EXECUTION","CUSTOM_LOGIC_ALLOW_FILE_RESOURCES","CUSTOM_LOGIC_CUSTOM_CODE","CUSTOM_LOGIC_CALLBACK","CUSTOM_LOGIC_RESOURCES","CUSTOM_LOGIC_LOAD_CONFIG","CUSTOM_LOGIC_CREATE_CONFIG","SERVER_ENABLE","SERVER_HOST","SERVER_PORT","SERVER_UPLOAD_LIMIT","SERVER_BENCHMARKING","SERVER_PROXY_HOST","SERVER_PROXY_PORT","SERVER_PROXY_TIMEOUT","SERVER_RATE_LIMITING_ENABLE","SERVER_RATE_LIMITING_MAX_REQUESTS","SERVER_RATE_LIMITING_WINDOW","SERVER_RATE_LIMITING_DELAY","SERVER_RATE_LIMITING_TRUST_PROXY","SERVER_RATE_LIMITING_SKIP_KEY","SERVER_RATE_LIMITING_SKIP_TOKEN","SERVER_SSL_ENABLE","SERVER_SSL_FORCE","SERVER_SSL_PORT","SERVER_SSL_CERT_PATH","POOL_MIN_WORKERS","POOL_MAX_WORKERS","POOL_WORK_LIMIT","POOL_ACQUIRE_TIMEOUT","POOL_CREATE_TIMEOUT","POOL_DESTROY_TIMEOUT","POOL_IDLE_TIMEOUT","POOL_CREATE_RETRY_INTERVAL","POOL_REAPER_INTERVAL","POOL_BENCHMARKING","LOGGING_LEVEL","LOGGING_FILE","LOGGING_DEST","LOGGING_TO_CONSOLE","LOGGING_TO_FILE","UI_ENABLE","UI_ROUTE","OTHER_NODE_ENV","OTHER_LISTEN_TO_PROCESS_EXITS","OTHER_NO_LOGO","OTHER_HARD_RESET_PAGE","OTHER_BROWSER_SHELL_MODE","DEBUG_ENABLE","DEBUG_HEADLESS","DEBUG_DEVTOOLS","DEBUG_LISTEN_TO_CONSOLE","DEBUG_DUMPIO","DEBUG_SLOW_MO","DEBUG_DEBUGGING_PORT","envs","parse","env","strictValidate","configOptions","looseValidate","validateOption","name","option","context","propertyName","propertyInfo","code","ZodIssueCode","invalid_type","received","ZodParsedType","defaultError","custom","data","invalid_union","unionErrors","index","_initGlobalOptions","getOptions","getReference","setOptions","customOptions","cliArgs","modifyGlobal","cliOptions","_loadConfigFile","_pairArgumentValue","generalOptions","_updateOptions","mergeOptions","originalOptions","newOptions","entries","mapToNewOptions","oldOptions","propertiesChain","reduce","obj","prop","isAllowedConfig","allowFunctions","objectConfig","eval","JSON","stringifiedOptions","_optionsStringify","parsedOptions","_","configOpt","customOpt","cliOpt","configVal","customVal","cliVal","envVal","stringifyFunctions","stringify","replaceAll","Error","configIndex","findIndex","arg","configFileName","i","async","fetch","requestOptions","Promise","resolve","reject","_getProtocolModule","get","response","responseData","on","chunk","text","https","http","ExportError","constructor","statusCode","super","setError","cache","activeManifest","sources","hcVersion","checkAndUpdateCache","highchartsOptions","serverProxyOptions","fetchedModules","getCachePath","manifestPath","sourcePath","recursive","_updateCache","requestUpdate","manifest","modules","moduleMap","m","numberOfModules","moduleName","extractVersion","_saveConfigToManifest","getHighchartsVersion","updateHighchartsVersion","newVersion","cacheSources","extractModuleName","scriptPath","_fetchAndProcessScript","script","shouldThrowError","newManifest","writeFileSync","_fetchScripts","proxyAgent","HttpsProxyAgent","agent","allFetchPromises","all","c","setupHighcharts","Highcharts","animObject","duration","createChart","merge","wrap","setOptionsObj","isRenderComplete","Chart","proceed","userOptions","cb","exporting","enabled","plotOptions","series","label","tooltip","animation","onHighchartsRender","addEvent","Series","chart","Function","finalOptions","finalCallback","defaultOptions","template","browser","createBrowser","puppeteerArgs","enabledDebug","debugOptions","launchOptions","userDataDir","handleSIGINT","handleSIGTERM","handleSIGHUP","waitForInitialPage","defaultViewport","tryCount","open","launch","setTimeout","closeBrowser","connected","close","newPage","poolResource","page","setCacheEnabled","_setPageContent","_setPageEvents","isClosed","clearPage","hardReset","goto","waitUntil","evaluate","document","body","innerHTML","id","workCount","addPageResources","customLogicOptions","injectedResources","injectedJs","content","isLocal","jsResource","addScriptTag","injectedCss","cssImports","match","cssImportPath","cssResource","addStyleTag","clearPageResources","resource","dispose","oldCharts","charts","oldChart","destroy","scriptsToRemove","getElementsByTagName","stylesToRemove","linksToRemove","element","remove","setContent","cssTemplate","svgTemplate","puppeteerExport","exportOptions","isSVG","_setAsSvg","_setAsOptions","size","svgElement","querySelector","chartHeight","baseVal","chartWidth","style","zoom","margin","parseFloat","x","y","_getClipRegion","viewportHeight","abs","ceil","viewportWidth","result","setViewport","deviceScaleFactor","_createSVG","_createImage","_createPDF","$eval","getBoundingClientRect","trunc","outerHTML","clip","race","screenshot","encoding","fullPage","optimizeForSpeed","captureBeyondViewport","quality","omitBackground","_resolve","emulateMediaType","pdf","poolStats","exportsAttempted","exportsPerformed","exportsDropped","exportsFromSvg","exportsFromOptions","exportsFromSvgAttempts","exportsFromOptionsAttempts","timeSpent","timeSpentAverage","initPool","poolOptions","Pool","_factory","acquireTimeoutMillis","createTimeoutMillis","destroyTimeoutMillis","idleTimeoutMillis","createRetryIntervalMillis","reapIntervalMillis","propagateCreateError","clearStatus","_eventId","initialResources","acquire","promise","release","killPool","worker","used","destroyed","postWork","workerHandle","getPoolInfo","acquireCounter","_requestId","workStart","exportCounter","exportTime","getPoolStats","getPoolInfoJSON","numUsed","available","numFree","allCreated","pendingAcquires","numPendingAcquires","pendingCreates","numPendingCreates","pendingValidations","numPendingValidations","pendingDestroys","absoluteAll","create","random","startDate","validate","mainFrame","detached","removeAllListeners","sanitize","JSDOM","DOMPurify","ADD_TAGS","singleExport","startExport","batchExport","batchFunctions","pair","batchResults","allSettled","reason","endCallback","fileContent","_exportFromSvg","_exportFromOptions","getAllowCodeExecution","setAllowCodeExecution","inputToExport","_prepareExport","_handleCustomLogic","_handleGlobalAndTheme","_findChartSize","optionsChart","optionsExporting","globalOptionsChart","globalOptionsExporting","themeOptionsChart","themeOptionsExporting","sourceHeight","sourceWidth","param","_handleResources","allowedProps","handledResources","correctResources","propName","optionsName","timerIds","addTimer","clearAllTimers","clearInterval","clearTimeout","logErrorMiddleware","request","next","returnErrorMiddleware","status","json","errorMiddleware","app","use","rateLimitingMiddleware","rateLimitingOptions","msg","rateOptions","limiter","rateLimit","windowMs","delayMs","handler","format","send","default","skip","query","access_token","HttpError","setStatus","contentTypeMiddleware","contentType","headers","requestBodyMiddleware","connection","remoteAddress","validatedOptions","filename","validationMiddleware","post","reversedMime","png","jpeg","gif","requestExport","requestCounter","connectionAborted","socket","hadErrors","header","attachment","exportRoutes","serverStartTime","packageFile","successRates","recordInterval","windowSize","_calculateMovingAverage","a","b","_startSuccessRate","setInterval","stats","successRatio","healthRoutes","period","movingAverage","bootTime","uptime","floor","serverVersion","highchartsVersion","averageExportTime","attemptedExports","performedExports","failedExports","sucessRatio","toFixed","svgExports","jsonExports","svgExportsAttempts","jsonExportsAttempts","uiRoutes","sendFile","acceptRanges","versionChangeRoutes","token","activeServers","Map","express","startServer","serverOptions","uploadLimitBytes","storage","multer","memoryStorage","upload","limits","fieldSize","disable","cors","methods","set","limit","urlencoded","extended","none","static","httpServer","createServer","_attachServerErrorHandlers","listen","cert","readFile","httpsServer","closeServers","delete","getServers","getExpress","getApp","middlewares","shutdownCleanUp","exitCode","exit","initExport","_attachProcessExitListeners"],"mappings":"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AOP,GAAOpD,KAAK,KAAO,MAClC6D,IACKA,GAASpB,QAAQE,QAAUF,QAAQG,cACrCH,QAAQE,QAAS,EACjBF,QAAQG,aAAc,EACtBgB,aAAa,EAAGC,EAAO,yCACxB,GAGP,CC3PO,MAAMqB,cAAgB,CAC3BC,UAAW,CACTjC,KAAM,CACJvB,MAAO,CACL,mCACA,kBACA,0CACA,2BACA,kCACA,kCACA,wCACA,2CACA,qBACA,4BACA,2CACA,uDACA,6BACA,yBACA,0BACA,+BACA,uBACA,uFACA,yBACA,oCACA,oBACA,0BACA,8CACA,2BACA,0BACA,6BACA,mCACA,wCACA,mCACA,2BACA,kCACA,uBACA,iBACA,yBACA,8BACA,oBACA,2BACA,eACA,6BACA,iBACA,aACA,eACA,sBACA,cACA,yBACA,oBACA,uBAEFyD,MAAO,CAAC,YACRC,QAAS,iBACTC,QAAS,gBACTC,YAAa,+BACbC,cAAe,CACbvG,KAAM,OACNwG,UAAW,OAIjBC,WAAY,CACVC,QAAS,CACPhE,MAAO,SACPyD,MAAO,CAAC,UACRC,QAAS,qBACTE,YAAa,qBACbC,cAAe,CACbvG,KAAM,SAGV2G,OAAQ,CACNjE,MAAO,8BACPyD,MAAO,CAAC,UACRC,QAAS,qBACTE,YAAa,iCACbC,cAAe,CACbvG,KAAM,SAGV4G,WAAY,CACVlE,OAAO,EACPyD,MAAO,CAAC,WACRC,QAAS,yBACTE,YAAa,kDACbC,cAAe,CACbvG,KAAM,WAGV6G,UAAW,CACTnE,MAAO,SACPyD,MAAO,CAAC,UACRC,QAAS,wBACTE,YAAa,+CACbC,cAAe,CACbvG,KAAM,SAGV8G,YAAa,CACXpE,MAAO,CAAC,aAAc,kBAAmB,iBACzCyD,MAAO,CAAC,YACRC,QAAS,0BACTE,YAAa,mCACbC,cAAe,CACbvG,KAAM,cACN+G,aAAc,0DAGlBC,cAAe,CACbtE,MAAO,CACL,QACA,MACA,QACA,YACA,uBACA,gBAEA,eACA,QACA,OACA,aACA,mBACA,eACA,cACA,UACA,UACA,cACA,WACA,UACA,YACA,cACA,YACA,sBACA,SACA,SACA,WACA,aACA,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"} \ No newline at end of file From 9116fd9c4f7c71eefccd12e73aa29299ce28e4c6 Mon Sep 17 00:00:00 2001 From: PaulDalek Date: Tue, 21 Jan 2025 02:29:35 +0100 Subject: [PATCH 07/19] Added option to enable or disable validation of options. --- .env.sample | 1 + lib/schemas/config.js | 9 +++++++++ 2 files changed, 10 insertions(+) diff --git a/.env.sample b/.env.sample index 02b80816..35f24371 100644 --- a/.env.sample +++ b/.env.sample @@ -98,6 +98,7 @@ OTHER_LISTEN_TO_PROCESS_EXITS = true OTHER_NO_LOGO = false OTHER_HARD_RESET_PAGE = false OTHER_BROWSER_SHELL_MODE = true +OTHER_VALIDATION = true # DEBUG CONFIG DEBUG_ENABLE = false diff --git a/lib/schemas/config.js b/lib/schemas/config.js index 1c44f1b7..0a141b0e 100644 --- a/lib/schemas/config.js +++ b/lib/schemas/config.js @@ -919,6 +919,15 @@ export const defaultConfig = { promptOptions: { type: 'toggle' } + }, + validation: { + value: true, + types: ['boolean'], + envLink: 'OTHER_VALIDATION', + description: 'Whether or not to enable validation of options types', + promptOptions: { + type: 'toggle' + } } }, debug: { From ac2159472f608ca214d48c6205c07abef8dce37a Mon Sep 17 00:00:00 2001 From: PaulDalek Date: Tue, 21 Jan 2025 02:30:10 +0100 Subject: [PATCH 08/19] Updates of validators in the validation module. --- lib/validation.js | 451 +++++++++++++++++++++++----------------------- 1 file changed, 224 insertions(+), 227 deletions(-) diff --git a/lib/validation.js b/lib/validation.js index 3dc02fc2..02d2ec10 100644 --- a/lib/validation.js +++ b/lib/validation.js @@ -61,10 +61,10 @@ const v = { * validator. * * - When `strictCheck` is false, the schema will accept values are true, - * false, null, 'true', 'false', 'undefined', 'null', and ''. The strings - * 'undefined', 'null', and '' will be transformed to null, the string 'true' - * will be transformed to the boolean value true, and 'false' will - * be transformed to the boolean value false. + * false, null, 'true', '1', 'false', '0', 'undefined', 'null', and ''. + * The strings 'undefined', 'null', and '' will be transformed to null, + * the string 'true' will be transformed to the boolean value true, + * and 'false' will be transformed to the boolean value false. * * @function boolean * @@ -79,10 +79,10 @@ const v = { : z .union([ z - .enum(['true', 'false', 'undefined', 'null', '']) + .enum(['true', '1', 'false', '0', 'undefined', 'null', '']) .transform((value) => !['undefined', 'null', ''].includes(value) - ? value === 'true' + ? value === 'true' || value === '1' : null ), z.boolean() @@ -119,7 +119,7 @@ const v = { (value) => !['false', 'undefined', 'null', ''].includes(value), { params: { - errorMessage: `The string contains a forbidden value` + errorMessage: 'The string contains a forbidden value' } } ) @@ -254,7 +254,7 @@ const v = { ['undefined', 'null', ''].includes(value), { params: { - errorMessage: `The value must be numeric and positive` + errorMessage: 'The value must be numeric and positive' } } ) @@ -305,7 +305,7 @@ const v = { ['undefined', 'null', ''].includes(value), { params: { - errorMessage: `The value must be numeric and non-negative` + errorMessage: 'The value must be numeric and non-negative' } } ) @@ -399,13 +399,12 @@ const v = { .trim() .refine( (value) => - value.indexOf('= 0 || - value.indexOf('= 0 || (value.startsWith('{') && value.endsWith('}')) || ['undefined', 'null', ''].includes(value), { params: { - errorMessage: `The value must be a string that contains '= 5 && value.endsWith('.svg')), { params: { - errorMessage: `The value must be a string that ends with .json or .svg` + errorMessage: + 'The value must be a string that ends with .json or .svg' } } ) @@ -752,7 +753,8 @@ const config = { ['undefined', 'null', ''].includes(value), { params: { - errorMessage: `The value must be a string that ends with .json or .svg` + errorMessage: + 'The value must be a string that ends with .json or .svg' } } ) @@ -815,7 +817,8 @@ const config = { ['false', 'undefined', 'null', ''].includes(value), { params: { - errorMessage: `The value must be a string that contains '= 6 && value.endsWith('.json')), { params: { - errorMessage: `The value must be a string that starts with '{' and ends with '}` + errorMessage: + "The value must be a string that starts with '{' and ends with '}" } } ); @@ -1315,7 +1321,7 @@ const config = { ['undefined', 'null', ''].includes(value), { params: { - errorMessage: `The value must be a string that ends with '.json'` + errorMessage: 'The value must be a string that ends with .json' } } ) @@ -1351,7 +1357,7 @@ const config = { value === null || (value.length >= 6 && value.endsWith('.json')), { params: { - errorMessage: `The value must be a string that ends with .json ` + errorMessage: 'The value must be a string that ends with .json' } } ); @@ -2006,7 +2012,7 @@ const config = { value === null || (value.length >= 5 && value.endsWith('.log')), { params: { - errorMessage: `The value must be a string that ends with '.log'` + errorMessage: 'The value must be a string that ends with .log' } } ); @@ -2192,6 +2198,24 @@ const config = { return v.boolean(strictCheck); }, + /** + * The `validation` validator that returns a Zod schema with an optional + * stricter check based on the `strictCheck` parameter. + * + * The validation schema ensures the same work as the `boolean` validator. + * + * @function validation + * + * @param {boolean} strictCheck - Determines if stricter validation should + * be applied. + * + * @returns {z.ZodSchema} A Zod schema object for validating the `validation` + * option. + */ + validation(strictCheck) { + return v.boolean(strictCheck); + }, + /** * The `enableDebug` validator that returns a Zod schema with an optional * stricter check based on the `strictCheck` parameter. @@ -2336,13 +2360,10 @@ const config = { * option. */ requestId() { - return ( - z - .string() - /// TO DO: Correct - .uuid({ message: 'The value must be a stringified UUID' }) - .nullable() - ); + return z + .string() + .uuid({ message: 'The value must be a stringified UUID' }) + .nullable(); } }; @@ -2350,7 +2371,7 @@ const config = { const PuppeteerSchema = (strictCheck) => z .object({ - args: config.args(strictCheck) + args: validators.args(strictCheck) }) .partial(); @@ -2358,14 +2379,14 @@ const PuppeteerSchema = (strictCheck) => const HighchartsSchema = (strictCheck) => z .object({ - version: config.version(strictCheck), - cdnUrl: config.cdnUrl(strictCheck), - forceFetch: config.forceFetch(strictCheck), - cachePath: config.cachePath(strictCheck), - coreScripts: config.coreScripts(strictCheck), - moduleScripts: config.moduleScripts(strictCheck), - indicatorScripts: config.indicatorScripts(strictCheck), - customScripts: config.customScripts(strictCheck) + version: validators.version(strictCheck), + cdnUrl: validators.cdnUrl(strictCheck), + forceFetch: validators.forceFetch(strictCheck), + cachePath: validators.cachePath(strictCheck), + coreScripts: validators.coreScripts(strictCheck), + moduleScripts: validators.moduleScripts(strictCheck), + indicatorScripts: validators.indicatorScripts(strictCheck), + customScripts: validators.customScripts(strictCheck) }) .partial(); @@ -2373,25 +2394,25 @@ const HighchartsSchema = (strictCheck) => const ExportSchema = (strictCheck) => z .object({ - infile: config.infile(strictCheck), - instr: config.instr(), - options: config.options(), - svg: config.svg(), - outfile: config.outfile(strictCheck), - type: config.type(strictCheck), - constr: config.constr(strictCheck), - b64: config.b64(strictCheck), - noDownload: config.noDownload(strictCheck), - defaultHeight: config.defaultHeight(strictCheck), - defaultWidth: config.defaultWidth(strictCheck), - defaultScale: config.defaultScale(strictCheck), - height: config.height(strictCheck), - width: config.width(strictCheck), - scale: config.scale(strictCheck), - globalOptions: config.globalOptions(), - themeOptions: config.themeOptions(), - batch: config.batch(false), - rasterizationTimeout: config.rasterizationTimeout(strictCheck) + infile: validators.infile(strictCheck), + instr: validators.instr(), + options: validators.options(), + svg: validators.svg(), + outfile: validators.outfile(strictCheck), + type: validators.type(strictCheck), + constr: validators.constr(strictCheck), + b64: validators.b64(strictCheck), + noDownload: validators.noDownload(strictCheck), + defaultHeight: validators.defaultHeight(strictCheck), + defaultWidth: validators.defaultWidth(strictCheck), + defaultScale: validators.defaultScale(strictCheck), + height: validators.height(strictCheck), + width: validators.width(strictCheck), + scale: validators.scale(strictCheck), + globalOptions: validators.globalOptions(), + themeOptions: validators.themeOptions(), + batch: validators.batch(false), + rasterizationTimeout: validators.rasterizationTimeout(strictCheck) }) .partial(); @@ -2399,13 +2420,13 @@ const ExportSchema = (strictCheck) => const CustomLogicSchema = (strictCheck) => z .object({ - allowCodeExecution: config.allowCodeExecution(strictCheck), - allowFileResources: config.allowFileResources(strictCheck), - customCode: config.customCode(false), - callback: config.callback(false), - resources: config.resources(strictCheck), - loadConfig: config.loadConfig(false), - createConfig: config.createConfig(false) + allowCodeExecution: validators.allowCodeExecution(strictCheck), + allowFileResources: validators.allowFileResources(strictCheck), + customCode: validators.customCode(false), + callback: validators.callback(false), + resources: validators.resources(strictCheck), + loadConfig: validators.loadConfig(false), + createConfig: validators.createConfig(false) }) .partial(); @@ -2413,9 +2434,9 @@ const CustomLogicSchema = (strictCheck) => const ProxySchema = (strictCheck) => z .object({ - host: config.proxyHost(false), - port: config.proxyPort(strictCheck), - timeout: config.proxyTimeout(strictCheck) + host: validators.proxyHost(false), + port: validators.proxyPort(strictCheck), + timeout: validators.proxyTimeout(strictCheck) }) .partial(); @@ -2423,13 +2444,13 @@ const ProxySchema = (strictCheck) => const RateLimitingSchema = (strictCheck) => z .object({ - enable: config.enableRateLimiting(strictCheck), - maxRequests: config.maxRequests(strictCheck), - window: config.window(strictCheck), - delay: config.delay(strictCheck), - trustProxy: config.trustProxy(strictCheck), - skipKey: config.skipKey(false), - skipToken: config.skipToken(false) + enable: validators.enableRateLimiting(strictCheck), + maxRequests: validators.maxRequests(strictCheck), + window: validators.window(strictCheck), + delay: validators.delay(strictCheck), + trustProxy: validators.trustProxy(strictCheck), + skipKey: validators.skipKey(false), + skipToken: validators.skipToken(false) }) .partial(); @@ -2437,20 +2458,21 @@ const RateLimitingSchema = (strictCheck) => const SslSchema = (strictCheck) => z .object({ - enable: config.enableSsl(strictCheck), - force: config.sslForce(strictCheck), - port: config.sslPort(strictCheck), - certPath: config.sslCertPath(false) + enable: validators.enableSsl(strictCheck), + force: validators.sslForce(strictCheck), + port: validators.sslPort(strictCheck), + certPath: validators.sslCertPath(false) }) .partial(); // Schema for the server section of options const ServerSchema = (strictCheck) => z.object({ - enable: config.enableServer(strictCheck).optional(), - host: config.host(strictCheck).optional(), - port: config.port(strictCheck).optional(), - benchmarking: config.serverBenchmarking(strictCheck).optional(), + enable: validators.enableServer(strictCheck).optional(), + host: validators.host(strictCheck).optional(), + port: validators.port(strictCheck).optional(), + uploadLimit: validators.uploadLimit(strictCheck).optional(), + benchmarking: validators.serverBenchmarking(strictCheck).optional(), proxy: ProxySchema(strictCheck).optional(), rateLimiting: RateLimitingSchema(strictCheck).optional(), ssl: SslSchema(strictCheck).optional() @@ -2460,16 +2482,16 @@ const ServerSchema = (strictCheck) => const PoolSchema = (strictCheck) => z .object({ - minWorkers: config.minWorkers(strictCheck), - maxWorkers: config.maxWorkers(strictCheck), - workLimit: config.workLimit(strictCheck), - acquireTimeout: config.acquireTimeout(strictCheck), - createTimeout: config.createTimeout(strictCheck), - destroyTimeout: config.destroyTimeout(strictCheck), - idleTimeout: config.idleTimeout(strictCheck), - createRetryInterval: config.createRetryInterval(strictCheck), - reaperInterval: config.reaperInterval(strictCheck), - benchmarking: config.poolBenchmarking(strictCheck) + minWorkers: validators.minWorkers(strictCheck), + maxWorkers: validators.maxWorkers(strictCheck), + workLimit: validators.workLimit(strictCheck), + acquireTimeout: validators.acquireTimeout(strictCheck), + createTimeout: validators.createTimeout(strictCheck), + destroyTimeout: validators.destroyTimeout(strictCheck), + idleTimeout: validators.idleTimeout(strictCheck), + createRetryInterval: validators.createRetryInterval(strictCheck), + reaperInterval: validators.reaperInterval(strictCheck), + benchmarking: validators.poolBenchmarking(strictCheck) }) .partial(); @@ -2477,11 +2499,11 @@ const PoolSchema = (strictCheck) => const LoggingSchema = (strictCheck) => z .object({ - level: config.logLevel(strictCheck), - file: config.logFile(strictCheck), - dest: config.logDest(strictCheck), - toConsole: config.logToConsole(strictCheck), - toFile: config.logToFile(strictCheck) + level: validators.logLevel(strictCheck), + file: validators.logFile(strictCheck), + dest: validators.logDest(strictCheck), + toConsole: validators.logToConsole(strictCheck), + toFile: validators.logToFile(strictCheck) }) .partial(); @@ -2489,8 +2511,8 @@ const LoggingSchema = (strictCheck) => const UiSchema = (strictCheck) => z .object({ - enable: config.enableUi(strictCheck), - route: config.uiRoute(strictCheck) + enable: validators.enableUi(strictCheck), + route: validators.uiRoute(strictCheck) }) .partial(); @@ -2498,11 +2520,12 @@ const UiSchema = (strictCheck) => const OtherSchema = (strictCheck) => z .object({ - nodeEnv: config.nodeEnv(strictCheck), - listenToProcessExits: config.listenToProcessExits(strictCheck), - noLogo: config.noLogo(strictCheck), - hardResetPage: config.hardResetPage(strictCheck), - browserShellMode: config.browserShellMode(strictCheck) + nodeEnv: validators.nodeEnv(strictCheck), + listenToProcessExits: validators.listenToProcessExits(strictCheck), + noLogo: validators.noLogo(strictCheck), + hardResetPage: validators.hardResetPage(strictCheck), + browserShellMode: validators.browserShellMode(strictCheck), + validation: validators.validation(strictCheck) }) .partial(); @@ -2510,28 +2533,19 @@ const OtherSchema = (strictCheck) => const DebugSchema = (strictCheck) => z .object({ - enable: config.enableDebug(strictCheck), - headless: config.headless(strictCheck), - devtools: config.devtools(strictCheck), - listenToConsole: config.listenToConsole(strictCheck), - dumpio: config.dumpio(strictCheck), - slowMo: config.slowMo(strictCheck), - debuggingPort: config.debuggingPort(strictCheck) + enable: validators.enableDebug(strictCheck), + headless: validators.headless(strictCheck), + devtools: validators.devtools(strictCheck), + listenToConsole: validators.listenToConsole(strictCheck), + dumpio: validators.dumpio(strictCheck), + slowMo: validators.slowMo(strictCheck), + debuggingPort: validators.debuggingPort(strictCheck) }) .partial(); -//// -// // Schema for the payload section of options -// const PayloadSchema = () => -// z -// .object({ -// requestId: config.requestId() -// }) -// .partial(); -//// - // Strict schema for the config export const StrictConfigSchema = z.object({ + requestId: validators.requestId(), puppeteer: PuppeteerSchema(true), highcharts: HighchartsSchema(true), export: ExportSchema(true), @@ -2542,11 +2556,11 @@ export const StrictConfigSchema = z.object({ ui: UiSchema(true), other: OtherSchema(true), debug: DebugSchema(true) - //// payload: PayloadSchema() }); // Loose schema for the config export const LooseConfigSchema = z.object({ + requestId: validators.requestId(), puppeteer: PuppeteerSchema(false), highcharts: HighchartsSchema(false), export: ExportSchema(false), @@ -2557,120 +2571,120 @@ export const LooseConfigSchema = z.object({ ui: UiSchema(false), other: OtherSchema(false), debug: DebugSchema(false) - //// payload: PayloadSchema() }); // Schema for the environment variables config export const EnvSchema = z.object({ // puppeteer - PUPPETEER_ARGS: config.args(false), + PUPPETEER_ARGS: validators.args(false), // highcharts - HIGHCHARTS_VERSION: config.version(false), - HIGHCHARTS_CDN_URL: config.cdnUrl(false), - HIGHCHARTS_FORCE_FETCH: config.forceFetch(false), - HIGHCHARTS_CACHE_PATH: config.cachePath(false), - HIGHCHARTS_ADMIN_TOKEN: config.adminToken(false), - HIGHCHARTS_CORE_SCRIPTS: config.coreScripts(false), - HIGHCHARTS_MODULE_SCRIPTS: config.moduleScripts(false), - HIGHCHARTS_INDICATOR_SCRIPTS: config.indicatorScripts(false), - HIGHCHARTS_CUSTOM_SCRIPTS: config.customScripts(false), + HIGHCHARTS_VERSION: validators.version(false), + HIGHCHARTS_CDN_URL: validators.cdnUrl(false), + HIGHCHARTS_FORCE_FETCH: validators.forceFetch(false), + HIGHCHARTS_CACHE_PATH: validators.cachePath(false), + HIGHCHARTS_ADMIN_TOKEN: validators.adminToken(false), + HIGHCHARTS_CORE_SCRIPTS: validators.coreScripts(false), + HIGHCHARTS_MODULE_SCRIPTS: validators.moduleScripts(false), + HIGHCHARTS_INDICATOR_SCRIPTS: validators.indicatorScripts(false), + HIGHCHARTS_CUSTOM_SCRIPTS: validators.customScripts(false), // export - EXPORT_INFILE: config.infile(false), - EXPORT_INSTR: config.instr(), - EXPORT_OPTIONS: config.options(), - EXPORT_SVG: config.svg(), - EXPORT_BATCH: config.batch(false), - EXPORT_OUTFILE: config.outfile(false), - EXPORT_TYPE: config.type(false), - EXPORT_CONSTR: config.constr(false), - EXPORT_B64: config.b64(false), - EXPORT_NO_DOWNLOAD: config.noDownload(false), - EXPORT_HEIGHT: config.height(false), - EXPORT_WIDTH: config.width(false), - EXPORT_SCALE: config.scale(false), - EXPORT_DEFAULT_HEIGHT: config.defaultHeight(false), - EXPORT_DEFAULT_WIDTH: config.defaultWidth(false), - EXPORT_DEFAULT_SCALE: config.defaultScale(false), - EXPORT_GLOBAL_OPTIONS: config.globalOptions(), - EXPORT_THEME_OPTIONS: config.themeOptions(), - EXPORT_RASTERIZATION_TIMEOUT: config.rasterizationTimeout(false), + EXPORT_INFILE: validators.infile(false), + EXPORT_INSTR: validators.instr(), + EXPORT_OPTIONS: validators.options(), + EXPORT_SVG: validators.svg(), + EXPORT_BATCH: validators.batch(false), + EXPORT_OUTFILE: validators.outfile(false), + EXPORT_TYPE: validators.type(false), + EXPORT_CONSTR: validators.constr(false), + EXPORT_B64: validators.b64(false), + EXPORT_NO_DOWNLOAD: validators.noDownload(false), + EXPORT_HEIGHT: validators.height(false), + EXPORT_WIDTH: validators.width(false), + EXPORT_SCALE: validators.scale(false), + EXPORT_DEFAULT_HEIGHT: validators.defaultHeight(false), + EXPORT_DEFAULT_WIDTH: validators.defaultWidth(false), + EXPORT_DEFAULT_SCALE: validators.defaultScale(false), + EXPORT_GLOBAL_OPTIONS: validators.globalOptions(), + EXPORT_THEME_OPTIONS: validators.themeOptions(), + EXPORT_RASTERIZATION_TIMEOUT: validators.rasterizationTimeout(false), // custom - CUSTOM_LOGIC_ALLOW_CODE_EXECUTION: config.allowCodeExecution(false), - CUSTOM_LOGIC_ALLOW_FILE_RESOURCES: config.allowFileResources(false), - CUSTOM_LOGIC_CUSTOM_CODE: config.customCode(false), - CUSTOM_LOGIC_CALLBACK: config.callback(false), - CUSTOM_LOGIC_RESOURCES: config.resources(false), - CUSTOM_LOGIC_LOAD_CONFIG: config.loadConfig(false), - CUSTOM_LOGIC_CREATE_CONFIG: config.createConfig(false), + CUSTOM_LOGIC_ALLOW_CODE_EXECUTION: validators.allowCodeExecution(false), + CUSTOM_LOGIC_ALLOW_FILE_RESOURCES: validators.allowFileResources(false), + CUSTOM_LOGIC_CUSTOM_CODE: validators.customCode(false), + CUSTOM_LOGIC_CALLBACK: validators.callback(false), + CUSTOM_LOGIC_RESOURCES: validators.resources(false), + CUSTOM_LOGIC_LOAD_CONFIG: validators.loadConfig(false), + CUSTOM_LOGIC_CREATE_CONFIG: validators.createConfig(false), // server - SERVER_ENABLE: config.enableServer(false), - SERVER_HOST: config.host(false), - SERVER_PORT: config.port(false), - SERVER_UPLOAD_LIMIT: config.uploadLimit(false), - SERVER_BENCHMARKING: config.serverBenchmarking(false), + SERVER_ENABLE: validators.enableServer(false), + SERVER_HOST: validators.host(false), + SERVER_PORT: validators.port(false), + SERVER_UPLOAD_LIMIT: validators.uploadLimit(false), + SERVER_BENCHMARKING: validators.serverBenchmarking(false), // server proxy - SERVER_PROXY_HOST: config.proxyHost(false), - SERVER_PROXY_PORT: config.proxyPort(false), - SERVER_PROXY_TIMEOUT: config.proxyTimeout(false), + SERVER_PROXY_HOST: validators.proxyHost(false), + SERVER_PROXY_PORT: validators.proxyPort(false), + SERVER_PROXY_TIMEOUT: validators.proxyTimeout(false), // server rate limiting - SERVER_RATE_LIMITING_ENABLE: config.enableRateLimiting(false), - SERVER_RATE_LIMITING_MAX_REQUESTS: config.maxRequests(false), - SERVER_RATE_LIMITING_WINDOW: config.window(false), - SERVER_RATE_LIMITING_DELAY: config.delay(false), - SERVER_RATE_LIMITING_TRUST_PROXY: config.trustProxy(false), - SERVER_RATE_LIMITING_SKIP_KEY: config.skipKey(false), - SERVER_RATE_LIMITING_SKIP_TOKEN: config.skipToken(false), + SERVER_RATE_LIMITING_ENABLE: validators.enableRateLimiting(false), + SERVER_RATE_LIMITING_MAX_REQUESTS: validators.maxRequests(false), + SERVER_RATE_LIMITING_WINDOW: validators.window(false), + SERVER_RATE_LIMITING_DELAY: validators.delay(false), + SERVER_RATE_LIMITING_TRUST_PROXY: validators.trustProxy(false), + SERVER_RATE_LIMITING_SKIP_KEY: validators.skipKey(false), + SERVER_RATE_LIMITING_SKIP_TOKEN: validators.skipToken(false), // server ssl - SERVER_SSL_ENABLE: config.enableSsl(false), - SERVER_SSL_FORCE: config.sslForce(false), - SERVER_SSL_PORT: config.sslPort(false), - SERVER_SSL_CERT_PATH: config.sslCertPath(false), + SERVER_SSL_ENABLE: validators.enableSsl(false), + SERVER_SSL_FORCE: validators.sslForce(false), + SERVER_SSL_PORT: validators.sslPort(false), + SERVER_SSL_CERT_PATH: validators.sslCertPath(false), // pool - POOL_MIN_WORKERS: config.minWorkers(false), - POOL_MAX_WORKERS: config.maxWorkers(false), - POOL_WORK_LIMIT: config.workLimit(false), - POOL_ACQUIRE_TIMEOUT: config.acquireTimeout(false), - POOL_CREATE_TIMEOUT: config.createTimeout(false), - POOL_DESTROY_TIMEOUT: config.destroyTimeout(false), - POOL_IDLE_TIMEOUT: config.idleTimeout(false), - POOL_CREATE_RETRY_INTERVAL: config.createRetryInterval(false), - POOL_REAPER_INTERVAL: config.reaperInterval(false), - POOL_BENCHMARKING: config.poolBenchmarking(false), + POOL_MIN_WORKERS: validators.minWorkers(false), + POOL_MAX_WORKERS: validators.maxWorkers(false), + POOL_WORK_LIMIT: validators.workLimit(false), + POOL_ACQUIRE_TIMEOUT: validators.acquireTimeout(false), + POOL_CREATE_TIMEOUT: validators.createTimeout(false), + POOL_DESTROY_TIMEOUT: validators.destroyTimeout(false), + POOL_IDLE_TIMEOUT: validators.idleTimeout(false), + POOL_CREATE_RETRY_INTERVAL: validators.createRetryInterval(false), + POOL_REAPER_INTERVAL: validators.reaperInterval(false), + POOL_BENCHMARKING: validators.poolBenchmarking(false), // logging - LOGGING_LEVEL: config.logLevel(false), - LOGGING_FILE: config.logFile(false), - LOGGING_DEST: config.logDest(false), - LOGGING_TO_CONSOLE: config.logToConsole(false), - LOGGING_TO_FILE: config.logToFile(false), + LOGGING_LEVEL: validators.logLevel(false), + LOGGING_FILE: validators.logFile(false), + LOGGING_DEST: validators.logDest(false), + LOGGING_TO_CONSOLE: validators.logToConsole(false), + LOGGING_TO_FILE: validators.logToFile(false), // ui - UI_ENABLE: config.enableUi(false), - UI_ROUTE: config.uiRoute(false), + UI_ENABLE: validators.enableUi(false), + UI_ROUTE: validators.uiRoute(false), // other - OTHER_NODE_ENV: config.nodeEnv(false), - OTHER_LISTEN_TO_PROCESS_EXITS: config.listenToProcessExits(false), - OTHER_NO_LOGO: config.noLogo(false), - OTHER_HARD_RESET_PAGE: config.hardResetPage(false), - OTHER_BROWSER_SHELL_MODE: config.browserShellMode(false), + OTHER_NODE_ENV: validators.nodeEnv(false), + OTHER_LISTEN_TO_PROCESS_EXITS: validators.listenToProcessExits(false), + OTHER_NO_LOGO: validators.noLogo(false), + OTHER_HARD_RESET_PAGE: validators.hardResetPage(false), + OTHER_BROWSER_SHELL_MODE: validators.browserShellMode(false), + OTHER_VALIDATION: validators.validation(false), // debugger - DEBUG_ENABLE: config.enableDebug(false), - DEBUG_HEADLESS: config.headless(false), - DEBUG_DEVTOOLS: config.devtools(false), - DEBUG_LISTEN_TO_CONSOLE: config.listenToConsole(false), - DEBUG_DUMPIO: config.dumpio(false), - DEBUG_SLOW_MO: config.slowMo(false), - DEBUG_DEBUGGING_PORT: config.debuggingPort(false) + DEBUG_ENABLE: validators.enableDebug(false), + DEBUG_HEADLESS: validators.headless(false), + DEBUG_DEVTOOLS: validators.devtools(false), + DEBUG_LISTEN_TO_CONSOLE: validators.listenToConsole(false), + DEBUG_DUMPIO: validators.dumpio(false), + DEBUG_SLOW_MO: validators.slowMo(false), + DEBUG_DEBUGGING_PORT: validators.debuggingPort(false) }); /** @@ -2709,23 +2723,6 @@ export function looseValidate(configOptions) { return LooseConfigSchema.partial().parse(configOptions); } -/** - * Validates a provided option using the specific validator from the config - * object. - * - * @function validateOption - * - * @param {string} name - The name of an option to validate. - * @param {any} option - The option to validate. - * @param {boolean} strictCheck - Determines if stricter validation should - * be applied. - * - * @returns {any} The parsed and validated option value. - */ -export function validateOption(name, option, strictCheck) { - return config[name](strictCheck).parse(option); -} - /** * Custom error mapping function for Zod schema validation. * @@ -2813,11 +2810,11 @@ function _customErrorMap(issue, context) { } export default { + validators, StrictConfigSchema, LooseConfigSchema, EnvSchema, envs, strictValidate, - looseValidate, - validateOption + looseValidate }; From a38fabd3dc9d4bc9538420e1a4ee31880a1cc218 Mon Sep 17 00:00:00 2001 From: PaulDalek Date: Tue, 21 Jan 2025 02:30:19 +0100 Subject: [PATCH 09/19] Added two functions for validating data and some corrections. --- lib/config.js | 122 +++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 107 insertions(+), 15 deletions(-) diff --git a/lib/config.js b/lib/config.js index 198645d0..4014901a 100644 --- a/lib/config.js +++ b/lib/config.js @@ -25,9 +25,17 @@ import { join } from 'path'; import { log, logWithStack, logZodIssues } from './logger.js'; import { __dirname, isObject, deepCopy, getAbsolutePath } from './utils.js'; -import { envs, looseValidate, strictValidate } from './validation.js'; +import { + envs, + looseValidate, + strictValidate, + validators +} from './validation.js'; + import { defaultConfig, nestedProps, absoluteProps } from './schemas/config.js'; +import ExportError from './errors/ExportError.js'; + // Sets the global options with initial values from the default config const globalOptions = _initGlobalOptions(defaultConfig); @@ -85,36 +93,47 @@ export function setGlobalOptions(customOptions = {}, cliArgs = []) { let cliOptions = {}; // Only for the CLI usage - if (cliArgs.length) { + if (cliArgs && Array.isArray(cliArgs) && cliArgs.length) { try { // Validate options from the custom JSON loaded via the `loadConfig` - configOptions = strictValidate(_loadConfigFile(cliArgs)); + configOptions = strictValidate( + _loadConfigFile(cliArgs, globalOptions.customLogic) + ); } catch (error) { logZodIssues( 1, error.issues, - '[config] Custom JSON options validation error' + '[validation] Custom options from the `loadConfig` option validation error' ); } - } - // Apply custom options if there are any - if (customOptions && Object.keys(customOptions).length !== 0) { try { - // Validate custom options provided by the user - customOptions = strictValidate(customOptions); + // Validate options from the CLI + cliOptions = looseValidate(_pairArgumentValue(nestedProps, cliArgs)); } catch (error) { - logZodIssues(1, error.issues, '[config] Custom options validation error'); + logZodIssues( + 1, + error.issues, + '[validation] CLI options validation error' + ); } } - // Only for the CLI usage - if (cliArgs.length) { + // Apply custom options if there are any + if ( + customOptions && + isObject(customOptions) && + Object.keys(customOptions).length + ) { try { - // Validate options from the CLI - cliOptions = looseValidate(_pairArgumentValue(nestedProps, cliArgs)); + // Validate custom options provided by the user + customOptions = strictValidate(customOptions); } catch (error) { - logZodIssues(1, error.issues, '[config] CLI options validation error'); + logZodIssues( + 1, + error.issues, + '[validation] Custom options validation error' + ); } } @@ -241,6 +260,77 @@ export function mapToNewOptions(oldOptions) { return newOptions; } +/** + * Validates a specified option using the corresponding validator from the + * configuration object. Returns the original option if the validation + * is disabled globally. + * + * @function validateOption + * + * @param {string} name - The name of the option to validate. + * @param {any} configOption - The value of the option to validate. + * @param {boolean} [strictCheck=true] - Determines if stricter validation + * should be applied. The default value is `true`. + * + * @returns {any} The parsed and validated value of the option. + */ +export function validateOption(name, configOption, strictCheck = true) { + // Return the original option if the validation is disabled + if (!getOptions().other.validation) { + return configOption; + } + + try { + // Return validated option + return validators[name](strictCheck).parse(configOption); + } catch (error) { + // Log Zod issues + logZodIssues( + 1, + error.issues, + `[validation] The ${name} option validation error` + ); + + // Throw validation error + throw new ExportError( + `[validation] The ${name} option validation error`, + 400 + ); + } +} + +/** + * Validates the provided configuration options for the exporting process. + * Returns the original option if the validation is disabled globally. + * + * @function validateOptions + * + * @param {Object} configOptions - The configuration options to be validated. + * @param {boolean} [strictCheck=true] - Determines if stricter validation + * should be applied. The default value is `true`. + * + * @returns {Object} The parsed and validated configuration options object. + */ +export function validateOptions(configOptions, strictCheck = true) { + // Return the original config if the validation is disabled + if (!getOptions().other.validation) { + return configOptions; + } + + try { + // Return validated options + return strictCheck + ? strictValidate(configOptions) + : looseValidate(configOptions); + } catch (error) { + // Log Zod issues + logZodIssues(1, error.issues, '[validation] Options validation error'); + + // Throw validation error + throw new ExportError('[validation] Options validation error', 400); + } +} + /** * Validates, parses, and checks if the provided config is allowed set * of options. @@ -676,6 +766,8 @@ export default { updateOptions, mergeOptions, mapToNewOptions, + validateOption, + validateOptions, isAllowedConfig, printLicense, printUsage, From 579f9a6e78ae46c84b25c254fdd814e2cf517907 Mon Sep 17 00:00:00 2001 From: PaulDalek Date: Tue, 21 Jan 2025 02:31:04 +0100 Subject: [PATCH 10/19] Secured incoming data with the validation logic. --- lib/chart.js | 72 ++++++++++++----------- lib/index.js | 52 ++++++++++------- lib/prompt.js | 5 +- lib/server/middlewares/validation.js | 87 ++++++++++++---------------- lib/server/routes/versionChange.js | 13 +++++ lib/server/server.js | 22 ++++--- 6 files changed, 138 insertions(+), 113 deletions(-) diff --git a/lib/chart.js b/lib/chart.js index d4ad83ba..c1281d50 100644 --- a/lib/chart.js +++ b/lib/chart.js @@ -21,8 +21,14 @@ See LICENSE file in root for details. import { readFileSync, writeFileSync } from 'fs'; -import { getOptions, isAllowedConfig, mergeOptions } from './config.js'; -import { log, logWithStack, logZodIssues } from './logger.js'; +import { + getOptions, + isAllowedConfig, + mergeOptions, + validateOption, + validateOptions +} from './config.js'; +import { log, logWithStack } from './logger.js'; import { getPoolStats, killPool, postWork } from './pool.js'; import { sanitize } from './sanitize.js'; import { @@ -36,7 +42,6 @@ import { roundNumber, wrapAround } from './utils.js'; -import { strictValidate, validateOption } from './validation.js'; import ExportError from './errors/ExportError.js'; @@ -65,6 +70,9 @@ let allowCodeExecution = false; export async function singleExport(options) { // Check if the export makes sense if (options && options.export) { + // Validate single export options + options = validateOptions(options); + // Perform an export await startExport( { export: options.export, customLogic: options.customLogic }, @@ -134,6 +142,9 @@ export async function singleExport(options) { export async function batchExport(options) { // Check if the export makes sense if (options && options.export && options.export.batch) { + // Validate batch export options + options = validateOptions(options); + // An array for collecting batch exports const batchFunctions = []; @@ -292,29 +303,11 @@ export async function startExport(exportingOptions, endCallback) { // Check the file's extension if (exportOptions.infile.endsWith('.svg')) { - try { - // Set to the `svg` option - exportOptions.svg = validateOption('svg', fileContent, false); - } catch (error) { - logZodIssues( - 1, - error.issues, - '[config] The `svg` option validation error' - ); - throw error; - } + // Set to the `svg` option + exportOptions.svg = validateOption('svg', fileContent); } else if (exportOptions.infile.endsWith('.json')) { - try { - // Set to the `instr` option - exportOptions.instr = validateOption('instr', fileContent, false); - } catch (error) { - logZodIssues( - 1, - error.issues, - '[config] The `instr` option validation error' - ); - throw error; - } + // Set to the `instr` option + exportOptions.instr = validateOption('instr', fileContent); } else { throw new ExportError( '[chart] Incorrect value of the `infile` option.', @@ -531,14 +524,6 @@ async function _prepareExport(options) { ..._findChartSize(exportOptions) }; - // The last strict validation of options right before exporting process - try { - // Validate final options - options = strictValidate(options); - } catch (error) { - logZodIssues(1, error.issues, '[config] Final options validation error'); - } - // Post the work to the pool return postWork(options); } @@ -679,6 +664,12 @@ function _handleCustomLogic(customLogicOptions, allowCodeExecution) { customLogicOptions.customCode, customLogicOptions.allowFileResources ); + + // Validate the option + customLogicOptions.customCode = validateOption( + 'customCode', + customLogicOptions.customCode + ); } catch (error) { logWithStack(2, error, '[chart] The `customCode` cannot be loaded.'); @@ -694,6 +685,12 @@ function _handleCustomLogic(customLogicOptions, allowCodeExecution) { customLogicOptions.allowFileResources, true ); + + // Validate the option + customLogicOptions.callback = validateOption( + 'callback', + customLogicOptions.callback + ); } catch (error) { logWithStack(2, error, '[chart] The `callback` cannot be loaded.'); @@ -808,6 +805,9 @@ function _handleResources( } } + // Validate option + handledResources = validateOption('resources', handledResources); + // Return resources return handledResources; } @@ -860,6 +860,12 @@ function _handleGlobalAndTheme( allowCodeExecution ); } + + // Validate the option + exportOptions[optionsName] = validateOption( + optionsName, + exportOptions[optionsName] + ); } } catch (error) { logWithStack( diff --git a/lib/index.js b/lib/index.js index 2d90259d..3edeb8f4 100644 --- a/lib/index.js +++ b/lib/index.js @@ -32,7 +32,9 @@ import { getOptions, updateOptions, setGlobalOptions, - mapToNewOptions + mapToNewOptions, + validateOption, + validateOptions } from './config.js'; import { log, @@ -65,8 +67,8 @@ import server from './server/server.js'; * is an empty object. */ export async function initExport(initOptions = {}) { - // Init and update the instance options object - const options = updateOptions(initOptions, true); + // Init, validate and update the instance options object + const options = updateOptions(validateOptions(initOptions), true); // Set the `allowCodeExecution` per export module scope setAllowCodeExecution(options.customLogic.allowCodeExecution); @@ -135,6 +137,10 @@ export default { setGlobalOptions, mapToNewOptions, + // Validation + validateOption, + validateOptions, + // Exporting initExport, singleExport, @@ -151,35 +157,41 @@ export default { logZodIssues, setLogLevel: function (level) { // Update the instance options object - const options = updateOptions({ - logging: { - level - } - }); + const options = updateOptions( + validateOptions({ + logging: { + level + } + }) + ); // Call the function setLogLevel(options.logging.level); }, enableConsoleLogging: function (toConsole) { // Update the instance options object - const options = updateOptions({ - logging: { - toConsole - } - }); + const options = updateOptions( + validateOptions({ + logging: { + toConsole + } + }) + ); // Call the function enableConsoleLogging(options.logging.toConsole); }, enableFileLogging: function (dest, file, toFile) { // Update the instance options object - const options = updateOptions({ - logging: { - dest, - file, - toFile - } - }); + const options = updateOptions( + validateOptions({ + logging: { + dest, + file, + toFile + } + }) + ); // Call the function enableFileLogging( diff --git a/lib/prompt.js b/lib/prompt.js index d4ac3f6b..9f073129 100644 --- a/lib/prompt.js +++ b/lib/prompt.js @@ -23,7 +23,7 @@ import { writeFile } from 'fs/promises'; import prompts from 'prompts'; -import { isAllowedConfig } from './config.js'; +import { isAllowedConfig, validateOptions } from './config.js'; import { log, logWithStack } from './logger.js'; import { getAbsolutePath } from './utils.js'; @@ -166,6 +166,9 @@ export async function manualConfig(configFileName, allowCodeExecution) { // If all questions have been answered, save the updated config if (++questionsCounter === allQuestions.length) { try { + // Validate the prompt result + configFile = validateOptions(configFile); + // Save the prompt result await writeFile( getAbsolutePath(configFileName), diff --git a/lib/server/middlewares/validation.js b/lib/server/middlewares/validation.js index d39224ee..4af2496e 100644 --- a/lib/server/middlewares/validation.js +++ b/lib/server/middlewares/validation.js @@ -26,7 +26,7 @@ See LICENSE file in root for details. import { v4 as uuid } from 'uuid'; import { getAllowCodeExecution } from '../../chart.js'; -import { isAllowedConfig } from '../../config.js'; +import { isAllowedConfig, validateOptions } from '../../config.js'; import { log, logZodIssues } from '../../logger.js'; import { fixConstr, @@ -152,55 +152,42 @@ function requestBodyMiddleware(request, response, next) { ); } - try { - // Validate options from the body and store parsed structure in the request - request.validatedOptions = looseValidate({ - // Set the created ID as a `_requestId` property in the validated options - _requestId: requestId, - export: { - instr, - svg: body.svg, - outfile: - body.outfile || - `${request.params.filename || 'chart'}.${fixType(body.type)}`, - type: fixType(body.type, body.outfile), - constr: fixConstr(body.constr), - b64: body.b64, - noDownload: body.noDownload, - height: body.height, - width: body.width, - scale: body.scale, - globalOptions: isAllowedConfig( - body.globalOptions, - true, - allowCodeExecution - ), - themeOptions: isAllowedConfig( - body.themeOptions, - true, - allowCodeExecution - ) - }, - customLogic: { - allowCodeExecution, - allowFileResources: false, - customCode: body.customCode, - callback: body.callback, - resources: isAllowedConfig(body.resources, true, allowCodeExecution) - } - }); - } catch (error) { - logZodIssues( - 1, - error.issues, - '[config] Request options validation error' - ); - - throw new ExportError( - 'The provided options are not correct. Please check if your data is of the correct types.', - 400 - ); - } + // Validate the request options and store parsed structure in the request + request.validatedOptions = validateOptions({ + // Set the created ID as a `requestId` property in the options + requestId, + export: { + instr, + svg: body.svg, + outfile: + body.outfile || + `${request.params.filename || 'chart'}.${body.type || 'png'}`, + type: body.type, + constr: body.constr, + b64: body.b64, + noDownload: body.noDownload, + height: body.height, + width: body.width, + scale: body.scale, + globalOptions: isAllowedConfig( + body.globalOptions, + true, + allowCodeExecution + ), + themeOptions: isAllowedConfig( + body.themeOptions, + true, + allowCodeExecution + ) + }, + customLogic: { + allowCodeExecution, + allowFileResources: false, + customCode: body.customCode, + callback: body.callback, + resources: isAllowedConfig(body.resources, true, allowCodeExecution) + } + }); // Call the next middleware return next(); diff --git a/lib/server/routes/versionChange.js b/lib/server/routes/versionChange.js index ad49c2c0..f8512576 100644 --- a/lib/server/routes/versionChange.js +++ b/lib/server/routes/versionChange.js @@ -18,6 +18,7 @@ See LICENSE file in root for details. */ import { updateHighchartsVersion, getHighchartsVersion } from '../../cache.js'; +import { validateOption } from '../../config.js'; import { log } from '../../logger.js'; import { envs } from '../../validation.js'; @@ -63,6 +64,18 @@ export default function versionChangeRoutes(app) { // Compare versions let newVersion = request.params.newVersion; + + // Validate the version + try { + newVersion = validateOption('version', request.params.newVersion); + } catch (error) { + throw new ExportError( + `[version] Version is incorrect: ${error.message}`, + 400 + ).setError(error); + } + + // When a correct value found if (newVersion) { try { // Update version diff --git a/lib/server/server.js b/lib/server/server.js index ba744174..2e8bf81c 100644 --- a/lib/server/server.js +++ b/lib/server/server.js @@ -30,7 +30,7 @@ import http from 'http'; import https from 'https'; import multer from 'multer'; -import { updateOptions } from '../config.js'; +import { updateOptions, validateOptions } from '../config.js'; import { log, logWithStack } from '../logger.js'; import { __dirname, getAbsolutePath } from '../utils.js'; @@ -74,9 +74,11 @@ const app = express(); export async function startServer(serverOptions) { try { // Update the instance options object - const options = updateOptions({ - server: serverOptions - }); + const options = updateOptions( + validateOptions({ + server: serverOptions + }) + ); // Use validated options serverOptions = options.server; @@ -293,11 +295,13 @@ export function getApp() { */ export function enableRateLimiting(rateLimitingOptions) { // Update the instance options object - const options = updateOptions({ - server: { - rateLimiting: rateLimitingOptions - } - }); + const options = updateOptions( + validateOptions({ + server: { + rateLimiting: rateLimitingOptions + } + }) + ); // Set the rate limiting options rateLimitingMiddleware(app, options.server.rateLimitingOptions); From 45cac8486e5922c21a138351a8bc9738f234128d Mon Sep 17 00:00:00 2001 From: PaulDalek Date: Tue, 21 Jan 2025 02:31:18 +0100 Subject: [PATCH 11/19] The logZodIssues function small modifications. --- lib/logger.js | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/lib/logger.js b/lib/logger.js index 0bc5e748..2833aa2d 100644 --- a/lib/logger.js +++ b/lib/logger.js @@ -160,23 +160,23 @@ export function logWithStack(newLevel, error, customMessage) { } /** - * Logs an error message about Zod issues with the validation. Optionally, - * a custom message can be provided. + * Logs an error message related to Zod validation issues. Optionally, a custom + * message can be provided. * * @function logZodIssues * * @param {number} newLevel - The log level. - * @param {Error[]} issues - The array of Zod issues. - * @param {string} customMessage - An optional custom message to be logged - * along with the error. + * @param {Error[]} issues - An array of Zod validation issues. + * @param {string} customMessage - An optional custom message to be included + * in the log alongside the error. */ -export function logZodIssues(newLevel, issues = [], customMessage) { +export function logZodIssues(newLevel, issues, customMessage) { logWithStack( newLevel, null, [ - `${customMessage} - the following Zod issues occured:`, - ...issues.map((issue) => `- ${issue.message}`) + `${customMessage || '[validation] Validation error'} - the following Zod issues occured:`, + ...(issues || []).map((issue) => `- ${issue.message}`) ].join('\n') ); } From ac9cfb8b989ab9784012d7825b5b4fa88e1b5cdc Mon Sep 17 00:00:00 2001 From: PaulDalek Date: Tue, 21 Jan 2025 02:31:31 +0100 Subject: [PATCH 12/19] Added tests for the validation and requestId parameters. --- tests/unit/validation/cli.test.js | 26 +++++++------------- tests/unit/validation/config.test.js | 26 +++++++------------- tests/unit/validation/envs.test.js | 3 +++ tests/unit/validation/shared.js | 36 +++++++++++----------------- 4 files changed, 33 insertions(+), 58 deletions(-) diff --git a/tests/unit/validation/cli.test.js b/tests/unit/validation/cli.test.js index e69a1a03..ad92238c 100644 --- a/tests/unit/validation/cli.test.js +++ b/tests/unit/validation/cli.test.js @@ -21,6 +21,9 @@ describe('CLI options should be correctly parsed and validated', () => { // Return config tests with a specific schema and strictCheck flag injected const tests = configTests(LooseConfigSchema.partial(), false); + // requestId + tests.requestId('requestId'); + // puppeteer tests.puppeteer('puppeteer', { args: [ @@ -253,7 +256,8 @@ describe('CLI options should be correctly parsed and validated', () => { listenToProcessExits: true, noLogo: false, hardResetPage: false, - browserShellMode: true + browserShellMode: true, + validation: true }); // debug @@ -266,13 +270,6 @@ describe('CLI options should be correctly parsed and validated', () => { slowMo: 0, debuggingPort: 9222 }); - - //// - // // payload - // tests.payload('payload', { - // requestId: 'd4faa416-0e85-433a-9f84-e735567d8fa5' - // }); - //// }); describe('Puppeteer configuration options should be correctly parsed and validated', () => { @@ -632,6 +629,9 @@ describe('Other configuration options should be correctly parsed and validated', // other.browserShellMode tests.otherBrowserShellMode('browserShellMode'); + + // other.validation + tests.otherValidation('validation'); }); describe('Debug configuration options should be correctly parsed and validated', () => { @@ -659,13 +659,3 @@ describe('Debug configuration options should be correctly parsed and validated', // debug.debuggingPort tests.debugDebuggingPort('debuggingPort'); }); - -//// -// describe('Payload configuration options should be correctly parsed and validated', () => { -// // Return config tests with a specific schema and strictCheck flag injected -// const tests = configTests(LooseConfigSchema.shape.payload, false); - -// // payload.requestId -// tests.payloadRequestId('requestId'); -// }); -//// diff --git a/tests/unit/validation/config.test.js b/tests/unit/validation/config.test.js index 7f0a6531..3d360d90 100644 --- a/tests/unit/validation/config.test.js +++ b/tests/unit/validation/config.test.js @@ -21,6 +21,9 @@ describe('Configuration options should be correctly parsed and validated', () => // Return config tests with a specific schema and strictCheck flag injected const tests = configTests(StrictConfigSchema.partial(), true); + // requestId + tests.requestId('requestId'); + // puppeteer tests.puppeteer('puppeteer', { args: [ @@ -253,7 +256,8 @@ describe('Configuration options should be correctly parsed and validated', () => listenToProcessExits: true, noLogo: false, hardResetPage: false, - browserShellMode: true + browserShellMode: true, + validation: true }); // debug @@ -266,13 +270,6 @@ describe('Configuration options should be correctly parsed and validated', () => slowMo: 0, debuggingPort: 9222 }); - - //// - // // payload - // tests.payload('payload', { - // requestId: 'd4faa416-0e85-433a-9f84-e735567d8fa5' - // }); - //// }); describe('Puppeteer configuration options should be correctly parsed and validated', () => { @@ -643,6 +640,9 @@ describe('Other configuration options should be correctly parsed and validated', // other.browserShellMode tests.otherBrowserShellMode('browserShellMode'); + + // other.validation + tests.otherValidation('validation'); }); describe('Debug configuration options should be correctly parsed and validated', () => { @@ -670,13 +670,3 @@ describe('Debug configuration options should be correctly parsed and validated', // debug.debuggingPort tests.debugDebuggingPort('debuggingPort'); }); - -//// -// describe('Payload configuration options should be correctly parsed and validated', () => { -// // Return config tests with a specific schema and strictCheck flag injected -// const tests = configTests(StrictConfigSchema.shape.payload, true); - -// // payload.requestId -// tests.payloadRequestId('requestId'); -// }); -//// diff --git a/tests/unit/validation/envs.test.js b/tests/unit/validation/envs.test.js index 1be06f7c..7e5cd8dc 100644 --- a/tests/unit/validation/envs.test.js +++ b/tests/unit/validation/envs.test.js @@ -315,6 +315,9 @@ describe('OTHER environment variables should be correctly parsed and validated', // OTHER_BROWSER_SHELL_MODE tests.otherBrowserShellMode('OTHER_BROWSER_SHELL_MODE'); + + // OTHER_VALIDATION + tests.otherValidation('OTHER_VALIDATION'); }); describe('DEBUG environment variables should be correctly parsed and validated', () => { diff --git a/tests/unit/validation/shared.js b/tests/unit/validation/shared.js index 593d5b63..4edc16ab 100644 --- a/tests/unit/validation/shared.js +++ b/tests/unit/validation/shared.js @@ -214,6 +214,13 @@ export function configTests(schema, strictCheck) { expect(schema.parse(obj)[property]).toBe(false); }); + it('should accept a stringified 0 and 1 values and transform them to a boolean', () => { + const obj = { [property]: '1' }; + expect(schema.parse(obj)[property]).toBe(true); + obj[property] = '0'; + expect(schema.parse(obj)[property]).toBe(false); + }); + it('should accept null', () => { acceptNull(property); }); @@ -234,6 +241,7 @@ export function configTests(schema, strictCheck) { validatePropOfSchema(schema, property, [ 'emptyString', 'stringBoolean', + 'stringNumber', 'stringUndefined', 'stringNull', 'boolean', @@ -1057,20 +1065,6 @@ export function configTests(schema, strictCheck) { expect(schema.parse(obj)[property]).toBe('{ a: "1", b: { c: 3 } }'); }); - it('should accept a string value that starts with the { - const obj = { - [property]: "..." - }; - expect(schema.parse(obj)[property]).toBe( - "..." - ); - obj[property] = - '...'; - expect(schema.parse(obj)[property]).toBe( - '...' - ); - }); - it('should not accept any array values', () => { const obj = { [property]: [] }; expect(() => schema.parse(obj)).toThrow(); @@ -2241,6 +2235,9 @@ export function configTests(schema, strictCheck) { // The options config validation tests return { + requestId: (property) => { + describe(property, () => validationTests.requestId(property)); + }, puppeteer: (property, value) => { describe(property, () => validationTests.configObject(property, value)); }, @@ -2531,6 +2528,9 @@ export function configTests(schema, strictCheck) { otherBrowserShellMode: (property) => { describe(property, () => validationTests.boolean(property)); }, + otherValidation: (property) => { + describe(property, () => validationTests.boolean(property)); + }, debug: (property, value) => { describe(property, () => validationTests.configObject(property, value)); }, @@ -2555,13 +2555,5 @@ export function configTests(schema, strictCheck) { debugDebuggingPort: (property) => { describe(property, () => validationTests.nonNegativeNum(property)); } - //// - // payload: (property, value) => { - // describe(property, () => validationTests.configObject(property, value)); - // }, - // payloadRequestId: (property) => { - // describe(property, () => validationTests.requestId(property)); - // } - //// }; } From b564f2cc6f0a0cef44c44523fa8eeb2facce32ae Mon Sep 17 00:00:00 2001 From: PaulDalek Date: Tue, 21 Jan 2025 02:31:39 +0100 Subject: [PATCH 13/19] Updated README with the new info about validation option and new validating API functions. --- README.md | 26 ++++++++++++++++++++++---- 1 file changed, 22 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 06375eec..319fc06f 100644 --- a/README.md +++ b/README.md @@ -270,7 +270,8 @@ _Available default JSON config:_ "listenToProcessExits": true, "noLogo": false, "hardResetPage": false, - "browserShellMode": true + "browserShellMode": true, + "validation": true }, "debug": { "enable": false, @@ -406,6 +407,7 @@ _Available environment variables:_ - `OTHER_NO_LOGO`: Skip printing the logo on a startup. Will be replaced by a simple text (defaults to `false`). - `OTHER_HARD_RESET_PAGE`: Determines whether the page's content should be reset from scratch, including Highcharts scripts (defaults to `false`). - `OTHER_BROWSER_SHELL_MODE`: Decides whether to enable older but much more performant _shell_ mode for the browser (defaults to `true`). +- `OTHER_VALIDATION`: Decides whether or not to enable validation of options types (defaults to `true`). ### Debugging Config @@ -537,6 +539,7 @@ _Available CLI arguments:_ - `--noLogo`: Skip printing the logo on a startup. Will be replaced by a simple text (defaults to `false`). - `--hardResetPage`: Determines whether the page's content should be reset from scratch, including Highcharts scripts (defaults to `false`). - `--browserShellMode`: Decides whether to enable older but much more performant _shell_ mode for the browser (defaults to `true`). +- `--validation`: Decides whether or not to enable validation of options types (defaults to `true`). ### Debugging Config @@ -776,6 +779,21 @@ This package supports both CommonJS and ES modules. - `@returns {Object}` A new object containing options structured according to the mapping defined in `nestedProps` or an empty object if the provided `oldOptions` is not a correct object. +- `function validateOption(name, configOption, strictCheck = true)`: Validates a specified option using the corresponding validator from the configuration object. Returns the original option if the validation is disabled globally. + + - `@param {string} name` - The name of the option to validate. + - `@param {any} configOption` - The value of the option to validate. + - `@param {boolean} [strictCheck=true]` - Determines if stricter validation should be applied. The default value is `true`. + + - `@returns {any}` The parsed and validated value of the option. + +- `function validateOptions(configOptions, strictCheck = true)`: Validates the provided configuration options for the exporting process. Returns the original option if the validation is disabled globally. + + - `@param {Object} configOptions` - The configuration options to be validated. + - `@param {boolean} [strictCheck=true]` - Determines if stricter validation should be applied. The default value is `true`. + + - `@returns {Object}` The parsed and validated configuration options object. + - `async function initExport(initOptions = {})`: Initializes the export process. Tasks such as configuring logging, checking the cache and sources, and initializing the resource pool occur during this stage. This function must be called before attempting to export charts or set up a server. @@ -831,11 +849,11 @@ This package supports both CommonJS and ES modules. - `@returns {void}` Exits the function execution if attempting to log at a level higher than allowed. -- `function logZodIssues(newLevel, issues = [], customMessage)`: Logs an error message about Zod issues with the validation. Optionally, a custom message can be provided. +- `function logZodIssues(newLevel, issues, customMessage)`: Logs an error message related to Zod validation issues. Optionally, a custom message can be provided. - `@param {number} newLevel` - The log level. - - `@param {Error[]} issues` - The array of Zod issues. - - `@param {string} customMessage` - An optional custom message to be logged along with the error. + - `@param {Error[]} issues` - An array of Zod validation issues. + - `@param {string} customMessage` - An optional custom message to be included in the log alongside the error. - `function setLogLevel(level)`: Sets the log level to the specified value. Log levels are (`0` = no logging, `1` = error, `2` = warning, `3` = notice, `4` = verbose, or `5` = benchmark). From 67e8093c35b065dc55bb62690ac0b35303e033fd Mon Sep 17 00:00:00 2001 From: PaulDalek Date: Tue, 21 Jan 2025 02:32:09 +0100 Subject: [PATCH 14/19] Built scripts. --- dist/index.cjs | 4 ++-- dist/index.esm.js | 2 +- dist/index.esm.js.map | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/dist/index.cjs b/dist/index.cjs index d82b30a2..3bc873ff 100644 --- a/dist/index.cjs +++ b/dist/index.cjs @@ -1,2 +1,2 @@ -"use strict";Object.defineProperty(exports,"__esModule",{value:!0}),require("colors");var fs=require("fs"),path=require("path"),httpsProxyAgent=require("https-proxy-agent"),url=require("url"),dotenv=require("dotenv"),zod=require("zod"),http=require("http"),https=require("https"),tarn=require("tarn"),uuid=require("uuid"),puppeteer=require("puppeteer"),DOMPurify=require("dompurify"),jsdom=require("jsdom"),promises=require("fs/promises"),cors=require("cors"),express=require("express"),multer=require("multer"),rateLimit=require("express-rate-limit"),_documentCurrentScript="undefined"!=typeof document?document.currentScript:null;const __dirname$1=url.fileURLToPath(new URL("../.","undefined"==typeof document?require("url").pathToFileURL(__filename).href:_documentCurrentScript&&"SCRIPT"===_documentCurrentScript.tagName.toUpperCase()&&_documentCurrentScript.src||new URL("index.cjs",document.baseURI).href));function deepCopy(e){if(null===e||"object"!=typeof e)return e;const t=Array.isArray(e)?[]:{};for(const o in e)Object.prototype.hasOwnProperty.call(e,o)&&(t[o]=deepCopy(e[o]));return t}function fixConstr(e){try{const t=`${e.toLowerCase().replace("chart","")}Chart`;return"Chart"===t&&t.toLowerCase(),["chart","stockChart","mapChart","ganttChart"].includes(t)?t:"chart"}catch{return"chart"}}function fixOutfile(e,t){return`${getAbsolutePath(t||"chart").split(".").shift()}.${e}`}function fixType(e,t=null){const o={"image/png":"png","image/jpeg":"jpeg","application/pdf":"pdf","image/svg+xml":"svg"},n=Object.values(o);if(t){const o=t.split(".").pop();"jpg"===o?e="jpeg":n.includes(o)&&e!==o&&(e=o)}return o[e]||n.find((t=>t===e))||"png"}function getAbsolutePath(e){return path.isAbsolute(e)?e:path.join(__dirname$1,e)}function getBase64(e,t){return"pdf"===t||"svg"==t?Buffer.from(e,"utf8").toString("base64"):e}function getNewDate(){return(new Date).toString().split("(")[0].trim()}function getNewDateTime(){return(new Date).getTime()}function isObject(e){return"[object Object]"===Object.prototype.toString.call(e)}function isObjectEmpty(e){return"object"==typeof e&&!Array.isArray(e)&&null!==e&&0===Object.keys(e).length}function isPrivateRangeUrlFound(e){return[/xlink:href="(?:http:\/\/|https:\/\/)?localhost\b/,/xlink:href="(?:http:\/\/|https:\/\/)?10\.\d{1,3}\.\d{1,3}\.\d{1,3}\b/,/xlink:href="(?:http:\/\/|https:\/\/)?127\.\d{1,3}\.\d{1,3}\.\d{1,3}\b/,/xlink:href="(?:http:\/\/|https:\/\/)?172\.(1[6-9]|2[0-9]|3[0-1])\.\d{1,3}\.\d{1,3}\b/,/xlink:href="(?:http:\/\/|https:\/\/)?192\.168\.\d{1,3}\.\d{1,3}\b/].some((t=>t.test(e)))}function measureTime(){const e=process.hrtime.bigint();return()=>Number(process.hrtime.bigint()-e)/1e6}function roundNumber(e,t=1){const o=Math.pow(10,t||0);return Math.round(+e*o)/o}function wrapAround(e,t,o=!1){if(e&&"string"==typeof e)return(e=e.trim()).endsWith(".js")?t?wrapAround(fs.readFileSync(getAbsolutePath(e),"utf8"),t,o):null:!o&&(e.startsWith("function()")||e.startsWith("function ()")||e.startsWith("()=>")||e.startsWith("() =>"))?`(${e})()`:e.replace(/;$/,"")}const colors=["red","yellow","blue","gray","green"],logging={toConsole:!0,toFile:!1,pathCreated:!1,pathToLog:"",levelsDesc:[{title:"error",color:colors[0]},{title:"warning",color:colors[1]},{title:"notice",color:colors[2]},{title:"verbose",color:colors[3]},{title:"benchmark",color:colors[4]}]};function log(...e){const[t,...o]=e,{levelsDesc:n,level:r}=logging;if(5!==t&&(0===t||t>r||r>n.length))return;const i=`${getNewDate()} [${n[t-1].title}] -`;logging.toFile&&_logToFile(o,i),logging.toConsole&&console.log.apply(void 0,[i.toString()[logging.levelsDesc[t-1].color]].concat(o))}function logWithStack(e,t,o){const n=o||t&&t.message||"",{level:r,levelsDesc:i}=logging;if(0===e||e>r||r>i.length)return;const s=`${getNewDate()} [${i[e-1].title}] -`,a=t&&t.stack,l=[n];a&&l.push("\n",a),logging.toFile&&_logToFile(l,s),logging.toConsole&&console.log.apply(void 0,[s.toString()[logging.levelsDesc[e-1].color]].concat([l.shift()[colors[e-1]],...l]))}function logZodIssues(e,t=[],o){logWithStack(e,null,[`${o} - the following Zod issues occured:`,...t.map((e=>`- ${e.message}`))].join("\n"))}function initLogging(e){const{level:t,dest:o,file:n,toConsole:r,toFile:i}=e;logging.pathCreated=!1,logging.pathToLog="",setLogLevel(t),enableConsoleLogging(r),enableFileLogging(o,n,i)}function setLogLevel(e){Number.isInteger(e)&&e>=0&&e<=logging.levelsDesc.length&&(logging.level=e)}function enableConsoleLogging(e){logging.toConsole=!!e}function enableFileLogging(e,t,o){logging.toFile=!!o,logging.toFile&&(logging.dest=e||"",logging.file=t||"")}function _logToFile(e,t){logging.pathCreated||(!fs.existsSync(getAbsolutePath(logging.dest))&&fs.mkdirSync(getAbsolutePath(logging.dest)),logging.pathToLog=getAbsolutePath(path.join(logging.dest,logging.file)),logging.pathCreated=!0),fs.appendFile(logging.pathToLog,[t].concat(e).join(" ")+"\n",(e=>{e&&logging.toFile&&logging.pathCreated&&(logging.toFile=!1,logging.pathCreated=!1,logWithStack(2,e,"[logger] Unable to write to log file."))}))}const defaultConfig={puppeteer:{args:{value:["--allow-running-insecure-content","--ash-no-nudges","--autoplay-policy=user-gesture-required","--block-new-web-contents","--disable-accelerated-2d-canvas","--disable-background-networking","--disable-background-timer-throttling","--disable-backgrounding-occluded-windows","--disable-breakpad","--disable-checker-imaging","--disable-client-side-phishing-detection","--disable-component-extensions-with-background-pages","--disable-component-update","--disable-default-apps","--disable-dev-shm-usage","--disable-domain-reliability","--disable-extensions","--disable-features=CalculateNativeWinOcclusion,InterestFeedContentSuggestions,WebOTP","--disable-hang-monitor","--disable-ipc-flooding-protection","--disable-logging","--disable-notifications","--disable-offer-store-unmasked-wallet-cards","--disable-popup-blocking","--disable-print-preview","--disable-prompt-on-repost","--disable-renderer-backgrounding","--disable-search-engine-choice-screen","--disable-session-crashed-bubble","--disable-setuid-sandbox","--disable-site-isolation-trials","--disable-speech-api","--disable-sync","--enable-unsafe-webgpu","--hide-crash-restore-bubble","--hide-scrollbars","--metrics-recording-only","--mute-audio","--no-default-browser-check","--no-first-run","--no-pings","--no-sandbox","--no-startup-window","--no-zygote","--password-store=basic","--process-per-tab","--use-mock-keychain"],types:["string[]"],envLink:"PUPPETEER_ARGS",cliName:"puppeteerArgs",description:"Array of Puppeteer arguments",promptOptions:{type:"list",separator:";"}}},highcharts:{version:{value:"latest",types:["string"],envLink:"HIGHCHARTS_VERSION",description:"Highcharts version",promptOptions:{type:"text"}},cdnUrl:{value:"https://code.highcharts.com",types:["string"],envLink:"HIGHCHARTS_CDN_URL",description:"CDN URL for Highcharts scripts",promptOptions:{type:"text"}},forceFetch:{value:!1,types:["boolean"],envLink:"HIGHCHARTS_FORCE_FETCH",description:"Flag to refetch scripts after each server rerun",promptOptions:{type:"toggle"}},cachePath:{value:".cache",types:["string"],envLink:"HIGHCHARTS_CACHE_PATH",description:"Directory path for cached Highcharts scripts",promptOptions:{type:"text"}},coreScripts:{value:["highcharts","highcharts-more","highcharts-3d"],types:["string[]"],envLink:"HIGHCHARTS_CORE_SCRIPTS",description:"Highcharts core scripts to fetch",promptOptions:{type:"multiselect",instructions:"Space: Select specific, A: Select all, Enter: Confirm"}},moduleScripts:{value:["stock","map","gantt","exporting","parallel-coordinates","accessibility","boost-canvas","boost","data","data-tools","draggable-points","static-scale","broken-axis","heatmap","tilemap","tiledwebmap","timeline","treemap","treegraph","item-series","drilldown","histogram-bellcurve","bullet","funnel","funnel3d","geoheatmap","pyramid3d","networkgraph","overlapping-datalabels","pareto","pattern-fill","pictorial","price-indicator","sankey","arc-diagram","dependency-wheel","series-label","series-on-point","solid-gauge","sonification","streamgraph","sunburst","variable-pie","variwide","vector","venn","windbarb","wordcloud","xrange","no-data-to-display","drag-panes","debugger","dumbbell","lollipop","cylinder","organization","dotplot","marker-clusters","hollowcandlestick","heikinashi","flowmap","export-data","navigator","textpath"],types:["string[]"],envLink:"HIGHCHARTS_MODULE_SCRIPTS",description:"Highcharts module scripts to fetch",promptOptions:{type:"multiselect",instructions:"Space: Select specific, A: Select all, Enter: Confirm"}},indicatorScripts:{value:["indicators-all"],types:["string[]"],envLink:"HIGHCHARTS_INDICATOR_SCRIPTS",description:"Highcharts indicator scripts to fetch",promptOptions:{type:"multiselect",instructions:"Space: Select specific, A: Select all, Enter: Confirm"}},customScripts:{value:["https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.30.1/moment.min.js","https://cdnjs.cloudflare.com/ajax/libs/moment-timezone/0.5.45/moment-timezone-with-data.min.js"],types:["string[]"],envLink:"HIGHCHARTS_CUSTOM_SCRIPTS",description:"Additional custom scripts or dependencies to fetch",promptOptions:{type:"list",separator:";"}}},export:{infile:{value:null,types:["string","null"],envLink:"EXPORT_INFILE",description:"Input filename with type, formatted correctly as JSON or SVG",promptOptions:{type:"text"}},instr:{value:null,types:["Object","string","null"],envLink:"EXPORT_INSTR",description:"Overrides the `infile` with JSON, stringified JSON, or SVG input",promptOptions:{type:"text"}},options:{value:null,types:["Object","string","null"],envLink:"EXPORT_OPTIONS",description:"Alias for the `instr` option",promptOptions:{type:"text"}},svg:{value:null,types:["string","null"],envLink:"EXPORT_SVG",description:"SVG string representation of the chart to render",promptOptions:{type:"text"}},batch:{value:null,types:["string","null"],envLink:"EXPORT_BATCH",description:'Batch job string with input/output pairs: "in=out;in=out;..."',promptOptions:{type:"text"}},outfile:{value:null,types:["string","null"],envLink:"EXPORT_OUTFILE",description:"Output filename with type. Can be jpeg, png, pdf, or svg and ignores `type` option",promptOptions:{type:"text"}},type:{value:"png",types:["string"],envLink:"EXPORT_TYPE",description:"File export format. Can be jpeg, png, pdf, or svg",promptOptions:{type:"select",hint:"Default: png",choices:["png","jpeg","pdf","svg"]}},constr:{value:"chart",types:["string"],envLink:"EXPORT_CONSTR",description:"Chart constructor. Can be chart, stockChart, mapChart, or ganttChart",promptOptions:{type:"select",hint:"Default: chart",choices:["chart","stockChart","mapChart","ganttChart"]}},b64:{value:!1,types:["boolean"],envLink:"EXPORT_B64",description:"Whether or not to the chart should be received in Base64 format instead of binary",promptOptions:{type:"toggle"}},noDownload:{value:!1,types:["boolean"],envLink:"EXPORT_NO_DOWNLOAD",description:"Whether or not to include or exclude attachment headers in the response",promptOptions:{type:"toggle"}},height:{value:null,types:["number","null"],envLink:"EXPORT_HEIGHT",description:"Height of the exported chart, overrides chart settings",promptOptions:{type:"number"}},width:{value:null,types:["number","null"],envLink:"EXPORT_WIDTH",description:"Width of the exported chart, overrides chart settings",promptOptions:{type:"number"}},scale:{value:null,types:["number","null"],envLink:"EXPORT_SCALE",description:"Scale of the exported chart, overrides chart settings. Ranges from 0.1 to 5.0",promptOptions:{type:"number"}},defaultHeight:{value:400,types:["number"],envLink:"EXPORT_DEFAULT_HEIGHT",description:"Default height of the exported chart if not set",promptOptions:{type:"number"}},defaultWidth:{value:600,types:["number"],envLink:"EXPORT_DEFAULT_WIDTH",description:"Default width of the exported chart if not set",promptOptions:{type:"number"}},defaultScale:{value:1,types:["number"],envLink:"EXPORT_DEFAULT_SCALE",description:"Default scale of the exported chart if not set. Ranges from 0.1 to 5.0",promptOptions:{type:"number",min:.1,max:5}},globalOptions:{value:null,types:["Object","string","null"],envLink:"EXPORT_GLOBAL_OPTIONS",description:"JSON, stringified JSON or filename with global options for Highcharts.setOptions",promptOptions:{type:"text"}},themeOptions:{value:null,types:["Object","string","null"],envLink:"EXPORT_THEME_OPTIONS",description:"JSON, stringified JSON or filename with theme options for Highcharts.setOptions",promptOptions:{type:"text"}},rasterizationTimeout:{value:1500,types:["number"],envLink:"EXPORT_RASTERIZATION_TIMEOUT",description:"Milliseconds to wait for webpage rendering",promptOptions:{type:"number"}}},customLogic:{allowCodeExecution:{value:!1,types:["boolean"],envLink:"CUSTOM_LOGIC_ALLOW_CODE_EXECUTION",description:"Allows or disallows execution of arbitrary code during exporting",promptOptions:{type:"toggle"}},allowFileResources:{value:!1,types:["boolean"],envLink:"CUSTOM_LOGIC_ALLOW_FILE_RESOURCES",description:"Allows or disallows injection of filesystem resources (disabled in server mode)",promptOptions:{type:"toggle"}},customCode:{value:null,types:["string","null"],envLink:"CUSTOM_LOGIC_CUSTOM_CODE",description:"Custom code to execute before chart initialization. Can be a function, code wrapped in a function, or a .js filename",promptOptions:{type:"text"}},callback:{value:null,types:["string","null"],envLink:"CUSTOM_LOGIC_CALLBACK",description:"JavaScript code to run during construction. Can be a function or a .js filename",promptOptions:{type:"text"}},resources:{value:null,types:["Object","string","null"],envLink:"CUSTOM_LOGIC_RESOURCES",description:"Additional resources as JSON, stringified JSON, or filename, containing files, js, and css sections",promptOptions:{type:"text"}},loadConfig:{value:null,types:["string","null"],envLink:"CUSTOM_LOGIC_LOAD_CONFIG",legacyName:"fromFile",description:"File with a pre-defined configuration to use",promptOptions:{type:"text"}},createConfig:{value:null,types:["string","null"],envLink:"CUSTOM_LOGIC_CREATE_CONFIG",description:"Prompt-based option setting, saved to a provided config file",promptOptions:{type:"text"}}},server:{enable:{value:!1,types:["boolean"],envLink:"SERVER_ENABLE",cliName:"enableServer",description:"Starts the server when true",promptOptions:{type:"toggle"}},host:{value:"0.0.0.0",types:["string"],envLink:"SERVER_HOST",description:"Hostname of the server",promptOptions:{type:"text"}},port:{value:7801,types:["number"],envLink:"SERVER_PORT",description:"Port number for the server",promptOptions:{type:"number"}},uploadLimit:{value:3,types:["number"],envLink:"SERVER_UPLOAD_LIMIT",description:"Maximum request body size in MB",promptOptions:{type:"number"}},benchmarking:{value:!1,types:["boolean"],envLink:"SERVER_BENCHMARKING",cliName:"serverBenchmarking",description:"Displays or not action durations in milliseconds during server requests",promptOptions:{type:"toggle"}},proxy:{host:{value:null,types:["string","null"],envLink:"SERVER_PROXY_HOST",cliName:"proxyHost",description:"Host of the proxy server, if applicable",promptOptions:{type:"text"}},port:{value:null,types:["number","null"],envLink:"SERVER_PROXY_PORT",cliName:"proxyPort",description:"Port of the proxy server, if applicable",promptOptions:{type:"number"}},timeout:{value:5e3,types:["number"],envLink:"SERVER_PROXY_TIMEOUT",cliName:"proxyTimeout",description:"Timeout in milliseconds for the proxy server, if applicable",promptOptions:{type:"number"}}},rateLimiting:{enable:{value:!1,types:["boolean"],envLink:"SERVER_RATE_LIMITING_ENABLE",cliName:"enableRateLimiting",description:"Enables or disables rate limiting on the server",promptOptions:{type:"toggle"}},maxRequests:{value:10,types:["number"],envLink:"SERVER_RATE_LIMITING_MAX_REQUESTS",legacyName:"rateLimit",description:"Maximum number of requests allowed per minute",promptOptions:{type:"number"}},window:{value:1,types:["number"],envLink:"SERVER_RATE_LIMITING_WINDOW",description:"Time window in minutes for rate limiting",promptOptions:{type:"number"}},delay:{value:0,types:["number"],envLink:"SERVER_RATE_LIMITING_DELAY",description:"Delay duration between successive requests before reaching the limit",promptOptions:{type:"number"}},trustProxy:{value:!1,types:["boolean"],envLink:"SERVER_RATE_LIMITING_TRUST_PROXY",description:"Set to true if the server is behind a load balancer",promptOptions:{type:"toggle"}},skipKey:{value:null,types:["string","null"],envLink:"SERVER_RATE_LIMITING_SKIP_KEY",description:"Key to bypass the rate limiter, used with `skipToken`",promptOptions:{type:"text"}},skipToken:{value:null,types:["string","null"],envLink:"SERVER_RATE_LIMITING_SKIP_TOKEN",description:"Token to bypass the rate limiter, used with `skipKey`",promptOptions:{type:"text"}}},ssl:{enable:{value:!1,types:["boolean"],envLink:"SERVER_SSL_ENABLE",cliName:"enableSsl",description:"Enables or disables SSL protocol",promptOptions:{type:"toggle"}},force:{value:!1,types:["boolean"],envLink:"SERVER_SSL_FORCE",cliName:"sslForce",legacyName:"sslOnly",description:"Forces the server to use HTTPS only when true",promptOptions:{type:"toggle"}},port:{value:443,types:["number"],envLink:"SERVER_SSL_PORT",cliName:"sslPort",description:"Port for the SSL server",promptOptions:{type:"number"}},certPath:{value:null,types:["string","null"],envLink:"SERVER_SSL_CERT_PATH",cliName:"sslCertPath",legacyName:"sslPath",description:"Path to the SSL certificate/key file",promptOptions:{type:"text"}}}},pool:{minWorkers:{value:4,types:["number"],envLink:"POOL_MIN_WORKERS",description:"Minimum and initial number of pool workers to spawn",promptOptions:{type:"number"}},maxWorkers:{value:8,types:["number"],envLink:"POOL_MAX_WORKERS",legacyName:"workers",description:"Maximum number of pool workers to spawn",promptOptions:{type:"number"}},workLimit:{value:40,types:["number"],envLink:"POOL_WORK_LIMIT",description:"Number of tasks a worker can handle before restarting",promptOptions:{type:"number"}},acquireTimeout:{value:5e3,types:["number"],envLink:"POOL_ACQUIRE_TIMEOUT",description:"Timeout in milliseconds for acquiring a resource",promptOptions:{type:"number"}},createTimeout:{value:5e3,types:["number"],envLink:"POOL_CREATE_TIMEOUT",description:"Timeout in milliseconds for creating a resource",promptOptions:{type:"number"}},destroyTimeout:{value:5e3,types:["number"],envLink:"POOL_DESTROY_TIMEOUT",description:"Timeout in milliseconds for destroying a resource",promptOptions:{type:"number"}},idleTimeout:{value:3e4,types:["number"],envLink:"POOL_IDLE_TIMEOUT",description:"Timeout in milliseconds for destroying idle resources",promptOptions:{type:"number"}},createRetryInterval:{value:200,types:["number"],envLink:"POOL_CREATE_RETRY_INTERVAL",description:"Interval in milliseconds before retrying resource creation on failure",promptOptions:{type:"number"}},reaperInterval:{value:1e3,types:["number"],envLink:"POOL_REAPER_INTERVAL",description:"Interval in milliseconds to check and destroy idle resources",promptOptions:{type:"number"}},benchmarking:{value:!1,types:["boolean"],envLink:"POOL_BENCHMARKING",cliName:"poolBenchmarking",description:"Shows statistics for the pool of resources",promptOptions:{type:"toggle"}}},logging:{level:{value:4,types:["number"],envLink:"LOGGING_LEVEL",cliName:"logLevel",description:"Logging verbosity level",promptOptions:{type:"number",round:0,min:0,max:5}},file:{value:"highcharts-export-server.log",types:["string"],envLink:"LOGGING_FILE",cliName:"logFile",description:"Log file name. Requires `logToFile` and `logDest` to be set",promptOptions:{type:"text"}},dest:{value:"log",types:["string"],envLink:"LOGGING_DEST",cliName:"logDest",description:"Path to store log files. Requires `logToFile` to be set",promptOptions:{type:"text"}},toConsole:{value:!0,types:["boolean"],envLink:"LOGGING_TO_CONSOLE",cliName:"logToConsole",description:"Enables or disables console logging",promptOptions:{type:"toggle"}},toFile:{value:!0,types:["boolean"],envLink:"LOGGING_TO_FILE",cliName:"logToFile",description:"Enables or disables logging to a file",promptOptions:{type:"toggle"}}},ui:{enable:{value:!1,types:["boolean"],envLink:"UI_ENABLE",cliName:"enableUi",description:"Enables or disables the UI for the export server",promptOptions:{type:"toggle"}},route:{value:"/",types:["string"],envLink:"UI_ROUTE",cliName:"uiRoute",description:"The endpoint route for the UI",promptOptions:{type:"text"}}},other:{nodeEnv:{value:"production",types:["string"],envLink:"OTHER_NODE_ENV",description:"The Node.js environment type",promptOptions:{type:"text"}},listenToProcessExits:{value:!0,types:["boolean"],envLink:"OTHER_LISTEN_TO_PROCESS_EXITS",description:"Whether or not to attach process.exit handlers",promptOptions:{type:"toggle"}},noLogo:{value:!1,types:["boolean"],envLink:"OTHER_NO_LOGO",description:"Display or skip printing the logo on startup",promptOptions:{type:"toggle"}},hardResetPage:{value:!1,types:["boolean"],envLink:"OTHER_HARD_RESET_PAGE",description:"Whether or not to reset the page content entirely",promptOptions:{type:"toggle"}},browserShellMode:{value:!0,types:["boolean"],envLink:"OTHER_BROWSER_SHELL_MODE",description:"Whether or not to set the browser to run in shell mode",promptOptions:{type:"toggle"}}},debug:{enable:{value:!1,types:["boolean"],envLink:"DEBUG_ENABLE",cliName:"enableDebug",description:"Enables or disables debug mode for the underlying browser",promptOptions:{type:"toggle"}},headless:{value:!1,types:["boolean"],envLink:"DEBUG_HEADLESS",description:"Whether or not to set the browser to run in headless mode during debugging",promptOptions:{type:"toggle"}},devtools:{value:!1,types:["boolean"],envLink:"DEBUG_DEVTOOLS",description:"Enables or disables DevTools in headful mode",promptOptions:{type:"toggle"}},listenToConsole:{value:!1,types:["boolean"],envLink:"DEBUG_LISTEN_TO_CONSOLE",description:"Enables or disables listening to console messages from the browser",promptOptions:{type:"toggle"}},dumpio:{value:!1,types:["boolean"],envLink:"DEBUG_DUMPIO",description:"Redirects or not browser stdout and stderr to process.stdout and process.stderr",promptOptions:{type:"toggle"}},slowMo:{value:0,types:["number"],envLink:"DEBUG_SLOW_MO",description:"Delays Puppeteer operations by the specified milliseconds",promptOptions:{type:"number"}},debuggingPort:{value:9222,types:["number"],envLink:"DEBUG_DEBUGGING_PORT",description:"Port used for debugging",promptOptions:{type:"number"}}}},nestedProps=_createNestedProps(defaultConfig),absoluteProps=_createAbsoluteProps(defaultConfig);function _createNestedProps(e,t={},o=""){return Object.keys(e).forEach((n=>{const r=e[n];void 0===r.value?_createNestedProps(r,t,`${o}.${n}`):(t[r.cliName||n]=`${o}.${n}`.substring(1),void 0!==r.legacyName&&(t[r.legacyName]=`${o}.${n}`.substring(1)))})),t}function _createAbsoluteProps(e,t=[]){return Object.keys(e).forEach((o=>{const n=e[o];void 0===n.types?_createAbsoluteProps(n,t):n.types.includes("Object")&&t.push(o)})),t}dotenv.config();const{coreScripts:coreScripts,moduleScripts:moduleScripts,indicatorScripts:indicatorScripts}=defaultConfig.highcharts;zod.z.setErrorMap(_customErrorMap);const v={boolean:e=>e?zod.z.boolean():zod.z.union([zod.z.enum(["true","false","undefined","null",""]).transform((e=>["undefined","null",""].includes(e)?null:"true"===e)),zod.z.boolean()]).nullable(),string:e=>e?zod.z.string().trim().refine((e=>!["false","undefined","null",""].includes(e)),{params:{errorMessage:"The string contains a forbidden value"}}):zod.z.string().trim().transform((e=>["false","undefined","null",""].includes(e)?null:e)).nullable(),enum:(e,t)=>t?zod.z.enum([...e]):zod.z.enum([...e,"undefined","null",""]).transform((e=>["undefined","null",""].includes(e)?null:e)).nullable(),stringArray(e,t,o){const n=zod.z.string().trim().array(),r=zod.z.string().trim().transform((e=>(e.startsWith("[")&&(e=e.slice(1)),e.endsWith("]")&&(e=e.slice(0,-1)),e.split(t)))),i=t=>t.map((e=>e.trim())).filter(e);return o?n.transform(i):zod.z.union([r,n]).transform(i).transform((e=>e.length?e:null)).nullable()},positiveNum:e=>e?zod.z.number().positive():zod.z.union([zod.z.string().trim().refine((e=>!isNaN(Number(e))&&Number(e)>0||["undefined","null",""].includes(e)),{params:{errorMessage:"The value must be numeric and positive"}}).transform((e=>["undefined","null",""].includes(e)?null:Number(e))),zod.z.number().positive()]).nullable(),nonNegativeNum:e=>e?zod.z.number().nonnegative():zod.z.union([zod.z.string().trim().refine((e=>!isNaN(Number(e))&&Number(e)>=0||["undefined","null",""].includes(e)),{params:{errorMessage:"The value must be numeric and non-negative"}}).transform((e=>["undefined","null",""].includes(e)?null:Number(e))),zod.z.number().nonnegative()]).nullable(),startsWith:(e,t)=>t?zod.z.string().trim().refine((t=>e.some((e=>t.startsWith(e)))),{params:{errorMessage:`The value must be a string that starts with ${e.join(", ")}`}}):zod.z.string().trim().refine((t=>e.some((e=>t.startsWith(e)))||["undefined","null",""].includes(t)),{params:{errorMessage:`The value must be a string that starts with ${e.join(", ")}`}}).transform((e=>["undefined","null",""].includes(e)?null:e)).nullable(),chartConfig:()=>zod.z.union([zod.z.string().trim().refine((e=>e.indexOf("=0||e.indexOf("=0||e.startsWith("{")&&e.endsWith("}")||["undefined","null",""].includes(e)),{params:{errorMessage:"The value must be a string that contains '["undefined","null",""].includes(e)?null:e)),zod.z.object({}).passthrough()]).nullable(),additionalOptions:()=>zod.z.union([zod.z.string().trim().refine((e=>e.length>=6&&e.endsWith(".json")||e.startsWith("{")&&e.endsWith("}")||["undefined","null",""].includes(e)),{params:{errorMessage:"The value must be a string that ends with '.json' or starts with '{' and ends with '}'"}}).transform((e=>["undefined","null",""].includes(e)?null:e)),zod.z.object({}).passthrough()]).nullable()},config={args:e=>v.stringArray((e=>!["false","undefined","null",""].includes(e)),";",e),version:e=>e?zod.z.string().trim().refine((e=>/^(latest|\d{1,2}(\.\d{1,2}){0,2})$/.test(e)),{params:{errorMessage:"The value must be 'latest', a major version, or in the form XX.YY.ZZ"}}):zod.z.string().trim().refine((e=>/^(latest|\d{1,2}(\.\d{1,2}){0,2})$/.test(e)||["undefined","null",""].includes(e)),{params:{errorMessage:"The value must be 'latest', a major version, or in the form XX.YY.ZZ"}}).transform((e=>["undefined","null",""].includes(e)?null:e)).nullable(),cdnUrl:e=>v.startsWith(["http://","https://"],e),forceFetch:e=>v.boolean(e),cachePath:e=>v.string(e),adminToken:e=>v.string(e),coreScripts:e=>v.stringArray((e=>coreScripts.value.includes(e)),",",e),moduleScripts:e=>v.stringArray((e=>moduleScripts.value.includes(e)),",",e),indicatorScripts:e=>v.stringArray((e=>indicatorScripts.value.includes(e)),",",e),customScripts:e=>v.stringArray((e=>e.startsWith("https://")||e.startsWith("http://")),",",e),infile:e=>e?zod.z.string().trim().refine((e=>e.length>=6&&e.endsWith(".json")||e.length>=5&&e.endsWith(".svg")),{params:{errorMessage:"The value must be a string that ends with .json or .svg"}}).nullable():zod.z.string().trim().refine((e=>e.length>=6&&e.endsWith(".json")||e.length>=5&&e.endsWith(".svg")||["undefined","null",""].includes(e)),{params:{errorMessage:"The value must be a string that ends with .json or .svg"}}).transform((e=>["undefined","null",""].includes(e)?null:e)).nullable(),instr:()=>v.chartConfig(),options:()=>v.chartConfig(),svg:()=>zod.z.string().trim().refine((e=>e.indexOf("=0||e.indexOf("=0||["false","undefined","null",""].includes(e)),{params:{errorMessage:"The value must be a string that contains '["false","undefined","null",""].includes(e)?null:e)).nullable(),outfile:e=>e?zod.z.string().trim().refine((e=>e.length>=6&&e.endsWith(".jpeg")||e.length>=5&&(e.endsWith(".jpg")||e.endsWith(".png")||e.endsWith(".pdf")||e.endsWith(".svg"))),{params:{errorMessage:"The value must be a string that ends with .jpeg, .jpg, .png, .pdf, or .svg"}}).nullable():zod.z.string().trim().refine((e=>e.length>=6&&e.endsWith(".jpeg")||e.length>=5&&(e.endsWith(".jpg")||e.endsWith(".png")||e.endsWith(".pdf")||e.endsWith(".svg"))||["undefined","null",""].includes(e)),{params:{errorMessage:"The value must be a string that ends with .jpeg, .jpg, .png, .pdf, or .svg"}}).transform((e=>["undefined","null",""].includes(e)?null:e)).nullable(),type:e=>v.enum(["jpeg","jpg","png","pdf","svg"],e),constr:e=>v.enum(["chart","stockChart","mapChart","ganttChart"],e),b64:e=>v.boolean(e),noDownload:e=>v.boolean(e),defaultHeight:e=>v.positiveNum(e),defaultWidth:e=>v.positiveNum(e),defaultScale:e=>e?zod.z.number().gte(.1).lte(5):zod.z.union([zod.z.string().trim().refine((e=>!isNaN(Number(e))&&!0!==e&&!e.startsWith("[")&&Number(e)>=.1&&Number(e)<=5||["undefined","null",""].includes(e)),{params:{errorMessage:"The value must be within a 0.1 and 5.0 range"}}).transform((e=>["undefined","null",""].includes(e)?null:Number(e))),zod.z.number().gte(.1).lte(5)]).nullable(),height(e){return this.defaultHeight(e).nullable()},width(e){return this.defaultWidth(e).nullable()},scale(e){return this.defaultScale(e).nullable()},globalOptions:()=>v.additionalOptions(),themeOptions:()=>v.additionalOptions(),batch:e=>v.string(e),rasterizationTimeout:e=>v.nonNegativeNum(e),allowCodeExecution:e=>v.boolean(e),allowFileResources:e=>v.boolean(e),customCode:e=>v.string(e),callback:e=>v.string(e),resources(e){const t=zod.z.object({js:v.string(!1),css:v.string(!1),files:v.stringArray((e=>!["undefined","null",""].includes(e)),",",!0).nullable()}).partial(),o=zod.z.string().trim().refine((e=>e.startsWith("{")&&e.endsWith("}")||e.length>=6&&e.endsWith(".json")),{params:{errorMessage:"The value must be a string that starts with '{' and ends with '}"}}),n=zod.z.string().trim().refine((e=>e.startsWith("{")&&e.endsWith("}")||e.length>=6&&e.endsWith(".json")||["undefined","null",""].includes(e)),{params:{errorMessage:"The value must be a string that ends with '.json'"}}).transform((e=>["undefined","null",""].includes(e)?null:e));return e?zod.z.union([t,o]).nullable():zod.z.union([t,n]).nullable()},loadConfig:e=>v.string(e).refine((e=>null===e||e.length>=6&&e.endsWith(".json")),{params:{errorMessage:"The value must be a string that ends with .json "}}),createConfig(e){return this.loadConfig(e)},enableServer:e=>v.boolean(e),host:e=>v.string(e),port:e=>v.nonNegativeNum(e),uploadLimit:e=>v.positiveNum(e),serverBenchmarking:e=>v.boolean(e),proxyHost:e=>v.string(e),proxyPort:e=>v.nonNegativeNum(e).nullable(),proxyTimeout:e=>v.nonNegativeNum(e),enableRateLimiting:e=>v.boolean(e),maxRequests:e=>v.nonNegativeNum(e),window:e=>v.nonNegativeNum(e),delay:e=>v.nonNegativeNum(e),trustProxy:e=>v.boolean(e),skipKey:e=>v.string(e),skipToken:e=>v.string(e),enableSsl:e=>v.boolean(e),sslForce:e=>v.boolean(e),sslPort:e=>v.nonNegativeNum(e),sslCertPath:e=>v.string(e),minWorkers:e=>v.positiveNum(e),maxWorkers:e=>v.positiveNum(e),workLimit:e=>v.positiveNum(e),acquireTimeout:e=>v.nonNegativeNum(e),createTimeout:e=>v.nonNegativeNum(e),destroyTimeout:e=>v.nonNegativeNum(e),idleTimeout:e=>v.nonNegativeNum(e),createRetryInterval:e=>v.nonNegativeNum(e),reaperInterval:e=>v.nonNegativeNum(e),poolBenchmarking:e=>v.boolean(e),resourcesInterval:e=>v.nonNegativeNum(e),logLevel:e=>e?zod.z.number().int().gte(0).lte(5):zod.z.union([zod.z.string().trim().refine((e=>!isNaN(Number(e))&&!0!==e&&!e.startsWith("[")&&Number.isInteger(Number(e))&&Number(e)>=0&&Number(e)<=5||["undefined","null",""].includes(e)),{params:{errorMessage:"The value must be within a 0 and 5 range"}}).transform((e=>["undefined","null",""].includes(e)?null:Number(e))),zod.z.number().int().gte(0).lte(5)]).nullable(),logFile:e=>v.string(e).refine((e=>null===e||e.length>=5&&e.endsWith(".log")),{params:{errorMessage:"The value must be a string that ends with '.log'"}}),logDest:e=>v.string(e),logToConsole:e=>v.boolean(e),logToFile:e=>v.boolean(e),enableUi:e=>v.boolean(e),uiRoute:e=>v.startsWith(["/"],e),nodeEnv:e=>v.enum(["development","production","test"],e),listenToProcessExits:e=>v.boolean(e),noLogo:e=>v.boolean(e),hardResetPage:e=>v.boolean(e),browserShellMode:e=>v.boolean(e),enableDebug:e=>v.boolean(e),headless:e=>v.boolean(e),devtools:e=>v.boolean(e),listenToConsole:e=>v.boolean(e),dumpio:e=>v.boolean(e),slowMo:e=>v.nonNegativeNum(e),debuggingPort:e=>v.nonNegativeNum(e),requestId:()=>zod.z.string().uuid({message:"The value must be a stringified UUID"}).nullable()},PuppeteerSchema=e=>zod.z.object({args:config.args(e)}).partial(),HighchartsSchema=e=>zod.z.object({version:config.version(e),cdnUrl:config.cdnUrl(e),forceFetch:config.forceFetch(e),cachePath:config.cachePath(e),coreScripts:config.coreScripts(e),moduleScripts:config.moduleScripts(e),indicatorScripts:config.indicatorScripts(e),customScripts:config.customScripts(e)}).partial(),ExportSchema=e=>zod.z.object({infile:config.infile(e),instr:config.instr(),options:config.options(),svg:config.svg(),outfile:config.outfile(e),type:config.type(e),constr:config.constr(e),b64:config.b64(e),noDownload:config.noDownload(e),defaultHeight:config.defaultHeight(e),defaultWidth:config.defaultWidth(e),defaultScale:config.defaultScale(e),height:config.height(e),width:config.width(e),scale:config.scale(e),globalOptions:config.globalOptions(),themeOptions:config.themeOptions(),batch:config.batch(!1),rasterizationTimeout:config.rasterizationTimeout(e)}).partial(),CustomLogicSchema=e=>zod.z.object({allowCodeExecution:config.allowCodeExecution(e),allowFileResources:config.allowFileResources(e),customCode:config.customCode(!1),callback:config.callback(!1),resources:config.resources(e),loadConfig:config.loadConfig(!1),createConfig:config.createConfig(!1)}).partial(),ProxySchema=e=>zod.z.object({host:config.proxyHost(!1),port:config.proxyPort(e),timeout:config.proxyTimeout(e)}).partial(),RateLimitingSchema=e=>zod.z.object({enable:config.enableRateLimiting(e),maxRequests:config.maxRequests(e),window:config.window(e),delay:config.delay(e),trustProxy:config.trustProxy(e),skipKey:config.skipKey(!1),skipToken:config.skipToken(!1)}).partial(),SslSchema=e=>zod.z.object({enable:config.enableSsl(e),force:config.sslForce(e),port:config.sslPort(e),certPath:config.sslCertPath(!1)}).partial(),ServerSchema=e=>zod.z.object({enable:config.enableServer(e).optional(),host:config.host(e).optional(),port:config.port(e).optional(),benchmarking:config.serverBenchmarking(e).optional(),proxy:ProxySchema(e).optional(),rateLimiting:RateLimitingSchema(e).optional(),ssl:SslSchema(e).optional()}),PoolSchema=e=>zod.z.object({minWorkers:config.minWorkers(e),maxWorkers:config.maxWorkers(e),workLimit:config.workLimit(e),acquireTimeout:config.acquireTimeout(e),createTimeout:config.createTimeout(e),destroyTimeout:config.destroyTimeout(e),idleTimeout:config.idleTimeout(e),createRetryInterval:config.createRetryInterval(e),reaperInterval:config.reaperInterval(e),benchmarking:config.poolBenchmarking(e)}).partial(),LoggingSchema=e=>zod.z.object({level:config.logLevel(e),file:config.logFile(e),dest:config.logDest(e),toConsole:config.logToConsole(e),toFile:config.logToFile(e)}).partial(),UiSchema=e=>zod.z.object({enable:config.enableUi(e),route:config.uiRoute(e)}).partial(),OtherSchema=e=>zod.z.object({nodeEnv:config.nodeEnv(e),listenToProcessExits:config.listenToProcessExits(e),noLogo:config.noLogo(e),hardResetPage:config.hardResetPage(e),browserShellMode:config.browserShellMode(e)}).partial(),DebugSchema=e=>zod.z.object({enable:config.enableDebug(e),headless:config.headless(e),devtools:config.devtools(e),listenToConsole:config.listenToConsole(e),dumpio:config.dumpio(e),slowMo:config.slowMo(e),debuggingPort:config.debuggingPort(e)}).partial(),StrictConfigSchema=zod.z.object({puppeteer:PuppeteerSchema(!0),highcharts:HighchartsSchema(!0),export:ExportSchema(!0),customLogic:CustomLogicSchema(!0),server:ServerSchema(!0),pool:PoolSchema(!0),logging:LoggingSchema(!0),ui:UiSchema(!0),other:OtherSchema(!0),debug:DebugSchema(!0)}),LooseConfigSchema=zod.z.object({puppeteer:PuppeteerSchema(!1),highcharts:HighchartsSchema(!1),export:ExportSchema(!1),customLogic:CustomLogicSchema(!1),server:ServerSchema(!1),pool:PoolSchema(!1),logging:LoggingSchema(!1),ui:UiSchema(!1),other:OtherSchema(!1),debug:DebugSchema(!1)}),EnvSchema=zod.z.object({PUPPETEER_ARGS:config.args(!1),HIGHCHARTS_VERSION:config.version(!1),HIGHCHARTS_CDN_URL:config.cdnUrl(!1),HIGHCHARTS_FORCE_FETCH:config.forceFetch(!1),HIGHCHARTS_CACHE_PATH:config.cachePath(!1),HIGHCHARTS_ADMIN_TOKEN:config.adminToken(!1),HIGHCHARTS_CORE_SCRIPTS:config.coreScripts(!1),HIGHCHARTS_MODULE_SCRIPTS:config.moduleScripts(!1),HIGHCHARTS_INDICATOR_SCRIPTS:config.indicatorScripts(!1),HIGHCHARTS_CUSTOM_SCRIPTS:config.customScripts(!1),EXPORT_INFILE:config.infile(!1),EXPORT_INSTR:config.instr(),EXPORT_OPTIONS:config.options(),EXPORT_SVG:config.svg(),EXPORT_BATCH:config.batch(!1),EXPORT_OUTFILE:config.outfile(!1),EXPORT_TYPE:config.type(!1),EXPORT_CONSTR:config.constr(!1),EXPORT_B64:config.b64(!1),EXPORT_NO_DOWNLOAD:config.noDownload(!1),EXPORT_HEIGHT:config.height(!1),EXPORT_WIDTH:config.width(!1),EXPORT_SCALE:config.scale(!1),EXPORT_DEFAULT_HEIGHT:config.defaultHeight(!1),EXPORT_DEFAULT_WIDTH:config.defaultWidth(!1),EXPORT_DEFAULT_SCALE:config.defaultScale(!1),EXPORT_GLOBAL_OPTIONS:config.globalOptions(),EXPORT_THEME_OPTIONS:config.themeOptions(),EXPORT_RASTERIZATION_TIMEOUT:config.rasterizationTimeout(!1),CUSTOM_LOGIC_ALLOW_CODE_EXECUTION:config.allowCodeExecution(!1),CUSTOM_LOGIC_ALLOW_FILE_RESOURCES:config.allowFileResources(!1),CUSTOM_LOGIC_CUSTOM_CODE:config.customCode(!1),CUSTOM_LOGIC_CALLBACK:config.callback(!1),CUSTOM_LOGIC_RESOURCES:config.resources(!1),CUSTOM_LOGIC_LOAD_CONFIG:config.loadConfig(!1),CUSTOM_LOGIC_CREATE_CONFIG:config.createConfig(!1),SERVER_ENABLE:config.enableServer(!1),SERVER_HOST:config.host(!1),SERVER_PORT:config.port(!1),SERVER_UPLOAD_LIMIT:config.uploadLimit(!1),SERVER_BENCHMARKING:config.serverBenchmarking(!1),SERVER_PROXY_HOST:config.proxyHost(!1),SERVER_PROXY_PORT:config.proxyPort(!1),SERVER_PROXY_TIMEOUT:config.proxyTimeout(!1),SERVER_RATE_LIMITING_ENABLE:config.enableRateLimiting(!1),SERVER_RATE_LIMITING_MAX_REQUESTS:config.maxRequests(!1),SERVER_RATE_LIMITING_WINDOW:config.window(!1),SERVER_RATE_LIMITING_DELAY:config.delay(!1),SERVER_RATE_LIMITING_TRUST_PROXY:config.trustProxy(!1),SERVER_RATE_LIMITING_SKIP_KEY:config.skipKey(!1),SERVER_RATE_LIMITING_SKIP_TOKEN:config.skipToken(!1),SERVER_SSL_ENABLE:config.enableSsl(!1),SERVER_SSL_FORCE:config.sslForce(!1),SERVER_SSL_PORT:config.sslPort(!1),SERVER_SSL_CERT_PATH:config.sslCertPath(!1),POOL_MIN_WORKERS:config.minWorkers(!1),POOL_MAX_WORKERS:config.maxWorkers(!1),POOL_WORK_LIMIT:config.workLimit(!1),POOL_ACQUIRE_TIMEOUT:config.acquireTimeout(!1),POOL_CREATE_TIMEOUT:config.createTimeout(!1),POOL_DESTROY_TIMEOUT:config.destroyTimeout(!1),POOL_IDLE_TIMEOUT:config.idleTimeout(!1),POOL_CREATE_RETRY_INTERVAL:config.createRetryInterval(!1),POOL_REAPER_INTERVAL:config.reaperInterval(!1),POOL_BENCHMARKING:config.poolBenchmarking(!1),LOGGING_LEVEL:config.logLevel(!1),LOGGING_FILE:config.logFile(!1),LOGGING_DEST:config.logDest(!1),LOGGING_TO_CONSOLE:config.logToConsole(!1),LOGGING_TO_FILE:config.logToFile(!1),UI_ENABLE:config.enableUi(!1),UI_ROUTE:config.uiRoute(!1),OTHER_NODE_ENV:config.nodeEnv(!1),OTHER_LISTEN_TO_PROCESS_EXITS:config.listenToProcessExits(!1),OTHER_NO_LOGO:config.noLogo(!1),OTHER_HARD_RESET_PAGE:config.hardResetPage(!1),OTHER_BROWSER_SHELL_MODE:config.browserShellMode(!1),DEBUG_ENABLE:config.enableDebug(!1),DEBUG_HEADLESS:config.headless(!1),DEBUG_DEVTOOLS:config.devtools(!1),DEBUG_LISTEN_TO_CONSOLE:config.listenToConsole(!1),DEBUG_DUMPIO:config.dumpio(!1),DEBUG_SLOW_MO:config.slowMo(!1),DEBUG_DEBUGGING_PORT:config.debuggingPort(!1)}),envs=EnvSchema.partial().parse(process.env);function strictValidate(e){return StrictConfigSchema.partial().parse(e)}function looseValidate(e){return LooseConfigSchema.partial().parse(e)}function validateOption(e,t,o){return config[e](o).parse(t)}function _customErrorMap(e,t){const o=e.path.join("."),n=`Invalid value for the ${o}`;if(e.code===zod.z.ZodIssueCode.invalid_type)return e.received===zod.z.ZodParsedType.undefined?{message:`${n} - No value was provided.`}:{message:`${n} - Invalid type. ${t.defaultError}.`};if(e.code===zod.z.ZodIssueCode.custom&&e.params?.errorMessage)return{message:`${n} - ${e.params?.errorMessage}, received '${t.data}'.`};if(e.code===zod.z.ZodIssueCode.invalid_union){let t=`Multiple errors occurred for the ${o}:\n`;return e.unionErrors.forEach((e=>{const o=e.issues[0].message.indexOf("-");t+=-1!==o?`${e.issues[0].message}\n`.substring(o):`${e.issues[0].message}\n`})),{message:t}}return{message:`${n} - ${t.defaultError}.`}}const globalOptions=_initGlobalOptions(defaultConfig),instanceOptions=deepCopy(globalOptions);function getOptions(e=!0){return e?instanceOptions:globalOptions}function setGlobalOptions(e={},t=[]){let o={},n={};if(t.length)try{o=strictValidate(_loadConfigFile(t))}catch(e){logZodIssues(1,e.issues,"[config] Custom JSON options validation error")}if(e&&0!==Object.keys(e).length)try{e=strictValidate(e)}catch(e){logZodIssues(1,e.issues,"[config] Custom options validation error")}if(t.length)try{n=looseValidate(_pairArgumentValue(nestedProps,t))}catch(e){logZodIssues(1,e.issues,"[config] CLI options validation error")}return _updateGlobalOptions(defaultConfig,globalOptions,o,n,e),globalOptions}function updateOptions(e,t=!1){return t&&(Object.keys(instanceOptions).forEach((e=>{delete instanceOptions[e]})),mergeOptions(instanceOptions,deepCopy(globalOptions))),mergeOptions(instanceOptions,e),instanceOptions}function mergeOptions(e,t){if(isObject(e)&&isObject(t))for(const[o,n]of Object.entries(t))e[o]=isObject(n)&&!absoluteProps.includes(o)&&void 0!==e[o]?mergeOptions(e[o],n):void 0!==n?n:e[o]||null;return e}function mapToNewOptions(e){const t={};if(isObject(e))for(const[o,n]of Object.entries(e)){const e=nestedProps[o]?nestedProps[o].split("."):[];e.reduce(((t,o,r)=>t[o]=e.length-1===r?n:t[o]||{}),t)}else log(2,"[config] No correct object with options was provided. Returning an empty array.");return t}function isAllowedConfig(config,toString=!1,allowFunctions=!1){try{if(!isObject(config)&&"string"!=typeof config)return null;const objectConfig="string"==typeof config?allowFunctions?eval(`(${config})`):JSON.parse(config):config,stringifiedOptions=_optionsStringify(objectConfig,allowFunctions,!1),parsedOptions=allowFunctions?JSON.parse(_optionsStringify(objectConfig,allowFunctions,!0),((_,value)=>"string"==typeof value&&value.startsWith("function")?eval(`(${value})`):value)):JSON.parse(stringifiedOptions);return toString?stringifiedOptions:parsedOptions}catch(e){return null}}function _initGlobalOptions(e){const t={};for(const[o,n]of Object.entries(e))if(Object.prototype.hasOwnProperty.call(n,"value")){const e=envs[n.envLink];t[o]=null!=e?e:n.value}else t[o]=_initGlobalOptions(n);return t}function _updateGlobalOptions(e,t,o,n,r){Object.keys(e).forEach((i=>{const s=e[i],a=o&&o[i],l=n&&n[i],c=r&&r[i];if(void 0===s.value)_updateGlobalOptions(s,t[i],a,l,c);else{null!=a&&(t[i]=a);const e=envs[s.envLink];s.envLink in envs&&null!=e&&(t[i]=e),null!=l&&(t[i]=l),null!=c&&(t[i]=c)}}))}function _optionsStringify(e,t,o){return JSON.stringify(e,((e,n)=>{if("string"==typeof n&&(n=n.trim()),"function"==typeof n||"string"==typeof n&&n.startsWith("function")&&n.endsWith("}")){if(t)return o?`"EXP_FUN${(n+"").replaceAll(/\s+/g," ")}EXP_FUN"`:`EXP_FUN${(n+"").replaceAll(/\s+/g," ")}EXP_FUN`;throw new Error}return n})).replaceAll(o?/\\"EXP_FUN|EXP_FUN\\"/g:/"EXP_FUN|EXP_FUN"/g,"")}function _loadConfigFile(e,t){const o=e.findIndex((e=>"loadConfig"===e.replace(/-/g,"")));return o>-1&&e[o+1]&&t.allowFileResources,{}}function _pairArgumentValue(e,t){const o={};for(let n=0;n{if(i.length-1===s){const i=t[++n];i||log(2,`[config] Missing value for the CLI '--${r}' argument. Using the default value.`),e[o]=i||null}else void 0===e[o]&&(e[o]={});return e[o]}),o)}return o}async function fetch(e,t={}){return new Promise(((o,n)=>{_getProtocolModule(e).get(e,t,(e=>{let t="";e.on("data",(e=>{t+=e})),e.on("end",(()=>{t||n("Nothing was fetched from the URL."),e.text=t,o(e)}))})).on("error",(e=>{n(e)}))}))}function _getProtocolModule(e){return e.startsWith("https")?https:http}class ExportError extends Error{constructor(e,t){super(),this.message=e,this.stackMessage=e,t&&(this.statusCode=t)}setStatus(e){return this.statusCode=e,this}setError(e){return this.error=e,e.name&&(this.name=e.name),e.statusCode&&(this.statusCode=e.statusCode),e.stack&&(this.stackMessage=e.message,this.stack=e.stack),this}}const cache={cdnUrl:"https://code.highcharts.com",activeManifest:{},sources:"",hcVersion:""};async function checkAndUpdateCache(e,t){try{let o;const n=getCachePath(),r=path.join(n,"manifest.json"),i=path.join(n,"sources.js");if(!fs.existsSync(n)&&fs.mkdirSync(n,{recursive:!0}),!fs.existsSync(r)||e.forceFetch)log(3,"[cache] Fetching and caching Highcharts dependencies."),o=await _updateCache(e,t,i);else{let n=!1;const s=JSON.parse(fs.readFileSync(r),"utf8");if(s.modules&&Array.isArray(s.modules)){const e={};s.modules.forEach((t=>e[t]=1)),s.modules=e}const{coreScripts:a,moduleScripts:l,indicatorScripts:c}=e,p=a.length+l.length+c.length;s.version!==e.version?(log(2,"[cache] A Highcharts version mismatch in the cache, need to re-fetch."),n=!0):Object.keys(s.modules||{}).length!==p?(log(2,"[cache] The cache and the requested modules do not match, need to re-fetch."),n=!0):n=(l||[]).some((e=>{if(!s.modules[e])return log(2,`[cache] The ${e} is missing in the cache, need to re-fetch.`),!0})),n?o=await _updateCache(e,t,i):(log(3,"[cache] Dependency cache is up to date, proceeding."),cache.sources=fs.readFileSync(i,"utf8"),o=s.modules,cache.hcVersion=extractVersion(cache.sources))}await _saveConfigToManifest(e,o)}catch(e){throw new ExportError("[cache] Could not configure cache and create or update the config manifest.",500).setError(e)}}function getHighchartsVersion(){return cache.hcVersion}async function updateHighchartsVersion(e){const t=getOptions();t.highcharts.version=e,await checkAndUpdateCache(t.highcharts,t.server.proxy)}function extractVersion(e){return e.substring(0,e.indexOf("*/")).replace("/*","").replace("*/","").replace(/\n/g,"").trim()}function extractModuleName(e){return e.replace(/(.*)\/|(.*)modules\/|stock\/(.*)indicators\/|maps\/(.*)modules\//gi,"")}function getCachePath(){return getAbsolutePath(getOptions().highcharts.cachePath)}async function _fetchAndProcessScript(e,t,o,n=!1){e.endsWith(".js")&&(e=e.substring(0,e.length-3)),log(4,`[cache] Fetching script - ${e}.js`);const r=await fetch(`${e}.js`,t);if(200===r.statusCode&&"string"==typeof r.text){if(o){o[extractModuleName(e)]=1}return r.text}if(n)throw new ExportError(`[cache] Could not fetch the ${e}.js. The script might not exist in the requested version (status code: ${r.statusCode}).`,404).setError(r);log(2,`[cache] Could not fetch the ${e}.js. The script might not exist in the requested version.`)}async function _saveConfigToManifest(e,t={}){const o={version:e.version,modules:t};cache.activeManifest=o,log(3,"[cache] Writing a new manifest.");try{fs.writeFileSync(path.join(getCachePath(),"manifest.json"),JSON.stringify(o),"utf8")}catch(e){throw new ExportError("[cache] Error writing the cache manifest.",500).setError(e)}}async function _fetchScripts(e,t,o,n,r){let i;const s=n.host,a=n.port;if(s&&a)try{i=new httpsProxyAgent.HttpsProxyAgent({host:s,port:a})}catch(e){throw new ExportError("[cache] Could not create a Proxy Agent.",500).setError(e)}const l=i?{agent:i,timeout:n.timeout}:{},c=[...e.map((e=>_fetchAndProcessScript(`${e}`,l,r,!0))),...t.map((e=>_fetchAndProcessScript(`${e}`,l,r))),...o.map((e=>_fetchAndProcessScript(`${e}`,l)))];return(await Promise.all(c)).join(";\n")}async function _updateCache(e,t,o){const n="latest"===e.version?null:`${e.version}`,r=e.cdnUrl||cache.cdnUrl;try{const i={};return log(3,`[cache] Updating cache version to Highcharts: ${n||"latest"}.`),cache.sources=await _fetchScripts([...e.coreScripts.map((e=>n?`${r}/${n}/${e}`:`${r}/${e}`))],[...e.moduleScripts.map((e=>"map"===e?n?`${r}/maps/${n}/modules/${e}`:`${r}/maps/modules/${e}`:n?`${r}/${n}/modules/${e}`:`${r}/modules/${e}`)),...e.indicatorScripts.map((e=>n?`${r}/stock/${n}/indicators/${e}`:`${r}/stock/indicators/${e}`))],e.customScripts,t,i),cache.hcVersion=extractVersion(cache.sources),fs.writeFileSync(o,cache.sources),i}catch(e){throw new ExportError("[cache] Unable to update the local Highcharts cache.",500).setError(e)}}function setupHighcharts(){Highcharts.animObject=function(){return{duration:0}}}async function createChart(e,t){const{getOptions:o,setOptions:n,merge:r,wrap:i}=Highcharts;Highcharts.setOptionsObj=r(!1,{},o()),window.isRenderComplete=!1,i(Highcharts.Chart.prototype,"init",(function(e,t,o){((t=r(t,{exporting:{enabled:!1},plotOptions:{series:{label:{enabled:!1}}},tooltip:{}})).series||[]).forEach((function(e){e.animation=!1})),window.onHighchartsRender||(window.onHighchartsRender=Highcharts.addEvent(this,"render",(()=>{window.isRenderComplete=!0}))),e.apply(this,[t,o])})),i(Highcharts.Series.prototype,"init",(function(e,t,o){e.apply(this,[t,o])}));const s={chart:{animation:!1,height:e.height,width:e.width},exporting:{enabled:!1}},a=new Function(`return ${e.instr}`)(),l=new Function(`return ${e.themeOptions}`)(),c=new Function(`return ${e.globalOptions}`)(),p=r(!1,l,a,s),u=t.callback?new Function(`return ${t.callback}`)():null;t.customCode&&new Function("options",t.customCode)(a),c&&n(c),Highcharts[e.constr]("container",p,u);const g=o();for(const e in g)"function"!=typeof g[e]&&delete g[e];n(Highcharts.setOptionsObj),Highcharts.setOptionsObj={}}const template=fs.readFileSync(path.join(__dirname$1,"templates","template.html"),"utf8");let browser=null;async function createBrowser(e){const{debug:t,other:o}=getOptions(),{enable:n,...r}=t,i={headless:!o.browserShellMode||"shell",userDataDir:"tmp",args:e||[],handleSIGINT:!1,handleSIGTERM:!1,handleSIGHUP:!1,waitForInitialPage:!1,defaultViewport:null,...n&&r};if(!browser){let e=0;const t=async()=>{try{log(3,`[browser] Attempting to get a browser instance (try ${++e}).`),browser=await puppeteer.launch(i)}catch(o){if(logWithStack(1,o,"[browser] Failed to launch a browser instance."),!(e<25))throw o;log(3,`[browser] Retry to open a browser (${e} out of 25).`),await new Promise((e=>setTimeout(e,4e3))),await t()}};try{await t(),"shell"===i.headless&&log(3,"[browser] Launched browser in shell mode."),n&&log(3,"[browser] Launched browser in debug mode.")}catch(e){throw new ExportError("[browser] Maximum retries to open a browser instance reached.",500).setError(e)}if(!browser)throw new ExportError("[browser] Cannot find a browser to open.",500)}return browser}async function closeBrowser(){browser&&browser.connected&&await browser.close(),browser=null,log(4,"[browser] Closed the browser.")}async function newPage(e){if(!browser||!browser.connected)throw new ExportError("[browser] Browser is not yet connected.",500);if(e.page=await browser.newPage(),await e.page.setCacheEnabled(!1),await _setPageContent(e.page),_setPageEvents(e.page),!e.page||e.page.isClosed())throw new ExportError("[browser] The page is invalid or closed.",400)}async function clearPage(e,t=!1){try{if(e.page&&!e.page.isClosed())return t?(await e.page.goto("about:blank",{waitUntil:"domcontentloaded"}),await _setPageContent(e.page)):await e.page.evaluate((()=>{document.body.innerHTML='
'})),!0}catch(t){logWithStack(2,t,`[pool] Pool resource [${e.id}] - Content of the page could not be cleared.`),e.workCount=getOptions().pool.workLimit+1}return!1}async function addPageResources(e,t){const o=[],n=t.resources;if(n){const r=[];if(n.js&&r.push({content:n.js}),n.files)for(const e of n.files){const t=!e.startsWith("http");r.push(t?{content:fs.readFileSync(getAbsolutePath(e),"utf8")}:{url:e})}for(const t of r)try{o.push(await e.addScriptTag(t))}catch(e){logWithStack(2,e,"[browser] The JS resource cannot be loaded.")}r.length=0;const i=[];if(n.css){let r=n.css.match(/@import\s*([^;]*);/g);if(r)for(let e of r)e&&(e=e.replace("url(","").replace("@import","").replace(/"/g,"").replace(/'/g,"").replace(/;/,"").replace(/\)/g,"").trim(),e.startsWith("http")?i.push({url:e}):t.allowFileResources&&i.push({path:path.join(__dirname$1,e)}));i.push({content:n.css.replace(/@import\s*([^;]*);/g,"")||" "});for(const t of i)try{o.push(await e.addStyleTag(t))}catch(e){logWithStack(2,e,"[browser] The CSS resource cannot be loaded.")}i.length=0}}return o}async function clearPageResources(e,t){try{for(const e of t)await e.dispose();await e.evaluate((()=>{if("undefined"!=typeof Highcharts){const e=Highcharts.charts;if(Array.isArray(e)&&e.length)for(const t of e)t&&t.destroy(),Highcharts.charts.shift()}const[...e]=document.getElementsByTagName("script"),[,...t]=document.getElementsByTagName("style"),[...o]=document.getElementsByTagName("link");for(const n of[...e,...t,...o])n.remove()}))}catch(e){logWithStack(2,e,"[browser] Could not clear page's resources.")}}async function _setPageContent(e){await e.setContent(template,{waitUntil:"domcontentloaded"}),await e.addScriptTag({path:path.join(getCachePath(),"sources.js")}),await e.evaluate(setupHighcharts)}function _setPageEvents(e){const{debug:t}=getOptions();e.on("pageerror",(async()=>{e.isClosed()})),t.enable&&t.listenToConsole&&e.on("console",(e=>{console.log(`[debug] ${e.text()}`)}))}var cssTemplate=()=>"\n\nhtml, body {\n margin: 0;\n padding: 0;\n box-sizing: border-box;\n}\n\n#table-div, #sliders, #datatable, #controls, .ld-row {\n display: none;\n height: 0;\n}\n\n#chart-container {\n box-sizing: border-box;\n margin: 0;\n overflow: auto;\n font-size: 0;\n}\n\n#chart-container > figure, div {\n margin-top: 0 !important;\n margin-bottom: 0 !important;\n}\n\n",svgTemplate=e=>`\n\n\n \n \n Highcharts Export\n \n \n \n
\n ${e}\n
\n \n\n\n`;async function puppeteerExport(e,t,o){const n=[];try{let r=!1;if(t.svg){if(log(4,"[export] Treating as SVG input."),"svg"===t.type)return t.svg;r=!0,await e.setContent(svgTemplate(t.svg),{waitUntil:"domcontentloaded"})}else log(4,"[export] Treating as JSON config."),await e.evaluate(createChart,t,o);n.push(...await addPageResources(e,o));const i=r?await e.evaluate((e=>{const t=document.querySelector("#chart-container svg:first-of-type"),o=t.height.baseVal.value*e,n=t.width.baseVal.value*e;return document.body.style.zoom=e,document.body.style.margin="0px",{chartHeight:o,chartWidth:n}}),parseFloat(t.scale)):await e.evaluate((()=>{const{chartHeight:e,chartWidth:t}=window.Highcharts.charts[0];return document.body.style.zoom=1,{chartHeight:e,chartWidth:t}})),{x:s,y:a}=await _getClipRegion(e),l=Math.abs(Math.ceil(i.chartHeight||t.height)),c=Math.abs(Math.ceil(i.chartWidth||t.width));let p;switch(await e.setViewport({height:l,width:c,deviceScaleFactor:r?1:parseFloat(t.scale)}),t.type){case"svg":p=await _createSVG(e);break;case"png":case"jpeg":p=await _createImage(e,t.type,{width:c,height:l,x:s,y:a},t.rasterizationTimeout);break;case"pdf":p=await _createPDF(e,l,c,t.rasterizationTimeout);break;default:throw new ExportError(`[export] Unsupported output format: ${t.type}.`,400)}return await clearPageResources(e,n),p}catch(t){return await clearPageResources(e,n),t}}async function _getClipRegion(e){return e.$eval("#chart-container",(e=>{const{x:t,y:o,width:n,height:r}=e.getBoundingClientRect();return{x:t,y:o,width:n,height:Math.trunc(r>1?r:500)}}))}async function _createSVG(e){return e.$eval("#container svg:first-of-type",(e=>e.outerHTML))}async function _createImage(e,t,o,n){return Promise.race([e.screenshot({type:t,clip:o,encoding:"base64",fullPage:!1,optimizeForSpeed:!0,captureBeyondViewport:!0,..."png"!==t?{quality:80}:{},omitBackground:"png"==t}),new Promise(((e,t)=>setTimeout((()=>t(new ExportError("Rasterization timeout",408))),n||1500)))])}async function _createPDF(e,t,o,n){return await e.emulateMediaType("screen"),e.pdf({height:t+1,width:o,encoding:"base64",timeout:n||1500})}let pool=null;const poolStats={exportsAttempted:0,exportsPerformed:0,exportsDropped:0,exportsFromSvg:0,exportsFromOptions:0,exportsFromSvgAttempts:0,exportsFromOptionsAttempts:0,timeSpent:0,timeSpentAverage:0};async function initPool(e,t){await createBrowser(t);try{if(log(3,`[pool] Initializing pool with workers: min ${e.minWorkers}, max ${e.maxWorkers}.`),pool)return void log(4,"[pool] Already initialized, please kill it before creating a new one.");e.minWorkers>e.maxWorkers&&(e.minWorkers=e.maxWorkers),pool=new tarn.Pool({..._factory(e),min:e.minWorkers,max:e.maxWorkers,acquireTimeoutMillis:e.acquireTimeout,createTimeoutMillis:e.createTimeout,destroyTimeoutMillis:e.destroyTimeout,idleTimeoutMillis:e.idleTimeout,createRetryIntervalMillis:e.createRetryInterval,reapIntervalMillis:e.reaperInterval,propagateCreateError:!1}),pool.on("release",(async e=>{const t=await clearPage(e,!1);log(4,`[pool] Pool resource [${e.id}] - Releasing a worker. Clear page status: ${t}.`)})),pool.on("destroySuccess",((e,t)=>{log(4,`[pool] Pool resource [${t.id}] - Destroyed a worker successfully.`),t.page=null}));const t=[];for(let o=0;o{pool.release(e)})),log(3,"[pool] The pool is ready"+(t.length?` with ${t.length} initial resources waiting.`:"."))}catch(e){throw new ExportError("[pool] Could not configure and create the pool of workers.",500).setError(e)}}async function killPool(){if(log(3,"[pool] Killing pool with all workers and closing browser."),pool){for(const e of pool.used)pool.release(e.resource);pool.destroyed||(await pool.destroy(),log(4,"[pool] Destroyed the pool of resources.")),pool=null}await closeBrowser()}async function postWork(e){let t;try{if(log(4,"[pool] Work received, starting to process."),++poolStats.exportsAttempted,e.pool.benchmarking&&getPoolInfo(),!pool)throw new ExportError("[pool] Work received, but pool has not been started.",500);const o=measureTime();try{log(4,"[pool] Acquiring a worker handle."),t=await pool.acquire().promise,e.server.benchmarking&&log(5,"[benchmark] "+(e.requestId?`Request [${e.requestId}] - `:""),`Acquiring a worker handle took ${o()}ms.`)}catch(t){throw new ExportError(`[pool] ${e.requestId?`Request [${e.requestId}] - `:""}Error encountered when acquiring an available entry: ${o()}ms.`,400).setError(t)}if(log(4,"[pool] Acquired a worker handle."),!t.page)throw t.workCount=e.pool.workLimit+1,new ExportError("[pool] Resolved worker page is invalid: the pool setup is wonky.",400);const n=getNewDateTime();log(4,`[pool] Pool resource [${t.id}] - Starting work on this pool entry.`);const r=measureTime(),i=await puppeteerExport(t.page,e.export,e.customLogic);if(i instanceof Error)throw"Rasterization timeout"===i.message&&(t.workCount=e.pool.workLimit+1,t.page=null),"TimeoutError"===i.name||"Rasterization timeout"===i.message?new ExportError(`[pool] ${e.requestId?`Request [${e.requestId}] - `:""}Rasterization timeout: your chart may be too complex or large, and failed to render within the allotted time.`).setError(i):new ExportError(`[pool] ${e.requestId?`Request [${e.requestId}] - `:""}Error encountered during export: ${r()}ms.`).setError(i);e.server.benchmarking&&log(5,"[benchmark] "+(e.requestId?`Request [${e.requestId}] - `:""),`Exporting a chart sucessfully took ${r()}ms.`),pool.release(t);const s=getNewDateTime()-n;return poolStats.timeSpent+=s,poolStats.timeSpentAverage=poolStats.timeSpent/++poolStats.exportsPerformed,log(4,`[pool] Work completed in ${s}ms.`),{result:i,options:e}}catch(e){throw++poolStats.exportsDropped,t&&pool.release(t),e}}function getPoolStats(){return poolStats}function getPoolInfoJSON(){return{min:pool.min,max:pool.max,used:pool.numUsed(),available:pool.numFree(),allCreated:pool.numUsed()+pool.numFree(),pendingAcquires:pool.numPendingAcquires(),pendingCreates:pool.numPendingCreates(),pendingValidations:pool.numPendingValidations(),pendingDestroys:pool.pendingDestroys.length,absoluteAll:pool.numUsed()+pool.numFree()+pool.numPendingAcquires()+pool.numPendingCreates()+pool.numPendingValidations()+pool.pendingDestroys.length}}function getPoolInfo(){const{min:e,max:t,used:o,available:n,allCreated:r,pendingAcquires:i,pendingCreates:s,pendingValidations:a,pendingDestroys:l,absoluteAll:c}=getPoolInfoJSON();log(5,`[pool] The minimum number of resources allowed by pool: ${e}.`),log(5,`[pool] The maximum number of resources allowed by pool: ${t}.`),log(5,`[pool] The number of used resources: ${o}.`),log(5,`[pool] The number of free resources: ${n}.`),log(5,`[pool] The number of all created (used and free) resources: ${r}.`),log(5,`[pool] The number of resources waiting to be acquired: ${i}.`),log(5,`[pool] The number of resources waiting to be created: ${s}.`),log(5,`[pool] The number of resources waiting to be validated: ${a}.`),log(5,`[pool] The number of resources waiting to be destroyed: ${l}.`),log(5,`[pool] The number of all resources: ${c}.`)}function _factory(e){return{create:async()=>{const t={id:uuid.v4(),workCount:Math.round(Math.random()*(e.workLimit/2))};try{const e=getNewDateTime();return await newPage(t),log(3,`[pool] Pool resource [${t.id}] - Successfully created a worker, took ${getNewDateTime()-e}ms.`),t}catch(e){throw log(3,`[pool] Pool resource [${t.id}] - Error encountered when creating a new page.`),e}},validate:async t=>t.page?t.page.isClosed()?(log(3,`[pool] Pool resource [${t.id}] - Validation failed (page is closed or invalid).`),!1):t.page.mainFrame().detached?(log(3,`[pool] Pool resource [${t.id}] - Validation failed (page's frame is detached).`),!1):!(e.workLimit&&++t.workCount>e.workLimit)||(log(3,`[pool] Pool resource [${t.id}] - Validation failed (exceeded the ${e.workLimit} works per resource limit).`),!1):(log(3,`[pool] Pool resource [${t.id}] - Validation failed (no valid page is found).`),!1),destroy:async e=>{if(log(3,`[pool] Pool resource [${e.id}] - Destroying a worker.`),e.page&&!e.page.isClosed())try{e.page.removeAllListeners("pageerror"),e.page.removeAllListeners("console"),e.page.removeAllListeners("framedetached"),await e.page.close()}catch(t){throw log(3,`[pool] Pool resource [${e.id}] - Page could not be closed upon destroying.`),t}}}}function sanitize(e){const t=new jsdom.JSDOM("").window;return DOMPurify(t).sanitize(e,{ADD_TAGS:["foreignObject"]})}let allowCodeExecution=!1;async function singleExport(e){if(!e||!e.export)throw new ExportError("[chart] No expected `export` options were found. Please provide one of the following options: `infile`, `instr`, `options`, or `svg` to generate a valid image.",400);await startExport({export:e.export,customLogic:e.customLogic},(async(e,t)=>{if(e)throw e;const{b64:o,outfile:n,type:r}=t.options.export;try{o?fs.writeFileSync(`${n.split(".").shift()||"chart"}.txt`,getBase64(t.result,r)):fs.writeFileSync(n||`chart.${r}`,"svg"!==r?Buffer.from(t.result,"base64"):t.result)}catch(e){throw new ExportError("[chart] Error while saving a chart.",500).setError(e)}await killPool()}))}async function batchExport(e){if(!(e&&e.export&&e.export.batch))throw new ExportError("[chart] No expected `export` options were found. Please provide the `batch` option to generate valid images.",400);{const t=[];for(let o of e.export.batch.split(";")||[])o=o.split("="),2===o.length?t.push(startExport({export:{...e.export,infile:o[0],outfile:o[1]},customLogic:e.customLogic},((e,t)=>{if(e)throw e;const{b64:o,outfile:n,type:r}=t.options.export;try{o?fs.writeFileSync(`${n.split(".").shift()||"chart"}.txt`,getBase64(t.result,r)):fs.writeFileSync(n,"svg"!==r?Buffer.from(t.result,"base64"):t.result)}catch(e){throw new ExportError("[chart] Error while saving a chart.",500).setError(e)}}))):log(2,"[chart] No correct pair found for the batch export.");const o=await Promise.allSettled(t);await killPool(),o.forEach(((e,t)=>{e.reason&&logWithStack(1,e.reason,`[chart] Batch export number ${t+1} could not be correctly completed.`)}))}}async function startExport(e,t){try{if(!isObject(e))throw new ExportError("[chart] Incorrect value of the provided `exportingOptions`. Needs to be an object.",400);const o=mergeOptions(deepCopy(getOptions()),{export:e.export,customLogic:e.customLogic}),n=o.export;if(log(4,"[chart] Starting the exporting process."),null!==n.infile){let e;log(4,"[chart] Attempting to export from a file input.");try{e=fs.readFileSync(getAbsolutePath(n.infile),"utf8")}catch(e){throw new ExportError("[chart] Error loading content from a file input.",400).setError(e)}if(n.infile.endsWith(".svg"))try{n.svg=validateOption("svg",e,!1)}catch(e){throw logZodIssues(1,e.issues,"[config] The `svg` option validation error"),e}else{if(!n.infile.endsWith(".json"))throw new ExportError("[chart] Incorrect value of the `infile` option.",400);try{n.instr=validateOption("instr",e,!1)}catch(e){throw logZodIssues(1,e.issues,"[config] The `instr` option validation error"),e}}}if(null!==n.svg){log(4,"[chart] Attempting to export from an SVG input."),++getPoolStats().exportsFromSvgAttempts;const e=await _exportFromSvg(sanitize(n.svg),o);return++getPoolStats().exportsFromSvg,t(null,e)}if(null!==n.instr||null!==n.options){log(4,"[chart] Attempting to export from options input."),++getPoolStats().exportsFromOptionsAttempts;const e=await _exportFromOptions(n.instr||n.options,o);return++getPoolStats().exportsFromOptions,t(null,e)}return t(new ExportError("[chart] No valid input specified. Check if at least one of the following parameters is correctly set: 'infile', 'instr', 'options', or 'svg'.",400))}catch(e){return t(e)}}function getAllowCodeExecution(){return allowCodeExecution}function setAllowCodeExecution(e){allowCodeExecution=e}async function _exportFromSvg(e,t){if("string"==typeof e&&(e.indexOf("=0||e.indexOf("=0))return log(4,"[chart] Parsing input as SVG."),t.export.svg=e,t.export.instr=null,t.export.options=null,_prepareExport(t);throw new ExportError("[chart] Not a correct SVG input.",400)}async function _exportFromOptions(e,t){log(4,"[chart] Parsing input from options.");const o=isAllowedConfig(e,!0,t.customLogic.allowCodeExecution);if(null===o||"string"!=typeof o||!o.startsWith("{")||!o.endsWith("}"))throw new ExportError("[chart] Invalid configuration provided - Only options configurations and SVG are allowed for this server. If this is your server, JavaScript custom code can be enabled by starting the server with the `allowCodeExecution` options set to true.",403);return t.export.instr=o,t.export.svg=null,_prepareExport(t)}async function _prepareExport(e){const{export:t,customLogic:o}=e;t.type=fixType(t.type,t.outfile),t.outfile=fixOutfile(t.type,t.outfile),t.constr=fixConstr(t.constr),log(3,`[chart] The custom logic is ${o.allowCodeExecution?"allowed":"disallowed"}.`),_handleCustomLogic(o,o.allowCodeExecution),_handleGlobalAndTheme(t,o.allowFileResources,o.allowCodeExecution),e.export={...t,..._findChartSize(t)};try{e=strictValidate(e)}catch(e){logZodIssues(1,e.issues,"[config] Final options validation error")}return postWork(e)}function _findChartSize(e){const{chart:t,exporting:o}=e.options||isAllowedConfig(e.instr)||!1,{chart:n,exporting:r}=isAllowedConfig(e.globalOptions)||!1,{chart:i,exporting:s}=isAllowedConfig(e.themeOptions)||!1,a=roundNumber(Math.max(.1,Math.min(e.scale||o?.scale||r?.scale||s?.scale||e.defaultScale||1,5)),2),l={height:e.height||o?.sourceHeight||t?.height||r?.sourceHeight||n?.height||s?.sourceHeight||i?.height||e.defaultHeight||400,width:e.width||o?.sourceWidth||t?.width||r?.sourceWidth||n?.width||s?.sourceWidth||i?.width||e.defaultWidth||600,scale:a};for(let[e,t]of Object.entries(l))l[e]="string"==typeof t?+t.replace(/px|%/gi,""):t;return l}function _handleCustomLogic(e,t){if(t){if("string"==typeof e.resources)e.resources=_handleResources(e.resources,e.allowFileResources,!0);else if(!e.resources)try{e.resources=_handleResources(fs.readFileSync(getAbsolutePath("resources.json"),"utf8"),e.allowFileResources,!0)}catch(e){log(2,"[chart] Unable to load the default `resources.json` file.")}try{e.customCode=wrapAround(e.customCode,e.allowFileResources)}catch(t){logWithStack(2,t,"[chart] The `customCode` cannot be loaded."),e.customCode=null}try{e.callback=wrapAround(e.callback,e.allowFileResources,!0)}catch(t){logWithStack(2,t,"[chart] The `callback` cannot be loaded."),e.callback=null}[null,void 0].includes(e.customCode)&&log(3,"[chart] No value for the `customCode` option found."),[null,void 0].includes(e.callback)&&log(3,"[chart] No value for the `callback` option found."),[null,void 0].includes(e.resources)&&log(3,"[chart] No value for the `resources` option found.")}else if(e.callback||e.resources||e.customCode)throw e.callback=null,e.resources=null,e.customCode=null,new ExportError("[chart] The 'callback', 'resources', and 'customCode' options have been disabled for this server.",403)}function _handleResources(e=null,t,o){const n=["js","css","files"];let r=e,i=!1;if(t&&e.endsWith(".json"))try{r=isAllowedConfig(fs.readFileSync(getAbsolutePath(e),"utf8"),!1,o)}catch{return null}else r=isAllowedConfig(e,!1,o),r&&!t&&delete r.files;for(const e in r)n.includes(e)?i||(i=!0):delete r[e];return i?(r.files&&(r.files=r.files.map((e=>e.trim())),(!r.files||r.files.length<=0)&&delete r.files),r):null}function _handleGlobalAndTheme(e,t,o){["globalOptions","themeOptions"].forEach((n=>{try{e[n]&&(t&&"string"==typeof e[n]&&e[n].endsWith(".json")?e[n]=isAllowedConfig(fs.readFileSync(getAbsolutePath(e[n]),"utf8"),!0,o):e[n]=isAllowedConfig(e[n],!0,o))}catch(t){logWithStack(2,t,`[chart] The \`${n}\` cannot be loaded.`),e[n]=null}})),[null,void 0].includes(e.globalOptions)&&log(3,"[chart] No value for the `globalOptions` option found."),[null,void 0].includes(e.themeOptions)&&log(3,"[chart] No value for the `themeOptions` option found.")}const timerIds=[];function addTimer(e){timerIds.push(e)}function clearAllTimers(){log(4,"[timer] Clearing all registered intervals and timeouts.");for(const e of timerIds)clearInterval(e),clearTimeout(e)}function logErrorMiddleware(e,t,o,n){return logWithStack(1,e),"development"!==getOptions().other.nodeEnv&&delete e.stack,n(e)}function returnErrorMiddleware(e,t,o,n){const{message:r,stack:i}=e,s=e.statusCode||400;o.status(s).json({statusCode:s,message:r,stack:i})}function errorMiddleware(e){e.use(logErrorMiddleware),e.use(returnErrorMiddleware)}function rateLimitingMiddleware(e,t){try{if(t.enable){const o="Too many requests, you have been rate limited. Please try again later.",n={window:t.window||1,maxRequests:t.maxRequests||30,delay:t.delay||0,trustProxy:t.trustProxy||!1,skipKey:t.skipKey||null,skipToken:t.skipToken||null};n.trustProxy&&e.enable("trust proxy");const r=rateLimit({windowMs:60*n.window*1e3,limit:n.maxRequests,delayMs:n.delay,handler:(e,t)=>{t.format({json:()=>{t.status(429).send({message:o})},default:()=>{t.status(429).send(o)}})},skip:e=>null!==n.skipKey&&null!==n.skipToken&&e.query.key===n.skipKey&&e.query.access_token===n.skipToken&&(log(4,"[rate limiting] Skipping rate limiter."),!0)});e.use(r),log(3,`[rate limiting] Enabled rate limiting with ${n.maxRequests} requests per ${n.window} minute for each IP, trusting proxy: ${n.trustProxy}.`)}}catch(e){throw new ExportError("[rate limiting] Could not configure and set the rate limiting options.",500).setError(e)}}function contentTypeMiddleware(e,t,o){try{const t=e.headers["content-type"]||"";if(!t.includes("application/json")&&!t.includes("application/x-www-form-urlencoded")&&!t.includes("multipart/form-data"))throw new ExportError("[validation] Content-Type must be application/json, application/x-www-form-urlencoded, or multipart/form-data.",415);return o()}catch(e){return o(e)}}function requestBodyMiddleware(e,t,o){try{const t=e.body,n=uuid.v4();if(!t||isObjectEmpty(t))throw log(2,`[validation] Request [${n}] - The request from ${e.headers["x-forwarded-for"]||e.connection.remoteAddress} was incorrect. Received payload is empty.`),new ExportError(`[validation] Request [${n}] - The request body is required. Please ensure that your Content-Type header is correct. Accepted types are 'application/json' and 'multipart/form-data'.`,400);const r=getAllowCodeExecution(),i=isAllowedConfig(t.instr||t.options||t.infile||t.data,!0,r);if(null===i&&!t.svg)throw log(2,`[validation] Request [${n}] - The request from ${e.headers["x-forwarded-for"]||e.connection.remoteAddress} was incorrect. Received payload is missing correct chart data for export: ${JSON.stringify(t)}.`),new ExportError(`Request [${n}] - [validation] No correct chart data found. Ensure that you are using either application/json or multipart/form-data headers. If sending JSON, make sure the chart data is in the 'infile', 'options', or 'data' attribute. If sending SVG, ensure it is in the 'svg' attribute.`,400);if(t.svg&&isPrivateRangeUrlFound(t.svg))throw new ExportError(`Request [${n}] - [validation] SVG potentially contain at least one forbidden URL in 'xlink:href' element. Please review the SVG content and ensure that all referenced URLs comply with security policies.`,400);try{e.validatedOptions=looseValidate({_requestId:n,export:{instr:i,svg:t.svg,outfile:t.outfile||`${e.params.filename||"chart"}.${fixType(t.type)}`,type:fixType(t.type,t.outfile),constr:fixConstr(t.constr),b64:t.b64,noDownload:t.noDownload,height:t.height,width:t.width,scale:t.scale,globalOptions:isAllowedConfig(t.globalOptions,!0,r),themeOptions:isAllowedConfig(t.themeOptions,!0,r)},customLogic:{allowCodeExecution:r,allowFileResources:!1,customCode:t.customCode,callback:t.callback,resources:isAllowedConfig(t.resources,!0,r)}})}catch(e){throw logZodIssues(1,e.issues,"[config] Request options validation error"),new ExportError("The provided options are not correct. Please check if your data is of the correct types.",400)}return o()}catch(e){return o(e)}}function validationMiddleware(e){e.post(["/","/:filename"],contentTypeMiddleware),e.post(["/","/:filename"],requestBodyMiddleware)}const reversedMime={png:"image/png",jpeg:"image/jpeg",gif:"image/gif",pdf:"application/pdf",svg:"image/svg+xml"};async function requestExport(e,t,o){try{const o=measureTime();let n=!1;e.socket.on("close",(e=>{e&&(n=!0)}));const r=e.validatedOptions,i=r.requestId;log(4,`[export] Request [${i}] - Got an incoming HTTP request.`),await startExport(r,((r,s)=>{if(e.socket.removeAllListeners("close"),n)log(3,`[export] Request [${i}] - The client closed the connection before the chart finished processing.`);else{if(r)throw r;if(!s||!s.result)throw log(2,`[export] Request [${i}] - Request from ${e.headers["x-forwarded-for"]||e.connection.remoteAddress} was incorrect. Received result is ${s.result}.`),new ExportError(`[export] Request [${i}] - Unexpected return of the export result from the chart generation. Please check your request data.`,400);if(s.result){log(3,`[export] Request [${i}] - The whole exporting process took ${o()}ms.`);const{type:e,b64:n,noDownload:r,outfile:a}=s.options.export;return n?t.send(getBase64(s.result,e)):(t.header("Content-Type",reversedMime[e]||"image/png"),r||t.attachment(a),"svg"===e?t.send(s.result):t.send(Buffer.from(s.result,"base64")))}}}))}catch(e){return o(e)}}function exportRoutes(e){e.post("/",requestExport),e.post("/:filename",requestExport)}const serverStartTime=new Date,packageFile=JSON.parse(fs.readFileSync(path.join(__dirname$1,"package.json"),"utf8")),successRates=[],recordInterval=6e4,windowSize=30;function _calculateMovingAverage(){return successRates.reduce(((e,t)=>e+t),0)/successRates.length}function _startSuccessRate(){return setInterval((()=>{const e=getPoolStats(),t=0===e.exportsAttempted?1:e.exportsPerformed/e.exportsAttempted*100;successRates.push(t),successRates.length>windowSize&&successRates.shift()}),recordInterval)}function healthRoutes(e){addTimer(_startSuccessRate()),e.get("/health",((e,t,o)=>{try{log(4,"[health] Returning server health.");const e=getPoolStats(),o=successRates.length,n=_calculateMovingAverage();t.send({status:"OK",bootTime:serverStartTime,uptime:`${Math.floor((getNewDateTime()-serverStartTime.getTime())/1e3/60)} minutes`,serverVersion:packageFile.version,highchartsVersion:getHighchartsVersion(),averageExportTime:e.timeSpentAverage,attemptedExports:e.exportsAttempted,performedExports:e.exportsPerformed,failedExports:e.exportsDropped,sucessRatio:e.exportsPerformed/e.exportsAttempted*100,pool:getPoolInfoJSON(),period:o,movingAverage:n,message:isNaN(n)||!successRates.length?"Too early to report. No exports made yet. Please check back soon.":`Last ${o} minutes had a success rate of ${n.toFixed(2)}%.`,svgExports:e.exportsFromSvg,jsonExports:e.exportsFromOptions,svgExportsAttempts:e.exportsFromSvgAttempts,jsonExportsAttempts:e.exportsFromOptionsAttempts})}catch(e){return o(e)}}))}function uiRoutes(e){e.get(getOptions().ui.route||"/",((e,t,o)=>{try{log(4,"[ui] Returning UI for the export."),t.sendFile(path.join(__dirname$1,"public","index.html"),{acceptRanges:!1})}catch(e){return o(e)}}))}function versionChangeRoutes(e){e.post("/version_change/:newVersion",(async(e,t,o)=>{try{log(4,"[version] Changing Highcharts version.");const o=envs.HIGHCHARTS_ADMIN_TOKEN;if(!o||!o.length)throw new ExportError("[version] The server is not configured to perform run-time version changes: HIGHCHARTS_ADMIN_TOKEN is not set.",401);const n=e.get("hc-auth");if(!n||n!==o)throw new ExportError("[version] Invalid or missing token: Set the token in the hc-auth header.",401);let r=e.params.newVersion;if(!r)throw new ExportError("[version] No new version supplied.",400);try{await updateHighchartsVersion(r)}catch(e){throw new ExportError(`[version] Version change: ${e.message}`,400).setError(e)}t.status(200).send({statusCode:200,highchartsVersion:getHighchartsVersion(),message:`Successfully updated Highcharts to version: ${r}.`})}catch(e){return o(e)}}))}const activeServers=new Map,app=express();async function startServer(e){try{const t=updateOptions({server:e});if(!(e=t.server).enable||!app)throw new ExportError("[server] Server cannot be started (not enabled or no correct Express app found).",500);const o=1024*e.uploadLimit*1024,n=multer.memoryStorage(),r=multer({storage:n,limits:{fieldSize:o}});if(app.disable("x-powered-by"),app.use(cors({methods:["POST","GET","OPTIONS"]})),app.use(((e,t,o)=>{t.set("Accept-Ranges","none"),o()})),app.use(express.json({limit:o})),app.use(express.urlencoded({extended:!0,limit:o})),app.use(r.none()),app.use(express.static(path.join(__dirname$1,"public"))),!e.ssl.force){const t=http.createServer(app);_attachServerErrorHandlers(t),t.listen(e.port,e.host,(()=>{activeServers.set(e.port,t),log(3,`[server] Started HTTP server on ${e.host}:${e.port}.`)}))}if(e.ssl.enable){let t,o;try{t=await promises.readFile(path.join(getAbsolutePath(e.ssl.certPath),"server.key"),"utf8"),o=await promises.readFile(path.join(getAbsolutePath(e.ssl.certPath),"server.crt"),"utf8")}catch(t){log(2,`[server] Unable to load key/certificate from the '${e.ssl.certPath}' path. Could not run secured layer server.`)}if(t&&o){const n=https.createServer({key:t,cert:o},app);_attachServerErrorHandlers(n),n.listen(e.ssl.port,e.host,(()=>{activeServers.set(e.ssl.port,n),log(3,`[server] Started HTTPS server on ${e.host}:${e.ssl.port}.`)}))}}rateLimitingMiddleware(app,e.rateLimiting),validationMiddleware(app),exportRoutes(app),healthRoutes(app),uiRoutes(app),versionChangeRoutes(app),errorMiddleware(app)}catch(e){throw new ExportError("[server] Could not configure and start the server.",500).setError(e)}}function closeServers(){if(activeServers.size>0){log(4,"[server] Closing all servers.");for(const[e,t]of activeServers)t.close((()=>{activeServers.delete(e),log(4,`[server] Closed server on port: ${e}.`)}))}}function getServers(){return activeServers}function getExpress(){return express}function getApp(){return app}function enableRateLimiting(e){const t=updateOptions({server:{rateLimiting:e}});rateLimitingMiddleware(app,t.server.rateLimitingOptions)}function use(e,...t){app.use(e,...t)}function get(e,...t){app.get(e,...t)}function post(e,...t){app.post(e,...t)}function _attachServerErrorHandlers(e){e.on("clientError",((e,t)=>{logWithStack(1,e,`[server] Client error: ${e.message}, destroying socket.`),t.destroy()})),e.on("error",(e=>{logWithStack(1,e,`[server] Server error: ${e.message}`)})),e.on("connection",(e=>{e.on("error",(e=>{logWithStack(1,e,`[server] Socket error: ${e.message}`)}))}))}var server={startServer:startServer,closeServers:closeServers,getServers:getServers,getExpress:getExpress,getApp:getApp,enableRateLimiting:enableRateLimiting,use:use,get:get,post:post};async function shutdownCleanUp(e=0){await Promise.allSettled([clearAllTimers(),closeServers(),killPool()]),process.exit(e)}async function initExport(e={}){const t=updateOptions(e,!0);setAllowCodeExecution(t.customLogic.allowCodeExecution),initLogging(t.logging),t.other.listenToProcessExits&&_attachProcessExitListeners(),await checkAndUpdateCache(t.highcharts,t.server.proxy),await initPool(t.pool,t.puppeteer.args)}function _attachProcessExitListeners(){log(3,"[process] Attaching exit listeners to the process."),process.on("exit",(e=>{log(4,`[process] Process exited with code ${e}.`)})),process.on("SIGINT",(async(e,t)=>{log(4,`[process] The ${e} event with code: ${t}.`),await shutdownCleanUp()})),process.on("SIGTERM",(async(e,t)=>{log(4,`[process] The ${e} event with code: ${t}.`),await shutdownCleanUp()})),process.on("SIGHUP",(async(e,t)=>{log(4,`[process] The ${e} event with code: ${t}.`),await shutdownCleanUp()})),process.on("uncaughtException",(async(e,t)=>{logWithStack(1,e,`[process] The ${t} error.`),await shutdownCleanUp(1)}))}var index={...server,getOptions:getOptions,setGlobalOptions:setGlobalOptions,mapToNewOptions:mapToNewOptions,initExport:initExport,singleExport:singleExport,batchExport:batchExport,startExport:startExport,killPool:killPool,shutdownCleanUp:shutdownCleanUp,log:log,logWithStack:logWithStack,logZodIssues:logZodIssues,setLogLevel:function(e){setLogLevel(updateOptions({logging:{level:e}}).logging.level)},enableConsoleLogging:function(e){enableConsoleLogging(updateOptions({logging:{toConsole:e}}).logging.toConsole)},enableFileLogging:function(e,t,o){const n=updateOptions({logging:{dest:e,file:t,toFile:o}});enableFileLogging(n.logging.dest,n.logging.file,n.logging.toFile)}};exports.default=index,exports.initExport=initExport; -//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguY2pzIiwic291cmNlcyI6WyIuLi9saWIvdXRpbHMuanMiLCIuLi9saWIvbG9nZ2VyLmpzIiwiLi4vbGliL3NjaGVtYXMvY29uZmlnLmpzIiwiLi4vbGliL3ZhbGlkYXRpb24uanMiLCIuLi9saWIvY29uZmlnLmpzIiwiLi4vbGliL2ZldGNoLmpzIiwiLi4vbGliL2Vycm9ycy9FeHBvcnRFcnJvci5qcyIsIi4uL2xpYi9jYWNoZS5qcyIsIi4uL2xpYi9oaWdoY2hhcnRzLmpzIiwiLi4vbGliL2Jyb3dzZXIuanMiLCIuLi90ZW1wbGF0ZXMvc3ZnRXhwb3J0L2Nzcy5qcyIsIi4uL3RlbXBsYXRlcy9zdmdFeHBvcnQvc3ZnRXhwb3J0LmpzIiwiLi4vbGliL2V4cG9ydC5qcyIsIi4uL2xpYi9wb29sLmpzIiwiLi4vbGliL3Nhbml0aXplLmpzIiwiLi4vbGliL2NoYXJ0LmpzIiwiLi4vbGliL3RpbWVyLmpzIiwiLi4vbGliL3NlcnZlci9taWRkbGV3YXJlcy9lcnJvci5qcyIsIi4uL2xpYi9zZXJ2ZXIvbWlkZGxld2FyZXMvcmF0ZUxpbWl0aW5nLmpzIiwiLi4vbGliL3NlcnZlci9taWRkbGV3YXJlcy92YWxpZGF0aW9uLmpzIiwiLi4vbGliL3NlcnZlci9yb3V0ZXMvZXhwb3J0LmpzIiwiLi4vbGliL3NlcnZlci9yb3V0ZXMvaGVhbHRoLmpzIiwiLi4vbGliL3NlcnZlci9yb3V0ZXMvdWkuanMiLCIuLi9saWIvc2VydmVyL3JvdXRlcy92ZXJzaW9uQ2hhbmdlLmpzIiwiLi4vbGliL3NlcnZlci9zZXJ2ZXIuanMiLCIuLi9saWIvcmVzb3VyY2VSZWxlYXNlLmpzIiwiLi4vbGliL2luZGV4LmpzIl0sInNvdXJjZXNDb250ZW50IjpbIi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXHJcblxyXG5IaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXJcclxuXHJcbkNvcHlyaWdodCAoYykgMjAxNi0yMDI1LCBIaWdoc29mdFxyXG5cclxuTGljZW5jZWQgdW5kZXIgdGhlIE1JVCBsaWNlbmNlLlxyXG5cclxuQWRkaXRpb25hbGx5IGEgdmFsaWQgSGlnaGNoYXJ0cyBsaWNlbnNlIGlzIHJlcXVpcmVkIGZvciB1c2UuXHJcblxyXG5TZWUgTElDRU5TRSBmaWxlIGluIHJvb3QgZm9yIGRldGFpbHMuXHJcblxyXG4qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xyXG5cclxuLyoqXHJcbiAqIEBvdmVydmlldyBUaGUgSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyIHV0aWxpdHkgbW9kdWxlIHByb3ZpZGVzXHJcbiAqIGEgY29tcHJlaGVuc2l2ZSBzZXQgb2YgaGVscGVyIGZ1bmN0aW9ucyBhbmQgY29uc3RhbnRzIGRlc2lnbmVkIHRvIHN0cmVhbWxpbmVcclxuICogYW5kIGVuaGFuY2UgdmFyaW91cyBvcGVyYXRpb25zIHJlcXVpcmVkIGZvciBIaWdoY2hhcnRzIGV4cG9ydCB0YXNrcy5cclxuICovXHJcblxyXG5pbXBvcnQgeyByZWFkRmlsZVN5bmMgfSBmcm9tICdmcyc7XHJcbmltcG9ydCB7IGlzQWJzb2x1dGUsIGpvaW4gfSBmcm9tICdwYXRoJztcclxuaW1wb3J0IHsgZmlsZVVSTFRvUGF0aCB9IGZyb20gJ3VybCc7XHJcblxyXG5jb25zdCBNQVhfQkFDS09GRl9BVFRFTVBUUyA9IDY7XHJcblxyXG4vLyBUaGUgZGlyZWN0b3J5IHBhdGhcclxuZXhwb3J0IGNvbnN0IF9fZGlybmFtZSA9IGZpbGVVUkxUb1BhdGgobmV3IFVSTCgnLi4vLicsIGltcG9ydC5tZXRhLnVybCkpO1xyXG5cclxuLyoqXHJcbiAqIENsZWFycyBhbmQgc3RhbmRhcmRpemVzIHRleHQgYnkgcmVwbGFjaW5nIG11bHRpcGxlIGNvbnNlY3V0aXZlIHdoaXRlc3BhY2VcclxuICogY2hhcmFjdGVycyB3aXRoIGEgc2luZ2xlIHNwYWNlIGFuZCB0cmltbWluZyBhbnkgbGVhZGluZyBvciB0cmFpbGluZ1xyXG4gKiB3aGl0ZXNwYWNlLlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gY2xlYXJUZXh0XHJcbiAqXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSB0ZXh0IC0gVGhlIGlucHV0IHRleHQgdG8gYmUgY2xlYXJlZC5cclxuICogQHBhcmFtIHtSZWdFeHB9IFtydWxlPS9cXHNcXHMrL2ddIC0gVGhlIHJlZ3VsYXIgZXhwcmVzc2lvbiBydWxlIHRvIG1hdGNoXHJcbiAqIG11bHRpcGxlIGNvbnNlY3V0aXZlIHdoaXRlc3BhY2UgY2hhcmFjdGVycy4gVGhlIGRlZmF1bHQgdmFsdWVcclxuICogaXMgdGhlICcvXFxzXFxzKy9nJyBSZWdFeHAuXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSBbcmVwbGFjZXI9JyAnXSAtIFRoZSBzdHJpbmcgdXNlZCB0byByZXBsYWNlIG11bHRpcGxlXHJcbiAqIGNvbnNlY3V0aXZlIHdoaXRlc3BhY2UgY2hhcmFjdGVycy4gVGhlIGRlZmF1bHQgdmFsdWUgaXMgdGhlICcgJyBzdHJpbmcuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtzdHJpbmd9IFRoZSBjbGVhcmVkIGFuZCBzdGFuZGFyZGl6ZWQgdGV4dC5cclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiBjbGVhclRleHQodGV4dCwgcnVsZSA9IC9cXHNcXHMrL2csIHJlcGxhY2VyID0gJyAnKSB7XHJcbiAgcmV0dXJuIHRleHQucmVwbGFjZUFsbChydWxlLCByZXBsYWNlcikudHJpbSgpO1xyXG59XHJcblxyXG4vKipcclxuICogQ3JlYXRlcyBhIGRlZXAgY29weSBvZiB0aGUgZ2l2ZW4gb2JqZWN0IG9yIGFycmF5LlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gZGVlcENvcHlcclxuICpcclxuICogQHBhcmFtIHsoT2JqZWN0fEFycmF5KX0gb2JqQXJyIC0gVGhlIG9iamVjdCBvciBhcnJheSB0byBiZSBkZWVwbHkgY29waWVkLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7KE9iamVjdHxBcnJheSl9IFRoZSBkZWVwIGNvcHkgb2YgdGhlIHByb3ZpZGVkIG9iamVjdCBvciBhcnJheS5cclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiBkZWVwQ29weShvYmpBcnIpIHtcclxuICAvLyBJZiB0aGUgYG9iakFycmAgaXMgbnVsbCBvciBub3Qgb2YgdGhlIGBvYmplY3RgIHR5cGUsIHJldHVybiBpdFxyXG4gIGlmIChvYmpBcnIgPT09IG51bGwgfHwgdHlwZW9mIG9iakFyciAhPT0gJ29iamVjdCcpIHtcclxuICAgIHJldHVybiBvYmpBcnI7XHJcbiAgfVxyXG5cclxuICAvLyBQcmVwYXJlIGVpdGhlciBhIG5ldyBhcnJheSBvciBhIG5ldyBvYmplY3RcclxuICBjb25zdCBvYmpBcnJDb3B5ID0gQXJyYXkuaXNBcnJheShvYmpBcnIpID8gW10gOiB7fTtcclxuXHJcbiAgLy8gUmVjdXJzaXZlbHkgY29weSBlYWNoIHByb3BlcnR5XHJcbiAgZm9yIChjb25zdCBrZXkgaW4gb2JqQXJyKSB7XHJcbiAgICBpZiAoT2JqZWN0LnByb3RvdHlwZS5oYXNPd25Qcm9wZXJ0eS5jYWxsKG9iakFyciwga2V5KSkge1xyXG4gICAgICBvYmpBcnJDb3B5W2tleV0gPSBkZWVwQ29weShvYmpBcnJba2V5XSk7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICAvLyBSZXR1cm4gdGhlIGNvcGllZCBvYmplY3RcclxuICByZXR1cm4gb2JqQXJyQ29weTtcclxufVxyXG5cclxuLyoqXHJcbiAqIEltcGxlbWVudHMgYW4gZXhwb25lbnRpYWwgYmFja29mZiBzdHJhdGVneSBmb3IgcmV0cnlpbmcgYSBmdW5jdGlvbiB1bnRpbFxyXG4gKiBhIGNlcnRhaW4gbnVtYmVyIG9mIGF0dGVtcHRzIGFyZSByZWFjaGVkLlxyXG4gKlxyXG4gKiBAYXN5bmNcclxuICogQGZ1bmN0aW9uIGV4cEJhY2tvZmZcclxuICpcclxuICogQHBhcmFtIHtGdW5jdGlvbn0gZm4gLSBUaGUgZnVuY3Rpb24gdG8gYmUgcmV0cmllZC5cclxuICogQHBhcmFtIHtudW1iZXJ9IFthdHRlbXB0PTBdIC0gVGhlIGN1cnJlbnQgYXR0ZW1wdCBudW1iZXIuIFRoZSBkZWZhdWx0IHZhbHVlXHJcbiAqIGlzIGAwYC5cclxuICogQHBhcmFtIHsuLi51bmtub3dufSBhcmdzIC0gQXJndW1lbnRzIHRvIGJlIHBhc3NlZCB0byB0aGUgZnVuY3Rpb24uXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtQcm9taXNlPHVua25vd24+fSBBIFByb21pc2UgdGhhdCByZXNvbHZlcyB0byB0aGUgcmVzdWx0XHJcbiAqIG9mIHRoZSBmdW5jdGlvbiBpZiBzdWNjZXNzZnVsLlxyXG4gKlxyXG4gKiBAdGhyb3dzIHtFcnJvcn0gVGhyb3dzIGFuIGBFcnJvcmAgaWYgdGhlIG1heGltdW0gbnVtYmVyIG9mIGF0dGVtcHRzXHJcbiAqIGlzIHJlYWNoZWQuXHJcbiAqL1xyXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gZXhwQmFja29mZihmbiwgYXR0ZW1wdCA9IDAsIC4uLmFyZ3MpIHtcclxuICB0cnkge1xyXG4gICAgLy8gVHJ5IHRvIGNhbGwgdGhlIGZ1bmN0aW9uXHJcbiAgICByZXR1cm4gYXdhaXQgZm4oLi4uYXJncyk7XHJcbiAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgIC8vIENhbGN1bGF0ZSBkZWxheSBpbiBtc1xyXG4gICAgY29uc3QgZGVsYXlJbk1zID0gMiAqKiBhdHRlbXB0ICogMTAwMDtcclxuXHJcbiAgICAvLyBJZiB0aGUgYXR0ZW1wdCBleGNlZWRzIHRoZSBtYXhpbXVtIGF0dGVtcHRzIG9mIHJlcGVhdCwgdGhyb3cgYW4gZXJyb3JcclxuICAgIGlmICgrK2F0dGVtcHQgPj0gTUFYX0JBQ0tPRkZfQVRURU1QVFMpIHtcclxuICAgICAgdGhyb3cgZXJyb3I7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gV2FpdCBnaXZlbiBhbW91bnQgb2YgdGltZVxyXG4gICAgYXdhaXQgbmV3IFByb21pc2UoKHJlc3BvbnNlKSA9PiBzZXRUaW1lb3V0KHJlc3BvbnNlLCBkZWxheUluTXMpKTtcclxuXHJcbiAgICAvLy8gVE8gRE86IENvcnJlY3RcclxuICAgIC8vIC8vIEluZm9ybWF0aW9uIGFib3V0IHRoZSByZXNvdXJjZSB0aW1lb3V0XHJcbiAgICAvLyBsb2coXHJcbiAgICAvLyAgIDMsXHJcbiAgICAvLyAgIGBbdXRpbHNdIFdhaXRlZCAke2RlbGF5SW5Nc31tcyB1bnRpbCBuZXh0IGNhbGwgZm9yIHRoZSByZXNvdXJjZSBvZiBJRDogJHthcmdzWzBdfS5gXHJcbiAgICAvLyApO1xyXG5cclxuICAgIC8vIFRyeSBhZ2FpblxyXG4gICAgcmV0dXJuIGV4cEJhY2tvZmYoZm4sIGF0dGVtcHQsIC4uLmFyZ3MpO1xyXG4gIH1cclxufVxyXG5cclxuLyoqXHJcbiAqIEFkanVzdHMgdGhlIGNvbnN0cnVjdG9yIG5hbWUgYnkgdHJhbnNmb3JtaW5nIGFuZCBub3JtYWxpemluZyBpdCBiYXNlZFxyXG4gKiBvbiBjb21tb24gY2hhcnQgdHlwZXMuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBmaXhDb25zdHJcclxuICpcclxuICogQHBhcmFtIHtzdHJpbmd9IGNvbnN0ciAtIFRoZSBvcmlnaW5hbCBjb25zdHJ1Y3RvciBuYW1lIHRvIGJlIGZpeGVkLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7c3RyaW5nfSBUaGUgY29ycmVjdGVkIGNvbnN0cnVjdG9yIG5hbWUsIG9yICdjaGFydCcgaWYgdGhlIGlucHV0XHJcbiAqIGlzIG5vdCByZWNvZ25pemVkLlxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIGZpeENvbnN0cihjb25zdHIpIHtcclxuICB0cnkge1xyXG4gICAgLy8gRml4IHRoZSBjb25zdHJ1Y3RvciBieSBsb3dlcmluZyBjYXNpbmdcclxuICAgIGNvbnN0IGZpeGVkQ29uc3RyID0gYCR7Y29uc3RyLnRvTG93ZXJDYXNlKCkucmVwbGFjZSgnY2hhcnQnLCAnJyl9Q2hhcnRgO1xyXG5cclxuICAgIC8vIEhhbmRsZSB0aGUgY2FzZSB3aGVyZSB0aGUgcmVzdWx0IGlzIGp1c3QgJ0NoYXJ0J1xyXG4gICAgaWYgKGZpeGVkQ29uc3RyID09PSAnQ2hhcnQnKSB7XHJcbiAgICAgIGZpeGVkQ29uc3RyLnRvTG93ZXJDYXNlKCk7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gUmV0dXJuIHRoZSBjb3JyZWN0ZWQgY29uc3RydWN0b3IsIG90aGVyd2lzZSBkZWZhdWx0IHRvICdjaGFydCdcclxuICAgIHJldHVybiBbJ2NoYXJ0JywgJ3N0b2NrQ2hhcnQnLCAnbWFwQ2hhcnQnLCAnZ2FudHRDaGFydCddLmluY2x1ZGVzKFxyXG4gICAgICBmaXhlZENvbnN0clxyXG4gICAgKVxyXG4gICAgICA/IGZpeGVkQ29uc3RyXHJcbiAgICAgIDogJ2NoYXJ0JztcclxuICB9IGNhdGNoIHtcclxuICAgIC8vIERlZmF1bHQgdG8gJ2NoYXJ0JyBpbiBjYXNlIG9mIGFueSBlcnJvclxyXG4gICAgcmV0dXJuICdjaGFydCc7XHJcbiAgfVxyXG59XHJcblxyXG4vKipcclxuICogRml4ZXMgdGhlIG91dGZpbGUgYmFzZWQgb24gcHJvdmlkZWQgdHlwZS5cclxuICpcclxuICogQGZ1bmN0aW9uIGZpeE91dGZpbGVcclxuICpcclxuICogQHBhcmFtIHtzdHJpbmd9IHR5cGUgLSBUaGUgb3JpZ2luYWwgZXhwb3J0IHR5cGUuXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSBvdXRmaWxlIC0gVGhlIGZpbGUgcGF0aCBvciBuYW1lLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7c3RyaW5nfSBUaGUgY29ycmVjdGVkIG91dGZpbGUuXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gZml4T3V0ZmlsZSh0eXBlLCBvdXRmaWxlKSB7XHJcbiAgLy8gR2V0IHRoZSBmaWxlIG5hbWUgZnJvbSB0aGUgYG91dGZpbGVgIG9wdGlvblxyXG4gIGNvbnN0IGZpbGVOYW1lID0gZ2V0QWJzb2x1dGVQYXRoKG91dGZpbGUgfHwgJ2NoYXJ0JylcclxuICAgIC5zcGxpdCgnLicpXHJcbiAgICAuc2hpZnQoKTtcclxuXHJcbiAgLy8gUmV0dXJuIGEgY29ycmVjdCBvdXRmaWxlXHJcbiAgcmV0dXJuIGAke2ZpbGVOYW1lfS4ke3R5cGV9YDtcclxufVxyXG5cclxuLyoqXHJcbiAqIEZpeGVzIHRoZSBleHBvcnQgdHlwZSBiYXNlZCBvbiBNSU1FIHR5cGVzIGFuZCBmaWxlIGV4dGVuc2lvbnMuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBmaXhUeXBlXHJcbiAqXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSB0eXBlIC0gVGhlIG9yaWdpbmFsIGV4cG9ydCB0eXBlLlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gW291dGZpbGU9bnVsbF0gLSBUaGUgZmlsZSBwYXRoIG9yIG5hbWUuIFRoZSBkZWZhdWx0IHZhbHVlXHJcbiAqIGlzIGBudWxsYC5cclxuICpcclxuICogQHJldHVybnMge3N0cmluZ30gVGhlIGNvcnJlY3RlZCBleHBvcnQgdHlwZS5cclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiBmaXhUeXBlKHR5cGUsIG91dGZpbGUgPSBudWxsKSB7XHJcbiAgLy8gTUlNRSB0eXBlc1xyXG4gIGNvbnN0IG1pbWVUeXBlcyA9IHtcclxuICAgICdpbWFnZS9wbmcnOiAncG5nJyxcclxuICAgICdpbWFnZS9qcGVnJzogJ2pwZWcnLFxyXG4gICAgJ2FwcGxpY2F0aW9uL3BkZic6ICdwZGYnLFxyXG4gICAgJ2ltYWdlL3N2Zyt4bWwnOiAnc3ZnJ1xyXG4gIH07XHJcblxyXG4gIC8vIEdldCBmb3JtYXRzXHJcbiAgY29uc3QgZm9ybWF0cyA9IE9iamVjdC52YWx1ZXMobWltZVR5cGVzKTtcclxuXHJcbiAgLy8gQ2hlY2sgaWYgdHlwZSBhbmQgb3V0ZmlsZSdzIGV4dGVuc2lvbnMgYXJlIHRoZSBzYW1lXHJcbiAgaWYgKG91dGZpbGUpIHtcclxuICAgIGNvbnN0IG91dFR5cGUgPSBvdXRmaWxlLnNwbGl0KCcuJykucG9wKCk7XHJcblxyXG4gICAgLy8gU3VwcG9ydCB0aGUgSlBHIHR5cGVcclxuICAgIGlmIChvdXRUeXBlID09PSAnanBnJykge1xyXG4gICAgICB0eXBlID0gJ2pwZWcnO1xyXG4gICAgfSBlbHNlIGlmIChmb3JtYXRzLmluY2x1ZGVzKG91dFR5cGUpICYmIHR5cGUgIT09IG91dFR5cGUpIHtcclxuICAgICAgdHlwZSA9IG91dFR5cGU7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICAvLyBSZXR1cm4gYSBjb3JyZWN0IHR5cGVcclxuICByZXR1cm4gbWltZVR5cGVzW3R5cGVdIHx8IGZvcm1hdHMuZmluZCgodCkgPT4gdCA9PT0gdHlwZSkgfHwgJ3BuZyc7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBDaGVja3MgaWYgdGhlIGdpdmVuIHBhdGggaXMgcmVsYXRpdmUgb3IgYWJzb2x1dGUgYW5kIHJldHVybnMgdGhlIGNvcnJlY3RlZCxcclxuICogYWJzb2x1dGUgcGF0aC5cclxuICpcclxuICogQGZ1bmN0aW9uIGlzQWJzb2x1dGVQYXRoXHJcbiAqXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSBwYXRoIC0gVGhlIHBhdGggdG8gYmUgY2hlY2tlZCBvbi5cclxuICpcclxuICogQHJldHVybnMge3N0cmluZ30gVGhlIGFic29sdXRlIHBhdGguXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gZ2V0QWJzb2x1dGVQYXRoKHBhdGgpIHtcclxuICByZXR1cm4gaXNBYnNvbHV0ZShwYXRoKSA/IHBhdGggOiBqb2luKF9fZGlybmFtZSwgcGF0aCk7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBDb252ZXJ0cyBpbnB1dCBkYXRhIHRvIGEgQmFzZTY0IHN0cmluZyBiYXNlZCBvbiB0aGUgZXhwb3J0IHR5cGUuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBnZXRCYXNlNjRcclxuICpcclxuICogQHBhcmFtIHtzdHJpbmd9IGlucHV0IC0gVGhlIGlucHV0IHRvIGJlIHRyYW5zZm9ybWVkIHRvIEJhc2U2NCBmb3JtYXQuXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSB0eXBlIC0gVGhlIG9yaWdpbmFsIGV4cG9ydCB0eXBlLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7c3RyaW5nfSBUaGUgQmFzZTY0IHN0cmluZyByZXByZXNlbnRhdGlvbiBvZiB0aGUgaW5wdXQuXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gZ2V0QmFzZTY0KGlucHV0LCB0eXBlKSB7XHJcbiAgLy8gRm9yIHBkZiBhbmQgc3ZnIHR5cGVzIHRoZSBpbnB1dCBtdXN0IGJlIHRyYW5zZm9ybWVkIHRvIEJhc2U2NCBmcm9tIGEgYnVmZmVyXHJcbiAgaWYgKHR5cGUgPT09ICdwZGYnIHx8IHR5cGUgPT0gJ3N2ZycpIHtcclxuICAgIHJldHVybiBCdWZmZXIuZnJvbShpbnB1dCwgJ3V0ZjgnKS50b1N0cmluZygnYmFzZTY0Jyk7XHJcbiAgfVxyXG5cclxuICAvLyBGb3IgcG5nIGFuZCBqcGVnIGlucHV0IGlzIGFscmVhZHkgYSBCYXNlNjQgc3RyaW5nXHJcbiAgcmV0dXJuIGlucHV0O1xyXG59XHJcblxyXG4vKipcclxuICogUmV0dXJucyBzdHJpbmdpZmllZCBkYXRlIHdpdGhvdXQgdGhlIEdNVCB0ZXh0IGluZm9ybWF0aW9uLlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gZ2V0TmV3RGF0ZVxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIGdldE5ld0RhdGUoKSB7XHJcbiAgLy8gR2V0IHJpZCBvZiB0aGUgR01UIHRleHQgaW5mb3JtYXRpb25cclxuICByZXR1cm4gbmV3IERhdGUoKS50b1N0cmluZygpLnNwbGl0KCcoJylbMF0udHJpbSgpO1xyXG59XHJcblxyXG4vKipcclxuICogUmV0dXJucyB0aGUgc3RvcmVkIHRpbWUgdmFsdWUgaW4gbWlsbGlzZWNvbmRzLlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gZ2V0TmV3RGF0ZVRpbWVcclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiBnZXROZXdEYXRlVGltZSgpIHtcclxuICByZXR1cm4gbmV3IERhdGUoKS5nZXRUaW1lKCk7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBDaGVja3MgaWYgdGhlIGdpdmVuIGl0ZW0gaXMgYW4gb2JqZWN0LlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gaXNPYmplY3RcclxuICpcclxuICogQHBhcmFtIHt1bmtub3dufSBpdGVtIC0gVGhlIGl0ZW0gdG8gYmUgY2hlY2tlZC5cclxuICpcclxuICogQHJldHVybnMge2Jvb2xlYW59IFRydWUgaWYgdGhlIGl0ZW0gaXMgYW4gb2JqZWN0LCBmYWxzZSBvdGhlcndpc2UuXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gaXNPYmplY3QoaXRlbSkge1xyXG4gIHJldHVybiBPYmplY3QucHJvdG90eXBlLnRvU3RyaW5nLmNhbGwoaXRlbSkgPT09ICdbb2JqZWN0IE9iamVjdF0nO1xyXG59XHJcblxyXG4vKipcclxuICogQ2hlY2tzIGlmIHRoZSBnaXZlbiBvYmplY3QgaXMgZW1wdHkuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBpc09iamVjdEVtcHR5XHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBpdGVtIC0gVGhlIG9iamVjdCB0byBiZSBjaGVja2VkLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7Ym9vbGVhbn0gVHJ1ZSBpZiB0aGUgb2JqZWN0IGlzIGVtcHR5LCBmYWxzZSBvdGhlcndpc2UuXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gaXNPYmplY3RFbXB0eShpdGVtKSB7XHJcbiAgcmV0dXJuIChcclxuICAgIHR5cGVvZiBpdGVtID09PSAnb2JqZWN0JyAmJlxyXG4gICAgIUFycmF5LmlzQXJyYXkoaXRlbSkgJiZcclxuICAgIGl0ZW0gIT09IG51bGwgJiZcclxuICAgIE9iamVjdC5rZXlzKGl0ZW0pLmxlbmd0aCA9PT0gMFxyXG4gICk7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBDaGVja3MgaWYgYSBwcml2YXRlIElQIHJhbmdlIFVSTCBpcyBmb3VuZCBpbiB0aGUgZ2l2ZW4gc3RyaW5nLlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gaXNQcml2YXRlUmFuZ2VVcmxGb3VuZFxyXG4gKlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gaXRlbSAtIFRoZSBzdHJpbmcgdG8gYmUgY2hlY2tlZCBmb3IgYSBwcml2YXRlIElQIHJhbmdlIFVSTC5cclxuICpcclxuICogQHJldHVybnMge2Jvb2xlYW59IFRydWUgaWYgYSBwcml2YXRlIElQIHJhbmdlIFVSTCBpcyBmb3VuZCwgZmFsc2Ugb3RoZXJ3aXNlLlxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIGlzUHJpdmF0ZVJhbmdlVXJsRm91bmQoaXRlbSkge1xyXG4gIGNvbnN0IHJlZ2V4UGF0dGVybnMgPSBbXHJcbiAgICAveGxpbms6aHJlZj1cIig/Omh0dHA6XFwvXFwvfGh0dHBzOlxcL1xcLyk/bG9jYWxob3N0XFxiLyxcclxuICAgIC94bGluazpocmVmPVwiKD86aHR0cDpcXC9cXC98aHR0cHM6XFwvXFwvKT8xMFxcLlxcZHsxLDN9XFwuXFxkezEsM31cXC5cXGR7MSwzfVxcYi8sXHJcbiAgICAveGxpbms6aHJlZj1cIig/Omh0dHA6XFwvXFwvfGh0dHBzOlxcL1xcLyk/MTI3XFwuXFxkezEsM31cXC5cXGR7MSwzfVxcLlxcZHsxLDN9XFxiLyxcclxuICAgIC94bGluazpocmVmPVwiKD86aHR0cDpcXC9cXC98aHR0cHM6XFwvXFwvKT8xNzJcXC4oMVs2LTldfDJbMC05XXwzWzAtMV0pXFwuXFxkezEsM31cXC5cXGR7MSwzfVxcYi8sXHJcbiAgICAveGxpbms6aHJlZj1cIig/Omh0dHA6XFwvXFwvfGh0dHBzOlxcL1xcLyk/MTkyXFwuMTY4XFwuXFxkezEsM31cXC5cXGR7MSwzfVxcYi9cclxuICBdO1xyXG5cclxuICByZXR1cm4gcmVnZXhQYXR0ZXJucy5zb21lKChwYXR0ZXJuKSA9PiBwYXR0ZXJuLnRlc3QoaXRlbSkpO1xyXG59XHJcblxyXG4vKipcclxuICogVXRpbGl0eSB0byBtZWFzdXJlIGVsYXBzZWQgdGltZSB1c2luZyB0aGUgTm9kZS5qcyBgcHJvY2Vzcy5ocnRpbWUoKWAgbWV0aG9kLlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gbWVhc3VyZVRpbWVcclxuICpcclxuICogQHJldHVybnMge0Z1bmN0aW9ufSBBIGZ1bmN0aW9uIHRvIGNhbGN1bGF0ZSB0aGUgZWxhcHNlZCB0aW1lIGluIG1pbGxpc2Vjb25kcy5cclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiBtZWFzdXJlVGltZSgpIHtcclxuICBjb25zdCBzdGFydCA9IHByb2Nlc3MuaHJ0aW1lLmJpZ2ludCgpO1xyXG4gIHJldHVybiAoKSA9PiBOdW1iZXIocHJvY2Vzcy5ocnRpbWUuYmlnaW50KCkgLSBzdGFydCkgLyAxMDAwMDAwO1xyXG59XHJcblxyXG4vKipcclxuICogUm91bmRzIGEgbnVtYmVyIHRvIHRoZSBzcGVjaWZpZWQgcHJlY2lzaW9uLlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gcm91bmROdW1iZXJcclxuICpcclxuICogQHBhcmFtIHtudW1iZXJ9IHZhbHVlIC0gVGhlIG51bWJlciB0byBiZSByb3VuZGVkLlxyXG4gKiBAcGFyYW0ge251bWJlcn0gcHJlY2lzaW9uIC0gVGhlIG51bWJlciBvZiBkZWNpbWFsIHBsYWNlcyB0byByb3VuZCB0by5cclxuICpcclxuICogQHJldHVybnMge251bWJlcn0gVGhlIHJvdW5kZWQgbnVtYmVyLlxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIHJvdW5kTnVtYmVyKHZhbHVlLCBwcmVjaXNpb24gPSAxKSB7XHJcbiAgY29uc3QgbXVsdGlwbGllciA9IE1hdGgucG93KDEwLCBwcmVjaXNpb24gfHwgMCk7XHJcbiAgcmV0dXJuIE1hdGgucm91bmQoK3ZhbHVlICogbXVsdGlwbGllcikgLyBtdWx0aXBsaWVyO1xyXG59XHJcblxyXG4vKipcclxuICogQ29udmVydHMgYSB2YWx1ZSB0byBhIGJvb2xlYW4uXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiB0b0Jvb2xlYW5cclxuICpcclxuICogQHBhcmFtIHt1bmtub3dufSBpdGVtIC0gVGhlIHZhbHVlIHRvIGJlIGNvbnZlcnRlZCB0byBhIGJvb2xlYW4uXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtib29sZWFufSBUaGUgYm9vbGVhbiByZXByZXNlbnRhdGlvbiBvZiB0aGUgaW5wdXQgdmFsdWUuXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gdG9Cb29sZWFuKGl0ZW0pIHtcclxuICByZXR1cm4gWydmYWxzZScsICd1bmRlZmluZWQnLCAnbnVsbCcsICdOYU4nLCAnMCcsICcnXS5pbmNsdWRlcyhpdGVtKVxyXG4gICAgPyBmYWxzZVxyXG4gICAgOiAhIWl0ZW07XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBXcmFwcyBjdXN0b20gY29kZSB0byBleGVjdXRlIGl0IHNhZmVseS5cclxuICpcclxuICogQGZ1bmN0aW9uIHdyYXBBcm91bmRcclxuICpcclxuICogQHBhcmFtIHtzdHJpbmd9IGN1c3RvbUNvZGUgLSBUaGUgY3VzdG9tIGNvZGUgdG8gYmUgd3JhcHBlZC5cclxuICogQHBhcmFtIHtib29sZWFufSBhbGxvd0ZpbGVSZXNvdXJjZXMgLSBGbGFnIHRvIGFsbG93IGxvYWRpbmcgY29kZSBmcm9tIGEgZmlsZS5cclxuICogQHBhcmFtIHtib29sZWFufSBbaXNDYWxsYmFjaz1mYWxzZV0gLSBGbGFnIHRoYXQgaW5kaWNhdGVzIHRoZSByZXR1cm5lZCBjb2RlXHJcbiAqIG11c3QgYmUgaW4gYSBjYWxsYmFjayBmb3JtYXQuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHsoc3RyaW5nfG51bGwpfSBUaGUgd3JhcHBlZCBjdXN0b20gY29kZSBvciBudWxsIGlmIHdyYXBwaW5nIGZhaWxzLlxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIHdyYXBBcm91bmQoY3VzdG9tQ29kZSwgYWxsb3dGaWxlUmVzb3VyY2VzLCBpc0NhbGxiYWNrID0gZmFsc2UpIHtcclxuICBpZiAoY3VzdG9tQ29kZSAmJiB0eXBlb2YgY3VzdG9tQ29kZSA9PT0gJ3N0cmluZycpIHtcclxuICAgIGN1c3RvbUNvZGUgPSBjdXN0b21Db2RlLnRyaW0oKTtcclxuXHJcbiAgICBpZiAoY3VzdG9tQ29kZS5lbmRzV2l0aCgnLmpzJykpIHtcclxuICAgICAgLy8gTG9hZCBhIGZpbGUgaWYgdGhlIGZpbGUgcmVzb3VyY2VzIGFyZSBhbGxvd2VkXHJcbiAgICAgIHJldHVybiBhbGxvd0ZpbGVSZXNvdXJjZXNcclxuICAgICAgICA/IHdyYXBBcm91bmQoXHJcbiAgICAgICAgICAgIHJlYWRGaWxlU3luYyhnZXRBYnNvbHV0ZVBhdGgoY3VzdG9tQ29kZSksICd1dGY4JyksXHJcbiAgICAgICAgICAgIGFsbG93RmlsZVJlc291cmNlcyxcclxuICAgICAgICAgICAgaXNDYWxsYmFja1xyXG4gICAgICAgICAgKVxyXG4gICAgICAgIDogbnVsbDtcclxuICAgIH0gZWxzZSBpZiAoXHJcbiAgICAgICFpc0NhbGxiYWNrICYmXHJcbiAgICAgIChjdXN0b21Db2RlLnN0YXJ0c1dpdGgoJ2Z1bmN0aW9uKCknKSB8fFxyXG4gICAgICAgIGN1c3RvbUNvZGUuc3RhcnRzV2l0aCgnZnVuY3Rpb24gKCknKSB8fFxyXG4gICAgICAgIGN1c3RvbUNvZGUuc3RhcnRzV2l0aCgnKCk9PicpIHx8XHJcbiAgICAgICAgY3VzdG9tQ29kZS5zdGFydHNXaXRoKCcoKSA9PicpKVxyXG4gICAgKSB7XHJcbiAgICAgIC8vIFRyZWF0IGEgZnVuY3Rpb24gYXMgYSBzZWxmLWludm9raW5nIGV4cHJlc3Npb25cclxuICAgICAgcmV0dXJuIGAoJHtjdXN0b21Db2RlfSkoKWA7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gT3IgcmV0dXJuIGFzIGEgc3RyaW5naWZpZWQgY29kZVxyXG4gICAgcmV0dXJuIGN1c3RvbUNvZGUucmVwbGFjZSgvOyQvLCAnJyk7XHJcbiAgfVxyXG59XHJcblxyXG5leHBvcnQgZGVmYXVsdCB7XHJcbiAgX19kaXJuYW1lLFxyXG4gIGNsZWFyVGV4dCxcclxuICBkZWVwQ29weSxcclxuICBleHBCYWNrb2ZmLFxyXG4gIGZpeENvbnN0cixcclxuICBmaXhPdXRmaWxlLFxyXG4gIGZpeFR5cGUsXHJcbiAgZ2V0QWJzb2x1dGVQYXRoLFxyXG4gIGdldEJhc2U2NCxcclxuICBnZXROZXdEYXRlLFxyXG4gIGdldE5ld0RhdGVUaW1lLFxyXG4gIGlzT2JqZWN0LFxyXG4gIGlzT2JqZWN0RW1wdHksXHJcbiAgaXNQcml2YXRlUmFuZ2VVcmxGb3VuZCxcclxuICBtZWFzdXJlVGltZSxcclxuICByb3VuZE51bWJlcixcclxuICB0b0Jvb2xlYW4sXHJcbiAgd3JhcEFyb3VuZFxyXG59O1xyXG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxyXG5cclxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXHJcblxyXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNSwgSGlnaHNvZnRcclxuXHJcbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cclxuXHJcbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxyXG5cclxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxyXG5cclxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cclxuXHJcbi8qKlxyXG4gKiBAb3ZlcnZpZXcgQSBtb2R1bGUgZm9yIG1hbmFnaW5nIGxvZ2dpbmcgZnVuY3Rpb25hbGl0eSB3aXRoIGN1c3RvbWl6YWJsZVxyXG4gKiBsb2cgbGV2ZWxzLCBjb25zb2xlIGFuZCBmaWxlIGxvZ2dpbmcgb3B0aW9ucywgYW5kIGVycm9yIGhhbmRsaW5nIHN1cHBvcnQuXHJcbiAqIFRoZSBtb2R1bGUgYWxzbyBlbnN1cmVzIHRoYXQgZmlsZS1iYXNlZCBsb2dzIGFyZSBzdG9yZWQgaW4gYSBzdHJ1Y3R1cmVkXHJcbiAqIGRpcmVjdG9yeSwgY3JlYXRpbmcgdGhlIG5lY2Vzc2FyeSBwYXRocyBhdXRvbWF0aWNhbGx5IGlmIHRoZXkgZG8gbm90IGV4aXN0LlxyXG4gKi9cclxuXHJcbmltcG9ydCB7IGFwcGVuZEZpbGUsIGV4aXN0c1N5bmMsIG1rZGlyU3luYyB9IGZyb20gJ2ZzJztcclxuaW1wb3J0IHsgam9pbiB9IGZyb20gJ3BhdGgnO1xyXG5cclxuaW1wb3J0IHsgZ2V0QWJzb2x1dGVQYXRoLCBnZXROZXdEYXRlIH0gZnJvbSAnLi91dGlscy5qcyc7XHJcblxyXG4vLyBUaGUgYXZhaWxhYmxlIGNvbG9yc1xyXG5jb25zdCBjb2xvcnMgPSBbJ3JlZCcsICd5ZWxsb3cnLCAnYmx1ZScsICdncmF5JywgJ2dyZWVuJ107XHJcblxyXG4vLyBUaGUgZGVmYXVsdCBsb2dnaW5nIGNvbmZpZ1xyXG5jb25zdCBsb2dnaW5nID0ge1xyXG4gIC8vIEZsYWdzIGZvciBsb2dnaW5nIHN0YXR1c1xyXG4gIHRvQ29uc29sZTogdHJ1ZSxcclxuICB0b0ZpbGU6IGZhbHNlLFxyXG4gIHBhdGhDcmVhdGVkOiBmYWxzZSxcclxuICAvLyBGdWxsIHBhdGggdG8gdGhlIGxvZyBmaWxlXHJcbiAgcGF0aFRvTG9nOiAnJyxcclxuICAvLyBMb2cgbGV2ZWxzXHJcbiAgbGV2ZWxzRGVzYzogW1xyXG4gICAge1xyXG4gICAgICB0aXRsZTogJ2Vycm9yJyxcclxuICAgICAgY29sb3I6IGNvbG9yc1swXVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdGl0bGU6ICd3YXJuaW5nJyxcclxuICAgICAgY29sb3I6IGNvbG9yc1sxXVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdGl0bGU6ICdub3RpY2UnLFxyXG4gICAgICBjb2xvcjogY29sb3JzWzJdXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0aXRsZTogJ3ZlcmJvc2UnLFxyXG4gICAgICBjb2xvcjogY29sb3JzWzNdXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0aXRsZTogJ2JlbmNobWFyaycsXHJcbiAgICAgIGNvbG9yOiBjb2xvcnNbNF1cclxuICAgIH1cclxuICBdXHJcbn07XHJcblxyXG4vKipcclxuICogTG9ncyBhIG1lc3NhZ2Ugd2l0aCBhIHNwZWNpZmllZCBsb2cgbGV2ZWwuIEFjY2VwdHMgYSB2YXJpYWJsZSBudW1iZXJcclxuICogb2YgYXJndW1lbnRzLiBUaGUgYXJndW1lbnRzIGFmdGVyIHRoZSBgbGV2ZWxgIGFyZSBwYXNzZWQgdG8gYGNvbnNvbGUubG9nYFxyXG4gKiBhbmQvb3IgdXNlZCB0byBjb25zdHJ1Y3QgYW5kIGFwcGVuZCBtZXNzYWdlcyB0byBhIGxvZyBmaWxlLlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gbG9nXHJcbiAqXHJcbiAqIEBwYXJhbSB7Li4udW5rbm93bn0gYXJncyAtIEFuIGFycmF5IG9mIGFyZ3VtZW50cyB3aGVyZSB0aGUgZmlyc3QgaXMgdGhlIGxvZ1xyXG4gKiBsZXZlbCBhbmQgdGhlIHJlbWFpbmluZyBhcmUgc3RyaW5ncyB1c2VkIHRvIGJ1aWxkIHRoZSBsb2cgbWVzc2FnZS5cclxuICpcclxuICogQHJldHVybnMge3ZvaWR9IEV4aXRzIHRoZSBmdW5jdGlvbiBleGVjdXRpb24gaWYgYXR0ZW1wdGluZyB0byBsb2cgYXQgYSBsZXZlbFxyXG4gKiBoaWdoZXIgdGhhbiBhbGxvd2VkLlxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIGxvZyguLi5hcmdzKSB7XHJcbiAgY29uc3QgW25ld0xldmVsLCAuLi50ZXh0c10gPSBhcmdzO1xyXG5cclxuICAvLyBDdXJyZW50IGxvZ2dpbmcgb3B0aW9uc1xyXG4gIGNvbnN0IHsgbGV2ZWxzRGVzYywgbGV2ZWwgfSA9IGxvZ2dpbmc7XHJcblxyXG4gIC8vIENoZWNrIGlmIHRoZSBsb2cgbGV2ZWwgaXMgd2l0aGluIGEgY29ycmVjdCByYW5nZSBvciBpcyBpdCBhIGJlbmNobWFyayBsb2dcclxuICBpZiAoXHJcbiAgICBuZXdMZXZlbCAhPT0gNSAmJlxyXG4gICAgKG5ld0xldmVsID09PSAwIHx8IG5ld0xldmVsID4gbGV2ZWwgfHwgbGV2ZWwgPiBsZXZlbHNEZXNjLmxlbmd0aClcclxuICApIHtcclxuICAgIHJldHVybjtcclxuICB9XHJcblxyXG4gIC8vIENyZWF0ZSBhIG1lc3NhZ2UncyBwcmVmaXhcclxuICBjb25zdCBwcmVmaXggPSBgJHtnZXROZXdEYXRlKCl9IFske2xldmVsc0Rlc2NbbmV3TGV2ZWwgLSAxXS50aXRsZX1dIC1gO1xyXG5cclxuICAvLyBMb2cgdG8gZmlsZVxyXG4gIGlmIChsb2dnaW5nLnRvRmlsZSkge1xyXG4gICAgX2xvZ1RvRmlsZSh0ZXh0cywgcHJlZml4KTtcclxuICB9XHJcblxyXG4gIC8vIExvZyB0byBjb25zb2xlXHJcbiAgaWYgKGxvZ2dpbmcudG9Db25zb2xlKSB7XHJcbiAgICBjb25zb2xlLmxvZy5hcHBseShcclxuICAgICAgdW5kZWZpbmVkLFxyXG4gICAgICBbcHJlZml4LnRvU3RyaW5nKClbbG9nZ2luZy5sZXZlbHNEZXNjW25ld0xldmVsIC0gMV0uY29sb3JdXS5jb25jYXQodGV4dHMpXHJcbiAgICApO1xyXG4gIH1cclxufVxyXG5cclxuLyoqXHJcbiAqIExvZ3MgYW4gZXJyb3IgbWVzc2FnZSBhbG9uZyB3aXRoIGl0cyBzdGFjayB0cmFjZS4gT3B0aW9uYWxseSwgYSBjdXN0b20gbWVzc2FnZVxyXG4gKiBjYW4gYmUgcHJvdmlkZWQuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBsb2dXaXRoU3RhY2tcclxuICpcclxuICogQHBhcmFtIHtudW1iZXJ9IG5ld0xldmVsIC0gVGhlIGxvZyBsZXZlbC5cclxuICogQHBhcmFtIHtFcnJvcn0gZXJyb3IgLSBUaGUgZXJyb3Igb2JqZWN0IGNvbnRhaW5pbmcgdGhlIHN0YWNrIHRyYWNlLlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gY3VzdG9tTWVzc2FnZSAtIEFuIG9wdGlvbmFsIGN1c3RvbSBtZXNzYWdlIHRvIGJlIGluY2x1ZGVkXHJcbiAqIGluIHRoZSBsb2cgYWxvbmdzaWRlIHRoZSBlcnJvci5cclxuICpcclxuICogQHJldHVybnMge3ZvaWR9IEV4aXRzIHRoZSBmdW5jdGlvbiBleGVjdXRpb24gaWYgYXR0ZW1wdGluZyB0byBsb2cgYXQgYSBsZXZlbFxyXG4gKiBoaWdoZXIgdGhhbiBhbGxvd2VkLlxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIGxvZ1dpdGhTdGFjayhuZXdMZXZlbCwgZXJyb3IsIGN1c3RvbU1lc3NhZ2UpIHtcclxuICAvLyBHZXQgdGhlIG1haW4gbWVzc2FnZVxyXG4gIGNvbnN0IG1haW5NZXNzYWdlID0gY3VzdG9tTWVzc2FnZSB8fCAoZXJyb3IgJiYgZXJyb3IubWVzc2FnZSkgfHwgJyc7XHJcblxyXG4gIC8vIEN1cnJlbnQgbG9nZ2luZyBvcHRpb25zXHJcbiAgY29uc3QgeyBsZXZlbCwgbGV2ZWxzRGVzYyB9ID0gbG9nZ2luZztcclxuXHJcbiAgLy8gQ2hlY2sgaWYgdGhlIGxvZyBsZXZlbCBpcyB3aXRoaW4gYSBjb3JyZWN0IHJhbmdlXHJcbiAgaWYgKG5ld0xldmVsID09PSAwIHx8IG5ld0xldmVsID4gbGV2ZWwgfHwgbGV2ZWwgPiBsZXZlbHNEZXNjLmxlbmd0aCkge1xyXG4gICAgcmV0dXJuO1xyXG4gIH1cclxuXHJcbiAgLy8gQ3JlYXRlIGEgbWVzc2FnZSdzIHByZWZpeFxyXG4gIGNvbnN0IHByZWZpeCA9IGAke2dldE5ld0RhdGUoKX0gWyR7bGV2ZWxzRGVzY1tuZXdMZXZlbCAtIDFdLnRpdGxlfV0gLWA7XHJcblxyXG4gIC8vIEFkZCB0aGUgd2hvbGUgc3RhY2sgbWVzc2FnZVxyXG4gIGNvbnN0IHN0YWNrTWVzc2FnZSA9IGVycm9yICYmIGVycm9yLnN0YWNrO1xyXG5cclxuICAvLyBDb21iaW5lIGN1c3RvbSBtZXNzYWdlIG9yIGVycm9yIG1lc3NhZ2Ugd2l0aCBlcnJvciBzdGFjayBtZXNzYWdlLCBpZiBleGlzdHNcclxuICBjb25zdCB0ZXh0cyA9IFttYWluTWVzc2FnZV07XHJcbiAgaWYgKHN0YWNrTWVzc2FnZSkge1xyXG4gICAgdGV4dHMucHVzaCgnXFxuJywgc3RhY2tNZXNzYWdlKTtcclxuICB9XHJcblxyXG4gIC8vIExvZyB0byBmaWxlXHJcbiAgaWYgKGxvZ2dpbmcudG9GaWxlKSB7XHJcbiAgICBfbG9nVG9GaWxlKHRleHRzLCBwcmVmaXgpO1xyXG4gIH1cclxuXHJcbiAgLy8gTG9nIHRvIGNvbnNvbGVcclxuICBpZiAobG9nZ2luZy50b0NvbnNvbGUpIHtcclxuICAgIGNvbnNvbGUubG9nLmFwcGx5KFxyXG4gICAgICB1bmRlZmluZWQsXHJcbiAgICAgIFtwcmVmaXgudG9TdHJpbmcoKVtsb2dnaW5nLmxldmVsc0Rlc2NbbmV3TGV2ZWwgLSAxXS5jb2xvcl1dLmNvbmNhdChbXHJcbiAgICAgICAgdGV4dHMuc2hpZnQoKVtjb2xvcnNbbmV3TGV2ZWwgLSAxXV0sXHJcbiAgICAgICAgLi4udGV4dHNcclxuICAgICAgXSlcclxuICAgICk7XHJcbiAgfVxyXG59XHJcblxyXG4vKipcclxuICogTG9ncyBhbiBlcnJvciBtZXNzYWdlIGFib3V0IFpvZCBpc3N1ZXMgd2l0aCB0aGUgdmFsaWRhdGlvbi4gT3B0aW9uYWxseSxcclxuICogYSBjdXN0b20gbWVzc2FnZSBjYW4gYmUgcHJvdmlkZWQuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBsb2dab2RJc3N1ZXNcclxuICpcclxuICogQHBhcmFtIHtudW1iZXJ9IG5ld0xldmVsIC0gVGhlIGxvZyBsZXZlbC5cclxuICogQHBhcmFtIHtFcnJvcltdfSBpc3N1ZXMgLSBUaGUgYXJyYXkgb2YgWm9kIGlzc3Vlcy5cclxuICogQHBhcmFtIHtzdHJpbmd9IGN1c3RvbU1lc3NhZ2UgLSBBbiBvcHRpb25hbCBjdXN0b20gbWVzc2FnZSB0byBiZSBsb2dnZWRcclxuICogYWxvbmcgd2l0aCB0aGUgZXJyb3IuXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gbG9nWm9kSXNzdWVzKG5ld0xldmVsLCBpc3N1ZXMgPSBbXSwgY3VzdG9tTWVzc2FnZSkge1xyXG4gIGxvZ1dpdGhTdGFjayhcclxuICAgIG5ld0xldmVsLFxyXG4gICAgbnVsbCxcclxuICAgIFtcclxuICAgICAgYCR7Y3VzdG9tTWVzc2FnZX0gLSB0aGUgZm9sbG93aW5nIFpvZCBpc3N1ZXMgb2NjdXJlZDpgLFxyXG4gICAgICAuLi5pc3N1ZXMubWFwKChpc3N1ZSkgPT4gYC0gJHtpc3N1ZS5tZXNzYWdlfWApXHJcbiAgICBdLmpvaW4oJ1xcbicpXHJcbiAgKTtcclxufVxyXG5cclxuLyoqXHJcbiAqIEluaXRpYWxpemVzIGxvZ2dpbmcgd2l0aCB0aGUgc3BlY2lmaWVkIGxvZ2dpbmcgY29uZmlndXJhdGlvbi5cclxuICpcclxuICogQGZ1bmN0aW9uIGluaXRMb2dnaW5nXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBsb2dnaW5nT3B0aW9ucyAtIFRoZSBjb25maWd1cmF0aW9uIG9iamVjdCBjb250YWluaW5nXHJcbiAqIGBsb2dnaW5nYCBvcHRpb25zLlxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIGluaXRMb2dnaW5nKGxvZ2dpbmdPcHRpb25zKSB7XHJcbiAgLy8gR2V0IG9wdGlvbnMgZnJvbSB0aGUgYGxvZ2dpbmdPcHRpb25zYCBvYmplY3RcclxuICBjb25zdCB7IGxldmVsLCBkZXN0LCBmaWxlLCB0b0NvbnNvbGUsIHRvRmlsZSB9ID0gbG9nZ2luZ09wdGlvbnM7XHJcblxyXG4gIC8vIFJlc2V0IGZsYWdzIHRvIHRoZSBkZWZhdWx0IHZhbHVlc1xyXG4gIGxvZ2dpbmcucGF0aENyZWF0ZWQgPSBmYWxzZTtcclxuICBsb2dnaW5nLnBhdGhUb0xvZyA9ICcnO1xyXG5cclxuICAvLyBTZXQgdGhlIGxvZ2dpbmcgbGV2ZWxcclxuICBzZXRMb2dMZXZlbChsZXZlbCk7XHJcblxyXG4gIC8vIFNldCB0aGUgY29uc29sZSBsb2dnaW5nXHJcbiAgZW5hYmxlQ29uc29sZUxvZ2dpbmcodG9Db25zb2xlKTtcclxuXHJcbiAgLy8gU2V0IHRoZSBmaWxlIGxvZ2dpbmdcclxuICBlbmFibGVGaWxlTG9nZ2luZyhkZXN0LCBmaWxlLCB0b0ZpbGUpO1xyXG59XHJcblxyXG4vKipcclxuICogU2V0cyB0aGUgbG9nIGxldmVsIHRvIHRoZSBzcGVjaWZpZWQgdmFsdWUuIExvZyBsZXZlbHMgYXJlIChgMGAgPSBubyBsb2dnaW5nLFxyXG4gKiBgMWAgPSBlcnJvciwgYDJgID0gd2FybmluZywgYDNgID0gbm90aWNlLCBgNGAgPSB2ZXJib3NlLCBvciBgNWAgPSBiZW5jaG1hcmspLlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gc2V0TG9nTGV2ZWxcclxuICpcclxuICogQHBhcmFtIHtudW1iZXJ9IGxldmVsIC0gVGhlIGxvZyBsZXZlbCB0byBiZSBzZXQuXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gc2V0TG9nTGV2ZWwobGV2ZWwpIHtcclxuICBpZiAoXHJcbiAgICBOdW1iZXIuaXNJbnRlZ2VyKGxldmVsKSAmJlxyXG4gICAgbGV2ZWwgPj0gMCAmJlxyXG4gICAgbGV2ZWwgPD0gbG9nZ2luZy5sZXZlbHNEZXNjLmxlbmd0aFxyXG4gICkge1xyXG4gICAgLy8gVXBkYXRlIHRoZSBtb2R1bGUgbG9nZ2luZydzIGBsZXZlbGAgb3B0aW9uXHJcbiAgICBsb2dnaW5nLmxldmVsID0gbGV2ZWw7XHJcbiAgfVxyXG59XHJcblxyXG4vKipcclxuICogRW5hYmxlcyBjb25zb2xlIGxvZ2dpbmcuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBlbmFibGVDb25zb2xlTG9nZ2luZ1xyXG4gKlxyXG4gKiBAcGFyYW0ge2Jvb2xlYW59IHRvQ29uc29sZSAtIFRoZSBmbGFnIGZvciBzZXR0aW5nIHRoZSBsb2dnaW5nIHRvIHRoZSBjb25zb2xlLlxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIGVuYWJsZUNvbnNvbGVMb2dnaW5nKHRvQ29uc29sZSkge1xyXG4gIC8vIFVwZGF0ZSB0aGUgbW9kdWxlIGxvZ2dpbmcncyBgdG9Db25zb2xlYCBvcHRpb25cclxuICBsb2dnaW5nLnRvQ29uc29sZSA9ICEhdG9Db25zb2xlO1xyXG59XHJcblxyXG4vKipcclxuICogRW5hYmxlcyBmaWxlIGxvZ2dpbmcgd2l0aCB0aGUgc3BlY2lmaWVkIGRlc3RpbmF0aW9uIGFuZCBsb2cgZmlsZSBuYW1lLlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gZW5hYmxlRmlsZUxvZ2dpbmdcclxuICpcclxuICogQHBhcmFtIHtzdHJpbmd9IGRlc3QgLSBUaGUgZGVzdGluYXRpb24gcGF0aCB3aGVyZSB0aGUgbG9nIGZpbGUgc2hvdWxkXHJcbiAqIGJlIHNhdmVkLlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gZmlsZSAtIFRoZSBuYW1lIG9mIHRoZSBsb2cgZmlsZS5cclxuICogQHBhcmFtIHtib29sZWFufSB0b0ZpbGUgLSBBIGZsYWcgaW5kaWNhdGluZyB3aGV0aGVyIGxvZ2dpbmcgc2hvdWxkXHJcbiAqIGJlIGRpcmVjdGVkIHRvIGEgZmlsZS5cclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiBlbmFibGVGaWxlTG9nZ2luZyhkZXN0LCBmaWxlLCB0b0ZpbGUpIHtcclxuICAvLyBVcGRhdGUgdGhlIG1vZHVsZSBsb2dnaW5nJ3MgYHRvRmlsZWAgb3B0aW9uXHJcbiAgbG9nZ2luZy50b0ZpbGUgPSAhIXRvRmlsZTtcclxuXHJcbiAgLy8gU2V0IHRoZSBgZGVzdGAgYW5kIGBmaWxlYCBvcHRpb25zIG9ubHkgaWYgdGhlIGZpbGUgbG9nZ2luZyBpcyBlbmFibGVkXHJcbiAgaWYgKGxvZ2dpbmcudG9GaWxlKSB7XHJcbiAgICBsb2dnaW5nLmRlc3QgPSBkZXN0IHx8ICcnO1xyXG4gICAgbG9nZ2luZy5maWxlID0gZmlsZSB8fCAnJztcclxuICB9XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBMb2dzIHRoZSBwcm92aWRlZCB0ZXh0cyB0byBhIGZpbGUsIGlmIGZpbGUgbG9nZ2luZyBpcyBlbmFibGVkLiBJdCBjcmVhdGVzXHJcbiAqIHRoZSBuZWNlc3NhcnkgZGlyZWN0b3J5IHN0cnVjdHVyZSBpZiBub3QgYWxyZWFkeSBjcmVhdGVkIGFuZCBhcHBlbmRzXHJcbiAqIHRoZSBjb250ZW50LCBpbmNsdWRpbmcgYW4gb3B0aW9uYWwgcHJlZml4LCB0byB0aGUgc3BlY2lmaWVkIGxvZyBmaWxlLlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gX2xvZ1RvRmlsZVxyXG4gKlxyXG4gKiBAcGFyYW0ge0FycmF5LjxzdHJpbmc+fSB0ZXh0cyAtIEFuIGFycmF5IG9mIHRleHRzIHRvIGJlIGxvZ2dlZC5cclxuICogQHBhcmFtIHtzdHJpbmd9IHByZWZpeCAtIEFuIG9wdGlvbmFsIHByZWZpeCB0byBiZSBhZGRlZCB0byBlYWNoIGxvZyBlbnRyeS5cclxuICovXHJcbmZ1bmN0aW9uIF9sb2dUb0ZpbGUodGV4dHMsIHByZWZpeCkge1xyXG4gIGlmICghbG9nZ2luZy5wYXRoQ3JlYXRlZCkge1xyXG4gICAgLy8gQ3JlYXRlIGlmIGRvZXMgbm90IGV4aXN0XHJcbiAgICAhZXhpc3RzU3luYyhnZXRBYnNvbHV0ZVBhdGgobG9nZ2luZy5kZXN0KSkgJiZcclxuICAgICAgbWtkaXJTeW5jKGdldEFic29sdXRlUGF0aChsb2dnaW5nLmRlc3QpKTtcclxuXHJcbiAgICAvLyBDcmVhdGUgdGhlIGZ1bGwgcGF0aFxyXG4gICAgbG9nZ2luZy5wYXRoVG9Mb2cgPSBnZXRBYnNvbHV0ZVBhdGgoam9pbihsb2dnaW5nLmRlc3QsIGxvZ2dpbmcuZmlsZSkpO1xyXG5cclxuICAgIC8vIFdlIG5vdyBhc3N1bWUgdGhlIHBhdGggaXMgYXZhaWxhYmxlLCBlLmcuIGl0J3MgdGhlIHJlc3BvbnNpYmlsaXR5XHJcbiAgICAvLyBvZiB0aGUgdXNlciB0byBjcmVhdGUgdGhlIHBhdGggd2l0aCB0aGUgY29ycmVjdCBhY2Nlc3MgcmlnaHRzLlxyXG4gICAgbG9nZ2luZy5wYXRoQ3JlYXRlZCA9IHRydWU7XHJcbiAgfVxyXG5cclxuICAvLyBBZGQgdGhlIGNvbnRlbnQgdG8gYSBmaWxlXHJcbiAgYXBwZW5kRmlsZShcclxuICAgIGxvZ2dpbmcucGF0aFRvTG9nLFxyXG4gICAgW3ByZWZpeF0uY29uY2F0KHRleHRzKS5qb2luKCcgJykgKyAnXFxuJyxcclxuICAgIChlcnJvcikgPT4ge1xyXG4gICAgICBpZiAoZXJyb3IgJiYgbG9nZ2luZy50b0ZpbGUgJiYgbG9nZ2luZy5wYXRoQ3JlYXRlZCkge1xyXG4gICAgICAgIGxvZ2dpbmcudG9GaWxlID0gZmFsc2U7XHJcbiAgICAgICAgbG9nZ2luZy5wYXRoQ3JlYXRlZCA9IGZhbHNlO1xyXG4gICAgICAgIGxvZ1dpdGhTdGFjaygyLCBlcnJvciwgYFtsb2dnZXJdIFVuYWJsZSB0byB3cml0ZSB0byBsb2cgZmlsZS5gKTtcclxuICAgICAgfVxyXG4gICAgfVxyXG4gICk7XHJcbn1cclxuXHJcbmV4cG9ydCBkZWZhdWx0IHtcclxuICBsb2csXHJcbiAgbG9nV2l0aFN0YWNrLFxyXG4gIGxvZ1pvZElzc3VlcyxcclxuICBpbml0TG9nZ2luZyxcclxuICBzZXRMb2dMZXZlbCxcclxuICBlbmFibGVDb25zb2xlTG9nZ2luZyxcclxuICBlbmFibGVGaWxlTG9nZ2luZ1xyXG59O1xyXG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxyXG5cclxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXHJcblxyXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNSwgSGlnaHNvZnRcclxuXHJcbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cclxuXHJcbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxyXG5cclxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxyXG5cclxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cclxuXHJcbi8qKlxyXG4gKiBAb3ZlcnZpZXcgQ29uZmlndXJhdGlvbiBtYW5hZ2VtZW50IG1vZHVsZSBmb3IgdGhlIEhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlci5cclxuICogUHJvdmlkZXMgZGVmYXVsdCBjb25maWd1cmF0aW9ucyB0aGF0IHN1cHBvcnQgZW52aXJvbm1lbnQgdmFyaWFibGVzLCBDTElcclxuICogYXJndW1lbnRzLCBhbmQgaW50ZXJhY3RpdmUgcHJvbXB0cyBmb3IgY3VzdG9taXphdGlvbiBvZiBvcHRpb25zIGFuZCBmZWF0dXJlcy5cclxuICogQWRkaXRpb25hbGx5LCBpdCBtYXBzIGxlZ2FjeSBvcHRpb25zIHRvIG1vZGVybiBzdHJ1Y3R1cmVzLCBnZW5lcmF0ZXMgbmVzdGVkXHJcbiAqIGFyZ3VtZW50IG1hcHBpbmdzLCBhbmQgZGlzcGxheXMgQ0xJIHVzYWdlIGluZm9ybWF0aW9uLlxyXG4gKi9cclxuXHJcbi8qKlxyXG4gKiBUaGUgY29uZmlndXJhdGlvbiBvYmplY3QgY29udGFpbmluZyBhbGwgYXZhaWxhYmxlIG9wdGlvbnMsIG9yZ2FuaXplZFxyXG4gKiBieSBzZWN0aW9ucy5cclxuICpcclxuICogVGhpcyBvYmplY3QgaW5jbHVkZXM6XHJcbiAqIC0gRGVmYXVsdCB2YWx1ZXMgZm9yIGVhY2ggb3B0aW9uXHJcbiAqIC0gRGF0YSB0eXBlcyBmb3IgdmFsaWRhdGlvblxyXG4gKiAtIE5hbWVzIG9mIGNvcnJlc3BvbmRpbmcgZW52aXJvbm1lbnQgdmFyaWFibGVzXHJcbiAqIC0gRGVzY3JpcHRpb25zIG9mIGVhY2ggcHJvcGVydHlcclxuICogLSBJbmZvcm1hdGlvbiB1c2VkIGZvciBwcm9tcHRzIGluIGludGVyYWN0aXZlIGNvbmZpZ3VyYXRpb25cclxuICogLSBbT3B0aW9uYWxdIENvcnJlc3BvbmRpbmcgQ0xJIGFyZ3VtZW50IG5hbWVzIGZvciBDTEkgdXNhZ2VcclxuICogLSBbT3B0aW9uYWxdIExlZ2FjeSBuYW1lcyBmcm9tIHRoZSBwcmV2aW91cyBQaGFudG9tSlMtYmFzZWQgc2VydmVyXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgZGVmYXVsdENvbmZpZyA9IHtcclxuICBwdXBwZXRlZXI6IHtcclxuICAgIGFyZ3M6IHtcclxuICAgICAgdmFsdWU6IFtcclxuICAgICAgICAnLS1hbGxvdy1ydW5uaW5nLWluc2VjdXJlLWNvbnRlbnQnLFxyXG4gICAgICAgICctLWFzaC1uby1udWRnZXMnLFxyXG4gICAgICAgICctLWF1dG9wbGF5LXBvbGljeT11c2VyLWdlc3R1cmUtcmVxdWlyZWQnLFxyXG4gICAgICAgICctLWJsb2NrLW5ldy13ZWItY29udGVudHMnLFxyXG4gICAgICAgICctLWRpc2FibGUtYWNjZWxlcmF0ZWQtMmQtY2FudmFzJyxcclxuICAgICAgICAnLS1kaXNhYmxlLWJhY2tncm91bmQtbmV0d29ya2luZycsXHJcbiAgICAgICAgJy0tZGlzYWJsZS1iYWNrZ3JvdW5kLXRpbWVyLXRocm90dGxpbmcnLFxyXG4gICAgICAgICctLWRpc2FibGUtYmFja2dyb3VuZGluZy1vY2NsdWRlZC13aW5kb3dzJyxcclxuICAgICAgICAnLS1kaXNhYmxlLWJyZWFrcGFkJyxcclxuICAgICAgICAnLS1kaXNhYmxlLWNoZWNrZXItaW1hZ2luZycsXHJcbiAgICAgICAgJy0tZGlzYWJsZS1jbGllbnQtc2lkZS1waGlzaGluZy1kZXRlY3Rpb24nLFxyXG4gICAgICAgICctLWRpc2FibGUtY29tcG9uZW50LWV4dGVuc2lvbnMtd2l0aC1iYWNrZ3JvdW5kLXBhZ2VzJyxcclxuICAgICAgICAnLS1kaXNhYmxlLWNvbXBvbmVudC11cGRhdGUnLFxyXG4gICAgICAgICctLWRpc2FibGUtZGVmYXVsdC1hcHBzJyxcclxuICAgICAgICAnLS1kaXNhYmxlLWRldi1zaG0tdXNhZ2UnLFxyXG4gICAgICAgICctLWRpc2FibGUtZG9tYWluLXJlbGlhYmlsaXR5JyxcclxuICAgICAgICAnLS1kaXNhYmxlLWV4dGVuc2lvbnMnLFxyXG4gICAgICAgICctLWRpc2FibGUtZmVhdHVyZXM9Q2FsY3VsYXRlTmF0aXZlV2luT2NjbHVzaW9uLEludGVyZXN0RmVlZENvbnRlbnRTdWdnZXN0aW9ucyxXZWJPVFAnLFxyXG4gICAgICAgICctLWRpc2FibGUtaGFuZy1tb25pdG9yJyxcclxuICAgICAgICAnLS1kaXNhYmxlLWlwYy1mbG9vZGluZy1wcm90ZWN0aW9uJyxcclxuICAgICAgICAnLS1kaXNhYmxlLWxvZ2dpbmcnLFxyXG4gICAgICAgICctLWRpc2FibGUtbm90aWZpY2F0aW9ucycsXHJcbiAgICAgICAgJy0tZGlzYWJsZS1vZmZlci1zdG9yZS11bm1hc2tlZC13YWxsZXQtY2FyZHMnLFxyXG4gICAgICAgICctLWRpc2FibGUtcG9wdXAtYmxvY2tpbmcnLFxyXG4gICAgICAgICctLWRpc2FibGUtcHJpbnQtcHJldmlldycsXHJcbiAgICAgICAgJy0tZGlzYWJsZS1wcm9tcHQtb24tcmVwb3N0JyxcclxuICAgICAgICAnLS1kaXNhYmxlLXJlbmRlcmVyLWJhY2tncm91bmRpbmcnLFxyXG4gICAgICAgICctLWRpc2FibGUtc2VhcmNoLWVuZ2luZS1jaG9pY2Utc2NyZWVuJyxcclxuICAgICAgICAnLS1kaXNhYmxlLXNlc3Npb24tY3Jhc2hlZC1idWJibGUnLFxyXG4gICAgICAgICctLWRpc2FibGUtc2V0dWlkLXNhbmRib3gnLFxyXG4gICAgICAgICctLWRpc2FibGUtc2l0ZS1pc29sYXRpb24tdHJpYWxzJyxcclxuICAgICAgICAnLS1kaXNhYmxlLXNwZWVjaC1hcGknLFxyXG4gICAgICAgICctLWRpc2FibGUtc3luYycsXHJcbiAgICAgICAgJy0tZW5hYmxlLXVuc2FmZS13ZWJncHUnLFxyXG4gICAgICAgICctLWhpZGUtY3Jhc2gtcmVzdG9yZS1idWJibGUnLFxyXG4gICAgICAgICctLWhpZGUtc2Nyb2xsYmFycycsXHJcbiAgICAgICAgJy0tbWV0cmljcy1yZWNvcmRpbmctb25seScsXHJcbiAgICAgICAgJy0tbXV0ZS1hdWRpbycsXHJcbiAgICAgICAgJy0tbm8tZGVmYXVsdC1icm93c2VyLWNoZWNrJyxcclxuICAgICAgICAnLS1uby1maXJzdC1ydW4nLFxyXG4gICAgICAgICctLW5vLXBpbmdzJyxcclxuICAgICAgICAnLS1uby1zYW5kYm94JyxcclxuICAgICAgICAnLS1uby1zdGFydHVwLXdpbmRvdycsXHJcbiAgICAgICAgJy0tbm8tenlnb3RlJyxcclxuICAgICAgICAnLS1wYXNzd29yZC1zdG9yZT1iYXNpYycsXHJcbiAgICAgICAgJy0tcHJvY2Vzcy1wZXItdGFiJyxcclxuICAgICAgICAnLS11c2UtbW9jay1rZXljaGFpbidcclxuICAgICAgXSxcclxuICAgICAgdHlwZXM6IFsnc3RyaW5nW10nXSxcclxuICAgICAgZW52TGluazogJ1BVUFBFVEVFUl9BUkdTJyxcclxuICAgICAgY2xpTmFtZTogJ3B1cHBldGVlckFyZ3MnLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ0FycmF5IG9mIFB1cHBldGVlciBhcmd1bWVudHMnLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ2xpc3QnLFxyXG4gICAgICAgIHNlcGFyYXRvcjogJzsnXHJcbiAgICAgIH1cclxuICAgIH1cclxuICB9LFxyXG4gIGhpZ2hjaGFydHM6IHtcclxuICAgIHZlcnNpb246IHtcclxuICAgICAgdmFsdWU6ICdsYXRlc3QnLFxyXG4gICAgICB0eXBlczogWydzdHJpbmcnXSxcclxuICAgICAgZW52TGluazogJ0hJR0hDSEFSVFNfVkVSU0lPTicsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnSGlnaGNoYXJ0cyB2ZXJzaW9uJyxcclxuICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgIHR5cGU6ICd0ZXh0J1xyXG4gICAgICB9XHJcbiAgICB9LFxyXG4gICAgY2RuVXJsOiB7XHJcbiAgICAgIHZhbHVlOiAnaHR0cHM6Ly9jb2RlLmhpZ2hjaGFydHMuY29tJyxcclxuICAgICAgdHlwZXM6IFsnc3RyaW5nJ10sXHJcbiAgICAgIGVudkxpbms6ICdISUdIQ0hBUlRTX0NETl9VUkwnLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ0NETiBVUkwgZm9yIEhpZ2hjaGFydHMgc2NyaXB0cycsXHJcbiAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICB0eXBlOiAndGV4dCdcclxuICAgICAgfVxyXG4gICAgfSxcclxuICAgIGZvcmNlRmV0Y2g6IHtcclxuICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICB0eXBlczogWydib29sZWFuJ10sXHJcbiAgICAgIGVudkxpbms6ICdISUdIQ0hBUlRTX0ZPUkNFX0ZFVENIJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdGbGFnIHRvIHJlZmV0Y2ggc2NyaXB0cyBhZnRlciBlYWNoIHNlcnZlciByZXJ1bicsXHJcbiAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICB0eXBlOiAndG9nZ2xlJ1xyXG4gICAgICB9XHJcbiAgICB9LFxyXG4gICAgY2FjaGVQYXRoOiB7XHJcbiAgICAgIHZhbHVlOiAnLmNhY2hlJyxcclxuICAgICAgdHlwZXM6IFsnc3RyaW5nJ10sXHJcbiAgICAgIGVudkxpbms6ICdISUdIQ0hBUlRTX0NBQ0hFX1BBVEgnLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ0RpcmVjdG9yeSBwYXRoIGZvciBjYWNoZWQgSGlnaGNoYXJ0cyBzY3JpcHRzJyxcclxuICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgIHR5cGU6ICd0ZXh0J1xyXG4gICAgICB9XHJcbiAgICB9LFxyXG4gICAgY29yZVNjcmlwdHM6IHtcclxuICAgICAgdmFsdWU6IFsnaGlnaGNoYXJ0cycsICdoaWdoY2hhcnRzLW1vcmUnLCAnaGlnaGNoYXJ0cy0zZCddLFxyXG4gICAgICB0eXBlczogWydzdHJpbmdbXSddLFxyXG4gICAgICBlbnZMaW5rOiAnSElHSENIQVJUU19DT1JFX1NDUklQVFMnLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ0hpZ2hjaGFydHMgY29yZSBzY3JpcHRzIHRvIGZldGNoJyxcclxuICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgIHR5cGU6ICdtdWx0aXNlbGVjdCcsXHJcbiAgICAgICAgaW5zdHJ1Y3Rpb25zOiAnU3BhY2U6IFNlbGVjdCBzcGVjaWZpYywgQTogU2VsZWN0IGFsbCwgRW50ZXI6IENvbmZpcm0nXHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICBtb2R1bGVTY3JpcHRzOiB7XHJcbiAgICAgIHZhbHVlOiBbXHJcbiAgICAgICAgJ3N0b2NrJyxcclxuICAgICAgICAnbWFwJyxcclxuICAgICAgICAnZ2FudHQnLFxyXG4gICAgICAgICdleHBvcnRpbmcnLFxyXG4gICAgICAgICdwYXJhbGxlbC1jb29yZGluYXRlcycsXHJcbiAgICAgICAgJ2FjY2Vzc2liaWxpdHknLFxyXG4gICAgICAgIC8vICdhbm5vdGF0aW9ucy1hZHZhbmNlZCcsXHJcbiAgICAgICAgJ2Jvb3N0LWNhbnZhcycsXHJcbiAgICAgICAgJ2Jvb3N0JyxcclxuICAgICAgICAnZGF0YScsXHJcbiAgICAgICAgJ2RhdGEtdG9vbHMnLFxyXG4gICAgICAgICdkcmFnZ2FibGUtcG9pbnRzJyxcclxuICAgICAgICAnc3RhdGljLXNjYWxlJyxcclxuICAgICAgICAnYnJva2VuLWF4aXMnLFxyXG4gICAgICAgICdoZWF0bWFwJyxcclxuICAgICAgICAndGlsZW1hcCcsXHJcbiAgICAgICAgJ3RpbGVkd2VibWFwJyxcclxuICAgICAgICAndGltZWxpbmUnLFxyXG4gICAgICAgICd0cmVlbWFwJyxcclxuICAgICAgICAndHJlZWdyYXBoJyxcclxuICAgICAgICAnaXRlbS1zZXJpZXMnLFxyXG4gICAgICAgICdkcmlsbGRvd24nLFxyXG4gICAgICAgICdoaXN0b2dyYW0tYmVsbGN1cnZlJyxcclxuICAgICAgICAnYnVsbGV0JyxcclxuICAgICAgICAnZnVubmVsJyxcclxuICAgICAgICAnZnVubmVsM2QnLFxyXG4gICAgICAgICdnZW9oZWF0bWFwJyxcclxuICAgICAgICAncHlyYW1pZDNkJyxcclxuICAgICAgICAnbmV0d29ya2dyYXBoJyxcclxuICAgICAgICAnb3ZlcmxhcHBpbmctZGF0YWxhYmVscycsXHJcbiAgICAgICAgJ3BhcmV0bycsXHJcbiAgICAgICAgJ3BhdHRlcm4tZmlsbCcsXHJcbiAgICAgICAgJ3BpY3RvcmlhbCcsXHJcbiAgICAgICAgJ3ByaWNlLWluZGljYXRvcicsXHJcbiAgICAgICAgJ3NhbmtleScsXHJcbiAgICAgICAgJ2FyYy1kaWFncmFtJyxcclxuICAgICAgICAnZGVwZW5kZW5jeS13aGVlbCcsXHJcbiAgICAgICAgJ3Nlcmllcy1sYWJlbCcsXHJcbiAgICAgICAgJ3Nlcmllcy1vbi1wb2ludCcsXHJcbiAgICAgICAgJ3NvbGlkLWdhdWdlJyxcclxuICAgICAgICAnc29uaWZpY2F0aW9uJyxcclxuICAgICAgICAvLyAnc3RvY2stdG9vbHMnLFxyXG4gICAgICAgICdzdHJlYW1ncmFwaCcsXHJcbiAgICAgICAgJ3N1bmJ1cnN0JyxcclxuICAgICAgICAndmFyaWFibGUtcGllJyxcclxuICAgICAgICAndmFyaXdpZGUnLFxyXG4gICAgICAgICd2ZWN0b3InLFxyXG4gICAgICAgICd2ZW5uJyxcclxuICAgICAgICAnd2luZGJhcmInLFxyXG4gICAgICAgICd3b3JkY2xvdWQnLFxyXG4gICAgICAgICd4cmFuZ2UnLFxyXG4gICAgICAgICduby1kYXRhLXRvLWRpc3BsYXknLFxyXG4gICAgICAgICdkcmFnLXBhbmVzJyxcclxuICAgICAgICAnZGVidWdnZXInLFxyXG4gICAgICAgICdkdW1iYmVsbCcsXHJcbiAgICAgICAgJ2xvbGxpcG9wJyxcclxuICAgICAgICAnY3lsaW5kZXInLFxyXG4gICAgICAgICdvcmdhbml6YXRpb24nLFxyXG4gICAgICAgICdkb3RwbG90JyxcclxuICAgICAgICAnbWFya2VyLWNsdXN0ZXJzJyxcclxuICAgICAgICAnaG9sbG93Y2FuZGxlc3RpY2snLFxyXG4gICAgICAgICdoZWlraW5hc2hpJyxcclxuICAgICAgICAnZmxvd21hcCcsXHJcbiAgICAgICAgJ2V4cG9ydC1kYXRhJyxcclxuICAgICAgICAnbmF2aWdhdG9yJyxcclxuICAgICAgICAndGV4dHBhdGgnXHJcbiAgICAgIF0sXHJcbiAgICAgIHR5cGVzOiBbJ3N0cmluZ1tdJ10sXHJcbiAgICAgIGVudkxpbms6ICdISUdIQ0hBUlRTX01PRFVMRV9TQ1JJUFRTJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdIaWdoY2hhcnRzIG1vZHVsZSBzY3JpcHRzIHRvIGZldGNoJyxcclxuICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgIHR5cGU6ICdtdWx0aXNlbGVjdCcsXHJcbiAgICAgICAgaW5zdHJ1Y3Rpb25zOiAnU3BhY2U6IFNlbGVjdCBzcGVjaWZpYywgQTogU2VsZWN0IGFsbCwgRW50ZXI6IENvbmZpcm0nXHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICBpbmRpY2F0b3JTY3JpcHRzOiB7XHJcbiAgICAgIHZhbHVlOiBbJ2luZGljYXRvcnMtYWxsJ10sXHJcbiAgICAgIHR5cGVzOiBbJ3N0cmluZ1tdJ10sXHJcbiAgICAgIGVudkxpbms6ICdISUdIQ0hBUlRTX0lORElDQVRPUl9TQ1JJUFRTJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdIaWdoY2hhcnRzIGluZGljYXRvciBzY3JpcHRzIHRvIGZldGNoJyxcclxuICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgIHR5cGU6ICdtdWx0aXNlbGVjdCcsXHJcbiAgICAgICAgaW5zdHJ1Y3Rpb25zOiAnU3BhY2U6IFNlbGVjdCBzcGVjaWZpYywgQTogU2VsZWN0IGFsbCwgRW50ZXI6IENvbmZpcm0nXHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICBjdXN0b21TY3JpcHRzOiB7XHJcbiAgICAgIHZhbHVlOiBbXHJcbiAgICAgICAgJ2h0dHBzOi8vY2RuanMuY2xvdWRmbGFyZS5jb20vYWpheC9saWJzL21vbWVudC5qcy8yLjMwLjEvbW9tZW50Lm1pbi5qcycsXHJcbiAgICAgICAgJ2h0dHBzOi8vY2RuanMuY2xvdWRmbGFyZS5jb20vYWpheC9saWJzL21vbWVudC10aW1lem9uZS8wLjUuNDUvbW9tZW50LXRpbWV6b25lLXdpdGgtZGF0YS5taW4uanMnXHJcbiAgICAgIF0sXHJcbiAgICAgIHR5cGVzOiBbJ3N0cmluZ1tdJ10sXHJcbiAgICAgIGVudkxpbms6ICdISUdIQ0hBUlRTX0NVU1RPTV9TQ1JJUFRTJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdBZGRpdGlvbmFsIGN1c3RvbSBzY3JpcHRzIG9yIGRlcGVuZGVuY2llcyB0byBmZXRjaCcsXHJcbiAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICB0eXBlOiAnbGlzdCcsXHJcbiAgICAgICAgc2VwYXJhdG9yOiAnOydcclxuICAgICAgfVxyXG4gICAgfVxyXG4gIH0sXHJcbiAgZXhwb3J0OiB7XHJcbiAgICBpbmZpbGU6IHtcclxuICAgICAgdmFsdWU6IG51bGwsXHJcbiAgICAgIHR5cGVzOiBbJ3N0cmluZycsICdudWxsJ10sXHJcbiAgICAgIGVudkxpbms6ICdFWFBPUlRfSU5GSUxFJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ0lucHV0IGZpbGVuYW1lIHdpdGggdHlwZSwgZm9ybWF0dGVkIGNvcnJlY3RseSBhcyBKU09OIG9yIFNWRycsXHJcbiAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICB0eXBlOiAndGV4dCdcclxuICAgICAgfVxyXG4gICAgfSxcclxuICAgIGluc3RyOiB7XHJcbiAgICAgIHZhbHVlOiBudWxsLFxyXG4gICAgICB0eXBlczogWydPYmplY3QnLCAnc3RyaW5nJywgJ251bGwnXSxcclxuICAgICAgZW52TGluazogJ0VYUE9SVF9JTlNUUicsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdPdmVycmlkZXMgdGhlIGBpbmZpbGVgIHdpdGggSlNPTiwgc3RyaW5naWZpZWQgSlNPTiwgb3IgU1ZHIGlucHV0JyxcclxuICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgIHR5cGU6ICd0ZXh0J1xyXG4gICAgICB9XHJcbiAgICB9LFxyXG4gICAgb3B0aW9uczoge1xyXG4gICAgICB2YWx1ZTogbnVsbCxcclxuICAgICAgdHlwZXM6IFsnT2JqZWN0JywgJ3N0cmluZycsICdudWxsJ10sXHJcbiAgICAgIGVudkxpbms6ICdFWFBPUlRfT1BUSU9OUycsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnQWxpYXMgZm9yIHRoZSBgaW5zdHJgIG9wdGlvbicsXHJcbiAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICB0eXBlOiAndGV4dCdcclxuICAgICAgfVxyXG4gICAgfSxcclxuICAgIHN2Zzoge1xyXG4gICAgICB2YWx1ZTogbnVsbCxcclxuICAgICAgdHlwZXM6IFsnc3RyaW5nJywgJ251bGwnXSxcclxuICAgICAgZW52TGluazogJ0VYUE9SVF9TVkcnLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ1NWRyBzdHJpbmcgcmVwcmVzZW50YXRpb24gb2YgdGhlIGNoYXJ0IHRvIHJlbmRlcicsXHJcbiAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICB0eXBlOiAndGV4dCdcclxuICAgICAgfVxyXG4gICAgfSxcclxuICAgIGJhdGNoOiB7XHJcbiAgICAgIHZhbHVlOiBudWxsLFxyXG4gICAgICB0eXBlczogWydzdHJpbmcnLCAnbnVsbCddLFxyXG4gICAgICBlbnZMaW5rOiAnRVhQT1JUX0JBVENIJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ0JhdGNoIGpvYiBzdHJpbmcgd2l0aCBpbnB1dC9vdXRwdXQgcGFpcnM6IFwiaW49b3V0O2luPW91dDsuLi5cIicsXHJcbiAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICB0eXBlOiAndGV4dCdcclxuICAgICAgfVxyXG4gICAgfSxcclxuICAgIG91dGZpbGU6IHtcclxuICAgICAgdmFsdWU6IG51bGwsXHJcbiAgICAgIHR5cGVzOiBbJ3N0cmluZycsICdudWxsJ10sXHJcbiAgICAgIGVudkxpbms6ICdFWFBPUlRfT1VURklMRScsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdPdXRwdXQgZmlsZW5hbWUgd2l0aCB0eXBlLiBDYW4gYmUganBlZywgcG5nLCBwZGYsIG9yIHN2ZyBhbmQgaWdub3JlcyBgdHlwZWAgb3B0aW9uJyxcclxuICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgIHR5cGU6ICd0ZXh0J1xyXG4gICAgICB9XHJcbiAgICB9LFxyXG4gICAgdHlwZToge1xyXG4gICAgICB2YWx1ZTogJ3BuZycsXHJcbiAgICAgIHR5cGVzOiBbJ3N0cmluZyddLFxyXG4gICAgICBlbnZMaW5rOiAnRVhQT1JUX1RZUEUnLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ0ZpbGUgZXhwb3J0IGZvcm1hdC4gQ2FuIGJlIGpwZWcsIHBuZywgcGRmLCBvciBzdmcnLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ3NlbGVjdCcsXHJcbiAgICAgICAgaGludDogJ0RlZmF1bHQ6IHBuZycsXHJcbiAgICAgICAgY2hvaWNlczogWydwbmcnLCAnanBlZycsICdwZGYnLCAnc3ZnJ11cclxuICAgICAgfVxyXG4gICAgfSxcclxuICAgIGNvbnN0cjoge1xyXG4gICAgICB2YWx1ZTogJ2NoYXJ0JyxcclxuICAgICAgdHlwZXM6IFsnc3RyaW5nJ10sXHJcbiAgICAgIGVudkxpbms6ICdFWFBPUlRfQ09OU1RSJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ0NoYXJ0IGNvbnN0cnVjdG9yLiBDYW4gYmUgY2hhcnQsIHN0b2NrQ2hhcnQsIG1hcENoYXJ0LCBvciBnYW50dENoYXJ0JyxcclxuICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgIHR5cGU6ICdzZWxlY3QnLFxyXG4gICAgICAgIGhpbnQ6ICdEZWZhdWx0OiBjaGFydCcsXHJcbiAgICAgICAgY2hvaWNlczogWydjaGFydCcsICdzdG9ja0NoYXJ0JywgJ21hcENoYXJ0JywgJ2dhbnR0Q2hhcnQnXVxyXG4gICAgICB9XHJcbiAgICB9LFxyXG4gICAgYjY0OiB7XHJcbiAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgdHlwZXM6IFsnYm9vbGVhbiddLFxyXG4gICAgICBlbnZMaW5rOiAnRVhQT1JUX0I2NCcsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdXaGV0aGVyIG9yIG5vdCB0byB0aGUgY2hhcnQgc2hvdWxkIGJlIHJlY2VpdmVkIGluIEJhc2U2NCBmb3JtYXQgaW5zdGVhZCBvZiBiaW5hcnknLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ3RvZ2dsZSdcclxuICAgICAgfVxyXG4gICAgfSxcclxuICAgIG5vRG93bmxvYWQ6IHtcclxuICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICB0eXBlczogWydib29sZWFuJ10sXHJcbiAgICAgIGVudkxpbms6ICdFWFBPUlRfTk9fRE9XTkxPQUQnLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnV2hldGhlciBvciBub3QgdG8gaW5jbHVkZSBvciBleGNsdWRlIGF0dGFjaG1lbnQgaGVhZGVycyBpbiB0aGUgcmVzcG9uc2UnLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ3RvZ2dsZSdcclxuICAgICAgfVxyXG4gICAgfSxcclxuICAgIGhlaWdodDoge1xyXG4gICAgICB2YWx1ZTogbnVsbCxcclxuICAgICAgdHlwZXM6IFsnbnVtYmVyJywgJ251bGwnXSxcclxuICAgICAgZW52TGluazogJ0VYUE9SVF9IRUlHSFQnLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ0hlaWdodCBvZiB0aGUgZXhwb3J0ZWQgY2hhcnQsIG92ZXJyaWRlcyBjaGFydCBzZXR0aW5ncycsXHJcbiAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICB0eXBlOiAnbnVtYmVyJ1xyXG4gICAgICB9XHJcbiAgICB9LFxyXG4gICAgd2lkdGg6IHtcclxuICAgICAgdmFsdWU6IG51bGwsXHJcbiAgICAgIHR5cGVzOiBbJ251bWJlcicsICdudWxsJ10sXHJcbiAgICAgIGVudkxpbms6ICdFWFBPUlRfV0lEVEgnLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ1dpZHRoIG9mIHRoZSBleHBvcnRlZCBjaGFydCwgb3ZlcnJpZGVzIGNoYXJ0IHNldHRpbmdzJyxcclxuICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgIHR5cGU6ICdudW1iZXInXHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICBzY2FsZToge1xyXG4gICAgICB2YWx1ZTogbnVsbCxcclxuICAgICAgdHlwZXM6IFsnbnVtYmVyJywgJ251bGwnXSxcclxuICAgICAgZW52TGluazogJ0VYUE9SVF9TQ0FMRScsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdTY2FsZSBvZiB0aGUgZXhwb3J0ZWQgY2hhcnQsIG92ZXJyaWRlcyBjaGFydCBzZXR0aW5ncy4gUmFuZ2VzIGZyb20gMC4xIHRvIDUuMCcsXHJcbiAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICB0eXBlOiAnbnVtYmVyJ1xyXG4gICAgICB9XHJcbiAgICB9LFxyXG4gICAgZGVmYXVsdEhlaWdodDoge1xyXG4gICAgICB2YWx1ZTogNDAwLFxyXG4gICAgICB0eXBlczogWydudW1iZXInXSxcclxuICAgICAgZW52TGluazogJ0VYUE9SVF9ERUZBVUxUX0hFSUdIVCcsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnRGVmYXVsdCBoZWlnaHQgb2YgdGhlIGV4cG9ydGVkIGNoYXJ0IGlmIG5vdCBzZXQnLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ251bWJlcidcclxuICAgICAgfVxyXG4gICAgfSxcclxuICAgIGRlZmF1bHRXaWR0aDoge1xyXG4gICAgICB2YWx1ZTogNjAwLFxyXG4gICAgICB0eXBlczogWydudW1iZXInXSxcclxuICAgICAgZW52TGluazogJ0VYUE9SVF9ERUZBVUxUX1dJRFRIJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdEZWZhdWx0IHdpZHRoIG9mIHRoZSBleHBvcnRlZCBjaGFydCBpZiBub3Qgc2V0JyxcclxuICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgIHR5cGU6ICdudW1iZXInXHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICBkZWZhdWx0U2NhbGU6IHtcclxuICAgICAgdmFsdWU6IDEsXHJcbiAgICAgIHR5cGVzOiBbJ251bWJlciddLFxyXG4gICAgICBlbnZMaW5rOiAnRVhQT1JUX0RFRkFVTFRfU0NBTEUnLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnRGVmYXVsdCBzY2FsZSBvZiB0aGUgZXhwb3J0ZWQgY2hhcnQgaWYgbm90IHNldC4gUmFuZ2VzIGZyb20gMC4xIHRvIDUuMCcsXHJcbiAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgICBtaW46IDAuMSxcclxuICAgICAgICBtYXg6IDVcclxuICAgICAgfVxyXG4gICAgfSxcclxuICAgIGdsb2JhbE9wdGlvbnM6IHtcclxuICAgICAgdmFsdWU6IG51bGwsXHJcbiAgICAgIHR5cGVzOiBbJ09iamVjdCcsICdzdHJpbmcnLCAnbnVsbCddLFxyXG4gICAgICBlbnZMaW5rOiAnRVhQT1JUX0dMT0JBTF9PUFRJT05TJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ0pTT04sIHN0cmluZ2lmaWVkIEpTT04gb3IgZmlsZW5hbWUgd2l0aCBnbG9iYWwgb3B0aW9ucyBmb3IgSGlnaGNoYXJ0cy5zZXRPcHRpb25zJyxcclxuICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgIHR5cGU6ICd0ZXh0J1xyXG4gICAgICB9XHJcbiAgICB9LFxyXG4gICAgdGhlbWVPcHRpb25zOiB7XHJcbiAgICAgIHZhbHVlOiBudWxsLFxyXG4gICAgICB0eXBlczogWydPYmplY3QnLCAnc3RyaW5nJywgJ251bGwnXSxcclxuICAgICAgZW52TGluazogJ0VYUE9SVF9USEVNRV9PUFRJT05TJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ0pTT04sIHN0cmluZ2lmaWVkIEpTT04gb3IgZmlsZW5hbWUgd2l0aCB0aGVtZSBvcHRpb25zIGZvciBIaWdoY2hhcnRzLnNldE9wdGlvbnMnLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ3RleHQnXHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICByYXN0ZXJpemF0aW9uVGltZW91dDoge1xyXG4gICAgICB2YWx1ZTogMTUwMCxcclxuICAgICAgdHlwZXM6IFsnbnVtYmVyJ10sXHJcbiAgICAgIGVudkxpbms6ICdFWFBPUlRfUkFTVEVSSVpBVElPTl9USU1FT1VUJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdNaWxsaXNlY29uZHMgdG8gd2FpdCBmb3Igd2VicGFnZSByZW5kZXJpbmcnLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ251bWJlcidcclxuICAgICAgfVxyXG4gICAgfVxyXG4gIH0sXHJcbiAgY3VzdG9tTG9naWM6IHtcclxuICAgIGFsbG93Q29kZUV4ZWN1dGlvbjoge1xyXG4gICAgICB2YWx1ZTogZmFsc2UsXHJcbiAgICAgIHR5cGVzOiBbJ2Jvb2xlYW4nXSxcclxuICAgICAgZW52TGluazogJ0NVU1RPTV9MT0dJQ19BTExPV19DT0RFX0VYRUNVVElPTicsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdBbGxvd3Mgb3IgZGlzYWxsb3dzIGV4ZWN1dGlvbiBvZiBhcmJpdHJhcnkgY29kZSBkdXJpbmcgZXhwb3J0aW5nJyxcclxuICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgIHR5cGU6ICd0b2dnbGUnXHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICBhbGxvd0ZpbGVSZXNvdXJjZXM6IHtcclxuICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICB0eXBlczogWydib29sZWFuJ10sXHJcbiAgICAgIGVudkxpbms6ICdDVVNUT01fTE9HSUNfQUxMT1dfRklMRV9SRVNPVVJDRVMnLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnQWxsb3dzIG9yIGRpc2FsbG93cyBpbmplY3Rpb24gb2YgZmlsZXN5c3RlbSByZXNvdXJjZXMgKGRpc2FibGVkIGluIHNlcnZlciBtb2RlKScsXHJcbiAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICB0eXBlOiAndG9nZ2xlJ1xyXG4gICAgICB9XHJcbiAgICB9LFxyXG4gICAgY3VzdG9tQ29kZToge1xyXG4gICAgICB2YWx1ZTogbnVsbCxcclxuICAgICAgdHlwZXM6IFsnc3RyaW5nJywgJ251bGwnXSxcclxuICAgICAgZW52TGluazogJ0NVU1RPTV9MT0dJQ19DVVNUT01fQ09ERScsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdDdXN0b20gY29kZSB0byBleGVjdXRlIGJlZm9yZSBjaGFydCBpbml0aWFsaXphdGlvbi4gQ2FuIGJlIGEgZnVuY3Rpb24sIGNvZGUgd3JhcHBlZCBpbiBhIGZ1bmN0aW9uLCBvciBhIC5qcyBmaWxlbmFtZScsXHJcbiAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICB0eXBlOiAndGV4dCdcclxuICAgICAgfVxyXG4gICAgfSxcclxuICAgIGNhbGxiYWNrOiB7XHJcbiAgICAgIHZhbHVlOiBudWxsLFxyXG4gICAgICB0eXBlczogWydzdHJpbmcnLCAnbnVsbCddLFxyXG4gICAgICBlbnZMaW5rOiAnQ1VTVE9NX0xPR0lDX0NBTExCQUNLJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ0phdmFTY3JpcHQgY29kZSB0byBydW4gZHVyaW5nIGNvbnN0cnVjdGlvbi4gQ2FuIGJlIGEgZnVuY3Rpb24gb3IgYSAuanMgZmlsZW5hbWUnLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ3RleHQnXHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICByZXNvdXJjZXM6IHtcclxuICAgICAgdmFsdWU6IG51bGwsXHJcbiAgICAgIHR5cGVzOiBbJ09iamVjdCcsICdzdHJpbmcnLCAnbnVsbCddLFxyXG4gICAgICBlbnZMaW5rOiAnQ1VTVE9NX0xPR0lDX1JFU09VUkNFUycsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdBZGRpdGlvbmFsIHJlc291cmNlcyBhcyBKU09OLCBzdHJpbmdpZmllZCBKU09OLCBvciBmaWxlbmFtZSwgY29udGFpbmluZyBmaWxlcywganMsIGFuZCBjc3Mgc2VjdGlvbnMnLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ3RleHQnXHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICBsb2FkQ29uZmlnOiB7XHJcbiAgICAgIHZhbHVlOiBudWxsLFxyXG4gICAgICB0eXBlczogWydzdHJpbmcnLCAnbnVsbCddLFxyXG4gICAgICBlbnZMaW5rOiAnQ1VTVE9NX0xPR0lDX0xPQURfQ09ORklHJyxcclxuICAgICAgbGVnYWN5TmFtZTogJ2Zyb21GaWxlJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdGaWxlIHdpdGggYSBwcmUtZGVmaW5lZCBjb25maWd1cmF0aW9uIHRvIHVzZScsXHJcbiAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICB0eXBlOiAndGV4dCdcclxuICAgICAgfVxyXG4gICAgfSxcclxuICAgIGNyZWF0ZUNvbmZpZzoge1xyXG4gICAgICB2YWx1ZTogbnVsbCxcclxuICAgICAgdHlwZXM6IFsnc3RyaW5nJywgJ251bGwnXSxcclxuICAgICAgZW52TGluazogJ0NVU1RPTV9MT0dJQ19DUkVBVEVfQ09ORklHJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ1Byb21wdC1iYXNlZCBvcHRpb24gc2V0dGluZywgc2F2ZWQgdG8gYSBwcm92aWRlZCBjb25maWcgZmlsZScsXHJcbiAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICB0eXBlOiAndGV4dCdcclxuICAgICAgfVxyXG4gICAgfVxyXG4gIH0sXHJcbiAgc2VydmVyOiB7XHJcbiAgICBlbmFibGU6IHtcclxuICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICB0eXBlczogWydib29sZWFuJ10sXHJcbiAgICAgIGVudkxpbms6ICdTRVJWRVJfRU5BQkxFJyxcclxuICAgICAgY2xpTmFtZTogJ2VuYWJsZVNlcnZlcicsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnU3RhcnRzIHRoZSBzZXJ2ZXIgd2hlbiB0cnVlJyxcclxuICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgIHR5cGU6ICd0b2dnbGUnXHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICBob3N0OiB7XHJcbiAgICAgIHZhbHVlOiAnMC4wLjAuMCcsXHJcbiAgICAgIHR5cGVzOiBbJ3N0cmluZyddLFxyXG4gICAgICBlbnZMaW5rOiAnU0VSVkVSX0hPU1QnLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ0hvc3RuYW1lIG9mIHRoZSBzZXJ2ZXInLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ3RleHQnXHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICBwb3J0OiB7XHJcbiAgICAgIHZhbHVlOiA3ODAxLFxyXG4gICAgICB0eXBlczogWydudW1iZXInXSxcclxuICAgICAgZW52TGluazogJ1NFUlZFUl9QT1JUJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdQb3J0IG51bWJlciBmb3IgdGhlIHNlcnZlcicsXHJcbiAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICB0eXBlOiAnbnVtYmVyJ1xyXG4gICAgICB9XHJcbiAgICB9LFxyXG4gICAgdXBsb2FkTGltaXQ6IHtcclxuICAgICAgdmFsdWU6IDMsXHJcbiAgICAgIHR5cGVzOiBbJ251bWJlciddLFxyXG4gICAgICBlbnZMaW5rOiAnU0VSVkVSX1VQTE9BRF9MSU1JVCcsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnTWF4aW11bSByZXF1ZXN0IGJvZHkgc2l6ZSBpbiBNQicsXHJcbiAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICB0eXBlOiAnbnVtYmVyJ1xyXG4gICAgICB9XHJcbiAgICB9LFxyXG4gICAgYmVuY2htYXJraW5nOiB7XHJcbiAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgdHlwZXM6IFsnYm9vbGVhbiddLFxyXG4gICAgICBlbnZMaW5rOiAnU0VSVkVSX0JFTkNITUFSS0lORycsXHJcbiAgICAgIGNsaU5hbWU6ICdzZXJ2ZXJCZW5jaG1hcmtpbmcnLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnRGlzcGxheXMgb3Igbm90IGFjdGlvbiBkdXJhdGlvbnMgaW4gbWlsbGlzZWNvbmRzIGR1cmluZyBzZXJ2ZXIgcmVxdWVzdHMnLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ3RvZ2dsZSdcclxuICAgICAgfVxyXG4gICAgfSxcclxuICAgIHByb3h5OiB7XHJcbiAgICAgIGhvc3Q6IHtcclxuICAgICAgICB2YWx1ZTogbnVsbCxcclxuICAgICAgICB0eXBlczogWydzdHJpbmcnLCAnbnVsbCddLFxyXG4gICAgICAgIGVudkxpbms6ICdTRVJWRVJfUFJPWFlfSE9TVCcsXHJcbiAgICAgICAgY2xpTmFtZTogJ3Byb3h5SG9zdCcsXHJcbiAgICAgICAgZGVzY3JpcHRpb246ICdIb3N0IG9mIHRoZSBwcm94eSBzZXJ2ZXIsIGlmIGFwcGxpY2FibGUnLFxyXG4gICAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICAgIHR5cGU6ICd0ZXh0J1xyXG4gICAgICAgIH1cclxuICAgICAgfSxcclxuICAgICAgcG9ydDoge1xyXG4gICAgICAgIHZhbHVlOiBudWxsLFxyXG4gICAgICAgIHR5cGVzOiBbJ251bWJlcicsICdudWxsJ10sXHJcbiAgICAgICAgZW52TGluazogJ1NFUlZFUl9QUk9YWV9QT1JUJyxcclxuICAgICAgICBjbGlOYW1lOiAncHJveHlQb3J0JyxcclxuICAgICAgICBkZXNjcmlwdGlvbjogJ1BvcnQgb2YgdGhlIHByb3h5IHNlcnZlciwgaWYgYXBwbGljYWJsZScsXHJcbiAgICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgICAgdHlwZTogJ251bWJlcidcclxuICAgICAgICB9XHJcbiAgICAgIH0sXHJcbiAgICAgIHRpbWVvdXQ6IHtcclxuICAgICAgICB2YWx1ZTogNTAwMCxcclxuICAgICAgICB0eXBlczogWydudW1iZXInXSxcclxuICAgICAgICBlbnZMaW5rOiAnU0VSVkVSX1BST1hZX1RJTUVPVVQnLFxyXG4gICAgICAgIGNsaU5hbWU6ICdwcm94eVRpbWVvdXQnLFxyXG4gICAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICAgJ1RpbWVvdXQgaW4gbWlsbGlzZWNvbmRzIGZvciB0aGUgcHJveHkgc2VydmVyLCBpZiBhcHBsaWNhYmxlJyxcclxuICAgICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgICB0eXBlOiAnbnVtYmVyJ1xyXG4gICAgICAgIH1cclxuICAgICAgfVxyXG4gICAgfSxcclxuICAgIHJhdGVMaW1pdGluZzoge1xyXG4gICAgICBlbmFibGU6IHtcclxuICAgICAgICB2YWx1ZTogZmFsc2UsXHJcbiAgICAgICAgdHlwZXM6IFsnYm9vbGVhbiddLFxyXG4gICAgICAgIGVudkxpbms6ICdTRVJWRVJfUkFURV9MSU1JVElOR19FTkFCTEUnLFxyXG4gICAgICAgIGNsaU5hbWU6ICdlbmFibGVSYXRlTGltaXRpbmcnLFxyXG4gICAgICAgIGRlc2NyaXB0aW9uOiAnRW5hYmxlcyBvciBkaXNhYmxlcyByYXRlIGxpbWl0aW5nIG9uIHRoZSBzZXJ2ZXInLFxyXG4gICAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICAgIHR5cGU6ICd0b2dnbGUnXHJcbiAgICAgICAgfVxyXG4gICAgICB9LFxyXG4gICAgICBtYXhSZXF1ZXN0czoge1xyXG4gICAgICAgIHZhbHVlOiAxMCxcclxuICAgICAgICB0eXBlczogWydudW1iZXInXSxcclxuICAgICAgICBlbnZMaW5rOiAnU0VSVkVSX1JBVEVfTElNSVRJTkdfTUFYX1JFUVVFU1RTJyxcclxuICAgICAgICBsZWdhY3lOYW1lOiAncmF0ZUxpbWl0JyxcclxuICAgICAgICBkZXNjcmlwdGlvbjogJ01heGltdW0gbnVtYmVyIG9mIHJlcXVlc3RzIGFsbG93ZWQgcGVyIG1pbnV0ZScsXHJcbiAgICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgICAgdHlwZTogJ251bWJlcidcclxuICAgICAgICB9XHJcbiAgICAgIH0sXHJcbiAgICAgIHdpbmRvdzoge1xyXG4gICAgICAgIHZhbHVlOiAxLFxyXG4gICAgICAgIHR5cGVzOiBbJ251bWJlciddLFxyXG4gICAgICAgIGVudkxpbms6ICdTRVJWRVJfUkFURV9MSU1JVElOR19XSU5ET1cnLFxyXG4gICAgICAgIGRlc2NyaXB0aW9uOiAnVGltZSB3aW5kb3cgaW4gbWludXRlcyBmb3IgcmF0ZSBsaW1pdGluZycsXHJcbiAgICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgICAgdHlwZTogJ251bWJlcidcclxuICAgICAgICB9XHJcbiAgICAgIH0sXHJcbiAgICAgIGRlbGF5OiB7XHJcbiAgICAgICAgdmFsdWU6IDAsXHJcbiAgICAgICAgdHlwZXM6IFsnbnVtYmVyJ10sXHJcbiAgICAgICAgZW52TGluazogJ1NFUlZFUl9SQVRFX0xJTUlUSU5HX0RFTEFZJyxcclxuICAgICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAgICdEZWxheSBkdXJhdGlvbiBiZXR3ZWVuIHN1Y2Nlc3NpdmUgcmVxdWVzdHMgYmVmb3JlIHJlYWNoaW5nIHRoZSBsaW1pdCcsXHJcbiAgICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgICAgdHlwZTogJ251bWJlcidcclxuICAgICAgICB9XHJcbiAgICAgIH0sXHJcbiAgICAgIHRydXN0UHJveHk6IHtcclxuICAgICAgICB2YWx1ZTogZmFsc2UsXHJcbiAgICAgICAgdHlwZXM6IFsnYm9vbGVhbiddLFxyXG4gICAgICAgIGVudkxpbms6ICdTRVJWRVJfUkFURV9MSU1JVElOR19UUlVTVF9QUk9YWScsXHJcbiAgICAgICAgZGVzY3JpcHRpb246ICdTZXQgdG8gdHJ1ZSBpZiB0aGUgc2VydmVyIGlzIGJlaGluZCBhIGxvYWQgYmFsYW5jZXInLFxyXG4gICAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICAgIHR5cGU6ICd0b2dnbGUnXHJcbiAgICAgICAgfVxyXG4gICAgICB9LFxyXG4gICAgICBza2lwS2V5OiB7XHJcbiAgICAgICAgdmFsdWU6IG51bGwsXHJcbiAgICAgICAgdHlwZXM6IFsnc3RyaW5nJywgJ251bGwnXSxcclxuICAgICAgICBlbnZMaW5rOiAnU0VSVkVSX1JBVEVfTElNSVRJTkdfU0tJUF9LRVknLFxyXG4gICAgICAgIGRlc2NyaXB0aW9uOiAnS2V5IHRvIGJ5cGFzcyB0aGUgcmF0ZSBsaW1pdGVyLCB1c2VkIHdpdGggYHNraXBUb2tlbmAnLFxyXG4gICAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICAgIHR5cGU6ICd0ZXh0J1xyXG4gICAgICAgIH1cclxuICAgICAgfSxcclxuICAgICAgc2tpcFRva2VuOiB7XHJcbiAgICAgICAgdmFsdWU6IG51bGwsXHJcbiAgICAgICAgdHlwZXM6IFsnc3RyaW5nJywgJ251bGwnXSxcclxuICAgICAgICBlbnZMaW5rOiAnU0VSVkVSX1JBVEVfTElNSVRJTkdfU0tJUF9UT0tFTicsXHJcbiAgICAgICAgZGVzY3JpcHRpb246ICdUb2tlbiB0byBieXBhc3MgdGhlIHJhdGUgbGltaXRlciwgdXNlZCB3aXRoIGBza2lwS2V5YCcsXHJcbiAgICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgICAgdHlwZTogJ3RleHQnXHJcbiAgICAgICAgfVxyXG4gICAgICB9XHJcbiAgICB9LFxyXG4gICAgc3NsOiB7XHJcbiAgICAgIGVuYWJsZToge1xyXG4gICAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgICB0eXBlczogWydib29sZWFuJ10sXHJcbiAgICAgICAgZW52TGluazogJ1NFUlZFUl9TU0xfRU5BQkxFJyxcclxuICAgICAgICBjbGlOYW1lOiAnZW5hYmxlU3NsJyxcclxuICAgICAgICBkZXNjcmlwdGlvbjogJ0VuYWJsZXMgb3IgZGlzYWJsZXMgU1NMIHByb3RvY29sJyxcclxuICAgICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgICB0eXBlOiAndG9nZ2xlJ1xyXG4gICAgICAgIH1cclxuICAgICAgfSxcclxuICAgICAgZm9yY2U6IHtcclxuICAgICAgICB2YWx1ZTogZmFsc2UsXHJcbiAgICAgICAgdHlwZXM6IFsnYm9vbGVhbiddLFxyXG4gICAgICAgIGVudkxpbms6ICdTRVJWRVJfU1NMX0ZPUkNFJyxcclxuICAgICAgICBjbGlOYW1lOiAnc3NsRm9yY2UnLFxyXG4gICAgICAgIGxlZ2FjeU5hbWU6ICdzc2xPbmx5JyxcclxuICAgICAgICBkZXNjcmlwdGlvbjogJ0ZvcmNlcyB0aGUgc2VydmVyIHRvIHVzZSBIVFRQUyBvbmx5IHdoZW4gdHJ1ZScsXHJcbiAgICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgICAgdHlwZTogJ3RvZ2dsZSdcclxuICAgICAgICB9XHJcbiAgICAgIH0sXHJcbiAgICAgIHBvcnQ6IHtcclxuICAgICAgICB2YWx1ZTogNDQzLFxyXG4gICAgICAgIHR5cGVzOiBbJ251bWJlciddLFxyXG4gICAgICAgIGVudkxpbms6ICdTRVJWRVJfU1NMX1BPUlQnLFxyXG4gICAgICAgIGNsaU5hbWU6ICdzc2xQb3J0JyxcclxuICAgICAgICBkZXNjcmlwdGlvbjogJ1BvcnQgZm9yIHRoZSBTU0wgc2VydmVyJyxcclxuICAgICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgICB0eXBlOiAnbnVtYmVyJ1xyXG4gICAgICAgIH1cclxuICAgICAgfSxcclxuICAgICAgY2VydFBhdGg6IHtcclxuICAgICAgICB2YWx1ZTogbnVsbCxcclxuICAgICAgICB0eXBlczogWydzdHJpbmcnLCAnbnVsbCddLFxyXG4gICAgICAgIGVudkxpbms6ICdTRVJWRVJfU1NMX0NFUlRfUEFUSCcsXHJcbiAgICAgICAgY2xpTmFtZTogJ3NzbENlcnRQYXRoJyxcclxuICAgICAgICBsZWdhY3lOYW1lOiAnc3NsUGF0aCcsXHJcbiAgICAgICAgZGVzY3JpcHRpb246ICdQYXRoIHRvIHRoZSBTU0wgY2VydGlmaWNhdGUva2V5IGZpbGUnLFxyXG4gICAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICAgIHR5cGU6ICd0ZXh0J1xyXG4gICAgICAgIH1cclxuICAgICAgfVxyXG4gICAgfVxyXG4gIH0sXHJcbiAgcG9vbDoge1xyXG4gICAgbWluV29ya2Vyczoge1xyXG4gICAgICB2YWx1ZTogNCxcclxuICAgICAgdHlwZXM6IFsnbnVtYmVyJ10sXHJcbiAgICAgIGVudkxpbms6ICdQT09MX01JTl9XT1JLRVJTJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdNaW5pbXVtIGFuZCBpbml0aWFsIG51bWJlciBvZiBwb29sIHdvcmtlcnMgdG8gc3Bhd24nLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ251bWJlcidcclxuICAgICAgfVxyXG4gICAgfSxcclxuICAgIG1heFdvcmtlcnM6IHtcclxuICAgICAgdmFsdWU6IDgsXHJcbiAgICAgIHR5cGVzOiBbJ251bWJlciddLFxyXG4gICAgICBlbnZMaW5rOiAnUE9PTF9NQVhfV09SS0VSUycsXHJcbiAgICAgIGxlZ2FjeU5hbWU6ICd3b3JrZXJzJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdNYXhpbXVtIG51bWJlciBvZiBwb29sIHdvcmtlcnMgdG8gc3Bhd24nLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ251bWJlcidcclxuICAgICAgfVxyXG4gICAgfSxcclxuICAgIHdvcmtMaW1pdDoge1xyXG4gICAgICB2YWx1ZTogNDAsXHJcbiAgICAgIHR5cGVzOiBbJ251bWJlciddLFxyXG4gICAgICBlbnZMaW5rOiAnUE9PTF9XT1JLX0xJTUlUJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdOdW1iZXIgb2YgdGFza3MgYSB3b3JrZXIgY2FuIGhhbmRsZSBiZWZvcmUgcmVzdGFydGluZycsXHJcbiAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICB0eXBlOiAnbnVtYmVyJ1xyXG4gICAgICB9XHJcbiAgICB9LFxyXG4gICAgYWNxdWlyZVRpbWVvdXQ6IHtcclxuICAgICAgdmFsdWU6IDUwMDAsXHJcbiAgICAgIHR5cGVzOiBbJ251bWJlciddLFxyXG4gICAgICBlbnZMaW5rOiAnUE9PTF9BQ1FVSVJFX1RJTUVPVVQnLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ1RpbWVvdXQgaW4gbWlsbGlzZWNvbmRzIGZvciBhY3F1aXJpbmcgYSByZXNvdXJjZScsXHJcbiAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICB0eXBlOiAnbnVtYmVyJ1xyXG4gICAgICB9XHJcbiAgICB9LFxyXG4gICAgY3JlYXRlVGltZW91dDoge1xyXG4gICAgICB2YWx1ZTogNTAwMCxcclxuICAgICAgdHlwZXM6IFsnbnVtYmVyJ10sXHJcbiAgICAgIGVudkxpbms6ICdQT09MX0NSRUFURV9USU1FT1VUJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdUaW1lb3V0IGluIG1pbGxpc2Vjb25kcyBmb3IgY3JlYXRpbmcgYSByZXNvdXJjZScsXHJcbiAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICB0eXBlOiAnbnVtYmVyJ1xyXG4gICAgICB9XHJcbiAgICB9LFxyXG4gICAgZGVzdHJveVRpbWVvdXQ6IHtcclxuICAgICAgdmFsdWU6IDUwMDAsXHJcbiAgICAgIHR5cGVzOiBbJ251bWJlciddLFxyXG4gICAgICBlbnZMaW5rOiAnUE9PTF9ERVNUUk9ZX1RJTUVPVVQnLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ1RpbWVvdXQgaW4gbWlsbGlzZWNvbmRzIGZvciBkZXN0cm95aW5nIGEgcmVzb3VyY2UnLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ251bWJlcidcclxuICAgICAgfVxyXG4gICAgfSxcclxuICAgIGlkbGVUaW1lb3V0OiB7XHJcbiAgICAgIHZhbHVlOiAzMDAwMCxcclxuICAgICAgdHlwZXM6IFsnbnVtYmVyJ10sXHJcbiAgICAgIGVudkxpbms6ICdQT09MX0lETEVfVElNRU9VVCcsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnVGltZW91dCBpbiBtaWxsaXNlY29uZHMgZm9yIGRlc3Ryb3lpbmcgaWRsZSByZXNvdXJjZXMnLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ251bWJlcidcclxuICAgICAgfVxyXG4gICAgfSxcclxuICAgIGNyZWF0ZVJldHJ5SW50ZXJ2YWw6IHtcclxuICAgICAgdmFsdWU6IDIwMCxcclxuICAgICAgdHlwZXM6IFsnbnVtYmVyJ10sXHJcbiAgICAgIGVudkxpbms6ICdQT09MX0NSRUFURV9SRVRSWV9JTlRFUlZBTCcsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdJbnRlcnZhbCBpbiBtaWxsaXNlY29uZHMgYmVmb3JlIHJldHJ5aW5nIHJlc291cmNlIGNyZWF0aW9uIG9uIGZhaWx1cmUnLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ251bWJlcidcclxuICAgICAgfVxyXG4gICAgfSxcclxuICAgIHJlYXBlckludGVydmFsOiB7XHJcbiAgICAgIHZhbHVlOiAxMDAwLFxyXG4gICAgICB0eXBlczogWydudW1iZXInXSxcclxuICAgICAgZW52TGluazogJ1BPT0xfUkVBUEVSX0lOVEVSVkFMJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ0ludGVydmFsIGluIG1pbGxpc2Vjb25kcyB0byBjaGVjayBhbmQgZGVzdHJveSBpZGxlIHJlc291cmNlcycsXHJcbiAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICB0eXBlOiAnbnVtYmVyJ1xyXG4gICAgICB9XHJcbiAgICB9LFxyXG4gICAgYmVuY2htYXJraW5nOiB7XHJcbiAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgdHlwZXM6IFsnYm9vbGVhbiddLFxyXG4gICAgICBlbnZMaW5rOiAnUE9PTF9CRU5DSE1BUktJTkcnLFxyXG4gICAgICBjbGlOYW1lOiAncG9vbEJlbmNobWFya2luZycsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnU2hvd3Mgc3RhdGlzdGljcyBmb3IgdGhlIHBvb2wgb2YgcmVzb3VyY2VzJyxcclxuICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgIHR5cGU6ICd0b2dnbGUnXHJcbiAgICAgIH1cclxuICAgIH1cclxuICB9LFxyXG4gIGxvZ2dpbmc6IHtcclxuICAgIGxldmVsOiB7XHJcbiAgICAgIHZhbHVlOiA0LFxyXG4gICAgICB0eXBlczogWydudW1iZXInXSxcclxuICAgICAgZW52TGluazogJ0xPR0dJTkdfTEVWRUwnLFxyXG4gICAgICBjbGlOYW1lOiAnbG9nTGV2ZWwnLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ0xvZ2dpbmcgdmVyYm9zaXR5IGxldmVsJyxcclxuICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICAgIHJvdW5kOiAwLFxyXG4gICAgICAgIG1pbjogMCxcclxuICAgICAgICBtYXg6IDVcclxuICAgICAgfVxyXG4gICAgfSxcclxuICAgIGZpbGU6IHtcclxuICAgICAgdmFsdWU6ICdoaWdoY2hhcnRzLWV4cG9ydC1zZXJ2ZXIubG9nJyxcclxuICAgICAgdHlwZXM6IFsnc3RyaW5nJ10sXHJcbiAgICAgIGVudkxpbms6ICdMT0dHSU5HX0ZJTEUnLFxyXG4gICAgICBjbGlOYW1lOiAnbG9nRmlsZScsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdMb2cgZmlsZSBuYW1lLiBSZXF1aXJlcyBgbG9nVG9GaWxlYCBhbmQgYGxvZ0Rlc3RgIHRvIGJlIHNldCcsXHJcbiAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICB0eXBlOiAndGV4dCdcclxuICAgICAgfVxyXG4gICAgfSxcclxuICAgIGRlc3Q6IHtcclxuICAgICAgdmFsdWU6ICdsb2cnLFxyXG4gICAgICB0eXBlczogWydzdHJpbmcnXSxcclxuICAgICAgZW52TGluazogJ0xPR0dJTkdfREVTVCcsXHJcbiAgICAgIGNsaU5hbWU6ICdsb2dEZXN0JyxcclxuICAgICAgZGVzY3JpcHRpb246ICdQYXRoIHRvIHN0b3JlIGxvZyBmaWxlcy4gUmVxdWlyZXMgYGxvZ1RvRmlsZWAgdG8gYmUgc2V0JyxcclxuICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgIHR5cGU6ICd0ZXh0J1xyXG4gICAgICB9XHJcbiAgICB9LFxyXG4gICAgdG9Db25zb2xlOiB7XHJcbiAgICAgIHZhbHVlOiB0cnVlLFxyXG4gICAgICB0eXBlczogWydib29sZWFuJ10sXHJcbiAgICAgIGVudkxpbms6ICdMT0dHSU5HX1RPX0NPTlNPTEUnLFxyXG4gICAgICBjbGlOYW1lOiAnbG9nVG9Db25zb2xlJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdFbmFibGVzIG9yIGRpc2FibGVzIGNvbnNvbGUgbG9nZ2luZycsXHJcbiAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICB0eXBlOiAndG9nZ2xlJ1xyXG4gICAgICB9XHJcbiAgICB9LFxyXG4gICAgdG9GaWxlOiB7XHJcbiAgICAgIHZhbHVlOiB0cnVlLFxyXG4gICAgICB0eXBlczogWydib29sZWFuJ10sXHJcbiAgICAgIGVudkxpbms6ICdMT0dHSU5HX1RPX0ZJTEUnLFxyXG4gICAgICBjbGlOYW1lOiAnbG9nVG9GaWxlJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdFbmFibGVzIG9yIGRpc2FibGVzIGxvZ2dpbmcgdG8gYSBmaWxlJyxcclxuICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgIHR5cGU6ICd0b2dnbGUnXHJcbiAgICAgIH1cclxuICAgIH1cclxuICB9LFxyXG4gIHVpOiB7XHJcbiAgICBlbmFibGU6IHtcclxuICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICB0eXBlczogWydib29sZWFuJ10sXHJcbiAgICAgIGVudkxpbms6ICdVSV9FTkFCTEUnLFxyXG4gICAgICBjbGlOYW1lOiAnZW5hYmxlVWknLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ0VuYWJsZXMgb3IgZGlzYWJsZXMgdGhlIFVJIGZvciB0aGUgZXhwb3J0IHNlcnZlcicsXHJcbiAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICB0eXBlOiAndG9nZ2xlJ1xyXG4gICAgICB9XHJcbiAgICB9LFxyXG4gICAgcm91dGU6IHtcclxuICAgICAgdmFsdWU6ICcvJyxcclxuICAgICAgdHlwZXM6IFsnc3RyaW5nJ10sXHJcbiAgICAgIGVudkxpbms6ICdVSV9ST1VURScsXHJcbiAgICAgIGNsaU5hbWU6ICd1aVJvdXRlJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdUaGUgZW5kcG9pbnQgcm91dGUgZm9yIHRoZSBVSScsXHJcbiAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICB0eXBlOiAndGV4dCdcclxuICAgICAgfVxyXG4gICAgfVxyXG4gIH0sXHJcbiAgb3RoZXI6IHtcclxuICAgIG5vZGVFbnY6IHtcclxuICAgICAgdmFsdWU6ICdwcm9kdWN0aW9uJyxcclxuICAgICAgdHlwZXM6IFsnc3RyaW5nJ10sXHJcbiAgICAgIGVudkxpbms6ICdPVEhFUl9OT0RFX0VOVicsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnVGhlIE5vZGUuanMgZW52aXJvbm1lbnQgdHlwZScsXHJcbiAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICB0eXBlOiAndGV4dCdcclxuICAgICAgfVxyXG4gICAgfSxcclxuICAgIGxpc3RlblRvUHJvY2Vzc0V4aXRzOiB7XHJcbiAgICAgIHZhbHVlOiB0cnVlLFxyXG4gICAgICB0eXBlczogWydib29sZWFuJ10sXHJcbiAgICAgIGVudkxpbms6ICdPVEhFUl9MSVNURU5fVE9fUFJPQ0VTU19FWElUUycsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnV2hldGhlciBvciBub3QgdG8gYXR0YWNoIHByb2Nlc3MuZXhpdCBoYW5kbGVycycsXHJcbiAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICB0eXBlOiAndG9nZ2xlJ1xyXG4gICAgICB9XHJcbiAgICB9LFxyXG4gICAgbm9Mb2dvOiB7XHJcbiAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgdHlwZXM6IFsnYm9vbGVhbiddLFxyXG4gICAgICBlbnZMaW5rOiAnT1RIRVJfTk9fTE9HTycsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnRGlzcGxheSBvciBza2lwIHByaW50aW5nIHRoZSBsb2dvIG9uIHN0YXJ0dXAnLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ3RvZ2dsZSdcclxuICAgICAgfVxyXG4gICAgfSxcclxuICAgIGhhcmRSZXNldFBhZ2U6IHtcclxuICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICB0eXBlczogWydib29sZWFuJ10sXHJcbiAgICAgIGVudkxpbms6ICdPVEhFUl9IQVJEX1JFU0VUX1BBR0UnLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ1doZXRoZXIgb3Igbm90IHRvIHJlc2V0IHRoZSBwYWdlIGNvbnRlbnQgZW50aXJlbHknLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ3RvZ2dsZSdcclxuICAgICAgfVxyXG4gICAgfSxcclxuICAgIGJyb3dzZXJTaGVsbE1vZGU6IHtcclxuICAgICAgdmFsdWU6IHRydWUsXHJcbiAgICAgIHR5cGVzOiBbJ2Jvb2xlYW4nXSxcclxuICAgICAgZW52TGluazogJ09USEVSX0JST1dTRVJfU0hFTExfTU9ERScsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnV2hldGhlciBvciBub3QgdG8gc2V0IHRoZSBicm93c2VyIHRvIHJ1biBpbiBzaGVsbCBtb2RlJyxcclxuICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgIHR5cGU6ICd0b2dnbGUnXHJcbiAgICAgIH1cclxuICAgIH1cclxuICB9LFxyXG4gIGRlYnVnOiB7XHJcbiAgICBlbmFibGU6IHtcclxuICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICB0eXBlczogWydib29sZWFuJ10sXHJcbiAgICAgIGVudkxpbms6ICdERUJVR19FTkFCTEUnLFxyXG4gICAgICBjbGlOYW1lOiAnZW5hYmxlRGVidWcnLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ0VuYWJsZXMgb3IgZGlzYWJsZXMgZGVidWcgbW9kZSBmb3IgdGhlIHVuZGVybHlpbmcgYnJvd3NlcicsXHJcbiAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICB0eXBlOiAndG9nZ2xlJ1xyXG4gICAgICB9XHJcbiAgICB9LFxyXG4gICAgaGVhZGxlc3M6IHtcclxuICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICB0eXBlczogWydib29sZWFuJ10sXHJcbiAgICAgIGVudkxpbms6ICdERUJVR19IRUFETEVTUycsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdXaGV0aGVyIG9yIG5vdCB0byBzZXQgdGhlIGJyb3dzZXIgdG8gcnVuIGluIGhlYWRsZXNzIG1vZGUgZHVyaW5nIGRlYnVnZ2luZycsXHJcbiAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICB0eXBlOiAndG9nZ2xlJ1xyXG4gICAgICB9XHJcbiAgICB9LFxyXG4gICAgZGV2dG9vbHM6IHtcclxuICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICB0eXBlczogWydib29sZWFuJ10sXHJcbiAgICAgIGVudkxpbms6ICdERUJVR19ERVZUT09MUycsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnRW5hYmxlcyBvciBkaXNhYmxlcyBEZXZUb29scyBpbiBoZWFkZnVsIG1vZGUnLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ3RvZ2dsZSdcclxuICAgICAgfVxyXG4gICAgfSxcclxuICAgIGxpc3RlblRvQ29uc29sZToge1xyXG4gICAgICB2YWx1ZTogZmFsc2UsXHJcbiAgICAgIHR5cGVzOiBbJ2Jvb2xlYW4nXSxcclxuICAgICAgZW52TGluazogJ0RFQlVHX0xJU1RFTl9UT19DT05TT0xFJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ0VuYWJsZXMgb3IgZGlzYWJsZXMgbGlzdGVuaW5nIHRvIGNvbnNvbGUgbWVzc2FnZXMgZnJvbSB0aGUgYnJvd3NlcicsXHJcbiAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICB0eXBlOiAndG9nZ2xlJ1xyXG4gICAgICB9XHJcbiAgICB9LFxyXG4gICAgZHVtcGlvOiB7XHJcbiAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgdHlwZXM6IFsnYm9vbGVhbiddLFxyXG4gICAgICBlbnZMaW5rOiAnREVCVUdfRFVNUElPJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ1JlZGlyZWN0cyBvciBub3QgYnJvd3NlciBzdGRvdXQgYW5kIHN0ZGVyciB0byBwcm9jZXNzLnN0ZG91dCBhbmQgcHJvY2Vzcy5zdGRlcnInLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ3RvZ2dsZSdcclxuICAgICAgfVxyXG4gICAgfSxcclxuICAgIHNsb3dNbzoge1xyXG4gICAgICB2YWx1ZTogMCxcclxuICAgICAgdHlwZXM6IFsnbnVtYmVyJ10sXHJcbiAgICAgIGVudkxpbms6ICdERUJVR19TTE9XX01PJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdEZWxheXMgUHVwcGV0ZWVyIG9wZXJhdGlvbnMgYnkgdGhlIHNwZWNpZmllZCBtaWxsaXNlY29uZHMnLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ251bWJlcidcclxuICAgICAgfVxyXG4gICAgfSxcclxuICAgIGRlYnVnZ2luZ1BvcnQ6IHtcclxuICAgICAgdmFsdWU6IDkyMjIsXHJcbiAgICAgIHR5cGVzOiBbJ251bWJlciddLFxyXG4gICAgICBlbnZMaW5rOiAnREVCVUdfREVCVUdHSU5HX1BPUlQnLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ1BvcnQgdXNlZCBmb3IgZGVidWdnaW5nJyxcclxuICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgIHR5cGU6ICdudW1iZXInXHJcbiAgICAgIH1cclxuICAgIH1cclxuICB9XHJcbn07XHJcblxyXG4vLyBQcm9wZXJ0aWVzIG5lc3RpbmcgbGV2ZWwgb2YgYWxsIG9wdGlvbnNcclxuZXhwb3J0IGNvbnN0IG5lc3RlZFByb3BzID0gX2NyZWF0ZU5lc3RlZFByb3BzKGRlZmF1bHRDb25maWcpO1xyXG5cclxuLy8gUHJvcGVydGllcyBuYW1lcyB0aGF0IHNob3VsZCBub3QgYmUgcmVjdXJzaXZlbHkgbWVyZ2VkXHJcbmV4cG9ydCBjb25zdCBhYnNvbHV0ZVByb3BzID0gX2NyZWF0ZUFic29sdXRlUHJvcHMoZGVmYXVsdENvbmZpZyk7XHJcblxyXG4vKipcclxuICogUmVjdXJzaXZlbHkgZ2VuZXJhdGVzIGEgbWFwcGluZyBvZiBuZXN0ZWQgYXJndW1lbnQgY2hhaW5zIGZyb20gYSBuZXN0ZWRcclxuICogY29uZmlnIG9iamVjdC4gVGhpcyBmdW5jdGlvbiB0cmF2ZXJzZXMgYSBuZXN0ZWQgb2JqZWN0IGFuZCBjcmVhdGVzIGEgbWFwcGluZ1xyXG4gKiB3aGVyZSBlYWNoIGtleSBpcyBhbiBhcmd1bWVudCBuYW1lIChlaXRoZXIgZnJvbSBgY2xpTmFtZWAsIGBsZWdhY3lOYW1lYCxcclxuICogb3IgdGhlIG9yaWdpbmFsIGtleSkgYW5kIGVhY2ggdmFsdWUgaXMgYSBzdHJpbmcgcmVwcmVzZW50aW5nIHRoZSBjaGFpblxyXG4gKiBvZiBuZXN0ZWQgcHJvcGVydGllcyBsZWFkaW5nIHRvIHRoYXQgYXJndW1lbnQuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBfY3JlYXRlTmVzdGVkUHJvcHNcclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IGNvbmZpZyAtIFRoZSBjb25maWd1cmF0aW9uIG9iamVjdC5cclxuICogQHBhcmFtIHtPYmplY3R9IFtuZXN0ZWRQcm9wcz17fV0gLSBUaGUgYWNjdW11bGF0b3Igb2JqZWN0IGZvciBzdG9yaW5nXHJcbiAqIHRoZSByZXN1bHRpbmcgYXJndW1lbnRzIGNoYWlucy4gIFRoZSBkZWZhdWx0IHZhbHVlIGlzIGFuIGVtcHR5IG9iamVjdC5cclxuICogQHBhcmFtIHtzdHJpbmd9IFtwcm9wQ2hhaW49JyddIC0gVGhlIGN1cnJlbnQgY2hhaW4gb2YgbmVzdGVkIHByb3BlcnRpZXMsXHJcbiAqIHVzZWQgaW50ZXJuYWxseSBkdXJpbmcgcmVjdXJzaW9uLiAgVGhlIGRlZmF1bHQgdmFsdWUgaXMgYW4gZW1wdHkgc3RyaW5nLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7T2JqZWN0fSBBbiBvYmplY3QgbWFwcGluZyBhcmd1bWVudCBuYW1lcyB0byB0aGVpciBjb3JyZXNwb25kaW5nXHJcbiAqIG5lc3RlZCBwcm9wZXJ0eSBjaGFpbnMuXHJcbiAqL1xyXG5mdW5jdGlvbiBfY3JlYXRlTmVzdGVkUHJvcHMoY29uZmlnLCBuZXN0ZWRQcm9wcyA9IHt9LCBwcm9wQ2hhaW4gPSAnJykge1xyXG4gIE9iamVjdC5rZXlzKGNvbmZpZykuZm9yRWFjaCgoa2V5KSA9PiB7XHJcbiAgICAvLyBHZXQgdGhlIHNwZWNpZmljIHNlY3Rpb25cclxuICAgIGNvbnN0IGVudHJ5ID0gY29uZmlnW2tleV07XHJcblxyXG4gICAgLy8gQ2hlY2sgaWYgdGhlcmUgaXMgc3RpbGwgbW9yZSBkZXB0aCB0byB0cmF2ZXJzZVxyXG4gICAgaWYgKHR5cGVvZiBlbnRyeS52YWx1ZSA9PT0gJ3VuZGVmaW5lZCcpIHtcclxuICAgICAgLy8gUmVjdXJzZSBpbnRvIGRlZXBlciBsZXZlbHMgb2YgbmVzdGVkIGFyZ3VtZW50c1xyXG4gICAgICBfY3JlYXRlTmVzdGVkUHJvcHMoZW50cnksIG5lc3RlZFByb3BzLCBgJHtwcm9wQ2hhaW59LiR7a2V5fWApO1xyXG4gICAgfSBlbHNlIHtcclxuICAgICAgLy8gQ3JlYXRlIHRoZSBjaGFpbiBvZiBuZXN0ZWQgYXJndW1lbnRzXHJcbiAgICAgIG5lc3RlZFByb3BzW2VudHJ5LmNsaU5hbWUgfHwga2V5XSA9IGAke3Byb3BDaGFpbn0uJHtrZXl9YC5zdWJzdHJpbmcoMSk7XHJcblxyXG4gICAgICAvLyBTdXBwb3J0IGZvciB0aGUgbGVnYWN5LCBQaGFudG9tSlMgcHJvcGVydGllcyBuYW1lc1xyXG4gICAgICBpZiAoZW50cnkubGVnYWN5TmFtZSAhPT0gdW5kZWZpbmVkKSB7XHJcbiAgICAgICAgbmVzdGVkUHJvcHNbZW50cnkubGVnYWN5TmFtZV0gPSBgJHtwcm9wQ2hhaW59LiR7a2V5fWAuc3Vic3RyaW5nKDEpO1xyXG4gICAgICB9XHJcbiAgICB9XHJcbiAgfSk7XHJcblxyXG4gIC8vIFJldHVybiB0aGUgb2JqZWN0IHdpdGggbmVzdGVkIGFyZ3VtZW50IGNoYWluc1xyXG4gIHJldHVybiBuZXN0ZWRQcm9wcztcclxufVxyXG5cclxuLyoqXHJcbiAqIFJlY3Vyc2l2ZWx5IGdhdGhlcnMgdGhlIG5hbWVzIG9mIHByb3BlcnRpZXMgZnJvbSBhIGNvbmZpZ3VyYXRpb24gb2JqZWN0IHRoYXRcclxuICogY2FuIGJlIHRyZWF0ZWQgYXMgYWJzb2x1dGUgcHJvcGVydGllcy4gVGhlc2UgcHJvcGVydGllcyBoYXZlIHZhbHVlcyB0aGF0XHJcbiAqIGFyZSBvYmplY3RzIGFuZCBkbyBub3QgY29udGFpbiBmdXJ0aGVyIG5lc3RlZCBkZXB0aCB3aGVuIG1lcmdpbmcgYW4gb2JqZWN0XHJcbiAqIGNvbnRhaW5pbmcgdGhlc2Ugb3B0aW9ucy5cclxuICpcclxuICogQGZ1bmN0aW9uIF9jcmVhdGVBYnNvbHV0ZVByb3BzXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBjb25maWcgLSBUaGUgY29uZmlndXJhdGlvbiBvYmplY3QuXHJcbiAqIEBwYXJhbSB7QXJyYXkuPHN0cmluZz59IFthYnNvbHV0ZVByb3BzPVtdXSAtIEFuIGFycmF5IHRvIGNvbGxlY3QgdGhlIG5hbWVzXHJcbiAqIG9mIGFic29sdXRlIHByb3BlcnRpZXMuIFRoZSBkZWZhdWx0IHZhbHVlIGlzIGFuIGVtcHR5IGFycmF5LlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7QXJyYXkuPHN0cmluZz59IEFuIGFycmF5IGNvbnRhaW5pbmcgdGhlIG5hbWVzIG9mIGFic29sdXRlXHJcbiAqIHByb3BlcnRpZXMuXHJcbiAqL1xyXG5mdW5jdGlvbiBfY3JlYXRlQWJzb2x1dGVQcm9wcyhjb25maWcsIGFic29sdXRlUHJvcHMgPSBbXSkge1xyXG4gIE9iamVjdC5rZXlzKGNvbmZpZykuZm9yRWFjaCgoa2V5KSA9PiB7XHJcbiAgICAvLyBHZXQgdGhlIHNwZWNpZmljIHNlY3Rpb25cclxuICAgIGNvbnN0IGVudHJ5ID0gY29uZmlnW2tleV07XHJcblxyXG4gICAgLy8gQ2hlY2sgaWYgdGhlcmUgaXMgc3RpbGwgbW9yZSBkZXB0aCB0byB0cmF2ZXJzZVxyXG4gICAgaWYgKHR5cGVvZiBlbnRyeS50eXBlcyA9PT0gJ3VuZGVmaW5lZCcpIHtcclxuICAgICAgLy8gUmVjdXJzZSBpbnRvIGRlZXBlciBsZXZlbHNcclxuICAgICAgX2NyZWF0ZUFic29sdXRlUHJvcHMoZW50cnksIGFic29sdXRlUHJvcHMpO1xyXG4gICAgfSBlbHNlIHtcclxuICAgICAgLy8gSWYgdGhlIG9wdGlvbiBjYW4gYmUgYW4gb2JqZWN0LCBzYXZlIGl0cyB0eXBlIGluIHRoZSBhcnJheVxyXG4gICAgICBpZiAoZW50cnkudHlwZXMuaW5jbHVkZXMoJ09iamVjdCcpKSB7XHJcbiAgICAgICAgYWJzb2x1dGVQcm9wcy5wdXNoKGtleSk7XHJcbiAgICAgIH1cclxuICAgIH1cclxuICB9KTtcclxuXHJcbiAgLy8gUmV0dXJuIHRoZSBhcnJheSB3aXRoIHRoZSBuYW1lcyBvZiBhYnNvbHV0ZSBwcm9wZXJ0aWVzXHJcbiAgcmV0dXJuIGFic29sdXRlUHJvcHM7XHJcbn1cclxuXHJcbmV4cG9ydCBkZWZhdWx0IHtcclxuICBkZWZhdWx0Q29uZmlnLFxyXG4gIG5lc3RlZFByb3BzLFxyXG4gIGFic29sdXRlUHJvcHNcclxufTtcclxuIiwiLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcclxuXHJcbkhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlclxyXG5cclxuQ29weXJpZ2h0IChjKSAyMDE2LTIwMjUsIEhpZ2hzb2Z0XHJcblxyXG5MaWNlbmNlZCB1bmRlciB0aGUgTUlUIGxpY2VuY2UuXHJcblxyXG5BZGRpdGlvbmFsbHkgYSB2YWxpZCBIaWdoY2hhcnRzIGxpY2Vuc2UgaXMgcmVxdWlyZWQgZm9yIHVzZS5cclxuXHJcblNlZSBMSUNFTlNFIGZpbGUgaW4gcm9vdCBmb3IgZGV0YWlscy5cclxuXHJcbioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXHJcblxyXG4vKipcclxuICogQG92ZXJ2aWV3IFRoaXMgZmlsZSBoYW5kbGVzIHBhcnNpbmcgYW5kIHZhbGlkYXRpbmcgb3B0aW9ucyBmcm9tIG11bHRpcGxlXHJcbiAqIHNvdXJjZXMgKHRoZSBjb25maWcgZmlsZSwgY3VzdG9tIEpTT04sIGVudmlyb25tZW50IHZhcmlhYmxlcywgQ0xJIGFyZ3VtZW50cyxcclxuICogYW5kIHJlcXVlc3QgcGF5bG9hZCkgdXNpbmcgdGhlICd6b2QnIGxpYnJhcnkuXHJcbiAqXHJcbiAqIEVudmlyb25tZW50IHZhcmlhYmxlcyBhcmUgcGFyc2VkIGFuZCB2YWxpZGF0ZWQgb25seSBvbmNlIGF0IGFwcGxpY2F0aW9uXHJcbiAqIHN0YXJ0dXAsIGFuZCB0aGUgdmFsaWRhdGVkIHJlc3VsdHMgYXJlIGV4cG9ydGVkIGFzIGBlbnZzYCBmb3IgdXNlIHRocm91Z2hvdXRcclxuICogdGhlIGFwcGxpY2F0aW9uLlxyXG4gKlxyXG4gKiBPcHRpb25zIGZyb20gb3RoZXIgc291cmNlcywgaG93ZXZlciwgYXJlIHBhcnNlZCBhbmQgdmFsaWRhdGVkIG9uIGRlbWFuZCxcclxuICogZWFjaCB0aW1lIGFuIGV4cG9ydCBpcyBhdHRlbXB0ZWQuXHJcbiAqL1xyXG5cclxuaW1wb3J0IGRvdGVudiBmcm9tICdkb3RlbnYnO1xyXG5pbXBvcnQgeyB6IH0gZnJvbSAnem9kJztcclxuXHJcbmltcG9ydCB7IGRlZmF1bHRDb25maWcgfSBmcm9tICcuL3NjaGVtYXMvY29uZmlnLmpzJztcclxuXHJcbi8vIExvYWQgdGhlIC5lbnYgaW50byBlbnZpcm9ubWVudCB2YXJpYWJsZXNcclxuZG90ZW52LmNvbmZpZygpO1xyXG5cclxuLy8gR2V0IHNjcmlwdHMgbmFtZXMgb2YgZWFjaCBjYXRlZ29yeSBmcm9tIHRoZSBkZWZhdWx0IGNvbmZpZ1xyXG5jb25zdCB7IGNvcmVTY3JpcHRzLCBtb2R1bGVTY3JpcHRzLCBpbmRpY2F0b3JTY3JpcHRzIH0gPVxyXG4gIGRlZmF1bHRDb25maWcuaGlnaGNoYXJ0cztcclxuXHJcbi8vIFNldHMgdGhlIGN1c3RvbSBlcnJvciBtYXAgZ2xvYmFsbHlcclxuei5zZXRFcnJvck1hcChfY3VzdG9tRXJyb3JNYXApO1xyXG5cclxuLyoqXHJcbiAqIE9iamVjdCBjb250YWluaW5nIGN1c3RvbSBnZW5lcmFsIHZhbGlkYXRvcnMgYW5kIHBhcnNlcnMgdG8gYXZvaWQgcmVwZXRpdGlvblxyXG4gKiBpbiBzY2hlbWEgb2JqZWN0cy4gQWxsIHZhbGlkYXRvcnMgYXBwbHkgdG8gdmFsdWVzIGZyb20gdmFyaW91cyBzb3VyY2VzLFxyXG4gKiBpbmNsdWRpbmcgdGhlIGRlZmF1bHQgY29uZmlnIGZpbGUsIGEgY3VzdG9tIEpTT04gZmlsZSBsb2FkZWQgd2l0aCB0aGUgb3B0aW9uXHJcbiAqIGNhbGxlZCBgbG9hZENvbmZpZ2AsIHRoZSAuZW52IGZpbGUsIENMSSBhcmd1bWVudHMsIGFuZCB0aGUgcmVxdWVzdCBwYXlsb2FkLlxyXG4gKiBUaGUgYHN0cmljdENoZWNrYCBmbGFnIGVuYWJsZXMgc3RyaWN0ZXIgdmFsaWRhdGlvbiBhbmQgcGFyc2luZyBydWxlcy4gVGhpc1xyXG4gKiBmbGFnIGlzIHNldCB0byBmYWxzZSBmb3IgdmFsdWVzIHRoYXQgY29tZSBmcm9tIHRoZSAuZW52IGZpbGUgb3IgQ0xJIGFyZ3VtZW50c1xyXG4gKiBiZWNhdXNlIHRoZXkgYXJlIHByb3ZpZGVkIGFzIHN0cmluZ3MgYW5kIG5lZWQgdG8gYmUgcGFyc2VkIGFjY29yZGluZ2x5IGZpcnN0LlxyXG4gKi9cclxuY29uc3QgdiA9IHtcclxuICAvKipcclxuICAgKiBUaGUgYGJvb2xlYW5gIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGggYW4gb3B0aW9uYWwgc3RyaWN0ZXJcclxuICAgKiBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGF0OlxyXG4gICAqXHJcbiAgICogLSBXaGVuIGBzdHJpY3RDaGVja2AgaXMgdHJ1ZSwgdGhlIHNjaGVtYSB3aWxsIGFjY2VwdCB2YWx1ZXMgYXJlIHRydWVcclxuICAgKiBhbmQgZmFsc2UgYW5kIHRoZSBzY2hlbWEgd2lsbCB2YWxpZGF0ZSBhZ2FpbnN0IHRoZSBkZWZhdWx0IGJvb2xlYW5cclxuICAgKiB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiAtIFdoZW4gYHN0cmljdENoZWNrYCBpcyBmYWxzZSwgdGhlIHNjaGVtYSB3aWxsIGFjY2VwdCB2YWx1ZXMgYXJlIHRydWUsXHJcbiAgICogZmFsc2UsIG51bGwsICd0cnVlJywgJ2ZhbHNlJywgJ3VuZGVmaW5lZCcsICdudWxsJywgYW5kICcnLiBUaGUgc3RyaW5nc1xyXG4gICAqICd1bmRlZmluZWQnLCAnbnVsbCcsIGFuZCAnJyB3aWxsIGJlIHRyYW5zZm9ybWVkIHRvIG51bGwsIHRoZSBzdHJpbmcgJ3RydWUnXHJcbiAgICogd2lsbCBiZSB0cmFuc2Zvcm1lZCB0byB0aGUgYm9vbGVhbiB2YWx1ZSB0cnVlLCBhbmQgJ2ZhbHNlJyB3aWxsXHJcbiAgICogYmUgdHJhbnNmb3JtZWQgdG8gdGhlIGJvb2xlYW4gdmFsdWUgZmFsc2UuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gYm9vbGVhblxyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nIGJvb2xlYW4gdmFsdWVzLlxyXG4gICAqL1xyXG4gIGJvb2xlYW4oc3RyaWN0Q2hlY2spIHtcclxuICAgIHJldHVybiBzdHJpY3RDaGVja1xyXG4gICAgICA/IHouYm9vbGVhbigpXHJcbiAgICAgIDogelxyXG4gICAgICAgICAgLnVuaW9uKFtcclxuICAgICAgICAgICAgelxyXG4gICAgICAgICAgICAgIC5lbnVtKFsndHJ1ZScsICdmYWxzZScsICd1bmRlZmluZWQnLCAnbnVsbCcsICcnXSlcclxuICAgICAgICAgICAgICAudHJhbnNmb3JtKCh2YWx1ZSkgPT5cclxuICAgICAgICAgICAgICAgICFbJ3VuZGVmaW5lZCcsICdudWxsJywgJyddLmluY2x1ZGVzKHZhbHVlKVxyXG4gICAgICAgICAgICAgICAgICA/IHZhbHVlID09PSAndHJ1ZSdcclxuICAgICAgICAgICAgICAgICAgOiBudWxsXHJcbiAgICAgICAgICAgICAgKSxcclxuICAgICAgICAgICAgei5ib29sZWFuKClcclxuICAgICAgICAgIF0pXHJcbiAgICAgICAgICAubnVsbGFibGUoKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYHN0cmluZ2AgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbCBzdHJpY3RlclxyXG4gICAqIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoYXQ6XHJcbiAgICpcclxuICAgKiAtIFdoZW4gYHN0cmljdENoZWNrYCBpcyB0cnVlLCB0aGUgc2NoZW1hIHdpbGwgYWNjZXB0IHRyaW1tZWQgc3RyaW5ncyBleGNlcHRcclxuICAgKiB0aGUgZm9yYmlkZGVuIHZhbHVlczogJ2ZhbHNlJywgJ3VuZGVmaW5lZCcsICdudWxsJywgYW5kICcnLlxyXG4gICAqXHJcbiAgICogLSBXaGVuIGBzdHJpY3RDaGVja2AgaXMgZmFsc2UsIHRoZSBzY2hlbWEgd2lsbCBhY2NlcHQgdHJpbW1lZCBzdHJpbmdzXHJcbiAgICogYW5kIG51bGwuIFRoZSBmb3JiaWRkZW4gdmFsdWVzOiAnZmFsc2UnLCAndW5kZWZpbmVkJywgJ251bGwnLCBhbmQgJycgd2lsbFxyXG4gICAqIGJlIHRyYW5zZm9ybWVkIHRvIG51bGwuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gc3RyaW5nXHJcbiAgICpcclxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IHN0cmljdENoZWNrIC0gRGV0ZXJtaW5lcyBpZiBzdHJpY3RlciB2YWxpZGF0aW9uIHNob3VsZFxyXG4gICAqIGJlIGFwcGxpZWQuXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9IEEgWm9kIHNjaGVtYSBvYmplY3QgZm9yIHZhbGlkYXRpbmcgc3RyaW5nIHZhbHVlcy5cclxuICAgKi9cclxuICBzdHJpbmcoc3RyaWN0Q2hlY2spIHtcclxuICAgIHJldHVybiBzdHJpY3RDaGVja1xyXG4gICAgICA/IHpcclxuICAgICAgICAgIC5zdHJpbmcoKVxyXG4gICAgICAgICAgLnRyaW0oKVxyXG4gICAgICAgICAgLnJlZmluZShcclxuICAgICAgICAgICAgKHZhbHVlKSA9PiAhWydmYWxzZScsICd1bmRlZmluZWQnLCAnbnVsbCcsICcnXS5pbmNsdWRlcyh2YWx1ZSksXHJcbiAgICAgICAgICAgIHtcclxuICAgICAgICAgICAgICBwYXJhbXM6IHtcclxuICAgICAgICAgICAgICAgIGVycm9yTWVzc2FnZTogYFRoZSBzdHJpbmcgY29udGFpbnMgYSBmb3JiaWRkZW4gdmFsdWVgXHJcbiAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICB9XHJcbiAgICAgICAgICApXHJcbiAgICAgIDogelxyXG4gICAgICAgICAgLnN0cmluZygpXHJcbiAgICAgICAgICAudHJpbSgpXHJcbiAgICAgICAgICAudHJhbnNmb3JtKCh2YWx1ZSkgPT5cclxuICAgICAgICAgICAgIVsnZmFsc2UnLCAndW5kZWZpbmVkJywgJ251bGwnLCAnJ10uaW5jbHVkZXModmFsdWUpID8gdmFsdWUgOiBudWxsXHJcbiAgICAgICAgICApXHJcbiAgICAgICAgICAubnVsbGFibGUoKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYGVudW1gIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGggYW4gb3B0aW9uYWwgc3RyaWN0ZXJcclxuICAgKiBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgc2NoZW1hIHdpbGwgdmFsaWRhdGUgYWdhaW5zdCB0aGUgcHJvdmlkZWQgYHZhbHVlc2AgYXJyYXkuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGF0OlxyXG4gICAqXHJcbiAgICogLSBXaGVuIGBzdHJpY3RDaGVja2AgaXMgdHJ1ZSwgdGhlIHNjaGVtYSB3aWxsIHZhbGlkYXRlIGFnYWluc3QgdGhlIGB2YWx1ZXNgXHJcbiAgICogYXJyYXkgd2l0aCB0aGUgZGVmYXVsdCBlbnVtIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIC0gV2hlbiBgc3RyaWN0Q2hlY2tgIGlzIGZhbHNlLCB0aGUgc2NoZW1hIHdpbGwgYWNjZXB0IGFsc28gbnVsbCxcclxuICAgKiAndW5kZWZpbmVkJywgJ251bGwnLCBhbmQgJycsIHdoaWNoIHdpbGwgYmUgdHJhbnNmb3JtZWQgdG8gbnVsbC5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiBlbnVtXHJcbiAgICpcclxuICAgKiBAcGFyYW0ge0FycmF5LjxzdHJpbmc+fSB2YWx1ZXMgLSBBbiBhcnJheSBvZiB2YWxpZCBzdHJpbmcgdmFsdWVzXHJcbiAgICogZm9yIHRoZSBlbnVtLlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZyBlbnVtIHZhbHVlcy5cclxuICAgKi9cclxuICBlbnVtKHZhbHVlcywgc3RyaWN0Q2hlY2spIHtcclxuICAgIHJldHVybiBzdHJpY3RDaGVja1xyXG4gICAgICA/IHouZW51bShbLi4udmFsdWVzXSlcclxuICAgICAgOiB6XHJcbiAgICAgICAgICAuZW51bShbLi4udmFsdWVzLCAndW5kZWZpbmVkJywgJ251bGwnLCAnJ10pXHJcbiAgICAgICAgICAudHJhbnNmb3JtKCh2YWx1ZSkgPT5cclxuICAgICAgICAgICAgIVsndW5kZWZpbmVkJywgJ251bGwnLCAnJ10uaW5jbHVkZXModmFsdWUpID8gdmFsdWUgOiBudWxsXHJcbiAgICAgICAgICApXHJcbiAgICAgICAgICAubnVsbGFibGUoKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYHN0cmluZ0FycmF5YCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoIGFuIG9wdGlvbmFsXHJcbiAgICogc3RyaWN0ZXIgY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhhdDpcclxuICAgKlxyXG4gICAqIC0gV2hlbiBgc3RyaWN0Q2hlY2tgIGlzIHRydWUsIHRoZSBzY2hlbWEgd2lsbCBhY2NlcHQgYW4gYXJyYXkgb2YgdHJpbW1lZFxyXG4gICAqIHN0cmluZyB2YWx1ZXMgZmlsdGVyZWQgYnkgdGhlIGxvZ2ljIHByb3ZpZGVkIHRocm91Z2ggdGhlIGBmaWx0ZXJDYWxsYmFja2AuXHJcbiAgICpcclxuICAgKiAtIFdoZW4gYHN0cmljdENoZWNrYCBpcyBmYWxzZSwgdGhlIHNjaGVtYSB3aWxsIGFjY2VwdCBudWxsIGFuZCB0cmltbWVkXHJcbiAgICogc3RyaW5nIHZhbHVlcyB3aGljaCB3aWxsIGJlIHNwbGl0dGVkIGludG8gYW4gYXJyYXkgb2Ygc3RyaW5ncyBhbmQgZmlsdGVyZWRcclxuICAgKiBmcm9tIHRoZSAnWycgYW5kICddJyBjaGFyYWN0ZXJzIGFuZCBieSB0aGUgbG9naWMgcHJvdmlkZWQgdGhyb3VnaFxyXG4gICAqIHRoZSBgZmlsdGVyQ2FsbGJhY2tgLiBJZiB0aGUgYXJyYXkgaXMgZW1wdHksIGl0IHdpbGwgYmUgdHJhbnNmb3JtZWRcclxuICAgKiB0byBudWxsLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIHN0cmluZ0FycmF5XHJcbiAgICpcclxuICAgKiBAcGFyYW0ge2Z1bmN0aW9ufSBmaWx0ZXJDYWxsYmFjayAtIFRoZSBmaWx0ZXIgY2FsbGJhY2suXHJcbiAgICogQHBhcmFtIHtzdHJpbmd9IHNlcGFyYXRvciAtIFRoZSBzZXBhcmF0b3IgZm9yIHNwbGl0aW5nIGEgc3RyaW5nLlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZyBhcnJheSBvZiBzdHJpbmdcclxuICAgKiB2YWx1ZXMuXHJcbiAgICovXHJcbiAgc3RyaW5nQXJyYXkoZmlsdGVyQ2FsbGJhY2ssIHNlcGFyYXRvciwgc3RyaWN0Q2hlY2spIHtcclxuICAgIGNvbnN0IGFycmF5U2NoZW1hID0gei5zdHJpbmcoKS50cmltKCkuYXJyYXkoKTtcclxuICAgIGNvbnN0IHN0cmluZ1NjaGVtYSA9IHpcclxuICAgICAgLnN0cmluZygpXHJcbiAgICAgIC50cmltKClcclxuICAgICAgLnRyYW5zZm9ybSgodmFsdWUpID0+IHtcclxuICAgICAgICBpZiAodmFsdWUuc3RhcnRzV2l0aCgnWycpKSB7XHJcbiAgICAgICAgICB2YWx1ZSA9IHZhbHVlLnNsaWNlKDEpO1xyXG4gICAgICAgIH1cclxuICAgICAgICBpZiAodmFsdWUuZW5kc1dpdGgoJ10nKSkge1xyXG4gICAgICAgICAgdmFsdWUgPSB2YWx1ZS5zbGljZSgwLCAtMSk7XHJcbiAgICAgICAgfVxyXG4gICAgICAgIHJldHVybiB2YWx1ZS5zcGxpdChzZXBhcmF0b3IpO1xyXG4gICAgICB9KTtcclxuXHJcbiAgICBjb25zdCB0cmFuc2Zvcm1DYWxsYmFjayA9ICh2YWx1ZSkgPT5cclxuICAgICAgdmFsdWUubWFwKCh2YWx1ZSkgPT4gdmFsdWUudHJpbSgpKS5maWx0ZXIoZmlsdGVyQ2FsbGJhY2spO1xyXG5cclxuICAgIHJldHVybiBzdHJpY3RDaGVja1xyXG4gICAgICA/IGFycmF5U2NoZW1hLnRyYW5zZm9ybSh0cmFuc2Zvcm1DYWxsYmFjaylcclxuICAgICAgOiB6XHJcbiAgICAgICAgICAudW5pb24oW3N0cmluZ1NjaGVtYSwgYXJyYXlTY2hlbWFdKVxyXG4gICAgICAgICAgLnRyYW5zZm9ybSh0cmFuc2Zvcm1DYWxsYmFjaylcclxuICAgICAgICAgIC50cmFuc2Zvcm0oKHZhbHVlKSA9PiAodmFsdWUubGVuZ3RoID8gdmFsdWUgOiBudWxsKSlcclxuICAgICAgICAgIC5udWxsYWJsZSgpO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgcG9zaXRpdmVOdW1gIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGggYW4gb3B0aW9uYWxcclxuICAgKiBzdHJpY3RlciBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGF0OlxyXG4gICAqXHJcbiAgICogLSBXaGVuIGBzdHJpY3RDaGVja2AgaXMgdHJ1ZSwgdGhlIHNjaGVtYSB3aWxsIGFjY2VwdCBwb3NpdGl2ZSBudW1iZXIgdmFsdWVzXHJcbiAgICogYW5kIHZhbGlkYXRlIGFnYWluc3QgdGhlIGRlZmF1bHQgcG9zaXRpdmUgbnVtYmVyIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIC0gV2hlbiBgc3RyaWN0Q2hlY2tgIGlzIGZhbHNlLCB0aGUgc2NoZW1hIHdpbGwgYWNjZXB0IHBvc2l0aXZlIG51bWJlclxyXG4gICAqIHZhbHVlcywgbnVsbCwgYW5kIHRyaW1tZWQgc3RyaW5nIHZhbHVlcyB0aGF0IGNhbiBlaXRoZXIgYmUgJ3VuZGVmaW5lZCcsXHJcbiAgICogJ251bGwnLCAnJywgb3IgcmVwcmVzZW50IGEgcG9zaXRpdmUgbnVtYmVyLiBJdCB3aWxsIHRyYW5zZm9ybSB0aGUgc3RyaW5nXHJcbiAgICogdG8gYSBwb3NpdGl2ZSBudW1iZXIsIG9yIHRvIG51bGwgaWYgaXQgaXMgJ3VuZGVmaW5lZCcsICdudWxsJywgb3IgJycuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gcG9zaXRpdmVOdW1cclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZyBwb3NpdGl2ZSBudW1iZXJcclxuICAgKiB2YWx1ZXMuXHJcbiAgICovXHJcbiAgcG9zaXRpdmVOdW0oc3RyaWN0Q2hlY2spIHtcclxuICAgIHJldHVybiBzdHJpY3RDaGVja1xyXG4gICAgICA/IHoubnVtYmVyKCkucG9zaXRpdmUoKVxyXG4gICAgICA6IHpcclxuICAgICAgICAgIC51bmlvbihbXHJcbiAgICAgICAgICAgIHpcclxuICAgICAgICAgICAgICAuc3RyaW5nKClcclxuICAgICAgICAgICAgICAudHJpbSgpXHJcbiAgICAgICAgICAgICAgLnJlZmluZShcclxuICAgICAgICAgICAgICAgICh2YWx1ZSkgPT5cclxuICAgICAgICAgICAgICAgICAgKCFpc05hTihOdW1iZXIodmFsdWUpKSAmJiBOdW1iZXIodmFsdWUpID4gMCkgfHxcclxuICAgICAgICAgICAgICAgICAgWyd1bmRlZmluZWQnLCAnbnVsbCcsICcnXS5pbmNsdWRlcyh2YWx1ZSksXHJcbiAgICAgICAgICAgICAgICB7XHJcbiAgICAgICAgICAgICAgICAgIHBhcmFtczoge1xyXG4gICAgICAgICAgICAgICAgICAgIGVycm9yTWVzc2FnZTogYFRoZSB2YWx1ZSBtdXN0IGJlIG51bWVyaWMgYW5kIHBvc2l0aXZlYFxyXG4gICAgICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgICAgKVxyXG4gICAgICAgICAgICAgIC50cmFuc2Zvcm0oKHZhbHVlKSA9PlxyXG4gICAgICAgICAgICAgICAgIVsndW5kZWZpbmVkJywgJ251bGwnLCAnJ10uaW5jbHVkZXModmFsdWUpXHJcbiAgICAgICAgICAgICAgICAgID8gTnVtYmVyKHZhbHVlKVxyXG4gICAgICAgICAgICAgICAgICA6IG51bGxcclxuICAgICAgICAgICAgICApLFxyXG4gICAgICAgICAgICB6Lm51bWJlcigpLnBvc2l0aXZlKClcclxuICAgICAgICAgIF0pXHJcbiAgICAgICAgICAubnVsbGFibGUoKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYG5vbk5lZ2F0aXZlTnVtYCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoIGFuIG9wdGlvbmFsXHJcbiAgICogc3RyaWN0ZXIgY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhhdDpcclxuICAgKlxyXG4gICAqIC0gV2hlbiBgc3RyaWN0Q2hlY2tgIGlzIHRydWUsIHRoZSBzY2hlbWEgd2lsbCBhY2NlcHQgbm9uLW5lZ2F0aXZlIG51bWJlclxyXG4gICAqIHZhbHVlcyBhbmQgdmFsaWRhdGUgYWdhaW5zdCB0aGUgZGVmYXVsdCBub24tbmVnYXRpdmUgbnVtYmVyIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIC0gV2hlbiBgc3RyaWN0Q2hlY2tgIGlzIGZhbHNlLCB0aGUgc2NoZW1hIHdpbGwgYWNjZXB0IG5vbi1uZWdhdGl2ZSBudW1iZXJcclxuICAgKiB2YWx1ZXMsIG51bGwsIGFuZCB0cmltbWVkIHN0cmluZyB2YWx1ZXMgdGhhdCBjYW4gZWl0aGVyIGJlICd1bmRlZmluZWQnLFxyXG4gICAqICdudWxsJywgJycsIG9yIHJlcHJlc2VudCBhIG5vbi1uZWdhdGl2ZSBudW1iZXIuIEl0IHdpbGwgdHJhbnNmb3JtXHJcbiAgICogdGhlIHN0cmluZyB0byBhIG5vbi1uZWdhdGl2ZSBudW1iZXIsIG9yIHRvIG51bGwgaWYgaXQgaXMgJ3VuZGVmaW5lZCcsXHJcbiAgICogJ251bGwnLCBvciAnJy5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiBub25OZWdhdGl2ZU51bVxyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nIG5vbi1uZWdhdGl2ZVxyXG4gICAqIG51bWJlciB2YWx1ZXMuXHJcbiAgICovXHJcbiAgbm9uTmVnYXRpdmVOdW0oc3RyaWN0Q2hlY2spIHtcclxuICAgIHJldHVybiBzdHJpY3RDaGVja1xyXG4gICAgICA/IHoubnVtYmVyKCkubm9ubmVnYXRpdmUoKVxyXG4gICAgICA6IHpcclxuICAgICAgICAgIC51bmlvbihbXHJcbiAgICAgICAgICAgIHpcclxuICAgICAgICAgICAgICAuc3RyaW5nKClcclxuICAgICAgICAgICAgICAudHJpbSgpXHJcbiAgICAgICAgICAgICAgLnJlZmluZShcclxuICAgICAgICAgICAgICAgICh2YWx1ZSkgPT5cclxuICAgICAgICAgICAgICAgICAgKCFpc05hTihOdW1iZXIodmFsdWUpKSAmJiBOdW1iZXIodmFsdWUpID49IDApIHx8XHJcbiAgICAgICAgICAgICAgICAgIFsndW5kZWZpbmVkJywgJ251bGwnLCAnJ10uaW5jbHVkZXModmFsdWUpLFxyXG4gICAgICAgICAgICAgICAge1xyXG4gICAgICAgICAgICAgICAgICBwYXJhbXM6IHtcclxuICAgICAgICAgICAgICAgICAgICBlcnJvck1lc3NhZ2U6IGBUaGUgdmFsdWUgbXVzdCBiZSBudW1lcmljIGFuZCBub24tbmVnYXRpdmVgXHJcbiAgICAgICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgICApXHJcbiAgICAgICAgICAgICAgLnRyYW5zZm9ybSgodmFsdWUpID0+XHJcbiAgICAgICAgICAgICAgICAhWyd1bmRlZmluZWQnLCAnbnVsbCcsICcnXS5pbmNsdWRlcyh2YWx1ZSlcclxuICAgICAgICAgICAgICAgICAgPyBOdW1iZXIodmFsdWUpXHJcbiAgICAgICAgICAgICAgICAgIDogbnVsbFxyXG4gICAgICAgICAgICAgICksXHJcbiAgICAgICAgICAgIHoubnVtYmVyKCkubm9ubmVnYXRpdmUoKVxyXG4gICAgICAgICAgXSlcclxuICAgICAgICAgIC5udWxsYWJsZSgpO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgc3RhcnRzV2l0aGAgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbFxyXG4gICAqIHN0cmljdGVyIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSBzY2hlbWEgd2lsbCB2YWxpZGF0ZSBhZ2FpbnN0IHRoZSBwcm92aWRlZCBgcHJlZml4ZXNgIGFycmF5IHRvIGNoZWNrXHJcbiAgICogd2hldGhlciBhIHN0cmluZyB2YWx1ZSBzdGFydHMgd2l0aCBhbnkgb2YgdGhlIHZhbHVlcyBwcm92aWRlZFxyXG4gICAqIGluIHRoZSBgcHJlZml4ZXNgIGFycmF5LlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhhdDpcclxuICAgKlxyXG4gICAqIC0gV2hlbiBgc3RyaWN0Q2hlY2tgIGlzIHRydWUsIHRoZSBzY2hlbWEgd2lsbCBhY2NlcHQgdHJpbW1lZCBzdHJpbmcgdmFsdWVzXHJcbiAgICogdGhhdCBzdGFydCB3aXRoIHZhbHVlcyBmcm9tIHRoZSBwcmVmaXhlcyBhcnJheS5cclxuICAgKlxyXG4gICAqIC0gV2hlbiBgc3RyaWN0Q2hlY2tgIGlzIGZhbHNlLCB0aGUgc2NoZW1hIHdpbGwgYWNjZXB0IHRyaW1tZWQgc3RyaW5nIHZhbHVlc1xyXG4gICAqIHRoYXQgc3RhcnQgd2l0aCB2YWx1ZXMgZnJvbSB0aGUgcHJlZml4ZXMgYXJyYXksIG51bGwsICd1bmRlZmluZWQnLCAnbnVsbCcsXHJcbiAgICogYW5kICcnIHdoZXJlIHRoZSBzY2hlbWEgd2lsbCB0cmFuc2Zvcm0gdGhlbSB0byBudWxsLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIHN0YXJ0c1dpdGhcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7QXJyYXkuPHN0cmluZz59IHByZWZpeGVzIC0gQW4gYXJyYXkgb2YgcHJlZml4ZXMgdG8gdmFsaWRhdGVcclxuICAgKiB0aGUgc3RyaW5nIGFnYWluc3QuXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nIHN0cmluZ3MgdGhhdFxyXG4gICAqIHN0YXJ0cyB3aXRoIHZhbHVlcy5cclxuICAgKi9cclxuICBzdGFydHNXaXRoKHByZWZpeGVzLCBzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHN0cmljdENoZWNrXHJcbiAgICAgID8gelxyXG4gICAgICAgICAgLnN0cmluZygpXHJcbiAgICAgICAgICAudHJpbSgpXHJcbiAgICAgICAgICAucmVmaW5lKFxyXG4gICAgICAgICAgICAodmFsdWUpID0+IHByZWZpeGVzLnNvbWUoKHByZWZpeCkgPT4gdmFsdWUuc3RhcnRzV2l0aChwcmVmaXgpKSxcclxuICAgICAgICAgICAge1xyXG4gICAgICAgICAgICAgIHBhcmFtczoge1xyXG4gICAgICAgICAgICAgICAgZXJyb3JNZXNzYWdlOiBgVGhlIHZhbHVlIG11c3QgYmUgYSBzdHJpbmcgdGhhdCBzdGFydHMgd2l0aCAke3ByZWZpeGVzLmpvaW4oJywgJyl9YFxyXG4gICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgfVxyXG4gICAgICAgICAgKVxyXG4gICAgICA6IHpcclxuICAgICAgICAgIC5zdHJpbmcoKVxyXG4gICAgICAgICAgLnRyaW0oKVxyXG4gICAgICAgICAgLnJlZmluZShcclxuICAgICAgICAgICAgKHZhbHVlKSA9PlxyXG4gICAgICAgICAgICAgIHByZWZpeGVzLnNvbWUoKHByZWZpeCkgPT4gdmFsdWUuc3RhcnRzV2l0aChwcmVmaXgpKSB8fFxyXG4gICAgICAgICAgICAgIFsndW5kZWZpbmVkJywgJ251bGwnLCAnJ10uaW5jbHVkZXModmFsdWUpLFxyXG4gICAgICAgICAgICB7XHJcbiAgICAgICAgICAgICAgcGFyYW1zOiB7XHJcbiAgICAgICAgICAgICAgICBlcnJvck1lc3NhZ2U6IGBUaGUgdmFsdWUgbXVzdCBiZSBhIHN0cmluZyB0aGF0IHN0YXJ0cyB3aXRoICR7cHJlZml4ZXMuam9pbignLCAnKX1gXHJcbiAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICB9XHJcbiAgICAgICAgICApXHJcbiAgICAgICAgICAudHJhbnNmb3JtKCh2YWx1ZSkgPT5cclxuICAgICAgICAgICAgIVsndW5kZWZpbmVkJywgJ251bGwnLCAnJ10uaW5jbHVkZXModmFsdWUpID8gdmFsdWUgOiBudWxsXHJcbiAgICAgICAgICApXHJcbiAgICAgICAgICAubnVsbGFibGUoKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYGNoYXJ0Q29uZmlnYCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYS5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoYXQgdGhlIHNjaGVtYSB3aWxsIGFjY2VwdCBvYmplY3QgdmFsdWVzXHJcbiAgICogb3IgdHJpbW1lZCBzdHJpbmcgdmFsdWVzIHRoYXQgY29udGFpbiAnPHN2Zycgb3IgJzw/eG1sJyBlbGVtZW50cywgc3RhcnRcclxuICAgKiB3aXRoIHRoZSAneycgYW5kIGVuZCB3aXRoIHRoZSAnfScsIGFuZCBudWxsLiBUaGUgJ3VuZGVmaW5lZCcsICdudWxsJyxcclxuICAgKiBhbmQgJycgdmFsdWVzIHdpbGwgYmUgdHJhbnNmb3JtZWQgdG8gbnVsbC5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiBjaGFydENvbmZpZ1xyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nIGNoYXJ0XHJcbiAgICogY29uZmlndXJhdGlvbiB2YWx1ZS5cclxuICAgKi9cclxuICBjaGFydENvbmZpZygpIHtcclxuICAgIHJldHVybiB6XHJcbiAgICAgIC51bmlvbihbXHJcbiAgICAgICAgelxyXG4gICAgICAgICAgLnN0cmluZygpXHJcbiAgICAgICAgICAudHJpbSgpXHJcbiAgICAgICAgICAucmVmaW5lKFxyXG4gICAgICAgICAgICAodmFsdWUpID0+XHJcbiAgICAgICAgICAgICAgdmFsdWUuaW5kZXhPZignPHN2ZycpID49IDAgfHxcclxuICAgICAgICAgICAgICB2YWx1ZS5pbmRleE9mKCc8P3htbCcpID49IDAgfHxcclxuICAgICAgICAgICAgICAodmFsdWUuc3RhcnRzV2l0aCgneycpICYmIHZhbHVlLmVuZHNXaXRoKCd9JykpIHx8XHJcbiAgICAgICAgICAgICAgWyd1bmRlZmluZWQnLCAnbnVsbCcsICcnXS5pbmNsdWRlcyh2YWx1ZSksXHJcbiAgICAgICAgICAgIHtcclxuICAgICAgICAgICAgICBwYXJhbXM6IHtcclxuICAgICAgICAgICAgICAgIGVycm9yTWVzc2FnZTogYFRoZSB2YWx1ZSBtdXN0IGJlIGEgc3RyaW5nIHRoYXQgY29udGFpbnMgJzxzdmcnIG9yICc8P3htbCcgb3Igc3RhcnRzIHdpdGggJ3snIGFuZCBlbmRzIHdpdGggJ30nYFxyXG4gICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgfVxyXG4gICAgICAgICAgKVxyXG4gICAgICAgICAgLnRyYW5zZm9ybSgodmFsdWUpID0+XHJcbiAgICAgICAgICAgICFbJ3VuZGVmaW5lZCcsICdudWxsJywgJyddLmluY2x1ZGVzKHZhbHVlKSA/IHZhbHVlIDogbnVsbFxyXG4gICAgICAgICAgKSxcclxuICAgICAgICB6Lm9iamVjdCh7fSkucGFzc3Rocm91Z2goKVxyXG4gICAgICBdKVxyXG4gICAgICAubnVsbGFibGUoKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYGFkZGl0aW9uYWxPcHRpb25zYCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYS5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoYXQgdGhlIHNjaGVtYSB3aWxsIGFjY2VwdCBvYmplY3QgdmFsdWVzXHJcbiAgICogb3IgdHJpbW1lZCBzdHJpbmcgdmFsdWVzIHRoYXQgZW5kIHdpdGggJy5qc29uJyBhbmQgYXJlIGF0IGxlYXN0IG9uZVxyXG4gICAqIGNoYXJhY3RlciBsb25nIGV4Y2x1ZGluZyB0aGUgZXh0ZW5zaW9uLCBzdGFydCB3aXRoIHRoZSAneycgYW5kIGVuZFxyXG4gICAqIHdpdGggdGhlICd9JywgYW5kIG51bGwuIFRoZSAndW5kZWZpbmVkJywgJ251bGwnLCBhbmQgJycgdmFsdWVzIHdpbGxcclxuICAgKiBiZSB0cmFuc2Zvcm1lZCB0byBudWxsLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIGFkZGl0aW9uYWxPcHRpb25zXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9ICBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nIGFkZGl0aW9uYWwgY2hhcnRcclxuICAgKiBvcHRpb25zIHZhbHVlLlxyXG4gICAqL1xyXG4gIGFkZGl0aW9uYWxPcHRpb25zKCkge1xyXG4gICAgcmV0dXJuIHpcclxuICAgICAgLnVuaW9uKFtcclxuICAgICAgICB6XHJcbiAgICAgICAgICAuc3RyaW5nKClcclxuICAgICAgICAgIC50cmltKClcclxuICAgICAgICAgIC5yZWZpbmUoXHJcbiAgICAgICAgICAgICh2YWx1ZSkgPT5cclxuICAgICAgICAgICAgICAodmFsdWUubGVuZ3RoID49IDYgJiYgdmFsdWUuZW5kc1dpdGgoJy5qc29uJykpIHx8XHJcbiAgICAgICAgICAgICAgKHZhbHVlLnN0YXJ0c1dpdGgoJ3snKSAmJiB2YWx1ZS5lbmRzV2l0aCgnfScpKSB8fFxyXG4gICAgICAgICAgICAgIFsndW5kZWZpbmVkJywgJ251bGwnLCAnJ10uaW5jbHVkZXModmFsdWUpLFxyXG4gICAgICAgICAgICB7XHJcbiAgICAgICAgICAgICAgcGFyYW1zOiB7XHJcbiAgICAgICAgICAgICAgICBlcnJvck1lc3NhZ2U6IGBUaGUgdmFsdWUgbXVzdCBiZSBhIHN0cmluZyB0aGF0IGVuZHMgd2l0aCAnLmpzb24nIG9yIHN0YXJ0cyB3aXRoICd7JyBhbmQgZW5kcyB3aXRoICd9J2BcclxuICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgIH1cclxuICAgICAgICAgIClcclxuICAgICAgICAgIC50cmFuc2Zvcm0oKHZhbHVlKSA9PlxyXG4gICAgICAgICAgICAhWyd1bmRlZmluZWQnLCAnbnVsbCcsICcnXS5pbmNsdWRlcyh2YWx1ZSkgPyB2YWx1ZSA6IG51bGxcclxuICAgICAgICAgICksXHJcbiAgICAgICAgei5vYmplY3Qoe30pLnBhc3N0aHJvdWdoKClcclxuICAgICAgXSlcclxuICAgICAgLm51bGxhYmxlKCk7XHJcbiAgfVxyXG59O1xyXG5cclxuLyoqXHJcbiAqIE9iamVjdCBjb250YWluaW5nIGN1c3RvbSBjb25maWcgdmFsaWRhdG9ycyBhbmQgcGFyc2VycyB0byBhdm9pZCByZXBldGl0aW9uXHJcbiAqIGluIHNjaGVtYSBvYmplY3RzLiBBbGwgdmFsaWRhdG9ycyBhcHBseSB0byB2YWx1ZXMgZnJvbSB2YXJpb3VzIHNvdXJjZXMsXHJcbiAqIGluY2x1ZGluZyB0aGUgZGVmYXVsdCBjb25maWcgZmlsZSwgYSBjdXN0b20gSlNPTiBmaWxlIGxvYWRlZCB3aXRoIHRoZSBvcHRpb25cclxuICogY2FsbGVkIGBsb2FkQ29uZmlnYCwgdGhlIC5lbnYgZmlsZSwgQ0xJIGFyZ3VtZW50cywgYW5kIHRoZSByZXF1ZXN0IHBheWxvYWQuXHJcbiAqIFRoZSBgc3RyaWN0Q2hlY2tgIGZsYWcgZW5hYmxlcyBzdHJpY3RlciB2YWxpZGF0aW9uIGFuZCBwYXJzaW5nIHJ1bGVzLiBUaGlzXHJcbiAqIGZsYWcgaXMgc2V0IHRvIGZhbHNlIGZvciB2YWx1ZXMgdGhhdCBjb21lIGZyb20gdGhlIC5lbnYgZmlsZSBvciBDTEkgYXJndW1lbnRzXHJcbiAqIGJlY2F1c2UgdGhleSBhcmUgcHJvdmlkZWQgYXMgc3RyaW5ncyBhbmQgbmVlZCB0byBiZSBwYXJzZWQgYWNjb3JkaW5nbHkgZmlyc3QuXHJcbiAqL1xyXG5jb25zdCBjb25maWcgPSB7XHJcbiAgLyoqXHJcbiAgICogVGhlIGBhcmdzYCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoIGFuIG9wdGlvbmFsIHN0cmljdGVyXHJcbiAgICogY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhlIHNhbWUgd29yayBhcyB0aGUgYHN0cmluZ0FycmF5YCB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gYXJnc1xyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nIHRoZSBgYXJnc2BcclxuICAgKiBvcHRpb24uXHJcbiAgICovXHJcbiAgYXJncyhzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHYuc3RyaW5nQXJyYXkoXHJcbiAgICAgICh2YWx1ZSkgPT4gIVsnZmFsc2UnLCAndW5kZWZpbmVkJywgJ251bGwnLCAnJ10uaW5jbHVkZXModmFsdWUpLFxyXG4gICAgICAnOycsXHJcbiAgICAgIHN0cmljdENoZWNrXHJcbiAgICApO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgdmVyc2lvbmAgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbCBzdHJpY3RlclxyXG4gICAqIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoYXQ6XHJcbiAgICpcclxuICAgKiAtIFdoZW4gYHN0cmljdENoZWNrYCBpcyB0cnVlLCB0aGUgc2NoZW1hIHdpbGwgYWNjZXB0IHRyaW1tZWQgc3RyaW5nIHZhbHVlc1xyXG4gICAqIHRoYXQgYXJlIGEgUmVnRXhwLWJhc2VkIHRoYXQgYWxsb3dzIHRvIGJlICdsYXRlc3QnLCBvciBpbiB0aGUgZm9ybWF0IFhYLFxyXG4gICAqIFhYLllZLCBvciBYWC5ZWS5aWiwgd2hlcmUgWFgsIFlZLCBhbmQgWlogYXJlIG51bWVyaWMgZm9yIHRoZSBIaWdoY2hhcnRzXHJcbiAgICogdmVyc2lvbiBvcHRpb24uXHJcbiAgICpcclxuICAgKiAtIFdoZW4gYHN0cmljdENoZWNrYCBpcyBmYWxzZSwgdGhlIHNjaGVtYSB3aWxsIGFjY2VwdCBhbHNvIG51bGwsXHJcbiAgICogJ3VuZGVmaW5lZCcsICdudWxsJywgb3IgJycgYW5kIGluIGFsbCBjYXNlcyB0aGUgc2NoZW1hIHdpbGwgdHJhbnNmb3JtIHRoZW1cclxuICAgKiB0byBudWxsLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIHZlcnNpb25cclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZyB0aGUgYHZlcnNpb25gXHJcbiAgICogb3B0aW9uLlxyXG4gICAqL1xyXG4gIHZlcnNpb24oc3RyaWN0Q2hlY2spIHtcclxuICAgIHJldHVybiBzdHJpY3RDaGVja1xyXG4gICAgICA/IHpcclxuICAgICAgICAgIC5zdHJpbmcoKVxyXG4gICAgICAgICAgLnRyaW0oKVxyXG4gICAgICAgICAgLnJlZmluZSgodmFsdWUpID0+IC9eKGxhdGVzdHxcXGR7MSwyfShcXC5cXGR7MSwyfSl7MCwyfSkkLy50ZXN0KHZhbHVlKSwge1xyXG4gICAgICAgICAgICBwYXJhbXM6IHtcclxuICAgICAgICAgICAgICBlcnJvck1lc3NhZ2U6XHJcbiAgICAgICAgICAgICAgICBcIlRoZSB2YWx1ZSBtdXN0IGJlICdsYXRlc3QnLCBhIG1ham9yIHZlcnNpb24sIG9yIGluIHRoZSBmb3JtIFhYLllZLlpaXCJcclxuICAgICAgICAgICAgfVxyXG4gICAgICAgICAgfSlcclxuICAgICAgOiB6XHJcbiAgICAgICAgICAuc3RyaW5nKClcclxuICAgICAgICAgIC50cmltKClcclxuICAgICAgICAgIC5yZWZpbmUoXHJcbiAgICAgICAgICAgICh2YWx1ZSkgPT5cclxuICAgICAgICAgICAgICAvXihsYXRlc3R8XFxkezEsMn0oXFwuXFxkezEsMn0pezAsMn0pJC8udGVzdCh2YWx1ZSkgfHxcclxuICAgICAgICAgICAgICBbJ3VuZGVmaW5lZCcsICdudWxsJywgJyddLmluY2x1ZGVzKHZhbHVlKSxcclxuICAgICAgICAgICAge1xyXG4gICAgICAgICAgICAgIHBhcmFtczoge1xyXG4gICAgICAgICAgICAgICAgZXJyb3JNZXNzYWdlOlxyXG4gICAgICAgICAgICAgICAgICBcIlRoZSB2YWx1ZSBtdXN0IGJlICdsYXRlc3QnLCBhIG1ham9yIHZlcnNpb24sIG9yIGluIHRoZSBmb3JtIFhYLllZLlpaXCJcclxuICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgIH1cclxuICAgICAgICAgIClcclxuICAgICAgICAgIC50cmFuc2Zvcm0oKHZhbHVlKSA9PlxyXG4gICAgICAgICAgICAhWyd1bmRlZmluZWQnLCAnbnVsbCcsICcnXS5pbmNsdWRlcyh2YWx1ZSkgPyB2YWx1ZSA6IG51bGxcclxuICAgICAgICAgIClcclxuICAgICAgICAgIC5udWxsYWJsZSgpO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgY2RuVXJsYCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoIGFuIG9wdGlvbmFsIHN0cmljdGVyXHJcbiAgICogY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhlIHNhbWUgd29yayBhcyB0aGUgYHN0YXJ0c1dpdGhgIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiBjZG5VcmxcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZyB0aGUgYGNkblVybGBcclxuICAgKiBvcHRpb24uXHJcbiAgICovXHJcbiAgY2RuVXJsKHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gdi5zdGFydHNXaXRoKFsnaHR0cDovLycsICdodHRwczovLyddLCBzdHJpY3RDaGVjayk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGBmb3JjZUZldGNoYCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoIGFuIG9wdGlvbmFsXHJcbiAgICogc3RyaWN0ZXIgY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhlIHNhbWUgd29yayBhcyB0aGUgYGJvb2xlYW5gIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiBmb3JjZUZldGNoXHJcbiAgICpcclxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IHN0cmljdENoZWNrIC0gRGV0ZXJtaW5lcyBpZiBzdHJpY3RlciB2YWxpZGF0aW9uIHNob3VsZFxyXG4gICAqIGJlIGFwcGxpZWQuXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9IEEgWm9kIHNjaGVtYSBvYmplY3QgZm9yIHZhbGlkYXRpbmcgdGhlIGBmb3JjZUZldGNoYFxyXG4gICAqIG9wdGlvbi5cclxuICAgKi9cclxuICBmb3JjZUZldGNoKHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gdi5ib29sZWFuKHN0cmljdENoZWNrKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYGNhY2hlUGF0aGAgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbFxyXG4gICAqIHN0cmljdGVyIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgdGhlIGBzdHJpbmdgIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiBjYWNoZVBhdGhcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZyB0aGUgYGNhY2hlUGF0aGBcclxuICAgKiBvcHRpb24uXHJcbiAgICovXHJcbiAgY2FjaGVQYXRoKHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gdi5zdHJpbmcoc3RyaWN0Q2hlY2spO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgYWRtaW5Ub2tlbmAgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbFxyXG4gICAqIHN0cmljdGVyIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgdGhlIGBzdHJpbmdgIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiBhZG1pblRva2VuXHJcbiAgICpcclxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IHN0cmljdENoZWNrIC0gRGV0ZXJtaW5lcyBpZiBzdHJpY3RlciB2YWxpZGF0aW9uIHNob3VsZFxyXG4gICAqIGJlIGFwcGxpZWQuXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9IEEgWm9kIHNjaGVtYSBvYmplY3QgZm9yIHZhbGlkYXRpbmcgdGhlIGBhZG1pblRva2VuYFxyXG4gICAqIG9wdGlvbi5cclxuICAgKi9cclxuICBhZG1pblRva2VuKHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gdi5zdHJpbmcoc3RyaWN0Q2hlY2spO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgY29yZVNjcmlwdHNgIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGggYW4gb3B0aW9uYWxcclxuICAgKiBzdHJpY3RlciBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGUgc2FtZSB3b3JrIGFzIHRoZSBgc3RyaW5nQXJyYXlgIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiBjb3JlU2NyaXB0c1xyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nIHRoZSBgY29yZVNjcmlwdHNgXHJcbiAgICogb3B0aW9uLlxyXG4gICAqL1xyXG4gIGNvcmVTY3JpcHRzKHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gdi5zdHJpbmdBcnJheShcclxuICAgICAgKHZhbHVlKSA9PiBjb3JlU2NyaXB0cy52YWx1ZS5pbmNsdWRlcyh2YWx1ZSksXHJcbiAgICAgICcsJyxcclxuICAgICAgc3RyaWN0Q2hlY2tcclxuICAgICk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGBtb2R1bGVTY3JpcHRzYCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoIGFuIG9wdGlvbmFsXHJcbiAgICogc3RyaWN0ZXIgY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhlIHNhbWUgd29yayBhcyB0aGUgYHN0cmluZ0FycmF5YCB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gbW9kdWxlU2NyaXB0c1xyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nXHJcbiAgICogdGhlIGBtb2R1bGVTY3JpcHRzYCBvcHRpb24uXHJcbiAgICovXHJcbiAgbW9kdWxlU2NyaXB0cyhzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHYuc3RyaW5nQXJyYXkoXHJcbiAgICAgICh2YWx1ZSkgPT4gbW9kdWxlU2NyaXB0cy52YWx1ZS5pbmNsdWRlcyh2YWx1ZSksXHJcbiAgICAgICcsJyxcclxuICAgICAgc3RyaWN0Q2hlY2tcclxuICAgICk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGBpbmRpY2F0b3JTY3JpcHRzYCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoIGFuIG9wdGlvbmFsXHJcbiAgICogc3RyaWN0ZXIgY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhlIHNhbWUgd29yayBhcyB0aGUgYHN0cmluZ0FycmF5YCB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gaW5kaWNhdG9yU2NyaXB0c1xyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nXHJcbiAgICogdGhlIGBpbmRpY2F0b3JTY3JpcHRzYCBvcHRpb24uXHJcbiAgICovXHJcbiAgaW5kaWNhdG9yU2NyaXB0cyhzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHYuc3RyaW5nQXJyYXkoXHJcbiAgICAgICh2YWx1ZSkgPT4gaW5kaWNhdG9yU2NyaXB0cy52YWx1ZS5pbmNsdWRlcyh2YWx1ZSksXHJcbiAgICAgICcsJyxcclxuICAgICAgc3RyaWN0Q2hlY2tcclxuICAgICk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGBjdXN0b21TY3JpcHRzYCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoIGFuIG9wdGlvbmFsXHJcbiAgICogc3RyaWN0ZXIgY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhlIHNhbWUgd29yayBhcyB0aGUgYHN0cmluZ0FycmF5YCB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gY3VzdG9tU2NyaXB0c1xyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nXHJcbiAgICogdGhlIGBjdXN0b21TY3JpcHRzYCBvcHRpb24uXHJcbiAgICovXHJcbiAgY3VzdG9tU2NyaXB0cyhzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHYuc3RyaW5nQXJyYXkoXHJcbiAgICAgICh2YWx1ZSkgPT4gdmFsdWUuc3RhcnRzV2l0aCgnaHR0cHM6Ly8nKSB8fCB2YWx1ZS5zdGFydHNXaXRoKCdodHRwOi8vJyksXHJcbiAgICAgICcsJyxcclxuICAgICAgc3RyaWN0Q2hlY2tcclxuICAgICk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGBpbmZpbGVgIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGggYW4gb3B0aW9uYWwgc3RyaWN0ZXJcclxuICAgKiBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGF0OlxyXG4gICAqXHJcbiAgICogLSBXaGVuIGBzdHJpY3RDaGVja2AgaXMgdHJ1ZSwgdGhlIHNjaGVtYSB3aWxsIGFjY2VwdCB0cmltbWVkIHN0cmluZyB2YWx1ZXNcclxuICAgKiB0aGF0IGVuZCB3aXRoICcuanNvbicgb3IgJy5zdmcnLCBhcmUgYXQgbGVhc3Qgb25lIGNoYXJhY3RlciBsb25nIGV4Y2x1ZGluZ1xyXG4gICAqIHRoZSBleHRlbnNpb24sIG9yIG51bGwuXHJcbiAgICpcclxuICAgKiAtIFdoZW4gYHN0cmljdENoZWNrYCBpcyBmYWxzZSwgdGhlIHNjaGVtYSB3aWxsIGFjY2VwdCB0cmltbWVkIHN0cmluZyB2YWx1ZXNcclxuICAgKiB0aGF0IGVuZCB3aXRoICcuanNvbicgb3IgJy5zdmcnLCBhcmUgYXQgbGVhc3Qgb25lIGNoYXJhY3RlciBsb25nIGV4Y2x1ZGluZ1xyXG4gICAqIHRoZSBleHRlbnNpb24gYW5kIHdpbGwgYmUgbnVsbCBpZiB0aGUgcHJvdmlkZWQgdmFsdWUgaXMgbnVsbCwgJ3VuZGVmaW5lZCcsXHJcbiAgICogJ251bGwnLCBvciAnJy5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiBpbmZpbGVcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZyB0aGUgYGluZmlsZWBcclxuICAgKiBvcHRpb24uXHJcbiAgICovXHJcbiAgaW5maWxlKHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gc3RyaWN0Q2hlY2tcclxuICAgICAgPyB6XHJcbiAgICAgICAgICAuc3RyaW5nKClcclxuICAgICAgICAgIC50cmltKClcclxuICAgICAgICAgIC5yZWZpbmUoXHJcbiAgICAgICAgICAgICh2YWx1ZSkgPT5cclxuICAgICAgICAgICAgICAodmFsdWUubGVuZ3RoID49IDYgJiYgdmFsdWUuZW5kc1dpdGgoJy5qc29uJykpIHx8XHJcbiAgICAgICAgICAgICAgKHZhbHVlLmxlbmd0aCA+PSA1ICYmIHZhbHVlLmVuZHNXaXRoKCcuc3ZnJykpLFxyXG4gICAgICAgICAgICB7XHJcbiAgICAgICAgICAgICAgcGFyYW1zOiB7XHJcbiAgICAgICAgICAgICAgICBlcnJvck1lc3NhZ2U6IGBUaGUgdmFsdWUgbXVzdCBiZSBhIHN0cmluZyB0aGF0IGVuZHMgd2l0aCAuanNvbiBvciAuc3ZnYFxyXG4gICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgfVxyXG4gICAgICAgICAgKVxyXG4gICAgICAgICAgLm51bGxhYmxlKClcclxuICAgICAgOiB6XHJcbiAgICAgICAgICAuc3RyaW5nKClcclxuICAgICAgICAgIC50cmltKClcclxuICAgICAgICAgIC5yZWZpbmUoXHJcbiAgICAgICAgICAgICh2YWx1ZSkgPT5cclxuICAgICAgICAgICAgICAodmFsdWUubGVuZ3RoID49IDYgJiYgdmFsdWUuZW5kc1dpdGgoJy5qc29uJykpIHx8XHJcbiAgICAgICAgICAgICAgKHZhbHVlLmxlbmd0aCA+PSA1ICYmIHZhbHVlLmVuZHNXaXRoKCcuc3ZnJykpIHx8XHJcbiAgICAgICAgICAgICAgWyd1bmRlZmluZWQnLCAnbnVsbCcsICcnXS5pbmNsdWRlcyh2YWx1ZSksXHJcbiAgICAgICAgICAgIHtcclxuICAgICAgICAgICAgICBwYXJhbXM6IHtcclxuICAgICAgICAgICAgICAgIGVycm9yTWVzc2FnZTogYFRoZSB2YWx1ZSBtdXN0IGJlIGEgc3RyaW5nIHRoYXQgZW5kcyB3aXRoIC5qc29uIG9yIC5zdmdgXHJcbiAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICB9XHJcbiAgICAgICAgICApXHJcbiAgICAgICAgICAudHJhbnNmb3JtKCh2YWx1ZSkgPT5cclxuICAgICAgICAgICAgIVsndW5kZWZpbmVkJywgJ251bGwnLCAnJ10uaW5jbHVkZXModmFsdWUpID8gdmFsdWUgOiBudWxsXHJcbiAgICAgICAgICApXHJcbiAgICAgICAgICAubnVsbGFibGUoKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYGluc3RyYCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYS5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgdGhlIGBvcHRpb25zYCB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gaW5zdHJcclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZyB0aGUgYGluc3RyYFxyXG4gICAqIG9wdGlvbi5cclxuICAgKi9cclxuICBpbnN0cigpIHtcclxuICAgIHJldHVybiB2LmNoYXJ0Q29uZmlnKCk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGBvcHRpb25zYCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYS5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgdGhlIGBvcHRpb25zYCB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gb3B0aW9uc1xyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nIHRoZSBgb3B0aW9uc2BcclxuICAgKiBvcHRpb24uXHJcbiAgICovXHJcbiAgb3B0aW9ucygpIHtcclxuICAgIHJldHVybiB2LmNoYXJ0Q29uZmlnKCk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGBzdmdgIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhhdCB0aGUgc2NoZW1hIHdpbGwgYWNjZXB0IG9iamVjdCB2YWx1ZXNcclxuICAgKiBvciB0cmltbWVkIHN0cmluZyB2YWx1ZXMgdGhhdCBjb250YWluICc8c3ZnJyBvciAnPD94bWwnIGVsZW1lbnRzIGFuZCBudWxsLlxyXG4gICAqIFRoZSAndW5kZWZpbmVkJywgJ251bGwnLCBhbmQgJycgdmFsdWVzIHdpbGwgYmUgdHJhbnNmb3JtZWQgdG8gbnVsbC5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiBzdmdcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZyB0aGUgYHN2Z2Agb3B0aW9uLlxyXG4gICAqL1xyXG4gIHN2ZygpIHtcclxuICAgIHJldHVybiB6XHJcbiAgICAgIC5zdHJpbmcoKVxyXG4gICAgICAudHJpbSgpXHJcbiAgICAgIC5yZWZpbmUoXHJcbiAgICAgICAgKHZhbHVlKSA9PlxyXG4gICAgICAgICAgdmFsdWUuaW5kZXhPZignPHN2ZycpID49IDAgfHxcclxuICAgICAgICAgIHZhbHVlLmluZGV4T2YoJzw/eG1sJykgPj0gMCB8fFxyXG4gICAgICAgICAgWydmYWxzZScsICd1bmRlZmluZWQnLCAnbnVsbCcsICcnXS5pbmNsdWRlcyh2YWx1ZSksXHJcbiAgICAgICAge1xyXG4gICAgICAgICAgcGFyYW1zOiB7XHJcbiAgICAgICAgICAgIGVycm9yTWVzc2FnZTogYFRoZSB2YWx1ZSBtdXN0IGJlIGEgc3RyaW5nIHRoYXQgY29udGFpbnMgJzxzdmcnIG9yICc8P3htbCdgXHJcbiAgICAgICAgICB9XHJcbiAgICAgICAgfVxyXG4gICAgICApXHJcbiAgICAgIC50cmFuc2Zvcm0oKHZhbHVlKSA9PlxyXG4gICAgICAgICFbJ2ZhbHNlJywgJ3VuZGVmaW5lZCcsICdudWxsJywgJyddLmluY2x1ZGVzKHZhbHVlKSA/IHZhbHVlIDogbnVsbFxyXG4gICAgICApXHJcbiAgICAgIC5udWxsYWJsZSgpO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgb3V0ZmlsZWAgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbCBzdHJpY3RlclxyXG4gICAqIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoYXQ6XHJcbiAgICpcclxuICAgKiAtIFdoZW4gYHN0cmljdENoZWNrYCBpcyB0cnVlLCB0aGUgc2NoZW1hIHdpbGwgYWNjZXB0IHRyaW1tZWQgc3RyaW5nIHZhbHVlc1xyXG4gICAqIHRoYXQgZW5kIHdpdGggJy5qcGVnJywgJy5qcGcnLCAnLnBuZycsICcucGRmJywgb3IgJy5zdmcnLCBhcmUgYXQgbGVhc3Qgb25lXHJcbiAgICogY2hhcmFjdGVyIGxvbmcgZXhjbHVkaW5nIHRoZSBleHRlbnNpb24sIG9yIG51bGwuXHJcbiAgICpcclxuICAgKiAtIFdoZW4gYHN0cmljdENoZWNrYCBpcyBmYWxzZSwgdGhlIHNjaGVtYSB3aWxsIGFjY2VwdCB0cmltbWVkIHN0cmluZyB2YWx1ZXNcclxuICAgKiB0aGF0IGVuZCB3aXRoICcuanBlZycsICcuanBnJywgJy5wbmcnLCAnLnBkZicsIG9yICcuc3ZnJywgYXJlIGF0IGxlYXN0IG9uZVxyXG4gICAqIGNoYXJhY3RlciBsb25nIGV4Y2x1ZGluZyB0aGUgZXh0ZW5zaW9uIGFuZCB3aWxsIGJlIG51bGwgaWYgdGhlIHByb3ZpZGVkXHJcbiAgICogdmFsdWUgaXMgbnVsbCwgJ3VuZGVmaW5lZCcsICdudWxsJywgb3IgJycuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gb3V0ZmlsZVxyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nIHRoZSBgb3V0ZmlsZWBcclxuICAgKiBvcHRpb24uXHJcbiAgICovXHJcbiAgb3V0ZmlsZShzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHN0cmljdENoZWNrXHJcbiAgICAgID8gelxyXG4gICAgICAgICAgLnN0cmluZygpXHJcbiAgICAgICAgICAudHJpbSgpXHJcbiAgICAgICAgICAucmVmaW5lKFxyXG4gICAgICAgICAgICAodmFsdWUpID0+XHJcbiAgICAgICAgICAgICAgKHZhbHVlLmxlbmd0aCA+PSA2ICYmIHZhbHVlLmVuZHNXaXRoKCcuanBlZycpKSB8fFxyXG4gICAgICAgICAgICAgICh2YWx1ZS5sZW5ndGggPj0gNSAmJlxyXG4gICAgICAgICAgICAgICAgKHZhbHVlLmVuZHNXaXRoKCcuanBnJykgfHxcclxuICAgICAgICAgICAgICAgICAgdmFsdWUuZW5kc1dpdGgoJy5wbmcnKSB8fFxyXG4gICAgICAgICAgICAgICAgICB2YWx1ZS5lbmRzV2l0aCgnLnBkZicpIHx8XHJcbiAgICAgICAgICAgICAgICAgIHZhbHVlLmVuZHNXaXRoKCcuc3ZnJykpKSxcclxuICAgICAgICAgICAge1xyXG4gICAgICAgICAgICAgIHBhcmFtczoge1xyXG4gICAgICAgICAgICAgICAgZXJyb3JNZXNzYWdlOiBgVGhlIHZhbHVlIG11c3QgYmUgYSBzdHJpbmcgdGhhdCBlbmRzIHdpdGggLmpwZWcsIC5qcGcsIC5wbmcsIC5wZGYsIG9yIC5zdmdgXHJcbiAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICB9XHJcbiAgICAgICAgICApXHJcbiAgICAgICAgICAubnVsbGFibGUoKVxyXG4gICAgICA6IHpcclxuICAgICAgICAgIC5zdHJpbmcoKVxyXG4gICAgICAgICAgLnRyaW0oKVxyXG4gICAgICAgICAgLnJlZmluZShcclxuICAgICAgICAgICAgKHZhbHVlKSA9PlxyXG4gICAgICAgICAgICAgICh2YWx1ZS5sZW5ndGggPj0gNiAmJiB2YWx1ZS5lbmRzV2l0aCgnLmpwZWcnKSkgfHxcclxuICAgICAgICAgICAgICAodmFsdWUubGVuZ3RoID49IDUgJiZcclxuICAgICAgICAgICAgICAgICh2YWx1ZS5lbmRzV2l0aCgnLmpwZycpIHx8XHJcbiAgICAgICAgICAgICAgICAgIHZhbHVlLmVuZHNXaXRoKCcucG5nJykgfHxcclxuICAgICAgICAgICAgICAgICAgdmFsdWUuZW5kc1dpdGgoJy5wZGYnKSB8fFxyXG4gICAgICAgICAgICAgICAgICB2YWx1ZS5lbmRzV2l0aCgnLnN2ZycpKSkgfHxcclxuICAgICAgICAgICAgICBbJ3VuZGVmaW5lZCcsICdudWxsJywgJyddLmluY2x1ZGVzKHZhbHVlKSxcclxuICAgICAgICAgICAge1xyXG4gICAgICAgICAgICAgIHBhcmFtczoge1xyXG4gICAgICAgICAgICAgICAgZXJyb3JNZXNzYWdlOiBgVGhlIHZhbHVlIG11c3QgYmUgYSBzdHJpbmcgdGhhdCBlbmRzIHdpdGggLmpwZWcsIC5qcGcsIC5wbmcsIC5wZGYsIG9yIC5zdmdgXHJcbiAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICB9XHJcbiAgICAgICAgICApXHJcbiAgICAgICAgICAudHJhbnNmb3JtKCh2YWx1ZSkgPT5cclxuICAgICAgICAgICAgIVsndW5kZWZpbmVkJywgJ251bGwnLCAnJ10uaW5jbHVkZXModmFsdWUpID8gdmFsdWUgOiBudWxsXHJcbiAgICAgICAgICApXHJcbiAgICAgICAgICAubnVsbGFibGUoKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYHR5cGVgIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGggYW4gb3B0aW9uYWwgc3RyaWN0ZXJcclxuICAgKiBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGUgc2FtZSB3b3JrIGFzIHRoZSBgZW51bWAgdmFsaWRhdG9yLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIHR5cGVcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZyB0aGUgYHR5cGVgXHJcbiAgICogb3B0aW9uLlxyXG4gICAqL1xyXG4gIHR5cGUoc3RyaWN0Q2hlY2spIHtcclxuICAgIHJldHVybiB2LmVudW0oWydqcGVnJywgJ2pwZycsICdwbmcnLCAncGRmJywgJ3N2ZyddLCBzdHJpY3RDaGVjayk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGBjb25zdHJgIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGggYW4gb3B0aW9uYWwgc3RyaWN0ZXJcclxuICAgKiBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGUgc2FtZSB3b3JrIGFzIHRoZSBgZW51bWAgdmFsaWRhdG9yLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIGNvbnN0clxyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nIHRoZSBgY29uc3RyYFxyXG4gICAqIG9wdGlvbi5cclxuICAgKi9cclxuICBjb25zdHIoc3RyaWN0Q2hlY2spIHtcclxuICAgIHJldHVybiB2LmVudW0oXHJcbiAgICAgIFsnY2hhcnQnLCAnc3RvY2tDaGFydCcsICdtYXBDaGFydCcsICdnYW50dENoYXJ0J10sXHJcbiAgICAgIHN0cmljdENoZWNrXHJcbiAgICApO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgYjY0YCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoIGFuIG9wdGlvbmFsIHN0cmljdGVyXHJcbiAgICogY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhlIHNhbWUgd29yayBhcyB0aGUgYGJvb2xlYW5gIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiBiNjRcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZyB0aGUgYGI2NGAgb3B0aW9uLlxyXG4gICAqL1xyXG4gIGI2NChzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHYuYm9vbGVhbihzdHJpY3RDaGVjayk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGBub0Rvd25sb2FkYCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoIGFuIG9wdGlvbmFsXHJcbiAgICogc3RyaWN0ZXIgY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhlIHNhbWUgd29yayBhcyB0aGUgYGJvb2xlYW5gIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiBub0Rvd25sb2FkXHJcbiAgICpcclxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IHN0cmljdENoZWNrIC0gRGV0ZXJtaW5lcyBpZiBzdHJpY3RlciB2YWxpZGF0aW9uIHNob3VsZFxyXG4gICAqIGJlIGFwcGxpZWQuXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9IEEgWm9kIHNjaGVtYSBvYmplY3QgZm9yIHZhbGlkYXRpbmcgdGhlIGBub0Rvd25sb2FkYFxyXG4gICAqIG9wdGlvbi5cclxuICAgKi9cclxuICBub0Rvd25sb2FkKHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gdi5ib29sZWFuKHN0cmljdENoZWNrKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYGRlZmF1bHRIZWlnaHRgIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGggYW4gb3B0aW9uYWxcclxuICAgKiBzdHJpY3RlciBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGUgc2FtZSB3b3JrIGFzIHRoZSBgcG9zaXRpdmVOdW1gIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiBkZWZhdWx0SGVpZ2h0XHJcbiAgICpcclxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IHN0cmljdENoZWNrIC0gRGV0ZXJtaW5lcyBpZiBzdHJpY3RlciB2YWxpZGF0aW9uIHNob3VsZFxyXG4gICAqIGJlIGFwcGxpZWQuXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9IEEgWm9kIHNjaGVtYSBvYmplY3QgZm9yIHZhbGlkYXRpbmdcclxuICAgKiB0aGUgYGRlZmF1bHRIZWlnaHRgIG9wdGlvbi5cclxuICAgKi9cclxuICBkZWZhdWx0SGVpZ2h0KHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gdi5wb3NpdGl2ZU51bShzdHJpY3RDaGVjayk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGBkZWZhdWx0V2lkdGhgIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGggYW4gb3B0aW9uYWxcclxuICAgKiBzdHJpY3RlciBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGUgc2FtZSB3b3JrIGFzIHRoZSBgcG9zaXRpdmVOdW1gIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiBkZWZhdWx0V2lkdGhcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZ1xyXG4gICAqIHRoZSBgZGVmYXVsdFdpZHRoYCBvcHRpb24uXHJcbiAgICovXHJcbiAgZGVmYXVsdFdpZHRoKHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gdi5wb3NpdGl2ZU51bShzdHJpY3RDaGVjayk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGBkZWZhdWx0U2NhbGVgIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGggYW4gb3B0aW9uYWxcclxuICAgKiBzdHJpY3RlciBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGF0OlxyXG4gICAqXHJcbiAgICogLSBXaGVuIGBzdHJpY3RDaGVja2AgaXMgdHJ1ZSwgdGhlIHNjaGVtYSB3aWxsIGFjY2VwdCBudW1iZXIgdmFsdWVzIHRoYXRcclxuICAgKiBhcmUgYmV0d2VlbiAwLjEgYW5kIDUgKGluY2x1c2l2ZSkuXHJcbiAgICpcclxuICAgKiAtIFdoZW4gYHN0cmljdENoZWNrYCBpcyBmYWxzZSwgdGhlIHNjaGVtYSB3aWxsIGFjY2VwdCBudW1iZXIgdmFsdWVzXHJcbiAgICogYW5kIHN0cmluZ2lmaWVkIG51bWJlciB2YWx1ZXMgdGhhdCBhcmUgYmV0d2VlbiAwLjEgYW5kIDUgKGluY2x1c2l2ZSksIG51bGwsXHJcbiAgICogJ3VuZGVmaW5lZCcsICdudWxsJywgYW5kICcnIHdoaWNoIHdpbGwgYmUgdHJhbnNmb3JtZWQgdG8gbnVsbC5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiBkZWZhdWx0U2NhbGVcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZ1xyXG4gICAqIHRoZSBgZGVmYXVsdFNjYWxlYCBvcHRpb24uXHJcbiAgICovXHJcbiAgZGVmYXVsdFNjYWxlKHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gc3RyaWN0Q2hlY2tcclxuICAgICAgPyB6Lm51bWJlcigpLmd0ZSgwLjEpLmx0ZSg1KVxyXG4gICAgICA6IHpcclxuICAgICAgICAgIC51bmlvbihbXHJcbiAgICAgICAgICAgIHpcclxuICAgICAgICAgICAgICAuc3RyaW5nKClcclxuICAgICAgICAgICAgICAudHJpbSgpXHJcbiAgICAgICAgICAgICAgLnJlZmluZShcclxuICAgICAgICAgICAgICAgICh2YWx1ZSkgPT5cclxuICAgICAgICAgICAgICAgICAgKCFpc05hTihOdW1iZXIodmFsdWUpKSAmJlxyXG4gICAgICAgICAgICAgICAgICAgIHZhbHVlICE9PSB0cnVlICYmXHJcbiAgICAgICAgICAgICAgICAgICAgIXZhbHVlLnN0YXJ0c1dpdGgoJ1snKSAmJlxyXG4gICAgICAgICAgICAgICAgICAgIE51bWJlcih2YWx1ZSkgPj0gMC4xICYmXHJcbiAgICAgICAgICAgICAgICAgICAgTnVtYmVyKHZhbHVlKSA8PSA1KSB8fFxyXG4gICAgICAgICAgICAgICAgICBbJ3VuZGVmaW5lZCcsICdudWxsJywgJyddLmluY2x1ZGVzKHZhbHVlKSxcclxuICAgICAgICAgICAgICAgIHtcclxuICAgICAgICAgICAgICAgICAgcGFyYW1zOiB7XHJcbiAgICAgICAgICAgICAgICAgICAgZXJyb3JNZXNzYWdlOiAnVGhlIHZhbHVlIG11c3QgYmUgd2l0aGluIGEgMC4xIGFuZCA1LjAgcmFuZ2UnXHJcbiAgICAgICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgICApXHJcbiAgICAgICAgICAgICAgLnRyYW5zZm9ybSgodmFsdWUpID0+XHJcbiAgICAgICAgICAgICAgICAhWyd1bmRlZmluZWQnLCAnbnVsbCcsICcnXS5pbmNsdWRlcyh2YWx1ZSlcclxuICAgICAgICAgICAgICAgICAgPyBOdW1iZXIodmFsdWUpXHJcbiAgICAgICAgICAgICAgICAgIDogbnVsbFxyXG4gICAgICAgICAgICAgICksXHJcbiAgICAgICAgICAgIHoubnVtYmVyKCkuZ3RlKDAuMSkubHRlKDUpXHJcbiAgICAgICAgICBdKVxyXG4gICAgICAgICAgLm51bGxhYmxlKCk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGBoZWlnaHRgIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGggYW4gb3B0aW9uYWwgc3RyaWN0ZXJcclxuICAgKiBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGUgc2FtZSB3b3JrIGFzIGEgbnVsbGFibGUgYGRlZmF1bHRIZWlnaHRgXHJcbiAgICogdmFsaWRhdG9yLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIGhlaWdodFxyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nIHRoZSBgaGVpZ2h0YFxyXG4gICAqIG9wdGlvbi5cclxuICAgKi9cclxuICBoZWlnaHQoc3RyaWN0Q2hlY2spIHtcclxuICAgIHJldHVybiB0aGlzLmRlZmF1bHRIZWlnaHQoc3RyaWN0Q2hlY2spLm51bGxhYmxlKCk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGB3aWR0aGAgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbCBzdHJpY3RlclxyXG4gICAqIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgYSBudWxsYWJsZSBgZGVmYXVsdFdpZHRoYFxyXG4gICAqIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiB3aWR0aFxyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nIHRoZSBgd2lkdGhgXHJcbiAgICogb3B0aW9uLlxyXG4gICAqL1xyXG4gIHdpZHRoKHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gdGhpcy5kZWZhdWx0V2lkdGgoc3RyaWN0Q2hlY2spLm51bGxhYmxlKCk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGBzY2FsZWAgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbCBzdHJpY3RlclxyXG4gICAqIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgYSBudWxsYWJsZSBgZGVmYXVsdFNjYWxlYFxyXG4gICAqIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiBzY2FsZVxyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nIHRoZSBgc2NhbGVgXHJcbiAgICogb3B0aW9uLlxyXG4gICAqL1xyXG4gIHNjYWxlKHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gdGhpcy5kZWZhdWx0U2NhbGUoc3RyaWN0Q2hlY2spLm51bGxhYmxlKCk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGBnbG9iYWxPcHRpb25zYCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYS5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgdGhlIGBhZGRpdGlvbmFsT3B0aW9uc2BcclxuICAgKiB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gZ2xvYmFsT3B0aW9uc1xyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nXHJcbiAgICogdGhlIGBnbG9iYWxPcHRpb25zYCBvcHRpb24uXHJcbiAgICovXHJcbiAgZ2xvYmFsT3B0aW9ucygpIHtcclxuICAgIHJldHVybiB2LmFkZGl0aW9uYWxPcHRpb25zKCk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGB0aGVtZU9wdGlvbnNgIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhlIHNhbWUgd29yayBhcyB0aGUgYGFkZGl0aW9uYWxPcHRpb25zYFxyXG4gICAqIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiB0aGVtZU9wdGlvbnNcclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZ1xyXG4gICAqIHRoZSBgdGhlbWVPcHRpb25zYCBvcHRpb24uXHJcbiAgICovXHJcbiAgdGhlbWVPcHRpb25zKCkge1xyXG4gICAgcmV0dXJuIHYuYWRkaXRpb25hbE9wdGlvbnMoKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYGJhdGNoYCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoIGFuIG9wdGlvbmFsIHN0cmljdGVyXHJcbiAgICogY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhlIHNhbWUgd29yayBhcyB0aGUgYHN0cmluZ2AgdmFsaWRhdG9yLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIGJhdGNoXHJcbiAgICpcclxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IHN0cmljdENoZWNrIC0gRGV0ZXJtaW5lcyBpZiBzdHJpY3RlciB2YWxpZGF0aW9uIHNob3VsZFxyXG4gICAqIGJlIGFwcGxpZWQuXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9IEEgWm9kIHNjaGVtYSBvYmplY3QgZm9yIHZhbGlkYXRpbmcgdGhlIGBiYXRjaGBcclxuICAgKiBvcHRpb24uXHJcbiAgICovXHJcbiAgYmF0Y2goc3RyaWN0Q2hlY2spIHtcclxuICAgIHJldHVybiB2LnN0cmluZyhzdHJpY3RDaGVjayk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGByYXN0ZXJpemF0aW9uVGltZW91dGAgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aFxyXG4gICAqIGFuIG9wdGlvbmFsIHN0cmljdGVyIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgdGhlIGBub25OZWdhdGl2ZU51bWBcclxuICAgKiB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gcmFzdGVyaXphdGlvblRpbWVvdXRcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZ1xyXG4gICAqIHRoZSBgcmFzdGVyaXphdGlvblRpbWVvdXRgIG9wdGlvbi5cclxuICAgKi9cclxuICByYXN0ZXJpemF0aW9uVGltZW91dChzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHYubm9uTmVnYXRpdmVOdW0oc3RyaWN0Q2hlY2spO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgYWxsb3dDb2RlRXhlY3V0aW9uYCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoXHJcbiAgICogYW4gb3B0aW9uYWwgc3RyaWN0ZXIgY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhlIHNhbWUgd29yayBhcyB0aGUgYGJvb2xlYW5gIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiBhbGxvd0NvZGVFeGVjdXRpb25cclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZ1xyXG4gICAqIHRoZSBgYWxsb3dDb2RlRXhlY3V0aW9uYCBvcHRpb24uXHJcbiAgICovXHJcbiAgYWxsb3dDb2RlRXhlY3V0aW9uKHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gdi5ib29sZWFuKHN0cmljdENoZWNrKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYGFsbG93RmlsZVJlc291cmNlc2AgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aFxyXG4gICAqIGFuIG9wdGlvbmFsIHN0cmljdGVyIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgdGhlIGBib29sZWFuYCB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gYWxsb3dGaWxlUmVzb3VyY2VzXHJcbiAgICpcclxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IHN0cmljdENoZWNrIC0gRGV0ZXJtaW5lcyBpZiBzdHJpY3RlciB2YWxpZGF0aW9uIHNob3VsZFxyXG4gICAqIGJlIGFwcGxpZWQuXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9IEEgWm9kIHNjaGVtYSBvYmplY3QgZm9yIHZhbGlkYXRpbmdcclxuICAgKiB0aGUgYGFsbG93RmlsZVJlc291cmNlc2Agb3B0aW9uLlxyXG4gICAqL1xyXG4gIGFsbG93RmlsZVJlc291cmNlcyhzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHYuYm9vbGVhbihzdHJpY3RDaGVjayk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGBjdXN0b21Db2RlYCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoIGFuIG9wdGlvbmFsXHJcbiAgICogc3RyaWN0ZXIgY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhlIHNhbWUgd29yayBhcyB0aGUgYHN0cmluZ2AgdmFsaWRhdG9yLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIGN1c3RvbUNvZGVcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZyB0aGUgYGN1c3RvbUNvZGVgXHJcbiAgICogb3B0aW9uLlxyXG4gICAqL1xyXG4gIGN1c3RvbUNvZGUoc3RyaWN0Q2hlY2spIHtcclxuICAgIHJldHVybiB2LnN0cmluZyhzdHJpY3RDaGVjayk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGBjYWxsYmFja2AgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbFxyXG4gICAqIHN0cmljdGVyIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgdGhlIGBzdHJpbmdgIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiBjYWxsYmFja1xyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nIHRoZSBgY2FsbGJhY2tgXHJcbiAgICogb3B0aW9uLlxyXG4gICAqL1xyXG4gIGNhbGxiYWNrKHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gdi5zdHJpbmcoc3RyaWN0Q2hlY2spO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgcmVzb3VyY2VzYCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoIGFuIG9wdGlvbmFsXHJcbiAgICogc3RyaWN0ZXIgY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhhdDpcclxuICAgKlxyXG4gICAqIC0gV2hlbiBgc3RyaWN0Q2hlY2tgIGlzIHRydWUsIHRoZSBzY2hlbWEgd2lsbCBhY2NlcHQgYSBwYXJ0aWFsIG9iamVjdFxyXG4gICAqIHdpdGggYWxsb3dlZCBwcm9wZXJ0aWVzIGBqc2AsIGBjc3NgLCBhbmQgYGZpbGVzYCB3aGVyZSBlYWNoIG9mIHRoZSBhbGxvd2VkXHJcbiAgICogcHJvcGVydGllcyBjYW4gYmUgbnVsbCwgc3RyaW5naWZpZWQgdmVyc2lvbiBvZiB0aGUgb2JqZWN0LCBzdHJpbmcgdGhhdCBlbmRzXHJcbiAgICogd2l0aCB0aGUgJy5qc29uJywgYW5kIG51bGwuXHJcbiAgICpcclxuICAgKiAtIFdoZW4gYHN0cmljdENoZWNrYCBpcyBmYWxzZSwgdGhlIHNjaGVtYSB3aWxsIGFjY2VwdCBhIHN0cmluZ2lmaWVkIHZlcnNpb25cclxuICAgKiBvZiBhIHBhcnRpYWwgb2JqZWN0IHdpdGggYWxsb3dlZCBwcm9wZXJ0aWVzIGBqc2AsIGBjc3NgLCBhbmQgYGZpbGVzYCB3aGVyZVxyXG4gICAqIGVhY2ggb2YgdGhlIGFsbG93ZWQgcHJvcGVydGllcyBjYW4gYmUgbnVsbCwgc3RyaW5nIHRoYXQgZW5kcyB3aXRoIHRoZVxyXG4gICAqICcuanNvbicsIGFuZCB3aWxsIGJlIG51bGwgaWYgdGhlIHByb3ZpZGVkIHZhbHVlIGlzICd1bmRlZmluZWQnLCAnbnVsbCdcclxuICAgKiBvciAnJy5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiByZXNvdXJjZXNcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZyB0aGUgYHJlc291cmNlc2BcclxuICAgKiBvcHRpb24uXHJcbiAgICovXHJcbiAgcmVzb3VyY2VzKHN0cmljdENoZWNrKSB7XHJcbiAgICBjb25zdCBvYmplY3RTY2hlbWEgPSB6XHJcbiAgICAgIC5vYmplY3Qoe1xyXG4gICAgICAgIGpzOiB2LnN0cmluZyhmYWxzZSksXHJcbiAgICAgICAgY3NzOiB2LnN0cmluZyhmYWxzZSksXHJcbiAgICAgICAgZmlsZXM6IHZcclxuICAgICAgICAgIC5zdHJpbmdBcnJheShcclxuICAgICAgICAgICAgKHZhbHVlKSA9PiAhWyd1bmRlZmluZWQnLCAnbnVsbCcsICcnXS5pbmNsdWRlcyh2YWx1ZSksXHJcbiAgICAgICAgICAgICcsJyxcclxuICAgICAgICAgICAgdHJ1ZVxyXG4gICAgICAgICAgKVxyXG4gICAgICAgICAgLm51bGxhYmxlKClcclxuICAgICAgfSlcclxuICAgICAgLnBhcnRpYWwoKTtcclxuXHJcbiAgICBjb25zdCBzdHJpbmdTY2hlbWExID0gelxyXG4gICAgICAuc3RyaW5nKClcclxuICAgICAgLnRyaW0oKVxyXG4gICAgICAucmVmaW5lKFxyXG4gICAgICAgICh2YWx1ZSkgPT5cclxuICAgICAgICAgICh2YWx1ZS5zdGFydHNXaXRoKCd7JykgJiYgdmFsdWUuZW5kc1dpdGgoJ30nKSkgfHxcclxuICAgICAgICAgICh2YWx1ZS5sZW5ndGggPj0gNiAmJiB2YWx1ZS5lbmRzV2l0aCgnLmpzb24nKSksXHJcbiAgICAgICAge1xyXG4gICAgICAgICAgcGFyYW1zOiB7XHJcbiAgICAgICAgICAgIGVycm9yTWVzc2FnZTogYFRoZSB2YWx1ZSBtdXN0IGJlIGEgc3RyaW5nIHRoYXQgc3RhcnRzIHdpdGggJ3snIGFuZCBlbmRzIHdpdGggJ31gXHJcbiAgICAgICAgICB9XHJcbiAgICAgICAgfVxyXG4gICAgICApO1xyXG5cclxuICAgIGNvbnN0IHN0cmluZ1NjaGVtYTIgPSB6XHJcbiAgICAgIC5zdHJpbmcoKVxyXG4gICAgICAudHJpbSgpXHJcbiAgICAgIC5yZWZpbmUoXHJcbiAgICAgICAgKHZhbHVlKSA9PlxyXG4gICAgICAgICAgKHZhbHVlLnN0YXJ0c1dpdGgoJ3snKSAmJiB2YWx1ZS5lbmRzV2l0aCgnfScpKSB8fFxyXG4gICAgICAgICAgKHZhbHVlLmxlbmd0aCA+PSA2ICYmIHZhbHVlLmVuZHNXaXRoKCcuanNvbicpKSB8fFxyXG4gICAgICAgICAgWyd1bmRlZmluZWQnLCAnbnVsbCcsICcnXS5pbmNsdWRlcyh2YWx1ZSksXHJcbiAgICAgICAge1xyXG4gICAgICAgICAgcGFyYW1zOiB7XHJcbiAgICAgICAgICAgIGVycm9yTWVzc2FnZTogYFRoZSB2YWx1ZSBtdXN0IGJlIGEgc3RyaW5nIHRoYXQgZW5kcyB3aXRoICcuanNvbidgXHJcbiAgICAgICAgICB9XHJcbiAgICAgICAgfVxyXG4gICAgICApXHJcbiAgICAgIC50cmFuc2Zvcm0oKHZhbHVlKSA9PlxyXG4gICAgICAgICFbJ3VuZGVmaW5lZCcsICdudWxsJywgJyddLmluY2x1ZGVzKHZhbHVlKSA/IHZhbHVlIDogbnVsbFxyXG4gICAgICApO1xyXG5cclxuICAgIHJldHVybiBzdHJpY3RDaGVja1xyXG4gICAgICA/IHoudW5pb24oW29iamVjdFNjaGVtYSwgc3RyaW5nU2NoZW1hMV0pLm51bGxhYmxlKClcclxuICAgICAgOiB6LnVuaW9uKFtvYmplY3RTY2hlbWEsIHN0cmluZ1NjaGVtYTJdKS5udWxsYWJsZSgpO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgbG9hZENvbmZpZ2AgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbFxyXG4gICAqIHN0cmljdGVyIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgdGhlIGBzdHJpbmdgIHZhbGlkYXRvci5cclxuICAgKiBBZGRpdGlvbmFsbHksIGl0IG11c3QgYmUgYSBzdHJpbmcgdGhhdCBlbmRzIHdpdGggJy5qc29uJy5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiBsb2FkQ29uZmlnXHJcbiAgICpcclxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IHN0cmljdENoZWNrIC0gRGV0ZXJtaW5lcyBpZiBzdHJpY3RlciB2YWxpZGF0aW9uIHNob3VsZFxyXG4gICAqIGJlIGFwcGxpZWQuXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9IEEgWm9kIHNjaGVtYSBvYmplY3QgZm9yIHZhbGlkYXRpbmcgdGhlIGBsb2FkQ29uZmlnYFxyXG4gICAqIG9wdGlvbi5cclxuICAgKi9cclxuICBsb2FkQ29uZmlnKHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gdlxyXG4gICAgICAuc3RyaW5nKHN0cmljdENoZWNrKVxyXG4gICAgICAucmVmaW5lKFxyXG4gICAgICAgICh2YWx1ZSkgPT5cclxuICAgICAgICAgIHZhbHVlID09PSBudWxsIHx8ICh2YWx1ZS5sZW5ndGggPj0gNiAmJiB2YWx1ZS5lbmRzV2l0aCgnLmpzb24nKSksXHJcbiAgICAgICAge1xyXG4gICAgICAgICAgcGFyYW1zOiB7XHJcbiAgICAgICAgICAgIGVycm9yTWVzc2FnZTogYFRoZSB2YWx1ZSBtdXN0IGJlIGEgc3RyaW5nIHRoYXQgZW5kcyB3aXRoIC5qc29uIGBcclxuICAgICAgICAgIH1cclxuICAgICAgICB9XHJcbiAgICAgICk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGBjcmVhdGVDb25maWdgIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGggYW4gb3B0aW9uYWxcclxuICAgKiBzdHJpY3RlciBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGUgc2FtZSB3b3JrIGFzIHRoZSBgbG9hZENvbmZpZ2AgdmFsaWRhdG9yLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIGNyZWF0ZUNvbmZpZ1xyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nXHJcbiAgICogdGhlIGBjcmVhdGVDb25maWdgIG9wdGlvbi5cclxuICAgKi9cclxuICBjcmVhdGVDb25maWcoc3RyaWN0Q2hlY2spIHtcclxuICAgIHJldHVybiB0aGlzLmxvYWRDb25maWcoc3RyaWN0Q2hlY2spO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgZW5hYmxlU2VydmVyYCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoIGFuIG9wdGlvbmFsXHJcbiAgICogc3RyaWN0ZXIgY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhlIHNhbWUgd29yayBhcyB0aGUgYGJvb2xlYW5gIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiBlbmFibGVTZXJ2ZXJcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZ1xyXG4gICAqIHRoZSBgZW5hYmxlU2VydmVyYCBvcHRpb24uXHJcbiAgICovXHJcbiAgZW5hYmxlU2VydmVyKHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gdi5ib29sZWFuKHN0cmljdENoZWNrKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYGhvc3RgIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGggYW4gb3B0aW9uYWwgc3RyaWN0ZXJcclxuICAgKiBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGUgc2FtZSB3b3JrIGFzIHRoZSBgc3RyaW5nYCB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gaG9zdFxyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nIHRoZSBgaG9zdGBcclxuICAgKiBvcHRpb24uXHJcbiAgICovXHJcbiAgaG9zdChzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHYuc3RyaW5nKHN0cmljdENoZWNrKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYHBvcnRgIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGggYW4gb3B0aW9uYWwgc3RyaWN0ZXJcclxuICAgKiBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGUgc2FtZSB3b3JrIGFzIHRoZSBgbm9uTmVnYXRpdmVOdW1gXHJcbiAgICogdmFsaWRhdG9yLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIHBvcnRcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZyB0aGUgYHBvcnRgXHJcbiAgICogb3B0aW9uLlxyXG4gICAqL1xyXG4gIHBvcnQoc3RyaWN0Q2hlY2spIHtcclxuICAgIHJldHVybiB2Lm5vbk5lZ2F0aXZlTnVtKHN0cmljdENoZWNrKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYHVwbG9hZExpbWl0YCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoIGFuIG9wdGlvbmFsXHJcbiAgICogc3RyaWN0ZXIgY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhlIHNhbWUgd29yayBhcyB0aGUgYHBvc2l0aXZlTnVtYCB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gdXBsb2FkTGltaXRcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZyB0aGUgYHVwbG9hZExpbWl0YFxyXG4gICAqIG9wdGlvbi5cclxuICAgKi9cclxuICB1cGxvYWRMaW1pdChzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHYucG9zaXRpdmVOdW0oc3RyaWN0Q2hlY2spO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgc2VydmVyQmVuY2htYXJraW5nYCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoXHJcbiAgICogYW4gb3B0aW9uYWwgc3RyaWN0ZXIgY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhlIHNhbWUgd29yayBhcyB0aGUgYGJvb2xlYW5gIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiBzZXJ2ZXJCZW5jaG1hcmtpbmdcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZ1xyXG4gICAqIHRoZSBgc2VydmVyQmVuY2htYXJraW5nYCBvcHRpb24uXHJcbiAgICovXHJcbiAgc2VydmVyQmVuY2htYXJraW5nKHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gdi5ib29sZWFuKHN0cmljdENoZWNrKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYHByb3h5SG9zdGAgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbFxyXG4gICAqIHN0cmljdGVyIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgdGhlIGBzdHJpbmdgIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiBwcm94eUhvc3RcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZyB0aGUgYHByb3h5SG9zdGBcclxuICAgKiBvcHRpb24uXHJcbiAgICovXHJcbiAgcHJveHlIb3N0KHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gdi5zdHJpbmcoc3RyaWN0Q2hlY2spO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgcHJveHlQb3J0YCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoIGFuIG9wdGlvbmFsXHJcbiAgICogc3RyaWN0ZXIgY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhlIHNhbWUgd29yayBhcyBhIG51bGxhYmxlIGBub25OZWdhdGl2ZU51bWBcclxuICAgKiB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gcHJveHlQb3J0XHJcbiAgICpcclxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IHN0cmljdENoZWNrIC0gRGV0ZXJtaW5lcyBpZiBzdHJpY3RlciB2YWxpZGF0aW9uIHNob3VsZFxyXG4gICAqIGJlIGFwcGxpZWQuXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9IEEgWm9kIHNjaGVtYSBvYmplY3QgZm9yIHZhbGlkYXRpbmcgdGhlIGBwcm94eVBvcnRgXHJcbiAgICogb3B0aW9uLlxyXG4gICAqL1xyXG4gIHByb3h5UG9ydChzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHYubm9uTmVnYXRpdmVOdW0oc3RyaWN0Q2hlY2spLm51bGxhYmxlKCk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGBwcm94eVRpbWVvdXRgIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGggYW4gb3B0aW9uYWxcclxuICAgKiBzdHJpY3RlciBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGUgc2FtZSB3b3JrIGFzIHRoZSBgbm9uTmVnYXRpdmVOdW1gXHJcbiAgICogdmFsaWRhdG9yLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIHByb3h5VGltZW91dFxyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nXHJcbiAgICogdGhlIGBwcm94eVRpbWVvdXRgIG9wdGlvbi5cclxuICAgKi9cclxuICBwcm94eVRpbWVvdXQoc3RyaWN0Q2hlY2spIHtcclxuICAgIHJldHVybiB2Lm5vbk5lZ2F0aXZlTnVtKHN0cmljdENoZWNrKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYGVuYWJsZVJhdGVMaW1pdGluZ2AgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aFxyXG4gICAqIGFuIG9wdGlvbmFsIHN0cmljdGVyIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgdGhlIGBib29sZWFuYCB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gZW5hYmxlUmF0ZUxpbWl0aW5nXHJcbiAgICpcclxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IHN0cmljdENoZWNrIC0gRGV0ZXJtaW5lcyBpZiBzdHJpY3RlciB2YWxpZGF0aW9uIHNob3VsZFxyXG4gICAqIGJlIGFwcGxpZWQuXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9IEEgWm9kIHNjaGVtYSBvYmplY3QgZm9yIHZhbGlkYXRpbmdcclxuICAgKiB0aGUgYGVuYWJsZVJhdGVMaW1pdGluZ2Agb3B0aW9uLlxyXG4gICAqL1xyXG4gIGVuYWJsZVJhdGVMaW1pdGluZyhzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHYuYm9vbGVhbihzdHJpY3RDaGVjayk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGBtYXhSZXF1ZXN0c2AgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbFxyXG4gICAqIHN0cmljdGVyIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgdGhlIGBub25OZWdhdGl2ZU51bWBcclxuICAgKiB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gbWF4UmVxdWVzdHNcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZyB0aGUgYG1heFJlcXVlc3RzYFxyXG4gICAqIG9wdGlvbi5cclxuICAgKi9cclxuICBtYXhSZXF1ZXN0cyhzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHYubm9uTmVnYXRpdmVOdW0oc3RyaWN0Q2hlY2spO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgd2luZG93YCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoIGFuIG9wdGlvbmFsIHN0cmljdGVyXHJcbiAgICogY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhlIHNhbWUgd29yayBhcyB0aGUgYG5vbk5lZ2F0aXZlTnVtYFxyXG4gICAqIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiB3aW5kb3dcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZyB0aGUgYHdpbmRvd2BcclxuICAgKiBvcHRpb24uXHJcbiAgICovXHJcbiAgd2luZG93KHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gdi5ub25OZWdhdGl2ZU51bShzdHJpY3RDaGVjayk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGBkZWxheWAgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbCBzdHJpY3RlclxyXG4gICAqIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgdGhlIGBub25OZWdhdGl2ZU51bWBcclxuICAgKiB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gZGVsYXlcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZyB0aGUgYGRlbGF5YFxyXG4gICAqIG9wdGlvbi5cclxuICAgKi9cclxuICBkZWxheShzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHYubm9uTmVnYXRpdmVOdW0oc3RyaWN0Q2hlY2spO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgdHJ1c3RQcm94eWAgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbFxyXG4gICAqIHN0cmljdGVyIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgdGhlIGBib29sZWFuYCB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gdHJ1c3RQcm94eVxyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nIHRoZSBgdHJ1c3RQcm94eWBcclxuICAgKiBvcHRpb24uXHJcbiAgICovXHJcbiAgdHJ1c3RQcm94eShzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHYuYm9vbGVhbihzdHJpY3RDaGVjayk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGBza2lwS2V5YCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoIGFuIG9wdGlvbmFsIHN0cmljdGVyXHJcbiAgICogY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhlIHNhbWUgd29yayBhcyB0aGUgYHN0cmluZ2AgdmFsaWRhdG9yLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIHNraXBLZXlcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZyB0aGUgYHNraXBLZXlgXHJcbiAgICogb3B0aW9uLlxyXG4gICAqL1xyXG4gIHNraXBLZXkoc3RyaWN0Q2hlY2spIHtcclxuICAgIHJldHVybiB2LnN0cmluZyhzdHJpY3RDaGVjayk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGBza2lwVG9rZW5gIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGggYW4gb3B0aW9uYWxcclxuICAgKiBzdHJpY3RlciBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGUgc2FtZSB3b3JrIGFzIHRoZSBgc3RyaW5nYCB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gc2tpcFRva2VuXHJcbiAgICpcclxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IHN0cmljdENoZWNrIC0gRGV0ZXJtaW5lcyBpZiBzdHJpY3RlciB2YWxpZGF0aW9uIHNob3VsZFxyXG4gICAqIGJlIGFwcGxpZWQuXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9IEEgWm9kIHNjaGVtYSBvYmplY3QgZm9yIHZhbGlkYXRpbmcgdGhlIGBza2lwVG9rZW5gXHJcbiAgICogb3B0aW9uLlxyXG4gICAqL1xyXG4gIHNraXBUb2tlbihzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHYuc3RyaW5nKHN0cmljdENoZWNrKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYGVuYWJsZVNzbGAgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbFxyXG4gICAqIHN0cmljdGVyIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgdGhlIGBib29sZWFuYCB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gZW5hYmxlU3NsXHJcbiAgICpcclxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IHN0cmljdENoZWNrIC0gRGV0ZXJtaW5lcyBpZiBzdHJpY3RlciB2YWxpZGF0aW9uIHNob3VsZFxyXG4gICAqIGJlIGFwcGxpZWQuXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9IEEgWm9kIHNjaGVtYSBvYmplY3QgZm9yIHZhbGlkYXRpbmcgdGhlIGBlbmFibGVTc2xgXHJcbiAgICogb3B0aW9uLlxyXG4gICAqL1xyXG4gIGVuYWJsZVNzbChzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHYuYm9vbGVhbihzdHJpY3RDaGVjayk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGBzc2xGb3JjZWAgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbFxyXG4gICAqIHN0cmljdGVyIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgdGhlIGBib29sZWFuYCB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gc3NsRm9yY2VcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZyB0aGUgYHNzbEZvcmNlYFxyXG4gICAqIG9wdGlvbi5cclxuICAgKi9cclxuICBzc2xGb3JjZShzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHYuYm9vbGVhbihzdHJpY3RDaGVjayk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGBzc2xQb3J0YCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoIGFuIG9wdGlvbmFsIHN0cmljdGVyXHJcbiAgICogY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhlIHNhbWUgd29yayBhcyB0aGUgYG5vbk5lZ2F0aXZlTnVtYFxyXG4gICAqIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiBzc2xQb3J0XHJcbiAgICpcclxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IHN0cmljdENoZWNrIC0gRGV0ZXJtaW5lcyBpZiBzdHJpY3RlciB2YWxpZGF0aW9uIHNob3VsZFxyXG4gICAqIGJlIGFwcGxpZWQuXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9IEEgWm9kIHNjaGVtYSBvYmplY3QgZm9yIHZhbGlkYXRpbmcgdGhlIGBzc2xQb3J0YFxyXG4gICAqIG9wdGlvbi5cclxuICAgKi9cclxuICBzc2xQb3J0KHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gdi5ub25OZWdhdGl2ZU51bShzdHJpY3RDaGVjayk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGBzc2xDZXJ0UGF0aGAgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbFxyXG4gICAqIHN0cmljdGVyIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgdGhlIGBzdHJpbmdgIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiBzc2xDZXJ0UGF0aFxyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nIHRoZSBgc3NsQ2VydFBhdGhgXHJcbiAgICogb3B0aW9uLlxyXG4gICAqL1xyXG4gIHNzbENlcnRQYXRoKHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gdi5zdHJpbmcoc3RyaWN0Q2hlY2spO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgbWluV29ya2Vyc2AgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbFxyXG4gICAqIHN0cmljdGVyIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgdGhlIGBwb3NpdGl2ZU51bWAgdmFsaWRhdG9yLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIG1pbldvcmtlcnNcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZyB0aGUgYG1pbldvcmtlcnNgXHJcbiAgICogb3B0aW9uLlxyXG4gICAqL1xyXG4gIG1pbldvcmtlcnMoc3RyaWN0Q2hlY2spIHtcclxuICAgIHJldHVybiB2LnBvc2l0aXZlTnVtKHN0cmljdENoZWNrKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYG1heFdvcmtlcnNgIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGggYW4gb3B0aW9uYWxcclxuICAgKiBzdHJpY3RlciBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGUgc2FtZSB3b3JrIGFzIHRoZSBgcG9zaXRpdmVOdW1gIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiBtYXhXb3JrZXJzXHJcbiAgICpcclxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IHN0cmljdENoZWNrIC0gRGV0ZXJtaW5lcyBpZiBzdHJpY3RlciB2YWxpZGF0aW9uIHNob3VsZFxyXG4gICAqIGJlIGFwcGxpZWQuXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9IEEgWm9kIHNjaGVtYSBvYmplY3QgZm9yIHZhbGlkYXRpbmcgdGhlIGBtYXhXb3JrZXJzYFxyXG4gICAqIG9wdGlvbi5cclxuICAgKi9cclxuICBtYXhXb3JrZXJzKHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gdi5wb3NpdGl2ZU51bShzdHJpY3RDaGVjayk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGB3b3JrTGltaXRgIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGggYW4gb3B0aW9uYWxcclxuICAgKiBzdHJpY3RlciBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGUgc2FtZSB3b3JrIGFzIHRoZSBgcG9zaXRpdmVOdW1gIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiB3b3JrTGltaXRcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZyB0aGUgYHdvcmtMaW1pdGBcclxuICAgKiBvcHRpb24uXHJcbiAgICovXHJcbiAgd29ya0xpbWl0KHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gdi5wb3NpdGl2ZU51bShzdHJpY3RDaGVjayk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGBhY3F1aXJlVGltZW91dGAgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbFxyXG4gICAqIHN0cmljdGVyIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgdGhlIGBub25OZWdhdGl2ZU51bWBcclxuICAgKiB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gYWNxdWlyZVRpbWVvdXRcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZ1xyXG4gICAqIHRoZSBgYWNxdWlyZVRpbWVvdXRgIG9wdGlvbi5cclxuICAgKi9cclxuICBhY3F1aXJlVGltZW91dChzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHYubm9uTmVnYXRpdmVOdW0oc3RyaWN0Q2hlY2spO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgY3JlYXRlVGltZW91dGAgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbFxyXG4gICAqIHN0cmljdGVyIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgdGhlIGBub25OZWdhdGl2ZU51bWBcclxuICAgKiB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gY3JlYXRlVGltZW91dFxyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nXHJcbiAgICogdGhlIGBjcmVhdGVUaW1lb3V0YCBvcHRpb24uXHJcbiAgICovXHJcbiAgY3JlYXRlVGltZW91dChzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHYubm9uTmVnYXRpdmVOdW0oc3RyaWN0Q2hlY2spO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgZGVzdHJveVRpbWVvdXRgIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGggYW4gb3B0aW9uYWxcclxuICAgKiBzdHJpY3RlciBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGUgc2FtZSB3b3JrIGFzIHRoZSBgbm9uTmVnYXRpdmVOdW1gXHJcbiAgICogdmFsaWRhdG9yLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIGRlc3Ryb3lUaW1lb3V0XHJcbiAgICpcclxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IHN0cmljdENoZWNrIC0gRGV0ZXJtaW5lcyBpZiBzdHJpY3RlciB2YWxpZGF0aW9uIHNob3VsZFxyXG4gICAqIGJlIGFwcGxpZWQuXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9IEEgWm9kIHNjaGVtYSBvYmplY3QgZm9yIHZhbGlkYXRpbmdcclxuICAgKiB0aGUgYGRlc3Ryb3lUaW1lb3V0YCBvcHRpb24uXHJcbiAgICovXHJcbiAgZGVzdHJveVRpbWVvdXQoc3RyaWN0Q2hlY2spIHtcclxuICAgIHJldHVybiB2Lm5vbk5lZ2F0aXZlTnVtKHN0cmljdENoZWNrKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYGlkbGVUaW1lb3V0YCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoIGFuIG9wdGlvbmFsXHJcbiAgICogc3RyaWN0ZXIgY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhlIHNhbWUgd29yayBhcyB0aGUgYG5vbk5lZ2F0aXZlTnVtYFxyXG4gICAqIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiBpZGxlVGltZW91dFxyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nXHJcbiAgICogdGhlIGBpZGxlVGltZW91dGAgb3B0aW9uLlxyXG4gICAqL1xyXG4gIGlkbGVUaW1lb3V0KHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gdi5ub25OZWdhdGl2ZU51bShzdHJpY3RDaGVjayk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGBjcmVhdGVSZXRyeUludGVydmFsYCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoXHJcbiAgICogYW4gb3B0aW9uYWwgc3RyaWN0ZXIgY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhlIHNhbWUgd29yayBhcyB0aGUgYG5vbk5lZ2F0aXZlTnVtYFxyXG4gICAqIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiBjcmVhdGVSZXRyeUludGVydmFsXHJcbiAgICpcclxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IHN0cmljdENoZWNrIC0gRGV0ZXJtaW5lcyBpZiBzdHJpY3RlciB2YWxpZGF0aW9uIHNob3VsZFxyXG4gICAqIGJlIGFwcGxpZWQuXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9IEEgWm9kIHNjaGVtYSBvYmplY3QgZm9yIHZhbGlkYXRpbmdcclxuICAgKiB0aGUgYGNyZWF0ZVJldHJ5SW50ZXJ2YWxgIG9wdGlvbi5cclxuICAgKi9cclxuICBjcmVhdGVSZXRyeUludGVydmFsKHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gdi5ub25OZWdhdGl2ZU51bShzdHJpY3RDaGVjayk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGByZWFwZXJJbnRlcnZhbGAgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbFxyXG4gICAqIHN0cmljdGVyIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgdGhlIGBub25OZWdhdGl2ZU51bWBcclxuICAgKiB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gcmVhcGVySW50ZXJ2YWxcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZ1xyXG4gICAqIHRoZSBgcmVhcGVySW50ZXJ2YWxgIG9wdGlvbi5cclxuICAgKi9cclxuICByZWFwZXJJbnRlcnZhbChzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHYubm9uTmVnYXRpdmVOdW0oc3RyaWN0Q2hlY2spO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgcG9vbEJlbmNobWFya2luZ2AgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbFxyXG4gICAqIHN0cmljdGVyIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgdGhlIGBib29sZWFuYCB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gcG9vbEJlbmNobWFya2luZ1xyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nXHJcbiAgICogdGhlIGBwb29sQmVuY2htYXJraW5nYCBvcHRpb24uXHJcbiAgICovXHJcbiAgcG9vbEJlbmNobWFya2luZyhzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHYuYm9vbGVhbihzdHJpY3RDaGVjayk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGByZXNvdXJjZXNJbnRlcnZhbGAgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aFxyXG4gICAqIGFuIG9wdGlvbmFsIHN0cmljdGVyIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgdGhlIGBub25OZWdhdGl2ZU51bWBcclxuICAgKiB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gcmVzb3VyY2VzSW50ZXJ2YWxcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZ1xyXG4gICAqIHRoZSBgcmVzb3VyY2VzSW50ZXJ2YWxgIG9wdGlvbi5cclxuICAgKi9cclxuICByZXNvdXJjZXNJbnRlcnZhbChzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHYubm9uTmVnYXRpdmVOdW0oc3RyaWN0Q2hlY2spO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgbG9nTGV2ZWxgIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGggYW4gb3B0aW9uYWxcclxuICAgKiBzdHJpY3RlciBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGF0OlxyXG4gICAqXHJcbiAgICogLSBXaGVuIGBzdHJpY3RDaGVja2AgaXMgdHJ1ZSwgdGhlIHNjaGVtYSB3aWxsIGFjY2VwdCBpbnRlZ2VyIG51bWJlciB2YWx1ZXNcclxuICAgKiB0aGF0IGFyZSBiZXR3ZWVuIDAgYW5kIDUgKGluY2x1c2l2ZSkuXHJcbiAgICpcclxuICAgKiAtIFdoZW4gYHN0cmljdENoZWNrYCBpcyBmYWxzZSwgdGhlIHNjaGVtYSB3aWxsIGFjY2VwdCBpbnRlZ2VyIG51bWJlciB2YWx1ZXNcclxuICAgKiBhbmQgc3RyaW5naWZpZWQgaW50ZWdlciBudW1iZXIgdmFsdWVzIHRoYXQgYXJlIGJldHdlZW4gMSBhbmQgNSAoaW5jbHVzaXZlKSxcclxuICAgKiBudWxsLCAndW5kZWZpbmVkJywgJ251bGwnLCBhbmQgJycgd2hpY2ggd2lsbCBiZSB0cmFuc2Zvcm1lZCB0byBudWxsLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIGxvZ0xldmVsXHJcbiAgICpcclxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IHN0cmljdENoZWNrIC0gRGV0ZXJtaW5lcyBpZiBzdHJpY3RlciB2YWxpZGF0aW9uIHNob3VsZFxyXG4gICAqIGJlIGFwcGxpZWQuXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9IEEgWm9kIHNjaGVtYSBvYmplY3QgZm9yIHZhbGlkYXRpbmcgdGhlIGBsb2dMZXZlbGBcclxuICAgKiBvcHRpb24uXHJcbiAgICovXHJcbiAgbG9nTGV2ZWwoc3RyaWN0Q2hlY2spIHtcclxuICAgIHJldHVybiBzdHJpY3RDaGVja1xyXG4gICAgICA/IHoubnVtYmVyKCkuaW50KCkuZ3RlKDApLmx0ZSg1KVxyXG4gICAgICA6IHpcclxuICAgICAgICAgIC51bmlvbihbXHJcbiAgICAgICAgICAgIHpcclxuICAgICAgICAgICAgICAuc3RyaW5nKClcclxuICAgICAgICAgICAgICAudHJpbSgpXHJcbiAgICAgICAgICAgICAgLnJlZmluZShcclxuICAgICAgICAgICAgICAgICh2YWx1ZSkgPT5cclxuICAgICAgICAgICAgICAgICAgKCFpc05hTihOdW1iZXIodmFsdWUpKSAmJlxyXG4gICAgICAgICAgICAgICAgICAgIHZhbHVlICE9PSB0cnVlICYmXHJcbiAgICAgICAgICAgICAgICAgICAgIXZhbHVlLnN0YXJ0c1dpdGgoJ1snKSAmJlxyXG4gICAgICAgICAgICAgICAgICAgIE51bWJlci5pc0ludGVnZXIoTnVtYmVyKHZhbHVlKSkgJiZcclxuICAgICAgICAgICAgICAgICAgICBOdW1iZXIodmFsdWUpID49IDAgJiZcclxuICAgICAgICAgICAgICAgICAgICBOdW1iZXIodmFsdWUpIDw9IDUpIHx8XHJcbiAgICAgICAgICAgICAgICAgIFsndW5kZWZpbmVkJywgJ251bGwnLCAnJ10uaW5jbHVkZXModmFsdWUpLFxyXG4gICAgICAgICAgICAgICAge1xyXG4gICAgICAgICAgICAgICAgICBwYXJhbXM6IHtcclxuICAgICAgICAgICAgICAgICAgICBlcnJvck1lc3NhZ2U6ICdUaGUgdmFsdWUgbXVzdCBiZSB3aXRoaW4gYSAwIGFuZCA1IHJhbmdlJ1xyXG4gICAgICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgICAgKVxyXG4gICAgICAgICAgICAgIC50cmFuc2Zvcm0oKHZhbHVlKSA9PlxyXG4gICAgICAgICAgICAgICAgIVsndW5kZWZpbmVkJywgJ251bGwnLCAnJ10uaW5jbHVkZXModmFsdWUpXHJcbiAgICAgICAgICAgICAgICAgID8gTnVtYmVyKHZhbHVlKVxyXG4gICAgICAgICAgICAgICAgICA6IG51bGxcclxuICAgICAgICAgICAgICApLFxyXG4gICAgICAgICAgICB6Lm51bWJlcigpLmludCgpLmd0ZSgwKS5sdGUoNSlcclxuICAgICAgICAgIF0pXHJcbiAgICAgICAgICAubnVsbGFibGUoKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYGxvZ0ZpbGVgIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGggYW4gb3B0aW9uYWwgc3RyaWN0ZXJcclxuICAgKiBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGUgc2FtZSB3b3JrIGFzIHRoZSBgc3RyaW5nYCB2YWxpZGF0b3IuXHJcbiAgICogQWRkaXRpb25hbGx5LCBpdCBtdXN0IGJlIGEgc3RyaW5nIHRoYXQgZW5kcyB3aXRoICcubG9nJy5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiBsb2dGaWxlXHJcbiAgICpcclxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IHN0cmljdENoZWNrIC0gRGV0ZXJtaW5lcyBpZiBzdHJpY3RlciB2YWxpZGF0aW9uIHNob3VsZFxyXG4gICAqIGJlIGFwcGxpZWQuXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9IEEgWm9kIHNjaGVtYSBvYmplY3QgZm9yIHZhbGlkYXRpbmcgdGhlIGBsb2dGaWxlYFxyXG4gICAqIG9wdGlvbi5cclxuICAgKi9cclxuICBsb2dGaWxlKHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gdlxyXG4gICAgICAuc3RyaW5nKHN0cmljdENoZWNrKVxyXG4gICAgICAucmVmaW5lKFxyXG4gICAgICAgICh2YWx1ZSkgPT5cclxuICAgICAgICAgIHZhbHVlID09PSBudWxsIHx8ICh2YWx1ZS5sZW5ndGggPj0gNSAmJiB2YWx1ZS5lbmRzV2l0aCgnLmxvZycpKSxcclxuICAgICAgICB7XHJcbiAgICAgICAgICBwYXJhbXM6IHtcclxuICAgICAgICAgICAgZXJyb3JNZXNzYWdlOiBgVGhlIHZhbHVlIG11c3QgYmUgYSBzdHJpbmcgdGhhdCBlbmRzIHdpdGggJy5sb2cnYFxyXG4gICAgICAgICAgfVxyXG4gICAgICAgIH1cclxuICAgICAgKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYGxvZ0Rlc3RgIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGggYW4gb3B0aW9uYWwgc3RyaWN0ZXJcclxuICAgKiBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGUgc2FtZSB3b3JrIGFzIHRoZSBgc3RyaW5nYCB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gbG9nRGVzdFxyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nIHRoZSBgbG9nRGVzdGBcclxuICAgKiBvcHRpb24uXHJcbiAgICovXHJcbiAgbG9nRGVzdChzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHYuc3RyaW5nKHN0cmljdENoZWNrKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYGxvZ1RvQ29uc29sZWAgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbFxyXG4gICAqIHN0cmljdGVyIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgdGhlIGBib29sZWFuYCB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gbG9nVG9Db25zb2xlXHJcbiAgICpcclxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IHN0cmljdENoZWNrIC0gRGV0ZXJtaW5lcyBpZiBzdHJpY3RlciB2YWxpZGF0aW9uIHNob3VsZFxyXG4gICAqIGJlIGFwcGxpZWQuXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9IEEgWm9kIHNjaGVtYSBvYmplY3QgZm9yIHZhbGlkYXRpbmdcclxuICAgKiB0aGUgYGxvZ1RvQ29uc29sZWAgb3B0aW9uLlxyXG4gICAqL1xyXG4gIGxvZ1RvQ29uc29sZShzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHYuYm9vbGVhbihzdHJpY3RDaGVjayk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGBsb2dUb0ZpbGVgIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGggYW4gb3B0aW9uYWxcclxuICAgKiBzdHJpY3RlciBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGUgc2FtZSB3b3JrIGFzIHRoZSBgYm9vbGVhbmAgdmFsaWRhdG9yLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIGxvZ1RvRmlsZVxyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nIHRoZSBgbG9nVG9GaWxlYFxyXG4gICAqIG9wdGlvbi5cclxuICAgKi9cclxuICBsb2dUb0ZpbGUoc3RyaWN0Q2hlY2spIHtcclxuICAgIHJldHVybiB2LmJvb2xlYW4oc3RyaWN0Q2hlY2spO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgZW5hYmxlVWlgIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGggYW4gb3B0aW9uYWxcclxuICAgKiBzdHJpY3RlciBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGUgc2FtZSB3b3JrIGFzIHRoZSBgYm9vbGVhbmAgdmFsaWRhdG9yLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIGVuYWJsZVVpXHJcbiAgICpcclxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IHN0cmljdENoZWNrIC0gRGV0ZXJtaW5lcyBpZiBzdHJpY3RlciB2YWxpZGF0aW9uIHNob3VsZFxyXG4gICAqIGJlIGFwcGxpZWQuXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9IEEgWm9kIHNjaGVtYSBvYmplY3QgZm9yIHZhbGlkYXRpbmcgdGhlIGBlbmFibGVVaWBcclxuICAgKiBvcHRpb24uXHJcbiAgICovXHJcbiAgZW5hYmxlVWkoc3RyaWN0Q2hlY2spIHtcclxuICAgIHJldHVybiB2LmJvb2xlYW4oc3RyaWN0Q2hlY2spO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgdWlSb3V0ZWAgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbFxyXG4gICAqIHN0cmljdGVyIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgdGhlIGBzdGFydHNXaXRoYCB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gdWlSb3V0ZVxyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nIHRoZSBgdWlSb3V0ZWBcclxuICAgKiBvcHRpb24uXHJcbiAgICovXHJcbiAgdWlSb3V0ZShzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHYuc3RhcnRzV2l0aChbJy8nXSwgc3RyaWN0Q2hlY2spO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgbm9kZUVudmAgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbFxyXG4gICAqIHN0cmljdGVyIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgdGhlIGBlbnVtYCB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gbm9kZUVudlxyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nIHRoZSBgbm9kZUVudmBcclxuICAgKiBvcHRpb24uXHJcbiAgICovXHJcbiAgbm9kZUVudihzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHYuZW51bShbJ2RldmVsb3BtZW50JywgJ3Byb2R1Y3Rpb24nLCAndGVzdCddLCBzdHJpY3RDaGVjayk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGBsaXN0ZW5Ub1Byb2Nlc3NFeGl0c2AgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aFxyXG4gICAqIGFuIG9wdGlvbmFsIHN0cmljdGVyIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgdGhlIGBib29sZWFuYCB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gbGlzdGVuVG9Qcm9jZXNzRXhpdHNcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZ1xyXG4gICAqIHRoZSBgbGlzdGVuVG9Qcm9jZXNzRXhpdHNgIG9wdGlvbi5cclxuICAgKi9cclxuICBsaXN0ZW5Ub1Byb2Nlc3NFeGl0cyhzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHYuYm9vbGVhbihzdHJpY3RDaGVjayk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGBub0xvZ29gIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGggYW4gb3B0aW9uYWxcclxuICAgKiBzdHJpY3RlciBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGUgc2FtZSB3b3JrIGFzIHRoZSBgYm9vbGVhbmAgdmFsaWRhdG9yLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIG5vTG9nb1xyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nIHRoZSBgbm9Mb2dvYFxyXG4gICAqIG9wdGlvbi5cclxuICAgKi9cclxuICBub0xvZ28oc3RyaWN0Q2hlY2spIHtcclxuICAgIHJldHVybiB2LmJvb2xlYW4oc3RyaWN0Q2hlY2spO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgaGFyZFJlc2V0UGFnZWAgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbFxyXG4gICAqIHN0cmljdGVyIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgdGhlIGBib29sZWFuYCB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gaGFyZFJlc2V0UGFnZVxyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nXHJcbiAgICogdGhlIGBoYXJkUmVzZXRQYWdlYCBvcHRpb24uXHJcbiAgICovXHJcbiAgaGFyZFJlc2V0UGFnZShzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHYuYm9vbGVhbihzdHJpY3RDaGVjayk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGBicm93c2VyU2hlbGxNb2RlYCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoIGFuIG9wdGlvbmFsXHJcbiAgICogc3RyaWN0ZXIgY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhlIHNhbWUgd29yayBhcyB0aGUgYGJvb2xlYW5gIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiBicm93c2VyU2hlbGxNb2RlXHJcbiAgICpcclxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IHN0cmljdENoZWNrIC0gRGV0ZXJtaW5lcyBpZiBzdHJpY3RlciB2YWxpZGF0aW9uIHNob3VsZFxyXG4gICAqIGJlIGFwcGxpZWQuXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9IEEgWm9kIHNjaGVtYSBvYmplY3QgZm9yIHZhbGlkYXRpbmdcclxuICAgKiB0aGUgYGJyb3dzZXJTaGVsbE1vZGVgIG9wdGlvbi5cclxuICAgKi9cclxuICBicm93c2VyU2hlbGxNb2RlKHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gdi5ib29sZWFuKHN0cmljdENoZWNrKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYGVuYWJsZURlYnVnYCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoIGFuIG9wdGlvbmFsXHJcbiAgICogc3RyaWN0ZXIgY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhlIHNhbWUgd29yayBhcyB0aGUgYGJvb2xlYW5gIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiBlbmFibGVEZWJ1Z1xyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nIHRoZSBgZW5hYmxlRGVidWdgXHJcbiAgICogb3B0aW9uLlxyXG4gICAqL1xyXG4gIGVuYWJsZURlYnVnKHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gdi5ib29sZWFuKHN0cmljdENoZWNrKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYGhlYWRsZXNzYCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoIGFuIG9wdGlvbmFsXHJcbiAgICogc3RyaWN0ZXIgY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhlIHNhbWUgd29yayBhcyB0aGUgYGJvb2xlYW5gIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiBoZWFkbGVzc1xyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nIHRoZSBgaGVhZGxlc3NgXHJcbiAgICogb3B0aW9uLlxyXG4gICAqL1xyXG4gIGhlYWRsZXNzKHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gdi5ib29sZWFuKHN0cmljdENoZWNrKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYGRldnRvb2xzYCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoIGFuIG9wdGlvbmFsXHJcbiAgICogc3RyaWN0ZXIgY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhlIHNhbWUgd29yayBhcyB0aGUgYGJvb2xlYW5gIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiBkZXZ0b29sc1xyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nIHRoZSBgZGV2dG9vbHNgXHJcbiAgICogb3B0aW9uLlxyXG4gICAqL1xyXG4gIGRldnRvb2xzKHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gdi5ib29sZWFuKHN0cmljdENoZWNrKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYGxpc3RlblRvQ29uc29sZWAgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbFxyXG4gICAqIHN0cmljdGVyIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgdGhlIGBib29sZWFuYCB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gbGlzdGVuVG9Db25zb2xlXHJcbiAgICpcclxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IHN0cmljdENoZWNrIC0gRGV0ZXJtaW5lcyBpZiBzdHJpY3RlciB2YWxpZGF0aW9uIHNob3VsZFxyXG4gICAqIGJlIGFwcGxpZWQuXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9IEEgWm9kIHNjaGVtYSBvYmplY3QgZm9yIHZhbGlkYXRpbmdcclxuICAgKiB0aGUgYGxpc3RlblRvQ29uc29sZWAgb3B0aW9uLlxyXG4gICAqL1xyXG4gIGxpc3RlblRvQ29uc29sZShzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHYuYm9vbGVhbihzdHJpY3RDaGVjayk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGBkdW1waW9gIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGggYW4gb3B0aW9uYWwgc3RyaWN0ZXJcclxuICAgKiBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGUgc2FtZSB3b3JrIGFzIHRoZSBgYm9vbGVhbmAgdmFsaWRhdG9yLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIGR1bXBpb1xyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nIHRoZSBgZHVtcGlvYFxyXG4gICAqIG9wdGlvbi5cclxuICAgKi9cclxuICBkdW1waW8oc3RyaWN0Q2hlY2spIHtcclxuICAgIHJldHVybiB2LmJvb2xlYW4oc3RyaWN0Q2hlY2spO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgc2xvd01vYCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoIGFuIG9wdGlvbmFsIHN0cmljdGVyXHJcbiAgICogY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhlIHNhbWUgd29yayBhcyB0aGUgYG5vbk5lZ2F0aXZlTnVtYFxyXG4gICAqIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiBzbG93TW9cclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZyB0aGUgYHNsb3dNb2BcclxuICAgKiBvcHRpb24uXHJcbiAgICovXHJcbiAgc2xvd01vKHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gdi5ub25OZWdhdGl2ZU51bShzdHJpY3RDaGVjayk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGBkZWJ1Z2dpbmdQb3J0YCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoIGFuIG9wdGlvbmFsXHJcbiAgICogc3RyaWN0ZXIgY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhlIHNhbWUgd29yayBhcyB0aGUgYG5vbk5lZ2F0aXZlTnVtYFxyXG4gICAqIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiBkZWJ1Z2dpbmdQb3J0XHJcbiAgICpcclxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IHN0cmljdENoZWNrIC0gRGV0ZXJtaW5lcyBpZiBzdHJpY3RlciB2YWxpZGF0aW9uIHNob3VsZFxyXG4gICAqIGJlIGFwcGxpZWQuXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9IEEgWm9kIHNjaGVtYSBvYmplY3QgZm9yIHZhbGlkYXRpbmdcclxuICAgKiB0aGUgYGRlYnVnZ2luZ1BvcnRgIG9wdGlvbi5cclxuICAgKi9cclxuICBkZWJ1Z2dpbmdQb3J0KHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gdi5ub25OZWdhdGl2ZU51bShzdHJpY3RDaGVjayk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGByZXF1ZXN0SWRgIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGggYW4gb3B0aW9uYWxcclxuICAgKiBzdHJpY3RlciBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGUgc2FtZSB3b3JrIGFzIHRoZSBgc3RyaW5nYCB2YWxpZGF0b3IuXHJcbiAgICogQWRkaXRpb25hbGx5LCBpdCBtdXN0IGJlIGEgc3RyaW5naWZpZWQgVVVJRCBvciBjYW4gYmUgbnVsbC5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiByZXF1ZXN0SWRcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZyB0aGUgYHJlcXVlc3RJZGBcclxuICAgKiBvcHRpb24uXHJcbiAgICovXHJcbiAgcmVxdWVzdElkKCkge1xyXG4gICAgcmV0dXJuIChcclxuICAgICAgelxyXG4gICAgICAgIC5zdHJpbmcoKVxyXG4gICAgICAgIC8vLyBUTyBETzogQ29ycmVjdFxyXG4gICAgICAgIC51dWlkKHsgbWVzc2FnZTogJ1RoZSB2YWx1ZSBtdXN0IGJlIGEgc3RyaW5naWZpZWQgVVVJRCcgfSlcclxuICAgICAgICAubnVsbGFibGUoKVxyXG4gICAgKTtcclxuICB9XHJcbn07XHJcblxyXG4vLyBTY2hlbWEgZm9yIHRoZSBwdXBwZXRlZXIgc2VjdGlvbiBvZiBvcHRpb25zXHJcbmNvbnN0IFB1cHBldGVlclNjaGVtYSA9IChzdHJpY3RDaGVjaykgPT5cclxuICB6XHJcbiAgICAub2JqZWN0KHtcclxuICAgICAgYXJnczogY29uZmlnLmFyZ3Moc3RyaWN0Q2hlY2spXHJcbiAgICB9KVxyXG4gICAgLnBhcnRpYWwoKTtcclxuXHJcbi8vIFNjaGVtYSBmb3IgdGhlIGhpZ2hjaGFydHMgc2VjdGlvbiBvZiBvcHRpb25zXHJcbmNvbnN0IEhpZ2hjaGFydHNTY2hlbWEgPSAoc3RyaWN0Q2hlY2spID0+XHJcbiAgelxyXG4gICAgLm9iamVjdCh7XHJcbiAgICAgIHZlcnNpb246IGNvbmZpZy52ZXJzaW9uKHN0cmljdENoZWNrKSxcclxuICAgICAgY2RuVXJsOiBjb25maWcuY2RuVXJsKHN0cmljdENoZWNrKSxcclxuICAgICAgZm9yY2VGZXRjaDogY29uZmlnLmZvcmNlRmV0Y2goc3RyaWN0Q2hlY2spLFxyXG4gICAgICBjYWNoZVBhdGg6IGNvbmZpZy5jYWNoZVBhdGgoc3RyaWN0Q2hlY2spLFxyXG4gICAgICBjb3JlU2NyaXB0czogY29uZmlnLmNvcmVTY3JpcHRzKHN0cmljdENoZWNrKSxcclxuICAgICAgbW9kdWxlU2NyaXB0czogY29uZmlnLm1vZHVsZVNjcmlwdHMoc3RyaWN0Q2hlY2spLFxyXG4gICAgICBpbmRpY2F0b3JTY3JpcHRzOiBjb25maWcuaW5kaWNhdG9yU2NyaXB0cyhzdHJpY3RDaGVjayksXHJcbiAgICAgIGN1c3RvbVNjcmlwdHM6IGNvbmZpZy5jdXN0b21TY3JpcHRzKHN0cmljdENoZWNrKVxyXG4gICAgfSlcclxuICAgIC5wYXJ0aWFsKCk7XHJcblxyXG4vLyBTY2hlbWEgZm9yIHRoZSBleHBvcnQgc2VjdGlvbiBvZiBvcHRpb25zXHJcbmNvbnN0IEV4cG9ydFNjaGVtYSA9IChzdHJpY3RDaGVjaykgPT5cclxuICB6XHJcbiAgICAub2JqZWN0KHtcclxuICAgICAgaW5maWxlOiBjb25maWcuaW5maWxlKHN0cmljdENoZWNrKSxcclxuICAgICAgaW5zdHI6IGNvbmZpZy5pbnN0cigpLFxyXG4gICAgICBvcHRpb25zOiBjb25maWcub3B0aW9ucygpLFxyXG4gICAgICBzdmc6IGNvbmZpZy5zdmcoKSxcclxuICAgICAgb3V0ZmlsZTogY29uZmlnLm91dGZpbGUoc3RyaWN0Q2hlY2spLFxyXG4gICAgICB0eXBlOiBjb25maWcudHlwZShzdHJpY3RDaGVjayksXHJcbiAgICAgIGNvbnN0cjogY29uZmlnLmNvbnN0cihzdHJpY3RDaGVjayksXHJcbiAgICAgIGI2NDogY29uZmlnLmI2NChzdHJpY3RDaGVjayksXHJcbiAgICAgIG5vRG93bmxvYWQ6IGNvbmZpZy5ub0Rvd25sb2FkKHN0cmljdENoZWNrKSxcclxuICAgICAgZGVmYXVsdEhlaWdodDogY29uZmlnLmRlZmF1bHRIZWlnaHQoc3RyaWN0Q2hlY2spLFxyXG4gICAgICBkZWZhdWx0V2lkdGg6IGNvbmZpZy5kZWZhdWx0V2lkdGgoc3RyaWN0Q2hlY2spLFxyXG4gICAgICBkZWZhdWx0U2NhbGU6IGNvbmZpZy5kZWZhdWx0U2NhbGUoc3RyaWN0Q2hlY2spLFxyXG4gICAgICBoZWlnaHQ6IGNvbmZpZy5oZWlnaHQoc3RyaWN0Q2hlY2spLFxyXG4gICAgICB3aWR0aDogY29uZmlnLndpZHRoKHN0cmljdENoZWNrKSxcclxuICAgICAgc2NhbGU6IGNvbmZpZy5zY2FsZShzdHJpY3RDaGVjayksXHJcbiAgICAgIGdsb2JhbE9wdGlvbnM6IGNvbmZpZy5nbG9iYWxPcHRpb25zKCksXHJcbiAgICAgIHRoZW1lT3B0aW9uczogY29uZmlnLnRoZW1lT3B0aW9ucygpLFxyXG4gICAgICBiYXRjaDogY29uZmlnLmJhdGNoKGZhbHNlKSxcclxuICAgICAgcmFzdGVyaXphdGlvblRpbWVvdXQ6IGNvbmZpZy5yYXN0ZXJpemF0aW9uVGltZW91dChzdHJpY3RDaGVjaylcclxuICAgIH0pXHJcbiAgICAucGFydGlhbCgpO1xyXG5cclxuLy8gU2NoZW1hIGZvciB0aGUgY3VzdG9tTG9naWMgc2VjdGlvbiBvZiBvcHRpb25zXHJcbmNvbnN0IEN1c3RvbUxvZ2ljU2NoZW1hID0gKHN0cmljdENoZWNrKSA9PlxyXG4gIHpcclxuICAgIC5vYmplY3Qoe1xyXG4gICAgICBhbGxvd0NvZGVFeGVjdXRpb246IGNvbmZpZy5hbGxvd0NvZGVFeGVjdXRpb24oc3RyaWN0Q2hlY2spLFxyXG4gICAgICBhbGxvd0ZpbGVSZXNvdXJjZXM6IGNvbmZpZy5hbGxvd0ZpbGVSZXNvdXJjZXMoc3RyaWN0Q2hlY2spLFxyXG4gICAgICBjdXN0b21Db2RlOiBjb25maWcuY3VzdG9tQ29kZShmYWxzZSksXHJcbiAgICAgIGNhbGxiYWNrOiBjb25maWcuY2FsbGJhY2soZmFsc2UpLFxyXG4gICAgICByZXNvdXJjZXM6IGNvbmZpZy5yZXNvdXJjZXMoc3RyaWN0Q2hlY2spLFxyXG4gICAgICBsb2FkQ29uZmlnOiBjb25maWcubG9hZENvbmZpZyhmYWxzZSksXHJcbiAgICAgIGNyZWF0ZUNvbmZpZzogY29uZmlnLmNyZWF0ZUNvbmZpZyhmYWxzZSlcclxuICAgIH0pXHJcbiAgICAucGFydGlhbCgpO1xyXG5cclxuLy8gU2NoZW1hIGZvciB0aGUgc2VydmVyLnByb3h5IHNlY3Rpb24gb2Ygb3B0aW9uc1xyXG5jb25zdCBQcm94eVNjaGVtYSA9IChzdHJpY3RDaGVjaykgPT5cclxuICB6XHJcbiAgICAub2JqZWN0KHtcclxuICAgICAgaG9zdDogY29uZmlnLnByb3h5SG9zdChmYWxzZSksXHJcbiAgICAgIHBvcnQ6IGNvbmZpZy5wcm94eVBvcnQoc3RyaWN0Q2hlY2spLFxyXG4gICAgICB0aW1lb3V0OiBjb25maWcucHJveHlUaW1lb3V0KHN0cmljdENoZWNrKVxyXG4gICAgfSlcclxuICAgIC5wYXJ0aWFsKCk7XHJcblxyXG4vLyBTY2hlbWEgZm9yIHRoZSBzZXJ2ZXIucmF0ZUxpbWl0aW5nIHNlY3Rpb24gb2Ygb3B0aW9uc1xyXG5jb25zdCBSYXRlTGltaXRpbmdTY2hlbWEgPSAoc3RyaWN0Q2hlY2spID0+XHJcbiAgelxyXG4gICAgLm9iamVjdCh7XHJcbiAgICAgIGVuYWJsZTogY29uZmlnLmVuYWJsZVJhdGVMaW1pdGluZyhzdHJpY3RDaGVjayksXHJcbiAgICAgIG1heFJlcXVlc3RzOiBjb25maWcubWF4UmVxdWVzdHMoc3RyaWN0Q2hlY2spLFxyXG4gICAgICB3aW5kb3c6IGNvbmZpZy53aW5kb3coc3RyaWN0Q2hlY2spLFxyXG4gICAgICBkZWxheTogY29uZmlnLmRlbGF5KHN0cmljdENoZWNrKSxcclxuICAgICAgdHJ1c3RQcm94eTogY29uZmlnLnRydXN0UHJveHkoc3RyaWN0Q2hlY2spLFxyXG4gICAgICBza2lwS2V5OiBjb25maWcuc2tpcEtleShmYWxzZSksXHJcbiAgICAgIHNraXBUb2tlbjogY29uZmlnLnNraXBUb2tlbihmYWxzZSlcclxuICAgIH0pXHJcbiAgICAucGFydGlhbCgpO1xyXG5cclxuLy8gU2NoZW1hIGZvciB0aGUgc2VydmVyLnNzbCBzZWN0aW9uIG9mIG9wdGlvbnNcclxuY29uc3QgU3NsU2NoZW1hID0gKHN0cmljdENoZWNrKSA9PlxyXG4gIHpcclxuICAgIC5vYmplY3Qoe1xyXG4gICAgICBlbmFibGU6IGNvbmZpZy5lbmFibGVTc2woc3RyaWN0Q2hlY2spLFxyXG4gICAgICBmb3JjZTogY29uZmlnLnNzbEZvcmNlKHN0cmljdENoZWNrKSxcclxuICAgICAgcG9ydDogY29uZmlnLnNzbFBvcnQoc3RyaWN0Q2hlY2spLFxyXG4gICAgICBjZXJ0UGF0aDogY29uZmlnLnNzbENlcnRQYXRoKGZhbHNlKVxyXG4gICAgfSlcclxuICAgIC5wYXJ0aWFsKCk7XHJcblxyXG4vLyBTY2hlbWEgZm9yIHRoZSBzZXJ2ZXIgc2VjdGlvbiBvZiBvcHRpb25zXHJcbmNvbnN0IFNlcnZlclNjaGVtYSA9IChzdHJpY3RDaGVjaykgPT5cclxuICB6Lm9iamVjdCh7XHJcbiAgICBlbmFibGU6IGNvbmZpZy5lbmFibGVTZXJ2ZXIoc3RyaWN0Q2hlY2spLm9wdGlvbmFsKCksXHJcbiAgICBob3N0OiBjb25maWcuaG9zdChzdHJpY3RDaGVjaykub3B0aW9uYWwoKSxcclxuICAgIHBvcnQ6IGNvbmZpZy5wb3J0KHN0cmljdENoZWNrKS5vcHRpb25hbCgpLFxyXG4gICAgYmVuY2htYXJraW5nOiBjb25maWcuc2VydmVyQmVuY2htYXJraW5nKHN0cmljdENoZWNrKS5vcHRpb25hbCgpLFxyXG4gICAgcHJveHk6IFByb3h5U2NoZW1hKHN0cmljdENoZWNrKS5vcHRpb25hbCgpLFxyXG4gICAgcmF0ZUxpbWl0aW5nOiBSYXRlTGltaXRpbmdTY2hlbWEoc3RyaWN0Q2hlY2spLm9wdGlvbmFsKCksXHJcbiAgICBzc2w6IFNzbFNjaGVtYShzdHJpY3RDaGVjaykub3B0aW9uYWwoKVxyXG4gIH0pO1xyXG5cclxuLy8gU2NoZW1hIGZvciB0aGUgcG9vbCBzZWN0aW9uIG9mIG9wdGlvbnNcclxuY29uc3QgUG9vbFNjaGVtYSA9IChzdHJpY3RDaGVjaykgPT5cclxuICB6XHJcbiAgICAub2JqZWN0KHtcclxuICAgICAgbWluV29ya2VyczogY29uZmlnLm1pbldvcmtlcnMoc3RyaWN0Q2hlY2spLFxyXG4gICAgICBtYXhXb3JrZXJzOiBjb25maWcubWF4V29ya2VycyhzdHJpY3RDaGVjayksXHJcbiAgICAgIHdvcmtMaW1pdDogY29uZmlnLndvcmtMaW1pdChzdHJpY3RDaGVjayksXHJcbiAgICAgIGFjcXVpcmVUaW1lb3V0OiBjb25maWcuYWNxdWlyZVRpbWVvdXQoc3RyaWN0Q2hlY2spLFxyXG4gICAgICBjcmVhdGVUaW1lb3V0OiBjb25maWcuY3JlYXRlVGltZW91dChzdHJpY3RDaGVjayksXHJcbiAgICAgIGRlc3Ryb3lUaW1lb3V0OiBjb25maWcuZGVzdHJveVRpbWVvdXQoc3RyaWN0Q2hlY2spLFxyXG4gICAgICBpZGxlVGltZW91dDogY29uZmlnLmlkbGVUaW1lb3V0KHN0cmljdENoZWNrKSxcclxuICAgICAgY3JlYXRlUmV0cnlJbnRlcnZhbDogY29uZmlnLmNyZWF0ZVJldHJ5SW50ZXJ2YWwoc3RyaWN0Q2hlY2spLFxyXG4gICAgICByZWFwZXJJbnRlcnZhbDogY29uZmlnLnJlYXBlckludGVydmFsKHN0cmljdENoZWNrKSxcclxuICAgICAgYmVuY2htYXJraW5nOiBjb25maWcucG9vbEJlbmNobWFya2luZyhzdHJpY3RDaGVjaylcclxuICAgIH0pXHJcbiAgICAucGFydGlhbCgpO1xyXG5cclxuLy8gU2NoZW1hIGZvciB0aGUgbG9nZ2luZyBzZWN0aW9uIG9mIG9wdGlvbnNcclxuY29uc3QgTG9nZ2luZ1NjaGVtYSA9IChzdHJpY3RDaGVjaykgPT5cclxuICB6XHJcbiAgICAub2JqZWN0KHtcclxuICAgICAgbGV2ZWw6IGNvbmZpZy5sb2dMZXZlbChzdHJpY3RDaGVjayksXHJcbiAgICAgIGZpbGU6IGNvbmZpZy5sb2dGaWxlKHN0cmljdENoZWNrKSxcclxuICAgICAgZGVzdDogY29uZmlnLmxvZ0Rlc3Qoc3RyaWN0Q2hlY2spLFxyXG4gICAgICB0b0NvbnNvbGU6IGNvbmZpZy5sb2dUb0NvbnNvbGUoc3RyaWN0Q2hlY2spLFxyXG4gICAgICB0b0ZpbGU6IGNvbmZpZy5sb2dUb0ZpbGUoc3RyaWN0Q2hlY2spXHJcbiAgICB9KVxyXG4gICAgLnBhcnRpYWwoKTtcclxuXHJcbi8vIFNjaGVtYSBmb3IgdGhlIHVpIHNlY3Rpb24gb2Ygb3B0aW9uc1xyXG5jb25zdCBVaVNjaGVtYSA9IChzdHJpY3RDaGVjaykgPT5cclxuICB6XHJcbiAgICAub2JqZWN0KHtcclxuICAgICAgZW5hYmxlOiBjb25maWcuZW5hYmxlVWkoc3RyaWN0Q2hlY2spLFxyXG4gICAgICByb3V0ZTogY29uZmlnLnVpUm91dGUoc3RyaWN0Q2hlY2spXHJcbiAgICB9KVxyXG4gICAgLnBhcnRpYWwoKTtcclxuXHJcbi8vIFNjaGVtYSBmb3IgdGhlIG90aGVyIHNlY3Rpb24gb2Ygb3B0aW9uc1xyXG5jb25zdCBPdGhlclNjaGVtYSA9IChzdHJpY3RDaGVjaykgPT5cclxuICB6XHJcbiAgICAub2JqZWN0KHtcclxuICAgICAgbm9kZUVudjogY29uZmlnLm5vZGVFbnYoc3RyaWN0Q2hlY2spLFxyXG4gICAgICBsaXN0ZW5Ub1Byb2Nlc3NFeGl0czogY29uZmlnLmxpc3RlblRvUHJvY2Vzc0V4aXRzKHN0cmljdENoZWNrKSxcclxuICAgICAgbm9Mb2dvOiBjb25maWcubm9Mb2dvKHN0cmljdENoZWNrKSxcclxuICAgICAgaGFyZFJlc2V0UGFnZTogY29uZmlnLmhhcmRSZXNldFBhZ2Uoc3RyaWN0Q2hlY2spLFxyXG4gICAgICBicm93c2VyU2hlbGxNb2RlOiBjb25maWcuYnJvd3NlclNoZWxsTW9kZShzdHJpY3RDaGVjaylcclxuICAgIH0pXHJcbiAgICAucGFydGlhbCgpO1xyXG5cclxuLy8gU2NoZW1hIGZvciB0aGUgZGVidWcgc2VjdGlvbiBvZiBvcHRpb25zXHJcbmNvbnN0IERlYnVnU2NoZW1hID0gKHN0cmljdENoZWNrKSA9PlxyXG4gIHpcclxuICAgIC5vYmplY3Qoe1xyXG4gICAgICBlbmFibGU6IGNvbmZpZy5lbmFibGVEZWJ1ZyhzdHJpY3RDaGVjayksXHJcbiAgICAgIGhlYWRsZXNzOiBjb25maWcuaGVhZGxlc3Moc3RyaWN0Q2hlY2spLFxyXG4gICAgICBkZXZ0b29sczogY29uZmlnLmRldnRvb2xzKHN0cmljdENoZWNrKSxcclxuICAgICAgbGlzdGVuVG9Db25zb2xlOiBjb25maWcubGlzdGVuVG9Db25zb2xlKHN0cmljdENoZWNrKSxcclxuICAgICAgZHVtcGlvOiBjb25maWcuZHVtcGlvKHN0cmljdENoZWNrKSxcclxuICAgICAgc2xvd01vOiBjb25maWcuc2xvd01vKHN0cmljdENoZWNrKSxcclxuICAgICAgZGVidWdnaW5nUG9ydDogY29uZmlnLmRlYnVnZ2luZ1BvcnQoc3RyaWN0Q2hlY2spXHJcbiAgICB9KVxyXG4gICAgLnBhcnRpYWwoKTtcclxuXHJcbi8vLy9cclxuLy8gLy8gU2NoZW1hIGZvciB0aGUgcGF5bG9hZCBzZWN0aW9uIG9mIG9wdGlvbnNcclxuLy8gY29uc3QgUGF5bG9hZFNjaGVtYSA9ICgpID0+XHJcbi8vICAgelxyXG4vLyAgICAgLm9iamVjdCh7XHJcbi8vICAgICAgIHJlcXVlc3RJZDogY29uZmlnLnJlcXVlc3RJZCgpXHJcbi8vICAgICB9KVxyXG4vLyAgICAgLnBhcnRpYWwoKTtcclxuLy8vL1xyXG5cclxuLy8gU3RyaWN0IHNjaGVtYSBmb3IgdGhlIGNvbmZpZ1xyXG5leHBvcnQgY29uc3QgU3RyaWN0Q29uZmlnU2NoZW1hID0gei5vYmplY3Qoe1xyXG4gIHB1cHBldGVlcjogUHVwcGV0ZWVyU2NoZW1hKHRydWUpLFxyXG4gIGhpZ2hjaGFydHM6IEhpZ2hjaGFydHNTY2hlbWEodHJ1ZSksXHJcbiAgZXhwb3J0OiBFeHBvcnRTY2hlbWEodHJ1ZSksXHJcbiAgY3VzdG9tTG9naWM6IEN1c3RvbUxvZ2ljU2NoZW1hKHRydWUpLFxyXG4gIHNlcnZlcjogU2VydmVyU2NoZW1hKHRydWUpLFxyXG4gIHBvb2w6IFBvb2xTY2hlbWEodHJ1ZSksXHJcbiAgbG9nZ2luZzogTG9nZ2luZ1NjaGVtYSh0cnVlKSxcclxuICB1aTogVWlTY2hlbWEodHJ1ZSksXHJcbiAgb3RoZXI6IE90aGVyU2NoZW1hKHRydWUpLFxyXG4gIGRlYnVnOiBEZWJ1Z1NjaGVtYSh0cnVlKVxyXG4gIC8vLy8gcGF5bG9hZDogUGF5bG9hZFNjaGVtYSgpXHJcbn0pO1xyXG5cclxuLy8gTG9vc2Ugc2NoZW1hIGZvciB0aGUgY29uZmlnXHJcbmV4cG9ydCBjb25zdCBMb29zZUNvbmZpZ1NjaGVtYSA9IHoub2JqZWN0KHtcclxuICBwdXBwZXRlZXI6IFB1cHBldGVlclNjaGVtYShmYWxzZSksXHJcbiAgaGlnaGNoYXJ0czogSGlnaGNoYXJ0c1NjaGVtYShmYWxzZSksXHJcbiAgZXhwb3J0OiBFeHBvcnRTY2hlbWEoZmFsc2UpLFxyXG4gIGN1c3RvbUxvZ2ljOiBDdXN0b21Mb2dpY1NjaGVtYShmYWxzZSksXHJcbiAgc2VydmVyOiBTZXJ2ZXJTY2hlbWEoZmFsc2UpLFxyXG4gIHBvb2w6IFBvb2xTY2hlbWEoZmFsc2UpLFxyXG4gIGxvZ2dpbmc6IExvZ2dpbmdTY2hlbWEoZmFsc2UpLFxyXG4gIHVpOiBVaVNjaGVtYShmYWxzZSksXHJcbiAgb3RoZXI6IE90aGVyU2NoZW1hKGZhbHNlKSxcclxuICBkZWJ1ZzogRGVidWdTY2hlbWEoZmFsc2UpXHJcbiAgLy8vLyBwYXlsb2FkOiBQYXlsb2FkU2NoZW1hKClcclxufSk7XHJcblxyXG4vLyBTY2hlbWEgZm9yIHRoZSBlbnZpcm9ubWVudCB2YXJpYWJsZXMgY29uZmlnXHJcbmV4cG9ydCBjb25zdCBFbnZTY2hlbWEgPSB6Lm9iamVjdCh7XHJcbiAgLy8gcHVwcGV0ZWVyXHJcbiAgUFVQUEVURUVSX0FSR1M6IGNvbmZpZy5hcmdzKGZhbHNlKSxcclxuXHJcbiAgLy8gaGlnaGNoYXJ0c1xyXG4gIEhJR0hDSEFSVFNfVkVSU0lPTjogY29uZmlnLnZlcnNpb24oZmFsc2UpLFxyXG4gIEhJR0hDSEFSVFNfQ0ROX1VSTDogY29uZmlnLmNkblVybChmYWxzZSksXHJcbiAgSElHSENIQVJUU19GT1JDRV9GRVRDSDogY29uZmlnLmZvcmNlRmV0Y2goZmFsc2UpLFxyXG4gIEhJR0hDSEFSVFNfQ0FDSEVfUEFUSDogY29uZmlnLmNhY2hlUGF0aChmYWxzZSksXHJcbiAgSElHSENIQVJUU19BRE1JTl9UT0tFTjogY29uZmlnLmFkbWluVG9rZW4oZmFsc2UpLFxyXG4gIEhJR0hDSEFSVFNfQ09SRV9TQ1JJUFRTOiBjb25maWcuY29yZVNjcmlwdHMoZmFsc2UpLFxyXG4gIEhJR0hDSEFSVFNfTU9EVUxFX1NDUklQVFM6IGNvbmZpZy5tb2R1bGVTY3JpcHRzKGZhbHNlKSxcclxuICBISUdIQ0hBUlRTX0lORElDQVRPUl9TQ1JJUFRTOiBjb25maWcuaW5kaWNhdG9yU2NyaXB0cyhmYWxzZSksXHJcbiAgSElHSENIQVJUU19DVVNUT01fU0NSSVBUUzogY29uZmlnLmN1c3RvbVNjcmlwdHMoZmFsc2UpLFxyXG5cclxuICAvLyBleHBvcnRcclxuICBFWFBPUlRfSU5GSUxFOiBjb25maWcuaW5maWxlKGZhbHNlKSxcclxuICBFWFBPUlRfSU5TVFI6IGNvbmZpZy5pbnN0cigpLFxyXG4gIEVYUE9SVF9PUFRJT05TOiBjb25maWcub3B0aW9ucygpLFxyXG4gIEVYUE9SVF9TVkc6IGNvbmZpZy5zdmcoKSxcclxuICBFWFBPUlRfQkFUQ0g6IGNvbmZpZy5iYXRjaChmYWxzZSksXHJcbiAgRVhQT1JUX09VVEZJTEU6IGNvbmZpZy5vdXRmaWxlKGZhbHNlKSxcclxuICBFWFBPUlRfVFlQRTogY29uZmlnLnR5cGUoZmFsc2UpLFxyXG4gIEVYUE9SVF9DT05TVFI6IGNvbmZpZy5jb25zdHIoZmFsc2UpLFxyXG4gIEVYUE9SVF9CNjQ6IGNvbmZpZy5iNjQoZmFsc2UpLFxyXG4gIEVYUE9SVF9OT19ET1dOTE9BRDogY29uZmlnLm5vRG93bmxvYWQoZmFsc2UpLFxyXG4gIEVYUE9SVF9IRUlHSFQ6IGNvbmZpZy5oZWlnaHQoZmFsc2UpLFxyXG4gIEVYUE9SVF9XSURUSDogY29uZmlnLndpZHRoKGZhbHNlKSxcclxuICBFWFBPUlRfU0NBTEU6IGNvbmZpZy5zY2FsZShmYWxzZSksXHJcbiAgRVhQT1JUX0RFRkFVTFRfSEVJR0hUOiBjb25maWcuZGVmYXVsdEhlaWdodChmYWxzZSksXHJcbiAgRVhQT1JUX0RFRkFVTFRfV0lEVEg6IGNvbmZpZy5kZWZhdWx0V2lkdGgoZmFsc2UpLFxyXG4gIEVYUE9SVF9ERUZBVUxUX1NDQUxFOiBjb25maWcuZGVmYXVsdFNjYWxlKGZhbHNlKSxcclxuICBFWFBPUlRfR0xPQkFMX09QVElPTlM6IGNvbmZpZy5nbG9iYWxPcHRpb25zKCksXHJcbiAgRVhQT1JUX1RIRU1FX09QVElPTlM6IGNvbmZpZy50aGVtZU9wdGlvbnMoKSxcclxuICBFWFBPUlRfUkFTVEVSSVpBVElPTl9USU1FT1VUOiBjb25maWcucmFzdGVyaXphdGlvblRpbWVvdXQoZmFsc2UpLFxyXG5cclxuICAvLyBjdXN0b21cclxuICBDVVNUT01fTE9HSUNfQUxMT1dfQ09ERV9FWEVDVVRJT046IGNvbmZpZy5hbGxvd0NvZGVFeGVjdXRpb24oZmFsc2UpLFxyXG4gIENVU1RPTV9MT0dJQ19BTExPV19GSUxFX1JFU09VUkNFUzogY29uZmlnLmFsbG93RmlsZVJlc291cmNlcyhmYWxzZSksXHJcbiAgQ1VTVE9NX0xPR0lDX0NVU1RPTV9DT0RFOiBjb25maWcuY3VzdG9tQ29kZShmYWxzZSksXHJcbiAgQ1VTVE9NX0xPR0lDX0NBTExCQUNLOiBjb25maWcuY2FsbGJhY2soZmFsc2UpLFxyXG4gIENVU1RPTV9MT0dJQ19SRVNPVVJDRVM6IGNvbmZpZy5yZXNvdXJjZXMoZmFsc2UpLFxyXG4gIENVU1RPTV9MT0dJQ19MT0FEX0NPTkZJRzogY29uZmlnLmxvYWRDb25maWcoZmFsc2UpLFxyXG4gIENVU1RPTV9MT0dJQ19DUkVBVEVfQ09ORklHOiBjb25maWcuY3JlYXRlQ29uZmlnKGZhbHNlKSxcclxuXHJcbiAgLy8gc2VydmVyXHJcbiAgU0VSVkVSX0VOQUJMRTogY29uZmlnLmVuYWJsZVNlcnZlcihmYWxzZSksXHJcbiAgU0VSVkVSX0hPU1Q6IGNvbmZpZy5ob3N0KGZhbHNlKSxcclxuICBTRVJWRVJfUE9SVDogY29uZmlnLnBvcnQoZmFsc2UpLFxyXG4gIFNFUlZFUl9VUExPQURfTElNSVQ6IGNvbmZpZy51cGxvYWRMaW1pdChmYWxzZSksXHJcbiAgU0VSVkVSX0JFTkNITUFSS0lORzogY29uZmlnLnNlcnZlckJlbmNobWFya2luZyhmYWxzZSksXHJcblxyXG4gIC8vIHNlcnZlciBwcm94eVxyXG4gIFNFUlZFUl9QUk9YWV9IT1NUOiBjb25maWcucHJveHlIb3N0KGZhbHNlKSxcclxuICBTRVJWRVJfUFJPWFlfUE9SVDogY29uZmlnLnByb3h5UG9ydChmYWxzZSksXHJcbiAgU0VSVkVSX1BST1hZX1RJTUVPVVQ6IGNvbmZpZy5wcm94eVRpbWVvdXQoZmFsc2UpLFxyXG5cclxuICAvLyBzZXJ2ZXIgcmF0ZSBsaW1pdGluZ1xyXG4gIFNFUlZFUl9SQVRFX0xJTUlUSU5HX0VOQUJMRTogY29uZmlnLmVuYWJsZVJhdGVMaW1pdGluZyhmYWxzZSksXHJcbiAgU0VSVkVSX1JBVEVfTElNSVRJTkdfTUFYX1JFUVVFU1RTOiBjb25maWcubWF4UmVxdWVzdHMoZmFsc2UpLFxyXG4gIFNFUlZFUl9SQVRFX0xJTUlUSU5HX1dJTkRPVzogY29uZmlnLndpbmRvdyhmYWxzZSksXHJcbiAgU0VSVkVSX1JBVEVfTElNSVRJTkdfREVMQVk6IGNvbmZpZy5kZWxheShmYWxzZSksXHJcbiAgU0VSVkVSX1JBVEVfTElNSVRJTkdfVFJVU1RfUFJPWFk6IGNvbmZpZy50cnVzdFByb3h5KGZhbHNlKSxcclxuICBTRVJWRVJfUkFURV9MSU1JVElOR19TS0lQX0tFWTogY29uZmlnLnNraXBLZXkoZmFsc2UpLFxyXG4gIFNFUlZFUl9SQVRFX0xJTUlUSU5HX1NLSVBfVE9LRU46IGNvbmZpZy5za2lwVG9rZW4oZmFsc2UpLFxyXG5cclxuICAvLyBzZXJ2ZXIgc3NsXHJcbiAgU0VSVkVSX1NTTF9FTkFCTEU6IGNvbmZpZy5lbmFibGVTc2woZmFsc2UpLFxyXG4gIFNFUlZFUl9TU0xfRk9SQ0U6IGNvbmZpZy5zc2xGb3JjZShmYWxzZSksXHJcbiAgU0VSVkVSX1NTTF9QT1JUOiBjb25maWcuc3NsUG9ydChmYWxzZSksXHJcbiAgU0VSVkVSX1NTTF9DRVJUX1BBVEg6IGNvbmZpZy5zc2xDZXJ0UGF0aChmYWxzZSksXHJcblxyXG4gIC8vIHBvb2xcclxuICBQT09MX01JTl9XT1JLRVJTOiBjb25maWcubWluV29ya2VycyhmYWxzZSksXHJcbiAgUE9PTF9NQVhfV09SS0VSUzogY29uZmlnLm1heFdvcmtlcnMoZmFsc2UpLFxyXG4gIFBPT0xfV09SS19MSU1JVDogY29uZmlnLndvcmtMaW1pdChmYWxzZSksXHJcbiAgUE9PTF9BQ1FVSVJFX1RJTUVPVVQ6IGNvbmZpZy5hY3F1aXJlVGltZW91dChmYWxzZSksXHJcbiAgUE9PTF9DUkVBVEVfVElNRU9VVDogY29uZmlnLmNyZWF0ZVRpbWVvdXQoZmFsc2UpLFxyXG4gIFBPT0xfREVTVFJPWV9USU1FT1VUOiBjb25maWcuZGVzdHJveVRpbWVvdXQoZmFsc2UpLFxyXG4gIFBPT0xfSURMRV9USU1FT1VUOiBjb25maWcuaWRsZVRpbWVvdXQoZmFsc2UpLFxyXG4gIFBPT0xfQ1JFQVRFX1JFVFJZX0lOVEVSVkFMOiBjb25maWcuY3JlYXRlUmV0cnlJbnRlcnZhbChmYWxzZSksXHJcbiAgUE9PTF9SRUFQRVJfSU5URVJWQUw6IGNvbmZpZy5yZWFwZXJJbnRlcnZhbChmYWxzZSksXHJcbiAgUE9PTF9CRU5DSE1BUktJTkc6IGNvbmZpZy5wb29sQmVuY2htYXJraW5nKGZhbHNlKSxcclxuXHJcbiAgLy8gbG9nZ2luZ1xyXG4gIExPR0dJTkdfTEVWRUw6IGNvbmZpZy5sb2dMZXZlbChmYWxzZSksXHJcbiAgTE9HR0lOR19GSUxFOiBjb25maWcubG9nRmlsZShmYWxzZSksXHJcbiAgTE9HR0lOR19ERVNUOiBjb25maWcubG9nRGVzdChmYWxzZSksXHJcbiAgTE9HR0lOR19UT19DT05TT0xFOiBjb25maWcubG9nVG9Db25zb2xlKGZhbHNlKSxcclxuICBMT0dHSU5HX1RPX0ZJTEU6IGNvbmZpZy5sb2dUb0ZpbGUoZmFsc2UpLFxyXG5cclxuICAvLyB1aVxyXG4gIFVJX0VOQUJMRTogY29uZmlnLmVuYWJsZVVpKGZhbHNlKSxcclxuICBVSV9ST1VURTogY29uZmlnLnVpUm91dGUoZmFsc2UpLFxyXG5cclxuICAvLyBvdGhlclxyXG4gIE9USEVSX05PREVfRU5WOiBjb25maWcubm9kZUVudihmYWxzZSksXHJcbiAgT1RIRVJfTElTVEVOX1RPX1BST0NFU1NfRVhJVFM6IGNvbmZpZy5saXN0ZW5Ub1Byb2Nlc3NFeGl0cyhmYWxzZSksXHJcbiAgT1RIRVJfTk9fTE9HTzogY29uZmlnLm5vTG9nbyhmYWxzZSksXHJcbiAgT1RIRVJfSEFSRF9SRVNFVF9QQUdFOiBjb25maWcuaGFyZFJlc2V0UGFnZShmYWxzZSksXHJcbiAgT1RIRVJfQlJPV1NFUl9TSEVMTF9NT0RFOiBjb25maWcuYnJvd3NlclNoZWxsTW9kZShmYWxzZSksXHJcblxyXG4gIC8vIGRlYnVnZ2VyXHJcbiAgREVCVUdfRU5BQkxFOiBjb25maWcuZW5hYmxlRGVidWcoZmFsc2UpLFxyXG4gIERFQlVHX0hFQURMRVNTOiBjb25maWcuaGVhZGxlc3MoZmFsc2UpLFxyXG4gIERFQlVHX0RFVlRPT0xTOiBjb25maWcuZGV2dG9vbHMoZmFsc2UpLFxyXG4gIERFQlVHX0xJU1RFTl9UT19DT05TT0xFOiBjb25maWcubGlzdGVuVG9Db25zb2xlKGZhbHNlKSxcclxuICBERUJVR19EVU1QSU86IGNvbmZpZy5kdW1waW8oZmFsc2UpLFxyXG4gIERFQlVHX1NMT1dfTU86IGNvbmZpZy5zbG93TW8oZmFsc2UpLFxyXG4gIERFQlVHX0RFQlVHR0lOR19QT1JUOiBjb25maWcuZGVidWdnaW5nUG9ydChmYWxzZSlcclxufSk7XHJcblxyXG4vKipcclxuICogVmFsaWRhdGVzIHRoZSBlbnZpcm9ubWVudCB2YXJpYWJsZXMgb3B0aW9ucyB1c2luZyB0aGUgRW52U2NoZW1hLlxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gcHJvY2Vzcy5lbnYgLSBUaGUgY29uZmlndXJhdGlvbiBvcHRpb25zIGZyb20gZW52aXJvbm1lbnRcclxuICogdmFyaWFibGVzIGZpbGUgdG8gdmFsaWRhdGUuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtPYmplY3R9IFRoZSBwYXJzZWQgYW5kIHZhbGlkYXRlZCBlbnZpcm9ubWVudCB2YXJpYWJsZXMuXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgZW52cyA9IEVudlNjaGVtYS5wYXJ0aWFsKCkucGFyc2UocHJvY2Vzcy5lbnYpO1xyXG5cclxuLyoqXHJcbiAqIFZhbGlkYXRlcyB0aGUgY29uZmlndXJhdGlvbiBvcHRpb25zIHVzaW5nIHRoZSBgU3RyaWN0Q29uZmlnU2NoZW1hYC5cclxuICpcclxuICogQGZ1bmN0aW9uIHN0cmljdFZhbGlkYXRlXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBjb25maWdPcHRpb25zIC0gVGhlIGNvbmZpZ3VyYXRpb24gb3B0aW9ucyB0byB2YWxpZGF0ZS5cclxuICpcclxuICogQHJldHVybnMge09iamVjdH0gVGhlIHBhcnNlZCBhbmQgdmFsaWRhdGVkIGNvbmZpZ3VyYXRpb24gb3B0aW9ucy5cclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiBzdHJpY3RWYWxpZGF0ZShjb25maWdPcHRpb25zKSB7XHJcbiAgcmV0dXJuIFN0cmljdENvbmZpZ1NjaGVtYS5wYXJ0aWFsKCkucGFyc2UoY29uZmlnT3B0aW9ucyk7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBWYWxpZGF0ZXMgdGhlIGNvbmZpZ3VyYXRpb24gb3B0aW9ucyB1c2luZyB0aGUgYExvb3NlQ29uZmlnU2NoZW1hYC5cclxuICpcclxuICogQGZ1bmN0aW9uIGxvb3NlVmFsaWRhdGVcclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IGNvbmZpZ09wdGlvbnMgLSBUaGUgY29uZmlndXJhdGlvbiBvcHRpb25zIHRvIHZhbGlkYXRlLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7T2JqZWN0fSBUaGUgcGFyc2VkIGFuZCB2YWxpZGF0ZWQgY29uZmlndXJhdGlvbiBvcHRpb25zLlxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIGxvb3NlVmFsaWRhdGUoY29uZmlnT3B0aW9ucykge1xyXG4gIHJldHVybiBMb29zZUNvbmZpZ1NjaGVtYS5wYXJ0aWFsKCkucGFyc2UoY29uZmlnT3B0aW9ucyk7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBWYWxpZGF0ZXMgYSBwcm92aWRlZCBvcHRpb24gdXNpbmcgdGhlIHNwZWNpZmljIHZhbGlkYXRvciBmcm9tIHRoZSBjb25maWdcclxuICogb2JqZWN0LlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gdmFsaWRhdGVPcHRpb25cclxuICpcclxuICogQHBhcmFtIHtzdHJpbmd9IG5hbWUgLSBUaGUgbmFtZSBvZiBhbiBvcHRpb24gdG8gdmFsaWRhdGUuXHJcbiAqIEBwYXJhbSB7YW55fSBvcHRpb24gLSBUaGUgb3B0aW9uIHRvIHZhbGlkYXRlLlxyXG4gKiBAcGFyYW0ge2Jvb2xlYW59IHN0cmljdENoZWNrIC0gRGV0ZXJtaW5lcyBpZiBzdHJpY3RlciB2YWxpZGF0aW9uIHNob3VsZFxyXG4gKiBiZSBhcHBsaWVkLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7YW55fSBUaGUgcGFyc2VkIGFuZCB2YWxpZGF0ZWQgb3B0aW9uIHZhbHVlLlxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIHZhbGlkYXRlT3B0aW9uKG5hbWUsIG9wdGlvbiwgc3RyaWN0Q2hlY2spIHtcclxuICByZXR1cm4gY29uZmlnW25hbWVdKHN0cmljdENoZWNrKS5wYXJzZShvcHRpb24pO1xyXG59XHJcblxyXG4vKipcclxuICogQ3VzdG9tIGVycm9yIG1hcHBpbmcgZnVuY3Rpb24gZm9yIFpvZCBzY2hlbWEgdmFsaWRhdGlvbi5cclxuICpcclxuICogVGhpcyBmdW5jdGlvbiBjdXN0b21pemVzIHRoZSBlcnJvciBtZXNzYWdlcyBwcm9kdWNlZCBieSBab2Qgc2NoZW1hXHJcbiAqIHZhbGlkYXRpb24sIHByb3ZpZGluZyBtb3JlIHNwZWNpZmljIGFuZCB1c2VyLWZyaWVuZGx5IGZlZWRiYWNrIGJhc2VkIG9uIHRoZVxyXG4gKiBpc3N1ZSB0eXBlIGFuZCBjb250ZXh0LlxyXG4gKlxyXG4gKiBUaGUgZnVuY3Rpb24gbW9kaWZpZXMgdGhlIGVycm9yIG1lc3NhZ2VzIGFzIGZvbGxvd3M6XHJcbiAqXHJcbiAqIC0gRm9yIG1pc3NpbmcgcmVxdWlyZWQgdmFsdWVzICh1bmRlZmluZWQpLCBpdCByZXR1cm5zIGEgbWVzc2FnZSBpbmRpY2F0aW5nXHJcbiAqIHRoYXQgbm8gdmFsdWUgd2FzIHByb3ZpZGVkIGZvciB0aGUgc3BlY2lmaWMgcHJvcGVydHkuXHJcbiAqXHJcbiAqIC0gRm9yIGN1c3RvbSB2YWxpZGF0aW9uIGVycm9ycywgaWYgYSBjdXN0b20gZXJyb3IgbWVzc2FnZSBpcyBwcm92aWRlZCBpbiB0aGVcclxuICogaXNzdWUgcGFyYW1ldGVycywgaXQgaW5jbHVkZXMgdGhpcyBtZXNzYWdlIGFsb25nIHdpdGggdGhlIGludmFsaWQgZGF0YVxyXG4gKiByZWNlaXZlZC5cclxuICpcclxuICogLSBGb3IgYWxsIG90aGVyIGVycm9ycywgaXQgYXBwZW5kcyBwcm9wZXJ0eS1zcGVjaWZpYyBpbmZvcm1hdGlvbiB0byB0aGVcclxuICogZGVmYXVsdCBlcnJvciBtZXNzYWdlIHByb3ZpZGVkIGJ5IFpvZC5cclxuICpcclxuICogQGZ1bmN0aW9uIF9jdXN0b21FcnJvck1hcFxyXG4gKlxyXG4gKiBAcGFyYW0ge3ouWm9kSXNzdWV9IGlzc3VlIC0gVGhlIGlzc3VlIG9iamVjdCByZXByZXNlbnRpbmcgdGhlIHZhbGlkYXRpb25cclxuICogZXJyb3IuXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBjb250ZXh0IC0gVGhlIGNvbnRleHQgb2JqZWN0IHByb3ZpZGluZyBhZGRpdGlvbmFsIGluZm9ybWF0aW9uXHJcbiAqIGFib3V0IHRoZSB2YWxpZGF0aW9uIGVycm9yLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7T2JqZWN0fSBBbiBvYmplY3QgY29udGFpbmluZyB0aGUgY3VzdG9taXplZCBlcnJvciBtZXNzYWdlLlxyXG4gKi9cclxuZnVuY3Rpb24gX2N1c3RvbUVycm9yTWFwKGlzc3VlLCBjb250ZXh0KSB7XHJcbiAgLy8gR2V0IHRoZSBjaGFpbiBvZiBwcm9wZXJ0aWVzIHdoaWNoIGVycm9yIGRpcmVjdGx5IHJlZmVycyB0b1xyXG4gIGNvbnN0IHByb3BlcnR5TmFtZSA9IGlzc3VlLnBhdGguam9pbignLicpO1xyXG5cclxuICAvLyBDcmVhdGUgdGhlIGZpcnN0IHBhcnQgb2YgdGhlIG1lc3NhZ2UgYWJvdXQgdGhlIHByb3BlcnR5IGluZm9ybWF0aW9uXHJcbiAgY29uc3QgcHJvcGVydHlJbmZvID0gYEludmFsaWQgdmFsdWUgZm9yIHRoZSAke3Byb3BlcnR5TmFtZX1gO1xyXG5cclxuICAvLyBNb2RpZmllZCBtZXNzYWdlIGZvciB0aGUgaW52YWxpZCB0eXBlXHJcbiAgaWYgKGlzc3VlLmNvZGUgPT09IHouWm9kSXNzdWVDb2RlLmludmFsaWRfdHlwZSkge1xyXG4gICAgLy8gTW9kaWZpZWQgbWVzc2FnZSBmb3IgdGhlIHJlcXVpcmVkIHZhbHVlc1xyXG4gICAgaWYgKGlzc3VlLnJlY2VpdmVkID09PSB6LlpvZFBhcnNlZFR5cGUudW5kZWZpbmVkKSB7XHJcbiAgICAgIHJldHVybiB7XHJcbiAgICAgICAgbWVzc2FnZTogYCR7cHJvcGVydHlJbmZvfSAtIE5vIHZhbHVlIHdhcyBwcm92aWRlZC5gXHJcbiAgICAgIH07XHJcbiAgICB9XHJcblxyXG4gICAgLy8gTW9kaWZpZWQgbWVzc2FnZSBmb3IgdGhlIHNwZWNpZmljIGludmFsaWQgdHlwZSB3aGVuIHZhbHVlcyBleGlzdFxyXG4gICAgcmV0dXJuIHtcclxuICAgICAgbWVzc2FnZTogYCR7cHJvcGVydHlJbmZvfSAtIEludmFsaWQgdHlwZS4gJHtjb250ZXh0LmRlZmF1bHRFcnJvcn0uYFxyXG4gICAgfTtcclxuICB9XHJcblxyXG4gIC8vIE1vZGlmaWVkIG1lc3NhZ2UgZm9yIHRoZSBjdXN0b20gdmFsaWRhdGlvblxyXG4gIGlmIChpc3N1ZS5jb2RlID09PSB6LlpvZElzc3VlQ29kZS5jdXN0b20pIHtcclxuICAgIC8vIElmIHRoZSBjdXN0b20gbWVzc2FnZSBmb3IgZXJyb3IgZXhpc3QsIGluY2x1ZGUgaXRcclxuICAgIGlmIChpc3N1ZS5wYXJhbXM/LmVycm9yTWVzc2FnZSkge1xyXG4gICAgICByZXR1cm4ge1xyXG4gICAgICAgIG1lc3NhZ2U6IGAke3Byb3BlcnR5SW5mb30gLSAke2lzc3VlLnBhcmFtcz8uZXJyb3JNZXNzYWdlfSwgcmVjZWl2ZWQgJyR7Y29udGV4dC5kYXRhfScuYFxyXG4gICAgICB9O1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgLy8gTW9kaWZpZWQgbWVzc2FnZSBmb3IgdGhlIGludmFsaWQgdW5pb24gZXJyb3JcclxuICBpZiAoaXNzdWUuY29kZSA9PT0gei5ab2RJc3N1ZUNvZGUuaW52YWxpZF91bmlvbikge1xyXG4gICAgLy8gQ3JlYXRlIHRoZSBmaXJzdCBwYXJ0IG9mIHRoZSBtZXNzYWdlIGFib3V0IHRoZSBtdWx0aXBsZSBlcnJvcnNcclxuICAgIGxldCBtZXNzYWdlID0gYE11bHRpcGxlIGVycm9ycyBvY2N1cnJlZCBmb3IgdGhlICR7cHJvcGVydHlOYW1lfTpcXG5gO1xyXG5cclxuICAgIC8vIEN5Y2xlIHRocm91Z2ggYWxsIGVycm9ycyBhbmQgY3JlYXRlIGEgY29ycmVjdCBtZXNzYWdlXHJcbiAgICBpc3N1ZS51bmlvbkVycm9ycy5mb3JFYWNoKCh2YWx1ZSkgPT4ge1xyXG4gICAgICBjb25zdCBpbmRleCA9IHZhbHVlLmlzc3Vlc1swXS5tZXNzYWdlLmluZGV4T2YoJy0nKTtcclxuICAgICAgbWVzc2FnZSArPVxyXG4gICAgICAgIGluZGV4ICE9PSAtMVxyXG4gICAgICAgICAgPyBgJHt2YWx1ZS5pc3N1ZXNbMF0ubWVzc2FnZX1cXG5gLnN1YnN0cmluZyhpbmRleClcclxuICAgICAgICAgIDogYCR7dmFsdWUuaXNzdWVzWzBdLm1lc3NhZ2V9XFxuYDtcclxuICAgIH0pO1xyXG5cclxuICAgIC8vIFJldHVybiB0aGUgZmluYWwgbWVzc2FnZSBmb3IgdGhlIGludmFsaWQgdW5pb24gZXJyb3JcclxuICAgIHJldHVybiB7XHJcbiAgICAgIG1lc3NhZ2VcclxuICAgIH07XHJcbiAgfVxyXG5cclxuICAvLyBSZXR1cm4gdGhlIGRlZmF1bHQgZXJyb3IgbWVzc2FnZSwgZXh0ZW5kZWQgYnkgdGhlIGluZm8gYWJvdXQgdGhlIHByb3BlcnR5XHJcbiAgcmV0dXJuIHtcclxuICAgIG1lc3NhZ2U6IGAke3Byb3BlcnR5SW5mb30gLSAke2NvbnRleHQuZGVmYXVsdEVycm9yfS5gXHJcbiAgfTtcclxufVxyXG5cclxuZXhwb3J0IGRlZmF1bHQge1xyXG4gIFN0cmljdENvbmZpZ1NjaGVtYSxcclxuICBMb29zZUNvbmZpZ1NjaGVtYSxcclxuICBFbnZTY2hlbWEsXHJcbiAgZW52cyxcclxuICBzdHJpY3RWYWxpZGF0ZSxcclxuICBsb29zZVZhbGlkYXRlLFxyXG4gIHZhbGlkYXRlT3B0aW9uXHJcbn07XHJcbiIsIi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXHJcblxyXG5IaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXJcclxuXHJcbkNvcHlyaWdodCAoYykgMjAxNi0yMDI1LCBIaWdoc29mdFxyXG5cclxuTGljZW5jZWQgdW5kZXIgdGhlIE1JVCBsaWNlbmNlLlxyXG5cclxuQWRkaXRpb25hbGx5IGEgdmFsaWQgSGlnaGNoYXJ0cyBsaWNlbnNlIGlzIHJlcXVpcmVkIGZvciB1c2UuXHJcblxyXG5TZWUgTElDRU5TRSBmaWxlIGluIHJvb3QgZm9yIGRldGFpbHMuXHJcblxyXG4qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xyXG5cclxuLyoqXHJcbiAqIEBvdmVydmlldyBNYW5hZ2VzIGNvbmZpZ3VyYXRpb24gZm9yIHRoZSBIaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXIgYnkgbG9hZGluZ1xyXG4gKiBhbmQgbWVyZ2luZyBvcHRpb25zIGZyb20gbXVsdGlwbGUgc291cmNlcywgc3VjaCBhcyBkZWZhdWx0IHNldHRpbmdzLFxyXG4gKiBlbnZpcm9ubWVudCB2YXJpYWJsZXMsIHVzZXItcHJvdmlkZWQgb3B0aW9ucywgYW5kIGNvbW1hbmQtbGluZSBhcmd1bWVudHMuXHJcbiAqIEVuc3VyZXMgdGhlIGdsb2JhbCBvcHRpb25zIGFyZSB1cC10by1kYXRlIHdpdGggdGhlIGhpZ2hlc3QgcHJpb3JpdHkgdmFsdWVzLlxyXG4gKiBQcm92aWRlcyBmdW5jdGlvbnMgZm9yIGFjY2Vzc2luZyBhbmQgdXBkYXRpbmcgY29uZmlndXJhdGlvbi5cclxuICovXHJcblxyXG5pbXBvcnQgeyByZWFkRmlsZVN5bmMgfSBmcm9tICdmcyc7XHJcbmltcG9ydCB7IGpvaW4gfSBmcm9tICdwYXRoJztcclxuXHJcbmltcG9ydCB7IGxvZywgbG9nV2l0aFN0YWNrLCBsb2dab2RJc3N1ZXMgfSBmcm9tICcuL2xvZ2dlci5qcyc7XHJcbmltcG9ydCB7IF9fZGlybmFtZSwgaXNPYmplY3QsIGRlZXBDb3B5LCBnZXRBYnNvbHV0ZVBhdGggfSBmcm9tICcuL3V0aWxzLmpzJztcclxuaW1wb3J0IHsgZW52cywgbG9vc2VWYWxpZGF0ZSwgc3RyaWN0VmFsaWRhdGUgfSBmcm9tICcuL3ZhbGlkYXRpb24uanMnO1xyXG5pbXBvcnQgeyBkZWZhdWx0Q29uZmlnLCBuZXN0ZWRQcm9wcywgYWJzb2x1dGVQcm9wcyB9IGZyb20gJy4vc2NoZW1hcy9jb25maWcuanMnO1xyXG5cclxuLy8gU2V0cyB0aGUgZ2xvYmFsIG9wdGlvbnMgd2l0aCBpbml0aWFsIHZhbHVlcyBmcm9tIHRoZSBkZWZhdWx0IGNvbmZpZ1xyXG5jb25zdCBnbG9iYWxPcHRpb25zID0gX2luaXRHbG9iYWxPcHRpb25zKGRlZmF1bHRDb25maWcpO1xyXG5cclxuLy8gQW4gb2JqZWN0IGZvciB0aGUgaW5zdGFuY2Ugb3B0aW9ucywgY3JlYXRlZCBlYWNoIHRpbWUgdGhlIGBpbml0RXhwb3J0YCBvY2N1cnNcclxuY29uc3QgaW5zdGFuY2VPcHRpb25zID0gZGVlcENvcHkoZ2xvYmFsT3B0aW9ucyk7XHJcblxyXG4vKipcclxuICogUmV0cmlldmVzIGEgcmVmZXJlbmNlIHRvIHRoZSBvcHRpb25zIG9iamVjdC4gRGVwZW5kaW5nIG9uIHRoZSBgZ2V0SW5zdGFuY2VgXHJcbiAqIHBhcmFtZXRlciwgaXQgcmV0dXJucyBlaXRoZXIgdGhlIGdsb2JhbCBvcHRpb25zIG9yIHRoZSBpbnN0YW5jZS1zcGVjaWZpY1xyXG4gKiBvcHRpb25zIG9iamVjdC5cclxuICpcclxuICogQGZ1bmN0aW9uIGdldE9wdGlvbnNcclxuICpcclxuICogQHBhcmFtIHtib29sZWFufSBbZ2V0SW5zdGFuY2U9dHJ1ZV0gLSBPcHRpb25hbCBwYXJhbWV0ZXIgdGhhdCBkZWNpZGVzIHdoZXRoZXJcclxuICogdG8gcmV0dXJuIHRoZSBpbnN0YW5jZS1zcGVjaWZpYyBvcHRpb25zICh3aGVuIGB0cnVlYCkgb3IgdGhlIGdsb2JhbCBvcHRpb25zXHJcbiAqICh3aGVuIGBmYWxzZWApLiBUaGUgZGVmYXVsdCB2YWx1ZSBpcyBgdHJ1ZWAuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtPYmplY3R9IEEgcmVmZXJlbmNlIHRvIGVpdGhlciB0aGUgZ2xvYmFsIG9wdGlvbnNcclxuICogb3IgdGhlIGluc3RhbmNlLXNwZWNpZmljIG9wdGlvbnMsIGJhc2VkIG9uIHRoZSBgZ2V0SW5zdGFuY2VgIHBhcmFtZXRlci5cclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiBnZXRPcHRpb25zKGdldEluc3RhbmNlID0gdHJ1ZSkge1xyXG4gIHJldHVybiBnZXRJbnN0YW5jZSA/IGluc3RhbmNlT3B0aW9ucyA6IGdsb2JhbE9wdGlvbnM7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBTZXRzIHRoZSBnbG9iYWwgb3B0aW9ucyBvZiB0aGUgZXhwb3J0IHNlcnZlciwga2VlcGluZyB0aGUgcHJpbmNpcGxlXHJcbiAqIG9mIHRoZSBvcHRpb25zIGxvYWQgcHJpb3JpdHkgZnJvbSBhbGwgYXZhaWxhYmxlIHNvdXJjZXMuIEl0IGFjY2VwdHMgb3B0aW9uYWxcclxuICogYGN1c3RvbU9wdGlvbnNgIG9iamVjdCBhbmQgYGNsaUFyZ3NgIGFycmF5IHdpdGggYXJndW1lbnRzIGZyb20gdGhlIENMSS4gVGhlc2VcclxuICogb3B0aW9ucyB3aWxsIGJlIHZhbGlkYXRlZCBhbmQgYXBwbGllZCBpZiBwcm92aWRlZC5cclxuICpcclxuICogVGhlIHByaW9yaXR5IG9yZGVyIG9mIHNldHRpbmcgdmFsdWVzIGlzOlxyXG4gKlxyXG4gKiAxLiBPcHRpb25zIGZyb20gdGhlIGBsaWIvc2NoZW1hcy9jb25maWcuanNgIGZpbGUgKGRlZmF1bHQgdmFsdWVzKS5cclxuICogMi4gT3B0aW9ucyBmcm9tIGEgY3VzdG9tIEpTT04gZmlsZSAobG9hZGVkIGJ5IHRoZSBgbG9hZENvbmZpZ2Agb3B0aW9uKS5cclxuICogMy4gT3B0aW9ucyBmcm9tIHRoZSBlbnZpcm9ubWVudCB2YXJpYWJsZXMgKHRoZSBgLmVudmAgZmlsZSkuXHJcbiAqIDQuIE9wdGlvbnMgZnJvbSB0aGUgY29tbWFuZCBsaW5lIGludGVyZmFjZSAoQ0xJKS5cclxuICogNS4gT3B0aW9ucyBmcm9tIHRoZSBmaXJzdCBwYXJhbWV0ZXIgKHRoZSBgY3VzdG9tT3B0aW9uc2AgaXMgYnkgZGVmYXVsdFxyXG4gKiBhbiBlbXB0eSBvYmplY3QpLlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gc2V0R2xvYmFsT3B0aW9uc1xyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gW2N1c3RvbU9wdGlvbnM9e31dIC0gT3B0aW9uYWwgY3VzdG9tIG9wdGlvbnMgZm9yIGFkZGl0aW9uYWxcclxuICogY29uZmlndXJhdGlvbi4gVGhlIGRlZmF1bHQgdmFsdWUgaXMgYW4gZW1wdHkgb2JqZWN0LlxyXG4gKiBAcGFyYW0ge0FycmF5LjxzdHJpbmc+fSBbY2xpQXJncz1bXV0gLSBPcHRpb25hbCBjb21tYW5kIGxpbmUgYXJndW1lbnRzXHJcbiAqIGZvciBhZGRpdGlvbmFsIGNvbmZpZ3VyYXRpb24uIFRoZSBkZWZhdWx0IHZhbHVlIGlzIGFuIGVtcHR5IGFycmF5LlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7T2JqZWN0fSBUaGUgdXBkYXRlZCBnbG9iYWwgb3B0aW9ucyBvYmplY3QsIHJlZmxlY3RpbmcgdGhlIG1lcmdlZFxyXG4gKiBjb25maWd1cmF0aW9uIGZyb20gYWxsIGF2YWlsYWJsZSBzb3VyY2VzLlxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIHNldEdsb2JhbE9wdGlvbnMoY3VzdG9tT3B0aW9ucyA9IHt9LCBjbGlBcmdzID0gW10pIHtcclxuICAvLyBPYmplY3QgZm9yIG9wdGlvbnMgbG9hZGVkIHZpYSB0aGUgYGxvYWRDb25maWdgIG9wdGlvblxyXG4gIGxldCBjb25maWdPcHRpb25zID0ge307XHJcblxyXG4gIC8vIE9iamVjdCBmb3Igb3B0aW9ucyBmcm9tIHRoZSBDTElcclxuICBsZXQgY2xpT3B0aW9ucyA9IHt9O1xyXG5cclxuICAvLyBPbmx5IGZvciB0aGUgQ0xJIHVzYWdlXHJcbiAgaWYgKGNsaUFyZ3MubGVuZ3RoKSB7XHJcbiAgICB0cnkge1xyXG4gICAgICAvLyBWYWxpZGF0ZSBvcHRpb25zIGZyb20gdGhlIGN1c3RvbSBKU09OIGxvYWRlZCB2aWEgdGhlIGBsb2FkQ29uZmlnYFxyXG4gICAgICBjb25maWdPcHRpb25zID0gc3RyaWN0VmFsaWRhdGUoX2xvYWRDb25maWdGaWxlKGNsaUFyZ3MpKTtcclxuICAgIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICAgIGxvZ1pvZElzc3VlcyhcclxuICAgICAgICAxLFxyXG4gICAgICAgIGVycm9yLmlzc3VlcyxcclxuICAgICAgICAnW2NvbmZpZ10gQ3VzdG9tIEpTT04gb3B0aW9ucyB2YWxpZGF0aW9uIGVycm9yJ1xyXG4gICAgICApO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgLy8gQXBwbHkgY3VzdG9tIG9wdGlvbnMgaWYgdGhlcmUgYXJlIGFueVxyXG4gIGlmIChjdXN0b21PcHRpb25zICYmIE9iamVjdC5rZXlzKGN1c3RvbU9wdGlvbnMpLmxlbmd0aCAhPT0gMCkge1xyXG4gICAgdHJ5IHtcclxuICAgICAgLy8gVmFsaWRhdGUgY3VzdG9tIG9wdGlvbnMgcHJvdmlkZWQgYnkgdGhlIHVzZXJcclxuICAgICAgY3VzdG9tT3B0aW9ucyA9IHN0cmljdFZhbGlkYXRlKGN1c3RvbU9wdGlvbnMpO1xyXG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICAgbG9nWm9kSXNzdWVzKDEsIGVycm9yLmlzc3VlcywgJ1tjb25maWddIEN1c3RvbSBvcHRpb25zIHZhbGlkYXRpb24gZXJyb3InKTtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIC8vIE9ubHkgZm9yIHRoZSBDTEkgdXNhZ2VcclxuICBpZiAoY2xpQXJncy5sZW5ndGgpIHtcclxuICAgIHRyeSB7XHJcbiAgICAgIC8vIFZhbGlkYXRlIG9wdGlvbnMgZnJvbSB0aGUgQ0xJXHJcbiAgICAgIGNsaU9wdGlvbnMgPSBsb29zZVZhbGlkYXRlKF9wYWlyQXJndW1lbnRWYWx1ZShuZXN0ZWRQcm9wcywgY2xpQXJncykpO1xyXG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICAgbG9nWm9kSXNzdWVzKDEsIGVycm9yLmlzc3VlcywgJ1tjb25maWddIENMSSBvcHRpb25zIHZhbGlkYXRpb24gZXJyb3InKTtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIC8vIFVwZGF0ZSB2YWx1ZXMgb2YgdGhlIGdsb2JhbCBvcHRpb25zIHdpdGggdmFsdWVzIGZyb20gZWFjaCBzb3VyY2UgcG9zc2libGVcclxuICBfdXBkYXRlR2xvYmFsT3B0aW9ucyhcclxuICAgIGRlZmF1bHRDb25maWcsXHJcbiAgICBnbG9iYWxPcHRpb25zLFxyXG4gICAgY29uZmlnT3B0aW9ucyxcclxuICAgIGNsaU9wdGlvbnMsXHJcbiAgICBjdXN0b21PcHRpb25zXHJcbiAgKTtcclxuXHJcbiAgLy8gUmV0dXJuIHVwZGF0ZWQgZ2xvYmFsIG9wdGlvbnNcclxuICByZXR1cm4gZ2xvYmFsT3B0aW9ucztcclxufVxyXG5cclxuLyoqXHJcbiAqIFVwZGF0ZXMgdGhlIGluc3RhbmNlIG9wdGlvbnMgd2l0aCBhZGRpdGlvbmFsIG9wdGlvbnMuIEl0IG9wdGlvbmFsbHkgYWxsb3dzXHJcbiAqIHRvIHJlaW5pdGlhbGl6ZSB0aGUgaW5zdGFuY2Ugb3B0aW9ucyB3aXRoIHRoZSB2YWx1ZXMgb2YgYSBjdXJyZW50IGdsb2JhbFxyXG4gKiBvcHRpb25zIG9iamVjdC5cclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IHVwZGF0ZU9wdGlvbnMgLSBUaGUgdXBkYXRlIG9wdGlvbnMgdG8gbWVyZ2UgaW50byB0aGUgaW5zdGFuY2VcclxuICogb3B0aW9ucy5cclxuICogQHBhcmFtIHtib29sZWFufSBbbmV3SW5zdGFuY2U9ZmFsc2VdIC0gQSBmbGFnIHRvIGluZGljYXRlIHdoZXRoZXIgdG8gaW5pdFxyXG4gKiBvcHRpb25zIGZvciBhIG5ldyBpbnN0YW5jZS4gSWYgYHRydWVgLCB0aGUgZXhpc3RpbmcgaW5zdGFuY2Ugb3B0aW9ucyB3aWxsXHJcbiAqIGJlIGNsZWFyZWQgYW5kIHJlaW5pdGlhbGl6ZWQgYmFzZWQgb24gdGhlIGdsb2JhbCBvcHRpb25zLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7T2JqZWN0fSAtIFRoZSB1cGRhdGVkIGluc3RhbmNlIG9wdGlvbnMuXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gdXBkYXRlT3B0aW9ucyh1cGRhdGVPcHRpb25zLCBuZXdJbnN0YW5jZSA9IGZhbHNlKSB7XHJcbiAgLy8gQ2hlY2sgaWYgb3B0aW9ucyBuZWVkIHRvIGJlIGNyZWF0ZWQgZm9yIGEgbmV3IGluc3RhbmNlXHJcbiAgaWYgKG5ld0luc3RhbmNlKSB7XHJcbiAgICAvLyBHZXQgcmlkIG9mIHRoZSBvbGQgaW5zdGFuY2Ugb3B0aW9uc1xyXG4gICAgT2JqZWN0LmtleXMoaW5zdGFuY2VPcHRpb25zKS5mb3JFYWNoKChrZXkpID0+IHtcclxuICAgICAgZGVsZXRlIGluc3RhbmNlT3B0aW9uc1trZXldO1xyXG4gICAgfSk7XHJcblxyXG4gICAgLy8gSW5pdCB0aGUgbmV3IGluc3RhbmNlIG9wdGlvbnMgYmFzZWQgb24gdGhlIGdsb2JhbCBvcHRpb25zXHJcbiAgICBtZXJnZU9wdGlvbnMoaW5zdGFuY2VPcHRpb25zLCBkZWVwQ29weShnbG9iYWxPcHRpb25zKSk7XHJcbiAgfVxyXG5cclxuICAvLyBNZXJnZSBhZGRpdGlvbmFsIG9wdGlvbnMgdG8gdGhlIGluc3RhbmNlIG9wdGlvbnNcclxuICBtZXJnZU9wdGlvbnMoaW5zdGFuY2VPcHRpb25zLCB1cGRhdGVPcHRpb25zKTtcclxuXHJcbiAgLy8gUmV0dXJuIHRoZSByZWZlcmVuY2UgdG8gdGhlIGluc3RhbmNlIG9wdGlvbnMgb2JqZWN0XHJcbiAgcmV0dXJuIGluc3RhbmNlT3B0aW9ucztcclxufVxyXG5cclxuLyoqXHJcbiAqIE1lcmdlcyB0d28gc2V0cyBvZiBjb25maWd1cmF0aW9uIG9wdGlvbnMsIGNvbnNpZGVyaW5nIGFic29sdXRlIHByb3BlcnRpZXMuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBtZXJnZU9wdGlvbnNcclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IG9yaWdpbmFsT3B0aW9ucyAtIE9yaWdpbmFsIGNvbmZpZ3VyYXRpb24gb3B0aW9ucy5cclxuICogQHBhcmFtIHtPYmplY3R9IG5ld09wdGlvbnMgLSBOZXcgY29uZmlndXJhdGlvbiBvcHRpb25zIHRvIGJlIG1lcmdlZC5cclxuICpcclxuICogQHJldHVybnMge09iamVjdH0gTWVyZ2VkIGNvbmZpZ3VyYXRpb24gb3B0aW9ucy5cclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiBtZXJnZU9wdGlvbnMob3JpZ2luYWxPcHRpb25zLCBuZXdPcHRpb25zKSB7XHJcbiAgLy8gQ2hlY2sgaWYgdGhlIGBvcmlnaW5hbE9wdGlvbnNgIGFuZCBgbmV3T3B0aW9uc2AgYXJlIGNvcnJlY3Qgb2JqZWN0c1xyXG4gIGlmIChpc09iamVjdChvcmlnaW5hbE9wdGlvbnMpICYmIGlzT2JqZWN0KG5ld09wdGlvbnMpKSB7XHJcbiAgICBmb3IgKGNvbnN0IFtrZXksIHZhbHVlXSBvZiBPYmplY3QuZW50cmllcyhuZXdPcHRpb25zKSkge1xyXG4gICAgICBvcmlnaW5hbE9wdGlvbnNba2V5XSA9XHJcbiAgICAgICAgaXNPYmplY3QodmFsdWUpICYmXHJcbiAgICAgICAgIWFic29sdXRlUHJvcHMuaW5jbHVkZXMoa2V5KSAmJlxyXG4gICAgICAgIG9yaWdpbmFsT3B0aW9uc1trZXldICE9PSB1bmRlZmluZWRcclxuICAgICAgICAgID8gbWVyZ2VPcHRpb25zKG9yaWdpbmFsT3B0aW9uc1trZXldLCB2YWx1ZSlcclxuICAgICAgICAgIDogdmFsdWUgIT09IHVuZGVmaW5lZFxyXG4gICAgICAgICAgICA/IHZhbHVlXHJcbiAgICAgICAgICAgIDogb3JpZ2luYWxPcHRpb25zW2tleV0gfHwgbnVsbDtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIC8vIFJldHVybiB0aGUgb3JpZ2luYWwgKG1vZGlmaWVkIG9yIG5vdCkgb3B0aW9uc1xyXG4gIHJldHVybiBvcmlnaW5hbE9wdGlvbnM7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBNYXBzIG9sZC1zdHJ1Y3R1cmVkIGNvbmZpZ3VyYXRpb24gb3B0aW9ucyAoUGhhbnRvbUpTKSB0byBhIG5ldyBmb3JtYXRcclxuICogKFB1cHBldGVlcikuIFRoaXMgZnVuY3Rpb24gY29udmVydHMgZmxhdCwgb2xkLXN0cnVjdHVyZWQgb3B0aW9ucyBpbnRvXHJcbiAqIGEgbmV3LCBuZXN0ZWQgY29uZmlndXJhdGlvbiBmb3JtYXQgYmFzZWQgb24gYSBwcmVkZWZpbmVkIG1hcHBpbmdcclxuICogKGBuZXN0ZWRQcm9wc2ApLiBUaGUgbmV3IGZvcm1hdCBpcyB1c2VkIGZvciBQdXBwZXRlZXIsIHdoaWxlIHRoZSBvbGQgZm9ybWF0XHJcbiAqIHdhcyB1c2VkIGZvciBQaGFudG9tSlMuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBtYXBUb05ld09wdGlvbnNcclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IG9sZE9wdGlvbnMgLSBUaGUgb2xkLCBmbGF0IGNvbmZpZ3VyYXRpb24gb3B0aW9uc1xyXG4gKiB0byBiZSBjb252ZXJ0ZWQuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtPYmplY3R9IEEgbmV3IG9iamVjdCBjb250YWluaW5nIG9wdGlvbnMgc3RydWN0dXJlZCBhY2NvcmRpbmdcclxuICogdG8gdGhlIG1hcHBpbmcgZGVmaW5lZCBpbiBgbmVzdGVkUHJvcHNgIG9yIGFuIGVtcHR5IG9iamVjdCBpZiB0aGUgcHJvdmlkZWRcclxuICogYG9sZE9wdGlvbnNgIGlzIG5vdCBhIGNvcnJlY3Qgb2JqZWN0LlxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIG1hcFRvTmV3T3B0aW9ucyhvbGRPcHRpb25zKSB7XHJcbiAgLy8gQW4gb2JqZWN0IGZvciB0aGUgbmV3IHN0cnVjdHVyZWQgb3B0aW9uc1xyXG4gIGNvbnN0IG5ld09wdGlvbnMgPSB7fTtcclxuXHJcbiAgLy8gQ2hlY2sgaWYgcHJvdmlkZWQgdmFsdWUgaXMgYSBjb3JyZWN0IG9iamVjdFxyXG4gIGlmIChpc09iamVjdChvbGRPcHRpb25zKSkge1xyXG4gICAgLy8gSXRlcmF0ZSBvdmVyIGVhY2gga2V5LXZhbHVlIHBhaXIgaW4gdGhlIG9sZC1zdHJ1Y3R1cmVkIG9wdGlvbnNcclxuICAgIGZvciAoY29uc3QgW2tleSwgdmFsdWVdIG9mIE9iamVjdC5lbnRyaWVzKG9sZE9wdGlvbnMpKSB7XHJcbiAgICAgIC8vIElmIHRoZXJlIGlzIGEgbmVzdGVkIG1hcHBpbmcsIHNwbGl0IGl0IGludG8gYSBwcm9wZXJ0aWVzIGNoYWluXHJcbiAgICAgIGNvbnN0IHByb3BlcnRpZXNDaGFpbiA9IG5lc3RlZFByb3BzW2tleV1cclxuICAgICAgICA/IG5lc3RlZFByb3BzW2tleV0uc3BsaXQoJy4nKVxyXG4gICAgICAgIDogW107XHJcblxyXG4gICAgICAvLyBJZiBpdCBpcyB0aGUgbGFzdCBwcm9wZXJ0eSBpbiB0aGUgY2hhaW4sIGFzc2lnbiB0aGUgdmFsdWUsIG90aGVyd2lzZSxcclxuICAgICAgLy8gY3JlYXRlIG9yIHJldXNlIHRoZSBuZXN0ZWQgb2JqZWN0XHJcbiAgICAgIHByb3BlcnRpZXNDaGFpbi5yZWR1Y2UoXHJcbiAgICAgICAgKG9iaiwgcHJvcCwgaW5kZXgpID0+XHJcbiAgICAgICAgICAob2JqW3Byb3BdID1cclxuICAgICAgICAgICAgcHJvcGVydGllc0NoYWluLmxlbmd0aCAtIDEgPT09IGluZGV4ID8gdmFsdWUgOiBvYmpbcHJvcF0gfHwge30pLFxyXG4gICAgICAgIG5ld09wdGlvbnNcclxuICAgICAgKTtcclxuICAgIH1cclxuICB9IGVsc2Uge1xyXG4gICAgbG9nKFxyXG4gICAgICAyLFxyXG4gICAgICAnW2NvbmZpZ10gTm8gY29ycmVjdCBvYmplY3Qgd2l0aCBvcHRpb25zIHdhcyBwcm92aWRlZC4gUmV0dXJuaW5nIGFuIGVtcHR5IGFycmF5LidcclxuICAgICk7XHJcbiAgfVxyXG5cclxuICAvLyBSZXR1cm4gdGhlIG5ldywgc3RydWN0dXJlZCBvcHRpb25zIG9iamVjdFxyXG4gIHJldHVybiBuZXdPcHRpb25zO1xyXG59XHJcblxyXG4vKipcclxuICogVmFsaWRhdGVzLCBwYXJzZXMsIGFuZCBjaGVja3MgaWYgdGhlIHByb3ZpZGVkIGNvbmZpZyBpcyBhbGxvd2VkIHNldFxyXG4gKiBvZiBvcHRpb25zLlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gaXNBbGxvd2VkQ29uZmlnXHJcbiAqXHJcbiAqIEBwYXJhbSB7dW5rbm93bn0gY29uZmlnIC0gVGhlIGNvbmZpZyB0byBiZSB2YWxpZGF0ZWQgYW5kIHBhcnNlZCBhcyBhIHNldFxyXG4gKiBvZiBvcHRpb25zLiBNdXN0IGJlIGVpdGhlciBhbiBvYmplY3Qgb3IgYSBzdHJpbmcuXHJcbiAqIEBwYXJhbSB7Ym9vbGVhbn0gW3RvU3RyaW5nPWZhbHNlXSAtIFdoZXRoZXIgdG8gcmV0dXJuIGEgc3RyaW5naWZpZWQgdmVyc2lvblxyXG4gKiBvZiB0aGUgcGFyc2VkIGNvbmZpZy4gVGhlIGRlZmF1bHQgdmFsdWUgaXMgYGZhbHNlYC5cclxuICogQHBhcmFtIHtib29sZWFufSBbYWxsb3dGdW5jdGlvbnM9ZmFsc2VdIC0gV2hldGhlciB0byBhbGxvdyBmdW5jdGlvbnNcclxuICogaW4gdGhlIHBhcnNlZCBjb25maWcuIElmIHRydWUsIGZ1bmN0aW9ucyBhcmUgcHJlc2VydmVkLiBPdGhlcndpc2UsIHdoZW5cclxuICogYSBmdW5jdGlvbiBpcyBmb3VuZCwgbnVsbCBpcyByZXR1cm5lZC4gVGhlIGRlZmF1bHQgdmFsdWUgaXMgYGZhbHNlYC5cclxuICpcclxuICogQHJldHVybnMgeyhPYmplY3R8c3RyaW5nfG51bGwpfSBSZXR1cm5zIGEgcGFyc2VkIHNldCBvZiBvcHRpb25zIG9iamVjdCxcclxuICogYSBzdHJpbmdpZmllZCBzZXQgb2Ygb3B0aW9ucyBvYmplY3QgaWYgdGhlIGB0b1N0cmluZ2AgaXMgdHJ1ZSwgYW5kIG51bGxcclxuICogaWYgdGhlIGNvbmZpZyBpcyBub3QgYSB2YWxpZCBzZXQgb2Ygb3B0aW9ucyBvciBwYXJzaW5nIGZhaWxzLlxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIGlzQWxsb3dlZENvbmZpZyhcclxuICBjb25maWcsXHJcbiAgdG9TdHJpbmcgPSBmYWxzZSxcclxuICBhbGxvd0Z1bmN0aW9ucyA9IGZhbHNlXHJcbikge1xyXG4gIHRyeSB7XHJcbiAgICAvLyBBY2NlcHQgb25seSBvYmplY3RzIGFuZCBzdHJpbmdzXHJcbiAgICBpZiAoIWlzT2JqZWN0KGNvbmZpZykgJiYgdHlwZW9mIGNvbmZpZyAhPT0gJ3N0cmluZycpIHtcclxuICAgICAgLy8gUmV0dXJuIG51bGwgaWYgYW55IG90aGVyIHR5cGVcclxuICAgICAgcmV0dXJuIG51bGw7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gR2V0IHRoZSBvYmplY3QgcmVwcmVzZW50YXRpb24gb2YgdGhlIG9yaWdpbmFsIGNvbmZpZ1xyXG4gICAgY29uc3Qgb2JqZWN0Q29uZmlnID1cclxuICAgICAgdHlwZW9mIGNvbmZpZyA9PT0gJ3N0cmluZydcclxuICAgICAgICA/IGFsbG93RnVuY3Rpb25zXHJcbiAgICAgICAgICA/IGV2YWwoYCgke2NvbmZpZ30pYClcclxuICAgICAgICAgIDogSlNPTi5wYXJzZShjb25maWcpXHJcbiAgICAgICAgOiBjb25maWc7XHJcblxyXG4gICAgLy8gUHJlc2VydmUgb3IgcmVtb3ZlIHBvdGVudGlhbCBmdW5jdGlvbnMgYmFzZWQgb24gdGhlIGBhbGxvd0Z1bmN0aW9uc2AgZmxhZ1xyXG4gICAgY29uc3Qgc3RyaW5naWZpZWRPcHRpb25zID0gX29wdGlvbnNTdHJpbmdpZnkoXHJcbiAgICAgIG9iamVjdENvbmZpZyxcclxuICAgICAgYWxsb3dGdW5jdGlvbnMsXHJcbiAgICAgIGZhbHNlXHJcbiAgICApO1xyXG5cclxuICAgIC8vIFBhcnNlIHRoZSBjb25maWcgdG8gY2hlY2sgaWYgaXQgaXMgdmFsaWQgc2V0IG9mIG9wdGlvbnNcclxuICAgIGNvbnN0IHBhcnNlZE9wdGlvbnMgPSBhbGxvd0Z1bmN0aW9uc1xyXG4gICAgICA/IEpTT04ucGFyc2UoXHJcbiAgICAgICAgICBfb3B0aW9uc1N0cmluZ2lmeShvYmplY3RDb25maWcsIGFsbG93RnVuY3Rpb25zLCB0cnVlKSxcclxuICAgICAgICAgIChfLCB2YWx1ZSkgPT5cclxuICAgICAgICAgICAgdHlwZW9mIHZhbHVlID09PSAnc3RyaW5nJyAmJiB2YWx1ZS5zdGFydHNXaXRoKCdmdW5jdGlvbicpXHJcbiAgICAgICAgICAgICAgPyBldmFsKGAoJHt2YWx1ZX0pYClcclxuICAgICAgICAgICAgICA6IHZhbHVlXHJcbiAgICAgICAgKVxyXG4gICAgICA6IEpTT04ucGFyc2Uoc3RyaW5naWZpZWRPcHRpb25zKTtcclxuXHJcbiAgICAvLyBSZXR1cm4gc3RyaW5naWZpZWQgb3Igb2JqZWN0IG9wdGlvbnMgYmFzZWQgb24gdGhlIGB0b1N0cmluZ2AgZmxhZ1xyXG4gICAgcmV0dXJuIHRvU3RyaW5nID8gc3RyaW5naWZpZWRPcHRpb25zIDogcGFyc2VkT3B0aW9ucztcclxuICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgLy8gUmV0dXJuIG51bGwgaWYgcGFyc2luZyBmYWlsc1xyXG4gICAgcmV0dXJuIG51bGw7XHJcbiAgfVxyXG59XHJcblxyXG4vKipcclxuICogUHJpbnRzIHRoZSBIaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXIgbG9nbywgdmVyc2lvbiwgYW5kIGxpY2Vuc2UgaW5mb3JtYXRpb24uXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBwcmludExpY2Vuc2VcclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiBwcmludExpY2Vuc2UoKSB7XHJcbiAgLy8gUHJpbnQgdGhlIGxvZ28gYW5kIHZlcnNpb24gaW5mb3JtYXRpb25cclxuICBwcmludFZlcnNpb24oKTtcclxuXHJcbiAgLy8gUHJpbnQgdGhlIGxpY2Vuc2UgaW5mb3JtYXRpb25cclxuICBjb25zb2xlLmxvZyhcclxuICAgICdUaGlzIHNvZnR3YXJlIHJlcXVpcmVzIGEgdmFsaWQgSGlnaGNoYXJ0cyBsaWNlbnNlIGZvciBjb21tZXJjaWFsIHVzZS5cXG4nXHJcbiAgICAgIC55ZWxsb3csXHJcbiAgICAnXFxuRm9yIGEgZnVsbCBsaXN0IG9mIENMSSBvcHRpb25zLCB0eXBlOicsXHJcbiAgICAnXFxuaGlnaGNoYXJ0cy1leHBvcnQtc2VydmVyIC0taGVscFxcbicuZ3JlZW4sXHJcbiAgICAnXFxuSWYgeW91IGRvIG5vdCBoYXZlIGEgbGljZW5zZSwgb25lIGNhbiBiZSBvYnRhaW5lZCBoZXJlOicsXHJcbiAgICAnXFxuaHR0cHM6Ly9zaG9wLmhpZ2hzb2Z0LmNvbS9cXG4nLmdyZWVuLFxyXG4gICAgJ1xcblRvIGN1c3RvbWl6ZSB5b3VyIGluc3RhbGxhdGlvbiwgcGxlYXNlIHJlZmVyIHRvIHRoZSBSRUFETUUgZmlsZSBhdDonLFxyXG4gICAgJ1xcbmh0dHBzOi8vZ2l0aHViLmNvbS9oaWdoY2hhcnRzL25vZGUtZXhwb3J0LXNlcnZlciNyZWFkbWVcXG4nLmdyZWVuXHJcbiAgKTtcclxufVxyXG5cclxuLyoqXHJcbiAqIFByaW50cyB1c2FnZSBpbmZvcm1hdGlvbiBmb3IgQ0xJIGFyZ3VtZW50cywgZGlzcGxheWluZyBhdmFpbGFibGUgb3B0aW9uc1xyXG4gKiBhbmQgdGhlaXIgZGVzY3JpcHRpb25zLiBJdCBjYW4gbGlzdCBwcm9wZXJ0aWVzIHJlY3Vyc2l2ZWx5IGlmIGNhdGVnb3JpZXNcclxuICogY29udGFpbiBuZXN0ZWQgb3B0aW9ucy5cclxuICpcclxuICogQGZ1bmN0aW9uIHByaW50VXNhZ2VcclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiBwcmludFVzYWdlKCkge1xyXG4gIC8vIERpc3BsYXkgUkVBRE1FIGFuZCBnZW5lcmFsIHVzYWdlIGluZm9ybWF0aW9uXHJcbiAgY29uc29sZS5sb2coXHJcbiAgICAnXFxuVXNhZ2Ugb2YgQ0xJIGFyZ3VtZW50czonLmJvbGQsXHJcbiAgICAnXFxuLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0nLFxyXG4gICAgYFxcbkZvciBtb3JlIGRldGFpbGVkIGluZm9ybWF0aW9uLCB2aXNpdCB0aGUgUkVBRE1FIGZpbGUgYXQ6ICR7J2h0dHBzOi8vZ2l0aHViLmNvbS9oaWdoY2hhcnRzL25vZGUtZXhwb3J0LXNlcnZlciNyZWFkbWUnLmdyZWVufS5cXG5gXHJcbiAgKTtcclxuXHJcbiAgLy8gSXRlcmF0ZSB0aHJvdWdoIGVhY2ggY2F0ZWdvcnkgaW4gdGhlIGBkZWZhdWx0Q29uZmlnYCBhbmQgZGlzcGxheSB1c2FnZSBpbmZvXHJcbiAgT2JqZWN0LmtleXMoZGVmYXVsdENvbmZpZykuZm9yRWFjaCgoY2F0ZWdvcnkpID0+IHtcclxuICAgIGNvbnNvbGUubG9nKGAke2NhdGVnb3J5LnRvVXBwZXJDYXNlKCl9YC5ib2xkLnJlZCk7XHJcbiAgICBfY3ljbGVDYXRlZ29yaWVzKGRlZmF1bHRDb25maWdbY2F0ZWdvcnldKTtcclxuICAgIGNvbnNvbGUubG9nKCcnKTtcclxuICB9KTtcclxufVxyXG5cclxuLyoqXHJcbiAqIFByaW50cyB0aGUgSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyIGxvZ28gb3IgdGV4dCB3aXRoIHRoZSB2ZXJzaW9uXHJcbiAqIGluZm9ybWF0aW9uLlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gcHJpbnRWZXJzaW9uXHJcbiAqXHJcbiAqIEBwYXJhbSB7Ym9vbGVhbn0gW25vTG9nbz1mYWxzZV0gLSBJZiB0cnVlLCBvbmx5IHByaW50cyB0ZXh0IHdpdGggdGhlIHZlcnNpb25cclxuICogaW5mb3JtYXRpb24sIHdpdGhvdXQgdGhlIGxvZ28uIFRoZSBkZWZhdWx0IHZhbHVlIGlzIGBmYWxzZWAuXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gcHJpbnRWZXJzaW9uKG5vTG9nbyA9IGZhbHNlKSB7XHJcbiAgLy8gR2V0IHBhY2thZ2UgdmVyc2lvbiBlaXRoZXIgZnJvbSBgLmVudmAgb3IgZnJvbSBgcGFja2FnZS5qc29uYFxyXG4gIGNvbnN0IHBhY2thZ2VWZXJzaW9uID0gSlNPTi5wYXJzZShcclxuICAgIHJlYWRGaWxlU3luYyhqb2luKF9fZGlybmFtZSwgJ3BhY2thZ2UuanNvbicpLCAndXRmOCcpXHJcbiAgKS52ZXJzaW9uO1xyXG5cclxuICAvLyBQcmludCB0ZXh0IG9ubHlcclxuICBpZiAobm9Mb2dvKSB7XHJcbiAgICBjb25zb2xlLmxvZyhgSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyIHYke3BhY2thZ2VWZXJzaW9ufWApO1xyXG4gIH0gZWxzZSB7XHJcbiAgICAvLyBQcmludCB0aGUgbG9nb1xyXG4gICAgY29uc29sZS5sb2coXHJcbiAgICAgIHJlYWRGaWxlU3luYyhqb2luKF9fZGlybmFtZSwgJ21zZycsICdzdGFydHVwLm1zZycpLCAndXRmOCcpLnRvU3RyaW5nKClcclxuICAgICAgICAuYm9sZC55ZWxsb3csXHJcbiAgICAgIGB2JHtwYWNrYWdlVmVyc2lvbn1cXG5gLmJvbGRcclxuICAgICk7XHJcbiAgfVxyXG59XHJcblxyXG4vKipcclxuICogSW5pdGlhbGl6ZXMgYW5kIHJldHVybnMgZ2xvYmFsIG9wdGlvbnMgb2JqZWN0IGJhc2VkIG9uIHByb3ZpZGVkXHJcbiAqIGNvbmZpZ3VyYXRpb24sIHNldHRpbmcgdmFsdWVzIGZyb20gbmVzdGVkIHByb3BlcnRpZXMgcmVjdXJzaXZlbHkuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBfaW5pdEdsb2JhbE9wdGlvbnNcclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IGNvbmZpZyAtIFRoZSBjb25maWd1cmF0aW9uIG9iamVjdCB0byBiZSB1c2VkIGZvciBpbml0aWFsaXppbmdcclxuICogb3B0aW9ucy5cclxuICpcclxuICogQHJldHVybnMge09iamVjdH0gSW5pdGlhbGl6ZWQgb3B0aW9ucyBvYmplY3QuXHJcbiAqL1xyXG5mdW5jdGlvbiBfaW5pdEdsb2JhbE9wdGlvbnMoY29uZmlnKSB7XHJcbiAgY29uc3Qgb3B0aW9ucyA9IHt9O1xyXG5cclxuICAvLyBTdGFydCBpbml0aWFsaXppbmcgdGhlIGBvcHRpb25zYCBvYmplY3QgcmVjdXJzaXZlbHlcclxuICBmb3IgKGNvbnN0IFtuYW1lLCBpdGVtXSBvZiBPYmplY3QuZW50cmllcyhjb25maWcpKSB7XHJcbiAgICBpZiAoT2JqZWN0LnByb3RvdHlwZS5oYXNPd25Qcm9wZXJ0eS5jYWxsKGl0ZW0sICd2YWx1ZScpKSB7XHJcbiAgICAgIC8vIElmIGEgdmFsdWUgZnJvbSBlbnZpcm9ubWVudCB2YXJpYWJsZXMgZXhpc3RzLCBpdCB0YWtlcyBwcmVjZWRlbmNlXHJcbiAgICAgIGNvbnN0IGVudlZhbCA9IGVudnNbaXRlbS5lbnZMaW5rXTtcclxuICAgICAgaWYgKGVudlZhbCAhPT0gdW5kZWZpbmVkICYmIGVudlZhbCAhPT0gbnVsbCkge1xyXG4gICAgICAgIG9wdGlvbnNbbmFtZV0gPSBlbnZWYWw7XHJcbiAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgb3B0aW9uc1tuYW1lXSA9IGl0ZW0udmFsdWU7XHJcbiAgICAgIH1cclxuICAgIH0gZWxzZSB7XHJcbiAgICAgIG9wdGlvbnNbbmFtZV0gPSBfaW5pdEdsb2JhbE9wdGlvbnMoaXRlbSk7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICAvLyBSZXR1cm4gdGhlIGNyZWF0ZWQgYG9wdGlvbnNgIG9iamVjdFxyXG4gIHJldHVybiBvcHRpb25zO1xyXG59XHJcblxyXG4vKipcclxuICogVXBkYXRlcyBnbG9iYWwgb3B0aW9ucyBvYmplY3Qgd2l0aCB2YWx1ZXMgZnJvbSB2YXJpb3VzIHNvdXJjZXMsIGZvbGxvd2luZ1xyXG4gKiBhIHNwZWNpZmljIHByaW9yaXRpemF0aW9uIG9yZGVyLiBUaGUgZnVuY3Rpb24gY2hlY2tzIGZvciB2YWx1ZXMgaW4gdGhlIG9yZGVyXHJcbiAqIG9mIHByZWNlZGVuY2U6IHRoZSBgbG9hZENvbmZpZ2AgY29uZmlndXJhdGlvbiBvcHRpb25zLCBlbnZpcm9ubWVudCB2YXJpYWJsZXMsXHJcbiAqIGN1c3RvbSBvcHRpb25zLCBhbmQgQ0xJIG9wdGlvbnMuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBfdXBkYXRlR2xvYmFsT3B0aW9uc1xyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gY29uZmlnIC0gVGhlIGNvbmZpZ3VyYXRpb24gb2JqZWN0LCB3aGljaCBpbmNsdWRlcyB0aGUgaW5pdGlhbFxyXG4gKiBzZXR0aW5ncyBhbmQgbWV0YWRhdGEgZm9yIGVhY2ggb3B0aW9uLiBUaGlzIG9iamVjdCBpcyB1c2VkIHRvIGRldGVybWluZVxyXG4gKiB0aGUgc3RydWN0dXJlIGFuZCBkZWZhdWx0IHZhbHVlcyBmb3IgdGhlIG9wdGlvbnMuXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBvcHRpb25zIC0gVGhlIGdsb2JhbCBvcHRpb25zIG9iamVjdCB0aGF0IHdpbGwgYmUgdXBkYXRlZFxyXG4gKiB3aXRoIHZhbHVlcyBmcm9tIG90aGVyIHNvdXJjZXMuXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBjb25maWdPcHQgLSBUaGUgY29uZmlndXJhdGlvbiBvcHRpb25zIG9iamVjdCwgbG9hZGVkIHdpdGhcclxuICogdGhlIGBsb2FkQ29uZmlnYCBvcHRpb24sIHdoaWNoIG1heSBwcm92aWRlIHZhbHVlcyB0byBvdmVycmlkZSBkZWZhdWx0cy5cclxuICogQHBhcmFtIHtPYmplY3R9IGNsaU9wdCAtIFRoZSBDTEkgb3B0aW9ucyBvYmplY3QsIHdoaWNoIG1heSBpbmNsdWRlIHZhbHVlc1xyXG4gKiBwcm92aWRlZCB0aHJvdWdoIGNvbW1hbmQtbGluZSBhcmd1bWVudHMgYW5kIG1heSBvdmVycmlkZSBjb25maWd1cmF0aW9uXHJcbiAqIG9wdGlvbnMuXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBjdXN0b21PcHQgLSBUaGUgY3VzdG9tIG9wdGlvbnMgb2JqZWN0LCB0eXBpY2FsbHkgY29udGFpbmluZ1xyXG4gKiBhZGRpdGlvbmFsIGFuZCB1c2VyLWRlZmluZWQgdmFsdWVzLCB3aGljaCBoYXMgdGhlIGhpZ2hlc3QgcHJlY2VkZW5jZSBhbW9uZ1xyXG4gKiBvcHRpb25zLlxyXG4gKi9cclxuZnVuY3Rpb24gX3VwZGF0ZUdsb2JhbE9wdGlvbnMoY29uZmlnLCBvcHRpb25zLCBjb25maWdPcHQsIGNsaU9wdCwgY3VzdG9tT3B0KSB7XHJcbiAgT2JqZWN0LmtleXMoY29uZmlnKS5mb3JFYWNoKChrZXkpID0+IHtcclxuICAgIC8vIEdldCB0aGUgY29uZmlnIGVudHJ5IG9mIGEgc3BlY2lmaWMgb3B0aW9uXHJcbiAgICBjb25zdCBlbnRyeSA9IGNvbmZpZ1trZXldO1xyXG5cclxuICAgIC8vIEdhdGhlciB2YWx1ZXMgZm9yIHRoZSBvcHRpb25zIGZyb20gZXZlcnkgcG9zc2libGUgc291cmNlLCBpZiBleGlzdHNcclxuICAgIGNvbnN0IGNvbmZpZ1ZhbCA9IGNvbmZpZ09wdCAmJiBjb25maWdPcHRba2V5XTtcclxuICAgIGNvbnN0IGNsaVZhbCA9IGNsaU9wdCAmJiBjbGlPcHRba2V5XTtcclxuICAgIGNvbnN0IGN1c3RvbVZhbCA9IGN1c3RvbU9wdCAmJiBjdXN0b21PcHRba2V5XTtcclxuXHJcbiAgICAvLyBJZiB0aGUgdmFsdWUgbm90IGZvdW5kLCBuZWVkIHRvIGdvIGRlZXBlclxyXG4gICAgaWYgKHR5cGVvZiBlbnRyeS52YWx1ZSA9PT0gJ3VuZGVmaW5lZCcpIHtcclxuICAgICAgX3VwZGF0ZUdsb2JhbE9wdGlvbnMoZW50cnksIG9wdGlvbnNba2V5XSwgY29uZmlnVmFsLCBjbGlWYWwsIGN1c3RvbVZhbCk7XHJcbiAgICB9IGVsc2Uge1xyXG4gICAgICAvLyBJZiBhIHZhbHVlIGZyb20gY3VzdG9tIEpTT04gb3B0aW9ucyBleGlzdHMsIGl0IHRha2VzIHByZWNlZGVuY2VcclxuICAgICAgaWYgKGNvbmZpZ1ZhbCAhPT0gdW5kZWZpbmVkICYmIGNvbmZpZ1ZhbCAhPT0gbnVsbCkge1xyXG4gICAgICAgIG9wdGlvbnNba2V5XSA9IGNvbmZpZ1ZhbDtcclxuICAgICAgfVxyXG5cclxuICAgICAgLy8gSWYgYSB2YWx1ZSBmcm9tIGVudmlyb25tZW50IHZhcmlhYmxlcyBleGlzdHMsIGl0IHRha2VzIHByZWNlZGVuY2VcclxuICAgICAgY29uc3QgZW52VmFsID0gZW52c1tlbnRyeS5lbnZMaW5rXTtcclxuICAgICAgaWYgKGVudHJ5LmVudkxpbmsgaW4gZW52cyAmJiBlbnZWYWwgIT09IHVuZGVmaW5lZCAmJiBlbnZWYWwgIT09IG51bGwpIHtcclxuICAgICAgICBvcHRpb25zW2tleV0gPSBlbnZWYWw7XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIC8vIElmIGEgdmFsdWUgZnJvbSBDTEkgb3B0aW9ucyBleGlzdHMsIGl0IHRha2VzIHByZWNlZGVuY2VcclxuICAgICAgaWYgKGNsaVZhbCAhPT0gdW5kZWZpbmVkICYmIGNsaVZhbCAhPT0gbnVsbCkge1xyXG4gICAgICAgIG9wdGlvbnNba2V5XSA9IGNsaVZhbDtcclxuICAgICAgfVxyXG5cclxuICAgICAgLy8gSWYgYSB2YWx1ZSBmcm9tIHVzZXIgb3B0aW9ucyBleGlzdHMsIGl0IHRha2VzIHByZWNlZGVuY2VcclxuICAgICAgaWYgKGN1c3RvbVZhbCAhPT0gdW5kZWZpbmVkICYmIGN1c3RvbVZhbCAhPT0gbnVsbCkge1xyXG4gICAgICAgIG9wdGlvbnNba2V5XSA9IGN1c3RvbVZhbDtcclxuICAgICAgfVxyXG4gICAgfVxyXG4gIH0pO1xyXG59XHJcblxyXG4vKipcclxuICogQ29udmVydHMgdGhlIHByb3ZpZGVkIG9wdGlvbnMgb2JqZWN0IHRvIGEgSlNPTi1mb3JtYXR0ZWQgc3RyaW5nXHJcbiAqIHdpdGggdGhlIG9wdGlvbiB0byBwcmVzZXJ2ZSBmdW5jdGlvbnMuIEluIG9yZGVyIGZvciBhIGZ1bmN0aW9uXHJcbiAqIHRvIGJlIHByZXNlcnZlZCwgaXQgbmVlZHMgdG8gZm9sbG93IHRoZSBmb3JtYXQgYGZ1bmN0aW9uICguLi4pIHsuLi59YC5cclxuICogU3VjaCBhIGZ1bmN0aW9uIGNhbiBhbHNvIGJlIHN0cmluZ2lmaWVkLlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gX29wdGlvbnNTdHJpbmdpZnlcclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IG9wdGlvbnMgLSBUaGUgb3B0aW9ucyBvYmplY3QgdG8gYmUgY29udmVydGVkIHRvIGEgc3RyaW5nLlxyXG4gKiBAcGFyYW0ge2Jvb2xlYW59IGFsbG93RnVuY3Rpb25zIC0gSWYgc2V0IHRvIHRydWUsIGZ1bmN0aW9ucyBhcmUgcHJlc2VydmVkXHJcbiAqIGluIHRoZSBvdXRwdXQuIE90aGVyd2lzZSBhbiBlcnJvciBpcyB0aHJvd24uXHJcbiAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaW5naWZ5RnVuY3Rpb25zIC0gSWYgc2V0IHRvIHRydWUsIGZ1bmN0aW9ucyBhcmUgc2F2ZWRcclxuICogYXMgc3RyaW5ncy4gVGhlIGBhbGxvd0Z1bmN0aW9uc2AgbXVzdCBiZSBzZXQgdG8gdHJ1ZSBhcyB3ZWxsIGZvciB0aGlzIHRvIHRha2VcclxuICogYW4gZWZmZWN0LlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7c3RyaW5nfSBUaGUgSlNPTi1mb3JtYXR0ZWQgc3RyaW5nIHJlcHJlc2VudGluZyB0aGUgb3B0aW9ucy5cclxuICpcclxuICogQHRocm93cyB7RXJyb3J9IFRocm93cyBhbiBgRXJyb3JgIHdoZW4gZnVuY3Rpb25zIGFyZSBub3QgYWxsb3dlZCBidXQgYXJlXHJcbiAqIGZvdW5kIGluIHByb3ZpZGVkIG9wdGlvbnMgb2JqZWN0LlxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIF9vcHRpb25zU3RyaW5naWZ5KG9wdGlvbnMsIGFsbG93RnVuY3Rpb25zLCBzdHJpbmdpZnlGdW5jdGlvbnMpIHtcclxuICBjb25zdCByZXBsYWNlckNhbGxiYWNrID0gKF8sIHZhbHVlKSA9PiB7XHJcbiAgICAvLyBUcmltIHN0cmluZyB2YWx1ZXNcclxuICAgIGlmICh0eXBlb2YgdmFsdWUgPT09ICdzdHJpbmcnKSB7XHJcbiAgICAgIHZhbHVlID0gdmFsdWUudHJpbSgpO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIElmIHZhbHVlIGlzIGEgZnVuY3Rpb24gb3Igc3RyaW5naWZpZWQgZnVuY3Rpb25cclxuICAgIGlmIChcclxuICAgICAgdHlwZW9mIHZhbHVlID09PSAnZnVuY3Rpb24nIHx8XHJcbiAgICAgICh0eXBlb2YgdmFsdWUgPT09ICdzdHJpbmcnICYmXHJcbiAgICAgICAgdmFsdWUuc3RhcnRzV2l0aCgnZnVuY3Rpb24nKSAmJlxyXG4gICAgICAgIHZhbHVlLmVuZHNXaXRoKCd9JykpXHJcbiAgICApIHtcclxuICAgICAgLy8gSWYgYWxsb3dGdW5jdGlvbnMgaXMgc2V0IHRvIHRydWUsIHByZXNlcnZlIGZ1bmN0aW9uc1xyXG4gICAgICBpZiAoYWxsb3dGdW5jdGlvbnMpIHtcclxuICAgICAgICAvLyBCYXNlZCBvbiB0aGUgYHN0cmluZ2lmeUZ1bmN0aW9uc2Agb3B0aW9ucywgc2V0IGZ1bmN0aW9uIHZhbHVlc1xyXG4gICAgICAgIHJldHVybiBzdHJpbmdpZnlGdW5jdGlvbnNcclxuICAgICAgICAgID8gLy8gQXMgc3RyaW5naWZpZWQgZnVuY3Rpb25zXHJcbiAgICAgICAgICAgIGBcIkVYUF9GVU4keyh2YWx1ZSArICcnKS5yZXBsYWNlQWxsKC9cXHMrL2csICcgJyl9RVhQX0ZVTlwiYFxyXG4gICAgICAgICAgOiAvLyBBcyBmdW5jdGlvbnNcclxuICAgICAgICAgICAgYEVYUF9GVU4keyh2YWx1ZSArICcnKS5yZXBsYWNlQWxsKC9cXHMrL2csICcgJyl9RVhQX0ZVTmA7XHJcbiAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgLy8gVGhyb3cgYW4gZXJyb3Igb3RoZXJ3aXNlXHJcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKCk7XHJcbiAgICAgIH1cclxuICAgIH1cclxuXHJcbiAgICAvLyBJbiBhbGwgb3RoZXIgY2FzZXMsIHNpbXBseSByZXR1cm4gdGhlIHZhbHVlXHJcbiAgICByZXR1cm4gdmFsdWU7XHJcbiAgfTtcclxuXHJcbiAgLy8gU3RyaW5naWZ5IG9wdGlvbnMgYW5kIGlmIHJlcXVpcmVkLCByZXBsYWNlIHNwZWNpYWwgZnVuY3Rpb25zIG1hcmtzXHJcbiAgcmV0dXJuIEpTT04uc3RyaW5naWZ5KG9wdGlvbnMsIHJlcGxhY2VyQ2FsbGJhY2spLnJlcGxhY2VBbGwoXHJcbiAgICBzdHJpbmdpZnlGdW5jdGlvbnMgPyAvXFxcXFwiRVhQX0ZVTnxFWFBfRlVOXFxcXFwiL2cgOiAvXCJFWFBfRlVOfEVYUF9GVU5cIi9nLFxyXG4gICAgJydcclxuICApO1xyXG59XHJcblxyXG4vKipcclxuICogTG9hZHMgYWRkaXRpb25hbCBjb25maWd1cmF0aW9uIGZyb20gYSBzcGVjaWZpZWQgZmlsZSBwcm92aWRlZCB2aWFcclxuICogdGhlIGBsb2FkQ29uZmlnYCBvcHRpb24gaW4gdGhlIGNvbW1hbmQtbGluZSBhcmd1bWVudHMuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBfbG9hZENvbmZpZ0ZpbGVcclxuICpcclxuICogQHBhcmFtIHtBcnJheS48c3RyaW5nPn0gY2xpQXJncyAtIENvbW1hbmQtbGluZSBhcmd1bWVudHMgdG8gc2VhcmNoXHJcbiAqIGZvciB0aGUgYGxvYWRDb25maWdgIG9wdGlvbiBhbmQgdGhlIGNvcnJlc3BvbmRpbmcgZmlsZSBwYXRoLlxyXG4gKiBAcGFyYW0ge09iamVjdH0gY3VzdG9tTG9naWNPcHRpb25zIC0gVGhlIGNvbmZpZ3VyYXRpb24gb2JqZWN0IGNvbnRhaW5pbmdcclxuICogYGN1c3RvbUxvZ2ljYCBvcHRpb25zLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7T2JqZWN0fSBUaGUgYWRkaXRpb25hbCBjb25maWd1cmF0aW9uIGxvYWRlZCBmcm9tIHRoZSBzcGVjaWZpZWRcclxuICogZmlsZSwgb3IgYW4gZW1wdHkgb2JqZWN0IGlmIHRoZSBmaWxlIGlzIG5vdCBmb3VuZCwgaW52YWxpZCwgb3IgYW4gZXJyb3JcclxuICogb2NjdXJzLlxyXG4gKi9cclxuZnVuY3Rpb24gX2xvYWRDb25maWdGaWxlKGNsaUFyZ3MsIGN1c3RvbUxvZ2ljT3B0aW9ucykge1xyXG4gIC8vIENoZWNrIGlmIHRoZSBgbG9hZENvbmZpZ2Agb3B0aW9uIHdhcyB1c2VkXHJcbiAgY29uc3QgY29uZmlnSW5kZXggPSBjbGlBcmdzLmZpbmRJbmRleChcclxuICAgIChhcmcpID0+IGFyZy5yZXBsYWNlKC8tL2csICcnKSA9PT0gJ2xvYWRDb25maWcnXHJcbiAgKTtcclxuXHJcbiAgLy8gR2V0IHRoZSBgbG9hZENvbmZpZ2Agb3B0aW9uIHZhbHVlXHJcbiAgY29uc3QgY29uZmlnRmlsZU5hbWUgPSBjb25maWdJbmRleCA+IC0xICYmIGNsaUFyZ3NbY29uZmlnSW5kZXggKyAxXTtcclxuXHJcbiAgLy8gQ2hlY2sgaWYgdGhlIGBsb2FkQ29uZmlnYCBpcyBwcmVzZW50IGFuZCBoYXMgYSBjb3JyZWN0IHZhbHVlXHJcbiAgaWYgKGNvbmZpZ0ZpbGVOYW1lICYmIGN1c3RvbUxvZ2ljT3B0aW9ucy5hbGxvd0ZpbGVSZXNvdXJjZXMpIHtcclxuICAgIHRyeSB7XHJcbiAgICAgIC8vIExvYWQgYW4gb3B0aW9uYWwgY3VzdG9tIEpTT04gY29uZmlnIGZpbGVcclxuICAgICAgcmV0dXJuIGlzQWxsb3dlZENvbmZpZyhcclxuICAgICAgICByZWFkRmlsZVN5bmMoZ2V0QWJzb2x1dGVQYXRoKGNvbmZpZ0ZpbGVOYW1lKSwgJ3V0ZjgnKSxcclxuICAgICAgICBmYWxzZSxcclxuICAgICAgICBjdXN0b21Mb2dpY09wdGlvbnMuYWxsb3dDb2RlRXhlY3V0aW9uXHJcbiAgICAgICk7XHJcbiAgICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgICBsb2dXaXRoU3RhY2soXHJcbiAgICAgICAgMixcclxuICAgICAgICBlcnJvcixcclxuICAgICAgICBgW2NvbmZpZ10gVW5hYmxlIHRvIGxvYWQgdGhlIGNvbmZpZ3VyYXRpb24gZnJvbSB0aGUgJHtjb25maWdGaWxlTmFtZX0gZmlsZS5gXHJcbiAgICAgICk7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICAvLyBObyBhZGRpdGlvbmFsIG9wdGlvbnMgdG8gcmV0dXJuXHJcbiAgcmV0dXJuIHt9O1xyXG59XHJcblxyXG4vKipcclxuICogUGFyc2VzIGNvbW1hbmQtbGluZSBhcmd1bWVudHMgYW5kIHBhaXJzIGVhY2ggYXJndW1lbnQgd2l0aCBpdHMgY29ycmVzcG9uZGluZ1xyXG4gKiBvcHRpb24gaW4gdGhlIGNvbmZpZ3VyYXRpb24uIFRoZSB2YWx1ZXMgYXJlIHN0cnVjdHVyZWQgaW50byBhIG5lc3RlZCBvcHRpb25zXHJcbiAqIG9iamVjdCwgYmFzZWQgb24gcHJlZGVmaW5lZCBtYXBwaW5ncy5cclxuICpcclxuICogQGZ1bmN0aW9uIF9wYWlyQXJndW1lbnRWYWx1ZVxyXG4gKlxyXG4gKiBAcGFyYW0ge0FycmF5LjxzdHJpbmc+fSBuZXN0ZWRQcm9wcyAtIEFuIGFycmF5IG9mIG5lc3RpbmcgbGV2ZWwgZm9yIGFsbFxyXG4gKiBvcHRpb25zLlxyXG4gKiBAcGFyYW0ge0FycmF5LjxzdHJpbmc+fSBjbGlBcmdzIC0gQW4gYXJyYXkgb2YgY29tbWFuZC1saW5lIGFyZ3VtZW50c1xyXG4gKiBjb250YWluaW5nIG9wdGlvbnMgYW5kIHRoZWlyIGFzc29jaWF0ZWQgdmFsdWVzLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7T2JqZWN0fSBBbiB1cGRhdGVkIG9wdGlvbnMgb2JqZWN0IHdoZXJlIGVhY2ggb3B0aW9uIGZyb21cclxuICogdGhlIGNvbW1hbmQtbGluZSBpcyBwYWlyZWQgd2l0aCBpdHMgdmFsdWUsIHN0cnVjdHVyZWQgaW50byBuZXN0ZWQgb2JqZWN0c1xyXG4gKiBhcyBkZWZpbmVkLlxyXG4gKi9cclxuZnVuY3Rpb24gX3BhaXJBcmd1bWVudFZhbHVlKG5lc3RlZFByb3BzLCBjbGlBcmdzKSB7XHJcbiAgLy8gQW4gZW1wdHkgb2JqZWN0IHRvIGNvbGxlY3QgYW5kIHN0cnVjdHVyaXplIGRhdGEgZnJvbSB0aGUgYXJnc1xyXG4gIGNvbnN0IGNsaU9wdGlvbnMgPSB7fTtcclxuXHJcbiAgLy8gQ3ljbGUgdGhyb3VnaCBhbGwgQ0xJIGFyZ3MgYW5kIGZpbHRlciB0aGVtXHJcbiAgZm9yIChsZXQgaSA9IDA7IGkgPCBjbGlBcmdzLmxlbmd0aDsgaSsrKSB7XHJcbiAgICBjb25zdCBvcHRpb24gPSBjbGlBcmdzW2ldLnJlcGxhY2UoLy0vZywgJycpO1xyXG5cclxuICAgIC8vIEZpbmQgdGhlIHJpZ2h0IHBsYWNlIGZvciBwcm9wZXJ0eSdzIHZhbHVlXHJcbiAgICBjb25zdCBwcm9wZXJ0aWVzQ2hhaW4gPSBuZXN0ZWRQcm9wc1tvcHRpb25dXHJcbiAgICAgID8gbmVzdGVkUHJvcHNbb3B0aW9uXS5zcGxpdCgnLicpXHJcbiAgICAgIDogW107XHJcblxyXG4gICAgLy8gQ3JlYXRlIG9wdGlvbnMgb2JqZWN0IHdpdGggdmFsdWVzIGZyb20gQ0xJIGZvciBsYXRlciBwYXJzaW5nIGFuZCBtZXJnaW5nXHJcbiAgICBwcm9wZXJ0aWVzQ2hhaW4ucmVkdWNlKChvYmosIHByb3AsIGluZGV4KSA9PiB7XHJcbiAgICAgIGlmIChwcm9wZXJ0aWVzQ2hhaW4ubGVuZ3RoIC0gMSA9PT0gaW5kZXgpIHtcclxuICAgICAgICBjb25zdCB2YWx1ZSA9IGNsaUFyZ3NbKytpXTtcclxuICAgICAgICBpZiAoIXZhbHVlKSB7XHJcbiAgICAgICAgICBsb2coXHJcbiAgICAgICAgICAgIDIsXHJcbiAgICAgICAgICAgIGBbY29uZmlnXSBNaXNzaW5nIHZhbHVlIGZvciB0aGUgQ0xJICctLSR7b3B0aW9ufScgYXJndW1lbnQuIFVzaW5nIHRoZSBkZWZhdWx0IHZhbHVlLmBcclxuICAgICAgICAgICk7XHJcbiAgICAgICAgfVxyXG4gICAgICAgIG9ialtwcm9wXSA9IHZhbHVlIHx8IG51bGw7XHJcbiAgICAgIH0gZWxzZSBpZiAob2JqW3Byb3BdID09PSB1bmRlZmluZWQpIHtcclxuICAgICAgICBvYmpbcHJvcF0gPSB7fTtcclxuICAgICAgfVxyXG4gICAgICByZXR1cm4gb2JqW3Byb3BdO1xyXG4gICAgfSwgY2xpT3B0aW9ucyk7XHJcbiAgfVxyXG5cclxuICAvLyBSZXR1cm4gcGFyc2VkIENMSSBvcHRpb25zXHJcbiAgcmV0dXJuIGNsaU9wdGlvbnM7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBSZWN1cnNpdmVseSB0cmF2ZXJzZXMgdGhlIG9wdGlvbnMgb2JqZWN0IHRvIHByaW50IHRoZSB1c2FnZSBpbmZvcm1hdGlvblxyXG4gKiBmb3IgZWFjaCBvcHRpb24gY2F0ZWdvcnkgYW5kIGluZGl2aWR1YWwgb3B0aW9uLlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gX2N5Y2xlQ2F0ZWdvcmllc1xyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gb3B0aW9ucyAtIFRoZSBvcHRpb25zIG9iamVjdCBjb250YWluaW5nIENMSSBvcHRpb25zLiBJdCBtYXlcclxuICogaW5jbHVkZSBuZXN0ZWQgY2F0ZWdvcmllcyBhbmQgaW5kaXZpZHVhbCBvcHRpb25zLlxyXG4gKi9cclxuZnVuY3Rpb24gX2N5Y2xlQ2F0ZWdvcmllcyhvcHRpb25zKSB7XHJcbiAgZm9yIChjb25zdCBbbmFtZSwgb3B0aW9uXSBvZiBPYmplY3QuZW50cmllcyhvcHRpb25zKSkge1xyXG4gICAgLy8gSWYgdGhlIGN1cnJlbnQgZW50cnkgaXMgYSBjYXRlZ29yeSBhbmQgbm90IGEgbGVhZiBvcHRpb24sIHJlY3Vyc2UgaW50byBpdFxyXG4gICAgaWYgKCFPYmplY3QucHJvdG90eXBlLmhhc093blByb3BlcnR5LmNhbGwob3B0aW9uLCAndmFsdWUnKSkge1xyXG4gICAgICBfY3ljbGVDYXRlZ29yaWVzKG9wdGlvbik7XHJcbiAgICB9IGVsc2Uge1xyXG4gICAgICAvLyBQcmVwYXJlIGRlc2NyaXB0aW9uXHJcbiAgICAgIGNvbnN0IGRlc2NOYW1lID0gYCAtLSR7b3B0aW9uLmNsaU5hbWUgfHwgbmFtZX1gO1xyXG5cclxuICAgICAgLy8gR2V0IHRoZSB2YWx1ZVxyXG4gICAgICBsZXQgb3B0aW9uVmFsdWUgPSBvcHRpb24udmFsdWU7XHJcblxyXG4gICAgICAvLyBQcmVwYXJlIHZhbHVlIGZvciBvcHRpb24gdGhhdCBpcyBub3QgbnVsbCBhbmQgaXMgYXJyYXkgb2Ygc3RyaW5nc1xyXG4gICAgICBpZiAob3B0aW9uVmFsdWUgIT09IG51bGwgJiYgb3B0aW9uLnR5cGVzLmluY2x1ZGVzKCdzdHJpbmdbXScpKSB7XHJcbiAgICAgICAgb3B0aW9uVmFsdWUgPVxyXG4gICAgICAgICAgJ1snICsgb3B0aW9uVmFsdWUubWFwKChpdGVtKSA9PiBgJyR7aXRlbX0nYCkuam9pbignLCAnKSArICddJztcclxuICAgICAgfVxyXG5cclxuICAgICAgLy8gUHJlcGFyZSB2YWx1ZSBmb3Igb3B0aW9uIHRoYXQgaXMgbm90IG51bGwgYW5kIGlzIGEgc3RyaW5nXHJcbiAgICAgIGlmIChvcHRpb25WYWx1ZSAhPT0gbnVsbCAmJiBvcHRpb24udHlwZXMuaW5jbHVkZXMoJ3N0cmluZycpKSB7XHJcbiAgICAgICAgb3B0aW9uVmFsdWUgPSBgJyR7b3B0aW9uVmFsdWV9J2A7XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIC8vIERpc3BsYXkgY29ycmVjdGx5IGFsaWduZWQgbWVzc2FnZXNcclxuICAgICAgY29uc29sZS5sb2coXHJcbiAgICAgICAgZGVzY05hbWUuZ3JlZW4sXHJcbiAgICAgICAgYCR7KCc8JyArIG9wdGlvbi50eXBlcy5qb2luKCd8JykgKyAnPicpLnllbGxvd31gLFxyXG4gICAgICAgIGAke1N0cmluZyhvcHRpb25WYWx1ZSkuYm9sZH1gLmJsdWUsXHJcbiAgICAgICAgYC0gJHtvcHRpb24uZGVzY3JpcHRpb259LmBcclxuICAgICAgKTtcclxuICAgIH1cclxuICB9XHJcbn1cclxuXHJcbmV4cG9ydCBkZWZhdWx0IHtcclxuICBnZXRPcHRpb25zLFxyXG4gIHNldEdsb2JhbE9wdGlvbnMsXHJcbiAgdXBkYXRlT3B0aW9ucyxcclxuICBtZXJnZU9wdGlvbnMsXHJcbiAgbWFwVG9OZXdPcHRpb25zLFxyXG4gIGlzQWxsb3dlZENvbmZpZyxcclxuICBwcmludExpY2Vuc2UsXHJcbiAgcHJpbnRVc2FnZSxcclxuICBwcmludFZlcnNpb25cclxufTtcclxuIiwiLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcclxuXHJcbkhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlclxyXG5cclxuQ29weXJpZ2h0IChjKSAyMDE2LTIwMjUsIEhpZ2hzb2Z0XHJcblxyXG5MaWNlbmNlZCB1bmRlciB0aGUgTUlUIGxpY2VuY2UuXHJcblxyXG5BZGRpdGlvbmFsbHkgYSB2YWxpZCBIaWdoY2hhcnRzIGxpY2Vuc2UgaXMgcmVxdWlyZWQgZm9yIHVzZS5cclxuXHJcblNlZSBMSUNFTlNFIGZpbGUgaW4gcm9vdCBmb3IgZGV0YWlscy5cclxuXHJcbioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXHJcblxyXG4vKipcclxuICogQG92ZXJ2aWV3IEhUVFAgdXRpbGl0eSBtb2R1bGUgZm9yIGZldGNoaW5nIGFuZCBwb3N0aW5nIGRhdGEuIFN1cHBvcnRzIGJvdGhcclxuICogSFRUUCBhbmQgSFRUUFMgcHJvdG9jb2xzLCBwcm92aWRpbmcgbWV0aG9kcyB0byBtYWtlIEdFVCBhbmQgUE9TVCByZXF1ZXN0c1xyXG4gKiB3aXRoIGN1c3RvbWl6YWJsZSBvcHRpb25zLiBJbmNsdWRlcyBwcm90b2NvbCBkZXRlcm1pbmF0aW9uIGJhc2VkIG9uIFVSTFxyXG4gKiBhbmQgYXVnbWVudHMgcmVzcG9uc2Ugb2JqZWN0cyB3aXRoIGEgJ3RleHQnIHByb3BlcnR5IGZvciBlYXNpZXIgZGF0YSBhY2Nlc3MuXHJcbiAqL1xyXG5cclxuaW1wb3J0IGh0dHAgZnJvbSAnaHR0cCc7XHJcbmltcG9ydCBodHRwcyBmcm9tICdodHRwcyc7XHJcblxyXG4vKipcclxuICogRmV0Y2hlcyBkYXRhIGZyb20gdGhlIHNwZWNpZmllZCBVUkwgdXNpbmcgZWl0aGVyIEhUVFAgb3IgSFRUUFMgcHJvdG9jb2wuXHJcbiAqXHJcbiAqIEBhc3luY1xyXG4gKiBAZnVuY3Rpb24gZmV0Y2hcclxuICpcclxuICogQHBhcmFtIHtzdHJpbmd9IHVybCAtIFRoZSBVUkwgdG8gZmV0Y2ggZGF0YSBmcm9tLlxyXG4gKiBAcGFyYW0ge09iamVjdH0gW3JlcXVlc3RPcHRpb25zPXt9XSAtIE9wdGlvbnMgZm9yIHRoZSBIVFRQL0hUVFBTIHJlcXVlc3QuXHJcbiAqIFRoZSBkZWZhdWx0IHZhbHVlIGlzIGFuIGVtcHR5IG9iamVjdC5cclxuICpcclxuICogQHJldHVybnMge1Byb21pc2U8T2JqZWN0Pn0gQSBQcm9taXNlIHRoYXQgcmVzb2x2ZXMgdG8gdGhlIEhUVFAvSFRUUFMgcmVzcG9uc2VcclxuICogb2JqZWN0IHdpdGggYWRkZWQgJ3RleHQnIHByb3BlcnR5IG9yIHJlamVjdGluZyB3aXRoIGFuIGVycm9yLlxyXG4gKi9cclxuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIGZldGNoKHVybCwgcmVxdWVzdE9wdGlvbnMgPSB7fSkge1xyXG4gIHJldHVybiBuZXcgUHJvbWlzZSgocmVzb2x2ZSwgcmVqZWN0KSA9PiB7XHJcbiAgICBfZ2V0UHJvdG9jb2xNb2R1bGUodXJsKVxyXG4gICAgICAuZ2V0KHVybCwgcmVxdWVzdE9wdGlvbnMsIChyZXNwb25zZSkgPT4ge1xyXG4gICAgICAgIGxldCByZXNwb25zZURhdGEgPSAnJztcclxuXHJcbiAgICAgICAgLy8gQSBjaHVuayBvZiBkYXRhIGhhcyBiZWVuIHJlY2VpdmVkXHJcbiAgICAgICAgcmVzcG9uc2Uub24oJ2RhdGEnLCAoY2h1bmspID0+IHtcclxuICAgICAgICAgIHJlc3BvbnNlRGF0YSArPSBjaHVuaztcclxuICAgICAgICB9KTtcclxuXHJcbiAgICAgICAgLy8gVGhlIHdob2xlIHJlc3BvbnNlIGhhcyBiZWVuIHJlY2VpdmVkXHJcbiAgICAgICAgcmVzcG9uc2Uub24oJ2VuZCcsICgpID0+IHtcclxuICAgICAgICAgIGlmICghcmVzcG9uc2VEYXRhKSB7XHJcbiAgICAgICAgICAgIHJlamVjdCgnTm90aGluZyB3YXMgZmV0Y2hlZCBmcm9tIHRoZSBVUkwuJyk7XHJcbiAgICAgICAgICB9XHJcbiAgICAgICAgICByZXNwb25zZS50ZXh0ID0gcmVzcG9uc2VEYXRhO1xyXG4gICAgICAgICAgcmVzb2x2ZShyZXNwb25zZSk7XHJcbiAgICAgICAgfSk7XHJcbiAgICAgIH0pXHJcbiAgICAgIC5vbignZXJyb3InLCAoZXJyb3IpID0+IHtcclxuICAgICAgICByZWplY3QoZXJyb3IpO1xyXG4gICAgICB9KTtcclxuICB9KTtcclxufVxyXG5cclxuLyoqXHJcbiAqIFNlbmRzIGEgUE9TVCByZXF1ZXN0IHRvIHRoZSBzcGVjaWZpZWQgVVJMIHdpdGggdGhlIHByb3ZpZGVkIEpTT04gYm9keSB1c2luZ1xyXG4gKiBlaXRoZXIgSFRUUCBvciBIVFRQUyBwcm90b2NvbC5cclxuICpcclxuICogQGFzeW5jXHJcbiAqIEBmdW5jdGlvbiBwb3N0XHJcbiAqXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSB1cmwgLSBUaGUgVVJMIHRvIHNlbmQgdGhlIFBPU1QgcmVxdWVzdCB0by5cclxuICogQHBhcmFtIHtPYmplY3R9IFtib2R5PXt9XSAtIFRoZSBKU09OIGJvZHkgdG8gaW5jbHVkZSBpbiB0aGUgUE9TVCByZXF1ZXN0LlxyXG4gKiBUaGUgZGVmYXVsdCB2YWx1ZSBpcyBhbiBlbXB0eSBvYmplY3QuXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBbcmVxdWVzdE9wdGlvbnM9e31dIC0gT3B0aW9ucyBmb3IgdGhlIEhUVFAvSFRUUFMgcmVxdWVzdC5cclxuICogVGhlIGRlZmF1bHQgdmFsdWUgaXMgYW4gZW1wdHkgb2JqZWN0LlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7UHJvbWlzZTxPYmplY3Q+fSBBIFByb21pc2UgdGhhdCByZXNvbHZlcyB0byB0aGUgSFRUUC9IVFRQUyByZXNwb25zZVxyXG4gKiBvYmplY3Qgd2l0aCBhZGRlZCAndGV4dCcgcHJvcGVydHkgb3IgcmVqZWN0aW5nIHdpdGggYW4gZXJyb3IuXHJcbiAqL1xyXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gcG9zdCh1cmwsIGJvZHkgPSB7fSwgcmVxdWVzdE9wdGlvbnMgPSB7fSkge1xyXG4gIHJldHVybiBuZXcgUHJvbWlzZSgocmVzb2x2ZSwgcmVqZWN0KSA9PiB7XHJcbiAgICBjb25zdCBkYXRhID0gSlNPTi5zdHJpbmdpZnkoYm9keSk7XHJcblxyXG4gICAgLy8gU2V0IGRlZmF1bHQgaGVhZGVycyBhbmQgbWVyZ2Ugd2l0aCByZXF1ZXN0T3B0aW9uc1xyXG4gICAgY29uc3Qgb3B0aW9ucyA9IE9iamVjdC5hc3NpZ24oXHJcbiAgICAgIHtcclxuICAgICAgICBtZXRob2Q6ICdQT1NUJyxcclxuICAgICAgICBoZWFkZXJzOiB7XHJcbiAgICAgICAgICAnQ29udGVudC1UeXBlJzogJ2FwcGxpY2F0aW9uL2pzb24nLFxyXG4gICAgICAgICAgJ0NvbnRlbnQtTGVuZ3RoJzogZGF0YS5sZW5ndGhcclxuICAgICAgICB9XHJcbiAgICAgIH0sXHJcbiAgICAgIHJlcXVlc3RPcHRpb25zXHJcbiAgICApO1xyXG5cclxuICAgIGNvbnN0IHJlcXVlc3QgPSBfZ2V0UHJvdG9jb2xNb2R1bGUodXJsKVxyXG4gICAgICAucmVxdWVzdCh1cmwsIG9wdGlvbnMsIChyZXNwb25zZSkgPT4ge1xyXG4gICAgICAgIGxldCByZXNwb25zZURhdGEgPSAnJztcclxuXHJcbiAgICAgICAgLy8gQSBjaHVuayBvZiBkYXRhIGhhcyBiZWVuIHJlY2VpdmVkXHJcbiAgICAgICAgcmVzcG9uc2Uub24oJ2RhdGEnLCAoY2h1bmspID0+IHtcclxuICAgICAgICAgIHJlc3BvbnNlRGF0YSArPSBjaHVuaztcclxuICAgICAgICB9KTtcclxuXHJcbiAgICAgICAgLy8gVGhlIHdob2xlIHJlc3BvbnNlIGhhcyBiZWVuIHJlY2VpdmVkXHJcbiAgICAgICAgcmVzcG9uc2Uub24oJ2VuZCcsICgpID0+IHtcclxuICAgICAgICAgIHRyeSB7XHJcbiAgICAgICAgICAgIHJlc3BvbnNlLnRleHQgPSByZXNwb25zZURhdGE7XHJcbiAgICAgICAgICAgIHJlc29sdmUocmVzcG9uc2UpO1xyXG4gICAgICAgICAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICAgICAgICAgcmVqZWN0KGVycm9yKTtcclxuICAgICAgICAgIH1cclxuICAgICAgICB9KTtcclxuICAgICAgfSlcclxuICAgICAgLm9uKCdlcnJvcicsIChlcnJvcikgPT4ge1xyXG4gICAgICAgIHJlamVjdChlcnJvcik7XHJcbiAgICAgIH0pO1xyXG5cclxuICAgIC8vIFdyaXRlIHRoZSByZXF1ZXN0IGJvZHkgYW5kIGVuZCB0aGUgcmVxdWVzdFxyXG4gICAgcmVxdWVzdC53cml0ZShkYXRhKTtcclxuICAgIHJlcXVlc3QuZW5kKCk7XHJcbiAgfSk7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBSZXR1cm5zIHRoZSBIVFRQIG9yIEhUVFBTIHByb3RvY29sIG1vZHVsZSBiYXNlZCBvbiB0aGUgcHJvdmlkZWQgVVJMLlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gX2dldFByb3RvY29sTW9kdWxlXHJcbiAqXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSB1cmwgLSBUaGUgVVJMIHRvIGRldGVybWluZSB0aGUgcHJvdG9jb2wuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtPYmplY3R9IFRoZSBIVFRQIG9yIEhUVFBTIHByb3RvY29sIG1vZHVsZSAoaHR0cCBvciBodHRwcykuXHJcbiAqL1xyXG5mdW5jdGlvbiBfZ2V0UHJvdG9jb2xNb2R1bGUodXJsKSB7XHJcbiAgcmV0dXJuIHVybC5zdGFydHNXaXRoKCdodHRwcycpID8gaHR0cHMgOiBodHRwO1xyXG59XHJcblxyXG5leHBvcnQgZGVmYXVsdCB7XHJcbiAgZmV0Y2gsXHJcbiAgcG9zdFxyXG59O1xyXG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxyXG5cclxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXHJcblxyXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNSwgSGlnaHNvZnRcclxuXHJcbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cclxuXHJcbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxyXG5cclxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxyXG5cclxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cclxuXHJcbi8qKlxyXG4gKiBBIGN1c3RvbSBlcnJvciBjbGFzcyBmb3IgaGFuZGxpbmcgZXhwb3J0LXJlbGF0ZWQgZXJyb3JzLiBFeHRlbmRzIHRoZSBuYXRpdmVcclxuICogYEVycm9yYCBjbGFzcyB0byBpbmNsdWRlIGFkZGl0aW9uYWwgcHJvcGVydGllcyBsaWtlIHN0YXR1cyBjb2RlIGFuZCBzdGFja1xyXG4gKiB0cmFjZSBkZXRhaWxzLlxyXG4gKi9cclxuY2xhc3MgRXhwb3J0RXJyb3IgZXh0ZW5kcyBFcnJvciB7XHJcbiAgLyoqXHJcbiAgICogQ3JlYXRlcyBhbiBpbnN0YW5jZSBvZiB0aGUgYEV4cG9ydEVycm9yYC5cclxuICAgKlxyXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBtZXNzYWdlIC0gVGhlIGVycm9yIG1lc3NhZ2UgdG8gYmUgZGlzcGxheWVkLlxyXG4gICAqIEBwYXJhbSB7bnVtYmVyfSBzdGF0dXNDb2RlIC0gT3B0aW9uYWwgSFRUUCBzdGF0dXMgY29kZSBhc3NvY2lhdGVkXHJcbiAgICogd2l0aCB0aGUgZXJyb3IgKGUuZy4sIDQwMCwgNTAwKS5cclxuICAgKi9cclxuICBjb25zdHJ1Y3RvcihtZXNzYWdlLCBzdGF0dXNDb2RlKSB7XHJcbiAgICBzdXBlcigpO1xyXG5cclxuICAgIHRoaXMubWVzc2FnZSA9IG1lc3NhZ2U7XHJcbiAgICB0aGlzLnN0YWNrTWVzc2FnZSA9IG1lc3NhZ2U7XHJcblxyXG4gICAgaWYgKHN0YXR1c0NvZGUpIHtcclxuICAgICAgdGhpcy5zdGF0dXNDb2RlID0gc3RhdHVzQ29kZTtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIC8qKlxyXG4gICAqIFNldHMgb3IgdXBkYXRlcyB0aGUgSFRUUCBzdGF0dXMgY29kZSBmb3IgdGhlIGVycm9yLlxyXG4gICAqXHJcbiAgICogQHBhcmFtIHtudW1iZXJ9IHN0YXR1c0NvZGUgLSBUaGUgSFRUUCBzdGF0dXMgY29kZSB0byBhc3NpZ24gdG8gdGhlIGVycm9yLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge0V4cG9ydEVycm9yfSBUaGUgdXBkYXRlZCBpbnN0YW5jZSBvZiB0aGUgYEV4cG9ydEVycm9yYCBjbGFzcy5cclxuICAgKi9cclxuICBzZXRTdGF0dXMoc3RhdHVzQ29kZSkge1xyXG4gICAgdGhpcy5zdGF0dXNDb2RlID0gc3RhdHVzQ29kZTtcclxuXHJcbiAgICByZXR1cm4gdGhpcztcclxuICB9XHJcblxyXG4gIC8qKlxyXG4gICAqIFNldHMgYWRkaXRpb25hbCBlcnJvciBkZXRhaWxzIGJhc2VkIG9uIGFuIGV4aXN0aW5nIGVycm9yIG9iamVjdC5cclxuICAgKlxyXG4gICAqIEBwYXJhbSB7RXJyb3J9IGVycm9yIC0gQW4gZXJyb3Igb2JqZWN0IGNvbnRhaW5pbmcgZGV0YWlscyB0byBwb3B1bGF0ZVxyXG4gICAqIHRoZSBgRXhwb3J0RXJyb3JgIGluc3RhbmNlLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge0V4cG9ydEVycm9yfSBUaGUgdXBkYXRlZCBpbnN0YW5jZSBvZiB0aGUgYEV4cG9ydEVycm9yYCBjbGFzcy5cclxuICAgKi9cclxuICBzZXRFcnJvcihlcnJvcikge1xyXG4gICAgdGhpcy5lcnJvciA9IGVycm9yO1xyXG5cclxuICAgIGlmIChlcnJvci5uYW1lKSB7XHJcbiAgICAgIHRoaXMubmFtZSA9IGVycm9yLm5hbWU7XHJcbiAgICB9XHJcblxyXG4gICAgaWYgKGVycm9yLnN0YXR1c0NvZGUpIHtcclxuICAgICAgdGhpcy5zdGF0dXNDb2RlID0gZXJyb3Iuc3RhdHVzQ29kZTtcclxuICAgIH1cclxuXHJcbiAgICBpZiAoZXJyb3Iuc3RhY2spIHtcclxuICAgICAgdGhpcy5zdGFja01lc3NhZ2UgPSBlcnJvci5tZXNzYWdlO1xyXG4gICAgICB0aGlzLnN0YWNrID0gZXJyb3Iuc3RhY2s7XHJcbiAgICB9XHJcblxyXG4gICAgcmV0dXJuIHRoaXM7XHJcbiAgfVxyXG59XHJcblxyXG5leHBvcnQgZGVmYXVsdCBFeHBvcnRFcnJvcjtcclxuIiwiLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcclxuXHJcbkhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlclxyXG5cclxuQ29weXJpZ2h0IChjKSAyMDE2LTIwMjUsIEhpZ2hzb2Z0XHJcblxyXG5MaWNlbmNlZCB1bmRlciB0aGUgTUlUIGxpY2VuY2UuXHJcblxyXG5BZGRpdGlvbmFsbHkgYSB2YWxpZCBIaWdoY2hhcnRzIGxpY2Vuc2UgaXMgcmVxdWlyZWQgZm9yIHVzZS5cclxuXHJcblNlZSBMSUNFTlNFIGZpbGUgaW4gcm9vdCBmb3IgZGV0YWlscy5cclxuXHJcbioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXHJcblxyXG4vKipcclxuICogQG92ZXJ2aWV3IFRoZSBjYWNoZSBtYW5hZ2VyIGlzIHJlc3BvbnNpYmxlIGZvciBoYW5kbGluZyBhbmQgbWFuYWdpbmdcclxuICogdGhlIEhpZ2hjaGFydHMgbGlicmFyeSBhbG9uZyB3aXRoIGl0cyBkZXBlbmRlbmNpZXMuIEl0IGVuc3VyZXMgdGhhdCB0aGVzZVxyXG4gKiByZXNvdXJjZXMgYXJlIHN0b3JlZCBhbmQgcmV0cmlldmVkIGVmZmljaWVudGx5IHRvIG9wdGltaXplIHBlcmZvcm1hbmNlXHJcbiAqIGFuZCByZWR1Y2UgcmVkdW5kYW50IG5ldHdvcmsgcmVxdWVzdHMuIFRoZSBjYWNoZSBpcyBzdG9yZWQgaW4gdGhlIGAuY2FjaGVgXHJcbiAqIGRpcmVjdG9yeSBieSBkZWZhdWx0LCB3aGljaCBzZXJ2ZXMgYXMgYSBkZWRpY2F0ZWQgZm9sZGVyIGZvciBrZWVwaW5nIGNhY2hlZFxyXG4gKiBmaWxlcy5cclxuICovXHJcblxyXG5pbXBvcnQgeyBleGlzdHNTeW5jLCBta2RpclN5bmMsIHJlYWRGaWxlU3luYywgd3JpdGVGaWxlU3luYyB9IGZyb20gJ2ZzJztcclxuaW1wb3J0IHsgam9pbiB9IGZyb20gJ3BhdGgnO1xyXG5cclxuaW1wb3J0IHsgSHR0cHNQcm94eUFnZW50IH0gZnJvbSAnaHR0cHMtcHJveHktYWdlbnQnO1xyXG5cclxuaW1wb3J0IHsgZ2V0T3B0aW9ucyB9IGZyb20gJy4vY29uZmlnLmpzJztcclxuaW1wb3J0IHsgZmV0Y2ggfSBmcm9tICcuL2ZldGNoLmpzJztcclxuaW1wb3J0IHsgbG9nIH0gZnJvbSAnLi9sb2dnZXIuanMnO1xyXG5pbXBvcnQgeyBfX2Rpcm5hbWUsIGdldEFic29sdXRlUGF0aCB9IGZyb20gJy4vdXRpbHMuanMnO1xyXG5cclxuaW1wb3J0IEV4cG9ydEVycm9yIGZyb20gJy4vZXJyb3JzL0V4cG9ydEVycm9yLmpzJztcclxuXHJcbi8vIFRoZSBpbml0aWFsIGNhY2hlIHRlbXBsYXRlXHJcbmNvbnN0IGNhY2hlID0ge1xyXG4gIGNkblVybDogJ2h0dHBzOi8vY29kZS5oaWdoY2hhcnRzLmNvbScsXHJcbiAgYWN0aXZlTWFuaWZlc3Q6IHt9LFxyXG4gIHNvdXJjZXM6ICcnLFxyXG4gIGhjVmVyc2lvbjogJydcclxufTtcclxuXHJcbi8qKlxyXG4gKiBDaGVja3MgdGhlIGNhY2hlIGZvciBIaWdoY2hhcnRzIGRlcGVuZGVuY2llcywgdXBkYXRlcyB0aGUgY2FjaGUgaWYgbmVlZGVkLFxyXG4gKiBhbmQgbG9hZHMgdGhlIHNvdXJjZXMuXHJcbiAqXHJcbiAqIEBhc3luY1xyXG4gKiBAZnVuY3Rpb24gY2hlY2tBbmRVcGRhdGVDYWNoZVxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gaGlnaGNoYXJ0c09wdGlvbnMgLSBUaGUgY29uZmlndXJhdGlvbiBvYmplY3QgY29udGFpbmluZ1xyXG4gKiBgaGlnaGNoYXJ0c2Agb3B0aW9ucy5cclxuICogQHBhcmFtIHtPYmplY3R9IHNlcnZlclByb3h5T3B0aW9ucy0gVGhlIGNvbmZpZ3VyYXRpb24gb2JqZWN0IGNvbnRhaW5pbmdcclxuICogYHNlcnZlci5wcm94eWAgb3B0aW9ucy5cclxuICovXHJcbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBjaGVja0FuZFVwZGF0ZUNhY2hlKFxyXG4gIGhpZ2hjaGFydHNPcHRpb25zLFxyXG4gIHNlcnZlclByb3h5T3B0aW9uc1xyXG4pIHtcclxuICB0cnkge1xyXG4gICAgbGV0IGZldGNoZWRNb2R1bGVzO1xyXG5cclxuICAgIC8vIEdldCB0aGUgY2FjaGUgcGF0aFxyXG4gICAgY29uc3QgY2FjaGVQYXRoID0gZ2V0Q2FjaGVQYXRoKCk7XHJcblxyXG4gICAgLy8gUHJlcGFyZSBwYXRocyB0byBtYW5pZmVzdCBhbmQgc291cmNlcyBmcm9tIHRoZSBjYWNoZSBmb2xkZXJcclxuICAgIGNvbnN0IG1hbmlmZXN0UGF0aCA9IGpvaW4oY2FjaGVQYXRoLCAnbWFuaWZlc3QuanNvbicpO1xyXG4gICAgY29uc3Qgc291cmNlUGF0aCA9IGpvaW4oY2FjaGVQYXRoLCAnc291cmNlcy5qcycpO1xyXG5cclxuICAgIC8vIENyZWF0ZSB0aGUgY2FjaGUgZGVzdGluYXRpb24gaWYgaXQgZG9lc24ndCBleGlzdCBhbHJlYWR5XHJcbiAgICAhZXhpc3RzU3luYyhjYWNoZVBhdGgpICYmIG1rZGlyU3luYyhjYWNoZVBhdGgsIHsgcmVjdXJzaXZlOiB0cnVlIH0pO1xyXG5cclxuICAgIC8vIEZldGNoIGFsbCB0aGUgc2NyaXB0cyBlaXRoZXIgaWYgdGhlIGBtYW5pZmVzdC5qc29uYCBkb2VzIG5vdCBleGlzdFxyXG4gICAgLy8gb3IgaWYgdGhlIGBmb3JjZUZldGNoYCBvcHRpb24gaXMgZW5hYmxlZFxyXG4gICAgaWYgKCFleGlzdHNTeW5jKG1hbmlmZXN0UGF0aCkgfHwgaGlnaGNoYXJ0c09wdGlvbnMuZm9yY2VGZXRjaCkge1xyXG4gICAgICBsb2coMywgJ1tjYWNoZV0gRmV0Y2hpbmcgYW5kIGNhY2hpbmcgSGlnaGNoYXJ0cyBkZXBlbmRlbmNpZXMuJyk7XHJcbiAgICAgIGZldGNoZWRNb2R1bGVzID0gYXdhaXQgX3VwZGF0ZUNhY2hlKFxyXG4gICAgICAgIGhpZ2hjaGFydHNPcHRpb25zLFxyXG4gICAgICAgIHNlcnZlclByb3h5T3B0aW9ucyxcclxuICAgICAgICBzb3VyY2VQYXRoXHJcbiAgICAgICk7XHJcbiAgICB9IGVsc2Uge1xyXG4gICAgICBsZXQgcmVxdWVzdFVwZGF0ZSA9IGZhbHNlO1xyXG5cclxuICAgICAgLy8gUmVhZCB0aGUgbWFuaWZlc3QgSlNPTlxyXG4gICAgICBjb25zdCBtYW5pZmVzdCA9IEpTT04ucGFyc2UocmVhZEZpbGVTeW5jKG1hbmlmZXN0UGF0aCksICd1dGY4Jyk7XHJcblxyXG4gICAgICAvLyBDaGVjayBpZiB0aGUgbW9kdWxlcyBpcyBhbiBhcnJheSwgaWYgc28sIHdlIHJld3JpdGUgaXQgdG8gYSBtYXAgdG8gbWFrZVxyXG4gICAgICAvLyBpdCBlYXNpZXIgdG8gcmVzb2x2ZSBtb2R1bGVzLlxyXG4gICAgICBpZiAobWFuaWZlc3QubW9kdWxlcyAmJiBBcnJheS5pc0FycmF5KG1hbmlmZXN0Lm1vZHVsZXMpKSB7XHJcbiAgICAgICAgY29uc3QgbW9kdWxlTWFwID0ge307XHJcbiAgICAgICAgbWFuaWZlc3QubW9kdWxlcy5mb3JFYWNoKChtKSA9PiAobW9kdWxlTWFwW21dID0gMSkpO1xyXG4gICAgICAgIG1hbmlmZXN0Lm1vZHVsZXMgPSBtb2R1bGVNYXA7XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIC8vIEdldCB0aGUgYWN0dWFsIG51bWJlciBvZiBzY3JpcHRzIHRvIGJlIGZldGNoZWRcclxuICAgICAgY29uc3QgeyBjb3JlU2NyaXB0cywgbW9kdWxlU2NyaXB0cywgaW5kaWNhdG9yU2NyaXB0cyB9ID1cclxuICAgICAgICBoaWdoY2hhcnRzT3B0aW9ucztcclxuICAgICAgY29uc3QgbnVtYmVyT2ZNb2R1bGVzID1cclxuICAgICAgICBjb3JlU2NyaXB0cy5sZW5ndGggKyBtb2R1bGVTY3JpcHRzLmxlbmd0aCArIGluZGljYXRvclNjcmlwdHMubGVuZ3RoO1xyXG5cclxuICAgICAgLy8gQ29tcGFyZSB0aGUgbG9hZGVkIGhpZ2hjaGFydHMgY29uZmlnIHdpdGggdGhlIGNvbnRlbnRzIGluIGNhY2hlLlxyXG4gICAgICAvLyBJZiB0aGVyZSBhcmUgY2hhbmdlcywgZmV0Y2ggcmVxdWVzdGVkIG1vZHVsZXMgYW5kIHByb2R1Y3RzLFxyXG4gICAgICAvLyBhbmQgYmFrZSB0aGVtIGludG8gYSBnaWFudCBibG9iLiBTYXZlIHRoZSBibG9iLlxyXG4gICAgICBpZiAobWFuaWZlc3QudmVyc2lvbiAhPT0gaGlnaGNoYXJ0c09wdGlvbnMudmVyc2lvbikge1xyXG4gICAgICAgIGxvZyhcclxuICAgICAgICAgIDIsXHJcbiAgICAgICAgICAnW2NhY2hlXSBBIEhpZ2hjaGFydHMgdmVyc2lvbiBtaXNtYXRjaCBpbiB0aGUgY2FjaGUsIG5lZWQgdG8gcmUtZmV0Y2guJ1xyXG4gICAgICAgICk7XHJcbiAgICAgICAgcmVxdWVzdFVwZGF0ZSA9IHRydWU7XHJcbiAgICAgIH0gZWxzZSBpZiAoXHJcbiAgICAgICAgT2JqZWN0LmtleXMobWFuaWZlc3QubW9kdWxlcyB8fCB7fSkubGVuZ3RoICE9PSBudW1iZXJPZk1vZHVsZXNcclxuICAgICAgKSB7XHJcbiAgICAgICAgbG9nKFxyXG4gICAgICAgICAgMixcclxuICAgICAgICAgICdbY2FjaGVdIFRoZSBjYWNoZSBhbmQgdGhlIHJlcXVlc3RlZCBtb2R1bGVzIGRvIG5vdCBtYXRjaCwgbmVlZCB0byByZS1mZXRjaC4nXHJcbiAgICAgICAgKTtcclxuICAgICAgICByZXF1ZXN0VXBkYXRlID0gdHJ1ZTtcclxuICAgICAgfSBlbHNlIHtcclxuICAgICAgICAvLyBDaGVjayBlYWNoIG1vZHVsZSwgaWYgYW55dGhpbmcgaXMgbWlzc2luZyByZWZldGNoIGV2ZXJ5dGhpbmdcclxuICAgICAgICByZXF1ZXN0VXBkYXRlID0gKG1vZHVsZVNjcmlwdHMgfHwgW10pLnNvbWUoKG1vZHVsZU5hbWUpID0+IHtcclxuICAgICAgICAgIGlmICghbWFuaWZlc3QubW9kdWxlc1ttb2R1bGVOYW1lXSkge1xyXG4gICAgICAgICAgICBsb2coXHJcbiAgICAgICAgICAgICAgMixcclxuICAgICAgICAgICAgICBgW2NhY2hlXSBUaGUgJHttb2R1bGVOYW1lfSBpcyBtaXNzaW5nIGluIHRoZSBjYWNoZSwgbmVlZCB0byByZS1mZXRjaC5gXHJcbiAgICAgICAgICAgICk7XHJcbiAgICAgICAgICAgIHJldHVybiB0cnVlO1xyXG4gICAgICAgICAgfVxyXG4gICAgICAgIH0pO1xyXG4gICAgICB9XHJcblxyXG4gICAgICAvLyBVcGRhdGUgY2FjaGUgaWYgbmVlZGVkXHJcbiAgICAgIGlmIChyZXF1ZXN0VXBkYXRlKSB7XHJcbiAgICAgICAgZmV0Y2hlZE1vZHVsZXMgPSBhd2FpdCBfdXBkYXRlQ2FjaGUoXHJcbiAgICAgICAgICBoaWdoY2hhcnRzT3B0aW9ucyxcclxuICAgICAgICAgIHNlcnZlclByb3h5T3B0aW9ucyxcclxuICAgICAgICAgIHNvdXJjZVBhdGhcclxuICAgICAgICApO1xyXG4gICAgICB9IGVsc2Uge1xyXG4gICAgICAgIGxvZygzLCAnW2NhY2hlXSBEZXBlbmRlbmN5IGNhY2hlIGlzIHVwIHRvIGRhdGUsIHByb2NlZWRpbmcuJyk7XHJcblxyXG4gICAgICAgIC8vIExvYWQgdGhlIHNvdXJjZXNcclxuICAgICAgICBjYWNoZS5zb3VyY2VzID0gcmVhZEZpbGVTeW5jKHNvdXJjZVBhdGgsICd1dGY4Jyk7XHJcblxyXG4gICAgICAgIC8vIEdldCBjdXJyZW50IG1vZHVsZXMgbWFwXHJcbiAgICAgICAgZmV0Y2hlZE1vZHVsZXMgPSBtYW5pZmVzdC5tb2R1bGVzO1xyXG5cclxuICAgICAgICAvLyBFeHRyYWN0IGFuZCBzYXZlIHZlcnNpb24gb2YgY3VycmVudGx5IHVzZWQgSGlnaGNoYXJ0c1xyXG4gICAgICAgIGNhY2hlLmhjVmVyc2lvbiA9IGV4dHJhY3RWZXJzaW9uKGNhY2hlLnNvdXJjZXMpO1xyXG4gICAgICB9XHJcbiAgICB9XHJcblxyXG4gICAgLy8gRmluYWxseSwgc2F2ZSB0aGUgbmV3IG1hbmlmZXN0LCB3aGljaCBpcyBiYXNpY2FsbHkgb3VyIGN1cnJlbnQgY29uZmlnXHJcbiAgICAvLyBpbiBhIHNsaWdodGx5IGRpZmZlcmVudCBmb3JtYXRcclxuICAgIGF3YWl0IF9zYXZlQ29uZmlnVG9NYW5pZmVzdChoaWdoY2hhcnRzT3B0aW9ucywgZmV0Y2hlZE1vZHVsZXMpO1xyXG4gIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoXHJcbiAgICAgICdbY2FjaGVdIENvdWxkIG5vdCBjb25maWd1cmUgY2FjaGUgYW5kIGNyZWF0ZSBvciB1cGRhdGUgdGhlIGNvbmZpZyBtYW5pZmVzdC4nLFxyXG4gICAgICA1MDBcclxuICAgICkuc2V0RXJyb3IoZXJyb3IpO1xyXG4gIH1cclxufVxyXG5cclxuLyoqXHJcbiAqIEdldHMgdGhlIHZlcnNpb24gb2YgSGlnaGNoYXJ0cyBmcm9tIHRoZSBjYWNoZS5cclxuICpcclxuICogQGZ1bmN0aW9uIGdldEhpZ2hjaGFydHNWZXJzaW9uXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtzdHJpbmd9IFRoZSBjYWNoZWQgSGlnaGNoYXJ0cyB2ZXJzaW9uLlxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIGdldEhpZ2hjaGFydHNWZXJzaW9uKCkge1xyXG4gIHJldHVybiBjYWNoZS5oY1ZlcnNpb247XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBVcGRhdGVzIHRoZSBIaWdoY2hhcnRzIHZlcnNpb24gaW4gdGhlIGFwcGxpZWQgY29uZmlndXJhdGlvbiBhbmQgY2hlY2tzXHJcbiAqIHRoZSBjYWNoZSBmb3IgdGhlIG5ldyB2ZXJzaW9uLlxyXG4gKlxyXG4gKiBAYXN5bmNcclxuICogQGZ1bmN0aW9uIHVwZGF0ZUhpZ2hjaGFydHNWZXJzaW9uXHJcbiAqXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSBuZXdWZXJzaW9uIC0gVGhlIG5ldyBIaWdoY2hhcnRzIHZlcnNpb24gdG8gYmUgYXBwbGllZC5cclxuICovXHJcbmV4cG9ydCBhc3luYyBmdW5jdGlvbiB1cGRhdGVIaWdoY2hhcnRzVmVyc2lvbihuZXdWZXJzaW9uKSB7XHJcbiAgLy8gR2V0IHRoZSByZWZlcmVuY2UgdG8gdGhlIGdsb2JhbCBvcHRpb25zIHRvIHVwZGF0ZSB0byB0aGUgbmV3IHZlcnNpb25cclxuICBjb25zdCBvcHRpb25zID0gZ2V0T3B0aW9ucygpO1xyXG5cclxuICAvLyBTZXQgdG8gdGhlIG5ldyB2ZXJzaW9uXHJcbiAgb3B0aW9ucy5oaWdoY2hhcnRzLnZlcnNpb24gPSBuZXdWZXJzaW9uO1xyXG5cclxuICAvLyBDaGVjayBpZiBjYWNoZSBuZWVkcyB0byBiZSB1cGRhdGVkXHJcbiAgYXdhaXQgY2hlY2tBbmRVcGRhdGVDYWNoZShvcHRpb25zLmhpZ2hjaGFydHMsIG9wdGlvbnMuc2VydmVyLnByb3h5KTtcclxufVxyXG5cclxuLyoqXHJcbiAqIEV4dHJhY3RzIEhpZ2hjaGFydHMgdmVyc2lvbiBmcm9tIHRoZSBjYWNoZSdzIHNvdXJjZXMgc3RyaW5nLlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gZXh0cmFjdFZlcnNpb25cclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IGNhY2hlU291cmNlcyAtIFRoZSBjYWNoZSBzb3VyY2VzIG9iamVjdC5cclxuICpcclxuICogQHJldHVybnMge3N0cmluZ30gVGhlIGV4dHJhY3RlZCBIaWdoY2hhcnRzIHZlcnNpb24uXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gZXh0cmFjdFZlcnNpb24oY2FjaGVTb3VyY2VzKSB7XHJcbiAgcmV0dXJuIGNhY2hlU291cmNlc1xyXG4gICAgLnN1YnN0cmluZygwLCBjYWNoZVNvdXJjZXMuaW5kZXhPZignKi8nKSlcclxuICAgIC5yZXBsYWNlKCcvKicsICcnKVxyXG4gICAgLnJlcGxhY2UoJyovJywgJycpXHJcbiAgICAucmVwbGFjZSgvXFxuL2csICcnKVxyXG4gICAgLnRyaW0oKTtcclxufVxyXG5cclxuLyoqXHJcbiAqIEV4dHJhY3RzIHRoZSBIaWdoY2hhcnRzIG1vZHVsZSBuYW1lIGJhc2VkIG9uIHRoZSBzY3JpcHRQYXRoLlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gZXh0cmFjdE1vZHVsZU5hbWVcclxuICpcclxuICogQHBhcmFtIHtzdHJpbmd9IHNjcmlwdFBhdGggLSBUaGUgcGF0aCBvZiB0aGUgc2NyaXB0IGZyb20gd2hpY2ggdGhlIG1vZHVsZVxyXG4gKiBuYW1lIHdpbGwgYmUgZXh0cmFjdGVkLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7c3RyaW5nfSBUaGUgZXh0cmFjdGVkIG1vZHVsZSBuYW1lLlxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIGV4dHJhY3RNb2R1bGVOYW1lKHNjcmlwdFBhdGgpIHtcclxuICByZXR1cm4gc2NyaXB0UGF0aC5yZXBsYWNlKFxyXG4gICAgLyguKilcXC98KC4qKW1vZHVsZXNcXC98c3RvY2tcXC8oLiopaW5kaWNhdG9yc1xcL3xtYXBzXFwvKC4qKW1vZHVsZXNcXC8vZ2ksXHJcbiAgICAnJ1xyXG4gICk7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBSZXRyaWV2ZXMgdGhlIGN1cnJlbnQgY2FjaGUgb2JqZWN0LlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gZ2V0Q2FjaGVcclxuICpcclxuICogQHJldHVybnMge09iamVjdH0gVGhlIGNhY2hlIG9iamVjdCBjb250YWluaW5nIHZhcmlvdXMgY2FjaGVkIGRhdGEuXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gZ2V0Q2FjaGUoKSB7XHJcbiAgcmV0dXJuIGNhY2hlO1xyXG59XHJcblxyXG4vKipcclxuICogR2V0cyB0aGUgY2FjaGUgcGF0aCBmb3IgSGlnaGNoYXJ0cy5cclxuICpcclxuICogQGZ1bmN0aW9uIGdldENhY2hlUGF0aFxyXG4gKlxyXG4gKiBAcmV0dXJucyB7c3RyaW5nfSBUaGUgYWJzb2x1dGUgcGF0aCB0byB0aGUgY2FjaGUgZGlyZWN0b3J5IGZvciBIaWdoY2hhcnRzLlxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIGdldENhY2hlUGF0aCgpIHtcclxuICByZXR1cm4gZ2V0QWJzb2x1dGVQYXRoKGdldE9wdGlvbnMoKS5oaWdoY2hhcnRzLmNhY2hlUGF0aCwgJ3V0ZjgnKTsgLy8gIzU2MlxyXG59XHJcblxyXG4vKipcclxuICogRmV0Y2hlcyBhIHNpbmdsZSBzY3JpcHQgYW5kIHVwZGF0ZXMgdGhlIGBmZXRjaGVkTW9kdWxlc2AgYWNjb3JkaW5nbHkuXHJcbiAqXHJcbiAqIEBhc3luY1xyXG4gKiBAZnVuY3Rpb24gX2ZldGNoQW5kUHJvY2Vzc1NjcmlwdFxyXG4gKlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gc2NyaXB0IC0gQSBwYXRoIHRvIHNjcmlwdCB0byBnZXQuXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSByZXF1ZXN0T3B0aW9ucyAtIEFkZGl0aW9uYWwgb3B0aW9ucyBmb3IgdGhlIHByb3h5IGFnZW50XHJcbiAqIHRvIHVzZSBmb3IgYSByZXF1ZXN0LlxyXG4gKiBAcGFyYW0ge09iamVjdH0gZmV0Y2hlZE1vZHVsZXMgLSBBbiBvYmplY3Qgd2hpY2ggdHJhY2tzIHdoaWNoIEhpZ2hjaGFydHNcclxuICogbW9kdWxlcyBoYXZlIGJlZW4gZmV0Y2hlZC5cclxuICogQHBhcmFtIHtib29sZWFufSBbc2hvdWxkVGhyb3dFcnJvcj1mYWxzZV0gLSBBIGZsYWcgdG8gaW5kaWNhdGUgaWYgdGhlIGVycm9yXHJcbiAqIHNob3VsZCBiZSB0aHJvd24uIFRoaXMgc2hvdWxkIGJlIHVzZWQgb25seSBmb3IgdGhlIGNvcmUgc2NyaXB0cy4gVGhlIGRlZmF1bHRcclxuICogdmFsdWUgaXMgYGZhbHNlYC5cclxuICpcclxuICogQHJldHVybnMge1Byb21pc2U8c3RyaW5nPn0gQSBQcm9taXNlIHRoYXQgcmVzb2x2ZXMgdG8gdGhlIHRleHQgcmVwcmVzZW50YXRpb25cclxuICogb2YgdGhlIGZldGNoZWQgc2NyaXB0LlxyXG4gKlxyXG4gKiBAdGhyb3dzIHtFeHBvcnRFcnJvcn0gVGhyb3dzIGFuIGBFeHBvcnRFcnJvcmAgaWYgdGhlcmUgaXMgYSBwcm9ibGVtXHJcbiAqIHdpdGggZmV0Y2hpbmcgdGhlIHNjcmlwdC5cclxuICovXHJcbmFzeW5jIGZ1bmN0aW9uIF9mZXRjaEFuZFByb2Nlc3NTY3JpcHQoXHJcbiAgc2NyaXB0LFxyXG4gIHJlcXVlc3RPcHRpb25zLFxyXG4gIGZldGNoZWRNb2R1bGVzLFxyXG4gIHNob3VsZFRocm93RXJyb3IgPSBmYWxzZVxyXG4pIHtcclxuICAvLyBHZXQgcmlkIG9mIHRoZSAuanMgZnJvbSB0aGUgY3VzdG9tIHN0cmluZ3NcclxuICBpZiAoc2NyaXB0LmVuZHNXaXRoKCcuanMnKSkge1xyXG4gICAgc2NyaXB0ID0gc2NyaXB0LnN1YnN0cmluZygwLCBzY3JpcHQubGVuZ3RoIC0gMyk7XHJcbiAgfVxyXG4gIGxvZyg0LCBgW2NhY2hlXSBGZXRjaGluZyBzY3JpcHQgLSAke3NjcmlwdH0uanNgKTtcclxuXHJcbiAgLy8gRmV0Y2ggdGhlIHNjcmlwdFxyXG4gIGNvbnN0IHJlc3BvbnNlID0gYXdhaXQgZmV0Y2goYCR7c2NyaXB0fS5qc2AsIHJlcXVlc3RPcHRpb25zKTtcclxuXHJcbiAgLy8gSWYgT0ssIHJldHVybiBpdHMgdGV4dCByZXByZXNlbnRhdGlvblxyXG4gIGlmIChyZXNwb25zZS5zdGF0dXNDb2RlID09PSAyMDAgJiYgdHlwZW9mIHJlc3BvbnNlLnRleHQgPT0gJ3N0cmluZycpIHtcclxuICAgIGlmIChmZXRjaGVkTW9kdWxlcykge1xyXG4gICAgICBjb25zdCBtb2R1bGVOYW1lID0gZXh0cmFjdE1vZHVsZU5hbWUoc2NyaXB0KTtcclxuICAgICAgZmV0Y2hlZE1vZHVsZXNbbW9kdWxlTmFtZV0gPSAxO1xyXG4gICAgfVxyXG4gICAgcmV0dXJuIHJlc3BvbnNlLnRleHQ7XHJcbiAgfVxyXG5cclxuICAvLyBCYXNlZCBvbiB0aGUgYHNob3VsZFRocm93RXJyb3JgIGZsYWcsIGRlY2lkZSBob3cgdG8gc2VydmUgZXJyb3IgbWVzc2FnZVxyXG4gIGlmIChzaG91bGRUaHJvd0Vycm9yKSB7XHJcbiAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoXHJcbiAgICAgIGBbY2FjaGVdIENvdWxkIG5vdCBmZXRjaCB0aGUgJHtzY3JpcHR9LmpzLiBUaGUgc2NyaXB0IG1pZ2h0IG5vdCBleGlzdCBpbiB0aGUgcmVxdWVzdGVkIHZlcnNpb24gKHN0YXR1cyBjb2RlOiAke3Jlc3BvbnNlLnN0YXR1c0NvZGV9KS5gLFxyXG4gICAgICA0MDRcclxuICAgICkuc2V0RXJyb3IocmVzcG9uc2UpO1xyXG4gIH0gZWxzZSB7XHJcbiAgICBsb2coXHJcbiAgICAgIDIsXHJcbiAgICAgIGBbY2FjaGVdIENvdWxkIG5vdCBmZXRjaCB0aGUgJHtzY3JpcHR9LmpzLiBUaGUgc2NyaXB0IG1pZ2h0IG5vdCBleGlzdCBpbiB0aGUgcmVxdWVzdGVkIHZlcnNpb24uYFxyXG4gICAgKTtcclxuICB9XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBTYXZlcyB0aGUgcHJvdmlkZWQgY29uZmlndXJhdGlvbiBhbmQgZmV0Y2hlZCBtb2R1bGVzIHRvIHRoZSBjYWNoZSBtYW5pZmVzdFxyXG4gKiBmaWxlLlxyXG4gKlxyXG4gKiBAYXN5bmNcclxuICogQGZ1bmN0aW9uIF9zYXZlQ29uZmlnVG9NYW5pZmVzdFxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gaGlnaGNoYXJ0c09wdGlvbnMgLSBUaGUgY29uZmlndXJhdGlvbiBvYmplY3QgY29udGFpbmluZ1xyXG4gKiBgaGlnaGNoYXJ0c2Agb3B0aW9ucy5cclxuICogQHBhcmFtIHtPYmplY3R9IFtmZXRjaGVkTW9kdWxlcz17fV0gLSBBbiBvYmplY3Qgd2hpY2ggdHJhY2tzIHdoaWNoIEhpZ2hjaGFydHNcclxuICogbW9kdWxlcyBoYXZlIGJlZW4gZmV0Y2hlZC4gVGhlIGRlZmF1bHQgdmFsdWUgaXMgYW4gZW1wdHkgb2JqZWN0LlxyXG4gKlxyXG4gKiBAdGhyb3dzIHtFeHBvcnRFcnJvcn0gVGhyb3dzIGFuIGBFeHBvcnRFcnJvcmAgaWYgYW4gZXJyb3Igb2NjdXJzIHdoaWxlXHJcbiAqIHdyaXRpbmcgdGhlIGNhY2hlIG1hbmlmZXN0LlxyXG4gKi9cclxuYXN5bmMgZnVuY3Rpb24gX3NhdmVDb25maWdUb01hbmlmZXN0KGhpZ2hjaGFydHNPcHRpb25zLCBmZXRjaGVkTW9kdWxlcyA9IHt9KSB7XHJcbiAgY29uc3QgbmV3TWFuaWZlc3QgPSB7XHJcbiAgICB2ZXJzaW9uOiBoaWdoY2hhcnRzT3B0aW9ucy52ZXJzaW9uLFxyXG4gICAgbW9kdWxlczogZmV0Y2hlZE1vZHVsZXNcclxuICB9O1xyXG5cclxuICAvLyBVcGRhdGUgY2FjaGUgb2JqZWN0IHdpdGggdGhlIGN1cnJlbnQgbW9kdWxlc1xyXG4gIGNhY2hlLmFjdGl2ZU1hbmlmZXN0ID0gbmV3TWFuaWZlc3Q7XHJcblxyXG4gIGxvZygzLCAnW2NhY2hlXSBXcml0aW5nIGEgbmV3IG1hbmlmZXN0LicpO1xyXG4gIHRyeSB7XHJcbiAgICB3cml0ZUZpbGVTeW5jKFxyXG4gICAgICBqb2luKGdldENhY2hlUGF0aCgpLCAnbWFuaWZlc3QuanNvbicpLFxyXG4gICAgICBKU09OLnN0cmluZ2lmeShuZXdNYW5pZmVzdCksXHJcbiAgICAgICd1dGY4J1xyXG4gICAgKTtcclxuICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgdGhyb3cgbmV3IEV4cG9ydEVycm9yKFxyXG4gICAgICAnW2NhY2hlXSBFcnJvciB3cml0aW5nIHRoZSBjYWNoZSBtYW5pZmVzdC4nLFxyXG4gICAgICA1MDBcclxuICAgICkuc2V0RXJyb3IoZXJyb3IpO1xyXG4gIH1cclxufVxyXG5cclxuLyoqXHJcbiAqIEZldGNoZXMgSGlnaGNoYXJ0cyBgc2NyaXB0c2AgYW5kIGBjdXN0b21TY3JpcHRzYCBmcm9tIHRoZSBnaXZlbiBDRE5zLlxyXG4gKlxyXG4gKiBAYXN5bmNcclxuICogQGZ1bmN0aW9uIF9mZXRjaFNjcmlwdHNcclxuICpcclxuICogQHBhcmFtIHtBcnJheS48c3RyaW5nPn0gY29yZVNjcmlwdHMgLSBIaWdoY2hhcnRzIGNvcmUgc2NyaXB0cyB0byBmZXRjaC5cclxuICogQHBhcmFtIHtBcnJheS48c3RyaW5nPn0gbW9kdWxlU2NyaXB0cyAtIEhpZ2hjaGFydHMgbW9kdWxlcyB0byBmZXRjaC5cclxuICogQHBhcmFtIHtBcnJheS48c3RyaW5nPn0gY3VzdG9tU2NyaXB0cyAtIEN1c3RvbSBzY3JpcHQgcGF0aHMgdG8gZmV0Y2ggKGZ1bGxcclxuICogVVJMcykuXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBzZXJ2ZXJQcm94eU9wdGlvbnMgLSBUaGUgY29uZmlndXJhdGlvbiBvYmplY3QgY29udGFpbmluZ1xyXG4gKiBgc2VydmVyLnByb3h5YCBvcHRpb25zLlxyXG4gKiBAcGFyYW0ge09iamVjdH0gZmV0Y2hlZE1vZHVsZXMgLSBBbiBvYmplY3Qgd2hpY2ggdHJhY2tzIHdoaWNoIEhpZ2hjaGFydHNcclxuICogbW9kdWxlcyBoYXZlIGJlZW4gZmV0Y2hlZC5cclxuICpcclxuICogQHJldHVybnMge1Byb21pc2U8c3RyaW5nPn0gQSBQcm9taXNlIHRoYXQgcmVzb2x2ZXMgdG8gdGhlIGZldGNoZWQgc2NyaXB0c1xyXG4gKiBjb250ZW50IGpvaW5lZC5cclxuICpcclxuICogQHRocm93cyB7RXhwb3J0RXJyb3J9IFRocm93cyBhbiBgRXhwb3J0RXJyb3JgIGlmIGFuIGVycm9yIG9jY3VycyB3aGlsZVxyXG4gKiBzZXR0aW5nIGFuIEhUVFAgQWdlbnQgZm9yIHByb3h5LlxyXG4gKi9cclxuYXN5bmMgZnVuY3Rpb24gX2ZldGNoU2NyaXB0cyhcclxuICBjb3JlU2NyaXB0cyxcclxuICBtb2R1bGVTY3JpcHRzLFxyXG4gIGN1c3RvbVNjcmlwdHMsXHJcbiAgc2VydmVyUHJveHlPcHRpb25zLFxyXG4gIGZldGNoZWRNb2R1bGVzXHJcbikge1xyXG4gIC8vIENvbmZpZ3VyZSBwcm94eSBpZiBleGlzdHNcclxuICBsZXQgcHJveHlBZ2VudDtcclxuICBjb25zdCBwcm94eUhvc3QgPSBzZXJ2ZXJQcm94eU9wdGlvbnMuaG9zdDtcclxuICBjb25zdCBwcm94eVBvcnQgPSBzZXJ2ZXJQcm94eU9wdGlvbnMucG9ydDtcclxuXHJcbiAgLy8gVHJ5IHRvIGNyZWF0ZSBhIFByb3h5IEFnZW50XHJcbiAgaWYgKHByb3h5SG9zdCAmJiBwcm94eVBvcnQpIHtcclxuICAgIHRyeSB7XHJcbiAgICAgIHByb3h5QWdlbnQgPSBuZXcgSHR0cHNQcm94eUFnZW50KHtcclxuICAgICAgICBob3N0OiBwcm94eUhvc3QsXHJcbiAgICAgICAgcG9ydDogcHJveHlQb3J0XHJcbiAgICAgIH0pO1xyXG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICAgdGhyb3cgbmV3IEV4cG9ydEVycm9yKFxyXG4gICAgICAgICdbY2FjaGVdIENvdWxkIG5vdCBjcmVhdGUgYSBQcm94eSBBZ2VudC4nLFxyXG4gICAgICAgIDUwMFxyXG4gICAgICApLnNldEVycm9yKGVycm9yKTtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIC8vIElmIGV4aXN0cywgYWRkIHByb3h5IGFnZW50IHRvIHJlcXVlc3Qgb3B0aW9uc1xyXG4gIGNvbnN0IHJlcXVlc3RPcHRpb25zID0gcHJveHlBZ2VudFxyXG4gICAgPyB7XHJcbiAgICAgICAgYWdlbnQ6IHByb3h5QWdlbnQsXHJcbiAgICAgICAgdGltZW91dDogc2VydmVyUHJveHlPcHRpb25zLnRpbWVvdXRcclxuICAgICAgfVxyXG4gICAgOiB7fTtcclxuXHJcbiAgY29uc3QgYWxsRmV0Y2hQcm9taXNlcyA9IFtcclxuICAgIC4uLmNvcmVTY3JpcHRzLm1hcCgoc2NyaXB0KSA9PlxyXG4gICAgICBfZmV0Y2hBbmRQcm9jZXNzU2NyaXB0KGAke3NjcmlwdH1gLCByZXF1ZXN0T3B0aW9ucywgZmV0Y2hlZE1vZHVsZXMsIHRydWUpXHJcbiAgICApLFxyXG4gICAgLi4ubW9kdWxlU2NyaXB0cy5tYXAoKHNjcmlwdCkgPT5cclxuICAgICAgX2ZldGNoQW5kUHJvY2Vzc1NjcmlwdChgJHtzY3JpcHR9YCwgcmVxdWVzdE9wdGlvbnMsIGZldGNoZWRNb2R1bGVzKVxyXG4gICAgKSxcclxuICAgIC4uLmN1c3RvbVNjcmlwdHMubWFwKChzY3JpcHQpID0+XHJcbiAgICAgIF9mZXRjaEFuZFByb2Nlc3NTY3JpcHQoYCR7c2NyaXB0fWAsIHJlcXVlc3RPcHRpb25zKVxyXG4gICAgKVxyXG4gIF07XHJcblxyXG4gIGNvbnN0IGZldGNoZWRTY3JpcHRzID0gYXdhaXQgUHJvbWlzZS5hbGwoYWxsRmV0Y2hQcm9taXNlcyk7XHJcbiAgcmV0dXJuIGZldGNoZWRTY3JpcHRzLmpvaW4oJztcXG4nKTtcclxufVxyXG5cclxuLyoqXHJcbiAqIFVwZGF0ZXMgdGhlIGxvY2FsIGNhY2hlIHdpdGggSGlnaGNoYXJ0cyBzY3JpcHRzIGFuZCB0aGVpciB2ZXJzaW9ucy5cclxuICpcclxuICogQGFzeW5jXHJcbiAqIEBmdW5jdGlvbiBfdXBkYXRlQ2FjaGVcclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IGhpZ2hjaGFydHNPcHRpb25zIC0gVGhlIGNvbmZpZ3VyYXRpb24gb2JqZWN0IGNvbnRhaW5pbmdcclxuICogYGhpZ2hjaGFydHNgIG9wdGlvbnMuXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBzZXJ2ZXJQcm94eU9wdGlvbnMgLSBUaGUgY29uZmlndXJhdGlvbiBvYmplY3QgY29udGFpbmluZ1xyXG4gKiBgc2VydmVyLnByb3h5YCBvcHRpb25zLlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gc291cmNlUGF0aCAtIFRoZSBwYXRoIHRvIHRoZSBzb3VyY2UgZmlsZSBpbiB0aGUgY2FjaGUuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtQcm9taXNlPE9iamVjdD59IEEgUHJvbWlzZSB0aGF0IHJlc29sdmVzIHRvIGFuIG9iamVjdCByZXByZXNlbnRpbmdcclxuICogdGhlIGZldGNoZWQgbW9kdWxlcy5cclxuICpcclxuICogQHRocm93cyB7RXhwb3J0RXJyb3J9IFRocm93cyBhbiBgRXhwb3J0RXJyb3JgIGlmIHRoZXJlIGlzIGFuIGlzc3VlIHVwZGF0aW5nXHJcbiAqIHRoZSBsb2NhbCBIaWdoY2hhcnRzIGNhY2hlLlxyXG4gKi9cclxuYXN5bmMgZnVuY3Rpb24gX3VwZGF0ZUNhY2hlKGhpZ2hjaGFydHNPcHRpb25zLCBzZXJ2ZXJQcm94eU9wdGlvbnMsIHNvdXJjZVBhdGgpIHtcclxuICAvLyBHZXQgSGlnaGNoYXJ0cyB2ZXJzaW9uIGZvciBzY3JpcHRzXHJcbiAgY29uc3QgaGNWZXJzaW9uID1cclxuICAgIGhpZ2hjaGFydHNPcHRpb25zLnZlcnNpb24gPT09ICdsYXRlc3QnXHJcbiAgICAgID8gbnVsbFxyXG4gICAgICA6IGAke2hpZ2hjaGFydHNPcHRpb25zLnZlcnNpb259YDtcclxuXHJcbiAgLy8gR2V0IHRoZSBDRE4gdXJsIGZvciBzY3JpcHRzXHJcbiAgY29uc3QgY2RuVXJsID0gaGlnaGNoYXJ0c09wdGlvbnMuY2RuVXJsIHx8IGNhY2hlLmNkblVybDtcclxuXHJcbiAgdHJ5IHtcclxuICAgIGNvbnN0IGZldGNoZWRNb2R1bGVzID0ge307XHJcblxyXG4gICAgbG9nKFxyXG4gICAgICAzLFxyXG4gICAgICBgW2NhY2hlXSBVcGRhdGluZyBjYWNoZSB2ZXJzaW9uIHRvIEhpZ2hjaGFydHM6ICR7aGNWZXJzaW9uIHx8ICdsYXRlc3QnfS5gXHJcbiAgICApO1xyXG5cclxuICAgIGNhY2hlLnNvdXJjZXMgPSBhd2FpdCBfZmV0Y2hTY3JpcHRzKFxyXG4gICAgICBbXHJcbiAgICAgICAgLi4uaGlnaGNoYXJ0c09wdGlvbnMuY29yZVNjcmlwdHMubWFwKChjKSA9PlxyXG4gICAgICAgICAgaGNWZXJzaW9uID8gYCR7Y2RuVXJsfS8ke2hjVmVyc2lvbn0vJHtjfWAgOiBgJHtjZG5Vcmx9LyR7Y31gXHJcbiAgICAgICAgKVxyXG4gICAgICBdLFxyXG4gICAgICBbXHJcbiAgICAgICAgLi4uaGlnaGNoYXJ0c09wdGlvbnMubW9kdWxlU2NyaXB0cy5tYXAoKG0pID0+XHJcbiAgICAgICAgICBtID09PSAnbWFwJ1xyXG4gICAgICAgICAgICA/IGhjVmVyc2lvblxyXG4gICAgICAgICAgICAgID8gYCR7Y2RuVXJsfS9tYXBzLyR7aGNWZXJzaW9ufS9tb2R1bGVzLyR7bX1gXHJcbiAgICAgICAgICAgICAgOiBgJHtjZG5Vcmx9L21hcHMvbW9kdWxlcy8ke219YFxyXG4gICAgICAgICAgICA6IGhjVmVyc2lvblxyXG4gICAgICAgICAgICAgID8gYCR7Y2RuVXJsfS8ke2hjVmVyc2lvbn0vbW9kdWxlcy8ke219YFxyXG4gICAgICAgICAgICAgIDogYCR7Y2RuVXJsfS9tb2R1bGVzLyR7bX1gXHJcbiAgICAgICAgKSxcclxuICAgICAgICAuLi5oaWdoY2hhcnRzT3B0aW9ucy5pbmRpY2F0b3JTY3JpcHRzLm1hcCgoaSkgPT5cclxuICAgICAgICAgIGhjVmVyc2lvblxyXG4gICAgICAgICAgICA/IGAke2NkblVybH0vc3RvY2svJHtoY1ZlcnNpb259L2luZGljYXRvcnMvJHtpfWBcclxuICAgICAgICAgICAgOiBgJHtjZG5Vcmx9L3N0b2NrL2luZGljYXRvcnMvJHtpfWBcclxuICAgICAgICApXHJcbiAgICAgIF0sXHJcbiAgICAgIGhpZ2hjaGFydHNPcHRpb25zLmN1c3RvbVNjcmlwdHMsXHJcbiAgICAgIHNlcnZlclByb3h5T3B0aW9ucyxcclxuICAgICAgZmV0Y2hlZE1vZHVsZXNcclxuICAgICk7XHJcblxyXG4gICAgLy8gRXh0cmFjdCBhbmQgc2F2ZSB2ZXJzaW9uIG9mIGN1cnJlbnRseSB1c2VkIEhpZ2hjaGFydHNcclxuICAgIGNhY2hlLmhjVmVyc2lvbiA9IGV4dHJhY3RWZXJzaW9uKGNhY2hlLnNvdXJjZXMpO1xyXG5cclxuICAgIC8vIFNhdmUgdGhlIGZldGNoZWQgbW9kdWxlcyBpbnRvIGNhY2hlcycgc291cmNlIEpTT05cclxuICAgIHdyaXRlRmlsZVN5bmMoc291cmNlUGF0aCwgY2FjaGUuc291cmNlcyk7XHJcbiAgICByZXR1cm4gZmV0Y2hlZE1vZHVsZXM7XHJcbiAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcihcclxuICAgICAgJ1tjYWNoZV0gVW5hYmxlIHRvIHVwZGF0ZSB0aGUgbG9jYWwgSGlnaGNoYXJ0cyBjYWNoZS4nLFxyXG4gICAgICA1MDBcclxuICAgICkuc2V0RXJyb3IoZXJyb3IpO1xyXG4gIH1cclxufVxyXG5cclxuZXhwb3J0IGRlZmF1bHQge1xyXG4gIGNoZWNrQW5kVXBkYXRlQ2FjaGUsXHJcbiAgZ2V0SGlnaGNoYXJ0c1ZlcnNpb24sXHJcbiAgdXBkYXRlSGlnaGNoYXJ0c1ZlcnNpb24sXHJcbiAgZXh0cmFjdFZlcnNpb24sXHJcbiAgZXh0cmFjdE1vZHVsZU5hbWUsXHJcbiAgZ2V0Q2FjaGUsXHJcbiAgZ2V0Q2FjaGVQYXRoXHJcbn07XHJcbiIsIi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXHJcblxyXG5IaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXJcclxuXHJcbkNvcHlyaWdodCAoYykgMjAxNi0yMDI1LCBIaWdoc29mdFxyXG5cclxuTGljZW5jZWQgdW5kZXIgdGhlIE1JVCBsaWNlbmNlLlxyXG5cclxuQWRkaXRpb25hbGx5IGEgdmFsaWQgSGlnaGNoYXJ0cyBsaWNlbnNlIGlzIHJlcXVpcmVkIGZvciB1c2UuXHJcblxyXG5TZWUgTElDRU5TRSBmaWxlIGluIHJvb3QgZm9yIGRldGFpbHMuXHJcblxyXG4qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xyXG5cclxuLyoqXHJcbiAqIEBvdmVydmlldyBQcm92aWRlcyBtZXRob2RzIGZvciBpbml0aWFsaXppbmcgSGlnaGNoYXJ0cyB3aXRoIGN1c3RvbWl6ZWRcclxuICogYW5pbWF0aW9uIHNldHRpbmdzIGFuZCB0cmlnZ2VyaW5nIHRoZSBjcmVhdGlvbiBvZiBIaWdoY2hhcnRzIGNoYXJ0cyB3aXRoXHJcbiAqIGV4cG9ydC1zcGVjaWZpYyBjb25maWd1cmF0aW9ucyBpbiB0aGUgcGFnZSBjb250ZXh0LiBTdXBwb3J0cyBkeW5hbWljIG9wdGlvblxyXG4gKiBtZXJnaW5nLCBjdXN0b20gbG9naWMgaW5qZWN0aW9uLCBhbmQgY29udHJvbCBvdmVyIHJlbmRlcmluZyBiZWhhdmlvcnMuIFVzZWRcclxuICogYnkgdGhlIFB1cHBldGVlciBwYWdlLlxyXG4gKi9cclxuXHJcbi8qIGVzbGludC1kaXNhYmxlIG5vLXVuZGVmICovXHJcblxyXG4vKipcclxuICogU2V0dGluZyB0aGUgYEhpZ2hjaGFydHMuYW5pbU9iamVjdGAgZnVuY3Rpb24uIENhbGxlZCB3aGVuIGluaXRpbmcgdGhlIHBhZ2UuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBzZXR1cEhpZ2hjaGFydHNcclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiBzZXR1cEhpZ2hjaGFydHMoKSB7XHJcbiAgSGlnaGNoYXJ0cy5hbmltT2JqZWN0ID0gZnVuY3Rpb24gKCkge1xyXG4gICAgcmV0dXJuIHsgZHVyYXRpb246IDAgfTtcclxuICB9O1xyXG59XHJcblxyXG4vKipcclxuICogQ3JlYXRlcyB0aGUgYWN0dWFsIEhpZ2hjaGFydHMgY2hhcnQgb24gYSBwYWdlLlxyXG4gKlxyXG4gKiBAYXN5bmNcclxuICogQGZ1bmN0aW9uIGNyZWF0ZUNoYXJ0XHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBleHBvcnRPcHRpb25zIC0gVGhlIGNvbmZpZ3VyYXRpb24gb2JqZWN0IGNvbnRhaW5pbmcgYGV4cG9ydGBcclxuICogb3B0aW9ucy5cclxuICogQHBhcmFtIHtPYmplY3R9IGN1c3RvbUxvZ2ljT3B0aW9ucyAtIFRoZSBjb25maWd1cmF0aW9uIG9iamVjdCBjb250YWluaW5nXHJcbiAqIGBjdXN0b21Mb2dpY2Agb3B0aW9ucy5cclxuICpcclxuICovXHJcbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBjcmVhdGVDaGFydChleHBvcnRPcHRpb25zLCBjdXN0b21Mb2dpY09wdGlvbnMpIHtcclxuICAvLyBHZXQgcmVxdWlyZWQgZnVuY3Rpb25zXHJcbiAgY29uc3QgeyBnZXRPcHRpb25zLCBzZXRPcHRpb25zLCBtZXJnZSwgd3JhcCB9ID0gSGlnaGNoYXJ0cztcclxuXHJcbiAgLy8gQ3JlYXRlIGEgc2VwYXJhdGUgb2JqZWN0IGZvciBhIHBvdGVudGlhbCBgc2V0T3B0aW9uc2AgdXNhZ2VzIGluIG9yZGVyXHJcbiAgLy8gdG8gcHJldmVudCBmcm9tIHBvbGx1dGluZyBvdGhlciBleHBvcnRzIHRoYXQgY2FuIGhhcHBlbiBvbiB0aGUgc2FtZSBwYWdlXHJcbiAgSGlnaGNoYXJ0cy5zZXRPcHRpb25zT2JqID0gbWVyZ2UoZmFsc2UsIHt9LCBnZXRPcHRpb25zKCkpO1xyXG5cclxuICAvLyBOT1RFOiBJcyB0aGlzIHVzZWQgZm9yIGFueXRoaW5nIHVzZWZ1bD9cclxuICB3aW5kb3cuaXNSZW5kZXJDb21wbGV0ZSA9IGZhbHNlO1xyXG4gIHdyYXAoSGlnaGNoYXJ0cy5DaGFydC5wcm90b3R5cGUsICdpbml0JywgZnVuY3Rpb24gKHByb2NlZWQsIHVzZXJPcHRpb25zLCBjYikge1xyXG4gICAgLy8gT3ZlcnJpZGUgdGhlIGB1c2VyT3B0aW9uc2Agd2l0aCBpbWFnZSBmcmllbmRseSBvcHRpb25zXHJcbiAgICB1c2VyT3B0aW9ucyA9IG1lcmdlKHVzZXJPcHRpb25zLCB7XHJcbiAgICAgIGV4cG9ydGluZzoge1xyXG4gICAgICAgIGVuYWJsZWQ6IGZhbHNlXHJcbiAgICAgIH0sXHJcbiAgICAgIHBsb3RPcHRpb25zOiB7XHJcbiAgICAgICAgc2VyaWVzOiB7XHJcbiAgICAgICAgICBsYWJlbDoge1xyXG4gICAgICAgICAgICBlbmFibGVkOiBmYWxzZVxyXG4gICAgICAgICAgfVxyXG4gICAgICAgIH1cclxuICAgICAgfSxcclxuICAgICAgLyogRXhwZWN0cyB0b29sdGlwIGluIHRoZSBgdXNlck9wdGlvbnNgIHdoZW4gYGZvckV4cG9ydGAgaXMgdHJ1ZS5cclxuICAgICAgICBodHRwczovL2dpdGh1Yi5jb20vaGlnaGNoYXJ0cy9oaWdoY2hhcnRzL2Jsb2IvM2FkNDMwYTM1M2I4MDU2YjllNzY0YWE0ZTVjZDY4MjhhYTQ3OWRiMi9qcy9wYXJ0cy9DaGFydC5qcyNMMjQxXHJcbiAgICAgICAgKi9cclxuICAgICAgdG9vbHRpcDoge31cclxuICAgIH0pO1xyXG5cclxuICAgICh1c2VyT3B0aW9ucy5zZXJpZXMgfHwgW10pLmZvckVhY2goZnVuY3Rpb24gKHNlcmllcykge1xyXG4gICAgICBzZXJpZXMuYW5pbWF0aW9uID0gZmFsc2U7XHJcbiAgICB9KTtcclxuXHJcbiAgICAvLyBBZGQgZmxhZyB0byBrbm93IGlmIGNoYXJ0IHJlbmRlciBoYXMgYmVlbiBjYWxsZWQuXHJcbiAgICBpZiAoIXdpbmRvdy5vbkhpZ2hjaGFydHNSZW5kZXIpIHtcclxuICAgICAgd2luZG93Lm9uSGlnaGNoYXJ0c1JlbmRlciA9IEhpZ2hjaGFydHMuYWRkRXZlbnQodGhpcywgJ3JlbmRlcicsICgpID0+IHtcclxuICAgICAgICB3aW5kb3cuaXNSZW5kZXJDb21wbGV0ZSA9IHRydWU7XHJcbiAgICAgIH0pO1xyXG4gICAgfVxyXG5cclxuICAgIHByb2NlZWQuYXBwbHkodGhpcywgW3VzZXJPcHRpb25zLCBjYl0pO1xyXG4gIH0pO1xyXG5cclxuICB3cmFwKEhpZ2hjaGFydHMuU2VyaWVzLnByb3RvdHlwZSwgJ2luaXQnLCBmdW5jdGlvbiAocHJvY2VlZCwgY2hhcnQsIG9wdGlvbnMpIHtcclxuICAgIHByb2NlZWQuYXBwbHkodGhpcywgW2NoYXJ0LCBvcHRpb25zXSk7XHJcbiAgfSk7XHJcblxyXG4gIC8vIFNvbWUgbWFuZGF0b3J5IGFkZGl0aW9uYWwgYGNoYXJ0YCBhbmQgYGV4cG9ydGluZ2Agb3B0aW9uc1xyXG4gIGNvbnN0IGFkZGl0aW9uYWxPcHRpb25zID0ge1xyXG4gICAgY2hhcnQ6IHtcclxuICAgICAgLy8gQnkgZGVmYXVsdCBhbmltYXRpb24gaXMgZGlzYWJsZWRcclxuICAgICAgYW5pbWF0aW9uOiBmYWxzZSxcclxuICAgICAgLy8gR2V0IHRoZSByaWdodCBzaXplIHZhbHVlc1xyXG4gICAgICBoZWlnaHQ6IGV4cG9ydE9wdGlvbnMuaGVpZ2h0LFxyXG4gICAgICB3aWR0aDogZXhwb3J0T3B0aW9ucy53aWR0aFxyXG4gICAgfSxcclxuICAgIGV4cG9ydGluZzoge1xyXG4gICAgICAvLyBObyBuZWVkIGZvciB0aGUgZXhwb3J0aW5nIGJ1dHRvblxyXG4gICAgICBlbmFibGVkOiBmYWxzZVxyXG4gICAgfVxyXG4gIH07XHJcblxyXG4gIC8vIEdldCB0aGUgaW5wdXQgdG8gZXhwb3J0IGZyb20gdGhlIGBpbnN0cmAgb3B0aW9uXHJcbiAgY29uc3QgdXNlck9wdGlvbnMgPSBuZXcgRnVuY3Rpb24oYHJldHVybiAke2V4cG9ydE9wdGlvbnMuaW5zdHJ9YCkoKTtcclxuXHJcbiAgLy8gR2V0IHRoZSBgdGhlbWVPcHRpb25zYCBvcHRpb25cclxuICBjb25zdCB0aGVtZU9wdGlvbnMgPSBuZXcgRnVuY3Rpb24oYHJldHVybiAke2V4cG9ydE9wdGlvbnMudGhlbWVPcHRpb25zfWApKCk7XHJcblxyXG4gIC8vIEdldCB0aGUgYGdsb2JhbE9wdGlvbnNgIG9wdGlvblxyXG4gIGNvbnN0IGdsb2JhbE9wdGlvbnMgPSBuZXcgRnVuY3Rpb24oYHJldHVybiAke2V4cG9ydE9wdGlvbnMuZ2xvYmFsT3B0aW9uc31gKSgpO1xyXG5cclxuICAvLyBNZXJnZSB0aGUgZm9sbG93aW5nIG9wdGlvbnMgb2JqZWN0cyB0byBjcmVhdGUgZmluYWwgb3B0aW9uc1xyXG4gIGNvbnN0IGZpbmFsT3B0aW9ucyA9IG1lcmdlKFxyXG4gICAgZmFsc2UsXHJcbiAgICB0aGVtZU9wdGlvbnMsXHJcbiAgICB1c2VyT3B0aW9ucyxcclxuICAgIC8vIFBsYWNlZCBpdCBoZXJlIGluc3RlYWQgaW4gdGhlIGluaXQgYmVjYXVzZSBvZiB0aGUgc2l6ZSBpc3N1ZXNcclxuICAgIGFkZGl0aW9uYWxPcHRpb25zXHJcbiAgKTtcclxuXHJcbiAgLy8gUHJlcGFyZSB0aGUgYGNhbGxiYWNrYCBvcHRpb25cclxuICBjb25zdCBmaW5hbENhbGxiYWNrID0gY3VzdG9tTG9naWNPcHRpb25zLmNhbGxiYWNrXHJcbiAgICA/IG5ldyBGdW5jdGlvbihgcmV0dXJuICR7Y3VzdG9tTG9naWNPcHRpb25zLmNhbGxiYWNrfWApKClcclxuICAgIDogbnVsbDtcclxuXHJcbiAgLy8gVHJpZ2dlciB0aGUgYGN1c3RvbUNvZGVgIG9wdGlvblxyXG4gIGlmIChjdXN0b21Mb2dpY09wdGlvbnMuY3VzdG9tQ29kZSkge1xyXG4gICAgbmV3IEZ1bmN0aW9uKCdvcHRpb25zJywgY3VzdG9tTG9naWNPcHRpb25zLmN1c3RvbUNvZGUpKHVzZXJPcHRpb25zKTtcclxuICB9XHJcblxyXG4gIC8vIFNldCB0aGUgZ2xvYmFsIG9wdGlvbnMgaWYgZXhpc3RcclxuICBpZiAoZ2xvYmFsT3B0aW9ucykge1xyXG4gICAgc2V0T3B0aW9ucyhnbG9iYWxPcHRpb25zKTtcclxuICB9XHJcblxyXG4gIC8vIENhbGwgdGhlIGNoYXJ0IGNyZWF0aW9uXHJcbiAgSGlnaGNoYXJ0c1tleHBvcnRPcHRpb25zLmNvbnN0cl0oJ2NvbnRhaW5lcicsIGZpbmFsT3B0aW9ucywgZmluYWxDYWxsYmFjayk7XHJcblxyXG4gIC8vIEdldCB0aGUgY3VycmVudCBnbG9iYWwgb3B0aW9uc1xyXG4gIGNvbnN0IGRlZmF1bHRPcHRpb25zID0gZ2V0T3B0aW9ucygpO1xyXG5cclxuICAvLyBDbGVhciBpdCBqdXN0IGluIGNhc2UgKGUuZy4gdGhlIGBzZXRPcHRpb25zYCB3YXMgdXNlZCBpbiB0aGUgYGN1c3RvbUNvZGVgKVxyXG4gIGZvciAoY29uc3QgcHJvcCBpbiBkZWZhdWx0T3B0aW9ucykge1xyXG4gICAgaWYgKHR5cGVvZiBkZWZhdWx0T3B0aW9uc1twcm9wXSAhPT0gJ2Z1bmN0aW9uJykge1xyXG4gICAgICBkZWxldGUgZGVmYXVsdE9wdGlvbnNbcHJvcF07XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICAvLyBTZXQgdGhlIGRlZmF1bHQgb3B0aW9ucyBiYWNrXHJcbiAgc2V0T3B0aW9ucyhIaWdoY2hhcnRzLnNldE9wdGlvbnNPYmopO1xyXG5cclxuICAvLyBFbXB0eSB0aGUgY3VzdG9tIGdsb2JhbCBvcHRpb25zIG9iamVjdFxyXG4gIEhpZ2hjaGFydHMuc2V0T3B0aW9uc09iaiA9IHt9O1xyXG59XHJcblxyXG5leHBvcnQgZGVmYXVsdCB7XHJcbiAgc2V0dXBIaWdoY2hhcnRzLFxyXG4gIGNyZWF0ZUNoYXJ0XHJcbn07XHJcbiIsIi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXHJcblxyXG5IaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXJcclxuXHJcbkNvcHlyaWdodCAoYykgMjAxNi0yMDI1LCBIaWdoc29mdFxyXG5cclxuTGljZW5jZWQgdW5kZXIgdGhlIE1JVCBsaWNlbmNlLlxyXG5cclxuQWRkaXRpb25hbGx5IGEgdmFsaWQgSGlnaGNoYXJ0cyBsaWNlbnNlIGlzIHJlcXVpcmVkIGZvciB1c2UuXHJcblxyXG5TZWUgTElDRU5TRSBmaWxlIGluIHJvb3QgZm9yIGRldGFpbHMuXHJcblxyXG4qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xyXG5cclxuLyoqXHJcbiAqIEBvdmVydmlldyBUaGlzIG1vZHVsZSBwcm92aWRlcyBmdW5jdGlvbnMgZm9yIG1hbmFnaW5nIFB1cHBldGVlciBicm93c2VyXHJcbiAqIGluc3RhbmNlLCBjcmVhdGluZyBhbmQgY2xlYXJpbmcgcGFnZXMsIGluamVjdGluZyBjdXN0b20gcmVzb3VyY2VzLFxyXG4gKiBhbmQgc2V0dGluZyB1cCBIaWdoY2hhcnRzIGZvciBzZXJ2ZXItc2lkZSByZW5kZXJpbmcuIFRoZSBtb2R1bGUgZW5zdXJlc1xyXG4gKiB0aGF0IHJlc291cmNlcyBhcmUgY29ycmVjdGx5IG1hbmFnZWQgYW5kIGNhbiBoYW5kbGUgZmFpbHVyZXMgZHVyaW5nXHJcbiAqIG9wZXJhdGlvbnMgbGlrZSBsYXVuY2hpbmcgdGhlIGJyb3dzZXIgb3IgY3JlYXRpbmcgbmV3IHBhZ2VzLlxyXG4gKi9cclxuXHJcbmltcG9ydCB7IHJlYWRGaWxlU3luYyB9IGZyb20gJ2ZzJztcclxuaW1wb3J0IHsgam9pbiB9IGZyb20gJ3BhdGgnO1xyXG5cclxuaW1wb3J0IHB1cHBldGVlciBmcm9tICdwdXBwZXRlZXInO1xyXG5cclxuaW1wb3J0IHsgZ2V0Q2FjaGVQYXRoIH0gZnJvbSAnLi9jYWNoZS5qcyc7XHJcbmltcG9ydCB7IGdldE9wdGlvbnMgfSBmcm9tICcuL2NvbmZpZy5qcyc7XHJcbmltcG9ydCB7IHNldHVwSGlnaGNoYXJ0cyB9IGZyb20gJy4vaGlnaGNoYXJ0cy5qcyc7XHJcbmltcG9ydCB7IGxvZywgbG9nV2l0aFN0YWNrIH0gZnJvbSAnLi9sb2dnZXIuanMnO1xyXG5pbXBvcnQgeyBfX2Rpcm5hbWUsIGdldEFic29sdXRlUGF0aCB9IGZyb20gJy4vdXRpbHMuanMnO1xyXG5cclxuaW1wb3J0IEV4cG9ydEVycm9yIGZyb20gJy4vZXJyb3JzL0V4cG9ydEVycm9yLmpzJztcclxuXHJcbi8vIEdldCB0aGUgdGVtcGxhdGUgZm9yIHBhZ2VzXHJcbmNvbnN0IHRlbXBsYXRlID0gcmVhZEZpbGVTeW5jKFxyXG4gIGpvaW4oX19kaXJuYW1lLCAndGVtcGxhdGVzJywgJ3RlbXBsYXRlLmh0bWwnKSxcclxuICAndXRmOCdcclxuKTtcclxuXHJcbi8vIFRvIHNhdmUgdGhlIGJyb3dzZXJcclxubGV0IGJyb3dzZXIgPSBudWxsO1xyXG5cclxuLyoqXHJcbiAqIFJldHJpZXZlcyB0aGUgZXhpc3RpbmcgUHVwcGV0ZWVyIGJyb3dzZXIgaW5zdGFuY2UuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBnZXRCcm93c2VyXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtPYmplY3R9IFRoZSBQdXBwZXRlZXIgYnJvd3NlciBpbnN0YW5jZS5cclxuICpcclxuICogQHRocm93cyB7RXhwb3J0RXJyb3J9IFRocm93cyBhbiBgRXhwb3J0RXJyb3JgIGlmIG5vIHZhbGlkIGJyb3dzZXJcclxuICogaGFzIGJlZW4gY3JlYXRlZC5cclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiBnZXRCcm93c2VyKCkge1xyXG4gIGlmICghYnJvd3Nlcikge1xyXG4gICAgdGhyb3cgbmV3IEV4cG9ydEVycm9yKCdbYnJvd3Nlcl0gTm8gdmFsaWQgYnJvd3NlciBoYXMgYmVlbiBjcmVhdGVkLicsIDUwMCk7XHJcbiAgfVxyXG4gIHJldHVybiBicm93c2VyO1xyXG59XHJcblxyXG4vKipcclxuICogQ3JlYXRlcyBhIFB1cHBldGVlciBicm93c2VyIGluc3RhbmNlIHdpdGggdGhlIHNwZWNpZmllZCBhcmd1bWVudHMuXHJcbiAqXHJcbiAqIEBhc3luY1xyXG4gKiBAZnVuY3Rpb24gY3JlYXRlQnJvd3NlclxyXG4gKlxyXG4gKiBAcGFyYW0ge0FycmF5LjxzdHJpbmc+fSBwdXBwZXRlZXJBcmdzIC0gQWRkaXRpb25hbCBhcmd1bWVudHMgZm9yIFB1cHBldGVlclxyXG4gKiBsYXVuY2guXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtQcm9taXNlPE9iamVjdD59IEEgUHJvbWlzZSB0aGF0IHJlc29sdmVzIHRvIHRoZSBjcmVhdGVkIFB1cHBldGVlclxyXG4gKiBicm93c2VyIGluc3RhbmNlLlxyXG4gKlxyXG4gKiBAdGhyb3dzIHtFeHBvcnRFcnJvcn0gVGhyb3dzIGFuIGBFeHBvcnRFcnJvcmAgaWYgbWF4IHJldHJpZXMgdG8gb3BlblxyXG4gKiBhIGJyb3dzZXIgaW5zdGFuY2UgYXJlIHJlYWNoZWQsIG9yIGlmIG5vIGJyb3dzZXIgaW5zdGFuY2UgaXMgZm91bmQgYWZ0ZXJcclxuICogcmV0cmllcy5cclxuICovXHJcbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBjcmVhdGVCcm93c2VyKHB1cHBldGVlckFyZ3MpIHtcclxuICAvLyBHZXQgYGRlYnVnYCBhbmQgYG90aGVyYCBvcHRpb25zXHJcbiAgY29uc3QgeyBkZWJ1Zywgb3RoZXIgfSA9IGdldE9wdGlvbnMoKTtcclxuXHJcbiAgLy8gR2V0IHRoZSBgZGVidWdgIG9wdGlvbnNcclxuICBjb25zdCB7IGVuYWJsZTogZW5hYmxlZERlYnVnLCAuLi5kZWJ1Z09wdGlvbnMgfSA9IGRlYnVnO1xyXG5cclxuICAvLyBMYXVuY2ggb3B0aW9ucyBmb3IgdGhlIGJyb3dzZXIgaW5zdGFuY2VcclxuICBjb25zdCBsYXVuY2hPcHRpb25zID0ge1xyXG4gICAgaGVhZGxlc3M6IG90aGVyLmJyb3dzZXJTaGVsbE1vZGUgPyAnc2hlbGwnIDogdHJ1ZSxcclxuICAgIHVzZXJEYXRhRGlyOiAndG1wJyxcclxuICAgIGFyZ3M6IHB1cHBldGVlckFyZ3MgfHwgW10sXHJcbiAgICBoYW5kbGVTSUdJTlQ6IGZhbHNlLFxyXG4gICAgaGFuZGxlU0lHVEVSTTogZmFsc2UsXHJcbiAgICBoYW5kbGVTSUdIVVA6IGZhbHNlLFxyXG4gICAgd2FpdEZvckluaXRpYWxQYWdlOiBmYWxzZSxcclxuICAgIGRlZmF1bHRWaWV3cG9ydDogbnVsbCxcclxuICAgIC4uLihlbmFibGVkRGVidWcgJiYgZGVidWdPcHRpb25zKVxyXG4gIH07XHJcblxyXG4gIC8vIENyZWF0ZSBhIGJyb3dzZXJcclxuICBpZiAoIWJyb3dzZXIpIHtcclxuICAgIC8vIEEgY291bnRlciBmb3IgdGhlIGJyb3dzZXIncyBsYXVuY2ggcmV0cmllc1xyXG4gICAgbGV0IHRyeUNvdW50ID0gMDtcclxuXHJcbiAgICBjb25zdCBvcGVuID0gYXN5bmMgKCkgPT4ge1xyXG4gICAgICB0cnkge1xyXG4gICAgICAgIGxvZyhcclxuICAgICAgICAgIDMsXHJcbiAgICAgICAgICBgW2Jyb3dzZXJdIEF0dGVtcHRpbmcgdG8gZ2V0IGEgYnJvd3NlciBpbnN0YW5jZSAodHJ5ICR7Kyt0cnlDb3VudH0pLmBcclxuICAgICAgICApO1xyXG5cclxuICAgICAgICAvLyBMYXVuY2ggdGhlIGJyb3dzZXJcclxuICAgICAgICBicm93c2VyID0gYXdhaXQgcHVwcGV0ZWVyLmxhdW5jaChsYXVuY2hPcHRpb25zKTtcclxuICAgICAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICAgICBsb2dXaXRoU3RhY2soXHJcbiAgICAgICAgICAxLFxyXG4gICAgICAgICAgZXJyb3IsXHJcbiAgICAgICAgICAnW2Jyb3dzZXJdIEZhaWxlZCB0byBsYXVuY2ggYSBicm93c2VyIGluc3RhbmNlLidcclxuICAgICAgICApO1xyXG5cclxuICAgICAgICAvLyBSZXRyeSB0byBsYXVuY2ggYnJvd3NlciB1bnRpbCByZWFjaGluZyBtYXggYXR0ZW1wdHNcclxuICAgICAgICBpZiAodHJ5Q291bnQgPCAyNSkge1xyXG4gICAgICAgICAgbG9nKDMsIGBbYnJvd3Nlcl0gUmV0cnkgdG8gb3BlbiBhIGJyb3dzZXIgKCR7dHJ5Q291bnR9IG91dCBvZiAyNSkuYCk7XHJcblxyXG4gICAgICAgICAgLy8gV2FpdCBmb3IgYSA0IHNlY29uZHMgYmVmb3JlIHRyeWluZyBhZ2FpblxyXG4gICAgICAgICAgYXdhaXQgbmV3IFByb21pc2UoKHJlc3BvbnNlKSA9PiBzZXRUaW1lb3V0KHJlc3BvbnNlLCA0MDAwKSk7XHJcbiAgICAgICAgICBhd2FpdCBvcGVuKCk7XHJcbiAgICAgICAgfSBlbHNlIHtcclxuICAgICAgICAgIHRocm93IGVycm9yO1xyXG4gICAgICAgIH1cclxuICAgICAgfVxyXG4gICAgfTtcclxuXHJcbiAgICB0cnkge1xyXG4gICAgICBhd2FpdCBvcGVuKCk7XHJcblxyXG4gICAgICAvLyBTaGVsbCBtb2RlIGluZm9ybVxyXG4gICAgICBpZiAobGF1bmNoT3B0aW9ucy5oZWFkbGVzcyA9PT0gJ3NoZWxsJykge1xyXG4gICAgICAgIGxvZygzLCBgW2Jyb3dzZXJdIExhdW5jaGVkIGJyb3dzZXIgaW4gc2hlbGwgbW9kZS5gKTtcclxuICAgICAgfVxyXG5cclxuICAgICAgLy8gRGVidWcgbW9kZSBpbmZvcm1cclxuICAgICAgaWYgKGVuYWJsZWREZWJ1Zykge1xyXG4gICAgICAgIGxvZygzLCBgW2Jyb3dzZXJdIExhdW5jaGVkIGJyb3dzZXIgaW4gZGVidWcgbW9kZS5gKTtcclxuICAgICAgfVxyXG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICAgdGhyb3cgbmV3IEV4cG9ydEVycm9yKFxyXG4gICAgICAgICdbYnJvd3Nlcl0gTWF4aW11bSByZXRyaWVzIHRvIG9wZW4gYSBicm93c2VyIGluc3RhbmNlIHJlYWNoZWQuJyxcclxuICAgICAgICA1MDBcclxuICAgICAgKS5zZXRFcnJvcihlcnJvcik7XHJcbiAgICB9XHJcblxyXG4gICAgaWYgKCFicm93c2VyKSB7XHJcbiAgICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcignW2Jyb3dzZXJdIENhbm5vdCBmaW5kIGEgYnJvd3NlciB0byBvcGVuLicsIDUwMCk7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICAvLyBSZXR1cm4gYSBicm93c2VyIGluc3RhbmNlXHJcbiAgcmV0dXJuIGJyb3dzZXI7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBDbG9zZXMgdGhlIFB1cHBldGVlciBicm93c2VyIGluc3RhbmNlIGlmIGl0IGlzIGNvbm5lY3RlZC5cclxuICpcclxuICogQGFzeW5jXHJcbiAqIEBmdW5jdGlvbiBjbG9zZUJyb3dzZXJcclxuICovXHJcbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBjbG9zZUJyb3dzZXIoKSB7XHJcbiAgLy8gQ2xvc2UgdGhlIGJyb3dzZXIgd2hlbiBjb25uZWN0ZWRcclxuICBpZiAoYnJvd3NlciAmJiBicm93c2VyLmNvbm5lY3RlZCkge1xyXG4gICAgYXdhaXQgYnJvd3Nlci5jbG9zZSgpO1xyXG4gIH1cclxuICBicm93c2VyID0gbnVsbDtcclxuICBsb2coNCwgJ1ticm93c2VyXSBDbG9zZWQgdGhlIGJyb3dzZXIuJyk7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBDcmVhdGVzIGEgbmV3IFB1cHBldGVlciBwYWdlIHdpdGhpbiBhbiBleGlzdGluZyBicm93c2VyIGluc3RhbmNlLlxyXG4gKiBUaGUgZnVuY3Rpb24gY3JlYXRlcyBhIG5ldyBwYWdlLCBkaXNhYmxlcyBjYWNoaW5nLCBzZXRzIGNvbnRlbnQgdXNpbmdcclxuICogdGhlIGBfc2V0UGFnZUNvbnRlbnQoKWAsIGFuZCByZXR1cm5zIHRoZSBjcmVhdGVkIFB1cHBldGVlciBwYWdlLlxyXG4gKlxyXG4gKiBAYXN5bmNcclxuICogQGZ1bmN0aW9uIG5ld1BhZ2VcclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IHBvb2xSZXNvdXJjZSAtIFRoZSBwb29sIHJlc291cmNlIHRoYXQgY29udGFpbnMgYGlkYCxcclxuICogYHdvcmtDb3VudGAsIGFuZCBgcGFnZWAuXHJcbiAqXHJcbiAqIEB0aHJvd3Mge0V4cG9ydEVycm9yfSBUaHJvd3MgYW4gYEV4cG9ydEVycm9yYCBpZiBubyB2YWxpZCBicm93c2VyXHJcbiAqIGhhcyBiZWVuIGNvbm5lY3RlZCBvciBpZiBhIHBhZ2UgaXMgaW52YWxpZCBvciBjbG9zZWQuXHJcbiAqL1xyXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gbmV3UGFnZShwb29sUmVzb3VyY2UpIHtcclxuICAvLyBFcnJvciBpbiBjYXNlIG9mIG5vIGNvbm5lY3RlZCBicm93c2VyXHJcbiAgaWYgKCFicm93c2VyIHx8ICFicm93c2VyLmNvbm5lY3RlZCkge1xyXG4gICAgdGhyb3cgbmV3IEV4cG9ydEVycm9yKGBbYnJvd3Nlcl0gQnJvd3NlciBpcyBub3QgeWV0IGNvbm5lY3RlZC5gLCA1MDApO1xyXG4gIH1cclxuXHJcbiAgLy8gQ3JlYXRlIGEgcGFnZVxyXG4gIHBvb2xSZXNvdXJjZS5wYWdlID0gYXdhaXQgYnJvd3Nlci5uZXdQYWdlKCk7XHJcblxyXG4gIC8vIERpc2FibGUgY2FjaGVcclxuICBhd2FpdCBwb29sUmVzb3VyY2UucGFnZS5zZXRDYWNoZUVuYWJsZWQoZmFsc2UpO1xyXG5cclxuICAvLyBTZXQgdGhlIGNvbnRlbnRcclxuICBhd2FpdCBfc2V0UGFnZUNvbnRlbnQocG9vbFJlc291cmNlLnBhZ2UpO1xyXG5cclxuICAvLyBTZXQgcGFnZSBldmVudHNcclxuICBfc2V0UGFnZUV2ZW50cyhwb29sUmVzb3VyY2UucGFnZSk7XHJcblxyXG4gIC8vIENoZWNrIGlmIHRoZSBwYWdlIGlzIGNvcnJlY3RseSBjcmVhdGVkXHJcbiAgaWYgKCFwb29sUmVzb3VyY2UucGFnZSB8fCBwb29sUmVzb3VyY2UucGFnZS5pc0Nsb3NlZCgpKSB7XHJcbiAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoJ1ticm93c2VyXSBUaGUgcGFnZSBpcyBpbnZhbGlkIG9yIGNsb3NlZC4nLCA0MDApO1xyXG4gIH1cclxufVxyXG5cclxuLyoqXHJcbiAqIENsZWFycyB0aGUgY29udGVudCBvZiBhIFB1cHBldGVlciBQYWdlIGJhc2VkIG9uIHRoZSBzcGVjaWZpZWQgbW9kZS4gTG9nc1xyXG4gKiB0aHJvd24gZXJyb3IgaWYgY2xlYXJpbmcgb2YgYSBwYWdlJ3MgY29udGVudCBmYWlscy5cclxuICpcclxuICogQGFzeW5jXHJcbiAqIEBmdW5jdGlvbiBjbGVhclBhZ2VcclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IHBvb2xSZXNvdXJjZSAtIFRoZSBwb29sIHJlc291cmNlIHRoYXQgY29udGFpbnMgcGFnZSBhbmQgaWQuXHJcbiAqIEBwYXJhbSB7Ym9vbGVhbn0gW2hhcmRSZXNldD1mYWxzZV0gLSBBIGZsYWcgaW5kaWNhdGluZyB0aGUgdHlwZSBvZiBjbGVhcmluZ1xyXG4gKiB0byBiZSBwZXJmb3JtZWQuIElmIHRydWUsIG5hdmlnYXRlcyB0byBgYWJvdXQ6YmxhbmtgIGFuZCByZXNldHMgY29udGVudFxyXG4gKiBhbmQgc2NyaXB0cy4gSWYgZmFsc2UsIGNsZWFycyB0aGUgYm9keSBjb250ZW50IGJ5IHNldHRpbmcgYSBwcmVkZWZpbmVkIEhUTUxcclxuICogc3RydWN0dXJlLiBUaGUgZGVmYXVsdCB2YWx1ZSBpcyBgZmFsc2VgLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7UHJvbWlzZTxib29sZWFuPn0gQSBQcm9taXNlIHRoYXQgcmVzb2x2ZXMgdG8gdHJ1ZSB3aGVuIHBhZ2VcclxuICogaXMgY29ycmVjdGx5IGNsZWFyZWQgYW5kIGZhbHNlIHdoZW4gaXQgaXMgbm90LlxyXG4gKi9cclxuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIGNsZWFyUGFnZShwb29sUmVzb3VyY2UsIGhhcmRSZXNldCA9IGZhbHNlKSB7XHJcbiAgdHJ5IHtcclxuICAgIGlmIChwb29sUmVzb3VyY2UucGFnZSAmJiAhcG9vbFJlc291cmNlLnBhZ2UuaXNDbG9zZWQoKSkge1xyXG4gICAgICBpZiAoaGFyZFJlc2V0KSB7XHJcbiAgICAgICAgLy8gTmF2aWdhdGUgdG8gYGFib3V0OmJsYW5rYFxyXG4gICAgICAgIGF3YWl0IHBvb2xSZXNvdXJjZS5wYWdlLmdvdG8oJ2Fib3V0OmJsYW5rJywge1xyXG4gICAgICAgICAgd2FpdFVudGlsOiAnZG9tY29udGVudGxvYWRlZCdcclxuICAgICAgICB9KTtcclxuXHJcbiAgICAgICAgLy8gU2V0IHRoZSBjb250ZW50IGFuZCBhbmQgc2NyaXB0cyBhZ2FpblxyXG4gICAgICAgIGF3YWl0IF9zZXRQYWdlQ29udGVudChwb29sUmVzb3VyY2UucGFnZSk7XHJcbiAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgLy8gQ2xlYXIgYm9keSBjb250ZW50XHJcbiAgICAgICAgYXdhaXQgcG9vbFJlc291cmNlLnBhZ2UuZXZhbHVhdGUoKCkgPT4ge1xyXG4gICAgICAgICAgZG9jdW1lbnQuYm9keS5pbm5lckhUTUwgPVxyXG4gICAgICAgICAgICAnPGRpdiBpZD1cImNoYXJ0LWNvbnRhaW5lclwiPjxkaXYgaWQ9XCJjb250YWluZXJcIj48L2Rpdj48L2Rpdj4nO1xyXG4gICAgICAgIH0pO1xyXG4gICAgICB9XHJcbiAgICAgIHJldHVybiB0cnVlO1xyXG4gICAgfVxyXG4gIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICBsb2dXaXRoU3RhY2soXHJcbiAgICAgIDIsXHJcbiAgICAgIGVycm9yLFxyXG4gICAgICBgW3Bvb2xdIFBvb2wgcmVzb3VyY2UgWyR7cG9vbFJlc291cmNlLmlkfV0gLSBDb250ZW50IG9mIHRoZSBwYWdlIGNvdWxkIG5vdCBiZSBjbGVhcmVkLmBcclxuICAgICk7XHJcblxyXG4gICAgLy8gU2V0IHRoZSBgd29ya0xpbWl0YCB0byBleGNlZWRlZCBpbiBvcmRlciB0byByZWNyZWF0ZSB0aGUgcmVzb3VyY2VcclxuICAgIHBvb2xSZXNvdXJjZS53b3JrQ291bnQgPSBnZXRPcHRpb25zKCkucG9vbC53b3JrTGltaXQgKyAxO1xyXG4gIH1cclxuICByZXR1cm4gZmFsc2U7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBBZGRzIGN1c3RvbSBKUyBhbmQgQ1NTIHJlc291cmNlcyB0byBhIFB1cHBldGVlciBQYWdlIGJhc2VkIG9uIHRoZSBzcGVjaWZpZWRcclxuICogb3B0aW9ucy5cclxuICpcclxuICogQGFzeW5jXHJcbiAqIEBmdW5jdGlvbiBhZGRQYWdlUmVzb3VyY2VzXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBwYWdlIC0gVGhlIFB1cHBldGVlciBwYWdlIG9iamVjdCB0byB3aGljaCByZXNvdXJjZXMgd2lsbFxyXG4gKiBiZSBhZGRlZC5cclxuICogQHBhcmFtIHtPYmplY3R9IGN1c3RvbUxvZ2ljT3B0aW9ucyAtIFRoZSBjb25maWd1cmF0aW9uIG9iamVjdCBjb250YWluaW5nXHJcbiAqIGBjdXN0b21Mb2dpY2Agb3B0aW9ucy5cclxuICpcclxuICogQHJldHVybnMge1Byb21pc2U8QXJyYXkuPE9iamVjdD4+fSBBIFByb21pc2UgdGhhdCByZXNvbHZlcyB0byBhbiBhcnJheVxyXG4gKiBvZiBpbmplY3RlZCByZXNvdXJjZXMuXHJcbiAqL1xyXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gYWRkUGFnZVJlc291cmNlcyhwYWdlLCBjdXN0b21Mb2dpY09wdGlvbnMpIHtcclxuICAvLyBJbmplY3RlZCByZXNvdXJjZXMgYXJyYXlcclxuICBjb25zdCBpbmplY3RlZFJlc291cmNlcyA9IFtdO1xyXG5cclxuICAvLyBVc2UgcmVzb3VyY2VzXHJcbiAgY29uc3QgcmVzb3VyY2VzID0gY3VzdG9tTG9naWNPcHRpb25zLnJlc291cmNlcztcclxuICBpZiAocmVzb3VyY2VzKSB7XHJcbiAgICBjb25zdCBpbmplY3RlZEpzID0gW107XHJcblxyXG4gICAgLy8gTG9hZCBjdXN0b20gSlMgY29kZVxyXG4gICAgaWYgKHJlc291cmNlcy5qcykge1xyXG4gICAgICBpbmplY3RlZEpzLnB1c2goe1xyXG4gICAgICAgIGNvbnRlbnQ6IHJlc291cmNlcy5qc1xyXG4gICAgICB9KTtcclxuICAgIH1cclxuXHJcbiAgICAvLyBMb2FkIHNjcmlwdHMgZnJvbSBhbGwgY3VzdG9tIGZpbGVzXHJcbiAgICBpZiAocmVzb3VyY2VzLmZpbGVzKSB7XHJcbiAgICAgIGZvciAoY29uc3QgZmlsZSBvZiByZXNvdXJjZXMuZmlsZXMpIHtcclxuICAgICAgICBjb25zdCBpc0xvY2FsID0gIWZpbGUuc3RhcnRzV2l0aCgnaHR0cCcpID8gdHJ1ZSA6IGZhbHNlO1xyXG5cclxuICAgICAgICAvLyBBZGQgZWFjaCBjdXN0b20gc2NyaXB0IGZyb20gcmVzb3VyY2VzJyBmaWxlc1xyXG4gICAgICAgIGluamVjdGVkSnMucHVzaChcclxuICAgICAgICAgIGlzTG9jYWxcclxuICAgICAgICAgICAgPyB7XHJcbiAgICAgICAgICAgICAgICBjb250ZW50OiByZWFkRmlsZVN5bmMoZ2V0QWJzb2x1dGVQYXRoKGZpbGUpLCAndXRmOCcpXHJcbiAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICA6IHtcclxuICAgICAgICAgICAgICAgIHVybDogZmlsZVxyXG4gICAgICAgICAgICAgIH1cclxuICAgICAgICApO1xyXG4gICAgICB9XHJcbiAgICB9XHJcblxyXG4gICAgZm9yIChjb25zdCBqc1Jlc291cmNlIG9mIGluamVjdGVkSnMpIHtcclxuICAgICAgdHJ5IHtcclxuICAgICAgICBpbmplY3RlZFJlc291cmNlcy5wdXNoKGF3YWl0IHBhZ2UuYWRkU2NyaXB0VGFnKGpzUmVzb3VyY2UpKTtcclxuICAgICAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICAgICBsb2dXaXRoU3RhY2soMiwgZXJyb3IsIGBbYnJvd3Nlcl0gVGhlIEpTIHJlc291cmNlIGNhbm5vdCBiZSBsb2FkZWQuYCk7XHJcbiAgICAgIH1cclxuICAgIH1cclxuICAgIGluamVjdGVkSnMubGVuZ3RoID0gMDtcclxuXHJcbiAgICAvLyBMb2FkIENTU1xyXG4gICAgY29uc3QgaW5qZWN0ZWRDc3MgPSBbXTtcclxuICAgIGlmIChyZXNvdXJjZXMuY3NzKSB7XHJcbiAgICAgIGxldCBjc3NJbXBvcnRzID0gcmVzb3VyY2VzLmNzcy5tYXRjaCgvQGltcG9ydFxccyooW147XSopOy9nKTtcclxuICAgICAgaWYgKGNzc0ltcG9ydHMpIHtcclxuICAgICAgICAvLyBIYW5kbGUgY3NzIHNlY3Rpb25cclxuICAgICAgICBmb3IgKGxldCBjc3NJbXBvcnRQYXRoIG9mIGNzc0ltcG9ydHMpIHtcclxuICAgICAgICAgIGlmIChjc3NJbXBvcnRQYXRoKSB7XHJcbiAgICAgICAgICAgIGNzc0ltcG9ydFBhdGggPSBjc3NJbXBvcnRQYXRoXHJcbiAgICAgICAgICAgICAgLnJlcGxhY2UoJ3VybCgnLCAnJylcclxuICAgICAgICAgICAgICAucmVwbGFjZSgnQGltcG9ydCcsICcnKVxyXG4gICAgICAgICAgICAgIC5yZXBsYWNlKC9cIi9nLCAnJylcclxuICAgICAgICAgICAgICAucmVwbGFjZSgvJy9nLCAnJylcclxuICAgICAgICAgICAgICAucmVwbGFjZSgvOy8sICcnKVxyXG4gICAgICAgICAgICAgIC5yZXBsYWNlKC9cXCkvZywgJycpXHJcbiAgICAgICAgICAgICAgLnRyaW0oKTtcclxuXHJcbiAgICAgICAgICAgIC8vIEFkZCBlYWNoIGN1c3RvbSBjc3MgZnJvbSByZXNvdXJjZXNcclxuICAgICAgICAgICAgaWYgKGNzc0ltcG9ydFBhdGguc3RhcnRzV2l0aCgnaHR0cCcpKSB7XHJcbiAgICAgICAgICAgICAgaW5qZWN0ZWRDc3MucHVzaCh7XHJcbiAgICAgICAgICAgICAgICB1cmw6IGNzc0ltcG9ydFBhdGhcclxuICAgICAgICAgICAgICB9KTtcclxuICAgICAgICAgICAgfSBlbHNlIGlmIChjdXN0b21Mb2dpY09wdGlvbnMuYWxsb3dGaWxlUmVzb3VyY2VzKSB7XHJcbiAgICAgICAgICAgICAgaW5qZWN0ZWRDc3MucHVzaCh7XHJcbiAgICAgICAgICAgICAgICBwYXRoOiBqb2luKF9fZGlybmFtZSwgY3NzSW1wb3J0UGF0aClcclxuICAgICAgICAgICAgICB9KTtcclxuICAgICAgICAgICAgfVxyXG4gICAgICAgICAgfVxyXG4gICAgICAgIH1cclxuICAgICAgfVxyXG5cclxuICAgICAgLy8gVGhlIHJlc3Qgb2YgdGhlIENTUyBzZWN0aW9uIHdpbGwgYmUgY29udGVudCBieSBub3dcclxuICAgICAgaW5qZWN0ZWRDc3MucHVzaCh7XHJcbiAgICAgICAgY29udGVudDogcmVzb3VyY2VzLmNzcy5yZXBsYWNlKC9AaW1wb3J0XFxzKihbXjtdKik7L2csICcnKSB8fCAnICdcclxuICAgICAgfSk7XHJcblxyXG4gICAgICBmb3IgKGNvbnN0IGNzc1Jlc291cmNlIG9mIGluamVjdGVkQ3NzKSB7XHJcbiAgICAgICAgdHJ5IHtcclxuICAgICAgICAgIGluamVjdGVkUmVzb3VyY2VzLnB1c2goYXdhaXQgcGFnZS5hZGRTdHlsZVRhZyhjc3NSZXNvdXJjZSkpO1xyXG4gICAgICAgIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICAgICAgICBsb2dXaXRoU3RhY2soXHJcbiAgICAgICAgICAgIDIsXHJcbiAgICAgICAgICAgIGVycm9yLFxyXG4gICAgICAgICAgICBgW2Jyb3dzZXJdIFRoZSBDU1MgcmVzb3VyY2UgY2Fubm90IGJlIGxvYWRlZC5gXHJcbiAgICAgICAgICApO1xyXG4gICAgICAgIH1cclxuICAgICAgfVxyXG4gICAgICBpbmplY3RlZENzcy5sZW5ndGggPSAwO1xyXG4gICAgfVxyXG4gIH1cclxuICByZXR1cm4gaW5qZWN0ZWRSZXNvdXJjZXM7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBDbGVhcnMgb3V0IGFsbCBzdGF0ZSBzZXQgb24gdGhlIHBhZ2Ugd2l0aCBgYWRkU2NyaXB0VGFnYCBhbmQgYGFkZFN0eWxlVGFnYC5cclxuICogUmVtb3ZlcyBpbmplY3RlZCByZXNvdXJjZXMgYW5kIHJlc2V0cyBDU1MgYW5kIHNjcmlwdCB0YWdzIG9uIHRoZSBwYWdlLlxyXG4gKiBBZGRpdGlvbmFsbHksIGl0IGRlc3Ryb3lzIHByZXZpb3VzbHkgZXhpc3RpbmcgY2hhcnRzLlxyXG4gKlxyXG4gKiBAYXN5bmNcclxuICogQGZ1bmN0aW9uIGNsZWFyUGFnZVJlc291cmNlc1xyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gcGFnZSAtIFRoZSBQdXBwZXRlZXIgcGFnZSBvYmplY3QgZnJvbSB3aGljaCByZXNvdXJjZXMgd2lsbFxyXG4gKiBiZSBjbGVhcmVkLlxyXG4gKiBAcGFyYW0ge0FycmF5LjxPYmplY3Q+fSBpbmplY3RlZFJlc291cmNlcyAtIEFycmF5IG9mIGluamVjdGVkIHJlc291cmNlc1xyXG4gKiB0byBiZSBjbGVhcmVkLlxyXG4gKi9cclxuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIGNsZWFyUGFnZVJlc291cmNlcyhwYWdlLCBpbmplY3RlZFJlc291cmNlcykge1xyXG4gIHRyeSB7XHJcbiAgICBmb3IgKGNvbnN0IHJlc291cmNlIG9mIGluamVjdGVkUmVzb3VyY2VzKSB7XHJcbiAgICAgIGF3YWl0IHJlc291cmNlLmRpc3Bvc2UoKTtcclxuICAgIH1cclxuXHJcbiAgICAvLyBEZXN0cm95IG9sZCBjaGFydHMgYWZ0ZXIgZXhwb3J0IGlzIGRvbmUgYW5kIHJlc2V0IGFsbCBDU1MgYW5kIHNjcmlwdCB0YWdzXHJcbiAgICBhd2FpdCBwYWdlLmV2YWx1YXRlKCgpID0+IHtcclxuICAgICAgLy8gV2UgYXJlIG5vdCBndWFyYW50ZWVkIHRoYXQgSGlnaGNoYXJ0cyBpcyBsb2FkZWQsIHdoZW4gZG9pbmcgU1ZHIGV4cG9ydHNcclxuICAgICAgaWYgKHR5cGVvZiBIaWdoY2hhcnRzICE9PSAndW5kZWZpbmVkJykge1xyXG4gICAgICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBuby11bmRlZlxyXG4gICAgICAgIGNvbnN0IG9sZENoYXJ0cyA9IEhpZ2hjaGFydHMuY2hhcnRzO1xyXG5cclxuICAgICAgICAvLyBDaGVjayBpbiBhbnkgYWxyZWFkeSBleGlzdGluZyBjaGFydHNcclxuICAgICAgICBpZiAoQXJyYXkuaXNBcnJheShvbGRDaGFydHMpICYmIG9sZENoYXJ0cy5sZW5ndGgpIHtcclxuICAgICAgICAgIC8vIERlc3Ryb3kgb2xkIGNoYXJ0c1xyXG4gICAgICAgICAgZm9yIChjb25zdCBvbGRDaGFydCBvZiBvbGRDaGFydHMpIHtcclxuICAgICAgICAgICAgb2xkQ2hhcnQgJiYgb2xkQ2hhcnQuZGVzdHJveSgpO1xyXG4gICAgICAgICAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgbm8tdW5kZWZcclxuICAgICAgICAgICAgSGlnaGNoYXJ0cy5jaGFydHMuc2hpZnQoKTtcclxuICAgICAgICAgIH1cclxuICAgICAgICB9XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBuby11bmRlZlxyXG4gICAgICBjb25zdCBbLi4uc2NyaXB0c1RvUmVtb3ZlXSA9IGRvY3VtZW50LmdldEVsZW1lbnRzQnlUYWdOYW1lKCdzY3JpcHQnKTtcclxuICAgICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIG5vLXVuZGVmXHJcbiAgICAgIGNvbnN0IFssIC4uLnN0eWxlc1RvUmVtb3ZlXSA9IGRvY3VtZW50LmdldEVsZW1lbnRzQnlUYWdOYW1lKCdzdHlsZScpO1xyXG4gICAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgbm8tdW5kZWZcclxuICAgICAgY29uc3QgWy4uLmxpbmtzVG9SZW1vdmVdID0gZG9jdW1lbnQuZ2V0RWxlbWVudHNCeVRhZ05hbWUoJ2xpbmsnKTtcclxuXHJcbiAgICAgIC8vIFJlbW92ZSB0YWdzXHJcbiAgICAgIGZvciAoY29uc3QgZWxlbWVudCBvZiBbXHJcbiAgICAgICAgLi4uc2NyaXB0c1RvUmVtb3ZlLFxyXG4gICAgICAgIC4uLnN0eWxlc1RvUmVtb3ZlLFxyXG4gICAgICAgIC4uLmxpbmtzVG9SZW1vdmVcclxuICAgICAgXSkge1xyXG4gICAgICAgIGVsZW1lbnQucmVtb3ZlKCk7XHJcbiAgICAgIH1cclxuICAgIH0pO1xyXG4gIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICBsb2dXaXRoU3RhY2soMiwgZXJyb3IsIGBbYnJvd3Nlcl0gQ291bGQgbm90IGNsZWFyIHBhZ2UncyByZXNvdXJjZXMuYCk7XHJcbiAgfVxyXG59XHJcblxyXG4vKipcclxuICogU2V0cyB0aGUgY29udGVudCBmb3IgYSBQdXBwZXRlZXIgUGFnZSB1c2luZyBhIHByZWRlZmluZWQgdGVtcGxhdGVcclxuICogYW5kIGFkZGl0aW9uYWwgc2NyaXB0cy5cclxuICpcclxuICogQGFzeW5jXHJcbiAqIEBmdW5jdGlvbiBfc2V0UGFnZUNvbnRlbnRcclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IHBhZ2UgLSBUaGUgUHVwcGV0ZWVyIHBhZ2Ugb2JqZWN0IHRvIHdoaWNoIHRoZSBjb250ZW50XHJcbiAqIGlzIGJlaW5nIHNldC5cclxuICovXHJcbmFzeW5jIGZ1bmN0aW9uIF9zZXRQYWdlQ29udGVudChwYWdlKSB7XHJcbiAgLy8gU2V0IHRoZSBpbml0aWFsIHBhZ2UgY29udGVudFxyXG4gIGF3YWl0IHBhZ2Uuc2V0Q29udGVudCh0ZW1wbGF0ZSwgeyB3YWl0VW50aWw6ICdkb21jb250ZW50bG9hZGVkJyB9KTtcclxuXHJcbiAgLy8gQWRkIGFsbCByZWdpc3RlcmVkIEhpZ2NoYXJ0cyBzY3JpcHRzLCBxdWl0ZSBkZW1hbmRpbmdcclxuICBhd2FpdCBwYWdlLmFkZFNjcmlwdFRhZyh7IHBhdGg6IGpvaW4oZ2V0Q2FjaGVQYXRoKCksICdzb3VyY2VzLmpzJykgfSk7XHJcblxyXG4gIC8vIFNldCB0aGUgaW5pdGlhbCBgYW5pbU9iamVjdGAgZm9yIEhpZ2hjaGFydHNcclxuICBhd2FpdCBwYWdlLmV2YWx1YXRlKHNldHVwSGlnaGNoYXJ0cyk7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBTZXQgZXZlbnRzIChsaWtlIGBwYWdlZXJyb3JgIGFuZCBgY29uc29sZWApIGZvciBhIFB1cHBldGVlciBQYWdlIGluIG9yZGVyXHJcbiAqIHRvIGNhdGNoIGFuZCBkaXNwbGF5IGVycm9ycyBhbmQgY29uc29sZSBsb2dzIGZyb20gdGhlIHdpbmRvdyBjb250ZXh0LlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gX3NldFBhZ2VFdmVudHNcclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IHBhZ2UgLSBUaGUgUHVwcGV0ZWVyIHBhZ2Ugb2JqZWN0IHRvIHdoaWNoIHRoZSBsaXN0ZW5lcnNcclxuICogYXJlIGJlaW5nIHNldC5cclxuICovXHJcbmZ1bmN0aW9uIF9zZXRQYWdlRXZlbnRzKHBhZ2UpIHtcclxuICAvLyBHZXQgYGRlYnVnYCBvcHRpb25zXHJcbiAgY29uc3QgeyBkZWJ1ZyB9ID0gZ2V0T3B0aW9ucygpO1xyXG5cclxuICAvLyBTZXQgdGhlIGBwYWdlZXJyb3JgIGxpc3RlbmVyXHJcbiAgcGFnZS5vbigncGFnZWVycm9yJywgYXN5bmMgKCkgPT4ge1xyXG4gICAgLy8gSXQgd291bGQgc2VlbSBsaWtlIHRoaXMgbWF5IGZpcmUgYXQgdGhlIHNhbWUgdGltZSBvciBzaG9ydGx5IGJlZm9yZVxyXG4gICAgLy8gYSBwYWdlIGlzIGNsb3NlZC5cclxuICAgIGlmIChwYWdlLmlzQ2xvc2VkKCkpIHtcclxuICAgICAgcmV0dXJuO1xyXG4gICAgfVxyXG4gIH0pO1xyXG5cclxuICAvLyBTZXQgdGhlIGBjb25zb2xlYCBsaXN0ZW5lciwgaWYgbmVlZGVkXHJcbiAgaWYgKGRlYnVnLmVuYWJsZSAmJiBkZWJ1Zy5saXN0ZW5Ub0NvbnNvbGUpIHtcclxuICAgIHBhZ2Uub24oJ2NvbnNvbGUnLCAobWVzc2FnZSkgPT4ge1xyXG4gICAgICBjb25zb2xlLmxvZyhgW2RlYnVnXSAke21lc3NhZ2UudGV4dCgpfWApO1xyXG4gICAgfSk7XHJcbiAgfVxyXG59XHJcblxyXG5leHBvcnQgZGVmYXVsdCB7XHJcbiAgZ2V0QnJvd3NlcixcclxuICBjcmVhdGVCcm93c2VyLFxyXG4gIGNsb3NlQnJvd3NlcixcclxuICBuZXdQYWdlLFxyXG4gIGNsZWFyUGFnZSxcclxuICBhZGRQYWdlUmVzb3VyY2VzLFxyXG4gIGNsZWFyUGFnZVJlc291cmNlc1xyXG59O1xyXG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxyXG5cclxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXHJcblxyXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNSwgSGlnaHNvZnRcclxuXHJcbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cclxuXHJcbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxyXG5cclxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxyXG5cclxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cclxuXHJcbi8qKlxyXG4gKiBUaGUgQ1NTIHRvIGJlIHVzZWQgb24gdGhlIGV4cG9ydGVkIHBhZ2UuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtzdHJpbmd9IFRoZSBDU1MgY29uZmlndXJhdGlvbi5cclxuICovXHJcbmV4cG9ydCBkZWZhdWx0ICgpID0+IGBcclxuXHJcbmh0bWwsIGJvZHkge1xyXG4gIG1hcmdpbjogMDtcclxuICBwYWRkaW5nOiAwO1xyXG4gIGJveC1zaXppbmc6IGJvcmRlci1ib3g7XHJcbn1cclxuXHJcbiN0YWJsZS1kaXYsICNzbGlkZXJzLCAjZGF0YXRhYmxlLCAjY29udHJvbHMsIC5sZC1yb3cge1xyXG4gIGRpc3BsYXk6IG5vbmU7XHJcbiAgaGVpZ2h0OiAwO1xyXG59XHJcblxyXG4jY2hhcnQtY29udGFpbmVyIHtcclxuICBib3gtc2l6aW5nOiBib3JkZXItYm94O1xyXG4gIG1hcmdpbjogMDtcclxuICBvdmVyZmxvdzogYXV0bztcclxuICBmb250LXNpemU6IDA7XHJcbn1cclxuXHJcbiNjaGFydC1jb250YWluZXIgPiBmaWd1cmUsIGRpdiB7XHJcbiAgbWFyZ2luLXRvcDogMCAhaW1wb3J0YW50O1xyXG4gIG1hcmdpbi1ib3R0b206IDAgIWltcG9ydGFudDtcclxufVxyXG5cclxuYDtcclxuIiwiLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcclxuXHJcbkhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlclxyXG5cclxuQ29weXJpZ2h0IChjKSAyMDE2LTIwMjUsIEhpZ2hzb2Z0XHJcblxyXG5MaWNlbmNlZCB1bmRlciB0aGUgTUlUIGxpY2VuY2UuXHJcblxyXG5BZGRpdGlvbmFsbHkgYSB2YWxpZCBIaWdoY2hhcnRzIGxpY2Vuc2UgaXMgcmVxdWlyZWQgZm9yIHVzZS5cclxuXHJcblNlZSBMSUNFTlNFIGZpbGUgaW4gcm9vdCBmb3IgZGV0YWlscy5cclxuXHJcbioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXHJcblxyXG5pbXBvcnQgY3NzVGVtcGxhdGUgZnJvbSAnLi9jc3MuanMnO1xyXG5cclxuLyoqXHJcbiAqIFRoZSBTVkcgdGVtcGxhdGUgdG8gdXNlIHdoZW4gbG9hZGluZyBTVkcgY29udGVudCB0byBiZSBleHBvcnRlZC5cclxuICpcclxuICogQHBhcmFtIHtzdHJpbmd9IHN2ZyAtIFRoZSBTVkcgaW5wdXQgY29udGVudCB0byBiZSBleHBvcnRlZC5cclxuICpcclxuICogQHJldHVybnMge3N0cmluZ30gVGhlIFNWRyB0ZW1wbGF0ZS5cclxuICovXHJcbmV4cG9ydCBkZWZhdWx0IChzdmcpID0+IGBcclxuPCFET0NUWVBFIGh0bWw+XHJcbjxodG1sIGxhbmc9J2VuLVVTJz5cclxuICA8aGVhZD5cclxuICAgIDxtZXRhIGh0dHAtZXF1aXY9XCJDb250ZW50LVR5cGVcIiBjb250ZW50PVwidGV4dC9odG1sOyBjaGFyc2V0PXV0Zi04XCI+XHJcbiAgICA8dGl0bGU+SGlnaGNoYXJ0cyBFeHBvcnQ8L3RpdGxlPlxyXG4gIDwvaGVhZD5cclxuICA8c3R5bGU+XHJcbiAgICAke2Nzc1RlbXBsYXRlKCl9XHJcbiAgPC9zdHlsZT5cclxuICA8Ym9keT5cclxuICAgIDxkaXYgaWQ9XCJjaGFydC1jb250YWluZXJcIj5cclxuICAgICAgJHtzdmd9XHJcbiAgICA8L2Rpdj5cclxuICA8L2JvZHk+XHJcbjwvaHRtbD5cclxuXHJcbmA7XHJcbiIsIi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXHJcblxyXG5IaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXJcclxuXHJcbkNvcHlyaWdodCAoYykgMjAxNi0yMDI1LCBIaWdoc29mdFxyXG5cclxuTGljZW5jZWQgdW5kZXIgdGhlIE1JVCBsaWNlbmNlLlxyXG5cclxuQWRkaXRpb25hbGx5IGEgdmFsaWQgSGlnaGNoYXJ0cyBsaWNlbnNlIGlzIHJlcXVpcmVkIGZvciB1c2UuXHJcblxyXG5TZWUgTElDRU5TRSBmaWxlIGluIHJvb3QgZm9yIGRldGFpbHMuXHJcblxyXG4qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xyXG5cclxuLyoqXHJcbiAqIEBvdmVydmlldyBUaGlzIG1vZHVsZSBoYW5kbGVzIGNoYXJ0IGV4cG9ydCBmdW5jdGlvbmFsaXR5IHVzaW5nIFB1cHBldGVlci5cclxuICogSXQgc3VwcG9ydHMgZXhwb3J0aW5nIGNoYXJ0cyBhcyBTVkcsIFBORywgSlBFRywgYW5kIFBERiBmb3JtYXRzLiBUaGUgbW9kdWxlXHJcbiAqIG1hbmFnZXMgcGFnZSByZXNvdXJjZXMsIHNldHMgdXAgdGhlIGV4cG9ydCBlbnZpcm9ubWVudCwgYW5kIHByb2Nlc3NlcyBjaGFydFxyXG4gKiBjb25maWd1cmF0aW9ucyBvciBTVkcgaW5wdXRzIGZvciByZW5kZXJpbmcuIEV4cG9ydHMgdG8gYSBjaGFydCBmcm9tIGEgcGFnZVxyXG4gKiB1c2luZyBQdXBwZXRlZXIuXHJcbiAqL1xyXG5cclxuaW1wb3J0IHsgYWRkUGFnZVJlc291cmNlcywgY2xlYXJQYWdlUmVzb3VyY2VzIH0gZnJvbSAnLi9icm93c2VyLmpzJztcclxuaW1wb3J0IHsgY3JlYXRlQ2hhcnQgfSBmcm9tICcuL2hpZ2hjaGFydHMuanMnO1xyXG5pbXBvcnQgeyBsb2cgfSBmcm9tICcuL2xvZ2dlci5qcyc7XHJcblxyXG5pbXBvcnQgc3ZnVGVtcGxhdGUgZnJvbSAnLi4vdGVtcGxhdGVzL3N2Z0V4cG9ydC9zdmdFeHBvcnQuanMnO1xyXG5cclxuaW1wb3J0IEV4cG9ydEVycm9yIGZyb20gJy4vZXJyb3JzL0V4cG9ydEVycm9yLmpzJztcclxuXHJcbi8qKlxyXG4gKiBFeHBvcnRzIHRvIGEgY2hhcnQgZnJvbSBhIHBhZ2UgdXNpbmcgUHVwcGV0ZWVyLlxyXG4gKlxyXG4gKiBAYXN5bmNcclxuICogQGZ1bmN0aW9uIHB1cHBldGVlckV4cG9ydFxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gcGFnZSAtIFB1cHBldGVlciBwYWdlIG9iamVjdC5cclxuICogQHBhcmFtIHtPYmplY3R9IGV4cG9ydE9wdGlvbnMgLSBUaGUgY29uZmlndXJhdGlvbiBvYmplY3QgY29udGFpbmluZyBgZXhwb3J0YFxyXG4gKiBvcHRpb25zLlxyXG4gKiBAcGFyYW0ge09iamVjdH0gY3VzdG9tTG9naWNPcHRpb25zIC0gVGhlIGNvbmZpZ3VyYXRpb24gb2JqZWN0IGNvbnRhaW5pbmdcclxuICogYGN1c3RvbUxvZ2ljYCBvcHRpb25zLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7UHJvbWlzZTwoc3RyaW5nfEJ1ZmZlcnxFeHBvcnRFcnJvcik+fSBBIFByb21pc2UgdGhhdCByZXNvbHZlc1xyXG4gKiB0byB0aGUgZXhwb3J0ZWQgZGF0YSBvciByZWplY3Rpbmcgd2l0aCBhbiBgRXhwb3J0RXJyb3JgLlxyXG4gKlxyXG4gKiBAdGhyb3dzIHtFeHBvcnRFcnJvcn0gVGhyb3dzIGFuIGBFeHBvcnRFcnJvcmAgaWYgZXhwb3J0IHRvIGFuIHVuc3VwcG9ydGVkXHJcbiAqIG91dHB1dCBmb3JtYXQgb2NjdXJzLlxyXG4gKi9cclxuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIHB1cHBldGVlckV4cG9ydChwYWdlLCBleHBvcnRPcHRpb25zLCBjdXN0b21Mb2dpY09wdGlvbnMpIHtcclxuICAvLyBJbmplY3RlZCByZXNvdXJjZXMgYXJyYXkgKGFkZGl0aW9uYWwgSlMgYW5kIENTUylcclxuICBjb25zdCBpbmplY3RlZFJlc291cmNlcyA9IFtdO1xyXG5cclxuICB0cnkge1xyXG4gICAgbGV0IGlzU1ZHID0gZmFsc2U7XHJcblxyXG4gICAgLy8gRGVjaWRlIG9uIHRoZSBleHBvcnQgbWV0aG9kXHJcbiAgICBpZiAoZXhwb3J0T3B0aW9ucy5zdmcpIHtcclxuICAgICAgbG9nKDQsICdbZXhwb3J0XSBUcmVhdGluZyBhcyBTVkcgaW5wdXQuJyk7XHJcblxyXG4gICAgICAvLyBJZiB0aGUgYHR5cGVgIGlzIGFsc28gU1ZHLCByZXR1cm4gdGhlIGlucHV0XHJcbiAgICAgIGlmIChleHBvcnRPcHRpb25zLnR5cGUgPT09ICdzdmcnKSB7XHJcbiAgICAgICAgcmV0dXJuIGV4cG9ydE9wdGlvbnMuc3ZnO1xyXG4gICAgICB9XHJcblxyXG4gICAgICAvLyBNYXJrIGFzIFNWRyBleHBvcnQgZm9yIHRoZSBsYXRlciBzaXplIGNvcnJlY3Rpb25zXHJcbiAgICAgIGlzU1ZHID0gdHJ1ZTtcclxuXHJcbiAgICAgIC8vIFNWRyBleHBvcnRcclxuICAgICAgYXdhaXQgcGFnZS5zZXRDb250ZW50KHN2Z1RlbXBsYXRlKGV4cG9ydE9wdGlvbnMuc3ZnKSwge1xyXG4gICAgICAgIHdhaXRVbnRpbDogJ2RvbWNvbnRlbnRsb2FkZWQnXHJcbiAgICAgIH0pO1xyXG4gICAgfSBlbHNlIHtcclxuICAgICAgbG9nKDQsICdbZXhwb3J0XSBUcmVhdGluZyBhcyBKU09OIGNvbmZpZy4nKTtcclxuXHJcbiAgICAgIC8vIE9wdGlvbnMgZXhwb3J0XHJcbiAgICAgIGF3YWl0IHBhZ2UuZXZhbHVhdGUoY3JlYXRlQ2hhcnQsIGV4cG9ydE9wdGlvbnMsIGN1c3RvbUxvZ2ljT3B0aW9ucyk7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gS2VlcHMgdHJhY2sgb2YgYWxsIHJlc291cmNlcyBhZGRlZCBvbiB0aGUgcGFnZSB3aXRoIGFkZFhYWFRhZy4gZXRjXHJcbiAgICAvLyBJdCdzIFZJVEFMIHRoYXQgYWxsIGFkZGVkIHJlc291cmNlcyBlbmRzIHVwIGhlcmUgc28gd2UgY2FuIGNsZWFyIHRoaW5nc1xyXG4gICAgLy8gb3V0IHdoZW4gZG9pbmcgYSBuZXcgZXhwb3J0IGluIHRoZSBzYW1lIHBhZ2UhXHJcbiAgICBpbmplY3RlZFJlc291cmNlcy5wdXNoKFxyXG4gICAgICAuLi4oYXdhaXQgYWRkUGFnZVJlc291cmNlcyhwYWdlLCBjdXN0b21Mb2dpY09wdGlvbnMpKVxyXG4gICAgKTtcclxuXHJcbiAgICAvLyBHZXQgdGhlIHJlYWwgY2hhcnQgc2l6ZSBhbmQgc2V0IHRoZSB6b29tIGFjY29yZGluZ2x5XHJcbiAgICBjb25zdCBzaXplID0gaXNTVkdcclxuICAgICAgPyBhd2FpdCBwYWdlLmV2YWx1YXRlKChzY2FsZSkgPT4ge1xyXG4gICAgICAgICAgY29uc3Qgc3ZnRWxlbWVudCA9IGRvY3VtZW50LnF1ZXJ5U2VsZWN0b3IoXHJcbiAgICAgICAgICAgICcjY2hhcnQtY29udGFpbmVyIHN2ZzpmaXJzdC1vZi10eXBlJ1xyXG4gICAgICAgICAgKTtcclxuXHJcbiAgICAgICAgICAvLyBHZXQgdGhlIHZhbHVlcyBjb3JyZWN0bHkgc2NhbGVkXHJcbiAgICAgICAgICBjb25zdCBjaGFydEhlaWdodCA9IHN2Z0VsZW1lbnQuaGVpZ2h0LmJhc2VWYWwudmFsdWUgKiBzY2FsZTtcclxuICAgICAgICAgIGNvbnN0IGNoYXJ0V2lkdGggPSBzdmdFbGVtZW50LndpZHRoLmJhc2VWYWwudmFsdWUgKiBzY2FsZTtcclxuXHJcbiAgICAgICAgICAvLyBJbiBjYXNlIG9mIFNWRyB0aGUgem9vbSBtdXN0IGJlIHNldCBkaXJlY3RseSBmb3IgYm9keSBhcyBzY2FsZVxyXG4gICAgICAgICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIG5vLXVuZGVmXHJcbiAgICAgICAgICBkb2N1bWVudC5ib2R5LnN0eWxlLnpvb20gPSBzY2FsZTtcclxuXHJcbiAgICAgICAgICAvLyBTZXQgdGhlIG1hcmdpbiB0byAwcHhcclxuICAgICAgICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBuby11bmRlZlxyXG4gICAgICAgICAgZG9jdW1lbnQuYm9keS5zdHlsZS5tYXJnaW4gPSAnMHB4JztcclxuXHJcbiAgICAgICAgICByZXR1cm4ge1xyXG4gICAgICAgICAgICBjaGFydEhlaWdodCxcclxuICAgICAgICAgICAgY2hhcnRXaWR0aFxyXG4gICAgICAgICAgfTtcclxuICAgICAgICB9LCBwYXJzZUZsb2F0KGV4cG9ydE9wdGlvbnMuc2NhbGUpKVxyXG4gICAgICA6IGF3YWl0IHBhZ2UuZXZhbHVhdGUoKCkgPT4ge1xyXG4gICAgICAgICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIG5vLXVuZGVmXHJcbiAgICAgICAgICBjb25zdCB7IGNoYXJ0SGVpZ2h0LCBjaGFydFdpZHRoIH0gPSB3aW5kb3cuSGlnaGNoYXJ0cy5jaGFydHNbMF07XHJcblxyXG4gICAgICAgICAgLy8gTm8gbmVlZCBmb3Igc3VjaCBzY2FsZSBtYW5pcHVsYXRpb24gaW4gY2FzZSBvZiBvdGhlciB0eXBlc1xyXG4gICAgICAgICAgLy8gb2YgZXhwb3J0cy4gUmVzZXQgdGhlIHpvb20gZm9yIG90aGVyIGV4cG9ydHMgdGhhbiB0byBTVkdzXHJcbiAgICAgICAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgbm8tdW5kZWZcclxuICAgICAgICAgIGRvY3VtZW50LmJvZHkuc3R5bGUuem9vbSA9IDE7XHJcblxyXG4gICAgICAgICAgcmV0dXJuIHtcclxuICAgICAgICAgICAgY2hhcnRIZWlnaHQsXHJcbiAgICAgICAgICAgIGNoYXJ0V2lkdGhcclxuICAgICAgICAgIH07XHJcbiAgICAgICAgfSk7XHJcblxyXG4gICAgLy8gR2V0IHRoZSBjbGlwIHJlZ2lvbiBmb3IgdGhlIHBhZ2VcclxuICAgIGNvbnN0IHsgeCwgeSB9ID0gYXdhaXQgX2dldENsaXBSZWdpb24ocGFnZSk7XHJcblxyXG4gICAgLy8gU2V0IGZpbmFsIGBoZWlnaHRgIGZvciB2aWV3cG9ydFxyXG4gICAgY29uc3Qgdmlld3BvcnRIZWlnaHQgPSBNYXRoLmFicyhcclxuICAgICAgTWF0aC5jZWlsKHNpemUuY2hhcnRIZWlnaHQgfHwgZXhwb3J0T3B0aW9ucy5oZWlnaHQpXHJcbiAgICApO1xyXG5cclxuICAgIC8vIFNldCBmaW5hbCBgd2lkdGhgIGZvciB2aWV3cG9ydFxyXG4gICAgY29uc3Qgdmlld3BvcnRXaWR0aCA9IE1hdGguYWJzKFxyXG4gICAgICBNYXRoLmNlaWwoc2l6ZS5jaGFydFdpZHRoIHx8IGV4cG9ydE9wdGlvbnMud2lkdGgpXHJcbiAgICApO1xyXG5cclxuICAgIC8vIFNldCB0aGUgZmluYWwgdmlld3BvcnQgbm93IHRoYXQgd2UgaGF2ZSB0aGUgcmVhbCBoZWlnaHRcclxuICAgIGF3YWl0IHBhZ2Uuc2V0Vmlld3BvcnQoe1xyXG4gICAgICBoZWlnaHQ6IHZpZXdwb3J0SGVpZ2h0LFxyXG4gICAgICB3aWR0aDogdmlld3BvcnRXaWR0aCxcclxuICAgICAgZGV2aWNlU2NhbGVGYWN0b3I6IGlzU1ZHID8gMSA6IHBhcnNlRmxvYXQoZXhwb3J0T3B0aW9ucy5zY2FsZSlcclxuICAgIH0pO1xyXG5cclxuICAgIGxldCByZXN1bHQ7XHJcbiAgICAvLyBSYXN0ZXJpemF0aW9uIHByb2Nlc3NcclxuICAgIHN3aXRjaCAoZXhwb3J0T3B0aW9ucy50eXBlKSB7XHJcbiAgICAgIGNhc2UgJ3N2Zyc6XHJcbiAgICAgICAgcmVzdWx0ID0gYXdhaXQgX2NyZWF0ZVNWRyhwYWdlKTtcclxuICAgICAgICBicmVhaztcclxuICAgICAgY2FzZSAncG5nJzpcclxuICAgICAgY2FzZSAnanBlZyc6XHJcbiAgICAgICAgcmVzdWx0ID0gYXdhaXQgX2NyZWF0ZUltYWdlKFxyXG4gICAgICAgICAgcGFnZSxcclxuICAgICAgICAgIGV4cG9ydE9wdGlvbnMudHlwZSxcclxuICAgICAgICAgIHtcclxuICAgICAgICAgICAgd2lkdGg6IHZpZXdwb3J0V2lkdGgsXHJcbiAgICAgICAgICAgIGhlaWdodDogdmlld3BvcnRIZWlnaHQsXHJcbiAgICAgICAgICAgIHgsXHJcbiAgICAgICAgICAgIHlcclxuICAgICAgICAgIH0sXHJcbiAgICAgICAgICBleHBvcnRPcHRpb25zLnJhc3Rlcml6YXRpb25UaW1lb3V0XHJcbiAgICAgICAgKTtcclxuICAgICAgICBicmVhaztcclxuICAgICAgY2FzZSAncGRmJzpcclxuICAgICAgICByZXN1bHQgPSBhd2FpdCBfY3JlYXRlUERGKFxyXG4gICAgICAgICAgcGFnZSxcclxuICAgICAgICAgIHZpZXdwb3J0SGVpZ2h0LFxyXG4gICAgICAgICAgdmlld3BvcnRXaWR0aCxcclxuICAgICAgICAgIGV4cG9ydE9wdGlvbnMucmFzdGVyaXphdGlvblRpbWVvdXRcclxuICAgICAgICApO1xyXG4gICAgICAgIGJyZWFrO1xyXG4gICAgICBkZWZhdWx0OlxyXG4gICAgICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcihcclxuICAgICAgICAgIGBbZXhwb3J0XSBVbnN1cHBvcnRlZCBvdXRwdXQgZm9ybWF0OiAke2V4cG9ydE9wdGlvbnMudHlwZX0uYCxcclxuICAgICAgICAgIDQwMFxyXG4gICAgICAgICk7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gQ2xlYXIgcHJldmlvdXNseSBpbmplY3RlZCBKUyBhbmQgQ1NTIHJlc291cmNlc1xyXG4gICAgYXdhaXQgY2xlYXJQYWdlUmVzb3VyY2VzKHBhZ2UsIGluamVjdGVkUmVzb3VyY2VzKTtcclxuICAgIHJldHVybiByZXN1bHQ7XHJcbiAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgIGF3YWl0IGNsZWFyUGFnZVJlc291cmNlcyhwYWdlLCBpbmplY3RlZFJlc291cmNlcyk7XHJcbiAgICByZXR1cm4gZXJyb3I7XHJcbiAgfVxyXG59XHJcblxyXG4vKipcclxuICogUmV0cmlldmVzIHRoZSBjbGlwcGluZyByZWdpb24gY29vcmRpbmF0ZXMgb2YgdGhlIHNwZWNpZmllZCBwYWdlIGVsZW1lbnRcclxuICogd2l0aCB0aGUgJ2NoYXJ0LWNvbnRhaW5lcicgaWQuXHJcbiAqXHJcbiAqIEBhc3luY1xyXG4gKiBAZnVuY3Rpb24gX2dldENsaXBSZWdpb25cclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IHBhZ2UgLSBQdXBwZXRlZXIgcGFnZSBvYmplY3QuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtQcm9taXNlPE9iamVjdD59IEEgUHJvbWlzZSB0aGF0IHJlc29sdmVzIHRvIGFuIG9iamVjdCBjb250YWluaW5nXHJcbiAqIGB4YCwgYHlgLCBgd2lkdGhgLCBhbmQgYGhlaWdodGAgcHJvcGVydGllcy5cclxuICovXHJcbmFzeW5jIGZ1bmN0aW9uIF9nZXRDbGlwUmVnaW9uKHBhZ2UpIHtcclxuICByZXR1cm4gcGFnZS4kZXZhbCgnI2NoYXJ0LWNvbnRhaW5lcicsIChlbGVtZW50KSA9PiB7XHJcbiAgICBjb25zdCB7IHgsIHksIHdpZHRoLCBoZWlnaHQgfSA9IGVsZW1lbnQuZ2V0Qm91bmRpbmdDbGllbnRSZWN0KCk7XHJcbiAgICByZXR1cm4ge1xyXG4gICAgICB4LFxyXG4gICAgICB5LFxyXG4gICAgICB3aWR0aCxcclxuICAgICAgaGVpZ2h0OiBNYXRoLnRydW5jKGhlaWdodCA+IDEgPyBoZWlnaHQgOiA1MDApXHJcbiAgICB9O1xyXG4gIH0pO1xyXG59XHJcblxyXG4vKipcclxuICogQ3JlYXRlcyBhbiBTVkcgYnkgZXZhbHVhdGluZyB0aGUgYG91dGVySFRNTGAgb2YgdGhlIGZpcnN0ICdzdmcnIGVsZW1lbnRcclxuICogaW5zaWRlIGFuIGVsZW1lbnQgd2l0aCB0aGUgaWQgJ2NvbnRhaW5lcicuXHJcbiAqXHJcbiAqIEBhc3luY1xyXG4gKiBAZnVuY3Rpb24gX2NyZWF0ZVNWR1xyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gcGFnZSAtIFB1cHBldGVlciBwYWdlIG9iamVjdC5cclxuICpcclxuICogQHJldHVybnMge1Byb21pc2U8c3RyaW5nPn0gQSBQcm9taXNlIHRoYXQgcmVzb2x2ZXMgdG8gdGhlIFNWRyBzdHJpbmcuXHJcbiAqL1xyXG5hc3luYyBmdW5jdGlvbiBfY3JlYXRlU1ZHKHBhZ2UpIHtcclxuICByZXR1cm4gcGFnZS4kZXZhbChcclxuICAgICcjY29udGFpbmVyIHN2ZzpmaXJzdC1vZi10eXBlJyxcclxuICAgIChlbGVtZW50KSA9PiBlbGVtZW50Lm91dGVySFRNTFxyXG4gICk7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBDcmVhdGVzIGFuIGltYWdlIHVzaW5nIFB1cHBldGVlcidzIHBhZ2UgYHNjcmVlbnNob3RgIGZ1bmN0aW9uYWxpdHkgd2l0aFxyXG4gKiBzcGVjaWZpZWQgb3B0aW9ucy5cclxuICpcclxuICogQGFzeW5jXHJcbiAqIEBmdW5jdGlvbiBfY3JlYXRlSW1hZ2VcclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IHBhZ2UgLSBQdXBwZXRlZXIgcGFnZSBvYmplY3QuXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSB0eXBlIC0gSW1hZ2UgdHlwZS5cclxuICogQHBhcmFtIHtPYmplY3R9IGNsaXAgLSBDbGlwcGluZyByZWdpb24gY29vcmRpbmF0ZXMuXHJcbiAqIEBwYXJhbSB7bnVtYmVyfSByYXN0ZXJpemF0aW9uVGltZW91dCAtIFRpbWVvdXQgZm9yIHJhc3Rlcml6YXRpb25cclxuICogaW4gbWlsbGlzZWNvbmRzLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7UHJvbWlzZTxCdWZmZXI+fSBBIFByb21pc2UgdGhhdCByZXNvbHZlcyB0byB0aGUgaW1hZ2UgYnVmZmVyXHJcbiAqIG9yIHJlamVjdGluZyB3aXRoIGFuIGBFeHBvcnRFcnJvcmAgZm9yIHRpbWVvdXQuXHJcbiAqL1xyXG5hc3luYyBmdW5jdGlvbiBfY3JlYXRlSW1hZ2UocGFnZSwgdHlwZSwgY2xpcCwgcmFzdGVyaXphdGlvblRpbWVvdXQpIHtcclxuICByZXR1cm4gUHJvbWlzZS5yYWNlKFtcclxuICAgIHBhZ2Uuc2NyZWVuc2hvdCh7XHJcbiAgICAgIHR5cGUsXHJcbiAgICAgIGNsaXAsXHJcbiAgICAgIGVuY29kaW5nOiAnYmFzZTY0JyxcclxuICAgICAgZnVsbFBhZ2U6IGZhbHNlLFxyXG4gICAgICBvcHRpbWl6ZUZvclNwZWVkOiB0cnVlLFxyXG4gICAgICBjYXB0dXJlQmV5b25kVmlld3BvcnQ6IHRydWUsXHJcbiAgICAgIC4uLih0eXBlICE9PSAncG5nJyA/IHsgcXVhbGl0eTogODAgfSA6IHt9KSxcclxuICAgICAgLy8gQWx3YXlzIHJlbmRlciBvbiBhIHRyYW5zcGFyZW50IHBhZ2UgaWYgdGhlIGV4cGVjdGVkIHR5cGUgZm9ybWF0IGlzIFBOR1xyXG4gICAgICBvbWl0QmFja2dyb3VuZDogdHlwZSA9PSAncG5nJyAvLyAjNDQ3LCAjNDYzXHJcbiAgICB9KSxcclxuICAgIG5ldyBQcm9taXNlKChfcmVzb2x2ZSwgcmVqZWN0KSA9PlxyXG4gICAgICBzZXRUaW1lb3V0KFxyXG4gICAgICAgICgpID0+IHJlamVjdChuZXcgRXhwb3J0RXJyb3IoJ1Jhc3Rlcml6YXRpb24gdGltZW91dCcsIDQwOCkpLFxyXG4gICAgICAgIHJhc3Rlcml6YXRpb25UaW1lb3V0IHx8IDE1MDBcclxuICAgICAgKVxyXG4gICAgKVxyXG4gIF0pO1xyXG59XHJcblxyXG4vKipcclxuICogQ3JlYXRlcyBhIFBERiB1c2luZyBQdXBwZXRlZXIncyBwYWdlIGBwZGZgIGZ1bmN0aW9uYWxpdHkgd2l0aCBzcGVjaWZpZWRcclxuICogb3B0aW9ucy5cclxuICpcclxuICogQGFzeW5jXHJcbiAqIEBmdW5jdGlvbiBfY3JlYXRlUERGXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBwYWdlIC0gUHVwcGV0ZWVyIHBhZ2Ugb2JqZWN0LlxyXG4gKiBAcGFyYW0ge251bWJlcn0gaGVpZ2h0IC0gUERGIGhlaWdodC5cclxuICogQHBhcmFtIHtudW1iZXJ9IHdpZHRoIC0gUERGIHdpZHRoLlxyXG4gKiBAcGFyYW0ge251bWJlcn0gcmFzdGVyaXphdGlvblRpbWVvdXQgLSBUaW1lb3V0IGZvciByYXN0ZXJpemF0aW9uXHJcbiAqIGluIG1pbGxpc2Vjb25kcy5cclxuICpcclxuICogQHJldHVybnMge1Byb21pc2U8QnVmZmVyPn0gQSBQcm9taXNlIHRoYXQgcmVzb2x2ZXMgdG8gdGhlIFBERiBidWZmZXIuXHJcbiAqL1xyXG5hc3luYyBmdW5jdGlvbiBfY3JlYXRlUERGKHBhZ2UsIGhlaWdodCwgd2lkdGgsIHJhc3Rlcml6YXRpb25UaW1lb3V0KSB7XHJcbiAgYXdhaXQgcGFnZS5lbXVsYXRlTWVkaWFUeXBlKCdzY3JlZW4nKTtcclxuICByZXR1cm4gcGFnZS5wZGYoe1xyXG4gICAgLy8gVGhpcyB3aWxsIHJlbW92ZSBhbiBleHRyYSBlbXB0eSBwYWdlIGluIFBERiBleHBvcnRzXHJcbiAgICBoZWlnaHQ6IGhlaWdodCArIDEsXHJcbiAgICB3aWR0aCxcclxuICAgIGVuY29kaW5nOiAnYmFzZTY0JyxcclxuICAgIHRpbWVvdXQ6IHJhc3Rlcml6YXRpb25UaW1lb3V0IHx8IDE1MDBcclxuICB9KTtcclxufVxyXG5cclxuZXhwb3J0IGRlZmF1bHQge1xyXG4gIHB1cHBldGVlckV4cG9ydFxyXG59O1xyXG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxyXG5cclxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXHJcblxyXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNSwgSGlnaHNvZnRcclxuXHJcbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cclxuXHJcbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxyXG5cclxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxyXG5cclxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cclxuXHJcbi8qKlxyXG4gKiBAb3ZlcnZpZXcgVGhpcyBtb2R1bGUgcHJvdmlkZXMgYSB3b3JrZXIgcG9vbCBpbXBsZW1lbnRhdGlvbiBmb3IgbWFuYWdpbmdcclxuICogdGhlIGJyb3dzZXIgaW5zdGFuY2UgYW5kIHBhZ2VzLCBzcGVjaWZpY2FsbHkgZGVzaWduZWQgZm9yIHVzZSB3aXRoXHJcbiAqIHRoZSBIaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXIuIEl0IG9wdGltaXplcyByZXNvdXJjZXMgdXNhZ2UgYW5kIHBlcmZvcm1hbmNlXHJcbiAqIGJ5IG1haW50YWluaW5nIGEgcG9vbCBvZiB3b3JrZXJzIHRoYXQgY2FuIGhhbmRsZSBjb25jdXJyZW50IGV4cG9ydCB0YXNrc1xyXG4gKiB1c2luZyBQdXBwZXRlZXIuXHJcbiAqL1xyXG5cclxuaW1wb3J0IHsgUG9vbCB9IGZyb20gJ3Rhcm4nO1xyXG5pbXBvcnQgeyB2NCBhcyB1dWlkIH0gZnJvbSAndXVpZCc7XHJcblxyXG5pbXBvcnQgeyBjcmVhdGVCcm93c2VyLCBjbG9zZUJyb3dzZXIsIG5ld1BhZ2UsIGNsZWFyUGFnZSB9IGZyb20gJy4vYnJvd3Nlci5qcyc7XHJcbmltcG9ydCB7IHB1cHBldGVlckV4cG9ydCB9IGZyb20gJy4vZXhwb3J0LmpzJztcclxuaW1wb3J0IHsgbG9nLCBsb2dXaXRoU3RhY2sgfSBmcm9tICcuL2xvZ2dlci5qcyc7XHJcbmltcG9ydCB7IGdldE5ld0RhdGVUaW1lLCBtZWFzdXJlVGltZSB9IGZyb20gJy4vdXRpbHMuanMnO1xyXG5cclxuaW1wb3J0IEV4cG9ydEVycm9yIGZyb20gJy4vZXJyb3JzL0V4cG9ydEVycm9yLmpzJztcclxuXHJcbi8vIFRoZSBwb29sIGluc3RhbmNlXHJcbmxldCBwb29sID0gbnVsbDtcclxuXHJcbi8vIFBvb2wgc3RhdGlzdGljc1xyXG5jb25zdCBwb29sU3RhdHMgPSB7XHJcbiAgZXhwb3J0c0F0dGVtcHRlZDogMCxcclxuICBleHBvcnRzUGVyZm9ybWVkOiAwLFxyXG4gIGV4cG9ydHNEcm9wcGVkOiAwLFxyXG4gIGV4cG9ydHNGcm9tU3ZnOiAwLFxyXG4gIGV4cG9ydHNGcm9tT3B0aW9uczogMCxcclxuICBleHBvcnRzRnJvbVN2Z0F0dGVtcHRzOiAwLFxyXG4gIGV4cG9ydHNGcm9tT3B0aW9uc0F0dGVtcHRzOiAwLFxyXG4gIHRpbWVTcGVudDogMCxcclxuICB0aW1lU3BlbnRBdmVyYWdlOiAwXHJcbn07XHJcblxyXG4vKipcclxuICogSW5pdGlhbGl6ZXMgdGhlIGV4cG9ydCBwb29sIHdpdGggdGhlIHByb3ZpZGVkIGNvbmZpZ3VyYXRpb24sIGNyZWF0aW5nXHJcbiAqIGEgYnJvd3NlciBpbnN0YW5jZSBhbmQgc2V0dGluZyB1cCB3b3JrZXIgcmVzb3VyY2VzLlxyXG4gKlxyXG4gKiBAYXN5bmNcclxuICogQGZ1bmN0aW9uIGluaXRQb29sXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBwb29sT3B0aW9ucyAtIFRoZSBjb25maWd1cmF0aW9uIG9iamVjdCBjb250YWluaW5nIGBwb29sYFxyXG4gKiBvcHRpb25zLlxyXG4gKiBAcGFyYW0ge0FycmF5LjxzdHJpbmc+fSBwdXBwZXRlZXJBcmdzIC0gQWRkaXRpb25hbCBhcmd1bWVudHMgZm9yIFB1cHBldGVlclxyXG4gKiBsYXVuY2guXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtQcm9taXNlPHZvaWQ+fSBBIFByb21pc2UgdGhhdCByZXNvbHZlcyB0byBlbmRpbmcgdGhlIGZ1bmN0aW9uXHJcbiAqIGV4ZWN1dGlvbiB3aGVuIGFuIGFscmVhZHkgaW5pdGlhbGl6ZWQgcG9vbCBvZiByZXNvdXJjZXMgaXMgZm91bmQuXHJcbiAqXHJcbiAqIEB0aHJvd3Mge0V4cG9ydEVycm9yfSBUaHJvd3MgYW4gYEV4cG9ydEVycm9yYCBpZiBjb3VsZCBub3QgY3JlYXRlIHRoZSBwb29sXHJcbiAqIG9mIHdvcmtlcnMuXHJcbiAqL1xyXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gaW5pdFBvb2wocG9vbE9wdGlvbnMsIHB1cHBldGVlckFyZ3MpIHtcclxuICAvLyBDcmVhdGUgYSBicm93c2VyIGluc3RhbmNlIHdpdGggdGhlIHB1cHBldGVlciBhcmd1bWVudHNcclxuICBhd2FpdCBjcmVhdGVCcm93c2VyKHB1cHBldGVlckFyZ3MpO1xyXG5cclxuICB0cnkge1xyXG4gICAgbG9nKFxyXG4gICAgICAzLFxyXG4gICAgICBgW3Bvb2xdIEluaXRpYWxpemluZyBwb29sIHdpdGggd29ya2VyczogbWluICR7cG9vbE9wdGlvbnMubWluV29ya2Vyc30sIG1heCAke3Bvb2xPcHRpb25zLm1heFdvcmtlcnN9LmBcclxuICAgICk7XHJcblxyXG4gICAgaWYgKHBvb2wpIHtcclxuICAgICAgbG9nKFxyXG4gICAgICAgIDQsXHJcbiAgICAgICAgJ1twb29sXSBBbHJlYWR5IGluaXRpYWxpemVkLCBwbGVhc2Uga2lsbCBpdCBiZWZvcmUgY3JlYXRpbmcgYSBuZXcgb25lLidcclxuICAgICAgKTtcclxuICAgICAgcmV0dXJuO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIEtlZXAgYW4gZXllIG9uIGEgY29ycmVjdCBtaW4gYW5kIG1heCB3b3JrZXJzIG51bWJlclxyXG4gICAgaWYgKHBvb2xPcHRpb25zLm1pbldvcmtlcnMgPiBwb29sT3B0aW9ucy5tYXhXb3JrZXJzKSB7XHJcbiAgICAgIHBvb2xPcHRpb25zLm1pbldvcmtlcnMgPSBwb29sT3B0aW9ucy5tYXhXb3JrZXJzO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIENyZWF0ZSBhIHBvb2wgYWxvbmcgd2l0aCBhIG1pbmltYWwgbnVtYmVyIG9mIHJlc291cmNlc1xyXG4gICAgcG9vbCA9IG5ldyBQb29sKHtcclxuICAgICAgLy8gR2V0IHRoZSBgY3JlYXRlYCwgYHZhbGlkYXRlYCwgYW5kIGBkZXN0cm95YCBmdW5jdGlvbnNcclxuICAgICAgLi4uX2ZhY3RvcnkocG9vbE9wdGlvbnMpLFxyXG4gICAgICBtaW46IHBvb2xPcHRpb25zLm1pbldvcmtlcnMsXHJcbiAgICAgIG1heDogcG9vbE9wdGlvbnMubWF4V29ya2VycyxcclxuICAgICAgYWNxdWlyZVRpbWVvdXRNaWxsaXM6IHBvb2xPcHRpb25zLmFjcXVpcmVUaW1lb3V0LFxyXG4gICAgICBjcmVhdGVUaW1lb3V0TWlsbGlzOiBwb29sT3B0aW9ucy5jcmVhdGVUaW1lb3V0LFxyXG4gICAgICBkZXN0cm95VGltZW91dE1pbGxpczogcG9vbE9wdGlvbnMuZGVzdHJveVRpbWVvdXQsXHJcbiAgICAgIGlkbGVUaW1lb3V0TWlsbGlzOiBwb29sT3B0aW9ucy5pZGxlVGltZW91dCxcclxuICAgICAgY3JlYXRlUmV0cnlJbnRlcnZhbE1pbGxpczogcG9vbE9wdGlvbnMuY3JlYXRlUmV0cnlJbnRlcnZhbCxcclxuICAgICAgcmVhcEludGVydmFsTWlsbGlzOiBwb29sT3B0aW9ucy5yZWFwZXJJbnRlcnZhbCxcclxuICAgICAgcHJvcGFnYXRlQ3JlYXRlRXJyb3I6IGZhbHNlXHJcbiAgICB9KTtcclxuXHJcbiAgICAvLyBTZXQgZXZlbnRzXHJcbiAgICBwb29sLm9uKCdyZWxlYXNlJywgYXN5bmMgKHJlc291cmNlKSA9PiB7XHJcbiAgICAgIC8vIENsZWFyIHBhZ2VcclxuICAgICAgY29uc3QgY2xlYXJTdGF0dXMgPSBhd2FpdCBjbGVhclBhZ2UocmVzb3VyY2UsIGZhbHNlKTtcclxuICAgICAgbG9nKFxyXG4gICAgICAgIDQsXHJcbiAgICAgICAgYFtwb29sXSBQb29sIHJlc291cmNlIFske3Jlc291cmNlLmlkfV0gLSBSZWxlYXNpbmcgYSB3b3JrZXIuIENsZWFyIHBhZ2Ugc3RhdHVzOiAke2NsZWFyU3RhdHVzfS5gXHJcbiAgICAgICk7XHJcbiAgICB9KTtcclxuXHJcbiAgICBwb29sLm9uKCdkZXN0cm95U3VjY2VzcycsIChfZXZlbnRJZCwgcmVzb3VyY2UpID0+IHtcclxuICAgICAgbG9nKFxyXG4gICAgICAgIDQsXHJcbiAgICAgICAgYFtwb29sXSBQb29sIHJlc291cmNlIFske3Jlc291cmNlLmlkfV0gLSBEZXN0cm95ZWQgYSB3b3JrZXIgc3VjY2Vzc2Z1bGx5LmBcclxuICAgICAgKTtcclxuICAgICAgcmVzb3VyY2UucGFnZSA9IG51bGw7XHJcbiAgICB9KTtcclxuXHJcbiAgICBjb25zdCBpbml0aWFsUmVzb3VyY2VzID0gW107XHJcbiAgICAvLyBDcmVhdGUgYW4gaW5pdGlhbCBudW1iZXIgb2YgcmVzb3VyY2VzXHJcbiAgICBmb3IgKGxldCBpID0gMDsgaSA8IHBvb2xPcHRpb25zLm1pbldvcmtlcnM7IGkrKykge1xyXG4gICAgICB0cnkge1xyXG4gICAgICAgIGNvbnN0IHJlc291cmNlID0gYXdhaXQgcG9vbC5hY3F1aXJlKCkucHJvbWlzZTtcclxuICAgICAgICBpbml0aWFsUmVzb3VyY2VzLnB1c2gocmVzb3VyY2UpO1xyXG4gICAgICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgICAgIGxvZ1dpdGhTdGFjaygyLCBlcnJvciwgJ1twb29sXSBDb3VsZCBub3QgY3JlYXRlIGFuIGluaXRpYWwgcmVzb3VyY2UuJyk7XHJcbiAgICAgIH1cclxuICAgIH1cclxuXHJcbiAgICAvLyBSZWxlYXNlIHRoZSBpbml0aWFsIG51bWJlciBvZiByZXNvdXJjZXMgYmFjayB0byB0aGUgcG9vbFxyXG4gICAgaW5pdGlhbFJlc291cmNlcy5mb3JFYWNoKChyZXNvdXJjZSkgPT4ge1xyXG4gICAgICBwb29sLnJlbGVhc2UocmVzb3VyY2UpO1xyXG4gICAgfSk7XHJcblxyXG4gICAgbG9nKFxyXG4gICAgICAzLFxyXG4gICAgICBgW3Bvb2xdIFRoZSBwb29sIGlzIHJlYWR5JHtpbml0aWFsUmVzb3VyY2VzLmxlbmd0aCA/IGAgd2l0aCAke2luaXRpYWxSZXNvdXJjZXMubGVuZ3RofSBpbml0aWFsIHJlc291cmNlcyB3YWl0aW5nLmAgOiAnLid9YFxyXG4gICAgKTtcclxuICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgdGhyb3cgbmV3IEV4cG9ydEVycm9yKFxyXG4gICAgICAnW3Bvb2xdIENvdWxkIG5vdCBjb25maWd1cmUgYW5kIGNyZWF0ZSB0aGUgcG9vbCBvZiB3b3JrZXJzLicsXHJcbiAgICAgIDUwMFxyXG4gICAgKS5zZXRFcnJvcihlcnJvcik7XHJcbiAgfVxyXG59XHJcblxyXG4vKipcclxuICogVGVybWluYXRlcyBhbGwgd29ya2VycyBpbiB0aGUgcG9vbCwgZGVzdHJveXMgdGhlIHBvb2wsIGFuZCBjbG9zZXMgdGhlIGJyb3dzZXJcclxuICogaW5zdGFuY2UuXHJcbiAqXHJcbiAqIEBhc3luY1xyXG4gKiBAZnVuY3Rpb24ga2lsbFBvb2xcclxuICpcclxuICogQHJldHVybnMge1Byb21pc2U8dm9pZD59IEEgUHJvbWlzZSB0aGF0IHJlc29sdmVzIG9uY2UgYWxsIHdvcmtlcnMgYXJlXHJcbiAqIHRlcm1pbmF0ZWQsIHRoZSBwb29sIGlzIGRlc3Ryb3llZCwgYW5kIHRoZSBicm93c2VyIGlzIHN1Y2Nlc3NmdWxseSBjbG9zZWQuXHJcbiAqL1xyXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24ga2lsbFBvb2woKSB7XHJcbiAgbG9nKDMsICdbcG9vbF0gS2lsbGluZyBwb29sIHdpdGggYWxsIHdvcmtlcnMgYW5kIGNsb3NpbmcgYnJvd3Nlci4nKTtcclxuXHJcbiAgLy8gSWYgc3RpbGwgYWxpdmUsIGRlc3Ryb3kgdGhlIHBvb2wgb2YgcGFnZXMgYmVmb3JlIGNsb3NpbmcgYSBicm93c2VyXHJcbiAgaWYgKHBvb2wpIHtcclxuICAgIC8vIEZyZWUgdXAgbm90IHJlbGVhc2VkIHdvcmtlcnNcclxuICAgIGZvciAoY29uc3Qgd29ya2VyIG9mIHBvb2wudXNlZCkge1xyXG4gICAgICBwb29sLnJlbGVhc2Uod29ya2VyLnJlc291cmNlKTtcclxuICAgIH1cclxuXHJcbiAgICAvLyBEZXN0cm95IHRoZSBwb29sIGlmIGl0IGlzIHN0aWxsIGF2YWlsYWJsZVxyXG4gICAgaWYgKCFwb29sLmRlc3Ryb3llZCkge1xyXG4gICAgICBhd2FpdCBwb29sLmRlc3Ryb3koKTtcclxuICAgICAgbG9nKDQsICdbcG9vbF0gRGVzdHJveWVkIHRoZSBwb29sIG9mIHJlc291cmNlcy4nKTtcclxuICAgIH1cclxuICAgIHBvb2wgPSBudWxsO1xyXG4gIH1cclxuXHJcbiAgLy8gQ2xvc2UgdGhlIGJyb3dzZXIgaW5zdGFuY2VcclxuICBhd2FpdCBjbG9zZUJyb3dzZXIoKTtcclxufVxyXG5cclxuLyoqXHJcbiAqIFByb2Nlc3NlcyB0aGUgZXhwb3J0IHdvcmsgdXNpbmcgYSB3b3JrZXIgZnJvbSB0aGUgcG9vbC4gQWNxdWlyZXMgYSB3b3JrZXJcclxuICogaGFuZGxlIGZyb20gdGhlIHBvb2wsIHBlcmZvcm1zIHRoZSBleHBvcnQgdXNpbmcgcHVwcGV0ZWVyLCBhbmQgcmVsZWFzZXNcclxuICogdGhlIHdvcmtlciBoYW5kbGUgYmFjayB0byB0aGUgcG9vbC5cclxuICpcclxuICogQGFzeW5jXHJcbiAqIEBmdW5jdGlvbiBwb3N0V29ya1xyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gb3B0aW9ucyAtIFRoZSBjb25maWd1cmF0aW9uIG9iamVjdCBjb250YWluaW5nIGNvbXBsZXRlIHNldFxyXG4gKiBvZiBvcHRpb25zLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7UHJvbWlzZTxPYmplY3Q+fSBBIFByb21pc2UgdGhhdCByZXNvbHZlcyB0byB0aGUgZXhwb3J0IHJlc3VsdFxyXG4gKiBhbmQgb3B0aW9ucy5cclxuICpcclxuICogQHRocm93cyB7RXhwb3J0RXJyb3J9IFRocm93cyBhbiBgRXhwb3J0RXJyb3JgIGlmIGFuIGVycm9yIG9jY3VycyBkdXJpbmdcclxuICogdGhlIGV4cG9ydCBwcm9jZXNzLlxyXG4gKi9cclxuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIHBvc3RXb3JrKG9wdGlvbnMpIHtcclxuICBsZXQgd29ya2VySGFuZGxlO1xyXG5cclxuICB0cnkge1xyXG4gICAgbG9nKDQsICdbcG9vbF0gV29yayByZWNlaXZlZCwgc3RhcnRpbmcgdG8gcHJvY2Vzcy4nKTtcclxuXHJcbiAgICAvLyBBbiBleHBvcnQgYXR0ZW1wdCBjb3VudGVkXHJcbiAgICArK3Bvb2xTdGF0cy5leHBvcnRzQXR0ZW1wdGVkO1xyXG5cclxuICAgIC8vIERpc3BsYXkgdGhlIHBvb2wgaW5mb3JtYXRpb24gaWYgbmVlZGVkXHJcbiAgICBpZiAob3B0aW9ucy5wb29sLmJlbmNobWFya2luZykge1xyXG4gICAgICBnZXRQb29sSW5mbygpO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIFRocm93IGFuIGVycm9yIGluIGNhc2Ugb2YgbGFja2luZyB0aGUgcG9vbCBpbnN0YW5jZVxyXG4gICAgaWYgKCFwb29sKSB7XHJcbiAgICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcihcclxuICAgICAgICAnW3Bvb2xdIFdvcmsgcmVjZWl2ZWQsIGJ1dCBwb29sIGhhcyBub3QgYmVlbiBzdGFydGVkLicsXHJcbiAgICAgICAgNTAwXHJcbiAgICAgICk7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gVGhlIGFjcXVpcmUgY291bnRlclxyXG4gICAgY29uc3QgYWNxdWlyZUNvdW50ZXIgPSBtZWFzdXJlVGltZSgpO1xyXG5cclxuICAgIC8vIFRyeSB0byBhY3F1aXJlIHRoZSB3b3JrZXIgYWxvbmcgd2l0aCB0aGUgaWQsIHdvcmtzIGNvdW50IGFuZCBwYWdlXHJcbiAgICB0cnkge1xyXG4gICAgICBsb2coNCwgJ1twb29sXSBBY3F1aXJpbmcgYSB3b3JrZXIgaGFuZGxlLicpO1xyXG5cclxuICAgICAgLy8gQWNxdWlyZSBhIHBvb2wgcmVzb3VyY2VcclxuICAgICAgd29ya2VySGFuZGxlID0gYXdhaXQgcG9vbC5hY3F1aXJlKCkucHJvbWlzZTtcclxuXHJcbiAgICAgIC8vIENoZWNrIHRoZSBwYWdlIGFjcXVpcmUgdGltZVxyXG4gICAgICBpZiAob3B0aW9ucy5zZXJ2ZXIuYmVuY2htYXJraW5nKSB7XHJcbiAgICAgICAgbG9nKFxyXG4gICAgICAgICAgNSxcclxuICAgICAgICAgIGBbYmVuY2htYXJrXSAke29wdGlvbnMucmVxdWVzdElkID8gYFJlcXVlc3QgWyR7b3B0aW9ucy5yZXF1ZXN0SWR9XSAtIGAgOiAnJ31gLFxyXG4gICAgICAgICAgYEFjcXVpcmluZyBhIHdvcmtlciBoYW5kbGUgdG9vayAke2FjcXVpcmVDb3VudGVyKCl9bXMuYFxyXG4gICAgICAgICk7XHJcbiAgICAgIH1cclxuICAgIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcihcclxuICAgICAgICBgW3Bvb2xdICR7XHJcbiAgICAgICAgICBvcHRpb25zLnJlcXVlc3RJZCA/IGBSZXF1ZXN0IFske29wdGlvbnMucmVxdWVzdElkfV0gLSBgIDogJydcclxuICAgICAgICB9RXJyb3IgZW5jb3VudGVyZWQgd2hlbiBhY3F1aXJpbmcgYW4gYXZhaWxhYmxlIGVudHJ5OiAke2FjcXVpcmVDb3VudGVyKCl9bXMuYCxcclxuICAgICAgICA0MDBcclxuICAgICAgKS5zZXRFcnJvcihlcnJvcik7XHJcbiAgICB9XHJcbiAgICBsb2coNCwgJ1twb29sXSBBY3F1aXJlZCBhIHdvcmtlciBoYW5kbGUuJyk7XHJcblxyXG4gICAgaWYgKCF3b3JrZXJIYW5kbGUucGFnZSkge1xyXG4gICAgICAvLyBTZXQgdGhlIGB3b3JrTGltaXRgIHRvIGV4Y2VlZGVkIGluIG9yZGVyIHRvIHJlY3JlYXRlIHRoZSByZXNvdXJjZVxyXG4gICAgICB3b3JrZXJIYW5kbGUud29ya0NvdW50ID0gb3B0aW9ucy5wb29sLndvcmtMaW1pdCArIDE7XHJcbiAgICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcihcclxuICAgICAgICAnW3Bvb2xdIFJlc29sdmVkIHdvcmtlciBwYWdlIGlzIGludmFsaWQ6IHRoZSBwb29sIHNldHVwIGlzIHdvbmt5LicsXHJcbiAgICAgICAgNDAwXHJcbiAgICAgICk7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gU2F2ZSB0aGUgc3RhcnQgdGltZVxyXG4gICAgY29uc3Qgd29ya1N0YXJ0ID0gZ2V0TmV3RGF0ZVRpbWUoKTtcclxuXHJcbiAgICBsb2coXHJcbiAgICAgIDQsXHJcbiAgICAgIGBbcG9vbF0gUG9vbCByZXNvdXJjZSBbJHt3b3JrZXJIYW5kbGUuaWR9XSAtIFN0YXJ0aW5nIHdvcmsgb24gdGhpcyBwb29sIGVudHJ5LmBcclxuICAgICk7XHJcblxyXG4gICAgLy8gU3RhcnQgbWVhc3VyaW5nIGV4cG9ydCB0aW1lXHJcbiAgICBjb25zdCBleHBvcnRDb3VudGVyID0gbWVhc3VyZVRpbWUoKTtcclxuXHJcbiAgICAvLyBQZXJmb3JtIGFuIGV4cG9ydCBvbiBhIHB1cHBldGVlciBsZXZlbFxyXG4gICAgY29uc3QgcmVzdWx0ID0gYXdhaXQgcHVwcGV0ZWVyRXhwb3J0KFxyXG4gICAgICB3b3JrZXJIYW5kbGUucGFnZSxcclxuICAgICAgb3B0aW9ucy5leHBvcnQsXHJcbiAgICAgIG9wdGlvbnMuY3VzdG9tTG9naWNcclxuICAgICk7XHJcblxyXG4gICAgLy8gQ2hlY2sgaWYgaXQncyBhbiBlcnJvclxyXG4gICAgaWYgKHJlc3VsdCBpbnN0YW5jZW9mIEVycm9yKSB7XHJcbiAgICAgIC8vIE5PVEU6XHJcbiAgICAgIC8vIElmIHRoZXJlJ3MgYSByYXN0ZXJpemF0aW9uIHRpbWVvdXQsIHdlIHdhbnQgbmVlZCB0byBmbHVzaCB0aGUgcGFnZS5cclxuICAgICAgLy8gVGhpcyBpcyBiZWNhdXNlIHRoZSBwYWdlIG1heSBiZSBpbiBhIHN0YXRlIHdoZXJlIGl0J3Mgd2FpdGluZyBmb3JcclxuICAgICAgLy8gdGhlIHNjcmVlbnNob3QgdG8gZmluaXNoIGV2ZW4gdGhvdWdoIHRoZSB0aW1lb3V0IGhhcyBvY2N1cmVkLlxyXG4gICAgICAvLyBXaGljaCBvZiBjb3Vyc2UgY2F1c2VzIGEgbG90IG9mIGlzc3VlcyB3aXRoIHRoZSBldmVudCBzeXN0ZW0sXHJcbiAgICAgIC8vIGFuZCBwYWdlIGNvbnNpc3RlbmN5LlxyXG4gICAgICAvL1xyXG4gICAgICAvLyBOT1RFOlxyXG4gICAgICAvLyBPbmx5IHBhZ2Uuc2NyZWVuc2hvdCB3aWxsIHRocm93IHRoaXMsIHRpbWVvdXRzIGZvciBQREYncyBhcmVcclxuICAgICAgLy8gaGFuZGxlZCBieSB0aGUgcGFnZS5wZGYgZnVuY3Rpb24gaXRzZWxmLlxyXG4gICAgICAvL1xyXG4gICAgICAvLyAuLi55ZXMsIHRoaXMgaXMgdWdseS5cclxuICAgICAgaWYgKHJlc3VsdC5tZXNzYWdlID09PSAnUmFzdGVyaXphdGlvbiB0aW1lb3V0Jykge1xyXG4gICAgICAgIC8vIFNldCB0aGUgYHdvcmtMaW1pdGAgdG8gZXhjZWVkZWQgaW4gb3JkZXIgdG8gcmVjcmVhdGUgdGhlIHJlc291cmNlXHJcbiAgICAgICAgd29ya2VySGFuZGxlLndvcmtDb3VudCA9IG9wdGlvbnMucG9vbC53b3JrTGltaXQgKyAxO1xyXG4gICAgICAgIHdvcmtlckhhbmRsZS5wYWdlID0gbnVsbDtcclxuICAgICAgfVxyXG5cclxuICAgICAgaWYgKFxyXG4gICAgICAgIHJlc3VsdC5uYW1lID09PSAnVGltZW91dEVycm9yJyB8fFxyXG4gICAgICAgIHJlc3VsdC5tZXNzYWdlID09PSAnUmFzdGVyaXphdGlvbiB0aW1lb3V0J1xyXG4gICAgICApIHtcclxuICAgICAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoXHJcbiAgICAgICAgICBgW3Bvb2xdICR7XHJcbiAgICAgICAgICAgIG9wdGlvbnMucmVxdWVzdElkID8gYFJlcXVlc3QgWyR7b3B0aW9ucy5yZXF1ZXN0SWR9XSAtIGAgOiAnJ1xyXG4gICAgICAgICAgfVJhc3Rlcml6YXRpb24gdGltZW91dDogeW91ciBjaGFydCBtYXkgYmUgdG9vIGNvbXBsZXggb3IgbGFyZ2UsIGFuZCBmYWlsZWQgdG8gcmVuZGVyIHdpdGhpbiB0aGUgYWxsb3R0ZWQgdGltZS5gXHJcbiAgICAgICAgKS5zZXRFcnJvcihyZXN1bHQpO1xyXG4gICAgICB9IGVsc2Uge1xyXG4gICAgICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcihcclxuICAgICAgICAgIGBbcG9vbF0gJHtcclxuICAgICAgICAgICAgb3B0aW9ucy5yZXF1ZXN0SWQgPyBgUmVxdWVzdCBbJHtvcHRpb25zLnJlcXVlc3RJZH1dIC0gYCA6ICcnXHJcbiAgICAgICAgICB9RXJyb3IgZW5jb3VudGVyZWQgZHVyaW5nIGV4cG9ydDogJHtleHBvcnRDb3VudGVyKCl9bXMuYFxyXG4gICAgICAgICkuc2V0RXJyb3IocmVzdWx0KTtcclxuICAgICAgfVxyXG4gICAgfVxyXG5cclxuICAgIC8vIENoZWNrIHRoZSBQdXBwZXRlZXIgZXhwb3J0IHRpbWVcclxuICAgIGlmIChvcHRpb25zLnNlcnZlci5iZW5jaG1hcmtpbmcpIHtcclxuICAgICAgbG9nKFxyXG4gICAgICAgIDUsXHJcbiAgICAgICAgYFtiZW5jaG1hcmtdICR7b3B0aW9ucy5yZXF1ZXN0SWQgPyBgUmVxdWVzdCBbJHtvcHRpb25zLnJlcXVlc3RJZH1dIC0gYCA6ICcnfWAsXHJcbiAgICAgICAgYEV4cG9ydGluZyBhIGNoYXJ0IHN1Y2Vzc2Z1bGx5IHRvb2sgJHtleHBvcnRDb3VudGVyKCl9bXMuYFxyXG4gICAgICApO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIFJlbGVhc2UgdGhlIHJlc291cmNlIGJhY2sgdG8gdGhlIHBvb2xcclxuICAgIHBvb2wucmVsZWFzZSh3b3JrZXJIYW5kbGUpO1xyXG5cclxuICAgIC8vIFVzZWQgZm9yIHN0YXRpc3RpY3MgaW4gYXZlcmFnZVRpbWUgYW5kIHByb2Nlc3NlZFdvcmtDb3VudCwgd2hpY2hcclxuICAgIC8vIGluIHR1cm4gaXMgdXNlZCBieSB0aGUgL2hlYWx0aCByb3V0ZS5cclxuICAgIGNvbnN0IHdvcmtFbmQgPSBnZXROZXdEYXRlVGltZSgpO1xyXG4gICAgY29uc3QgZXhwb3J0VGltZSA9IHdvcmtFbmQgLSB3b3JrU3RhcnQ7XHJcblxyXG4gICAgcG9vbFN0YXRzLnRpbWVTcGVudCArPSBleHBvcnRUaW1lO1xyXG4gICAgcG9vbFN0YXRzLnRpbWVTcGVudEF2ZXJhZ2UgPVxyXG4gICAgICBwb29sU3RhdHMudGltZVNwZW50IC8gKytwb29sU3RhdHMuZXhwb3J0c1BlcmZvcm1lZDtcclxuXHJcbiAgICBsb2coNCwgYFtwb29sXSBXb3JrIGNvbXBsZXRlZCBpbiAke2V4cG9ydFRpbWV9bXMuYCk7XHJcblxyXG4gICAgLy8gT3RoZXJ3aXNlIHJldHVybiB0aGUgcmVzdWx0XHJcbiAgICByZXR1cm4ge1xyXG4gICAgICByZXN1bHQsXHJcbiAgICAgIG9wdGlvbnNcclxuICAgIH07XHJcbiAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICsrcG9vbFN0YXRzLmV4cG9ydHNEcm9wcGVkO1xyXG5cclxuICAgIGlmICh3b3JrZXJIYW5kbGUpIHtcclxuICAgICAgcG9vbC5yZWxlYXNlKHdvcmtlckhhbmRsZSk7XHJcbiAgICB9XHJcblxyXG4gICAgdGhyb3cgZXJyb3I7XHJcbiAgfVxyXG59XHJcblxyXG4vKipcclxuICogUmV0cmlldmVzIHRoZSBjdXJyZW50IHBvb2wgaW5zdGFuY2UuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBnZXRQb29sXHJcbiAqXHJcbiAqIEByZXR1cm5zIHsoT2JqZWN0fG51bGwpfSBUaGUgY3VycmVudCBwb29sIGluc3RhbmNlIGlmIGluaXRpYWxpemVkLCBvciBudWxsXHJcbiAqIGlmIHRoZSBwb29sIGhhcyBub3QgYmVlbiBjcmVhdGVkLlxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIGdldFBvb2woKSB7XHJcbiAgcmV0dXJuIHBvb2w7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBHZXRzIHRoZSBzdGF0aXN0aWMgb2YgYSBwb29sIGluc3RhY2UgYWJvdXQgZXhwb3J0cy5cclxuICpcclxuICogQGZ1bmN0aW9uIGdldFBvb2xTdGF0c1xyXG4gKlxyXG4gKiBAcmV0dXJucyB7T2JqZWN0fSBUaGUgY3VycmVudCBwb29sIHN0YXRpc3RpY3MuXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gZ2V0UG9vbFN0YXRzKCkge1xyXG4gIHJldHVybiBwb29sU3RhdHM7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBSZXRyaWV2ZXMgcG9vbCBpbmZvcm1hdGlvbiBpbiBKU09OIGZvcm1hdCwgaW5jbHVkaW5nIG1pbmltdW0gYW5kIG1heGltdW1cclxuICogd29ya2VycywgYXZhaWxhYmxlIHdvcmtlcnMsIHdvcmtlcnMgaW4gdXNlLCBhbmQgcGVuZGluZyBhY3F1aXJlIHJlcXVlc3RzLlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gZ2V0UG9vbEluZm9KU09OXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtPYmplY3R9IFBvb2wgaW5mb3JtYXRpb24gaW4gSlNPTiBmb3JtYXQuXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gZ2V0UG9vbEluZm9KU09OKCkge1xyXG4gIHJldHVybiB7XHJcbiAgICBtaW46IHBvb2wubWluLFxyXG4gICAgbWF4OiBwb29sLm1heCxcclxuICAgIHVzZWQ6IHBvb2wubnVtVXNlZCgpLFxyXG4gICAgYXZhaWxhYmxlOiBwb29sLm51bUZyZWUoKSxcclxuICAgIGFsbENyZWF0ZWQ6IHBvb2wubnVtVXNlZCgpICsgcG9vbC5udW1GcmVlKCksXHJcbiAgICBwZW5kaW5nQWNxdWlyZXM6IHBvb2wubnVtUGVuZGluZ0FjcXVpcmVzKCksXHJcbiAgICBwZW5kaW5nQ3JlYXRlczogcG9vbC5udW1QZW5kaW5nQ3JlYXRlcygpLFxyXG4gICAgcGVuZGluZ1ZhbGlkYXRpb25zOiBwb29sLm51bVBlbmRpbmdWYWxpZGF0aW9ucygpLFxyXG4gICAgcGVuZGluZ0Rlc3Ryb3lzOiBwb29sLnBlbmRpbmdEZXN0cm95cy5sZW5ndGgsXHJcbiAgICBhYnNvbHV0ZUFsbDpcclxuICAgICAgcG9vbC5udW1Vc2VkKCkgK1xyXG4gICAgICBwb29sLm51bUZyZWUoKSArXHJcbiAgICAgIHBvb2wubnVtUGVuZGluZ0FjcXVpcmVzKCkgK1xyXG4gICAgICBwb29sLm51bVBlbmRpbmdDcmVhdGVzKCkgK1xyXG4gICAgICBwb29sLm51bVBlbmRpbmdWYWxpZGF0aW9ucygpICtcclxuICAgICAgcG9vbC5wZW5kaW5nRGVzdHJveXMubGVuZ3RoXHJcbiAgfTtcclxufVxyXG5cclxuLyoqXHJcbiAqIExvZ3MgaW5mb3JtYXRpb24gYWJvdXQgdGhlIGN1cnJlbnQgc3RhdGUgb2YgdGhlIHBvb2wsIGluY2x1ZGluZyB0aGUgbWluaW11bVxyXG4gKiBhbmQgbWF4aW11bSB3b3JrZXJzLCBhdmFpbGFibGUgd29ya2Vycywgd29ya2VycyBpbiB1c2UsIGFuZCBwZW5kaW5nIGFjcXVpcmVcclxuICogcmVxdWVzdHMuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBnZXRQb29sSW5mb1xyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIGdldFBvb2xJbmZvKCkge1xyXG4gIGNvbnN0IHtcclxuICAgIG1pbixcclxuICAgIG1heCxcclxuICAgIHVzZWQsXHJcbiAgICBhdmFpbGFibGUsXHJcbiAgICBhbGxDcmVhdGVkLFxyXG4gICAgcGVuZGluZ0FjcXVpcmVzLFxyXG4gICAgcGVuZGluZ0NyZWF0ZXMsXHJcbiAgICBwZW5kaW5nVmFsaWRhdGlvbnMsXHJcbiAgICBwZW5kaW5nRGVzdHJveXMsXHJcbiAgICBhYnNvbHV0ZUFsbFxyXG4gIH0gPSBnZXRQb29sSW5mb0pTT04oKTtcclxuXHJcbiAgbG9nKDUsIGBbcG9vbF0gVGhlIG1pbmltdW0gbnVtYmVyIG9mIHJlc291cmNlcyBhbGxvd2VkIGJ5IHBvb2w6ICR7bWlufS5gKTtcclxuICBsb2coNSwgYFtwb29sXSBUaGUgbWF4aW11bSBudW1iZXIgb2YgcmVzb3VyY2VzIGFsbG93ZWQgYnkgcG9vbDogJHttYXh9LmApO1xyXG4gIGxvZyg1LCBgW3Bvb2xdIFRoZSBudW1iZXIgb2YgdXNlZCByZXNvdXJjZXM6ICR7dXNlZH0uYCk7XHJcbiAgbG9nKDUsIGBbcG9vbF0gVGhlIG51bWJlciBvZiBmcmVlIHJlc291cmNlczogJHthdmFpbGFibGV9LmApO1xyXG4gIGxvZyhcclxuICAgIDUsXHJcbiAgICBgW3Bvb2xdIFRoZSBudW1iZXIgb2YgYWxsIGNyZWF0ZWQgKHVzZWQgYW5kIGZyZWUpIHJlc291cmNlczogJHthbGxDcmVhdGVkfS5gXHJcbiAgKTtcclxuICBsb2coXHJcbiAgICA1LFxyXG4gICAgYFtwb29sXSBUaGUgbnVtYmVyIG9mIHJlc291cmNlcyB3YWl0aW5nIHRvIGJlIGFjcXVpcmVkOiAke3BlbmRpbmdBY3F1aXJlc30uYFxyXG4gICk7XHJcbiAgbG9nKFxyXG4gICAgNSxcclxuICAgIGBbcG9vbF0gVGhlIG51bWJlciBvZiByZXNvdXJjZXMgd2FpdGluZyB0byBiZSBjcmVhdGVkOiAke3BlbmRpbmdDcmVhdGVzfS5gXHJcbiAgKTtcclxuICBsb2coXHJcbiAgICA1LFxyXG4gICAgYFtwb29sXSBUaGUgbnVtYmVyIG9mIHJlc291cmNlcyB3YWl0aW5nIHRvIGJlIHZhbGlkYXRlZDogJHtwZW5kaW5nVmFsaWRhdGlvbnN9LmBcclxuICApO1xyXG4gIGxvZyhcclxuICAgIDUsXHJcbiAgICBgW3Bvb2xdIFRoZSBudW1iZXIgb2YgcmVzb3VyY2VzIHdhaXRpbmcgdG8gYmUgZGVzdHJveWVkOiAke3BlbmRpbmdEZXN0cm95c30uYFxyXG4gICk7XHJcbiAgbG9nKDUsIGBbcG9vbF0gVGhlIG51bWJlciBvZiBhbGwgcmVzb3VyY2VzOiAke2Fic29sdXRlQWxsfS5gKTtcclxufVxyXG5cclxuLyoqXHJcbiAqIEZhY3RvcnkgZnVuY3Rpb24gdGhhdCByZXR1cm5zIGFuIG9iamVjdCB3aXRoIGBjcmVhdGVgLCBgdmFsaWRhdGVgLFxyXG4gKiBhbmQgYGRlc3Ryb3lgIGZ1bmN0aW9ucyBmb3IgdGhlIHBvb2wgaW5zdGFuY2UuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBfZmFjdG9yeVxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gcG9vbE9wdGlvbnMgLSBUaGUgY29uZmlndXJhdGlvbiBvYmplY3QgY29udGFpbmluZyBgcG9vbGBcclxuICogb3B0aW9ucy5cclxuICovXHJcbmZ1bmN0aW9uIF9mYWN0b3J5KHBvb2xPcHRpb25zKSB7XHJcbiAgcmV0dXJuIHtcclxuICAgIC8qKlxyXG4gICAgICogQ3JlYXRlcyBhIG5ldyB3b3JrZXIgcGFnZSBmb3IgdGhlIGV4cG9ydCBwb29sLlxyXG4gICAgICpcclxuICAgICAqIEBhc3luY1xyXG4gICAgICogQGZ1bmN0aW9uIGNyZWF0ZVxyXG4gICAgICpcclxuICAgICAqIEByZXR1cm5zIHtQcm9taXNlPE9iamVjdD59IEEgUHJvbWlzZSB0aGF0IHJlc29sdmVzIHRvIGFuIG9iamVjdFxyXG4gICAgICogY29udGFpbmluZyB0aGUgd29ya2VyIElELCBhIHJlZmVyZW5jZSB0byB0aGUgYnJvd3NlciBwYWdlLCBhbmQgaW5pdGlhbFxyXG4gICAgICogd29yayBjb3VudC5cclxuICAgICAqXHJcbiAgICAgKiBAdGhyb3dzIHtFeHBvcnRFcnJvcn0gVGhyb3dzIGFuIGBFeHBvcnRFcnJvcmAgaWYgdGhlcmUgaXMgYW4gZXJyb3IgZHVyaW5nXHJcbiAgICAgKiB0aGUgY3JlYXRpb24gb2YgdGhlIG5ldyBwYWdlLlxyXG4gICAgICovXHJcbiAgICBjcmVhdGU6IGFzeW5jICgpID0+IHtcclxuICAgICAgLy8gSW5pdCB0aGUgcmVzb3VyY2Ugd2l0aCB1bmlxdWUgaWQgYW5kIHdvcmsgY291bnRcclxuICAgICAgY29uc3QgcG9vbFJlc291cmNlID0ge1xyXG4gICAgICAgIGlkOiB1dWlkKCksXHJcbiAgICAgICAgLy8gVHJ5IHRvIGRpc3RyaWJ1dGUgdGhlIGluaXRpYWwgd29yayBjb3VudFxyXG4gICAgICAgIHdvcmtDb3VudDogTWF0aC5yb3VuZChNYXRoLnJhbmRvbSgpICogKHBvb2xPcHRpb25zLndvcmtMaW1pdCAvIDIpKVxyXG4gICAgICB9O1xyXG5cclxuICAgICAgdHJ5IHtcclxuICAgICAgICAvLyBTdGFydCBtZWFzdXJpbmcgYSBwYWdlIGNyZWF0aW9uIHRpbWVcclxuICAgICAgICBjb25zdCBzdGFydERhdGUgPSBnZXROZXdEYXRlVGltZSgpO1xyXG5cclxuICAgICAgICAvLyBDcmVhdGUgYSBuZXcgcGFnZVxyXG4gICAgICAgIGF3YWl0IG5ld1BhZ2UocG9vbFJlc291cmNlKTtcclxuXHJcbiAgICAgICAgLy8gTWVhc3VyZSB0aGUgdGltZSBvZiBmdWxsIGNyZWF0aW9uIGFuZCBjb25maWd1cmF0aW9uIG9mIGEgcGFnZVxyXG4gICAgICAgIGxvZyhcclxuICAgICAgICAgIDMsXHJcbiAgICAgICAgICBgW3Bvb2xdIFBvb2wgcmVzb3VyY2UgWyR7cG9vbFJlc291cmNlLmlkfV0gLSBTdWNjZXNzZnVsbHkgY3JlYXRlZCBhIHdvcmtlciwgdG9vayAke1xyXG4gICAgICAgICAgICBnZXROZXdEYXRlVGltZSgpIC0gc3RhcnREYXRlXHJcbiAgICAgICAgICB9bXMuYFxyXG4gICAgICAgICk7XHJcblxyXG4gICAgICAgIC8vIFJldHVybiByZWFkeSBwb29sIHJlc291cmNlXHJcbiAgICAgICAgcmV0dXJuIHBvb2xSZXNvdXJjZTtcclxuICAgICAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICAgICBsb2coXHJcbiAgICAgICAgICAzLFxyXG4gICAgICAgICAgYFtwb29sXSBQb29sIHJlc291cmNlIFske3Bvb2xSZXNvdXJjZS5pZH1dIC0gRXJyb3IgZW5jb3VudGVyZWQgd2hlbiBjcmVhdGluZyBhIG5ldyBwYWdlLmBcclxuICAgICAgICApO1xyXG4gICAgICAgIHRocm93IGVycm9yO1xyXG4gICAgICB9XHJcbiAgICB9LFxyXG5cclxuICAgIC8qKlxyXG4gICAgICogVmFsaWRhdGVzIGEgd29ya2VyIHBhZ2UgaW4gdGhlIGV4cG9ydCBwb29sLCBjaGVja2luZyBpZiBpdCBoYXMgZXhjZWVkZWRcclxuICAgICAqIHRoZSB3b3JrIGxpbWl0LlxyXG4gICAgICpcclxuICAgICAqIEBhc3luY1xyXG4gICAgICogQGZ1bmN0aW9uIHZhbGlkYXRlXHJcbiAgICAgKlxyXG4gICAgICogQHBhcmFtIHtPYmplY3R9IHBvb2xSZXNvdXJjZSAtIFRoZSBoYW5kbGUgdG8gdGhlIHdvcmtlciwgY29udGFpbmluZ1xyXG4gICAgICogdGhlIHdvcmtlcidzIElELCBhIHJlZmVyZW5jZSB0byB0aGUgYnJvd3NlciBwYWdlLCBhbmQgd29yayBjb3VudC5cclxuICAgICAqXHJcbiAgICAgKiBAcmV0dXJucyB7UHJvbWlzZTxib29sZWFuPn0gQSBQcm9taXNlIHRoYXQgcmVzb2x2ZXMgdG8gdHJ1ZSBpZiB0aGUgd29ya2VyXHJcbiAgICAgKiBpcyB2YWxpZCBhbmQgd2l0aGluIHRoZSB3b3JrIGxpbWl0OyBvdGhlcndpc2UsIHRvIGZhbHNlLlxyXG4gICAgICovXHJcbiAgICB2YWxpZGF0ZTogYXN5bmMgKHBvb2xSZXNvdXJjZSkgPT4ge1xyXG4gICAgICAvLyBOT1RFOlxyXG4gICAgICAvLyBJbiBjZXJ0YWluIGNhc2VzIGFjcXVpcmluZyB0aHJvd3MgYSBUYXJnZXRDbG9zZUVycm9yLCB3aGljaCBtYXlcclxuICAgICAgLy8gYmUgY2F1c2VkIGJ5IHR3byB0aGluZ3M6XHJcbiAgICAgIC8vIC0gVGhlIHBhZ2UgaXMgY2xvc2VkIGFuZCBhdHRlbXB0ZWQgdG8gYmUgcmV1c2VkLlxyXG4gICAgICAvLyAtIExvc3QgY29udGFjdCB3aXRoIHRoZSBicm93c2VyLlxyXG4gICAgICAvL1xyXG4gICAgICAvLyBXaGF0IHdlJ3JlIHNlZWluZyBpbiBsb2dzIGlzIHRoYXQgc3VjY2Vzc2l2ZSBleHBvcnRzIHR5cGljYWxseVxyXG4gICAgICAvLyBzdWNjZWVkcywgYW5kIHRoZSBzZXJ2ZXIgcmVjb3ZlcnMsIGluZGljYXRpbmcgdGhhdCBpdCdzIGxpa2VseVxyXG4gICAgICAvLyB0aGUgZmlyc3QgY2FzZS4gVGhpcyBpcyBhbiBhdHRlbXB0IGF0IGFsbGlldmF0aW5nIHRoZSBpc3N1ZSBieVxyXG4gICAgICAvLyBzaW1wbHkgbm90IHZhbGlkYXRpbmcgdGhlIHdvcmtlciBpZiB0aGUgcGFnZSBpcyBudWxsIG9yIGNsb3NlZC5cclxuICAgICAgLy9cclxuICAgICAgLy8gVGhlIGFjdHVhbCByZXN1bHQgZnJvbSB3aGVuIHRoaXMgaGFwcGVuZWQsIHdhcyB0aGF0IGEgd29ya2VyIHdvdWxkXHJcbiAgICAgIC8vIGJlIGNvbXBsZXRlbHkgbG9ja2VkLCBzdG9wcGluZyBpdCBmcm9tIGJlaW5nIGFjcXVpcmVkIHVudGlsXHJcbiAgICAgIC8vIGl0cyB3b3JrIGNvdW50IHJlYWNoZWQgdGhlIGxpbWl0LlxyXG5cclxuICAgICAgLy8gQ2hlY2sgaWYgdGhlIGBwYWdlYCBpcyB2YWxpZFxyXG4gICAgICBpZiAoIXBvb2xSZXNvdXJjZS5wYWdlKSB7XHJcbiAgICAgICAgbG9nKFxyXG4gICAgICAgICAgMyxcclxuICAgICAgICAgIGBbcG9vbF0gUG9vbCByZXNvdXJjZSBbJHtwb29sUmVzb3VyY2UuaWR9XSAtIFZhbGlkYXRpb24gZmFpbGVkIChubyB2YWxpZCBwYWdlIGlzIGZvdW5kKS5gXHJcbiAgICAgICAgKTtcclxuICAgICAgICByZXR1cm4gZmFsc2U7XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIC8vIENoZWNrIGlmIHRoZSBgcGFnZWAgaXMgY2xvc2VkXHJcbiAgICAgIGlmIChwb29sUmVzb3VyY2UucGFnZS5pc0Nsb3NlZCgpKSB7XHJcbiAgICAgICAgbG9nKFxyXG4gICAgICAgICAgMyxcclxuICAgICAgICAgIGBbcG9vbF0gUG9vbCByZXNvdXJjZSBbJHtwb29sUmVzb3VyY2UuaWR9XSAtIFZhbGlkYXRpb24gZmFpbGVkIChwYWdlIGlzIGNsb3NlZCBvciBpbnZhbGlkKS5gXHJcbiAgICAgICAgKTtcclxuICAgICAgICByZXR1cm4gZmFsc2U7XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIC8vIENoZWNrIGlmIHRoZSBgbWFpbkZyYW1lYCBpcyBkZXRhY2hlZFxyXG4gICAgICBpZiAocG9vbFJlc291cmNlLnBhZ2UubWFpbkZyYW1lKCkuZGV0YWNoZWQpIHtcclxuICAgICAgICBsb2coXHJcbiAgICAgICAgICAzLFxyXG4gICAgICAgICAgYFtwb29sXSBQb29sIHJlc291cmNlIFske3Bvb2xSZXNvdXJjZS5pZH1dIC0gVmFsaWRhdGlvbiBmYWlsZWQgKHBhZ2UncyBmcmFtZSBpcyBkZXRhY2hlZCkuYFxyXG4gICAgICAgICk7XHJcbiAgICAgICAgcmV0dXJuIGZhbHNlO1xyXG4gICAgICB9XHJcblxyXG4gICAgICAvLyBDaGVjayBpZiB0aGUgYHdvcmtMaW1pdGAgaXMgZXhjZWVkZWRcclxuICAgICAgaWYgKFxyXG4gICAgICAgIHBvb2xPcHRpb25zLndvcmtMaW1pdCAmJlxyXG4gICAgICAgICsrcG9vbFJlc291cmNlLndvcmtDb3VudCA+IHBvb2xPcHRpb25zLndvcmtMaW1pdFxyXG4gICAgICApIHtcclxuICAgICAgICBsb2coXHJcbiAgICAgICAgICAzLFxyXG4gICAgICAgICAgYFtwb29sXSBQb29sIHJlc291cmNlIFske3Bvb2xSZXNvdXJjZS5pZH1dIC0gVmFsaWRhdGlvbiBmYWlsZWQgKGV4Y2VlZGVkIHRoZSAke3Bvb2xPcHRpb25zLndvcmtMaW1pdH0gd29ya3MgcGVyIHJlc291cmNlIGxpbWl0KS5gXHJcbiAgICAgICAgKTtcclxuICAgICAgICByZXR1cm4gZmFsc2U7XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIC8vIFRoZSBgcG9vbFJlc291cmNlYCBpcyB2YWxpZGF0ZWRcclxuICAgICAgcmV0dXJuIHRydWU7XHJcbiAgICB9LFxyXG5cclxuICAgIC8qKlxyXG4gICAgICogRGVzdHJveXMgYSB3b3JrZXIgZW50cnkgaW4gdGhlIGV4cG9ydCBwb29sLCBjbG9zaW5nIGl0cyBhc3NvY2lhdGVkIHBhZ2UuXHJcbiAgICAgKlxyXG4gICAgICogQGFzeW5jXHJcbiAgICAgKiBAZnVuY3Rpb24gZGVzdHJveVxyXG4gICAgICpcclxuICAgICAqIEBwYXJhbSB7T2JqZWN0fSBwb29sUmVzb3VyY2UgLSBUaGUgaGFuZGxlIHRvIHRoZSB3b3JrZXIsIGNvbnRhaW5pbmdcclxuICAgICAqIHRoZSB3b3JrZXIncyBJRCwgYSByZWZlcmVuY2UgdG8gdGhlIGJyb3dzZXIgcGFnZSwgYW5kIHdvcmsgY291bnQuXHJcbiAgICAgKi9cclxuICAgIGRlc3Ryb3k6IGFzeW5jIChwb29sUmVzb3VyY2UpID0+IHtcclxuICAgICAgbG9nKFxyXG4gICAgICAgIDMsXHJcbiAgICAgICAgYFtwb29sXSBQb29sIHJlc291cmNlIFske3Bvb2xSZXNvdXJjZS5pZH1dIC0gRGVzdHJveWluZyBhIHdvcmtlci5gXHJcbiAgICAgICk7XHJcblxyXG4gICAgICBpZiAocG9vbFJlc291cmNlLnBhZ2UgJiYgIXBvb2xSZXNvdXJjZS5wYWdlLmlzQ2xvc2VkKCkpIHtcclxuICAgICAgICB0cnkge1xyXG4gICAgICAgICAgLy8gUmVtb3ZlIGFsbCBhdHRhY2hlZCBldmVudCBsaXN0ZW5lcnMgZnJvbSB0aGUgcmVzb3VyY2VcclxuICAgICAgICAgIHBvb2xSZXNvdXJjZS5wYWdlLnJlbW92ZUFsbExpc3RlbmVycygncGFnZWVycm9yJyk7XHJcbiAgICAgICAgICBwb29sUmVzb3VyY2UucGFnZS5yZW1vdmVBbGxMaXN0ZW5lcnMoJ2NvbnNvbGUnKTtcclxuICAgICAgICAgIHBvb2xSZXNvdXJjZS5wYWdlLnJlbW92ZUFsbExpc3RlbmVycygnZnJhbWVkZXRhY2hlZCcpO1xyXG5cclxuICAgICAgICAgIC8vIFdlIG5lZWQgdG8gd2FpdCBhcm91bmQgZm9yIHRoaXNcclxuICAgICAgICAgIGF3YWl0IHBvb2xSZXNvdXJjZS5wYWdlLmNsb3NlKCk7XHJcbiAgICAgICAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICAgICAgIGxvZyhcclxuICAgICAgICAgICAgMyxcclxuICAgICAgICAgICAgYFtwb29sXSBQb29sIHJlc291cmNlIFske3Bvb2xSZXNvdXJjZS5pZH1dIC0gUGFnZSBjb3VsZCBub3QgYmUgY2xvc2VkIHVwb24gZGVzdHJveWluZy5gXHJcbiAgICAgICAgICApO1xyXG4gICAgICAgICAgdGhyb3cgZXJyb3I7XHJcbiAgICAgICAgfVxyXG4gICAgICB9XHJcbiAgICB9XHJcbiAgfTtcclxufVxyXG5cclxuZXhwb3J0IGRlZmF1bHQge1xyXG4gIGluaXRQb29sLFxyXG4gIGtpbGxQb29sLFxyXG4gIHBvc3RXb3JrLFxyXG4gIGdldFBvb2wsXHJcbiAgZ2V0UG9vbFN0YXRzLFxyXG4gIGdldFBvb2xJbmZvLFxyXG4gIGdldFBvb2xJbmZvSlNPTlxyXG59O1xyXG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxyXG5cclxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXHJcblxyXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNSwgSGlnaHNvZnRcclxuXHJcbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cclxuXHJcbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxyXG5cclxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxyXG5cclxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cclxuXHJcbi8qKlxyXG4gKiBAb3ZlcnZpZXcgVXNlZCB0byBzYW5pdGl6ZSB0aGUgc3RyaW5ncyBjb21pbmcgZnJvbSB0aGUgZXhwb3J0aW5nIG1vZHVsZVxyXG4gKiB0byBwcmV2ZW50IFhTUyBhdHRhY2tzICh3aXRoIHRoZSBET01QdXJpZnkgbGlicmFyeSkuXHJcbiAqL1xyXG5cclxuaW1wb3J0IERPTVB1cmlmeSBmcm9tICdkb21wdXJpZnknO1xyXG5pbXBvcnQgeyBKU0RPTSB9IGZyb20gJ2pzZG9tJztcclxuXHJcbi8qKlxyXG4gKiBTYW5pdGl6ZXMgYSBnaXZlbiBIVE1MIHN0cmluZyBieSByZW1vdmluZyA8c2NyaXB0PiB0YWdzLiBUaGlzIGZ1bmN0aW9uIHVzZXNcclxuICogYSByZWd1bGFyIGV4cHJlc3Npb24gdG8gZmluZCBhbmQgcmVtb3ZlIGFsbCBvY2N1cnJlbmNlcyBvZiA8c2NyaXB0Pjwvc2NyaXB0PlxyXG4gKiB0YWdzIGFuZCBhbnkgY29udGVudCB3aXRoaW4gdGhlbS5cclxuICpcclxuICogQGZ1bmN0aW9uIHNhbml0aXplXHJcbiAqXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSBpbnB1dCAtIFRoZSBIVE1MIHN0cmluZyB0byBiZSBzYW5pdGl6ZWQuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtzdHJpbmd9IFRoZSBzYW5pdGl6ZWQgSFRNTCBzdHJpbmcuXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gc2FuaXRpemUoaW5wdXQpIHtcclxuICAvLyBHZXQgdGhlIHZpcnR1YWwgRE9NXHJcbiAgY29uc3Qgd2luZG93ID0gbmV3IEpTRE9NKCcnKS53aW5kb3c7XHJcblxyXG4gIC8vIENyZWF0ZSBhIHB1cmlmeWluZyBpbnN0YW5jZVxyXG4gIGNvbnN0IHB1cmlmeSA9IERPTVB1cmlmeSh3aW5kb3cpO1xyXG5cclxuICAvLyBSZXR1cm4gc2FuaXRpemVkIGlucHV0XHJcbiAgcmV0dXJuIHB1cmlmeS5zYW5pdGl6ZShpbnB1dCwgeyBBRERfVEFHUzogWydmb3JlaWduT2JqZWN0J10gfSk7XHJcbn1cclxuXHJcbmV4cG9ydCBkZWZhdWx0IHtcclxuICBzYW5pdGl6ZVxyXG59O1xyXG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxyXG5cclxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXHJcblxyXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNSwgSGlnaHNvZnRcclxuXHJcbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cclxuXHJcbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxyXG5cclxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxyXG5cclxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cclxuXHJcbi8qKlxyXG4gKiBAb3ZlcnZpZXcgVGhpcyBtb2R1bGUgcHJvdmlkZXMgZnVuY3Rpb25zIHRvIHByZXBhcmUgZm9yIHRoZSBleHBvcnRpbmcgY2hhcnRzXHJcbiAqIGludG8gdmFyaW91cyBpbWFnZSBvdXRwdXQgZm9ybWF0cyBzdWNoIGFzIEpQRUcsIFBORywgUERGLCBhbmQgU1ZHcy5cclxuICogSXQgc3VwcG9ydHMgc2luZ2xlIGFuZCBiYXRjaCBleHBvcnQgb3BlcmF0aW9ucyBhbmQgYWxsb3dzIGN1c3RvbWl6YXRpb25cclxuICogdGhyb3VnaCBvcHRpb25zIHBhc3NlZCBmcm9tIGNvbmZpZ3VyYXRpb25zIG9yIEFQSXMuXHJcbiAqL1xyXG5cclxuaW1wb3J0IHsgcmVhZEZpbGVTeW5jLCB3cml0ZUZpbGVTeW5jIH0gZnJvbSAnZnMnO1xyXG5cclxuaW1wb3J0IHsgZ2V0T3B0aW9ucywgaXNBbGxvd2VkQ29uZmlnLCBtZXJnZU9wdGlvbnMgfSBmcm9tICcuL2NvbmZpZy5qcyc7XHJcbmltcG9ydCB7IGxvZywgbG9nV2l0aFN0YWNrLCBsb2dab2RJc3N1ZXMgfSBmcm9tICcuL2xvZ2dlci5qcyc7XHJcbmltcG9ydCB7IGdldFBvb2xTdGF0cywga2lsbFBvb2wsIHBvc3RXb3JrIH0gZnJvbSAnLi9wb29sLmpzJztcclxuaW1wb3J0IHsgc2FuaXRpemUgfSBmcm9tICcuL3Nhbml0aXplLmpzJztcclxuaW1wb3J0IHtcclxuICBkZWVwQ29weSxcclxuICBmaXhDb25zdHIsXHJcbiAgZml4T3V0ZmlsZSxcclxuICBmaXhUeXBlLFxyXG4gIGdldEFic29sdXRlUGF0aCxcclxuICBnZXRCYXNlNjQsXHJcbiAgaXNPYmplY3QsXHJcbiAgcm91bmROdW1iZXIsXHJcbiAgd3JhcEFyb3VuZFxyXG59IGZyb20gJy4vdXRpbHMuanMnO1xyXG5pbXBvcnQgeyBzdHJpY3RWYWxpZGF0ZSwgdmFsaWRhdGVPcHRpb24gfSBmcm9tICcuL3ZhbGlkYXRpb24uanMnO1xyXG5cclxuaW1wb3J0IEV4cG9ydEVycm9yIGZyb20gJy4vZXJyb3JzL0V4cG9ydEVycm9yLmpzJztcclxuXHJcbi8vIFRoZSBnbG9iYWwgZmxhZyBmb3IgdGhlIGNvZGUgZXhlY3V0aW9uIHBlcm1pc3Npb25cclxubGV0IGFsbG93Q29kZUV4ZWN1dGlvbiA9IGZhbHNlO1xyXG5cclxuLyoqXHJcbiAqIFN0YXJ0cyBhIHNpbmdsZSBleHBvcnQgcHJvY2VzcyBiYXNlZCBvbiB0aGUgc3BlY2lmaWVkIG9wdGlvbnMgYW5kIHNhdmVzXHJcbiAqIHRoZSByZXN1bHRpbmcgaW1hZ2UgdG8gdGhlIHByb3ZpZGVkIG91dHB1dCBmaWxlLlxyXG4gKlxyXG4gKiBAYXN5bmNcclxuICogQGZ1bmN0aW9uIHNpbmdsZUV4cG9ydFxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gb3B0aW9ucyAtIFRoZSBgb3B0aW9uc2Agb2JqZWN0LCB3aGljaCBzaG91bGQgaW5jbHVkZSBzZXR0aW5nc1xyXG4gKiBmcm9tIHRoZSBgZXhwb3J0YCBhbmQgYGN1c3RvbUxvZ2ljYCBzZWN0aW9ucy4gSXQgY2FuIGJlIGEgcGFydGlhbCBvciBjb21wbGV0ZVxyXG4gKiBzZXQgb2Ygb3B0aW9ucyBmcm9tIHRoZXNlIHNlY3Rpb25zLiBUaGUgb2JqZWN0IG11c3QgY29udGFpbiBhdCBsZWFzdCBvbmVcclxuICogb2YgdGhlIGZvbGxvd2luZyBgZXhwb3J0YCBwcm9wZXJ0aWVzOiBgaW5maWxlYCwgYGluc3RyYCwgYG9wdGlvbnNgLCBvciBgc3ZnYFxyXG4gKiB0byBnZW5lcmF0ZSBhIHZhbGlkIGltYWdlLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7UHJvbWlzZTx2b2lkPn0gQSBQcm9taXNlIHRoYXQgcmVzb2x2ZXMgb25jZSB0aGUgc2luZ2xlIGV4cG9ydFxyXG4gKiBwcm9jZXNzIGlzIGNvbXBsZXRlZC5cclxuICpcclxuICogQHRocm93cyB7RXhwb3J0RXJyb3J9IFRocm93cyBhbiBgRXhwb3J0RXJyb3JgIGlmIGFuIGVycm9yIG9jY3VycyBkdXJpbmdcclxuICogdGhlIHNpbmdsZSBleHBvcnQgcHJvY2Vzcy5cclxuICovXHJcbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBzaW5nbGVFeHBvcnQob3B0aW9ucykge1xyXG4gIC8vIENoZWNrIGlmIHRoZSBleHBvcnQgbWFrZXMgc2Vuc2VcclxuICBpZiAob3B0aW9ucyAmJiBvcHRpb25zLmV4cG9ydCkge1xyXG4gICAgLy8gUGVyZm9ybSBhbiBleHBvcnRcclxuICAgIGF3YWl0IHN0YXJ0RXhwb3J0KFxyXG4gICAgICB7IGV4cG9ydDogb3B0aW9ucy5leHBvcnQsIGN1c3RvbUxvZ2ljOiBvcHRpb25zLmN1c3RvbUxvZ2ljIH0sXHJcbiAgICAgIGFzeW5jIChlcnJvciwgZGF0YSkgPT4ge1xyXG4gICAgICAgIC8vIEV4aXQgcHJvY2VzcyB3aGVuIGVycm9yIGV4aXN0c1xyXG4gICAgICAgIGlmIChlcnJvcikge1xyXG4gICAgICAgICAgdGhyb3cgZXJyb3I7XHJcbiAgICAgICAgfVxyXG5cclxuICAgICAgICAvLyBHZXQgdGhlIGBiNjRgLCBgb3V0ZmlsZWAsIGFuZCBgdHlwZWAgZm9yIGEgY2hhcnRcclxuICAgICAgICBjb25zdCB7IGI2NCwgb3V0ZmlsZSwgdHlwZSB9ID0gZGF0YS5vcHRpb25zLmV4cG9ydDtcclxuXHJcbiAgICAgICAgLy8gU2F2ZSB0aGUgcmVzdWx0XHJcbiAgICAgICAgdHJ5IHtcclxuICAgICAgICAgIGlmIChiNjQpIHtcclxuICAgICAgICAgICAgLy8gQXMgYSBCYXNlNjQgc3RyaW5nIHRvIGEgdHh0IGZpbGVcclxuICAgICAgICAgICAgd3JpdGVGaWxlU3luYyhcclxuICAgICAgICAgICAgICBgJHtvdXRmaWxlLnNwbGl0KCcuJykuc2hpZnQoKSB8fCAnY2hhcnQnfS50eHRgLFxyXG4gICAgICAgICAgICAgIGdldEJhc2U2NChkYXRhLnJlc3VsdCwgdHlwZSlcclxuICAgICAgICAgICAgKTtcclxuICAgICAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgICAgIC8vIEFzIGEgY29ycmVjdCBpbWFnZSBmb3JtYXRcclxuICAgICAgICAgICAgd3JpdGVGaWxlU3luYyhcclxuICAgICAgICAgICAgICBvdXRmaWxlIHx8IGBjaGFydC4ke3R5cGV9YCxcclxuICAgICAgICAgICAgICB0eXBlICE9PSAnc3ZnJyA/IEJ1ZmZlci5mcm9tKGRhdGEucmVzdWx0LCAnYmFzZTY0JykgOiBkYXRhLnJlc3VsdFxyXG4gICAgICAgICAgICApO1xyXG4gICAgICAgICAgfVxyXG4gICAgICAgIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICAgICAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoXHJcbiAgICAgICAgICAgICdbY2hhcnRdIEVycm9yIHdoaWxlIHNhdmluZyBhIGNoYXJ0LicsXHJcbiAgICAgICAgICAgIDUwMFxyXG4gICAgICAgICAgKS5zZXRFcnJvcihlcnJvcik7XHJcbiAgICAgICAgfVxyXG5cclxuICAgICAgICAvLyBLaWxsIHBvb2wgYW5kIGNsb3NlIGJyb3dzZXIgYWZ0ZXIgZmluaXNoaW5nIHNpbmdsZSBleHBvcnRcclxuICAgICAgICBhd2FpdCBraWxsUG9vbCgpO1xyXG4gICAgICB9XHJcbiAgICApO1xyXG4gIH0gZWxzZSB7XHJcbiAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoXHJcbiAgICAgICdbY2hhcnRdIE5vIGV4cGVjdGVkIGBleHBvcnRgIG9wdGlvbnMgd2VyZSBmb3VuZC4gUGxlYXNlIHByb3ZpZGUgb25lIG9mIHRoZSBmb2xsb3dpbmcgb3B0aW9uczogYGluZmlsZWAsIGBpbnN0cmAsIGBvcHRpb25zYCwgb3IgYHN2Z2AgdG8gZ2VuZXJhdGUgYSB2YWxpZCBpbWFnZS4nLFxyXG4gICAgICA0MDBcclxuICAgICk7XHJcbiAgfVxyXG59XHJcblxyXG4vKipcclxuICogU3RhcnRzIGEgYmF0Y2ggZXhwb3J0IHByb2Nlc3MgZm9yIG11bHRpcGxlIGNoYXJ0cyBiYXNlZCBvbiBpbmZvcm1hdGlvblxyXG4gKiBwcm92aWRlZCBpbiB0aGUgYGJhdGNoYCBvcHRpb24uIFRoZSBgYmF0Y2hgIGlzIGEgc3RyaW5nIGluIHRoZSBmb2xsb3dpbmdcclxuICogZm9ybWF0OiBcImluZmlsZTEuanNvbj1vdXRmaWxlMS5wbmc7aW5maWxlMi5qc29uPW91dGZpbGUyLnBuZzsuLi5cIi4gUmVzdWx0c1xyXG4gKiBhcmUgc2F2ZWQgdG8gdGhlIHNwZWNpZmllZCBvdXRwdXQgZmlsZXMuXHJcbiAqXHJcbiAqIEBhc3luY1xyXG4gKiBAZnVuY3Rpb24gYmF0Y2hFeHBvcnRcclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IG9wdGlvbnMgLSBUaGUgYG9wdGlvbnNgIG9iamVjdCwgd2hpY2ggc2hvdWxkIGluY2x1ZGUgc2V0dGluZ3NcclxuICogZnJvbSB0aGUgYGV4cG9ydGAgYW5kIGBjdXN0b21Mb2dpY2Agc2VjdGlvbnMuIEl0IGNhbiBiZSBhIHBhcnRpYWwgb3IgY29tcGxldGVcclxuICogc2V0IG9mIG9wdGlvbnMgZnJvbSB0aGVzZSBzZWN0aW9ucy4gSXQgbXVzdCBjb250YWluIHRoZSBgYmF0Y2hgIG9wdGlvbiBmcm9tXHJcbiAqIHRoZSBgZXhwb3J0YCBzZWN0aW9uIHRvIGdlbmVyYXRlIHZhbGlkIGltYWdlcy5cclxuICpcclxuICogQHJldHVybnMge1Byb21pc2U8dm9pZD59IEEgUHJvbWlzZSB0aGF0IHJlc29sdmVzIG9uY2UgdGhlIGJhdGNoIGV4cG9ydFxyXG4gKiBwcm9jZXNzZXMgYXJlIGNvbXBsZXRlZC5cclxuICpcclxuICogQHRocm93cyB7RXhwb3J0RXJyb3J9IFRocm93cyBhbiBgRXhwb3J0RXJyb3JgIGlmIGFuIGVycm9yIG9jY3VycyBkdXJpbmdcclxuICogYW55IG9mIHRoZSBiYXRjaCBleHBvcnQgcHJvY2Vzcy5cclxuICovXHJcbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBiYXRjaEV4cG9ydChvcHRpb25zKSB7XHJcbiAgLy8gQ2hlY2sgaWYgdGhlIGV4cG9ydCBtYWtlcyBzZW5zZVxyXG4gIGlmIChvcHRpb25zICYmIG9wdGlvbnMuZXhwb3J0ICYmIG9wdGlvbnMuZXhwb3J0LmJhdGNoKSB7XHJcbiAgICAvLyBBbiBhcnJheSBmb3IgY29sbGVjdGluZyBiYXRjaCBleHBvcnRzXHJcbiAgICBjb25zdCBiYXRjaEZ1bmN0aW9ucyA9IFtdO1xyXG5cclxuICAgIC8vIFNwbGl0IGFuZCBwYWlyIHRoZSBgYmF0Y2hgIGFyZ3VtZW50c1xyXG4gICAgZm9yIChsZXQgcGFpciBvZiBvcHRpb25zLmV4cG9ydC5iYXRjaC5zcGxpdCgnOycpIHx8IFtdKSB7XHJcbiAgICAgIHBhaXIgPSBwYWlyLnNwbGl0KCc9Jyk7XHJcbiAgICAgIGlmIChwYWlyLmxlbmd0aCA9PT0gMikge1xyXG4gICAgICAgIGJhdGNoRnVuY3Rpb25zLnB1c2goXHJcbiAgICAgICAgICBzdGFydEV4cG9ydChcclxuICAgICAgICAgICAge1xyXG4gICAgICAgICAgICAgIGV4cG9ydDoge1xyXG4gICAgICAgICAgICAgICAgLi4ub3B0aW9ucy5leHBvcnQsXHJcbiAgICAgICAgICAgICAgICBpbmZpbGU6IHBhaXJbMF0sXHJcbiAgICAgICAgICAgICAgICBvdXRmaWxlOiBwYWlyWzFdXHJcbiAgICAgICAgICAgICAgfSxcclxuICAgICAgICAgICAgICBjdXN0b21Mb2dpYzogb3B0aW9ucy5jdXN0b21Mb2dpY1xyXG4gICAgICAgICAgICB9LFxyXG4gICAgICAgICAgICAoZXJyb3IsIGRhdGEpID0+IHtcclxuICAgICAgICAgICAgICAvLyBFeGl0IHByb2Nlc3Mgd2hlbiBlcnJvciBleGlzdHNcclxuICAgICAgICAgICAgICBpZiAoZXJyb3IpIHtcclxuICAgICAgICAgICAgICAgIHRocm93IGVycm9yO1xyXG4gICAgICAgICAgICAgIH1cclxuXHJcbiAgICAgICAgICAgICAgLy8gR2V0IHRoZSBgYjY0YCwgYG91dGZpbGVgLCBhbmQgYHR5cGVgIGZvciBhIGNoYXJ0XHJcbiAgICAgICAgICAgICAgY29uc3QgeyBiNjQsIG91dGZpbGUsIHR5cGUgfSA9IGRhdGEub3B0aW9ucy5leHBvcnQ7XHJcblxyXG4gICAgICAgICAgICAgIC8vIFNhdmUgdGhlIHJlc3VsdFxyXG4gICAgICAgICAgICAgIHRyeSB7XHJcbiAgICAgICAgICAgICAgICBpZiAoYjY0KSB7XHJcbiAgICAgICAgICAgICAgICAgIC8vIEFzIGEgQmFzZTY0IHN0cmluZyB0byBhIHR4dCBmaWxlXHJcbiAgICAgICAgICAgICAgICAgIHdyaXRlRmlsZVN5bmMoXHJcbiAgICAgICAgICAgICAgICAgICAgYCR7b3V0ZmlsZS5zcGxpdCgnLicpLnNoaWZ0KCkgfHwgJ2NoYXJ0J30udHh0YCxcclxuICAgICAgICAgICAgICAgICAgICBnZXRCYXNlNjQoZGF0YS5yZXN1bHQsIHR5cGUpXHJcbiAgICAgICAgICAgICAgICAgICk7XHJcbiAgICAgICAgICAgICAgICB9IGVsc2Uge1xyXG4gICAgICAgICAgICAgICAgICAvLyBBcyBhIGNvcnJlY3QgaW1hZ2UgZm9ybWF0XHJcbiAgICAgICAgICAgICAgICAgIHdyaXRlRmlsZVN5bmMoXHJcbiAgICAgICAgICAgICAgICAgICAgb3V0ZmlsZSxcclxuICAgICAgICAgICAgICAgICAgICB0eXBlICE9PSAnc3ZnJ1xyXG4gICAgICAgICAgICAgICAgICAgICAgPyBCdWZmZXIuZnJvbShkYXRhLnJlc3VsdCwgJ2Jhc2U2NCcpXHJcbiAgICAgICAgICAgICAgICAgICAgICA6IGRhdGEucmVzdWx0XHJcbiAgICAgICAgICAgICAgICAgICk7XHJcbiAgICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgICAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICAgICAgICAgICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcihcclxuICAgICAgICAgICAgICAgICAgJ1tjaGFydF0gRXJyb3Igd2hpbGUgc2F2aW5nIGEgY2hhcnQuJyxcclxuICAgICAgICAgICAgICAgICAgNTAwXHJcbiAgICAgICAgICAgICAgICApLnNldEVycm9yKGVycm9yKTtcclxuICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgIH1cclxuICAgICAgICAgIClcclxuICAgICAgICApO1xyXG4gICAgICB9IGVsc2Uge1xyXG4gICAgICAgIGxvZygyLCAnW2NoYXJ0XSBObyBjb3JyZWN0IHBhaXIgZm91bmQgZm9yIHRoZSBiYXRjaCBleHBvcnQuJyk7XHJcbiAgICAgIH1cclxuICAgIH1cclxuXHJcbiAgICAvLyBBd2FpdCBhbGwgZXhwb3J0cyBhcmUgZG9uZVxyXG4gICAgY29uc3QgYmF0Y2hSZXN1bHRzID0gYXdhaXQgUHJvbWlzZS5hbGxTZXR0bGVkKGJhdGNoRnVuY3Rpb25zKTtcclxuXHJcbiAgICAvLyBLaWxsIHBvb2wgYW5kIGNsb3NlIGJyb3dzZXIgYWZ0ZXIgZmluaXNoaW5nIGJhdGNoIGV4cG9ydFxyXG4gICAgYXdhaXQga2lsbFBvb2woKTtcclxuXHJcbiAgICAvLyBMb2cgZXJyb3JzIGlmIGZvdW5kXHJcbiAgICBiYXRjaFJlc3VsdHMuZm9yRWFjaCgocmVzdWx0LCBpbmRleCkgPT4ge1xyXG4gICAgICAvLyBMb2cgdGhlIGVycm9yIHdpdGggc3RhY2sgYWJvdXQgdGhlIHNwZWNpZmljIGJhdGNoIGV4cG9ydFxyXG4gICAgICBpZiAocmVzdWx0LnJlYXNvbikge1xyXG4gICAgICAgIGxvZ1dpdGhTdGFjayhcclxuICAgICAgICAgIDEsXHJcbiAgICAgICAgICByZXN1bHQucmVhc29uLFxyXG4gICAgICAgICAgYFtjaGFydF0gQmF0Y2ggZXhwb3J0IG51bWJlciAke2luZGV4ICsgMX0gY291bGQgbm90IGJlIGNvcnJlY3RseSBjb21wbGV0ZWQuYFxyXG4gICAgICAgICk7XHJcbiAgICAgIH1cclxuICAgIH0pO1xyXG4gIH0gZWxzZSB7XHJcbiAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoXHJcbiAgICAgICdbY2hhcnRdIE5vIGV4cGVjdGVkIGBleHBvcnRgIG9wdGlvbnMgd2VyZSBmb3VuZC4gUGxlYXNlIHByb3ZpZGUgdGhlIGBiYXRjaGAgb3B0aW9uIHRvIGdlbmVyYXRlIHZhbGlkIGltYWdlcy4nLFxyXG4gICAgICA0MDBcclxuICAgICk7XHJcbiAgfVxyXG59XHJcblxyXG4vKipcclxuICogU3RhcnRzIGFuIGV4cG9ydCBwcm9jZXNzLiBUaGUgYGV4cG9ydGluZ09wdGlvbnNgIHBhcmFtZXRlciBpcyBhbiBvYmplY3QgdGhhdFxyXG4gKiBzaG91bGQgaW5jbHVkZSBzZXR0aW5ncyBmcm9tIHRoZSBgZXhwb3J0YCBhbmQgYGN1c3RvbUxvZ2ljYCBzZWN0aW9ucy4gSXQgY2FuXHJcbiAqIGJlIGEgcGFydGlhbCBvciBjb21wbGV0ZSBzZXQgb2Ygb3B0aW9ucyBmcm9tIHRoZXNlIHNlY3Rpb25zLiBJZiBwYXJ0aWFsXHJcbiAqIG9wdGlvbnMgYXJlIHByb3ZpZGVkLCBtaXNzaW5nIHZhbHVlcyB3aWxsIGJlIG1lcmdlZCB3aXRoIHRoZSBjdXJyZW50IGdsb2JhbFxyXG4gKiBvcHRpb25zLlxyXG4gKlxyXG4gKiBUaGUgYGVuZENhbGxiYWNrYCBmdW5jdGlvbiBpcyBpbnZva2VkIHVwb24gdGhlIGNvbXBsZXRpb24gb2YgdGhlIGV4cG9ydCxcclxuICogZWl0aGVyIHN1Y2Nlc3NmdWxseSBvciB3aXRoIGFuIGVycm9yLiBUaGUgYGVycm9yYCBvYmplY3QgaXMgcHJvdmlkZWRcclxuICogYXMgdGhlIGZpcnN0IGFyZ3VtZW50LCBhbmQgdGhlIGBkYXRhYCBvYmplY3QgaXMgdGhlIHNlY29uZCwgY29udGFpbmluZ1xyXG4gKiB0aGUgQmFzZTY0IHJlcHJlc2VudGF0aW9uIG9mIHRoZSBjaGFydCBpbiB0aGUgYHJlc3VsdGAgcHJvcGVydHlcclxuICogYW5kIHRoZSBjb21wbGV0ZSBzZXQgb2Ygb3B0aW9ucyBpbiB0aGUgYG9wdGlvbnNgIHByb3BlcnR5LlxyXG4gKlxyXG4gKiBAYXN5bmNcclxuICogQGZ1bmN0aW9uIHN0YXJ0RXhwb3J0XHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBleHBvcnRpbmdPcHRpb25zIC0gVGhlIGBleHBvcnRpbmdPcHRpb25zYCBvYmplY3QsIHdoaWNoXHJcbiAqIHNob3VsZCBpbmNsdWRlIHNldHRpbmdzIGZyb20gdGhlIGBleHBvcnRgIGFuZCBgY3VzdG9tTG9naWNgIHNlY3Rpb25zLiBJdCBjYW5cclxuICogYmUgYSBwYXJ0aWFsIG9yIGNvbXBsZXRlIHNldCBvZiBvcHRpb25zIGZyb20gdGhlc2Ugc2VjdGlvbnMuIElmIHRoZSBwcm92aWRlZFxyXG4gKiBvcHRpb25zIGFyZSBwYXJ0aWFsLCBtaXNzaW5nIHZhbHVlcyB3aWxsIGJlIG1lcmdlZCB3aXRoIHRoZSBjdXJyZW50IGdsb2JhbFxyXG4gKiBvcHRpb25zLlxyXG4gKiBAcGFyYW0ge0Z1bmN0aW9ufSBlbmRDYWxsYmFjayAtIFRoZSBjYWxsYmFjayBmdW5jdGlvbiB0byBiZSBpbnZva2VkIHVwb25cclxuICogZmluYWxpemluZyB0aGUgZXhwb3J0IHByb2Nlc3Mgb3IgdXBvbiBlbmNvdW50ZXJpbmcgYW4gZXJyb3IuIFRoZSBmaXJzdFxyXG4gKiBhcmd1bWVudCBpcyB0aGUgYGVycm9yYCBvYmplY3QsIGFuZCB0aGUgc2Vjb25kIGFyZ3VtZW50IGlzIHRoZSBgZGF0YWAgb2JqZWN0LFxyXG4gKiB3aGljaCBpbmNsdWRlcyB0aGUgQmFzZTY0IHJlcHJlc2VudGF0aW9uIG9mIHRoZSBjaGFydCBpbiB0aGUgYHJlc3VsdGBcclxuICogcHJvcGVydHkgYW5kIHRoZSBmdWxsIHNldCBvZiBvcHRpb25zIGluIHRoZSBgb3B0aW9uc2AgcHJvcGVydHkuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtQcm9taXNlPHZvaWQ+fSBUaGlzIGZ1bmN0aW9uIGRvZXMgbm90IHJldHVybiBhIHZhbHVlIGRpcmVjdGx5LlxyXG4gKiBJbnN0ZWFkLCBpdCBjb21tdW5pY2F0ZXMgcmVzdWx0cyB2aWEgdGhlIGBlbmRDYWxsYmFja2AuXHJcbiAqXHJcbiAqIEB0aHJvd3Mge0V4cG9ydEVycm9yfSBUaHJvd3MgYW4gYEV4cG9ydEVycm9yYCBpZiB0aGVyZSBpcyBhIHByb2JsZW0gd2l0aFxyXG4gKiBwcm9jZXNzaW5nIGlucHV0IG9mIGFueSB0eXBlLiBUaGUgZXJyb3IgaXMgcGFzc2VkIGludG8gdGhlIGBlbmRDYWxsYmFja2BcclxuICogZnVuY3Rpb24gYW5kIHByb2Nlc3NlZCB0aGVyZS5cclxuICovXHJcbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBzdGFydEV4cG9ydChleHBvcnRpbmdPcHRpb25zLCBlbmRDYWxsYmFjaykge1xyXG4gIHRyeSB7XHJcbiAgICAvLyBDaGVjayBpZiBwcm92aWRlZCBvcHRpb25zIGlzIGFuIG9iamVjdFxyXG4gICAgaWYgKCFpc09iamVjdChleHBvcnRpbmdPcHRpb25zKSkge1xyXG4gICAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoXHJcbiAgICAgICAgJ1tjaGFydF0gSW5jb3JyZWN0IHZhbHVlIG9mIHRoZSBwcm92aWRlZCBgZXhwb3J0aW5nT3B0aW9uc2AuIE5lZWRzIHRvIGJlIGFuIG9iamVjdC4nLFxyXG4gICAgICAgIDQwMFxyXG4gICAgICApO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIE1lcmdlIGFkZGl0aW9uYWwgb3B0aW9ucyB0byB0aGUgY29weSBvZiB0aGUgaW5zdGFuY2Ugb3B0aW9uc1xyXG4gICAgY29uc3Qgb3B0aW9ucyA9IG1lcmdlT3B0aW9ucyhkZWVwQ29weShnZXRPcHRpb25zKCkpLCB7XHJcbiAgICAgIGV4cG9ydDogZXhwb3J0aW5nT3B0aW9ucy5leHBvcnQsXHJcbiAgICAgIGN1c3RvbUxvZ2ljOiBleHBvcnRpbmdPcHRpb25zLmN1c3RvbUxvZ2ljXHJcbiAgICB9KTtcclxuXHJcbiAgICAvLyBHZXQgdGhlIGBleHBvcnRgIG9wdGlvbnNcclxuICAgIGNvbnN0IGV4cG9ydE9wdGlvbnMgPSBvcHRpb25zLmV4cG9ydDtcclxuXHJcbiAgICAvLyBTdGFydGluZyBleHBvcnRpbmcgcHJvY2VzcyBtZXNzYWdlXHJcbiAgICBsb2coNCwgJ1tjaGFydF0gU3RhcnRpbmcgdGhlIGV4cG9ydGluZyBwcm9jZXNzLicpO1xyXG5cclxuICAgIC8vIEV4cG9ydCB1c2luZyBvcHRpb25zIGZyb20gdGhlIGZpbGUgYXMgYW4gaW5wdXRcclxuICAgIGlmIChleHBvcnRPcHRpb25zLmluZmlsZSAhPT0gbnVsbCkge1xyXG4gICAgICBsb2coNCwgJ1tjaGFydF0gQXR0ZW1wdGluZyB0byBleHBvcnQgZnJvbSBhIGZpbGUgaW5wdXQuJyk7XHJcblxyXG4gICAgICBsZXQgZmlsZUNvbnRlbnQ7XHJcbiAgICAgIHRyeSB7XHJcbiAgICAgICAgLy8gVHJ5IHRvIHJlYWQgdGhlIGZpbGUgdG8gZ2V0IHRoZSBzdHJpbmcgcmVwcmVzZW50YXRpb25cclxuICAgICAgICBmaWxlQ29udGVudCA9IHJlYWRGaWxlU3luYyhcclxuICAgICAgICAgIGdldEFic29sdXRlUGF0aChleHBvcnRPcHRpb25zLmluZmlsZSksXHJcbiAgICAgICAgICAndXRmOCdcclxuICAgICAgICApO1xyXG4gICAgICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcihcclxuICAgICAgICAgICdbY2hhcnRdIEVycm9yIGxvYWRpbmcgY29udGVudCBmcm9tIGEgZmlsZSBpbnB1dC4nLFxyXG4gICAgICAgICAgNDAwXHJcbiAgICAgICAgKS5zZXRFcnJvcihlcnJvcik7XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIC8vIENoZWNrIHRoZSBmaWxlJ3MgZXh0ZW5zaW9uXHJcbiAgICAgIGlmIChleHBvcnRPcHRpb25zLmluZmlsZS5lbmRzV2l0aCgnLnN2ZycpKSB7XHJcbiAgICAgICAgdHJ5IHtcclxuICAgICAgICAgIC8vIFNldCB0byB0aGUgYHN2Z2Agb3B0aW9uXHJcbiAgICAgICAgICBleHBvcnRPcHRpb25zLnN2ZyA9IHZhbGlkYXRlT3B0aW9uKCdzdmcnLCBmaWxlQ29udGVudCwgZmFsc2UpO1xyXG4gICAgICAgIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICAgICAgICBsb2dab2RJc3N1ZXMoXHJcbiAgICAgICAgICAgIDEsXHJcbiAgICAgICAgICAgIGVycm9yLmlzc3VlcyxcclxuICAgICAgICAgICAgJ1tjb25maWddIFRoZSBgc3ZnYCBvcHRpb24gdmFsaWRhdGlvbiBlcnJvcidcclxuICAgICAgICAgICk7XHJcbiAgICAgICAgICB0aHJvdyBlcnJvcjtcclxuICAgICAgICB9XHJcbiAgICAgIH0gZWxzZSBpZiAoZXhwb3J0T3B0aW9ucy5pbmZpbGUuZW5kc1dpdGgoJy5qc29uJykpIHtcclxuICAgICAgICB0cnkge1xyXG4gICAgICAgICAgLy8gU2V0IHRvIHRoZSBgaW5zdHJgIG9wdGlvblxyXG4gICAgICAgICAgZXhwb3J0T3B0aW9ucy5pbnN0ciA9IHZhbGlkYXRlT3B0aW9uKCdpbnN0cicsIGZpbGVDb250ZW50LCBmYWxzZSk7XHJcbiAgICAgICAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICAgICAgIGxvZ1pvZElzc3VlcyhcclxuICAgICAgICAgICAgMSxcclxuICAgICAgICAgICAgZXJyb3IuaXNzdWVzLFxyXG4gICAgICAgICAgICAnW2NvbmZpZ10gVGhlIGBpbnN0cmAgb3B0aW9uIHZhbGlkYXRpb24gZXJyb3InXHJcbiAgICAgICAgICApO1xyXG4gICAgICAgICAgdGhyb3cgZXJyb3I7XHJcbiAgICAgICAgfVxyXG4gICAgICB9IGVsc2Uge1xyXG4gICAgICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcihcclxuICAgICAgICAgICdbY2hhcnRdIEluY29ycmVjdCB2YWx1ZSBvZiB0aGUgYGluZmlsZWAgb3B0aW9uLicsXHJcbiAgICAgICAgICA0MDBcclxuICAgICAgICApO1xyXG4gICAgICB9XHJcbiAgICB9XHJcblxyXG4gICAgLy8gRXhwb3J0IHVzaW5nIFNWRyBhcyBhbiBpbnB1dFxyXG4gICAgaWYgKGV4cG9ydE9wdGlvbnMuc3ZnICE9PSBudWxsKSB7XHJcbiAgICAgIGxvZyg0LCAnW2NoYXJ0XSBBdHRlbXB0aW5nIHRvIGV4cG9ydCBmcm9tIGFuIFNWRyBpbnB1dC4nKTtcclxuXHJcbiAgICAgIC8vIFNWRyBleHBvcnRzIGF0dGVtcHRzIGNvdW50ZXJcclxuICAgICAgKytnZXRQb29sU3RhdHMoKS5leHBvcnRzRnJvbVN2Z0F0dGVtcHRzO1xyXG5cclxuICAgICAgLy8gRXhwb3J0IGZyb20gYW4gU1ZHIHN0cmluZ1xyXG4gICAgICBjb25zdCByZXN1bHQgPSBhd2FpdCBfZXhwb3J0RnJvbVN2ZyhcclxuICAgICAgICBzYW5pdGl6ZShleHBvcnRPcHRpb25zLnN2ZyksIC8vICMyMDlcclxuICAgICAgICBvcHRpb25zXHJcbiAgICAgICk7XHJcblxyXG4gICAgICAvLyBTVkcgZXhwb3J0cyBjb3VudGVyXHJcbiAgICAgICsrZ2V0UG9vbFN0YXRzKCkuZXhwb3J0c0Zyb21Tdmc7XHJcblxyXG4gICAgICAvLyBQYXNzIFNWRyBleHBvcnQgcmVzdWx0IHRvIHRoZSBlbmQgY2FsbGJhY2tcclxuICAgICAgcmV0dXJuIGVuZENhbGxiYWNrKG51bGwsIHJlc3VsdCk7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gRXhwb3J0IHVzaW5nIG9wdGlvbnMgYXMgYW4gaW5wdXRcclxuICAgIGlmIChleHBvcnRPcHRpb25zLmluc3RyICE9PSBudWxsIHx8IGV4cG9ydE9wdGlvbnMub3B0aW9ucyAhPT0gbnVsbCkge1xyXG4gICAgICBsb2coNCwgJ1tjaGFydF0gQXR0ZW1wdGluZyB0byBleHBvcnQgZnJvbSBvcHRpb25zIGlucHV0LicpO1xyXG5cclxuICAgICAgLy8gT3B0aW9ucyBleHBvcnRzIGF0dGVtcHRzIGNvdW50ZXJcclxuICAgICAgKytnZXRQb29sU3RhdHMoKS5leHBvcnRzRnJvbU9wdGlvbnNBdHRlbXB0cztcclxuXHJcbiAgICAgIC8vIEV4cG9ydCBmcm9tIG9wdGlvbnNcclxuICAgICAgY29uc3QgcmVzdWx0ID0gYXdhaXQgX2V4cG9ydEZyb21PcHRpb25zKFxyXG4gICAgICAgIGV4cG9ydE9wdGlvbnMuaW5zdHIgfHwgZXhwb3J0T3B0aW9ucy5vcHRpb25zLFxyXG4gICAgICAgIG9wdGlvbnNcclxuICAgICAgKTtcclxuXHJcbiAgICAgIC8vIE9wdGlvbnMgZXhwb3J0cyBjb3VudGVyXHJcbiAgICAgICsrZ2V0UG9vbFN0YXRzKCkuZXhwb3J0c0Zyb21PcHRpb25zO1xyXG5cclxuICAgICAgLy8gUGFzcyBvcHRpb25zIGV4cG9ydCByZXN1bHQgdG8gdGhlIGVuZCBjYWxsYmFja1xyXG4gICAgICByZXR1cm4gZW5kQ2FsbGJhY2sobnVsbCwgcmVzdWx0KTtcclxuICAgIH1cclxuXHJcbiAgICAvLyBObyBpbnB1dCBzcGVjaWZpZWQsIHBhc3MgYW4gZXJyb3IgbWVzc2FnZSB0byB0aGUgY2FsbGJhY2tcclxuICAgIHJldHVybiBlbmRDYWxsYmFjayhcclxuICAgICAgbmV3IEV4cG9ydEVycm9yKFxyXG4gICAgICAgIGBbY2hhcnRdIE5vIHZhbGlkIGlucHV0IHNwZWNpZmllZC4gQ2hlY2sgaWYgYXQgbGVhc3Qgb25lIG9mIHRoZSBmb2xsb3dpbmcgcGFyYW1ldGVycyBpcyBjb3JyZWN0bHkgc2V0OiAnaW5maWxlJywgJ2luc3RyJywgJ29wdGlvbnMnLCBvciAnc3ZnJy5gLFxyXG4gICAgICAgIDQwMFxyXG4gICAgICApXHJcbiAgICApO1xyXG4gIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICByZXR1cm4gZW5kQ2FsbGJhY2soZXJyb3IpO1xyXG4gIH1cclxufVxyXG5cclxuLyoqXHJcbiAqIFJldHJpZXZlcyBhbmQgcmV0dXJucyB0aGUgY3VycmVudCBzdGF0dXMgb2YgdGhlIGNvZGUgZXhlY3V0aW9uIHBlcm1pc3Npb24uXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBnZXRBbGxvd0NvZGVFeGVjdXRpb25cclxuICpcclxuICogQHJldHVybnMge2Jvb2xlYW59IFRoZSB2YWx1ZSBvZiB0aGUgZ2xvYmFsIGBhbGxvd0NvZGVFeGVjdXRpb25gIG9wdGlvbi5cclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiBnZXRBbGxvd0NvZGVFeGVjdXRpb24oKSB7XHJcbiAgcmV0dXJuIGFsbG93Q29kZUV4ZWN1dGlvbjtcclxufVxyXG5cclxuLyoqXHJcbiAqIFNldHMgdGhlIGNvZGUgZXhlY3V0aW9uIHBlcm1pc3Npb24gYmFzZWQgb24gdGhlIHByb3ZpZGVkIGJvb2xlYW4gdmFsdWUuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBzZXRBbGxvd0NvZGVFeGVjdXRpb25cclxuICpcclxuICogQHBhcmFtIHtib29sZWFufSB2YWx1ZSAtIFRoZSBib29sZWFuIHZhbHVlIHRvIGJlIGFzc2lnbmVkIHRvIHRoZSBnbG9iYWxcclxuICogYGFsbG93Q29kZUV4ZWN1dGlvbmAgb3B0aW9uLlxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIHNldEFsbG93Q29kZUV4ZWN1dGlvbih2YWx1ZSkge1xyXG4gIGFsbG93Q29kZUV4ZWN1dGlvbiA9IHZhbHVlO1xyXG59XHJcblxyXG4vKipcclxuICogRXhwb3J0cyBmcm9tIGFuIFNWRyBiYXNlZCBpbnB1dCB3aXRoIHRoZSBwcm92aWRlZCBvcHRpb25zLlxyXG4gKlxyXG4gKiBAYXN5bmNcclxuICogQGZ1bmN0aW9uIF9leHBvcnRGcm9tU3ZnXHJcbiAqXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSBpbnB1dFRvRXhwb3J0IC0gVGhlIFNWRyBiYXNlZCBpbnB1dCB0byBiZSBleHBvcnRlZC5cclxuICogQHBhcmFtIHtPYmplY3R9IG9wdGlvbnMgLSBUaGUgY29uZmlndXJhdGlvbiBvYmplY3QgY29udGFpbmluZyBjb21wbGV0ZSBzZXRcclxuICogb2Ygb3B0aW9ucy5cclxuICpcclxuICogQHJldHVybnMge1Byb21pc2U8dW5rbm93bj59IEEgUHJvbWlzZSB0aGF0IHJlc29sdmVzIHRvIGEgcmVzdWx0IG9mIHRoZSBleHBvcnRcclxuICogcHJvY2Vzcy5cclxuICpcclxuICogQHRocm93cyB7RXhwb3J0RXJyb3J9IFRocm93cyBhbiBgRXhwb3J0RXJyb3JgIGlmIHRoZXJlIGlzIG5vdCBhIGNvcnJlY3QgU1ZHXHJcbiAqIGlucHV0LlxyXG4gKi9cclxuYXN5bmMgZnVuY3Rpb24gX2V4cG9ydEZyb21TdmcoaW5wdXRUb0V4cG9ydCwgb3B0aW9ucykge1xyXG4gIC8vIENoZWNrIGlmIGl0IGlzIFNWR1xyXG4gIGlmIChcclxuICAgIHR5cGVvZiBpbnB1dFRvRXhwb3J0ID09PSAnc3RyaW5nJyAmJlxyXG4gICAgKGlucHV0VG9FeHBvcnQuaW5kZXhPZignPHN2ZycpID49IDAgfHwgaW5wdXRUb0V4cG9ydC5pbmRleE9mKCc8P3htbCcpID49IDApXHJcbiAgKSB7XHJcbiAgICBsb2coNCwgJ1tjaGFydF0gUGFyc2luZyBpbnB1dCBhcyBTVkcuJyk7XHJcblxyXG4gICAgLy8gU2V0IHRoZSBleHBvcnQgaW5wdXQgYXMgU1ZHXHJcbiAgICBvcHRpb25zLmV4cG9ydC5zdmcgPSBpbnB1dFRvRXhwb3J0O1xyXG5cclxuICAgIC8vIFJlc2V0IHRoZSByZXN0IG9mIHRoZSBleHBvcnQgaW5wdXQgb3B0aW9uc1xyXG4gICAgb3B0aW9ucy5leHBvcnQuaW5zdHIgPSBudWxsO1xyXG4gICAgb3B0aW9ucy5leHBvcnQub3B0aW9ucyA9IG51bGw7XHJcblxyXG4gICAgLy8gQ2FsbCB0aGUgZnVuY3Rpb24gd2l0aCBhbiBTVkcgc3RyaW5nIGFzIGFuIGV4cG9ydCBpbnB1dFxyXG4gICAgcmV0dXJuIF9wcmVwYXJlRXhwb3J0KG9wdGlvbnMpO1xyXG4gIH0gZWxzZSB7XHJcbiAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoJ1tjaGFydF0gTm90IGEgY29ycmVjdCBTVkcgaW5wdXQuJywgNDAwKTtcclxuICB9XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBFeHBvcnRzIGZyb20gYW4gb3B0aW9ucyBiYXNlZCBpbnB1dCB3aXRoIHRoZSBwcm92aWRlZCBvcHRpb25zLlxyXG4gKlxyXG4gKiBAYXN5bmNcclxuICogQGZ1bmN0aW9uIF9leHBvcnRGcm9tT3B0aW9uc1xyXG4gKlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gaW5wdXRUb0V4cG9ydCAtIFRoZSBvcHRpb25zIGJhc2VkIGlucHV0IHRvIGJlIGV4cG9ydGVkLlxyXG4gKiBAcGFyYW0ge09iamVjdH0gb3B0aW9ucyAtIFRoZSBjb25maWd1cmF0aW9uIG9iamVjdCBjb250YWluaW5nIGNvbXBsZXRlIHNldFxyXG4gKiBvZiBvcHRpb25zLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7UHJvbWlzZTx1bmtub3duPn0gQSBQcm9taXNlIHRoYXQgcmVzb2x2ZXMgdG8gYSByZXN1bHQgb2YgdGhlIGV4cG9ydFxyXG4gKiBwcm9jZXNzLlxyXG4gKlxyXG4gKiBAdGhyb3dzIHtFeHBvcnRFcnJvcn0gVGhyb3dzIGFuIGBFeHBvcnRFcnJvcmAgaWYgdGhlcmUgaXMgbm90IGEgY29ycmVjdFxyXG4gKiBjaGFydCBvcHRpb25zIGlucHV0LlxyXG4gKi9cclxuYXN5bmMgZnVuY3Rpb24gX2V4cG9ydEZyb21PcHRpb25zKGlucHV0VG9FeHBvcnQsIG9wdGlvbnMpIHtcclxuICBsb2coNCwgJ1tjaGFydF0gUGFyc2luZyBpbnB1dCBmcm9tIG9wdGlvbnMuJyk7XHJcblxyXG4gIC8vIFRyeSB0byBjaGVjaywgdmFsaWRhdGUgYW5kIHBhcnNlIHRvIHN0cmluZ2lmaWVkIG9wdGlvbnNcclxuICBjb25zdCBzdHJpbmdpZmllZE9wdGlvbnMgPSBpc0FsbG93ZWRDb25maWcoXHJcbiAgICBpbnB1dFRvRXhwb3J0LFxyXG4gICAgdHJ1ZSxcclxuICAgIG9wdGlvbnMuY3VzdG9tTG9naWMuYWxsb3dDb2RlRXhlY3V0aW9uXHJcbiAgKTtcclxuXHJcbiAgLy8gQ2hlY2sgaWYgYSBjb3JyZWN0IHN0cmluZ2lmaWVkIG9wdGlvbnNcclxuICBpZiAoXHJcbiAgICBzdHJpbmdpZmllZE9wdGlvbnMgPT09IG51bGwgfHxcclxuICAgIHR5cGVvZiBzdHJpbmdpZmllZE9wdGlvbnMgIT09ICdzdHJpbmcnIHx8XHJcbiAgICAhc3RyaW5naWZpZWRPcHRpb25zLnN0YXJ0c1dpdGgoJ3snKSB8fFxyXG4gICAgIXN0cmluZ2lmaWVkT3B0aW9ucy5lbmRzV2l0aCgnfScpXHJcbiAgKSB7XHJcbiAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoXHJcbiAgICAgICdbY2hhcnRdIEludmFsaWQgY29uZmlndXJhdGlvbiBwcm92aWRlZCAtIE9ubHkgb3B0aW9ucyBjb25maWd1cmF0aW9ucyBhbmQgU1ZHIGFyZSBhbGxvd2VkIGZvciB0aGlzIHNlcnZlci4gSWYgdGhpcyBpcyB5b3VyIHNlcnZlciwgSmF2YVNjcmlwdCBjdXN0b20gY29kZSBjYW4gYmUgZW5hYmxlZCBieSBzdGFydGluZyB0aGUgc2VydmVyIHdpdGggdGhlIGBhbGxvd0NvZGVFeGVjdXRpb25gIG9wdGlvbnMgc2V0IHRvIHRydWUuJyxcclxuICAgICAgNDAzXHJcbiAgICApO1xyXG4gIH1cclxuXHJcbiAgLy8gU2V0IHRoZSBleHBvcnQgaW5wdXQgYXMgYSBzdHJpbmdpZmllZCBjaGFydCBvcHRpb25zXHJcbiAgb3B0aW9ucy5leHBvcnQuaW5zdHIgPSBzdHJpbmdpZmllZE9wdGlvbnM7XHJcblxyXG4gIC8vIFJlc2V0IHRoZSByZXN0IG9mIHRoZSBleHBvcnQgaW5wdXQgb3B0aW9uc1xyXG4gIG9wdGlvbnMuZXhwb3J0LnN2ZyA9IG51bGw7XHJcblxyXG4gIC8vIENhbGwgdGhlIGZ1bmN0aW9uIHdpdGggYSBzdHJpbmdpZmllZCBjaGFydCBvcHRpb25zXHJcbiAgcmV0dXJuIF9wcmVwYXJlRXhwb3J0KG9wdGlvbnMpO1xyXG59XHJcblxyXG4vKipcclxuICogRnVuY3Rpb24gZm9yIGZpbmFsaXppbmcgb3B0aW9ucyBhbmQgY29uZmlndXJhdGlvbnMgYmVmb3JlIGV4cG9ydC5cclxuICpcclxuICogQGFzeW5jXHJcbiAqIEBmdW5jdGlvbiBfcHJlcGFyZUV4cG9ydFxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gb3B0aW9ucyAtIFRoZSBjb25maWd1cmF0aW9uIG9iamVjdCBjb250YWluaW5nIGNvbXBsZXRlIHNldFxyXG4gKiBvZiBvcHRpb25zLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7UHJvbWlzZTx1bmtub3duPn0gQSBQcm9taXNlIHRoYXQgcmVzb2x2ZXMgdG8gYSByZXN1bHQgb2YgdGhlIGV4cG9ydFxyXG4gKiBwcm9jZXNzLlxyXG4gKi9cclxuYXN5bmMgZnVuY3Rpb24gX3ByZXBhcmVFeHBvcnQob3B0aW9ucykge1xyXG4gIGNvbnN0IHsgZXhwb3J0OiBleHBvcnRPcHRpb25zLCBjdXN0b21Mb2dpYzogY3VzdG9tTG9naWNPcHRpb25zIH0gPSBvcHRpb25zO1xyXG5cclxuICAvLyBQcmVwYXJlIHRoZSBgdHlwZWAgb3B0aW9uXHJcbiAgZXhwb3J0T3B0aW9ucy50eXBlID0gZml4VHlwZShleHBvcnRPcHRpb25zLnR5cGUsIGV4cG9ydE9wdGlvbnMub3V0ZmlsZSk7XHJcblxyXG4gIC8vIFByZXBhcmUgdGhlIGBvdXRmaWxlYCBvcHRpb25cclxuICBleHBvcnRPcHRpb25zLm91dGZpbGUgPSBmaXhPdXRmaWxlKGV4cG9ydE9wdGlvbnMudHlwZSwgZXhwb3J0T3B0aW9ucy5vdXRmaWxlKTtcclxuXHJcbiAgLy8gUHJlcGFyZSB0aGUgYGNvbnN0cmAgb3B0aW9uXHJcbiAgZXhwb3J0T3B0aW9ucy5jb25zdHIgPSBmaXhDb25zdHIoZXhwb3J0T3B0aW9ucy5jb25zdHIpO1xyXG5cclxuICAvLyBOb3RpZnkgYWJvdXQgdGhlIGN1c3RvbSBsb2dpYyB1c2FnZSBzdGF0dXNcclxuICBsb2coXHJcbiAgICAzLFxyXG4gICAgYFtjaGFydF0gVGhlIGN1c3RvbSBsb2dpYyBpcyAke2N1c3RvbUxvZ2ljT3B0aW9ucy5hbGxvd0NvZGVFeGVjdXRpb24gPyAnYWxsb3dlZCcgOiAnZGlzYWxsb3dlZCd9LmBcclxuICApO1xyXG5cclxuICAvLyBQcmVwYXJlIHRoZSBjdXN0b20gbG9naWMgb3B0aW9ucyAoYGN1c3RvbUNvZGVgLCBgY2FsbGJhY2tgLCBgcmVzb3VyY2VzYClcclxuICBfaGFuZGxlQ3VzdG9tTG9naWMoY3VzdG9tTG9naWNPcHRpb25zLCBjdXN0b21Mb2dpY09wdGlvbnMuYWxsb3dDb2RlRXhlY3V0aW9uKTtcclxuXHJcbiAgLy8gUHJlcGFyZSB0aGUgYGdsb2JhbE9wdGlvbnNgIGFuZCBgdGhlbWVPcHRpb25zYCBvcHRpb25zXHJcbiAgX2hhbmRsZUdsb2JhbEFuZFRoZW1lKFxyXG4gICAgZXhwb3J0T3B0aW9ucyxcclxuICAgIGN1c3RvbUxvZ2ljT3B0aW9ucy5hbGxvd0ZpbGVSZXNvdXJjZXMsXHJcbiAgICBjdXN0b21Mb2dpY09wdGlvbnMuYWxsb3dDb2RlRXhlY3V0aW9uXHJcbiAgKTtcclxuXHJcbiAgLy8gUHJlcGFyZSB0aGUgYGhlaWdodGAsIGB3aWR0aGAsIGFuZCBgc2NhbGVgIG9wdGlvbnNcclxuICBvcHRpb25zLmV4cG9ydCA9IHtcclxuICAgIC4uLmV4cG9ydE9wdGlvbnMsXHJcbiAgICAuLi5fZmluZENoYXJ0U2l6ZShleHBvcnRPcHRpb25zKVxyXG4gIH07XHJcblxyXG4gIC8vIFRoZSBsYXN0IHN0cmljdCB2YWxpZGF0aW9uIG9mIG9wdGlvbnMgcmlnaHQgYmVmb3JlIGV4cG9ydGluZyBwcm9jZXNzXHJcbiAgdHJ5IHtcclxuICAgIC8vIFZhbGlkYXRlIGZpbmFsIG9wdGlvbnNcclxuICAgIG9wdGlvbnMgPSBzdHJpY3RWYWxpZGF0ZShvcHRpb25zKTtcclxuICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgbG9nWm9kSXNzdWVzKDEsIGVycm9yLmlzc3VlcywgJ1tjb25maWddIEZpbmFsIG9wdGlvbnMgdmFsaWRhdGlvbiBlcnJvcicpO1xyXG4gIH1cclxuXHJcbiAgLy8gUG9zdCB0aGUgd29yayB0byB0aGUgcG9vbFxyXG4gIHJldHVybiBwb3N0V29yayhvcHRpb25zKTtcclxufVxyXG5cclxuLyoqXHJcbiAqIENhbGN1bGF0ZXMgdGhlIGBoZWlnaHRgLCBgd2lkdGhgIGFuZCBgc2NhbGVgIGZvciBjaGFydCBleHBvcnRzIGJhc2VkXHJcbiAqIG9uIHRoZSBwcm92aWRlZCBleHBvcnQgb3B0aW9ucy5cclxuICpcclxuICogVGhlIGZ1bmN0aW9uIHByaW9yaXRpemVzIHZhbHVlcyBpbiB0aGUgZm9sbG93aW5nIG9yZGVyOlxyXG4gKiAxLiBUaGUgYGhlaWdodGAsIGB3aWR0aGAsIGBzY2FsZWAgZnJvbSB0aGUgYGV4cG9ydE9wdGlvbnNgLlxyXG4gKiAyLiBPcHRpb25zIGZyb20gdGhlIGNoYXJ0IGNvbmZpZ3VyYXRpb24gKGZyb20gYGV4cG9ydGluZ2AgYW5kIGBjaGFydGApLlxyXG4gKiAzLiBPcHRpb25zIGZyb20gdGhlIGdsb2JhbCBvcHRpb25zIChmcm9tIGBleHBvcnRpbmdgIGFuZCBgY2hhcnRgKS5cclxuICogNC4gT3B0aW9ucyBmcm9tIHRoZSB0aGVtZSBvcHRpb25zIChmcm9tIGBleHBvcnRpbmdgIGFuZCBgY2hhcnRgIHNlY3Rpb25zKS5cclxuICogNS4gRmFsbGJhY2sgZGVmYXVsdCB2YWx1ZXMgKGBoZWlnaHQgPSA0MDBgLCBgd2lkdGggPSA2MDBgLCBgc2NhbGUgPSAxYCkuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBfZmluZENoYXJ0U2l6ZVxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gZXhwb3J0T3B0aW9ucyAtIFRoZSBjb25maWd1cmF0aW9uIG9iamVjdCBjb250YWluaW5nIGBleHBvcnRgXHJcbiAqIG9wdGlvbnMuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtPYmplY3R9IFRoZSBvYmplY3QgY29udGFpbmluZyBjYWxjdWxhdGVkIGBoZWlnaHRgLCBgd2lkdGhgXHJcbiAqIGFuZCBgc2NhbGVgIHZhbHVlcyBmb3IgdGhlIGNoYXJ0IGV4cG9ydC5cclxuICovXHJcbmZ1bmN0aW9uIF9maW5kQ2hhcnRTaXplKGV4cG9ydE9wdGlvbnMpIHtcclxuICAvLyBDaGVjayB0aGUgYG9wdGlvbnNgIGFuZCBgaW5zdHJgIGZvciBjaGFydCBhbmQgZXhwb3J0aW5nIHNlY3Rpb25zXHJcbiAgY29uc3QgeyBjaGFydDogb3B0aW9uc0NoYXJ0LCBleHBvcnRpbmc6IG9wdGlvbnNFeHBvcnRpbmcgfSA9XHJcbiAgICBleHBvcnRPcHRpb25zLm9wdGlvbnMgfHwgaXNBbGxvd2VkQ29uZmlnKGV4cG9ydE9wdGlvbnMuaW5zdHIpIHx8IGZhbHNlO1xyXG5cclxuICAvLyBDaGVjayB0aGUgYGdsb2JhbE9wdGlvbnNgIGZvciBjaGFydCBhbmQgZXhwb3J0aW5nIHNlY3Rpb25zXHJcbiAgY29uc3QgeyBjaGFydDogZ2xvYmFsT3B0aW9uc0NoYXJ0LCBleHBvcnRpbmc6IGdsb2JhbE9wdGlvbnNFeHBvcnRpbmcgfSA9XHJcbiAgICBpc0FsbG93ZWRDb25maWcoZXhwb3J0T3B0aW9ucy5nbG9iYWxPcHRpb25zKSB8fCBmYWxzZTtcclxuXHJcbiAgLy8gQ2hlY2sgdGhlIGB0aGVtZU9wdGlvbnNgIGZvciBjaGFydCBhbmQgZXhwb3J0aW5nIHNlY3Rpb25zXHJcbiAgY29uc3QgeyBjaGFydDogdGhlbWVPcHRpb25zQ2hhcnQsIGV4cG9ydGluZzogdGhlbWVPcHRpb25zRXhwb3J0aW5nIH0gPVxyXG4gICAgaXNBbGxvd2VkQ29uZmlnKGV4cG9ydE9wdGlvbnMudGhlbWVPcHRpb25zKSB8fCBmYWxzZTtcclxuXHJcbiAgLy8gRmluZCB0aGUgYHNjYWxlYCB2YWx1ZTpcclxuICAvLyAtIEl0IGNhbm5vdCBiZSBsb3dlciB0aGFuIDAuMVxyXG4gIC8vIC0gSXQgY2Fubm90IGJlIGhpZ2hlciB0aGFuIDUuMFxyXG4gIC8vIC0gSXQgbXVzdCBiZSByb3VuZGVkIHRvIDIgZGVjaW1hbCBwbGFjZXMgKGUuZy4gMC4yMzIzNCAtPiAwLjIzKVxyXG4gIGNvbnN0IHNjYWxlID0gcm91bmROdW1iZXIoXHJcbiAgICBNYXRoLm1heChcclxuICAgICAgMC4xLFxyXG4gICAgICBNYXRoLm1pbihcclxuICAgICAgICBleHBvcnRPcHRpb25zLnNjYWxlIHx8XHJcbiAgICAgICAgICBvcHRpb25zRXhwb3J0aW5nPy5zY2FsZSB8fFxyXG4gICAgICAgICAgZ2xvYmFsT3B0aW9uc0V4cG9ydGluZz8uc2NhbGUgfHxcclxuICAgICAgICAgIHRoZW1lT3B0aW9uc0V4cG9ydGluZz8uc2NhbGUgfHxcclxuICAgICAgICAgIGV4cG9ydE9wdGlvbnMuZGVmYXVsdFNjYWxlIHx8XHJcbiAgICAgICAgICAxLFxyXG4gICAgICAgIDUuMFxyXG4gICAgICApXHJcbiAgICApLFxyXG4gICAgMlxyXG4gICk7XHJcblxyXG4gIC8vIEZpbmQgdGhlIGBoZWlnaHRgIHZhbHVlXHJcbiAgY29uc3QgaGVpZ2h0ID1cclxuICAgIGV4cG9ydE9wdGlvbnMuaGVpZ2h0IHx8XHJcbiAgICBvcHRpb25zRXhwb3J0aW5nPy5zb3VyY2VIZWlnaHQgfHxcclxuICAgIG9wdGlvbnNDaGFydD8uaGVpZ2h0IHx8XHJcbiAgICBnbG9iYWxPcHRpb25zRXhwb3J0aW5nPy5zb3VyY2VIZWlnaHQgfHxcclxuICAgIGdsb2JhbE9wdGlvbnNDaGFydD8uaGVpZ2h0IHx8XHJcbiAgICB0aGVtZU9wdGlvbnNFeHBvcnRpbmc/LnNvdXJjZUhlaWdodCB8fFxyXG4gICAgdGhlbWVPcHRpb25zQ2hhcnQ/LmhlaWdodCB8fFxyXG4gICAgZXhwb3J0T3B0aW9ucy5kZWZhdWx0SGVpZ2h0IHx8XHJcbiAgICA0MDA7XHJcblxyXG4gIC8vIEZpbmQgdGhlIGB3aWR0aGAgdmFsdWVcclxuICBjb25zdCB3aWR0aCA9XHJcbiAgICBleHBvcnRPcHRpb25zLndpZHRoIHx8XHJcbiAgICBvcHRpb25zRXhwb3J0aW5nPy5zb3VyY2VXaWR0aCB8fFxyXG4gICAgb3B0aW9uc0NoYXJ0Py53aWR0aCB8fFxyXG4gICAgZ2xvYmFsT3B0aW9uc0V4cG9ydGluZz8uc291cmNlV2lkdGggfHxcclxuICAgIGdsb2JhbE9wdGlvbnNDaGFydD8ud2lkdGggfHxcclxuICAgIHRoZW1lT3B0aW9uc0V4cG9ydGluZz8uc291cmNlV2lkdGggfHxcclxuICAgIHRoZW1lT3B0aW9uc0NoYXJ0Py53aWR0aCB8fFxyXG4gICAgZXhwb3J0T3B0aW9ucy5kZWZhdWx0V2lkdGggfHxcclxuICAgIDYwMDtcclxuXHJcbiAgLy8gR2F0aGVyIGBoZWlnaHRgLCBgd2lkdGhgIGFuZCBgc2NhbGVgIGluZm9ybWF0aW9uIGluIG9uZSBvYmplY3RcclxuICBjb25zdCBzaXplID0geyBoZWlnaHQsIHdpZHRoLCBzY2FsZSB9O1xyXG5cclxuICAvLyBHZXQgcmlkIG9mIHBvdGVudGlhbCBgcHhgIGFuZCBgJWBcclxuICBmb3IgKGxldCBbcGFyYW0sIHZhbHVlXSBvZiBPYmplY3QuZW50cmllcyhzaXplKSkge1xyXG4gICAgc2l6ZVtwYXJhbV0gPVxyXG4gICAgICB0eXBlb2YgdmFsdWUgPT09ICdzdHJpbmcnID8gK3ZhbHVlLnJlcGxhY2UoL3B4fCUvZ2ksICcnKSA6IHZhbHVlO1xyXG4gIH1cclxuXHJcbiAgLy8gUmV0dXJuIHRoZSBzaXplIG9iamVjdFxyXG4gIHJldHVybiBzaXplO1xyXG59XHJcblxyXG4vKipcclxuICogSGFuZGxlcyB0aGUgZXhlY3V0aW9uIG9mIGN1c3RvbSBsb2dpYyBvcHRpb25zLCBpbmNsdWRpbmcgbG9hZGluZyBgcmVzb3VyY2VzYCxcclxuICogYGN1c3RvbUNvZGVgLCBhbmQgYGNhbGxiYWNrYC4gSWYgY29kZSBleGVjdXRpb24gaXMgYWxsb3dlZCwgaXQgcHJvY2Vzc2VzXHJcbiAqIHRoZSBjdXN0b20gbG9naWMgb3B0aW9ucyBhY2NvcmRpbmdseS4gSWYgY29kZSBleGVjdXRpb24gaXMgbm90IGFsbG93ZWQsXHJcbiAqIGl0IGRpc2FibGVzIHRoZSB1c2FnZSBvZiByZXNvdXJjZXMsIGN1c3RvbSBjb2RlIGFuZCBjYWxsYmFjay5cclxuICpcclxuICogQGZ1bmN0aW9uIF9oYW5kbGVDdXN0b21Mb2dpY1xyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gY3VzdG9tTG9naWNPcHRpb25zIC0gVGhlIGNvbmZpZ3VyYXRpb24gb2JqZWN0IGNvbnRhaW5pbmdcclxuICogYGN1c3RvbUxvZ2ljYCBvcHRpb25zLlxyXG4gKiBAcGFyYW0ge2Jvb2xlYW59IGFsbG93Q29kZUV4ZWN1dGlvbiAtIEEgZmxhZyBpbmRpY2F0aW5nIHdoZXRoZXIgY29kZVxyXG4gKiBleGVjdXRpb24gaXMgYWxsb3dlZC5cclxuICpcclxuICogQHRocm93cyB7RXhwb3J0RXJyb3J9IFRocm93cyBhbiBgRXhwb3J0RXJyb3JgIGlmIGNvZGUgZXhlY3V0aW9uXHJcbiAqIGlzIG5vdCBhbGxvd2VkIGJ1dCBjdXN0b20gbG9naWMgb3B0aW9ucyBhcmUgc3RpbGwgcHJvdmlkZWQuXHJcbiAqL1xyXG5mdW5jdGlvbiBfaGFuZGxlQ3VzdG9tTG9naWMoY3VzdG9tTG9naWNPcHRpb25zLCBhbGxvd0NvZGVFeGVjdXRpb24pIHtcclxuICAvLyBJbiBjYXNlIG9mIGFsbG93aW5nIGNvZGUgZXhlY3V0aW9uXHJcbiAgaWYgKGFsbG93Q29kZUV4ZWN1dGlvbikge1xyXG4gICAgLy8gUHJvY2VzcyB0aGUgYHJlc291cmNlc2Agb3B0aW9uXHJcbiAgICBpZiAodHlwZW9mIGN1c3RvbUxvZ2ljT3B0aW9ucy5yZXNvdXJjZXMgPT09ICdzdHJpbmcnKSB7XHJcbiAgICAgIC8vIEN1c3RvbSBzdHJpbmdpZmllZCByZXNvdXJjZXNcclxuICAgICAgY3VzdG9tTG9naWNPcHRpb25zLnJlc291cmNlcyA9IF9oYW5kbGVSZXNvdXJjZXMoXHJcbiAgICAgICAgY3VzdG9tTG9naWNPcHRpb25zLnJlc291cmNlcyxcclxuICAgICAgICBjdXN0b21Mb2dpY09wdGlvbnMuYWxsb3dGaWxlUmVzb3VyY2VzLFxyXG4gICAgICAgIHRydWVcclxuICAgICAgKTtcclxuICAgIH0gZWxzZSBpZiAoIWN1c3RvbUxvZ2ljT3B0aW9ucy5yZXNvdXJjZXMpIHtcclxuICAgICAgdHJ5IHtcclxuICAgICAgICAvLyBMb2FkIHRoZSBkZWZhdWx0IG9uZVxyXG4gICAgICAgIGN1c3RvbUxvZ2ljT3B0aW9ucy5yZXNvdXJjZXMgPSBfaGFuZGxlUmVzb3VyY2VzKFxyXG4gICAgICAgICAgcmVhZEZpbGVTeW5jKGdldEFic29sdXRlUGF0aCgncmVzb3VyY2VzLmpzb24nKSwgJ3V0ZjgnKSxcclxuICAgICAgICAgIGN1c3RvbUxvZ2ljT3B0aW9ucy5hbGxvd0ZpbGVSZXNvdXJjZXMsXHJcbiAgICAgICAgICB0cnVlXHJcbiAgICAgICAgKTtcclxuICAgICAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICAgICBsb2coMiwgJ1tjaGFydF0gVW5hYmxlIHRvIGxvYWQgdGhlIGRlZmF1bHQgYHJlc291cmNlcy5qc29uYCBmaWxlLicpO1xyXG4gICAgICB9XHJcbiAgICB9XHJcblxyXG4gICAgLy8gUHJvY2VzcyB0aGUgYGN1c3RvbUNvZGVgIG9wdGlvblxyXG4gICAgdHJ5IHtcclxuICAgICAgLy8gVHJ5IHRvIGxvYWQgY3VzdG9tIGNvZGUgYW5kIHdyYXAgYXJvdW5kIGl0IGluIGEgc2VsZiBpbnZva2luZyBmdW5jdGlvblxyXG4gICAgICBjdXN0b21Mb2dpY09wdGlvbnMuY3VzdG9tQ29kZSA9IHdyYXBBcm91bmQoXHJcbiAgICAgICAgY3VzdG9tTG9naWNPcHRpb25zLmN1c3RvbUNvZGUsXHJcbiAgICAgICAgY3VzdG9tTG9naWNPcHRpb25zLmFsbG93RmlsZVJlc291cmNlc1xyXG4gICAgICApO1xyXG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICAgbG9nV2l0aFN0YWNrKDIsIGVycm9yLCAnW2NoYXJ0XSBUaGUgYGN1c3RvbUNvZGVgIGNhbm5vdCBiZSBsb2FkZWQuJyk7XHJcblxyXG4gICAgICAvLyBJbiBjYXNlIG9mIGFuIGVycm9yLCBzZXQgdGhlIG9wdGlvbiB3aXRoIG51bGxcclxuICAgICAgY3VzdG9tTG9naWNPcHRpb25zLmN1c3RvbUNvZGUgPSBudWxsO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIFByb2Nlc3MgdGhlIGBjYWxsYmFja2Agb3B0aW9uXHJcbiAgICB0cnkge1xyXG4gICAgICAvLyBUcnkgdG8gbG9hZCBjYWxsYmFjayBmdW5jdGlvblxyXG4gICAgICBjdXN0b21Mb2dpY09wdGlvbnMuY2FsbGJhY2sgPSB3cmFwQXJvdW5kKFxyXG4gICAgICAgIGN1c3RvbUxvZ2ljT3B0aW9ucy5jYWxsYmFjayxcclxuICAgICAgICBjdXN0b21Mb2dpY09wdGlvbnMuYWxsb3dGaWxlUmVzb3VyY2VzLFxyXG4gICAgICAgIHRydWVcclxuICAgICAgKTtcclxuICAgIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICAgIGxvZ1dpdGhTdGFjaygyLCBlcnJvciwgJ1tjaGFydF0gVGhlIGBjYWxsYmFja2AgY2Fubm90IGJlIGxvYWRlZC4nKTtcclxuXHJcbiAgICAgIC8vIEluIGNhc2Ugb2YgYW4gZXJyb3IsIHNldCB0aGUgb3B0aW9uIHdpdGggbnVsbFxyXG4gICAgICBjdXN0b21Mb2dpY09wdGlvbnMuY2FsbGJhY2sgPSBudWxsO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIENoZWNrIGlmIHRoZXJlIGlzIHRoZSBgY3VzdG9tQ29kZWAgcHJlc2VudFxyXG4gICAgaWYgKFtudWxsLCB1bmRlZmluZWRdLmluY2x1ZGVzKGN1c3RvbUxvZ2ljT3B0aW9ucy5jdXN0b21Db2RlKSkge1xyXG4gICAgICBsb2coMywgJ1tjaGFydF0gTm8gdmFsdWUgZm9yIHRoZSBgY3VzdG9tQ29kZWAgb3B0aW9uIGZvdW5kLicpO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIENoZWNrIGlmIHRoZXJlIGlzIHRoZSBgY2FsbGJhY2tgIHByZXNlbnRcclxuICAgIGlmIChbbnVsbCwgdW5kZWZpbmVkXS5pbmNsdWRlcyhjdXN0b21Mb2dpY09wdGlvbnMuY2FsbGJhY2spKSB7XHJcbiAgICAgIGxvZygzLCAnW2NoYXJ0XSBObyB2YWx1ZSBmb3IgdGhlIGBjYWxsYmFja2Agb3B0aW9uIGZvdW5kLicpO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIENoZWNrIGlmIHRoZXJlIGlzIHRoZSBgcmVzb3VyY2VzYCBwcmVzZW50XHJcbiAgICBpZiAoW251bGwsIHVuZGVmaW5lZF0uaW5jbHVkZXMoY3VzdG9tTG9naWNPcHRpb25zLnJlc291cmNlcykpIHtcclxuICAgICAgbG9nKDMsICdbY2hhcnRdIE5vIHZhbHVlIGZvciB0aGUgYHJlc291cmNlc2Agb3B0aW9uIGZvdW5kLicpO1xyXG4gICAgfVxyXG4gIH0gZWxzZSB7XHJcbiAgICAvLyBJZiB0aGUgYGFsbG93Q29kZUV4ZWN1dGlvbmAgZmxhZyBpcyBzZXQgdG8gZmFsc2UsIHdlIHNob3VsZCByZWZ1c2VcclxuICAgIC8vIHRoZSB1c2FnZSBvZiB0aGUgYGNhbGxiYWNrYCwgYHJlc291cmNlc2AsIGFuZCBgY3VzdG9tQ29kZWAgb3B0aW9ucy5cclxuICAgIC8vIEFkZGl0aW9uYWxseSwgdGhlIHdvcmtlciB3aWxsIHJlZnVzZSB0byBydW4gYXJiaXRyYXJ5IEphdmFTY3JpcHQuXHJcbiAgICBpZiAoXHJcbiAgICAgIGN1c3RvbUxvZ2ljT3B0aW9ucy5jYWxsYmFjayB8fFxyXG4gICAgICBjdXN0b21Mb2dpY09wdGlvbnMucmVzb3VyY2VzIHx8XHJcbiAgICAgIGN1c3RvbUxvZ2ljT3B0aW9ucy5jdXN0b21Db2RlXHJcbiAgICApIHtcclxuICAgICAgLy8gUmVzZXQgYWxsIGN1c3RvbSBjb2RlIG9wdGlvbnNcclxuICAgICAgY3VzdG9tTG9naWNPcHRpb25zLmNhbGxiYWNrID0gbnVsbDtcclxuICAgICAgY3VzdG9tTG9naWNPcHRpb25zLnJlc291cmNlcyA9IG51bGw7XHJcbiAgICAgIGN1c3RvbUxvZ2ljT3B0aW9ucy5jdXN0b21Db2RlID0gbnVsbDtcclxuXHJcbiAgICAgIC8vIFNlbmQgYSBtZXNzYWdlIHNheWluZyB0aGF0IHRoZSBleHBvcnRlciBkb2VzIG5vdCBzdXBwb3J0IHRoZXNlIHNldHRpbmdzXHJcbiAgICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcihcclxuICAgICAgICBgW2NoYXJ0XSBUaGUgJ2NhbGxiYWNrJywgJ3Jlc291cmNlcycsIGFuZCAnY3VzdG9tQ29kZScgb3B0aW9ucyBoYXZlIGJlZW4gZGlzYWJsZWQgZm9yIHRoaXMgc2VydmVyLmAsXHJcbiAgICAgICAgNDAzXHJcbiAgICAgICk7XHJcbiAgICB9XHJcbiAgfVxyXG59XHJcblxyXG4vKipcclxuICogSGFuZGxlcyBhbmQgdmFsaWRhdGVzIHJlc291cmNlcyBmcm9tIHRoZSBgcmVzb3VyY2VzYCBvcHRpb24gZm9yIGV4cG9ydC5cclxuICpcclxuICogQGZ1bmN0aW9uIF9oYW5kbGVSZXNvdXJjZXNcclxuICpcclxuICogQHBhcmFtIHsoT2JqZWN0fHN0cmluZ3xudWxsKX0gW3Jlc291cmNlcz1udWxsXSAtIFRoZSByZXNvdXJjZXMgdG8gYmUgaGFuZGxlZC5cclxuICogQ2FuIGJlIGVpdGhlciBhIEpTT04gb2JqZWN0LCBzdHJpbmdpZmllZCBKU09OLCBhIHBhdGggdG8gYSBKU09OIGZpbGUsXHJcbiAqIG9yIG51bGwuIFRoZSBkZWZhdWx0IHZhbHVlIGlzIGBudWxsYC5cclxuICogQHBhcmFtIHtib29sZWFufSBhbGxvd0ZpbGVSZXNvdXJjZXMgLSBBIGZsYWcgaW5kaWNhdGluZyB3aGV0aGVyIGxvYWRpbmdcclxuICogcmVzb3VyY2VzIGZyb20gZmlsZXMgaXMgYWxsb3dlZC5cclxuICogQHBhcmFtIHtib29sZWFufSBhbGxvd0NvZGVFeGVjdXRpb24gLSBBIGZsYWcgaW5kaWNhdGluZyB3aGV0aGVyIGNvZGVcclxuICogZXhlY3V0aW9uIGlzIGFsbG93ZWQuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHsoT2JqZWN0fG51bGwpfSBUaGUgaGFuZGxlZCByZXNvdXJjZXMgb3IgbnVsbCBpZiBubyB2YWxpZCByZXNvdXJjZXNcclxuICogYXJlIGZvdW5kLlxyXG4gKi9cclxuZnVuY3Rpb24gX2hhbmRsZVJlc291cmNlcyhcclxuICByZXNvdXJjZXMgPSBudWxsLFxyXG4gIGFsbG93RmlsZVJlc291cmNlcyxcclxuICBhbGxvd0NvZGVFeGVjdXRpb25cclxuKSB7XHJcbiAgLy8gTGlzdCBvZiBhbGxvd2VkIHNlY3Rpb25zIGluIHRoZSByZXNvdXJjZXMgSlNPTlxyXG4gIGNvbnN0IGFsbG93ZWRQcm9wcyA9IFsnanMnLCAnY3NzJywgJ2ZpbGVzJ107XHJcblxyXG4gIGxldCBoYW5kbGVkUmVzb3VyY2VzID0gcmVzb3VyY2VzO1xyXG4gIGxldCBjb3JyZWN0UmVzb3VyY2VzID0gZmFsc2U7XHJcblxyXG4gIC8vIFRyeSB0byBsb2FkIHJlc291cmNlcyBmcm9tIGEgZmlsZVxyXG4gIGlmIChhbGxvd0ZpbGVSZXNvdXJjZXMgJiYgcmVzb3VyY2VzLmVuZHNXaXRoKCcuanNvbicpKSB7XHJcbiAgICB0cnkge1xyXG4gICAgICBoYW5kbGVkUmVzb3VyY2VzID0gaXNBbGxvd2VkQ29uZmlnKFxyXG4gICAgICAgIHJlYWRGaWxlU3luYyhnZXRBYnNvbHV0ZVBhdGgocmVzb3VyY2VzKSwgJ3V0ZjgnKSxcclxuICAgICAgICBmYWxzZSxcclxuICAgICAgICBhbGxvd0NvZGVFeGVjdXRpb25cclxuICAgICAgKTtcclxuICAgIH0gY2F0Y2gge1xyXG4gICAgICByZXR1cm4gbnVsbDtcclxuICAgIH1cclxuICB9IGVsc2Uge1xyXG4gICAgLy8gVHJ5IHRvIGdldCBKU09OXHJcbiAgICBoYW5kbGVkUmVzb3VyY2VzID0gaXNBbGxvd2VkQ29uZmlnKHJlc291cmNlcywgZmFsc2UsIGFsbG93Q29kZUV4ZWN1dGlvbik7XHJcblxyXG4gICAgLy8gR2V0IHJpZCBvZiB0aGUgZmlsZXMgc2VjdGlvblxyXG4gICAgaWYgKGhhbmRsZWRSZXNvdXJjZXMgJiYgIWFsbG93RmlsZVJlc291cmNlcykge1xyXG4gICAgICBkZWxldGUgaGFuZGxlZFJlc291cmNlcy5maWxlcztcclxuICAgIH1cclxuICB9XHJcblxyXG4gIC8vIEZpbHRlciBmcm9tIHVubmVjZXNzYXJ5IHByb3BlcnRpZXNcclxuICBmb3IgKGNvbnN0IHByb3BOYW1lIGluIGhhbmRsZWRSZXNvdXJjZXMpIHtcclxuICAgIGlmICghYWxsb3dlZFByb3BzLmluY2x1ZGVzKHByb3BOYW1lKSkge1xyXG4gICAgICBkZWxldGUgaGFuZGxlZFJlc291cmNlc1twcm9wTmFtZV07XHJcbiAgICB9IGVsc2UgaWYgKCFjb3JyZWN0UmVzb3VyY2VzKSB7XHJcbiAgICAgIGNvcnJlY3RSZXNvdXJjZXMgPSB0cnVlO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgLy8gQ2hlY2sgaWYgYXQgbGVhc3Qgb25lIG9mIGFsbG93ZWQgcHJvcGVydGllcyBpcyBwcmVzZW50XHJcbiAgaWYgKCFjb3JyZWN0UmVzb3VyY2VzKSB7XHJcbiAgICByZXR1cm4gbnVsbDtcclxuICB9XHJcblxyXG4gIC8vIEhhbmRsZSBmaWxlcyBzZWN0aW9uXHJcbiAgaWYgKGhhbmRsZWRSZXNvdXJjZXMuZmlsZXMpIHtcclxuICAgIGhhbmRsZWRSZXNvdXJjZXMuZmlsZXMgPSBoYW5kbGVkUmVzb3VyY2VzLmZpbGVzLm1hcCgoaXRlbSkgPT4gaXRlbS50cmltKCkpO1xyXG4gICAgaWYgKCFoYW5kbGVkUmVzb3VyY2VzLmZpbGVzIHx8IGhhbmRsZWRSZXNvdXJjZXMuZmlsZXMubGVuZ3RoIDw9IDApIHtcclxuICAgICAgZGVsZXRlIGhhbmRsZWRSZXNvdXJjZXMuZmlsZXM7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICAvLyBSZXR1cm4gcmVzb3VyY2VzXHJcbiAgcmV0dXJuIGhhbmRsZWRSZXNvdXJjZXM7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBIYW5kbGVzIHRoZSBsb2FkaW5nIGFuZCB2YWxpZGF0aW9uIG9mIHRoZSBgZ2xvYmFsT3B0aW9uc2AgYW5kIGB0aGVtZU9wdGlvbnNgXHJcbiAqIGluIHRoZSBleHBvcnQgb3B0aW9ucy4gSWYgdGhlIG9wdGlvbiBpcyBhIHN0cmluZyBhbmQgcmVmZXJlbmNlcyBhIEpTT04gZmlsZVxyXG4gKiAod2hlbiB0aGUgYGFsbG93RmlsZVJlc291cmNlc2AgaXMgdHJ1ZSksIGl0IHJlYWRzIGFuZCBwYXJzZXMgdGhlIGZpbGUuXHJcbiAqIE90aGVyd2lzZSwgaXQgYXR0ZW1wdHMgdG8gcGFyc2UgdGhlIHN0cmluZyBvciBvYmplY3QgYXMgSlNPTi4gSWYgYW55IGVycm9yc1xyXG4gKiBvY2N1ciBkdXJpbmcgdGhpcyBwcm9jZXNzLCB0aGUgb3B0aW9uIGlzIHNldCB0byBudWxsLiBJZiB0aGVyZSBpcyBhbiBlcnJvclxyXG4gKiBsb2FkaW5nIG9yIHBhcnNpbmcgdGhlIGBnbG9iYWxPcHRpb25zYCBvciBgdGhlbWVPcHRpb25zYCwgdGhlIGVycm9yIGlzIGxvZ2dlZFxyXG4gKiBhbmQgdGhlIG9wdGlvbiBpcyBzZXQgdG8gbnVsbC5cclxuICpcclxuICogQGZ1bmN0aW9uIF9oYW5kbGVHbG9iYWxBbmRUaGVtZVxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gZXhwb3J0T3B0aW9ucyAtIFRoZSBjb25maWd1cmF0aW9uIG9iamVjdCBjb250YWluaW5nIGBleHBvcnRgXHJcbiAqIG9wdGlvbnMuXHJcbiAqIEBwYXJhbSB7Ym9vbGVhbn0gYWxsb3dGaWxlUmVzb3VyY2VzIC0gQSBmbGFnIGluZGljYXRpbmcgd2hldGhlciBsb2FkaW5nXHJcbiAqIHJlc291cmNlcyBmcm9tIGZpbGVzIGlzIGFsbG93ZWQuXHJcbiAqIEBwYXJhbSB7Ym9vbGVhbn0gYWxsb3dDb2RlRXhlY3V0aW9uIC0gQSBmbGFnIGluZGljYXRpbmcgd2hldGhlciBjb2RlXHJcbiAqIGV4ZWN1dGlvbiBpcyBhbGxvd2VkLlxyXG4gKi9cclxuZnVuY3Rpb24gX2hhbmRsZUdsb2JhbEFuZFRoZW1lKFxyXG4gIGV4cG9ydE9wdGlvbnMsXHJcbiAgYWxsb3dGaWxlUmVzb3VyY2VzLFxyXG4gIGFsbG93Q29kZUV4ZWN1dGlvblxyXG4pIHtcclxuICAvLyBDaGVjayB0aGUgYGdsb2JhbE9wdGlvbnNgIGFuZCBgdGhlbWVPcHRpb25zYCBvcHRpb25zXHJcbiAgWydnbG9iYWxPcHRpb25zJywgJ3RoZW1lT3B0aW9ucyddLmZvckVhY2goKG9wdGlvbnNOYW1lKSA9PiB7XHJcbiAgICB0cnkge1xyXG4gICAgICAvLyBDaGVjayBpZiB0aGUgb3B0aW9uIGV4aXN0c1xyXG4gICAgICBpZiAoZXhwb3J0T3B0aW9uc1tvcHRpb25zTmFtZV0pIHtcclxuICAgICAgICAvLyBDaGVjayBpZiBpdCBpcyBhIHN0cmluZyBhbmQgYSBmaWxlIG5hbWUgd2l0aCB0aGUgYC5qc29uYCBleHRlbnNpb25cclxuICAgICAgICBpZiAoXHJcbiAgICAgICAgICBhbGxvd0ZpbGVSZXNvdXJjZXMgJiZcclxuICAgICAgICAgIHR5cGVvZiBleHBvcnRPcHRpb25zW29wdGlvbnNOYW1lXSA9PT0gJ3N0cmluZycgJiZcclxuICAgICAgICAgIGV4cG9ydE9wdGlvbnNbb3B0aW9uc05hbWVdLmVuZHNXaXRoKCcuanNvbicpXHJcbiAgICAgICAgKSB7XHJcbiAgICAgICAgICAvLyBDaGVjayBpZiB0aGUgZmlsZSBjb250ZW50IGNhbiBiZSBhIGNvbmZpZywgYW5kIHNhdmUgaXQgYXMgYSBzdHJpbmdcclxuICAgICAgICAgIGV4cG9ydE9wdGlvbnNbb3B0aW9uc05hbWVdID0gaXNBbGxvd2VkQ29uZmlnKFxyXG4gICAgICAgICAgICByZWFkRmlsZVN5bmMoZ2V0QWJzb2x1dGVQYXRoKGV4cG9ydE9wdGlvbnNbb3B0aW9uc05hbWVdKSwgJ3V0ZjgnKSxcclxuICAgICAgICAgICAgdHJ1ZSxcclxuICAgICAgICAgICAgYWxsb3dDb2RlRXhlY3V0aW9uXHJcbiAgICAgICAgICApO1xyXG4gICAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgICAvLyBDaGVjayBpZiB0aGUgdmFsdWUgY2FuIGJlIGEgY29uZmlnLCBhbmQgc2F2ZSBpdCBhcyBhIHN0cmluZ1xyXG4gICAgICAgICAgZXhwb3J0T3B0aW9uc1tvcHRpb25zTmFtZV0gPSBpc0FsbG93ZWRDb25maWcoXHJcbiAgICAgICAgICAgIGV4cG9ydE9wdGlvbnNbb3B0aW9uc05hbWVdLFxyXG4gICAgICAgICAgICB0cnVlLFxyXG4gICAgICAgICAgICBhbGxvd0NvZGVFeGVjdXRpb25cclxuICAgICAgICAgICk7XHJcbiAgICAgICAgfVxyXG4gICAgICB9XHJcbiAgICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgICBsb2dXaXRoU3RhY2soXHJcbiAgICAgICAgMixcclxuICAgICAgICBlcnJvcixcclxuICAgICAgICBgW2NoYXJ0XSBUaGUgXFxgJHtvcHRpb25zTmFtZX1cXGAgY2Fubm90IGJlIGxvYWRlZC5gXHJcbiAgICAgICk7XHJcblxyXG4gICAgICAvLyBJbiBjYXNlIG9mIGFuIGVycm9yLCBzZXQgdGhlIG9wdGlvbiB3aXRoIG51bGxcclxuICAgICAgZXhwb3J0T3B0aW9uc1tvcHRpb25zTmFtZV0gPSBudWxsO1xyXG4gICAgfVxyXG4gIH0pO1xyXG5cclxuICAvLyBDaGVjayBpZiB0aGVyZSBpcyB0aGUgYGdsb2JhbE9wdGlvbnNgIHByZXNlbnRcclxuICBpZiAoW251bGwsIHVuZGVmaW5lZF0uaW5jbHVkZXMoZXhwb3J0T3B0aW9ucy5nbG9iYWxPcHRpb25zKSkge1xyXG4gICAgbG9nKDMsICdbY2hhcnRdIE5vIHZhbHVlIGZvciB0aGUgYGdsb2JhbE9wdGlvbnNgIG9wdGlvbiBmb3VuZC4nKTtcclxuICB9XHJcblxyXG4gIC8vIENoZWNrIGlmIHRoZXJlIGlzIHRoZSBgdGhlbWVPcHRpb25zYCBwcmVzZW50XHJcbiAgaWYgKFtudWxsLCB1bmRlZmluZWRdLmluY2x1ZGVzKGV4cG9ydE9wdGlvbnMudGhlbWVPcHRpb25zKSkge1xyXG4gICAgbG9nKDMsICdbY2hhcnRdIE5vIHZhbHVlIGZvciB0aGUgYHRoZW1lT3B0aW9uc2Agb3B0aW9uIGZvdW5kLicpO1xyXG4gIH1cclxufVxyXG5cclxuZXhwb3J0IGRlZmF1bHQge1xyXG4gIHNpbmdsZUV4cG9ydCxcclxuICBiYXRjaEV4cG9ydCxcclxuICBzdGFydEV4cG9ydCxcclxuICBnZXRBbGxvd0NvZGVFeGVjdXRpb24sXHJcbiAgc2V0QWxsb3dDb2RlRXhlY3V0aW9uXHJcbn07XHJcbiIsIi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXHJcblxyXG5IaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXJcclxuXHJcbkNvcHlyaWdodCAoYykgMjAxNi0yMDI1LCBIaWdoc29mdFxyXG5cclxuTGljZW5jZWQgdW5kZXIgdGhlIE1JVCBsaWNlbmNlLlxyXG5cclxuQWRkaXRpb25hbGx5IGEgdmFsaWQgSGlnaGNoYXJ0cyBsaWNlbnNlIGlzIHJlcXVpcmVkIGZvciB1c2UuXHJcblxyXG5TZWUgTElDRU5TRSBmaWxlIGluIHJvb3QgZm9yIGRldGFpbHMuXHJcblxyXG4qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xyXG5cclxuLyoqXHJcbiAqIEBvdmVydmlldyBUaGlzIG1vZHVsZSBwcm92aWRlcyB1dGlsaXR5IGZ1bmN0aW9ucyBmb3IgbWFuYWdpbmcgaW50ZXJ2YWxzXHJcbiAqIGFuZCB0aW1lb3V0cyBpbiBhIGNlbnRyYWxpemVkIG1hbm5lci4gSXQgbWFpbnRhaW5zIGEgcmVnaXN0cnkgb2YgYWxsIGFjdGl2ZVxyXG4gKiB0aW1lcnMgYW5kIGFsbG93cyBmb3IgdGhlaXIgZWZmaWNpZW50IGNsZWFudXAgd2hlbiBuZWVkZWQuIFRoaXMgY2FuIGJlIHVzZWZ1bFxyXG4gKiBpbiBhcHBsaWNhdGlvbnMgd2hlcmUgcHJvcGVyIHJlc291cmNlIG1hbmFnZW1lbnQgYW5kIGNsZWFuIHNodXRkb3duIG9mIHRpbWVyc1xyXG4gKiBhcmUgY3JpdGljYWwgdG8gYXZvaWQgbWVtb3J5IGxlYWtzIG9yIHVuaW50ZW5kZWQgYmVoYXZpb3IuXHJcbiAqL1xyXG5cclxuaW1wb3J0IHsgbG9nIH0gZnJvbSAnLi9sb2dnZXIuanMnO1xyXG5cclxuLy8gQXJyYXkgdGhhdCBjb250YWlucyBpZHMgb2YgYWxsIG9uZ29pbmcgaW50ZXJ2YWxzIGFuZCB0aW1lb3V0c1xyXG5jb25zdCB0aW1lcklkcyA9IFtdO1xyXG5cclxuLyoqXHJcbiAqIEFkZHMgaWQgb2YgdGhlIGBzZXRJbnRlcnZhbGAgb3IgYHNldFRpbWVvdXRgIGFuZCB0byB0aGUgYHRpbWVySWRzYCBhcnJheS5cclxuICpcclxuICogQGZ1bmN0aW9uIGFkZFRpbWVyXHJcbiAqXHJcbiAqIEBwYXJhbSB7Tm9kZUpTLlRpbWVvdXR9IGlkIC0gSWQgb2YgYW4gaW50ZXJ2YWwgb3IgYSB0aW1lb3V0LlxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIGFkZFRpbWVyKGlkKSB7XHJcbiAgdGltZXJJZHMucHVzaChpZCk7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBDbGVhcnMgYWxsIG9mIG9uZ29pbmcgaW50ZXJ2YWxzIGFuZCB0aW1lb3V0cyBieSBpZHMgZ2F0aGVyZWRcclxuICogaW4gdGhlIGB0aW1lcklkc2AgYXJyYXkuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBjbGVhckFsbFRpbWVyc1xyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIGNsZWFyQWxsVGltZXJzKCkge1xyXG4gIGxvZyg0LCBgW3RpbWVyXSBDbGVhcmluZyBhbGwgcmVnaXN0ZXJlZCBpbnRlcnZhbHMgYW5kIHRpbWVvdXRzLmApO1xyXG4gIGZvciAoY29uc3QgaWQgb2YgdGltZXJJZHMpIHtcclxuICAgIGNsZWFySW50ZXJ2YWwoaWQpO1xyXG4gICAgY2xlYXJUaW1lb3V0KGlkKTtcclxuICB9XHJcbn1cclxuXHJcbmV4cG9ydCBkZWZhdWx0IHtcclxuICBhZGRUaW1lcixcclxuICBjbGVhckFsbFRpbWVyc1xyXG59O1xyXG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxyXG5cclxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXHJcblxyXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNSwgSGlnaHNvZnRcclxuXHJcbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cclxuXHJcbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxyXG5cclxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxyXG5cclxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cclxuXHJcbi8qKlxyXG4gKiBAb3ZlcnZpZXcgUHJvdmlkZXMgbWlkZGxld2FyZSBmdW5jdGlvbnMgZm9yIGxvZ2dpbmcgZXJyb3JzIHdpdGggc3RhY2sgdHJhY2VzXHJcbiAqIGFuZCBoYW5kbGluZyBlcnJvciByZXNwb25zZXMgaW4gYW4gRXhwcmVzcyBhcHBsaWNhdGlvbi5cclxuICovXHJcblxyXG5pbXBvcnQgeyBnZXRPcHRpb25zIH0gZnJvbSAnLi4vLi4vY29uZmlnLmpzJztcclxuaW1wb3J0IHsgbG9nV2l0aFN0YWNrIH0gZnJvbSAnLi4vLi4vbG9nZ2VyLmpzJztcclxuXHJcbi8qKlxyXG4gKiBNaWRkbGV3YXJlIGZvciBsb2dnaW5nIGVycm9ycyB3aXRoIHN0YWNrIHRyYWNlIGFuZCBoYW5kbGluZyBlcnJvciByZXNwb25zZS5cclxuICpcclxuICogQGZ1bmN0aW9uIGxvZ0Vycm9yTWlkZGxld2FyZVxyXG4gKlxyXG4gKiBAcGFyYW0ge0Vycm9yfSBlcnJvciAtIFRoZSBlcnJvciBvYmplY3QuXHJcbiAqIEBwYXJhbSB7RXhwcmVzcy5SZXF1ZXN0fSByZXF1ZXN0IC0gVGhlIEV4cHJlc3MgcmVxdWVzdCBvYmplY3QuXHJcbiAqIEBwYXJhbSB7RXhwcmVzcy5SZXNwb25zZX0gcmVzcG9uc2UgLSBUaGUgRXhwcmVzcyByZXNwb25zZSBvYmplY3QuXHJcbiAqIEBwYXJhbSB7RnVuY3Rpb259IG5leHQgLSBUaGUgbmV4dCBtaWRkbGV3YXJlIGZ1bmN0aW9uLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7dW5kZWZpbmVkfSBUaGUgY2FsbCB0byB0aGUgbmV4dCBtaWRkbGV3YXJlIGZ1bmN0aW9uIHdpdGhcclxuICogdGhlIHBhc3NlZCBlcnJvci5cclxuICovXHJcbmZ1bmN0aW9uIGxvZ0Vycm9yTWlkZGxld2FyZShlcnJvciwgcmVxdWVzdCwgcmVzcG9uc2UsIG5leHQpIHtcclxuICAvLyBEaXNwbGF5IHRoZSBlcnJvciB3aXRoIHN0YWNrIGluIGEgY29ycmVjdCBmb3JtYXRcclxuICBsb2dXaXRoU3RhY2soMSwgZXJyb3IpO1xyXG5cclxuICAvLyBEZWxldGUgdGhlIHN0YWNrIGZvciB0aGUgZW52aXJvbm1lbnQgb3RoZXIgdGhhbiB0aGUgZGV2ZWxvcG1lbnRcclxuICBpZiAoZ2V0T3B0aW9ucygpLm90aGVyLm5vZGVFbnYgIT09ICdkZXZlbG9wbWVudCcpIHtcclxuICAgIGRlbGV0ZSBlcnJvci5zdGFjaztcclxuICB9XHJcblxyXG4gIC8vIENhbGwgdGhlIGByZXR1cm5FcnJvck1pZGRsZXdhcmVgIG1pZGRsZXdhcmVcclxuICByZXR1cm4gbmV4dChlcnJvcik7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBNaWRkbGV3YXJlIGZvciByZXR1cm5pbmcgZXJyb3IgcmVzcG9uc2UuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiByZXR1cm5FcnJvck1pZGRsZXdhcmVcclxuICpcclxuICogQHBhcmFtIHtFcnJvcn0gZXJyb3IgLSBUaGUgZXJyb3Igb2JqZWN0LlxyXG4gKiBAcGFyYW0ge0V4cHJlc3MuUmVxdWVzdH0gcmVxdWVzdCAtIFRoZSBFeHByZXNzIHJlcXVlc3Qgb2JqZWN0LlxyXG4gKiBAcGFyYW0ge0V4cHJlc3MuUmVzcG9uc2V9IHJlc3BvbnNlIC0gVGhlIEV4cHJlc3MgcmVzcG9uc2Ugb2JqZWN0LlxyXG4gKiBAcGFyYW0ge0Z1bmN0aW9ufSBuZXh0IC0gVGhlIG5leHQgbWlkZGxld2FyZSBmdW5jdGlvbi5cclxuICovXHJcbmZ1bmN0aW9uIHJldHVybkVycm9yTWlkZGxld2FyZShlcnJvciwgcmVxdWVzdCwgcmVzcG9uc2UsIG5leHQpIHtcclxuICAvLyBHYXRoZXIgYWxsIHJlcXVpZWQgaW5mb3JtYXRpb24gZm9yIHRoZSByZXNwb25zZVxyXG4gIGNvbnN0IHsgbWVzc2FnZSwgc3RhY2sgfSA9IGVycm9yO1xyXG5cclxuICAvLyBVc2UgdGhlIGVycm9yJ3Mgc3RhdHVzIGNvZGUgb3IgdGhlIGRlZmF1bHQgNDAwXHJcbiAgY29uc3Qgc3RhdHVzQ29kZSA9IGVycm9yLnN0YXR1c0NvZGUgfHwgNDAwO1xyXG5cclxuICAvLyBTZXQgYW5kIHJldHVybiByZXNwb25zZVxyXG4gIHJlc3BvbnNlLnN0YXR1cyhzdGF0dXNDb2RlKS5qc29uKHsgc3RhdHVzQ29kZSwgbWVzc2FnZSwgc3RhY2sgfSk7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBBZGRzIHRoZSBlcnJvciBtaWRkbGV3YXJlcyB0byB0aGUgcGFzc2VkIGV4cHJlc3MgYXBwIGluc3RhbmNlLlxyXG4gKlxyXG4gKiBAcGFyYW0ge0V4cHJlc3N9IGFwcCAtIFRoZSBFeHByZXNzIGFwcCBpbnN0YW5jZS5cclxuICovXHJcbmV4cG9ydCBkZWZhdWx0IGZ1bmN0aW9uIGVycm9yTWlkZGxld2FyZShhcHApIHtcclxuICAvLyBBZGQgbG9nIGVycm9yIG1pZGRsZXdhcmVcclxuICBhcHAudXNlKGxvZ0Vycm9yTWlkZGxld2FyZSk7XHJcblxyXG4gIC8vIEFkZCBzZXQgc3RhdHVzIGFuZCByZXR1cm4gZXJyb3IgbWlkZGxld2FyZVxyXG4gIGFwcC51c2UocmV0dXJuRXJyb3JNaWRkbGV3YXJlKTtcclxufVxyXG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxyXG5cclxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXHJcblxyXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNSwgSGlnaHNvZnRcclxuXHJcbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cclxuXHJcbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxyXG5cclxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxyXG5cclxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cclxuXHJcbi8qKlxyXG4gKiBAb3ZlcnZpZXcgUHJvdmlkZXMgbWlkZGxld2FyZSBmdW5jdGlvbnMgZm9yIGNvbmZpZ3VyaW5nIGFuZCBlbmFibGluZyByYXRlXHJcbiAqIGxpbWl0aW5nIGluIGFuIEV4cHJlc3MgYXBwbGljYXRpb24uXHJcbiAqL1xyXG5cclxuaW1wb3J0IHJhdGVMaW1pdCBmcm9tICdleHByZXNzLXJhdGUtbGltaXQnO1xyXG5cclxuaW1wb3J0IHsgbG9nIH0gZnJvbSAnLi4vLi4vbG9nZ2VyLmpzJztcclxuXHJcbmltcG9ydCBFeHBvcnRFcnJvciBmcm9tICcuLi8uLi9lcnJvcnMvRXhwb3J0RXJyb3IuanMnO1xyXG5cclxuLyoqXHJcbiAqIE1pZGRsZXdhcmUgZm9yIGVuYWJsaW5nIHJhdGUgbGltaXRpbmcgb24gdGhlIHNwZWNpZmllZCBFeHByZXNzIGFwcC5cclxuICpcclxuICogQHBhcmFtIHtFeHByZXNzfSBhcHAgLSBUaGUgRXhwcmVzcyBhcHAgaW5zdGFuY2UuXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSByYXRlTGltaXRpbmdPcHRpb25zIC0gVGhlIGNvbmZpZ3VyYXRpb24gb2JqZWN0IGNvbnRhaW5pbmdcclxuICogYHJhdGVMaW1pdGluZ2Agb3B0aW9ucy5cclxuICpcclxuICogQHRocm93cyB7RXhwb3J0RXJyb3J9IFRocm93cyBhbiBgRXhwb3J0RXJyb3JgIGlmIGNvdWxkIG5vdCBjb25maWd1cmUgYW5kIHNldFxyXG4gKiB0aGUgcmF0ZSBsaW1pdGluZyBvcHRpb25zLlxyXG4gKi9cclxuZXhwb3J0IGRlZmF1bHQgZnVuY3Rpb24gcmF0ZUxpbWl0aW5nTWlkZGxld2FyZShhcHAsIHJhdGVMaW1pdGluZ09wdGlvbnMpIHtcclxuICB0cnkge1xyXG4gICAgLy8gQ2hlY2sgaWYgdGhlIHJhdGUgbGltaXRpbmcgaXMgZW5hYmxlZFxyXG4gICAgaWYgKHJhdGVMaW1pdGluZ09wdGlvbnMuZW5hYmxlKSB7XHJcbiAgICAgIGNvbnN0IG1lc3NhZ2UgPVxyXG4gICAgICAgICdUb28gbWFueSByZXF1ZXN0cywgeW91IGhhdmUgYmVlbiByYXRlIGxpbWl0ZWQuIFBsZWFzZSB0cnkgYWdhaW4gbGF0ZXIuJztcclxuXHJcbiAgICAgIC8vIE9wdGlvbnMgZm9yIHRoZSByYXRlIGxpbWl0ZXJcclxuICAgICAgY29uc3QgcmF0ZU9wdGlvbnMgPSB7XHJcbiAgICAgICAgd2luZG93OiByYXRlTGltaXRpbmdPcHRpb25zLndpbmRvdyB8fCAxLFxyXG4gICAgICAgIG1heFJlcXVlc3RzOiByYXRlTGltaXRpbmdPcHRpb25zLm1heFJlcXVlc3RzIHx8IDMwLFxyXG4gICAgICAgIGRlbGF5OiByYXRlTGltaXRpbmdPcHRpb25zLmRlbGF5IHx8IDAsXHJcbiAgICAgICAgdHJ1c3RQcm94eTogcmF0ZUxpbWl0aW5nT3B0aW9ucy50cnVzdFByb3h5IHx8IGZhbHNlLFxyXG4gICAgICAgIHNraXBLZXk6IHJhdGVMaW1pdGluZ09wdGlvbnMuc2tpcEtleSB8fCBudWxsLFxyXG4gICAgICAgIHNraXBUb2tlbjogcmF0ZUxpbWl0aW5nT3B0aW9ucy5za2lwVG9rZW4gfHwgbnVsbFxyXG4gICAgICB9O1xyXG5cclxuICAgICAgLy8gU2V0IGlmIGJlaGluZCBhIHByb3h5XHJcbiAgICAgIGlmIChyYXRlT3B0aW9ucy50cnVzdFByb3h5KSB7XHJcbiAgICAgICAgYXBwLmVuYWJsZSgndHJ1c3QgcHJveHknKTtcclxuICAgICAgfVxyXG5cclxuICAgICAgLy8gQ3JlYXRlIGEgbGltaXRlclxyXG4gICAgICBjb25zdCBsaW1pdGVyID0gcmF0ZUxpbWl0KHtcclxuICAgICAgICAvLyBUaW1lIGZyYW1lIGZvciB3aGljaCByZXF1ZXN0cyBhcmUgY2hlY2tlZCBhbmQgcmVtZW1iZXJlZFxyXG4gICAgICAgIHdpbmRvd01zOiByYXRlT3B0aW9ucy53aW5kb3cgKiA2MCAqIDEwMDAsXHJcbiAgICAgICAgLy8gTGltaXQgZWFjaCBJUCB0byAxMDAgcmVxdWVzdHMgcGVyIGB3aW5kb3dNc2BcclxuICAgICAgICBsaW1pdDogcmF0ZU9wdGlvbnMubWF4UmVxdWVzdHMsXHJcbiAgICAgICAgLy8gRGlzYWJsZSBkZWxheWluZywgZnVsbCBzcGVlZCB1bnRpbCB0aGUgbWF4IGxpbWl0IGlzIHJlYWNoZWRcclxuICAgICAgICBkZWxheU1zOiByYXRlT3B0aW9ucy5kZWxheSxcclxuICAgICAgICBoYW5kbGVyOiAocmVxdWVzdCwgcmVzcG9uc2UpID0+IHtcclxuICAgICAgICAgIHJlc3BvbnNlLmZvcm1hdCh7XHJcbiAgICAgICAgICAgIGpzb246ICgpID0+IHtcclxuICAgICAgICAgICAgICByZXNwb25zZS5zdGF0dXMoNDI5KS5zZW5kKHsgbWVzc2FnZSB9KTtcclxuICAgICAgICAgICAgfSxcclxuICAgICAgICAgICAgZGVmYXVsdDogKCkgPT4ge1xyXG4gICAgICAgICAgICAgIHJlc3BvbnNlLnN0YXR1cyg0MjkpLnNlbmQobWVzc2FnZSk7XHJcbiAgICAgICAgICAgIH1cclxuICAgICAgICAgIH0pO1xyXG4gICAgICAgIH0sXHJcbiAgICAgICAgc2tpcDogKHJlcXVlc3QpID0+IHtcclxuICAgICAgICAgIC8vIEFsbG93IGJ5cGFzc2luZyB0aGUgbGltaXRlciBpZiBhIHZhbGlkIGtleS90b2tlbiBoYXMgYmVlbiBzZW50XHJcbiAgICAgICAgICBpZiAoXHJcbiAgICAgICAgICAgIHJhdGVPcHRpb25zLnNraXBLZXkgIT09IG51bGwgJiZcclxuICAgICAgICAgICAgcmF0ZU9wdGlvbnMuc2tpcFRva2VuICE9PSBudWxsICYmXHJcbiAgICAgICAgICAgIHJlcXVlc3QucXVlcnkua2V5ID09PSByYXRlT3B0aW9ucy5za2lwS2V5ICYmXHJcbiAgICAgICAgICAgIHJlcXVlc3QucXVlcnkuYWNjZXNzX3Rva2VuID09PSByYXRlT3B0aW9ucy5za2lwVG9rZW5cclxuICAgICAgICAgICkge1xyXG4gICAgICAgICAgICBsb2coNCwgJ1tyYXRlIGxpbWl0aW5nXSBTa2lwcGluZyByYXRlIGxpbWl0ZXIuJyk7XHJcbiAgICAgICAgICAgIHJldHVybiB0cnVlO1xyXG4gICAgICAgICAgfVxyXG4gICAgICAgICAgcmV0dXJuIGZhbHNlO1xyXG4gICAgICAgIH1cclxuICAgICAgfSk7XHJcblxyXG4gICAgICAvLyBVc2UgYSBsaW1pdGVyIGFzIGEgbWlkZGxld2FyZVxyXG4gICAgICBhcHAudXNlKGxpbWl0ZXIpO1xyXG5cclxuICAgICAgbG9nKFxyXG4gICAgICAgIDMsXHJcbiAgICAgICAgYFtyYXRlIGxpbWl0aW5nXSBFbmFibGVkIHJhdGUgbGltaXRpbmcgd2l0aCAke3JhdGVPcHRpb25zLm1heFJlcXVlc3RzfSByZXF1ZXN0cyBwZXIgJHtyYXRlT3B0aW9ucy53aW5kb3d9IG1pbnV0ZSBmb3IgZWFjaCBJUCwgdHJ1c3RpbmcgcHJveHk6ICR7cmF0ZU9wdGlvbnMudHJ1c3RQcm94eX0uYFxyXG4gICAgICApO1xyXG4gICAgfVxyXG4gIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoXHJcbiAgICAgICdbcmF0ZSBsaW1pdGluZ10gQ291bGQgbm90IGNvbmZpZ3VyZSBhbmQgc2V0IHRoZSByYXRlIGxpbWl0aW5nIG9wdGlvbnMuJyxcclxuICAgICAgNTAwXHJcbiAgICApLnNldEVycm9yKGVycm9yKTtcclxuICB9XHJcbn1cclxuIiwiLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcclxuXHJcbkhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlclxyXG5cclxuQ29weXJpZ2h0IChjKSAyMDE2LTIwMjUsIEhpZ2hzb2Z0XHJcblxyXG5MaWNlbmNlZCB1bmRlciB0aGUgTUlUIGxpY2VuY2UuXHJcblxyXG5BZGRpdGlvbmFsbHkgYSB2YWxpZCBIaWdoY2hhcnRzIGxpY2Vuc2UgaXMgcmVxdWlyZWQgZm9yIHVzZS5cclxuXHJcblNlZSBMSUNFTlNFIGZpbGUgaW4gcm9vdCBmb3IgZGV0YWlscy5cclxuXHJcbioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXHJcblxyXG4vKipcclxuICogQG92ZXJ2aWV3IFByb3ZpZGVzIG1pZGRsZXdhcmUgZnVuY3Rpb25zIGZvciB2YWxpZGF0aW5nIGluY29taW5nIEhUVFAgcmVxdWVzdHNcclxuICogaW4gYW4gRXhwcmVzcyBhcHBsaWNhdGlvbi4gVGhpcyBtb2R1bGUgZW5zdXJlcyB0aGF0IHJlcXVlc3RzIGNvbnRhaW5cclxuICogYXBwcm9wcmlhdGUgY29udGVudCB0eXBlcyBhbmQgdmFsaWQgcmVxdWVzdCBib2RpZXMsIGluY2x1ZGluZyBwcm9wZXIgSlNPTlxyXG4gKiBzdHJ1Y3R1cmVzIGFuZCBjaGFydCBkYXRhIGZvciBleHBvcnRzLiBJdCBjaGVja3MgZm9yIHBvdGVudGlhbCBpc3N1ZXMgc3VjaFxyXG4gKiBhcyBtaXNzaW5nIG9yIG1hbGZvcm1lZCBkYXRhLCBwcml2YXRlIHJhbmdlIFVSTHMgaW4gU1ZHIHBheWxvYWRzLCBhbmQgYWxsb3dzXHJcbiAqIGZvciBmbGV4aWJsZSBvcHRpb25zIHZhbGlkYXRpb24uIFRoZSBtaWRkbGV3YXJlIGxvZ3MgZGV0YWlsZWQgaW5mb3JtYXRpb25cclxuICogYW5kIGhhbmRsZXMgZXJyb3JzIHJlbGF0ZWQgdG8gaW5jb3JyZWN0IHBheWxvYWRzLCBjaGFydCBkYXRhLCBhbmQgcHJpdmF0ZSBVUkxcclxuICogdXNhZ2UuXHJcbiAqL1xyXG5cclxuaW1wb3J0IHsgdjQgYXMgdXVpZCB9IGZyb20gJ3V1aWQnO1xyXG5cclxuaW1wb3J0IHsgZ2V0QWxsb3dDb2RlRXhlY3V0aW9uIH0gZnJvbSAnLi4vLi4vY2hhcnQuanMnO1xyXG5pbXBvcnQgeyBpc0FsbG93ZWRDb25maWcgfSBmcm9tICcuLi8uLi9jb25maWcuanMnO1xyXG5pbXBvcnQgeyBsb2csIGxvZ1pvZElzc3VlcyB9IGZyb20gJy4uLy4uL2xvZ2dlci5qcyc7XHJcbmltcG9ydCB7XHJcbiAgZml4Q29uc3RyLFxyXG4gIGZpeFR5cGUsXHJcbiAgaXNPYmplY3RFbXB0eSxcclxuICBpc1ByaXZhdGVSYW5nZVVybEZvdW5kXHJcbn0gZnJvbSAnLi4vLi4vdXRpbHMuanMnO1xyXG5pbXBvcnQgeyBsb29zZVZhbGlkYXRlIH0gZnJvbSAnLi4vLi4vdmFsaWRhdGlvbi5qcyc7XHJcblxyXG5pbXBvcnQgRXhwb3J0RXJyb3IgZnJvbSAnLi4vLi4vZXJyb3JzL0V4cG9ydEVycm9yLmpzJztcclxuXHJcbi8qKlxyXG4gKiBNaWRkbGV3YXJlIGZvciB2YWxpZGF0aW5nIHRoZSBjb250ZW50LXR5cGUgaGVhZGVyLlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gY29udGVudFR5cGVNaWRkbGV3YXJlXHJcbiAqXHJcbiAqIEBwYXJhbSB7RXhwcmVzcy5SZXF1ZXN0fSByZXF1ZXN0IC0gVGhlIEV4cHJlc3MgcmVxdWVzdCBvYmplY3QuXHJcbiAqIEBwYXJhbSB7RXhwcmVzcy5SZXNwb25zZX0gcmVzcG9uc2UgLSBUaGUgRXhwcmVzcyByZXNwb25zZSBvYmplY3QuXHJcbiAqIEBwYXJhbSB7RnVuY3Rpb259IG5leHQgLSBUaGUgbmV4dCBtaWRkbGV3YXJlIGZ1bmN0aW9uLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7dW5kZWZpbmVkfSBUaGUgY2FsbCB0byB0aGUgbmV4dCBtaWRkbGV3YXJlIGZ1bmN0aW9uLlxyXG4gKlxyXG4gKiBAdGhyb3dzIHtFeHBvcnRFcnJvcn0gVGhyb3dzIGFuIGBFeHBvcnRFcnJvcmAgaWYgdGhlIGNvbnRlbnQtdHlwZVxyXG4gKiBpcyBub3QgY29ycmVjdC5cclxuICovXHJcbmZ1bmN0aW9uIGNvbnRlbnRUeXBlTWlkZGxld2FyZShyZXF1ZXN0LCByZXNwb25zZSwgbmV4dCkge1xyXG4gIHRyeSB7XHJcbiAgICAvLyBHZXQgdGhlIGNvbnRlbnQgdHlwZSBoZWFkZXJcclxuICAgIGNvbnN0IGNvbnRlbnRUeXBlID0gcmVxdWVzdC5oZWFkZXJzWydjb250ZW50LXR5cGUnXSB8fCAnJztcclxuXHJcbiAgICAvLyBBbGxvdyBvbmx5IEpTT04sIFVSTC1lbmNvZGVkIGFuZCBmb3JtIGRhdGEgd2l0aG91dCBmaWxlcyB0eXBlcyBvZiBkYXRhXHJcbiAgICBpZiAoXHJcbiAgICAgICFjb250ZW50VHlwZS5pbmNsdWRlcygnYXBwbGljYXRpb24vanNvbicpICYmXHJcbiAgICAgICFjb250ZW50VHlwZS5pbmNsdWRlcygnYXBwbGljYXRpb24veC13d3ctZm9ybS11cmxlbmNvZGVkJykgJiZcclxuICAgICAgIWNvbnRlbnRUeXBlLmluY2x1ZGVzKCdtdWx0aXBhcnQvZm9ybS1kYXRhJylcclxuICAgICkge1xyXG4gICAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoXHJcbiAgICAgICAgJ1t2YWxpZGF0aW9uXSBDb250ZW50LVR5cGUgbXVzdCBiZSBhcHBsaWNhdGlvbi9qc29uLCBhcHBsaWNhdGlvbi94LXd3dy1mb3JtLXVybGVuY29kZWQsIG9yIG11bHRpcGFydC9mb3JtLWRhdGEuJyxcclxuICAgICAgICA0MTVcclxuICAgICAgKTtcclxuICAgIH1cclxuXHJcbiAgICAvLyBDYWxsIHRoZSBgcmVxdWVzdEJvZHlNaWRkbGV3YXJlYCBtaWRkbGV3YXJlXHJcbiAgICByZXR1cm4gbmV4dCgpO1xyXG4gIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICByZXR1cm4gbmV4dChlcnJvcik7XHJcbiAgfVxyXG59XHJcblxyXG4vKipcclxuICogTWlkZGxld2FyZSBmb3IgdmFsaWRhdGluZyB0aGUgcmVxdWVzdCdzIGJvZHkuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiByZXF1ZXN0Qm9keU1pZGRsZXdhcmVcclxuICpcclxuICogQHBhcmFtIHtFeHByZXNzLlJlcXVlc3R9IHJlcXVlc3QgLSBUaGUgRXhwcmVzcyByZXF1ZXN0IG9iamVjdC5cclxuICogQHBhcmFtIHtFeHByZXNzLlJlc3BvbnNlfSByZXNwb25zZSAtIFRoZSBFeHByZXNzIHJlc3BvbnNlIG9iamVjdC5cclxuICogQHBhcmFtIHtGdW5jdGlvbn0gbmV4dCAtIFRoZSBuZXh0IG1pZGRsZXdhcmUgZnVuY3Rpb24uXHJcbiAqXHJcbiAqIEByZXR1cm5zIHt1bmRlZmluZWR9IFRoZSBjYWxsIHRvIHRoZSBuZXh0IG1pZGRsZXdhcmUgZnVuY3Rpb24uXHJcbiAqXHJcbiAqIEB0aHJvd3Mge0V4cG9ydEVycm9yfSBUaHJvd3MgYW4gYEV4cG9ydEVycm9yYCBpZiB0aGUgYm9keSBpcyBub3QgY29ycmVjdC5cclxuICogQHRocm93cyB7RXhwb3J0RXJyb3J9IFRocm93cyBhbiBgRXhwb3J0RXJyb3JgIGlmIHRoZSBjaGFydCBkYXRhIGZyb20gdGhlIGJvZHlcclxuICogaXMgbm90IGNvcnJlY3QuXHJcbiAqIEB0aHJvd3Mge0V4cG9ydEVycm9yfSBUaHJvd3MgYW4gYEV4cG9ydEVycm9yYCBpbiBjYXNlIG9mIHRoZSBwcml2YXRlIHJhbmdlXHJcbiAqIHVybCBlcnJvci5cclxuICovXHJcbmZ1bmN0aW9uIHJlcXVlc3RCb2R5TWlkZGxld2FyZShyZXF1ZXN0LCByZXNwb25zZSwgbmV4dCkge1xyXG4gIHRyeSB7XHJcbiAgICAvLyBHZXQgdGhlIHJlcXVlc3QgYm9keVxyXG4gICAgY29uc3QgYm9keSA9IHJlcXVlc3QuYm9keTtcclxuXHJcbiAgICAvLyBDcmVhdGUgYSB1bmlxdWUgSUQgZm9yIGEgcmVxdWVzdFxyXG4gICAgY29uc3QgcmVxdWVzdElkID0gdXVpZCgpO1xyXG5cclxuICAgIC8vIFRocm93IGFuIGVycm9yIGlmIHRoZXJlIGlzIG5vIGNvcnJlY3QgYm9keVxyXG4gICAgaWYgKCFib2R5IHx8IGlzT2JqZWN0RW1wdHkoYm9keSkpIHtcclxuICAgICAgbG9nKFxyXG4gICAgICAgIDIsXHJcbiAgICAgICAgYFt2YWxpZGF0aW9uXSBSZXF1ZXN0IFske3JlcXVlc3RJZH1dIC0gVGhlIHJlcXVlc3QgZnJvbSAke1xyXG4gICAgICAgICAgcmVxdWVzdC5oZWFkZXJzWyd4LWZvcndhcmRlZC1mb3InXSB8fCByZXF1ZXN0LmNvbm5lY3Rpb24ucmVtb3RlQWRkcmVzc1xyXG4gICAgICAgIH0gd2FzIGluY29ycmVjdC4gUmVjZWl2ZWQgcGF5bG9hZCBpcyBlbXB0eS5gXHJcbiAgICAgICk7XHJcblxyXG4gICAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoXHJcbiAgICAgICAgYFt2YWxpZGF0aW9uXSBSZXF1ZXN0IFske3JlcXVlc3RJZH1dIC0gVGhlIHJlcXVlc3QgYm9keSBpcyByZXF1aXJlZC4gUGxlYXNlIGVuc3VyZSB0aGF0IHlvdXIgQ29udGVudC1UeXBlIGhlYWRlciBpcyBjb3JyZWN0LiBBY2NlcHRlZCB0eXBlcyBhcmUgJ2FwcGxpY2F0aW9uL2pzb24nIGFuZCAnbXVsdGlwYXJ0L2Zvcm0tZGF0YScuYCxcclxuICAgICAgICA0MDBcclxuICAgICAgKTtcclxuICAgIH1cclxuXHJcbiAgICAvLyBHZXQgdGhlIGBhbGxvd0NvZGVFeGVjdXRpb25gIG9wdGlvbiBmb3IgdGhlIHNlcnZlclxyXG4gICAgY29uc3QgYWxsb3dDb2RlRXhlY3V0aW9uID0gZ2V0QWxsb3dDb2RlRXhlY3V0aW9uKCk7XHJcblxyXG4gICAgLy8gRmluZCBhIGNvcnJlY3QgY2hhcnQgb3B0aW9uc1xyXG4gICAgY29uc3QgaW5zdHIgPSBpc0FsbG93ZWRDb25maWcoXHJcbiAgICAgIC8vIFVzZSBvbmUgb2YgdGhlIGJlbG93XHJcbiAgICAgIGJvZHkuaW5zdHIgfHwgYm9keS5vcHRpb25zIHx8IGJvZHkuaW5maWxlIHx8IGJvZHkuZGF0YSxcclxuICAgICAgLy8gU3RyaW5naWZ5IG9wdGlvbnNcclxuICAgICAgdHJ1ZSxcclxuICAgICAgLy8gQWxsb3cgb3IgZGlzYWxsb3cgZnVuY3Rpb25zXHJcbiAgICAgIGFsbG93Q29kZUV4ZWN1dGlvblxyXG4gICAgKTtcclxuXHJcbiAgICAvLyBUaHJvdyBhbiBlcnJvciBpZiB0aGVyZSBpcyBubyBjb3JyZWN0IGNoYXJ0IGRhdGFcclxuICAgIGlmIChpbnN0ciA9PT0gbnVsbCAmJiAhYm9keS5zdmcpIHtcclxuICAgICAgbG9nKFxyXG4gICAgICAgIDIsXHJcbiAgICAgICAgYFt2YWxpZGF0aW9uXSBSZXF1ZXN0IFske3JlcXVlc3RJZH1dIC0gVGhlIHJlcXVlc3QgZnJvbSAke1xyXG4gICAgICAgICAgcmVxdWVzdC5oZWFkZXJzWyd4LWZvcndhcmRlZC1mb3InXSB8fCByZXF1ZXN0LmNvbm5lY3Rpb24ucmVtb3RlQWRkcmVzc1xyXG4gICAgICAgIH0gd2FzIGluY29ycmVjdC4gUmVjZWl2ZWQgcGF5bG9hZCBpcyBtaXNzaW5nIGNvcnJlY3QgY2hhcnQgZGF0YSBmb3IgZXhwb3J0OiAke0pTT04uc3RyaW5naWZ5KGJvZHkpfS5gXHJcbiAgICAgICk7XHJcblxyXG4gICAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoXHJcbiAgICAgICAgYFJlcXVlc3QgWyR7cmVxdWVzdElkfV0gLSBbdmFsaWRhdGlvbl0gTm8gY29ycmVjdCBjaGFydCBkYXRhIGZvdW5kLiBFbnN1cmUgdGhhdCB5b3UgYXJlIHVzaW5nIGVpdGhlciBhcHBsaWNhdGlvbi9qc29uIG9yIG11bHRpcGFydC9mb3JtLWRhdGEgaGVhZGVycy4gSWYgc2VuZGluZyBKU09OLCBtYWtlIHN1cmUgdGhlIGNoYXJ0IGRhdGEgaXMgaW4gdGhlICdpbmZpbGUnLCAnb3B0aW9ucycsIG9yICdkYXRhJyBhdHRyaWJ1dGUuIElmIHNlbmRpbmcgU1ZHLCBlbnN1cmUgaXQgaXMgaW4gdGhlICdzdmcnIGF0dHJpYnV0ZS5gLFxyXG4gICAgICAgIDQwMFxyXG4gICAgICApO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIFRocm93IGFuIGVycm9yIGlmIHRlc3Qgb2YgeGxpbms6aHJlZiBlbGVtZW50cyBmcm9tIHBheWxvYWQncyBTVkcgZmFpbHNcclxuICAgIGlmIChib2R5LnN2ZyAmJiBpc1ByaXZhdGVSYW5nZVVybEZvdW5kKGJvZHkuc3ZnKSkge1xyXG4gICAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoXHJcbiAgICAgICAgYFJlcXVlc3QgWyR7cmVxdWVzdElkfV0gLSBbdmFsaWRhdGlvbl0gU1ZHIHBvdGVudGlhbGx5IGNvbnRhaW4gYXQgbGVhc3Qgb25lIGZvcmJpZGRlbiBVUkwgaW4gJ3hsaW5rOmhyZWYnIGVsZW1lbnQuIFBsZWFzZSByZXZpZXcgdGhlIFNWRyBjb250ZW50IGFuZCBlbnN1cmUgdGhhdCBhbGwgcmVmZXJlbmNlZCBVUkxzIGNvbXBseSB3aXRoIHNlY3VyaXR5IHBvbGljaWVzLmAsXHJcbiAgICAgICAgNDAwXHJcbiAgICAgICk7XHJcbiAgICB9XHJcblxyXG4gICAgdHJ5IHtcclxuICAgICAgLy8gVmFsaWRhdGUgb3B0aW9ucyBmcm9tIHRoZSBib2R5IGFuZCBzdG9yZSBwYXJzZWQgc3RydWN0dXJlIGluIHRoZSByZXF1ZXN0XHJcbiAgICAgIHJlcXVlc3QudmFsaWRhdGVkT3B0aW9ucyA9IGxvb3NlVmFsaWRhdGUoe1xyXG4gICAgICAgIC8vIFNldCB0aGUgY3JlYXRlZCBJRCBhcyBhIGBfcmVxdWVzdElkYCBwcm9wZXJ0eSBpbiB0aGUgdmFsaWRhdGVkIG9wdGlvbnNcclxuICAgICAgICBfcmVxdWVzdElkOiByZXF1ZXN0SWQsXHJcbiAgICAgICAgZXhwb3J0OiB7XHJcbiAgICAgICAgICBpbnN0cixcclxuICAgICAgICAgIHN2ZzogYm9keS5zdmcsXHJcbiAgICAgICAgICBvdXRmaWxlOlxyXG4gICAgICAgICAgICBib2R5Lm91dGZpbGUgfHxcclxuICAgICAgICAgICAgYCR7cmVxdWVzdC5wYXJhbXMuZmlsZW5hbWUgfHwgJ2NoYXJ0J30uJHtmaXhUeXBlKGJvZHkudHlwZSl9YCxcclxuICAgICAgICAgIHR5cGU6IGZpeFR5cGUoYm9keS50eXBlLCBib2R5Lm91dGZpbGUpLFxyXG4gICAgICAgICAgY29uc3RyOiBmaXhDb25zdHIoYm9keS5jb25zdHIpLFxyXG4gICAgICAgICAgYjY0OiBib2R5LmI2NCxcclxuICAgICAgICAgIG5vRG93bmxvYWQ6IGJvZHkubm9Eb3dubG9hZCxcclxuICAgICAgICAgIGhlaWdodDogYm9keS5oZWlnaHQsXHJcbiAgICAgICAgICB3aWR0aDogYm9keS53aWR0aCxcclxuICAgICAgICAgIHNjYWxlOiBib2R5LnNjYWxlLFxyXG4gICAgICAgICAgZ2xvYmFsT3B0aW9uczogaXNBbGxvd2VkQ29uZmlnKFxyXG4gICAgICAgICAgICBib2R5Lmdsb2JhbE9wdGlvbnMsXHJcbiAgICAgICAgICAgIHRydWUsXHJcbiAgICAgICAgICAgIGFsbG93Q29kZUV4ZWN1dGlvblxyXG4gICAgICAgICAgKSxcclxuICAgICAgICAgIHRoZW1lT3B0aW9uczogaXNBbGxvd2VkQ29uZmlnKFxyXG4gICAgICAgICAgICBib2R5LnRoZW1lT3B0aW9ucyxcclxuICAgICAgICAgICAgdHJ1ZSxcclxuICAgICAgICAgICAgYWxsb3dDb2RlRXhlY3V0aW9uXHJcbiAgICAgICAgICApXHJcbiAgICAgICAgfSxcclxuICAgICAgICBjdXN0b21Mb2dpYzoge1xyXG4gICAgICAgICAgYWxsb3dDb2RlRXhlY3V0aW9uLFxyXG4gICAgICAgICAgYWxsb3dGaWxlUmVzb3VyY2VzOiBmYWxzZSxcclxuICAgICAgICAgIGN1c3RvbUNvZGU6IGJvZHkuY3VzdG9tQ29kZSxcclxuICAgICAgICAgIGNhbGxiYWNrOiBib2R5LmNhbGxiYWNrLFxyXG4gICAgICAgICAgcmVzb3VyY2VzOiBpc0FsbG93ZWRDb25maWcoYm9keS5yZXNvdXJjZXMsIHRydWUsIGFsbG93Q29kZUV4ZWN1dGlvbilcclxuICAgICAgICB9XHJcbiAgICAgIH0pO1xyXG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICAgbG9nWm9kSXNzdWVzKFxyXG4gICAgICAgIDEsXHJcbiAgICAgICAgZXJyb3IuaXNzdWVzLFxyXG4gICAgICAgICdbY29uZmlnXSBSZXF1ZXN0IG9wdGlvbnMgdmFsaWRhdGlvbiBlcnJvcidcclxuICAgICAgKTtcclxuXHJcbiAgICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcihcclxuICAgICAgICAnVGhlIHByb3ZpZGVkIG9wdGlvbnMgYXJlIG5vdCBjb3JyZWN0LiBQbGVhc2UgY2hlY2sgaWYgeW91ciBkYXRhIGlzIG9mIHRoZSBjb3JyZWN0IHR5cGVzLicsXHJcbiAgICAgICAgNDAwXHJcbiAgICAgICk7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gQ2FsbCB0aGUgbmV4dCBtaWRkbGV3YXJlXHJcbiAgICByZXR1cm4gbmV4dCgpO1xyXG4gIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICByZXR1cm4gbmV4dChlcnJvcik7XHJcbiAgfVxyXG59XHJcblxyXG4vKipcclxuICogQWRkcyB0aGUgdmFsaWRhdGlvbiBtaWRkbGV3YXJlcyB0byB0aGUgcGFzc2VkIGV4cHJlc3MgYXBwIGluc3RhbmNlLlxyXG4gKlxyXG4gKiBAcGFyYW0ge0V4cHJlc3N9IGFwcCAtIFRoZSBFeHByZXNzIGFwcCBpbnN0YW5jZS5cclxuICovXHJcbmV4cG9ydCBkZWZhdWx0IGZ1bmN0aW9uIHZhbGlkYXRpb25NaWRkbGV3YXJlKGFwcCkge1xyXG4gIC8vIEFkZCBjb250ZW50IHR5cGUgdmFsaWRhdGlvbiBtaWRkbGV3YXJlXHJcbiAgYXBwLnBvc3QoWycvJywgJy86ZmlsZW5hbWUnXSwgY29udGVudFR5cGVNaWRkbGV3YXJlKTtcclxuXHJcbiAgLy8gQWRkIHJlcXVlc3QgYm9keSByZXF1ZXN0IHZhbGlkYXRpb24gbWlkZGxld2FyZVxyXG4gIGFwcC5wb3N0KFsnLycsICcvOmZpbGVuYW1lJ10sIHJlcXVlc3RCb2R5TWlkZGxld2FyZSk7XHJcbn1cclxuIiwiLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcclxuXHJcbkhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlclxyXG5cclxuQ29weXJpZ2h0IChjKSAyMDE2LTIwMjUsIEhpZ2hzb2Z0XHJcblxyXG5MaWNlbmNlZCB1bmRlciB0aGUgTUlUIGxpY2VuY2UuXHJcblxyXG5BZGRpdGlvbmFsbHkgYSB2YWxpZCBIaWdoY2hhcnRzIGxpY2Vuc2UgaXMgcmVxdWlyZWQgZm9yIHVzZS5cclxuXHJcblNlZSBMSUNFTlNFIGZpbGUgaW4gcm9vdCBmb3IgZGV0YWlscy5cclxuXHJcbioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXHJcblxyXG4vKipcclxuICogQG92ZXJ2aWV3IERlZmluZXMgdGhlIGV4cG9ydCByb3V0ZXMgYW5kIGxvZ2ljIGZvciBoYW5kbGluZyBjaGFydCBleHBvcnRcclxuICogcmVxdWVzdHMgaW4gYW4gRXhwcmVzcyBzZXJ2ZXIuIFRoaXMgbW9kdWxlIHByb2Nlc3NlcyBpbmNvbWluZyByZXF1ZXN0c1xyXG4gKiB0byBleHBvcnQgY2hhcnRzIGluIHZhcmlvdXMgZm9ybWF0cyAoZS5nLiBKUEVHLCBQTkcsIFBERiwgU1ZHKS4gSXQgaW50ZWdyYXRlc1xyXG4gKiB3aXRoIEhpZ2hjaGFydHMnIGNvcmUgZnVuY3Rpb25hbGl0aWVzIGFuZCBzdXBwb3J0cyBib3RoIGltbWVkaWF0ZSBkb3dubG9hZFxyXG4gKiByZXNwb25zZXMgYW5kIEJhc2U2NC1lbmNvZGVkIGNvbnRlbnQgcmV0dXJucy4gVGhlIGNvZGUgYWxzbyBmZWF0dXJlc1xyXG4gKiBiZW5jaG1hcmtpbmcgZm9yIHBlcmZvcm1hbmNlIG1vbml0b3JpbmcuXHJcbiAqL1xyXG5cclxuaW1wb3J0IHsgc3RhcnRFeHBvcnQgfSBmcm9tICcuLi8uLi9jaGFydC5qcyc7XHJcbmltcG9ydCB7IGxvZyB9IGZyb20gJy4uLy4uL2xvZ2dlci5qcyc7XHJcbmltcG9ydCB7IGdldEJhc2U2NCwgbWVhc3VyZVRpbWUgfSBmcm9tICcuLi8uLi91dGlscy5qcyc7XHJcblxyXG5pbXBvcnQgRXhwb3J0RXJyb3IgZnJvbSAnLi4vLi4vZXJyb3JzL0V4cG9ydEVycm9yLmpzJztcclxuXHJcbi8vIFJldmVyc2VkIE1JTUUgdHlwZXNcclxuY29uc3QgcmV2ZXJzZWRNaW1lID0ge1xyXG4gIHBuZzogJ2ltYWdlL3BuZycsXHJcbiAganBlZzogJ2ltYWdlL2pwZWcnLFxyXG4gIGdpZjogJ2ltYWdlL2dpZicsXHJcbiAgcGRmOiAnYXBwbGljYXRpb24vcGRmJyxcclxuICBzdmc6ICdpbWFnZS9zdmcreG1sJ1xyXG59O1xyXG5cclxuLyoqXHJcbiAqIEhhbmRsZXMgdGhlIGV4cG9ydCByZXF1ZXN0cyBmcm9tIHRoZSBjbGllbnQuXHJcbiAqXHJcbiAqIEBhc3luY1xyXG4gKiBAZnVuY3Rpb24gcmVxdWVzdEV4cG9ydFxyXG4gKlxyXG4gKiBAcGFyYW0ge0V4cHJlc3MuUmVxdWVzdH0gcmVxdWVzdCAtIFRoZSBFeHByZXNzIHJlcXVlc3Qgb2JqZWN0LlxyXG4gKiBAcGFyYW0ge0V4cHJlc3MuUmVzcG9uc2V9IHJlc3BvbnNlIC0gVGhlIEV4cHJlc3MgcmVzcG9uc2Ugb2JqZWN0LlxyXG4gKiBAcGFyYW0ge0Z1bmN0aW9ufSBuZXh0IC0gVGhlIG5leHQgbWlkZGxld2FyZSBmdW5jdGlvbi5cclxuICpcclxuICogQHJldHVybnMge1Byb21pc2U8dm9pZD59IEEgUHJvbWlzZSB0aGF0IHJlc29sdmVzIG9uY2UgdGhlIGV4cG9ydCBwcm9jZXNzXHJcbiAqIGlzIGNvbXBsZXRlLlxyXG4gKi9cclxuYXN5bmMgZnVuY3Rpb24gcmVxdWVzdEV4cG9ydChyZXF1ZXN0LCByZXNwb25zZSwgbmV4dCkge1xyXG4gIHRyeSB7XHJcbiAgICAvLyBTdGFydCBjb3VudGluZyB0aW1lIGZvciBhIHJlcXVlc3RcclxuICAgIGNvbnN0IHJlcXVlc3RDb3VudGVyID0gbWVhc3VyZVRpbWUoKTtcclxuXHJcbiAgICAvLyBJbiBjYXNlIHRoZSBjb25uZWN0aW9uIGlzIGNsb3NlZCwgZm9yY2UgdG8gYWJvcnQgZnVydGhlciBhY3Rpb25zXHJcbiAgICBsZXQgY29ubmVjdGlvbkFib3J0ZWQgPSBmYWxzZTtcclxuICAgIHJlcXVlc3Quc29ja2V0Lm9uKCdjbG9zZScsIChoYWRFcnJvcnMpID0+IHtcclxuICAgICAgaWYgKGhhZEVycm9ycykge1xyXG4gICAgICAgIGNvbm5lY3Rpb25BYm9ydGVkID0gdHJ1ZTtcclxuICAgICAgfVxyXG4gICAgfSk7XHJcblxyXG4gICAgLy8gR2V0IHRoZSBvcHRpb25zIHByZXZpb3VzbHkgdmFsaWRhdGVkIGluIHRoZSB2YWxpZGF0aW9uIG1pZGRsZXdhcmVcclxuICAgIGNvbnN0IHJlcXVlc3RPcHRpb25zID0gcmVxdWVzdC52YWxpZGF0ZWRPcHRpb25zO1xyXG5cclxuICAgIC8vIEdldCB0aGUgcmVxdWVzdCBpZFxyXG4gICAgY29uc3QgcmVxdWVzdElkID0gcmVxdWVzdE9wdGlvbnMucmVxdWVzdElkO1xyXG5cclxuICAgIC8vIEluZm8gYWJvdXQgYW4gaW5jb21pbmcgcmVxdWVzdCB3aXRoIGNvcnJlY3QgZGF0YVxyXG4gICAgbG9nKDQsIGBbZXhwb3J0XSBSZXF1ZXN0IFske3JlcXVlc3RJZH1dIC0gR290IGFuIGluY29taW5nIEhUVFAgcmVxdWVzdC5gKTtcclxuXHJcbiAgICAvLyBTdGFydCB0aGUgZXhwb3J0IHByb2Nlc3NcclxuICAgIGF3YWl0IHN0YXJ0RXhwb3J0KHJlcXVlc3RPcHRpb25zLCAoZXJyb3IsIGRhdGEpID0+IHtcclxuICAgICAgLy8gUmVtb3ZlIHRoZSBjbG9zZSBldmVudCBmcm9tIHRoZSBzb2NrZXRcclxuICAgICAgcmVxdWVzdC5zb2NrZXQucmVtb3ZlQWxsTGlzdGVuZXJzKCdjbG9zZScpO1xyXG5cclxuICAgICAgLy8gSWYgdGhlIGNvbm5lY3Rpb24gd2FzIGNsb3NlZCwgZG8gbm90aGluZ1xyXG4gICAgICBpZiAoY29ubmVjdGlvbkFib3J0ZWQpIHtcclxuICAgICAgICBsb2coXHJcbiAgICAgICAgICAzLFxyXG4gICAgICAgICAgYFtleHBvcnRdIFJlcXVlc3QgWyR7cmVxdWVzdElkfV0gLSBUaGUgY2xpZW50IGNsb3NlZCB0aGUgY29ubmVjdGlvbiBiZWZvcmUgdGhlIGNoYXJ0IGZpbmlzaGVkIHByb2Nlc3NpbmcuYFxyXG4gICAgICAgICk7XHJcbiAgICAgICAgcmV0dXJuO1xyXG4gICAgICB9XHJcblxyXG4gICAgICAvLyBJZiBlcnJvciwgbG9nIGl0IGFuZCBzZW5kIGl0IHRvIHRoZSBlcnJvciBtaWRkbGV3YXJlXHJcbiAgICAgIGlmIChlcnJvcikge1xyXG4gICAgICAgIHRocm93IGVycm9yO1xyXG4gICAgICB9XHJcblxyXG4gICAgICAvLyBJZiBkYXRhIGlzIG1pc3NpbmcsIGxvZyB0aGUgbWVzc2FnZSBhbmQgc2VuZCBpdCB0byB0aGUgZXJyb3IgbWlkZGxld2FyZVxyXG4gICAgICBpZiAoIWRhdGEgfHwgIWRhdGEucmVzdWx0KSB7XHJcbiAgICAgICAgbG9nKFxyXG4gICAgICAgICAgMixcclxuICAgICAgICAgIGBbZXhwb3J0XSBSZXF1ZXN0IFske3JlcXVlc3RJZH1dIC0gUmVxdWVzdCBmcm9tICR7XHJcbiAgICAgICAgICAgIHJlcXVlc3QuaGVhZGVyc1sneC1mb3J3YXJkZWQtZm9yJ10gfHxcclxuICAgICAgICAgICAgcmVxdWVzdC5jb25uZWN0aW9uLnJlbW90ZUFkZHJlc3NcclxuICAgICAgICAgIH0gd2FzIGluY29ycmVjdC4gUmVjZWl2ZWQgcmVzdWx0IGlzICR7ZGF0YS5yZXN1bHR9LmBcclxuICAgICAgICApO1xyXG5cclxuICAgICAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoXHJcbiAgICAgICAgICBgW2V4cG9ydF0gUmVxdWVzdCBbJHtyZXF1ZXN0SWR9XSAtIFVuZXhwZWN0ZWQgcmV0dXJuIG9mIHRoZSBleHBvcnQgcmVzdWx0IGZyb20gdGhlIGNoYXJ0IGdlbmVyYXRpb24uIFBsZWFzZSBjaGVjayB5b3VyIHJlcXVlc3QgZGF0YS5gLFxyXG4gICAgICAgICAgNDAwXHJcbiAgICAgICAgKTtcclxuICAgICAgfVxyXG5cclxuICAgICAgLy8gUmV0dXJuIHRoZSByZXN1bHQgaW4gYW4gYXBwcm9wcmlhdGUgZm9ybWF0XHJcbiAgICAgIGlmIChkYXRhLnJlc3VsdCkge1xyXG4gICAgICAgIGxvZyhcclxuICAgICAgICAgIDMsXHJcbiAgICAgICAgICBgW2V4cG9ydF0gUmVxdWVzdCBbJHtyZXF1ZXN0SWR9XSAtIFRoZSB3aG9sZSBleHBvcnRpbmcgcHJvY2VzcyB0b29rICR7cmVxdWVzdENvdW50ZXIoKX1tcy5gXHJcbiAgICAgICAgKTtcclxuXHJcbiAgICAgICAgLy8gR2V0IHRoZSBgdHlwZWAsIGBiNjRgLCBgbm9Eb3dubG9hZGAsIGFuZCBgb3V0ZmlsZWAgZnJvbSBvcHRpb25zXHJcbiAgICAgICAgY29uc3QgeyB0eXBlLCBiNjQsIG5vRG93bmxvYWQsIG91dGZpbGUgfSA9IGRhdGEub3B0aW9ucy5leHBvcnQ7XHJcblxyXG4gICAgICAgIC8vIElmIG9ubHkgQmFzZTY0IGlzIHJlcXVpcmVkLCByZXR1cm4gaXRcclxuICAgICAgICBpZiAoYjY0KSB7XHJcbiAgICAgICAgICByZXR1cm4gcmVzcG9uc2Uuc2VuZChnZXRCYXNlNjQoZGF0YS5yZXN1bHQsIHR5cGUpKTtcclxuICAgICAgICB9XHJcblxyXG4gICAgICAgIC8vIFNldCBjb3JyZWN0IGNvbnRlbnQgdHlwZVxyXG4gICAgICAgIHJlc3BvbnNlLmhlYWRlcignQ29udGVudC1UeXBlJywgcmV2ZXJzZWRNaW1lW3R5cGVdIHx8ICdpbWFnZS9wbmcnKTtcclxuXHJcbiAgICAgICAgLy8gRGVjaWRlIHdoZXRoZXIgdG8gZG93bmxvYWQgb3Igbm90IGNoYXJ0IGZpbGVcclxuICAgICAgICBpZiAoIW5vRG93bmxvYWQpIHtcclxuICAgICAgICAgIHJlc3BvbnNlLmF0dGFjaG1lbnQob3V0ZmlsZSk7XHJcbiAgICAgICAgfVxyXG5cclxuICAgICAgICAvLyBJZiBTVkcsIHJldHVybiBwbGFpbiBjb250ZW50LCBvdGhlcndpc2UgYSBiNjQgc3RyaW5nIGZyb20gYSBidWZmZXJcclxuICAgICAgICByZXR1cm4gdHlwZSA9PT0gJ3N2ZydcclxuICAgICAgICAgID8gcmVzcG9uc2Uuc2VuZChkYXRhLnJlc3VsdClcclxuICAgICAgICAgIDogcmVzcG9uc2Uuc2VuZChCdWZmZXIuZnJvbShkYXRhLnJlc3VsdCwgJ2Jhc2U2NCcpKTtcclxuICAgICAgfVxyXG4gICAgfSk7XHJcbiAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgIHJldHVybiBuZXh0KGVycm9yKTtcclxuICB9XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBBZGRzIHRoZSBgZXhwb3J0YCByb3V0ZXMuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBleHBvcnRSb3V0ZXNcclxuICpcclxuICogQHBhcmFtIHtFeHByZXNzfSBhcHAgLSBUaGUgRXhwcmVzcyBhcHAgaW5zdGFuY2UuXHJcbiAqL1xyXG5leHBvcnQgZGVmYXVsdCBmdW5jdGlvbiBleHBvcnRSb3V0ZXMoYXBwKSB7XHJcbiAgLyoqXHJcbiAgICogQWRkcyB0aGUgUE9TVCAnLycgLSBBIHJvdXRlIGZvciBoYW5kbGluZyBQT1NUIHJlcXVlc3RzIGF0IHRoZSByb290XHJcbiAgICogZW5kcG9pbnQuXHJcbiAgICovXHJcbiAgYXBwLnBvc3QoJy8nLCByZXF1ZXN0RXhwb3J0KTtcclxuXHJcbiAgLyoqXHJcbiAgICogQWRkcyB0aGUgUE9TVCAnLzpmaWxlbmFtZScgLSBBIHJvdXRlIGZvciBoYW5kbGluZyBQT1NUIHJlcXVlc3RzIHdpdGhcclxuICAgKiBhIHNwZWNpZmllZCBmaWxlbmFtZSBwYXJhbWV0ZXIuXHJcbiAgICovXHJcbiAgYXBwLnBvc3QoJy86ZmlsZW5hbWUnLCByZXF1ZXN0RXhwb3J0KTtcclxufVxyXG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxyXG5cclxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXHJcblxyXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNSwgSGlnaHNvZnRcclxuXHJcbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cclxuXHJcbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxyXG5cclxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxyXG5cclxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cclxuXHJcbi8qKlxyXG4gKiBAb3ZlcnZpZXcgRGVmaW5lcyBhbiBFeHByZXNzIHJvdXRlIGZvciBzZXJ2ZXIgaGVhbHRoIG1vbml0b3JpbmcsIGluY2x1ZGluZ1xyXG4gKiB1cHRpbWUsIHN1Y2Nlc3MgcmF0ZXMsIGFuZCBvdGhlciBzZXJ2ZXIgc3RhdGlzdGljcy5cclxuICovXHJcblxyXG5pbXBvcnQgeyByZWFkRmlsZVN5bmMgfSBmcm9tICdmcyc7XHJcbmltcG9ydCB7IGpvaW4gfSBmcm9tICdwYXRoJztcclxuXHJcbmltcG9ydCB7IGdldEhpZ2hjaGFydHNWZXJzaW9uIH0gZnJvbSAnLi4vLi4vY2FjaGUuanMnO1xyXG5pbXBvcnQgeyBsb2cgfSBmcm9tICcuLi8uLi9sb2dnZXIuanMnO1xyXG5pbXBvcnQgeyBnZXRQb29sU3RhdHMsIGdldFBvb2xJbmZvSlNPTiB9IGZyb20gJy4uLy4uL3Bvb2wuanMnO1xyXG5pbXBvcnQgeyBhZGRUaW1lciB9IGZyb20gJy4uLy4uL3RpbWVyLmpzJztcclxuaW1wb3J0IHsgX19kaXJuYW1lLCBnZXROZXdEYXRlVGltZSB9IGZyb20gJy4uLy4uL3V0aWxzLmpzJztcclxuXHJcbi8vIFNldCB0aGUgc3RhcnQgZGF0ZSBvZiB0aGUgc2VydmVyXHJcbmNvbnN0IHNlcnZlclN0YXJ0VGltZSA9IG5ldyBEYXRlKCk7XHJcblxyXG4vLyBHZXQgdGhlIGBwYWNrYWdlLmpzb25gIGNvbnRlbnRcclxuY29uc3QgcGFja2FnZUZpbGUgPSBKU09OLnBhcnNlKFxyXG4gIHJlYWRGaWxlU3luYyhqb2luKF9fZGlybmFtZSwgJ3BhY2thZ2UuanNvbicpLCAndXRmOCcpXHJcbik7XHJcblxyXG4vLyBBbiBhcnJheSBmb3Igc3VjY2VzcyByYXRlIHJhdGlvc1xyXG5jb25zdCBzdWNjZXNzUmF0ZXMgPSBbXTtcclxuXHJcbi8vIFJlY29yZCBldmVyeSBtaW51dGVcclxuY29uc3QgcmVjb3JkSW50ZXJ2YWwgPSA2MCAqIDEwMDA7XHJcblxyXG4vLyAzMCBtaW51dGVzXHJcbmNvbnN0IHdpbmRvd1NpemUgPSAzMDtcclxuXHJcbi8qKlxyXG4gKiBDYWxjdWxhdGVzIG1vdmluZyBhdmVyYWdlIGluZGljYXRvciBiYXNlZCBvbiB0aGUgZGF0YSBmcm9tIHRoZSBgc3VjY2Vzc1JhdGVzYFxyXG4gKiBhcnJheS5cclxuICpcclxuICogQGZ1bmN0aW9uIF9jYWxjdWxhdGVNb3ZpbmdBdmVyYWdlXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtudW1iZXJ9IEEgbW92aW5nIGF2ZXJhZ2UgZm9yIHN1Y2Nlc3MgcmF0aW8gb2YgdGhlIHNlcnZlciBleHBvcnRzLlxyXG4gKi9cclxuZnVuY3Rpb24gX2NhbGN1bGF0ZU1vdmluZ0F2ZXJhZ2UoKSB7XHJcbiAgcmV0dXJuIHN1Y2Nlc3NSYXRlcy5yZWR1Y2UoKGEsIGIpID0+IGEgKyBiLCAwKSAvIHN1Y2Nlc3NSYXRlcy5sZW5ndGg7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBTdGFydHMgdGhlIGludGVydmFsIHJlc3BvbnNpYmxlIGZvciBjYWxjdWxhdGluZyBjdXJyZW50IHN1Y2Nlc3MgcmF0ZSByYXRpb1xyXG4gKiBhbmQgY29sbGVjdHMgcmVjb3JkcyB0byB0aGUgYHN1Y2Nlc3NSYXRlc2AgYXJyYXkuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBfc3RhcnRTdWNjZXNzUmF0ZVxyXG4gKlxyXG4gKiBAcmV0dXJucyB7Tm9kZUpTLlRpbWVvdXR9IElkIG9mIGFuIGludGVydmFsLlxyXG4gKi9cclxuZnVuY3Rpb24gX3N0YXJ0U3VjY2Vzc1JhdGUoKSB7XHJcbiAgcmV0dXJuIHNldEludGVydmFsKCgpID0+IHtcclxuICAgIGNvbnN0IHN0YXRzID0gZ2V0UG9vbFN0YXRzKCk7XHJcbiAgICBjb25zdCBzdWNjZXNzUmF0aW8gPVxyXG4gICAgICBzdGF0cy5leHBvcnRzQXR0ZW1wdGVkID09PSAwXHJcbiAgICAgICAgPyAxXHJcbiAgICAgICAgOiAoc3RhdHMuZXhwb3J0c1BlcmZvcm1lZCAvIHN0YXRzLmV4cG9ydHNBdHRlbXB0ZWQpICogMTAwO1xyXG5cclxuICAgIHN1Y2Nlc3NSYXRlcy5wdXNoKHN1Y2Nlc3NSYXRpbyk7XHJcbiAgICBpZiAoc3VjY2Vzc1JhdGVzLmxlbmd0aCA+IHdpbmRvd1NpemUpIHtcclxuICAgICAgc3VjY2Vzc1JhdGVzLnNoaWZ0KCk7XHJcbiAgICB9XHJcbiAgfSwgcmVjb3JkSW50ZXJ2YWwpO1xyXG59XHJcblxyXG4vKipcclxuICogQWRkcyB0aGUgYGhlYWx0aGAgcm91dGVzLlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gaGVhbHRoUm91dGVzXHJcbiAqXHJcbiAqIEBwYXJhbSB7RXhwcmVzc30gYXBwIC0gVGhlIEV4cHJlc3MgYXBwIGluc3RhbmNlLlxyXG4gKi9cclxuZXhwb3J0IGRlZmF1bHQgZnVuY3Rpb24gaGVhbHRoUm91dGVzKGFwcCkge1xyXG4gIC8vIFN0YXJ0IHByb2Nlc3Npbmcgc3VjY2VzcyByYXRlIHJhdGlvIGludGVydmFsIGFuZCBzYXZlIGl0cyBpZCB0byB0aGUgYXJyYXlcclxuICAvLyBmb3IgdGhlIGdyYWNlZnVsIGNsZWFyaW5nIG9uIHNodXRkb3duIHdpdGggaW5qZWN0ZWQgYGFkZFRpbWVyYCBmdW50aW9uXHJcbiAgYWRkVGltZXIoX3N0YXJ0U3VjY2Vzc1JhdGUoKSk7XHJcblxyXG4gIC8qKlxyXG4gICAqIEFkZHMgdGhlIEdFVCAnL2hlYWx0aCcgLSBBIHJvdXRlIGZvciBnZXR0aW5nIHRoZSBiYXNpYyBzdGF0cyBvZiB0aGUgc2VydmVyLlxyXG4gICAqL1xyXG4gIGFwcC5nZXQoJy9oZWFsdGgnLCAocmVxdWVzdCwgcmVzcG9uc2UsIG5leHQpID0+IHtcclxuICAgIHRyeSB7XHJcbiAgICAgIGxvZyg0LCAnW2hlYWx0aF0gUmV0dXJuaW5nIHNlcnZlciBoZWFsdGguJyk7XHJcblxyXG4gICAgICBjb25zdCBzdGF0cyA9IGdldFBvb2xTdGF0cygpO1xyXG4gICAgICBjb25zdCBwZXJpb2QgPSBzdWNjZXNzUmF0ZXMubGVuZ3RoO1xyXG4gICAgICBjb25zdCBtb3ZpbmdBdmVyYWdlID0gX2NhbGN1bGF0ZU1vdmluZ0F2ZXJhZ2UoKTtcclxuXHJcbiAgICAgIC8vIFNlbmQgdGhlIHNlcnZlcidzIHN0YXRpc3RpY3NcclxuICAgICAgcmVzcG9uc2Uuc2VuZCh7XHJcbiAgICAgICAgLy8gU3RhdHVzIGFuZCB0aW1lc1xyXG4gICAgICAgIHN0YXR1czogJ09LJyxcclxuICAgICAgICBib290VGltZTogc2VydmVyU3RhcnRUaW1lLFxyXG4gICAgICAgIHVwdGltZTogYCR7TWF0aC5mbG9vcigoZ2V0TmV3RGF0ZVRpbWUoKSAtIHNlcnZlclN0YXJ0VGltZS5nZXRUaW1lKCkpIC8gMTAwMCAvIDYwKX0gbWludXRlc2AsXHJcblxyXG4gICAgICAgIC8vIFZlcnNpb25zXHJcbiAgICAgICAgc2VydmVyVmVyc2lvbjogcGFja2FnZUZpbGUudmVyc2lvbixcclxuICAgICAgICBoaWdoY2hhcnRzVmVyc2lvbjogZ2V0SGlnaGNoYXJ0c1ZlcnNpb24oKSxcclxuXHJcbiAgICAgICAgLy8gRXhwb3J0c1xyXG4gICAgICAgIGF2ZXJhZ2VFeHBvcnRUaW1lOiBzdGF0cy50aW1lU3BlbnRBdmVyYWdlLFxyXG4gICAgICAgIGF0dGVtcHRlZEV4cG9ydHM6IHN0YXRzLmV4cG9ydHNBdHRlbXB0ZWQsXHJcbiAgICAgICAgcGVyZm9ybWVkRXhwb3J0czogc3RhdHMuZXhwb3J0c1BlcmZvcm1lZCxcclxuICAgICAgICBmYWlsZWRFeHBvcnRzOiBzdGF0cy5leHBvcnRzRHJvcHBlZCxcclxuICAgICAgICBzdWNlc3NSYXRpbzogKHN0YXRzLmV4cG9ydHNQZXJmb3JtZWQgLyBzdGF0cy5leHBvcnRzQXR0ZW1wdGVkKSAqIDEwMCxcclxuXHJcbiAgICAgICAgLy8gUG9vbFxyXG4gICAgICAgIHBvb2w6IGdldFBvb2xJbmZvSlNPTigpLFxyXG5cclxuICAgICAgICAvLyBNb3ZpbmcgYXZlcmFnZVxyXG4gICAgICAgIHBlcmlvZCxcclxuICAgICAgICBtb3ZpbmdBdmVyYWdlLFxyXG4gICAgICAgIG1lc3NhZ2U6XHJcbiAgICAgICAgICBpc05hTihtb3ZpbmdBdmVyYWdlKSB8fCAhc3VjY2Vzc1JhdGVzLmxlbmd0aFxyXG4gICAgICAgICAgICA/ICdUb28gZWFybHkgdG8gcmVwb3J0LiBObyBleHBvcnRzIG1hZGUgeWV0LiBQbGVhc2UgY2hlY2sgYmFjayBzb29uLidcclxuICAgICAgICAgICAgOiBgTGFzdCAke3BlcmlvZH0gbWludXRlcyBoYWQgYSBzdWNjZXNzIHJhdGUgb2YgJHttb3ZpbmdBdmVyYWdlLnRvRml4ZWQoMil9JS5gLFxyXG5cclxuICAgICAgICAvLyBTVkcgYW5kIEpTT04gZXhwb3J0c1xyXG4gICAgICAgIHN2Z0V4cG9ydHM6IHN0YXRzLmV4cG9ydHNGcm9tU3ZnLFxyXG4gICAgICAgIGpzb25FeHBvcnRzOiBzdGF0cy5leHBvcnRzRnJvbU9wdGlvbnMsXHJcbiAgICAgICAgc3ZnRXhwb3J0c0F0dGVtcHRzOiBzdGF0cy5leHBvcnRzRnJvbVN2Z0F0dGVtcHRzLFxyXG4gICAgICAgIGpzb25FeHBvcnRzQXR0ZW1wdHM6IHN0YXRzLmV4cG9ydHNGcm9tT3B0aW9uc0F0dGVtcHRzXHJcbiAgICAgIH0pO1xyXG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICAgcmV0dXJuIG5leHQoZXJyb3IpO1xyXG4gICAgfVxyXG4gIH0pO1xyXG59XHJcbiIsIi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXHJcblxyXG5IaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXJcclxuXHJcbkNvcHlyaWdodCAoYykgMjAxNi0yMDI1LCBIaWdoc29mdFxyXG5cclxuTGljZW5jZWQgdW5kZXIgdGhlIE1JVCBsaWNlbmNlLlxyXG5cclxuQWRkaXRpb25hbGx5IGEgdmFsaWQgSGlnaGNoYXJ0cyBsaWNlbnNlIGlzIHJlcXVpcmVkIGZvciB1c2UuXHJcblxyXG5TZWUgTElDRU5TRSBmaWxlIGluIHJvb3QgZm9yIGRldGFpbHMuXHJcblxyXG4qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xyXG5cclxuLyoqXHJcbiAqIEBvdmVydmlldyBEZWZpbmVzIGFuIEV4cHJlc3Mgcm91dGUgZm9yIHNlcnZpbmcgdGhlIFVJIGZvciB0aGUgZXhwb3J0IHNlcnZlclxyXG4gKiB3aGVuIGVuYWJsZWQuXHJcbiAqL1xyXG5cclxuaW1wb3J0IHsgam9pbiB9IGZyb20gJ3BhdGgnO1xyXG5cclxuaW1wb3J0IHsgZ2V0T3B0aW9ucyB9IGZyb20gJy4uLy4uL2NvbmZpZy5qcyc7XHJcbmltcG9ydCB7IGxvZyB9IGZyb20gJy4uLy4uL2xvZ2dlci5qcyc7XHJcbmltcG9ydCB7IF9fZGlybmFtZSB9IGZyb20gJy4uLy4uL3V0aWxzLmpzJztcclxuXHJcbi8qKlxyXG4gKiBBZGRzIHRoZSBgdWlgIHJvdXRlcy5cclxuICpcclxuICogQGZ1bmN0aW9uIHVpUm91dGVzXHJcbiAqXHJcbiAqIEBwYXJhbSB7RXhwcmVzc30gYXBwIC0gVGhlIEV4cHJlc3MgYXBwIGluc3RhbmNlLlxyXG4gKi9cclxuZXhwb3J0IGRlZmF1bHQgZnVuY3Rpb24gdWlSb3V0ZXMoYXBwKSB7XHJcbiAgLyoqXHJcbiAgICogQWRkcyB0aGUgR0VUICcvJyAtIEEgcm91dGUgZm9yIGEgVUkgd2hlbiBlbmFibGVkIG9uIHRoZSBleHBvcnQgc2VydmVyLlxyXG4gICAqL1xyXG4gIGFwcC5nZXQoZ2V0T3B0aW9ucygpLnVpLnJvdXRlIHx8ICcvJywgKHJlcXVlc3QsIHJlc3BvbnNlLCBuZXh0KSA9PiB7XHJcbiAgICB0cnkge1xyXG4gICAgICBsb2coNCwgJ1t1aV0gUmV0dXJuaW5nIFVJIGZvciB0aGUgZXhwb3J0LicpO1xyXG5cclxuICAgICAgcmVzcG9uc2Uuc2VuZEZpbGUoam9pbihfX2Rpcm5hbWUsICdwdWJsaWMnLCAnaW5kZXguaHRtbCcpLCB7XHJcbiAgICAgICAgYWNjZXB0UmFuZ2VzOiBmYWxzZVxyXG4gICAgICB9KTtcclxuICAgIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICAgIHJldHVybiBuZXh0KGVycm9yKTtcclxuICAgIH1cclxuICB9KTtcclxufVxyXG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxyXG5cclxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXHJcblxyXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNSwgSGlnaHNvZnRcclxuXHJcbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cclxuXHJcbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxyXG5cclxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxyXG5cclxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cclxuXHJcbi8qKlxyXG4gKiBAb3ZlcnZpZXcgRGVmaW5lcyBhbiBFeHByZXNzIHJvdXRlIGZvciB1cGRhdGluZyB0aGUgSGlnaGNoYXJ0cyB2ZXJzaW9uXHJcbiAqIG9uIHRoZSBzZXJ2ZXIsIHdpdGggYXV0aGVudGljYXRpb24gYW5kIHZhbGlkYXRpb24uXHJcbiAqL1xyXG5cclxuaW1wb3J0IHsgdXBkYXRlSGlnaGNoYXJ0c1ZlcnNpb24sIGdldEhpZ2hjaGFydHNWZXJzaW9uIH0gZnJvbSAnLi4vLi4vY2FjaGUuanMnO1xyXG5pbXBvcnQgeyBsb2cgfSBmcm9tICcuLi8uLi9sb2dnZXIuanMnO1xyXG5pbXBvcnQgeyBlbnZzIH0gZnJvbSAnLi4vLi4vdmFsaWRhdGlvbi5qcyc7XHJcblxyXG5pbXBvcnQgRXhwb3J0RXJyb3IgZnJvbSAnLi4vLi4vZXJyb3JzL0V4cG9ydEVycm9yLmpzJztcclxuXHJcbi8qKlxyXG4gKiBBZGRzIHRoZSBgdmVyc2lvbl9jaGFuZ2VgIHJvdXRlcy5cclxuICpcclxuICogQGZ1bmN0aW9uIHZlcnNpb25DaGFuZ2VSb3V0ZXNcclxuICpcclxuICogQHBhcmFtIHtFeHByZXNzfSBhcHAgLSBUaGUgRXhwcmVzcyBhcHAgaW5zdGFuY2UuXHJcbiAqL1xyXG5leHBvcnQgZGVmYXVsdCBmdW5jdGlvbiB2ZXJzaW9uQ2hhbmdlUm91dGVzKGFwcCkge1xyXG4gIC8qKlxyXG4gICAqIEFkZHMgdGhlIFBPU1QgJy92ZXJzaW9uX2NoYW5nZS86bmV3VmVyc2lvbicgLSBBIHJvdXRlIGZvciBjaGFuZ2luZ1xyXG4gICAqIHRoZSBIaWdoY2hhcnRzIHZlcnNpb24gb24gdGhlIHNlcnZlci5cclxuICAgKi9cclxuICBhcHAucG9zdCgnL3ZlcnNpb25fY2hhbmdlLzpuZXdWZXJzaW9uJywgYXN5bmMgKHJlcXVlc3QsIHJlc3BvbnNlLCBuZXh0KSA9PiB7XHJcbiAgICB0cnkge1xyXG4gICAgICBsb2coNCwgJ1t2ZXJzaW9uXSBDaGFuZ2luZyBIaWdoY2hhcnRzIHZlcnNpb24uJyk7XHJcblxyXG4gICAgICAvLyBHZXQgdGhlIHRva2VuIGRpcmVjdGx5IGZyb20gZW52c1xyXG4gICAgICBjb25zdCBhZG1pblRva2VuID0gZW52cy5ISUdIQ0hBUlRTX0FETUlOX1RPS0VOO1xyXG5cclxuICAgICAgLy8gQ2hlY2sgdGhlIGV4aXN0ZW5jZSBvZiB0aGUgdG9rZW5cclxuICAgICAgaWYgKCFhZG1pblRva2VuIHx8ICFhZG1pblRva2VuLmxlbmd0aCkge1xyXG4gICAgICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcihcclxuICAgICAgICAgICdbdmVyc2lvbl0gVGhlIHNlcnZlciBpcyBub3QgY29uZmlndXJlZCB0byBwZXJmb3JtIHJ1bi10aW1lIHZlcnNpb24gY2hhbmdlczogSElHSENIQVJUU19BRE1JTl9UT0tFTiBpcyBub3Qgc2V0LicsXHJcbiAgICAgICAgICA0MDFcclxuICAgICAgICApO1xyXG4gICAgICB9XHJcblxyXG4gICAgICAvLyBHZXQgdGhlIHRva2VuIGZyb20gdGhlIGhjLWF1dGggaGVhZGVyXHJcbiAgICAgIGNvbnN0IHRva2VuID0gcmVxdWVzdC5nZXQoJ2hjLWF1dGgnKTtcclxuXHJcbiAgICAgIC8vIENoZWNrIGlmIHRoZSBoYy1hdXRoIGhlYWRlciBjb250YWluIGEgY29ycmVjdCB0b2tlblxyXG4gICAgICBpZiAoIXRva2VuIHx8IHRva2VuICE9PSBhZG1pblRva2VuKSB7XHJcbiAgICAgICAgdGhyb3cgbmV3IEV4cG9ydEVycm9yKFxyXG4gICAgICAgICAgJ1t2ZXJzaW9uXSBJbnZhbGlkIG9yIG1pc3NpbmcgdG9rZW46IFNldCB0aGUgdG9rZW4gaW4gdGhlIGhjLWF1dGggaGVhZGVyLicsXHJcbiAgICAgICAgICA0MDFcclxuICAgICAgICApO1xyXG4gICAgICB9XHJcblxyXG4gICAgICAvLyBDb21wYXJlIHZlcnNpb25zXHJcbiAgICAgIGxldCBuZXdWZXJzaW9uID0gcmVxdWVzdC5wYXJhbXMubmV3VmVyc2lvbjtcclxuICAgICAgaWYgKG5ld1ZlcnNpb24pIHtcclxuICAgICAgICB0cnkge1xyXG4gICAgICAgICAgLy8gVXBkYXRlIHZlcnNpb25cclxuICAgICAgICAgIGF3YWl0IHVwZGF0ZUhpZ2hjaGFydHNWZXJzaW9uKG5ld1ZlcnNpb24pO1xyXG4gICAgICAgIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICAgICAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoXHJcbiAgICAgICAgICAgIGBbdmVyc2lvbl0gVmVyc2lvbiBjaGFuZ2U6ICR7ZXJyb3IubWVzc2FnZX1gLFxyXG4gICAgICAgICAgICA0MDBcclxuICAgICAgICAgICkuc2V0RXJyb3IoZXJyb3IpO1xyXG4gICAgICAgIH1cclxuXHJcbiAgICAgICAgLy8gU3VjY2Vzc1xyXG4gICAgICAgIHJlc3BvbnNlLnN0YXR1cygyMDApLnNlbmQoe1xyXG4gICAgICAgICAgc3RhdHVzQ29kZTogMjAwLFxyXG4gICAgICAgICAgaGlnaGNoYXJ0c1ZlcnNpb246IGdldEhpZ2hjaGFydHNWZXJzaW9uKCksXHJcbiAgICAgICAgICBtZXNzYWdlOiBgU3VjY2Vzc2Z1bGx5IHVwZGF0ZWQgSGlnaGNoYXJ0cyB0byB2ZXJzaW9uOiAke25ld1ZlcnNpb259LmBcclxuICAgICAgICB9KTtcclxuICAgICAgfSBlbHNlIHtcclxuICAgICAgICAvLyBObyB2ZXJzaW9uIHNwZWNpZmllZFxyXG4gICAgICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcignW3ZlcnNpb25dIE5vIG5ldyB2ZXJzaW9uIHN1cHBsaWVkLicsIDQwMCk7XHJcbiAgICAgIH1cclxuICAgIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICAgIHJldHVybiBuZXh0KGVycm9yKTtcclxuICAgIH1cclxuICB9KTtcclxufVxyXG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxyXG5cclxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXHJcblxyXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNSwgSGlnaHNvZnRcclxuXHJcbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cclxuXHJcbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxyXG5cclxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxyXG5cclxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cclxuXHJcbi8qKlxyXG4gKiBAb3ZlcnZpZXcgQSBtb2R1bGUgdGhhdCBzZXRzIHVwIGFuZCBtYW5hZ2VzIEhUVFAgYW5kIEhUVFBTIHNlcnZlcnNcclxuICogZm9yIHRoZSBIaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXIuIEl0IGhhbmRsZXMgc2VydmVyIGluaXRpYWxpemF0aW9uLFxyXG4gKiBjb25maWd1cmF0aW9uLCBlcnJvciBoYW5kbGluZywgbWlkZGxld2FyZSBzZXR1cCwgcm91dGUgZGVmaW5pdGlvbiwgYW5kIHJhdGVcclxuICogbGltaXRpbmcuIFRoZSBtb2R1bGUgZXhwb3J0cyBmdW5jdGlvbnMgdG8gc3RhcnQsIHN0b3AsIGFuZCBtYW5hZ2Ugc2VydmVyXHJcbiAqIGluc3RhbmNlcywgYXMgd2VsbCBhcyB1dGlsaXR5IGZ1bmN0aW9ucyBmb3IgZGVmaW5pbmcgcm91dGVzIGFuZCBhdHRhY2hpbmdcclxuICogbWlkZGxld2FyZXMuXHJcbiAqL1xyXG5cclxuaW1wb3J0IHsgcmVhZEZpbGUgfSBmcm9tICdmcy9wcm9taXNlcyc7XHJcbmltcG9ydCB7IGpvaW4gfSBmcm9tICdwYXRoJztcclxuXHJcbmltcG9ydCBjb3JzIGZyb20gJ2NvcnMnO1xyXG5pbXBvcnQgZXhwcmVzcyBmcm9tICdleHByZXNzJztcclxuaW1wb3J0IGh0dHAgZnJvbSAnaHR0cCc7XHJcbmltcG9ydCBodHRwcyBmcm9tICdodHRwcyc7XHJcbmltcG9ydCBtdWx0ZXIgZnJvbSAnbXVsdGVyJztcclxuXHJcbmltcG9ydCB7IHVwZGF0ZU9wdGlvbnMgfSBmcm9tICcuLi9jb25maWcuanMnO1xyXG5pbXBvcnQgeyBsb2csIGxvZ1dpdGhTdGFjayB9IGZyb20gJy4uL2xvZ2dlci5qcyc7XHJcbmltcG9ydCB7IF9fZGlybmFtZSwgZ2V0QWJzb2x1dGVQYXRoIH0gZnJvbSAnLi4vdXRpbHMuanMnO1xyXG5cclxuaW1wb3J0IGVycm9yTWlkZGxld2FyZSBmcm9tICcuL21pZGRsZXdhcmVzL2Vycm9yLmpzJztcclxuaW1wb3J0IHJhdGVMaW1pdGluZ01pZGRsZXdhcmUgZnJvbSAnLi9taWRkbGV3YXJlcy9yYXRlTGltaXRpbmcuanMnO1xyXG5pbXBvcnQgdmFsaWRhdGlvbk1pZGRsZXdhcmUgZnJvbSAnLi9taWRkbGV3YXJlcy92YWxpZGF0aW9uLmpzJztcclxuXHJcbmltcG9ydCBleHBvcnRSb3V0ZXMgZnJvbSAnLi9yb3V0ZXMvZXhwb3J0LmpzJztcclxuaW1wb3J0IGhlYWx0aFJvdXRlcyBmcm9tICcuL3JvdXRlcy9oZWFsdGguanMnO1xyXG5pbXBvcnQgdWlSb3V0ZXMgZnJvbSAnLi9yb3V0ZXMvdWkuanMnO1xyXG5pbXBvcnQgdmVyc2lvbkNoYW5nZVJvdXRlcyBmcm9tICcuL3JvdXRlcy92ZXJzaW9uQ2hhbmdlLmpzJztcclxuXHJcbmltcG9ydCBFeHBvcnRFcnJvciBmcm9tICcuLi9lcnJvcnMvRXhwb3J0RXJyb3IuanMnO1xyXG5cclxuLy8gQXJyYXkgb2YgYW4gYWN0aXZlIHNlcnZlcnNcclxuY29uc3QgYWN0aXZlU2VydmVycyA9IG5ldyBNYXAoKTtcclxuXHJcbi8vIENyZWF0ZSBleHByZXNzIGFwcFxyXG5jb25zdCBhcHAgPSBleHByZXNzKCk7XHJcblxyXG4vKipcclxuICogU3RhcnRzIGFuIEhUVFAgYW5kL29yIEhUVFBTIHNlcnZlciBiYXNlZCBvbiB0aGUgcHJvdmlkZWQgY29uZmlndXJhdGlvbi5cclxuICogVGhlIGBzZXJ2ZXJPcHRpb25zYCBvYmplY3QgY29udGFpbnMgc2VydmVyLXJlbGF0ZWQgcHJvcGVydGllcyAocmVmZXJcclxuICogdG8gdGhlIGBzZXJ2ZXJgIHNlY3Rpb24gaW4gdGhlIGBsaWIvc2NoZW1hcy9jb25maWcuanNgIGZpbGUgZm9yIGRldGFpbHMpLlxyXG4gKlxyXG4gKiBAYXN5bmNcclxuICogQGZ1bmN0aW9uIHN0YXJ0U2VydmVyXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBzZXJ2ZXJPcHRpb25zIC0gVGhlIGNvbmZpZ3VyYXRpb24gb2JqZWN0IGNvbnRhaW5pbmcgYHNlcnZlcmBcclxuICogb3B0aW9ucy4gVGhpcyBvYmplY3QgbWF5IGluY2x1ZGUgYSBwYXJ0aWFsIG9yIGNvbXBsZXRlIHNldCBvZiB0aGUgYHNlcnZlcmBcclxuICogb3B0aW9ucy4gSWYgdGhlIG9wdGlvbnMgYXJlIHBhcnRpYWwsIG1pc3NpbmcgdmFsdWVzIHdpbGwgZGVmYXVsdFxyXG4gKiB0byB0aGUgY3VycmVudCBnbG9iYWwgY29uZmlndXJhdGlvbi5cclxuICpcclxuICogQHJldHVybnMge1Byb21pc2U8dm9pZD59IEEgUHJvbWlzZSB0aGF0IHJlc29sdmVzIHdoZW4gdGhlIHNlcnZlciBpcyBlaXRoZXJcclxuICogbm90IGVuYWJsZWQgb3Igbm8gdmFsaWQgRXhwcmVzcyBhcHAgaXMgZm91bmQsIHNpZ25hbGluZyB0aGUgZW5kIG9mIHRoZVxyXG4gKiBmdW5jdGlvbidzIGV4ZWN1dGlvbi5cclxuICpcclxuICogQHRocm93cyB7RXhwb3J0RXJyb3J9IFRocm93cyBhbiBgRXhwb3J0RXJyb3JgIGlmIHRoZSBzZXJ2ZXIgY2Fubm90XHJcbiAqIGJlIGNvbmZpZ3VyZWQgYW5kIHN0YXJ0ZWQuXHJcbiAqL1xyXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gc3RhcnRTZXJ2ZXIoc2VydmVyT3B0aW9ucykge1xyXG4gIHRyeSB7XHJcbiAgICAvLyBVcGRhdGUgdGhlIGluc3RhbmNlIG9wdGlvbnMgb2JqZWN0XHJcbiAgICBjb25zdCBvcHRpb25zID0gdXBkYXRlT3B0aW9ucyh7XHJcbiAgICAgIHNlcnZlcjogc2VydmVyT3B0aW9uc1xyXG4gICAgfSk7XHJcblxyXG4gICAgLy8gVXNlIHZhbGlkYXRlZCBvcHRpb25zXHJcbiAgICBzZXJ2ZXJPcHRpb25zID0gb3B0aW9ucy5zZXJ2ZXI7XHJcblxyXG4gICAgLy8gU3RvcCBpZiBub3QgZW5hYmxlZFxyXG4gICAgaWYgKCFzZXJ2ZXJPcHRpb25zLmVuYWJsZSB8fCAhYXBwKSB7XHJcbiAgICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcihcclxuICAgICAgICAnW3NlcnZlcl0gU2VydmVyIGNhbm5vdCBiZSBzdGFydGVkIChub3QgZW5hYmxlZCBvciBubyBjb3JyZWN0IEV4cHJlc3MgYXBwIGZvdW5kKS4nLFxyXG4gICAgICAgIDUwMFxyXG4gICAgICApO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIFRvbyBiaWcgbGltaXRzIGxlYWQgdG8gdGltZW91dHMgaW4gdGhlIGV4cG9ydCBwcm9jZXNzIHdoZW5cclxuICAgIC8vIHRoZSByYXN0ZXJpemF0aW9uIHRpbWVvdXQgaXMgc2V0IHRvbyBsb3dcclxuICAgIGNvbnN0IHVwbG9hZExpbWl0Qnl0ZXMgPSBzZXJ2ZXJPcHRpb25zLnVwbG9hZExpbWl0ICogMTAyNCAqIDEwMjQ7XHJcblxyXG4gICAgLy8gTWVtb3J5IHN0b3JhZ2UgZm9yIG11bHRlciBwYWNrYWdlXHJcbiAgICBjb25zdCBzdG9yYWdlID0gbXVsdGVyLm1lbW9yeVN0b3JhZ2UoKTtcclxuXHJcbiAgICAvLyBFbmFibGUgcGFyc2luZyBvZiBmb3JtIGRhdGEgKGZpbGVzKSB3aXRoIG11bHRlciBwYWNrYWdlXHJcbiAgICBjb25zdCB1cGxvYWQgPSBtdWx0ZXIoe1xyXG4gICAgICBzdG9yYWdlLFxyXG4gICAgICBsaW1pdHM6IHtcclxuICAgICAgICBmaWVsZFNpemU6IHVwbG9hZExpbWl0Qnl0ZXNcclxuICAgICAgfVxyXG4gICAgfSk7XHJcblxyXG4gICAgLy8gRGlzYWJsZSB0aGUgWC1Qb3dlcmVkLUJ5IGhlYWRlclxyXG4gICAgYXBwLmRpc2FibGUoJ3gtcG93ZXJlZC1ieScpO1xyXG5cclxuICAgIC8vIEVuYWJsZSBDT1JTIHN1cHBvcnRcclxuICAgIGFwcC51c2UoXHJcbiAgICAgIGNvcnMoe1xyXG4gICAgICAgIG1ldGhvZHM6IFsnUE9TVCcsICdHRVQnLCAnT1BUSU9OUyddXHJcbiAgICAgIH0pXHJcbiAgICApO1xyXG5cclxuICAgIC8vIEdldHRpbmcgYSBsb3Qgb2YgYFJhbmdlTm90U2F0aXNmaWFibGVFcnJvcmAgZXhjZXB0aW9ucyAoZXZlbiB0aG91Z2ggdGhpc1xyXG4gICAgLy8gaXMgYSBkZXByZWNhdGVkIG9wdGlvbnMsIGxldCdzIHRyeSB0byBzZXQgaXQgdG8gZmFsc2UpXHJcbiAgICBhcHAudXNlKChyZXF1ZXN0LCByZXNwb25zZSwgbmV4dCkgPT4ge1xyXG4gICAgICByZXNwb25zZS5zZXQoJ0FjY2VwdC1SYW5nZXMnLCAnbm9uZScpO1xyXG4gICAgICBuZXh0KCk7XHJcbiAgICB9KTtcclxuXHJcbiAgICAvLyBFbmFibGUgYm9keSBwYXJzZXIgZm9yIEpTT04gZGF0YVxyXG4gICAgYXBwLnVzZShcclxuICAgICAgZXhwcmVzcy5qc29uKHtcclxuICAgICAgICBsaW1pdDogdXBsb2FkTGltaXRCeXRlc1xyXG4gICAgICB9KVxyXG4gICAgKTtcclxuXHJcbiAgICAvLyBFbmFibGUgYm9keSBwYXJzZXIgZm9yIFVSTC1lbmNvZGVkIGZvcm0gZGF0YVxyXG4gICAgYXBwLnVzZShcclxuICAgICAgZXhwcmVzcy51cmxlbmNvZGVkKHtcclxuICAgICAgICBleHRlbmRlZDogdHJ1ZSxcclxuICAgICAgICBsaW1pdDogdXBsb2FkTGltaXRCeXRlc1xyXG4gICAgICB9KVxyXG4gICAgKTtcclxuXHJcbiAgICAvLyBVc2Ugb25seSBub24tZmlsZSBtdWx0aXBhcnQgZm9ybSBmaWVsZHNcclxuICAgIGFwcC51c2UodXBsb2FkLm5vbmUoKSk7XHJcblxyXG4gICAgLy8gU2V0IHVwIHN0YXRpYyBmb2xkZXIncyByb3V0ZVxyXG4gICAgYXBwLnVzZShleHByZXNzLnN0YXRpYyhqb2luKF9fZGlybmFtZSwgJ3B1YmxpYycpKSk7XHJcblxyXG4gICAgLy8gTGlzdGVuIEhUVFAgc2VydmVyXHJcbiAgICBpZiAoIXNlcnZlck9wdGlvbnMuc3NsLmZvcmNlKSB7XHJcbiAgICAgIC8vIE1haW4gc2VydmVyIGluc3RhbmNlIChIVFRQKVxyXG4gICAgICBjb25zdCBodHRwU2VydmVyID0gaHR0cC5jcmVhdGVTZXJ2ZXIoYXBwKTtcclxuXHJcbiAgICAgIC8vIEF0dGFjaCBlcnJvciBoYW5kbGVycyBhbmQgbGlzdGVuIHRvIHRoZSBzZXJ2ZXJcclxuICAgICAgX2F0dGFjaFNlcnZlckVycm9ySGFuZGxlcnMoaHR0cFNlcnZlcik7XHJcblxyXG4gICAgICAvLyBMaXN0ZW5cclxuICAgICAgaHR0cFNlcnZlci5saXN0ZW4oc2VydmVyT3B0aW9ucy5wb3J0LCBzZXJ2ZXJPcHRpb25zLmhvc3QsICgpID0+IHtcclxuICAgICAgICAvLyBTYXZlIHRoZSByZWZlcmVuY2UgdG8gSFRUUCBzZXJ2ZXJcclxuICAgICAgICBhY3RpdmVTZXJ2ZXJzLnNldChzZXJ2ZXJPcHRpb25zLnBvcnQsIGh0dHBTZXJ2ZXIpO1xyXG5cclxuICAgICAgICBsb2coXHJcbiAgICAgICAgICAzLFxyXG4gICAgICAgICAgYFtzZXJ2ZXJdIFN0YXJ0ZWQgSFRUUCBzZXJ2ZXIgb24gJHtzZXJ2ZXJPcHRpb25zLmhvc3R9OiR7c2VydmVyT3B0aW9ucy5wb3J0fS5gXHJcbiAgICAgICAgKTtcclxuICAgICAgfSk7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gTGlzdGVuIEhUVFBTIHNlcnZlclxyXG4gICAgaWYgKHNlcnZlck9wdGlvbnMuc3NsLmVuYWJsZSkge1xyXG4gICAgICAvLyBTZXQgdXAgYW4gU1NMIHNlcnZlciBhbHNvXHJcbiAgICAgIGxldCBrZXksIGNlcnQ7XHJcblxyXG4gICAgICB0cnkge1xyXG4gICAgICAgIC8vIEdldCB0aGUgU1NMIGtleVxyXG4gICAgICAgIGtleSA9IGF3YWl0IHJlYWRGaWxlKFxyXG4gICAgICAgICAgam9pbihnZXRBYnNvbHV0ZVBhdGgoc2VydmVyT3B0aW9ucy5zc2wuY2VydFBhdGgpLCAnc2VydmVyLmtleScpLFxyXG4gICAgICAgICAgJ3V0ZjgnXHJcbiAgICAgICAgKTtcclxuXHJcbiAgICAgICAgLy8gR2V0IHRoZSBTU0wgY2VydGlmaWNhdGVcclxuICAgICAgICBjZXJ0ID0gYXdhaXQgcmVhZEZpbGUoXHJcbiAgICAgICAgICBqb2luKGdldEFic29sdXRlUGF0aChzZXJ2ZXJPcHRpb25zLnNzbC5jZXJ0UGF0aCksICdzZXJ2ZXIuY3J0JyksXHJcbiAgICAgICAgICAndXRmOCdcclxuICAgICAgICApO1xyXG4gICAgICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgICAgIGxvZyhcclxuICAgICAgICAgIDIsXHJcbiAgICAgICAgICBgW3NlcnZlcl0gVW5hYmxlIHRvIGxvYWQga2V5L2NlcnRpZmljYXRlIGZyb20gdGhlICcke3NlcnZlck9wdGlvbnMuc3NsLmNlcnRQYXRofScgcGF0aC4gQ291bGQgbm90IHJ1biBzZWN1cmVkIGxheWVyIHNlcnZlci5gXHJcbiAgICAgICAgKTtcclxuICAgICAgfVxyXG5cclxuICAgICAgaWYgKGtleSAmJiBjZXJ0KSB7XHJcbiAgICAgICAgLy8gTWFpbiBzZXJ2ZXIgaW5zdGFuY2UgKEhUVFBTKVxyXG4gICAgICAgIGNvbnN0IGh0dHBzU2VydmVyID0gaHR0cHMuY3JlYXRlU2VydmVyKHsga2V5LCBjZXJ0IH0sIGFwcCk7XHJcblxyXG4gICAgICAgIC8vIEF0dGFjaCBlcnJvciBoYW5kbGVycyBhbmQgbGlzdGVuIHRvIHRoZSBzZXJ2ZXJcclxuICAgICAgICBfYXR0YWNoU2VydmVyRXJyb3JIYW5kbGVycyhodHRwc1NlcnZlcik7XHJcblxyXG4gICAgICAgIC8vIExpc3RlblxyXG4gICAgICAgIGh0dHBzU2VydmVyLmxpc3RlbihzZXJ2ZXJPcHRpb25zLnNzbC5wb3J0LCBzZXJ2ZXJPcHRpb25zLmhvc3QsICgpID0+IHtcclxuICAgICAgICAgIC8vIFNhdmUgdGhlIHJlZmVyZW5jZSB0byBIVFRQUyBzZXJ2ZXJcclxuICAgICAgICAgIGFjdGl2ZVNlcnZlcnMuc2V0KHNlcnZlck9wdGlvbnMuc3NsLnBvcnQsIGh0dHBzU2VydmVyKTtcclxuXHJcbiAgICAgICAgICBsb2coXHJcbiAgICAgICAgICAgIDMsXHJcbiAgICAgICAgICAgIGBbc2VydmVyXSBTdGFydGVkIEhUVFBTIHNlcnZlciBvbiAke3NlcnZlck9wdGlvbnMuaG9zdH06JHtzZXJ2ZXJPcHRpb25zLnNzbC5wb3J0fS5gXHJcbiAgICAgICAgICApO1xyXG4gICAgICAgIH0pO1xyXG4gICAgICB9XHJcbiAgICB9XHJcblxyXG4gICAgLy8gU2V0IHVwIHRoZSByYXRlIGxpbWl0ZXJcclxuICAgIHJhdGVMaW1pdGluZ01pZGRsZXdhcmUoYXBwLCBzZXJ2ZXJPcHRpb25zLnJhdGVMaW1pdGluZyk7XHJcblxyXG4gICAgLy8gU2V0IHVwIHRoZSB2YWxpZGF0aW9uIGhhbmRsZXJcclxuICAgIHZhbGlkYXRpb25NaWRkbGV3YXJlKGFwcCk7XHJcblxyXG4gICAgLy8gU2V0IHVwIHJvdXRlc1xyXG4gICAgZXhwb3J0Um91dGVzKGFwcCk7XHJcbiAgICBoZWFsdGhSb3V0ZXMoYXBwKTtcclxuICAgIHVpUm91dGVzKGFwcCk7XHJcbiAgICB2ZXJzaW9uQ2hhbmdlUm91dGVzKGFwcCk7XHJcblxyXG4gICAgLy8gU2V0IHVwIHRoZSBjZW50cmFsaXplZCBlcnJvciBoYW5kbGVyXHJcbiAgICBlcnJvck1pZGRsZXdhcmUoYXBwKTtcclxuICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgdGhyb3cgbmV3IEV4cG9ydEVycm9yKFxyXG4gICAgICAnW3NlcnZlcl0gQ291bGQgbm90IGNvbmZpZ3VyZSBhbmQgc3RhcnQgdGhlIHNlcnZlci4nLFxyXG4gICAgICA1MDBcclxuICAgICkuc2V0RXJyb3IoZXJyb3IpO1xyXG4gIH1cclxufVxyXG5cclxuLyoqXHJcbiAqIENsb3NlcyBhbGwgc2VydmVycyBhc3NvY2lhdGVkIHdpdGggRXhwcmVzcyBhcHAgaW5zdGFuY2UuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBjbG9zZVNlcnZlcnNcclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiBjbG9zZVNlcnZlcnMoKSB7XHJcbiAgLy8gQ2hlY2sgaWYgdGhlcmUgYXJlIHNlcnZlcnMgd29ya2luZ1xyXG4gIGlmIChhY3RpdmVTZXJ2ZXJzLnNpemUgPiAwKSB7XHJcbiAgICBsb2coNCwgYFtzZXJ2ZXJdIENsb3NpbmcgYWxsIHNlcnZlcnMuYCk7XHJcblxyXG4gICAgLy8gQ2xvc2UgZWFjaCBvbmUgb2Ygc2VydmVyc1xyXG4gICAgZm9yIChjb25zdCBbcG9ydCwgc2VydmVyXSBvZiBhY3RpdmVTZXJ2ZXJzKSB7XHJcbiAgICAgIHNlcnZlci5jbG9zZSgoKSA9PiB7XHJcbiAgICAgICAgYWN0aXZlU2VydmVycy5kZWxldGUocG9ydCk7XHJcbiAgICAgICAgbG9nKDQsIGBbc2VydmVyXSBDbG9zZWQgc2VydmVyIG9uIHBvcnQ6ICR7cG9ydH0uYCk7XHJcbiAgICAgIH0pO1xyXG4gICAgfVxyXG4gIH1cclxufVxyXG5cclxuLyoqXHJcbiAqIEdldCBhbGwgc2VydmVycyBhc3NvY2lhdGVkIHdpdGggRXhwcmVzcyBhcHAgaW5zdGFuY2UuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBnZXRTZXJ2ZXJzXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtBcnJheS48T2JqZWN0Pn0gU2VydmVycyBhc3NvY2lhdGVkIHdpdGggRXhwcmVzcyBhcHAgaW5zdGFuY2UuXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gZ2V0U2VydmVycygpIHtcclxuICByZXR1cm4gYWN0aXZlU2VydmVycztcclxufVxyXG5cclxuLyoqXHJcbiAqIEdldCB0aGUgRXhwcmVzcyBpbnN0YW5jZS5cclxuICpcclxuICogQGZ1bmN0aW9uIGdldEV4cHJlc3NcclxuICpcclxuICogQHJldHVybnMge0V4cHJlc3N9IFRoZSBFeHByZXNzIGluc3RhbmNlLlxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIGdldEV4cHJlc3MoKSB7XHJcbiAgcmV0dXJuIGV4cHJlc3M7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBHZXQgdGhlIEV4cHJlc3MgYXBwIGluc3RhbmNlLlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gZ2V0QXBwXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtFeHByZXNzfSBUaGUgRXhwcmVzcyBhcHAgaW5zdGFuY2UuXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gZ2V0QXBwKCkge1xyXG4gIHJldHVybiBhcHA7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBFbmFibGUgcmF0ZSBsaW1pdGluZyBmb3IgdGhlIHNlcnZlci5cclxuICpcclxuICogQGZ1bmN0aW9uIGVuYWJsZVJhdGVMaW1pdGluZ1xyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gcmF0ZUxpbWl0aW5nT3B0aW9ucyAtIFRoZSBjb25maWd1cmF0aW9uIG9iamVjdCBjb250YWluaW5nXHJcbiAqIGByYXRlTGltaXRpbmdgIG9wdGlvbnMuIFRoaXMgb2JqZWN0IG1heSBpbmNsdWRlIGEgcGFydGlhbCBvciBjb21wbGV0ZSBzZXRcclxuICogb2YgdGhlIGByYXRlTGltaXRpbmdgIG9wdGlvbnMuIElmIHRoZSBvcHRpb25zIGFyZSBwYXJ0aWFsLCBtaXNzaW5nIHZhbHVlc1xyXG4gKiB3aWxsIGRlZmF1bHQgdG8gdGhlIGN1cnJlbnQgZ2xvYmFsIGNvbmZpZ3VyYXRpb24uXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gZW5hYmxlUmF0ZUxpbWl0aW5nKHJhdGVMaW1pdGluZ09wdGlvbnMpIHtcclxuICAvLyBVcGRhdGUgdGhlIGluc3RhbmNlIG9wdGlvbnMgb2JqZWN0XHJcbiAgY29uc3Qgb3B0aW9ucyA9IHVwZGF0ZU9wdGlvbnMoe1xyXG4gICAgc2VydmVyOiB7XHJcbiAgICAgIHJhdGVMaW1pdGluZzogcmF0ZUxpbWl0aW5nT3B0aW9uc1xyXG4gICAgfVxyXG4gIH0pO1xyXG5cclxuICAvLyBTZXQgdGhlIHJhdGUgbGltaXRpbmcgb3B0aW9uc1xyXG4gIHJhdGVMaW1pdGluZ01pZGRsZXdhcmUoYXBwLCBvcHRpb25zLnNlcnZlci5yYXRlTGltaXRpbmdPcHRpb25zKTtcclxufVxyXG5cclxuLyoqXHJcbiAqIEFwcGx5IG1pZGRsZXdhcmUocykgdG8gYSBzcGVjaWZpYyBwYXRoLlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gdXNlXHJcbiAqXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSBwYXRoIC0gVGhlIHBhdGggdG8gd2hpY2ggdGhlIG1pZGRsZXdhcmUocykgc2hvdWxkIGJlIGFwcGxpZWQuXHJcbiAqIEBwYXJhbSB7Li4uRnVuY3Rpb259IG1pZGRsZXdhcmVzIC0gVGhlIG1pZGRsZXdhcmUgZnVuY3Rpb24ocykgdG8gYmUgYXBwbGllZC5cclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiB1c2UocGF0aCwgLi4ubWlkZGxld2FyZXMpIHtcclxuICBhcHAudXNlKHBhdGgsIC4uLm1pZGRsZXdhcmVzKTtcclxufVxyXG5cclxuLyoqXHJcbiAqIFNldCB1cCBhIHJvdXRlIHdpdGggR0VUIG1ldGhvZCBhbmQgYXBwbHkgbWlkZGxld2FyZShzKS5cclxuICpcclxuICogQGZ1bmN0aW9uIGdldFxyXG4gKlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gcGF0aCAtIFRoZSBwYXRoIHRvIHdoaWNoIHRoZSBtaWRkbGV3YXJlKHMpIHNob3VsZCBiZSBhcHBsaWVkLlxyXG4gKiBAcGFyYW0gey4uLkZ1bmN0aW9ufSBtaWRkbGV3YXJlcyAtIFRoZSBtaWRkbGV3YXJlIGZ1bmN0aW9uKHMpIHRvIGJlIGFwcGxpZWQuXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gZ2V0KHBhdGgsIC4uLm1pZGRsZXdhcmVzKSB7XHJcbiAgYXBwLmdldChwYXRoLCAuLi5taWRkbGV3YXJlcyk7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBTZXQgdXAgYSByb3V0ZSB3aXRoIFBPU1QgbWV0aG9kIGFuZCBhcHBseSBtaWRkbGV3YXJlKHMpLlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gcG9zdFxyXG4gKlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gcGF0aCAtIFRoZSBwYXRoIHRvIHdoaWNoIHRoZSBtaWRkbGV3YXJlKHMpIHNob3VsZCBiZSBhcHBsaWVkLlxyXG4gKiBAcGFyYW0gey4uLkZ1bmN0aW9ufSBtaWRkbGV3YXJlcyAtIFRoZSBtaWRkbGV3YXJlIGZ1bmN0aW9uKHMpIHRvIGJlIGFwcGxpZWQuXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gcG9zdChwYXRoLCAuLi5taWRkbGV3YXJlcykge1xyXG4gIGFwcC5wb3N0KHBhdGgsIC4uLm1pZGRsZXdhcmVzKTtcclxufVxyXG5cclxuLyoqXHJcbiAqIEF0dGFjaCBlcnJvciBoYW5kbGVycyB0byB0aGUgc2VydmVyLlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gX2F0dGFjaFNlcnZlckVycm9ySGFuZGxlcnNcclxuICpcclxuICogQHBhcmFtIHsoaHR0cC5TZXJ2ZXJ8aHR0cHMuU2VydmVyKX0gc2VydmVyIC0gVGhlIEhUVFAvSFRUUFMgc2VydmVyIGluc3RhbmNlLlxyXG4gKi9cclxuZnVuY3Rpb24gX2F0dGFjaFNlcnZlckVycm9ySGFuZGxlcnMoc2VydmVyKSB7XHJcbiAgc2VydmVyLm9uKCdjbGllbnRFcnJvcicsIChlcnJvciwgc29ja2V0KSA9PiB7XHJcbiAgICBsb2dXaXRoU3RhY2soXHJcbiAgICAgIDEsXHJcbiAgICAgIGVycm9yLFxyXG4gICAgICBgW3NlcnZlcl0gQ2xpZW50IGVycm9yOiAke2Vycm9yLm1lc3NhZ2V9LCBkZXN0cm95aW5nIHNvY2tldC5gXHJcbiAgICApO1xyXG4gICAgc29ja2V0LmRlc3Ryb3koKTtcclxuICB9KTtcclxuXHJcbiAgc2VydmVyLm9uKCdlcnJvcicsIChlcnJvcikgPT4ge1xyXG4gICAgbG9nV2l0aFN0YWNrKDEsIGVycm9yLCBgW3NlcnZlcl0gU2VydmVyIGVycm9yOiAke2Vycm9yLm1lc3NhZ2V9YCk7XHJcbiAgfSk7XHJcblxyXG4gIHNlcnZlci5vbignY29ubmVjdGlvbicsIChzb2NrZXQpID0+IHtcclxuICAgIHNvY2tldC5vbignZXJyb3InLCAoZXJyb3IpID0+IHtcclxuICAgICAgbG9nV2l0aFN0YWNrKDEsIGVycm9yLCBgW3NlcnZlcl0gU29ja2V0IGVycm9yOiAke2Vycm9yLm1lc3NhZ2V9YCk7XHJcbiAgICB9KTtcclxuICB9KTtcclxufVxyXG5cclxuZXhwb3J0IGRlZmF1bHQge1xyXG4gIHN0YXJ0U2VydmVyLFxyXG4gIGNsb3NlU2VydmVycyxcclxuICBnZXRTZXJ2ZXJzLFxyXG4gIGdldEV4cHJlc3MsXHJcbiAgZ2V0QXBwLFxyXG4gIGVuYWJsZVJhdGVMaW1pdGluZyxcclxuICB1c2UsXHJcbiAgZ2V0LFxyXG4gIHBvc3RcclxufTtcclxuIiwiLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcclxuXHJcbkhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlclxyXG5cclxuQ29weXJpZ2h0IChjKSAyMDE2LTIwMjUsIEhpZ2hzb2Z0XHJcblxyXG5MaWNlbmNlZCB1bmRlciB0aGUgTUlUIGxpY2VuY2UuXHJcblxyXG5BZGRpdGlvbmFsbHkgYSB2YWxpZCBIaWdoY2hhcnRzIGxpY2Vuc2UgaXMgcmVxdWlyZWQgZm9yIHVzZS5cclxuXHJcblNlZSBMSUNFTlNFIGZpbGUgaW4gcm9vdCBmb3IgZGV0YWlscy5cclxuXHJcbioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXHJcblxyXG4vKipcclxuICogQG92ZXJ2aWV3IEhhbmRsZXMgZ3JhY2VmdWwgc2h1dGRvd24gb2YgdGhlIEhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlciwgZW5zdXJpbmdcclxuICogcHJvcGVyIGNsZWFudXAgb2YgcmVzb3VyY2VzIHN1Y2ggYXMgYnJvd3NlciwgcGFnZXMsIHNlcnZlcnMsIGFuZCB0aW1lcnMuXHJcbiAqL1xyXG5cclxuaW1wb3J0IHsga2lsbFBvb2wgfSBmcm9tICcuL3Bvb2wuanMnO1xyXG5pbXBvcnQgeyBjbGVhckFsbFRpbWVycyB9IGZyb20gJy4vdGltZXIuanMnO1xyXG5cclxuaW1wb3J0IHsgY2xvc2VTZXJ2ZXJzIH0gZnJvbSAnLi9zZXJ2ZXIvc2VydmVyLmpzJztcclxuXHJcbi8qKlxyXG4gKiBQZXJmb3JtcyBjbGVhbnVwIG9wZXJhdGlvbnMgdG8gZW5zdXJlIGEgZ3JhY2VmdWwgc2h1dGRvd24gb2YgdGhlIHByb2Nlc3MuXHJcbiAqIFRoaXMgaW5jbHVkZXMgY2xlYXJpbmcgYWxsIHJlZ2lzdGVyZWQgdGltZW91dHMvaW50ZXJ2YWxzLCBjbG9zaW5nIGFjdGl2ZVxyXG4gKiBzZXJ2ZXJzLCB0ZXJtaW5hdGluZyByZXNvdXJjZXMgKHBhZ2VzKSBvZiB0aGUgcG9vbCwgcG9vbCBpdHNlbGYsIGFuZCBjbG9zaW5nXHJcbiAqIHRoZSBicm93c2VyLlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gc2h1dGRvd25DbGVhblVwXHJcbiAqXHJcbiAqIEBwYXJhbSB7bnVtYmVyfSBbZXhpdENvZGU9MF0gLSBUaGUgZXhpdCBjb2RlIHRvIHVzZSB3aXRoIGBwcm9jZXNzLmV4aXQoKWAuXHJcbiAqIFRoZSBkZWZhdWx0IHZhbHVlIGlzIGAwYC5cclxuICovXHJcbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBzaHV0ZG93bkNsZWFuVXAoZXhpdENvZGUgPSAwKSB7XHJcbiAgLy8gQXdhaXQgZnJlZWluZyBhbGwgcmVzb3VyY2VzXHJcbiAgYXdhaXQgUHJvbWlzZS5hbGxTZXR0bGVkKFtcclxuICAgIC8vIENsZWFyIGFsbCBvbmdvaW5nIGludGVydmFsc1xyXG4gICAgY2xlYXJBbGxUaW1lcnMoKSxcclxuXHJcbiAgICAvLyBHZXQgYXZhaWxhYmxlIHNlcnZlciBpbnN0YW5jZXMgKEhUVFAvSFRUUFMpIGFuZCBjbG9zZSB0aGVtXHJcbiAgICBjbG9zZVNlcnZlcnMoKSxcclxuXHJcbiAgICAvLyBDbG9zZSBhbiBhY3RpdmUgcG9vbCBhbG9uZyB3aXRoIGl0cyB3b3JrZXJzIGFuZCB0aGUgYnJvd3NlciBpbnN0YW5jZVxyXG4gICAga2lsbFBvb2woKVxyXG4gIF0pO1xyXG5cclxuICAvLyBFeGl0IHByb2Nlc3Mgd2l0aCBhIGNvcnJlY3QgY29kZVxyXG4gIHByb2Nlc3MuZXhpdChleGl0Q29kZSk7XHJcbn1cclxuXHJcbmV4cG9ydCBkZWZhdWx0IHtcclxuICBzaHV0ZG93bkNsZWFuVXBcclxufTtcclxuIiwiLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcclxuXHJcbkhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlclxyXG5cclxuQ29weXJpZ2h0IChjKSAyMDE2LTIwMjUsIEhpZ2hzb2Z0XHJcblxyXG5MaWNlbmNlZCB1bmRlciB0aGUgTUlUIGxpY2VuY2UuXHJcblxyXG5BZGRpdGlvbmFsbHkgYSB2YWxpZCBIaWdoY2hhcnRzIGxpY2Vuc2UgaXMgcmVxdWlyZWQgZm9yIHVzZS5cclxuXHJcblNlZSBMSUNFTlNFIGZpbGUgaW4gcm9vdCBmb3IgZGV0YWlscy5cclxuXHJcbioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXHJcblxyXG4vKipcclxuICogQG92ZXJ2aWV3IENvcmUgbW9kdWxlIGZvciBpbml0aWFsaXppbmcgYW5kIG1hbmFnaW5nIHRoZSBIaWdoY2hhcnRzIEV4cG9ydFxyXG4gKiBTZXJ2ZXIuIFByb3ZpZGVzIGZ1bmN0aW9uYWxpdGllcyBmb3IgY29uZmlndXJpbmcgZXhwb3J0cywgc2V0dGluZyB1cCBzZXJ2ZXJcclxuICogb3BlcmF0aW9ucywgbG9nZ2luZywgc2NyaXB0cyBjYWNoaW5nLCByZXNvdXJjZSBwb29saW5nLCBhbmQgZ3JhY2VmdWwgcHJvY2Vzc1xyXG4gKiBjbGVhbnVwLlxyXG4gKi9cclxuXHJcbmltcG9ydCAnY29sb3JzJztcclxuXHJcbmltcG9ydCB7IGNoZWNrQW5kVXBkYXRlQ2FjaGUgfSBmcm9tICcuL2NhY2hlLmpzJztcclxuaW1wb3J0IHtcclxuICBzaW5nbGVFeHBvcnQsXHJcbiAgYmF0Y2hFeHBvcnQsXHJcbiAgc3RhcnRFeHBvcnQsXHJcbiAgc2V0QWxsb3dDb2RlRXhlY3V0aW9uXHJcbn0gZnJvbSAnLi9jaGFydC5qcyc7XHJcbmltcG9ydCB7XHJcbiAgZ2V0T3B0aW9ucyxcclxuICB1cGRhdGVPcHRpb25zLFxyXG4gIHNldEdsb2JhbE9wdGlvbnMsXHJcbiAgbWFwVG9OZXdPcHRpb25zXHJcbn0gZnJvbSAnLi9jb25maWcuanMnO1xyXG5pbXBvcnQge1xyXG4gIGxvZyxcclxuICBsb2dXaXRoU3RhY2ssXHJcbiAgbG9nWm9kSXNzdWVzLFxyXG4gIGluaXRMb2dnaW5nLFxyXG4gIGVuYWJsZUNvbnNvbGVMb2dnaW5nLFxyXG4gIGVuYWJsZUZpbGVMb2dnaW5nLFxyXG4gIHNldExvZ0xldmVsXHJcbn0gZnJvbSAnLi9sb2dnZXIuanMnO1xyXG5pbXBvcnQgeyBpbml0UG9vbCwga2lsbFBvb2wgfSBmcm9tICcuL3Bvb2wuanMnO1xyXG5pbXBvcnQgeyBzaHV0ZG93bkNsZWFuVXAgfSBmcm9tICcuL3Jlc291cmNlUmVsZWFzZS5qcyc7XHJcblxyXG5pbXBvcnQgc2VydmVyIGZyb20gJy4vc2VydmVyL3NlcnZlci5qcyc7XHJcblxyXG4vKipcclxuICogSW5pdGlhbGl6ZXMgdGhlIGV4cG9ydCBwcm9jZXNzLiBUYXNrcyBzdWNoIGFzIGNvbmZpZ3VyaW5nIGxvZ2dpbmcsIGNoZWNraW5nXHJcbiAqIHRoZSBjYWNoZSBhbmQgc291cmNlcywgYW5kIGluaXRpYWxpemluZyB0aGUgcmVzb3VyY2UgcG9vbCBvY2N1ciBkdXJpbmcgdGhpc1xyXG4gKiBzdGFnZS5cclxuICpcclxuICogVGhpcyBmdW5jdGlvbiBtdXN0IGJlIGNhbGxlZCBiZWZvcmUgYXR0ZW1wdGluZyB0byBleHBvcnQgY2hhcnRzIG9yIHNldFxyXG4gKiB1cCBhIHNlcnZlci5cclxuICpcclxuICogQGFzeW5jXHJcbiAqIEBmdW5jdGlvbiBpbml0RXhwb3J0XHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBbaW5pdE9wdGlvbnM9e31dIC0gVGhlIGBpbml0T3B0aW9uc2Agb2JqZWN0LCB3aGljaCBtYXlcclxuICogYmUgYSBwYXJ0aWFsIG9yIGNvbXBsZXRlIHNldCBvZiBvcHRpb25zLiBJZiB0aGUgb3B0aW9ucyBhcmUgcGFydGlhbCwgbWlzc2luZ1xyXG4gKiB2YWx1ZXMgd2lsbCBkZWZhdWx0IHRvIHRoZSBjdXJyZW50IGdsb2JhbCBjb25maWd1cmF0aW9uLiBUaGUgZGVmYXVsdCB2YWx1ZVxyXG4gKiBpcyBhbiBlbXB0eSBvYmplY3QuXHJcbiAqL1xyXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gaW5pdEV4cG9ydChpbml0T3B0aW9ucyA9IHt9KSB7XHJcbiAgLy8gSW5pdCBhbmQgdXBkYXRlIHRoZSBpbnN0YW5jZSBvcHRpb25zIG9iamVjdFxyXG4gIGNvbnN0IG9wdGlvbnMgPSB1cGRhdGVPcHRpb25zKGluaXRPcHRpb25zLCB0cnVlKTtcclxuXHJcbiAgLy8gU2V0IHRoZSBgYWxsb3dDb2RlRXhlY3V0aW9uYCBwZXIgZXhwb3J0IG1vZHVsZSBzY29wZVxyXG4gIHNldEFsbG93Q29kZUV4ZWN1dGlvbihvcHRpb25zLmN1c3RvbUxvZ2ljLmFsbG93Q29kZUV4ZWN1dGlvbik7XHJcblxyXG4gIC8vIEluaXQgdGhlIGxvZ2dpbmdcclxuICBpbml0TG9nZ2luZyhvcHRpb25zLmxvZ2dpbmcpO1xyXG5cclxuICAvLyBBdHRhY2ggcHJvY2VzcycgZXhpdCBsaXN0ZW5lcnNcclxuICBpZiAob3B0aW9ucy5vdGhlci5saXN0ZW5Ub1Byb2Nlc3NFeGl0cykge1xyXG4gICAgX2F0dGFjaFByb2Nlc3NFeGl0TGlzdGVuZXJzKCk7XHJcbiAgfVxyXG5cclxuICAvLyBDaGVjayBpZiBjYWNoZSBuZWVkcyB0byBiZSB1cGRhdGVkXHJcbiAgYXdhaXQgY2hlY2tBbmRVcGRhdGVDYWNoZShvcHRpb25zLmhpZ2hjaGFydHMsIG9wdGlvbnMuc2VydmVyLnByb3h5KTtcclxuXHJcbiAgLy8gSW5pdCB0aGUgcG9vbFxyXG4gIGF3YWl0IGluaXRQb29sKG9wdGlvbnMucG9vbCwgb3B0aW9ucy5wdXBwZXRlZXIuYXJncyk7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBBdHRhY2hlcyBleGl0IGxpc3RlbmVycyB0byB0aGUgcHJvY2VzcywgZW5zdXJpbmcgcHJvcGVyIGNsZWFudXAgb2YgcmVzb3VyY2VzXHJcbiAqIGFuZCB0ZXJtaW5hdGlvbiBvbiBleGl0IHNpZ25hbHMuIEhhbmRsZXMgJ2V4aXQnLCAnU0lHSU5UJywgJ1NJR1RFUk0nXHJcbiAqIGFuZCAndW5jYXVnaHRFeGNlcHRpb24nIGV2ZW50cy5cclxuICpcclxuICogQGZ1bmN0aW9uIF9hdHRhY2hQcm9jZXNzRXhpdExpc3RlbmVyc1xyXG4gKi9cclxuZnVuY3Rpb24gX2F0dGFjaFByb2Nlc3NFeGl0TGlzdGVuZXJzKCkge1xyXG4gIGxvZygzLCAnW3Byb2Nlc3NdIEF0dGFjaGluZyBleGl0IGxpc3RlbmVycyB0byB0aGUgcHJvY2Vzcy4nKTtcclxuXHJcbiAgLy8gSGFuZGxlciBmb3IgdGhlICdleGl0J1xyXG4gIHByb2Nlc3Mub24oJ2V4aXQnLCAoY29kZSkgPT4ge1xyXG4gICAgbG9nKDQsIGBbcHJvY2Vzc10gUHJvY2VzcyBleGl0ZWQgd2l0aCBjb2RlICR7Y29kZX0uYCk7XHJcbiAgfSk7XHJcblxyXG4gIC8vIEhhbmRsZXIgZm9yIHRoZSAnU0lHSU5UJ1xyXG4gIHByb2Nlc3Mub24oJ1NJR0lOVCcsIGFzeW5jIChuYW1lLCBjb2RlKSA9PiB7XHJcbiAgICBsb2coNCwgYFtwcm9jZXNzXSBUaGUgJHtuYW1lfSBldmVudCB3aXRoIGNvZGU6ICR7Y29kZX0uYCk7XHJcbiAgICBhd2FpdCBzaHV0ZG93bkNsZWFuVXAoKTtcclxuICB9KTtcclxuXHJcbiAgLy8gSGFuZGxlciBmb3IgdGhlICdTSUdURVJNJ1xyXG4gIHByb2Nlc3Mub24oJ1NJR1RFUk0nLCBhc3luYyAobmFtZSwgY29kZSkgPT4ge1xyXG4gICAgbG9nKDQsIGBbcHJvY2Vzc10gVGhlICR7bmFtZX0gZXZlbnQgd2l0aCBjb2RlOiAke2NvZGV9LmApO1xyXG4gICAgYXdhaXQgc2h1dGRvd25DbGVhblVwKCk7XHJcbiAgfSk7XHJcblxyXG4gIC8vIEhhbmRsZXIgZm9yIHRoZSAnU0lHSFVQJ1xyXG4gIHByb2Nlc3Mub24oJ1NJR0hVUCcsIGFzeW5jIChuYW1lLCBjb2RlKSA9PiB7XHJcbiAgICBsb2coNCwgYFtwcm9jZXNzXSBUaGUgJHtuYW1lfSBldmVudCB3aXRoIGNvZGU6ICR7Y29kZX0uYCk7XHJcbiAgICBhd2FpdCBzaHV0ZG93bkNsZWFuVXAoKTtcclxuICB9KTtcclxuXHJcbiAgLy8gSGFuZGxlciBmb3IgdGhlICd1bmNhdWdodEV4Y2VwdGlvbidcclxuICBwcm9jZXNzLm9uKCd1bmNhdWdodEV4Y2VwdGlvbicsIGFzeW5jIChlcnJvciwgbmFtZSkgPT4ge1xyXG4gICAgbG9nV2l0aFN0YWNrKDEsIGVycm9yLCBgW3Byb2Nlc3NdIFRoZSAke25hbWV9IGVycm9yLmApO1xyXG4gICAgYXdhaXQgc2h1dGRvd25DbGVhblVwKDEpO1xyXG4gIH0pO1xyXG59XHJcblxyXG5leHBvcnQgZGVmYXVsdCB7XHJcbiAgLy8gU2VydmVyXHJcbiAgLi4uc2VydmVyLFxyXG5cclxuICAvLyBPcHRpb25zXHJcbiAgZ2V0T3B0aW9ucyxcclxuICBzZXRHbG9iYWxPcHRpb25zLFxyXG4gIG1hcFRvTmV3T3B0aW9ucyxcclxuXHJcbiAgLy8gRXhwb3J0aW5nXHJcbiAgaW5pdEV4cG9ydCxcclxuICBzaW5nbGVFeHBvcnQsXHJcbiAgYmF0Y2hFeHBvcnQsXHJcbiAgc3RhcnRFeHBvcnQsXHJcblxyXG4gIC8vIFJlbGVhc2VcclxuICBraWxsUG9vbCxcclxuICBzaHV0ZG93bkNsZWFuVXAsXHJcblxyXG4gIC8vIExvZ3NcclxuICBsb2csXHJcbiAgbG9nV2l0aFN0YWNrLFxyXG4gIGxvZ1pvZElzc3VlcyxcclxuICBzZXRMb2dMZXZlbDogZnVuY3Rpb24gKGxldmVsKSB7XHJcbiAgICAvLyBVcGRhdGUgdGhlIGluc3RhbmNlIG9wdGlvbnMgb2JqZWN0XHJcbiAgICBjb25zdCBvcHRpb25zID0gdXBkYXRlT3B0aW9ucyh7XHJcbiAgICAgIGxvZ2dpbmc6IHtcclxuICAgICAgICBsZXZlbFxyXG4gICAgICB9XHJcbiAgICB9KTtcclxuXHJcbiAgICAvLyBDYWxsIHRoZSBmdW5jdGlvblxyXG4gICAgc2V0TG9nTGV2ZWwob3B0aW9ucy5sb2dnaW5nLmxldmVsKTtcclxuICB9LFxyXG4gIGVuYWJsZUNvbnNvbGVMb2dnaW5nOiBmdW5jdGlvbiAodG9Db25zb2xlKSB7XHJcbiAgICAvLyBVcGRhdGUgdGhlIGluc3RhbmNlIG9wdGlvbnMgb2JqZWN0XHJcbiAgICBjb25zdCBvcHRpb25zID0gdXBkYXRlT3B0aW9ucyh7XHJcbiAgICAgIGxvZ2dpbmc6IHtcclxuICAgICAgICB0b0NvbnNvbGVcclxuICAgICAgfVxyXG4gICAgfSk7XHJcblxyXG4gICAgLy8gQ2FsbCB0aGUgZnVuY3Rpb25cclxuICAgIGVuYWJsZUNvbnNvbGVMb2dnaW5nKG9wdGlvbnMubG9nZ2luZy50b0NvbnNvbGUpO1xyXG4gIH0sXHJcbiAgZW5hYmxlRmlsZUxvZ2dpbmc6IGZ1bmN0aW9uIChkZXN0LCBmaWxlLCB0b0ZpbGUpIHtcclxuICAgIC8vIFVwZGF0ZSB0aGUgaW5zdGFuY2Ugb3B0aW9ucyBvYmplY3RcclxuICAgIGNvbnN0IG9wdGlvbnMgPSB1cGRhdGVPcHRpb25zKHtcclxuICAgICAgbG9nZ2luZzoge1xyXG4gICAgICAgIGRlc3QsXHJcbiAgICAgICAgZmlsZSxcclxuICAgICAgICB0b0ZpbGVcclxuICAgICAgfVxyXG4gICAgfSk7XHJcblxyXG4gICAgLy8gQ2FsbCB0aGUgZnVuY3Rpb25cclxuICAgIGVuYWJsZUZpbGVMb2dnaW5nKFxyXG4gICAgICBvcHRpb25zLmxvZ2dpbmcuZGVzdCxcclxuICAgICAgb3B0aW9ucy5sb2dnaW5nLmZpbGUsXHJcbiAgICAgIG9wdGlvbnMubG9nZ2luZy50b0ZpbGVcclxuICAgICk7XHJcbiAgfVxyXG59O1xyXG4iXSwibmFtZXMiOlsiX19kaXJuYW1lIiwiZmlsZVVSTFRvUGF0aCIsIlVSTCIsImRvY3VtZW50IiwicmVxdWlyZSIsInBhdGhUb0ZpbGVVUkwiLCJfX2ZpbGVuYW1lIiwiaHJlZiIsIl9kb2N1bWVudEN1cnJlbnRTY3JpcHQiLCJ0YWdOYW1lIiwidG9VcHBlckNhc2UiLCJzcmMiLCJiYXNlVVJJIiwiZGVlcENvcHkiLCJvYmpBcnIiLCJvYmpBcnJDb3B5IiwiQXJyYXkiLCJpc0FycmF5Iiwia2V5IiwiT2JqZWN0IiwicHJvdG90eXBlIiwiaGFzT3duUHJvcGVydHkiLCJjYWxsIiwiZml4Q29uc3RyIiwiY29uc3RyIiwiZml4ZWRDb25zdHIiLCJ0b0xvd2VyQ2FzZSIsInJlcGxhY2UiLCJpbmNsdWRlcyIsImZpeE91dGZpbGUiLCJ0eXBlIiwib3V0ZmlsZSIsImdldEFic29sdXRlUGF0aCIsInNwbGl0Iiwic2hpZnQiLCJmaXhUeXBlIiwibWltZVR5cGVzIiwiZm9ybWF0cyIsInZhbHVlcyIsIm91dFR5cGUiLCJwb3AiLCJmaW5kIiwidCIsInBhdGgiLCJpc0Fic29sdXRlIiwiam9pbiIsImdldEJhc2U2NCIsImlucHV0IiwiQnVmZmVyIiwiZnJvbSIsInRvU3RyaW5nIiwiZ2V0TmV3RGF0ZSIsIkRhdGUiLCJ0cmltIiwiZ2V0TmV3RGF0ZVRpbWUiLCJnZXRUaW1lIiwiaXNPYmplY3QiLCJpdGVtIiwiaXNPYmplY3RFbXB0eSIsImtleXMiLCJsZW5ndGgiLCJpc1ByaXZhdGVSYW5nZVVybEZvdW5kIiwic29tZSIsInBhdHRlcm4iLCJ0ZXN0IiwibWVhc3VyZVRpbWUiLCJzdGFydCIsInByb2Nlc3MiLCJocnRpbWUiLCJiaWdpbnQiLCJOdW1iZXIiLCJyb3VuZE51bWJlciIsInZhbHVlIiwicHJlY2lzaW9uIiwibXVsdGlwbGllciIsIk1hdGgiLCJwb3ciLCJyb3VuZCIsIndyYXBBcm91bmQiLCJjdXN0b21Db2RlIiwiYWxsb3dGaWxlUmVzb3VyY2VzIiwiaXNDYWxsYmFjayIsImVuZHNXaXRoIiwicmVhZEZpbGVTeW5jIiwic3RhcnRzV2l0aCIsImNvbG9ycyIsImxvZ2dpbmciLCJ0b0NvbnNvbGUiLCJ0b0ZpbGUiLCJwYXRoQ3JlYXRlZCIsInBhdGhUb0xvZyIsImxldmVsc0Rlc2MiLCJ0aXRsZSIsImNvbG9yIiwibG9nIiwiYXJncyIsIm5ld0xldmVsIiwidGV4dHMiLCJsZXZlbCIsInByZWZpeCIsIl9sb2dUb0ZpbGUiLCJjb25zb2xlIiwiYXBwbHkiLCJ1bmRlZmluZWQiLCJjb25jYXQiLCJsb2dXaXRoU3RhY2siLCJlcnJvciIsImN1c3RvbU1lc3NhZ2UiLCJtYWluTWVzc2FnZSIsIm1lc3NhZ2UiLCJzdGFja01lc3NhZ2UiLCJzdGFjayIsInB1c2giLCJsb2dab2RJc3N1ZXMiLCJpc3N1ZXMiLCJtYXAiLCJpc3N1ZSIsImluaXRMb2dnaW5nIiwibG9nZ2luZ09wdGlvbnMiLCJkZXN0IiwiZmlsZSIsInNldExvZ0xldmVsIiwiZW5hYmxlQ29uc29sZUxvZ2dpbmciLCJlbmFibGVGaWxlTG9nZ2luZyIsImlzSW50ZWdlciIsImV4aXN0c1N5bmMiLCJta2RpclN5bmMiLCJhcHBlbmRGaWxlIiwiZGVmYXVsdENvbmZpZyIsInB1cHBldGVlciIsInR5cGVzIiwiZW52TGluayIsImNsaU5hbWUiLCJkZXNjcmlwdGlvbiIsInByb21wdE9wdGlvbnMiLCJzZXBhcmF0b3IiLCJoaWdoY2hhcnRzIiwidmVyc2lvbiIsImNkblVybCIsImZvcmNlRmV0Y2giLCJjYWNoZVBhdGgiLCJjb3JlU2NyaXB0cyIsImluc3RydWN0aW9ucyIsIm1vZHVsZVNjcmlwdHMiLCJpbmRpY2F0b3JTY3JpcHRzIiwiY3VzdG9tU2NyaXB0cyIsImV4cG9ydCIsImluZmlsZSIsImluc3RyIiwib3B0aW9ucyIsInN2ZyIsImJhdGNoIiwiaGludCIsImNob2ljZXMiLCJiNjQiLCJub0Rvd25sb2FkIiwiaGVpZ2h0Iiwid2lkdGgiLCJzY2FsZSIsImRlZmF1bHRIZWlnaHQiLCJkZWZhdWx0V2lkdGgiLCJkZWZhdWx0U2NhbGUiLCJtaW4iLCJtYXgiLCJnbG9iYWxPcHRpb25zIiwidGhlbWVPcHRpb25zIiwicmFzdGVyaXphdGlvblRpbWVvdXQiLCJjdXN0b21Mb2dpYyIsImFsbG93Q29kZUV4ZWN1dGlvbiIsImNhbGxiYWNrIiwicmVzb3VyY2VzIiwibG9hZENvbmZpZyIsImxlZ2FjeU5hbWUiLCJjcmVhdGVDb25maWciLCJzZXJ2ZXIiLCJlbmFibGUiLCJob3N0IiwicG9ydCIsInVwbG9hZExpbWl0IiwiYmVuY2htYXJraW5nIiwicHJveHkiLCJ0aW1lb3V0IiwicmF0ZUxpbWl0aW5nIiwibWF4UmVxdWVzdHMiLCJ3aW5kb3ciLCJkZWxheSIsInRydXN0UHJveHkiLCJza2lwS2V5Iiwic2tpcFRva2VuIiwic3NsIiwiZm9yY2UiLCJjZXJ0UGF0aCIsInBvb2wiLCJtaW5Xb3JrZXJzIiwibWF4V29ya2VycyIsIndvcmtMaW1pdCIsImFjcXVpcmVUaW1lb3V0IiwiY3JlYXRlVGltZW91dCIsImRlc3Ryb3lUaW1lb3V0IiwiaWRsZVRpbWVvdXQiLCJjcmVhdGVSZXRyeUludGVydmFsIiwicmVhcGVySW50ZXJ2YWwiLCJ1aSIsInJvdXRlIiwib3RoZXIiLCJub2RlRW52IiwibGlzdGVuVG9Qcm9jZXNzRXhpdHMiLCJub0xvZ28iLCJoYXJkUmVzZXRQYWdlIiwiYnJvd3NlclNoZWxsTW9kZSIsImRlYnVnIiwiaGVhZGxlc3MiLCJkZXZ0b29scyIsImxpc3RlblRvQ29uc29sZSIsImR1bXBpbyIsInNsb3dNbyIsImRlYnVnZ2luZ1BvcnQiLCJuZXN0ZWRQcm9wcyIsIl9jcmVhdGVOZXN0ZWRQcm9wcyIsImFic29sdXRlUHJvcHMiLCJfY3JlYXRlQWJzb2x1dGVQcm9wcyIsImNvbmZpZyIsInByb3BDaGFpbiIsImZvckVhY2giLCJlbnRyeSIsInN1YnN0cmluZyIsImRvdGVudiIsInoiLCJzZXRFcnJvck1hcCIsIl9jdXN0b21FcnJvck1hcCIsInYiLCJib29sZWFuIiwic3RyaWN0Q2hlY2siLCJ1bmlvbiIsImVudW0iLCJ0cmFuc2Zvcm0iLCJudWxsYWJsZSIsInN0cmluZyIsInJlZmluZSIsInBhcmFtcyIsImVycm9yTWVzc2FnZSIsInN0cmluZ0FycmF5IiwiZmlsdGVyQ2FsbGJhY2siLCJhcnJheVNjaGVtYSIsImFycmF5Iiwic3RyaW5nU2NoZW1hIiwic2xpY2UiLCJ0cmFuc2Zvcm1DYWxsYmFjayIsImZpbHRlciIsInBvc2l0aXZlTnVtIiwibnVtYmVyIiwicG9zaXRpdmUiLCJpc05hTiIsIm5vbk5lZ2F0aXZlTnVtIiwibm9ubmVnYXRpdmUiLCJwcmVmaXhlcyIsImNoYXJ0Q29uZmlnIiwiaW5kZXhPZiIsIm9iamVjdCIsInBhc3N0aHJvdWdoIiwiYWRkaXRpb25hbE9wdGlvbnMiLCJhZG1pblRva2VuIiwiZ3RlIiwibHRlIiwidGhpcyIsIm9iamVjdFNjaGVtYSIsImpzIiwiY3NzIiwiZmlsZXMiLCJwYXJ0aWFsIiwic3RyaW5nU2NoZW1hMSIsInN0cmluZ1NjaGVtYTIiLCJlbmFibGVTZXJ2ZXIiLCJzZXJ2ZXJCZW5jaG1hcmtpbmciLCJwcm94eUhvc3QiLCJwcm94eVBvcnQiLCJwcm94eVRpbWVvdXQiLCJlbmFibGVSYXRlTGltaXRpbmciLCJlbmFibGVTc2wiLCJzc2xGb3JjZSIsInNzbFBvcnQiLCJzc2xDZXJ0UGF0aCIsInBvb2xCZW5jaG1hcmtpbmciLCJyZXNvdXJjZXNJbnRlcnZhbCIsImxvZ0xldmVsIiwiaW50IiwibG9nRmlsZSIsImxvZ0Rlc3QiLCJsb2dUb0NvbnNvbGUiLCJsb2dUb0ZpbGUiLCJlbmFibGVVaSIsInVpUm91dGUiLCJlbmFibGVEZWJ1ZyIsInJlcXVlc3RJZCIsInV1aWQiLCJQdXBwZXRlZXJTY2hlbWEiLCJIaWdoY2hhcnRzU2NoZW1hIiwiRXhwb3J0U2NoZW1hIiwiQ3VzdG9tTG9naWNTY2hlbWEiLCJQcm94eVNjaGVtYSIsIlJhdGVMaW1pdGluZ1NjaGVtYSIsIlNzbFNjaGVtYSIsIlNlcnZlclNjaGVtYSIsIm9wdGlvbmFsIiwiUG9vbFNjaGVtYSIsIkxvZ2dpbmdTY2hlbWEiLCJVaVNjaGVtYSIsIk90aGVyU2NoZW1hIiwiRGVidWdTY2hlbWEiLCJTdHJpY3RDb25maWdTY2hlbWEiLCJMb29zZUNvbmZpZ1NjaGVtYSIsIkVudlNjaGVtYSIsIlBVUFBFVEVFUl9BUkdTIiwiSElHSENIQVJUU19WRVJTSU9OIiwiSElHSENIQVJUU19DRE5fVVJMIiwiSElHSENIQVJUU19GT1JDRV9GRVRDSCIsIkhJR0hDSEFSVFNfQ0FDSEVfUEFUSCIsIkhJR0hDSEFSVFNfQURNSU5fVE9LRU4iLCJISUdIQ0hBUlRTX0NPUkVfU0NSSVBUUyIsIkhJR0hDSEFSVFNfTU9EVUxFX1NDUklQVFMiLCJISUdIQ0hBUlRTX0lORElDQVRPUl9TQ1JJUFRTIiwiSElHSENIQVJUU19DVVNUT01fU0NSSVBUUyIsIkVYUE9SVF9JTkZJTEUiLCJFWFBPUlRfSU5TVFIiLCJFWFBPUlRfT1BUSU9OUyIsIkVYUE9SVF9TVkciLCJFWFBPUlRfQkFUQ0giLCJFWFBPUlRfT1VURklMRSIsIkVYUE9SVF9UWVBFIiwiRVhQT1JUX0NPTlNUUiIsIkVYUE9SVF9CNjQiLCJFWFBPUlRfTk9fRE9XTkxPQUQiLCJFWFBPUlRfSEVJR0hUIiwiRVhQT1JUX1dJRFRIIiwiRVhQT1JUX1NDQUxFIiwiRVhQT1JUX0RFRkFVTFRfSEVJR0hUIiwiRVhQT1JUX0RFRkFVTFRfV0lEVEgiLCJFWFBPUlRfREVGQVVMVF9TQ0FMRSIsIkVYUE9SVF9HTE9CQUxfT1BUSU9OUyIsIkVYUE9SVF9USEVNRV9PUFRJT05TIiwiRVhQT1JUX1JBU1RFUklaQVRJT05fVElNRU9VVCIsIkNVU1RPTV9MT0dJQ19BTExPV19DT0RFX0VYRUNVVElPTiIsIkNVU1RPTV9MT0dJQ19BTExPV19GSUxFX1JFU09VUkNFUyIsIkNVU1RPTV9MT0dJQ19DVVNUT01fQ09ERSIsIkNVU1RPTV9MT0dJQ19DQUxMQkFDSyIsIkNVU1RPTV9MT0dJQ19SRVNPVVJDRVMiLCJDVVNUT01fTE9HSUNfTE9BRF9DT05GSUciLCJDVVNUT01fTE9HSUNfQ1JFQVRFX0NPTkZJRyIsIlNFUlZFUl9FTkFCTEUiLCJTRVJWRVJfSE9TVCIsIlNFUlZFUl9QT1JUIiwiU0VSVkVSX1VQTE9BRF9MSU1JVCIsIlNFUlZFUl9CRU5DSE1BUktJTkciLCJTRVJWRVJfUFJPWFlfSE9TVCIsIlNFUlZFUl9QUk9YWV9QT1JUIiwiU0VSVkVSX1BST1hZX1RJTUVPVVQiLCJTRVJWRVJfUkFURV9MSU1JVElOR19FTkFCTEUiLCJTRVJWRVJfUkFURV9MSU1JVElOR19NQVhfUkVRVUVTVFMiLCJTRVJWRVJfUkFURV9MSU1JVElOR19XSU5ET1ciLCJTRVJWRVJfUkFURV9MSU1JVElOR19ERUxBWSIsIlNFUlZFUl9SQVRFX0xJTUlUSU5HX1RSVVNUX1BST1hZIiwiU0VSVkVSX1JBVEVfTElNSVRJTkdfU0tJUF9LRVkiLCJTRVJWRVJfUkFURV9MSU1JVElOR19TS0lQX1RPS0VOIiwiU0VSVkVSX1NTTF9FTkFCTEUiLCJTRVJWRVJfU1NMX0ZPUkNFIiwiU0VSVkVSX1NTTF9QT1JUIiwiU0VSVkVSX1NTTF9DRVJUX1BBVEgiLCJQT09MX01JTl9XT1JLRVJTIiwiUE9PTF9NQVhfV09SS0VSUyIsIlBPT0xfV09SS19MSU1JVCIsIlBPT0xfQUNRVUlSRV9USU1FT1VUIiwiUE9PTF9DUkVBVEVfVElNRU9VVCIsIlBPT0xfREVTVFJPWV9USU1FT1VUIiwiUE9PTF9JRExFX1RJTUVPVVQiLCJQT09MX0NSRUFURV9SRVRSWV9JTlRFUlZBTCIsIlBPT0xfUkVBUEVSX0lOVEVSVkFMIiwiUE9PTF9CRU5DSE1BUktJTkciLCJMT0dHSU5HX0xFVkVMIiwiTE9HR0lOR19GSUxFIiwiTE9HR0lOR19ERVNUIiwiTE9HR0lOR19UT19DT05TT0xFIiwiTE9HR0lOR19UT19GSUxFIiwiVUlfRU5BQkxFIiwiVUlfUk9VVEUiLCJPVEhFUl9OT0RFX0VOViIsIk9USEVSX0xJU1RFTl9UT19QUk9DRVNTX0VYSVRTIiwiT1RIRVJfTk9fTE9HTyIsIk9USEVSX0hBUkRfUkVTRVRfUEFHRSIsIk9USEVSX0JST1dTRVJfU0hFTExfTU9ERSIsIkRFQlVHX0VOQUJMRSIsIkRFQlVHX0hFQURMRVNTIiwiREVCVUdfREVWVE9PTFMiLCJERUJVR19MSVNURU5fVE9fQ09OU09MRSIsIkRFQlVHX0RVTVBJTyIsIkRFQlVHX1NMT1dfTU8iLCJERUJVR19ERUJVR0dJTkdfUE9SVCIsImVudnMiLCJwYXJzZSIsImVudiIsInN0cmljdFZhbGlkYXRlIiwiY29uZmlnT3B0aW9ucyIsImxvb3NlVmFsaWRhdGUiLCJ2YWxpZGF0ZU9wdGlvbiIsIm5hbWUiLCJvcHRpb24iLCJjb250ZXh0IiwicHJvcGVydHlOYW1lIiwicHJvcGVydHlJbmZvIiwiY29kZSIsIlpvZElzc3VlQ29kZSIsImludmFsaWRfdHlwZSIsInJlY2VpdmVkIiwiWm9kUGFyc2VkVHlwZSIsImRlZmF1bHRFcnJvciIsImN1c3RvbSIsImRhdGEiLCJpbnZhbGlkX3VuaW9uIiwidW5pb25FcnJvcnMiLCJpbmRleCIsIl9pbml0R2xvYmFsT3B0aW9ucyIsImluc3RhbmNlT3B0aW9ucyIsImdldE9wdGlvbnMiLCJnZXRJbnN0YW5jZSIsInNldEdsb2JhbE9wdGlvbnMiLCJjdXN0b21PcHRpb25zIiwiY2xpQXJncyIsImNsaU9wdGlvbnMiLCJfbG9hZENvbmZpZ0ZpbGUiLCJfcGFpckFyZ3VtZW50VmFsdWUiLCJfdXBkYXRlR2xvYmFsT3B0aW9ucyIsInVwZGF0ZU9wdGlvbnMiLCJuZXdJbnN0YW5jZSIsIm1lcmdlT3B0aW9ucyIsIm9yaWdpbmFsT3B0aW9ucyIsIm5ld09wdGlvbnMiLCJlbnRyaWVzIiwibWFwVG9OZXdPcHRpb25zIiwib2xkT3B0aW9ucyIsInByb3BlcnRpZXNDaGFpbiIsInJlZHVjZSIsIm9iaiIsInByb3AiLCJpc0FsbG93ZWRDb25maWciLCJhbGxvd0Z1bmN0aW9ucyIsIm9iamVjdENvbmZpZyIsImV2YWwiLCJKU09OIiwic3RyaW5naWZpZWRPcHRpb25zIiwiX29wdGlvbnNTdHJpbmdpZnkiLCJwYXJzZWRPcHRpb25zIiwiXyIsImVudlZhbCIsImNvbmZpZ09wdCIsImNsaU9wdCIsImN1c3RvbU9wdCIsImNvbmZpZ1ZhbCIsImNsaVZhbCIsImN1c3RvbVZhbCIsInN0cmluZ2lmeUZ1bmN0aW9ucyIsInN0cmluZ2lmeSIsInJlcGxhY2VBbGwiLCJFcnJvciIsImN1c3RvbUxvZ2ljT3B0aW9ucyIsImNvbmZpZ0luZGV4IiwiZmluZEluZGV4IiwiYXJnIiwiaSIsImFzeW5jIiwiZmV0Y2giLCJ1cmwiLCJyZXF1ZXN0T3B0aW9ucyIsIlByb21pc2UiLCJyZXNvbHZlIiwicmVqZWN0IiwiX2dldFByb3RvY29sTW9kdWxlIiwiZ2V0IiwicmVzcG9uc2UiLCJyZXNwb25zZURhdGEiLCJvbiIsImNodW5rIiwidGV4dCIsImh0dHBzIiwiaHR0cCIsIkV4cG9ydEVycm9yIiwiY29uc3RydWN0b3IiLCJzdGF0dXNDb2RlIiwic3VwZXIiLCJzZXRTdGF0dXMiLCJzZXRFcnJvciIsImNhY2hlIiwiYWN0aXZlTWFuaWZlc3QiLCJzb3VyY2VzIiwiaGNWZXJzaW9uIiwiY2hlY2tBbmRVcGRhdGVDYWNoZSIsImhpZ2hjaGFydHNPcHRpb25zIiwic2VydmVyUHJveHlPcHRpb25zIiwiZmV0Y2hlZE1vZHVsZXMiLCJnZXRDYWNoZVBhdGgiLCJtYW5pZmVzdFBhdGgiLCJzb3VyY2VQYXRoIiwicmVjdXJzaXZlIiwiX3VwZGF0ZUNhY2hlIiwicmVxdWVzdFVwZGF0ZSIsIm1hbmlmZXN0IiwibW9kdWxlcyIsIm1vZHVsZU1hcCIsIm0iLCJudW1iZXJPZk1vZHVsZXMiLCJtb2R1bGVOYW1lIiwiZXh0cmFjdFZlcnNpb24iLCJfc2F2ZUNvbmZpZ1RvTWFuaWZlc3QiLCJnZXRIaWdoY2hhcnRzVmVyc2lvbiIsInVwZGF0ZUhpZ2hjaGFydHNWZXJzaW9uIiwibmV3VmVyc2lvbiIsImNhY2hlU291cmNlcyIsImV4dHJhY3RNb2R1bGVOYW1lIiwic2NyaXB0UGF0aCIsIl9mZXRjaEFuZFByb2Nlc3NTY3JpcHQiLCJzY3JpcHQiLCJzaG91bGRUaHJvd0Vycm9yIiwibmV3TWFuaWZlc3QiLCJ3cml0ZUZpbGVTeW5jIiwiX2ZldGNoU2NyaXB0cyIsInByb3h5QWdlbnQiLCJIdHRwc1Byb3h5QWdlbnQiLCJhZ2VudCIsImFsbEZldGNoUHJvbWlzZXMiLCJhbGwiLCJjIiwic2V0dXBIaWdoY2hhcnRzIiwiSGlnaGNoYXJ0cyIsImFuaW1PYmplY3QiLCJkdXJhdGlvbiIsImNyZWF0ZUNoYXJ0IiwiZXhwb3J0T3B0aW9ucyIsInNldE9wdGlvbnMiLCJtZXJnZSIsIndyYXAiLCJzZXRPcHRpb25zT2JqIiwiaXNSZW5kZXJDb21wbGV0ZSIsIkNoYXJ0IiwicHJvY2VlZCIsInVzZXJPcHRpb25zIiwiY2IiLCJleHBvcnRpbmciLCJlbmFibGVkIiwicGxvdE9wdGlvbnMiLCJzZXJpZXMiLCJsYWJlbCIsInRvb2x0aXAiLCJhbmltYXRpb24iLCJvbkhpZ2hjaGFydHNSZW5kZXIiLCJhZGRFdmVudCIsIlNlcmllcyIsImNoYXJ0IiwiRnVuY3Rpb24iLCJmaW5hbE9wdGlvbnMiLCJmaW5hbENhbGxiYWNrIiwiZGVmYXVsdE9wdGlvbnMiLCJ0ZW1wbGF0ZSIsImJyb3dzZXIiLCJjcmVhdGVCcm93c2VyIiwicHVwcGV0ZWVyQXJncyIsImVuYWJsZWREZWJ1ZyIsImRlYnVnT3B0aW9ucyIsImxhdW5jaE9wdGlvbnMiLCJ1c2VyRGF0YURpciIsImhhbmRsZVNJR0lOVCIsImhhbmRsZVNJR1RFUk0iLCJoYW5kbGVTSUdIVVAiLCJ3YWl0Rm9ySW5pdGlhbFBhZ2UiLCJkZWZhdWx0Vmlld3BvcnQiLCJ0cnlDb3VudCIsIm9wZW4iLCJsYXVuY2giLCJzZXRUaW1lb3V0IiwiY2xvc2VCcm93c2VyIiwiY29ubmVjdGVkIiwiY2xvc2UiLCJuZXdQYWdlIiwicG9vbFJlc291cmNlIiwicGFnZSIsInNldENhY2hlRW5hYmxlZCIsIl9zZXRQYWdlQ29udGVudCIsIl9zZXRQYWdlRXZlbnRzIiwiaXNDbG9zZWQiLCJjbGVhclBhZ2UiLCJoYXJkUmVzZXQiLCJnb3RvIiwid2FpdFVudGlsIiwiZXZhbHVhdGUiLCJib2R5IiwiaW5uZXJIVE1MIiwiaWQiLCJ3b3JrQ291bnQiLCJhZGRQYWdlUmVzb3VyY2VzIiwiaW5qZWN0ZWRSZXNvdXJjZXMiLCJpbmplY3RlZEpzIiwiY29udGVudCIsImlzTG9jYWwiLCJqc1Jlc291cmNlIiwiYWRkU2NyaXB0VGFnIiwiaW5qZWN0ZWRDc3MiLCJjc3NJbXBvcnRzIiwibWF0Y2giLCJjc3NJbXBvcnRQYXRoIiwiY3NzUmVzb3VyY2UiLCJhZGRTdHlsZVRhZyIsImNsZWFyUGFnZVJlc291cmNlcyIsInJlc291cmNlIiwiZGlzcG9zZSIsIm9sZENoYXJ0cyIsImNoYXJ0cyIsIm9sZENoYXJ0IiwiZGVzdHJveSIsInNjcmlwdHNUb1JlbW92ZSIsImdldEVsZW1lbnRzQnlUYWdOYW1lIiwic3R5bGVzVG9SZW1vdmUiLCJsaW5rc1RvUmVtb3ZlIiwiZWxlbWVudCIsInJlbW92ZSIsInNldENvbnRlbnQiLCJjc3NUZW1wbGF0ZSIsInN2Z1RlbXBsYXRlIiwicHVwcGV0ZWVyRXhwb3J0IiwiaXNTVkciLCJzaXplIiwic3ZnRWxlbWVudCIsInF1ZXJ5U2VsZWN0b3IiLCJjaGFydEhlaWdodCIsImJhc2VWYWwiLCJjaGFydFdpZHRoIiwic3R5bGUiLCJ6b29tIiwibWFyZ2luIiwicGFyc2VGbG9hdCIsIngiLCJ5IiwiX2dldENsaXBSZWdpb24iLCJ2aWV3cG9ydEhlaWdodCIsImFicyIsImNlaWwiLCJ2aWV3cG9ydFdpZHRoIiwicmVzdWx0Iiwic2V0Vmlld3BvcnQiLCJkZXZpY2VTY2FsZUZhY3RvciIsIl9jcmVhdGVTVkciLCJfY3JlYXRlSW1hZ2UiLCJfY3JlYXRlUERGIiwiJGV2YWwiLCJnZXRCb3VuZGluZ0NsaWVudFJlY3QiLCJ0cnVuYyIsIm91dGVySFRNTCIsImNsaXAiLCJyYWNlIiwic2NyZWVuc2hvdCIsImVuY29kaW5nIiwiZnVsbFBhZ2UiLCJvcHRpbWl6ZUZvclNwZWVkIiwiY2FwdHVyZUJleW9uZFZpZXdwb3J0IiwicXVhbGl0eSIsIm9taXRCYWNrZ3JvdW5kIiwiX3Jlc29sdmUiLCJlbXVsYXRlTWVkaWFUeXBlIiwicGRmIiwicG9vbFN0YXRzIiwiZXhwb3J0c0F0dGVtcHRlZCIsImV4cG9ydHNQZXJmb3JtZWQiLCJleHBvcnRzRHJvcHBlZCIsImV4cG9ydHNGcm9tU3ZnIiwiZXhwb3J0c0Zyb21PcHRpb25zIiwiZXhwb3J0c0Zyb21TdmdBdHRlbXB0cyIsImV4cG9ydHNGcm9tT3B0aW9uc0F0dGVtcHRzIiwidGltZVNwZW50IiwidGltZVNwZW50QXZlcmFnZSIsImluaXRQb29sIiwicG9vbE9wdGlvbnMiLCJQb29sIiwiX2ZhY3RvcnkiLCJhY3F1aXJlVGltZW91dE1pbGxpcyIsImNyZWF0ZVRpbWVvdXRNaWxsaXMiLCJkZXN0cm95VGltZW91dE1pbGxpcyIsImlkbGVUaW1lb3V0TWlsbGlzIiwiY3JlYXRlUmV0cnlJbnRlcnZhbE1pbGxpcyIsInJlYXBJbnRlcnZhbE1pbGxpcyIsInByb3BhZ2F0ZUNyZWF0ZUVycm9yIiwiY2xlYXJTdGF0dXMiLCJfZXZlbnRJZCIsImluaXRpYWxSZXNvdXJjZXMiLCJhY3F1aXJlIiwicHJvbWlzZSIsInJlbGVhc2UiLCJraWxsUG9vbCIsIndvcmtlciIsInVzZWQiLCJkZXN0cm95ZWQiLCJwb3N0V29yayIsIndvcmtlckhhbmRsZSIsImdldFBvb2xJbmZvIiwiYWNxdWlyZUNvdW50ZXIiLCJ3b3JrU3RhcnQiLCJleHBvcnRDb3VudGVyIiwiZXhwb3J0VGltZSIsImdldFBvb2xTdGF0cyIsImdldFBvb2xJbmZvSlNPTiIsIm51bVVzZWQiLCJhdmFpbGFibGUiLCJudW1GcmVlIiwiYWxsQ3JlYXRlZCIsInBlbmRpbmdBY3F1aXJlcyIsIm51bVBlbmRpbmdBY3F1aXJlcyIsInBlbmRpbmdDcmVhdGVzIiwibnVtUGVuZGluZ0NyZWF0ZXMiLCJwZW5kaW5nVmFsaWRhdGlvbnMiLCJudW1QZW5kaW5nVmFsaWRhdGlvbnMiLCJwZW5kaW5nRGVzdHJveXMiLCJhYnNvbHV0ZUFsbCIsImNyZWF0ZSIsInJhbmRvbSIsInN0YXJ0RGF0ZSIsInZhbGlkYXRlIiwibWFpbkZyYW1lIiwiZGV0YWNoZWQiLCJyZW1vdmVBbGxMaXN0ZW5lcnMiLCJzYW5pdGl6ZSIsIkpTRE9NIiwiRE9NUHVyaWZ5IiwiQUREX1RBR1MiLCJzaW5nbGVFeHBvcnQiLCJzdGFydEV4cG9ydCIsImJhdGNoRXhwb3J0IiwiYmF0Y2hGdW5jdGlvbnMiLCJwYWlyIiwiYmF0Y2hSZXN1bHRzIiwiYWxsU2V0dGxlZCIsInJlYXNvbiIsImV4cG9ydGluZ09wdGlvbnMiLCJlbmRDYWxsYmFjayIsImZpbGVDb250ZW50IiwiX2V4cG9ydEZyb21TdmciLCJfZXhwb3J0RnJvbU9wdGlvbnMiLCJnZXRBbGxvd0NvZGVFeGVjdXRpb24iLCJzZXRBbGxvd0NvZGVFeGVjdXRpb24iLCJpbnB1dFRvRXhwb3J0IiwiX3ByZXBhcmVFeHBvcnQiLCJfaGFuZGxlQ3VzdG9tTG9naWMiLCJfaGFuZGxlR2xvYmFsQW5kVGhlbWUiLCJfZmluZENoYXJ0U2l6ZSIsIm9wdGlvbnNDaGFydCIsIm9wdGlvbnNFeHBvcnRpbmciLCJnbG9iYWxPcHRpb25zQ2hhcnQiLCJnbG9iYWxPcHRpb25zRXhwb3J0aW5nIiwidGhlbWVPcHRpb25zQ2hhcnQiLCJ0aGVtZU9wdGlvbnNFeHBvcnRpbmciLCJzb3VyY2VIZWlnaHQiLCJzb3VyY2VXaWR0aCIsInBhcmFtIiwiX2hhbmRsZVJlc291cmNlcyIsImFsbG93ZWRQcm9wcyIsImhhbmRsZWRSZXNvdXJjZXMiLCJjb3JyZWN0UmVzb3VyY2VzIiwicHJvcE5hbWUiLCJvcHRpb25zTmFtZSIsInRpbWVySWRzIiwiYWRkVGltZXIiLCJjbGVhckFsbFRpbWVycyIsImNsZWFySW50ZXJ2YWwiLCJjbGVhclRpbWVvdXQiLCJsb2dFcnJvck1pZGRsZXdhcmUiLCJyZXF1ZXN0IiwibmV4dCIsInJldHVybkVycm9yTWlkZGxld2FyZSIsInN0YXR1cyIsImpzb24iLCJlcnJvck1pZGRsZXdhcmUiLCJhcHAiLCJ1c2UiLCJyYXRlTGltaXRpbmdNaWRkbGV3YXJlIiwicmF0ZUxpbWl0aW5nT3B0aW9ucyIsInJhdGVPcHRpb25zIiwibGltaXRlciIsInJhdGVMaW1pdCIsIndpbmRvd01zIiwibGltaXQiLCJkZWxheU1zIiwiaGFuZGxlciIsImZvcm1hdCIsInNlbmQiLCJkZWZhdWx0Iiwic2tpcCIsInF1ZXJ5IiwiYWNjZXNzX3Rva2VuIiwiY29udGVudFR5cGVNaWRkbGV3YXJlIiwiY29udGVudFR5cGUiLCJoZWFkZXJzIiwicmVxdWVzdEJvZHlNaWRkbGV3YXJlIiwiY29ubmVjdGlvbiIsInJlbW90ZUFkZHJlc3MiLCJ2YWxpZGF0ZWRPcHRpb25zIiwiX3JlcXVlc3RJZCIsImZpbGVuYW1lIiwidmFsaWRhdGlvbk1pZGRsZXdhcmUiLCJwb3N0IiwicmV2ZXJzZWRNaW1lIiwicG5nIiwianBlZyIsImdpZiIsInJlcXVlc3RFeHBvcnQiLCJyZXF1ZXN0Q291bnRlciIsImNvbm5lY3Rpb25BYm9ydGVkIiwic29ja2V0IiwiaGFkRXJyb3JzIiwiaGVhZGVyIiwiYXR0YWNobWVudCIsImV4cG9ydFJvdXRlcyIsInNlcnZlclN0YXJ0VGltZSIsInBhY2thZ2VGaWxlIiwic3VjY2Vzc1JhdGVzIiwicmVjb3JkSW50ZXJ2YWwiLCJ3aW5kb3dTaXplIiwiX2NhbGN1bGF0ZU1vdmluZ0F2ZXJhZ2UiLCJhIiwiYiIsIl9zdGFydFN1Y2Nlc3NSYXRlIiwic2V0SW50ZXJ2YWwiLCJzdGF0cyIsInN1Y2Nlc3NSYXRpbyIsImhlYWx0aFJvdXRlcyIsInBlcmlvZCIsIm1vdmluZ0F2ZXJhZ2UiLCJib290VGltZSIsInVwdGltZSIsImZsb29yIiwic2VydmVyVmVyc2lvbiIsImhpZ2hjaGFydHNWZXJzaW9uIiwiYXZlcmFnZUV4cG9ydFRpbWUiLCJhdHRlbXB0ZWRFeHBvcnRzIiwicGVyZm9ybWVkRXhwb3J0cyIsImZhaWxlZEV4cG9ydHMiLCJzdWNlc3NSYXRpbyIsInRvRml4ZWQiLCJzdmdFeHBvcnRzIiwianNvbkV4cG9ydHMiLCJzdmdFeHBvcnRzQXR0ZW1wdHMiLCJqc29uRXhwb3J0c0F0dGVtcHRzIiwidWlSb3V0ZXMiLCJzZW5kRmlsZSIsImFjY2VwdFJhbmdlcyIsInZlcnNpb25DaGFuZ2VSb3V0ZXMiLCJ0b2tlbiIsImFjdGl2ZVNlcnZlcnMiLCJNYXAiLCJleHByZXNzIiwic3RhcnRTZXJ2ZXIiLCJzZXJ2ZXJPcHRpb25zIiwidXBsb2FkTGltaXRCeXRlcyIsInN0b3JhZ2UiLCJtdWx0ZXIiLCJtZW1vcnlTdG9yYWdlIiwidXBsb2FkIiwibGltaXRzIiwiZmllbGRTaXplIiwiZGlzYWJsZSIsImNvcnMiLCJtZXRob2RzIiwic2V0IiwidXJsZW5jb2RlZCIsImV4dGVuZGVkIiwibm9uZSIsInN0YXRpYyIsImh0dHBTZXJ2ZXIiLCJjcmVhdGVTZXJ2ZXIiLCJfYXR0YWNoU2VydmVyRXJyb3JIYW5kbGVycyIsImxpc3RlbiIsImNlcnQiLCJyZWFkRmlsZSIsImh0dHBzU2VydmVyIiwiY2xvc2VTZXJ2ZXJzIiwiZGVsZXRlIiwiZ2V0U2VydmVycyIsImdldEV4cHJlc3MiLCJnZXRBcHAiLCJtaWRkbGV3YXJlcyIsInNodXRkb3duQ2xlYW5VcCIsImV4aXRDb2RlIiwiZXhpdCIsImluaXRFeHBvcnQiLCJpbml0T3B0aW9ucyIsIl9hdHRhY2hQcm9jZXNzRXhpdExpc3RlbmVycyJdLCJtYXBwaW5ncyI6InduQkEyQk8sTUFBTUEsWUFBWUMsSUFBYUEsY0FBQyxJQUFJQyxJQUFJLE9BQVEsb0JBQUFDLFNBQUFDLFFBQUEsT0FBQUMsY0FBQUMsWUFBQUMsS0FBQUMsd0JBQUEsV0FBQUEsdUJBQUFDLFFBQUFDLGVBQUFGLHVCQUFBRyxLQUFBLElBQUFULElBQUEsWUFBQUMsU0FBQVMsU0FBQUwsT0ErQmhELFNBQVNNLFNBQVNDLEdBRXZCLEdBQWUsT0FBWEEsR0FBcUMsaUJBQVhBLEVBQzVCLE9BQU9BLEVBSVQsTUFBTUMsRUFBYUMsTUFBTUMsUUFBUUgsR0FBVSxHQUFLLEdBR2hELElBQUssTUFBTUksS0FBT0osRUFDWkssT0FBT0MsVUFBVUMsZUFBZUMsS0FBS1IsRUFBUUksS0FDL0NILEVBQVdHLEdBQU9M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 +"use strict";Object.defineProperty(exports,"__esModule",{value:!0}),require("colors");var fs=require("fs"),path=require("path"),httpsProxyAgent=require("https-proxy-agent"),url=require("url"),dotenv=require("dotenv"),zod=require("zod"),http=require("http"),https=require("https"),tarn=require("tarn"),uuid=require("uuid"),puppeteer=require("puppeteer"),DOMPurify=require("dompurify"),jsdom=require("jsdom"),promises=require("fs/promises"),cors=require("cors"),express=require("express"),multer=require("multer"),rateLimit=require("express-rate-limit"),_documentCurrentScript="undefined"!=typeof document?document.currentScript:null;const __dirname$1=url.fileURLToPath(new URL("../.","undefined"==typeof document?require("url").pathToFileURL(__filename).href:_documentCurrentScript&&"SCRIPT"===_documentCurrentScript.tagName.toUpperCase()&&_documentCurrentScript.src||new URL("index.cjs",document.baseURI).href));function deepCopy(e){if(null===e||"object"!=typeof e)return e;const t=Array.isArray(e)?[]:{};for(const o in e)Object.prototype.hasOwnProperty.call(e,o)&&(t[o]=deepCopy(e[o]));return t}function fixConstr(e){try{const t=`${e.toLowerCase().replace("chart","")}Chart`;return"Chart"===t&&t.toLowerCase(),["chart","stockChart","mapChart","ganttChart"].includes(t)?t:"chart"}catch{return"chart"}}function fixOutfile(e,t){return`${getAbsolutePath(t||"chart").split(".").shift()}.${e}`}function fixType(e,t=null){const o={"image/png":"png","image/jpeg":"jpeg","application/pdf":"pdf","image/svg+xml":"svg"},r=Object.values(o);if(t){const o=t.split(".").pop();"jpg"===o?e="jpeg":r.includes(o)&&e!==o&&(e=o)}return o[e]||r.find((t=>t===e))||"png"}function getAbsolutePath(e){return path.isAbsolute(e)?e:path.join(__dirname$1,e)}function getBase64(e,t){return"pdf"===t||"svg"==t?Buffer.from(e,"utf8").toString("base64"):e}function getNewDate(){return(new Date).toString().split("(")[0].trim()}function getNewDateTime(){return(new Date).getTime()}function isObject(e){return"[object Object]"===Object.prototype.toString.call(e)}function isObjectEmpty(e){return"object"==typeof e&&!Array.isArray(e)&&null!==e&&0===Object.keys(e).length}function isPrivateRangeUrlFound(e){return[/xlink:href="(?:http:\/\/|https:\/\/)?localhost\b/,/xlink:href="(?:http:\/\/|https:\/\/)?10\.\d{1,3}\.\d{1,3}\.\d{1,3}\b/,/xlink:href="(?:http:\/\/|https:\/\/)?127\.\d{1,3}\.\d{1,3}\.\d{1,3}\b/,/xlink:href="(?:http:\/\/|https:\/\/)?172\.(1[6-9]|2[0-9]|3[0-1])\.\d{1,3}\.\d{1,3}\b/,/xlink:href="(?:http:\/\/|https:\/\/)?192\.168\.\d{1,3}\.\d{1,3}\b/].some((t=>t.test(e)))}function measureTime(){const e=process.hrtime.bigint();return()=>Number(process.hrtime.bigint()-e)/1e6}function roundNumber(e,t=1){const o=Math.pow(10,t||0);return Math.round(+e*o)/o}function wrapAround(e,t,o=!1){if(e&&"string"==typeof e)return(e=e.trim()).endsWith(".js")?t?wrapAround(fs.readFileSync(getAbsolutePath(e),"utf8"),t,o):null:!o&&(e.startsWith("function()")||e.startsWith("function ()")||e.startsWith("()=>")||e.startsWith("() =>"))?`(${e})()`:e.replace(/;$/,"")}const colors=["red","yellow","blue","gray","green"],logging={toConsole:!0,toFile:!1,pathCreated:!1,pathToLog:"",levelsDesc:[{title:"error",color:colors[0]},{title:"warning",color:colors[1]},{title:"notice",color:colors[2]},{title:"verbose",color:colors[3]},{title:"benchmark",color:colors[4]}]};function log(...e){const[t,...o]=e,{levelsDesc:r,level:i}=logging;if(5!==t&&(0===t||t>i||i>r.length))return;const n=`${getNewDate()} [${r[t-1].title}] -`;logging.toFile&&_logToFile(o,n),logging.toConsole&&console.log.apply(void 0,[n.toString()[logging.levelsDesc[t-1].color]].concat(o))}function logWithStack(e,t,o){const r=o||t&&t.message||"",{level:i,levelsDesc:n}=logging;if(0===e||e>i||i>n.length)return;const s=`${getNewDate()} [${n[e-1].title}] -`,a=t&&t.stack,l=[r];a&&l.push("\n",a),logging.toFile&&_logToFile(l,s),logging.toConsole&&console.log.apply(void 0,[s.toString()[logging.levelsDesc[e-1].color]].concat([l.shift()[colors[e-1]],...l]))}function logZodIssues(e,t,o){logWithStack(e,null,[`${o||"[validation] Validation error"} - the following Zod issues occured:`,...(t||[]).map((e=>`- ${e.message}`))].join("\n"))}function initLogging(e){const{level:t,dest:o,file:r,toConsole:i,toFile:n}=e;logging.pathCreated=!1,logging.pathToLog="",setLogLevel(t),enableConsoleLogging(i),enableFileLogging(o,r,n)}function setLogLevel(e){Number.isInteger(e)&&e>=0&&e<=logging.levelsDesc.length&&(logging.level=e)}function enableConsoleLogging(e){logging.toConsole=!!e}function enableFileLogging(e,t,o){logging.toFile=!!o,logging.toFile&&(logging.dest=e||"",logging.file=t||"")}function _logToFile(e,t){logging.pathCreated||(!fs.existsSync(getAbsolutePath(logging.dest))&&fs.mkdirSync(getAbsolutePath(logging.dest)),logging.pathToLog=getAbsolutePath(path.join(logging.dest,logging.file)),logging.pathCreated=!0),fs.appendFile(logging.pathToLog,[t].concat(e).join(" ")+"\n",(e=>{e&&logging.toFile&&logging.pathCreated&&(logging.toFile=!1,logging.pathCreated=!1,logWithStack(2,e,"[logger] Unable to write to log file."))}))}const defaultConfig={puppeteer:{args:{value:["--allow-running-insecure-content","--ash-no-nudges","--autoplay-policy=user-gesture-required","--block-new-web-contents","--disable-accelerated-2d-canvas","--disable-background-networking","--disable-background-timer-throttling","--disable-backgrounding-occluded-windows","--disable-breakpad","--disable-checker-imaging","--disable-client-side-phishing-detection","--disable-component-extensions-with-background-pages","--disable-component-update","--disable-default-apps","--disable-dev-shm-usage","--disable-domain-reliability","--disable-extensions","--disable-features=CalculateNativeWinOcclusion,InterestFeedContentSuggestions,WebOTP","--disable-hang-monitor","--disable-ipc-flooding-protection","--disable-logging","--disable-notifications","--disable-offer-store-unmasked-wallet-cards","--disable-popup-blocking","--disable-print-preview","--disable-prompt-on-repost","--disable-renderer-backgrounding","--disable-search-engine-choice-screen","--disable-session-crashed-bubble","--disable-setuid-sandbox","--disable-site-isolation-trials","--disable-speech-api","--disable-sync","--enable-unsafe-webgpu","--hide-crash-restore-bubble","--hide-scrollbars","--metrics-recording-only","--mute-audio","--no-default-browser-check","--no-first-run","--no-pings","--no-sandbox","--no-startup-window","--no-zygote","--password-store=basic","--process-per-tab","--use-mock-keychain"],types:["string[]"],envLink:"PUPPETEER_ARGS",cliName:"puppeteerArgs",description:"Array of Puppeteer arguments",promptOptions:{type:"list",separator:";"}}},highcharts:{version:{value:"latest",types:["string"],envLink:"HIGHCHARTS_VERSION",description:"Highcharts version",promptOptions:{type:"text"}},cdnUrl:{value:"https://code.highcharts.com",types:["string"],envLink:"HIGHCHARTS_CDN_URL",description:"CDN URL for Highcharts scripts",promptOptions:{type:"text"}},forceFetch:{value:!1,types:["boolean"],envLink:"HIGHCHARTS_FORCE_FETCH",description:"Flag to refetch scripts after each server rerun",promptOptions:{type:"toggle"}},cachePath:{value:".cache",types:["string"],envLink:"HIGHCHARTS_CACHE_PATH",description:"Directory path for cached Highcharts scripts",promptOptions:{type:"text"}},coreScripts:{value:["highcharts","highcharts-more","highcharts-3d"],types:["string[]"],envLink:"HIGHCHARTS_CORE_SCRIPTS",description:"Highcharts core scripts to fetch",promptOptions:{type:"multiselect",instructions:"Space: Select specific, A: Select all, Enter: Confirm"}},moduleScripts:{value:["stock","map","gantt","exporting","parallel-coordinates","accessibility","boost-canvas","boost","data","data-tools","draggable-points","static-scale","broken-axis","heatmap","tilemap","tiledwebmap","timeline","treemap","treegraph","item-series","drilldown","histogram-bellcurve","bullet","funnel","funnel3d","geoheatmap","pyramid3d","networkgraph","overlapping-datalabels","pareto","pattern-fill","pictorial","price-indicator","sankey","arc-diagram","dependency-wheel","series-label","series-on-point","solid-gauge","sonification","streamgraph","sunburst","variable-pie","variwide","vector","venn","windbarb","wordcloud","xrange","no-data-to-display","drag-panes","debugger","dumbbell","lollipop","cylinder","organization","dotplot","marker-clusters","hollowcandlestick","heikinashi","flowmap","export-data","navigator","textpath"],types:["string[]"],envLink:"HIGHCHARTS_MODULE_SCRIPTS",description:"Highcharts module scripts to fetch",promptOptions:{type:"multiselect",instructions:"Space: Select specific, A: Select all, Enter: Confirm"}},indicatorScripts:{value:["indicators-all"],types:["string[]"],envLink:"HIGHCHARTS_INDICATOR_SCRIPTS",description:"Highcharts indicator scripts to fetch",promptOptions:{type:"multiselect",instructions:"Space: Select specific, A: Select all, Enter: Confirm"}},customScripts:{value:["https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.30.1/moment.min.js","https://cdnjs.cloudflare.com/ajax/libs/moment-timezone/0.5.45/moment-timezone-with-data.min.js"],types:["string[]"],envLink:"HIGHCHARTS_CUSTOM_SCRIPTS",description:"Additional custom scripts or dependencies to fetch",promptOptions:{type:"list",separator:";"}}},export:{infile:{value:null,types:["string","null"],envLink:"EXPORT_INFILE",description:"Input filename with type, formatted correctly as JSON or SVG",promptOptions:{type:"text"}},instr:{value:null,types:["Object","string","null"],envLink:"EXPORT_INSTR",description:"Overrides the `infile` with JSON, stringified JSON, or SVG input",promptOptions:{type:"text"}},options:{value:null,types:["Object","string","null"],envLink:"EXPORT_OPTIONS",description:"Alias for the `instr` option",promptOptions:{type:"text"}},svg:{value:null,types:["string","null"],envLink:"EXPORT_SVG",description:"SVG string representation of the chart to render",promptOptions:{type:"text"}},batch:{value:null,types:["string","null"],envLink:"EXPORT_BATCH",description:'Batch job string with input/output pairs: "in=out;in=out;..."',promptOptions:{type:"text"}},outfile:{value:null,types:["string","null"],envLink:"EXPORT_OUTFILE",description:"Output filename with type. Can be jpeg, png, pdf, or svg and ignores `type` option",promptOptions:{type:"text"}},type:{value:"png",types:["string"],envLink:"EXPORT_TYPE",description:"File export format. Can be jpeg, png, pdf, or svg",promptOptions:{type:"select",hint:"Default: png",choices:["png","jpeg","pdf","svg"]}},constr:{value:"chart",types:["string"],envLink:"EXPORT_CONSTR",description:"Chart constructor. Can be chart, stockChart, mapChart, or ganttChart",promptOptions:{type:"select",hint:"Default: chart",choices:["chart","stockChart","mapChart","ganttChart"]}},b64:{value:!1,types:["boolean"],envLink:"EXPORT_B64",description:"Whether or not to the chart should be received in Base64 format instead of binary",promptOptions:{type:"toggle"}},noDownload:{value:!1,types:["boolean"],envLink:"EXPORT_NO_DOWNLOAD",description:"Whether or not to include or exclude attachment headers in the response",promptOptions:{type:"toggle"}},height:{value:null,types:["number","null"],envLink:"EXPORT_HEIGHT",description:"Height of the exported chart, overrides chart settings",promptOptions:{type:"number"}},width:{value:null,types:["number","null"],envLink:"EXPORT_WIDTH",description:"Width of the exported chart, overrides chart settings",promptOptions:{type:"number"}},scale:{value:null,types:["number","null"],envLink:"EXPORT_SCALE",description:"Scale of the exported chart, overrides chart settings. Ranges from 0.1 to 5.0",promptOptions:{type:"number"}},defaultHeight:{value:400,types:["number"],envLink:"EXPORT_DEFAULT_HEIGHT",description:"Default height of the exported chart if not set",promptOptions:{type:"number"}},defaultWidth:{value:600,types:["number"],envLink:"EXPORT_DEFAULT_WIDTH",description:"Default width of the exported chart if not set",promptOptions:{type:"number"}},defaultScale:{value:1,types:["number"],envLink:"EXPORT_DEFAULT_SCALE",description:"Default scale of the exported chart if not set. Ranges from 0.1 to 5.0",promptOptions:{type:"number",min:.1,max:5}},globalOptions:{value:null,types:["Object","string","null"],envLink:"EXPORT_GLOBAL_OPTIONS",description:"JSON, stringified JSON or filename with global options for Highcharts.setOptions",promptOptions:{type:"text"}},themeOptions:{value:null,types:["Object","string","null"],envLink:"EXPORT_THEME_OPTIONS",description:"JSON, stringified JSON or filename with theme options for Highcharts.setOptions",promptOptions:{type:"text"}},rasterizationTimeout:{value:1500,types:["number"],envLink:"EXPORT_RASTERIZATION_TIMEOUT",description:"Milliseconds to wait for webpage rendering",promptOptions:{type:"number"}}},customLogic:{allowCodeExecution:{value:!1,types:["boolean"],envLink:"CUSTOM_LOGIC_ALLOW_CODE_EXECUTION",description:"Allows or disallows execution of arbitrary code during exporting",promptOptions:{type:"toggle"}},allowFileResources:{value:!1,types:["boolean"],envLink:"CUSTOM_LOGIC_ALLOW_FILE_RESOURCES",description:"Allows or disallows injection of filesystem resources (disabled in server mode)",promptOptions:{type:"toggle"}},customCode:{value:null,types:["string","null"],envLink:"CUSTOM_LOGIC_CUSTOM_CODE",description:"Custom code to execute before chart initialization. Can be a function, code wrapped in a function, or a .js filename",promptOptions:{type:"text"}},callback:{value:null,types:["string","null"],envLink:"CUSTOM_LOGIC_CALLBACK",description:"JavaScript code to run during construction. Can be a function or a .js filename",promptOptions:{type:"text"}},resources:{value:null,types:["Object","string","null"],envLink:"CUSTOM_LOGIC_RESOURCES",description:"Additional resources as JSON, stringified JSON, or filename, containing files, js, and css sections",promptOptions:{type:"text"}},loadConfig:{value:null,types:["string","null"],envLink:"CUSTOM_LOGIC_LOAD_CONFIG",legacyName:"fromFile",description:"File with a pre-defined configuration to use",promptOptions:{type:"text"}},createConfig:{value:null,types:["string","null"],envLink:"CUSTOM_LOGIC_CREATE_CONFIG",description:"Prompt-based option setting, saved to a provided config file",promptOptions:{type:"text"}}},server:{enable:{value:!1,types:["boolean"],envLink:"SERVER_ENABLE",cliName:"enableServer",description:"Starts the server when true",promptOptions:{type:"toggle"}},host:{value:"0.0.0.0",types:["string"],envLink:"SERVER_HOST",description:"Hostname of the server",promptOptions:{type:"text"}},port:{value:7801,types:["number"],envLink:"SERVER_PORT",description:"Port number for the server",promptOptions:{type:"number"}},uploadLimit:{value:3,types:["number"],envLink:"SERVER_UPLOAD_LIMIT",description:"Maximum request body size in MB",promptOptions:{type:"number"}},benchmarking:{value:!1,types:["boolean"],envLink:"SERVER_BENCHMARKING",cliName:"serverBenchmarking",description:"Displays or not action durations in milliseconds during server requests",promptOptions:{type:"toggle"}},proxy:{host:{value:null,types:["string","null"],envLink:"SERVER_PROXY_HOST",cliName:"proxyHost",description:"Host of the proxy server, if applicable",promptOptions:{type:"text"}},port:{value:null,types:["number","null"],envLink:"SERVER_PROXY_PORT",cliName:"proxyPort",description:"Port of the proxy server, if applicable",promptOptions:{type:"number"}},timeout:{value:5e3,types:["number"],envLink:"SERVER_PROXY_TIMEOUT",cliName:"proxyTimeout",description:"Timeout in milliseconds for the proxy server, if applicable",promptOptions:{type:"number"}}},rateLimiting:{enable:{value:!1,types:["boolean"],envLink:"SERVER_RATE_LIMITING_ENABLE",cliName:"enableRateLimiting",description:"Enables or disables rate limiting on the server",promptOptions:{type:"toggle"}},maxRequests:{value:10,types:["number"],envLink:"SERVER_RATE_LIMITING_MAX_REQUESTS",legacyName:"rateLimit",description:"Maximum number of requests allowed per minute",promptOptions:{type:"number"}},window:{value:1,types:["number"],envLink:"SERVER_RATE_LIMITING_WINDOW",description:"Time window in minutes for rate limiting",promptOptions:{type:"number"}},delay:{value:0,types:["number"],envLink:"SERVER_RATE_LIMITING_DELAY",description:"Delay duration between successive requests before reaching the limit",promptOptions:{type:"number"}},trustProxy:{value:!1,types:["boolean"],envLink:"SERVER_RATE_LIMITING_TRUST_PROXY",description:"Set to true if the server is behind a load balancer",promptOptions:{type:"toggle"}},skipKey:{value:null,types:["string","null"],envLink:"SERVER_RATE_LIMITING_SKIP_KEY",description:"Key to bypass the rate limiter, used with `skipToken`",promptOptions:{type:"text"}},skipToken:{value:null,types:["string","null"],envLink:"SERVER_RATE_LIMITING_SKIP_TOKEN",description:"Token to bypass the rate limiter, used with `skipKey`",promptOptions:{type:"text"}}},ssl:{enable:{value:!1,types:["boolean"],envLink:"SERVER_SSL_ENABLE",cliName:"enableSsl",description:"Enables or disables SSL protocol",promptOptions:{type:"toggle"}},force:{value:!1,types:["boolean"],envLink:"SERVER_SSL_FORCE",cliName:"sslForce",legacyName:"sslOnly",description:"Forces the server to use HTTPS only when true",promptOptions:{type:"toggle"}},port:{value:443,types:["number"],envLink:"SERVER_SSL_PORT",cliName:"sslPort",description:"Port for the SSL server",promptOptions:{type:"number"}},certPath:{value:null,types:["string","null"],envLink:"SERVER_SSL_CERT_PATH",cliName:"sslCertPath",legacyName:"sslPath",description:"Path to the SSL certificate/key file",promptOptions:{type:"text"}}}},pool:{minWorkers:{value:4,types:["number"],envLink:"POOL_MIN_WORKERS",description:"Minimum and initial number of pool workers to spawn",promptOptions:{type:"number"}},maxWorkers:{value:8,types:["number"],envLink:"POOL_MAX_WORKERS",legacyName:"workers",description:"Maximum number of pool workers to spawn",promptOptions:{type:"number"}},workLimit:{value:40,types:["number"],envLink:"POOL_WORK_LIMIT",description:"Number of tasks a worker can handle before restarting",promptOptions:{type:"number"}},acquireTimeout:{value:5e3,types:["number"],envLink:"POOL_ACQUIRE_TIMEOUT",description:"Timeout in milliseconds for acquiring a resource",promptOptions:{type:"number"}},createTimeout:{value:5e3,types:["number"],envLink:"POOL_CREATE_TIMEOUT",description:"Timeout in milliseconds for creating a resource",promptOptions:{type:"number"}},destroyTimeout:{value:5e3,types:["number"],envLink:"POOL_DESTROY_TIMEOUT",description:"Timeout in milliseconds for destroying a resource",promptOptions:{type:"number"}},idleTimeout:{value:3e4,types:["number"],envLink:"POOL_IDLE_TIMEOUT",description:"Timeout in milliseconds for destroying idle resources",promptOptions:{type:"number"}},createRetryInterval:{value:200,types:["number"],envLink:"POOL_CREATE_RETRY_INTERVAL",description:"Interval in milliseconds before retrying resource creation on failure",promptOptions:{type:"number"}},reaperInterval:{value:1e3,types:["number"],envLink:"POOL_REAPER_INTERVAL",description:"Interval in milliseconds to check and destroy idle resources",promptOptions:{type:"number"}},benchmarking:{value:!1,types:["boolean"],envLink:"POOL_BENCHMARKING",cliName:"poolBenchmarking",description:"Shows statistics for the pool of resources",promptOptions:{type:"toggle"}}},logging:{level:{value:4,types:["number"],envLink:"LOGGING_LEVEL",cliName:"logLevel",description:"Logging verbosity level",promptOptions:{type:"number",round:0,min:0,max:5}},file:{value:"highcharts-export-server.log",types:["string"],envLink:"LOGGING_FILE",cliName:"logFile",description:"Log file name. Requires `logToFile` and `logDest` to be set",promptOptions:{type:"text"}},dest:{value:"log",types:["string"],envLink:"LOGGING_DEST",cliName:"logDest",description:"Path to store log files. Requires `logToFile` to be set",promptOptions:{type:"text"}},toConsole:{value:!0,types:["boolean"],envLink:"LOGGING_TO_CONSOLE",cliName:"logToConsole",description:"Enables or disables console logging",promptOptions:{type:"toggle"}},toFile:{value:!0,types:["boolean"],envLink:"LOGGING_TO_FILE",cliName:"logToFile",description:"Enables or disables logging to a file",promptOptions:{type:"toggle"}}},ui:{enable:{value:!1,types:["boolean"],envLink:"UI_ENABLE",cliName:"enableUi",description:"Enables or disables the UI for the export server",promptOptions:{type:"toggle"}},route:{value:"/",types:["string"],envLink:"UI_ROUTE",cliName:"uiRoute",description:"The endpoint route for the UI",promptOptions:{type:"text"}}},other:{nodeEnv:{value:"production",types:["string"],envLink:"OTHER_NODE_ENV",description:"The Node.js environment type",promptOptions:{type:"text"}},listenToProcessExits:{value:!0,types:["boolean"],envLink:"OTHER_LISTEN_TO_PROCESS_EXITS",description:"Whether or not to attach process.exit handlers",promptOptions:{type:"toggle"}},noLogo:{value:!1,types:["boolean"],envLink:"OTHER_NO_LOGO",description:"Display or skip printing the logo on startup",promptOptions:{type:"toggle"}},hardResetPage:{value:!1,types:["boolean"],envLink:"OTHER_HARD_RESET_PAGE",description:"Whether or not to reset the page content entirely",promptOptions:{type:"toggle"}},browserShellMode:{value:!0,types:["boolean"],envLink:"OTHER_BROWSER_SHELL_MODE",description:"Whether or not to set the browser to run in shell mode",promptOptions:{type:"toggle"}},validation:{value:!0,types:["boolean"],envLink:"OTHER_VALIDATION",description:"Whether or not to enable validation of options types",promptOptions:{type:"toggle"}}},debug:{enable:{value:!1,types:["boolean"],envLink:"DEBUG_ENABLE",cliName:"enableDebug",description:"Enables or disables debug mode for the underlying browser",promptOptions:{type:"toggle"}},headless:{value:!1,types:["boolean"],envLink:"DEBUG_HEADLESS",description:"Whether or not to set the browser to run in headless mode during debugging",promptOptions:{type:"toggle"}},devtools:{value:!1,types:["boolean"],envLink:"DEBUG_DEVTOOLS",description:"Enables or disables DevTools in headful mode",promptOptions:{type:"toggle"}},listenToConsole:{value:!1,types:["boolean"],envLink:"DEBUG_LISTEN_TO_CONSOLE",description:"Enables or disables listening to console messages from the browser",promptOptions:{type:"toggle"}},dumpio:{value:!1,types:["boolean"],envLink:"DEBUG_DUMPIO",description:"Redirects or not browser stdout and stderr to process.stdout and process.stderr",promptOptions:{type:"toggle"}},slowMo:{value:0,types:["number"],envLink:"DEBUG_SLOW_MO",description:"Delays Puppeteer operations by the specified milliseconds",promptOptions:{type:"number"}},debuggingPort:{value:9222,types:["number"],envLink:"DEBUG_DEBUGGING_PORT",description:"Port used for debugging",promptOptions:{type:"number"}}}},nestedProps=_createNestedProps(defaultConfig),absoluteProps=_createAbsoluteProps(defaultConfig);function _createNestedProps(e,t={},o=""){return Object.keys(e).forEach((r=>{const i=e[r];void 0===i.value?_createNestedProps(i,t,`${o}.${r}`):(t[i.cliName||r]=`${o}.${r}`.substring(1),void 0!==i.legacyName&&(t[i.legacyName]=`${o}.${r}`.substring(1)))})),t}function _createAbsoluteProps(e,t=[]){return Object.keys(e).forEach((o=>{const r=e[o];void 0===r.types?_createAbsoluteProps(r,t):r.types.includes("Object")&&t.push(o)})),t}dotenv.config();const{coreScripts:coreScripts,moduleScripts:moduleScripts,indicatorScripts:indicatorScripts}=defaultConfig.highcharts;zod.z.setErrorMap(_customErrorMap);const v={boolean:e=>e?zod.z.boolean():zod.z.union([zod.z.enum(["true","1","false","0","undefined","null",""]).transform((e=>["undefined","null",""].includes(e)?null:"true"===e||"1"===e)),zod.z.boolean()]).nullable(),string:e=>e?zod.z.string().trim().refine((e=>!["false","undefined","null",""].includes(e)),{params:{errorMessage:"The string contains a forbidden value"}}):zod.z.string().trim().transform((e=>["false","undefined","null",""].includes(e)?null:e)).nullable(),enum:(e,t)=>t?zod.z.enum([...e]):zod.z.enum([...e,"undefined","null",""]).transform((e=>["undefined","null",""].includes(e)?null:e)).nullable(),stringArray(e,t,o){const r=zod.z.string().trim().array(),i=zod.z.string().trim().transform((e=>(e.startsWith("[")&&(e=e.slice(1)),e.endsWith("]")&&(e=e.slice(0,-1)),e.split(t)))),n=t=>t.map((e=>e.trim())).filter(e);return o?r.transform(n):zod.z.union([i,r]).transform(n).transform((e=>e.length?e:null)).nullable()},positiveNum:e=>e?zod.z.number().positive():zod.z.union([zod.z.string().trim().refine((e=>!isNaN(Number(e))&&Number(e)>0||["undefined","null",""].includes(e)),{params:{errorMessage:"The value must be numeric and positive"}}).transform((e=>["undefined","null",""].includes(e)?null:Number(e))),zod.z.number().positive()]).nullable(),nonNegativeNum:e=>e?zod.z.number().nonnegative():zod.z.union([zod.z.string().trim().refine((e=>!isNaN(Number(e))&&Number(e)>=0||["undefined","null",""].includes(e)),{params:{errorMessage:"The value must be numeric and non-negative"}}).transform((e=>["undefined","null",""].includes(e)?null:Number(e))),zod.z.number().nonnegative()]).nullable(),startsWith:(e,t)=>t?zod.z.string().trim().refine((t=>e.some((e=>t.startsWith(e)))),{params:{errorMessage:`The value must be a string that starts with ${e.join(", ")}`}}):zod.z.string().trim().refine((t=>e.some((e=>t.startsWith(e)))||["undefined","null",""].includes(t)),{params:{errorMessage:`The value must be a string that starts with ${e.join(", ")}`}}).transform((e=>["undefined","null",""].includes(e)?null:e)).nullable(),chartConfig:()=>zod.z.union([zod.z.string().trim().refine((e=>e.startsWith("{")&&e.endsWith("}")||["undefined","null",""].includes(e)),{params:{errorMessage:"The value must be a string that starts with '{' and ends with '}'"}}).transform((e=>["undefined","null",""].includes(e)?null:e)),zod.z.object({}).passthrough()]).nullable(),additionalOptions:()=>zod.z.union([zod.z.string().trim().refine((e=>e.length>=6&&e.endsWith(".json")||e.startsWith("{")&&e.endsWith("}")||["undefined","null",""].includes(e)),{params:{errorMessage:"The value must be a string that ends with '.json' or starts with '{' and ends with '}'"}}).transform((e=>["undefined","null",""].includes(e)?null:e)),zod.z.object({}).passthrough()]).nullable()},validators={args:e=>v.stringArray((e=>!["false","undefined","null",""].includes(e)),";",e),version:e=>e?zod.z.string().trim().refine((e=>/^(latest|\d{1,2}(\.\d{1,2}){0,2})$/.test(e)),{params:{errorMessage:"The value must be 'latest', a major version, or in the form XX.YY.ZZ"}}):zod.z.string().trim().refine((e=>/^(latest|\d{1,2}(\.\d{1,2}){0,2})$/.test(e)||["undefined","null",""].includes(e)),{params:{errorMessage:"The value must be 'latest', a major version, or in the form XX.YY.ZZ"}}).transform((e=>["undefined","null",""].includes(e)?null:e)).nullable(),cdnUrl:e=>v.startsWith(["http://","https://"],e),forceFetch:e=>v.boolean(e),cachePath:e=>v.string(e),adminToken:e=>v.string(e),coreScripts:e=>v.stringArray((e=>coreScripts.value.includes(e)),",",e),moduleScripts:e=>v.stringArray((e=>moduleScripts.value.includes(e)),",",e),indicatorScripts:e=>v.stringArray((e=>indicatorScripts.value.includes(e)),",",e),customScripts:e=>v.stringArray((e=>e.startsWith("https://")||e.startsWith("http://")),",",e),infile:e=>e?zod.z.string().trim().refine((e=>e.length>=6&&e.endsWith(".json")||e.length>=5&&e.endsWith(".svg")),{params:{errorMessage:"The value must be a string that ends with .json or .svg"}}).nullable():zod.z.string().trim().refine((e=>e.length>=6&&e.endsWith(".json")||e.length>=5&&e.endsWith(".svg")||["undefined","null",""].includes(e)),{params:{errorMessage:"The value must be a string that ends with .json or .svg"}}).transform((e=>["undefined","null",""].includes(e)?null:e)).nullable(),instr:()=>v.chartConfig(),options:()=>v.chartConfig(),svg:()=>zod.z.string().trim().refine((e=>e.indexOf("=0||e.indexOf("=0||["false","undefined","null",""].includes(e)),{params:{errorMessage:"The value must be a string that contains '["false","undefined","null",""].includes(e)?null:e)).nullable(),outfile:e=>e?zod.z.string().trim().refine((e=>e.length>=6&&e.endsWith(".jpeg")||e.length>=5&&(e.endsWith(".jpg")||e.endsWith(".png")||e.endsWith(".pdf")||e.endsWith(".svg"))),{params:{errorMessage:"The value must be a string that ends with .jpeg, .jpg, .png, .pdf, or .svg"}}).nullable():zod.z.string().trim().refine((e=>e.length>=6&&e.endsWith(".jpeg")||e.length>=5&&(e.endsWith(".jpg")||e.endsWith(".png")||e.endsWith(".pdf")||e.endsWith(".svg"))||["undefined","null",""].includes(e)),{params:{errorMessage:"The value must be a string that ends with .jpeg, .jpg, .png, .pdf, or .svg"}}).transform((e=>["undefined","null",""].includes(e)?null:e)).nullable(),type:e=>v.enum(["jpeg","jpg","png","pdf","svg"],e),constr:e=>v.enum(["chart","stockChart","mapChart","ganttChart"],e),b64:e=>v.boolean(e),noDownload:e=>v.boolean(e),defaultHeight:e=>v.positiveNum(e),defaultWidth:e=>v.positiveNum(e),defaultScale:e=>e?zod.z.number().gte(.1).lte(5):zod.z.union([zod.z.string().trim().refine((e=>!isNaN(Number(e))&&!0!==e&&!e.startsWith("[")&&Number(e)>=.1&&Number(e)<=5||["undefined","null",""].includes(e)),{params:{errorMessage:"The value must be within a 0.1 and 5.0 range"}}).transform((e=>["undefined","null",""].includes(e)?null:Number(e))),zod.z.number().gte(.1).lte(5)]).nullable(),height(e){return this.defaultHeight(e).nullable()},width(e){return this.defaultWidth(e).nullable()},scale(e){return this.defaultScale(e).nullable()},globalOptions:()=>v.additionalOptions(),themeOptions:()=>v.additionalOptions(),batch:e=>v.string(e),rasterizationTimeout:e=>v.nonNegativeNum(e),allowCodeExecution:e=>v.boolean(e),allowFileResources:e=>v.boolean(e),customCode:e=>v.string(e),callback:e=>v.string(e),resources(e){const t=zod.z.object({js:v.string(!1),css:v.string(!1),files:v.stringArray((e=>!["undefined","null",""].includes(e)),",",!0).nullable()}).partial(),o=zod.z.string().trim().refine((e=>e.startsWith("{")&&e.endsWith("}")||e.length>=6&&e.endsWith(".json")),{params:{errorMessage:"The value must be a string that starts with '{' and ends with '}"}}),r=zod.z.string().trim().refine((e=>e.startsWith("{")&&e.endsWith("}")||e.length>=6&&e.endsWith(".json")||["undefined","null",""].includes(e)),{params:{errorMessage:"The value must be a string that ends with .json"}}).transform((e=>["undefined","null",""].includes(e)?null:e));return e?zod.z.union([t,o]).nullable():zod.z.union([t,r]).nullable()},loadConfig:e=>v.string(e).refine((e=>null===e||e.length>=6&&e.endsWith(".json")),{params:{errorMessage:"The value must be a string that ends with .json"}}),createConfig(e){return this.loadConfig(e)},enableServer:e=>v.boolean(e),host:e=>v.string(e),port:e=>v.nonNegativeNum(e),uploadLimit:e=>v.positiveNum(e),serverBenchmarking:e=>v.boolean(e),proxyHost:e=>v.string(e),proxyPort:e=>v.nonNegativeNum(e).nullable(),proxyTimeout:e=>v.nonNegativeNum(e),enableRateLimiting:e=>v.boolean(e),maxRequests:e=>v.nonNegativeNum(e),window:e=>v.nonNegativeNum(e),delay:e=>v.nonNegativeNum(e),trustProxy:e=>v.boolean(e),skipKey:e=>v.string(e),skipToken:e=>v.string(e),enableSsl:e=>v.boolean(e),sslForce:e=>v.boolean(e),sslPort:e=>v.nonNegativeNum(e),sslCertPath:e=>v.string(e),minWorkers:e=>v.positiveNum(e),maxWorkers:e=>v.positiveNum(e),workLimit:e=>v.positiveNum(e),acquireTimeout:e=>v.nonNegativeNum(e),createTimeout:e=>v.nonNegativeNum(e),destroyTimeout:e=>v.nonNegativeNum(e),idleTimeout:e=>v.nonNegativeNum(e),createRetryInterval:e=>v.nonNegativeNum(e),reaperInterval:e=>v.nonNegativeNum(e),poolBenchmarking:e=>v.boolean(e),resourcesInterval:e=>v.nonNegativeNum(e),logLevel:e=>e?zod.z.number().int().gte(0).lte(5):zod.z.union([zod.z.string().trim().refine((e=>!isNaN(Number(e))&&!0!==e&&!e.startsWith("[")&&Number.isInteger(Number(e))&&Number(e)>=0&&Number(e)<=5||["undefined","null",""].includes(e)),{params:{errorMessage:"The value must be within a 0 and 5 range"}}).transform((e=>["undefined","null",""].includes(e)?null:Number(e))),zod.z.number().int().gte(0).lte(5)]).nullable(),logFile:e=>v.string(e).refine((e=>null===e||e.length>=5&&e.endsWith(".log")),{params:{errorMessage:"The value must be a string that ends with .log"}}),logDest:e=>v.string(e),logToConsole:e=>v.boolean(e),logToFile:e=>v.boolean(e),enableUi:e=>v.boolean(e),uiRoute:e=>v.startsWith(["/"],e),nodeEnv:e=>v.enum(["development","production","test"],e),listenToProcessExits:e=>v.boolean(e),noLogo:e=>v.boolean(e),hardResetPage:e=>v.boolean(e),browserShellMode:e=>v.boolean(e),validation:e=>v.boolean(e),enableDebug:e=>v.boolean(e),headless:e=>v.boolean(e),devtools:e=>v.boolean(e),listenToConsole:e=>v.boolean(e),dumpio:e=>v.boolean(e),slowMo:e=>v.nonNegativeNum(e),debuggingPort:e=>v.nonNegativeNum(e),requestId:()=>zod.z.string().uuid({message:"The value must be a stringified UUID"}).nullable()},PuppeteerSchema=e=>zod.z.object({args:validators.args(e)}).partial(),HighchartsSchema=e=>zod.z.object({version:validators.version(e),cdnUrl:validators.cdnUrl(e),forceFetch:validators.forceFetch(e),cachePath:validators.cachePath(e),coreScripts:validators.coreScripts(e),moduleScripts:validators.moduleScripts(e),indicatorScripts:validators.indicatorScripts(e),customScripts:validators.customScripts(e)}).partial(),ExportSchema=e=>zod.z.object({infile:validators.infile(e),instr:validators.instr(),options:validators.options(),svg:validators.svg(),outfile:validators.outfile(e),type:validators.type(e),constr:validators.constr(e),b64:validators.b64(e),noDownload:validators.noDownload(e),defaultHeight:validators.defaultHeight(e),defaultWidth:validators.defaultWidth(e),defaultScale:validators.defaultScale(e),height:validators.height(e),width:validators.width(e),scale:validators.scale(e),globalOptions:validators.globalOptions(),themeOptions:validators.themeOptions(),batch:validators.batch(!1),rasterizationTimeout:validators.rasterizationTimeout(e)}).partial(),CustomLogicSchema=e=>zod.z.object({allowCodeExecution:validators.allowCodeExecution(e),allowFileResources:validators.allowFileResources(e),customCode:validators.customCode(!1),callback:validators.callback(!1),resources:validators.resources(e),loadConfig:validators.loadConfig(!1),createConfig:validators.createConfig(!1)}).partial(),ProxySchema=e=>zod.z.object({host:validators.proxyHost(!1),port:validators.proxyPort(e),timeout:validators.proxyTimeout(e)}).partial(),RateLimitingSchema=e=>zod.z.object({enable:validators.enableRateLimiting(e),maxRequests:validators.maxRequests(e),window:validators.window(e),delay:validators.delay(e),trustProxy:validators.trustProxy(e),skipKey:validators.skipKey(!1),skipToken:validators.skipToken(!1)}).partial(),SslSchema=e=>zod.z.object({enable:validators.enableSsl(e),force:validators.sslForce(e),port:validators.sslPort(e),certPath:validators.sslCertPath(!1)}).partial(),ServerSchema=e=>zod.z.object({enable:validators.enableServer(e).optional(),host:validators.host(e).optional(),port:validators.port(e).optional(),uploadLimit:validators.uploadLimit(e).optional(),benchmarking:validators.serverBenchmarking(e).optional(),proxy:ProxySchema(e).optional(),rateLimiting:RateLimitingSchema(e).optional(),ssl:SslSchema(e).optional()}),PoolSchema=e=>zod.z.object({minWorkers:validators.minWorkers(e),maxWorkers:validators.maxWorkers(e),workLimit:validators.workLimit(e),acquireTimeout:validators.acquireTimeout(e),createTimeout:validators.createTimeout(e),destroyTimeout:validators.destroyTimeout(e),idleTimeout:validators.idleTimeout(e),createRetryInterval:validators.createRetryInterval(e),reaperInterval:validators.reaperInterval(e),benchmarking:validators.poolBenchmarking(e)}).partial(),LoggingSchema=e=>zod.z.object({level:validators.logLevel(e),file:validators.logFile(e),dest:validators.logDest(e),toConsole:validators.logToConsole(e),toFile:validators.logToFile(e)}).partial(),UiSchema=e=>zod.z.object({enable:validators.enableUi(e),route:validators.uiRoute(e)}).partial(),OtherSchema=e=>zod.z.object({nodeEnv:validators.nodeEnv(e),listenToProcessExits:validators.listenToProcessExits(e),noLogo:validators.noLogo(e),hardResetPage:validators.hardResetPage(e),browserShellMode:validators.browserShellMode(e),validation:validators.validation(e)}).partial(),DebugSchema=e=>zod.z.object({enable:validators.enableDebug(e),headless:validators.headless(e),devtools:validators.devtools(e),listenToConsole:validators.listenToConsole(e),dumpio:validators.dumpio(e),slowMo:validators.slowMo(e),debuggingPort:validators.debuggingPort(e)}).partial(),StrictConfigSchema=zod.z.object({requestId:validators.requestId(),puppeteer:PuppeteerSchema(!0),highcharts:HighchartsSchema(!0),export:ExportSchema(!0),customLogic:CustomLogicSchema(!0),server:ServerSchema(!0),pool:PoolSchema(!0),logging:LoggingSchema(!0),ui:UiSchema(!0),other:OtherSchema(!0),debug:DebugSchema(!0)}),LooseConfigSchema=zod.z.object({requestId:validators.requestId(),puppeteer:PuppeteerSchema(!1),highcharts:HighchartsSchema(!1),export:ExportSchema(!1),customLogic:CustomLogicSchema(!1),server:ServerSchema(!1),pool:PoolSchema(!1),logging:LoggingSchema(!1),ui:UiSchema(!1),other:OtherSchema(!1),debug:DebugSchema(!1)}),EnvSchema=zod.z.object({PUPPETEER_ARGS:validators.args(!1),HIGHCHARTS_VERSION:validators.version(!1),HIGHCHARTS_CDN_URL:validators.cdnUrl(!1),HIGHCHARTS_FORCE_FETCH:validators.forceFetch(!1),HIGHCHARTS_CACHE_PATH:validators.cachePath(!1),HIGHCHARTS_ADMIN_TOKEN:validators.adminToken(!1),HIGHCHARTS_CORE_SCRIPTS:validators.coreScripts(!1),HIGHCHARTS_MODULE_SCRIPTS:validators.moduleScripts(!1),HIGHCHARTS_INDICATOR_SCRIPTS:validators.indicatorScripts(!1),HIGHCHARTS_CUSTOM_SCRIPTS:validators.customScripts(!1),EXPORT_INFILE:validators.infile(!1),EXPORT_INSTR:validators.instr(),EXPORT_OPTIONS:validators.options(),EXPORT_SVG:validators.svg(),EXPORT_BATCH:validators.batch(!1),EXPORT_OUTFILE:validators.outfile(!1),EXPORT_TYPE:validators.type(!1),EXPORT_CONSTR:validators.constr(!1),EXPORT_B64:validators.b64(!1),EXPORT_NO_DOWNLOAD:validators.noDownload(!1),EXPORT_HEIGHT:validators.height(!1),EXPORT_WIDTH:validators.width(!1),EXPORT_SCALE:validators.scale(!1),EXPORT_DEFAULT_HEIGHT:validators.defaultHeight(!1),EXPORT_DEFAULT_WIDTH:validators.defaultWidth(!1),EXPORT_DEFAULT_SCALE:validators.defaultScale(!1),EXPORT_GLOBAL_OPTIONS:validators.globalOptions(),EXPORT_THEME_OPTIONS:validators.themeOptions(),EXPORT_RASTERIZATION_TIMEOUT:validators.rasterizationTimeout(!1),CUSTOM_LOGIC_ALLOW_CODE_EXECUTION:validators.allowCodeExecution(!1),CUSTOM_LOGIC_ALLOW_FILE_RESOURCES:validators.allowFileResources(!1),CUSTOM_LOGIC_CUSTOM_CODE:validators.customCode(!1),CUSTOM_LOGIC_CALLBACK:validators.callback(!1),CUSTOM_LOGIC_RESOURCES:validators.resources(!1),CUSTOM_LOGIC_LOAD_CONFIG:validators.loadConfig(!1),CUSTOM_LOGIC_CREATE_CONFIG:validators.createConfig(!1),SERVER_ENABLE:validators.enableServer(!1),SERVER_HOST:validators.host(!1),SERVER_PORT:validators.port(!1),SERVER_UPLOAD_LIMIT:validators.uploadLimit(!1),SERVER_BENCHMARKING:validators.serverBenchmarking(!1),SERVER_PROXY_HOST:validators.proxyHost(!1),SERVER_PROXY_PORT:validators.proxyPort(!1),SERVER_PROXY_TIMEOUT:validators.proxyTimeout(!1),SERVER_RATE_LIMITING_ENABLE:validators.enableRateLimiting(!1),SERVER_RATE_LIMITING_MAX_REQUESTS:validators.maxRequests(!1),SERVER_RATE_LIMITING_WINDOW:validators.window(!1),SERVER_RATE_LIMITING_DELAY:validators.delay(!1),SERVER_RATE_LIMITING_TRUST_PROXY:validators.trustProxy(!1),SERVER_RATE_LIMITING_SKIP_KEY:validators.skipKey(!1),SERVER_RATE_LIMITING_SKIP_TOKEN:validators.skipToken(!1),SERVER_SSL_ENABLE:validators.enableSsl(!1),SERVER_SSL_FORCE:validators.sslForce(!1),SERVER_SSL_PORT:validators.sslPort(!1),SERVER_SSL_CERT_PATH:validators.sslCertPath(!1),POOL_MIN_WORKERS:validators.minWorkers(!1),POOL_MAX_WORKERS:validators.maxWorkers(!1),POOL_WORK_LIMIT:validators.workLimit(!1),POOL_ACQUIRE_TIMEOUT:validators.acquireTimeout(!1),POOL_CREATE_TIMEOUT:validators.createTimeout(!1),POOL_DESTROY_TIMEOUT:validators.destroyTimeout(!1),POOL_IDLE_TIMEOUT:validators.idleTimeout(!1),POOL_CREATE_RETRY_INTERVAL:validators.createRetryInterval(!1),POOL_REAPER_INTERVAL:validators.reaperInterval(!1),POOL_BENCHMARKING:validators.poolBenchmarking(!1),LOGGING_LEVEL:validators.logLevel(!1),LOGGING_FILE:validators.logFile(!1),LOGGING_DEST:validators.logDest(!1),LOGGING_TO_CONSOLE:validators.logToConsole(!1),LOGGING_TO_FILE:validators.logToFile(!1),UI_ENABLE:validators.enableUi(!1),UI_ROUTE:validators.uiRoute(!1),OTHER_NODE_ENV:validators.nodeEnv(!1),OTHER_LISTEN_TO_PROCESS_EXITS:validators.listenToProcessExits(!1),OTHER_NO_LOGO:validators.noLogo(!1),OTHER_HARD_RESET_PAGE:validators.hardResetPage(!1),OTHER_BROWSER_SHELL_MODE:validators.browserShellMode(!1),OTHER_VALIDATION:validators.validation(!1),DEBUG_ENABLE:validators.enableDebug(!1),DEBUG_HEADLESS:validators.headless(!1),DEBUG_DEVTOOLS:validators.devtools(!1),DEBUG_LISTEN_TO_CONSOLE:validators.listenToConsole(!1),DEBUG_DUMPIO:validators.dumpio(!1),DEBUG_SLOW_MO:validators.slowMo(!1),DEBUG_DEBUGGING_PORT:validators.debuggingPort(!1)}),envs=EnvSchema.partial().parse(process.env);function strictValidate(e){return StrictConfigSchema.partial().parse(e)}function looseValidate(e){return LooseConfigSchema.partial().parse(e)}function _customErrorMap(e,t){const o=e.path.join("."),r=`Invalid value for the ${o}`;if(e.code===zod.z.ZodIssueCode.invalid_type)return e.received===zod.z.ZodParsedType.undefined?{message:`${r} - No value was provided.`}:{message:`${r} - Invalid type. ${t.defaultError}.`};if(e.code===zod.z.ZodIssueCode.custom&&e.params?.errorMessage)return{message:`${r} - ${e.params?.errorMessage}, received '${t.data}'.`};if(e.code===zod.z.ZodIssueCode.invalid_union){let t=`Multiple errors occurred for the ${o}:\n`;return e.unionErrors.forEach((e=>{const o=e.issues[0].message.indexOf("-");t+=-1!==o?`${e.issues[0].message}\n`.substring(o):`${e.issues[0].message}\n`})),{message:t}}return{message:`${r} - ${t.defaultError}.`}}class ExportError extends Error{constructor(e,t){super(),this.message=e,this.stackMessage=e,t&&(this.statusCode=t)}setStatus(e){return this.statusCode=e,this}setError(e){return this.error=e,e.name&&(this.name=e.name),e.statusCode&&(this.statusCode=e.statusCode),e.stack&&(this.stackMessage=e.message,this.stack=e.stack),this}}const globalOptions=_initGlobalOptions(defaultConfig),instanceOptions=deepCopy(globalOptions);function getOptions(e=!0){return e?instanceOptions:globalOptions}function setGlobalOptions(e={},t=[]){let o={},r={};if(t&&Array.isArray(t)&&t.length){try{o=strictValidate(_loadConfigFile(t,globalOptions.customLogic))}catch(e){logZodIssues(1,e.issues,"[validation] Custom options from the `loadConfig` option validation error")}try{r=looseValidate(_pairArgumentValue(nestedProps,t))}catch(e){logZodIssues(1,e.issues,"[validation] CLI options validation error")}}if(e&&isObject(e)&&Object.keys(e).length)try{e=strictValidate(e)}catch(e){logZodIssues(1,e.issues,"[validation] Custom options validation error")}return _updateGlobalOptions(defaultConfig,globalOptions,o,r,e),globalOptions}function updateOptions(e,t=!1){return t&&(Object.keys(instanceOptions).forEach((e=>{delete instanceOptions[e]})),mergeOptions(instanceOptions,deepCopy(globalOptions))),mergeOptions(instanceOptions,e),instanceOptions}function mergeOptions(e,t){if(isObject(e)&&isObject(t))for(const[o,r]of Object.entries(t))e[o]=isObject(r)&&!absoluteProps.includes(o)&&void 0!==e[o]?mergeOptions(e[o],r):void 0!==r?r:e[o]||null;return e}function mapToNewOptions(e){const t={};if(isObject(e))for(const[o,r]of Object.entries(e)){const e=nestedProps[o]?nestedProps[o].split("."):[];e.reduce(((t,o,i)=>t[o]=e.length-1===i?r:t[o]||{}),t)}else log(2,"[config] No correct object with options was provided. Returning an empty array.");return t}function validateOption(e,t,o=!0){if(!getOptions().other.validation)return t;try{return validators[e](o).parse(t)}catch(t){throw logZodIssues(1,t.issues,`[validation] The ${e} option validation error`),new ExportError(`[validation] The ${e} option validation error`,400)}}function validateOptions(e,t=!0){if(!getOptions().other.validation)return e;try{return t?strictValidate(e):looseValidate(e)}catch(e){throw logZodIssues(1,e.issues,"[validation] Options validation error"),new ExportError("[validation] Options validation error",400)}}function isAllowedConfig(config,toString=!1,allowFunctions=!1){try{if(!isObject(config)&&"string"!=typeof config)return null;const objectConfig="string"==typeof config?allowFunctions?eval(`(${config})`):JSON.parse(config):config,stringifiedOptions=_optionsStringify(objectConfig,allowFunctions,!1),parsedOptions=allowFunctions?JSON.parse(_optionsStringify(objectConfig,allowFunctions,!0),((_,value)=>"string"==typeof value&&value.startsWith("function")?eval(`(${value})`):value)):JSON.parse(stringifiedOptions);return toString?stringifiedOptions:parsedOptions}catch(e){return null}}function _initGlobalOptions(e){const t={};for(const[o,r]of Object.entries(e))if(Object.prototype.hasOwnProperty.call(r,"value")){const e=envs[r.envLink];t[o]=null!=e?e:r.value}else t[o]=_initGlobalOptions(r);return t}function _updateGlobalOptions(e,t,o,r,i){Object.keys(e).forEach((n=>{const s=e[n],a=o&&o[n],l=r&&r[n],c=i&&i[n];if(void 0===s.value)_updateGlobalOptions(s,t[n],a,l,c);else{null!=a&&(t[n]=a);const e=envs[s.envLink];s.envLink in envs&&null!=e&&(t[n]=e),null!=l&&(t[n]=l),null!=c&&(t[n]=c)}}))}function _optionsStringify(e,t,o){return JSON.stringify(e,((e,r)=>{if("string"==typeof r&&(r=r.trim()),"function"==typeof r||"string"==typeof r&&r.startsWith("function")&&r.endsWith("}")){if(t)return o?`"EXP_FUN${(r+"").replaceAll(/\s+/g," ")}EXP_FUN"`:`EXP_FUN${(r+"").replaceAll(/\s+/g," ")}EXP_FUN`;throw new Error}return r})).replaceAll(o?/\\"EXP_FUN|EXP_FUN\\"/g:/"EXP_FUN|EXP_FUN"/g,"")}function _loadConfigFile(e,t){const o=e.findIndex((e=>"loadConfig"===e.replace(/-/g,""))),r=o>-1&&e[o+1];if(r&&t.allowFileResources)try{return isAllowedConfig(fs.readFileSync(getAbsolutePath(r),"utf8"),!1,t.allowCodeExecution)}catch(e){logWithStack(2,e,`[config] Unable to load the configuration from the ${r} file.`)}return{}}function _pairArgumentValue(e,t){const o={};for(let r=0;r{if(n.length-1===s){const n=t[++r];n||log(2,`[config] Missing value for the CLI '--${i}' argument. Using the default value.`),e[o]=n||null}else void 0===e[o]&&(e[o]={});return e[o]}),o)}return o}async function fetch(e,t={}){return new Promise(((o,r)=>{_getProtocolModule(e).get(e,t,(e=>{let t="";e.on("data",(e=>{t+=e})),e.on("end",(()=>{t||r("Nothing was fetched from the URL."),e.text=t,o(e)}))})).on("error",(e=>{r(e)}))}))}function _getProtocolModule(e){return e.startsWith("https")?https:http}const cache={cdnUrl:"https://code.highcharts.com",activeManifest:{},sources:"",hcVersion:""};async function checkAndUpdateCache(e,t){try{let o;const r=getCachePath(),i=path.join(r,"manifest.json"),n=path.join(r,"sources.js");if(!fs.existsSync(r)&&fs.mkdirSync(r,{recursive:!0}),!fs.existsSync(i)||e.forceFetch)log(3,"[cache] Fetching and caching Highcharts dependencies."),o=await _updateCache(e,t,n);else{let r=!1;const s=JSON.parse(fs.readFileSync(i),"utf8");if(s.modules&&Array.isArray(s.modules)){const e={};s.modules.forEach((t=>e[t]=1)),s.modules=e}const{coreScripts:a,moduleScripts:l,indicatorScripts:c}=e,p=a.length+l.length+c.length;s.version!==e.version?(log(2,"[cache] A Highcharts version mismatch in the cache, need to re-fetch."),r=!0):Object.keys(s.modules||{}).length!==p?(log(2,"[cache] The cache and the requested modules do not match, need to re-fetch."),r=!0):r=(l||[]).some((e=>{if(!s.modules[e])return log(2,`[cache] The ${e} is missing in the cache, need to re-fetch.`),!0})),r?o=await _updateCache(e,t,n):(log(3,"[cache] Dependency cache is up to date, proceeding."),cache.sources=fs.readFileSync(n,"utf8"),o=s.modules,cache.hcVersion=extractVersion(cache.sources))}await _saveConfigToManifest(e,o)}catch(e){throw new ExportError("[cache] Could not configure cache and create or update the config manifest.",500).setError(e)}}function getHighchartsVersion(){return cache.hcVersion}async function updateHighchartsVersion(e){const t=getOptions();t.highcharts.version=e,await checkAndUpdateCache(t.highcharts,t.server.proxy)}function extractVersion(e){return e.substring(0,e.indexOf("*/")).replace("/*","").replace("*/","").replace(/\n/g,"").trim()}function extractModuleName(e){return e.replace(/(.*)\/|(.*)modules\/|stock\/(.*)indicators\/|maps\/(.*)modules\//gi,"")}function getCachePath(){return getAbsolutePath(getOptions().highcharts.cachePath)}async function _fetchAndProcessScript(e,t,o,r=!1){e.endsWith(".js")&&(e=e.substring(0,e.length-3)),log(4,`[cache] Fetching script - ${e}.js`);const i=await fetch(`${e}.js`,t);if(200===i.statusCode&&"string"==typeof i.text){if(o){o[extractModuleName(e)]=1}return i.text}if(r)throw new ExportError(`[cache] Could not fetch the ${e}.js. The script might not exist in the requested version (status code: ${i.statusCode}).`,404).setError(i);log(2,`[cache] Could not fetch the ${e}.js. The script might not exist in the requested version.`)}async function _saveConfigToManifest(e,t={}){const o={version:e.version,modules:t};cache.activeManifest=o,log(3,"[cache] Writing a new manifest.");try{fs.writeFileSync(path.join(getCachePath(),"manifest.json"),JSON.stringify(o),"utf8")}catch(e){throw new ExportError("[cache] Error writing the cache manifest.",500).setError(e)}}async function _fetchScripts(e,t,o,r,i){let n;const s=r.host,a=r.port;if(s&&a)try{n=new httpsProxyAgent.HttpsProxyAgent({host:s,port:a})}catch(e){throw new ExportError("[cache] Could not create a Proxy Agent.",500).setError(e)}const l=n?{agent:n,timeout:r.timeout}:{},c=[...e.map((e=>_fetchAndProcessScript(`${e}`,l,i,!0))),...t.map((e=>_fetchAndProcessScript(`${e}`,l,i))),...o.map((e=>_fetchAndProcessScript(`${e}`,l)))];return(await Promise.all(c)).join(";\n")}async function _updateCache(e,t,o){const r="latest"===e.version?null:`${e.version}`,i=e.cdnUrl||cache.cdnUrl;try{const n={};return log(3,`[cache] Updating cache version to Highcharts: ${r||"latest"}.`),cache.sources=await _fetchScripts([...e.coreScripts.map((e=>r?`${i}/${r}/${e}`:`${i}/${e}`))],[...e.moduleScripts.map((e=>"map"===e?r?`${i}/maps/${r}/modules/${e}`:`${i}/maps/modules/${e}`:r?`${i}/${r}/modules/${e}`:`${i}/modules/${e}`)),...e.indicatorScripts.map((e=>r?`${i}/stock/${r}/indicators/${e}`:`${i}/stock/indicators/${e}`))],e.customScripts,t,n),cache.hcVersion=extractVersion(cache.sources),fs.writeFileSync(o,cache.sources),n}catch(e){throw new ExportError("[cache] Unable to update the local Highcharts cache.",500).setError(e)}}function setupHighcharts(){Highcharts.animObject=function(){return{duration:0}}}async function createChart(e,t){const{getOptions:o,setOptions:r,merge:i,wrap:n}=Highcharts;Highcharts.setOptionsObj=i(!1,{},o()),window.isRenderComplete=!1,n(Highcharts.Chart.prototype,"init",(function(e,t,o){((t=i(t,{exporting:{enabled:!1},plotOptions:{series:{label:{enabled:!1}}},tooltip:{}})).series||[]).forEach((function(e){e.animation=!1})),window.onHighchartsRender||(window.onHighchartsRender=Highcharts.addEvent(this,"render",(()=>{window.isRenderComplete=!0}))),e.apply(this,[t,o])})),n(Highcharts.Series.prototype,"init",(function(e,t,o){e.apply(this,[t,o])}));const s={chart:{animation:!1,height:e.height,width:e.width},exporting:{enabled:!1}},a=new Function(`return ${e.instr}`)(),l=new Function(`return ${e.themeOptions}`)(),c=new Function(`return ${e.globalOptions}`)(),p=i(!1,l,a,s),u=t.callback?new Function(`return ${t.callback}`)():null;t.customCode&&new Function("options",t.customCode)(a),c&&r(c),Highcharts[e.constr]("container",p,u);const d=o();for(const e in d)"function"!=typeof d[e]&&delete d[e];r(Highcharts.setOptionsObj),Highcharts.setOptionsObj={}}const template=fs.readFileSync(path.join(__dirname$1,"templates","template.html"),"utf8");let browser=null;async function createBrowser(e){const{debug:t,other:o}=getOptions(),{enable:r,...i}=t,n={headless:!o.browserShellMode||"shell",userDataDir:"tmp",args:e||[],handleSIGINT:!1,handleSIGTERM:!1,handleSIGHUP:!1,waitForInitialPage:!1,defaultViewport:null,...r&&i};if(!browser){let e=0;const t=async()=>{try{log(3,`[browser] Attempting to get a browser instance (try ${++e}).`),browser=await puppeteer.launch(n)}catch(o){if(logWithStack(1,o,"[browser] Failed to launch a browser instance."),!(e<25))throw o;log(3,`[browser] Retry to open a browser (${e} out of 25).`),await new Promise((e=>setTimeout(e,4e3))),await t()}};try{await t(),"shell"===n.headless&&log(3,"[browser] Launched browser in shell mode."),r&&log(3,"[browser] Launched browser in debug mode.")}catch(e){throw new ExportError("[browser] Maximum retries to open a browser instance reached.",500).setError(e)}if(!browser)throw new ExportError("[browser] Cannot find a browser to open.",500)}return browser}async function closeBrowser(){browser&&browser.connected&&await browser.close(),browser=null,log(4,"[browser] Closed the browser.")}async function newPage(e){if(!browser||!browser.connected)throw new ExportError("[browser] Browser is not yet connected.",500);if(e.page=await browser.newPage(),await e.page.setCacheEnabled(!1),await _setPageContent(e.page),_setPageEvents(e.page),!e.page||e.page.isClosed())throw new ExportError("[browser] The page is invalid or closed.",400)}async function clearPage(e,t=!1){try{if(e.page&&!e.page.isClosed())return t?(await e.page.goto("about:blank",{waitUntil:"domcontentloaded"}),await _setPageContent(e.page)):await e.page.evaluate((()=>{document.body.innerHTML='
'})),!0}catch(t){logWithStack(2,t,`[pool] Pool resource [${e.id}] - Content of the page could not be cleared.`),e.workCount=getOptions().pool.workLimit+1}return!1}async function addPageResources(e,t){const o=[],r=t.resources;if(r){const i=[];if(r.js&&i.push({content:r.js}),r.files)for(const e of r.files){const t=!e.startsWith("http");i.push(t?{content:fs.readFileSync(getAbsolutePath(e),"utf8")}:{url:e})}for(const t of i)try{o.push(await e.addScriptTag(t))}catch(e){logWithStack(2,e,"[browser] The JS resource cannot be loaded.")}i.length=0;const n=[];if(r.css){let i=r.css.match(/@import\s*([^;]*);/g);if(i)for(let e of i)e&&(e=e.replace("url(","").replace("@import","").replace(/"/g,"").replace(/'/g,"").replace(/;/,"").replace(/\)/g,"").trim(),e.startsWith("http")?n.push({url:e}):t.allowFileResources&&n.push({path:path.join(__dirname$1,e)}));n.push({content:r.css.replace(/@import\s*([^;]*);/g,"")||" "});for(const t of n)try{o.push(await e.addStyleTag(t))}catch(e){logWithStack(2,e,"[browser] The CSS resource cannot be loaded.")}n.length=0}}return o}async function clearPageResources(e,t){try{for(const e of t)await e.dispose();await e.evaluate((()=>{if("undefined"!=typeof Highcharts){const e=Highcharts.charts;if(Array.isArray(e)&&e.length)for(const t of e)t&&t.destroy(),Highcharts.charts.shift()}const[...e]=document.getElementsByTagName("script"),[,...t]=document.getElementsByTagName("style"),[...o]=document.getElementsByTagName("link");for(const r of[...e,...t,...o])r.remove()}))}catch(e){logWithStack(2,e,"[browser] Could not clear page's resources.")}}async function _setPageContent(e){await e.setContent(template,{waitUntil:"domcontentloaded"}),await e.addScriptTag({path:path.join(getCachePath(),"sources.js")}),await e.evaluate(setupHighcharts)}function _setPageEvents(e){const{debug:t}=getOptions();e.on("pageerror",(async()=>{e.isClosed()})),t.enable&&t.listenToConsole&&e.on("console",(e=>{console.log(`[debug] ${e.text()}`)}))}var cssTemplate=()=>"\n\nhtml, body {\n margin: 0;\n padding: 0;\n box-sizing: border-box;\n}\n\n#table-div, #sliders, #datatable, #controls, .ld-row {\n display: none;\n height: 0;\n}\n\n#chart-container {\n box-sizing: border-box;\n margin: 0;\n overflow: auto;\n font-size: 0;\n}\n\n#chart-container > figure, div {\n margin-top: 0 !important;\n margin-bottom: 0 !important;\n}\n\n",svgTemplate=e=>`\n\n\n \n \n Highcharts Export\n \n \n \n
\n ${e}\n
\n \n\n\n`;async function puppeteerExport(e,t,o){const r=[];try{let i=!1;if(t.svg){if(log(4,"[export] Treating as SVG input."),"svg"===t.type)return t.svg;i=!0,await e.setContent(svgTemplate(t.svg),{waitUntil:"domcontentloaded"})}else log(4,"[export] Treating as JSON config."),await e.evaluate(createChart,t,o);r.push(...await addPageResources(e,o));const n=i?await e.evaluate((e=>{const t=document.querySelector("#chart-container svg:first-of-type"),o=t.height.baseVal.value*e,r=t.width.baseVal.value*e;return document.body.style.zoom=e,document.body.style.margin="0px",{chartHeight:o,chartWidth:r}}),parseFloat(t.scale)):await e.evaluate((()=>{const{chartHeight:e,chartWidth:t}=window.Highcharts.charts[0];return document.body.style.zoom=1,{chartHeight:e,chartWidth:t}})),{x:s,y:a}=await _getClipRegion(e),l=Math.abs(Math.ceil(n.chartHeight||t.height)),c=Math.abs(Math.ceil(n.chartWidth||t.width));let p;switch(await e.setViewport({height:l,width:c,deviceScaleFactor:i?1:parseFloat(t.scale)}),t.type){case"svg":p=await _createSVG(e);break;case"png":case"jpeg":p=await _createImage(e,t.type,{width:c,height:l,x:s,y:a},t.rasterizationTimeout);break;case"pdf":p=await _createPDF(e,l,c,t.rasterizationTimeout);break;default:throw new ExportError(`[export] Unsupported output format: ${t.type}.`,400)}return await clearPageResources(e,r),p}catch(t){return await clearPageResources(e,r),t}}async function _getClipRegion(e){return e.$eval("#chart-container",(e=>{const{x:t,y:o,width:r,height:i}=e.getBoundingClientRect();return{x:t,y:o,width:r,height:Math.trunc(i>1?i:500)}}))}async function _createSVG(e){return e.$eval("#container svg:first-of-type",(e=>e.outerHTML))}async function _createImage(e,t,o,r){return Promise.race([e.screenshot({type:t,clip:o,encoding:"base64",fullPage:!1,optimizeForSpeed:!0,captureBeyondViewport:!0,..."png"!==t?{quality:80}:{},omitBackground:"png"==t}),new Promise(((e,t)=>setTimeout((()=>t(new ExportError("Rasterization timeout",408))),r||1500)))])}async function _createPDF(e,t,o,r){return await e.emulateMediaType("screen"),e.pdf({height:t+1,width:o,encoding:"base64",timeout:r||1500})}let pool=null;const poolStats={exportsAttempted:0,exportsPerformed:0,exportsDropped:0,exportsFromSvg:0,exportsFromOptions:0,exportsFromSvgAttempts:0,exportsFromOptionsAttempts:0,timeSpent:0,timeSpentAverage:0};async function initPool(e,t){await createBrowser(t);try{if(log(3,`[pool] Initializing pool with workers: min ${e.minWorkers}, max ${e.maxWorkers}.`),pool)return void log(4,"[pool] Already initialized, please kill it before creating a new one.");e.minWorkers>e.maxWorkers&&(e.minWorkers=e.maxWorkers),pool=new tarn.Pool({..._factory(e),min:e.minWorkers,max:e.maxWorkers,acquireTimeoutMillis:e.acquireTimeout,createTimeoutMillis:e.createTimeout,destroyTimeoutMillis:e.destroyTimeout,idleTimeoutMillis:e.idleTimeout,createRetryIntervalMillis:e.createRetryInterval,reapIntervalMillis:e.reaperInterval,propagateCreateError:!1}),pool.on("release",(async e=>{const t=await clearPage(e,!1);log(4,`[pool] Pool resource [${e.id}] - Releasing a worker. Clear page status: ${t}.`)})),pool.on("destroySuccess",((e,t)=>{log(4,`[pool] Pool resource [${t.id}] - Destroyed a worker successfully.`),t.page=null}));const t=[];for(let o=0;o{pool.release(e)})),log(3,"[pool] The pool is ready"+(t.length?` with ${t.length} initial resources waiting.`:"."))}catch(e){throw new ExportError("[pool] Could not configure and create the pool of workers.",500).setError(e)}}async function killPool(){if(log(3,"[pool] Killing pool with all workers and closing browser."),pool){for(const e of pool.used)pool.release(e.resource);pool.destroyed||(await pool.destroy(),log(4,"[pool] Destroyed the pool of resources.")),pool=null}await closeBrowser()}async function postWork(e){let t;try{if(log(4,"[pool] Work received, starting to process."),++poolStats.exportsAttempted,e.pool.benchmarking&&getPoolInfo(),!pool)throw new ExportError("[pool] Work received, but pool has not been started.",500);const o=measureTime();try{log(4,"[pool] Acquiring a worker handle."),t=await pool.acquire().promise,e.server.benchmarking&&log(5,"[benchmark] "+(e.requestId?`Request [${e.requestId}] - `:""),`Acquiring a worker handle took ${o()}ms.`)}catch(t){throw new ExportError(`[pool] ${e.requestId?`Request [${e.requestId}] - `:""}Error encountered when acquiring an available entry: ${o()}ms.`,400).setError(t)}if(log(4,"[pool] Acquired a worker handle."),!t.page)throw t.workCount=e.pool.workLimit+1,new ExportError("[pool] Resolved worker page is invalid: the pool setup is wonky.",400);const r=getNewDateTime();log(4,`[pool] Pool resource [${t.id}] - Starting work on this pool entry.`);const i=measureTime(),n=await puppeteerExport(t.page,e.export,e.customLogic);if(n instanceof Error)throw"Rasterization timeout"===n.message&&(t.workCount=e.pool.workLimit+1,t.page=null),"TimeoutError"===n.name||"Rasterization timeout"===n.message?new ExportError(`[pool] ${e.requestId?`Request [${e.requestId}] - `:""}Rasterization timeout: your chart may be too complex or large, and failed to render within the allotted time.`).setError(n):new ExportError(`[pool] ${e.requestId?`Request [${e.requestId}] - `:""}Error encountered during export: ${i()}ms.`).setError(n);e.server.benchmarking&&log(5,"[benchmark] "+(e.requestId?`Request [${e.requestId}] - `:""),`Exporting a chart sucessfully took ${i()}ms.`),pool.release(t);const s=getNewDateTime()-r;return poolStats.timeSpent+=s,poolStats.timeSpentAverage=poolStats.timeSpent/++poolStats.exportsPerformed,log(4,`[pool] Work completed in ${s}ms.`),{result:n,options:e}}catch(e){throw++poolStats.exportsDropped,t&&pool.release(t),e}}function getPoolStats(){return poolStats}function getPoolInfoJSON(){return{min:pool.min,max:pool.max,used:pool.numUsed(),available:pool.numFree(),allCreated:pool.numUsed()+pool.numFree(),pendingAcquires:pool.numPendingAcquires(),pendingCreates:pool.numPendingCreates(),pendingValidations:pool.numPendingValidations(),pendingDestroys:pool.pendingDestroys.length,absoluteAll:pool.numUsed()+pool.numFree()+pool.numPendingAcquires()+pool.numPendingCreates()+pool.numPendingValidations()+pool.pendingDestroys.length}}function getPoolInfo(){const{min:e,max:t,used:o,available:r,allCreated:i,pendingAcquires:n,pendingCreates:s,pendingValidations:a,pendingDestroys:l,absoluteAll:c}=getPoolInfoJSON();log(5,`[pool] The minimum number of resources allowed by pool: ${e}.`),log(5,`[pool] The maximum number of resources allowed by pool: ${t}.`),log(5,`[pool] The number of used resources: ${o}.`),log(5,`[pool] The number of free resources: ${r}.`),log(5,`[pool] The number of all created (used and free) resources: ${i}.`),log(5,`[pool] The number of resources waiting to be acquired: ${n}.`),log(5,`[pool] The number of resources waiting to be created: ${s}.`),log(5,`[pool] The number of resources waiting to be validated: ${a}.`),log(5,`[pool] The number of resources waiting to be destroyed: ${l}.`),log(5,`[pool] The number of all resources: ${c}.`)}function _factory(e){return{create:async()=>{const t={id:uuid.v4(),workCount:Math.round(Math.random()*(e.workLimit/2))};try{const e=getNewDateTime();return await newPage(t),log(3,`[pool] Pool resource [${t.id}] - Successfully created a worker, took ${getNewDateTime()-e}ms.`),t}catch(e){throw log(3,`[pool] Pool resource [${t.id}] - Error encountered when creating a new page.`),e}},validate:async t=>t.page?t.page.isClosed()?(log(3,`[pool] Pool resource [${t.id}] - Validation failed (page is closed or invalid).`),!1):t.page.mainFrame().detached?(log(3,`[pool] Pool resource [${t.id}] - Validation failed (page's frame is detached).`),!1):!(e.workLimit&&++t.workCount>e.workLimit)||(log(3,`[pool] Pool resource [${t.id}] - Validation failed (exceeded the ${e.workLimit} works per resource limit).`),!1):(log(3,`[pool] Pool resource [${t.id}] - Validation failed (no valid page is found).`),!1),destroy:async e=>{if(log(3,`[pool] Pool resource [${e.id}] - Destroying a worker.`),e.page&&!e.page.isClosed())try{e.page.removeAllListeners("pageerror"),e.page.removeAllListeners("console"),e.page.removeAllListeners("framedetached"),await e.page.close()}catch(t){throw log(3,`[pool] Pool resource [${e.id}] - Page could not be closed upon destroying.`),t}}}}function sanitize(e){const t=new jsdom.JSDOM("").window;return DOMPurify(t).sanitize(e,{ADD_TAGS:["foreignObject"]})}let allowCodeExecution=!1;async function singleExport(e){if(!e||!e.export)throw new ExportError("[chart] No expected `export` options were found. Please provide one of the following options: `infile`, `instr`, `options`, or `svg` to generate a valid image.",400);e=validateOptions(e),await startExport({export:e.export,customLogic:e.customLogic},(async(e,t)=>{if(e)throw e;const{b64:o,outfile:r,type:i}=t.options.export;try{o?fs.writeFileSync(`${r.split(".").shift()||"chart"}.txt`,getBase64(t.result,i)):fs.writeFileSync(r||`chart.${i}`,"svg"!==i?Buffer.from(t.result,"base64"):t.result)}catch(e){throw new ExportError("[chart] Error while saving a chart.",500).setError(e)}await killPool()}))}async function batchExport(e){if(!(e&&e.export&&e.export.batch))throw new ExportError("[chart] No expected `export` options were found. Please provide the `batch` option to generate valid images.",400);{e=validateOptions(e);const t=[];for(let o of e.export.batch.split(";")||[])o=o.split("="),2===o.length?t.push(startExport({export:{...e.export,infile:o[0],outfile:o[1]},customLogic:e.customLogic},((e,t)=>{if(e)throw e;const{b64:o,outfile:r,type:i}=t.options.export;try{o?fs.writeFileSync(`${r.split(".").shift()||"chart"}.txt`,getBase64(t.result,i)):fs.writeFileSync(r,"svg"!==i?Buffer.from(t.result,"base64"):t.result)}catch(e){throw new ExportError("[chart] Error while saving a chart.",500).setError(e)}}))):log(2,"[chart] No correct pair found for the batch export.");const o=await Promise.allSettled(t);await killPool(),o.forEach(((e,t)=>{e.reason&&logWithStack(1,e.reason,`[chart] Batch export number ${t+1} could not be correctly completed.`)}))}}async function startExport(e,t){try{if(!isObject(e))throw new ExportError("[chart] Incorrect value of the provided `exportingOptions`. Needs to be an object.",400);const o=mergeOptions(deepCopy(getOptions()),{export:e.export,customLogic:e.customLogic}),r=o.export;if(log(4,"[chart] Starting the exporting process."),null!==r.infile){let e;log(4,"[chart] Attempting to export from a file input.");try{e=fs.readFileSync(getAbsolutePath(r.infile),"utf8")}catch(e){throw new ExportError("[chart] Error loading content from a file input.",400).setError(e)}if(r.infile.endsWith(".svg"))r.svg=validateOption("svg",e);else{if(!r.infile.endsWith(".json"))throw new ExportError("[chart] Incorrect value of the `infile` option.",400);r.instr=validateOption("instr",e)}}if(null!==r.svg){log(4,"[chart] Attempting to export from an SVG input."),++getPoolStats().exportsFromSvgAttempts;const e=await _exportFromSvg(sanitize(r.svg),o);return++getPoolStats().exportsFromSvg,t(null,e)}if(null!==r.instr||null!==r.options){log(4,"[chart] Attempting to export from options input."),++getPoolStats().exportsFromOptionsAttempts;const e=await _exportFromOptions(r.instr||r.options,o);return++getPoolStats().exportsFromOptions,t(null,e)}return t(new ExportError("[chart] No valid input specified. Check if at least one of the following parameters is correctly set: 'infile', 'instr', 'options', or 'svg'.",400))}catch(e){return t(e)}}function getAllowCodeExecution(){return allowCodeExecution}function setAllowCodeExecution(e){allowCodeExecution=e}async function _exportFromSvg(e,t){if("string"==typeof e&&(e.indexOf("=0||e.indexOf("=0))return log(4,"[chart] Parsing input as SVG."),t.export.svg=e,t.export.instr=null,t.export.options=null,_prepareExport(t);throw new ExportError("[chart] Not a correct SVG input.",400)}async function _exportFromOptions(e,t){log(4,"[chart] Parsing input from options.");const o=isAllowedConfig(e,!0,t.customLogic.allowCodeExecution);if(null===o||"string"!=typeof o||!o.startsWith("{")||!o.endsWith("}"))throw new ExportError("[chart] Invalid configuration provided - Only options configurations and SVG are allowed for this server. If this is your server, JavaScript custom code can be enabled by starting the server with the `allowCodeExecution` options set to true.",403);return t.export.instr=o,t.export.svg=null,_prepareExport(t)}async function _prepareExport(e){const{export:t,customLogic:o}=e;return t.type=fixType(t.type,t.outfile),t.outfile=fixOutfile(t.type,t.outfile),t.constr=fixConstr(t.constr),log(3,`[chart] The custom logic is ${o.allowCodeExecution?"allowed":"disallowed"}.`),_handleCustomLogic(o,o.allowCodeExecution),_handleGlobalAndTheme(t,o.allowFileResources,o.allowCodeExecution),e.export={...t,..._findChartSize(t)},postWork(e)}function _findChartSize(e){const{chart:t,exporting:o}=e.options||isAllowedConfig(e.instr)||!1,{chart:r,exporting:i}=isAllowedConfig(e.globalOptions)||!1,{chart:n,exporting:s}=isAllowedConfig(e.themeOptions)||!1,a=roundNumber(Math.max(.1,Math.min(e.scale||o?.scale||i?.scale||s?.scale||e.defaultScale||1,5)),2),l={height:e.height||o?.sourceHeight||t?.height||i?.sourceHeight||r?.height||s?.sourceHeight||n?.height||e.defaultHeight||400,width:e.width||o?.sourceWidth||t?.width||i?.sourceWidth||r?.width||s?.sourceWidth||n?.width||e.defaultWidth||600,scale:a};for(let[e,t]of Object.entries(l))l[e]="string"==typeof t?+t.replace(/px|%/gi,""):t;return l}function _handleCustomLogic(e,t){if(t){if("string"==typeof e.resources)e.resources=_handleResources(e.resources,e.allowFileResources,!0);else if(!e.resources)try{e.resources=_handleResources(fs.readFileSync(getAbsolutePath("resources.json"),"utf8"),e.allowFileResources,!0)}catch(e){log(2,"[chart] Unable to load the default `resources.json` file.")}try{e.customCode=wrapAround(e.customCode,e.allowFileResources),e.customCode=validateOption("customCode",e.customCode)}catch(t){logWithStack(2,t,"[chart] The `customCode` cannot be loaded."),e.customCode=null}try{e.callback=wrapAround(e.callback,e.allowFileResources,!0),e.callback=validateOption("callback",e.callback)}catch(t){logWithStack(2,t,"[chart] The `callback` cannot be loaded."),e.callback=null}[null,void 0].includes(e.customCode)&&log(3,"[chart] No value for the `customCode` option found."),[null,void 0].includes(e.callback)&&log(3,"[chart] No value for the `callback` option found."),[null,void 0].includes(e.resources)&&log(3,"[chart] No value for the `resources` option found.")}else if(e.callback||e.resources||e.customCode)throw e.callback=null,e.resources=null,e.customCode=null,new ExportError("[chart] The 'callback', 'resources', and 'customCode' options have been disabled for this server.",403)}function _handleResources(e=null,t,o){const r=["js","css","files"];let i=e,n=!1;if(t&&e.endsWith(".json"))try{i=isAllowedConfig(fs.readFileSync(getAbsolutePath(e),"utf8"),!1,o)}catch{return null}else i=isAllowedConfig(e,!1,o),i&&!t&&delete i.files;for(const e in i)r.includes(e)?n||(n=!0):delete i[e];return n?(i.files&&(i.files=i.files.map((e=>e.trim())),(!i.files||i.files.length<=0)&&delete i.files),i=validateOption("resources",i),i):null}function _handleGlobalAndTheme(e,t,o){["globalOptions","themeOptions"].forEach((r=>{try{e[r]&&(t&&"string"==typeof e[r]&&e[r].endsWith(".json")?e[r]=isAllowedConfig(fs.readFileSync(getAbsolutePath(e[r]),"utf8"),!0,o):e[r]=isAllowedConfig(e[r],!0,o),e[r]=validateOption(r,e[r]))}catch(t){logWithStack(2,t,`[chart] The \`${r}\` cannot be loaded.`),e[r]=null}})),[null,void 0].includes(e.globalOptions)&&log(3,"[chart] No value for the `globalOptions` option found."),[null,void 0].includes(e.themeOptions)&&log(3,"[chart] No value for the `themeOptions` option found.")}const timerIds=[];function addTimer(e){timerIds.push(e)}function clearAllTimers(){log(4,"[timer] Clearing all registered intervals and timeouts.");for(const e of timerIds)clearInterval(e),clearTimeout(e)}function logErrorMiddleware(e,t,o,r){return logWithStack(1,e),"development"!==getOptions().other.nodeEnv&&delete e.stack,r(e)}function returnErrorMiddleware(e,t,o,r){const{message:i,stack:n}=e,s=e.statusCode||400;o.status(s).json({statusCode:s,message:i,stack:n})}function errorMiddleware(e){e.use(logErrorMiddleware),e.use(returnErrorMiddleware)}function rateLimitingMiddleware(e,t){try{if(t.enable){const o="Too many requests, you have been rate limited. Please try again later.",r={window:t.window||1,maxRequests:t.maxRequests||30,delay:t.delay||0,trustProxy:t.trustProxy||!1,skipKey:t.skipKey||null,skipToken:t.skipToken||null};r.trustProxy&&e.enable("trust proxy");const i=rateLimit({windowMs:60*r.window*1e3,limit:r.maxRequests,delayMs:r.delay,handler:(e,t)=>{t.format({json:()=>{t.status(429).send({message:o})},default:()=>{t.status(429).send(o)}})},skip:e=>null!==r.skipKey&&null!==r.skipToken&&e.query.key===r.skipKey&&e.query.access_token===r.skipToken&&(log(4,"[rate limiting] Skipping rate limiter."),!0)});e.use(i),log(3,`[rate limiting] Enabled rate limiting with ${r.maxRequests} requests per ${r.window} minute for each IP, trusting proxy: ${r.trustProxy}.`)}}catch(e){throw new ExportError("[rate limiting] Could not configure and set the rate limiting options.",500).setError(e)}}function contentTypeMiddleware(e,t,o){try{const t=e.headers["content-type"]||"";if(!t.includes("application/json")&&!t.includes("application/x-www-form-urlencoded")&&!t.includes("multipart/form-data"))throw new ExportError("[validation] Content-Type must be application/json, application/x-www-form-urlencoded, or multipart/form-data.",415);return o()}catch(e){return o(e)}}function requestBodyMiddleware(e,t,o){try{const t=e.body,r=uuid.v4();if(!t||isObjectEmpty(t))throw log(2,`[validation] Request [${r}] - The request from ${e.headers["x-forwarded-for"]||e.connection.remoteAddress} was incorrect. Received payload is empty.`),new ExportError(`[validation] Request [${r}] - The request body is required. Please ensure that your Content-Type header is correct. Accepted types are 'application/json' and 'multipart/form-data'.`,400);const i=getAllowCodeExecution(),n=isAllowedConfig(t.instr||t.options||t.infile||t.data,!0,i);if(null===n&&!t.svg)throw log(2,`[validation] Request [${r}] - The request from ${e.headers["x-forwarded-for"]||e.connection.remoteAddress} was incorrect. Received payload is missing correct chart data for export: ${JSON.stringify(t)}.`),new ExportError(`Request [${r}] - [validation] No correct chart data found. Ensure that you are using either application/json or multipart/form-data headers. If sending JSON, make sure the chart data is in the 'infile', 'options', or 'data' attribute. If sending SVG, ensure it is in the 'svg' attribute.`,400);if(t.svg&&isPrivateRangeUrlFound(t.svg))throw new ExportError(`Request [${r}] - [validation] SVG potentially contain at least one forbidden URL in 'xlink:href' element. Please review the SVG content and ensure that all referenced URLs comply with security policies.`,400);return e.validatedOptions=validateOptions({requestId:r,export:{instr:n,svg:t.svg,outfile:t.outfile||`${e.params.filename||"chart"}.${t.type||"png"}`,type:t.type,constr:t.constr,b64:t.b64,noDownload:t.noDownload,height:t.height,width:t.width,scale:t.scale,globalOptions:isAllowedConfig(t.globalOptions,!0,i),themeOptions:isAllowedConfig(t.themeOptions,!0,i)},customLogic:{allowCodeExecution:i,allowFileResources:!1,customCode:t.customCode,callback:t.callback,resources:isAllowedConfig(t.resources,!0,i)}}),o()}catch(e){return o(e)}}function validationMiddleware(e){e.post(["/","/:filename"],contentTypeMiddleware),e.post(["/","/:filename"],requestBodyMiddleware)}const reversedMime={png:"image/png",jpeg:"image/jpeg",gif:"image/gif",pdf:"application/pdf",svg:"image/svg+xml"};async function requestExport(e,t,o){try{const o=measureTime();let r=!1;e.socket.on("close",(e=>{e&&(r=!0)}));const i=e.validatedOptions,n=i.requestId;log(4,`[export] Request [${n}] - Got an incoming HTTP request.`),await startExport(i,((i,s)=>{if(e.socket.removeAllListeners("close"),r)log(3,`[export] Request [${n}] - The client closed the connection before the chart finished processing.`);else{if(i)throw i;if(!s||!s.result)throw log(2,`[export] Request [${n}] - Request from ${e.headers["x-forwarded-for"]||e.connection.remoteAddress} was incorrect. Received result is ${s.result}.`),new ExportError(`[export] Request [${n}] - Unexpected return of the export result from the chart generation. Please check your request data.`,400);if(s.result){log(3,`[export] Request [${n}] - The whole exporting process took ${o()}ms.`);const{type:e,b64:r,noDownload:i,outfile:a}=s.options.export;return r?t.send(getBase64(s.result,e)):(t.header("Content-Type",reversedMime[e]||"image/png"),i||t.attachment(a),"svg"===e?t.send(s.result):t.send(Buffer.from(s.result,"base64")))}}}))}catch(e){return o(e)}}function exportRoutes(e){e.post("/",requestExport),e.post("/:filename",requestExport)}const serverStartTime=new Date,packageFile=JSON.parse(fs.readFileSync(path.join(__dirname$1,"package.json"),"utf8")),successRates=[],recordInterval=6e4,windowSize=30;function _calculateMovingAverage(){return successRates.reduce(((e,t)=>e+t),0)/successRates.length}function _startSuccessRate(){return setInterval((()=>{const e=getPoolStats(),t=0===e.exportsAttempted?1:e.exportsPerformed/e.exportsAttempted*100;successRates.push(t),successRates.length>windowSize&&successRates.shift()}),recordInterval)}function healthRoutes(e){addTimer(_startSuccessRate()),e.get("/health",((e,t,o)=>{try{log(4,"[health] Returning server health.");const e=getPoolStats(),o=successRates.length,r=_calculateMovingAverage();t.send({status:"OK",bootTime:serverStartTime,uptime:`${Math.floor((getNewDateTime()-serverStartTime.getTime())/1e3/60)} minutes`,serverVersion:packageFile.version,highchartsVersion:getHighchartsVersion(),averageExportTime:e.timeSpentAverage,attemptedExports:e.exportsAttempted,performedExports:e.exportsPerformed,failedExports:e.exportsDropped,sucessRatio:e.exportsPerformed/e.exportsAttempted*100,pool:getPoolInfoJSON(),period:o,movingAverage:r,message:isNaN(r)||!successRates.length?"Too early to report. No exports made yet. Please check back soon.":`Last ${o} minutes had a success rate of ${r.toFixed(2)}%.`,svgExports:e.exportsFromSvg,jsonExports:e.exportsFromOptions,svgExportsAttempts:e.exportsFromSvgAttempts,jsonExportsAttempts:e.exportsFromOptionsAttempts})}catch(e){return o(e)}}))}function uiRoutes(e){e.get(getOptions().ui.route||"/",((e,t,o)=>{try{log(4,"[ui] Returning UI for the export."),t.sendFile(path.join(__dirname$1,"public","index.html"),{acceptRanges:!1})}catch(e){return o(e)}}))}function versionChangeRoutes(e){e.post("/version_change/:newVersion",(async(e,t,o)=>{try{log(4,"[version] Changing Highcharts version.");const o=envs.HIGHCHARTS_ADMIN_TOKEN;if(!o||!o.length)throw new ExportError("[version] The server is not configured to perform run-time version changes: HIGHCHARTS_ADMIN_TOKEN is not set.",401);const r=e.get("hc-auth");if(!r||r!==o)throw new ExportError("[version] Invalid or missing token: Set the token in the hc-auth header.",401);let i=e.params.newVersion;try{i=validateOption("version",e.params.newVersion)}catch(e){throw new ExportError(`[version] Version is incorrect: ${e.message}`,400).setError(e)}if(!i)throw new ExportError("[version] No new version supplied.",400);try{await updateHighchartsVersion(i)}catch(e){throw new ExportError(`[version] Version change: ${e.message}`,400).setError(e)}t.status(200).send({statusCode:200,highchartsVersion:getHighchartsVersion(),message:`Successfully updated Highcharts to version: ${i}.`})}catch(e){return o(e)}}))}const activeServers=new Map,app=express();async function startServer(e){try{const t=updateOptions(validateOptions({server:e}));if(!(e=t.server).enable||!app)throw new ExportError("[server] Server cannot be started (not enabled or no correct Express app found).",500);const o=1024*e.uploadLimit*1024,r=multer.memoryStorage(),i=multer({storage:r,limits:{fieldSize:o}});if(app.disable("x-powered-by"),app.use(cors({methods:["POST","GET","OPTIONS"]})),app.use(((e,t,o)=>{t.set("Accept-Ranges","none"),o()})),app.use(express.json({limit:o})),app.use(express.urlencoded({extended:!0,limit:o})),app.use(i.none()),app.use(express.static(path.join(__dirname$1,"public"))),!e.ssl.force){const t=http.createServer(app);_attachServerErrorHandlers(t),t.listen(e.port,e.host,(()=>{activeServers.set(e.port,t),log(3,`[server] Started HTTP server on ${e.host}:${e.port}.`)}))}if(e.ssl.enable){let t,o;try{t=await promises.readFile(path.join(getAbsolutePath(e.ssl.certPath),"server.key"),"utf8"),o=await promises.readFile(path.join(getAbsolutePath(e.ssl.certPath),"server.crt"),"utf8")}catch(t){log(2,`[server] Unable to load key/certificate from the '${e.ssl.certPath}' path. Could not run secured layer server.`)}if(t&&o){const r=https.createServer({key:t,cert:o},app);_attachServerErrorHandlers(r),r.listen(e.ssl.port,e.host,(()=>{activeServers.set(e.ssl.port,r),log(3,`[server] Started HTTPS server on ${e.host}:${e.ssl.port}.`)}))}}rateLimitingMiddleware(app,e.rateLimiting),validationMiddleware(app),exportRoutes(app),healthRoutes(app),uiRoutes(app),versionChangeRoutes(app),errorMiddleware(app)}catch(e){throw new ExportError("[server] Could not configure and start the server.",500).setError(e)}}function closeServers(){if(activeServers.size>0){log(4,"[server] Closing all servers.");for(const[e,t]of activeServers)t.close((()=>{activeServers.delete(e),log(4,`[server] Closed server on port: ${e}.`)}))}}function getServers(){return activeServers}function getExpress(){return express}function getApp(){return app}function enableRateLimiting(e){const t=updateOptions(validateOptions({server:{rateLimiting:e}}));rateLimitingMiddleware(app,t.server.rateLimitingOptions)}function use(e,...t){app.use(e,...t)}function get(e,...t){app.get(e,...t)}function post(e,...t){app.post(e,...t)}function _attachServerErrorHandlers(e){e.on("clientError",((e,t)=>{logWithStack(1,e,`[server] Client error: ${e.message}, destroying socket.`),t.destroy()})),e.on("error",(e=>{logWithStack(1,e,`[server] Server error: ${e.message}`)})),e.on("connection",(e=>{e.on("error",(e=>{logWithStack(1,e,`[server] Socket error: ${e.message}`)}))}))}var server={startServer:startServer,closeServers:closeServers,getServers:getServers,getExpress:getExpress,getApp:getApp,enableRateLimiting:enableRateLimiting,use:use,get:get,post:post};async function shutdownCleanUp(e=0){await Promise.allSettled([clearAllTimers(),closeServers(),killPool()]),process.exit(e)}async function initExport(e={}){const t=updateOptions(validateOptions(e),!0);setAllowCodeExecution(t.customLogic.allowCodeExecution),initLogging(t.logging),t.other.listenToProcessExits&&_attachProcessExitListeners(),await checkAndUpdateCache(t.highcharts,t.server.proxy),await initPool(t.pool,t.puppeteer.args)}function _attachProcessExitListeners(){log(3,"[process] Attaching exit listeners to the process."),process.on("exit",(e=>{log(4,`[process] Process exited with code ${e}.`)})),process.on("SIGINT",(async(e,t)=>{log(4,`[process] The ${e} event with code: ${t}.`),await shutdownCleanUp()})),process.on("SIGTERM",(async(e,t)=>{log(4,`[process] The ${e} event with code: ${t}.`),await shutdownCleanUp()})),process.on("SIGHUP",(async(e,t)=>{log(4,`[process] The ${e} event with code: ${t}.`),await shutdownCleanUp()})),process.on("uncaughtException",(async(e,t)=>{logWithStack(1,e,`[process] The ${t} error.`),await shutdownCleanUp(1)}))}var index={...server,getOptions:getOptions,setGlobalOptions:setGlobalOptions,mapToNewOptions:mapToNewOptions,validateOption:validateOption,validateOptions:validateOptions,initExport:initExport,singleExport:singleExport,batchExport:batchExport,startExport:startExport,killPool:killPool,shutdownCleanUp:shutdownCleanUp,log:log,logWithStack:logWithStack,logZodIssues:logZodIssues,setLogLevel:function(e){setLogLevel(updateOptions(validateOptions({logging:{level:e}})).logging.level)},enableConsoleLogging:function(e){enableConsoleLogging(updateOptions(validateOptions({logging:{toConsole:e}})).logging.toConsole)},enableFileLogging:function(e,t,o){const r=updateOptions(validateOptions({logging:{dest:e,file:t,toFile:o}}));enableFileLogging(r.logging.dest,r.logging.file,r.logging.toFile)}};exports.default=index,exports.initExport=initExport; +//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguY2pzIiwic291cmNlcyI6WyIuLi9saWIvdXRpbHMuanMiLCIuLi9saWIvbG9nZ2VyLmpzIiwiLi4vbGliL3NjaGVtYXMvY29uZmlnLmpzIiwiLi4vbGliL3ZhbGlkYXRpb24uanMiLCIuLi9saWIvZXJyb3JzL0V4cG9ydEVycm9yLmpzIiwiLi4vbGliL2NvbmZpZy5qcyIsIi4uL2xpYi9mZXRjaC5qcyIsIi4uL2xpYi9jYWNoZS5qcyIsIi4uL2xpYi9oaWdoY2hhcnRzLmpzIiwiLi4vbGliL2Jyb3dzZXIuanMiLCIuLi90ZW1wbGF0ZXMvc3ZnRXhwb3J0L2Nzcy5qcyIsIi4uL3RlbXBsYXRlcy9zdmdFeHBvcnQvc3ZnRXhwb3J0LmpzIiwiLi4vbGliL2V4cG9ydC5qcyIsIi4uL2xpYi9wb29sLmpzIiwiLi4vbGliL3Nhbml0aXplLmpzIiwiLi4vbGliL2NoYXJ0LmpzIiwiLi4vbGliL3RpbWVyLmpzIiwiLi4vbGliL3NlcnZlci9taWRkbGV3YXJlcy9lcnJvci5qcyIsIi4uL2xpYi9zZXJ2ZXIvbWlkZGxld2FyZXMvcmF0ZUxpbWl0aW5nLmpzIiwiLi4vbGliL3NlcnZlci9taWRkbGV3YXJlcy92YWxpZGF0aW9uLmpzIiwiLi4vbGliL3NlcnZlci9yb3V0ZXMvZXhwb3J0LmpzIiwiLi4vbGliL3NlcnZlci9yb3V0ZXMvaGVhbHRoLmpzIiwiLi4vbGliL3NlcnZlci9yb3V0ZXMvdWkuanMiLCIuLi9saWIvc2VydmVyL3JvdXRlcy92ZXJzaW9uQ2hhbmdlLmpzIiwiLi4vbGliL3NlcnZlci9zZXJ2ZXIuanMiLCIuLi9saWIvcmVzb3VyY2VSZWxlYXNlLmpzIiwiLi4vbGliL2luZGV4LmpzIl0sInNvdXJjZXNDb250ZW50IjpbIi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXHJcblxyXG5IaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXJcclxuXHJcbkNvcHlyaWdodCAoYykgMjAxNi0yMDI1LCBIaWdoc29mdFxyXG5cclxuTGljZW5jZWQgdW5kZXIgdGhlIE1JVCBsaWNlbmNlLlxyXG5cclxuQWRkaXRpb25hbGx5IGEgdmFsaWQgSGlnaGNoYXJ0cyBsaWNlbnNlIGlzIHJlcXVpcmVkIGZvciB1c2UuXHJcblxyXG5TZWUgTElDRU5TRSBmaWxlIGluIHJvb3QgZm9yIGRldGFpbHMuXHJcblxyXG4qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xyXG5cclxuLyoqXHJcbiAqIEBvdmVydmlldyBUaGUgSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyIHV0aWxpdHkgbW9kdWxlIHByb3ZpZGVzXHJcbiAqIGEgY29tcHJlaGVuc2l2ZSBzZXQgb2YgaGVscGVyIGZ1bmN0aW9ucyBhbmQgY29uc3RhbnRzIGRlc2lnbmVkIHRvIHN0cmVhbWxpbmVcclxuICogYW5kIGVuaGFuY2UgdmFyaW91cyBvcGVyYXRpb25zIHJlcXVpcmVkIGZvciBIaWdoY2hhcnRzIGV4cG9ydCB0YXNrcy5cclxuICovXHJcblxyXG5pbXBvcnQgeyByZWFkRmlsZVN5bmMgfSBmcm9tICdmcyc7XHJcbmltcG9ydCB7IGlzQWJzb2x1dGUsIGpvaW4gfSBmcm9tICdwYXRoJztcclxuaW1wb3J0IHsgZmlsZVVSTFRvUGF0aCB9IGZyb20gJ3VybCc7XHJcblxyXG5jb25zdCBNQVhfQkFDS09GRl9BVFRFTVBUUyA9IDY7XHJcblxyXG4vLyBUaGUgZGlyZWN0b3J5IHBhdGhcclxuZXhwb3J0IGNvbnN0IF9fZGlybmFtZSA9IGZpbGVVUkxUb1BhdGgobmV3IFVSTCgnLi4vLicsIGltcG9ydC5tZXRhLnVybCkpO1xyXG5cclxuLyoqXHJcbiAqIENsZWFycyBhbmQgc3RhbmRhcmRpemVzIHRleHQgYnkgcmVwbGFjaW5nIG11bHRpcGxlIGNvbnNlY3V0aXZlIHdoaXRlc3BhY2VcclxuICogY2hhcmFjdGVycyB3aXRoIGEgc2luZ2xlIHNwYWNlIGFuZCB0cmltbWluZyBhbnkgbGVhZGluZyBvciB0cmFpbGluZ1xyXG4gKiB3aGl0ZXNwYWNlLlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gY2xlYXJUZXh0XHJcbiAqXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSB0ZXh0IC0gVGhlIGlucHV0IHRleHQgdG8gYmUgY2xlYXJlZC5cclxuICogQHBhcmFtIHtSZWdFeHB9IFtydWxlPS9cXHNcXHMrL2ddIC0gVGhlIHJlZ3VsYXIgZXhwcmVzc2lvbiBydWxlIHRvIG1hdGNoXHJcbiAqIG11bHRpcGxlIGNvbnNlY3V0aXZlIHdoaXRlc3BhY2UgY2hhcmFjdGVycy4gVGhlIGRlZmF1bHQgdmFsdWVcclxuICogaXMgdGhlICcvXFxzXFxzKy9nJyBSZWdFeHAuXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSBbcmVwbGFjZXI9JyAnXSAtIFRoZSBzdHJpbmcgdXNlZCB0byByZXBsYWNlIG11bHRpcGxlXHJcbiAqIGNvbnNlY3V0aXZlIHdoaXRlc3BhY2UgY2hhcmFjdGVycy4gVGhlIGRlZmF1bHQgdmFsdWUgaXMgdGhlICcgJyBzdHJpbmcuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtzdHJpbmd9IFRoZSBjbGVhcmVkIGFuZCBzdGFuZGFyZGl6ZWQgdGV4dC5cclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiBjbGVhclRleHQodGV4dCwgcnVsZSA9IC9cXHNcXHMrL2csIHJlcGxhY2VyID0gJyAnKSB7XHJcbiAgcmV0dXJuIHRleHQucmVwbGFjZUFsbChydWxlLCByZXBsYWNlcikudHJpbSgpO1xyXG59XHJcblxyXG4vKipcclxuICogQ3JlYXRlcyBhIGRlZXAgY29weSBvZiB0aGUgZ2l2ZW4gb2JqZWN0IG9yIGFycmF5LlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gZGVlcENvcHlcclxuICpcclxuICogQHBhcmFtIHsoT2JqZWN0fEFycmF5KX0gb2JqQXJyIC0gVGhlIG9iamVjdCBvciBhcnJheSB0byBiZSBkZWVwbHkgY29waWVkLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7KE9iamVjdHxBcnJheSl9IFRoZSBkZWVwIGNvcHkgb2YgdGhlIHByb3ZpZGVkIG9iamVjdCBvciBhcnJheS5cclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiBkZWVwQ29weShvYmpBcnIpIHtcclxuICAvLyBJZiB0aGUgYG9iakFycmAgaXMgbnVsbCBvciBub3Qgb2YgdGhlIGBvYmplY3RgIHR5cGUsIHJldHVybiBpdFxyXG4gIGlmIChvYmpBcnIgPT09IG51bGwgfHwgdHlwZW9mIG9iakFyciAhPT0gJ29iamVjdCcpIHtcclxuICAgIHJldHVybiBvYmpBcnI7XHJcbiAgfVxyXG5cclxuICAvLyBQcmVwYXJlIGVpdGhlciBhIG5ldyBhcnJheSBvciBhIG5ldyBvYmplY3RcclxuICBjb25zdCBvYmpBcnJDb3B5ID0gQXJyYXkuaXNBcnJheShvYmpBcnIpID8gW10gOiB7fTtcclxuXHJcbiAgLy8gUmVjdXJzaXZlbHkgY29weSBlYWNoIHByb3BlcnR5XHJcbiAgZm9yIChjb25zdCBrZXkgaW4gb2JqQXJyKSB7XHJcbiAgICBpZiAoT2JqZWN0LnByb3RvdHlwZS5oYXNPd25Qcm9wZXJ0eS5jYWxsKG9iakFyciwga2V5KSkge1xyXG4gICAgICBvYmpBcnJDb3B5W2tleV0gPSBkZWVwQ29weShvYmpBcnJba2V5XSk7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICAvLyBSZXR1cm4gdGhlIGNvcGllZCBvYmplY3RcclxuICByZXR1cm4gb2JqQXJyQ29weTtcclxufVxyXG5cclxuLyoqXHJcbiAqIEltcGxlbWVudHMgYW4gZXhwb25lbnRpYWwgYmFja29mZiBzdHJhdGVneSBmb3IgcmV0cnlpbmcgYSBmdW5jdGlvbiB1bnRpbFxyXG4gKiBhIGNlcnRhaW4gbnVtYmVyIG9mIGF0dGVtcHRzIGFyZSByZWFjaGVkLlxyXG4gKlxyXG4gKiBAYXN5bmNcclxuICogQGZ1bmN0aW9uIGV4cEJhY2tvZmZcclxuICpcclxuICogQHBhcmFtIHtGdW5jdGlvbn0gZm4gLSBUaGUgZnVuY3Rpb24gdG8gYmUgcmV0cmllZC5cclxuICogQHBhcmFtIHtudW1iZXJ9IFthdHRlbXB0PTBdIC0gVGhlIGN1cnJlbnQgYXR0ZW1wdCBudW1iZXIuIFRoZSBkZWZhdWx0IHZhbHVlXHJcbiAqIGlzIGAwYC5cclxuICogQHBhcmFtIHsuLi51bmtub3dufSBhcmdzIC0gQXJndW1lbnRzIHRvIGJlIHBhc3NlZCB0byB0aGUgZnVuY3Rpb24uXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtQcm9taXNlPHVua25vd24+fSBBIFByb21pc2UgdGhhdCByZXNvbHZlcyB0byB0aGUgcmVzdWx0XHJcbiAqIG9mIHRoZSBmdW5jdGlvbiBpZiBzdWNjZXNzZnVsLlxyXG4gKlxyXG4gKiBAdGhyb3dzIHtFcnJvcn0gVGhyb3dzIGFuIGBFcnJvcmAgaWYgdGhlIG1heGltdW0gbnVtYmVyIG9mIGF0dGVtcHRzXHJcbiAqIGlzIHJlYWNoZWQuXHJcbiAqL1xyXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gZXhwQmFja29mZihmbiwgYXR0ZW1wdCA9IDAsIC4uLmFyZ3MpIHtcclxuICB0cnkge1xyXG4gICAgLy8gVHJ5IHRvIGNhbGwgdGhlIGZ1bmN0aW9uXHJcbiAgICByZXR1cm4gYXdhaXQgZm4oLi4uYXJncyk7XHJcbiAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgIC8vIENhbGN1bGF0ZSBkZWxheSBpbiBtc1xyXG4gICAgY29uc3QgZGVsYXlJbk1zID0gMiAqKiBhdHRlbXB0ICogMTAwMDtcclxuXHJcbiAgICAvLyBJZiB0aGUgYXR0ZW1wdCBleGNlZWRzIHRoZSBtYXhpbXVtIGF0dGVtcHRzIG9mIHJlcGVhdCwgdGhyb3cgYW4gZXJyb3JcclxuICAgIGlmICgrK2F0dGVtcHQgPj0gTUFYX0JBQ0tPRkZfQVRURU1QVFMpIHtcclxuICAgICAgdGhyb3cgZXJyb3I7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gV2FpdCBnaXZlbiBhbW91bnQgb2YgdGltZVxyXG4gICAgYXdhaXQgbmV3IFByb21pc2UoKHJlc3BvbnNlKSA9PiBzZXRUaW1lb3V0KHJlc3BvbnNlLCBkZWxheUluTXMpKTtcclxuXHJcbiAgICAvLy8gVE8gRE86IENvcnJlY3RcclxuICAgIC8vIC8vIEluZm9ybWF0aW9uIGFib3V0IHRoZSByZXNvdXJjZSB0aW1lb3V0XHJcbiAgICAvLyBsb2coXHJcbiAgICAvLyAgIDMsXHJcbiAgICAvLyAgIGBbdXRpbHNdIFdhaXRlZCAke2RlbGF5SW5Nc31tcyB1bnRpbCBuZXh0IGNhbGwgZm9yIHRoZSByZXNvdXJjZSBvZiBJRDogJHthcmdzWzBdfS5gXHJcbiAgICAvLyApO1xyXG5cclxuICAgIC8vIFRyeSBhZ2FpblxyXG4gICAgcmV0dXJuIGV4cEJhY2tvZmYoZm4sIGF0dGVtcHQsIC4uLmFyZ3MpO1xyXG4gIH1cclxufVxyXG5cclxuLyoqXHJcbiAqIEFkanVzdHMgdGhlIGNvbnN0cnVjdG9yIG5hbWUgYnkgdHJhbnNmb3JtaW5nIGFuZCBub3JtYWxpemluZyBpdCBiYXNlZFxyXG4gKiBvbiBjb21tb24gY2hhcnQgdHlwZXMuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBmaXhDb25zdHJcclxuICpcclxuICogQHBhcmFtIHtzdHJpbmd9IGNvbnN0ciAtIFRoZSBvcmlnaW5hbCBjb25zdHJ1Y3RvciBuYW1lIHRvIGJlIGZpeGVkLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7c3RyaW5nfSBUaGUgY29ycmVjdGVkIGNvbnN0cnVjdG9yIG5hbWUsIG9yICdjaGFydCcgaWYgdGhlIGlucHV0XHJcbiAqIGlzIG5vdCByZWNvZ25pemVkLlxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIGZpeENvbnN0cihjb25zdHIpIHtcclxuICB0cnkge1xyXG4gICAgLy8gRml4IHRoZSBjb25zdHJ1Y3RvciBieSBsb3dlcmluZyBjYXNpbmdcclxuICAgIGNvbnN0IGZpeGVkQ29uc3RyID0gYCR7Y29uc3RyLnRvTG93ZXJDYXNlKCkucmVwbGFjZSgnY2hhcnQnLCAnJyl9Q2hhcnRgO1xyXG5cclxuICAgIC8vIEhhbmRsZSB0aGUgY2FzZSB3aGVyZSB0aGUgcmVzdWx0IGlzIGp1c3QgJ0NoYXJ0J1xyXG4gICAgaWYgKGZpeGVkQ29uc3RyID09PSAnQ2hhcnQnKSB7XHJcbiAgICAgIGZpeGVkQ29uc3RyLnRvTG93ZXJDYXNlKCk7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gUmV0dXJuIHRoZSBjb3JyZWN0ZWQgY29uc3RydWN0b3IsIG90aGVyd2lzZSBkZWZhdWx0IHRvICdjaGFydCdcclxuICAgIHJldHVybiBbJ2NoYXJ0JywgJ3N0b2NrQ2hhcnQnLCAnbWFwQ2hhcnQnLCAnZ2FudHRDaGFydCddLmluY2x1ZGVzKFxyXG4gICAgICBmaXhlZENvbnN0clxyXG4gICAgKVxyXG4gICAgICA/IGZpeGVkQ29uc3RyXHJcbiAgICAgIDogJ2NoYXJ0JztcclxuICB9IGNhdGNoIHtcclxuICAgIC8vIERlZmF1bHQgdG8gJ2NoYXJ0JyBpbiBjYXNlIG9mIGFueSBlcnJvclxyXG4gICAgcmV0dXJuICdjaGFydCc7XHJcbiAgfVxyXG59XHJcblxyXG4vKipcclxuICogRml4ZXMgdGhlIG91dGZpbGUgYmFzZWQgb24gcHJvdmlkZWQgdHlwZS5cclxuICpcclxuICogQGZ1bmN0aW9uIGZpeE91dGZpbGVcclxuICpcclxuICogQHBhcmFtIHtzdHJpbmd9IHR5cGUgLSBUaGUgb3JpZ2luYWwgZXhwb3J0IHR5cGUuXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSBvdXRmaWxlIC0gVGhlIGZpbGUgcGF0aCBvciBuYW1lLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7c3RyaW5nfSBUaGUgY29ycmVjdGVkIG91dGZpbGUuXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gZml4T3V0ZmlsZSh0eXBlLCBvdXRmaWxlKSB7XHJcbiAgLy8gR2V0IHRoZSBmaWxlIG5hbWUgZnJvbSB0aGUgYG91dGZpbGVgIG9wdGlvblxyXG4gIGNvbnN0IGZpbGVOYW1lID0gZ2V0QWJzb2x1dGVQYXRoKG91dGZpbGUgfHwgJ2NoYXJ0JylcclxuICAgIC5zcGxpdCgnLicpXHJcbiAgICAuc2hpZnQoKTtcclxuXHJcbiAgLy8gUmV0dXJuIGEgY29ycmVjdCBvdXRmaWxlXHJcbiAgcmV0dXJuIGAke2ZpbGVOYW1lfS4ke3R5cGV9YDtcclxufVxyXG5cclxuLyoqXHJcbiAqIEZpeGVzIHRoZSBleHBvcnQgdHlwZSBiYXNlZCBvbiBNSU1FIHR5cGVzIGFuZCBmaWxlIGV4dGVuc2lvbnMuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBmaXhUeXBlXHJcbiAqXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSB0eXBlIC0gVGhlIG9yaWdpbmFsIGV4cG9ydCB0eXBlLlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gW291dGZpbGU9bnVsbF0gLSBUaGUgZmlsZSBwYXRoIG9yIG5hbWUuIFRoZSBkZWZhdWx0IHZhbHVlXHJcbiAqIGlzIGBudWxsYC5cclxuICpcclxuICogQHJldHVybnMge3N0cmluZ30gVGhlIGNvcnJlY3RlZCBleHBvcnQgdHlwZS5cclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiBmaXhUeXBlKHR5cGUsIG91dGZpbGUgPSBudWxsKSB7XHJcbiAgLy8gTUlNRSB0eXBlc1xyXG4gIGNvbnN0IG1pbWVUeXBlcyA9IHtcclxuICAgICdpbWFnZS9wbmcnOiAncG5nJyxcclxuICAgICdpbWFnZS9qcGVnJzogJ2pwZWcnLFxyXG4gICAgJ2FwcGxpY2F0aW9uL3BkZic6ICdwZGYnLFxyXG4gICAgJ2ltYWdlL3N2Zyt4bWwnOiAnc3ZnJ1xyXG4gIH07XHJcblxyXG4gIC8vIEdldCBmb3JtYXRzXHJcbiAgY29uc3QgZm9ybWF0cyA9IE9iamVjdC52YWx1ZXMobWltZVR5cGVzKTtcclxuXHJcbiAgLy8gQ2hlY2sgaWYgdHlwZSBhbmQgb3V0ZmlsZSdzIGV4dGVuc2lvbnMgYXJlIHRoZSBzYW1lXHJcbiAgaWYgKG91dGZpbGUpIHtcclxuICAgIGNvbnN0IG91dFR5cGUgPSBvdXRmaWxlLnNwbGl0KCcuJykucG9wKCk7XHJcblxyXG4gICAgLy8gU3VwcG9ydCB0aGUgSlBHIHR5cGVcclxuICAgIGlmIChvdXRUeXBlID09PSAnanBnJykge1xyXG4gICAgICB0eXBlID0gJ2pwZWcnO1xyXG4gICAgfSBlbHNlIGlmIChmb3JtYXRzLmluY2x1ZGVzKG91dFR5cGUpICYmIHR5cGUgIT09IG91dFR5cGUpIHtcclxuICAgICAgdHlwZSA9IG91dFR5cGU7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICAvLyBSZXR1cm4gYSBjb3JyZWN0IHR5cGVcclxuICByZXR1cm4gbWltZVR5cGVzW3R5cGVdIHx8IGZvcm1hdHMuZmluZCgodCkgPT4gdCA9PT0gdHlwZSkgfHwgJ3BuZyc7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBDaGVja3MgaWYgdGhlIGdpdmVuIHBhdGggaXMgcmVsYXRpdmUgb3IgYWJzb2x1dGUgYW5kIHJldHVybnMgdGhlIGNvcnJlY3RlZCxcclxuICogYWJzb2x1dGUgcGF0aC5cclxuICpcclxuICogQGZ1bmN0aW9uIGlzQWJzb2x1dGVQYXRoXHJcbiAqXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSBwYXRoIC0gVGhlIHBhdGggdG8gYmUgY2hlY2tlZCBvbi5cclxuICpcclxuICogQHJldHVybnMge3N0cmluZ30gVGhlIGFic29sdXRlIHBhdGguXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gZ2V0QWJzb2x1dGVQYXRoKHBhdGgpIHtcclxuICByZXR1cm4gaXNBYnNvbHV0ZShwYXRoKSA/IHBhdGggOiBqb2luKF9fZGlybmFtZSwgcGF0aCk7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBDb252ZXJ0cyBpbnB1dCBkYXRhIHRvIGEgQmFzZTY0IHN0cmluZyBiYXNlZCBvbiB0aGUgZXhwb3J0IHR5cGUuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBnZXRCYXNlNjRcclxuICpcclxuICogQHBhcmFtIHtzdHJpbmd9IGlucHV0IC0gVGhlIGlucHV0IHRvIGJlIHRyYW5zZm9ybWVkIHRvIEJhc2U2NCBmb3JtYXQuXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSB0eXBlIC0gVGhlIG9yaWdpbmFsIGV4cG9ydCB0eXBlLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7c3RyaW5nfSBUaGUgQmFzZTY0IHN0cmluZyByZXByZXNlbnRhdGlvbiBvZiB0aGUgaW5wdXQuXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gZ2V0QmFzZTY0KGlucHV0LCB0eXBlKSB7XHJcbiAgLy8gRm9yIHBkZiBhbmQgc3ZnIHR5cGVzIHRoZSBpbnB1dCBtdXN0IGJlIHRyYW5zZm9ybWVkIHRvIEJhc2U2NCBmcm9tIGEgYnVmZmVyXHJcbiAgaWYgKHR5cGUgPT09ICdwZGYnIHx8IHR5cGUgPT0gJ3N2ZycpIHtcclxuICAgIHJldHVybiBCdWZmZXIuZnJvbShpbnB1dCwgJ3V0ZjgnKS50b1N0cmluZygnYmFzZTY0Jyk7XHJcbiAgfVxyXG5cclxuICAvLyBGb3IgcG5nIGFuZCBqcGVnIGlucHV0IGlzIGFscmVhZHkgYSBCYXNlNjQgc3RyaW5nXHJcbiAgcmV0dXJuIGlucHV0O1xyXG59XHJcblxyXG4vKipcclxuICogUmV0dXJucyBzdHJpbmdpZmllZCBkYXRlIHdpdGhvdXQgdGhlIEdNVCB0ZXh0IGluZm9ybWF0aW9uLlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gZ2V0TmV3RGF0ZVxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIGdldE5ld0RhdGUoKSB7XHJcbiAgLy8gR2V0IHJpZCBvZiB0aGUgR01UIHRleHQgaW5mb3JtYXRpb25cclxuICByZXR1cm4gbmV3IERhdGUoKS50b1N0cmluZygpLnNwbGl0KCcoJylbMF0udHJpbSgpO1xyXG59XHJcblxyXG4vKipcclxuICogUmV0dXJucyB0aGUgc3RvcmVkIHRpbWUgdmFsdWUgaW4gbWlsbGlzZWNvbmRzLlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gZ2V0TmV3RGF0ZVRpbWVcclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiBnZXROZXdEYXRlVGltZSgpIHtcclxuICByZXR1cm4gbmV3IERhdGUoKS5nZXRUaW1lKCk7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBDaGVja3MgaWYgdGhlIGdpdmVuIGl0ZW0gaXMgYW4gb2JqZWN0LlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gaXNPYmplY3RcclxuICpcclxuICogQHBhcmFtIHt1bmtub3dufSBpdGVtIC0gVGhlIGl0ZW0gdG8gYmUgY2hlY2tlZC5cclxuICpcclxuICogQHJldHVybnMge2Jvb2xlYW59IFRydWUgaWYgdGhlIGl0ZW0gaXMgYW4gb2JqZWN0LCBmYWxzZSBvdGhlcndpc2UuXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gaXNPYmplY3QoaXRlbSkge1xyXG4gIHJldHVybiBPYmplY3QucHJvdG90eXBlLnRvU3RyaW5nLmNhbGwoaXRlbSkgPT09ICdbb2JqZWN0IE9iamVjdF0nO1xyXG59XHJcblxyXG4vKipcclxuICogQ2hlY2tzIGlmIHRoZSBnaXZlbiBvYmplY3QgaXMgZW1wdHkuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBpc09iamVjdEVtcHR5XHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBpdGVtIC0gVGhlIG9iamVjdCB0byBiZSBjaGVja2VkLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7Ym9vbGVhbn0gVHJ1ZSBpZiB0aGUgb2JqZWN0IGlzIGVtcHR5LCBmYWxzZSBvdGhlcndpc2UuXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gaXNPYmplY3RFbXB0eShpdGVtKSB7XHJcbiAgcmV0dXJuIChcclxuICAgIHR5cGVvZiBpdGVtID09PSAnb2JqZWN0JyAmJlxyXG4gICAgIUFycmF5LmlzQXJyYXkoaXRlbSkgJiZcclxuICAgIGl0ZW0gIT09IG51bGwgJiZcclxuICAgIE9iamVjdC5rZXlzKGl0ZW0pLmxlbmd0aCA9PT0gMFxyXG4gICk7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBDaGVja3MgaWYgYSBwcml2YXRlIElQIHJhbmdlIFVSTCBpcyBmb3VuZCBpbiB0aGUgZ2l2ZW4gc3RyaW5nLlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gaXNQcml2YXRlUmFuZ2VVcmxGb3VuZFxyXG4gKlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gaXRlbSAtIFRoZSBzdHJpbmcgdG8gYmUgY2hlY2tlZCBmb3IgYSBwcml2YXRlIElQIHJhbmdlIFVSTC5cclxuICpcclxuICogQHJldHVybnMge2Jvb2xlYW59IFRydWUgaWYgYSBwcml2YXRlIElQIHJhbmdlIFVSTCBpcyBmb3VuZCwgZmFsc2Ugb3RoZXJ3aXNlLlxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIGlzUHJpdmF0ZVJhbmdlVXJsRm91bmQoaXRlbSkge1xyXG4gIGNvbnN0IHJlZ2V4UGF0dGVybnMgPSBbXHJcbiAgICAveGxpbms6aHJlZj1cIig/Omh0dHA6XFwvXFwvfGh0dHBzOlxcL1xcLyk/bG9jYWxob3N0XFxiLyxcclxuICAgIC94bGluazpocmVmPVwiKD86aHR0cDpcXC9cXC98aHR0cHM6XFwvXFwvKT8xMFxcLlxcZHsxLDN9XFwuXFxkezEsM31cXC5cXGR7MSwzfVxcYi8sXHJcbiAgICAveGxpbms6aHJlZj1cIig/Omh0dHA6XFwvXFwvfGh0dHBzOlxcL1xcLyk/MTI3XFwuXFxkezEsM31cXC5cXGR7MSwzfVxcLlxcZHsxLDN9XFxiLyxcclxuICAgIC94bGluazpocmVmPVwiKD86aHR0cDpcXC9cXC98aHR0cHM6XFwvXFwvKT8xNzJcXC4oMVs2LTldfDJbMC05XXwzWzAtMV0pXFwuXFxkezEsM31cXC5cXGR7MSwzfVxcYi8sXHJcbiAgICAveGxpbms6aHJlZj1cIig/Omh0dHA6XFwvXFwvfGh0dHBzOlxcL1xcLyk/MTkyXFwuMTY4XFwuXFxkezEsM31cXC5cXGR7MSwzfVxcYi9cclxuICBdO1xyXG5cclxuICByZXR1cm4gcmVnZXhQYXR0ZXJucy5zb21lKChwYXR0ZXJuKSA9PiBwYXR0ZXJuLnRlc3QoaXRlbSkpO1xyXG59XHJcblxyXG4vKipcclxuICogVXRpbGl0eSB0byBtZWFzdXJlIGVsYXBzZWQgdGltZSB1c2luZyB0aGUgTm9kZS5qcyBgcHJvY2Vzcy5ocnRpbWUoKWAgbWV0aG9kLlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gbWVhc3VyZVRpbWVcclxuICpcclxuICogQHJldHVybnMge0Z1bmN0aW9ufSBBIGZ1bmN0aW9uIHRvIGNhbGN1bGF0ZSB0aGUgZWxhcHNlZCB0aW1lIGluIG1pbGxpc2Vjb25kcy5cclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiBtZWFzdXJlVGltZSgpIHtcclxuICBjb25zdCBzdGFydCA9IHByb2Nlc3MuaHJ0aW1lLmJpZ2ludCgpO1xyXG4gIHJldHVybiAoKSA9PiBOdW1iZXIocHJvY2Vzcy5ocnRpbWUuYmlnaW50KCkgLSBzdGFydCkgLyAxMDAwMDAwO1xyXG59XHJcblxyXG4vKipcclxuICogUm91bmRzIGEgbnVtYmVyIHRvIHRoZSBzcGVjaWZpZWQgcHJlY2lzaW9uLlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gcm91bmROdW1iZXJcclxuICpcclxuICogQHBhcmFtIHtudW1iZXJ9IHZhbHVlIC0gVGhlIG51bWJlciB0byBiZSByb3VuZGVkLlxyXG4gKiBAcGFyYW0ge251bWJlcn0gcHJlY2lzaW9uIC0gVGhlIG51bWJlciBvZiBkZWNpbWFsIHBsYWNlcyB0byByb3VuZCB0by5cclxuICpcclxuICogQHJldHVybnMge251bWJlcn0gVGhlIHJvdW5kZWQgbnVtYmVyLlxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIHJvdW5kTnVtYmVyKHZhbHVlLCBwcmVjaXNpb24gPSAxKSB7XHJcbiAgY29uc3QgbXVsdGlwbGllciA9IE1hdGgucG93KDEwLCBwcmVjaXNpb24gfHwgMCk7XHJcbiAgcmV0dXJuIE1hdGgucm91bmQoK3ZhbHVlICogbXVsdGlwbGllcikgLyBtdWx0aXBsaWVyO1xyXG59XHJcblxyXG4vKipcclxuICogQ29udmVydHMgYSB2YWx1ZSB0byBhIGJvb2xlYW4uXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiB0b0Jvb2xlYW5cclxuICpcclxuICogQHBhcmFtIHt1bmtub3dufSBpdGVtIC0gVGhlIHZhbHVlIHRvIGJlIGNvbnZlcnRlZCB0byBhIGJvb2xlYW4uXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtib29sZWFufSBUaGUgYm9vbGVhbiByZXByZXNlbnRhdGlvbiBvZiB0aGUgaW5wdXQgdmFsdWUuXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gdG9Cb29sZWFuKGl0ZW0pIHtcclxuICByZXR1cm4gWydmYWxzZScsICd1bmRlZmluZWQnLCAnbnVsbCcsICdOYU4nLCAnMCcsICcnXS5pbmNsdWRlcyhpdGVtKVxyXG4gICAgPyBmYWxzZVxyXG4gICAgOiAhIWl0ZW07XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBXcmFwcyBjdXN0b20gY29kZSB0byBleGVjdXRlIGl0IHNhZmVseS5cclxuICpcclxuICogQGZ1bmN0aW9uIHdyYXBBcm91bmRcclxuICpcclxuICogQHBhcmFtIHtzdHJpbmd9IGN1c3RvbUNvZGUgLSBUaGUgY3VzdG9tIGNvZGUgdG8gYmUgd3JhcHBlZC5cclxuICogQHBhcmFtIHtib29sZWFufSBhbGxvd0ZpbGVSZXNvdXJjZXMgLSBGbGFnIHRvIGFsbG93IGxvYWRpbmcgY29kZSBmcm9tIGEgZmlsZS5cclxuICogQHBhcmFtIHtib29sZWFufSBbaXNDYWxsYmFjaz1mYWxzZV0gLSBGbGFnIHRoYXQgaW5kaWNhdGVzIHRoZSByZXR1cm5lZCBjb2RlXHJcbiAqIG11c3QgYmUgaW4gYSBjYWxsYmFjayBmb3JtYXQuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHsoc3RyaW5nfG51bGwpfSBUaGUgd3JhcHBlZCBjdXN0b20gY29kZSBvciBudWxsIGlmIHdyYXBwaW5nIGZhaWxzLlxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIHdyYXBBcm91bmQoY3VzdG9tQ29kZSwgYWxsb3dGaWxlUmVzb3VyY2VzLCBpc0NhbGxiYWNrID0gZmFsc2UpIHtcclxuICBpZiAoY3VzdG9tQ29kZSAmJiB0eXBlb2YgY3VzdG9tQ29kZSA9PT0gJ3N0cmluZycpIHtcclxuICAgIGN1c3RvbUNvZGUgPSBjdXN0b21Db2RlLnRyaW0oKTtcclxuXHJcbiAgICBpZiAoY3VzdG9tQ29kZS5lbmRzV2l0aCgnLmpzJykpIHtcclxuICAgICAgLy8gTG9hZCBhIGZpbGUgaWYgdGhlIGZpbGUgcmVzb3VyY2VzIGFyZSBhbGxvd2VkXHJcbiAgICAgIHJldHVybiBhbGxvd0ZpbGVSZXNvdXJjZXNcclxuICAgICAgICA/IHdyYXBBcm91bmQoXHJcbiAgICAgICAgICAgIHJlYWRGaWxlU3luYyhnZXRBYnNvbHV0ZVBhdGgoY3VzdG9tQ29kZSksICd1dGY4JyksXHJcbiAgICAgICAgICAgIGFsbG93RmlsZVJlc291cmNlcyxcclxuICAgICAgICAgICAgaXNDYWxsYmFja1xyXG4gICAgICAgICAgKVxyXG4gICAgICAgIDogbnVsbDtcclxuICAgIH0gZWxzZSBpZiAoXHJcbiAgICAgICFpc0NhbGxiYWNrICYmXHJcbiAgICAgIChjdXN0b21Db2RlLnN0YXJ0c1dpdGgoJ2Z1bmN0aW9uKCknKSB8fFxyXG4gICAgICAgIGN1c3RvbUNvZGUuc3RhcnRzV2l0aCgnZnVuY3Rpb24gKCknKSB8fFxyXG4gICAgICAgIGN1c3RvbUNvZGUuc3RhcnRzV2l0aCgnKCk9PicpIHx8XHJcbiAgICAgICAgY3VzdG9tQ29kZS5zdGFydHNXaXRoKCcoKSA9PicpKVxyXG4gICAgKSB7XHJcbiAgICAgIC8vIFRyZWF0IGEgZnVuY3Rpb24gYXMgYSBzZWxmLWludm9raW5nIGV4cHJlc3Npb25cclxuICAgICAgcmV0dXJuIGAoJHtjdXN0b21Db2RlfSkoKWA7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gT3IgcmV0dXJuIGFzIGEgc3RyaW5naWZpZWQgY29kZVxyXG4gICAgcmV0dXJuIGN1c3RvbUNvZGUucmVwbGFjZSgvOyQvLCAnJyk7XHJcbiAgfVxyXG59XHJcblxyXG5leHBvcnQgZGVmYXVsdCB7XHJcbiAgX19kaXJuYW1lLFxyXG4gIGNsZWFyVGV4dCxcclxuICBkZWVwQ29weSxcclxuICBleHBCYWNrb2ZmLFxyXG4gIGZpeENvbnN0cixcclxuICBmaXhPdXRmaWxlLFxyXG4gIGZpeFR5cGUsXHJcbiAgZ2V0QWJzb2x1dGVQYXRoLFxyXG4gIGdldEJhc2U2NCxcclxuICBnZXROZXdEYXRlLFxyXG4gIGdldE5ld0RhdGVUaW1lLFxyXG4gIGlzT2JqZWN0LFxyXG4gIGlzT2JqZWN0RW1wdHksXHJcbiAgaXNQcml2YXRlUmFuZ2VVcmxGb3VuZCxcclxuICBtZWFzdXJlVGltZSxcclxuICByb3VuZE51bWJlcixcclxuICB0b0Jvb2xlYW4sXHJcbiAgd3JhcEFyb3VuZFxyXG59O1xyXG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxyXG5cclxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXHJcblxyXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNSwgSGlnaHNvZnRcclxuXHJcbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cclxuXHJcbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxyXG5cclxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxyXG5cclxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cclxuXHJcbi8qKlxyXG4gKiBAb3ZlcnZpZXcgQSBtb2R1bGUgZm9yIG1hbmFnaW5nIGxvZ2dpbmcgZnVuY3Rpb25hbGl0eSB3aXRoIGN1c3RvbWl6YWJsZVxyXG4gKiBsb2cgbGV2ZWxzLCBjb25zb2xlIGFuZCBmaWxlIGxvZ2dpbmcgb3B0aW9ucywgYW5kIGVycm9yIGhhbmRsaW5nIHN1cHBvcnQuXHJcbiAqIFRoZSBtb2R1bGUgYWxzbyBlbnN1cmVzIHRoYXQgZmlsZS1iYXNlZCBsb2dzIGFyZSBzdG9yZWQgaW4gYSBzdHJ1Y3R1cmVkXHJcbiAqIGRpcmVjdG9yeSwgY3JlYXRpbmcgdGhlIG5lY2Vzc2FyeSBwYXRocyBhdXRvbWF0aWNhbGx5IGlmIHRoZXkgZG8gbm90IGV4aXN0LlxyXG4gKi9cclxuXHJcbmltcG9ydCB7IGFwcGVuZEZpbGUsIGV4aXN0c1N5bmMsIG1rZGlyU3luYyB9IGZyb20gJ2ZzJztcclxuaW1wb3J0IHsgam9pbiB9IGZyb20gJ3BhdGgnO1xyXG5cclxuaW1wb3J0IHsgZ2V0QWJzb2x1dGVQYXRoLCBnZXROZXdEYXRlIH0gZnJvbSAnLi91dGlscy5qcyc7XHJcblxyXG4vLyBUaGUgYXZhaWxhYmxlIGNvbG9yc1xyXG5jb25zdCBjb2xvcnMgPSBbJ3JlZCcsICd5ZWxsb3cnLCAnYmx1ZScsICdncmF5JywgJ2dyZWVuJ107XHJcblxyXG4vLyBUaGUgZGVmYXVsdCBsb2dnaW5nIGNvbmZpZ1xyXG5jb25zdCBsb2dnaW5nID0ge1xyXG4gIC8vIEZsYWdzIGZvciBsb2dnaW5nIHN0YXR1c1xyXG4gIHRvQ29uc29sZTogdHJ1ZSxcclxuICB0b0ZpbGU6IGZhbHNlLFxyXG4gIHBhdGhDcmVhdGVkOiBmYWxzZSxcclxuICAvLyBGdWxsIHBhdGggdG8gdGhlIGxvZyBmaWxlXHJcbiAgcGF0aFRvTG9nOiAnJyxcclxuICAvLyBMb2cgbGV2ZWxzXHJcbiAgbGV2ZWxzRGVzYzogW1xyXG4gICAge1xyXG4gICAgICB0aXRsZTogJ2Vycm9yJyxcclxuICAgICAgY29sb3I6IGNvbG9yc1swXVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdGl0bGU6ICd3YXJuaW5nJyxcclxuICAgICAgY29sb3I6IGNvbG9yc1sxXVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdGl0bGU6ICdub3RpY2UnLFxyXG4gICAgICBjb2xvcjogY29sb3JzWzJdXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0aXRsZTogJ3ZlcmJvc2UnLFxyXG4gICAgICBjb2xvcjogY29sb3JzWzNdXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0aXRsZTogJ2JlbmNobWFyaycsXHJcbiAgICAgIGNvbG9yOiBjb2xvcnNbNF1cclxuICAgIH1cclxuICBdXHJcbn07XHJcblxyXG4vKipcclxuICogTG9ncyBhIG1lc3NhZ2Ugd2l0aCBhIHNwZWNpZmllZCBsb2cgbGV2ZWwuIEFjY2VwdHMgYSB2YXJpYWJsZSBudW1iZXJcclxuICogb2YgYXJndW1lbnRzLiBUaGUgYXJndW1lbnRzIGFmdGVyIHRoZSBgbGV2ZWxgIGFyZSBwYXNzZWQgdG8gYGNvbnNvbGUubG9nYFxyXG4gKiBhbmQvb3IgdXNlZCB0byBjb25zdHJ1Y3QgYW5kIGFwcGVuZCBtZXNzYWdlcyB0byBhIGxvZyBmaWxlLlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gbG9nXHJcbiAqXHJcbiAqIEBwYXJhbSB7Li4udW5rbm93bn0gYXJncyAtIEFuIGFycmF5IG9mIGFyZ3VtZW50cyB3aGVyZSB0aGUgZmlyc3QgaXMgdGhlIGxvZ1xyXG4gKiBsZXZlbCBhbmQgdGhlIHJlbWFpbmluZyBhcmUgc3RyaW5ncyB1c2VkIHRvIGJ1aWxkIHRoZSBsb2cgbWVzc2FnZS5cclxuICpcclxuICogQHJldHVybnMge3ZvaWR9IEV4aXRzIHRoZSBmdW5jdGlvbiBleGVjdXRpb24gaWYgYXR0ZW1wdGluZyB0byBsb2cgYXQgYSBsZXZlbFxyXG4gKiBoaWdoZXIgdGhhbiBhbGxvd2VkLlxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIGxvZyguLi5hcmdzKSB7XHJcbiAgY29uc3QgW25ld0xldmVsLCAuLi50ZXh0c10gPSBhcmdzO1xyXG5cclxuICAvLyBDdXJyZW50IGxvZ2dpbmcgb3B0aW9uc1xyXG4gIGNvbnN0IHsgbGV2ZWxzRGVzYywgbGV2ZWwgfSA9IGxvZ2dpbmc7XHJcblxyXG4gIC8vIENoZWNrIGlmIHRoZSBsb2cgbGV2ZWwgaXMgd2l0aGluIGEgY29ycmVjdCByYW5nZSBvciBpcyBpdCBhIGJlbmNobWFyayBsb2dcclxuICBpZiAoXHJcbiAgICBuZXdMZXZlbCAhPT0gNSAmJlxyXG4gICAgKG5ld0xldmVsID09PSAwIHx8IG5ld0xldmVsID4gbGV2ZWwgfHwgbGV2ZWwgPiBsZXZlbHNEZXNjLmxlbmd0aClcclxuICApIHtcclxuICAgIHJldHVybjtcclxuICB9XHJcblxyXG4gIC8vIENyZWF0ZSBhIG1lc3NhZ2UncyBwcmVmaXhcclxuICBjb25zdCBwcmVmaXggPSBgJHtnZXROZXdEYXRlKCl9IFske2xldmVsc0Rlc2NbbmV3TGV2ZWwgLSAxXS50aXRsZX1dIC1gO1xyXG5cclxuICAvLyBMb2cgdG8gZmlsZVxyXG4gIGlmIChsb2dnaW5nLnRvRmlsZSkge1xyXG4gICAgX2xvZ1RvRmlsZSh0ZXh0cywgcHJlZml4KTtcclxuICB9XHJcblxyXG4gIC8vIExvZyB0byBjb25zb2xlXHJcbiAgaWYgKGxvZ2dpbmcudG9Db25zb2xlKSB7XHJcbiAgICBjb25zb2xlLmxvZy5hcHBseShcclxuICAgICAgdW5kZWZpbmVkLFxyXG4gICAgICBbcHJlZml4LnRvU3RyaW5nKClbbG9nZ2luZy5sZXZlbHNEZXNjW25ld0xldmVsIC0gMV0uY29sb3JdXS5jb25jYXQodGV4dHMpXHJcbiAgICApO1xyXG4gIH1cclxufVxyXG5cclxuLyoqXHJcbiAqIExvZ3MgYW4gZXJyb3IgbWVzc2FnZSBhbG9uZyB3aXRoIGl0cyBzdGFjayB0cmFjZS4gT3B0aW9uYWxseSwgYSBjdXN0b20gbWVzc2FnZVxyXG4gKiBjYW4gYmUgcHJvdmlkZWQuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBsb2dXaXRoU3RhY2tcclxuICpcclxuICogQHBhcmFtIHtudW1iZXJ9IG5ld0xldmVsIC0gVGhlIGxvZyBsZXZlbC5cclxuICogQHBhcmFtIHtFcnJvcn0gZXJyb3IgLSBUaGUgZXJyb3Igb2JqZWN0IGNvbnRhaW5pbmcgdGhlIHN0YWNrIHRyYWNlLlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gY3VzdG9tTWVzc2FnZSAtIEFuIG9wdGlvbmFsIGN1c3RvbSBtZXNzYWdlIHRvIGJlIGluY2x1ZGVkXHJcbiAqIGluIHRoZSBsb2cgYWxvbmdzaWRlIHRoZSBlcnJvci5cclxuICpcclxuICogQHJldHVybnMge3ZvaWR9IEV4aXRzIHRoZSBmdW5jdGlvbiBleGVjdXRpb24gaWYgYXR0ZW1wdGluZyB0byBsb2cgYXQgYSBsZXZlbFxyXG4gKiBoaWdoZXIgdGhhbiBhbGxvd2VkLlxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIGxvZ1dpdGhTdGFjayhuZXdMZXZlbCwgZXJyb3IsIGN1c3RvbU1lc3NhZ2UpIHtcclxuICAvLyBHZXQgdGhlIG1haW4gbWVzc2FnZVxyXG4gIGNvbnN0IG1haW5NZXNzYWdlID0gY3VzdG9tTWVzc2FnZSB8fCAoZXJyb3IgJiYgZXJyb3IubWVzc2FnZSkgfHwgJyc7XHJcblxyXG4gIC8vIEN1cnJlbnQgbG9nZ2luZyBvcHRpb25zXHJcbiAgY29uc3QgeyBsZXZlbCwgbGV2ZWxzRGVzYyB9ID0gbG9nZ2luZztcclxuXHJcbiAgLy8gQ2hlY2sgaWYgdGhlIGxvZyBsZXZlbCBpcyB3aXRoaW4gYSBjb3JyZWN0IHJhbmdlXHJcbiAgaWYgKG5ld0xldmVsID09PSAwIHx8IG5ld0xldmVsID4gbGV2ZWwgfHwgbGV2ZWwgPiBsZXZlbHNEZXNjLmxlbmd0aCkge1xyXG4gICAgcmV0dXJuO1xyXG4gIH1cclxuXHJcbiAgLy8gQ3JlYXRlIGEgbWVzc2FnZSdzIHByZWZpeFxyXG4gIGNvbnN0IHByZWZpeCA9IGAke2dldE5ld0RhdGUoKX0gWyR7bGV2ZWxzRGVzY1tuZXdMZXZlbCAtIDFdLnRpdGxlfV0gLWA7XHJcblxyXG4gIC8vIEFkZCB0aGUgd2hvbGUgc3RhY2sgbWVzc2FnZVxyXG4gIGNvbnN0IHN0YWNrTWVzc2FnZSA9IGVycm9yICYmIGVycm9yLnN0YWNrO1xyXG5cclxuICAvLyBDb21iaW5lIGN1c3RvbSBtZXNzYWdlIG9yIGVycm9yIG1lc3NhZ2Ugd2l0aCBlcnJvciBzdGFjayBtZXNzYWdlLCBpZiBleGlzdHNcclxuICBjb25zdCB0ZXh0cyA9IFttYWluTWVzc2FnZV07XHJcbiAgaWYgKHN0YWNrTWVzc2FnZSkge1xyXG4gICAgdGV4dHMucHVzaCgnXFxuJywgc3RhY2tNZXNzYWdlKTtcclxuICB9XHJcblxyXG4gIC8vIExvZyB0byBmaWxlXHJcbiAgaWYgKGxvZ2dpbmcudG9GaWxlKSB7XHJcbiAgICBfbG9nVG9GaWxlKHRleHRzLCBwcmVmaXgpO1xyXG4gIH1cclxuXHJcbiAgLy8gTG9nIHRvIGNvbnNvbGVcclxuICBpZiAobG9nZ2luZy50b0NvbnNvbGUpIHtcclxuICAgIGNvbnNvbGUubG9nLmFwcGx5KFxyXG4gICAgICB1bmRlZmluZWQsXHJcbiAgICAgIFtwcmVmaXgudG9TdHJpbmcoKVtsb2dnaW5nLmxldmVsc0Rlc2NbbmV3TGV2ZWwgLSAxXS5jb2xvcl1dLmNvbmNhdChbXHJcbiAgICAgICAgdGV4dHMuc2hpZnQoKVtjb2xvcnNbbmV3TGV2ZWwgLSAxXV0sXHJcbiAgICAgICAgLi4udGV4dHNcclxuICAgICAgXSlcclxuICAgICk7XHJcbiAgfVxyXG59XHJcblxyXG4vKipcclxuICogTG9ncyBhbiBlcnJvciBtZXNzYWdlIHJlbGF0ZWQgdG8gWm9kIHZhbGlkYXRpb24gaXNzdWVzLiBPcHRpb25hbGx5LCBhIGN1c3RvbVxyXG4gKiBtZXNzYWdlIGNhbiBiZSBwcm92aWRlZC5cclxuICpcclxuICogQGZ1bmN0aW9uIGxvZ1pvZElzc3Vlc1xyXG4gKlxyXG4gKiBAcGFyYW0ge251bWJlcn0gbmV3TGV2ZWwgLSBUaGUgbG9nIGxldmVsLlxyXG4gKiBAcGFyYW0ge0Vycm9yW119IGlzc3VlcyAtIEFuIGFycmF5IG9mIFpvZCB2YWxpZGF0aW9uIGlzc3Vlcy5cclxuICogQHBhcmFtIHtzdHJpbmd9IGN1c3RvbU1lc3NhZ2UgLSBBbiBvcHRpb25hbCBjdXN0b20gbWVzc2FnZSB0byBiZSBpbmNsdWRlZFxyXG4gKiBpbiB0aGUgbG9nIGFsb25nc2lkZSB0aGUgZXJyb3IuXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gbG9nWm9kSXNzdWVzKG5ld0xldmVsLCBpc3N1ZXMsIGN1c3RvbU1lc3NhZ2UpIHtcclxuICBsb2dXaXRoU3RhY2soXHJcbiAgICBuZXdMZXZlbCxcclxuICAgIG51bGwsXHJcbiAgICBbXHJcbiAgICAgIGAke2N1c3RvbU1lc3NhZ2UgfHwgJ1t2YWxpZGF0aW9uXSBWYWxpZGF0aW9uIGVycm9yJ30gLSB0aGUgZm9sbG93aW5nIFpvZCBpc3N1ZXMgb2NjdXJlZDpgLFxyXG4gICAgICAuLi4oaXNzdWVzIHx8IFtdKS5tYXAoKGlzc3VlKSA9PiBgLSAke2lzc3VlLm1lc3NhZ2V9YClcclxuICAgIF0uam9pbignXFxuJylcclxuICApO1xyXG59XHJcblxyXG4vKipcclxuICogSW5pdGlhbGl6ZXMgbG9nZ2luZyB3aXRoIHRoZSBzcGVjaWZpZWQgbG9nZ2luZyBjb25maWd1cmF0aW9uLlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gaW5pdExvZ2dpbmdcclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IGxvZ2dpbmdPcHRpb25zIC0gVGhlIGNvbmZpZ3VyYXRpb24gb2JqZWN0IGNvbnRhaW5pbmdcclxuICogYGxvZ2dpbmdgIG9wdGlvbnMuXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gaW5pdExvZ2dpbmcobG9nZ2luZ09wdGlvbnMpIHtcclxuICAvLyBHZXQgb3B0aW9ucyBmcm9tIHRoZSBgbG9nZ2luZ09wdGlvbnNgIG9iamVjdFxyXG4gIGNvbnN0IHsgbGV2ZWwsIGRlc3QsIGZpbGUsIHRvQ29uc29sZSwgdG9GaWxlIH0gPSBsb2dnaW5nT3B0aW9ucztcclxuXHJcbiAgLy8gUmVzZXQgZmxhZ3MgdG8gdGhlIGRlZmF1bHQgdmFsdWVzXHJcbiAgbG9nZ2luZy5wYXRoQ3JlYXRlZCA9IGZhbHNlO1xyXG4gIGxvZ2dpbmcucGF0aFRvTG9nID0gJyc7XHJcblxyXG4gIC8vIFNldCB0aGUgbG9nZ2luZyBsZXZlbFxyXG4gIHNldExvZ0xldmVsKGxldmVsKTtcclxuXHJcbiAgLy8gU2V0IHRoZSBjb25zb2xlIGxvZ2dpbmdcclxuICBlbmFibGVDb25zb2xlTG9nZ2luZyh0b0NvbnNvbGUpO1xyXG5cclxuICAvLyBTZXQgdGhlIGZpbGUgbG9nZ2luZ1xyXG4gIGVuYWJsZUZpbGVMb2dnaW5nKGRlc3QsIGZpbGUsIHRvRmlsZSk7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBTZXRzIHRoZSBsb2cgbGV2ZWwgdG8gdGhlIHNwZWNpZmllZCB2YWx1ZS4gTG9nIGxldmVscyBhcmUgKGAwYCA9IG5vIGxvZ2dpbmcsXHJcbiAqIGAxYCA9IGVycm9yLCBgMmAgPSB3YXJuaW5nLCBgM2AgPSBub3RpY2UsIGA0YCA9IHZlcmJvc2UsIG9yIGA1YCA9IGJlbmNobWFyaykuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBzZXRMb2dMZXZlbFxyXG4gKlxyXG4gKiBAcGFyYW0ge251bWJlcn0gbGV2ZWwgLSBUaGUgbG9nIGxldmVsIHRvIGJlIHNldC5cclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiBzZXRMb2dMZXZlbChsZXZlbCkge1xyXG4gIGlmIChcclxuICAgIE51bWJlci5pc0ludGVnZXIobGV2ZWwpICYmXHJcbiAgICBsZXZlbCA+PSAwICYmXHJcbiAgICBsZXZlbCA8PSBsb2dnaW5nLmxldmVsc0Rlc2MubGVuZ3RoXHJcbiAgKSB7XHJcbiAgICAvLyBVcGRhdGUgdGhlIG1vZHVsZSBsb2dnaW5nJ3MgYGxldmVsYCBvcHRpb25cclxuICAgIGxvZ2dpbmcubGV2ZWwgPSBsZXZlbDtcclxuICB9XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBFbmFibGVzIGNvbnNvbGUgbG9nZ2luZy5cclxuICpcclxuICogQGZ1bmN0aW9uIGVuYWJsZUNvbnNvbGVMb2dnaW5nXHJcbiAqXHJcbiAqIEBwYXJhbSB7Ym9vbGVhbn0gdG9Db25zb2xlIC0gVGhlIGZsYWcgZm9yIHNldHRpbmcgdGhlIGxvZ2dpbmcgdG8gdGhlIGNvbnNvbGUuXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gZW5hYmxlQ29uc29sZUxvZ2dpbmcodG9Db25zb2xlKSB7XHJcbiAgLy8gVXBkYXRlIHRoZSBtb2R1bGUgbG9nZ2luZydzIGB0b0NvbnNvbGVgIG9wdGlvblxyXG4gIGxvZ2dpbmcudG9Db25zb2xlID0gISF0b0NvbnNvbGU7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBFbmFibGVzIGZpbGUgbG9nZ2luZyB3aXRoIHRoZSBzcGVjaWZpZWQgZGVzdGluYXRpb24gYW5kIGxvZyBmaWxlIG5hbWUuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBlbmFibGVGaWxlTG9nZ2luZ1xyXG4gKlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gZGVzdCAtIFRoZSBkZXN0aW5hdGlvbiBwYXRoIHdoZXJlIHRoZSBsb2cgZmlsZSBzaG91bGRcclxuICogYmUgc2F2ZWQuXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSBmaWxlIC0gVGhlIG5hbWUgb2YgdGhlIGxvZyBmaWxlLlxyXG4gKiBAcGFyYW0ge2Jvb2xlYW59IHRvRmlsZSAtIEEgZmxhZyBpbmRpY2F0aW5nIHdoZXRoZXIgbG9nZ2luZyBzaG91bGRcclxuICogYmUgZGlyZWN0ZWQgdG8gYSBmaWxlLlxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIGVuYWJsZUZpbGVMb2dnaW5nKGRlc3QsIGZpbGUsIHRvRmlsZSkge1xyXG4gIC8vIFVwZGF0ZSB0aGUgbW9kdWxlIGxvZ2dpbmcncyBgdG9GaWxlYCBvcHRpb25cclxuICBsb2dnaW5nLnRvRmlsZSA9ICEhdG9GaWxlO1xyXG5cclxuICAvLyBTZXQgdGhlIGBkZXN0YCBhbmQgYGZpbGVgIG9wdGlvbnMgb25seSBpZiB0aGUgZmlsZSBsb2dnaW5nIGlzIGVuYWJsZWRcclxuICBpZiAobG9nZ2luZy50b0ZpbGUpIHtcclxuICAgIGxvZ2dpbmcuZGVzdCA9IGRlc3QgfHwgJyc7XHJcbiAgICBsb2dnaW5nLmZpbGUgPSBmaWxlIHx8ICcnO1xyXG4gIH1cclxufVxyXG5cclxuLyoqXHJcbiAqIExvZ3MgdGhlIHByb3ZpZGVkIHRleHRzIHRvIGEgZmlsZSwgaWYgZmlsZSBsb2dnaW5nIGlzIGVuYWJsZWQuIEl0IGNyZWF0ZXNcclxuICogdGhlIG5lY2Vzc2FyeSBkaXJlY3Rvcnkgc3RydWN0dXJlIGlmIG5vdCBhbHJlYWR5IGNyZWF0ZWQgYW5kIGFwcGVuZHNcclxuICogdGhlIGNvbnRlbnQsIGluY2x1ZGluZyBhbiBvcHRpb25hbCBwcmVmaXgsIHRvIHRoZSBzcGVjaWZpZWQgbG9nIGZpbGUuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBfbG9nVG9GaWxlXHJcbiAqXHJcbiAqIEBwYXJhbSB7QXJyYXkuPHN0cmluZz59IHRleHRzIC0gQW4gYXJyYXkgb2YgdGV4dHMgdG8gYmUgbG9nZ2VkLlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gcHJlZml4IC0gQW4gb3B0aW9uYWwgcHJlZml4IHRvIGJlIGFkZGVkIHRvIGVhY2ggbG9nIGVudHJ5LlxyXG4gKi9cclxuZnVuY3Rpb24gX2xvZ1RvRmlsZSh0ZXh0cywgcHJlZml4KSB7XHJcbiAgaWYgKCFsb2dnaW5nLnBhdGhDcmVhdGVkKSB7XHJcbiAgICAvLyBDcmVhdGUgaWYgZG9lcyBub3QgZXhpc3RcclxuICAgICFleGlzdHNTeW5jKGdldEFic29sdXRlUGF0aChsb2dnaW5nLmRlc3QpKSAmJlxyXG4gICAgICBta2RpclN5bmMoZ2V0QWJzb2x1dGVQYXRoKGxvZ2dpbmcuZGVzdCkpO1xyXG5cclxuICAgIC8vIENyZWF0ZSB0aGUgZnVsbCBwYXRoXHJcbiAgICBsb2dnaW5nLnBhdGhUb0xvZyA9IGdldEFic29sdXRlUGF0aChqb2luKGxvZ2dpbmcuZGVzdCwgbG9nZ2luZy5maWxlKSk7XHJcblxyXG4gICAgLy8gV2Ugbm93IGFzc3VtZSB0aGUgcGF0aCBpcyBhdmFpbGFibGUsIGUuZy4gaXQncyB0aGUgcmVzcG9uc2liaWxpdHlcclxuICAgIC8vIG9mIHRoZSB1c2VyIHRvIGNyZWF0ZSB0aGUgcGF0aCB3aXRoIHRoZSBjb3JyZWN0IGFjY2VzcyByaWdodHMuXHJcbiAgICBsb2dnaW5nLnBhdGhDcmVhdGVkID0gdHJ1ZTtcclxuICB9XHJcblxyXG4gIC8vIEFkZCB0aGUgY29udGVudCB0byBhIGZpbGVcclxuICBhcHBlbmRGaWxlKFxyXG4gICAgbG9nZ2luZy5wYXRoVG9Mb2csXHJcbiAgICBbcHJlZml4XS5jb25jYXQodGV4dHMpLmpvaW4oJyAnKSArICdcXG4nLFxyXG4gICAgKGVycm9yKSA9PiB7XHJcbiAgICAgIGlmIChlcnJvciAmJiBsb2dnaW5nLnRvRmlsZSAmJiBsb2dnaW5nLnBhdGhDcmVhdGVkKSB7XHJcbiAgICAgICAgbG9nZ2luZy50b0ZpbGUgPSBmYWxzZTtcclxuICAgICAgICBsb2dnaW5nLnBhdGhDcmVhdGVkID0gZmFsc2U7XHJcbiAgICAgICAgbG9nV2l0aFN0YWNrKDIsIGVycm9yLCBgW2xvZ2dlcl0gVW5hYmxlIHRvIHdyaXRlIHRvIGxvZyBmaWxlLmApO1xyXG4gICAgICB9XHJcbiAgICB9XHJcbiAgKTtcclxufVxyXG5cclxuZXhwb3J0IGRlZmF1bHQge1xyXG4gIGxvZyxcclxuICBsb2dXaXRoU3RhY2ssXHJcbiAgbG9nWm9kSXNzdWVzLFxyXG4gIGluaXRMb2dnaW5nLFxyXG4gIHNldExvZ0xldmVsLFxyXG4gIGVuYWJsZUNvbnNvbGVMb2dnaW5nLFxyXG4gIGVuYWJsZUZpbGVMb2dnaW5nXHJcbn07XHJcbiIsIi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXHJcblxyXG5IaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXJcclxuXHJcbkNvcHlyaWdodCAoYykgMjAxNi0yMDI1LCBIaWdoc29mdFxyXG5cclxuTGljZW5jZWQgdW5kZXIgdGhlIE1JVCBsaWNlbmNlLlxyXG5cclxuQWRkaXRpb25hbGx5IGEgdmFsaWQgSGlnaGNoYXJ0cyBsaWNlbnNlIGlzIHJlcXVpcmVkIGZvciB1c2UuXHJcblxyXG5TZWUgTElDRU5TRSBmaWxlIGluIHJvb3QgZm9yIGRldGFpbHMuXHJcblxyXG4qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xyXG5cclxuLyoqXHJcbiAqIEBvdmVydmlldyBDb25maWd1cmF0aW9uIG1hbmFnZW1lbnQgbW9kdWxlIGZvciB0aGUgSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyLlxyXG4gKiBQcm92aWRlcyBkZWZhdWx0IGNvbmZpZ3VyYXRpb25zIHRoYXQgc3VwcG9ydCBlbnZpcm9ubWVudCB2YXJpYWJsZXMsIENMSVxyXG4gKiBhcmd1bWVudHMsIGFuZCBpbnRlcmFjdGl2ZSBwcm9tcHRzIGZvciBjdXN0b21pemF0aW9uIG9mIG9wdGlvbnMgYW5kIGZlYXR1cmVzLlxyXG4gKiBBZGRpdGlvbmFsbHksIGl0IG1hcHMgbGVnYWN5IG9wdGlvbnMgdG8gbW9kZXJuIHN0cnVjdHVyZXMsIGdlbmVyYXRlcyBuZXN0ZWRcclxuICogYXJndW1lbnQgbWFwcGluZ3MsIGFuZCBkaXNwbGF5cyBDTEkgdXNhZ2UgaW5mb3JtYXRpb24uXHJcbiAqL1xyXG5cclxuLyoqXHJcbiAqIFRoZSBjb25maWd1cmF0aW9uIG9iamVjdCBjb250YWluaW5nIGFsbCBhdmFpbGFibGUgb3B0aW9ucywgb3JnYW5pemVkXHJcbiAqIGJ5IHNlY3Rpb25zLlxyXG4gKlxyXG4gKiBUaGlzIG9iamVjdCBpbmNsdWRlczpcclxuICogLSBEZWZhdWx0IHZhbHVlcyBmb3IgZWFjaCBvcHRpb25cclxuICogLSBEYXRhIHR5cGVzIGZvciB2YWxpZGF0aW9uXHJcbiAqIC0gTmFtZXMgb2YgY29ycmVzcG9uZGluZyBlbnZpcm9ubWVudCB2YXJpYWJsZXNcclxuICogLSBEZXNjcmlwdGlvbnMgb2YgZWFjaCBwcm9wZXJ0eVxyXG4gKiAtIEluZm9ybWF0aW9uIHVzZWQgZm9yIHByb21wdHMgaW4gaW50ZXJhY3RpdmUgY29uZmlndXJhdGlvblxyXG4gKiAtIFtPcHRpb25hbF0gQ29ycmVzcG9uZGluZyBDTEkgYXJndW1lbnQgbmFtZXMgZm9yIENMSSB1c2FnZVxyXG4gKiAtIFtPcHRpb25hbF0gTGVnYWN5IG5hbWVzIGZyb20gdGhlIHByZXZpb3VzIFBoYW50b21KUy1iYXNlZCBzZXJ2ZXJcclxuICovXHJcbmV4cG9ydCBjb25zdCBkZWZhdWx0Q29uZmlnID0ge1xyXG4gIHB1cHBldGVlcjoge1xyXG4gICAgYXJnczoge1xyXG4gICAgICB2YWx1ZTogW1xyXG4gICAgICAgICctLWFsbG93LXJ1bm5pbmctaW5zZWN1cmUtY29udGVudCcsXHJcbiAgICAgICAgJy0tYXNoLW5vLW51ZGdlcycsXHJcbiAgICAgICAgJy0tYXV0b3BsYXktcG9saWN5PXVzZXItZ2VzdHVyZS1yZXF1aXJlZCcsXHJcbiAgICAgICAgJy0tYmxvY2stbmV3LXdlYi1jb250ZW50cycsXHJcbiAgICAgICAgJy0tZGlzYWJsZS1hY2NlbGVyYXRlZC0yZC1jYW52YXMnLFxyXG4gICAgICAgICctLWRpc2FibGUtYmFja2dyb3VuZC1uZXR3b3JraW5nJyxcclxuICAgICAgICAnLS1kaXNhYmxlLWJhY2tncm91bmQtdGltZXItdGhyb3R0bGluZycsXHJcbiAgICAgICAgJy0tZGlzYWJsZS1iYWNrZ3JvdW5kaW5nLW9jY2x1ZGVkLXdpbmRvd3MnLFxyXG4gICAgICAgICctLWRpc2FibGUtYnJlYWtwYWQnLFxyXG4gICAgICAgICctLWRpc2FibGUtY2hlY2tlci1pbWFnaW5nJyxcclxuICAgICAgICAnLS1kaXNhYmxlLWNsaWVudC1zaWRlLXBoaXNoaW5nLWRldGVjdGlvbicsXHJcbiAgICAgICAgJy0tZGlzYWJsZS1jb21wb25lbnQtZXh0ZW5zaW9ucy13aXRoLWJhY2tncm91bmQtcGFnZXMnLFxyXG4gICAgICAgICctLWRpc2FibGUtY29tcG9uZW50LXVwZGF0ZScsXHJcbiAgICAgICAgJy0tZGlzYWJsZS1kZWZhdWx0LWFwcHMnLFxyXG4gICAgICAgICctLWRpc2FibGUtZGV2LXNobS11c2FnZScsXHJcbiAgICAgICAgJy0tZGlzYWJsZS1kb21haW4tcmVsaWFiaWxpdHknLFxyXG4gICAgICAgICctLWRpc2FibGUtZXh0ZW5zaW9ucycsXHJcbiAgICAgICAgJy0tZGlzYWJsZS1mZWF0dXJlcz1DYWxjdWxhdGVOYXRpdmVXaW5PY2NsdXNpb24sSW50ZXJlc3RGZWVkQ29udGVudFN1Z2dlc3Rpb25zLFdlYk9UUCcsXHJcbiAgICAgICAgJy0tZGlzYWJsZS1oYW5nLW1vbml0b3InLFxyXG4gICAgICAgICctLWRpc2FibGUtaXBjLWZsb29kaW5nLXByb3RlY3Rpb24nLFxyXG4gICAgICAgICctLWRpc2FibGUtbG9nZ2luZycsXHJcbiAgICAgICAgJy0tZGlzYWJsZS1ub3RpZmljYXRpb25zJyxcclxuICAgICAgICAnLS1kaXNhYmxlLW9mZmVyLXN0b3JlLXVubWFza2VkLXdhbGxldC1jYXJkcycsXHJcbiAgICAgICAgJy0tZGlzYWJsZS1wb3B1cC1ibG9ja2luZycsXHJcbiAgICAgICAgJy0tZGlzYWJsZS1wcmludC1wcmV2aWV3JyxcclxuICAgICAgICAnLS1kaXNhYmxlLXByb21wdC1vbi1yZXBvc3QnLFxyXG4gICAgICAgICctLWRpc2FibGUtcmVuZGVyZXItYmFja2dyb3VuZGluZycsXHJcbiAgICAgICAgJy0tZGlzYWJsZS1zZWFyY2gtZW5naW5lLWNob2ljZS1zY3JlZW4nLFxyXG4gICAgICAgICctLWRpc2FibGUtc2Vzc2lvbi1jcmFzaGVkLWJ1YmJsZScsXHJcbiAgICAgICAgJy0tZGlzYWJsZS1zZXR1aWQtc2FuZGJveCcsXHJcbiAgICAgICAgJy0tZGlzYWJsZS1zaXRlLWlzb2xhdGlvbi10cmlhbHMnLFxyXG4gICAgICAgICctLWRpc2FibGUtc3BlZWNoLWFwaScsXHJcbiAgICAgICAgJy0tZGlzYWJsZS1zeW5jJyxcclxuICAgICAgICAnLS1lbmFibGUtdW5zYWZlLXdlYmdwdScsXHJcbiAgICAgICAgJy0taGlkZS1jcmFzaC1yZXN0b3JlLWJ1YmJsZScsXHJcbiAgICAgICAgJy0taGlkZS1zY3JvbGxiYXJzJyxcclxuICAgICAgICAnLS1tZXRyaWNzLXJlY29yZGluZy1vbmx5JyxcclxuICAgICAgICAnLS1tdXRlLWF1ZGlvJyxcclxuICAgICAgICAnLS1uby1kZWZhdWx0LWJyb3dzZXItY2hlY2snLFxyXG4gICAgICAgICctLW5vLWZpcnN0LXJ1bicsXHJcbiAgICAgICAgJy0tbm8tcGluZ3MnLFxyXG4gICAgICAgICctLW5vLXNhbmRib3gnLFxyXG4gICAgICAgICctLW5vLXN0YXJ0dXAtd2luZG93JyxcclxuICAgICAgICAnLS1uby16eWdvdGUnLFxyXG4gICAgICAgICctLXBhc3N3b3JkLXN0b3JlPWJhc2ljJyxcclxuICAgICAgICAnLS1wcm9jZXNzLXBlci10YWInLFxyXG4gICAgICAgICctLXVzZS1tb2NrLWtleWNoYWluJ1xyXG4gICAgICBdLFxyXG4gICAgICB0eXBlczogWydzdHJpbmdbXSddLFxyXG4gICAgICBlbnZMaW5rOiAnUFVQUEVURUVSX0FSR1MnLFxyXG4gICAgICBjbGlOYW1lOiAncHVwcGV0ZWVyQXJncycsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnQXJyYXkgb2YgUHVwcGV0ZWVyIGFyZ3VtZW50cycsXHJcbiAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICB0eXBlOiAnbGlzdCcsXHJcbiAgICAgICAgc2VwYXJhdG9yOiAnOydcclxuICAgICAgfVxyXG4gICAgfVxyXG4gIH0sXHJcbiAgaGlnaGNoYXJ0czoge1xyXG4gICAgdmVyc2lvbjoge1xyXG4gICAgICB2YWx1ZTogJ2xhdGVzdCcsXHJcbiAgICAgIHR5cGVzOiBbJ3N0cmluZyddLFxyXG4gICAgICBlbnZMaW5rOiAnSElHSENIQVJUU19WRVJTSU9OJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdIaWdoY2hhcnRzIHZlcnNpb24nLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ3RleHQnXHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICBjZG5Vcmw6IHtcclxuICAgICAgdmFsdWU6ICdodHRwczovL2NvZGUuaGlnaGNoYXJ0cy5jb20nLFxyXG4gICAgICB0eXBlczogWydzdHJpbmcnXSxcclxuICAgICAgZW52TGluazogJ0hJR0hDSEFSVFNfQ0ROX1VSTCcsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnQ0ROIFVSTCBmb3IgSGlnaGNoYXJ0cyBzY3JpcHRzJyxcclxuICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgIHR5cGU6ICd0ZXh0J1xyXG4gICAgICB9XHJcbiAgICB9LFxyXG4gICAgZm9yY2VGZXRjaDoge1xyXG4gICAgICB2YWx1ZTogZmFsc2UsXHJcbiAgICAgIHR5cGVzOiBbJ2Jvb2xlYW4nXSxcclxuICAgICAgZW52TGluazogJ0hJR0hDSEFSVFNfRk9SQ0VfRkVUQ0gnLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ0ZsYWcgdG8gcmVmZXRjaCBzY3JpcHRzIGFmdGVyIGVhY2ggc2VydmVyIHJlcnVuJyxcclxuICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgIHR5cGU6ICd0b2dnbGUnXHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICBjYWNoZVBhdGg6IHtcclxuICAgICAgdmFsdWU6ICcuY2FjaGUnLFxyXG4gICAgICB0eXBlczogWydzdHJpbmcnXSxcclxuICAgICAgZW52TGluazogJ0hJR0hDSEFSVFNfQ0FDSEVfUEFUSCcsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnRGlyZWN0b3J5IHBhdGggZm9yIGNhY2hlZCBIaWdoY2hhcnRzIHNjcmlwdHMnLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ3RleHQnXHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICBjb3JlU2NyaXB0czoge1xyXG4gICAgICB2YWx1ZTogWydoaWdoY2hhcnRzJywgJ2hpZ2hjaGFydHMtbW9yZScsICdoaWdoY2hhcnRzLTNkJ10sXHJcbiAgICAgIHR5cGVzOiBbJ3N0cmluZ1tdJ10sXHJcbiAgICAgIGVudkxpbms6ICdISUdIQ0hBUlRTX0NPUkVfU0NSSVBUUycsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnSGlnaGNoYXJ0cyBjb3JlIHNjcmlwdHMgdG8gZmV0Y2gnLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ211bHRpc2VsZWN0JyxcclxuICAgICAgICBpbnN0cnVjdGlvbnM6ICdTcGFjZTogU2VsZWN0IHNwZWNpZmljLCBBOiBTZWxlY3QgYWxsLCBFbnRlcjogQ29uZmlybSdcclxuICAgICAgfVxyXG4gICAgfSxcclxuICAgIG1vZHVsZVNjcmlwdHM6IHtcclxuICAgICAgdmFsdWU6IFtcclxuICAgICAgICAnc3RvY2snLFxyXG4gICAgICAgICdtYXAnLFxyXG4gICAgICAgICdnYW50dCcsXHJcbiAgICAgICAgJ2V4cG9ydGluZycsXHJcbiAgICAgICAgJ3BhcmFsbGVsLWNvb3JkaW5hdGVzJyxcclxuICAgICAgICAnYWNjZXNzaWJpbGl0eScsXHJcbiAgICAgICAgLy8gJ2Fubm90YXRpb25zLWFkdmFuY2VkJyxcclxuICAgICAgICAnYm9vc3QtY2FudmFzJyxcclxuICAgICAgICAnYm9vc3QnLFxyXG4gICAgICAgICdkYXRhJyxcclxuICAgICAgICAnZGF0YS10b29scycsXHJcbiAgICAgICAgJ2RyYWdnYWJsZS1wb2ludHMnLFxyXG4gICAgICAgICdzdGF0aWMtc2NhbGUnLFxyXG4gICAgICAgICdicm9rZW4tYXhpcycsXHJcbiAgICAgICAgJ2hlYXRtYXAnLFxyXG4gICAgICAgICd0aWxlbWFwJyxcclxuICAgICAgICAndGlsZWR3ZWJtYXAnLFxyXG4gICAgICAgICd0aW1lbGluZScsXHJcbiAgICAgICAgJ3RyZWVtYXAnLFxyXG4gICAgICAgICd0cmVlZ3JhcGgnLFxyXG4gICAgICAgICdpdGVtLXNlcmllcycsXHJcbiAgICAgICAgJ2RyaWxsZG93bicsXHJcbiAgICAgICAgJ2hpc3RvZ3JhbS1iZWxsY3VydmUnLFxyXG4gICAgICAgICdidWxsZXQnLFxyXG4gICAgICAgICdmdW5uZWwnLFxyXG4gICAgICAgICdmdW5uZWwzZCcsXHJcbiAgICAgICAgJ2dlb2hlYXRtYXAnLFxyXG4gICAgICAgICdweXJhbWlkM2QnLFxyXG4gICAgICAgICduZXR3b3JrZ3JhcGgnLFxyXG4gICAgICAgICdvdmVybGFwcGluZy1kYXRhbGFiZWxzJyxcclxuICAgICAgICAncGFyZXRvJyxcclxuICAgICAgICAncGF0dGVybi1maWxsJyxcclxuICAgICAgICAncGljdG9yaWFsJyxcclxuICAgICAgICAncHJpY2UtaW5kaWNhdG9yJyxcclxuICAgICAgICAnc2Fua2V5JyxcclxuICAgICAgICAnYXJjLWRpYWdyYW0nLFxyXG4gICAgICAgICdkZXBlbmRlbmN5LXdoZWVsJyxcclxuICAgICAgICAnc2VyaWVzLWxhYmVsJyxcclxuICAgICAgICAnc2VyaWVzLW9uLXBvaW50JyxcclxuICAgICAgICAnc29saWQtZ2F1Z2UnLFxyXG4gICAgICAgICdzb25pZmljYXRpb24nLFxyXG4gICAgICAgIC8vICdzdG9jay10b29scycsXHJcbiAgICAgICAgJ3N0cmVhbWdyYXBoJyxcclxuICAgICAgICAnc3VuYnVyc3QnLFxyXG4gICAgICAgICd2YXJpYWJsZS1waWUnLFxyXG4gICAgICAgICd2YXJpd2lkZScsXHJcbiAgICAgICAgJ3ZlY3RvcicsXHJcbiAgICAgICAgJ3Zlbm4nLFxyXG4gICAgICAgICd3aW5kYmFyYicsXHJcbiAgICAgICAgJ3dvcmRjbG91ZCcsXHJcbiAgICAgICAgJ3hyYW5nZScsXHJcbiAgICAgICAgJ25vLWRhdGEtdG8tZGlzcGxheScsXHJcbiAgICAgICAgJ2RyYWctcGFuZXMnLFxyXG4gICAgICAgICdkZWJ1Z2dlcicsXHJcbiAgICAgICAgJ2R1bWJiZWxsJyxcclxuICAgICAgICAnbG9sbGlwb3AnLFxyXG4gICAgICAgICdjeWxpbmRlcicsXHJcbiAgICAgICAgJ29yZ2FuaXphdGlvbicsXHJcbiAgICAgICAgJ2RvdHBsb3QnLFxyXG4gICAgICAgICdtYXJrZXItY2x1c3RlcnMnLFxyXG4gICAgICAgICdob2xsb3djYW5kbGVzdGljaycsXHJcbiAgICAgICAgJ2hlaWtpbmFzaGknLFxyXG4gICAgICAgICdmbG93bWFwJyxcclxuICAgICAgICAnZXhwb3J0LWRhdGEnLFxyXG4gICAgICAgICduYXZpZ2F0b3InLFxyXG4gICAgICAgICd0ZXh0cGF0aCdcclxuICAgICAgXSxcclxuICAgICAgdHlwZXM6IFsnc3RyaW5nW10nXSxcclxuICAgICAgZW52TGluazogJ0hJR0hDSEFSVFNfTU9EVUxFX1NDUklQVFMnLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ0hpZ2hjaGFydHMgbW9kdWxlIHNjcmlwdHMgdG8gZmV0Y2gnLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ211bHRpc2VsZWN0JyxcclxuICAgICAgICBpbnN0cnVjdGlvbnM6ICdTcGFjZTogU2VsZWN0IHNwZWNpZmljLCBBOiBTZWxlY3QgYWxsLCBFbnRlcjogQ29uZmlybSdcclxuICAgICAgfVxyXG4gICAgfSxcclxuICAgIGluZGljYXRvclNjcmlwdHM6IHtcclxuICAgICAgdmFsdWU6IFsnaW5kaWNhdG9ycy1hbGwnXSxcclxuICAgICAgdHlwZXM6IFsnc3RyaW5nW10nXSxcclxuICAgICAgZW52TGluazogJ0hJR0hDSEFSVFNfSU5ESUNBVE9SX1NDUklQVFMnLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ0hpZ2hjaGFydHMgaW5kaWNhdG9yIHNjcmlwdHMgdG8gZmV0Y2gnLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ211bHRpc2VsZWN0JyxcclxuICAgICAgICBpbnN0cnVjdGlvbnM6ICdTcGFjZTogU2VsZWN0IHNwZWNpZmljLCBBOiBTZWxlY3QgYWxsLCBFbnRlcjogQ29uZmlybSdcclxuICAgICAgfVxyXG4gICAgfSxcclxuICAgIGN1c3RvbVNjcmlwdHM6IHtcclxuICAgICAgdmFsdWU6IFtcclxuICAgICAgICAnaHR0cHM6Ly9jZG5qcy5jbG91ZGZsYXJlLmNvbS9hamF4L2xpYnMvbW9tZW50LmpzLzIuMzAuMS9tb21lbnQubWluLmpzJyxcclxuICAgICAgICAnaHR0cHM6Ly9jZG5qcy5jbG91ZGZsYXJlLmNvbS9hamF4L2xpYnMvbW9tZW50LXRpbWV6b25lLzAuNS40NS9tb21lbnQtdGltZXpvbmUtd2l0aC1kYXRhLm1pbi5qcydcclxuICAgICAgXSxcclxuICAgICAgdHlwZXM6IFsnc3RyaW5nW10nXSxcclxuICAgICAgZW52TGluazogJ0hJR0hDSEFSVFNfQ1VTVE9NX1NDUklQVFMnLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ0FkZGl0aW9uYWwgY3VzdG9tIHNjcmlwdHMgb3IgZGVwZW5kZW5jaWVzIHRvIGZldGNoJyxcclxuICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgIHR5cGU6ICdsaXN0JyxcclxuICAgICAgICBzZXBhcmF0b3I6ICc7J1xyXG4gICAgICB9XHJcbiAgICB9XHJcbiAgfSxcclxuICBleHBvcnQ6IHtcclxuICAgIGluZmlsZToge1xyXG4gICAgICB2YWx1ZTogbnVsbCxcclxuICAgICAgdHlwZXM6IFsnc3RyaW5nJywgJ251bGwnXSxcclxuICAgICAgZW52TGluazogJ0VYUE9SVF9JTkZJTEUnLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnSW5wdXQgZmlsZW5hbWUgd2l0aCB0eXBlLCBmb3JtYXR0ZWQgY29ycmVjdGx5IGFzIEpTT04gb3IgU1ZHJyxcclxuICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgIHR5cGU6ICd0ZXh0J1xyXG4gICAgICB9XHJcbiAgICB9LFxyXG4gICAgaW5zdHI6IHtcclxuICAgICAgdmFsdWU6IG51bGwsXHJcbiAgICAgIHR5cGVzOiBbJ09iamVjdCcsICdzdHJpbmcnLCAnbnVsbCddLFxyXG4gICAgICBlbnZMaW5rOiAnRVhQT1JUX0lOU1RSJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ092ZXJyaWRlcyB0aGUgYGluZmlsZWAgd2l0aCBKU09OLCBzdHJpbmdpZmllZCBKU09OLCBvciBTVkcgaW5wdXQnLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ3RleHQnXHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICBvcHRpb25zOiB7XHJcbiAgICAgIHZhbHVlOiBudWxsLFxyXG4gICAgICB0eXBlczogWydPYmplY3QnLCAnc3RyaW5nJywgJ251bGwnXSxcclxuICAgICAgZW52TGluazogJ0VYUE9SVF9PUFRJT05TJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdBbGlhcyBmb3IgdGhlIGBpbnN0cmAgb3B0aW9uJyxcclxuICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgIHR5cGU6ICd0ZXh0J1xyXG4gICAgICB9XHJcbiAgICB9LFxyXG4gICAgc3ZnOiB7XHJcbiAgICAgIHZhbHVlOiBudWxsLFxyXG4gICAgICB0eXBlczogWydzdHJpbmcnLCAnbnVsbCddLFxyXG4gICAgICBlbnZMaW5rOiAnRVhQT1JUX1NWRycsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnU1ZHIHN0cmluZyByZXByZXNlbnRhdGlvbiBvZiB0aGUgY2hhcnQgdG8gcmVuZGVyJyxcclxuICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgIHR5cGU6ICd0ZXh0J1xyXG4gICAgICB9XHJcbiAgICB9LFxyXG4gICAgYmF0Y2g6IHtcclxuICAgICAgdmFsdWU6IG51bGwsXHJcbiAgICAgIHR5cGVzOiBbJ3N0cmluZycsICdudWxsJ10sXHJcbiAgICAgIGVudkxpbms6ICdFWFBPUlRfQkFUQ0gnLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnQmF0Y2ggam9iIHN0cmluZyB3aXRoIGlucHV0L291dHB1dCBwYWlyczogXCJpbj1vdXQ7aW49b3V0Oy4uLlwiJyxcclxuICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgIHR5cGU6ICd0ZXh0J1xyXG4gICAgICB9XHJcbiAgICB9LFxyXG4gICAgb3V0ZmlsZToge1xyXG4gICAgICB2YWx1ZTogbnVsbCxcclxuICAgICAgdHlwZXM6IFsnc3RyaW5nJywgJ251bGwnXSxcclxuICAgICAgZW52TGluazogJ0VYUE9SVF9PVVRGSUxFJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ091dHB1dCBmaWxlbmFtZSB3aXRoIHR5cGUuIENhbiBiZSBqcGVnLCBwbmcsIHBkZiwgb3Igc3ZnIGFuZCBpZ25vcmVzIGB0eXBlYCBvcHRpb24nLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ3RleHQnXHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICB0eXBlOiB7XHJcbiAgICAgIHZhbHVlOiAncG5nJyxcclxuICAgICAgdHlwZXM6IFsnc3RyaW5nJ10sXHJcbiAgICAgIGVudkxpbms6ICdFWFBPUlRfVFlQRScsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnRmlsZSBleHBvcnQgZm9ybWF0LiBDYW4gYmUganBlZywgcG5nLCBwZGYsIG9yIHN2ZycsXHJcbiAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICB0eXBlOiAnc2VsZWN0JyxcclxuICAgICAgICBoaW50OiAnRGVmYXVsdDogcG5nJyxcclxuICAgICAgICBjaG9pY2VzOiBbJ3BuZycsICdqcGVnJywgJ3BkZicsICdzdmcnXVxyXG4gICAgICB9XHJcbiAgICB9LFxyXG4gICAgY29uc3RyOiB7XHJcbiAgICAgIHZhbHVlOiAnY2hhcnQnLFxyXG4gICAgICB0eXBlczogWydzdHJpbmcnXSxcclxuICAgICAgZW52TGluazogJ0VYUE9SVF9DT05TVFInLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnQ2hhcnQgY29uc3RydWN0b3IuIENhbiBiZSBjaGFydCwgc3RvY2tDaGFydCwgbWFwQ2hhcnQsIG9yIGdhbnR0Q2hhcnQnLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ3NlbGVjdCcsXHJcbiAgICAgICAgaGludDogJ0RlZmF1bHQ6IGNoYXJ0JyxcclxuICAgICAgICBjaG9pY2VzOiBbJ2NoYXJ0JywgJ3N0b2NrQ2hhcnQnLCAnbWFwQ2hhcnQnLCAnZ2FudHRDaGFydCddXHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICBiNjQ6IHtcclxuICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICB0eXBlczogWydib29sZWFuJ10sXHJcbiAgICAgIGVudkxpbms6ICdFWFBPUlRfQjY0JyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ1doZXRoZXIgb3Igbm90IHRvIHRoZSBjaGFydCBzaG91bGQgYmUgcmVjZWl2ZWQgaW4gQmFzZTY0IGZvcm1hdCBpbnN0ZWFkIG9mIGJpbmFyeScsXHJcbiAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICB0eXBlOiAndG9nZ2xlJ1xyXG4gICAgICB9XHJcbiAgICB9LFxyXG4gICAgbm9Eb3dubG9hZDoge1xyXG4gICAgICB2YWx1ZTogZmFsc2UsXHJcbiAgICAgIHR5cGVzOiBbJ2Jvb2xlYW4nXSxcclxuICAgICAgZW52TGluazogJ0VYUE9SVF9OT19ET1dOTE9BRCcsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdXaGV0aGVyIG9yIG5vdCB0byBpbmNsdWRlIG9yIGV4Y2x1ZGUgYXR0YWNobWVudCBoZWFkZXJzIGluIHRoZSByZXNwb25zZScsXHJcbiAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICB0eXBlOiAndG9nZ2xlJ1xyXG4gICAgICB9XHJcbiAgICB9LFxyXG4gICAgaGVpZ2h0OiB7XHJcbiAgICAgIHZhbHVlOiBudWxsLFxyXG4gICAgICB0eXBlczogWydudW1iZXInLCAnbnVsbCddLFxyXG4gICAgICBlbnZMaW5rOiAnRVhQT1JUX0hFSUdIVCcsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnSGVpZ2h0IG9mIHRoZSBleHBvcnRlZCBjaGFydCwgb3ZlcnJpZGVzIGNoYXJ0IHNldHRpbmdzJyxcclxuICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgIHR5cGU6ICdudW1iZXInXHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICB3aWR0aDoge1xyXG4gICAgICB2YWx1ZTogbnVsbCxcclxuICAgICAgdHlwZXM6IFsnbnVtYmVyJywgJ251bGwnXSxcclxuICAgICAgZW52TGluazogJ0VYUE9SVF9XSURUSCcsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnV2lkdGggb2YgdGhlIGV4cG9ydGVkIGNoYXJ0LCBvdmVycmlkZXMgY2hhcnQgc2V0dGluZ3MnLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ251bWJlcidcclxuICAgICAgfVxyXG4gICAgfSxcclxuICAgIHNjYWxlOiB7XHJcbiAgICAgIHZhbHVlOiBudWxsLFxyXG4gICAgICB0eXBlczogWydudW1iZXInLCAnbnVsbCddLFxyXG4gICAgICBlbnZMaW5rOiAnRVhQT1JUX1NDQUxFJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ1NjYWxlIG9mIHRoZSBleHBvcnRlZCBjaGFydCwgb3ZlcnJpZGVzIGNoYXJ0IHNldHRpbmdzLiBSYW5nZXMgZnJvbSAwLjEgdG8gNS4wJyxcclxuICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgIHR5cGU6ICdudW1iZXInXHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICBkZWZhdWx0SGVpZ2h0OiB7XHJcbiAgICAgIHZhbHVlOiA0MDAsXHJcbiAgICAgIHR5cGVzOiBbJ251bWJlciddLFxyXG4gICAgICBlbnZMaW5rOiAnRVhQT1JUX0RFRkFVTFRfSEVJR0hUJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdEZWZhdWx0IGhlaWdodCBvZiB0aGUgZXhwb3J0ZWQgY2hhcnQgaWYgbm90IHNldCcsXHJcbiAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICB0eXBlOiAnbnVtYmVyJ1xyXG4gICAgICB9XHJcbiAgICB9LFxyXG4gICAgZGVmYXVsdFdpZHRoOiB7XHJcbiAgICAgIHZhbHVlOiA2MDAsXHJcbiAgICAgIHR5cGVzOiBbJ251bWJlciddLFxyXG4gICAgICBlbnZMaW5rOiAnRVhQT1JUX0RFRkFVTFRfV0lEVEgnLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ0RlZmF1bHQgd2lkdGggb2YgdGhlIGV4cG9ydGVkIGNoYXJ0IGlmIG5vdCBzZXQnLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ251bWJlcidcclxuICAgICAgfVxyXG4gICAgfSxcclxuICAgIGRlZmF1bHRTY2FsZToge1xyXG4gICAgICB2YWx1ZTogMSxcclxuICAgICAgdHlwZXM6IFsnbnVtYmVyJ10sXHJcbiAgICAgIGVudkxpbms6ICdFWFBPUlRfREVGQVVMVF9TQ0FMRScsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdEZWZhdWx0IHNjYWxlIG9mIHRoZSBleHBvcnRlZCBjaGFydCBpZiBub3Qgc2V0LiBSYW5nZXMgZnJvbSAwLjEgdG8gNS4wJyxcclxuICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICAgIG1pbjogMC4xLFxyXG4gICAgICAgIG1heDogNVxyXG4gICAgICB9XHJcbiAgICB9LFxyXG4gICAgZ2xvYmFsT3B0aW9uczoge1xyXG4gICAgICB2YWx1ZTogbnVsbCxcclxuICAgICAgdHlwZXM6IFsnT2JqZWN0JywgJ3N0cmluZycsICdudWxsJ10sXHJcbiAgICAgIGVudkxpbms6ICdFWFBPUlRfR0xPQkFMX09QVElPTlMnLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnSlNPTiwgc3RyaW5naWZpZWQgSlNPTiBvciBmaWxlbmFtZSB3aXRoIGdsb2JhbCBvcHRpb25zIGZvciBIaWdoY2hhcnRzLnNldE9wdGlvbnMnLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ3RleHQnXHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICB0aGVtZU9wdGlvbnM6IHtcclxuICAgICAgdmFsdWU6IG51bGwsXHJcbiAgICAgIHR5cGVzOiBbJ09iamVjdCcsICdzdHJpbmcnLCAnbnVsbCddLFxyXG4gICAgICBlbnZMaW5rOiAnRVhQT1JUX1RIRU1FX09QVElPTlMnLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnSlNPTiwgc3RyaW5naWZpZWQgSlNPTiBvciBmaWxlbmFtZSB3aXRoIHRoZW1lIG9wdGlvbnMgZm9yIEhpZ2hjaGFydHMuc2V0T3B0aW9ucycsXHJcbiAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICB0eXBlOiAndGV4dCdcclxuICAgICAgfVxyXG4gICAgfSxcclxuICAgIHJhc3Rlcml6YXRpb25UaW1lb3V0OiB7XHJcbiAgICAgIHZhbHVlOiAxNTAwLFxyXG4gICAgICB0eXBlczogWydudW1iZXInXSxcclxuICAgICAgZW52TGluazogJ0VYUE9SVF9SQVNURVJJWkFUSU9OX1RJTUVPVVQnLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ01pbGxpc2Vjb25kcyB0byB3YWl0IGZvciB3ZWJwYWdlIHJlbmRlcmluZycsXHJcbiAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICB0eXBlOiAnbnVtYmVyJ1xyXG4gICAgICB9XHJcbiAgICB9XHJcbiAgfSxcclxuICBjdXN0b21Mb2dpYzoge1xyXG4gICAgYWxsb3dDb2RlRXhlY3V0aW9uOiB7XHJcbiAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgdHlwZXM6IFsnYm9vbGVhbiddLFxyXG4gICAgICBlbnZMaW5rOiAnQ1VTVE9NX0xPR0lDX0FMTE9XX0NPREVfRVhFQ1VUSU9OJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ0FsbG93cyBvciBkaXNhbGxvd3MgZXhlY3V0aW9uIG9mIGFyYml0cmFyeSBjb2RlIGR1cmluZyBleHBvcnRpbmcnLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ3RvZ2dsZSdcclxuICAgICAgfVxyXG4gICAgfSxcclxuICAgIGFsbG93RmlsZVJlc291cmNlczoge1xyXG4gICAgICB2YWx1ZTogZmFsc2UsXHJcbiAgICAgIHR5cGVzOiBbJ2Jvb2xlYW4nXSxcclxuICAgICAgZW52TGluazogJ0NVU1RPTV9MT0dJQ19BTExPV19GSUxFX1JFU09VUkNFUycsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdBbGxvd3Mgb3IgZGlzYWxsb3dzIGluamVjdGlvbiBvZiBmaWxlc3lzdGVtIHJlc291cmNlcyAoZGlzYWJsZWQgaW4gc2VydmVyIG1vZGUpJyxcclxuICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgIHR5cGU6ICd0b2dnbGUnXHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICBjdXN0b21Db2RlOiB7XHJcbiAgICAgIHZhbHVlOiBudWxsLFxyXG4gICAgICB0eXBlczogWydzdHJpbmcnLCAnbnVsbCddLFxyXG4gICAgICBlbnZMaW5rOiAnQ1VTVE9NX0xPR0lDX0NVU1RPTV9DT0RFJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ0N1c3RvbSBjb2RlIHRvIGV4ZWN1dGUgYmVmb3JlIGNoYXJ0IGluaXRpYWxpemF0aW9uLiBDYW4gYmUgYSBmdW5jdGlvbiwgY29kZSB3cmFwcGVkIGluIGEgZnVuY3Rpb24sIG9yIGEgLmpzIGZpbGVuYW1lJyxcclxuICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgIHR5cGU6ICd0ZXh0J1xyXG4gICAgICB9XHJcbiAgICB9LFxyXG4gICAgY2FsbGJhY2s6IHtcclxuICAgICAgdmFsdWU6IG51bGwsXHJcbiAgICAgIHR5cGVzOiBbJ3N0cmluZycsICdudWxsJ10sXHJcbiAgICAgIGVudkxpbms6ICdDVVNUT01fTE9HSUNfQ0FMTEJBQ0snLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnSmF2YVNjcmlwdCBjb2RlIHRvIHJ1biBkdXJpbmcgY29uc3RydWN0aW9uLiBDYW4gYmUgYSBmdW5jdGlvbiBvciBhIC5qcyBmaWxlbmFtZScsXHJcbiAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICB0eXBlOiAndGV4dCdcclxuICAgICAgfVxyXG4gICAgfSxcclxuICAgIHJlc291cmNlczoge1xyXG4gICAgICB2YWx1ZTogbnVsbCxcclxuICAgICAgdHlwZXM6IFsnT2JqZWN0JywgJ3N0cmluZycsICdudWxsJ10sXHJcbiAgICAgIGVudkxpbms6ICdDVVNUT01fTE9HSUNfUkVTT1VSQ0VTJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ0FkZGl0aW9uYWwgcmVzb3VyY2VzIGFzIEpTT04sIHN0cmluZ2lmaWVkIEpTT04sIG9yIGZpbGVuYW1lLCBjb250YWluaW5nIGZpbGVzLCBqcywgYW5kIGNzcyBzZWN0aW9ucycsXHJcbiAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICB0eXBlOiAndGV4dCdcclxuICAgICAgfVxyXG4gICAgfSxcclxuICAgIGxvYWRDb25maWc6IHtcclxuICAgICAgdmFsdWU6IG51bGwsXHJcbiAgICAgIHR5cGVzOiBbJ3N0cmluZycsICdudWxsJ10sXHJcbiAgICAgIGVudkxpbms6ICdDVVNUT01fTE9HSUNfTE9BRF9DT05GSUcnLFxyXG4gICAgICBsZWdhY3lOYW1lOiAnZnJvbUZpbGUnLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ0ZpbGUgd2l0aCBhIHByZS1kZWZpbmVkIGNvbmZpZ3VyYXRpb24gdG8gdXNlJyxcclxuICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgIHR5cGU6ICd0ZXh0J1xyXG4gICAgICB9XHJcbiAgICB9LFxyXG4gICAgY3JlYXRlQ29uZmlnOiB7XHJcbiAgICAgIHZhbHVlOiBudWxsLFxyXG4gICAgICB0eXBlczogWydzdHJpbmcnLCAnbnVsbCddLFxyXG4gICAgICBlbnZMaW5rOiAnQ1VTVE9NX0xPR0lDX0NSRUFURV9DT05GSUcnLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnUHJvbXB0LWJhc2VkIG9wdGlvbiBzZXR0aW5nLCBzYXZlZCB0byBhIHByb3ZpZGVkIGNvbmZpZyBmaWxlJyxcclxuICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgIHR5cGU6ICd0ZXh0J1xyXG4gICAgICB9XHJcbiAgICB9XHJcbiAgfSxcclxuICBzZXJ2ZXI6IHtcclxuICAgIGVuYWJsZToge1xyXG4gICAgICB2YWx1ZTogZmFsc2UsXHJcbiAgICAgIHR5cGVzOiBbJ2Jvb2xlYW4nXSxcclxuICAgICAgZW52TGluazogJ1NFUlZFUl9FTkFCTEUnLFxyXG4gICAgICBjbGlOYW1lOiAnZW5hYmxlU2VydmVyJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdTdGFydHMgdGhlIHNlcnZlciB3aGVuIHRydWUnLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ3RvZ2dsZSdcclxuICAgICAgfVxyXG4gICAgfSxcclxuICAgIGhvc3Q6IHtcclxuICAgICAgdmFsdWU6ICcwLjAuMC4wJyxcclxuICAgICAgdHlwZXM6IFsnc3RyaW5nJ10sXHJcbiAgICAgIGVudkxpbms6ICdTRVJWRVJfSE9TVCcsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnSG9zdG5hbWUgb2YgdGhlIHNlcnZlcicsXHJcbiAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICB0eXBlOiAndGV4dCdcclxuICAgICAgfVxyXG4gICAgfSxcclxuICAgIHBvcnQ6IHtcclxuICAgICAgdmFsdWU6IDc4MDEsXHJcbiAgICAgIHR5cGVzOiBbJ251bWJlciddLFxyXG4gICAgICBlbnZMaW5rOiAnU0VSVkVSX1BPUlQnLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ1BvcnQgbnVtYmVyIGZvciB0aGUgc2VydmVyJyxcclxuICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgIHR5cGU6ICdudW1iZXInXHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICB1cGxvYWRMaW1pdDoge1xyXG4gICAgICB2YWx1ZTogMyxcclxuICAgICAgdHlwZXM6IFsnbnVtYmVyJ10sXHJcbiAgICAgIGVudkxpbms6ICdTRVJWRVJfVVBMT0FEX0xJTUlUJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdNYXhpbXVtIHJlcXVlc3QgYm9keSBzaXplIGluIE1CJyxcclxuICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgIHR5cGU6ICdudW1iZXInXHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICBiZW5jaG1hcmtpbmc6IHtcclxuICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICB0eXBlczogWydib29sZWFuJ10sXHJcbiAgICAgIGVudkxpbms6ICdTRVJWRVJfQkVOQ0hNQVJLSU5HJyxcclxuICAgICAgY2xpTmFtZTogJ3NlcnZlckJlbmNobWFya2luZycsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdEaXNwbGF5cyBvciBub3QgYWN0aW9uIGR1cmF0aW9ucyBpbiBtaWxsaXNlY29uZHMgZHVyaW5nIHNlcnZlciByZXF1ZXN0cycsXHJcbiAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICB0eXBlOiAndG9nZ2xlJ1xyXG4gICAgICB9XHJcbiAgICB9LFxyXG4gICAgcHJveHk6IHtcclxuICAgICAgaG9zdDoge1xyXG4gICAgICAgIHZhbHVlOiBudWxsLFxyXG4gICAgICAgIHR5cGVzOiBbJ3N0cmluZycsICdudWxsJ10sXHJcbiAgICAgICAgZW52TGluazogJ1NFUlZFUl9QUk9YWV9IT1NUJyxcclxuICAgICAgICBjbGlOYW1lOiAncHJveHlIb3N0JyxcclxuICAgICAgICBkZXNjcmlwdGlvbjogJ0hvc3Qgb2YgdGhlIHByb3h5IHNlcnZlciwgaWYgYXBwbGljYWJsZScsXHJcbiAgICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgICAgdHlwZTogJ3RleHQnXHJcbiAgICAgICAgfVxyXG4gICAgICB9LFxyXG4gICAgICBwb3J0OiB7XHJcbiAgICAgICAgdmFsdWU6IG51bGwsXHJcbiAgICAgICAgdHlwZXM6IFsnbnVtYmVyJywgJ251bGwnXSxcclxuICAgICAgICBlbnZMaW5rOiAnU0VSVkVSX1BST1hZX1BPUlQnLFxyXG4gICAgICAgIGNsaU5hbWU6ICdwcm94eVBvcnQnLFxyXG4gICAgICAgIGRlc2NyaXB0aW9uOiAnUG9ydCBvZiB0aGUgcHJveHkgc2VydmVyLCBpZiBhcHBsaWNhYmxlJyxcclxuICAgICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgICB0eXBlOiAnbnVtYmVyJ1xyXG4gICAgICAgIH1cclxuICAgICAgfSxcclxuICAgICAgdGltZW91dDoge1xyXG4gICAgICAgIHZhbHVlOiA1MDAwLFxyXG4gICAgICAgIHR5cGVzOiBbJ251bWJlciddLFxyXG4gICAgICAgIGVudkxpbms6ICdTRVJWRVJfUFJPWFlfVElNRU9VVCcsXHJcbiAgICAgICAgY2xpTmFtZTogJ3Byb3h5VGltZW91dCcsXHJcbiAgICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgICAnVGltZW91dCBpbiBtaWxsaXNlY29uZHMgZm9yIHRoZSBwcm94eSBzZXJ2ZXIsIGlmIGFwcGxpY2FibGUnLFxyXG4gICAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICAgIHR5cGU6ICdudW1iZXInXHJcbiAgICAgICAgfVxyXG4gICAgICB9XHJcbiAgICB9LFxyXG4gICAgcmF0ZUxpbWl0aW5nOiB7XHJcbiAgICAgIGVuYWJsZToge1xyXG4gICAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgICB0eXBlczogWydib29sZWFuJ10sXHJcbiAgICAgICAgZW52TGluazogJ1NFUlZFUl9SQVRFX0xJTUlUSU5HX0VOQUJMRScsXHJcbiAgICAgICAgY2xpTmFtZTogJ2VuYWJsZVJhdGVMaW1pdGluZycsXHJcbiAgICAgICAgZGVzY3JpcHRpb246ICdFbmFibGVzIG9yIGRpc2FibGVzIHJhdGUgbGltaXRpbmcgb24gdGhlIHNlcnZlcicsXHJcbiAgICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgICAgdHlwZTogJ3RvZ2dsZSdcclxuICAgICAgICB9XHJcbiAgICAgIH0sXHJcbiAgICAgIG1heFJlcXVlc3RzOiB7XHJcbiAgICAgICAgdmFsdWU6IDEwLFxyXG4gICAgICAgIHR5cGVzOiBbJ251bWJlciddLFxyXG4gICAgICAgIGVudkxpbms6ICdTRVJWRVJfUkFURV9MSU1JVElOR19NQVhfUkVRVUVTVFMnLFxyXG4gICAgICAgIGxlZ2FjeU5hbWU6ICdyYXRlTGltaXQnLFxyXG4gICAgICAgIGRlc2NyaXB0aW9uOiAnTWF4aW11bSBudW1iZXIgb2YgcmVxdWVzdHMgYWxsb3dlZCBwZXIgbWludXRlJyxcclxuICAgICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgICB0eXBlOiAnbnVtYmVyJ1xyXG4gICAgICAgIH1cclxuICAgICAgfSxcclxuICAgICAgd2luZG93OiB7XHJcbiAgICAgICAgdmFsdWU6IDEsXHJcbiAgICAgICAgdHlwZXM6IFsnbnVtYmVyJ10sXHJcbiAgICAgICAgZW52TGluazogJ1NFUlZFUl9SQVRFX0xJTUlUSU5HX1dJTkRPVycsXHJcbiAgICAgICAgZGVzY3JpcHRpb246ICdUaW1lIHdpbmRvdyBpbiBtaW51dGVzIGZvciByYXRlIGxpbWl0aW5nJyxcclxuICAgICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgICB0eXBlOiAnbnVtYmVyJ1xyXG4gICAgICAgIH1cclxuICAgICAgfSxcclxuICAgICAgZGVsYXk6IHtcclxuICAgICAgICB2YWx1ZTogMCxcclxuICAgICAgICB0eXBlczogWydudW1iZXInXSxcclxuICAgICAgICBlbnZMaW5rOiAnU0VSVkVSX1JBVEVfTElNSVRJTkdfREVMQVknLFxyXG4gICAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICAgJ0RlbGF5IGR1cmF0aW9uIGJldHdlZW4gc3VjY2Vzc2l2ZSByZXF1ZXN0cyBiZWZvcmUgcmVhY2hpbmcgdGhlIGxpbWl0JyxcclxuICAgICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgICB0eXBlOiAnbnVtYmVyJ1xyXG4gICAgICAgIH1cclxuICAgICAgfSxcclxuICAgICAgdHJ1c3RQcm94eToge1xyXG4gICAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgICB0eXBlczogWydib29sZWFuJ10sXHJcbiAgICAgICAgZW52TGluazogJ1NFUlZFUl9SQVRFX0xJTUlUSU5HX1RSVVNUX1BST1hZJyxcclxuICAgICAgICBkZXNjcmlwdGlvbjogJ1NldCB0byB0cnVlIGlmIHRoZSBzZXJ2ZXIgaXMgYmVoaW5kIGEgbG9hZCBiYWxhbmNlcicsXHJcbiAgICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgICAgdHlwZTogJ3RvZ2dsZSdcclxuICAgICAgICB9XHJcbiAgICAgIH0sXHJcbiAgICAgIHNraXBLZXk6IHtcclxuICAgICAgICB2YWx1ZTogbnVsbCxcclxuICAgICAgICB0eXBlczogWydzdHJpbmcnLCAnbnVsbCddLFxyXG4gICAgICAgIGVudkxpbms6ICdTRVJWRVJfUkFURV9MSU1JVElOR19TS0lQX0tFWScsXHJcbiAgICAgICAgZGVzY3JpcHRpb246ICdLZXkgdG8gYnlwYXNzIHRoZSByYXRlIGxpbWl0ZXIsIHVzZWQgd2l0aCBgc2tpcFRva2VuYCcsXHJcbiAgICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgICAgdHlwZTogJ3RleHQnXHJcbiAgICAgICAgfVxyXG4gICAgICB9LFxyXG4gICAgICBza2lwVG9rZW46IHtcclxuICAgICAgICB2YWx1ZTogbnVsbCxcclxuICAgICAgICB0eXBlczogWydzdHJpbmcnLCAnbnVsbCddLFxyXG4gICAgICAgIGVudkxpbms6ICdTRVJWRVJfUkFURV9MSU1JVElOR19TS0lQX1RPS0VOJyxcclxuICAgICAgICBkZXNjcmlwdGlvbjogJ1Rva2VuIHRvIGJ5cGFzcyB0aGUgcmF0ZSBsaW1pdGVyLCB1c2VkIHdpdGggYHNraXBLZXlgJyxcclxuICAgICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgICB0eXBlOiAndGV4dCdcclxuICAgICAgICB9XHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICBzc2w6IHtcclxuICAgICAgZW5hYmxlOiB7XHJcbiAgICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICAgIHR5cGVzOiBbJ2Jvb2xlYW4nXSxcclxuICAgICAgICBlbnZMaW5rOiAnU0VSVkVSX1NTTF9FTkFCTEUnLFxyXG4gICAgICAgIGNsaU5hbWU6ICdlbmFibGVTc2wnLFxyXG4gICAgICAgIGRlc2NyaXB0aW9uOiAnRW5hYmxlcyBvciBkaXNhYmxlcyBTU0wgcHJvdG9jb2wnLFxyXG4gICAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICAgIHR5cGU6ICd0b2dnbGUnXHJcbiAgICAgICAgfVxyXG4gICAgICB9LFxyXG4gICAgICBmb3JjZToge1xyXG4gICAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgICB0eXBlczogWydib29sZWFuJ10sXHJcbiAgICAgICAgZW52TGluazogJ1NFUlZFUl9TU0xfRk9SQ0UnLFxyXG4gICAgICAgIGNsaU5hbWU6ICdzc2xGb3JjZScsXHJcbiAgICAgICAgbGVnYWN5TmFtZTogJ3NzbE9ubHknLFxyXG4gICAgICAgIGRlc2NyaXB0aW9uOiAnRm9yY2VzIHRoZSBzZXJ2ZXIgdG8gdXNlIEhUVFBTIG9ubHkgd2hlbiB0cnVlJyxcclxuICAgICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgICB0eXBlOiAndG9nZ2xlJ1xyXG4gICAgICAgIH1cclxuICAgICAgfSxcclxuICAgICAgcG9ydDoge1xyXG4gICAgICAgIHZhbHVlOiA0NDMsXHJcbiAgICAgICAgdHlwZXM6IFsnbnVtYmVyJ10sXHJcbiAgICAgICAgZW52TGluazogJ1NFUlZFUl9TU0xfUE9SVCcsXHJcbiAgICAgICAgY2xpTmFtZTogJ3NzbFBvcnQnLFxyXG4gICAgICAgIGRlc2NyaXB0aW9uOiAnUG9ydCBmb3IgdGhlIFNTTCBzZXJ2ZXInLFxyXG4gICAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICAgIHR5cGU6ICdudW1iZXInXHJcbiAgICAgICAgfVxyXG4gICAgICB9LFxyXG4gICAgICBjZXJ0UGF0aDoge1xyXG4gICAgICAgIHZhbHVlOiBudWxsLFxyXG4gICAgICAgIHR5cGVzOiBbJ3N0cmluZycsICdudWxsJ10sXHJcbiAgICAgICAgZW52TGluazogJ1NFUlZFUl9TU0xfQ0VSVF9QQVRIJyxcclxuICAgICAgICBjbGlOYW1lOiAnc3NsQ2VydFBhdGgnLFxyXG4gICAgICAgIGxlZ2FjeU5hbWU6ICdzc2xQYXRoJyxcclxuICAgICAgICBkZXNjcmlwdGlvbjogJ1BhdGggdG8gdGhlIFNTTCBjZXJ0aWZpY2F0ZS9rZXkgZmlsZScsXHJcbiAgICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgICAgdHlwZTogJ3RleHQnXHJcbiAgICAgICAgfVxyXG4gICAgICB9XHJcbiAgICB9XHJcbiAgfSxcclxuICBwb29sOiB7XHJcbiAgICBtaW5Xb3JrZXJzOiB7XHJcbiAgICAgIHZhbHVlOiA0LFxyXG4gICAgICB0eXBlczogWydudW1iZXInXSxcclxuICAgICAgZW52TGluazogJ1BPT0xfTUlOX1dPUktFUlMnLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ01pbmltdW0gYW5kIGluaXRpYWwgbnVtYmVyIG9mIHBvb2wgd29ya2VycyB0byBzcGF3bicsXHJcbiAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICB0eXBlOiAnbnVtYmVyJ1xyXG4gICAgICB9XHJcbiAgICB9LFxyXG4gICAgbWF4V29ya2Vyczoge1xyXG4gICAgICB2YWx1ZTogOCxcclxuICAgICAgdHlwZXM6IFsnbnVtYmVyJ10sXHJcbiAgICAgIGVudkxpbms6ICdQT09MX01BWF9XT1JLRVJTJyxcclxuICAgICAgbGVnYWN5TmFtZTogJ3dvcmtlcnMnLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ01heGltdW0gbnVtYmVyIG9mIHBvb2wgd29ya2VycyB0byBzcGF3bicsXHJcbiAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICB0eXBlOiAnbnVtYmVyJ1xyXG4gICAgICB9XHJcbiAgICB9LFxyXG4gICAgd29ya0xpbWl0OiB7XHJcbiAgICAgIHZhbHVlOiA0MCxcclxuICAgICAgdHlwZXM6IFsnbnVtYmVyJ10sXHJcbiAgICAgIGVudkxpbms6ICdQT09MX1dPUktfTElNSVQnLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ051bWJlciBvZiB0YXNrcyBhIHdvcmtlciBjYW4gaGFuZGxlIGJlZm9yZSByZXN0YXJ0aW5nJyxcclxuICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgIHR5cGU6ICdudW1iZXInXHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICBhY3F1aXJlVGltZW91dDoge1xyXG4gICAgICB2YWx1ZTogNTAwMCxcclxuICAgICAgdHlwZXM6IFsnbnVtYmVyJ10sXHJcbiAgICAgIGVudkxpbms6ICdQT09MX0FDUVVJUkVfVElNRU9VVCcsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnVGltZW91dCBpbiBtaWxsaXNlY29uZHMgZm9yIGFjcXVpcmluZyBhIHJlc291cmNlJyxcclxuICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgIHR5cGU6ICdudW1iZXInXHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICBjcmVhdGVUaW1lb3V0OiB7XHJcbiAgICAgIHZhbHVlOiA1MDAwLFxyXG4gICAgICB0eXBlczogWydudW1iZXInXSxcclxuICAgICAgZW52TGluazogJ1BPT0xfQ1JFQVRFX1RJTUVPVVQnLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ1RpbWVvdXQgaW4gbWlsbGlzZWNvbmRzIGZvciBjcmVhdGluZyBhIHJlc291cmNlJyxcclxuICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgIHR5cGU6ICdudW1iZXInXHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICBkZXN0cm95VGltZW91dDoge1xyXG4gICAgICB2YWx1ZTogNTAwMCxcclxuICAgICAgdHlwZXM6IFsnbnVtYmVyJ10sXHJcbiAgICAgIGVudkxpbms6ICdQT09MX0RFU1RST1lfVElNRU9VVCcsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnVGltZW91dCBpbiBtaWxsaXNlY29uZHMgZm9yIGRlc3Ryb3lpbmcgYSByZXNvdXJjZScsXHJcbiAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICB0eXBlOiAnbnVtYmVyJ1xyXG4gICAgICB9XHJcbiAgICB9LFxyXG4gICAgaWRsZVRpbWVvdXQ6IHtcclxuICAgICAgdmFsdWU6IDMwMDAwLFxyXG4gICAgICB0eXBlczogWydudW1iZXInXSxcclxuICAgICAgZW52TGluazogJ1BPT0xfSURMRV9USU1FT1VUJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdUaW1lb3V0IGluIG1pbGxpc2Vjb25kcyBmb3IgZGVzdHJveWluZyBpZGxlIHJlc291cmNlcycsXHJcbiAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICB0eXBlOiAnbnVtYmVyJ1xyXG4gICAgICB9XHJcbiAgICB9LFxyXG4gICAgY3JlYXRlUmV0cnlJbnRlcnZhbDoge1xyXG4gICAgICB2YWx1ZTogMjAwLFxyXG4gICAgICB0eXBlczogWydudW1iZXInXSxcclxuICAgICAgZW52TGluazogJ1BPT0xfQ1JFQVRFX1JFVFJZX0lOVEVSVkFMJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ0ludGVydmFsIGluIG1pbGxpc2Vjb25kcyBiZWZvcmUgcmV0cnlpbmcgcmVzb3VyY2UgY3JlYXRpb24gb24gZmFpbHVyZScsXHJcbiAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICB0eXBlOiAnbnVtYmVyJ1xyXG4gICAgICB9XHJcbiAgICB9LFxyXG4gICAgcmVhcGVySW50ZXJ2YWw6IHtcclxuICAgICAgdmFsdWU6IDEwMDAsXHJcbiAgICAgIHR5cGVzOiBbJ251bWJlciddLFxyXG4gICAgICBlbnZMaW5rOiAnUE9PTF9SRUFQRVJfSU5URVJWQUwnLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnSW50ZXJ2YWwgaW4gbWlsbGlzZWNvbmRzIHRvIGNoZWNrIGFuZCBkZXN0cm95IGlkbGUgcmVzb3VyY2VzJyxcclxuICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgIHR5cGU6ICdudW1iZXInXHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICBiZW5jaG1hcmtpbmc6IHtcclxuICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICB0eXBlczogWydib29sZWFuJ10sXHJcbiAgICAgIGVudkxpbms6ICdQT09MX0JFTkNITUFSS0lORycsXHJcbiAgICAgIGNsaU5hbWU6ICdwb29sQmVuY2htYXJraW5nJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdTaG93cyBzdGF0aXN0aWNzIGZvciB0aGUgcG9vbCBvZiByZXNvdXJjZXMnLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ3RvZ2dsZSdcclxuICAgICAgfVxyXG4gICAgfVxyXG4gIH0sXHJcbiAgbG9nZ2luZzoge1xyXG4gICAgbGV2ZWw6IHtcclxuICAgICAgdmFsdWU6IDQsXHJcbiAgICAgIHR5cGVzOiBbJ251bWJlciddLFxyXG4gICAgICBlbnZMaW5rOiAnTE9HR0lOR19MRVZFTCcsXHJcbiAgICAgIGNsaU5hbWU6ICdsb2dMZXZlbCcsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnTG9nZ2luZyB2ZXJib3NpdHkgbGV2ZWwnLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgICAgcm91bmQ6IDAsXHJcbiAgICAgICAgbWluOiAwLFxyXG4gICAgICAgIG1heDogNVxyXG4gICAgICB9XHJcbiAgICB9LFxyXG4gICAgZmlsZToge1xyXG4gICAgICB2YWx1ZTogJ2hpZ2hjaGFydHMtZXhwb3J0LXNlcnZlci5sb2cnLFxyXG4gICAgICB0eXBlczogWydzdHJpbmcnXSxcclxuICAgICAgZW52TGluazogJ0xPR0dJTkdfRklMRScsXHJcbiAgICAgIGNsaU5hbWU6ICdsb2dGaWxlJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ0xvZyBmaWxlIG5hbWUuIFJlcXVpcmVzIGBsb2dUb0ZpbGVgIGFuZCBgbG9nRGVzdGAgdG8gYmUgc2V0JyxcclxuICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgIHR5cGU6ICd0ZXh0J1xyXG4gICAgICB9XHJcbiAgICB9LFxyXG4gICAgZGVzdDoge1xyXG4gICAgICB2YWx1ZTogJ2xvZycsXHJcbiAgICAgIHR5cGVzOiBbJ3N0cmluZyddLFxyXG4gICAgICBlbnZMaW5rOiAnTE9HR0lOR19ERVNUJyxcclxuICAgICAgY2xpTmFtZTogJ2xvZ0Rlc3QnLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ1BhdGggdG8gc3RvcmUgbG9nIGZpbGVzLiBSZXF1aXJlcyBgbG9nVG9GaWxlYCB0byBiZSBzZXQnLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ3RleHQnXHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICB0b0NvbnNvbGU6IHtcclxuICAgICAgdmFsdWU6IHRydWUsXHJcbiAgICAgIHR5cGVzOiBbJ2Jvb2xlYW4nXSxcclxuICAgICAgZW52TGluazogJ0xPR0dJTkdfVE9fQ09OU09MRScsXHJcbiAgICAgIGNsaU5hbWU6ICdsb2dUb0NvbnNvbGUnLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ0VuYWJsZXMgb3IgZGlzYWJsZXMgY29uc29sZSBsb2dnaW5nJyxcclxuICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgIHR5cGU6ICd0b2dnbGUnXHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICB0b0ZpbGU6IHtcclxuICAgICAgdmFsdWU6IHRydWUsXHJcbiAgICAgIHR5cGVzOiBbJ2Jvb2xlYW4nXSxcclxuICAgICAgZW52TGluazogJ0xPR0dJTkdfVE9fRklMRScsXHJcbiAgICAgIGNsaU5hbWU6ICdsb2dUb0ZpbGUnLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ0VuYWJsZXMgb3IgZGlzYWJsZXMgbG9nZ2luZyB0byBhIGZpbGUnLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ3RvZ2dsZSdcclxuICAgICAgfVxyXG4gICAgfVxyXG4gIH0sXHJcbiAgdWk6IHtcclxuICAgIGVuYWJsZToge1xyXG4gICAgICB2YWx1ZTogZmFsc2UsXHJcbiAgICAgIHR5cGVzOiBbJ2Jvb2xlYW4nXSxcclxuICAgICAgZW52TGluazogJ1VJX0VOQUJMRScsXHJcbiAgICAgIGNsaU5hbWU6ICdlbmFibGVVaScsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnRW5hYmxlcyBvciBkaXNhYmxlcyB0aGUgVUkgZm9yIHRoZSBleHBvcnQgc2VydmVyJyxcclxuICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgIHR5cGU6ICd0b2dnbGUnXHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICByb3V0ZToge1xyXG4gICAgICB2YWx1ZTogJy8nLFxyXG4gICAgICB0eXBlczogWydzdHJpbmcnXSxcclxuICAgICAgZW52TGluazogJ1VJX1JPVVRFJyxcclxuICAgICAgY2xpTmFtZTogJ3VpUm91dGUnLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ1RoZSBlbmRwb2ludCByb3V0ZSBmb3IgdGhlIFVJJyxcclxuICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgIHR5cGU6ICd0ZXh0J1xyXG4gICAgICB9XHJcbiAgICB9XHJcbiAgfSxcclxuICBvdGhlcjoge1xyXG4gICAgbm9kZUVudjoge1xyXG4gICAgICB2YWx1ZTogJ3Byb2R1Y3Rpb24nLFxyXG4gICAgICB0eXBlczogWydzdHJpbmcnXSxcclxuICAgICAgZW52TGluazogJ09USEVSX05PREVfRU5WJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdUaGUgTm9kZS5qcyBlbnZpcm9ubWVudCB0eXBlJyxcclxuICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgIHR5cGU6ICd0ZXh0J1xyXG4gICAgICB9XHJcbiAgICB9LFxyXG4gICAgbGlzdGVuVG9Qcm9jZXNzRXhpdHM6IHtcclxuICAgICAgdmFsdWU6IHRydWUsXHJcbiAgICAgIHR5cGVzOiBbJ2Jvb2xlYW4nXSxcclxuICAgICAgZW52TGluazogJ09USEVSX0xJU1RFTl9UT19QUk9DRVNTX0VYSVRTJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdXaGV0aGVyIG9yIG5vdCB0byBhdHRhY2ggcHJvY2Vzcy5leGl0IGhhbmRsZXJzJyxcclxuICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgIHR5cGU6ICd0b2dnbGUnXHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICBub0xvZ286IHtcclxuICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICB0eXBlczogWydib29sZWFuJ10sXHJcbiAgICAgIGVudkxpbms6ICdPVEhFUl9OT19MT0dPJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdEaXNwbGF5IG9yIHNraXAgcHJpbnRpbmcgdGhlIGxvZ28gb24gc3RhcnR1cCcsXHJcbiAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICB0eXBlOiAndG9nZ2xlJ1xyXG4gICAgICB9XHJcbiAgICB9LFxyXG4gICAgaGFyZFJlc2V0UGFnZToge1xyXG4gICAgICB2YWx1ZTogZmFsc2UsXHJcbiAgICAgIHR5cGVzOiBbJ2Jvb2xlYW4nXSxcclxuICAgICAgZW52TGluazogJ09USEVSX0hBUkRfUkVTRVRfUEFHRScsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnV2hldGhlciBvciBub3QgdG8gcmVzZXQgdGhlIHBhZ2UgY29udGVudCBlbnRpcmVseScsXHJcbiAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICB0eXBlOiAndG9nZ2xlJ1xyXG4gICAgICB9XHJcbiAgICB9LFxyXG4gICAgYnJvd3NlclNoZWxsTW9kZToge1xyXG4gICAgICB2YWx1ZTogdHJ1ZSxcclxuICAgICAgdHlwZXM6IFsnYm9vbGVhbiddLFxyXG4gICAgICBlbnZMaW5rOiAnT1RIRVJfQlJPV1NFUl9TSEVMTF9NT0RFJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdXaGV0aGVyIG9yIG5vdCB0byBzZXQgdGhlIGJyb3dzZXIgdG8gcnVuIGluIHNoZWxsIG1vZGUnLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ3RvZ2dsZSdcclxuICAgICAgfVxyXG4gICAgfSxcclxuICAgIHZhbGlkYXRpb246IHtcclxuICAgICAgdmFsdWU6IHRydWUsXHJcbiAgICAgIHR5cGVzOiBbJ2Jvb2xlYW4nXSxcclxuICAgICAgZW52TGluazogJ09USEVSX1ZBTElEQVRJT04nLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ1doZXRoZXIgb3Igbm90IHRvIGVuYWJsZSB2YWxpZGF0aW9uIG9mIG9wdGlvbnMgdHlwZXMnLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ3RvZ2dsZSdcclxuICAgICAgfVxyXG4gICAgfVxyXG4gIH0sXHJcbiAgZGVidWc6IHtcclxuICAgIGVuYWJsZToge1xyXG4gICAgICB2YWx1ZTogZmFsc2UsXHJcbiAgICAgIHR5cGVzOiBbJ2Jvb2xlYW4nXSxcclxuICAgICAgZW52TGluazogJ0RFQlVHX0VOQUJMRScsXHJcbiAgICAgIGNsaU5hbWU6ICdlbmFibGVEZWJ1ZycsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnRW5hYmxlcyBvciBkaXNhYmxlcyBkZWJ1ZyBtb2RlIGZvciB0aGUgdW5kZXJseWluZyBicm93c2VyJyxcclxuICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgIHR5cGU6ICd0b2dnbGUnXHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICBoZWFkbGVzczoge1xyXG4gICAgICB2YWx1ZTogZmFsc2UsXHJcbiAgICAgIHR5cGVzOiBbJ2Jvb2xlYW4nXSxcclxuICAgICAgZW52TGluazogJ0RFQlVHX0hFQURMRVNTJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ1doZXRoZXIgb3Igbm90IHRvIHNldCB0aGUgYnJvd3NlciB0byBydW4gaW4gaGVhZGxlc3MgbW9kZSBkdXJpbmcgZGVidWdnaW5nJyxcclxuICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgIHR5cGU6ICd0b2dnbGUnXHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICBkZXZ0b29sczoge1xyXG4gICAgICB2YWx1ZTogZmFsc2UsXHJcbiAgICAgIHR5cGVzOiBbJ2Jvb2xlYW4nXSxcclxuICAgICAgZW52TGluazogJ0RFQlVHX0RFVlRPT0xTJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdFbmFibGVzIG9yIGRpc2FibGVzIERldlRvb2xzIGluIGhlYWRmdWwgbW9kZScsXHJcbiAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICB0eXBlOiAndG9nZ2xlJ1xyXG4gICAgICB9XHJcbiAgICB9LFxyXG4gICAgbGlzdGVuVG9Db25zb2xlOiB7XHJcbiAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgdHlwZXM6IFsnYm9vbGVhbiddLFxyXG4gICAgICBlbnZMaW5rOiAnREVCVUdfTElTVEVOX1RPX0NPTlNPTEUnLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnRW5hYmxlcyBvciBkaXNhYmxlcyBsaXN0ZW5pbmcgdG8gY29uc29sZSBtZXNzYWdlcyBmcm9tIHRoZSBicm93c2VyJyxcclxuICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgIHR5cGU6ICd0b2dnbGUnXHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICBkdW1waW86IHtcclxuICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICB0eXBlczogWydib29sZWFuJ10sXHJcbiAgICAgIGVudkxpbms6ICdERUJVR19EVU1QSU8nLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnUmVkaXJlY3RzIG9yIG5vdCBicm93c2VyIHN0ZG91dCBhbmQgc3RkZXJyIHRvIHByb2Nlc3Muc3Rkb3V0IGFuZCBwcm9jZXNzLnN0ZGVycicsXHJcbiAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICB0eXBlOiAndG9nZ2xlJ1xyXG4gICAgICB9XHJcbiAgICB9LFxyXG4gICAgc2xvd01vOiB7XHJcbiAgICAgIHZhbHVlOiAwLFxyXG4gICAgICB0eXBlczogWydudW1iZXInXSxcclxuICAgICAgZW52TGluazogJ0RFQlVHX1NMT1dfTU8nLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ0RlbGF5cyBQdXBwZXRlZXIgb3BlcmF0aW9ucyBieSB0aGUgc3BlY2lmaWVkIG1pbGxpc2Vjb25kcycsXHJcbiAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICB0eXBlOiAnbnVtYmVyJ1xyXG4gICAgICB9XHJcbiAgICB9LFxyXG4gICAgZGVidWdnaW5nUG9ydDoge1xyXG4gICAgICB2YWx1ZTogOTIyMixcclxuICAgICAgdHlwZXM6IFsnbnVtYmVyJ10sXHJcbiAgICAgIGVudkxpbms6ICdERUJVR19ERUJVR0dJTkdfUE9SVCcsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnUG9ydCB1c2VkIGZvciBkZWJ1Z2dpbmcnLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ251bWJlcidcclxuICAgICAgfVxyXG4gICAgfVxyXG4gIH1cclxufTtcclxuXHJcbi8vIFByb3BlcnRpZXMgbmVzdGluZyBsZXZlbCBvZiBhbGwgb3B0aW9uc1xyXG5leHBvcnQgY29uc3QgbmVzdGVkUHJvcHMgPSBfY3JlYXRlTmVzdGVkUHJvcHMoZGVmYXVsdENvbmZpZyk7XHJcblxyXG4vLyBQcm9wZXJ0aWVzIG5hbWVzIHRoYXQgc2hvdWxkIG5vdCBiZSByZWN1cnNpdmVseSBtZXJnZWRcclxuZXhwb3J0IGNvbnN0IGFic29sdXRlUHJvcHMgPSBfY3JlYXRlQWJzb2x1dGVQcm9wcyhkZWZhdWx0Q29uZmlnKTtcclxuXHJcbi8qKlxyXG4gKiBSZWN1cnNpdmVseSBnZW5lcmF0ZXMgYSBtYXBwaW5nIG9mIG5lc3RlZCBhcmd1bWVudCBjaGFpbnMgZnJvbSBhIG5lc3RlZFxyXG4gKiBjb25maWcgb2JqZWN0LiBUaGlzIGZ1bmN0aW9uIHRyYXZlcnNlcyBhIG5lc3RlZCBvYmplY3QgYW5kIGNyZWF0ZXMgYSBtYXBwaW5nXHJcbiAqIHdoZXJlIGVhY2gga2V5IGlzIGFuIGFyZ3VtZW50IG5hbWUgKGVpdGhlciBmcm9tIGBjbGlOYW1lYCwgYGxlZ2FjeU5hbWVgLFxyXG4gKiBvciB0aGUgb3JpZ2luYWwga2V5KSBhbmQgZWFjaCB2YWx1ZSBpcyBhIHN0cmluZyByZXByZXNlbnRpbmcgdGhlIGNoYWluXHJcbiAqIG9mIG5lc3RlZCBwcm9wZXJ0aWVzIGxlYWRpbmcgdG8gdGhhdCBhcmd1bWVudC5cclxuICpcclxuICogQGZ1bmN0aW9uIF9jcmVhdGVOZXN0ZWRQcm9wc1xyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gY29uZmlnIC0gVGhlIGNvbmZpZ3VyYXRpb24gb2JqZWN0LlxyXG4gKiBAcGFyYW0ge09iamVjdH0gW25lc3RlZFByb3BzPXt9XSAtIFRoZSBhY2N1bXVsYXRvciBvYmplY3QgZm9yIHN0b3JpbmdcclxuICogdGhlIHJlc3VsdGluZyBhcmd1bWVudHMgY2hhaW5zLiAgVGhlIGRlZmF1bHQgdmFsdWUgaXMgYW4gZW1wdHkgb2JqZWN0LlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gW3Byb3BDaGFpbj0nJ10gLSBUaGUgY3VycmVudCBjaGFpbiBvZiBuZXN0ZWQgcHJvcGVydGllcyxcclxuICogdXNlZCBpbnRlcm5hbGx5IGR1cmluZyByZWN1cnNpb24uICBUaGUgZGVmYXVsdCB2YWx1ZSBpcyBhbiBlbXB0eSBzdHJpbmcuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtPYmplY3R9IEFuIG9iamVjdCBtYXBwaW5nIGFyZ3VtZW50IG5hbWVzIHRvIHRoZWlyIGNvcnJlc3BvbmRpbmdcclxuICogbmVzdGVkIHByb3BlcnR5IGNoYWlucy5cclxuICovXHJcbmZ1bmN0aW9uIF9jcmVhdGVOZXN0ZWRQcm9wcyhjb25maWcsIG5lc3RlZFByb3BzID0ge30sIHByb3BDaGFpbiA9ICcnKSB7XHJcbiAgT2JqZWN0LmtleXMoY29uZmlnKS5mb3JFYWNoKChrZXkpID0+IHtcclxuICAgIC8vIEdldCB0aGUgc3BlY2lmaWMgc2VjdGlvblxyXG4gICAgY29uc3QgZW50cnkgPSBjb25maWdba2V5XTtcclxuXHJcbiAgICAvLyBDaGVjayBpZiB0aGVyZSBpcyBzdGlsbCBtb3JlIGRlcHRoIHRvIHRyYXZlcnNlXHJcbiAgICBpZiAodHlwZW9mIGVudHJ5LnZhbHVlID09PSAndW5kZWZpbmVkJykge1xyXG4gICAgICAvLyBSZWN1cnNlIGludG8gZGVlcGVyIGxldmVscyBvZiBuZXN0ZWQgYXJndW1lbnRzXHJcbiAgICAgIF9jcmVhdGVOZXN0ZWRQcm9wcyhlbnRyeSwgbmVzdGVkUHJvcHMsIGAke3Byb3BDaGFpbn0uJHtrZXl9YCk7XHJcbiAgICB9IGVsc2Uge1xyXG4gICAgICAvLyBDcmVhdGUgdGhlIGNoYWluIG9mIG5lc3RlZCBhcmd1bWVudHNcclxuICAgICAgbmVzdGVkUHJvcHNbZW50cnkuY2xpTmFtZSB8fCBrZXldID0gYCR7cHJvcENoYWlufS4ke2tleX1gLnN1YnN0cmluZygxKTtcclxuXHJcbiAgICAgIC8vIFN1cHBvcnQgZm9yIHRoZSBsZWdhY3ksIFBoYW50b21KUyBwcm9wZXJ0aWVzIG5hbWVzXHJcbiAgICAgIGlmIChlbnRyeS5sZWdhY3lOYW1lICE9PSB1bmRlZmluZWQpIHtcclxuICAgICAgICBuZXN0ZWRQcm9wc1tlbnRyeS5sZWdhY3lOYW1lXSA9IGAke3Byb3BDaGFpbn0uJHtrZXl9YC5zdWJzdHJpbmcoMSk7XHJcbiAgICAgIH1cclxuICAgIH1cclxuICB9KTtcclxuXHJcbiAgLy8gUmV0dXJuIHRoZSBvYmplY3Qgd2l0aCBuZXN0ZWQgYXJndW1lbnQgY2hhaW5zXHJcbiAgcmV0dXJuIG5lc3RlZFByb3BzO1xyXG59XHJcblxyXG4vKipcclxuICogUmVjdXJzaXZlbHkgZ2F0aGVycyB0aGUgbmFtZXMgb2YgcHJvcGVydGllcyBmcm9tIGEgY29uZmlndXJhdGlvbiBvYmplY3QgdGhhdFxyXG4gKiBjYW4gYmUgdHJlYXRlZCBhcyBhYnNvbHV0ZSBwcm9wZXJ0aWVzLiBUaGVzZSBwcm9wZXJ0aWVzIGhhdmUgdmFsdWVzIHRoYXRcclxuICogYXJlIG9iamVjdHMgYW5kIGRvIG5vdCBjb250YWluIGZ1cnRoZXIgbmVzdGVkIGRlcHRoIHdoZW4gbWVyZ2luZyBhbiBvYmplY3RcclxuICogY29udGFpbmluZyB0aGVzZSBvcHRpb25zLlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gX2NyZWF0ZUFic29sdXRlUHJvcHNcclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IGNvbmZpZyAtIFRoZSBjb25maWd1cmF0aW9uIG9iamVjdC5cclxuICogQHBhcmFtIHtBcnJheS48c3RyaW5nPn0gW2Fic29sdXRlUHJvcHM9W11dIC0gQW4gYXJyYXkgdG8gY29sbGVjdCB0aGUgbmFtZXNcclxuICogb2YgYWJzb2x1dGUgcHJvcGVydGllcy4gVGhlIGRlZmF1bHQgdmFsdWUgaXMgYW4gZW1wdHkgYXJyYXkuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtBcnJheS48c3RyaW5nPn0gQW4gYXJyYXkgY29udGFpbmluZyB0aGUgbmFtZXMgb2YgYWJzb2x1dGVcclxuICogcHJvcGVydGllcy5cclxuICovXHJcbmZ1bmN0aW9uIF9jcmVhdGVBYnNvbHV0ZVByb3BzKGNvbmZpZywgYWJzb2x1dGVQcm9wcyA9IFtdKSB7XHJcbiAgT2JqZWN0LmtleXMoY29uZmlnKS5mb3JFYWNoKChrZXkpID0+IHtcclxuICAgIC8vIEdldCB0aGUgc3BlY2lmaWMgc2VjdGlvblxyXG4gICAgY29uc3QgZW50cnkgPSBjb25maWdba2V5XTtcclxuXHJcbiAgICAvLyBDaGVjayBpZiB0aGVyZSBpcyBzdGlsbCBtb3JlIGRlcHRoIHRvIHRyYXZlcnNlXHJcbiAgICBpZiAodHlwZW9mIGVudHJ5LnR5cGVzID09PSAndW5kZWZpbmVkJykge1xyXG4gICAgICAvLyBSZWN1cnNlIGludG8gZGVlcGVyIGxldmVsc1xyXG4gICAgICBfY3JlYXRlQWJzb2x1dGVQcm9wcyhlbnRyeSwgYWJzb2x1dGVQcm9wcyk7XHJcbiAgICB9IGVsc2Uge1xyXG4gICAgICAvLyBJZiB0aGUgb3B0aW9uIGNhbiBiZSBhbiBvYmplY3QsIHNhdmUgaXRzIHR5cGUgaW4gdGhlIGFycmF5XHJcbiAgICAgIGlmIChlbnRyeS50eXBlcy5pbmNsdWRlcygnT2JqZWN0JykpIHtcclxuICAgICAgICBhYnNvbHV0ZVByb3BzLnB1c2goa2V5KTtcclxuICAgICAgfVxyXG4gICAgfVxyXG4gIH0pO1xyXG5cclxuICAvLyBSZXR1cm4gdGhlIGFycmF5IHdpdGggdGhlIG5hbWVzIG9mIGFic29sdXRlIHByb3BlcnRpZXNcclxuICByZXR1cm4gYWJzb2x1dGVQcm9wcztcclxufVxyXG5cclxuZXhwb3J0IGRlZmF1bHQge1xyXG4gIGRlZmF1bHRDb25maWcsXHJcbiAgbmVzdGVkUHJvcHMsXHJcbiAgYWJzb2x1dGVQcm9wc1xyXG59O1xyXG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxyXG5cclxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXHJcblxyXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNSwgSGlnaHNvZnRcclxuXHJcbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cclxuXHJcbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxyXG5cclxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxyXG5cclxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cclxuXHJcbi8qKlxyXG4gKiBAb3ZlcnZpZXcgVGhpcyBmaWxlIGhhbmRsZXMgcGFyc2luZyBhbmQgdmFsaWRhdGluZyBvcHRpb25zIGZyb20gbXVsdGlwbGVcclxuICogc291cmNlcyAodGhlIGNvbmZpZyBmaWxlLCBjdXN0b20gSlNPTiwgZW52aXJvbm1lbnQgdmFyaWFibGVzLCBDTEkgYXJndW1lbnRzLFxyXG4gKiBhbmQgcmVxdWVzdCBwYXlsb2FkKSB1c2luZyB0aGUgJ3pvZCcgbGlicmFyeS5cclxuICpcclxuICogRW52aXJvbm1lbnQgdmFyaWFibGVzIGFyZSBwYXJzZWQgYW5kIHZhbGlkYXRlZCBvbmx5IG9uY2UgYXQgYXBwbGljYXRpb25cclxuICogc3RhcnR1cCwgYW5kIHRoZSB2YWxpZGF0ZWQgcmVzdWx0cyBhcmUgZXhwb3J0ZWQgYXMgYGVudnNgIGZvciB1c2UgdGhyb3VnaG91dFxyXG4gKiB0aGUgYXBwbGljYXRpb24uXHJcbiAqXHJcbiAqIE9wdGlvbnMgZnJvbSBvdGhlciBzb3VyY2VzLCBob3dldmVyLCBhcmUgcGFyc2VkIGFuZCB2YWxpZGF0ZWQgb24gZGVtYW5kLFxyXG4gKiBlYWNoIHRpbWUgYW4gZXhwb3J0IGlzIGF0dGVtcHRlZC5cclxuICovXHJcblxyXG5pbXBvcnQgZG90ZW52IGZyb20gJ2RvdGVudic7XHJcbmltcG9ydCB7IHogfSBmcm9tICd6b2QnO1xyXG5cclxuaW1wb3J0IHsgZGVmYXVsdENvbmZpZyB9IGZyb20gJy4vc2NoZW1hcy9jb25maWcuanMnO1xyXG5cclxuLy8gTG9hZCB0aGUgLmVudiBpbnRvIGVudmlyb25tZW50IHZhcmlhYmxlc1xyXG5kb3RlbnYuY29uZmlnKCk7XHJcblxyXG4vLyBHZXQgc2NyaXB0cyBuYW1lcyBvZiBlYWNoIGNhdGVnb3J5IGZyb20gdGhlIGRlZmF1bHQgY29uZmlnXHJcbmNvbnN0IHsgY29yZVNjcmlwdHMsIG1vZHVsZVNjcmlwdHMsIGluZGljYXRvclNjcmlwdHMgfSA9XHJcbiAgZGVmYXVsdENvbmZpZy5oaWdoY2hhcnRzO1xyXG5cclxuLy8gU2V0cyB0aGUgY3VzdG9tIGVycm9yIG1hcCBnbG9iYWxseVxyXG56LnNldEVycm9yTWFwKF9jdXN0b21FcnJvck1hcCk7XHJcblxyXG4vKipcclxuICogT2JqZWN0IGNvbnRhaW5pbmcgY3VzdG9tIGdlbmVyYWwgdmFsaWRhdG9ycyBhbmQgcGFyc2VycyB0byBhdm9pZCByZXBldGl0aW9uXHJcbiAqIGluIHNjaGVtYSBvYmplY3RzLiBBbGwgdmFsaWRhdG9ycyBhcHBseSB0byB2YWx1ZXMgZnJvbSB2YXJpb3VzIHNvdXJjZXMsXHJcbiAqIGluY2x1ZGluZyB0aGUgZGVmYXVsdCBjb25maWcgZmlsZSwgYSBjdXN0b20gSlNPTiBmaWxlIGxvYWRlZCB3aXRoIHRoZSBvcHRpb25cclxuICogY2FsbGVkIGBsb2FkQ29uZmlnYCwgdGhlIC5lbnYgZmlsZSwgQ0xJIGFyZ3VtZW50cywgYW5kIHRoZSByZXF1ZXN0IHBheWxvYWQuXHJcbiAqIFRoZSBgc3RyaWN0Q2hlY2tgIGZsYWcgZW5hYmxlcyBzdHJpY3RlciB2YWxpZGF0aW9uIGFuZCBwYXJzaW5nIHJ1bGVzLiBUaGlzXHJcbiAqIGZsYWcgaXMgc2V0IHRvIGZhbHNlIGZvciB2YWx1ZXMgdGhhdCBjb21lIGZyb20gdGhlIC5lbnYgZmlsZSBvciBDTEkgYXJndW1lbnRzXHJcbiAqIGJlY2F1c2UgdGhleSBhcmUgcHJvdmlkZWQgYXMgc3RyaW5ncyBhbmQgbmVlZCB0byBiZSBwYXJzZWQgYWNjb3JkaW5nbHkgZmlyc3QuXHJcbiAqL1xyXG5jb25zdCB2ID0ge1xyXG4gIC8qKlxyXG4gICAqIFRoZSBgYm9vbGVhbmAgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbCBzdHJpY3RlclxyXG4gICAqIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoYXQ6XHJcbiAgICpcclxuICAgKiAtIFdoZW4gYHN0cmljdENoZWNrYCBpcyB0cnVlLCB0aGUgc2NoZW1hIHdpbGwgYWNjZXB0IHZhbHVlcyBhcmUgdHJ1ZVxyXG4gICAqIGFuZCBmYWxzZSBhbmQgdGhlIHNjaGVtYSB3aWxsIHZhbGlkYXRlIGFnYWluc3QgdGhlIGRlZmF1bHQgYm9vbGVhblxyXG4gICAqIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIC0gV2hlbiBgc3RyaWN0Q2hlY2tgIGlzIGZhbHNlLCB0aGUgc2NoZW1hIHdpbGwgYWNjZXB0IHZhbHVlcyBhcmUgdHJ1ZSxcclxuICAgKiBmYWxzZSwgbnVsbCwgJ3RydWUnLCAnMScsICdmYWxzZScsICcwJywgJ3VuZGVmaW5lZCcsICdudWxsJywgYW5kICcnLlxyXG4gICAqIFRoZSBzdHJpbmdzICd1bmRlZmluZWQnLCAnbnVsbCcsIGFuZCAnJyB3aWxsIGJlIHRyYW5zZm9ybWVkIHRvIG51bGwsXHJcbiAgICogdGhlIHN0cmluZyAndHJ1ZScgd2lsbCBiZSB0cmFuc2Zvcm1lZCB0byB0aGUgYm9vbGVhbiB2YWx1ZSB0cnVlLFxyXG4gICAqIGFuZCAnZmFsc2UnIHdpbGwgYmUgdHJhbnNmb3JtZWQgdG8gdGhlIGJvb2xlYW4gdmFsdWUgZmFsc2UuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gYm9vbGVhblxyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nIGJvb2xlYW4gdmFsdWVzLlxyXG4gICAqL1xyXG4gIGJvb2xlYW4oc3RyaWN0Q2hlY2spIHtcclxuICAgIHJldHVybiBzdHJpY3RDaGVja1xyXG4gICAgICA/IHouYm9vbGVhbigpXHJcbiAgICAgIDogelxyXG4gICAgICAgICAgLnVuaW9uKFtcclxuICAgICAgICAgICAgelxyXG4gICAgICAgICAgICAgIC5lbnVtKFsndHJ1ZScsICcxJywgJ2ZhbHNlJywgJzAnLCAndW5kZWZpbmVkJywgJ251bGwnLCAnJ10pXHJcbiAgICAgICAgICAgICAgLnRyYW5zZm9ybSgodmFsdWUpID0+XHJcbiAgICAgICAgICAgICAgICAhWyd1bmRlZmluZWQnLCAnbnVsbCcsICcnXS5pbmNsdWRlcyh2YWx1ZSlcclxuICAgICAgICAgICAgICAgICAgPyB2YWx1ZSA9PT0gJ3RydWUnIHx8IHZhbHVlID09PSAnMSdcclxuICAgICAgICAgICAgICAgICAgOiBudWxsXHJcbiAgICAgICAgICAgICAgKSxcclxuICAgICAgICAgICAgei5ib29sZWFuKClcclxuICAgICAgICAgIF0pXHJcbiAgICAgICAgICAubnVsbGFibGUoKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYHN0cmluZ2AgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbCBzdHJpY3RlclxyXG4gICAqIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoYXQ6XHJcbiAgICpcclxuICAgKiAtIFdoZW4gYHN0cmljdENoZWNrYCBpcyB0cnVlLCB0aGUgc2NoZW1hIHdpbGwgYWNjZXB0IHRyaW1tZWQgc3RyaW5ncyBleGNlcHRcclxuICAgKiB0aGUgZm9yYmlkZGVuIHZhbHVlczogJ2ZhbHNlJywgJ3VuZGVmaW5lZCcsICdudWxsJywgYW5kICcnLlxyXG4gICAqXHJcbiAgICogLSBXaGVuIGBzdHJpY3RDaGVja2AgaXMgZmFsc2UsIHRoZSBzY2hlbWEgd2lsbCBhY2NlcHQgdHJpbW1lZCBzdHJpbmdzXHJcbiAgICogYW5kIG51bGwuIFRoZSBmb3JiaWRkZW4gdmFsdWVzOiAnZmFsc2UnLCAndW5kZWZpbmVkJywgJ251bGwnLCBhbmQgJycgd2lsbFxyXG4gICAqIGJlIHRyYW5zZm9ybWVkIHRvIG51bGwuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gc3RyaW5nXHJcbiAgICpcclxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IHN0cmljdENoZWNrIC0gRGV0ZXJtaW5lcyBpZiBzdHJpY3RlciB2YWxpZGF0aW9uIHNob3VsZFxyXG4gICAqIGJlIGFwcGxpZWQuXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9IEEgWm9kIHNjaGVtYSBvYmplY3QgZm9yIHZhbGlkYXRpbmcgc3RyaW5nIHZhbHVlcy5cclxuICAgKi9cclxuICBzdHJpbmcoc3RyaWN0Q2hlY2spIHtcclxuICAgIHJldHVybiBzdHJpY3RDaGVja1xyXG4gICAgICA/IHpcclxuICAgICAgICAgIC5zdHJpbmcoKVxyXG4gICAgICAgICAgLnRyaW0oKVxyXG4gICAgICAgICAgLnJlZmluZShcclxuICAgICAgICAgICAgKHZhbHVlKSA9PiAhWydmYWxzZScsICd1bmRlZmluZWQnLCAnbnVsbCcsICcnXS5pbmNsdWRlcyh2YWx1ZSksXHJcbiAgICAgICAgICAgIHtcclxuICAgICAgICAgICAgICBwYXJhbXM6IHtcclxuICAgICAgICAgICAgICAgIGVycm9yTWVzc2FnZTogJ1RoZSBzdHJpbmcgY29udGFpbnMgYSBmb3JiaWRkZW4gdmFsdWUnXHJcbiAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICB9XHJcbiAgICAgICAgICApXHJcbiAgICAgIDogelxyXG4gICAgICAgICAgLnN0cmluZygpXHJcbiAgICAgICAgICAudHJpbSgpXHJcbiAgICAgICAgICAudHJhbnNmb3JtKCh2YWx1ZSkgPT5cclxuICAgICAgICAgICAgIVsnZmFsc2UnLCAndW5kZWZpbmVkJywgJ251bGwnLCAnJ10uaW5jbHVkZXModmFsdWUpID8gdmFsdWUgOiBudWxsXHJcbiAgICAgICAgICApXHJcbiAgICAgICAgICAubnVsbGFibGUoKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYGVudW1gIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGggYW4gb3B0aW9uYWwgc3RyaWN0ZXJcclxuICAgKiBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgc2NoZW1hIHdpbGwgdmFsaWRhdGUgYWdhaW5zdCB0aGUgcHJvdmlkZWQgYHZhbHVlc2AgYXJyYXkuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGF0OlxyXG4gICAqXHJcbiAgICogLSBXaGVuIGBzdHJpY3RDaGVja2AgaXMgdHJ1ZSwgdGhlIHNjaGVtYSB3aWxsIHZhbGlkYXRlIGFnYWluc3QgdGhlIGB2YWx1ZXNgXHJcbiAgICogYXJyYXkgd2l0aCB0aGUgZGVmYXVsdCBlbnVtIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIC0gV2hlbiBgc3RyaWN0Q2hlY2tgIGlzIGZhbHNlLCB0aGUgc2NoZW1hIHdpbGwgYWNjZXB0IGFsc28gbnVsbCxcclxuICAgKiAndW5kZWZpbmVkJywgJ251bGwnLCBhbmQgJycsIHdoaWNoIHdpbGwgYmUgdHJhbnNmb3JtZWQgdG8gbnVsbC5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiBlbnVtXHJcbiAgICpcclxuICAgKiBAcGFyYW0ge0FycmF5LjxzdHJpbmc+fSB2YWx1ZXMgLSBBbiBhcnJheSBvZiB2YWxpZCBzdHJpbmcgdmFsdWVzXHJcbiAgICogZm9yIHRoZSBlbnVtLlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZyBlbnVtIHZhbHVlcy5cclxuICAgKi9cclxuICBlbnVtKHZhbHVlcywgc3RyaWN0Q2hlY2spIHtcclxuICAgIHJldHVybiBzdHJpY3RDaGVja1xyXG4gICAgICA/IHouZW51bShbLi4udmFsdWVzXSlcclxuICAgICAgOiB6XHJcbiAgICAgICAgICAuZW51bShbLi4udmFsdWVzLCAndW5kZWZpbmVkJywgJ251bGwnLCAnJ10pXHJcbiAgICAgICAgICAudHJhbnNmb3JtKCh2YWx1ZSkgPT5cclxuICAgICAgICAgICAgIVsndW5kZWZpbmVkJywgJ251bGwnLCAnJ10uaW5jbHVkZXModmFsdWUpID8gdmFsdWUgOiBudWxsXHJcbiAgICAgICAgICApXHJcbiAgICAgICAgICAubnVsbGFibGUoKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYHN0cmluZ0FycmF5YCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoIGFuIG9wdGlvbmFsXHJcbiAgICogc3RyaWN0ZXIgY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhhdDpcclxuICAgKlxyXG4gICAqIC0gV2hlbiBgc3RyaWN0Q2hlY2tgIGlzIHRydWUsIHRoZSBzY2hlbWEgd2lsbCBhY2NlcHQgYW4gYXJyYXkgb2YgdHJpbW1lZFxyXG4gICAqIHN0cmluZyB2YWx1ZXMgZmlsdGVyZWQgYnkgdGhlIGxvZ2ljIHByb3ZpZGVkIHRocm91Z2ggdGhlIGBmaWx0ZXJDYWxsYmFja2AuXHJcbiAgICpcclxuICAgKiAtIFdoZW4gYHN0cmljdENoZWNrYCBpcyBmYWxzZSwgdGhlIHNjaGVtYSB3aWxsIGFjY2VwdCBudWxsIGFuZCB0cmltbWVkXHJcbiAgICogc3RyaW5nIHZhbHVlcyB3aGljaCB3aWxsIGJlIHNwbGl0dGVkIGludG8gYW4gYXJyYXkgb2Ygc3RyaW5ncyBhbmQgZmlsdGVyZWRcclxuICAgKiBmcm9tIHRoZSAnWycgYW5kICddJyBjaGFyYWN0ZXJzIGFuZCBieSB0aGUgbG9naWMgcHJvdmlkZWQgdGhyb3VnaFxyXG4gICAqIHRoZSBgZmlsdGVyQ2FsbGJhY2tgLiBJZiB0aGUgYXJyYXkgaXMgZW1wdHksIGl0IHdpbGwgYmUgdHJhbnNmb3JtZWRcclxuICAgKiB0byBudWxsLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIHN0cmluZ0FycmF5XHJcbiAgICpcclxuICAgKiBAcGFyYW0ge2Z1bmN0aW9ufSBmaWx0ZXJDYWxsYmFjayAtIFRoZSBmaWx0ZXIgY2FsbGJhY2suXHJcbiAgICogQHBhcmFtIHtzdHJpbmd9IHNlcGFyYXRvciAtIFRoZSBzZXBhcmF0b3IgZm9yIHNwbGl0aW5nIGEgc3RyaW5nLlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZyBhcnJheSBvZiBzdHJpbmdcclxuICAgKiB2YWx1ZXMuXHJcbiAgICovXHJcbiAgc3RyaW5nQXJyYXkoZmlsdGVyQ2FsbGJhY2ssIHNlcGFyYXRvciwgc3RyaWN0Q2hlY2spIHtcclxuICAgIGNvbnN0IGFycmF5U2NoZW1hID0gei5zdHJpbmcoKS50cmltKCkuYXJyYXkoKTtcclxuICAgIGNvbnN0IHN0cmluZ1NjaGVtYSA9IHpcclxuICAgICAgLnN0cmluZygpXHJcbiAgICAgIC50cmltKClcclxuICAgICAgLnRyYW5zZm9ybSgodmFsdWUpID0+IHtcclxuICAgICAgICBpZiAodmFsdWUuc3RhcnRzV2l0aCgnWycpKSB7XHJcbiAgICAgICAgICB2YWx1ZSA9IHZhbHVlLnNsaWNlKDEpO1xyXG4gICAgICAgIH1cclxuICAgICAgICBpZiAodmFsdWUuZW5kc1dpdGgoJ10nKSkge1xyXG4gICAgICAgICAgdmFsdWUgPSB2YWx1ZS5zbGljZSgwLCAtMSk7XHJcbiAgICAgICAgfVxyXG4gICAgICAgIHJldHVybiB2YWx1ZS5zcGxpdChzZXBhcmF0b3IpO1xyXG4gICAgICB9KTtcclxuXHJcbiAgICBjb25zdCB0cmFuc2Zvcm1DYWxsYmFjayA9ICh2YWx1ZSkgPT5cclxuICAgICAgdmFsdWUubWFwKCh2YWx1ZSkgPT4gdmFsdWUudHJpbSgpKS5maWx0ZXIoZmlsdGVyQ2FsbGJhY2spO1xyXG5cclxuICAgIHJldHVybiBzdHJpY3RDaGVja1xyXG4gICAgICA/IGFycmF5U2NoZW1hLnRyYW5zZm9ybSh0cmFuc2Zvcm1DYWxsYmFjaylcclxuICAgICAgOiB6XHJcbiAgICAgICAgICAudW5pb24oW3N0cmluZ1NjaGVtYSwgYXJyYXlTY2hlbWFdKVxyXG4gICAgICAgICAgLnRyYW5zZm9ybSh0cmFuc2Zvcm1DYWxsYmFjaylcclxuICAgICAgICAgIC50cmFuc2Zvcm0oKHZhbHVlKSA9PiAodmFsdWUubGVuZ3RoID8gdmFsdWUgOiBudWxsKSlcclxuICAgICAgICAgIC5udWxsYWJsZSgpO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgcG9zaXRpdmVOdW1gIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGggYW4gb3B0aW9uYWxcclxuICAgKiBzdHJpY3RlciBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGF0OlxyXG4gICAqXHJcbiAgICogLSBXaGVuIGBzdHJpY3RDaGVja2AgaXMgdHJ1ZSwgdGhlIHNjaGVtYSB3aWxsIGFjY2VwdCBwb3NpdGl2ZSBudW1iZXIgdmFsdWVzXHJcbiAgICogYW5kIHZhbGlkYXRlIGFnYWluc3QgdGhlIGRlZmF1bHQgcG9zaXRpdmUgbnVtYmVyIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIC0gV2hlbiBgc3RyaWN0Q2hlY2tgIGlzIGZhbHNlLCB0aGUgc2NoZW1hIHdpbGwgYWNjZXB0IHBvc2l0aXZlIG51bWJlclxyXG4gICAqIHZhbHVlcywgbnVsbCwgYW5kIHRyaW1tZWQgc3RyaW5nIHZhbHVlcyB0aGF0IGNhbiBlaXRoZXIgYmUgJ3VuZGVmaW5lZCcsXHJcbiAgICogJ251bGwnLCAnJywgb3IgcmVwcmVzZW50IGEgcG9zaXRpdmUgbnVtYmVyLiBJdCB3aWxsIHRyYW5zZm9ybSB0aGUgc3RyaW5nXHJcbiAgICogdG8gYSBwb3NpdGl2ZSBudW1iZXIsIG9yIHRvIG51bGwgaWYgaXQgaXMgJ3VuZGVmaW5lZCcsICdudWxsJywgb3IgJycuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gcG9zaXRpdmVOdW1cclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZyBwb3NpdGl2ZSBudW1iZXJcclxuICAgKiB2YWx1ZXMuXHJcbiAgICovXHJcbiAgcG9zaXRpdmVOdW0oc3RyaWN0Q2hlY2spIHtcclxuICAgIHJldHVybiBzdHJpY3RDaGVja1xyXG4gICAgICA/IHoubnVtYmVyKCkucG9zaXRpdmUoKVxyXG4gICAgICA6IHpcclxuICAgICAgICAgIC51bmlvbihbXHJcbiAgICAgICAgICAgIHpcclxuICAgICAgICAgICAgICAuc3RyaW5nKClcclxuICAgICAgICAgICAgICAudHJpbSgpXHJcbiAgICAgICAgICAgICAgLnJlZmluZShcclxuICAgICAgICAgICAgICAgICh2YWx1ZSkgPT5cclxuICAgICAgICAgICAgICAgICAgKCFpc05hTihOdW1iZXIodmFsdWUpKSAmJiBOdW1iZXIodmFsdWUpID4gMCkgfHxcclxuICAgICAgICAgICAgICAgICAgWyd1bmRlZmluZWQnLCAnbnVsbCcsICcnXS5pbmNsdWRlcyh2YWx1ZSksXHJcbiAgICAgICAgICAgICAgICB7XHJcbiAgICAgICAgICAgICAgICAgIHBhcmFtczoge1xyXG4gICAgICAgICAgICAgICAgICAgIGVycm9yTWVzc2FnZTogJ1RoZSB2YWx1ZSBtdXN0IGJlIG51bWVyaWMgYW5kIHBvc2l0aXZlJ1xyXG4gICAgICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgICAgKVxyXG4gICAgICAgICAgICAgIC50cmFuc2Zvcm0oKHZhbHVlKSA9PlxyXG4gICAgICAgICAgICAgICAgIVsndW5kZWZpbmVkJywgJ251bGwnLCAnJ10uaW5jbHVkZXModmFsdWUpXHJcbiAgICAgICAgICAgICAgICAgID8gTnVtYmVyKHZhbHVlKVxyXG4gICAgICAgICAgICAgICAgICA6IG51bGxcclxuICAgICAgICAgICAgICApLFxyXG4gICAgICAgICAgICB6Lm51bWJlcigpLnBvc2l0aXZlKClcclxuICAgICAgICAgIF0pXHJcbiAgICAgICAgICAubnVsbGFibGUoKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYG5vbk5lZ2F0aXZlTnVtYCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoIGFuIG9wdGlvbmFsXHJcbiAgICogc3RyaWN0ZXIgY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhhdDpcclxuICAgKlxyXG4gICAqIC0gV2hlbiBgc3RyaWN0Q2hlY2tgIGlzIHRydWUsIHRoZSBzY2hlbWEgd2lsbCBhY2NlcHQgbm9uLW5lZ2F0aXZlIG51bWJlclxyXG4gICAqIHZhbHVlcyBhbmQgdmFsaWRhdGUgYWdhaW5zdCB0aGUgZGVmYXVsdCBub24tbmVnYXRpdmUgbnVtYmVyIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIC0gV2hlbiBgc3RyaWN0Q2hlY2tgIGlzIGZhbHNlLCB0aGUgc2NoZW1hIHdpbGwgYWNjZXB0IG5vbi1uZWdhdGl2ZSBudW1iZXJcclxuICAgKiB2YWx1ZXMsIG51bGwsIGFuZCB0cmltbWVkIHN0cmluZyB2YWx1ZXMgdGhhdCBjYW4gZWl0aGVyIGJlICd1bmRlZmluZWQnLFxyXG4gICAqICdudWxsJywgJycsIG9yIHJlcHJlc2VudCBhIG5vbi1uZWdhdGl2ZSBudW1iZXIuIEl0IHdpbGwgdHJhbnNmb3JtXHJcbiAgICogdGhlIHN0cmluZyB0byBhIG5vbi1uZWdhdGl2ZSBudW1iZXIsIG9yIHRvIG51bGwgaWYgaXQgaXMgJ3VuZGVmaW5lZCcsXHJcbiAgICogJ251bGwnLCBvciAnJy5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiBub25OZWdhdGl2ZU51bVxyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nIG5vbi1uZWdhdGl2ZVxyXG4gICAqIG51bWJlciB2YWx1ZXMuXHJcbiAgICovXHJcbiAgbm9uTmVnYXRpdmVOdW0oc3RyaWN0Q2hlY2spIHtcclxuICAgIHJldHVybiBzdHJpY3RDaGVja1xyXG4gICAgICA/IHoubnVtYmVyKCkubm9ubmVnYXRpdmUoKVxyXG4gICAgICA6IHpcclxuICAgICAgICAgIC51bmlvbihbXHJcbiAgICAgICAgICAgIHpcclxuICAgICAgICAgICAgICAuc3RyaW5nKClcclxuICAgICAgICAgICAgICAudHJpbSgpXHJcbiAgICAgICAgICAgICAgLnJlZmluZShcclxuICAgICAgICAgICAgICAgICh2YWx1ZSkgPT5cclxuICAgICAgICAgICAgICAgICAgKCFpc05hTihOdW1iZXIodmFsdWUpKSAmJiBOdW1iZXIodmFsdWUpID49IDApIHx8XHJcbiAgICAgICAgICAgICAgICAgIFsndW5kZWZpbmVkJywgJ251bGwnLCAnJ10uaW5jbHVkZXModmFsdWUpLFxyXG4gICAgICAgICAgICAgICAge1xyXG4gICAgICAgICAgICAgICAgICBwYXJhbXM6IHtcclxuICAgICAgICAgICAgICAgICAgICBlcnJvck1lc3NhZ2U6ICdUaGUgdmFsdWUgbXVzdCBiZSBudW1lcmljIGFuZCBub24tbmVnYXRpdmUnXHJcbiAgICAgICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgICApXHJcbiAgICAgICAgICAgICAgLnRyYW5zZm9ybSgodmFsdWUpID0+XHJcbiAgICAgICAgICAgICAgICAhWyd1bmRlZmluZWQnLCAnbnVsbCcsICcnXS5pbmNsdWRlcyh2YWx1ZSlcclxuICAgICAgICAgICAgICAgICAgPyBOdW1iZXIodmFsdWUpXHJcbiAgICAgICAgICAgICAgICAgIDogbnVsbFxyXG4gICAgICAgICAgICAgICksXHJcbiAgICAgICAgICAgIHoubnVtYmVyKCkubm9ubmVnYXRpdmUoKVxyXG4gICAgICAgICAgXSlcclxuICAgICAgICAgIC5udWxsYWJsZSgpO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgc3RhcnRzV2l0aGAgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbFxyXG4gICAqIHN0cmljdGVyIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSBzY2hlbWEgd2lsbCB2YWxpZGF0ZSBhZ2FpbnN0IHRoZSBwcm92aWRlZCBgcHJlZml4ZXNgIGFycmF5IHRvIGNoZWNrXHJcbiAgICogd2hldGhlciBhIHN0cmluZyB2YWx1ZSBzdGFydHMgd2l0aCBhbnkgb2YgdGhlIHZhbHVlcyBwcm92aWRlZFxyXG4gICAqIGluIHRoZSBgcHJlZml4ZXNgIGFycmF5LlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhhdDpcclxuICAgKlxyXG4gICAqIC0gV2hlbiBgc3RyaWN0Q2hlY2tgIGlzIHRydWUsIHRoZSBzY2hlbWEgd2lsbCBhY2NlcHQgdHJpbW1lZCBzdHJpbmcgdmFsdWVzXHJcbiAgICogdGhhdCBzdGFydCB3aXRoIHZhbHVlcyBmcm9tIHRoZSBwcmVmaXhlcyBhcnJheS5cclxuICAgKlxyXG4gICAqIC0gV2hlbiBgc3RyaWN0Q2hlY2tgIGlzIGZhbHNlLCB0aGUgc2NoZW1hIHdpbGwgYWNjZXB0IHRyaW1tZWQgc3RyaW5nIHZhbHVlc1xyXG4gICAqIHRoYXQgc3RhcnQgd2l0aCB2YWx1ZXMgZnJvbSB0aGUgcHJlZml4ZXMgYXJyYXksIG51bGwsICd1bmRlZmluZWQnLCAnbnVsbCcsXHJcbiAgICogYW5kICcnIHdoZXJlIHRoZSBzY2hlbWEgd2lsbCB0cmFuc2Zvcm0gdGhlbSB0byBudWxsLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIHN0YXJ0c1dpdGhcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7QXJyYXkuPHN0cmluZz59IHByZWZpeGVzIC0gQW4gYXJyYXkgb2YgcHJlZml4ZXMgdG8gdmFsaWRhdGVcclxuICAgKiB0aGUgc3RyaW5nIGFnYWluc3QuXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nIHN0cmluZ3MgdGhhdFxyXG4gICAqIHN0YXJ0cyB3aXRoIHZhbHVlcy5cclxuICAgKi9cclxuICBzdGFydHNXaXRoKHByZWZpeGVzLCBzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHN0cmljdENoZWNrXHJcbiAgICAgID8gelxyXG4gICAgICAgICAgLnN0cmluZygpXHJcbiAgICAgICAgICAudHJpbSgpXHJcbiAgICAgICAgICAucmVmaW5lKFxyXG4gICAgICAgICAgICAodmFsdWUpID0+IHByZWZpeGVzLnNvbWUoKHByZWZpeCkgPT4gdmFsdWUuc3RhcnRzV2l0aChwcmVmaXgpKSxcclxuICAgICAgICAgICAge1xyXG4gICAgICAgICAgICAgIHBhcmFtczoge1xyXG4gICAgICAgICAgICAgICAgZXJyb3JNZXNzYWdlOiBgVGhlIHZhbHVlIG11c3QgYmUgYSBzdHJpbmcgdGhhdCBzdGFydHMgd2l0aCAke3ByZWZpeGVzLmpvaW4oJywgJyl9YFxyXG4gICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgfVxyXG4gICAgICAgICAgKVxyXG4gICAgICA6IHpcclxuICAgICAgICAgIC5zdHJpbmcoKVxyXG4gICAgICAgICAgLnRyaW0oKVxyXG4gICAgICAgICAgLnJlZmluZShcclxuICAgICAgICAgICAgKHZhbHVlKSA9PlxyXG4gICAgICAgICAgICAgIHByZWZpeGVzLnNvbWUoKHByZWZpeCkgPT4gdmFsdWUuc3RhcnRzV2l0aChwcmVmaXgpKSB8fFxyXG4gICAgICAgICAgICAgIFsndW5kZWZpbmVkJywgJ251bGwnLCAnJ10uaW5jbHVkZXModmFsdWUpLFxyXG4gICAgICAgICAgICB7XHJcbiAgICAgICAgICAgICAgcGFyYW1zOiB7XHJcbiAgICAgICAgICAgICAgICBlcnJvck1lc3NhZ2U6IGBUaGUgdmFsdWUgbXVzdCBiZSBhIHN0cmluZyB0aGF0IHN0YXJ0cyB3aXRoICR7cHJlZml4ZXMuam9pbignLCAnKX1gXHJcbiAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICB9XHJcbiAgICAgICAgICApXHJcbiAgICAgICAgICAudHJhbnNmb3JtKCh2YWx1ZSkgPT5cclxuICAgICAgICAgICAgIVsndW5kZWZpbmVkJywgJ251bGwnLCAnJ10uaW5jbHVkZXModmFsdWUpID8gdmFsdWUgOiBudWxsXHJcbiAgICAgICAgICApXHJcbiAgICAgICAgICAubnVsbGFibGUoKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYGNoYXJ0Q29uZmlnYCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYS5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoYXQgdGhlIHNjaGVtYSB3aWxsIGFjY2VwdCBvYmplY3QgdmFsdWVzXHJcbiAgICogb3IgdHJpbW1lZCBzdHJpbmcgdmFsdWVzIHRoYXQgY29udGFpbiAnPHN2Zycgb3IgJzw/eG1sJyBlbGVtZW50cywgc3RhcnRcclxuICAgKiB3aXRoIHRoZSAneycgYW5kIGVuZCB3aXRoIHRoZSAnfScsIGFuZCBudWxsLiBUaGUgJ3VuZGVmaW5lZCcsICdudWxsJyxcclxuICAgKiBhbmQgJycgdmFsdWVzIHdpbGwgYmUgdHJhbnNmb3JtZWQgdG8gbnVsbC5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiBjaGFydENvbmZpZ1xyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nIGNoYXJ0XHJcbiAgICogY29uZmlndXJhdGlvbiB2YWx1ZS5cclxuICAgKi9cclxuICBjaGFydENvbmZpZygpIHtcclxuICAgIHJldHVybiB6XHJcbiAgICAgIC51bmlvbihbXHJcbiAgICAgICAgelxyXG4gICAgICAgICAgLnN0cmluZygpXHJcbiAgICAgICAgICAudHJpbSgpXHJcbiAgICAgICAgICAucmVmaW5lKFxyXG4gICAgICAgICAgICAodmFsdWUpID0+XHJcbiAgICAgICAgICAgICAgKHZhbHVlLnN0YXJ0c1dpdGgoJ3snKSAmJiB2YWx1ZS5lbmRzV2l0aCgnfScpKSB8fFxyXG4gICAgICAgICAgICAgIFsndW5kZWZpbmVkJywgJ251bGwnLCAnJ10uaW5jbHVkZXModmFsdWUpLFxyXG4gICAgICAgICAgICB7XHJcbiAgICAgICAgICAgICAgcGFyYW1zOiB7XHJcbiAgICAgICAgICAgICAgICBlcnJvck1lc3NhZ2U6XHJcbiAgICAgICAgICAgICAgICAgIFwiVGhlIHZhbHVlIG11c3QgYmUgYSBzdHJpbmcgdGhhdCBzdGFydHMgd2l0aCAneycgYW5kIGVuZHMgd2l0aCAnfSdcIlxyXG4gICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgfVxyXG4gICAgICAgICAgKVxyXG4gICAgICAgICAgLnRyYW5zZm9ybSgodmFsdWUpID0+XHJcbiAgICAgICAgICAgICFbJ3VuZGVmaW5lZCcsICdudWxsJywgJyddLmluY2x1ZGVzKHZhbHVlKSA/IHZhbHVlIDogbnVsbFxyXG4gICAgICAgICAgKSxcclxuICAgICAgICB6Lm9iamVjdCh7fSkucGFzc3Rocm91Z2goKVxyXG4gICAgICBdKVxyXG4gICAgICAubnVsbGFibGUoKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYGFkZGl0aW9uYWxPcHRpb25zYCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYS5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoYXQgdGhlIHNjaGVtYSB3aWxsIGFjY2VwdCBvYmplY3QgdmFsdWVzXHJcbiAgICogb3IgdHJpbW1lZCBzdHJpbmcgdmFsdWVzIHRoYXQgZW5kIHdpdGggJy5qc29uJyBhbmQgYXJlIGF0IGxlYXN0IG9uZVxyXG4gICAqIGNoYXJhY3RlciBsb25nIGV4Y2x1ZGluZyB0aGUgZXh0ZW5zaW9uLCBzdGFydCB3aXRoIHRoZSAneycgYW5kIGVuZFxyXG4gICAqIHdpdGggdGhlICd9JywgYW5kIG51bGwuIFRoZSAndW5kZWZpbmVkJywgJ251bGwnLCBhbmQgJycgdmFsdWVzIHdpbGxcclxuICAgKiBiZSB0cmFuc2Zvcm1lZCB0byBudWxsLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIGFkZGl0aW9uYWxPcHRpb25zXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9ICBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nIGFkZGl0aW9uYWwgY2hhcnRcclxuICAgKiBvcHRpb25zIHZhbHVlLlxyXG4gICAqL1xyXG4gIGFkZGl0aW9uYWxPcHRpb25zKCkge1xyXG4gICAgcmV0dXJuIHpcclxuICAgICAgLnVuaW9uKFtcclxuICAgICAgICB6XHJcbiAgICAgICAgICAuc3RyaW5nKClcclxuICAgICAgICAgIC50cmltKClcclxuICAgICAgICAgIC5yZWZpbmUoXHJcbiAgICAgICAgICAgICh2YWx1ZSkgPT5cclxuICAgICAgICAgICAgICAodmFsdWUubGVuZ3RoID49IDYgJiYgdmFsdWUuZW5kc1dpdGgoJy5qc29uJykpIHx8XHJcbiAgICAgICAgICAgICAgKHZhbHVlLnN0YXJ0c1dpdGgoJ3snKSAmJiB2YWx1ZS5lbmRzV2l0aCgnfScpKSB8fFxyXG4gICAgICAgICAgICAgIFsndW5kZWZpbmVkJywgJ251bGwnLCAnJ10uaW5jbHVkZXModmFsdWUpLFxyXG4gICAgICAgICAgICB7XHJcbiAgICAgICAgICAgICAgcGFyYW1zOiB7XHJcbiAgICAgICAgICAgICAgICBlcnJvck1lc3NhZ2U6XHJcbiAgICAgICAgICAgICAgICAgIFwiVGhlIHZhbHVlIG11c3QgYmUgYSBzdHJpbmcgdGhhdCBlbmRzIHdpdGggJy5qc29uJyBvciBzdGFydHMgd2l0aCAneycgYW5kIGVuZHMgd2l0aCAnfSdcIlxyXG4gICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgfVxyXG4gICAgICAgICAgKVxyXG4gICAgICAgICAgLnRyYW5zZm9ybSgodmFsdWUpID0+XHJcbiAgICAgICAgICAgICFbJ3VuZGVmaW5lZCcsICdudWxsJywgJyddLmluY2x1ZGVzKHZhbHVlKSA/IHZhbHVlIDogbnVsbFxyXG4gICAgICAgICAgKSxcclxuICAgICAgICB6Lm9iamVjdCh7fSkucGFzc3Rocm91Z2goKVxyXG4gICAgICBdKVxyXG4gICAgICAubnVsbGFibGUoKTtcclxuICB9XHJcbn07XHJcblxyXG4vKipcclxuICogT2JqZWN0IGNvbnRhaW5pbmcgY3VzdG9tIGNvbmZpZyB2YWxpZGF0b3JzIGFuZCBwYXJzZXJzIHRvIGF2b2lkIHJlcGV0aXRpb25cclxuICogaW4gc2NoZW1hIG9iamVjdHMuIEFsbCB2YWxpZGF0b3JzIGFwcGx5IHRvIHZhbHVlcyBmcm9tIHZhcmlvdXMgc291cmNlcyxcclxuICogaW5jbHVkaW5nIHRoZSBkZWZhdWx0IGNvbmZpZyBmaWxlLCBhIGN1c3RvbSBKU09OIGZpbGUgbG9hZGVkIHdpdGggdGhlIG9wdGlvblxyXG4gKiBjYWxsZWQgYGxvYWRDb25maWdgLCB0aGUgLmVudiBmaWxlLCBDTEkgYXJndW1lbnRzLCBhbmQgdGhlIHJlcXVlc3QgcGF5bG9hZC5cclxuICogVGhlIGBzdHJpY3RDaGVja2AgZmxhZyBlbmFibGVzIHN0cmljdGVyIHZhbGlkYXRpb24gYW5kIHBhcnNpbmcgcnVsZXMuIFRoaXNcclxuICogZmxhZyBpcyBzZXQgdG8gZmFsc2UgZm9yIHZhbHVlcyB0aGF0IGNvbWUgZnJvbSB0aGUgLmVudiBmaWxlIG9yIENMSSBhcmd1bWVudHNcclxuICogYmVjYXVzZSB0aGV5IGFyZSBwcm92aWRlZCBhcyBzdHJpbmdzIGFuZCBuZWVkIHRvIGJlIHBhcnNlZCBhY2NvcmRpbmdseSBmaXJzdC5cclxuICovXHJcbmV4cG9ydCBjb25zdCB2YWxpZGF0b3JzID0ge1xyXG4gIC8qKlxyXG4gICAqIFRoZSBgYXJnc2AgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbCBzdHJpY3RlclxyXG4gICAqIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgdGhlIGBzdHJpbmdBcnJheWAgdmFsaWRhdG9yLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIGFyZ3NcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZyB0aGUgYGFyZ3NgXHJcbiAgICogb3B0aW9uLlxyXG4gICAqL1xyXG4gIGFyZ3Moc3RyaWN0Q2hlY2spIHtcclxuICAgIHJldHVybiB2LnN0cmluZ0FycmF5KFxyXG4gICAgICAodmFsdWUpID0+ICFbJ2ZhbHNlJywgJ3VuZGVmaW5lZCcsICdudWxsJywgJyddLmluY2x1ZGVzKHZhbHVlKSxcclxuICAgICAgJzsnLFxyXG4gICAgICBzdHJpY3RDaGVja1xyXG4gICAgKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYHZlcnNpb25gIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGggYW4gb3B0aW9uYWwgc3RyaWN0ZXJcclxuICAgKiBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGF0OlxyXG4gICAqXHJcbiAgICogLSBXaGVuIGBzdHJpY3RDaGVja2AgaXMgdHJ1ZSwgdGhlIHNjaGVtYSB3aWxsIGFjY2VwdCB0cmltbWVkIHN0cmluZyB2YWx1ZXNcclxuICAgKiB0aGF0IGFyZSBhIFJlZ0V4cC1iYXNlZCB0aGF0IGFsbG93cyB0byBiZSAnbGF0ZXN0Jywgb3IgaW4gdGhlIGZvcm1hdCBYWCxcclxuICAgKiBYWC5ZWSwgb3IgWFguWVkuWlosIHdoZXJlIFhYLCBZWSwgYW5kIFpaIGFyZSBudW1lcmljIGZvciB0aGUgSGlnaGNoYXJ0c1xyXG4gICAqIHZlcnNpb24gb3B0aW9uLlxyXG4gICAqXHJcbiAgICogLSBXaGVuIGBzdHJpY3RDaGVja2AgaXMgZmFsc2UsIHRoZSBzY2hlbWEgd2lsbCBhY2NlcHQgYWxzbyBudWxsLFxyXG4gICAqICd1bmRlZmluZWQnLCAnbnVsbCcsIG9yICcnIGFuZCBpbiBhbGwgY2FzZXMgdGhlIHNjaGVtYSB3aWxsIHRyYW5zZm9ybSB0aGVtXHJcbiAgICogdG8gbnVsbC5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiB2ZXJzaW9uXHJcbiAgICpcclxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IHN0cmljdENoZWNrIC0gRGV0ZXJtaW5lcyBpZiBzdHJpY3RlciB2YWxpZGF0aW9uIHNob3VsZFxyXG4gICAqIGJlIGFwcGxpZWQuXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9IEEgWm9kIHNjaGVtYSBvYmplY3QgZm9yIHZhbGlkYXRpbmcgdGhlIGB2ZXJzaW9uYFxyXG4gICAqIG9wdGlvbi5cclxuICAgKi9cclxuICB2ZXJzaW9uKHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gc3RyaWN0Q2hlY2tcclxuICAgICAgPyB6XHJcbiAgICAgICAgICAuc3RyaW5nKClcclxuICAgICAgICAgIC50cmltKClcclxuICAgICAgICAgIC5yZWZpbmUoKHZhbHVlKSA9PiAvXihsYXRlc3R8XFxkezEsMn0oXFwuXFxkezEsMn0pezAsMn0pJC8udGVzdCh2YWx1ZSksIHtcclxuICAgICAgICAgICAgcGFyYW1zOiB7XHJcbiAgICAgICAgICAgICAgZXJyb3JNZXNzYWdlOlxyXG4gICAgICAgICAgICAgICAgXCJUaGUgdmFsdWUgbXVzdCBiZSAnbGF0ZXN0JywgYSBtYWpvciB2ZXJzaW9uLCBvciBpbiB0aGUgZm9ybSBYWC5ZWS5aWlwiXHJcbiAgICAgICAgICAgIH1cclxuICAgICAgICAgIH0pXHJcbiAgICAgIDogelxyXG4gICAgICAgICAgLnN0cmluZygpXHJcbiAgICAgICAgICAudHJpbSgpXHJcbiAgICAgICAgICAucmVmaW5lKFxyXG4gICAgICAgICAgICAodmFsdWUpID0+XHJcbiAgICAgICAgICAgICAgL14obGF0ZXN0fFxcZHsxLDJ9KFxcLlxcZHsxLDJ9KXswLDJ9KSQvLnRlc3QodmFsdWUpIHx8XHJcbiAgICAgICAgICAgICAgWyd1bmRlZmluZWQnLCAnbnVsbCcsICcnXS5pbmNsdWRlcyh2YWx1ZSksXHJcbiAgICAgICAgICAgIHtcclxuICAgICAgICAgICAgICBwYXJhbXM6IHtcclxuICAgICAgICAgICAgICAgIGVycm9yTWVzc2FnZTpcclxuICAgICAgICAgICAgICAgICAgXCJUaGUgdmFsdWUgbXVzdCBiZSAnbGF0ZXN0JywgYSBtYWpvciB2ZXJzaW9uLCBvciBpbiB0aGUgZm9ybSBYWC5ZWS5aWlwiXHJcbiAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICB9XHJcbiAgICAgICAgICApXHJcbiAgICAgICAgICAudHJhbnNmb3JtKCh2YWx1ZSkgPT5cclxuICAgICAgICAgICAgIVsndW5kZWZpbmVkJywgJ251bGwnLCAnJ10uaW5jbHVkZXModmFsdWUpID8gdmFsdWUgOiBudWxsXHJcbiAgICAgICAgICApXHJcbiAgICAgICAgICAubnVsbGFibGUoKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYGNkblVybGAgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbCBzdHJpY3RlclxyXG4gICAqIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgdGhlIGBzdGFydHNXaXRoYCB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gY2RuVXJsXHJcbiAgICpcclxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IHN0cmljdENoZWNrIC0gRGV0ZXJtaW5lcyBpZiBzdHJpY3RlciB2YWxpZGF0aW9uIHNob3VsZFxyXG4gICAqIGJlIGFwcGxpZWQuXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9IEEgWm9kIHNjaGVtYSBvYmplY3QgZm9yIHZhbGlkYXRpbmcgdGhlIGBjZG5VcmxgXHJcbiAgICogb3B0aW9uLlxyXG4gICAqL1xyXG4gIGNkblVybChzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHYuc3RhcnRzV2l0aChbJ2h0dHA6Ly8nLCAnaHR0cHM6Ly8nXSwgc3RyaWN0Q2hlY2spO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgZm9yY2VGZXRjaGAgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbFxyXG4gICAqIHN0cmljdGVyIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgdGhlIGBib29sZWFuYCB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gZm9yY2VGZXRjaFxyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nIHRoZSBgZm9yY2VGZXRjaGBcclxuICAgKiBvcHRpb24uXHJcbiAgICovXHJcbiAgZm9yY2VGZXRjaChzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHYuYm9vbGVhbihzdHJpY3RDaGVjayk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGBjYWNoZVBhdGhgIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGggYW4gb3B0aW9uYWxcclxuICAgKiBzdHJpY3RlciBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGUgc2FtZSB3b3JrIGFzIHRoZSBgc3RyaW5nYCB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gY2FjaGVQYXRoXHJcbiAgICpcclxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IHN0cmljdENoZWNrIC0gRGV0ZXJtaW5lcyBpZiBzdHJpY3RlciB2YWxpZGF0aW9uIHNob3VsZFxyXG4gICAqIGJlIGFwcGxpZWQuXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9IEEgWm9kIHNjaGVtYSBvYmplY3QgZm9yIHZhbGlkYXRpbmcgdGhlIGBjYWNoZVBhdGhgXHJcbiAgICogb3B0aW9uLlxyXG4gICAqL1xyXG4gIGNhY2hlUGF0aChzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHYuc3RyaW5nKHN0cmljdENoZWNrKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYGFkbWluVG9rZW5gIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGggYW4gb3B0aW9uYWxcclxuICAgKiBzdHJpY3RlciBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGUgc2FtZSB3b3JrIGFzIHRoZSBgc3RyaW5nYCB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gYWRtaW5Ub2tlblxyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nIHRoZSBgYWRtaW5Ub2tlbmBcclxuICAgKiBvcHRpb24uXHJcbiAgICovXHJcbiAgYWRtaW5Ub2tlbihzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHYuc3RyaW5nKHN0cmljdENoZWNrKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYGNvcmVTY3JpcHRzYCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoIGFuIG9wdGlvbmFsXHJcbiAgICogc3RyaWN0ZXIgY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhlIHNhbWUgd29yayBhcyB0aGUgYHN0cmluZ0FycmF5YCB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gY29yZVNjcmlwdHNcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZyB0aGUgYGNvcmVTY3JpcHRzYFxyXG4gICAqIG9wdGlvbi5cclxuICAgKi9cclxuICBjb3JlU2NyaXB0cyhzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHYuc3RyaW5nQXJyYXkoXHJcbiAgICAgICh2YWx1ZSkgPT4gY29yZVNjcmlwdHMudmFsdWUuaW5jbHVkZXModmFsdWUpLFxyXG4gICAgICAnLCcsXHJcbiAgICAgIHN0cmljdENoZWNrXHJcbiAgICApO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgbW9kdWxlU2NyaXB0c2AgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbFxyXG4gICAqIHN0cmljdGVyIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgdGhlIGBzdHJpbmdBcnJheWAgdmFsaWRhdG9yLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIG1vZHVsZVNjcmlwdHNcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZ1xyXG4gICAqIHRoZSBgbW9kdWxlU2NyaXB0c2Agb3B0aW9uLlxyXG4gICAqL1xyXG4gIG1vZHVsZVNjcmlwdHMoc3RyaWN0Q2hlY2spIHtcclxuICAgIHJldHVybiB2LnN0cmluZ0FycmF5KFxyXG4gICAgICAodmFsdWUpID0+IG1vZHVsZVNjcmlwdHMudmFsdWUuaW5jbHVkZXModmFsdWUpLFxyXG4gICAgICAnLCcsXHJcbiAgICAgIHN0cmljdENoZWNrXHJcbiAgICApO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgaW5kaWNhdG9yU2NyaXB0c2AgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbFxyXG4gICAqIHN0cmljdGVyIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgdGhlIGBzdHJpbmdBcnJheWAgdmFsaWRhdG9yLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIGluZGljYXRvclNjcmlwdHNcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZ1xyXG4gICAqIHRoZSBgaW5kaWNhdG9yU2NyaXB0c2Agb3B0aW9uLlxyXG4gICAqL1xyXG4gIGluZGljYXRvclNjcmlwdHMoc3RyaWN0Q2hlY2spIHtcclxuICAgIHJldHVybiB2LnN0cmluZ0FycmF5KFxyXG4gICAgICAodmFsdWUpID0+IGluZGljYXRvclNjcmlwdHMudmFsdWUuaW5jbHVkZXModmFsdWUpLFxyXG4gICAgICAnLCcsXHJcbiAgICAgIHN0cmljdENoZWNrXHJcbiAgICApO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgY3VzdG9tU2NyaXB0c2AgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbFxyXG4gICAqIHN0cmljdGVyIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgdGhlIGBzdHJpbmdBcnJheWAgdmFsaWRhdG9yLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIGN1c3RvbVNjcmlwdHNcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZ1xyXG4gICAqIHRoZSBgY3VzdG9tU2NyaXB0c2Agb3B0aW9uLlxyXG4gICAqL1xyXG4gIGN1c3RvbVNjcmlwdHMoc3RyaWN0Q2hlY2spIHtcclxuICAgIHJldHVybiB2LnN0cmluZ0FycmF5KFxyXG4gICAgICAodmFsdWUpID0+IHZhbHVlLnN0YXJ0c1dpdGgoJ2h0dHBzOi8vJykgfHwgdmFsdWUuc3RhcnRzV2l0aCgnaHR0cDovLycpLFxyXG4gICAgICAnLCcsXHJcbiAgICAgIHN0cmljdENoZWNrXHJcbiAgICApO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgaW5maWxlYCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoIGFuIG9wdGlvbmFsIHN0cmljdGVyXHJcbiAgICogY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhhdDpcclxuICAgKlxyXG4gICAqIC0gV2hlbiBgc3RyaWN0Q2hlY2tgIGlzIHRydWUsIHRoZSBzY2hlbWEgd2lsbCBhY2NlcHQgdHJpbW1lZCBzdHJpbmcgdmFsdWVzXHJcbiAgICogdGhhdCBlbmQgd2l0aCAnLmpzb24nIG9yICcuc3ZnJywgYXJlIGF0IGxlYXN0IG9uZSBjaGFyYWN0ZXIgbG9uZyBleGNsdWRpbmdcclxuICAgKiB0aGUgZXh0ZW5zaW9uLCBvciBudWxsLlxyXG4gICAqXHJcbiAgICogLSBXaGVuIGBzdHJpY3RDaGVja2AgaXMgZmFsc2UsIHRoZSBzY2hlbWEgd2lsbCBhY2NlcHQgdHJpbW1lZCBzdHJpbmcgdmFsdWVzXHJcbiAgICogdGhhdCBlbmQgd2l0aCAnLmpzb24nIG9yICcuc3ZnJywgYXJlIGF0IGxlYXN0IG9uZSBjaGFyYWN0ZXIgbG9uZyBleGNsdWRpbmdcclxuICAgKiB0aGUgZXh0ZW5zaW9uIGFuZCB3aWxsIGJlIG51bGwgaWYgdGhlIHByb3ZpZGVkIHZhbHVlIGlzIG51bGwsICd1bmRlZmluZWQnLFxyXG4gICAqICdudWxsJywgb3IgJycuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gaW5maWxlXHJcbiAgICpcclxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IHN0cmljdENoZWNrIC0gRGV0ZXJtaW5lcyBpZiBzdHJpY3RlciB2YWxpZGF0aW9uIHNob3VsZFxyXG4gICAqIGJlIGFwcGxpZWQuXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9IEEgWm9kIHNjaGVtYSBvYmplY3QgZm9yIHZhbGlkYXRpbmcgdGhlIGBpbmZpbGVgXHJcbiAgICogb3B0aW9uLlxyXG4gICAqL1xyXG4gIGluZmlsZShzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHN0cmljdENoZWNrXHJcbiAgICAgID8gelxyXG4gICAgICAgICAgLnN0cmluZygpXHJcbiAgICAgICAgICAudHJpbSgpXHJcbiAgICAgICAgICAucmVmaW5lKFxyXG4gICAgICAgICAgICAodmFsdWUpID0+XHJcbiAgICAgICAgICAgICAgKHZhbHVlLmxlbmd0aCA+PSA2ICYmIHZhbHVlLmVuZHNXaXRoKCcuanNvbicpKSB8fFxyXG4gICAgICAgICAgICAgICh2YWx1ZS5sZW5ndGggPj0gNSAmJiB2YWx1ZS5lbmRzV2l0aCgnLnN2ZycpKSxcclxuICAgICAgICAgICAge1xyXG4gICAgICAgICAgICAgIHBhcmFtczoge1xyXG4gICAgICAgICAgICAgICAgZXJyb3JNZXNzYWdlOlxyXG4gICAgICAgICAgICAgICAgICAnVGhlIHZhbHVlIG11c3QgYmUgYSBzdHJpbmcgdGhhdCBlbmRzIHdpdGggLmpzb24gb3IgLnN2ZydcclxuICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgIH1cclxuICAgICAgICAgIClcclxuICAgICAgICAgIC5udWxsYWJsZSgpXHJcbiAgICAgIDogelxyXG4gICAgICAgICAgLnN0cmluZygpXHJcbiAgICAgICAgICAudHJpbSgpXHJcbiAgICAgICAgICAucmVmaW5lKFxyXG4gICAgICAgICAgICAodmFsdWUpID0+XHJcbiAgICAgICAgICAgICAgKHZhbHVlLmxlbmd0aCA+PSA2ICYmIHZhbHVlLmVuZHNXaXRoKCcuanNvbicpKSB8fFxyXG4gICAgICAgICAgICAgICh2YWx1ZS5sZW5ndGggPj0gNSAmJiB2YWx1ZS5lbmRzV2l0aCgnLnN2ZycpKSB8fFxyXG4gICAgICAgICAgICAgIFsndW5kZWZpbmVkJywgJ251bGwnLCAnJ10uaW5jbHVkZXModmFsdWUpLFxyXG4gICAgICAgICAgICB7XHJcbiAgICAgICAgICAgICAgcGFyYW1zOiB7XHJcbiAgICAgICAgICAgICAgICBlcnJvck1lc3NhZ2U6XHJcbiAgICAgICAgICAgICAgICAgICdUaGUgdmFsdWUgbXVzdCBiZSBhIHN0cmluZyB0aGF0IGVuZHMgd2l0aCAuanNvbiBvciAuc3ZnJ1xyXG4gICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgfVxyXG4gICAgICAgICAgKVxyXG4gICAgICAgICAgLnRyYW5zZm9ybSgodmFsdWUpID0+XHJcbiAgICAgICAgICAgICFbJ3VuZGVmaW5lZCcsICdudWxsJywgJyddLmluY2x1ZGVzKHZhbHVlKSA/IHZhbHVlIDogbnVsbFxyXG4gICAgICAgICAgKVxyXG4gICAgICAgICAgLm51bGxhYmxlKCk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGBpbnN0cmAgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGUgc2FtZSB3b3JrIGFzIHRoZSBgb3B0aW9uc2AgdmFsaWRhdG9yLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIGluc3RyXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9IEEgWm9kIHNjaGVtYSBvYmplY3QgZm9yIHZhbGlkYXRpbmcgdGhlIGBpbnN0cmBcclxuICAgKiBvcHRpb24uXHJcbiAgICovXHJcbiAgaW5zdHIoKSB7XHJcbiAgICByZXR1cm4gdi5jaGFydENvbmZpZygpO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgb3B0aW9uc2AgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGUgc2FtZSB3b3JrIGFzIHRoZSBgb3B0aW9uc2AgdmFsaWRhdG9yLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIG9wdGlvbnNcclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZyB0aGUgYG9wdGlvbnNgXHJcbiAgICogb3B0aW9uLlxyXG4gICAqL1xyXG4gIG9wdGlvbnMoKSB7XHJcbiAgICByZXR1cm4gdi5jaGFydENvbmZpZygpO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgc3ZnYCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYS5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoYXQgdGhlIHNjaGVtYSB3aWxsIGFjY2VwdCBvYmplY3QgdmFsdWVzXHJcbiAgICogb3IgdHJpbW1lZCBzdHJpbmcgdmFsdWVzIHRoYXQgY29udGFpbiAnPHN2Zycgb3IgJzw/eG1sJyBlbGVtZW50cyBhbmQgbnVsbC5cclxuICAgKiBUaGUgJ3VuZGVmaW5lZCcsICdudWxsJywgYW5kICcnIHZhbHVlcyB3aWxsIGJlIHRyYW5zZm9ybWVkIHRvIG51bGwuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gc3ZnXHJcbiAgICpcclxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IHN0cmljdENoZWNrIC0gRGV0ZXJtaW5lcyBpZiBzdHJpY3RlciB2YWxpZGF0aW9uIHNob3VsZFxyXG4gICAqIGJlIGFwcGxpZWQuXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9IEEgWm9kIHNjaGVtYSBvYmplY3QgZm9yIHZhbGlkYXRpbmcgdGhlIGBzdmdgIG9wdGlvbi5cclxuICAgKi9cclxuICBzdmcoKSB7XHJcbiAgICByZXR1cm4gelxyXG4gICAgICAuc3RyaW5nKClcclxuICAgICAgLnRyaW0oKVxyXG4gICAgICAucmVmaW5lKFxyXG4gICAgICAgICh2YWx1ZSkgPT5cclxuICAgICAgICAgIHZhbHVlLmluZGV4T2YoJzxzdmcnKSA+PSAwIHx8XHJcbiAgICAgICAgICB2YWx1ZS5pbmRleE9mKCc8P3htbCcpID49IDAgfHxcclxuICAgICAgICAgIFsnZmFsc2UnLCAndW5kZWZpbmVkJywgJ251bGwnLCAnJ10uaW5jbHVkZXModmFsdWUpLFxyXG4gICAgICAgIHtcclxuICAgICAgICAgIHBhcmFtczoge1xyXG4gICAgICAgICAgICBlcnJvck1lc3NhZ2U6XHJcbiAgICAgICAgICAgICAgXCJUaGUgdmFsdWUgbXVzdCBiZSBhIHN0cmluZyB0aGF0IGNvbnRhaW5zICc8c3ZnJyBvciAnPD94bWwnXCJcclxuICAgICAgICAgIH1cclxuICAgICAgICB9XHJcbiAgICAgIClcclxuICAgICAgLnRyYW5zZm9ybSgodmFsdWUpID0+XHJcbiAgICAgICAgIVsnZmFsc2UnLCAndW5kZWZpbmVkJywgJ251bGwnLCAnJ10uaW5jbHVkZXModmFsdWUpID8gdmFsdWUgOiBudWxsXHJcbiAgICAgIClcclxuICAgICAgLm51bGxhYmxlKCk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGBvdXRmaWxlYCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoIGFuIG9wdGlvbmFsIHN0cmljdGVyXHJcbiAgICogY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhhdDpcclxuICAgKlxyXG4gICAqIC0gV2hlbiBgc3RyaWN0Q2hlY2tgIGlzIHRydWUsIHRoZSBzY2hlbWEgd2lsbCBhY2NlcHQgdHJpbW1lZCBzdHJpbmcgdmFsdWVzXHJcbiAgICogdGhhdCBlbmQgd2l0aCAnLmpwZWcnLCAnLmpwZycsICcucG5nJywgJy5wZGYnLCBvciAnLnN2ZycsIGFyZSBhdCBsZWFzdCBvbmVcclxuICAgKiBjaGFyYWN0ZXIgbG9uZyBleGNsdWRpbmcgdGhlIGV4dGVuc2lvbiwgb3IgbnVsbC5cclxuICAgKlxyXG4gICAqIC0gV2hlbiBgc3RyaWN0Q2hlY2tgIGlzIGZhbHNlLCB0aGUgc2NoZW1hIHdpbGwgYWNjZXB0IHRyaW1tZWQgc3RyaW5nIHZhbHVlc1xyXG4gICAqIHRoYXQgZW5kIHdpdGggJy5qcGVnJywgJy5qcGcnLCAnLnBuZycsICcucGRmJywgb3IgJy5zdmcnLCBhcmUgYXQgbGVhc3Qgb25lXHJcbiAgICogY2hhcmFjdGVyIGxvbmcgZXhjbHVkaW5nIHRoZSBleHRlbnNpb24gYW5kIHdpbGwgYmUgbnVsbCBpZiB0aGUgcHJvdmlkZWRcclxuICAgKiB2YWx1ZSBpcyBudWxsLCAndW5kZWZpbmVkJywgJ251bGwnLCBvciAnJy5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiBvdXRmaWxlXHJcbiAgICpcclxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IHN0cmljdENoZWNrIC0gRGV0ZXJtaW5lcyBpZiBzdHJpY3RlciB2YWxpZGF0aW9uIHNob3VsZFxyXG4gICAqIGJlIGFwcGxpZWQuXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9IEEgWm9kIHNjaGVtYSBvYmplY3QgZm9yIHZhbGlkYXRpbmcgdGhlIGBvdXRmaWxlYFxyXG4gICAqIG9wdGlvbi5cclxuICAgKi9cclxuICBvdXRmaWxlKHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gc3RyaWN0Q2hlY2tcclxuICAgICAgPyB6XHJcbiAgICAgICAgICAuc3RyaW5nKClcclxuICAgICAgICAgIC50cmltKClcclxuICAgICAgICAgIC5yZWZpbmUoXHJcbiAgICAgICAgICAgICh2YWx1ZSkgPT5cclxuICAgICAgICAgICAgICAodmFsdWUubGVuZ3RoID49IDYgJiYgdmFsdWUuZW5kc1dpdGgoJy5qcGVnJykpIHx8XHJcbiAgICAgICAgICAgICAgKHZhbHVlLmxlbmd0aCA+PSA1ICYmXHJcbiAgICAgICAgICAgICAgICAodmFsdWUuZW5kc1dpdGgoJy5qcGcnKSB8fFxyXG4gICAgICAgICAgICAgICAgICB2YWx1ZS5lbmRzV2l0aCgnLnBuZycpIHx8XHJcbiAgICAgICAgICAgICAgICAgIHZhbHVlLmVuZHNXaXRoKCcucGRmJykgfHxcclxuICAgICAgICAgICAgICAgICAgdmFsdWUuZW5kc1dpdGgoJy5zdmcnKSkpLFxyXG4gICAgICAgICAgICB7XHJcbiAgICAgICAgICAgICAgcGFyYW1zOiB7XHJcbiAgICAgICAgICAgICAgICBlcnJvck1lc3NhZ2U6XHJcbiAgICAgICAgICAgICAgICAgICdUaGUgdmFsdWUgbXVzdCBiZSBhIHN0cmluZyB0aGF0IGVuZHMgd2l0aCAuanBlZywgLmpwZywgLnBuZywgLnBkZiwgb3IgLnN2ZydcclxuICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgIH1cclxuICAgICAgICAgIClcclxuICAgICAgICAgIC5udWxsYWJsZSgpXHJcbiAgICAgIDogelxyXG4gICAgICAgICAgLnN0cmluZygpXHJcbiAgICAgICAgICAudHJpbSgpXHJcbiAgICAgICAgICAucmVmaW5lKFxyXG4gICAgICAgICAgICAodmFsdWUpID0+XHJcbiAgICAgICAgICAgICAgKHZhbHVlLmxlbmd0aCA+PSA2ICYmIHZhbHVlLmVuZHNXaXRoKCcuanBlZycpKSB8fFxyXG4gICAgICAgICAgICAgICh2YWx1ZS5sZW5ndGggPj0gNSAmJlxyXG4gICAgICAgICAgICAgICAgKHZhbHVlLmVuZHNXaXRoKCcuanBnJykgfHxcclxuICAgICAgICAgICAgICAgICAgdmFsdWUuZW5kc1dpdGgoJy5wbmcnKSB8fFxyXG4gICAgICAgICAgICAgICAgICB2YWx1ZS5lbmRzV2l0aCgnLnBkZicpIHx8XHJcbiAgICAgICAgICAgICAgICAgIHZhbHVlLmVuZHNXaXRoKCcuc3ZnJykpKSB8fFxyXG4gICAgICAgICAgICAgIFsndW5kZWZpbmVkJywgJ251bGwnLCAnJ10uaW5jbHVkZXModmFsdWUpLFxyXG4gICAgICAgICAgICB7XHJcbiAgICAgICAgICAgICAgcGFyYW1zOiB7XHJcbiAgICAgICAgICAgICAgICBlcnJvck1lc3NhZ2U6XHJcbiAgICAgICAgICAgICAgICAgICdUaGUgdmFsdWUgbXVzdCBiZSBhIHN0cmluZyB0aGF0IGVuZHMgd2l0aCAuanBlZywgLmpwZywgLnBuZywgLnBkZiwgb3IgLnN2ZydcclxuICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgIH1cclxuICAgICAgICAgIClcclxuICAgICAgICAgIC50cmFuc2Zvcm0oKHZhbHVlKSA9PlxyXG4gICAgICAgICAgICAhWyd1bmRlZmluZWQnLCAnbnVsbCcsICcnXS5pbmNsdWRlcyh2YWx1ZSkgPyB2YWx1ZSA6IG51bGxcclxuICAgICAgICAgIClcclxuICAgICAgICAgIC5udWxsYWJsZSgpO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgdHlwZWAgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbCBzdHJpY3RlclxyXG4gICAqIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgdGhlIGBlbnVtYCB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gdHlwZVxyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nIHRoZSBgdHlwZWBcclxuICAgKiBvcHRpb24uXHJcbiAgICovXHJcbiAgdHlwZShzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHYuZW51bShbJ2pwZWcnLCAnanBnJywgJ3BuZycsICdwZGYnLCAnc3ZnJ10sIHN0cmljdENoZWNrKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYGNvbnN0cmAgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbCBzdHJpY3RlclxyXG4gICAqIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgdGhlIGBlbnVtYCB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gY29uc3RyXHJcbiAgICpcclxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IHN0cmljdENoZWNrIC0gRGV0ZXJtaW5lcyBpZiBzdHJpY3RlciB2YWxpZGF0aW9uIHNob3VsZFxyXG4gICAqIGJlIGFwcGxpZWQuXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9IEEgWm9kIHNjaGVtYSBvYmplY3QgZm9yIHZhbGlkYXRpbmcgdGhlIGBjb25zdHJgXHJcbiAgICogb3B0aW9uLlxyXG4gICAqL1xyXG4gIGNvbnN0cihzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHYuZW51bShcclxuICAgICAgWydjaGFydCcsICdzdG9ja0NoYXJ0JywgJ21hcENoYXJ0JywgJ2dhbnR0Q2hhcnQnXSxcclxuICAgICAgc3RyaWN0Q2hlY2tcclxuICAgICk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGBiNjRgIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGggYW4gb3B0aW9uYWwgc3RyaWN0ZXJcclxuICAgKiBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGUgc2FtZSB3b3JrIGFzIHRoZSBgYm9vbGVhbmAgdmFsaWRhdG9yLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIGI2NFxyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nIHRoZSBgYjY0YCBvcHRpb24uXHJcbiAgICovXHJcbiAgYjY0KHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gdi5ib29sZWFuKHN0cmljdENoZWNrKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYG5vRG93bmxvYWRgIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGggYW4gb3B0aW9uYWxcclxuICAgKiBzdHJpY3RlciBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGUgc2FtZSB3b3JrIGFzIHRoZSBgYm9vbGVhbmAgdmFsaWRhdG9yLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIG5vRG93bmxvYWRcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZyB0aGUgYG5vRG93bmxvYWRgXHJcbiAgICogb3B0aW9uLlxyXG4gICAqL1xyXG4gIG5vRG93bmxvYWQoc3RyaWN0Q2hlY2spIHtcclxuICAgIHJldHVybiB2LmJvb2xlYW4oc3RyaWN0Q2hlY2spO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgZGVmYXVsdEhlaWdodGAgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbFxyXG4gICAqIHN0cmljdGVyIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgdGhlIGBwb3NpdGl2ZU51bWAgdmFsaWRhdG9yLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIGRlZmF1bHRIZWlnaHRcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZ1xyXG4gICAqIHRoZSBgZGVmYXVsdEhlaWdodGAgb3B0aW9uLlxyXG4gICAqL1xyXG4gIGRlZmF1bHRIZWlnaHQoc3RyaWN0Q2hlY2spIHtcclxuICAgIHJldHVybiB2LnBvc2l0aXZlTnVtKHN0cmljdENoZWNrKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYGRlZmF1bHRXaWR0aGAgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbFxyXG4gICAqIHN0cmljdGVyIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgdGhlIGBwb3NpdGl2ZU51bWAgdmFsaWRhdG9yLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIGRlZmF1bHRXaWR0aFxyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nXHJcbiAgICogdGhlIGBkZWZhdWx0V2lkdGhgIG9wdGlvbi5cclxuICAgKi9cclxuICBkZWZhdWx0V2lkdGgoc3RyaWN0Q2hlY2spIHtcclxuICAgIHJldHVybiB2LnBvc2l0aXZlTnVtKHN0cmljdENoZWNrKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYGRlZmF1bHRTY2FsZWAgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbFxyXG4gICAqIHN0cmljdGVyIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoYXQ6XHJcbiAgICpcclxuICAgKiAtIFdoZW4gYHN0cmljdENoZWNrYCBpcyB0cnVlLCB0aGUgc2NoZW1hIHdpbGwgYWNjZXB0IG51bWJlciB2YWx1ZXMgdGhhdFxyXG4gICAqIGFyZSBiZXR3ZWVuIDAuMSBhbmQgNSAoaW5jbHVzaXZlKS5cclxuICAgKlxyXG4gICAqIC0gV2hlbiBgc3RyaWN0Q2hlY2tgIGlzIGZhbHNlLCB0aGUgc2NoZW1hIHdpbGwgYWNjZXB0IG51bWJlciB2YWx1ZXNcclxuICAgKiBhbmQgc3RyaW5naWZpZWQgbnVtYmVyIHZhbHVlcyB0aGF0IGFyZSBiZXR3ZWVuIDAuMSBhbmQgNSAoaW5jbHVzaXZlKSwgbnVsbCxcclxuICAgKiAndW5kZWZpbmVkJywgJ251bGwnLCBhbmQgJycgd2hpY2ggd2lsbCBiZSB0cmFuc2Zvcm1lZCB0byBudWxsLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIGRlZmF1bHRTY2FsZVxyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nXHJcbiAgICogdGhlIGBkZWZhdWx0U2NhbGVgIG9wdGlvbi5cclxuICAgKi9cclxuICBkZWZhdWx0U2NhbGUoc3RyaWN0Q2hlY2spIHtcclxuICAgIHJldHVybiBzdHJpY3RDaGVja1xyXG4gICAgICA/IHoubnVtYmVyKCkuZ3RlKDAuMSkubHRlKDUpXHJcbiAgICAgIDogelxyXG4gICAgICAgICAgLnVuaW9uKFtcclxuICAgICAgICAgICAgelxyXG4gICAgICAgICAgICAgIC5zdHJpbmcoKVxyXG4gICAgICAgICAgICAgIC50cmltKClcclxuICAgICAgICAgICAgICAucmVmaW5lKFxyXG4gICAgICAgICAgICAgICAgKHZhbHVlKSA9PlxyXG4gICAgICAgICAgICAgICAgICAoIWlzTmFOKE51bWJlcih2YWx1ZSkpICYmXHJcbiAgICAgICAgICAgICAgICAgICAgdmFsdWUgIT09IHRydWUgJiZcclxuICAgICAgICAgICAgICAgICAgICAhdmFsdWUuc3RhcnRzV2l0aCgnWycpICYmXHJcbiAgICAgICAgICAgICAgICAgICAgTnVtYmVyKHZhbHVlKSA+PSAwLjEgJiZcclxuICAgICAgICAgICAgICAgICAgICBOdW1iZXIodmFsdWUpIDw9IDUpIHx8XHJcbiAgICAgICAgICAgICAgICAgIFsndW5kZWZpbmVkJywgJ251bGwnLCAnJ10uaW5jbHVkZXModmFsdWUpLFxyXG4gICAgICAgICAgICAgICAge1xyXG4gICAgICAgICAgICAgICAgICBwYXJhbXM6IHtcclxuICAgICAgICAgICAgICAgICAgICBlcnJvck1lc3NhZ2U6ICdUaGUgdmFsdWUgbXVzdCBiZSB3aXRoaW4gYSAwLjEgYW5kIDUuMCByYW5nZSdcclxuICAgICAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICAgIClcclxuICAgICAgICAgICAgICAudHJhbnNmb3JtKCh2YWx1ZSkgPT5cclxuICAgICAgICAgICAgICAgICFbJ3VuZGVmaW5lZCcsICdudWxsJywgJyddLmluY2x1ZGVzKHZhbHVlKVxyXG4gICAgICAgICAgICAgICAgICA/IE51bWJlcih2YWx1ZSlcclxuICAgICAgICAgICAgICAgICAgOiBudWxsXHJcbiAgICAgICAgICAgICAgKSxcclxuICAgICAgICAgICAgei5udW1iZXIoKS5ndGUoMC4xKS5sdGUoNSlcclxuICAgICAgICAgIF0pXHJcbiAgICAgICAgICAubnVsbGFibGUoKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYGhlaWdodGAgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbCBzdHJpY3RlclxyXG4gICAqIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgYSBudWxsYWJsZSBgZGVmYXVsdEhlaWdodGBcclxuICAgKiB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gaGVpZ2h0XHJcbiAgICpcclxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IHN0cmljdENoZWNrIC0gRGV0ZXJtaW5lcyBpZiBzdHJpY3RlciB2YWxpZGF0aW9uIHNob3VsZFxyXG4gICAqIGJlIGFwcGxpZWQuXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9IEEgWm9kIHNjaGVtYSBvYmplY3QgZm9yIHZhbGlkYXRpbmcgdGhlIGBoZWlnaHRgXHJcbiAgICogb3B0aW9uLlxyXG4gICAqL1xyXG4gIGhlaWdodChzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHRoaXMuZGVmYXVsdEhlaWdodChzdHJpY3RDaGVjaykubnVsbGFibGUoKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYHdpZHRoYCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoIGFuIG9wdGlvbmFsIHN0cmljdGVyXHJcbiAgICogY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhlIHNhbWUgd29yayBhcyBhIG51bGxhYmxlIGBkZWZhdWx0V2lkdGhgXHJcbiAgICogdmFsaWRhdG9yLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIHdpZHRoXHJcbiAgICpcclxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IHN0cmljdENoZWNrIC0gRGV0ZXJtaW5lcyBpZiBzdHJpY3RlciB2YWxpZGF0aW9uIHNob3VsZFxyXG4gICAqIGJlIGFwcGxpZWQuXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9IEEgWm9kIHNjaGVtYSBvYmplY3QgZm9yIHZhbGlkYXRpbmcgdGhlIGB3aWR0aGBcclxuICAgKiBvcHRpb24uXHJcbiAgICovXHJcbiAgd2lkdGgoc3RyaWN0Q2hlY2spIHtcclxuICAgIHJldHVybiB0aGlzLmRlZmF1bHRXaWR0aChzdHJpY3RDaGVjaykubnVsbGFibGUoKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYHNjYWxlYCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoIGFuIG9wdGlvbmFsIHN0cmljdGVyXHJcbiAgICogY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhlIHNhbWUgd29yayBhcyBhIG51bGxhYmxlIGBkZWZhdWx0U2NhbGVgXHJcbiAgICogdmFsaWRhdG9yLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIHNjYWxlXHJcbiAgICpcclxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IHN0cmljdENoZWNrIC0gRGV0ZXJtaW5lcyBpZiBzdHJpY3RlciB2YWxpZGF0aW9uIHNob3VsZFxyXG4gICAqIGJlIGFwcGxpZWQuXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9IEEgWm9kIHNjaGVtYSBvYmplY3QgZm9yIHZhbGlkYXRpbmcgdGhlIGBzY2FsZWBcclxuICAgKiBvcHRpb24uXHJcbiAgICovXHJcbiAgc2NhbGUoc3RyaWN0Q2hlY2spIHtcclxuICAgIHJldHVybiB0aGlzLmRlZmF1bHRTY2FsZShzdHJpY3RDaGVjaykubnVsbGFibGUoKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYGdsb2JhbE9wdGlvbnNgIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhlIHNhbWUgd29yayBhcyB0aGUgYGFkZGl0aW9uYWxPcHRpb25zYFxyXG4gICAqIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiBnbG9iYWxPcHRpb25zXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9IEEgWm9kIHNjaGVtYSBvYmplY3QgZm9yIHZhbGlkYXRpbmdcclxuICAgKiB0aGUgYGdsb2JhbE9wdGlvbnNgIG9wdGlvbi5cclxuICAgKi9cclxuICBnbG9iYWxPcHRpb25zKCkge1xyXG4gICAgcmV0dXJuIHYuYWRkaXRpb25hbE9wdGlvbnMoKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYHRoZW1lT3B0aW9uc2AgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGUgc2FtZSB3b3JrIGFzIHRoZSBgYWRkaXRpb25hbE9wdGlvbnNgXHJcbiAgICogdmFsaWRhdG9yLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIHRoZW1lT3B0aW9uc1xyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nXHJcbiAgICogdGhlIGB0aGVtZU9wdGlvbnNgIG9wdGlvbi5cclxuICAgKi9cclxuICB0aGVtZU9wdGlvbnMoKSB7XHJcbiAgICByZXR1cm4gdi5hZGRpdGlvbmFsT3B0aW9ucygpO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgYmF0Y2hgIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGggYW4gb3B0aW9uYWwgc3RyaWN0ZXJcclxuICAgKiBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGUgc2FtZSB3b3JrIGFzIHRoZSBgc3RyaW5nYCB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gYmF0Y2hcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZyB0aGUgYGJhdGNoYFxyXG4gICAqIG9wdGlvbi5cclxuICAgKi9cclxuICBiYXRjaChzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHYuc3RyaW5nKHN0cmljdENoZWNrKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYHJhc3Rlcml6YXRpb25UaW1lb3V0YCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoXHJcbiAgICogYW4gb3B0aW9uYWwgc3RyaWN0ZXIgY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhlIHNhbWUgd29yayBhcyB0aGUgYG5vbk5lZ2F0aXZlTnVtYFxyXG4gICAqIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiByYXN0ZXJpemF0aW9uVGltZW91dFxyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nXHJcbiAgICogdGhlIGByYXN0ZXJpemF0aW9uVGltZW91dGAgb3B0aW9uLlxyXG4gICAqL1xyXG4gIHJhc3Rlcml6YXRpb25UaW1lb3V0KHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gdi5ub25OZWdhdGl2ZU51bShzdHJpY3RDaGVjayk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGBhbGxvd0NvZGVFeGVjdXRpb25gIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGhcclxuICAgKiBhbiBvcHRpb25hbCBzdHJpY3RlciBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGUgc2FtZSB3b3JrIGFzIHRoZSBgYm9vbGVhbmAgdmFsaWRhdG9yLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIGFsbG93Q29kZUV4ZWN1dGlvblxyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nXHJcbiAgICogdGhlIGBhbGxvd0NvZGVFeGVjdXRpb25gIG9wdGlvbi5cclxuICAgKi9cclxuICBhbGxvd0NvZGVFeGVjdXRpb24oc3RyaWN0Q2hlY2spIHtcclxuICAgIHJldHVybiB2LmJvb2xlYW4oc3RyaWN0Q2hlY2spO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgYWxsb3dGaWxlUmVzb3VyY2VzYCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoXHJcbiAgICogYW4gb3B0aW9uYWwgc3RyaWN0ZXIgY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhlIHNhbWUgd29yayBhcyB0aGUgYGJvb2xlYW5gIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiBhbGxvd0ZpbGVSZXNvdXJjZXNcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZ1xyXG4gICAqIHRoZSBgYWxsb3dGaWxlUmVzb3VyY2VzYCBvcHRpb24uXHJcbiAgICovXHJcbiAgYWxsb3dGaWxlUmVzb3VyY2VzKHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gdi5ib29sZWFuKHN0cmljdENoZWNrKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYGN1c3RvbUNvZGVgIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGggYW4gb3B0aW9uYWxcclxuICAgKiBzdHJpY3RlciBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGUgc2FtZSB3b3JrIGFzIHRoZSBgc3RyaW5nYCB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gY3VzdG9tQ29kZVxyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nIHRoZSBgY3VzdG9tQ29kZWBcclxuICAgKiBvcHRpb24uXHJcbiAgICovXHJcbiAgY3VzdG9tQ29kZShzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHYuc3RyaW5nKHN0cmljdENoZWNrKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYGNhbGxiYWNrYCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoIGFuIG9wdGlvbmFsXHJcbiAgICogc3RyaWN0ZXIgY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhlIHNhbWUgd29yayBhcyB0aGUgYHN0cmluZ2AgdmFsaWRhdG9yLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIGNhbGxiYWNrXHJcbiAgICpcclxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IHN0cmljdENoZWNrIC0gRGV0ZXJtaW5lcyBpZiBzdHJpY3RlciB2YWxpZGF0aW9uIHNob3VsZFxyXG4gICAqIGJlIGFwcGxpZWQuXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9IEEgWm9kIHNjaGVtYSBvYmplY3QgZm9yIHZhbGlkYXRpbmcgdGhlIGBjYWxsYmFja2BcclxuICAgKiBvcHRpb24uXHJcbiAgICovXHJcbiAgY2FsbGJhY2soc3RyaWN0Q2hlY2spIHtcclxuICAgIHJldHVybiB2LnN0cmluZyhzdHJpY3RDaGVjayk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGByZXNvdXJjZXNgIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGggYW4gb3B0aW9uYWxcclxuICAgKiBzdHJpY3RlciBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGF0OlxyXG4gICAqXHJcbiAgICogLSBXaGVuIGBzdHJpY3RDaGVja2AgaXMgdHJ1ZSwgdGhlIHNjaGVtYSB3aWxsIGFjY2VwdCBhIHBhcnRpYWwgb2JqZWN0XHJcbiAgICogd2l0aCBhbGxvd2VkIHByb3BlcnRpZXMgYGpzYCwgYGNzc2AsIGFuZCBgZmlsZXNgIHdoZXJlIGVhY2ggb2YgdGhlIGFsbG93ZWRcclxuICAgKiBwcm9wZXJ0aWVzIGNhbiBiZSBudWxsLCBzdHJpbmdpZmllZCB2ZXJzaW9uIG9mIHRoZSBvYmplY3QsIHN0cmluZyB0aGF0IGVuZHNcclxuICAgKiB3aXRoIHRoZSAnLmpzb24nLCBhbmQgbnVsbC5cclxuICAgKlxyXG4gICAqIC0gV2hlbiBgc3RyaWN0Q2hlY2tgIGlzIGZhbHNlLCB0aGUgc2NoZW1hIHdpbGwgYWNjZXB0IGEgc3RyaW5naWZpZWQgdmVyc2lvblxyXG4gICAqIG9mIGEgcGFydGlhbCBvYmplY3Qgd2l0aCBhbGxvd2VkIHByb3BlcnRpZXMgYGpzYCwgYGNzc2AsIGFuZCBgZmlsZXNgIHdoZXJlXHJcbiAgICogZWFjaCBvZiB0aGUgYWxsb3dlZCBwcm9wZXJ0aWVzIGNhbiBiZSBudWxsLCBzdHJpbmcgdGhhdCBlbmRzIHdpdGggdGhlXHJcbiAgICogJy5qc29uJywgYW5kIHdpbGwgYmUgbnVsbCBpZiB0aGUgcHJvdmlkZWQgdmFsdWUgaXMgJ3VuZGVmaW5lZCcsICdudWxsJ1xyXG4gICAqIG9yICcnLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIHJlc291cmNlc1xyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nIHRoZSBgcmVzb3VyY2VzYFxyXG4gICAqIG9wdGlvbi5cclxuICAgKi9cclxuICByZXNvdXJjZXMoc3RyaWN0Q2hlY2spIHtcclxuICAgIGNvbnN0IG9iamVjdFNjaGVtYSA9IHpcclxuICAgICAgLm9iamVjdCh7XHJcbiAgICAgICAganM6IHYuc3RyaW5nKGZhbHNlKSxcclxuICAgICAgICBjc3M6IHYuc3RyaW5nKGZhbHNlKSxcclxuICAgICAgICBmaWxlczogdlxyXG4gICAgICAgICAgLnN0cmluZ0FycmF5KFxyXG4gICAgICAgICAgICAodmFsdWUpID0+ICFbJ3VuZGVmaW5lZCcsICdudWxsJywgJyddLmluY2x1ZGVzKHZhbHVlKSxcclxuICAgICAgICAgICAgJywnLFxyXG4gICAgICAgICAgICB0cnVlXHJcbiAgICAgICAgICApXHJcbiAgICAgICAgICAubnVsbGFibGUoKVxyXG4gICAgICB9KVxyXG4gICAgICAucGFydGlhbCgpO1xyXG5cclxuICAgIGNvbnN0IHN0cmluZ1NjaGVtYTEgPSB6XHJcbiAgICAgIC5zdHJpbmcoKVxyXG4gICAgICAudHJpbSgpXHJcbiAgICAgIC5yZWZpbmUoXHJcbiAgICAgICAgKHZhbHVlKSA9PlxyXG4gICAgICAgICAgKHZhbHVlLnN0YXJ0c1dpdGgoJ3snKSAmJiB2YWx1ZS5lbmRzV2l0aCgnfScpKSB8fFxyXG4gICAgICAgICAgKHZhbHVlLmxlbmd0aCA+PSA2ICYmIHZhbHVlLmVuZHNXaXRoKCcuanNvbicpKSxcclxuICAgICAgICB7XHJcbiAgICAgICAgICBwYXJhbXM6IHtcclxuICAgICAgICAgICAgZXJyb3JNZXNzYWdlOlxyXG4gICAgICAgICAgICAgIFwiVGhlIHZhbHVlIG11c3QgYmUgYSBzdHJpbmcgdGhhdCBzdGFydHMgd2l0aCAneycgYW5kIGVuZHMgd2l0aCAnfVwiXHJcbiAgICAgICAgICB9XHJcbiAgICAgICAgfVxyXG4gICAgICApO1xyXG5cclxuICAgIGNvbnN0IHN0cmluZ1NjaGVtYTIgPSB6XHJcbiAgICAgIC5zdHJpbmcoKVxyXG4gICAgICAudHJpbSgpXHJcbiAgICAgIC5yZWZpbmUoXHJcbiAgICAgICAgKHZhbHVlKSA9PlxyXG4gICAgICAgICAgKHZhbHVlLnN0YXJ0c1dpdGgoJ3snKSAmJiB2YWx1ZS5lbmRzV2l0aCgnfScpKSB8fFxyXG4gICAgICAgICAgKHZhbHVlLmxlbmd0aCA+PSA2ICYmIHZhbHVlLmVuZHNXaXRoKCcuanNvbicpKSB8fFxyXG4gICAgICAgICAgWyd1bmRlZmluZWQnLCAnbnVsbCcsICcnXS5pbmNsdWRlcyh2YWx1ZSksXHJcbiAgICAgICAge1xyXG4gICAgICAgICAgcGFyYW1zOiB7XHJcbiAgICAgICAgICAgIGVycm9yTWVzc2FnZTogJ1RoZSB2YWx1ZSBtdXN0IGJlIGEgc3RyaW5nIHRoYXQgZW5kcyB3aXRoIC5qc29uJ1xyXG4gICAgICAgICAgfVxyXG4gICAgICAgIH1cclxuICAgICAgKVxyXG4gICAgICAudHJhbnNmb3JtKCh2YWx1ZSkgPT5cclxuICAgICAgICAhWyd1bmRlZmluZWQnLCAnbnVsbCcsICcnXS5pbmNsdWRlcyh2YWx1ZSkgPyB2YWx1ZSA6IG51bGxcclxuICAgICAgKTtcclxuXHJcbiAgICByZXR1cm4gc3RyaWN0Q2hlY2tcclxuICAgICAgPyB6LnVuaW9uKFtvYmplY3RTY2hlbWEsIHN0cmluZ1NjaGVtYTFdKS5udWxsYWJsZSgpXHJcbiAgICAgIDogei51bmlvbihbb2JqZWN0U2NoZW1hLCBzdHJpbmdTY2hlbWEyXSkubnVsbGFibGUoKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYGxvYWRDb25maWdgIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGggYW4gb3B0aW9uYWxcclxuICAgKiBzdHJpY3RlciBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGUgc2FtZSB3b3JrIGFzIHRoZSBgc3RyaW5nYCB2YWxpZGF0b3IuXHJcbiAgICogQWRkaXRpb25hbGx5LCBpdCBtdXN0IGJlIGEgc3RyaW5nIHRoYXQgZW5kcyB3aXRoICcuanNvbicuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gbG9hZENvbmZpZ1xyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nIHRoZSBgbG9hZENvbmZpZ2BcclxuICAgKiBvcHRpb24uXHJcbiAgICovXHJcbiAgbG9hZENvbmZpZyhzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHZcclxuICAgICAgLnN0cmluZyhzdHJpY3RDaGVjaylcclxuICAgICAgLnJlZmluZShcclxuICAgICAgICAodmFsdWUpID0+XHJcbiAgICAgICAgICB2YWx1ZSA9PT0gbnVsbCB8fCAodmFsdWUubGVuZ3RoID49IDYgJiYgdmFsdWUuZW5kc1dpdGgoJy5qc29uJykpLFxyXG4gICAgICAgIHtcclxuICAgICAgICAgIHBhcmFtczoge1xyXG4gICAgICAgICAgICBlcnJvck1lc3NhZ2U6ICdUaGUgdmFsdWUgbXVzdCBiZSBhIHN0cmluZyB0aGF0IGVuZHMgd2l0aCAuanNvbidcclxuICAgICAgICAgIH1cclxuICAgICAgICB9XHJcbiAgICAgICk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGBjcmVhdGVDb25maWdgIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGggYW4gb3B0aW9uYWxcclxuICAgKiBzdHJpY3RlciBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGUgc2FtZSB3b3JrIGFzIHRoZSBgbG9hZENvbmZpZ2AgdmFsaWRhdG9yLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIGNyZWF0ZUNvbmZpZ1xyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nXHJcbiAgICogdGhlIGBjcmVhdGVDb25maWdgIG9wdGlvbi5cclxuICAgKi9cclxuICBjcmVhdGVDb25maWcoc3RyaWN0Q2hlY2spIHtcclxuICAgIHJldHVybiB0aGlzLmxvYWRDb25maWcoc3RyaWN0Q2hlY2spO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgZW5hYmxlU2VydmVyYCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoIGFuIG9wdGlvbmFsXHJcbiAgICogc3RyaWN0ZXIgY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhlIHNhbWUgd29yayBhcyB0aGUgYGJvb2xlYW5gIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiBlbmFibGVTZXJ2ZXJcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZ1xyXG4gICAqIHRoZSBgZW5hYmxlU2VydmVyYCBvcHRpb24uXHJcbiAgICovXHJcbiAgZW5hYmxlU2VydmVyKHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gdi5ib29sZWFuKHN0cmljdENoZWNrKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYGhvc3RgIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGggYW4gb3B0aW9uYWwgc3RyaWN0ZXJcclxuICAgKiBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGUgc2FtZSB3b3JrIGFzIHRoZSBgc3RyaW5nYCB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gaG9zdFxyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nIHRoZSBgaG9zdGBcclxuICAgKiBvcHRpb24uXHJcbiAgICovXHJcbiAgaG9zdChzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHYuc3RyaW5nKHN0cmljdENoZWNrKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYHBvcnRgIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGggYW4gb3B0aW9uYWwgc3RyaWN0ZXJcclxuICAgKiBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGUgc2FtZSB3b3JrIGFzIHRoZSBgbm9uTmVnYXRpdmVOdW1gXHJcbiAgICogdmFsaWRhdG9yLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIHBvcnRcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZyB0aGUgYHBvcnRgXHJcbiAgICogb3B0aW9uLlxyXG4gICAqL1xyXG4gIHBvcnQoc3RyaWN0Q2hlY2spIHtcclxuICAgIHJldHVybiB2Lm5vbk5lZ2F0aXZlTnVtKHN0cmljdENoZWNrKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYHVwbG9hZExpbWl0YCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoIGFuIG9wdGlvbmFsXHJcbiAgICogc3RyaWN0ZXIgY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhlIHNhbWUgd29yayBhcyB0aGUgYHBvc2l0aXZlTnVtYCB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gdXBsb2FkTGltaXRcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZyB0aGUgYHVwbG9hZExpbWl0YFxyXG4gICAqIG9wdGlvbi5cclxuICAgKi9cclxuICB1cGxvYWRMaW1pdChzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHYucG9zaXRpdmVOdW0oc3RyaWN0Q2hlY2spO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgc2VydmVyQmVuY2htYXJraW5nYCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoXHJcbiAgICogYW4gb3B0aW9uYWwgc3RyaWN0ZXIgY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhlIHNhbWUgd29yayBhcyB0aGUgYGJvb2xlYW5gIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiBzZXJ2ZXJCZW5jaG1hcmtpbmdcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZ1xyXG4gICAqIHRoZSBgc2VydmVyQmVuY2htYXJraW5nYCBvcHRpb24uXHJcbiAgICovXHJcbiAgc2VydmVyQmVuY2htYXJraW5nKHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gdi5ib29sZWFuKHN0cmljdENoZWNrKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYHByb3h5SG9zdGAgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbFxyXG4gICAqIHN0cmljdGVyIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgdGhlIGBzdHJpbmdgIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiBwcm94eUhvc3RcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZyB0aGUgYHByb3h5SG9zdGBcclxuICAgKiBvcHRpb24uXHJcbiAgICovXHJcbiAgcHJveHlIb3N0KHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gdi5zdHJpbmcoc3RyaWN0Q2hlY2spO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgcHJveHlQb3J0YCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoIGFuIG9wdGlvbmFsXHJcbiAgICogc3RyaWN0ZXIgY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhlIHNhbWUgd29yayBhcyBhIG51bGxhYmxlIGBub25OZWdhdGl2ZU51bWBcclxuICAgKiB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gcHJveHlQb3J0XHJcbiAgICpcclxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IHN0cmljdENoZWNrIC0gRGV0ZXJtaW5lcyBpZiBzdHJpY3RlciB2YWxpZGF0aW9uIHNob3VsZFxyXG4gICAqIGJlIGFwcGxpZWQuXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9IEEgWm9kIHNjaGVtYSBvYmplY3QgZm9yIHZhbGlkYXRpbmcgdGhlIGBwcm94eVBvcnRgXHJcbiAgICogb3B0aW9uLlxyXG4gICAqL1xyXG4gIHByb3h5UG9ydChzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHYubm9uTmVnYXRpdmVOdW0oc3RyaWN0Q2hlY2spLm51bGxhYmxlKCk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGBwcm94eVRpbWVvdXRgIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGggYW4gb3B0aW9uYWxcclxuICAgKiBzdHJpY3RlciBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGUgc2FtZSB3b3JrIGFzIHRoZSBgbm9uTmVnYXRpdmVOdW1gXHJcbiAgICogdmFsaWRhdG9yLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIHByb3h5VGltZW91dFxyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nXHJcbiAgICogdGhlIGBwcm94eVRpbWVvdXRgIG9wdGlvbi5cclxuICAgKi9cclxuICBwcm94eVRpbWVvdXQoc3RyaWN0Q2hlY2spIHtcclxuICAgIHJldHVybiB2Lm5vbk5lZ2F0aXZlTnVtKHN0cmljdENoZWNrKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYGVuYWJsZVJhdGVMaW1pdGluZ2AgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aFxyXG4gICAqIGFuIG9wdGlvbmFsIHN0cmljdGVyIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgdGhlIGBib29sZWFuYCB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gZW5hYmxlUmF0ZUxpbWl0aW5nXHJcbiAgICpcclxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IHN0cmljdENoZWNrIC0gRGV0ZXJtaW5lcyBpZiBzdHJpY3RlciB2YWxpZGF0aW9uIHNob3VsZFxyXG4gICAqIGJlIGFwcGxpZWQuXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9IEEgWm9kIHNjaGVtYSBvYmplY3QgZm9yIHZhbGlkYXRpbmdcclxuICAgKiB0aGUgYGVuYWJsZVJhdGVMaW1pdGluZ2Agb3B0aW9uLlxyXG4gICAqL1xyXG4gIGVuYWJsZVJhdGVMaW1pdGluZyhzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHYuYm9vbGVhbihzdHJpY3RDaGVjayk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGBtYXhSZXF1ZXN0c2AgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbFxyXG4gICAqIHN0cmljdGVyIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgdGhlIGBub25OZWdhdGl2ZU51bWBcclxuICAgKiB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gbWF4UmVxdWVzdHNcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZyB0aGUgYG1heFJlcXVlc3RzYFxyXG4gICAqIG9wdGlvbi5cclxuICAgKi9cclxuICBtYXhSZXF1ZXN0cyhzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHYubm9uTmVnYXRpdmVOdW0oc3RyaWN0Q2hlY2spO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgd2luZG93YCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoIGFuIG9wdGlvbmFsIHN0cmljdGVyXHJcbiAgICogY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhlIHNhbWUgd29yayBhcyB0aGUgYG5vbk5lZ2F0aXZlTnVtYFxyXG4gICAqIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiB3aW5kb3dcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZyB0aGUgYHdpbmRvd2BcclxuICAgKiBvcHRpb24uXHJcbiAgICovXHJcbiAgd2luZG93KHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gdi5ub25OZWdhdGl2ZU51bShzdHJpY3RDaGVjayk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGBkZWxheWAgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbCBzdHJpY3RlclxyXG4gICAqIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgdGhlIGBub25OZWdhdGl2ZU51bWBcclxuICAgKiB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gZGVsYXlcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZyB0aGUgYGRlbGF5YFxyXG4gICAqIG9wdGlvbi5cclxuICAgKi9cclxuICBkZWxheShzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHYubm9uTmVnYXRpdmVOdW0oc3RyaWN0Q2hlY2spO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgdHJ1c3RQcm94eWAgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbFxyXG4gICAqIHN0cmljdGVyIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgdGhlIGBib29sZWFuYCB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gdHJ1c3RQcm94eVxyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nIHRoZSBgdHJ1c3RQcm94eWBcclxuICAgKiBvcHRpb24uXHJcbiAgICovXHJcbiAgdHJ1c3RQcm94eShzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHYuYm9vbGVhbihzdHJpY3RDaGVjayk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGBza2lwS2V5YCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoIGFuIG9wdGlvbmFsIHN0cmljdGVyXHJcbiAgICogY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhlIHNhbWUgd29yayBhcyB0aGUgYHN0cmluZ2AgdmFsaWRhdG9yLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIHNraXBLZXlcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZyB0aGUgYHNraXBLZXlgXHJcbiAgICogb3B0aW9uLlxyXG4gICAqL1xyXG4gIHNraXBLZXkoc3RyaWN0Q2hlY2spIHtcclxuICAgIHJldHVybiB2LnN0cmluZyhzdHJpY3RDaGVjayk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGBza2lwVG9rZW5gIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGggYW4gb3B0aW9uYWxcclxuICAgKiBzdHJpY3RlciBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGUgc2FtZSB3b3JrIGFzIHRoZSBgc3RyaW5nYCB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gc2tpcFRva2VuXHJcbiAgICpcclxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IHN0cmljdENoZWNrIC0gRGV0ZXJtaW5lcyBpZiBzdHJpY3RlciB2YWxpZGF0aW9uIHNob3VsZFxyXG4gICAqIGJlIGFwcGxpZWQuXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9IEEgWm9kIHNjaGVtYSBvYmplY3QgZm9yIHZhbGlkYXRpbmcgdGhlIGBza2lwVG9rZW5gXHJcbiAgICogb3B0aW9uLlxyXG4gICAqL1xyXG4gIHNraXBUb2tlbihzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHYuc3RyaW5nKHN0cmljdENoZWNrKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYGVuYWJsZVNzbGAgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbFxyXG4gICAqIHN0cmljdGVyIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgdGhlIGBib29sZWFuYCB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gZW5hYmxlU3NsXHJcbiAgICpcclxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IHN0cmljdENoZWNrIC0gRGV0ZXJtaW5lcyBpZiBzdHJpY3RlciB2YWxpZGF0aW9uIHNob3VsZFxyXG4gICAqIGJlIGFwcGxpZWQuXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9IEEgWm9kIHNjaGVtYSBvYmplY3QgZm9yIHZhbGlkYXRpbmcgdGhlIGBlbmFibGVTc2xgXHJcbiAgICogb3B0aW9uLlxyXG4gICAqL1xyXG4gIGVuYWJsZVNzbChzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHYuYm9vbGVhbihzdHJpY3RDaGVjayk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGBzc2xGb3JjZWAgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbFxyXG4gICAqIHN0cmljdGVyIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgdGhlIGBib29sZWFuYCB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gc3NsRm9yY2VcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZyB0aGUgYHNzbEZvcmNlYFxyXG4gICAqIG9wdGlvbi5cclxuICAgKi9cclxuICBzc2xGb3JjZShzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHYuYm9vbGVhbihzdHJpY3RDaGVjayk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGBzc2xQb3J0YCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoIGFuIG9wdGlvbmFsIHN0cmljdGVyXHJcbiAgICogY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhlIHNhbWUgd29yayBhcyB0aGUgYG5vbk5lZ2F0aXZlTnVtYFxyXG4gICAqIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiBzc2xQb3J0XHJcbiAgICpcclxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IHN0cmljdENoZWNrIC0gRGV0ZXJtaW5lcyBpZiBzdHJpY3RlciB2YWxpZGF0aW9uIHNob3VsZFxyXG4gICAqIGJlIGFwcGxpZWQuXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9IEEgWm9kIHNjaGVtYSBvYmplY3QgZm9yIHZhbGlkYXRpbmcgdGhlIGBzc2xQb3J0YFxyXG4gICAqIG9wdGlvbi5cclxuICAgKi9cclxuICBzc2xQb3J0KHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gdi5ub25OZWdhdGl2ZU51bShzdHJpY3RDaGVjayk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGBzc2xDZXJ0UGF0aGAgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbFxyXG4gICAqIHN0cmljdGVyIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgdGhlIGBzdHJpbmdgIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiBzc2xDZXJ0UGF0aFxyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nIHRoZSBgc3NsQ2VydFBhdGhgXHJcbiAgICogb3B0aW9uLlxyXG4gICAqL1xyXG4gIHNzbENlcnRQYXRoKHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gdi5zdHJpbmcoc3RyaWN0Q2hlY2spO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgbWluV29ya2Vyc2AgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbFxyXG4gICAqIHN0cmljdGVyIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgdGhlIGBwb3NpdGl2ZU51bWAgdmFsaWRhdG9yLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIG1pbldvcmtlcnNcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZyB0aGUgYG1pbldvcmtlcnNgXHJcbiAgICogb3B0aW9uLlxyXG4gICAqL1xyXG4gIG1pbldvcmtlcnMoc3RyaWN0Q2hlY2spIHtcclxuICAgIHJldHVybiB2LnBvc2l0aXZlTnVtKHN0cmljdENoZWNrKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYG1heFdvcmtlcnNgIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGggYW4gb3B0aW9uYWxcclxuICAgKiBzdHJpY3RlciBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGUgc2FtZSB3b3JrIGFzIHRoZSBgcG9zaXRpdmVOdW1gIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiBtYXhXb3JrZXJzXHJcbiAgICpcclxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IHN0cmljdENoZWNrIC0gRGV0ZXJtaW5lcyBpZiBzdHJpY3RlciB2YWxpZGF0aW9uIHNob3VsZFxyXG4gICAqIGJlIGFwcGxpZWQuXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9IEEgWm9kIHNjaGVtYSBvYmplY3QgZm9yIHZhbGlkYXRpbmcgdGhlIGBtYXhXb3JrZXJzYFxyXG4gICAqIG9wdGlvbi5cclxuICAgKi9cclxuICBtYXhXb3JrZXJzKHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gdi5wb3NpdGl2ZU51bShzdHJpY3RDaGVjayk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGB3b3JrTGltaXRgIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGggYW4gb3B0aW9uYWxcclxuICAgKiBzdHJpY3RlciBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGUgc2FtZSB3b3JrIGFzIHRoZSBgcG9zaXRpdmVOdW1gIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiB3b3JrTGltaXRcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZyB0aGUgYHdvcmtMaW1pdGBcclxuICAgKiBvcHRpb24uXHJcbiAgICovXHJcbiAgd29ya0xpbWl0KHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gdi5wb3NpdGl2ZU51bShzdHJpY3RDaGVjayk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGBhY3F1aXJlVGltZW91dGAgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbFxyXG4gICAqIHN0cmljdGVyIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgdGhlIGBub25OZWdhdGl2ZU51bWBcclxuICAgKiB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gYWNxdWlyZVRpbWVvdXRcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZ1xyXG4gICAqIHRoZSBgYWNxdWlyZVRpbWVvdXRgIG9wdGlvbi5cclxuICAgKi9cclxuICBhY3F1aXJlVGltZW91dChzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHYubm9uTmVnYXRpdmVOdW0oc3RyaWN0Q2hlY2spO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgY3JlYXRlVGltZW91dGAgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbFxyXG4gICAqIHN0cmljdGVyIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgdGhlIGBub25OZWdhdGl2ZU51bWBcclxuICAgKiB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gY3JlYXRlVGltZW91dFxyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nXHJcbiAgICogdGhlIGBjcmVhdGVUaW1lb3V0YCBvcHRpb24uXHJcbiAgICovXHJcbiAgY3JlYXRlVGltZW91dChzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHYubm9uTmVnYXRpdmVOdW0oc3RyaWN0Q2hlY2spO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgZGVzdHJveVRpbWVvdXRgIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGggYW4gb3B0aW9uYWxcclxuICAgKiBzdHJpY3RlciBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGUgc2FtZSB3b3JrIGFzIHRoZSBgbm9uTmVnYXRpdmVOdW1gXHJcbiAgICogdmFsaWRhdG9yLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIGRlc3Ryb3lUaW1lb3V0XHJcbiAgICpcclxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IHN0cmljdENoZWNrIC0gRGV0ZXJtaW5lcyBpZiBzdHJpY3RlciB2YWxpZGF0aW9uIHNob3VsZFxyXG4gICAqIGJlIGFwcGxpZWQuXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9IEEgWm9kIHNjaGVtYSBvYmplY3QgZm9yIHZhbGlkYXRpbmdcclxuICAgKiB0aGUgYGRlc3Ryb3lUaW1lb3V0YCBvcHRpb24uXHJcbiAgICovXHJcbiAgZGVzdHJveVRpbWVvdXQoc3RyaWN0Q2hlY2spIHtcclxuICAgIHJldHVybiB2Lm5vbk5lZ2F0aXZlTnVtKHN0cmljdENoZWNrKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYGlkbGVUaW1lb3V0YCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoIGFuIG9wdGlvbmFsXHJcbiAgICogc3RyaWN0ZXIgY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhlIHNhbWUgd29yayBhcyB0aGUgYG5vbk5lZ2F0aXZlTnVtYFxyXG4gICAqIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiBpZGxlVGltZW91dFxyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nXHJcbiAgICogdGhlIGBpZGxlVGltZW91dGAgb3B0aW9uLlxyXG4gICAqL1xyXG4gIGlkbGVUaW1lb3V0KHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gdi5ub25OZWdhdGl2ZU51bShzdHJpY3RDaGVjayk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGBjcmVhdGVSZXRyeUludGVydmFsYCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoXHJcbiAgICogYW4gb3B0aW9uYWwgc3RyaWN0ZXIgY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhlIHNhbWUgd29yayBhcyB0aGUgYG5vbk5lZ2F0aXZlTnVtYFxyXG4gICAqIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiBjcmVhdGVSZXRyeUludGVydmFsXHJcbiAgICpcclxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IHN0cmljdENoZWNrIC0gRGV0ZXJtaW5lcyBpZiBzdHJpY3RlciB2YWxpZGF0aW9uIHNob3VsZFxyXG4gICAqIGJlIGFwcGxpZWQuXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9IEEgWm9kIHNjaGVtYSBvYmplY3QgZm9yIHZhbGlkYXRpbmdcclxuICAgKiB0aGUgYGNyZWF0ZVJldHJ5SW50ZXJ2YWxgIG9wdGlvbi5cclxuICAgKi9cclxuICBjcmVhdGVSZXRyeUludGVydmFsKHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gdi5ub25OZWdhdGl2ZU51bShzdHJpY3RDaGVjayk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGByZWFwZXJJbnRlcnZhbGAgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbFxyXG4gICAqIHN0cmljdGVyIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgdGhlIGBub25OZWdhdGl2ZU51bWBcclxuICAgKiB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gcmVhcGVySW50ZXJ2YWxcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZ1xyXG4gICAqIHRoZSBgcmVhcGVySW50ZXJ2YWxgIG9wdGlvbi5cclxuICAgKi9cclxuICByZWFwZXJJbnRlcnZhbChzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHYubm9uTmVnYXRpdmVOdW0oc3RyaWN0Q2hlY2spO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgcG9vbEJlbmNobWFya2luZ2AgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbFxyXG4gICAqIHN0cmljdGVyIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgdGhlIGBib29sZWFuYCB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gcG9vbEJlbmNobWFya2luZ1xyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nXHJcbiAgICogdGhlIGBwb29sQmVuY2htYXJraW5nYCBvcHRpb24uXHJcbiAgICovXHJcbiAgcG9vbEJlbmNobWFya2luZyhzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHYuYm9vbGVhbihzdHJpY3RDaGVjayk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGByZXNvdXJjZXNJbnRlcnZhbGAgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aFxyXG4gICAqIGFuIG9wdGlvbmFsIHN0cmljdGVyIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgdGhlIGBub25OZWdhdGl2ZU51bWBcclxuICAgKiB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gcmVzb3VyY2VzSW50ZXJ2YWxcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZ1xyXG4gICAqIHRoZSBgcmVzb3VyY2VzSW50ZXJ2YWxgIG9wdGlvbi5cclxuICAgKi9cclxuICByZXNvdXJjZXNJbnRlcnZhbChzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHYubm9uTmVnYXRpdmVOdW0oc3RyaWN0Q2hlY2spO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgbG9nTGV2ZWxgIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGggYW4gb3B0aW9uYWxcclxuICAgKiBzdHJpY3RlciBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGF0OlxyXG4gICAqXHJcbiAgICogLSBXaGVuIGBzdHJpY3RDaGVja2AgaXMgdHJ1ZSwgdGhlIHNjaGVtYSB3aWxsIGFjY2VwdCBpbnRlZ2VyIG51bWJlciB2YWx1ZXNcclxuICAgKiB0aGF0IGFyZSBiZXR3ZWVuIDAgYW5kIDUgKGluY2x1c2l2ZSkuXHJcbiAgICpcclxuICAgKiAtIFdoZW4gYHN0cmljdENoZWNrYCBpcyBmYWxzZSwgdGhlIHNjaGVtYSB3aWxsIGFjY2VwdCBpbnRlZ2VyIG51bWJlciB2YWx1ZXNcclxuICAgKiBhbmQgc3RyaW5naWZpZWQgaW50ZWdlciBudW1iZXIgdmFsdWVzIHRoYXQgYXJlIGJldHdlZW4gMSBhbmQgNSAoaW5jbHVzaXZlKSxcclxuICAgKiBudWxsLCAndW5kZWZpbmVkJywgJ251bGwnLCBhbmQgJycgd2hpY2ggd2lsbCBiZSB0cmFuc2Zvcm1lZCB0byBudWxsLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIGxvZ0xldmVsXHJcbiAgICpcclxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IHN0cmljdENoZWNrIC0gRGV0ZXJtaW5lcyBpZiBzdHJpY3RlciB2YWxpZGF0aW9uIHNob3VsZFxyXG4gICAqIGJlIGFwcGxpZWQuXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9IEEgWm9kIHNjaGVtYSBvYmplY3QgZm9yIHZhbGlkYXRpbmcgdGhlIGBsb2dMZXZlbGBcclxuICAgKiBvcHRpb24uXHJcbiAgICovXHJcbiAgbG9nTGV2ZWwoc3RyaWN0Q2hlY2spIHtcclxuICAgIHJldHVybiBzdHJpY3RDaGVja1xyXG4gICAgICA/IHoubnVtYmVyKCkuaW50KCkuZ3RlKDApLmx0ZSg1KVxyXG4gICAgICA6IHpcclxuICAgICAgICAgIC51bmlvbihbXHJcbiAgICAgICAgICAgIHpcclxuICAgICAgICAgICAgICAuc3RyaW5nKClcclxuICAgICAgICAgICAgICAudHJpbSgpXHJcbiAgICAgICAgICAgICAgLnJlZmluZShcclxuICAgICAgICAgICAgICAgICh2YWx1ZSkgPT5cclxuICAgICAgICAgICAgICAgICAgKCFpc05hTihOdW1iZXIodmFsdWUpKSAmJlxyXG4gICAgICAgICAgICAgICAgICAgIHZhbHVlICE9PSB0cnVlICYmXHJcbiAgICAgICAgICAgICAgICAgICAgIXZhbHVlLnN0YXJ0c1dpdGgoJ1snKSAmJlxyXG4gICAgICAgICAgICAgICAgICAgIE51bWJlci5pc0ludGVnZXIoTnVtYmVyKHZhbHVlKSkgJiZcclxuICAgICAgICAgICAgICAgICAgICBOdW1iZXIodmFsdWUpID49IDAgJiZcclxuICAgICAgICAgICAgICAgICAgICBOdW1iZXIodmFsdWUpIDw9IDUpIHx8XHJcbiAgICAgICAgICAgICAgICAgIFsndW5kZWZpbmVkJywgJ251bGwnLCAnJ10uaW5jbHVkZXModmFsdWUpLFxyXG4gICAgICAgICAgICAgICAge1xyXG4gICAgICAgICAgICAgICAgICBwYXJhbXM6IHtcclxuICAgICAgICAgICAgICAgICAgICBlcnJvck1lc3NhZ2U6ICdUaGUgdmFsdWUgbXVzdCBiZSB3aXRoaW4gYSAwIGFuZCA1IHJhbmdlJ1xyXG4gICAgICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgICAgKVxyXG4gICAgICAgICAgICAgIC50cmFuc2Zvcm0oKHZhbHVlKSA9PlxyXG4gICAgICAgICAgICAgICAgIVsndW5kZWZpbmVkJywgJ251bGwnLCAnJ10uaW5jbHVkZXModmFsdWUpXHJcbiAgICAgICAgICAgICAgICAgID8gTnVtYmVyKHZhbHVlKVxyXG4gICAgICAgICAgICAgICAgICA6IG51bGxcclxuICAgICAgICAgICAgICApLFxyXG4gICAgICAgICAgICB6Lm51bWJlcigpLmludCgpLmd0ZSgwKS5sdGUoNSlcclxuICAgICAgICAgIF0pXHJcbiAgICAgICAgICAubnVsbGFibGUoKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYGxvZ0ZpbGVgIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGggYW4gb3B0aW9uYWwgc3RyaWN0ZXJcclxuICAgKiBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGUgc2FtZSB3b3JrIGFzIHRoZSBgc3RyaW5nYCB2YWxpZGF0b3IuXHJcbiAgICogQWRkaXRpb25hbGx5LCBpdCBtdXN0IGJlIGEgc3RyaW5nIHRoYXQgZW5kcyB3aXRoICcubG9nJy5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiBsb2dGaWxlXHJcbiAgICpcclxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IHN0cmljdENoZWNrIC0gRGV0ZXJtaW5lcyBpZiBzdHJpY3RlciB2YWxpZGF0aW9uIHNob3VsZFxyXG4gICAqIGJlIGFwcGxpZWQuXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9IEEgWm9kIHNjaGVtYSBvYmplY3QgZm9yIHZhbGlkYXRpbmcgdGhlIGBsb2dGaWxlYFxyXG4gICAqIG9wdGlvbi5cclxuICAgKi9cclxuICBsb2dGaWxlKHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gdlxyXG4gICAgICAuc3RyaW5nKHN0cmljdENoZWNrKVxyXG4gICAgICAucmVmaW5lKFxyXG4gICAgICAgICh2YWx1ZSkgPT5cclxuICAgICAgICAgIHZhbHVlID09PSBudWxsIHx8ICh2YWx1ZS5sZW5ndGggPj0gNSAmJiB2YWx1ZS5lbmRzV2l0aCgnLmxvZycpKSxcclxuICAgICAgICB7XHJcbiAgICAgICAgICBwYXJhbXM6IHtcclxuICAgICAgICAgICAgZXJyb3JNZXNzYWdlOiAnVGhlIHZhbHVlIG11c3QgYmUgYSBzdHJpbmcgdGhhdCBlbmRzIHdpdGggLmxvZydcclxuICAgICAgICAgIH1cclxuICAgICAgICB9XHJcbiAgICAgICk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGBsb2dEZXN0YCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoIGFuIG9wdGlvbmFsIHN0cmljdGVyXHJcbiAgICogY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhlIHNhbWUgd29yayBhcyB0aGUgYHN0cmluZ2AgdmFsaWRhdG9yLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIGxvZ0Rlc3RcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZyB0aGUgYGxvZ0Rlc3RgXHJcbiAgICogb3B0aW9uLlxyXG4gICAqL1xyXG4gIGxvZ0Rlc3Qoc3RyaWN0Q2hlY2spIHtcclxuICAgIHJldHVybiB2LnN0cmluZyhzdHJpY3RDaGVjayk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGBsb2dUb0NvbnNvbGVgIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGggYW4gb3B0aW9uYWxcclxuICAgKiBzdHJpY3RlciBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGUgc2FtZSB3b3JrIGFzIHRoZSBgYm9vbGVhbmAgdmFsaWRhdG9yLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIGxvZ1RvQ29uc29sZVxyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nXHJcbiAgICogdGhlIGBsb2dUb0NvbnNvbGVgIG9wdGlvbi5cclxuICAgKi9cclxuICBsb2dUb0NvbnNvbGUoc3RyaWN0Q2hlY2spIHtcclxuICAgIHJldHVybiB2LmJvb2xlYW4oc3RyaWN0Q2hlY2spO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgbG9nVG9GaWxlYCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoIGFuIG9wdGlvbmFsXHJcbiAgICogc3RyaWN0ZXIgY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhlIHNhbWUgd29yayBhcyB0aGUgYGJvb2xlYW5gIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiBsb2dUb0ZpbGVcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZyB0aGUgYGxvZ1RvRmlsZWBcclxuICAgKiBvcHRpb24uXHJcbiAgICovXHJcbiAgbG9nVG9GaWxlKHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gdi5ib29sZWFuKHN0cmljdENoZWNrKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYGVuYWJsZVVpYCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoIGFuIG9wdGlvbmFsXHJcbiAgICogc3RyaWN0ZXIgY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhlIHNhbWUgd29yayBhcyB0aGUgYGJvb2xlYW5gIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiBlbmFibGVVaVxyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nIHRoZSBgZW5hYmxlVWlgXHJcbiAgICogb3B0aW9uLlxyXG4gICAqL1xyXG4gIGVuYWJsZVVpKHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gdi5ib29sZWFuKHN0cmljdENoZWNrKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYHVpUm91dGVgIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGggYW4gb3B0aW9uYWxcclxuICAgKiBzdHJpY3RlciBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGUgc2FtZSB3b3JrIGFzIHRoZSBgc3RhcnRzV2l0aGAgdmFsaWRhdG9yLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIHVpUm91dGVcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZyB0aGUgYHVpUm91dGVgXHJcbiAgICogb3B0aW9uLlxyXG4gICAqL1xyXG4gIHVpUm91dGUoc3RyaWN0Q2hlY2spIHtcclxuICAgIHJldHVybiB2LnN0YXJ0c1dpdGgoWycvJ10sIHN0cmljdENoZWNrKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYG5vZGVFbnZgIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGggYW4gb3B0aW9uYWxcclxuICAgKiBzdHJpY3RlciBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGUgc2FtZSB3b3JrIGFzIHRoZSBgZW51bWAgdmFsaWRhdG9yLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIG5vZGVFbnZcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZyB0aGUgYG5vZGVFbnZgXHJcbiAgICogb3B0aW9uLlxyXG4gICAqL1xyXG4gIG5vZGVFbnYoc3RyaWN0Q2hlY2spIHtcclxuICAgIHJldHVybiB2LmVudW0oWydkZXZlbG9wbWVudCcsICdwcm9kdWN0aW9uJywgJ3Rlc3QnXSwgc3RyaWN0Q2hlY2spO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgbGlzdGVuVG9Qcm9jZXNzRXhpdHNgIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGhcclxuICAgKiBhbiBvcHRpb25hbCBzdHJpY3RlciBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGUgc2FtZSB3b3JrIGFzIHRoZSBgYm9vbGVhbmAgdmFsaWRhdG9yLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIGxpc3RlblRvUHJvY2Vzc0V4aXRzXHJcbiAgICpcclxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IHN0cmljdENoZWNrIC0gRGV0ZXJtaW5lcyBpZiBzdHJpY3RlciB2YWxpZGF0aW9uIHNob3VsZFxyXG4gICAqIGJlIGFwcGxpZWQuXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9IEEgWm9kIHNjaGVtYSBvYmplY3QgZm9yIHZhbGlkYXRpbmdcclxuICAgKiB0aGUgYGxpc3RlblRvUHJvY2Vzc0V4aXRzYCBvcHRpb24uXHJcbiAgICovXHJcbiAgbGlzdGVuVG9Qcm9jZXNzRXhpdHMoc3RyaWN0Q2hlY2spIHtcclxuICAgIHJldHVybiB2LmJvb2xlYW4oc3RyaWN0Q2hlY2spO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgbm9Mb2dvYCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoIGFuIG9wdGlvbmFsXHJcbiAgICogc3RyaWN0ZXIgY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhlIHNhbWUgd29yayBhcyB0aGUgYGJvb2xlYW5gIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiBub0xvZ29cclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZyB0aGUgYG5vTG9nb2BcclxuICAgKiBvcHRpb24uXHJcbiAgICovXHJcbiAgbm9Mb2dvKHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gdi5ib29sZWFuKHN0cmljdENoZWNrKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYGhhcmRSZXNldFBhZ2VgIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGggYW4gb3B0aW9uYWxcclxuICAgKiBzdHJpY3RlciBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGUgc2FtZSB3b3JrIGFzIHRoZSBgYm9vbGVhbmAgdmFsaWRhdG9yLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIGhhcmRSZXNldFBhZ2VcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZ1xyXG4gICAqIHRoZSBgaGFyZFJlc2V0UGFnZWAgb3B0aW9uLlxyXG4gICAqL1xyXG4gIGhhcmRSZXNldFBhZ2Uoc3RyaWN0Q2hlY2spIHtcclxuICAgIHJldHVybiB2LmJvb2xlYW4oc3RyaWN0Q2hlY2spO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgYnJvd3NlclNoZWxsTW9kZWAgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbFxyXG4gICAqIHN0cmljdGVyIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgdGhlIGBib29sZWFuYCB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gYnJvd3NlclNoZWxsTW9kZVxyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nXHJcbiAgICogdGhlIGBicm93c2VyU2hlbGxNb2RlYCBvcHRpb24uXHJcbiAgICovXHJcbiAgYnJvd3NlclNoZWxsTW9kZShzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHYuYm9vbGVhbihzdHJpY3RDaGVjayk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGB2YWxpZGF0aW9uYCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoIGFuIG9wdGlvbmFsXHJcbiAgICogc3RyaWN0ZXIgY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhlIHNhbWUgd29yayBhcyB0aGUgYGJvb2xlYW5gIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiB2YWxpZGF0aW9uXHJcbiAgICpcclxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IHN0cmljdENoZWNrIC0gRGV0ZXJtaW5lcyBpZiBzdHJpY3RlciB2YWxpZGF0aW9uIHNob3VsZFxyXG4gICAqIGJlIGFwcGxpZWQuXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9IEEgWm9kIHNjaGVtYSBvYmplY3QgZm9yIHZhbGlkYXRpbmcgdGhlIGB2YWxpZGF0aW9uYFxyXG4gICAqIG9wdGlvbi5cclxuICAgKi9cclxuICB2YWxpZGF0aW9uKHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gdi5ib29sZWFuKHN0cmljdENoZWNrKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYGVuYWJsZURlYnVnYCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoIGFuIG9wdGlvbmFsXHJcbiAgICogc3RyaWN0ZXIgY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhlIHNhbWUgd29yayBhcyB0aGUgYGJvb2xlYW5gIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiBlbmFibGVEZWJ1Z1xyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nIHRoZSBgZW5hYmxlRGVidWdgXHJcbiAgICogb3B0aW9uLlxyXG4gICAqL1xyXG4gIGVuYWJsZURlYnVnKHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gdi5ib29sZWFuKHN0cmljdENoZWNrKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYGhlYWRsZXNzYCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoIGFuIG9wdGlvbmFsXHJcbiAgICogc3RyaWN0ZXIgY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhlIHNhbWUgd29yayBhcyB0aGUgYGJvb2xlYW5gIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiBoZWFkbGVzc1xyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nIHRoZSBgaGVhZGxlc3NgXHJcbiAgICogb3B0aW9uLlxyXG4gICAqL1xyXG4gIGhlYWRsZXNzKHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gdi5ib29sZWFuKHN0cmljdENoZWNrKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYGRldnRvb2xzYCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoIGFuIG9wdGlvbmFsXHJcbiAgICogc3RyaWN0ZXIgY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhlIHNhbWUgd29yayBhcyB0aGUgYGJvb2xlYW5gIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiBkZXZ0b29sc1xyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nIHRoZSBgZGV2dG9vbHNgXHJcbiAgICogb3B0aW9uLlxyXG4gICAqL1xyXG4gIGRldnRvb2xzKHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gdi5ib29sZWFuKHN0cmljdENoZWNrKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYGxpc3RlblRvQ29uc29sZWAgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbFxyXG4gICAqIHN0cmljdGVyIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgdGhlIGBib29sZWFuYCB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gbGlzdGVuVG9Db25zb2xlXHJcbiAgICpcclxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IHN0cmljdENoZWNrIC0gRGV0ZXJtaW5lcyBpZiBzdHJpY3RlciB2YWxpZGF0aW9uIHNob3VsZFxyXG4gICAqIGJlIGFwcGxpZWQuXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9IEEgWm9kIHNjaGVtYSBvYmplY3QgZm9yIHZhbGlkYXRpbmdcclxuICAgKiB0aGUgYGxpc3RlblRvQ29uc29sZWAgb3B0aW9uLlxyXG4gICAqL1xyXG4gIGxpc3RlblRvQ29uc29sZShzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHYuYm9vbGVhbihzdHJpY3RDaGVjayk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGBkdW1waW9gIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGggYW4gb3B0aW9uYWwgc3RyaWN0ZXJcclxuICAgKiBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGUgc2FtZSB3b3JrIGFzIHRoZSBgYm9vbGVhbmAgdmFsaWRhdG9yLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIGR1bXBpb1xyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nIHRoZSBgZHVtcGlvYFxyXG4gICAqIG9wdGlvbi5cclxuICAgKi9cclxuICBkdW1waW8oc3RyaWN0Q2hlY2spIHtcclxuICAgIHJldHVybiB2LmJvb2xlYW4oc3RyaWN0Q2hlY2spO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgc2xvd01vYCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoIGFuIG9wdGlvbmFsIHN0cmljdGVyXHJcbiAgICogY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhlIHNhbWUgd29yayBhcyB0aGUgYG5vbk5lZ2F0aXZlTnVtYFxyXG4gICAqIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiBzbG93TW9cclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZyB0aGUgYHNsb3dNb2BcclxuICAgKiBvcHRpb24uXHJcbiAgICovXHJcbiAgc2xvd01vKHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gdi5ub25OZWdhdGl2ZU51bShzdHJpY3RDaGVjayk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGBkZWJ1Z2dpbmdQb3J0YCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoIGFuIG9wdGlvbmFsXHJcbiAgICogc3RyaWN0ZXIgY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhlIHNhbWUgd29yayBhcyB0aGUgYG5vbk5lZ2F0aXZlTnVtYFxyXG4gICAqIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiBkZWJ1Z2dpbmdQb3J0XHJcbiAgICpcclxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IHN0cmljdENoZWNrIC0gRGV0ZXJtaW5lcyBpZiBzdHJpY3RlciB2YWxpZGF0aW9uIHNob3VsZFxyXG4gICAqIGJlIGFwcGxpZWQuXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9IEEgWm9kIHNjaGVtYSBvYmplY3QgZm9yIHZhbGlkYXRpbmdcclxuICAgKiB0aGUgYGRlYnVnZ2luZ1BvcnRgIG9wdGlvbi5cclxuICAgKi9cclxuICBkZWJ1Z2dpbmdQb3J0KHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gdi5ub25OZWdhdGl2ZU51bShzdHJpY3RDaGVjayk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGByZXF1ZXN0SWRgIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGggYW4gb3B0aW9uYWxcclxuICAgKiBzdHJpY3RlciBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGUgc2FtZSB3b3JrIGFzIHRoZSBgc3RyaW5nYCB2YWxpZGF0b3IuXHJcbiAgICogQWRkaXRpb25hbGx5LCBpdCBtdXN0IGJlIGEgc3RyaW5naWZpZWQgVVVJRCBvciBjYW4gYmUgbnVsbC5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiByZXF1ZXN0SWRcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZyB0aGUgYHJlcXVlc3RJZGBcclxuICAgKiBvcHRpb24uXHJcbiAgICovXHJcbiAgcmVxdWVzdElkKCkge1xyXG4gICAgcmV0dXJuIHpcclxuICAgICAgLnN0cmluZygpXHJcbiAgICAgIC51dWlkKHsgbWVzc2FnZTogJ1RoZSB2YWx1ZSBtdXN0IGJlIGEgc3RyaW5naWZpZWQgVVVJRCcgfSlcclxuICAgICAgLm51bGxhYmxlKCk7XHJcbiAgfVxyXG59O1xyXG5cclxuLy8gU2NoZW1hIGZvciB0aGUgcHVwcGV0ZWVyIHNlY3Rpb24gb2Ygb3B0aW9uc1xyXG5jb25zdCBQdXBwZXRlZXJTY2hlbWEgPSAoc3RyaWN0Q2hlY2spID0+XHJcbiAgelxyXG4gICAgLm9iamVjdCh7XHJcbiAgICAgIGFyZ3M6IHZhbGlkYXRvcnMuYXJncyhzdHJpY3RDaGVjaylcclxuICAgIH0pXHJcbiAgICAucGFydGlhbCgpO1xyXG5cclxuLy8gU2NoZW1hIGZvciB0aGUgaGlnaGNoYXJ0cyBzZWN0aW9uIG9mIG9wdGlvbnNcclxuY29uc3QgSGlnaGNoYXJ0c1NjaGVtYSA9IChzdHJpY3RDaGVjaykgPT5cclxuICB6XHJcbiAgICAub2JqZWN0KHtcclxuICAgICAgdmVyc2lvbjogdmFsaWRhdG9ycy52ZXJzaW9uKHN0cmljdENoZWNrKSxcclxuICAgICAgY2RuVXJsOiB2YWxpZGF0b3JzLmNkblVybChzdHJpY3RDaGVjayksXHJcbiAgICAgIGZvcmNlRmV0Y2g6IHZhbGlkYXRvcnMuZm9yY2VGZXRjaChzdHJpY3RDaGVjayksXHJcbiAgICAgIGNhY2hlUGF0aDogdmFsaWRhdG9ycy5jYWNoZVBhdGgoc3RyaWN0Q2hlY2spLFxyXG4gICAgICBjb3JlU2NyaXB0czogdmFsaWRhdG9ycy5jb3JlU2NyaXB0cyhzdHJpY3RDaGVjayksXHJcbiAgICAgIG1vZHVsZVNjcmlwdHM6IHZhbGlkYXRvcnMubW9kdWxlU2NyaXB0cyhzdHJpY3RDaGVjayksXHJcbiAgICAgIGluZGljYXRvclNjcmlwdHM6IHZhbGlkYXRvcnMuaW5kaWNhdG9yU2NyaXB0cyhzdHJpY3RDaGVjayksXHJcbiAgICAgIGN1c3RvbVNjcmlwdHM6IHZhbGlkYXRvcnMuY3VzdG9tU2NyaXB0cyhzdHJpY3RDaGVjaylcclxuICAgIH0pXHJcbiAgICAucGFydGlhbCgpO1xyXG5cclxuLy8gU2NoZW1hIGZvciB0aGUgZXhwb3J0IHNlY3Rpb24gb2Ygb3B0aW9uc1xyXG5jb25zdCBFeHBvcnRTY2hlbWEgPSAoc3RyaWN0Q2hlY2spID0+XHJcbiAgelxyXG4gICAgLm9iamVjdCh7XHJcbiAgICAgIGluZmlsZTogdmFsaWRhdG9ycy5pbmZpbGUoc3RyaWN0Q2hlY2spLFxyXG4gICAgICBpbnN0cjogdmFsaWRhdG9ycy5pbnN0cigpLFxyXG4gICAgICBvcHRpb25zOiB2YWxpZGF0b3JzLm9wdGlvbnMoKSxcclxuICAgICAgc3ZnOiB2YWxpZGF0b3JzLnN2ZygpLFxyXG4gICAgICBvdXRmaWxlOiB2YWxpZGF0b3JzLm91dGZpbGUoc3RyaWN0Q2hlY2spLFxyXG4gICAgICB0eXBlOiB2YWxpZGF0b3JzLnR5cGUoc3RyaWN0Q2hlY2spLFxyXG4gICAgICBjb25zdHI6IHZhbGlkYXRvcnMuY29uc3RyKHN0cmljdENoZWNrKSxcclxuICAgICAgYjY0OiB2YWxpZGF0b3JzLmI2NChzdHJpY3RDaGVjayksXHJcbiAgICAgIG5vRG93bmxvYWQ6IHZhbGlkYXRvcnMubm9Eb3dubG9hZChzdHJpY3RDaGVjayksXHJcbiAgICAgIGRlZmF1bHRIZWlnaHQ6IHZhbGlkYXRvcnMuZGVmYXVsdEhlaWdodChzdHJpY3RDaGVjayksXHJcbiAgICAgIGRlZmF1bHRXaWR0aDogdmFsaWRhdG9ycy5kZWZhdWx0V2lkdGgoc3RyaWN0Q2hlY2spLFxyXG4gICAgICBkZWZhdWx0U2NhbGU6IHZhbGlkYXRvcnMuZGVmYXVsdFNjYWxlKHN0cmljdENoZWNrKSxcclxuICAgICAgaGVpZ2h0OiB2YWxpZGF0b3JzLmhlaWdodChzdHJpY3RDaGVjayksXHJcbiAgICAgIHdpZHRoOiB2YWxpZGF0b3JzLndpZHRoKHN0cmljdENoZWNrKSxcclxuICAgICAgc2NhbGU6IHZhbGlkYXRvcnMuc2NhbGUoc3RyaWN0Q2hlY2spLFxyXG4gICAgICBnbG9iYWxPcHRpb25zOiB2YWxpZGF0b3JzLmdsb2JhbE9wdGlvbnMoKSxcclxuICAgICAgdGhlbWVPcHRpb25zOiB2YWxpZGF0b3JzLnRoZW1lT3B0aW9ucygpLFxyXG4gICAgICBiYXRjaDogdmFsaWRhdG9ycy5iYXRjaChmYWxzZSksXHJcbiAgICAgIHJhc3Rlcml6YXRpb25UaW1lb3V0OiB2YWxpZGF0b3JzLnJhc3Rlcml6YXRpb25UaW1lb3V0KHN0cmljdENoZWNrKVxyXG4gICAgfSlcclxuICAgIC5wYXJ0aWFsKCk7XHJcblxyXG4vLyBTY2hlbWEgZm9yIHRoZSBjdXN0b21Mb2dpYyBzZWN0aW9uIG9mIG9wdGlvbnNcclxuY29uc3QgQ3VzdG9tTG9naWNTY2hlbWEgPSAoc3RyaWN0Q2hlY2spID0+XHJcbiAgelxyXG4gICAgLm9iamVjdCh7XHJcbiAgICAgIGFsbG93Q29kZUV4ZWN1dGlvbjogdmFsaWRhdG9ycy5hbGxvd0NvZGVFeGVjdXRpb24oc3RyaWN0Q2hlY2spLFxyXG4gICAgICBhbGxvd0ZpbGVSZXNvdXJjZXM6IHZhbGlkYXRvcnMuYWxsb3dGaWxlUmVzb3VyY2VzKHN0cmljdENoZWNrKSxcclxuICAgICAgY3VzdG9tQ29kZTogdmFsaWRhdG9ycy5jdXN0b21Db2RlKGZhbHNlKSxcclxuICAgICAgY2FsbGJhY2s6IHZhbGlkYXRvcnMuY2FsbGJhY2soZmFsc2UpLFxyXG4gICAgICByZXNvdXJjZXM6IHZhbGlkYXRvcnMucmVzb3VyY2VzKHN0cmljdENoZWNrKSxcclxuICAgICAgbG9hZENvbmZpZzogdmFsaWRhdG9ycy5sb2FkQ29uZmlnKGZhbHNlKSxcclxuICAgICAgY3JlYXRlQ29uZmlnOiB2YWxpZGF0b3JzLmNyZWF0ZUNvbmZpZyhmYWxzZSlcclxuICAgIH0pXHJcbiAgICAucGFydGlhbCgpO1xyXG5cclxuLy8gU2NoZW1hIGZvciB0aGUgc2VydmVyLnByb3h5IHNlY3Rpb24gb2Ygb3B0aW9uc1xyXG5jb25zdCBQcm94eVNjaGVtYSA9IChzdHJpY3RDaGVjaykgPT5cclxuICB6XHJcbiAgICAub2JqZWN0KHtcclxuICAgICAgaG9zdDogdmFsaWRhdG9ycy5wcm94eUhvc3QoZmFsc2UpLFxyXG4gICAgICBwb3J0OiB2YWxpZGF0b3JzLnByb3h5UG9ydChzdHJpY3RDaGVjayksXHJcbiAgICAgIHRpbWVvdXQ6IHZhbGlkYXRvcnMucHJveHlUaW1lb3V0KHN0cmljdENoZWNrKVxyXG4gICAgfSlcclxuICAgIC5wYXJ0aWFsKCk7XHJcblxyXG4vLyBTY2hlbWEgZm9yIHRoZSBzZXJ2ZXIucmF0ZUxpbWl0aW5nIHNlY3Rpb24gb2Ygb3B0aW9uc1xyXG5jb25zdCBSYXRlTGltaXRpbmdTY2hlbWEgPSAoc3RyaWN0Q2hlY2spID0+XHJcbiAgelxyXG4gICAgLm9iamVjdCh7XHJcbiAgICAgIGVuYWJsZTogdmFsaWRhdG9ycy5lbmFibGVSYXRlTGltaXRpbmcoc3RyaWN0Q2hlY2spLFxyXG4gICAgICBtYXhSZXF1ZXN0czogdmFsaWRhdG9ycy5tYXhSZXF1ZXN0cyhzdHJpY3RDaGVjayksXHJcbiAgICAgIHdpbmRvdzogdmFsaWRhdG9ycy53aW5kb3coc3RyaWN0Q2hlY2spLFxyXG4gICAgICBkZWxheTogdmFsaWRhdG9ycy5kZWxheShzdHJpY3RDaGVjayksXHJcbiAgICAgIHRydXN0UHJveHk6IHZhbGlkYXRvcnMudHJ1c3RQcm94eShzdHJpY3RDaGVjayksXHJcbiAgICAgIHNraXBLZXk6IHZhbGlkYXRvcnMuc2tpcEtleShmYWxzZSksXHJcbiAgICAgIHNraXBUb2tlbjogdmFsaWRhdG9ycy5za2lwVG9rZW4oZmFsc2UpXHJcbiAgICB9KVxyXG4gICAgLnBhcnRpYWwoKTtcclxuXHJcbi8vIFNjaGVtYSBmb3IgdGhlIHNlcnZlci5zc2wgc2VjdGlvbiBvZiBvcHRpb25zXHJcbmNvbnN0IFNzbFNjaGVtYSA9IChzdHJpY3RDaGVjaykgPT5cclxuICB6XHJcbiAgICAub2JqZWN0KHtcclxuICAgICAgZW5hYmxlOiB2YWxpZGF0b3JzLmVuYWJsZVNzbChzdHJpY3RDaGVjayksXHJcbiAgICAgIGZvcmNlOiB2YWxpZGF0b3JzLnNzbEZvcmNlKHN0cmljdENoZWNrKSxcclxuICAgICAgcG9ydDogdmFsaWRhdG9ycy5zc2xQb3J0KHN0cmljdENoZWNrKSxcclxuICAgICAgY2VydFBhdGg6IHZhbGlkYXRvcnMuc3NsQ2VydFBhdGgoZmFsc2UpXHJcbiAgICB9KVxyXG4gICAgLnBhcnRpYWwoKTtcclxuXHJcbi8vIFNjaGVtYSBmb3IgdGhlIHNlcnZlciBzZWN0aW9uIG9mIG9wdGlvbnNcclxuY29uc3QgU2VydmVyU2NoZW1hID0gKHN0cmljdENoZWNrKSA9PlxyXG4gIHoub2JqZWN0KHtcclxuICAgIGVuYWJsZTogdmFsaWRhdG9ycy5lbmFibGVTZXJ2ZXIoc3RyaWN0Q2hlY2spLm9wdGlvbmFsKCksXHJcbiAgICBob3N0OiB2YWxpZGF0b3JzLmhvc3Qoc3RyaWN0Q2hlY2spLm9wdGlvbmFsKCksXHJcbiAgICBwb3J0OiB2YWxpZGF0b3JzLnBvcnQoc3RyaWN0Q2hlY2spLm9wdGlvbmFsKCksXHJcbiAgICB1cGxvYWRMaW1pdDogdmFsaWRhdG9ycy51cGxvYWRMaW1pdChzdHJpY3RDaGVjaykub3B0aW9uYWwoKSxcclxuICAgIGJlbmNobWFya2luZzogdmFsaWRhdG9ycy5zZXJ2ZXJCZW5jaG1hcmtpbmcoc3RyaWN0Q2hlY2spLm9wdGlvbmFsKCksXHJcbiAgICBwcm94eTogUHJveHlTY2hlbWEoc3RyaWN0Q2hlY2spLm9wdGlvbmFsKCksXHJcbiAgICByYXRlTGltaXRpbmc6IFJhdGVMaW1pdGluZ1NjaGVtYShzdHJpY3RDaGVjaykub3B0aW9uYWwoKSxcclxuICAgIHNzbDogU3NsU2NoZW1hKHN0cmljdENoZWNrKS5vcHRpb25hbCgpXHJcbiAgfSk7XHJcblxyXG4vLyBTY2hlbWEgZm9yIHRoZSBwb29sIHNlY3Rpb24gb2Ygb3B0aW9uc1xyXG5jb25zdCBQb29sU2NoZW1hID0gKHN0cmljdENoZWNrKSA9PlxyXG4gIHpcclxuICAgIC5vYmplY3Qoe1xyXG4gICAgICBtaW5Xb3JrZXJzOiB2YWxpZGF0b3JzLm1pbldvcmtlcnMoc3RyaWN0Q2hlY2spLFxyXG4gICAgICBtYXhXb3JrZXJzOiB2YWxpZGF0b3JzLm1heFdvcmtlcnMoc3RyaWN0Q2hlY2spLFxyXG4gICAgICB3b3JrTGltaXQ6IHZhbGlkYXRvcnMud29ya0xpbWl0KHN0cmljdENoZWNrKSxcclxuICAgICAgYWNxdWlyZVRpbWVvdXQ6IHZhbGlkYXRvcnMuYWNxdWlyZVRpbWVvdXQoc3RyaWN0Q2hlY2spLFxyXG4gICAgICBjcmVhdGVUaW1lb3V0OiB2YWxpZGF0b3JzLmNyZWF0ZVRpbWVvdXQoc3RyaWN0Q2hlY2spLFxyXG4gICAgICBkZXN0cm95VGltZW91dDogdmFsaWRhdG9ycy5kZXN0cm95VGltZW91dChzdHJpY3RDaGVjayksXHJcbiAgICAgIGlkbGVUaW1lb3V0OiB2YWxpZGF0b3JzLmlkbGVUaW1lb3V0KHN0cmljdENoZWNrKSxcclxuICAgICAgY3JlYXRlUmV0cnlJbnRlcnZhbDogdmFsaWRhdG9ycy5jcmVhdGVSZXRyeUludGVydmFsKHN0cmljdENoZWNrKSxcclxuICAgICAgcmVhcGVySW50ZXJ2YWw6IHZhbGlkYXRvcnMucmVhcGVySW50ZXJ2YWwoc3RyaWN0Q2hlY2spLFxyXG4gICAgICBiZW5jaG1hcmtpbmc6IHZhbGlkYXRvcnMucG9vbEJlbmNobWFya2luZyhzdHJpY3RDaGVjaylcclxuICAgIH0pXHJcbiAgICAucGFydGlhbCgpO1xyXG5cclxuLy8gU2NoZW1hIGZvciB0aGUgbG9nZ2luZyBzZWN0aW9uIG9mIG9wdGlvbnNcclxuY29uc3QgTG9nZ2luZ1NjaGVtYSA9IChzdHJpY3RDaGVjaykgPT5cclxuICB6XHJcbiAgICAub2JqZWN0KHtcclxuICAgICAgbGV2ZWw6IHZhbGlkYXRvcnMubG9nTGV2ZWwoc3RyaWN0Q2hlY2spLFxyXG4gICAgICBmaWxlOiB2YWxpZGF0b3JzLmxvZ0ZpbGUoc3RyaWN0Q2hlY2spLFxyXG4gICAgICBkZXN0OiB2YWxpZGF0b3JzLmxvZ0Rlc3Qoc3RyaWN0Q2hlY2spLFxyXG4gICAgICB0b0NvbnNvbGU6IHZhbGlkYXRvcnMubG9nVG9Db25zb2xlKHN0cmljdENoZWNrKSxcclxuICAgICAgdG9GaWxlOiB2YWxpZGF0b3JzLmxvZ1RvRmlsZShzdHJpY3RDaGVjaylcclxuICAgIH0pXHJcbiAgICAucGFydGlhbCgpO1xyXG5cclxuLy8gU2NoZW1hIGZvciB0aGUgdWkgc2VjdGlvbiBvZiBvcHRpb25zXHJcbmNvbnN0IFVpU2NoZW1hID0gKHN0cmljdENoZWNrKSA9PlxyXG4gIHpcclxuICAgIC5vYmplY3Qoe1xyXG4gICAgICBlbmFibGU6IHZhbGlkYXRvcnMuZW5hYmxlVWkoc3RyaWN0Q2hlY2spLFxyXG4gICAgICByb3V0ZTogdmFsaWRhdG9ycy51aVJvdXRlKHN0cmljdENoZWNrKVxyXG4gICAgfSlcclxuICAgIC5wYXJ0aWFsKCk7XHJcblxyXG4vLyBTY2hlbWEgZm9yIHRoZSBvdGhlciBzZWN0aW9uIG9mIG9wdGlvbnNcclxuY29uc3QgT3RoZXJTY2hlbWEgPSAoc3RyaWN0Q2hlY2spID0+XHJcbiAgelxyXG4gICAgLm9iamVjdCh7XHJcbiAgICAgIG5vZGVFbnY6IHZhbGlkYXRvcnMubm9kZUVudihzdHJpY3RDaGVjayksXHJcbiAgICAgIGxpc3RlblRvUHJvY2Vzc0V4aXRzOiB2YWxpZGF0b3JzLmxpc3RlblRvUHJvY2Vzc0V4aXRzKHN0cmljdENoZWNrKSxcclxuICAgICAgbm9Mb2dvOiB2YWxpZGF0b3JzLm5vTG9nbyhzdHJpY3RDaGVjayksXHJcbiAgICAgIGhhcmRSZXNldFBhZ2U6IHZhbGlkYXRvcnMuaGFyZFJlc2V0UGFnZShzdHJpY3RDaGVjayksXHJcbiAgICAgIGJyb3dzZXJTaGVsbE1vZGU6IHZhbGlkYXRvcnMuYnJvd3NlclNoZWxsTW9kZShzdHJpY3RDaGVjayksXHJcbiAgICAgIHZhbGlkYXRpb246IHZhbGlkYXRvcnMudmFsaWRhdGlvbihzdHJpY3RDaGVjaylcclxuICAgIH0pXHJcbiAgICAucGFydGlhbCgpO1xyXG5cclxuLy8gU2NoZW1hIGZvciB0aGUgZGVidWcgc2VjdGlvbiBvZiBvcHRpb25zXHJcbmNvbnN0IERlYnVnU2NoZW1hID0gKHN0cmljdENoZWNrKSA9PlxyXG4gIHpcclxuICAgIC5vYmplY3Qoe1xyXG4gICAgICBlbmFibGU6IHZhbGlkYXRvcnMuZW5hYmxlRGVidWcoc3RyaWN0Q2hlY2spLFxyXG4gICAgICBoZWFkbGVzczogdmFsaWRhdG9ycy5oZWFkbGVzcyhzdHJpY3RDaGVjayksXHJcbiAgICAgIGRldnRvb2xzOiB2YWxpZGF0b3JzLmRldnRvb2xzKHN0cmljdENoZWNrKSxcclxuICAgICAgbGlzdGVuVG9Db25zb2xlOiB2YWxpZGF0b3JzLmxpc3RlblRvQ29uc29sZShzdHJpY3RDaGVjayksXHJcbiAgICAgIGR1bXBpbzogdmFsaWRhdG9ycy5kdW1waW8oc3RyaWN0Q2hlY2spLFxyXG4gICAgICBzbG93TW86IHZhbGlkYXRvcnMuc2xvd01vKHN0cmljdENoZWNrKSxcclxuICAgICAgZGVidWdnaW5nUG9ydDogdmFsaWRhdG9ycy5kZWJ1Z2dpbmdQb3J0KHN0cmljdENoZWNrKVxyXG4gICAgfSlcclxuICAgIC5wYXJ0aWFsKCk7XHJcblxyXG4vLyBTdHJpY3Qgc2NoZW1hIGZvciB0aGUgY29uZmlnXHJcbmV4cG9ydCBjb25zdCBTdHJpY3RDb25maWdTY2hlbWEgPSB6Lm9iamVjdCh7XHJcbiAgcmVxdWVzdElkOiB2YWxpZGF0b3JzLnJlcXVlc3RJZCgpLFxyXG4gIHB1cHBldGVlcjogUHVwcGV0ZWVyU2NoZW1hKHRydWUpLFxyXG4gIGhpZ2hjaGFydHM6IEhpZ2hjaGFydHNTY2hlbWEodHJ1ZSksXHJcbiAgZXhwb3J0OiBFeHBvcnRTY2hlbWEodHJ1ZSksXHJcbiAgY3VzdG9tTG9naWM6IEN1c3RvbUxvZ2ljU2NoZW1hKHRydWUpLFxyXG4gIHNlcnZlcjogU2VydmVyU2NoZW1hKHRydWUpLFxyXG4gIHBvb2w6IFBvb2xTY2hlbWEodHJ1ZSksXHJcbiAgbG9nZ2luZzogTG9nZ2luZ1NjaGVtYSh0cnVlKSxcclxuICB1aTogVWlTY2hlbWEodHJ1ZSksXHJcbiAgb3RoZXI6IE90aGVyU2NoZW1hKHRydWUpLFxyXG4gIGRlYnVnOiBEZWJ1Z1NjaGVtYSh0cnVlKVxyXG59KTtcclxuXHJcbi8vIExvb3NlIHNjaGVtYSBmb3IgdGhlIGNvbmZpZ1xyXG5leHBvcnQgY29uc3QgTG9vc2VDb25maWdTY2hlbWEgPSB6Lm9iamVjdCh7XHJcbiAgcmVxdWVzdElkOiB2YWxpZGF0b3JzLnJlcXVlc3RJZCgpLFxyXG4gIHB1cHBldGVlcjogUHVwcGV0ZWVyU2NoZW1hKGZhbHNlKSxcclxuICBoaWdoY2hhcnRzOiBIaWdoY2hhcnRzU2NoZW1hKGZhbHNlKSxcclxuICBleHBvcnQ6IEV4cG9ydFNjaGVtYShmYWxzZSksXHJcbiAgY3VzdG9tTG9naWM6IEN1c3RvbUxvZ2ljU2NoZW1hKGZhbHNlKSxcclxuICBzZXJ2ZXI6IFNlcnZlclNjaGVtYShmYWxzZSksXHJcbiAgcG9vbDogUG9vbFNjaGVtYShmYWxzZSksXHJcbiAgbG9nZ2luZzogTG9nZ2luZ1NjaGVtYShmYWxzZSksXHJcbiAgdWk6IFVpU2NoZW1hKGZhbHNlKSxcclxuICBvdGhlcjogT3RoZXJTY2hlbWEoZmFsc2UpLFxyXG4gIGRlYnVnOiBEZWJ1Z1NjaGVtYShmYWxzZSlcclxufSk7XHJcblxyXG4vLyBTY2hlbWEgZm9yIHRoZSBlbnZpcm9ubWVudCB2YXJpYWJsZXMgY29uZmlnXHJcbmV4cG9ydCBjb25zdCBFbnZTY2hlbWEgPSB6Lm9iamVjdCh7XHJcbiAgLy8gcHVwcGV0ZWVyXHJcbiAgUFVQUEVURUVSX0FSR1M6IHZhbGlkYXRvcnMuYXJncyhmYWxzZSksXHJcblxyXG4gIC8vIGhpZ2hjaGFydHNcclxuICBISUdIQ0hBUlRTX1ZFUlNJT046IHZhbGlkYXRvcnMudmVyc2lvbihmYWxzZSksXHJcbiAgSElHSENIQVJUU19DRE5fVVJMOiB2YWxpZGF0b3JzLmNkblVybChmYWxzZSksXHJcbiAgSElHSENIQVJUU19GT1JDRV9GRVRDSDogdmFsaWRhdG9ycy5mb3JjZUZldGNoKGZhbHNlKSxcclxuICBISUdIQ0hBUlRTX0NBQ0hFX1BBVEg6IHZhbGlkYXRvcnMuY2FjaGVQYXRoKGZhbHNlKSxcclxuICBISUdIQ0hBUlRTX0FETUlOX1RPS0VOOiB2YWxpZGF0b3JzLmFkbWluVG9rZW4oZmFsc2UpLFxyXG4gIEhJR0hDSEFSVFNfQ09SRV9TQ1JJUFRTOiB2YWxpZGF0b3JzLmNvcmVTY3JpcHRzKGZhbHNlKSxcclxuICBISUdIQ0hBUlRTX01PRFVMRV9TQ1JJUFRTOiB2YWxpZGF0b3JzLm1vZHVsZVNjcmlwdHMoZmFsc2UpLFxyXG4gIEhJR0hDSEFSVFNfSU5ESUNBVE9SX1NDUklQVFM6IHZhbGlkYXRvcnMuaW5kaWNhdG9yU2NyaXB0cyhmYWxzZSksXHJcbiAgSElHSENIQVJUU19DVVNUT01fU0NSSVBUUzogdmFsaWRhdG9ycy5jdXN0b21TY3JpcHRzKGZhbHNlKSxcclxuXHJcbiAgLy8gZXhwb3J0XHJcbiAgRVhQT1JUX0lORklMRTogdmFsaWRhdG9ycy5pbmZpbGUoZmFsc2UpLFxyXG4gIEVYUE9SVF9JTlNUUjogdmFsaWRhdG9ycy5pbnN0cigpLFxyXG4gIEVYUE9SVF9PUFRJT05TOiB2YWxpZGF0b3JzLm9wdGlvbnMoKSxcclxuICBFWFBPUlRfU1ZHOiB2YWxpZGF0b3JzLnN2ZygpLFxyXG4gIEVYUE9SVF9CQVRDSDogdmFsaWRhdG9ycy5iYXRjaChmYWxzZSksXHJcbiAgRVhQT1JUX09VVEZJTEU6IHZhbGlkYXRvcnMub3V0ZmlsZShmYWxzZSksXHJcbiAgRVhQT1JUX1RZUEU6IHZhbGlkYXRvcnMudHlwZShmYWxzZSksXHJcbiAgRVhQT1JUX0NPTlNUUjogdmFsaWRhdG9ycy5jb25zdHIoZmFsc2UpLFxyXG4gIEVYUE9SVF9CNjQ6IHZhbGlkYXRvcnMuYjY0KGZhbHNlKSxcclxuICBFWFBPUlRfTk9fRE9XTkxPQUQ6IHZhbGlkYXRvcnMubm9Eb3dubG9hZChmYWxzZSksXHJcbiAgRVhQT1JUX0hFSUdIVDogdmFsaWRhdG9ycy5oZWlnaHQoZmFsc2UpLFxyXG4gIEVYUE9SVF9XSURUSDogdmFsaWRhdG9ycy53aWR0aChmYWxzZSksXHJcbiAgRVhQT1JUX1NDQUxFOiB2YWxpZGF0b3JzLnNjYWxlKGZhbHNlKSxcclxuICBFWFBPUlRfREVGQVVMVF9IRUlHSFQ6IHZhbGlkYXRvcnMuZGVmYXVsdEhlaWdodChmYWxzZSksXHJcbiAgRVhQT1JUX0RFRkFVTFRfV0lEVEg6IHZhbGlkYXRvcnMuZGVmYXVsdFdpZHRoKGZhbHNlKSxcclxuICBFWFBPUlRfREVGQVVMVF9TQ0FMRTogdmFsaWRhdG9ycy5kZWZhdWx0U2NhbGUoZmFsc2UpLFxyXG4gIEVYUE9SVF9HTE9CQUxfT1BUSU9OUzogdmFsaWRhdG9ycy5nbG9iYWxPcHRpb25zKCksXHJcbiAgRVhQT1JUX1RIRU1FX09QVElPTlM6IHZhbGlkYXRvcnMudGhlbWVPcHRpb25zKCksXHJcbiAgRVhQT1JUX1JBU1RFUklaQVRJT05fVElNRU9VVDogdmFsaWRhdG9ycy5yYXN0ZXJpemF0aW9uVGltZW91dChmYWxzZSksXHJcblxyXG4gIC8vIGN1c3RvbVxyXG4gIENVU1RPTV9MT0dJQ19BTExPV19DT0RFX0VYRUNVVElPTjogdmFsaWRhdG9ycy5hbGxvd0NvZGVFeGVjdXRpb24oZmFsc2UpLFxyXG4gIENVU1RPTV9MT0dJQ19BTExPV19GSUxFX1JFU09VUkNFUzogdmFsaWRhdG9ycy5hbGxvd0ZpbGVSZXNvdXJjZXMoZmFsc2UpLFxyXG4gIENVU1RPTV9MT0dJQ19DVVNUT01fQ09ERTogdmFsaWRhdG9ycy5jdXN0b21Db2RlKGZhbHNlKSxcclxuICBDVVNUT01fTE9HSUNfQ0FMTEJBQ0s6IHZhbGlkYXRvcnMuY2FsbGJhY2soZmFsc2UpLFxyXG4gIENVU1RPTV9MT0dJQ19SRVNPVVJDRVM6IHZhbGlkYXRvcnMucmVzb3VyY2VzKGZhbHNlKSxcclxuICBDVVNUT01fTE9HSUNfTE9BRF9DT05GSUc6IHZhbGlkYXRvcnMubG9hZENvbmZpZyhmYWxzZSksXHJcbiAgQ1VTVE9NX0xPR0lDX0NSRUFURV9DT05GSUc6IHZhbGlkYXRvcnMuY3JlYXRlQ29uZmlnKGZhbHNlKSxcclxuXHJcbiAgLy8gc2VydmVyXHJcbiAgU0VSVkVSX0VOQUJMRTogdmFsaWRhdG9ycy5lbmFibGVTZXJ2ZXIoZmFsc2UpLFxyXG4gIFNFUlZFUl9IT1NUOiB2YWxpZGF0b3JzLmhvc3QoZmFsc2UpLFxyXG4gIFNFUlZFUl9QT1JUOiB2YWxpZGF0b3JzLnBvcnQoZmFsc2UpLFxyXG4gIFNFUlZFUl9VUExPQURfTElNSVQ6IHZhbGlkYXRvcnMudXBsb2FkTGltaXQoZmFsc2UpLFxyXG4gIFNFUlZFUl9CRU5DSE1BUktJTkc6IHZhbGlkYXRvcnMuc2VydmVyQmVuY2htYXJraW5nKGZhbHNlKSxcclxuXHJcbiAgLy8gc2VydmVyIHByb3h5XHJcbiAgU0VSVkVSX1BST1hZX0hPU1Q6IHZhbGlkYXRvcnMucHJveHlIb3N0KGZhbHNlKSxcclxuICBTRVJWRVJfUFJPWFlfUE9SVDogdmFsaWRhdG9ycy5wcm94eVBvcnQoZmFsc2UpLFxyXG4gIFNFUlZFUl9QUk9YWV9USU1FT1VUOiB2YWxpZGF0b3JzLnByb3h5VGltZW91dChmYWxzZSksXHJcblxyXG4gIC8vIHNlcnZlciByYXRlIGxpbWl0aW5nXHJcbiAgU0VSVkVSX1JBVEVfTElNSVRJTkdfRU5BQkxFOiB2YWxpZGF0b3JzLmVuYWJsZVJhdGVMaW1pdGluZyhmYWxzZSksXHJcbiAgU0VSVkVSX1JBVEVfTElNSVRJTkdfTUFYX1JFUVVFU1RTOiB2YWxpZGF0b3JzLm1heFJlcXVlc3RzKGZhbHNlKSxcclxuICBTRVJWRVJfUkFURV9MSU1JVElOR19XSU5ET1c6IHZhbGlkYXRvcnMud2luZG93KGZhbHNlKSxcclxuICBTRVJWRVJfUkFURV9MSU1JVElOR19ERUxBWTogdmFsaWRhdG9ycy5kZWxheShmYWxzZSksXHJcbiAgU0VSVkVSX1JBVEVfTElNSVRJTkdfVFJVU1RfUFJPWFk6IHZhbGlkYXRvcnMudHJ1c3RQcm94eShmYWxzZSksXHJcbiAgU0VSVkVSX1JBVEVfTElNSVRJTkdfU0tJUF9LRVk6IHZhbGlkYXRvcnMuc2tpcEtleShmYWxzZSksXHJcbiAgU0VSVkVSX1JBVEVfTElNSVRJTkdfU0tJUF9UT0tFTjogdmFsaWRhdG9ycy5za2lwVG9rZW4oZmFsc2UpLFxyXG5cclxuICAvLyBzZXJ2ZXIgc3NsXHJcbiAgU0VSVkVSX1NTTF9FTkFCTEU6IHZhbGlkYXRvcnMuZW5hYmxlU3NsKGZhbHNlKSxcclxuICBTRVJWRVJfU1NMX0ZPUkNFOiB2YWxpZGF0b3JzLnNzbEZvcmNlKGZhbHNlKSxcclxuICBTRVJWRVJfU1NMX1BPUlQ6IHZhbGlkYXRvcnMuc3NsUG9ydChmYWxzZSksXHJcbiAgU0VSVkVSX1NTTF9DRVJUX1BBVEg6IHZhbGlkYXRvcnMuc3NsQ2VydFBhdGgoZmFsc2UpLFxyXG5cclxuICAvLyBwb29sXHJcbiAgUE9PTF9NSU5fV09SS0VSUzogdmFsaWRhdG9ycy5taW5Xb3JrZXJzKGZhbHNlKSxcclxuICBQT09MX01BWF9XT1JLRVJTOiB2YWxpZGF0b3JzLm1heFdvcmtlcnMoZmFsc2UpLFxyXG4gIFBPT0xfV09SS19MSU1JVDogdmFsaWRhdG9ycy53b3JrTGltaXQoZmFsc2UpLFxyXG4gIFBPT0xfQUNRVUlSRV9USU1FT1VUOiB2YWxpZGF0b3JzLmFjcXVpcmVUaW1lb3V0KGZhbHNlKSxcclxuICBQT09MX0NSRUFURV9USU1FT1VUOiB2YWxpZGF0b3JzLmNyZWF0ZVRpbWVvdXQoZmFsc2UpLFxyXG4gIFBPT0xfREVTVFJPWV9USU1FT1VUOiB2YWxpZGF0b3JzLmRlc3Ryb3lUaW1lb3V0KGZhbHNlKSxcclxuICBQT09MX0lETEVfVElNRU9VVDogdmFsaWRhdG9ycy5pZGxlVGltZW91dChmYWxzZSksXHJcbiAgUE9PTF9DUkVBVEVfUkVUUllfSU5URVJWQUw6IHZhbGlkYXRvcnMuY3JlYXRlUmV0cnlJbnRlcnZhbChmYWxzZSksXHJcbiAgUE9PTF9SRUFQRVJfSU5URVJWQUw6IHZhbGlkYXRvcnMucmVhcGVySW50ZXJ2YWwoZmFsc2UpLFxyXG4gIFBPT0xfQkVOQ0hNQVJLSU5HOiB2YWxpZGF0b3JzLnBvb2xCZW5jaG1hcmtpbmcoZmFsc2UpLFxyXG5cclxuICAvLyBsb2dnaW5nXHJcbiAgTE9HR0lOR19MRVZFTDogdmFsaWRhdG9ycy5sb2dMZXZlbChmYWxzZSksXHJcbiAgTE9HR0lOR19GSUxFOiB2YWxpZGF0b3JzLmxvZ0ZpbGUoZmFsc2UpLFxyXG4gIExPR0dJTkdfREVTVDogdmFsaWRhdG9ycy5sb2dEZXN0KGZhbHNlKSxcclxuICBMT0dHSU5HX1RPX0NPTlNPTEU6IHZhbGlkYXRvcnMubG9nVG9Db25zb2xlKGZhbHNlKSxcclxuICBMT0dHSU5HX1RPX0ZJTEU6IHZhbGlkYXRvcnMubG9nVG9GaWxlKGZhbHNlKSxcclxuXHJcbiAgLy8gdWlcclxuICBVSV9FTkFCTEU6IHZhbGlkYXRvcnMuZW5hYmxlVWkoZmFsc2UpLFxyXG4gIFVJX1JPVVRFOiB2YWxpZGF0b3JzLnVpUm91dGUoZmFsc2UpLFxyXG5cclxuICAvLyBvdGhlclxyXG4gIE9USEVSX05PREVfRU5WOiB2YWxpZGF0b3JzLm5vZGVFbnYoZmFsc2UpLFxyXG4gIE9USEVSX0xJU1RFTl9UT19QUk9DRVNTX0VYSVRTOiB2YWxpZGF0b3JzLmxpc3RlblRvUHJvY2Vzc0V4aXRzKGZhbHNlKSxcclxuICBPVEhFUl9OT19MT0dPOiB2YWxpZGF0b3JzLm5vTG9nbyhmYWxzZSksXHJcbiAgT1RIRVJfSEFSRF9SRVNFVF9QQUdFOiB2YWxpZGF0b3JzLmhhcmRSZXNldFBhZ2UoZmFsc2UpLFxyXG4gIE9USEVSX0JST1dTRVJfU0hFTExfTU9ERTogdmFsaWRhdG9ycy5icm93c2VyU2hlbGxNb2RlKGZhbHNlKSxcclxuICBPVEhFUl9WQUxJREFUSU9OOiB2YWxpZGF0b3JzLnZhbGlkYXRpb24oZmFsc2UpLFxyXG5cclxuICAvLyBkZWJ1Z2dlclxyXG4gIERFQlVHX0VOQUJMRTogdmFsaWRhdG9ycy5lbmFibGVEZWJ1ZyhmYWxzZSksXHJcbiAgREVCVUdfSEVBRExFU1M6IHZhbGlkYXRvcnMuaGVhZGxlc3MoZmFsc2UpLFxyXG4gIERFQlVHX0RFVlRPT0xTOiB2YWxpZGF0b3JzLmRldnRvb2xzKGZhbHNlKSxcclxuICBERUJVR19MSVNURU5fVE9fQ09OU09MRTogdmFsaWRhdG9ycy5saXN0ZW5Ub0NvbnNvbGUoZmFsc2UpLFxyXG4gIERFQlVHX0RVTVBJTzogdmFsaWRhdG9ycy5kdW1waW8oZmFsc2UpLFxyXG4gIERFQlVHX1NMT1dfTU86IHZhbGlkYXRvcnMuc2xvd01vKGZhbHNlKSxcclxuICBERUJVR19ERUJVR0dJTkdfUE9SVDogdmFsaWRhdG9ycy5kZWJ1Z2dpbmdQb3J0KGZhbHNlKVxyXG59KTtcclxuXHJcbi8qKlxyXG4gKiBWYWxpZGF0ZXMgdGhlIGVudmlyb25tZW50IHZhcmlhYmxlcyBvcHRpb25zIHVzaW5nIHRoZSBFbnZTY2hlbWEuXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBwcm9jZXNzLmVudiAtIFRoZSBjb25maWd1cmF0aW9uIG9wdGlvbnMgZnJvbSBlbnZpcm9ubWVudFxyXG4gKiB2YXJpYWJsZXMgZmlsZSB0byB2YWxpZGF0ZS5cclxuICpcclxuICogQHJldHVybnMge09iamVjdH0gVGhlIHBhcnNlZCBhbmQgdmFsaWRhdGVkIGVudmlyb25tZW50IHZhcmlhYmxlcy5cclxuICovXHJcbmV4cG9ydCBjb25zdCBlbnZzID0gRW52U2NoZW1hLnBhcnRpYWwoKS5wYXJzZShwcm9jZXNzLmVudik7XHJcblxyXG4vKipcclxuICogVmFsaWRhdGVzIHRoZSBjb25maWd1cmF0aW9uIG9wdGlvbnMgdXNpbmcgdGhlIGBTdHJpY3RDb25maWdTY2hlbWFgLlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gc3RyaWN0VmFsaWRhdGVcclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IGNvbmZpZ09wdGlvbnMgLSBUaGUgY29uZmlndXJhdGlvbiBvcHRpb25zIHRvIHZhbGlkYXRlLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7T2JqZWN0fSBUaGUgcGFyc2VkIGFuZCB2YWxpZGF0ZWQgY29uZmlndXJhdGlvbiBvcHRpb25zLlxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIHN0cmljdFZhbGlkYXRlKGNvbmZpZ09wdGlvbnMpIHtcclxuICByZXR1cm4gU3RyaWN0Q29uZmlnU2NoZW1hLnBhcnRpYWwoKS5wYXJzZShjb25maWdPcHRpb25zKTtcclxufVxyXG5cclxuLyoqXHJcbiAqIFZhbGlkYXRlcyB0aGUgY29uZmlndXJhdGlvbiBvcHRpb25zIHVzaW5nIHRoZSBgTG9vc2VDb25maWdTY2hlbWFgLlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gbG9vc2VWYWxpZGF0ZVxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gY29uZmlnT3B0aW9ucyAtIFRoZSBjb25maWd1cmF0aW9uIG9wdGlvbnMgdG8gdmFsaWRhdGUuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtPYmplY3R9IFRoZSBwYXJzZWQgYW5kIHZhbGlkYXRlZCBjb25maWd1cmF0aW9uIG9wdGlvbnMuXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gbG9vc2VWYWxpZGF0ZShjb25maWdPcHRpb25zKSB7XHJcbiAgcmV0dXJuIExvb3NlQ29uZmlnU2NoZW1hLnBhcnRpYWwoKS5wYXJzZShjb25maWdPcHRpb25zKTtcclxufVxyXG5cclxuLyoqXHJcbiAqIEN1c3RvbSBlcnJvciBtYXBwaW5nIGZ1bmN0aW9uIGZvciBab2Qgc2NoZW1hIHZhbGlkYXRpb24uXHJcbiAqXHJcbiAqIFRoaXMgZnVuY3Rpb24gY3VzdG9taXplcyB0aGUgZXJyb3IgbWVzc2FnZXMgcHJvZHVjZWQgYnkgWm9kIHNjaGVtYVxyXG4gKiB2YWxpZGF0aW9uLCBwcm92aWRpbmcgbW9yZSBzcGVjaWZpYyBhbmQgdXNlci1mcmllbmRseSBmZWVkYmFjayBiYXNlZCBvbiB0aGVcclxuICogaXNzdWUgdHlwZSBhbmQgY29udGV4dC5cclxuICpcclxuICogVGhlIGZ1bmN0aW9uIG1vZGlmaWVzIHRoZSBlcnJvciBtZXNzYWdlcyBhcyBmb2xsb3dzOlxyXG4gKlxyXG4gKiAtIEZvciBtaXNzaW5nIHJlcXVpcmVkIHZhbHVlcyAodW5kZWZpbmVkKSwgaXQgcmV0dXJucyBhIG1lc3NhZ2UgaW5kaWNhdGluZ1xyXG4gKiB0aGF0IG5vIHZhbHVlIHdhcyBwcm92aWRlZCBmb3IgdGhlIHNwZWNpZmljIHByb3BlcnR5LlxyXG4gKlxyXG4gKiAtIEZvciBjdXN0b20gdmFsaWRhdGlvbiBlcnJvcnMsIGlmIGEgY3VzdG9tIGVycm9yIG1lc3NhZ2UgaXMgcHJvdmlkZWQgaW4gdGhlXHJcbiAqIGlzc3VlIHBhcmFtZXRlcnMsIGl0IGluY2x1ZGVzIHRoaXMgbWVzc2FnZSBhbG9uZyB3aXRoIHRoZSBpbnZhbGlkIGRhdGFcclxuICogcmVjZWl2ZWQuXHJcbiAqXHJcbiAqIC0gRm9yIGFsbCBvdGhlciBlcnJvcnMsIGl0IGFwcGVuZHMgcHJvcGVydHktc3BlY2lmaWMgaW5mb3JtYXRpb24gdG8gdGhlXHJcbiAqIGRlZmF1bHQgZXJyb3IgbWVzc2FnZSBwcm92aWRlZCBieSBab2QuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBfY3VzdG9tRXJyb3JNYXBcclxuICpcclxuICogQHBhcmFtIHt6LlpvZElzc3VlfSBpc3N1ZSAtIFRoZSBpc3N1ZSBvYmplY3QgcmVwcmVzZW50aW5nIHRoZSB2YWxpZGF0aW9uXHJcbiAqIGVycm9yLlxyXG4gKiBAcGFyYW0ge09iamVjdH0gY29udGV4dCAtIFRoZSBjb250ZXh0IG9iamVjdCBwcm92aWRpbmcgYWRkaXRpb25hbCBpbmZvcm1hdGlvblxyXG4gKiBhYm91dCB0aGUgdmFsaWRhdGlvbiBlcnJvci5cclxuICpcclxuICogQHJldHVybnMge09iamVjdH0gQW4gb2JqZWN0IGNvbnRhaW5pbmcgdGhlIGN1c3RvbWl6ZWQgZXJyb3IgbWVzc2FnZS5cclxuICovXHJcbmZ1bmN0aW9uIF9jdXN0b21FcnJvck1hcChpc3N1ZSwgY29udGV4dCkge1xyXG4gIC8vIEdldCB0aGUgY2hhaW4gb2YgcHJvcGVydGllcyB3aGljaCBlcnJvciBkaXJlY3RseSByZWZlcnMgdG9cclxuICBjb25zdCBwcm9wZXJ0eU5hbWUgPSBpc3N1ZS5wYXRoLmpvaW4oJy4nKTtcclxuXHJcbiAgLy8gQ3JlYXRlIHRoZSBmaXJzdCBwYXJ0IG9mIHRoZSBtZXNzYWdlIGFib3V0IHRoZSBwcm9wZXJ0eSBpbmZvcm1hdGlvblxyXG4gIGNvbnN0IHByb3BlcnR5SW5mbyA9IGBJbnZhbGlkIHZhbHVlIGZvciB0aGUgJHtwcm9wZXJ0eU5hbWV9YDtcclxuXHJcbiAgLy8gTW9kaWZpZWQgbWVzc2FnZSBmb3IgdGhlIGludmFsaWQgdHlwZVxyXG4gIGlmIChpc3N1ZS5jb2RlID09PSB6LlpvZElzc3VlQ29kZS5pbnZhbGlkX3R5cGUpIHtcclxuICAgIC8vIE1vZGlmaWVkIG1lc3NhZ2UgZm9yIHRoZSByZXF1aXJlZCB2YWx1ZXNcclxuICAgIGlmIChpc3N1ZS5yZWNlaXZlZCA9PT0gei5ab2RQYXJzZWRUeXBlLnVuZGVmaW5lZCkge1xyXG4gICAgICByZXR1cm4ge1xyXG4gICAgICAgIG1lc3NhZ2U6IGAke3Byb3BlcnR5SW5mb30gLSBObyB2YWx1ZSB3YXMgcHJvdmlkZWQuYFxyXG4gICAgICB9O1xyXG4gICAgfVxyXG5cclxuICAgIC8vIE1vZGlmaWVkIG1lc3NhZ2UgZm9yIHRoZSBzcGVjaWZpYyBpbnZhbGlkIHR5cGUgd2hlbiB2YWx1ZXMgZXhpc3RcclxuICAgIHJldHVybiB7XHJcbiAgICAgIG1lc3NhZ2U6IGAke3Byb3BlcnR5SW5mb30gLSBJbnZhbGlkIHR5cGUuICR7Y29udGV4dC5kZWZhdWx0RXJyb3J9LmBcclxuICAgIH07XHJcbiAgfVxyXG5cclxuICAvLyBNb2RpZmllZCBtZXNzYWdlIGZvciB0aGUgY3VzdG9tIHZhbGlkYXRpb25cclxuICBpZiAoaXNzdWUuY29kZSA9PT0gei5ab2RJc3N1ZUNvZGUuY3VzdG9tKSB7XHJcbiAgICAvLyBJZiB0aGUgY3VzdG9tIG1lc3NhZ2UgZm9yIGVycm9yIGV4aXN0LCBpbmNsdWRlIGl0XHJcbiAgICBpZiAoaXNzdWUucGFyYW1zPy5lcnJvck1lc3NhZ2UpIHtcclxuICAgICAgcmV0dXJuIHtcclxuICAgICAgICBtZXNzYWdlOiBgJHtwcm9wZXJ0eUluZm99IC0gJHtpc3N1ZS5wYXJhbXM/LmVycm9yTWVzc2FnZX0sIHJlY2VpdmVkICcke2NvbnRleHQuZGF0YX0nLmBcclxuICAgICAgfTtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIC8vIE1vZGlmaWVkIG1lc3NhZ2UgZm9yIHRoZSBpbnZhbGlkIHVuaW9uIGVycm9yXHJcbiAgaWYgKGlzc3VlLmNvZGUgPT09IHouWm9kSXNzdWVDb2RlLmludmFsaWRfdW5pb24pIHtcclxuICAgIC8vIENyZWF0ZSB0aGUgZmlyc3QgcGFydCBvZiB0aGUgbWVzc2FnZSBhYm91dCB0aGUgbXVsdGlwbGUgZXJyb3JzXHJcbiAgICBsZXQgbWVzc2FnZSA9IGBNdWx0aXBsZSBlcnJvcnMgb2NjdXJyZWQgZm9yIHRoZSAke3Byb3BlcnR5TmFtZX06XFxuYDtcclxuXHJcbiAgICAvLyBDeWNsZSB0aHJvdWdoIGFsbCBlcnJvcnMgYW5kIGNyZWF0ZSBhIGNvcnJlY3QgbWVzc2FnZVxyXG4gICAgaXNzdWUudW5pb25FcnJvcnMuZm9yRWFjaCgodmFsdWUpID0+IHtcclxuICAgICAgY29uc3QgaW5kZXggPSB2YWx1ZS5pc3N1ZXNbMF0ubWVzc2FnZS5pbmRleE9mKCctJyk7XHJcbiAgICAgIG1lc3NhZ2UgKz1cclxuICAgICAgICBpbmRleCAhPT0gLTFcclxuICAgICAgICAgID8gYCR7dmFsdWUuaXNzdWVzWzBdLm1lc3NhZ2V9XFxuYC5zdWJzdHJpbmcoaW5kZXgpXHJcbiAgICAgICAgICA6IGAke3ZhbHVlLmlzc3Vlc1swXS5tZXNzYWdlfVxcbmA7XHJcbiAgICB9KTtcclxuXHJcbiAgICAvLyBSZXR1cm4gdGhlIGZpbmFsIG1lc3NhZ2UgZm9yIHRoZSBpbnZhbGlkIHVuaW9uIGVycm9yXHJcbiAgICByZXR1cm4ge1xyXG4gICAgICBtZXNzYWdlXHJcbiAgICB9O1xyXG4gIH1cclxuXHJcbiAgLy8gUmV0dXJuIHRoZSBkZWZhdWx0IGVycm9yIG1lc3NhZ2UsIGV4dGVuZGVkIGJ5IHRoZSBpbmZvIGFib3V0IHRoZSBwcm9wZXJ0eVxyXG4gIHJldHVybiB7XHJcbiAgICBtZXNzYWdlOiBgJHtwcm9wZXJ0eUluZm99IC0gJHtjb250ZXh0LmRlZmF1bHRFcnJvcn0uYFxyXG4gIH07XHJcbn1cclxuXHJcbmV4cG9ydCBkZWZhdWx0IHtcclxuICB2YWxpZGF0b3JzLFxyXG4gIFN0cmljdENvbmZpZ1NjaGVtYSxcclxuICBMb29zZUNvbmZpZ1NjaGVtYSxcclxuICBFbnZTY2hlbWEsXHJcbiAgZW52cyxcclxuICBzdHJpY3RWYWxpZGF0ZSxcclxuICBsb29zZVZhbGlkYXRlXHJcbn07XHJcbiIsIi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXHJcblxyXG5IaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXJcclxuXHJcbkNvcHlyaWdodCAoYykgMjAxNi0yMDI1LCBIaWdoc29mdFxyXG5cclxuTGljZW5jZWQgdW5kZXIgdGhlIE1JVCBsaWNlbmNlLlxyXG5cclxuQWRkaXRpb25hbGx5IGEgdmFsaWQgSGlnaGNoYXJ0cyBsaWNlbnNlIGlzIHJlcXVpcmVkIGZvciB1c2UuXHJcblxyXG5TZWUgTElDRU5TRSBmaWxlIGluIHJvb3QgZm9yIGRldGFpbHMuXHJcblxyXG4qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xyXG5cclxuLyoqXHJcbiAqIEEgY3VzdG9tIGVycm9yIGNsYXNzIGZvciBoYW5kbGluZyBleHBvcnQtcmVsYXRlZCBlcnJvcnMuIEV4dGVuZHMgdGhlIG5hdGl2ZVxyXG4gKiBgRXJyb3JgIGNsYXNzIHRvIGluY2x1ZGUgYWRkaXRpb25hbCBwcm9wZXJ0aWVzIGxpa2Ugc3RhdHVzIGNvZGUgYW5kIHN0YWNrXHJcbiAqIHRyYWNlIGRldGFpbHMuXHJcbiAqL1xyXG5jbGFzcyBFeHBvcnRFcnJvciBleHRlbmRzIEVycm9yIHtcclxuICAvKipcclxuICAgKiBDcmVhdGVzIGFuIGluc3RhbmNlIG9mIHRoZSBgRXhwb3J0RXJyb3JgLlxyXG4gICAqXHJcbiAgICogQHBhcmFtIHtzdHJpbmd9IG1lc3NhZ2UgLSBUaGUgZXJyb3IgbWVzc2FnZSB0byBiZSBkaXNwbGF5ZWQuXHJcbiAgICogQHBhcmFtIHtudW1iZXJ9IHN0YXR1c0NvZGUgLSBPcHRpb25hbCBIVFRQIHN0YXR1cyBjb2RlIGFzc29jaWF0ZWRcclxuICAgKiB3aXRoIHRoZSBlcnJvciAoZS5nLiwgNDAwLCA1MDApLlxyXG4gICAqL1xyXG4gIGNvbnN0cnVjdG9yKG1lc3NhZ2UsIHN0YXR1c0NvZGUpIHtcclxuICAgIHN1cGVyKCk7XHJcblxyXG4gICAgdGhpcy5tZXNzYWdlID0gbWVzc2FnZTtcclxuICAgIHRoaXMuc3RhY2tNZXNzYWdlID0gbWVzc2FnZTtcclxuXHJcbiAgICBpZiAoc3RhdHVzQ29kZSkge1xyXG4gICAgICB0aGlzLnN0YXR1c0NvZGUgPSBzdGF0dXNDb2RlO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgLyoqXHJcbiAgICogU2V0cyBvciB1cGRhdGVzIHRoZSBIVFRQIHN0YXR1cyBjb2RlIGZvciB0aGUgZXJyb3IuXHJcbiAgICpcclxuICAgKiBAcGFyYW0ge251bWJlcn0gc3RhdHVzQ29kZSAtIFRoZSBIVFRQIHN0YXR1cyBjb2RlIHRvIGFzc2lnbiB0byB0aGUgZXJyb3IuXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7RXhwb3J0RXJyb3J9IFRoZSB1cGRhdGVkIGluc3RhbmNlIG9mIHRoZSBgRXhwb3J0RXJyb3JgIGNsYXNzLlxyXG4gICAqL1xyXG4gIHNldFN0YXR1cyhzdGF0dXNDb2RlKSB7XHJcbiAgICB0aGlzLnN0YXR1c0NvZGUgPSBzdGF0dXNDb2RlO1xyXG5cclxuICAgIHJldHVybiB0aGlzO1xyXG4gIH1cclxuXHJcbiAgLyoqXHJcbiAgICogU2V0cyBhZGRpdGlvbmFsIGVycm9yIGRldGFpbHMgYmFzZWQgb24gYW4gZXhpc3RpbmcgZXJyb3Igb2JqZWN0LlxyXG4gICAqXHJcbiAgICogQHBhcmFtIHtFcnJvcn0gZXJyb3IgLSBBbiBlcnJvciBvYmplY3QgY29udGFpbmluZyBkZXRhaWxzIHRvIHBvcHVsYXRlXHJcbiAgICogdGhlIGBFeHBvcnRFcnJvcmAgaW5zdGFuY2UuXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7RXhwb3J0RXJyb3J9IFRoZSB1cGRhdGVkIGluc3RhbmNlIG9mIHRoZSBgRXhwb3J0RXJyb3JgIGNsYXNzLlxyXG4gICAqL1xyXG4gIHNldEVycm9yKGVycm9yKSB7XHJcbiAgICB0aGlzLmVycm9yID0gZXJyb3I7XHJcblxyXG4gICAgaWYgKGVycm9yLm5hbWUpIHtcclxuICAgICAgdGhpcy5uYW1lID0gZXJyb3IubmFtZTtcclxuICAgIH1cclxuXHJcbiAgICBpZiAoZXJyb3Iuc3RhdHVzQ29kZSkge1xyXG4gICAgICB0aGlzLnN0YXR1c0NvZGUgPSBlcnJvci5zdGF0dXNDb2RlO1xyXG4gICAgfVxyXG5cclxuICAgIGlmIChlcnJvci5zdGFjaykge1xyXG4gICAgICB0aGlzLnN0YWNrTWVzc2FnZSA9IGVycm9yLm1lc3NhZ2U7XHJcbiAgICAgIHRoaXMuc3RhY2sgPSBlcnJvci5zdGFjaztcclxuICAgIH1cclxuXHJcbiAgICByZXR1cm4gdGhpcztcclxuICB9XHJcbn1cclxuXHJcbmV4cG9ydCBkZWZhdWx0IEV4cG9ydEVycm9yO1xyXG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxyXG5cclxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXHJcblxyXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNSwgSGlnaHNvZnRcclxuXHJcbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cclxuXHJcbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxyXG5cclxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxyXG5cclxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cclxuXHJcbi8qKlxyXG4gKiBAb3ZlcnZpZXcgTWFuYWdlcyBjb25maWd1cmF0aW9uIGZvciB0aGUgSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyIGJ5IGxvYWRpbmdcclxuICogYW5kIG1lcmdpbmcgb3B0aW9ucyBmcm9tIG11bHRpcGxlIHNvdXJjZXMsIHN1Y2ggYXMgZGVmYXVsdCBzZXR0aW5ncyxcclxuICogZW52aXJvbm1lbnQgdmFyaWFibGVzLCB1c2VyLXByb3ZpZGVkIG9wdGlvbnMsIGFuZCBjb21tYW5kLWxpbmUgYXJndW1lbnRzLlxyXG4gKiBFbnN1cmVzIHRoZSBnbG9iYWwgb3B0aW9ucyBhcmUgdXAtdG8tZGF0ZSB3aXRoIHRoZSBoaWdoZXN0IHByaW9yaXR5IHZhbHVlcy5cclxuICogUHJvdmlkZXMgZnVuY3Rpb25zIGZvciBhY2Nlc3NpbmcgYW5kIHVwZGF0aW5nIGNvbmZpZ3VyYXRpb24uXHJcbiAqL1xyXG5cclxuaW1wb3J0IHsgcmVhZEZpbGVTeW5jIH0gZnJvbSAnZnMnO1xyXG5pbXBvcnQgeyBqb2luIH0gZnJvbSAncGF0aCc7XHJcblxyXG5pbXBvcnQgeyBsb2csIGxvZ1dpdGhTdGFjaywgbG9nWm9kSXNzdWVzIH0gZnJvbSAnLi9sb2dnZXIuanMnO1xyXG5pbXBvcnQgeyBfX2Rpcm5hbWUsIGlzT2JqZWN0LCBkZWVwQ29weSwgZ2V0QWJzb2x1dGVQYXRoIH0gZnJvbSAnLi91dGlscy5qcyc7XHJcbmltcG9ydCB7XHJcbiAgZW52cyxcclxuICBsb29zZVZhbGlkYXRlLFxyXG4gIHN0cmljdFZhbGlkYXRlLFxyXG4gIHZhbGlkYXRvcnNcclxufSBmcm9tICcuL3ZhbGlkYXRpb24uanMnO1xyXG5cclxuaW1wb3J0IHsgZGVmYXVsdENvbmZpZywgbmVzdGVkUHJvcHMsIGFic29sdXRlUHJvcHMgfSBmcm9tICcuL3NjaGVtYXMvY29uZmlnLmpzJztcclxuXHJcbmltcG9ydCBFeHBvcnRFcnJvciBmcm9tICcuL2Vycm9ycy9FeHBvcnRFcnJvci5qcyc7XHJcblxyXG4vLyBTZXRzIHRoZSBnbG9iYWwgb3B0aW9ucyB3aXRoIGluaXRpYWwgdmFsdWVzIGZyb20gdGhlIGRlZmF1bHQgY29uZmlnXHJcbmNvbnN0IGdsb2JhbE9wdGlvbnMgPSBfaW5pdEdsb2JhbE9wdGlvbnMoZGVmYXVsdENvbmZpZyk7XHJcblxyXG4vLyBBbiBvYmplY3QgZm9yIHRoZSBpbnN0YW5jZSBvcHRpb25zLCBjcmVhdGVkIGVhY2ggdGltZSB0aGUgYGluaXRFeHBvcnRgIG9jY3Vyc1xyXG5jb25zdCBpbnN0YW5jZU9wdGlvbnMgPSBkZWVwQ29weShnbG9iYWxPcHRpb25zKTtcclxuXHJcbi8qKlxyXG4gKiBSZXRyaWV2ZXMgYSByZWZlcmVuY2UgdG8gdGhlIG9wdGlvbnMgb2JqZWN0LiBEZXBlbmRpbmcgb24gdGhlIGBnZXRJbnN0YW5jZWBcclxuICogcGFyYW1ldGVyLCBpdCByZXR1cm5zIGVpdGhlciB0aGUgZ2xvYmFsIG9wdGlvbnMgb3IgdGhlIGluc3RhbmNlLXNwZWNpZmljXHJcbiAqIG9wdGlvbnMgb2JqZWN0LlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gZ2V0T3B0aW9uc1xyXG4gKlxyXG4gKiBAcGFyYW0ge2Jvb2xlYW59IFtnZXRJbnN0YW5jZT10cnVlXSAtIE9wdGlvbmFsIHBhcmFtZXRlciB0aGF0IGRlY2lkZXMgd2hldGhlclxyXG4gKiB0byByZXR1cm4gdGhlIGluc3RhbmNlLXNwZWNpZmljIG9wdGlvbnMgKHdoZW4gYHRydWVgKSBvciB0aGUgZ2xvYmFsIG9wdGlvbnNcclxuICogKHdoZW4gYGZhbHNlYCkuIFRoZSBkZWZhdWx0IHZhbHVlIGlzIGB0cnVlYC5cclxuICpcclxuICogQHJldHVybnMge09iamVjdH0gQSByZWZlcmVuY2UgdG8gZWl0aGVyIHRoZSBnbG9iYWwgb3B0aW9uc1xyXG4gKiBvciB0aGUgaW5zdGFuY2Utc3BlY2lmaWMgb3B0aW9ucywgYmFzZWQgb24gdGhlIGBnZXRJbnN0YW5jZWAgcGFyYW1ldGVyLlxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIGdldE9wdGlvbnMoZ2V0SW5zdGFuY2UgPSB0cnVlKSB7XHJcbiAgcmV0dXJuIGdldEluc3RhbmNlID8gaW5zdGFuY2VPcHRpb25zIDogZ2xvYmFsT3B0aW9ucztcclxufVxyXG5cclxuLyoqXHJcbiAqIFNldHMgdGhlIGdsb2JhbCBvcHRpb25zIG9mIHRoZSBleHBvcnQgc2VydmVyLCBrZWVwaW5nIHRoZSBwcmluY2lwbGVcclxuICogb2YgdGhlIG9wdGlvbnMgbG9hZCBwcmlvcml0eSBmcm9tIGFsbCBhdmFpbGFibGUgc291cmNlcy4gSXQgYWNjZXB0cyBvcHRpb25hbFxyXG4gKiBgY3VzdG9tT3B0aW9uc2Agb2JqZWN0IGFuZCBgY2xpQXJnc2AgYXJyYXkgd2l0aCBhcmd1bWVudHMgZnJvbSB0aGUgQ0xJLiBUaGVzZVxyXG4gKiBvcHRpb25zIHdpbGwgYmUgdmFsaWRhdGVkIGFuZCBhcHBsaWVkIGlmIHByb3ZpZGVkLlxyXG4gKlxyXG4gKiBUaGUgcHJpb3JpdHkgb3JkZXIgb2Ygc2V0dGluZyB2YWx1ZXMgaXM6XHJcbiAqXHJcbiAqIDEuIE9wdGlvbnMgZnJvbSB0aGUgYGxpYi9zY2hlbWFzL2NvbmZpZy5qc2AgZmlsZSAoZGVmYXVsdCB2YWx1ZXMpLlxyXG4gKiAyLiBPcHRpb25zIGZyb20gYSBjdXN0b20gSlNPTiBmaWxlIChsb2FkZWQgYnkgdGhlIGBsb2FkQ29uZmlnYCBvcHRpb24pLlxyXG4gKiAzLiBPcHRpb25zIGZyb20gdGhlIGVudmlyb25tZW50IHZhcmlhYmxlcyAodGhlIGAuZW52YCBmaWxlKS5cclxuICogNC4gT3B0aW9ucyBmcm9tIHRoZSBjb21tYW5kIGxpbmUgaW50ZXJmYWNlIChDTEkpLlxyXG4gKiA1LiBPcHRpb25zIGZyb20gdGhlIGZpcnN0IHBhcmFtZXRlciAodGhlIGBjdXN0b21PcHRpb25zYCBpcyBieSBkZWZhdWx0XHJcbiAqIGFuIGVtcHR5IG9iamVjdCkuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBzZXRHbG9iYWxPcHRpb25zXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBbY3VzdG9tT3B0aW9ucz17fV0gLSBPcHRpb25hbCBjdXN0b20gb3B0aW9ucyBmb3IgYWRkaXRpb25hbFxyXG4gKiBjb25maWd1cmF0aW9uLiBUaGUgZGVmYXVsdCB2YWx1ZSBpcyBhbiBlbXB0eSBvYmplY3QuXHJcbiAqIEBwYXJhbSB7QXJyYXkuPHN0cmluZz59IFtjbGlBcmdzPVtdXSAtIE9wdGlvbmFsIGNvbW1hbmQgbGluZSBhcmd1bWVudHNcclxuICogZm9yIGFkZGl0aW9uYWwgY29uZmlndXJhdGlvbi4gVGhlIGRlZmF1bHQgdmFsdWUgaXMgYW4gZW1wdHkgYXJyYXkuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtPYmplY3R9IFRoZSB1cGRhdGVkIGdsb2JhbCBvcHRpb25zIG9iamVjdCwgcmVmbGVjdGluZyB0aGUgbWVyZ2VkXHJcbiAqIGNvbmZpZ3VyYXRpb24gZnJvbSBhbGwgYXZhaWxhYmxlIHNvdXJjZXMuXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gc2V0R2xvYmFsT3B0aW9ucyhjdXN0b21PcHRpb25zID0ge30sIGNsaUFyZ3MgPSBbXSkge1xyXG4gIC8vIE9iamVjdCBmb3Igb3B0aW9ucyBsb2FkZWQgdmlhIHRoZSBgbG9hZENvbmZpZ2Agb3B0aW9uXHJcbiAgbGV0IGNvbmZpZ09wdGlvbnMgPSB7fTtcclxuXHJcbiAgLy8gT2JqZWN0IGZvciBvcHRpb25zIGZyb20gdGhlIENMSVxyXG4gIGxldCBjbGlPcHRpb25zID0ge307XHJcblxyXG4gIC8vIE9ubHkgZm9yIHRoZSBDTEkgdXNhZ2VcclxuICBpZiAoY2xpQXJncyAmJiBBcnJheS5pc0FycmF5KGNsaUFyZ3MpICYmIGNsaUFyZ3MubGVuZ3RoKSB7XHJcbiAgICB0cnkge1xyXG4gICAgICAvLyBWYWxpZGF0ZSBvcHRpb25zIGZyb20gdGhlIGN1c3RvbSBKU09OIGxvYWRlZCB2aWEgdGhlIGBsb2FkQ29uZmlnYFxyXG4gICAgICBjb25maWdPcHRpb25zID0gc3RyaWN0VmFsaWRhdGUoXHJcbiAgICAgICAgX2xvYWRDb25maWdGaWxlKGNsaUFyZ3MsIGdsb2JhbE9wdGlvbnMuY3VzdG9tTG9naWMpXHJcbiAgICAgICk7XHJcbiAgICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgICBsb2dab2RJc3N1ZXMoXHJcbiAgICAgICAgMSxcclxuICAgICAgICBlcnJvci5pc3N1ZXMsXHJcbiAgICAgICAgJ1t2YWxpZGF0aW9uXSBDdXN0b20gb3B0aW9ucyBmcm9tIHRoZSBgbG9hZENvbmZpZ2Agb3B0aW9uIHZhbGlkYXRpb24gZXJyb3InXHJcbiAgICAgICk7XHJcbiAgICB9XHJcblxyXG4gICAgdHJ5IHtcclxuICAgICAgLy8gVmFsaWRhdGUgb3B0aW9ucyBmcm9tIHRoZSBDTElcclxuICAgICAgY2xpT3B0aW9ucyA9IGxvb3NlVmFsaWRhdGUoX3BhaXJBcmd1bWVudFZhbHVlKG5lc3RlZFByb3BzLCBjbGlBcmdzKSk7XHJcbiAgICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgICBsb2dab2RJc3N1ZXMoXHJcbiAgICAgICAgMSxcclxuICAgICAgICBlcnJvci5pc3N1ZXMsXHJcbiAgICAgICAgJ1t2YWxpZGF0aW9uXSBDTEkgb3B0aW9ucyB2YWxpZGF0aW9uIGVycm9yJ1xyXG4gICAgICApO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgLy8gQXBwbHkgY3VzdG9tIG9wdGlvbnMgaWYgdGhlcmUgYXJlIGFueVxyXG4gIGlmIChcclxuICAgIGN1c3RvbU9wdGlvbnMgJiZcclxuICAgIGlzT2JqZWN0KGN1c3RvbU9wdGlvbnMpICYmXHJcbiAgICBPYmplY3Qua2V5cyhjdXN0b21PcHRpb25zKS5sZW5ndGhcclxuICApIHtcclxuICAgIHRyeSB7XHJcbiAgICAgIC8vIFZhbGlkYXRlIGN1c3RvbSBvcHRpb25zIHByb3ZpZGVkIGJ5IHRoZSB1c2VyXHJcbiAgICAgIGN1c3RvbU9wdGlvbnMgPSBzdHJpY3RWYWxpZGF0ZShjdXN0b21PcHRpb25zKTtcclxuICAgIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICAgIGxvZ1pvZElzc3VlcyhcclxuICAgICAgICAxLFxyXG4gICAgICAgIGVycm9yLmlzc3VlcyxcclxuICAgICAgICAnW3ZhbGlkYXRpb25dIEN1c3RvbSBvcHRpb25zIHZhbGlkYXRpb24gZXJyb3InXHJcbiAgICAgICk7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICAvLyBVcGRhdGUgdmFsdWVzIG9mIHRoZSBnbG9iYWwgb3B0aW9ucyB3aXRoIHZhbHVlcyBmcm9tIGVhY2ggc291cmNlIHBvc3NpYmxlXHJcbiAgX3VwZGF0ZUdsb2JhbE9wdGlvbnMoXHJcbiAgICBkZWZhdWx0Q29uZmlnLFxyXG4gICAgZ2xvYmFsT3B0aW9ucyxcclxuICAgIGNvbmZpZ09wdGlvbnMsXHJcbiAgICBjbGlPcHRpb25zLFxyXG4gICAgY3VzdG9tT3B0aW9uc1xyXG4gICk7XHJcblxyXG4gIC8vIFJldHVybiB1cGRhdGVkIGdsb2JhbCBvcHRpb25zXHJcbiAgcmV0dXJuIGdsb2JhbE9wdGlvbnM7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBVcGRhdGVzIHRoZSBpbnN0YW5jZSBvcHRpb25zIHdpdGggYWRkaXRpb25hbCBvcHRpb25zLiBJdCBvcHRpb25hbGx5IGFsbG93c1xyXG4gKiB0byByZWluaXRpYWxpemUgdGhlIGluc3RhbmNlIG9wdGlvbnMgd2l0aCB0aGUgdmFsdWVzIG9mIGEgY3VycmVudCBnbG9iYWxcclxuICogb3B0aW9ucyBvYmplY3QuXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSB1cGRhdGVPcHRpb25zIC0gVGhlIHVwZGF0ZSBvcHRpb25zIHRvIG1lcmdlIGludG8gdGhlIGluc3RhbmNlXHJcbiAqIG9wdGlvbnMuXHJcbiAqIEBwYXJhbSB7Ym9vbGVhbn0gW25ld0luc3RhbmNlPWZhbHNlXSAtIEEgZmxhZyB0byBpbmRpY2F0ZSB3aGV0aGVyIHRvIGluaXRcclxuICogb3B0aW9ucyBmb3IgYSBuZXcgaW5zdGFuY2UuIElmIGB0cnVlYCwgdGhlIGV4aXN0aW5nIGluc3RhbmNlIG9wdGlvbnMgd2lsbFxyXG4gKiBiZSBjbGVhcmVkIGFuZCByZWluaXRpYWxpemVkIGJhc2VkIG9uIHRoZSBnbG9iYWwgb3B0aW9ucy5cclxuICpcclxuICogQHJldHVybnMge09iamVjdH0gLSBUaGUgdXBkYXRlZCBpbnN0YW5jZSBvcHRpb25zLlxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIHVwZGF0ZU9wdGlvbnModXBkYXRlT3B0aW9ucywgbmV3SW5zdGFuY2UgPSBmYWxzZSkge1xyXG4gIC8vIENoZWNrIGlmIG9wdGlvbnMgbmVlZCB0byBiZSBjcmVhdGVkIGZvciBhIG5ldyBpbnN0YW5jZVxyXG4gIGlmIChuZXdJbnN0YW5jZSkge1xyXG4gICAgLy8gR2V0IHJpZCBvZiB0aGUgb2xkIGluc3RhbmNlIG9wdGlvbnNcclxuICAgIE9iamVjdC5rZXlzKGluc3RhbmNlT3B0aW9ucykuZm9yRWFjaCgoa2V5KSA9PiB7XHJcbiAgICAgIGRlbGV0ZSBpbnN0YW5jZU9wdGlvbnNba2V5XTtcclxuICAgIH0pO1xyXG5cclxuICAgIC8vIEluaXQgdGhlIG5ldyBpbnN0YW5jZSBvcHRpb25zIGJhc2VkIG9uIHRoZSBnbG9iYWwgb3B0aW9uc1xyXG4gICAgbWVyZ2VPcHRpb25zKGluc3RhbmNlT3B0aW9ucywgZGVlcENvcHkoZ2xvYmFsT3B0aW9ucykpO1xyXG4gIH1cclxuXHJcbiAgLy8gTWVyZ2UgYWRkaXRpb25hbCBvcHRpb25zIHRvIHRoZSBpbnN0YW5jZSBvcHRpb25zXHJcbiAgbWVyZ2VPcHRpb25zKGluc3RhbmNlT3B0aW9ucywgdXBkYXRlT3B0aW9ucyk7XHJcblxyXG4gIC8vIFJldHVybiB0aGUgcmVmZXJlbmNlIHRvIHRoZSBpbnN0YW5jZSBvcHRpb25zIG9iamVjdFxyXG4gIHJldHVybiBpbnN0YW5jZU9wdGlvbnM7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBNZXJnZXMgdHdvIHNldHMgb2YgY29uZmlndXJhdGlvbiBvcHRpb25zLCBjb25zaWRlcmluZyBhYnNvbHV0ZSBwcm9wZXJ0aWVzLlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gbWVyZ2VPcHRpb25zXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBvcmlnaW5hbE9wdGlvbnMgLSBPcmlnaW5hbCBjb25maWd1cmF0aW9uIG9wdGlvbnMuXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBuZXdPcHRpb25zIC0gTmV3IGNvbmZpZ3VyYXRpb24gb3B0aW9ucyB0byBiZSBtZXJnZWQuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtPYmplY3R9IE1lcmdlZCBjb25maWd1cmF0aW9uIG9wdGlvbnMuXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gbWVyZ2VPcHRpb25zKG9yaWdpbmFsT3B0aW9ucywgbmV3T3B0aW9ucykge1xyXG4gIC8vIENoZWNrIGlmIHRoZSBgb3JpZ2luYWxPcHRpb25zYCBhbmQgYG5ld09wdGlvbnNgIGFyZSBjb3JyZWN0IG9iamVjdHNcclxuICBpZiAoaXNPYmplY3Qob3JpZ2luYWxPcHRpb25zKSAmJiBpc09iamVjdChuZXdPcHRpb25zKSkge1xyXG4gICAgZm9yIChjb25zdCBba2V5LCB2YWx1ZV0gb2YgT2JqZWN0LmVudHJpZXMobmV3T3B0aW9ucykpIHtcclxuICAgICAgb3JpZ2luYWxPcHRpb25zW2tleV0gPVxyXG4gICAgICAgIGlzT2JqZWN0KHZhbHVlKSAmJlxyXG4gICAgICAgICFhYnNvbHV0ZVByb3BzLmluY2x1ZGVzKGtleSkgJiZcclxuICAgICAgICBvcmlnaW5hbE9wdGlvbnNba2V5XSAhPT0gdW5kZWZpbmVkXHJcbiAgICAgICAgICA/IG1lcmdlT3B0aW9ucyhvcmlnaW5hbE9wdGlvbnNba2V5XSwgdmFsdWUpXHJcbiAgICAgICAgICA6IHZhbHVlICE9PSB1bmRlZmluZWRcclxuICAgICAgICAgICAgPyB2YWx1ZVxyXG4gICAgICAgICAgICA6IG9yaWdpbmFsT3B0aW9uc1trZXldIHx8IG51bGw7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICAvLyBSZXR1cm4gdGhlIG9yaWdpbmFsIChtb2RpZmllZCBvciBub3QpIG9wdGlvbnNcclxuICByZXR1cm4gb3JpZ2luYWxPcHRpb25zO1xyXG59XHJcblxyXG4vKipcclxuICogTWFwcyBvbGQtc3RydWN0dXJlZCBjb25maWd1cmF0aW9uIG9wdGlvbnMgKFBoYW50b21KUykgdG8gYSBuZXcgZm9ybWF0XHJcbiAqIChQdXBwZXRlZXIpLiBUaGlzIGZ1bmN0aW9uIGNvbnZlcnRzIGZsYXQsIG9sZC1zdHJ1Y3R1cmVkIG9wdGlvbnMgaW50b1xyXG4gKiBhIG5ldywgbmVzdGVkIGNvbmZpZ3VyYXRpb24gZm9ybWF0IGJhc2VkIG9uIGEgcHJlZGVmaW5lZCBtYXBwaW5nXHJcbiAqIChgbmVzdGVkUHJvcHNgKS4gVGhlIG5ldyBmb3JtYXQgaXMgdXNlZCBmb3IgUHVwcGV0ZWVyLCB3aGlsZSB0aGUgb2xkIGZvcm1hdFxyXG4gKiB3YXMgdXNlZCBmb3IgUGhhbnRvbUpTLlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gbWFwVG9OZXdPcHRpb25zXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBvbGRPcHRpb25zIC0gVGhlIG9sZCwgZmxhdCBjb25maWd1cmF0aW9uIG9wdGlvbnNcclxuICogdG8gYmUgY29udmVydGVkLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7T2JqZWN0fSBBIG5ldyBvYmplY3QgY29udGFpbmluZyBvcHRpb25zIHN0cnVjdHVyZWQgYWNjb3JkaW5nXHJcbiAqIHRvIHRoZSBtYXBwaW5nIGRlZmluZWQgaW4gYG5lc3RlZFByb3BzYCBvciBhbiBlbXB0eSBvYmplY3QgaWYgdGhlIHByb3ZpZGVkXHJcbiAqIGBvbGRPcHRpb25zYCBpcyBub3QgYSBjb3JyZWN0IG9iamVjdC5cclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiBtYXBUb05ld09wdGlvbnMob2xkT3B0aW9ucykge1xyXG4gIC8vIEFuIG9iamVjdCBmb3IgdGhlIG5ldyBzdHJ1Y3R1cmVkIG9wdGlvbnNcclxuICBjb25zdCBuZXdPcHRpb25zID0ge307XHJcblxyXG4gIC8vIENoZWNrIGlmIHByb3ZpZGVkIHZhbHVlIGlzIGEgY29ycmVjdCBvYmplY3RcclxuICBpZiAoaXNPYmplY3Qob2xkT3B0aW9ucykpIHtcclxuICAgIC8vIEl0ZXJhdGUgb3ZlciBlYWNoIGtleS12YWx1ZSBwYWlyIGluIHRoZSBvbGQtc3RydWN0dXJlZCBvcHRpb25zXHJcbiAgICBmb3IgKGNvbnN0IFtrZXksIHZhbHVlXSBvZiBPYmplY3QuZW50cmllcyhvbGRPcHRpb25zKSkge1xyXG4gICAgICAvLyBJZiB0aGVyZSBpcyBhIG5lc3RlZCBtYXBwaW5nLCBzcGxpdCBpdCBpbnRvIGEgcHJvcGVydGllcyBjaGFpblxyXG4gICAgICBjb25zdCBwcm9wZXJ0aWVzQ2hhaW4gPSBuZXN0ZWRQcm9wc1trZXldXHJcbiAgICAgICAgPyBuZXN0ZWRQcm9wc1trZXldLnNwbGl0KCcuJylcclxuICAgICAgICA6IFtdO1xyXG5cclxuICAgICAgLy8gSWYgaXQgaXMgdGhlIGxhc3QgcHJvcGVydHkgaW4gdGhlIGNoYWluLCBhc3NpZ24gdGhlIHZhbHVlLCBvdGhlcndpc2UsXHJcbiAgICAgIC8vIGNyZWF0ZSBvciByZXVzZSB0aGUgbmVzdGVkIG9iamVjdFxyXG4gICAgICBwcm9wZXJ0aWVzQ2hhaW4ucmVkdWNlKFxyXG4gICAgICAgIChvYmosIHByb3AsIGluZGV4KSA9PlxyXG4gICAgICAgICAgKG9ialtwcm9wXSA9XHJcbiAgICAgICAgICAgIHByb3BlcnRpZXNDaGFpbi5sZW5ndGggLSAxID09PSBpbmRleCA/IHZhbHVlIDogb2JqW3Byb3BdIHx8IHt9KSxcclxuICAgICAgICBuZXdPcHRpb25zXHJcbiAgICAgICk7XHJcbiAgICB9XHJcbiAgfSBlbHNlIHtcclxuICAgIGxvZyhcclxuICAgICAgMixcclxuICAgICAgJ1tjb25maWddIE5vIGNvcnJlY3Qgb2JqZWN0IHdpdGggb3B0aW9ucyB3YXMgcHJvdmlkZWQuIFJldHVybmluZyBhbiBlbXB0eSBhcnJheS4nXHJcbiAgICApO1xyXG4gIH1cclxuXHJcbiAgLy8gUmV0dXJuIHRoZSBuZXcsIHN0cnVjdHVyZWQgb3B0aW9ucyBvYmplY3RcclxuICByZXR1cm4gbmV3T3B0aW9ucztcclxufVxyXG5cclxuLyoqXHJcbiAqIFZhbGlkYXRlcyBhIHNwZWNpZmllZCBvcHRpb24gdXNpbmcgdGhlIGNvcnJlc3BvbmRpbmcgdmFsaWRhdG9yIGZyb20gdGhlXHJcbiAqIGNvbmZpZ3VyYXRpb24gb2JqZWN0LiBSZXR1cm5zIHRoZSBvcmlnaW5hbCBvcHRpb24gaWYgdGhlIHZhbGlkYXRpb25cclxuICogaXMgZGlzYWJsZWQgZ2xvYmFsbHkuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiB2YWxpZGF0ZU9wdGlvblxyXG4gKlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gbmFtZSAtIFRoZSBuYW1lIG9mIHRoZSBvcHRpb24gdG8gdmFsaWRhdGUuXHJcbiAqIEBwYXJhbSB7YW55fSBjb25maWdPcHRpb24gLSBUaGUgdmFsdWUgb2YgdGhlIG9wdGlvbiB0byB2YWxpZGF0ZS5cclxuICogQHBhcmFtIHtib29sZWFufSBbc3RyaWN0Q2hlY2s9dHJ1ZV0gLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb25cclxuICogc2hvdWxkIGJlIGFwcGxpZWQuIFRoZSBkZWZhdWx0IHZhbHVlIGlzIGB0cnVlYC5cclxuICpcclxuICogQHJldHVybnMge2FueX0gVGhlIHBhcnNlZCBhbmQgdmFsaWRhdGVkIHZhbHVlIG9mIHRoZSBvcHRpb24uXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gdmFsaWRhdGVPcHRpb24obmFtZSwgY29uZmlnT3B0aW9uLCBzdHJpY3RDaGVjayA9IHRydWUpIHtcclxuICAvLyBSZXR1cm4gdGhlIG9yaWdpbmFsIG9wdGlvbiBpZiB0aGUgdmFsaWRhdGlvbiBpcyBkaXNhYmxlZFxyXG4gIGlmICghZ2V0T3B0aW9ucygpLm90aGVyLnZhbGlkYXRpb24pIHtcclxuICAgIHJldHVybiBjb25maWdPcHRpb247XHJcbiAgfVxyXG5cclxuICB0cnkge1xyXG4gICAgLy8gUmV0dXJuIHZhbGlkYXRlZCBvcHRpb25cclxuICAgIHJldHVybiB2YWxpZGF0b3JzW25hbWVdKHN0cmljdENoZWNrKS5wYXJzZShjb25maWdPcHRpb24pO1xyXG4gIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICAvLyBMb2cgWm9kIGlzc3Vlc1xyXG4gICAgbG9nWm9kSXNzdWVzKFxyXG4gICAgICAxLFxyXG4gICAgICBlcnJvci5pc3N1ZXMsXHJcbiAgICAgIGBbdmFsaWRhdGlvbl0gVGhlICR7bmFtZX0gb3B0aW9uIHZhbGlkYXRpb24gZXJyb3JgXHJcbiAgICApO1xyXG5cclxuICAgIC8vIFRocm93IHZhbGlkYXRpb24gZXJyb3JcclxuICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcihcclxuICAgICAgYFt2YWxpZGF0aW9uXSBUaGUgJHtuYW1lfSBvcHRpb24gdmFsaWRhdGlvbiBlcnJvcmAsXHJcbiAgICAgIDQwMFxyXG4gICAgKTtcclxuICB9XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBWYWxpZGF0ZXMgdGhlIHByb3ZpZGVkIGNvbmZpZ3VyYXRpb24gb3B0aW9ucyBmb3IgdGhlIGV4cG9ydGluZyBwcm9jZXNzLlxyXG4gKiBSZXR1cm5zIHRoZSBvcmlnaW5hbCBvcHRpb24gaWYgdGhlIHZhbGlkYXRpb24gaXMgZGlzYWJsZWQgZ2xvYmFsbHkuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiB2YWxpZGF0ZU9wdGlvbnNcclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IGNvbmZpZ09wdGlvbnMgLSBUaGUgY29uZmlndXJhdGlvbiBvcHRpb25zIHRvIGJlIHZhbGlkYXRlZC5cclxuICogQHBhcmFtIHtib29sZWFufSBbc3RyaWN0Q2hlY2s9dHJ1ZV0gLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb25cclxuICogc2hvdWxkIGJlIGFwcGxpZWQuIFRoZSBkZWZhdWx0IHZhbHVlIGlzIGB0cnVlYC5cclxuICpcclxuICogQHJldHVybnMge09iamVjdH0gVGhlIHBhcnNlZCBhbmQgdmFsaWRhdGVkIGNvbmZpZ3VyYXRpb24gb3B0aW9ucyBvYmplY3QuXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gdmFsaWRhdGVPcHRpb25zKGNvbmZpZ09wdGlvbnMsIHN0cmljdENoZWNrID0gdHJ1ZSkge1xyXG4gIC8vIFJldHVybiB0aGUgb3JpZ2luYWwgY29uZmlnIGlmIHRoZSB2YWxpZGF0aW9uIGlzIGRpc2FibGVkXHJcbiAgaWYgKCFnZXRPcHRpb25zKCkub3RoZXIudmFsaWRhdGlvbikge1xyXG4gICAgcmV0dXJuIGNvbmZpZ09wdGlvbnM7XHJcbiAgfVxyXG5cclxuICB0cnkge1xyXG4gICAgLy8gUmV0dXJuIHZhbGlkYXRlZCBvcHRpb25zXHJcbiAgICByZXR1cm4gc3RyaWN0Q2hlY2tcclxuICAgICAgPyBzdHJpY3RWYWxpZGF0ZShjb25maWdPcHRpb25zKVxyXG4gICAgICA6IGxvb3NlVmFsaWRhdGUoY29uZmlnT3B0aW9ucyk7XHJcbiAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgIC8vIExvZyBab2QgaXNzdWVzXHJcbiAgICBsb2dab2RJc3N1ZXMoMSwgZXJyb3IuaXNzdWVzLCAnW3ZhbGlkYXRpb25dIE9wdGlvbnMgdmFsaWRhdGlvbiBlcnJvcicpO1xyXG5cclxuICAgIC8vIFRocm93IHZhbGlkYXRpb24gZXJyb3JcclxuICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcignW3ZhbGlkYXRpb25dIE9wdGlvbnMgdmFsaWRhdGlvbiBlcnJvcicsIDQwMCk7XHJcbiAgfVxyXG59XHJcblxyXG4vKipcclxuICogVmFsaWRhdGVzLCBwYXJzZXMsIGFuZCBjaGVja3MgaWYgdGhlIHByb3ZpZGVkIGNvbmZpZyBpcyBhbGxvd2VkIHNldFxyXG4gKiBvZiBvcHRpb25zLlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gaXNBbGxvd2VkQ29uZmlnXHJcbiAqXHJcbiAqIEBwYXJhbSB7dW5rbm93bn0gY29uZmlnIC0gVGhlIGNvbmZpZyB0byBiZSB2YWxpZGF0ZWQgYW5kIHBhcnNlZCBhcyBhIHNldFxyXG4gKiBvZiBvcHRpb25zLiBNdXN0IGJlIGVpdGhlciBhbiBvYmplY3Qgb3IgYSBzdHJpbmcuXHJcbiAqIEBwYXJhbSB7Ym9vbGVhbn0gW3RvU3RyaW5nPWZhbHNlXSAtIFdoZXRoZXIgdG8gcmV0dXJuIGEgc3RyaW5naWZpZWQgdmVyc2lvblxyXG4gKiBvZiB0aGUgcGFyc2VkIGNvbmZpZy4gVGhlIGRlZmF1bHQgdmFsdWUgaXMgYGZhbHNlYC5cclxuICogQHBhcmFtIHtib29sZWFufSBbYWxsb3dGdW5jdGlvbnM9ZmFsc2VdIC0gV2hldGhlciB0byBhbGxvdyBmdW5jdGlvbnNcclxuICogaW4gdGhlIHBhcnNlZCBjb25maWcuIElmIHRydWUsIGZ1bmN0aW9ucyBhcmUgcHJlc2VydmVkLiBPdGhlcndpc2UsIHdoZW5cclxuICogYSBmdW5jdGlvbiBpcyBmb3VuZCwgbnVsbCBpcyByZXR1cm5lZC4gVGhlIGRlZmF1bHQgdmFsdWUgaXMgYGZhbHNlYC5cclxuICpcclxuICogQHJldHVybnMgeyhPYmplY3R8c3RyaW5nfG51bGwpfSBSZXR1cm5zIGEgcGFyc2VkIHNldCBvZiBvcHRpb25zIG9iamVjdCxcclxuICogYSBzdHJpbmdpZmllZCBzZXQgb2Ygb3B0aW9ucyBvYmplY3QgaWYgdGhlIGB0b1N0cmluZ2AgaXMgdHJ1ZSwgYW5kIG51bGxcclxuICogaWYgdGhlIGNvbmZpZyBpcyBub3QgYSB2YWxpZCBzZXQgb2Ygb3B0aW9ucyBvciBwYXJzaW5nIGZhaWxzLlxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIGlzQWxsb3dlZENvbmZpZyhcclxuICBjb25maWcsXHJcbiAgdG9TdHJpbmcgPSBmYWxzZSxcclxuICBhbGxvd0Z1bmN0aW9ucyA9IGZhbHNlXHJcbikge1xyXG4gIHRyeSB7XHJcbiAgICAvLyBBY2NlcHQgb25seSBvYmplY3RzIGFuZCBzdHJpbmdzXHJcbiAgICBpZiAoIWlzT2JqZWN0KGNvbmZpZykgJiYgdHlwZW9mIGNvbmZpZyAhPT0gJ3N0cmluZycpIHtcclxuICAgICAgLy8gUmV0dXJuIG51bGwgaWYgYW55IG90aGVyIHR5cGVcclxuICAgICAgcmV0dXJuIG51bGw7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gR2V0IHRoZSBvYmplY3QgcmVwcmVzZW50YXRpb24gb2YgdGhlIG9yaWdpbmFsIGNvbmZpZ1xyXG4gICAgY29uc3Qgb2JqZWN0Q29uZmlnID1cclxuICAgICAgdHlwZW9mIGNvbmZpZyA9PT0gJ3N0cmluZydcclxuICAgICAgICA/IGFsbG93RnVuY3Rpb25zXHJcbiAgICAgICAgICA/IGV2YWwoYCgke2NvbmZpZ30pYClcclxuICAgICAgICAgIDogSlNPTi5wYXJzZShjb25maWcpXHJcbiAgICAgICAgOiBjb25maWc7XHJcblxyXG4gICAgLy8gUHJlc2VydmUgb3IgcmVtb3ZlIHBvdGVudGlhbCBmdW5jdGlvbnMgYmFzZWQgb24gdGhlIGBhbGxvd0Z1bmN0aW9uc2AgZmxhZ1xyXG4gICAgY29uc3Qgc3RyaW5naWZpZWRPcHRpb25zID0gX29wdGlvbnNTdHJpbmdpZnkoXHJcbiAgICAgIG9iamVjdENvbmZpZyxcclxuICAgICAgYWxsb3dGdW5jdGlvbnMsXHJcbiAgICAgIGZhbHNlXHJcbiAgICApO1xyXG5cclxuICAgIC8vIFBhcnNlIHRoZSBjb25maWcgdG8gY2hlY2sgaWYgaXQgaXMgdmFsaWQgc2V0IG9mIG9wdGlvbnNcclxuICAgIGNvbnN0IHBhcnNlZE9wdGlvbnMgPSBhbGxvd0Z1bmN0aW9uc1xyXG4gICAgICA/IEpTT04ucGFyc2UoXHJcbiAgICAgICAgICBfb3B0aW9uc1N0cmluZ2lmeShvYmplY3RDb25maWcsIGFsbG93RnVuY3Rpb25zLCB0cnVlKSxcclxuICAgICAgICAgIChfLCB2YWx1ZSkgPT5cclxuICAgICAgICAgICAgdHlwZW9mIHZhbHVlID09PSAnc3RyaW5nJyAmJiB2YWx1ZS5zdGFydHNXaXRoKCdmdW5jdGlvbicpXHJcbiAgICAgICAgICAgICAgPyBldmFsKGAoJHt2YWx1ZX0pYClcclxuICAgICAgICAgICAgICA6IHZhbHVlXHJcbiAgICAgICAgKVxyXG4gICAgICA6IEpTT04ucGFyc2Uoc3RyaW5naWZpZWRPcHRpb25zKTtcclxuXHJcbiAgICAvLyBSZXR1cm4gc3RyaW5naWZpZWQgb3Igb2JqZWN0IG9wdGlvbnMgYmFzZWQgb24gdGhlIGB0b1N0cmluZ2AgZmxhZ1xyXG4gICAgcmV0dXJuIHRvU3RyaW5nID8gc3RyaW5naWZpZWRPcHRpb25zIDogcGFyc2VkT3B0aW9ucztcclxuICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgLy8gUmV0dXJuIG51bGwgaWYgcGFyc2luZyBmYWlsc1xyXG4gICAgcmV0dXJuIG51bGw7XHJcbiAgfVxyXG59XHJcblxyXG4vKipcclxuICogUHJpbnRzIHRoZSBIaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXIgbG9nbywgdmVyc2lvbiwgYW5kIGxpY2Vuc2UgaW5mb3JtYXRpb24uXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBwcmludExpY2Vuc2VcclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiBwcmludExpY2Vuc2UoKSB7XHJcbiAgLy8gUHJpbnQgdGhlIGxvZ28gYW5kIHZlcnNpb24gaW5mb3JtYXRpb25cclxuICBwcmludFZlcnNpb24oKTtcclxuXHJcbiAgLy8gUHJpbnQgdGhlIGxpY2Vuc2UgaW5mb3JtYXRpb25cclxuICBjb25zb2xlLmxvZyhcclxuICAgICdUaGlzIHNvZnR3YXJlIHJlcXVpcmVzIGEgdmFsaWQgSGlnaGNoYXJ0cyBsaWNlbnNlIGZvciBjb21tZXJjaWFsIHVzZS5cXG4nXHJcbiAgICAgIC55ZWxsb3csXHJcbiAgICAnXFxuRm9yIGEgZnVsbCBsaXN0IG9mIENMSSBvcHRpb25zLCB0eXBlOicsXHJcbiAgICAnXFxuaGlnaGNoYXJ0cy1leHBvcnQtc2VydmVyIC0taGVscFxcbicuZ3JlZW4sXHJcbiAgICAnXFxuSWYgeW91IGRvIG5vdCBoYXZlIGEgbGljZW5zZSwgb25lIGNhbiBiZSBvYnRhaW5lZCBoZXJlOicsXHJcbiAgICAnXFxuaHR0cHM6Ly9zaG9wLmhpZ2hzb2Z0LmNvbS9cXG4nLmdyZWVuLFxyXG4gICAgJ1xcblRvIGN1c3RvbWl6ZSB5b3VyIGluc3RhbGxhdGlvbiwgcGxlYXNlIHJlZmVyIHRvIHRoZSBSRUFETUUgZmlsZSBhdDonLFxyXG4gICAgJ1xcbmh0dHBzOi8vZ2l0aHViLmNvbS9oaWdoY2hhcnRzL25vZGUtZXhwb3J0LXNlcnZlciNyZWFkbWVcXG4nLmdyZWVuXHJcbiAgKTtcclxufVxyXG5cclxuLyoqXHJcbiAqIFByaW50cyB1c2FnZSBpbmZvcm1hdGlvbiBmb3IgQ0xJIGFyZ3VtZW50cywgZGlzcGxheWluZyBhdmFpbGFibGUgb3B0aW9uc1xyXG4gKiBhbmQgdGhlaXIgZGVzY3JpcHRpb25zLiBJdCBjYW4gbGlzdCBwcm9wZXJ0aWVzIHJlY3Vyc2l2ZWx5IGlmIGNhdGVnb3JpZXNcclxuICogY29udGFpbiBuZXN0ZWQgb3B0aW9ucy5cclxuICpcclxuICogQGZ1bmN0aW9uIHByaW50VXNhZ2VcclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiBwcmludFVzYWdlKCkge1xyXG4gIC8vIERpc3BsYXkgUkVBRE1FIGFuZCBnZW5lcmFsIHVzYWdlIGluZm9ybWF0aW9uXHJcbiAgY29uc29sZS5sb2coXHJcbiAgICAnXFxuVXNhZ2Ugb2YgQ0xJIGFyZ3VtZW50czonLmJvbGQsXHJcbiAgICAnXFxuLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0nLFxyXG4gICAgYFxcbkZvciBtb3JlIGRldGFpbGVkIGluZm9ybWF0aW9uLCB2aXNpdCB0aGUgUkVBRE1FIGZpbGUgYXQ6ICR7J2h0dHBzOi8vZ2l0aHViLmNvbS9oaWdoY2hhcnRzL25vZGUtZXhwb3J0LXNlcnZlciNyZWFkbWUnLmdyZWVufS5cXG5gXHJcbiAgKTtcclxuXHJcbiAgLy8gSXRlcmF0ZSB0aHJvdWdoIGVhY2ggY2F0ZWdvcnkgaW4gdGhlIGBkZWZhdWx0Q29uZmlnYCBhbmQgZGlzcGxheSB1c2FnZSBpbmZvXHJcbiAgT2JqZWN0LmtleXMoZGVmYXVsdENvbmZpZykuZm9yRWFjaCgoY2F0ZWdvcnkpID0+IHtcclxuICAgIGNvbnNvbGUubG9nKGAke2NhdGVnb3J5LnRvVXBwZXJDYXNlKCl9YC5ib2xkLnJlZCk7XHJcbiAgICBfY3ljbGVDYXRlZ29yaWVzKGRlZmF1bHRDb25maWdbY2F0ZWdvcnldKTtcclxuICAgIGNvbnNvbGUubG9nKCcnKTtcclxuICB9KTtcclxufVxyXG5cclxuLyoqXHJcbiAqIFByaW50cyB0aGUgSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyIGxvZ28gb3IgdGV4dCB3aXRoIHRoZSB2ZXJzaW9uXHJcbiAqIGluZm9ybWF0aW9uLlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gcHJpbnRWZXJzaW9uXHJcbiAqXHJcbiAqIEBwYXJhbSB7Ym9vbGVhbn0gW25vTG9nbz1mYWxzZV0gLSBJZiB0cnVlLCBvbmx5IHByaW50cyB0ZXh0IHdpdGggdGhlIHZlcnNpb25cclxuICogaW5mb3JtYXRpb24sIHdpdGhvdXQgdGhlIGxvZ28uIFRoZSBkZWZhdWx0IHZhbHVlIGlzIGBmYWxzZWAuXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gcHJpbnRWZXJzaW9uKG5vTG9nbyA9IGZhbHNlKSB7XHJcbiAgLy8gR2V0IHBhY2thZ2UgdmVyc2lvbiBlaXRoZXIgZnJvbSBgLmVudmAgb3IgZnJvbSBgcGFja2FnZS5qc29uYFxyXG4gIGNvbnN0IHBhY2thZ2VWZXJzaW9uID0gSlNPTi5wYXJzZShcclxuICAgIHJlYWRGaWxlU3luYyhqb2luKF9fZGlybmFtZSwgJ3BhY2thZ2UuanNvbicpLCAndXRmOCcpXHJcbiAgKS52ZXJzaW9uO1xyXG5cclxuICAvLyBQcmludCB0ZXh0IG9ubHlcclxuICBpZiAobm9Mb2dvKSB7XHJcbiAgICBjb25zb2xlLmxvZyhgSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyIHYke3BhY2thZ2VWZXJzaW9ufWApO1xyXG4gIH0gZWxzZSB7XHJcbiAgICAvLyBQcmludCB0aGUgbG9nb1xyXG4gICAgY29uc29sZS5sb2coXHJcbiAgICAgIHJlYWRGaWxlU3luYyhqb2luKF9fZGlybmFtZSwgJ21zZycsICdzdGFydHVwLm1zZycpLCAndXRmOCcpLnRvU3RyaW5nKClcclxuICAgICAgICAuYm9sZC55ZWxsb3csXHJcbiAgICAgIGB2JHtwYWNrYWdlVmVyc2lvbn1cXG5gLmJvbGRcclxuICAgICk7XHJcbiAgfVxyXG59XHJcblxyXG4vKipcclxuICogSW5pdGlhbGl6ZXMgYW5kIHJldHVybnMgZ2xvYmFsIG9wdGlvbnMgb2JqZWN0IGJhc2VkIG9uIHByb3ZpZGVkXHJcbiAqIGNvbmZpZ3VyYXRpb24sIHNldHRpbmcgdmFsdWVzIGZyb20gbmVzdGVkIHByb3BlcnRpZXMgcmVjdXJzaXZlbHkuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBfaW5pdEdsb2JhbE9wdGlvbnNcclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IGNvbmZpZyAtIFRoZSBjb25maWd1cmF0aW9uIG9iamVjdCB0byBiZSB1c2VkIGZvciBpbml0aWFsaXppbmdcclxuICogb3B0aW9ucy5cclxuICpcclxuICogQHJldHVybnMge09iamVjdH0gSW5pdGlhbGl6ZWQgb3B0aW9ucyBvYmplY3QuXHJcbiAqL1xyXG5mdW5jdGlvbiBfaW5pdEdsb2JhbE9wdGlvbnMoY29uZmlnKSB7XHJcbiAgY29uc3Qgb3B0aW9ucyA9IHt9O1xyXG5cclxuICAvLyBTdGFydCBpbml0aWFsaXppbmcgdGhlIGBvcHRpb25zYCBvYmplY3QgcmVjdXJzaXZlbHlcclxuICBmb3IgKGNvbnN0IFtuYW1lLCBpdGVtXSBvZiBPYmplY3QuZW50cmllcyhjb25maWcpKSB7XHJcbiAgICBpZiAoT2JqZWN0LnByb3RvdHlwZS5oYXNPd25Qcm9wZXJ0eS5jYWxsKGl0ZW0sICd2YWx1ZScpKSB7XHJcbiAgICAgIC8vIElmIGEgdmFsdWUgZnJvbSBlbnZpcm9ubWVudCB2YXJpYWJsZXMgZXhpc3RzLCBpdCB0YWtlcyBwcmVjZWRlbmNlXHJcbiAgICAgIGNvbnN0IGVudlZhbCA9IGVudnNbaXRlbS5lbnZMaW5rXTtcclxuICAgICAgaWYgKGVudlZhbCAhPT0gdW5kZWZpbmVkICYmIGVudlZhbCAhPT0gbnVsbCkge1xyXG4gICAgICAgIG9wdGlvbnNbbmFtZV0gPSBlbnZWYWw7XHJcbiAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgb3B0aW9uc1tuYW1lXSA9IGl0ZW0udmFsdWU7XHJcbiAgICAgIH1cclxuICAgIH0gZWxzZSB7XHJcbiAgICAgIG9wdGlvbnNbbmFtZV0gPSBfaW5pdEdsb2JhbE9wdGlvbnMoaXRlbSk7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICAvLyBSZXR1cm4gdGhlIGNyZWF0ZWQgYG9wdGlvbnNgIG9iamVjdFxyXG4gIHJldHVybiBvcHRpb25zO1xyXG59XHJcblxyXG4vKipcclxuICogVXBkYXRlcyBnbG9iYWwgb3B0aW9ucyBvYmplY3Qgd2l0aCB2YWx1ZXMgZnJvbSB2YXJpb3VzIHNvdXJjZXMsIGZvbGxvd2luZ1xyXG4gKiBhIHNwZWNpZmljIHByaW9yaXRpemF0aW9uIG9yZGVyLiBUaGUgZnVuY3Rpb24gY2hlY2tzIGZvciB2YWx1ZXMgaW4gdGhlIG9yZGVyXHJcbiAqIG9mIHByZWNlZGVuY2U6IHRoZSBgbG9hZENvbmZpZ2AgY29uZmlndXJhdGlvbiBvcHRpb25zLCBlbnZpcm9ubWVudCB2YXJpYWJsZXMsXHJcbiAqIGN1c3RvbSBvcHRpb25zLCBhbmQgQ0xJIG9wdGlvbnMuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBfdXBkYXRlR2xvYmFsT3B0aW9uc1xyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gY29uZmlnIC0gVGhlIGNvbmZpZ3VyYXRpb24gb2JqZWN0LCB3aGljaCBpbmNsdWRlcyB0aGUgaW5pdGlhbFxyXG4gKiBzZXR0aW5ncyBhbmQgbWV0YWRhdGEgZm9yIGVhY2ggb3B0aW9uLiBUaGlzIG9iamVjdCBpcyB1c2VkIHRvIGRldGVybWluZVxyXG4gKiB0aGUgc3RydWN0dXJlIGFuZCBkZWZhdWx0IHZhbHVlcyBmb3IgdGhlIG9wdGlvbnMuXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBvcHRpb25zIC0gVGhlIGdsb2JhbCBvcHRpb25zIG9iamVjdCB0aGF0IHdpbGwgYmUgdXBkYXRlZFxyXG4gKiB3aXRoIHZhbHVlcyBmcm9tIG90aGVyIHNvdXJjZXMuXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBjb25maWdPcHQgLSBUaGUgY29uZmlndXJhdGlvbiBvcHRpb25zIG9iamVjdCwgbG9hZGVkIHdpdGhcclxuICogdGhlIGBsb2FkQ29uZmlnYCBvcHRpb24sIHdoaWNoIG1heSBwcm92aWRlIHZhbHVlcyB0byBvdmVycmlkZSBkZWZhdWx0cy5cclxuICogQHBhcmFtIHtPYmplY3R9IGNsaU9wdCAtIFRoZSBDTEkgb3B0aW9ucyBvYmplY3QsIHdoaWNoIG1heSBpbmNsdWRlIHZhbHVlc1xyXG4gKiBwcm92aWRlZCB0aHJvdWdoIGNvbW1hbmQtbGluZSBhcmd1bWVudHMgYW5kIG1heSBvdmVycmlkZSBjb25maWd1cmF0aW9uXHJcbiAqIG9wdGlvbnMuXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBjdXN0b21PcHQgLSBUaGUgY3VzdG9tIG9wdGlvbnMgb2JqZWN0LCB0eXBpY2FsbHkgY29udGFpbmluZ1xyXG4gKiBhZGRpdGlvbmFsIGFuZCB1c2VyLWRlZmluZWQgdmFsdWVzLCB3aGljaCBoYXMgdGhlIGhpZ2hlc3QgcHJlY2VkZW5jZSBhbW9uZ1xyXG4gKiBvcHRpb25zLlxyXG4gKi9cclxuZnVuY3Rpb24gX3VwZGF0ZUdsb2JhbE9wdGlvbnMoY29uZmlnLCBvcHRpb25zLCBjb25maWdPcHQsIGNsaU9wdCwgY3VzdG9tT3B0KSB7XHJcbiAgT2JqZWN0LmtleXMoY29uZmlnKS5mb3JFYWNoKChrZXkpID0+IHtcclxuICAgIC8vIEdldCB0aGUgY29uZmlnIGVudHJ5IG9mIGEgc3BlY2lmaWMgb3B0aW9uXHJcbiAgICBjb25zdCBlbnRyeSA9IGNvbmZpZ1trZXldO1xyXG5cclxuICAgIC8vIEdhdGhlciB2YWx1ZXMgZm9yIHRoZSBvcHRpb25zIGZyb20gZXZlcnkgcG9zc2libGUgc291cmNlLCBpZiBleGlzdHNcclxuICAgIGNvbnN0IGNvbmZpZ1ZhbCA9IGNvbmZpZ09wdCAmJiBjb25maWdPcHRba2V5XTtcclxuICAgIGNvbnN0IGNsaVZhbCA9IGNsaU9wdCAmJiBjbGlPcHRba2V5XTtcclxuICAgIGNvbnN0IGN1c3RvbVZhbCA9IGN1c3RvbU9wdCAmJiBjdXN0b21PcHRba2V5XTtcclxuXHJcbiAgICAvLyBJZiB0aGUgdmFsdWUgbm90IGZvdW5kLCBuZWVkIHRvIGdvIGRlZXBlclxyXG4gICAgaWYgKHR5cGVvZiBlbnRyeS52YWx1ZSA9PT0gJ3VuZGVmaW5lZCcpIHtcclxuICAgICAgX3VwZGF0ZUdsb2JhbE9wdGlvbnMoZW50cnksIG9wdGlvbnNba2V5XSwgY29uZmlnVmFsLCBjbGlWYWwsIGN1c3RvbVZhbCk7XHJcbiAgICB9IGVsc2Uge1xyXG4gICAgICAvLyBJZiBhIHZhbHVlIGZyb20gY3VzdG9tIEpTT04gb3B0aW9ucyBleGlzdHMsIGl0IHRha2VzIHByZWNlZGVuY2VcclxuICAgICAgaWYgKGNvbmZpZ1ZhbCAhPT0gdW5kZWZpbmVkICYmIGNvbmZpZ1ZhbCAhPT0gbnVsbCkge1xyXG4gICAgICAgIG9wdGlvbnNba2V5XSA9IGNvbmZpZ1ZhbDtcclxuICAgICAgfVxyXG5cclxuICAgICAgLy8gSWYgYSB2YWx1ZSBmcm9tIGVudmlyb25tZW50IHZhcmlhYmxlcyBleGlzdHMsIGl0IHRha2VzIHByZWNlZGVuY2VcclxuICAgICAgY29uc3QgZW52VmFsID0gZW52c1tlbnRyeS5lbnZMaW5rXTtcclxuICAgICAgaWYgKGVudHJ5LmVudkxpbmsgaW4gZW52cyAmJiBlbnZWYWwgIT09IHVuZGVmaW5lZCAmJiBlbnZWYWwgIT09IG51bGwpIHtcclxuICAgICAgICBvcHRpb25zW2tleV0gPSBlbnZWYWw7XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIC8vIElmIGEgdmFsdWUgZnJvbSBDTEkgb3B0aW9ucyBleGlzdHMsIGl0IHRha2VzIHByZWNlZGVuY2VcclxuICAgICAgaWYgKGNsaVZhbCAhPT0gdW5kZWZpbmVkICYmIGNsaVZhbCAhPT0gbnVsbCkge1xyXG4gICAgICAgIG9wdGlvbnNba2V5XSA9IGNsaVZhbDtcclxuICAgICAgfVxyXG5cclxuICAgICAgLy8gSWYgYSB2YWx1ZSBmcm9tIHVzZXIgb3B0aW9ucyBleGlzdHMsIGl0IHRha2VzIHByZWNlZGVuY2VcclxuICAgICAgaWYgKGN1c3RvbVZhbCAhPT0gdW5kZWZpbmVkICYmIGN1c3RvbVZhbCAhPT0gbnVsbCkge1xyXG4gICAgICAgIG9wdGlvbnNba2V5XSA9IGN1c3RvbVZhbDtcclxuICAgICAgfVxyXG4gICAgfVxyXG4gIH0pO1xyXG59XHJcblxyXG4vKipcclxuICogQ29udmVydHMgdGhlIHByb3ZpZGVkIG9wdGlvbnMgb2JqZWN0IHRvIGEgSlNPTi1mb3JtYXR0ZWQgc3RyaW5nXHJcbiAqIHdpdGggdGhlIG9wdGlvbiB0byBwcmVzZXJ2ZSBmdW5jdGlvbnMuIEluIG9yZGVyIGZvciBhIGZ1bmN0aW9uXHJcbiAqIHRvIGJlIHByZXNlcnZlZCwgaXQgbmVlZHMgdG8gZm9sbG93IHRoZSBmb3JtYXQgYGZ1bmN0aW9uICguLi4pIHsuLi59YC5cclxuICogU3VjaCBhIGZ1bmN0aW9uIGNhbiBhbHNvIGJlIHN0cmluZ2lmaWVkLlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gX29wdGlvbnNTdHJpbmdpZnlcclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IG9wdGlvbnMgLSBUaGUgb3B0aW9ucyBvYmplY3QgdG8gYmUgY29udmVydGVkIHRvIGEgc3RyaW5nLlxyXG4gKiBAcGFyYW0ge2Jvb2xlYW59IGFsbG93RnVuY3Rpb25zIC0gSWYgc2V0IHRvIHRydWUsIGZ1bmN0aW9ucyBhcmUgcHJlc2VydmVkXHJcbiAqIGluIHRoZSBvdXRwdXQuIE90aGVyd2lzZSBhbiBlcnJvciBpcyB0aHJvd24uXHJcbiAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaW5naWZ5RnVuY3Rpb25zIC0gSWYgc2V0IHRvIHRydWUsIGZ1bmN0aW9ucyBhcmUgc2F2ZWRcclxuICogYXMgc3RyaW5ncy4gVGhlIGBhbGxvd0Z1bmN0aW9uc2AgbXVzdCBiZSBzZXQgdG8gdHJ1ZSBhcyB3ZWxsIGZvciB0aGlzIHRvIHRha2VcclxuICogYW4gZWZmZWN0LlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7c3RyaW5nfSBUaGUgSlNPTi1mb3JtYXR0ZWQgc3RyaW5nIHJlcHJlc2VudGluZyB0aGUgb3B0aW9ucy5cclxuICpcclxuICogQHRocm93cyB7RXJyb3J9IFRocm93cyBhbiBgRXJyb3JgIHdoZW4gZnVuY3Rpb25zIGFyZSBub3QgYWxsb3dlZCBidXQgYXJlXHJcbiAqIGZvdW5kIGluIHByb3ZpZGVkIG9wdGlvbnMgb2JqZWN0LlxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIF9vcHRpb25zU3RyaW5naWZ5KG9wdGlvbnMsIGFsbG93RnVuY3Rpb25zLCBzdHJpbmdpZnlGdW5jdGlvbnMpIHtcclxuICBjb25zdCByZXBsYWNlckNhbGxiYWNrID0gKF8sIHZhbHVlKSA9PiB7XHJcbiAgICAvLyBUcmltIHN0cmluZyB2YWx1ZXNcclxuICAgIGlmICh0eXBlb2YgdmFsdWUgPT09ICdzdHJpbmcnKSB7XHJcbiAgICAgIHZhbHVlID0gdmFsdWUudHJpbSgpO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIElmIHZhbHVlIGlzIGEgZnVuY3Rpb24gb3Igc3RyaW5naWZpZWQgZnVuY3Rpb25cclxuICAgIGlmIChcclxuICAgICAgdHlwZW9mIHZhbHVlID09PSAnZnVuY3Rpb24nIHx8XHJcbiAgICAgICh0eXBlb2YgdmFsdWUgPT09ICdzdHJpbmcnICYmXHJcbiAgICAgICAgdmFsdWUuc3RhcnRzV2l0aCgnZnVuY3Rpb24nKSAmJlxyXG4gICAgICAgIHZhbHVlLmVuZHNXaXRoKCd9JykpXHJcbiAgICApIHtcclxuICAgICAgLy8gSWYgYWxsb3dGdW5jdGlvbnMgaXMgc2V0IHRvIHRydWUsIHByZXNlcnZlIGZ1bmN0aW9uc1xyXG4gICAgICBpZiAoYWxsb3dGdW5jdGlvbnMpIHtcclxuICAgICAgICAvLyBCYXNlZCBvbiB0aGUgYHN0cmluZ2lmeUZ1bmN0aW9uc2Agb3B0aW9ucywgc2V0IGZ1bmN0aW9uIHZhbHVlc1xyXG4gICAgICAgIHJldHVybiBzdHJpbmdpZnlGdW5jdGlvbnNcclxuICAgICAgICAgID8gLy8gQXMgc3RyaW5naWZpZWQgZnVuY3Rpb25zXHJcbiAgICAgICAgICAgIGBcIkVYUF9GVU4keyh2YWx1ZSArICcnKS5yZXBsYWNlQWxsKC9cXHMrL2csICcgJyl9RVhQX0ZVTlwiYFxyXG4gICAgICAgICAgOiAvLyBBcyBmdW5jdGlvbnNcclxuICAgICAgICAgICAgYEVYUF9GVU4keyh2YWx1ZSArICcnKS5yZXBsYWNlQWxsKC9cXHMrL2csICcgJyl9RVhQX0ZVTmA7XHJcbiAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgLy8gVGhyb3cgYW4gZXJyb3Igb3RoZXJ3aXNlXHJcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKCk7XHJcbiAgICAgIH1cclxuICAgIH1cclxuXHJcbiAgICAvLyBJbiBhbGwgb3RoZXIgY2FzZXMsIHNpbXBseSByZXR1cm4gdGhlIHZhbHVlXHJcbiAgICByZXR1cm4gdmFsdWU7XHJcbiAgfTtcclxuXHJcbiAgLy8gU3RyaW5naWZ5IG9wdGlvbnMgYW5kIGlmIHJlcXVpcmVkLCByZXBsYWNlIHNwZWNpYWwgZnVuY3Rpb25zIG1hcmtzXHJcbiAgcmV0dXJuIEpTT04uc3RyaW5naWZ5KG9wdGlvbnMsIHJlcGxhY2VyQ2FsbGJhY2spLnJlcGxhY2VBbGwoXHJcbiAgICBzdHJpbmdpZnlGdW5jdGlvbnMgPyAvXFxcXFwiRVhQX0ZVTnxFWFBfRlVOXFxcXFwiL2cgOiAvXCJFWFBfRlVOfEVYUF9GVU5cIi9nLFxyXG4gICAgJydcclxuICApO1xyXG59XHJcblxyXG4vKipcclxuICogTG9hZHMgYWRkaXRpb25hbCBjb25maWd1cmF0aW9uIGZyb20gYSBzcGVjaWZpZWQgZmlsZSBwcm92aWRlZCB2aWFcclxuICogdGhlIGBsb2FkQ29uZmlnYCBvcHRpb24gaW4gdGhlIGNvbW1hbmQtbGluZSBhcmd1bWVudHMuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBfbG9hZENvbmZpZ0ZpbGVcclxuICpcclxuICogQHBhcmFtIHtBcnJheS48c3RyaW5nPn0gY2xpQXJncyAtIENvbW1hbmQtbGluZSBhcmd1bWVudHMgdG8gc2VhcmNoXHJcbiAqIGZvciB0aGUgYGxvYWRDb25maWdgIG9wdGlvbiBhbmQgdGhlIGNvcnJlc3BvbmRpbmcgZmlsZSBwYXRoLlxyXG4gKiBAcGFyYW0ge09iamVjdH0gY3VzdG9tTG9naWNPcHRpb25zIC0gVGhlIGNvbmZpZ3VyYXRpb24gb2JqZWN0IGNvbnRhaW5pbmdcclxuICogYGN1c3RvbUxvZ2ljYCBvcHRpb25zLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7T2JqZWN0fSBUaGUgYWRkaXRpb25hbCBjb25maWd1cmF0aW9uIGxvYWRlZCBmcm9tIHRoZSBzcGVjaWZpZWRcclxuICogZmlsZSwgb3IgYW4gZW1wdHkgb2JqZWN0IGlmIHRoZSBmaWxlIGlzIG5vdCBmb3VuZCwgaW52YWxpZCwgb3IgYW4gZXJyb3JcclxuICogb2NjdXJzLlxyXG4gKi9cclxuZnVuY3Rpb24gX2xvYWRDb25maWdGaWxlKGNsaUFyZ3MsIGN1c3RvbUxvZ2ljT3B0aW9ucykge1xyXG4gIC8vIENoZWNrIGlmIHRoZSBgbG9hZENvbmZpZ2Agb3B0aW9uIHdhcyB1c2VkXHJcbiAgY29uc3QgY29uZmlnSW5kZXggPSBjbGlBcmdzLmZpbmRJbmRleChcclxuICAgIChhcmcpID0+IGFyZy5yZXBsYWNlKC8tL2csICcnKSA9PT0gJ2xvYWRDb25maWcnXHJcbiAgKTtcclxuXHJcbiAgLy8gR2V0IHRoZSBgbG9hZENvbmZpZ2Agb3B0aW9uIHZhbHVlXHJcbiAgY29uc3QgY29uZmlnRmlsZU5hbWUgPSBjb25maWdJbmRleCA+IC0xICYmIGNsaUFyZ3NbY29uZmlnSW5kZXggKyAxXTtcclxuXHJcbiAgLy8gQ2hlY2sgaWYgdGhlIGBsb2FkQ29uZmlnYCBpcyBwcmVzZW50IGFuZCBoYXMgYSBjb3JyZWN0IHZhbHVlXHJcbiAgaWYgKGNvbmZpZ0ZpbGVOYW1lICYmIGN1c3RvbUxvZ2ljT3B0aW9ucy5hbGxvd0ZpbGVSZXNvdXJjZXMpIHtcclxuICAgIHRyeSB7XHJcbiAgICAgIC8vIExvYWQgYW4gb3B0aW9uYWwgY3VzdG9tIEpTT04gY29uZmlnIGZpbGVcclxuICAgICAgcmV0dXJuIGlzQWxsb3dlZENvbmZpZyhcclxuICAgICAgICByZWFkRmlsZVN5bmMoZ2V0QWJzb2x1dGVQYXRoKGNvbmZpZ0ZpbGVOYW1lKSwgJ3V0ZjgnKSxcclxuICAgICAgICBmYWxzZSxcclxuICAgICAgICBjdXN0b21Mb2dpY09wdGlvbnMuYWxsb3dDb2RlRXhlY3V0aW9uXHJcbiAgICAgICk7XHJcbiAgICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgICBsb2dXaXRoU3RhY2soXHJcbiAgICAgICAgMixcclxuICAgICAgICBlcnJvcixcclxuICAgICAgICBgW2NvbmZpZ10gVW5hYmxlIHRvIGxvYWQgdGhlIGNvbmZpZ3VyYXRpb24gZnJvbSB0aGUgJHtjb25maWdGaWxlTmFtZX0gZmlsZS5gXHJcbiAgICAgICk7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICAvLyBObyBhZGRpdGlvbmFsIG9wdGlvbnMgdG8gcmV0dXJuXHJcbiAgcmV0dXJuIHt9O1xyXG59XHJcblxyXG4vKipcclxuICogUGFyc2VzIGNvbW1hbmQtbGluZSBhcmd1bWVudHMgYW5kIHBhaXJzIGVhY2ggYXJndW1lbnQgd2l0aCBpdHMgY29ycmVzcG9uZGluZ1xyXG4gKiBvcHRpb24gaW4gdGhlIGNvbmZpZ3VyYXRpb24uIFRoZSB2YWx1ZXMgYXJlIHN0cnVjdHVyZWQgaW50byBhIG5lc3RlZCBvcHRpb25zXHJcbiAqIG9iamVjdCwgYmFzZWQgb24gcHJlZGVmaW5lZCBtYXBwaW5ncy5cclxuICpcclxuICogQGZ1bmN0aW9uIF9wYWlyQXJndW1lbnRWYWx1ZVxyXG4gKlxyXG4gKiBAcGFyYW0ge0FycmF5LjxzdHJpbmc+fSBuZXN0ZWRQcm9wcyAtIEFuIGFycmF5IG9mIG5lc3RpbmcgbGV2ZWwgZm9yIGFsbFxyXG4gKiBvcHRpb25zLlxyXG4gKiBAcGFyYW0ge0FycmF5LjxzdHJpbmc+fSBjbGlBcmdzIC0gQW4gYXJyYXkgb2YgY29tbWFuZC1saW5lIGFyZ3VtZW50c1xyXG4gKiBjb250YWluaW5nIG9wdGlvbnMgYW5kIHRoZWlyIGFzc29jaWF0ZWQgdmFsdWVzLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7T2JqZWN0fSBBbiB1cGRhdGVkIG9wdGlvbnMgb2JqZWN0IHdoZXJlIGVhY2ggb3B0aW9uIGZyb21cclxuICogdGhlIGNvbW1hbmQtbGluZSBpcyBwYWlyZWQgd2l0aCBpdHMgdmFsdWUsIHN0cnVjdHVyZWQgaW50byBuZXN0ZWQgb2JqZWN0c1xyXG4gKiBhcyBkZWZpbmVkLlxyXG4gKi9cclxuZnVuY3Rpb24gX3BhaXJBcmd1bWVudFZhbHVlKG5lc3RlZFByb3BzLCBjbGlBcmdzKSB7XHJcbiAgLy8gQW4gZW1wdHkgb2JqZWN0IHRvIGNvbGxlY3QgYW5kIHN0cnVjdHVyaXplIGRhdGEgZnJvbSB0aGUgYXJnc1xyXG4gIGNvbnN0IGNsaU9wdGlvbnMgPSB7fTtcclxuXHJcbiAgLy8gQ3ljbGUgdGhyb3VnaCBhbGwgQ0xJIGFyZ3MgYW5kIGZpbHRlciB0aGVtXHJcbiAgZm9yIChsZXQgaSA9IDA7IGkgPCBjbGlBcmdzLmxlbmd0aDsgaSsrKSB7XHJcbiAgICBjb25zdCBvcHRpb24gPSBjbGlBcmdzW2ldLnJlcGxhY2UoLy0vZywgJycpO1xyXG5cclxuICAgIC8vIEZpbmQgdGhlIHJpZ2h0IHBsYWNlIGZvciBwcm9wZXJ0eSdzIHZhbHVlXHJcbiAgICBjb25zdCBwcm9wZXJ0aWVzQ2hhaW4gPSBuZXN0ZWRQcm9wc1tvcHRpb25dXHJcbiAgICAgID8gbmVzdGVkUHJvcHNbb3B0aW9uXS5zcGxpdCgnLicpXHJcbiAgICAgIDogW107XHJcblxyXG4gICAgLy8gQ3JlYXRlIG9wdGlvbnMgb2JqZWN0IHdpdGggdmFsdWVzIGZyb20gQ0xJIGZvciBsYXRlciBwYXJzaW5nIGFuZCBtZXJnaW5nXHJcbiAgICBwcm9wZXJ0aWVzQ2hhaW4ucmVkdWNlKChvYmosIHByb3AsIGluZGV4KSA9PiB7XHJcbiAgICAgIGlmIChwcm9wZXJ0aWVzQ2hhaW4ubGVuZ3RoIC0gMSA9PT0gaW5kZXgpIHtcclxuICAgICAgICBjb25zdCB2YWx1ZSA9IGNsaUFyZ3NbKytpXTtcclxuICAgICAgICBpZiAoIXZhbHVlKSB7XHJcbiAgICAgICAgICBsb2coXHJcbiAgICAgICAgICAgIDIsXHJcbiAgICAgICAgICAgIGBbY29uZmlnXSBNaXNzaW5nIHZhbHVlIGZvciB0aGUgQ0xJICctLSR7b3B0aW9ufScgYXJndW1lbnQuIFVzaW5nIHRoZSBkZWZhdWx0IHZhbHVlLmBcclxuICAgICAgICAgICk7XHJcbiAgICAgICAgfVxyXG4gICAgICAgIG9ialtwcm9wXSA9IHZhbHVlIHx8IG51bGw7XHJcbiAgICAgIH0gZWxzZSBpZiAob2JqW3Byb3BdID09PSB1bmRlZmluZWQpIHtcclxuICAgICAgICBvYmpbcHJvcF0gPSB7fTtcclxuICAgICAgfVxyXG4gICAgICByZXR1cm4gb2JqW3Byb3BdO1xyXG4gICAgfSwgY2xpT3B0aW9ucyk7XHJcbiAgfVxyXG5cclxuICAvLyBSZXR1cm4gcGFyc2VkIENMSSBvcHRpb25zXHJcbiAgcmV0dXJuIGNsaU9wdGlvbnM7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBSZWN1cnNpdmVseSB0cmF2ZXJzZXMgdGhlIG9wdGlvbnMgb2JqZWN0IHRvIHByaW50IHRoZSB1c2FnZSBpbmZvcm1hdGlvblxyXG4gKiBmb3IgZWFjaCBvcHRpb24gY2F0ZWdvcnkgYW5kIGluZGl2aWR1YWwgb3B0aW9uLlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gX2N5Y2xlQ2F0ZWdvcmllc1xyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gb3B0aW9ucyAtIFRoZSBvcHRpb25zIG9iamVjdCBjb250YWluaW5nIENMSSBvcHRpb25zLiBJdCBtYXlcclxuICogaW5jbHVkZSBuZXN0ZWQgY2F0ZWdvcmllcyBhbmQgaW5kaXZpZHVhbCBvcHRpb25zLlxyXG4gKi9cclxuZnVuY3Rpb24gX2N5Y2xlQ2F0ZWdvcmllcyhvcHRpb25zKSB7XHJcbiAgZm9yIChjb25zdCBbbmFtZSwgb3B0aW9uXSBvZiBPYmplY3QuZW50cmllcyhvcHRpb25zKSkge1xyXG4gICAgLy8gSWYgdGhlIGN1cnJlbnQgZW50cnkgaXMgYSBjYXRlZ29yeSBhbmQgbm90IGEgbGVhZiBvcHRpb24sIHJlY3Vyc2UgaW50byBpdFxyXG4gICAgaWYgKCFPYmplY3QucHJvdG90eXBlLmhhc093blByb3BlcnR5LmNhbGwob3B0aW9uLCAndmFsdWUnKSkge1xyXG4gICAgICBfY3ljbGVDYXRlZ29yaWVzKG9wdGlvbik7XHJcbiAgICB9IGVsc2Uge1xyXG4gICAgICAvLyBQcmVwYXJlIGRlc2NyaXB0aW9uXHJcbiAgICAgIGNvbnN0IGRlc2NOYW1lID0gYCAtLSR7b3B0aW9uLmNsaU5hbWUgfHwgbmFtZX1gO1xyXG5cclxuICAgICAgLy8gR2V0IHRoZSB2YWx1ZVxyXG4gICAgICBsZXQgb3B0aW9uVmFsdWUgPSBvcHRpb24udmFsdWU7XHJcblxyXG4gICAgICAvLyBQcmVwYXJlIHZhbHVlIGZvciBvcHRpb24gdGhhdCBpcyBub3QgbnVsbCBhbmQgaXMgYXJyYXkgb2Ygc3RyaW5nc1xyXG4gICAgICBpZiAob3B0aW9uVmFsdWUgIT09IG51bGwgJiYgb3B0aW9uLnR5cGVzLmluY2x1ZGVzKCdzdHJpbmdbXScpKSB7XHJcbiAgICAgICAgb3B0aW9uVmFsdWUgPVxyXG4gICAgICAgICAgJ1snICsgb3B0aW9uVmFsdWUubWFwKChpdGVtKSA9PiBgJyR7aXRlbX0nYCkuam9pbignLCAnKSArICddJztcclxuICAgICAgfVxyXG5cclxuICAgICAgLy8gUHJlcGFyZSB2YWx1ZSBmb3Igb3B0aW9uIHRoYXQgaXMgbm90IG51bGwgYW5kIGlzIGEgc3RyaW5nXHJcbiAgICAgIGlmIChvcHRpb25WYWx1ZSAhPT0gbnVsbCAmJiBvcHRpb24udHlwZXMuaW5jbHVkZXMoJ3N0cmluZycpKSB7XHJcbiAgICAgICAgb3B0aW9uVmFsdWUgPSBgJyR7b3B0aW9uVmFsdWV9J2A7XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIC8vIERpc3BsYXkgY29ycmVjdGx5IGFsaWduZWQgbWVzc2FnZXNcclxuICAgICAgY29uc29sZS5sb2coXHJcbiAgICAgICAgZGVzY05hbWUuZ3JlZW4sXHJcbiAgICAgICAgYCR7KCc8JyArIG9wdGlvbi50eXBlcy5qb2luKCd8JykgKyAnPicpLnllbGxvd31gLFxyXG4gICAgICAgIGAke1N0cmluZyhvcHRpb25WYWx1ZSkuYm9sZH1gLmJsdWUsXHJcbiAgICAgICAgYC0gJHtvcHRpb24uZGVzY3JpcHRpb259LmBcclxuICAgICAgKTtcclxuICAgIH1cclxuICB9XHJcbn1cclxuXHJcbmV4cG9ydCBkZWZhdWx0IHtcclxuICBnZXRPcHRpb25zLFxyXG4gIHNldEdsb2JhbE9wdGlvbnMsXHJcbiAgdXBkYXRlT3B0aW9ucyxcclxuICBtZXJnZU9wdGlvbnMsXHJcbiAgbWFwVG9OZXdPcHRpb25zLFxyXG4gIHZhbGlkYXRlT3B0aW9uLFxyXG4gIHZhbGlkYXRlT3B0aW9ucyxcclxuICBpc0FsbG93ZWRDb25maWcsXHJcbiAgcHJpbnRMaWNlbnNlLFxyXG4gIHByaW50VXNhZ2UsXHJcbiAgcHJpbnRWZXJzaW9uXHJcbn07XHJcbiIsIi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXHJcblxyXG5IaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXJcclxuXHJcbkNvcHlyaWdodCAoYykgMjAxNi0yMDI1LCBIaWdoc29mdFxyXG5cclxuTGljZW5jZWQgdW5kZXIgdGhlIE1JVCBsaWNlbmNlLlxyXG5cclxuQWRkaXRpb25hbGx5IGEgdmFsaWQgSGlnaGNoYXJ0cyBsaWNlbnNlIGlzIHJlcXVpcmVkIGZvciB1c2UuXHJcblxyXG5TZWUgTElDRU5TRSBmaWxlIGluIHJvb3QgZm9yIGRldGFpbHMuXHJcblxyXG4qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xyXG5cclxuLyoqXHJcbiAqIEBvdmVydmlldyBIVFRQIHV0aWxpdHkgbW9kdWxlIGZvciBmZXRjaGluZyBhbmQgcG9zdGluZyBkYXRhLiBTdXBwb3J0cyBib3RoXHJcbiAqIEhUVFAgYW5kIEhUVFBTIHByb3RvY29scywgcHJvdmlkaW5nIG1ldGhvZHMgdG8gbWFrZSBHRVQgYW5kIFBPU1QgcmVxdWVzdHNcclxuICogd2l0aCBjdXN0b21pemFibGUgb3B0aW9ucy4gSW5jbHVkZXMgcHJvdG9jb2wgZGV0ZXJtaW5hdGlvbiBiYXNlZCBvbiBVUkxcclxuICogYW5kIGF1Z21lbnRzIHJlc3BvbnNlIG9iamVjdHMgd2l0aCBhICd0ZXh0JyBwcm9wZXJ0eSBmb3IgZWFzaWVyIGRhdGEgYWNjZXNzLlxyXG4gKi9cclxuXHJcbmltcG9ydCBodHRwIGZyb20gJ2h0dHAnO1xyXG5pbXBvcnQgaHR0cHMgZnJvbSAnaHR0cHMnO1xyXG5cclxuLyoqXHJcbiAqIEZldGNoZXMgZGF0YSBmcm9tIHRoZSBzcGVjaWZpZWQgVVJMIHVzaW5nIGVpdGhlciBIVFRQIG9yIEhUVFBTIHByb3RvY29sLlxyXG4gKlxyXG4gKiBAYXN5bmNcclxuICogQGZ1bmN0aW9uIGZldGNoXHJcbiAqXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSB1cmwgLSBUaGUgVVJMIHRvIGZldGNoIGRhdGEgZnJvbS5cclxuICogQHBhcmFtIHtPYmplY3R9IFtyZXF1ZXN0T3B0aW9ucz17fV0gLSBPcHRpb25zIGZvciB0aGUgSFRUUC9IVFRQUyByZXF1ZXN0LlxyXG4gKiBUaGUgZGVmYXVsdCB2YWx1ZSBpcyBhbiBlbXB0eSBvYmplY3QuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtQcm9taXNlPE9iamVjdD59IEEgUHJvbWlzZSB0aGF0IHJlc29sdmVzIHRvIHRoZSBIVFRQL0hUVFBTIHJlc3BvbnNlXHJcbiAqIG9iamVjdCB3aXRoIGFkZGVkICd0ZXh0JyBwcm9wZXJ0eSBvciByZWplY3Rpbmcgd2l0aCBhbiBlcnJvci5cclxuICovXHJcbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBmZXRjaCh1cmwsIHJlcXVlc3RPcHRpb25zID0ge30pIHtcclxuICByZXR1cm4gbmV3IFByb21pc2UoKHJlc29sdmUsIHJlamVjdCkgPT4ge1xyXG4gICAgX2dldFByb3RvY29sTW9kdWxlKHVybClcclxuICAgICAgLmdldCh1cmwsIHJlcXVlc3RPcHRpb25zLCAocmVzcG9uc2UpID0+IHtcclxuICAgICAgICBsZXQgcmVzcG9uc2VEYXRhID0gJyc7XHJcblxyXG4gICAgICAgIC8vIEEgY2h1bmsgb2YgZGF0YSBoYXMgYmVlbiByZWNlaXZlZFxyXG4gICAgICAgIHJlc3BvbnNlLm9uKCdkYXRhJywgKGNodW5rKSA9PiB7XHJcbiAgICAgICAgICByZXNwb25zZURhdGEgKz0gY2h1bms7XHJcbiAgICAgICAgfSk7XHJcblxyXG4gICAgICAgIC8vIFRoZSB3aG9sZSByZXNwb25zZSBoYXMgYmVlbiByZWNlaXZlZFxyXG4gICAgICAgIHJlc3BvbnNlLm9uKCdlbmQnLCAoKSA9PiB7XHJcbiAgICAgICAgICBpZiAoIXJlc3BvbnNlRGF0YSkge1xyXG4gICAgICAgICAgICByZWplY3QoJ05vdGhpbmcgd2FzIGZldGNoZWQgZnJvbSB0aGUgVVJMLicpO1xyXG4gICAgICAgICAgfVxyXG4gICAgICAgICAgcmVzcG9uc2UudGV4dCA9IHJlc3BvbnNlRGF0YTtcclxuICAgICAgICAgIHJlc29sdmUocmVzcG9uc2UpO1xyXG4gICAgICAgIH0pO1xyXG4gICAgICB9KVxyXG4gICAgICAub24oJ2Vycm9yJywgKGVycm9yKSA9PiB7XHJcbiAgICAgICAgcmVqZWN0KGVycm9yKTtcclxuICAgICAgfSk7XHJcbiAgfSk7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBTZW5kcyBhIFBPU1QgcmVxdWVzdCB0byB0aGUgc3BlY2lmaWVkIFVSTCB3aXRoIHRoZSBwcm92aWRlZCBKU09OIGJvZHkgdXNpbmdcclxuICogZWl0aGVyIEhUVFAgb3IgSFRUUFMgcHJvdG9jb2wuXHJcbiAqXHJcbiAqIEBhc3luY1xyXG4gKiBAZnVuY3Rpb24gcG9zdFxyXG4gKlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gdXJsIC0gVGhlIFVSTCB0byBzZW5kIHRoZSBQT1NUIHJlcXVlc3QgdG8uXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBbYm9keT17fV0gLSBUaGUgSlNPTiBib2R5IHRvIGluY2x1ZGUgaW4gdGhlIFBPU1QgcmVxdWVzdC5cclxuICogVGhlIGRlZmF1bHQgdmFsdWUgaXMgYW4gZW1wdHkgb2JqZWN0LlxyXG4gKiBAcGFyYW0ge09iamVjdH0gW3JlcXVlc3RPcHRpb25zPXt9XSAtIE9wdGlvbnMgZm9yIHRoZSBIVFRQL0hUVFBTIHJlcXVlc3QuXHJcbiAqIFRoZSBkZWZhdWx0IHZhbHVlIGlzIGFuIGVtcHR5IG9iamVjdC5cclxuICpcclxuICogQHJldHVybnMge1Byb21pc2U8T2JqZWN0Pn0gQSBQcm9taXNlIHRoYXQgcmVzb2x2ZXMgdG8gdGhlIEhUVFAvSFRUUFMgcmVzcG9uc2VcclxuICogb2JqZWN0IHdpdGggYWRkZWQgJ3RleHQnIHByb3BlcnR5IG9yIHJlamVjdGluZyB3aXRoIGFuIGVycm9yLlxyXG4gKi9cclxuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIHBvc3QodXJsLCBib2R5ID0ge30sIHJlcXVlc3RPcHRpb25zID0ge30pIHtcclxuICByZXR1cm4gbmV3IFByb21pc2UoKHJlc29sdmUsIHJlamVjdCkgPT4ge1xyXG4gICAgY29uc3QgZGF0YSA9IEpTT04uc3RyaW5naWZ5KGJvZHkpO1xyXG5cclxuICAgIC8vIFNldCBkZWZhdWx0IGhlYWRlcnMgYW5kIG1lcmdlIHdpdGggcmVxdWVzdE9wdGlvbnNcclxuICAgIGNvbnN0IG9wdGlvbnMgPSBPYmplY3QuYXNzaWduKFxyXG4gICAgICB7XHJcbiAgICAgICAgbWV0aG9kOiAnUE9TVCcsXHJcbiAgICAgICAgaGVhZGVyczoge1xyXG4gICAgICAgICAgJ0NvbnRlbnQtVHlwZSc6ICdhcHBsaWNhdGlvbi9qc29uJyxcclxuICAgICAgICAgICdDb250ZW50LUxlbmd0aCc6IGRhdGEubGVuZ3RoXHJcbiAgICAgICAgfVxyXG4gICAgICB9LFxyXG4gICAgICByZXF1ZXN0T3B0aW9uc1xyXG4gICAgKTtcclxuXHJcbiAgICBjb25zdCByZXF1ZXN0ID0gX2dldFByb3RvY29sTW9kdWxlKHVybClcclxuICAgICAgLnJlcXVlc3QodXJsLCBvcHRpb25zLCAocmVzcG9uc2UpID0+IHtcclxuICAgICAgICBsZXQgcmVzcG9uc2VEYXRhID0gJyc7XHJcblxyXG4gICAgICAgIC8vIEEgY2h1bmsgb2YgZGF0YSBoYXMgYmVlbiByZWNlaXZlZFxyXG4gICAgICAgIHJlc3BvbnNlLm9uKCdkYXRhJywgKGNodW5rKSA9PiB7XHJcbiAgICAgICAgICByZXNwb25zZURhdGEgKz0gY2h1bms7XHJcbiAgICAgICAgfSk7XHJcblxyXG4gICAgICAgIC8vIFRoZSB3aG9sZSByZXNwb25zZSBoYXMgYmVlbiByZWNlaXZlZFxyXG4gICAgICAgIHJlc3BvbnNlLm9uKCdlbmQnLCAoKSA9PiB7XHJcbiAgICAgICAgICB0cnkge1xyXG4gICAgICAgICAgICByZXNwb25zZS50ZXh0ID0gcmVzcG9uc2VEYXRhO1xyXG4gICAgICAgICAgICByZXNvbHZlKHJlc3BvbnNlKTtcclxuICAgICAgICAgIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICAgICAgICAgIHJlamVjdChlcnJvcik7XHJcbiAgICAgICAgICB9XHJcbiAgICAgICAgfSk7XHJcbiAgICAgIH0pXHJcbiAgICAgIC5vbignZXJyb3InLCAoZXJyb3IpID0+IHtcclxuICAgICAgICByZWplY3QoZXJyb3IpO1xyXG4gICAgICB9KTtcclxuXHJcbiAgICAvLyBXcml0ZSB0aGUgcmVxdWVzdCBib2R5IGFuZCBlbmQgdGhlIHJlcXVlc3RcclxuICAgIHJlcXVlc3Qud3JpdGUoZGF0YSk7XHJcbiAgICByZXF1ZXN0LmVuZCgpO1xyXG4gIH0pO1xyXG59XHJcblxyXG4vKipcclxuICogUmV0dXJucyB0aGUgSFRUUCBvciBIVFRQUyBwcm90b2NvbCBtb2R1bGUgYmFzZWQgb24gdGhlIHByb3ZpZGVkIFVSTC5cclxuICpcclxuICogQGZ1bmN0aW9uIF9nZXRQcm90b2NvbE1vZHVsZVxyXG4gKlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gdXJsIC0gVGhlIFVSTCB0byBkZXRlcm1pbmUgdGhlIHByb3RvY29sLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7T2JqZWN0fSBUaGUgSFRUUCBvciBIVFRQUyBwcm90b2NvbCBtb2R1bGUgKGh0dHAgb3IgaHR0cHMpLlxyXG4gKi9cclxuZnVuY3Rpb24gX2dldFByb3RvY29sTW9kdWxlKHVybCkge1xyXG4gIHJldHVybiB1cmwuc3RhcnRzV2l0aCgnaHR0cHMnKSA/IGh0dHBzIDogaHR0cDtcclxufVxyXG5cclxuZXhwb3J0IGRlZmF1bHQge1xyXG4gIGZldGNoLFxyXG4gIHBvc3RcclxufTtcclxuIiwiLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcclxuXHJcbkhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlclxyXG5cclxuQ29weXJpZ2h0IChjKSAyMDE2LTIwMjUsIEhpZ2hzb2Z0XHJcblxyXG5MaWNlbmNlZCB1bmRlciB0aGUgTUlUIGxpY2VuY2UuXHJcblxyXG5BZGRpdGlvbmFsbHkgYSB2YWxpZCBIaWdoY2hhcnRzIGxpY2Vuc2UgaXMgcmVxdWlyZWQgZm9yIHVzZS5cclxuXHJcblNlZSBMSUNFTlNFIGZpbGUgaW4gcm9vdCBmb3IgZGV0YWlscy5cclxuXHJcbioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXHJcblxyXG4vKipcclxuICogQG92ZXJ2aWV3IFRoZSBjYWNoZSBtYW5hZ2VyIGlzIHJlc3BvbnNpYmxlIGZvciBoYW5kbGluZyBhbmQgbWFuYWdpbmdcclxuICogdGhlIEhpZ2hjaGFydHMgbGlicmFyeSBhbG9uZyB3aXRoIGl0cyBkZXBlbmRlbmNpZXMuIEl0IGVuc3VyZXMgdGhhdCB0aGVzZVxyXG4gKiByZXNvdXJjZXMgYXJlIHN0b3JlZCBhbmQgcmV0cmlldmVkIGVmZmljaWVudGx5IHRvIG9wdGltaXplIHBlcmZvcm1hbmNlXHJcbiAqIGFuZCByZWR1Y2UgcmVkdW5kYW50IG5ldHdvcmsgcmVxdWVzdHMuIFRoZSBjYWNoZSBpcyBzdG9yZWQgaW4gdGhlIGAuY2FjaGVgXHJcbiAqIGRpcmVjdG9yeSBieSBkZWZhdWx0LCB3aGljaCBzZXJ2ZXMgYXMgYSBkZWRpY2F0ZWQgZm9sZGVyIGZvciBrZWVwaW5nIGNhY2hlZFxyXG4gKiBmaWxlcy5cclxuICovXHJcblxyXG5pbXBvcnQgeyBleGlzdHNTeW5jLCBta2RpclN5bmMsIHJlYWRGaWxlU3luYywgd3JpdGVGaWxlU3luYyB9IGZyb20gJ2ZzJztcclxuaW1wb3J0IHsgam9pbiB9IGZyb20gJ3BhdGgnO1xyXG5cclxuaW1wb3J0IHsgSHR0cHNQcm94eUFnZW50IH0gZnJvbSAnaHR0cHMtcHJveHktYWdlbnQnO1xyXG5cclxuaW1wb3J0IHsgZ2V0T3B0aW9ucyB9IGZyb20gJy4vY29uZmlnLmpzJztcclxuaW1wb3J0IHsgZmV0Y2ggfSBmcm9tICcuL2ZldGNoLmpzJztcclxuaW1wb3J0IHsgbG9nIH0gZnJvbSAnLi9sb2dnZXIuanMnO1xyXG5pbXBvcnQgeyBfX2Rpcm5hbWUsIGdldEFic29sdXRlUGF0aCB9IGZyb20gJy4vdXRpbHMuanMnO1xyXG5cclxuaW1wb3J0IEV4cG9ydEVycm9yIGZyb20gJy4vZXJyb3JzL0V4cG9ydEVycm9yLmpzJztcclxuXHJcbi8vIFRoZSBpbml0aWFsIGNhY2hlIHRlbXBsYXRlXHJcbmNvbnN0IGNhY2hlID0ge1xyXG4gIGNkblVybDogJ2h0dHBzOi8vY29kZS5oaWdoY2hhcnRzLmNvbScsXHJcbiAgYWN0aXZlTWFuaWZlc3Q6IHt9LFxyXG4gIHNvdXJjZXM6ICcnLFxyXG4gIGhjVmVyc2lvbjogJydcclxufTtcclxuXHJcbi8qKlxyXG4gKiBDaGVja3MgdGhlIGNhY2hlIGZvciBIaWdoY2hhcnRzIGRlcGVuZGVuY2llcywgdXBkYXRlcyB0aGUgY2FjaGUgaWYgbmVlZGVkLFxyXG4gKiBhbmQgbG9hZHMgdGhlIHNvdXJjZXMuXHJcbiAqXHJcbiAqIEBhc3luY1xyXG4gKiBAZnVuY3Rpb24gY2hlY2tBbmRVcGRhdGVDYWNoZVxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gaGlnaGNoYXJ0c09wdGlvbnMgLSBUaGUgY29uZmlndXJhdGlvbiBvYmplY3QgY29udGFpbmluZ1xyXG4gKiBgaGlnaGNoYXJ0c2Agb3B0aW9ucy5cclxuICogQHBhcmFtIHtPYmplY3R9IHNlcnZlclByb3h5T3B0aW9ucy0gVGhlIGNvbmZpZ3VyYXRpb24gb2JqZWN0IGNvbnRhaW5pbmdcclxuICogYHNlcnZlci5wcm94eWAgb3B0aW9ucy5cclxuICovXHJcbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBjaGVja0FuZFVwZGF0ZUNhY2hlKFxyXG4gIGhpZ2hjaGFydHNPcHRpb25zLFxyXG4gIHNlcnZlclByb3h5T3B0aW9uc1xyXG4pIHtcclxuICB0cnkge1xyXG4gICAgbGV0IGZldGNoZWRNb2R1bGVzO1xyXG5cclxuICAgIC8vIEdldCB0aGUgY2FjaGUgcGF0aFxyXG4gICAgY29uc3QgY2FjaGVQYXRoID0gZ2V0Q2FjaGVQYXRoKCk7XHJcblxyXG4gICAgLy8gUHJlcGFyZSBwYXRocyB0byBtYW5pZmVzdCBhbmQgc291cmNlcyBmcm9tIHRoZSBjYWNoZSBmb2xkZXJcclxuICAgIGNvbnN0IG1hbmlmZXN0UGF0aCA9IGpvaW4oY2FjaGVQYXRoLCAnbWFuaWZlc3QuanNvbicpO1xyXG4gICAgY29uc3Qgc291cmNlUGF0aCA9IGpvaW4oY2FjaGVQYXRoLCAnc291cmNlcy5qcycpO1xyXG5cclxuICAgIC8vIENyZWF0ZSB0aGUgY2FjaGUgZGVzdGluYXRpb24gaWYgaXQgZG9lc24ndCBleGlzdCBhbHJlYWR5XHJcbiAgICAhZXhpc3RzU3luYyhjYWNoZVBhdGgpICYmIG1rZGlyU3luYyhjYWNoZVBhdGgsIHsgcmVjdXJzaXZlOiB0cnVlIH0pO1xyXG5cclxuICAgIC8vIEZldGNoIGFsbCB0aGUgc2NyaXB0cyBlaXRoZXIgaWYgdGhlIGBtYW5pZmVzdC5qc29uYCBkb2VzIG5vdCBleGlzdFxyXG4gICAgLy8gb3IgaWYgdGhlIGBmb3JjZUZldGNoYCBvcHRpb24gaXMgZW5hYmxlZFxyXG4gICAgaWYgKCFleGlzdHNTeW5jKG1hbmlmZXN0UGF0aCkgfHwgaGlnaGNoYXJ0c09wdGlvbnMuZm9yY2VGZXRjaCkge1xyXG4gICAgICBsb2coMywgJ1tjYWNoZV0gRmV0Y2hpbmcgYW5kIGNhY2hpbmcgSGlnaGNoYXJ0cyBkZXBlbmRlbmNpZXMuJyk7XHJcbiAgICAgIGZldGNoZWRNb2R1bGVzID0gYXdhaXQgX3VwZGF0ZUNhY2hlKFxyXG4gICAgICAgIGhpZ2hjaGFydHNPcHRpb25zLFxyXG4gICAgICAgIHNlcnZlclByb3h5T3B0aW9ucyxcclxuICAgICAgICBzb3VyY2VQYXRoXHJcbiAgICAgICk7XHJcbiAgICB9IGVsc2Uge1xyXG4gICAgICBsZXQgcmVxdWVzdFVwZGF0ZSA9IGZhbHNlO1xyXG5cclxuICAgICAgLy8gUmVhZCB0aGUgbWFuaWZlc3QgSlNPTlxyXG4gICAgICBjb25zdCBtYW5pZmVzdCA9IEpTT04ucGFyc2UocmVhZEZpbGVTeW5jKG1hbmlmZXN0UGF0aCksICd1dGY4Jyk7XHJcblxyXG4gICAgICAvLyBDaGVjayBpZiB0aGUgbW9kdWxlcyBpcyBhbiBhcnJheSwgaWYgc28sIHdlIHJld3JpdGUgaXQgdG8gYSBtYXAgdG8gbWFrZVxyXG4gICAgICAvLyBpdCBlYXNpZXIgdG8gcmVzb2x2ZSBtb2R1bGVzLlxyXG4gICAgICBpZiAobWFuaWZlc3QubW9kdWxlcyAmJiBBcnJheS5pc0FycmF5KG1hbmlmZXN0Lm1vZHVsZXMpKSB7XHJcbiAgICAgICAgY29uc3QgbW9kdWxlTWFwID0ge307XHJcbiAgICAgICAgbWFuaWZlc3QubW9kdWxlcy5mb3JFYWNoKChtKSA9PiAobW9kdWxlTWFwW21dID0gMSkpO1xyXG4gICAgICAgIG1hbmlmZXN0Lm1vZHVsZXMgPSBtb2R1bGVNYXA7XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIC8vIEdldCB0aGUgYWN0dWFsIG51bWJlciBvZiBzY3JpcHRzIHRvIGJlIGZldGNoZWRcclxuICAgICAgY29uc3QgeyBjb3JlU2NyaXB0cywgbW9kdWxlU2NyaXB0cywgaW5kaWNhdG9yU2NyaXB0cyB9ID1cclxuICAgICAgICBoaWdoY2hhcnRzT3B0aW9ucztcclxuICAgICAgY29uc3QgbnVtYmVyT2ZNb2R1bGVzID1cclxuICAgICAgICBjb3JlU2NyaXB0cy5sZW5ndGggKyBtb2R1bGVTY3JpcHRzLmxlbmd0aCArIGluZGljYXRvclNjcmlwdHMubGVuZ3RoO1xyXG5cclxuICAgICAgLy8gQ29tcGFyZSB0aGUgbG9hZGVkIGhpZ2hjaGFydHMgY29uZmlnIHdpdGggdGhlIGNvbnRlbnRzIGluIGNhY2hlLlxyXG4gICAgICAvLyBJZiB0aGVyZSBhcmUgY2hhbmdlcywgZmV0Y2ggcmVxdWVzdGVkIG1vZHVsZXMgYW5kIHByb2R1Y3RzLFxyXG4gICAgICAvLyBhbmQgYmFrZSB0aGVtIGludG8gYSBnaWFudCBibG9iLiBTYXZlIHRoZSBibG9iLlxyXG4gICAgICBpZiAobWFuaWZlc3QudmVyc2lvbiAhPT0gaGlnaGNoYXJ0c09wdGlvbnMudmVyc2lvbikge1xyXG4gICAgICAgIGxvZyhcclxuICAgICAgICAgIDIsXHJcbiAgICAgICAgICAnW2NhY2hlXSBBIEhpZ2hjaGFydHMgdmVyc2lvbiBtaXNtYXRjaCBpbiB0aGUgY2FjaGUsIG5lZWQgdG8gcmUtZmV0Y2guJ1xyXG4gICAgICAgICk7XHJcbiAgICAgICAgcmVxdWVzdFVwZGF0ZSA9IHRydWU7XHJcbiAgICAgIH0gZWxzZSBpZiAoXHJcbiAgICAgICAgT2JqZWN0LmtleXMobWFuaWZlc3QubW9kdWxlcyB8fCB7fSkubGVuZ3RoICE9PSBudW1iZXJPZk1vZHVsZXNcclxuICAgICAgKSB7XHJcbiAgICAgICAgbG9nKFxyXG4gICAgICAgICAgMixcclxuICAgICAgICAgICdbY2FjaGVdIFRoZSBjYWNoZSBhbmQgdGhlIHJlcXVlc3RlZCBtb2R1bGVzIGRvIG5vdCBtYXRjaCwgbmVlZCB0byByZS1mZXRjaC4nXHJcbiAgICAgICAgKTtcclxuICAgICAgICByZXF1ZXN0VXBkYXRlID0gdHJ1ZTtcclxuICAgICAgfSBlbHNlIHtcclxuICAgICAgICAvLyBDaGVjayBlYWNoIG1vZHVsZSwgaWYgYW55dGhpbmcgaXMgbWlzc2luZyByZWZldGNoIGV2ZXJ5dGhpbmdcclxuICAgICAgICByZXF1ZXN0VXBkYXRlID0gKG1vZHVsZVNjcmlwdHMgfHwgW10pLnNvbWUoKG1vZHVsZU5hbWUpID0+IHtcclxuICAgICAgICAgIGlmICghbWFuaWZlc3QubW9kdWxlc1ttb2R1bGVOYW1lXSkge1xyXG4gICAgICAgICAgICBsb2coXHJcbiAgICAgICAgICAgICAgMixcclxuICAgICAgICAgICAgICBgW2NhY2hlXSBUaGUgJHttb2R1bGVOYW1lfSBpcyBtaXNzaW5nIGluIHRoZSBjYWNoZSwgbmVlZCB0byByZS1mZXRjaC5gXHJcbiAgICAgICAgICAgICk7XHJcbiAgICAgICAgICAgIHJldHVybiB0cnVlO1xyXG4gICAgICAgICAgfVxyXG4gICAgICAgIH0pO1xyXG4gICAgICB9XHJcblxyXG4gICAgICAvLyBVcGRhdGUgY2FjaGUgaWYgbmVlZGVkXHJcbiAgICAgIGlmIChyZXF1ZXN0VXBkYXRlKSB7XHJcbiAgICAgICAgZmV0Y2hlZE1vZHVsZXMgPSBhd2FpdCBfdXBkYXRlQ2FjaGUoXHJcbiAgICAgICAgICBoaWdoY2hhcnRzT3B0aW9ucyxcclxuICAgICAgICAgIHNlcnZlclByb3h5T3B0aW9ucyxcclxuICAgICAgICAgIHNvdXJjZVBhdGhcclxuICAgICAgICApO1xyXG4gICAgICB9IGVsc2Uge1xyXG4gICAgICAgIGxvZygzLCAnW2NhY2hlXSBEZXBlbmRlbmN5IGNhY2hlIGlzIHVwIHRvIGRhdGUsIHByb2NlZWRpbmcuJyk7XHJcblxyXG4gICAgICAgIC8vIExvYWQgdGhlIHNvdXJjZXNcclxuICAgICAgICBjYWNoZS5zb3VyY2VzID0gcmVhZEZpbGVTeW5jKHNvdXJjZVBhdGgsICd1dGY4Jyk7XHJcblxyXG4gICAgICAgIC8vIEdldCBjdXJyZW50IG1vZHVsZXMgbWFwXHJcbiAgICAgICAgZmV0Y2hlZE1vZHVsZXMgPSBtYW5pZmVzdC5tb2R1bGVzO1xyXG5cclxuICAgICAgICAvLyBFeHRyYWN0IGFuZCBzYXZlIHZlcnNpb24gb2YgY3VycmVudGx5IHVzZWQgSGlnaGNoYXJ0c1xyXG4gICAgICAgIGNhY2hlLmhjVmVyc2lvbiA9IGV4dHJhY3RWZXJzaW9uKGNhY2hlLnNvdXJjZXMpO1xyXG4gICAgICB9XHJcbiAgICB9XHJcblxyXG4gICAgLy8gRmluYWxseSwgc2F2ZSB0aGUgbmV3IG1hbmlmZXN0LCB3aGljaCBpcyBiYXNpY2FsbHkgb3VyIGN1cnJlbnQgY29uZmlnXHJcbiAgICAvLyBpbiBhIHNsaWdodGx5IGRpZmZlcmVudCBmb3JtYXRcclxuICAgIGF3YWl0IF9zYXZlQ29uZmlnVG9NYW5pZmVzdChoaWdoY2hhcnRzT3B0aW9ucywgZmV0Y2hlZE1vZHVsZXMpO1xyXG4gIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoXHJcbiAgICAgICdbY2FjaGVdIENvdWxkIG5vdCBjb25maWd1cmUgY2FjaGUgYW5kIGNyZWF0ZSBvciB1cGRhdGUgdGhlIGNvbmZpZyBtYW5pZmVzdC4nLFxyXG4gICAgICA1MDBcclxuICAgICkuc2V0RXJyb3IoZXJyb3IpO1xyXG4gIH1cclxufVxyXG5cclxuLyoqXHJcbiAqIEdldHMgdGhlIHZlcnNpb24gb2YgSGlnaGNoYXJ0cyBmcm9tIHRoZSBjYWNoZS5cclxuICpcclxuICogQGZ1bmN0aW9uIGdldEhpZ2hjaGFydHNWZXJzaW9uXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtzdHJpbmd9IFRoZSBjYWNoZWQgSGlnaGNoYXJ0cyB2ZXJzaW9uLlxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIGdldEhpZ2hjaGFydHNWZXJzaW9uKCkge1xyXG4gIHJldHVybiBjYWNoZS5oY1ZlcnNpb247XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBVcGRhdGVzIHRoZSBIaWdoY2hhcnRzIHZlcnNpb24gaW4gdGhlIGFwcGxpZWQgY29uZmlndXJhdGlvbiBhbmQgY2hlY2tzXHJcbiAqIHRoZSBjYWNoZSBmb3IgdGhlIG5ldyB2ZXJzaW9uLlxyXG4gKlxyXG4gKiBAYXN5bmNcclxuICogQGZ1bmN0aW9uIHVwZGF0ZUhpZ2hjaGFydHNWZXJzaW9uXHJcbiAqXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSBuZXdWZXJzaW9uIC0gVGhlIG5ldyBIaWdoY2hhcnRzIHZlcnNpb24gdG8gYmUgYXBwbGllZC5cclxuICovXHJcbmV4cG9ydCBhc3luYyBmdW5jdGlvbiB1cGRhdGVIaWdoY2hhcnRzVmVyc2lvbihuZXdWZXJzaW9uKSB7XHJcbiAgLy8gR2V0IHRoZSByZWZlcmVuY2UgdG8gdGhlIGdsb2JhbCBvcHRpb25zIHRvIHVwZGF0ZSB0byB0aGUgbmV3IHZlcnNpb25cclxuICBjb25zdCBvcHRpb25zID0gZ2V0T3B0aW9ucygpO1xyXG5cclxuICAvLyBTZXQgdG8gdGhlIG5ldyB2ZXJzaW9uXHJcbiAgb3B0aW9ucy5oaWdoY2hhcnRzLnZlcnNpb24gPSBuZXdWZXJzaW9uO1xyXG5cclxuICAvLyBDaGVjayBpZiBjYWNoZSBuZWVkcyB0byBiZSB1cGRhdGVkXHJcbiAgYXdhaXQgY2hlY2tBbmRVcGRhdGVDYWNoZShvcHRpb25zLmhpZ2hjaGFydHMsIG9wdGlvbnMuc2VydmVyLnByb3h5KTtcclxufVxyXG5cclxuLyoqXHJcbiAqIEV4dHJhY3RzIEhpZ2hjaGFydHMgdmVyc2lvbiBmcm9tIHRoZSBjYWNoZSdzIHNvdXJjZXMgc3RyaW5nLlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gZXh0cmFjdFZlcnNpb25cclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IGNhY2hlU291cmNlcyAtIFRoZSBjYWNoZSBzb3VyY2VzIG9iamVjdC5cclxuICpcclxuICogQHJldHVybnMge3N0cmluZ30gVGhlIGV4dHJhY3RlZCBIaWdoY2hhcnRzIHZlcnNpb24uXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gZXh0cmFjdFZlcnNpb24oY2FjaGVTb3VyY2VzKSB7XHJcbiAgcmV0dXJuIGNhY2hlU291cmNlc1xyXG4gICAgLnN1YnN0cmluZygwLCBjYWNoZVNvdXJjZXMuaW5kZXhPZignKi8nKSlcclxuICAgIC5yZXBsYWNlKCcvKicsICcnKVxyXG4gICAgLnJlcGxhY2UoJyovJywgJycpXHJcbiAgICAucmVwbGFjZSgvXFxuL2csICcnKVxyXG4gICAgLnRyaW0oKTtcclxufVxyXG5cclxuLyoqXHJcbiAqIEV4dHJhY3RzIHRoZSBIaWdoY2hhcnRzIG1vZHVsZSBuYW1lIGJhc2VkIG9uIHRoZSBzY3JpcHRQYXRoLlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gZXh0cmFjdE1vZHVsZU5hbWVcclxuICpcclxuICogQHBhcmFtIHtzdHJpbmd9IHNjcmlwdFBhdGggLSBUaGUgcGF0aCBvZiB0aGUgc2NyaXB0IGZyb20gd2hpY2ggdGhlIG1vZHVsZVxyXG4gKiBuYW1lIHdpbGwgYmUgZXh0cmFjdGVkLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7c3RyaW5nfSBUaGUgZXh0cmFjdGVkIG1vZHVsZSBuYW1lLlxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIGV4dHJhY3RNb2R1bGVOYW1lKHNjcmlwdFBhdGgpIHtcclxuICByZXR1cm4gc2NyaXB0UGF0aC5yZXBsYWNlKFxyXG4gICAgLyguKilcXC98KC4qKW1vZHVsZXNcXC98c3RvY2tcXC8oLiopaW5kaWNhdG9yc1xcL3xtYXBzXFwvKC4qKW1vZHVsZXNcXC8vZ2ksXHJcbiAgICAnJ1xyXG4gICk7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBSZXRyaWV2ZXMgdGhlIGN1cnJlbnQgY2FjaGUgb2JqZWN0LlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gZ2V0Q2FjaGVcclxuICpcclxuICogQHJldHVybnMge09iamVjdH0gVGhlIGNhY2hlIG9iamVjdCBjb250YWluaW5nIHZhcmlvdXMgY2FjaGVkIGRhdGEuXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gZ2V0Q2FjaGUoKSB7XHJcbiAgcmV0dXJuIGNhY2hlO1xyXG59XHJcblxyXG4vKipcclxuICogR2V0cyB0aGUgY2FjaGUgcGF0aCBmb3IgSGlnaGNoYXJ0cy5cclxuICpcclxuICogQGZ1bmN0aW9uIGdldENhY2hlUGF0aFxyXG4gKlxyXG4gKiBAcmV0dXJucyB7c3RyaW5nfSBUaGUgYWJzb2x1dGUgcGF0aCB0byB0aGUgY2FjaGUgZGlyZWN0b3J5IGZvciBIaWdoY2hhcnRzLlxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIGdldENhY2hlUGF0aCgpIHtcclxuICByZXR1cm4gZ2V0QWJzb2x1dGVQYXRoKGdldE9wdGlvbnMoKS5oaWdoY2hhcnRzLmNhY2hlUGF0aCwgJ3V0ZjgnKTsgLy8gIzU2MlxyXG59XHJcblxyXG4vKipcclxuICogRmV0Y2hlcyBhIHNpbmdsZSBzY3JpcHQgYW5kIHVwZGF0ZXMgdGhlIGBmZXRjaGVkTW9kdWxlc2AgYWNjb3JkaW5nbHkuXHJcbiAqXHJcbiAqIEBhc3luY1xyXG4gKiBAZnVuY3Rpb24gX2ZldGNoQW5kUHJvY2Vzc1NjcmlwdFxyXG4gKlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gc2NyaXB0IC0gQSBwYXRoIHRvIHNjcmlwdCB0byBnZXQuXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSByZXF1ZXN0T3B0aW9ucyAtIEFkZGl0aW9uYWwgb3B0aW9ucyBmb3IgdGhlIHByb3h5IGFnZW50XHJcbiAqIHRvIHVzZSBmb3IgYSByZXF1ZXN0LlxyXG4gKiBAcGFyYW0ge09iamVjdH0gZmV0Y2hlZE1vZHVsZXMgLSBBbiBvYmplY3Qgd2hpY2ggdHJhY2tzIHdoaWNoIEhpZ2hjaGFydHNcclxuICogbW9kdWxlcyBoYXZlIGJlZW4gZmV0Y2hlZC5cclxuICogQHBhcmFtIHtib29sZWFufSBbc2hvdWxkVGhyb3dFcnJvcj1mYWxzZV0gLSBBIGZsYWcgdG8gaW5kaWNhdGUgaWYgdGhlIGVycm9yXHJcbiAqIHNob3VsZCBiZSB0aHJvd24uIFRoaXMgc2hvdWxkIGJlIHVzZWQgb25seSBmb3IgdGhlIGNvcmUgc2NyaXB0cy4gVGhlIGRlZmF1bHRcclxuICogdmFsdWUgaXMgYGZhbHNlYC5cclxuICpcclxuICogQHJldHVybnMge1Byb21pc2U8c3RyaW5nPn0gQSBQcm9taXNlIHRoYXQgcmVzb2x2ZXMgdG8gdGhlIHRleHQgcmVwcmVzZW50YXRpb25cclxuICogb2YgdGhlIGZldGNoZWQgc2NyaXB0LlxyXG4gKlxyXG4gKiBAdGhyb3dzIHtFeHBvcnRFcnJvcn0gVGhyb3dzIGFuIGBFeHBvcnRFcnJvcmAgaWYgdGhlcmUgaXMgYSBwcm9ibGVtXHJcbiAqIHdpdGggZmV0Y2hpbmcgdGhlIHNjcmlwdC5cclxuICovXHJcbmFzeW5jIGZ1bmN0aW9uIF9mZXRjaEFuZFByb2Nlc3NTY3JpcHQoXHJcbiAgc2NyaXB0LFxyXG4gIHJlcXVlc3RPcHRpb25zLFxyXG4gIGZldGNoZWRNb2R1bGVzLFxyXG4gIHNob3VsZFRocm93RXJyb3IgPSBmYWxzZVxyXG4pIHtcclxuICAvLyBHZXQgcmlkIG9mIHRoZSAuanMgZnJvbSB0aGUgY3VzdG9tIHN0cmluZ3NcclxuICBpZiAoc2NyaXB0LmVuZHNXaXRoKCcuanMnKSkge1xyXG4gICAgc2NyaXB0ID0gc2NyaXB0LnN1YnN0cmluZygwLCBzY3JpcHQubGVuZ3RoIC0gMyk7XHJcbiAgfVxyXG4gIGxvZyg0LCBgW2NhY2hlXSBGZXRjaGluZyBzY3JpcHQgLSAke3NjcmlwdH0uanNgKTtcclxuXHJcbiAgLy8gRmV0Y2ggdGhlIHNjcmlwdFxyXG4gIGNvbnN0IHJlc3BvbnNlID0gYXdhaXQgZmV0Y2goYCR7c2NyaXB0fS5qc2AsIHJlcXVlc3RPcHRpb25zKTtcclxuXHJcbiAgLy8gSWYgT0ssIHJldHVybiBpdHMgdGV4dCByZXByZXNlbnRhdGlvblxyXG4gIGlmIChyZXNwb25zZS5zdGF0dXNDb2RlID09PSAyMDAgJiYgdHlwZW9mIHJlc3BvbnNlLnRleHQgPT0gJ3N0cmluZycpIHtcclxuICAgIGlmIChmZXRjaGVkTW9kdWxlcykge1xyXG4gICAgICBjb25zdCBtb2R1bGVOYW1lID0gZXh0cmFjdE1vZHVsZU5hbWUoc2NyaXB0KTtcclxuICAgICAgZmV0Y2hlZE1vZHVsZXNbbW9kdWxlTmFtZV0gPSAxO1xyXG4gICAgfVxyXG4gICAgcmV0dXJuIHJlc3BvbnNlLnRleHQ7XHJcbiAgfVxyXG5cclxuICAvLyBCYXNlZCBvbiB0aGUgYHNob3VsZFRocm93RXJyb3JgIGZsYWcsIGRlY2lkZSBob3cgdG8gc2VydmUgZXJyb3IgbWVzc2FnZVxyXG4gIGlmIChzaG91bGRUaHJvd0Vycm9yKSB7XHJcbiAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoXHJcbiAgICAgIGBbY2FjaGVdIENvdWxkIG5vdCBmZXRjaCB0aGUgJHtzY3JpcHR9LmpzLiBUaGUgc2NyaXB0IG1pZ2h0IG5vdCBleGlzdCBpbiB0aGUgcmVxdWVzdGVkIHZlcnNpb24gKHN0YXR1cyBjb2RlOiAke3Jlc3BvbnNlLnN0YXR1c0NvZGV9KS5gLFxyXG4gICAgICA0MDRcclxuICAgICkuc2V0RXJyb3IocmVzcG9uc2UpO1xyXG4gIH0gZWxzZSB7XHJcbiAgICBsb2coXHJcbiAgICAgIDIsXHJcbiAgICAgIGBbY2FjaGVdIENvdWxkIG5vdCBmZXRjaCB0aGUgJHtzY3JpcHR9LmpzLiBUaGUgc2NyaXB0IG1pZ2h0IG5vdCBleGlzdCBpbiB0aGUgcmVxdWVzdGVkIHZlcnNpb24uYFxyXG4gICAgKTtcclxuICB9XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBTYXZlcyB0aGUgcHJvdmlkZWQgY29uZmlndXJhdGlvbiBhbmQgZmV0Y2hlZCBtb2R1bGVzIHRvIHRoZSBjYWNoZSBtYW5pZmVzdFxyXG4gKiBmaWxlLlxyXG4gKlxyXG4gKiBAYXN5bmNcclxuICogQGZ1bmN0aW9uIF9zYXZlQ29uZmlnVG9NYW5pZmVzdFxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gaGlnaGNoYXJ0c09wdGlvbnMgLSBUaGUgY29uZmlndXJhdGlvbiBvYmplY3QgY29udGFpbmluZ1xyXG4gKiBgaGlnaGNoYXJ0c2Agb3B0aW9ucy5cclxuICogQHBhcmFtIHtPYmplY3R9IFtmZXRjaGVkTW9kdWxlcz17fV0gLSBBbiBvYmplY3Qgd2hpY2ggdHJhY2tzIHdoaWNoIEhpZ2hjaGFydHNcclxuICogbW9kdWxlcyBoYXZlIGJlZW4gZmV0Y2hlZC4gVGhlIGRlZmF1bHQgdmFsdWUgaXMgYW4gZW1wdHkgb2JqZWN0LlxyXG4gKlxyXG4gKiBAdGhyb3dzIHtFeHBvcnRFcnJvcn0gVGhyb3dzIGFuIGBFeHBvcnRFcnJvcmAgaWYgYW4gZXJyb3Igb2NjdXJzIHdoaWxlXHJcbiAqIHdyaXRpbmcgdGhlIGNhY2hlIG1hbmlmZXN0LlxyXG4gKi9cclxuYXN5bmMgZnVuY3Rpb24gX3NhdmVDb25maWdUb01hbmlmZXN0KGhpZ2hjaGFydHNPcHRpb25zLCBmZXRjaGVkTW9kdWxlcyA9IHt9KSB7XHJcbiAgY29uc3QgbmV3TWFuaWZlc3QgPSB7XHJcbiAgICB2ZXJzaW9uOiBoaWdoY2hhcnRzT3B0aW9ucy52ZXJzaW9uLFxyXG4gICAgbW9kdWxlczogZmV0Y2hlZE1vZHVsZXNcclxuICB9O1xyXG5cclxuICAvLyBVcGRhdGUgY2FjaGUgb2JqZWN0IHdpdGggdGhlIGN1cnJlbnQgbW9kdWxlc1xyXG4gIGNhY2hlLmFjdGl2ZU1hbmlmZXN0ID0gbmV3TWFuaWZlc3Q7XHJcblxyXG4gIGxvZygzLCAnW2NhY2hlXSBXcml0aW5nIGEgbmV3IG1hbmlmZXN0LicpO1xyXG4gIHRyeSB7XHJcbiAgICB3cml0ZUZpbGVTeW5jKFxyXG4gICAgICBqb2luKGdldENhY2hlUGF0aCgpLCAnbWFuaWZlc3QuanNvbicpLFxyXG4gICAgICBKU09OLnN0cmluZ2lmeShuZXdNYW5pZmVzdCksXHJcbiAgICAgICd1dGY4J1xyXG4gICAgKTtcclxuICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgdGhyb3cgbmV3IEV4cG9ydEVycm9yKFxyXG4gICAgICAnW2NhY2hlXSBFcnJvciB3cml0aW5nIHRoZSBjYWNoZSBtYW5pZmVzdC4nLFxyXG4gICAgICA1MDBcclxuICAgICkuc2V0RXJyb3IoZXJyb3IpO1xyXG4gIH1cclxufVxyXG5cclxuLyoqXHJcbiAqIEZldGNoZXMgSGlnaGNoYXJ0cyBgc2NyaXB0c2AgYW5kIGBjdXN0b21TY3JpcHRzYCBmcm9tIHRoZSBnaXZlbiBDRE5zLlxyXG4gKlxyXG4gKiBAYXN5bmNcclxuICogQGZ1bmN0aW9uIF9mZXRjaFNjcmlwdHNcclxuICpcclxuICogQHBhcmFtIHtBcnJheS48c3RyaW5nPn0gY29yZVNjcmlwdHMgLSBIaWdoY2hhcnRzIGNvcmUgc2NyaXB0cyB0byBmZXRjaC5cclxuICogQHBhcmFtIHtBcnJheS48c3RyaW5nPn0gbW9kdWxlU2NyaXB0cyAtIEhpZ2hjaGFydHMgbW9kdWxlcyB0byBmZXRjaC5cclxuICogQHBhcmFtIHtBcnJheS48c3RyaW5nPn0gY3VzdG9tU2NyaXB0cyAtIEN1c3RvbSBzY3JpcHQgcGF0aHMgdG8gZmV0Y2ggKGZ1bGxcclxuICogVVJMcykuXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBzZXJ2ZXJQcm94eU9wdGlvbnMgLSBUaGUgY29uZmlndXJhdGlvbiBvYmplY3QgY29udGFpbmluZ1xyXG4gKiBgc2VydmVyLnByb3h5YCBvcHRpb25zLlxyXG4gKiBAcGFyYW0ge09iamVjdH0gZmV0Y2hlZE1vZHVsZXMgLSBBbiBvYmplY3Qgd2hpY2ggdHJhY2tzIHdoaWNoIEhpZ2hjaGFydHNcclxuICogbW9kdWxlcyBoYXZlIGJlZW4gZmV0Y2hlZC5cclxuICpcclxuICogQHJldHVybnMge1Byb21pc2U8c3RyaW5nPn0gQSBQcm9taXNlIHRoYXQgcmVzb2x2ZXMgdG8gdGhlIGZldGNoZWQgc2NyaXB0c1xyXG4gKiBjb250ZW50IGpvaW5lZC5cclxuICpcclxuICogQHRocm93cyB7RXhwb3J0RXJyb3J9IFRocm93cyBhbiBgRXhwb3J0RXJyb3JgIGlmIGFuIGVycm9yIG9jY3VycyB3aGlsZVxyXG4gKiBzZXR0aW5nIGFuIEhUVFAgQWdlbnQgZm9yIHByb3h5LlxyXG4gKi9cclxuYXN5bmMgZnVuY3Rpb24gX2ZldGNoU2NyaXB0cyhcclxuICBjb3JlU2NyaXB0cyxcclxuICBtb2R1bGVTY3JpcHRzLFxyXG4gIGN1c3RvbVNjcmlwdHMsXHJcbiAgc2VydmVyUHJveHlPcHRpb25zLFxyXG4gIGZldGNoZWRNb2R1bGVzXHJcbikge1xyXG4gIC8vIENvbmZpZ3VyZSBwcm94eSBpZiBleGlzdHNcclxuICBsZXQgcHJveHlBZ2VudDtcclxuICBjb25zdCBwcm94eUhvc3QgPSBzZXJ2ZXJQcm94eU9wdGlvbnMuaG9zdDtcclxuICBjb25zdCBwcm94eVBvcnQgPSBzZXJ2ZXJQcm94eU9wdGlvbnMucG9ydDtcclxuXHJcbiAgLy8gVHJ5IHRvIGNyZWF0ZSBhIFByb3h5IEFnZW50XHJcbiAgaWYgKHByb3h5SG9zdCAmJiBwcm94eVBvcnQpIHtcclxuICAgIHRyeSB7XHJcbiAgICAgIHByb3h5QWdlbnQgPSBuZXcgSHR0cHNQcm94eUFnZW50KHtcclxuICAgICAgICBob3N0OiBwcm94eUhvc3QsXHJcbiAgICAgICAgcG9ydDogcHJveHlQb3J0XHJcbiAgICAgIH0pO1xyXG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICAgdGhyb3cgbmV3IEV4cG9ydEVycm9yKFxyXG4gICAgICAgICdbY2FjaGVdIENvdWxkIG5vdCBjcmVhdGUgYSBQcm94eSBBZ2VudC4nLFxyXG4gICAgICAgIDUwMFxyXG4gICAgICApLnNldEVycm9yKGVycm9yKTtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIC8vIElmIGV4aXN0cywgYWRkIHByb3h5IGFnZW50IHRvIHJlcXVlc3Qgb3B0aW9uc1xyXG4gIGNvbnN0IHJlcXVlc3RPcHRpb25zID0gcHJveHlBZ2VudFxyXG4gICAgPyB7XHJcbiAgICAgICAgYWdlbnQ6IHByb3h5QWdlbnQsXHJcbiAgICAgICAgdGltZW91dDogc2VydmVyUHJveHlPcHRpb25zLnRpbWVvdXRcclxuICAgICAgfVxyXG4gICAgOiB7fTtcclxuXHJcbiAgY29uc3QgYWxsRmV0Y2hQcm9taXNlcyA9IFtcclxuICAgIC4uLmNvcmVTY3JpcHRzLm1hcCgoc2NyaXB0KSA9PlxyXG4gICAgICBfZmV0Y2hBbmRQcm9jZXNzU2NyaXB0KGAke3NjcmlwdH1gLCByZXF1ZXN0T3B0aW9ucywgZmV0Y2hlZE1vZHVsZXMsIHRydWUpXHJcbiAgICApLFxyXG4gICAgLi4ubW9kdWxlU2NyaXB0cy5tYXAoKHNjcmlwdCkgPT5cclxuICAgICAgX2ZldGNoQW5kUHJvY2Vzc1NjcmlwdChgJHtzY3JpcHR9YCwgcmVxdWVzdE9wdGlvbnMsIGZldGNoZWRNb2R1bGVzKVxyXG4gICAgKSxcclxuICAgIC4uLmN1c3RvbVNjcmlwdHMubWFwKChzY3JpcHQpID0+XHJcbiAgICAgIF9mZXRjaEFuZFByb2Nlc3NTY3JpcHQoYCR7c2NyaXB0fWAsIHJlcXVlc3RPcHRpb25zKVxyXG4gICAgKVxyXG4gIF07XHJcblxyXG4gIGNvbnN0IGZldGNoZWRTY3JpcHRzID0gYXdhaXQgUHJvbWlzZS5hbGwoYWxsRmV0Y2hQcm9taXNlcyk7XHJcbiAgcmV0dXJuIGZldGNoZWRTY3JpcHRzLmpvaW4oJztcXG4nKTtcclxufVxyXG5cclxuLyoqXHJcbiAqIFVwZGF0ZXMgdGhlIGxvY2FsIGNhY2hlIHdpdGggSGlnaGNoYXJ0cyBzY3JpcHRzIGFuZCB0aGVpciB2ZXJzaW9ucy5cclxuICpcclxuICogQGFzeW5jXHJcbiAqIEBmdW5jdGlvbiBfdXBkYXRlQ2FjaGVcclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IGhpZ2hjaGFydHNPcHRpb25zIC0gVGhlIGNvbmZpZ3VyYXRpb24gb2JqZWN0IGNvbnRhaW5pbmdcclxuICogYGhpZ2hjaGFydHNgIG9wdGlvbnMuXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBzZXJ2ZXJQcm94eU9wdGlvbnMgLSBUaGUgY29uZmlndXJhdGlvbiBvYmplY3QgY29udGFpbmluZ1xyXG4gKiBgc2VydmVyLnByb3h5YCBvcHRpb25zLlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gc291cmNlUGF0aCAtIFRoZSBwYXRoIHRvIHRoZSBzb3VyY2UgZmlsZSBpbiB0aGUgY2FjaGUuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtQcm9taXNlPE9iamVjdD59IEEgUHJvbWlzZSB0aGF0IHJlc29sdmVzIHRvIGFuIG9iamVjdCByZXByZXNlbnRpbmdcclxuICogdGhlIGZldGNoZWQgbW9kdWxlcy5cclxuICpcclxuICogQHRocm93cyB7RXhwb3J0RXJyb3J9IFRocm93cyBhbiBgRXhwb3J0RXJyb3JgIGlmIHRoZXJlIGlzIGFuIGlzc3VlIHVwZGF0aW5nXHJcbiAqIHRoZSBsb2NhbCBIaWdoY2hhcnRzIGNhY2hlLlxyXG4gKi9cclxuYXN5bmMgZnVuY3Rpb24gX3VwZGF0ZUNhY2hlKGhpZ2hjaGFydHNPcHRpb25zLCBzZXJ2ZXJQcm94eU9wdGlvbnMsIHNvdXJjZVBhdGgpIHtcclxuICAvLyBHZXQgSGlnaGNoYXJ0cyB2ZXJzaW9uIGZvciBzY3JpcHRzXHJcbiAgY29uc3QgaGNWZXJzaW9uID1cclxuICAgIGhpZ2hjaGFydHNPcHRpb25zLnZlcnNpb24gPT09ICdsYXRlc3QnXHJcbiAgICAgID8gbnVsbFxyXG4gICAgICA6IGAke2hpZ2hjaGFydHNPcHRpb25zLnZlcnNpb259YDtcclxuXHJcbiAgLy8gR2V0IHRoZSBDRE4gdXJsIGZvciBzY3JpcHRzXHJcbiAgY29uc3QgY2RuVXJsID0gaGlnaGNoYXJ0c09wdGlvbnMuY2RuVXJsIHx8IGNhY2hlLmNkblVybDtcclxuXHJcbiAgdHJ5IHtcclxuICAgIGNvbnN0IGZldGNoZWRNb2R1bGVzID0ge307XHJcblxyXG4gICAgbG9nKFxyXG4gICAgICAzLFxyXG4gICAgICBgW2NhY2hlXSBVcGRhdGluZyBjYWNoZSB2ZXJzaW9uIHRvIEhpZ2hjaGFydHM6ICR7aGNWZXJzaW9uIHx8ICdsYXRlc3QnfS5gXHJcbiAgICApO1xyXG5cclxuICAgIGNhY2hlLnNvdXJjZXMgPSBhd2FpdCBfZmV0Y2hTY3JpcHRzKFxyXG4gICAgICBbXHJcbiAgICAgICAgLi4uaGlnaGNoYXJ0c09wdGlvbnMuY29yZVNjcmlwdHMubWFwKChjKSA9PlxyXG4gICAgICAgICAgaGNWZXJzaW9uID8gYCR7Y2RuVXJsfS8ke2hjVmVyc2lvbn0vJHtjfWAgOiBgJHtjZG5Vcmx9LyR7Y31gXHJcbiAgICAgICAgKVxyXG4gICAgICBdLFxyXG4gICAgICBbXHJcbiAgICAgICAgLi4uaGlnaGNoYXJ0c09wdGlvbnMubW9kdWxlU2NyaXB0cy5tYXAoKG0pID0+XHJcbiAgICAgICAgICBtID09PSAnbWFwJ1xyXG4gICAgICAgICAgICA/IGhjVmVyc2lvblxyXG4gICAgICAgICAgICAgID8gYCR7Y2RuVXJsfS9tYXBzLyR7aGNWZXJzaW9ufS9tb2R1bGVzLyR7bX1gXHJcbiAgICAgICAgICAgICAgOiBgJHtjZG5Vcmx9L21hcHMvbW9kdWxlcy8ke219YFxyXG4gICAgICAgICAgICA6IGhjVmVyc2lvblxyXG4gICAgICAgICAgICAgID8gYCR7Y2RuVXJsfS8ke2hjVmVyc2lvbn0vbW9kdWxlcy8ke219YFxyXG4gICAgICAgICAgICAgIDogYCR7Y2RuVXJsfS9tb2R1bGVzLyR7bX1gXHJcbiAgICAgICAgKSxcclxuICAgICAgICAuLi5oaWdoY2hhcnRzT3B0aW9ucy5pbmRpY2F0b3JTY3JpcHRzLm1hcCgoaSkgPT5cclxuICAgICAgICAgIGhjVmVyc2lvblxyXG4gICAgICAgICAgICA/IGAke2NkblVybH0vc3RvY2svJHtoY1ZlcnNpb259L2luZGljYXRvcnMvJHtpfWBcclxuICAgICAgICAgICAgOiBgJHtjZG5Vcmx9L3N0b2NrL2luZGljYXRvcnMvJHtpfWBcclxuICAgICAgICApXHJcbiAgICAgIF0sXHJcbiAgICAgIGhpZ2hjaGFydHNPcHRpb25zLmN1c3RvbVNjcmlwdHMsXHJcbiAgICAgIHNlcnZlclByb3h5T3B0aW9ucyxcclxuICAgICAgZmV0Y2hlZE1vZHVsZXNcclxuICAgICk7XHJcblxyXG4gICAgLy8gRXh0cmFjdCBhbmQgc2F2ZSB2ZXJzaW9uIG9mIGN1cnJlbnRseSB1c2VkIEhpZ2hjaGFydHNcclxuICAgIGNhY2hlLmhjVmVyc2lvbiA9IGV4dHJhY3RWZXJzaW9uKGNhY2hlLnNvdXJjZXMpO1xyXG5cclxuICAgIC8vIFNhdmUgdGhlIGZldGNoZWQgbW9kdWxlcyBpbnRvIGNhY2hlcycgc291cmNlIEpTT05cclxuICAgIHdyaXRlRmlsZVN5bmMoc291cmNlUGF0aCwgY2FjaGUuc291cmNlcyk7XHJcbiAgICByZXR1cm4gZmV0Y2hlZE1vZHVsZXM7XHJcbiAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcihcclxuICAgICAgJ1tjYWNoZV0gVW5hYmxlIHRvIHVwZGF0ZSB0aGUgbG9jYWwgSGlnaGNoYXJ0cyBjYWNoZS4nLFxyXG4gICAgICA1MDBcclxuICAgICkuc2V0RXJyb3IoZXJyb3IpO1xyXG4gIH1cclxufVxyXG5cclxuZXhwb3J0IGRlZmF1bHQge1xyXG4gIGNoZWNrQW5kVXBkYXRlQ2FjaGUsXHJcbiAgZ2V0SGlnaGNoYXJ0c1ZlcnNpb24sXHJcbiAgdXBkYXRlSGlnaGNoYXJ0c1ZlcnNpb24sXHJcbiAgZXh0cmFjdFZlcnNpb24sXHJcbiAgZXh0cmFjdE1vZHVsZU5hbWUsXHJcbiAgZ2V0Q2FjaGUsXHJcbiAgZ2V0Q2FjaGVQYXRoXHJcbn07XHJcbiIsIi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXHJcblxyXG5IaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXJcclxuXHJcbkNvcHlyaWdodCAoYykgMjAxNi0yMDI1LCBIaWdoc29mdFxyXG5cclxuTGljZW5jZWQgdW5kZXIgdGhlIE1JVCBsaWNlbmNlLlxyXG5cclxuQWRkaXRpb25hbGx5IGEgdmFsaWQgSGlnaGNoYXJ0cyBsaWNlbnNlIGlzIHJlcXVpcmVkIGZvciB1c2UuXHJcblxyXG5TZWUgTElDRU5TRSBmaWxlIGluIHJvb3QgZm9yIGRldGFpbHMuXHJcblxyXG4qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xyXG5cclxuLyoqXHJcbiAqIEBvdmVydmlldyBQcm92aWRlcyBtZXRob2RzIGZvciBpbml0aWFsaXppbmcgSGlnaGNoYXJ0cyB3aXRoIGN1c3RvbWl6ZWRcclxuICogYW5pbWF0aW9uIHNldHRpbmdzIGFuZCB0cmlnZ2VyaW5nIHRoZSBjcmVhdGlvbiBvZiBIaWdoY2hhcnRzIGNoYXJ0cyB3aXRoXHJcbiAqIGV4cG9ydC1zcGVjaWZpYyBjb25maWd1cmF0aW9ucyBpbiB0aGUgcGFnZSBjb250ZXh0LiBTdXBwb3J0cyBkeW5hbWljIG9wdGlvblxyXG4gKiBtZXJnaW5nLCBjdXN0b20gbG9naWMgaW5qZWN0aW9uLCBhbmQgY29udHJvbCBvdmVyIHJlbmRlcmluZyBiZWhhdmlvcnMuIFVzZWRcclxuICogYnkgdGhlIFB1cHBldGVlciBwYWdlLlxyXG4gKi9cclxuXHJcbi8qIGVzbGludC1kaXNhYmxlIG5vLXVuZGVmICovXHJcblxyXG4vKipcclxuICogU2V0dGluZyB0aGUgYEhpZ2hjaGFydHMuYW5pbU9iamVjdGAgZnVuY3Rpb24uIENhbGxlZCB3aGVuIGluaXRpbmcgdGhlIHBhZ2UuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBzZXR1cEhpZ2hjaGFydHNcclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiBzZXR1cEhpZ2hjaGFydHMoKSB7XHJcbiAgSGlnaGNoYXJ0cy5hbmltT2JqZWN0ID0gZnVuY3Rpb24gKCkge1xyXG4gICAgcmV0dXJuIHsgZHVyYXRpb246IDAgfTtcclxuICB9O1xyXG59XHJcblxyXG4vKipcclxuICogQ3JlYXRlcyB0aGUgYWN0dWFsIEhpZ2hjaGFydHMgY2hhcnQgb24gYSBwYWdlLlxyXG4gKlxyXG4gKiBAYXN5bmNcclxuICogQGZ1bmN0aW9uIGNyZWF0ZUNoYXJ0XHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBleHBvcnRPcHRpb25zIC0gVGhlIGNvbmZpZ3VyYXRpb24gb2JqZWN0IGNvbnRhaW5pbmcgYGV4cG9ydGBcclxuICogb3B0aW9ucy5cclxuICogQHBhcmFtIHtPYmplY3R9IGN1c3RvbUxvZ2ljT3B0aW9ucyAtIFRoZSBjb25maWd1cmF0aW9uIG9iamVjdCBjb250YWluaW5nXHJcbiAqIGBjdXN0b21Mb2dpY2Agb3B0aW9ucy5cclxuICpcclxuICovXHJcbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBjcmVhdGVDaGFydChleHBvcnRPcHRpb25zLCBjdXN0b21Mb2dpY09wdGlvbnMpIHtcclxuICAvLyBHZXQgcmVxdWlyZWQgZnVuY3Rpb25zXHJcbiAgY29uc3QgeyBnZXRPcHRpb25zLCBzZXRPcHRpb25zLCBtZXJnZSwgd3JhcCB9ID0gSGlnaGNoYXJ0cztcclxuXHJcbiAgLy8gQ3JlYXRlIGEgc2VwYXJhdGUgb2JqZWN0IGZvciBhIHBvdGVudGlhbCBgc2V0T3B0aW9uc2AgdXNhZ2VzIGluIG9yZGVyXHJcbiAgLy8gdG8gcHJldmVudCBmcm9tIHBvbGx1dGluZyBvdGhlciBleHBvcnRzIHRoYXQgY2FuIGhhcHBlbiBvbiB0aGUgc2FtZSBwYWdlXHJcbiAgSGlnaGNoYXJ0cy5zZXRPcHRpb25zT2JqID0gbWVyZ2UoZmFsc2UsIHt9LCBnZXRPcHRpb25zKCkpO1xyXG5cclxuICAvLyBOT1RFOiBJcyB0aGlzIHVzZWQgZm9yIGFueXRoaW5nIHVzZWZ1bD9cclxuICB3aW5kb3cuaXNSZW5kZXJDb21wbGV0ZSA9IGZhbHNlO1xyXG4gIHdyYXAoSGlnaGNoYXJ0cy5DaGFydC5wcm90b3R5cGUsICdpbml0JywgZnVuY3Rpb24gKHByb2NlZWQsIHVzZXJPcHRpb25zLCBjYikge1xyXG4gICAgLy8gT3ZlcnJpZGUgdGhlIGB1c2VyT3B0aW9uc2Agd2l0aCBpbWFnZSBmcmllbmRseSBvcHRpb25zXHJcbiAgICB1c2VyT3B0aW9ucyA9IG1lcmdlKHVzZXJPcHRpb25zLCB7XHJcbiAgICAgIGV4cG9ydGluZzoge1xyXG4gICAgICAgIGVuYWJsZWQ6IGZhbHNlXHJcbiAgICAgIH0sXHJcbiAgICAgIHBsb3RPcHRpb25zOiB7XHJcbiAgICAgICAgc2VyaWVzOiB7XHJcbiAgICAgICAgICBsYWJlbDoge1xyXG4gICAgICAgICAgICBlbmFibGVkOiBmYWxzZVxyXG4gICAgICAgICAgfVxyXG4gICAgICAgIH1cclxuICAgICAgfSxcclxuICAgICAgLyogRXhwZWN0cyB0b29sdGlwIGluIHRoZSBgdXNlck9wdGlvbnNgIHdoZW4gYGZvckV4cG9ydGAgaXMgdHJ1ZS5cclxuICAgICAgICBodHRwczovL2dpdGh1Yi5jb20vaGlnaGNoYXJ0cy9oaWdoY2hhcnRzL2Jsb2IvM2FkNDMwYTM1M2I4MDU2YjllNzY0YWE0ZTVjZDY4MjhhYTQ3OWRiMi9qcy9wYXJ0cy9DaGFydC5qcyNMMjQxXHJcbiAgICAgICAgKi9cclxuICAgICAgdG9vbHRpcDoge31cclxuICAgIH0pO1xyXG5cclxuICAgICh1c2VyT3B0aW9ucy5zZXJpZXMgfHwgW10pLmZvckVhY2goZnVuY3Rpb24gKHNlcmllcykge1xyXG4gICAgICBzZXJpZXMuYW5pbWF0aW9uID0gZmFsc2U7XHJcbiAgICB9KTtcclxuXHJcbiAgICAvLyBBZGQgZmxhZyB0byBrbm93IGlmIGNoYXJ0IHJlbmRlciBoYXMgYmVlbiBjYWxsZWQuXHJcbiAgICBpZiAoIXdpbmRvdy5vbkhpZ2hjaGFydHNSZW5kZXIpIHtcclxuICAgICAgd2luZG93Lm9uSGlnaGNoYXJ0c1JlbmRlciA9IEhpZ2hjaGFydHMuYWRkRXZlbnQodGhpcywgJ3JlbmRlcicsICgpID0+IHtcclxuICAgICAgICB3aW5kb3cuaXNSZW5kZXJDb21wbGV0ZSA9IHRydWU7XHJcbiAgICAgIH0pO1xyXG4gICAgfVxyXG5cclxuICAgIHByb2NlZWQuYXBwbHkodGhpcywgW3VzZXJPcHRpb25zLCBjYl0pO1xyXG4gIH0pO1xyXG5cclxuICB3cmFwKEhpZ2hjaGFydHMuU2VyaWVzLnByb3RvdHlwZSwgJ2luaXQnLCBmdW5jdGlvbiAocHJvY2VlZCwgY2hhcnQsIG9wdGlvbnMpIHtcclxuICAgIHByb2NlZWQuYXBwbHkodGhpcywgW2NoYXJ0LCBvcHRpb25zXSk7XHJcbiAgfSk7XHJcblxyXG4gIC8vIFNvbWUgbWFuZGF0b3J5IGFkZGl0aW9uYWwgYGNoYXJ0YCBhbmQgYGV4cG9ydGluZ2Agb3B0aW9uc1xyXG4gIGNvbnN0IGFkZGl0aW9uYWxPcHRpb25zID0ge1xyXG4gICAgY2hhcnQ6IHtcclxuICAgICAgLy8gQnkgZGVmYXVsdCBhbmltYXRpb24gaXMgZGlzYWJsZWRcclxuICAgICAgYW5pbWF0aW9uOiBmYWxzZSxcclxuICAgICAgLy8gR2V0IHRoZSByaWdodCBzaXplIHZhbHVlc1xyXG4gICAgICBoZWlnaHQ6IGV4cG9ydE9wdGlvbnMuaGVpZ2h0LFxyXG4gICAgICB3aWR0aDogZXhwb3J0T3B0aW9ucy53aWR0aFxyXG4gICAgfSxcclxuICAgIGV4cG9ydGluZzoge1xyXG4gICAgICAvLyBObyBuZWVkIGZvciB0aGUgZXhwb3J0aW5nIGJ1dHRvblxyXG4gICAgICBlbmFibGVkOiBmYWxzZVxyXG4gICAgfVxyXG4gIH07XHJcblxyXG4gIC8vIEdldCB0aGUgaW5wdXQgdG8gZXhwb3J0IGZyb20gdGhlIGBpbnN0cmAgb3B0aW9uXHJcbiAgY29uc3QgdXNlck9wdGlvbnMgPSBuZXcgRnVuY3Rpb24oYHJldHVybiAke2V4cG9ydE9wdGlvbnMuaW5zdHJ9YCkoKTtcclxuXHJcbiAgLy8gR2V0IHRoZSBgdGhlbWVPcHRpb25zYCBvcHRpb25cclxuICBjb25zdCB0aGVtZU9wdGlvbnMgPSBuZXcgRnVuY3Rpb24oYHJldHVybiAke2V4cG9ydE9wdGlvbnMudGhlbWVPcHRpb25zfWApKCk7XHJcblxyXG4gIC8vIEdldCB0aGUgYGdsb2JhbE9wdGlvbnNgIG9wdGlvblxyXG4gIGNvbnN0IGdsb2JhbE9wdGlvbnMgPSBuZXcgRnVuY3Rpb24oYHJldHVybiAke2V4cG9ydE9wdGlvbnMuZ2xvYmFsT3B0aW9uc31gKSgpO1xyXG5cclxuICAvLyBNZXJnZSB0aGUgZm9sbG93aW5nIG9wdGlvbnMgb2JqZWN0cyB0byBjcmVhdGUgZmluYWwgb3B0aW9uc1xyXG4gIGNvbnN0IGZpbmFsT3B0aW9ucyA9IG1lcmdlKFxyXG4gICAgZmFsc2UsXHJcbiAgICB0aGVtZU9wdGlvbnMsXHJcbiAgICB1c2VyT3B0aW9ucyxcclxuICAgIC8vIFBsYWNlZCBpdCBoZXJlIGluc3RlYWQgaW4gdGhlIGluaXQgYmVjYXVzZSBvZiB0aGUgc2l6ZSBpc3N1ZXNcclxuICAgIGFkZGl0aW9uYWxPcHRpb25zXHJcbiAgKTtcclxuXHJcbiAgLy8gUHJlcGFyZSB0aGUgYGNhbGxiYWNrYCBvcHRpb25cclxuICBjb25zdCBmaW5hbENhbGxiYWNrID0gY3VzdG9tTG9naWNPcHRpb25zLmNhbGxiYWNrXHJcbiAgICA/IG5ldyBGdW5jdGlvbihgcmV0dXJuICR7Y3VzdG9tTG9naWNPcHRpb25zLmNhbGxiYWNrfWApKClcclxuICAgIDogbnVsbDtcclxuXHJcbiAgLy8gVHJpZ2dlciB0aGUgYGN1c3RvbUNvZGVgIG9wdGlvblxyXG4gIGlmIChjdXN0b21Mb2dpY09wdGlvbnMuY3VzdG9tQ29kZSkge1xyXG4gICAgbmV3IEZ1bmN0aW9uKCdvcHRpb25zJywgY3VzdG9tTG9naWNPcHRpb25zLmN1c3RvbUNvZGUpKHVzZXJPcHRpb25zKTtcclxuICB9XHJcblxyXG4gIC8vIFNldCB0aGUgZ2xvYmFsIG9wdGlvbnMgaWYgZXhpc3RcclxuICBpZiAoZ2xvYmFsT3B0aW9ucykge1xyXG4gICAgc2V0T3B0aW9ucyhnbG9iYWxPcHRpb25zKTtcclxuICB9XHJcblxyXG4gIC8vIENhbGwgdGhlIGNoYXJ0IGNyZWF0aW9uXHJcbiAgSGlnaGNoYXJ0c1tleHBvcnRPcHRpb25zLmNvbnN0cl0oJ2NvbnRhaW5lcicsIGZpbmFsT3B0aW9ucywgZmluYWxDYWxsYmFjayk7XHJcblxyXG4gIC8vIEdldCB0aGUgY3VycmVudCBnbG9iYWwgb3B0aW9uc1xyXG4gIGNvbnN0IGRlZmF1bHRPcHRpb25zID0gZ2V0T3B0aW9ucygpO1xyXG5cclxuICAvLyBDbGVhciBpdCBqdXN0IGluIGNhc2UgKGUuZy4gdGhlIGBzZXRPcHRpb25zYCB3YXMgdXNlZCBpbiB0aGUgYGN1c3RvbUNvZGVgKVxyXG4gIGZvciAoY29uc3QgcHJvcCBpbiBkZWZhdWx0T3B0aW9ucykge1xyXG4gICAgaWYgKHR5cGVvZiBkZWZhdWx0T3B0aW9uc1twcm9wXSAhPT0gJ2Z1bmN0aW9uJykge1xyXG4gICAgICBkZWxldGUgZGVmYXVsdE9wdGlvbnNbcHJvcF07XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICAvLyBTZXQgdGhlIGRlZmF1bHQgb3B0aW9ucyBiYWNrXHJcbiAgc2V0T3B0aW9ucyhIaWdoY2hhcnRzLnNldE9wdGlvbnNPYmopO1xyXG5cclxuICAvLyBFbXB0eSB0aGUgY3VzdG9tIGdsb2JhbCBvcHRpb25zIG9iamVjdFxyXG4gIEhpZ2hjaGFydHMuc2V0T3B0aW9uc09iaiA9IHt9O1xyXG59XHJcblxyXG5leHBvcnQgZGVmYXVsdCB7XHJcbiAgc2V0dXBIaWdoY2hhcnRzLFxyXG4gIGNyZWF0ZUNoYXJ0XHJcbn07XHJcbiIsIi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXHJcblxyXG5IaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXJcclxuXHJcbkNvcHlyaWdodCAoYykgMjAxNi0yMDI1LCBIaWdoc29mdFxyXG5cclxuTGljZW5jZWQgdW5kZXIgdGhlIE1JVCBsaWNlbmNlLlxyXG5cclxuQWRkaXRpb25hbGx5IGEgdmFsaWQgSGlnaGNoYXJ0cyBsaWNlbnNlIGlzIHJlcXVpcmVkIGZvciB1c2UuXHJcblxyXG5TZWUgTElDRU5TRSBmaWxlIGluIHJvb3QgZm9yIGRldGFpbHMuXHJcblxyXG4qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xyXG5cclxuLyoqXHJcbiAqIEBvdmVydmlldyBUaGlzIG1vZHVsZSBwcm92aWRlcyBmdW5jdGlvbnMgZm9yIG1hbmFnaW5nIFB1cHBldGVlciBicm93c2VyXHJcbiAqIGluc3RhbmNlLCBjcmVhdGluZyBhbmQgY2xlYXJpbmcgcGFnZXMsIGluamVjdGluZyBjdXN0b20gcmVzb3VyY2VzLFxyXG4gKiBhbmQgc2V0dGluZyB1cCBIaWdoY2hhcnRzIGZvciBzZXJ2ZXItc2lkZSByZW5kZXJpbmcuIFRoZSBtb2R1bGUgZW5zdXJlc1xyXG4gKiB0aGF0IHJlc291cmNlcyBhcmUgY29ycmVjdGx5IG1hbmFnZWQgYW5kIGNhbiBoYW5kbGUgZmFpbHVyZXMgZHVyaW5nXHJcbiAqIG9wZXJhdGlvbnMgbGlrZSBsYXVuY2hpbmcgdGhlIGJyb3dzZXIgb3IgY3JlYXRpbmcgbmV3IHBhZ2VzLlxyXG4gKi9cclxuXHJcbmltcG9ydCB7IHJlYWRGaWxlU3luYyB9IGZyb20gJ2ZzJztcclxuaW1wb3J0IHsgam9pbiB9IGZyb20gJ3BhdGgnO1xyXG5cclxuaW1wb3J0IHB1cHBldGVlciBmcm9tICdwdXBwZXRlZXInO1xyXG5cclxuaW1wb3J0IHsgZ2V0Q2FjaGVQYXRoIH0gZnJvbSAnLi9jYWNoZS5qcyc7XHJcbmltcG9ydCB7IGdldE9wdGlvbnMgfSBmcm9tICcuL2NvbmZpZy5qcyc7XHJcbmltcG9ydCB7IHNldHVwSGlnaGNoYXJ0cyB9IGZyb20gJy4vaGlnaGNoYXJ0cy5qcyc7XHJcbmltcG9ydCB7IGxvZywgbG9nV2l0aFN0YWNrIH0gZnJvbSAnLi9sb2dnZXIuanMnO1xyXG5pbXBvcnQgeyBfX2Rpcm5hbWUsIGdldEFic29sdXRlUGF0aCB9IGZyb20gJy4vdXRpbHMuanMnO1xyXG5cclxuaW1wb3J0IEV4cG9ydEVycm9yIGZyb20gJy4vZXJyb3JzL0V4cG9ydEVycm9yLmpzJztcclxuXHJcbi8vIEdldCB0aGUgdGVtcGxhdGUgZm9yIHBhZ2VzXHJcbmNvbnN0IHRlbXBsYXRlID0gcmVhZEZpbGVTeW5jKFxyXG4gIGpvaW4oX19kaXJuYW1lLCAndGVtcGxhdGVzJywgJ3RlbXBsYXRlLmh0bWwnKSxcclxuICAndXRmOCdcclxuKTtcclxuXHJcbi8vIFRvIHNhdmUgdGhlIGJyb3dzZXJcclxubGV0IGJyb3dzZXIgPSBudWxsO1xyXG5cclxuLyoqXHJcbiAqIFJldHJpZXZlcyB0aGUgZXhpc3RpbmcgUHVwcGV0ZWVyIGJyb3dzZXIgaW5zdGFuY2UuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBnZXRCcm93c2VyXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtPYmplY3R9IFRoZSBQdXBwZXRlZXIgYnJvd3NlciBpbnN0YW5jZS5cclxuICpcclxuICogQHRocm93cyB7RXhwb3J0RXJyb3J9IFRocm93cyBhbiBgRXhwb3J0RXJyb3JgIGlmIG5vIHZhbGlkIGJyb3dzZXJcclxuICogaGFzIGJlZW4gY3JlYXRlZC5cclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiBnZXRCcm93c2VyKCkge1xyXG4gIGlmICghYnJvd3Nlcikge1xyXG4gICAgdGhyb3cgbmV3IEV4cG9ydEVycm9yKCdbYnJvd3Nlcl0gTm8gdmFsaWQgYnJvd3NlciBoYXMgYmVlbiBjcmVhdGVkLicsIDUwMCk7XHJcbiAgfVxyXG4gIHJldHVybiBicm93c2VyO1xyXG59XHJcblxyXG4vKipcclxuICogQ3JlYXRlcyBhIFB1cHBldGVlciBicm93c2VyIGluc3RhbmNlIHdpdGggdGhlIHNwZWNpZmllZCBhcmd1bWVudHMuXHJcbiAqXHJcbiAqIEBhc3luY1xyXG4gKiBAZnVuY3Rpb24gY3JlYXRlQnJvd3NlclxyXG4gKlxyXG4gKiBAcGFyYW0ge0FycmF5LjxzdHJpbmc+fSBwdXBwZXRlZXJBcmdzIC0gQWRkaXRpb25hbCBhcmd1bWVudHMgZm9yIFB1cHBldGVlclxyXG4gKiBsYXVuY2guXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtQcm9taXNlPE9iamVjdD59IEEgUHJvbWlzZSB0aGF0IHJlc29sdmVzIHRvIHRoZSBjcmVhdGVkIFB1cHBldGVlclxyXG4gKiBicm93c2VyIGluc3RhbmNlLlxyXG4gKlxyXG4gKiBAdGhyb3dzIHtFeHBvcnRFcnJvcn0gVGhyb3dzIGFuIGBFeHBvcnRFcnJvcmAgaWYgbWF4IHJldHJpZXMgdG8gb3BlblxyXG4gKiBhIGJyb3dzZXIgaW5zdGFuY2UgYXJlIHJlYWNoZWQsIG9yIGlmIG5vIGJyb3dzZXIgaW5zdGFuY2UgaXMgZm91bmQgYWZ0ZXJcclxuICogcmV0cmllcy5cclxuICovXHJcbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBjcmVhdGVCcm93c2VyKHB1cHBldGVlckFyZ3MpIHtcclxuICAvLyBHZXQgYGRlYnVnYCBhbmQgYG90aGVyYCBvcHRpb25zXHJcbiAgY29uc3QgeyBkZWJ1Zywgb3RoZXIgfSA9IGdldE9wdGlvbnMoKTtcclxuXHJcbiAgLy8gR2V0IHRoZSBgZGVidWdgIG9wdGlvbnNcclxuICBjb25zdCB7IGVuYWJsZTogZW5hYmxlZERlYnVnLCAuLi5kZWJ1Z09wdGlvbnMgfSA9IGRlYnVnO1xyXG5cclxuICAvLyBMYXVuY2ggb3B0aW9ucyBmb3IgdGhlIGJyb3dzZXIgaW5zdGFuY2VcclxuICBjb25zdCBsYXVuY2hPcHRpb25zID0ge1xyXG4gICAgaGVhZGxlc3M6IG90aGVyLmJyb3dzZXJTaGVsbE1vZGUgPyAnc2hlbGwnIDogdHJ1ZSxcclxuICAgIHVzZXJEYXRhRGlyOiAndG1wJyxcclxuICAgIGFyZ3M6IHB1cHBldGVlckFyZ3MgfHwgW10sXHJcbiAgICBoYW5kbGVTSUdJTlQ6IGZhbHNlLFxyXG4gICAgaGFuZGxlU0lHVEVSTTogZmFsc2UsXHJcbiAgICBoYW5kbGVTSUdIVVA6IGZhbHNlLFxyXG4gICAgd2FpdEZvckluaXRpYWxQYWdlOiBmYWxzZSxcclxuICAgIGRlZmF1bHRWaWV3cG9ydDogbnVsbCxcclxuICAgIC4uLihlbmFibGVkRGVidWcgJiYgZGVidWdPcHRpb25zKVxyXG4gIH07XHJcblxyXG4gIC8vIENyZWF0ZSBhIGJyb3dzZXJcclxuICBpZiAoIWJyb3dzZXIpIHtcclxuICAgIC8vIEEgY291bnRlciBmb3IgdGhlIGJyb3dzZXIncyBsYXVuY2ggcmV0cmllc1xyXG4gICAgbGV0IHRyeUNvdW50ID0gMDtcclxuXHJcbiAgICBjb25zdCBvcGVuID0gYXN5bmMgKCkgPT4ge1xyXG4gICAgICB0cnkge1xyXG4gICAgICAgIGxvZyhcclxuICAgICAgICAgIDMsXHJcbiAgICAgICAgICBgW2Jyb3dzZXJdIEF0dGVtcHRpbmcgdG8gZ2V0IGEgYnJvd3NlciBpbnN0YW5jZSAodHJ5ICR7Kyt0cnlDb3VudH0pLmBcclxuICAgICAgICApO1xyXG5cclxuICAgICAgICAvLyBMYXVuY2ggdGhlIGJyb3dzZXJcclxuICAgICAgICBicm93c2VyID0gYXdhaXQgcHVwcGV0ZWVyLmxhdW5jaChsYXVuY2hPcHRpb25zKTtcclxuICAgICAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICAgICBsb2dXaXRoU3RhY2soXHJcbiAgICAgICAgICAxLFxyXG4gICAgICAgICAgZXJyb3IsXHJcbiAgICAgICAgICAnW2Jyb3dzZXJdIEZhaWxlZCB0byBsYXVuY2ggYSBicm93c2VyIGluc3RhbmNlLidcclxuICAgICAgICApO1xyXG5cclxuICAgICAgICAvLyBSZXRyeSB0byBsYXVuY2ggYnJvd3NlciB1bnRpbCByZWFjaGluZyBtYXggYXR0ZW1wdHNcclxuICAgICAgICBpZiAodHJ5Q291bnQgPCAyNSkge1xyXG4gICAgICAgICAgbG9nKDMsIGBbYnJvd3Nlcl0gUmV0cnkgdG8gb3BlbiBhIGJyb3dzZXIgKCR7dHJ5Q291bnR9IG91dCBvZiAyNSkuYCk7XHJcblxyXG4gICAgICAgICAgLy8gV2FpdCBmb3IgYSA0IHNlY29uZHMgYmVmb3JlIHRyeWluZyBhZ2FpblxyXG4gICAgICAgICAgYXdhaXQgbmV3IFByb21pc2UoKHJlc3BvbnNlKSA9PiBzZXRUaW1lb3V0KHJlc3BvbnNlLCA0MDAwKSk7XHJcbiAgICAgICAgICBhd2FpdCBvcGVuKCk7XHJcbiAgICAgICAgfSBlbHNlIHtcclxuICAgICAgICAgIHRocm93IGVycm9yO1xyXG4gICAgICAgIH1cclxuICAgICAgfVxyXG4gICAgfTtcclxuXHJcbiAgICB0cnkge1xyXG4gICAgICBhd2FpdCBvcGVuKCk7XHJcblxyXG4gICAgICAvLyBTaGVsbCBtb2RlIGluZm9ybVxyXG4gICAgICBpZiAobGF1bmNoT3B0aW9ucy5oZWFkbGVzcyA9PT0gJ3NoZWxsJykge1xyXG4gICAgICAgIGxvZygzLCBgW2Jyb3dzZXJdIExhdW5jaGVkIGJyb3dzZXIgaW4gc2hlbGwgbW9kZS5gKTtcclxuICAgICAgfVxyXG5cclxuICAgICAgLy8gRGVidWcgbW9kZSBpbmZvcm1cclxuICAgICAgaWYgKGVuYWJsZWREZWJ1Zykge1xyXG4gICAgICAgIGxvZygzLCBgW2Jyb3dzZXJdIExhdW5jaGVkIGJyb3dzZXIgaW4gZGVidWcgbW9kZS5gKTtcclxuICAgICAgfVxyXG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICAgdGhyb3cgbmV3IEV4cG9ydEVycm9yKFxyXG4gICAgICAgICdbYnJvd3Nlcl0gTWF4aW11bSByZXRyaWVzIHRvIG9wZW4gYSBicm93c2VyIGluc3RhbmNlIHJlYWNoZWQuJyxcclxuICAgICAgICA1MDBcclxuICAgICAgKS5zZXRFcnJvcihlcnJvcik7XHJcbiAgICB9XHJcblxyXG4gICAgaWYgKCFicm93c2VyKSB7XHJcbiAgICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcignW2Jyb3dzZXJdIENhbm5vdCBmaW5kIGEgYnJvd3NlciB0byBvcGVuLicsIDUwMCk7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICAvLyBSZXR1cm4gYSBicm93c2VyIGluc3RhbmNlXHJcbiAgcmV0dXJuIGJyb3dzZXI7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBDbG9zZXMgdGhlIFB1cHBldGVlciBicm93c2VyIGluc3RhbmNlIGlmIGl0IGlzIGNvbm5lY3RlZC5cclxuICpcclxuICogQGFzeW5jXHJcbiAqIEBmdW5jdGlvbiBjbG9zZUJyb3dzZXJcclxuICovXHJcbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBjbG9zZUJyb3dzZXIoKSB7XHJcbiAgLy8gQ2xvc2UgdGhlIGJyb3dzZXIgd2hlbiBjb25uZWN0ZWRcclxuICBpZiAoYnJvd3NlciAmJiBicm93c2VyLmNvbm5lY3RlZCkge1xyXG4gICAgYXdhaXQgYnJvd3Nlci5jbG9zZSgpO1xyXG4gIH1cclxuICBicm93c2VyID0gbnVsbDtcclxuICBsb2coNCwgJ1ticm93c2VyXSBDbG9zZWQgdGhlIGJyb3dzZXIuJyk7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBDcmVhdGVzIGEgbmV3IFB1cHBldGVlciBwYWdlIHdpdGhpbiBhbiBleGlzdGluZyBicm93c2VyIGluc3RhbmNlLlxyXG4gKiBUaGUgZnVuY3Rpb24gY3JlYXRlcyBhIG5ldyBwYWdlLCBkaXNhYmxlcyBjYWNoaW5nLCBzZXRzIGNvbnRlbnQgdXNpbmdcclxuICogdGhlIGBfc2V0UGFnZUNvbnRlbnQoKWAsIGFuZCByZXR1cm5zIHRoZSBjcmVhdGVkIFB1cHBldGVlciBwYWdlLlxyXG4gKlxyXG4gKiBAYXN5bmNcclxuICogQGZ1bmN0aW9uIG5ld1BhZ2VcclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IHBvb2xSZXNvdXJjZSAtIFRoZSBwb29sIHJlc291cmNlIHRoYXQgY29udGFpbnMgYGlkYCxcclxuICogYHdvcmtDb3VudGAsIGFuZCBgcGFnZWAuXHJcbiAqXHJcbiAqIEB0aHJvd3Mge0V4cG9ydEVycm9yfSBUaHJvd3MgYW4gYEV4cG9ydEVycm9yYCBpZiBubyB2YWxpZCBicm93c2VyXHJcbiAqIGhhcyBiZWVuIGNvbm5lY3RlZCBvciBpZiBhIHBhZ2UgaXMgaW52YWxpZCBvciBjbG9zZWQuXHJcbiAqL1xyXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gbmV3UGFnZShwb29sUmVzb3VyY2UpIHtcclxuICAvLyBFcnJvciBpbiBjYXNlIG9mIG5vIGNvbm5lY3RlZCBicm93c2VyXHJcbiAgaWYgKCFicm93c2VyIHx8ICFicm93c2VyLmNvbm5lY3RlZCkge1xyXG4gICAgdGhyb3cgbmV3IEV4cG9ydEVycm9yKGBbYnJvd3Nlcl0gQnJvd3NlciBpcyBub3QgeWV0IGNvbm5lY3RlZC5gLCA1MDApO1xyXG4gIH1cclxuXHJcbiAgLy8gQ3JlYXRlIGEgcGFnZVxyXG4gIHBvb2xSZXNvdXJjZS5wYWdlID0gYXdhaXQgYnJvd3Nlci5uZXdQYWdlKCk7XHJcblxyXG4gIC8vIERpc2FibGUgY2FjaGVcclxuICBhd2FpdCBwb29sUmVzb3VyY2UucGFnZS5zZXRDYWNoZUVuYWJsZWQoZmFsc2UpO1xyXG5cclxuICAvLyBTZXQgdGhlIGNvbnRlbnRcclxuICBhd2FpdCBfc2V0UGFnZUNvbnRlbnQocG9vbFJlc291cmNlLnBhZ2UpO1xyXG5cclxuICAvLyBTZXQgcGFnZSBldmVudHNcclxuICBfc2V0UGFnZUV2ZW50cyhwb29sUmVzb3VyY2UucGFnZSk7XHJcblxyXG4gIC8vIENoZWNrIGlmIHRoZSBwYWdlIGlzIGNvcnJlY3RseSBjcmVhdGVkXHJcbiAgaWYgKCFwb29sUmVzb3VyY2UucGFnZSB8fCBwb29sUmVzb3VyY2UucGFnZS5pc0Nsb3NlZCgpKSB7XHJcbiAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoJ1ticm93c2VyXSBUaGUgcGFnZSBpcyBpbnZhbGlkIG9yIGNsb3NlZC4nLCA0MDApO1xyXG4gIH1cclxufVxyXG5cclxuLyoqXHJcbiAqIENsZWFycyB0aGUgY29udGVudCBvZiBhIFB1cHBldGVlciBQYWdlIGJhc2VkIG9uIHRoZSBzcGVjaWZpZWQgbW9kZS4gTG9nc1xyXG4gKiB0aHJvd24gZXJyb3IgaWYgY2xlYXJpbmcgb2YgYSBwYWdlJ3MgY29udGVudCBmYWlscy5cclxuICpcclxuICogQGFzeW5jXHJcbiAqIEBmdW5jdGlvbiBjbGVhclBhZ2VcclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IHBvb2xSZXNvdXJjZSAtIFRoZSBwb29sIHJlc291cmNlIHRoYXQgY29udGFpbnMgcGFnZSBhbmQgaWQuXHJcbiAqIEBwYXJhbSB7Ym9vbGVhbn0gW2hhcmRSZXNldD1mYWxzZV0gLSBBIGZsYWcgaW5kaWNhdGluZyB0aGUgdHlwZSBvZiBjbGVhcmluZ1xyXG4gKiB0byBiZSBwZXJmb3JtZWQuIElmIHRydWUsIG5hdmlnYXRlcyB0byBgYWJvdXQ6YmxhbmtgIGFuZCByZXNldHMgY29udGVudFxyXG4gKiBhbmQgc2NyaXB0cy4gSWYgZmFsc2UsIGNsZWFycyB0aGUgYm9keSBjb250ZW50IGJ5IHNldHRpbmcgYSBwcmVkZWZpbmVkIEhUTUxcclxuICogc3RydWN0dXJlLiBUaGUgZGVmYXVsdCB2YWx1ZSBpcyBgZmFsc2VgLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7UHJvbWlzZTxib29sZWFuPn0gQSBQcm9taXNlIHRoYXQgcmVzb2x2ZXMgdG8gdHJ1ZSB3aGVuIHBhZ2VcclxuICogaXMgY29ycmVjdGx5IGNsZWFyZWQgYW5kIGZhbHNlIHdoZW4gaXQgaXMgbm90LlxyXG4gKi9cclxuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIGNsZWFyUGFnZShwb29sUmVzb3VyY2UsIGhhcmRSZXNldCA9IGZhbHNlKSB7XHJcbiAgdHJ5IHtcclxuICAgIGlmIChwb29sUmVzb3VyY2UucGFnZSAmJiAhcG9vbFJlc291cmNlLnBhZ2UuaXNDbG9zZWQoKSkge1xyXG4gICAgICBpZiAoaGFyZFJlc2V0KSB7XHJcbiAgICAgICAgLy8gTmF2aWdhdGUgdG8gYGFib3V0OmJsYW5rYFxyXG4gICAgICAgIGF3YWl0IHBvb2xSZXNvdXJjZS5wYWdlLmdvdG8oJ2Fib3V0OmJsYW5rJywge1xyXG4gICAgICAgICAgd2FpdFVudGlsOiAnZG9tY29udGVudGxvYWRlZCdcclxuICAgICAgICB9KTtcclxuXHJcbiAgICAgICAgLy8gU2V0IHRoZSBjb250ZW50IGFuZCBhbmQgc2NyaXB0cyBhZ2FpblxyXG4gICAgICAgIGF3YWl0IF9zZXRQYWdlQ29udGVudChwb29sUmVzb3VyY2UucGFnZSk7XHJcbiAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgLy8gQ2xlYXIgYm9keSBjb250ZW50XHJcbiAgICAgICAgYXdhaXQgcG9vbFJlc291cmNlLnBhZ2UuZXZhbHVhdGUoKCkgPT4ge1xyXG4gICAgICAgICAgZG9jdW1lbnQuYm9keS5pbm5lckhUTUwgPVxyXG4gICAgICAgICAgICAnPGRpdiBpZD1cImNoYXJ0LWNvbnRhaW5lclwiPjxkaXYgaWQ9XCJjb250YWluZXJcIj48L2Rpdj48L2Rpdj4nO1xyXG4gICAgICAgIH0pO1xyXG4gICAgICB9XHJcbiAgICAgIHJldHVybiB0cnVlO1xyXG4gICAgfVxyXG4gIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICBsb2dXaXRoU3RhY2soXHJcbiAgICAgIDIsXHJcbiAgICAgIGVycm9yLFxyXG4gICAgICBgW3Bvb2xdIFBvb2wgcmVzb3VyY2UgWyR7cG9vbFJlc291cmNlLmlkfV0gLSBDb250ZW50IG9mIHRoZSBwYWdlIGNvdWxkIG5vdCBiZSBjbGVhcmVkLmBcclxuICAgICk7XHJcblxyXG4gICAgLy8gU2V0IHRoZSBgd29ya0xpbWl0YCB0byBleGNlZWRlZCBpbiBvcmRlciB0byByZWNyZWF0ZSB0aGUgcmVzb3VyY2VcclxuICAgIHBvb2xSZXNvdXJjZS53b3JrQ291bnQgPSBnZXRPcHRpb25zKCkucG9vbC53b3JrTGltaXQgKyAxO1xyXG4gIH1cclxuICByZXR1cm4gZmFsc2U7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBBZGRzIGN1c3RvbSBKUyBhbmQgQ1NTIHJlc291cmNlcyB0byBhIFB1cHBldGVlciBQYWdlIGJhc2VkIG9uIHRoZSBzcGVjaWZpZWRcclxuICogb3B0aW9ucy5cclxuICpcclxuICogQGFzeW5jXHJcbiAqIEBmdW5jdGlvbiBhZGRQYWdlUmVzb3VyY2VzXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBwYWdlIC0gVGhlIFB1cHBldGVlciBwYWdlIG9iamVjdCB0byB3aGljaCByZXNvdXJjZXMgd2lsbFxyXG4gKiBiZSBhZGRlZC5cclxuICogQHBhcmFtIHtPYmplY3R9IGN1c3RvbUxvZ2ljT3B0aW9ucyAtIFRoZSBjb25maWd1cmF0aW9uIG9iamVjdCBjb250YWluaW5nXHJcbiAqIGBjdXN0b21Mb2dpY2Agb3B0aW9ucy5cclxuICpcclxuICogQHJldHVybnMge1Byb21pc2U8QXJyYXkuPE9iamVjdD4+fSBBIFByb21pc2UgdGhhdCByZXNvbHZlcyB0byBhbiBhcnJheVxyXG4gKiBvZiBpbmplY3RlZCByZXNvdXJjZXMuXHJcbiAqL1xyXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gYWRkUGFnZVJlc291cmNlcyhwYWdlLCBjdXN0b21Mb2dpY09wdGlvbnMpIHtcclxuICAvLyBJbmplY3RlZCByZXNvdXJjZXMgYXJyYXlcclxuICBjb25zdCBpbmplY3RlZFJlc291cmNlcyA9IFtdO1xyXG5cclxuICAvLyBVc2UgcmVzb3VyY2VzXHJcbiAgY29uc3QgcmVzb3VyY2VzID0gY3VzdG9tTG9naWNPcHRpb25zLnJlc291cmNlcztcclxuICBpZiAocmVzb3VyY2VzKSB7XHJcbiAgICBjb25zdCBpbmplY3RlZEpzID0gW107XHJcblxyXG4gICAgLy8gTG9hZCBjdXN0b20gSlMgY29kZVxyXG4gICAgaWYgKHJlc291cmNlcy5qcykge1xyXG4gICAgICBpbmplY3RlZEpzLnB1c2goe1xyXG4gICAgICAgIGNvbnRlbnQ6IHJlc291cmNlcy5qc1xyXG4gICAgICB9KTtcclxuICAgIH1cclxuXHJcbiAgICAvLyBMb2FkIHNjcmlwdHMgZnJvbSBhbGwgY3VzdG9tIGZpbGVzXHJcbiAgICBpZiAocmVzb3VyY2VzLmZpbGVzKSB7XHJcbiAgICAgIGZvciAoY29uc3QgZmlsZSBvZiByZXNvdXJjZXMuZmlsZXMpIHtcclxuICAgICAgICBjb25zdCBpc0xvY2FsID0gIWZpbGUuc3RhcnRzV2l0aCgnaHR0cCcpID8gdHJ1ZSA6IGZhbHNlO1xyXG5cclxuICAgICAgICAvLyBBZGQgZWFjaCBjdXN0b20gc2NyaXB0IGZyb20gcmVzb3VyY2VzJyBmaWxlc1xyXG4gICAgICAgIGluamVjdGVkSnMucHVzaChcclxuICAgICAgICAgIGlzTG9jYWxcclxuICAgICAgICAgICAgPyB7XHJcbiAgICAgICAgICAgICAgICBjb250ZW50OiByZWFkRmlsZVN5bmMoZ2V0QWJzb2x1dGVQYXRoKGZpbGUpLCAndXRmOCcpXHJcbiAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICA6IHtcclxuICAgICAgICAgICAgICAgIHVybDogZmlsZVxyXG4gICAgICAgICAgICAgIH1cclxuICAgICAgICApO1xyXG4gICAgICB9XHJcbiAgICB9XHJcblxyXG4gICAgZm9yIChjb25zdCBqc1Jlc291cmNlIG9mIGluamVjdGVkSnMpIHtcclxuICAgICAgdHJ5IHtcclxuICAgICAgICBpbmplY3RlZFJlc291cmNlcy5wdXNoKGF3YWl0IHBhZ2UuYWRkU2NyaXB0VGFnKGpzUmVzb3VyY2UpKTtcclxuICAgICAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICAgICBsb2dXaXRoU3RhY2soMiwgZXJyb3IsIGBbYnJvd3Nlcl0gVGhlIEpTIHJlc291cmNlIGNhbm5vdCBiZSBsb2FkZWQuYCk7XHJcbiAgICAgIH1cclxuICAgIH1cclxuICAgIGluamVjdGVkSnMubGVuZ3RoID0gMDtcclxuXHJcbiAgICAvLyBMb2FkIENTU1xyXG4gICAgY29uc3QgaW5qZWN0ZWRDc3MgPSBbXTtcclxuICAgIGlmIChyZXNvdXJjZXMuY3NzKSB7XHJcbiAgICAgIGxldCBjc3NJbXBvcnRzID0gcmVzb3VyY2VzLmNzcy5tYXRjaCgvQGltcG9ydFxccyooW147XSopOy9nKTtcclxuICAgICAgaWYgKGNzc0ltcG9ydHMpIHtcclxuICAgICAgICAvLyBIYW5kbGUgY3NzIHNlY3Rpb25cclxuICAgICAgICBmb3IgKGxldCBjc3NJbXBvcnRQYXRoIG9mIGNzc0ltcG9ydHMpIHtcclxuICAgICAgICAgIGlmIChjc3NJbXBvcnRQYXRoKSB7XHJcbiAgICAgICAgICAgIGNzc0ltcG9ydFBhdGggPSBjc3NJbXBvcnRQYXRoXHJcbiAgICAgICAgICAgICAgLnJlcGxhY2UoJ3VybCgnLCAnJylcclxuICAgICAgICAgICAgICAucmVwbGFjZSgnQGltcG9ydCcsICcnKVxyXG4gICAgICAgICAgICAgIC5yZXBsYWNlKC9cIi9nLCAnJylcclxuICAgICAgICAgICAgICAucmVwbGFjZSgvJy9nLCAnJylcclxuICAgICAgICAgICAgICAucmVwbGFjZSgvOy8sICcnKVxyXG4gICAgICAgICAgICAgIC5yZXBsYWNlKC9cXCkvZywgJycpXHJcbiAgICAgICAgICAgICAgLnRyaW0oKTtcclxuXHJcbiAgICAgICAgICAgIC8vIEFkZCBlYWNoIGN1c3RvbSBjc3MgZnJvbSByZXNvdXJjZXNcclxuICAgICAgICAgICAgaWYgKGNzc0ltcG9ydFBhdGguc3RhcnRzV2l0aCgnaHR0cCcpKSB7XHJcbiAgICAgICAgICAgICAgaW5qZWN0ZWRDc3MucHVzaCh7XHJcbiAgICAgICAgICAgICAgICB1cmw6IGNzc0ltcG9ydFBhdGhcclxuICAgICAgICAgICAgICB9KTtcclxuICAgICAgICAgICAgfSBlbHNlIGlmIChjdXN0b21Mb2dpY09wdGlvbnMuYWxsb3dGaWxlUmVzb3VyY2VzKSB7XHJcbiAgICAgICAgICAgICAgaW5qZWN0ZWRDc3MucHVzaCh7XHJcbiAgICAgICAgICAgICAgICBwYXRoOiBqb2luKF9fZGlybmFtZSwgY3NzSW1wb3J0UGF0aClcclxuICAgICAgICAgICAgICB9KTtcclxuICAgICAgICAgICAgfVxyXG4gICAgICAgICAgfVxyXG4gICAgICAgIH1cclxuICAgICAgfVxyXG5cclxuICAgICAgLy8gVGhlIHJlc3Qgb2YgdGhlIENTUyBzZWN0aW9uIHdpbGwgYmUgY29udGVudCBieSBub3dcclxuICAgICAgaW5qZWN0ZWRDc3MucHVzaCh7XHJcbiAgICAgICAgY29udGVudDogcmVzb3VyY2VzLmNzcy5yZXBsYWNlKC9AaW1wb3J0XFxzKihbXjtdKik7L2csICcnKSB8fCAnICdcclxuICAgICAgfSk7XHJcblxyXG4gICAgICBmb3IgKGNvbnN0IGNzc1Jlc291cmNlIG9mIGluamVjdGVkQ3NzKSB7XHJcbiAgICAgICAgdHJ5IHtcclxuICAgICAgICAgIGluamVjdGVkUmVzb3VyY2VzLnB1c2goYXdhaXQgcGFnZS5hZGRTdHlsZVRhZyhjc3NSZXNvdXJjZSkpO1xyXG4gICAgICAgIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICAgICAgICBsb2dXaXRoU3RhY2soXHJcbiAgICAgICAgICAgIDIsXHJcbiAgICAgICAgICAgIGVycm9yLFxyXG4gICAgICAgICAgICBgW2Jyb3dzZXJdIFRoZSBDU1MgcmVzb3VyY2UgY2Fubm90IGJlIGxvYWRlZC5gXHJcbiAgICAgICAgICApO1xyXG4gICAgICAgIH1cclxuICAgICAgfVxyXG4gICAgICBpbmplY3RlZENzcy5sZW5ndGggPSAwO1xyXG4gICAgfVxyXG4gIH1cclxuICByZXR1cm4gaW5qZWN0ZWRSZXNvdXJjZXM7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBDbGVhcnMgb3V0IGFsbCBzdGF0ZSBzZXQgb24gdGhlIHBhZ2Ugd2l0aCBgYWRkU2NyaXB0VGFnYCBhbmQgYGFkZFN0eWxlVGFnYC5cclxuICogUmVtb3ZlcyBpbmplY3RlZCByZXNvdXJjZXMgYW5kIHJlc2V0cyBDU1MgYW5kIHNjcmlwdCB0YWdzIG9uIHRoZSBwYWdlLlxyXG4gKiBBZGRpdGlvbmFsbHksIGl0IGRlc3Ryb3lzIHByZXZpb3VzbHkgZXhpc3RpbmcgY2hhcnRzLlxyXG4gKlxyXG4gKiBAYXN5bmNcclxuICogQGZ1bmN0aW9uIGNsZWFyUGFnZVJlc291cmNlc1xyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gcGFnZSAtIFRoZSBQdXBwZXRlZXIgcGFnZSBvYmplY3QgZnJvbSB3aGljaCByZXNvdXJjZXMgd2lsbFxyXG4gKiBiZSBjbGVhcmVkLlxyXG4gKiBAcGFyYW0ge0FycmF5LjxPYmplY3Q+fSBpbmplY3RlZFJlc291cmNlcyAtIEFycmF5IG9mIGluamVjdGVkIHJlc291cmNlc1xyXG4gKiB0byBiZSBjbGVhcmVkLlxyXG4gKi9cclxuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIGNsZWFyUGFnZVJlc291cmNlcyhwYWdlLCBpbmplY3RlZFJlc291cmNlcykge1xyXG4gIHRyeSB7XHJcbiAgICBmb3IgKGNvbnN0IHJlc291cmNlIG9mIGluamVjdGVkUmVzb3VyY2VzKSB7XHJcbiAgICAgIGF3YWl0IHJlc291cmNlLmRpc3Bvc2UoKTtcclxuICAgIH1cclxuXHJcbiAgICAvLyBEZXN0cm95IG9sZCBjaGFydHMgYWZ0ZXIgZXhwb3J0IGlzIGRvbmUgYW5kIHJlc2V0IGFsbCBDU1MgYW5kIHNjcmlwdCB0YWdzXHJcbiAgICBhd2FpdCBwYWdlLmV2YWx1YXRlKCgpID0+IHtcclxuICAgICAgLy8gV2UgYXJlIG5vdCBndWFyYW50ZWVkIHRoYXQgSGlnaGNoYXJ0cyBpcyBsb2FkZWQsIHdoZW4gZG9pbmcgU1ZHIGV4cG9ydHNcclxuICAgICAgaWYgKHR5cGVvZiBIaWdoY2hhcnRzICE9PSAndW5kZWZpbmVkJykge1xyXG4gICAgICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBuby11bmRlZlxyXG4gICAgICAgIGNvbnN0IG9sZENoYXJ0cyA9IEhpZ2hjaGFydHMuY2hhcnRzO1xyXG5cclxuICAgICAgICAvLyBDaGVjayBpbiBhbnkgYWxyZWFkeSBleGlzdGluZyBjaGFydHNcclxuICAgICAgICBpZiAoQXJyYXkuaXNBcnJheShvbGRDaGFydHMpICYmIG9sZENoYXJ0cy5sZW5ndGgpIHtcclxuICAgICAgICAgIC8vIERlc3Ryb3kgb2xkIGNoYXJ0c1xyXG4gICAgICAgICAgZm9yIChjb25zdCBvbGRDaGFydCBvZiBvbGRDaGFydHMpIHtcclxuICAgICAgICAgICAgb2xkQ2hhcnQgJiYgb2xkQ2hhcnQuZGVzdHJveSgpO1xyXG4gICAgICAgICAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgbm8tdW5kZWZcclxuICAgICAgICAgICAgSGlnaGNoYXJ0cy5jaGFydHMuc2hpZnQoKTtcclxuICAgICAgICAgIH1cclxuICAgICAgICB9XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBuby11bmRlZlxyXG4gICAgICBjb25zdCBbLi4uc2NyaXB0c1RvUmVtb3ZlXSA9IGRvY3VtZW50LmdldEVsZW1lbnRzQnlUYWdOYW1lKCdzY3JpcHQnKTtcclxuICAgICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIG5vLXVuZGVmXHJcbiAgICAgIGNvbnN0IFssIC4uLnN0eWxlc1RvUmVtb3ZlXSA9IGRvY3VtZW50LmdldEVsZW1lbnRzQnlUYWdOYW1lKCdzdHlsZScpO1xyXG4gICAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgbm8tdW5kZWZcclxuICAgICAgY29uc3QgWy4uLmxpbmtzVG9SZW1vdmVdID0gZG9jdW1lbnQuZ2V0RWxlbWVudHNCeVRhZ05hbWUoJ2xpbmsnKTtcclxuXHJcbiAgICAgIC8vIFJlbW92ZSB0YWdzXHJcbiAgICAgIGZvciAoY29uc3QgZWxlbWVudCBvZiBbXHJcbiAgICAgICAgLi4uc2NyaXB0c1RvUmVtb3ZlLFxyXG4gICAgICAgIC4uLnN0eWxlc1RvUmVtb3ZlLFxyXG4gICAgICAgIC4uLmxpbmtzVG9SZW1vdmVcclxuICAgICAgXSkge1xyXG4gICAgICAgIGVsZW1lbnQucmVtb3ZlKCk7XHJcbiAgICAgIH1cclxuICAgIH0pO1xyXG4gIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICBsb2dXaXRoU3RhY2soMiwgZXJyb3IsIGBbYnJvd3Nlcl0gQ291bGQgbm90IGNsZWFyIHBhZ2UncyByZXNvdXJjZXMuYCk7XHJcbiAgfVxyXG59XHJcblxyXG4vKipcclxuICogU2V0cyB0aGUgY29udGVudCBmb3IgYSBQdXBwZXRlZXIgUGFnZSB1c2luZyBhIHByZWRlZmluZWQgdGVtcGxhdGVcclxuICogYW5kIGFkZGl0aW9uYWwgc2NyaXB0cy5cclxuICpcclxuICogQGFzeW5jXHJcbiAqIEBmdW5jdGlvbiBfc2V0UGFnZUNvbnRlbnRcclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IHBhZ2UgLSBUaGUgUHVwcGV0ZWVyIHBhZ2Ugb2JqZWN0IHRvIHdoaWNoIHRoZSBjb250ZW50XHJcbiAqIGlzIGJlaW5nIHNldC5cclxuICovXHJcbmFzeW5jIGZ1bmN0aW9uIF9zZXRQYWdlQ29udGVudChwYWdlKSB7XHJcbiAgLy8gU2V0IHRoZSBpbml0aWFsIHBhZ2UgY29udGVudFxyXG4gIGF3YWl0IHBhZ2Uuc2V0Q29udGVudCh0ZW1wbGF0ZSwgeyB3YWl0VW50aWw6ICdkb21jb250ZW50bG9hZGVkJyB9KTtcclxuXHJcbiAgLy8gQWRkIGFsbCByZWdpc3RlcmVkIEhpZ2NoYXJ0cyBzY3JpcHRzLCBxdWl0ZSBkZW1hbmRpbmdcclxuICBhd2FpdCBwYWdlLmFkZFNjcmlwdFRhZyh7IHBhdGg6IGpvaW4oZ2V0Q2FjaGVQYXRoKCksICdzb3VyY2VzLmpzJykgfSk7XHJcblxyXG4gIC8vIFNldCB0aGUgaW5pdGlhbCBgYW5pbU9iamVjdGAgZm9yIEhpZ2hjaGFydHNcclxuICBhd2FpdCBwYWdlLmV2YWx1YXRlKHNldHVwSGlnaGNoYXJ0cyk7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBTZXQgZXZlbnRzIChsaWtlIGBwYWdlZXJyb3JgIGFuZCBgY29uc29sZWApIGZvciBhIFB1cHBldGVlciBQYWdlIGluIG9yZGVyXHJcbiAqIHRvIGNhdGNoIGFuZCBkaXNwbGF5IGVycm9ycyBhbmQgY29uc29sZSBsb2dzIGZyb20gdGhlIHdpbmRvdyBjb250ZXh0LlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gX3NldFBhZ2VFdmVudHNcclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IHBhZ2UgLSBUaGUgUHVwcGV0ZWVyIHBhZ2Ugb2JqZWN0IHRvIHdoaWNoIHRoZSBsaXN0ZW5lcnNcclxuICogYXJlIGJlaW5nIHNldC5cclxuICovXHJcbmZ1bmN0aW9uIF9zZXRQYWdlRXZlbnRzKHBhZ2UpIHtcclxuICAvLyBHZXQgYGRlYnVnYCBvcHRpb25zXHJcbiAgY29uc3QgeyBkZWJ1ZyB9ID0gZ2V0T3B0aW9ucygpO1xyXG5cclxuICAvLyBTZXQgdGhlIGBwYWdlZXJyb3JgIGxpc3RlbmVyXHJcbiAgcGFnZS5vbigncGFnZWVycm9yJywgYXN5bmMgKCkgPT4ge1xyXG4gICAgLy8gSXQgd291bGQgc2VlbSBsaWtlIHRoaXMgbWF5IGZpcmUgYXQgdGhlIHNhbWUgdGltZSBvciBzaG9ydGx5IGJlZm9yZVxyXG4gICAgLy8gYSBwYWdlIGlzIGNsb3NlZC5cclxuICAgIGlmIChwYWdlLmlzQ2xvc2VkKCkpIHtcclxuICAgICAgcmV0dXJuO1xyXG4gICAgfVxyXG4gIH0pO1xyXG5cclxuICAvLyBTZXQgdGhlIGBjb25zb2xlYCBsaXN0ZW5lciwgaWYgbmVlZGVkXHJcbiAgaWYgKGRlYnVnLmVuYWJsZSAmJiBkZWJ1Zy5saXN0ZW5Ub0NvbnNvbGUpIHtcclxuICAgIHBhZ2Uub24oJ2NvbnNvbGUnLCAobWVzc2FnZSkgPT4ge1xyXG4gICAgICBjb25zb2xlLmxvZyhgW2RlYnVnXSAke21lc3NhZ2UudGV4dCgpfWApO1xyXG4gICAgfSk7XHJcbiAgfVxyXG59XHJcblxyXG5leHBvcnQgZGVmYXVsdCB7XHJcbiAgZ2V0QnJvd3NlcixcclxuICBjcmVhdGVCcm93c2VyLFxyXG4gIGNsb3NlQnJvd3NlcixcclxuICBuZXdQYWdlLFxyXG4gIGNsZWFyUGFnZSxcclxuICBhZGRQYWdlUmVzb3VyY2VzLFxyXG4gIGNsZWFyUGFnZVJlc291cmNlc1xyXG59O1xyXG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxyXG5cclxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXHJcblxyXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNSwgSGlnaHNvZnRcclxuXHJcbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cclxuXHJcbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxyXG5cclxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxyXG5cclxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cclxuXHJcbi8qKlxyXG4gKiBUaGUgQ1NTIHRvIGJlIHVzZWQgb24gdGhlIGV4cG9ydGVkIHBhZ2UuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtzdHJpbmd9IFRoZSBDU1MgY29uZmlndXJhdGlvbi5cclxuICovXHJcbmV4cG9ydCBkZWZhdWx0ICgpID0+IGBcclxuXHJcbmh0bWwsIGJvZHkge1xyXG4gIG1hcmdpbjogMDtcclxuICBwYWRkaW5nOiAwO1xyXG4gIGJveC1zaXppbmc6IGJvcmRlci1ib3g7XHJcbn1cclxuXHJcbiN0YWJsZS1kaXYsICNzbGlkZXJzLCAjZGF0YXRhYmxlLCAjY29udHJvbHMsIC5sZC1yb3cge1xyXG4gIGRpc3BsYXk6IG5vbmU7XHJcbiAgaGVpZ2h0OiAwO1xyXG59XHJcblxyXG4jY2hhcnQtY29udGFpbmVyIHtcclxuICBib3gtc2l6aW5nOiBib3JkZXItYm94O1xyXG4gIG1hcmdpbjogMDtcclxuICBvdmVyZmxvdzogYXV0bztcclxuICBmb250LXNpemU6IDA7XHJcbn1cclxuXHJcbiNjaGFydC1jb250YWluZXIgPiBmaWd1cmUsIGRpdiB7XHJcbiAgbWFyZ2luLXRvcDogMCAhaW1wb3J0YW50O1xyXG4gIG1hcmdpbi1ib3R0b206IDAgIWltcG9ydGFudDtcclxufVxyXG5cclxuYDtcclxuIiwiLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcclxuXHJcbkhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlclxyXG5cclxuQ29weXJpZ2h0IChjKSAyMDE2LTIwMjUsIEhpZ2hzb2Z0XHJcblxyXG5MaWNlbmNlZCB1bmRlciB0aGUgTUlUIGxpY2VuY2UuXHJcblxyXG5BZGRpdGlvbmFsbHkgYSB2YWxpZCBIaWdoY2hhcnRzIGxpY2Vuc2UgaXMgcmVxdWlyZWQgZm9yIHVzZS5cclxuXHJcblNlZSBMSUNFTlNFIGZpbGUgaW4gcm9vdCBmb3IgZGV0YWlscy5cclxuXHJcbioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXHJcblxyXG5pbXBvcnQgY3NzVGVtcGxhdGUgZnJvbSAnLi9jc3MuanMnO1xyXG5cclxuLyoqXHJcbiAqIFRoZSBTVkcgdGVtcGxhdGUgdG8gdXNlIHdoZW4gbG9hZGluZyBTVkcgY29udGVudCB0byBiZSBleHBvcnRlZC5cclxuICpcclxuICogQHBhcmFtIHtzdHJpbmd9IHN2ZyAtIFRoZSBTVkcgaW5wdXQgY29udGVudCB0byBiZSBleHBvcnRlZC5cclxuICpcclxuICogQHJldHVybnMge3N0cmluZ30gVGhlIFNWRyB0ZW1wbGF0ZS5cclxuICovXHJcbmV4cG9ydCBkZWZhdWx0IChzdmcpID0+IGBcclxuPCFET0NUWVBFIGh0bWw+XHJcbjxodG1sIGxhbmc9J2VuLVVTJz5cclxuICA8aGVhZD5cclxuICAgIDxtZXRhIGh0dHAtZXF1aXY9XCJDb250ZW50LVR5cGVcIiBjb250ZW50PVwidGV4dC9odG1sOyBjaGFyc2V0PXV0Zi04XCI+XHJcbiAgICA8dGl0bGU+SGlnaGNoYXJ0cyBFeHBvcnQ8L3RpdGxlPlxyXG4gIDwvaGVhZD5cclxuICA8c3R5bGU+XHJcbiAgICAke2Nzc1RlbXBsYXRlKCl9XHJcbiAgPC9zdHlsZT5cclxuICA8Ym9keT5cclxuICAgIDxkaXYgaWQ9XCJjaGFydC1jb250YWluZXJcIj5cclxuICAgICAgJHtzdmd9XHJcbiAgICA8L2Rpdj5cclxuICA8L2JvZHk+XHJcbjwvaHRtbD5cclxuXHJcbmA7XHJcbiIsIi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXHJcblxyXG5IaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXJcclxuXHJcbkNvcHlyaWdodCAoYykgMjAxNi0yMDI1LCBIaWdoc29mdFxyXG5cclxuTGljZW5jZWQgdW5kZXIgdGhlIE1JVCBsaWNlbmNlLlxyXG5cclxuQWRkaXRpb25hbGx5IGEgdmFsaWQgSGlnaGNoYXJ0cyBsaWNlbnNlIGlzIHJlcXVpcmVkIGZvciB1c2UuXHJcblxyXG5TZWUgTElDRU5TRSBmaWxlIGluIHJvb3QgZm9yIGRldGFpbHMuXHJcblxyXG4qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xyXG5cclxuLyoqXHJcbiAqIEBvdmVydmlldyBUaGlzIG1vZHVsZSBoYW5kbGVzIGNoYXJ0IGV4cG9ydCBmdW5jdGlvbmFsaXR5IHVzaW5nIFB1cHBldGVlci5cclxuICogSXQgc3VwcG9ydHMgZXhwb3J0aW5nIGNoYXJ0cyBhcyBTVkcsIFBORywgSlBFRywgYW5kIFBERiBmb3JtYXRzLiBUaGUgbW9kdWxlXHJcbiAqIG1hbmFnZXMgcGFnZSByZXNvdXJjZXMsIHNldHMgdXAgdGhlIGV4cG9ydCBlbnZpcm9ubWVudCwgYW5kIHByb2Nlc3NlcyBjaGFydFxyXG4gKiBjb25maWd1cmF0aW9ucyBvciBTVkcgaW5wdXRzIGZvciByZW5kZXJpbmcuIEV4cG9ydHMgdG8gYSBjaGFydCBmcm9tIGEgcGFnZVxyXG4gKiB1c2luZyBQdXBwZXRlZXIuXHJcbiAqL1xyXG5cclxuaW1wb3J0IHsgYWRkUGFnZVJlc291cmNlcywgY2xlYXJQYWdlUmVzb3VyY2VzIH0gZnJvbSAnLi9icm93c2VyLmpzJztcclxuaW1wb3J0IHsgY3JlYXRlQ2hhcnQgfSBmcm9tICcuL2hpZ2hjaGFydHMuanMnO1xyXG5pbXBvcnQgeyBsb2cgfSBmcm9tICcuL2xvZ2dlci5qcyc7XHJcblxyXG5pbXBvcnQgc3ZnVGVtcGxhdGUgZnJvbSAnLi4vdGVtcGxhdGVzL3N2Z0V4cG9ydC9zdmdFeHBvcnQuanMnO1xyXG5cclxuaW1wb3J0IEV4cG9ydEVycm9yIGZyb20gJy4vZXJyb3JzL0V4cG9ydEVycm9yLmpzJztcclxuXHJcbi8qKlxyXG4gKiBFeHBvcnRzIHRvIGEgY2hhcnQgZnJvbSBhIHBhZ2UgdXNpbmcgUHVwcGV0ZWVyLlxyXG4gKlxyXG4gKiBAYXN5bmNcclxuICogQGZ1bmN0aW9uIHB1cHBldGVlckV4cG9ydFxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gcGFnZSAtIFB1cHBldGVlciBwYWdlIG9iamVjdC5cclxuICogQHBhcmFtIHtPYmplY3R9IGV4cG9ydE9wdGlvbnMgLSBUaGUgY29uZmlndXJhdGlvbiBvYmplY3QgY29udGFpbmluZyBgZXhwb3J0YFxyXG4gKiBvcHRpb25zLlxyXG4gKiBAcGFyYW0ge09iamVjdH0gY3VzdG9tTG9naWNPcHRpb25zIC0gVGhlIGNvbmZpZ3VyYXRpb24gb2JqZWN0IGNvbnRhaW5pbmdcclxuICogYGN1c3RvbUxvZ2ljYCBvcHRpb25zLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7UHJvbWlzZTwoc3RyaW5nfEJ1ZmZlcnxFeHBvcnRFcnJvcik+fSBBIFByb21pc2UgdGhhdCByZXNvbHZlc1xyXG4gKiB0byB0aGUgZXhwb3J0ZWQgZGF0YSBvciByZWplY3Rpbmcgd2l0aCBhbiBgRXhwb3J0RXJyb3JgLlxyXG4gKlxyXG4gKiBAdGhyb3dzIHtFeHBvcnRFcnJvcn0gVGhyb3dzIGFuIGBFeHBvcnRFcnJvcmAgaWYgZXhwb3J0IHRvIGFuIHVuc3VwcG9ydGVkXHJcbiAqIG91dHB1dCBmb3JtYXQgb2NjdXJzLlxyXG4gKi9cclxuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIHB1cHBldGVlckV4cG9ydChwYWdlLCBleHBvcnRPcHRpb25zLCBjdXN0b21Mb2dpY09wdGlvbnMpIHtcclxuICAvLyBJbmplY3RlZCByZXNvdXJjZXMgYXJyYXkgKGFkZGl0aW9uYWwgSlMgYW5kIENTUylcclxuICBjb25zdCBpbmplY3RlZFJlc291cmNlcyA9IFtdO1xyXG5cclxuICB0cnkge1xyXG4gICAgbGV0IGlzU1ZHID0gZmFsc2U7XHJcblxyXG4gICAgLy8gRGVjaWRlIG9uIHRoZSBleHBvcnQgbWV0aG9kXHJcbiAgICBpZiAoZXhwb3J0T3B0aW9ucy5zdmcpIHtcclxuICAgICAgbG9nKDQsICdbZXhwb3J0XSBUcmVhdGluZyBhcyBTVkcgaW5wdXQuJyk7XHJcblxyXG4gICAgICAvLyBJZiB0aGUgYHR5cGVgIGlzIGFsc28gU1ZHLCByZXR1cm4gdGhlIGlucHV0XHJcbiAgICAgIGlmIChleHBvcnRPcHRpb25zLnR5cGUgPT09ICdzdmcnKSB7XHJcbiAgICAgICAgcmV0dXJuIGV4cG9ydE9wdGlvbnMuc3ZnO1xyXG4gICAgICB9XHJcblxyXG4gICAgICAvLyBNYXJrIGFzIFNWRyBleHBvcnQgZm9yIHRoZSBsYXRlciBzaXplIGNvcnJlY3Rpb25zXHJcbiAgICAgIGlzU1ZHID0gdHJ1ZTtcclxuXHJcbiAgICAgIC8vIFNWRyBleHBvcnRcclxuICAgICAgYXdhaXQgcGFnZS5zZXRDb250ZW50KHN2Z1RlbXBsYXRlKGV4cG9ydE9wdGlvbnMuc3ZnKSwge1xyXG4gICAgICAgIHdhaXRVbnRpbDogJ2RvbWNvbnRlbnRsb2FkZWQnXHJcbiAgICAgIH0pO1xyXG4gICAgfSBlbHNlIHtcclxuICAgICAgbG9nKDQsICdbZXhwb3J0XSBUcmVhdGluZyBhcyBKU09OIGNvbmZpZy4nKTtcclxuXHJcbiAgICAgIC8vIE9wdGlvbnMgZXhwb3J0XHJcbiAgICAgIGF3YWl0IHBhZ2UuZXZhbHVhdGUoY3JlYXRlQ2hhcnQsIGV4cG9ydE9wdGlvbnMsIGN1c3RvbUxvZ2ljT3B0aW9ucyk7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gS2VlcHMgdHJhY2sgb2YgYWxsIHJlc291cmNlcyBhZGRlZCBvbiB0aGUgcGFnZSB3aXRoIGFkZFhYWFRhZy4gZXRjXHJcbiAgICAvLyBJdCdzIFZJVEFMIHRoYXQgYWxsIGFkZGVkIHJlc291cmNlcyBlbmRzIHVwIGhlcmUgc28gd2UgY2FuIGNsZWFyIHRoaW5nc1xyXG4gICAgLy8gb3V0IHdoZW4gZG9pbmcgYSBuZXcgZXhwb3J0IGluIHRoZSBzYW1lIHBhZ2UhXHJcbiAgICBpbmplY3RlZFJlc291cmNlcy5wdXNoKFxyXG4gICAgICAuLi4oYXdhaXQgYWRkUGFnZVJlc291cmNlcyhwYWdlLCBjdXN0b21Mb2dpY09wdGlvbnMpKVxyXG4gICAgKTtcclxuXHJcbiAgICAvLyBHZXQgdGhlIHJlYWwgY2hhcnQgc2l6ZSBhbmQgc2V0IHRoZSB6b29tIGFjY29yZGluZ2x5XHJcbiAgICBjb25zdCBzaXplID0gaXNTVkdcclxuICAgICAgPyBhd2FpdCBwYWdlLmV2YWx1YXRlKChzY2FsZSkgPT4ge1xyXG4gICAgICAgICAgY29uc3Qgc3ZnRWxlbWVudCA9IGRvY3VtZW50LnF1ZXJ5U2VsZWN0b3IoXHJcbiAgICAgICAgICAgICcjY2hhcnQtY29udGFpbmVyIHN2ZzpmaXJzdC1vZi10eXBlJ1xyXG4gICAgICAgICAgKTtcclxuXHJcbiAgICAgICAgICAvLyBHZXQgdGhlIHZhbHVlcyBjb3JyZWN0bHkgc2NhbGVkXHJcbiAgICAgICAgICBjb25zdCBjaGFydEhlaWdodCA9IHN2Z0VsZW1lbnQuaGVpZ2h0LmJhc2VWYWwudmFsdWUgKiBzY2FsZTtcclxuICAgICAgICAgIGNvbnN0IGNoYXJ0V2lkdGggPSBzdmdFbGVtZW50LndpZHRoLmJhc2VWYWwudmFsdWUgKiBzY2FsZTtcclxuXHJcbiAgICAgICAgICAvLyBJbiBjYXNlIG9mIFNWRyB0aGUgem9vbSBtdXN0IGJlIHNldCBkaXJlY3RseSBmb3IgYm9keSBhcyBzY2FsZVxyXG4gICAgICAgICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIG5vLXVuZGVmXHJcbiAgICAgICAgICBkb2N1bWVudC5ib2R5LnN0eWxlLnpvb20gPSBzY2FsZTtcclxuXHJcbiAgICAgICAgICAvLyBTZXQgdGhlIG1hcmdpbiB0byAwcHhcclxuICAgICAgICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBuby11bmRlZlxyXG4gICAgICAgICAgZG9jdW1lbnQuYm9keS5zdHlsZS5tYXJnaW4gPSAnMHB4JztcclxuXHJcbiAgICAgICAgICByZXR1cm4ge1xyXG4gICAgICAgICAgICBjaGFydEhlaWdodCxcclxuICAgICAgICAgICAgY2hhcnRXaWR0aFxyXG4gICAgICAgICAgfTtcclxuICAgICAgICB9LCBwYXJzZUZsb2F0KGV4cG9ydE9wdGlvbnMuc2NhbGUpKVxyXG4gICAgICA6IGF3YWl0IHBhZ2UuZXZhbHVhdGUoKCkgPT4ge1xyXG4gICAgICAgICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIG5vLXVuZGVmXHJcbiAgICAgICAgICBjb25zdCB7IGNoYXJ0SGVpZ2h0LCBjaGFydFdpZHRoIH0gPSB3aW5kb3cuSGlnaGNoYXJ0cy5jaGFydHNbMF07XHJcblxyXG4gICAgICAgICAgLy8gTm8gbmVlZCBmb3Igc3VjaCBzY2FsZSBtYW5pcHVsYXRpb24gaW4gY2FzZSBvZiBvdGhlciB0eXBlc1xyXG4gICAgICAgICAgLy8gb2YgZXhwb3J0cy4gUmVzZXQgdGhlIHpvb20gZm9yIG90aGVyIGV4cG9ydHMgdGhhbiB0byBTVkdzXHJcbiAgICAgICAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgbm8tdW5kZWZcclxuICAgICAgICAgIGRvY3VtZW50LmJvZHkuc3R5bGUuem9vbSA9IDE7XHJcblxyXG4gICAgICAgICAgcmV0dXJuIHtcclxuICAgICAgICAgICAgY2hhcnRIZWlnaHQsXHJcbiAgICAgICAgICAgIGNoYXJ0V2lkdGhcclxuICAgICAgICAgIH07XHJcbiAgICAgICAgfSk7XHJcblxyXG4gICAgLy8gR2V0IHRoZSBjbGlwIHJlZ2lvbiBmb3IgdGhlIHBhZ2VcclxuICAgIGNvbnN0IHsgeCwgeSB9ID0gYXdhaXQgX2dldENsaXBSZWdpb24ocGFnZSk7XHJcblxyXG4gICAgLy8gU2V0IGZpbmFsIGBoZWlnaHRgIGZvciB2aWV3cG9ydFxyXG4gICAgY29uc3Qgdmlld3BvcnRIZWlnaHQgPSBNYXRoLmFicyhcclxuICAgICAgTWF0aC5jZWlsKHNpemUuY2hhcnRIZWlnaHQgfHwgZXhwb3J0T3B0aW9ucy5oZWlnaHQpXHJcbiAgICApO1xyXG5cclxuICAgIC8vIFNldCBmaW5hbCBgd2lkdGhgIGZvciB2aWV3cG9ydFxyXG4gICAgY29uc3Qgdmlld3BvcnRXaWR0aCA9IE1hdGguYWJzKFxyXG4gICAgICBNYXRoLmNlaWwoc2l6ZS5jaGFydFdpZHRoIHx8IGV4cG9ydE9wdGlvbnMud2lkdGgpXHJcbiAgICApO1xyXG5cclxuICAgIC8vIFNldCB0aGUgZmluYWwgdmlld3BvcnQgbm93IHRoYXQgd2UgaGF2ZSB0aGUgcmVhbCBoZWlnaHRcclxuICAgIGF3YWl0IHBhZ2Uuc2V0Vmlld3BvcnQoe1xyXG4gICAgICBoZWlnaHQ6IHZpZXdwb3J0SGVpZ2h0LFxyXG4gICAgICB3aWR0aDogdmlld3BvcnRXaWR0aCxcclxuICAgICAgZGV2aWNlU2NhbGVGYWN0b3I6IGlzU1ZHID8gMSA6IHBhcnNlRmxvYXQoZXhwb3J0T3B0aW9ucy5zY2FsZSlcclxuICAgIH0pO1xyXG5cclxuICAgIGxldCByZXN1bHQ7XHJcbiAgICAvLyBSYXN0ZXJpemF0aW9uIHByb2Nlc3NcclxuICAgIHN3aXRjaCAoZXhwb3J0T3B0aW9ucy50eXBlKSB7XHJcbiAgICAgIGNhc2UgJ3N2Zyc6XHJcbiAgICAgICAgcmVzdWx0ID0gYXdhaXQgX2NyZWF0ZVNWRyhwYWdlKTtcclxuICAgICAgICBicmVhaztcclxuICAgICAgY2FzZSAncG5nJzpcclxuICAgICAgY2FzZSAnanBlZyc6XHJcbiAgICAgICAgcmVzdWx0ID0gYXdhaXQgX2NyZWF0ZUltYWdlKFxyXG4gICAgICAgICAgcGFnZSxcclxuICAgICAgICAgIGV4cG9ydE9wdGlvbnMudHlwZSxcclxuICAgICAgICAgIHtcclxuICAgICAgICAgICAgd2lkdGg6IHZpZXdwb3J0V2lkdGgsXHJcbiAgICAgICAgICAgIGhlaWdodDogdmlld3BvcnRIZWlnaHQsXHJcbiAgICAgICAgICAgIHgsXHJcbiAgICAgICAgICAgIHlcclxuICAgICAgICAgIH0sXHJcbiAgICAgICAgICBleHBvcnRPcHRpb25zLnJhc3Rlcml6YXRpb25UaW1lb3V0XHJcbiAgICAgICAgKTtcclxuICAgICAgICBicmVhaztcclxuICAgICAgY2FzZSAncGRmJzpcclxuICAgICAgICByZXN1bHQgPSBhd2FpdCBfY3JlYXRlUERGKFxyXG4gICAgICAgICAgcGFnZSxcclxuICAgICAgICAgIHZpZXdwb3J0SGVpZ2h0LFxyXG4gICAgICAgICAgdmlld3BvcnRXaWR0aCxcclxuICAgICAgICAgIGV4cG9ydE9wdGlvbnMucmFzdGVyaXphdGlvblRpbWVvdXRcclxuICAgICAgICApO1xyXG4gICAgICAgIGJyZWFrO1xyXG4gICAgICBkZWZhdWx0OlxyXG4gICAgICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcihcclxuICAgICAgICAgIGBbZXhwb3J0XSBVbnN1cHBvcnRlZCBvdXRwdXQgZm9ybWF0OiAke2V4cG9ydE9wdGlvbnMudHlwZX0uYCxcclxuICAgICAgICAgIDQwMFxyXG4gICAgICAgICk7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gQ2xlYXIgcHJldmlvdXNseSBpbmplY3RlZCBKUyBhbmQgQ1NTIHJlc291cmNlc1xyXG4gICAgYXdhaXQgY2xlYXJQYWdlUmVzb3VyY2VzKHBhZ2UsIGluamVjdGVkUmVzb3VyY2VzKTtcclxuICAgIHJldHVybiByZXN1bHQ7XHJcbiAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgIGF3YWl0IGNsZWFyUGFnZVJlc291cmNlcyhwYWdlLCBpbmplY3RlZFJlc291cmNlcyk7XHJcbiAgICByZXR1cm4gZXJyb3I7XHJcbiAgfVxyXG59XHJcblxyXG4vKipcclxuICogUmV0cmlldmVzIHRoZSBjbGlwcGluZyByZWdpb24gY29vcmRpbmF0ZXMgb2YgdGhlIHNwZWNpZmllZCBwYWdlIGVsZW1lbnRcclxuICogd2l0aCB0aGUgJ2NoYXJ0LWNvbnRhaW5lcicgaWQuXHJcbiAqXHJcbiAqIEBhc3luY1xyXG4gKiBAZnVuY3Rpb24gX2dldENsaXBSZWdpb25cclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IHBhZ2UgLSBQdXBwZXRlZXIgcGFnZSBvYmplY3QuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtQcm9taXNlPE9iamVjdD59IEEgUHJvbWlzZSB0aGF0IHJlc29sdmVzIHRvIGFuIG9iamVjdCBjb250YWluaW5nXHJcbiAqIGB4YCwgYHlgLCBgd2lkdGhgLCBhbmQgYGhlaWdodGAgcHJvcGVydGllcy5cclxuICovXHJcbmFzeW5jIGZ1bmN0aW9uIF9nZXRDbGlwUmVnaW9uKHBhZ2UpIHtcclxuICByZXR1cm4gcGFnZS4kZXZhbCgnI2NoYXJ0LWNvbnRhaW5lcicsIChlbGVtZW50KSA9PiB7XHJcbiAgICBjb25zdCB7IHgsIHksIHdpZHRoLCBoZWlnaHQgfSA9IGVsZW1lbnQuZ2V0Qm91bmRpbmdDbGllbnRSZWN0KCk7XHJcbiAgICByZXR1cm4ge1xyXG4gICAgICB4LFxyXG4gICAgICB5LFxyXG4gICAgICB3aWR0aCxcclxuICAgICAgaGVpZ2h0OiBNYXRoLnRydW5jKGhlaWdodCA+IDEgPyBoZWlnaHQgOiA1MDApXHJcbiAgICB9O1xyXG4gIH0pO1xyXG59XHJcblxyXG4vKipcclxuICogQ3JlYXRlcyBhbiBTVkcgYnkgZXZhbHVhdGluZyB0aGUgYG91dGVySFRNTGAgb2YgdGhlIGZpcnN0ICdzdmcnIGVsZW1lbnRcclxuICogaW5zaWRlIGFuIGVsZW1lbnQgd2l0aCB0aGUgaWQgJ2NvbnRhaW5lcicuXHJcbiAqXHJcbiAqIEBhc3luY1xyXG4gKiBAZnVuY3Rpb24gX2NyZWF0ZVNWR1xyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gcGFnZSAtIFB1cHBldGVlciBwYWdlIG9iamVjdC5cclxuICpcclxuICogQHJldHVybnMge1Byb21pc2U8c3RyaW5nPn0gQSBQcm9taXNlIHRoYXQgcmVzb2x2ZXMgdG8gdGhlIFNWRyBzdHJpbmcuXHJcbiAqL1xyXG5hc3luYyBmdW5jdGlvbiBfY3JlYXRlU1ZHKHBhZ2UpIHtcclxuICByZXR1cm4gcGFnZS4kZXZhbChcclxuICAgICcjY29udGFpbmVyIHN2ZzpmaXJzdC1vZi10eXBlJyxcclxuICAgIChlbGVtZW50KSA9PiBlbGVtZW50Lm91dGVySFRNTFxyXG4gICk7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBDcmVhdGVzIGFuIGltYWdlIHVzaW5nIFB1cHBldGVlcidzIHBhZ2UgYHNjcmVlbnNob3RgIGZ1bmN0aW9uYWxpdHkgd2l0aFxyXG4gKiBzcGVjaWZpZWQgb3B0aW9ucy5cclxuICpcclxuICogQGFzeW5jXHJcbiAqIEBmdW5jdGlvbiBfY3JlYXRlSW1hZ2VcclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IHBhZ2UgLSBQdXBwZXRlZXIgcGFnZSBvYmplY3QuXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSB0eXBlIC0gSW1hZ2UgdHlwZS5cclxuICogQHBhcmFtIHtPYmplY3R9IGNsaXAgLSBDbGlwcGluZyByZWdpb24gY29vcmRpbmF0ZXMuXHJcbiAqIEBwYXJhbSB7bnVtYmVyfSByYXN0ZXJpemF0aW9uVGltZW91dCAtIFRpbWVvdXQgZm9yIHJhc3Rlcml6YXRpb25cclxuICogaW4gbWlsbGlzZWNvbmRzLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7UHJvbWlzZTxCdWZmZXI+fSBBIFByb21pc2UgdGhhdCByZXNvbHZlcyB0byB0aGUgaW1hZ2UgYnVmZmVyXHJcbiAqIG9yIHJlamVjdGluZyB3aXRoIGFuIGBFeHBvcnRFcnJvcmAgZm9yIHRpbWVvdXQuXHJcbiAqL1xyXG5hc3luYyBmdW5jdGlvbiBfY3JlYXRlSW1hZ2UocGFnZSwgdHlwZSwgY2xpcCwgcmFzdGVyaXphdGlvblRpbWVvdXQpIHtcclxuICByZXR1cm4gUHJvbWlzZS5yYWNlKFtcclxuICAgIHBhZ2Uuc2NyZWVuc2hvdCh7XHJcbiAgICAgIHR5cGUsXHJcbiAgICAgIGNsaXAsXHJcbiAgICAgIGVuY29kaW5nOiAnYmFzZTY0JyxcclxuICAgICAgZnVsbFBhZ2U6IGZhbHNlLFxyXG4gICAgICBvcHRpbWl6ZUZvclNwZWVkOiB0cnVlLFxyXG4gICAgICBjYXB0dXJlQmV5b25kVmlld3BvcnQ6IHRydWUsXHJcbiAgICAgIC4uLih0eXBlICE9PSAncG5nJyA/IHsgcXVhbGl0eTogODAgfSA6IHt9KSxcclxuICAgICAgLy8gQWx3YXlzIHJlbmRlciBvbiBhIHRyYW5zcGFyZW50IHBhZ2UgaWYgdGhlIGV4cGVjdGVkIHR5cGUgZm9ybWF0IGlzIFBOR1xyXG4gICAgICBvbWl0QmFja2dyb3VuZDogdHlwZSA9PSAncG5nJyAvLyAjNDQ3LCAjNDYzXHJcbiAgICB9KSxcclxuICAgIG5ldyBQcm9taXNlKChfcmVzb2x2ZSwgcmVqZWN0KSA9PlxyXG4gICAgICBzZXRUaW1lb3V0KFxyXG4gICAgICAgICgpID0+IHJlamVjdChuZXcgRXhwb3J0RXJyb3IoJ1Jhc3Rlcml6YXRpb24gdGltZW91dCcsIDQwOCkpLFxyXG4gICAgICAgIHJhc3Rlcml6YXRpb25UaW1lb3V0IHx8IDE1MDBcclxuICAgICAgKVxyXG4gICAgKVxyXG4gIF0pO1xyXG59XHJcblxyXG4vKipcclxuICogQ3JlYXRlcyBhIFBERiB1c2luZyBQdXBwZXRlZXIncyBwYWdlIGBwZGZgIGZ1bmN0aW9uYWxpdHkgd2l0aCBzcGVjaWZpZWRcclxuICogb3B0aW9ucy5cclxuICpcclxuICogQGFzeW5jXHJcbiAqIEBmdW5jdGlvbiBfY3JlYXRlUERGXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBwYWdlIC0gUHVwcGV0ZWVyIHBhZ2Ugb2JqZWN0LlxyXG4gKiBAcGFyYW0ge251bWJlcn0gaGVpZ2h0IC0gUERGIGhlaWdodC5cclxuICogQHBhcmFtIHtudW1iZXJ9IHdpZHRoIC0gUERGIHdpZHRoLlxyXG4gKiBAcGFyYW0ge251bWJlcn0gcmFzdGVyaXphdGlvblRpbWVvdXQgLSBUaW1lb3V0IGZvciByYXN0ZXJpemF0aW9uXHJcbiAqIGluIG1pbGxpc2Vjb25kcy5cclxuICpcclxuICogQHJldHVybnMge1Byb21pc2U8QnVmZmVyPn0gQSBQcm9taXNlIHRoYXQgcmVzb2x2ZXMgdG8gdGhlIFBERiBidWZmZXIuXHJcbiAqL1xyXG5hc3luYyBmdW5jdGlvbiBfY3JlYXRlUERGKHBhZ2UsIGhlaWdodCwgd2lkdGgsIHJhc3Rlcml6YXRpb25UaW1lb3V0KSB7XHJcbiAgYXdhaXQgcGFnZS5lbXVsYXRlTWVkaWFUeXBlKCdzY3JlZW4nKTtcclxuICByZXR1cm4gcGFnZS5wZGYoe1xyXG4gICAgLy8gVGhpcyB3aWxsIHJlbW92ZSBhbiBleHRyYSBlbXB0eSBwYWdlIGluIFBERiBleHBvcnRzXHJcbiAgICBoZWlnaHQ6IGhlaWdodCArIDEsXHJcbiAgICB3aWR0aCxcclxuICAgIGVuY29kaW5nOiAnYmFzZTY0JyxcclxuICAgIHRpbWVvdXQ6IHJhc3Rlcml6YXRpb25UaW1lb3V0IHx8IDE1MDBcclxuICB9KTtcclxufVxyXG5cclxuZXhwb3J0IGRlZmF1bHQge1xyXG4gIHB1cHBldGVlckV4cG9ydFxyXG59O1xyXG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxyXG5cclxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXHJcblxyXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNSwgSGlnaHNvZnRcclxuXHJcbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cclxuXHJcbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxyXG5cclxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxyXG5cclxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cclxuXHJcbi8qKlxyXG4gKiBAb3ZlcnZpZXcgVGhpcyBtb2R1bGUgcHJvdmlkZXMgYSB3b3JrZXIgcG9vbCBpbXBsZW1lbnRhdGlvbiBmb3IgbWFuYWdpbmdcclxuICogdGhlIGJyb3dzZXIgaW5zdGFuY2UgYW5kIHBhZ2VzLCBzcGVjaWZpY2FsbHkgZGVzaWduZWQgZm9yIHVzZSB3aXRoXHJcbiAqIHRoZSBIaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXIuIEl0IG9wdGltaXplcyByZXNvdXJjZXMgdXNhZ2UgYW5kIHBlcmZvcm1hbmNlXHJcbiAqIGJ5IG1haW50YWluaW5nIGEgcG9vbCBvZiB3b3JrZXJzIHRoYXQgY2FuIGhhbmRsZSBjb25jdXJyZW50IGV4cG9ydCB0YXNrc1xyXG4gKiB1c2luZyBQdXBwZXRlZXIuXHJcbiAqL1xyXG5cclxuaW1wb3J0IHsgUG9vbCB9IGZyb20gJ3Rhcm4nO1xyXG5pbXBvcnQgeyB2NCBhcyB1dWlkIH0gZnJvbSAndXVpZCc7XHJcblxyXG5pbXBvcnQgeyBjcmVhdGVCcm93c2VyLCBjbG9zZUJyb3dzZXIsIG5ld1BhZ2UsIGNsZWFyUGFnZSB9IGZyb20gJy4vYnJvd3Nlci5qcyc7XHJcbmltcG9ydCB7IHB1cHBldGVlckV4cG9ydCB9IGZyb20gJy4vZXhwb3J0LmpzJztcclxuaW1wb3J0IHsgbG9nLCBsb2dXaXRoU3RhY2sgfSBmcm9tICcuL2xvZ2dlci5qcyc7XHJcbmltcG9ydCB7IGdldE5ld0RhdGVUaW1lLCBtZWFzdXJlVGltZSB9IGZyb20gJy4vdXRpbHMuanMnO1xyXG5cclxuaW1wb3J0IEV4cG9ydEVycm9yIGZyb20gJy4vZXJyb3JzL0V4cG9ydEVycm9yLmpzJztcclxuXHJcbi8vIFRoZSBwb29sIGluc3RhbmNlXHJcbmxldCBwb29sID0gbnVsbDtcclxuXHJcbi8vIFBvb2wgc3RhdGlzdGljc1xyXG5jb25zdCBwb29sU3RhdHMgPSB7XHJcbiAgZXhwb3J0c0F0dGVtcHRlZDogMCxcclxuICBleHBvcnRzUGVyZm9ybWVkOiAwLFxyXG4gIGV4cG9ydHNEcm9wcGVkOiAwLFxyXG4gIGV4cG9ydHNGcm9tU3ZnOiAwLFxyXG4gIGV4cG9ydHNGcm9tT3B0aW9uczogMCxcclxuICBleHBvcnRzRnJvbVN2Z0F0dGVtcHRzOiAwLFxyXG4gIGV4cG9ydHNGcm9tT3B0aW9uc0F0dGVtcHRzOiAwLFxyXG4gIHRpbWVTcGVudDogMCxcclxuICB0aW1lU3BlbnRBdmVyYWdlOiAwXHJcbn07XHJcblxyXG4vKipcclxuICogSW5pdGlhbGl6ZXMgdGhlIGV4cG9ydCBwb29sIHdpdGggdGhlIHByb3ZpZGVkIGNvbmZpZ3VyYXRpb24sIGNyZWF0aW5nXHJcbiAqIGEgYnJvd3NlciBpbnN0YW5jZSBhbmQgc2V0dGluZyB1cCB3b3JrZXIgcmVzb3VyY2VzLlxyXG4gKlxyXG4gKiBAYXN5bmNcclxuICogQGZ1bmN0aW9uIGluaXRQb29sXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBwb29sT3B0aW9ucyAtIFRoZSBjb25maWd1cmF0aW9uIG9iamVjdCBjb250YWluaW5nIGBwb29sYFxyXG4gKiBvcHRpb25zLlxyXG4gKiBAcGFyYW0ge0FycmF5LjxzdHJpbmc+fSBwdXBwZXRlZXJBcmdzIC0gQWRkaXRpb25hbCBhcmd1bWVudHMgZm9yIFB1cHBldGVlclxyXG4gKiBsYXVuY2guXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtQcm9taXNlPHZvaWQ+fSBBIFByb21pc2UgdGhhdCByZXNvbHZlcyB0byBlbmRpbmcgdGhlIGZ1bmN0aW9uXHJcbiAqIGV4ZWN1dGlvbiB3aGVuIGFuIGFscmVhZHkgaW5pdGlhbGl6ZWQgcG9vbCBvZiByZXNvdXJjZXMgaXMgZm91bmQuXHJcbiAqXHJcbiAqIEB0aHJvd3Mge0V4cG9ydEVycm9yfSBUaHJvd3MgYW4gYEV4cG9ydEVycm9yYCBpZiBjb3VsZCBub3QgY3JlYXRlIHRoZSBwb29sXHJcbiAqIG9mIHdvcmtlcnMuXHJcbiAqL1xyXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gaW5pdFBvb2wocG9vbE9wdGlvbnMsIHB1cHBldGVlckFyZ3MpIHtcclxuICAvLyBDcmVhdGUgYSBicm93c2VyIGluc3RhbmNlIHdpdGggdGhlIHB1cHBldGVlciBhcmd1bWVudHNcclxuICBhd2FpdCBjcmVhdGVCcm93c2VyKHB1cHBldGVlckFyZ3MpO1xyXG5cclxuICB0cnkge1xyXG4gICAgbG9nKFxyXG4gICAgICAzLFxyXG4gICAgICBgW3Bvb2xdIEluaXRpYWxpemluZyBwb29sIHdpdGggd29ya2VyczogbWluICR7cG9vbE9wdGlvbnMubWluV29ya2Vyc30sIG1heCAke3Bvb2xPcHRpb25zLm1heFdvcmtlcnN9LmBcclxuICAgICk7XHJcblxyXG4gICAgaWYgKHBvb2wpIHtcclxuICAgICAgbG9nKFxyXG4gICAgICAgIDQsXHJcbiAgICAgICAgJ1twb29sXSBBbHJlYWR5IGluaXRpYWxpemVkLCBwbGVhc2Uga2lsbCBpdCBiZWZvcmUgY3JlYXRpbmcgYSBuZXcgb25lLidcclxuICAgICAgKTtcclxuICAgICAgcmV0dXJuO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIEtlZXAgYW4gZXllIG9uIGEgY29ycmVjdCBtaW4gYW5kIG1heCB3b3JrZXJzIG51bWJlclxyXG4gICAgaWYgKHBvb2xPcHRpb25zLm1pbldvcmtlcnMgPiBwb29sT3B0aW9ucy5tYXhXb3JrZXJzKSB7XHJcbiAgICAgIHBvb2xPcHRpb25zLm1pbldvcmtlcnMgPSBwb29sT3B0aW9ucy5tYXhXb3JrZXJzO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIENyZWF0ZSBhIHBvb2wgYWxvbmcgd2l0aCBhIG1pbmltYWwgbnVtYmVyIG9mIHJlc291cmNlc1xyXG4gICAgcG9vbCA9IG5ldyBQb29sKHtcclxuICAgICAgLy8gR2V0IHRoZSBgY3JlYXRlYCwgYHZhbGlkYXRlYCwgYW5kIGBkZXN0cm95YCBmdW5jdGlvbnNcclxuICAgICAgLi4uX2ZhY3RvcnkocG9vbE9wdGlvbnMpLFxyXG4gICAgICBtaW46IHBvb2xPcHRpb25zLm1pbldvcmtlcnMsXHJcbiAgICAgIG1heDogcG9vbE9wdGlvbnMubWF4V29ya2VycyxcclxuICAgICAgYWNxdWlyZVRpbWVvdXRNaWxsaXM6IHBvb2xPcHRpb25zLmFjcXVpcmVUaW1lb3V0LFxyXG4gICAgICBjcmVhdGVUaW1lb3V0TWlsbGlzOiBwb29sT3B0aW9ucy5jcmVhdGVUaW1lb3V0LFxyXG4gICAgICBkZXN0cm95VGltZW91dE1pbGxpczogcG9vbE9wdGlvbnMuZGVzdHJveVRpbWVvdXQsXHJcbiAgICAgIGlkbGVUaW1lb3V0TWlsbGlzOiBwb29sT3B0aW9ucy5pZGxlVGltZW91dCxcclxuICAgICAgY3JlYXRlUmV0cnlJbnRlcnZhbE1pbGxpczogcG9vbE9wdGlvbnMuY3JlYXRlUmV0cnlJbnRlcnZhbCxcclxuICAgICAgcmVhcEludGVydmFsTWlsbGlzOiBwb29sT3B0aW9ucy5yZWFwZXJJbnRlcnZhbCxcclxuICAgICAgcHJvcGFnYXRlQ3JlYXRlRXJyb3I6IGZhbHNlXHJcbiAgICB9KTtcclxuXHJcbiAgICAvLyBTZXQgZXZlbnRzXHJcbiAgICBwb29sLm9uKCdyZWxlYXNlJywgYXN5bmMgKHJlc291cmNlKSA9PiB7XHJcbiAgICAgIC8vIENsZWFyIHBhZ2VcclxuICAgICAgY29uc3QgY2xlYXJTdGF0dXMgPSBhd2FpdCBjbGVhclBhZ2UocmVzb3VyY2UsIGZhbHNlKTtcclxuICAgICAgbG9nKFxyXG4gICAgICAgIDQsXHJcbiAgICAgICAgYFtwb29sXSBQb29sIHJlc291cmNlIFske3Jlc291cmNlLmlkfV0gLSBSZWxlYXNpbmcgYSB3b3JrZXIuIENsZWFyIHBhZ2Ugc3RhdHVzOiAke2NsZWFyU3RhdHVzfS5gXHJcbiAgICAgICk7XHJcbiAgICB9KTtcclxuXHJcbiAgICBwb29sLm9uKCdkZXN0cm95U3VjY2VzcycsIChfZXZlbnRJZCwgcmVzb3VyY2UpID0+IHtcclxuICAgICAgbG9nKFxyXG4gICAgICAgIDQsXHJcbiAgICAgICAgYFtwb29sXSBQb29sIHJlc291cmNlIFske3Jlc291cmNlLmlkfV0gLSBEZXN0cm95ZWQgYSB3b3JrZXIgc3VjY2Vzc2Z1bGx5LmBcclxuICAgICAgKTtcclxuICAgICAgcmVzb3VyY2UucGFnZSA9IG51bGw7XHJcbiAgICB9KTtcclxuXHJcbiAgICBjb25zdCBpbml0aWFsUmVzb3VyY2VzID0gW107XHJcbiAgICAvLyBDcmVhdGUgYW4gaW5pdGlhbCBudW1iZXIgb2YgcmVzb3VyY2VzXHJcbiAgICBmb3IgKGxldCBpID0gMDsgaSA8IHBvb2xPcHRpb25zLm1pbldvcmtlcnM7IGkrKykge1xyXG4gICAgICB0cnkge1xyXG4gICAgICAgIGNvbnN0IHJlc291cmNlID0gYXdhaXQgcG9vbC5hY3F1aXJlKCkucHJvbWlzZTtcclxuICAgICAgICBpbml0aWFsUmVzb3VyY2VzLnB1c2gocmVzb3VyY2UpO1xyXG4gICAgICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgICAgIGxvZ1dpdGhTdGFjaygyLCBlcnJvciwgJ1twb29sXSBDb3VsZCBub3QgY3JlYXRlIGFuIGluaXRpYWwgcmVzb3VyY2UuJyk7XHJcbiAgICAgIH1cclxuICAgIH1cclxuXHJcbiAgICAvLyBSZWxlYXNlIHRoZSBpbml0aWFsIG51bWJlciBvZiByZXNvdXJjZXMgYmFjayB0byB0aGUgcG9vbFxyXG4gICAgaW5pdGlhbFJlc291cmNlcy5mb3JFYWNoKChyZXNvdXJjZSkgPT4ge1xyXG4gICAgICBwb29sLnJlbGVhc2UocmVzb3VyY2UpO1xyXG4gICAgfSk7XHJcblxyXG4gICAgbG9nKFxyXG4gICAgICAzLFxyXG4gICAgICBgW3Bvb2xdIFRoZSBwb29sIGlzIHJlYWR5JHtpbml0aWFsUmVzb3VyY2VzLmxlbmd0aCA/IGAgd2l0aCAke2luaXRpYWxSZXNvdXJjZXMubGVuZ3RofSBpbml0aWFsIHJlc291cmNlcyB3YWl0aW5nLmAgOiAnLid9YFxyXG4gICAgKTtcclxuICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgdGhyb3cgbmV3IEV4cG9ydEVycm9yKFxyXG4gICAgICAnW3Bvb2xdIENvdWxkIG5vdCBjb25maWd1cmUgYW5kIGNyZWF0ZSB0aGUgcG9vbCBvZiB3b3JrZXJzLicsXHJcbiAgICAgIDUwMFxyXG4gICAgKS5zZXRFcnJvcihlcnJvcik7XHJcbiAgfVxyXG59XHJcblxyXG4vKipcclxuICogVGVybWluYXRlcyBhbGwgd29ya2VycyBpbiB0aGUgcG9vbCwgZGVzdHJveXMgdGhlIHBvb2wsIGFuZCBjbG9zZXMgdGhlIGJyb3dzZXJcclxuICogaW5zdGFuY2UuXHJcbiAqXHJcbiAqIEBhc3luY1xyXG4gKiBAZnVuY3Rpb24ga2lsbFBvb2xcclxuICpcclxuICogQHJldHVybnMge1Byb21pc2U8dm9pZD59IEEgUHJvbWlzZSB0aGF0IHJlc29sdmVzIG9uY2UgYWxsIHdvcmtlcnMgYXJlXHJcbiAqIHRlcm1pbmF0ZWQsIHRoZSBwb29sIGlzIGRlc3Ryb3llZCwgYW5kIHRoZSBicm93c2VyIGlzIHN1Y2Nlc3NmdWxseSBjbG9zZWQuXHJcbiAqL1xyXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24ga2lsbFBvb2woKSB7XHJcbiAgbG9nKDMsICdbcG9vbF0gS2lsbGluZyBwb29sIHdpdGggYWxsIHdvcmtlcnMgYW5kIGNsb3NpbmcgYnJvd3Nlci4nKTtcclxuXHJcbiAgLy8gSWYgc3RpbGwgYWxpdmUsIGRlc3Ryb3kgdGhlIHBvb2wgb2YgcGFnZXMgYmVmb3JlIGNsb3NpbmcgYSBicm93c2VyXHJcbiAgaWYgKHBvb2wpIHtcclxuICAgIC8vIEZyZWUgdXAgbm90IHJlbGVhc2VkIHdvcmtlcnNcclxuICAgIGZvciAoY29uc3Qgd29ya2VyIG9mIHBvb2wudXNlZCkge1xyXG4gICAgICBwb29sLnJlbGVhc2Uod29ya2VyLnJlc291cmNlKTtcclxuICAgIH1cclxuXHJcbiAgICAvLyBEZXN0cm95IHRoZSBwb29sIGlmIGl0IGlzIHN0aWxsIGF2YWlsYWJsZVxyXG4gICAgaWYgKCFwb29sLmRlc3Ryb3llZCkge1xyXG4gICAgICBhd2FpdCBwb29sLmRlc3Ryb3koKTtcclxuICAgICAgbG9nKDQsICdbcG9vbF0gRGVzdHJveWVkIHRoZSBwb29sIG9mIHJlc291cmNlcy4nKTtcclxuICAgIH1cclxuICAgIHBvb2wgPSBudWxsO1xyXG4gIH1cclxuXHJcbiAgLy8gQ2xvc2UgdGhlIGJyb3dzZXIgaW5zdGFuY2VcclxuICBhd2FpdCBjbG9zZUJyb3dzZXIoKTtcclxufVxyXG5cclxuLyoqXHJcbiAqIFByb2Nlc3NlcyB0aGUgZXhwb3J0IHdvcmsgdXNpbmcgYSB3b3JrZXIgZnJvbSB0aGUgcG9vbC4gQWNxdWlyZXMgYSB3b3JrZXJcclxuICogaGFuZGxlIGZyb20gdGhlIHBvb2wsIHBlcmZvcm1zIHRoZSBleHBvcnQgdXNpbmcgcHVwcGV0ZWVyLCBhbmQgcmVsZWFzZXNcclxuICogdGhlIHdvcmtlciBoYW5kbGUgYmFjayB0byB0aGUgcG9vbC5cclxuICpcclxuICogQGFzeW5jXHJcbiAqIEBmdW5jdGlvbiBwb3N0V29ya1xyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gb3B0aW9ucyAtIFRoZSBjb25maWd1cmF0aW9uIG9iamVjdCBjb250YWluaW5nIGNvbXBsZXRlIHNldFxyXG4gKiBvZiBvcHRpb25zLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7UHJvbWlzZTxPYmplY3Q+fSBBIFByb21pc2UgdGhhdCByZXNvbHZlcyB0byB0aGUgZXhwb3J0IHJlc3VsdFxyXG4gKiBhbmQgb3B0aW9ucy5cclxuICpcclxuICogQHRocm93cyB7RXhwb3J0RXJyb3J9IFRocm93cyBhbiBgRXhwb3J0RXJyb3JgIGlmIGFuIGVycm9yIG9jY3VycyBkdXJpbmdcclxuICogdGhlIGV4cG9ydCBwcm9jZXNzLlxyXG4gKi9cclxuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIHBvc3RXb3JrKG9wdGlvbnMpIHtcclxuICBsZXQgd29ya2VySGFuZGxlO1xyXG5cclxuICB0cnkge1xyXG4gICAgbG9nKDQsICdbcG9vbF0gV29yayByZWNlaXZlZCwgc3RhcnRpbmcgdG8gcHJvY2Vzcy4nKTtcclxuXHJcbiAgICAvLyBBbiBleHBvcnQgYXR0ZW1wdCBjb3VudGVkXHJcbiAgICArK3Bvb2xTdGF0cy5leHBvcnRzQXR0ZW1wdGVkO1xyXG5cclxuICAgIC8vIERpc3BsYXkgdGhlIHBvb2wgaW5mb3JtYXRpb24gaWYgbmVlZGVkXHJcbiAgICBpZiAob3B0aW9ucy5wb29sLmJlbmNobWFya2luZykge1xyXG4gICAgICBnZXRQb29sSW5mbygpO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIFRocm93IGFuIGVycm9yIGluIGNhc2Ugb2YgbGFja2luZyB0aGUgcG9vbCBpbnN0YW5jZVxyXG4gICAgaWYgKCFwb29sKSB7XHJcbiAgICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcihcclxuICAgICAgICAnW3Bvb2xdIFdvcmsgcmVjZWl2ZWQsIGJ1dCBwb29sIGhhcyBub3QgYmVlbiBzdGFydGVkLicsXHJcbiAgICAgICAgNTAwXHJcbiAgICAgICk7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gVGhlIGFjcXVpcmUgY291bnRlclxyXG4gICAgY29uc3QgYWNxdWlyZUNvdW50ZXIgPSBtZWFzdXJlVGltZSgpO1xyXG5cclxuICAgIC8vIFRyeSB0byBhY3F1aXJlIHRoZSB3b3JrZXIgYWxvbmcgd2l0aCB0aGUgaWQsIHdvcmtzIGNvdW50IGFuZCBwYWdlXHJcbiAgICB0cnkge1xyXG4gICAgICBsb2coNCwgJ1twb29sXSBBY3F1aXJpbmcgYSB3b3JrZXIgaGFuZGxlLicpO1xyXG5cclxuICAgICAgLy8gQWNxdWlyZSBhIHBvb2wgcmVzb3VyY2VcclxuICAgICAgd29ya2VySGFuZGxlID0gYXdhaXQgcG9vbC5hY3F1aXJlKCkucHJvbWlzZTtcclxuXHJcbiAgICAgIC8vIENoZWNrIHRoZSBwYWdlIGFjcXVpcmUgdGltZVxyXG4gICAgICBpZiAob3B0aW9ucy5zZXJ2ZXIuYmVuY2htYXJraW5nKSB7XHJcbiAgICAgICAgbG9nKFxyXG4gICAgICAgICAgNSxcclxuICAgICAgICAgIGBbYmVuY2htYXJrXSAke29wdGlvbnMucmVxdWVzdElkID8gYFJlcXVlc3QgWyR7b3B0aW9ucy5yZXF1ZXN0SWR9XSAtIGAgOiAnJ31gLFxyXG4gICAgICAgICAgYEFjcXVpcmluZyBhIHdvcmtlciBoYW5kbGUgdG9vayAke2FjcXVpcmVDb3VudGVyKCl9bXMuYFxyXG4gICAgICAgICk7XHJcbiAgICAgIH1cclxuICAgIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcihcclxuICAgICAgICBgW3Bvb2xdICR7XHJcbiAgICAgICAgICBvcHRpb25zLnJlcXVlc3RJZCA/IGBSZXF1ZXN0IFske29wdGlvbnMucmVxdWVzdElkfV0gLSBgIDogJydcclxuICAgICAgICB9RXJyb3IgZW5jb3VudGVyZWQgd2hlbiBhY3F1aXJpbmcgYW4gYXZhaWxhYmxlIGVudHJ5OiAke2FjcXVpcmVDb3VudGVyKCl9bXMuYCxcclxuICAgICAgICA0MDBcclxuICAgICAgKS5zZXRFcnJvcihlcnJvcik7XHJcbiAgICB9XHJcbiAgICBsb2coNCwgJ1twb29sXSBBY3F1aXJlZCBhIHdvcmtlciBoYW5kbGUuJyk7XHJcblxyXG4gICAgaWYgKCF3b3JrZXJIYW5kbGUucGFnZSkge1xyXG4gICAgICAvLyBTZXQgdGhlIGB3b3JrTGltaXRgIHRvIGV4Y2VlZGVkIGluIG9yZGVyIHRvIHJlY3JlYXRlIHRoZSByZXNvdXJjZVxyXG4gICAgICB3b3JrZXJIYW5kbGUud29ya0NvdW50ID0gb3B0aW9ucy5wb29sLndvcmtMaW1pdCArIDE7XHJcbiAgICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcihcclxuICAgICAgICAnW3Bvb2xdIFJlc29sdmVkIHdvcmtlciBwYWdlIGlzIGludmFsaWQ6IHRoZSBwb29sIHNldHVwIGlzIHdvbmt5LicsXHJcbiAgICAgICAgNDAwXHJcbiAgICAgICk7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gU2F2ZSB0aGUgc3RhcnQgdGltZVxyXG4gICAgY29uc3Qgd29ya1N0YXJ0ID0gZ2V0TmV3RGF0ZVRpbWUoKTtcclxuXHJcbiAgICBsb2coXHJcbiAgICAgIDQsXHJcbiAgICAgIGBbcG9vbF0gUG9vbCByZXNvdXJjZSBbJHt3b3JrZXJIYW5kbGUuaWR9XSAtIFN0YXJ0aW5nIHdvcmsgb24gdGhpcyBwb29sIGVudHJ5LmBcclxuICAgICk7XHJcblxyXG4gICAgLy8gU3RhcnQgbWVhc3VyaW5nIGV4cG9ydCB0aW1lXHJcbiAgICBjb25zdCBleHBvcnRDb3VudGVyID0gbWVhc3VyZVRpbWUoKTtcclxuXHJcbiAgICAvLyBQZXJmb3JtIGFuIGV4cG9ydCBvbiBhIHB1cHBldGVlciBsZXZlbFxyXG4gICAgY29uc3QgcmVzdWx0ID0gYXdhaXQgcHVwcGV0ZWVyRXhwb3J0KFxyXG4gICAgICB3b3JrZXJIYW5kbGUucGFnZSxcclxuICAgICAgb3B0aW9ucy5leHBvcnQsXHJcbiAgICAgIG9wdGlvbnMuY3VzdG9tTG9naWNcclxuICAgICk7XHJcblxyXG4gICAgLy8gQ2hlY2sgaWYgaXQncyBhbiBlcnJvclxyXG4gICAgaWYgKHJlc3VsdCBpbnN0YW5jZW9mIEVycm9yKSB7XHJcbiAgICAgIC8vIE5PVEU6XHJcbiAgICAgIC8vIElmIHRoZXJlJ3MgYSByYXN0ZXJpemF0aW9uIHRpbWVvdXQsIHdlIHdhbnQgbmVlZCB0byBmbHVzaCB0aGUgcGFnZS5cclxuICAgICAgLy8gVGhpcyBpcyBiZWNhdXNlIHRoZSBwYWdlIG1heSBiZSBpbiBhIHN0YXRlIHdoZXJlIGl0J3Mgd2FpdGluZyBmb3JcclxuICAgICAgLy8gdGhlIHNjcmVlbnNob3QgdG8gZmluaXNoIGV2ZW4gdGhvdWdoIHRoZSB0aW1lb3V0IGhhcyBvY2N1cmVkLlxyXG4gICAgICAvLyBXaGljaCBvZiBjb3Vyc2UgY2F1c2VzIGEgbG90IG9mIGlzc3VlcyB3aXRoIHRoZSBldmVudCBzeXN0ZW0sXHJcbiAgICAgIC8vIGFuZCBwYWdlIGNvbnNpc3RlbmN5LlxyXG4gICAgICAvL1xyXG4gICAgICAvLyBOT1RFOlxyXG4gICAgICAvLyBPbmx5IHBhZ2Uuc2NyZWVuc2hvdCB3aWxsIHRocm93IHRoaXMsIHRpbWVvdXRzIGZvciBQREYncyBhcmVcclxuICAgICAgLy8gaGFuZGxlZCBieSB0aGUgcGFnZS5wZGYgZnVuY3Rpb24gaXRzZWxmLlxyXG4gICAgICAvL1xyXG4gICAgICAvLyAuLi55ZXMsIHRoaXMgaXMgdWdseS5cclxuICAgICAgaWYgKHJlc3VsdC5tZXNzYWdlID09PSAnUmFzdGVyaXphdGlvbiB0aW1lb3V0Jykge1xyXG4gICAgICAgIC8vIFNldCB0aGUgYHdvcmtMaW1pdGAgdG8gZXhjZWVkZWQgaW4gb3JkZXIgdG8gcmVjcmVhdGUgdGhlIHJlc291cmNlXHJcbiAgICAgICAgd29ya2VySGFuZGxlLndvcmtDb3VudCA9IG9wdGlvbnMucG9vbC53b3JrTGltaXQgKyAxO1xyXG4gICAgICAgIHdvcmtlckhhbmRsZS5wYWdlID0gbnVsbDtcclxuICAgICAgfVxyXG5cclxuICAgICAgaWYgKFxyXG4gICAgICAgIHJlc3VsdC5uYW1lID09PSAnVGltZW91dEVycm9yJyB8fFxyXG4gICAgICAgIHJlc3VsdC5tZXNzYWdlID09PSAnUmFzdGVyaXphdGlvbiB0aW1lb3V0J1xyXG4gICAgICApIHtcclxuICAgICAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoXHJcbiAgICAgICAgICBgW3Bvb2xdICR7XHJcbiAgICAgICAgICAgIG9wdGlvbnMucmVxdWVzdElkID8gYFJlcXVlc3QgWyR7b3B0aW9ucy5yZXF1ZXN0SWR9XSAtIGAgOiAnJ1xyXG4gICAgICAgICAgfVJhc3Rlcml6YXRpb24gdGltZW91dDogeW91ciBjaGFydCBtYXkgYmUgdG9vIGNvbXBsZXggb3IgbGFyZ2UsIGFuZCBmYWlsZWQgdG8gcmVuZGVyIHdpdGhpbiB0aGUgYWxsb3R0ZWQgdGltZS5gXHJcbiAgICAgICAgKS5zZXRFcnJvcihyZXN1bHQpO1xyXG4gICAgICB9IGVsc2Uge1xyXG4gICAgICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcihcclxuICAgICAgICAgIGBbcG9vbF0gJHtcclxuICAgICAgICAgICAgb3B0aW9ucy5yZXF1ZXN0SWQgPyBgUmVxdWVzdCBbJHtvcHRpb25zLnJlcXVlc3RJZH1dIC0gYCA6ICcnXHJcbiAgICAgICAgICB9RXJyb3IgZW5jb3VudGVyZWQgZHVyaW5nIGV4cG9ydDogJHtleHBvcnRDb3VudGVyKCl9bXMuYFxyXG4gICAgICAgICkuc2V0RXJyb3IocmVzdWx0KTtcclxuICAgICAgfVxyXG4gICAgfVxyXG5cclxuICAgIC8vIENoZWNrIHRoZSBQdXBwZXRlZXIgZXhwb3J0IHRpbWVcclxuICAgIGlmIChvcHRpb25zLnNlcnZlci5iZW5jaG1hcmtpbmcpIHtcclxuICAgICAgbG9nKFxyXG4gICAgICAgIDUsXHJcbiAgICAgICAgYFtiZW5jaG1hcmtdICR7b3B0aW9ucy5yZXF1ZXN0SWQgPyBgUmVxdWVzdCBbJHtvcHRpb25zLnJlcXVlc3RJZH1dIC0gYCA6ICcnfWAsXHJcbiAgICAgICAgYEV4cG9ydGluZyBhIGNoYXJ0IHN1Y2Vzc2Z1bGx5IHRvb2sgJHtleHBvcnRDb3VudGVyKCl9bXMuYFxyXG4gICAgICApO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIFJlbGVhc2UgdGhlIHJlc291cmNlIGJhY2sgdG8gdGhlIHBvb2xcclxuICAgIHBvb2wucmVsZWFzZSh3b3JrZXJIYW5kbGUpO1xyXG5cclxuICAgIC8vIFVzZWQgZm9yIHN0YXRpc3RpY3MgaW4gYXZlcmFnZVRpbWUgYW5kIHByb2Nlc3NlZFdvcmtDb3VudCwgd2hpY2hcclxuICAgIC8vIGluIHR1cm4gaXMgdXNlZCBieSB0aGUgL2hlYWx0aCByb3V0ZS5cclxuICAgIGNvbnN0IHdvcmtFbmQgPSBnZXROZXdEYXRlVGltZSgpO1xyXG4gICAgY29uc3QgZXhwb3J0VGltZSA9IHdvcmtFbmQgLSB3b3JrU3RhcnQ7XHJcblxyXG4gICAgcG9vbFN0YXRzLnRpbWVTcGVudCArPSBleHBvcnRUaW1lO1xyXG4gICAgcG9vbFN0YXRzLnRpbWVTcGVudEF2ZXJhZ2UgPVxyXG4gICAgICBwb29sU3RhdHMudGltZVNwZW50IC8gKytwb29sU3RhdHMuZXhwb3J0c1BlcmZvcm1lZDtcclxuXHJcbiAgICBsb2coNCwgYFtwb29sXSBXb3JrIGNvbXBsZXRlZCBpbiAke2V4cG9ydFRpbWV9bXMuYCk7XHJcblxyXG4gICAgLy8gT3RoZXJ3aXNlIHJldHVybiB0aGUgcmVzdWx0XHJcbiAgICByZXR1cm4ge1xyXG4gICAgICByZXN1bHQsXHJcbiAgICAgIG9wdGlvbnNcclxuICAgIH07XHJcbiAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICsrcG9vbFN0YXRzLmV4cG9ydHNEcm9wcGVkO1xyXG5cclxuICAgIGlmICh3b3JrZXJIYW5kbGUpIHtcclxuICAgICAgcG9vbC5yZWxlYXNlKHdvcmtlckhhbmRsZSk7XHJcbiAgICB9XHJcblxyXG4gICAgdGhyb3cgZXJyb3I7XHJcbiAgfVxyXG59XHJcblxyXG4vKipcclxuICogUmV0cmlldmVzIHRoZSBjdXJyZW50IHBvb2wgaW5zdGFuY2UuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBnZXRQb29sXHJcbiAqXHJcbiAqIEByZXR1cm5zIHsoT2JqZWN0fG51bGwpfSBUaGUgY3VycmVudCBwb29sIGluc3RhbmNlIGlmIGluaXRpYWxpemVkLCBvciBudWxsXHJcbiAqIGlmIHRoZSBwb29sIGhhcyBub3QgYmVlbiBjcmVhdGVkLlxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIGdldFBvb2woKSB7XHJcbiAgcmV0dXJuIHBvb2w7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBHZXRzIHRoZSBzdGF0aXN0aWMgb2YgYSBwb29sIGluc3RhY2UgYWJvdXQgZXhwb3J0cy5cclxuICpcclxuICogQGZ1bmN0aW9uIGdldFBvb2xTdGF0c1xyXG4gKlxyXG4gKiBAcmV0dXJucyB7T2JqZWN0fSBUaGUgY3VycmVudCBwb29sIHN0YXRpc3RpY3MuXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gZ2V0UG9vbFN0YXRzKCkge1xyXG4gIHJldHVybiBwb29sU3RhdHM7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBSZXRyaWV2ZXMgcG9vbCBpbmZvcm1hdGlvbiBpbiBKU09OIGZvcm1hdCwgaW5jbHVkaW5nIG1pbmltdW0gYW5kIG1heGltdW1cclxuICogd29ya2VycywgYXZhaWxhYmxlIHdvcmtlcnMsIHdvcmtlcnMgaW4gdXNlLCBhbmQgcGVuZGluZyBhY3F1aXJlIHJlcXVlc3RzLlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gZ2V0UG9vbEluZm9KU09OXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtPYmplY3R9IFBvb2wgaW5mb3JtYXRpb24gaW4gSlNPTiBmb3JtYXQuXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gZ2V0UG9vbEluZm9KU09OKCkge1xyXG4gIHJldHVybiB7XHJcbiAgICBtaW46IHBvb2wubWluLFxyXG4gICAgbWF4OiBwb29sLm1heCxcclxuICAgIHVzZWQ6IHBvb2wubnVtVXNlZCgpLFxyXG4gICAgYXZhaWxhYmxlOiBwb29sLm51bUZyZWUoKSxcclxuICAgIGFsbENyZWF0ZWQ6IHBvb2wubnVtVXNlZCgpICsgcG9vbC5udW1GcmVlKCksXHJcbiAgICBwZW5kaW5nQWNxdWlyZXM6IHBvb2wubnVtUGVuZGluZ0FjcXVpcmVzKCksXHJcbiAgICBwZW5kaW5nQ3JlYXRlczogcG9vbC5udW1QZW5kaW5nQ3JlYXRlcygpLFxyXG4gICAgcGVuZGluZ1ZhbGlkYXRpb25zOiBwb29sLm51bVBlbmRpbmdWYWxpZGF0aW9ucygpLFxyXG4gICAgcGVuZGluZ0Rlc3Ryb3lzOiBwb29sLnBlbmRpbmdEZXN0cm95cy5sZW5ndGgsXHJcbiAgICBhYnNvbHV0ZUFsbDpcclxuICAgICAgcG9vbC5udW1Vc2VkKCkgK1xyXG4gICAgICBwb29sLm51bUZyZWUoKSArXHJcbiAgICAgIHBvb2wubnVtUGVuZGluZ0FjcXVpcmVzKCkgK1xyXG4gICAgICBwb29sLm51bVBlbmRpbmdDcmVhdGVzKCkgK1xyXG4gICAgICBwb29sLm51bVBlbmRpbmdWYWxpZGF0aW9ucygpICtcclxuICAgICAgcG9vbC5wZW5kaW5nRGVzdHJveXMubGVuZ3RoXHJcbiAgfTtcclxufVxyXG5cclxuLyoqXHJcbiAqIExvZ3MgaW5mb3JtYXRpb24gYWJvdXQgdGhlIGN1cnJlbnQgc3RhdGUgb2YgdGhlIHBvb2wsIGluY2x1ZGluZyB0aGUgbWluaW11bVxyXG4gKiBhbmQgbWF4aW11bSB3b3JrZXJzLCBhdmFpbGFibGUgd29ya2Vycywgd29ya2VycyBpbiB1c2UsIGFuZCBwZW5kaW5nIGFjcXVpcmVcclxuICogcmVxdWVzdHMuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBnZXRQb29sSW5mb1xyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIGdldFBvb2xJbmZvKCkge1xyXG4gIGNvbnN0IHtcclxuICAgIG1pbixcclxuICAgIG1heCxcclxuICAgIHVzZWQsXHJcbiAgICBhdmFpbGFibGUsXHJcbiAgICBhbGxDcmVhdGVkLFxyXG4gICAgcGVuZGluZ0FjcXVpcmVzLFxyXG4gICAgcGVuZGluZ0NyZWF0ZXMsXHJcbiAgICBwZW5kaW5nVmFsaWRhdGlvbnMsXHJcbiAgICBwZW5kaW5nRGVzdHJveXMsXHJcbiAgICBhYnNvbHV0ZUFsbFxyXG4gIH0gPSBnZXRQb29sSW5mb0pTT04oKTtcclxuXHJcbiAgbG9nKDUsIGBbcG9vbF0gVGhlIG1pbmltdW0gbnVtYmVyIG9mIHJlc291cmNlcyBhbGxvd2VkIGJ5IHBvb2w6ICR7bWlufS5gKTtcclxuICBsb2coNSwgYFtwb29sXSBUaGUgbWF4aW11bSBudW1iZXIgb2YgcmVzb3VyY2VzIGFsbG93ZWQgYnkgcG9vbDogJHttYXh9LmApO1xyXG4gIGxvZyg1LCBgW3Bvb2xdIFRoZSBudW1iZXIgb2YgdXNlZCByZXNvdXJjZXM6ICR7dXNlZH0uYCk7XHJcbiAgbG9nKDUsIGBbcG9vbF0gVGhlIG51bWJlciBvZiBmcmVlIHJlc291cmNlczogJHthdmFpbGFibGV9LmApO1xyXG4gIGxvZyhcclxuICAgIDUsXHJcbiAgICBgW3Bvb2xdIFRoZSBudW1iZXIgb2YgYWxsIGNyZWF0ZWQgKHVzZWQgYW5kIGZyZWUpIHJlc291cmNlczogJHthbGxDcmVhdGVkfS5gXHJcbiAgKTtcclxuICBsb2coXHJcbiAgICA1LFxyXG4gICAgYFtwb29sXSBUaGUgbnVtYmVyIG9mIHJlc291cmNlcyB3YWl0aW5nIHRvIGJlIGFjcXVpcmVkOiAke3BlbmRpbmdBY3F1aXJlc30uYFxyXG4gICk7XHJcbiAgbG9nKFxyXG4gICAgNSxcclxuICAgIGBbcG9vbF0gVGhlIG51bWJlciBvZiByZXNvdXJjZXMgd2FpdGluZyB0byBiZSBjcmVhdGVkOiAke3BlbmRpbmdDcmVhdGVzfS5gXHJcbiAgKTtcclxuICBsb2coXHJcbiAgICA1LFxyXG4gICAgYFtwb29sXSBUaGUgbnVtYmVyIG9mIHJlc291cmNlcyB3YWl0aW5nIHRvIGJlIHZhbGlkYXRlZDogJHtwZW5kaW5nVmFsaWRhdGlvbnN9LmBcclxuICApO1xyXG4gIGxvZyhcclxuICAgIDUsXHJcbiAgICBgW3Bvb2xdIFRoZSBudW1iZXIgb2YgcmVzb3VyY2VzIHdhaXRpbmcgdG8gYmUgZGVzdHJveWVkOiAke3BlbmRpbmdEZXN0cm95c30uYFxyXG4gICk7XHJcbiAgbG9nKDUsIGBbcG9vbF0gVGhlIG51bWJlciBvZiBhbGwgcmVzb3VyY2VzOiAke2Fic29sdXRlQWxsfS5gKTtcclxufVxyXG5cclxuLyoqXHJcbiAqIEZhY3RvcnkgZnVuY3Rpb24gdGhhdCByZXR1cm5zIGFuIG9iamVjdCB3aXRoIGBjcmVhdGVgLCBgdmFsaWRhdGVgLFxyXG4gKiBhbmQgYGRlc3Ryb3lgIGZ1bmN0aW9ucyBmb3IgdGhlIHBvb2wgaW5zdGFuY2UuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBfZmFjdG9yeVxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gcG9vbE9wdGlvbnMgLSBUaGUgY29uZmlndXJhdGlvbiBvYmplY3QgY29udGFpbmluZyBgcG9vbGBcclxuICogb3B0aW9ucy5cclxuICovXHJcbmZ1bmN0aW9uIF9mYWN0b3J5KHBvb2xPcHRpb25zKSB7XHJcbiAgcmV0dXJuIHtcclxuICAgIC8qKlxyXG4gICAgICogQ3JlYXRlcyBhIG5ldyB3b3JrZXIgcGFnZSBmb3IgdGhlIGV4cG9ydCBwb29sLlxyXG4gICAgICpcclxuICAgICAqIEBhc3luY1xyXG4gICAgICogQGZ1bmN0aW9uIGNyZWF0ZVxyXG4gICAgICpcclxuICAgICAqIEByZXR1cm5zIHtQcm9taXNlPE9iamVjdD59IEEgUHJvbWlzZSB0aGF0IHJlc29sdmVzIHRvIGFuIG9iamVjdFxyXG4gICAgICogY29udGFpbmluZyB0aGUgd29ya2VyIElELCBhIHJlZmVyZW5jZSB0byB0aGUgYnJvd3NlciBwYWdlLCBhbmQgaW5pdGlhbFxyXG4gICAgICogd29yayBjb3VudC5cclxuICAgICAqXHJcbiAgICAgKiBAdGhyb3dzIHtFeHBvcnRFcnJvcn0gVGhyb3dzIGFuIGBFeHBvcnRFcnJvcmAgaWYgdGhlcmUgaXMgYW4gZXJyb3IgZHVyaW5nXHJcbiAgICAgKiB0aGUgY3JlYXRpb24gb2YgdGhlIG5ldyBwYWdlLlxyXG4gICAgICovXHJcbiAgICBjcmVhdGU6IGFzeW5jICgpID0+IHtcclxuICAgICAgLy8gSW5pdCB0aGUgcmVzb3VyY2Ugd2l0aCB1bmlxdWUgaWQgYW5kIHdvcmsgY291bnRcclxuICAgICAgY29uc3QgcG9vbFJlc291cmNlID0ge1xyXG4gICAgICAgIGlkOiB1dWlkKCksXHJcbiAgICAgICAgLy8gVHJ5IHRvIGRpc3RyaWJ1dGUgdGhlIGluaXRpYWwgd29yayBjb3VudFxyXG4gICAgICAgIHdvcmtDb3VudDogTWF0aC5yb3VuZChNYXRoLnJhbmRvbSgpICogKHBvb2xPcHRpb25zLndvcmtMaW1pdCAvIDIpKVxyXG4gICAgICB9O1xyXG5cclxuICAgICAgdHJ5IHtcclxuICAgICAgICAvLyBTdGFydCBtZWFzdXJpbmcgYSBwYWdlIGNyZWF0aW9uIHRpbWVcclxuICAgICAgICBjb25zdCBzdGFydERhdGUgPSBnZXROZXdEYXRlVGltZSgpO1xyXG5cclxuICAgICAgICAvLyBDcmVhdGUgYSBuZXcgcGFnZVxyXG4gICAgICAgIGF3YWl0IG5ld1BhZ2UocG9vbFJlc291cmNlKTtcclxuXHJcbiAgICAgICAgLy8gTWVhc3VyZSB0aGUgdGltZSBvZiBmdWxsIGNyZWF0aW9uIGFuZCBjb25maWd1cmF0aW9uIG9mIGEgcGFnZVxyXG4gICAgICAgIGxvZyhcclxuICAgICAgICAgIDMsXHJcbiAgICAgICAgICBgW3Bvb2xdIFBvb2wgcmVzb3VyY2UgWyR7cG9vbFJlc291cmNlLmlkfV0gLSBTdWNjZXNzZnVsbHkgY3JlYXRlZCBhIHdvcmtlciwgdG9vayAke1xyXG4gICAgICAgICAgICBnZXROZXdEYXRlVGltZSgpIC0gc3RhcnREYXRlXHJcbiAgICAgICAgICB9bXMuYFxyXG4gICAgICAgICk7XHJcblxyXG4gICAgICAgIC8vIFJldHVybiByZWFkeSBwb29sIHJlc291cmNlXHJcbiAgICAgICAgcmV0dXJuIHBvb2xSZXNvdXJjZTtcclxuICAgICAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICAgICBsb2coXHJcbiAgICAgICAgICAzLFxyXG4gICAgICAgICAgYFtwb29sXSBQb29sIHJlc291cmNlIFske3Bvb2xSZXNvdXJjZS5pZH1dIC0gRXJyb3IgZW5jb3VudGVyZWQgd2hlbiBjcmVhdGluZyBhIG5ldyBwYWdlLmBcclxuICAgICAgICApO1xyXG4gICAgICAgIHRocm93IGVycm9yO1xyXG4gICAgICB9XHJcbiAgICB9LFxyXG5cclxuICAgIC8qKlxyXG4gICAgICogVmFsaWRhdGVzIGEgd29ya2VyIHBhZ2UgaW4gdGhlIGV4cG9ydCBwb29sLCBjaGVja2luZyBpZiBpdCBoYXMgZXhjZWVkZWRcclxuICAgICAqIHRoZSB3b3JrIGxpbWl0LlxyXG4gICAgICpcclxuICAgICAqIEBhc3luY1xyXG4gICAgICogQGZ1bmN0aW9uIHZhbGlkYXRlXHJcbiAgICAgKlxyXG4gICAgICogQHBhcmFtIHtPYmplY3R9IHBvb2xSZXNvdXJjZSAtIFRoZSBoYW5kbGUgdG8gdGhlIHdvcmtlciwgY29udGFpbmluZ1xyXG4gICAgICogdGhlIHdvcmtlcidzIElELCBhIHJlZmVyZW5jZSB0byB0aGUgYnJvd3NlciBwYWdlLCBhbmQgd29yayBjb3VudC5cclxuICAgICAqXHJcbiAgICAgKiBAcmV0dXJucyB7UHJvbWlzZTxib29sZWFuPn0gQSBQcm9taXNlIHRoYXQgcmVzb2x2ZXMgdG8gdHJ1ZSBpZiB0aGUgd29ya2VyXHJcbiAgICAgKiBpcyB2YWxpZCBhbmQgd2l0aGluIHRoZSB3b3JrIGxpbWl0OyBvdGhlcndpc2UsIHRvIGZhbHNlLlxyXG4gICAgICovXHJcbiAgICB2YWxpZGF0ZTogYXN5bmMgKHBvb2xSZXNvdXJjZSkgPT4ge1xyXG4gICAgICAvLyBOT1RFOlxyXG4gICAgICAvLyBJbiBjZXJ0YWluIGNhc2VzIGFjcXVpcmluZyB0aHJvd3MgYSBUYXJnZXRDbG9zZUVycm9yLCB3aGljaCBtYXlcclxuICAgICAgLy8gYmUgY2F1c2VkIGJ5IHR3byB0aGluZ3M6XHJcbiAgICAgIC8vIC0gVGhlIHBhZ2UgaXMgY2xvc2VkIGFuZCBhdHRlbXB0ZWQgdG8gYmUgcmV1c2VkLlxyXG4gICAgICAvLyAtIExvc3QgY29udGFjdCB3aXRoIHRoZSBicm93c2VyLlxyXG4gICAgICAvL1xyXG4gICAgICAvLyBXaGF0IHdlJ3JlIHNlZWluZyBpbiBsb2dzIGlzIHRoYXQgc3VjY2Vzc2l2ZSBleHBvcnRzIHR5cGljYWxseVxyXG4gICAgICAvLyBzdWNjZWVkcywgYW5kIHRoZSBzZXJ2ZXIgcmVjb3ZlcnMsIGluZGljYXRpbmcgdGhhdCBpdCdzIGxpa2VseVxyXG4gICAgICAvLyB0aGUgZmlyc3QgY2FzZS4gVGhpcyBpcyBhbiBhdHRlbXB0IGF0IGFsbGlldmF0aW5nIHRoZSBpc3N1ZSBieVxyXG4gICAgICAvLyBzaW1wbHkgbm90IHZhbGlkYXRpbmcgdGhlIHdvcmtlciBpZiB0aGUgcGFnZSBpcyBudWxsIG9yIGNsb3NlZC5cclxuICAgICAgLy9cclxuICAgICAgLy8gVGhlIGFjdHVhbCByZXN1bHQgZnJvbSB3aGVuIHRoaXMgaGFwcGVuZWQsIHdhcyB0aGF0IGEgd29ya2VyIHdvdWxkXHJcbiAgICAgIC8vIGJlIGNvbXBsZXRlbHkgbG9ja2VkLCBzdG9wcGluZyBpdCBmcm9tIGJlaW5nIGFjcXVpcmVkIHVudGlsXHJcbiAgICAgIC8vIGl0cyB3b3JrIGNvdW50IHJlYWNoZWQgdGhlIGxpbWl0LlxyXG5cclxuICAgICAgLy8gQ2hlY2sgaWYgdGhlIGBwYWdlYCBpcyB2YWxpZFxyXG4gICAgICBpZiAoIXBvb2xSZXNvdXJjZS5wYWdlKSB7XHJcbiAgICAgICAgbG9nKFxyXG4gICAgICAgICAgMyxcclxuICAgICAgICAgIGBbcG9vbF0gUG9vbCByZXNvdXJjZSBbJHtwb29sUmVzb3VyY2UuaWR9XSAtIFZhbGlkYXRpb24gZmFpbGVkIChubyB2YWxpZCBwYWdlIGlzIGZvdW5kKS5gXHJcbiAgICAgICAgKTtcclxuICAgICAgICByZXR1cm4gZmFsc2U7XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIC8vIENoZWNrIGlmIHRoZSBgcGFnZWAgaXMgY2xvc2VkXHJcbiAgICAgIGlmIChwb29sUmVzb3VyY2UucGFnZS5pc0Nsb3NlZCgpKSB7XHJcbiAgICAgICAgbG9nKFxyXG4gICAgICAgICAgMyxcclxuICAgICAgICAgIGBbcG9vbF0gUG9vbCByZXNvdXJjZSBbJHtwb29sUmVzb3VyY2UuaWR9XSAtIFZhbGlkYXRpb24gZmFpbGVkIChwYWdlIGlzIGNsb3NlZCBvciBpbnZhbGlkKS5gXHJcbiAgICAgICAgKTtcclxuICAgICAgICByZXR1cm4gZmFsc2U7XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIC8vIENoZWNrIGlmIHRoZSBgbWFpbkZyYW1lYCBpcyBkZXRhY2hlZFxyXG4gICAgICBpZiAocG9vbFJlc291cmNlLnBhZ2UubWFpbkZyYW1lKCkuZGV0YWNoZWQpIHtcclxuICAgICAgICBsb2coXHJcbiAgICAgICAgICAzLFxyXG4gICAgICAgICAgYFtwb29sXSBQb29sIHJlc291cmNlIFske3Bvb2xSZXNvdXJjZS5pZH1dIC0gVmFsaWRhdGlvbiBmYWlsZWQgKHBhZ2UncyBmcmFtZSBpcyBkZXRhY2hlZCkuYFxyXG4gICAgICAgICk7XHJcbiAgICAgICAgcmV0dXJuIGZhbHNlO1xyXG4gICAgICB9XHJcblxyXG4gICAgICAvLyBDaGVjayBpZiB0aGUgYHdvcmtMaW1pdGAgaXMgZXhjZWVkZWRcclxuICAgICAgaWYgKFxyXG4gICAgICAgIHBvb2xPcHRpb25zLndvcmtMaW1pdCAmJlxyXG4gICAgICAgICsrcG9vbFJlc291cmNlLndvcmtDb3VudCA+IHBvb2xPcHRpb25zLndvcmtMaW1pdFxyXG4gICAgICApIHtcclxuICAgICAgICBsb2coXHJcbiAgICAgICAgICAzLFxyXG4gICAgICAgICAgYFtwb29sXSBQb29sIHJlc291cmNlIFske3Bvb2xSZXNvdXJjZS5pZH1dIC0gVmFsaWRhdGlvbiBmYWlsZWQgKGV4Y2VlZGVkIHRoZSAke3Bvb2xPcHRpb25zLndvcmtMaW1pdH0gd29ya3MgcGVyIHJlc291cmNlIGxpbWl0KS5gXHJcbiAgICAgICAgKTtcclxuICAgICAgICByZXR1cm4gZmFsc2U7XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIC8vIFRoZSBgcG9vbFJlc291cmNlYCBpcyB2YWxpZGF0ZWRcclxuICAgICAgcmV0dXJuIHRydWU7XHJcbiAgICB9LFxyXG5cclxuICAgIC8qKlxyXG4gICAgICogRGVzdHJveXMgYSB3b3JrZXIgZW50cnkgaW4gdGhlIGV4cG9ydCBwb29sLCBjbG9zaW5nIGl0cyBhc3NvY2lhdGVkIHBhZ2UuXHJcbiAgICAgKlxyXG4gICAgICogQGFzeW5jXHJcbiAgICAgKiBAZnVuY3Rpb24gZGVzdHJveVxyXG4gICAgICpcclxuICAgICAqIEBwYXJhbSB7T2JqZWN0fSBwb29sUmVzb3VyY2UgLSBUaGUgaGFuZGxlIHRvIHRoZSB3b3JrZXIsIGNvbnRhaW5pbmdcclxuICAgICAqIHRoZSB3b3JrZXIncyBJRCwgYSByZWZlcmVuY2UgdG8gdGhlIGJyb3dzZXIgcGFnZSwgYW5kIHdvcmsgY291bnQuXHJcbiAgICAgKi9cclxuICAgIGRlc3Ryb3k6IGFzeW5jIChwb29sUmVzb3VyY2UpID0+IHtcclxuICAgICAgbG9nKFxyXG4gICAgICAgIDMsXHJcbiAgICAgICAgYFtwb29sXSBQb29sIHJlc291cmNlIFske3Bvb2xSZXNvdXJjZS5pZH1dIC0gRGVzdHJveWluZyBhIHdvcmtlci5gXHJcbiAgICAgICk7XHJcblxyXG4gICAgICBpZiAocG9vbFJlc291cmNlLnBhZ2UgJiYgIXBvb2xSZXNvdXJjZS5wYWdlLmlzQ2xvc2VkKCkpIHtcclxuICAgICAgICB0cnkge1xyXG4gICAgICAgICAgLy8gUmVtb3ZlIGFsbCBhdHRhY2hlZCBldmVudCBsaXN0ZW5lcnMgZnJvbSB0aGUgcmVzb3VyY2VcclxuICAgICAgICAgIHBvb2xSZXNvdXJjZS5wYWdlLnJlbW92ZUFsbExpc3RlbmVycygncGFnZWVycm9yJyk7XHJcbiAgICAgICAgICBwb29sUmVzb3VyY2UucGFnZS5yZW1vdmVBbGxMaXN0ZW5lcnMoJ2NvbnNvbGUnKTtcclxuICAgICAgICAgIHBvb2xSZXNvdXJjZS5wYWdlLnJlbW92ZUFsbExpc3RlbmVycygnZnJhbWVkZXRhY2hlZCcpO1xyXG5cclxuICAgICAgICAgIC8vIFdlIG5lZWQgdG8gd2FpdCBhcm91bmQgZm9yIHRoaXNcclxuICAgICAgICAgIGF3YWl0IHBvb2xSZXNvdXJjZS5wYWdlLmNsb3NlKCk7XHJcbiAgICAgICAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICAgICAgIGxvZyhcclxuICAgICAgICAgICAgMyxcclxuICAgICAgICAgICAgYFtwb29sXSBQb29sIHJlc291cmNlIFske3Bvb2xSZXNvdXJjZS5pZH1dIC0gUGFnZSBjb3VsZCBub3QgYmUgY2xvc2VkIHVwb24gZGVzdHJveWluZy5gXHJcbiAgICAgICAgICApO1xyXG4gICAgICAgICAgdGhyb3cgZXJyb3I7XHJcbiAgICAgICAgfVxyXG4gICAgICB9XHJcbiAgICB9XHJcbiAgfTtcclxufVxyXG5cclxuZXhwb3J0IGRlZmF1bHQge1xyXG4gIGluaXRQb29sLFxyXG4gIGtpbGxQb29sLFxyXG4gIHBvc3RXb3JrLFxyXG4gIGdldFBvb2wsXHJcbiAgZ2V0UG9vbFN0YXRzLFxyXG4gIGdldFBvb2xJbmZvLFxyXG4gIGdldFBvb2xJbmZvSlNPTlxyXG59O1xyXG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxyXG5cclxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXHJcblxyXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNSwgSGlnaHNvZnRcclxuXHJcbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cclxuXHJcbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxyXG5cclxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxyXG5cclxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cclxuXHJcbi8qKlxyXG4gKiBAb3ZlcnZpZXcgVXNlZCB0byBzYW5pdGl6ZSB0aGUgc3RyaW5ncyBjb21pbmcgZnJvbSB0aGUgZXhwb3J0aW5nIG1vZHVsZVxyXG4gKiB0byBwcmV2ZW50IFhTUyBhdHRhY2tzICh3aXRoIHRoZSBET01QdXJpZnkgbGlicmFyeSkuXHJcbiAqL1xyXG5cclxuaW1wb3J0IERPTVB1cmlmeSBmcm9tICdkb21wdXJpZnknO1xyXG5pbXBvcnQgeyBKU0RPTSB9IGZyb20gJ2pzZG9tJztcclxuXHJcbi8qKlxyXG4gKiBTYW5pdGl6ZXMgYSBnaXZlbiBIVE1MIHN0cmluZyBieSByZW1vdmluZyA8c2NyaXB0PiB0YWdzLiBUaGlzIGZ1bmN0aW9uIHVzZXNcclxuICogYSByZWd1bGFyIGV4cHJlc3Npb24gdG8gZmluZCBhbmQgcmVtb3ZlIGFsbCBvY2N1cnJlbmNlcyBvZiA8c2NyaXB0Pjwvc2NyaXB0PlxyXG4gKiB0YWdzIGFuZCBhbnkgY29udGVudCB3aXRoaW4gdGhlbS5cclxuICpcclxuICogQGZ1bmN0aW9uIHNhbml0aXplXHJcbiAqXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSBpbnB1dCAtIFRoZSBIVE1MIHN0cmluZyB0byBiZSBzYW5pdGl6ZWQuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtzdHJpbmd9IFRoZSBzYW5pdGl6ZWQgSFRNTCBzdHJpbmcuXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gc2FuaXRpemUoaW5wdXQpIHtcclxuICAvLyBHZXQgdGhlIHZpcnR1YWwgRE9NXHJcbiAgY29uc3Qgd2luZG93ID0gbmV3IEpTRE9NKCcnKS53aW5kb3c7XHJcblxyXG4gIC8vIENyZWF0ZSBhIHB1cmlmeWluZyBpbnN0YW5jZVxyXG4gIGNvbnN0IHB1cmlmeSA9IERPTVB1cmlmeSh3aW5kb3cpO1xyXG5cclxuICAvLyBSZXR1cm4gc2FuaXRpemVkIGlucHV0XHJcbiAgcmV0dXJuIHB1cmlmeS5zYW5pdGl6ZShpbnB1dCwgeyBBRERfVEFHUzogWydmb3JlaWduT2JqZWN0J10gfSk7XHJcbn1cclxuXHJcbmV4cG9ydCBkZWZhdWx0IHtcclxuICBzYW5pdGl6ZVxyXG59O1xyXG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxyXG5cclxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXHJcblxyXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNSwgSGlnaHNvZnRcclxuXHJcbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cclxuXHJcbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxyXG5cclxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxyXG5cclxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cclxuXHJcbi8qKlxyXG4gKiBAb3ZlcnZpZXcgVGhpcyBtb2R1bGUgcHJvdmlkZXMgZnVuY3Rpb25zIHRvIHByZXBhcmUgZm9yIHRoZSBleHBvcnRpbmcgY2hhcnRzXHJcbiAqIGludG8gdmFyaW91cyBpbWFnZSBvdXRwdXQgZm9ybWF0cyBzdWNoIGFzIEpQRUcsIFBORywgUERGLCBhbmQgU1ZHcy5cclxuICogSXQgc3VwcG9ydHMgc2luZ2xlIGFuZCBiYXRjaCBleHBvcnQgb3BlcmF0aW9ucyBhbmQgYWxsb3dzIGN1c3RvbWl6YXRpb25cclxuICogdGhyb3VnaCBvcHRpb25zIHBhc3NlZCBmcm9tIGNvbmZpZ3VyYXRpb25zIG9yIEFQSXMuXHJcbiAqL1xyXG5cclxuaW1wb3J0IHsgcmVhZEZpbGVTeW5jLCB3cml0ZUZpbGVTeW5jIH0gZnJvbSAnZnMnO1xyXG5cclxuaW1wb3J0IHtcclxuICBnZXRPcHRpb25zLFxyXG4gIGlzQWxsb3dlZENvbmZpZyxcclxuICBtZXJnZU9wdGlvbnMsXHJcbiAgdmFsaWRhdGVPcHRpb24sXHJcbiAgdmFsaWRhdGVPcHRpb25zXHJcbn0gZnJvbSAnLi9jb25maWcuanMnO1xyXG5pbXBvcnQgeyBsb2csIGxvZ1dpdGhTdGFjayB9IGZyb20gJy4vbG9nZ2VyLmpzJztcclxuaW1wb3J0IHsgZ2V0UG9vbFN0YXRzLCBraWxsUG9vbCwgcG9zdFdvcmsgfSBmcm9tICcuL3Bvb2wuanMnO1xyXG5pbXBvcnQgeyBzYW5pdGl6ZSB9IGZyb20gJy4vc2FuaXRpemUuanMnO1xyXG5pbXBvcnQge1xyXG4gIGRlZXBDb3B5LFxyXG4gIGZpeENvbnN0cixcclxuICBmaXhPdXRmaWxlLFxyXG4gIGZpeFR5cGUsXHJcbiAgZ2V0QWJzb2x1dGVQYXRoLFxyXG4gIGdldEJhc2U2NCxcclxuICBpc09iamVjdCxcclxuICByb3VuZE51bWJlcixcclxuICB3cmFwQXJvdW5kXHJcbn0gZnJvbSAnLi91dGlscy5qcyc7XHJcblxyXG5pbXBvcnQgRXhwb3J0RXJyb3IgZnJvbSAnLi9lcnJvcnMvRXhwb3J0RXJyb3IuanMnO1xyXG5cclxuLy8gVGhlIGdsb2JhbCBmbGFnIGZvciB0aGUgY29kZSBleGVjdXRpb24gcGVybWlzc2lvblxyXG5sZXQgYWxsb3dDb2RlRXhlY3V0aW9uID0gZmFsc2U7XHJcblxyXG4vKipcclxuICogU3RhcnRzIGEgc2luZ2xlIGV4cG9ydCBwcm9jZXNzIGJhc2VkIG9uIHRoZSBzcGVjaWZpZWQgb3B0aW9ucyBhbmQgc2F2ZXNcclxuICogdGhlIHJlc3VsdGluZyBpbWFnZSB0byB0aGUgcHJvdmlkZWQgb3V0cHV0IGZpbGUuXHJcbiAqXHJcbiAqIEBhc3luY1xyXG4gKiBAZnVuY3Rpb24gc2luZ2xlRXhwb3J0XHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBvcHRpb25zIC0gVGhlIGBvcHRpb25zYCBvYmplY3QsIHdoaWNoIHNob3VsZCBpbmNsdWRlIHNldHRpbmdzXHJcbiAqIGZyb20gdGhlIGBleHBvcnRgIGFuZCBgY3VzdG9tTG9naWNgIHNlY3Rpb25zLiBJdCBjYW4gYmUgYSBwYXJ0aWFsIG9yIGNvbXBsZXRlXHJcbiAqIHNldCBvZiBvcHRpb25zIGZyb20gdGhlc2Ugc2VjdGlvbnMuIFRoZSBvYmplY3QgbXVzdCBjb250YWluIGF0IGxlYXN0IG9uZVxyXG4gKiBvZiB0aGUgZm9sbG93aW5nIGBleHBvcnRgIHByb3BlcnRpZXM6IGBpbmZpbGVgLCBgaW5zdHJgLCBgb3B0aW9uc2AsIG9yIGBzdmdgXHJcbiAqIHRvIGdlbmVyYXRlIGEgdmFsaWQgaW1hZ2UuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtQcm9taXNlPHZvaWQ+fSBBIFByb21pc2UgdGhhdCByZXNvbHZlcyBvbmNlIHRoZSBzaW5nbGUgZXhwb3J0XHJcbiAqIHByb2Nlc3MgaXMgY29tcGxldGVkLlxyXG4gKlxyXG4gKiBAdGhyb3dzIHtFeHBvcnRFcnJvcn0gVGhyb3dzIGFuIGBFeHBvcnRFcnJvcmAgaWYgYW4gZXJyb3Igb2NjdXJzIGR1cmluZ1xyXG4gKiB0aGUgc2luZ2xlIGV4cG9ydCBwcm9jZXNzLlxyXG4gKi9cclxuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIHNpbmdsZUV4cG9ydChvcHRpb25zKSB7XHJcbiAgLy8gQ2hlY2sgaWYgdGhlIGV4cG9ydCBtYWtlcyBzZW5zZVxyXG4gIGlmIChvcHRpb25zICYmIG9wdGlvbnMuZXhwb3J0KSB7XHJcbiAgICAvLyBWYWxpZGF0ZSBzaW5nbGUgZXhwb3J0IG9wdGlvbnNcclxuICAgIG9wdGlvbnMgPSB2YWxpZGF0ZU9wdGlvbnMob3B0aW9ucyk7XHJcblxyXG4gICAgLy8gUGVyZm9ybSBhbiBleHBvcnRcclxuICAgIGF3YWl0IHN0YXJ0RXhwb3J0KFxyXG4gICAgICB7IGV4cG9ydDogb3B0aW9ucy5leHBvcnQsIGN1c3RvbUxvZ2ljOiBvcHRpb25zLmN1c3RvbUxvZ2ljIH0sXHJcbiAgICAgIGFzeW5jIChlcnJvciwgZGF0YSkgPT4ge1xyXG4gICAgICAgIC8vIEV4aXQgcHJvY2VzcyB3aGVuIGVycm9yIGV4aXN0c1xyXG4gICAgICAgIGlmIChlcnJvcikge1xyXG4gICAgICAgICAgdGhyb3cgZXJyb3I7XHJcbiAgICAgICAgfVxyXG5cclxuICAgICAgICAvLyBHZXQgdGhlIGBiNjRgLCBgb3V0ZmlsZWAsIGFuZCBgdHlwZWAgZm9yIGEgY2hhcnRcclxuICAgICAgICBjb25zdCB7IGI2NCwgb3V0ZmlsZSwgdHlwZSB9ID0gZGF0YS5vcHRpb25zLmV4cG9ydDtcclxuXHJcbiAgICAgICAgLy8gU2F2ZSB0aGUgcmVzdWx0XHJcbiAgICAgICAgdHJ5IHtcclxuICAgICAgICAgIGlmIChiNjQpIHtcclxuICAgICAgICAgICAgLy8gQXMgYSBCYXNlNjQgc3RyaW5nIHRvIGEgdHh0IGZpbGVcclxuICAgICAgICAgICAgd3JpdGVGaWxlU3luYyhcclxuICAgICAgICAgICAgICBgJHtvdXRmaWxlLnNwbGl0KCcuJykuc2hpZnQoKSB8fCAnY2hhcnQnfS50eHRgLFxyXG4gICAgICAgICAgICAgIGdldEJhc2U2NChkYXRhLnJlc3VsdCwgdHlwZSlcclxuICAgICAgICAgICAgKTtcclxuICAgICAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgICAgIC8vIEFzIGEgY29ycmVjdCBpbWFnZSBmb3JtYXRcclxuICAgICAgICAgICAgd3JpdGVGaWxlU3luYyhcclxuICAgICAgICAgICAgICBvdXRmaWxlIHx8IGBjaGFydC4ke3R5cGV9YCxcclxuICAgICAgICAgICAgICB0eXBlICE9PSAnc3ZnJyA/IEJ1ZmZlci5mcm9tKGRhdGEucmVzdWx0LCAnYmFzZTY0JykgOiBkYXRhLnJlc3VsdFxyXG4gICAgICAgICAgICApO1xyXG4gICAgICAgICAgfVxyXG4gICAgICAgIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICAgICAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoXHJcbiAgICAgICAgICAgICdbY2hhcnRdIEVycm9yIHdoaWxlIHNhdmluZyBhIGNoYXJ0LicsXHJcbiAgICAgICAgICAgIDUwMFxyXG4gICAgICAgICAgKS5zZXRFcnJvcihlcnJvcik7XHJcbiAgICAgICAgfVxyXG5cclxuICAgICAgICAvLyBLaWxsIHBvb2wgYW5kIGNsb3NlIGJyb3dzZXIgYWZ0ZXIgZmluaXNoaW5nIHNpbmdsZSBleHBvcnRcclxuICAgICAgICBhd2FpdCBraWxsUG9vbCgpO1xyXG4gICAgICB9XHJcbiAgICApO1xyXG4gIH0gZWxzZSB7XHJcbiAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoXHJcbiAgICAgICdbY2hhcnRdIE5vIGV4cGVjdGVkIGBleHBvcnRgIG9wdGlvbnMgd2VyZSBmb3VuZC4gUGxlYXNlIHByb3ZpZGUgb25lIG9mIHRoZSBmb2xsb3dpbmcgb3B0aW9uczogYGluZmlsZWAsIGBpbnN0cmAsIGBvcHRpb25zYCwgb3IgYHN2Z2AgdG8gZ2VuZXJhdGUgYSB2YWxpZCBpbWFnZS4nLFxyXG4gICAgICA0MDBcclxuICAgICk7XHJcbiAgfVxyXG59XHJcblxyXG4vKipcclxuICogU3RhcnRzIGEgYmF0Y2ggZXhwb3J0IHByb2Nlc3MgZm9yIG11bHRpcGxlIGNoYXJ0cyBiYXNlZCBvbiBpbmZvcm1hdGlvblxyXG4gKiBwcm92aWRlZCBpbiB0aGUgYGJhdGNoYCBvcHRpb24uIFRoZSBgYmF0Y2hgIGlzIGEgc3RyaW5nIGluIHRoZSBmb2xsb3dpbmdcclxuICogZm9ybWF0OiBcImluZmlsZTEuanNvbj1vdXRmaWxlMS5wbmc7aW5maWxlMi5qc29uPW91dGZpbGUyLnBuZzsuLi5cIi4gUmVzdWx0c1xyXG4gKiBhcmUgc2F2ZWQgdG8gdGhlIHNwZWNpZmllZCBvdXRwdXQgZmlsZXMuXHJcbiAqXHJcbiAqIEBhc3luY1xyXG4gKiBAZnVuY3Rpb24gYmF0Y2hFeHBvcnRcclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IG9wdGlvbnMgLSBUaGUgYG9wdGlvbnNgIG9iamVjdCwgd2hpY2ggc2hvdWxkIGluY2x1ZGUgc2V0dGluZ3NcclxuICogZnJvbSB0aGUgYGV4cG9ydGAgYW5kIGBjdXN0b21Mb2dpY2Agc2VjdGlvbnMuIEl0IGNhbiBiZSBhIHBhcnRpYWwgb3IgY29tcGxldGVcclxuICogc2V0IG9mIG9wdGlvbnMgZnJvbSB0aGVzZSBzZWN0aW9ucy4gSXQgbXVzdCBjb250YWluIHRoZSBgYmF0Y2hgIG9wdGlvbiBmcm9tXHJcbiAqIHRoZSBgZXhwb3J0YCBzZWN0aW9uIHRvIGdlbmVyYXRlIHZhbGlkIGltYWdlcy5cclxuICpcclxuICogQHJldHVybnMge1Byb21pc2U8dm9pZD59IEEgUHJvbWlzZSB0aGF0IHJlc29sdmVzIG9uY2UgdGhlIGJhdGNoIGV4cG9ydFxyXG4gKiBwcm9jZXNzZXMgYXJlIGNvbXBsZXRlZC5cclxuICpcclxuICogQHRocm93cyB7RXhwb3J0RXJyb3J9IFRocm93cyBhbiBgRXhwb3J0RXJyb3JgIGlmIGFuIGVycm9yIG9jY3VycyBkdXJpbmdcclxuICogYW55IG9mIHRoZSBiYXRjaCBleHBvcnQgcHJvY2Vzcy5cclxuICovXHJcbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBiYXRjaEV4cG9ydChvcHRpb25zKSB7XHJcbiAgLy8gQ2hlY2sgaWYgdGhlIGV4cG9ydCBtYWtlcyBzZW5zZVxyXG4gIGlmIChvcHRpb25zICYmIG9wdGlvbnMuZXhwb3J0ICYmIG9wdGlvbnMuZXhwb3J0LmJhdGNoKSB7XHJcbiAgICAvLyBWYWxpZGF0ZSBiYXRjaCBleHBvcnQgb3B0aW9uc1xyXG4gICAgb3B0aW9ucyA9IHZhbGlkYXRlT3B0aW9ucyhvcHRpb25zKTtcclxuXHJcbiAgICAvLyBBbiBhcnJheSBmb3IgY29sbGVjdGluZyBiYXRjaCBleHBvcnRzXHJcbiAgICBjb25zdCBiYXRjaEZ1bmN0aW9ucyA9IFtdO1xyXG5cclxuICAgIC8vIFNwbGl0IGFuZCBwYWlyIHRoZSBgYmF0Y2hgIGFyZ3VtZW50c1xyXG4gICAgZm9yIChsZXQgcGFpciBvZiBvcHRpb25zLmV4cG9ydC5iYXRjaC5zcGxpdCgnOycpIHx8IFtdKSB7XHJcbiAgICAgIHBhaXIgPSBwYWlyLnNwbGl0KCc9Jyk7XHJcbiAgICAgIGlmIChwYWlyLmxlbmd0aCA9PT0gMikge1xyXG4gICAgICAgIGJhdGNoRnVuY3Rpb25zLnB1c2goXHJcbiAgICAgICAgICBzdGFydEV4cG9ydChcclxuICAgICAgICAgICAge1xyXG4gICAgICAgICAgICAgIGV4cG9ydDoge1xyXG4gICAgICAgICAgICAgICAgLi4ub3B0aW9ucy5leHBvcnQsXHJcbiAgICAgICAgICAgICAgICBpbmZpbGU6IHBhaXJbMF0sXHJcbiAgICAgICAgICAgICAgICBvdXRmaWxlOiBwYWlyWzFdXHJcbiAgICAgICAgICAgICAgfSxcclxuICAgICAgICAgICAgICBjdXN0b21Mb2dpYzogb3B0aW9ucy5jdXN0b21Mb2dpY1xyXG4gICAgICAgICAgICB9LFxyXG4gICAgICAgICAgICAoZXJyb3IsIGRhdGEpID0+IHtcclxuICAgICAgICAgICAgICAvLyBFeGl0IHByb2Nlc3Mgd2hlbiBlcnJvciBleGlzdHNcclxuICAgICAgICAgICAgICBpZiAoZXJyb3IpIHtcclxuICAgICAgICAgICAgICAgIHRocm93IGVycm9yO1xyXG4gICAgICAgICAgICAgIH1cclxuXHJcbiAgICAgICAgICAgICAgLy8gR2V0IHRoZSBgYjY0YCwgYG91dGZpbGVgLCBhbmQgYHR5cGVgIGZvciBhIGNoYXJ0XHJcbiAgICAgICAgICAgICAgY29uc3QgeyBiNjQsIG91dGZpbGUsIHR5cGUgfSA9IGRhdGEub3B0aW9ucy5leHBvcnQ7XHJcblxyXG4gICAgICAgICAgICAgIC8vIFNhdmUgdGhlIHJlc3VsdFxyXG4gICAgICAgICAgICAgIHRyeSB7XHJcbiAgICAgICAgICAgICAgICBpZiAoYjY0KSB7XHJcbiAgICAgICAgICAgICAgICAgIC8vIEFzIGEgQmFzZTY0IHN0cmluZyB0byBhIHR4dCBmaWxlXHJcbiAgICAgICAgICAgICAgICAgIHdyaXRlRmlsZVN5bmMoXHJcbiAgICAgICAgICAgICAgICAgICAgYCR7b3V0ZmlsZS5zcGxpdCgnLicpLnNoaWZ0KCkgfHwgJ2NoYXJ0J30udHh0YCxcclxuICAgICAgICAgICAgICAgICAgICBnZXRCYXNlNjQoZGF0YS5yZXN1bHQsIHR5cGUpXHJcbiAgICAgICAgICAgICAgICAgICk7XHJcbiAgICAgICAgICAgICAgICB9IGVsc2Uge1xyXG4gICAgICAgICAgICAgICAgICAvLyBBcyBhIGNvcnJlY3QgaW1hZ2UgZm9ybWF0XHJcbiAgICAgICAgICAgICAgICAgIHdyaXRlRmlsZVN5bmMoXHJcbiAgICAgICAgICAgICAgICAgICAgb3V0ZmlsZSxcclxuICAgICAgICAgICAgICAgICAgICB0eXBlICE9PSAnc3ZnJ1xyXG4gICAgICAgICAgICAgICAgICAgICAgPyBCdWZmZXIuZnJvbShkYXRhLnJlc3VsdCwgJ2Jhc2U2NCcpXHJcbiAgICAgICAgICAgICAgICAgICAgICA6IGRhdGEucmVzdWx0XHJcbiAgICAgICAgICAgICAgICAgICk7XHJcbiAgICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgICAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICAgICAgICAgICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcihcclxuICAgICAgICAgICAgICAgICAgJ1tjaGFydF0gRXJyb3Igd2hpbGUgc2F2aW5nIGEgY2hhcnQuJyxcclxuICAgICAgICAgICAgICAgICAgNTAwXHJcbiAgICAgICAgICAgICAgICApLnNldEVycm9yKGVycm9yKTtcclxuICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgIH1cclxuICAgICAgICAgIClcclxuICAgICAgICApO1xyXG4gICAgICB9IGVsc2Uge1xyXG4gICAgICAgIGxvZygyLCAnW2NoYXJ0XSBObyBjb3JyZWN0IHBhaXIgZm91bmQgZm9yIHRoZSBiYXRjaCBleHBvcnQuJyk7XHJcbiAgICAgIH1cclxuICAgIH1cclxuXHJcbiAgICAvLyBBd2FpdCBhbGwgZXhwb3J0cyBhcmUgZG9uZVxyXG4gICAgY29uc3QgYmF0Y2hSZXN1bHRzID0gYXdhaXQgUHJvbWlzZS5hbGxTZXR0bGVkKGJhdGNoRnVuY3Rpb25zKTtcclxuXHJcbiAgICAvLyBLaWxsIHBvb2wgYW5kIGNsb3NlIGJyb3dzZXIgYWZ0ZXIgZmluaXNoaW5nIGJhdGNoIGV4cG9ydFxyXG4gICAgYXdhaXQga2lsbFBvb2woKTtcclxuXHJcbiAgICAvLyBMb2cgZXJyb3JzIGlmIGZvdW5kXHJcbiAgICBiYXRjaFJlc3VsdHMuZm9yRWFjaCgocmVzdWx0LCBpbmRleCkgPT4ge1xyXG4gICAgICAvLyBMb2cgdGhlIGVycm9yIHdpdGggc3RhY2sgYWJvdXQgdGhlIHNwZWNpZmljIGJhdGNoIGV4cG9ydFxyXG4gICAgICBpZiAocmVzdWx0LnJlYXNvbikge1xyXG4gICAgICAgIGxvZ1dpdGhTdGFjayhcclxuICAgICAgICAgIDEsXHJcbiAgICAgICAgICByZXN1bHQucmVhc29uLFxyXG4gICAgICAgICAgYFtjaGFydF0gQmF0Y2ggZXhwb3J0IG51bWJlciAke2luZGV4ICsgMX0gY291bGQgbm90IGJlIGNvcnJlY3RseSBjb21wbGV0ZWQuYFxyXG4gICAgICAgICk7XHJcbiAgICAgIH1cclxuICAgIH0pO1xyXG4gIH0gZWxzZSB7XHJcbiAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoXHJcbiAgICAgICdbY2hhcnRdIE5vIGV4cGVjdGVkIGBleHBvcnRgIG9wdGlvbnMgd2VyZSBmb3VuZC4gUGxlYXNlIHByb3ZpZGUgdGhlIGBiYXRjaGAgb3B0aW9uIHRvIGdlbmVyYXRlIHZhbGlkIGltYWdlcy4nLFxyXG4gICAgICA0MDBcclxuICAgICk7XHJcbiAgfVxyXG59XHJcblxyXG4vKipcclxuICogU3RhcnRzIGFuIGV4cG9ydCBwcm9jZXNzLiBUaGUgYGV4cG9ydGluZ09wdGlvbnNgIHBhcmFtZXRlciBpcyBhbiBvYmplY3QgdGhhdFxyXG4gKiBzaG91bGQgaW5jbHVkZSBzZXR0aW5ncyBmcm9tIHRoZSBgZXhwb3J0YCBhbmQgYGN1c3RvbUxvZ2ljYCBzZWN0aW9ucy4gSXQgY2FuXHJcbiAqIGJlIGEgcGFydGlhbCBvciBjb21wbGV0ZSBzZXQgb2Ygb3B0aW9ucyBmcm9tIHRoZXNlIHNlY3Rpb25zLiBJZiBwYXJ0aWFsXHJcbiAqIG9wdGlvbnMgYXJlIHByb3ZpZGVkLCBtaXNzaW5nIHZhbHVlcyB3aWxsIGJlIG1lcmdlZCB3aXRoIHRoZSBjdXJyZW50IGdsb2JhbFxyXG4gKiBvcHRpb25zLlxyXG4gKlxyXG4gKiBUaGUgYGVuZENhbGxiYWNrYCBmdW5jdGlvbiBpcyBpbnZva2VkIHVwb24gdGhlIGNvbXBsZXRpb24gb2YgdGhlIGV4cG9ydCxcclxuICogZWl0aGVyIHN1Y2Nlc3NmdWxseSBvciB3aXRoIGFuIGVycm9yLiBUaGUgYGVycm9yYCBvYmplY3QgaXMgcHJvdmlkZWRcclxuICogYXMgdGhlIGZpcnN0IGFyZ3VtZW50LCBhbmQgdGhlIGBkYXRhYCBvYmplY3QgaXMgdGhlIHNlY29uZCwgY29udGFpbmluZ1xyXG4gKiB0aGUgQmFzZTY0IHJlcHJlc2VudGF0aW9uIG9mIHRoZSBjaGFydCBpbiB0aGUgYHJlc3VsdGAgcHJvcGVydHlcclxuICogYW5kIHRoZSBjb21wbGV0ZSBzZXQgb2Ygb3B0aW9ucyBpbiB0aGUgYG9wdGlvbnNgIHByb3BlcnR5LlxyXG4gKlxyXG4gKiBAYXN5bmNcclxuICogQGZ1bmN0aW9uIHN0YXJ0RXhwb3J0XHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBleHBvcnRpbmdPcHRpb25zIC0gVGhlIGBleHBvcnRpbmdPcHRpb25zYCBvYmplY3QsIHdoaWNoXHJcbiAqIHNob3VsZCBpbmNsdWRlIHNldHRpbmdzIGZyb20gdGhlIGBleHBvcnRgIGFuZCBgY3VzdG9tTG9naWNgIHNlY3Rpb25zLiBJdCBjYW5cclxuICogYmUgYSBwYXJ0aWFsIG9yIGNvbXBsZXRlIHNldCBvZiBvcHRpb25zIGZyb20gdGhlc2Ugc2VjdGlvbnMuIElmIHRoZSBwcm92aWRlZFxyXG4gKiBvcHRpb25zIGFyZSBwYXJ0aWFsLCBtaXNzaW5nIHZhbHVlcyB3aWxsIGJlIG1lcmdlZCB3aXRoIHRoZSBjdXJyZW50IGdsb2JhbFxyXG4gKiBvcHRpb25zLlxyXG4gKiBAcGFyYW0ge0Z1bmN0aW9ufSBlbmRDYWxsYmFjayAtIFRoZSBjYWxsYmFjayBmdW5jdGlvbiB0byBiZSBpbnZva2VkIHVwb25cclxuICogZmluYWxpemluZyB0aGUgZXhwb3J0IHByb2Nlc3Mgb3IgdXBvbiBlbmNvdW50ZXJpbmcgYW4gZXJyb3IuIFRoZSBmaXJzdFxyXG4gKiBhcmd1bWVudCBpcyB0aGUgYGVycm9yYCBvYmplY3QsIGFuZCB0aGUgc2Vjb25kIGFyZ3VtZW50IGlzIHRoZSBgZGF0YWAgb2JqZWN0LFxyXG4gKiB3aGljaCBpbmNsdWRlcyB0aGUgQmFzZTY0IHJlcHJlc2VudGF0aW9uIG9mIHRoZSBjaGFydCBpbiB0aGUgYHJlc3VsdGBcclxuICogcHJvcGVydHkgYW5kIHRoZSBmdWxsIHNldCBvZiBvcHRpb25zIGluIHRoZSBgb3B0aW9uc2AgcHJvcGVydHkuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtQcm9taXNlPHZvaWQ+fSBUaGlzIGZ1bmN0aW9uIGRvZXMgbm90IHJldHVybiBhIHZhbHVlIGRpcmVjdGx5LlxyXG4gKiBJbnN0ZWFkLCBpdCBjb21tdW5pY2F0ZXMgcmVzdWx0cyB2aWEgdGhlIGBlbmRDYWxsYmFja2AuXHJcbiAqXHJcbiAqIEB0aHJvd3Mge0V4cG9ydEVycm9yfSBUaHJvd3MgYW4gYEV4cG9ydEVycm9yYCBpZiB0aGVyZSBpcyBhIHByb2JsZW0gd2l0aFxyXG4gKiBwcm9jZXNzaW5nIGlucHV0IG9mIGFueSB0eXBlLiBUaGUgZXJyb3IgaXMgcGFzc2VkIGludG8gdGhlIGBlbmRDYWxsYmFja2BcclxuICogZnVuY3Rpb24gYW5kIHByb2Nlc3NlZCB0aGVyZS5cclxuICovXHJcbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBzdGFydEV4cG9ydChleHBvcnRpbmdPcHRpb25zLCBlbmRDYWxsYmFjaykge1xyXG4gIHRyeSB7XHJcbiAgICAvLyBDaGVjayBpZiBwcm92aWRlZCBvcHRpb25zIGlzIGFuIG9iamVjdFxyXG4gICAgaWYgKCFpc09iamVjdChleHBvcnRpbmdPcHRpb25zKSkge1xyXG4gICAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoXHJcbiAgICAgICAgJ1tjaGFydF0gSW5jb3JyZWN0IHZhbHVlIG9mIHRoZSBwcm92aWRlZCBgZXhwb3J0aW5nT3B0aW9uc2AuIE5lZWRzIHRvIGJlIGFuIG9iamVjdC4nLFxyXG4gICAgICAgIDQwMFxyXG4gICAgICApO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIE1lcmdlIGFkZGl0aW9uYWwgb3B0aW9ucyB0byB0aGUgY29weSBvZiB0aGUgaW5zdGFuY2Ugb3B0aW9uc1xyXG4gICAgY29uc3Qgb3B0aW9ucyA9IG1lcmdlT3B0aW9ucyhkZWVwQ29weShnZXRPcHRpb25zKCkpLCB7XHJcbiAgICAgIGV4cG9ydDogZXhwb3J0aW5nT3B0aW9ucy5leHBvcnQsXHJcbiAgICAgIGN1c3RvbUxvZ2ljOiBleHBvcnRpbmdPcHRpb25zLmN1c3RvbUxvZ2ljXHJcbiAgICB9KTtcclxuXHJcbiAgICAvLyBHZXQgdGhlIGBleHBvcnRgIG9wdGlvbnNcclxuICAgIGNvbnN0IGV4cG9ydE9wdGlvbnMgPSBvcHRpb25zLmV4cG9ydDtcclxuXHJcbiAgICAvLyBTdGFydGluZyBleHBvcnRpbmcgcHJvY2VzcyBtZXNzYWdlXHJcbiAgICBsb2coNCwgJ1tjaGFydF0gU3RhcnRpbmcgdGhlIGV4cG9ydGluZyBwcm9jZXNzLicpO1xyXG5cclxuICAgIC8vIEV4cG9ydCB1c2luZyBvcHRpb25zIGZyb20gdGhlIGZpbGUgYXMgYW4gaW5wdXRcclxuICAgIGlmIChleHBvcnRPcHRpb25zLmluZmlsZSAhPT0gbnVsbCkge1xyXG4gICAgICBsb2coNCwgJ1tjaGFydF0gQXR0ZW1wdGluZyB0byBleHBvcnQgZnJvbSBhIGZpbGUgaW5wdXQuJyk7XHJcblxyXG4gICAgICBsZXQgZmlsZUNvbnRlbnQ7XHJcbiAgICAgIHRyeSB7XHJcbiAgICAgICAgLy8gVHJ5IHRvIHJlYWQgdGhlIGZpbGUgdG8gZ2V0IHRoZSBzdHJpbmcgcmVwcmVzZW50YXRpb25cclxuICAgICAgICBmaWxlQ29udGVudCA9IHJlYWRGaWxlU3luYyhcclxuICAgICAgICAgIGdldEFic29sdXRlUGF0aChleHBvcnRPcHRpb25zLmluZmlsZSksXHJcbiAgICAgICAgICAndXRmOCdcclxuICAgICAgICApO1xyXG4gICAgICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcihcclxuICAgICAgICAgICdbY2hhcnRdIEVycm9yIGxvYWRpbmcgY29udGVudCBmcm9tIGEgZmlsZSBpbnB1dC4nLFxyXG4gICAgICAgICAgNDAwXHJcbiAgICAgICAgKS5zZXRFcnJvcihlcnJvcik7XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIC8vIENoZWNrIHRoZSBmaWxlJ3MgZXh0ZW5zaW9uXHJcbiAgICAgIGlmIChleHBvcnRPcHRpb25zLmluZmlsZS5lbmRzV2l0aCgnLnN2ZycpKSB7XHJcbiAgICAgICAgLy8gU2V0IHRvIHRoZSBgc3ZnYCBvcHRpb25cclxuICAgICAgICBleHBvcnRPcHRpb25zLnN2ZyA9IHZhbGlkYXRlT3B0aW9uKCdzdmcnLCBmaWxlQ29udGVudCk7XHJcbiAgICAgIH0gZWxzZSBpZiAoZXhwb3J0T3B0aW9ucy5pbmZpbGUuZW5kc1dpdGgoJy5qc29uJykpIHtcclxuICAgICAgICAvLyBTZXQgdG8gdGhlIGBpbnN0cmAgb3B0aW9uXHJcbiAgICAgICAgZXhwb3J0T3B0aW9ucy5pbnN0ciA9IHZhbGlkYXRlT3B0aW9uKCdpbnN0cicsIGZpbGVDb250ZW50KTtcclxuICAgICAgfSBlbHNlIHtcclxuICAgICAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoXHJcbiAgICAgICAgICAnW2NoYXJ0XSBJbmNvcnJlY3QgdmFsdWUgb2YgdGhlIGBpbmZpbGVgIG9wdGlvbi4nLFxyXG4gICAgICAgICAgNDAwXHJcbiAgICAgICAgKTtcclxuICAgICAgfVxyXG4gICAgfVxyXG5cclxuICAgIC8vIEV4cG9ydCB1c2luZyBTVkcgYXMgYW4gaW5wdXRcclxuICAgIGlmIChleHBvcnRPcHRpb25zLnN2ZyAhPT0gbnVsbCkge1xyXG4gICAgICBsb2coNCwgJ1tjaGFydF0gQXR0ZW1wdGluZyB0byBleHBvcnQgZnJvbSBhbiBTVkcgaW5wdXQuJyk7XHJcblxyXG4gICAgICAvLyBTVkcgZXhwb3J0cyBhdHRlbXB0cyBjb3VudGVyXHJcbiAgICAgICsrZ2V0UG9vbFN0YXRzKCkuZXhwb3J0c0Zyb21TdmdBdHRlbXB0cztcclxuXHJcbiAgICAgIC8vIEV4cG9ydCBmcm9tIGFuIFNWRyBzdHJpbmdcclxuICAgICAgY29uc3QgcmVzdWx0ID0gYXdhaXQgX2V4cG9ydEZyb21TdmcoXHJcbiAgICAgICAgc2FuaXRpemUoZXhwb3J0T3B0aW9ucy5zdmcpLCAvLyAjMjA5XHJcbiAgICAgICAgb3B0aW9uc1xyXG4gICAgICApO1xyXG5cclxuICAgICAgLy8gU1ZHIGV4cG9ydHMgY291bnRlclxyXG4gICAgICArK2dldFBvb2xTdGF0cygpLmV4cG9ydHNGcm9tU3ZnO1xyXG5cclxuICAgICAgLy8gUGFzcyBTVkcgZXhwb3J0IHJlc3VsdCB0byB0aGUgZW5kIGNhbGxiYWNrXHJcbiAgICAgIHJldHVybiBlbmRDYWxsYmFjayhudWxsLCByZXN1bHQpO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIEV4cG9ydCB1c2luZyBvcHRpb25zIGFzIGFuIGlucHV0XHJcbiAgICBpZiAoZXhwb3J0T3B0aW9ucy5pbnN0ciAhPT0gbnVsbCB8fCBleHBvcnRPcHRpb25zLm9wdGlvbnMgIT09IG51bGwpIHtcclxuICAgICAgbG9nKDQsICdbY2hhcnRdIEF0dGVtcHRpbmcgdG8gZXhwb3J0IGZyb20gb3B0aW9ucyBpbnB1dC4nKTtcclxuXHJcbiAgICAgIC8vIE9wdGlvbnMgZXhwb3J0cyBhdHRlbXB0cyBjb3VudGVyXHJcbiAgICAgICsrZ2V0UG9vbFN0YXRzKCkuZXhwb3J0c0Zyb21PcHRpb25zQXR0ZW1wdHM7XHJcblxyXG4gICAgICAvLyBFeHBvcnQgZnJvbSBvcHRpb25zXHJcbiAgICAgIGNvbnN0IHJlc3VsdCA9IGF3YWl0IF9leHBvcnRGcm9tT3B0aW9ucyhcclxuICAgICAgICBleHBvcnRPcHRpb25zLmluc3RyIHx8IGV4cG9ydE9wdGlvbnMub3B0aW9ucyxcclxuICAgICAgICBvcHRpb25zXHJcbiAgICAgICk7XHJcblxyXG4gICAgICAvLyBPcHRpb25zIGV4cG9ydHMgY291bnRlclxyXG4gICAgICArK2dldFBvb2xTdGF0cygpLmV4cG9ydHNGcm9tT3B0aW9ucztcclxuXHJcbiAgICAgIC8vIFBhc3Mgb3B0aW9ucyBleHBvcnQgcmVzdWx0IHRvIHRoZSBlbmQgY2FsbGJhY2tcclxuICAgICAgcmV0dXJuIGVuZENhbGxiYWNrKG51bGwsIHJlc3VsdCk7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gTm8gaW5wdXQgc3BlY2lmaWVkLCBwYXNzIGFuIGVycm9yIG1lc3NhZ2UgdG8gdGhlIGNhbGxiYWNrXHJcbiAgICByZXR1cm4gZW5kQ2FsbGJhY2soXHJcbiAgICAgIG5ldyBFeHBvcnRFcnJvcihcclxuICAgICAgICBgW2NoYXJ0XSBObyB2YWxpZCBpbnB1dCBzcGVjaWZpZWQuIENoZWNrIGlmIGF0IGxlYXN0IG9uZSBvZiB0aGUgZm9sbG93aW5nIHBhcmFtZXRlcnMgaXMgY29ycmVjdGx5IHNldDogJ2luZmlsZScsICdpbnN0cicsICdvcHRpb25zJywgb3IgJ3N2ZycuYCxcclxuICAgICAgICA0MDBcclxuICAgICAgKVxyXG4gICAgKTtcclxuICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgcmV0dXJuIGVuZENhbGxiYWNrKGVycm9yKTtcclxuICB9XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBSZXRyaWV2ZXMgYW5kIHJldHVybnMgdGhlIGN1cnJlbnQgc3RhdHVzIG9mIHRoZSBjb2RlIGV4ZWN1dGlvbiBwZXJtaXNzaW9uLlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gZ2V0QWxsb3dDb2RlRXhlY3V0aW9uXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtib29sZWFufSBUaGUgdmFsdWUgb2YgdGhlIGdsb2JhbCBgYWxsb3dDb2RlRXhlY3V0aW9uYCBvcHRpb24uXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gZ2V0QWxsb3dDb2RlRXhlY3V0aW9uKCkge1xyXG4gIHJldHVybiBhbGxvd0NvZGVFeGVjdXRpb247XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBTZXRzIHRoZSBjb2RlIGV4ZWN1dGlvbiBwZXJtaXNzaW9uIGJhc2VkIG9uIHRoZSBwcm92aWRlZCBib29sZWFuIHZhbHVlLlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gc2V0QWxsb3dDb2RlRXhlY3V0aW9uXHJcbiAqXHJcbiAqIEBwYXJhbSB7Ym9vbGVhbn0gdmFsdWUgLSBUaGUgYm9vbGVhbiB2YWx1ZSB0byBiZSBhc3NpZ25lZCB0byB0aGUgZ2xvYmFsXHJcbiAqIGBhbGxvd0NvZGVFeGVjdXRpb25gIG9wdGlvbi5cclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiBzZXRBbGxvd0NvZGVFeGVjdXRpb24odmFsdWUpIHtcclxuICBhbGxvd0NvZGVFeGVjdXRpb24gPSB2YWx1ZTtcclxufVxyXG5cclxuLyoqXHJcbiAqIEV4cG9ydHMgZnJvbSBhbiBTVkcgYmFzZWQgaW5wdXQgd2l0aCB0aGUgcHJvdmlkZWQgb3B0aW9ucy5cclxuICpcclxuICogQGFzeW5jXHJcbiAqIEBmdW5jdGlvbiBfZXhwb3J0RnJvbVN2Z1xyXG4gKlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gaW5wdXRUb0V4cG9ydCAtIFRoZSBTVkcgYmFzZWQgaW5wdXQgdG8gYmUgZXhwb3J0ZWQuXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBvcHRpb25zIC0gVGhlIGNvbmZpZ3VyYXRpb24gb2JqZWN0IGNvbnRhaW5pbmcgY29tcGxldGUgc2V0XHJcbiAqIG9mIG9wdGlvbnMuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtQcm9taXNlPHVua25vd24+fSBBIFByb21pc2UgdGhhdCByZXNvbHZlcyB0byBhIHJlc3VsdCBvZiB0aGUgZXhwb3J0XHJcbiAqIHByb2Nlc3MuXHJcbiAqXHJcbiAqIEB0aHJvd3Mge0V4cG9ydEVycm9yfSBUaHJvd3MgYW4gYEV4cG9ydEVycm9yYCBpZiB0aGVyZSBpcyBub3QgYSBjb3JyZWN0IFNWR1xyXG4gKiBpbnB1dC5cclxuICovXHJcbmFzeW5jIGZ1bmN0aW9uIF9leHBvcnRGcm9tU3ZnKGlucHV0VG9FeHBvcnQsIG9wdGlvbnMpIHtcclxuICAvLyBDaGVjayBpZiBpdCBpcyBTVkdcclxuICBpZiAoXHJcbiAgICB0eXBlb2YgaW5wdXRUb0V4cG9ydCA9PT0gJ3N0cmluZycgJiZcclxuICAgIChpbnB1dFRvRXhwb3J0LmluZGV4T2YoJzxzdmcnKSA+PSAwIHx8IGlucHV0VG9FeHBvcnQuaW5kZXhPZignPD94bWwnKSA+PSAwKVxyXG4gICkge1xyXG4gICAgbG9nKDQsICdbY2hhcnRdIFBhcnNpbmcgaW5wdXQgYXMgU1ZHLicpO1xyXG5cclxuICAgIC8vIFNldCB0aGUgZXhwb3J0IGlucHV0IGFzIFNWR1xyXG4gICAgb3B0aW9ucy5leHBvcnQuc3ZnID0gaW5wdXRUb0V4cG9ydDtcclxuXHJcbiAgICAvLyBSZXNldCB0aGUgcmVzdCBvZiB0aGUgZXhwb3J0IGlucHV0IG9wdGlvbnNcclxuICAgIG9wdGlvbnMuZXhwb3J0Lmluc3RyID0gbnVsbDtcclxuICAgIG9wdGlvbnMuZXhwb3J0Lm9wdGlvbnMgPSBudWxsO1xyXG5cclxuICAgIC8vIENhbGwgdGhlIGZ1bmN0aW9uIHdpdGggYW4gU1ZHIHN0cmluZyBhcyBhbiBleHBvcnQgaW5wdXRcclxuICAgIHJldHVybiBfcHJlcGFyZUV4cG9ydChvcHRpb25zKTtcclxuICB9IGVsc2Uge1xyXG4gICAgdGhyb3cgbmV3IEV4cG9ydEVycm9yKCdbY2hhcnRdIE5vdCBhIGNvcnJlY3QgU1ZHIGlucHV0LicsIDQwMCk7XHJcbiAgfVxyXG59XHJcblxyXG4vKipcclxuICogRXhwb3J0cyBmcm9tIGFuIG9wdGlvbnMgYmFzZWQgaW5wdXQgd2l0aCB0aGUgcHJvdmlkZWQgb3B0aW9ucy5cclxuICpcclxuICogQGFzeW5jXHJcbiAqIEBmdW5jdGlvbiBfZXhwb3J0RnJvbU9wdGlvbnNcclxuICpcclxuICogQHBhcmFtIHtzdHJpbmd9IGlucHV0VG9FeHBvcnQgLSBUaGUgb3B0aW9ucyBiYXNlZCBpbnB1dCB0byBiZSBleHBvcnRlZC5cclxuICogQHBhcmFtIHtPYmplY3R9IG9wdGlvbnMgLSBUaGUgY29uZmlndXJhdGlvbiBvYmplY3QgY29udGFpbmluZyBjb21wbGV0ZSBzZXRcclxuICogb2Ygb3B0aW9ucy5cclxuICpcclxuICogQHJldHVybnMge1Byb21pc2U8dW5rbm93bj59IEEgUHJvbWlzZSB0aGF0IHJlc29sdmVzIHRvIGEgcmVzdWx0IG9mIHRoZSBleHBvcnRcclxuICogcHJvY2Vzcy5cclxuICpcclxuICogQHRocm93cyB7RXhwb3J0RXJyb3J9IFRocm93cyBhbiBgRXhwb3J0RXJyb3JgIGlmIHRoZXJlIGlzIG5vdCBhIGNvcnJlY3RcclxuICogY2hhcnQgb3B0aW9ucyBpbnB1dC5cclxuICovXHJcbmFzeW5jIGZ1bmN0aW9uIF9leHBvcnRGcm9tT3B0aW9ucyhpbnB1dFRvRXhwb3J0LCBvcHRpb25zKSB7XHJcbiAgbG9nKDQsICdbY2hhcnRdIFBhcnNpbmcgaW5wdXQgZnJvbSBvcHRpb25zLicpO1xyXG5cclxuICAvLyBUcnkgdG8gY2hlY2ssIHZhbGlkYXRlIGFuZCBwYXJzZSB0byBzdHJpbmdpZmllZCBvcHRpb25zXHJcbiAgY29uc3Qgc3RyaW5naWZpZWRPcHRpb25zID0gaXNBbGxvd2VkQ29uZmlnKFxyXG4gICAgaW5wdXRUb0V4cG9ydCxcclxuICAgIHRydWUsXHJcbiAgICBvcHRpb25zLmN1c3RvbUxvZ2ljLmFsbG93Q29kZUV4ZWN1dGlvblxyXG4gICk7XHJcblxyXG4gIC8vIENoZWNrIGlmIGEgY29ycmVjdCBzdHJpbmdpZmllZCBvcHRpb25zXHJcbiAgaWYgKFxyXG4gICAgc3RyaW5naWZpZWRPcHRpb25zID09PSBudWxsIHx8XHJcbiAgICB0eXBlb2Ygc3RyaW5naWZpZWRPcHRpb25zICE9PSAnc3RyaW5nJyB8fFxyXG4gICAgIXN0cmluZ2lmaWVkT3B0aW9ucy5zdGFydHNXaXRoKCd7JykgfHxcclxuICAgICFzdHJpbmdpZmllZE9wdGlvbnMuZW5kc1dpdGgoJ30nKVxyXG4gICkge1xyXG4gICAgdGhyb3cgbmV3IEV4cG9ydEVycm9yKFxyXG4gICAgICAnW2NoYXJ0XSBJbnZhbGlkIGNvbmZpZ3VyYXRpb24gcHJvdmlkZWQgLSBPbmx5IG9wdGlvbnMgY29uZmlndXJhdGlvbnMgYW5kIFNWRyBhcmUgYWxsb3dlZCBmb3IgdGhpcyBzZXJ2ZXIuIElmIHRoaXMgaXMgeW91ciBzZXJ2ZXIsIEphdmFTY3JpcHQgY3VzdG9tIGNvZGUgY2FuIGJlIGVuYWJsZWQgYnkgc3RhcnRpbmcgdGhlIHNlcnZlciB3aXRoIHRoZSBgYWxsb3dDb2RlRXhlY3V0aW9uYCBvcHRpb25zIHNldCB0byB0cnVlLicsXHJcbiAgICAgIDQwM1xyXG4gICAgKTtcclxuICB9XHJcblxyXG4gIC8vIFNldCB0aGUgZXhwb3J0IGlucHV0IGFzIGEgc3RyaW5naWZpZWQgY2hhcnQgb3B0aW9uc1xyXG4gIG9wdGlvbnMuZXhwb3J0Lmluc3RyID0gc3RyaW5naWZpZWRPcHRpb25zO1xyXG5cclxuICAvLyBSZXNldCB0aGUgcmVzdCBvZiB0aGUgZXhwb3J0IGlucHV0IG9wdGlvbnNcclxuICBvcHRpb25zLmV4cG9ydC5zdmcgPSBudWxsO1xyXG5cclxuICAvLyBDYWxsIHRoZSBmdW5jdGlvbiB3aXRoIGEgc3RyaW5naWZpZWQgY2hhcnQgb3B0aW9uc1xyXG4gIHJldHVybiBfcHJlcGFyZUV4cG9ydChvcHRpb25zKTtcclxufVxyXG5cclxuLyoqXHJcbiAqIEZ1bmN0aW9uIGZvciBmaW5hbGl6aW5nIG9wdGlvbnMgYW5kIGNvbmZpZ3VyYXRpb25zIGJlZm9yZSBleHBvcnQuXHJcbiAqXHJcbiAqIEBhc3luY1xyXG4gKiBAZnVuY3Rpb24gX3ByZXBhcmVFeHBvcnRcclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IG9wdGlvbnMgLSBUaGUgY29uZmlndXJhdGlvbiBvYmplY3QgY29udGFpbmluZyBjb21wbGV0ZSBzZXRcclxuICogb2Ygb3B0aW9ucy5cclxuICpcclxuICogQHJldHVybnMge1Byb21pc2U8dW5rbm93bj59IEEgUHJvbWlzZSB0aGF0IHJlc29sdmVzIHRvIGEgcmVzdWx0IG9mIHRoZSBleHBvcnRcclxuICogcHJvY2Vzcy5cclxuICovXHJcbmFzeW5jIGZ1bmN0aW9uIF9wcmVwYXJlRXhwb3J0KG9wdGlvbnMpIHtcclxuICBjb25zdCB7IGV4cG9ydDogZXhwb3J0T3B0aW9ucywgY3VzdG9tTG9naWM6IGN1c3RvbUxvZ2ljT3B0aW9ucyB9ID0gb3B0aW9ucztcclxuXHJcbiAgLy8gUHJlcGFyZSB0aGUgYHR5cGVgIG9wdGlvblxyXG4gIGV4cG9ydE9wdGlvbnMudHlwZSA9IGZpeFR5cGUoZXhwb3J0T3B0aW9ucy50eXBlLCBleHBvcnRPcHRpb25zLm91dGZpbGUpO1xyXG5cclxuICAvLyBQcmVwYXJlIHRoZSBgb3V0ZmlsZWAgb3B0aW9uXHJcbiAgZXhwb3J0T3B0aW9ucy5vdXRmaWxlID0gZml4T3V0ZmlsZShleHBvcnRPcHRpb25zLnR5cGUsIGV4cG9ydE9wdGlvbnMub3V0ZmlsZSk7XHJcblxyXG4gIC8vIFByZXBhcmUgdGhlIGBjb25zdHJgIG9wdGlvblxyXG4gIGV4cG9ydE9wdGlvbnMuY29uc3RyID0gZml4Q29uc3RyKGV4cG9ydE9wdGlvbnMuY29uc3RyKTtcclxuXHJcbiAgLy8gTm90aWZ5IGFib3V0IHRoZSBjdXN0b20gbG9naWMgdXNhZ2Ugc3RhdHVzXHJcbiAgbG9nKFxyXG4gICAgMyxcclxuICAgIGBbY2hhcnRdIFRoZSBjdXN0b20gbG9naWMgaXMgJHtjdXN0b21Mb2dpY09wdGlvbnMuYWxsb3dDb2RlRXhlY3V0aW9uID8gJ2FsbG93ZWQnIDogJ2Rpc2FsbG93ZWQnfS5gXHJcbiAgKTtcclxuXHJcbiAgLy8gUHJlcGFyZSB0aGUgY3VzdG9tIGxvZ2ljIG9wdGlvbnMgKGBjdXN0b21Db2RlYCwgYGNhbGxiYWNrYCwgYHJlc291cmNlc2ApXHJcbiAgX2hhbmRsZUN1c3RvbUxvZ2ljKGN1c3RvbUxvZ2ljT3B0aW9ucywgY3VzdG9tTG9naWNPcHRpb25zLmFsbG93Q29kZUV4ZWN1dGlvbik7XHJcblxyXG4gIC8vIFByZXBhcmUgdGhlIGBnbG9iYWxPcHRpb25zYCBhbmQgYHRoZW1lT3B0aW9uc2Agb3B0aW9uc1xyXG4gIF9oYW5kbGVHbG9iYWxBbmRUaGVtZShcclxuICAgIGV4cG9ydE9wdGlvbnMsXHJcbiAgICBjdXN0b21Mb2dpY09wdGlvbnMuYWxsb3dGaWxlUmVzb3VyY2VzLFxyXG4gICAgY3VzdG9tTG9naWNPcHRpb25zLmFsbG93Q29kZUV4ZWN1dGlvblxyXG4gICk7XHJcblxyXG4gIC8vIFByZXBhcmUgdGhlIGBoZWlnaHRgLCBgd2lkdGhgLCBhbmQgYHNjYWxlYCBvcHRpb25zXHJcbiAgb3B0aW9ucy5leHBvcnQgPSB7XHJcbiAgICAuLi5leHBvcnRPcHRpb25zLFxyXG4gICAgLi4uX2ZpbmRDaGFydFNpemUoZXhwb3J0T3B0aW9ucylcclxuICB9O1xyXG5cclxuICAvLyBQb3N0IHRoZSB3b3JrIHRvIHRoZSBwb29sXHJcbiAgcmV0dXJuIHBvc3RXb3JrKG9wdGlvbnMpO1xyXG59XHJcblxyXG4vKipcclxuICogQ2FsY3VsYXRlcyB0aGUgYGhlaWdodGAsIGB3aWR0aGAgYW5kIGBzY2FsZWAgZm9yIGNoYXJ0IGV4cG9ydHMgYmFzZWRcclxuICogb24gdGhlIHByb3ZpZGVkIGV4cG9ydCBvcHRpb25zLlxyXG4gKlxyXG4gKiBUaGUgZnVuY3Rpb24gcHJpb3JpdGl6ZXMgdmFsdWVzIGluIHRoZSBmb2xsb3dpbmcgb3JkZXI6XHJcbiAqIDEuIFRoZSBgaGVpZ2h0YCwgYHdpZHRoYCwgYHNjYWxlYCBmcm9tIHRoZSBgZXhwb3J0T3B0aW9uc2AuXHJcbiAqIDIuIE9wdGlvbnMgZnJvbSB0aGUgY2hhcnQgY29uZmlndXJhdGlvbiAoZnJvbSBgZXhwb3J0aW5nYCBhbmQgYGNoYXJ0YCkuXHJcbiAqIDMuIE9wdGlvbnMgZnJvbSB0aGUgZ2xvYmFsIG9wdGlvbnMgKGZyb20gYGV4cG9ydGluZ2AgYW5kIGBjaGFydGApLlxyXG4gKiA0LiBPcHRpb25zIGZyb20gdGhlIHRoZW1lIG9wdGlvbnMgKGZyb20gYGV4cG9ydGluZ2AgYW5kIGBjaGFydGAgc2VjdGlvbnMpLlxyXG4gKiA1LiBGYWxsYmFjayBkZWZhdWx0IHZhbHVlcyAoYGhlaWdodCA9IDQwMGAsIGB3aWR0aCA9IDYwMGAsIGBzY2FsZSA9IDFgKS5cclxuICpcclxuICogQGZ1bmN0aW9uIF9maW5kQ2hhcnRTaXplXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBleHBvcnRPcHRpb25zIC0gVGhlIGNvbmZpZ3VyYXRpb24gb2JqZWN0IGNvbnRhaW5pbmcgYGV4cG9ydGBcclxuICogb3B0aW9ucy5cclxuICpcclxuICogQHJldHVybnMge09iamVjdH0gVGhlIG9iamVjdCBjb250YWluaW5nIGNhbGN1bGF0ZWQgYGhlaWdodGAsIGB3aWR0aGBcclxuICogYW5kIGBzY2FsZWAgdmFsdWVzIGZvciB0aGUgY2hhcnQgZXhwb3J0LlxyXG4gKi9cclxuZnVuY3Rpb24gX2ZpbmRDaGFydFNpemUoZXhwb3J0T3B0aW9ucykge1xyXG4gIC8vIENoZWNrIHRoZSBgb3B0aW9uc2AgYW5kIGBpbnN0cmAgZm9yIGNoYXJ0IGFuZCBleHBvcnRpbmcgc2VjdGlvbnNcclxuICBjb25zdCB7IGNoYXJ0OiBvcHRpb25zQ2hhcnQsIGV4cG9ydGluZzogb3B0aW9uc0V4cG9ydGluZyB9ID1cclxuICAgIGV4cG9ydE9wdGlvbnMub3B0aW9ucyB8fCBpc0FsbG93ZWRDb25maWcoZXhwb3J0T3B0aW9ucy5pbnN0cikgfHwgZmFsc2U7XHJcblxyXG4gIC8vIENoZWNrIHRoZSBgZ2xvYmFsT3B0aW9uc2AgZm9yIGNoYXJ0IGFuZCBleHBvcnRpbmcgc2VjdGlvbnNcclxuICBjb25zdCB7IGNoYXJ0OiBnbG9iYWxPcHRpb25zQ2hhcnQsIGV4cG9ydGluZzogZ2xvYmFsT3B0aW9uc0V4cG9ydGluZyB9ID1cclxuICAgIGlzQWxsb3dlZENvbmZpZyhleHBvcnRPcHRpb25zLmdsb2JhbE9wdGlvbnMpIHx8IGZhbHNlO1xyXG5cclxuICAvLyBDaGVjayB0aGUgYHRoZW1lT3B0aW9uc2AgZm9yIGNoYXJ0IGFuZCBleHBvcnRpbmcgc2VjdGlvbnNcclxuICBjb25zdCB7IGNoYXJ0OiB0aGVtZU9wdGlvbnNDaGFydCwgZXhwb3J0aW5nOiB0aGVtZU9wdGlvbnNFeHBvcnRpbmcgfSA9XHJcbiAgICBpc0FsbG93ZWRDb25maWcoZXhwb3J0T3B0aW9ucy50aGVtZU9wdGlvbnMpIHx8IGZhbHNlO1xyXG5cclxuICAvLyBGaW5kIHRoZSBgc2NhbGVgIHZhbHVlOlxyXG4gIC8vIC0gSXQgY2Fubm90IGJlIGxvd2VyIHRoYW4gMC4xXHJcbiAgLy8gLSBJdCBjYW5ub3QgYmUgaGlnaGVyIHRoYW4gNS4wXHJcbiAgLy8gLSBJdCBtdXN0IGJlIHJvdW5kZWQgdG8gMiBkZWNpbWFsIHBsYWNlcyAoZS5nLiAwLjIzMjM0IC0+IDAuMjMpXHJcbiAgY29uc3Qgc2NhbGUgPSByb3VuZE51bWJlcihcclxuICAgIE1hdGgubWF4KFxyXG4gICAgICAwLjEsXHJcbiAgICAgIE1hdGgubWluKFxyXG4gICAgICAgIGV4cG9ydE9wdGlvbnMuc2NhbGUgfHxcclxuICAgICAgICAgIG9wdGlvbnNFeHBvcnRpbmc/LnNjYWxlIHx8XHJcbiAgICAgICAgICBnbG9iYWxPcHRpb25zRXhwb3J0aW5nPy5zY2FsZSB8fFxyXG4gICAgICAgICAgdGhlbWVPcHRpb25zRXhwb3J0aW5nPy5zY2FsZSB8fFxyXG4gICAgICAgICAgZXhwb3J0T3B0aW9ucy5kZWZhdWx0U2NhbGUgfHxcclxuICAgICAgICAgIDEsXHJcbiAgICAgICAgNS4wXHJcbiAgICAgIClcclxuICAgICksXHJcbiAgICAyXHJcbiAgKTtcclxuXHJcbiAgLy8gRmluZCB0aGUgYGhlaWdodGAgdmFsdWVcclxuICBjb25zdCBoZWlnaHQgPVxyXG4gICAgZXhwb3J0T3B0aW9ucy5oZWlnaHQgfHxcclxuICAgIG9wdGlvbnNFeHBvcnRpbmc/LnNvdXJjZUhlaWdodCB8fFxyXG4gICAgb3B0aW9uc0NoYXJ0Py5oZWlnaHQgfHxcclxuICAgIGdsb2JhbE9wdGlvbnNFeHBvcnRpbmc/LnNvdXJjZUhlaWdodCB8fFxyXG4gICAgZ2xvYmFsT3B0aW9uc0NoYXJ0Py5oZWlnaHQgfHxcclxuICAgIHRoZW1lT3B0aW9uc0V4cG9ydGluZz8uc291cmNlSGVpZ2h0IHx8XHJcbiAgICB0aGVtZU9wdGlvbnNDaGFydD8uaGVpZ2h0IHx8XHJcbiAgICBleHBvcnRPcHRpb25zLmRlZmF1bHRIZWlnaHQgfHxcclxuICAgIDQwMDtcclxuXHJcbiAgLy8gRmluZCB0aGUgYHdpZHRoYCB2YWx1ZVxyXG4gIGNvbnN0IHdpZHRoID1cclxuICAgIGV4cG9ydE9wdGlvbnMud2lkdGggfHxcclxuICAgIG9wdGlvbnNFeHBvcnRpbmc/LnNvdXJjZVdpZHRoIHx8XHJcbiAgICBvcHRpb25zQ2hhcnQ/LndpZHRoIHx8XHJcbiAgICBnbG9iYWxPcHRpb25zRXhwb3J0aW5nPy5zb3VyY2VXaWR0aCB8fFxyXG4gICAgZ2xvYmFsT3B0aW9uc0NoYXJ0Py53aWR0aCB8fFxyXG4gICAgdGhlbWVPcHRpb25zRXhwb3J0aW5nPy5zb3VyY2VXaWR0aCB8fFxyXG4gICAgdGhlbWVPcHRpb25zQ2hhcnQ/LndpZHRoIHx8XHJcbiAgICBleHBvcnRPcHRpb25zLmRlZmF1bHRXaWR0aCB8fFxyXG4gICAgNjAwO1xyXG5cclxuICAvLyBHYXRoZXIgYGhlaWdodGAsIGB3aWR0aGAgYW5kIGBzY2FsZWAgaW5mb3JtYXRpb24gaW4gb25lIG9iamVjdFxyXG4gIGNvbnN0IHNpemUgPSB7IGhlaWdodCwgd2lkdGgsIHNjYWxlIH07XHJcblxyXG4gIC8vIEdldCByaWQgb2YgcG90ZW50aWFsIGBweGAgYW5kIGAlYFxyXG4gIGZvciAobGV0IFtwYXJhbSwgdmFsdWVdIG9mIE9iamVjdC5lbnRyaWVzKHNpemUpKSB7XHJcbiAgICBzaXplW3BhcmFtXSA9XHJcbiAgICAgIHR5cGVvZiB2YWx1ZSA9PT0gJ3N0cmluZycgPyArdmFsdWUucmVwbGFjZSgvcHh8JS9naSwgJycpIDogdmFsdWU7XHJcbiAgfVxyXG5cclxuICAvLyBSZXR1cm4gdGhlIHNpemUgb2JqZWN0XHJcbiAgcmV0dXJuIHNpemU7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBIYW5kbGVzIHRoZSBleGVjdXRpb24gb2YgY3VzdG9tIGxvZ2ljIG9wdGlvbnMsIGluY2x1ZGluZyBsb2FkaW5nIGByZXNvdXJjZXNgLFxyXG4gKiBgY3VzdG9tQ29kZWAsIGFuZCBgY2FsbGJhY2tgLiBJZiBjb2RlIGV4ZWN1dGlvbiBpcyBhbGxvd2VkLCBpdCBwcm9jZXNzZXNcclxuICogdGhlIGN1c3RvbSBsb2dpYyBvcHRpb25zIGFjY29yZGluZ2x5LiBJZiBjb2RlIGV4ZWN1dGlvbiBpcyBub3QgYWxsb3dlZCxcclxuICogaXQgZGlzYWJsZXMgdGhlIHVzYWdlIG9mIHJlc291cmNlcywgY3VzdG9tIGNvZGUgYW5kIGNhbGxiYWNrLlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gX2hhbmRsZUN1c3RvbUxvZ2ljXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBjdXN0b21Mb2dpY09wdGlvbnMgLSBUaGUgY29uZmlndXJhdGlvbiBvYmplY3QgY29udGFpbmluZ1xyXG4gKiBgY3VzdG9tTG9naWNgIG9wdGlvbnMuXHJcbiAqIEBwYXJhbSB7Ym9vbGVhbn0gYWxsb3dDb2RlRXhlY3V0aW9uIC0gQSBmbGFnIGluZGljYXRpbmcgd2hldGhlciBjb2RlXHJcbiAqIGV4ZWN1dGlvbiBpcyBhbGxvd2VkLlxyXG4gKlxyXG4gKiBAdGhyb3dzIHtFeHBvcnRFcnJvcn0gVGhyb3dzIGFuIGBFeHBvcnRFcnJvcmAgaWYgY29kZSBleGVjdXRpb25cclxuICogaXMgbm90IGFsbG93ZWQgYnV0IGN1c3RvbSBsb2dpYyBvcHRpb25zIGFyZSBzdGlsbCBwcm92aWRlZC5cclxuICovXHJcbmZ1bmN0aW9uIF9oYW5kbGVDdXN0b21Mb2dpYyhjdXN0b21Mb2dpY09wdGlvbnMsIGFsbG93Q29kZUV4ZWN1dGlvbikge1xyXG4gIC8vIEluIGNhc2Ugb2YgYWxsb3dpbmcgY29kZSBleGVjdXRpb25cclxuICBpZiAoYWxsb3dDb2RlRXhlY3V0aW9uKSB7XHJcbiAgICAvLyBQcm9jZXNzIHRoZSBgcmVzb3VyY2VzYCBvcHRpb25cclxuICAgIGlmICh0eXBlb2YgY3VzdG9tTG9naWNPcHRpb25zLnJlc291cmNlcyA9PT0gJ3N0cmluZycpIHtcclxuICAgICAgLy8gQ3VzdG9tIHN0cmluZ2lmaWVkIHJlc291cmNlc1xyXG4gICAgICBjdXN0b21Mb2dpY09wdGlvbnMucmVzb3VyY2VzID0gX2hhbmRsZVJlc291cmNlcyhcclxuICAgICAgICBjdXN0b21Mb2dpY09wdGlvbnMucmVzb3VyY2VzLFxyXG4gICAgICAgIGN1c3RvbUxvZ2ljT3B0aW9ucy5hbGxvd0ZpbGVSZXNvdXJjZXMsXHJcbiAgICAgICAgdHJ1ZVxyXG4gICAgICApO1xyXG4gICAgfSBlbHNlIGlmICghY3VzdG9tTG9naWNPcHRpb25zLnJlc291cmNlcykge1xyXG4gICAgICB0cnkge1xyXG4gICAgICAgIC8vIExvYWQgdGhlIGRlZmF1bHQgb25lXHJcbiAgICAgICAgY3VzdG9tTG9naWNPcHRpb25zLnJlc291cmNlcyA9IF9oYW5kbGVSZXNvdXJjZXMoXHJcbiAgICAgICAgICByZWFkRmlsZVN5bmMoZ2V0QWJzb2x1dGVQYXRoKCdyZXNvdXJjZXMuanNvbicpLCAndXRmOCcpLFxyXG4gICAgICAgICAgY3VzdG9tTG9naWNPcHRpb25zLmFsbG93RmlsZVJlc291cmNlcyxcclxuICAgICAgICAgIHRydWVcclxuICAgICAgICApO1xyXG4gICAgICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgICAgIGxvZygyLCAnW2NoYXJ0XSBVbmFibGUgdG8gbG9hZCB0aGUgZGVmYXVsdCBgcmVzb3VyY2VzLmpzb25gIGZpbGUuJyk7XHJcbiAgICAgIH1cclxuICAgIH1cclxuXHJcbiAgICAvLyBQcm9jZXNzIHRoZSBgY3VzdG9tQ29kZWAgb3B0aW9uXHJcbiAgICB0cnkge1xyXG4gICAgICAvLyBUcnkgdG8gbG9hZCBjdXN0b20gY29kZSBhbmQgd3JhcCBhcm91bmQgaXQgaW4gYSBzZWxmIGludm9raW5nIGZ1bmN0aW9uXHJcbiAgICAgIGN1c3RvbUxvZ2ljT3B0aW9ucy5jdXN0b21Db2RlID0gd3JhcEFyb3VuZChcclxuICAgICAgICBjdXN0b21Mb2dpY09wdGlvbnMuY3VzdG9tQ29kZSxcclxuICAgICAgICBjdXN0b21Mb2dpY09wdGlvbnMuYWxsb3dGaWxlUmVzb3VyY2VzXHJcbiAgICAgICk7XHJcblxyXG4gICAgICAvLyBWYWxpZGF0ZSB0aGUgb3B0aW9uXHJcbiAgICAgIGN1c3RvbUxvZ2ljT3B0aW9ucy5jdXN0b21Db2RlID0gdmFsaWRhdGVPcHRpb24oXHJcbiAgICAgICAgJ2N1c3RvbUNvZGUnLFxyXG4gICAgICAgIGN1c3RvbUxvZ2ljT3B0aW9ucy5jdXN0b21Db2RlXHJcbiAgICAgICk7XHJcbiAgICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgICBsb2dXaXRoU3RhY2soMiwgZXJyb3IsICdbY2hhcnRdIFRoZSBgY3VzdG9tQ29kZWAgY2Fubm90IGJlIGxvYWRlZC4nKTtcclxuXHJcbiAgICAgIC8vIEluIGNhc2Ugb2YgYW4gZXJyb3IsIHNldCB0aGUgb3B0aW9uIHdpdGggbnVsbFxyXG4gICAgICBjdXN0b21Mb2dpY09wdGlvbnMuY3VzdG9tQ29kZSA9IG51bGw7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gUHJvY2VzcyB0aGUgYGNhbGxiYWNrYCBvcHRpb25cclxuICAgIHRyeSB7XHJcbiAgICAgIC8vIFRyeSB0byBsb2FkIGNhbGxiYWNrIGZ1bmN0aW9uXHJcbiAgICAgIGN1c3RvbUxvZ2ljT3B0aW9ucy5jYWxsYmFjayA9IHdyYXBBcm91bmQoXHJcbiAgICAgICAgY3VzdG9tTG9naWNPcHRpb25zLmNhbGxiYWNrLFxyXG4gICAgICAgIGN1c3RvbUxvZ2ljT3B0aW9ucy5hbGxvd0ZpbGVSZXNvdXJjZXMsXHJcbiAgICAgICAgdHJ1ZVxyXG4gICAgICApO1xyXG5cclxuICAgICAgLy8gVmFsaWRhdGUgdGhlIG9wdGlvblxyXG4gICAgICBjdXN0b21Mb2dpY09wdGlvbnMuY2FsbGJhY2sgPSB2YWxpZGF0ZU9wdGlvbihcclxuICAgICAgICAnY2FsbGJhY2snLFxyXG4gICAgICAgIGN1c3RvbUxvZ2ljT3B0aW9ucy5jYWxsYmFja1xyXG4gICAgICApO1xyXG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICAgbG9nV2l0aFN0YWNrKDIsIGVycm9yLCAnW2NoYXJ0XSBUaGUgYGNhbGxiYWNrYCBjYW5ub3QgYmUgbG9hZGVkLicpO1xyXG5cclxuICAgICAgLy8gSW4gY2FzZSBvZiBhbiBlcnJvciwgc2V0IHRoZSBvcHRpb24gd2l0aCBudWxsXHJcbiAgICAgIGN1c3RvbUxvZ2ljT3B0aW9ucy5jYWxsYmFjayA9IG51bGw7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gQ2hlY2sgaWYgdGhlcmUgaXMgdGhlIGBjdXN0b21Db2RlYCBwcmVzZW50XHJcbiAgICBpZiAoW251bGwsIHVuZGVmaW5lZF0uaW5jbHVkZXMoY3VzdG9tTG9naWNPcHRpb25zLmN1c3RvbUNvZGUpKSB7XHJcbiAgICAgIGxvZygzLCAnW2NoYXJ0XSBObyB2YWx1ZSBmb3IgdGhlIGBjdXN0b21Db2RlYCBvcHRpb24gZm91bmQuJyk7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gQ2hlY2sgaWYgdGhlcmUgaXMgdGhlIGBjYWxsYmFja2AgcHJlc2VudFxyXG4gICAgaWYgKFtudWxsLCB1bmRlZmluZWRdLmluY2x1ZGVzKGN1c3RvbUxvZ2ljT3B0aW9ucy5jYWxsYmFjaykpIHtcclxuICAgICAgbG9nKDMsICdbY2hhcnRdIE5vIHZhbHVlIGZvciB0aGUgYGNhbGxiYWNrYCBvcHRpb24gZm91bmQuJyk7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gQ2hlY2sgaWYgdGhlcmUgaXMgdGhlIGByZXNvdXJjZXNgIHByZXNlbnRcclxuICAgIGlmIChbbnVsbCwgdW5kZWZpbmVkXS5pbmNsdWRlcyhjdXN0b21Mb2dpY09wdGlvbnMucmVzb3VyY2VzKSkge1xyXG4gICAgICBsb2coMywgJ1tjaGFydF0gTm8gdmFsdWUgZm9yIHRoZSBgcmVzb3VyY2VzYCBvcHRpb24gZm91bmQuJyk7XHJcbiAgICB9XHJcbiAgfSBlbHNlIHtcclxuICAgIC8vIElmIHRoZSBgYWxsb3dDb2RlRXhlY3V0aW9uYCBmbGFnIGlzIHNldCB0byBmYWxzZSwgd2Ugc2hvdWxkIHJlZnVzZVxyXG4gICAgLy8gdGhlIHVzYWdlIG9mIHRoZSBgY2FsbGJhY2tgLCBgcmVzb3VyY2VzYCwgYW5kIGBjdXN0b21Db2RlYCBvcHRpb25zLlxyXG4gICAgLy8gQWRkaXRpb25hbGx5LCB0aGUgd29ya2VyIHdpbGwgcmVmdXNlIHRvIHJ1biBhcmJpdHJhcnkgSmF2YVNjcmlwdC5cclxuICAgIGlmIChcclxuICAgICAgY3VzdG9tTG9naWNPcHRpb25zLmNhbGxiYWNrIHx8XHJcbiAgICAgIGN1c3RvbUxvZ2ljT3B0aW9ucy5yZXNvdXJjZXMgfHxcclxuICAgICAgY3VzdG9tTG9naWNPcHRpb25zLmN1c3RvbUNvZGVcclxuICAgICkge1xyXG4gICAgICAvLyBSZXNldCBhbGwgY3VzdG9tIGNvZGUgb3B0aW9uc1xyXG4gICAgICBjdXN0b21Mb2dpY09wdGlvbnMuY2FsbGJhY2sgPSBudWxsO1xyXG4gICAgICBjdXN0b21Mb2dpY09wdGlvbnMucmVzb3VyY2VzID0gbnVsbDtcclxuICAgICAgY3VzdG9tTG9naWNPcHRpb25zLmN1c3RvbUNvZGUgPSBudWxsO1xyXG5cclxuICAgICAgLy8gU2VuZCBhIG1lc3NhZ2Ugc2F5aW5nIHRoYXQgdGhlIGV4cG9ydGVyIGRvZXMgbm90IHN1cHBvcnQgdGhlc2Ugc2V0dGluZ3NcclxuICAgICAgdGhyb3cgbmV3IEV4cG9ydEVycm9yKFxyXG4gICAgICAgIGBbY2hhcnRdIFRoZSAnY2FsbGJhY2snLCAncmVzb3VyY2VzJywgYW5kICdjdXN0b21Db2RlJyBvcHRpb25zIGhhdmUgYmVlbiBkaXNhYmxlZCBmb3IgdGhpcyBzZXJ2ZXIuYCxcclxuICAgICAgICA0MDNcclxuICAgICAgKTtcclxuICAgIH1cclxuICB9XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBIYW5kbGVzIGFuZCB2YWxpZGF0ZXMgcmVzb3VyY2VzIGZyb20gdGhlIGByZXNvdXJjZXNgIG9wdGlvbiBmb3IgZXhwb3J0LlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gX2hhbmRsZVJlc291cmNlc1xyXG4gKlxyXG4gKiBAcGFyYW0geyhPYmplY3R8c3RyaW5nfG51bGwpfSBbcmVzb3VyY2VzPW51bGxdIC0gVGhlIHJlc291cmNlcyB0byBiZSBoYW5kbGVkLlxyXG4gKiBDYW4gYmUgZWl0aGVyIGEgSlNPTiBvYmplY3QsIHN0cmluZ2lmaWVkIEpTT04sIGEgcGF0aCB0byBhIEpTT04gZmlsZSxcclxuICogb3IgbnVsbC4gVGhlIGRlZmF1bHQgdmFsdWUgaXMgYG51bGxgLlxyXG4gKiBAcGFyYW0ge2Jvb2xlYW59IGFsbG93RmlsZVJlc291cmNlcyAtIEEgZmxhZyBpbmRpY2F0aW5nIHdoZXRoZXIgbG9hZGluZ1xyXG4gKiByZXNvdXJjZXMgZnJvbSBmaWxlcyBpcyBhbGxvd2VkLlxyXG4gKiBAcGFyYW0ge2Jvb2xlYW59IGFsbG93Q29kZUV4ZWN1dGlvbiAtIEEgZmxhZyBpbmRpY2F0aW5nIHdoZXRoZXIgY29kZVxyXG4gKiBleGVjdXRpb24gaXMgYWxsb3dlZC5cclxuICpcclxuICogQHJldHVybnMgeyhPYmplY3R8bnVsbCl9IFRoZSBoYW5kbGVkIHJlc291cmNlcyBvciBudWxsIGlmIG5vIHZhbGlkIHJlc291cmNlc1xyXG4gKiBhcmUgZm91bmQuXHJcbiAqL1xyXG5mdW5jdGlvbiBfaGFuZGxlUmVzb3VyY2VzKFxyXG4gIHJlc291cmNlcyA9IG51bGwsXHJcbiAgYWxsb3dGaWxlUmVzb3VyY2VzLFxyXG4gIGFsbG93Q29kZUV4ZWN1dGlvblxyXG4pIHtcclxuICAvLyBMaXN0IG9mIGFsbG93ZWQgc2VjdGlvbnMgaW4gdGhlIHJlc291cmNlcyBKU09OXHJcbiAgY29uc3QgYWxsb3dlZFByb3BzID0gWydqcycsICdjc3MnLCAnZmlsZXMnXTtcclxuXHJcbiAgbGV0IGhhbmRsZWRSZXNvdXJjZXMgPSByZXNvdXJjZXM7XHJcbiAgbGV0IGNvcnJlY3RSZXNvdXJjZXMgPSBmYWxzZTtcclxuXHJcbiAgLy8gVHJ5IHRvIGxvYWQgcmVzb3VyY2VzIGZyb20gYSBmaWxlXHJcbiAgaWYgKGFsbG93RmlsZVJlc291cmNlcyAmJiByZXNvdXJjZXMuZW5kc1dpdGgoJy5qc29uJykpIHtcclxuICAgIHRyeSB7XHJcbiAgICAgIGhhbmRsZWRSZXNvdXJjZXMgPSBpc0FsbG93ZWRDb25maWcoXHJcbiAgICAgICAgcmVhZEZpbGVTeW5jKGdldEFic29sdXRlUGF0aChyZXNvdXJjZXMpLCAndXRmOCcpLFxyXG4gICAgICAgIGZhbHNlLFxyXG4gICAgICAgIGFsbG93Q29kZUV4ZWN1dGlvblxyXG4gICAgICApO1xyXG4gICAgfSBjYXRjaCB7XHJcbiAgICAgIHJldHVybiBudWxsO1xyXG4gICAgfVxyXG4gIH0gZWxzZSB7XHJcbiAgICAvLyBUcnkgdG8gZ2V0IEpTT05cclxuICAgIGhhbmRsZWRSZXNvdXJjZXMgPSBpc0FsbG93ZWRDb25maWcocmVzb3VyY2VzLCBmYWxzZSwgYWxsb3dDb2RlRXhlY3V0aW9uKTtcclxuXHJcbiAgICAvLyBHZXQgcmlkIG9mIHRoZSBmaWxlcyBzZWN0aW9uXHJcbiAgICBpZiAoaGFuZGxlZFJlc291cmNlcyAmJiAhYWxsb3dGaWxlUmVzb3VyY2VzKSB7XHJcbiAgICAgIGRlbGV0ZSBoYW5kbGVkUmVzb3VyY2VzLmZpbGVzO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgLy8gRmlsdGVyIGZyb20gdW5uZWNlc3NhcnkgcHJvcGVydGllc1xyXG4gIGZvciAoY29uc3QgcHJvcE5hbWUgaW4gaGFuZGxlZFJlc291cmNlcykge1xyXG4gICAgaWYgKCFhbGxvd2VkUHJvcHMuaW5jbHVkZXMocHJvcE5hbWUpKSB7XHJcbiAgICAgIGRlbGV0ZSBoYW5kbGVkUmVzb3VyY2VzW3Byb3BOYW1lXTtcclxuICAgIH0gZWxzZSBpZiAoIWNvcnJlY3RSZXNvdXJjZXMpIHtcclxuICAgICAgY29ycmVjdFJlc291cmNlcyA9IHRydWU7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICAvLyBDaGVjayBpZiBhdCBsZWFzdCBvbmUgb2YgYWxsb3dlZCBwcm9wZXJ0aWVzIGlzIHByZXNlbnRcclxuICBpZiAoIWNvcnJlY3RSZXNvdXJjZXMpIHtcclxuICAgIHJldHVybiBudWxsO1xyXG4gIH1cclxuXHJcbiAgLy8gSGFuZGxlIGZpbGVzIHNlY3Rpb25cclxuICBpZiAoaGFuZGxlZFJlc291cmNlcy5maWxlcykge1xyXG4gICAgaGFuZGxlZFJlc291cmNlcy5maWxlcyA9IGhhbmRsZWRSZXNvdXJjZXMuZmlsZXMubWFwKChpdGVtKSA9PiBpdGVtLnRyaW0oKSk7XHJcbiAgICBpZiAoIWhhbmRsZWRSZXNvdXJjZXMuZmlsZXMgfHwgaGFuZGxlZFJlc291cmNlcy5maWxlcy5sZW5ndGggPD0gMCkge1xyXG4gICAgICBkZWxldGUgaGFuZGxlZFJlc291cmNlcy5maWxlcztcclxuICAgIH1cclxuICB9XHJcblxyXG4gIC8vIFZhbGlkYXRlIG9wdGlvblxyXG4gIGhhbmRsZWRSZXNvdXJjZXMgPSB2YWxpZGF0ZU9wdGlvbigncmVzb3VyY2VzJywgaGFuZGxlZFJlc291cmNlcyk7XHJcblxyXG4gIC8vIFJldHVybiByZXNvdXJjZXNcclxuICByZXR1cm4gaGFuZGxlZFJlc291cmNlcztcclxufVxyXG5cclxuLyoqXHJcbiAqIEhhbmRsZXMgdGhlIGxvYWRpbmcgYW5kIHZhbGlkYXRpb24gb2YgdGhlIGBnbG9iYWxPcHRpb25zYCBhbmQgYHRoZW1lT3B0aW9uc2BcclxuICogaW4gdGhlIGV4cG9ydCBvcHRpb25zLiBJZiB0aGUgb3B0aW9uIGlzIGEgc3RyaW5nIGFuZCByZWZlcmVuY2VzIGEgSlNPTiBmaWxlXHJcbiAqICh3aGVuIHRoZSBgYWxsb3dGaWxlUmVzb3VyY2VzYCBpcyB0cnVlKSwgaXQgcmVhZHMgYW5kIHBhcnNlcyB0aGUgZmlsZS5cclxuICogT3RoZXJ3aXNlLCBpdCBhdHRlbXB0cyB0byBwYXJzZSB0aGUgc3RyaW5nIG9yIG9iamVjdCBhcyBKU09OLiBJZiBhbnkgZXJyb3JzXHJcbiAqIG9jY3VyIGR1cmluZyB0aGlzIHByb2Nlc3MsIHRoZSBvcHRpb24gaXMgc2V0IHRvIG51bGwuIElmIHRoZXJlIGlzIGFuIGVycm9yXHJcbiAqIGxvYWRpbmcgb3IgcGFyc2luZyB0aGUgYGdsb2JhbE9wdGlvbnNgIG9yIGB0aGVtZU9wdGlvbnNgLCB0aGUgZXJyb3IgaXMgbG9nZ2VkXHJcbiAqIGFuZCB0aGUgb3B0aW9uIGlzIHNldCB0byBudWxsLlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gX2hhbmRsZUdsb2JhbEFuZFRoZW1lXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBleHBvcnRPcHRpb25zIC0gVGhlIGNvbmZpZ3VyYXRpb24gb2JqZWN0IGNvbnRhaW5pbmcgYGV4cG9ydGBcclxuICogb3B0aW9ucy5cclxuICogQHBhcmFtIHtib29sZWFufSBhbGxvd0ZpbGVSZXNvdXJjZXMgLSBBIGZsYWcgaW5kaWNhdGluZyB3aGV0aGVyIGxvYWRpbmdcclxuICogcmVzb3VyY2VzIGZyb20gZmlsZXMgaXMgYWxsb3dlZC5cclxuICogQHBhcmFtIHtib29sZWFufSBhbGxvd0NvZGVFeGVjdXRpb24gLSBBIGZsYWcgaW5kaWNhdGluZyB3aGV0aGVyIGNvZGVcclxuICogZXhlY3V0aW9uIGlzIGFsbG93ZWQuXHJcbiAqL1xyXG5mdW5jdGlvbiBfaGFuZGxlR2xvYmFsQW5kVGhlbWUoXHJcbiAgZXhwb3J0T3B0aW9ucyxcclxuICBhbGxvd0ZpbGVSZXNvdXJjZXMsXHJcbiAgYWxsb3dDb2RlRXhlY3V0aW9uXHJcbikge1xyXG4gIC8vIENoZWNrIHRoZSBgZ2xvYmFsT3B0aW9uc2AgYW5kIGB0aGVtZU9wdGlvbnNgIG9wdGlvbnNcclxuICBbJ2dsb2JhbE9wdGlvbnMnLCAndGhlbWVPcHRpb25zJ10uZm9yRWFjaCgob3B0aW9uc05hbWUpID0+IHtcclxuICAgIHRyeSB7XHJcbiAgICAgIC8vIENoZWNrIGlmIHRoZSBvcHRpb24gZXhpc3RzXHJcbiAgICAgIGlmIChleHBvcnRPcHRpb25zW29wdGlvbnNOYW1lXSkge1xyXG4gICAgICAgIC8vIENoZWNrIGlmIGl0IGlzIGEgc3RyaW5nIGFuZCBhIGZpbGUgbmFtZSB3aXRoIHRoZSBgLmpzb25gIGV4dGVuc2lvblxyXG4gICAgICAgIGlmIChcclxuICAgICAgICAgIGFsbG93RmlsZVJlc291cmNlcyAmJlxyXG4gICAgICAgICAgdHlwZW9mIGV4cG9ydE9wdGlvbnNbb3B0aW9uc05hbWVdID09PSAnc3RyaW5nJyAmJlxyXG4gICAgICAgICAgZXhwb3J0T3B0aW9uc1tvcHRpb25zTmFtZV0uZW5kc1dpdGgoJy5qc29uJylcclxuICAgICAgICApIHtcclxuICAgICAgICAgIC8vIENoZWNrIGlmIHRoZSBmaWxlIGNvbnRlbnQgY2FuIGJlIGEgY29uZmlnLCBhbmQgc2F2ZSBpdCBhcyBhIHN0cmluZ1xyXG4gICAgICAgICAgZXhwb3J0T3B0aW9uc1tvcHRpb25zTmFtZV0gPSBpc0FsbG93ZWRDb25maWcoXHJcbiAgICAgICAgICAgIHJlYWRGaWxlU3luYyhnZXRBYnNvbHV0ZVBhdGgoZXhwb3J0T3B0aW9uc1tvcHRpb25zTmFtZV0pLCAndXRmOCcpLFxyXG4gICAgICAgICAgICB0cnVlLFxyXG4gICAgICAgICAgICBhbGxvd0NvZGVFeGVjdXRpb25cclxuICAgICAgICAgICk7XHJcbiAgICAgICAgfSBlbHNlIHtcclxuICAgICAgICAgIC8vIENoZWNrIGlmIHRoZSB2YWx1ZSBjYW4gYmUgYSBjb25maWcsIGFuZCBzYXZlIGl0IGFzIGEgc3RyaW5nXHJcbiAgICAgICAgICBleHBvcnRPcHRpb25zW29wdGlvbnNOYW1lXSA9IGlzQWxsb3dlZENvbmZpZyhcclxuICAgICAgICAgICAgZXhwb3J0T3B0aW9uc1tvcHRpb25zTmFtZV0sXHJcbiAgICAgICAgICAgIHRydWUsXHJcbiAgICAgICAgICAgIGFsbG93Q29kZUV4ZWN1dGlvblxyXG4gICAgICAgICAgKTtcclxuICAgICAgICB9XHJcblxyXG4gICAgICAgIC8vIFZhbGlkYXRlIHRoZSBvcHRpb25cclxuICAgICAgICBleHBvcnRPcHRpb25zW29wdGlvbnNOYW1lXSA9IHZhbGlkYXRlT3B0aW9uKFxyXG4gICAgICAgICAgb3B0aW9uc05hbWUsXHJcbiAgICAgICAgICBleHBvcnRPcHRpb25zW29wdGlvbnNOYW1lXVxyXG4gICAgICAgICk7XHJcbiAgICAgIH1cclxuICAgIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICAgIGxvZ1dpdGhTdGFjayhcclxuICAgICAgICAyLFxyXG4gICAgICAgIGVycm9yLFxyXG4gICAgICAgIGBbY2hhcnRdIFRoZSBcXGAke29wdGlvbnNOYW1lfVxcYCBjYW5ub3QgYmUgbG9hZGVkLmBcclxuICAgICAgKTtcclxuXHJcbiAgICAgIC8vIEluIGNhc2Ugb2YgYW4gZXJyb3IsIHNldCB0aGUgb3B0aW9uIHdpdGggbnVsbFxyXG4gICAgICBleHBvcnRPcHRpb25zW29wdGlvbnNOYW1lXSA9IG51bGw7XHJcbiAgICB9XHJcbiAgfSk7XHJcblxyXG4gIC8vIENoZWNrIGlmIHRoZXJlIGlzIHRoZSBgZ2xvYmFsT3B0aW9uc2AgcHJlc2VudFxyXG4gIGlmIChbbnVsbCwgdW5kZWZpbmVkXS5pbmNsdWRlcyhleHBvcnRPcHRpb25zLmdsb2JhbE9wdGlvbnMpKSB7XHJcbiAgICBsb2coMywgJ1tjaGFydF0gTm8gdmFsdWUgZm9yIHRoZSBgZ2xvYmFsT3B0aW9uc2Agb3B0aW9uIGZvdW5kLicpO1xyXG4gIH1cclxuXHJcbiAgLy8gQ2hlY2sgaWYgdGhlcmUgaXMgdGhlIGB0aGVtZU9wdGlvbnNgIHByZXNlbnRcclxuICBpZiAoW251bGwsIHVuZGVmaW5lZF0uaW5jbHVkZXMoZXhwb3J0T3B0aW9ucy50aGVtZU9wdGlvbnMpKSB7XHJcbiAgICBsb2coMywgJ1tjaGFydF0gTm8gdmFsdWUgZm9yIHRoZSBgdGhlbWVPcHRpb25zYCBvcHRpb24gZm91bmQuJyk7XHJcbiAgfVxyXG59XHJcblxyXG5leHBvcnQgZGVmYXVsdCB7XHJcbiAgc2luZ2xlRXhwb3J0LFxyXG4gIGJhdGNoRXhwb3J0LFxyXG4gIHN0YXJ0RXhwb3J0LFxyXG4gIGdldEFsbG93Q29kZUV4ZWN1dGlvbixcclxuICBzZXRBbGxvd0NvZGVFeGVjdXRpb25cclxufTtcclxuIiwiLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcclxuXHJcbkhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlclxyXG5cclxuQ29weXJpZ2h0IChjKSAyMDE2LTIwMjUsIEhpZ2hzb2Z0XHJcblxyXG5MaWNlbmNlZCB1bmRlciB0aGUgTUlUIGxpY2VuY2UuXHJcblxyXG5BZGRpdGlvbmFsbHkgYSB2YWxpZCBIaWdoY2hhcnRzIGxpY2Vuc2UgaXMgcmVxdWlyZWQgZm9yIHVzZS5cclxuXHJcblNlZSBMSUNFTlNFIGZpbGUgaW4gcm9vdCBmb3IgZGV0YWlscy5cclxuXHJcbioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXHJcblxyXG4vKipcclxuICogQG92ZXJ2aWV3IFRoaXMgbW9kdWxlIHByb3ZpZGVzIHV0aWxpdHkgZnVuY3Rpb25zIGZvciBtYW5hZ2luZyBpbnRlcnZhbHNcclxuICogYW5kIHRpbWVvdXRzIGluIGEgY2VudHJhbGl6ZWQgbWFubmVyLiBJdCBtYWludGFpbnMgYSByZWdpc3RyeSBvZiBhbGwgYWN0aXZlXHJcbiAqIHRpbWVycyBhbmQgYWxsb3dzIGZvciB0aGVpciBlZmZpY2llbnQgY2xlYW51cCB3aGVuIG5lZWRlZC4gVGhpcyBjYW4gYmUgdXNlZnVsXHJcbiAqIGluIGFwcGxpY2F0aW9ucyB3aGVyZSBwcm9wZXIgcmVzb3VyY2UgbWFuYWdlbWVudCBhbmQgY2xlYW4gc2h1dGRvd24gb2YgdGltZXJzXHJcbiAqIGFyZSBjcml0aWNhbCB0byBhdm9pZCBtZW1vcnkgbGVha3Mgb3IgdW5pbnRlbmRlZCBiZWhhdmlvci5cclxuICovXHJcblxyXG5pbXBvcnQgeyBsb2cgfSBmcm9tICcuL2xvZ2dlci5qcyc7XHJcblxyXG4vLyBBcnJheSB0aGF0IGNvbnRhaW5zIGlkcyBvZiBhbGwgb25nb2luZyBpbnRlcnZhbHMgYW5kIHRpbWVvdXRzXHJcbmNvbnN0IHRpbWVySWRzID0gW107XHJcblxyXG4vKipcclxuICogQWRkcyBpZCBvZiB0aGUgYHNldEludGVydmFsYCBvciBgc2V0VGltZW91dGAgYW5kIHRvIHRoZSBgdGltZXJJZHNgIGFycmF5LlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gYWRkVGltZXJcclxuICpcclxuICogQHBhcmFtIHtOb2RlSlMuVGltZW91dH0gaWQgLSBJZCBvZiBhbiBpbnRlcnZhbCBvciBhIHRpbWVvdXQuXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gYWRkVGltZXIoaWQpIHtcclxuICB0aW1lcklkcy5wdXNoKGlkKTtcclxufVxyXG5cclxuLyoqXHJcbiAqIENsZWFycyBhbGwgb2Ygb25nb2luZyBpbnRlcnZhbHMgYW5kIHRpbWVvdXRzIGJ5IGlkcyBnYXRoZXJlZFxyXG4gKiBpbiB0aGUgYHRpbWVySWRzYCBhcnJheS5cclxuICpcclxuICogQGZ1bmN0aW9uIGNsZWFyQWxsVGltZXJzXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gY2xlYXJBbGxUaW1lcnMoKSB7XHJcbiAgbG9nKDQsIGBbdGltZXJdIENsZWFyaW5nIGFsbCByZWdpc3RlcmVkIGludGVydmFscyBhbmQgdGltZW91dHMuYCk7XHJcbiAgZm9yIChjb25zdCBpZCBvZiB0aW1lcklkcykge1xyXG4gICAgY2xlYXJJbnRlcnZhbChpZCk7XHJcbiAgICBjbGVhclRpbWVvdXQoaWQpO1xyXG4gIH1cclxufVxyXG5cclxuZXhwb3J0IGRlZmF1bHQge1xyXG4gIGFkZFRpbWVyLFxyXG4gIGNsZWFyQWxsVGltZXJzXHJcbn07XHJcbiIsIi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXHJcblxyXG5IaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXJcclxuXHJcbkNvcHlyaWdodCAoYykgMjAxNi0yMDI1LCBIaWdoc29mdFxyXG5cclxuTGljZW5jZWQgdW5kZXIgdGhlIE1JVCBsaWNlbmNlLlxyXG5cclxuQWRkaXRpb25hbGx5IGEgdmFsaWQgSGlnaGNoYXJ0cyBsaWNlbnNlIGlzIHJlcXVpcmVkIGZvciB1c2UuXHJcblxyXG5TZWUgTElDRU5TRSBmaWxlIGluIHJvb3QgZm9yIGRldGFpbHMuXHJcblxyXG4qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xyXG5cclxuLyoqXHJcbiAqIEBvdmVydmlldyBQcm92aWRlcyBtaWRkbGV3YXJlIGZ1bmN0aW9ucyBmb3IgbG9nZ2luZyBlcnJvcnMgd2l0aCBzdGFjayB0cmFjZXNcclxuICogYW5kIGhhbmRsaW5nIGVycm9yIHJlc3BvbnNlcyBpbiBhbiBFeHByZXNzIGFwcGxpY2F0aW9uLlxyXG4gKi9cclxuXHJcbmltcG9ydCB7IGdldE9wdGlvbnMgfSBmcm9tICcuLi8uLi9jb25maWcuanMnO1xyXG5pbXBvcnQgeyBsb2dXaXRoU3RhY2sgfSBmcm9tICcuLi8uLi9sb2dnZXIuanMnO1xyXG5cclxuLyoqXHJcbiAqIE1pZGRsZXdhcmUgZm9yIGxvZ2dpbmcgZXJyb3JzIHdpdGggc3RhY2sgdHJhY2UgYW5kIGhhbmRsaW5nIGVycm9yIHJlc3BvbnNlLlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gbG9nRXJyb3JNaWRkbGV3YXJlXHJcbiAqXHJcbiAqIEBwYXJhbSB7RXJyb3J9IGVycm9yIC0gVGhlIGVycm9yIG9iamVjdC5cclxuICogQHBhcmFtIHtFeHByZXNzLlJlcXVlc3R9IHJlcXVlc3QgLSBUaGUgRXhwcmVzcyByZXF1ZXN0IG9iamVjdC5cclxuICogQHBhcmFtIHtFeHByZXNzLlJlc3BvbnNlfSByZXNwb25zZSAtIFRoZSBFeHByZXNzIHJlc3BvbnNlIG9iamVjdC5cclxuICogQHBhcmFtIHtGdW5jdGlvbn0gbmV4dCAtIFRoZSBuZXh0IG1pZGRsZXdhcmUgZnVuY3Rpb24uXHJcbiAqXHJcbiAqIEByZXR1cm5zIHt1bmRlZmluZWR9IFRoZSBjYWxsIHRvIHRoZSBuZXh0IG1pZGRsZXdhcmUgZnVuY3Rpb24gd2l0aFxyXG4gKiB0aGUgcGFzc2VkIGVycm9yLlxyXG4gKi9cclxuZnVuY3Rpb24gbG9nRXJyb3JNaWRkbGV3YXJlKGVycm9yLCByZXF1ZXN0LCByZXNwb25zZSwgbmV4dCkge1xyXG4gIC8vIERpc3BsYXkgdGhlIGVycm9yIHdpdGggc3RhY2sgaW4gYSBjb3JyZWN0IGZvcm1hdFxyXG4gIGxvZ1dpdGhTdGFjaygxLCBlcnJvcik7XHJcblxyXG4gIC8vIERlbGV0ZSB0aGUgc3RhY2sgZm9yIHRoZSBlbnZpcm9ubWVudCBvdGhlciB0aGFuIHRoZSBkZXZlbG9wbWVudFxyXG4gIGlmIChnZXRPcHRpb25zKCkub3RoZXIubm9kZUVudiAhPT0gJ2RldmVsb3BtZW50Jykge1xyXG4gICAgZGVsZXRlIGVycm9yLnN0YWNrO1xyXG4gIH1cclxuXHJcbiAgLy8gQ2FsbCB0aGUgYHJldHVybkVycm9yTWlkZGxld2FyZWAgbWlkZGxld2FyZVxyXG4gIHJldHVybiBuZXh0KGVycm9yKTtcclxufVxyXG5cclxuLyoqXHJcbiAqIE1pZGRsZXdhcmUgZm9yIHJldHVybmluZyBlcnJvciByZXNwb25zZS5cclxuICpcclxuICogQGZ1bmN0aW9uIHJldHVybkVycm9yTWlkZGxld2FyZVxyXG4gKlxyXG4gKiBAcGFyYW0ge0Vycm9yfSBlcnJvciAtIFRoZSBlcnJvciBvYmplY3QuXHJcbiAqIEBwYXJhbSB7RXhwcmVzcy5SZXF1ZXN0fSByZXF1ZXN0IC0gVGhlIEV4cHJlc3MgcmVxdWVzdCBvYmplY3QuXHJcbiAqIEBwYXJhbSB7RXhwcmVzcy5SZXNwb25zZX0gcmVzcG9uc2UgLSBUaGUgRXhwcmVzcyByZXNwb25zZSBvYmplY3QuXHJcbiAqIEBwYXJhbSB7RnVuY3Rpb259IG5leHQgLSBUaGUgbmV4dCBtaWRkbGV3YXJlIGZ1bmN0aW9uLlxyXG4gKi9cclxuZnVuY3Rpb24gcmV0dXJuRXJyb3JNaWRkbGV3YXJlKGVycm9yLCByZXF1ZXN0LCByZXNwb25zZSwgbmV4dCkge1xyXG4gIC8vIEdhdGhlciBhbGwgcmVxdWllZCBpbmZvcm1hdGlvbiBmb3IgdGhlIHJlc3BvbnNlXHJcbiAgY29uc3QgeyBtZXNzYWdlLCBzdGFjayB9ID0gZXJyb3I7XHJcblxyXG4gIC8vIFVzZSB0aGUgZXJyb3IncyBzdGF0dXMgY29kZSBvciB0aGUgZGVmYXVsdCA0MDBcclxuICBjb25zdCBzdGF0dXNDb2RlID0gZXJyb3Iuc3RhdHVzQ29kZSB8fCA0MDA7XHJcblxyXG4gIC8vIFNldCBhbmQgcmV0dXJuIHJlc3BvbnNlXHJcbiAgcmVzcG9uc2Uuc3RhdHVzKHN0YXR1c0NvZGUpLmpzb24oeyBzdGF0dXNDb2RlLCBtZXNzYWdlLCBzdGFjayB9KTtcclxufVxyXG5cclxuLyoqXHJcbiAqIEFkZHMgdGhlIGVycm9yIG1pZGRsZXdhcmVzIHRvIHRoZSBwYXNzZWQgZXhwcmVzcyBhcHAgaW5zdGFuY2UuXHJcbiAqXHJcbiAqIEBwYXJhbSB7RXhwcmVzc30gYXBwIC0gVGhlIEV4cHJlc3MgYXBwIGluc3RhbmNlLlxyXG4gKi9cclxuZXhwb3J0IGRlZmF1bHQgZnVuY3Rpb24gZXJyb3JNaWRkbGV3YXJlKGFwcCkge1xyXG4gIC8vIEFkZCBsb2cgZXJyb3IgbWlkZGxld2FyZVxyXG4gIGFwcC51c2UobG9nRXJyb3JNaWRkbGV3YXJlKTtcclxuXHJcbiAgLy8gQWRkIHNldCBzdGF0dXMgYW5kIHJldHVybiBlcnJvciBtaWRkbGV3YXJlXHJcbiAgYXBwLnVzZShyZXR1cm5FcnJvck1pZGRsZXdhcmUpO1xyXG59XHJcbiIsIi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXHJcblxyXG5IaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXJcclxuXHJcbkNvcHlyaWdodCAoYykgMjAxNi0yMDI1LCBIaWdoc29mdFxyXG5cclxuTGljZW5jZWQgdW5kZXIgdGhlIE1JVCBsaWNlbmNlLlxyXG5cclxuQWRkaXRpb25hbGx5IGEgdmFsaWQgSGlnaGNoYXJ0cyBsaWNlbnNlIGlzIHJlcXVpcmVkIGZvciB1c2UuXHJcblxyXG5TZWUgTElDRU5TRSBmaWxlIGluIHJvb3QgZm9yIGRldGFpbHMuXHJcblxyXG4qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xyXG5cclxuLyoqXHJcbiAqIEBvdmVydmlldyBQcm92aWRlcyBtaWRkbGV3YXJlIGZ1bmN0aW9ucyBmb3IgY29uZmlndXJpbmcgYW5kIGVuYWJsaW5nIHJhdGVcclxuICogbGltaXRpbmcgaW4gYW4gRXhwcmVzcyBhcHBsaWNhdGlvbi5cclxuICovXHJcblxyXG5pbXBvcnQgcmF0ZUxpbWl0IGZyb20gJ2V4cHJlc3MtcmF0ZS1saW1pdCc7XHJcblxyXG5pbXBvcnQgeyBsb2cgfSBmcm9tICcuLi8uLi9sb2dnZXIuanMnO1xyXG5cclxuaW1wb3J0IEV4cG9ydEVycm9yIGZyb20gJy4uLy4uL2Vycm9ycy9FeHBvcnRFcnJvci5qcyc7XHJcblxyXG4vKipcclxuICogTWlkZGxld2FyZSBmb3IgZW5hYmxpbmcgcmF0ZSBsaW1pdGluZyBvbiB0aGUgc3BlY2lmaWVkIEV4cHJlc3MgYXBwLlxyXG4gKlxyXG4gKiBAcGFyYW0ge0V4cHJlc3N9IGFwcCAtIFRoZSBFeHByZXNzIGFwcCBpbnN0YW5jZS5cclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IHJhdGVMaW1pdGluZ09wdGlvbnMgLSBUaGUgY29uZmlndXJhdGlvbiBvYmplY3QgY29udGFpbmluZ1xyXG4gKiBgcmF0ZUxpbWl0aW5nYCBvcHRpb25zLlxyXG4gKlxyXG4gKiBAdGhyb3dzIHtFeHBvcnRFcnJvcn0gVGhyb3dzIGFuIGBFeHBvcnRFcnJvcmAgaWYgY291bGQgbm90IGNvbmZpZ3VyZSBhbmQgc2V0XHJcbiAqIHRoZSByYXRlIGxpbWl0aW5nIG9wdGlvbnMuXHJcbiAqL1xyXG5leHBvcnQgZGVmYXVsdCBmdW5jdGlvbiByYXRlTGltaXRpbmdNaWRkbGV3YXJlKGFwcCwgcmF0ZUxpbWl0aW5nT3B0aW9ucykge1xyXG4gIHRyeSB7XHJcbiAgICAvLyBDaGVjayBpZiB0aGUgcmF0ZSBsaW1pdGluZyBpcyBlbmFibGVkXHJcbiAgICBpZiAocmF0ZUxpbWl0aW5nT3B0aW9ucy5lbmFibGUpIHtcclxuICAgICAgY29uc3QgbWVzc2FnZSA9XHJcbiAgICAgICAgJ1RvbyBtYW55IHJlcXVlc3RzLCB5b3UgaGF2ZSBiZWVuIHJhdGUgbGltaXRlZC4gUGxlYXNlIHRyeSBhZ2FpbiBsYXRlci4nO1xyXG5cclxuICAgICAgLy8gT3B0aW9ucyBmb3IgdGhlIHJhdGUgbGltaXRlclxyXG4gICAgICBjb25zdCByYXRlT3B0aW9ucyA9IHtcclxuICAgICAgICB3aW5kb3c6IHJhdGVMaW1pdGluZ09wdGlvbnMud2luZG93IHx8IDEsXHJcbiAgICAgICAgbWF4UmVxdWVzdHM6IHJhdGVMaW1pdGluZ09wdGlvbnMubWF4UmVxdWVzdHMgfHwgMzAsXHJcbiAgICAgICAgZGVsYXk6IHJhdGVMaW1pdGluZ09wdGlvbnMuZGVsYXkgfHwgMCxcclxuICAgICAgICB0cnVzdFByb3h5OiByYXRlTGltaXRpbmdPcHRpb25zLnRydXN0UHJveHkgfHwgZmFsc2UsXHJcbiAgICAgICAgc2tpcEtleTogcmF0ZUxpbWl0aW5nT3B0aW9ucy5za2lwS2V5IHx8IG51bGwsXHJcbiAgICAgICAgc2tpcFRva2VuOiByYXRlTGltaXRpbmdPcHRpb25zLnNraXBUb2tlbiB8fCBudWxsXHJcbiAgICAgIH07XHJcblxyXG4gICAgICAvLyBTZXQgaWYgYmVoaW5kIGEgcHJveHlcclxuICAgICAgaWYgKHJhdGVPcHRpb25zLnRydXN0UHJveHkpIHtcclxuICAgICAgICBhcHAuZW5hYmxlKCd0cnVzdCBwcm94eScpO1xyXG4gICAgICB9XHJcblxyXG4gICAgICAvLyBDcmVhdGUgYSBsaW1pdGVyXHJcbiAgICAgIGNvbnN0IGxpbWl0ZXIgPSByYXRlTGltaXQoe1xyXG4gICAgICAgIC8vIFRpbWUgZnJhbWUgZm9yIHdoaWNoIHJlcXVlc3RzIGFyZSBjaGVja2VkIGFuZCByZW1lbWJlcmVkXHJcbiAgICAgICAgd2luZG93TXM6IHJhdGVPcHRpb25zLndpbmRvdyAqIDYwICogMTAwMCxcclxuICAgICAgICAvLyBMaW1pdCBlYWNoIElQIHRvIDEwMCByZXF1ZXN0cyBwZXIgYHdpbmRvd01zYFxyXG4gICAgICAgIGxpbWl0OiByYXRlT3B0aW9ucy5tYXhSZXF1ZXN0cyxcclxuICAgICAgICAvLyBEaXNhYmxlIGRlbGF5aW5nLCBmdWxsIHNwZWVkIHVudGlsIHRoZSBtYXggbGltaXQgaXMgcmVhY2hlZFxyXG4gICAgICAgIGRlbGF5TXM6IHJhdGVPcHRpb25zLmRlbGF5LFxyXG4gICAgICAgIGhhbmRsZXI6IChyZXF1ZXN0LCByZXNwb25zZSkgPT4ge1xyXG4gICAgICAgICAgcmVzcG9uc2UuZm9ybWF0KHtcclxuICAgICAgICAgICAganNvbjogKCkgPT4ge1xyXG4gICAgICAgICAgICAgIHJlc3BvbnNlLnN0YXR1cyg0MjkpLnNlbmQoeyBtZXNzYWdlIH0pO1xyXG4gICAgICAgICAgICB9LFxyXG4gICAgICAgICAgICBkZWZhdWx0OiAoKSA9PiB7XHJcbiAgICAgICAgICAgICAgcmVzcG9uc2Uuc3RhdHVzKDQyOSkuc2VuZChtZXNzYWdlKTtcclxuICAgICAgICAgICAgfVxyXG4gICAgICAgICAgfSk7XHJcbiAgICAgICAgfSxcclxuICAgICAgICBza2lwOiAocmVxdWVzdCkgPT4ge1xyXG4gICAgICAgICAgLy8gQWxsb3cgYnlwYXNzaW5nIHRoZSBsaW1pdGVyIGlmIGEgdmFsaWQga2V5L3Rva2VuIGhhcyBiZWVuIHNlbnRcclxuICAgICAgICAgIGlmIChcclxuICAgICAgICAgICAgcmF0ZU9wdGlvbnMuc2tpcEtleSAhPT0gbnVsbCAmJlxyXG4gICAgICAgICAgICByYXRlT3B0aW9ucy5za2lwVG9rZW4gIT09IG51bGwgJiZcclxuICAgICAgICAgICAgcmVxdWVzdC5xdWVyeS5rZXkgPT09IHJhdGVPcHRpb25zLnNraXBLZXkgJiZcclxuICAgICAgICAgICAgcmVxdWVzdC5xdWVyeS5hY2Nlc3NfdG9rZW4gPT09IHJhdGVPcHRpb25zLnNraXBUb2tlblxyXG4gICAgICAgICAgKSB7XHJcbiAgICAgICAgICAgIGxvZyg0LCAnW3JhdGUgbGltaXRpbmddIFNraXBwaW5nIHJhdGUgbGltaXRlci4nKTtcclxuICAgICAgICAgICAgcmV0dXJuIHRydWU7XHJcbiAgICAgICAgICB9XHJcbiAgICAgICAgICByZXR1cm4gZmFsc2U7XHJcbiAgICAgICAgfVxyXG4gICAgICB9KTtcclxuXHJcbiAgICAgIC8vIFVzZSBhIGxpbWl0ZXIgYXMgYSBtaWRkbGV3YXJlXHJcbiAgICAgIGFwcC51c2UobGltaXRlcik7XHJcblxyXG4gICAgICBsb2coXHJcbiAgICAgICAgMyxcclxuICAgICAgICBgW3JhdGUgbGltaXRpbmddIEVuYWJsZWQgcmF0ZSBsaW1pdGluZyB3aXRoICR7cmF0ZU9wdGlvbnMubWF4UmVxdWVzdHN9IHJlcXVlc3RzIHBlciAke3JhdGVPcHRpb25zLndpbmRvd30gbWludXRlIGZvciBlYWNoIElQLCB0cnVzdGluZyBwcm94eTogJHtyYXRlT3B0aW9ucy50cnVzdFByb3h5fS5gXHJcbiAgICAgICk7XHJcbiAgICB9XHJcbiAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcihcclxuICAgICAgJ1tyYXRlIGxpbWl0aW5nXSBDb3VsZCBub3QgY29uZmlndXJlIGFuZCBzZXQgdGhlIHJhdGUgbGltaXRpbmcgb3B0aW9ucy4nLFxyXG4gICAgICA1MDBcclxuICAgICkuc2V0RXJyb3IoZXJyb3IpO1xyXG4gIH1cclxufVxyXG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxyXG5cclxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXHJcblxyXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNSwgSGlnaHNvZnRcclxuXHJcbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cclxuXHJcbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxyXG5cclxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxyXG5cclxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cclxuXHJcbi8qKlxyXG4gKiBAb3ZlcnZpZXcgUHJvdmlkZXMgbWlkZGxld2FyZSBmdW5jdGlvbnMgZm9yIHZhbGlkYXRpbmcgaW5jb21pbmcgSFRUUCByZXF1ZXN0c1xyXG4gKiBpbiBhbiBFeHByZXNzIGFwcGxpY2F0aW9uLiBUaGlzIG1vZHVsZSBlbnN1cmVzIHRoYXQgcmVxdWVzdHMgY29udGFpblxyXG4gKiBhcHByb3ByaWF0ZSBjb250ZW50IHR5cGVzIGFuZCB2YWxpZCByZXF1ZXN0IGJvZGllcywgaW5jbHVkaW5nIHByb3BlciBKU09OXHJcbiAqIHN0cnVjdHVyZXMgYW5kIGNoYXJ0IGRhdGEgZm9yIGV4cG9ydHMuIEl0IGNoZWNrcyBmb3IgcG90ZW50aWFsIGlzc3VlcyBzdWNoXHJcbiAqIGFzIG1pc3Npbmcgb3IgbWFsZm9ybWVkIGRhdGEsIHByaXZhdGUgcmFuZ2UgVVJMcyBpbiBTVkcgcGF5bG9hZHMsIGFuZCBhbGxvd3NcclxuICogZm9yIGZsZXhpYmxlIG9wdGlvbnMgdmFsaWRhdGlvbi4gVGhlIG1pZGRsZXdhcmUgbG9ncyBkZXRhaWxlZCBpbmZvcm1hdGlvblxyXG4gKiBhbmQgaGFuZGxlcyBlcnJvcnMgcmVsYXRlZCB0byBpbmNvcnJlY3QgcGF5bG9hZHMsIGNoYXJ0IGRhdGEsIGFuZCBwcml2YXRlIFVSTFxyXG4gKiB1c2FnZS5cclxuICovXHJcblxyXG5pbXBvcnQgeyB2NCBhcyB1dWlkIH0gZnJvbSAndXVpZCc7XHJcblxyXG5pbXBvcnQgeyBnZXRBbGxvd0NvZGVFeGVjdXRpb24gfSBmcm9tICcuLi8uLi9jaGFydC5qcyc7XHJcbmltcG9ydCB7IGlzQWxsb3dlZENvbmZpZywgdmFsaWRhdGVPcHRpb25zIH0gZnJvbSAnLi4vLi4vY29uZmlnLmpzJztcclxuaW1wb3J0IHsgbG9nLCBsb2dab2RJc3N1ZXMgfSBmcm9tICcuLi8uLi9sb2dnZXIuanMnO1xyXG5pbXBvcnQge1xyXG4gIGZpeENvbnN0cixcclxuICBmaXhUeXBlLFxyXG4gIGlzT2JqZWN0RW1wdHksXHJcbiAgaXNQcml2YXRlUmFuZ2VVcmxGb3VuZFxyXG59IGZyb20gJy4uLy4uL3V0aWxzLmpzJztcclxuaW1wb3J0IHsgbG9vc2VWYWxpZGF0ZSB9IGZyb20gJy4uLy4uL3ZhbGlkYXRpb24uanMnO1xyXG5cclxuaW1wb3J0IEV4cG9ydEVycm9yIGZyb20gJy4uLy4uL2Vycm9ycy9FeHBvcnRFcnJvci5qcyc7XHJcblxyXG4vKipcclxuICogTWlkZGxld2FyZSBmb3IgdmFsaWRhdGluZyB0aGUgY29udGVudC10eXBlIGhlYWRlci5cclxuICpcclxuICogQGZ1bmN0aW9uIGNvbnRlbnRUeXBlTWlkZGxld2FyZVxyXG4gKlxyXG4gKiBAcGFyYW0ge0V4cHJlc3MuUmVxdWVzdH0gcmVxdWVzdCAtIFRoZSBFeHByZXNzIHJlcXVlc3Qgb2JqZWN0LlxyXG4gKiBAcGFyYW0ge0V4cHJlc3MuUmVzcG9uc2V9IHJlc3BvbnNlIC0gVGhlIEV4cHJlc3MgcmVzcG9uc2Ugb2JqZWN0LlxyXG4gKiBAcGFyYW0ge0Z1bmN0aW9ufSBuZXh0IC0gVGhlIG5leHQgbWlkZGxld2FyZSBmdW5jdGlvbi5cclxuICpcclxuICogQHJldHVybnMge3VuZGVmaW5lZH0gVGhlIGNhbGwgdG8gdGhlIG5leHQgbWlkZGxld2FyZSBmdW5jdGlvbi5cclxuICpcclxuICogQHRocm93cyB7RXhwb3J0RXJyb3J9IFRocm93cyBhbiBgRXhwb3J0RXJyb3JgIGlmIHRoZSBjb250ZW50LXR5cGVcclxuICogaXMgbm90IGNvcnJlY3QuXHJcbiAqL1xyXG5mdW5jdGlvbiBjb250ZW50VHlwZU1pZGRsZXdhcmUocmVxdWVzdCwgcmVzcG9uc2UsIG5leHQpIHtcclxuICB0cnkge1xyXG4gICAgLy8gR2V0IHRoZSBjb250ZW50IHR5cGUgaGVhZGVyXHJcbiAgICBjb25zdCBjb250ZW50VHlwZSA9IHJlcXVlc3QuaGVhZGVyc1snY29udGVudC10eXBlJ10gfHwgJyc7XHJcblxyXG4gICAgLy8gQWxsb3cgb25seSBKU09OLCBVUkwtZW5jb2RlZCBhbmQgZm9ybSBkYXRhIHdpdGhvdXQgZmlsZXMgdHlwZXMgb2YgZGF0YVxyXG4gICAgaWYgKFxyXG4gICAgICAhY29udGVudFR5cGUuaW5jbHVkZXMoJ2FwcGxpY2F0aW9uL2pzb24nKSAmJlxyXG4gICAgICAhY29udGVudFR5cGUuaW5jbHVkZXMoJ2FwcGxpY2F0aW9uL3gtd3d3LWZvcm0tdXJsZW5jb2RlZCcpICYmXHJcbiAgICAgICFjb250ZW50VHlwZS5pbmNsdWRlcygnbXVsdGlwYXJ0L2Zvcm0tZGF0YScpXHJcbiAgICApIHtcclxuICAgICAgdGhyb3cgbmV3IEV4cG9ydEVycm9yKFxyXG4gICAgICAgICdbdmFsaWRhdGlvbl0gQ29udGVudC1UeXBlIG11c3QgYmUgYXBwbGljYXRpb24vanNvbiwgYXBwbGljYXRpb24veC13d3ctZm9ybS11cmxlbmNvZGVkLCBvciBtdWx0aXBhcnQvZm9ybS1kYXRhLicsXHJcbiAgICAgICAgNDE1XHJcbiAgICAgICk7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gQ2FsbCB0aGUgYHJlcXVlc3RCb2R5TWlkZGxld2FyZWAgbWlkZGxld2FyZVxyXG4gICAgcmV0dXJuIG5leHQoKTtcclxuICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgcmV0dXJuIG5leHQoZXJyb3IpO1xyXG4gIH1cclxufVxyXG5cclxuLyoqXHJcbiAqIE1pZGRsZXdhcmUgZm9yIHZhbGlkYXRpbmcgdGhlIHJlcXVlc3QncyBib2R5LlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gcmVxdWVzdEJvZHlNaWRkbGV3YXJlXHJcbiAqXHJcbiAqIEBwYXJhbSB7RXhwcmVzcy5SZXF1ZXN0fSByZXF1ZXN0IC0gVGhlIEV4cHJlc3MgcmVxdWVzdCBvYmplY3QuXHJcbiAqIEBwYXJhbSB7RXhwcmVzcy5SZXNwb25zZX0gcmVzcG9uc2UgLSBUaGUgRXhwcmVzcyByZXNwb25zZSBvYmplY3QuXHJcbiAqIEBwYXJhbSB7RnVuY3Rpb259IG5leHQgLSBUaGUgbmV4dCBtaWRkbGV3YXJlIGZ1bmN0aW9uLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7dW5kZWZpbmVkfSBUaGUgY2FsbCB0byB0aGUgbmV4dCBtaWRkbGV3YXJlIGZ1bmN0aW9uLlxyXG4gKlxyXG4gKiBAdGhyb3dzIHtFeHBvcnRFcnJvcn0gVGhyb3dzIGFuIGBFeHBvcnRFcnJvcmAgaWYgdGhlIGJvZHkgaXMgbm90IGNvcnJlY3QuXHJcbiAqIEB0aHJvd3Mge0V4cG9ydEVycm9yfSBUaHJvd3MgYW4gYEV4cG9ydEVycm9yYCBpZiB0aGUgY2hhcnQgZGF0YSBmcm9tIHRoZSBib2R5XHJcbiAqIGlzIG5vdCBjb3JyZWN0LlxyXG4gKiBAdGhyb3dzIHtFeHBvcnRFcnJvcn0gVGhyb3dzIGFuIGBFeHBvcnRFcnJvcmAgaW4gY2FzZSBvZiB0aGUgcHJpdmF0ZSByYW5nZVxyXG4gKiB1cmwgZXJyb3IuXHJcbiAqL1xyXG5mdW5jdGlvbiByZXF1ZXN0Qm9keU1pZGRsZXdhcmUocmVxdWVzdCwgcmVzcG9uc2UsIG5leHQpIHtcclxuICB0cnkge1xyXG4gICAgLy8gR2V0IHRoZSByZXF1ZXN0IGJvZHlcclxuICAgIGNvbnN0IGJvZHkgPSByZXF1ZXN0LmJvZHk7XHJcblxyXG4gICAgLy8gQ3JlYXRlIGEgdW5pcXVlIElEIGZvciBhIHJlcXVlc3RcclxuICAgIGNvbnN0IHJlcXVlc3RJZCA9IHV1aWQoKTtcclxuXHJcbiAgICAvLyBUaHJvdyBhbiBlcnJvciBpZiB0aGVyZSBpcyBubyBjb3JyZWN0IGJvZHlcclxuICAgIGlmICghYm9keSB8fCBpc09iamVjdEVtcHR5KGJvZHkpKSB7XHJcbiAgICAgIGxvZyhcclxuICAgICAgICAyLFxyXG4gICAgICAgIGBbdmFsaWRhdGlvbl0gUmVxdWVzdCBbJHtyZXF1ZXN0SWR9XSAtIFRoZSByZXF1ZXN0IGZyb20gJHtcclxuICAgICAgICAgIHJlcXVlc3QuaGVhZGVyc1sneC1mb3J3YXJkZWQtZm9yJ10gfHwgcmVxdWVzdC5jb25uZWN0aW9uLnJlbW90ZUFkZHJlc3NcclxuICAgICAgICB9IHdhcyBpbmNvcnJlY3QuIFJlY2VpdmVkIHBheWxvYWQgaXMgZW1wdHkuYFxyXG4gICAgICApO1xyXG5cclxuICAgICAgdGhyb3cgbmV3IEV4cG9ydEVycm9yKFxyXG4gICAgICAgIGBbdmFsaWRhdGlvbl0gUmVxdWVzdCBbJHtyZXF1ZXN0SWR9XSAtIFRoZSByZXF1ZXN0IGJvZHkgaXMgcmVxdWlyZWQuIFBsZWFzZSBlbnN1cmUgdGhhdCB5b3VyIENvbnRlbnQtVHlwZSBoZWFkZXIgaXMgY29ycmVjdC4gQWNjZXB0ZWQgdHlwZXMgYXJlICdhcHBsaWNhdGlvbi9qc29uJyBhbmQgJ211bHRpcGFydC9mb3JtLWRhdGEnLmAsXHJcbiAgICAgICAgNDAwXHJcbiAgICAgICk7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gR2V0IHRoZSBgYWxsb3dDb2RlRXhlY3V0aW9uYCBvcHRpb24gZm9yIHRoZSBzZXJ2ZXJcclxuICAgIGNvbnN0IGFsbG93Q29kZUV4ZWN1dGlvbiA9IGdldEFsbG93Q29kZUV4ZWN1dGlvbigpO1xyXG5cclxuICAgIC8vIEZpbmQgYSBjb3JyZWN0IGNoYXJ0IG9wdGlvbnNcclxuICAgIGNvbnN0IGluc3RyID0gaXNBbGxvd2VkQ29uZmlnKFxyXG4gICAgICAvLyBVc2Ugb25lIG9mIHRoZSBiZWxvd1xyXG4gICAgICBib2R5Lmluc3RyIHx8IGJvZHkub3B0aW9ucyB8fCBib2R5LmluZmlsZSB8fCBib2R5LmRhdGEsXHJcbiAgICAgIC8vIFN0cmluZ2lmeSBvcHRpb25zXHJcbiAgICAgIHRydWUsXHJcbiAgICAgIC8vIEFsbG93IG9yIGRpc2FsbG93IGZ1bmN0aW9uc1xyXG4gICAgICBhbGxvd0NvZGVFeGVjdXRpb25cclxuICAgICk7XHJcblxyXG4gICAgLy8gVGhyb3cgYW4gZXJyb3IgaWYgdGhlcmUgaXMgbm8gY29ycmVjdCBjaGFydCBkYXRhXHJcbiAgICBpZiAoaW5zdHIgPT09IG51bGwgJiYgIWJvZHkuc3ZnKSB7XHJcbiAgICAgIGxvZyhcclxuICAgICAgICAyLFxyXG4gICAgICAgIGBbdmFsaWRhdGlvbl0gUmVxdWVzdCBbJHtyZXF1ZXN0SWR9XSAtIFRoZSByZXF1ZXN0IGZyb20gJHtcclxuICAgICAgICAgIHJlcXVlc3QuaGVhZGVyc1sneC1mb3J3YXJkZWQtZm9yJ10gfHwgcmVxdWVzdC5jb25uZWN0aW9uLnJlbW90ZUFkZHJlc3NcclxuICAgICAgICB9IHdhcyBpbmNvcnJlY3QuIFJlY2VpdmVkIHBheWxvYWQgaXMgbWlzc2luZyBjb3JyZWN0IGNoYXJ0IGRhdGEgZm9yIGV4cG9ydDogJHtKU09OLnN0cmluZ2lmeShib2R5KX0uYFxyXG4gICAgICApO1xyXG5cclxuICAgICAgdGhyb3cgbmV3IEV4cG9ydEVycm9yKFxyXG4gICAgICAgIGBSZXF1ZXN0IFske3JlcXVlc3RJZH1dIC0gW3ZhbGlkYXRpb25dIE5vIGNvcnJlY3QgY2hhcnQgZGF0YSBmb3VuZC4gRW5zdXJlIHRoYXQgeW91IGFyZSB1c2luZyBlaXRoZXIgYXBwbGljYXRpb24vanNvbiBvciBtdWx0aXBhcnQvZm9ybS1kYXRhIGhlYWRlcnMuIElmIHNlbmRpbmcgSlNPTiwgbWFrZSBzdXJlIHRoZSBjaGFydCBkYXRhIGlzIGluIHRoZSAnaW5maWxlJywgJ29wdGlvbnMnLCBvciAnZGF0YScgYXR0cmlidXRlLiBJZiBzZW5kaW5nIFNWRywgZW5zdXJlIGl0IGlzIGluIHRoZSAnc3ZnJyBhdHRyaWJ1dGUuYCxcclxuICAgICAgICA0MDBcclxuICAgICAgKTtcclxuICAgIH1cclxuXHJcbiAgICAvLyBUaHJvdyBhbiBlcnJvciBpZiB0ZXN0IG9mIHhsaW5rOmhyZWYgZWxlbWVudHMgZnJvbSBwYXlsb2FkJ3MgU1ZHIGZhaWxzXHJcbiAgICBpZiAoYm9keS5zdmcgJiYgaXNQcml2YXRlUmFuZ2VVcmxGb3VuZChib2R5LnN2ZykpIHtcclxuICAgICAgdGhyb3cgbmV3IEV4cG9ydEVycm9yKFxyXG4gICAgICAgIGBSZXF1ZXN0IFske3JlcXVlc3RJZH1dIC0gW3ZhbGlkYXRpb25dIFNWRyBwb3RlbnRpYWxseSBjb250YWluIGF0IGxlYXN0IG9uZSBmb3JiaWRkZW4gVVJMIGluICd4bGluazpocmVmJyBlbGVtZW50LiBQbGVhc2UgcmV2aWV3IHRoZSBTVkcgY29udGVudCBhbmQgZW5zdXJlIHRoYXQgYWxsIHJlZmVyZW5jZWQgVVJMcyBjb21wbHkgd2l0aCBzZWN1cml0eSBwb2xpY2llcy5gLFxyXG4gICAgICAgIDQwMFxyXG4gICAgICApO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIFZhbGlkYXRlIHRoZSByZXF1ZXN0IG9wdGlvbnMgYW5kIHN0b3JlIHBhcnNlZCBzdHJ1Y3R1cmUgaW4gdGhlIHJlcXVlc3RcclxuICAgIHJlcXVlc3QudmFsaWRhdGVkT3B0aW9ucyA9IHZhbGlkYXRlT3B0aW9ucyh7XHJcbiAgICAgIC8vIFNldCB0aGUgY3JlYXRlZCBJRCBhcyBhIGByZXF1ZXN0SWRgIHByb3BlcnR5IGluIHRoZSBvcHRpb25zXHJcbiAgICAgIHJlcXVlc3RJZCxcclxuICAgICAgZXhwb3J0OiB7XHJcbiAgICAgICAgaW5zdHIsXHJcbiAgICAgICAgc3ZnOiBib2R5LnN2ZyxcclxuICAgICAgICBvdXRmaWxlOlxyXG4gICAgICAgICAgYm9keS5vdXRmaWxlIHx8XHJcbiAgICAgICAgICBgJHtyZXF1ZXN0LnBhcmFtcy5maWxlbmFtZSB8fCAnY2hhcnQnfS4ke2JvZHkudHlwZSB8fCAncG5nJ31gLFxyXG4gICAgICAgIHR5cGU6IGJvZHkudHlwZSxcclxuICAgICAgICBjb25zdHI6IGJvZHkuY29uc3RyLFxyXG4gICAgICAgIGI2NDogYm9keS5iNjQsXHJcbiAgICAgICAgbm9Eb3dubG9hZDogYm9keS5ub0Rvd25sb2FkLFxyXG4gICAgICAgIGhlaWdodDogYm9keS5oZWlnaHQsXHJcbiAgICAgICAgd2lkdGg6IGJvZHkud2lkdGgsXHJcbiAgICAgICAgc2NhbGU6IGJvZHkuc2NhbGUsXHJcbiAgICAgICAgZ2xvYmFsT3B0aW9uczogaXNBbGxvd2VkQ29uZmlnKFxyXG4gICAgICAgICAgYm9keS5nbG9iYWxPcHRpb25zLFxyXG4gICAgICAgICAgdHJ1ZSxcclxuICAgICAgICAgIGFsbG93Q29kZUV4ZWN1dGlvblxyXG4gICAgICAgICksXHJcbiAgICAgICAgdGhlbWVPcHRpb25zOiBpc0FsbG93ZWRDb25maWcoXHJcbiAgICAgICAgICBib2R5LnRoZW1lT3B0aW9ucyxcclxuICAgICAgICAgIHRydWUsXHJcbiAgICAgICAgICBhbGxvd0NvZGVFeGVjdXRpb25cclxuICAgICAgICApXHJcbiAgICAgIH0sXHJcbiAgICAgIGN1c3RvbUxvZ2ljOiB7XHJcbiAgICAgICAgYWxsb3dDb2RlRXhlY3V0aW9uLFxyXG4gICAgICAgIGFsbG93RmlsZVJlc291cmNlczogZmFsc2UsXHJcbiAgICAgICAgY3VzdG9tQ29kZTogYm9keS5jdXN0b21Db2RlLFxyXG4gICAgICAgIGNhbGxiYWNrOiBib2R5LmNhbGxiYWNrLFxyXG4gICAgICAgIHJlc291cmNlczogaXNBbGxvd2VkQ29uZmlnKGJvZHkucmVzb3VyY2VzLCB0cnVlLCBhbGxvd0NvZGVFeGVjdXRpb24pXHJcbiAgICAgIH1cclxuICAgIH0pO1xyXG5cclxuICAgIC8vIENhbGwgdGhlIG5leHQgbWlkZGxld2FyZVxyXG4gICAgcmV0dXJuIG5leHQoKTtcclxuICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgcmV0dXJuIG5leHQoZXJyb3IpO1xyXG4gIH1cclxufVxyXG5cclxuLyoqXHJcbiAqIEFkZHMgdGhlIHZhbGlkYXRpb24gbWlkZGxld2FyZXMgdG8gdGhlIHBhc3NlZCBleHByZXNzIGFwcCBpbnN0YW5jZS5cclxuICpcclxuICogQHBhcmFtIHtFeHByZXNzfSBhcHAgLSBUaGUgRXhwcmVzcyBhcHAgaW5zdGFuY2UuXHJcbiAqL1xyXG5leHBvcnQgZGVmYXVsdCBmdW5jdGlvbiB2YWxpZGF0aW9uTWlkZGxld2FyZShhcHApIHtcclxuICAvLyBBZGQgY29udGVudCB0eXBlIHZhbGlkYXRpb24gbWlkZGxld2FyZVxyXG4gIGFwcC5wb3N0KFsnLycsICcvOmZpbGVuYW1lJ10sIGNvbnRlbnRUeXBlTWlkZGxld2FyZSk7XHJcblxyXG4gIC8vIEFkZCByZXF1ZXN0IGJvZHkgcmVxdWVzdCB2YWxpZGF0aW9uIG1pZGRsZXdhcmVcclxuICBhcHAucG9zdChbJy8nLCAnLzpmaWxlbmFtZSddLCByZXF1ZXN0Qm9keU1pZGRsZXdhcmUpO1xyXG59XHJcbiIsIi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXHJcblxyXG5IaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXJcclxuXHJcbkNvcHlyaWdodCAoYykgMjAxNi0yMDI1LCBIaWdoc29mdFxyXG5cclxuTGljZW5jZWQgdW5kZXIgdGhlIE1JVCBsaWNlbmNlLlxyXG5cclxuQWRkaXRpb25hbGx5IGEgdmFsaWQgSGlnaGNoYXJ0cyBsaWNlbnNlIGlzIHJlcXVpcmVkIGZvciB1c2UuXHJcblxyXG5TZWUgTElDRU5TRSBmaWxlIGluIHJvb3QgZm9yIGRldGFpbHMuXHJcblxyXG4qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xyXG5cclxuLyoqXHJcbiAqIEBvdmVydmlldyBEZWZpbmVzIHRoZSBleHBvcnQgcm91dGVzIGFuZCBsb2dpYyBmb3IgaGFuZGxpbmcgY2hhcnQgZXhwb3J0XHJcbiAqIHJlcXVlc3RzIGluIGFuIEV4cHJlc3Mgc2VydmVyLiBUaGlzIG1vZHVsZSBwcm9jZXNzZXMgaW5jb21pbmcgcmVxdWVzdHNcclxuICogdG8gZXhwb3J0IGNoYXJ0cyBpbiB2YXJpb3VzIGZvcm1hdHMgKGUuZy4gSlBFRywgUE5HLCBQREYsIFNWRykuIEl0IGludGVncmF0ZXNcclxuICogd2l0aCBIaWdoY2hhcnRzJyBjb3JlIGZ1bmN0aW9uYWxpdGllcyBhbmQgc3VwcG9ydHMgYm90aCBpbW1lZGlhdGUgZG93bmxvYWRcclxuICogcmVzcG9uc2VzIGFuZCBCYXNlNjQtZW5jb2RlZCBjb250ZW50IHJldHVybnMuIFRoZSBjb2RlIGFsc28gZmVhdHVyZXNcclxuICogYmVuY2htYXJraW5nIGZvciBwZXJmb3JtYW5jZSBtb25pdG9yaW5nLlxyXG4gKi9cclxuXHJcbmltcG9ydCB7IHN0YXJ0RXhwb3J0IH0gZnJvbSAnLi4vLi4vY2hhcnQuanMnO1xyXG5pbXBvcnQgeyBsb2cgfSBmcm9tICcuLi8uLi9sb2dnZXIuanMnO1xyXG5pbXBvcnQgeyBnZXRCYXNlNjQsIG1lYXN1cmVUaW1lIH0gZnJvbSAnLi4vLi4vdXRpbHMuanMnO1xyXG5cclxuaW1wb3J0IEV4cG9ydEVycm9yIGZyb20gJy4uLy4uL2Vycm9ycy9FeHBvcnRFcnJvci5qcyc7XHJcblxyXG4vLyBSZXZlcnNlZCBNSU1FIHR5cGVzXHJcbmNvbnN0IHJldmVyc2VkTWltZSA9IHtcclxuICBwbmc6ICdpbWFnZS9wbmcnLFxyXG4gIGpwZWc6ICdpbWFnZS9qcGVnJyxcclxuICBnaWY6ICdpbWFnZS9naWYnLFxyXG4gIHBkZjogJ2FwcGxpY2F0aW9uL3BkZicsXHJcbiAgc3ZnOiAnaW1hZ2Uvc3ZnK3htbCdcclxufTtcclxuXHJcbi8qKlxyXG4gKiBIYW5kbGVzIHRoZSBleHBvcnQgcmVxdWVzdHMgZnJvbSB0aGUgY2xpZW50LlxyXG4gKlxyXG4gKiBAYXN5bmNcclxuICogQGZ1bmN0aW9uIHJlcXVlc3RFeHBvcnRcclxuICpcclxuICogQHBhcmFtIHtFeHByZXNzLlJlcXVlc3R9IHJlcXVlc3QgLSBUaGUgRXhwcmVzcyByZXF1ZXN0IG9iamVjdC5cclxuICogQHBhcmFtIHtFeHByZXNzLlJlc3BvbnNlfSByZXNwb25zZSAtIFRoZSBFeHByZXNzIHJlc3BvbnNlIG9iamVjdC5cclxuICogQHBhcmFtIHtGdW5jdGlvbn0gbmV4dCAtIFRoZSBuZXh0IG1pZGRsZXdhcmUgZnVuY3Rpb24uXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtQcm9taXNlPHZvaWQ+fSBBIFByb21pc2UgdGhhdCByZXNvbHZlcyBvbmNlIHRoZSBleHBvcnQgcHJvY2Vzc1xyXG4gKiBpcyBjb21wbGV0ZS5cclxuICovXHJcbmFzeW5jIGZ1bmN0aW9uIHJlcXVlc3RFeHBvcnQocmVxdWVzdCwgcmVzcG9uc2UsIG5leHQpIHtcclxuICB0cnkge1xyXG4gICAgLy8gU3RhcnQgY291bnRpbmcgdGltZSBmb3IgYSByZXF1ZXN0XHJcbiAgICBjb25zdCByZXF1ZXN0Q291bnRlciA9IG1lYXN1cmVUaW1lKCk7XHJcblxyXG4gICAgLy8gSW4gY2FzZSB0aGUgY29ubmVjdGlvbiBpcyBjbG9zZWQsIGZvcmNlIHRvIGFib3J0IGZ1cnRoZXIgYWN0aW9uc1xyXG4gICAgbGV0IGNvbm5lY3Rpb25BYm9ydGVkID0gZmFsc2U7XHJcbiAgICByZXF1ZXN0LnNvY2tldC5vbignY2xvc2UnLCAoaGFkRXJyb3JzKSA9PiB7XHJcbiAgICAgIGlmIChoYWRFcnJvcnMpIHtcclxuICAgICAgICBjb25uZWN0aW9uQWJvcnRlZCA9IHRydWU7XHJcbiAgICAgIH1cclxuICAgIH0pO1xyXG5cclxuICAgIC8vIEdldCB0aGUgb3B0aW9ucyBwcmV2aW91c2x5IHZhbGlkYXRlZCBpbiB0aGUgdmFsaWRhdGlvbiBtaWRkbGV3YXJlXHJcbiAgICBjb25zdCByZXF1ZXN0T3B0aW9ucyA9IHJlcXVlc3QudmFsaWRhdGVkT3B0aW9ucztcclxuXHJcbiAgICAvLyBHZXQgdGhlIHJlcXVlc3QgaWRcclxuICAgIGNvbnN0IHJlcXVlc3RJZCA9IHJlcXVlc3RPcHRpb25zLnJlcXVlc3RJZDtcclxuXHJcbiAgICAvLyBJbmZvIGFib3V0IGFuIGluY29taW5nIHJlcXVlc3Qgd2l0aCBjb3JyZWN0IGRhdGFcclxuICAgIGxvZyg0LCBgW2V4cG9ydF0gUmVxdWVzdCBbJHtyZXF1ZXN0SWR9XSAtIEdvdCBhbiBpbmNvbWluZyBIVFRQIHJlcXVlc3QuYCk7XHJcblxyXG4gICAgLy8gU3RhcnQgdGhlIGV4cG9ydCBwcm9jZXNzXHJcbiAgICBhd2FpdCBzdGFydEV4cG9ydChyZXF1ZXN0T3B0aW9ucywgKGVycm9yLCBkYXRhKSA9PiB7XHJcbiAgICAgIC8vIFJlbW92ZSB0aGUgY2xvc2UgZXZlbnQgZnJvbSB0aGUgc29ja2V0XHJcbiAgICAgIHJlcXVlc3Quc29ja2V0LnJlbW92ZUFsbExpc3RlbmVycygnY2xvc2UnKTtcclxuXHJcbiAgICAgIC8vIElmIHRoZSBjb25uZWN0aW9uIHdhcyBjbG9zZWQsIGRvIG5vdGhpbmdcclxuICAgICAgaWYgKGNvbm5lY3Rpb25BYm9ydGVkKSB7XHJcbiAgICAgICAgbG9nKFxyXG4gICAgICAgICAgMyxcclxuICAgICAgICAgIGBbZXhwb3J0XSBSZXF1ZXN0IFske3JlcXVlc3RJZH1dIC0gVGhlIGNsaWVudCBjbG9zZWQgdGhlIGNvbm5lY3Rpb24gYmVmb3JlIHRoZSBjaGFydCBmaW5pc2hlZCBwcm9jZXNzaW5nLmBcclxuICAgICAgICApO1xyXG4gICAgICAgIHJldHVybjtcclxuICAgICAgfVxyXG5cclxuICAgICAgLy8gSWYgZXJyb3IsIGxvZyBpdCBhbmQgc2VuZCBpdCB0byB0aGUgZXJyb3IgbWlkZGxld2FyZVxyXG4gICAgICBpZiAoZXJyb3IpIHtcclxuICAgICAgICB0aHJvdyBlcnJvcjtcclxuICAgICAgfVxyXG5cclxuICAgICAgLy8gSWYgZGF0YSBpcyBtaXNzaW5nLCBsb2cgdGhlIG1lc3NhZ2UgYW5kIHNlbmQgaXQgdG8gdGhlIGVycm9yIG1pZGRsZXdhcmVcclxuICAgICAgaWYgKCFkYXRhIHx8ICFkYXRhLnJlc3VsdCkge1xyXG4gICAgICAgIGxvZyhcclxuICAgICAgICAgIDIsXHJcbiAgICAgICAgICBgW2V4cG9ydF0gUmVxdWVzdCBbJHtyZXF1ZXN0SWR9XSAtIFJlcXVlc3QgZnJvbSAke1xyXG4gICAgICAgICAgICByZXF1ZXN0LmhlYWRlcnNbJ3gtZm9yd2FyZGVkLWZvciddIHx8XHJcbiAgICAgICAgICAgIHJlcXVlc3QuY29ubmVjdGlvbi5yZW1vdGVBZGRyZXNzXHJcbiAgICAgICAgICB9IHdhcyBpbmNvcnJlY3QuIFJlY2VpdmVkIHJlc3VsdCBpcyAke2RhdGEucmVzdWx0fS5gXHJcbiAgICAgICAgKTtcclxuXHJcbiAgICAgICAgdGhyb3cgbmV3IEV4cG9ydEVycm9yKFxyXG4gICAgICAgICAgYFtleHBvcnRdIFJlcXVlc3QgWyR7cmVxdWVzdElkfV0gLSBVbmV4cGVjdGVkIHJldHVybiBvZiB0aGUgZXhwb3J0IHJlc3VsdCBmcm9tIHRoZSBjaGFydCBnZW5lcmF0aW9uLiBQbGVhc2UgY2hlY2sgeW91ciByZXF1ZXN0IGRhdGEuYCxcclxuICAgICAgICAgIDQwMFxyXG4gICAgICAgICk7XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIC8vIFJldHVybiB0aGUgcmVzdWx0IGluIGFuIGFwcHJvcHJpYXRlIGZvcm1hdFxyXG4gICAgICBpZiAoZGF0YS5yZXN1bHQpIHtcclxuICAgICAgICBsb2coXHJcbiAgICAgICAgICAzLFxyXG4gICAgICAgICAgYFtleHBvcnRdIFJlcXVlc3QgWyR7cmVxdWVzdElkfV0gLSBUaGUgd2hvbGUgZXhwb3J0aW5nIHByb2Nlc3MgdG9vayAke3JlcXVlc3RDb3VudGVyKCl9bXMuYFxyXG4gICAgICAgICk7XHJcblxyXG4gICAgICAgIC8vIEdldCB0aGUgYHR5cGVgLCBgYjY0YCwgYG5vRG93bmxvYWRgLCBhbmQgYG91dGZpbGVgIGZyb20gb3B0aW9uc1xyXG4gICAgICAgIGNvbnN0IHsgdHlwZSwgYjY0LCBub0Rvd25sb2FkLCBvdXRmaWxlIH0gPSBkYXRhLm9wdGlvbnMuZXhwb3J0O1xyXG5cclxuICAgICAgICAvLyBJZiBvbmx5IEJhc2U2NCBpcyByZXF1aXJlZCwgcmV0dXJuIGl0XHJcbiAgICAgICAgaWYgKGI2NCkge1xyXG4gICAgICAgICAgcmV0dXJuIHJlc3BvbnNlLnNlbmQoZ2V0QmFzZTY0KGRhdGEucmVzdWx0LCB0eXBlKSk7XHJcbiAgICAgICAgfVxyXG5cclxuICAgICAgICAvLyBTZXQgY29ycmVjdCBjb250ZW50IHR5cGVcclxuICAgICAgICByZXNwb25zZS5oZWFkZXIoJ0NvbnRlbnQtVHlwZScsIHJldmVyc2VkTWltZVt0eXBlXSB8fCAnaW1hZ2UvcG5nJyk7XHJcblxyXG4gICAgICAgIC8vIERlY2lkZSB3aGV0aGVyIHRvIGRvd25sb2FkIG9yIG5vdCBjaGFydCBmaWxlXHJcbiAgICAgICAgaWYgKCFub0Rvd25sb2FkKSB7XHJcbiAgICAgICAgICByZXNwb25zZS5hdHRhY2htZW50KG91dGZpbGUpO1xyXG4gICAgICAgIH1cclxuXHJcbiAgICAgICAgLy8gSWYgU1ZHLCByZXR1cm4gcGxhaW4gY29udGVudCwgb3RoZXJ3aXNlIGEgYjY0IHN0cmluZyBmcm9tIGEgYnVmZmVyXHJcbiAgICAgICAgcmV0dXJuIHR5cGUgPT09ICdzdmcnXHJcbiAgICAgICAgICA/IHJlc3BvbnNlLnNlbmQoZGF0YS5yZXN1bHQpXHJcbiAgICAgICAgICA6IHJlc3BvbnNlLnNlbmQoQnVmZmVyLmZyb20oZGF0YS5yZXN1bHQsICdiYXNlNjQnKSk7XHJcbiAgICAgIH1cclxuICAgIH0pO1xyXG4gIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICByZXR1cm4gbmV4dChlcnJvcik7XHJcbiAgfVxyXG59XHJcblxyXG4vKipcclxuICogQWRkcyB0aGUgYGV4cG9ydGAgcm91dGVzLlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gZXhwb3J0Um91dGVzXHJcbiAqXHJcbiAqIEBwYXJhbSB7RXhwcmVzc30gYXBwIC0gVGhlIEV4cHJlc3MgYXBwIGluc3RhbmNlLlxyXG4gKi9cclxuZXhwb3J0IGRlZmF1bHQgZnVuY3Rpb24gZXhwb3J0Um91dGVzKGFwcCkge1xyXG4gIC8qKlxyXG4gICAqIEFkZHMgdGhlIFBPU1QgJy8nIC0gQSByb3V0ZSBmb3IgaGFuZGxpbmcgUE9TVCByZXF1ZXN0cyBhdCB0aGUgcm9vdFxyXG4gICAqIGVuZHBvaW50LlxyXG4gICAqL1xyXG4gIGFwcC5wb3N0KCcvJywgcmVxdWVzdEV4cG9ydCk7XHJcblxyXG4gIC8qKlxyXG4gICAqIEFkZHMgdGhlIFBPU1QgJy86ZmlsZW5hbWUnIC0gQSByb3V0ZSBmb3IgaGFuZGxpbmcgUE9TVCByZXF1ZXN0cyB3aXRoXHJcbiAgICogYSBzcGVjaWZpZWQgZmlsZW5hbWUgcGFyYW1ldGVyLlxyXG4gICAqL1xyXG4gIGFwcC5wb3N0KCcvOmZpbGVuYW1lJywgcmVxdWVzdEV4cG9ydCk7XHJcbn1cclxuIiwiLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcclxuXHJcbkhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlclxyXG5cclxuQ29weXJpZ2h0IChjKSAyMDE2LTIwMjUsIEhpZ2hzb2Z0XHJcblxyXG5MaWNlbmNlZCB1bmRlciB0aGUgTUlUIGxpY2VuY2UuXHJcblxyXG5BZGRpdGlvbmFsbHkgYSB2YWxpZCBIaWdoY2hhcnRzIGxpY2Vuc2UgaXMgcmVxdWlyZWQgZm9yIHVzZS5cclxuXHJcblNlZSBMSUNFTlNFIGZpbGUgaW4gcm9vdCBmb3IgZGV0YWlscy5cclxuXHJcbioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXHJcblxyXG4vKipcclxuICogQG92ZXJ2aWV3IERlZmluZXMgYW4gRXhwcmVzcyByb3V0ZSBmb3Igc2VydmVyIGhlYWx0aCBtb25pdG9yaW5nLCBpbmNsdWRpbmdcclxuICogdXB0aW1lLCBzdWNjZXNzIHJhdGVzLCBhbmQgb3RoZXIgc2VydmVyIHN0YXRpc3RpY3MuXHJcbiAqL1xyXG5cclxuaW1wb3J0IHsgcmVhZEZpbGVTeW5jIH0gZnJvbSAnZnMnO1xyXG5pbXBvcnQgeyBqb2luIH0gZnJvbSAncGF0aCc7XHJcblxyXG5pbXBvcnQgeyBnZXRIaWdoY2hhcnRzVmVyc2lvbiB9IGZyb20gJy4uLy4uL2NhY2hlLmpzJztcclxuaW1wb3J0IHsgbG9nIH0gZnJvbSAnLi4vLi4vbG9nZ2VyLmpzJztcclxuaW1wb3J0IHsgZ2V0UG9vbFN0YXRzLCBnZXRQb29sSW5mb0pTT04gfSBmcm9tICcuLi8uLi9wb29sLmpzJztcclxuaW1wb3J0IHsgYWRkVGltZXIgfSBmcm9tICcuLi8uLi90aW1lci5qcyc7XHJcbmltcG9ydCB7IF9fZGlybmFtZSwgZ2V0TmV3RGF0ZVRpbWUgfSBmcm9tICcuLi8uLi91dGlscy5qcyc7XHJcblxyXG4vLyBTZXQgdGhlIHN0YXJ0IGRhdGUgb2YgdGhlIHNlcnZlclxyXG5jb25zdCBzZXJ2ZXJTdGFydFRpbWUgPSBuZXcgRGF0ZSgpO1xyXG5cclxuLy8gR2V0IHRoZSBgcGFja2FnZS5qc29uYCBjb250ZW50XHJcbmNvbnN0IHBhY2thZ2VGaWxlID0gSlNPTi5wYXJzZShcclxuICByZWFkRmlsZVN5bmMoam9pbihfX2Rpcm5hbWUsICdwYWNrYWdlLmpzb24nKSwgJ3V0ZjgnKVxyXG4pO1xyXG5cclxuLy8gQW4gYXJyYXkgZm9yIHN1Y2Nlc3MgcmF0ZSByYXRpb3NcclxuY29uc3Qgc3VjY2Vzc1JhdGVzID0gW107XHJcblxyXG4vLyBSZWNvcmQgZXZlcnkgbWludXRlXHJcbmNvbnN0IHJlY29yZEludGVydmFsID0gNjAgKiAxMDAwO1xyXG5cclxuLy8gMzAgbWludXRlc1xyXG5jb25zdCB3aW5kb3dTaXplID0gMzA7XHJcblxyXG4vKipcclxuICogQ2FsY3VsYXRlcyBtb3ZpbmcgYXZlcmFnZSBpbmRpY2F0b3IgYmFzZWQgb24gdGhlIGRhdGEgZnJvbSB0aGUgYHN1Y2Nlc3NSYXRlc2BcclxuICogYXJyYXkuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBfY2FsY3VsYXRlTW92aW5nQXZlcmFnZVxyXG4gKlxyXG4gKiBAcmV0dXJucyB7bnVtYmVyfSBBIG1vdmluZyBhdmVyYWdlIGZvciBzdWNjZXNzIHJhdGlvIG9mIHRoZSBzZXJ2ZXIgZXhwb3J0cy5cclxuICovXHJcbmZ1bmN0aW9uIF9jYWxjdWxhdGVNb3ZpbmdBdmVyYWdlKCkge1xyXG4gIHJldHVybiBzdWNjZXNzUmF0ZXMucmVkdWNlKChhLCBiKSA9PiBhICsgYiwgMCkgLyBzdWNjZXNzUmF0ZXMubGVuZ3RoO1xyXG59XHJcblxyXG4vKipcclxuICogU3RhcnRzIHRoZSBpbnRlcnZhbCByZXNwb25zaWJsZSBmb3IgY2FsY3VsYXRpbmcgY3VycmVudCBzdWNjZXNzIHJhdGUgcmF0aW9cclxuICogYW5kIGNvbGxlY3RzIHJlY29yZHMgdG8gdGhlIGBzdWNjZXNzUmF0ZXNgIGFycmF5LlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gX3N0YXJ0U3VjY2Vzc1JhdGVcclxuICpcclxuICogQHJldHVybnMge05vZGVKUy5UaW1lb3V0fSBJZCBvZiBhbiBpbnRlcnZhbC5cclxuICovXHJcbmZ1bmN0aW9uIF9zdGFydFN1Y2Nlc3NSYXRlKCkge1xyXG4gIHJldHVybiBzZXRJbnRlcnZhbCgoKSA9PiB7XHJcbiAgICBjb25zdCBzdGF0cyA9IGdldFBvb2xTdGF0cygpO1xyXG4gICAgY29uc3Qgc3VjY2Vzc1JhdGlvID1cclxuICAgICAgc3RhdHMuZXhwb3J0c0F0dGVtcHRlZCA9PT0gMFxyXG4gICAgICAgID8gMVxyXG4gICAgICAgIDogKHN0YXRzLmV4cG9ydHNQZXJmb3JtZWQgLyBzdGF0cy5leHBvcnRzQXR0ZW1wdGVkKSAqIDEwMDtcclxuXHJcbiAgICBzdWNjZXNzUmF0ZXMucHVzaChzdWNjZXNzUmF0aW8pO1xyXG4gICAgaWYgKHN1Y2Nlc3NSYXRlcy5sZW5ndGggPiB3aW5kb3dTaXplKSB7XHJcbiAgICAgIHN1Y2Nlc3NSYXRlcy5zaGlmdCgpO1xyXG4gICAgfVxyXG4gIH0sIHJlY29yZEludGVydmFsKTtcclxufVxyXG5cclxuLyoqXHJcbiAqIEFkZHMgdGhlIGBoZWFsdGhgIHJvdXRlcy5cclxuICpcclxuICogQGZ1bmN0aW9uIGhlYWx0aFJvdXRlc1xyXG4gKlxyXG4gKiBAcGFyYW0ge0V4cHJlc3N9IGFwcCAtIFRoZSBFeHByZXNzIGFwcCBpbnN0YW5jZS5cclxuICovXHJcbmV4cG9ydCBkZWZhdWx0IGZ1bmN0aW9uIGhlYWx0aFJvdXRlcyhhcHApIHtcclxuICAvLyBTdGFydCBwcm9jZXNzaW5nIHN1Y2Nlc3MgcmF0ZSByYXRpbyBpbnRlcnZhbCBhbmQgc2F2ZSBpdHMgaWQgdG8gdGhlIGFycmF5XHJcbiAgLy8gZm9yIHRoZSBncmFjZWZ1bCBjbGVhcmluZyBvbiBzaHV0ZG93biB3aXRoIGluamVjdGVkIGBhZGRUaW1lcmAgZnVudGlvblxyXG4gIGFkZFRpbWVyKF9zdGFydFN1Y2Nlc3NSYXRlKCkpO1xyXG5cclxuICAvKipcclxuICAgKiBBZGRzIHRoZSBHRVQgJy9oZWFsdGgnIC0gQSByb3V0ZSBmb3IgZ2V0dGluZyB0aGUgYmFzaWMgc3RhdHMgb2YgdGhlIHNlcnZlci5cclxuICAgKi9cclxuICBhcHAuZ2V0KCcvaGVhbHRoJywgKHJlcXVlc3QsIHJlc3BvbnNlLCBuZXh0KSA9PiB7XHJcbiAgICB0cnkge1xyXG4gICAgICBsb2coNCwgJ1toZWFsdGhdIFJldHVybmluZyBzZXJ2ZXIgaGVhbHRoLicpO1xyXG5cclxuICAgICAgY29uc3Qgc3RhdHMgPSBnZXRQb29sU3RhdHMoKTtcclxuICAgICAgY29uc3QgcGVyaW9kID0gc3VjY2Vzc1JhdGVzLmxlbmd0aDtcclxuICAgICAgY29uc3QgbW92aW5nQXZlcmFnZSA9IF9jYWxjdWxhdGVNb3ZpbmdBdmVyYWdlKCk7XHJcblxyXG4gICAgICAvLyBTZW5kIHRoZSBzZXJ2ZXIncyBzdGF0aXN0aWNzXHJcbiAgICAgIHJlc3BvbnNlLnNlbmQoe1xyXG4gICAgICAgIC8vIFN0YXR1cyBhbmQgdGltZXNcclxuICAgICAgICBzdGF0dXM6ICdPSycsXHJcbiAgICAgICAgYm9vdFRpbWU6IHNlcnZlclN0YXJ0VGltZSxcclxuICAgICAgICB1cHRpbWU6IGAke01hdGguZmxvb3IoKGdldE5ld0RhdGVUaW1lKCkgLSBzZXJ2ZXJTdGFydFRpbWUuZ2V0VGltZSgpKSAvIDEwMDAgLyA2MCl9IG1pbnV0ZXNgLFxyXG5cclxuICAgICAgICAvLyBWZXJzaW9uc1xyXG4gICAgICAgIHNlcnZlclZlcnNpb246IHBhY2thZ2VGaWxlLnZlcnNpb24sXHJcbiAgICAgICAgaGlnaGNoYXJ0c1ZlcnNpb246IGdldEhpZ2hjaGFydHNWZXJzaW9uKCksXHJcblxyXG4gICAgICAgIC8vIEV4cG9ydHNcclxuICAgICAgICBhdmVyYWdlRXhwb3J0VGltZTogc3RhdHMudGltZVNwZW50QXZlcmFnZSxcclxuICAgICAgICBhdHRlbXB0ZWRFeHBvcnRzOiBzdGF0cy5leHBvcnRzQXR0ZW1wdGVkLFxyXG4gICAgICAgIHBlcmZvcm1lZEV4cG9ydHM6IHN0YXRzLmV4cG9ydHNQZXJmb3JtZWQsXHJcbiAgICAgICAgZmFpbGVkRXhwb3J0czogc3RhdHMuZXhwb3J0c0Ryb3BwZWQsXHJcbiAgICAgICAgc3VjZXNzUmF0aW86IChzdGF0cy5leHBvcnRzUGVyZm9ybWVkIC8gc3RhdHMuZXhwb3J0c0F0dGVtcHRlZCkgKiAxMDAsXHJcblxyXG4gICAgICAgIC8vIFBvb2xcclxuICAgICAgICBwb29sOiBnZXRQb29sSW5mb0pTT04oKSxcclxuXHJcbiAgICAgICAgLy8gTW92aW5nIGF2ZXJhZ2VcclxuICAgICAgICBwZXJpb2QsXHJcbiAgICAgICAgbW92aW5nQXZlcmFnZSxcclxuICAgICAgICBtZXNzYWdlOlxyXG4gICAgICAgICAgaXNOYU4obW92aW5nQXZlcmFnZSkgfHwgIXN1Y2Nlc3NSYXRlcy5sZW5ndGhcclxuICAgICAgICAgICAgPyAnVG9vIGVhcmx5IHRvIHJlcG9ydC4gTm8gZXhwb3J0cyBtYWRlIHlldC4gUGxlYXNlIGNoZWNrIGJhY2sgc29vbi4nXHJcbiAgICAgICAgICAgIDogYExhc3QgJHtwZXJpb2R9IG1pbnV0ZXMgaGFkIGEgc3VjY2VzcyByYXRlIG9mICR7bW92aW5nQXZlcmFnZS50b0ZpeGVkKDIpfSUuYCxcclxuXHJcbiAgICAgICAgLy8gU1ZHIGFuZCBKU09OIGV4cG9ydHNcclxuICAgICAgICBzdmdFeHBvcnRzOiBzdGF0cy5leHBvcnRzRnJvbVN2ZyxcclxuICAgICAgICBqc29uRXhwb3J0czogc3RhdHMuZXhwb3J0c0Zyb21PcHRpb25zLFxyXG4gICAgICAgIHN2Z0V4cG9ydHNBdHRlbXB0czogc3RhdHMuZXhwb3J0c0Zyb21TdmdBdHRlbXB0cyxcclxuICAgICAgICBqc29uRXhwb3J0c0F0dGVtcHRzOiBzdGF0cy5leHBvcnRzRnJvbU9wdGlvbnNBdHRlbXB0c1xyXG4gICAgICB9KTtcclxuICAgIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICAgIHJldHVybiBuZXh0KGVycm9yKTtcclxuICAgIH1cclxuICB9KTtcclxufVxyXG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxyXG5cclxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXHJcblxyXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNSwgSGlnaHNvZnRcclxuXHJcbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cclxuXHJcbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxyXG5cclxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxyXG5cclxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cclxuXHJcbi8qKlxyXG4gKiBAb3ZlcnZpZXcgRGVmaW5lcyBhbiBFeHByZXNzIHJvdXRlIGZvciBzZXJ2aW5nIHRoZSBVSSBmb3IgdGhlIGV4cG9ydCBzZXJ2ZXJcclxuICogd2hlbiBlbmFibGVkLlxyXG4gKi9cclxuXHJcbmltcG9ydCB7IGpvaW4gfSBmcm9tICdwYXRoJztcclxuXHJcbmltcG9ydCB7IGdldE9wdGlvbnMgfSBmcm9tICcuLi8uLi9jb25maWcuanMnO1xyXG5pbXBvcnQgeyBsb2cgfSBmcm9tICcuLi8uLi9sb2dnZXIuanMnO1xyXG5pbXBvcnQgeyBfX2Rpcm5hbWUgfSBmcm9tICcuLi8uLi91dGlscy5qcyc7XHJcblxyXG4vKipcclxuICogQWRkcyB0aGUgYHVpYCByb3V0ZXMuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiB1aVJvdXRlc1xyXG4gKlxyXG4gKiBAcGFyYW0ge0V4cHJlc3N9IGFwcCAtIFRoZSBFeHByZXNzIGFwcCBpbnN0YW5jZS5cclxuICovXHJcbmV4cG9ydCBkZWZhdWx0IGZ1bmN0aW9uIHVpUm91dGVzKGFwcCkge1xyXG4gIC8qKlxyXG4gICAqIEFkZHMgdGhlIEdFVCAnLycgLSBBIHJvdXRlIGZvciBhIFVJIHdoZW4gZW5hYmxlZCBvbiB0aGUgZXhwb3J0IHNlcnZlci5cclxuICAgKi9cclxuICBhcHAuZ2V0KGdldE9wdGlvbnMoKS51aS5yb3V0ZSB8fCAnLycsIChyZXF1ZXN0LCByZXNwb25zZSwgbmV4dCkgPT4ge1xyXG4gICAgdHJ5IHtcclxuICAgICAgbG9nKDQsICdbdWldIFJldHVybmluZyBVSSBmb3IgdGhlIGV4cG9ydC4nKTtcclxuXHJcbiAgICAgIHJlc3BvbnNlLnNlbmRGaWxlKGpvaW4oX19kaXJuYW1lLCAncHVibGljJywgJ2luZGV4Lmh0bWwnKSwge1xyXG4gICAgICAgIGFjY2VwdFJhbmdlczogZmFsc2VcclxuICAgICAgfSk7XHJcbiAgICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgICByZXR1cm4gbmV4dChlcnJvcik7XHJcbiAgICB9XHJcbiAgfSk7XHJcbn1cclxuIiwiLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcclxuXHJcbkhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlclxyXG5cclxuQ29weXJpZ2h0IChjKSAyMDE2LTIwMjUsIEhpZ2hzb2Z0XHJcblxyXG5MaWNlbmNlZCB1bmRlciB0aGUgTUlUIGxpY2VuY2UuXHJcblxyXG5BZGRpdGlvbmFsbHkgYSB2YWxpZCBIaWdoY2hhcnRzIGxpY2Vuc2UgaXMgcmVxdWlyZWQgZm9yIHVzZS5cclxuXHJcblNlZSBMSUNFTlNFIGZpbGUgaW4gcm9vdCBmb3IgZGV0YWlscy5cclxuXHJcbioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXHJcblxyXG4vKipcclxuICogQG92ZXJ2aWV3IERlZmluZXMgYW4gRXhwcmVzcyByb3V0ZSBmb3IgdXBkYXRpbmcgdGhlIEhpZ2hjaGFydHMgdmVyc2lvblxyXG4gKiBvbiB0aGUgc2VydmVyLCB3aXRoIGF1dGhlbnRpY2F0aW9uIGFuZCB2YWxpZGF0aW9uLlxyXG4gKi9cclxuXHJcbmltcG9ydCB7IHVwZGF0ZUhpZ2hjaGFydHNWZXJzaW9uLCBnZXRIaWdoY2hhcnRzVmVyc2lvbiB9IGZyb20gJy4uLy4uL2NhY2hlLmpzJztcclxuaW1wb3J0IHsgdmFsaWRhdGVPcHRpb24gfSBmcm9tICcuLi8uLi9jb25maWcuanMnO1xyXG5pbXBvcnQgeyBsb2cgfSBmcm9tICcuLi8uLi9sb2dnZXIuanMnO1xyXG5pbXBvcnQgeyBlbnZzIH0gZnJvbSAnLi4vLi4vdmFsaWRhdGlvbi5qcyc7XHJcblxyXG5pbXBvcnQgRXhwb3J0RXJyb3IgZnJvbSAnLi4vLi4vZXJyb3JzL0V4cG9ydEVycm9yLmpzJztcclxuXHJcbi8qKlxyXG4gKiBBZGRzIHRoZSBgdmVyc2lvbl9jaGFuZ2VgIHJvdXRlcy5cclxuICpcclxuICogQGZ1bmN0aW9uIHZlcnNpb25DaGFuZ2VSb3V0ZXNcclxuICpcclxuICogQHBhcmFtIHtFeHByZXNzfSBhcHAgLSBUaGUgRXhwcmVzcyBhcHAgaW5zdGFuY2UuXHJcbiAqL1xyXG5leHBvcnQgZGVmYXVsdCBmdW5jdGlvbiB2ZXJzaW9uQ2hhbmdlUm91dGVzKGFwcCkge1xyXG4gIC8qKlxyXG4gICAqIEFkZHMgdGhlIFBPU1QgJy92ZXJzaW9uX2NoYW5nZS86bmV3VmVyc2lvbicgLSBBIHJvdXRlIGZvciBjaGFuZ2luZ1xyXG4gICAqIHRoZSBIaWdoY2hhcnRzIHZlcnNpb24gb24gdGhlIHNlcnZlci5cclxuICAgKi9cclxuICBhcHAucG9zdCgnL3ZlcnNpb25fY2hhbmdlLzpuZXdWZXJzaW9uJywgYXN5bmMgKHJlcXVlc3QsIHJlc3BvbnNlLCBuZXh0KSA9PiB7XHJcbiAgICB0cnkge1xyXG4gICAgICBsb2coNCwgJ1t2ZXJzaW9uXSBDaGFuZ2luZyBIaWdoY2hhcnRzIHZlcnNpb24uJyk7XHJcblxyXG4gICAgICAvLyBHZXQgdGhlIHRva2VuIGRpcmVjdGx5IGZyb20gZW52c1xyXG4gICAgICBjb25zdCBhZG1pblRva2VuID0gZW52cy5ISUdIQ0hBUlRTX0FETUlOX1RPS0VOO1xyXG5cclxuICAgICAgLy8gQ2hlY2sgdGhlIGV4aXN0ZW5jZSBvZiB0aGUgdG9rZW5cclxuICAgICAgaWYgKCFhZG1pblRva2VuIHx8ICFhZG1pblRva2VuLmxlbmd0aCkge1xyXG4gICAgICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcihcclxuICAgICAgICAgICdbdmVyc2lvbl0gVGhlIHNlcnZlciBpcyBub3QgY29uZmlndXJlZCB0byBwZXJmb3JtIHJ1bi10aW1lIHZlcnNpb24gY2hhbmdlczogSElHSENIQVJUU19BRE1JTl9UT0tFTiBpcyBub3Qgc2V0LicsXHJcbiAgICAgICAgICA0MDFcclxuICAgICAgICApO1xyXG4gICAgICB9XHJcblxyXG4gICAgICAvLyBHZXQgdGhlIHRva2VuIGZyb20gdGhlIGhjLWF1dGggaGVhZGVyXHJcbiAgICAgIGNvbnN0IHRva2VuID0gcmVxdWVzdC5nZXQoJ2hjLWF1dGgnKTtcclxuXHJcbiAgICAgIC8vIENoZWNrIGlmIHRoZSBoYy1hdXRoIGhlYWRlciBjb250YWluIGEgY29ycmVjdCB0b2tlblxyXG4gICAgICBpZiAoIXRva2VuIHx8IHRva2VuICE9PSBhZG1pblRva2VuKSB7XHJcbiAgICAgICAgdGhyb3cgbmV3IEV4cG9ydEVycm9yKFxyXG4gICAgICAgICAgJ1t2ZXJzaW9uXSBJbnZhbGlkIG9yIG1pc3NpbmcgdG9rZW46IFNldCB0aGUgdG9rZW4gaW4gdGhlIGhjLWF1dGggaGVhZGVyLicsXHJcbiAgICAgICAgICA0MDFcclxuICAgICAgICApO1xyXG4gICAgICB9XHJcblxyXG4gICAgICAvLyBDb21wYXJlIHZlcnNpb25zXHJcbiAgICAgIGxldCBuZXdWZXJzaW9uID0gcmVxdWVzdC5wYXJhbXMubmV3VmVyc2lvbjtcclxuXHJcbiAgICAgIC8vIFZhbGlkYXRlIHRoZSB2ZXJzaW9uXHJcbiAgICAgIHRyeSB7XHJcbiAgICAgICAgbmV3VmVyc2lvbiA9IHZhbGlkYXRlT3B0aW9uKCd2ZXJzaW9uJywgcmVxdWVzdC5wYXJhbXMubmV3VmVyc2lvbik7XHJcbiAgICAgIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICAgICAgdGhyb3cgbmV3IEV4cG9ydEVycm9yKFxyXG4gICAgICAgICAgYFt2ZXJzaW9uXSBWZXJzaW9uIGlzIGluY29ycmVjdDogJHtlcnJvci5tZXNzYWdlfWAsXHJcbiAgICAgICAgICA0MDBcclxuICAgICAgICApLnNldEVycm9yKGVycm9yKTtcclxuICAgICAgfVxyXG5cclxuICAgICAgLy8gV2hlbiBhIGNvcnJlY3QgdmFsdWUgZm91bmRcclxuICAgICAgaWYgKG5ld1ZlcnNpb24pIHtcclxuICAgICAgICB0cnkge1xyXG4gICAgICAgICAgLy8gVXBkYXRlIHZlcnNpb25cclxuICAgICAgICAgIGF3YWl0IHVwZGF0ZUhpZ2hjaGFydHNWZXJzaW9uKG5ld1ZlcnNpb24pO1xyXG4gICAgICAgIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICAgICAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoXHJcbiAgICAgICAgICAgIGBbdmVyc2lvbl0gVmVyc2lvbiBjaGFuZ2U6ICR7ZXJyb3IubWVzc2FnZX1gLFxyXG4gICAgICAgICAgICA0MDBcclxuICAgICAgICAgICkuc2V0RXJyb3IoZXJyb3IpO1xyXG4gICAgICAgIH1cclxuXHJcbiAgICAgICAgLy8gU3VjY2Vzc1xyXG4gICAgICAgIHJlc3BvbnNlLnN0YXR1cygyMDApLnNlbmQoe1xyXG4gICAgICAgICAgc3RhdHVzQ29kZTogMjAwLFxyXG4gICAgICAgICAgaGlnaGNoYXJ0c1ZlcnNpb246IGdldEhpZ2hjaGFydHNWZXJzaW9uKCksXHJcbiAgICAgICAgICBtZXNzYWdlOiBgU3VjY2Vzc2Z1bGx5IHVwZGF0ZWQgSGlnaGNoYXJ0cyB0byB2ZXJzaW9uOiAke25ld1ZlcnNpb259LmBcclxuICAgICAgICB9KTtcclxuICAgICAgfSBlbHNlIHtcclxuICAgICAgICAvLyBObyB2ZXJzaW9uIHNwZWNpZmllZFxyXG4gICAgICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcignW3ZlcnNpb25dIE5vIG5ldyB2ZXJzaW9uIHN1cHBsaWVkLicsIDQwMCk7XHJcbiAgICAgIH1cclxuICAgIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICAgIHJldHVybiBuZXh0KGVycm9yKTtcclxuICAgIH1cclxuICB9KTtcclxufVxyXG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxyXG5cclxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXHJcblxyXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNSwgSGlnaHNvZnRcclxuXHJcbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cclxuXHJcbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxyXG5cclxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxyXG5cclxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cclxuXHJcbi8qKlxyXG4gKiBAb3ZlcnZpZXcgQSBtb2R1bGUgdGhhdCBzZXRzIHVwIGFuZCBtYW5hZ2VzIEhUVFAgYW5kIEhUVFBTIHNlcnZlcnNcclxuICogZm9yIHRoZSBIaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXIuIEl0IGhhbmRsZXMgc2VydmVyIGluaXRpYWxpemF0aW9uLFxyXG4gKiBjb25maWd1cmF0aW9uLCBlcnJvciBoYW5kbGluZywgbWlkZGxld2FyZSBzZXR1cCwgcm91dGUgZGVmaW5pdGlvbiwgYW5kIHJhdGVcclxuICogbGltaXRpbmcuIFRoZSBtb2R1bGUgZXhwb3J0cyBmdW5jdGlvbnMgdG8gc3RhcnQsIHN0b3AsIGFuZCBtYW5hZ2Ugc2VydmVyXHJcbiAqIGluc3RhbmNlcywgYXMgd2VsbCBhcyB1dGlsaXR5IGZ1bmN0aW9ucyBmb3IgZGVmaW5pbmcgcm91dGVzIGFuZCBhdHRhY2hpbmdcclxuICogbWlkZGxld2FyZXMuXHJcbiAqL1xyXG5cclxuaW1wb3J0IHsgcmVhZEZpbGUgfSBmcm9tICdmcy9wcm9taXNlcyc7XHJcbmltcG9ydCB7IGpvaW4gfSBmcm9tICdwYXRoJztcclxuXHJcbmltcG9ydCBjb3JzIGZyb20gJ2NvcnMnO1xyXG5pbXBvcnQgZXhwcmVzcyBmcm9tICdleHByZXNzJztcclxuaW1wb3J0IGh0dHAgZnJvbSAnaHR0cCc7XHJcbmltcG9ydCBodHRwcyBmcm9tICdodHRwcyc7XHJcbmltcG9ydCBtdWx0ZXIgZnJvbSAnbXVsdGVyJztcclxuXHJcbmltcG9ydCB7IHVwZGF0ZU9wdGlvbnMsIHZhbGlkYXRlT3B0aW9ucyB9IGZyb20gJy4uL2NvbmZpZy5qcyc7XHJcbmltcG9ydCB7IGxvZywgbG9nV2l0aFN0YWNrIH0gZnJvbSAnLi4vbG9nZ2VyLmpzJztcclxuaW1wb3J0IHsgX19kaXJuYW1lLCBnZXRBYnNvbHV0ZVBhdGggfSBmcm9tICcuLi91dGlscy5qcyc7XHJcblxyXG5pbXBvcnQgZXJyb3JNaWRkbGV3YXJlIGZyb20gJy4vbWlkZGxld2FyZXMvZXJyb3IuanMnO1xyXG5pbXBvcnQgcmF0ZUxpbWl0aW5nTWlkZGxld2FyZSBmcm9tICcuL21pZGRsZXdhcmVzL3JhdGVMaW1pdGluZy5qcyc7XHJcbmltcG9ydCB2YWxpZGF0aW9uTWlkZGxld2FyZSBmcm9tICcuL21pZGRsZXdhcmVzL3ZhbGlkYXRpb24uanMnO1xyXG5cclxuaW1wb3J0IGV4cG9ydFJvdXRlcyBmcm9tICcuL3JvdXRlcy9leHBvcnQuanMnO1xyXG5pbXBvcnQgaGVhbHRoUm91dGVzIGZyb20gJy4vcm91dGVzL2hlYWx0aC5qcyc7XHJcbmltcG9ydCB1aVJvdXRlcyBmcm9tICcuL3JvdXRlcy91aS5qcyc7XHJcbmltcG9ydCB2ZXJzaW9uQ2hhbmdlUm91dGVzIGZyb20gJy4vcm91dGVzL3ZlcnNpb25DaGFuZ2UuanMnO1xyXG5cclxuaW1wb3J0IEV4cG9ydEVycm9yIGZyb20gJy4uL2Vycm9ycy9FeHBvcnRFcnJvci5qcyc7XHJcblxyXG4vLyBBcnJheSBvZiBhbiBhY3RpdmUgc2VydmVyc1xyXG5jb25zdCBhY3RpdmVTZXJ2ZXJzID0gbmV3IE1hcCgpO1xyXG5cclxuLy8gQ3JlYXRlIGV4cHJlc3MgYXBwXHJcbmNvbnN0IGFwcCA9IGV4cHJlc3MoKTtcclxuXHJcbi8qKlxyXG4gKiBTdGFydHMgYW4gSFRUUCBhbmQvb3IgSFRUUFMgc2VydmVyIGJhc2VkIG9uIHRoZSBwcm92aWRlZCBjb25maWd1cmF0aW9uLlxyXG4gKiBUaGUgYHNlcnZlck9wdGlvbnNgIG9iamVjdCBjb250YWlucyBzZXJ2ZXItcmVsYXRlZCBwcm9wZXJ0aWVzIChyZWZlclxyXG4gKiB0byB0aGUgYHNlcnZlcmAgc2VjdGlvbiBpbiB0aGUgYGxpYi9zY2hlbWFzL2NvbmZpZy5qc2AgZmlsZSBmb3IgZGV0YWlscykuXHJcbiAqXHJcbiAqIEBhc3luY1xyXG4gKiBAZnVuY3Rpb24gc3RhcnRTZXJ2ZXJcclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IHNlcnZlck9wdGlvbnMgLSBUaGUgY29uZmlndXJhdGlvbiBvYmplY3QgY29udGFpbmluZyBgc2VydmVyYFxyXG4gKiBvcHRpb25zLiBUaGlzIG9iamVjdCBtYXkgaW5jbHVkZSBhIHBhcnRpYWwgb3IgY29tcGxldGUgc2V0IG9mIHRoZSBgc2VydmVyYFxyXG4gKiBvcHRpb25zLiBJZiB0aGUgb3B0aW9ucyBhcmUgcGFydGlhbCwgbWlzc2luZyB2YWx1ZXMgd2lsbCBkZWZhdWx0XHJcbiAqIHRvIHRoZSBjdXJyZW50IGdsb2JhbCBjb25maWd1cmF0aW9uLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7UHJvbWlzZTx2b2lkPn0gQSBQcm9taXNlIHRoYXQgcmVzb2x2ZXMgd2hlbiB0aGUgc2VydmVyIGlzIGVpdGhlclxyXG4gKiBub3QgZW5hYmxlZCBvciBubyB2YWxpZCBFeHByZXNzIGFwcCBpcyBmb3VuZCwgc2lnbmFsaW5nIHRoZSBlbmQgb2YgdGhlXHJcbiAqIGZ1bmN0aW9uJ3MgZXhlY3V0aW9uLlxyXG4gKlxyXG4gKiBAdGhyb3dzIHtFeHBvcnRFcnJvcn0gVGhyb3dzIGFuIGBFeHBvcnRFcnJvcmAgaWYgdGhlIHNlcnZlciBjYW5ub3RcclxuICogYmUgY29uZmlndXJlZCBhbmQgc3RhcnRlZC5cclxuICovXHJcbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBzdGFydFNlcnZlcihzZXJ2ZXJPcHRpb25zKSB7XHJcbiAgdHJ5IHtcclxuICAgIC8vIFVwZGF0ZSB0aGUgaW5zdGFuY2Ugb3B0aW9ucyBvYmplY3RcclxuICAgIGNvbnN0IG9wdGlvbnMgPSB1cGRhdGVPcHRpb25zKFxyXG4gICAgICB2YWxpZGF0ZU9wdGlvbnMoe1xyXG4gICAgICAgIHNlcnZlcjogc2VydmVyT3B0aW9uc1xyXG4gICAgICB9KVxyXG4gICAgKTtcclxuXHJcbiAgICAvLyBVc2UgdmFsaWRhdGVkIG9wdGlvbnNcclxuICAgIHNlcnZlck9wdGlvbnMgPSBvcHRpb25zLnNlcnZlcjtcclxuXHJcbiAgICAvLyBTdG9wIGlmIG5vdCBlbmFibGVkXHJcbiAgICBpZiAoIXNlcnZlck9wdGlvbnMuZW5hYmxlIHx8ICFhcHApIHtcclxuICAgICAgdGhyb3cgbmV3IEV4cG9ydEVycm9yKFxyXG4gICAgICAgICdbc2VydmVyXSBTZXJ2ZXIgY2Fubm90IGJlIHN0YXJ0ZWQgKG5vdCBlbmFibGVkIG9yIG5vIGNvcnJlY3QgRXhwcmVzcyBhcHAgZm91bmQpLicsXHJcbiAgICAgICAgNTAwXHJcbiAgICAgICk7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gVG9vIGJpZyBsaW1pdHMgbGVhZCB0byB0aW1lb3V0cyBpbiB0aGUgZXhwb3J0IHByb2Nlc3Mgd2hlblxyXG4gICAgLy8gdGhlIHJhc3Rlcml6YXRpb24gdGltZW91dCBpcyBzZXQgdG9vIGxvd1xyXG4gICAgY29uc3QgdXBsb2FkTGltaXRCeXRlcyA9IHNlcnZlck9wdGlvbnMudXBsb2FkTGltaXQgKiAxMDI0ICogMTAyNDtcclxuXHJcbiAgICAvLyBNZW1vcnkgc3RvcmFnZSBmb3IgbXVsdGVyIHBhY2thZ2VcclxuICAgIGNvbnN0IHN0b3JhZ2UgPSBtdWx0ZXIubWVtb3J5U3RvcmFnZSgpO1xyXG5cclxuICAgIC8vIEVuYWJsZSBwYXJzaW5nIG9mIGZvcm0gZGF0YSAoZmlsZXMpIHdpdGggbXVsdGVyIHBhY2thZ2VcclxuICAgIGNvbnN0IHVwbG9hZCA9IG11bHRlcih7XHJcbiAgICAgIHN0b3JhZ2UsXHJcbiAgICAgIGxpbWl0czoge1xyXG4gICAgICAgIGZpZWxkU2l6ZTogdXBsb2FkTGltaXRCeXRlc1xyXG4gICAgICB9XHJcbiAgICB9KTtcclxuXHJcbiAgICAvLyBEaXNhYmxlIHRoZSBYLVBvd2VyZWQtQnkgaGVhZGVyXHJcbiAgICBhcHAuZGlzYWJsZSgneC1wb3dlcmVkLWJ5Jyk7XHJcblxyXG4gICAgLy8gRW5hYmxlIENPUlMgc3VwcG9ydFxyXG4gICAgYXBwLnVzZShcclxuICAgICAgY29ycyh7XHJcbiAgICAgICAgbWV0aG9kczogWydQT1NUJywgJ0dFVCcsICdPUFRJT05TJ11cclxuICAgICAgfSlcclxuICAgICk7XHJcblxyXG4gICAgLy8gR2V0dGluZyBhIGxvdCBvZiBgUmFuZ2VOb3RTYXRpc2ZpYWJsZUVycm9yYCBleGNlcHRpb25zIChldmVuIHRob3VnaCB0aGlzXHJcbiAgICAvLyBpcyBhIGRlcHJlY2F0ZWQgb3B0aW9ucywgbGV0J3MgdHJ5IHRvIHNldCBpdCB0byBmYWxzZSlcclxuICAgIGFwcC51c2UoKHJlcXVlc3QsIHJlc3BvbnNlLCBuZXh0KSA9PiB7XHJcbiAgICAgIHJlc3BvbnNlLnNldCgnQWNjZXB0LVJhbmdlcycsICdub25lJyk7XHJcbiAgICAgIG5leHQoKTtcclxuICAgIH0pO1xyXG5cclxuICAgIC8vIEVuYWJsZSBib2R5IHBhcnNlciBmb3IgSlNPTiBkYXRhXHJcbiAgICBhcHAudXNlKFxyXG4gICAgICBleHByZXNzLmpzb24oe1xyXG4gICAgICAgIGxpbWl0OiB1cGxvYWRMaW1pdEJ5dGVzXHJcbiAgICAgIH0pXHJcbiAgICApO1xyXG5cclxuICAgIC8vIEVuYWJsZSBib2R5IHBhcnNlciBmb3IgVVJMLWVuY29kZWQgZm9ybSBkYXRhXHJcbiAgICBhcHAudXNlKFxyXG4gICAgICBleHByZXNzLnVybGVuY29kZWQoe1xyXG4gICAgICAgIGV4dGVuZGVkOiB0cnVlLFxyXG4gICAgICAgIGxpbWl0OiB1cGxvYWRMaW1pdEJ5dGVzXHJcbiAgICAgIH0pXHJcbiAgICApO1xyXG5cclxuICAgIC8vIFVzZSBvbmx5IG5vbi1maWxlIG11bHRpcGFydCBmb3JtIGZpZWxkc1xyXG4gICAgYXBwLnVzZSh1cGxvYWQubm9uZSgpKTtcclxuXHJcbiAgICAvLyBTZXQgdXAgc3RhdGljIGZvbGRlcidzIHJvdXRlXHJcbiAgICBhcHAudXNlKGV4cHJlc3Muc3RhdGljKGpvaW4oX19kaXJuYW1lLCAncHVibGljJykpKTtcclxuXHJcbiAgICAvLyBMaXN0ZW4gSFRUUCBzZXJ2ZXJcclxuICAgIGlmICghc2VydmVyT3B0aW9ucy5zc2wuZm9yY2UpIHtcclxuICAgICAgLy8gTWFpbiBzZXJ2ZXIgaW5zdGFuY2UgKEhUVFApXHJcbiAgICAgIGNvbnN0IGh0dHBTZXJ2ZXIgPSBodHRwLmNyZWF0ZVNlcnZlcihhcHApO1xyXG5cclxuICAgICAgLy8gQXR0YWNoIGVycm9yIGhhbmRsZXJzIGFuZCBsaXN0ZW4gdG8gdGhlIHNlcnZlclxyXG4gICAgICBfYXR0YWNoU2VydmVyRXJyb3JIYW5kbGVycyhodHRwU2VydmVyKTtcclxuXHJcbiAgICAgIC8vIExpc3RlblxyXG4gICAgICBodHRwU2VydmVyLmxpc3RlbihzZXJ2ZXJPcHRpb25zLnBvcnQsIHNlcnZlck9wdGlvbnMuaG9zdCwgKCkgPT4ge1xyXG4gICAgICAgIC8vIFNhdmUgdGhlIHJlZmVyZW5jZSB0byBIVFRQIHNlcnZlclxyXG4gICAgICAgIGFjdGl2ZVNlcnZlcnMuc2V0KHNlcnZlck9wdGlvbnMucG9ydCwgaHR0cFNlcnZlcik7XHJcblxyXG4gICAgICAgIGxvZyhcclxuICAgICAgICAgIDMsXHJcbiAgICAgICAgICBgW3NlcnZlcl0gU3RhcnRlZCBIVFRQIHNlcnZlciBvbiAke3NlcnZlck9wdGlvbnMuaG9zdH06JHtzZXJ2ZXJPcHRpb25zLnBvcnR9LmBcclxuICAgICAgICApO1xyXG4gICAgICB9KTtcclxuICAgIH1cclxuXHJcbiAgICAvLyBMaXN0ZW4gSFRUUFMgc2VydmVyXHJcbiAgICBpZiAoc2VydmVyT3B0aW9ucy5zc2wuZW5hYmxlKSB7XHJcbiAgICAgIC8vIFNldCB1cCBhbiBTU0wgc2VydmVyIGFsc29cclxuICAgICAgbGV0IGtleSwgY2VydDtcclxuXHJcbiAgICAgIHRyeSB7XHJcbiAgICAgICAgLy8gR2V0IHRoZSBTU0wga2V5XHJcbiAgICAgICAga2V5ID0gYXdhaXQgcmVhZEZpbGUoXHJcbiAgICAgICAgICBqb2luKGdldEFic29sdXRlUGF0aChzZXJ2ZXJPcHRpb25zLnNzbC5jZXJ0UGF0aCksICdzZXJ2ZXIua2V5JyksXHJcbiAgICAgICAgICAndXRmOCdcclxuICAgICAgICApO1xyXG5cclxuICAgICAgICAvLyBHZXQgdGhlIFNTTCBjZXJ0aWZpY2F0ZVxyXG4gICAgICAgIGNlcnQgPSBhd2FpdCByZWFkRmlsZShcclxuICAgICAgICAgIGpvaW4oZ2V0QWJzb2x1dGVQYXRoKHNlcnZlck9wdGlvbnMuc3NsLmNlcnRQYXRoKSwgJ3NlcnZlci5jcnQnKSxcclxuICAgICAgICAgICd1dGY4J1xyXG4gICAgICAgICk7XHJcbiAgICAgIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICAgICAgbG9nKFxyXG4gICAgICAgICAgMixcclxuICAgICAgICAgIGBbc2VydmVyXSBVbmFibGUgdG8gbG9hZCBrZXkvY2VydGlmaWNhdGUgZnJvbSB0aGUgJyR7c2VydmVyT3B0aW9ucy5zc2wuY2VydFBhdGh9JyBwYXRoLiBDb3VsZCBub3QgcnVuIHNlY3VyZWQgbGF5ZXIgc2VydmVyLmBcclxuICAgICAgICApO1xyXG4gICAgICB9XHJcblxyXG4gICAgICBpZiAoa2V5ICYmIGNlcnQpIHtcclxuICAgICAgICAvLyBNYWluIHNlcnZlciBpbnN0YW5jZSAoSFRUUFMpXHJcbiAgICAgICAgY29uc3QgaHR0cHNTZXJ2ZXIgPSBodHRwcy5jcmVhdGVTZXJ2ZXIoeyBrZXksIGNlcnQgfSwgYXBwKTtcclxuXHJcbiAgICAgICAgLy8gQXR0YWNoIGVycm9yIGhhbmRsZXJzIGFuZCBsaXN0ZW4gdG8gdGhlIHNlcnZlclxyXG4gICAgICAgIF9hdHRhY2hTZXJ2ZXJFcnJvckhhbmRsZXJzKGh0dHBzU2VydmVyKTtcclxuXHJcbiAgICAgICAgLy8gTGlzdGVuXHJcbiAgICAgICAgaHR0cHNTZXJ2ZXIubGlzdGVuKHNlcnZlck9wdGlvbnMuc3NsLnBvcnQsIHNlcnZlck9wdGlvbnMuaG9zdCwgKCkgPT4ge1xyXG4gICAgICAgICAgLy8gU2F2ZSB0aGUgcmVmZXJlbmNlIHRvIEhUVFBTIHNlcnZlclxyXG4gICAgICAgICAgYWN0aXZlU2VydmVycy5zZXQoc2VydmVyT3B0aW9ucy5zc2wucG9ydCwgaHR0cHNTZXJ2ZXIpO1xyXG5cclxuICAgICAgICAgIGxvZyhcclxuICAgICAgICAgICAgMyxcclxuICAgICAgICAgICAgYFtzZXJ2ZXJdIFN0YXJ0ZWQgSFRUUFMgc2VydmVyIG9uICR7c2VydmVyT3B0aW9ucy5ob3N0fToke3NlcnZlck9wdGlvbnMuc3NsLnBvcnR9LmBcclxuICAgICAgICAgICk7XHJcbiAgICAgICAgfSk7XHJcbiAgICAgIH1cclxuICAgIH1cclxuXHJcbiAgICAvLyBTZXQgdXAgdGhlIHJhdGUgbGltaXRlclxyXG4gICAgcmF0ZUxpbWl0aW5nTWlkZGxld2FyZShhcHAsIHNlcnZlck9wdGlvbnMucmF0ZUxpbWl0aW5nKTtcclxuXHJcbiAgICAvLyBTZXQgdXAgdGhlIHZhbGlkYXRpb24gaGFuZGxlclxyXG4gICAgdmFsaWRhdGlvbk1pZGRsZXdhcmUoYXBwKTtcclxuXHJcbiAgICAvLyBTZXQgdXAgcm91dGVzXHJcbiAgICBleHBvcnRSb3V0ZXMoYXBwKTtcclxuICAgIGhlYWx0aFJvdXRlcyhhcHApO1xyXG4gICAgdWlSb3V0ZXMoYXBwKTtcclxuICAgIHZlcnNpb25DaGFuZ2VSb3V0ZXMoYXBwKTtcclxuXHJcbiAgICAvLyBTZXQgdXAgdGhlIGNlbnRyYWxpemVkIGVycm9yIGhhbmRsZXJcclxuICAgIGVycm9yTWlkZGxld2FyZShhcHApO1xyXG4gIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoXHJcbiAgICAgICdbc2VydmVyXSBDb3VsZCBub3QgY29uZmlndXJlIGFuZCBzdGFydCB0aGUgc2VydmVyLicsXHJcbiAgICAgIDUwMFxyXG4gICAgKS5zZXRFcnJvcihlcnJvcik7XHJcbiAgfVxyXG59XHJcblxyXG4vKipcclxuICogQ2xvc2VzIGFsbCBzZXJ2ZXJzIGFzc29jaWF0ZWQgd2l0aCBFeHByZXNzIGFwcCBpbnN0YW5jZS5cclxuICpcclxuICogQGZ1bmN0aW9uIGNsb3NlU2VydmVyc1xyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIGNsb3NlU2VydmVycygpIHtcclxuICAvLyBDaGVjayBpZiB0aGVyZSBhcmUgc2VydmVycyB3b3JraW5nXHJcbiAgaWYgKGFjdGl2ZVNlcnZlcnMuc2l6ZSA+IDApIHtcclxuICAgIGxvZyg0LCBgW3NlcnZlcl0gQ2xvc2luZyBhbGwgc2VydmVycy5gKTtcclxuXHJcbiAgICAvLyBDbG9zZSBlYWNoIG9uZSBvZiBzZXJ2ZXJzXHJcbiAgICBmb3IgKGNvbnN0IFtwb3J0LCBzZXJ2ZXJdIG9mIGFjdGl2ZVNlcnZlcnMpIHtcclxuICAgICAgc2VydmVyLmNsb3NlKCgpID0+IHtcclxuICAgICAgICBhY3RpdmVTZXJ2ZXJzLmRlbGV0ZShwb3J0KTtcclxuICAgICAgICBsb2coNCwgYFtzZXJ2ZXJdIENsb3NlZCBzZXJ2ZXIgb24gcG9ydDogJHtwb3J0fS5gKTtcclxuICAgICAgfSk7XHJcbiAgICB9XHJcbiAgfVxyXG59XHJcblxyXG4vKipcclxuICogR2V0IGFsbCBzZXJ2ZXJzIGFzc29jaWF0ZWQgd2l0aCBFeHByZXNzIGFwcCBpbnN0YW5jZS5cclxuICpcclxuICogQGZ1bmN0aW9uIGdldFNlcnZlcnNcclxuICpcclxuICogQHJldHVybnMge0FycmF5LjxPYmplY3Q+fSBTZXJ2ZXJzIGFzc29jaWF0ZWQgd2l0aCBFeHByZXNzIGFwcCBpbnN0YW5jZS5cclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiBnZXRTZXJ2ZXJzKCkge1xyXG4gIHJldHVybiBhY3RpdmVTZXJ2ZXJzO1xyXG59XHJcblxyXG4vKipcclxuICogR2V0IHRoZSBFeHByZXNzIGluc3RhbmNlLlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gZ2V0RXhwcmVzc1xyXG4gKlxyXG4gKiBAcmV0dXJucyB7RXhwcmVzc30gVGhlIEV4cHJlc3MgaW5zdGFuY2UuXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gZ2V0RXhwcmVzcygpIHtcclxuICByZXR1cm4gZXhwcmVzcztcclxufVxyXG5cclxuLyoqXHJcbiAqIEdldCB0aGUgRXhwcmVzcyBhcHAgaW5zdGFuY2UuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBnZXRBcHBcclxuICpcclxuICogQHJldHVybnMge0V4cHJlc3N9IFRoZSBFeHByZXNzIGFwcCBpbnN0YW5jZS5cclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiBnZXRBcHAoKSB7XHJcbiAgcmV0dXJuIGFwcDtcclxufVxyXG5cclxuLyoqXHJcbiAqIEVuYWJsZSByYXRlIGxpbWl0aW5nIGZvciB0aGUgc2VydmVyLlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gZW5hYmxlUmF0ZUxpbWl0aW5nXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSByYXRlTGltaXRpbmdPcHRpb25zIC0gVGhlIGNvbmZpZ3VyYXRpb24gb2JqZWN0IGNvbnRhaW5pbmdcclxuICogYHJhdGVMaW1pdGluZ2Agb3B0aW9ucy4gVGhpcyBvYmplY3QgbWF5IGluY2x1ZGUgYSBwYXJ0aWFsIG9yIGNvbXBsZXRlIHNldFxyXG4gKiBvZiB0aGUgYHJhdGVMaW1pdGluZ2Agb3B0aW9ucy4gSWYgdGhlIG9wdGlvbnMgYXJlIHBhcnRpYWwsIG1pc3NpbmcgdmFsdWVzXHJcbiAqIHdpbGwgZGVmYXVsdCB0byB0aGUgY3VycmVudCBnbG9iYWwgY29uZmlndXJhdGlvbi5cclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiBlbmFibGVSYXRlTGltaXRpbmcocmF0ZUxpbWl0aW5nT3B0aW9ucykge1xyXG4gIC8vIFVwZGF0ZSB0aGUgaW5zdGFuY2Ugb3B0aW9ucyBvYmplY3RcclxuICBjb25zdCBvcHRpb25zID0gdXBkYXRlT3B0aW9ucyhcclxuICAgIHZhbGlkYXRlT3B0aW9ucyh7XHJcbiAgICAgIHNlcnZlcjoge1xyXG4gICAgICAgIHJhdGVMaW1pdGluZzogcmF0ZUxpbWl0aW5nT3B0aW9uc1xyXG4gICAgICB9XHJcbiAgICB9KVxyXG4gICk7XHJcblxyXG4gIC8vIFNldCB0aGUgcmF0ZSBsaW1pdGluZyBvcHRpb25zXHJcbiAgcmF0ZUxpbWl0aW5nTWlkZGxld2FyZShhcHAsIG9wdGlvbnMuc2VydmVyLnJhdGVMaW1pdGluZ09wdGlvbnMpO1xyXG59XHJcblxyXG4vKipcclxuICogQXBwbHkgbWlkZGxld2FyZShzKSB0byBhIHNwZWNpZmljIHBhdGguXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiB1c2VcclxuICpcclxuICogQHBhcmFtIHtzdHJpbmd9IHBhdGggLSBUaGUgcGF0aCB0byB3aGljaCB0aGUgbWlkZGxld2FyZShzKSBzaG91bGQgYmUgYXBwbGllZC5cclxuICogQHBhcmFtIHsuLi5GdW5jdGlvbn0gbWlkZGxld2FyZXMgLSBUaGUgbWlkZGxld2FyZSBmdW5jdGlvbihzKSB0byBiZSBhcHBsaWVkLlxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIHVzZShwYXRoLCAuLi5taWRkbGV3YXJlcykge1xyXG4gIGFwcC51c2UocGF0aCwgLi4ubWlkZGxld2FyZXMpO1xyXG59XHJcblxyXG4vKipcclxuICogU2V0IHVwIGEgcm91dGUgd2l0aCBHRVQgbWV0aG9kIGFuZCBhcHBseSBtaWRkbGV3YXJlKHMpLlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gZ2V0XHJcbiAqXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSBwYXRoIC0gVGhlIHBhdGggdG8gd2hpY2ggdGhlIG1pZGRsZXdhcmUocykgc2hvdWxkIGJlIGFwcGxpZWQuXHJcbiAqIEBwYXJhbSB7Li4uRnVuY3Rpb259IG1pZGRsZXdhcmVzIC0gVGhlIG1pZGRsZXdhcmUgZnVuY3Rpb24ocykgdG8gYmUgYXBwbGllZC5cclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiBnZXQocGF0aCwgLi4ubWlkZGxld2FyZXMpIHtcclxuICBhcHAuZ2V0KHBhdGgsIC4uLm1pZGRsZXdhcmVzKTtcclxufVxyXG5cclxuLyoqXHJcbiAqIFNldCB1cCBhIHJvdXRlIHdpdGggUE9TVCBtZXRob2QgYW5kIGFwcGx5IG1pZGRsZXdhcmUocykuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBwb3N0XHJcbiAqXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSBwYXRoIC0gVGhlIHBhdGggdG8gd2hpY2ggdGhlIG1pZGRsZXdhcmUocykgc2hvdWxkIGJlIGFwcGxpZWQuXHJcbiAqIEBwYXJhbSB7Li4uRnVuY3Rpb259IG1pZGRsZXdhcmVzIC0gVGhlIG1pZGRsZXdhcmUgZnVuY3Rpb24ocykgdG8gYmUgYXBwbGllZC5cclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiBwb3N0KHBhdGgsIC4uLm1pZGRsZXdhcmVzKSB7XHJcbiAgYXBwLnBvc3QocGF0aCwgLi4ubWlkZGxld2FyZXMpO1xyXG59XHJcblxyXG4vKipcclxuICogQXR0YWNoIGVycm9yIGhhbmRsZXJzIHRvIHRoZSBzZXJ2ZXIuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBfYXR0YWNoU2VydmVyRXJyb3JIYW5kbGVyc1xyXG4gKlxyXG4gKiBAcGFyYW0geyhodHRwLlNlcnZlcnxodHRwcy5TZXJ2ZXIpfSBzZXJ2ZXIgLSBUaGUgSFRUUC9IVFRQUyBzZXJ2ZXIgaW5zdGFuY2UuXHJcbiAqL1xyXG5mdW5jdGlvbiBfYXR0YWNoU2VydmVyRXJyb3JIYW5kbGVycyhzZXJ2ZXIpIHtcclxuICBzZXJ2ZXIub24oJ2NsaWVudEVycm9yJywgKGVycm9yLCBzb2NrZXQpID0+IHtcclxuICAgIGxvZ1dpdGhTdGFjayhcclxuICAgICAgMSxcclxuICAgICAgZXJyb3IsXHJcbiAgICAgIGBbc2VydmVyXSBDbGllbnQgZXJyb3I6ICR7ZXJyb3IubWVzc2FnZX0sIGRlc3Ryb3lpbmcgc29ja2V0LmBcclxuICAgICk7XHJcbiAgICBzb2NrZXQuZGVzdHJveSgpO1xyXG4gIH0pO1xyXG5cclxuICBzZXJ2ZXIub24oJ2Vycm9yJywgKGVycm9yKSA9PiB7XHJcbiAgICBsb2dXaXRoU3RhY2soMSwgZXJyb3IsIGBbc2VydmVyXSBTZXJ2ZXIgZXJyb3I6ICR7ZXJyb3IubWVzc2FnZX1gKTtcclxuICB9KTtcclxuXHJcbiAgc2VydmVyLm9uKCdjb25uZWN0aW9uJywgKHNvY2tldCkgPT4ge1xyXG4gICAgc29ja2V0Lm9uKCdlcnJvcicsIChlcnJvcikgPT4ge1xyXG4gICAgICBsb2dXaXRoU3RhY2soMSwgZXJyb3IsIGBbc2VydmVyXSBTb2NrZXQgZXJyb3I6ICR7ZXJyb3IubWVzc2FnZX1gKTtcclxuICAgIH0pO1xyXG4gIH0pO1xyXG59XHJcblxyXG5leHBvcnQgZGVmYXVsdCB7XHJcbiAgc3RhcnRTZXJ2ZXIsXHJcbiAgY2xvc2VTZXJ2ZXJzLFxyXG4gIGdldFNlcnZlcnMsXHJcbiAgZ2V0RXhwcmVzcyxcclxuICBnZXRBcHAsXHJcbiAgZW5hYmxlUmF0ZUxpbWl0aW5nLFxyXG4gIHVzZSxcclxuICBnZXQsXHJcbiAgcG9zdFxyXG59O1xyXG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxyXG5cclxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXHJcblxyXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNSwgSGlnaHNvZnRcclxuXHJcbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cclxuXHJcbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxyXG5cclxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxyXG5cclxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cclxuXHJcbi8qKlxyXG4gKiBAb3ZlcnZpZXcgSGFuZGxlcyBncmFjZWZ1bCBzaHV0ZG93biBvZiB0aGUgSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyLCBlbnN1cmluZ1xyXG4gKiBwcm9wZXIgY2xlYW51cCBvZiByZXNvdXJjZXMgc3VjaCBhcyBicm93c2VyLCBwYWdlcywgc2VydmVycywgYW5kIHRpbWVycy5cclxuICovXHJcblxyXG5pbXBvcnQgeyBraWxsUG9vbCB9IGZyb20gJy4vcG9vbC5qcyc7XHJcbmltcG9ydCB7IGNsZWFyQWxsVGltZXJzIH0gZnJvbSAnLi90aW1lci5qcyc7XHJcblxyXG5pbXBvcnQgeyBjbG9zZVNlcnZlcnMgfSBmcm9tICcuL3NlcnZlci9zZXJ2ZXIuanMnO1xyXG5cclxuLyoqXHJcbiAqIFBlcmZvcm1zIGNsZWFudXAgb3BlcmF0aW9ucyB0byBlbnN1cmUgYSBncmFjZWZ1bCBzaHV0ZG93biBvZiB0aGUgcHJvY2Vzcy5cclxuICogVGhpcyBpbmNsdWRlcyBjbGVhcmluZyBhbGwgcmVnaXN0ZXJlZCB0aW1lb3V0cy9pbnRlcnZhbHMsIGNsb3NpbmcgYWN0aXZlXHJcbiAqIHNlcnZlcnMsIHRlcm1pbmF0aW5nIHJlc291cmNlcyAocGFnZXMpIG9mIHRoZSBwb29sLCBwb29sIGl0c2VsZiwgYW5kIGNsb3NpbmdcclxuICogdGhlIGJyb3dzZXIuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBzaHV0ZG93bkNsZWFuVXBcclxuICpcclxuICogQHBhcmFtIHtudW1iZXJ9IFtleGl0Q29kZT0wXSAtIFRoZSBleGl0IGNvZGUgdG8gdXNlIHdpdGggYHByb2Nlc3MuZXhpdCgpYC5cclxuICogVGhlIGRlZmF1bHQgdmFsdWUgaXMgYDBgLlxyXG4gKi9cclxuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIHNodXRkb3duQ2xlYW5VcChleGl0Q29kZSA9IDApIHtcclxuICAvLyBBd2FpdCBmcmVlaW5nIGFsbCByZXNvdXJjZXNcclxuICBhd2FpdCBQcm9taXNlLmFsbFNldHRsZWQoW1xyXG4gICAgLy8gQ2xlYXIgYWxsIG9uZ29pbmcgaW50ZXJ2YWxzXHJcbiAgICBjbGVhckFsbFRpbWVycygpLFxyXG5cclxuICAgIC8vIEdldCBhdmFpbGFibGUgc2VydmVyIGluc3RhbmNlcyAoSFRUUC9IVFRQUykgYW5kIGNsb3NlIHRoZW1cclxuICAgIGNsb3NlU2VydmVycygpLFxyXG5cclxuICAgIC8vIENsb3NlIGFuIGFjdGl2ZSBwb29sIGFsb25nIHdpdGggaXRzIHdvcmtlcnMgYW5kIHRoZSBicm93c2VyIGluc3RhbmNlXHJcbiAgICBraWxsUG9vbCgpXHJcbiAgXSk7XHJcblxyXG4gIC8vIEV4aXQgcHJvY2VzcyB3aXRoIGEgY29ycmVjdCBjb2RlXHJcbiAgcHJvY2Vzcy5leGl0KGV4aXRDb2RlKTtcclxufVxyXG5cclxuZXhwb3J0IGRlZmF1bHQge1xyXG4gIHNodXRkb3duQ2xlYW5VcFxyXG59O1xyXG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxyXG5cclxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXHJcblxyXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNSwgSGlnaHNvZnRcclxuXHJcbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cclxuXHJcbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxyXG5cclxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxyXG5cclxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cclxuXHJcbi8qKlxyXG4gKiBAb3ZlcnZpZXcgQ29yZSBtb2R1bGUgZm9yIGluaXRpYWxpemluZyBhbmQgbWFuYWdpbmcgdGhlIEhpZ2hjaGFydHMgRXhwb3J0XHJcbiAqIFNlcnZlci4gUHJvdmlkZXMgZnVuY3Rpb25hbGl0aWVzIGZvciBjb25maWd1cmluZyBleHBvcnRzLCBzZXR0aW5nIHVwIHNlcnZlclxyXG4gKiBvcGVyYXRpb25zLCBsb2dnaW5nLCBzY3JpcHRzIGNhY2hpbmcsIHJlc291cmNlIHBvb2xpbmcsIGFuZCBncmFjZWZ1bCBwcm9jZXNzXHJcbiAqIGNsZWFudXAuXHJcbiAqL1xyXG5cclxuaW1wb3J0ICdjb2xvcnMnO1xyXG5cclxuaW1wb3J0IHsgY2hlY2tBbmRVcGRhdGVDYWNoZSB9IGZyb20gJy4vY2FjaGUuanMnO1xyXG5pbXBvcnQge1xyXG4gIHNpbmdsZUV4cG9ydCxcclxuICBiYXRjaEV4cG9ydCxcclxuICBzdGFydEV4cG9ydCxcclxuICBzZXRBbGxvd0NvZGVFeGVjdXRpb25cclxufSBmcm9tICcuL2NoYXJ0LmpzJztcclxuaW1wb3J0IHtcclxuICBnZXRPcHRpb25zLFxyXG4gIHVwZGF0ZU9wdGlvbnMsXHJcbiAgc2V0R2xvYmFsT3B0aW9ucyxcclxuICBtYXBUb05ld09wdGlvbnMsXHJcbiAgdmFsaWRhdGVPcHRpb24sXHJcbiAgdmFsaWRhdGVPcHRpb25zXHJcbn0gZnJvbSAnLi9jb25maWcuanMnO1xyXG5pbXBvcnQge1xyXG4gIGxvZyxcclxuICBsb2dXaXRoU3RhY2ssXHJcbiAgbG9nWm9kSXNzdWVzLFxyXG4gIGluaXRMb2dnaW5nLFxyXG4gIGVuYWJsZUNvbnNvbGVMb2dnaW5nLFxyXG4gIGVuYWJsZUZpbGVMb2dnaW5nLFxyXG4gIHNldExvZ0xldmVsXHJcbn0gZnJvbSAnLi9sb2dnZXIuanMnO1xyXG5pbXBvcnQgeyBpbml0UG9vbCwga2lsbFBvb2wgfSBmcm9tICcuL3Bvb2wuanMnO1xyXG5pbXBvcnQgeyBzaHV0ZG93bkNsZWFuVXAgfSBmcm9tICcuL3Jlc291cmNlUmVsZWFzZS5qcyc7XHJcblxyXG5pbXBvcnQgc2VydmVyIGZyb20gJy4vc2VydmVyL3NlcnZlci5qcyc7XHJcblxyXG4vKipcclxuICogSW5pdGlhbGl6ZXMgdGhlIGV4cG9ydCBwcm9jZXNzLiBUYXNrcyBzdWNoIGFzIGNvbmZpZ3VyaW5nIGxvZ2dpbmcsIGNoZWNraW5nXHJcbiAqIHRoZSBjYWNoZSBhbmQgc291cmNlcywgYW5kIGluaXRpYWxpemluZyB0aGUgcmVzb3VyY2UgcG9vbCBvY2N1ciBkdXJpbmcgdGhpc1xyXG4gKiBzdGFnZS5cclxuICpcclxuICogVGhpcyBmdW5jdGlvbiBtdXN0IGJlIGNhbGxlZCBiZWZvcmUgYXR0ZW1wdGluZyB0byBleHBvcnQgY2hhcnRzIG9yIHNldFxyXG4gKiB1cCBhIHNlcnZlci5cclxuICpcclxuICogQGFzeW5jXHJcbiAqIEBmdW5jdGlvbiBpbml0RXhwb3J0XHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBbaW5pdE9wdGlvbnM9e31dIC0gVGhlIGBpbml0T3B0aW9uc2Agb2JqZWN0LCB3aGljaCBtYXlcclxuICogYmUgYSBwYXJ0aWFsIG9yIGNvbXBsZXRlIHNldCBvZiBvcHRpb25zLiBJZiB0aGUgb3B0aW9ucyBhcmUgcGFydGlhbCwgbWlzc2luZ1xyXG4gKiB2YWx1ZXMgd2lsbCBkZWZhdWx0IHRvIHRoZSBjdXJyZW50IGdsb2JhbCBjb25maWd1cmF0aW9uLiBUaGUgZGVmYXVsdCB2YWx1ZVxyXG4gKiBpcyBhbiBlbXB0eSBvYmplY3QuXHJcbiAqL1xyXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gaW5pdEV4cG9ydChpbml0T3B0aW9ucyA9IHt9KSB7XHJcbiAgLy8gSW5pdCwgdmFsaWRhdGUgYW5kIHVwZGF0ZSB0aGUgaW5zdGFuY2Ugb3B0aW9ucyBvYmplY3RcclxuICBjb25zdCBvcHRpb25zID0gdXBkYXRlT3B0aW9ucyh2YWxpZGF0ZU9wdGlvbnMoaW5pdE9wdGlvbnMpLCB0cnVlKTtcclxuXHJcbiAgLy8gU2V0IHRoZSBgYWxsb3dDb2RlRXhlY3V0aW9uYCBwZXIgZXhwb3J0IG1vZHVsZSBzY29wZVxyXG4gIHNldEFsbG93Q29kZUV4ZWN1dGlvbihvcHRpb25zLmN1c3RvbUxvZ2ljLmFsbG93Q29kZUV4ZWN1dGlvbik7XHJcblxyXG4gIC8vIEluaXQgdGhlIGxvZ2dpbmdcclxuICBpbml0TG9nZ2luZyhvcHRpb25zLmxvZ2dpbmcpO1xyXG5cclxuICAvLyBBdHRhY2ggcHJvY2VzcycgZXhpdCBsaXN0ZW5lcnNcclxuICBpZiAob3B0aW9ucy5vdGhlci5saXN0ZW5Ub1Byb2Nlc3NFeGl0cykge1xyXG4gICAgX2F0dGFjaFByb2Nlc3NFeGl0TGlzdGVuZXJzKCk7XHJcbiAgfVxyXG5cclxuICAvLyBDaGVjayBpZiBjYWNoZSBuZWVkcyB0byBiZSB1cGRhdGVkXHJcbiAgYXdhaXQgY2hlY2tBbmRVcGRhdGVDYWNoZShvcHRpb25zLmhpZ2hjaGFydHMsIG9wdGlvbnMuc2VydmVyLnByb3h5KTtcclxuXHJcbiAgLy8gSW5pdCB0aGUgcG9vbFxyXG4gIGF3YWl0IGluaXRQb29sKG9wdGlvbnMucG9vbCwgb3B0aW9ucy5wdXBwZXRlZXIuYXJncyk7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBBdHRhY2hlcyBleGl0IGxpc3RlbmVycyB0byB0aGUgcHJvY2VzcywgZW5zdXJpbmcgcHJvcGVyIGNsZWFudXAgb2YgcmVzb3VyY2VzXHJcbiAqIGFuZCB0ZXJtaW5hdGlvbiBvbiBleGl0IHNpZ25hbHMuIEhhbmRsZXMgJ2V4aXQnLCAnU0lHSU5UJywgJ1NJR1RFUk0nXHJcbiAqIGFuZCAndW5jYXVnaHRFeGNlcHRpb24nIGV2ZW50cy5cclxuICpcclxuICogQGZ1bmN0aW9uIF9hdHRhY2hQcm9jZXNzRXhpdExpc3RlbmVyc1xyXG4gKi9cclxuZnVuY3Rpb24gX2F0dGFjaFByb2Nlc3NFeGl0TGlzdGVuZXJzKCkge1xyXG4gIGxvZygzLCAnW3Byb2Nlc3NdIEF0dGFjaGluZyBleGl0IGxpc3RlbmVycyB0byB0aGUgcHJvY2Vzcy4nKTtcclxuXHJcbiAgLy8gSGFuZGxlciBmb3IgdGhlICdleGl0J1xyXG4gIHByb2Nlc3Mub24oJ2V4aXQnLCAoY29kZSkgPT4ge1xyXG4gICAgbG9nKDQsIGBbcHJvY2Vzc10gUHJvY2VzcyBleGl0ZWQgd2l0aCBjb2RlICR7Y29kZX0uYCk7XHJcbiAgfSk7XHJcblxyXG4gIC8vIEhhbmRsZXIgZm9yIHRoZSAnU0lHSU5UJ1xyXG4gIHByb2Nlc3Mub24oJ1NJR0lOVCcsIGFzeW5jIChuYW1lLCBjb2RlKSA9PiB7XHJcbiAgICBsb2coNCwgYFtwcm9jZXNzXSBUaGUgJHtuYW1lfSBldmVudCB3aXRoIGNvZGU6ICR7Y29kZX0uYCk7XHJcbiAgICBhd2FpdCBzaHV0ZG93bkNsZWFuVXAoKTtcclxuICB9KTtcclxuXHJcbiAgLy8gSGFuZGxlciBmb3IgdGhlICdTSUdURVJNJ1xyXG4gIHByb2Nlc3Mub24oJ1NJR1RFUk0nLCBhc3luYyAobmFtZSwgY29kZSkgPT4ge1xyXG4gICAgbG9nKDQsIGBbcHJvY2Vzc10gVGhlICR7bmFtZX0gZXZlbnQgd2l0aCBjb2RlOiAke2NvZGV9LmApO1xyXG4gICAgYXdhaXQgc2h1dGRvd25DbGVhblVwKCk7XHJcbiAgfSk7XHJcblxyXG4gIC8vIEhhbmRsZXIgZm9yIHRoZSAnU0lHSFVQJ1xyXG4gIHByb2Nlc3Mub24oJ1NJR0hVUCcsIGFzeW5jIChuYW1lLCBjb2RlKSA9PiB7XHJcbiAgICBsb2coNCwgYFtwcm9jZXNzXSBUaGUgJHtuYW1lfSBldmVudCB3aXRoIGNvZGU6ICR7Y29kZX0uYCk7XHJcbiAgICBhd2FpdCBzaHV0ZG93bkNsZWFuVXAoKTtcclxuICB9KTtcclxuXHJcbiAgLy8gSGFuZGxlciBmb3IgdGhlICd1bmNhdWdodEV4Y2VwdGlvbidcclxuICBwcm9jZXNzLm9uKCd1bmNhdWdodEV4Y2VwdGlvbicsIGFzeW5jIChlcnJvciwgbmFtZSkgPT4ge1xyXG4gICAgbG9nV2l0aFN0YWNrKDEsIGVycm9yLCBgW3Byb2Nlc3NdIFRoZSAke25hbWV9IGVycm9yLmApO1xyXG4gICAgYXdhaXQgc2h1dGRvd25DbGVhblVwKDEpO1xyXG4gIH0pO1xyXG59XHJcblxyXG5leHBvcnQgZGVmYXVsdCB7XHJcbiAgLy8gU2VydmVyXHJcbiAgLi4uc2VydmVyLFxyXG5cclxuICAvLyBPcHRpb25zXHJcbiAgZ2V0T3B0aW9ucyxcclxuICBzZXRHbG9iYWxPcHRpb25zLFxyXG4gIG1hcFRvTmV3T3B0aW9ucyxcclxuXHJcbiAgLy8gVmFsaWRhdGlvblxyXG4gIHZhbGlkYXRlT3B0aW9uLFxyXG4gIHZhbGlkYXRlT3B0aW9ucyxcclxuXHJcbiAgLy8gRXhwb3J0aW5nXHJcbiAgaW5pdEV4cG9ydCxcclxuICBzaW5nbGVFeHBvcnQsXHJcbiAgYmF0Y2hFeHBvcnQsXHJcbiAgc3RhcnRFeHBvcnQsXHJcblxyXG4gIC8vIFJlbGVhc2VcclxuICBraWxsUG9vbCxcclxuICBzaHV0ZG93bkNsZWFuVXAsXHJcblxyXG4gIC8vIExvZ3NcclxuICBsb2csXHJcbiAgbG9nV2l0aFN0YWNrLFxyXG4gIGxvZ1pvZElzc3VlcyxcclxuICBzZXRMb2dMZXZlbDogZnVuY3Rpb24gKGxldmVsKSB7XHJcbiAgICAvLyBVcGRhdGUgdGhlIGluc3RhbmNlIG9wdGlvbnMgb2JqZWN0XHJcbiAgICBjb25zdCBvcHRpb25zID0gdXBkYXRlT3B0aW9ucyhcclxuICAgICAgdmFsaWRhdGVPcHRpb25zKHtcclxuICAgICAgICBsb2dnaW5nOiB7XHJcbiAgICAgICAgICBsZXZlbFxyXG4gICAgICAgIH1cclxuICAgICAgfSlcclxuICAgICk7XHJcblxyXG4gICAgLy8gQ2FsbCB0aGUgZnVuY3Rpb25cclxuICAgIHNldExvZ0xldmVsKG9wdGlvbnMubG9nZ2luZy5sZXZlbCk7XHJcbiAgfSxcclxuICBlbmFibGVDb25zb2xlTG9nZ2luZzogZnVuY3Rpb24gKHRvQ29uc29sZSkge1xyXG4gICAgLy8gVXBkYXRlIHRoZSBpbnN0YW5jZSBvcHRpb25zIG9iamVjdFxyXG4gICAgY29uc3Qgb3B0aW9ucyA9IHVwZGF0ZU9wdGlvbnMoXHJcbiAgICAgIHZhbGlkYXRlT3B0aW9ucyh7XHJcbiAgICAgICAgbG9nZ2luZzoge1xyXG4gICAgICAgICAgdG9Db25zb2xlXHJcbiAgICAgICAgfVxyXG4gICAgICB9KVxyXG4gICAgKTtcclxuXHJcbiAgICAvLyBDYWxsIHRoZSBmdW5jdGlvblxyXG4gICAgZW5hYmxlQ29uc29sZUxvZ2dpbmcob3B0aW9ucy5sb2dnaW5nLnRvQ29uc29sZSk7XHJcbiAgfSxcclxuICBlbmFibGVGaWxlTG9nZ2luZzogZnVuY3Rpb24gKGRlc3QsIGZpbGUsIHRvRmlsZSkge1xyXG4gICAgLy8gVXBkYXRlIHRoZSBpbnN0YW5jZSBvcHRpb25zIG9iamVjdFxyXG4gICAgY29uc3Qgb3B0aW9ucyA9IHVwZGF0ZU9wdGlvbnMoXHJcbiAgICAgIHZhbGlkYXRlT3B0aW9ucyh7XHJcbiAgICAgICAgbG9nZ2luZzoge1xyXG4gICAgICAgICAgZGVzdCxcclxuICAgICAgICAgIGZpbGUsXHJcbiAgICAgICAgICB0b0ZpbGVcclxuICAgICAgICB9XHJcbiAgICAgIH0pXHJcbiAgICApO1xyXG5cclxuICAgIC8vIENhbGwgdGhlIGZ1bmN0aW9uXHJcbiAgICBlbmFibGVGaWxlTG9nZ2luZyhcclxuICAgICAgb3B0aW9ucy5sb2dnaW5nLmRlc3QsXHJcbiAgICAgIG9wdGlvbnMubG9nZ2luZy5maWxlLFxyXG4gICAgICBvcHRpb25zLmxvZ2dpbmcudG9GaWxlXHJcbiAgICApO1xyXG4gIH1cclxufTtcclxuIl0sIm5hbWVzIjpbIl9fZGlybmFtZSIsImZpbGVVUkxUb1BhdGgiLCJVUkwiLCJkb2N1bWVudCIsInJlcXVpcmUiLCJwYXRoVG9GaWxlVVJMIiwiX19maWxlbmFtZSIsImhyZWYiLCJfZG9jdW1lbnRDdXJyZW50U2NyaXB0IiwidGFnTmFtZSIsInRvVXBwZXJDYXNlIiwic3JjIiwiYmFzZVVSSSIsImRlZXBDb3B5Iiwib2JqQXJyIiwib2JqQXJyQ29weSIsIkFycmF5IiwiaXNBcnJheSIsImtleSIsIk9iamVjdCIsInByb3RvdHlwZSIsImhhc093blByb3BlcnR5IiwiY2FsbCIsImZpeENvbnN0ciIsImNvbnN0ciIsImZpeGVkQ29uc3RyIiwidG9Mb3dlckNhc2UiLCJyZXBsYWNlIiwiaW5jbHVkZXMiLCJmaXhPdXRmaWxlIiwidHlwZSIsIm91dGZpbGUiLCJnZXRBYnNvbHV0ZVBhdGgiLCJzcGxpdCIsInNoaWZ0IiwiZml4VHlwZSIsIm1pbWVUeXBlcyIsImZvcm1hdHMiLCJ2YWx1ZXMiLCJvdXRUeXBlIiwicG9wIiwiZmluZCIsInQiLCJwYXRoIiwiaXNBYnNvbHV0ZSIsImpvaW4iLCJnZXRCYXNlNjQiLCJpbnB1dCIsIkJ1ZmZlciIsImZyb20iLCJ0b1N0cmluZyIsImdldE5ld0RhdGUiLCJEYXRlIiwidHJpbSIsImdldE5ld0RhdGVUaW1lIiwiZ2V0VGltZSIsImlzT2JqZWN0IiwiaXRlbSIsImlzT2JqZWN0RW1wdHkiLCJrZXlzIiwibGVuZ3RoIiwiaXNQcml2YXRlUmFuZ2VVcmxGb3VuZCIsInNvbWUiLCJwYXR0ZXJuIiwidGVzdCIsIm1lYXN1cmVUaW1lIiwic3RhcnQiLCJwcm9jZXNzIiwiaHJ0aW1lIiwiYmlnaW50IiwiTnVtYmVyIiwicm91bmROdW1iZXIiLCJ2YWx1ZSIsInByZWNpc2lvbiIsIm11bHRpcGxpZXIiLCJNYXRoIiwicG93Iiwicm91bmQiLCJ3cmFwQXJvdW5kIiwiY3VzdG9tQ29kZSIsImFsbG93RmlsZVJlc291cmNlcyIsImlzQ2FsbGJhY2siLCJlbmRzV2l0aCIsInJlYWRGaWxlU3luYyIsInN0YXJ0c1dpdGgiLCJjb2xvcnMiLCJsb2dnaW5nIiwidG9Db25zb2xlIiwidG9GaWxlIiwicGF0aENyZWF0ZWQiLCJwYXRoVG9Mb2ciLCJsZXZlbHNEZXNjIiwidGl0bGUiLCJjb2xvciIsImxvZyIsImFyZ3MiLCJuZXdMZXZlbCIsInRleHRzIiwibGV2ZWwiLCJwcmVmaXgiLCJfbG9nVG9GaWxlIiwiY29uc29sZSIsImFwcGx5IiwidW5kZWZpbmVkIiwiY29uY2F0IiwibG9nV2l0aFN0YWNrIiwiZXJyb3IiLCJjdXN0b21NZXNzYWdlIiwibWFpbk1lc3NhZ2UiLCJtZXNzYWdlIiwic3RhY2tNZXNzYWdlIiwic3RhY2siLCJwdXNoIiwibG9nWm9kSXNzdWVzIiwiaXNzdWVzIiwibWFwIiwiaXNzdWUiLCJpbml0TG9nZ2luZyIsImxvZ2dpbmdPcHRpb25zIiwiZGVzdCIsImZpbGUiLCJzZXRMb2dMZXZlbCIsImVuYWJsZUNvbnNvbGVMb2dnaW5nIiwiZW5hYmxlRmlsZUxvZ2dpbmciLCJpc0ludGVnZXIiLCJleGlzdHNTeW5jIiwibWtkaXJTeW5jIiwiYXBwZW5kRmlsZSIsImRlZmF1bHRDb25maWciLCJwdXBwZXRlZXIiLCJ0eXBlcyIsImVudkxpbmsiLCJjbGlOYW1lIiwiZGVzY3JpcHRpb24iLCJwcm9tcHRPcHRpb25zIiwic2VwYXJhdG9yIiwiaGlnaGNoYXJ0cyIsInZlcnNpb24iLCJjZG5VcmwiLCJmb3JjZUZldGNoIiwiY2FjaGVQYXRoIiwiY29yZVNjcmlwdHMiLCJpbnN0cnVjdGlvbnMiLCJtb2R1bGVTY3JpcHRzIiwiaW5kaWNhdG9yU2NyaXB0cyIsImN1c3RvbVNjcmlwdHMiLCJleHBvcnQiLCJpbmZpbGUiLCJpbnN0ciIsIm9wdGlvbnMiLCJzdmciLCJiYXRjaCIsImhpbnQiLCJjaG9pY2VzIiwiYjY0Iiwibm9Eb3dubG9hZCIsImhlaWdodCIsIndpZHRoIiwic2NhbGUiLCJkZWZhdWx0SGVpZ2h0IiwiZGVmYXVsdFdpZHRoIiwiZGVmYXVsdFNjYWxlIiwibWluIiwibWF4IiwiZ2xvYmFsT3B0aW9ucyIsInRoZW1lT3B0aW9ucyIsInJhc3Rlcml6YXRpb25UaW1lb3V0IiwiY3VzdG9tTG9naWMiLCJhbGxvd0NvZGVFeGVjdXRpb24iLCJjYWxsYmFjayIsInJlc291cmNlcyIsImxvYWRDb25maWciLCJsZWdhY3lOYW1lIiwiY3JlYXRlQ29uZmlnIiwic2VydmVyIiwiZW5hYmxlIiwiaG9zdCIsInBvcnQiLCJ1cGxvYWRMaW1pdCIsImJlbmNobWFya2luZyIsInByb3h5IiwidGltZW91dCIsInJhdGVMaW1pdGluZyIsIm1heFJlcXVlc3RzIiwid2luZG93IiwiZGVsYXkiLCJ0cnVzdFByb3h5Iiwic2tpcEtleSIsInNraXBUb2tlbiIsInNzbCIsImZvcmNlIiwiY2VydFBhdGgiLCJwb29sIiwibWluV29ya2VycyIsIm1heFdvcmtlcnMiLCJ3b3JrTGltaXQiLCJhY3F1aXJlVGltZW91dCIsImNyZWF0ZVRpbWVvdXQiLCJkZXN0cm95VGltZW91dCIsImlkbGVUaW1lb3V0IiwiY3JlYXRlUmV0cnlJbnRlcnZhbCIsInJlYXBlckludGVydmFsIiwidWkiLCJyb3V0ZSIsIm90aGVyIiwibm9kZUVudiIsImxpc3RlblRvUHJvY2Vzc0V4aXRzIiwibm9Mb2dvIiwiaGFyZFJlc2V0UGFnZSIsImJyb3dzZXJTaGVsbE1vZGUiLCJ2YWxpZGF0aW9uIiwiZGVidWciLCJoZWFkbGVzcyIsImRldnRvb2xzIiwibGlzdGVuVG9Db25zb2xlIiwiZHVtcGlvIiwic2xvd01vIiwiZGVidWdnaW5nUG9ydCIsIm5lc3RlZFByb3BzIiwiX2NyZWF0ZU5lc3RlZFByb3BzIiwiYWJzb2x1dGVQcm9wcyIsIl9jcmVhdGVBYnNvbHV0ZVByb3BzIiwiY29uZmlnIiwicHJvcENoYWluIiwiZm9yRWFjaCIsImVudHJ5Iiwic3Vic3RyaW5nIiwiZG90ZW52IiwieiIsInNldEVycm9yTWFwIiwiX2N1c3RvbUVycm9yTWFwIiwidiIsImJvb2xlYW4iLCJzdHJpY3RDaGVjayIsInVuaW9uIiwiZW51bSIsInRyYW5zZm9ybSIsIm51bGxhYmxlIiwic3RyaW5nIiwicmVmaW5lIiwicGFyYW1zIiwiZXJyb3JNZXNzYWdlIiwic3RyaW5nQXJyYXkiLCJmaWx0ZXJDYWxsYmFjayIsImFycmF5U2NoZW1hIiwiYXJyYXkiLCJzdHJpbmdTY2hlbWEiLCJzbGljZSIsInRyYW5zZm9ybUNhbGxiYWNrIiwiZmlsdGVyIiwicG9zaXRpdmVOdW0iLCJudW1iZXIiLCJwb3NpdGl2ZSIsImlzTmFOIiwibm9uTmVnYXRpdmVOdW0iLCJub25uZWdhdGl2ZSIsInByZWZpeGVzIiwiY2hhcnRDb25maWciLCJvYmplY3QiLCJwYXNzdGhyb3VnaCIsImFkZGl0aW9uYWxPcHRpb25zIiwidmFsaWRhdG9ycyIsImFkbWluVG9rZW4iLCJpbmRleE9mIiwiZ3RlIiwibHRlIiwidGhpcyIsIm9iamVjdFNjaGVtYSIsImpzIiwiY3NzIiwiZmlsZXMiLCJwYXJ0aWFsIiwic3RyaW5nU2NoZW1hMSIsInN0cmluZ1NjaGVtYTIiLCJlbmFibGVTZXJ2ZXIiLCJzZXJ2ZXJCZW5jaG1hcmtpbmciLCJwcm94eUhvc3QiLCJwcm94eVBvcnQiLCJwcm94eVRpbWVvdXQiLCJlbmFibGVSYXRlTGltaXRpbmciLCJlbmFibGVTc2wiLCJzc2xGb3JjZSIsInNzbFBvcnQiLCJzc2xDZXJ0UGF0aCIsInBvb2xCZW5jaG1hcmtpbmciLCJyZXNvdXJjZXNJbnRlcnZhbCIsImxvZ0xldmVsIiwiaW50IiwibG9nRmlsZSIsImxvZ0Rlc3QiLCJsb2dUb0NvbnNvbGUiLCJsb2dUb0ZpbGUiLCJlbmFibGVVaSIsInVpUm91dGUiLCJlbmFibGVEZWJ1ZyIsInJlcXVlc3RJZCIsInV1aWQiLCJQdXBwZXRlZXJTY2hlbWEiLCJIaWdoY2hhcnRzU2NoZW1hIiwiRXhwb3J0U2NoZW1hIiwiQ3VzdG9tTG9naWNTY2hlbWEiLCJQcm94eVNjaGVtYSIsIlJhdGVMaW1pdGluZ1NjaGVtYSIsIlNzbFNjaGVtYSIsIlNlcnZlclNjaGVtYSIsIm9wdGlvbmFsIiwiUG9vbFNjaGVtYSIsIkxvZ2dpbmdTY2hlbWEiLCJVaVNjaGVtYSIsIk90aGVyU2NoZW1hIiwiRGVidWdTY2hlbWEiLCJTdHJpY3RDb25maWdTY2hlbWEiLCJMb29zZUNvbmZpZ1NjaGVtYSIsIkVudlNjaGVtYSIsIlBVUFBFVEVFUl9BUkdTIiwiSElHSENIQVJUU19WRVJTSU9OIiwiSElHSENIQVJUU19DRE5fVVJMIiwiSElHSENIQVJUU19GT1JDRV9GRVRDSCIsIkhJR0hDSEFSVFNfQ0FDSEVfUEFUSCIsIkhJR0hDSEFSVFNfQURNSU5fVE9LRU4iLCJISUdIQ0hBUlRTX0NPUkVfU0NSSVBUUyIsIkhJR0hDSEFSVFNfTU9EVUxFX1NDUklQVFMiLCJISUdIQ0hBUlRTX0lORElDQVRPUl9TQ1JJUFRTIiwiSElHSENIQVJUU19DVVNUT01fU0NSSVBUUyIsIkVYUE9SVF9JTkZJTEUiLCJFWFBPUlRfSU5TVFIiLCJFWFBPUlRfT1BUSU9OUyIsIkVYUE9SVF9TVkciLCJFWFBPUlRfQkFUQ0giLCJFWFBPUlRfT1VURklMRSIsIkVYUE9SVF9UWVBFIiwiRVhQT1JUX0NPTlNUUiIsIkVYUE9SVF9CNjQiLCJFWFBPUlRfTk9fRE9XTkxPQUQiLCJFWFBPUlRfSEVJR0hUIiwiRVhQT1JUX1dJRFRIIiwiRVhQT1JUX1NDQUxFIiwiRVhQT1JUX0RFRkFVTFRfSEVJR0hUIiwiRVhQT1JUX0RFRkFVTFRfV0lEVEgiLCJFWFBPUlRfREVGQVVMVF9TQ0FMRSIsIkVYUE9SVF9HTE9CQUxfT1BUSU9OUyIsIkVYUE9SVF9USEVNRV9PUFRJT05TIiwiRVhQT1JUX1JBU1RFUklaQVRJT05fVElNRU9VVCIsIkNVU1RPTV9MT0dJQ19BTExPV19DT0RFX0VYRUNVVElPTiIsIkNVU1RPTV9MT0dJQ19BTExPV19GSUxFX1JFU09VUkNFUyIsIkNVU1RPTV9MT0dJQ19DVVNUT01fQ09ERSIsIkNVU1RPTV9MT0dJQ19DQUxMQkFDSyIsIkNVU1RPTV9MT0dJQ19SRVNPVVJDRVMiLCJDVVNUT01fTE9HSUNfTE9BRF9DT05GSUciLCJDVVNUT01fTE9HSUNfQ1JFQVRFX0NPTkZJRyIsIlNFUlZFUl9FTkFCTEUiLCJTRVJWRVJfSE9TVCIsIlNFUlZFUl9QT1JUIiwiU0VSVkVSX1VQTE9BRF9MSU1JVCIsIlNFUlZFUl9CRU5DSE1BUktJTkciLCJTRVJWRVJfUFJPWFlfSE9TVCIsIlNFUlZFUl9QUk9YWV9QT1JUIiwiU0VSVkVSX1BST1hZX1RJTUVPVVQiLCJTRVJWRVJfUkFURV9MSU1JVElOR19FTkFCTEUiLCJTRVJWRVJfUkFURV9MSU1JVElOR19NQVhfUkVRVUVTVFMiLCJTRVJWRVJfUkFURV9MSU1JVElOR19XSU5ET1ciLCJTRVJWRVJfUkFURV9MSU1JVElOR19ERUxBWSIsIlNFUlZFUl9SQVRFX0xJTUlUSU5HX1RSVVNUX1BST1hZIiwiU0VSVkVSX1JBVEVfTElNSVRJTkdfU0tJUF9LRVkiLCJTRVJWRVJfUkFURV9MSU1JVElOR19TS0lQX1RPS0VOIiwiU0VSVkVSX1NTTF9FTkFCTEUiLCJTRVJWRVJfU1NMX0ZPUkNFIiwiU0VSVkVSX1NTTF9QT1JUIiwiU0VSVkVSX1NTTF9DRVJUX1BBVEgiLCJQT09MX01JTl9XT1JLRVJTIiwiUE9PTF9NQVhfV09SS0VSUyIsIlBPT0xfV09SS19MSU1JVCIsIlBPT0xfQUNRVUlSRV9USU1FT1VUIiwiUE9PTF9DUkVBVEVfVElNRU9VVCIsIlBPT0xfREVTVFJPWV9USU1FT1VUIiwiUE9PTF9JRExFX1RJTUVPVVQiLCJQT09MX0NSRUFURV9SRVRSWV9JTlRFUlZBTCIsIlBPT0xfUkVBUEVSX0lOVEVSVkFMIiwiUE9PTF9CRU5DSE1BUktJTkciLCJMT0dHSU5HX0xFVkVMIiwiTE9HR0lOR19GSUxFIiwiTE9HR0lOR19ERVNUIiwiTE9HR0lOR19UT19DT05TT0xFIiwiTE9HR0lOR19UT19GSUxFIiwiVUlfRU5BQkxFIiwiVUlfUk9VVEUiLCJPVEhFUl9OT0RFX0VOViIsIk9USEVSX0xJU1RFTl9UT19QUk9DRVNTX0VYSVRTIiwiT1RIRVJfTk9fTE9HTyIsIk9USEVSX0hBUkRfUkVTRVRfUEFHRSIsIk9USEVSX0JST1dTRVJfU0hFTExfTU9ERSIsIk9USEVSX1ZBTElEQVRJT04iLCJERUJVR19FTkFCTEUiLCJERUJVR19IRUFETEVTUyIsIkRFQlVHX0RFVlRPT0xTIiwiREVCVUdfTElTVEVOX1RPX0NPTlNPTEUiLCJERUJVR19EVU1QSU8iLCJERUJVR19TTE9XX01PIiwiREVCVUdfREVCVUdHSU5HX1BPUlQiLCJlbnZzIiwicGFyc2UiLCJlbnYiLCJzdHJpY3RWYWxpZGF0ZSIsImNvbmZpZ09wdGlvbnMiLCJsb29zZVZhbGlkYXRlIiwiY29udGV4dCIsInByb3BlcnR5TmFtZSIsInByb3BlcnR5SW5mbyIsImNvZGUiLCJab2RJc3N1ZUNvZGUiLCJpbnZhbGlkX3R5cGUiLCJyZWNlaXZlZCIsIlpvZFBhcnNlZFR5cGUiLCJkZWZhdWx0RXJyb3IiLCJjdXN0b20iLCJkYXRhIiwiaW52YWxpZF91bmlvbiIsInVuaW9uRXJyb3JzIiwiaW5kZXgiLCJFeHBvcnRFcnJvciIsIkVycm9yIiwiY29uc3RydWN0b3IiLCJzdGF0dXNDb2RlIiwic3VwZXIiLCJzZXRTdGF0dXMiLCJzZXRFcnJvciIsIm5hbWUiLCJfaW5pdEdsb2JhbE9wdGlvbnMiLCJpbnN0YW5jZU9wdGlvbnMiLCJnZXRPcHRpb25zIiwiZ2V0SW5zdGFuY2UiLCJzZXRHbG9iYWxPcHRpb25zIiwiY3VzdG9tT3B0aW9ucyIsImNsaUFyZ3MiLCJjbGlPcHRpb25zIiwiX2xvYWRDb25maWdGaWxlIiwiX3BhaXJBcmd1bWVudFZhbHVlIiwiX3VwZGF0ZUdsb2JhbE9wdGlvbnMiLCJ1cGRhdGVPcHRpb25zIiwibmV3SW5zdGFuY2UiLCJtZXJnZU9wdGlvbnMiLCJvcmlnaW5hbE9wdGlvbnMiLCJuZXdPcHRpb25zIiwiZW50cmllcyIsIm1hcFRvTmV3T3B0aW9ucyIsIm9sZE9wdGlvbnMiLCJwcm9wZXJ0aWVzQ2hhaW4iLCJyZWR1Y2UiLCJvYmoiLCJwcm9wIiwidmFsaWRhdGVPcHRpb24iLCJjb25maWdPcHRpb24iLCJ2YWxpZGF0ZU9wdGlvbnMiLCJpc0FsbG93ZWRDb25maWciLCJhbGxvd0Z1bmN0aW9ucyIsIm9iamVjdENvbmZpZyIsImV2YWwiLCJKU09OIiwic3RyaW5naWZpZWRPcHRpb25zIiwiX29wdGlvbnNTdHJpbmdpZnkiLCJwYXJzZWRPcHRpb25zIiwiXyIsImVudlZhbCIsImNvbmZpZ09wdCIsImNsaU9wdCIsImN1c3RvbU9wdCIsImNvbmZpZ1ZhbCIsImNsaVZhbCIsImN1c3RvbVZhbCIsInN0cmluZ2lmeUZ1bmN0aW9ucyIsInN0cmluZ2lmeSIsInJlcGxhY2VBbGwiLCJjdXN0b21Mb2dpY09wdGlvbnMiLCJjb25maWdJbmRleCIsImZpbmRJbmRleCIsImFyZyIsImNvbmZpZ0ZpbGVOYW1lIiwiaSIsIm9wdGlvbiIsImFzeW5jIiwiZmV0Y2giLCJ1cmwiLCJyZXF1ZXN0T3B0aW9ucyIsIlByb21pc2UiLCJyZXNvbHZlIiwicmVqZWN0IiwiX2dldFByb3RvY29sTW9kdWxlIiwiZ2V0IiwicmVzcG9uc2UiLCJyZXNwb25zZURhdGEiLCJvbiIsImNodW5rIiwidGV4dCIsImh0dHBzIiwiaHR0cCIsImNhY2hlIiwiYWN0aXZlTWFuaWZlc3QiLCJzb3VyY2VzIiwiaGNWZXJzaW9uIiwiY2hlY2tBbmRVcGRhdGVDYWNoZSIsImhpZ2hjaGFydHNPcHRpb25zIiwic2VydmVyUHJveHlPcHRpb25zIiwiZmV0Y2hlZE1vZHVsZXMiLCJnZXRDYWNoZVBhdGgiLCJtYW5pZmVzdFBhdGgiLCJzb3VyY2VQYXRoIiwicmVjdXJzaXZlIiwiX3VwZGF0ZUNhY2hlIiwicmVxdWVzdFVwZGF0ZSIsIm1hbmlmZXN0IiwibW9kdWxlcyIsIm1vZHVsZU1hcCIsIm0iLCJudW1iZXJPZk1vZHVsZXMiLCJtb2R1bGVOYW1lIiwiZXh0cmFjdFZlcnNpb24iLCJfc2F2ZUNvbmZpZ1RvTWFuaWZlc3QiLCJnZXRIaWdoY2hhcnRzVmVyc2lvbiIsInVwZGF0ZUhpZ2hjaGFydHNWZXJzaW9uIiwibmV3VmVyc2lvbiIsImNhY2hlU291cmNlcyIsImV4dHJhY3RNb2R1bGVOYW1lIiwic2NyaXB0UGF0aCIsIl9mZXRjaEFuZFByb2Nlc3NTY3JpcHQiLCJzY3JpcHQiLCJzaG91bGRUaHJvd0Vycm9yIiwibmV3TWFuaWZlc3QiLCJ3cml0ZUZpbGVTeW5jIiwiX2ZldGNoU2NyaXB0cyIsInByb3h5QWdlbnQiLCJIdHRwc1Byb3h5QWdlbnQiLCJhZ2VudCIsImFsbEZldGNoUHJvbWlzZXMiLCJhbGwiLCJjIiwic2V0dXBIaWdoY2hhcnRzIiwiSGlnaGNoYXJ0cyIsImFuaW1PYmplY3QiLCJkdXJhdGlvbiIsImNyZWF0ZUNoYXJ0IiwiZXhwb3J0T3B0aW9ucyIsInNldE9wdGlvbnMiLCJtZXJnZSIsIndyYXAiLCJzZXRPcHRpb25zT2JqIiwiaXNSZW5kZXJDb21wbGV0ZSIsIkNoYXJ0IiwicHJvY2VlZCIsInVzZXJPcHRpb25zIiwiY2IiLCJleHBvcnRpbmciLCJlbmFibGVkIiwicGxvdE9wdGlvbnMiLCJzZXJpZXMiLCJsYWJlbCIsInRvb2x0aXAiLCJhbmltYXRpb24iLCJvbkhpZ2hjaGFydHNSZW5kZXIiLCJhZGRFdmVudCIsIlNlcmllcyIsImNoYXJ0IiwiRnVuY3Rpb24iLCJmaW5hbE9wdGlvbnMiLCJmaW5hbENhbGxiYWNrIiwiZGVmYXVsdE9wdGlvbnMiLCJ0ZW1wbGF0ZSIsImJyb3dzZXIiLCJjcmVhdGVCcm93c2VyIiwicHVwcGV0ZWVyQXJncyIsImVuYWJsZWREZWJ1ZyIsImRlYnVnT3B0aW9ucyIsImxhdW5jaE9wdGlvbnMiLCJ1c2VyRGF0YURpciIsImhhbmRsZVNJR0lOVCIsImhhbmRsZVNJR1RFUk0iLCJoYW5kbGVTSUdIVVAiLCJ3YWl0Rm9ySW5pdGlhbFBhZ2UiLCJkZWZhdWx0Vmlld3BvcnQiLCJ0cnlDb3VudCIsIm9wZW4iLCJsYXVuY2giLCJzZXRUaW1lb3V0IiwiY2xvc2VCcm93c2VyIiwiY29ubmVjdGVkIiwiY2xvc2UiLCJuZXdQYWdlIiwicG9vbFJlc291cmNlIiwicGFnZSIsInNldENhY2hlRW5hYmxlZCIsIl9zZXRQYWdlQ29udGVudCIsIl9zZXRQYWdlRXZlbnRzIiwiaXNDbG9zZWQiLCJjbGVhclBhZ2UiLCJoYXJkUmVzZXQiLCJnb3RvIiwid2FpdFVudGlsIiwiZXZhbHVhdGUiLCJib2R5IiwiaW5uZXJIVE1MIiwiaWQiLCJ3b3JrQ291bnQiLCJhZGRQYWdlUmVzb3VyY2VzIiwiaW5qZWN0ZWRSZXNvdXJjZXMiLCJpbmplY3RlZEpzIiwiY29udGVudCIsImlzTG9jYWwiLCJqc1Jlc291cmNlIiwiYWRkU2NyaXB0VGFnIiwiaW5qZWN0ZWRDc3MiLCJjc3NJbXBvcnRzIiwibWF0Y2giLCJjc3NJbXBvcnRQYXRoIiwiY3NzUmVzb3VyY2UiLCJhZGRTdHlsZVRhZyIsImNsZWFyUGFnZVJlc291cmNlcyIsInJlc291cmNlIiwiZGlzcG9zZSIsIm9sZENoYXJ0cyIsImNoYXJ0cyIsIm9sZENoYXJ0IiwiZGVzdHJveSIsInNjcmlwdHNUb1JlbW92ZSIsImdldEVsZW1lbnRzQnlUYWdOYW1lIiwic3R5bGVzVG9SZW1vdmUiLCJsaW5rc1RvUmVtb3ZlIiwiZWxlbWVudCIsInJlbW92ZSIsInNldENvbnRlbnQiLCJjc3NUZW1wbGF0ZSIsInN2Z1RlbXBsYXRlIiwicHVwcGV0ZWVyRXhwb3J0IiwiaXNTVkciLCJzaXplIiwic3ZnRWxlbWVudCIsInF1ZXJ5U2VsZWN0b3IiLCJjaGFydEhlaWdodCIsImJhc2VWYWwiLCJjaGFydFdpZHRoIiwic3R5bGUiLCJ6b29tIiwibWFyZ2luIiwicGFyc2VGbG9hdCIsIngiLCJ5IiwiX2dldENsaXBSZWdpb24iLCJ2aWV3cG9ydEhlaWdodCIsImFicyIsImNlaWwiLCJ2aWV3cG9ydFdpZHRoIiwicmVzdWx0Iiwic2V0Vmlld3BvcnQiLCJkZXZpY2VTY2FsZUZhY3RvciIsIl9jcmVhdGVTVkciLCJfY3JlYXRlSW1hZ2UiLCJfY3JlYXRlUERGIiwiJGV2YWwiLCJnZXRCb3VuZGluZ0NsaWVudFJlY3QiLCJ0cnVuYyIsIm91dGVySFRNTCIsImNsaXAiLCJyYWNlIiwic2NyZWVuc2hvdCIsImVuY29kaW5nIiwiZnVsbFBhZ2UiLCJvcHRpbWl6ZUZvclNwZWVkIiwiY2FwdHVyZUJleW9uZFZpZXdwb3J0IiwicXVhbGl0eSIsIm9taXRCYWNrZ3JvdW5kIiwiX3Jlc29sdmUiLCJlbXVsYXRlTWVkaWFUeXBlIiwicGRmIiwicG9vbFN0YXRzIiwiZXhwb3J0c0F0dGVtcHRlZCIsImV4cG9ydHNQZXJmb3JtZWQiLCJleHBvcnRzRHJvcHBlZCIsImV4cG9ydHNGcm9tU3ZnIiwiZXhwb3J0c0Zyb21PcHRpb25zIiwiZXhwb3J0c0Zyb21TdmdBdHRlbXB0cyIsImV4cG9ydHNGcm9tT3B0aW9uc0F0dGVtcHRzIiwidGltZVNwZW50IiwidGltZVNwZW50QXZlcmFnZSIsImluaXRQb29sIiwicG9vbE9wdGlvbnMiLCJQb29sIiwiX2ZhY3RvcnkiLCJhY3F1aXJlVGltZW91dE1pbGxpcyIsImNyZWF0ZVRpbWVvdXRNaWxsaXMiLCJkZXN0cm95VGltZW91dE1pbGxpcyIsImlkbGVUaW1lb3V0TWlsbGlzIiwiY3JlYXRlUmV0cnlJbnRlcnZhbE1pbGxpcyIsInJlYXBJbnRlcnZhbE1pbGxpcyIsInByb3BhZ2F0ZUNyZWF0ZUVycm9yIiwiY2xlYXJTdGF0dXMiLCJfZXZlbnRJZCIsImluaXRpYWxSZXNvdXJjZXMiLCJhY3F1aXJlIiwicHJvbWlzZSIsInJlbGVhc2UiLCJraWxsUG9vbCIsIndvcmtlciIsInVzZWQiLCJkZXN0cm95ZWQiLCJwb3N0V29yayIsIndvcmtlckhhbmRsZSIsImdldFBvb2xJbmZvIiwiYWNxdWlyZUNvdW50ZXIiLCJ3b3JrU3RhcnQiLCJleHBvcnRDb3VudGVyIiwiZXhwb3J0VGltZSIsImdldFBvb2xTdGF0cyIsImdldFBvb2xJbmZvSlNPTiIsIm51bVVzZWQiLCJhdmFpbGFibGUiLCJudW1GcmVlIiwiYWxsQ3JlYXRlZCIsInBlbmRpbmdBY3F1aXJlcyIsIm51bVBlbmRpbmdBY3F1aXJlcyIsInBlbmRpbmdDcmVhdGVzIiwibnVtUGVuZGluZ0NyZWF0ZXMiLCJwZW5kaW5nVmFsaWRhdGlvbnMiLCJudW1QZW5kaW5nVmFsaWRhdGlvbnMiLCJwZW5kaW5nRGVzdHJveXMiLCJhYnNvbHV0ZUFsbCIsImNyZWF0ZSIsInJhbmRvbSIsInN0YXJ0RGF0ZSIsInZhbGlkYXRlIiwibWFpbkZyYW1lIiwiZGV0YWNoZWQiLCJyZW1vdmVBbGxMaXN0ZW5lcnMiLCJzYW5pdGl6ZSIsIkpTRE9NIiwiRE9NUHVyaWZ5IiwiQUREX1RBR1MiLCJzaW5nbGVFeHBvcnQiLCJzdGFydEV4cG9ydCIsImJhdGNoRXhwb3J0IiwiYmF0Y2hGdW5jdGlvbnMiLCJwYWlyIiwiYmF0Y2hSZXN1bHRzIiwiYWxsU2V0dGxlZCIsInJlYXNvbiIsImV4cG9ydGluZ09wdGlvbnMiLCJlbmRDYWxsYmFjayIsImZpbGVDb250ZW50IiwiX2V4cG9ydEZyb21TdmciLCJfZXhwb3J0RnJvbU9wdGlvbnMiLCJnZXRBbGxvd0NvZGVFeGVjdXRpb24iLCJzZXRBbGxvd0NvZGVFeGVjdXRpb24iLCJpbnB1dFRvRXhwb3J0IiwiX3ByZXBhcmVFeHBvcnQiLCJfaGFuZGxlQ3VzdG9tTG9naWMiLCJfaGFuZGxlR2xvYmFsQW5kVGhlbWUiLCJfZmluZENoYXJ0U2l6ZSIsIm9wdGlvbnNDaGFydCIsIm9wdGlvbnNFeHBvcnRpbmciLCJnbG9iYWxPcHRpb25zQ2hhcnQiLCJnbG9iYWxPcHRpb25zRXhwb3J0aW5nIiwidGhlbWVPcHRpb25zQ2hhcnQiLCJ0aGVtZU9wdGlvbnNFeHBvcnRpbmciLCJzb3VyY2VIZWlnaHQiLCJzb3VyY2VXaWR0aCIsInBhcmFtIiwiX2hhbmRsZVJlc291cmNlcyIsImFsbG93ZWRQcm9wcyIsImhhbmRsZWRSZXNvdXJjZXMiLCJjb3JyZWN0UmVzb3VyY2VzIiwicHJvcE5hbWUiLCJvcHRpb25zTmFtZSIsInRpbWVySWRzIiwiYWRkVGltZXIiLCJjbGVhckFsbFRpbWVycyIsImNsZWFySW50ZXJ2YWwiLCJjbGVhclRpbWVvdXQiLCJsb2dFcnJvck1pZGRsZXdhcmUiLCJyZXF1ZXN0IiwibmV4dCIsInJldHVybkVycm9yTWlkZGxld2FyZSIsInN0YXR1cyIsImpzb24iLCJlcnJvck1pZGRsZXdhcmUiLCJhcHAiLCJ1c2UiLCJyYXRlTGltaXRpbmdNaWRkbGV3YXJlIiwicmF0ZUxpbWl0aW5nT3B0aW9ucyIsInJhdGVPcHRpb25zIiwibGltaXRlciIsInJhdGVMaW1pdCIsIndpbmRvd01zIiwibGltaXQiLCJkZWxheU1zIiwiaGFuZGxlciIsImZvcm1hdCIsInNlbmQiLCJkZWZhdWx0Iiwic2tpcCIsInF1ZXJ5IiwiYWNjZXNzX3Rva2VuIiwiY29udGVudFR5cGVNaWRkbGV3YXJlIiwiY29udGVudFR5cGUiLCJoZWFkZXJzIiwicmVxdWVzdEJvZHlNaWRkbGV3YXJlIiwiY29ubmVjdGlvbiIsInJlbW90ZUFkZHJlc3MiLCJ2YWxpZGF0ZWRPcHRpb25zIiwiZmlsZW5hbWUiLCJ2YWxpZGF0aW9uTWlkZGxld2FyZSIsInBvc3QiLCJyZXZlcnNlZE1pbWUiLCJwbmciLCJqcGVnIiwiZ2lmIiwicmVxdWVzdEV4cG9ydCIsInJlcXVlc3RDb3VudGVyIiwiY29ubmVjdGlvbkFib3J0ZWQiLCJzb2NrZXQiLCJoYWRFcnJvcnMiLCJoZWFkZXIiLCJhdHRhY2htZW50IiwiZXhwb3J0Um91dGVzIiwic2VydmVyU3RhcnRUaW1lIiwicGFja2FnZUZpbGUiLCJzdWNjZXNzUmF0ZXMiLCJyZWNvcmRJbnRlcnZhbCIsIndpbmRvd1NpemUiLCJfY2FsY3VsYXRlTW92aW5nQXZlcmFnZSIsImEiLCJiIiwiX3N0YXJ0U3VjY2Vzc1JhdGUiLCJzZXRJbnRlcnZhbCIsInN0YXRzIiwic3VjY2Vzc1JhdGlvIiwiaGVhbHRoUm91dGVzIiwicGVyaW9kIiwibW92aW5nQXZlcmFnZSIsImJvb3RUaW1lIiwidXB0aW1lIiwiZmxvb3IiLCJzZXJ2ZXJWZXJzaW9uIiwiaGlnaGNoYXJ0c1ZlcnNpb24iLCJhdmVyYWdlRXhwb3J0VGltZSIsImF0dGVtcHRlZEV4cG9ydHMiLCJwZXJmb3JtZWRFeHBvcnRzIiwiZmFpbGVkRXhwb3J0cyIsInN1Y2Vzc1JhdGlvIiwidG9GaXhlZCIsInN2Z0V4cG9ydHMiLCJqc29uRXhwb3J0cyIsInN2Z0V4cG9ydHNBdHRlbXB0cyIsImpzb25FeHBvcnRzQXR0ZW1wdHMiLCJ1aVJvdXRlcyIsInNlbmRGaWxlIiwiYWNjZXB0UmFuZ2VzIiwidmVyc2lvbkNoYW5nZVJvdXRlcyIsInRva2VuIiwiYWN0aXZlU2VydmVycyIsIk1hcCIsImV4cHJlc3MiLCJzdGFydFNlcnZlciIsInNlcnZlck9wdGlvbnMiLCJ1cGxvYWRMaW1pdEJ5dGVzIiwic3RvcmFnZSIsIm11bHRlciIsIm1lbW9yeVN0b3JhZ2UiLCJ1cGxvYWQiLCJsaW1pdHMiLCJmaWVsZFNpemUiLCJkaXNhYmxlIiwiY29ycyIsIm1ldGhvZHMiLCJzZXQiLCJ1cmxlbmNvZGVkIiwiZXh0ZW5kZWQiLCJub25lIiwic3RhdGljIiwiaHR0cFNlcnZlciIsImNyZWF0ZVNlcnZlciIsIl9hdHRhY2hTZXJ2ZXJFcnJvckhhbmRsZXJzIiwibGlzdGVuIiwiY2VydCIsInJlYWRGaWxlIiwiaHR0cHNTZXJ2ZXIiLCJjbG9zZVNlcnZlcnMiLCJkZWxldGUiLCJnZXRTZXJ2ZXJzIiwiZ2V0RXhwcmVzcyIsImdldEFwcCIsIm1pZGRsZXdhcmVzIiwic2h1dGRvd25DbGVhblVwIiwiZXhpdENvZGUiLCJleGl0IiwiaW5pdEV4cG9ydCIsImluaXRPcHRpb25zIiwiX2F0dGFjaFByb2Nlc3NFeGl0TGlzdGVuZXJzIl0sIm1hcHBpbmdzIjoid25CQTJCTyxNQUFNQSxZQUFZQyxJQUFhQSxjQUFDLElBQUlDLElBQUksT0FBUSxvQkFBQUMsU0FBQUMsUUFBQSxPQUFBQyxjQUFBQyxZQUFBQyxLQUFBQyx3QkFBQSxXQUFBQSx1QkFBQUMsUUFBQUMsZUFBQUYsdUJBQUFHLEtBQUEsSUFBQVQsSUFBQSxZQUFBQyxTQUFBUyxTQUFBTCxPQStCaEQsU0FBU00sU0FBU0MsR0FFdkIsR0FBZSxPQUFYQSxHQUFxQyxpQkFBWEEsRUFDNUIsT0FBT0EsRUFJVCxNQUFNQyxFQUFhQyxNQUFNQyxRQUFRSCxHQUFVLEdBQUssR0FHaEQsSUFBSyxNQUFNSSxLQUFPSixFQUNaSyxPQUFPQyxVQUFVQyxlQUFlQyxLQUFLUixFQUFRSSxLQUMvQ0gsRUFBV0csR0FBT0wsU0FBU0MsRUFBT0ksS0FLdEMsT0FBT0gsQ0FDVCxDQTJETyxTQUFTUSxVQUFVQyxHQUN4QixJQUVFLE1BQU1DLEVBQWMsR0FBR0QsRUFBT0UsY0FBY0MsUUFBUSxRQUFTLFdBUTdELE1BTG9CLFVBQWhCRixHQUNGQSxFQUFZQyxjQUlQLENBQUMsUUFBUyxhQUFjLFdBQVksY0FBY0UsU0FDdkRILEdBRUVBLEVBQ0EsT0FDUixDQUFJLE1BRUEsTUFBTyxPQUNSLENBQ0gsQ0FZTyxTQUFTSSxXQUFXQyxFQUFNQyxHQU8vQixNQUFPLEdBTFVDLGdCQUFnQkQsR0FBVyxTQUN6Q0UsTUFBTSxLQUNOQyxXQUdtQkosR0FDeEIsQ0FhTyxTQUFTSyxRQUFRTCxFQUFNQyxFQUFVLE1BRXRDLE1BQU1LLEVBQVksQ0FDaEIsWUFBYSxNQUNiLGFBQWMsT0FDZCxrQkFBbUIsTUFDbkIs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 diff --git a/dist/index.esm.js b/dist/index.esm.js index f712f11f..6e43222d 100644 --- a/dist/index.esm.js +++ b/dist/index.esm.js @@ -1,2 +1,2 @@ -import"colors";import{readFileSync,existsSync,mkdirSync,appendFile,writeFileSync}from"fs";import{isAbsolute,join}from"path";import{HttpsProxyAgent}from"https-proxy-agent";import{fileURLToPath}from"url";import dotenv from"dotenv";import{z}from"zod";import http from"http";import https from"https";import{Pool}from"tarn";import{v4}from"uuid";import puppeteer from"puppeteer";import DOMPurify from"dompurify";import{JSDOM}from"jsdom";import{readFile}from"fs/promises";import cors from"cors";import express from"express";import multer from"multer";import rateLimit from"express-rate-limit";const __dirname=fileURLToPath(new URL("../.",import.meta.url));function deepCopy(e){if(null===e||"object"!=typeof e)return e;const t=Array.isArray(e)?[]:{};for(const o in e)Object.prototype.hasOwnProperty.call(e,o)&&(t[o]=deepCopy(e[o]));return t}function fixConstr(e){try{const t=`${e.toLowerCase().replace("chart","")}Chart`;return"Chart"===t&&t.toLowerCase(),["chart","stockChart","mapChart","ganttChart"].includes(t)?t:"chart"}catch{return"chart"}}function fixOutfile(e,t){return`${getAbsolutePath(t||"chart").split(".").shift()}.${e}`}function fixType(e,t=null){const o={"image/png":"png","image/jpeg":"jpeg","application/pdf":"pdf","image/svg+xml":"svg"},n=Object.values(o);if(t){const o=t.split(".").pop();"jpg"===o?e="jpeg":n.includes(o)&&e!==o&&(e=o)}return o[e]||n.find((t=>t===e))||"png"}function getAbsolutePath(e){return isAbsolute(e)?e:join(__dirname,e)}function getBase64(e,t){return"pdf"===t||"svg"==t?Buffer.from(e,"utf8").toString("base64"):e}function getNewDate(){return(new Date).toString().split("(")[0].trim()}function getNewDateTime(){return(new Date).getTime()}function isObject(e){return"[object Object]"===Object.prototype.toString.call(e)}function isObjectEmpty(e){return"object"==typeof e&&!Array.isArray(e)&&null!==e&&0===Object.keys(e).length}function isPrivateRangeUrlFound(e){return[/xlink:href="(?:http:\/\/|https:\/\/)?localhost\b/,/xlink:href="(?:http:\/\/|https:\/\/)?10\.\d{1,3}\.\d{1,3}\.\d{1,3}\b/,/xlink:href="(?:http:\/\/|https:\/\/)?127\.\d{1,3}\.\d{1,3}\.\d{1,3}\b/,/xlink:href="(?:http:\/\/|https:\/\/)?172\.(1[6-9]|2[0-9]|3[0-1])\.\d{1,3}\.\d{1,3}\b/,/xlink:href="(?:http:\/\/|https:\/\/)?192\.168\.\d{1,3}\.\d{1,3}\b/].some((t=>t.test(e)))}function measureTime(){const e=process.hrtime.bigint();return()=>Number(process.hrtime.bigint()-e)/1e6}function roundNumber(e,t=1){const o=Math.pow(10,t||0);return Math.round(+e*o)/o}function wrapAround(e,t,o=!1){if(e&&"string"==typeof e)return(e=e.trim()).endsWith(".js")?t?wrapAround(readFileSync(getAbsolutePath(e),"utf8"),t,o):null:!o&&(e.startsWith("function()")||e.startsWith("function ()")||e.startsWith("()=>")||e.startsWith("() =>"))?`(${e})()`:e.replace(/;$/,"")}const colors=["red","yellow","blue","gray","green"],logging={toConsole:!0,toFile:!1,pathCreated:!1,pathToLog:"",levelsDesc:[{title:"error",color:colors[0]},{title:"warning",color:colors[1]},{title:"notice",color:colors[2]},{title:"verbose",color:colors[3]},{title:"benchmark",color:colors[4]}]};function log(...e){const[t,...o]=e,{levelsDesc:n,level:r}=logging;if(5!==t&&(0===t||t>r||r>n.length))return;const i=`${getNewDate()} [${n[t-1].title}] -`;logging.toFile&&_logToFile(o,i),logging.toConsole&&console.log.apply(void 0,[i.toString()[logging.levelsDesc[t-1].color]].concat(o))}function logWithStack(e,t,o){const n=o||t&&t.message||"",{level:r,levelsDesc:i}=logging;if(0===e||e>r||r>i.length)return;const s=`${getNewDate()} [${i[e-1].title}] -`,a=t&&t.stack,l=[n];a&&l.push("\n",a),logging.toFile&&_logToFile(l,s),logging.toConsole&&console.log.apply(void 0,[s.toString()[logging.levelsDesc[e-1].color]].concat([l.shift()[colors[e-1]],...l]))}function logZodIssues(e,t=[],o){logWithStack(e,null,[`${o} - the following Zod issues occured:`,...t.map((e=>`- ${e.message}`))].join("\n"))}function initLogging(e){const{level:t,dest:o,file:n,toConsole:r,toFile:i}=e;logging.pathCreated=!1,logging.pathToLog="",setLogLevel(t),enableConsoleLogging(r),enableFileLogging(o,n,i)}function setLogLevel(e){Number.isInteger(e)&&e>=0&&e<=logging.levelsDesc.length&&(logging.level=e)}function enableConsoleLogging(e){logging.toConsole=!!e}function enableFileLogging(e,t,o){logging.toFile=!!o,logging.toFile&&(logging.dest=e||"",logging.file=t||"")}function _logToFile(e,t){logging.pathCreated||(!existsSync(getAbsolutePath(logging.dest))&&mkdirSync(getAbsolutePath(logging.dest)),logging.pathToLog=getAbsolutePath(join(logging.dest,logging.file)),logging.pathCreated=!0),appendFile(logging.pathToLog,[t].concat(e).join(" ")+"\n",(e=>{e&&logging.toFile&&logging.pathCreated&&(logging.toFile=!1,logging.pathCreated=!1,logWithStack(2,e,"[logger] Unable to write to log file."))}))}const defaultConfig={puppeteer:{args:{value:["--allow-running-insecure-content","--ash-no-nudges","--autoplay-policy=user-gesture-required","--block-new-web-contents","--disable-accelerated-2d-canvas","--disable-background-networking","--disable-background-timer-throttling","--disable-backgrounding-occluded-windows","--disable-breakpad","--disable-checker-imaging","--disable-client-side-phishing-detection","--disable-component-extensions-with-background-pages","--disable-component-update","--disable-default-apps","--disable-dev-shm-usage","--disable-domain-reliability","--disable-extensions","--disable-features=CalculateNativeWinOcclusion,InterestFeedContentSuggestions,WebOTP","--disable-hang-monitor","--disable-ipc-flooding-protection","--disable-logging","--disable-notifications","--disable-offer-store-unmasked-wallet-cards","--disable-popup-blocking","--disable-print-preview","--disable-prompt-on-repost","--disable-renderer-backgrounding","--disable-search-engine-choice-screen","--disable-session-crashed-bubble","--disable-setuid-sandbox","--disable-site-isolation-trials","--disable-speech-api","--disable-sync","--enable-unsafe-webgpu","--hide-crash-restore-bubble","--hide-scrollbars","--metrics-recording-only","--mute-audio","--no-default-browser-check","--no-first-run","--no-pings","--no-sandbox","--no-startup-window","--no-zygote","--password-store=basic","--process-per-tab","--use-mock-keychain"],types:["string[]"],envLink:"PUPPETEER_ARGS",cliName:"puppeteerArgs",description:"Array of Puppeteer arguments",promptOptions:{type:"list",separator:";"}}},highcharts:{version:{value:"latest",types:["string"],envLink:"HIGHCHARTS_VERSION",description:"Highcharts version",promptOptions:{type:"text"}},cdnUrl:{value:"https://code.highcharts.com",types:["string"],envLink:"HIGHCHARTS_CDN_URL",description:"CDN URL for Highcharts scripts",promptOptions:{type:"text"}},forceFetch:{value:!1,types:["boolean"],envLink:"HIGHCHARTS_FORCE_FETCH",description:"Flag to refetch scripts after each server rerun",promptOptions:{type:"toggle"}},cachePath:{value:".cache",types:["string"],envLink:"HIGHCHARTS_CACHE_PATH",description:"Directory path for cached Highcharts scripts",promptOptions:{type:"text"}},coreScripts:{value:["highcharts","highcharts-more","highcharts-3d"],types:["string[]"],envLink:"HIGHCHARTS_CORE_SCRIPTS",description:"Highcharts core scripts to fetch",promptOptions:{type:"multiselect",instructions:"Space: Select specific, A: Select all, Enter: Confirm"}},moduleScripts:{value:["stock","map","gantt","exporting","parallel-coordinates","accessibility","boost-canvas","boost","data","data-tools","draggable-points","static-scale","broken-axis","heatmap","tilemap","tiledwebmap","timeline","treemap","treegraph","item-series","drilldown","histogram-bellcurve","bullet","funnel","funnel3d","geoheatmap","pyramid3d","networkgraph","overlapping-datalabels","pareto","pattern-fill","pictorial","price-indicator","sankey","arc-diagram","dependency-wheel","series-label","series-on-point","solid-gauge","sonification","streamgraph","sunburst","variable-pie","variwide","vector","venn","windbarb","wordcloud","xrange","no-data-to-display","drag-panes","debugger","dumbbell","lollipop","cylinder","organization","dotplot","marker-clusters","hollowcandlestick","heikinashi","flowmap","export-data","navigator","textpath"],types:["string[]"],envLink:"HIGHCHARTS_MODULE_SCRIPTS",description:"Highcharts module scripts to fetch",promptOptions:{type:"multiselect",instructions:"Space: Select specific, A: Select all, Enter: Confirm"}},indicatorScripts:{value:["indicators-all"],types:["string[]"],envLink:"HIGHCHARTS_INDICATOR_SCRIPTS",description:"Highcharts indicator scripts to fetch",promptOptions:{type:"multiselect",instructions:"Space: Select specific, A: Select all, Enter: Confirm"}},customScripts:{value:["https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.30.1/moment.min.js","https://cdnjs.cloudflare.com/ajax/libs/moment-timezone/0.5.45/moment-timezone-with-data.min.js"],types:["string[]"],envLink:"HIGHCHARTS_CUSTOM_SCRIPTS",description:"Additional custom scripts or dependencies to fetch",promptOptions:{type:"list",separator:";"}}},export:{infile:{value:null,types:["string","null"],envLink:"EXPORT_INFILE",description:"Input filename with type, formatted correctly as JSON or SVG",promptOptions:{type:"text"}},instr:{value:null,types:["Object","string","null"],envLink:"EXPORT_INSTR",description:"Overrides the `infile` with JSON, stringified JSON, or SVG input",promptOptions:{type:"text"}},options:{value:null,types:["Object","string","null"],envLink:"EXPORT_OPTIONS",description:"Alias for the `instr` option",promptOptions:{type:"text"}},svg:{value:null,types:["string","null"],envLink:"EXPORT_SVG",description:"SVG string representation of the chart to render",promptOptions:{type:"text"}},batch:{value:null,types:["string","null"],envLink:"EXPORT_BATCH",description:'Batch job string with input/output pairs: "in=out;in=out;..."',promptOptions:{type:"text"}},outfile:{value:null,types:["string","null"],envLink:"EXPORT_OUTFILE",description:"Output filename with type. Can be jpeg, png, pdf, or svg and ignores `type` option",promptOptions:{type:"text"}},type:{value:"png",types:["string"],envLink:"EXPORT_TYPE",description:"File export format. Can be jpeg, png, pdf, or svg",promptOptions:{type:"select",hint:"Default: png",choices:["png","jpeg","pdf","svg"]}},constr:{value:"chart",types:["string"],envLink:"EXPORT_CONSTR",description:"Chart constructor. Can be chart, stockChart, mapChart, or ganttChart",promptOptions:{type:"select",hint:"Default: chart",choices:["chart","stockChart","mapChart","ganttChart"]}},b64:{value:!1,types:["boolean"],envLink:"EXPORT_B64",description:"Whether or not to the chart should be received in Base64 format instead of binary",promptOptions:{type:"toggle"}},noDownload:{value:!1,types:["boolean"],envLink:"EXPORT_NO_DOWNLOAD",description:"Whether or not to include or exclude attachment headers in the response",promptOptions:{type:"toggle"}},height:{value:null,types:["number","null"],envLink:"EXPORT_HEIGHT",description:"Height of the exported chart, overrides chart settings",promptOptions:{type:"number"}},width:{value:null,types:["number","null"],envLink:"EXPORT_WIDTH",description:"Width of the exported chart, overrides chart settings",promptOptions:{type:"number"}},scale:{value:null,types:["number","null"],envLink:"EXPORT_SCALE",description:"Scale of the exported chart, overrides chart settings. Ranges from 0.1 to 5.0",promptOptions:{type:"number"}},defaultHeight:{value:400,types:["number"],envLink:"EXPORT_DEFAULT_HEIGHT",description:"Default height of the exported chart if not set",promptOptions:{type:"number"}},defaultWidth:{value:600,types:["number"],envLink:"EXPORT_DEFAULT_WIDTH",description:"Default width of the exported chart if not set",promptOptions:{type:"number"}},defaultScale:{value:1,types:["number"],envLink:"EXPORT_DEFAULT_SCALE",description:"Default scale of the exported chart if not set. Ranges from 0.1 to 5.0",promptOptions:{type:"number",min:.1,max:5}},globalOptions:{value:null,types:["Object","string","null"],envLink:"EXPORT_GLOBAL_OPTIONS",description:"JSON, stringified JSON or filename with global options for Highcharts.setOptions",promptOptions:{type:"text"}},themeOptions:{value:null,types:["Object","string","null"],envLink:"EXPORT_THEME_OPTIONS",description:"JSON, stringified JSON or filename with theme options for Highcharts.setOptions",promptOptions:{type:"text"}},rasterizationTimeout:{value:1500,types:["number"],envLink:"EXPORT_RASTERIZATION_TIMEOUT",description:"Milliseconds to wait for webpage rendering",promptOptions:{type:"number"}}},customLogic:{allowCodeExecution:{value:!1,types:["boolean"],envLink:"CUSTOM_LOGIC_ALLOW_CODE_EXECUTION",description:"Allows or disallows execution of arbitrary code during exporting",promptOptions:{type:"toggle"}},allowFileResources:{value:!1,types:["boolean"],envLink:"CUSTOM_LOGIC_ALLOW_FILE_RESOURCES",description:"Allows or disallows injection of filesystem resources (disabled in server mode)",promptOptions:{type:"toggle"}},customCode:{value:null,types:["string","null"],envLink:"CUSTOM_LOGIC_CUSTOM_CODE",description:"Custom code to execute before chart initialization. Can be a function, code wrapped in a function, or a .js filename",promptOptions:{type:"text"}},callback:{value:null,types:["string","null"],envLink:"CUSTOM_LOGIC_CALLBACK",description:"JavaScript code to run during construction. Can be a function or a .js filename",promptOptions:{type:"text"}},resources:{value:null,types:["Object","string","null"],envLink:"CUSTOM_LOGIC_RESOURCES",description:"Additional resources as JSON, stringified JSON, or filename, containing files, js, and css sections",promptOptions:{type:"text"}},loadConfig:{value:null,types:["string","null"],envLink:"CUSTOM_LOGIC_LOAD_CONFIG",legacyName:"fromFile",description:"File with a pre-defined configuration to use",promptOptions:{type:"text"}},createConfig:{value:null,types:["string","null"],envLink:"CUSTOM_LOGIC_CREATE_CONFIG",description:"Prompt-based option setting, saved to a provided config file",promptOptions:{type:"text"}}},server:{enable:{value:!1,types:["boolean"],envLink:"SERVER_ENABLE",cliName:"enableServer",description:"Starts the server when true",promptOptions:{type:"toggle"}},host:{value:"0.0.0.0",types:["string"],envLink:"SERVER_HOST",description:"Hostname of the server",promptOptions:{type:"text"}},port:{value:7801,types:["number"],envLink:"SERVER_PORT",description:"Port number for the server",promptOptions:{type:"number"}},uploadLimit:{value:3,types:["number"],envLink:"SERVER_UPLOAD_LIMIT",description:"Maximum request body size in MB",promptOptions:{type:"number"}},benchmarking:{value:!1,types:["boolean"],envLink:"SERVER_BENCHMARKING",cliName:"serverBenchmarking",description:"Displays or not action durations in milliseconds during server requests",promptOptions:{type:"toggle"}},proxy:{host:{value:null,types:["string","null"],envLink:"SERVER_PROXY_HOST",cliName:"proxyHost",description:"Host of the proxy server, if applicable",promptOptions:{type:"text"}},port:{value:null,types:["number","null"],envLink:"SERVER_PROXY_PORT",cliName:"proxyPort",description:"Port of the proxy server, if applicable",promptOptions:{type:"number"}},timeout:{value:5e3,types:["number"],envLink:"SERVER_PROXY_TIMEOUT",cliName:"proxyTimeout",description:"Timeout in milliseconds for the proxy server, if applicable",promptOptions:{type:"number"}}},rateLimiting:{enable:{value:!1,types:["boolean"],envLink:"SERVER_RATE_LIMITING_ENABLE",cliName:"enableRateLimiting",description:"Enables or disables rate limiting on the server",promptOptions:{type:"toggle"}},maxRequests:{value:10,types:["number"],envLink:"SERVER_RATE_LIMITING_MAX_REQUESTS",legacyName:"rateLimit",description:"Maximum number of requests allowed per minute",promptOptions:{type:"number"}},window:{value:1,types:["number"],envLink:"SERVER_RATE_LIMITING_WINDOW",description:"Time window in minutes for rate limiting",promptOptions:{type:"number"}},delay:{value:0,types:["number"],envLink:"SERVER_RATE_LIMITING_DELAY",description:"Delay duration between successive requests before reaching the limit",promptOptions:{type:"number"}},trustProxy:{value:!1,types:["boolean"],envLink:"SERVER_RATE_LIMITING_TRUST_PROXY",description:"Set to true if the server is behind a load balancer",promptOptions:{type:"toggle"}},skipKey:{value:null,types:["string","null"],envLink:"SERVER_RATE_LIMITING_SKIP_KEY",description:"Key to bypass the rate limiter, used with `skipToken`",promptOptions:{type:"text"}},skipToken:{value:null,types:["string","null"],envLink:"SERVER_RATE_LIMITING_SKIP_TOKEN",description:"Token to bypass the rate limiter, used with `skipKey`",promptOptions:{type:"text"}}},ssl:{enable:{value:!1,types:["boolean"],envLink:"SERVER_SSL_ENABLE",cliName:"enableSsl",description:"Enables or disables SSL protocol",promptOptions:{type:"toggle"}},force:{value:!1,types:["boolean"],envLink:"SERVER_SSL_FORCE",cliName:"sslForce",legacyName:"sslOnly",description:"Forces the server to use HTTPS only when true",promptOptions:{type:"toggle"}},port:{value:443,types:["number"],envLink:"SERVER_SSL_PORT",cliName:"sslPort",description:"Port for the SSL server",promptOptions:{type:"number"}},certPath:{value:null,types:["string","null"],envLink:"SERVER_SSL_CERT_PATH",cliName:"sslCertPath",legacyName:"sslPath",description:"Path to the SSL certificate/key file",promptOptions:{type:"text"}}}},pool:{minWorkers:{value:4,types:["number"],envLink:"POOL_MIN_WORKERS",description:"Minimum and initial number of pool workers to spawn",promptOptions:{type:"number"}},maxWorkers:{value:8,types:["number"],envLink:"POOL_MAX_WORKERS",legacyName:"workers",description:"Maximum number of pool workers to spawn",promptOptions:{type:"number"}},workLimit:{value:40,types:["number"],envLink:"POOL_WORK_LIMIT",description:"Number of tasks a worker can handle before restarting",promptOptions:{type:"number"}},acquireTimeout:{value:5e3,types:["number"],envLink:"POOL_ACQUIRE_TIMEOUT",description:"Timeout in milliseconds for acquiring a resource",promptOptions:{type:"number"}},createTimeout:{value:5e3,types:["number"],envLink:"POOL_CREATE_TIMEOUT",description:"Timeout in milliseconds for creating a resource",promptOptions:{type:"number"}},destroyTimeout:{value:5e3,types:["number"],envLink:"POOL_DESTROY_TIMEOUT",description:"Timeout in milliseconds for destroying a resource",promptOptions:{type:"number"}},idleTimeout:{value:3e4,types:["number"],envLink:"POOL_IDLE_TIMEOUT",description:"Timeout in milliseconds for destroying idle resources",promptOptions:{type:"number"}},createRetryInterval:{value:200,types:["number"],envLink:"POOL_CREATE_RETRY_INTERVAL",description:"Interval in milliseconds before retrying resource creation on failure",promptOptions:{type:"number"}},reaperInterval:{value:1e3,types:["number"],envLink:"POOL_REAPER_INTERVAL",description:"Interval in milliseconds to check and destroy idle resources",promptOptions:{type:"number"}},benchmarking:{value:!1,types:["boolean"],envLink:"POOL_BENCHMARKING",cliName:"poolBenchmarking",description:"Shows statistics for the pool of resources",promptOptions:{type:"toggle"}}},logging:{level:{value:4,types:["number"],envLink:"LOGGING_LEVEL",cliName:"logLevel",description:"Logging verbosity level",promptOptions:{type:"number",round:0,min:0,max:5}},file:{value:"highcharts-export-server.log",types:["string"],envLink:"LOGGING_FILE",cliName:"logFile",description:"Log file name. Requires `logToFile` and `logDest` to be set",promptOptions:{type:"text"}},dest:{value:"log",types:["string"],envLink:"LOGGING_DEST",cliName:"logDest",description:"Path to store log files. Requires `logToFile` to be set",promptOptions:{type:"text"}},toConsole:{value:!0,types:["boolean"],envLink:"LOGGING_TO_CONSOLE",cliName:"logToConsole",description:"Enables or disables console logging",promptOptions:{type:"toggle"}},toFile:{value:!0,types:["boolean"],envLink:"LOGGING_TO_FILE",cliName:"logToFile",description:"Enables or disables logging to a file",promptOptions:{type:"toggle"}}},ui:{enable:{value:!1,types:["boolean"],envLink:"UI_ENABLE",cliName:"enableUi",description:"Enables or disables the UI for the export server",promptOptions:{type:"toggle"}},route:{value:"/",types:["string"],envLink:"UI_ROUTE",cliName:"uiRoute",description:"The endpoint route for the UI",promptOptions:{type:"text"}}},other:{nodeEnv:{value:"production",types:["string"],envLink:"OTHER_NODE_ENV",description:"The Node.js environment type",promptOptions:{type:"text"}},listenToProcessExits:{value:!0,types:["boolean"],envLink:"OTHER_LISTEN_TO_PROCESS_EXITS",description:"Whether or not to attach process.exit handlers",promptOptions:{type:"toggle"}},noLogo:{value:!1,types:["boolean"],envLink:"OTHER_NO_LOGO",description:"Display or skip printing the logo on startup",promptOptions:{type:"toggle"}},hardResetPage:{value:!1,types:["boolean"],envLink:"OTHER_HARD_RESET_PAGE",description:"Whether or not to reset the page content entirely",promptOptions:{type:"toggle"}},browserShellMode:{value:!0,types:["boolean"],envLink:"OTHER_BROWSER_SHELL_MODE",description:"Whether or not to set the browser to run in shell mode",promptOptions:{type:"toggle"}}},debug:{enable:{value:!1,types:["boolean"],envLink:"DEBUG_ENABLE",cliName:"enableDebug",description:"Enables or disables debug mode for the underlying browser",promptOptions:{type:"toggle"}},headless:{value:!1,types:["boolean"],envLink:"DEBUG_HEADLESS",description:"Whether or not to set the browser to run in headless mode during debugging",promptOptions:{type:"toggle"}},devtools:{value:!1,types:["boolean"],envLink:"DEBUG_DEVTOOLS",description:"Enables or disables DevTools in headful mode",promptOptions:{type:"toggle"}},listenToConsole:{value:!1,types:["boolean"],envLink:"DEBUG_LISTEN_TO_CONSOLE",description:"Enables or disables listening to console messages from the browser",promptOptions:{type:"toggle"}},dumpio:{value:!1,types:["boolean"],envLink:"DEBUG_DUMPIO",description:"Redirects or not browser stdout and stderr to process.stdout and process.stderr",promptOptions:{type:"toggle"}},slowMo:{value:0,types:["number"],envLink:"DEBUG_SLOW_MO",description:"Delays Puppeteer operations by the specified milliseconds",promptOptions:{type:"number"}},debuggingPort:{value:9222,types:["number"],envLink:"DEBUG_DEBUGGING_PORT",description:"Port used for debugging",promptOptions:{type:"number"}}}},nestedProps=_createNestedProps(defaultConfig),absoluteProps=_createAbsoluteProps(defaultConfig);function _createNestedProps(e,t={},o=""){return Object.keys(e).forEach((n=>{const r=e[n];void 0===r.value?_createNestedProps(r,t,`${o}.${n}`):(t[r.cliName||n]=`${o}.${n}`.substring(1),void 0!==r.legacyName&&(t[r.legacyName]=`${o}.${n}`.substring(1)))})),t}function _createAbsoluteProps(e,t=[]){return Object.keys(e).forEach((o=>{const n=e[o];void 0===n.types?_createAbsoluteProps(n,t):n.types.includes("Object")&&t.push(o)})),t}dotenv.config();const{coreScripts:coreScripts,moduleScripts:moduleScripts,indicatorScripts:indicatorScripts}=defaultConfig.highcharts;z.setErrorMap(_customErrorMap);const v={boolean:e=>e?z.boolean():z.union([z.enum(["true","false","undefined","null",""]).transform((e=>["undefined","null",""].includes(e)?null:"true"===e)),z.boolean()]).nullable(),string:e=>e?z.string().trim().refine((e=>!["false","undefined","null",""].includes(e)),{params:{errorMessage:"The string contains a forbidden value"}}):z.string().trim().transform((e=>["false","undefined","null",""].includes(e)?null:e)).nullable(),enum:(e,t)=>t?z.enum([...e]):z.enum([...e,"undefined","null",""]).transform((e=>["undefined","null",""].includes(e)?null:e)).nullable(),stringArray(e,t,o){const n=z.string().trim().array(),r=z.string().trim().transform((e=>(e.startsWith("[")&&(e=e.slice(1)),e.endsWith("]")&&(e=e.slice(0,-1)),e.split(t)))),i=t=>t.map((e=>e.trim())).filter(e);return o?n.transform(i):z.union([r,n]).transform(i).transform((e=>e.length?e:null)).nullable()},positiveNum:e=>e?z.number().positive():z.union([z.string().trim().refine((e=>!isNaN(Number(e))&&Number(e)>0||["undefined","null",""].includes(e)),{params:{errorMessage:"The value must be numeric and positive"}}).transform((e=>["undefined","null",""].includes(e)?null:Number(e))),z.number().positive()]).nullable(),nonNegativeNum:e=>e?z.number().nonnegative():z.union([z.string().trim().refine((e=>!isNaN(Number(e))&&Number(e)>=0||["undefined","null",""].includes(e)),{params:{errorMessage:"The value must be numeric and non-negative"}}).transform((e=>["undefined","null",""].includes(e)?null:Number(e))),z.number().nonnegative()]).nullable(),startsWith:(e,t)=>t?z.string().trim().refine((t=>e.some((e=>t.startsWith(e)))),{params:{errorMessage:`The value must be a string that starts with ${e.join(", ")}`}}):z.string().trim().refine((t=>e.some((e=>t.startsWith(e)))||["undefined","null",""].includes(t)),{params:{errorMessage:`The value must be a string that starts with ${e.join(", ")}`}}).transform((e=>["undefined","null",""].includes(e)?null:e)).nullable(),chartConfig:()=>z.union([z.string().trim().refine((e=>e.indexOf("=0||e.indexOf("=0||e.startsWith("{")&&e.endsWith("}")||["undefined","null",""].includes(e)),{params:{errorMessage:"The value must be a string that contains '["undefined","null",""].includes(e)?null:e)),z.object({}).passthrough()]).nullable(),additionalOptions:()=>z.union([z.string().trim().refine((e=>e.length>=6&&e.endsWith(".json")||e.startsWith("{")&&e.endsWith("}")||["undefined","null",""].includes(e)),{params:{errorMessage:"The value must be a string that ends with '.json' or starts with '{' and ends with '}'"}}).transform((e=>["undefined","null",""].includes(e)?null:e)),z.object({}).passthrough()]).nullable()},config={args:e=>v.stringArray((e=>!["false","undefined","null",""].includes(e)),";",e),version:e=>e?z.string().trim().refine((e=>/^(latest|\d{1,2}(\.\d{1,2}){0,2})$/.test(e)),{params:{errorMessage:"The value must be 'latest', a major version, or in the form XX.YY.ZZ"}}):z.string().trim().refine((e=>/^(latest|\d{1,2}(\.\d{1,2}){0,2})$/.test(e)||["undefined","null",""].includes(e)),{params:{errorMessage:"The value must be 'latest', a major version, or in the form XX.YY.ZZ"}}).transform((e=>["undefined","null",""].includes(e)?null:e)).nullable(),cdnUrl:e=>v.startsWith(["http://","https://"],e),forceFetch:e=>v.boolean(e),cachePath:e=>v.string(e),adminToken:e=>v.string(e),coreScripts:e=>v.stringArray((e=>coreScripts.value.includes(e)),",",e),moduleScripts:e=>v.stringArray((e=>moduleScripts.value.includes(e)),",",e),indicatorScripts:e=>v.stringArray((e=>indicatorScripts.value.includes(e)),",",e),customScripts:e=>v.stringArray((e=>e.startsWith("https://")||e.startsWith("http://")),",",e),infile:e=>e?z.string().trim().refine((e=>e.length>=6&&e.endsWith(".json")||e.length>=5&&e.endsWith(".svg")),{params:{errorMessage:"The value must be a string that ends with .json or .svg"}}).nullable():z.string().trim().refine((e=>e.length>=6&&e.endsWith(".json")||e.length>=5&&e.endsWith(".svg")||["undefined","null",""].includes(e)),{params:{errorMessage:"The value must be a string that ends with .json or .svg"}}).transform((e=>["undefined","null",""].includes(e)?null:e)).nullable(),instr:()=>v.chartConfig(),options:()=>v.chartConfig(),svg:()=>z.string().trim().refine((e=>e.indexOf("=0||e.indexOf("=0||["false","undefined","null",""].includes(e)),{params:{errorMessage:"The value must be a string that contains '["false","undefined","null",""].includes(e)?null:e)).nullable(),outfile:e=>e?z.string().trim().refine((e=>e.length>=6&&e.endsWith(".jpeg")||e.length>=5&&(e.endsWith(".jpg")||e.endsWith(".png")||e.endsWith(".pdf")||e.endsWith(".svg"))),{params:{errorMessage:"The value must be a string that ends with .jpeg, .jpg, .png, .pdf, or .svg"}}).nullable():z.string().trim().refine((e=>e.length>=6&&e.endsWith(".jpeg")||e.length>=5&&(e.endsWith(".jpg")||e.endsWith(".png")||e.endsWith(".pdf")||e.endsWith(".svg"))||["undefined","null",""].includes(e)),{params:{errorMessage:"The value must be a string that ends with .jpeg, .jpg, .png, .pdf, or .svg"}}).transform((e=>["undefined","null",""].includes(e)?null:e)).nullable(),type:e=>v.enum(["jpeg","jpg","png","pdf","svg"],e),constr:e=>v.enum(["chart","stockChart","mapChart","ganttChart"],e),b64:e=>v.boolean(e),noDownload:e=>v.boolean(e),defaultHeight:e=>v.positiveNum(e),defaultWidth:e=>v.positiveNum(e),defaultScale:e=>e?z.number().gte(.1).lte(5):z.union([z.string().trim().refine((e=>!isNaN(Number(e))&&!0!==e&&!e.startsWith("[")&&Number(e)>=.1&&Number(e)<=5||["undefined","null",""].includes(e)),{params:{errorMessage:"The value must be within a 0.1 and 5.0 range"}}).transform((e=>["undefined","null",""].includes(e)?null:Number(e))),z.number().gte(.1).lte(5)]).nullable(),height(e){return this.defaultHeight(e).nullable()},width(e){return this.defaultWidth(e).nullable()},scale(e){return this.defaultScale(e).nullable()},globalOptions:()=>v.additionalOptions(),themeOptions:()=>v.additionalOptions(),batch:e=>v.string(e),rasterizationTimeout:e=>v.nonNegativeNum(e),allowCodeExecution:e=>v.boolean(e),allowFileResources:e=>v.boolean(e),customCode:e=>v.string(e),callback:e=>v.string(e),resources(e){const t=z.object({js:v.string(!1),css:v.string(!1),files:v.stringArray((e=>!["undefined","null",""].includes(e)),",",!0).nullable()}).partial(),o=z.string().trim().refine((e=>e.startsWith("{")&&e.endsWith("}")||e.length>=6&&e.endsWith(".json")),{params:{errorMessage:"The value must be a string that starts with '{' and ends with '}"}}),n=z.string().trim().refine((e=>e.startsWith("{")&&e.endsWith("}")||e.length>=6&&e.endsWith(".json")||["undefined","null",""].includes(e)),{params:{errorMessage:"The value must be a string that ends with '.json'"}}).transform((e=>["undefined","null",""].includes(e)?null:e));return e?z.union([t,o]).nullable():z.union([t,n]).nullable()},loadConfig:e=>v.string(e).refine((e=>null===e||e.length>=6&&e.endsWith(".json")),{params:{errorMessage:"The value must be a string that ends with .json "}}),createConfig(e){return this.loadConfig(e)},enableServer:e=>v.boolean(e),host:e=>v.string(e),port:e=>v.nonNegativeNum(e),uploadLimit:e=>v.positiveNum(e),serverBenchmarking:e=>v.boolean(e),proxyHost:e=>v.string(e),proxyPort:e=>v.nonNegativeNum(e).nullable(),proxyTimeout:e=>v.nonNegativeNum(e),enableRateLimiting:e=>v.boolean(e),maxRequests:e=>v.nonNegativeNum(e),window:e=>v.nonNegativeNum(e),delay:e=>v.nonNegativeNum(e),trustProxy:e=>v.boolean(e),skipKey:e=>v.string(e),skipToken:e=>v.string(e),enableSsl:e=>v.boolean(e),sslForce:e=>v.boolean(e),sslPort:e=>v.nonNegativeNum(e),sslCertPath:e=>v.string(e),minWorkers:e=>v.positiveNum(e),maxWorkers:e=>v.positiveNum(e),workLimit:e=>v.positiveNum(e),acquireTimeout:e=>v.nonNegativeNum(e),createTimeout:e=>v.nonNegativeNum(e),destroyTimeout:e=>v.nonNegativeNum(e),idleTimeout:e=>v.nonNegativeNum(e),createRetryInterval:e=>v.nonNegativeNum(e),reaperInterval:e=>v.nonNegativeNum(e),poolBenchmarking:e=>v.boolean(e),resourcesInterval:e=>v.nonNegativeNum(e),logLevel:e=>e?z.number().int().gte(0).lte(5):z.union([z.string().trim().refine((e=>!isNaN(Number(e))&&!0!==e&&!e.startsWith("[")&&Number.isInteger(Number(e))&&Number(e)>=0&&Number(e)<=5||["undefined","null",""].includes(e)),{params:{errorMessage:"The value must be within a 0 and 5 range"}}).transform((e=>["undefined","null",""].includes(e)?null:Number(e))),z.number().int().gte(0).lte(5)]).nullable(),logFile:e=>v.string(e).refine((e=>null===e||e.length>=5&&e.endsWith(".log")),{params:{errorMessage:"The value must be a string that ends with '.log'"}}),logDest:e=>v.string(e),logToConsole:e=>v.boolean(e),logToFile:e=>v.boolean(e),enableUi:e=>v.boolean(e),uiRoute:e=>v.startsWith(["/"],e),nodeEnv:e=>v.enum(["development","production","test"],e),listenToProcessExits:e=>v.boolean(e),noLogo:e=>v.boolean(e),hardResetPage:e=>v.boolean(e),browserShellMode:e=>v.boolean(e),enableDebug:e=>v.boolean(e),headless:e=>v.boolean(e),devtools:e=>v.boolean(e),listenToConsole:e=>v.boolean(e),dumpio:e=>v.boolean(e),slowMo:e=>v.nonNegativeNum(e),debuggingPort:e=>v.nonNegativeNum(e),requestId:()=>z.string().uuid({message:"The value must be a stringified UUID"}).nullable()},PuppeteerSchema=e=>z.object({args:config.args(e)}).partial(),HighchartsSchema=e=>z.object({version:config.version(e),cdnUrl:config.cdnUrl(e),forceFetch:config.forceFetch(e),cachePath:config.cachePath(e),coreScripts:config.coreScripts(e),moduleScripts:config.moduleScripts(e),indicatorScripts:config.indicatorScripts(e),customScripts:config.customScripts(e)}).partial(),ExportSchema=e=>z.object({infile:config.infile(e),instr:config.instr(),options:config.options(),svg:config.svg(),outfile:config.outfile(e),type:config.type(e),constr:config.constr(e),b64:config.b64(e),noDownload:config.noDownload(e),defaultHeight:config.defaultHeight(e),defaultWidth:config.defaultWidth(e),defaultScale:config.defaultScale(e),height:config.height(e),width:config.width(e),scale:config.scale(e),globalOptions:config.globalOptions(),themeOptions:config.themeOptions(),batch:config.batch(!1),rasterizationTimeout:config.rasterizationTimeout(e)}).partial(),CustomLogicSchema=e=>z.object({allowCodeExecution:config.allowCodeExecution(e),allowFileResources:config.allowFileResources(e),customCode:config.customCode(!1),callback:config.callback(!1),resources:config.resources(e),loadConfig:config.loadConfig(!1),createConfig:config.createConfig(!1)}).partial(),ProxySchema=e=>z.object({host:config.proxyHost(!1),port:config.proxyPort(e),timeout:config.proxyTimeout(e)}).partial(),RateLimitingSchema=e=>z.object({enable:config.enableRateLimiting(e),maxRequests:config.maxRequests(e),window:config.window(e),delay:config.delay(e),trustProxy:config.trustProxy(e),skipKey:config.skipKey(!1),skipToken:config.skipToken(!1)}).partial(),SslSchema=e=>z.object({enable:config.enableSsl(e),force:config.sslForce(e),port:config.sslPort(e),certPath:config.sslCertPath(!1)}).partial(),ServerSchema=e=>z.object({enable:config.enableServer(e).optional(),host:config.host(e).optional(),port:config.port(e).optional(),benchmarking:config.serverBenchmarking(e).optional(),proxy:ProxySchema(e).optional(),rateLimiting:RateLimitingSchema(e).optional(),ssl:SslSchema(e).optional()}),PoolSchema=e=>z.object({minWorkers:config.minWorkers(e),maxWorkers:config.maxWorkers(e),workLimit:config.workLimit(e),acquireTimeout:config.acquireTimeout(e),createTimeout:config.createTimeout(e),destroyTimeout:config.destroyTimeout(e),idleTimeout:config.idleTimeout(e),createRetryInterval:config.createRetryInterval(e),reaperInterval:config.reaperInterval(e),benchmarking:config.poolBenchmarking(e)}).partial(),LoggingSchema=e=>z.object({level:config.logLevel(e),file:config.logFile(e),dest:config.logDest(e),toConsole:config.logToConsole(e),toFile:config.logToFile(e)}).partial(),UiSchema=e=>z.object({enable:config.enableUi(e),route:config.uiRoute(e)}).partial(),OtherSchema=e=>z.object({nodeEnv:config.nodeEnv(e),listenToProcessExits:config.listenToProcessExits(e),noLogo:config.noLogo(e),hardResetPage:config.hardResetPage(e),browserShellMode:config.browserShellMode(e)}).partial(),DebugSchema=e=>z.object({enable:config.enableDebug(e),headless:config.headless(e),devtools:config.devtools(e),listenToConsole:config.listenToConsole(e),dumpio:config.dumpio(e),slowMo:config.slowMo(e),debuggingPort:config.debuggingPort(e)}).partial(),StrictConfigSchema=z.object({puppeteer:PuppeteerSchema(!0),highcharts:HighchartsSchema(!0),export:ExportSchema(!0),customLogic:CustomLogicSchema(!0),server:ServerSchema(!0),pool:PoolSchema(!0),logging:LoggingSchema(!0),ui:UiSchema(!0),other:OtherSchema(!0),debug:DebugSchema(!0)}),LooseConfigSchema=z.object({puppeteer:PuppeteerSchema(!1),highcharts:HighchartsSchema(!1),export:ExportSchema(!1),customLogic:CustomLogicSchema(!1),server:ServerSchema(!1),pool:PoolSchema(!1),logging:LoggingSchema(!1),ui:UiSchema(!1),other:OtherSchema(!1),debug:DebugSchema(!1)}),EnvSchema=z.object({PUPPETEER_ARGS:config.args(!1),HIGHCHARTS_VERSION:config.version(!1),HIGHCHARTS_CDN_URL:config.cdnUrl(!1),HIGHCHARTS_FORCE_FETCH:config.forceFetch(!1),HIGHCHARTS_CACHE_PATH:config.cachePath(!1),HIGHCHARTS_ADMIN_TOKEN:config.adminToken(!1),HIGHCHARTS_CORE_SCRIPTS:config.coreScripts(!1),HIGHCHARTS_MODULE_SCRIPTS:config.moduleScripts(!1),HIGHCHARTS_INDICATOR_SCRIPTS:config.indicatorScripts(!1),HIGHCHARTS_CUSTOM_SCRIPTS:config.customScripts(!1),EXPORT_INFILE:config.infile(!1),EXPORT_INSTR:config.instr(),EXPORT_OPTIONS:config.options(),EXPORT_SVG:config.svg(),EXPORT_BATCH:config.batch(!1),EXPORT_OUTFILE:config.outfile(!1),EXPORT_TYPE:config.type(!1),EXPORT_CONSTR:config.constr(!1),EXPORT_B64:config.b64(!1),EXPORT_NO_DOWNLOAD:config.noDownload(!1),EXPORT_HEIGHT:config.height(!1),EXPORT_WIDTH:config.width(!1),EXPORT_SCALE:config.scale(!1),EXPORT_DEFAULT_HEIGHT:config.defaultHeight(!1),EXPORT_DEFAULT_WIDTH:config.defaultWidth(!1),EXPORT_DEFAULT_SCALE:config.defaultScale(!1),EXPORT_GLOBAL_OPTIONS:config.globalOptions(),EXPORT_THEME_OPTIONS:config.themeOptions(),EXPORT_RASTERIZATION_TIMEOUT:config.rasterizationTimeout(!1),CUSTOM_LOGIC_ALLOW_CODE_EXECUTION:config.allowCodeExecution(!1),CUSTOM_LOGIC_ALLOW_FILE_RESOURCES:config.allowFileResources(!1),CUSTOM_LOGIC_CUSTOM_CODE:config.customCode(!1),CUSTOM_LOGIC_CALLBACK:config.callback(!1),CUSTOM_LOGIC_RESOURCES:config.resources(!1),CUSTOM_LOGIC_LOAD_CONFIG:config.loadConfig(!1),CUSTOM_LOGIC_CREATE_CONFIG:config.createConfig(!1),SERVER_ENABLE:config.enableServer(!1),SERVER_HOST:config.host(!1),SERVER_PORT:config.port(!1),SERVER_UPLOAD_LIMIT:config.uploadLimit(!1),SERVER_BENCHMARKING:config.serverBenchmarking(!1),SERVER_PROXY_HOST:config.proxyHost(!1),SERVER_PROXY_PORT:config.proxyPort(!1),SERVER_PROXY_TIMEOUT:config.proxyTimeout(!1),SERVER_RATE_LIMITING_ENABLE:config.enableRateLimiting(!1),SERVER_RATE_LIMITING_MAX_REQUESTS:config.maxRequests(!1),SERVER_RATE_LIMITING_WINDOW:config.window(!1),SERVER_RATE_LIMITING_DELAY:config.delay(!1),SERVER_RATE_LIMITING_TRUST_PROXY:config.trustProxy(!1),SERVER_RATE_LIMITING_SKIP_KEY:config.skipKey(!1),SERVER_RATE_LIMITING_SKIP_TOKEN:config.skipToken(!1),SERVER_SSL_ENABLE:config.enableSsl(!1),SERVER_SSL_FORCE:config.sslForce(!1),SERVER_SSL_PORT:config.sslPort(!1),SERVER_SSL_CERT_PATH:config.sslCertPath(!1),POOL_MIN_WORKERS:config.minWorkers(!1),POOL_MAX_WORKERS:config.maxWorkers(!1),POOL_WORK_LIMIT:config.workLimit(!1),POOL_ACQUIRE_TIMEOUT:config.acquireTimeout(!1),POOL_CREATE_TIMEOUT:config.createTimeout(!1),POOL_DESTROY_TIMEOUT:config.destroyTimeout(!1),POOL_IDLE_TIMEOUT:config.idleTimeout(!1),POOL_CREATE_RETRY_INTERVAL:config.createRetryInterval(!1),POOL_REAPER_INTERVAL:config.reaperInterval(!1),POOL_BENCHMARKING:config.poolBenchmarking(!1),LOGGING_LEVEL:config.logLevel(!1),LOGGING_FILE:config.logFile(!1),LOGGING_DEST:config.logDest(!1),LOGGING_TO_CONSOLE:config.logToConsole(!1),LOGGING_TO_FILE:config.logToFile(!1),UI_ENABLE:config.enableUi(!1),UI_ROUTE:config.uiRoute(!1),OTHER_NODE_ENV:config.nodeEnv(!1),OTHER_LISTEN_TO_PROCESS_EXITS:config.listenToProcessExits(!1),OTHER_NO_LOGO:config.noLogo(!1),OTHER_HARD_RESET_PAGE:config.hardResetPage(!1),OTHER_BROWSER_SHELL_MODE:config.browserShellMode(!1),DEBUG_ENABLE:config.enableDebug(!1),DEBUG_HEADLESS:config.headless(!1),DEBUG_DEVTOOLS:config.devtools(!1),DEBUG_LISTEN_TO_CONSOLE:config.listenToConsole(!1),DEBUG_DUMPIO:config.dumpio(!1),DEBUG_SLOW_MO:config.slowMo(!1),DEBUG_DEBUGGING_PORT:config.debuggingPort(!1)}),envs=EnvSchema.partial().parse(process.env);function strictValidate(e){return StrictConfigSchema.partial().parse(e)}function looseValidate(e){return LooseConfigSchema.partial().parse(e)}function validateOption(e,t,o){return config[e](o).parse(t)}function _customErrorMap(e,t){const o=e.path.join("."),n=`Invalid value for the ${o}`;if(e.code===z.ZodIssueCode.invalid_type)return e.received===z.ZodParsedType.undefined?{message:`${n} - No value was provided.`}:{message:`${n} - Invalid type. ${t.defaultError}.`};if(e.code===z.ZodIssueCode.custom&&e.params?.errorMessage)return{message:`${n} - ${e.params?.errorMessage}, received '${t.data}'.`};if(e.code===z.ZodIssueCode.invalid_union){let t=`Multiple errors occurred for the ${o}:\n`;return e.unionErrors.forEach((e=>{const o=e.issues[0].message.indexOf("-");t+=-1!==o?`${e.issues[0].message}\n`.substring(o):`${e.issues[0].message}\n`})),{message:t}}return{message:`${n} - ${t.defaultError}.`}}const globalOptions=_initGlobalOptions(defaultConfig),instanceOptions=deepCopy(globalOptions);function getOptions(e=!0){return e?instanceOptions:globalOptions}function setGlobalOptions(e={},t=[]){let o={},n={};if(t.length)try{o=strictValidate(_loadConfigFile(t))}catch(e){logZodIssues(1,e.issues,"[config] Custom JSON options validation error")}if(e&&0!==Object.keys(e).length)try{e=strictValidate(e)}catch(e){logZodIssues(1,e.issues,"[config] Custom options validation error")}if(t.length)try{n=looseValidate(_pairArgumentValue(nestedProps,t))}catch(e){logZodIssues(1,e.issues,"[config] CLI options validation error")}return _updateGlobalOptions(defaultConfig,globalOptions,o,n,e),globalOptions}function updateOptions(e,t=!1){return t&&(Object.keys(instanceOptions).forEach((e=>{delete instanceOptions[e]})),mergeOptions(instanceOptions,deepCopy(globalOptions))),mergeOptions(instanceOptions,e),instanceOptions}function mergeOptions(e,t){if(isObject(e)&&isObject(t))for(const[o,n]of Object.entries(t))e[o]=isObject(n)&&!absoluteProps.includes(o)&&void 0!==e[o]?mergeOptions(e[o],n):void 0!==n?n:e[o]||null;return e}function mapToNewOptions(e){const t={};if(isObject(e))for(const[o,n]of Object.entries(e)){const e=nestedProps[o]?nestedProps[o].split("."):[];e.reduce(((t,o,r)=>t[o]=e.length-1===r?n:t[o]||{}),t)}else log(2,"[config] No correct object with options was provided. Returning an empty array.");return t}function isAllowedConfig(config,toString=!1,allowFunctions=!1){try{if(!isObject(config)&&"string"!=typeof config)return null;const objectConfig="string"==typeof config?allowFunctions?eval(`(${config})`):JSON.parse(config):config,stringifiedOptions=_optionsStringify(objectConfig,allowFunctions,!1),parsedOptions=allowFunctions?JSON.parse(_optionsStringify(objectConfig,allowFunctions,!0),((_,value)=>"string"==typeof value&&value.startsWith("function")?eval(`(${value})`):value)):JSON.parse(stringifiedOptions);return toString?stringifiedOptions:parsedOptions}catch(e){return null}}function _initGlobalOptions(e){const t={};for(const[o,n]of Object.entries(e))if(Object.prototype.hasOwnProperty.call(n,"value")){const e=envs[n.envLink];t[o]=null!=e?e:n.value}else t[o]=_initGlobalOptions(n);return t}function _updateGlobalOptions(e,t,o,n,r){Object.keys(e).forEach((i=>{const s=e[i],a=o&&o[i],l=n&&n[i],c=r&&r[i];if(void 0===s.value)_updateGlobalOptions(s,t[i],a,l,c);else{null!=a&&(t[i]=a);const e=envs[s.envLink];s.envLink in envs&&null!=e&&(t[i]=e),null!=l&&(t[i]=l),null!=c&&(t[i]=c)}}))}function _optionsStringify(e,t,o){return JSON.stringify(e,((e,n)=>{if("string"==typeof n&&(n=n.trim()),"function"==typeof n||"string"==typeof n&&n.startsWith("function")&&n.endsWith("}")){if(t)return o?`"EXP_FUN${(n+"").replaceAll(/\s+/g," ")}EXP_FUN"`:`EXP_FUN${(n+"").replaceAll(/\s+/g," ")}EXP_FUN`;throw new Error}return n})).replaceAll(o?/\\"EXP_FUN|EXP_FUN\\"/g:/"EXP_FUN|EXP_FUN"/g,"")}function _loadConfigFile(e,t){const o=e.findIndex((e=>"loadConfig"===e.replace(/-/g,"")));return o>-1&&e[o+1]&&t.allowFileResources,{}}function _pairArgumentValue(e,t){const o={};for(let n=0;n{if(i.length-1===s){const i=t[++n];i||log(2,`[config] Missing value for the CLI '--${r}' argument. Using the default value.`),e[o]=i||null}else void 0===e[o]&&(e[o]={});return e[o]}),o)}return o}async function fetch(e,t={}){return new Promise(((o,n)=>{_getProtocolModule(e).get(e,t,(e=>{let t="";e.on("data",(e=>{t+=e})),e.on("end",(()=>{t||n("Nothing was fetched from the URL."),e.text=t,o(e)}))})).on("error",(e=>{n(e)}))}))}function _getProtocolModule(e){return e.startsWith("https")?https:http}class ExportError extends Error{constructor(e,t){super(),this.message=e,this.stackMessage=e,t&&(this.statusCode=t)}setStatus(e){return this.statusCode=e,this}setError(e){return this.error=e,e.name&&(this.name=e.name),e.statusCode&&(this.statusCode=e.statusCode),e.stack&&(this.stackMessage=e.message,this.stack=e.stack),this}}const cache={cdnUrl:"https://code.highcharts.com",activeManifest:{},sources:"",hcVersion:""};async function checkAndUpdateCache(e,t){try{let o;const n=getCachePath(),r=join(n,"manifest.json"),i=join(n,"sources.js");if(!existsSync(n)&&mkdirSync(n,{recursive:!0}),!existsSync(r)||e.forceFetch)log(3,"[cache] Fetching and caching Highcharts dependencies."),o=await _updateCache(e,t,i);else{let n=!1;const s=JSON.parse(readFileSync(r),"utf8");if(s.modules&&Array.isArray(s.modules)){const e={};s.modules.forEach((t=>e[t]=1)),s.modules=e}const{coreScripts:a,moduleScripts:l,indicatorScripts:c}=e,p=a.length+l.length+c.length;s.version!==e.version?(log(2,"[cache] A Highcharts version mismatch in the cache, need to re-fetch."),n=!0):Object.keys(s.modules||{}).length!==p?(log(2,"[cache] The cache and the requested modules do not match, need to re-fetch."),n=!0):n=(l||[]).some((e=>{if(!s.modules[e])return log(2,`[cache] The ${e} is missing in the cache, need to re-fetch.`),!0})),n?o=await _updateCache(e,t,i):(log(3,"[cache] Dependency cache is up to date, proceeding."),cache.sources=readFileSync(i,"utf8"),o=s.modules,cache.hcVersion=extractVersion(cache.sources))}await _saveConfigToManifest(e,o)}catch(e){throw new ExportError("[cache] Could not configure cache and create or update the config manifest.",500).setError(e)}}function getHighchartsVersion(){return cache.hcVersion}async function updateHighchartsVersion(e){const t=getOptions();t.highcharts.version=e,await checkAndUpdateCache(t.highcharts,t.server.proxy)}function extractVersion(e){return e.substring(0,e.indexOf("*/")).replace("/*","").replace("*/","").replace(/\n/g,"").trim()}function extractModuleName(e){return e.replace(/(.*)\/|(.*)modules\/|stock\/(.*)indicators\/|maps\/(.*)modules\//gi,"")}function getCachePath(){return getAbsolutePath(getOptions().highcharts.cachePath)}async function _fetchAndProcessScript(e,t,o,n=!1){e.endsWith(".js")&&(e=e.substring(0,e.length-3)),log(4,`[cache] Fetching script - ${e}.js`);const r=await fetch(`${e}.js`,t);if(200===r.statusCode&&"string"==typeof r.text){if(o){o[extractModuleName(e)]=1}return r.text}if(n)throw new ExportError(`[cache] Could not fetch the ${e}.js. The script might not exist in the requested version (status code: ${r.statusCode}).`,404).setError(r);log(2,`[cache] Could not fetch the ${e}.js. The script might not exist in the requested version.`)}async function _saveConfigToManifest(e,t={}){const o={version:e.version,modules:t};cache.activeManifest=o,log(3,"[cache] Writing a new manifest.");try{writeFileSync(join(getCachePath(),"manifest.json"),JSON.stringify(o),"utf8")}catch(e){throw new ExportError("[cache] Error writing the cache manifest.",500).setError(e)}}async function _fetchScripts(e,t,o,n,r){let i;const s=n.host,a=n.port;if(s&&a)try{i=new HttpsProxyAgent({host:s,port:a})}catch(e){throw new ExportError("[cache] Could not create a Proxy Agent.",500).setError(e)}const l=i?{agent:i,timeout:n.timeout}:{},c=[...e.map((e=>_fetchAndProcessScript(`${e}`,l,r,!0))),...t.map((e=>_fetchAndProcessScript(`${e}`,l,r))),...o.map((e=>_fetchAndProcessScript(`${e}`,l)))];return(await Promise.all(c)).join(";\n")}async function _updateCache(e,t,o){const n="latest"===e.version?null:`${e.version}`,r=e.cdnUrl||cache.cdnUrl;try{const i={};return log(3,`[cache] Updating cache version to Highcharts: ${n||"latest"}.`),cache.sources=await _fetchScripts([...e.coreScripts.map((e=>n?`${r}/${n}/${e}`:`${r}/${e}`))],[...e.moduleScripts.map((e=>"map"===e?n?`${r}/maps/${n}/modules/${e}`:`${r}/maps/modules/${e}`:n?`${r}/${n}/modules/${e}`:`${r}/modules/${e}`)),...e.indicatorScripts.map((e=>n?`${r}/stock/${n}/indicators/${e}`:`${r}/stock/indicators/${e}`))],e.customScripts,t,i),cache.hcVersion=extractVersion(cache.sources),writeFileSync(o,cache.sources),i}catch(e){throw new ExportError("[cache] Unable to update the local Highcharts cache.",500).setError(e)}}function setupHighcharts(){Highcharts.animObject=function(){return{duration:0}}}async function createChart(e,t){const{getOptions:o,setOptions:n,merge:r,wrap:i}=Highcharts;Highcharts.setOptionsObj=r(!1,{},o()),window.isRenderComplete=!1,i(Highcharts.Chart.prototype,"init",(function(e,t,o){((t=r(t,{exporting:{enabled:!1},plotOptions:{series:{label:{enabled:!1}}},tooltip:{}})).series||[]).forEach((function(e){e.animation=!1})),window.onHighchartsRender||(window.onHighchartsRender=Highcharts.addEvent(this,"render",(()=>{window.isRenderComplete=!0}))),e.apply(this,[t,o])})),i(Highcharts.Series.prototype,"init",(function(e,t,o){e.apply(this,[t,o])}));const s={chart:{animation:!1,height:e.height,width:e.width},exporting:{enabled:!1}},a=new Function(`return ${e.instr}`)(),l=new Function(`return ${e.themeOptions}`)(),c=new Function(`return ${e.globalOptions}`)(),p=r(!1,l,a,s),u=t.callback?new Function(`return ${t.callback}`)():null;t.customCode&&new Function("options",t.customCode)(a),c&&n(c),Highcharts[e.constr]("container",p,u);const g=o();for(const e in g)"function"!=typeof g[e]&&delete g[e];n(Highcharts.setOptionsObj),Highcharts.setOptionsObj={}}const template=readFileSync(join(__dirname,"templates","template.html"),"utf8");let browser=null;async function createBrowser(e){const{debug:t,other:o}=getOptions(),{enable:n,...r}=t,i={headless:!o.browserShellMode||"shell",userDataDir:"tmp",args:e||[],handleSIGINT:!1,handleSIGTERM:!1,handleSIGHUP:!1,waitForInitialPage:!1,defaultViewport:null,...n&&r};if(!browser){let e=0;const t=async()=>{try{log(3,`[browser] Attempting to get a browser instance (try ${++e}).`),browser=await puppeteer.launch(i)}catch(o){if(logWithStack(1,o,"[browser] Failed to launch a browser instance."),!(e<25))throw o;log(3,`[browser] Retry to open a browser (${e} out of 25).`),await new Promise((e=>setTimeout(e,4e3))),await t()}};try{await t(),"shell"===i.headless&&log(3,"[browser] Launched browser in shell mode."),n&&log(3,"[browser] Launched browser in debug mode.")}catch(e){throw new ExportError("[browser] Maximum retries to open a browser instance reached.",500).setError(e)}if(!browser)throw new ExportError("[browser] Cannot find a browser to open.",500)}return browser}async function closeBrowser(){browser&&browser.connected&&await browser.close(),browser=null,log(4,"[browser] Closed the browser.")}async function newPage(e){if(!browser||!browser.connected)throw new ExportError("[browser] Browser is not yet connected.",500);if(e.page=await browser.newPage(),await e.page.setCacheEnabled(!1),await _setPageContent(e.page),_setPageEvents(e.page),!e.page||e.page.isClosed())throw new ExportError("[browser] The page is invalid or closed.",400)}async function clearPage(e,t=!1){try{if(e.page&&!e.page.isClosed())return t?(await e.page.goto("about:blank",{waitUntil:"domcontentloaded"}),await _setPageContent(e.page)):await e.page.evaluate((()=>{document.body.innerHTML='
'})),!0}catch(t){logWithStack(2,t,`[pool] Pool resource [${e.id}] - Content of the page could not be cleared.`),e.workCount=getOptions().pool.workLimit+1}return!1}async function addPageResources(e,t){const o=[],n=t.resources;if(n){const r=[];if(n.js&&r.push({content:n.js}),n.files)for(const e of n.files){const t=!e.startsWith("http");r.push(t?{content:readFileSync(getAbsolutePath(e),"utf8")}:{url:e})}for(const t of r)try{o.push(await e.addScriptTag(t))}catch(e){logWithStack(2,e,"[browser] The JS resource cannot be loaded.")}r.length=0;const i=[];if(n.css){let r=n.css.match(/@import\s*([^;]*);/g);if(r)for(let e of r)e&&(e=e.replace("url(","").replace("@import","").replace(/"/g,"").replace(/'/g,"").replace(/;/,"").replace(/\)/g,"").trim(),e.startsWith("http")?i.push({url:e}):t.allowFileResources&&i.push({path:join(__dirname,e)}));i.push({content:n.css.replace(/@import\s*([^;]*);/g,"")||" "});for(const t of i)try{o.push(await e.addStyleTag(t))}catch(e){logWithStack(2,e,"[browser] The CSS resource cannot be loaded.")}i.length=0}}return o}async function clearPageResources(e,t){try{for(const e of t)await e.dispose();await e.evaluate((()=>{if("undefined"!=typeof Highcharts){const e=Highcharts.charts;if(Array.isArray(e)&&e.length)for(const t of e)t&&t.destroy(),Highcharts.charts.shift()}const[...e]=document.getElementsByTagName("script"),[,...t]=document.getElementsByTagName("style"),[...o]=document.getElementsByTagName("link");for(const n of[...e,...t,...o])n.remove()}))}catch(e){logWithStack(2,e,"[browser] Could not clear page's resources.")}}async function _setPageContent(e){await e.setContent(template,{waitUntil:"domcontentloaded"}),await e.addScriptTag({path:join(getCachePath(),"sources.js")}),await e.evaluate(setupHighcharts)}function _setPageEvents(e){const{debug:t}=getOptions();e.on("pageerror",(async()=>{e.isClosed()})),t.enable&&t.listenToConsole&&e.on("console",(e=>{console.log(`[debug] ${e.text()}`)}))}var cssTemplate=()=>"\n\nhtml, body {\n margin: 0;\n padding: 0;\n box-sizing: border-box;\n}\n\n#table-div, #sliders, #datatable, #controls, .ld-row {\n display: none;\n height: 0;\n}\n\n#chart-container {\n box-sizing: border-box;\n margin: 0;\n overflow: auto;\n font-size: 0;\n}\n\n#chart-container > figure, div {\n margin-top: 0 !important;\n margin-bottom: 0 !important;\n}\n\n",svgTemplate=e=>`\n\n\n \n \n Highcharts Export\n \n \n \n
\n ${e}\n
\n \n\n\n`;async function puppeteerExport(e,t,o){const n=[];try{let r=!1;if(t.svg){if(log(4,"[export] Treating as SVG input."),"svg"===t.type)return t.svg;r=!0,await e.setContent(svgTemplate(t.svg),{waitUntil:"domcontentloaded"})}else log(4,"[export] Treating as JSON config."),await e.evaluate(createChart,t,o);n.push(...await addPageResources(e,o));const i=r?await e.evaluate((e=>{const t=document.querySelector("#chart-container svg:first-of-type"),o=t.height.baseVal.value*e,n=t.width.baseVal.value*e;return document.body.style.zoom=e,document.body.style.margin="0px",{chartHeight:o,chartWidth:n}}),parseFloat(t.scale)):await e.evaluate((()=>{const{chartHeight:e,chartWidth:t}=window.Highcharts.charts[0];return document.body.style.zoom=1,{chartHeight:e,chartWidth:t}})),{x:s,y:a}=await _getClipRegion(e),l=Math.abs(Math.ceil(i.chartHeight||t.height)),c=Math.abs(Math.ceil(i.chartWidth||t.width));let p;switch(await e.setViewport({height:l,width:c,deviceScaleFactor:r?1:parseFloat(t.scale)}),t.type){case"svg":p=await _createSVG(e);break;case"png":case"jpeg":p=await _createImage(e,t.type,{width:c,height:l,x:s,y:a},t.rasterizationTimeout);break;case"pdf":p=await _createPDF(e,l,c,t.rasterizationTimeout);break;default:throw new ExportError(`[export] Unsupported output format: ${t.type}.`,400)}return await clearPageResources(e,n),p}catch(t){return await clearPageResources(e,n),t}}async function _getClipRegion(e){return e.$eval("#chart-container",(e=>{const{x:t,y:o,width:n,height:r}=e.getBoundingClientRect();return{x:t,y:o,width:n,height:Math.trunc(r>1?r:500)}}))}async function _createSVG(e){return e.$eval("#container svg:first-of-type",(e=>e.outerHTML))}async function _createImage(e,t,o,n){return Promise.race([e.screenshot({type:t,clip:o,encoding:"base64",fullPage:!1,optimizeForSpeed:!0,captureBeyondViewport:!0,..."png"!==t?{quality:80}:{},omitBackground:"png"==t}),new Promise(((e,t)=>setTimeout((()=>t(new ExportError("Rasterization timeout",408))),n||1500)))])}async function _createPDF(e,t,o,n){return await e.emulateMediaType("screen"),e.pdf({height:t+1,width:o,encoding:"base64",timeout:n||1500})}let pool=null;const poolStats={exportsAttempted:0,exportsPerformed:0,exportsDropped:0,exportsFromSvg:0,exportsFromOptions:0,exportsFromSvgAttempts:0,exportsFromOptionsAttempts:0,timeSpent:0,timeSpentAverage:0};async function initPool(e,t){await createBrowser(t);try{if(log(3,`[pool] Initializing pool with workers: min ${e.minWorkers}, max ${e.maxWorkers}.`),pool)return void log(4,"[pool] Already initialized, please kill it before creating a new one.");e.minWorkers>e.maxWorkers&&(e.minWorkers=e.maxWorkers),pool=new Pool({..._factory(e),min:e.minWorkers,max:e.maxWorkers,acquireTimeoutMillis:e.acquireTimeout,createTimeoutMillis:e.createTimeout,destroyTimeoutMillis:e.destroyTimeout,idleTimeoutMillis:e.idleTimeout,createRetryIntervalMillis:e.createRetryInterval,reapIntervalMillis:e.reaperInterval,propagateCreateError:!1}),pool.on("release",(async e=>{const t=await clearPage(e,!1);log(4,`[pool] Pool resource [${e.id}] - Releasing a worker. Clear page status: ${t}.`)})),pool.on("destroySuccess",((e,t)=>{log(4,`[pool] Pool resource [${t.id}] - Destroyed a worker successfully.`),t.page=null}));const t=[];for(let o=0;o{pool.release(e)})),log(3,"[pool] The pool is ready"+(t.length?` with ${t.length} initial resources waiting.`:"."))}catch(e){throw new ExportError("[pool] Could not configure and create the pool of workers.",500).setError(e)}}async function killPool(){if(log(3,"[pool] Killing pool with all workers and closing browser."),pool){for(const e of pool.used)pool.release(e.resource);pool.destroyed||(await pool.destroy(),log(4,"[pool] Destroyed the pool of resources.")),pool=null}await closeBrowser()}async function postWork(e){let t;try{if(log(4,"[pool] Work received, starting to process."),++poolStats.exportsAttempted,e.pool.benchmarking&&getPoolInfo(),!pool)throw new ExportError("[pool] Work received, but pool has not been started.",500);const o=measureTime();try{log(4,"[pool] Acquiring a worker handle."),t=await pool.acquire().promise,e.server.benchmarking&&log(5,"[benchmark] "+(e.requestId?`Request [${e.requestId}] - `:""),`Acquiring a worker handle took ${o()}ms.`)}catch(t){throw new ExportError(`[pool] ${e.requestId?`Request [${e.requestId}] - `:""}Error encountered when acquiring an available entry: ${o()}ms.`,400).setError(t)}if(log(4,"[pool] Acquired a worker handle."),!t.page)throw t.workCount=e.pool.workLimit+1,new ExportError("[pool] Resolved worker page is invalid: the pool setup is wonky.",400);const n=getNewDateTime();log(4,`[pool] Pool resource [${t.id}] - Starting work on this pool entry.`);const r=measureTime(),i=await puppeteerExport(t.page,e.export,e.customLogic);if(i instanceof Error)throw"Rasterization timeout"===i.message&&(t.workCount=e.pool.workLimit+1,t.page=null),"TimeoutError"===i.name||"Rasterization timeout"===i.message?new ExportError(`[pool] ${e.requestId?`Request [${e.requestId}] - `:""}Rasterization timeout: your chart may be too complex or large, and failed to render within the allotted time.`).setError(i):new ExportError(`[pool] ${e.requestId?`Request [${e.requestId}] - `:""}Error encountered during export: ${r()}ms.`).setError(i);e.server.benchmarking&&log(5,"[benchmark] "+(e.requestId?`Request [${e.requestId}] - `:""),`Exporting a chart sucessfully took ${r()}ms.`),pool.release(t);const s=getNewDateTime()-n;return poolStats.timeSpent+=s,poolStats.timeSpentAverage=poolStats.timeSpent/++poolStats.exportsPerformed,log(4,`[pool] Work completed in ${s}ms.`),{result:i,options:e}}catch(e){throw++poolStats.exportsDropped,t&&pool.release(t),e}}function getPoolStats(){return poolStats}function getPoolInfoJSON(){return{min:pool.min,max:pool.max,used:pool.numUsed(),available:pool.numFree(),allCreated:pool.numUsed()+pool.numFree(),pendingAcquires:pool.numPendingAcquires(),pendingCreates:pool.numPendingCreates(),pendingValidations:pool.numPendingValidations(),pendingDestroys:pool.pendingDestroys.length,absoluteAll:pool.numUsed()+pool.numFree()+pool.numPendingAcquires()+pool.numPendingCreates()+pool.numPendingValidations()+pool.pendingDestroys.length}}function getPoolInfo(){const{min:e,max:t,used:o,available:n,allCreated:r,pendingAcquires:i,pendingCreates:s,pendingValidations:a,pendingDestroys:l,absoluteAll:c}=getPoolInfoJSON();log(5,`[pool] The minimum number of resources allowed by pool: ${e}.`),log(5,`[pool] The maximum number of resources allowed by pool: ${t}.`),log(5,`[pool] The number of used resources: ${o}.`),log(5,`[pool] The number of free resources: ${n}.`),log(5,`[pool] The number of all created (used and free) resources: ${r}.`),log(5,`[pool] The number of resources waiting to be acquired: ${i}.`),log(5,`[pool] The number of resources waiting to be created: ${s}.`),log(5,`[pool] The number of resources waiting to be validated: ${a}.`),log(5,`[pool] The number of resources waiting to be destroyed: ${l}.`),log(5,`[pool] The number of all resources: ${c}.`)}function _factory(e){return{create:async()=>{const t={id:v4(),workCount:Math.round(Math.random()*(e.workLimit/2))};try{const e=getNewDateTime();return await newPage(t),log(3,`[pool] Pool resource [${t.id}] - Successfully created a worker, took ${getNewDateTime()-e}ms.`),t}catch(e){throw log(3,`[pool] Pool resource [${t.id}] - Error encountered when creating a new page.`),e}},validate:async t=>t.page?t.page.isClosed()?(log(3,`[pool] Pool resource [${t.id}] - Validation failed (page is closed or invalid).`),!1):t.page.mainFrame().detached?(log(3,`[pool] Pool resource [${t.id}] - Validation failed (page's frame is detached).`),!1):!(e.workLimit&&++t.workCount>e.workLimit)||(log(3,`[pool] Pool resource [${t.id}] - Validation failed (exceeded the ${e.workLimit} works per resource limit).`),!1):(log(3,`[pool] Pool resource [${t.id}] - Validation failed (no valid page is found).`),!1),destroy:async e=>{if(log(3,`[pool] Pool resource [${e.id}] - Destroying a worker.`),e.page&&!e.page.isClosed())try{e.page.removeAllListeners("pageerror"),e.page.removeAllListeners("console"),e.page.removeAllListeners("framedetached"),await e.page.close()}catch(t){throw log(3,`[pool] Pool resource [${e.id}] - Page could not be closed upon destroying.`),t}}}}function sanitize(e){const t=new JSDOM("").window;return DOMPurify(t).sanitize(e,{ADD_TAGS:["foreignObject"]})}let allowCodeExecution=!1;async function singleExport(e){if(!e||!e.export)throw new ExportError("[chart] No expected `export` options were found. Please provide one of the following options: `infile`, `instr`, `options`, or `svg` to generate a valid image.",400);await startExport({export:e.export,customLogic:e.customLogic},(async(e,t)=>{if(e)throw e;const{b64:o,outfile:n,type:r}=t.options.export;try{o?writeFileSync(`${n.split(".").shift()||"chart"}.txt`,getBase64(t.result,r)):writeFileSync(n||`chart.${r}`,"svg"!==r?Buffer.from(t.result,"base64"):t.result)}catch(e){throw new ExportError("[chart] Error while saving a chart.",500).setError(e)}await killPool()}))}async function batchExport(e){if(!(e&&e.export&&e.export.batch))throw new ExportError("[chart] No expected `export` options were found. Please provide the `batch` option to generate valid images.",400);{const t=[];for(let o of e.export.batch.split(";")||[])o=o.split("="),2===o.length?t.push(startExport({export:{...e.export,infile:o[0],outfile:o[1]},customLogic:e.customLogic},((e,t)=>{if(e)throw e;const{b64:o,outfile:n,type:r}=t.options.export;try{o?writeFileSync(`${n.split(".").shift()||"chart"}.txt`,getBase64(t.result,r)):writeFileSync(n,"svg"!==r?Buffer.from(t.result,"base64"):t.result)}catch(e){throw new ExportError("[chart] Error while saving a chart.",500).setError(e)}}))):log(2,"[chart] No correct pair found for the batch export.");const o=await Promise.allSettled(t);await killPool(),o.forEach(((e,t)=>{e.reason&&logWithStack(1,e.reason,`[chart] Batch export number ${t+1} could not be correctly completed.`)}))}}async function startExport(e,t){try{if(!isObject(e))throw new ExportError("[chart] Incorrect value of the provided `exportingOptions`. Needs to be an object.",400);const o=mergeOptions(deepCopy(getOptions()),{export:e.export,customLogic:e.customLogic}),n=o.export;if(log(4,"[chart] Starting the exporting process."),null!==n.infile){let e;log(4,"[chart] Attempting to export from a file input.");try{e=readFileSync(getAbsolutePath(n.infile),"utf8")}catch(e){throw new ExportError("[chart] Error loading content from a file input.",400).setError(e)}if(n.infile.endsWith(".svg"))try{n.svg=validateOption("svg",e,!1)}catch(e){throw logZodIssues(1,e.issues,"[config] The `svg` option validation error"),e}else{if(!n.infile.endsWith(".json"))throw new ExportError("[chart] Incorrect value of the `infile` option.",400);try{n.instr=validateOption("instr",e,!1)}catch(e){throw logZodIssues(1,e.issues,"[config] The `instr` option validation error"),e}}}if(null!==n.svg){log(4,"[chart] Attempting to export from an SVG input."),++getPoolStats().exportsFromSvgAttempts;const e=await _exportFromSvg(sanitize(n.svg),o);return++getPoolStats().exportsFromSvg,t(null,e)}if(null!==n.instr||null!==n.options){log(4,"[chart] Attempting to export from options input."),++getPoolStats().exportsFromOptionsAttempts;const e=await _exportFromOptions(n.instr||n.options,o);return++getPoolStats().exportsFromOptions,t(null,e)}return t(new ExportError("[chart] No valid input specified. Check if at least one of the following parameters is correctly set: 'infile', 'instr', 'options', or 'svg'.",400))}catch(e){return t(e)}}function getAllowCodeExecution(){return allowCodeExecution}function setAllowCodeExecution(e){allowCodeExecution=e}async function _exportFromSvg(e,t){if("string"==typeof e&&(e.indexOf("=0||e.indexOf("=0))return log(4,"[chart] Parsing input as SVG."),t.export.svg=e,t.export.instr=null,t.export.options=null,_prepareExport(t);throw new ExportError("[chart] Not a correct SVG input.",400)}async function _exportFromOptions(e,t){log(4,"[chart] Parsing input from options.");const o=isAllowedConfig(e,!0,t.customLogic.allowCodeExecution);if(null===o||"string"!=typeof o||!o.startsWith("{")||!o.endsWith("}"))throw new ExportError("[chart] Invalid configuration provided - Only options configurations and SVG are allowed for this server. If this is your server, JavaScript custom code can be enabled by starting the server with the `allowCodeExecution` options set to true.",403);return t.export.instr=o,t.export.svg=null,_prepareExport(t)}async function _prepareExport(e){const{export:t,customLogic:o}=e;t.type=fixType(t.type,t.outfile),t.outfile=fixOutfile(t.type,t.outfile),t.constr=fixConstr(t.constr),log(3,`[chart] The custom logic is ${o.allowCodeExecution?"allowed":"disallowed"}.`),_handleCustomLogic(o,o.allowCodeExecution),_handleGlobalAndTheme(t,o.allowFileResources,o.allowCodeExecution),e.export={...t,..._findChartSize(t)};try{e=strictValidate(e)}catch(e){logZodIssues(1,e.issues,"[config] Final options validation error")}return postWork(e)}function _findChartSize(e){const{chart:t,exporting:o}=e.options||isAllowedConfig(e.instr)||!1,{chart:n,exporting:r}=isAllowedConfig(e.globalOptions)||!1,{chart:i,exporting:s}=isAllowedConfig(e.themeOptions)||!1,a=roundNumber(Math.max(.1,Math.min(e.scale||o?.scale||r?.scale||s?.scale||e.defaultScale||1,5)),2),l={height:e.height||o?.sourceHeight||t?.height||r?.sourceHeight||n?.height||s?.sourceHeight||i?.height||e.defaultHeight||400,width:e.width||o?.sourceWidth||t?.width||r?.sourceWidth||n?.width||s?.sourceWidth||i?.width||e.defaultWidth||600,scale:a};for(let[e,t]of Object.entries(l))l[e]="string"==typeof t?+t.replace(/px|%/gi,""):t;return l}function _handleCustomLogic(e,t){if(t){if("string"==typeof e.resources)e.resources=_handleResources(e.resources,e.allowFileResources,!0);else if(!e.resources)try{e.resources=_handleResources(readFileSync(getAbsolutePath("resources.json"),"utf8"),e.allowFileResources,!0)}catch(e){log(2,"[chart] Unable to load the default `resources.json` file.")}try{e.customCode=wrapAround(e.customCode,e.allowFileResources)}catch(t){logWithStack(2,t,"[chart] The `customCode` cannot be loaded."),e.customCode=null}try{e.callback=wrapAround(e.callback,e.allowFileResources,!0)}catch(t){logWithStack(2,t,"[chart] The `callback` cannot be loaded."),e.callback=null}[null,void 0].includes(e.customCode)&&log(3,"[chart] No value for the `customCode` option found."),[null,void 0].includes(e.callback)&&log(3,"[chart] No value for the `callback` option found."),[null,void 0].includes(e.resources)&&log(3,"[chart] No value for the `resources` option found.")}else if(e.callback||e.resources||e.customCode)throw e.callback=null,e.resources=null,e.customCode=null,new ExportError("[chart] The 'callback', 'resources', and 'customCode' options have been disabled for this server.",403)}function _handleResources(e=null,t,o){const n=["js","css","files"];let r=e,i=!1;if(t&&e.endsWith(".json"))try{r=isAllowedConfig(readFileSync(getAbsolutePath(e),"utf8"),!1,o)}catch{return null}else r=isAllowedConfig(e,!1,o),r&&!t&&delete r.files;for(const e in r)n.includes(e)?i||(i=!0):delete r[e];return i?(r.files&&(r.files=r.files.map((e=>e.trim())),(!r.files||r.files.length<=0)&&delete r.files),r):null}function _handleGlobalAndTheme(e,t,o){["globalOptions","themeOptions"].forEach((n=>{try{e[n]&&(t&&"string"==typeof e[n]&&e[n].endsWith(".json")?e[n]=isAllowedConfig(readFileSync(getAbsolutePath(e[n]),"utf8"),!0,o):e[n]=isAllowedConfig(e[n],!0,o))}catch(t){logWithStack(2,t,`[chart] The \`${n}\` cannot be loaded.`),e[n]=null}})),[null,void 0].includes(e.globalOptions)&&log(3,"[chart] No value for the `globalOptions` option found."),[null,void 0].includes(e.themeOptions)&&log(3,"[chart] No value for the `themeOptions` option found.")}const timerIds=[];function addTimer(e){timerIds.push(e)}function clearAllTimers(){log(4,"[timer] Clearing all registered intervals and timeouts.");for(const e of timerIds)clearInterval(e),clearTimeout(e)}function logErrorMiddleware(e,t,o,n){return logWithStack(1,e),"development"!==getOptions().other.nodeEnv&&delete e.stack,n(e)}function returnErrorMiddleware(e,t,o,n){const{message:r,stack:i}=e,s=e.statusCode||400;o.status(s).json({statusCode:s,message:r,stack:i})}function errorMiddleware(e){e.use(logErrorMiddleware),e.use(returnErrorMiddleware)}function rateLimitingMiddleware(e,t){try{if(t.enable){const o="Too many requests, you have been rate limited. Please try again later.",n={window:t.window||1,maxRequests:t.maxRequests||30,delay:t.delay||0,trustProxy:t.trustProxy||!1,skipKey:t.skipKey||null,skipToken:t.skipToken||null};n.trustProxy&&e.enable("trust proxy");const r=rateLimit({windowMs:60*n.window*1e3,limit:n.maxRequests,delayMs:n.delay,handler:(e,t)=>{t.format({json:()=>{t.status(429).send({message:o})},default:()=>{t.status(429).send(o)}})},skip:e=>null!==n.skipKey&&null!==n.skipToken&&e.query.key===n.skipKey&&e.query.access_token===n.skipToken&&(log(4,"[rate limiting] Skipping rate limiter."),!0)});e.use(r),log(3,`[rate limiting] Enabled rate limiting with ${n.maxRequests} requests per ${n.window} minute for each IP, trusting proxy: ${n.trustProxy}.`)}}catch(e){throw new ExportError("[rate limiting] Could not configure and set the rate limiting options.",500).setError(e)}}function contentTypeMiddleware(e,t,o){try{const t=e.headers["content-type"]||"";if(!t.includes("application/json")&&!t.includes("application/x-www-form-urlencoded")&&!t.includes("multipart/form-data"))throw new ExportError("[validation] Content-Type must be application/json, application/x-www-form-urlencoded, or multipart/form-data.",415);return o()}catch(e){return o(e)}}function requestBodyMiddleware(e,t,o){try{const t=e.body,n=v4();if(!t||isObjectEmpty(t))throw log(2,`[validation] Request [${n}] - The request from ${e.headers["x-forwarded-for"]||e.connection.remoteAddress} was incorrect. Received payload is empty.`),new ExportError(`[validation] Request [${n}] - The request body is required. Please ensure that your Content-Type header is correct. Accepted types are 'application/json' and 'multipart/form-data'.`,400);const r=getAllowCodeExecution(),i=isAllowedConfig(t.instr||t.options||t.infile||t.data,!0,r);if(null===i&&!t.svg)throw log(2,`[validation] Request [${n}] - The request from ${e.headers["x-forwarded-for"]||e.connection.remoteAddress} was incorrect. Received payload is missing correct chart data for export: ${JSON.stringify(t)}.`),new ExportError(`Request [${n}] - [validation] No correct chart data found. Ensure that you are using either application/json or multipart/form-data headers. If sending JSON, make sure the chart data is in the 'infile', 'options', or 'data' attribute. If sending SVG, ensure it is in the 'svg' attribute.`,400);if(t.svg&&isPrivateRangeUrlFound(t.svg))throw new ExportError(`Request [${n}] - [validation] SVG potentially contain at least one forbidden URL in 'xlink:href' element. Please review the SVG content and ensure that all referenced URLs comply with security policies.`,400);try{e.validatedOptions=looseValidate({_requestId:n,export:{instr:i,svg:t.svg,outfile:t.outfile||`${e.params.filename||"chart"}.${fixType(t.type)}`,type:fixType(t.type,t.outfile),constr:fixConstr(t.constr),b64:t.b64,noDownload:t.noDownload,height:t.height,width:t.width,scale:t.scale,globalOptions:isAllowedConfig(t.globalOptions,!0,r),themeOptions:isAllowedConfig(t.themeOptions,!0,r)},customLogic:{allowCodeExecution:r,allowFileResources:!1,customCode:t.customCode,callback:t.callback,resources:isAllowedConfig(t.resources,!0,r)}})}catch(e){throw logZodIssues(1,e.issues,"[config] Request options validation error"),new ExportError("The provided options are not correct. Please check if your data is of the correct types.",400)}return o()}catch(e){return o(e)}}function validationMiddleware(e){e.post(["/","/:filename"],contentTypeMiddleware),e.post(["/","/:filename"],requestBodyMiddleware)}const reversedMime={png:"image/png",jpeg:"image/jpeg",gif:"image/gif",pdf:"application/pdf",svg:"image/svg+xml"};async function requestExport(e,t,o){try{const o=measureTime();let n=!1;e.socket.on("close",(e=>{e&&(n=!0)}));const r=e.validatedOptions,i=r.requestId;log(4,`[export] Request [${i}] - Got an incoming HTTP request.`),await startExport(r,((r,s)=>{if(e.socket.removeAllListeners("close"),n)log(3,`[export] Request [${i}] - The client closed the connection before the chart finished processing.`);else{if(r)throw r;if(!s||!s.result)throw log(2,`[export] Request [${i}] - Request from ${e.headers["x-forwarded-for"]||e.connection.remoteAddress} was incorrect. Received result is ${s.result}.`),new ExportError(`[export] Request [${i}] - Unexpected return of the export result from the chart generation. Please check your request data.`,400);if(s.result){log(3,`[export] Request [${i}] - The whole exporting process took ${o()}ms.`);const{type:e,b64:n,noDownload:r,outfile:a}=s.options.export;return n?t.send(getBase64(s.result,e)):(t.header("Content-Type",reversedMime[e]||"image/png"),r||t.attachment(a),"svg"===e?t.send(s.result):t.send(Buffer.from(s.result,"base64")))}}}))}catch(e){return o(e)}}function exportRoutes(e){e.post("/",requestExport),e.post("/:filename",requestExport)}const serverStartTime=new Date,packageFile=JSON.parse(readFileSync(join(__dirname,"package.json"),"utf8")),successRates=[],recordInterval=6e4,windowSize=30;function _calculateMovingAverage(){return successRates.reduce(((e,t)=>e+t),0)/successRates.length}function _startSuccessRate(){return setInterval((()=>{const e=getPoolStats(),t=0===e.exportsAttempted?1:e.exportsPerformed/e.exportsAttempted*100;successRates.push(t),successRates.length>windowSize&&successRates.shift()}),recordInterval)}function healthRoutes(e){addTimer(_startSuccessRate()),e.get("/health",((e,t,o)=>{try{log(4,"[health] Returning server health.");const e=getPoolStats(),o=successRates.length,n=_calculateMovingAverage();t.send({status:"OK",bootTime:serverStartTime,uptime:`${Math.floor((getNewDateTime()-serverStartTime.getTime())/1e3/60)} minutes`,serverVersion:packageFile.version,highchartsVersion:getHighchartsVersion(),averageExportTime:e.timeSpentAverage,attemptedExports:e.exportsAttempted,performedExports:e.exportsPerformed,failedExports:e.exportsDropped,sucessRatio:e.exportsPerformed/e.exportsAttempted*100,pool:getPoolInfoJSON(),period:o,movingAverage:n,message:isNaN(n)||!successRates.length?"Too early to report. No exports made yet. Please check back soon.":`Last ${o} minutes had a success rate of ${n.toFixed(2)}%.`,svgExports:e.exportsFromSvg,jsonExports:e.exportsFromOptions,svgExportsAttempts:e.exportsFromSvgAttempts,jsonExportsAttempts:e.exportsFromOptionsAttempts})}catch(e){return o(e)}}))}function uiRoutes(e){e.get(getOptions().ui.route||"/",((e,t,o)=>{try{log(4,"[ui] Returning UI for the export."),t.sendFile(join(__dirname,"public","index.html"),{acceptRanges:!1})}catch(e){return o(e)}}))}function versionChangeRoutes(e){e.post("/version_change/:newVersion",(async(e,t,o)=>{try{log(4,"[version] Changing Highcharts version.");const o=envs.HIGHCHARTS_ADMIN_TOKEN;if(!o||!o.length)throw new ExportError("[version] The server is not configured to perform run-time version changes: HIGHCHARTS_ADMIN_TOKEN is not set.",401);const n=e.get("hc-auth");if(!n||n!==o)throw new ExportError("[version] Invalid or missing token: Set the token in the hc-auth header.",401);let r=e.params.newVersion;if(!r)throw new ExportError("[version] No new version supplied.",400);try{await updateHighchartsVersion(r)}catch(e){throw new ExportError(`[version] Version change: ${e.message}`,400).setError(e)}t.status(200).send({statusCode:200,highchartsVersion:getHighchartsVersion(),message:`Successfully updated Highcharts to version: ${r}.`})}catch(e){return o(e)}}))}const activeServers=new Map,app=express();async function startServer(e){try{const t=updateOptions({server:e});if(!(e=t.server).enable||!app)throw new ExportError("[server] Server cannot be started (not enabled or no correct Express app found).",500);const o=1024*e.uploadLimit*1024,n=multer.memoryStorage(),r=multer({storage:n,limits:{fieldSize:o}});if(app.disable("x-powered-by"),app.use(cors({methods:["POST","GET","OPTIONS"]})),app.use(((e,t,o)=>{t.set("Accept-Ranges","none"),o()})),app.use(express.json({limit:o})),app.use(express.urlencoded({extended:!0,limit:o})),app.use(r.none()),app.use(express.static(join(__dirname,"public"))),!e.ssl.force){const t=http.createServer(app);_attachServerErrorHandlers(t),t.listen(e.port,e.host,(()=>{activeServers.set(e.port,t),log(3,`[server] Started HTTP server on ${e.host}:${e.port}.`)}))}if(e.ssl.enable){let t,o;try{t=await readFile(join(getAbsolutePath(e.ssl.certPath),"server.key"),"utf8"),o=await readFile(join(getAbsolutePath(e.ssl.certPath),"server.crt"),"utf8")}catch(t){log(2,`[server] Unable to load key/certificate from the '${e.ssl.certPath}' path. Could not run secured layer server.`)}if(t&&o){const n=https.createServer({key:t,cert:o},app);_attachServerErrorHandlers(n),n.listen(e.ssl.port,e.host,(()=>{activeServers.set(e.ssl.port,n),log(3,`[server] Started HTTPS server on ${e.host}:${e.ssl.port}.`)}))}}rateLimitingMiddleware(app,e.rateLimiting),validationMiddleware(app),exportRoutes(app),healthRoutes(app),uiRoutes(app),versionChangeRoutes(app),errorMiddleware(app)}catch(e){throw new ExportError("[server] Could not configure and start the server.",500).setError(e)}}function closeServers(){if(activeServers.size>0){log(4,"[server] Closing all servers.");for(const[e,t]of activeServers)t.close((()=>{activeServers.delete(e),log(4,`[server] Closed server on port: ${e}.`)}))}}function getServers(){return activeServers}function getExpress(){return express}function getApp(){return app}function enableRateLimiting(e){const t=updateOptions({server:{rateLimiting:e}});rateLimitingMiddleware(app,t.server.rateLimitingOptions)}function use(e,...t){app.use(e,...t)}function get(e,...t){app.get(e,...t)}function post(e,...t){app.post(e,...t)}function _attachServerErrorHandlers(e){e.on("clientError",((e,t)=>{logWithStack(1,e,`[server] Client error: ${e.message}, destroying socket.`),t.destroy()})),e.on("error",(e=>{logWithStack(1,e,`[server] Server error: ${e.message}`)})),e.on("connection",(e=>{e.on("error",(e=>{logWithStack(1,e,`[server] Socket error: ${e.message}`)}))}))}var server={startServer:startServer,closeServers:closeServers,getServers:getServers,getExpress:getExpress,getApp:getApp,enableRateLimiting:enableRateLimiting,use:use,get:get,post:post};async function shutdownCleanUp(e=0){await Promise.allSettled([clearAllTimers(),closeServers(),killPool()]),process.exit(e)}async function initExport(e={}){const t=updateOptions(e,!0);setAllowCodeExecution(t.customLogic.allowCodeExecution),initLogging(t.logging),t.other.listenToProcessExits&&_attachProcessExitListeners(),await checkAndUpdateCache(t.highcharts,t.server.proxy),await initPool(t.pool,t.puppeteer.args)}function _attachProcessExitListeners(){log(3,"[process] Attaching exit listeners to the process."),process.on("exit",(e=>{log(4,`[process] Process exited with code ${e}.`)})),process.on("SIGINT",(async(e,t)=>{log(4,`[process] The ${e} event with code: ${t}.`),await shutdownCleanUp()})),process.on("SIGTERM",(async(e,t)=>{log(4,`[process] The ${e} event with code: ${t}.`),await shutdownCleanUp()})),process.on("SIGHUP",(async(e,t)=>{log(4,`[process] The ${e} event with code: ${t}.`),await shutdownCleanUp()})),process.on("uncaughtException",(async(e,t)=>{logWithStack(1,e,`[process] The ${t} error.`),await shutdownCleanUp(1)}))}var index={...server,getOptions:getOptions,setGlobalOptions:setGlobalOptions,mapToNewOptions:mapToNewOptions,initExport:initExport,singleExport:singleExport,batchExport:batchExport,startExport:startExport,killPool:killPool,shutdownCleanUp:shutdownCleanUp,log:log,logWithStack:logWithStack,logZodIssues:logZodIssues,setLogLevel:function(e){setLogLevel(updateOptions({logging:{level:e}}).logging.level)},enableConsoleLogging:function(e){enableConsoleLogging(updateOptions({logging:{toConsole:e}}).logging.toConsole)},enableFileLogging:function(e,t,o){const n=updateOptions({logging:{dest:e,file:t,toFile:o}});enableFileLogging(n.logging.dest,n.logging.file,n.logging.toFile)}};export{index as default,initExport}; +import"colors";import{readFileSync,existsSync,mkdirSync,appendFile,writeFileSync}from"fs";import{isAbsolute,join}from"path";import{HttpsProxyAgent}from"https-proxy-agent";import{fileURLToPath}from"url";import dotenv from"dotenv";import{z}from"zod";import http from"http";import https from"https";import{Pool}from"tarn";import{v4}from"uuid";import puppeteer from"puppeteer";import DOMPurify from"dompurify";import{JSDOM}from"jsdom";import{readFile}from"fs/promises";import cors from"cors";import express from"express";import multer from"multer";import rateLimit from"express-rate-limit";const __dirname=fileURLToPath(new URL("../.",import.meta.url));function deepCopy(e){if(null===e||"object"!=typeof e)return e;const t=Array.isArray(e)?[]:{};for(const o in e)Object.prototype.hasOwnProperty.call(e,o)&&(t[o]=deepCopy(e[o]));return t}function fixConstr(e){try{const t=`${e.toLowerCase().replace("chart","")}Chart`;return"Chart"===t&&t.toLowerCase(),["chart","stockChart","mapChart","ganttChart"].includes(t)?t:"chart"}catch{return"chart"}}function fixOutfile(e,t){return`${getAbsolutePath(t||"chart").split(".").shift()}.${e}`}function fixType(e,t=null){const o={"image/png":"png","image/jpeg":"jpeg","application/pdf":"pdf","image/svg+xml":"svg"},r=Object.values(o);if(t){const o=t.split(".").pop();"jpg"===o?e="jpeg":r.includes(o)&&e!==o&&(e=o)}return o[e]||r.find((t=>t===e))||"png"}function getAbsolutePath(e){return isAbsolute(e)?e:join(__dirname,e)}function getBase64(e,t){return"pdf"===t||"svg"==t?Buffer.from(e,"utf8").toString("base64"):e}function getNewDate(){return(new Date).toString().split("(")[0].trim()}function getNewDateTime(){return(new Date).getTime()}function isObject(e){return"[object Object]"===Object.prototype.toString.call(e)}function isObjectEmpty(e){return"object"==typeof e&&!Array.isArray(e)&&null!==e&&0===Object.keys(e).length}function isPrivateRangeUrlFound(e){return[/xlink:href="(?:http:\/\/|https:\/\/)?localhost\b/,/xlink:href="(?:http:\/\/|https:\/\/)?10\.\d{1,3}\.\d{1,3}\.\d{1,3}\b/,/xlink:href="(?:http:\/\/|https:\/\/)?127\.\d{1,3}\.\d{1,3}\.\d{1,3}\b/,/xlink:href="(?:http:\/\/|https:\/\/)?172\.(1[6-9]|2[0-9]|3[0-1])\.\d{1,3}\.\d{1,3}\b/,/xlink:href="(?:http:\/\/|https:\/\/)?192\.168\.\d{1,3}\.\d{1,3}\b/].some((t=>t.test(e)))}function measureTime(){const e=process.hrtime.bigint();return()=>Number(process.hrtime.bigint()-e)/1e6}function roundNumber(e,t=1){const o=Math.pow(10,t||0);return Math.round(+e*o)/o}function wrapAround(e,t,o=!1){if(e&&"string"==typeof e)return(e=e.trim()).endsWith(".js")?t?wrapAround(readFileSync(getAbsolutePath(e),"utf8"),t,o):null:!o&&(e.startsWith("function()")||e.startsWith("function ()")||e.startsWith("()=>")||e.startsWith("() =>"))?`(${e})()`:e.replace(/;$/,"")}const colors=["red","yellow","blue","gray","green"],logging={toConsole:!0,toFile:!1,pathCreated:!1,pathToLog:"",levelsDesc:[{title:"error",color:colors[0]},{title:"warning",color:colors[1]},{title:"notice",color:colors[2]},{title:"verbose",color:colors[3]},{title:"benchmark",color:colors[4]}]};function log(...e){const[t,...o]=e,{levelsDesc:r,level:i}=logging;if(5!==t&&(0===t||t>i||i>r.length))return;const n=`${getNewDate()} [${r[t-1].title}] -`;logging.toFile&&_logToFile(o,n),logging.toConsole&&console.log.apply(void 0,[n.toString()[logging.levelsDesc[t-1].color]].concat(o))}function logWithStack(e,t,o){const r=o||t&&t.message||"",{level:i,levelsDesc:n}=logging;if(0===e||e>i||i>n.length)return;const s=`${getNewDate()} [${n[e-1].title}] -`,a=t&&t.stack,l=[r];a&&l.push("\n",a),logging.toFile&&_logToFile(l,s),logging.toConsole&&console.log.apply(void 0,[s.toString()[logging.levelsDesc[e-1].color]].concat([l.shift()[colors[e-1]],...l]))}function logZodIssues(e,t,o){logWithStack(e,null,[`${o||"[validation] Validation error"} - the following Zod issues occured:`,...(t||[]).map((e=>`- ${e.message}`))].join("\n"))}function initLogging(e){const{level:t,dest:o,file:r,toConsole:i,toFile:n}=e;logging.pathCreated=!1,logging.pathToLog="",setLogLevel(t),enableConsoleLogging(i),enableFileLogging(o,r,n)}function setLogLevel(e){Number.isInteger(e)&&e>=0&&e<=logging.levelsDesc.length&&(logging.level=e)}function enableConsoleLogging(e){logging.toConsole=!!e}function enableFileLogging(e,t,o){logging.toFile=!!o,logging.toFile&&(logging.dest=e||"",logging.file=t||"")}function _logToFile(e,t){logging.pathCreated||(!existsSync(getAbsolutePath(logging.dest))&&mkdirSync(getAbsolutePath(logging.dest)),logging.pathToLog=getAbsolutePath(join(logging.dest,logging.file)),logging.pathCreated=!0),appendFile(logging.pathToLog,[t].concat(e).join(" ")+"\n",(e=>{e&&logging.toFile&&logging.pathCreated&&(logging.toFile=!1,logging.pathCreated=!1,logWithStack(2,e,"[logger] Unable to write to log file."))}))}const defaultConfig={puppeteer:{args:{value:["--allow-running-insecure-content","--ash-no-nudges","--autoplay-policy=user-gesture-required","--block-new-web-contents","--disable-accelerated-2d-canvas","--disable-background-networking","--disable-background-timer-throttling","--disable-backgrounding-occluded-windows","--disable-breakpad","--disable-checker-imaging","--disable-client-side-phishing-detection","--disable-component-extensions-with-background-pages","--disable-component-update","--disable-default-apps","--disable-dev-shm-usage","--disable-domain-reliability","--disable-extensions","--disable-features=CalculateNativeWinOcclusion,InterestFeedContentSuggestions,WebOTP","--disable-hang-monitor","--disable-ipc-flooding-protection","--disable-logging","--disable-notifications","--disable-offer-store-unmasked-wallet-cards","--disable-popup-blocking","--disable-print-preview","--disable-prompt-on-repost","--disable-renderer-backgrounding","--disable-search-engine-choice-screen","--disable-session-crashed-bubble","--disable-setuid-sandbox","--disable-site-isolation-trials","--disable-speech-api","--disable-sync","--enable-unsafe-webgpu","--hide-crash-restore-bubble","--hide-scrollbars","--metrics-recording-only","--mute-audio","--no-default-browser-check","--no-first-run","--no-pings","--no-sandbox","--no-startup-window","--no-zygote","--password-store=basic","--process-per-tab","--use-mock-keychain"],types:["string[]"],envLink:"PUPPETEER_ARGS",cliName:"puppeteerArgs",description:"Array of Puppeteer arguments",promptOptions:{type:"list",separator:";"}}},highcharts:{version:{value:"latest",types:["string"],envLink:"HIGHCHARTS_VERSION",description:"Highcharts version",promptOptions:{type:"text"}},cdnUrl:{value:"https://code.highcharts.com",types:["string"],envLink:"HIGHCHARTS_CDN_URL",description:"CDN URL for Highcharts scripts",promptOptions:{type:"text"}},forceFetch:{value:!1,types:["boolean"],envLink:"HIGHCHARTS_FORCE_FETCH",description:"Flag to refetch scripts after each server rerun",promptOptions:{type:"toggle"}},cachePath:{value:".cache",types:["string"],envLink:"HIGHCHARTS_CACHE_PATH",description:"Directory path for cached Highcharts scripts",promptOptions:{type:"text"}},coreScripts:{value:["highcharts","highcharts-more","highcharts-3d"],types:["string[]"],envLink:"HIGHCHARTS_CORE_SCRIPTS",description:"Highcharts core scripts to fetch",promptOptions:{type:"multiselect",instructions:"Space: Select specific, A: Select all, Enter: Confirm"}},moduleScripts:{value:["stock","map","gantt","exporting","parallel-coordinates","accessibility","boost-canvas","boost","data","data-tools","draggable-points","static-scale","broken-axis","heatmap","tilemap","tiledwebmap","timeline","treemap","treegraph","item-series","drilldown","histogram-bellcurve","bullet","funnel","funnel3d","geoheatmap","pyramid3d","networkgraph","overlapping-datalabels","pareto","pattern-fill","pictorial","price-indicator","sankey","arc-diagram","dependency-wheel","series-label","series-on-point","solid-gauge","sonification","streamgraph","sunburst","variable-pie","variwide","vector","venn","windbarb","wordcloud","xrange","no-data-to-display","drag-panes","debugger","dumbbell","lollipop","cylinder","organization","dotplot","marker-clusters","hollowcandlestick","heikinashi","flowmap","export-data","navigator","textpath"],types:["string[]"],envLink:"HIGHCHARTS_MODULE_SCRIPTS",description:"Highcharts module scripts to fetch",promptOptions:{type:"multiselect",instructions:"Space: Select specific, A: Select all, Enter: Confirm"}},indicatorScripts:{value:["indicators-all"],types:["string[]"],envLink:"HIGHCHARTS_INDICATOR_SCRIPTS",description:"Highcharts indicator scripts to fetch",promptOptions:{type:"multiselect",instructions:"Space: Select specific, A: Select all, Enter: Confirm"}},customScripts:{value:["https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.30.1/moment.min.js","https://cdnjs.cloudflare.com/ajax/libs/moment-timezone/0.5.45/moment-timezone-with-data.min.js"],types:["string[]"],envLink:"HIGHCHARTS_CUSTOM_SCRIPTS",description:"Additional custom scripts or dependencies to fetch",promptOptions:{type:"list",separator:";"}}},export:{infile:{value:null,types:["string","null"],envLink:"EXPORT_INFILE",description:"Input filename with type, formatted correctly as JSON or SVG",promptOptions:{type:"text"}},instr:{value:null,types:["Object","string","null"],envLink:"EXPORT_INSTR",description:"Overrides the `infile` with JSON, stringified JSON, or SVG input",promptOptions:{type:"text"}},options:{value:null,types:["Object","string","null"],envLink:"EXPORT_OPTIONS",description:"Alias for the `instr` option",promptOptions:{type:"text"}},svg:{value:null,types:["string","null"],envLink:"EXPORT_SVG",description:"SVG string representation of the chart to render",promptOptions:{type:"text"}},batch:{value:null,types:["string","null"],envLink:"EXPORT_BATCH",description:'Batch job string with input/output pairs: "in=out;in=out;..."',promptOptions:{type:"text"}},outfile:{value:null,types:["string","null"],envLink:"EXPORT_OUTFILE",description:"Output filename with type. Can be jpeg, png, pdf, or svg and ignores `type` option",promptOptions:{type:"text"}},type:{value:"png",types:["string"],envLink:"EXPORT_TYPE",description:"File export format. Can be jpeg, png, pdf, or svg",promptOptions:{type:"select",hint:"Default: png",choices:["png","jpeg","pdf","svg"]}},constr:{value:"chart",types:["string"],envLink:"EXPORT_CONSTR",description:"Chart constructor. Can be chart, stockChart, mapChart, or ganttChart",promptOptions:{type:"select",hint:"Default: chart",choices:["chart","stockChart","mapChart","ganttChart"]}},b64:{value:!1,types:["boolean"],envLink:"EXPORT_B64",description:"Whether or not to the chart should be received in Base64 format instead of binary",promptOptions:{type:"toggle"}},noDownload:{value:!1,types:["boolean"],envLink:"EXPORT_NO_DOWNLOAD",description:"Whether or not to include or exclude attachment headers in the response",promptOptions:{type:"toggle"}},height:{value:null,types:["number","null"],envLink:"EXPORT_HEIGHT",description:"Height of the exported chart, overrides chart settings",promptOptions:{type:"number"}},width:{value:null,types:["number","null"],envLink:"EXPORT_WIDTH",description:"Width of the exported chart, overrides chart settings",promptOptions:{type:"number"}},scale:{value:null,types:["number","null"],envLink:"EXPORT_SCALE",description:"Scale of the exported chart, overrides chart settings. Ranges from 0.1 to 5.0",promptOptions:{type:"number"}},defaultHeight:{value:400,types:["number"],envLink:"EXPORT_DEFAULT_HEIGHT",description:"Default height of the exported chart if not set",promptOptions:{type:"number"}},defaultWidth:{value:600,types:["number"],envLink:"EXPORT_DEFAULT_WIDTH",description:"Default width of the exported chart if not set",promptOptions:{type:"number"}},defaultScale:{value:1,types:["number"],envLink:"EXPORT_DEFAULT_SCALE",description:"Default scale of the exported chart if not set. Ranges from 0.1 to 5.0",promptOptions:{type:"number",min:.1,max:5}},globalOptions:{value:null,types:["Object","string","null"],envLink:"EXPORT_GLOBAL_OPTIONS",description:"JSON, stringified JSON or filename with global options for Highcharts.setOptions",promptOptions:{type:"text"}},themeOptions:{value:null,types:["Object","string","null"],envLink:"EXPORT_THEME_OPTIONS",description:"JSON, stringified JSON or filename with theme options for Highcharts.setOptions",promptOptions:{type:"text"}},rasterizationTimeout:{value:1500,types:["number"],envLink:"EXPORT_RASTERIZATION_TIMEOUT",description:"Milliseconds to wait for webpage rendering",promptOptions:{type:"number"}}},customLogic:{allowCodeExecution:{value:!1,types:["boolean"],envLink:"CUSTOM_LOGIC_ALLOW_CODE_EXECUTION",description:"Allows or disallows execution of arbitrary code during exporting",promptOptions:{type:"toggle"}},allowFileResources:{value:!1,types:["boolean"],envLink:"CUSTOM_LOGIC_ALLOW_FILE_RESOURCES",description:"Allows or disallows injection of filesystem resources (disabled in server mode)",promptOptions:{type:"toggle"}},customCode:{value:null,types:["string","null"],envLink:"CUSTOM_LOGIC_CUSTOM_CODE",description:"Custom code to execute before chart initialization. Can be a function, code wrapped in a function, or a .js filename",promptOptions:{type:"text"}},callback:{value:null,types:["string","null"],envLink:"CUSTOM_LOGIC_CALLBACK",description:"JavaScript code to run during construction. Can be a function or a .js filename",promptOptions:{type:"text"}},resources:{value:null,types:["Object","string","null"],envLink:"CUSTOM_LOGIC_RESOURCES",description:"Additional resources as JSON, stringified JSON, or filename, containing files, js, and css sections",promptOptions:{type:"text"}},loadConfig:{value:null,types:["string","null"],envLink:"CUSTOM_LOGIC_LOAD_CONFIG",legacyName:"fromFile",description:"File with a pre-defined configuration to use",promptOptions:{type:"text"}},createConfig:{value:null,types:["string","null"],envLink:"CUSTOM_LOGIC_CREATE_CONFIG",description:"Prompt-based option setting, saved to a provided config file",promptOptions:{type:"text"}}},server:{enable:{value:!1,types:["boolean"],envLink:"SERVER_ENABLE",cliName:"enableServer",description:"Starts the server when true",promptOptions:{type:"toggle"}},host:{value:"0.0.0.0",types:["string"],envLink:"SERVER_HOST",description:"Hostname of the server",promptOptions:{type:"text"}},port:{value:7801,types:["number"],envLink:"SERVER_PORT",description:"Port number for the server",promptOptions:{type:"number"}},uploadLimit:{value:3,types:["number"],envLink:"SERVER_UPLOAD_LIMIT",description:"Maximum request body size in MB",promptOptions:{type:"number"}},benchmarking:{value:!1,types:["boolean"],envLink:"SERVER_BENCHMARKING",cliName:"serverBenchmarking",description:"Displays or not action durations in milliseconds during server requests",promptOptions:{type:"toggle"}},proxy:{host:{value:null,types:["string","null"],envLink:"SERVER_PROXY_HOST",cliName:"proxyHost",description:"Host of the proxy server, if applicable",promptOptions:{type:"text"}},port:{value:null,types:["number","null"],envLink:"SERVER_PROXY_PORT",cliName:"proxyPort",description:"Port of the proxy server, if applicable",promptOptions:{type:"number"}},timeout:{value:5e3,types:["number"],envLink:"SERVER_PROXY_TIMEOUT",cliName:"proxyTimeout",description:"Timeout in milliseconds for the proxy server, if applicable",promptOptions:{type:"number"}}},rateLimiting:{enable:{value:!1,types:["boolean"],envLink:"SERVER_RATE_LIMITING_ENABLE",cliName:"enableRateLimiting",description:"Enables or disables rate limiting on the server",promptOptions:{type:"toggle"}},maxRequests:{value:10,types:["number"],envLink:"SERVER_RATE_LIMITING_MAX_REQUESTS",legacyName:"rateLimit",description:"Maximum number of requests allowed per minute",promptOptions:{type:"number"}},window:{value:1,types:["number"],envLink:"SERVER_RATE_LIMITING_WINDOW",description:"Time window in minutes for rate limiting",promptOptions:{type:"number"}},delay:{value:0,types:["number"],envLink:"SERVER_RATE_LIMITING_DELAY",description:"Delay duration between successive requests before reaching the limit",promptOptions:{type:"number"}},trustProxy:{value:!1,types:["boolean"],envLink:"SERVER_RATE_LIMITING_TRUST_PROXY",description:"Set to true if the server is behind a load balancer",promptOptions:{type:"toggle"}},skipKey:{value:null,types:["string","null"],envLink:"SERVER_RATE_LIMITING_SKIP_KEY",description:"Key to bypass the rate limiter, used with `skipToken`",promptOptions:{type:"text"}},skipToken:{value:null,types:["string","null"],envLink:"SERVER_RATE_LIMITING_SKIP_TOKEN",description:"Token to bypass the rate limiter, used with `skipKey`",promptOptions:{type:"text"}}},ssl:{enable:{value:!1,types:["boolean"],envLink:"SERVER_SSL_ENABLE",cliName:"enableSsl",description:"Enables or disables SSL protocol",promptOptions:{type:"toggle"}},force:{value:!1,types:["boolean"],envLink:"SERVER_SSL_FORCE",cliName:"sslForce",legacyName:"sslOnly",description:"Forces the server to use HTTPS only when true",promptOptions:{type:"toggle"}},port:{value:443,types:["number"],envLink:"SERVER_SSL_PORT",cliName:"sslPort",description:"Port for the SSL server",promptOptions:{type:"number"}},certPath:{value:null,types:["string","null"],envLink:"SERVER_SSL_CERT_PATH",cliName:"sslCertPath",legacyName:"sslPath",description:"Path to the SSL certificate/key file",promptOptions:{type:"text"}}}},pool:{minWorkers:{value:4,types:["number"],envLink:"POOL_MIN_WORKERS",description:"Minimum and initial number of pool workers to spawn",promptOptions:{type:"number"}},maxWorkers:{value:8,types:["number"],envLink:"POOL_MAX_WORKERS",legacyName:"workers",description:"Maximum number of pool workers to spawn",promptOptions:{type:"number"}},workLimit:{value:40,types:["number"],envLink:"POOL_WORK_LIMIT",description:"Number of tasks a worker can handle before restarting",promptOptions:{type:"number"}},acquireTimeout:{value:5e3,types:["number"],envLink:"POOL_ACQUIRE_TIMEOUT",description:"Timeout in milliseconds for acquiring a resource",promptOptions:{type:"number"}},createTimeout:{value:5e3,types:["number"],envLink:"POOL_CREATE_TIMEOUT",description:"Timeout in milliseconds for creating a resource",promptOptions:{type:"number"}},destroyTimeout:{value:5e3,types:["number"],envLink:"POOL_DESTROY_TIMEOUT",description:"Timeout in milliseconds for destroying a resource",promptOptions:{type:"number"}},idleTimeout:{value:3e4,types:["number"],envLink:"POOL_IDLE_TIMEOUT",description:"Timeout in milliseconds for destroying idle resources",promptOptions:{type:"number"}},createRetryInterval:{value:200,types:["number"],envLink:"POOL_CREATE_RETRY_INTERVAL",description:"Interval in milliseconds before retrying resource creation on failure",promptOptions:{type:"number"}},reaperInterval:{value:1e3,types:["number"],envLink:"POOL_REAPER_INTERVAL",description:"Interval in milliseconds to check and destroy idle resources",promptOptions:{type:"number"}},benchmarking:{value:!1,types:["boolean"],envLink:"POOL_BENCHMARKING",cliName:"poolBenchmarking",description:"Shows statistics for the pool of resources",promptOptions:{type:"toggle"}}},logging:{level:{value:4,types:["number"],envLink:"LOGGING_LEVEL",cliName:"logLevel",description:"Logging verbosity level",promptOptions:{type:"number",round:0,min:0,max:5}},file:{value:"highcharts-export-server.log",types:["string"],envLink:"LOGGING_FILE",cliName:"logFile",description:"Log file name. Requires `logToFile` and `logDest` to be set",promptOptions:{type:"text"}},dest:{value:"log",types:["string"],envLink:"LOGGING_DEST",cliName:"logDest",description:"Path to store log files. Requires `logToFile` to be set",promptOptions:{type:"text"}},toConsole:{value:!0,types:["boolean"],envLink:"LOGGING_TO_CONSOLE",cliName:"logToConsole",description:"Enables or disables console logging",promptOptions:{type:"toggle"}},toFile:{value:!0,types:["boolean"],envLink:"LOGGING_TO_FILE",cliName:"logToFile",description:"Enables or disables logging to a file",promptOptions:{type:"toggle"}}},ui:{enable:{value:!1,types:["boolean"],envLink:"UI_ENABLE",cliName:"enableUi",description:"Enables or disables the UI for the export server",promptOptions:{type:"toggle"}},route:{value:"/",types:["string"],envLink:"UI_ROUTE",cliName:"uiRoute",description:"The endpoint route for the UI",promptOptions:{type:"text"}}},other:{nodeEnv:{value:"production",types:["string"],envLink:"OTHER_NODE_ENV",description:"The Node.js environment type",promptOptions:{type:"text"}},listenToProcessExits:{value:!0,types:["boolean"],envLink:"OTHER_LISTEN_TO_PROCESS_EXITS",description:"Whether or not to attach process.exit handlers",promptOptions:{type:"toggle"}},noLogo:{value:!1,types:["boolean"],envLink:"OTHER_NO_LOGO",description:"Display or skip printing the logo on startup",promptOptions:{type:"toggle"}},hardResetPage:{value:!1,types:["boolean"],envLink:"OTHER_HARD_RESET_PAGE",description:"Whether or not to reset the page content entirely",promptOptions:{type:"toggle"}},browserShellMode:{value:!0,types:["boolean"],envLink:"OTHER_BROWSER_SHELL_MODE",description:"Whether or not to set the browser to run in shell mode",promptOptions:{type:"toggle"}},validation:{value:!0,types:["boolean"],envLink:"OTHER_VALIDATION",description:"Whether or not to enable validation of options types",promptOptions:{type:"toggle"}}},debug:{enable:{value:!1,types:["boolean"],envLink:"DEBUG_ENABLE",cliName:"enableDebug",description:"Enables or disables debug mode for the underlying browser",promptOptions:{type:"toggle"}},headless:{value:!1,types:["boolean"],envLink:"DEBUG_HEADLESS",description:"Whether or not to set the browser to run in headless mode during debugging",promptOptions:{type:"toggle"}},devtools:{value:!1,types:["boolean"],envLink:"DEBUG_DEVTOOLS",description:"Enables or disables DevTools in headful mode",promptOptions:{type:"toggle"}},listenToConsole:{value:!1,types:["boolean"],envLink:"DEBUG_LISTEN_TO_CONSOLE",description:"Enables or disables listening to console messages from the browser",promptOptions:{type:"toggle"}},dumpio:{value:!1,types:["boolean"],envLink:"DEBUG_DUMPIO",description:"Redirects or not browser stdout and stderr to process.stdout and process.stderr",promptOptions:{type:"toggle"}},slowMo:{value:0,types:["number"],envLink:"DEBUG_SLOW_MO",description:"Delays Puppeteer operations by the specified milliseconds",promptOptions:{type:"number"}},debuggingPort:{value:9222,types:["number"],envLink:"DEBUG_DEBUGGING_PORT",description:"Port used for debugging",promptOptions:{type:"number"}}}},nestedProps=_createNestedProps(defaultConfig),absoluteProps=_createAbsoluteProps(defaultConfig);function _createNestedProps(e,t={},o=""){return Object.keys(e).forEach((r=>{const i=e[r];void 0===i.value?_createNestedProps(i,t,`${o}.${r}`):(t[i.cliName||r]=`${o}.${r}`.substring(1),void 0!==i.legacyName&&(t[i.legacyName]=`${o}.${r}`.substring(1)))})),t}function _createAbsoluteProps(e,t=[]){return Object.keys(e).forEach((o=>{const r=e[o];void 0===r.types?_createAbsoluteProps(r,t):r.types.includes("Object")&&t.push(o)})),t}dotenv.config();const{coreScripts:coreScripts,moduleScripts:moduleScripts,indicatorScripts:indicatorScripts}=defaultConfig.highcharts;z.setErrorMap(_customErrorMap);const v={boolean:e=>e?z.boolean():z.union([z.enum(["true","1","false","0","undefined","null",""]).transform((e=>["undefined","null",""].includes(e)?null:"true"===e||"1"===e)),z.boolean()]).nullable(),string:e=>e?z.string().trim().refine((e=>!["false","undefined","null",""].includes(e)),{params:{errorMessage:"The string contains a forbidden value"}}):z.string().trim().transform((e=>["false","undefined","null",""].includes(e)?null:e)).nullable(),enum:(e,t)=>t?z.enum([...e]):z.enum([...e,"undefined","null",""]).transform((e=>["undefined","null",""].includes(e)?null:e)).nullable(),stringArray(e,t,o){const r=z.string().trim().array(),i=z.string().trim().transform((e=>(e.startsWith("[")&&(e=e.slice(1)),e.endsWith("]")&&(e=e.slice(0,-1)),e.split(t)))),n=t=>t.map((e=>e.trim())).filter(e);return o?r.transform(n):z.union([i,r]).transform(n).transform((e=>e.length?e:null)).nullable()},positiveNum:e=>e?z.number().positive():z.union([z.string().trim().refine((e=>!isNaN(Number(e))&&Number(e)>0||["undefined","null",""].includes(e)),{params:{errorMessage:"The value must be numeric and positive"}}).transform((e=>["undefined","null",""].includes(e)?null:Number(e))),z.number().positive()]).nullable(),nonNegativeNum:e=>e?z.number().nonnegative():z.union([z.string().trim().refine((e=>!isNaN(Number(e))&&Number(e)>=0||["undefined","null",""].includes(e)),{params:{errorMessage:"The value must be numeric and non-negative"}}).transform((e=>["undefined","null",""].includes(e)?null:Number(e))),z.number().nonnegative()]).nullable(),startsWith:(e,t)=>t?z.string().trim().refine((t=>e.some((e=>t.startsWith(e)))),{params:{errorMessage:`The value must be a string that starts with ${e.join(", ")}`}}):z.string().trim().refine((t=>e.some((e=>t.startsWith(e)))||["undefined","null",""].includes(t)),{params:{errorMessage:`The value must be a string that starts with ${e.join(", ")}`}}).transform((e=>["undefined","null",""].includes(e)?null:e)).nullable(),chartConfig:()=>z.union([z.string().trim().refine((e=>e.startsWith("{")&&e.endsWith("}")||["undefined","null",""].includes(e)),{params:{errorMessage:"The value must be a string that starts with '{' and ends with '}'"}}).transform((e=>["undefined","null",""].includes(e)?null:e)),z.object({}).passthrough()]).nullable(),additionalOptions:()=>z.union([z.string().trim().refine((e=>e.length>=6&&e.endsWith(".json")||e.startsWith("{")&&e.endsWith("}")||["undefined","null",""].includes(e)),{params:{errorMessage:"The value must be a string that ends with '.json' or starts with '{' and ends with '}'"}}).transform((e=>["undefined","null",""].includes(e)?null:e)),z.object({}).passthrough()]).nullable()},validators={args:e=>v.stringArray((e=>!["false","undefined","null",""].includes(e)),";",e),version:e=>e?z.string().trim().refine((e=>/^(latest|\d{1,2}(\.\d{1,2}){0,2})$/.test(e)),{params:{errorMessage:"The value must be 'latest', a major version, or in the form XX.YY.ZZ"}}):z.string().trim().refine((e=>/^(latest|\d{1,2}(\.\d{1,2}){0,2})$/.test(e)||["undefined","null",""].includes(e)),{params:{errorMessage:"The value must be 'latest', a major version, or in the form XX.YY.ZZ"}}).transform((e=>["undefined","null",""].includes(e)?null:e)).nullable(),cdnUrl:e=>v.startsWith(["http://","https://"],e),forceFetch:e=>v.boolean(e),cachePath:e=>v.string(e),adminToken:e=>v.string(e),coreScripts:e=>v.stringArray((e=>coreScripts.value.includes(e)),",",e),moduleScripts:e=>v.stringArray((e=>moduleScripts.value.includes(e)),",",e),indicatorScripts:e=>v.stringArray((e=>indicatorScripts.value.includes(e)),",",e),customScripts:e=>v.stringArray((e=>e.startsWith("https://")||e.startsWith("http://")),",",e),infile:e=>e?z.string().trim().refine((e=>e.length>=6&&e.endsWith(".json")||e.length>=5&&e.endsWith(".svg")),{params:{errorMessage:"The value must be a string that ends with .json or .svg"}}).nullable():z.string().trim().refine((e=>e.length>=6&&e.endsWith(".json")||e.length>=5&&e.endsWith(".svg")||["undefined","null",""].includes(e)),{params:{errorMessage:"The value must be a string that ends with .json or .svg"}}).transform((e=>["undefined","null",""].includes(e)?null:e)).nullable(),instr:()=>v.chartConfig(),options:()=>v.chartConfig(),svg:()=>z.string().trim().refine((e=>e.indexOf("=0||e.indexOf("=0||["false","undefined","null",""].includes(e)),{params:{errorMessage:"The value must be a string that contains '["false","undefined","null",""].includes(e)?null:e)).nullable(),outfile:e=>e?z.string().trim().refine((e=>e.length>=6&&e.endsWith(".jpeg")||e.length>=5&&(e.endsWith(".jpg")||e.endsWith(".png")||e.endsWith(".pdf")||e.endsWith(".svg"))),{params:{errorMessage:"The value must be a string that ends with .jpeg, .jpg, .png, .pdf, or .svg"}}).nullable():z.string().trim().refine((e=>e.length>=6&&e.endsWith(".jpeg")||e.length>=5&&(e.endsWith(".jpg")||e.endsWith(".png")||e.endsWith(".pdf")||e.endsWith(".svg"))||["undefined","null",""].includes(e)),{params:{errorMessage:"The value must be a string that ends with .jpeg, .jpg, .png, .pdf, or .svg"}}).transform((e=>["undefined","null",""].includes(e)?null:e)).nullable(),type:e=>v.enum(["jpeg","jpg","png","pdf","svg"],e),constr:e=>v.enum(["chart","stockChart","mapChart","ganttChart"],e),b64:e=>v.boolean(e),noDownload:e=>v.boolean(e),defaultHeight:e=>v.positiveNum(e),defaultWidth:e=>v.positiveNum(e),defaultScale:e=>e?z.number().gte(.1).lte(5):z.union([z.string().trim().refine((e=>!isNaN(Number(e))&&!0!==e&&!e.startsWith("[")&&Number(e)>=.1&&Number(e)<=5||["undefined","null",""].includes(e)),{params:{errorMessage:"The value must be within a 0.1 and 5.0 range"}}).transform((e=>["undefined","null",""].includes(e)?null:Number(e))),z.number().gte(.1).lte(5)]).nullable(),height(e){return this.defaultHeight(e).nullable()},width(e){return this.defaultWidth(e).nullable()},scale(e){return this.defaultScale(e).nullable()},globalOptions:()=>v.additionalOptions(),themeOptions:()=>v.additionalOptions(),batch:e=>v.string(e),rasterizationTimeout:e=>v.nonNegativeNum(e),allowCodeExecution:e=>v.boolean(e),allowFileResources:e=>v.boolean(e),customCode:e=>v.string(e),callback:e=>v.string(e),resources(e){const t=z.object({js:v.string(!1),css:v.string(!1),files:v.stringArray((e=>!["undefined","null",""].includes(e)),",",!0).nullable()}).partial(),o=z.string().trim().refine((e=>e.startsWith("{")&&e.endsWith("}")||e.length>=6&&e.endsWith(".json")),{params:{errorMessage:"The value must be a string that starts with '{' and ends with '}"}}),r=z.string().trim().refine((e=>e.startsWith("{")&&e.endsWith("}")||e.length>=6&&e.endsWith(".json")||["undefined","null",""].includes(e)),{params:{errorMessage:"The value must be a string that ends with .json"}}).transform((e=>["undefined","null",""].includes(e)?null:e));return e?z.union([t,o]).nullable():z.union([t,r]).nullable()},loadConfig:e=>v.string(e).refine((e=>null===e||e.length>=6&&e.endsWith(".json")),{params:{errorMessage:"The value must be a string that ends with .json"}}),createConfig(e){return this.loadConfig(e)},enableServer:e=>v.boolean(e),host:e=>v.string(e),port:e=>v.nonNegativeNum(e),uploadLimit:e=>v.positiveNum(e),serverBenchmarking:e=>v.boolean(e),proxyHost:e=>v.string(e),proxyPort:e=>v.nonNegativeNum(e).nullable(),proxyTimeout:e=>v.nonNegativeNum(e),enableRateLimiting:e=>v.boolean(e),maxRequests:e=>v.nonNegativeNum(e),window:e=>v.nonNegativeNum(e),delay:e=>v.nonNegativeNum(e),trustProxy:e=>v.boolean(e),skipKey:e=>v.string(e),skipToken:e=>v.string(e),enableSsl:e=>v.boolean(e),sslForce:e=>v.boolean(e),sslPort:e=>v.nonNegativeNum(e),sslCertPath:e=>v.string(e),minWorkers:e=>v.positiveNum(e),maxWorkers:e=>v.positiveNum(e),workLimit:e=>v.positiveNum(e),acquireTimeout:e=>v.nonNegativeNum(e),createTimeout:e=>v.nonNegativeNum(e),destroyTimeout:e=>v.nonNegativeNum(e),idleTimeout:e=>v.nonNegativeNum(e),createRetryInterval:e=>v.nonNegativeNum(e),reaperInterval:e=>v.nonNegativeNum(e),poolBenchmarking:e=>v.boolean(e),resourcesInterval:e=>v.nonNegativeNum(e),logLevel:e=>e?z.number().int().gte(0).lte(5):z.union([z.string().trim().refine((e=>!isNaN(Number(e))&&!0!==e&&!e.startsWith("[")&&Number.isInteger(Number(e))&&Number(e)>=0&&Number(e)<=5||["undefined","null",""].includes(e)),{params:{errorMessage:"The value must be within a 0 and 5 range"}}).transform((e=>["undefined","null",""].includes(e)?null:Number(e))),z.number().int().gte(0).lte(5)]).nullable(),logFile:e=>v.string(e).refine((e=>null===e||e.length>=5&&e.endsWith(".log")),{params:{errorMessage:"The value must be a string that ends with .log"}}),logDest:e=>v.string(e),logToConsole:e=>v.boolean(e),logToFile:e=>v.boolean(e),enableUi:e=>v.boolean(e),uiRoute:e=>v.startsWith(["/"],e),nodeEnv:e=>v.enum(["development","production","test"],e),listenToProcessExits:e=>v.boolean(e),noLogo:e=>v.boolean(e),hardResetPage:e=>v.boolean(e),browserShellMode:e=>v.boolean(e),validation:e=>v.boolean(e),enableDebug:e=>v.boolean(e),headless:e=>v.boolean(e),devtools:e=>v.boolean(e),listenToConsole:e=>v.boolean(e),dumpio:e=>v.boolean(e),slowMo:e=>v.nonNegativeNum(e),debuggingPort:e=>v.nonNegativeNum(e),requestId:()=>z.string().uuid({message:"The value must be a stringified UUID"}).nullable()},PuppeteerSchema=e=>z.object({args:validators.args(e)}).partial(),HighchartsSchema=e=>z.object({version:validators.version(e),cdnUrl:validators.cdnUrl(e),forceFetch:validators.forceFetch(e),cachePath:validators.cachePath(e),coreScripts:validators.coreScripts(e),moduleScripts:validators.moduleScripts(e),indicatorScripts:validators.indicatorScripts(e),customScripts:validators.customScripts(e)}).partial(),ExportSchema=e=>z.object({infile:validators.infile(e),instr:validators.instr(),options:validators.options(),svg:validators.svg(),outfile:validators.outfile(e),type:validators.type(e),constr:validators.constr(e),b64:validators.b64(e),noDownload:validators.noDownload(e),defaultHeight:validators.defaultHeight(e),defaultWidth:validators.defaultWidth(e),defaultScale:validators.defaultScale(e),height:validators.height(e),width:validators.width(e),scale:validators.scale(e),globalOptions:validators.globalOptions(),themeOptions:validators.themeOptions(),batch:validators.batch(!1),rasterizationTimeout:validators.rasterizationTimeout(e)}).partial(),CustomLogicSchema=e=>z.object({allowCodeExecution:validators.allowCodeExecution(e),allowFileResources:validators.allowFileResources(e),customCode:validators.customCode(!1),callback:validators.callback(!1),resources:validators.resources(e),loadConfig:validators.loadConfig(!1),createConfig:validators.createConfig(!1)}).partial(),ProxySchema=e=>z.object({host:validators.proxyHost(!1),port:validators.proxyPort(e),timeout:validators.proxyTimeout(e)}).partial(),RateLimitingSchema=e=>z.object({enable:validators.enableRateLimiting(e),maxRequests:validators.maxRequests(e),window:validators.window(e),delay:validators.delay(e),trustProxy:validators.trustProxy(e),skipKey:validators.skipKey(!1),skipToken:validators.skipToken(!1)}).partial(),SslSchema=e=>z.object({enable:validators.enableSsl(e),force:validators.sslForce(e),port:validators.sslPort(e),certPath:validators.sslCertPath(!1)}).partial(),ServerSchema=e=>z.object({enable:validators.enableServer(e).optional(),host:validators.host(e).optional(),port:validators.port(e).optional(),uploadLimit:validators.uploadLimit(e).optional(),benchmarking:validators.serverBenchmarking(e).optional(),proxy:ProxySchema(e).optional(),rateLimiting:RateLimitingSchema(e).optional(),ssl:SslSchema(e).optional()}),PoolSchema=e=>z.object({minWorkers:validators.minWorkers(e),maxWorkers:validators.maxWorkers(e),workLimit:validators.workLimit(e),acquireTimeout:validators.acquireTimeout(e),createTimeout:validators.createTimeout(e),destroyTimeout:validators.destroyTimeout(e),idleTimeout:validators.idleTimeout(e),createRetryInterval:validators.createRetryInterval(e),reaperInterval:validators.reaperInterval(e),benchmarking:validators.poolBenchmarking(e)}).partial(),LoggingSchema=e=>z.object({level:validators.logLevel(e),file:validators.logFile(e),dest:validators.logDest(e),toConsole:validators.logToConsole(e),toFile:validators.logToFile(e)}).partial(),UiSchema=e=>z.object({enable:validators.enableUi(e),route:validators.uiRoute(e)}).partial(),OtherSchema=e=>z.object({nodeEnv:validators.nodeEnv(e),listenToProcessExits:validators.listenToProcessExits(e),noLogo:validators.noLogo(e),hardResetPage:validators.hardResetPage(e),browserShellMode:validators.browserShellMode(e),validation:validators.validation(e)}).partial(),DebugSchema=e=>z.object({enable:validators.enableDebug(e),headless:validators.headless(e),devtools:validators.devtools(e),listenToConsole:validators.listenToConsole(e),dumpio:validators.dumpio(e),slowMo:validators.slowMo(e),debuggingPort:validators.debuggingPort(e)}).partial(),StrictConfigSchema=z.object({requestId:validators.requestId(),puppeteer:PuppeteerSchema(!0),highcharts:HighchartsSchema(!0),export:ExportSchema(!0),customLogic:CustomLogicSchema(!0),server:ServerSchema(!0),pool:PoolSchema(!0),logging:LoggingSchema(!0),ui:UiSchema(!0),other:OtherSchema(!0),debug:DebugSchema(!0)}),LooseConfigSchema=z.object({requestId:validators.requestId(),puppeteer:PuppeteerSchema(!1),highcharts:HighchartsSchema(!1),export:ExportSchema(!1),customLogic:CustomLogicSchema(!1),server:ServerSchema(!1),pool:PoolSchema(!1),logging:LoggingSchema(!1),ui:UiSchema(!1),other:OtherSchema(!1),debug:DebugSchema(!1)}),EnvSchema=z.object({PUPPETEER_ARGS:validators.args(!1),HIGHCHARTS_VERSION:validators.version(!1),HIGHCHARTS_CDN_URL:validators.cdnUrl(!1),HIGHCHARTS_FORCE_FETCH:validators.forceFetch(!1),HIGHCHARTS_CACHE_PATH:validators.cachePath(!1),HIGHCHARTS_ADMIN_TOKEN:validators.adminToken(!1),HIGHCHARTS_CORE_SCRIPTS:validators.coreScripts(!1),HIGHCHARTS_MODULE_SCRIPTS:validators.moduleScripts(!1),HIGHCHARTS_INDICATOR_SCRIPTS:validators.indicatorScripts(!1),HIGHCHARTS_CUSTOM_SCRIPTS:validators.customScripts(!1),EXPORT_INFILE:validators.infile(!1),EXPORT_INSTR:validators.instr(),EXPORT_OPTIONS:validators.options(),EXPORT_SVG:validators.svg(),EXPORT_BATCH:validators.batch(!1),EXPORT_OUTFILE:validators.outfile(!1),EXPORT_TYPE:validators.type(!1),EXPORT_CONSTR:validators.constr(!1),EXPORT_B64:validators.b64(!1),EXPORT_NO_DOWNLOAD:validators.noDownload(!1),EXPORT_HEIGHT:validators.height(!1),EXPORT_WIDTH:validators.width(!1),EXPORT_SCALE:validators.scale(!1),EXPORT_DEFAULT_HEIGHT:validators.defaultHeight(!1),EXPORT_DEFAULT_WIDTH:validators.defaultWidth(!1),EXPORT_DEFAULT_SCALE:validators.defaultScale(!1),EXPORT_GLOBAL_OPTIONS:validators.globalOptions(),EXPORT_THEME_OPTIONS:validators.themeOptions(),EXPORT_RASTERIZATION_TIMEOUT:validators.rasterizationTimeout(!1),CUSTOM_LOGIC_ALLOW_CODE_EXECUTION:validators.allowCodeExecution(!1),CUSTOM_LOGIC_ALLOW_FILE_RESOURCES:validators.allowFileResources(!1),CUSTOM_LOGIC_CUSTOM_CODE:validators.customCode(!1),CUSTOM_LOGIC_CALLBACK:validators.callback(!1),CUSTOM_LOGIC_RESOURCES:validators.resources(!1),CUSTOM_LOGIC_LOAD_CONFIG:validators.loadConfig(!1),CUSTOM_LOGIC_CREATE_CONFIG:validators.createConfig(!1),SERVER_ENABLE:validators.enableServer(!1),SERVER_HOST:validators.host(!1),SERVER_PORT:validators.port(!1),SERVER_UPLOAD_LIMIT:validators.uploadLimit(!1),SERVER_BENCHMARKING:validators.serverBenchmarking(!1),SERVER_PROXY_HOST:validators.proxyHost(!1),SERVER_PROXY_PORT:validators.proxyPort(!1),SERVER_PROXY_TIMEOUT:validators.proxyTimeout(!1),SERVER_RATE_LIMITING_ENABLE:validators.enableRateLimiting(!1),SERVER_RATE_LIMITING_MAX_REQUESTS:validators.maxRequests(!1),SERVER_RATE_LIMITING_WINDOW:validators.window(!1),SERVER_RATE_LIMITING_DELAY:validators.delay(!1),SERVER_RATE_LIMITING_TRUST_PROXY:validators.trustProxy(!1),SERVER_RATE_LIMITING_SKIP_KEY:validators.skipKey(!1),SERVER_RATE_LIMITING_SKIP_TOKEN:validators.skipToken(!1),SERVER_SSL_ENABLE:validators.enableSsl(!1),SERVER_SSL_FORCE:validators.sslForce(!1),SERVER_SSL_PORT:validators.sslPort(!1),SERVER_SSL_CERT_PATH:validators.sslCertPath(!1),POOL_MIN_WORKERS:validators.minWorkers(!1),POOL_MAX_WORKERS:validators.maxWorkers(!1),POOL_WORK_LIMIT:validators.workLimit(!1),POOL_ACQUIRE_TIMEOUT:validators.acquireTimeout(!1),POOL_CREATE_TIMEOUT:validators.createTimeout(!1),POOL_DESTROY_TIMEOUT:validators.destroyTimeout(!1),POOL_IDLE_TIMEOUT:validators.idleTimeout(!1),POOL_CREATE_RETRY_INTERVAL:validators.createRetryInterval(!1),POOL_REAPER_INTERVAL:validators.reaperInterval(!1),POOL_BENCHMARKING:validators.poolBenchmarking(!1),LOGGING_LEVEL:validators.logLevel(!1),LOGGING_FILE:validators.logFile(!1),LOGGING_DEST:validators.logDest(!1),LOGGING_TO_CONSOLE:validators.logToConsole(!1),LOGGING_TO_FILE:validators.logToFile(!1),UI_ENABLE:validators.enableUi(!1),UI_ROUTE:validators.uiRoute(!1),OTHER_NODE_ENV:validators.nodeEnv(!1),OTHER_LISTEN_TO_PROCESS_EXITS:validators.listenToProcessExits(!1),OTHER_NO_LOGO:validators.noLogo(!1),OTHER_HARD_RESET_PAGE:validators.hardResetPage(!1),OTHER_BROWSER_SHELL_MODE:validators.browserShellMode(!1),OTHER_VALIDATION:validators.validation(!1),DEBUG_ENABLE:validators.enableDebug(!1),DEBUG_HEADLESS:validators.headless(!1),DEBUG_DEVTOOLS:validators.devtools(!1),DEBUG_LISTEN_TO_CONSOLE:validators.listenToConsole(!1),DEBUG_DUMPIO:validators.dumpio(!1),DEBUG_SLOW_MO:validators.slowMo(!1),DEBUG_DEBUGGING_PORT:validators.debuggingPort(!1)}),envs=EnvSchema.partial().parse(process.env);function strictValidate(e){return StrictConfigSchema.partial().parse(e)}function looseValidate(e){return LooseConfigSchema.partial().parse(e)}function _customErrorMap(e,t){const o=e.path.join("."),r=`Invalid value for the ${o}`;if(e.code===z.ZodIssueCode.invalid_type)return e.received===z.ZodParsedType.undefined?{message:`${r} - No value was provided.`}:{message:`${r} - Invalid type. ${t.defaultError}.`};if(e.code===z.ZodIssueCode.custom&&e.params?.errorMessage)return{message:`${r} - ${e.params?.errorMessage}, received '${t.data}'.`};if(e.code===z.ZodIssueCode.invalid_union){let t=`Multiple errors occurred for the ${o}:\n`;return e.unionErrors.forEach((e=>{const o=e.issues[0].message.indexOf("-");t+=-1!==o?`${e.issues[0].message}\n`.substring(o):`${e.issues[0].message}\n`})),{message:t}}return{message:`${r} - ${t.defaultError}.`}}class ExportError extends Error{constructor(e,t){super(),this.message=e,this.stackMessage=e,t&&(this.statusCode=t)}setStatus(e){return this.statusCode=e,this}setError(e){return this.error=e,e.name&&(this.name=e.name),e.statusCode&&(this.statusCode=e.statusCode),e.stack&&(this.stackMessage=e.message,this.stack=e.stack),this}}const globalOptions=_initGlobalOptions(defaultConfig),instanceOptions=deepCopy(globalOptions);function getOptions(e=!0){return e?instanceOptions:globalOptions}function setGlobalOptions(e={},t=[]){let o={},r={};if(t&&Array.isArray(t)&&t.length){try{o=strictValidate(_loadConfigFile(t,globalOptions.customLogic))}catch(e){logZodIssues(1,e.issues,"[validation] Custom options from the `loadConfig` option validation error")}try{r=looseValidate(_pairArgumentValue(nestedProps,t))}catch(e){logZodIssues(1,e.issues,"[validation] CLI options validation error")}}if(e&&isObject(e)&&Object.keys(e).length)try{e=strictValidate(e)}catch(e){logZodIssues(1,e.issues,"[validation] Custom options validation error")}return _updateGlobalOptions(defaultConfig,globalOptions,o,r,e),globalOptions}function updateOptions(e,t=!1){return t&&(Object.keys(instanceOptions).forEach((e=>{delete instanceOptions[e]})),mergeOptions(instanceOptions,deepCopy(globalOptions))),mergeOptions(instanceOptions,e),instanceOptions}function mergeOptions(e,t){if(isObject(e)&&isObject(t))for(const[o,r]of Object.entries(t))e[o]=isObject(r)&&!absoluteProps.includes(o)&&void 0!==e[o]?mergeOptions(e[o],r):void 0!==r?r:e[o]||null;return e}function mapToNewOptions(e){const t={};if(isObject(e))for(const[o,r]of Object.entries(e)){const e=nestedProps[o]?nestedProps[o].split("."):[];e.reduce(((t,o,i)=>t[o]=e.length-1===i?r:t[o]||{}),t)}else log(2,"[config] No correct object with options was provided. Returning an empty array.");return t}function validateOption(e,t,o=!0){if(!getOptions().other.validation)return t;try{return validators[e](o).parse(t)}catch(t){throw logZodIssues(1,t.issues,`[validation] The ${e} option validation error`),new ExportError(`[validation] The ${e} option validation error`,400)}}function validateOptions(e,t=!0){if(!getOptions().other.validation)return e;try{return t?strictValidate(e):looseValidate(e)}catch(e){throw logZodIssues(1,e.issues,"[validation] Options validation error"),new ExportError("[validation] Options validation error",400)}}function isAllowedConfig(config,toString=!1,allowFunctions=!1){try{if(!isObject(config)&&"string"!=typeof config)return null;const objectConfig="string"==typeof config?allowFunctions?eval(`(${config})`):JSON.parse(config):config,stringifiedOptions=_optionsStringify(objectConfig,allowFunctions,!1),parsedOptions=allowFunctions?JSON.parse(_optionsStringify(objectConfig,allowFunctions,!0),((_,value)=>"string"==typeof value&&value.startsWith("function")?eval(`(${value})`):value)):JSON.parse(stringifiedOptions);return toString?stringifiedOptions:parsedOptions}catch(e){return null}}function _initGlobalOptions(e){const t={};for(const[o,r]of Object.entries(e))if(Object.prototype.hasOwnProperty.call(r,"value")){const e=envs[r.envLink];t[o]=null!=e?e:r.value}else t[o]=_initGlobalOptions(r);return t}function _updateGlobalOptions(e,t,o,r,i){Object.keys(e).forEach((n=>{const s=e[n],a=o&&o[n],l=r&&r[n],c=i&&i[n];if(void 0===s.value)_updateGlobalOptions(s,t[n],a,l,c);else{null!=a&&(t[n]=a);const e=envs[s.envLink];s.envLink in envs&&null!=e&&(t[n]=e),null!=l&&(t[n]=l),null!=c&&(t[n]=c)}}))}function _optionsStringify(e,t,o){return JSON.stringify(e,((e,r)=>{if("string"==typeof r&&(r=r.trim()),"function"==typeof r||"string"==typeof r&&r.startsWith("function")&&r.endsWith("}")){if(t)return o?`"EXP_FUN${(r+"").replaceAll(/\s+/g," ")}EXP_FUN"`:`EXP_FUN${(r+"").replaceAll(/\s+/g," ")}EXP_FUN`;throw new Error}return r})).replaceAll(o?/\\"EXP_FUN|EXP_FUN\\"/g:/"EXP_FUN|EXP_FUN"/g,"")}function _loadConfigFile(e,t){const o=e.findIndex((e=>"loadConfig"===e.replace(/-/g,""))),r=o>-1&&e[o+1];if(r&&t.allowFileResources)try{return isAllowedConfig(readFileSync(getAbsolutePath(r),"utf8"),!1,t.allowCodeExecution)}catch(e){logWithStack(2,e,`[config] Unable to load the configuration from the ${r} file.`)}return{}}function _pairArgumentValue(e,t){const o={};for(let r=0;r{if(n.length-1===s){const n=t[++r];n||log(2,`[config] Missing value for the CLI '--${i}' argument. Using the default value.`),e[o]=n||null}else void 0===e[o]&&(e[o]={});return e[o]}),o)}return o}async function fetch(e,t={}){return new Promise(((o,r)=>{_getProtocolModule(e).get(e,t,(e=>{let t="";e.on("data",(e=>{t+=e})),e.on("end",(()=>{t||r("Nothing was fetched from the URL."),e.text=t,o(e)}))})).on("error",(e=>{r(e)}))}))}function _getProtocolModule(e){return e.startsWith("https")?https:http}const cache={cdnUrl:"https://code.highcharts.com",activeManifest:{},sources:"",hcVersion:""};async function checkAndUpdateCache(e,t){try{let o;const r=getCachePath(),i=join(r,"manifest.json"),n=join(r,"sources.js");if(!existsSync(r)&&mkdirSync(r,{recursive:!0}),!existsSync(i)||e.forceFetch)log(3,"[cache] Fetching and caching Highcharts dependencies."),o=await _updateCache(e,t,n);else{let r=!1;const s=JSON.parse(readFileSync(i),"utf8");if(s.modules&&Array.isArray(s.modules)){const e={};s.modules.forEach((t=>e[t]=1)),s.modules=e}const{coreScripts:a,moduleScripts:l,indicatorScripts:c}=e,p=a.length+l.length+c.length;s.version!==e.version?(log(2,"[cache] A Highcharts version mismatch in the cache, need to re-fetch."),r=!0):Object.keys(s.modules||{}).length!==p?(log(2,"[cache] The cache and the requested modules do not match, need to re-fetch."),r=!0):r=(l||[]).some((e=>{if(!s.modules[e])return log(2,`[cache] The ${e} is missing in the cache, need to re-fetch.`),!0})),r?o=await _updateCache(e,t,n):(log(3,"[cache] Dependency cache is up to date, proceeding."),cache.sources=readFileSync(n,"utf8"),o=s.modules,cache.hcVersion=extractVersion(cache.sources))}await _saveConfigToManifest(e,o)}catch(e){throw new ExportError("[cache] Could not configure cache and create or update the config manifest.",500).setError(e)}}function getHighchartsVersion(){return cache.hcVersion}async function updateHighchartsVersion(e){const t=getOptions();t.highcharts.version=e,await checkAndUpdateCache(t.highcharts,t.server.proxy)}function extractVersion(e){return e.substring(0,e.indexOf("*/")).replace("/*","").replace("*/","").replace(/\n/g,"").trim()}function extractModuleName(e){return e.replace(/(.*)\/|(.*)modules\/|stock\/(.*)indicators\/|maps\/(.*)modules\//gi,"")}function getCachePath(){return getAbsolutePath(getOptions().highcharts.cachePath)}async function _fetchAndProcessScript(e,t,o,r=!1){e.endsWith(".js")&&(e=e.substring(0,e.length-3)),log(4,`[cache] Fetching script - ${e}.js`);const i=await fetch(`${e}.js`,t);if(200===i.statusCode&&"string"==typeof i.text){if(o){o[extractModuleName(e)]=1}return i.text}if(r)throw new ExportError(`[cache] Could not fetch the ${e}.js. The script might not exist in the requested version (status code: ${i.statusCode}).`,404).setError(i);log(2,`[cache] Could not fetch the ${e}.js. The script might not exist in the requested version.`)}async function _saveConfigToManifest(e,t={}){const o={version:e.version,modules:t};cache.activeManifest=o,log(3,"[cache] Writing a new manifest.");try{writeFileSync(join(getCachePath(),"manifest.json"),JSON.stringify(o),"utf8")}catch(e){throw new ExportError("[cache] Error writing the cache manifest.",500).setError(e)}}async function _fetchScripts(e,t,o,r,i){let n;const s=r.host,a=r.port;if(s&&a)try{n=new HttpsProxyAgent({host:s,port:a})}catch(e){throw new ExportError("[cache] Could not create a Proxy Agent.",500).setError(e)}const l=n?{agent:n,timeout:r.timeout}:{},c=[...e.map((e=>_fetchAndProcessScript(`${e}`,l,i,!0))),...t.map((e=>_fetchAndProcessScript(`${e}`,l,i))),...o.map((e=>_fetchAndProcessScript(`${e}`,l)))];return(await Promise.all(c)).join(";\n")}async function _updateCache(e,t,o){const r="latest"===e.version?null:`${e.version}`,i=e.cdnUrl||cache.cdnUrl;try{const n={};return log(3,`[cache] Updating cache version to Highcharts: ${r||"latest"}.`),cache.sources=await _fetchScripts([...e.coreScripts.map((e=>r?`${i}/${r}/${e}`:`${i}/${e}`))],[...e.moduleScripts.map((e=>"map"===e?r?`${i}/maps/${r}/modules/${e}`:`${i}/maps/modules/${e}`:r?`${i}/${r}/modules/${e}`:`${i}/modules/${e}`)),...e.indicatorScripts.map((e=>r?`${i}/stock/${r}/indicators/${e}`:`${i}/stock/indicators/${e}`))],e.customScripts,t,n),cache.hcVersion=extractVersion(cache.sources),writeFileSync(o,cache.sources),n}catch(e){throw new ExportError("[cache] Unable to update the local Highcharts cache.",500).setError(e)}}function setupHighcharts(){Highcharts.animObject=function(){return{duration:0}}}async function createChart(e,t){const{getOptions:o,setOptions:r,merge:i,wrap:n}=Highcharts;Highcharts.setOptionsObj=i(!1,{},o()),window.isRenderComplete=!1,n(Highcharts.Chart.prototype,"init",(function(e,t,o){((t=i(t,{exporting:{enabled:!1},plotOptions:{series:{label:{enabled:!1}}},tooltip:{}})).series||[]).forEach((function(e){e.animation=!1})),window.onHighchartsRender||(window.onHighchartsRender=Highcharts.addEvent(this,"render",(()=>{window.isRenderComplete=!0}))),e.apply(this,[t,o])})),n(Highcharts.Series.prototype,"init",(function(e,t,o){e.apply(this,[t,o])}));const s={chart:{animation:!1,height:e.height,width:e.width},exporting:{enabled:!1}},a=new Function(`return ${e.instr}`)(),l=new Function(`return ${e.themeOptions}`)(),c=new Function(`return ${e.globalOptions}`)(),p=i(!1,l,a,s),u=t.callback?new Function(`return ${t.callback}`)():null;t.customCode&&new Function("options",t.customCode)(a),c&&r(c),Highcharts[e.constr]("container",p,u);const d=o();for(const e in d)"function"!=typeof d[e]&&delete d[e];r(Highcharts.setOptionsObj),Highcharts.setOptionsObj={}}const template=readFileSync(join(__dirname,"templates","template.html"),"utf8");let browser=null;async function createBrowser(e){const{debug:t,other:o}=getOptions(),{enable:r,...i}=t,n={headless:!o.browserShellMode||"shell",userDataDir:"tmp",args:e||[],handleSIGINT:!1,handleSIGTERM:!1,handleSIGHUP:!1,waitForInitialPage:!1,defaultViewport:null,...r&&i};if(!browser){let e=0;const t=async()=>{try{log(3,`[browser] Attempting to get a browser instance (try ${++e}).`),browser=await puppeteer.launch(n)}catch(o){if(logWithStack(1,o,"[browser] Failed to launch a browser instance."),!(e<25))throw o;log(3,`[browser] Retry to open a browser (${e} out of 25).`),await new Promise((e=>setTimeout(e,4e3))),await t()}};try{await t(),"shell"===n.headless&&log(3,"[browser] Launched browser in shell mode."),r&&log(3,"[browser] Launched browser in debug mode.")}catch(e){throw new ExportError("[browser] Maximum retries to open a browser instance reached.",500).setError(e)}if(!browser)throw new ExportError("[browser] Cannot find a browser to open.",500)}return browser}async function closeBrowser(){browser&&browser.connected&&await browser.close(),browser=null,log(4,"[browser] Closed the browser.")}async function newPage(e){if(!browser||!browser.connected)throw new ExportError("[browser] Browser is not yet connected.",500);if(e.page=await browser.newPage(),await e.page.setCacheEnabled(!1),await _setPageContent(e.page),_setPageEvents(e.page),!e.page||e.page.isClosed())throw new ExportError("[browser] The page is invalid or closed.",400)}async function clearPage(e,t=!1){try{if(e.page&&!e.page.isClosed())return t?(await e.page.goto("about:blank",{waitUntil:"domcontentloaded"}),await _setPageContent(e.page)):await e.page.evaluate((()=>{document.body.innerHTML='
'})),!0}catch(t){logWithStack(2,t,`[pool] Pool resource [${e.id}] - Content of the page could not be cleared.`),e.workCount=getOptions().pool.workLimit+1}return!1}async function addPageResources(e,t){const o=[],r=t.resources;if(r){const i=[];if(r.js&&i.push({content:r.js}),r.files)for(const e of r.files){const t=!e.startsWith("http");i.push(t?{content:readFileSync(getAbsolutePath(e),"utf8")}:{url:e})}for(const t of i)try{o.push(await e.addScriptTag(t))}catch(e){logWithStack(2,e,"[browser] The JS resource cannot be loaded.")}i.length=0;const n=[];if(r.css){let i=r.css.match(/@import\s*([^;]*);/g);if(i)for(let e of i)e&&(e=e.replace("url(","").replace("@import","").replace(/"/g,"").replace(/'/g,"").replace(/;/,"").replace(/\)/g,"").trim(),e.startsWith("http")?n.push({url:e}):t.allowFileResources&&n.push({path:join(__dirname,e)}));n.push({content:r.css.replace(/@import\s*([^;]*);/g,"")||" "});for(const t of n)try{o.push(await e.addStyleTag(t))}catch(e){logWithStack(2,e,"[browser] The CSS resource cannot be loaded.")}n.length=0}}return o}async function clearPageResources(e,t){try{for(const e of t)await e.dispose();await e.evaluate((()=>{if("undefined"!=typeof Highcharts){const e=Highcharts.charts;if(Array.isArray(e)&&e.length)for(const t of e)t&&t.destroy(),Highcharts.charts.shift()}const[...e]=document.getElementsByTagName("script"),[,...t]=document.getElementsByTagName("style"),[...o]=document.getElementsByTagName("link");for(const r of[...e,...t,...o])r.remove()}))}catch(e){logWithStack(2,e,"[browser] Could not clear page's resources.")}}async function _setPageContent(e){await e.setContent(template,{waitUntil:"domcontentloaded"}),await e.addScriptTag({path:join(getCachePath(),"sources.js")}),await e.evaluate(setupHighcharts)}function _setPageEvents(e){const{debug:t}=getOptions();e.on("pageerror",(async()=>{e.isClosed()})),t.enable&&t.listenToConsole&&e.on("console",(e=>{console.log(`[debug] ${e.text()}`)}))}var cssTemplate=()=>"\n\nhtml, body {\n margin: 0;\n padding: 0;\n box-sizing: border-box;\n}\n\n#table-div, #sliders, #datatable, #controls, .ld-row {\n display: none;\n height: 0;\n}\n\n#chart-container {\n box-sizing: border-box;\n margin: 0;\n overflow: auto;\n font-size: 0;\n}\n\n#chart-container > figure, div {\n margin-top: 0 !important;\n margin-bottom: 0 !important;\n}\n\n",svgTemplate=e=>`\n\n\n \n \n Highcharts Export\n \n \n \n
\n ${e}\n
\n \n\n\n`;async function puppeteerExport(e,t,o){const r=[];try{let i=!1;if(t.svg){if(log(4,"[export] Treating as SVG input."),"svg"===t.type)return t.svg;i=!0,await e.setContent(svgTemplate(t.svg),{waitUntil:"domcontentloaded"})}else log(4,"[export] Treating as JSON config."),await e.evaluate(createChart,t,o);r.push(...await addPageResources(e,o));const n=i?await e.evaluate((e=>{const t=document.querySelector("#chart-container svg:first-of-type"),o=t.height.baseVal.value*e,r=t.width.baseVal.value*e;return document.body.style.zoom=e,document.body.style.margin="0px",{chartHeight:o,chartWidth:r}}),parseFloat(t.scale)):await e.evaluate((()=>{const{chartHeight:e,chartWidth:t}=window.Highcharts.charts[0];return document.body.style.zoom=1,{chartHeight:e,chartWidth:t}})),{x:s,y:a}=await _getClipRegion(e),l=Math.abs(Math.ceil(n.chartHeight||t.height)),c=Math.abs(Math.ceil(n.chartWidth||t.width));let p;switch(await e.setViewport({height:l,width:c,deviceScaleFactor:i?1:parseFloat(t.scale)}),t.type){case"svg":p=await _createSVG(e);break;case"png":case"jpeg":p=await _createImage(e,t.type,{width:c,height:l,x:s,y:a},t.rasterizationTimeout);break;case"pdf":p=await _createPDF(e,l,c,t.rasterizationTimeout);break;default:throw new ExportError(`[export] Unsupported output format: ${t.type}.`,400)}return await clearPageResources(e,r),p}catch(t){return await clearPageResources(e,r),t}}async function _getClipRegion(e){return e.$eval("#chart-container",(e=>{const{x:t,y:o,width:r,height:i}=e.getBoundingClientRect();return{x:t,y:o,width:r,height:Math.trunc(i>1?i:500)}}))}async function _createSVG(e){return e.$eval("#container svg:first-of-type",(e=>e.outerHTML))}async function _createImage(e,t,o,r){return Promise.race([e.screenshot({type:t,clip:o,encoding:"base64",fullPage:!1,optimizeForSpeed:!0,captureBeyondViewport:!0,..."png"!==t?{quality:80}:{},omitBackground:"png"==t}),new Promise(((e,t)=>setTimeout((()=>t(new ExportError("Rasterization timeout",408))),r||1500)))])}async function _createPDF(e,t,o,r){return await e.emulateMediaType("screen"),e.pdf({height:t+1,width:o,encoding:"base64",timeout:r||1500})}let pool=null;const poolStats={exportsAttempted:0,exportsPerformed:0,exportsDropped:0,exportsFromSvg:0,exportsFromOptions:0,exportsFromSvgAttempts:0,exportsFromOptionsAttempts:0,timeSpent:0,timeSpentAverage:0};async function initPool(e,t){await createBrowser(t);try{if(log(3,`[pool] Initializing pool with workers: min ${e.minWorkers}, max ${e.maxWorkers}.`),pool)return void log(4,"[pool] Already initialized, please kill it before creating a new one.");e.minWorkers>e.maxWorkers&&(e.minWorkers=e.maxWorkers),pool=new Pool({..._factory(e),min:e.minWorkers,max:e.maxWorkers,acquireTimeoutMillis:e.acquireTimeout,createTimeoutMillis:e.createTimeout,destroyTimeoutMillis:e.destroyTimeout,idleTimeoutMillis:e.idleTimeout,createRetryIntervalMillis:e.createRetryInterval,reapIntervalMillis:e.reaperInterval,propagateCreateError:!1}),pool.on("release",(async e=>{const t=await clearPage(e,!1);log(4,`[pool] Pool resource [${e.id}] - Releasing a worker. Clear page status: ${t}.`)})),pool.on("destroySuccess",((e,t)=>{log(4,`[pool] Pool resource [${t.id}] - Destroyed a worker successfully.`),t.page=null}));const t=[];for(let o=0;o{pool.release(e)})),log(3,"[pool] The pool is ready"+(t.length?` with ${t.length} initial resources waiting.`:"."))}catch(e){throw new ExportError("[pool] Could not configure and create the pool of workers.",500).setError(e)}}async function killPool(){if(log(3,"[pool] Killing pool with all workers and closing browser."),pool){for(const e of pool.used)pool.release(e.resource);pool.destroyed||(await pool.destroy(),log(4,"[pool] Destroyed the pool of resources.")),pool=null}await closeBrowser()}async function postWork(e){let t;try{if(log(4,"[pool] Work received, starting to process."),++poolStats.exportsAttempted,e.pool.benchmarking&&getPoolInfo(),!pool)throw new ExportError("[pool] Work received, but pool has not been started.",500);const o=measureTime();try{log(4,"[pool] Acquiring a worker handle."),t=await pool.acquire().promise,e.server.benchmarking&&log(5,"[benchmark] "+(e.requestId?`Request [${e.requestId}] - `:""),`Acquiring a worker handle took ${o()}ms.`)}catch(t){throw new ExportError(`[pool] ${e.requestId?`Request [${e.requestId}] - `:""}Error encountered when acquiring an available entry: ${o()}ms.`,400).setError(t)}if(log(4,"[pool] Acquired a worker handle."),!t.page)throw t.workCount=e.pool.workLimit+1,new ExportError("[pool] Resolved worker page is invalid: the pool setup is wonky.",400);const r=getNewDateTime();log(4,`[pool] Pool resource [${t.id}] - Starting work on this pool entry.`);const i=measureTime(),n=await puppeteerExport(t.page,e.export,e.customLogic);if(n instanceof Error)throw"Rasterization timeout"===n.message&&(t.workCount=e.pool.workLimit+1,t.page=null),"TimeoutError"===n.name||"Rasterization timeout"===n.message?new ExportError(`[pool] ${e.requestId?`Request [${e.requestId}] - `:""}Rasterization timeout: your chart may be too complex or large, and failed to render within the allotted time.`).setError(n):new ExportError(`[pool] ${e.requestId?`Request [${e.requestId}] - `:""}Error encountered during export: ${i()}ms.`).setError(n);e.server.benchmarking&&log(5,"[benchmark] "+(e.requestId?`Request [${e.requestId}] - `:""),`Exporting a chart sucessfully took ${i()}ms.`),pool.release(t);const s=getNewDateTime()-r;return poolStats.timeSpent+=s,poolStats.timeSpentAverage=poolStats.timeSpent/++poolStats.exportsPerformed,log(4,`[pool] Work completed in ${s}ms.`),{result:n,options:e}}catch(e){throw++poolStats.exportsDropped,t&&pool.release(t),e}}function getPoolStats(){return poolStats}function getPoolInfoJSON(){return{min:pool.min,max:pool.max,used:pool.numUsed(),available:pool.numFree(),allCreated:pool.numUsed()+pool.numFree(),pendingAcquires:pool.numPendingAcquires(),pendingCreates:pool.numPendingCreates(),pendingValidations:pool.numPendingValidations(),pendingDestroys:pool.pendingDestroys.length,absoluteAll:pool.numUsed()+pool.numFree()+pool.numPendingAcquires()+pool.numPendingCreates()+pool.numPendingValidations()+pool.pendingDestroys.length}}function getPoolInfo(){const{min:e,max:t,used:o,available:r,allCreated:i,pendingAcquires:n,pendingCreates:s,pendingValidations:a,pendingDestroys:l,absoluteAll:c}=getPoolInfoJSON();log(5,`[pool] The minimum number of resources allowed by pool: ${e}.`),log(5,`[pool] The maximum number of resources allowed by pool: ${t}.`),log(5,`[pool] The number of used resources: ${o}.`),log(5,`[pool] The number of free resources: ${r}.`),log(5,`[pool] The number of all created (used and free) resources: ${i}.`),log(5,`[pool] The number of resources waiting to be acquired: ${n}.`),log(5,`[pool] The number of resources waiting to be created: ${s}.`),log(5,`[pool] The number of resources waiting to be validated: ${a}.`),log(5,`[pool] The number of resources waiting to be destroyed: ${l}.`),log(5,`[pool] The number of all resources: ${c}.`)}function _factory(e){return{create:async()=>{const t={id:v4(),workCount:Math.round(Math.random()*(e.workLimit/2))};try{const e=getNewDateTime();return await newPage(t),log(3,`[pool] Pool resource [${t.id}] - Successfully created a worker, took ${getNewDateTime()-e}ms.`),t}catch(e){throw log(3,`[pool] Pool resource [${t.id}] - Error encountered when creating a new page.`),e}},validate:async t=>t.page?t.page.isClosed()?(log(3,`[pool] Pool resource [${t.id}] - Validation failed (page is closed or invalid).`),!1):t.page.mainFrame().detached?(log(3,`[pool] Pool resource [${t.id}] - Validation failed (page's frame is detached).`),!1):!(e.workLimit&&++t.workCount>e.workLimit)||(log(3,`[pool] Pool resource [${t.id}] - Validation failed (exceeded the ${e.workLimit} works per resource limit).`),!1):(log(3,`[pool] Pool resource [${t.id}] - Validation failed (no valid page is found).`),!1),destroy:async e=>{if(log(3,`[pool] Pool resource [${e.id}] - Destroying a worker.`),e.page&&!e.page.isClosed())try{e.page.removeAllListeners("pageerror"),e.page.removeAllListeners("console"),e.page.removeAllListeners("framedetached"),await e.page.close()}catch(t){throw log(3,`[pool] Pool resource [${e.id}] - Page could not be closed upon destroying.`),t}}}}function sanitize(e){const t=new JSDOM("").window;return DOMPurify(t).sanitize(e,{ADD_TAGS:["foreignObject"]})}let allowCodeExecution=!1;async function singleExport(e){if(!e||!e.export)throw new ExportError("[chart] No expected `export` options were found. Please provide one of the following options: `infile`, `instr`, `options`, or `svg` to generate a valid image.",400);e=validateOptions(e),await startExport({export:e.export,customLogic:e.customLogic},(async(e,t)=>{if(e)throw e;const{b64:o,outfile:r,type:i}=t.options.export;try{o?writeFileSync(`${r.split(".").shift()||"chart"}.txt`,getBase64(t.result,i)):writeFileSync(r||`chart.${i}`,"svg"!==i?Buffer.from(t.result,"base64"):t.result)}catch(e){throw new ExportError("[chart] Error while saving a chart.",500).setError(e)}await killPool()}))}async function batchExport(e){if(!(e&&e.export&&e.export.batch))throw new ExportError("[chart] No expected `export` options were found. Please provide the `batch` option to generate valid images.",400);{e=validateOptions(e);const t=[];for(let o of e.export.batch.split(";")||[])o=o.split("="),2===o.length?t.push(startExport({export:{...e.export,infile:o[0],outfile:o[1]},customLogic:e.customLogic},((e,t)=>{if(e)throw e;const{b64:o,outfile:r,type:i}=t.options.export;try{o?writeFileSync(`${r.split(".").shift()||"chart"}.txt`,getBase64(t.result,i)):writeFileSync(r,"svg"!==i?Buffer.from(t.result,"base64"):t.result)}catch(e){throw new ExportError("[chart] Error while saving a chart.",500).setError(e)}}))):log(2,"[chart] No correct pair found for the batch export.");const o=await Promise.allSettled(t);await killPool(),o.forEach(((e,t)=>{e.reason&&logWithStack(1,e.reason,`[chart] Batch export number ${t+1} could not be correctly completed.`)}))}}async function startExport(e,t){try{if(!isObject(e))throw new ExportError("[chart] Incorrect value of the provided `exportingOptions`. Needs to be an object.",400);const o=mergeOptions(deepCopy(getOptions()),{export:e.export,customLogic:e.customLogic}),r=o.export;if(log(4,"[chart] Starting the exporting process."),null!==r.infile){let e;log(4,"[chart] Attempting to export from a file input.");try{e=readFileSync(getAbsolutePath(r.infile),"utf8")}catch(e){throw new ExportError("[chart] Error loading content from a file input.",400).setError(e)}if(r.infile.endsWith(".svg"))r.svg=validateOption("svg",e);else{if(!r.infile.endsWith(".json"))throw new ExportError("[chart] Incorrect value of the `infile` option.",400);r.instr=validateOption("instr",e)}}if(null!==r.svg){log(4,"[chart] Attempting to export from an SVG input."),++getPoolStats().exportsFromSvgAttempts;const e=await _exportFromSvg(sanitize(r.svg),o);return++getPoolStats().exportsFromSvg,t(null,e)}if(null!==r.instr||null!==r.options){log(4,"[chart] Attempting to export from options input."),++getPoolStats().exportsFromOptionsAttempts;const e=await _exportFromOptions(r.instr||r.options,o);return++getPoolStats().exportsFromOptions,t(null,e)}return t(new ExportError("[chart] No valid input specified. Check if at least one of the following parameters is correctly set: 'infile', 'instr', 'options', or 'svg'.",400))}catch(e){return t(e)}}function getAllowCodeExecution(){return allowCodeExecution}function setAllowCodeExecution(e){allowCodeExecution=e}async function _exportFromSvg(e,t){if("string"==typeof e&&(e.indexOf("=0||e.indexOf("=0))return log(4,"[chart] Parsing input as SVG."),t.export.svg=e,t.export.instr=null,t.export.options=null,_prepareExport(t);throw new ExportError("[chart] Not a correct SVG input.",400)}async function _exportFromOptions(e,t){log(4,"[chart] Parsing input from options.");const o=isAllowedConfig(e,!0,t.customLogic.allowCodeExecution);if(null===o||"string"!=typeof o||!o.startsWith("{")||!o.endsWith("}"))throw new ExportError("[chart] Invalid configuration provided - Only options configurations and SVG are allowed for this server. If this is your server, JavaScript custom code can be enabled by starting the server with the `allowCodeExecution` options set to true.",403);return t.export.instr=o,t.export.svg=null,_prepareExport(t)}async function _prepareExport(e){const{export:t,customLogic:o}=e;return t.type=fixType(t.type,t.outfile),t.outfile=fixOutfile(t.type,t.outfile),t.constr=fixConstr(t.constr),log(3,`[chart] The custom logic is ${o.allowCodeExecution?"allowed":"disallowed"}.`),_handleCustomLogic(o,o.allowCodeExecution),_handleGlobalAndTheme(t,o.allowFileResources,o.allowCodeExecution),e.export={...t,..._findChartSize(t)},postWork(e)}function _findChartSize(e){const{chart:t,exporting:o}=e.options||isAllowedConfig(e.instr)||!1,{chart:r,exporting:i}=isAllowedConfig(e.globalOptions)||!1,{chart:n,exporting:s}=isAllowedConfig(e.themeOptions)||!1,a=roundNumber(Math.max(.1,Math.min(e.scale||o?.scale||i?.scale||s?.scale||e.defaultScale||1,5)),2),l={height:e.height||o?.sourceHeight||t?.height||i?.sourceHeight||r?.height||s?.sourceHeight||n?.height||e.defaultHeight||400,width:e.width||o?.sourceWidth||t?.width||i?.sourceWidth||r?.width||s?.sourceWidth||n?.width||e.defaultWidth||600,scale:a};for(let[e,t]of Object.entries(l))l[e]="string"==typeof t?+t.replace(/px|%/gi,""):t;return l}function _handleCustomLogic(e,t){if(t){if("string"==typeof e.resources)e.resources=_handleResources(e.resources,e.allowFileResources,!0);else if(!e.resources)try{e.resources=_handleResources(readFileSync(getAbsolutePath("resources.json"),"utf8"),e.allowFileResources,!0)}catch(e){log(2,"[chart] Unable to load the default `resources.json` file.")}try{e.customCode=wrapAround(e.customCode,e.allowFileResources),e.customCode=validateOption("customCode",e.customCode)}catch(t){logWithStack(2,t,"[chart] The `customCode` cannot be loaded."),e.customCode=null}try{e.callback=wrapAround(e.callback,e.allowFileResources,!0),e.callback=validateOption("callback",e.callback)}catch(t){logWithStack(2,t,"[chart] The `callback` cannot be loaded."),e.callback=null}[null,void 0].includes(e.customCode)&&log(3,"[chart] No value for the `customCode` option found."),[null,void 0].includes(e.callback)&&log(3,"[chart] No value for the `callback` option found."),[null,void 0].includes(e.resources)&&log(3,"[chart] No value for the `resources` option found.")}else if(e.callback||e.resources||e.customCode)throw e.callback=null,e.resources=null,e.customCode=null,new ExportError("[chart] The 'callback', 'resources', and 'customCode' options have been disabled for this server.",403)}function _handleResources(e=null,t,o){const r=["js","css","files"];let i=e,n=!1;if(t&&e.endsWith(".json"))try{i=isAllowedConfig(readFileSync(getAbsolutePath(e),"utf8"),!1,o)}catch{return null}else i=isAllowedConfig(e,!1,o),i&&!t&&delete i.files;for(const e in i)r.includes(e)?n||(n=!0):delete i[e];return n?(i.files&&(i.files=i.files.map((e=>e.trim())),(!i.files||i.files.length<=0)&&delete i.files),i=validateOption("resources",i),i):null}function _handleGlobalAndTheme(e,t,o){["globalOptions","themeOptions"].forEach((r=>{try{e[r]&&(t&&"string"==typeof e[r]&&e[r].endsWith(".json")?e[r]=isAllowedConfig(readFileSync(getAbsolutePath(e[r]),"utf8"),!0,o):e[r]=isAllowedConfig(e[r],!0,o),e[r]=validateOption(r,e[r]))}catch(t){logWithStack(2,t,`[chart] The \`${r}\` cannot be loaded.`),e[r]=null}})),[null,void 0].includes(e.globalOptions)&&log(3,"[chart] No value for the `globalOptions` option found."),[null,void 0].includes(e.themeOptions)&&log(3,"[chart] No value for the `themeOptions` option found.")}const timerIds=[];function addTimer(e){timerIds.push(e)}function clearAllTimers(){log(4,"[timer] Clearing all registered intervals and timeouts.");for(const e of timerIds)clearInterval(e),clearTimeout(e)}function logErrorMiddleware(e,t,o,r){return logWithStack(1,e),"development"!==getOptions().other.nodeEnv&&delete e.stack,r(e)}function returnErrorMiddleware(e,t,o,r){const{message:i,stack:n}=e,s=e.statusCode||400;o.status(s).json({statusCode:s,message:i,stack:n})}function errorMiddleware(e){e.use(logErrorMiddleware),e.use(returnErrorMiddleware)}function rateLimitingMiddleware(e,t){try{if(t.enable){const o="Too many requests, you have been rate limited. Please try again later.",r={window:t.window||1,maxRequests:t.maxRequests||30,delay:t.delay||0,trustProxy:t.trustProxy||!1,skipKey:t.skipKey||null,skipToken:t.skipToken||null};r.trustProxy&&e.enable("trust proxy");const i=rateLimit({windowMs:60*r.window*1e3,limit:r.maxRequests,delayMs:r.delay,handler:(e,t)=>{t.format({json:()=>{t.status(429).send({message:o})},default:()=>{t.status(429).send(o)}})},skip:e=>null!==r.skipKey&&null!==r.skipToken&&e.query.key===r.skipKey&&e.query.access_token===r.skipToken&&(log(4,"[rate limiting] Skipping rate limiter."),!0)});e.use(i),log(3,`[rate limiting] Enabled rate limiting with ${r.maxRequests} requests per ${r.window} minute for each IP, trusting proxy: ${r.trustProxy}.`)}}catch(e){throw new ExportError("[rate limiting] Could not configure and set the rate limiting options.",500).setError(e)}}function contentTypeMiddleware(e,t,o){try{const t=e.headers["content-type"]||"";if(!t.includes("application/json")&&!t.includes("application/x-www-form-urlencoded")&&!t.includes("multipart/form-data"))throw new ExportError("[validation] Content-Type must be application/json, application/x-www-form-urlencoded, or multipart/form-data.",415);return o()}catch(e){return o(e)}}function requestBodyMiddleware(e,t,o){try{const t=e.body,r=v4();if(!t||isObjectEmpty(t))throw log(2,`[validation] Request [${r}] - The request from ${e.headers["x-forwarded-for"]||e.connection.remoteAddress} was incorrect. Received payload is empty.`),new ExportError(`[validation] Request [${r}] - The request body is required. Please ensure that your Content-Type header is correct. Accepted types are 'application/json' and 'multipart/form-data'.`,400);const i=getAllowCodeExecution(),n=isAllowedConfig(t.instr||t.options||t.infile||t.data,!0,i);if(null===n&&!t.svg)throw log(2,`[validation] Request [${r}] - The request from ${e.headers["x-forwarded-for"]||e.connection.remoteAddress} was incorrect. Received payload is missing correct chart data for export: ${JSON.stringify(t)}.`),new ExportError(`Request [${r}] - [validation] No correct chart data found. Ensure that you are using either application/json or multipart/form-data headers. If sending JSON, make sure the chart data is in the 'infile', 'options', or 'data' attribute. If sending SVG, ensure it is in the 'svg' attribute.`,400);if(t.svg&&isPrivateRangeUrlFound(t.svg))throw new ExportError(`Request [${r}] - [validation] SVG potentially contain at least one forbidden URL in 'xlink:href' element. Please review the SVG content and ensure that all referenced URLs comply with security policies.`,400);return e.validatedOptions=validateOptions({requestId:r,export:{instr:n,svg:t.svg,outfile:t.outfile||`${e.params.filename||"chart"}.${t.type||"png"}`,type:t.type,constr:t.constr,b64:t.b64,noDownload:t.noDownload,height:t.height,width:t.width,scale:t.scale,globalOptions:isAllowedConfig(t.globalOptions,!0,i),themeOptions:isAllowedConfig(t.themeOptions,!0,i)},customLogic:{allowCodeExecution:i,allowFileResources:!1,customCode:t.customCode,callback:t.callback,resources:isAllowedConfig(t.resources,!0,i)}}),o()}catch(e){return o(e)}}function validationMiddleware(e){e.post(["/","/:filename"],contentTypeMiddleware),e.post(["/","/:filename"],requestBodyMiddleware)}const reversedMime={png:"image/png",jpeg:"image/jpeg",gif:"image/gif",pdf:"application/pdf",svg:"image/svg+xml"};async function requestExport(e,t,o){try{const o=measureTime();let r=!1;e.socket.on("close",(e=>{e&&(r=!0)}));const i=e.validatedOptions,n=i.requestId;log(4,`[export] Request [${n}] - Got an incoming HTTP request.`),await startExport(i,((i,s)=>{if(e.socket.removeAllListeners("close"),r)log(3,`[export] Request [${n}] - The client closed the connection before the chart finished processing.`);else{if(i)throw i;if(!s||!s.result)throw log(2,`[export] Request [${n}] - Request from ${e.headers["x-forwarded-for"]||e.connection.remoteAddress} was incorrect. Received result is ${s.result}.`),new ExportError(`[export] Request [${n}] - Unexpected return of the export result from the chart generation. Please check your request data.`,400);if(s.result){log(3,`[export] Request [${n}] - The whole exporting process took ${o()}ms.`);const{type:e,b64:r,noDownload:i,outfile:a}=s.options.export;return r?t.send(getBase64(s.result,e)):(t.header("Content-Type",reversedMime[e]||"image/png"),i||t.attachment(a),"svg"===e?t.send(s.result):t.send(Buffer.from(s.result,"base64")))}}}))}catch(e){return o(e)}}function exportRoutes(e){e.post("/",requestExport),e.post("/:filename",requestExport)}const serverStartTime=new Date,packageFile=JSON.parse(readFileSync(join(__dirname,"package.json"),"utf8")),successRates=[],recordInterval=6e4,windowSize=30;function _calculateMovingAverage(){return successRates.reduce(((e,t)=>e+t),0)/successRates.length}function _startSuccessRate(){return setInterval((()=>{const e=getPoolStats(),t=0===e.exportsAttempted?1:e.exportsPerformed/e.exportsAttempted*100;successRates.push(t),successRates.length>windowSize&&successRates.shift()}),recordInterval)}function healthRoutes(e){addTimer(_startSuccessRate()),e.get("/health",((e,t,o)=>{try{log(4,"[health] Returning server health.");const e=getPoolStats(),o=successRates.length,r=_calculateMovingAverage();t.send({status:"OK",bootTime:serverStartTime,uptime:`${Math.floor((getNewDateTime()-serverStartTime.getTime())/1e3/60)} minutes`,serverVersion:packageFile.version,highchartsVersion:getHighchartsVersion(),averageExportTime:e.timeSpentAverage,attemptedExports:e.exportsAttempted,performedExports:e.exportsPerformed,failedExports:e.exportsDropped,sucessRatio:e.exportsPerformed/e.exportsAttempted*100,pool:getPoolInfoJSON(),period:o,movingAverage:r,message:isNaN(r)||!successRates.length?"Too early to report. No exports made yet. Please check back soon.":`Last ${o} minutes had a success rate of ${r.toFixed(2)}%.`,svgExports:e.exportsFromSvg,jsonExports:e.exportsFromOptions,svgExportsAttempts:e.exportsFromSvgAttempts,jsonExportsAttempts:e.exportsFromOptionsAttempts})}catch(e){return o(e)}}))}function uiRoutes(e){e.get(getOptions().ui.route||"/",((e,t,o)=>{try{log(4,"[ui] Returning UI for the export."),t.sendFile(join(__dirname,"public","index.html"),{acceptRanges:!1})}catch(e){return o(e)}}))}function versionChangeRoutes(e){e.post("/version_change/:newVersion",(async(e,t,o)=>{try{log(4,"[version] Changing Highcharts version.");const o=envs.HIGHCHARTS_ADMIN_TOKEN;if(!o||!o.length)throw new ExportError("[version] The server is not configured to perform run-time version changes: HIGHCHARTS_ADMIN_TOKEN is not set.",401);const r=e.get("hc-auth");if(!r||r!==o)throw new ExportError("[version] Invalid or missing token: Set the token in the hc-auth header.",401);let i=e.params.newVersion;try{i=validateOption("version",e.params.newVersion)}catch(e){throw new ExportError(`[version] Version is incorrect: ${e.message}`,400).setError(e)}if(!i)throw new ExportError("[version] No new version supplied.",400);try{await updateHighchartsVersion(i)}catch(e){throw new ExportError(`[version] Version change: ${e.message}`,400).setError(e)}t.status(200).send({statusCode:200,highchartsVersion:getHighchartsVersion(),message:`Successfully updated Highcharts to version: ${i}.`})}catch(e){return o(e)}}))}const activeServers=new Map,app=express();async function startServer(e){try{const t=updateOptions(validateOptions({server:e}));if(!(e=t.server).enable||!app)throw new ExportError("[server] Server cannot be started (not enabled or no correct Express app found).",500);const o=1024*e.uploadLimit*1024,r=multer.memoryStorage(),i=multer({storage:r,limits:{fieldSize:o}});if(app.disable("x-powered-by"),app.use(cors({methods:["POST","GET","OPTIONS"]})),app.use(((e,t,o)=>{t.set("Accept-Ranges","none"),o()})),app.use(express.json({limit:o})),app.use(express.urlencoded({extended:!0,limit:o})),app.use(i.none()),app.use(express.static(join(__dirname,"public"))),!e.ssl.force){const t=http.createServer(app);_attachServerErrorHandlers(t),t.listen(e.port,e.host,(()=>{activeServers.set(e.port,t),log(3,`[server] Started HTTP server on ${e.host}:${e.port}.`)}))}if(e.ssl.enable){let t,o;try{t=await readFile(join(getAbsolutePath(e.ssl.certPath),"server.key"),"utf8"),o=await readFile(join(getAbsolutePath(e.ssl.certPath),"server.crt"),"utf8")}catch(t){log(2,`[server] Unable to load key/certificate from the '${e.ssl.certPath}' path. Could not run secured layer server.`)}if(t&&o){const r=https.createServer({key:t,cert:o},app);_attachServerErrorHandlers(r),r.listen(e.ssl.port,e.host,(()=>{activeServers.set(e.ssl.port,r),log(3,`[server] Started HTTPS server on ${e.host}:${e.ssl.port}.`)}))}}rateLimitingMiddleware(app,e.rateLimiting),validationMiddleware(app),exportRoutes(app),healthRoutes(app),uiRoutes(app),versionChangeRoutes(app),errorMiddleware(app)}catch(e){throw new ExportError("[server] Could not configure and start the server.",500).setError(e)}}function closeServers(){if(activeServers.size>0){log(4,"[server] Closing all servers.");for(const[e,t]of activeServers)t.close((()=>{activeServers.delete(e),log(4,`[server] Closed server on port: ${e}.`)}))}}function getServers(){return activeServers}function getExpress(){return express}function getApp(){return app}function enableRateLimiting(e){const t=updateOptions(validateOptions({server:{rateLimiting:e}}));rateLimitingMiddleware(app,t.server.rateLimitingOptions)}function use(e,...t){app.use(e,...t)}function get(e,...t){app.get(e,...t)}function post(e,...t){app.post(e,...t)}function _attachServerErrorHandlers(e){e.on("clientError",((e,t)=>{logWithStack(1,e,`[server] Client error: ${e.message}, destroying socket.`),t.destroy()})),e.on("error",(e=>{logWithStack(1,e,`[server] Server error: ${e.message}`)})),e.on("connection",(e=>{e.on("error",(e=>{logWithStack(1,e,`[server] Socket error: ${e.message}`)}))}))}var server={startServer:startServer,closeServers:closeServers,getServers:getServers,getExpress:getExpress,getApp:getApp,enableRateLimiting:enableRateLimiting,use:use,get:get,post:post};async function shutdownCleanUp(e=0){await Promise.allSettled([clearAllTimers(),closeServers(),killPool()]),process.exit(e)}async function initExport(e={}){const t=updateOptions(validateOptions(e),!0);setAllowCodeExecution(t.customLogic.allowCodeExecution),initLogging(t.logging),t.other.listenToProcessExits&&_attachProcessExitListeners(),await checkAndUpdateCache(t.highcharts,t.server.proxy),await initPool(t.pool,t.puppeteer.args)}function _attachProcessExitListeners(){log(3,"[process] Attaching exit listeners to the process."),process.on("exit",(e=>{log(4,`[process] Process exited with code ${e}.`)})),process.on("SIGINT",(async(e,t)=>{log(4,`[process] The ${e} event with code: ${t}.`),await shutdownCleanUp()})),process.on("SIGTERM",(async(e,t)=>{log(4,`[process] The ${e} event with code: ${t}.`),await shutdownCleanUp()})),process.on("SIGHUP",(async(e,t)=>{log(4,`[process] The ${e} event with code: ${t}.`),await shutdownCleanUp()})),process.on("uncaughtException",(async(e,t)=>{logWithStack(1,e,`[process] The ${t} error.`),await shutdownCleanUp(1)}))}var index={...server,getOptions:getOptions,setGlobalOptions:setGlobalOptions,mapToNewOptions:mapToNewOptions,validateOption:validateOption,validateOptions:validateOptions,initExport:initExport,singleExport:singleExport,batchExport:batchExport,startExport:startExport,killPool:killPool,shutdownCleanUp:shutdownCleanUp,log:log,logWithStack:logWithStack,logZodIssues:logZodIssues,setLogLevel:function(e){setLogLevel(updateOptions(validateOptions({logging:{level:e}})).logging.level)},enableConsoleLogging:function(e){enableConsoleLogging(updateOptions(validateOptions({logging:{toConsole:e}})).logging.toConsole)},enableFileLogging:function(e,t,o){const r=updateOptions(validateOptions({logging:{dest:e,file:t,toFile:o}}));enableFileLogging(r.logging.dest,r.logging.file,r.logging.toFile)}};export{index as default,initExport}; //# sourceMappingURL=index.esm.js.map diff --git a/dist/index.esm.js.map b/dist/index.esm.js.map index 545da11b..dd3f1f3e 100644 --- a/dist/index.esm.js.map +++ b/dist/index.esm.js.map @@ -1 +1 @@ -{"version":3,"file":"index.esm.js","sources":["../lib/utils.js","../lib/logger.js","../lib/schemas/config.js","../lib/validation.js","../lib/config.js","../lib/fetch.js","../lib/errors/ExportError.js","../lib/cache.js","../lib/highcharts.js","../lib/browser.js","../templates/svgExport/css.js","../templates/svgExport/svgExport.js","../lib/export.js","../lib/pool.js","../lib/sanitize.js","../lib/chart.js","../lib/timer.js","../lib/server/middlewares/error.js","../lib/server/middlewares/rateLimiting.js","../lib/server/middlewares/validation.js","../lib/server/routes/export.js","../lib/server/routes/health.js","../lib/server/routes/ui.js","../lib/server/routes/versionChange.js","../lib/server/server.js","../lib/resourceRelease.js","../lib/index.js"],"sourcesContent":["/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * @overview The Highcharts Export Server utility module provides\r\n * a comprehensive set of helper functions and constants designed to streamline\r\n * and enhance various operations required for Highcharts export tasks.\r\n */\r\n\r\nimport { readFileSync } from 'fs';\r\nimport { isAbsolute, join } from 'path';\r\nimport { fileURLToPath } from 'url';\r\n\r\nconst MAX_BACKOFF_ATTEMPTS = 6;\r\n\r\n// The directory path\r\nexport const __dirname = fileURLToPath(new URL('../.', import.meta.url));\r\n\r\n/**\r\n * Clears and standardizes text by replacing multiple consecutive whitespace\r\n * characters with a single space and trimming any leading or trailing\r\n * whitespace.\r\n *\r\n * @function clearText\r\n *\r\n * @param {string} text - The input text to be cleared.\r\n * @param {RegExp} [rule=/\\s\\s+/g] - The regular expression rule to match\r\n * multiple consecutive whitespace characters. The default value\r\n * is the '/\\s\\s+/g' RegExp.\r\n * @param {string} [replacer=' '] - The string used to replace multiple\r\n * consecutive whitespace characters. The default value is the ' ' string.\r\n *\r\n * @returns {string} The cleared and standardized text.\r\n */\r\nexport function clearText(text, rule = /\\s\\s+/g, replacer = ' ') {\r\n return text.replaceAll(rule, replacer).trim();\r\n}\r\n\r\n/**\r\n * Creates a deep copy of the given object or array.\r\n *\r\n * @function deepCopy\r\n *\r\n * @param {(Object|Array)} objArr - The object or array to be deeply copied.\r\n *\r\n * @returns {(Object|Array)} The deep copy of the provided object or array.\r\n */\r\nexport function deepCopy(objArr) {\r\n // If the `objArr` is null or not of the `object` type, return it\r\n if (objArr === null || typeof objArr !== 'object') {\r\n return objArr;\r\n }\r\n\r\n // Prepare either a new array or a new object\r\n const objArrCopy = Array.isArray(objArr) ? [] : {};\r\n\r\n // Recursively copy each property\r\n for (const key in objArr) {\r\n if (Object.prototype.hasOwnProperty.call(objArr, key)) {\r\n objArrCopy[key] = deepCopy(objArr[key]);\r\n }\r\n }\r\n\r\n // Return the copied object\r\n return objArrCopy;\r\n}\r\n\r\n/**\r\n * Implements an exponential backoff strategy for retrying a function until\r\n * a certain number of attempts are reached.\r\n *\r\n * @async\r\n * @function expBackoff\r\n *\r\n * @param {Function} fn - The function to be retried.\r\n * @param {number} [attempt=0] - The current attempt number. The default value\r\n * is `0`.\r\n * @param {...unknown} args - Arguments to be passed to the function.\r\n *\r\n * @returns {Promise} A Promise that resolves to the result\r\n * of the function if successful.\r\n *\r\n * @throws {Error} Throws an `Error` if the maximum number of attempts\r\n * is reached.\r\n */\r\nexport async function expBackoff(fn, attempt = 0, ...args) {\r\n try {\r\n // Try to call the function\r\n return await fn(...args);\r\n } catch (error) {\r\n // Calculate delay in ms\r\n const delayInMs = 2 ** attempt * 1000;\r\n\r\n // If the attempt exceeds the maximum attempts of repeat, throw an error\r\n if (++attempt >= MAX_BACKOFF_ATTEMPTS) {\r\n throw error;\r\n }\r\n\r\n // Wait given amount of time\r\n await new Promise((response) => setTimeout(response, delayInMs));\r\n\r\n /// TO DO: Correct\r\n // // Information about the resource timeout\r\n // log(\r\n // 3,\r\n // `[utils] Waited ${delayInMs}ms until next call for the resource of ID: ${args[0]}.`\r\n // );\r\n\r\n // Try again\r\n return expBackoff(fn, attempt, ...args);\r\n }\r\n}\r\n\r\n/**\r\n * Adjusts the constructor name by transforming and normalizing it based\r\n * on common chart types.\r\n *\r\n * @function fixConstr\r\n *\r\n * @param {string} constr - The original constructor name to be fixed.\r\n *\r\n * @returns {string} The corrected constructor name, or 'chart' if the input\r\n * is not recognized.\r\n */\r\nexport function fixConstr(constr) {\r\n try {\r\n // Fix the constructor by lowering casing\r\n const fixedConstr = `${constr.toLowerCase().replace('chart', '')}Chart`;\r\n\r\n // Handle the case where the result is just 'Chart'\r\n if (fixedConstr === 'Chart') {\r\n fixedConstr.toLowerCase();\r\n }\r\n\r\n // Return the corrected constructor, otherwise default to 'chart'\r\n return ['chart', 'stockChart', 'mapChart', 'ganttChart'].includes(\r\n fixedConstr\r\n )\r\n ? fixedConstr\r\n : 'chart';\r\n } catch {\r\n // Default to 'chart' in case of any error\r\n return 'chart';\r\n }\r\n}\r\n\r\n/**\r\n * Fixes the outfile based on provided type.\r\n *\r\n * @function fixOutfile\r\n *\r\n * @param {string} type - The original export type.\r\n * @param {string} outfile - The file path or name.\r\n *\r\n * @returns {string} The corrected outfile.\r\n */\r\nexport function fixOutfile(type, outfile) {\r\n // Get the file name from the `outfile` option\r\n const fileName = getAbsolutePath(outfile || 'chart')\r\n .split('.')\r\n .shift();\r\n\r\n // Return a correct outfile\r\n return `${fileName}.${type}`;\r\n}\r\n\r\n/**\r\n * Fixes the export type based on MIME types and file extensions.\r\n *\r\n * @function fixType\r\n *\r\n * @param {string} type - The original export type.\r\n * @param {string} [outfile=null] - The file path or name. The default value\r\n * is `null`.\r\n *\r\n * @returns {string} The corrected export type.\r\n */\r\nexport function fixType(type, outfile = null) {\r\n // MIME types\r\n const mimeTypes = {\r\n 'image/png': 'png',\r\n 'image/jpeg': 'jpeg',\r\n 'application/pdf': 'pdf',\r\n 'image/svg+xml': 'svg'\r\n };\r\n\r\n // Get formats\r\n const formats = Object.values(mimeTypes);\r\n\r\n // Check if type and outfile's extensions are the same\r\n if (outfile) {\r\n const outType = outfile.split('.').pop();\r\n\r\n // Support the JPG type\r\n if (outType === 'jpg') {\r\n type = 'jpeg';\r\n } else if (formats.includes(outType) && type !== outType) {\r\n type = outType;\r\n }\r\n }\r\n\r\n // Return a correct type\r\n return mimeTypes[type] || formats.find((t) => t === type) || 'png';\r\n}\r\n\r\n/**\r\n * Checks if the given path is relative or absolute and returns the corrected,\r\n * absolute path.\r\n *\r\n * @function isAbsolutePath\r\n *\r\n * @param {string} path - The path to be checked on.\r\n *\r\n * @returns {string} The absolute path.\r\n */\r\nexport function getAbsolutePath(path) {\r\n return isAbsolute(path) ? path : join(__dirname, path);\r\n}\r\n\r\n/**\r\n * Converts input data to a Base64 string based on the export type.\r\n *\r\n * @function getBase64\r\n *\r\n * @param {string} input - The input to be transformed to Base64 format.\r\n * @param {string} type - The original export type.\r\n *\r\n * @returns {string} The Base64 string representation of the input.\r\n */\r\nexport function getBase64(input, type) {\r\n // For pdf and svg types the input must be transformed to Base64 from a buffer\r\n if (type === 'pdf' || type == 'svg') {\r\n return Buffer.from(input, 'utf8').toString('base64');\r\n }\r\n\r\n // For png and jpeg input is already a Base64 string\r\n return input;\r\n}\r\n\r\n/**\r\n * Returns stringified date without the GMT text information.\r\n *\r\n * @function getNewDate\r\n */\r\nexport function getNewDate() {\r\n // Get rid of the GMT text information\r\n return new Date().toString().split('(')[0].trim();\r\n}\r\n\r\n/**\r\n * Returns the stored time value in milliseconds.\r\n *\r\n * @function getNewDateTime\r\n */\r\nexport function getNewDateTime() {\r\n return new Date().getTime();\r\n}\r\n\r\n/**\r\n * Checks if the given item is an object.\r\n *\r\n * @function isObject\r\n *\r\n * @param {unknown} item - The item to be checked.\r\n *\r\n * @returns {boolean} True if the item is an object, false otherwise.\r\n */\r\nexport function isObject(item) {\r\n return Object.prototype.toString.call(item) === '[object Object]';\r\n}\r\n\r\n/**\r\n * Checks if the given object is empty.\r\n *\r\n * @function isObjectEmpty\r\n *\r\n * @param {Object} item - The object to be checked.\r\n *\r\n * @returns {boolean} True if the object is empty, false otherwise.\r\n */\r\nexport function isObjectEmpty(item) {\r\n return (\r\n typeof item === 'object' &&\r\n !Array.isArray(item) &&\r\n item !== null &&\r\n Object.keys(item).length === 0\r\n );\r\n}\r\n\r\n/**\r\n * Checks if a private IP range URL is found in the given string.\r\n *\r\n * @function isPrivateRangeUrlFound\r\n *\r\n * @param {string} item - The string to be checked for a private IP range URL.\r\n *\r\n * @returns {boolean} True if a private IP range URL is found, false otherwise.\r\n */\r\nexport function isPrivateRangeUrlFound(item) {\r\n const regexPatterns = [\r\n /xlink:href=\"(?:http:\\/\\/|https:\\/\\/)?localhost\\b/,\r\n /xlink:href=\"(?:http:\\/\\/|https:\\/\\/)?10\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\b/,\r\n /xlink:href=\"(?:http:\\/\\/|https:\\/\\/)?127\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\b/,\r\n /xlink:href=\"(?:http:\\/\\/|https:\\/\\/)?172\\.(1[6-9]|2[0-9]|3[0-1])\\.\\d{1,3}\\.\\d{1,3}\\b/,\r\n /xlink:href=\"(?:http:\\/\\/|https:\\/\\/)?192\\.168\\.\\d{1,3}\\.\\d{1,3}\\b/\r\n ];\r\n\r\n return regexPatterns.some((pattern) => pattern.test(item));\r\n}\r\n\r\n/**\r\n * Utility to measure elapsed time using the Node.js `process.hrtime()` method.\r\n *\r\n * @function measureTime\r\n *\r\n * @returns {Function} A function to calculate the elapsed time in milliseconds.\r\n */\r\nexport function measureTime() {\r\n const start = process.hrtime.bigint();\r\n return () => Number(process.hrtime.bigint() - start) / 1000000;\r\n}\r\n\r\n/**\r\n * Rounds a number to the specified precision.\r\n *\r\n * @function roundNumber\r\n *\r\n * @param {number} value - The number to be rounded.\r\n * @param {number} precision - The number of decimal places to round to.\r\n *\r\n * @returns {number} The rounded number.\r\n */\r\nexport function roundNumber(value, precision = 1) {\r\n const multiplier = Math.pow(10, precision || 0);\r\n return Math.round(+value * multiplier) / multiplier;\r\n}\r\n\r\n/**\r\n * Converts a value to a boolean.\r\n *\r\n * @function toBoolean\r\n *\r\n * @param {unknown} item - The value to be converted to a boolean.\r\n *\r\n * @returns {boolean} The boolean representation of the input value.\r\n */\r\nexport function toBoolean(item) {\r\n return ['false', 'undefined', 'null', 'NaN', '0', ''].includes(item)\r\n ? false\r\n : !!item;\r\n}\r\n\r\n/**\r\n * Wraps custom code to execute it safely.\r\n *\r\n * @function wrapAround\r\n *\r\n * @param {string} customCode - The custom code to be wrapped.\r\n * @param {boolean} allowFileResources - Flag to allow loading code from a file.\r\n * @param {boolean} [isCallback=false] - Flag that indicates the returned code\r\n * must be in a callback format.\r\n *\r\n * @returns {(string|null)} The wrapped custom code or null if wrapping fails.\r\n */\r\nexport function wrapAround(customCode, allowFileResources, isCallback = false) {\r\n if (customCode && typeof customCode === 'string') {\r\n customCode = customCode.trim();\r\n\r\n if (customCode.endsWith('.js')) {\r\n // Load a file if the file resources are allowed\r\n return allowFileResources\r\n ? wrapAround(\r\n readFileSync(getAbsolutePath(customCode), 'utf8'),\r\n allowFileResources,\r\n isCallback\r\n )\r\n : null;\r\n } else if (\r\n !isCallback &&\r\n (customCode.startsWith('function()') ||\r\n customCode.startsWith('function ()') ||\r\n customCode.startsWith('()=>') ||\r\n customCode.startsWith('() =>'))\r\n ) {\r\n // Treat a function as a self-invoking expression\r\n return `(${customCode})()`;\r\n }\r\n\r\n // Or return as a stringified code\r\n return customCode.replace(/;$/, '');\r\n }\r\n}\r\n\r\nexport default {\r\n __dirname,\r\n clearText,\r\n deepCopy,\r\n expBackoff,\r\n fixConstr,\r\n fixOutfile,\r\n fixType,\r\n getAbsolutePath,\r\n getBase64,\r\n getNewDate,\r\n getNewDateTime,\r\n isObject,\r\n isObjectEmpty,\r\n isPrivateRangeUrlFound,\r\n measureTime,\r\n roundNumber,\r\n toBoolean,\r\n wrapAround\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * @overview A module for managing logging functionality with customizable\r\n * log levels, console and file logging options, and error handling support.\r\n * The module also ensures that file-based logs are stored in a structured\r\n * directory, creating the necessary paths automatically if they do not exist.\r\n */\r\n\r\nimport { appendFile, existsSync, mkdirSync } from 'fs';\r\nimport { join } from 'path';\r\n\r\nimport { getAbsolutePath, getNewDate } from './utils.js';\r\n\r\n// The available colors\r\nconst colors = ['red', 'yellow', 'blue', 'gray', 'green'];\r\n\r\n// The default logging config\r\nconst logging = {\r\n // Flags for logging status\r\n toConsole: true,\r\n toFile: false,\r\n pathCreated: false,\r\n // Full path to the log file\r\n pathToLog: '',\r\n // Log levels\r\n levelsDesc: [\r\n {\r\n title: 'error',\r\n color: colors[0]\r\n },\r\n {\r\n title: 'warning',\r\n color: colors[1]\r\n },\r\n {\r\n title: 'notice',\r\n color: colors[2]\r\n },\r\n {\r\n title: 'verbose',\r\n color: colors[3]\r\n },\r\n {\r\n title: 'benchmark',\r\n color: colors[4]\r\n }\r\n ]\r\n};\r\n\r\n/**\r\n * Logs a message with a specified log level. Accepts a variable number\r\n * of arguments. The arguments after the `level` are passed to `console.log`\r\n * and/or used to construct and append messages to a log file.\r\n *\r\n * @function log\r\n *\r\n * @param {...unknown} args - An array of arguments where the first is the log\r\n * level and the remaining are strings used to build the log message.\r\n *\r\n * @returns {void} Exits the function execution if attempting to log at a level\r\n * higher than allowed.\r\n */\r\nexport function log(...args) {\r\n const [newLevel, ...texts] = args;\r\n\r\n // Current logging options\r\n const { levelsDesc, level } = logging;\r\n\r\n // Check if the log level is within a correct range or is it a benchmark log\r\n if (\r\n newLevel !== 5 &&\r\n (newLevel === 0 || newLevel > level || level > levelsDesc.length)\r\n ) {\r\n return;\r\n }\r\n\r\n // Create a message's prefix\r\n const prefix = `${getNewDate()} [${levelsDesc[newLevel - 1].title}] -`;\r\n\r\n // Log to file\r\n if (logging.toFile) {\r\n _logToFile(texts, prefix);\r\n }\r\n\r\n // Log to console\r\n if (logging.toConsole) {\r\n console.log.apply(\r\n undefined,\r\n [prefix.toString()[logging.levelsDesc[newLevel - 1].color]].concat(texts)\r\n );\r\n }\r\n}\r\n\r\n/**\r\n * Logs an error message along with its stack trace. Optionally, a custom message\r\n * can be provided.\r\n *\r\n * @function logWithStack\r\n *\r\n * @param {number} newLevel - The log level.\r\n * @param {Error} error - The error object containing the stack trace.\r\n * @param {string} customMessage - An optional custom message to be included\r\n * in the log alongside the error.\r\n *\r\n * @returns {void} Exits the function execution if attempting to log at a level\r\n * higher than allowed.\r\n */\r\nexport function logWithStack(newLevel, error, customMessage) {\r\n // Get the main message\r\n const mainMessage = customMessage || (error && error.message) || '';\r\n\r\n // Current logging options\r\n const { level, levelsDesc } = logging;\r\n\r\n // Check if the log level is within a correct range\r\n if (newLevel === 0 || newLevel > level || level > levelsDesc.length) {\r\n return;\r\n }\r\n\r\n // Create a message's prefix\r\n const prefix = `${getNewDate()} [${levelsDesc[newLevel - 1].title}] -`;\r\n\r\n // Add the whole stack message\r\n const stackMessage = error && error.stack;\r\n\r\n // Combine custom message or error message with error stack message, if exists\r\n const texts = [mainMessage];\r\n if (stackMessage) {\r\n texts.push('\\n', stackMessage);\r\n }\r\n\r\n // Log to file\r\n if (logging.toFile) {\r\n _logToFile(texts, prefix);\r\n }\r\n\r\n // Log to console\r\n if (logging.toConsole) {\r\n console.log.apply(\r\n undefined,\r\n [prefix.toString()[logging.levelsDesc[newLevel - 1].color]].concat([\r\n texts.shift()[colors[newLevel - 1]],\r\n ...texts\r\n ])\r\n );\r\n }\r\n}\r\n\r\n/**\r\n * Logs an error message about Zod issues with the validation. Optionally,\r\n * a custom message can be provided.\r\n *\r\n * @function logZodIssues\r\n *\r\n * @param {number} newLevel - The log level.\r\n * @param {Error[]} issues - The array of Zod issues.\r\n * @param {string} customMessage - An optional custom message to be logged\r\n * along with the error.\r\n */\r\nexport function logZodIssues(newLevel, issues = [], customMessage) {\r\n logWithStack(\r\n newLevel,\r\n null,\r\n [\r\n `${customMessage} - the following Zod issues occured:`,\r\n ...issues.map((issue) => `- ${issue.message}`)\r\n ].join('\\n')\r\n );\r\n}\r\n\r\n/**\r\n * Initializes logging with the specified logging configuration.\r\n *\r\n * @function initLogging\r\n *\r\n * @param {Object} loggingOptions - The configuration object containing\r\n * `logging` options.\r\n */\r\nexport function initLogging(loggingOptions) {\r\n // Get options from the `loggingOptions` object\r\n const { level, dest, file, toConsole, toFile } = loggingOptions;\r\n\r\n // Reset flags to the default values\r\n logging.pathCreated = false;\r\n logging.pathToLog = '';\r\n\r\n // Set the logging level\r\n setLogLevel(level);\r\n\r\n // Set the console logging\r\n enableConsoleLogging(toConsole);\r\n\r\n // Set the file logging\r\n enableFileLogging(dest, file, toFile);\r\n}\r\n\r\n/**\r\n * Sets the log level to the specified value. Log levels are (`0` = no logging,\r\n * `1` = error, `2` = warning, `3` = notice, `4` = verbose, or `5` = benchmark).\r\n *\r\n * @function setLogLevel\r\n *\r\n * @param {number} level - The log level to be set.\r\n */\r\nexport function setLogLevel(level) {\r\n if (\r\n Number.isInteger(level) &&\r\n level >= 0 &&\r\n level <= logging.levelsDesc.length\r\n ) {\r\n // Update the module logging's `level` option\r\n logging.level = level;\r\n }\r\n}\r\n\r\n/**\r\n * Enables console logging.\r\n *\r\n * @function enableConsoleLogging\r\n *\r\n * @param {boolean} toConsole - The flag for setting the logging to the console.\r\n */\r\nexport function enableConsoleLogging(toConsole) {\r\n // Update the module logging's `toConsole` option\r\n logging.toConsole = !!toConsole;\r\n}\r\n\r\n/**\r\n * Enables file logging with the specified destination and log file name.\r\n *\r\n * @function enableFileLogging\r\n *\r\n * @param {string} dest - The destination path where the log file should\r\n * be saved.\r\n * @param {string} file - The name of the log file.\r\n * @param {boolean} toFile - A flag indicating whether logging should\r\n * be directed to a file.\r\n */\r\nexport function enableFileLogging(dest, file, toFile) {\r\n // Update the module logging's `toFile` option\r\n logging.toFile = !!toFile;\r\n\r\n // Set the `dest` and `file` options only if the file logging is enabled\r\n if (logging.toFile) {\r\n logging.dest = dest || '';\r\n logging.file = file || '';\r\n }\r\n}\r\n\r\n/**\r\n * Logs the provided texts to a file, if file logging is enabled. It creates\r\n * the necessary directory structure if not already created and appends\r\n * the content, including an optional prefix, to the specified log file.\r\n *\r\n * @function _logToFile\r\n *\r\n * @param {Array.} texts - An array of texts to be logged.\r\n * @param {string} prefix - An optional prefix to be added to each log entry.\r\n */\r\nfunction _logToFile(texts, prefix) {\r\n if (!logging.pathCreated) {\r\n // Create if does not exist\r\n !existsSync(getAbsolutePath(logging.dest)) &&\r\n mkdirSync(getAbsolutePath(logging.dest));\r\n\r\n // Create the full path\r\n logging.pathToLog = getAbsolutePath(join(logging.dest, logging.file));\r\n\r\n // We now assume the path is available, e.g. it's the responsibility\r\n // of the user to create the path with the correct access rights.\r\n logging.pathCreated = true;\r\n }\r\n\r\n // Add the content to a file\r\n appendFile(\r\n logging.pathToLog,\r\n [prefix].concat(texts).join(' ') + '\\n',\r\n (error) => {\r\n if (error && logging.toFile && logging.pathCreated) {\r\n logging.toFile = false;\r\n logging.pathCreated = false;\r\n logWithStack(2, error, `[logger] Unable to write to log file.`);\r\n }\r\n }\r\n );\r\n}\r\n\r\nexport default {\r\n log,\r\n logWithStack,\r\n logZodIssues,\r\n initLogging,\r\n setLogLevel,\r\n enableConsoleLogging,\r\n enableFileLogging\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * @overview Configuration management module for the Highcharts Export Server.\r\n * Provides default configurations that support environment variables, CLI\r\n * arguments, and interactive prompts for customization of options and features.\r\n * Additionally, it maps legacy options to modern structures, generates nested\r\n * argument mappings, and displays CLI usage information.\r\n */\r\n\r\n/**\r\n * The configuration object containing all available options, organized\r\n * by sections.\r\n *\r\n * This object includes:\r\n * - Default values for each option\r\n * - Data types for validation\r\n * - Names of corresponding environment variables\r\n * - Descriptions of each property\r\n * - Information used for prompts in interactive configuration\r\n * - [Optional] Corresponding CLI argument names for CLI usage\r\n * - [Optional] Legacy names from the previous PhantomJS-based server\r\n */\r\nexport const defaultConfig = {\r\n puppeteer: {\r\n args: {\r\n value: [\r\n '--allow-running-insecure-content',\r\n '--ash-no-nudges',\r\n '--autoplay-policy=user-gesture-required',\r\n '--block-new-web-contents',\r\n '--disable-accelerated-2d-canvas',\r\n '--disable-background-networking',\r\n '--disable-background-timer-throttling',\r\n '--disable-backgrounding-occluded-windows',\r\n '--disable-breakpad',\r\n '--disable-checker-imaging',\r\n '--disable-client-side-phishing-detection',\r\n '--disable-component-extensions-with-background-pages',\r\n '--disable-component-update',\r\n '--disable-default-apps',\r\n '--disable-dev-shm-usage',\r\n '--disable-domain-reliability',\r\n '--disable-extensions',\r\n '--disable-features=CalculateNativeWinOcclusion,InterestFeedContentSuggestions,WebOTP',\r\n '--disable-hang-monitor',\r\n '--disable-ipc-flooding-protection',\r\n '--disable-logging',\r\n '--disable-notifications',\r\n '--disable-offer-store-unmasked-wallet-cards',\r\n '--disable-popup-blocking',\r\n '--disable-print-preview',\r\n '--disable-prompt-on-repost',\r\n '--disable-renderer-backgrounding',\r\n '--disable-search-engine-choice-screen',\r\n '--disable-session-crashed-bubble',\r\n '--disable-setuid-sandbox',\r\n '--disable-site-isolation-trials',\r\n '--disable-speech-api',\r\n '--disable-sync',\r\n '--enable-unsafe-webgpu',\r\n '--hide-crash-restore-bubble',\r\n '--hide-scrollbars',\r\n '--metrics-recording-only',\r\n '--mute-audio',\r\n '--no-default-browser-check',\r\n '--no-first-run',\r\n '--no-pings',\r\n '--no-sandbox',\r\n '--no-startup-window',\r\n '--no-zygote',\r\n '--password-store=basic',\r\n '--process-per-tab',\r\n '--use-mock-keychain'\r\n ],\r\n types: ['string[]'],\r\n envLink: 'PUPPETEER_ARGS',\r\n cliName: 'puppeteerArgs',\r\n description: 'Array of Puppeteer arguments',\r\n promptOptions: {\r\n type: 'list',\r\n separator: ';'\r\n }\r\n }\r\n },\r\n highcharts: {\r\n version: {\r\n value: 'latest',\r\n types: ['string'],\r\n envLink: 'HIGHCHARTS_VERSION',\r\n description: 'Highcharts version',\r\n promptOptions: {\r\n type: 'text'\r\n }\r\n },\r\n cdnUrl: {\r\n value: 'https://code.highcharts.com',\r\n types: ['string'],\r\n envLink: 'HIGHCHARTS_CDN_URL',\r\n description: 'CDN URL for Highcharts scripts',\r\n promptOptions: {\r\n type: 'text'\r\n }\r\n },\r\n forceFetch: {\r\n value: false,\r\n types: ['boolean'],\r\n envLink: 'HIGHCHARTS_FORCE_FETCH',\r\n description: 'Flag to refetch scripts after each server rerun',\r\n promptOptions: {\r\n type: 'toggle'\r\n }\r\n },\r\n cachePath: {\r\n value: '.cache',\r\n types: ['string'],\r\n envLink: 'HIGHCHARTS_CACHE_PATH',\r\n description: 'Directory path for cached Highcharts scripts',\r\n promptOptions: {\r\n type: 'text'\r\n }\r\n },\r\n coreScripts: {\r\n value: ['highcharts', 'highcharts-more', 'highcharts-3d'],\r\n types: ['string[]'],\r\n envLink: 'HIGHCHARTS_CORE_SCRIPTS',\r\n description: 'Highcharts core scripts to fetch',\r\n promptOptions: {\r\n type: 'multiselect',\r\n instructions: 'Space: Select specific, A: Select all, Enter: Confirm'\r\n }\r\n },\r\n moduleScripts: {\r\n value: [\r\n 'stock',\r\n 'map',\r\n 'gantt',\r\n 'exporting',\r\n 'parallel-coordinates',\r\n 'accessibility',\r\n // 'annotations-advanced',\r\n 'boost-canvas',\r\n 'boost',\r\n 'data',\r\n 'data-tools',\r\n 'draggable-points',\r\n 'static-scale',\r\n 'broken-axis',\r\n 'heatmap',\r\n 'tilemap',\r\n 'tiledwebmap',\r\n 'timeline',\r\n 'treemap',\r\n 'treegraph',\r\n 'item-series',\r\n 'drilldown',\r\n 'histogram-bellcurve',\r\n 'bullet',\r\n 'funnel',\r\n 'funnel3d',\r\n 'geoheatmap',\r\n 'pyramid3d',\r\n 'networkgraph',\r\n 'overlapping-datalabels',\r\n 'pareto',\r\n 'pattern-fill',\r\n 'pictorial',\r\n 'price-indicator',\r\n 'sankey',\r\n 'arc-diagram',\r\n 'dependency-wheel',\r\n 'series-label',\r\n 'series-on-point',\r\n 'solid-gauge',\r\n 'sonification',\r\n // 'stock-tools',\r\n 'streamgraph',\r\n 'sunburst',\r\n 'variable-pie',\r\n 'variwide',\r\n 'vector',\r\n 'venn',\r\n 'windbarb',\r\n 'wordcloud',\r\n 'xrange',\r\n 'no-data-to-display',\r\n 'drag-panes',\r\n 'debugger',\r\n 'dumbbell',\r\n 'lollipop',\r\n 'cylinder',\r\n 'organization',\r\n 'dotplot',\r\n 'marker-clusters',\r\n 'hollowcandlestick',\r\n 'heikinashi',\r\n 'flowmap',\r\n 'export-data',\r\n 'navigator',\r\n 'textpath'\r\n ],\r\n types: ['string[]'],\r\n envLink: 'HIGHCHARTS_MODULE_SCRIPTS',\r\n description: 'Highcharts module scripts to fetch',\r\n promptOptions: {\r\n type: 'multiselect',\r\n instructions: 'Space: Select specific, A: Select all, Enter: Confirm'\r\n }\r\n },\r\n indicatorScripts: {\r\n value: ['indicators-all'],\r\n types: ['string[]'],\r\n envLink: 'HIGHCHARTS_INDICATOR_SCRIPTS',\r\n description: 'Highcharts indicator scripts to fetch',\r\n promptOptions: {\r\n type: 'multiselect',\r\n instructions: 'Space: Select specific, A: Select all, Enter: Confirm'\r\n }\r\n },\r\n customScripts: {\r\n value: [\r\n 'https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.30.1/moment.min.js',\r\n 'https://cdnjs.cloudflare.com/ajax/libs/moment-timezone/0.5.45/moment-timezone-with-data.min.js'\r\n ],\r\n types: ['string[]'],\r\n envLink: 'HIGHCHARTS_CUSTOM_SCRIPTS',\r\n description: 'Additional custom scripts or dependencies to fetch',\r\n promptOptions: {\r\n type: 'list',\r\n separator: ';'\r\n }\r\n }\r\n },\r\n export: {\r\n infile: {\r\n value: null,\r\n types: ['string', 'null'],\r\n envLink: 'EXPORT_INFILE',\r\n description:\r\n 'Input filename with type, formatted correctly as JSON or SVG',\r\n promptOptions: {\r\n type: 'text'\r\n }\r\n },\r\n instr: {\r\n value: null,\r\n types: ['Object', 'string', 'null'],\r\n envLink: 'EXPORT_INSTR',\r\n description:\r\n 'Overrides the `infile` with JSON, stringified JSON, or SVG input',\r\n promptOptions: {\r\n type: 'text'\r\n }\r\n },\r\n options: {\r\n value: null,\r\n types: ['Object', 'string', 'null'],\r\n envLink: 'EXPORT_OPTIONS',\r\n description: 'Alias for the `instr` option',\r\n promptOptions: {\r\n type: 'text'\r\n }\r\n },\r\n svg: {\r\n value: null,\r\n types: ['string', 'null'],\r\n envLink: 'EXPORT_SVG',\r\n description: 'SVG string representation of the chart to render',\r\n promptOptions: {\r\n type: 'text'\r\n }\r\n },\r\n batch: {\r\n value: null,\r\n types: ['string', 'null'],\r\n envLink: 'EXPORT_BATCH',\r\n description:\r\n 'Batch job string with input/output pairs: \"in=out;in=out;...\"',\r\n promptOptions: {\r\n type: 'text'\r\n }\r\n },\r\n outfile: {\r\n value: null,\r\n types: ['string', 'null'],\r\n envLink: 'EXPORT_OUTFILE',\r\n description:\r\n 'Output filename with type. Can be jpeg, png, pdf, or svg and ignores `type` option',\r\n promptOptions: {\r\n type: 'text'\r\n }\r\n },\r\n type: {\r\n value: 'png',\r\n types: ['string'],\r\n envLink: 'EXPORT_TYPE',\r\n description: 'File export format. Can be jpeg, png, pdf, or svg',\r\n promptOptions: {\r\n type: 'select',\r\n hint: 'Default: png',\r\n choices: ['png', 'jpeg', 'pdf', 'svg']\r\n }\r\n },\r\n constr: {\r\n value: 'chart',\r\n types: ['string'],\r\n envLink: 'EXPORT_CONSTR',\r\n description:\r\n 'Chart constructor. Can be chart, stockChart, mapChart, or ganttChart',\r\n promptOptions: {\r\n type: 'select',\r\n hint: 'Default: chart',\r\n choices: ['chart', 'stockChart', 'mapChart', 'ganttChart']\r\n }\r\n },\r\n b64: {\r\n value: false,\r\n types: ['boolean'],\r\n envLink: 'EXPORT_B64',\r\n description:\r\n 'Whether or not to the chart should be received in Base64 format instead of binary',\r\n promptOptions: {\r\n type: 'toggle'\r\n }\r\n },\r\n noDownload: {\r\n value: false,\r\n types: ['boolean'],\r\n envLink: 'EXPORT_NO_DOWNLOAD',\r\n description:\r\n 'Whether or not to include or exclude attachment headers in the response',\r\n promptOptions: {\r\n type: 'toggle'\r\n }\r\n },\r\n height: {\r\n value: null,\r\n types: ['number', 'null'],\r\n envLink: 'EXPORT_HEIGHT',\r\n description: 'Height of the exported chart, overrides chart settings',\r\n promptOptions: {\r\n type: 'number'\r\n }\r\n },\r\n width: {\r\n value: null,\r\n types: ['number', 'null'],\r\n envLink: 'EXPORT_WIDTH',\r\n description: 'Width of the exported chart, overrides chart settings',\r\n promptOptions: {\r\n type: 'number'\r\n }\r\n },\r\n scale: {\r\n value: null,\r\n types: ['number', 'null'],\r\n envLink: 'EXPORT_SCALE',\r\n description:\r\n 'Scale of the exported chart, overrides chart settings. Ranges from 0.1 to 5.0',\r\n promptOptions: {\r\n type: 'number'\r\n }\r\n },\r\n defaultHeight: {\r\n value: 400,\r\n types: ['number'],\r\n envLink: 'EXPORT_DEFAULT_HEIGHT',\r\n description: 'Default height of the exported chart if not set',\r\n promptOptions: {\r\n type: 'number'\r\n }\r\n },\r\n defaultWidth: {\r\n value: 600,\r\n types: ['number'],\r\n envLink: 'EXPORT_DEFAULT_WIDTH',\r\n description: 'Default width of the exported chart if not set',\r\n promptOptions: {\r\n type: 'number'\r\n }\r\n },\r\n defaultScale: {\r\n value: 1,\r\n types: ['number'],\r\n envLink: 'EXPORT_DEFAULT_SCALE',\r\n description:\r\n 'Default scale of the exported chart if not set. Ranges from 0.1 to 5.0',\r\n promptOptions: {\r\n type: 'number',\r\n min: 0.1,\r\n max: 5\r\n }\r\n },\r\n globalOptions: {\r\n value: null,\r\n types: ['Object', 'string', 'null'],\r\n envLink: 'EXPORT_GLOBAL_OPTIONS',\r\n description:\r\n 'JSON, stringified JSON or filename with global options for Highcharts.setOptions',\r\n promptOptions: {\r\n type: 'text'\r\n }\r\n },\r\n themeOptions: {\r\n value: null,\r\n types: ['Object', 'string', 'null'],\r\n envLink: 'EXPORT_THEME_OPTIONS',\r\n description:\r\n 'JSON, stringified JSON or filename with theme options for Highcharts.setOptions',\r\n promptOptions: {\r\n type: 'text'\r\n }\r\n },\r\n rasterizationTimeout: {\r\n value: 1500,\r\n types: ['number'],\r\n envLink: 'EXPORT_RASTERIZATION_TIMEOUT',\r\n description: 'Milliseconds to wait for webpage rendering',\r\n promptOptions: {\r\n type: 'number'\r\n }\r\n }\r\n },\r\n customLogic: {\r\n allowCodeExecution: {\r\n value: false,\r\n types: ['boolean'],\r\n envLink: 'CUSTOM_LOGIC_ALLOW_CODE_EXECUTION',\r\n description:\r\n 'Allows or disallows execution of arbitrary code during exporting',\r\n promptOptions: {\r\n type: 'toggle'\r\n }\r\n },\r\n allowFileResources: {\r\n value: false,\r\n types: ['boolean'],\r\n envLink: 'CUSTOM_LOGIC_ALLOW_FILE_RESOURCES',\r\n description:\r\n 'Allows or disallows injection of filesystem resources (disabled in server mode)',\r\n promptOptions: {\r\n type: 'toggle'\r\n }\r\n },\r\n customCode: {\r\n value: null,\r\n types: ['string', 'null'],\r\n envLink: 'CUSTOM_LOGIC_CUSTOM_CODE',\r\n description:\r\n 'Custom code to execute before chart initialization. Can be a function, code wrapped in a function, or a .js filename',\r\n promptOptions: {\r\n type: 'text'\r\n }\r\n },\r\n callback: {\r\n value: null,\r\n types: ['string', 'null'],\r\n envLink: 'CUSTOM_LOGIC_CALLBACK',\r\n description:\r\n 'JavaScript code to run during construction. Can be a function or a .js filename',\r\n promptOptions: {\r\n type: 'text'\r\n }\r\n },\r\n resources: {\r\n value: null,\r\n types: ['Object', 'string', 'null'],\r\n envLink: 'CUSTOM_LOGIC_RESOURCES',\r\n description:\r\n 'Additional resources as JSON, stringified JSON, or filename, containing files, js, and css sections',\r\n promptOptions: {\r\n type: 'text'\r\n }\r\n },\r\n loadConfig: {\r\n value: null,\r\n types: ['string', 'null'],\r\n envLink: 'CUSTOM_LOGIC_LOAD_CONFIG',\r\n legacyName: 'fromFile',\r\n description: 'File with a pre-defined configuration to use',\r\n promptOptions: {\r\n type: 'text'\r\n }\r\n },\r\n createConfig: {\r\n value: null,\r\n types: ['string', 'null'],\r\n envLink: 'CUSTOM_LOGIC_CREATE_CONFIG',\r\n description:\r\n 'Prompt-based option setting, saved to a provided config file',\r\n promptOptions: {\r\n type: 'text'\r\n }\r\n }\r\n },\r\n server: {\r\n enable: {\r\n value: false,\r\n types: ['boolean'],\r\n envLink: 'SERVER_ENABLE',\r\n cliName: 'enableServer',\r\n description: 'Starts the server when true',\r\n promptOptions: {\r\n type: 'toggle'\r\n }\r\n },\r\n host: {\r\n value: '0.0.0.0',\r\n types: ['string'],\r\n envLink: 'SERVER_HOST',\r\n description: 'Hostname of the server',\r\n promptOptions: {\r\n type: 'text'\r\n }\r\n },\r\n port: {\r\n value: 7801,\r\n types: ['number'],\r\n envLink: 'SERVER_PORT',\r\n description: 'Port number for the server',\r\n promptOptions: {\r\n type: 'number'\r\n }\r\n },\r\n uploadLimit: {\r\n value: 3,\r\n types: ['number'],\r\n envLink: 'SERVER_UPLOAD_LIMIT',\r\n description: 'Maximum request body size in MB',\r\n promptOptions: {\r\n type: 'number'\r\n }\r\n },\r\n benchmarking: {\r\n value: false,\r\n types: ['boolean'],\r\n envLink: 'SERVER_BENCHMARKING',\r\n cliName: 'serverBenchmarking',\r\n description:\r\n 'Displays or not action durations in milliseconds during server requests',\r\n promptOptions: {\r\n type: 'toggle'\r\n }\r\n },\r\n proxy: {\r\n host: {\r\n value: null,\r\n types: ['string', 'null'],\r\n envLink: 'SERVER_PROXY_HOST',\r\n cliName: 'proxyHost',\r\n description: 'Host of the proxy server, if applicable',\r\n promptOptions: {\r\n type: 'text'\r\n }\r\n },\r\n port: {\r\n value: null,\r\n types: ['number', 'null'],\r\n envLink: 'SERVER_PROXY_PORT',\r\n cliName: 'proxyPort',\r\n description: 'Port of the proxy server, if applicable',\r\n promptOptions: {\r\n type: 'number'\r\n }\r\n },\r\n timeout: {\r\n value: 5000,\r\n types: ['number'],\r\n envLink: 'SERVER_PROXY_TIMEOUT',\r\n cliName: 'proxyTimeout',\r\n description:\r\n 'Timeout in milliseconds for the proxy server, if applicable',\r\n promptOptions: {\r\n type: 'number'\r\n }\r\n }\r\n },\r\n rateLimiting: {\r\n enable: {\r\n value: false,\r\n types: ['boolean'],\r\n envLink: 'SERVER_RATE_LIMITING_ENABLE',\r\n cliName: 'enableRateLimiting',\r\n description: 'Enables or disables rate limiting on the server',\r\n promptOptions: {\r\n type: 'toggle'\r\n }\r\n },\r\n maxRequests: {\r\n value: 10,\r\n types: ['number'],\r\n envLink: 'SERVER_RATE_LIMITING_MAX_REQUESTS',\r\n legacyName: 'rateLimit',\r\n description: 'Maximum number of requests allowed per minute',\r\n promptOptions: {\r\n type: 'number'\r\n }\r\n },\r\n window: {\r\n value: 1,\r\n types: ['number'],\r\n envLink: 'SERVER_RATE_LIMITING_WINDOW',\r\n description: 'Time window in minutes for rate limiting',\r\n promptOptions: {\r\n type: 'number'\r\n }\r\n },\r\n delay: {\r\n value: 0,\r\n types: ['number'],\r\n envLink: 'SERVER_RATE_LIMITING_DELAY',\r\n description:\r\n 'Delay duration between successive requests before reaching the limit',\r\n promptOptions: {\r\n type: 'number'\r\n }\r\n },\r\n trustProxy: {\r\n value: false,\r\n types: ['boolean'],\r\n envLink: 'SERVER_RATE_LIMITING_TRUST_PROXY',\r\n description: 'Set to true if the server is behind a load balancer',\r\n promptOptions: {\r\n type: 'toggle'\r\n }\r\n },\r\n skipKey: {\r\n value: null,\r\n types: ['string', 'null'],\r\n envLink: 'SERVER_RATE_LIMITING_SKIP_KEY',\r\n description: 'Key to bypass the rate limiter, used with `skipToken`',\r\n promptOptions: {\r\n type: 'text'\r\n }\r\n },\r\n skipToken: {\r\n value: null,\r\n types: ['string', 'null'],\r\n envLink: 'SERVER_RATE_LIMITING_SKIP_TOKEN',\r\n description: 'Token to bypass the rate limiter, used with `skipKey`',\r\n promptOptions: {\r\n type: 'text'\r\n }\r\n }\r\n },\r\n ssl: {\r\n enable: {\r\n value: false,\r\n types: ['boolean'],\r\n envLink: 'SERVER_SSL_ENABLE',\r\n cliName: 'enableSsl',\r\n description: 'Enables or disables SSL protocol',\r\n promptOptions: {\r\n type: 'toggle'\r\n }\r\n },\r\n force: {\r\n value: false,\r\n types: ['boolean'],\r\n envLink: 'SERVER_SSL_FORCE',\r\n cliName: 'sslForce',\r\n legacyName: 'sslOnly',\r\n description: 'Forces the server to use HTTPS only when true',\r\n promptOptions: {\r\n type: 'toggle'\r\n }\r\n },\r\n port: {\r\n value: 443,\r\n types: ['number'],\r\n envLink: 'SERVER_SSL_PORT',\r\n cliName: 'sslPort',\r\n description: 'Port for the SSL server',\r\n promptOptions: {\r\n type: 'number'\r\n }\r\n },\r\n certPath: {\r\n value: null,\r\n types: ['string', 'null'],\r\n envLink: 'SERVER_SSL_CERT_PATH',\r\n cliName: 'sslCertPath',\r\n legacyName: 'sslPath',\r\n description: 'Path to the SSL certificate/key file',\r\n promptOptions: {\r\n type: 'text'\r\n }\r\n }\r\n }\r\n },\r\n pool: {\r\n minWorkers: {\r\n value: 4,\r\n types: ['number'],\r\n envLink: 'POOL_MIN_WORKERS',\r\n description: 'Minimum and initial number of pool workers to spawn',\r\n promptOptions: {\r\n type: 'number'\r\n }\r\n },\r\n maxWorkers: {\r\n value: 8,\r\n types: ['number'],\r\n envLink: 'POOL_MAX_WORKERS',\r\n legacyName: 'workers',\r\n description: 'Maximum number of pool workers to spawn',\r\n promptOptions: {\r\n type: 'number'\r\n }\r\n },\r\n workLimit: {\r\n value: 40,\r\n types: ['number'],\r\n envLink: 'POOL_WORK_LIMIT',\r\n description: 'Number of tasks a worker can handle before restarting',\r\n promptOptions: {\r\n type: 'number'\r\n }\r\n },\r\n acquireTimeout: {\r\n value: 5000,\r\n types: ['number'],\r\n envLink: 'POOL_ACQUIRE_TIMEOUT',\r\n description: 'Timeout in milliseconds for acquiring a resource',\r\n promptOptions: {\r\n type: 'number'\r\n }\r\n },\r\n createTimeout: {\r\n value: 5000,\r\n types: ['number'],\r\n envLink: 'POOL_CREATE_TIMEOUT',\r\n description: 'Timeout in milliseconds for creating a resource',\r\n promptOptions: {\r\n type: 'number'\r\n }\r\n },\r\n destroyTimeout: {\r\n value: 5000,\r\n types: ['number'],\r\n envLink: 'POOL_DESTROY_TIMEOUT',\r\n description: 'Timeout in milliseconds for destroying a resource',\r\n promptOptions: {\r\n type: 'number'\r\n }\r\n },\r\n idleTimeout: {\r\n value: 30000,\r\n types: ['number'],\r\n envLink: 'POOL_IDLE_TIMEOUT',\r\n description: 'Timeout in milliseconds for destroying idle resources',\r\n promptOptions: {\r\n type: 'number'\r\n }\r\n },\r\n createRetryInterval: {\r\n value: 200,\r\n types: ['number'],\r\n envLink: 'POOL_CREATE_RETRY_INTERVAL',\r\n description:\r\n 'Interval in milliseconds before retrying resource creation on failure',\r\n promptOptions: {\r\n type: 'number'\r\n }\r\n },\r\n reaperInterval: {\r\n value: 1000,\r\n types: ['number'],\r\n envLink: 'POOL_REAPER_INTERVAL',\r\n description:\r\n 'Interval in milliseconds to check and destroy idle resources',\r\n promptOptions: {\r\n type: 'number'\r\n }\r\n },\r\n benchmarking: {\r\n value: false,\r\n types: ['boolean'],\r\n envLink: 'POOL_BENCHMARKING',\r\n cliName: 'poolBenchmarking',\r\n description: 'Shows statistics for the pool of resources',\r\n promptOptions: {\r\n type: 'toggle'\r\n }\r\n }\r\n },\r\n logging: {\r\n level: {\r\n value: 4,\r\n types: ['number'],\r\n envLink: 'LOGGING_LEVEL',\r\n cliName: 'logLevel',\r\n description: 'Logging verbosity level',\r\n promptOptions: {\r\n type: 'number',\r\n round: 0,\r\n min: 0,\r\n max: 5\r\n }\r\n },\r\n file: {\r\n value: 'highcharts-export-server.log',\r\n types: ['string'],\r\n envLink: 'LOGGING_FILE',\r\n cliName: 'logFile',\r\n description:\r\n 'Log file name. Requires `logToFile` and `logDest` to be set',\r\n promptOptions: {\r\n type: 'text'\r\n }\r\n },\r\n dest: {\r\n value: 'log',\r\n types: ['string'],\r\n envLink: 'LOGGING_DEST',\r\n cliName: 'logDest',\r\n description: 'Path to store log files. Requires `logToFile` to be set',\r\n promptOptions: {\r\n type: 'text'\r\n }\r\n },\r\n toConsole: {\r\n value: true,\r\n types: ['boolean'],\r\n envLink: 'LOGGING_TO_CONSOLE',\r\n cliName: 'logToConsole',\r\n description: 'Enables or disables console logging',\r\n promptOptions: {\r\n type: 'toggle'\r\n }\r\n },\r\n toFile: {\r\n value: true,\r\n types: ['boolean'],\r\n envLink: 'LOGGING_TO_FILE',\r\n cliName: 'logToFile',\r\n description: 'Enables or disables logging to a file',\r\n promptOptions: {\r\n type: 'toggle'\r\n }\r\n }\r\n },\r\n ui: {\r\n enable: {\r\n value: false,\r\n types: ['boolean'],\r\n envLink: 'UI_ENABLE',\r\n cliName: 'enableUi',\r\n description: 'Enables or disables the UI for the export server',\r\n promptOptions: {\r\n type: 'toggle'\r\n }\r\n },\r\n route: {\r\n value: '/',\r\n types: ['string'],\r\n envLink: 'UI_ROUTE',\r\n cliName: 'uiRoute',\r\n description: 'The endpoint route for the UI',\r\n promptOptions: {\r\n type: 'text'\r\n }\r\n }\r\n },\r\n other: {\r\n nodeEnv: {\r\n value: 'production',\r\n types: ['string'],\r\n envLink: 'OTHER_NODE_ENV',\r\n description: 'The Node.js environment type',\r\n promptOptions: {\r\n type: 'text'\r\n }\r\n },\r\n listenToProcessExits: {\r\n value: true,\r\n types: ['boolean'],\r\n envLink: 'OTHER_LISTEN_TO_PROCESS_EXITS',\r\n description: 'Whether or not to attach process.exit handlers',\r\n promptOptions: {\r\n type: 'toggle'\r\n }\r\n },\r\n noLogo: {\r\n value: false,\r\n types: ['boolean'],\r\n envLink: 'OTHER_NO_LOGO',\r\n description: 'Display or skip printing the logo on startup',\r\n promptOptions: {\r\n type: 'toggle'\r\n }\r\n },\r\n hardResetPage: {\r\n value: false,\r\n types: ['boolean'],\r\n envLink: 'OTHER_HARD_RESET_PAGE',\r\n description: 'Whether or not to reset the page content entirely',\r\n promptOptions: {\r\n type: 'toggle'\r\n }\r\n },\r\n browserShellMode: {\r\n value: true,\r\n types: ['boolean'],\r\n envLink: 'OTHER_BROWSER_SHELL_MODE',\r\n description: 'Whether or not to set the browser to run in shell mode',\r\n promptOptions: {\r\n type: 'toggle'\r\n }\r\n }\r\n },\r\n debug: {\r\n enable: {\r\n value: false,\r\n types: ['boolean'],\r\n envLink: 'DEBUG_ENABLE',\r\n cliName: 'enableDebug',\r\n description: 'Enables or disables debug mode for the underlying browser',\r\n promptOptions: {\r\n type: 'toggle'\r\n }\r\n },\r\n headless: {\r\n value: false,\r\n types: ['boolean'],\r\n envLink: 'DEBUG_HEADLESS',\r\n description:\r\n 'Whether or not to set the browser to run in headless mode during debugging',\r\n promptOptions: {\r\n type: 'toggle'\r\n }\r\n },\r\n devtools: {\r\n value: false,\r\n types: ['boolean'],\r\n envLink: 'DEBUG_DEVTOOLS',\r\n description: 'Enables or disables DevTools in headful mode',\r\n promptOptions: {\r\n type: 'toggle'\r\n }\r\n },\r\n listenToConsole: {\r\n value: false,\r\n types: ['boolean'],\r\n envLink: 'DEBUG_LISTEN_TO_CONSOLE',\r\n description:\r\n 'Enables or disables listening to console messages from the browser',\r\n promptOptions: {\r\n type: 'toggle'\r\n }\r\n },\r\n dumpio: {\r\n value: false,\r\n types: ['boolean'],\r\n envLink: 'DEBUG_DUMPIO',\r\n description:\r\n 'Redirects or not browser stdout and stderr to process.stdout and process.stderr',\r\n promptOptions: {\r\n type: 'toggle'\r\n }\r\n },\r\n slowMo: {\r\n value: 0,\r\n types: ['number'],\r\n envLink: 'DEBUG_SLOW_MO',\r\n description: 'Delays Puppeteer operations by the specified milliseconds',\r\n promptOptions: {\r\n type: 'number'\r\n }\r\n },\r\n debuggingPort: {\r\n value: 9222,\r\n types: ['number'],\r\n envLink: 'DEBUG_DEBUGGING_PORT',\r\n description: 'Port used for debugging',\r\n promptOptions: {\r\n type: 'number'\r\n }\r\n }\r\n }\r\n};\r\n\r\n// Properties nesting level of all options\r\nexport const nestedProps = _createNestedProps(defaultConfig);\r\n\r\n// Properties names that should not be recursively merged\r\nexport const absoluteProps = _createAbsoluteProps(defaultConfig);\r\n\r\n/**\r\n * Recursively generates a mapping of nested argument chains from a nested\r\n * config object. This function traverses a nested object and creates a mapping\r\n * where each key is an argument name (either from `cliName`, `legacyName`,\r\n * or the original key) and each value is a string representing the chain\r\n * of nested properties leading to that argument.\r\n *\r\n * @function _createNestedProps\r\n *\r\n * @param {Object} config - The configuration object.\r\n * @param {Object} [nestedProps={}] - The accumulator object for storing\r\n * the resulting arguments chains. The default value is an empty object.\r\n * @param {string} [propChain=''] - The current chain of nested properties,\r\n * used internally during recursion. The default value is an empty string.\r\n *\r\n * @returns {Object} An object mapping argument names to their corresponding\r\n * nested property chains.\r\n */\r\nfunction _createNestedProps(config, nestedProps = {}, propChain = '') {\r\n Object.keys(config).forEach((key) => {\r\n // Get the specific section\r\n const entry = config[key];\r\n\r\n // Check if there is still more depth to traverse\r\n if (typeof entry.value === 'undefined') {\r\n // Recurse into deeper levels of nested arguments\r\n _createNestedProps(entry, nestedProps, `${propChain}.${key}`);\r\n } else {\r\n // Create the chain of nested arguments\r\n nestedProps[entry.cliName || key] = `${propChain}.${key}`.substring(1);\r\n\r\n // Support for the legacy, PhantomJS properties names\r\n if (entry.legacyName !== undefined) {\r\n nestedProps[entry.legacyName] = `${propChain}.${key}`.substring(1);\r\n }\r\n }\r\n });\r\n\r\n // Return the object with nested argument chains\r\n return nestedProps;\r\n}\r\n\r\n/**\r\n * Recursively gathers the names of properties from a configuration object that\r\n * can be treated as absolute properties. These properties have values that\r\n * are objects and do not contain further nested depth when merging an object\r\n * containing these options.\r\n *\r\n * @function _createAbsoluteProps\r\n *\r\n * @param {Object} config - The configuration object.\r\n * @param {Array.} [absoluteProps=[]] - An array to collect the names\r\n * of absolute properties. The default value is an empty array.\r\n *\r\n * @returns {Array.} An array containing the names of absolute\r\n * properties.\r\n */\r\nfunction _createAbsoluteProps(config, absoluteProps = []) {\r\n Object.keys(config).forEach((key) => {\r\n // Get the specific section\r\n const entry = config[key];\r\n\r\n // Check if there is still more depth to traverse\r\n if (typeof entry.types === 'undefined') {\r\n // Recurse into deeper levels\r\n _createAbsoluteProps(entry, absoluteProps);\r\n } else {\r\n // If the option can be an object, save its type in the array\r\n if (entry.types.includes('Object')) {\r\n absoluteProps.push(key);\r\n }\r\n }\r\n });\r\n\r\n // Return the array with the names of absolute properties\r\n return absoluteProps;\r\n}\r\n\r\nexport default {\r\n defaultConfig,\r\n nestedProps,\r\n absoluteProps\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * @overview This file handles parsing and validating options from multiple\r\n * sources (the config file, custom JSON, environment variables, CLI arguments,\r\n * and request payload) using the 'zod' library.\r\n *\r\n * Environment variables are parsed and validated only once at application\r\n * startup, and the validated results are exported as `envs` for use throughout\r\n * the application.\r\n *\r\n * Options from other sources, however, are parsed and validated on demand,\r\n * each time an export is attempted.\r\n */\r\n\r\nimport dotenv from 'dotenv';\r\nimport { z } from 'zod';\r\n\r\nimport { defaultConfig } from './schemas/config.js';\r\n\r\n// Load the .env into environment variables\r\ndotenv.config();\r\n\r\n// Get scripts names of each category from the default config\r\nconst { coreScripts, moduleScripts, indicatorScripts } =\r\n defaultConfig.highcharts;\r\n\r\n// Sets the custom error map globally\r\nz.setErrorMap(_customErrorMap);\r\n\r\n/**\r\n * Object containing custom general validators and parsers to avoid repetition\r\n * in schema objects. All validators apply to values from various sources,\r\n * including the default config file, a custom JSON file loaded with the option\r\n * called `loadConfig`, the .env file, CLI arguments, and the request payload.\r\n * The `strictCheck` flag enables stricter validation and parsing rules. This\r\n * flag is set to false for values that come from the .env file or CLI arguments\r\n * because they are provided as strings and need to be parsed accordingly first.\r\n */\r\nconst v = {\r\n /**\r\n * The `boolean` validator that returns a Zod schema with an optional stricter\r\n * check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures that:\r\n *\r\n * - When `strictCheck` is true, the schema will accept values are true\r\n * and false and the schema will validate against the default boolean\r\n * validator.\r\n *\r\n * - When `strictCheck` is false, the schema will accept values are true,\r\n * false, null, 'true', 'false', 'undefined', 'null', and ''. The strings\r\n * 'undefined', 'null', and '' will be transformed to null, the string 'true'\r\n * will be transformed to the boolean value true, and 'false' will\r\n * be transformed to the boolean value false.\r\n *\r\n * @function boolean\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating boolean values.\r\n */\r\n boolean(strictCheck) {\r\n return strictCheck\r\n ? z.boolean()\r\n : z\r\n .union([\r\n z\r\n .enum(['true', 'false', 'undefined', 'null', ''])\r\n .transform((value) =>\r\n !['undefined', 'null', ''].includes(value)\r\n ? value === 'true'\r\n : null\r\n ),\r\n z.boolean()\r\n ])\r\n .nullable();\r\n },\r\n\r\n /**\r\n * The `string` validator that returns a Zod schema with an optional stricter\r\n * check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures that:\r\n *\r\n * - When `strictCheck` is true, the schema will accept trimmed strings except\r\n * the forbidden values: 'false', 'undefined', 'null', and ''.\r\n *\r\n * - When `strictCheck` is false, the schema will accept trimmed strings\r\n * and null. The forbidden values: 'false', 'undefined', 'null', and '' will\r\n * be transformed to null.\r\n *\r\n * @function string\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating string values.\r\n */\r\n string(strictCheck) {\r\n return strictCheck\r\n ? z\r\n .string()\r\n .trim()\r\n .refine(\r\n (value) => !['false', 'undefined', 'null', ''].includes(value),\r\n {\r\n params: {\r\n errorMessage: `The string contains a forbidden value`\r\n }\r\n }\r\n )\r\n : z\r\n .string()\r\n .trim()\r\n .transform((value) =>\r\n !['false', 'undefined', 'null', ''].includes(value) ? value : null\r\n )\r\n .nullable();\r\n },\r\n\r\n /**\r\n * The `enum` validator that returns a Zod schema with an optional stricter\r\n * check based on the `strictCheck` parameter.\r\n *\r\n * The schema will validate against the provided `values` array.\r\n *\r\n * The validation schema ensures that:\r\n *\r\n * - When `strictCheck` is true, the schema will validate against the `values`\r\n * array with the default enum validator.\r\n *\r\n * - When `strictCheck` is false, the schema will accept also null,\r\n * 'undefined', 'null', and '', which will be transformed to null.\r\n *\r\n * @function enum\r\n *\r\n * @param {Array.} values - An array of valid string values\r\n * for the enum.\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating enum values.\r\n */\r\n enum(values, strictCheck) {\r\n return strictCheck\r\n ? z.enum([...values])\r\n : z\r\n .enum([...values, 'undefined', 'null', ''])\r\n .transform((value) =>\r\n !['undefined', 'null', ''].includes(value) ? value : null\r\n )\r\n .nullable();\r\n },\r\n\r\n /**\r\n * The `stringArray` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures that:\r\n *\r\n * - When `strictCheck` is true, the schema will accept an array of trimmed\r\n * string values filtered by the logic provided through the `filterCallback`.\r\n *\r\n * - When `strictCheck` is false, the schema will accept null and trimmed\r\n * string values which will be splitted into an array of strings and filtered\r\n * from the '[' and ']' characters and by the logic provided through\r\n * the `filterCallback`. If the array is empty, it will be transformed\r\n * to null.\r\n *\r\n * @function stringArray\r\n *\r\n * @param {function} filterCallback - The filter callback.\r\n * @param {string} separator - The separator for spliting a string.\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating array of string\r\n * values.\r\n */\r\n stringArray(filterCallback, separator, strictCheck) {\r\n const arraySchema = z.string().trim().array();\r\n const stringSchema = z\r\n .string()\r\n .trim()\r\n .transform((value) => {\r\n if (value.startsWith('[')) {\r\n value = value.slice(1);\r\n }\r\n if (value.endsWith(']')) {\r\n value = value.slice(0, -1);\r\n }\r\n return value.split(separator);\r\n });\r\n\r\n const transformCallback = (value) =>\r\n value.map((value) => value.trim()).filter(filterCallback);\r\n\r\n return strictCheck\r\n ? arraySchema.transform(transformCallback)\r\n : z\r\n .union([stringSchema, arraySchema])\r\n .transform(transformCallback)\r\n .transform((value) => (value.length ? value : null))\r\n .nullable();\r\n },\r\n\r\n /**\r\n * The `positiveNum` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures that:\r\n *\r\n * - When `strictCheck` is true, the schema will accept positive number values\r\n * and validate against the default positive number validator.\r\n *\r\n * - When `strictCheck` is false, the schema will accept positive number\r\n * values, null, and trimmed string values that can either be 'undefined',\r\n * 'null', '', or represent a positive number. It will transform the string\r\n * to a positive number, or to null if it is 'undefined', 'null', or ''.\r\n *\r\n * @function positiveNum\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating positive number\r\n * values.\r\n */\r\n positiveNum(strictCheck) {\r\n return strictCheck\r\n ? z.number().positive()\r\n : z\r\n .union([\r\n z\r\n .string()\r\n .trim()\r\n .refine(\r\n (value) =>\r\n (!isNaN(Number(value)) && Number(value) > 0) ||\r\n ['undefined', 'null', ''].includes(value),\r\n {\r\n params: {\r\n errorMessage: `The value must be numeric and positive`\r\n }\r\n }\r\n )\r\n .transform((value) =>\r\n !['undefined', 'null', ''].includes(value)\r\n ? Number(value)\r\n : null\r\n ),\r\n z.number().positive()\r\n ])\r\n .nullable();\r\n },\r\n\r\n /**\r\n * The `nonNegativeNum` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures that:\r\n *\r\n * - When `strictCheck` is true, the schema will accept non-negative number\r\n * values and validate against the default non-negative number validator.\r\n *\r\n * - When `strictCheck` is false, the schema will accept non-negative number\r\n * values, null, and trimmed string values that can either be 'undefined',\r\n * 'null', '', or represent a non-negative number. It will transform\r\n * the string to a non-negative number, or to null if it is 'undefined',\r\n * 'null', or ''.\r\n *\r\n * @function nonNegativeNum\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating non-negative\r\n * number values.\r\n */\r\n nonNegativeNum(strictCheck) {\r\n return strictCheck\r\n ? z.number().nonnegative()\r\n : z\r\n .union([\r\n z\r\n .string()\r\n .trim()\r\n .refine(\r\n (value) =>\r\n (!isNaN(Number(value)) && Number(value) >= 0) ||\r\n ['undefined', 'null', ''].includes(value),\r\n {\r\n params: {\r\n errorMessage: `The value must be numeric and non-negative`\r\n }\r\n }\r\n )\r\n .transform((value) =>\r\n !['undefined', 'null', ''].includes(value)\r\n ? Number(value)\r\n : null\r\n ),\r\n z.number().nonnegative()\r\n ])\r\n .nullable();\r\n },\r\n\r\n /**\r\n * The `startsWith` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The schema will validate against the provided `prefixes` array to check\r\n * whether a string value starts with any of the values provided\r\n * in the `prefixes` array.\r\n *\r\n * The validation schema ensures that:\r\n *\r\n * - When `strictCheck` is true, the schema will accept trimmed string values\r\n * that start with values from the prefixes array.\r\n *\r\n * - When `strictCheck` is false, the schema will accept trimmed string values\r\n * that start with values from the prefixes array, null, 'undefined', 'null',\r\n * and '' where the schema will transform them to null.\r\n *\r\n * @function startsWith\r\n *\r\n * @param {Array.} prefixes - An array of prefixes to validate\r\n * the string against.\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating strings that\r\n * starts with values.\r\n */\r\n startsWith(prefixes, strictCheck) {\r\n return strictCheck\r\n ? z\r\n .string()\r\n .trim()\r\n .refine(\r\n (value) => prefixes.some((prefix) => value.startsWith(prefix)),\r\n {\r\n params: {\r\n errorMessage: `The value must be a string that starts with ${prefixes.join(', ')}`\r\n }\r\n }\r\n )\r\n : z\r\n .string()\r\n .trim()\r\n .refine(\r\n (value) =>\r\n prefixes.some((prefix) => value.startsWith(prefix)) ||\r\n ['undefined', 'null', ''].includes(value),\r\n {\r\n params: {\r\n errorMessage: `The value must be a string that starts with ${prefixes.join(', ')}`\r\n }\r\n }\r\n )\r\n .transform((value) =>\r\n !['undefined', 'null', ''].includes(value) ? value : null\r\n )\r\n .nullable();\r\n },\r\n\r\n /**\r\n * The `chartConfig` validator that returns a Zod schema.\r\n *\r\n * The validation schema ensures that the schema will accept object values\r\n * or trimmed string values that contain '\r\n value.indexOf('= 0 ||\r\n value.indexOf('= 0 ||\r\n (value.startsWith('{') && value.endsWith('}')) ||\r\n ['undefined', 'null', ''].includes(value),\r\n {\r\n params: {\r\n errorMessage: `The value must be a string that contains '\r\n !['undefined', 'null', ''].includes(value) ? value : null\r\n ),\r\n z.object({}).passthrough()\r\n ])\r\n .nullable();\r\n },\r\n\r\n /**\r\n * The `additionalOptions` validator that returns a Zod schema.\r\n *\r\n * The validation schema ensures that the schema will accept object values\r\n * or trimmed string values that end with '.json' and are at least one\r\n * character long excluding the extension, start with the '{' and end\r\n * with the '}', and null. The 'undefined', 'null', and '' values will\r\n * be transformed to null.\r\n *\r\n * @function additionalOptions\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating additional chart\r\n * options value.\r\n */\r\n additionalOptions() {\r\n return z\r\n .union([\r\n z\r\n .string()\r\n .trim()\r\n .refine(\r\n (value) =>\r\n (value.length >= 6 && value.endsWith('.json')) ||\r\n (value.startsWith('{') && value.endsWith('}')) ||\r\n ['undefined', 'null', ''].includes(value),\r\n {\r\n params: {\r\n errorMessage: `The value must be a string that ends with '.json' or starts with '{' and ends with '}'`\r\n }\r\n }\r\n )\r\n .transform((value) =>\r\n !['undefined', 'null', ''].includes(value) ? value : null\r\n ),\r\n z.object({}).passthrough()\r\n ])\r\n .nullable();\r\n }\r\n};\r\n\r\n/**\r\n * Object containing custom config validators and parsers to avoid repetition\r\n * in schema objects. All validators apply to values from various sources,\r\n * including the default config file, a custom JSON file loaded with the option\r\n * called `loadConfig`, the .env file, CLI arguments, and the request payload.\r\n * The `strictCheck` flag enables stricter validation and parsing rules. This\r\n * flag is set to false for values that come from the .env file or CLI arguments\r\n * because they are provided as strings and need to be parsed accordingly first.\r\n */\r\nconst config = {\r\n /**\r\n * The `args` validator that returns a Zod schema with an optional stricter\r\n * check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `stringArray` validator.\r\n *\r\n * @function args\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `args`\r\n * option.\r\n */\r\n args(strictCheck) {\r\n return v.stringArray(\r\n (value) => !['false', 'undefined', 'null', ''].includes(value),\r\n ';',\r\n strictCheck\r\n );\r\n },\r\n\r\n /**\r\n * The `version` validator that returns a Zod schema with an optional stricter\r\n * check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures that:\r\n *\r\n * - When `strictCheck` is true, the schema will accept trimmed string values\r\n * that are a RegExp-based that allows to be 'latest', or in the format XX,\r\n * XX.YY, or XX.YY.ZZ, where XX, YY, and ZZ are numeric for the Highcharts\r\n * version option.\r\n *\r\n * - When `strictCheck` is false, the schema will accept also null,\r\n * 'undefined', 'null', or '' and in all cases the schema will transform them\r\n * to null.\r\n *\r\n * @function version\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `version`\r\n * option.\r\n */\r\n version(strictCheck) {\r\n return strictCheck\r\n ? z\r\n .string()\r\n .trim()\r\n .refine((value) => /^(latest|\\d{1,2}(\\.\\d{1,2}){0,2})$/.test(value), {\r\n params: {\r\n errorMessage:\r\n \"The value must be 'latest', a major version, or in the form XX.YY.ZZ\"\r\n }\r\n })\r\n : z\r\n .string()\r\n .trim()\r\n .refine(\r\n (value) =>\r\n /^(latest|\\d{1,2}(\\.\\d{1,2}){0,2})$/.test(value) ||\r\n ['undefined', 'null', ''].includes(value),\r\n {\r\n params: {\r\n errorMessage:\r\n \"The value must be 'latest', a major version, or in the form XX.YY.ZZ\"\r\n }\r\n }\r\n )\r\n .transform((value) =>\r\n !['undefined', 'null', ''].includes(value) ? value : null\r\n )\r\n .nullable();\r\n },\r\n\r\n /**\r\n * The `cdnUrl` validator that returns a Zod schema with an optional stricter\r\n * check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `startsWith` validator.\r\n *\r\n * @function cdnUrl\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `cdnUrl`\r\n * option.\r\n */\r\n cdnUrl(strictCheck) {\r\n return v.startsWith(['http://', 'https://'], strictCheck);\r\n },\r\n\r\n /**\r\n * The `forceFetch` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `boolean` validator.\r\n *\r\n * @function forceFetch\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `forceFetch`\r\n * option.\r\n */\r\n forceFetch(strictCheck) {\r\n return v.boolean(strictCheck);\r\n },\r\n\r\n /**\r\n * The `cachePath` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `string` validator.\r\n *\r\n * @function cachePath\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `cachePath`\r\n * option.\r\n */\r\n cachePath(strictCheck) {\r\n return v.string(strictCheck);\r\n },\r\n\r\n /**\r\n * The `adminToken` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `string` validator.\r\n *\r\n * @function adminToken\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `adminToken`\r\n * option.\r\n */\r\n adminToken(strictCheck) {\r\n return v.string(strictCheck);\r\n },\r\n\r\n /**\r\n * The `coreScripts` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `stringArray` validator.\r\n *\r\n * @function coreScripts\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `coreScripts`\r\n * option.\r\n */\r\n coreScripts(strictCheck) {\r\n return v.stringArray(\r\n (value) => coreScripts.value.includes(value),\r\n ',',\r\n strictCheck\r\n );\r\n },\r\n\r\n /**\r\n * The `moduleScripts` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `stringArray` validator.\r\n *\r\n * @function moduleScripts\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating\r\n * the `moduleScripts` option.\r\n */\r\n moduleScripts(strictCheck) {\r\n return v.stringArray(\r\n (value) => moduleScripts.value.includes(value),\r\n ',',\r\n strictCheck\r\n );\r\n },\r\n\r\n /**\r\n * The `indicatorScripts` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `stringArray` validator.\r\n *\r\n * @function indicatorScripts\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating\r\n * the `indicatorScripts` option.\r\n */\r\n indicatorScripts(strictCheck) {\r\n return v.stringArray(\r\n (value) => indicatorScripts.value.includes(value),\r\n ',',\r\n strictCheck\r\n );\r\n },\r\n\r\n /**\r\n * The `customScripts` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `stringArray` validator.\r\n *\r\n * @function customScripts\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating\r\n * the `customScripts` option.\r\n */\r\n customScripts(strictCheck) {\r\n return v.stringArray(\r\n (value) => value.startsWith('https://') || value.startsWith('http://'),\r\n ',',\r\n strictCheck\r\n );\r\n },\r\n\r\n /**\r\n * The `infile` validator that returns a Zod schema with an optional stricter\r\n * check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures that:\r\n *\r\n * - When `strictCheck` is true, the schema will accept trimmed string values\r\n * that end with '.json' or '.svg', are at least one character long excluding\r\n * the extension, or null.\r\n *\r\n * - When `strictCheck` is false, the schema will accept trimmed string values\r\n * that end with '.json' or '.svg', are at least one character long excluding\r\n * the extension and will be null if the provided value is null, 'undefined',\r\n * 'null', or ''.\r\n *\r\n * @function infile\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `infile`\r\n * option.\r\n */\r\n infile(strictCheck) {\r\n return strictCheck\r\n ? z\r\n .string()\r\n .trim()\r\n .refine(\r\n (value) =>\r\n (value.length >= 6 && value.endsWith('.json')) ||\r\n (value.length >= 5 && value.endsWith('.svg')),\r\n {\r\n params: {\r\n errorMessage: `The value must be a string that ends with .json or .svg`\r\n }\r\n }\r\n )\r\n .nullable()\r\n : z\r\n .string()\r\n .trim()\r\n .refine(\r\n (value) =>\r\n (value.length >= 6 && value.endsWith('.json')) ||\r\n (value.length >= 5 && value.endsWith('.svg')) ||\r\n ['undefined', 'null', ''].includes(value),\r\n {\r\n params: {\r\n errorMessage: `The value must be a string that ends with .json or .svg`\r\n }\r\n }\r\n )\r\n .transform((value) =>\r\n !['undefined', 'null', ''].includes(value) ? value : null\r\n )\r\n .nullable();\r\n },\r\n\r\n /**\r\n * The `instr` validator that returns a Zod schema.\r\n *\r\n * The validation schema ensures the same work as the `options` validator.\r\n *\r\n * @function instr\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `instr`\r\n * option.\r\n */\r\n instr() {\r\n return v.chartConfig();\r\n },\r\n\r\n /**\r\n * The `options` validator that returns a Zod schema.\r\n *\r\n * The validation schema ensures the same work as the `options` validator.\r\n *\r\n * @function options\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `options`\r\n * option.\r\n */\r\n options() {\r\n return v.chartConfig();\r\n },\r\n\r\n /**\r\n * The `svg` validator that returns a Zod schema.\r\n *\r\n * The validation schema ensures that the schema will accept object values\r\n * or trimmed string values that contain '\r\n value.indexOf('= 0 ||\r\n value.indexOf('= 0 ||\r\n ['false', 'undefined', 'null', ''].includes(value),\r\n {\r\n params: {\r\n errorMessage: `The value must be a string that contains '\r\n !['false', 'undefined', 'null', ''].includes(value) ? value : null\r\n )\r\n .nullable();\r\n },\r\n\r\n /**\r\n * The `outfile` validator that returns a Zod schema with an optional stricter\r\n * check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures that:\r\n *\r\n * - When `strictCheck` is true, the schema will accept trimmed string values\r\n * that end with '.jpeg', '.jpg', '.png', '.pdf', or '.svg', are at least one\r\n * character long excluding the extension, or null.\r\n *\r\n * - When `strictCheck` is false, the schema will accept trimmed string values\r\n * that end with '.jpeg', '.jpg', '.png', '.pdf', or '.svg', are at least one\r\n * character long excluding the extension and will be null if the provided\r\n * value is null, 'undefined', 'null', or ''.\r\n *\r\n * @function outfile\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `outfile`\r\n * option.\r\n */\r\n outfile(strictCheck) {\r\n return strictCheck\r\n ? z\r\n .string()\r\n .trim()\r\n .refine(\r\n (value) =>\r\n (value.length >= 6 && value.endsWith('.jpeg')) ||\r\n (value.length >= 5 &&\r\n (value.endsWith('.jpg') ||\r\n value.endsWith('.png') ||\r\n value.endsWith('.pdf') ||\r\n value.endsWith('.svg'))),\r\n {\r\n params: {\r\n errorMessage: `The value must be a string that ends with .jpeg, .jpg, .png, .pdf, or .svg`\r\n }\r\n }\r\n )\r\n .nullable()\r\n : z\r\n .string()\r\n .trim()\r\n .refine(\r\n (value) =>\r\n (value.length >= 6 && value.endsWith('.jpeg')) ||\r\n (value.length >= 5 &&\r\n (value.endsWith('.jpg') ||\r\n value.endsWith('.png') ||\r\n value.endsWith('.pdf') ||\r\n value.endsWith('.svg'))) ||\r\n ['undefined', 'null', ''].includes(value),\r\n {\r\n params: {\r\n errorMessage: `The value must be a string that ends with .jpeg, .jpg, .png, .pdf, or .svg`\r\n }\r\n }\r\n )\r\n .transform((value) =>\r\n !['undefined', 'null', ''].includes(value) ? value : null\r\n )\r\n .nullable();\r\n },\r\n\r\n /**\r\n * The `type` validator that returns a Zod schema with an optional stricter\r\n * check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `enum` validator.\r\n *\r\n * @function type\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `type`\r\n * option.\r\n */\r\n type(strictCheck) {\r\n return v.enum(['jpeg', 'jpg', 'png', 'pdf', 'svg'], strictCheck);\r\n },\r\n\r\n /**\r\n * The `constr` validator that returns a Zod schema with an optional stricter\r\n * check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `enum` validator.\r\n *\r\n * @function constr\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `constr`\r\n * option.\r\n */\r\n constr(strictCheck) {\r\n return v.enum(\r\n ['chart', 'stockChart', 'mapChart', 'ganttChart'],\r\n strictCheck\r\n );\r\n },\r\n\r\n /**\r\n * The `b64` validator that returns a Zod schema with an optional stricter\r\n * check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `boolean` validator.\r\n *\r\n * @function b64\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `b64` option.\r\n */\r\n b64(strictCheck) {\r\n return v.boolean(strictCheck);\r\n },\r\n\r\n /**\r\n * The `noDownload` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `boolean` validator.\r\n *\r\n * @function noDownload\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `noDownload`\r\n * option.\r\n */\r\n noDownload(strictCheck) {\r\n return v.boolean(strictCheck);\r\n },\r\n\r\n /**\r\n * The `defaultHeight` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `positiveNum` validator.\r\n *\r\n * @function defaultHeight\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating\r\n * the `defaultHeight` option.\r\n */\r\n defaultHeight(strictCheck) {\r\n return v.positiveNum(strictCheck);\r\n },\r\n\r\n /**\r\n * The `defaultWidth` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `positiveNum` validator.\r\n *\r\n * @function defaultWidth\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating\r\n * the `defaultWidth` option.\r\n */\r\n defaultWidth(strictCheck) {\r\n return v.positiveNum(strictCheck);\r\n },\r\n\r\n /**\r\n * The `defaultScale` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures that:\r\n *\r\n * - When `strictCheck` is true, the schema will accept number values that\r\n * are between 0.1 and 5 (inclusive).\r\n *\r\n * - When `strictCheck` is false, the schema will accept number values\r\n * and stringified number values that are between 0.1 and 5 (inclusive), null,\r\n * 'undefined', 'null', and '' which will be transformed to null.\r\n *\r\n * @function defaultScale\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating\r\n * the `defaultScale` option.\r\n */\r\n defaultScale(strictCheck) {\r\n return strictCheck\r\n ? z.number().gte(0.1).lte(5)\r\n : z\r\n .union([\r\n z\r\n .string()\r\n .trim()\r\n .refine(\r\n (value) =>\r\n (!isNaN(Number(value)) &&\r\n value !== true &&\r\n !value.startsWith('[') &&\r\n Number(value) >= 0.1 &&\r\n Number(value) <= 5) ||\r\n ['undefined', 'null', ''].includes(value),\r\n {\r\n params: {\r\n errorMessage: 'The value must be within a 0.1 and 5.0 range'\r\n }\r\n }\r\n )\r\n .transform((value) =>\r\n !['undefined', 'null', ''].includes(value)\r\n ? Number(value)\r\n : null\r\n ),\r\n z.number().gte(0.1).lte(5)\r\n ])\r\n .nullable();\r\n },\r\n\r\n /**\r\n * The `height` validator that returns a Zod schema with an optional stricter\r\n * check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as a nullable `defaultHeight`\r\n * validator.\r\n *\r\n * @function height\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `height`\r\n * option.\r\n */\r\n height(strictCheck) {\r\n return this.defaultHeight(strictCheck).nullable();\r\n },\r\n\r\n /**\r\n * The `width` validator that returns a Zod schema with an optional stricter\r\n * check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as a nullable `defaultWidth`\r\n * validator.\r\n *\r\n * @function width\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `width`\r\n * option.\r\n */\r\n width(strictCheck) {\r\n return this.defaultWidth(strictCheck).nullable();\r\n },\r\n\r\n /**\r\n * The `scale` validator that returns a Zod schema with an optional stricter\r\n * check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as a nullable `defaultScale`\r\n * validator.\r\n *\r\n * @function scale\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `scale`\r\n * option.\r\n */\r\n scale(strictCheck) {\r\n return this.defaultScale(strictCheck).nullable();\r\n },\r\n\r\n /**\r\n * The `globalOptions` validator that returns a Zod schema.\r\n *\r\n * The validation schema ensures the same work as the `additionalOptions`\r\n * validator.\r\n *\r\n * @function globalOptions\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating\r\n * the `globalOptions` option.\r\n */\r\n globalOptions() {\r\n return v.additionalOptions();\r\n },\r\n\r\n /**\r\n * The `themeOptions` validator that returns a Zod schema.\r\n *\r\n * The validation schema ensures the same work as the `additionalOptions`\r\n * validator.\r\n *\r\n * @function themeOptions\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating\r\n * the `themeOptions` option.\r\n */\r\n themeOptions() {\r\n return v.additionalOptions();\r\n },\r\n\r\n /**\r\n * The `batch` validator that returns a Zod schema with an optional stricter\r\n * check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `string` validator.\r\n *\r\n * @function batch\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `batch`\r\n * option.\r\n */\r\n batch(strictCheck) {\r\n return v.string(strictCheck);\r\n },\r\n\r\n /**\r\n * The `rasterizationTimeout` validator that returns a Zod schema with\r\n * an optional stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `nonNegativeNum`\r\n * validator.\r\n *\r\n * @function rasterizationTimeout\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating\r\n * the `rasterizationTimeout` option.\r\n */\r\n rasterizationTimeout(strictCheck) {\r\n return v.nonNegativeNum(strictCheck);\r\n },\r\n\r\n /**\r\n * The `allowCodeExecution` validator that returns a Zod schema with\r\n * an optional stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `boolean` validator.\r\n *\r\n * @function allowCodeExecution\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating\r\n * the `allowCodeExecution` option.\r\n */\r\n allowCodeExecution(strictCheck) {\r\n return v.boolean(strictCheck);\r\n },\r\n\r\n /**\r\n * The `allowFileResources` validator that returns a Zod schema with\r\n * an optional stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `boolean` validator.\r\n *\r\n * @function allowFileResources\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating\r\n * the `allowFileResources` option.\r\n */\r\n allowFileResources(strictCheck) {\r\n return v.boolean(strictCheck);\r\n },\r\n\r\n /**\r\n * The `customCode` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `string` validator.\r\n *\r\n * @function customCode\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `customCode`\r\n * option.\r\n */\r\n customCode(strictCheck) {\r\n return v.string(strictCheck);\r\n },\r\n\r\n /**\r\n * The `callback` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `string` validator.\r\n *\r\n * @function callback\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `callback`\r\n * option.\r\n */\r\n callback(strictCheck) {\r\n return v.string(strictCheck);\r\n },\r\n\r\n /**\r\n * The `resources` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures that:\r\n *\r\n * - When `strictCheck` is true, the schema will accept a partial object\r\n * with allowed properties `js`, `css`, and `files` where each of the allowed\r\n * properties can be null, stringified version of the object, string that ends\r\n * with the '.json', and null.\r\n *\r\n * - When `strictCheck` is false, the schema will accept a stringified version\r\n * of a partial object with allowed properties `js`, `css`, and `files` where\r\n * each of the allowed properties can be null, string that ends with the\r\n * '.json', and will be null if the provided value is 'undefined', 'null'\r\n * or ''.\r\n *\r\n * @function resources\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `resources`\r\n * option.\r\n */\r\n resources(strictCheck) {\r\n const objectSchema = z\r\n .object({\r\n js: v.string(false),\r\n css: v.string(false),\r\n files: v\r\n .stringArray(\r\n (value) => !['undefined', 'null', ''].includes(value),\r\n ',',\r\n true\r\n )\r\n .nullable()\r\n })\r\n .partial();\r\n\r\n const stringSchema1 = z\r\n .string()\r\n .trim()\r\n .refine(\r\n (value) =>\r\n (value.startsWith('{') && value.endsWith('}')) ||\r\n (value.length >= 6 && value.endsWith('.json')),\r\n {\r\n params: {\r\n errorMessage: `The value must be a string that starts with '{' and ends with '}`\r\n }\r\n }\r\n );\r\n\r\n const stringSchema2 = z\r\n .string()\r\n .trim()\r\n .refine(\r\n (value) =>\r\n (value.startsWith('{') && value.endsWith('}')) ||\r\n (value.length >= 6 && value.endsWith('.json')) ||\r\n ['undefined', 'null', ''].includes(value),\r\n {\r\n params: {\r\n errorMessage: `The value must be a string that ends with '.json'`\r\n }\r\n }\r\n )\r\n .transform((value) =>\r\n !['undefined', 'null', ''].includes(value) ? value : null\r\n );\r\n\r\n return strictCheck\r\n ? z.union([objectSchema, stringSchema1]).nullable()\r\n : z.union([objectSchema, stringSchema2]).nullable();\r\n },\r\n\r\n /**\r\n * The `loadConfig` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `string` validator.\r\n * Additionally, it must be a string that ends with '.json'.\r\n *\r\n * @function loadConfig\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `loadConfig`\r\n * option.\r\n */\r\n loadConfig(strictCheck) {\r\n return v\r\n .string(strictCheck)\r\n .refine(\r\n (value) =>\r\n value === null || (value.length >= 6 && value.endsWith('.json')),\r\n {\r\n params: {\r\n errorMessage: `The value must be a string that ends with .json `\r\n }\r\n }\r\n );\r\n },\r\n\r\n /**\r\n * The `createConfig` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `loadConfig` validator.\r\n *\r\n * @function createConfig\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating\r\n * the `createConfig` option.\r\n */\r\n createConfig(strictCheck) {\r\n return this.loadConfig(strictCheck);\r\n },\r\n\r\n /**\r\n * The `enableServer` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `boolean` validator.\r\n *\r\n * @function enableServer\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating\r\n * the `enableServer` option.\r\n */\r\n enableServer(strictCheck) {\r\n return v.boolean(strictCheck);\r\n },\r\n\r\n /**\r\n * The `host` validator that returns a Zod schema with an optional stricter\r\n * check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `string` validator.\r\n *\r\n * @function host\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `host`\r\n * option.\r\n */\r\n host(strictCheck) {\r\n return v.string(strictCheck);\r\n },\r\n\r\n /**\r\n * The `port` validator that returns a Zod schema with an optional stricter\r\n * check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `nonNegativeNum`\r\n * validator.\r\n *\r\n * @function port\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `port`\r\n * option.\r\n */\r\n port(strictCheck) {\r\n return v.nonNegativeNum(strictCheck);\r\n },\r\n\r\n /**\r\n * The `uploadLimit` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `positiveNum` validator.\r\n *\r\n * @function uploadLimit\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `uploadLimit`\r\n * option.\r\n */\r\n uploadLimit(strictCheck) {\r\n return v.positiveNum(strictCheck);\r\n },\r\n\r\n /**\r\n * The `serverBenchmarking` validator that returns a Zod schema with\r\n * an optional stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `boolean` validator.\r\n *\r\n * @function serverBenchmarking\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating\r\n * the `serverBenchmarking` option.\r\n */\r\n serverBenchmarking(strictCheck) {\r\n return v.boolean(strictCheck);\r\n },\r\n\r\n /**\r\n * The `proxyHost` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `string` validator.\r\n *\r\n * @function proxyHost\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `proxyHost`\r\n * option.\r\n */\r\n proxyHost(strictCheck) {\r\n return v.string(strictCheck);\r\n },\r\n\r\n /**\r\n * The `proxyPort` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as a nullable `nonNegativeNum`\r\n * validator.\r\n *\r\n * @function proxyPort\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `proxyPort`\r\n * option.\r\n */\r\n proxyPort(strictCheck) {\r\n return v.nonNegativeNum(strictCheck).nullable();\r\n },\r\n\r\n /**\r\n * The `proxyTimeout` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `nonNegativeNum`\r\n * validator.\r\n *\r\n * @function proxyTimeout\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating\r\n * the `proxyTimeout` option.\r\n */\r\n proxyTimeout(strictCheck) {\r\n return v.nonNegativeNum(strictCheck);\r\n },\r\n\r\n /**\r\n * The `enableRateLimiting` validator that returns a Zod schema with\r\n * an optional stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `boolean` validator.\r\n *\r\n * @function enableRateLimiting\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating\r\n * the `enableRateLimiting` option.\r\n */\r\n enableRateLimiting(strictCheck) {\r\n return v.boolean(strictCheck);\r\n },\r\n\r\n /**\r\n * The `maxRequests` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `nonNegativeNum`\r\n * validator.\r\n *\r\n * @function maxRequests\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `maxRequests`\r\n * option.\r\n */\r\n maxRequests(strictCheck) {\r\n return v.nonNegativeNum(strictCheck);\r\n },\r\n\r\n /**\r\n * The `window` validator that returns a Zod schema with an optional stricter\r\n * check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `nonNegativeNum`\r\n * validator.\r\n *\r\n * @function window\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `window`\r\n * option.\r\n */\r\n window(strictCheck) {\r\n return v.nonNegativeNum(strictCheck);\r\n },\r\n\r\n /**\r\n * The `delay` validator that returns a Zod schema with an optional stricter\r\n * check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `nonNegativeNum`\r\n * validator.\r\n *\r\n * @function delay\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `delay`\r\n * option.\r\n */\r\n delay(strictCheck) {\r\n return v.nonNegativeNum(strictCheck);\r\n },\r\n\r\n /**\r\n * The `trustProxy` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `boolean` validator.\r\n *\r\n * @function trustProxy\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `trustProxy`\r\n * option.\r\n */\r\n trustProxy(strictCheck) {\r\n return v.boolean(strictCheck);\r\n },\r\n\r\n /**\r\n * The `skipKey` validator that returns a Zod schema with an optional stricter\r\n * check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `string` validator.\r\n *\r\n * @function skipKey\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `skipKey`\r\n * option.\r\n */\r\n skipKey(strictCheck) {\r\n return v.string(strictCheck);\r\n },\r\n\r\n /**\r\n * The `skipToken` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `string` validator.\r\n *\r\n * @function skipToken\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `skipToken`\r\n * option.\r\n */\r\n skipToken(strictCheck) {\r\n return v.string(strictCheck);\r\n },\r\n\r\n /**\r\n * The `enableSsl` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `boolean` validator.\r\n *\r\n * @function enableSsl\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `enableSsl`\r\n * option.\r\n */\r\n enableSsl(strictCheck) {\r\n return v.boolean(strictCheck);\r\n },\r\n\r\n /**\r\n * The `sslForce` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `boolean` validator.\r\n *\r\n * @function sslForce\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `sslForce`\r\n * option.\r\n */\r\n sslForce(strictCheck) {\r\n return v.boolean(strictCheck);\r\n },\r\n\r\n /**\r\n * The `sslPort` validator that returns a Zod schema with an optional stricter\r\n * check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `nonNegativeNum`\r\n * validator.\r\n *\r\n * @function sslPort\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `sslPort`\r\n * option.\r\n */\r\n sslPort(strictCheck) {\r\n return v.nonNegativeNum(strictCheck);\r\n },\r\n\r\n /**\r\n * The `sslCertPath` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `string` validator.\r\n *\r\n * @function sslCertPath\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `sslCertPath`\r\n * option.\r\n */\r\n sslCertPath(strictCheck) {\r\n return v.string(strictCheck);\r\n },\r\n\r\n /**\r\n * The `minWorkers` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `positiveNum` validator.\r\n *\r\n * @function minWorkers\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `minWorkers`\r\n * option.\r\n */\r\n minWorkers(strictCheck) {\r\n return v.positiveNum(strictCheck);\r\n },\r\n\r\n /**\r\n * The `maxWorkers` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `positiveNum` validator.\r\n *\r\n * @function maxWorkers\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `maxWorkers`\r\n * option.\r\n */\r\n maxWorkers(strictCheck) {\r\n return v.positiveNum(strictCheck);\r\n },\r\n\r\n /**\r\n * The `workLimit` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `positiveNum` validator.\r\n *\r\n * @function workLimit\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `workLimit`\r\n * option.\r\n */\r\n workLimit(strictCheck) {\r\n return v.positiveNum(strictCheck);\r\n },\r\n\r\n /**\r\n * The `acquireTimeout` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `nonNegativeNum`\r\n * validator.\r\n *\r\n * @function acquireTimeout\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating\r\n * the `acquireTimeout` option.\r\n */\r\n acquireTimeout(strictCheck) {\r\n return v.nonNegativeNum(strictCheck);\r\n },\r\n\r\n /**\r\n * The `createTimeout` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `nonNegativeNum`\r\n * validator.\r\n *\r\n * @function createTimeout\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating\r\n * the `createTimeout` option.\r\n */\r\n createTimeout(strictCheck) {\r\n return v.nonNegativeNum(strictCheck);\r\n },\r\n\r\n /**\r\n * The `destroyTimeout` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `nonNegativeNum`\r\n * validator.\r\n *\r\n * @function destroyTimeout\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating\r\n * the `destroyTimeout` option.\r\n */\r\n destroyTimeout(strictCheck) {\r\n return v.nonNegativeNum(strictCheck);\r\n },\r\n\r\n /**\r\n * The `idleTimeout` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `nonNegativeNum`\r\n * validator.\r\n *\r\n * @function idleTimeout\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating\r\n * the `idleTimeout` option.\r\n */\r\n idleTimeout(strictCheck) {\r\n return v.nonNegativeNum(strictCheck);\r\n },\r\n\r\n /**\r\n * The `createRetryInterval` validator that returns a Zod schema with\r\n * an optional stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `nonNegativeNum`\r\n * validator.\r\n *\r\n * @function createRetryInterval\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating\r\n * the `createRetryInterval` option.\r\n */\r\n createRetryInterval(strictCheck) {\r\n return v.nonNegativeNum(strictCheck);\r\n },\r\n\r\n /**\r\n * The `reaperInterval` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `nonNegativeNum`\r\n * validator.\r\n *\r\n * @function reaperInterval\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating\r\n * the `reaperInterval` option.\r\n */\r\n reaperInterval(strictCheck) {\r\n return v.nonNegativeNum(strictCheck);\r\n },\r\n\r\n /**\r\n * The `poolBenchmarking` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `boolean` validator.\r\n *\r\n * @function poolBenchmarking\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating\r\n * the `poolBenchmarking` option.\r\n */\r\n poolBenchmarking(strictCheck) {\r\n return v.boolean(strictCheck);\r\n },\r\n\r\n /**\r\n * The `resourcesInterval` validator that returns a Zod schema with\r\n * an optional stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `nonNegativeNum`\r\n * validator.\r\n *\r\n * @function resourcesInterval\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating\r\n * the `resourcesInterval` option.\r\n */\r\n resourcesInterval(strictCheck) {\r\n return v.nonNegativeNum(strictCheck);\r\n },\r\n\r\n /**\r\n * The `logLevel` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures that:\r\n *\r\n * - When `strictCheck` is true, the schema will accept integer number values\r\n * that are between 0 and 5 (inclusive).\r\n *\r\n * - When `strictCheck` is false, the schema will accept integer number values\r\n * and stringified integer number values that are between 1 and 5 (inclusive),\r\n * null, 'undefined', 'null', and '' which will be transformed to null.\r\n *\r\n * @function logLevel\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `logLevel`\r\n * option.\r\n */\r\n logLevel(strictCheck) {\r\n return strictCheck\r\n ? z.number().int().gte(0).lte(5)\r\n : z\r\n .union([\r\n z\r\n .string()\r\n .trim()\r\n .refine(\r\n (value) =>\r\n (!isNaN(Number(value)) &&\r\n value !== true &&\r\n !value.startsWith('[') &&\r\n Number.isInteger(Number(value)) &&\r\n Number(value) >= 0 &&\r\n Number(value) <= 5) ||\r\n ['undefined', 'null', ''].includes(value),\r\n {\r\n params: {\r\n errorMessage: 'The value must be within a 0 and 5 range'\r\n }\r\n }\r\n )\r\n .transform((value) =>\r\n !['undefined', 'null', ''].includes(value)\r\n ? Number(value)\r\n : null\r\n ),\r\n z.number().int().gte(0).lte(5)\r\n ])\r\n .nullable();\r\n },\r\n\r\n /**\r\n * The `logFile` validator that returns a Zod schema with an optional stricter\r\n * check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `string` validator.\r\n * Additionally, it must be a string that ends with '.log'.\r\n *\r\n * @function logFile\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `logFile`\r\n * option.\r\n */\r\n logFile(strictCheck) {\r\n return v\r\n .string(strictCheck)\r\n .refine(\r\n (value) =>\r\n value === null || (value.length >= 5 && value.endsWith('.log')),\r\n {\r\n params: {\r\n errorMessage: `The value must be a string that ends with '.log'`\r\n }\r\n }\r\n );\r\n },\r\n\r\n /**\r\n * The `logDest` validator that returns a Zod schema with an optional stricter\r\n * check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `string` validator.\r\n *\r\n * @function logDest\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `logDest`\r\n * option.\r\n */\r\n logDest(strictCheck) {\r\n return v.string(strictCheck);\r\n },\r\n\r\n /**\r\n * The `logToConsole` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `boolean` validator.\r\n *\r\n * @function logToConsole\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating\r\n * the `logToConsole` option.\r\n */\r\n logToConsole(strictCheck) {\r\n return v.boolean(strictCheck);\r\n },\r\n\r\n /**\r\n * The `logToFile` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `boolean` validator.\r\n *\r\n * @function logToFile\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `logToFile`\r\n * option.\r\n */\r\n logToFile(strictCheck) {\r\n return v.boolean(strictCheck);\r\n },\r\n\r\n /**\r\n * The `enableUi` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `boolean` validator.\r\n *\r\n * @function enableUi\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `enableUi`\r\n * option.\r\n */\r\n enableUi(strictCheck) {\r\n return v.boolean(strictCheck);\r\n },\r\n\r\n /**\r\n * The `uiRoute` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `startsWith` validator.\r\n *\r\n * @function uiRoute\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `uiRoute`\r\n * option.\r\n */\r\n uiRoute(strictCheck) {\r\n return v.startsWith(['/'], strictCheck);\r\n },\r\n\r\n /**\r\n * The `nodeEnv` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `enum` validator.\r\n *\r\n * @function nodeEnv\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `nodeEnv`\r\n * option.\r\n */\r\n nodeEnv(strictCheck) {\r\n return v.enum(['development', 'production', 'test'], strictCheck);\r\n },\r\n\r\n /**\r\n * The `listenToProcessExits` validator that returns a Zod schema with\r\n * an optional stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `boolean` validator.\r\n *\r\n * @function listenToProcessExits\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating\r\n * the `listenToProcessExits` option.\r\n */\r\n listenToProcessExits(strictCheck) {\r\n return v.boolean(strictCheck);\r\n },\r\n\r\n /**\r\n * The `noLogo` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `boolean` validator.\r\n *\r\n * @function noLogo\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `noLogo`\r\n * option.\r\n */\r\n noLogo(strictCheck) {\r\n return v.boolean(strictCheck);\r\n },\r\n\r\n /**\r\n * The `hardResetPage` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `boolean` validator.\r\n *\r\n * @function hardResetPage\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating\r\n * the `hardResetPage` option.\r\n */\r\n hardResetPage(strictCheck) {\r\n return v.boolean(strictCheck);\r\n },\r\n\r\n /**\r\n * The `browserShellMode` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `boolean` validator.\r\n *\r\n * @function browserShellMode\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating\r\n * the `browserShellMode` option.\r\n */\r\n browserShellMode(strictCheck) {\r\n return v.boolean(strictCheck);\r\n },\r\n\r\n /**\r\n * The `enableDebug` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `boolean` validator.\r\n *\r\n * @function enableDebug\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `enableDebug`\r\n * option.\r\n */\r\n enableDebug(strictCheck) {\r\n return v.boolean(strictCheck);\r\n },\r\n\r\n /**\r\n * The `headless` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `boolean` validator.\r\n *\r\n * @function headless\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `headless`\r\n * option.\r\n */\r\n headless(strictCheck) {\r\n return v.boolean(strictCheck);\r\n },\r\n\r\n /**\r\n * The `devtools` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `boolean` validator.\r\n *\r\n * @function devtools\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `devtools`\r\n * option.\r\n */\r\n devtools(strictCheck) {\r\n return v.boolean(strictCheck);\r\n },\r\n\r\n /**\r\n * The `listenToConsole` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `boolean` validator.\r\n *\r\n * @function listenToConsole\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating\r\n * the `listenToConsole` option.\r\n */\r\n listenToConsole(strictCheck) {\r\n return v.boolean(strictCheck);\r\n },\r\n\r\n /**\r\n * The `dumpio` validator that returns a Zod schema with an optional stricter\r\n * check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `boolean` validator.\r\n *\r\n * @function dumpio\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `dumpio`\r\n * option.\r\n */\r\n dumpio(strictCheck) {\r\n return v.boolean(strictCheck);\r\n },\r\n\r\n /**\r\n * The `slowMo` validator that returns a Zod schema with an optional stricter\r\n * check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `nonNegativeNum`\r\n * validator.\r\n *\r\n * @function slowMo\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `slowMo`\r\n * option.\r\n */\r\n slowMo(strictCheck) {\r\n return v.nonNegativeNum(strictCheck);\r\n },\r\n\r\n /**\r\n * The `debuggingPort` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `nonNegativeNum`\r\n * validator.\r\n *\r\n * @function debuggingPort\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating\r\n * the `debuggingPort` option.\r\n */\r\n debuggingPort(strictCheck) {\r\n return v.nonNegativeNum(strictCheck);\r\n },\r\n\r\n /**\r\n * The `requestId` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `string` validator.\r\n * Additionally, it must be a stringified UUID or can be null.\r\n *\r\n * @function requestId\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `requestId`\r\n * option.\r\n */\r\n requestId() {\r\n return (\r\n z\r\n .string()\r\n /// TO DO: Correct\r\n .uuid({ message: 'The value must be a stringified UUID' })\r\n .nullable()\r\n );\r\n }\r\n};\r\n\r\n// Schema for the puppeteer section of options\r\nconst PuppeteerSchema = (strictCheck) =>\r\n z\r\n .object({\r\n args: config.args(strictCheck)\r\n })\r\n .partial();\r\n\r\n// Schema for the highcharts section of options\r\nconst HighchartsSchema = (strictCheck) =>\r\n z\r\n .object({\r\n version: config.version(strictCheck),\r\n cdnUrl: config.cdnUrl(strictCheck),\r\n forceFetch: config.forceFetch(strictCheck),\r\n cachePath: config.cachePath(strictCheck),\r\n coreScripts: config.coreScripts(strictCheck),\r\n moduleScripts: config.moduleScripts(strictCheck),\r\n indicatorScripts: config.indicatorScripts(strictCheck),\r\n customScripts: config.customScripts(strictCheck)\r\n })\r\n .partial();\r\n\r\n// Schema for the export section of options\r\nconst ExportSchema = (strictCheck) =>\r\n z\r\n .object({\r\n infile: config.infile(strictCheck),\r\n instr: config.instr(),\r\n options: config.options(),\r\n svg: config.svg(),\r\n outfile: config.outfile(strictCheck),\r\n type: config.type(strictCheck),\r\n constr: config.constr(strictCheck),\r\n b64: config.b64(strictCheck),\r\n noDownload: config.noDownload(strictCheck),\r\n defaultHeight: config.defaultHeight(strictCheck),\r\n defaultWidth: config.defaultWidth(strictCheck),\r\n defaultScale: config.defaultScale(strictCheck),\r\n height: config.height(strictCheck),\r\n width: config.width(strictCheck),\r\n scale: config.scale(strictCheck),\r\n globalOptions: config.globalOptions(),\r\n themeOptions: config.themeOptions(),\r\n batch: config.batch(false),\r\n rasterizationTimeout: config.rasterizationTimeout(strictCheck)\r\n })\r\n .partial();\r\n\r\n// Schema for the customLogic section of options\r\nconst CustomLogicSchema = (strictCheck) =>\r\n z\r\n .object({\r\n allowCodeExecution: config.allowCodeExecution(strictCheck),\r\n allowFileResources: config.allowFileResources(strictCheck),\r\n customCode: config.customCode(false),\r\n callback: config.callback(false),\r\n resources: config.resources(strictCheck),\r\n loadConfig: config.loadConfig(false),\r\n createConfig: config.createConfig(false)\r\n })\r\n .partial();\r\n\r\n// Schema for the server.proxy section of options\r\nconst ProxySchema = (strictCheck) =>\r\n z\r\n .object({\r\n host: config.proxyHost(false),\r\n port: config.proxyPort(strictCheck),\r\n timeout: config.proxyTimeout(strictCheck)\r\n })\r\n .partial();\r\n\r\n// Schema for the server.rateLimiting section of options\r\nconst RateLimitingSchema = (strictCheck) =>\r\n z\r\n .object({\r\n enable: config.enableRateLimiting(strictCheck),\r\n maxRequests: config.maxRequests(strictCheck),\r\n window: config.window(strictCheck),\r\n delay: config.delay(strictCheck),\r\n trustProxy: config.trustProxy(strictCheck),\r\n skipKey: config.skipKey(false),\r\n skipToken: config.skipToken(false)\r\n })\r\n .partial();\r\n\r\n// Schema for the server.ssl section of options\r\nconst SslSchema = (strictCheck) =>\r\n z\r\n .object({\r\n enable: config.enableSsl(strictCheck),\r\n force: config.sslForce(strictCheck),\r\n port: config.sslPort(strictCheck),\r\n certPath: config.sslCertPath(false)\r\n })\r\n .partial();\r\n\r\n// Schema for the server section of options\r\nconst ServerSchema = (strictCheck) =>\r\n z.object({\r\n enable: config.enableServer(strictCheck).optional(),\r\n host: config.host(strictCheck).optional(),\r\n port: config.port(strictCheck).optional(),\r\n benchmarking: config.serverBenchmarking(strictCheck).optional(),\r\n proxy: ProxySchema(strictCheck).optional(),\r\n rateLimiting: RateLimitingSchema(strictCheck).optional(),\r\n ssl: SslSchema(strictCheck).optional()\r\n });\r\n\r\n// Schema for the pool section of options\r\nconst PoolSchema = (strictCheck) =>\r\n z\r\n .object({\r\n minWorkers: config.minWorkers(strictCheck),\r\n maxWorkers: config.maxWorkers(strictCheck),\r\n workLimit: config.workLimit(strictCheck),\r\n acquireTimeout: config.acquireTimeout(strictCheck),\r\n createTimeout: config.createTimeout(strictCheck),\r\n destroyTimeout: config.destroyTimeout(strictCheck),\r\n idleTimeout: config.idleTimeout(strictCheck),\r\n createRetryInterval: config.createRetryInterval(strictCheck),\r\n reaperInterval: config.reaperInterval(strictCheck),\r\n benchmarking: config.poolBenchmarking(strictCheck)\r\n })\r\n .partial();\r\n\r\n// Schema for the logging section of options\r\nconst LoggingSchema = (strictCheck) =>\r\n z\r\n .object({\r\n level: config.logLevel(strictCheck),\r\n file: config.logFile(strictCheck),\r\n dest: config.logDest(strictCheck),\r\n toConsole: config.logToConsole(strictCheck),\r\n toFile: config.logToFile(strictCheck)\r\n })\r\n .partial();\r\n\r\n// Schema for the ui section of options\r\nconst UiSchema = (strictCheck) =>\r\n z\r\n .object({\r\n enable: config.enableUi(strictCheck),\r\n route: config.uiRoute(strictCheck)\r\n })\r\n .partial();\r\n\r\n// Schema for the other section of options\r\nconst OtherSchema = (strictCheck) =>\r\n z\r\n .object({\r\n nodeEnv: config.nodeEnv(strictCheck),\r\n listenToProcessExits: config.listenToProcessExits(strictCheck),\r\n noLogo: config.noLogo(strictCheck),\r\n hardResetPage: config.hardResetPage(strictCheck),\r\n browserShellMode: config.browserShellMode(strictCheck)\r\n })\r\n .partial();\r\n\r\n// Schema for the debug section of options\r\nconst DebugSchema = (strictCheck) =>\r\n z\r\n .object({\r\n enable: config.enableDebug(strictCheck),\r\n headless: config.headless(strictCheck),\r\n devtools: config.devtools(strictCheck),\r\n listenToConsole: config.listenToConsole(strictCheck),\r\n dumpio: config.dumpio(strictCheck),\r\n slowMo: config.slowMo(strictCheck),\r\n debuggingPort: config.debuggingPort(strictCheck)\r\n })\r\n .partial();\r\n\r\n////\r\n// // Schema for the payload section of options\r\n// const PayloadSchema = () =>\r\n// z\r\n// .object({\r\n// requestId: config.requestId()\r\n// })\r\n// .partial();\r\n////\r\n\r\n// Strict schema for the config\r\nexport const StrictConfigSchema = z.object({\r\n puppeteer: PuppeteerSchema(true),\r\n highcharts: HighchartsSchema(true),\r\n export: ExportSchema(true),\r\n customLogic: CustomLogicSchema(true),\r\n server: ServerSchema(true),\r\n pool: PoolSchema(true),\r\n logging: LoggingSchema(true),\r\n ui: UiSchema(true),\r\n other: OtherSchema(true),\r\n debug: DebugSchema(true)\r\n //// payload: PayloadSchema()\r\n});\r\n\r\n// Loose schema for the config\r\nexport const LooseConfigSchema = z.object({\r\n puppeteer: PuppeteerSchema(false),\r\n highcharts: HighchartsSchema(false),\r\n export: ExportSchema(false),\r\n customLogic: CustomLogicSchema(false),\r\n server: ServerSchema(false),\r\n pool: PoolSchema(false),\r\n logging: LoggingSchema(false),\r\n ui: UiSchema(false),\r\n other: OtherSchema(false),\r\n debug: DebugSchema(false)\r\n //// payload: PayloadSchema()\r\n});\r\n\r\n// Schema for the environment variables config\r\nexport const EnvSchema = z.object({\r\n // puppeteer\r\n PUPPETEER_ARGS: config.args(false),\r\n\r\n // highcharts\r\n HIGHCHARTS_VERSION: config.version(false),\r\n HIGHCHARTS_CDN_URL: config.cdnUrl(false),\r\n HIGHCHARTS_FORCE_FETCH: config.forceFetch(false),\r\n HIGHCHARTS_CACHE_PATH: config.cachePath(false),\r\n HIGHCHARTS_ADMIN_TOKEN: config.adminToken(false),\r\n HIGHCHARTS_CORE_SCRIPTS: config.coreScripts(false),\r\n HIGHCHARTS_MODULE_SCRIPTS: config.moduleScripts(false),\r\n HIGHCHARTS_INDICATOR_SCRIPTS: config.indicatorScripts(false),\r\n HIGHCHARTS_CUSTOM_SCRIPTS: config.customScripts(false),\r\n\r\n // export\r\n EXPORT_INFILE: config.infile(false),\r\n EXPORT_INSTR: config.instr(),\r\n EXPORT_OPTIONS: config.options(),\r\n EXPORT_SVG: config.svg(),\r\n EXPORT_BATCH: config.batch(false),\r\n EXPORT_OUTFILE: config.outfile(false),\r\n EXPORT_TYPE: config.type(false),\r\n EXPORT_CONSTR: config.constr(false),\r\n EXPORT_B64: config.b64(false),\r\n EXPORT_NO_DOWNLOAD: config.noDownload(false),\r\n EXPORT_HEIGHT: config.height(false),\r\n EXPORT_WIDTH: config.width(false),\r\n EXPORT_SCALE: config.scale(false),\r\n EXPORT_DEFAULT_HEIGHT: config.defaultHeight(false),\r\n EXPORT_DEFAULT_WIDTH: config.defaultWidth(false),\r\n EXPORT_DEFAULT_SCALE: config.defaultScale(false),\r\n EXPORT_GLOBAL_OPTIONS: config.globalOptions(),\r\n EXPORT_THEME_OPTIONS: config.themeOptions(),\r\n EXPORT_RASTERIZATION_TIMEOUT: config.rasterizationTimeout(false),\r\n\r\n // custom\r\n CUSTOM_LOGIC_ALLOW_CODE_EXECUTION: config.allowCodeExecution(false),\r\n CUSTOM_LOGIC_ALLOW_FILE_RESOURCES: config.allowFileResources(false),\r\n CUSTOM_LOGIC_CUSTOM_CODE: config.customCode(false),\r\n CUSTOM_LOGIC_CALLBACK: config.callback(false),\r\n CUSTOM_LOGIC_RESOURCES: config.resources(false),\r\n CUSTOM_LOGIC_LOAD_CONFIG: config.loadConfig(false),\r\n CUSTOM_LOGIC_CREATE_CONFIG: config.createConfig(false),\r\n\r\n // server\r\n SERVER_ENABLE: config.enableServer(false),\r\n SERVER_HOST: config.host(false),\r\n SERVER_PORT: config.port(false),\r\n SERVER_UPLOAD_LIMIT: config.uploadLimit(false),\r\n SERVER_BENCHMARKING: config.serverBenchmarking(false),\r\n\r\n // server proxy\r\n SERVER_PROXY_HOST: config.proxyHost(false),\r\n SERVER_PROXY_PORT: config.proxyPort(false),\r\n SERVER_PROXY_TIMEOUT: config.proxyTimeout(false),\r\n\r\n // server rate limiting\r\n SERVER_RATE_LIMITING_ENABLE: config.enableRateLimiting(false),\r\n SERVER_RATE_LIMITING_MAX_REQUESTS: config.maxRequests(false),\r\n SERVER_RATE_LIMITING_WINDOW: config.window(false),\r\n SERVER_RATE_LIMITING_DELAY: config.delay(false),\r\n SERVER_RATE_LIMITING_TRUST_PROXY: config.trustProxy(false),\r\n SERVER_RATE_LIMITING_SKIP_KEY: config.skipKey(false),\r\n SERVER_RATE_LIMITING_SKIP_TOKEN: config.skipToken(false),\r\n\r\n // server ssl\r\n SERVER_SSL_ENABLE: config.enableSsl(false),\r\n SERVER_SSL_FORCE: config.sslForce(false),\r\n SERVER_SSL_PORT: config.sslPort(false),\r\n SERVER_SSL_CERT_PATH: config.sslCertPath(false),\r\n\r\n // pool\r\n POOL_MIN_WORKERS: config.minWorkers(false),\r\n POOL_MAX_WORKERS: config.maxWorkers(false),\r\n POOL_WORK_LIMIT: config.workLimit(false),\r\n POOL_ACQUIRE_TIMEOUT: config.acquireTimeout(false),\r\n POOL_CREATE_TIMEOUT: config.createTimeout(false),\r\n POOL_DESTROY_TIMEOUT: config.destroyTimeout(false),\r\n POOL_IDLE_TIMEOUT: config.idleTimeout(false),\r\n POOL_CREATE_RETRY_INTERVAL: config.createRetryInterval(false),\r\n POOL_REAPER_INTERVAL: config.reaperInterval(false),\r\n POOL_BENCHMARKING: config.poolBenchmarking(false),\r\n\r\n // logging\r\n LOGGING_LEVEL: config.logLevel(false),\r\n LOGGING_FILE: config.logFile(false),\r\n LOGGING_DEST: config.logDest(false),\r\n LOGGING_TO_CONSOLE: config.logToConsole(false),\r\n LOGGING_TO_FILE: config.logToFile(false),\r\n\r\n // ui\r\n UI_ENABLE: config.enableUi(false),\r\n UI_ROUTE: config.uiRoute(false),\r\n\r\n // other\r\n OTHER_NODE_ENV: config.nodeEnv(false),\r\n OTHER_LISTEN_TO_PROCESS_EXITS: config.listenToProcessExits(false),\r\n OTHER_NO_LOGO: config.noLogo(false),\r\n OTHER_HARD_RESET_PAGE: config.hardResetPage(false),\r\n OTHER_BROWSER_SHELL_MODE: config.browserShellMode(false),\r\n\r\n // debugger\r\n DEBUG_ENABLE: config.enableDebug(false),\r\n DEBUG_HEADLESS: config.headless(false),\r\n DEBUG_DEVTOOLS: config.devtools(false),\r\n DEBUG_LISTEN_TO_CONSOLE: config.listenToConsole(false),\r\n DEBUG_DUMPIO: config.dumpio(false),\r\n DEBUG_SLOW_MO: config.slowMo(false),\r\n DEBUG_DEBUGGING_PORT: config.debuggingPort(false)\r\n});\r\n\r\n/**\r\n * Validates the environment variables options using the EnvSchema.\r\n *\r\n * @param {Object} process.env - The configuration options from environment\r\n * variables file to validate.\r\n *\r\n * @returns {Object} The parsed and validated environment variables.\r\n */\r\nexport const envs = EnvSchema.partial().parse(process.env);\r\n\r\n/**\r\n * Validates the configuration options using the `StrictConfigSchema`.\r\n *\r\n * @function strictValidate\r\n *\r\n * @param {Object} configOptions - The configuration options to validate.\r\n *\r\n * @returns {Object} The parsed and validated configuration options.\r\n */\r\nexport function strictValidate(configOptions) {\r\n return StrictConfigSchema.partial().parse(configOptions);\r\n}\r\n\r\n/**\r\n * Validates the configuration options using the `LooseConfigSchema`.\r\n *\r\n * @function looseValidate\r\n *\r\n * @param {Object} configOptions - The configuration options to validate.\r\n *\r\n * @returns {Object} The parsed and validated configuration options.\r\n */\r\nexport function looseValidate(configOptions) {\r\n return LooseConfigSchema.partial().parse(configOptions);\r\n}\r\n\r\n/**\r\n * Validates a provided option using the specific validator from the config\r\n * object.\r\n *\r\n * @function validateOption\r\n *\r\n * @param {string} name - The name of an option to validate.\r\n * @param {any} option - The option to validate.\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {any} The parsed and validated option value.\r\n */\r\nexport function validateOption(name, option, strictCheck) {\r\n return config[name](strictCheck).parse(option);\r\n}\r\n\r\n/**\r\n * Custom error mapping function for Zod schema validation.\r\n *\r\n * This function customizes the error messages produced by Zod schema\r\n * validation, providing more specific and user-friendly feedback based on the\r\n * issue type and context.\r\n *\r\n * The function modifies the error messages as follows:\r\n *\r\n * - For missing required values (undefined), it returns a message indicating\r\n * that no value was provided for the specific property.\r\n *\r\n * - For custom validation errors, if a custom error message is provided in the\r\n * issue parameters, it includes this message along with the invalid data\r\n * received.\r\n *\r\n * - For all other errors, it appends property-specific information to the\r\n * default error message provided by Zod.\r\n *\r\n * @function _customErrorMap\r\n *\r\n * @param {z.ZodIssue} issue - The issue object representing the validation\r\n * error.\r\n * @param {Object} context - The context object providing additional information\r\n * about the validation error.\r\n *\r\n * @returns {Object} An object containing the customized error message.\r\n */\r\nfunction _customErrorMap(issue, context) {\r\n // Get the chain of properties which error directly refers to\r\n const propertyName = issue.path.join('.');\r\n\r\n // Create the first part of the message about the property information\r\n const propertyInfo = `Invalid value for the ${propertyName}`;\r\n\r\n // Modified message for the invalid type\r\n if (issue.code === z.ZodIssueCode.invalid_type) {\r\n // Modified message for the required values\r\n if (issue.received === z.ZodParsedType.undefined) {\r\n return {\r\n message: `${propertyInfo} - No value was provided.`\r\n };\r\n }\r\n\r\n // Modified message for the specific invalid type when values exist\r\n return {\r\n message: `${propertyInfo} - Invalid type. ${context.defaultError}.`\r\n };\r\n }\r\n\r\n // Modified message for the custom validation\r\n if (issue.code === z.ZodIssueCode.custom) {\r\n // If the custom message for error exist, include it\r\n if (issue.params?.errorMessage) {\r\n return {\r\n message: `${propertyInfo} - ${issue.params?.errorMessage}, received '${context.data}'.`\r\n };\r\n }\r\n }\r\n\r\n // Modified message for the invalid union error\r\n if (issue.code === z.ZodIssueCode.invalid_union) {\r\n // Create the first part of the message about the multiple errors\r\n let message = `Multiple errors occurred for the ${propertyName}:\\n`;\r\n\r\n // Cycle through all errors and create a correct message\r\n issue.unionErrors.forEach((value) => {\r\n const index = value.issues[0].message.indexOf('-');\r\n message +=\r\n index !== -1\r\n ? `${value.issues[0].message}\\n`.substring(index)\r\n : `${value.issues[0].message}\\n`;\r\n });\r\n\r\n // Return the final message for the invalid union error\r\n return {\r\n message\r\n };\r\n }\r\n\r\n // Return the default error message, extended by the info about the property\r\n return {\r\n message: `${propertyInfo} - ${context.defaultError}.`\r\n };\r\n}\r\n\r\nexport default {\r\n StrictConfigSchema,\r\n LooseConfigSchema,\r\n EnvSchema,\r\n envs,\r\n strictValidate,\r\n looseValidate,\r\n validateOption\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * @overview Manages configuration for the Highcharts Export Server by loading\r\n * and merging options from multiple sources, such as default settings,\r\n * environment variables, user-provided options, and command-line arguments.\r\n * Ensures the global options are up-to-date with the highest priority values.\r\n * Provides functions for accessing and updating configuration.\r\n */\r\n\r\nimport { readFileSync } from 'fs';\r\nimport { join } from 'path';\r\n\r\nimport { log, logWithStack, logZodIssues } from './logger.js';\r\nimport { __dirname, isObject, deepCopy, getAbsolutePath } from './utils.js';\r\nimport { envs, looseValidate, strictValidate } from './validation.js';\r\nimport { defaultConfig, nestedProps, absoluteProps } from './schemas/config.js';\r\n\r\n// Sets the global options with initial values from the default config\r\nconst globalOptions = _initGlobalOptions(defaultConfig);\r\n\r\n// An object for the instance options, created each time the `initExport` occurs\r\nconst instanceOptions = deepCopy(globalOptions);\r\n\r\n/**\r\n * Retrieves a reference to the options object. Depending on the `getInstance`\r\n * parameter, it returns either the global options or the instance-specific\r\n * options object.\r\n *\r\n * @function getOptions\r\n *\r\n * @param {boolean} [getInstance=true] - Optional parameter that decides whether\r\n * to return the instance-specific options (when `true`) or the global options\r\n * (when `false`). The default value is `true`.\r\n *\r\n * @returns {Object} A reference to either the global options\r\n * or the instance-specific options, based on the `getInstance` parameter.\r\n */\r\nexport function getOptions(getInstance = true) {\r\n return getInstance ? instanceOptions : globalOptions;\r\n}\r\n\r\n/**\r\n * Sets the global options of the export server, keeping the principle\r\n * of the options load priority from all available sources. It accepts optional\r\n * `customOptions` object and `cliArgs` array with arguments from the CLI. These\r\n * options will be validated and applied if provided.\r\n *\r\n * The priority order of setting values is:\r\n *\r\n * 1. Options from the `lib/schemas/config.js` file (default values).\r\n * 2. Options from a custom JSON file (loaded by the `loadConfig` option).\r\n * 3. Options from the environment variables (the `.env` file).\r\n * 4. Options from the command line interface (CLI).\r\n * 5. Options from the first parameter (the `customOptions` is by default\r\n * an empty object).\r\n *\r\n * @function setGlobalOptions\r\n *\r\n * @param {Object} [customOptions={}] - Optional custom options for additional\r\n * configuration. The default value is an empty object.\r\n * @param {Array.} [cliArgs=[]] - Optional command line arguments\r\n * for additional configuration. The default value is an empty array.\r\n *\r\n * @returns {Object} The updated global options object, reflecting the merged\r\n * configuration from all available sources.\r\n */\r\nexport function setGlobalOptions(customOptions = {}, cliArgs = []) {\r\n // Object for options loaded via the `loadConfig` option\r\n let configOptions = {};\r\n\r\n // Object for options from the CLI\r\n let cliOptions = {};\r\n\r\n // Only for the CLI usage\r\n if (cliArgs.length) {\r\n try {\r\n // Validate options from the custom JSON loaded via the `loadConfig`\r\n configOptions = strictValidate(_loadConfigFile(cliArgs));\r\n } catch (error) {\r\n logZodIssues(\r\n 1,\r\n error.issues,\r\n '[config] Custom JSON options validation error'\r\n );\r\n }\r\n }\r\n\r\n // Apply custom options if there are any\r\n if (customOptions && Object.keys(customOptions).length !== 0) {\r\n try {\r\n // Validate custom options provided by the user\r\n customOptions = strictValidate(customOptions);\r\n } catch (error) {\r\n logZodIssues(1, error.issues, '[config] Custom options validation error');\r\n }\r\n }\r\n\r\n // Only for the CLI usage\r\n if (cliArgs.length) {\r\n try {\r\n // Validate options from the CLI\r\n cliOptions = looseValidate(_pairArgumentValue(nestedProps, cliArgs));\r\n } catch (error) {\r\n logZodIssues(1, error.issues, '[config] CLI options validation error');\r\n }\r\n }\r\n\r\n // Update values of the global options with values from each source possible\r\n _updateGlobalOptions(\r\n defaultConfig,\r\n globalOptions,\r\n configOptions,\r\n cliOptions,\r\n customOptions\r\n );\r\n\r\n // Return updated global options\r\n return globalOptions;\r\n}\r\n\r\n/**\r\n * Updates the instance options with additional options. It optionally allows\r\n * to reinitialize the instance options with the values of a current global\r\n * options object.\r\n *\r\n * @param {Object} updateOptions - The update options to merge into the instance\r\n * options.\r\n * @param {boolean} [newInstance=false] - A flag to indicate whether to init\r\n * options for a new instance. If `true`, the existing instance options will\r\n * be cleared and reinitialized based on the global options.\r\n *\r\n * @returns {Object} - The updated instance options.\r\n */\r\nexport function updateOptions(updateOptions, newInstance = false) {\r\n // Check if options need to be created for a new instance\r\n if (newInstance) {\r\n // Get rid of the old instance options\r\n Object.keys(instanceOptions).forEach((key) => {\r\n delete instanceOptions[key];\r\n });\r\n\r\n // Init the new instance options based on the global options\r\n mergeOptions(instanceOptions, deepCopy(globalOptions));\r\n }\r\n\r\n // Merge additional options to the instance options\r\n mergeOptions(instanceOptions, updateOptions);\r\n\r\n // Return the reference to the instance options object\r\n return instanceOptions;\r\n}\r\n\r\n/**\r\n * Merges two sets of configuration options, considering absolute properties.\r\n *\r\n * @function mergeOptions\r\n *\r\n * @param {Object} originalOptions - Original configuration options.\r\n * @param {Object} newOptions - New configuration options to be merged.\r\n *\r\n * @returns {Object} Merged configuration options.\r\n */\r\nexport function mergeOptions(originalOptions, newOptions) {\r\n // Check if the `originalOptions` and `newOptions` are correct objects\r\n if (isObject(originalOptions) && isObject(newOptions)) {\r\n for (const [key, value] of Object.entries(newOptions)) {\r\n originalOptions[key] =\r\n isObject(value) &&\r\n !absoluteProps.includes(key) &&\r\n originalOptions[key] !== undefined\r\n ? mergeOptions(originalOptions[key], value)\r\n : value !== undefined\r\n ? value\r\n : originalOptions[key] || null;\r\n }\r\n }\r\n\r\n // Return the original (modified or not) options\r\n return originalOptions;\r\n}\r\n\r\n/**\r\n * Maps old-structured configuration options (PhantomJS) to a new format\r\n * (Puppeteer). This function converts flat, old-structured options into\r\n * a new, nested configuration format based on a predefined mapping\r\n * (`nestedProps`). The new format is used for Puppeteer, while the old format\r\n * was used for PhantomJS.\r\n *\r\n * @function mapToNewOptions\r\n *\r\n * @param {Object} oldOptions - The old, flat configuration options\r\n * to be converted.\r\n *\r\n * @returns {Object} A new object containing options structured according\r\n * to the mapping defined in `nestedProps` or an empty object if the provided\r\n * `oldOptions` is not a correct object.\r\n */\r\nexport function mapToNewOptions(oldOptions) {\r\n // An object for the new structured options\r\n const newOptions = {};\r\n\r\n // Check if provided value is a correct object\r\n if (isObject(oldOptions)) {\r\n // Iterate over each key-value pair in the old-structured options\r\n for (const [key, value] of Object.entries(oldOptions)) {\r\n // If there is a nested mapping, split it into a properties chain\r\n const propertiesChain = nestedProps[key]\r\n ? nestedProps[key].split('.')\r\n : [];\r\n\r\n // If it is the last property in the chain, assign the value, otherwise,\r\n // create or reuse the nested object\r\n propertiesChain.reduce(\r\n (obj, prop, index) =>\r\n (obj[prop] =\r\n propertiesChain.length - 1 === index ? value : obj[prop] || {}),\r\n newOptions\r\n );\r\n }\r\n } else {\r\n log(\r\n 2,\r\n '[config] No correct object with options was provided. Returning an empty array.'\r\n );\r\n }\r\n\r\n // Return the new, structured options object\r\n return newOptions;\r\n}\r\n\r\n/**\r\n * Validates, parses, and checks if the provided config is allowed set\r\n * of options.\r\n *\r\n * @function isAllowedConfig\r\n *\r\n * @param {unknown} config - The config to be validated and parsed as a set\r\n * of options. Must be either an object or a string.\r\n * @param {boolean} [toString=false] - Whether to return a stringified version\r\n * of the parsed config. The default value is `false`.\r\n * @param {boolean} [allowFunctions=false] - Whether to allow functions\r\n * in the parsed config. If true, functions are preserved. Otherwise, when\r\n * a function is found, null is returned. The default value is `false`.\r\n *\r\n * @returns {(Object|string|null)} Returns a parsed set of options object,\r\n * a stringified set of options object if the `toString` is true, and null\r\n * if the config is not a valid set of options or parsing fails.\r\n */\r\nexport function isAllowedConfig(\r\n config,\r\n toString = false,\r\n allowFunctions = false\r\n) {\r\n try {\r\n // Accept only objects and strings\r\n if (!isObject(config) && typeof config !== 'string') {\r\n // Return null if any other type\r\n return null;\r\n }\r\n\r\n // Get the object representation of the original config\r\n const objectConfig =\r\n typeof config === 'string'\r\n ? allowFunctions\r\n ? eval(`(${config})`)\r\n : JSON.parse(config)\r\n : config;\r\n\r\n // Preserve or remove potential functions based on the `allowFunctions` flag\r\n const stringifiedOptions = _optionsStringify(\r\n objectConfig,\r\n allowFunctions,\r\n false\r\n );\r\n\r\n // Parse the config to check if it is valid set of options\r\n const parsedOptions = allowFunctions\r\n ? JSON.parse(\r\n _optionsStringify(objectConfig, allowFunctions, true),\r\n (_, value) =>\r\n typeof value === 'string' && value.startsWith('function')\r\n ? eval(`(${value})`)\r\n : value\r\n )\r\n : JSON.parse(stringifiedOptions);\r\n\r\n // Return stringified or object options based on the `toString` flag\r\n return toString ? stringifiedOptions : parsedOptions;\r\n } catch (error) {\r\n // Return null if parsing fails\r\n return null;\r\n }\r\n}\r\n\r\n/**\r\n * Prints the Highcharts Export Server logo, version, and license information.\r\n *\r\n * @function printLicense\r\n */\r\nexport function printLicense() {\r\n // Print the logo and version information\r\n printVersion();\r\n\r\n // Print the license information\r\n console.log(\r\n 'This software requires a valid Highcharts license for commercial use.\\n'\r\n .yellow,\r\n '\\nFor a full list of CLI options, type:',\r\n '\\nhighcharts-export-server --help\\n'.green,\r\n '\\nIf you do not have a license, one can be obtained here:',\r\n '\\nhttps://shop.highsoft.com/\\n'.green,\r\n '\\nTo customize your installation, please refer to the README file at:',\r\n '\\nhttps://github.com/highcharts/node-export-server#readme\\n'.green\r\n );\r\n}\r\n\r\n/**\r\n * Prints usage information for CLI arguments, displaying available options\r\n * and their descriptions. It can list properties recursively if categories\r\n * contain nested options.\r\n *\r\n * @function printUsage\r\n */\r\nexport function printUsage() {\r\n // Display README and general usage information\r\n console.log(\r\n '\\nUsage of CLI arguments:'.bold,\r\n '\\n-----------------------',\r\n `\\nFor more detailed information, visit the README file at: ${'https://github.com/highcharts/node-export-server#readme'.green}.\\n`\r\n );\r\n\r\n // Iterate through each category in the `defaultConfig` and display usage info\r\n Object.keys(defaultConfig).forEach((category) => {\r\n console.log(`${category.toUpperCase()}`.bold.red);\r\n _cycleCategories(defaultConfig[category]);\r\n console.log('');\r\n });\r\n}\r\n\r\n/**\r\n * Prints the Highcharts Export Server logo or text with the version\r\n * information.\r\n *\r\n * @function printVersion\r\n *\r\n * @param {boolean} [noLogo=false] - If true, only prints text with the version\r\n * information, without the logo. The default value is `false`.\r\n */\r\nexport function printVersion(noLogo = false) {\r\n // Get package version either from `.env` or from `package.json`\r\n const packageVersion = JSON.parse(\r\n readFileSync(join(__dirname, 'package.json'), 'utf8')\r\n ).version;\r\n\r\n // Print text only\r\n if (noLogo) {\r\n console.log(`Highcharts Export Server v${packageVersion}`);\r\n } else {\r\n // Print the logo\r\n console.log(\r\n readFileSync(join(__dirname, 'msg', 'startup.msg'), 'utf8').toString()\r\n .bold.yellow,\r\n `v${packageVersion}\\n`.bold\r\n );\r\n }\r\n}\r\n\r\n/**\r\n * Initializes and returns global options object based on provided\r\n * configuration, setting values from nested properties recursively.\r\n *\r\n * @function _initGlobalOptions\r\n *\r\n * @param {Object} config - The configuration object to be used for initializing\r\n * options.\r\n *\r\n * @returns {Object} Initialized options object.\r\n */\r\nfunction _initGlobalOptions(config) {\r\n const options = {};\r\n\r\n // Start initializing the `options` object recursively\r\n for (const [name, item] of Object.entries(config)) {\r\n if (Object.prototype.hasOwnProperty.call(item, 'value')) {\r\n // If a value from environment variables exists, it takes precedence\r\n const envVal = envs[item.envLink];\r\n if (envVal !== undefined && envVal !== null) {\r\n options[name] = envVal;\r\n } else {\r\n options[name] = item.value;\r\n }\r\n } else {\r\n options[name] = _initGlobalOptions(item);\r\n }\r\n }\r\n\r\n // Return the created `options` object\r\n return options;\r\n}\r\n\r\n/**\r\n * Updates global options object with values from various sources, following\r\n * a specific prioritization order. The function checks for values in the order\r\n * of precedence: the `loadConfig` configuration options, environment variables,\r\n * custom options, and CLI options.\r\n *\r\n * @function _updateGlobalOptions\r\n *\r\n * @param {Object} config - The configuration object, which includes the initial\r\n * settings and metadata for each option. This object is used to determine\r\n * the structure and default values for the options.\r\n * @param {Object} options - The global options object that will be updated\r\n * with values from other sources.\r\n * @param {Object} configOpt - The configuration options object, loaded with\r\n * the `loadConfig` option, which may provide values to override defaults.\r\n * @param {Object} cliOpt - The CLI options object, which may include values\r\n * provided through command-line arguments and may override configuration\r\n * options.\r\n * @param {Object} customOpt - The custom options object, typically containing\r\n * additional and user-defined values, which has the highest precedence among\r\n * options.\r\n */\r\nfunction _updateGlobalOptions(config, options, configOpt, cliOpt, customOpt) {\r\n Object.keys(config).forEach((key) => {\r\n // Get the config entry of a specific option\r\n const entry = config[key];\r\n\r\n // Gather values for the options from every possible source, if exists\r\n const configVal = configOpt && configOpt[key];\r\n const cliVal = cliOpt && cliOpt[key];\r\n const customVal = customOpt && customOpt[key];\r\n\r\n // If the value not found, need to go deeper\r\n if (typeof entry.value === 'undefined') {\r\n _updateGlobalOptions(entry, options[key], configVal, cliVal, customVal);\r\n } else {\r\n // If a value from custom JSON options exists, it takes precedence\r\n if (configVal !== undefined && configVal !== null) {\r\n options[key] = configVal;\r\n }\r\n\r\n // If a value from environment variables exists, it takes precedence\r\n const envVal = envs[entry.envLink];\r\n if (entry.envLink in envs && envVal !== undefined && envVal !== null) {\r\n options[key] = envVal;\r\n }\r\n\r\n // If a value from CLI options exists, it takes precedence\r\n if (cliVal !== undefined && cliVal !== null) {\r\n options[key] = cliVal;\r\n }\r\n\r\n // If a value from user options exists, it takes precedence\r\n if (customVal !== undefined && customVal !== null) {\r\n options[key] = customVal;\r\n }\r\n }\r\n });\r\n}\r\n\r\n/**\r\n * Converts the provided options object to a JSON-formatted string\r\n * with the option to preserve functions. In order for a function\r\n * to be preserved, it needs to follow the format `function (...) {...}`.\r\n * Such a function can also be stringified.\r\n *\r\n * @function _optionsStringify\r\n *\r\n * @param {Object} options - The options object to be converted to a string.\r\n * @param {boolean} allowFunctions - If set to true, functions are preserved\r\n * in the output. Otherwise an error is thrown.\r\n * @param {boolean} stringifyFunctions - If set to true, functions are saved\r\n * as strings. The `allowFunctions` must be set to true as well for this to take\r\n * an effect.\r\n *\r\n * @returns {string} The JSON-formatted string representing the options.\r\n *\r\n * @throws {Error} Throws an `Error` when functions are not allowed but are\r\n * found in provided options object.\r\n */\r\nexport function _optionsStringify(options, allowFunctions, stringifyFunctions) {\r\n const replacerCallback = (_, value) => {\r\n // Trim string values\r\n if (typeof value === 'string') {\r\n value = value.trim();\r\n }\r\n\r\n // If value is a function or stringified function\r\n if (\r\n typeof value === 'function' ||\r\n (typeof value === 'string' &&\r\n value.startsWith('function') &&\r\n value.endsWith('}'))\r\n ) {\r\n // If allowFunctions is set to true, preserve functions\r\n if (allowFunctions) {\r\n // Based on the `stringifyFunctions` options, set function values\r\n return stringifyFunctions\r\n ? // As stringified functions\r\n `\"EXP_FUN${(value + '').replaceAll(/\\s+/g, ' ')}EXP_FUN\"`\r\n : // As functions\r\n `EXP_FUN${(value + '').replaceAll(/\\s+/g, ' ')}EXP_FUN`;\r\n } else {\r\n // Throw an error otherwise\r\n throw new Error();\r\n }\r\n }\r\n\r\n // In all other cases, simply return the value\r\n return value;\r\n };\r\n\r\n // Stringify options and if required, replace special functions marks\r\n return JSON.stringify(options, replacerCallback).replaceAll(\r\n stringifyFunctions ? /\\\\\"EXP_FUN|EXP_FUN\\\\\"/g : /\"EXP_FUN|EXP_FUN\"/g,\r\n ''\r\n );\r\n}\r\n\r\n/**\r\n * Loads additional configuration from a specified file provided via\r\n * the `loadConfig` option in the command-line arguments.\r\n *\r\n * @function _loadConfigFile\r\n *\r\n * @param {Array.} cliArgs - Command-line arguments to search\r\n * for the `loadConfig` option and the corresponding file path.\r\n * @param {Object} customLogicOptions - The configuration object containing\r\n * `customLogic` options.\r\n *\r\n * @returns {Object} The additional configuration loaded from the specified\r\n * file, or an empty object if the file is not found, invalid, or an error\r\n * occurs.\r\n */\r\nfunction _loadConfigFile(cliArgs, customLogicOptions) {\r\n // Check if the `loadConfig` option was used\r\n const configIndex = cliArgs.findIndex(\r\n (arg) => arg.replace(/-/g, '') === 'loadConfig'\r\n );\r\n\r\n // Get the `loadConfig` option value\r\n const configFileName = configIndex > -1 && cliArgs[configIndex + 1];\r\n\r\n // Check if the `loadConfig` is present and has a correct value\r\n if (configFileName && customLogicOptions.allowFileResources) {\r\n try {\r\n // Load an optional custom JSON config file\r\n return isAllowedConfig(\r\n readFileSync(getAbsolutePath(configFileName), 'utf8'),\r\n false,\r\n customLogicOptions.allowCodeExecution\r\n );\r\n } catch (error) {\r\n logWithStack(\r\n 2,\r\n error,\r\n `[config] Unable to load the configuration from the ${configFileName} file.`\r\n );\r\n }\r\n }\r\n\r\n // No additional options to return\r\n return {};\r\n}\r\n\r\n/**\r\n * Parses command-line arguments and pairs each argument with its corresponding\r\n * option in the configuration. The values are structured into a nested options\r\n * object, based on predefined mappings.\r\n *\r\n * @function _pairArgumentValue\r\n *\r\n * @param {Array.} nestedProps - An array of nesting level for all\r\n * options.\r\n * @param {Array.} cliArgs - An array of command-line arguments\r\n * containing options and their associated values.\r\n *\r\n * @returns {Object} An updated options object where each option from\r\n * the command-line is paired with its value, structured into nested objects\r\n * as defined.\r\n */\r\nfunction _pairArgumentValue(nestedProps, cliArgs) {\r\n // An empty object to collect and structurize data from the args\r\n const cliOptions = {};\r\n\r\n // Cycle through all CLI args and filter them\r\n for (let i = 0; i < cliArgs.length; i++) {\r\n const option = cliArgs[i].replace(/-/g, '');\r\n\r\n // Find the right place for property's value\r\n const propertiesChain = nestedProps[option]\r\n ? nestedProps[option].split('.')\r\n : [];\r\n\r\n // Create options object with values from CLI for later parsing and merging\r\n propertiesChain.reduce((obj, prop, index) => {\r\n if (propertiesChain.length - 1 === index) {\r\n const value = cliArgs[++i];\r\n if (!value) {\r\n log(\r\n 2,\r\n `[config] Missing value for the CLI '--${option}' argument. Using the default value.`\r\n );\r\n }\r\n obj[prop] = value || null;\r\n } else if (obj[prop] === undefined) {\r\n obj[prop] = {};\r\n }\r\n return obj[prop];\r\n }, cliOptions);\r\n }\r\n\r\n // Return parsed CLI options\r\n return cliOptions;\r\n}\r\n\r\n/**\r\n * Recursively traverses the options object to print the usage information\r\n * for each option category and individual option.\r\n *\r\n * @function _cycleCategories\r\n *\r\n * @param {Object} options - The options object containing CLI options. It may\r\n * include nested categories and individual options.\r\n */\r\nfunction _cycleCategories(options) {\r\n for (const [name, option] of Object.entries(options)) {\r\n // If the current entry is a category and not a leaf option, recurse into it\r\n if (!Object.prototype.hasOwnProperty.call(option, 'value')) {\r\n _cycleCategories(option);\r\n } else {\r\n // Prepare description\r\n const descName = ` --${option.cliName || name}`;\r\n\r\n // Get the value\r\n let optionValue = option.value;\r\n\r\n // Prepare value for option that is not null and is array of strings\r\n if (optionValue !== null && option.types.includes('string[]')) {\r\n optionValue =\r\n '[' + optionValue.map((item) => `'${item}'`).join(', ') + ']';\r\n }\r\n\r\n // Prepare value for option that is not null and is a string\r\n if (optionValue !== null && option.types.includes('string')) {\r\n optionValue = `'${optionValue}'`;\r\n }\r\n\r\n // Display correctly aligned messages\r\n console.log(\r\n descName.green,\r\n `${('<' + option.types.join('|') + '>').yellow}`,\r\n `${String(optionValue).bold}`.blue,\r\n `- ${option.description}.`\r\n );\r\n }\r\n }\r\n}\r\n\r\nexport default {\r\n getOptions,\r\n setGlobalOptions,\r\n updateOptions,\r\n mergeOptions,\r\n mapToNewOptions,\r\n isAllowedConfig,\r\n printLicense,\r\n printUsage,\r\n printVersion\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * @overview HTTP utility module for fetching and posting data. Supports both\r\n * HTTP and HTTPS protocols, providing methods to make GET and POST requests\r\n * with customizable options. Includes protocol determination based on URL\r\n * and augments response objects with a 'text' property for easier data access.\r\n */\r\n\r\nimport http from 'http';\r\nimport https from 'https';\r\n\r\n/**\r\n * Fetches data from the specified URL using either HTTP or HTTPS protocol.\r\n *\r\n * @async\r\n * @function fetch\r\n *\r\n * @param {string} url - The URL to fetch data from.\r\n * @param {Object} [requestOptions={}] - Options for the HTTP/HTTPS request.\r\n * The default value is an empty object.\r\n *\r\n * @returns {Promise} A Promise that resolves to the HTTP/HTTPS response\r\n * object with added 'text' property or rejecting with an error.\r\n */\r\nexport async function fetch(url, requestOptions = {}) {\r\n return new Promise((resolve, reject) => {\r\n _getProtocolModule(url)\r\n .get(url, requestOptions, (response) => {\r\n let responseData = '';\r\n\r\n // A chunk of data has been received\r\n response.on('data', (chunk) => {\r\n responseData += chunk;\r\n });\r\n\r\n // The whole response has been received\r\n response.on('end', () => {\r\n if (!responseData) {\r\n reject('Nothing was fetched from the URL.');\r\n }\r\n response.text = responseData;\r\n resolve(response);\r\n });\r\n })\r\n .on('error', (error) => {\r\n reject(error);\r\n });\r\n });\r\n}\r\n\r\n/**\r\n * Sends a POST request to the specified URL with the provided JSON body using\r\n * either HTTP or HTTPS protocol.\r\n *\r\n * @async\r\n * @function post\r\n *\r\n * @param {string} url - The URL to send the POST request to.\r\n * @param {Object} [body={}] - The JSON body to include in the POST request.\r\n * The default value is an empty object.\r\n * @param {Object} [requestOptions={}] - Options for the HTTP/HTTPS request.\r\n * The default value is an empty object.\r\n *\r\n * @returns {Promise} A Promise that resolves to the HTTP/HTTPS response\r\n * object with added 'text' property or rejecting with an error.\r\n */\r\nexport async function post(url, body = {}, requestOptions = {}) {\r\n return new Promise((resolve, reject) => {\r\n const data = JSON.stringify(body);\r\n\r\n // Set default headers and merge with requestOptions\r\n const options = Object.assign(\r\n {\r\n method: 'POST',\r\n headers: {\r\n 'Content-Type': 'application/json',\r\n 'Content-Length': data.length\r\n }\r\n },\r\n requestOptions\r\n );\r\n\r\n const request = _getProtocolModule(url)\r\n .request(url, options, (response) => {\r\n let responseData = '';\r\n\r\n // A chunk of data has been received\r\n response.on('data', (chunk) => {\r\n responseData += chunk;\r\n });\r\n\r\n // The whole response has been received\r\n response.on('end', () => {\r\n try {\r\n response.text = responseData;\r\n resolve(response);\r\n } catch (error) {\r\n reject(error);\r\n }\r\n });\r\n })\r\n .on('error', (error) => {\r\n reject(error);\r\n });\r\n\r\n // Write the request body and end the request\r\n request.write(data);\r\n request.end();\r\n });\r\n}\r\n\r\n/**\r\n * Returns the HTTP or HTTPS protocol module based on the provided URL.\r\n *\r\n * @function _getProtocolModule\r\n *\r\n * @param {string} url - The URL to determine the protocol.\r\n *\r\n * @returns {Object} The HTTP or HTTPS protocol module (http or https).\r\n */\r\nfunction _getProtocolModule(url) {\r\n return url.startsWith('https') ? https : http;\r\n}\r\n\r\nexport default {\r\n fetch,\r\n post\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * A custom error class for handling export-related errors. Extends the native\r\n * `Error` class to include additional properties like status code and stack\r\n * trace details.\r\n */\r\nclass ExportError extends Error {\r\n /**\r\n * Creates an instance of the `ExportError`.\r\n *\r\n * @param {string} message - The error message to be displayed.\r\n * @param {number} statusCode - Optional HTTP status code associated\r\n * with the error (e.g., 400, 500).\r\n */\r\n constructor(message, statusCode) {\r\n super();\r\n\r\n this.message = message;\r\n this.stackMessage = message;\r\n\r\n if (statusCode) {\r\n this.statusCode = statusCode;\r\n }\r\n }\r\n\r\n /**\r\n * Sets or updates the HTTP status code for the error.\r\n *\r\n * @param {number} statusCode - The HTTP status code to assign to the error.\r\n *\r\n * @returns {ExportError} The updated instance of the `ExportError` class.\r\n */\r\n setStatus(statusCode) {\r\n this.statusCode = statusCode;\r\n\r\n return this;\r\n }\r\n\r\n /**\r\n * Sets additional error details based on an existing error object.\r\n *\r\n * @param {Error} error - An error object containing details to populate\r\n * the `ExportError` instance.\r\n *\r\n * @returns {ExportError} The updated instance of the `ExportError` class.\r\n */\r\n setError(error) {\r\n this.error = error;\r\n\r\n if (error.name) {\r\n this.name = error.name;\r\n }\r\n\r\n if (error.statusCode) {\r\n this.statusCode = error.statusCode;\r\n }\r\n\r\n if (error.stack) {\r\n this.stackMessage = error.message;\r\n this.stack = error.stack;\r\n }\r\n\r\n return this;\r\n }\r\n}\r\n\r\nexport default ExportError;\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * @overview The cache manager is responsible for handling and managing\r\n * the Highcharts library along with its dependencies. It ensures that these\r\n * resources are stored and retrieved efficiently to optimize performance\r\n * and reduce redundant network requests. The cache is stored in the `.cache`\r\n * directory by default, which serves as a dedicated folder for keeping cached\r\n * files.\r\n */\r\n\r\nimport { existsSync, mkdirSync, readFileSync, writeFileSync } from 'fs';\r\nimport { join } from 'path';\r\n\r\nimport { HttpsProxyAgent } from 'https-proxy-agent';\r\n\r\nimport { getOptions } from './config.js';\r\nimport { fetch } from './fetch.js';\r\nimport { log } from './logger.js';\r\nimport { __dirname, getAbsolutePath } from './utils.js';\r\n\r\nimport ExportError from './errors/ExportError.js';\r\n\r\n// The initial cache template\r\nconst cache = {\r\n cdnUrl: 'https://code.highcharts.com',\r\n activeManifest: {},\r\n sources: '',\r\n hcVersion: ''\r\n};\r\n\r\n/**\r\n * Checks the cache for Highcharts dependencies, updates the cache if needed,\r\n * and loads the sources.\r\n *\r\n * @async\r\n * @function checkAndUpdateCache\r\n *\r\n * @param {Object} highchartsOptions - The configuration object containing\r\n * `highcharts` options.\r\n * @param {Object} serverProxyOptions- The configuration object containing\r\n * `server.proxy` options.\r\n */\r\nexport async function checkAndUpdateCache(\r\n highchartsOptions,\r\n serverProxyOptions\r\n) {\r\n try {\r\n let fetchedModules;\r\n\r\n // Get the cache path\r\n const cachePath = getCachePath();\r\n\r\n // Prepare paths to manifest and sources from the cache folder\r\n const manifestPath = join(cachePath, 'manifest.json');\r\n const sourcePath = join(cachePath, 'sources.js');\r\n\r\n // Create the cache destination if it doesn't exist already\r\n !existsSync(cachePath) && mkdirSync(cachePath, { recursive: true });\r\n\r\n // Fetch all the scripts either if the `manifest.json` does not exist\r\n // or if the `forceFetch` option is enabled\r\n if (!existsSync(manifestPath) || highchartsOptions.forceFetch) {\r\n log(3, '[cache] Fetching and caching Highcharts dependencies.');\r\n fetchedModules = await _updateCache(\r\n highchartsOptions,\r\n serverProxyOptions,\r\n sourcePath\r\n );\r\n } else {\r\n let requestUpdate = false;\r\n\r\n // Read the manifest JSON\r\n const manifest = JSON.parse(readFileSync(manifestPath), 'utf8');\r\n\r\n // Check if the modules is an array, if so, we rewrite it to a map to make\r\n // it easier to resolve modules.\r\n if (manifest.modules && Array.isArray(manifest.modules)) {\r\n const moduleMap = {};\r\n manifest.modules.forEach((m) => (moduleMap[m] = 1));\r\n manifest.modules = moduleMap;\r\n }\r\n\r\n // Get the actual number of scripts to be fetched\r\n const { coreScripts, moduleScripts, indicatorScripts } =\r\n highchartsOptions;\r\n const numberOfModules =\r\n coreScripts.length + moduleScripts.length + indicatorScripts.length;\r\n\r\n // Compare the loaded highcharts config with the contents in cache.\r\n // If there are changes, fetch requested modules and products,\r\n // and bake them into a giant blob. Save the blob.\r\n if (manifest.version !== highchartsOptions.version) {\r\n log(\r\n 2,\r\n '[cache] A Highcharts version mismatch in the cache, need to re-fetch.'\r\n );\r\n requestUpdate = true;\r\n } else if (\r\n Object.keys(manifest.modules || {}).length !== numberOfModules\r\n ) {\r\n log(\r\n 2,\r\n '[cache] The cache and the requested modules do not match, need to re-fetch.'\r\n );\r\n requestUpdate = true;\r\n } else {\r\n // Check each module, if anything is missing refetch everything\r\n requestUpdate = (moduleScripts || []).some((moduleName) => {\r\n if (!manifest.modules[moduleName]) {\r\n log(\r\n 2,\r\n `[cache] The ${moduleName} is missing in the cache, need to re-fetch.`\r\n );\r\n return true;\r\n }\r\n });\r\n }\r\n\r\n // Update cache if needed\r\n if (requestUpdate) {\r\n fetchedModules = await _updateCache(\r\n highchartsOptions,\r\n serverProxyOptions,\r\n sourcePath\r\n );\r\n } else {\r\n log(3, '[cache] Dependency cache is up to date, proceeding.');\r\n\r\n // Load the sources\r\n cache.sources = readFileSync(sourcePath, 'utf8');\r\n\r\n // Get current modules map\r\n fetchedModules = manifest.modules;\r\n\r\n // Extract and save version of currently used Highcharts\r\n cache.hcVersion = extractVersion(cache.sources);\r\n }\r\n }\r\n\r\n // Finally, save the new manifest, which is basically our current config\r\n // in a slightly different format\r\n await _saveConfigToManifest(highchartsOptions, fetchedModules);\r\n } catch (error) {\r\n throw new ExportError(\r\n '[cache] Could not configure cache and create or update the config manifest.',\r\n 500\r\n ).setError(error);\r\n }\r\n}\r\n\r\n/**\r\n * Gets the version of Highcharts from the cache.\r\n *\r\n * @function getHighchartsVersion\r\n *\r\n * @returns {string} The cached Highcharts version.\r\n */\r\nexport function getHighchartsVersion() {\r\n return cache.hcVersion;\r\n}\r\n\r\n/**\r\n * Updates the Highcharts version in the applied configuration and checks\r\n * the cache for the new version.\r\n *\r\n * @async\r\n * @function updateHighchartsVersion\r\n *\r\n * @param {string} newVersion - The new Highcharts version to be applied.\r\n */\r\nexport async function updateHighchartsVersion(newVersion) {\r\n // Get the reference to the global options to update to the new version\r\n const options = getOptions();\r\n\r\n // Set to the new version\r\n options.highcharts.version = newVersion;\r\n\r\n // Check if cache needs to be updated\r\n await checkAndUpdateCache(options.highcharts, options.server.proxy);\r\n}\r\n\r\n/**\r\n * Extracts Highcharts version from the cache's sources string.\r\n *\r\n * @function extractVersion\r\n *\r\n * @param {Object} cacheSources - The cache sources object.\r\n *\r\n * @returns {string} The extracted Highcharts version.\r\n */\r\nexport function extractVersion(cacheSources) {\r\n return cacheSources\r\n .substring(0, cacheSources.indexOf('*/'))\r\n .replace('/*', '')\r\n .replace('*/', '')\r\n .replace(/\\n/g, '')\r\n .trim();\r\n}\r\n\r\n/**\r\n * Extracts the Highcharts module name based on the scriptPath.\r\n *\r\n * @function extractModuleName\r\n *\r\n * @param {string} scriptPath - The path of the script from which the module\r\n * name will be extracted.\r\n *\r\n * @returns {string} The extracted module name.\r\n */\r\nexport function extractModuleName(scriptPath) {\r\n return scriptPath.replace(\r\n /(.*)\\/|(.*)modules\\/|stock\\/(.*)indicators\\/|maps\\/(.*)modules\\//gi,\r\n ''\r\n );\r\n}\r\n\r\n/**\r\n * Retrieves the current cache object.\r\n *\r\n * @function getCache\r\n *\r\n * @returns {Object} The cache object containing various cached data.\r\n */\r\nexport function getCache() {\r\n return cache;\r\n}\r\n\r\n/**\r\n * Gets the cache path for Highcharts.\r\n *\r\n * @function getCachePath\r\n *\r\n * @returns {string} The absolute path to the cache directory for Highcharts.\r\n */\r\nexport function getCachePath() {\r\n return getAbsolutePath(getOptions().highcharts.cachePath, 'utf8'); // #562\r\n}\r\n\r\n/**\r\n * Fetches a single script and updates the `fetchedModules` accordingly.\r\n *\r\n * @async\r\n * @function _fetchAndProcessScript\r\n *\r\n * @param {string} script - A path to script to get.\r\n * @param {Object} requestOptions - Additional options for the proxy agent\r\n * to use for a request.\r\n * @param {Object} fetchedModules - An object which tracks which Highcharts\r\n * modules have been fetched.\r\n * @param {boolean} [shouldThrowError=false] - A flag to indicate if the error\r\n * should be thrown. This should be used only for the core scripts. The default\r\n * value is `false`.\r\n *\r\n * @returns {Promise} A Promise that resolves to the text representation\r\n * of the fetched script.\r\n *\r\n * @throws {ExportError} Throws an `ExportError` if there is a problem\r\n * with fetching the script.\r\n */\r\nasync function _fetchAndProcessScript(\r\n script,\r\n requestOptions,\r\n fetchedModules,\r\n shouldThrowError = false\r\n) {\r\n // Get rid of the .js from the custom strings\r\n if (script.endsWith('.js')) {\r\n script = script.substring(0, script.length - 3);\r\n }\r\n log(4, `[cache] Fetching script - ${script}.js`);\r\n\r\n // Fetch the script\r\n const response = await fetch(`${script}.js`, requestOptions);\r\n\r\n // If OK, return its text representation\r\n if (response.statusCode === 200 && typeof response.text == 'string') {\r\n if (fetchedModules) {\r\n const moduleName = extractModuleName(script);\r\n fetchedModules[moduleName] = 1;\r\n }\r\n return response.text;\r\n }\r\n\r\n // Based on the `shouldThrowError` flag, decide how to serve error message\r\n if (shouldThrowError) {\r\n throw new ExportError(\r\n `[cache] Could not fetch the ${script}.js. The script might not exist in the requested version (status code: ${response.statusCode}).`,\r\n 404\r\n ).setError(response);\r\n } else {\r\n log(\r\n 2,\r\n `[cache] Could not fetch the ${script}.js. The script might not exist in the requested version.`\r\n );\r\n }\r\n}\r\n\r\n/**\r\n * Saves the provided configuration and fetched modules to the cache manifest\r\n * file.\r\n *\r\n * @async\r\n * @function _saveConfigToManifest\r\n *\r\n * @param {Object} highchartsOptions - The configuration object containing\r\n * `highcharts` options.\r\n * @param {Object} [fetchedModules={}] - An object which tracks which Highcharts\r\n * modules have been fetched. The default value is an empty object.\r\n *\r\n * @throws {ExportError} Throws an `ExportError` if an error occurs while\r\n * writing the cache manifest.\r\n */\r\nasync function _saveConfigToManifest(highchartsOptions, fetchedModules = {}) {\r\n const newManifest = {\r\n version: highchartsOptions.version,\r\n modules: fetchedModules\r\n };\r\n\r\n // Update cache object with the current modules\r\n cache.activeManifest = newManifest;\r\n\r\n log(3, '[cache] Writing a new manifest.');\r\n try {\r\n writeFileSync(\r\n join(getCachePath(), 'manifest.json'),\r\n JSON.stringify(newManifest),\r\n 'utf8'\r\n );\r\n } catch (error) {\r\n throw new ExportError(\r\n '[cache] Error writing the cache manifest.',\r\n 500\r\n ).setError(error);\r\n }\r\n}\r\n\r\n/**\r\n * Fetches Highcharts `scripts` and `customScripts` from the given CDNs.\r\n *\r\n * @async\r\n * @function _fetchScripts\r\n *\r\n * @param {Array.} coreScripts - Highcharts core scripts to fetch.\r\n * @param {Array.} moduleScripts - Highcharts modules to fetch.\r\n * @param {Array.} customScripts - Custom script paths to fetch (full\r\n * URLs).\r\n * @param {Object} serverProxyOptions - The configuration object containing\r\n * `server.proxy` options.\r\n * @param {Object} fetchedModules - An object which tracks which Highcharts\r\n * modules have been fetched.\r\n *\r\n * @returns {Promise} A Promise that resolves to the fetched scripts\r\n * content joined.\r\n *\r\n * @throws {ExportError} Throws an `ExportError` if an error occurs while\r\n * setting an HTTP Agent for proxy.\r\n */\r\nasync function _fetchScripts(\r\n coreScripts,\r\n moduleScripts,\r\n customScripts,\r\n serverProxyOptions,\r\n fetchedModules\r\n) {\r\n // Configure proxy if exists\r\n let proxyAgent;\r\n const proxyHost = serverProxyOptions.host;\r\n const proxyPort = serverProxyOptions.port;\r\n\r\n // Try to create a Proxy Agent\r\n if (proxyHost && proxyPort) {\r\n try {\r\n proxyAgent = new HttpsProxyAgent({\r\n host: proxyHost,\r\n port: proxyPort\r\n });\r\n } catch (error) {\r\n throw new ExportError(\r\n '[cache] Could not create a Proxy Agent.',\r\n 500\r\n ).setError(error);\r\n }\r\n }\r\n\r\n // If exists, add proxy agent to request options\r\n const requestOptions = proxyAgent\r\n ? {\r\n agent: proxyAgent,\r\n timeout: serverProxyOptions.timeout\r\n }\r\n : {};\r\n\r\n const allFetchPromises = [\r\n ...coreScripts.map((script) =>\r\n _fetchAndProcessScript(`${script}`, requestOptions, fetchedModules, true)\r\n ),\r\n ...moduleScripts.map((script) =>\r\n _fetchAndProcessScript(`${script}`, requestOptions, fetchedModules)\r\n ),\r\n ...customScripts.map((script) =>\r\n _fetchAndProcessScript(`${script}`, requestOptions)\r\n )\r\n ];\r\n\r\n const fetchedScripts = await Promise.all(allFetchPromises);\r\n return fetchedScripts.join(';\\n');\r\n}\r\n\r\n/**\r\n * Updates the local cache with Highcharts scripts and their versions.\r\n *\r\n * @async\r\n * @function _updateCache\r\n *\r\n * @param {Object} highchartsOptions - The configuration object containing\r\n * `highcharts` options.\r\n * @param {Object} serverProxyOptions - The configuration object containing\r\n * `server.proxy` options.\r\n * @param {string} sourcePath - The path to the source file in the cache.\r\n *\r\n * @returns {Promise} A Promise that resolves to an object representing\r\n * the fetched modules.\r\n *\r\n * @throws {ExportError} Throws an `ExportError` if there is an issue updating\r\n * the local Highcharts cache.\r\n */\r\nasync function _updateCache(highchartsOptions, serverProxyOptions, sourcePath) {\r\n // Get Highcharts version for scripts\r\n const hcVersion =\r\n highchartsOptions.version === 'latest'\r\n ? null\r\n : `${highchartsOptions.version}`;\r\n\r\n // Get the CDN url for scripts\r\n const cdnUrl = highchartsOptions.cdnUrl || cache.cdnUrl;\r\n\r\n try {\r\n const fetchedModules = {};\r\n\r\n log(\r\n 3,\r\n `[cache] Updating cache version to Highcharts: ${hcVersion || 'latest'}.`\r\n );\r\n\r\n cache.sources = await _fetchScripts(\r\n [\r\n ...highchartsOptions.coreScripts.map((c) =>\r\n hcVersion ? `${cdnUrl}/${hcVersion}/${c}` : `${cdnUrl}/${c}`\r\n )\r\n ],\r\n [\r\n ...highchartsOptions.moduleScripts.map((m) =>\r\n m === 'map'\r\n ? hcVersion\r\n ? `${cdnUrl}/maps/${hcVersion}/modules/${m}`\r\n : `${cdnUrl}/maps/modules/${m}`\r\n : hcVersion\r\n ? `${cdnUrl}/${hcVersion}/modules/${m}`\r\n : `${cdnUrl}/modules/${m}`\r\n ),\r\n ...highchartsOptions.indicatorScripts.map((i) =>\r\n hcVersion\r\n ? `${cdnUrl}/stock/${hcVersion}/indicators/${i}`\r\n : `${cdnUrl}/stock/indicators/${i}`\r\n )\r\n ],\r\n highchartsOptions.customScripts,\r\n serverProxyOptions,\r\n fetchedModules\r\n );\r\n\r\n // Extract and save version of currently used Highcharts\r\n cache.hcVersion = extractVersion(cache.sources);\r\n\r\n // Save the fetched modules into caches' source JSON\r\n writeFileSync(sourcePath, cache.sources);\r\n return fetchedModules;\r\n } catch (error) {\r\n throw new ExportError(\r\n '[cache] Unable to update the local Highcharts cache.',\r\n 500\r\n ).setError(error);\r\n }\r\n}\r\n\r\nexport default {\r\n checkAndUpdateCache,\r\n getHighchartsVersion,\r\n updateHighchartsVersion,\r\n extractVersion,\r\n extractModuleName,\r\n getCache,\r\n getCachePath\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * @overview Provides methods for initializing Highcharts with customized\r\n * animation settings and triggering the creation of Highcharts charts with\r\n * export-specific configurations in the page context. Supports dynamic option\r\n * merging, custom logic injection, and control over rendering behaviors. Used\r\n * by the Puppeteer page.\r\n */\r\n\r\n/* eslint-disable no-undef */\r\n\r\n/**\r\n * Setting the `Highcharts.animObject` function. Called when initing the page.\r\n *\r\n * @function setupHighcharts\r\n */\r\nexport function setupHighcharts() {\r\n Highcharts.animObject = function () {\r\n return { duration: 0 };\r\n };\r\n}\r\n\r\n/**\r\n * Creates the actual Highcharts chart on a page.\r\n *\r\n * @async\r\n * @function createChart\r\n *\r\n * @param {Object} exportOptions - The configuration object containing `export`\r\n * options.\r\n * @param {Object} customLogicOptions - The configuration object containing\r\n * `customLogic` options.\r\n *\r\n */\r\nexport async function createChart(exportOptions, customLogicOptions) {\r\n // Get required functions\r\n const { getOptions, setOptions, merge, wrap } = Highcharts;\r\n\r\n // Create a separate object for a potential `setOptions` usages in order\r\n // to prevent from polluting other exports that can happen on the same page\r\n Highcharts.setOptionsObj = merge(false, {}, getOptions());\r\n\r\n // NOTE: Is this used for anything useful?\r\n window.isRenderComplete = false;\r\n wrap(Highcharts.Chart.prototype, 'init', function (proceed, userOptions, cb) {\r\n // Override the `userOptions` with image friendly options\r\n userOptions = merge(userOptions, {\r\n exporting: {\r\n enabled: false\r\n },\r\n plotOptions: {\r\n series: {\r\n label: {\r\n enabled: false\r\n }\r\n }\r\n },\r\n /* Expects tooltip in the `userOptions` when `forExport` is true.\r\n https://github.com/highcharts/highcharts/blob/3ad430a353b8056b9e764aa4e5cd6828aa479db2/js/parts/Chart.js#L241\r\n */\r\n tooltip: {}\r\n });\r\n\r\n (userOptions.series || []).forEach(function (series) {\r\n series.animation = false;\r\n });\r\n\r\n // Add flag to know if chart render has been called.\r\n if (!window.onHighchartsRender) {\r\n window.onHighchartsRender = Highcharts.addEvent(this, 'render', () => {\r\n window.isRenderComplete = true;\r\n });\r\n }\r\n\r\n proceed.apply(this, [userOptions, cb]);\r\n });\r\n\r\n wrap(Highcharts.Series.prototype, 'init', function (proceed, chart, options) {\r\n proceed.apply(this, [chart, options]);\r\n });\r\n\r\n // Some mandatory additional `chart` and `exporting` options\r\n const additionalOptions = {\r\n chart: {\r\n // By default animation is disabled\r\n animation: false,\r\n // Get the right size values\r\n height: exportOptions.height,\r\n width: exportOptions.width\r\n },\r\n exporting: {\r\n // No need for the exporting button\r\n enabled: false\r\n }\r\n };\r\n\r\n // Get the input to export from the `instr` option\r\n const userOptions = new Function(`return ${exportOptions.instr}`)();\r\n\r\n // Get the `themeOptions` option\r\n const themeOptions = new Function(`return ${exportOptions.themeOptions}`)();\r\n\r\n // Get the `globalOptions` option\r\n const globalOptions = new Function(`return ${exportOptions.globalOptions}`)();\r\n\r\n // Merge the following options objects to create final options\r\n const finalOptions = merge(\r\n false,\r\n themeOptions,\r\n userOptions,\r\n // Placed it here instead in the init because of the size issues\r\n additionalOptions\r\n );\r\n\r\n // Prepare the `callback` option\r\n const finalCallback = customLogicOptions.callback\r\n ? new Function(`return ${customLogicOptions.callback}`)()\r\n : null;\r\n\r\n // Trigger the `customCode` option\r\n if (customLogicOptions.customCode) {\r\n new Function('options', customLogicOptions.customCode)(userOptions);\r\n }\r\n\r\n // Set the global options if exist\r\n if (globalOptions) {\r\n setOptions(globalOptions);\r\n }\r\n\r\n // Call the chart creation\r\n Highcharts[exportOptions.constr]('container', finalOptions, finalCallback);\r\n\r\n // Get the current global options\r\n const defaultOptions = getOptions();\r\n\r\n // Clear it just in case (e.g. the `setOptions` was used in the `customCode`)\r\n for (const prop in defaultOptions) {\r\n if (typeof defaultOptions[prop] !== 'function') {\r\n delete defaultOptions[prop];\r\n }\r\n }\r\n\r\n // Set the default options back\r\n setOptions(Highcharts.setOptionsObj);\r\n\r\n // Empty the custom global options object\r\n Highcharts.setOptionsObj = {};\r\n}\r\n\r\nexport default {\r\n setupHighcharts,\r\n createChart\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * @overview This module provides functions for managing Puppeteer browser\r\n * instance, creating and clearing pages, injecting custom resources,\r\n * and setting up Highcharts for server-side rendering. The module ensures\r\n * that resources are correctly managed and can handle failures during\r\n * operations like launching the browser or creating new pages.\r\n */\r\n\r\nimport { readFileSync } from 'fs';\r\nimport { join } from 'path';\r\n\r\nimport puppeteer from 'puppeteer';\r\n\r\nimport { getCachePath } from './cache.js';\r\nimport { getOptions } from './config.js';\r\nimport { setupHighcharts } from './highcharts.js';\r\nimport { log, logWithStack } from './logger.js';\r\nimport { __dirname, getAbsolutePath } from './utils.js';\r\n\r\nimport ExportError from './errors/ExportError.js';\r\n\r\n// Get the template for pages\r\nconst template = readFileSync(\r\n join(__dirname, 'templates', 'template.html'),\r\n 'utf8'\r\n);\r\n\r\n// To save the browser\r\nlet browser = null;\r\n\r\n/**\r\n * Retrieves the existing Puppeteer browser instance.\r\n *\r\n * @function getBrowser\r\n *\r\n * @returns {Object} The Puppeteer browser instance.\r\n *\r\n * @throws {ExportError} Throws an `ExportError` if no valid browser\r\n * has been created.\r\n */\r\nexport function getBrowser() {\r\n if (!browser) {\r\n throw new ExportError('[browser] No valid browser has been created.', 500);\r\n }\r\n return browser;\r\n}\r\n\r\n/**\r\n * Creates a Puppeteer browser instance with the specified arguments.\r\n *\r\n * @async\r\n * @function createBrowser\r\n *\r\n * @param {Array.} puppeteerArgs - Additional arguments for Puppeteer\r\n * launch.\r\n *\r\n * @returns {Promise} A Promise that resolves to the created Puppeteer\r\n * browser instance.\r\n *\r\n * @throws {ExportError} Throws an `ExportError` if max retries to open\r\n * a browser instance are reached, or if no browser instance is found after\r\n * retries.\r\n */\r\nexport async function createBrowser(puppeteerArgs) {\r\n // Get `debug` and `other` options\r\n const { debug, other } = getOptions();\r\n\r\n // Get the `debug` options\r\n const { enable: enabledDebug, ...debugOptions } = debug;\r\n\r\n // Launch options for the browser instance\r\n const launchOptions = {\r\n headless: other.browserShellMode ? 'shell' : true,\r\n userDataDir: 'tmp',\r\n args: puppeteerArgs || [],\r\n handleSIGINT: false,\r\n handleSIGTERM: false,\r\n handleSIGHUP: false,\r\n waitForInitialPage: false,\r\n defaultViewport: null,\r\n ...(enabledDebug && debugOptions)\r\n };\r\n\r\n // Create a browser\r\n if (!browser) {\r\n // A counter for the browser's launch retries\r\n let tryCount = 0;\r\n\r\n const open = async () => {\r\n try {\r\n log(\r\n 3,\r\n `[browser] Attempting to get a browser instance (try ${++tryCount}).`\r\n );\r\n\r\n // Launch the browser\r\n browser = await puppeteer.launch(launchOptions);\r\n } catch (error) {\r\n logWithStack(\r\n 1,\r\n error,\r\n '[browser] Failed to launch a browser instance.'\r\n );\r\n\r\n // Retry to launch browser until reaching max attempts\r\n if (tryCount < 25) {\r\n log(3, `[browser] Retry to open a browser (${tryCount} out of 25).`);\r\n\r\n // Wait for a 4 seconds before trying again\r\n await new Promise((response) => setTimeout(response, 4000));\r\n await open();\r\n } else {\r\n throw error;\r\n }\r\n }\r\n };\r\n\r\n try {\r\n await open();\r\n\r\n // Shell mode inform\r\n if (launchOptions.headless === 'shell') {\r\n log(3, `[browser] Launched browser in shell mode.`);\r\n }\r\n\r\n // Debug mode inform\r\n if (enabledDebug) {\r\n log(3, `[browser] Launched browser in debug mode.`);\r\n }\r\n } catch (error) {\r\n throw new ExportError(\r\n '[browser] Maximum retries to open a browser instance reached.',\r\n 500\r\n ).setError(error);\r\n }\r\n\r\n if (!browser) {\r\n throw new ExportError('[browser] Cannot find a browser to open.', 500);\r\n }\r\n }\r\n\r\n // Return a browser instance\r\n return browser;\r\n}\r\n\r\n/**\r\n * Closes the Puppeteer browser instance if it is connected.\r\n *\r\n * @async\r\n * @function closeBrowser\r\n */\r\nexport async function closeBrowser() {\r\n // Close the browser when connected\r\n if (browser && browser.connected) {\r\n await browser.close();\r\n }\r\n browser = null;\r\n log(4, '[browser] Closed the browser.');\r\n}\r\n\r\n/**\r\n * Creates a new Puppeteer page within an existing browser instance.\r\n * The function creates a new page, disables caching, sets content using\r\n * the `_setPageContent()`, and returns the created Puppeteer page.\r\n *\r\n * @async\r\n * @function newPage\r\n *\r\n * @param {Object} poolResource - The pool resource that contains `id`,\r\n * `workCount`, and `page`.\r\n *\r\n * @throws {ExportError} Throws an `ExportError` if no valid browser\r\n * has been connected or if a page is invalid or closed.\r\n */\r\nexport async function newPage(poolResource) {\r\n // Error in case of no connected browser\r\n if (!browser || !browser.connected) {\r\n throw new ExportError(`[browser] Browser is not yet connected.`, 500);\r\n }\r\n\r\n // Create a page\r\n poolResource.page = await browser.newPage();\r\n\r\n // Disable cache\r\n await poolResource.page.setCacheEnabled(false);\r\n\r\n // Set the content\r\n await _setPageContent(poolResource.page);\r\n\r\n // Set page events\r\n _setPageEvents(poolResource.page);\r\n\r\n // Check if the page is correctly created\r\n if (!poolResource.page || poolResource.page.isClosed()) {\r\n throw new ExportError('[browser] The page is invalid or closed.', 400);\r\n }\r\n}\r\n\r\n/**\r\n * Clears the content of a Puppeteer Page based on the specified mode. Logs\r\n * thrown error if clearing of a page's content fails.\r\n *\r\n * @async\r\n * @function clearPage\r\n *\r\n * @param {Object} poolResource - The pool resource that contains page and id.\r\n * @param {boolean} [hardReset=false] - A flag indicating the type of clearing\r\n * to be performed. If true, navigates to `about:blank` and resets content\r\n * and scripts. If false, clears the body content by setting a predefined HTML\r\n * structure. The default value is `false`.\r\n *\r\n * @returns {Promise} A Promise that resolves to true when page\r\n * is correctly cleared and false when it is not.\r\n */\r\nexport async function clearPage(poolResource, hardReset = false) {\r\n try {\r\n if (poolResource.page && !poolResource.page.isClosed()) {\r\n if (hardReset) {\r\n // Navigate to `about:blank`\r\n await poolResource.page.goto('about:blank', {\r\n waitUntil: 'domcontentloaded'\r\n });\r\n\r\n // Set the content and and scripts again\r\n await _setPageContent(poolResource.page);\r\n } else {\r\n // Clear body content\r\n await poolResource.page.evaluate(() => {\r\n document.body.innerHTML =\r\n '
';\r\n });\r\n }\r\n return true;\r\n }\r\n } catch (error) {\r\n logWithStack(\r\n 2,\r\n error,\r\n `[pool] Pool resource [${poolResource.id}] - Content of the page could not be cleared.`\r\n );\r\n\r\n // Set the `workLimit` to exceeded in order to recreate the resource\r\n poolResource.workCount = getOptions().pool.workLimit + 1;\r\n }\r\n return false;\r\n}\r\n\r\n/**\r\n * Adds custom JS and CSS resources to a Puppeteer Page based on the specified\r\n * options.\r\n *\r\n * @async\r\n * @function addPageResources\r\n *\r\n * @param {Object} page - The Puppeteer page object to which resources will\r\n * be added.\r\n * @param {Object} customLogicOptions - The configuration object containing\r\n * `customLogic` options.\r\n *\r\n * @returns {Promise>} A Promise that resolves to an array\r\n * of injected resources.\r\n */\r\nexport async function addPageResources(page, customLogicOptions) {\r\n // Injected resources array\r\n const injectedResources = [];\r\n\r\n // Use resources\r\n const resources = customLogicOptions.resources;\r\n if (resources) {\r\n const injectedJs = [];\r\n\r\n // Load custom JS code\r\n if (resources.js) {\r\n injectedJs.push({\r\n content: resources.js\r\n });\r\n }\r\n\r\n // Load scripts from all custom files\r\n if (resources.files) {\r\n for (const file of resources.files) {\r\n const isLocal = !file.startsWith('http') ? true : false;\r\n\r\n // Add each custom script from resources' files\r\n injectedJs.push(\r\n isLocal\r\n ? {\r\n content: readFileSync(getAbsolutePath(file), 'utf8')\r\n }\r\n : {\r\n url: file\r\n }\r\n );\r\n }\r\n }\r\n\r\n for (const jsResource of injectedJs) {\r\n try {\r\n injectedResources.push(await page.addScriptTag(jsResource));\r\n } catch (error) {\r\n logWithStack(2, error, `[browser] The JS resource cannot be loaded.`);\r\n }\r\n }\r\n injectedJs.length = 0;\r\n\r\n // Load CSS\r\n const injectedCss = [];\r\n if (resources.css) {\r\n let cssImports = resources.css.match(/@import\\s*([^;]*);/g);\r\n if (cssImports) {\r\n // Handle css section\r\n for (let cssImportPath of cssImports) {\r\n if (cssImportPath) {\r\n cssImportPath = cssImportPath\r\n .replace('url(', '')\r\n .replace('@import', '')\r\n .replace(/\"/g, '')\r\n .replace(/'/g, '')\r\n .replace(/;/, '')\r\n .replace(/\\)/g, '')\r\n .trim();\r\n\r\n // Add each custom css from resources\r\n if (cssImportPath.startsWith('http')) {\r\n injectedCss.push({\r\n url: cssImportPath\r\n });\r\n } else if (customLogicOptions.allowFileResources) {\r\n injectedCss.push({\r\n path: join(__dirname, cssImportPath)\r\n });\r\n }\r\n }\r\n }\r\n }\r\n\r\n // The rest of the CSS section will be content by now\r\n injectedCss.push({\r\n content: resources.css.replace(/@import\\s*([^;]*);/g, '') || ' '\r\n });\r\n\r\n for (const cssResource of injectedCss) {\r\n try {\r\n injectedResources.push(await page.addStyleTag(cssResource));\r\n } catch (error) {\r\n logWithStack(\r\n 2,\r\n error,\r\n `[browser] The CSS resource cannot be loaded.`\r\n );\r\n }\r\n }\r\n injectedCss.length = 0;\r\n }\r\n }\r\n return injectedResources;\r\n}\r\n\r\n/**\r\n * Clears out all state set on the page with `addScriptTag` and `addStyleTag`.\r\n * Removes injected resources and resets CSS and script tags on the page.\r\n * Additionally, it destroys previously existing charts.\r\n *\r\n * @async\r\n * @function clearPageResources\r\n *\r\n * @param {Object} page - The Puppeteer page object from which resources will\r\n * be cleared.\r\n * @param {Array.} injectedResources - Array of injected resources\r\n * to be cleared.\r\n */\r\nexport async function clearPageResources(page, injectedResources) {\r\n try {\r\n for (const resource of injectedResources) {\r\n await resource.dispose();\r\n }\r\n\r\n // Destroy old charts after export is done and reset all CSS and script tags\r\n await page.evaluate(() => {\r\n // We are not guaranteed that Highcharts is loaded, when doing SVG exports\r\n if (typeof Highcharts !== 'undefined') {\r\n // eslint-disable-next-line no-undef\r\n const oldCharts = Highcharts.charts;\r\n\r\n // Check in any already existing charts\r\n if (Array.isArray(oldCharts) && oldCharts.length) {\r\n // Destroy old charts\r\n for (const oldChart of oldCharts) {\r\n oldChart && oldChart.destroy();\r\n // eslint-disable-next-line no-undef\r\n Highcharts.charts.shift();\r\n }\r\n }\r\n }\r\n\r\n // eslint-disable-next-line no-undef\r\n const [...scriptsToRemove] = document.getElementsByTagName('script');\r\n // eslint-disable-next-line no-undef\r\n const [, ...stylesToRemove] = document.getElementsByTagName('style');\r\n // eslint-disable-next-line no-undef\r\n const [...linksToRemove] = document.getElementsByTagName('link');\r\n\r\n // Remove tags\r\n for (const element of [\r\n ...scriptsToRemove,\r\n ...stylesToRemove,\r\n ...linksToRemove\r\n ]) {\r\n element.remove();\r\n }\r\n });\r\n } catch (error) {\r\n logWithStack(2, error, `[browser] Could not clear page's resources.`);\r\n }\r\n}\r\n\r\n/**\r\n * Sets the content for a Puppeteer Page using a predefined template\r\n * and additional scripts.\r\n *\r\n * @async\r\n * @function _setPageContent\r\n *\r\n * @param {Object} page - The Puppeteer page object to which the content\r\n * is being set.\r\n */\r\nasync function _setPageContent(page) {\r\n // Set the initial page content\r\n await page.setContent(template, { waitUntil: 'domcontentloaded' });\r\n\r\n // Add all registered Higcharts scripts, quite demanding\r\n await page.addScriptTag({ path: join(getCachePath(), 'sources.js') });\r\n\r\n // Set the initial `animObject` for Highcharts\r\n await page.evaluate(setupHighcharts);\r\n}\r\n\r\n/**\r\n * Set events (like `pageerror` and `console`) for a Puppeteer Page in order\r\n * to catch and display errors and console logs from the window context.\r\n *\r\n * @function _setPageEvents\r\n *\r\n * @param {Object} page - The Puppeteer page object to which the listeners\r\n * are being set.\r\n */\r\nfunction _setPageEvents(page) {\r\n // Get `debug` options\r\n const { debug } = getOptions();\r\n\r\n // Set the `pageerror` listener\r\n page.on('pageerror', async () => {\r\n // It would seem like this may fire at the same time or shortly before\r\n // a page is closed.\r\n if (page.isClosed()) {\r\n return;\r\n }\r\n });\r\n\r\n // Set the `console` listener, if needed\r\n if (debug.enable && debug.listenToConsole) {\r\n page.on('console', (message) => {\r\n console.log(`[debug] ${message.text()}`);\r\n });\r\n }\r\n}\r\n\r\nexport default {\r\n getBrowser,\r\n createBrowser,\r\n closeBrowser,\r\n newPage,\r\n clearPage,\r\n addPageResources,\r\n clearPageResources\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * The CSS to be used on the exported page.\r\n *\r\n * @returns {string} The CSS configuration.\r\n */\r\nexport default () => `\r\n\r\nhtml, body {\r\n margin: 0;\r\n padding: 0;\r\n box-sizing: border-box;\r\n}\r\n\r\n#table-div, #sliders, #datatable, #controls, .ld-row {\r\n display: none;\r\n height: 0;\r\n}\r\n\r\n#chart-container {\r\n box-sizing: border-box;\r\n margin: 0;\r\n overflow: auto;\r\n font-size: 0;\r\n}\r\n\r\n#chart-container > figure, div {\r\n margin-top: 0 !important;\r\n margin-bottom: 0 !important;\r\n}\r\n\r\n`;\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\nimport cssTemplate from './css.js';\r\n\r\n/**\r\n * The SVG template to use when loading SVG content to be exported.\r\n *\r\n * @param {string} svg - The SVG input content to be exported.\r\n *\r\n * @returns {string} The SVG template.\r\n */\r\nexport default (svg) => `\r\n\r\n\r\n \r\n \r\n Highcharts Export\r\n \r\n \r\n \r\n
\r\n ${svg}\r\n
\r\n \r\n\r\n\r\n`;\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * @overview This module handles chart export functionality using Puppeteer.\r\n * It supports exporting charts as SVG, PNG, JPEG, and PDF formats. The module\r\n * manages page resources, sets up the export environment, and processes chart\r\n * configurations or SVG inputs for rendering. Exports to a chart from a page\r\n * using Puppeteer.\r\n */\r\n\r\nimport { addPageResources, clearPageResources } from './browser.js';\r\nimport { createChart } from './highcharts.js';\r\nimport { log } from './logger.js';\r\n\r\nimport svgTemplate from '../templates/svgExport/svgExport.js';\r\n\r\nimport ExportError from './errors/ExportError.js';\r\n\r\n/**\r\n * Exports to a chart from a page using Puppeteer.\r\n *\r\n * @async\r\n * @function puppeteerExport\r\n *\r\n * @param {Object} page - Puppeteer page object.\r\n * @param {Object} exportOptions - The configuration object containing `export`\r\n * options.\r\n * @param {Object} customLogicOptions - The configuration object containing\r\n * `customLogic` options.\r\n *\r\n * @returns {Promise<(string|Buffer|ExportError)>} A Promise that resolves\r\n * to the exported data or rejecting with an `ExportError`.\r\n *\r\n * @throws {ExportError} Throws an `ExportError` if export to an unsupported\r\n * output format occurs.\r\n */\r\nexport async function puppeteerExport(page, exportOptions, customLogicOptions) {\r\n // Injected resources array (additional JS and CSS)\r\n const injectedResources = [];\r\n\r\n try {\r\n let isSVG = false;\r\n\r\n // Decide on the export method\r\n if (exportOptions.svg) {\r\n log(4, '[export] Treating as SVG input.');\r\n\r\n // If the `type` is also SVG, return the input\r\n if (exportOptions.type === 'svg') {\r\n return exportOptions.svg;\r\n }\r\n\r\n // Mark as SVG export for the later size corrections\r\n isSVG = true;\r\n\r\n // SVG export\r\n await page.setContent(svgTemplate(exportOptions.svg), {\r\n waitUntil: 'domcontentloaded'\r\n });\r\n } else {\r\n log(4, '[export] Treating as JSON config.');\r\n\r\n // Options export\r\n await page.evaluate(createChart, exportOptions, customLogicOptions);\r\n }\r\n\r\n // Keeps track of all resources added on the page with addXXXTag. etc\r\n // It's VITAL that all added resources ends up here so we can clear things\r\n // out when doing a new export in the same page!\r\n injectedResources.push(\r\n ...(await addPageResources(page, customLogicOptions))\r\n );\r\n\r\n // Get the real chart size and set the zoom accordingly\r\n const size = isSVG\r\n ? await page.evaluate((scale) => {\r\n const svgElement = document.querySelector(\r\n '#chart-container svg:first-of-type'\r\n );\r\n\r\n // Get the values correctly scaled\r\n const chartHeight = svgElement.height.baseVal.value * scale;\r\n const chartWidth = svgElement.width.baseVal.value * scale;\r\n\r\n // In case of SVG the zoom must be set directly for body as scale\r\n // eslint-disable-next-line no-undef\r\n document.body.style.zoom = scale;\r\n\r\n // Set the margin to 0px\r\n // eslint-disable-next-line no-undef\r\n document.body.style.margin = '0px';\r\n\r\n return {\r\n chartHeight,\r\n chartWidth\r\n };\r\n }, parseFloat(exportOptions.scale))\r\n : await page.evaluate(() => {\r\n // eslint-disable-next-line no-undef\r\n const { chartHeight, chartWidth } = window.Highcharts.charts[0];\r\n\r\n // No need for such scale manipulation in case of other types\r\n // of exports. Reset the zoom for other exports than to SVGs\r\n // eslint-disable-next-line no-undef\r\n document.body.style.zoom = 1;\r\n\r\n return {\r\n chartHeight,\r\n chartWidth\r\n };\r\n });\r\n\r\n // Get the clip region for the page\r\n const { x, y } = await _getClipRegion(page);\r\n\r\n // Set final `height` for viewport\r\n const viewportHeight = Math.abs(\r\n Math.ceil(size.chartHeight || exportOptions.height)\r\n );\r\n\r\n // Set final `width` for viewport\r\n const viewportWidth = Math.abs(\r\n Math.ceil(size.chartWidth || exportOptions.width)\r\n );\r\n\r\n // Set the final viewport now that we have the real height\r\n await page.setViewport({\r\n height: viewportHeight,\r\n width: viewportWidth,\r\n deviceScaleFactor: isSVG ? 1 : parseFloat(exportOptions.scale)\r\n });\r\n\r\n let result;\r\n // Rasterization process\r\n switch (exportOptions.type) {\r\n case 'svg':\r\n result = await _createSVG(page);\r\n break;\r\n case 'png':\r\n case 'jpeg':\r\n result = await _createImage(\r\n page,\r\n exportOptions.type,\r\n {\r\n width: viewportWidth,\r\n height: viewportHeight,\r\n x,\r\n y\r\n },\r\n exportOptions.rasterizationTimeout\r\n );\r\n break;\r\n case 'pdf':\r\n result = await _createPDF(\r\n page,\r\n viewportHeight,\r\n viewportWidth,\r\n exportOptions.rasterizationTimeout\r\n );\r\n break;\r\n default:\r\n throw new ExportError(\r\n `[export] Unsupported output format: ${exportOptions.type}.`,\r\n 400\r\n );\r\n }\r\n\r\n // Clear previously injected JS and CSS resources\r\n await clearPageResources(page, injectedResources);\r\n return result;\r\n } catch (error) {\r\n await clearPageResources(page, injectedResources);\r\n return error;\r\n }\r\n}\r\n\r\n/**\r\n * Retrieves the clipping region coordinates of the specified page element\r\n * with the 'chart-container' id.\r\n *\r\n * @async\r\n * @function _getClipRegion\r\n *\r\n * @param {Object} page - Puppeteer page object.\r\n *\r\n * @returns {Promise} A Promise that resolves to an object containing\r\n * `x`, `y`, `width`, and `height` properties.\r\n */\r\nasync function _getClipRegion(page) {\r\n return page.$eval('#chart-container', (element) => {\r\n const { x, y, width, height } = element.getBoundingClientRect();\r\n return {\r\n x,\r\n y,\r\n width,\r\n height: Math.trunc(height > 1 ? height : 500)\r\n };\r\n });\r\n}\r\n\r\n/**\r\n * Creates an SVG by evaluating the `outerHTML` of the first 'svg' element\r\n * inside an element with the id 'container'.\r\n *\r\n * @async\r\n * @function _createSVG\r\n *\r\n * @param {Object} page - Puppeteer page object.\r\n *\r\n * @returns {Promise} A Promise that resolves to the SVG string.\r\n */\r\nasync function _createSVG(page) {\r\n return page.$eval(\r\n '#container svg:first-of-type',\r\n (element) => element.outerHTML\r\n );\r\n}\r\n\r\n/**\r\n * Creates an image using Puppeteer's page `screenshot` functionality with\r\n * specified options.\r\n *\r\n * @async\r\n * @function _createImage\r\n *\r\n * @param {Object} page - Puppeteer page object.\r\n * @param {string} type - Image type.\r\n * @param {Object} clip - Clipping region coordinates.\r\n * @param {number} rasterizationTimeout - Timeout for rasterization\r\n * in milliseconds.\r\n *\r\n * @returns {Promise} A Promise that resolves to the image buffer\r\n * or rejecting with an `ExportError` for timeout.\r\n */\r\nasync function _createImage(page, type, clip, rasterizationTimeout) {\r\n return Promise.race([\r\n page.screenshot({\r\n type,\r\n clip,\r\n encoding: 'base64',\r\n fullPage: false,\r\n optimizeForSpeed: true,\r\n captureBeyondViewport: true,\r\n ...(type !== 'png' ? { quality: 80 } : {}),\r\n // Always render on a transparent page if the expected type format is PNG\r\n omitBackground: type == 'png' // #447, #463\r\n }),\r\n new Promise((_resolve, reject) =>\r\n setTimeout(\r\n () => reject(new ExportError('Rasterization timeout', 408)),\r\n rasterizationTimeout || 1500\r\n )\r\n )\r\n ]);\r\n}\r\n\r\n/**\r\n * Creates a PDF using Puppeteer's page `pdf` functionality with specified\r\n * options.\r\n *\r\n * @async\r\n * @function _createPDF\r\n *\r\n * @param {Object} page - Puppeteer page object.\r\n * @param {number} height - PDF height.\r\n * @param {number} width - PDF width.\r\n * @param {number} rasterizationTimeout - Timeout for rasterization\r\n * in milliseconds.\r\n *\r\n * @returns {Promise} A Promise that resolves to the PDF buffer.\r\n */\r\nasync function _createPDF(page, height, width, rasterizationTimeout) {\r\n await page.emulateMediaType('screen');\r\n return page.pdf({\r\n // This will remove an extra empty page in PDF exports\r\n height: height + 1,\r\n width,\r\n encoding: 'base64',\r\n timeout: rasterizationTimeout || 1500\r\n });\r\n}\r\n\r\nexport default {\r\n puppeteerExport\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * @overview This module provides a worker pool implementation for managing\r\n * the browser instance and pages, specifically designed for use with\r\n * the Highcharts Export Server. It optimizes resources usage and performance\r\n * by maintaining a pool of workers that can handle concurrent export tasks\r\n * using Puppeteer.\r\n */\r\n\r\nimport { Pool } from 'tarn';\r\nimport { v4 as uuid } from 'uuid';\r\n\r\nimport { createBrowser, closeBrowser, newPage, clearPage } from './browser.js';\r\nimport { puppeteerExport } from './export.js';\r\nimport { log, logWithStack } from './logger.js';\r\nimport { getNewDateTime, measureTime } from './utils.js';\r\n\r\nimport ExportError from './errors/ExportError.js';\r\n\r\n// The pool instance\r\nlet pool = null;\r\n\r\n// Pool statistics\r\nconst poolStats = {\r\n exportsAttempted: 0,\r\n exportsPerformed: 0,\r\n exportsDropped: 0,\r\n exportsFromSvg: 0,\r\n exportsFromOptions: 0,\r\n exportsFromSvgAttempts: 0,\r\n exportsFromOptionsAttempts: 0,\r\n timeSpent: 0,\r\n timeSpentAverage: 0\r\n};\r\n\r\n/**\r\n * Initializes the export pool with the provided configuration, creating\r\n * a browser instance and setting up worker resources.\r\n *\r\n * @async\r\n * @function initPool\r\n *\r\n * @param {Object} poolOptions - The configuration object containing `pool`\r\n * options.\r\n * @param {Array.} puppeteerArgs - Additional arguments for Puppeteer\r\n * launch.\r\n *\r\n * @returns {Promise} A Promise that resolves to ending the function\r\n * execution when an already initialized pool of resources is found.\r\n *\r\n * @throws {ExportError} Throws an `ExportError` if could not create the pool\r\n * of workers.\r\n */\r\nexport async function initPool(poolOptions, puppeteerArgs) {\r\n // Create a browser instance with the puppeteer arguments\r\n await createBrowser(puppeteerArgs);\r\n\r\n try {\r\n log(\r\n 3,\r\n `[pool] Initializing pool with workers: min ${poolOptions.minWorkers}, max ${poolOptions.maxWorkers}.`\r\n );\r\n\r\n if (pool) {\r\n log(\r\n 4,\r\n '[pool] Already initialized, please kill it before creating a new one.'\r\n );\r\n return;\r\n }\r\n\r\n // Keep an eye on a correct min and max workers number\r\n if (poolOptions.minWorkers > poolOptions.maxWorkers) {\r\n poolOptions.minWorkers = poolOptions.maxWorkers;\r\n }\r\n\r\n // Create a pool along with a minimal number of resources\r\n pool = new Pool({\r\n // Get the `create`, `validate`, and `destroy` functions\r\n ..._factory(poolOptions),\r\n min: poolOptions.minWorkers,\r\n max: poolOptions.maxWorkers,\r\n acquireTimeoutMillis: poolOptions.acquireTimeout,\r\n createTimeoutMillis: poolOptions.createTimeout,\r\n destroyTimeoutMillis: poolOptions.destroyTimeout,\r\n idleTimeoutMillis: poolOptions.idleTimeout,\r\n createRetryIntervalMillis: poolOptions.createRetryInterval,\r\n reapIntervalMillis: poolOptions.reaperInterval,\r\n propagateCreateError: false\r\n });\r\n\r\n // Set events\r\n pool.on('release', async (resource) => {\r\n // Clear page\r\n const clearStatus = await clearPage(resource, false);\r\n log(\r\n 4,\r\n `[pool] Pool resource [${resource.id}] - Releasing a worker. Clear page status: ${clearStatus}.`\r\n );\r\n });\r\n\r\n pool.on('destroySuccess', (_eventId, resource) => {\r\n log(\r\n 4,\r\n `[pool] Pool resource [${resource.id}] - Destroyed a worker successfully.`\r\n );\r\n resource.page = null;\r\n });\r\n\r\n const initialResources = [];\r\n // Create an initial number of resources\r\n for (let i = 0; i < poolOptions.minWorkers; i++) {\r\n try {\r\n const resource = await pool.acquire().promise;\r\n initialResources.push(resource);\r\n } catch (error) {\r\n logWithStack(2, error, '[pool] Could not create an initial resource.');\r\n }\r\n }\r\n\r\n // Release the initial number of resources back to the pool\r\n initialResources.forEach((resource) => {\r\n pool.release(resource);\r\n });\r\n\r\n log(\r\n 3,\r\n `[pool] The pool is ready${initialResources.length ? ` with ${initialResources.length} initial resources waiting.` : '.'}`\r\n );\r\n } catch (error) {\r\n throw new ExportError(\r\n '[pool] Could not configure and create the pool of workers.',\r\n 500\r\n ).setError(error);\r\n }\r\n}\r\n\r\n/**\r\n * Terminates all workers in the pool, destroys the pool, and closes the browser\r\n * instance.\r\n *\r\n * @async\r\n * @function killPool\r\n *\r\n * @returns {Promise} A Promise that resolves once all workers are\r\n * terminated, the pool is destroyed, and the browser is successfully closed.\r\n */\r\nexport async function killPool() {\r\n log(3, '[pool] Killing pool with all workers and closing browser.');\r\n\r\n // If still alive, destroy the pool of pages before closing a browser\r\n if (pool) {\r\n // Free up not released workers\r\n for (const worker of pool.used) {\r\n pool.release(worker.resource);\r\n }\r\n\r\n // Destroy the pool if it is still available\r\n if (!pool.destroyed) {\r\n await pool.destroy();\r\n log(4, '[pool] Destroyed the pool of resources.');\r\n }\r\n pool = null;\r\n }\r\n\r\n // Close the browser instance\r\n await closeBrowser();\r\n}\r\n\r\n/**\r\n * Processes the export work using a worker from the pool. Acquires a worker\r\n * handle from the pool, performs the export using puppeteer, and releases\r\n * the worker handle back to the pool.\r\n *\r\n * @async\r\n * @function postWork\r\n *\r\n * @param {Object} options - The configuration object containing complete set\r\n * of options.\r\n *\r\n * @returns {Promise} A Promise that resolves to the export result\r\n * and options.\r\n *\r\n * @throws {ExportError} Throws an `ExportError` if an error occurs during\r\n * the export process.\r\n */\r\nexport async function postWork(options) {\r\n let workerHandle;\r\n\r\n try {\r\n log(4, '[pool] Work received, starting to process.');\r\n\r\n // An export attempt counted\r\n ++poolStats.exportsAttempted;\r\n\r\n // Display the pool information if needed\r\n if (options.pool.benchmarking) {\r\n getPoolInfo();\r\n }\r\n\r\n // Throw an error in case of lacking the pool instance\r\n if (!pool) {\r\n throw new ExportError(\r\n '[pool] Work received, but pool has not been started.',\r\n 500\r\n );\r\n }\r\n\r\n // The acquire counter\r\n const acquireCounter = measureTime();\r\n\r\n // Try to acquire the worker along with the id, works count and page\r\n try {\r\n log(4, '[pool] Acquiring a worker handle.');\r\n\r\n // Acquire a pool resource\r\n workerHandle = await pool.acquire().promise;\r\n\r\n // Check the page acquire time\r\n if (options.server.benchmarking) {\r\n log(\r\n 5,\r\n `[benchmark] ${options.requestId ? `Request [${options.requestId}] - ` : ''}`,\r\n `Acquiring a worker handle took ${acquireCounter()}ms.`\r\n );\r\n }\r\n } catch (error) {\r\n throw new ExportError(\r\n `[pool] ${\r\n options.requestId ? `Request [${options.requestId}] - ` : ''\r\n }Error encountered when acquiring an available entry: ${acquireCounter()}ms.`,\r\n 400\r\n ).setError(error);\r\n }\r\n log(4, '[pool] Acquired a worker handle.');\r\n\r\n if (!workerHandle.page) {\r\n // Set the `workLimit` to exceeded in order to recreate the resource\r\n workerHandle.workCount = options.pool.workLimit + 1;\r\n throw new ExportError(\r\n '[pool] Resolved worker page is invalid: the pool setup is wonky.',\r\n 400\r\n );\r\n }\r\n\r\n // Save the start time\r\n const workStart = getNewDateTime();\r\n\r\n log(\r\n 4,\r\n `[pool] Pool resource [${workerHandle.id}] - Starting work on this pool entry.`\r\n );\r\n\r\n // Start measuring export time\r\n const exportCounter = measureTime();\r\n\r\n // Perform an export on a puppeteer level\r\n const result = await puppeteerExport(\r\n workerHandle.page,\r\n options.export,\r\n options.customLogic\r\n );\r\n\r\n // Check if it's an error\r\n if (result instanceof Error) {\r\n // NOTE:\r\n // If there's a rasterization timeout, we want need to flush the page.\r\n // This is because the page may be in a state where it's waiting for\r\n // the screenshot to finish even though the timeout has occured.\r\n // Which of course causes a lot of issues with the event system,\r\n // and page consistency.\r\n //\r\n // NOTE:\r\n // Only page.screenshot will throw this, timeouts for PDF's are\r\n // handled by the page.pdf function itself.\r\n //\r\n // ...yes, this is ugly.\r\n if (result.message === 'Rasterization timeout') {\r\n // Set the `workLimit` to exceeded in order to recreate the resource\r\n workerHandle.workCount = options.pool.workLimit + 1;\r\n workerHandle.page = null;\r\n }\r\n\r\n if (\r\n result.name === 'TimeoutError' ||\r\n result.message === 'Rasterization timeout'\r\n ) {\r\n throw new ExportError(\r\n `[pool] ${\r\n options.requestId ? `Request [${options.requestId}] - ` : ''\r\n }Rasterization timeout: your chart may be too complex or large, and failed to render within the allotted time.`\r\n ).setError(result);\r\n } else {\r\n throw new ExportError(\r\n `[pool] ${\r\n options.requestId ? `Request [${options.requestId}] - ` : ''\r\n }Error encountered during export: ${exportCounter()}ms.`\r\n ).setError(result);\r\n }\r\n }\r\n\r\n // Check the Puppeteer export time\r\n if (options.server.benchmarking) {\r\n log(\r\n 5,\r\n `[benchmark] ${options.requestId ? `Request [${options.requestId}] - ` : ''}`,\r\n `Exporting a chart sucessfully took ${exportCounter()}ms.`\r\n );\r\n }\r\n\r\n // Release the resource back to the pool\r\n pool.release(workerHandle);\r\n\r\n // Used for statistics in averageTime and processedWorkCount, which\r\n // in turn is used by the /health route.\r\n const workEnd = getNewDateTime();\r\n const exportTime = workEnd - workStart;\r\n\r\n poolStats.timeSpent += exportTime;\r\n poolStats.timeSpentAverage =\r\n poolStats.timeSpent / ++poolStats.exportsPerformed;\r\n\r\n log(4, `[pool] Work completed in ${exportTime}ms.`);\r\n\r\n // Otherwise return the result\r\n return {\r\n result,\r\n options\r\n };\r\n } catch (error) {\r\n ++poolStats.exportsDropped;\r\n\r\n if (workerHandle) {\r\n pool.release(workerHandle);\r\n }\r\n\r\n throw error;\r\n }\r\n}\r\n\r\n/**\r\n * Retrieves the current pool instance.\r\n *\r\n * @function getPool\r\n *\r\n * @returns {(Object|null)} The current pool instance if initialized, or null\r\n * if the pool has not been created.\r\n */\r\nexport function getPool() {\r\n return pool;\r\n}\r\n\r\n/**\r\n * Gets the statistic of a pool instace about exports.\r\n *\r\n * @function getPoolStats\r\n *\r\n * @returns {Object} The current pool statistics.\r\n */\r\nexport function getPoolStats() {\r\n return poolStats;\r\n}\r\n\r\n/**\r\n * Retrieves pool information in JSON format, including minimum and maximum\r\n * workers, available workers, workers in use, and pending acquire requests.\r\n *\r\n * @function getPoolInfoJSON\r\n *\r\n * @returns {Object} Pool information in JSON format.\r\n */\r\nexport function getPoolInfoJSON() {\r\n return {\r\n min: pool.min,\r\n max: pool.max,\r\n used: pool.numUsed(),\r\n available: pool.numFree(),\r\n allCreated: pool.numUsed() + pool.numFree(),\r\n pendingAcquires: pool.numPendingAcquires(),\r\n pendingCreates: pool.numPendingCreates(),\r\n pendingValidations: pool.numPendingValidations(),\r\n pendingDestroys: pool.pendingDestroys.length,\r\n absoluteAll:\r\n pool.numUsed() +\r\n pool.numFree() +\r\n pool.numPendingAcquires() +\r\n pool.numPendingCreates() +\r\n pool.numPendingValidations() +\r\n pool.pendingDestroys.length\r\n };\r\n}\r\n\r\n/**\r\n * Logs information about the current state of the pool, including the minimum\r\n * and maximum workers, available workers, workers in use, and pending acquire\r\n * requests.\r\n *\r\n * @function getPoolInfo\r\n */\r\nexport function getPoolInfo() {\r\n const {\r\n min,\r\n max,\r\n used,\r\n available,\r\n allCreated,\r\n pendingAcquires,\r\n pendingCreates,\r\n pendingValidations,\r\n pendingDestroys,\r\n absoluteAll\r\n } = getPoolInfoJSON();\r\n\r\n log(5, `[pool] The minimum number of resources allowed by pool: ${min}.`);\r\n log(5, `[pool] The maximum number of resources allowed by pool: ${max}.`);\r\n log(5, `[pool] The number of used resources: ${used}.`);\r\n log(5, `[pool] The number of free resources: ${available}.`);\r\n log(\r\n 5,\r\n `[pool] The number of all created (used and free) resources: ${allCreated}.`\r\n );\r\n log(\r\n 5,\r\n `[pool] The number of resources waiting to be acquired: ${pendingAcquires}.`\r\n );\r\n log(\r\n 5,\r\n `[pool] The number of resources waiting to be created: ${pendingCreates}.`\r\n );\r\n log(\r\n 5,\r\n `[pool] The number of resources waiting to be validated: ${pendingValidations}.`\r\n );\r\n log(\r\n 5,\r\n `[pool] The number of resources waiting to be destroyed: ${pendingDestroys}.`\r\n );\r\n log(5, `[pool] The number of all resources: ${absoluteAll}.`);\r\n}\r\n\r\n/**\r\n * Factory function that returns an object with `create`, `validate`,\r\n * and `destroy` functions for the pool instance.\r\n *\r\n * @function _factory\r\n *\r\n * @param {Object} poolOptions - The configuration object containing `pool`\r\n * options.\r\n */\r\nfunction _factory(poolOptions) {\r\n return {\r\n /**\r\n * Creates a new worker page for the export pool.\r\n *\r\n * @async\r\n * @function create\r\n *\r\n * @returns {Promise} A Promise that resolves to an object\r\n * containing the worker ID, a reference to the browser page, and initial\r\n * work count.\r\n *\r\n * @throws {ExportError} Throws an `ExportError` if there is an error during\r\n * the creation of the new page.\r\n */\r\n create: async () => {\r\n // Init the resource with unique id and work count\r\n const poolResource = {\r\n id: uuid(),\r\n // Try to distribute the initial work count\r\n workCount: Math.round(Math.random() * (poolOptions.workLimit / 2))\r\n };\r\n\r\n try {\r\n // Start measuring a page creation time\r\n const startDate = getNewDateTime();\r\n\r\n // Create a new page\r\n await newPage(poolResource);\r\n\r\n // Measure the time of full creation and configuration of a page\r\n log(\r\n 3,\r\n `[pool] Pool resource [${poolResource.id}] - Successfully created a worker, took ${\r\n getNewDateTime() - startDate\r\n }ms.`\r\n );\r\n\r\n // Return ready pool resource\r\n return poolResource;\r\n } catch (error) {\r\n log(\r\n 3,\r\n `[pool] Pool resource [${poolResource.id}] - Error encountered when creating a new page.`\r\n );\r\n throw error;\r\n }\r\n },\r\n\r\n /**\r\n * Validates a worker page in the export pool, checking if it has exceeded\r\n * the work limit.\r\n *\r\n * @async\r\n * @function validate\r\n *\r\n * @param {Object} poolResource - The handle to the worker, containing\r\n * the worker's ID, a reference to the browser page, and work count.\r\n *\r\n * @returns {Promise} A Promise that resolves to true if the worker\r\n * is valid and within the work limit; otherwise, to false.\r\n */\r\n validate: async (poolResource) => {\r\n // NOTE:\r\n // In certain cases acquiring throws a TargetCloseError, which may\r\n // be caused by two things:\r\n // - The page is closed and attempted to be reused.\r\n // - Lost contact with the browser.\r\n //\r\n // What we're seeing in logs is that successive exports typically\r\n // succeeds, and the server recovers, indicating that it's likely\r\n // the first case. This is an attempt at allievating the issue by\r\n // simply not validating the worker if the page is null or closed.\r\n //\r\n // The actual result from when this happened, was that a worker would\r\n // be completely locked, stopping it from being acquired until\r\n // its work count reached the limit.\r\n\r\n // Check if the `page` is valid\r\n if (!poolResource.page) {\r\n log(\r\n 3,\r\n `[pool] Pool resource [${poolResource.id}] - Validation failed (no valid page is found).`\r\n );\r\n return false;\r\n }\r\n\r\n // Check if the `page` is closed\r\n if (poolResource.page.isClosed()) {\r\n log(\r\n 3,\r\n `[pool] Pool resource [${poolResource.id}] - Validation failed (page is closed or invalid).`\r\n );\r\n return false;\r\n }\r\n\r\n // Check if the `mainFrame` is detached\r\n if (poolResource.page.mainFrame().detached) {\r\n log(\r\n 3,\r\n `[pool] Pool resource [${poolResource.id}] - Validation failed (page's frame is detached).`\r\n );\r\n return false;\r\n }\r\n\r\n // Check if the `workLimit` is exceeded\r\n if (\r\n poolOptions.workLimit &&\r\n ++poolResource.workCount > poolOptions.workLimit\r\n ) {\r\n log(\r\n 3,\r\n `[pool] Pool resource [${poolResource.id}] - Validation failed (exceeded the ${poolOptions.workLimit} works per resource limit).`\r\n );\r\n return false;\r\n }\r\n\r\n // The `poolResource` is validated\r\n return true;\r\n },\r\n\r\n /**\r\n * Destroys a worker entry in the export pool, closing its associated page.\r\n *\r\n * @async\r\n * @function destroy\r\n *\r\n * @param {Object} poolResource - The handle to the worker, containing\r\n * the worker's ID, a reference to the browser page, and work count.\r\n */\r\n destroy: async (poolResource) => {\r\n log(\r\n 3,\r\n `[pool] Pool resource [${poolResource.id}] - Destroying a worker.`\r\n );\r\n\r\n if (poolResource.page && !poolResource.page.isClosed()) {\r\n try {\r\n // Remove all attached event listeners from the resource\r\n poolResource.page.removeAllListeners('pageerror');\r\n poolResource.page.removeAllListeners('console');\r\n poolResource.page.removeAllListeners('framedetached');\r\n\r\n // We need to wait around for this\r\n await poolResource.page.close();\r\n } catch (error) {\r\n log(\r\n 3,\r\n `[pool] Pool resource [${poolResource.id}] - Page could not be closed upon destroying.`\r\n );\r\n throw error;\r\n }\r\n }\r\n }\r\n };\r\n}\r\n\r\nexport default {\r\n initPool,\r\n killPool,\r\n postWork,\r\n getPool,\r\n getPoolStats,\r\n getPoolInfo,\r\n getPoolInfoJSON\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * @overview Used to sanitize the strings coming from the exporting module\r\n * to prevent XSS attacks (with the DOMPurify library).\r\n */\r\n\r\nimport DOMPurify from 'dompurify';\r\nimport { JSDOM } from 'jsdom';\r\n\r\n/**\r\n * Sanitizes a given HTML string by removing \r\n * tags and any content within them.\r\n *\r\n * @function sanitize\r\n *\r\n * @param {string} input - The HTML string to be sanitized.\r\n *\r\n * @returns {string} The sanitized HTML string.\r\n */\r\nexport function sanitize(input) {\r\n // Get the virtual DOM\r\n const window = new JSDOM('').window;\r\n\r\n // Create a purifying instance\r\n const purify = DOMPurify(window);\r\n\r\n // Return sanitized input\r\n return purify.sanitize(input, { ADD_TAGS: ['foreignObject'] });\r\n}\r\n\r\nexport default {\r\n sanitize\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * @overview This module provides functions to prepare for the exporting charts\r\n * into various image output formats such as JPEG, PNG, PDF, and SVGs.\r\n * It supports single and batch export operations and allows customization\r\n * through options passed from configurations or APIs.\r\n */\r\n\r\nimport { readFileSync, writeFileSync } from 'fs';\r\n\r\nimport { getOptions, isAllowedConfig, mergeOptions } from './config.js';\r\nimport { log, logWithStack, logZodIssues } from './logger.js';\r\nimport { getPoolStats, killPool, postWork } from './pool.js';\r\nimport { sanitize } from './sanitize.js';\r\nimport {\r\n deepCopy,\r\n fixConstr,\r\n fixOutfile,\r\n fixType,\r\n getAbsolutePath,\r\n getBase64,\r\n isObject,\r\n roundNumber,\r\n wrapAround\r\n} from './utils.js';\r\nimport { strictValidate, validateOption } from './validation.js';\r\n\r\nimport ExportError from './errors/ExportError.js';\r\n\r\n// The global flag for the code execution permission\r\nlet allowCodeExecution = false;\r\n\r\n/**\r\n * Starts a single export process based on the specified options and saves\r\n * the resulting image to the provided output file.\r\n *\r\n * @async\r\n * @function singleExport\r\n *\r\n * @param {Object} options - The `options` object, which should include settings\r\n * from the `export` and `customLogic` sections. It can be a partial or complete\r\n * set of options from these sections. The object must contain at least one\r\n * of the following `export` properties: `infile`, `instr`, `options`, or `svg`\r\n * to generate a valid image.\r\n *\r\n * @returns {Promise} A Promise that resolves once the single export\r\n * process is completed.\r\n *\r\n * @throws {ExportError} Throws an `ExportError` if an error occurs during\r\n * the single export process.\r\n */\r\nexport async function singleExport(options) {\r\n // Check if the export makes sense\r\n if (options && options.export) {\r\n // Perform an export\r\n await startExport(\r\n { export: options.export, customLogic: options.customLogic },\r\n async (error, data) => {\r\n // Exit process when error exists\r\n if (error) {\r\n throw error;\r\n }\r\n\r\n // Get the `b64`, `outfile`, and `type` for a chart\r\n const { b64, outfile, type } = data.options.export;\r\n\r\n // Save the result\r\n try {\r\n if (b64) {\r\n // As a Base64 string to a txt file\r\n writeFileSync(\r\n `${outfile.split('.').shift() || 'chart'}.txt`,\r\n getBase64(data.result, type)\r\n );\r\n } else {\r\n // As a correct image format\r\n writeFileSync(\r\n outfile || `chart.${type}`,\r\n type !== 'svg' ? Buffer.from(data.result, 'base64') : data.result\r\n );\r\n }\r\n } catch (error) {\r\n throw new ExportError(\r\n '[chart] Error while saving a chart.',\r\n 500\r\n ).setError(error);\r\n }\r\n\r\n // Kill pool and close browser after finishing single export\r\n await killPool();\r\n }\r\n );\r\n } else {\r\n throw new ExportError(\r\n '[chart] No expected `export` options were found. Please provide one of the following options: `infile`, `instr`, `options`, or `svg` to generate a valid image.',\r\n 400\r\n );\r\n }\r\n}\r\n\r\n/**\r\n * Starts a batch export process for multiple charts based on information\r\n * provided in the `batch` option. The `batch` is a string in the following\r\n * format: \"infile1.json=outfile1.png;infile2.json=outfile2.png;...\". Results\r\n * are saved to the specified output files.\r\n *\r\n * @async\r\n * @function batchExport\r\n *\r\n * @param {Object} options - The `options` object, which should include settings\r\n * from the `export` and `customLogic` sections. It can be a partial or complete\r\n * set of options from these sections. It must contain the `batch` option from\r\n * the `export` section to generate valid images.\r\n *\r\n * @returns {Promise} A Promise that resolves once the batch export\r\n * processes are completed.\r\n *\r\n * @throws {ExportError} Throws an `ExportError` if an error occurs during\r\n * any of the batch export process.\r\n */\r\nexport async function batchExport(options) {\r\n // Check if the export makes sense\r\n if (options && options.export && options.export.batch) {\r\n // An array for collecting batch exports\r\n const batchFunctions = [];\r\n\r\n // Split and pair the `batch` arguments\r\n for (let pair of options.export.batch.split(';') || []) {\r\n pair = pair.split('=');\r\n if (pair.length === 2) {\r\n batchFunctions.push(\r\n startExport(\r\n {\r\n export: {\r\n ...options.export,\r\n infile: pair[0],\r\n outfile: pair[1]\r\n },\r\n customLogic: options.customLogic\r\n },\r\n (error, data) => {\r\n // Exit process when error exists\r\n if (error) {\r\n throw error;\r\n }\r\n\r\n // Get the `b64`, `outfile`, and `type` for a chart\r\n const { b64, outfile, type } = data.options.export;\r\n\r\n // Save the result\r\n try {\r\n if (b64) {\r\n // As a Base64 string to a txt file\r\n writeFileSync(\r\n `${outfile.split('.').shift() || 'chart'}.txt`,\r\n getBase64(data.result, type)\r\n );\r\n } else {\r\n // As a correct image format\r\n writeFileSync(\r\n outfile,\r\n type !== 'svg'\r\n ? Buffer.from(data.result, 'base64')\r\n : data.result\r\n );\r\n }\r\n } catch (error) {\r\n throw new ExportError(\r\n '[chart] Error while saving a chart.',\r\n 500\r\n ).setError(error);\r\n }\r\n }\r\n )\r\n );\r\n } else {\r\n log(2, '[chart] No correct pair found for the batch export.');\r\n }\r\n }\r\n\r\n // Await all exports are done\r\n const batchResults = await Promise.allSettled(batchFunctions);\r\n\r\n // Kill pool and close browser after finishing batch export\r\n await killPool();\r\n\r\n // Log errors if found\r\n batchResults.forEach((result, index) => {\r\n // Log the error with stack about the specific batch export\r\n if (result.reason) {\r\n logWithStack(\r\n 1,\r\n result.reason,\r\n `[chart] Batch export number ${index + 1} could not be correctly completed.`\r\n );\r\n }\r\n });\r\n } else {\r\n throw new ExportError(\r\n '[chart] No expected `export` options were found. Please provide the `batch` option to generate valid images.',\r\n 400\r\n );\r\n }\r\n}\r\n\r\n/**\r\n * Starts an export process. The `exportingOptions` parameter is an object that\r\n * should include settings from the `export` and `customLogic` sections. It can\r\n * be a partial or complete set of options from these sections. If partial\r\n * options are provided, missing values will be merged with the current global\r\n * options.\r\n *\r\n * The `endCallback` function is invoked upon the completion of the export,\r\n * either successfully or with an error. The `error` object is provided\r\n * as the first argument, and the `data` object is the second, containing\r\n * the Base64 representation of the chart in the `result` property\r\n * and the complete set of options in the `options` property.\r\n *\r\n * @async\r\n * @function startExport\r\n *\r\n * @param {Object} exportingOptions - The `exportingOptions` object, which\r\n * should include settings from the `export` and `customLogic` sections. It can\r\n * be a partial or complete set of options from these sections. If the provided\r\n * options are partial, missing values will be merged with the current global\r\n * options.\r\n * @param {Function} endCallback - The callback function to be invoked upon\r\n * finalizing the export process or upon encountering an error. The first\r\n * argument is the `error` object, and the second argument is the `data` object,\r\n * which includes the Base64 representation of the chart in the `result`\r\n * property and the full set of options in the `options` property.\r\n *\r\n * @returns {Promise} This function does not return a value directly.\r\n * Instead, it communicates results via the `endCallback`.\r\n *\r\n * @throws {ExportError} Throws an `ExportError` if there is a problem with\r\n * processing input of any type. The error is passed into the `endCallback`\r\n * function and processed there.\r\n */\r\nexport async function startExport(exportingOptions, endCallback) {\r\n try {\r\n // Check if provided options is an object\r\n if (!isObject(exportingOptions)) {\r\n throw new ExportError(\r\n '[chart] Incorrect value of the provided `exportingOptions`. Needs to be an object.',\r\n 400\r\n );\r\n }\r\n\r\n // Merge additional options to the copy of the instance options\r\n const options = mergeOptions(deepCopy(getOptions()), {\r\n export: exportingOptions.export,\r\n customLogic: exportingOptions.customLogic\r\n });\r\n\r\n // Get the `export` options\r\n const exportOptions = options.export;\r\n\r\n // Starting exporting process message\r\n log(4, '[chart] Starting the exporting process.');\r\n\r\n // Export using options from the file as an input\r\n if (exportOptions.infile !== null) {\r\n log(4, '[chart] Attempting to export from a file input.');\r\n\r\n let fileContent;\r\n try {\r\n // Try to read the file to get the string representation\r\n fileContent = readFileSync(\r\n getAbsolutePath(exportOptions.infile),\r\n 'utf8'\r\n );\r\n } catch (error) {\r\n throw new ExportError(\r\n '[chart] Error loading content from a file input.',\r\n 400\r\n ).setError(error);\r\n }\r\n\r\n // Check the file's extension\r\n if (exportOptions.infile.endsWith('.svg')) {\r\n try {\r\n // Set to the `svg` option\r\n exportOptions.svg = validateOption('svg', fileContent, false);\r\n } catch (error) {\r\n logZodIssues(\r\n 1,\r\n error.issues,\r\n '[config] The `svg` option validation error'\r\n );\r\n throw error;\r\n }\r\n } else if (exportOptions.infile.endsWith('.json')) {\r\n try {\r\n // Set to the `instr` option\r\n exportOptions.instr = validateOption('instr', fileContent, false);\r\n } catch (error) {\r\n logZodIssues(\r\n 1,\r\n error.issues,\r\n '[config] The `instr` option validation error'\r\n );\r\n throw error;\r\n }\r\n } else {\r\n throw new ExportError(\r\n '[chart] Incorrect value of the `infile` option.',\r\n 400\r\n );\r\n }\r\n }\r\n\r\n // Export using SVG as an input\r\n if (exportOptions.svg !== null) {\r\n log(4, '[chart] Attempting to export from an SVG input.');\r\n\r\n // SVG exports attempts counter\r\n ++getPoolStats().exportsFromSvgAttempts;\r\n\r\n // Export from an SVG string\r\n const result = await _exportFromSvg(\r\n sanitize(exportOptions.svg), // #209\r\n options\r\n );\r\n\r\n // SVG exports counter\r\n ++getPoolStats().exportsFromSvg;\r\n\r\n // Pass SVG export result to the end callback\r\n return endCallback(null, result);\r\n }\r\n\r\n // Export using options as an input\r\n if (exportOptions.instr !== null || exportOptions.options !== null) {\r\n log(4, '[chart] Attempting to export from options input.');\r\n\r\n // Options exports attempts counter\r\n ++getPoolStats().exportsFromOptionsAttempts;\r\n\r\n // Export from options\r\n const result = await _exportFromOptions(\r\n exportOptions.instr || exportOptions.options,\r\n options\r\n );\r\n\r\n // Options exports counter\r\n ++getPoolStats().exportsFromOptions;\r\n\r\n // Pass options export result to the end callback\r\n return endCallback(null, result);\r\n }\r\n\r\n // No input specified, pass an error message to the callback\r\n return endCallback(\r\n new ExportError(\r\n `[chart] No valid input specified. Check if at least one of the following parameters is correctly set: 'infile', 'instr', 'options', or 'svg'.`,\r\n 400\r\n )\r\n );\r\n } catch (error) {\r\n return endCallback(error);\r\n }\r\n}\r\n\r\n/**\r\n * Retrieves and returns the current status of the code execution permission.\r\n *\r\n * @function getAllowCodeExecution\r\n *\r\n * @returns {boolean} The value of the global `allowCodeExecution` option.\r\n */\r\nexport function getAllowCodeExecution() {\r\n return allowCodeExecution;\r\n}\r\n\r\n/**\r\n * Sets the code execution permission based on the provided boolean value.\r\n *\r\n * @function setAllowCodeExecution\r\n *\r\n * @param {boolean} value - The boolean value to be assigned to the global\r\n * `allowCodeExecution` option.\r\n */\r\nexport function setAllowCodeExecution(value) {\r\n allowCodeExecution = value;\r\n}\r\n\r\n/**\r\n * Exports from an SVG based input with the provided options.\r\n *\r\n * @async\r\n * @function _exportFromSvg\r\n *\r\n * @param {string} inputToExport - The SVG based input to be exported.\r\n * @param {Object} options - The configuration object containing complete set\r\n * of options.\r\n *\r\n * @returns {Promise} A Promise that resolves to a result of the export\r\n * process.\r\n *\r\n * @throws {ExportError} Throws an `ExportError` if there is not a correct SVG\r\n * input.\r\n */\r\nasync function _exportFromSvg(inputToExport, options) {\r\n // Check if it is SVG\r\n if (\r\n typeof inputToExport === 'string' &&\r\n (inputToExport.indexOf('= 0 || inputToExport.indexOf('= 0)\r\n ) {\r\n log(4, '[chart] Parsing input as SVG.');\r\n\r\n // Set the export input as SVG\r\n options.export.svg = inputToExport;\r\n\r\n // Reset the rest of the export input options\r\n options.export.instr = null;\r\n options.export.options = null;\r\n\r\n // Call the function with an SVG string as an export input\r\n return _prepareExport(options);\r\n } else {\r\n throw new ExportError('[chart] Not a correct SVG input.', 400);\r\n }\r\n}\r\n\r\n/**\r\n * Exports from an options based input with the provided options.\r\n *\r\n * @async\r\n * @function _exportFromOptions\r\n *\r\n * @param {string} inputToExport - The options based input to be exported.\r\n * @param {Object} options - The configuration object containing complete set\r\n * of options.\r\n *\r\n * @returns {Promise} A Promise that resolves to a result of the export\r\n * process.\r\n *\r\n * @throws {ExportError} Throws an `ExportError` if there is not a correct\r\n * chart options input.\r\n */\r\nasync function _exportFromOptions(inputToExport, options) {\r\n log(4, '[chart] Parsing input from options.');\r\n\r\n // Try to check, validate and parse to stringified options\r\n const stringifiedOptions = isAllowedConfig(\r\n inputToExport,\r\n true,\r\n options.customLogic.allowCodeExecution\r\n );\r\n\r\n // Check if a correct stringified options\r\n if (\r\n stringifiedOptions === null ||\r\n typeof stringifiedOptions !== 'string' ||\r\n !stringifiedOptions.startsWith('{') ||\r\n !stringifiedOptions.endsWith('}')\r\n ) {\r\n throw new ExportError(\r\n '[chart] Invalid configuration provided - Only options configurations and SVG are allowed for this server. If this is your server, JavaScript custom code can be enabled by starting the server with the `allowCodeExecution` options set to true.',\r\n 403\r\n );\r\n }\r\n\r\n // Set the export input as a stringified chart options\r\n options.export.instr = stringifiedOptions;\r\n\r\n // Reset the rest of the export input options\r\n options.export.svg = null;\r\n\r\n // Call the function with a stringified chart options\r\n return _prepareExport(options);\r\n}\r\n\r\n/**\r\n * Function for finalizing options and configurations before export.\r\n *\r\n * @async\r\n * @function _prepareExport\r\n *\r\n * @param {Object} options - The configuration object containing complete set\r\n * of options.\r\n *\r\n * @returns {Promise} A Promise that resolves to a result of the export\r\n * process.\r\n */\r\nasync function _prepareExport(options) {\r\n const { export: exportOptions, customLogic: customLogicOptions } = options;\r\n\r\n // Prepare the `type` option\r\n exportOptions.type = fixType(exportOptions.type, exportOptions.outfile);\r\n\r\n // Prepare the `outfile` option\r\n exportOptions.outfile = fixOutfile(exportOptions.type, exportOptions.outfile);\r\n\r\n // Prepare the `constr` option\r\n exportOptions.constr = fixConstr(exportOptions.constr);\r\n\r\n // Notify about the custom logic usage status\r\n log(\r\n 3,\r\n `[chart] The custom logic is ${customLogicOptions.allowCodeExecution ? 'allowed' : 'disallowed'}.`\r\n );\r\n\r\n // Prepare the custom logic options (`customCode`, `callback`, `resources`)\r\n _handleCustomLogic(customLogicOptions, customLogicOptions.allowCodeExecution);\r\n\r\n // Prepare the `globalOptions` and `themeOptions` options\r\n _handleGlobalAndTheme(\r\n exportOptions,\r\n customLogicOptions.allowFileResources,\r\n customLogicOptions.allowCodeExecution\r\n );\r\n\r\n // Prepare the `height`, `width`, and `scale` options\r\n options.export = {\r\n ...exportOptions,\r\n ..._findChartSize(exportOptions)\r\n };\r\n\r\n // The last strict validation of options right before exporting process\r\n try {\r\n // Validate final options\r\n options = strictValidate(options);\r\n } catch (error) {\r\n logZodIssues(1, error.issues, '[config] Final options validation error');\r\n }\r\n\r\n // Post the work to the pool\r\n return postWork(options);\r\n}\r\n\r\n/**\r\n * Calculates the `height`, `width` and `scale` for chart exports based\r\n * on the provided export options.\r\n *\r\n * The function prioritizes values in the following order:\r\n * 1. The `height`, `width`, `scale` from the `exportOptions`.\r\n * 2. Options from the chart configuration (from `exporting` and `chart`).\r\n * 3. Options from the global options (from `exporting` and `chart`).\r\n * 4. Options from the theme options (from `exporting` and `chart` sections).\r\n * 5. Fallback default values (`height = 400`, `width = 600`, `scale = 1`).\r\n *\r\n * @function _findChartSize\r\n *\r\n * @param {Object} exportOptions - The configuration object containing `export`\r\n * options.\r\n *\r\n * @returns {Object} The object containing calculated `height`, `width`\r\n * and `scale` values for the chart export.\r\n */\r\nfunction _findChartSize(exportOptions) {\r\n // Check the `options` and `instr` for chart and exporting sections\r\n const { chart: optionsChart, exporting: optionsExporting } =\r\n exportOptions.options || isAllowedConfig(exportOptions.instr) || false;\r\n\r\n // Check the `globalOptions` for chart and exporting sections\r\n const { chart: globalOptionsChart, exporting: globalOptionsExporting } =\r\n isAllowedConfig(exportOptions.globalOptions) || false;\r\n\r\n // Check the `themeOptions` for chart and exporting sections\r\n const { chart: themeOptionsChart, exporting: themeOptionsExporting } =\r\n isAllowedConfig(exportOptions.themeOptions) || false;\r\n\r\n // Find the `scale` value:\r\n // - It cannot be lower than 0.1\r\n // - It cannot be higher than 5.0\r\n // - It must be rounded to 2 decimal places (e.g. 0.23234 -> 0.23)\r\n const scale = roundNumber(\r\n Math.max(\r\n 0.1,\r\n Math.min(\r\n exportOptions.scale ||\r\n optionsExporting?.scale ||\r\n globalOptionsExporting?.scale ||\r\n themeOptionsExporting?.scale ||\r\n exportOptions.defaultScale ||\r\n 1,\r\n 5.0\r\n )\r\n ),\r\n 2\r\n );\r\n\r\n // Find the `height` value\r\n const height =\r\n exportOptions.height ||\r\n optionsExporting?.sourceHeight ||\r\n optionsChart?.height ||\r\n globalOptionsExporting?.sourceHeight ||\r\n globalOptionsChart?.height ||\r\n themeOptionsExporting?.sourceHeight ||\r\n themeOptionsChart?.height ||\r\n exportOptions.defaultHeight ||\r\n 400;\r\n\r\n // Find the `width` value\r\n const width =\r\n exportOptions.width ||\r\n optionsExporting?.sourceWidth ||\r\n optionsChart?.width ||\r\n globalOptionsExporting?.sourceWidth ||\r\n globalOptionsChart?.width ||\r\n themeOptionsExporting?.sourceWidth ||\r\n themeOptionsChart?.width ||\r\n exportOptions.defaultWidth ||\r\n 600;\r\n\r\n // Gather `height`, `width` and `scale` information in one object\r\n const size = { height, width, scale };\r\n\r\n // Get rid of potential `px` and `%`\r\n for (let [param, value] of Object.entries(size)) {\r\n size[param] =\r\n typeof value === 'string' ? +value.replace(/px|%/gi, '') : value;\r\n }\r\n\r\n // Return the size object\r\n return size;\r\n}\r\n\r\n/**\r\n * Handles the execution of custom logic options, including loading `resources`,\r\n * `customCode`, and `callback`. If code execution is allowed, it processes\r\n * the custom logic options accordingly. If code execution is not allowed,\r\n * it disables the usage of resources, custom code and callback.\r\n *\r\n * @function _handleCustomLogic\r\n *\r\n * @param {Object} customLogicOptions - The configuration object containing\r\n * `customLogic` options.\r\n * @param {boolean} allowCodeExecution - A flag indicating whether code\r\n * execution is allowed.\r\n *\r\n * @throws {ExportError} Throws an `ExportError` if code execution\r\n * is not allowed but custom logic options are still provided.\r\n */\r\nfunction _handleCustomLogic(customLogicOptions, allowCodeExecution) {\r\n // In case of allowing code execution\r\n if (allowCodeExecution) {\r\n // Process the `resources` option\r\n if (typeof customLogicOptions.resources === 'string') {\r\n // Custom stringified resources\r\n customLogicOptions.resources = _handleResources(\r\n customLogicOptions.resources,\r\n customLogicOptions.allowFileResources,\r\n true\r\n );\r\n } else if (!customLogicOptions.resources) {\r\n try {\r\n // Load the default one\r\n customLogicOptions.resources = _handleResources(\r\n readFileSync(getAbsolutePath('resources.json'), 'utf8'),\r\n customLogicOptions.allowFileResources,\r\n true\r\n );\r\n } catch (error) {\r\n log(2, '[chart] Unable to load the default `resources.json` file.');\r\n }\r\n }\r\n\r\n // Process the `customCode` option\r\n try {\r\n // Try to load custom code and wrap around it in a self invoking function\r\n customLogicOptions.customCode = wrapAround(\r\n customLogicOptions.customCode,\r\n customLogicOptions.allowFileResources\r\n );\r\n } catch (error) {\r\n logWithStack(2, error, '[chart] The `customCode` cannot be loaded.');\r\n\r\n // In case of an error, set the option with null\r\n customLogicOptions.customCode = null;\r\n }\r\n\r\n // Process the `callback` option\r\n try {\r\n // Try to load callback function\r\n customLogicOptions.callback = wrapAround(\r\n customLogicOptions.callback,\r\n customLogicOptions.allowFileResources,\r\n true\r\n );\r\n } catch (error) {\r\n logWithStack(2, error, '[chart] The `callback` cannot be loaded.');\r\n\r\n // In case of an error, set the option with null\r\n customLogicOptions.callback = null;\r\n }\r\n\r\n // Check if there is the `customCode` present\r\n if ([null, undefined].includes(customLogicOptions.customCode)) {\r\n log(3, '[chart] No value for the `customCode` option found.');\r\n }\r\n\r\n // Check if there is the `callback` present\r\n if ([null, undefined].includes(customLogicOptions.callback)) {\r\n log(3, '[chart] No value for the `callback` option found.');\r\n }\r\n\r\n // Check if there is the `resources` present\r\n if ([null, undefined].includes(customLogicOptions.resources)) {\r\n log(3, '[chart] No value for the `resources` option found.');\r\n }\r\n } else {\r\n // If the `allowCodeExecution` flag is set to false, we should refuse\r\n // the usage of the `callback`, `resources`, and `customCode` options.\r\n // Additionally, the worker will refuse to run arbitrary JavaScript.\r\n if (\r\n customLogicOptions.callback ||\r\n customLogicOptions.resources ||\r\n customLogicOptions.customCode\r\n ) {\r\n // Reset all custom code options\r\n customLogicOptions.callback = null;\r\n customLogicOptions.resources = null;\r\n customLogicOptions.customCode = null;\r\n\r\n // Send a message saying that the exporter does not support these settings\r\n throw new ExportError(\r\n `[chart] The 'callback', 'resources', and 'customCode' options have been disabled for this server.`,\r\n 403\r\n );\r\n }\r\n }\r\n}\r\n\r\n/**\r\n * Handles and validates resources from the `resources` option for export.\r\n *\r\n * @function _handleResources\r\n *\r\n * @param {(Object|string|null)} [resources=null] - The resources to be handled.\r\n * Can be either a JSON object, stringified JSON, a path to a JSON file,\r\n * or null. The default value is `null`.\r\n * @param {boolean} allowFileResources - A flag indicating whether loading\r\n * resources from files is allowed.\r\n * @param {boolean} allowCodeExecution - A flag indicating whether code\r\n * execution is allowed.\r\n *\r\n * @returns {(Object|null)} The handled resources or null if no valid resources\r\n * are found.\r\n */\r\nfunction _handleResources(\r\n resources = null,\r\n allowFileResources,\r\n allowCodeExecution\r\n) {\r\n // List of allowed sections in the resources JSON\r\n const allowedProps = ['js', 'css', 'files'];\r\n\r\n let handledResources = resources;\r\n let correctResources = false;\r\n\r\n // Try to load resources from a file\r\n if (allowFileResources && resources.endsWith('.json')) {\r\n try {\r\n handledResources = isAllowedConfig(\r\n readFileSync(getAbsolutePath(resources), 'utf8'),\r\n false,\r\n allowCodeExecution\r\n );\r\n } catch {\r\n return null;\r\n }\r\n } else {\r\n // Try to get JSON\r\n handledResources = isAllowedConfig(resources, false, allowCodeExecution);\r\n\r\n // Get rid of the files section\r\n if (handledResources && !allowFileResources) {\r\n delete handledResources.files;\r\n }\r\n }\r\n\r\n // Filter from unnecessary properties\r\n for (const propName in handledResources) {\r\n if (!allowedProps.includes(propName)) {\r\n delete handledResources[propName];\r\n } else if (!correctResources) {\r\n correctResources = true;\r\n }\r\n }\r\n\r\n // Check if at least one of allowed properties is present\r\n if (!correctResources) {\r\n return null;\r\n }\r\n\r\n // Handle files section\r\n if (handledResources.files) {\r\n handledResources.files = handledResources.files.map((item) => item.trim());\r\n if (!handledResources.files || handledResources.files.length <= 0) {\r\n delete handledResources.files;\r\n }\r\n }\r\n\r\n // Return resources\r\n return handledResources;\r\n}\r\n\r\n/**\r\n * Handles the loading and validation of the `globalOptions` and `themeOptions`\r\n * in the export options. If the option is a string and references a JSON file\r\n * (when the `allowFileResources` is true), it reads and parses the file.\r\n * Otherwise, it attempts to parse the string or object as JSON. If any errors\r\n * occur during this process, the option is set to null. If there is an error\r\n * loading or parsing the `globalOptions` or `themeOptions`, the error is logged\r\n * and the option is set to null.\r\n *\r\n * @function _handleGlobalAndTheme\r\n *\r\n * @param {Object} exportOptions - The configuration object containing `export`\r\n * options.\r\n * @param {boolean} allowFileResources - A flag indicating whether loading\r\n * resources from files is allowed.\r\n * @param {boolean} allowCodeExecution - A flag indicating whether code\r\n * execution is allowed.\r\n */\r\nfunction _handleGlobalAndTheme(\r\n exportOptions,\r\n allowFileResources,\r\n allowCodeExecution\r\n) {\r\n // Check the `globalOptions` and `themeOptions` options\r\n ['globalOptions', 'themeOptions'].forEach((optionsName) => {\r\n try {\r\n // Check if the option exists\r\n if (exportOptions[optionsName]) {\r\n // Check if it is a string and a file name with the `.json` extension\r\n if (\r\n allowFileResources &&\r\n typeof exportOptions[optionsName] === 'string' &&\r\n exportOptions[optionsName].endsWith('.json')\r\n ) {\r\n // Check if the file content can be a config, and save it as a string\r\n exportOptions[optionsName] = isAllowedConfig(\r\n readFileSync(getAbsolutePath(exportOptions[optionsName]), 'utf8'),\r\n true,\r\n allowCodeExecution\r\n );\r\n } else {\r\n // Check if the value can be a config, and save it as a string\r\n exportOptions[optionsName] = isAllowedConfig(\r\n exportOptions[optionsName],\r\n true,\r\n allowCodeExecution\r\n );\r\n }\r\n }\r\n } catch (error) {\r\n logWithStack(\r\n 2,\r\n error,\r\n `[chart] The \\`${optionsName}\\` cannot be loaded.`\r\n );\r\n\r\n // In case of an error, set the option with null\r\n exportOptions[optionsName] = null;\r\n }\r\n });\r\n\r\n // Check if there is the `globalOptions` present\r\n if ([null, undefined].includes(exportOptions.globalOptions)) {\r\n log(3, '[chart] No value for the `globalOptions` option found.');\r\n }\r\n\r\n // Check if there is the `themeOptions` present\r\n if ([null, undefined].includes(exportOptions.themeOptions)) {\r\n log(3, '[chart] No value for the `themeOptions` option found.');\r\n }\r\n}\r\n\r\nexport default {\r\n singleExport,\r\n batchExport,\r\n startExport,\r\n getAllowCodeExecution,\r\n setAllowCodeExecution\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * @overview This module provides utility functions for managing intervals\r\n * and timeouts in a centralized manner. It maintains a registry of all active\r\n * timers and allows for their efficient cleanup when needed. This can be useful\r\n * in applications where proper resource management and clean shutdown of timers\r\n * are critical to avoid memory leaks or unintended behavior.\r\n */\r\n\r\nimport { log } from './logger.js';\r\n\r\n// Array that contains ids of all ongoing intervals and timeouts\r\nconst timerIds = [];\r\n\r\n/**\r\n * Adds id of the `setInterval` or `setTimeout` and to the `timerIds` array.\r\n *\r\n * @function addTimer\r\n *\r\n * @param {NodeJS.Timeout} id - Id of an interval or a timeout.\r\n */\r\nexport function addTimer(id) {\r\n timerIds.push(id);\r\n}\r\n\r\n/**\r\n * Clears all of ongoing intervals and timeouts by ids gathered\r\n * in the `timerIds` array.\r\n *\r\n * @function clearAllTimers\r\n */\r\nexport function clearAllTimers() {\r\n log(4, `[timer] Clearing all registered intervals and timeouts.`);\r\n for (const id of timerIds) {\r\n clearInterval(id);\r\n clearTimeout(id);\r\n }\r\n}\r\n\r\nexport default {\r\n addTimer,\r\n clearAllTimers\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * @overview Provides middleware functions for logging errors with stack traces\r\n * and handling error responses in an Express application.\r\n */\r\n\r\nimport { getOptions } from '../../config.js';\r\nimport { logWithStack } from '../../logger.js';\r\n\r\n/**\r\n * Middleware for logging errors with stack trace and handling error response.\r\n *\r\n * @function logErrorMiddleware\r\n *\r\n * @param {Error} error - The error object.\r\n * @param {Express.Request} request - The Express request object.\r\n * @param {Express.Response} response - The Express response object.\r\n * @param {Function} next - The next middleware function.\r\n *\r\n * @returns {undefined} The call to the next middleware function with\r\n * the passed error.\r\n */\r\nfunction logErrorMiddleware(error, request, response, next) {\r\n // Display the error with stack in a correct format\r\n logWithStack(1, error);\r\n\r\n // Delete the stack for the environment other than the development\r\n if (getOptions().other.nodeEnv !== 'development') {\r\n delete error.stack;\r\n }\r\n\r\n // Call the `returnErrorMiddleware` middleware\r\n return next(error);\r\n}\r\n\r\n/**\r\n * Middleware for returning error response.\r\n *\r\n * @function returnErrorMiddleware\r\n *\r\n * @param {Error} error - The error object.\r\n * @param {Express.Request} request - The Express request object.\r\n * @param {Express.Response} response - The Express response object.\r\n * @param {Function} next - The next middleware function.\r\n */\r\nfunction returnErrorMiddleware(error, request, response, next) {\r\n // Gather all requied information for the response\r\n const { message, stack } = error;\r\n\r\n // Use the error's status code or the default 400\r\n const statusCode = error.statusCode || 400;\r\n\r\n // Set and return response\r\n response.status(statusCode).json({ statusCode, message, stack });\r\n}\r\n\r\n/**\r\n * Adds the error middlewares to the passed express app instance.\r\n *\r\n * @param {Express} app - The Express app instance.\r\n */\r\nexport default function errorMiddleware(app) {\r\n // Add log error middleware\r\n app.use(logErrorMiddleware);\r\n\r\n // Add set status and return error middleware\r\n app.use(returnErrorMiddleware);\r\n}\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * @overview Provides middleware functions for configuring and enabling rate\r\n * limiting in an Express application.\r\n */\r\n\r\nimport rateLimit from 'express-rate-limit';\r\n\r\nimport { log } from '../../logger.js';\r\n\r\nimport ExportError from '../../errors/ExportError.js';\r\n\r\n/**\r\n * Middleware for enabling rate limiting on the specified Express app.\r\n *\r\n * @param {Express} app - The Express app instance.\r\n *\r\n * @param {Object} rateLimitingOptions - The configuration object containing\r\n * `rateLimiting` options.\r\n *\r\n * @throws {ExportError} Throws an `ExportError` if could not configure and set\r\n * the rate limiting options.\r\n */\r\nexport default function rateLimitingMiddleware(app, rateLimitingOptions) {\r\n try {\r\n // Check if the rate limiting is enabled\r\n if (rateLimitingOptions.enable) {\r\n const message =\r\n 'Too many requests, you have been rate limited. Please try again later.';\r\n\r\n // Options for the rate limiter\r\n const rateOptions = {\r\n window: rateLimitingOptions.window || 1,\r\n maxRequests: rateLimitingOptions.maxRequests || 30,\r\n delay: rateLimitingOptions.delay || 0,\r\n trustProxy: rateLimitingOptions.trustProxy || false,\r\n skipKey: rateLimitingOptions.skipKey || null,\r\n skipToken: rateLimitingOptions.skipToken || null\r\n };\r\n\r\n // Set if behind a proxy\r\n if (rateOptions.trustProxy) {\r\n app.enable('trust proxy');\r\n }\r\n\r\n // Create a limiter\r\n const limiter = rateLimit({\r\n // Time frame for which requests are checked and remembered\r\n windowMs: rateOptions.window * 60 * 1000,\r\n // Limit each IP to 100 requests per `windowMs`\r\n limit: rateOptions.maxRequests,\r\n // Disable delaying, full speed until the max limit is reached\r\n delayMs: rateOptions.delay,\r\n handler: (request, response) => {\r\n response.format({\r\n json: () => {\r\n response.status(429).send({ message });\r\n },\r\n default: () => {\r\n response.status(429).send(message);\r\n }\r\n });\r\n },\r\n skip: (request) => {\r\n // Allow bypassing the limiter if a valid key/token has been sent\r\n if (\r\n rateOptions.skipKey !== null &&\r\n rateOptions.skipToken !== null &&\r\n request.query.key === rateOptions.skipKey &&\r\n request.query.access_token === rateOptions.skipToken\r\n ) {\r\n log(4, '[rate limiting] Skipping rate limiter.');\r\n return true;\r\n }\r\n return false;\r\n }\r\n });\r\n\r\n // Use a limiter as a middleware\r\n app.use(limiter);\r\n\r\n log(\r\n 3,\r\n `[rate limiting] Enabled rate limiting with ${rateOptions.maxRequests} requests per ${rateOptions.window} minute for each IP, trusting proxy: ${rateOptions.trustProxy}.`\r\n );\r\n }\r\n } catch (error) {\r\n throw new ExportError(\r\n '[rate limiting] Could not configure and set the rate limiting options.',\r\n 500\r\n ).setError(error);\r\n }\r\n}\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * @overview Provides middleware functions for validating incoming HTTP requests\r\n * in an Express application. This module ensures that requests contain\r\n * appropriate content types and valid request bodies, including proper JSON\r\n * structures and chart data for exports. It checks for potential issues such\r\n * as missing or malformed data, private range URLs in SVG payloads, and allows\r\n * for flexible options validation. The middleware logs detailed information\r\n * and handles errors related to incorrect payloads, chart data, and private URL\r\n * usage.\r\n */\r\n\r\nimport { v4 as uuid } from 'uuid';\r\n\r\nimport { getAllowCodeExecution } from '../../chart.js';\r\nimport { isAllowedConfig } from '../../config.js';\r\nimport { log, logZodIssues } from '../../logger.js';\r\nimport {\r\n fixConstr,\r\n fixType,\r\n isObjectEmpty,\r\n isPrivateRangeUrlFound\r\n} from '../../utils.js';\r\nimport { looseValidate } from '../../validation.js';\r\n\r\nimport ExportError from '../../errors/ExportError.js';\r\n\r\n/**\r\n * Middleware for validating the content-type header.\r\n *\r\n * @function contentTypeMiddleware\r\n *\r\n * @param {Express.Request} request - The Express request object.\r\n * @param {Express.Response} response - The Express response object.\r\n * @param {Function} next - The next middleware function.\r\n *\r\n * @returns {undefined} The call to the next middleware function.\r\n *\r\n * @throws {ExportError} Throws an `ExportError` if the content-type\r\n * is not correct.\r\n */\r\nfunction contentTypeMiddleware(request, response, next) {\r\n try {\r\n // Get the content type header\r\n const contentType = request.headers['content-type'] || '';\r\n\r\n // Allow only JSON, URL-encoded and form data without files types of data\r\n if (\r\n !contentType.includes('application/json') &&\r\n !contentType.includes('application/x-www-form-urlencoded') &&\r\n !contentType.includes('multipart/form-data')\r\n ) {\r\n throw new ExportError(\r\n '[validation] Content-Type must be application/json, application/x-www-form-urlencoded, or multipart/form-data.',\r\n 415\r\n );\r\n }\r\n\r\n // Call the `requestBodyMiddleware` middleware\r\n return next();\r\n } catch (error) {\r\n return next(error);\r\n }\r\n}\r\n\r\n/**\r\n * Middleware for validating the request's body.\r\n *\r\n * @function requestBodyMiddleware\r\n *\r\n * @param {Express.Request} request - The Express request object.\r\n * @param {Express.Response} response - The Express response object.\r\n * @param {Function} next - The next middleware function.\r\n *\r\n * @returns {undefined} The call to the next middleware function.\r\n *\r\n * @throws {ExportError} Throws an `ExportError` if the body is not correct.\r\n * @throws {ExportError} Throws an `ExportError` if the chart data from the body\r\n * is not correct.\r\n * @throws {ExportError} Throws an `ExportError` in case of the private range\r\n * url error.\r\n */\r\nfunction requestBodyMiddleware(request, response, next) {\r\n try {\r\n // Get the request body\r\n const body = request.body;\r\n\r\n // Create a unique ID for a request\r\n const requestId = uuid();\r\n\r\n // Throw an error if there is no correct body\r\n if (!body || isObjectEmpty(body)) {\r\n log(\r\n 2,\r\n `[validation] Request [${requestId}] - The request from ${\r\n request.headers['x-forwarded-for'] || request.connection.remoteAddress\r\n } was incorrect. Received payload is empty.`\r\n );\r\n\r\n throw new ExportError(\r\n `[validation] Request [${requestId}] - The request body is required. Please ensure that your Content-Type header is correct. Accepted types are 'application/json' and 'multipart/form-data'.`,\r\n 400\r\n );\r\n }\r\n\r\n // Get the `allowCodeExecution` option for the server\r\n const allowCodeExecution = getAllowCodeExecution();\r\n\r\n // Find a correct chart options\r\n const instr = isAllowedConfig(\r\n // Use one of the below\r\n body.instr || body.options || body.infile || body.data,\r\n // Stringify options\r\n true,\r\n // Allow or disallow functions\r\n allowCodeExecution\r\n );\r\n\r\n // Throw an error if there is no correct chart data\r\n if (instr === null && !body.svg) {\r\n log(\r\n 2,\r\n `[validation] Request [${requestId}] - The request from ${\r\n request.headers['x-forwarded-for'] || request.connection.remoteAddress\r\n } was incorrect. Received payload is missing correct chart data for export: ${JSON.stringify(body)}.`\r\n );\r\n\r\n throw new ExportError(\r\n `Request [${requestId}] - [validation] No correct chart data found. Ensure that you are using either application/json or multipart/form-data headers. If sending JSON, make sure the chart data is in the 'infile', 'options', or 'data' attribute. If sending SVG, ensure it is in the 'svg' attribute.`,\r\n 400\r\n );\r\n }\r\n\r\n // Throw an error if test of xlink:href elements from payload's SVG fails\r\n if (body.svg && isPrivateRangeUrlFound(body.svg)) {\r\n throw new ExportError(\r\n `Request [${requestId}] - [validation] SVG potentially contain at least one forbidden URL in 'xlink:href' element. Please review the SVG content and ensure that all referenced URLs comply with security policies.`,\r\n 400\r\n );\r\n }\r\n\r\n try {\r\n // Validate options from the body and store parsed structure in the request\r\n request.validatedOptions = looseValidate({\r\n // Set the created ID as a `_requestId` property in the validated options\r\n _requestId: requestId,\r\n export: {\r\n instr,\r\n svg: body.svg,\r\n outfile:\r\n body.outfile ||\r\n `${request.params.filename || 'chart'}.${fixType(body.type)}`,\r\n type: fixType(body.type, body.outfile),\r\n constr: fixConstr(body.constr),\r\n b64: body.b64,\r\n noDownload: body.noDownload,\r\n height: body.height,\r\n width: body.width,\r\n scale: body.scale,\r\n globalOptions: isAllowedConfig(\r\n body.globalOptions,\r\n true,\r\n allowCodeExecution\r\n ),\r\n themeOptions: isAllowedConfig(\r\n body.themeOptions,\r\n true,\r\n allowCodeExecution\r\n )\r\n },\r\n customLogic: {\r\n allowCodeExecution,\r\n allowFileResources: false,\r\n customCode: body.customCode,\r\n callback: body.callback,\r\n resources: isAllowedConfig(body.resources, true, allowCodeExecution)\r\n }\r\n });\r\n } catch (error) {\r\n logZodIssues(\r\n 1,\r\n error.issues,\r\n '[config] Request options validation error'\r\n );\r\n\r\n throw new ExportError(\r\n 'The provided options are not correct. Please check if your data is of the correct types.',\r\n 400\r\n );\r\n }\r\n\r\n // Call the next middleware\r\n return next();\r\n } catch (error) {\r\n return next(error);\r\n }\r\n}\r\n\r\n/**\r\n * Adds the validation middlewares to the passed express app instance.\r\n *\r\n * @param {Express} app - The Express app instance.\r\n */\r\nexport default function validationMiddleware(app) {\r\n // Add content type validation middleware\r\n app.post(['/', '/:filename'], contentTypeMiddleware);\r\n\r\n // Add request body request validation middleware\r\n app.post(['/', '/:filename'], requestBodyMiddleware);\r\n}\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * @overview Defines the export routes and logic for handling chart export\r\n * requests in an Express server. This module processes incoming requests\r\n * to export charts in various formats (e.g. JPEG, PNG, PDF, SVG). It integrates\r\n * with Highcharts' core functionalities and supports both immediate download\r\n * responses and Base64-encoded content returns. The code also features\r\n * benchmarking for performance monitoring.\r\n */\r\n\r\nimport { startExport } from '../../chart.js';\r\nimport { log } from '../../logger.js';\r\nimport { getBase64, measureTime } from '../../utils.js';\r\n\r\nimport ExportError from '../../errors/ExportError.js';\r\n\r\n// Reversed MIME types\r\nconst reversedMime = {\r\n png: 'image/png',\r\n jpeg: 'image/jpeg',\r\n gif: 'image/gif',\r\n pdf: 'application/pdf',\r\n svg: 'image/svg+xml'\r\n};\r\n\r\n/**\r\n * Handles the export requests from the client.\r\n *\r\n * @async\r\n * @function requestExport\r\n *\r\n * @param {Express.Request} request - The Express request object.\r\n * @param {Express.Response} response - The Express response object.\r\n * @param {Function} next - The next middleware function.\r\n *\r\n * @returns {Promise} A Promise that resolves once the export process\r\n * is complete.\r\n */\r\nasync function requestExport(request, response, next) {\r\n try {\r\n // Start counting time for a request\r\n const requestCounter = measureTime();\r\n\r\n // In case the connection is closed, force to abort further actions\r\n let connectionAborted = false;\r\n request.socket.on('close', (hadErrors) => {\r\n if (hadErrors) {\r\n connectionAborted = true;\r\n }\r\n });\r\n\r\n // Get the options previously validated in the validation middleware\r\n const requestOptions = request.validatedOptions;\r\n\r\n // Get the request id\r\n const requestId = requestOptions.requestId;\r\n\r\n // Info about an incoming request with correct data\r\n log(4, `[export] Request [${requestId}] - Got an incoming HTTP request.`);\r\n\r\n // Start the export process\r\n await startExport(requestOptions, (error, data) => {\r\n // Remove the close event from the socket\r\n request.socket.removeAllListeners('close');\r\n\r\n // If the connection was closed, do nothing\r\n if (connectionAborted) {\r\n log(\r\n 3,\r\n `[export] Request [${requestId}] - The client closed the connection before the chart finished processing.`\r\n );\r\n return;\r\n }\r\n\r\n // If error, log it and send it to the error middleware\r\n if (error) {\r\n throw error;\r\n }\r\n\r\n // If data is missing, log the message and send it to the error middleware\r\n if (!data || !data.result) {\r\n log(\r\n 2,\r\n `[export] Request [${requestId}] - Request from ${\r\n request.headers['x-forwarded-for'] ||\r\n request.connection.remoteAddress\r\n } was incorrect. Received result is ${data.result}.`\r\n );\r\n\r\n throw new ExportError(\r\n `[export] Request [${requestId}] - Unexpected return of the export result from the chart generation. Please check your request data.`,\r\n 400\r\n );\r\n }\r\n\r\n // Return the result in an appropriate format\r\n if (data.result) {\r\n log(\r\n 3,\r\n `[export] Request [${requestId}] - The whole exporting process took ${requestCounter()}ms.`\r\n );\r\n\r\n // Get the `type`, `b64`, `noDownload`, and `outfile` from options\r\n const { type, b64, noDownload, outfile } = data.options.export;\r\n\r\n // If only Base64 is required, return it\r\n if (b64) {\r\n return response.send(getBase64(data.result, type));\r\n }\r\n\r\n // Set correct content type\r\n response.header('Content-Type', reversedMime[type] || 'image/png');\r\n\r\n // Decide whether to download or not chart file\r\n if (!noDownload) {\r\n response.attachment(outfile);\r\n }\r\n\r\n // If SVG, return plain content, otherwise a b64 string from a buffer\r\n return type === 'svg'\r\n ? response.send(data.result)\r\n : response.send(Buffer.from(data.result, 'base64'));\r\n }\r\n });\r\n } catch (error) {\r\n return next(error);\r\n }\r\n}\r\n\r\n/**\r\n * Adds the `export` routes.\r\n *\r\n * @function exportRoutes\r\n *\r\n * @param {Express} app - The Express app instance.\r\n */\r\nexport default function exportRoutes(app) {\r\n /**\r\n * Adds the POST '/' - A route for handling POST requests at the root\r\n * endpoint.\r\n */\r\n app.post('/', requestExport);\r\n\r\n /**\r\n * Adds the POST '/:filename' - A route for handling POST requests with\r\n * a specified filename parameter.\r\n */\r\n app.post('/:filename', requestExport);\r\n}\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * @overview Defines an Express route for server health monitoring, including\r\n * uptime, success rates, and other server statistics.\r\n */\r\n\r\nimport { readFileSync } from 'fs';\r\nimport { join } from 'path';\r\n\r\nimport { getHighchartsVersion } from '../../cache.js';\r\nimport { log } from '../../logger.js';\r\nimport { getPoolStats, getPoolInfoJSON } from '../../pool.js';\r\nimport { addTimer } from '../../timer.js';\r\nimport { __dirname, getNewDateTime } from '../../utils.js';\r\n\r\n// Set the start date of the server\r\nconst serverStartTime = new Date();\r\n\r\n// Get the `package.json` content\r\nconst packageFile = JSON.parse(\r\n readFileSync(join(__dirname, 'package.json'), 'utf8')\r\n);\r\n\r\n// An array for success rate ratios\r\nconst successRates = [];\r\n\r\n// Record every minute\r\nconst recordInterval = 60 * 1000;\r\n\r\n// 30 minutes\r\nconst windowSize = 30;\r\n\r\n/**\r\n * Calculates moving average indicator based on the data from the `successRates`\r\n * array.\r\n *\r\n * @function _calculateMovingAverage\r\n *\r\n * @returns {number} A moving average for success ratio of the server exports.\r\n */\r\nfunction _calculateMovingAverage() {\r\n return successRates.reduce((a, b) => a + b, 0) / successRates.length;\r\n}\r\n\r\n/**\r\n * Starts the interval responsible for calculating current success rate ratio\r\n * and collects records to the `successRates` array.\r\n *\r\n * @function _startSuccessRate\r\n *\r\n * @returns {NodeJS.Timeout} Id of an interval.\r\n */\r\nfunction _startSuccessRate() {\r\n return setInterval(() => {\r\n const stats = getPoolStats();\r\n const successRatio =\r\n stats.exportsAttempted === 0\r\n ? 1\r\n : (stats.exportsPerformed / stats.exportsAttempted) * 100;\r\n\r\n successRates.push(successRatio);\r\n if (successRates.length > windowSize) {\r\n successRates.shift();\r\n }\r\n }, recordInterval);\r\n}\r\n\r\n/**\r\n * Adds the `health` routes.\r\n *\r\n * @function healthRoutes\r\n *\r\n * @param {Express} app - The Express app instance.\r\n */\r\nexport default function healthRoutes(app) {\r\n // Start processing success rate ratio interval and save its id to the array\r\n // for the graceful clearing on shutdown with injected `addTimer` funtion\r\n addTimer(_startSuccessRate());\r\n\r\n /**\r\n * Adds the GET '/health' - A route for getting the basic stats of the server.\r\n */\r\n app.get('/health', (request, response, next) => {\r\n try {\r\n log(4, '[health] Returning server health.');\r\n\r\n const stats = getPoolStats();\r\n const period = successRates.length;\r\n const movingAverage = _calculateMovingAverage();\r\n\r\n // Send the server's statistics\r\n response.send({\r\n // Status and times\r\n status: 'OK',\r\n bootTime: serverStartTime,\r\n uptime: `${Math.floor((getNewDateTime() - serverStartTime.getTime()) / 1000 / 60)} minutes`,\r\n\r\n // Versions\r\n serverVersion: packageFile.version,\r\n highchartsVersion: getHighchartsVersion(),\r\n\r\n // Exports\r\n averageExportTime: stats.timeSpentAverage,\r\n attemptedExports: stats.exportsAttempted,\r\n performedExports: stats.exportsPerformed,\r\n failedExports: stats.exportsDropped,\r\n sucessRatio: (stats.exportsPerformed / stats.exportsAttempted) * 100,\r\n\r\n // Pool\r\n pool: getPoolInfoJSON(),\r\n\r\n // Moving average\r\n period,\r\n movingAverage,\r\n message:\r\n isNaN(movingAverage) || !successRates.length\r\n ? 'Too early to report. No exports made yet. Please check back soon.'\r\n : `Last ${period} minutes had a success rate of ${movingAverage.toFixed(2)}%.`,\r\n\r\n // SVG and JSON exports\r\n svgExports: stats.exportsFromSvg,\r\n jsonExports: stats.exportsFromOptions,\r\n svgExportsAttempts: stats.exportsFromSvgAttempts,\r\n jsonExportsAttempts: stats.exportsFromOptionsAttempts\r\n });\r\n } catch (error) {\r\n return next(error);\r\n }\r\n });\r\n}\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * @overview Defines an Express route for serving the UI for the export server\r\n * when enabled.\r\n */\r\n\r\nimport { join } from 'path';\r\n\r\nimport { getOptions } from '../../config.js';\r\nimport { log } from '../../logger.js';\r\nimport { __dirname } from '../../utils.js';\r\n\r\n/**\r\n * Adds the `ui` routes.\r\n *\r\n * @function uiRoutes\r\n *\r\n * @param {Express} app - The Express app instance.\r\n */\r\nexport default function uiRoutes(app) {\r\n /**\r\n * Adds the GET '/' - A route for a UI when enabled on the export server.\r\n */\r\n app.get(getOptions().ui.route || '/', (request, response, next) => {\r\n try {\r\n log(4, '[ui] Returning UI for the export.');\r\n\r\n response.sendFile(join(__dirname, 'public', 'index.html'), {\r\n acceptRanges: false\r\n });\r\n } catch (error) {\r\n return next(error);\r\n }\r\n });\r\n}\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * @overview Defines an Express route for updating the Highcharts version\r\n * on the server, with authentication and validation.\r\n */\r\n\r\nimport { updateHighchartsVersion, getHighchartsVersion } from '../../cache.js';\r\nimport { log } from '../../logger.js';\r\nimport { envs } from '../../validation.js';\r\n\r\nimport ExportError from '../../errors/ExportError.js';\r\n\r\n/**\r\n * Adds the `version_change` routes.\r\n *\r\n * @function versionChangeRoutes\r\n *\r\n * @param {Express} app - The Express app instance.\r\n */\r\nexport default function versionChangeRoutes(app) {\r\n /**\r\n * Adds the POST '/version_change/:newVersion' - A route for changing\r\n * the Highcharts version on the server.\r\n */\r\n app.post('/version_change/:newVersion', async (request, response, next) => {\r\n try {\r\n log(4, '[version] Changing Highcharts version.');\r\n\r\n // Get the token directly from envs\r\n const adminToken = envs.HIGHCHARTS_ADMIN_TOKEN;\r\n\r\n // Check the existence of the token\r\n if (!adminToken || !adminToken.length) {\r\n throw new ExportError(\r\n '[version] The server is not configured to perform run-time version changes: HIGHCHARTS_ADMIN_TOKEN is not set.',\r\n 401\r\n );\r\n }\r\n\r\n // Get the token from the hc-auth header\r\n const token = request.get('hc-auth');\r\n\r\n // Check if the hc-auth header contain a correct token\r\n if (!token || token !== adminToken) {\r\n throw new ExportError(\r\n '[version] Invalid or missing token: Set the token in the hc-auth header.',\r\n 401\r\n );\r\n }\r\n\r\n // Compare versions\r\n let newVersion = request.params.newVersion;\r\n if (newVersion) {\r\n try {\r\n // Update version\r\n await updateHighchartsVersion(newVersion);\r\n } catch (error) {\r\n throw new ExportError(\r\n `[version] Version change: ${error.message}`,\r\n 400\r\n ).setError(error);\r\n }\r\n\r\n // Success\r\n response.status(200).send({\r\n statusCode: 200,\r\n highchartsVersion: getHighchartsVersion(),\r\n message: `Successfully updated Highcharts to version: ${newVersion}.`\r\n });\r\n } else {\r\n // No version specified\r\n throw new ExportError('[version] No new version supplied.', 400);\r\n }\r\n } catch (error) {\r\n return next(error);\r\n }\r\n });\r\n}\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * @overview A module that sets up and manages HTTP and HTTPS servers\r\n * for the Highcharts Export Server. It handles server initialization,\r\n * configuration, error handling, middleware setup, route definition, and rate\r\n * limiting. The module exports functions to start, stop, and manage server\r\n * instances, as well as utility functions for defining routes and attaching\r\n * middlewares.\r\n */\r\n\r\nimport { readFile } from 'fs/promises';\r\nimport { join } from 'path';\r\n\r\nimport cors from 'cors';\r\nimport express from 'express';\r\nimport http from 'http';\r\nimport https from 'https';\r\nimport multer from 'multer';\r\n\r\nimport { updateOptions } from '../config.js';\r\nimport { log, logWithStack } from '../logger.js';\r\nimport { __dirname, getAbsolutePath } from '../utils.js';\r\n\r\nimport errorMiddleware from './middlewares/error.js';\r\nimport rateLimitingMiddleware from './middlewares/rateLimiting.js';\r\nimport validationMiddleware from './middlewares/validation.js';\r\n\r\nimport exportRoutes from './routes/export.js';\r\nimport healthRoutes from './routes/health.js';\r\nimport uiRoutes from './routes/ui.js';\r\nimport versionChangeRoutes from './routes/versionChange.js';\r\n\r\nimport ExportError from '../errors/ExportError.js';\r\n\r\n// Array of an active servers\r\nconst activeServers = new Map();\r\n\r\n// Create express app\r\nconst app = express();\r\n\r\n/**\r\n * Starts an HTTP and/or HTTPS server based on the provided configuration.\r\n * The `serverOptions` object contains server-related properties (refer\r\n * to the `server` section in the `lib/schemas/config.js` file for details).\r\n *\r\n * @async\r\n * @function startServer\r\n *\r\n * @param {Object} serverOptions - The configuration object containing `server`\r\n * options. This object may include a partial or complete set of the `server`\r\n * options. If the options are partial, missing values will default\r\n * to the current global configuration.\r\n *\r\n * @returns {Promise} A Promise that resolves when the server is either\r\n * not enabled or no valid Express app is found, signaling the end of the\r\n * function's execution.\r\n *\r\n * @throws {ExportError} Throws an `ExportError` if the server cannot\r\n * be configured and started.\r\n */\r\nexport async function startServer(serverOptions) {\r\n try {\r\n // Update the instance options object\r\n const options = updateOptions({\r\n server: serverOptions\r\n });\r\n\r\n // Use validated options\r\n serverOptions = options.server;\r\n\r\n // Stop if not enabled\r\n if (!serverOptions.enable || !app) {\r\n throw new ExportError(\r\n '[server] Server cannot be started (not enabled or no correct Express app found).',\r\n 500\r\n );\r\n }\r\n\r\n // Too big limits lead to timeouts in the export process when\r\n // the rasterization timeout is set too low\r\n const uploadLimitBytes = serverOptions.uploadLimit * 1024 * 1024;\r\n\r\n // Memory storage for multer package\r\n const storage = multer.memoryStorage();\r\n\r\n // Enable parsing of form data (files) with multer package\r\n const upload = multer({\r\n storage,\r\n limits: {\r\n fieldSize: uploadLimitBytes\r\n }\r\n });\r\n\r\n // Disable the X-Powered-By header\r\n app.disable('x-powered-by');\r\n\r\n // Enable CORS support\r\n app.use(\r\n cors({\r\n methods: ['POST', 'GET', 'OPTIONS']\r\n })\r\n );\r\n\r\n // Getting a lot of `RangeNotSatisfiableError` exceptions (even though this\r\n // is a deprecated options, let's try to set it to false)\r\n app.use((request, response, next) => {\r\n response.set('Accept-Ranges', 'none');\r\n next();\r\n });\r\n\r\n // Enable body parser for JSON data\r\n app.use(\r\n express.json({\r\n limit: uploadLimitBytes\r\n })\r\n );\r\n\r\n // Enable body parser for URL-encoded form data\r\n app.use(\r\n express.urlencoded({\r\n extended: true,\r\n limit: uploadLimitBytes\r\n })\r\n );\r\n\r\n // Use only non-file multipart form fields\r\n app.use(upload.none());\r\n\r\n // Set up static folder's route\r\n app.use(express.static(join(__dirname, 'public')));\r\n\r\n // Listen HTTP server\r\n if (!serverOptions.ssl.force) {\r\n // Main server instance (HTTP)\r\n const httpServer = http.createServer(app);\r\n\r\n // Attach error handlers and listen to the server\r\n _attachServerErrorHandlers(httpServer);\r\n\r\n // Listen\r\n httpServer.listen(serverOptions.port, serverOptions.host, () => {\r\n // Save the reference to HTTP server\r\n activeServers.set(serverOptions.port, httpServer);\r\n\r\n log(\r\n 3,\r\n `[server] Started HTTP server on ${serverOptions.host}:${serverOptions.port}.`\r\n );\r\n });\r\n }\r\n\r\n // Listen HTTPS server\r\n if (serverOptions.ssl.enable) {\r\n // Set up an SSL server also\r\n let key, cert;\r\n\r\n try {\r\n // Get the SSL key\r\n key = await readFile(\r\n join(getAbsolutePath(serverOptions.ssl.certPath), 'server.key'),\r\n 'utf8'\r\n );\r\n\r\n // Get the SSL certificate\r\n cert = await readFile(\r\n join(getAbsolutePath(serverOptions.ssl.certPath), 'server.crt'),\r\n 'utf8'\r\n );\r\n } catch (error) {\r\n log(\r\n 2,\r\n `[server] Unable to load key/certificate from the '${serverOptions.ssl.certPath}' path. Could not run secured layer server.`\r\n );\r\n }\r\n\r\n if (key && cert) {\r\n // Main server instance (HTTPS)\r\n const httpsServer = https.createServer({ key, cert }, app);\r\n\r\n // Attach error handlers and listen to the server\r\n _attachServerErrorHandlers(httpsServer);\r\n\r\n // Listen\r\n httpsServer.listen(serverOptions.ssl.port, serverOptions.host, () => {\r\n // Save the reference to HTTPS server\r\n activeServers.set(serverOptions.ssl.port, httpsServer);\r\n\r\n log(\r\n 3,\r\n `[server] Started HTTPS server on ${serverOptions.host}:${serverOptions.ssl.port}.`\r\n );\r\n });\r\n }\r\n }\r\n\r\n // Set up the rate limiter\r\n rateLimitingMiddleware(app, serverOptions.rateLimiting);\r\n\r\n // Set up the validation handler\r\n validationMiddleware(app);\r\n\r\n // Set up routes\r\n exportRoutes(app);\r\n healthRoutes(app);\r\n uiRoutes(app);\r\n versionChangeRoutes(app);\r\n\r\n // Set up the centralized error handler\r\n errorMiddleware(app);\r\n } catch (error) {\r\n throw new ExportError(\r\n '[server] Could not configure and start the server.',\r\n 500\r\n ).setError(error);\r\n }\r\n}\r\n\r\n/**\r\n * Closes all servers associated with Express app instance.\r\n *\r\n * @function closeServers\r\n */\r\nexport function closeServers() {\r\n // Check if there are servers working\r\n if (activeServers.size > 0) {\r\n log(4, `[server] Closing all servers.`);\r\n\r\n // Close each one of servers\r\n for (const [port, server] of activeServers) {\r\n server.close(() => {\r\n activeServers.delete(port);\r\n log(4, `[server] Closed server on port: ${port}.`);\r\n });\r\n }\r\n }\r\n}\r\n\r\n/**\r\n * Get all servers associated with Express app instance.\r\n *\r\n * @function getServers\r\n *\r\n * @returns {Array.} Servers associated with Express app instance.\r\n */\r\nexport function getServers() {\r\n return activeServers;\r\n}\r\n\r\n/**\r\n * Get the Express instance.\r\n *\r\n * @function getExpress\r\n *\r\n * @returns {Express} The Express instance.\r\n */\r\nexport function getExpress() {\r\n return express;\r\n}\r\n\r\n/**\r\n * Get the Express app instance.\r\n *\r\n * @function getApp\r\n *\r\n * @returns {Express} The Express app instance.\r\n */\r\nexport function getApp() {\r\n return app;\r\n}\r\n\r\n/**\r\n * Enable rate limiting for the server.\r\n *\r\n * @function enableRateLimiting\r\n *\r\n * @param {Object} rateLimitingOptions - The configuration object containing\r\n * `rateLimiting` options. This object may include a partial or complete set\r\n * of the `rateLimiting` options. If the options are partial, missing values\r\n * will default to the current global configuration.\r\n */\r\nexport function enableRateLimiting(rateLimitingOptions) {\r\n // Update the instance options object\r\n const options = updateOptions({\r\n server: {\r\n rateLimiting: rateLimitingOptions\r\n }\r\n });\r\n\r\n // Set the rate limiting options\r\n rateLimitingMiddleware(app, options.server.rateLimitingOptions);\r\n}\r\n\r\n/**\r\n * Apply middleware(s) to a specific path.\r\n *\r\n * @function use\r\n *\r\n * @param {string} path - The path to which the middleware(s) should be applied.\r\n * @param {...Function} middlewares - The middleware function(s) to be applied.\r\n */\r\nexport function use(path, ...middlewares) {\r\n app.use(path, ...middlewares);\r\n}\r\n\r\n/**\r\n * Set up a route with GET method and apply middleware(s).\r\n *\r\n * @function get\r\n *\r\n * @param {string} path - The path to which the middleware(s) should be applied.\r\n * @param {...Function} middlewares - The middleware function(s) to be applied.\r\n */\r\nexport function get(path, ...middlewares) {\r\n app.get(path, ...middlewares);\r\n}\r\n\r\n/**\r\n * Set up a route with POST method and apply middleware(s).\r\n *\r\n * @function post\r\n *\r\n * @param {string} path - The path to which the middleware(s) should be applied.\r\n * @param {...Function} middlewares - The middleware function(s) to be applied.\r\n */\r\nexport function post(path, ...middlewares) {\r\n app.post(path, ...middlewares);\r\n}\r\n\r\n/**\r\n * Attach error handlers to the server.\r\n *\r\n * @function _attachServerErrorHandlers\r\n *\r\n * @param {(http.Server|https.Server)} server - The HTTP/HTTPS server instance.\r\n */\r\nfunction _attachServerErrorHandlers(server) {\r\n server.on('clientError', (error, socket) => {\r\n logWithStack(\r\n 1,\r\n error,\r\n `[server] Client error: ${error.message}, destroying socket.`\r\n );\r\n socket.destroy();\r\n });\r\n\r\n server.on('error', (error) => {\r\n logWithStack(1, error, `[server] Server error: ${error.message}`);\r\n });\r\n\r\n server.on('connection', (socket) => {\r\n socket.on('error', (error) => {\r\n logWithStack(1, error, `[server] Socket error: ${error.message}`);\r\n });\r\n });\r\n}\r\n\r\nexport default {\r\n startServer,\r\n closeServers,\r\n getServers,\r\n getExpress,\r\n getApp,\r\n enableRateLimiting,\r\n use,\r\n get,\r\n post\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * @overview Handles graceful shutdown of the Highcharts Export Server, ensuring\r\n * proper cleanup of resources such as browser, pages, servers, and timers.\r\n */\r\n\r\nimport { killPool } from './pool.js';\r\nimport { clearAllTimers } from './timer.js';\r\n\r\nimport { closeServers } from './server/server.js';\r\n\r\n/**\r\n * Performs cleanup operations to ensure a graceful shutdown of the process.\r\n * This includes clearing all registered timeouts/intervals, closing active\r\n * servers, terminating resources (pages) of the pool, pool itself, and closing\r\n * the browser.\r\n *\r\n * @function shutdownCleanUp\r\n *\r\n * @param {number} [exitCode=0] - The exit code to use with `process.exit()`.\r\n * The default value is `0`.\r\n */\r\nexport async function shutdownCleanUp(exitCode = 0) {\r\n // Await freeing all resources\r\n await Promise.allSettled([\r\n // Clear all ongoing intervals\r\n clearAllTimers(),\r\n\r\n // Get available server instances (HTTP/HTTPS) and close them\r\n closeServers(),\r\n\r\n // Close an active pool along with its workers and the browser instance\r\n killPool()\r\n ]);\r\n\r\n // Exit process with a correct code\r\n process.exit(exitCode);\r\n}\r\n\r\nexport default {\r\n shutdownCleanUp\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * @overview Core module for initializing and managing the Highcharts Export\r\n * Server. Provides functionalities for configuring exports, setting up server\r\n * operations, logging, scripts caching, resource pooling, and graceful process\r\n * cleanup.\r\n */\r\n\r\nimport 'colors';\r\n\r\nimport { checkAndUpdateCache } from './cache.js';\r\nimport {\r\n singleExport,\r\n batchExport,\r\n startExport,\r\n setAllowCodeExecution\r\n} from './chart.js';\r\nimport {\r\n getOptions,\r\n updateOptions,\r\n setGlobalOptions,\r\n mapToNewOptions\r\n} from './config.js';\r\nimport {\r\n log,\r\n logWithStack,\r\n logZodIssues,\r\n initLogging,\r\n enableConsoleLogging,\r\n enableFileLogging,\r\n setLogLevel\r\n} from './logger.js';\r\nimport { initPool, killPool } from './pool.js';\r\nimport { shutdownCleanUp } from './resourceRelease.js';\r\n\r\nimport server from './server/server.js';\r\n\r\n/**\r\n * Initializes the export process. Tasks such as configuring logging, checking\r\n * the cache and sources, and initializing the resource pool occur during this\r\n * stage.\r\n *\r\n * This function must be called before attempting to export charts or set\r\n * up a server.\r\n *\r\n * @async\r\n * @function initExport\r\n *\r\n * @param {Object} [initOptions={}] - The `initOptions` object, which may\r\n * be a partial or complete set of options. If the options are partial, missing\r\n * values will default to the current global configuration. The default value\r\n * is an empty object.\r\n */\r\nexport async function initExport(initOptions = {}) {\r\n // Init and update the instance options object\r\n const options = updateOptions(initOptions, true);\r\n\r\n // Set the `allowCodeExecution` per export module scope\r\n setAllowCodeExecution(options.customLogic.allowCodeExecution);\r\n\r\n // Init the logging\r\n initLogging(options.logging);\r\n\r\n // Attach process' exit listeners\r\n if (options.other.listenToProcessExits) {\r\n _attachProcessExitListeners();\r\n }\r\n\r\n // Check if cache needs to be updated\r\n await checkAndUpdateCache(options.highcharts, options.server.proxy);\r\n\r\n // Init the pool\r\n await initPool(options.pool, options.puppeteer.args);\r\n}\r\n\r\n/**\r\n * Attaches exit listeners to the process, ensuring proper cleanup of resources\r\n * and termination on exit signals. Handles 'exit', 'SIGINT', 'SIGTERM'\r\n * and 'uncaughtException' events.\r\n *\r\n * @function _attachProcessExitListeners\r\n */\r\nfunction _attachProcessExitListeners() {\r\n log(3, '[process] Attaching exit listeners to the process.');\r\n\r\n // Handler for the 'exit'\r\n process.on('exit', (code) => {\r\n log(4, `[process] Process exited with code ${code}.`);\r\n });\r\n\r\n // Handler for the 'SIGINT'\r\n process.on('SIGINT', async (name, code) => {\r\n log(4, `[process] The ${name} event with code: ${code}.`);\r\n await shutdownCleanUp();\r\n });\r\n\r\n // Handler for the 'SIGTERM'\r\n process.on('SIGTERM', async (name, code) => {\r\n log(4, `[process] The ${name} event with code: ${code}.`);\r\n await shutdownCleanUp();\r\n });\r\n\r\n // Handler for the 'SIGHUP'\r\n process.on('SIGHUP', async (name, code) => {\r\n log(4, `[process] The ${name} event with code: ${code}.`);\r\n await shutdownCleanUp();\r\n });\r\n\r\n // Handler for the 'uncaughtException'\r\n process.on('uncaughtException', async (error, name) => {\r\n logWithStack(1, error, `[process] The ${name} error.`);\r\n await shutdownCleanUp(1);\r\n });\r\n}\r\n\r\nexport default {\r\n // Server\r\n ...server,\r\n\r\n // Options\r\n getOptions,\r\n setGlobalOptions,\r\n mapToNewOptions,\r\n\r\n // Exporting\r\n initExport,\r\n singleExport,\r\n batchExport,\r\n startExport,\r\n\r\n // Release\r\n killPool,\r\n shutdownCleanUp,\r\n\r\n // Logs\r\n log,\r\n logWithStack,\r\n logZodIssues,\r\n setLogLevel: function (level) {\r\n // Update the instance options object\r\n const options = updateOptions({\r\n logging: {\r\n level\r\n }\r\n });\r\n\r\n // Call the function\r\n setLogLevel(options.logging.level);\r\n },\r\n enableConsoleLogging: function (toConsole) {\r\n // Update the instance options object\r\n const options = updateOptions({\r\n logging: {\r\n toConsole\r\n }\r\n });\r\n\r\n // Call the function\r\n enableConsoleLogging(options.logging.toConsole);\r\n },\r\n enableFileLogging: function (dest, file, toFile) {\r\n // Update the instance options object\r\n const options = updateOptions({\r\n logging: {\r\n dest,\r\n file,\r\n toFile\r\n }\r\n });\r\n\r\n // Call the function\r\n enableFileLogging(\r\n options.logging.dest,\r\n options.logging.file,\r\n options.logging.toFile\r\n );\r\n }\r\n};\r\n"],"names":["__dirname","fileURLToPath","URL","url","deepCopy","objArr","objArrCopy","Array","isArray","key","Object","prototype","hasOwnProperty","call","fixConstr","constr","fixedConstr","toLowerCase","replace","includes","fixOutfile","type","outfile","getAbsolutePath","split","shift","fixType","mimeTypes","formats","values","outType","pop","find","t","path","isAbsolute","join","getBase64","input","Buffer","from","toString","getNewDate","Date","trim","getNewDateTime","getTime","isObject","item","isObjectEmpty","keys","length","isPrivateRangeUrlFound","some","pattern","test","measureTime","start","process","hrtime","bigint","Number","roundNumber","value","precision","multiplier","Math","pow","round","wrapAround","customCode","allowFileResources","isCallback","endsWith","readFileSync","startsWith","colors","logging","toConsole","toFile","pathCreated","pathToLog","levelsDesc","title","color","log","args","newLevel","texts","level","prefix","_logToFile","console","apply","undefined","concat","logWithStack","error","customMessage","mainMessage","message","stackMessage","stack","push","logZodIssues","issues","map","issue","initLogging","loggingOptions","dest","file","setLogLevel","enableConsoleLogging","enableFileLogging","isInteger","existsSync","mkdirSync","appendFile","defaultConfig","puppeteer","types","envLink","cliName","description","promptOptions","separator","highcharts","version","cdnUrl","forceFetch","cachePath","coreScripts","instructions","moduleScripts","indicatorScripts","customScripts","export","infile","instr","options","svg","batch","hint","choices","b64","noDownload","height","width","scale","defaultHeight","defaultWidth","defaultScale","min","max","globalOptions","themeOptions","rasterizationTimeout","customLogic","allowCodeExecution","callback","resources","loadConfig","legacyName","createConfig","server","enable","host","port","uploadLimit","benchmarking","proxy","timeout","rateLimiting","maxRequests","window","delay","trustProxy","skipKey","skipToken","ssl","force","certPath","pool","minWorkers","maxWorkers","workLimit","acquireTimeout","createTimeout","destroyTimeout","idleTimeout","createRetryInterval","reaperInterval","ui","route","other","nodeEnv","listenToProcessExits","noLogo","hardResetPage","browserShellMode","debug","headless","devtools","listenToConsole","dumpio","slowMo","debuggingPort","nestedProps","_createNestedProps","absoluteProps","_createAbsoluteProps","config","propChain","forEach","entry","substring","dotenv","z","setErrorMap","_customErrorMap","v","boolean","strictCheck","union","enum","transform","nullable","string","refine","params","errorMessage","stringArray","filterCallback","arraySchema","array","stringSchema","slice","transformCallback","filter","positiveNum","number","positive","isNaN","nonNegativeNum","nonnegative","prefixes","chartConfig","indexOf","object","passthrough","additionalOptions","adminToken","gte","lte","this","objectSchema","js","css","files","partial","stringSchema1","stringSchema2","enableServer","serverBenchmarking","proxyHost","proxyPort","proxyTimeout","enableRateLimiting","enableSsl","sslForce","sslPort","sslCertPath","poolBenchmarking","resourcesInterval","logLevel","int","logFile","logDest","logToConsole","logToFile","enableUi","uiRoute","enableDebug","requestId","uuid","PuppeteerSchema","HighchartsSchema","ExportSchema","CustomLogicSchema","ProxySchema","RateLimitingSchema","SslSchema","ServerSchema","optional","PoolSchema","LoggingSchema","UiSchema","OtherSchema","DebugSchema","StrictConfigSchema","LooseConfigSchema","EnvSchema","PUPPETEER_ARGS","HIGHCHARTS_VERSION","HIGHCHARTS_CDN_URL","HIGHCHARTS_FORCE_FETCH","HIGHCHARTS_CACHE_PATH","HIGHCHARTS_ADMIN_TOKEN","HIGHCHARTS_CORE_SCRIPTS","HIGHCHARTS_MODULE_SCRIPTS","HIGHCHARTS_INDICATOR_SCRIPTS","HIGHCHARTS_CUSTOM_SCRIPTS","EXPORT_INFILE","EXPORT_INSTR","EXPORT_OPTIONS","EXPORT_SVG","EXPORT_BATCH","EXPORT_OUTFILE","EXPORT_TYPE","EXPORT_CONSTR","EXPORT_B64","EXPORT_NO_DOWNLOAD","EXPORT_HEIGHT","EXPORT_WIDTH","EXPORT_SCALE","EXPORT_DEFAULT_HEIGHT","EXPORT_DEFAULT_WIDTH","EXPORT_DEFAULT_SCALE","EXPORT_GLOBAL_OPTIONS","EXPORT_THEME_OPTIONS","EXPORT_RASTERIZATION_TIMEOUT","CUSTOM_LOGIC_ALLOW_CODE_EXECUTION","CUSTOM_LOGIC_ALLOW_FILE_RESOURCES","CUSTOM_LOGIC_CUSTOM_CODE","CUSTOM_LOGIC_CALLBACK","CUSTOM_LOGIC_RESOURCES","CUSTOM_LOGIC_LOAD_CONFIG","CUSTOM_LOGIC_CREATE_CONFIG","SERVER_ENABLE","SERVER_HOST","SERVER_PORT","SERVER_UPLOAD_LIMIT","SERVER_BENCHMARKING","SERVER_PROXY_HOST","SERVER_PROXY_PORT","SERVER_PROXY_TIMEOUT","SERVER_RATE_LIMITING_ENABLE","SERVER_RATE_LIMITING_MAX_REQUESTS","SERVER_RATE_LIMITING_WINDOW","SERVER_RATE_LIMITING_DELAY","SERVER_RATE_LIMITING_TRUST_PROXY","SERVER_RATE_LIMITING_SKIP_KEY","SERVER_RATE_LIMITING_SKIP_TOKEN","SERVER_SSL_ENABLE","SERVER_SSL_FORCE","SERVER_SSL_PORT","SERVER_SSL_CERT_PATH","POOL_MIN_WORKERS","POOL_MAX_WORKERS","POOL_WORK_LIMIT","POOL_ACQUIRE_TIMEOUT","POOL_CREATE_TIMEOUT","POOL_DESTROY_TIMEOUT","POOL_IDLE_TIMEOUT","POOL_CREATE_RETRY_INTERVAL","POOL_REAPER_INTERVAL","POOL_BENCHMARKING","LOGGING_LEVEL","LOGGING_FILE","LOGGING_DEST","LOGGING_TO_CONSOLE","LOGGING_TO_FILE","UI_ENABLE","UI_ROUTE","OTHER_NODE_ENV","OTHER_LISTEN_TO_PROCESS_EXITS","OTHER_NO_LOGO","OTHER_HARD_RESET_PAGE","OTHER_BROWSER_SHELL_MODE","DEBUG_ENABLE","DEBUG_HEADLESS","DEBUG_DEVTOOLS","DEBUG_LISTEN_TO_CONSOLE","DEBUG_DUMPIO","DEBUG_SLOW_MO","DEBUG_DEBUGGING_PORT","envs","parse","env","strictValidate","configOptions","looseValidate","validateOption","name","option","context","propertyName","propertyInfo","code","ZodIssueCode","invalid_type","received","ZodParsedType","defaultError","custom","data","invalid_union","unionErrors","index","_initGlobalOptions","instanceOptions","getOptions","getInstance","setGlobalOptions","customOptions","cliArgs","cliOptions","_loadConfigFile","_pairArgumentValue","_updateGlobalOptions","updateOptions","newInstance","mergeOptions","originalOptions","newOptions","entries","mapToNewOptions","oldOptions","propertiesChain","reduce","obj","prop","isAllowedConfig","allowFunctions","objectConfig","eval","JSON","stringifiedOptions","_optionsStringify","parsedOptions","_","envVal","configOpt","cliOpt","customOpt","configVal","cliVal","customVal","stringifyFunctions","stringify","replaceAll","Error","customLogicOptions","configIndex","findIndex","arg","i","async","fetch","requestOptions","Promise","resolve","reject","_getProtocolModule","get","response","responseData","on","chunk","text","https","http","ExportError","constructor","statusCode","super","setStatus","setError","cache","activeManifest","sources","hcVersion","checkAndUpdateCache","highchartsOptions","serverProxyOptions","fetchedModules","getCachePath","manifestPath","sourcePath","recursive","_updateCache","requestUpdate","manifest","modules","moduleMap","m","numberOfModules","moduleName","extractVersion","_saveConfigToManifest","getHighchartsVersion","updateHighchartsVersion","newVersion","cacheSources","extractModuleName","scriptPath","_fetchAndProcessScript","script","shouldThrowError","newManifest","writeFileSync","_fetchScripts","proxyAgent","HttpsProxyAgent","agent","allFetchPromises","all","c","setupHighcharts","Highcharts","animObject","duration","createChart","exportOptions","setOptions","merge","wrap","setOptionsObj","isRenderComplete","Chart","proceed","userOptions","cb","exporting","enabled","plotOptions","series","label","tooltip","animation","onHighchartsRender","addEvent","Series","chart","Function","finalOptions","finalCallback","defaultOptions","template","browser","createBrowser","puppeteerArgs","enabledDebug","debugOptions","launchOptions","userDataDir","handleSIGINT","handleSIGTERM","handleSIGHUP","waitForInitialPage","defaultViewport","tryCount","open","launch","setTimeout","closeBrowser","connected","close","newPage","poolResource","page","setCacheEnabled","_setPageContent","_setPageEvents","isClosed","clearPage","hardReset","goto","waitUntil","evaluate","document","body","innerHTML","id","workCount","addPageResources","injectedResources","injectedJs","content","isLocal","jsResource","addScriptTag","injectedCss","cssImports","match","cssImportPath","cssResource","addStyleTag","clearPageResources","resource","dispose","oldCharts","charts","oldChart","destroy","scriptsToRemove","getElementsByTagName","stylesToRemove","linksToRemove","element","remove","setContent","cssTemplate","svgTemplate","puppeteerExport","isSVG","size","svgElement","querySelector","chartHeight","baseVal","chartWidth","style","zoom","margin","parseFloat","x","y","_getClipRegion","viewportHeight","abs","ceil","viewportWidth","result","setViewport","deviceScaleFactor","_createSVG","_createImage","_createPDF","$eval","getBoundingClientRect","trunc","outerHTML","clip","race","screenshot","encoding","fullPage","optimizeForSpeed","captureBeyondViewport","quality","omitBackground","_resolve","emulateMediaType","pdf","poolStats","exportsAttempted","exportsPerformed","exportsDropped","exportsFromSvg","exportsFromOptions","exportsFromSvgAttempts","exportsFromOptionsAttempts","timeSpent","timeSpentAverage","initPool","poolOptions","Pool","_factory","acquireTimeoutMillis","createTimeoutMillis","destroyTimeoutMillis","idleTimeoutMillis","createRetryIntervalMillis","reapIntervalMillis","propagateCreateError","clearStatus","_eventId","initialResources","acquire","promise","release","killPool","worker","used","destroyed","postWork","workerHandle","getPoolInfo","acquireCounter","workStart","exportCounter","exportTime","getPoolStats","getPoolInfoJSON","numUsed","available","numFree","allCreated","pendingAcquires","numPendingAcquires","pendingCreates","numPendingCreates","pendingValidations","numPendingValidations","pendingDestroys","absoluteAll","create","random","startDate","validate","mainFrame","detached","removeAllListeners","sanitize","JSDOM","DOMPurify","ADD_TAGS","singleExport","startExport","batchExport","batchFunctions","pair","batchResults","allSettled","reason","exportingOptions","endCallback","fileContent","_exportFromSvg","_exportFromOptions","getAllowCodeExecution","setAllowCodeExecution","inputToExport","_prepareExport","_handleCustomLogic","_handleGlobalAndTheme","_findChartSize","optionsChart","optionsExporting","globalOptionsChart","globalOptionsExporting","themeOptionsChart","themeOptionsExporting","sourceHeight","sourceWidth","param","_handleResources","allowedProps","handledResources","correctResources","propName","optionsName","timerIds","addTimer","clearAllTimers","clearInterval","clearTimeout","logErrorMiddleware","request","next","returnErrorMiddleware","status","json","errorMiddleware","app","use","rateLimitingMiddleware","rateLimitingOptions","rateOptions","limiter","rateLimit","windowMs","limit","delayMs","handler","format","send","default","skip","query","access_token","contentTypeMiddleware","contentType","headers","requestBodyMiddleware","connection","remoteAddress","validatedOptions","_requestId","filename","validationMiddleware","post","reversedMime","png","jpeg","gif","requestExport","requestCounter","connectionAborted","socket","hadErrors","header","attachment","exportRoutes","serverStartTime","packageFile","successRates","recordInterval","windowSize","_calculateMovingAverage","a","b","_startSuccessRate","setInterval","stats","successRatio","healthRoutes","period","movingAverage","bootTime","uptime","floor","serverVersion","highchartsVersion","averageExportTime","attemptedExports","performedExports","failedExports","sucessRatio","toFixed","svgExports","jsonExports","svgExportsAttempts","jsonExportsAttempts","uiRoutes","sendFile","acceptRanges","versionChangeRoutes","token","activeServers","Map","express","startServer","serverOptions","uploadLimitBytes","storage","multer","memoryStorage","upload","limits","fieldSize","disable","cors","methods","set","urlencoded","extended","none","static","httpServer","createServer","_attachServerErrorHandlers","listen","cert","readFile","httpsServer","closeServers","delete","getServers","getExpress","getApp","middlewares","shutdownCleanUp","exitCode","exit","initExport","initOptions","_attachProcessExitListeners"],"mappings":"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A,OACA,aACA,mBACA,eACA,cACA,UACA,UACA,cACA,WACA,UACA,YACA,cACA,YACA,sBACA,SACA,SACA,WACA,aACA,YACA,eACA,yBACA,SACA,eACA,YACA,kBACA,SACA,cACA,mBACA,eACA,kBACA,cACA,eAEA,cACA,WACA,eACA,WACA,SACA,OACA,WACA,YACA,SACA,qBACA,aACA,WACA,WACA,WACA,WACA,eACA,UACA,kBACA,oBACA,aACA,UACA,cACA,YACA,YAEF0D,MAAO,CAAC,YACRC,QAAS,4BACTE,YAAa,qCACbC,cAAe,CACbxG,KAAM,cACNgH,aAAc,0DAGlBE,iBAAkB,CAChBxE,MAAO,CAAC,kBACR0D,MAAO,CAAC,YACRC,QAAS,+BACTE,YAAa,wCACbC,cAAe,CACbxG,KAAM,cACNgH,aAAc,0DAGlBG,cAAe,CACbzE,MAAO,CACL,wEACA,kGAEF0D,MAAO,CAAC,YACRC,QAAS,4BACTE,YAAa,qDACbC,cAAe,CACbxG,KAAM,OACNyG,UAAW,OAIjBW,OAAQ,CACNC,OAAQ,CACN3E,MAAO,KACP0D,MAAO,CAAC,SAAU,QAClBC,QAAS,gBACTE,YACE,+DACFC,cAAe,CACbxG,KAAM,SAGVsH,MAAO,CACL5E,MAAO,KACP0D,MAAO,CAAC,SAAU,SAAU,QAC5BC,QAAS,eACTE,YACE,mEACFC,cAAe,CACbxG,KAAM,SAGVuH,QAAS,CACP7E,MAAO,KACP0D,MAAO,CAAC,SAAU,SAAU,QAC5BC,QAAS,iBACTE,YAAa,+BACbC,cAAe,CACbxG,KAAM,SAGVwH,IAAK,CACH9E,MAAO,KACP0D,MAAO,CAAC,SAAU,QAClBC,QAAS,aACTE,YAAa,mDACbC,cAAe,CACbxG,KAAM,SAGVyH,MAAO,CACL/E,MAAO,KACP0D,MAAO,CAAC,SAAU,QAClBC,QAAS,eACTE,YACE,gEACFC,cAAe,CACbxG,KAAM,SAGVC,QAAS,CACPyC,MAAO,KACP0D,MAAO,CAAC,SAAU,QAClBC,QAAS,iBACTE,YACE,qFACFC,cAAe,CACbxG,KAAM,SAGVA,KAAM,CACJ0C,MAAO,MACP0D,MAAO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"} \ No newline at end of file +{"version":3,"file":"index.esm.js","sources":["../lib/utils.js","../lib/logger.js","../lib/schemas/config.js","../lib/validation.js","../lib/errors/ExportError.js","../lib/config.js","../lib/fetch.js","../lib/cache.js","../lib/highcharts.js","../lib/browser.js","../templates/svgExport/css.js","../templates/svgExport/svgExport.js","../lib/export.js","../lib/pool.js","../lib/sanitize.js","../lib/chart.js","../lib/timer.js","../lib/server/middlewares/error.js","../lib/server/middlewares/rateLimiting.js","../lib/server/middlewares/validation.js","../lib/server/routes/export.js","../lib/server/routes/health.js","../lib/server/routes/ui.js","../lib/server/routes/versionChange.js","../lib/server/server.js","../lib/resourceRelease.js","../lib/index.js"],"sourcesContent":["/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * @overview The Highcharts Export Server utility module provides\r\n * a comprehensive set of helper functions and constants designed to streamline\r\n * and enhance various operations required for Highcharts export tasks.\r\n */\r\n\r\nimport { readFileSync } from 'fs';\r\nimport { isAbsolute, join } from 'path';\r\nimport { fileURLToPath } from 'url';\r\n\r\nconst MAX_BACKOFF_ATTEMPTS = 6;\r\n\r\n// The directory path\r\nexport const __dirname = fileURLToPath(new URL('../.', import.meta.url));\r\n\r\n/**\r\n * Clears and standardizes text by replacing multiple consecutive whitespace\r\n * characters with a single space and trimming any leading or trailing\r\n * whitespace.\r\n *\r\n * @function clearText\r\n *\r\n * @param {string} text - The input text to be cleared.\r\n * @param {RegExp} [rule=/\\s\\s+/g] - The regular expression rule to match\r\n * multiple consecutive whitespace characters. The default value\r\n * is the '/\\s\\s+/g' RegExp.\r\n * @param {string} [replacer=' '] - The string used to replace multiple\r\n * consecutive whitespace characters. The default value is the ' ' string.\r\n *\r\n * @returns {string} The cleared and standardized text.\r\n */\r\nexport function clearText(text, rule = /\\s\\s+/g, replacer = ' ') {\r\n return text.replaceAll(rule, replacer).trim();\r\n}\r\n\r\n/**\r\n * Creates a deep copy of the given object or array.\r\n *\r\n * @function deepCopy\r\n *\r\n * @param {(Object|Array)} objArr - The object or array to be deeply copied.\r\n *\r\n * @returns {(Object|Array)} The deep copy of the provided object or array.\r\n */\r\nexport function deepCopy(objArr) {\r\n // If the `objArr` is null or not of the `object` type, return it\r\n if (objArr === null || typeof objArr !== 'object') {\r\n return objArr;\r\n }\r\n\r\n // Prepare either a new array or a new object\r\n const objArrCopy = Array.isArray(objArr) ? [] : {};\r\n\r\n // Recursively copy each property\r\n for (const key in objArr) {\r\n if (Object.prototype.hasOwnProperty.call(objArr, key)) {\r\n objArrCopy[key] = deepCopy(objArr[key]);\r\n }\r\n }\r\n\r\n // Return the copied object\r\n return objArrCopy;\r\n}\r\n\r\n/**\r\n * Implements an exponential backoff strategy for retrying a function until\r\n * a certain number of attempts are reached.\r\n *\r\n * @async\r\n * @function expBackoff\r\n *\r\n * @param {Function} fn - The function to be retried.\r\n * @param {number} [attempt=0] - The current attempt number. The default value\r\n * is `0`.\r\n * @param {...unknown} args - Arguments to be passed to the function.\r\n *\r\n * @returns {Promise} A Promise that resolves to the result\r\n * of the function if successful.\r\n *\r\n * @throws {Error} Throws an `Error` if the maximum number of attempts\r\n * is reached.\r\n */\r\nexport async function expBackoff(fn, attempt = 0, ...args) {\r\n try {\r\n // Try to call the function\r\n return await fn(...args);\r\n } catch (error) {\r\n // Calculate delay in ms\r\n const delayInMs = 2 ** attempt * 1000;\r\n\r\n // If the attempt exceeds the maximum attempts of repeat, throw an error\r\n if (++attempt >= MAX_BACKOFF_ATTEMPTS) {\r\n throw error;\r\n }\r\n\r\n // Wait given amount of time\r\n await new Promise((response) => setTimeout(response, delayInMs));\r\n\r\n /// TO DO: Correct\r\n // // Information about the resource timeout\r\n // log(\r\n // 3,\r\n // `[utils] Waited ${delayInMs}ms until next call for the resource of ID: ${args[0]}.`\r\n // );\r\n\r\n // Try again\r\n return expBackoff(fn, attempt, ...args);\r\n }\r\n}\r\n\r\n/**\r\n * Adjusts the constructor name by transforming and normalizing it based\r\n * on common chart types.\r\n *\r\n * @function fixConstr\r\n *\r\n * @param {string} constr - The original constructor name to be fixed.\r\n *\r\n * @returns {string} The corrected constructor name, or 'chart' if the input\r\n * is not recognized.\r\n */\r\nexport function fixConstr(constr) {\r\n try {\r\n // Fix the constructor by lowering casing\r\n const fixedConstr = `${constr.toLowerCase().replace('chart', '')}Chart`;\r\n\r\n // Handle the case where the result is just 'Chart'\r\n if (fixedConstr === 'Chart') {\r\n fixedConstr.toLowerCase();\r\n }\r\n\r\n // Return the corrected constructor, otherwise default to 'chart'\r\n return ['chart', 'stockChart', 'mapChart', 'ganttChart'].includes(\r\n fixedConstr\r\n )\r\n ? fixedConstr\r\n : 'chart';\r\n } catch {\r\n // Default to 'chart' in case of any error\r\n return 'chart';\r\n }\r\n}\r\n\r\n/**\r\n * Fixes the outfile based on provided type.\r\n *\r\n * @function fixOutfile\r\n *\r\n * @param {string} type - The original export type.\r\n * @param {string} outfile - The file path or name.\r\n *\r\n * @returns {string} The corrected outfile.\r\n */\r\nexport function fixOutfile(type, outfile) {\r\n // Get the file name from the `outfile` option\r\n const fileName = getAbsolutePath(outfile || 'chart')\r\n .split('.')\r\n .shift();\r\n\r\n // Return a correct outfile\r\n return `${fileName}.${type}`;\r\n}\r\n\r\n/**\r\n * Fixes the export type based on MIME types and file extensions.\r\n *\r\n * @function fixType\r\n *\r\n * @param {string} type - The original export type.\r\n * @param {string} [outfile=null] - The file path or name. The default value\r\n * is `null`.\r\n *\r\n * @returns {string} The corrected export type.\r\n */\r\nexport function fixType(type, outfile = null) {\r\n // MIME types\r\n const mimeTypes = {\r\n 'image/png': 'png',\r\n 'image/jpeg': 'jpeg',\r\n 'application/pdf': 'pdf',\r\n 'image/svg+xml': 'svg'\r\n };\r\n\r\n // Get formats\r\n const formats = Object.values(mimeTypes);\r\n\r\n // Check if type and outfile's extensions are the same\r\n if (outfile) {\r\n const outType = outfile.split('.').pop();\r\n\r\n // Support the JPG type\r\n if (outType === 'jpg') {\r\n type = 'jpeg';\r\n } else if (formats.includes(outType) && type !== outType) {\r\n type = outType;\r\n }\r\n }\r\n\r\n // Return a correct type\r\n return mimeTypes[type] || formats.find((t) => t === type) || 'png';\r\n}\r\n\r\n/**\r\n * Checks if the given path is relative or absolute and returns the corrected,\r\n * absolute path.\r\n *\r\n * @function isAbsolutePath\r\n *\r\n * @param {string} path - The path to be checked on.\r\n *\r\n * @returns {string} The absolute path.\r\n */\r\nexport function getAbsolutePath(path) {\r\n return isAbsolute(path) ? path : join(__dirname, path);\r\n}\r\n\r\n/**\r\n * Converts input data to a Base64 string based on the export type.\r\n *\r\n * @function getBase64\r\n *\r\n * @param {string} input - The input to be transformed to Base64 format.\r\n * @param {string} type - The original export type.\r\n *\r\n * @returns {string} The Base64 string representation of the input.\r\n */\r\nexport function getBase64(input, type) {\r\n // For pdf and svg types the input must be transformed to Base64 from a buffer\r\n if (type === 'pdf' || type == 'svg') {\r\n return Buffer.from(input, 'utf8').toString('base64');\r\n }\r\n\r\n // For png and jpeg input is already a Base64 string\r\n return input;\r\n}\r\n\r\n/**\r\n * Returns stringified date without the GMT text information.\r\n *\r\n * @function getNewDate\r\n */\r\nexport function getNewDate() {\r\n // Get rid of the GMT text information\r\n return new Date().toString().split('(')[0].trim();\r\n}\r\n\r\n/**\r\n * Returns the stored time value in milliseconds.\r\n *\r\n * @function getNewDateTime\r\n */\r\nexport function getNewDateTime() {\r\n return new Date().getTime();\r\n}\r\n\r\n/**\r\n * Checks if the given item is an object.\r\n *\r\n * @function isObject\r\n *\r\n * @param {unknown} item - The item to be checked.\r\n *\r\n * @returns {boolean} True if the item is an object, false otherwise.\r\n */\r\nexport function isObject(item) {\r\n return Object.prototype.toString.call(item) === '[object Object]';\r\n}\r\n\r\n/**\r\n * Checks if the given object is empty.\r\n *\r\n * @function isObjectEmpty\r\n *\r\n * @param {Object} item - The object to be checked.\r\n *\r\n * @returns {boolean} True if the object is empty, false otherwise.\r\n */\r\nexport function isObjectEmpty(item) {\r\n return (\r\n typeof item === 'object' &&\r\n !Array.isArray(item) &&\r\n item !== null &&\r\n Object.keys(item).length === 0\r\n );\r\n}\r\n\r\n/**\r\n * Checks if a private IP range URL is found in the given string.\r\n *\r\n * @function isPrivateRangeUrlFound\r\n *\r\n * @param {string} item - The string to be checked for a private IP range URL.\r\n *\r\n * @returns {boolean} True if a private IP range URL is found, false otherwise.\r\n */\r\nexport function isPrivateRangeUrlFound(item) {\r\n const regexPatterns = [\r\n /xlink:href=\"(?:http:\\/\\/|https:\\/\\/)?localhost\\b/,\r\n /xlink:href=\"(?:http:\\/\\/|https:\\/\\/)?10\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\b/,\r\n /xlink:href=\"(?:http:\\/\\/|https:\\/\\/)?127\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\b/,\r\n /xlink:href=\"(?:http:\\/\\/|https:\\/\\/)?172\\.(1[6-9]|2[0-9]|3[0-1])\\.\\d{1,3}\\.\\d{1,3}\\b/,\r\n /xlink:href=\"(?:http:\\/\\/|https:\\/\\/)?192\\.168\\.\\d{1,3}\\.\\d{1,3}\\b/\r\n ];\r\n\r\n return regexPatterns.some((pattern) => pattern.test(item));\r\n}\r\n\r\n/**\r\n * Utility to measure elapsed time using the Node.js `process.hrtime()` method.\r\n *\r\n * @function measureTime\r\n *\r\n * @returns {Function} A function to calculate the elapsed time in milliseconds.\r\n */\r\nexport function measureTime() {\r\n const start = process.hrtime.bigint();\r\n return () => Number(process.hrtime.bigint() - start) / 1000000;\r\n}\r\n\r\n/**\r\n * Rounds a number to the specified precision.\r\n *\r\n * @function roundNumber\r\n *\r\n * @param {number} value - The number to be rounded.\r\n * @param {number} precision - The number of decimal places to round to.\r\n *\r\n * @returns {number} The rounded number.\r\n */\r\nexport function roundNumber(value, precision = 1) {\r\n const multiplier = Math.pow(10, precision || 0);\r\n return Math.round(+value * multiplier) / multiplier;\r\n}\r\n\r\n/**\r\n * Converts a value to a boolean.\r\n *\r\n * @function toBoolean\r\n *\r\n * @param {unknown} item - The value to be converted to a boolean.\r\n *\r\n * @returns {boolean} The boolean representation of the input value.\r\n */\r\nexport function toBoolean(item) {\r\n return ['false', 'undefined', 'null', 'NaN', '0', ''].includes(item)\r\n ? false\r\n : !!item;\r\n}\r\n\r\n/**\r\n * Wraps custom code to execute it safely.\r\n *\r\n * @function wrapAround\r\n *\r\n * @param {string} customCode - The custom code to be wrapped.\r\n * @param {boolean} allowFileResources - Flag to allow loading code from a file.\r\n * @param {boolean} [isCallback=false] - Flag that indicates the returned code\r\n * must be in a callback format.\r\n *\r\n * @returns {(string|null)} The wrapped custom code or null if wrapping fails.\r\n */\r\nexport function wrapAround(customCode, allowFileResources, isCallback = false) {\r\n if (customCode && typeof customCode === 'string') {\r\n customCode = customCode.trim();\r\n\r\n if (customCode.endsWith('.js')) {\r\n // Load a file if the file resources are allowed\r\n return allowFileResources\r\n ? wrapAround(\r\n readFileSync(getAbsolutePath(customCode), 'utf8'),\r\n allowFileResources,\r\n isCallback\r\n )\r\n : null;\r\n } else if (\r\n !isCallback &&\r\n (customCode.startsWith('function()') ||\r\n customCode.startsWith('function ()') ||\r\n customCode.startsWith('()=>') ||\r\n customCode.startsWith('() =>'))\r\n ) {\r\n // Treat a function as a self-invoking expression\r\n return `(${customCode})()`;\r\n }\r\n\r\n // Or return as a stringified code\r\n return customCode.replace(/;$/, '');\r\n }\r\n}\r\n\r\nexport default {\r\n __dirname,\r\n clearText,\r\n deepCopy,\r\n expBackoff,\r\n fixConstr,\r\n fixOutfile,\r\n fixType,\r\n getAbsolutePath,\r\n getBase64,\r\n getNewDate,\r\n getNewDateTime,\r\n isObject,\r\n isObjectEmpty,\r\n isPrivateRangeUrlFound,\r\n measureTime,\r\n roundNumber,\r\n toBoolean,\r\n wrapAround\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * @overview A module for managing logging functionality with customizable\r\n * log levels, console and file logging options, and error handling support.\r\n * The module also ensures that file-based logs are stored in a structured\r\n * directory, creating the necessary paths automatically if they do not exist.\r\n */\r\n\r\nimport { appendFile, existsSync, mkdirSync } from 'fs';\r\nimport { join } from 'path';\r\n\r\nimport { getAbsolutePath, getNewDate } from './utils.js';\r\n\r\n// The available colors\r\nconst colors = ['red', 'yellow', 'blue', 'gray', 'green'];\r\n\r\n// The default logging config\r\nconst logging = {\r\n // Flags for logging status\r\n toConsole: true,\r\n toFile: false,\r\n pathCreated: false,\r\n // Full path to the log file\r\n pathToLog: '',\r\n // Log levels\r\n levelsDesc: [\r\n {\r\n title: 'error',\r\n color: colors[0]\r\n },\r\n {\r\n title: 'warning',\r\n color: colors[1]\r\n },\r\n {\r\n title: 'notice',\r\n color: colors[2]\r\n },\r\n {\r\n title: 'verbose',\r\n color: colors[3]\r\n },\r\n {\r\n title: 'benchmark',\r\n color: colors[4]\r\n }\r\n ]\r\n};\r\n\r\n/**\r\n * Logs a message with a specified log level. Accepts a variable number\r\n * of arguments. The arguments after the `level` are passed to `console.log`\r\n * and/or used to construct and append messages to a log file.\r\n *\r\n * @function log\r\n *\r\n * @param {...unknown} args - An array of arguments where the first is the log\r\n * level and the remaining are strings used to build the log message.\r\n *\r\n * @returns {void} Exits the function execution if attempting to log at a level\r\n * higher than allowed.\r\n */\r\nexport function log(...args) {\r\n const [newLevel, ...texts] = args;\r\n\r\n // Current logging options\r\n const { levelsDesc, level } = logging;\r\n\r\n // Check if the log level is within a correct range or is it a benchmark log\r\n if (\r\n newLevel !== 5 &&\r\n (newLevel === 0 || newLevel > level || level > levelsDesc.length)\r\n ) {\r\n return;\r\n }\r\n\r\n // Create a message's prefix\r\n const prefix = `${getNewDate()} [${levelsDesc[newLevel - 1].title}] -`;\r\n\r\n // Log to file\r\n if (logging.toFile) {\r\n _logToFile(texts, prefix);\r\n }\r\n\r\n // Log to console\r\n if (logging.toConsole) {\r\n console.log.apply(\r\n undefined,\r\n [prefix.toString()[logging.levelsDesc[newLevel - 1].color]].concat(texts)\r\n );\r\n }\r\n}\r\n\r\n/**\r\n * Logs an error message along with its stack trace. Optionally, a custom message\r\n * can be provided.\r\n *\r\n * @function logWithStack\r\n *\r\n * @param {number} newLevel - The log level.\r\n * @param {Error} error - The error object containing the stack trace.\r\n * @param {string} customMessage - An optional custom message to be included\r\n * in the log alongside the error.\r\n *\r\n * @returns {void} Exits the function execution if attempting to log at a level\r\n * higher than allowed.\r\n */\r\nexport function logWithStack(newLevel, error, customMessage) {\r\n // Get the main message\r\n const mainMessage = customMessage || (error && error.message) || '';\r\n\r\n // Current logging options\r\n const { level, levelsDesc } = logging;\r\n\r\n // Check if the log level is within a correct range\r\n if (newLevel === 0 || newLevel > level || level > levelsDesc.length) {\r\n return;\r\n }\r\n\r\n // Create a message's prefix\r\n const prefix = `${getNewDate()} [${levelsDesc[newLevel - 1].title}] -`;\r\n\r\n // Add the whole stack message\r\n const stackMessage = error && error.stack;\r\n\r\n // Combine custom message or error message with error stack message, if exists\r\n const texts = [mainMessage];\r\n if (stackMessage) {\r\n texts.push('\\n', stackMessage);\r\n }\r\n\r\n // Log to file\r\n if (logging.toFile) {\r\n _logToFile(texts, prefix);\r\n }\r\n\r\n // Log to console\r\n if (logging.toConsole) {\r\n console.log.apply(\r\n undefined,\r\n [prefix.toString()[logging.levelsDesc[newLevel - 1].color]].concat([\r\n texts.shift()[colors[newLevel - 1]],\r\n ...texts\r\n ])\r\n );\r\n }\r\n}\r\n\r\n/**\r\n * Logs an error message related to Zod validation issues. Optionally, a custom\r\n * message can be provided.\r\n *\r\n * @function logZodIssues\r\n *\r\n * @param {number} newLevel - The log level.\r\n * @param {Error[]} issues - An array of Zod validation issues.\r\n * @param {string} customMessage - An optional custom message to be included\r\n * in the log alongside the error.\r\n */\r\nexport function logZodIssues(newLevel, issues, customMessage) {\r\n logWithStack(\r\n newLevel,\r\n null,\r\n [\r\n `${customMessage || '[validation] Validation error'} - the following Zod issues occured:`,\r\n ...(issues || []).map((issue) => `- ${issue.message}`)\r\n ].join('\\n')\r\n );\r\n}\r\n\r\n/**\r\n * Initializes logging with the specified logging configuration.\r\n *\r\n * @function initLogging\r\n *\r\n * @param {Object} loggingOptions - The configuration object containing\r\n * `logging` options.\r\n */\r\nexport function initLogging(loggingOptions) {\r\n // Get options from the `loggingOptions` object\r\n const { level, dest, file, toConsole, toFile } = loggingOptions;\r\n\r\n // Reset flags to the default values\r\n logging.pathCreated = false;\r\n logging.pathToLog = '';\r\n\r\n // Set the logging level\r\n setLogLevel(level);\r\n\r\n // Set the console logging\r\n enableConsoleLogging(toConsole);\r\n\r\n // Set the file logging\r\n enableFileLogging(dest, file, toFile);\r\n}\r\n\r\n/**\r\n * Sets the log level to the specified value. Log levels are (`0` = no logging,\r\n * `1` = error, `2` = warning, `3` = notice, `4` = verbose, or `5` = benchmark).\r\n *\r\n * @function setLogLevel\r\n *\r\n * @param {number} level - The log level to be set.\r\n */\r\nexport function setLogLevel(level) {\r\n if (\r\n Number.isInteger(level) &&\r\n level >= 0 &&\r\n level <= logging.levelsDesc.length\r\n ) {\r\n // Update the module logging's `level` option\r\n logging.level = level;\r\n }\r\n}\r\n\r\n/**\r\n * Enables console logging.\r\n *\r\n * @function enableConsoleLogging\r\n *\r\n * @param {boolean} toConsole - The flag for setting the logging to the console.\r\n */\r\nexport function enableConsoleLogging(toConsole) {\r\n // Update the module logging's `toConsole` option\r\n logging.toConsole = !!toConsole;\r\n}\r\n\r\n/**\r\n * Enables file logging with the specified destination and log file name.\r\n *\r\n * @function enableFileLogging\r\n *\r\n * @param {string} dest - The destination path where the log file should\r\n * be saved.\r\n * @param {string} file - The name of the log file.\r\n * @param {boolean} toFile - A flag indicating whether logging should\r\n * be directed to a file.\r\n */\r\nexport function enableFileLogging(dest, file, toFile) {\r\n // Update the module logging's `toFile` option\r\n logging.toFile = !!toFile;\r\n\r\n // Set the `dest` and `file` options only if the file logging is enabled\r\n if (logging.toFile) {\r\n logging.dest = dest || '';\r\n logging.file = file || '';\r\n }\r\n}\r\n\r\n/**\r\n * Logs the provided texts to a file, if file logging is enabled. It creates\r\n * the necessary directory structure if not already created and appends\r\n * the content, including an optional prefix, to the specified log file.\r\n *\r\n * @function _logToFile\r\n *\r\n * @param {Array.} texts - An array of texts to be logged.\r\n * @param {string} prefix - An optional prefix to be added to each log entry.\r\n */\r\nfunction _logToFile(texts, prefix) {\r\n if (!logging.pathCreated) {\r\n // Create if does not exist\r\n !existsSync(getAbsolutePath(logging.dest)) &&\r\n mkdirSync(getAbsolutePath(logging.dest));\r\n\r\n // Create the full path\r\n logging.pathToLog = getAbsolutePath(join(logging.dest, logging.file));\r\n\r\n // We now assume the path is available, e.g. it's the responsibility\r\n // of the user to create the path with the correct access rights.\r\n logging.pathCreated = true;\r\n }\r\n\r\n // Add the content to a file\r\n appendFile(\r\n logging.pathToLog,\r\n [prefix].concat(texts).join(' ') + '\\n',\r\n (error) => {\r\n if (error && logging.toFile && logging.pathCreated) {\r\n logging.toFile = false;\r\n logging.pathCreated = false;\r\n logWithStack(2, error, `[logger] Unable to write to log file.`);\r\n }\r\n }\r\n );\r\n}\r\n\r\nexport default {\r\n log,\r\n logWithStack,\r\n logZodIssues,\r\n initLogging,\r\n setLogLevel,\r\n enableConsoleLogging,\r\n enableFileLogging\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * @overview Configuration management module for the Highcharts Export Server.\r\n * Provides default configurations that support environment variables, CLI\r\n * arguments, and interactive prompts for customization of options and features.\r\n * Additionally, it maps legacy options to modern structures, generates nested\r\n * argument mappings, and displays CLI usage information.\r\n */\r\n\r\n/**\r\n * The configuration object containing all available options, organized\r\n * by sections.\r\n *\r\n * This object includes:\r\n * - Default values for each option\r\n * - Data types for validation\r\n * - Names of corresponding environment variables\r\n * - Descriptions of each property\r\n * - Information used for prompts in interactive configuration\r\n * - [Optional] Corresponding CLI argument names for CLI usage\r\n * - [Optional] Legacy names from the previous PhantomJS-based server\r\n */\r\nexport const defaultConfig = {\r\n puppeteer: {\r\n args: {\r\n value: [\r\n '--allow-running-insecure-content',\r\n '--ash-no-nudges',\r\n '--autoplay-policy=user-gesture-required',\r\n '--block-new-web-contents',\r\n '--disable-accelerated-2d-canvas',\r\n '--disable-background-networking',\r\n '--disable-background-timer-throttling',\r\n '--disable-backgrounding-occluded-windows',\r\n '--disable-breakpad',\r\n '--disable-checker-imaging',\r\n '--disable-client-side-phishing-detection',\r\n '--disable-component-extensions-with-background-pages',\r\n '--disable-component-update',\r\n '--disable-default-apps',\r\n '--disable-dev-shm-usage',\r\n '--disable-domain-reliability',\r\n '--disable-extensions',\r\n '--disable-features=CalculateNativeWinOcclusion,InterestFeedContentSuggestions,WebOTP',\r\n '--disable-hang-monitor',\r\n '--disable-ipc-flooding-protection',\r\n '--disable-logging',\r\n '--disable-notifications',\r\n '--disable-offer-store-unmasked-wallet-cards',\r\n '--disable-popup-blocking',\r\n '--disable-print-preview',\r\n '--disable-prompt-on-repost',\r\n '--disable-renderer-backgrounding',\r\n '--disable-search-engine-choice-screen',\r\n '--disable-session-crashed-bubble',\r\n '--disable-setuid-sandbox',\r\n '--disable-site-isolation-trials',\r\n '--disable-speech-api',\r\n '--disable-sync',\r\n '--enable-unsafe-webgpu',\r\n '--hide-crash-restore-bubble',\r\n '--hide-scrollbars',\r\n '--metrics-recording-only',\r\n '--mute-audio',\r\n '--no-default-browser-check',\r\n '--no-first-run',\r\n '--no-pings',\r\n '--no-sandbox',\r\n '--no-startup-window',\r\n '--no-zygote',\r\n '--password-store=basic',\r\n '--process-per-tab',\r\n '--use-mock-keychain'\r\n ],\r\n types: ['string[]'],\r\n envLink: 'PUPPETEER_ARGS',\r\n cliName: 'puppeteerArgs',\r\n description: 'Array of Puppeteer arguments',\r\n promptOptions: {\r\n type: 'list',\r\n separator: ';'\r\n }\r\n }\r\n },\r\n highcharts: {\r\n version: {\r\n value: 'latest',\r\n types: ['string'],\r\n envLink: 'HIGHCHARTS_VERSION',\r\n description: 'Highcharts version',\r\n promptOptions: {\r\n type: 'text'\r\n }\r\n },\r\n cdnUrl: {\r\n value: 'https://code.highcharts.com',\r\n types: ['string'],\r\n envLink: 'HIGHCHARTS_CDN_URL',\r\n description: 'CDN URL for Highcharts scripts',\r\n promptOptions: {\r\n type: 'text'\r\n }\r\n },\r\n forceFetch: {\r\n value: false,\r\n types: ['boolean'],\r\n envLink: 'HIGHCHARTS_FORCE_FETCH',\r\n description: 'Flag to refetch scripts after each server rerun',\r\n promptOptions: {\r\n type: 'toggle'\r\n }\r\n },\r\n cachePath: {\r\n value: '.cache',\r\n types: ['string'],\r\n envLink: 'HIGHCHARTS_CACHE_PATH',\r\n description: 'Directory path for cached Highcharts scripts',\r\n promptOptions: {\r\n type: 'text'\r\n }\r\n },\r\n coreScripts: {\r\n value: ['highcharts', 'highcharts-more', 'highcharts-3d'],\r\n types: ['string[]'],\r\n envLink: 'HIGHCHARTS_CORE_SCRIPTS',\r\n description: 'Highcharts core scripts to fetch',\r\n promptOptions: {\r\n type: 'multiselect',\r\n instructions: 'Space: Select specific, A: Select all, Enter: Confirm'\r\n }\r\n },\r\n moduleScripts: {\r\n value: [\r\n 'stock',\r\n 'map',\r\n 'gantt',\r\n 'exporting',\r\n 'parallel-coordinates',\r\n 'accessibility',\r\n // 'annotations-advanced',\r\n 'boost-canvas',\r\n 'boost',\r\n 'data',\r\n 'data-tools',\r\n 'draggable-points',\r\n 'static-scale',\r\n 'broken-axis',\r\n 'heatmap',\r\n 'tilemap',\r\n 'tiledwebmap',\r\n 'timeline',\r\n 'treemap',\r\n 'treegraph',\r\n 'item-series',\r\n 'drilldown',\r\n 'histogram-bellcurve',\r\n 'bullet',\r\n 'funnel',\r\n 'funnel3d',\r\n 'geoheatmap',\r\n 'pyramid3d',\r\n 'networkgraph',\r\n 'overlapping-datalabels',\r\n 'pareto',\r\n 'pattern-fill',\r\n 'pictorial',\r\n 'price-indicator',\r\n 'sankey',\r\n 'arc-diagram',\r\n 'dependency-wheel',\r\n 'series-label',\r\n 'series-on-point',\r\n 'solid-gauge',\r\n 'sonification',\r\n // 'stock-tools',\r\n 'streamgraph',\r\n 'sunburst',\r\n 'variable-pie',\r\n 'variwide',\r\n 'vector',\r\n 'venn',\r\n 'windbarb',\r\n 'wordcloud',\r\n 'xrange',\r\n 'no-data-to-display',\r\n 'drag-panes',\r\n 'debugger',\r\n 'dumbbell',\r\n 'lollipop',\r\n 'cylinder',\r\n 'organization',\r\n 'dotplot',\r\n 'marker-clusters',\r\n 'hollowcandlestick',\r\n 'heikinashi',\r\n 'flowmap',\r\n 'export-data',\r\n 'navigator',\r\n 'textpath'\r\n ],\r\n types: ['string[]'],\r\n envLink: 'HIGHCHARTS_MODULE_SCRIPTS',\r\n description: 'Highcharts module scripts to fetch',\r\n promptOptions: {\r\n type: 'multiselect',\r\n instructions: 'Space: Select specific, A: Select all, Enter: Confirm'\r\n }\r\n },\r\n indicatorScripts: {\r\n value: ['indicators-all'],\r\n types: ['string[]'],\r\n envLink: 'HIGHCHARTS_INDICATOR_SCRIPTS',\r\n description: 'Highcharts indicator scripts to fetch',\r\n promptOptions: {\r\n type: 'multiselect',\r\n instructions: 'Space: Select specific, A: Select all, Enter: Confirm'\r\n }\r\n },\r\n customScripts: {\r\n value: [\r\n 'https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.30.1/moment.min.js',\r\n 'https://cdnjs.cloudflare.com/ajax/libs/moment-timezone/0.5.45/moment-timezone-with-data.min.js'\r\n ],\r\n types: ['string[]'],\r\n envLink: 'HIGHCHARTS_CUSTOM_SCRIPTS',\r\n description: 'Additional custom scripts or dependencies to fetch',\r\n promptOptions: {\r\n type: 'list',\r\n separator: ';'\r\n }\r\n }\r\n },\r\n export: {\r\n infile: {\r\n value: null,\r\n types: ['string', 'null'],\r\n envLink: 'EXPORT_INFILE',\r\n description:\r\n 'Input filename with type, formatted correctly as JSON or SVG',\r\n promptOptions: {\r\n type: 'text'\r\n }\r\n },\r\n instr: {\r\n value: null,\r\n types: ['Object', 'string', 'null'],\r\n envLink: 'EXPORT_INSTR',\r\n description:\r\n 'Overrides the `infile` with JSON, stringified JSON, or SVG input',\r\n promptOptions: {\r\n type: 'text'\r\n }\r\n },\r\n options: {\r\n value: null,\r\n types: ['Object', 'string', 'null'],\r\n envLink: 'EXPORT_OPTIONS',\r\n description: 'Alias for the `instr` option',\r\n promptOptions: {\r\n type: 'text'\r\n }\r\n },\r\n svg: {\r\n value: null,\r\n types: ['string', 'null'],\r\n envLink: 'EXPORT_SVG',\r\n description: 'SVG string representation of the chart to render',\r\n promptOptions: {\r\n type: 'text'\r\n }\r\n },\r\n batch: {\r\n value: null,\r\n types: ['string', 'null'],\r\n envLink: 'EXPORT_BATCH',\r\n description:\r\n 'Batch job string with input/output pairs: \"in=out;in=out;...\"',\r\n promptOptions: {\r\n type: 'text'\r\n }\r\n },\r\n outfile: {\r\n value: null,\r\n types: ['string', 'null'],\r\n envLink: 'EXPORT_OUTFILE',\r\n description:\r\n 'Output filename with type. Can be jpeg, png, pdf, or svg and ignores `type` option',\r\n promptOptions: {\r\n type: 'text'\r\n }\r\n },\r\n type: {\r\n value: 'png',\r\n types: ['string'],\r\n envLink: 'EXPORT_TYPE',\r\n description: 'File export format. Can be jpeg, png, pdf, or svg',\r\n promptOptions: {\r\n type: 'select',\r\n hint: 'Default: png',\r\n choices: ['png', 'jpeg', 'pdf', 'svg']\r\n }\r\n },\r\n constr: {\r\n value: 'chart',\r\n types: ['string'],\r\n envLink: 'EXPORT_CONSTR',\r\n description:\r\n 'Chart constructor. Can be chart, stockChart, mapChart, or ganttChart',\r\n promptOptions: {\r\n type: 'select',\r\n hint: 'Default: chart',\r\n choices: ['chart', 'stockChart', 'mapChart', 'ganttChart']\r\n }\r\n },\r\n b64: {\r\n value: false,\r\n types: ['boolean'],\r\n envLink: 'EXPORT_B64',\r\n description:\r\n 'Whether or not to the chart should be received in Base64 format instead of binary',\r\n promptOptions: {\r\n type: 'toggle'\r\n }\r\n },\r\n noDownload: {\r\n value: false,\r\n types: ['boolean'],\r\n envLink: 'EXPORT_NO_DOWNLOAD',\r\n description:\r\n 'Whether or not to include or exclude attachment headers in the response',\r\n promptOptions: {\r\n type: 'toggle'\r\n }\r\n },\r\n height: {\r\n value: null,\r\n types: ['number', 'null'],\r\n envLink: 'EXPORT_HEIGHT',\r\n description: 'Height of the exported chart, overrides chart settings',\r\n promptOptions: {\r\n type: 'number'\r\n }\r\n },\r\n width: {\r\n value: null,\r\n types: ['number', 'null'],\r\n envLink: 'EXPORT_WIDTH',\r\n description: 'Width of the exported chart, overrides chart settings',\r\n promptOptions: {\r\n type: 'number'\r\n }\r\n },\r\n scale: {\r\n value: null,\r\n types: ['number', 'null'],\r\n envLink: 'EXPORT_SCALE',\r\n description:\r\n 'Scale of the exported chart, overrides chart settings. Ranges from 0.1 to 5.0',\r\n promptOptions: {\r\n type: 'number'\r\n }\r\n },\r\n defaultHeight: {\r\n value: 400,\r\n types: ['number'],\r\n envLink: 'EXPORT_DEFAULT_HEIGHT',\r\n description: 'Default height of the exported chart if not set',\r\n promptOptions: {\r\n type: 'number'\r\n }\r\n },\r\n defaultWidth: {\r\n value: 600,\r\n types: ['number'],\r\n envLink: 'EXPORT_DEFAULT_WIDTH',\r\n description: 'Default width of the exported chart if not set',\r\n promptOptions: {\r\n type: 'number'\r\n }\r\n },\r\n defaultScale: {\r\n value: 1,\r\n types: ['number'],\r\n envLink: 'EXPORT_DEFAULT_SCALE',\r\n description:\r\n 'Default scale of the exported chart if not set. Ranges from 0.1 to 5.0',\r\n promptOptions: {\r\n type: 'number',\r\n min: 0.1,\r\n max: 5\r\n }\r\n },\r\n globalOptions: {\r\n value: null,\r\n types: ['Object', 'string', 'null'],\r\n envLink: 'EXPORT_GLOBAL_OPTIONS',\r\n description:\r\n 'JSON, stringified JSON or filename with global options for Highcharts.setOptions',\r\n promptOptions: {\r\n type: 'text'\r\n }\r\n },\r\n themeOptions: {\r\n value: null,\r\n types: ['Object', 'string', 'null'],\r\n envLink: 'EXPORT_THEME_OPTIONS',\r\n description:\r\n 'JSON, stringified JSON or filename with theme options for Highcharts.setOptions',\r\n promptOptions: {\r\n type: 'text'\r\n }\r\n },\r\n rasterizationTimeout: {\r\n value: 1500,\r\n types: ['number'],\r\n envLink: 'EXPORT_RASTERIZATION_TIMEOUT',\r\n description: 'Milliseconds to wait for webpage rendering',\r\n promptOptions: {\r\n type: 'number'\r\n }\r\n }\r\n },\r\n customLogic: {\r\n allowCodeExecution: {\r\n value: false,\r\n types: ['boolean'],\r\n envLink: 'CUSTOM_LOGIC_ALLOW_CODE_EXECUTION',\r\n description:\r\n 'Allows or disallows execution of arbitrary code during exporting',\r\n promptOptions: {\r\n type: 'toggle'\r\n }\r\n },\r\n allowFileResources: {\r\n value: false,\r\n types: ['boolean'],\r\n envLink: 'CUSTOM_LOGIC_ALLOW_FILE_RESOURCES',\r\n description:\r\n 'Allows or disallows injection of filesystem resources (disabled in server mode)',\r\n promptOptions: {\r\n type: 'toggle'\r\n }\r\n },\r\n customCode: {\r\n value: null,\r\n types: ['string', 'null'],\r\n envLink: 'CUSTOM_LOGIC_CUSTOM_CODE',\r\n description:\r\n 'Custom code to execute before chart initialization. Can be a function, code wrapped in a function, or a .js filename',\r\n promptOptions: {\r\n type: 'text'\r\n }\r\n },\r\n callback: {\r\n value: null,\r\n types: ['string', 'null'],\r\n envLink: 'CUSTOM_LOGIC_CALLBACK',\r\n description:\r\n 'JavaScript code to run during construction. Can be a function or a .js filename',\r\n promptOptions: {\r\n type: 'text'\r\n }\r\n },\r\n resources: {\r\n value: null,\r\n types: ['Object', 'string', 'null'],\r\n envLink: 'CUSTOM_LOGIC_RESOURCES',\r\n description:\r\n 'Additional resources as JSON, stringified JSON, or filename, containing files, js, and css sections',\r\n promptOptions: {\r\n type: 'text'\r\n }\r\n },\r\n loadConfig: {\r\n value: null,\r\n types: ['string', 'null'],\r\n envLink: 'CUSTOM_LOGIC_LOAD_CONFIG',\r\n legacyName: 'fromFile',\r\n description: 'File with a pre-defined configuration to use',\r\n promptOptions: {\r\n type: 'text'\r\n }\r\n },\r\n createConfig: {\r\n value: null,\r\n types: ['string', 'null'],\r\n envLink: 'CUSTOM_LOGIC_CREATE_CONFIG',\r\n description:\r\n 'Prompt-based option setting, saved to a provided config file',\r\n promptOptions: {\r\n type: 'text'\r\n }\r\n }\r\n },\r\n server: {\r\n enable: {\r\n value: false,\r\n types: ['boolean'],\r\n envLink: 'SERVER_ENABLE',\r\n cliName: 'enableServer',\r\n description: 'Starts the server when true',\r\n promptOptions: {\r\n type: 'toggle'\r\n }\r\n },\r\n host: {\r\n value: '0.0.0.0',\r\n types: ['string'],\r\n envLink: 'SERVER_HOST',\r\n description: 'Hostname of the server',\r\n promptOptions: {\r\n type: 'text'\r\n }\r\n },\r\n port: {\r\n value: 7801,\r\n types: ['number'],\r\n envLink: 'SERVER_PORT',\r\n description: 'Port number for the server',\r\n promptOptions: {\r\n type: 'number'\r\n }\r\n },\r\n uploadLimit: {\r\n value: 3,\r\n types: ['number'],\r\n envLink: 'SERVER_UPLOAD_LIMIT',\r\n description: 'Maximum request body size in MB',\r\n promptOptions: {\r\n type: 'number'\r\n }\r\n },\r\n benchmarking: {\r\n value: false,\r\n types: ['boolean'],\r\n envLink: 'SERVER_BENCHMARKING',\r\n cliName: 'serverBenchmarking',\r\n description:\r\n 'Displays or not action durations in milliseconds during server requests',\r\n promptOptions: {\r\n type: 'toggle'\r\n }\r\n },\r\n proxy: {\r\n host: {\r\n value: null,\r\n types: ['string', 'null'],\r\n envLink: 'SERVER_PROXY_HOST',\r\n cliName: 'proxyHost',\r\n description: 'Host of the proxy server, if applicable',\r\n promptOptions: {\r\n type: 'text'\r\n }\r\n },\r\n port: {\r\n value: null,\r\n types: ['number', 'null'],\r\n envLink: 'SERVER_PROXY_PORT',\r\n cliName: 'proxyPort',\r\n description: 'Port of the proxy server, if applicable',\r\n promptOptions: {\r\n type: 'number'\r\n }\r\n },\r\n timeout: {\r\n value: 5000,\r\n types: ['number'],\r\n envLink: 'SERVER_PROXY_TIMEOUT',\r\n cliName: 'proxyTimeout',\r\n description:\r\n 'Timeout in milliseconds for the proxy server, if applicable',\r\n promptOptions: {\r\n type: 'number'\r\n }\r\n }\r\n },\r\n rateLimiting: {\r\n enable: {\r\n value: false,\r\n types: ['boolean'],\r\n envLink: 'SERVER_RATE_LIMITING_ENABLE',\r\n cliName: 'enableRateLimiting',\r\n description: 'Enables or disables rate limiting on the server',\r\n promptOptions: {\r\n type: 'toggle'\r\n }\r\n },\r\n maxRequests: {\r\n value: 10,\r\n types: ['number'],\r\n envLink: 'SERVER_RATE_LIMITING_MAX_REQUESTS',\r\n legacyName: 'rateLimit',\r\n description: 'Maximum number of requests allowed per minute',\r\n promptOptions: {\r\n type: 'number'\r\n }\r\n },\r\n window: {\r\n value: 1,\r\n types: ['number'],\r\n envLink: 'SERVER_RATE_LIMITING_WINDOW',\r\n description: 'Time window in minutes for rate limiting',\r\n promptOptions: {\r\n type: 'number'\r\n }\r\n },\r\n delay: {\r\n value: 0,\r\n types: ['number'],\r\n envLink: 'SERVER_RATE_LIMITING_DELAY',\r\n description:\r\n 'Delay duration between successive requests before reaching the limit',\r\n promptOptions: {\r\n type: 'number'\r\n }\r\n },\r\n trustProxy: {\r\n value: false,\r\n types: ['boolean'],\r\n envLink: 'SERVER_RATE_LIMITING_TRUST_PROXY',\r\n description: 'Set to true if the server is behind a load balancer',\r\n promptOptions: {\r\n type: 'toggle'\r\n }\r\n },\r\n skipKey: {\r\n value: null,\r\n types: ['string', 'null'],\r\n envLink: 'SERVER_RATE_LIMITING_SKIP_KEY',\r\n description: 'Key to bypass the rate limiter, used with `skipToken`',\r\n promptOptions: {\r\n type: 'text'\r\n }\r\n },\r\n skipToken: {\r\n value: null,\r\n types: ['string', 'null'],\r\n envLink: 'SERVER_RATE_LIMITING_SKIP_TOKEN',\r\n description: 'Token to bypass the rate limiter, used with `skipKey`',\r\n promptOptions: {\r\n type: 'text'\r\n }\r\n }\r\n },\r\n ssl: {\r\n enable: {\r\n value: false,\r\n types: ['boolean'],\r\n envLink: 'SERVER_SSL_ENABLE',\r\n cliName: 'enableSsl',\r\n description: 'Enables or disables SSL protocol',\r\n promptOptions: {\r\n type: 'toggle'\r\n }\r\n },\r\n force: {\r\n value: false,\r\n types: ['boolean'],\r\n envLink: 'SERVER_SSL_FORCE',\r\n cliName: 'sslForce',\r\n legacyName: 'sslOnly',\r\n description: 'Forces the server to use HTTPS only when true',\r\n promptOptions: {\r\n type: 'toggle'\r\n }\r\n },\r\n port: {\r\n value: 443,\r\n types: ['number'],\r\n envLink: 'SERVER_SSL_PORT',\r\n cliName: 'sslPort',\r\n description: 'Port for the SSL server',\r\n promptOptions: {\r\n type: 'number'\r\n }\r\n },\r\n certPath: {\r\n value: null,\r\n types: ['string', 'null'],\r\n envLink: 'SERVER_SSL_CERT_PATH',\r\n cliName: 'sslCertPath',\r\n legacyName: 'sslPath',\r\n description: 'Path to the SSL certificate/key file',\r\n promptOptions: {\r\n type: 'text'\r\n }\r\n }\r\n }\r\n },\r\n pool: {\r\n minWorkers: {\r\n value: 4,\r\n types: ['number'],\r\n envLink: 'POOL_MIN_WORKERS',\r\n description: 'Minimum and initial number of pool workers to spawn',\r\n promptOptions: {\r\n type: 'number'\r\n }\r\n },\r\n maxWorkers: {\r\n value: 8,\r\n types: ['number'],\r\n envLink: 'POOL_MAX_WORKERS',\r\n legacyName: 'workers',\r\n description: 'Maximum number of pool workers to spawn',\r\n promptOptions: {\r\n type: 'number'\r\n }\r\n },\r\n workLimit: {\r\n value: 40,\r\n types: ['number'],\r\n envLink: 'POOL_WORK_LIMIT',\r\n description: 'Number of tasks a worker can handle before restarting',\r\n promptOptions: {\r\n type: 'number'\r\n }\r\n },\r\n acquireTimeout: {\r\n value: 5000,\r\n types: ['number'],\r\n envLink: 'POOL_ACQUIRE_TIMEOUT',\r\n description: 'Timeout in milliseconds for acquiring a resource',\r\n promptOptions: {\r\n type: 'number'\r\n }\r\n },\r\n createTimeout: {\r\n value: 5000,\r\n types: ['number'],\r\n envLink: 'POOL_CREATE_TIMEOUT',\r\n description: 'Timeout in milliseconds for creating a resource',\r\n promptOptions: {\r\n type: 'number'\r\n }\r\n },\r\n destroyTimeout: {\r\n value: 5000,\r\n types: ['number'],\r\n envLink: 'POOL_DESTROY_TIMEOUT',\r\n description: 'Timeout in milliseconds for destroying a resource',\r\n promptOptions: {\r\n type: 'number'\r\n }\r\n },\r\n idleTimeout: {\r\n value: 30000,\r\n types: ['number'],\r\n envLink: 'POOL_IDLE_TIMEOUT',\r\n description: 'Timeout in milliseconds for destroying idle resources',\r\n promptOptions: {\r\n type: 'number'\r\n }\r\n },\r\n createRetryInterval: {\r\n value: 200,\r\n types: ['number'],\r\n envLink: 'POOL_CREATE_RETRY_INTERVAL',\r\n description:\r\n 'Interval in milliseconds before retrying resource creation on failure',\r\n promptOptions: {\r\n type: 'number'\r\n }\r\n },\r\n reaperInterval: {\r\n value: 1000,\r\n types: ['number'],\r\n envLink: 'POOL_REAPER_INTERVAL',\r\n description:\r\n 'Interval in milliseconds to check and destroy idle resources',\r\n promptOptions: {\r\n type: 'number'\r\n }\r\n },\r\n benchmarking: {\r\n value: false,\r\n types: ['boolean'],\r\n envLink: 'POOL_BENCHMARKING',\r\n cliName: 'poolBenchmarking',\r\n description: 'Shows statistics for the pool of resources',\r\n promptOptions: {\r\n type: 'toggle'\r\n }\r\n }\r\n },\r\n logging: {\r\n level: {\r\n value: 4,\r\n types: ['number'],\r\n envLink: 'LOGGING_LEVEL',\r\n cliName: 'logLevel',\r\n description: 'Logging verbosity level',\r\n promptOptions: {\r\n type: 'number',\r\n round: 0,\r\n min: 0,\r\n max: 5\r\n }\r\n },\r\n file: {\r\n value: 'highcharts-export-server.log',\r\n types: ['string'],\r\n envLink: 'LOGGING_FILE',\r\n cliName: 'logFile',\r\n description:\r\n 'Log file name. Requires `logToFile` and `logDest` to be set',\r\n promptOptions: {\r\n type: 'text'\r\n }\r\n },\r\n dest: {\r\n value: 'log',\r\n types: ['string'],\r\n envLink: 'LOGGING_DEST',\r\n cliName: 'logDest',\r\n description: 'Path to store log files. Requires `logToFile` to be set',\r\n promptOptions: {\r\n type: 'text'\r\n }\r\n },\r\n toConsole: {\r\n value: true,\r\n types: ['boolean'],\r\n envLink: 'LOGGING_TO_CONSOLE',\r\n cliName: 'logToConsole',\r\n description: 'Enables or disables console logging',\r\n promptOptions: {\r\n type: 'toggle'\r\n }\r\n },\r\n toFile: {\r\n value: true,\r\n types: ['boolean'],\r\n envLink: 'LOGGING_TO_FILE',\r\n cliName: 'logToFile',\r\n description: 'Enables or disables logging to a file',\r\n promptOptions: {\r\n type: 'toggle'\r\n }\r\n }\r\n },\r\n ui: {\r\n enable: {\r\n value: false,\r\n types: ['boolean'],\r\n envLink: 'UI_ENABLE',\r\n cliName: 'enableUi',\r\n description: 'Enables or disables the UI for the export server',\r\n promptOptions: {\r\n type: 'toggle'\r\n }\r\n },\r\n route: {\r\n value: '/',\r\n types: ['string'],\r\n envLink: 'UI_ROUTE',\r\n cliName: 'uiRoute',\r\n description: 'The endpoint route for the UI',\r\n promptOptions: {\r\n type: 'text'\r\n }\r\n }\r\n },\r\n other: {\r\n nodeEnv: {\r\n value: 'production',\r\n types: ['string'],\r\n envLink: 'OTHER_NODE_ENV',\r\n description: 'The Node.js environment type',\r\n promptOptions: {\r\n type: 'text'\r\n }\r\n },\r\n listenToProcessExits: {\r\n value: true,\r\n types: ['boolean'],\r\n envLink: 'OTHER_LISTEN_TO_PROCESS_EXITS',\r\n description: 'Whether or not to attach process.exit handlers',\r\n promptOptions: {\r\n type: 'toggle'\r\n }\r\n },\r\n noLogo: {\r\n value: false,\r\n types: ['boolean'],\r\n envLink: 'OTHER_NO_LOGO',\r\n description: 'Display or skip printing the logo on startup',\r\n promptOptions: {\r\n type: 'toggle'\r\n }\r\n },\r\n hardResetPage: {\r\n value: false,\r\n types: ['boolean'],\r\n envLink: 'OTHER_HARD_RESET_PAGE',\r\n description: 'Whether or not to reset the page content entirely',\r\n promptOptions: {\r\n type: 'toggle'\r\n }\r\n },\r\n browserShellMode: {\r\n value: true,\r\n types: ['boolean'],\r\n envLink: 'OTHER_BROWSER_SHELL_MODE',\r\n description: 'Whether or not to set the browser to run in shell mode',\r\n promptOptions: {\r\n type: 'toggle'\r\n }\r\n },\r\n validation: {\r\n value: true,\r\n types: ['boolean'],\r\n envLink: 'OTHER_VALIDATION',\r\n description: 'Whether or not to enable validation of options types',\r\n promptOptions: {\r\n type: 'toggle'\r\n }\r\n }\r\n },\r\n debug: {\r\n enable: {\r\n value: false,\r\n types: ['boolean'],\r\n envLink: 'DEBUG_ENABLE',\r\n cliName: 'enableDebug',\r\n description: 'Enables or disables debug mode for the underlying browser',\r\n promptOptions: {\r\n type: 'toggle'\r\n }\r\n },\r\n headless: {\r\n value: false,\r\n types: ['boolean'],\r\n envLink: 'DEBUG_HEADLESS',\r\n description:\r\n 'Whether or not to set the browser to run in headless mode during debugging',\r\n promptOptions: {\r\n type: 'toggle'\r\n }\r\n },\r\n devtools: {\r\n value: false,\r\n types: ['boolean'],\r\n envLink: 'DEBUG_DEVTOOLS',\r\n description: 'Enables or disables DevTools in headful mode',\r\n promptOptions: {\r\n type: 'toggle'\r\n }\r\n },\r\n listenToConsole: {\r\n value: false,\r\n types: ['boolean'],\r\n envLink: 'DEBUG_LISTEN_TO_CONSOLE',\r\n description:\r\n 'Enables or disables listening to console messages from the browser',\r\n promptOptions: {\r\n type: 'toggle'\r\n }\r\n },\r\n dumpio: {\r\n value: false,\r\n types: ['boolean'],\r\n envLink: 'DEBUG_DUMPIO',\r\n description:\r\n 'Redirects or not browser stdout and stderr to process.stdout and process.stderr',\r\n promptOptions: {\r\n type: 'toggle'\r\n }\r\n },\r\n slowMo: {\r\n value: 0,\r\n types: ['number'],\r\n envLink: 'DEBUG_SLOW_MO',\r\n description: 'Delays Puppeteer operations by the specified milliseconds',\r\n promptOptions: {\r\n type: 'number'\r\n }\r\n },\r\n debuggingPort: {\r\n value: 9222,\r\n types: ['number'],\r\n envLink: 'DEBUG_DEBUGGING_PORT',\r\n description: 'Port used for debugging',\r\n promptOptions: {\r\n type: 'number'\r\n }\r\n }\r\n }\r\n};\r\n\r\n// Properties nesting level of all options\r\nexport const nestedProps = _createNestedProps(defaultConfig);\r\n\r\n// Properties names that should not be recursively merged\r\nexport const absoluteProps = _createAbsoluteProps(defaultConfig);\r\n\r\n/**\r\n * Recursively generates a mapping of nested argument chains from a nested\r\n * config object. This function traverses a nested object and creates a mapping\r\n * where each key is an argument name (either from `cliName`, `legacyName`,\r\n * or the original key) and each value is a string representing the chain\r\n * of nested properties leading to that argument.\r\n *\r\n * @function _createNestedProps\r\n *\r\n * @param {Object} config - The configuration object.\r\n * @param {Object} [nestedProps={}] - The accumulator object for storing\r\n * the resulting arguments chains. The default value is an empty object.\r\n * @param {string} [propChain=''] - The current chain of nested properties,\r\n * used internally during recursion. The default value is an empty string.\r\n *\r\n * @returns {Object} An object mapping argument names to their corresponding\r\n * nested property chains.\r\n */\r\nfunction _createNestedProps(config, nestedProps = {}, propChain = '') {\r\n Object.keys(config).forEach((key) => {\r\n // Get the specific section\r\n const entry = config[key];\r\n\r\n // Check if there is still more depth to traverse\r\n if (typeof entry.value === 'undefined') {\r\n // Recurse into deeper levels of nested arguments\r\n _createNestedProps(entry, nestedProps, `${propChain}.${key}`);\r\n } else {\r\n // Create the chain of nested arguments\r\n nestedProps[entry.cliName || key] = `${propChain}.${key}`.substring(1);\r\n\r\n // Support for the legacy, PhantomJS properties names\r\n if (entry.legacyName !== undefined) {\r\n nestedProps[entry.legacyName] = `${propChain}.${key}`.substring(1);\r\n }\r\n }\r\n });\r\n\r\n // Return the object with nested argument chains\r\n return nestedProps;\r\n}\r\n\r\n/**\r\n * Recursively gathers the names of properties from a configuration object that\r\n * can be treated as absolute properties. These properties have values that\r\n * are objects and do not contain further nested depth when merging an object\r\n * containing these options.\r\n *\r\n * @function _createAbsoluteProps\r\n *\r\n * @param {Object} config - The configuration object.\r\n * @param {Array.} [absoluteProps=[]] - An array to collect the names\r\n * of absolute properties. The default value is an empty array.\r\n *\r\n * @returns {Array.} An array containing the names of absolute\r\n * properties.\r\n */\r\nfunction _createAbsoluteProps(config, absoluteProps = []) {\r\n Object.keys(config).forEach((key) => {\r\n // Get the specific section\r\n const entry = config[key];\r\n\r\n // Check if there is still more depth to traverse\r\n if (typeof entry.types === 'undefined') {\r\n // Recurse into deeper levels\r\n _createAbsoluteProps(entry, absoluteProps);\r\n } else {\r\n // If the option can be an object, save its type in the array\r\n if (entry.types.includes('Object')) {\r\n absoluteProps.push(key);\r\n }\r\n }\r\n });\r\n\r\n // Return the array with the names of absolute properties\r\n return absoluteProps;\r\n}\r\n\r\nexport default {\r\n defaultConfig,\r\n nestedProps,\r\n absoluteProps\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * @overview This file handles parsing and validating options from multiple\r\n * sources (the config file, custom JSON, environment variables, CLI arguments,\r\n * and request payload) using the 'zod' library.\r\n *\r\n * Environment variables are parsed and validated only once at application\r\n * startup, and the validated results are exported as `envs` for use throughout\r\n * the application.\r\n *\r\n * Options from other sources, however, are parsed and validated on demand,\r\n * each time an export is attempted.\r\n */\r\n\r\nimport dotenv from 'dotenv';\r\nimport { z } from 'zod';\r\n\r\nimport { defaultConfig } from './schemas/config.js';\r\n\r\n// Load the .env into environment variables\r\ndotenv.config();\r\n\r\n// Get scripts names of each category from the default config\r\nconst { coreScripts, moduleScripts, indicatorScripts } =\r\n defaultConfig.highcharts;\r\n\r\n// Sets the custom error map globally\r\nz.setErrorMap(_customErrorMap);\r\n\r\n/**\r\n * Object containing custom general validators and parsers to avoid repetition\r\n * in schema objects. All validators apply to values from various sources,\r\n * including the default config file, a custom JSON file loaded with the option\r\n * called `loadConfig`, the .env file, CLI arguments, and the request payload.\r\n * The `strictCheck` flag enables stricter validation and parsing rules. This\r\n * flag is set to false for values that come from the .env file or CLI arguments\r\n * because they are provided as strings and need to be parsed accordingly first.\r\n */\r\nconst v = {\r\n /**\r\n * The `boolean` validator that returns a Zod schema with an optional stricter\r\n * check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures that:\r\n *\r\n * - When `strictCheck` is true, the schema will accept values are true\r\n * and false and the schema will validate against the default boolean\r\n * validator.\r\n *\r\n * - When `strictCheck` is false, the schema will accept values are true,\r\n * false, null, 'true', '1', 'false', '0', 'undefined', 'null', and ''.\r\n * The strings 'undefined', 'null', and '' will be transformed to null,\r\n * the string 'true' will be transformed to the boolean value true,\r\n * and 'false' will be transformed to the boolean value false.\r\n *\r\n * @function boolean\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating boolean values.\r\n */\r\n boolean(strictCheck) {\r\n return strictCheck\r\n ? z.boolean()\r\n : z\r\n .union([\r\n z\r\n .enum(['true', '1', 'false', '0', 'undefined', 'null', ''])\r\n .transform((value) =>\r\n !['undefined', 'null', ''].includes(value)\r\n ? value === 'true' || value === '1'\r\n : null\r\n ),\r\n z.boolean()\r\n ])\r\n .nullable();\r\n },\r\n\r\n /**\r\n * The `string` validator that returns a Zod schema with an optional stricter\r\n * check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures that:\r\n *\r\n * - When `strictCheck` is true, the schema will accept trimmed strings except\r\n * the forbidden values: 'false', 'undefined', 'null', and ''.\r\n *\r\n * - When `strictCheck` is false, the schema will accept trimmed strings\r\n * and null. The forbidden values: 'false', 'undefined', 'null', and '' will\r\n * be transformed to null.\r\n *\r\n * @function string\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating string values.\r\n */\r\n string(strictCheck) {\r\n return strictCheck\r\n ? z\r\n .string()\r\n .trim()\r\n .refine(\r\n (value) => !['false', 'undefined', 'null', ''].includes(value),\r\n {\r\n params: {\r\n errorMessage: 'The string contains a forbidden value'\r\n }\r\n }\r\n )\r\n : z\r\n .string()\r\n .trim()\r\n .transform((value) =>\r\n !['false', 'undefined', 'null', ''].includes(value) ? value : null\r\n )\r\n .nullable();\r\n },\r\n\r\n /**\r\n * The `enum` validator that returns a Zod schema with an optional stricter\r\n * check based on the `strictCheck` parameter.\r\n *\r\n * The schema will validate against the provided `values` array.\r\n *\r\n * The validation schema ensures that:\r\n *\r\n * - When `strictCheck` is true, the schema will validate against the `values`\r\n * array with the default enum validator.\r\n *\r\n * - When `strictCheck` is false, the schema will accept also null,\r\n * 'undefined', 'null', and '', which will be transformed to null.\r\n *\r\n * @function enum\r\n *\r\n * @param {Array.} values - An array of valid string values\r\n * for the enum.\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating enum values.\r\n */\r\n enum(values, strictCheck) {\r\n return strictCheck\r\n ? z.enum([...values])\r\n : z\r\n .enum([...values, 'undefined', 'null', ''])\r\n .transform((value) =>\r\n !['undefined', 'null', ''].includes(value) ? value : null\r\n )\r\n .nullable();\r\n },\r\n\r\n /**\r\n * The `stringArray` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures that:\r\n *\r\n * - When `strictCheck` is true, the schema will accept an array of trimmed\r\n * string values filtered by the logic provided through the `filterCallback`.\r\n *\r\n * - When `strictCheck` is false, the schema will accept null and trimmed\r\n * string values which will be splitted into an array of strings and filtered\r\n * from the '[' and ']' characters and by the logic provided through\r\n * the `filterCallback`. If the array is empty, it will be transformed\r\n * to null.\r\n *\r\n * @function stringArray\r\n *\r\n * @param {function} filterCallback - The filter callback.\r\n * @param {string} separator - The separator for spliting a string.\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating array of string\r\n * values.\r\n */\r\n stringArray(filterCallback, separator, strictCheck) {\r\n const arraySchema = z.string().trim().array();\r\n const stringSchema = z\r\n .string()\r\n .trim()\r\n .transform((value) => {\r\n if (value.startsWith('[')) {\r\n value = value.slice(1);\r\n }\r\n if (value.endsWith(']')) {\r\n value = value.slice(0, -1);\r\n }\r\n return value.split(separator);\r\n });\r\n\r\n const transformCallback = (value) =>\r\n value.map((value) => value.trim()).filter(filterCallback);\r\n\r\n return strictCheck\r\n ? arraySchema.transform(transformCallback)\r\n : z\r\n .union([stringSchema, arraySchema])\r\n .transform(transformCallback)\r\n .transform((value) => (value.length ? value : null))\r\n .nullable();\r\n },\r\n\r\n /**\r\n * The `positiveNum` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures that:\r\n *\r\n * - When `strictCheck` is true, the schema will accept positive number values\r\n * and validate against the default positive number validator.\r\n *\r\n * - When `strictCheck` is false, the schema will accept positive number\r\n * values, null, and trimmed string values that can either be 'undefined',\r\n * 'null', '', or represent a positive number. It will transform the string\r\n * to a positive number, or to null if it is 'undefined', 'null', or ''.\r\n *\r\n * @function positiveNum\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating positive number\r\n * values.\r\n */\r\n positiveNum(strictCheck) {\r\n return strictCheck\r\n ? z.number().positive()\r\n : z\r\n .union([\r\n z\r\n .string()\r\n .trim()\r\n .refine(\r\n (value) =>\r\n (!isNaN(Number(value)) && Number(value) > 0) ||\r\n ['undefined', 'null', ''].includes(value),\r\n {\r\n params: {\r\n errorMessage: 'The value must be numeric and positive'\r\n }\r\n }\r\n )\r\n .transform((value) =>\r\n !['undefined', 'null', ''].includes(value)\r\n ? Number(value)\r\n : null\r\n ),\r\n z.number().positive()\r\n ])\r\n .nullable();\r\n },\r\n\r\n /**\r\n * The `nonNegativeNum` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures that:\r\n *\r\n * - When `strictCheck` is true, the schema will accept non-negative number\r\n * values and validate against the default non-negative number validator.\r\n *\r\n * - When `strictCheck` is false, the schema will accept non-negative number\r\n * values, null, and trimmed string values that can either be 'undefined',\r\n * 'null', '', or represent a non-negative number. It will transform\r\n * the string to a non-negative number, or to null if it is 'undefined',\r\n * 'null', or ''.\r\n *\r\n * @function nonNegativeNum\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating non-negative\r\n * number values.\r\n */\r\n nonNegativeNum(strictCheck) {\r\n return strictCheck\r\n ? z.number().nonnegative()\r\n : z\r\n .union([\r\n z\r\n .string()\r\n .trim()\r\n .refine(\r\n (value) =>\r\n (!isNaN(Number(value)) && Number(value) >= 0) ||\r\n ['undefined', 'null', ''].includes(value),\r\n {\r\n params: {\r\n errorMessage: 'The value must be numeric and non-negative'\r\n }\r\n }\r\n )\r\n .transform((value) =>\r\n !['undefined', 'null', ''].includes(value)\r\n ? Number(value)\r\n : null\r\n ),\r\n z.number().nonnegative()\r\n ])\r\n .nullable();\r\n },\r\n\r\n /**\r\n * The `startsWith` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The schema will validate against the provided `prefixes` array to check\r\n * whether a string value starts with any of the values provided\r\n * in the `prefixes` array.\r\n *\r\n * The validation schema ensures that:\r\n *\r\n * - When `strictCheck` is true, the schema will accept trimmed string values\r\n * that start with values from the prefixes array.\r\n *\r\n * - When `strictCheck` is false, the schema will accept trimmed string values\r\n * that start with values from the prefixes array, null, 'undefined', 'null',\r\n * and '' where the schema will transform them to null.\r\n *\r\n * @function startsWith\r\n *\r\n * @param {Array.} prefixes - An array of prefixes to validate\r\n * the string against.\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating strings that\r\n * starts with values.\r\n */\r\n startsWith(prefixes, strictCheck) {\r\n return strictCheck\r\n ? z\r\n .string()\r\n .trim()\r\n .refine(\r\n (value) => prefixes.some((prefix) => value.startsWith(prefix)),\r\n {\r\n params: {\r\n errorMessage: `The value must be a string that starts with ${prefixes.join(', ')}`\r\n }\r\n }\r\n )\r\n : z\r\n .string()\r\n .trim()\r\n .refine(\r\n (value) =>\r\n prefixes.some((prefix) => value.startsWith(prefix)) ||\r\n ['undefined', 'null', ''].includes(value),\r\n {\r\n params: {\r\n errorMessage: `The value must be a string that starts with ${prefixes.join(', ')}`\r\n }\r\n }\r\n )\r\n .transform((value) =>\r\n !['undefined', 'null', ''].includes(value) ? value : null\r\n )\r\n .nullable();\r\n },\r\n\r\n /**\r\n * The `chartConfig` validator that returns a Zod schema.\r\n *\r\n * The validation schema ensures that the schema will accept object values\r\n * or trimmed string values that contain '\r\n (value.startsWith('{') && value.endsWith('}')) ||\r\n ['undefined', 'null', ''].includes(value),\r\n {\r\n params: {\r\n errorMessage:\r\n \"The value must be a string that starts with '{' and ends with '}'\"\r\n }\r\n }\r\n )\r\n .transform((value) =>\r\n !['undefined', 'null', ''].includes(value) ? value : null\r\n ),\r\n z.object({}).passthrough()\r\n ])\r\n .nullable();\r\n },\r\n\r\n /**\r\n * The `additionalOptions` validator that returns a Zod schema.\r\n *\r\n * The validation schema ensures that the schema will accept object values\r\n * or trimmed string values that end with '.json' and are at least one\r\n * character long excluding the extension, start with the '{' and end\r\n * with the '}', and null. The 'undefined', 'null', and '' values will\r\n * be transformed to null.\r\n *\r\n * @function additionalOptions\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating additional chart\r\n * options value.\r\n */\r\n additionalOptions() {\r\n return z\r\n .union([\r\n z\r\n .string()\r\n .trim()\r\n .refine(\r\n (value) =>\r\n (value.length >= 6 && value.endsWith('.json')) ||\r\n (value.startsWith('{') && value.endsWith('}')) ||\r\n ['undefined', 'null', ''].includes(value),\r\n {\r\n params: {\r\n errorMessage:\r\n \"The value must be a string that ends with '.json' or starts with '{' and ends with '}'\"\r\n }\r\n }\r\n )\r\n .transform((value) =>\r\n !['undefined', 'null', ''].includes(value) ? value : null\r\n ),\r\n z.object({}).passthrough()\r\n ])\r\n .nullable();\r\n }\r\n};\r\n\r\n/**\r\n * Object containing custom config validators and parsers to avoid repetition\r\n * in schema objects. All validators apply to values from various sources,\r\n * including the default config file, a custom JSON file loaded with the option\r\n * called `loadConfig`, the .env file, CLI arguments, and the request payload.\r\n * The `strictCheck` flag enables stricter validation and parsing rules. This\r\n * flag is set to false for values that come from the .env file or CLI arguments\r\n * because they are provided as strings and need to be parsed accordingly first.\r\n */\r\nexport const validators = {\r\n /**\r\n * The `args` validator that returns a Zod schema with an optional stricter\r\n * check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `stringArray` validator.\r\n *\r\n * @function args\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `args`\r\n * option.\r\n */\r\n args(strictCheck) {\r\n return v.stringArray(\r\n (value) => !['false', 'undefined', 'null', ''].includes(value),\r\n ';',\r\n strictCheck\r\n );\r\n },\r\n\r\n /**\r\n * The `version` validator that returns a Zod schema with an optional stricter\r\n * check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures that:\r\n *\r\n * - When `strictCheck` is true, the schema will accept trimmed string values\r\n * that are a RegExp-based that allows to be 'latest', or in the format XX,\r\n * XX.YY, or XX.YY.ZZ, where XX, YY, and ZZ are numeric for the Highcharts\r\n * version option.\r\n *\r\n * - When `strictCheck` is false, the schema will accept also null,\r\n * 'undefined', 'null', or '' and in all cases the schema will transform them\r\n * to null.\r\n *\r\n * @function version\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `version`\r\n * option.\r\n */\r\n version(strictCheck) {\r\n return strictCheck\r\n ? z\r\n .string()\r\n .trim()\r\n .refine((value) => /^(latest|\\d{1,2}(\\.\\d{1,2}){0,2})$/.test(value), {\r\n params: {\r\n errorMessage:\r\n \"The value must be 'latest', a major version, or in the form XX.YY.ZZ\"\r\n }\r\n })\r\n : z\r\n .string()\r\n .trim()\r\n .refine(\r\n (value) =>\r\n /^(latest|\\d{1,2}(\\.\\d{1,2}){0,2})$/.test(value) ||\r\n ['undefined', 'null', ''].includes(value),\r\n {\r\n params: {\r\n errorMessage:\r\n \"The value must be 'latest', a major version, or in the form XX.YY.ZZ\"\r\n }\r\n }\r\n )\r\n .transform((value) =>\r\n !['undefined', 'null', ''].includes(value) ? value : null\r\n )\r\n .nullable();\r\n },\r\n\r\n /**\r\n * The `cdnUrl` validator that returns a Zod schema with an optional stricter\r\n * check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `startsWith` validator.\r\n *\r\n * @function cdnUrl\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `cdnUrl`\r\n * option.\r\n */\r\n cdnUrl(strictCheck) {\r\n return v.startsWith(['http://', 'https://'], strictCheck);\r\n },\r\n\r\n /**\r\n * The `forceFetch` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `boolean` validator.\r\n *\r\n * @function forceFetch\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `forceFetch`\r\n * option.\r\n */\r\n forceFetch(strictCheck) {\r\n return v.boolean(strictCheck);\r\n },\r\n\r\n /**\r\n * The `cachePath` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `string` validator.\r\n *\r\n * @function cachePath\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `cachePath`\r\n * option.\r\n */\r\n cachePath(strictCheck) {\r\n return v.string(strictCheck);\r\n },\r\n\r\n /**\r\n * The `adminToken` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `string` validator.\r\n *\r\n * @function adminToken\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `adminToken`\r\n * option.\r\n */\r\n adminToken(strictCheck) {\r\n return v.string(strictCheck);\r\n },\r\n\r\n /**\r\n * The `coreScripts` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `stringArray` validator.\r\n *\r\n * @function coreScripts\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `coreScripts`\r\n * option.\r\n */\r\n coreScripts(strictCheck) {\r\n return v.stringArray(\r\n (value) => coreScripts.value.includes(value),\r\n ',',\r\n strictCheck\r\n );\r\n },\r\n\r\n /**\r\n * The `moduleScripts` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `stringArray` validator.\r\n *\r\n * @function moduleScripts\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating\r\n * the `moduleScripts` option.\r\n */\r\n moduleScripts(strictCheck) {\r\n return v.stringArray(\r\n (value) => moduleScripts.value.includes(value),\r\n ',',\r\n strictCheck\r\n );\r\n },\r\n\r\n /**\r\n * The `indicatorScripts` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `stringArray` validator.\r\n *\r\n * @function indicatorScripts\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating\r\n * the `indicatorScripts` option.\r\n */\r\n indicatorScripts(strictCheck) {\r\n return v.stringArray(\r\n (value) => indicatorScripts.value.includes(value),\r\n ',',\r\n strictCheck\r\n );\r\n },\r\n\r\n /**\r\n * The `customScripts` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `stringArray` validator.\r\n *\r\n * @function customScripts\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating\r\n * the `customScripts` option.\r\n */\r\n customScripts(strictCheck) {\r\n return v.stringArray(\r\n (value) => value.startsWith('https://') || value.startsWith('http://'),\r\n ',',\r\n strictCheck\r\n );\r\n },\r\n\r\n /**\r\n * The `infile` validator that returns a Zod schema with an optional stricter\r\n * check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures that:\r\n *\r\n * - When `strictCheck` is true, the schema will accept trimmed string values\r\n * that end with '.json' or '.svg', are at least one character long excluding\r\n * the extension, or null.\r\n *\r\n * - When `strictCheck` is false, the schema will accept trimmed string values\r\n * that end with '.json' or '.svg', are at least one character long excluding\r\n * the extension and will be null if the provided value is null, 'undefined',\r\n * 'null', or ''.\r\n *\r\n * @function infile\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `infile`\r\n * option.\r\n */\r\n infile(strictCheck) {\r\n return strictCheck\r\n ? z\r\n .string()\r\n .trim()\r\n .refine(\r\n (value) =>\r\n (value.length >= 6 && value.endsWith('.json')) ||\r\n (value.length >= 5 && value.endsWith('.svg')),\r\n {\r\n params: {\r\n errorMessage:\r\n 'The value must be a string that ends with .json or .svg'\r\n }\r\n }\r\n )\r\n .nullable()\r\n : z\r\n .string()\r\n .trim()\r\n .refine(\r\n (value) =>\r\n (value.length >= 6 && value.endsWith('.json')) ||\r\n (value.length >= 5 && value.endsWith('.svg')) ||\r\n ['undefined', 'null', ''].includes(value),\r\n {\r\n params: {\r\n errorMessage:\r\n 'The value must be a string that ends with .json or .svg'\r\n }\r\n }\r\n )\r\n .transform((value) =>\r\n !['undefined', 'null', ''].includes(value) ? value : null\r\n )\r\n .nullable();\r\n },\r\n\r\n /**\r\n * The `instr` validator that returns a Zod schema.\r\n *\r\n * The validation schema ensures the same work as the `options` validator.\r\n *\r\n * @function instr\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `instr`\r\n * option.\r\n */\r\n instr() {\r\n return v.chartConfig();\r\n },\r\n\r\n /**\r\n * The `options` validator that returns a Zod schema.\r\n *\r\n * The validation schema ensures the same work as the `options` validator.\r\n *\r\n * @function options\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `options`\r\n * option.\r\n */\r\n options() {\r\n return v.chartConfig();\r\n },\r\n\r\n /**\r\n * The `svg` validator that returns a Zod schema.\r\n *\r\n * The validation schema ensures that the schema will accept object values\r\n * or trimmed string values that contain '\r\n value.indexOf('= 0 ||\r\n value.indexOf('= 0 ||\r\n ['false', 'undefined', 'null', ''].includes(value),\r\n {\r\n params: {\r\n errorMessage:\r\n \"The value must be a string that contains '\r\n !['false', 'undefined', 'null', ''].includes(value) ? value : null\r\n )\r\n .nullable();\r\n },\r\n\r\n /**\r\n * The `outfile` validator that returns a Zod schema with an optional stricter\r\n * check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures that:\r\n *\r\n * - When `strictCheck` is true, the schema will accept trimmed string values\r\n * that end with '.jpeg', '.jpg', '.png', '.pdf', or '.svg', are at least one\r\n * character long excluding the extension, or null.\r\n *\r\n * - When `strictCheck` is false, the schema will accept trimmed string values\r\n * that end with '.jpeg', '.jpg', '.png', '.pdf', or '.svg', are at least one\r\n * character long excluding the extension and will be null if the provided\r\n * value is null, 'undefined', 'null', or ''.\r\n *\r\n * @function outfile\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `outfile`\r\n * option.\r\n */\r\n outfile(strictCheck) {\r\n return strictCheck\r\n ? z\r\n .string()\r\n .trim()\r\n .refine(\r\n (value) =>\r\n (value.length >= 6 && value.endsWith('.jpeg')) ||\r\n (value.length >= 5 &&\r\n (value.endsWith('.jpg') ||\r\n value.endsWith('.png') ||\r\n value.endsWith('.pdf') ||\r\n value.endsWith('.svg'))),\r\n {\r\n params: {\r\n errorMessage:\r\n 'The value must be a string that ends with .jpeg, .jpg, .png, .pdf, or .svg'\r\n }\r\n }\r\n )\r\n .nullable()\r\n : z\r\n .string()\r\n .trim()\r\n .refine(\r\n (value) =>\r\n (value.length >= 6 && value.endsWith('.jpeg')) ||\r\n (value.length >= 5 &&\r\n (value.endsWith('.jpg') ||\r\n value.endsWith('.png') ||\r\n value.endsWith('.pdf') ||\r\n value.endsWith('.svg'))) ||\r\n ['undefined', 'null', ''].includes(value),\r\n {\r\n params: {\r\n errorMessage:\r\n 'The value must be a string that ends with .jpeg, .jpg, .png, .pdf, or .svg'\r\n }\r\n }\r\n )\r\n .transform((value) =>\r\n !['undefined', 'null', ''].includes(value) ? value : null\r\n )\r\n .nullable();\r\n },\r\n\r\n /**\r\n * The `type` validator that returns a Zod schema with an optional stricter\r\n * check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `enum` validator.\r\n *\r\n * @function type\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `type`\r\n * option.\r\n */\r\n type(strictCheck) {\r\n return v.enum(['jpeg', 'jpg', 'png', 'pdf', 'svg'], strictCheck);\r\n },\r\n\r\n /**\r\n * The `constr` validator that returns a Zod schema with an optional stricter\r\n * check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `enum` validator.\r\n *\r\n * @function constr\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `constr`\r\n * option.\r\n */\r\n constr(strictCheck) {\r\n return v.enum(\r\n ['chart', 'stockChart', 'mapChart', 'ganttChart'],\r\n strictCheck\r\n );\r\n },\r\n\r\n /**\r\n * The `b64` validator that returns a Zod schema with an optional stricter\r\n * check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `boolean` validator.\r\n *\r\n * @function b64\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `b64` option.\r\n */\r\n b64(strictCheck) {\r\n return v.boolean(strictCheck);\r\n },\r\n\r\n /**\r\n * The `noDownload` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `boolean` validator.\r\n *\r\n * @function noDownload\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `noDownload`\r\n * option.\r\n */\r\n noDownload(strictCheck) {\r\n return v.boolean(strictCheck);\r\n },\r\n\r\n /**\r\n * The `defaultHeight` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `positiveNum` validator.\r\n *\r\n * @function defaultHeight\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating\r\n * the `defaultHeight` option.\r\n */\r\n defaultHeight(strictCheck) {\r\n return v.positiveNum(strictCheck);\r\n },\r\n\r\n /**\r\n * The `defaultWidth` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `positiveNum` validator.\r\n *\r\n * @function defaultWidth\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating\r\n * the `defaultWidth` option.\r\n */\r\n defaultWidth(strictCheck) {\r\n return v.positiveNum(strictCheck);\r\n },\r\n\r\n /**\r\n * The `defaultScale` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures that:\r\n *\r\n * - When `strictCheck` is true, the schema will accept number values that\r\n * are between 0.1 and 5 (inclusive).\r\n *\r\n * - When `strictCheck` is false, the schema will accept number values\r\n * and stringified number values that are between 0.1 and 5 (inclusive), null,\r\n * 'undefined', 'null', and '' which will be transformed to null.\r\n *\r\n * @function defaultScale\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating\r\n * the `defaultScale` option.\r\n */\r\n defaultScale(strictCheck) {\r\n return strictCheck\r\n ? z.number().gte(0.1).lte(5)\r\n : z\r\n .union([\r\n z\r\n .string()\r\n .trim()\r\n .refine(\r\n (value) =>\r\n (!isNaN(Number(value)) &&\r\n value !== true &&\r\n !value.startsWith('[') &&\r\n Number(value) >= 0.1 &&\r\n Number(value) <= 5) ||\r\n ['undefined', 'null', ''].includes(value),\r\n {\r\n params: {\r\n errorMessage: 'The value must be within a 0.1 and 5.0 range'\r\n }\r\n }\r\n )\r\n .transform((value) =>\r\n !['undefined', 'null', ''].includes(value)\r\n ? Number(value)\r\n : null\r\n ),\r\n z.number().gte(0.1).lte(5)\r\n ])\r\n .nullable();\r\n },\r\n\r\n /**\r\n * The `height` validator that returns a Zod schema with an optional stricter\r\n * check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as a nullable `defaultHeight`\r\n * validator.\r\n *\r\n * @function height\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `height`\r\n * option.\r\n */\r\n height(strictCheck) {\r\n return this.defaultHeight(strictCheck).nullable();\r\n },\r\n\r\n /**\r\n * The `width` validator that returns a Zod schema with an optional stricter\r\n * check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as a nullable `defaultWidth`\r\n * validator.\r\n *\r\n * @function width\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `width`\r\n * option.\r\n */\r\n width(strictCheck) {\r\n return this.defaultWidth(strictCheck).nullable();\r\n },\r\n\r\n /**\r\n * The `scale` validator that returns a Zod schema with an optional stricter\r\n * check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as a nullable `defaultScale`\r\n * validator.\r\n *\r\n * @function scale\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `scale`\r\n * option.\r\n */\r\n scale(strictCheck) {\r\n return this.defaultScale(strictCheck).nullable();\r\n },\r\n\r\n /**\r\n * The `globalOptions` validator that returns a Zod schema.\r\n *\r\n * The validation schema ensures the same work as the `additionalOptions`\r\n * validator.\r\n *\r\n * @function globalOptions\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating\r\n * the `globalOptions` option.\r\n */\r\n globalOptions() {\r\n return v.additionalOptions();\r\n },\r\n\r\n /**\r\n * The `themeOptions` validator that returns a Zod schema.\r\n *\r\n * The validation schema ensures the same work as the `additionalOptions`\r\n * validator.\r\n *\r\n * @function themeOptions\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating\r\n * the `themeOptions` option.\r\n */\r\n themeOptions() {\r\n return v.additionalOptions();\r\n },\r\n\r\n /**\r\n * The `batch` validator that returns a Zod schema with an optional stricter\r\n * check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `string` validator.\r\n *\r\n * @function batch\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `batch`\r\n * option.\r\n */\r\n batch(strictCheck) {\r\n return v.string(strictCheck);\r\n },\r\n\r\n /**\r\n * The `rasterizationTimeout` validator that returns a Zod schema with\r\n * an optional stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `nonNegativeNum`\r\n * validator.\r\n *\r\n * @function rasterizationTimeout\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating\r\n * the `rasterizationTimeout` option.\r\n */\r\n rasterizationTimeout(strictCheck) {\r\n return v.nonNegativeNum(strictCheck);\r\n },\r\n\r\n /**\r\n * The `allowCodeExecution` validator that returns a Zod schema with\r\n * an optional stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `boolean` validator.\r\n *\r\n * @function allowCodeExecution\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating\r\n * the `allowCodeExecution` option.\r\n */\r\n allowCodeExecution(strictCheck) {\r\n return v.boolean(strictCheck);\r\n },\r\n\r\n /**\r\n * The `allowFileResources` validator that returns a Zod schema with\r\n * an optional stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `boolean` validator.\r\n *\r\n * @function allowFileResources\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating\r\n * the `allowFileResources` option.\r\n */\r\n allowFileResources(strictCheck) {\r\n return v.boolean(strictCheck);\r\n },\r\n\r\n /**\r\n * The `customCode` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `string` validator.\r\n *\r\n * @function customCode\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `customCode`\r\n * option.\r\n */\r\n customCode(strictCheck) {\r\n return v.string(strictCheck);\r\n },\r\n\r\n /**\r\n * The `callback` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `string` validator.\r\n *\r\n * @function callback\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `callback`\r\n * option.\r\n */\r\n callback(strictCheck) {\r\n return v.string(strictCheck);\r\n },\r\n\r\n /**\r\n * The `resources` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures that:\r\n *\r\n * - When `strictCheck` is true, the schema will accept a partial object\r\n * with allowed properties `js`, `css`, and `files` where each of the allowed\r\n * properties can be null, stringified version of the object, string that ends\r\n * with the '.json', and null.\r\n *\r\n * - When `strictCheck` is false, the schema will accept a stringified version\r\n * of a partial object with allowed properties `js`, `css`, and `files` where\r\n * each of the allowed properties can be null, string that ends with the\r\n * '.json', and will be null if the provided value is 'undefined', 'null'\r\n * or ''.\r\n *\r\n * @function resources\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `resources`\r\n * option.\r\n */\r\n resources(strictCheck) {\r\n const objectSchema = z\r\n .object({\r\n js: v.string(false),\r\n css: v.string(false),\r\n files: v\r\n .stringArray(\r\n (value) => !['undefined', 'null', ''].includes(value),\r\n ',',\r\n true\r\n )\r\n .nullable()\r\n })\r\n .partial();\r\n\r\n const stringSchema1 = z\r\n .string()\r\n .trim()\r\n .refine(\r\n (value) =>\r\n (value.startsWith('{') && value.endsWith('}')) ||\r\n (value.length >= 6 && value.endsWith('.json')),\r\n {\r\n params: {\r\n errorMessage:\r\n \"The value must be a string that starts with '{' and ends with '}\"\r\n }\r\n }\r\n );\r\n\r\n const stringSchema2 = z\r\n .string()\r\n .trim()\r\n .refine(\r\n (value) =>\r\n (value.startsWith('{') && value.endsWith('}')) ||\r\n (value.length >= 6 && value.endsWith('.json')) ||\r\n ['undefined', 'null', ''].includes(value),\r\n {\r\n params: {\r\n errorMessage: 'The value must be a string that ends with .json'\r\n }\r\n }\r\n )\r\n .transform((value) =>\r\n !['undefined', 'null', ''].includes(value) ? value : null\r\n );\r\n\r\n return strictCheck\r\n ? z.union([objectSchema, stringSchema1]).nullable()\r\n : z.union([objectSchema, stringSchema2]).nullable();\r\n },\r\n\r\n /**\r\n * The `loadConfig` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `string` validator.\r\n * Additionally, it must be a string that ends with '.json'.\r\n *\r\n * @function loadConfig\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `loadConfig`\r\n * option.\r\n */\r\n loadConfig(strictCheck) {\r\n return v\r\n .string(strictCheck)\r\n .refine(\r\n (value) =>\r\n value === null || (value.length >= 6 && value.endsWith('.json')),\r\n {\r\n params: {\r\n errorMessage: 'The value must be a string that ends with .json'\r\n }\r\n }\r\n );\r\n },\r\n\r\n /**\r\n * The `createConfig` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `loadConfig` validator.\r\n *\r\n * @function createConfig\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating\r\n * the `createConfig` option.\r\n */\r\n createConfig(strictCheck) {\r\n return this.loadConfig(strictCheck);\r\n },\r\n\r\n /**\r\n * The `enableServer` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `boolean` validator.\r\n *\r\n * @function enableServer\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating\r\n * the `enableServer` option.\r\n */\r\n enableServer(strictCheck) {\r\n return v.boolean(strictCheck);\r\n },\r\n\r\n /**\r\n * The `host` validator that returns a Zod schema with an optional stricter\r\n * check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `string` validator.\r\n *\r\n * @function host\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `host`\r\n * option.\r\n */\r\n host(strictCheck) {\r\n return v.string(strictCheck);\r\n },\r\n\r\n /**\r\n * The `port` validator that returns a Zod schema with an optional stricter\r\n * check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `nonNegativeNum`\r\n * validator.\r\n *\r\n * @function port\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `port`\r\n * option.\r\n */\r\n port(strictCheck) {\r\n return v.nonNegativeNum(strictCheck);\r\n },\r\n\r\n /**\r\n * The `uploadLimit` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `positiveNum` validator.\r\n *\r\n * @function uploadLimit\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `uploadLimit`\r\n * option.\r\n */\r\n uploadLimit(strictCheck) {\r\n return v.positiveNum(strictCheck);\r\n },\r\n\r\n /**\r\n * The `serverBenchmarking` validator that returns a Zod schema with\r\n * an optional stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `boolean` validator.\r\n *\r\n * @function serverBenchmarking\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating\r\n * the `serverBenchmarking` option.\r\n */\r\n serverBenchmarking(strictCheck) {\r\n return v.boolean(strictCheck);\r\n },\r\n\r\n /**\r\n * The `proxyHost` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `string` validator.\r\n *\r\n * @function proxyHost\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `proxyHost`\r\n * option.\r\n */\r\n proxyHost(strictCheck) {\r\n return v.string(strictCheck);\r\n },\r\n\r\n /**\r\n * The `proxyPort` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as a nullable `nonNegativeNum`\r\n * validator.\r\n *\r\n * @function proxyPort\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `proxyPort`\r\n * option.\r\n */\r\n proxyPort(strictCheck) {\r\n return v.nonNegativeNum(strictCheck).nullable();\r\n },\r\n\r\n /**\r\n * The `proxyTimeout` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `nonNegativeNum`\r\n * validator.\r\n *\r\n * @function proxyTimeout\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating\r\n * the `proxyTimeout` option.\r\n */\r\n proxyTimeout(strictCheck) {\r\n return v.nonNegativeNum(strictCheck);\r\n },\r\n\r\n /**\r\n * The `enableRateLimiting` validator that returns a Zod schema with\r\n * an optional stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `boolean` validator.\r\n *\r\n * @function enableRateLimiting\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating\r\n * the `enableRateLimiting` option.\r\n */\r\n enableRateLimiting(strictCheck) {\r\n return v.boolean(strictCheck);\r\n },\r\n\r\n /**\r\n * The `maxRequests` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `nonNegativeNum`\r\n * validator.\r\n *\r\n * @function maxRequests\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `maxRequests`\r\n * option.\r\n */\r\n maxRequests(strictCheck) {\r\n return v.nonNegativeNum(strictCheck);\r\n },\r\n\r\n /**\r\n * The `window` validator that returns a Zod schema with an optional stricter\r\n * check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `nonNegativeNum`\r\n * validator.\r\n *\r\n * @function window\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `window`\r\n * option.\r\n */\r\n window(strictCheck) {\r\n return v.nonNegativeNum(strictCheck);\r\n },\r\n\r\n /**\r\n * The `delay` validator that returns a Zod schema with an optional stricter\r\n * check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `nonNegativeNum`\r\n * validator.\r\n *\r\n * @function delay\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `delay`\r\n * option.\r\n */\r\n delay(strictCheck) {\r\n return v.nonNegativeNum(strictCheck);\r\n },\r\n\r\n /**\r\n * The `trustProxy` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `boolean` validator.\r\n *\r\n * @function trustProxy\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `trustProxy`\r\n * option.\r\n */\r\n trustProxy(strictCheck) {\r\n return v.boolean(strictCheck);\r\n },\r\n\r\n /**\r\n * The `skipKey` validator that returns a Zod schema with an optional stricter\r\n * check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `string` validator.\r\n *\r\n * @function skipKey\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `skipKey`\r\n * option.\r\n */\r\n skipKey(strictCheck) {\r\n return v.string(strictCheck);\r\n },\r\n\r\n /**\r\n * The `skipToken` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `string` validator.\r\n *\r\n * @function skipToken\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `skipToken`\r\n * option.\r\n */\r\n skipToken(strictCheck) {\r\n return v.string(strictCheck);\r\n },\r\n\r\n /**\r\n * The `enableSsl` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `boolean` validator.\r\n *\r\n * @function enableSsl\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `enableSsl`\r\n * option.\r\n */\r\n enableSsl(strictCheck) {\r\n return v.boolean(strictCheck);\r\n },\r\n\r\n /**\r\n * The `sslForce` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `boolean` validator.\r\n *\r\n * @function sslForce\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `sslForce`\r\n * option.\r\n */\r\n sslForce(strictCheck) {\r\n return v.boolean(strictCheck);\r\n },\r\n\r\n /**\r\n * The `sslPort` validator that returns a Zod schema with an optional stricter\r\n * check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `nonNegativeNum`\r\n * validator.\r\n *\r\n * @function sslPort\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `sslPort`\r\n * option.\r\n */\r\n sslPort(strictCheck) {\r\n return v.nonNegativeNum(strictCheck);\r\n },\r\n\r\n /**\r\n * The `sslCertPath` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `string` validator.\r\n *\r\n * @function sslCertPath\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `sslCertPath`\r\n * option.\r\n */\r\n sslCertPath(strictCheck) {\r\n return v.string(strictCheck);\r\n },\r\n\r\n /**\r\n * The `minWorkers` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `positiveNum` validator.\r\n *\r\n * @function minWorkers\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `minWorkers`\r\n * option.\r\n */\r\n minWorkers(strictCheck) {\r\n return v.positiveNum(strictCheck);\r\n },\r\n\r\n /**\r\n * The `maxWorkers` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `positiveNum` validator.\r\n *\r\n * @function maxWorkers\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `maxWorkers`\r\n * option.\r\n */\r\n maxWorkers(strictCheck) {\r\n return v.positiveNum(strictCheck);\r\n },\r\n\r\n /**\r\n * The `workLimit` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `positiveNum` validator.\r\n *\r\n * @function workLimit\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `workLimit`\r\n * option.\r\n */\r\n workLimit(strictCheck) {\r\n return v.positiveNum(strictCheck);\r\n },\r\n\r\n /**\r\n * The `acquireTimeout` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `nonNegativeNum`\r\n * validator.\r\n *\r\n * @function acquireTimeout\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating\r\n * the `acquireTimeout` option.\r\n */\r\n acquireTimeout(strictCheck) {\r\n return v.nonNegativeNum(strictCheck);\r\n },\r\n\r\n /**\r\n * The `createTimeout` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `nonNegativeNum`\r\n * validator.\r\n *\r\n * @function createTimeout\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating\r\n * the `createTimeout` option.\r\n */\r\n createTimeout(strictCheck) {\r\n return v.nonNegativeNum(strictCheck);\r\n },\r\n\r\n /**\r\n * The `destroyTimeout` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `nonNegativeNum`\r\n * validator.\r\n *\r\n * @function destroyTimeout\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating\r\n * the `destroyTimeout` option.\r\n */\r\n destroyTimeout(strictCheck) {\r\n return v.nonNegativeNum(strictCheck);\r\n },\r\n\r\n /**\r\n * The `idleTimeout` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `nonNegativeNum`\r\n * validator.\r\n *\r\n * @function idleTimeout\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating\r\n * the `idleTimeout` option.\r\n */\r\n idleTimeout(strictCheck) {\r\n return v.nonNegativeNum(strictCheck);\r\n },\r\n\r\n /**\r\n * The `createRetryInterval` validator that returns a Zod schema with\r\n * an optional stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `nonNegativeNum`\r\n * validator.\r\n *\r\n * @function createRetryInterval\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating\r\n * the `createRetryInterval` option.\r\n */\r\n createRetryInterval(strictCheck) {\r\n return v.nonNegativeNum(strictCheck);\r\n },\r\n\r\n /**\r\n * The `reaperInterval` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `nonNegativeNum`\r\n * validator.\r\n *\r\n * @function reaperInterval\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating\r\n * the `reaperInterval` option.\r\n */\r\n reaperInterval(strictCheck) {\r\n return v.nonNegativeNum(strictCheck);\r\n },\r\n\r\n /**\r\n * The `poolBenchmarking` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `boolean` validator.\r\n *\r\n * @function poolBenchmarking\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating\r\n * the `poolBenchmarking` option.\r\n */\r\n poolBenchmarking(strictCheck) {\r\n return v.boolean(strictCheck);\r\n },\r\n\r\n /**\r\n * The `resourcesInterval` validator that returns a Zod schema with\r\n * an optional stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `nonNegativeNum`\r\n * validator.\r\n *\r\n * @function resourcesInterval\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating\r\n * the `resourcesInterval` option.\r\n */\r\n resourcesInterval(strictCheck) {\r\n return v.nonNegativeNum(strictCheck);\r\n },\r\n\r\n /**\r\n * The `logLevel` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures that:\r\n *\r\n * - When `strictCheck` is true, the schema will accept integer number values\r\n * that are between 0 and 5 (inclusive).\r\n *\r\n * - When `strictCheck` is false, the schema will accept integer number values\r\n * and stringified integer number values that are between 1 and 5 (inclusive),\r\n * null, 'undefined', 'null', and '' which will be transformed to null.\r\n *\r\n * @function logLevel\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `logLevel`\r\n * option.\r\n */\r\n logLevel(strictCheck) {\r\n return strictCheck\r\n ? z.number().int().gte(0).lte(5)\r\n : z\r\n .union([\r\n z\r\n .string()\r\n .trim()\r\n .refine(\r\n (value) =>\r\n (!isNaN(Number(value)) &&\r\n value !== true &&\r\n !value.startsWith('[') &&\r\n Number.isInteger(Number(value)) &&\r\n Number(value) >= 0 &&\r\n Number(value) <= 5) ||\r\n ['undefined', 'null', ''].includes(value),\r\n {\r\n params: {\r\n errorMessage: 'The value must be within a 0 and 5 range'\r\n }\r\n }\r\n )\r\n .transform((value) =>\r\n !['undefined', 'null', ''].includes(value)\r\n ? Number(value)\r\n : null\r\n ),\r\n z.number().int().gte(0).lte(5)\r\n ])\r\n .nullable();\r\n },\r\n\r\n /**\r\n * The `logFile` validator that returns a Zod schema with an optional stricter\r\n * check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `string` validator.\r\n * Additionally, it must be a string that ends with '.log'.\r\n *\r\n * @function logFile\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `logFile`\r\n * option.\r\n */\r\n logFile(strictCheck) {\r\n return v\r\n .string(strictCheck)\r\n .refine(\r\n (value) =>\r\n value === null || (value.length >= 5 && value.endsWith('.log')),\r\n {\r\n params: {\r\n errorMessage: 'The value must be a string that ends with .log'\r\n }\r\n }\r\n );\r\n },\r\n\r\n /**\r\n * The `logDest` validator that returns a Zod schema with an optional stricter\r\n * check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `string` validator.\r\n *\r\n * @function logDest\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `logDest`\r\n * option.\r\n */\r\n logDest(strictCheck) {\r\n return v.string(strictCheck);\r\n },\r\n\r\n /**\r\n * The `logToConsole` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `boolean` validator.\r\n *\r\n * @function logToConsole\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating\r\n * the `logToConsole` option.\r\n */\r\n logToConsole(strictCheck) {\r\n return v.boolean(strictCheck);\r\n },\r\n\r\n /**\r\n * The `logToFile` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `boolean` validator.\r\n *\r\n * @function logToFile\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `logToFile`\r\n * option.\r\n */\r\n logToFile(strictCheck) {\r\n return v.boolean(strictCheck);\r\n },\r\n\r\n /**\r\n * The `enableUi` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `boolean` validator.\r\n *\r\n * @function enableUi\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `enableUi`\r\n * option.\r\n */\r\n enableUi(strictCheck) {\r\n return v.boolean(strictCheck);\r\n },\r\n\r\n /**\r\n * The `uiRoute` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `startsWith` validator.\r\n *\r\n * @function uiRoute\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `uiRoute`\r\n * option.\r\n */\r\n uiRoute(strictCheck) {\r\n return v.startsWith(['/'], strictCheck);\r\n },\r\n\r\n /**\r\n * The `nodeEnv` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `enum` validator.\r\n *\r\n * @function nodeEnv\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `nodeEnv`\r\n * option.\r\n */\r\n nodeEnv(strictCheck) {\r\n return v.enum(['development', 'production', 'test'], strictCheck);\r\n },\r\n\r\n /**\r\n * The `listenToProcessExits` validator that returns a Zod schema with\r\n * an optional stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `boolean` validator.\r\n *\r\n * @function listenToProcessExits\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating\r\n * the `listenToProcessExits` option.\r\n */\r\n listenToProcessExits(strictCheck) {\r\n return v.boolean(strictCheck);\r\n },\r\n\r\n /**\r\n * The `noLogo` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `boolean` validator.\r\n *\r\n * @function noLogo\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `noLogo`\r\n * option.\r\n */\r\n noLogo(strictCheck) {\r\n return v.boolean(strictCheck);\r\n },\r\n\r\n /**\r\n * The `hardResetPage` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `boolean` validator.\r\n *\r\n * @function hardResetPage\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating\r\n * the `hardResetPage` option.\r\n */\r\n hardResetPage(strictCheck) {\r\n return v.boolean(strictCheck);\r\n },\r\n\r\n /**\r\n * The `browserShellMode` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `boolean` validator.\r\n *\r\n * @function browserShellMode\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating\r\n * the `browserShellMode` option.\r\n */\r\n browserShellMode(strictCheck) {\r\n return v.boolean(strictCheck);\r\n },\r\n\r\n /**\r\n * The `validation` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `boolean` validator.\r\n *\r\n * @function validation\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `validation`\r\n * option.\r\n */\r\n validation(strictCheck) {\r\n return v.boolean(strictCheck);\r\n },\r\n\r\n /**\r\n * The `enableDebug` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `boolean` validator.\r\n *\r\n * @function enableDebug\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `enableDebug`\r\n * option.\r\n */\r\n enableDebug(strictCheck) {\r\n return v.boolean(strictCheck);\r\n },\r\n\r\n /**\r\n * The `headless` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `boolean` validator.\r\n *\r\n * @function headless\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `headless`\r\n * option.\r\n */\r\n headless(strictCheck) {\r\n return v.boolean(strictCheck);\r\n },\r\n\r\n /**\r\n * The `devtools` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `boolean` validator.\r\n *\r\n * @function devtools\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `devtools`\r\n * option.\r\n */\r\n devtools(strictCheck) {\r\n return v.boolean(strictCheck);\r\n },\r\n\r\n /**\r\n * The `listenToConsole` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `boolean` validator.\r\n *\r\n * @function listenToConsole\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating\r\n * the `listenToConsole` option.\r\n */\r\n listenToConsole(strictCheck) {\r\n return v.boolean(strictCheck);\r\n },\r\n\r\n /**\r\n * The `dumpio` validator that returns a Zod schema with an optional stricter\r\n * check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `boolean` validator.\r\n *\r\n * @function dumpio\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `dumpio`\r\n * option.\r\n */\r\n dumpio(strictCheck) {\r\n return v.boolean(strictCheck);\r\n },\r\n\r\n /**\r\n * The `slowMo` validator that returns a Zod schema with an optional stricter\r\n * check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `nonNegativeNum`\r\n * validator.\r\n *\r\n * @function slowMo\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `slowMo`\r\n * option.\r\n */\r\n slowMo(strictCheck) {\r\n return v.nonNegativeNum(strictCheck);\r\n },\r\n\r\n /**\r\n * The `debuggingPort` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `nonNegativeNum`\r\n * validator.\r\n *\r\n * @function debuggingPort\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating\r\n * the `debuggingPort` option.\r\n */\r\n debuggingPort(strictCheck) {\r\n return v.nonNegativeNum(strictCheck);\r\n },\r\n\r\n /**\r\n * The `requestId` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `string` validator.\r\n * Additionally, it must be a stringified UUID or can be null.\r\n *\r\n * @function requestId\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `requestId`\r\n * option.\r\n */\r\n requestId() {\r\n return z\r\n .string()\r\n .uuid({ message: 'The value must be a stringified UUID' })\r\n .nullable();\r\n }\r\n};\r\n\r\n// Schema for the puppeteer section of options\r\nconst PuppeteerSchema = (strictCheck) =>\r\n z\r\n .object({\r\n args: validators.args(strictCheck)\r\n })\r\n .partial();\r\n\r\n// Schema for the highcharts section of options\r\nconst HighchartsSchema = (strictCheck) =>\r\n z\r\n .object({\r\n version: validators.version(strictCheck),\r\n cdnUrl: validators.cdnUrl(strictCheck),\r\n forceFetch: validators.forceFetch(strictCheck),\r\n cachePath: validators.cachePath(strictCheck),\r\n coreScripts: validators.coreScripts(strictCheck),\r\n moduleScripts: validators.moduleScripts(strictCheck),\r\n indicatorScripts: validators.indicatorScripts(strictCheck),\r\n customScripts: validators.customScripts(strictCheck)\r\n })\r\n .partial();\r\n\r\n// Schema for the export section of options\r\nconst ExportSchema = (strictCheck) =>\r\n z\r\n .object({\r\n infile: validators.infile(strictCheck),\r\n instr: validators.instr(),\r\n options: validators.options(),\r\n svg: validators.svg(),\r\n outfile: validators.outfile(strictCheck),\r\n type: validators.type(strictCheck),\r\n constr: validators.constr(strictCheck),\r\n b64: validators.b64(strictCheck),\r\n noDownload: validators.noDownload(strictCheck),\r\n defaultHeight: validators.defaultHeight(strictCheck),\r\n defaultWidth: validators.defaultWidth(strictCheck),\r\n defaultScale: validators.defaultScale(strictCheck),\r\n height: validators.height(strictCheck),\r\n width: validators.width(strictCheck),\r\n scale: validators.scale(strictCheck),\r\n globalOptions: validators.globalOptions(),\r\n themeOptions: validators.themeOptions(),\r\n batch: validators.batch(false),\r\n rasterizationTimeout: validators.rasterizationTimeout(strictCheck)\r\n })\r\n .partial();\r\n\r\n// Schema for the customLogic section of options\r\nconst CustomLogicSchema = (strictCheck) =>\r\n z\r\n .object({\r\n allowCodeExecution: validators.allowCodeExecution(strictCheck),\r\n allowFileResources: validators.allowFileResources(strictCheck),\r\n customCode: validators.customCode(false),\r\n callback: validators.callback(false),\r\n resources: validators.resources(strictCheck),\r\n loadConfig: validators.loadConfig(false),\r\n createConfig: validators.createConfig(false)\r\n })\r\n .partial();\r\n\r\n// Schema for the server.proxy section of options\r\nconst ProxySchema = (strictCheck) =>\r\n z\r\n .object({\r\n host: validators.proxyHost(false),\r\n port: validators.proxyPort(strictCheck),\r\n timeout: validators.proxyTimeout(strictCheck)\r\n })\r\n .partial();\r\n\r\n// Schema for the server.rateLimiting section of options\r\nconst RateLimitingSchema = (strictCheck) =>\r\n z\r\n .object({\r\n enable: validators.enableRateLimiting(strictCheck),\r\n maxRequests: validators.maxRequests(strictCheck),\r\n window: validators.window(strictCheck),\r\n delay: validators.delay(strictCheck),\r\n trustProxy: validators.trustProxy(strictCheck),\r\n skipKey: validators.skipKey(false),\r\n skipToken: validators.skipToken(false)\r\n })\r\n .partial();\r\n\r\n// Schema for the server.ssl section of options\r\nconst SslSchema = (strictCheck) =>\r\n z\r\n .object({\r\n enable: validators.enableSsl(strictCheck),\r\n force: validators.sslForce(strictCheck),\r\n port: validators.sslPort(strictCheck),\r\n certPath: validators.sslCertPath(false)\r\n })\r\n .partial();\r\n\r\n// Schema for the server section of options\r\nconst ServerSchema = (strictCheck) =>\r\n z.object({\r\n enable: validators.enableServer(strictCheck).optional(),\r\n host: validators.host(strictCheck).optional(),\r\n port: validators.port(strictCheck).optional(),\r\n uploadLimit: validators.uploadLimit(strictCheck).optional(),\r\n benchmarking: validators.serverBenchmarking(strictCheck).optional(),\r\n proxy: ProxySchema(strictCheck).optional(),\r\n rateLimiting: RateLimitingSchema(strictCheck).optional(),\r\n ssl: SslSchema(strictCheck).optional()\r\n });\r\n\r\n// Schema for the pool section of options\r\nconst PoolSchema = (strictCheck) =>\r\n z\r\n .object({\r\n minWorkers: validators.minWorkers(strictCheck),\r\n maxWorkers: validators.maxWorkers(strictCheck),\r\n workLimit: validators.workLimit(strictCheck),\r\n acquireTimeout: validators.acquireTimeout(strictCheck),\r\n createTimeout: validators.createTimeout(strictCheck),\r\n destroyTimeout: validators.destroyTimeout(strictCheck),\r\n idleTimeout: validators.idleTimeout(strictCheck),\r\n createRetryInterval: validators.createRetryInterval(strictCheck),\r\n reaperInterval: validators.reaperInterval(strictCheck),\r\n benchmarking: validators.poolBenchmarking(strictCheck)\r\n })\r\n .partial();\r\n\r\n// Schema for the logging section of options\r\nconst LoggingSchema = (strictCheck) =>\r\n z\r\n .object({\r\n level: validators.logLevel(strictCheck),\r\n file: validators.logFile(strictCheck),\r\n dest: validators.logDest(strictCheck),\r\n toConsole: validators.logToConsole(strictCheck),\r\n toFile: validators.logToFile(strictCheck)\r\n })\r\n .partial();\r\n\r\n// Schema for the ui section of options\r\nconst UiSchema = (strictCheck) =>\r\n z\r\n .object({\r\n enable: validators.enableUi(strictCheck),\r\n route: validators.uiRoute(strictCheck)\r\n })\r\n .partial();\r\n\r\n// Schema for the other section of options\r\nconst OtherSchema = (strictCheck) =>\r\n z\r\n .object({\r\n nodeEnv: validators.nodeEnv(strictCheck),\r\n listenToProcessExits: validators.listenToProcessExits(strictCheck),\r\n noLogo: validators.noLogo(strictCheck),\r\n hardResetPage: validators.hardResetPage(strictCheck),\r\n browserShellMode: validators.browserShellMode(strictCheck),\r\n validation: validators.validation(strictCheck)\r\n })\r\n .partial();\r\n\r\n// Schema for the debug section of options\r\nconst DebugSchema = (strictCheck) =>\r\n z\r\n .object({\r\n enable: validators.enableDebug(strictCheck),\r\n headless: validators.headless(strictCheck),\r\n devtools: validators.devtools(strictCheck),\r\n listenToConsole: validators.listenToConsole(strictCheck),\r\n dumpio: validators.dumpio(strictCheck),\r\n slowMo: validators.slowMo(strictCheck),\r\n debuggingPort: validators.debuggingPort(strictCheck)\r\n })\r\n .partial();\r\n\r\n// Strict schema for the config\r\nexport const StrictConfigSchema = z.object({\r\n requestId: validators.requestId(),\r\n puppeteer: PuppeteerSchema(true),\r\n highcharts: HighchartsSchema(true),\r\n export: ExportSchema(true),\r\n customLogic: CustomLogicSchema(true),\r\n server: ServerSchema(true),\r\n pool: PoolSchema(true),\r\n logging: LoggingSchema(true),\r\n ui: UiSchema(true),\r\n other: OtherSchema(true),\r\n debug: DebugSchema(true)\r\n});\r\n\r\n// Loose schema for the config\r\nexport const LooseConfigSchema = z.object({\r\n requestId: validators.requestId(),\r\n puppeteer: PuppeteerSchema(false),\r\n highcharts: HighchartsSchema(false),\r\n export: ExportSchema(false),\r\n customLogic: CustomLogicSchema(false),\r\n server: ServerSchema(false),\r\n pool: PoolSchema(false),\r\n logging: LoggingSchema(false),\r\n ui: UiSchema(false),\r\n other: OtherSchema(false),\r\n debug: DebugSchema(false)\r\n});\r\n\r\n// Schema for the environment variables config\r\nexport const EnvSchema = z.object({\r\n // puppeteer\r\n PUPPETEER_ARGS: validators.args(false),\r\n\r\n // highcharts\r\n HIGHCHARTS_VERSION: validators.version(false),\r\n HIGHCHARTS_CDN_URL: validators.cdnUrl(false),\r\n HIGHCHARTS_FORCE_FETCH: validators.forceFetch(false),\r\n HIGHCHARTS_CACHE_PATH: validators.cachePath(false),\r\n HIGHCHARTS_ADMIN_TOKEN: validators.adminToken(false),\r\n HIGHCHARTS_CORE_SCRIPTS: validators.coreScripts(false),\r\n HIGHCHARTS_MODULE_SCRIPTS: validators.moduleScripts(false),\r\n HIGHCHARTS_INDICATOR_SCRIPTS: validators.indicatorScripts(false),\r\n HIGHCHARTS_CUSTOM_SCRIPTS: validators.customScripts(false),\r\n\r\n // export\r\n EXPORT_INFILE: validators.infile(false),\r\n EXPORT_INSTR: validators.instr(),\r\n EXPORT_OPTIONS: validators.options(),\r\n EXPORT_SVG: validators.svg(),\r\n EXPORT_BATCH: validators.batch(false),\r\n EXPORT_OUTFILE: validators.outfile(false),\r\n EXPORT_TYPE: validators.type(false),\r\n EXPORT_CONSTR: validators.constr(false),\r\n EXPORT_B64: validators.b64(false),\r\n EXPORT_NO_DOWNLOAD: validators.noDownload(false),\r\n EXPORT_HEIGHT: validators.height(false),\r\n EXPORT_WIDTH: validators.width(false),\r\n EXPORT_SCALE: validators.scale(false),\r\n EXPORT_DEFAULT_HEIGHT: validators.defaultHeight(false),\r\n EXPORT_DEFAULT_WIDTH: validators.defaultWidth(false),\r\n EXPORT_DEFAULT_SCALE: validators.defaultScale(false),\r\n EXPORT_GLOBAL_OPTIONS: validators.globalOptions(),\r\n EXPORT_THEME_OPTIONS: validators.themeOptions(),\r\n EXPORT_RASTERIZATION_TIMEOUT: validators.rasterizationTimeout(false),\r\n\r\n // custom\r\n CUSTOM_LOGIC_ALLOW_CODE_EXECUTION: validators.allowCodeExecution(false),\r\n CUSTOM_LOGIC_ALLOW_FILE_RESOURCES: validators.allowFileResources(false),\r\n CUSTOM_LOGIC_CUSTOM_CODE: validators.customCode(false),\r\n CUSTOM_LOGIC_CALLBACK: validators.callback(false),\r\n CUSTOM_LOGIC_RESOURCES: validators.resources(false),\r\n CUSTOM_LOGIC_LOAD_CONFIG: validators.loadConfig(false),\r\n CUSTOM_LOGIC_CREATE_CONFIG: validators.createConfig(false),\r\n\r\n // server\r\n SERVER_ENABLE: validators.enableServer(false),\r\n SERVER_HOST: validators.host(false),\r\n SERVER_PORT: validators.port(false),\r\n SERVER_UPLOAD_LIMIT: validators.uploadLimit(false),\r\n SERVER_BENCHMARKING: validators.serverBenchmarking(false),\r\n\r\n // server proxy\r\n SERVER_PROXY_HOST: validators.proxyHost(false),\r\n SERVER_PROXY_PORT: validators.proxyPort(false),\r\n SERVER_PROXY_TIMEOUT: validators.proxyTimeout(false),\r\n\r\n // server rate limiting\r\n SERVER_RATE_LIMITING_ENABLE: validators.enableRateLimiting(false),\r\n SERVER_RATE_LIMITING_MAX_REQUESTS: validators.maxRequests(false),\r\n SERVER_RATE_LIMITING_WINDOW: validators.window(false),\r\n SERVER_RATE_LIMITING_DELAY: validators.delay(false),\r\n SERVER_RATE_LIMITING_TRUST_PROXY: validators.trustProxy(false),\r\n SERVER_RATE_LIMITING_SKIP_KEY: validators.skipKey(false),\r\n SERVER_RATE_LIMITING_SKIP_TOKEN: validators.skipToken(false),\r\n\r\n // server ssl\r\n SERVER_SSL_ENABLE: validators.enableSsl(false),\r\n SERVER_SSL_FORCE: validators.sslForce(false),\r\n SERVER_SSL_PORT: validators.sslPort(false),\r\n SERVER_SSL_CERT_PATH: validators.sslCertPath(false),\r\n\r\n // pool\r\n POOL_MIN_WORKERS: validators.minWorkers(false),\r\n POOL_MAX_WORKERS: validators.maxWorkers(false),\r\n POOL_WORK_LIMIT: validators.workLimit(false),\r\n POOL_ACQUIRE_TIMEOUT: validators.acquireTimeout(false),\r\n POOL_CREATE_TIMEOUT: validators.createTimeout(false),\r\n POOL_DESTROY_TIMEOUT: validators.destroyTimeout(false),\r\n POOL_IDLE_TIMEOUT: validators.idleTimeout(false),\r\n POOL_CREATE_RETRY_INTERVAL: validators.createRetryInterval(false),\r\n POOL_REAPER_INTERVAL: validators.reaperInterval(false),\r\n POOL_BENCHMARKING: validators.poolBenchmarking(false),\r\n\r\n // logging\r\n LOGGING_LEVEL: validators.logLevel(false),\r\n LOGGING_FILE: validators.logFile(false),\r\n LOGGING_DEST: validators.logDest(false),\r\n LOGGING_TO_CONSOLE: validators.logToConsole(false),\r\n LOGGING_TO_FILE: validators.logToFile(false),\r\n\r\n // ui\r\n UI_ENABLE: validators.enableUi(false),\r\n UI_ROUTE: validators.uiRoute(false),\r\n\r\n // other\r\n OTHER_NODE_ENV: validators.nodeEnv(false),\r\n OTHER_LISTEN_TO_PROCESS_EXITS: validators.listenToProcessExits(false),\r\n OTHER_NO_LOGO: validators.noLogo(false),\r\n OTHER_HARD_RESET_PAGE: validators.hardResetPage(false),\r\n OTHER_BROWSER_SHELL_MODE: validators.browserShellMode(false),\r\n OTHER_VALIDATION: validators.validation(false),\r\n\r\n // debugger\r\n DEBUG_ENABLE: validators.enableDebug(false),\r\n DEBUG_HEADLESS: validators.headless(false),\r\n DEBUG_DEVTOOLS: validators.devtools(false),\r\n DEBUG_LISTEN_TO_CONSOLE: validators.listenToConsole(false),\r\n DEBUG_DUMPIO: validators.dumpio(false),\r\n DEBUG_SLOW_MO: validators.slowMo(false),\r\n DEBUG_DEBUGGING_PORT: validators.debuggingPort(false)\r\n});\r\n\r\n/**\r\n * Validates the environment variables options using the EnvSchema.\r\n *\r\n * @param {Object} process.env - The configuration options from environment\r\n * variables file to validate.\r\n *\r\n * @returns {Object} The parsed and validated environment variables.\r\n */\r\nexport const envs = EnvSchema.partial().parse(process.env);\r\n\r\n/**\r\n * Validates the configuration options using the `StrictConfigSchema`.\r\n *\r\n * @function strictValidate\r\n *\r\n * @param {Object} configOptions - The configuration options to validate.\r\n *\r\n * @returns {Object} The parsed and validated configuration options.\r\n */\r\nexport function strictValidate(configOptions) {\r\n return StrictConfigSchema.partial().parse(configOptions);\r\n}\r\n\r\n/**\r\n * Validates the configuration options using the `LooseConfigSchema`.\r\n *\r\n * @function looseValidate\r\n *\r\n * @param {Object} configOptions - The configuration options to validate.\r\n *\r\n * @returns {Object} The parsed and validated configuration options.\r\n */\r\nexport function looseValidate(configOptions) {\r\n return LooseConfigSchema.partial().parse(configOptions);\r\n}\r\n\r\n/**\r\n * Custom error mapping function for Zod schema validation.\r\n *\r\n * This function customizes the error messages produced by Zod schema\r\n * validation, providing more specific and user-friendly feedback based on the\r\n * issue type and context.\r\n *\r\n * The function modifies the error messages as follows:\r\n *\r\n * - For missing required values (undefined), it returns a message indicating\r\n * that no value was provided for the specific property.\r\n *\r\n * - For custom validation errors, if a custom error message is provided in the\r\n * issue parameters, it includes this message along with the invalid data\r\n * received.\r\n *\r\n * - For all other errors, it appends property-specific information to the\r\n * default error message provided by Zod.\r\n *\r\n * @function _customErrorMap\r\n *\r\n * @param {z.ZodIssue} issue - The issue object representing the validation\r\n * error.\r\n * @param {Object} context - The context object providing additional information\r\n * about the validation error.\r\n *\r\n * @returns {Object} An object containing the customized error message.\r\n */\r\nfunction _customErrorMap(issue, context) {\r\n // Get the chain of properties which error directly refers to\r\n const propertyName = issue.path.join('.');\r\n\r\n // Create the first part of the message about the property information\r\n const propertyInfo = `Invalid value for the ${propertyName}`;\r\n\r\n // Modified message for the invalid type\r\n if (issue.code === z.ZodIssueCode.invalid_type) {\r\n // Modified message for the required values\r\n if (issue.received === z.ZodParsedType.undefined) {\r\n return {\r\n message: `${propertyInfo} - No value was provided.`\r\n };\r\n }\r\n\r\n // Modified message for the specific invalid type when values exist\r\n return {\r\n message: `${propertyInfo} - Invalid type. ${context.defaultError}.`\r\n };\r\n }\r\n\r\n // Modified message for the custom validation\r\n if (issue.code === z.ZodIssueCode.custom) {\r\n // If the custom message for error exist, include it\r\n if (issue.params?.errorMessage) {\r\n return {\r\n message: `${propertyInfo} - ${issue.params?.errorMessage}, received '${context.data}'.`\r\n };\r\n }\r\n }\r\n\r\n // Modified message for the invalid union error\r\n if (issue.code === z.ZodIssueCode.invalid_union) {\r\n // Create the first part of the message about the multiple errors\r\n let message = `Multiple errors occurred for the ${propertyName}:\\n`;\r\n\r\n // Cycle through all errors and create a correct message\r\n issue.unionErrors.forEach((value) => {\r\n const index = value.issues[0].message.indexOf('-');\r\n message +=\r\n index !== -1\r\n ? `${value.issues[0].message}\\n`.substring(index)\r\n : `${value.issues[0].message}\\n`;\r\n });\r\n\r\n // Return the final message for the invalid union error\r\n return {\r\n message\r\n };\r\n }\r\n\r\n // Return the default error message, extended by the info about the property\r\n return {\r\n message: `${propertyInfo} - ${context.defaultError}.`\r\n };\r\n}\r\n\r\nexport default {\r\n validators,\r\n StrictConfigSchema,\r\n LooseConfigSchema,\r\n EnvSchema,\r\n envs,\r\n strictValidate,\r\n looseValidate\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * A custom error class for handling export-related errors. Extends the native\r\n * `Error` class to include additional properties like status code and stack\r\n * trace details.\r\n */\r\nclass ExportError extends Error {\r\n /**\r\n * Creates an instance of the `ExportError`.\r\n *\r\n * @param {string} message - The error message to be displayed.\r\n * @param {number} statusCode - Optional HTTP status code associated\r\n * with the error (e.g., 400, 500).\r\n */\r\n constructor(message, statusCode) {\r\n super();\r\n\r\n this.message = message;\r\n this.stackMessage = message;\r\n\r\n if (statusCode) {\r\n this.statusCode = statusCode;\r\n }\r\n }\r\n\r\n /**\r\n * Sets or updates the HTTP status code for the error.\r\n *\r\n * @param {number} statusCode - The HTTP status code to assign to the error.\r\n *\r\n * @returns {ExportError} The updated instance of the `ExportError` class.\r\n */\r\n setStatus(statusCode) {\r\n this.statusCode = statusCode;\r\n\r\n return this;\r\n }\r\n\r\n /**\r\n * Sets additional error details based on an existing error object.\r\n *\r\n * @param {Error} error - An error object containing details to populate\r\n * the `ExportError` instance.\r\n *\r\n * @returns {ExportError} The updated instance of the `ExportError` class.\r\n */\r\n setError(error) {\r\n this.error = error;\r\n\r\n if (error.name) {\r\n this.name = error.name;\r\n }\r\n\r\n if (error.statusCode) {\r\n this.statusCode = error.statusCode;\r\n }\r\n\r\n if (error.stack) {\r\n this.stackMessage = error.message;\r\n this.stack = error.stack;\r\n }\r\n\r\n return this;\r\n }\r\n}\r\n\r\nexport default ExportError;\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * @overview Manages configuration for the Highcharts Export Server by loading\r\n * and merging options from multiple sources, such as default settings,\r\n * environment variables, user-provided options, and command-line arguments.\r\n * Ensures the global options are up-to-date with the highest priority values.\r\n * Provides functions for accessing and updating configuration.\r\n */\r\n\r\nimport { readFileSync } from 'fs';\r\nimport { join } from 'path';\r\n\r\nimport { log, logWithStack, logZodIssues } from './logger.js';\r\nimport { __dirname, isObject, deepCopy, getAbsolutePath } from './utils.js';\r\nimport {\r\n envs,\r\n looseValidate,\r\n strictValidate,\r\n validators\r\n} from './validation.js';\r\n\r\nimport { defaultConfig, nestedProps, absoluteProps } from './schemas/config.js';\r\n\r\nimport ExportError from './errors/ExportError.js';\r\n\r\n// Sets the global options with initial values from the default config\r\nconst globalOptions = _initGlobalOptions(defaultConfig);\r\n\r\n// An object for the instance options, created each time the `initExport` occurs\r\nconst instanceOptions = deepCopy(globalOptions);\r\n\r\n/**\r\n * Retrieves a reference to the options object. Depending on the `getInstance`\r\n * parameter, it returns either the global options or the instance-specific\r\n * options object.\r\n *\r\n * @function getOptions\r\n *\r\n * @param {boolean} [getInstance=true] - Optional parameter that decides whether\r\n * to return the instance-specific options (when `true`) or the global options\r\n * (when `false`). The default value is `true`.\r\n *\r\n * @returns {Object} A reference to either the global options\r\n * or the instance-specific options, based on the `getInstance` parameter.\r\n */\r\nexport function getOptions(getInstance = true) {\r\n return getInstance ? instanceOptions : globalOptions;\r\n}\r\n\r\n/**\r\n * Sets the global options of the export server, keeping the principle\r\n * of the options load priority from all available sources. It accepts optional\r\n * `customOptions` object and `cliArgs` array with arguments from the CLI. These\r\n * options will be validated and applied if provided.\r\n *\r\n * The priority order of setting values is:\r\n *\r\n * 1. Options from the `lib/schemas/config.js` file (default values).\r\n * 2. Options from a custom JSON file (loaded by the `loadConfig` option).\r\n * 3. Options from the environment variables (the `.env` file).\r\n * 4. Options from the command line interface (CLI).\r\n * 5. Options from the first parameter (the `customOptions` is by default\r\n * an empty object).\r\n *\r\n * @function setGlobalOptions\r\n *\r\n * @param {Object} [customOptions={}] - Optional custom options for additional\r\n * configuration. The default value is an empty object.\r\n * @param {Array.} [cliArgs=[]] - Optional command line arguments\r\n * for additional configuration. The default value is an empty array.\r\n *\r\n * @returns {Object} The updated global options object, reflecting the merged\r\n * configuration from all available sources.\r\n */\r\nexport function setGlobalOptions(customOptions = {}, cliArgs = []) {\r\n // Object for options loaded via the `loadConfig` option\r\n let configOptions = {};\r\n\r\n // Object for options from the CLI\r\n let cliOptions = {};\r\n\r\n // Only for the CLI usage\r\n if (cliArgs && Array.isArray(cliArgs) && cliArgs.length) {\r\n try {\r\n // Validate options from the custom JSON loaded via the `loadConfig`\r\n configOptions = strictValidate(\r\n _loadConfigFile(cliArgs, globalOptions.customLogic)\r\n );\r\n } catch (error) {\r\n logZodIssues(\r\n 1,\r\n error.issues,\r\n '[validation] Custom options from the `loadConfig` option validation error'\r\n );\r\n }\r\n\r\n try {\r\n // Validate options from the CLI\r\n cliOptions = looseValidate(_pairArgumentValue(nestedProps, cliArgs));\r\n } catch (error) {\r\n logZodIssues(\r\n 1,\r\n error.issues,\r\n '[validation] CLI options validation error'\r\n );\r\n }\r\n }\r\n\r\n // Apply custom options if there are any\r\n if (\r\n customOptions &&\r\n isObject(customOptions) &&\r\n Object.keys(customOptions).length\r\n ) {\r\n try {\r\n // Validate custom options provided by the user\r\n customOptions = strictValidate(customOptions);\r\n } catch (error) {\r\n logZodIssues(\r\n 1,\r\n error.issues,\r\n '[validation] Custom options validation error'\r\n );\r\n }\r\n }\r\n\r\n // Update values of the global options with values from each source possible\r\n _updateGlobalOptions(\r\n defaultConfig,\r\n globalOptions,\r\n configOptions,\r\n cliOptions,\r\n customOptions\r\n );\r\n\r\n // Return updated global options\r\n return globalOptions;\r\n}\r\n\r\n/**\r\n * Updates the instance options with additional options. It optionally allows\r\n * to reinitialize the instance options with the values of a current global\r\n * options object.\r\n *\r\n * @param {Object} updateOptions - The update options to merge into the instance\r\n * options.\r\n * @param {boolean} [newInstance=false] - A flag to indicate whether to init\r\n * options for a new instance. If `true`, the existing instance options will\r\n * be cleared and reinitialized based on the global options.\r\n *\r\n * @returns {Object} - The updated instance options.\r\n */\r\nexport function updateOptions(updateOptions, newInstance = false) {\r\n // Check if options need to be created for a new instance\r\n if (newInstance) {\r\n // Get rid of the old instance options\r\n Object.keys(instanceOptions).forEach((key) => {\r\n delete instanceOptions[key];\r\n });\r\n\r\n // Init the new instance options based on the global options\r\n mergeOptions(instanceOptions, deepCopy(globalOptions));\r\n }\r\n\r\n // Merge additional options to the instance options\r\n mergeOptions(instanceOptions, updateOptions);\r\n\r\n // Return the reference to the instance options object\r\n return instanceOptions;\r\n}\r\n\r\n/**\r\n * Merges two sets of configuration options, considering absolute properties.\r\n *\r\n * @function mergeOptions\r\n *\r\n * @param {Object} originalOptions - Original configuration options.\r\n * @param {Object} newOptions - New configuration options to be merged.\r\n *\r\n * @returns {Object} Merged configuration options.\r\n */\r\nexport function mergeOptions(originalOptions, newOptions) {\r\n // Check if the `originalOptions` and `newOptions` are correct objects\r\n if (isObject(originalOptions) && isObject(newOptions)) {\r\n for (const [key, value] of Object.entries(newOptions)) {\r\n originalOptions[key] =\r\n isObject(value) &&\r\n !absoluteProps.includes(key) &&\r\n originalOptions[key] !== undefined\r\n ? mergeOptions(originalOptions[key], value)\r\n : value !== undefined\r\n ? value\r\n : originalOptions[key] || null;\r\n }\r\n }\r\n\r\n // Return the original (modified or not) options\r\n return originalOptions;\r\n}\r\n\r\n/**\r\n * Maps old-structured configuration options (PhantomJS) to a new format\r\n * (Puppeteer). This function converts flat, old-structured options into\r\n * a new, nested configuration format based on a predefined mapping\r\n * (`nestedProps`). The new format is used for Puppeteer, while the old format\r\n * was used for PhantomJS.\r\n *\r\n * @function mapToNewOptions\r\n *\r\n * @param {Object} oldOptions - The old, flat configuration options\r\n * to be converted.\r\n *\r\n * @returns {Object} A new object containing options structured according\r\n * to the mapping defined in `nestedProps` or an empty object if the provided\r\n * `oldOptions` is not a correct object.\r\n */\r\nexport function mapToNewOptions(oldOptions) {\r\n // An object for the new structured options\r\n const newOptions = {};\r\n\r\n // Check if provided value is a correct object\r\n if (isObject(oldOptions)) {\r\n // Iterate over each key-value pair in the old-structured options\r\n for (const [key, value] of Object.entries(oldOptions)) {\r\n // If there is a nested mapping, split it into a properties chain\r\n const propertiesChain = nestedProps[key]\r\n ? nestedProps[key].split('.')\r\n : [];\r\n\r\n // If it is the last property in the chain, assign the value, otherwise,\r\n // create or reuse the nested object\r\n propertiesChain.reduce(\r\n (obj, prop, index) =>\r\n (obj[prop] =\r\n propertiesChain.length - 1 === index ? value : obj[prop] || {}),\r\n newOptions\r\n );\r\n }\r\n } else {\r\n log(\r\n 2,\r\n '[config] No correct object with options was provided. Returning an empty array.'\r\n );\r\n }\r\n\r\n // Return the new, structured options object\r\n return newOptions;\r\n}\r\n\r\n/**\r\n * Validates a specified option using the corresponding validator from the\r\n * configuration object. Returns the original option if the validation\r\n * is disabled globally.\r\n *\r\n * @function validateOption\r\n *\r\n * @param {string} name - The name of the option to validate.\r\n * @param {any} configOption - The value of the option to validate.\r\n * @param {boolean} [strictCheck=true] - Determines if stricter validation\r\n * should be applied. The default value is `true`.\r\n *\r\n * @returns {any} The parsed and validated value of the option.\r\n */\r\nexport function validateOption(name, configOption, strictCheck = true) {\r\n // Return the original option if the validation is disabled\r\n if (!getOptions().other.validation) {\r\n return configOption;\r\n }\r\n\r\n try {\r\n // Return validated option\r\n return validators[name](strictCheck).parse(configOption);\r\n } catch (error) {\r\n // Log Zod issues\r\n logZodIssues(\r\n 1,\r\n error.issues,\r\n `[validation] The ${name} option validation error`\r\n );\r\n\r\n // Throw validation error\r\n throw new ExportError(\r\n `[validation] The ${name} option validation error`,\r\n 400\r\n );\r\n }\r\n}\r\n\r\n/**\r\n * Validates the provided configuration options for the exporting process.\r\n * Returns the original option if the validation is disabled globally.\r\n *\r\n * @function validateOptions\r\n *\r\n * @param {Object} configOptions - The configuration options to be validated.\r\n * @param {boolean} [strictCheck=true] - Determines if stricter validation\r\n * should be applied. The default value is `true`.\r\n *\r\n * @returns {Object} The parsed and validated configuration options object.\r\n */\r\nexport function validateOptions(configOptions, strictCheck = true) {\r\n // Return the original config if the validation is disabled\r\n if (!getOptions().other.validation) {\r\n return configOptions;\r\n }\r\n\r\n try {\r\n // Return validated options\r\n return strictCheck\r\n ? strictValidate(configOptions)\r\n : looseValidate(configOptions);\r\n } catch (error) {\r\n // Log Zod issues\r\n logZodIssues(1, error.issues, '[validation] Options validation error');\r\n\r\n // Throw validation error\r\n throw new ExportError('[validation] Options validation error', 400);\r\n }\r\n}\r\n\r\n/**\r\n * Validates, parses, and checks if the provided config is allowed set\r\n * of options.\r\n *\r\n * @function isAllowedConfig\r\n *\r\n * @param {unknown} config - The config to be validated and parsed as a set\r\n * of options. Must be either an object or a string.\r\n * @param {boolean} [toString=false] - Whether to return a stringified version\r\n * of the parsed config. The default value is `false`.\r\n * @param {boolean} [allowFunctions=false] - Whether to allow functions\r\n * in the parsed config. If true, functions are preserved. Otherwise, when\r\n * a function is found, null is returned. The default value is `false`.\r\n *\r\n * @returns {(Object|string|null)} Returns a parsed set of options object,\r\n * a stringified set of options object if the `toString` is true, and null\r\n * if the config is not a valid set of options or parsing fails.\r\n */\r\nexport function isAllowedConfig(\r\n config,\r\n toString = false,\r\n allowFunctions = false\r\n) {\r\n try {\r\n // Accept only objects and strings\r\n if (!isObject(config) && typeof config !== 'string') {\r\n // Return null if any other type\r\n return null;\r\n }\r\n\r\n // Get the object representation of the original config\r\n const objectConfig =\r\n typeof config === 'string'\r\n ? allowFunctions\r\n ? eval(`(${config})`)\r\n : JSON.parse(config)\r\n : config;\r\n\r\n // Preserve or remove potential functions based on the `allowFunctions` flag\r\n const stringifiedOptions = _optionsStringify(\r\n objectConfig,\r\n allowFunctions,\r\n false\r\n );\r\n\r\n // Parse the config to check if it is valid set of options\r\n const parsedOptions = allowFunctions\r\n ? JSON.parse(\r\n _optionsStringify(objectConfig, allowFunctions, true),\r\n (_, value) =>\r\n typeof value === 'string' && value.startsWith('function')\r\n ? eval(`(${value})`)\r\n : value\r\n )\r\n : JSON.parse(stringifiedOptions);\r\n\r\n // Return stringified or object options based on the `toString` flag\r\n return toString ? stringifiedOptions : parsedOptions;\r\n } catch (error) {\r\n // Return null if parsing fails\r\n return null;\r\n }\r\n}\r\n\r\n/**\r\n * Prints the Highcharts Export Server logo, version, and license information.\r\n *\r\n * @function printLicense\r\n */\r\nexport function printLicense() {\r\n // Print the logo and version information\r\n printVersion();\r\n\r\n // Print the license information\r\n console.log(\r\n 'This software requires a valid Highcharts license for commercial use.\\n'\r\n .yellow,\r\n '\\nFor a full list of CLI options, type:',\r\n '\\nhighcharts-export-server --help\\n'.green,\r\n '\\nIf you do not have a license, one can be obtained here:',\r\n '\\nhttps://shop.highsoft.com/\\n'.green,\r\n '\\nTo customize your installation, please refer to the README file at:',\r\n '\\nhttps://github.com/highcharts/node-export-server#readme\\n'.green\r\n );\r\n}\r\n\r\n/**\r\n * Prints usage information for CLI arguments, displaying available options\r\n * and their descriptions. It can list properties recursively if categories\r\n * contain nested options.\r\n *\r\n * @function printUsage\r\n */\r\nexport function printUsage() {\r\n // Display README and general usage information\r\n console.log(\r\n '\\nUsage of CLI arguments:'.bold,\r\n '\\n-----------------------',\r\n `\\nFor more detailed information, visit the README file at: ${'https://github.com/highcharts/node-export-server#readme'.green}.\\n`\r\n );\r\n\r\n // Iterate through each category in the `defaultConfig` and display usage info\r\n Object.keys(defaultConfig).forEach((category) => {\r\n console.log(`${category.toUpperCase()}`.bold.red);\r\n _cycleCategories(defaultConfig[category]);\r\n console.log('');\r\n });\r\n}\r\n\r\n/**\r\n * Prints the Highcharts Export Server logo or text with the version\r\n * information.\r\n *\r\n * @function printVersion\r\n *\r\n * @param {boolean} [noLogo=false] - If true, only prints text with the version\r\n * information, without the logo. The default value is `false`.\r\n */\r\nexport function printVersion(noLogo = false) {\r\n // Get package version either from `.env` or from `package.json`\r\n const packageVersion = JSON.parse(\r\n readFileSync(join(__dirname, 'package.json'), 'utf8')\r\n ).version;\r\n\r\n // Print text only\r\n if (noLogo) {\r\n console.log(`Highcharts Export Server v${packageVersion}`);\r\n } else {\r\n // Print the logo\r\n console.log(\r\n readFileSync(join(__dirname, 'msg', 'startup.msg'), 'utf8').toString()\r\n .bold.yellow,\r\n `v${packageVersion}\\n`.bold\r\n );\r\n }\r\n}\r\n\r\n/**\r\n * Initializes and returns global options object based on provided\r\n * configuration, setting values from nested properties recursively.\r\n *\r\n * @function _initGlobalOptions\r\n *\r\n * @param {Object} config - The configuration object to be used for initializing\r\n * options.\r\n *\r\n * @returns {Object} Initialized options object.\r\n */\r\nfunction _initGlobalOptions(config) {\r\n const options = {};\r\n\r\n // Start initializing the `options` object recursively\r\n for (const [name, item] of Object.entries(config)) {\r\n if (Object.prototype.hasOwnProperty.call(item, 'value')) {\r\n // If a value from environment variables exists, it takes precedence\r\n const envVal = envs[item.envLink];\r\n if (envVal !== undefined && envVal !== null) {\r\n options[name] = envVal;\r\n } else {\r\n options[name] = item.value;\r\n }\r\n } else {\r\n options[name] = _initGlobalOptions(item);\r\n }\r\n }\r\n\r\n // Return the created `options` object\r\n return options;\r\n}\r\n\r\n/**\r\n * Updates global options object with values from various sources, following\r\n * a specific prioritization order. The function checks for values in the order\r\n * of precedence: the `loadConfig` configuration options, environment variables,\r\n * custom options, and CLI options.\r\n *\r\n * @function _updateGlobalOptions\r\n *\r\n * @param {Object} config - The configuration object, which includes the initial\r\n * settings and metadata for each option. This object is used to determine\r\n * the structure and default values for the options.\r\n * @param {Object} options - The global options object that will be updated\r\n * with values from other sources.\r\n * @param {Object} configOpt - The configuration options object, loaded with\r\n * the `loadConfig` option, which may provide values to override defaults.\r\n * @param {Object} cliOpt - The CLI options object, which may include values\r\n * provided through command-line arguments and may override configuration\r\n * options.\r\n * @param {Object} customOpt - The custom options object, typically containing\r\n * additional and user-defined values, which has the highest precedence among\r\n * options.\r\n */\r\nfunction _updateGlobalOptions(config, options, configOpt, cliOpt, customOpt) {\r\n Object.keys(config).forEach((key) => {\r\n // Get the config entry of a specific option\r\n const entry = config[key];\r\n\r\n // Gather values for the options from every possible source, if exists\r\n const configVal = configOpt && configOpt[key];\r\n const cliVal = cliOpt && cliOpt[key];\r\n const customVal = customOpt && customOpt[key];\r\n\r\n // If the value not found, need to go deeper\r\n if (typeof entry.value === 'undefined') {\r\n _updateGlobalOptions(entry, options[key], configVal, cliVal, customVal);\r\n } else {\r\n // If a value from custom JSON options exists, it takes precedence\r\n if (configVal !== undefined && configVal !== null) {\r\n options[key] = configVal;\r\n }\r\n\r\n // If a value from environment variables exists, it takes precedence\r\n const envVal = envs[entry.envLink];\r\n if (entry.envLink in envs && envVal !== undefined && envVal !== null) {\r\n options[key] = envVal;\r\n }\r\n\r\n // If a value from CLI options exists, it takes precedence\r\n if (cliVal !== undefined && cliVal !== null) {\r\n options[key] = cliVal;\r\n }\r\n\r\n // If a value from user options exists, it takes precedence\r\n if (customVal !== undefined && customVal !== null) {\r\n options[key] = customVal;\r\n }\r\n }\r\n });\r\n}\r\n\r\n/**\r\n * Converts the provided options object to a JSON-formatted string\r\n * with the option to preserve functions. In order for a function\r\n * to be preserved, it needs to follow the format `function (...) {...}`.\r\n * Such a function can also be stringified.\r\n *\r\n * @function _optionsStringify\r\n *\r\n * @param {Object} options - The options object to be converted to a string.\r\n * @param {boolean} allowFunctions - If set to true, functions are preserved\r\n * in the output. Otherwise an error is thrown.\r\n * @param {boolean} stringifyFunctions - If set to true, functions are saved\r\n * as strings. The `allowFunctions` must be set to true as well for this to take\r\n * an effect.\r\n *\r\n * @returns {string} The JSON-formatted string representing the options.\r\n *\r\n * @throws {Error} Throws an `Error` when functions are not allowed but are\r\n * found in provided options object.\r\n */\r\nexport function _optionsStringify(options, allowFunctions, stringifyFunctions) {\r\n const replacerCallback = (_, value) => {\r\n // Trim string values\r\n if (typeof value === 'string') {\r\n value = value.trim();\r\n }\r\n\r\n // If value is a function or stringified function\r\n if (\r\n typeof value === 'function' ||\r\n (typeof value === 'string' &&\r\n value.startsWith('function') &&\r\n value.endsWith('}'))\r\n ) {\r\n // If allowFunctions is set to true, preserve functions\r\n if (allowFunctions) {\r\n // Based on the `stringifyFunctions` options, set function values\r\n return stringifyFunctions\r\n ? // As stringified functions\r\n `\"EXP_FUN${(value + '').replaceAll(/\\s+/g, ' ')}EXP_FUN\"`\r\n : // As functions\r\n `EXP_FUN${(value + '').replaceAll(/\\s+/g, ' ')}EXP_FUN`;\r\n } else {\r\n // Throw an error otherwise\r\n throw new Error();\r\n }\r\n }\r\n\r\n // In all other cases, simply return the value\r\n return value;\r\n };\r\n\r\n // Stringify options and if required, replace special functions marks\r\n return JSON.stringify(options, replacerCallback).replaceAll(\r\n stringifyFunctions ? /\\\\\"EXP_FUN|EXP_FUN\\\\\"/g : /\"EXP_FUN|EXP_FUN\"/g,\r\n ''\r\n );\r\n}\r\n\r\n/**\r\n * Loads additional configuration from a specified file provided via\r\n * the `loadConfig` option in the command-line arguments.\r\n *\r\n * @function _loadConfigFile\r\n *\r\n * @param {Array.} cliArgs - Command-line arguments to search\r\n * for the `loadConfig` option and the corresponding file path.\r\n * @param {Object} customLogicOptions - The configuration object containing\r\n * `customLogic` options.\r\n *\r\n * @returns {Object} The additional configuration loaded from the specified\r\n * file, or an empty object if the file is not found, invalid, or an error\r\n * occurs.\r\n */\r\nfunction _loadConfigFile(cliArgs, customLogicOptions) {\r\n // Check if the `loadConfig` option was used\r\n const configIndex = cliArgs.findIndex(\r\n (arg) => arg.replace(/-/g, '') === 'loadConfig'\r\n );\r\n\r\n // Get the `loadConfig` option value\r\n const configFileName = configIndex > -1 && cliArgs[configIndex + 1];\r\n\r\n // Check if the `loadConfig` is present and has a correct value\r\n if (configFileName && customLogicOptions.allowFileResources) {\r\n try {\r\n // Load an optional custom JSON config file\r\n return isAllowedConfig(\r\n readFileSync(getAbsolutePath(configFileName), 'utf8'),\r\n false,\r\n customLogicOptions.allowCodeExecution\r\n );\r\n } catch (error) {\r\n logWithStack(\r\n 2,\r\n error,\r\n `[config] Unable to load the configuration from the ${configFileName} file.`\r\n );\r\n }\r\n }\r\n\r\n // No additional options to return\r\n return {};\r\n}\r\n\r\n/**\r\n * Parses command-line arguments and pairs each argument with its corresponding\r\n * option in the configuration. The values are structured into a nested options\r\n * object, based on predefined mappings.\r\n *\r\n * @function _pairArgumentValue\r\n *\r\n * @param {Array.} nestedProps - An array of nesting level for all\r\n * options.\r\n * @param {Array.} cliArgs - An array of command-line arguments\r\n * containing options and their associated values.\r\n *\r\n * @returns {Object} An updated options object where each option from\r\n * the command-line is paired with its value, structured into nested objects\r\n * as defined.\r\n */\r\nfunction _pairArgumentValue(nestedProps, cliArgs) {\r\n // An empty object to collect and structurize data from the args\r\n const cliOptions = {};\r\n\r\n // Cycle through all CLI args and filter them\r\n for (let i = 0; i < cliArgs.length; i++) {\r\n const option = cliArgs[i].replace(/-/g, '');\r\n\r\n // Find the right place for property's value\r\n const propertiesChain = nestedProps[option]\r\n ? nestedProps[option].split('.')\r\n : [];\r\n\r\n // Create options object with values from CLI for later parsing and merging\r\n propertiesChain.reduce((obj, prop, index) => {\r\n if (propertiesChain.length - 1 === index) {\r\n const value = cliArgs[++i];\r\n if (!value) {\r\n log(\r\n 2,\r\n `[config] Missing value for the CLI '--${option}' argument. Using the default value.`\r\n );\r\n }\r\n obj[prop] = value || null;\r\n } else if (obj[prop] === undefined) {\r\n obj[prop] = {};\r\n }\r\n return obj[prop];\r\n }, cliOptions);\r\n }\r\n\r\n // Return parsed CLI options\r\n return cliOptions;\r\n}\r\n\r\n/**\r\n * Recursively traverses the options object to print the usage information\r\n * for each option category and individual option.\r\n *\r\n * @function _cycleCategories\r\n *\r\n * @param {Object} options - The options object containing CLI options. It may\r\n * include nested categories and individual options.\r\n */\r\nfunction _cycleCategories(options) {\r\n for (const [name, option] of Object.entries(options)) {\r\n // If the current entry is a category and not a leaf option, recurse into it\r\n if (!Object.prototype.hasOwnProperty.call(option, 'value')) {\r\n _cycleCategories(option);\r\n } else {\r\n // Prepare description\r\n const descName = ` --${option.cliName || name}`;\r\n\r\n // Get the value\r\n let optionValue = option.value;\r\n\r\n // Prepare value for option that is not null and is array of strings\r\n if (optionValue !== null && option.types.includes('string[]')) {\r\n optionValue =\r\n '[' + optionValue.map((item) => `'${item}'`).join(', ') + ']';\r\n }\r\n\r\n // Prepare value for option that is not null and is a string\r\n if (optionValue !== null && option.types.includes('string')) {\r\n optionValue = `'${optionValue}'`;\r\n }\r\n\r\n // Display correctly aligned messages\r\n console.log(\r\n descName.green,\r\n `${('<' + option.types.join('|') + '>').yellow}`,\r\n `${String(optionValue).bold}`.blue,\r\n `- ${option.description}.`\r\n );\r\n }\r\n }\r\n}\r\n\r\nexport default {\r\n getOptions,\r\n setGlobalOptions,\r\n updateOptions,\r\n mergeOptions,\r\n mapToNewOptions,\r\n validateOption,\r\n validateOptions,\r\n isAllowedConfig,\r\n printLicense,\r\n printUsage,\r\n printVersion\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * @overview HTTP utility module for fetching and posting data. Supports both\r\n * HTTP and HTTPS protocols, providing methods to make GET and POST requests\r\n * with customizable options. Includes protocol determination based on URL\r\n * and augments response objects with a 'text' property for easier data access.\r\n */\r\n\r\nimport http from 'http';\r\nimport https from 'https';\r\n\r\n/**\r\n * Fetches data from the specified URL using either HTTP or HTTPS protocol.\r\n *\r\n * @async\r\n * @function fetch\r\n *\r\n * @param {string} url - The URL to fetch data from.\r\n * @param {Object} [requestOptions={}] - Options for the HTTP/HTTPS request.\r\n * The default value is an empty object.\r\n *\r\n * @returns {Promise} A Promise that resolves to the HTTP/HTTPS response\r\n * object with added 'text' property or rejecting with an error.\r\n */\r\nexport async function fetch(url, requestOptions = {}) {\r\n return new Promise((resolve, reject) => {\r\n _getProtocolModule(url)\r\n .get(url, requestOptions, (response) => {\r\n let responseData = '';\r\n\r\n // A chunk of data has been received\r\n response.on('data', (chunk) => {\r\n responseData += chunk;\r\n });\r\n\r\n // The whole response has been received\r\n response.on('end', () => {\r\n if (!responseData) {\r\n reject('Nothing was fetched from the URL.');\r\n }\r\n response.text = responseData;\r\n resolve(response);\r\n });\r\n })\r\n .on('error', (error) => {\r\n reject(error);\r\n });\r\n });\r\n}\r\n\r\n/**\r\n * Sends a POST request to the specified URL with the provided JSON body using\r\n * either HTTP or HTTPS protocol.\r\n *\r\n * @async\r\n * @function post\r\n *\r\n * @param {string} url - The URL to send the POST request to.\r\n * @param {Object} [body={}] - The JSON body to include in the POST request.\r\n * The default value is an empty object.\r\n * @param {Object} [requestOptions={}] - Options for the HTTP/HTTPS request.\r\n * The default value is an empty object.\r\n *\r\n * @returns {Promise} A Promise that resolves to the HTTP/HTTPS response\r\n * object with added 'text' property or rejecting with an error.\r\n */\r\nexport async function post(url, body = {}, requestOptions = {}) {\r\n return new Promise((resolve, reject) => {\r\n const data = JSON.stringify(body);\r\n\r\n // Set default headers and merge with requestOptions\r\n const options = Object.assign(\r\n {\r\n method: 'POST',\r\n headers: {\r\n 'Content-Type': 'application/json',\r\n 'Content-Length': data.length\r\n }\r\n },\r\n requestOptions\r\n );\r\n\r\n const request = _getProtocolModule(url)\r\n .request(url, options, (response) => {\r\n let responseData = '';\r\n\r\n // A chunk of data has been received\r\n response.on('data', (chunk) => {\r\n responseData += chunk;\r\n });\r\n\r\n // The whole response has been received\r\n response.on('end', () => {\r\n try {\r\n response.text = responseData;\r\n resolve(response);\r\n } catch (error) {\r\n reject(error);\r\n }\r\n });\r\n })\r\n .on('error', (error) => {\r\n reject(error);\r\n });\r\n\r\n // Write the request body and end the request\r\n request.write(data);\r\n request.end();\r\n });\r\n}\r\n\r\n/**\r\n * Returns the HTTP or HTTPS protocol module based on the provided URL.\r\n *\r\n * @function _getProtocolModule\r\n *\r\n * @param {string} url - The URL to determine the protocol.\r\n *\r\n * @returns {Object} The HTTP or HTTPS protocol module (http or https).\r\n */\r\nfunction _getProtocolModule(url) {\r\n return url.startsWith('https') ? https : http;\r\n}\r\n\r\nexport default {\r\n fetch,\r\n post\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * @overview The cache manager is responsible for handling and managing\r\n * the Highcharts library along with its dependencies. It ensures that these\r\n * resources are stored and retrieved efficiently to optimize performance\r\n * and reduce redundant network requests. The cache is stored in the `.cache`\r\n * directory by default, which serves as a dedicated folder for keeping cached\r\n * files.\r\n */\r\n\r\nimport { existsSync, mkdirSync, readFileSync, writeFileSync } from 'fs';\r\nimport { join } from 'path';\r\n\r\nimport { HttpsProxyAgent } from 'https-proxy-agent';\r\n\r\nimport { getOptions } from './config.js';\r\nimport { fetch } from './fetch.js';\r\nimport { log } from './logger.js';\r\nimport { __dirname, getAbsolutePath } from './utils.js';\r\n\r\nimport ExportError from './errors/ExportError.js';\r\n\r\n// The initial cache template\r\nconst cache = {\r\n cdnUrl: 'https://code.highcharts.com',\r\n activeManifest: {},\r\n sources: '',\r\n hcVersion: ''\r\n};\r\n\r\n/**\r\n * Checks the cache for Highcharts dependencies, updates the cache if needed,\r\n * and loads the sources.\r\n *\r\n * @async\r\n * @function checkAndUpdateCache\r\n *\r\n * @param {Object} highchartsOptions - The configuration object containing\r\n * `highcharts` options.\r\n * @param {Object} serverProxyOptions- The configuration object containing\r\n * `server.proxy` options.\r\n */\r\nexport async function checkAndUpdateCache(\r\n highchartsOptions,\r\n serverProxyOptions\r\n) {\r\n try {\r\n let fetchedModules;\r\n\r\n // Get the cache path\r\n const cachePath = getCachePath();\r\n\r\n // Prepare paths to manifest and sources from the cache folder\r\n const manifestPath = join(cachePath, 'manifest.json');\r\n const sourcePath = join(cachePath, 'sources.js');\r\n\r\n // Create the cache destination if it doesn't exist already\r\n !existsSync(cachePath) && mkdirSync(cachePath, { recursive: true });\r\n\r\n // Fetch all the scripts either if the `manifest.json` does not exist\r\n // or if the `forceFetch` option is enabled\r\n if (!existsSync(manifestPath) || highchartsOptions.forceFetch) {\r\n log(3, '[cache] Fetching and caching Highcharts dependencies.');\r\n fetchedModules = await _updateCache(\r\n highchartsOptions,\r\n serverProxyOptions,\r\n sourcePath\r\n );\r\n } else {\r\n let requestUpdate = false;\r\n\r\n // Read the manifest JSON\r\n const manifest = JSON.parse(readFileSync(manifestPath), 'utf8');\r\n\r\n // Check if the modules is an array, if so, we rewrite it to a map to make\r\n // it easier to resolve modules.\r\n if (manifest.modules && Array.isArray(manifest.modules)) {\r\n const moduleMap = {};\r\n manifest.modules.forEach((m) => (moduleMap[m] = 1));\r\n manifest.modules = moduleMap;\r\n }\r\n\r\n // Get the actual number of scripts to be fetched\r\n const { coreScripts, moduleScripts, indicatorScripts } =\r\n highchartsOptions;\r\n const numberOfModules =\r\n coreScripts.length + moduleScripts.length + indicatorScripts.length;\r\n\r\n // Compare the loaded highcharts config with the contents in cache.\r\n // If there are changes, fetch requested modules and products,\r\n // and bake them into a giant blob. Save the blob.\r\n if (manifest.version !== highchartsOptions.version) {\r\n log(\r\n 2,\r\n '[cache] A Highcharts version mismatch in the cache, need to re-fetch.'\r\n );\r\n requestUpdate = true;\r\n } else if (\r\n Object.keys(manifest.modules || {}).length !== numberOfModules\r\n ) {\r\n log(\r\n 2,\r\n '[cache] The cache and the requested modules do not match, need to re-fetch.'\r\n );\r\n requestUpdate = true;\r\n } else {\r\n // Check each module, if anything is missing refetch everything\r\n requestUpdate = (moduleScripts || []).some((moduleName) => {\r\n if (!manifest.modules[moduleName]) {\r\n log(\r\n 2,\r\n `[cache] The ${moduleName} is missing in the cache, need to re-fetch.`\r\n );\r\n return true;\r\n }\r\n });\r\n }\r\n\r\n // Update cache if needed\r\n if (requestUpdate) {\r\n fetchedModules = await _updateCache(\r\n highchartsOptions,\r\n serverProxyOptions,\r\n sourcePath\r\n );\r\n } else {\r\n log(3, '[cache] Dependency cache is up to date, proceeding.');\r\n\r\n // Load the sources\r\n cache.sources = readFileSync(sourcePath, 'utf8');\r\n\r\n // Get current modules map\r\n fetchedModules = manifest.modules;\r\n\r\n // Extract and save version of currently used Highcharts\r\n cache.hcVersion = extractVersion(cache.sources);\r\n }\r\n }\r\n\r\n // Finally, save the new manifest, which is basically our current config\r\n // in a slightly different format\r\n await _saveConfigToManifest(highchartsOptions, fetchedModules);\r\n } catch (error) {\r\n throw new ExportError(\r\n '[cache] Could not configure cache and create or update the config manifest.',\r\n 500\r\n ).setError(error);\r\n }\r\n}\r\n\r\n/**\r\n * Gets the version of Highcharts from the cache.\r\n *\r\n * @function getHighchartsVersion\r\n *\r\n * @returns {string} The cached Highcharts version.\r\n */\r\nexport function getHighchartsVersion() {\r\n return cache.hcVersion;\r\n}\r\n\r\n/**\r\n * Updates the Highcharts version in the applied configuration and checks\r\n * the cache for the new version.\r\n *\r\n * @async\r\n * @function updateHighchartsVersion\r\n *\r\n * @param {string} newVersion - The new Highcharts version to be applied.\r\n */\r\nexport async function updateHighchartsVersion(newVersion) {\r\n // Get the reference to the global options to update to the new version\r\n const options = getOptions();\r\n\r\n // Set to the new version\r\n options.highcharts.version = newVersion;\r\n\r\n // Check if cache needs to be updated\r\n await checkAndUpdateCache(options.highcharts, options.server.proxy);\r\n}\r\n\r\n/**\r\n * Extracts Highcharts version from the cache's sources string.\r\n *\r\n * @function extractVersion\r\n *\r\n * @param {Object} cacheSources - The cache sources object.\r\n *\r\n * @returns {string} The extracted Highcharts version.\r\n */\r\nexport function extractVersion(cacheSources) {\r\n return cacheSources\r\n .substring(0, cacheSources.indexOf('*/'))\r\n .replace('/*', '')\r\n .replace('*/', '')\r\n .replace(/\\n/g, '')\r\n .trim();\r\n}\r\n\r\n/**\r\n * Extracts the Highcharts module name based on the scriptPath.\r\n *\r\n * @function extractModuleName\r\n *\r\n * @param {string} scriptPath - The path of the script from which the module\r\n * name will be extracted.\r\n *\r\n * @returns {string} The extracted module name.\r\n */\r\nexport function extractModuleName(scriptPath) {\r\n return scriptPath.replace(\r\n /(.*)\\/|(.*)modules\\/|stock\\/(.*)indicators\\/|maps\\/(.*)modules\\//gi,\r\n ''\r\n );\r\n}\r\n\r\n/**\r\n * Retrieves the current cache object.\r\n *\r\n * @function getCache\r\n *\r\n * @returns {Object} The cache object containing various cached data.\r\n */\r\nexport function getCache() {\r\n return cache;\r\n}\r\n\r\n/**\r\n * Gets the cache path for Highcharts.\r\n *\r\n * @function getCachePath\r\n *\r\n * @returns {string} The absolute path to the cache directory for Highcharts.\r\n */\r\nexport function getCachePath() {\r\n return getAbsolutePath(getOptions().highcharts.cachePath, 'utf8'); // #562\r\n}\r\n\r\n/**\r\n * Fetches a single script and updates the `fetchedModules` accordingly.\r\n *\r\n * @async\r\n * @function _fetchAndProcessScript\r\n *\r\n * @param {string} script - A path to script to get.\r\n * @param {Object} requestOptions - Additional options for the proxy agent\r\n * to use for a request.\r\n * @param {Object} fetchedModules - An object which tracks which Highcharts\r\n * modules have been fetched.\r\n * @param {boolean} [shouldThrowError=false] - A flag to indicate if the error\r\n * should be thrown. This should be used only for the core scripts. The default\r\n * value is `false`.\r\n *\r\n * @returns {Promise} A Promise that resolves to the text representation\r\n * of the fetched script.\r\n *\r\n * @throws {ExportError} Throws an `ExportError` if there is a problem\r\n * with fetching the script.\r\n */\r\nasync function _fetchAndProcessScript(\r\n script,\r\n requestOptions,\r\n fetchedModules,\r\n shouldThrowError = false\r\n) {\r\n // Get rid of the .js from the custom strings\r\n if (script.endsWith('.js')) {\r\n script = script.substring(0, script.length - 3);\r\n }\r\n log(4, `[cache] Fetching script - ${script}.js`);\r\n\r\n // Fetch the script\r\n const response = await fetch(`${script}.js`, requestOptions);\r\n\r\n // If OK, return its text representation\r\n if (response.statusCode === 200 && typeof response.text == 'string') {\r\n if (fetchedModules) {\r\n const moduleName = extractModuleName(script);\r\n fetchedModules[moduleName] = 1;\r\n }\r\n return response.text;\r\n }\r\n\r\n // Based on the `shouldThrowError` flag, decide how to serve error message\r\n if (shouldThrowError) {\r\n throw new ExportError(\r\n `[cache] Could not fetch the ${script}.js. The script might not exist in the requested version (status code: ${response.statusCode}).`,\r\n 404\r\n ).setError(response);\r\n } else {\r\n log(\r\n 2,\r\n `[cache] Could not fetch the ${script}.js. The script might not exist in the requested version.`\r\n );\r\n }\r\n}\r\n\r\n/**\r\n * Saves the provided configuration and fetched modules to the cache manifest\r\n * file.\r\n *\r\n * @async\r\n * @function _saveConfigToManifest\r\n *\r\n * @param {Object} highchartsOptions - The configuration object containing\r\n * `highcharts` options.\r\n * @param {Object} [fetchedModules={}] - An object which tracks which Highcharts\r\n * modules have been fetched. The default value is an empty object.\r\n *\r\n * @throws {ExportError} Throws an `ExportError` if an error occurs while\r\n * writing the cache manifest.\r\n */\r\nasync function _saveConfigToManifest(highchartsOptions, fetchedModules = {}) {\r\n const newManifest = {\r\n version: highchartsOptions.version,\r\n modules: fetchedModules\r\n };\r\n\r\n // Update cache object with the current modules\r\n cache.activeManifest = newManifest;\r\n\r\n log(3, '[cache] Writing a new manifest.');\r\n try {\r\n writeFileSync(\r\n join(getCachePath(), 'manifest.json'),\r\n JSON.stringify(newManifest),\r\n 'utf8'\r\n );\r\n } catch (error) {\r\n throw new ExportError(\r\n '[cache] Error writing the cache manifest.',\r\n 500\r\n ).setError(error);\r\n }\r\n}\r\n\r\n/**\r\n * Fetches Highcharts `scripts` and `customScripts` from the given CDNs.\r\n *\r\n * @async\r\n * @function _fetchScripts\r\n *\r\n * @param {Array.} coreScripts - Highcharts core scripts to fetch.\r\n * @param {Array.} moduleScripts - Highcharts modules to fetch.\r\n * @param {Array.} customScripts - Custom script paths to fetch (full\r\n * URLs).\r\n * @param {Object} serverProxyOptions - The configuration object containing\r\n * `server.proxy` options.\r\n * @param {Object} fetchedModules - An object which tracks which Highcharts\r\n * modules have been fetched.\r\n *\r\n * @returns {Promise} A Promise that resolves to the fetched scripts\r\n * content joined.\r\n *\r\n * @throws {ExportError} Throws an `ExportError` if an error occurs while\r\n * setting an HTTP Agent for proxy.\r\n */\r\nasync function _fetchScripts(\r\n coreScripts,\r\n moduleScripts,\r\n customScripts,\r\n serverProxyOptions,\r\n fetchedModules\r\n) {\r\n // Configure proxy if exists\r\n let proxyAgent;\r\n const proxyHost = serverProxyOptions.host;\r\n const proxyPort = serverProxyOptions.port;\r\n\r\n // Try to create a Proxy Agent\r\n if (proxyHost && proxyPort) {\r\n try {\r\n proxyAgent = new HttpsProxyAgent({\r\n host: proxyHost,\r\n port: proxyPort\r\n });\r\n } catch (error) {\r\n throw new ExportError(\r\n '[cache] Could not create a Proxy Agent.',\r\n 500\r\n ).setError(error);\r\n }\r\n }\r\n\r\n // If exists, add proxy agent to request options\r\n const requestOptions = proxyAgent\r\n ? {\r\n agent: proxyAgent,\r\n timeout: serverProxyOptions.timeout\r\n }\r\n : {};\r\n\r\n const allFetchPromises = [\r\n ...coreScripts.map((script) =>\r\n _fetchAndProcessScript(`${script}`, requestOptions, fetchedModules, true)\r\n ),\r\n ...moduleScripts.map((script) =>\r\n _fetchAndProcessScript(`${script}`, requestOptions, fetchedModules)\r\n ),\r\n ...customScripts.map((script) =>\r\n _fetchAndProcessScript(`${script}`, requestOptions)\r\n )\r\n ];\r\n\r\n const fetchedScripts = await Promise.all(allFetchPromises);\r\n return fetchedScripts.join(';\\n');\r\n}\r\n\r\n/**\r\n * Updates the local cache with Highcharts scripts and their versions.\r\n *\r\n * @async\r\n * @function _updateCache\r\n *\r\n * @param {Object} highchartsOptions - The configuration object containing\r\n * `highcharts` options.\r\n * @param {Object} serverProxyOptions - The configuration object containing\r\n * `server.proxy` options.\r\n * @param {string} sourcePath - The path to the source file in the cache.\r\n *\r\n * @returns {Promise} A Promise that resolves to an object representing\r\n * the fetched modules.\r\n *\r\n * @throws {ExportError} Throws an `ExportError` if there is an issue updating\r\n * the local Highcharts cache.\r\n */\r\nasync function _updateCache(highchartsOptions, serverProxyOptions, sourcePath) {\r\n // Get Highcharts version for scripts\r\n const hcVersion =\r\n highchartsOptions.version === 'latest'\r\n ? null\r\n : `${highchartsOptions.version}`;\r\n\r\n // Get the CDN url for scripts\r\n const cdnUrl = highchartsOptions.cdnUrl || cache.cdnUrl;\r\n\r\n try {\r\n const fetchedModules = {};\r\n\r\n log(\r\n 3,\r\n `[cache] Updating cache version to Highcharts: ${hcVersion || 'latest'}.`\r\n );\r\n\r\n cache.sources = await _fetchScripts(\r\n [\r\n ...highchartsOptions.coreScripts.map((c) =>\r\n hcVersion ? `${cdnUrl}/${hcVersion}/${c}` : `${cdnUrl}/${c}`\r\n )\r\n ],\r\n [\r\n ...highchartsOptions.moduleScripts.map((m) =>\r\n m === 'map'\r\n ? hcVersion\r\n ? `${cdnUrl}/maps/${hcVersion}/modules/${m}`\r\n : `${cdnUrl}/maps/modules/${m}`\r\n : hcVersion\r\n ? `${cdnUrl}/${hcVersion}/modules/${m}`\r\n : `${cdnUrl}/modules/${m}`\r\n ),\r\n ...highchartsOptions.indicatorScripts.map((i) =>\r\n hcVersion\r\n ? `${cdnUrl}/stock/${hcVersion}/indicators/${i}`\r\n : `${cdnUrl}/stock/indicators/${i}`\r\n )\r\n ],\r\n highchartsOptions.customScripts,\r\n serverProxyOptions,\r\n fetchedModules\r\n );\r\n\r\n // Extract and save version of currently used Highcharts\r\n cache.hcVersion = extractVersion(cache.sources);\r\n\r\n // Save the fetched modules into caches' source JSON\r\n writeFileSync(sourcePath, cache.sources);\r\n return fetchedModules;\r\n } catch (error) {\r\n throw new ExportError(\r\n '[cache] Unable to update the local Highcharts cache.',\r\n 500\r\n ).setError(error);\r\n }\r\n}\r\n\r\nexport default {\r\n checkAndUpdateCache,\r\n getHighchartsVersion,\r\n updateHighchartsVersion,\r\n extractVersion,\r\n extractModuleName,\r\n getCache,\r\n getCachePath\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * @overview Provides methods for initializing Highcharts with customized\r\n * animation settings and triggering the creation of Highcharts charts with\r\n * export-specific configurations in the page context. Supports dynamic option\r\n * merging, custom logic injection, and control over rendering behaviors. Used\r\n * by the Puppeteer page.\r\n */\r\n\r\n/* eslint-disable no-undef */\r\n\r\n/**\r\n * Setting the `Highcharts.animObject` function. Called when initing the page.\r\n *\r\n * @function setupHighcharts\r\n */\r\nexport function setupHighcharts() {\r\n Highcharts.animObject = function () {\r\n return { duration: 0 };\r\n };\r\n}\r\n\r\n/**\r\n * Creates the actual Highcharts chart on a page.\r\n *\r\n * @async\r\n * @function createChart\r\n *\r\n * @param {Object} exportOptions - The configuration object containing `export`\r\n * options.\r\n * @param {Object} customLogicOptions - The configuration object containing\r\n * `customLogic` options.\r\n *\r\n */\r\nexport async function createChart(exportOptions, customLogicOptions) {\r\n // Get required functions\r\n const { getOptions, setOptions, merge, wrap } = Highcharts;\r\n\r\n // Create a separate object for a potential `setOptions` usages in order\r\n // to prevent from polluting other exports that can happen on the same page\r\n Highcharts.setOptionsObj = merge(false, {}, getOptions());\r\n\r\n // NOTE: Is this used for anything useful?\r\n window.isRenderComplete = false;\r\n wrap(Highcharts.Chart.prototype, 'init', function (proceed, userOptions, cb) {\r\n // Override the `userOptions` with image friendly options\r\n userOptions = merge(userOptions, {\r\n exporting: {\r\n enabled: false\r\n },\r\n plotOptions: {\r\n series: {\r\n label: {\r\n enabled: false\r\n }\r\n }\r\n },\r\n /* Expects tooltip in the `userOptions` when `forExport` is true.\r\n https://github.com/highcharts/highcharts/blob/3ad430a353b8056b9e764aa4e5cd6828aa479db2/js/parts/Chart.js#L241\r\n */\r\n tooltip: {}\r\n });\r\n\r\n (userOptions.series || []).forEach(function (series) {\r\n series.animation = false;\r\n });\r\n\r\n // Add flag to know if chart render has been called.\r\n if (!window.onHighchartsRender) {\r\n window.onHighchartsRender = Highcharts.addEvent(this, 'render', () => {\r\n window.isRenderComplete = true;\r\n });\r\n }\r\n\r\n proceed.apply(this, [userOptions, cb]);\r\n });\r\n\r\n wrap(Highcharts.Series.prototype, 'init', function (proceed, chart, options) {\r\n proceed.apply(this, [chart, options]);\r\n });\r\n\r\n // Some mandatory additional `chart` and `exporting` options\r\n const additionalOptions = {\r\n chart: {\r\n // By default animation is disabled\r\n animation: false,\r\n // Get the right size values\r\n height: exportOptions.height,\r\n width: exportOptions.width\r\n },\r\n exporting: {\r\n // No need for the exporting button\r\n enabled: false\r\n }\r\n };\r\n\r\n // Get the input to export from the `instr` option\r\n const userOptions = new Function(`return ${exportOptions.instr}`)();\r\n\r\n // Get the `themeOptions` option\r\n const themeOptions = new Function(`return ${exportOptions.themeOptions}`)();\r\n\r\n // Get the `globalOptions` option\r\n const globalOptions = new Function(`return ${exportOptions.globalOptions}`)();\r\n\r\n // Merge the following options objects to create final options\r\n const finalOptions = merge(\r\n false,\r\n themeOptions,\r\n userOptions,\r\n // Placed it here instead in the init because of the size issues\r\n additionalOptions\r\n );\r\n\r\n // Prepare the `callback` option\r\n const finalCallback = customLogicOptions.callback\r\n ? new Function(`return ${customLogicOptions.callback}`)()\r\n : null;\r\n\r\n // Trigger the `customCode` option\r\n if (customLogicOptions.customCode) {\r\n new Function('options', customLogicOptions.customCode)(userOptions);\r\n }\r\n\r\n // Set the global options if exist\r\n if (globalOptions) {\r\n setOptions(globalOptions);\r\n }\r\n\r\n // Call the chart creation\r\n Highcharts[exportOptions.constr]('container', finalOptions, finalCallback);\r\n\r\n // Get the current global options\r\n const defaultOptions = getOptions();\r\n\r\n // Clear it just in case (e.g. the `setOptions` was used in the `customCode`)\r\n for (const prop in defaultOptions) {\r\n if (typeof defaultOptions[prop] !== 'function') {\r\n delete defaultOptions[prop];\r\n }\r\n }\r\n\r\n // Set the default options back\r\n setOptions(Highcharts.setOptionsObj);\r\n\r\n // Empty the custom global options object\r\n Highcharts.setOptionsObj = {};\r\n}\r\n\r\nexport default {\r\n setupHighcharts,\r\n createChart\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * @overview This module provides functions for managing Puppeteer browser\r\n * instance, creating and clearing pages, injecting custom resources,\r\n * and setting up Highcharts for server-side rendering. The module ensures\r\n * that resources are correctly managed and can handle failures during\r\n * operations like launching the browser or creating new pages.\r\n */\r\n\r\nimport { readFileSync } from 'fs';\r\nimport { join } from 'path';\r\n\r\nimport puppeteer from 'puppeteer';\r\n\r\nimport { getCachePath } from './cache.js';\r\nimport { getOptions } from './config.js';\r\nimport { setupHighcharts } from './highcharts.js';\r\nimport { log, logWithStack } from './logger.js';\r\nimport { __dirname, getAbsolutePath } from './utils.js';\r\n\r\nimport ExportError from './errors/ExportError.js';\r\n\r\n// Get the template for pages\r\nconst template = readFileSync(\r\n join(__dirname, 'templates', 'template.html'),\r\n 'utf8'\r\n);\r\n\r\n// To save the browser\r\nlet browser = null;\r\n\r\n/**\r\n * Retrieves the existing Puppeteer browser instance.\r\n *\r\n * @function getBrowser\r\n *\r\n * @returns {Object} The Puppeteer browser instance.\r\n *\r\n * @throws {ExportError} Throws an `ExportError` if no valid browser\r\n * has been created.\r\n */\r\nexport function getBrowser() {\r\n if (!browser) {\r\n throw new ExportError('[browser] No valid browser has been created.', 500);\r\n }\r\n return browser;\r\n}\r\n\r\n/**\r\n * Creates a Puppeteer browser instance with the specified arguments.\r\n *\r\n * @async\r\n * @function createBrowser\r\n *\r\n * @param {Array.} puppeteerArgs - Additional arguments for Puppeteer\r\n * launch.\r\n *\r\n * @returns {Promise} A Promise that resolves to the created Puppeteer\r\n * browser instance.\r\n *\r\n * @throws {ExportError} Throws an `ExportError` if max retries to open\r\n * a browser instance are reached, or if no browser instance is found after\r\n * retries.\r\n */\r\nexport async function createBrowser(puppeteerArgs) {\r\n // Get `debug` and `other` options\r\n const { debug, other } = getOptions();\r\n\r\n // Get the `debug` options\r\n const { enable: enabledDebug, ...debugOptions } = debug;\r\n\r\n // Launch options for the browser instance\r\n const launchOptions = {\r\n headless: other.browserShellMode ? 'shell' : true,\r\n userDataDir: 'tmp',\r\n args: puppeteerArgs || [],\r\n handleSIGINT: false,\r\n handleSIGTERM: false,\r\n handleSIGHUP: false,\r\n waitForInitialPage: false,\r\n defaultViewport: null,\r\n ...(enabledDebug && debugOptions)\r\n };\r\n\r\n // Create a browser\r\n if (!browser) {\r\n // A counter for the browser's launch retries\r\n let tryCount = 0;\r\n\r\n const open = async () => {\r\n try {\r\n log(\r\n 3,\r\n `[browser] Attempting to get a browser instance (try ${++tryCount}).`\r\n );\r\n\r\n // Launch the browser\r\n browser = await puppeteer.launch(launchOptions);\r\n } catch (error) {\r\n logWithStack(\r\n 1,\r\n error,\r\n '[browser] Failed to launch a browser instance.'\r\n );\r\n\r\n // Retry to launch browser until reaching max attempts\r\n if (tryCount < 25) {\r\n log(3, `[browser] Retry to open a browser (${tryCount} out of 25).`);\r\n\r\n // Wait for a 4 seconds before trying again\r\n await new Promise((response) => setTimeout(response, 4000));\r\n await open();\r\n } else {\r\n throw error;\r\n }\r\n }\r\n };\r\n\r\n try {\r\n await open();\r\n\r\n // Shell mode inform\r\n if (launchOptions.headless === 'shell') {\r\n log(3, `[browser] Launched browser in shell mode.`);\r\n }\r\n\r\n // Debug mode inform\r\n if (enabledDebug) {\r\n log(3, `[browser] Launched browser in debug mode.`);\r\n }\r\n } catch (error) {\r\n throw new ExportError(\r\n '[browser] Maximum retries to open a browser instance reached.',\r\n 500\r\n ).setError(error);\r\n }\r\n\r\n if (!browser) {\r\n throw new ExportError('[browser] Cannot find a browser to open.', 500);\r\n }\r\n }\r\n\r\n // Return a browser instance\r\n return browser;\r\n}\r\n\r\n/**\r\n * Closes the Puppeteer browser instance if it is connected.\r\n *\r\n * @async\r\n * @function closeBrowser\r\n */\r\nexport async function closeBrowser() {\r\n // Close the browser when connected\r\n if (browser && browser.connected) {\r\n await browser.close();\r\n }\r\n browser = null;\r\n log(4, '[browser] Closed the browser.');\r\n}\r\n\r\n/**\r\n * Creates a new Puppeteer page within an existing browser instance.\r\n * The function creates a new page, disables caching, sets content using\r\n * the `_setPageContent()`, and returns the created Puppeteer page.\r\n *\r\n * @async\r\n * @function newPage\r\n *\r\n * @param {Object} poolResource - The pool resource that contains `id`,\r\n * `workCount`, and `page`.\r\n *\r\n * @throws {ExportError} Throws an `ExportError` if no valid browser\r\n * has been connected or if a page is invalid or closed.\r\n */\r\nexport async function newPage(poolResource) {\r\n // Error in case of no connected browser\r\n if (!browser || !browser.connected) {\r\n throw new ExportError(`[browser] Browser is not yet connected.`, 500);\r\n }\r\n\r\n // Create a page\r\n poolResource.page = await browser.newPage();\r\n\r\n // Disable cache\r\n await poolResource.page.setCacheEnabled(false);\r\n\r\n // Set the content\r\n await _setPageContent(poolResource.page);\r\n\r\n // Set page events\r\n _setPageEvents(poolResource.page);\r\n\r\n // Check if the page is correctly created\r\n if (!poolResource.page || poolResource.page.isClosed()) {\r\n throw new ExportError('[browser] The page is invalid or closed.', 400);\r\n }\r\n}\r\n\r\n/**\r\n * Clears the content of a Puppeteer Page based on the specified mode. Logs\r\n * thrown error if clearing of a page's content fails.\r\n *\r\n * @async\r\n * @function clearPage\r\n *\r\n * @param {Object} poolResource - The pool resource that contains page and id.\r\n * @param {boolean} [hardReset=false] - A flag indicating the type of clearing\r\n * to be performed. If true, navigates to `about:blank` and resets content\r\n * and scripts. If false, clears the body content by setting a predefined HTML\r\n * structure. The default value is `false`.\r\n *\r\n * @returns {Promise} A Promise that resolves to true when page\r\n * is correctly cleared and false when it is not.\r\n */\r\nexport async function clearPage(poolResource, hardReset = false) {\r\n try {\r\n if (poolResource.page && !poolResource.page.isClosed()) {\r\n if (hardReset) {\r\n // Navigate to `about:blank`\r\n await poolResource.page.goto('about:blank', {\r\n waitUntil: 'domcontentloaded'\r\n });\r\n\r\n // Set the content and and scripts again\r\n await _setPageContent(poolResource.page);\r\n } else {\r\n // Clear body content\r\n await poolResource.page.evaluate(() => {\r\n document.body.innerHTML =\r\n '
';\r\n });\r\n }\r\n return true;\r\n }\r\n } catch (error) {\r\n logWithStack(\r\n 2,\r\n error,\r\n `[pool] Pool resource [${poolResource.id}] - Content of the page could not be cleared.`\r\n );\r\n\r\n // Set the `workLimit` to exceeded in order to recreate the resource\r\n poolResource.workCount = getOptions().pool.workLimit + 1;\r\n }\r\n return false;\r\n}\r\n\r\n/**\r\n * Adds custom JS and CSS resources to a Puppeteer Page based on the specified\r\n * options.\r\n *\r\n * @async\r\n * @function addPageResources\r\n *\r\n * @param {Object} page - The Puppeteer page object to which resources will\r\n * be added.\r\n * @param {Object} customLogicOptions - The configuration object containing\r\n * `customLogic` options.\r\n *\r\n * @returns {Promise>} A Promise that resolves to an array\r\n * of injected resources.\r\n */\r\nexport async function addPageResources(page, customLogicOptions) {\r\n // Injected resources array\r\n const injectedResources = [];\r\n\r\n // Use resources\r\n const resources = customLogicOptions.resources;\r\n if (resources) {\r\n const injectedJs = [];\r\n\r\n // Load custom JS code\r\n if (resources.js) {\r\n injectedJs.push({\r\n content: resources.js\r\n });\r\n }\r\n\r\n // Load scripts from all custom files\r\n if (resources.files) {\r\n for (const file of resources.files) {\r\n const isLocal = !file.startsWith('http') ? true : false;\r\n\r\n // Add each custom script from resources' files\r\n injectedJs.push(\r\n isLocal\r\n ? {\r\n content: readFileSync(getAbsolutePath(file), 'utf8')\r\n }\r\n : {\r\n url: file\r\n }\r\n );\r\n }\r\n }\r\n\r\n for (const jsResource of injectedJs) {\r\n try {\r\n injectedResources.push(await page.addScriptTag(jsResource));\r\n } catch (error) {\r\n logWithStack(2, error, `[browser] The JS resource cannot be loaded.`);\r\n }\r\n }\r\n injectedJs.length = 0;\r\n\r\n // Load CSS\r\n const injectedCss = [];\r\n if (resources.css) {\r\n let cssImports = resources.css.match(/@import\\s*([^;]*);/g);\r\n if (cssImports) {\r\n // Handle css section\r\n for (let cssImportPath of cssImports) {\r\n if (cssImportPath) {\r\n cssImportPath = cssImportPath\r\n .replace('url(', '')\r\n .replace('@import', '')\r\n .replace(/\"/g, '')\r\n .replace(/'/g, '')\r\n .replace(/;/, '')\r\n .replace(/\\)/g, '')\r\n .trim();\r\n\r\n // Add each custom css from resources\r\n if (cssImportPath.startsWith('http')) {\r\n injectedCss.push({\r\n url: cssImportPath\r\n });\r\n } else if (customLogicOptions.allowFileResources) {\r\n injectedCss.push({\r\n path: join(__dirname, cssImportPath)\r\n });\r\n }\r\n }\r\n }\r\n }\r\n\r\n // The rest of the CSS section will be content by now\r\n injectedCss.push({\r\n content: resources.css.replace(/@import\\s*([^;]*);/g, '') || ' '\r\n });\r\n\r\n for (const cssResource of injectedCss) {\r\n try {\r\n injectedResources.push(await page.addStyleTag(cssResource));\r\n } catch (error) {\r\n logWithStack(\r\n 2,\r\n error,\r\n `[browser] The CSS resource cannot be loaded.`\r\n );\r\n }\r\n }\r\n injectedCss.length = 0;\r\n }\r\n }\r\n return injectedResources;\r\n}\r\n\r\n/**\r\n * Clears out all state set on the page with `addScriptTag` and `addStyleTag`.\r\n * Removes injected resources and resets CSS and script tags on the page.\r\n * Additionally, it destroys previously existing charts.\r\n *\r\n * @async\r\n * @function clearPageResources\r\n *\r\n * @param {Object} page - The Puppeteer page object from which resources will\r\n * be cleared.\r\n * @param {Array.} injectedResources - Array of injected resources\r\n * to be cleared.\r\n */\r\nexport async function clearPageResources(page, injectedResources) {\r\n try {\r\n for (const resource of injectedResources) {\r\n await resource.dispose();\r\n }\r\n\r\n // Destroy old charts after export is done and reset all CSS and script tags\r\n await page.evaluate(() => {\r\n // We are not guaranteed that Highcharts is loaded, when doing SVG exports\r\n if (typeof Highcharts !== 'undefined') {\r\n // eslint-disable-next-line no-undef\r\n const oldCharts = Highcharts.charts;\r\n\r\n // Check in any already existing charts\r\n if (Array.isArray(oldCharts) && oldCharts.length) {\r\n // Destroy old charts\r\n for (const oldChart of oldCharts) {\r\n oldChart && oldChart.destroy();\r\n // eslint-disable-next-line no-undef\r\n Highcharts.charts.shift();\r\n }\r\n }\r\n }\r\n\r\n // eslint-disable-next-line no-undef\r\n const [...scriptsToRemove] = document.getElementsByTagName('script');\r\n // eslint-disable-next-line no-undef\r\n const [, ...stylesToRemove] = document.getElementsByTagName('style');\r\n // eslint-disable-next-line no-undef\r\n const [...linksToRemove] = document.getElementsByTagName('link');\r\n\r\n // Remove tags\r\n for (const element of [\r\n ...scriptsToRemove,\r\n ...stylesToRemove,\r\n ...linksToRemove\r\n ]) {\r\n element.remove();\r\n }\r\n });\r\n } catch (error) {\r\n logWithStack(2, error, `[browser] Could not clear page's resources.`);\r\n }\r\n}\r\n\r\n/**\r\n * Sets the content for a Puppeteer Page using a predefined template\r\n * and additional scripts.\r\n *\r\n * @async\r\n * @function _setPageContent\r\n *\r\n * @param {Object} page - The Puppeteer page object to which the content\r\n * is being set.\r\n */\r\nasync function _setPageContent(page) {\r\n // Set the initial page content\r\n await page.setContent(template, { waitUntil: 'domcontentloaded' });\r\n\r\n // Add all registered Higcharts scripts, quite demanding\r\n await page.addScriptTag({ path: join(getCachePath(), 'sources.js') });\r\n\r\n // Set the initial `animObject` for Highcharts\r\n await page.evaluate(setupHighcharts);\r\n}\r\n\r\n/**\r\n * Set events (like `pageerror` and `console`) for a Puppeteer Page in order\r\n * to catch and display errors and console logs from the window context.\r\n *\r\n * @function _setPageEvents\r\n *\r\n * @param {Object} page - The Puppeteer page object to which the listeners\r\n * are being set.\r\n */\r\nfunction _setPageEvents(page) {\r\n // Get `debug` options\r\n const { debug } = getOptions();\r\n\r\n // Set the `pageerror` listener\r\n page.on('pageerror', async () => {\r\n // It would seem like this may fire at the same time or shortly before\r\n // a page is closed.\r\n if (page.isClosed()) {\r\n return;\r\n }\r\n });\r\n\r\n // Set the `console` listener, if needed\r\n if (debug.enable && debug.listenToConsole) {\r\n page.on('console', (message) => {\r\n console.log(`[debug] ${message.text()}`);\r\n });\r\n }\r\n}\r\n\r\nexport default {\r\n getBrowser,\r\n createBrowser,\r\n closeBrowser,\r\n newPage,\r\n clearPage,\r\n addPageResources,\r\n clearPageResources\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * The CSS to be used on the exported page.\r\n *\r\n * @returns {string} The CSS configuration.\r\n */\r\nexport default () => `\r\n\r\nhtml, body {\r\n margin: 0;\r\n padding: 0;\r\n box-sizing: border-box;\r\n}\r\n\r\n#table-div, #sliders, #datatable, #controls, .ld-row {\r\n display: none;\r\n height: 0;\r\n}\r\n\r\n#chart-container {\r\n box-sizing: border-box;\r\n margin: 0;\r\n overflow: auto;\r\n font-size: 0;\r\n}\r\n\r\n#chart-container > figure, div {\r\n margin-top: 0 !important;\r\n margin-bottom: 0 !important;\r\n}\r\n\r\n`;\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\nimport cssTemplate from './css.js';\r\n\r\n/**\r\n * The SVG template to use when loading SVG content to be exported.\r\n *\r\n * @param {string} svg - The SVG input content to be exported.\r\n *\r\n * @returns {string} The SVG template.\r\n */\r\nexport default (svg) => `\r\n\r\n\r\n \r\n \r\n Highcharts Export\r\n \r\n \r\n \r\n
\r\n ${svg}\r\n
\r\n \r\n\r\n\r\n`;\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * @overview This module handles chart export functionality using Puppeteer.\r\n * It supports exporting charts as SVG, PNG, JPEG, and PDF formats. The module\r\n * manages page resources, sets up the export environment, and processes chart\r\n * configurations or SVG inputs for rendering. Exports to a chart from a page\r\n * using Puppeteer.\r\n */\r\n\r\nimport { addPageResources, clearPageResources } from './browser.js';\r\nimport { createChart } from './highcharts.js';\r\nimport { log } from './logger.js';\r\n\r\nimport svgTemplate from '../templates/svgExport/svgExport.js';\r\n\r\nimport ExportError from './errors/ExportError.js';\r\n\r\n/**\r\n * Exports to a chart from a page using Puppeteer.\r\n *\r\n * @async\r\n * @function puppeteerExport\r\n *\r\n * @param {Object} page - Puppeteer page object.\r\n * @param {Object} exportOptions - The configuration object containing `export`\r\n * options.\r\n * @param {Object} customLogicOptions - The configuration object containing\r\n * `customLogic` options.\r\n *\r\n * @returns {Promise<(string|Buffer|ExportError)>} A Promise that resolves\r\n * to the exported data or rejecting with an `ExportError`.\r\n *\r\n * @throws {ExportError} Throws an `ExportError` if export to an unsupported\r\n * output format occurs.\r\n */\r\nexport async function puppeteerExport(page, exportOptions, customLogicOptions) {\r\n // Injected resources array (additional JS and CSS)\r\n const injectedResources = [];\r\n\r\n try {\r\n let isSVG = false;\r\n\r\n // Decide on the export method\r\n if (exportOptions.svg) {\r\n log(4, '[export] Treating as SVG input.');\r\n\r\n // If the `type` is also SVG, return the input\r\n if (exportOptions.type === 'svg') {\r\n return exportOptions.svg;\r\n }\r\n\r\n // Mark as SVG export for the later size corrections\r\n isSVG = true;\r\n\r\n // SVG export\r\n await page.setContent(svgTemplate(exportOptions.svg), {\r\n waitUntil: 'domcontentloaded'\r\n });\r\n } else {\r\n log(4, '[export] Treating as JSON config.');\r\n\r\n // Options export\r\n await page.evaluate(createChart, exportOptions, customLogicOptions);\r\n }\r\n\r\n // Keeps track of all resources added on the page with addXXXTag. etc\r\n // It's VITAL that all added resources ends up here so we can clear things\r\n // out when doing a new export in the same page!\r\n injectedResources.push(\r\n ...(await addPageResources(page, customLogicOptions))\r\n );\r\n\r\n // Get the real chart size and set the zoom accordingly\r\n const size = isSVG\r\n ? await page.evaluate((scale) => {\r\n const svgElement = document.querySelector(\r\n '#chart-container svg:first-of-type'\r\n );\r\n\r\n // Get the values correctly scaled\r\n const chartHeight = svgElement.height.baseVal.value * scale;\r\n const chartWidth = svgElement.width.baseVal.value * scale;\r\n\r\n // In case of SVG the zoom must be set directly for body as scale\r\n // eslint-disable-next-line no-undef\r\n document.body.style.zoom = scale;\r\n\r\n // Set the margin to 0px\r\n // eslint-disable-next-line no-undef\r\n document.body.style.margin = '0px';\r\n\r\n return {\r\n chartHeight,\r\n chartWidth\r\n };\r\n }, parseFloat(exportOptions.scale))\r\n : await page.evaluate(() => {\r\n // eslint-disable-next-line no-undef\r\n const { chartHeight, chartWidth } = window.Highcharts.charts[0];\r\n\r\n // No need for such scale manipulation in case of other types\r\n // of exports. Reset the zoom for other exports than to SVGs\r\n // eslint-disable-next-line no-undef\r\n document.body.style.zoom = 1;\r\n\r\n return {\r\n chartHeight,\r\n chartWidth\r\n };\r\n });\r\n\r\n // Get the clip region for the page\r\n const { x, y } = await _getClipRegion(page);\r\n\r\n // Set final `height` for viewport\r\n const viewportHeight = Math.abs(\r\n Math.ceil(size.chartHeight || exportOptions.height)\r\n );\r\n\r\n // Set final `width` for viewport\r\n const viewportWidth = Math.abs(\r\n Math.ceil(size.chartWidth || exportOptions.width)\r\n );\r\n\r\n // Set the final viewport now that we have the real height\r\n await page.setViewport({\r\n height: viewportHeight,\r\n width: viewportWidth,\r\n deviceScaleFactor: isSVG ? 1 : parseFloat(exportOptions.scale)\r\n });\r\n\r\n let result;\r\n // Rasterization process\r\n switch (exportOptions.type) {\r\n case 'svg':\r\n result = await _createSVG(page);\r\n break;\r\n case 'png':\r\n case 'jpeg':\r\n result = await _createImage(\r\n page,\r\n exportOptions.type,\r\n {\r\n width: viewportWidth,\r\n height: viewportHeight,\r\n x,\r\n y\r\n },\r\n exportOptions.rasterizationTimeout\r\n );\r\n break;\r\n case 'pdf':\r\n result = await _createPDF(\r\n page,\r\n viewportHeight,\r\n viewportWidth,\r\n exportOptions.rasterizationTimeout\r\n );\r\n break;\r\n default:\r\n throw new ExportError(\r\n `[export] Unsupported output format: ${exportOptions.type}.`,\r\n 400\r\n );\r\n }\r\n\r\n // Clear previously injected JS and CSS resources\r\n await clearPageResources(page, injectedResources);\r\n return result;\r\n } catch (error) {\r\n await clearPageResources(page, injectedResources);\r\n return error;\r\n }\r\n}\r\n\r\n/**\r\n * Retrieves the clipping region coordinates of the specified page element\r\n * with the 'chart-container' id.\r\n *\r\n * @async\r\n * @function _getClipRegion\r\n *\r\n * @param {Object} page - Puppeteer page object.\r\n *\r\n * @returns {Promise} A Promise that resolves to an object containing\r\n * `x`, `y`, `width`, and `height` properties.\r\n */\r\nasync function _getClipRegion(page) {\r\n return page.$eval('#chart-container', (element) => {\r\n const { x, y, width, height } = element.getBoundingClientRect();\r\n return {\r\n x,\r\n y,\r\n width,\r\n height: Math.trunc(height > 1 ? height : 500)\r\n };\r\n });\r\n}\r\n\r\n/**\r\n * Creates an SVG by evaluating the `outerHTML` of the first 'svg' element\r\n * inside an element with the id 'container'.\r\n *\r\n * @async\r\n * @function _createSVG\r\n *\r\n * @param {Object} page - Puppeteer page object.\r\n *\r\n * @returns {Promise} A Promise that resolves to the SVG string.\r\n */\r\nasync function _createSVG(page) {\r\n return page.$eval(\r\n '#container svg:first-of-type',\r\n (element) => element.outerHTML\r\n );\r\n}\r\n\r\n/**\r\n * Creates an image using Puppeteer's page `screenshot` functionality with\r\n * specified options.\r\n *\r\n * @async\r\n * @function _createImage\r\n *\r\n * @param {Object} page - Puppeteer page object.\r\n * @param {string} type - Image type.\r\n * @param {Object} clip - Clipping region coordinates.\r\n * @param {number} rasterizationTimeout - Timeout for rasterization\r\n * in milliseconds.\r\n *\r\n * @returns {Promise} A Promise that resolves to the image buffer\r\n * or rejecting with an `ExportError` for timeout.\r\n */\r\nasync function _createImage(page, type, clip, rasterizationTimeout) {\r\n return Promise.race([\r\n page.screenshot({\r\n type,\r\n clip,\r\n encoding: 'base64',\r\n fullPage: false,\r\n optimizeForSpeed: true,\r\n captureBeyondViewport: true,\r\n ...(type !== 'png' ? { quality: 80 } : {}),\r\n // Always render on a transparent page if the expected type format is PNG\r\n omitBackground: type == 'png' // #447, #463\r\n }),\r\n new Promise((_resolve, reject) =>\r\n setTimeout(\r\n () => reject(new ExportError('Rasterization timeout', 408)),\r\n rasterizationTimeout || 1500\r\n )\r\n )\r\n ]);\r\n}\r\n\r\n/**\r\n * Creates a PDF using Puppeteer's page `pdf` functionality with specified\r\n * options.\r\n *\r\n * @async\r\n * @function _createPDF\r\n *\r\n * @param {Object} page - Puppeteer page object.\r\n * @param {number} height - PDF height.\r\n * @param {number} width - PDF width.\r\n * @param {number} rasterizationTimeout - Timeout for rasterization\r\n * in milliseconds.\r\n *\r\n * @returns {Promise} A Promise that resolves to the PDF buffer.\r\n */\r\nasync function _createPDF(page, height, width, rasterizationTimeout) {\r\n await page.emulateMediaType('screen');\r\n return page.pdf({\r\n // This will remove an extra empty page in PDF exports\r\n height: height + 1,\r\n width,\r\n encoding: 'base64',\r\n timeout: rasterizationTimeout || 1500\r\n });\r\n}\r\n\r\nexport default {\r\n puppeteerExport\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * @overview This module provides a worker pool implementation for managing\r\n * the browser instance and pages, specifically designed for use with\r\n * the Highcharts Export Server. It optimizes resources usage and performance\r\n * by maintaining a pool of workers that can handle concurrent export tasks\r\n * using Puppeteer.\r\n */\r\n\r\nimport { Pool } from 'tarn';\r\nimport { v4 as uuid } from 'uuid';\r\n\r\nimport { createBrowser, closeBrowser, newPage, clearPage } from './browser.js';\r\nimport { puppeteerExport } from './export.js';\r\nimport { log, logWithStack } from './logger.js';\r\nimport { getNewDateTime, measureTime } from './utils.js';\r\n\r\nimport ExportError from './errors/ExportError.js';\r\n\r\n// The pool instance\r\nlet pool = null;\r\n\r\n// Pool statistics\r\nconst poolStats = {\r\n exportsAttempted: 0,\r\n exportsPerformed: 0,\r\n exportsDropped: 0,\r\n exportsFromSvg: 0,\r\n exportsFromOptions: 0,\r\n exportsFromSvgAttempts: 0,\r\n exportsFromOptionsAttempts: 0,\r\n timeSpent: 0,\r\n timeSpentAverage: 0\r\n};\r\n\r\n/**\r\n * Initializes the export pool with the provided configuration, creating\r\n * a browser instance and setting up worker resources.\r\n *\r\n * @async\r\n * @function initPool\r\n *\r\n * @param {Object} poolOptions - The configuration object containing `pool`\r\n * options.\r\n * @param {Array.} puppeteerArgs - Additional arguments for Puppeteer\r\n * launch.\r\n *\r\n * @returns {Promise} A Promise that resolves to ending the function\r\n * execution when an already initialized pool of resources is found.\r\n *\r\n * @throws {ExportError} Throws an `ExportError` if could not create the pool\r\n * of workers.\r\n */\r\nexport async function initPool(poolOptions, puppeteerArgs) {\r\n // Create a browser instance with the puppeteer arguments\r\n await createBrowser(puppeteerArgs);\r\n\r\n try {\r\n log(\r\n 3,\r\n `[pool] Initializing pool with workers: min ${poolOptions.minWorkers}, max ${poolOptions.maxWorkers}.`\r\n );\r\n\r\n if (pool) {\r\n log(\r\n 4,\r\n '[pool] Already initialized, please kill it before creating a new one.'\r\n );\r\n return;\r\n }\r\n\r\n // Keep an eye on a correct min and max workers number\r\n if (poolOptions.minWorkers > poolOptions.maxWorkers) {\r\n poolOptions.minWorkers = poolOptions.maxWorkers;\r\n }\r\n\r\n // Create a pool along with a minimal number of resources\r\n pool = new Pool({\r\n // Get the `create`, `validate`, and `destroy` functions\r\n ..._factory(poolOptions),\r\n min: poolOptions.minWorkers,\r\n max: poolOptions.maxWorkers,\r\n acquireTimeoutMillis: poolOptions.acquireTimeout,\r\n createTimeoutMillis: poolOptions.createTimeout,\r\n destroyTimeoutMillis: poolOptions.destroyTimeout,\r\n idleTimeoutMillis: poolOptions.idleTimeout,\r\n createRetryIntervalMillis: poolOptions.createRetryInterval,\r\n reapIntervalMillis: poolOptions.reaperInterval,\r\n propagateCreateError: false\r\n });\r\n\r\n // Set events\r\n pool.on('release', async (resource) => {\r\n // Clear page\r\n const clearStatus = await clearPage(resource, false);\r\n log(\r\n 4,\r\n `[pool] Pool resource [${resource.id}] - Releasing a worker. Clear page status: ${clearStatus}.`\r\n );\r\n });\r\n\r\n pool.on('destroySuccess', (_eventId, resource) => {\r\n log(\r\n 4,\r\n `[pool] Pool resource [${resource.id}] - Destroyed a worker successfully.`\r\n );\r\n resource.page = null;\r\n });\r\n\r\n const initialResources = [];\r\n // Create an initial number of resources\r\n for (let i = 0; i < poolOptions.minWorkers; i++) {\r\n try {\r\n const resource = await pool.acquire().promise;\r\n initialResources.push(resource);\r\n } catch (error) {\r\n logWithStack(2, error, '[pool] Could not create an initial resource.');\r\n }\r\n }\r\n\r\n // Release the initial number of resources back to the pool\r\n initialResources.forEach((resource) => {\r\n pool.release(resource);\r\n });\r\n\r\n log(\r\n 3,\r\n `[pool] The pool is ready${initialResources.length ? ` with ${initialResources.length} initial resources waiting.` : '.'}`\r\n );\r\n } catch (error) {\r\n throw new ExportError(\r\n '[pool] Could not configure and create the pool of workers.',\r\n 500\r\n ).setError(error);\r\n }\r\n}\r\n\r\n/**\r\n * Terminates all workers in the pool, destroys the pool, and closes the browser\r\n * instance.\r\n *\r\n * @async\r\n * @function killPool\r\n *\r\n * @returns {Promise} A Promise that resolves once all workers are\r\n * terminated, the pool is destroyed, and the browser is successfully closed.\r\n */\r\nexport async function killPool() {\r\n log(3, '[pool] Killing pool with all workers and closing browser.');\r\n\r\n // If still alive, destroy the pool of pages before closing a browser\r\n if (pool) {\r\n // Free up not released workers\r\n for (const worker of pool.used) {\r\n pool.release(worker.resource);\r\n }\r\n\r\n // Destroy the pool if it is still available\r\n if (!pool.destroyed) {\r\n await pool.destroy();\r\n log(4, '[pool] Destroyed the pool of resources.');\r\n }\r\n pool = null;\r\n }\r\n\r\n // Close the browser instance\r\n await closeBrowser();\r\n}\r\n\r\n/**\r\n * Processes the export work using a worker from the pool. Acquires a worker\r\n * handle from the pool, performs the export using puppeteer, and releases\r\n * the worker handle back to the pool.\r\n *\r\n * @async\r\n * @function postWork\r\n *\r\n * @param {Object} options - The configuration object containing complete set\r\n * of options.\r\n *\r\n * @returns {Promise} A Promise that resolves to the export result\r\n * and options.\r\n *\r\n * @throws {ExportError} Throws an `ExportError` if an error occurs during\r\n * the export process.\r\n */\r\nexport async function postWork(options) {\r\n let workerHandle;\r\n\r\n try {\r\n log(4, '[pool] Work received, starting to process.');\r\n\r\n // An export attempt counted\r\n ++poolStats.exportsAttempted;\r\n\r\n // Display the pool information if needed\r\n if (options.pool.benchmarking) {\r\n getPoolInfo();\r\n }\r\n\r\n // Throw an error in case of lacking the pool instance\r\n if (!pool) {\r\n throw new ExportError(\r\n '[pool] Work received, but pool has not been started.',\r\n 500\r\n );\r\n }\r\n\r\n // The acquire counter\r\n const acquireCounter = measureTime();\r\n\r\n // Try to acquire the worker along with the id, works count and page\r\n try {\r\n log(4, '[pool] Acquiring a worker handle.');\r\n\r\n // Acquire a pool resource\r\n workerHandle = await pool.acquire().promise;\r\n\r\n // Check the page acquire time\r\n if (options.server.benchmarking) {\r\n log(\r\n 5,\r\n `[benchmark] ${options.requestId ? `Request [${options.requestId}] - ` : ''}`,\r\n `Acquiring a worker handle took ${acquireCounter()}ms.`\r\n );\r\n }\r\n } catch (error) {\r\n throw new ExportError(\r\n `[pool] ${\r\n options.requestId ? `Request [${options.requestId}] - ` : ''\r\n }Error encountered when acquiring an available entry: ${acquireCounter()}ms.`,\r\n 400\r\n ).setError(error);\r\n }\r\n log(4, '[pool] Acquired a worker handle.');\r\n\r\n if (!workerHandle.page) {\r\n // Set the `workLimit` to exceeded in order to recreate the resource\r\n workerHandle.workCount = options.pool.workLimit + 1;\r\n throw new ExportError(\r\n '[pool] Resolved worker page is invalid: the pool setup is wonky.',\r\n 400\r\n );\r\n }\r\n\r\n // Save the start time\r\n const workStart = getNewDateTime();\r\n\r\n log(\r\n 4,\r\n `[pool] Pool resource [${workerHandle.id}] - Starting work on this pool entry.`\r\n );\r\n\r\n // Start measuring export time\r\n const exportCounter = measureTime();\r\n\r\n // Perform an export on a puppeteer level\r\n const result = await puppeteerExport(\r\n workerHandle.page,\r\n options.export,\r\n options.customLogic\r\n );\r\n\r\n // Check if it's an error\r\n if (result instanceof Error) {\r\n // NOTE:\r\n // If there's a rasterization timeout, we want need to flush the page.\r\n // This is because the page may be in a state where it's waiting for\r\n // the screenshot to finish even though the timeout has occured.\r\n // Which of course causes a lot of issues with the event system,\r\n // and page consistency.\r\n //\r\n // NOTE:\r\n // Only page.screenshot will throw this, timeouts for PDF's are\r\n // handled by the page.pdf function itself.\r\n //\r\n // ...yes, this is ugly.\r\n if (result.message === 'Rasterization timeout') {\r\n // Set the `workLimit` to exceeded in order to recreate the resource\r\n workerHandle.workCount = options.pool.workLimit + 1;\r\n workerHandle.page = null;\r\n }\r\n\r\n if (\r\n result.name === 'TimeoutError' ||\r\n result.message === 'Rasterization timeout'\r\n ) {\r\n throw new ExportError(\r\n `[pool] ${\r\n options.requestId ? `Request [${options.requestId}] - ` : ''\r\n }Rasterization timeout: your chart may be too complex or large, and failed to render within the allotted time.`\r\n ).setError(result);\r\n } else {\r\n throw new ExportError(\r\n `[pool] ${\r\n options.requestId ? `Request [${options.requestId}] - ` : ''\r\n }Error encountered during export: ${exportCounter()}ms.`\r\n ).setError(result);\r\n }\r\n }\r\n\r\n // Check the Puppeteer export time\r\n if (options.server.benchmarking) {\r\n log(\r\n 5,\r\n `[benchmark] ${options.requestId ? `Request [${options.requestId}] - ` : ''}`,\r\n `Exporting a chart sucessfully took ${exportCounter()}ms.`\r\n );\r\n }\r\n\r\n // Release the resource back to the pool\r\n pool.release(workerHandle);\r\n\r\n // Used for statistics in averageTime and processedWorkCount, which\r\n // in turn is used by the /health route.\r\n const workEnd = getNewDateTime();\r\n const exportTime = workEnd - workStart;\r\n\r\n poolStats.timeSpent += exportTime;\r\n poolStats.timeSpentAverage =\r\n poolStats.timeSpent / ++poolStats.exportsPerformed;\r\n\r\n log(4, `[pool] Work completed in ${exportTime}ms.`);\r\n\r\n // Otherwise return the result\r\n return {\r\n result,\r\n options\r\n };\r\n } catch (error) {\r\n ++poolStats.exportsDropped;\r\n\r\n if (workerHandle) {\r\n pool.release(workerHandle);\r\n }\r\n\r\n throw error;\r\n }\r\n}\r\n\r\n/**\r\n * Retrieves the current pool instance.\r\n *\r\n * @function getPool\r\n *\r\n * @returns {(Object|null)} The current pool instance if initialized, or null\r\n * if the pool has not been created.\r\n */\r\nexport function getPool() {\r\n return pool;\r\n}\r\n\r\n/**\r\n * Gets the statistic of a pool instace about exports.\r\n *\r\n * @function getPoolStats\r\n *\r\n * @returns {Object} The current pool statistics.\r\n */\r\nexport function getPoolStats() {\r\n return poolStats;\r\n}\r\n\r\n/**\r\n * Retrieves pool information in JSON format, including minimum and maximum\r\n * workers, available workers, workers in use, and pending acquire requests.\r\n *\r\n * @function getPoolInfoJSON\r\n *\r\n * @returns {Object} Pool information in JSON format.\r\n */\r\nexport function getPoolInfoJSON() {\r\n return {\r\n min: pool.min,\r\n max: pool.max,\r\n used: pool.numUsed(),\r\n available: pool.numFree(),\r\n allCreated: pool.numUsed() + pool.numFree(),\r\n pendingAcquires: pool.numPendingAcquires(),\r\n pendingCreates: pool.numPendingCreates(),\r\n pendingValidations: pool.numPendingValidations(),\r\n pendingDestroys: pool.pendingDestroys.length,\r\n absoluteAll:\r\n pool.numUsed() +\r\n pool.numFree() +\r\n pool.numPendingAcquires() +\r\n pool.numPendingCreates() +\r\n pool.numPendingValidations() +\r\n pool.pendingDestroys.length\r\n };\r\n}\r\n\r\n/**\r\n * Logs information about the current state of the pool, including the minimum\r\n * and maximum workers, available workers, workers in use, and pending acquire\r\n * requests.\r\n *\r\n * @function getPoolInfo\r\n */\r\nexport function getPoolInfo() {\r\n const {\r\n min,\r\n max,\r\n used,\r\n available,\r\n allCreated,\r\n pendingAcquires,\r\n pendingCreates,\r\n pendingValidations,\r\n pendingDestroys,\r\n absoluteAll\r\n } = getPoolInfoJSON();\r\n\r\n log(5, `[pool] The minimum number of resources allowed by pool: ${min}.`);\r\n log(5, `[pool] The maximum number of resources allowed by pool: ${max}.`);\r\n log(5, `[pool] The number of used resources: ${used}.`);\r\n log(5, `[pool] The number of free resources: ${available}.`);\r\n log(\r\n 5,\r\n `[pool] The number of all created (used and free) resources: ${allCreated}.`\r\n );\r\n log(\r\n 5,\r\n `[pool] The number of resources waiting to be acquired: ${pendingAcquires}.`\r\n );\r\n log(\r\n 5,\r\n `[pool] The number of resources waiting to be created: ${pendingCreates}.`\r\n );\r\n log(\r\n 5,\r\n `[pool] The number of resources waiting to be validated: ${pendingValidations}.`\r\n );\r\n log(\r\n 5,\r\n `[pool] The number of resources waiting to be destroyed: ${pendingDestroys}.`\r\n );\r\n log(5, `[pool] The number of all resources: ${absoluteAll}.`);\r\n}\r\n\r\n/**\r\n * Factory function that returns an object with `create`, `validate`,\r\n * and `destroy` functions for the pool instance.\r\n *\r\n * @function _factory\r\n *\r\n * @param {Object} poolOptions - The configuration object containing `pool`\r\n * options.\r\n */\r\nfunction _factory(poolOptions) {\r\n return {\r\n /**\r\n * Creates a new worker page for the export pool.\r\n *\r\n * @async\r\n * @function create\r\n *\r\n * @returns {Promise} A Promise that resolves to an object\r\n * containing the worker ID, a reference to the browser page, and initial\r\n * work count.\r\n *\r\n * @throws {ExportError} Throws an `ExportError` if there is an error during\r\n * the creation of the new page.\r\n */\r\n create: async () => {\r\n // Init the resource with unique id and work count\r\n const poolResource = {\r\n id: uuid(),\r\n // Try to distribute the initial work count\r\n workCount: Math.round(Math.random() * (poolOptions.workLimit / 2))\r\n };\r\n\r\n try {\r\n // Start measuring a page creation time\r\n const startDate = getNewDateTime();\r\n\r\n // Create a new page\r\n await newPage(poolResource);\r\n\r\n // Measure the time of full creation and configuration of a page\r\n log(\r\n 3,\r\n `[pool] Pool resource [${poolResource.id}] - Successfully created a worker, took ${\r\n getNewDateTime() - startDate\r\n }ms.`\r\n );\r\n\r\n // Return ready pool resource\r\n return poolResource;\r\n } catch (error) {\r\n log(\r\n 3,\r\n `[pool] Pool resource [${poolResource.id}] - Error encountered when creating a new page.`\r\n );\r\n throw error;\r\n }\r\n },\r\n\r\n /**\r\n * Validates a worker page in the export pool, checking if it has exceeded\r\n * the work limit.\r\n *\r\n * @async\r\n * @function validate\r\n *\r\n * @param {Object} poolResource - The handle to the worker, containing\r\n * the worker's ID, a reference to the browser page, and work count.\r\n *\r\n * @returns {Promise} A Promise that resolves to true if the worker\r\n * is valid and within the work limit; otherwise, to false.\r\n */\r\n validate: async (poolResource) => {\r\n // NOTE:\r\n // In certain cases acquiring throws a TargetCloseError, which may\r\n // be caused by two things:\r\n // - The page is closed and attempted to be reused.\r\n // - Lost contact with the browser.\r\n //\r\n // What we're seeing in logs is that successive exports typically\r\n // succeeds, and the server recovers, indicating that it's likely\r\n // the first case. This is an attempt at allievating the issue by\r\n // simply not validating the worker if the page is null or closed.\r\n //\r\n // The actual result from when this happened, was that a worker would\r\n // be completely locked, stopping it from being acquired until\r\n // its work count reached the limit.\r\n\r\n // Check if the `page` is valid\r\n if (!poolResource.page) {\r\n log(\r\n 3,\r\n `[pool] Pool resource [${poolResource.id}] - Validation failed (no valid page is found).`\r\n );\r\n return false;\r\n }\r\n\r\n // Check if the `page` is closed\r\n if (poolResource.page.isClosed()) {\r\n log(\r\n 3,\r\n `[pool] Pool resource [${poolResource.id}] - Validation failed (page is closed or invalid).`\r\n );\r\n return false;\r\n }\r\n\r\n // Check if the `mainFrame` is detached\r\n if (poolResource.page.mainFrame().detached) {\r\n log(\r\n 3,\r\n `[pool] Pool resource [${poolResource.id}] - Validation failed (page's frame is detached).`\r\n );\r\n return false;\r\n }\r\n\r\n // Check if the `workLimit` is exceeded\r\n if (\r\n poolOptions.workLimit &&\r\n ++poolResource.workCount > poolOptions.workLimit\r\n ) {\r\n log(\r\n 3,\r\n `[pool] Pool resource [${poolResource.id}] - Validation failed (exceeded the ${poolOptions.workLimit} works per resource limit).`\r\n );\r\n return false;\r\n }\r\n\r\n // The `poolResource` is validated\r\n return true;\r\n },\r\n\r\n /**\r\n * Destroys a worker entry in the export pool, closing its associated page.\r\n *\r\n * @async\r\n * @function destroy\r\n *\r\n * @param {Object} poolResource - The handle to the worker, containing\r\n * the worker's ID, a reference to the browser page, and work count.\r\n */\r\n destroy: async (poolResource) => {\r\n log(\r\n 3,\r\n `[pool] Pool resource [${poolResource.id}] - Destroying a worker.`\r\n );\r\n\r\n if (poolResource.page && !poolResource.page.isClosed()) {\r\n try {\r\n // Remove all attached event listeners from the resource\r\n poolResource.page.removeAllListeners('pageerror');\r\n poolResource.page.removeAllListeners('console');\r\n poolResource.page.removeAllListeners('framedetached');\r\n\r\n // We need to wait around for this\r\n await poolResource.page.close();\r\n } catch (error) {\r\n log(\r\n 3,\r\n `[pool] Pool resource [${poolResource.id}] - Page could not be closed upon destroying.`\r\n );\r\n throw error;\r\n }\r\n }\r\n }\r\n };\r\n}\r\n\r\nexport default {\r\n initPool,\r\n killPool,\r\n postWork,\r\n getPool,\r\n getPoolStats,\r\n getPoolInfo,\r\n getPoolInfoJSON\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * @overview Used to sanitize the strings coming from the exporting module\r\n * to prevent XSS attacks (with the DOMPurify library).\r\n */\r\n\r\nimport DOMPurify from 'dompurify';\r\nimport { JSDOM } from 'jsdom';\r\n\r\n/**\r\n * Sanitizes a given HTML string by removing \r\n * tags and any content within them.\r\n *\r\n * @function sanitize\r\n *\r\n * @param {string} input - The HTML string to be sanitized.\r\n *\r\n * @returns {string} The sanitized HTML string.\r\n */\r\nexport function sanitize(input) {\r\n // Get the virtual DOM\r\n const window = new JSDOM('').window;\r\n\r\n // Create a purifying instance\r\n const purify = DOMPurify(window);\r\n\r\n // Return sanitized input\r\n return purify.sanitize(input, { ADD_TAGS: ['foreignObject'] });\r\n}\r\n\r\nexport default {\r\n sanitize\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * @overview This module provides functions to prepare for the exporting charts\r\n * into various image output formats such as JPEG, PNG, PDF, and SVGs.\r\n * It supports single and batch export operations and allows customization\r\n * through options passed from configurations or APIs.\r\n */\r\n\r\nimport { readFileSync, writeFileSync } from 'fs';\r\n\r\nimport {\r\n getOptions,\r\n isAllowedConfig,\r\n mergeOptions,\r\n validateOption,\r\n validateOptions\r\n} from './config.js';\r\nimport { log, logWithStack } from './logger.js';\r\nimport { getPoolStats, killPool, postWork } from './pool.js';\r\nimport { sanitize } from './sanitize.js';\r\nimport {\r\n deepCopy,\r\n fixConstr,\r\n fixOutfile,\r\n fixType,\r\n getAbsolutePath,\r\n getBase64,\r\n isObject,\r\n roundNumber,\r\n wrapAround\r\n} from './utils.js';\r\n\r\nimport ExportError from './errors/ExportError.js';\r\n\r\n// The global flag for the code execution permission\r\nlet allowCodeExecution = false;\r\n\r\n/**\r\n * Starts a single export process based on the specified options and saves\r\n * the resulting image to the provided output file.\r\n *\r\n * @async\r\n * @function singleExport\r\n *\r\n * @param {Object} options - The `options` object, which should include settings\r\n * from the `export` and `customLogic` sections. It can be a partial or complete\r\n * set of options from these sections. The object must contain at least one\r\n * of the following `export` properties: `infile`, `instr`, `options`, or `svg`\r\n * to generate a valid image.\r\n *\r\n * @returns {Promise} A Promise that resolves once the single export\r\n * process is completed.\r\n *\r\n * @throws {ExportError} Throws an `ExportError` if an error occurs during\r\n * the single export process.\r\n */\r\nexport async function singleExport(options) {\r\n // Check if the export makes sense\r\n if (options && options.export) {\r\n // Validate single export options\r\n options = validateOptions(options);\r\n\r\n // Perform an export\r\n await startExport(\r\n { export: options.export, customLogic: options.customLogic },\r\n async (error, data) => {\r\n // Exit process when error exists\r\n if (error) {\r\n throw error;\r\n }\r\n\r\n // Get the `b64`, `outfile`, and `type` for a chart\r\n const { b64, outfile, type } = data.options.export;\r\n\r\n // Save the result\r\n try {\r\n if (b64) {\r\n // As a Base64 string to a txt file\r\n writeFileSync(\r\n `${outfile.split('.').shift() || 'chart'}.txt`,\r\n getBase64(data.result, type)\r\n );\r\n } else {\r\n // As a correct image format\r\n writeFileSync(\r\n outfile || `chart.${type}`,\r\n type !== 'svg' ? Buffer.from(data.result, 'base64') : data.result\r\n );\r\n }\r\n } catch (error) {\r\n throw new ExportError(\r\n '[chart] Error while saving a chart.',\r\n 500\r\n ).setError(error);\r\n }\r\n\r\n // Kill pool and close browser after finishing single export\r\n await killPool();\r\n }\r\n );\r\n } else {\r\n throw new ExportError(\r\n '[chart] No expected `export` options were found. Please provide one of the following options: `infile`, `instr`, `options`, or `svg` to generate a valid image.',\r\n 400\r\n );\r\n }\r\n}\r\n\r\n/**\r\n * Starts a batch export process for multiple charts based on information\r\n * provided in the `batch` option. The `batch` is a string in the following\r\n * format: \"infile1.json=outfile1.png;infile2.json=outfile2.png;...\". Results\r\n * are saved to the specified output files.\r\n *\r\n * @async\r\n * @function batchExport\r\n *\r\n * @param {Object} options - The `options` object, which should include settings\r\n * from the `export` and `customLogic` sections. It can be a partial or complete\r\n * set of options from these sections. It must contain the `batch` option from\r\n * the `export` section to generate valid images.\r\n *\r\n * @returns {Promise} A Promise that resolves once the batch export\r\n * processes are completed.\r\n *\r\n * @throws {ExportError} Throws an `ExportError` if an error occurs during\r\n * any of the batch export process.\r\n */\r\nexport async function batchExport(options) {\r\n // Check if the export makes sense\r\n if (options && options.export && options.export.batch) {\r\n // Validate batch export options\r\n options = validateOptions(options);\r\n\r\n // An array for collecting batch exports\r\n const batchFunctions = [];\r\n\r\n // Split and pair the `batch` arguments\r\n for (let pair of options.export.batch.split(';') || []) {\r\n pair = pair.split('=');\r\n if (pair.length === 2) {\r\n batchFunctions.push(\r\n startExport(\r\n {\r\n export: {\r\n ...options.export,\r\n infile: pair[0],\r\n outfile: pair[1]\r\n },\r\n customLogic: options.customLogic\r\n },\r\n (error, data) => {\r\n // Exit process when error exists\r\n if (error) {\r\n throw error;\r\n }\r\n\r\n // Get the `b64`, `outfile`, and `type` for a chart\r\n const { b64, outfile, type } = data.options.export;\r\n\r\n // Save the result\r\n try {\r\n if (b64) {\r\n // As a Base64 string to a txt file\r\n writeFileSync(\r\n `${outfile.split('.').shift() || 'chart'}.txt`,\r\n getBase64(data.result, type)\r\n );\r\n } else {\r\n // As a correct image format\r\n writeFileSync(\r\n outfile,\r\n type !== 'svg'\r\n ? Buffer.from(data.result, 'base64')\r\n : data.result\r\n );\r\n }\r\n } catch (error) {\r\n throw new ExportError(\r\n '[chart] Error while saving a chart.',\r\n 500\r\n ).setError(error);\r\n }\r\n }\r\n )\r\n );\r\n } else {\r\n log(2, '[chart] No correct pair found for the batch export.');\r\n }\r\n }\r\n\r\n // Await all exports are done\r\n const batchResults = await Promise.allSettled(batchFunctions);\r\n\r\n // Kill pool and close browser after finishing batch export\r\n await killPool();\r\n\r\n // Log errors if found\r\n batchResults.forEach((result, index) => {\r\n // Log the error with stack about the specific batch export\r\n if (result.reason) {\r\n logWithStack(\r\n 1,\r\n result.reason,\r\n `[chart] Batch export number ${index + 1} could not be correctly completed.`\r\n );\r\n }\r\n });\r\n } else {\r\n throw new ExportError(\r\n '[chart] No expected `export` options were found. Please provide the `batch` option to generate valid images.',\r\n 400\r\n );\r\n }\r\n}\r\n\r\n/**\r\n * Starts an export process. The `exportingOptions` parameter is an object that\r\n * should include settings from the `export` and `customLogic` sections. It can\r\n * be a partial or complete set of options from these sections. If partial\r\n * options are provided, missing values will be merged with the current global\r\n * options.\r\n *\r\n * The `endCallback` function is invoked upon the completion of the export,\r\n * either successfully or with an error. The `error` object is provided\r\n * as the first argument, and the `data` object is the second, containing\r\n * the Base64 representation of the chart in the `result` property\r\n * and the complete set of options in the `options` property.\r\n *\r\n * @async\r\n * @function startExport\r\n *\r\n * @param {Object} exportingOptions - The `exportingOptions` object, which\r\n * should include settings from the `export` and `customLogic` sections. It can\r\n * be a partial or complete set of options from these sections. If the provided\r\n * options are partial, missing values will be merged with the current global\r\n * options.\r\n * @param {Function} endCallback - The callback function to be invoked upon\r\n * finalizing the export process or upon encountering an error. The first\r\n * argument is the `error` object, and the second argument is the `data` object,\r\n * which includes the Base64 representation of the chart in the `result`\r\n * property and the full set of options in the `options` property.\r\n *\r\n * @returns {Promise} This function does not return a value directly.\r\n * Instead, it communicates results via the `endCallback`.\r\n *\r\n * @throws {ExportError} Throws an `ExportError` if there is a problem with\r\n * processing input of any type. The error is passed into the `endCallback`\r\n * function and processed there.\r\n */\r\nexport async function startExport(exportingOptions, endCallback) {\r\n try {\r\n // Check if provided options is an object\r\n if (!isObject(exportingOptions)) {\r\n throw new ExportError(\r\n '[chart] Incorrect value of the provided `exportingOptions`. Needs to be an object.',\r\n 400\r\n );\r\n }\r\n\r\n // Merge additional options to the copy of the instance options\r\n const options = mergeOptions(deepCopy(getOptions()), {\r\n export: exportingOptions.export,\r\n customLogic: exportingOptions.customLogic\r\n });\r\n\r\n // Get the `export` options\r\n const exportOptions = options.export;\r\n\r\n // Starting exporting process message\r\n log(4, '[chart] Starting the exporting process.');\r\n\r\n // Export using options from the file as an input\r\n if (exportOptions.infile !== null) {\r\n log(4, '[chart] Attempting to export from a file input.');\r\n\r\n let fileContent;\r\n try {\r\n // Try to read the file to get the string representation\r\n fileContent = readFileSync(\r\n getAbsolutePath(exportOptions.infile),\r\n 'utf8'\r\n );\r\n } catch (error) {\r\n throw new ExportError(\r\n '[chart] Error loading content from a file input.',\r\n 400\r\n ).setError(error);\r\n }\r\n\r\n // Check the file's extension\r\n if (exportOptions.infile.endsWith('.svg')) {\r\n // Set to the `svg` option\r\n exportOptions.svg = validateOption('svg', fileContent);\r\n } else if (exportOptions.infile.endsWith('.json')) {\r\n // Set to the `instr` option\r\n exportOptions.instr = validateOption('instr', fileContent);\r\n } else {\r\n throw new ExportError(\r\n '[chart] Incorrect value of the `infile` option.',\r\n 400\r\n );\r\n }\r\n }\r\n\r\n // Export using SVG as an input\r\n if (exportOptions.svg !== null) {\r\n log(4, '[chart] Attempting to export from an SVG input.');\r\n\r\n // SVG exports attempts counter\r\n ++getPoolStats().exportsFromSvgAttempts;\r\n\r\n // Export from an SVG string\r\n const result = await _exportFromSvg(\r\n sanitize(exportOptions.svg), // #209\r\n options\r\n );\r\n\r\n // SVG exports counter\r\n ++getPoolStats().exportsFromSvg;\r\n\r\n // Pass SVG export result to the end callback\r\n return endCallback(null, result);\r\n }\r\n\r\n // Export using options as an input\r\n if (exportOptions.instr !== null || exportOptions.options !== null) {\r\n log(4, '[chart] Attempting to export from options input.');\r\n\r\n // Options exports attempts counter\r\n ++getPoolStats().exportsFromOptionsAttempts;\r\n\r\n // Export from options\r\n const result = await _exportFromOptions(\r\n exportOptions.instr || exportOptions.options,\r\n options\r\n );\r\n\r\n // Options exports counter\r\n ++getPoolStats().exportsFromOptions;\r\n\r\n // Pass options export result to the end callback\r\n return endCallback(null, result);\r\n }\r\n\r\n // No input specified, pass an error message to the callback\r\n return endCallback(\r\n new ExportError(\r\n `[chart] No valid input specified. Check if at least one of the following parameters is correctly set: 'infile', 'instr', 'options', or 'svg'.`,\r\n 400\r\n )\r\n );\r\n } catch (error) {\r\n return endCallback(error);\r\n }\r\n}\r\n\r\n/**\r\n * Retrieves and returns the current status of the code execution permission.\r\n *\r\n * @function getAllowCodeExecution\r\n *\r\n * @returns {boolean} The value of the global `allowCodeExecution` option.\r\n */\r\nexport function getAllowCodeExecution() {\r\n return allowCodeExecution;\r\n}\r\n\r\n/**\r\n * Sets the code execution permission based on the provided boolean value.\r\n *\r\n * @function setAllowCodeExecution\r\n *\r\n * @param {boolean} value - The boolean value to be assigned to the global\r\n * `allowCodeExecution` option.\r\n */\r\nexport function setAllowCodeExecution(value) {\r\n allowCodeExecution = value;\r\n}\r\n\r\n/**\r\n * Exports from an SVG based input with the provided options.\r\n *\r\n * @async\r\n * @function _exportFromSvg\r\n *\r\n * @param {string} inputToExport - The SVG based input to be exported.\r\n * @param {Object} options - The configuration object containing complete set\r\n * of options.\r\n *\r\n * @returns {Promise} A Promise that resolves to a result of the export\r\n * process.\r\n *\r\n * @throws {ExportError} Throws an `ExportError` if there is not a correct SVG\r\n * input.\r\n */\r\nasync function _exportFromSvg(inputToExport, options) {\r\n // Check if it is SVG\r\n if (\r\n typeof inputToExport === 'string' &&\r\n (inputToExport.indexOf('= 0 || inputToExport.indexOf('= 0)\r\n ) {\r\n log(4, '[chart] Parsing input as SVG.');\r\n\r\n // Set the export input as SVG\r\n options.export.svg = inputToExport;\r\n\r\n // Reset the rest of the export input options\r\n options.export.instr = null;\r\n options.export.options = null;\r\n\r\n // Call the function with an SVG string as an export input\r\n return _prepareExport(options);\r\n } else {\r\n throw new ExportError('[chart] Not a correct SVG input.', 400);\r\n }\r\n}\r\n\r\n/**\r\n * Exports from an options based input with the provided options.\r\n *\r\n * @async\r\n * @function _exportFromOptions\r\n *\r\n * @param {string} inputToExport - The options based input to be exported.\r\n * @param {Object} options - The configuration object containing complete set\r\n * of options.\r\n *\r\n * @returns {Promise} A Promise that resolves to a result of the export\r\n * process.\r\n *\r\n * @throws {ExportError} Throws an `ExportError` if there is not a correct\r\n * chart options input.\r\n */\r\nasync function _exportFromOptions(inputToExport, options) {\r\n log(4, '[chart] Parsing input from options.');\r\n\r\n // Try to check, validate and parse to stringified options\r\n const stringifiedOptions = isAllowedConfig(\r\n inputToExport,\r\n true,\r\n options.customLogic.allowCodeExecution\r\n );\r\n\r\n // Check if a correct stringified options\r\n if (\r\n stringifiedOptions === null ||\r\n typeof stringifiedOptions !== 'string' ||\r\n !stringifiedOptions.startsWith('{') ||\r\n !stringifiedOptions.endsWith('}')\r\n ) {\r\n throw new ExportError(\r\n '[chart] Invalid configuration provided - Only options configurations and SVG are allowed for this server. If this is your server, JavaScript custom code can be enabled by starting the server with the `allowCodeExecution` options set to true.',\r\n 403\r\n );\r\n }\r\n\r\n // Set the export input as a stringified chart options\r\n options.export.instr = stringifiedOptions;\r\n\r\n // Reset the rest of the export input options\r\n options.export.svg = null;\r\n\r\n // Call the function with a stringified chart options\r\n return _prepareExport(options);\r\n}\r\n\r\n/**\r\n * Function for finalizing options and configurations before export.\r\n *\r\n * @async\r\n * @function _prepareExport\r\n *\r\n * @param {Object} options - The configuration object containing complete set\r\n * of options.\r\n *\r\n * @returns {Promise} A Promise that resolves to a result of the export\r\n * process.\r\n */\r\nasync function _prepareExport(options) {\r\n const { export: exportOptions, customLogic: customLogicOptions } = options;\r\n\r\n // Prepare the `type` option\r\n exportOptions.type = fixType(exportOptions.type, exportOptions.outfile);\r\n\r\n // Prepare the `outfile` option\r\n exportOptions.outfile = fixOutfile(exportOptions.type, exportOptions.outfile);\r\n\r\n // Prepare the `constr` option\r\n exportOptions.constr = fixConstr(exportOptions.constr);\r\n\r\n // Notify about the custom logic usage status\r\n log(\r\n 3,\r\n `[chart] The custom logic is ${customLogicOptions.allowCodeExecution ? 'allowed' : 'disallowed'}.`\r\n );\r\n\r\n // Prepare the custom logic options (`customCode`, `callback`, `resources`)\r\n _handleCustomLogic(customLogicOptions, customLogicOptions.allowCodeExecution);\r\n\r\n // Prepare the `globalOptions` and `themeOptions` options\r\n _handleGlobalAndTheme(\r\n exportOptions,\r\n customLogicOptions.allowFileResources,\r\n customLogicOptions.allowCodeExecution\r\n );\r\n\r\n // Prepare the `height`, `width`, and `scale` options\r\n options.export = {\r\n ...exportOptions,\r\n ..._findChartSize(exportOptions)\r\n };\r\n\r\n // Post the work to the pool\r\n return postWork(options);\r\n}\r\n\r\n/**\r\n * Calculates the `height`, `width` and `scale` for chart exports based\r\n * on the provided export options.\r\n *\r\n * The function prioritizes values in the following order:\r\n * 1. The `height`, `width`, `scale` from the `exportOptions`.\r\n * 2. Options from the chart configuration (from `exporting` and `chart`).\r\n * 3. Options from the global options (from `exporting` and `chart`).\r\n * 4. Options from the theme options (from `exporting` and `chart` sections).\r\n * 5. Fallback default values (`height = 400`, `width = 600`, `scale = 1`).\r\n *\r\n * @function _findChartSize\r\n *\r\n * @param {Object} exportOptions - The configuration object containing `export`\r\n * options.\r\n *\r\n * @returns {Object} The object containing calculated `height`, `width`\r\n * and `scale` values for the chart export.\r\n */\r\nfunction _findChartSize(exportOptions) {\r\n // Check the `options` and `instr` for chart and exporting sections\r\n const { chart: optionsChart, exporting: optionsExporting } =\r\n exportOptions.options || isAllowedConfig(exportOptions.instr) || false;\r\n\r\n // Check the `globalOptions` for chart and exporting sections\r\n const { chart: globalOptionsChart, exporting: globalOptionsExporting } =\r\n isAllowedConfig(exportOptions.globalOptions) || false;\r\n\r\n // Check the `themeOptions` for chart and exporting sections\r\n const { chart: themeOptionsChart, exporting: themeOptionsExporting } =\r\n isAllowedConfig(exportOptions.themeOptions) || false;\r\n\r\n // Find the `scale` value:\r\n // - It cannot be lower than 0.1\r\n // - It cannot be higher than 5.0\r\n // - It must be rounded to 2 decimal places (e.g. 0.23234 -> 0.23)\r\n const scale = roundNumber(\r\n Math.max(\r\n 0.1,\r\n Math.min(\r\n exportOptions.scale ||\r\n optionsExporting?.scale ||\r\n globalOptionsExporting?.scale ||\r\n themeOptionsExporting?.scale ||\r\n exportOptions.defaultScale ||\r\n 1,\r\n 5.0\r\n )\r\n ),\r\n 2\r\n );\r\n\r\n // Find the `height` value\r\n const height =\r\n exportOptions.height ||\r\n optionsExporting?.sourceHeight ||\r\n optionsChart?.height ||\r\n globalOptionsExporting?.sourceHeight ||\r\n globalOptionsChart?.height ||\r\n themeOptionsExporting?.sourceHeight ||\r\n themeOptionsChart?.height ||\r\n exportOptions.defaultHeight ||\r\n 400;\r\n\r\n // Find the `width` value\r\n const width =\r\n exportOptions.width ||\r\n optionsExporting?.sourceWidth ||\r\n optionsChart?.width ||\r\n globalOptionsExporting?.sourceWidth ||\r\n globalOptionsChart?.width ||\r\n themeOptionsExporting?.sourceWidth ||\r\n themeOptionsChart?.width ||\r\n exportOptions.defaultWidth ||\r\n 600;\r\n\r\n // Gather `height`, `width` and `scale` information in one object\r\n const size = { height, width, scale };\r\n\r\n // Get rid of potential `px` and `%`\r\n for (let [param, value] of Object.entries(size)) {\r\n size[param] =\r\n typeof value === 'string' ? +value.replace(/px|%/gi, '') : value;\r\n }\r\n\r\n // Return the size object\r\n return size;\r\n}\r\n\r\n/**\r\n * Handles the execution of custom logic options, including loading `resources`,\r\n * `customCode`, and `callback`. If code execution is allowed, it processes\r\n * the custom logic options accordingly. If code execution is not allowed,\r\n * it disables the usage of resources, custom code and callback.\r\n *\r\n * @function _handleCustomLogic\r\n *\r\n * @param {Object} customLogicOptions - The configuration object containing\r\n * `customLogic` options.\r\n * @param {boolean} allowCodeExecution - A flag indicating whether code\r\n * execution is allowed.\r\n *\r\n * @throws {ExportError} Throws an `ExportError` if code execution\r\n * is not allowed but custom logic options are still provided.\r\n */\r\nfunction _handleCustomLogic(customLogicOptions, allowCodeExecution) {\r\n // In case of allowing code execution\r\n if (allowCodeExecution) {\r\n // Process the `resources` option\r\n if (typeof customLogicOptions.resources === 'string') {\r\n // Custom stringified resources\r\n customLogicOptions.resources = _handleResources(\r\n customLogicOptions.resources,\r\n customLogicOptions.allowFileResources,\r\n true\r\n );\r\n } else if (!customLogicOptions.resources) {\r\n try {\r\n // Load the default one\r\n customLogicOptions.resources = _handleResources(\r\n readFileSync(getAbsolutePath('resources.json'), 'utf8'),\r\n customLogicOptions.allowFileResources,\r\n true\r\n );\r\n } catch (error) {\r\n log(2, '[chart] Unable to load the default `resources.json` file.');\r\n }\r\n }\r\n\r\n // Process the `customCode` option\r\n try {\r\n // Try to load custom code and wrap around it in a self invoking function\r\n customLogicOptions.customCode = wrapAround(\r\n customLogicOptions.customCode,\r\n customLogicOptions.allowFileResources\r\n );\r\n\r\n // Validate the option\r\n customLogicOptions.customCode = validateOption(\r\n 'customCode',\r\n customLogicOptions.customCode\r\n );\r\n } catch (error) {\r\n logWithStack(2, error, '[chart] The `customCode` cannot be loaded.');\r\n\r\n // In case of an error, set the option with null\r\n customLogicOptions.customCode = null;\r\n }\r\n\r\n // Process the `callback` option\r\n try {\r\n // Try to load callback function\r\n customLogicOptions.callback = wrapAround(\r\n customLogicOptions.callback,\r\n customLogicOptions.allowFileResources,\r\n true\r\n );\r\n\r\n // Validate the option\r\n customLogicOptions.callback = validateOption(\r\n 'callback',\r\n customLogicOptions.callback\r\n );\r\n } catch (error) {\r\n logWithStack(2, error, '[chart] The `callback` cannot be loaded.');\r\n\r\n // In case of an error, set the option with null\r\n customLogicOptions.callback = null;\r\n }\r\n\r\n // Check if there is the `customCode` present\r\n if ([null, undefined].includes(customLogicOptions.customCode)) {\r\n log(3, '[chart] No value for the `customCode` option found.');\r\n }\r\n\r\n // Check if there is the `callback` present\r\n if ([null, undefined].includes(customLogicOptions.callback)) {\r\n log(3, '[chart] No value for the `callback` option found.');\r\n }\r\n\r\n // Check if there is the `resources` present\r\n if ([null, undefined].includes(customLogicOptions.resources)) {\r\n log(3, '[chart] No value for the `resources` option found.');\r\n }\r\n } else {\r\n // If the `allowCodeExecution` flag is set to false, we should refuse\r\n // the usage of the `callback`, `resources`, and `customCode` options.\r\n // Additionally, the worker will refuse to run arbitrary JavaScript.\r\n if (\r\n customLogicOptions.callback ||\r\n customLogicOptions.resources ||\r\n customLogicOptions.customCode\r\n ) {\r\n // Reset all custom code options\r\n customLogicOptions.callback = null;\r\n customLogicOptions.resources = null;\r\n customLogicOptions.customCode = null;\r\n\r\n // Send a message saying that the exporter does not support these settings\r\n throw new ExportError(\r\n `[chart] The 'callback', 'resources', and 'customCode' options have been disabled for this server.`,\r\n 403\r\n );\r\n }\r\n }\r\n}\r\n\r\n/**\r\n * Handles and validates resources from the `resources` option for export.\r\n *\r\n * @function _handleResources\r\n *\r\n * @param {(Object|string|null)} [resources=null] - The resources to be handled.\r\n * Can be either a JSON object, stringified JSON, a path to a JSON file,\r\n * or null. The default value is `null`.\r\n * @param {boolean} allowFileResources - A flag indicating whether loading\r\n * resources from files is allowed.\r\n * @param {boolean} allowCodeExecution - A flag indicating whether code\r\n * execution is allowed.\r\n *\r\n * @returns {(Object|null)} The handled resources or null if no valid resources\r\n * are found.\r\n */\r\nfunction _handleResources(\r\n resources = null,\r\n allowFileResources,\r\n allowCodeExecution\r\n) {\r\n // List of allowed sections in the resources JSON\r\n const allowedProps = ['js', 'css', 'files'];\r\n\r\n let handledResources = resources;\r\n let correctResources = false;\r\n\r\n // Try to load resources from a file\r\n if (allowFileResources && resources.endsWith('.json')) {\r\n try {\r\n handledResources = isAllowedConfig(\r\n readFileSync(getAbsolutePath(resources), 'utf8'),\r\n false,\r\n allowCodeExecution\r\n );\r\n } catch {\r\n return null;\r\n }\r\n } else {\r\n // Try to get JSON\r\n handledResources = isAllowedConfig(resources, false, allowCodeExecution);\r\n\r\n // Get rid of the files section\r\n if (handledResources && !allowFileResources) {\r\n delete handledResources.files;\r\n }\r\n }\r\n\r\n // Filter from unnecessary properties\r\n for (const propName in handledResources) {\r\n if (!allowedProps.includes(propName)) {\r\n delete handledResources[propName];\r\n } else if (!correctResources) {\r\n correctResources = true;\r\n }\r\n }\r\n\r\n // Check if at least one of allowed properties is present\r\n if (!correctResources) {\r\n return null;\r\n }\r\n\r\n // Handle files section\r\n if (handledResources.files) {\r\n handledResources.files = handledResources.files.map((item) => item.trim());\r\n if (!handledResources.files || handledResources.files.length <= 0) {\r\n delete handledResources.files;\r\n }\r\n }\r\n\r\n // Validate option\r\n handledResources = validateOption('resources', handledResources);\r\n\r\n // Return resources\r\n return handledResources;\r\n}\r\n\r\n/**\r\n * Handles the loading and validation of the `globalOptions` and `themeOptions`\r\n * in the export options. If the option is a string and references a JSON file\r\n * (when the `allowFileResources` is true), it reads and parses the file.\r\n * Otherwise, it attempts to parse the string or object as JSON. If any errors\r\n * occur during this process, the option is set to null. If there is an error\r\n * loading or parsing the `globalOptions` or `themeOptions`, the error is logged\r\n * and the option is set to null.\r\n *\r\n * @function _handleGlobalAndTheme\r\n *\r\n * @param {Object} exportOptions - The configuration object containing `export`\r\n * options.\r\n * @param {boolean} allowFileResources - A flag indicating whether loading\r\n * resources from files is allowed.\r\n * @param {boolean} allowCodeExecution - A flag indicating whether code\r\n * execution is allowed.\r\n */\r\nfunction _handleGlobalAndTheme(\r\n exportOptions,\r\n allowFileResources,\r\n allowCodeExecution\r\n) {\r\n // Check the `globalOptions` and `themeOptions` options\r\n ['globalOptions', 'themeOptions'].forEach((optionsName) => {\r\n try {\r\n // Check if the option exists\r\n if (exportOptions[optionsName]) {\r\n // Check if it is a string and a file name with the `.json` extension\r\n if (\r\n allowFileResources &&\r\n typeof exportOptions[optionsName] === 'string' &&\r\n exportOptions[optionsName].endsWith('.json')\r\n ) {\r\n // Check if the file content can be a config, and save it as a string\r\n exportOptions[optionsName] = isAllowedConfig(\r\n readFileSync(getAbsolutePath(exportOptions[optionsName]), 'utf8'),\r\n true,\r\n allowCodeExecution\r\n );\r\n } else {\r\n // Check if the value can be a config, and save it as a string\r\n exportOptions[optionsName] = isAllowedConfig(\r\n exportOptions[optionsName],\r\n true,\r\n allowCodeExecution\r\n );\r\n }\r\n\r\n // Validate the option\r\n exportOptions[optionsName] = validateOption(\r\n optionsName,\r\n exportOptions[optionsName]\r\n );\r\n }\r\n } catch (error) {\r\n logWithStack(\r\n 2,\r\n error,\r\n `[chart] The \\`${optionsName}\\` cannot be loaded.`\r\n );\r\n\r\n // In case of an error, set the option with null\r\n exportOptions[optionsName] = null;\r\n }\r\n });\r\n\r\n // Check if there is the `globalOptions` present\r\n if ([null, undefined].includes(exportOptions.globalOptions)) {\r\n log(3, '[chart] No value for the `globalOptions` option found.');\r\n }\r\n\r\n // Check if there is the `themeOptions` present\r\n if ([null, undefined].includes(exportOptions.themeOptions)) {\r\n log(3, '[chart] No value for the `themeOptions` option found.');\r\n }\r\n}\r\n\r\nexport default {\r\n singleExport,\r\n batchExport,\r\n startExport,\r\n getAllowCodeExecution,\r\n setAllowCodeExecution\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * @overview This module provides utility functions for managing intervals\r\n * and timeouts in a centralized manner. It maintains a registry of all active\r\n * timers and allows for their efficient cleanup when needed. This can be useful\r\n * in applications where proper resource management and clean shutdown of timers\r\n * are critical to avoid memory leaks or unintended behavior.\r\n */\r\n\r\nimport { log } from './logger.js';\r\n\r\n// Array that contains ids of all ongoing intervals and timeouts\r\nconst timerIds = [];\r\n\r\n/**\r\n * Adds id of the `setInterval` or `setTimeout` and to the `timerIds` array.\r\n *\r\n * @function addTimer\r\n *\r\n * @param {NodeJS.Timeout} id - Id of an interval or a timeout.\r\n */\r\nexport function addTimer(id) {\r\n timerIds.push(id);\r\n}\r\n\r\n/**\r\n * Clears all of ongoing intervals and timeouts by ids gathered\r\n * in the `timerIds` array.\r\n *\r\n * @function clearAllTimers\r\n */\r\nexport function clearAllTimers() {\r\n log(4, `[timer] Clearing all registered intervals and timeouts.`);\r\n for (const id of timerIds) {\r\n clearInterval(id);\r\n clearTimeout(id);\r\n }\r\n}\r\n\r\nexport default {\r\n addTimer,\r\n clearAllTimers\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * @overview Provides middleware functions for logging errors with stack traces\r\n * and handling error responses in an Express application.\r\n */\r\n\r\nimport { getOptions } from '../../config.js';\r\nimport { logWithStack } from '../../logger.js';\r\n\r\n/**\r\n * Middleware for logging errors with stack trace and handling error response.\r\n *\r\n * @function logErrorMiddleware\r\n *\r\n * @param {Error} error - The error object.\r\n * @param {Express.Request} request - The Express request object.\r\n * @param {Express.Response} response - The Express response object.\r\n * @param {Function} next - The next middleware function.\r\n *\r\n * @returns {undefined} The call to the next middleware function with\r\n * the passed error.\r\n */\r\nfunction logErrorMiddleware(error, request, response, next) {\r\n // Display the error with stack in a correct format\r\n logWithStack(1, error);\r\n\r\n // Delete the stack for the environment other than the development\r\n if (getOptions().other.nodeEnv !== 'development') {\r\n delete error.stack;\r\n }\r\n\r\n // Call the `returnErrorMiddleware` middleware\r\n return next(error);\r\n}\r\n\r\n/**\r\n * Middleware for returning error response.\r\n *\r\n * @function returnErrorMiddleware\r\n *\r\n * @param {Error} error - The error object.\r\n * @param {Express.Request} request - The Express request object.\r\n * @param {Express.Response} response - The Express response object.\r\n * @param {Function} next - The next middleware function.\r\n */\r\nfunction returnErrorMiddleware(error, request, response, next) {\r\n // Gather all requied information for the response\r\n const { message, stack } = error;\r\n\r\n // Use the error's status code or the default 400\r\n const statusCode = error.statusCode || 400;\r\n\r\n // Set and return response\r\n response.status(statusCode).json({ statusCode, message, stack });\r\n}\r\n\r\n/**\r\n * Adds the error middlewares to the passed express app instance.\r\n *\r\n * @param {Express} app - The Express app instance.\r\n */\r\nexport default function errorMiddleware(app) {\r\n // Add log error middleware\r\n app.use(logErrorMiddleware);\r\n\r\n // Add set status and return error middleware\r\n app.use(returnErrorMiddleware);\r\n}\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * @overview Provides middleware functions for configuring and enabling rate\r\n * limiting in an Express application.\r\n */\r\n\r\nimport rateLimit from 'express-rate-limit';\r\n\r\nimport { log } from '../../logger.js';\r\n\r\nimport ExportError from '../../errors/ExportError.js';\r\n\r\n/**\r\n * Middleware for enabling rate limiting on the specified Express app.\r\n *\r\n * @param {Express} app - The Express app instance.\r\n *\r\n * @param {Object} rateLimitingOptions - The configuration object containing\r\n * `rateLimiting` options.\r\n *\r\n * @throws {ExportError} Throws an `ExportError` if could not configure and set\r\n * the rate limiting options.\r\n */\r\nexport default function rateLimitingMiddleware(app, rateLimitingOptions) {\r\n try {\r\n // Check if the rate limiting is enabled\r\n if (rateLimitingOptions.enable) {\r\n const message =\r\n 'Too many requests, you have been rate limited. Please try again later.';\r\n\r\n // Options for the rate limiter\r\n const rateOptions = {\r\n window: rateLimitingOptions.window || 1,\r\n maxRequests: rateLimitingOptions.maxRequests || 30,\r\n delay: rateLimitingOptions.delay || 0,\r\n trustProxy: rateLimitingOptions.trustProxy || false,\r\n skipKey: rateLimitingOptions.skipKey || null,\r\n skipToken: rateLimitingOptions.skipToken || null\r\n };\r\n\r\n // Set if behind a proxy\r\n if (rateOptions.trustProxy) {\r\n app.enable('trust proxy');\r\n }\r\n\r\n // Create a limiter\r\n const limiter = rateLimit({\r\n // Time frame for which requests are checked and remembered\r\n windowMs: rateOptions.window * 60 * 1000,\r\n // Limit each IP to 100 requests per `windowMs`\r\n limit: rateOptions.maxRequests,\r\n // Disable delaying, full speed until the max limit is reached\r\n delayMs: rateOptions.delay,\r\n handler: (request, response) => {\r\n response.format({\r\n json: () => {\r\n response.status(429).send({ message });\r\n },\r\n default: () => {\r\n response.status(429).send(message);\r\n }\r\n });\r\n },\r\n skip: (request) => {\r\n // Allow bypassing the limiter if a valid key/token has been sent\r\n if (\r\n rateOptions.skipKey !== null &&\r\n rateOptions.skipToken !== null &&\r\n request.query.key === rateOptions.skipKey &&\r\n request.query.access_token === rateOptions.skipToken\r\n ) {\r\n log(4, '[rate limiting] Skipping rate limiter.');\r\n return true;\r\n }\r\n return false;\r\n }\r\n });\r\n\r\n // Use a limiter as a middleware\r\n app.use(limiter);\r\n\r\n log(\r\n 3,\r\n `[rate limiting] Enabled rate limiting with ${rateOptions.maxRequests} requests per ${rateOptions.window} minute for each IP, trusting proxy: ${rateOptions.trustProxy}.`\r\n );\r\n }\r\n } catch (error) {\r\n throw new ExportError(\r\n '[rate limiting] Could not configure and set the rate limiting options.',\r\n 500\r\n ).setError(error);\r\n }\r\n}\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * @overview Provides middleware functions for validating incoming HTTP requests\r\n * in an Express application. This module ensures that requests contain\r\n * appropriate content types and valid request bodies, including proper JSON\r\n * structures and chart data for exports. It checks for potential issues such\r\n * as missing or malformed data, private range URLs in SVG payloads, and allows\r\n * for flexible options validation. The middleware logs detailed information\r\n * and handles errors related to incorrect payloads, chart data, and private URL\r\n * usage.\r\n */\r\n\r\nimport { v4 as uuid } from 'uuid';\r\n\r\nimport { getAllowCodeExecution } from '../../chart.js';\r\nimport { isAllowedConfig, validateOptions } from '../../config.js';\r\nimport { log, logZodIssues } from '../../logger.js';\r\nimport {\r\n fixConstr,\r\n fixType,\r\n isObjectEmpty,\r\n isPrivateRangeUrlFound\r\n} from '../../utils.js';\r\nimport { looseValidate } from '../../validation.js';\r\n\r\nimport ExportError from '../../errors/ExportError.js';\r\n\r\n/**\r\n * Middleware for validating the content-type header.\r\n *\r\n * @function contentTypeMiddleware\r\n *\r\n * @param {Express.Request} request - The Express request object.\r\n * @param {Express.Response} response - The Express response object.\r\n * @param {Function} next - The next middleware function.\r\n *\r\n * @returns {undefined} The call to the next middleware function.\r\n *\r\n * @throws {ExportError} Throws an `ExportError` if the content-type\r\n * is not correct.\r\n */\r\nfunction contentTypeMiddleware(request, response, next) {\r\n try {\r\n // Get the content type header\r\n const contentType = request.headers['content-type'] || '';\r\n\r\n // Allow only JSON, URL-encoded and form data without files types of data\r\n if (\r\n !contentType.includes('application/json') &&\r\n !contentType.includes('application/x-www-form-urlencoded') &&\r\n !contentType.includes('multipart/form-data')\r\n ) {\r\n throw new ExportError(\r\n '[validation] Content-Type must be application/json, application/x-www-form-urlencoded, or multipart/form-data.',\r\n 415\r\n );\r\n }\r\n\r\n // Call the `requestBodyMiddleware` middleware\r\n return next();\r\n } catch (error) {\r\n return next(error);\r\n }\r\n}\r\n\r\n/**\r\n * Middleware for validating the request's body.\r\n *\r\n * @function requestBodyMiddleware\r\n *\r\n * @param {Express.Request} request - The Express request object.\r\n * @param {Express.Response} response - The Express response object.\r\n * @param {Function} next - The next middleware function.\r\n *\r\n * @returns {undefined} The call to the next middleware function.\r\n *\r\n * @throws {ExportError} Throws an `ExportError` if the body is not correct.\r\n * @throws {ExportError} Throws an `ExportError` if the chart data from the body\r\n * is not correct.\r\n * @throws {ExportError} Throws an `ExportError` in case of the private range\r\n * url error.\r\n */\r\nfunction requestBodyMiddleware(request, response, next) {\r\n try {\r\n // Get the request body\r\n const body = request.body;\r\n\r\n // Create a unique ID for a request\r\n const requestId = uuid();\r\n\r\n // Throw an error if there is no correct body\r\n if (!body || isObjectEmpty(body)) {\r\n log(\r\n 2,\r\n `[validation] Request [${requestId}] - The request from ${\r\n request.headers['x-forwarded-for'] || request.connection.remoteAddress\r\n } was incorrect. Received payload is empty.`\r\n );\r\n\r\n throw new ExportError(\r\n `[validation] Request [${requestId}] - The request body is required. Please ensure that your Content-Type header is correct. Accepted types are 'application/json' and 'multipart/form-data'.`,\r\n 400\r\n );\r\n }\r\n\r\n // Get the `allowCodeExecution` option for the server\r\n const allowCodeExecution = getAllowCodeExecution();\r\n\r\n // Find a correct chart options\r\n const instr = isAllowedConfig(\r\n // Use one of the below\r\n body.instr || body.options || body.infile || body.data,\r\n // Stringify options\r\n true,\r\n // Allow or disallow functions\r\n allowCodeExecution\r\n );\r\n\r\n // Throw an error if there is no correct chart data\r\n if (instr === null && !body.svg) {\r\n log(\r\n 2,\r\n `[validation] Request [${requestId}] - The request from ${\r\n request.headers['x-forwarded-for'] || request.connection.remoteAddress\r\n } was incorrect. Received payload is missing correct chart data for export: ${JSON.stringify(body)}.`\r\n );\r\n\r\n throw new ExportError(\r\n `Request [${requestId}] - [validation] No correct chart data found. Ensure that you are using either application/json or multipart/form-data headers. If sending JSON, make sure the chart data is in the 'infile', 'options', or 'data' attribute. If sending SVG, ensure it is in the 'svg' attribute.`,\r\n 400\r\n );\r\n }\r\n\r\n // Throw an error if test of xlink:href elements from payload's SVG fails\r\n if (body.svg && isPrivateRangeUrlFound(body.svg)) {\r\n throw new ExportError(\r\n `Request [${requestId}] - [validation] SVG potentially contain at least one forbidden URL in 'xlink:href' element. Please review the SVG content and ensure that all referenced URLs comply with security policies.`,\r\n 400\r\n );\r\n }\r\n\r\n // Validate the request options and store parsed structure in the request\r\n request.validatedOptions = validateOptions({\r\n // Set the created ID as a `requestId` property in the options\r\n requestId,\r\n export: {\r\n instr,\r\n svg: body.svg,\r\n outfile:\r\n body.outfile ||\r\n `${request.params.filename || 'chart'}.${body.type || 'png'}`,\r\n type: body.type,\r\n constr: body.constr,\r\n b64: body.b64,\r\n noDownload: body.noDownload,\r\n height: body.height,\r\n width: body.width,\r\n scale: body.scale,\r\n globalOptions: isAllowedConfig(\r\n body.globalOptions,\r\n true,\r\n allowCodeExecution\r\n ),\r\n themeOptions: isAllowedConfig(\r\n body.themeOptions,\r\n true,\r\n allowCodeExecution\r\n )\r\n },\r\n customLogic: {\r\n allowCodeExecution,\r\n allowFileResources: false,\r\n customCode: body.customCode,\r\n callback: body.callback,\r\n resources: isAllowedConfig(body.resources, true, allowCodeExecution)\r\n }\r\n });\r\n\r\n // Call the next middleware\r\n return next();\r\n } catch (error) {\r\n return next(error);\r\n }\r\n}\r\n\r\n/**\r\n * Adds the validation middlewares to the passed express app instance.\r\n *\r\n * @param {Express} app - The Express app instance.\r\n */\r\nexport default function validationMiddleware(app) {\r\n // Add content type validation middleware\r\n app.post(['/', '/:filename'], contentTypeMiddleware);\r\n\r\n // Add request body request validation middleware\r\n app.post(['/', '/:filename'], requestBodyMiddleware);\r\n}\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * @overview Defines the export routes and logic for handling chart export\r\n * requests in an Express server. This module processes incoming requests\r\n * to export charts in various formats (e.g. JPEG, PNG, PDF, SVG). It integrates\r\n * with Highcharts' core functionalities and supports both immediate download\r\n * responses and Base64-encoded content returns. The code also features\r\n * benchmarking for performance monitoring.\r\n */\r\n\r\nimport { startExport } from '../../chart.js';\r\nimport { log } from '../../logger.js';\r\nimport { getBase64, measureTime } from '../../utils.js';\r\n\r\nimport ExportError from '../../errors/ExportError.js';\r\n\r\n// Reversed MIME types\r\nconst reversedMime = {\r\n png: 'image/png',\r\n jpeg: 'image/jpeg',\r\n gif: 'image/gif',\r\n pdf: 'application/pdf',\r\n svg: 'image/svg+xml'\r\n};\r\n\r\n/**\r\n * Handles the export requests from the client.\r\n *\r\n * @async\r\n * @function requestExport\r\n *\r\n * @param {Express.Request} request - The Express request object.\r\n * @param {Express.Response} response - The Express response object.\r\n * @param {Function} next - The next middleware function.\r\n *\r\n * @returns {Promise} A Promise that resolves once the export process\r\n * is complete.\r\n */\r\nasync function requestExport(request, response, next) {\r\n try {\r\n // Start counting time for a request\r\n const requestCounter = measureTime();\r\n\r\n // In case the connection is closed, force to abort further actions\r\n let connectionAborted = false;\r\n request.socket.on('close', (hadErrors) => {\r\n if (hadErrors) {\r\n connectionAborted = true;\r\n }\r\n });\r\n\r\n // Get the options previously validated in the validation middleware\r\n const requestOptions = request.validatedOptions;\r\n\r\n // Get the request id\r\n const requestId = requestOptions.requestId;\r\n\r\n // Info about an incoming request with correct data\r\n log(4, `[export] Request [${requestId}] - Got an incoming HTTP request.`);\r\n\r\n // Start the export process\r\n await startExport(requestOptions, (error, data) => {\r\n // Remove the close event from the socket\r\n request.socket.removeAllListeners('close');\r\n\r\n // If the connection was closed, do nothing\r\n if (connectionAborted) {\r\n log(\r\n 3,\r\n `[export] Request [${requestId}] - The client closed the connection before the chart finished processing.`\r\n );\r\n return;\r\n }\r\n\r\n // If error, log it and send it to the error middleware\r\n if (error) {\r\n throw error;\r\n }\r\n\r\n // If data is missing, log the message and send it to the error middleware\r\n if (!data || !data.result) {\r\n log(\r\n 2,\r\n `[export] Request [${requestId}] - Request from ${\r\n request.headers['x-forwarded-for'] ||\r\n request.connection.remoteAddress\r\n } was incorrect. Received result is ${data.result}.`\r\n );\r\n\r\n throw new ExportError(\r\n `[export] Request [${requestId}] - Unexpected return of the export result from the chart generation. Please check your request data.`,\r\n 400\r\n );\r\n }\r\n\r\n // Return the result in an appropriate format\r\n if (data.result) {\r\n log(\r\n 3,\r\n `[export] Request [${requestId}] - The whole exporting process took ${requestCounter()}ms.`\r\n );\r\n\r\n // Get the `type`, `b64`, `noDownload`, and `outfile` from options\r\n const { type, b64, noDownload, outfile } = data.options.export;\r\n\r\n // If only Base64 is required, return it\r\n if (b64) {\r\n return response.send(getBase64(data.result, type));\r\n }\r\n\r\n // Set correct content type\r\n response.header('Content-Type', reversedMime[type] || 'image/png');\r\n\r\n // Decide whether to download or not chart file\r\n if (!noDownload) {\r\n response.attachment(outfile);\r\n }\r\n\r\n // If SVG, return plain content, otherwise a b64 string from a buffer\r\n return type === 'svg'\r\n ? response.send(data.result)\r\n : response.send(Buffer.from(data.result, 'base64'));\r\n }\r\n });\r\n } catch (error) {\r\n return next(error);\r\n }\r\n}\r\n\r\n/**\r\n * Adds the `export` routes.\r\n *\r\n * @function exportRoutes\r\n *\r\n * @param {Express} app - The Express app instance.\r\n */\r\nexport default function exportRoutes(app) {\r\n /**\r\n * Adds the POST '/' - A route for handling POST requests at the root\r\n * endpoint.\r\n */\r\n app.post('/', requestExport);\r\n\r\n /**\r\n * Adds the POST '/:filename' - A route for handling POST requests with\r\n * a specified filename parameter.\r\n */\r\n app.post('/:filename', requestExport);\r\n}\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * @overview Defines an Express route for server health monitoring, including\r\n * uptime, success rates, and other server statistics.\r\n */\r\n\r\nimport { readFileSync } from 'fs';\r\nimport { join } from 'path';\r\n\r\nimport { getHighchartsVersion } from '../../cache.js';\r\nimport { log } from '../../logger.js';\r\nimport { getPoolStats, getPoolInfoJSON } from '../../pool.js';\r\nimport { addTimer } from '../../timer.js';\r\nimport { __dirname, getNewDateTime } from '../../utils.js';\r\n\r\n// Set the start date of the server\r\nconst serverStartTime = new Date();\r\n\r\n// Get the `package.json` content\r\nconst packageFile = JSON.parse(\r\n readFileSync(join(__dirname, 'package.json'), 'utf8')\r\n);\r\n\r\n// An array for success rate ratios\r\nconst successRates = [];\r\n\r\n// Record every minute\r\nconst recordInterval = 60 * 1000;\r\n\r\n// 30 minutes\r\nconst windowSize = 30;\r\n\r\n/**\r\n * Calculates moving average indicator based on the data from the `successRates`\r\n * array.\r\n *\r\n * @function _calculateMovingAverage\r\n *\r\n * @returns {number} A moving average for success ratio of the server exports.\r\n */\r\nfunction _calculateMovingAverage() {\r\n return successRates.reduce((a, b) => a + b, 0) / successRates.length;\r\n}\r\n\r\n/**\r\n * Starts the interval responsible for calculating current success rate ratio\r\n * and collects records to the `successRates` array.\r\n *\r\n * @function _startSuccessRate\r\n *\r\n * @returns {NodeJS.Timeout} Id of an interval.\r\n */\r\nfunction _startSuccessRate() {\r\n return setInterval(() => {\r\n const stats = getPoolStats();\r\n const successRatio =\r\n stats.exportsAttempted === 0\r\n ? 1\r\n : (stats.exportsPerformed / stats.exportsAttempted) * 100;\r\n\r\n successRates.push(successRatio);\r\n if (successRates.length > windowSize) {\r\n successRates.shift();\r\n }\r\n }, recordInterval);\r\n}\r\n\r\n/**\r\n * Adds the `health` routes.\r\n *\r\n * @function healthRoutes\r\n *\r\n * @param {Express} app - The Express app instance.\r\n */\r\nexport default function healthRoutes(app) {\r\n // Start processing success rate ratio interval and save its id to the array\r\n // for the graceful clearing on shutdown with injected `addTimer` funtion\r\n addTimer(_startSuccessRate());\r\n\r\n /**\r\n * Adds the GET '/health' - A route for getting the basic stats of the server.\r\n */\r\n app.get('/health', (request, response, next) => {\r\n try {\r\n log(4, '[health] Returning server health.');\r\n\r\n const stats = getPoolStats();\r\n const period = successRates.length;\r\n const movingAverage = _calculateMovingAverage();\r\n\r\n // Send the server's statistics\r\n response.send({\r\n // Status and times\r\n status: 'OK',\r\n bootTime: serverStartTime,\r\n uptime: `${Math.floor((getNewDateTime() - serverStartTime.getTime()) / 1000 / 60)} minutes`,\r\n\r\n // Versions\r\n serverVersion: packageFile.version,\r\n highchartsVersion: getHighchartsVersion(),\r\n\r\n // Exports\r\n averageExportTime: stats.timeSpentAverage,\r\n attemptedExports: stats.exportsAttempted,\r\n performedExports: stats.exportsPerformed,\r\n failedExports: stats.exportsDropped,\r\n sucessRatio: (stats.exportsPerformed / stats.exportsAttempted) * 100,\r\n\r\n // Pool\r\n pool: getPoolInfoJSON(),\r\n\r\n // Moving average\r\n period,\r\n movingAverage,\r\n message:\r\n isNaN(movingAverage) || !successRates.length\r\n ? 'Too early to report. No exports made yet. Please check back soon.'\r\n : `Last ${period} minutes had a success rate of ${movingAverage.toFixed(2)}%.`,\r\n\r\n // SVG and JSON exports\r\n svgExports: stats.exportsFromSvg,\r\n jsonExports: stats.exportsFromOptions,\r\n svgExportsAttempts: stats.exportsFromSvgAttempts,\r\n jsonExportsAttempts: stats.exportsFromOptionsAttempts\r\n });\r\n } catch (error) {\r\n return next(error);\r\n }\r\n });\r\n}\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * @overview Defines an Express route for serving the UI for the export server\r\n * when enabled.\r\n */\r\n\r\nimport { join } from 'path';\r\n\r\nimport { getOptions } from '../../config.js';\r\nimport { log } from '../../logger.js';\r\nimport { __dirname } from '../../utils.js';\r\n\r\n/**\r\n * Adds the `ui` routes.\r\n *\r\n * @function uiRoutes\r\n *\r\n * @param {Express} app - The Express app instance.\r\n */\r\nexport default function uiRoutes(app) {\r\n /**\r\n * Adds the GET '/' - A route for a UI when enabled on the export server.\r\n */\r\n app.get(getOptions().ui.route || '/', (request, response, next) => {\r\n try {\r\n log(4, '[ui] Returning UI for the export.');\r\n\r\n response.sendFile(join(__dirname, 'public', 'index.html'), {\r\n acceptRanges: false\r\n });\r\n } catch (error) {\r\n return next(error);\r\n }\r\n });\r\n}\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * @overview Defines an Express route for updating the Highcharts version\r\n * on the server, with authentication and validation.\r\n */\r\n\r\nimport { updateHighchartsVersion, getHighchartsVersion } from '../../cache.js';\r\nimport { validateOption } from '../../config.js';\r\nimport { log } from '../../logger.js';\r\nimport { envs } from '../../validation.js';\r\n\r\nimport ExportError from '../../errors/ExportError.js';\r\n\r\n/**\r\n * Adds the `version_change` routes.\r\n *\r\n * @function versionChangeRoutes\r\n *\r\n * @param {Express} app - The Express app instance.\r\n */\r\nexport default function versionChangeRoutes(app) {\r\n /**\r\n * Adds the POST '/version_change/:newVersion' - A route for changing\r\n * the Highcharts version on the server.\r\n */\r\n app.post('/version_change/:newVersion', async (request, response, next) => {\r\n try {\r\n log(4, '[version] Changing Highcharts version.');\r\n\r\n // Get the token directly from envs\r\n const adminToken = envs.HIGHCHARTS_ADMIN_TOKEN;\r\n\r\n // Check the existence of the token\r\n if (!adminToken || !adminToken.length) {\r\n throw new ExportError(\r\n '[version] The server is not configured to perform run-time version changes: HIGHCHARTS_ADMIN_TOKEN is not set.',\r\n 401\r\n );\r\n }\r\n\r\n // Get the token from the hc-auth header\r\n const token = request.get('hc-auth');\r\n\r\n // Check if the hc-auth header contain a correct token\r\n if (!token || token !== adminToken) {\r\n throw new ExportError(\r\n '[version] Invalid or missing token: Set the token in the hc-auth header.',\r\n 401\r\n );\r\n }\r\n\r\n // Compare versions\r\n let newVersion = request.params.newVersion;\r\n\r\n // Validate the version\r\n try {\r\n newVersion = validateOption('version', request.params.newVersion);\r\n } catch (error) {\r\n throw new ExportError(\r\n `[version] Version is incorrect: ${error.message}`,\r\n 400\r\n ).setError(error);\r\n }\r\n\r\n // When a correct value found\r\n if (newVersion) {\r\n try {\r\n // Update version\r\n await updateHighchartsVersion(newVersion);\r\n } catch (error) {\r\n throw new ExportError(\r\n `[version] Version change: ${error.message}`,\r\n 400\r\n ).setError(error);\r\n }\r\n\r\n // Success\r\n response.status(200).send({\r\n statusCode: 200,\r\n highchartsVersion: getHighchartsVersion(),\r\n message: `Successfully updated Highcharts to version: ${newVersion}.`\r\n });\r\n } else {\r\n // No version specified\r\n throw new ExportError('[version] No new version supplied.', 400);\r\n }\r\n } catch (error) {\r\n return next(error);\r\n }\r\n });\r\n}\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * @overview A module that sets up and manages HTTP and HTTPS servers\r\n * for the Highcharts Export Server. It handles server initialization,\r\n * configuration, error handling, middleware setup, route definition, and rate\r\n * limiting. The module exports functions to start, stop, and manage server\r\n * instances, as well as utility functions for defining routes and attaching\r\n * middlewares.\r\n */\r\n\r\nimport { readFile } from 'fs/promises';\r\nimport { join } from 'path';\r\n\r\nimport cors from 'cors';\r\nimport express from 'express';\r\nimport http from 'http';\r\nimport https from 'https';\r\nimport multer from 'multer';\r\n\r\nimport { updateOptions, validateOptions } from '../config.js';\r\nimport { log, logWithStack } from '../logger.js';\r\nimport { __dirname, getAbsolutePath } from '../utils.js';\r\n\r\nimport errorMiddleware from './middlewares/error.js';\r\nimport rateLimitingMiddleware from './middlewares/rateLimiting.js';\r\nimport validationMiddleware from './middlewares/validation.js';\r\n\r\nimport exportRoutes from './routes/export.js';\r\nimport healthRoutes from './routes/health.js';\r\nimport uiRoutes from './routes/ui.js';\r\nimport versionChangeRoutes from './routes/versionChange.js';\r\n\r\nimport ExportError from '../errors/ExportError.js';\r\n\r\n// Array of an active servers\r\nconst activeServers = new Map();\r\n\r\n// Create express app\r\nconst app = express();\r\n\r\n/**\r\n * Starts an HTTP and/or HTTPS server based on the provided configuration.\r\n * The `serverOptions` object contains server-related properties (refer\r\n * to the `server` section in the `lib/schemas/config.js` file for details).\r\n *\r\n * @async\r\n * @function startServer\r\n *\r\n * @param {Object} serverOptions - The configuration object containing `server`\r\n * options. This object may include a partial or complete set of the `server`\r\n * options. If the options are partial, missing values will default\r\n * to the current global configuration.\r\n *\r\n * @returns {Promise} A Promise that resolves when the server is either\r\n * not enabled or no valid Express app is found, signaling the end of the\r\n * function's execution.\r\n *\r\n * @throws {ExportError} Throws an `ExportError` if the server cannot\r\n * be configured and started.\r\n */\r\nexport async function startServer(serverOptions) {\r\n try {\r\n // Update the instance options object\r\n const options = updateOptions(\r\n validateOptions({\r\n server: serverOptions\r\n })\r\n );\r\n\r\n // Use validated options\r\n serverOptions = options.server;\r\n\r\n // Stop if not enabled\r\n if (!serverOptions.enable || !app) {\r\n throw new ExportError(\r\n '[server] Server cannot be started (not enabled or no correct Express app found).',\r\n 500\r\n );\r\n }\r\n\r\n // Too big limits lead to timeouts in the export process when\r\n // the rasterization timeout is set too low\r\n const uploadLimitBytes = serverOptions.uploadLimit * 1024 * 1024;\r\n\r\n // Memory storage for multer package\r\n const storage = multer.memoryStorage();\r\n\r\n // Enable parsing of form data (files) with multer package\r\n const upload = multer({\r\n storage,\r\n limits: {\r\n fieldSize: uploadLimitBytes\r\n }\r\n });\r\n\r\n // Disable the X-Powered-By header\r\n app.disable('x-powered-by');\r\n\r\n // Enable CORS support\r\n app.use(\r\n cors({\r\n methods: ['POST', 'GET', 'OPTIONS']\r\n })\r\n );\r\n\r\n // Getting a lot of `RangeNotSatisfiableError` exceptions (even though this\r\n // is a deprecated options, let's try to set it to false)\r\n app.use((request, response, next) => {\r\n response.set('Accept-Ranges', 'none');\r\n next();\r\n });\r\n\r\n // Enable body parser for JSON data\r\n app.use(\r\n express.json({\r\n limit: uploadLimitBytes\r\n })\r\n );\r\n\r\n // Enable body parser for URL-encoded form data\r\n app.use(\r\n express.urlencoded({\r\n extended: true,\r\n limit: uploadLimitBytes\r\n })\r\n );\r\n\r\n // Use only non-file multipart form fields\r\n app.use(upload.none());\r\n\r\n // Set up static folder's route\r\n app.use(express.static(join(__dirname, 'public')));\r\n\r\n // Listen HTTP server\r\n if (!serverOptions.ssl.force) {\r\n // Main server instance (HTTP)\r\n const httpServer = http.createServer(app);\r\n\r\n // Attach error handlers and listen to the server\r\n _attachServerErrorHandlers(httpServer);\r\n\r\n // Listen\r\n httpServer.listen(serverOptions.port, serverOptions.host, () => {\r\n // Save the reference to HTTP server\r\n activeServers.set(serverOptions.port, httpServer);\r\n\r\n log(\r\n 3,\r\n `[server] Started HTTP server on ${serverOptions.host}:${serverOptions.port}.`\r\n );\r\n });\r\n }\r\n\r\n // Listen HTTPS server\r\n if (serverOptions.ssl.enable) {\r\n // Set up an SSL server also\r\n let key, cert;\r\n\r\n try {\r\n // Get the SSL key\r\n key = await readFile(\r\n join(getAbsolutePath(serverOptions.ssl.certPath), 'server.key'),\r\n 'utf8'\r\n );\r\n\r\n // Get the SSL certificate\r\n cert = await readFile(\r\n join(getAbsolutePath(serverOptions.ssl.certPath), 'server.crt'),\r\n 'utf8'\r\n );\r\n } catch (error) {\r\n log(\r\n 2,\r\n `[server] Unable to load key/certificate from the '${serverOptions.ssl.certPath}' path. Could not run secured layer server.`\r\n );\r\n }\r\n\r\n if (key && cert) {\r\n // Main server instance (HTTPS)\r\n const httpsServer = https.createServer({ key, cert }, app);\r\n\r\n // Attach error handlers and listen to the server\r\n _attachServerErrorHandlers(httpsServer);\r\n\r\n // Listen\r\n httpsServer.listen(serverOptions.ssl.port, serverOptions.host, () => {\r\n // Save the reference to HTTPS server\r\n activeServers.set(serverOptions.ssl.port, httpsServer);\r\n\r\n log(\r\n 3,\r\n `[server] Started HTTPS server on ${serverOptions.host}:${serverOptions.ssl.port}.`\r\n );\r\n });\r\n }\r\n }\r\n\r\n // Set up the rate limiter\r\n rateLimitingMiddleware(app, serverOptions.rateLimiting);\r\n\r\n // Set up the validation handler\r\n validationMiddleware(app);\r\n\r\n // Set up routes\r\n exportRoutes(app);\r\n healthRoutes(app);\r\n uiRoutes(app);\r\n versionChangeRoutes(app);\r\n\r\n // Set up the centralized error handler\r\n errorMiddleware(app);\r\n } catch (error) {\r\n throw new ExportError(\r\n '[server] Could not configure and start the server.',\r\n 500\r\n ).setError(error);\r\n }\r\n}\r\n\r\n/**\r\n * Closes all servers associated with Express app instance.\r\n *\r\n * @function closeServers\r\n */\r\nexport function closeServers() {\r\n // Check if there are servers working\r\n if (activeServers.size > 0) {\r\n log(4, `[server] Closing all servers.`);\r\n\r\n // Close each one of servers\r\n for (const [port, server] of activeServers) {\r\n server.close(() => {\r\n activeServers.delete(port);\r\n log(4, `[server] Closed server on port: ${port}.`);\r\n });\r\n }\r\n }\r\n}\r\n\r\n/**\r\n * Get all servers associated with Express app instance.\r\n *\r\n * @function getServers\r\n *\r\n * @returns {Array.} Servers associated with Express app instance.\r\n */\r\nexport function getServers() {\r\n return activeServers;\r\n}\r\n\r\n/**\r\n * Get the Express instance.\r\n *\r\n * @function getExpress\r\n *\r\n * @returns {Express} The Express instance.\r\n */\r\nexport function getExpress() {\r\n return express;\r\n}\r\n\r\n/**\r\n * Get the Express app instance.\r\n *\r\n * @function getApp\r\n *\r\n * @returns {Express} The Express app instance.\r\n */\r\nexport function getApp() {\r\n return app;\r\n}\r\n\r\n/**\r\n * Enable rate limiting for the server.\r\n *\r\n * @function enableRateLimiting\r\n *\r\n * @param {Object} rateLimitingOptions - The configuration object containing\r\n * `rateLimiting` options. This object may include a partial or complete set\r\n * of the `rateLimiting` options. If the options are partial, missing values\r\n * will default to the current global configuration.\r\n */\r\nexport function enableRateLimiting(rateLimitingOptions) {\r\n // Update the instance options object\r\n const options = updateOptions(\r\n validateOptions({\r\n server: {\r\n rateLimiting: rateLimitingOptions\r\n }\r\n })\r\n );\r\n\r\n // Set the rate limiting options\r\n rateLimitingMiddleware(app, options.server.rateLimitingOptions);\r\n}\r\n\r\n/**\r\n * Apply middleware(s) to a specific path.\r\n *\r\n * @function use\r\n *\r\n * @param {string} path - The path to which the middleware(s) should be applied.\r\n * @param {...Function} middlewares - The middleware function(s) to be applied.\r\n */\r\nexport function use(path, ...middlewares) {\r\n app.use(path, ...middlewares);\r\n}\r\n\r\n/**\r\n * Set up a route with GET method and apply middleware(s).\r\n *\r\n * @function get\r\n *\r\n * @param {string} path - The path to which the middleware(s) should be applied.\r\n * @param {...Function} middlewares - The middleware function(s) to be applied.\r\n */\r\nexport function get(path, ...middlewares) {\r\n app.get(path, ...middlewares);\r\n}\r\n\r\n/**\r\n * Set up a route with POST method and apply middleware(s).\r\n *\r\n * @function post\r\n *\r\n * @param {string} path - The path to which the middleware(s) should be applied.\r\n * @param {...Function} middlewares - The middleware function(s) to be applied.\r\n */\r\nexport function post(path, ...middlewares) {\r\n app.post(path, ...middlewares);\r\n}\r\n\r\n/**\r\n * Attach error handlers to the server.\r\n *\r\n * @function _attachServerErrorHandlers\r\n *\r\n * @param {(http.Server|https.Server)} server - The HTTP/HTTPS server instance.\r\n */\r\nfunction _attachServerErrorHandlers(server) {\r\n server.on('clientError', (error, socket) => {\r\n logWithStack(\r\n 1,\r\n error,\r\n `[server] Client error: ${error.message}, destroying socket.`\r\n );\r\n socket.destroy();\r\n });\r\n\r\n server.on('error', (error) => {\r\n logWithStack(1, error, `[server] Server error: ${error.message}`);\r\n });\r\n\r\n server.on('connection', (socket) => {\r\n socket.on('error', (error) => {\r\n logWithStack(1, error, `[server] Socket error: ${error.message}`);\r\n });\r\n });\r\n}\r\n\r\nexport default {\r\n startServer,\r\n closeServers,\r\n getServers,\r\n getExpress,\r\n getApp,\r\n enableRateLimiting,\r\n use,\r\n get,\r\n post\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * @overview Handles graceful shutdown of the Highcharts Export Server, ensuring\r\n * proper cleanup of resources such as browser, pages, servers, and timers.\r\n */\r\n\r\nimport { killPool } from './pool.js';\r\nimport { clearAllTimers } from './timer.js';\r\n\r\nimport { closeServers } from './server/server.js';\r\n\r\n/**\r\n * Performs cleanup operations to ensure a graceful shutdown of the process.\r\n * This includes clearing all registered timeouts/intervals, closing active\r\n * servers, terminating resources (pages) of the pool, pool itself, and closing\r\n * the browser.\r\n *\r\n * @function shutdownCleanUp\r\n *\r\n * @param {number} [exitCode=0] - The exit code to use with `process.exit()`.\r\n * The default value is `0`.\r\n */\r\nexport async function shutdownCleanUp(exitCode = 0) {\r\n // Await freeing all resources\r\n await Promise.allSettled([\r\n // Clear all ongoing intervals\r\n clearAllTimers(),\r\n\r\n // Get available server instances (HTTP/HTTPS) and close them\r\n closeServers(),\r\n\r\n // Close an active pool along with its workers and the browser instance\r\n killPool()\r\n ]);\r\n\r\n // Exit process with a correct code\r\n process.exit(exitCode);\r\n}\r\n\r\nexport default {\r\n shutdownCleanUp\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * @overview Core module for initializing and managing the Highcharts Export\r\n * Server. Provides functionalities for configuring exports, setting up server\r\n * operations, logging, scripts caching, resource pooling, and graceful process\r\n * cleanup.\r\n */\r\n\r\nimport 'colors';\r\n\r\nimport { checkAndUpdateCache } from './cache.js';\r\nimport {\r\n singleExport,\r\n batchExport,\r\n startExport,\r\n setAllowCodeExecution\r\n} from './chart.js';\r\nimport {\r\n getOptions,\r\n updateOptions,\r\n setGlobalOptions,\r\n mapToNewOptions,\r\n validateOption,\r\n validateOptions\r\n} from './config.js';\r\nimport {\r\n log,\r\n logWithStack,\r\n logZodIssues,\r\n initLogging,\r\n enableConsoleLogging,\r\n enableFileLogging,\r\n setLogLevel\r\n} from './logger.js';\r\nimport { initPool, killPool } from './pool.js';\r\nimport { shutdownCleanUp } from './resourceRelease.js';\r\n\r\nimport server from './server/server.js';\r\n\r\n/**\r\n * Initializes the export process. Tasks such as configuring logging, checking\r\n * the cache and sources, and initializing the resource pool occur during this\r\n * stage.\r\n *\r\n * This function must be called before attempting to export charts or set\r\n * up a server.\r\n *\r\n * @async\r\n * @function initExport\r\n *\r\n * @param {Object} [initOptions={}] - The `initOptions` object, which may\r\n * be a partial or complete set of options. If the options are partial, missing\r\n * values will default to the current global configuration. The default value\r\n * is an empty object.\r\n */\r\nexport async function initExport(initOptions = {}) {\r\n // Init, validate and update the instance options object\r\n const options = updateOptions(validateOptions(initOptions), true);\r\n\r\n // Set the `allowCodeExecution` per export module scope\r\n setAllowCodeExecution(options.customLogic.allowCodeExecution);\r\n\r\n // Init the logging\r\n initLogging(options.logging);\r\n\r\n // Attach process' exit listeners\r\n if (options.other.listenToProcessExits) {\r\n _attachProcessExitListeners();\r\n }\r\n\r\n // Check if cache needs to be updated\r\n await checkAndUpdateCache(options.highcharts, options.server.proxy);\r\n\r\n // Init the pool\r\n await initPool(options.pool, options.puppeteer.args);\r\n}\r\n\r\n/**\r\n * Attaches exit listeners to the process, ensuring proper cleanup of resources\r\n * and termination on exit signals. Handles 'exit', 'SIGINT', 'SIGTERM'\r\n * and 'uncaughtException' events.\r\n *\r\n * @function _attachProcessExitListeners\r\n */\r\nfunction _attachProcessExitListeners() {\r\n log(3, '[process] Attaching exit listeners to the process.');\r\n\r\n // Handler for the 'exit'\r\n process.on('exit', (code) => {\r\n log(4, `[process] Process exited with code ${code}.`);\r\n });\r\n\r\n // Handler for the 'SIGINT'\r\n process.on('SIGINT', async (name, code) => {\r\n log(4, `[process] The ${name} event with code: ${code}.`);\r\n await shutdownCleanUp();\r\n });\r\n\r\n // Handler for the 'SIGTERM'\r\n process.on('SIGTERM', async (name, code) => {\r\n log(4, `[process] The ${name} event with code: ${code}.`);\r\n await shutdownCleanUp();\r\n });\r\n\r\n // Handler for the 'SIGHUP'\r\n process.on('SIGHUP', async (name, code) => {\r\n log(4, `[process] The ${name} event with code: ${code}.`);\r\n await shutdownCleanUp();\r\n });\r\n\r\n // Handler for the 'uncaughtException'\r\n process.on('uncaughtException', async (error, name) => {\r\n logWithStack(1, error, `[process] The ${name} error.`);\r\n await shutdownCleanUp(1);\r\n });\r\n}\r\n\r\nexport default {\r\n // Server\r\n ...server,\r\n\r\n // Options\r\n getOptions,\r\n setGlobalOptions,\r\n mapToNewOptions,\r\n\r\n // Validation\r\n validateOption,\r\n validateOptions,\r\n\r\n // Exporting\r\n initExport,\r\n singleExport,\r\n batchExport,\r\n startExport,\r\n\r\n // Release\r\n killPool,\r\n shutdownCleanUp,\r\n\r\n // Logs\r\n log,\r\n logWithStack,\r\n logZodIssues,\r\n setLogLevel: function (level) {\r\n // Update the instance options object\r\n const options = updateOptions(\r\n validateOptions({\r\n logging: {\r\n level\r\n }\r\n })\r\n );\r\n\r\n // Call the function\r\n setLogLevel(options.logging.level);\r\n },\r\n enableConsoleLogging: function (toConsole) {\r\n // Update the instance options object\r\n const options = updateOptions(\r\n validateOptions({\r\n logging: {\r\n toConsole\r\n }\r\n })\r\n );\r\n\r\n // Call the function\r\n enableConsoleLogging(options.logging.toConsole);\r\n },\r\n enableFileLogging: function (dest, file, toFile) {\r\n // Update the instance options object\r\n const options = updateOptions(\r\n validateOptions({\r\n logging: {\r\n dest,\r\n file,\r\n toFile\r\n }\r\n })\r\n );\r\n\r\n // Call the function\r\n enableFileLogging(\r\n options.logging.dest,\r\n options.logging.file,\r\n options.logging.toFile\r\n );\r\n }\r\n};\r\n"],"names":["__dirname","fileURLToPath","URL","url","deepCopy","objArr","objArrCopy","Array","isArray","key","Object","prototype","hasOwnProperty","call","fixConstr","constr","fixedConstr","toLowerCase","replace","includes","fixOutfile","type","outfile","getAbsolutePath","split","shift","fixType","mimeTypes","formats","values","outType","pop","find","t","path","isAbsolute","join","getBase64","input","Buffer","from","toString","getNewDate","Date","trim","getNewDateTime","getTime","isObject","item","isObjectEmpty","keys","length","isPrivateRangeUrlFound","some","pattern","test","measureTime","start","process","hrtime","bigint","Number","roundNumber","value","precision","multiplier","Math","pow","round","wrapAround","customCode","allowFileResources","isCallback","endsWith","readFileSync","startsWith","colors","logging","toConsole","toFile","pathCreated","pathToLog","levelsDesc","title","color","log","args","newLevel","texts","level","prefix","_logToFile","console","apply","undefined","concat","logWithStack","error","customMessage","mainMessage","message","stackMessage","stack","push","logZodIssues","issues","map","issue","initLogging","loggingOptions","dest","file","setLogLevel","enableConsoleLogging","enableFileLogging","isInteger","existsSync","mkdirSync","appendFile","defaultConfig","puppeteer","types","envLink","cliName","description","promptOptions","separator","highcharts","version","cdnUrl","forceFetch","cachePath","coreScripts","instructions","moduleScripts","indicatorScripts","customScripts","export","infile","instr","options","svg","batch","hint","choices","b64","noDownload","height","width","scale","defaultHeight","defaultWidth","defaultScale","min","max","globalOptions","themeOptions","rasterizationTimeout","customLogic","allowCodeExecution","callback","resources","loadConfig","legacyName","createConfig","server","enable","host","port","uploadLimit","benchmarking","proxy","timeout","rateLimiting","maxRequests","window","delay","trustProxy","skipKey","skipToken","ssl","force","certPath","pool","minWorkers","maxWorkers","workLimit","acquireTimeout","createTimeout","destroyTimeout","idleTimeout","createRetryInterval","reaperInterval","ui","route","other","nodeEnv","listenToProcessExits","noLogo","hardResetPage","browserShellMode","validation","debug","headless","devtools","listenToConsole","dumpio","slowMo","debuggingPort","nestedProps","_createNestedProps","absoluteProps","_createAbsoluteProps","config","propChain","forEach","entry","substring","dotenv","z","setErrorMap","_customErrorMap","v","boolean","strictCheck","union","enum","transform","nullable","string","refine","params","errorMessage","stringArray","filterCallback","arraySchema","array","stringSchema","slice","transformCallback","filter","positiveNum","number","positive","isNaN","nonNegativeNum","nonnegative","prefixes","chartConfig","object","passthrough","additionalOptions","validators","adminToken","indexOf","gte","lte","this","objectSchema","js","css","files","partial","stringSchema1","stringSchema2","enableServer","serverBenchmarking","proxyHost","proxyPort","proxyTimeout","enableRateLimiting","enableSsl","sslForce","sslPort","sslCertPath","poolBenchmarking","resourcesInterval","logLevel","int","logFile","logDest","logToConsole","logToFile","enableUi","uiRoute","enableDebug","requestId","uuid","PuppeteerSchema","HighchartsSchema","ExportSchema","CustomLogicSchema","ProxySchema","RateLimitingSchema","SslSchema","ServerSchema","optional","PoolSchema","LoggingSchema","UiSchema","OtherSchema","DebugSchema","StrictConfigSchema","LooseConfigSchema","EnvSchema","PUPPETEER_ARGS","HIGHCHARTS_VERSION","HIGHCHARTS_CDN_URL","HIGHCHARTS_FORCE_FETCH","HIGHCHARTS_CACHE_PATH","HIGHCHARTS_ADMIN_TOKEN","HIGHCHARTS_CORE_SCRIPTS","HIGHCHARTS_MODULE_SCRIPTS","HIGHCHARTS_INDICATOR_SCRIPTS","HIGHCHARTS_CUSTOM_SCRIPTS","EXPORT_INFILE","EXPORT_INSTR","EXPORT_OPTIONS","EXPORT_SVG","EXPORT_BATCH","EXPORT_OUTFILE","EXPORT_TYPE","EXPORT_CONSTR","EXPORT_B64","EXPORT_NO_DOWNLOAD","EXPORT_HEIGHT","EXPORT_WIDTH","EXPORT_SCALE","EXPORT_DEFAULT_HEIGHT","EXPORT_DEFAULT_WIDTH","EXPORT_DEFAULT_SCALE","EXPORT_GLOBAL_OPTIONS","EXPORT_THEME_OPTIONS","EXPORT_RASTERIZATION_TIMEOUT","CUSTOM_LOGIC_ALLOW_CODE_EXECUTION","CUSTOM_LOGIC_ALLOW_FILE_RESOURCES","CUSTOM_LOGIC_CUSTOM_CODE","CUSTOM_LOGIC_CALLBACK","CUSTOM_LOGIC_RESOURCES","CUSTOM_LOGIC_LOAD_CONFIG","CUSTOM_LOGIC_CREATE_CONFIG","SERVER_ENABLE","SERVER_HOST","SERVER_PORT","SERVER_UPLOAD_LIMIT","SERVER_BENCHMARKING","SERVER_PROXY_HOST","SERVER_PROXY_PORT","SERVER_PROXY_TIMEOUT","SERVER_RATE_LIMITING_ENABLE","SERVER_RATE_LIMITING_MAX_REQUESTS","SERVER_RATE_LIMITING_WINDOW","SERVER_RATE_LIMITING_DELAY","SERVER_RATE_LIMITING_TRUST_PROXY","SERVER_RATE_LIMITING_SKIP_KEY","SERVER_RATE_LIMITING_SKIP_TOKEN","SERVER_SSL_ENABLE","SERVER_SSL_FORCE","SERVER_SSL_PORT","SERVER_SSL_CERT_PATH","POOL_MIN_WORKERS","POOL_MAX_WORKERS","POOL_WORK_LIMIT","POOL_ACQUIRE_TIMEOUT","POOL_CREATE_TIMEOUT","POOL_DESTROY_TIMEOUT","POOL_IDLE_TIMEOUT","POOL_CREATE_RETRY_INTERVAL","POOL_REAPER_INTERVAL","POOL_BENCHMARKING","LOGGING_LEVEL","LOGGING_FILE","LOGGING_DEST","LOGGING_TO_CONSOLE","LOGGING_TO_FILE","UI_ENABLE","UI_ROUTE","OTHER_NODE_ENV","OTHER_LISTEN_TO_PROCESS_EXITS","OTHER_NO_LOGO","OTHER_HARD_RESET_PAGE","OTHER_BROWSER_SHELL_MODE","OTHER_VALIDATION","DEBUG_ENABLE","DEBUG_HEADLESS","DEBUG_DEVTOOLS","DEBUG_LISTEN_TO_CONSOLE","DEBUG_DUMPIO","DEBUG_SLOW_MO","DEBUG_DEBUGGING_PORT","envs","parse","env","strictValidate","configOptions","looseValidate","context","propertyName","propertyInfo","code","ZodIssueCode","invalid_type","received","ZodParsedType","defaultError","custom","data","invalid_union","unionErrors","index","ExportError","Error","constructor","statusCode","super","setStatus","setError","name","_initGlobalOptions","instanceOptions","getOptions","getInstance","setGlobalOptions","customOptions","cliArgs","cliOptions","_loadConfigFile","_pairArgumentValue","_updateGlobalOptions","updateOptions","newInstance","mergeOptions","originalOptions","newOptions","entries","mapToNewOptions","oldOptions","propertiesChain","reduce","obj","prop","validateOption","configOption","validateOptions","isAllowedConfig","allowFunctions","objectConfig","eval","JSON","stringifiedOptions","_optionsStringify","parsedOptions","_","envVal","configOpt","cliOpt","customOpt","configVal","cliVal","customVal","stringifyFunctions","stringify","replaceAll","customLogicOptions","configIndex","findIndex","arg","configFileName","i","option","async","fetch","requestOptions","Promise","resolve","reject","_getProtocolModule","get","response","responseData","on","chunk","text","https","http","cache","activeManifest","sources","hcVersion","checkAndUpdateCache","highchartsOptions","serverProxyOptions","fetchedModules","getCachePath","manifestPath","sourcePath","recursive","_updateCache","requestUpdate","manifest","modules","moduleMap","m","numberOfModules","moduleName","extractVersion","_saveConfigToManifest","getHighchartsVersion","updateHighchartsVersion","newVersion","cacheSources","extractModuleName","scriptPath","_fetchAndProcessScript","script","shouldThrowError","newManifest","writeFileSync","_fetchScripts","proxyAgent","HttpsProxyAgent","agent","allFetchPromises","all","c","setupHighcharts","Highcharts","animObject","duration","createChart","exportOptions","setOptions","merge","wrap","setOptionsObj","isRenderComplete","Chart","proceed","userOptions","cb","exporting","enabled","plotOptions","series","label","tooltip","animation","onHighchartsRender","addEvent","Series","chart","Function","finalOptions","finalCallback","defaultOptions","template","browser","createBrowser","puppeteerArgs","enabledDebug","debugOptions","launchOptions","userDataDir","handleSIGINT","handleSIGTERM","handleSIGHUP","waitForInitialPage","defaultViewport","tryCount","open","launch","setTimeout","closeBrowser","connected","close","newPage","poolResource","page","setCacheEnabled","_setPageContent","_setPageEvents","isClosed","clearPage","hardReset","goto","waitUntil","evaluate","document","body","innerHTML","id","workCount","addPageResources","injectedResources","injectedJs","content","isLocal","jsResource","addScriptTag","injectedCss","cssImports","match","cssImportPath","cssResource","addStyleTag","clearPageResources","resource","dispose","oldCharts","charts","oldChart","destroy","scriptsToRemove","getElementsByTagName","stylesToRemove","linksToRemove","element","remove","setContent","cssTemplate","svgTemplate","puppeteerExport","isSVG","size","svgElement","querySelector","chartHeight","baseVal","chartWidth","style","zoom","margin","parseFloat","x","y","_getClipRegion","viewportHeight","abs","ceil","viewportWidth","result","setViewport","deviceScaleFactor","_createSVG","_createImage","_createPDF","$eval","getBoundingClientRect","trunc","outerHTML","clip","race","screenshot","encoding","fullPage","optimizeForSpeed","captureBeyondViewport","quality","omitBackground","_resolve","emulateMediaType","pdf","poolStats","exportsAttempted","exportsPerformed","exportsDropped","exportsFromSvg","exportsFromOptions","exportsFromSvgAttempts","exportsFromOptionsAttempts","timeSpent","timeSpentAverage","initPool","poolOptions","Pool","_factory","acquireTimeoutMillis","createTimeoutMillis","destroyTimeoutMillis","idleTimeoutMillis","createRetryIntervalMillis","reapIntervalMillis","propagateCreateError","clearStatus","_eventId","initialResources","acquire","promise","release","killPool","worker","used","destroyed","postWork","workerHandle","getPoolInfo","acquireCounter","workStart","exportCounter","exportTime","getPoolStats","getPoolInfoJSON","numUsed","available","numFree","allCreated","pendingAcquires","numPendingAcquires","pendingCreates","numPendingCreates","pendingValidations","numPendingValidations","pendingDestroys","absoluteAll","create","random","startDate","validate","mainFrame","detached","removeAllListeners","sanitize","JSDOM","DOMPurify","ADD_TAGS","singleExport","startExport","batchExport","batchFunctions","pair","batchResults","allSettled","reason","exportingOptions","endCallback","fileContent","_exportFromSvg","_exportFromOptions","getAllowCodeExecution","setAllowCodeExecution","inputToExport","_prepareExport","_handleCustomLogic","_handleGlobalAndTheme","_findChartSize","optionsChart","optionsExporting","globalOptionsChart","globalOptionsExporting","themeOptionsChart","themeOptionsExporting","sourceHeight","sourceWidth","param","_handleResources","allowedProps","handledResources","correctResources","propName","optionsName","timerIds","addTimer","clearAllTimers","clearInterval","clearTimeout","logErrorMiddleware","request","next","returnErrorMiddleware","status","json","errorMiddleware","app","use","rateLimitingMiddleware","rateLimitingOptions","rateOptions","limiter","rateLimit","windowMs","limit","delayMs","handler","format","send","default","skip","query","access_token","contentTypeMiddleware","contentType","headers","requestBodyMiddleware","connection","remoteAddress","validatedOptions","filename","validationMiddleware","post","reversedMime","png","jpeg","gif","requestExport","requestCounter","connectionAborted","socket","hadErrors","header","attachment","exportRoutes","serverStartTime","packageFile","successRates","recordInterval","windowSize","_calculateMovingAverage","a","b","_startSuccessRate","setInterval","stats","successRatio","healthRoutes","period","movingAverage","bootTime","uptime","floor","serverVersion","highchartsVersion","averageExportTime","attemptedExports","performedExports","failedExports","sucessRatio","toFixed","svgExports","jsonExports","svgExportsAttempts","jsonExportsAttempts","uiRoutes","sendFile","acceptRanges","versionChangeRoutes","token","activeServers","Map","express","startServer","serverOptions","uploadLimitBytes","storage","multer","memoryStorage","upload","limits","fieldSize","disable","cors","methods","set","urlencoded","extended","none","static","httpServer","createServer","_attachServerErrorHandlers","listen","cert","readFile","httpsServer","closeServers","delete","getServers","getExpress","getApp","middlewares","shutdownCleanUp","exitCode","exit","initExport","initOptions","_attachProcessExitListeners"],"mappings":"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ACA,QACA,OACA,aACA,mBACA,eACA,cACA,UACA,UACA,cACA,WACA,UACA,YACA,cACA,YACA,sBACA,SACA,SACA,WACA,aACA,YACA,eACA,yBACA,SACA,eACA,YACA,kBACA,SACA,cACA,mBACA,eACA,kBACA,cACA,eAEA,cACA,WACA,eACA,WACA,SACA,OACA,WACA,YACA,SACA,qBACA,aACA,WACA,WACA,WACA,WACA,eACA,UACA,kBACA,oBACA,aACA,UACA,cACA,YACA,YAEF0D,MAAO,CAAC,YACRC,QAAS,4BACTE,YAAa,qCACbC,cAAe,CACbxG,KAAM,cACNgH,aAAc,0DAGlBE,iBAAkB,CAChBxE,MAAO,CAAC,kBACR0D,MAAO,CAAC,YACRC,QAAS,+BACTE,YAAa,wCACbC,cAAe,CACbxG,KAAM,cACNgH,aAAc,0DAGlBG,cAAe,CACbzE,MAAO,CACL,wEACA,kGAEF0D,MAAO,CAAC,YACRC,QAAS,4BACTE,YAAa,qDACbC,cAAe,CACbxG,KAAM,OACNyG,UAAW,OAIjBW,OAAQ,CACNC,OAAQ,CACN3E,MAAO,KACP0D,MAAO,CAAC,SAAU,QAClBC,QAAS,gBACTE,YACE,+DACFC,cAAe,CACbxG,KAAM,SAGVsH,MAAO,CACL5E,MAAO,KACP0D,MAAO,CAAC,SAAU,SAAU,QAC5BC,QAAS,eACTE,YACE,mEACFC,cAAe,CACbxG,KAAM,SAGVuH,QAAS,CACP7E,MAAO,KACP0D,MAAO,CAAC,SAAU,SAAU,QAC5BC,QAAS,iBACTE,YAAa,+BACbC,cAAe,CACbxG,KAAM,SAGVwH,IAAK,CACH9E,MAAO,KACP0D,MAAO,CAAC,SAAU,QAClBC,QAAS,aACTE,YAAa,mDACbC,cAAe,CACbxG,KAAM,SAGVyH,MAAO,CACL/E,MAAO,KACP0D,MAAO,CAAC,SAAU,QAClBC,QAAS,eACTE,YACE,gEACFC,cAAe,CACbxG,KAAM,SAGVC,QAAS,CACPyC,MAAO,KACP0D,MAAO,CAAC,SAAU,QAClBC,QAAS,iBACTE,YACE,qFACFC,cAAe,CACbxG,KAAM,SAGVA,KAAM,CACJ0C,MAAO,MACP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"} \ No newline at end of file From 99de905db570de99146b9ad28cb9fbfc9121822c Mon Sep 17 00:00:00 2001 From: PaulDalek Date: Tue, 21 Jan 2025 02:51:14 +0100 Subject: [PATCH 15/19] Imports corrections. --- dist/index.cjs | 2 +- dist/index.esm.js.map | 2 +- lib/config.js | 4 ++-- lib/index.js | 2 +- lib/pool.js | 2 +- lib/server/middlewares/validation.js | 10 ++-------- lib/server/routes/health.js | 2 +- lib/server/routes/versionChange.js | 2 +- 8 files changed, 10 insertions(+), 16 deletions(-) diff --git a/dist/index.cjs b/dist/index.cjs index 3bc873ff..47997d5a 100644 --- a/dist/index.cjs +++ b/dist/index.cjs @@ -1,2 +1,2 @@ "use strict";Object.defineProperty(exports,"__esModule",{value:!0}),require("colors");var fs=require("fs"),path=require("path"),httpsProxyAgent=require("https-proxy-agent"),url=require("url"),dotenv=require("dotenv"),zod=require("zod"),http=require("http"),https=require("https"),tarn=require("tarn"),uuid=require("uuid"),puppeteer=require("puppeteer"),DOMPurify=require("dompurify"),jsdom=require("jsdom"),promises=require("fs/promises"),cors=require("cors"),express=require("express"),multer=require("multer"),rateLimit=require("express-rate-limit"),_documentCurrentScript="undefined"!=typeof document?document.currentScript:null;const __dirname$1=url.fileURLToPath(new URL("../.","undefined"==typeof document?require("url").pathToFileURL(__filename).href:_documentCurrentScript&&"SCRIPT"===_documentCurrentScript.tagName.toUpperCase()&&_documentCurrentScript.src||new URL("index.cjs",document.baseURI).href));function deepCopy(e){if(null===e||"object"!=typeof e)return e;const t=Array.isArray(e)?[]:{};for(const o in e)Object.prototype.hasOwnProperty.call(e,o)&&(t[o]=deepCopy(e[o]));return t}function fixConstr(e){try{const t=`${e.toLowerCase().replace("chart","")}Chart`;return"Chart"===t&&t.toLowerCase(),["chart","stockChart","mapChart","ganttChart"].includes(t)?t:"chart"}catch{return"chart"}}function fixOutfile(e,t){return`${getAbsolutePath(t||"chart").split(".").shift()}.${e}`}function fixType(e,t=null){const o={"image/png":"png","image/jpeg":"jpeg","application/pdf":"pdf","image/svg+xml":"svg"},r=Object.values(o);if(t){const o=t.split(".").pop();"jpg"===o?e="jpeg":r.includes(o)&&e!==o&&(e=o)}return o[e]||r.find((t=>t===e))||"png"}function getAbsolutePath(e){return path.isAbsolute(e)?e:path.join(__dirname$1,e)}function getBase64(e,t){return"pdf"===t||"svg"==t?Buffer.from(e,"utf8").toString("base64"):e}function getNewDate(){return(new Date).toString().split("(")[0].trim()}function getNewDateTime(){return(new Date).getTime()}function isObject(e){return"[object Object]"===Object.prototype.toString.call(e)}function isObjectEmpty(e){return"object"==typeof e&&!Array.isArray(e)&&null!==e&&0===Object.keys(e).length}function isPrivateRangeUrlFound(e){return[/xlink:href="(?:http:\/\/|https:\/\/)?localhost\b/,/xlink:href="(?:http:\/\/|https:\/\/)?10\.\d{1,3}\.\d{1,3}\.\d{1,3}\b/,/xlink:href="(?:http:\/\/|https:\/\/)?127\.\d{1,3}\.\d{1,3}\.\d{1,3}\b/,/xlink:href="(?:http:\/\/|https:\/\/)?172\.(1[6-9]|2[0-9]|3[0-1])\.\d{1,3}\.\d{1,3}\b/,/xlink:href="(?:http:\/\/|https:\/\/)?192\.168\.\d{1,3}\.\d{1,3}\b/].some((t=>t.test(e)))}function measureTime(){const e=process.hrtime.bigint();return()=>Number(process.hrtime.bigint()-e)/1e6}function roundNumber(e,t=1){const o=Math.pow(10,t||0);return Math.round(+e*o)/o}function wrapAround(e,t,o=!1){if(e&&"string"==typeof e)return(e=e.trim()).endsWith(".js")?t?wrapAround(fs.readFileSync(getAbsolutePath(e),"utf8"),t,o):null:!o&&(e.startsWith("function()")||e.startsWith("function ()")||e.startsWith("()=>")||e.startsWith("() =>"))?`(${e})()`:e.replace(/;$/,"")}const colors=["red","yellow","blue","gray","green"],logging={toConsole:!0,toFile:!1,pathCreated:!1,pathToLog:"",levelsDesc:[{title:"error",color:colors[0]},{title:"warning",color:colors[1]},{title:"notice",color:colors[2]},{title:"verbose",color:colors[3]},{title:"benchmark",color:colors[4]}]};function log(...e){const[t,...o]=e,{levelsDesc:r,level:i}=logging;if(5!==t&&(0===t||t>i||i>r.length))return;const n=`${getNewDate()} [${r[t-1].title}] -`;logging.toFile&&_logToFile(o,n),logging.toConsole&&console.log.apply(void 0,[n.toString()[logging.levelsDesc[t-1].color]].concat(o))}function logWithStack(e,t,o){const r=o||t&&t.message||"",{level:i,levelsDesc:n}=logging;if(0===e||e>i||i>n.length)return;const s=`${getNewDate()} [${n[e-1].title}] -`,a=t&&t.stack,l=[r];a&&l.push("\n",a),logging.toFile&&_logToFile(l,s),logging.toConsole&&console.log.apply(void 0,[s.toString()[logging.levelsDesc[e-1].color]].concat([l.shift()[colors[e-1]],...l]))}function logZodIssues(e,t,o){logWithStack(e,null,[`${o||"[validation] Validation error"} - the following Zod issues occured:`,...(t||[]).map((e=>`- ${e.message}`))].join("\n"))}function initLogging(e){const{level:t,dest:o,file:r,toConsole:i,toFile:n}=e;logging.pathCreated=!1,logging.pathToLog="",setLogLevel(t),enableConsoleLogging(i),enableFileLogging(o,r,n)}function setLogLevel(e){Number.isInteger(e)&&e>=0&&e<=logging.levelsDesc.length&&(logging.level=e)}function enableConsoleLogging(e){logging.toConsole=!!e}function enableFileLogging(e,t,o){logging.toFile=!!o,logging.toFile&&(logging.dest=e||"",logging.file=t||"")}function _logToFile(e,t){logging.pathCreated||(!fs.existsSync(getAbsolutePath(logging.dest))&&fs.mkdirSync(getAbsolutePath(logging.dest)),logging.pathToLog=getAbsolutePath(path.join(logging.dest,logging.file)),logging.pathCreated=!0),fs.appendFile(logging.pathToLog,[t].concat(e).join(" ")+"\n",(e=>{e&&logging.toFile&&logging.pathCreated&&(logging.toFile=!1,logging.pathCreated=!1,logWithStack(2,e,"[logger] Unable to write to log file."))}))}const defaultConfig={puppeteer:{args:{value:["--allow-running-insecure-content","--ash-no-nudges","--autoplay-policy=user-gesture-required","--block-new-web-contents","--disable-accelerated-2d-canvas","--disable-background-networking","--disable-background-timer-throttling","--disable-backgrounding-occluded-windows","--disable-breakpad","--disable-checker-imaging","--disable-client-side-phishing-detection","--disable-component-extensions-with-background-pages","--disable-component-update","--disable-default-apps","--disable-dev-shm-usage","--disable-domain-reliability","--disable-extensions","--disable-features=CalculateNativeWinOcclusion,InterestFeedContentSuggestions,WebOTP","--disable-hang-monitor","--disable-ipc-flooding-protection","--disable-logging","--disable-notifications","--disable-offer-store-unmasked-wallet-cards","--disable-popup-blocking","--disable-print-preview","--disable-prompt-on-repost","--disable-renderer-backgrounding","--disable-search-engine-choice-screen","--disable-session-crashed-bubble","--disable-setuid-sandbox","--disable-site-isolation-trials","--disable-speech-api","--disable-sync","--enable-unsafe-webgpu","--hide-crash-restore-bubble","--hide-scrollbars","--metrics-recording-only","--mute-audio","--no-default-browser-check","--no-first-run","--no-pings","--no-sandbox","--no-startup-window","--no-zygote","--password-store=basic","--process-per-tab","--use-mock-keychain"],types:["string[]"],envLink:"PUPPETEER_ARGS",cliName:"puppeteerArgs",description:"Array of Puppeteer arguments",promptOptions:{type:"list",separator:";"}}},highcharts:{version:{value:"latest",types:["string"],envLink:"HIGHCHARTS_VERSION",description:"Highcharts version",promptOptions:{type:"text"}},cdnUrl:{value:"https://code.highcharts.com",types:["string"],envLink:"HIGHCHARTS_CDN_URL",description:"CDN URL for Highcharts scripts",promptOptions:{type:"text"}},forceFetch:{value:!1,types:["boolean"],envLink:"HIGHCHARTS_FORCE_FETCH",description:"Flag to refetch scripts after each server rerun",promptOptions:{type:"toggle"}},cachePath:{value:".cache",types:["string"],envLink:"HIGHCHARTS_CACHE_PATH",description:"Directory path for cached Highcharts scripts",promptOptions:{type:"text"}},coreScripts:{value:["highcharts","highcharts-more","highcharts-3d"],types:["string[]"],envLink:"HIGHCHARTS_CORE_SCRIPTS",description:"Highcharts core scripts to fetch",promptOptions:{type:"multiselect",instructions:"Space: Select specific, A: Select all, Enter: Confirm"}},moduleScripts:{value:["stock","map","gantt","exporting","parallel-coordinates","accessibility","boost-canvas","boost","data","data-tools","draggable-points","static-scale","broken-axis","heatmap","tilemap","tiledwebmap","timeline","treemap","treegraph","item-series","drilldown","histogram-bellcurve","bullet","funnel","funnel3d","geoheatmap","pyramid3d","networkgraph","overlapping-datalabels","pareto","pattern-fill","pictorial","price-indicator","sankey","arc-diagram","dependency-wheel","series-label","series-on-point","solid-gauge","sonification","streamgraph","sunburst","variable-pie","variwide","vector","venn","windbarb","wordcloud","xrange","no-data-to-display","drag-panes","debugger","dumbbell","lollipop","cylinder","organization","dotplot","marker-clusters","hollowcandlestick","heikinashi","flowmap","export-data","navigator","textpath"],types:["string[]"],envLink:"HIGHCHARTS_MODULE_SCRIPTS",description:"Highcharts module scripts to fetch",promptOptions:{type:"multiselect",instructions:"Space: Select specific, A: Select all, Enter: Confirm"}},indicatorScripts:{value:["indicators-all"],types:["string[]"],envLink:"HIGHCHARTS_INDICATOR_SCRIPTS",description:"Highcharts indicator scripts to fetch",promptOptions:{type:"multiselect",instructions:"Space: Select specific, A: Select all, Enter: Confirm"}},customScripts:{value:["https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.30.1/moment.min.js","https://cdnjs.cloudflare.com/ajax/libs/moment-timezone/0.5.45/moment-timezone-with-data.min.js"],types:["string[]"],envLink:"HIGHCHARTS_CUSTOM_SCRIPTS",description:"Additional custom scripts or dependencies to fetch",promptOptions:{type:"list",separator:";"}}},export:{infile:{value:null,types:["string","null"],envLink:"EXPORT_INFILE",description:"Input filename with type, formatted correctly as JSON or SVG",promptOptions:{type:"text"}},instr:{value:null,types:["Object","string","null"],envLink:"EXPORT_INSTR",description:"Overrides the `infile` with JSON, stringified JSON, or SVG input",promptOptions:{type:"text"}},options:{value:null,types:["Object","string","null"],envLink:"EXPORT_OPTIONS",description:"Alias for the `instr` option",promptOptions:{type:"text"}},svg:{value:null,types:["string","null"],envLink:"EXPORT_SVG",description:"SVG string representation of the chart to render",promptOptions:{type:"text"}},batch:{value:null,types:["string","null"],envLink:"EXPORT_BATCH",description:'Batch job string with input/output pairs: "in=out;in=out;..."',promptOptions:{type:"text"}},outfile:{value:null,types:["string","null"],envLink:"EXPORT_OUTFILE",description:"Output filename with type. Can be jpeg, png, pdf, or svg and ignores `type` option",promptOptions:{type:"text"}},type:{value:"png",types:["string"],envLink:"EXPORT_TYPE",description:"File export format. Can be jpeg, png, pdf, or svg",promptOptions:{type:"select",hint:"Default: png",choices:["png","jpeg","pdf","svg"]}},constr:{value:"chart",types:["string"],envLink:"EXPORT_CONSTR",description:"Chart constructor. Can be chart, stockChart, mapChart, or ganttChart",promptOptions:{type:"select",hint:"Default: chart",choices:["chart","stockChart","mapChart","ganttChart"]}},b64:{value:!1,types:["boolean"],envLink:"EXPORT_B64",description:"Whether or not to the chart should be received in Base64 format instead of binary",promptOptions:{type:"toggle"}},noDownload:{value:!1,types:["boolean"],envLink:"EXPORT_NO_DOWNLOAD",description:"Whether or not to include or exclude attachment headers in the response",promptOptions:{type:"toggle"}},height:{value:null,types:["number","null"],envLink:"EXPORT_HEIGHT",description:"Height of the exported chart, overrides chart settings",promptOptions:{type:"number"}},width:{value:null,types:["number","null"],envLink:"EXPORT_WIDTH",description:"Width of the exported chart, overrides chart settings",promptOptions:{type:"number"}},scale:{value:null,types:["number","null"],envLink:"EXPORT_SCALE",description:"Scale of the exported chart, overrides chart settings. Ranges from 0.1 to 5.0",promptOptions:{type:"number"}},defaultHeight:{value:400,types:["number"],envLink:"EXPORT_DEFAULT_HEIGHT",description:"Default height of the exported chart if not set",promptOptions:{type:"number"}},defaultWidth:{value:600,types:["number"],envLink:"EXPORT_DEFAULT_WIDTH",description:"Default width of the exported chart if not set",promptOptions:{type:"number"}},defaultScale:{value:1,types:["number"],envLink:"EXPORT_DEFAULT_SCALE",description:"Default scale of the exported chart if not set. Ranges from 0.1 to 5.0",promptOptions:{type:"number",min:.1,max:5}},globalOptions:{value:null,types:["Object","string","null"],envLink:"EXPORT_GLOBAL_OPTIONS",description:"JSON, stringified JSON or filename with global options for Highcharts.setOptions",promptOptions:{type:"text"}},themeOptions:{value:null,types:["Object","string","null"],envLink:"EXPORT_THEME_OPTIONS",description:"JSON, stringified JSON or filename with theme options for Highcharts.setOptions",promptOptions:{type:"text"}},rasterizationTimeout:{value:1500,types:["number"],envLink:"EXPORT_RASTERIZATION_TIMEOUT",description:"Milliseconds to wait for webpage rendering",promptOptions:{type:"number"}}},customLogic:{allowCodeExecution:{value:!1,types:["boolean"],envLink:"CUSTOM_LOGIC_ALLOW_CODE_EXECUTION",description:"Allows or disallows execution of arbitrary code during exporting",promptOptions:{type:"toggle"}},allowFileResources:{value:!1,types:["boolean"],envLink:"CUSTOM_LOGIC_ALLOW_FILE_RESOURCES",description:"Allows or disallows injection of filesystem resources (disabled in server mode)",promptOptions:{type:"toggle"}},customCode:{value:null,types:["string","null"],envLink:"CUSTOM_LOGIC_CUSTOM_CODE",description:"Custom code to execute before chart initialization. Can be a function, code wrapped in a function, or a .js filename",promptOptions:{type:"text"}},callback:{value:null,types:["string","null"],envLink:"CUSTOM_LOGIC_CALLBACK",description:"JavaScript code to run during construction. Can be a function or a .js filename",promptOptions:{type:"text"}},resources:{value:null,types:["Object","string","null"],envLink:"CUSTOM_LOGIC_RESOURCES",description:"Additional resources as JSON, stringified JSON, or filename, containing files, js, and css sections",promptOptions:{type:"text"}},loadConfig:{value:null,types:["string","null"],envLink:"CUSTOM_LOGIC_LOAD_CONFIG",legacyName:"fromFile",description:"File with a pre-defined configuration to use",promptOptions:{type:"text"}},createConfig:{value:null,types:["string","null"],envLink:"CUSTOM_LOGIC_CREATE_CONFIG",description:"Prompt-based option setting, saved to a provided config file",promptOptions:{type:"text"}}},server:{enable:{value:!1,types:["boolean"],envLink:"SERVER_ENABLE",cliName:"enableServer",description:"Starts the server when true",promptOptions:{type:"toggle"}},host:{value:"0.0.0.0",types:["string"],envLink:"SERVER_HOST",description:"Hostname of the server",promptOptions:{type:"text"}},port:{value:7801,types:["number"],envLink:"SERVER_PORT",description:"Port number for the server",promptOptions:{type:"number"}},uploadLimit:{value:3,types:["number"],envLink:"SERVER_UPLOAD_LIMIT",description:"Maximum request body size in MB",promptOptions:{type:"number"}},benchmarking:{value:!1,types:["boolean"],envLink:"SERVER_BENCHMARKING",cliName:"serverBenchmarking",description:"Displays or not action durations in milliseconds during server requests",promptOptions:{type:"toggle"}},proxy:{host:{value:null,types:["string","null"],envLink:"SERVER_PROXY_HOST",cliName:"proxyHost",description:"Host of the proxy server, if applicable",promptOptions:{type:"text"}},port:{value:null,types:["number","null"],envLink:"SERVER_PROXY_PORT",cliName:"proxyPort",description:"Port of the proxy server, if applicable",promptOptions:{type:"number"}},timeout:{value:5e3,types:["number"],envLink:"SERVER_PROXY_TIMEOUT",cliName:"proxyTimeout",description:"Timeout in milliseconds for the proxy server, if applicable",promptOptions:{type:"number"}}},rateLimiting:{enable:{value:!1,types:["boolean"],envLink:"SERVER_RATE_LIMITING_ENABLE",cliName:"enableRateLimiting",description:"Enables or disables rate limiting on the server",promptOptions:{type:"toggle"}},maxRequests:{value:10,types:["number"],envLink:"SERVER_RATE_LIMITING_MAX_REQUESTS",legacyName:"rateLimit",description:"Maximum number of requests allowed per minute",promptOptions:{type:"number"}},window:{value:1,types:["number"],envLink:"SERVER_RATE_LIMITING_WINDOW",description:"Time window in minutes for rate limiting",promptOptions:{type:"number"}},delay:{value:0,types:["number"],envLink:"SERVER_RATE_LIMITING_DELAY",description:"Delay duration between successive requests before reaching the limit",promptOptions:{type:"number"}},trustProxy:{value:!1,types:["boolean"],envLink:"SERVER_RATE_LIMITING_TRUST_PROXY",description:"Set to true if the server is behind a load balancer",promptOptions:{type:"toggle"}},skipKey:{value:null,types:["string","null"],envLink:"SERVER_RATE_LIMITING_SKIP_KEY",description:"Key to bypass the rate limiter, used with `skipToken`",promptOptions:{type:"text"}},skipToken:{value:null,types:["string","null"],envLink:"SERVER_RATE_LIMITING_SKIP_TOKEN",description:"Token to bypass the rate limiter, used with `skipKey`",promptOptions:{type:"text"}}},ssl:{enable:{value:!1,types:["boolean"],envLink:"SERVER_SSL_ENABLE",cliName:"enableSsl",description:"Enables or disables SSL protocol",promptOptions:{type:"toggle"}},force:{value:!1,types:["boolean"],envLink:"SERVER_SSL_FORCE",cliName:"sslForce",legacyName:"sslOnly",description:"Forces the server to use HTTPS only when true",promptOptions:{type:"toggle"}},port:{value:443,types:["number"],envLink:"SERVER_SSL_PORT",cliName:"sslPort",description:"Port for the SSL server",promptOptions:{type:"number"}},certPath:{value:null,types:["string","null"],envLink:"SERVER_SSL_CERT_PATH",cliName:"sslCertPath",legacyName:"sslPath",description:"Path to the SSL certificate/key file",promptOptions:{type:"text"}}}},pool:{minWorkers:{value:4,types:["number"],envLink:"POOL_MIN_WORKERS",description:"Minimum and initial number of pool workers to spawn",promptOptions:{type:"number"}},maxWorkers:{value:8,types:["number"],envLink:"POOL_MAX_WORKERS",legacyName:"workers",description:"Maximum number of pool workers to spawn",promptOptions:{type:"number"}},workLimit:{value:40,types:["number"],envLink:"POOL_WORK_LIMIT",description:"Number of tasks a worker can handle before restarting",promptOptions:{type:"number"}},acquireTimeout:{value:5e3,types:["number"],envLink:"POOL_ACQUIRE_TIMEOUT",description:"Timeout in milliseconds for acquiring a resource",promptOptions:{type:"number"}},createTimeout:{value:5e3,types:["number"],envLink:"POOL_CREATE_TIMEOUT",description:"Timeout in milliseconds for creating a resource",promptOptions:{type:"number"}},destroyTimeout:{value:5e3,types:["number"],envLink:"POOL_DESTROY_TIMEOUT",description:"Timeout in milliseconds for destroying a resource",promptOptions:{type:"number"}},idleTimeout:{value:3e4,types:["number"],envLink:"POOL_IDLE_TIMEOUT",description:"Timeout in milliseconds for destroying idle resources",promptOptions:{type:"number"}},createRetryInterval:{value:200,types:["number"],envLink:"POOL_CREATE_RETRY_INTERVAL",description:"Interval in milliseconds before retrying resource creation on failure",promptOptions:{type:"number"}},reaperInterval:{value:1e3,types:["number"],envLink:"POOL_REAPER_INTERVAL",description:"Interval in milliseconds to check and destroy idle resources",promptOptions:{type:"number"}},benchmarking:{value:!1,types:["boolean"],envLink:"POOL_BENCHMARKING",cliName:"poolBenchmarking",description:"Shows statistics for the pool of resources",promptOptions:{type:"toggle"}}},logging:{level:{value:4,types:["number"],envLink:"LOGGING_LEVEL",cliName:"logLevel",description:"Logging verbosity level",promptOptions:{type:"number",round:0,min:0,max:5}},file:{value:"highcharts-export-server.log",types:["string"],envLink:"LOGGING_FILE",cliName:"logFile",description:"Log file name. Requires `logToFile` and `logDest` to be set",promptOptions:{type:"text"}},dest:{value:"log",types:["string"],envLink:"LOGGING_DEST",cliName:"logDest",description:"Path to store log files. Requires `logToFile` to be set",promptOptions:{type:"text"}},toConsole:{value:!0,types:["boolean"],envLink:"LOGGING_TO_CONSOLE",cliName:"logToConsole",description:"Enables or disables console logging",promptOptions:{type:"toggle"}},toFile:{value:!0,types:["boolean"],envLink:"LOGGING_TO_FILE",cliName:"logToFile",description:"Enables or disables logging to a file",promptOptions:{type:"toggle"}}},ui:{enable:{value:!1,types:["boolean"],envLink:"UI_ENABLE",cliName:"enableUi",description:"Enables or disables the UI for the export server",promptOptions:{type:"toggle"}},route:{value:"/",types:["string"],envLink:"UI_ROUTE",cliName:"uiRoute",description:"The endpoint route for the UI",promptOptions:{type:"text"}}},other:{nodeEnv:{value:"production",types:["string"],envLink:"OTHER_NODE_ENV",description:"The Node.js environment type",promptOptions:{type:"text"}},listenToProcessExits:{value:!0,types:["boolean"],envLink:"OTHER_LISTEN_TO_PROCESS_EXITS",description:"Whether or not to attach process.exit handlers",promptOptions:{type:"toggle"}},noLogo:{value:!1,types:["boolean"],envLink:"OTHER_NO_LOGO",description:"Display or skip printing the logo on startup",promptOptions:{type:"toggle"}},hardResetPage:{value:!1,types:["boolean"],envLink:"OTHER_HARD_RESET_PAGE",description:"Whether or not to reset the page content entirely",promptOptions:{type:"toggle"}},browserShellMode:{value:!0,types:["boolean"],envLink:"OTHER_BROWSER_SHELL_MODE",description:"Whether or not to set the browser to run in shell mode",promptOptions:{type:"toggle"}},validation:{value:!0,types:["boolean"],envLink:"OTHER_VALIDATION",description:"Whether or not to enable validation of options types",promptOptions:{type:"toggle"}}},debug:{enable:{value:!1,types:["boolean"],envLink:"DEBUG_ENABLE",cliName:"enableDebug",description:"Enables or disables debug mode for the underlying browser",promptOptions:{type:"toggle"}},headless:{value:!1,types:["boolean"],envLink:"DEBUG_HEADLESS",description:"Whether or not to set the browser to run in headless mode during debugging",promptOptions:{type:"toggle"}},devtools:{value:!1,types:["boolean"],envLink:"DEBUG_DEVTOOLS",description:"Enables or disables DevTools in headful mode",promptOptions:{type:"toggle"}},listenToConsole:{value:!1,types:["boolean"],envLink:"DEBUG_LISTEN_TO_CONSOLE",description:"Enables or disables listening to console messages from the browser",promptOptions:{type:"toggle"}},dumpio:{value:!1,types:["boolean"],envLink:"DEBUG_DUMPIO",description:"Redirects or not browser stdout and stderr to process.stdout and process.stderr",promptOptions:{type:"toggle"}},slowMo:{value:0,types:["number"],envLink:"DEBUG_SLOW_MO",description:"Delays Puppeteer operations by the specified milliseconds",promptOptions:{type:"number"}},debuggingPort:{value:9222,types:["number"],envLink:"DEBUG_DEBUGGING_PORT",description:"Port used for debugging",promptOptions:{type:"number"}}}},nestedProps=_createNestedProps(defaultConfig),absoluteProps=_createAbsoluteProps(defaultConfig);function _createNestedProps(e,t={},o=""){return Object.keys(e).forEach((r=>{const i=e[r];void 0===i.value?_createNestedProps(i,t,`${o}.${r}`):(t[i.cliName||r]=`${o}.${r}`.substring(1),void 0!==i.legacyName&&(t[i.legacyName]=`${o}.${r}`.substring(1)))})),t}function _createAbsoluteProps(e,t=[]){return Object.keys(e).forEach((o=>{const r=e[o];void 0===r.types?_createAbsoluteProps(r,t):r.types.includes("Object")&&t.push(o)})),t}dotenv.config();const{coreScripts:coreScripts,moduleScripts:moduleScripts,indicatorScripts:indicatorScripts}=defaultConfig.highcharts;zod.z.setErrorMap(_customErrorMap);const v={boolean:e=>e?zod.z.boolean():zod.z.union([zod.z.enum(["true","1","false","0","undefined","null",""]).transform((e=>["undefined","null",""].includes(e)?null:"true"===e||"1"===e)),zod.z.boolean()]).nullable(),string:e=>e?zod.z.string().trim().refine((e=>!["false","undefined","null",""].includes(e)),{params:{errorMessage:"The string contains a forbidden value"}}):zod.z.string().trim().transform((e=>["false","undefined","null",""].includes(e)?null:e)).nullable(),enum:(e,t)=>t?zod.z.enum([...e]):zod.z.enum([...e,"undefined","null",""]).transform((e=>["undefined","null",""].includes(e)?null:e)).nullable(),stringArray(e,t,o){const r=zod.z.string().trim().array(),i=zod.z.string().trim().transform((e=>(e.startsWith("[")&&(e=e.slice(1)),e.endsWith("]")&&(e=e.slice(0,-1)),e.split(t)))),n=t=>t.map((e=>e.trim())).filter(e);return o?r.transform(n):zod.z.union([i,r]).transform(n).transform((e=>e.length?e:null)).nullable()},positiveNum:e=>e?zod.z.number().positive():zod.z.union([zod.z.string().trim().refine((e=>!isNaN(Number(e))&&Number(e)>0||["undefined","null",""].includes(e)),{params:{errorMessage:"The value must be numeric and positive"}}).transform((e=>["undefined","null",""].includes(e)?null:Number(e))),zod.z.number().positive()]).nullable(),nonNegativeNum:e=>e?zod.z.number().nonnegative():zod.z.union([zod.z.string().trim().refine((e=>!isNaN(Number(e))&&Number(e)>=0||["undefined","null",""].includes(e)),{params:{errorMessage:"The value must be numeric and non-negative"}}).transform((e=>["undefined","null",""].includes(e)?null:Number(e))),zod.z.number().nonnegative()]).nullable(),startsWith:(e,t)=>t?zod.z.string().trim().refine((t=>e.some((e=>t.startsWith(e)))),{params:{errorMessage:`The value must be a string that starts with ${e.join(", ")}`}}):zod.z.string().trim().refine((t=>e.some((e=>t.startsWith(e)))||["undefined","null",""].includes(t)),{params:{errorMessage:`The value must be a string that starts with ${e.join(", ")}`}}).transform((e=>["undefined","null",""].includes(e)?null:e)).nullable(),chartConfig:()=>zod.z.union([zod.z.string().trim().refine((e=>e.startsWith("{")&&e.endsWith("}")||["undefined","null",""].includes(e)),{params:{errorMessage:"The value must be a string that starts with '{' and ends with '}'"}}).transform((e=>["undefined","null",""].includes(e)?null:e)),zod.z.object({}).passthrough()]).nullable(),additionalOptions:()=>zod.z.union([zod.z.string().trim().refine((e=>e.length>=6&&e.endsWith(".json")||e.startsWith("{")&&e.endsWith("}")||["undefined","null",""].includes(e)),{params:{errorMessage:"The value must be a string that ends with '.json' or starts with '{' and ends with '}'"}}).transform((e=>["undefined","null",""].includes(e)?null:e)),zod.z.object({}).passthrough()]).nullable()},validators={args:e=>v.stringArray((e=>!["false","undefined","null",""].includes(e)),";",e),version:e=>e?zod.z.string().trim().refine((e=>/^(latest|\d{1,2}(\.\d{1,2}){0,2})$/.test(e)),{params:{errorMessage:"The value must be 'latest', a major version, or in the form XX.YY.ZZ"}}):zod.z.string().trim().refine((e=>/^(latest|\d{1,2}(\.\d{1,2}){0,2})$/.test(e)||["undefined","null",""].includes(e)),{params:{errorMessage:"The value must be 'latest', a major version, or in the form XX.YY.ZZ"}}).transform((e=>["undefined","null",""].includes(e)?null:e)).nullable(),cdnUrl:e=>v.startsWith(["http://","https://"],e),forceFetch:e=>v.boolean(e),cachePath:e=>v.string(e),adminToken:e=>v.string(e),coreScripts:e=>v.stringArray((e=>coreScripts.value.includes(e)),",",e),moduleScripts:e=>v.stringArray((e=>moduleScripts.value.includes(e)),",",e),indicatorScripts:e=>v.stringArray((e=>indicatorScripts.value.includes(e)),",",e),customScripts:e=>v.stringArray((e=>e.startsWith("https://")||e.startsWith("http://")),",",e),infile:e=>e?zod.z.string().trim().refine((e=>e.length>=6&&e.endsWith(".json")||e.length>=5&&e.endsWith(".svg")),{params:{errorMessage:"The value must be a string that ends with .json or .svg"}}).nullable():zod.z.string().trim().refine((e=>e.length>=6&&e.endsWith(".json")||e.length>=5&&e.endsWith(".svg")||["undefined","null",""].includes(e)),{params:{errorMessage:"The value must be a string that ends with .json or .svg"}}).transform((e=>["undefined","null",""].includes(e)?null:e)).nullable(),instr:()=>v.chartConfig(),options:()=>v.chartConfig(),svg:()=>zod.z.string().trim().refine((e=>e.indexOf("=0||e.indexOf("=0||["false","undefined","null",""].includes(e)),{params:{errorMessage:"The value must be a string that contains '["false","undefined","null",""].includes(e)?null:e)).nullable(),outfile:e=>e?zod.z.string().trim().refine((e=>e.length>=6&&e.endsWith(".jpeg")||e.length>=5&&(e.endsWith(".jpg")||e.endsWith(".png")||e.endsWith(".pdf")||e.endsWith(".svg"))),{params:{errorMessage:"The value must be a string that ends with .jpeg, .jpg, .png, .pdf, or .svg"}}).nullable():zod.z.string().trim().refine((e=>e.length>=6&&e.endsWith(".jpeg")||e.length>=5&&(e.endsWith(".jpg")||e.endsWith(".png")||e.endsWith(".pdf")||e.endsWith(".svg"))||["undefined","null",""].includes(e)),{params:{errorMessage:"The value must be a string that ends with .jpeg, .jpg, .png, .pdf, or .svg"}}).transform((e=>["undefined","null",""].includes(e)?null:e)).nullable(),type:e=>v.enum(["jpeg","jpg","png","pdf","svg"],e),constr:e=>v.enum(["chart","stockChart","mapChart","ganttChart"],e),b64:e=>v.boolean(e),noDownload:e=>v.boolean(e),defaultHeight:e=>v.positiveNum(e),defaultWidth:e=>v.positiveNum(e),defaultScale:e=>e?zod.z.number().gte(.1).lte(5):zod.z.union([zod.z.string().trim().refine((e=>!isNaN(Number(e))&&!0!==e&&!e.startsWith("[")&&Number(e)>=.1&&Number(e)<=5||["undefined","null",""].includes(e)),{params:{errorMessage:"The value must be within a 0.1 and 5.0 range"}}).transform((e=>["undefined","null",""].includes(e)?null:Number(e))),zod.z.number().gte(.1).lte(5)]).nullable(),height(e){return this.defaultHeight(e).nullable()},width(e){return this.defaultWidth(e).nullable()},scale(e){return this.defaultScale(e).nullable()},globalOptions:()=>v.additionalOptions(),themeOptions:()=>v.additionalOptions(),batch:e=>v.string(e),rasterizationTimeout:e=>v.nonNegativeNum(e),allowCodeExecution:e=>v.boolean(e),allowFileResources:e=>v.boolean(e),customCode:e=>v.string(e),callback:e=>v.string(e),resources(e){const t=zod.z.object({js:v.string(!1),css:v.string(!1),files:v.stringArray((e=>!["undefined","null",""].includes(e)),",",!0).nullable()}).partial(),o=zod.z.string().trim().refine((e=>e.startsWith("{")&&e.endsWith("}")||e.length>=6&&e.endsWith(".json")),{params:{errorMessage:"The value must be a string that starts with '{' and ends with '}"}}),r=zod.z.string().trim().refine((e=>e.startsWith("{")&&e.endsWith("}")||e.length>=6&&e.endsWith(".json")||["undefined","null",""].includes(e)),{params:{errorMessage:"The value must be a string that ends with .json"}}).transform((e=>["undefined","null",""].includes(e)?null:e));return e?zod.z.union([t,o]).nullable():zod.z.union([t,r]).nullable()},loadConfig:e=>v.string(e).refine((e=>null===e||e.length>=6&&e.endsWith(".json")),{params:{errorMessage:"The value must be a string that ends with .json"}}),createConfig(e){return this.loadConfig(e)},enableServer:e=>v.boolean(e),host:e=>v.string(e),port:e=>v.nonNegativeNum(e),uploadLimit:e=>v.positiveNum(e),serverBenchmarking:e=>v.boolean(e),proxyHost:e=>v.string(e),proxyPort:e=>v.nonNegativeNum(e).nullable(),proxyTimeout:e=>v.nonNegativeNum(e),enableRateLimiting:e=>v.boolean(e),maxRequests:e=>v.nonNegativeNum(e),window:e=>v.nonNegativeNum(e),delay:e=>v.nonNegativeNum(e),trustProxy:e=>v.boolean(e),skipKey:e=>v.string(e),skipToken:e=>v.string(e),enableSsl:e=>v.boolean(e),sslForce:e=>v.boolean(e),sslPort:e=>v.nonNegativeNum(e),sslCertPath:e=>v.string(e),minWorkers:e=>v.positiveNum(e),maxWorkers:e=>v.positiveNum(e),workLimit:e=>v.positiveNum(e),acquireTimeout:e=>v.nonNegativeNum(e),createTimeout:e=>v.nonNegativeNum(e),destroyTimeout:e=>v.nonNegativeNum(e),idleTimeout:e=>v.nonNegativeNum(e),createRetryInterval:e=>v.nonNegativeNum(e),reaperInterval:e=>v.nonNegativeNum(e),poolBenchmarking:e=>v.boolean(e),resourcesInterval:e=>v.nonNegativeNum(e),logLevel:e=>e?zod.z.number().int().gte(0).lte(5):zod.z.union([zod.z.string().trim().refine((e=>!isNaN(Number(e))&&!0!==e&&!e.startsWith("[")&&Number.isInteger(Number(e))&&Number(e)>=0&&Number(e)<=5||["undefined","null",""].includes(e)),{params:{errorMessage:"The value must be within a 0 and 5 range"}}).transform((e=>["undefined","null",""].includes(e)?null:Number(e))),zod.z.number().int().gte(0).lte(5)]).nullable(),logFile:e=>v.string(e).refine((e=>null===e||e.length>=5&&e.endsWith(".log")),{params:{errorMessage:"The value must be a string that ends with .log"}}),logDest:e=>v.string(e),logToConsole:e=>v.boolean(e),logToFile:e=>v.boolean(e),enableUi:e=>v.boolean(e),uiRoute:e=>v.startsWith(["/"],e),nodeEnv:e=>v.enum(["development","production","test"],e),listenToProcessExits:e=>v.boolean(e),noLogo:e=>v.boolean(e),hardResetPage:e=>v.boolean(e),browserShellMode:e=>v.boolean(e),validation:e=>v.boolean(e),enableDebug:e=>v.boolean(e),headless:e=>v.boolean(e),devtools:e=>v.boolean(e),listenToConsole:e=>v.boolean(e),dumpio:e=>v.boolean(e),slowMo:e=>v.nonNegativeNum(e),debuggingPort:e=>v.nonNegativeNum(e),requestId:()=>zod.z.string().uuid({message:"The value must be a stringified UUID"}).nullable()},PuppeteerSchema=e=>zod.z.object({args:validators.args(e)}).partial(),HighchartsSchema=e=>zod.z.object({version:validators.version(e),cdnUrl:validators.cdnUrl(e),forceFetch:validators.forceFetch(e),cachePath:validators.cachePath(e),coreScripts:validators.coreScripts(e),moduleScripts:validators.moduleScripts(e),indicatorScripts:validators.indicatorScripts(e),customScripts:validators.customScripts(e)}).partial(),ExportSchema=e=>zod.z.object({infile:validators.infile(e),instr:validators.instr(),options:validators.options(),svg:validators.svg(),outfile:validators.outfile(e),type:validators.type(e),constr:validators.constr(e),b64:validators.b64(e),noDownload:validators.noDownload(e),defaultHeight:validators.defaultHeight(e),defaultWidth:validators.defaultWidth(e),defaultScale:validators.defaultScale(e),height:validators.height(e),width:validators.width(e),scale:validators.scale(e),globalOptions:validators.globalOptions(),themeOptions:validators.themeOptions(),batch:validators.batch(!1),rasterizationTimeout:validators.rasterizationTimeout(e)}).partial(),CustomLogicSchema=e=>zod.z.object({allowCodeExecution:validators.allowCodeExecution(e),allowFileResources:validators.allowFileResources(e),customCode:validators.customCode(!1),callback:validators.callback(!1),resources:validators.resources(e),loadConfig:validators.loadConfig(!1),createConfig:validators.createConfig(!1)}).partial(),ProxySchema=e=>zod.z.object({host:validators.proxyHost(!1),port:validators.proxyPort(e),timeout:validators.proxyTimeout(e)}).partial(),RateLimitingSchema=e=>zod.z.object({enable:validators.enableRateLimiting(e),maxRequests:validators.maxRequests(e),window:validators.window(e),delay:validators.delay(e),trustProxy:validators.trustProxy(e),skipKey:validators.skipKey(!1),skipToken:validators.skipToken(!1)}).partial(),SslSchema=e=>zod.z.object({enable:validators.enableSsl(e),force:validators.sslForce(e),port:validators.sslPort(e),certPath:validators.sslCertPath(!1)}).partial(),ServerSchema=e=>zod.z.object({enable:validators.enableServer(e).optional(),host:validators.host(e).optional(),port:validators.port(e).optional(),uploadLimit:validators.uploadLimit(e).optional(),benchmarking:validators.serverBenchmarking(e).optional(),proxy:ProxySchema(e).optional(),rateLimiting:RateLimitingSchema(e).optional(),ssl:SslSchema(e).optional()}),PoolSchema=e=>zod.z.object({minWorkers:validators.minWorkers(e),maxWorkers:validators.maxWorkers(e),workLimit:validators.workLimit(e),acquireTimeout:validators.acquireTimeout(e),createTimeout:validators.createTimeout(e),destroyTimeout:validators.destroyTimeout(e),idleTimeout:validators.idleTimeout(e),createRetryInterval:validators.createRetryInterval(e),reaperInterval:validators.reaperInterval(e),benchmarking:validators.poolBenchmarking(e)}).partial(),LoggingSchema=e=>zod.z.object({level:validators.logLevel(e),file:validators.logFile(e),dest:validators.logDest(e),toConsole:validators.logToConsole(e),toFile:validators.logToFile(e)}).partial(),UiSchema=e=>zod.z.object({enable:validators.enableUi(e),route:validators.uiRoute(e)}).partial(),OtherSchema=e=>zod.z.object({nodeEnv:validators.nodeEnv(e),listenToProcessExits:validators.listenToProcessExits(e),noLogo:validators.noLogo(e),hardResetPage:validators.hardResetPage(e),browserShellMode:validators.browserShellMode(e),validation:validators.validation(e)}).partial(),DebugSchema=e=>zod.z.object({enable:validators.enableDebug(e),headless:validators.headless(e),devtools:validators.devtools(e),listenToConsole:validators.listenToConsole(e),dumpio:validators.dumpio(e),slowMo:validators.slowMo(e),debuggingPort:validators.debuggingPort(e)}).partial(),StrictConfigSchema=zod.z.object({requestId:validators.requestId(),puppeteer:PuppeteerSchema(!0),highcharts:HighchartsSchema(!0),export:ExportSchema(!0),customLogic:CustomLogicSchema(!0),server:ServerSchema(!0),pool:PoolSchema(!0),logging:LoggingSchema(!0),ui:UiSchema(!0),other:OtherSchema(!0),debug:DebugSchema(!0)}),LooseConfigSchema=zod.z.object({requestId:validators.requestId(),puppeteer:PuppeteerSchema(!1),highcharts:HighchartsSchema(!1),export:ExportSchema(!1),customLogic:CustomLogicSchema(!1),server:ServerSchema(!1),pool:PoolSchema(!1),logging:LoggingSchema(!1),ui:UiSchema(!1),other:OtherSchema(!1),debug:DebugSchema(!1)}),EnvSchema=zod.z.object({PUPPETEER_ARGS:validators.args(!1),HIGHCHARTS_VERSION:validators.version(!1),HIGHCHARTS_CDN_URL:validators.cdnUrl(!1),HIGHCHARTS_FORCE_FETCH:validators.forceFetch(!1),HIGHCHARTS_CACHE_PATH:validators.cachePath(!1),HIGHCHARTS_ADMIN_TOKEN:validators.adminToken(!1),HIGHCHARTS_CORE_SCRIPTS:validators.coreScripts(!1),HIGHCHARTS_MODULE_SCRIPTS:validators.moduleScripts(!1),HIGHCHARTS_INDICATOR_SCRIPTS:validators.indicatorScripts(!1),HIGHCHARTS_CUSTOM_SCRIPTS:validators.customScripts(!1),EXPORT_INFILE:validators.infile(!1),EXPORT_INSTR:validators.instr(),EXPORT_OPTIONS:validators.options(),EXPORT_SVG:validators.svg(),EXPORT_BATCH:validators.batch(!1),EXPORT_OUTFILE:validators.outfile(!1),EXPORT_TYPE:validators.type(!1),EXPORT_CONSTR:validators.constr(!1),EXPORT_B64:validators.b64(!1),EXPORT_NO_DOWNLOAD:validators.noDownload(!1),EXPORT_HEIGHT:validators.height(!1),EXPORT_WIDTH:validators.width(!1),EXPORT_SCALE:validators.scale(!1),EXPORT_DEFAULT_HEIGHT:validators.defaultHeight(!1),EXPORT_DEFAULT_WIDTH:validators.defaultWidth(!1),EXPORT_DEFAULT_SCALE:validators.defaultScale(!1),EXPORT_GLOBAL_OPTIONS:validators.globalOptions(),EXPORT_THEME_OPTIONS:validators.themeOptions(),EXPORT_RASTERIZATION_TIMEOUT:validators.rasterizationTimeout(!1),CUSTOM_LOGIC_ALLOW_CODE_EXECUTION:validators.allowCodeExecution(!1),CUSTOM_LOGIC_ALLOW_FILE_RESOURCES:validators.allowFileResources(!1),CUSTOM_LOGIC_CUSTOM_CODE:validators.customCode(!1),CUSTOM_LOGIC_CALLBACK:validators.callback(!1),CUSTOM_LOGIC_RESOURCES:validators.resources(!1),CUSTOM_LOGIC_LOAD_CONFIG:validators.loadConfig(!1),CUSTOM_LOGIC_CREATE_CONFIG:validators.createConfig(!1),SERVER_ENABLE:validators.enableServer(!1),SERVER_HOST:validators.host(!1),SERVER_PORT:validators.port(!1),SERVER_UPLOAD_LIMIT:validators.uploadLimit(!1),SERVER_BENCHMARKING:validators.serverBenchmarking(!1),SERVER_PROXY_HOST:validators.proxyHost(!1),SERVER_PROXY_PORT:validators.proxyPort(!1),SERVER_PROXY_TIMEOUT:validators.proxyTimeout(!1),SERVER_RATE_LIMITING_ENABLE:validators.enableRateLimiting(!1),SERVER_RATE_LIMITING_MAX_REQUESTS:validators.maxRequests(!1),SERVER_RATE_LIMITING_WINDOW:validators.window(!1),SERVER_RATE_LIMITING_DELAY:validators.delay(!1),SERVER_RATE_LIMITING_TRUST_PROXY:validators.trustProxy(!1),SERVER_RATE_LIMITING_SKIP_KEY:validators.skipKey(!1),SERVER_RATE_LIMITING_SKIP_TOKEN:validators.skipToken(!1),SERVER_SSL_ENABLE:validators.enableSsl(!1),SERVER_SSL_FORCE:validators.sslForce(!1),SERVER_SSL_PORT:validators.sslPort(!1),SERVER_SSL_CERT_PATH:validators.sslCertPath(!1),POOL_MIN_WORKERS:validators.minWorkers(!1),POOL_MAX_WORKERS:validators.maxWorkers(!1),POOL_WORK_LIMIT:validators.workLimit(!1),POOL_ACQUIRE_TIMEOUT:validators.acquireTimeout(!1),POOL_CREATE_TIMEOUT:validators.createTimeout(!1),POOL_DESTROY_TIMEOUT:validators.destroyTimeout(!1),POOL_IDLE_TIMEOUT:validators.idleTimeout(!1),POOL_CREATE_RETRY_INTERVAL:validators.createRetryInterval(!1),POOL_REAPER_INTERVAL:validators.reaperInterval(!1),POOL_BENCHMARKING:validators.poolBenchmarking(!1),LOGGING_LEVEL:validators.logLevel(!1),LOGGING_FILE:validators.logFile(!1),LOGGING_DEST:validators.logDest(!1),LOGGING_TO_CONSOLE:validators.logToConsole(!1),LOGGING_TO_FILE:validators.logToFile(!1),UI_ENABLE:validators.enableUi(!1),UI_ROUTE:validators.uiRoute(!1),OTHER_NODE_ENV:validators.nodeEnv(!1),OTHER_LISTEN_TO_PROCESS_EXITS:validators.listenToProcessExits(!1),OTHER_NO_LOGO:validators.noLogo(!1),OTHER_HARD_RESET_PAGE:validators.hardResetPage(!1),OTHER_BROWSER_SHELL_MODE:validators.browserShellMode(!1),OTHER_VALIDATION:validators.validation(!1),DEBUG_ENABLE:validators.enableDebug(!1),DEBUG_HEADLESS:validators.headless(!1),DEBUG_DEVTOOLS:validators.devtools(!1),DEBUG_LISTEN_TO_CONSOLE:validators.listenToConsole(!1),DEBUG_DUMPIO:validators.dumpio(!1),DEBUG_SLOW_MO:validators.slowMo(!1),DEBUG_DEBUGGING_PORT:validators.debuggingPort(!1)}),envs=EnvSchema.partial().parse(process.env);function strictValidate(e){return StrictConfigSchema.partial().parse(e)}function looseValidate(e){return LooseConfigSchema.partial().parse(e)}function _customErrorMap(e,t){const o=e.path.join("."),r=`Invalid value for the ${o}`;if(e.code===zod.z.ZodIssueCode.invalid_type)return e.received===zod.z.ZodParsedType.undefined?{message:`${r} - No value was provided.`}:{message:`${r} - Invalid type. ${t.defaultError}.`};if(e.code===zod.z.ZodIssueCode.custom&&e.params?.errorMessage)return{message:`${r} - ${e.params?.errorMessage}, received '${t.data}'.`};if(e.code===zod.z.ZodIssueCode.invalid_union){let t=`Multiple errors occurred for the ${o}:\n`;return e.unionErrors.forEach((e=>{const o=e.issues[0].message.indexOf("-");t+=-1!==o?`${e.issues[0].message}\n`.substring(o):`${e.issues[0].message}\n`})),{message:t}}return{message:`${r} - ${t.defaultError}.`}}class ExportError extends Error{constructor(e,t){super(),this.message=e,this.stackMessage=e,t&&(this.statusCode=t)}setStatus(e){return this.statusCode=e,this}setError(e){return this.error=e,e.name&&(this.name=e.name),e.statusCode&&(this.statusCode=e.statusCode),e.stack&&(this.stackMessage=e.message,this.stack=e.stack),this}}const globalOptions=_initGlobalOptions(defaultConfig),instanceOptions=deepCopy(globalOptions);function getOptions(e=!0){return e?instanceOptions:globalOptions}function setGlobalOptions(e={},t=[]){let o={},r={};if(t&&Array.isArray(t)&&t.length){try{o=strictValidate(_loadConfigFile(t,globalOptions.customLogic))}catch(e){logZodIssues(1,e.issues,"[validation] Custom options from the `loadConfig` option validation error")}try{r=looseValidate(_pairArgumentValue(nestedProps,t))}catch(e){logZodIssues(1,e.issues,"[validation] CLI options validation error")}}if(e&&isObject(e)&&Object.keys(e).length)try{e=strictValidate(e)}catch(e){logZodIssues(1,e.issues,"[validation] Custom options validation error")}return _updateGlobalOptions(defaultConfig,globalOptions,o,r,e),globalOptions}function updateOptions(e,t=!1){return t&&(Object.keys(instanceOptions).forEach((e=>{delete instanceOptions[e]})),mergeOptions(instanceOptions,deepCopy(globalOptions))),mergeOptions(instanceOptions,e),instanceOptions}function mergeOptions(e,t){if(isObject(e)&&isObject(t))for(const[o,r]of Object.entries(t))e[o]=isObject(r)&&!absoluteProps.includes(o)&&void 0!==e[o]?mergeOptions(e[o],r):void 0!==r?r:e[o]||null;return e}function mapToNewOptions(e){const t={};if(isObject(e))for(const[o,r]of Object.entries(e)){const e=nestedProps[o]?nestedProps[o].split("."):[];e.reduce(((t,o,i)=>t[o]=e.length-1===i?r:t[o]||{}),t)}else log(2,"[config] No correct object with options was provided. Returning an empty array.");return t}function validateOption(e,t,o=!0){if(!getOptions().other.validation)return t;try{return validators[e](o).parse(t)}catch(t){throw logZodIssues(1,t.issues,`[validation] The ${e} option validation error`),new ExportError(`[validation] The ${e} option validation error`,400)}}function validateOptions(e,t=!0){if(!getOptions().other.validation)return e;try{return t?strictValidate(e):looseValidate(e)}catch(e){throw logZodIssues(1,e.issues,"[validation] Options validation error"),new ExportError("[validation] Options validation error",400)}}function isAllowedConfig(config,toString=!1,allowFunctions=!1){try{if(!isObject(config)&&"string"!=typeof config)return null;const objectConfig="string"==typeof config?allowFunctions?eval(`(${config})`):JSON.parse(config):config,stringifiedOptions=_optionsStringify(objectConfig,allowFunctions,!1),parsedOptions=allowFunctions?JSON.parse(_optionsStringify(objectConfig,allowFunctions,!0),((_,value)=>"string"==typeof value&&value.startsWith("function")?eval(`(${value})`):value)):JSON.parse(stringifiedOptions);return toString?stringifiedOptions:parsedOptions}catch(e){return null}}function _initGlobalOptions(e){const t={};for(const[o,r]of Object.entries(e))if(Object.prototype.hasOwnProperty.call(r,"value")){const e=envs[r.envLink];t[o]=null!=e?e:r.value}else t[o]=_initGlobalOptions(r);return t}function _updateGlobalOptions(e,t,o,r,i){Object.keys(e).forEach((n=>{const s=e[n],a=o&&o[n],l=r&&r[n],c=i&&i[n];if(void 0===s.value)_updateGlobalOptions(s,t[n],a,l,c);else{null!=a&&(t[n]=a);const e=envs[s.envLink];s.envLink in envs&&null!=e&&(t[n]=e),null!=l&&(t[n]=l),null!=c&&(t[n]=c)}}))}function _optionsStringify(e,t,o){return JSON.stringify(e,((e,r)=>{if("string"==typeof r&&(r=r.trim()),"function"==typeof r||"string"==typeof r&&r.startsWith("function")&&r.endsWith("}")){if(t)return o?`"EXP_FUN${(r+"").replaceAll(/\s+/g," ")}EXP_FUN"`:`EXP_FUN${(r+"").replaceAll(/\s+/g," ")}EXP_FUN`;throw new Error}return r})).replaceAll(o?/\\"EXP_FUN|EXP_FUN\\"/g:/"EXP_FUN|EXP_FUN"/g,"")}function _loadConfigFile(e,t){const o=e.findIndex((e=>"loadConfig"===e.replace(/-/g,""))),r=o>-1&&e[o+1];if(r&&t.allowFileResources)try{return isAllowedConfig(fs.readFileSync(getAbsolutePath(r),"utf8"),!1,t.allowCodeExecution)}catch(e){logWithStack(2,e,`[config] Unable to load the configuration from the ${r} file.`)}return{}}function _pairArgumentValue(e,t){const o={};for(let r=0;r{if(n.length-1===s){const n=t[++r];n||log(2,`[config] Missing value for the CLI '--${i}' argument. Using the default value.`),e[o]=n||null}else void 0===e[o]&&(e[o]={});return e[o]}),o)}return o}async function fetch(e,t={}){return new Promise(((o,r)=>{_getProtocolModule(e).get(e,t,(e=>{let t="";e.on("data",(e=>{t+=e})),e.on("end",(()=>{t||r("Nothing was fetched from the URL."),e.text=t,o(e)}))})).on("error",(e=>{r(e)}))}))}function _getProtocolModule(e){return e.startsWith("https")?https:http}const cache={cdnUrl:"https://code.highcharts.com",activeManifest:{},sources:"",hcVersion:""};async function checkAndUpdateCache(e,t){try{let o;const r=getCachePath(),i=path.join(r,"manifest.json"),n=path.join(r,"sources.js");if(!fs.existsSync(r)&&fs.mkdirSync(r,{recursive:!0}),!fs.existsSync(i)||e.forceFetch)log(3,"[cache] Fetching and caching Highcharts dependencies."),o=await _updateCache(e,t,n);else{let r=!1;const s=JSON.parse(fs.readFileSync(i),"utf8");if(s.modules&&Array.isArray(s.modules)){const e={};s.modules.forEach((t=>e[t]=1)),s.modules=e}const{coreScripts:a,moduleScripts:l,indicatorScripts:c}=e,p=a.length+l.length+c.length;s.version!==e.version?(log(2,"[cache] A Highcharts version mismatch in the cache, need to re-fetch."),r=!0):Object.keys(s.modules||{}).length!==p?(log(2,"[cache] The cache and the requested modules do not match, need to re-fetch."),r=!0):r=(l||[]).some((e=>{if(!s.modules[e])return log(2,`[cache] The ${e} is missing in the cache, need to re-fetch.`),!0})),r?o=await _updateCache(e,t,n):(log(3,"[cache] Dependency cache is up to date, proceeding."),cache.sources=fs.readFileSync(n,"utf8"),o=s.modules,cache.hcVersion=extractVersion(cache.sources))}await _saveConfigToManifest(e,o)}catch(e){throw new ExportError("[cache] Could not configure cache and create or update the config manifest.",500).setError(e)}}function getHighchartsVersion(){return cache.hcVersion}async function updateHighchartsVersion(e){const t=getOptions();t.highcharts.version=e,await checkAndUpdateCache(t.highcharts,t.server.proxy)}function extractVersion(e){return e.substring(0,e.indexOf("*/")).replace("/*","").replace("*/","").replace(/\n/g,"").trim()}function extractModuleName(e){return e.replace(/(.*)\/|(.*)modules\/|stock\/(.*)indicators\/|maps\/(.*)modules\//gi,"")}function getCachePath(){return getAbsolutePath(getOptions().highcharts.cachePath)}async function _fetchAndProcessScript(e,t,o,r=!1){e.endsWith(".js")&&(e=e.substring(0,e.length-3)),log(4,`[cache] Fetching script - ${e}.js`);const i=await fetch(`${e}.js`,t);if(200===i.statusCode&&"string"==typeof i.text){if(o){o[extractModuleName(e)]=1}return i.text}if(r)throw new ExportError(`[cache] Could not fetch the ${e}.js. The script might not exist in the requested version (status code: ${i.statusCode}).`,404).setError(i);log(2,`[cache] Could not fetch the ${e}.js. The script might not exist in the requested version.`)}async function _saveConfigToManifest(e,t={}){const o={version:e.version,modules:t};cache.activeManifest=o,log(3,"[cache] Writing a new manifest.");try{fs.writeFileSync(path.join(getCachePath(),"manifest.json"),JSON.stringify(o),"utf8")}catch(e){throw new ExportError("[cache] Error writing the cache manifest.",500).setError(e)}}async function _fetchScripts(e,t,o,r,i){let n;const s=r.host,a=r.port;if(s&&a)try{n=new httpsProxyAgent.HttpsProxyAgent({host:s,port:a})}catch(e){throw new ExportError("[cache] Could not create a Proxy Agent.",500).setError(e)}const l=n?{agent:n,timeout:r.timeout}:{},c=[...e.map((e=>_fetchAndProcessScript(`${e}`,l,i,!0))),...t.map((e=>_fetchAndProcessScript(`${e}`,l,i))),...o.map((e=>_fetchAndProcessScript(`${e}`,l)))];return(await Promise.all(c)).join(";\n")}async function _updateCache(e,t,o){const r="latest"===e.version?null:`${e.version}`,i=e.cdnUrl||cache.cdnUrl;try{const n={};return log(3,`[cache] Updating cache version to Highcharts: ${r||"latest"}.`),cache.sources=await _fetchScripts([...e.coreScripts.map((e=>r?`${i}/${r}/${e}`:`${i}/${e}`))],[...e.moduleScripts.map((e=>"map"===e?r?`${i}/maps/${r}/modules/${e}`:`${i}/maps/modules/${e}`:r?`${i}/${r}/modules/${e}`:`${i}/modules/${e}`)),...e.indicatorScripts.map((e=>r?`${i}/stock/${r}/indicators/${e}`:`${i}/stock/indicators/${e}`))],e.customScripts,t,n),cache.hcVersion=extractVersion(cache.sources),fs.writeFileSync(o,cache.sources),n}catch(e){throw new ExportError("[cache] Unable to update the local Highcharts cache.",500).setError(e)}}function setupHighcharts(){Highcharts.animObject=function(){return{duration:0}}}async function createChart(e,t){const{getOptions:o,setOptions:r,merge:i,wrap:n}=Highcharts;Highcharts.setOptionsObj=i(!1,{},o()),window.isRenderComplete=!1,n(Highcharts.Chart.prototype,"init",(function(e,t,o){((t=i(t,{exporting:{enabled:!1},plotOptions:{series:{label:{enabled:!1}}},tooltip:{}})).series||[]).forEach((function(e){e.animation=!1})),window.onHighchartsRender||(window.onHighchartsRender=Highcharts.addEvent(this,"render",(()=>{window.isRenderComplete=!0}))),e.apply(this,[t,o])})),n(Highcharts.Series.prototype,"init",(function(e,t,o){e.apply(this,[t,o])}));const s={chart:{animation:!1,height:e.height,width:e.width},exporting:{enabled:!1}},a=new Function(`return ${e.instr}`)(),l=new Function(`return ${e.themeOptions}`)(),c=new Function(`return ${e.globalOptions}`)(),p=i(!1,l,a,s),u=t.callback?new Function(`return ${t.callback}`)():null;t.customCode&&new Function("options",t.customCode)(a),c&&r(c),Highcharts[e.constr]("container",p,u);const d=o();for(const e in d)"function"!=typeof d[e]&&delete d[e];r(Highcharts.setOptionsObj),Highcharts.setOptionsObj={}}const template=fs.readFileSync(path.join(__dirname$1,"templates","template.html"),"utf8");let browser=null;async function createBrowser(e){const{debug:t,other:o}=getOptions(),{enable:r,...i}=t,n={headless:!o.browserShellMode||"shell",userDataDir:"tmp",args:e||[],handleSIGINT:!1,handleSIGTERM:!1,handleSIGHUP:!1,waitForInitialPage:!1,defaultViewport:null,...r&&i};if(!browser){let e=0;const t=async()=>{try{log(3,`[browser] Attempting to get a browser instance (try ${++e}).`),browser=await puppeteer.launch(n)}catch(o){if(logWithStack(1,o,"[browser] Failed to launch a browser instance."),!(e<25))throw o;log(3,`[browser] Retry to open a browser (${e} out of 25).`),await new Promise((e=>setTimeout(e,4e3))),await t()}};try{await t(),"shell"===n.headless&&log(3,"[browser] Launched browser in shell mode."),r&&log(3,"[browser] Launched browser in debug mode.")}catch(e){throw new ExportError("[browser] Maximum retries to open a browser instance reached.",500).setError(e)}if(!browser)throw new ExportError("[browser] Cannot find a browser to open.",500)}return browser}async function closeBrowser(){browser&&browser.connected&&await browser.close(),browser=null,log(4,"[browser] Closed the browser.")}async function newPage(e){if(!browser||!browser.connected)throw new ExportError("[browser] Browser is not yet connected.",500);if(e.page=await browser.newPage(),await e.page.setCacheEnabled(!1),await _setPageContent(e.page),_setPageEvents(e.page),!e.page||e.page.isClosed())throw new ExportError("[browser] The page is invalid or closed.",400)}async function clearPage(e,t=!1){try{if(e.page&&!e.page.isClosed())return t?(await e.page.goto("about:blank",{waitUntil:"domcontentloaded"}),await _setPageContent(e.page)):await e.page.evaluate((()=>{document.body.innerHTML='
'})),!0}catch(t){logWithStack(2,t,`[pool] Pool resource [${e.id}] - Content of the page could not be cleared.`),e.workCount=getOptions().pool.workLimit+1}return!1}async function addPageResources(e,t){const o=[],r=t.resources;if(r){const i=[];if(r.js&&i.push({content:r.js}),r.files)for(const e of r.files){const t=!e.startsWith("http");i.push(t?{content:fs.readFileSync(getAbsolutePath(e),"utf8")}:{url:e})}for(const t of i)try{o.push(await e.addScriptTag(t))}catch(e){logWithStack(2,e,"[browser] The JS resource cannot be loaded.")}i.length=0;const n=[];if(r.css){let i=r.css.match(/@import\s*([^;]*);/g);if(i)for(let e of i)e&&(e=e.replace("url(","").replace("@import","").replace(/"/g,"").replace(/'/g,"").replace(/;/,"").replace(/\)/g,"").trim(),e.startsWith("http")?n.push({url:e}):t.allowFileResources&&n.push({path:path.join(__dirname$1,e)}));n.push({content:r.css.replace(/@import\s*([^;]*);/g,"")||" "});for(const t of n)try{o.push(await e.addStyleTag(t))}catch(e){logWithStack(2,e,"[browser] The CSS resource cannot be loaded.")}n.length=0}}return o}async function clearPageResources(e,t){try{for(const e of t)await e.dispose();await e.evaluate((()=>{if("undefined"!=typeof Highcharts){const e=Highcharts.charts;if(Array.isArray(e)&&e.length)for(const t of e)t&&t.destroy(),Highcharts.charts.shift()}const[...e]=document.getElementsByTagName("script"),[,...t]=document.getElementsByTagName("style"),[...o]=document.getElementsByTagName("link");for(const r of[...e,...t,...o])r.remove()}))}catch(e){logWithStack(2,e,"[browser] Could not clear page's resources.")}}async function _setPageContent(e){await e.setContent(template,{waitUntil:"domcontentloaded"}),await e.addScriptTag({path:path.join(getCachePath(),"sources.js")}),await e.evaluate(setupHighcharts)}function _setPageEvents(e){const{debug:t}=getOptions();e.on("pageerror",(async()=>{e.isClosed()})),t.enable&&t.listenToConsole&&e.on("console",(e=>{console.log(`[debug] ${e.text()}`)}))}var cssTemplate=()=>"\n\nhtml, body {\n margin: 0;\n padding: 0;\n box-sizing: border-box;\n}\n\n#table-div, #sliders, #datatable, #controls, .ld-row {\n display: none;\n height: 0;\n}\n\n#chart-container {\n box-sizing: border-box;\n margin: 0;\n overflow: auto;\n font-size: 0;\n}\n\n#chart-container > figure, div {\n margin-top: 0 !important;\n margin-bottom: 0 !important;\n}\n\n",svgTemplate=e=>`\n\n\n \n \n Highcharts Export\n \n \n \n
\n ${e}\n
\n \n\n\n`;async function puppeteerExport(e,t,o){const r=[];try{let i=!1;if(t.svg){if(log(4,"[export] Treating as SVG input."),"svg"===t.type)return t.svg;i=!0,await e.setContent(svgTemplate(t.svg),{waitUntil:"domcontentloaded"})}else log(4,"[export] Treating as JSON config."),await e.evaluate(createChart,t,o);r.push(...await addPageResources(e,o));const n=i?await e.evaluate((e=>{const t=document.querySelector("#chart-container svg:first-of-type"),o=t.height.baseVal.value*e,r=t.width.baseVal.value*e;return document.body.style.zoom=e,document.body.style.margin="0px",{chartHeight:o,chartWidth:r}}),parseFloat(t.scale)):await e.evaluate((()=>{const{chartHeight:e,chartWidth:t}=window.Highcharts.charts[0];return document.body.style.zoom=1,{chartHeight:e,chartWidth:t}})),{x:s,y:a}=await _getClipRegion(e),l=Math.abs(Math.ceil(n.chartHeight||t.height)),c=Math.abs(Math.ceil(n.chartWidth||t.width));let p;switch(await e.setViewport({height:l,width:c,deviceScaleFactor:i?1:parseFloat(t.scale)}),t.type){case"svg":p=await _createSVG(e);break;case"png":case"jpeg":p=await _createImage(e,t.type,{width:c,height:l,x:s,y:a},t.rasterizationTimeout);break;case"pdf":p=await _createPDF(e,l,c,t.rasterizationTimeout);break;default:throw new ExportError(`[export] Unsupported output format: ${t.type}.`,400)}return await clearPageResources(e,r),p}catch(t){return await clearPageResources(e,r),t}}async function _getClipRegion(e){return e.$eval("#chart-container",(e=>{const{x:t,y:o,width:r,height:i}=e.getBoundingClientRect();return{x:t,y:o,width:r,height:Math.trunc(i>1?i:500)}}))}async function _createSVG(e){return e.$eval("#container svg:first-of-type",(e=>e.outerHTML))}async function _createImage(e,t,o,r){return Promise.race([e.screenshot({type:t,clip:o,encoding:"base64",fullPage:!1,optimizeForSpeed:!0,captureBeyondViewport:!0,..."png"!==t?{quality:80}:{},omitBackground:"png"==t}),new Promise(((e,t)=>setTimeout((()=>t(new ExportError("Rasterization timeout",408))),r||1500)))])}async function _createPDF(e,t,o,r){return await e.emulateMediaType("screen"),e.pdf({height:t+1,width:o,encoding:"base64",timeout:r||1500})}let pool=null;const poolStats={exportsAttempted:0,exportsPerformed:0,exportsDropped:0,exportsFromSvg:0,exportsFromOptions:0,exportsFromSvgAttempts:0,exportsFromOptionsAttempts:0,timeSpent:0,timeSpentAverage:0};async function initPool(e,t){await createBrowser(t);try{if(log(3,`[pool] Initializing pool with workers: min ${e.minWorkers}, max ${e.maxWorkers}.`),pool)return void log(4,"[pool] Already initialized, please kill it before creating a new one.");e.minWorkers>e.maxWorkers&&(e.minWorkers=e.maxWorkers),pool=new tarn.Pool({..._factory(e),min:e.minWorkers,max:e.maxWorkers,acquireTimeoutMillis:e.acquireTimeout,createTimeoutMillis:e.createTimeout,destroyTimeoutMillis:e.destroyTimeout,idleTimeoutMillis:e.idleTimeout,createRetryIntervalMillis:e.createRetryInterval,reapIntervalMillis:e.reaperInterval,propagateCreateError:!1}),pool.on("release",(async e=>{const t=await clearPage(e,!1);log(4,`[pool] Pool resource [${e.id}] - Releasing a worker. Clear page status: ${t}.`)})),pool.on("destroySuccess",((e,t)=>{log(4,`[pool] Pool resource [${t.id}] - Destroyed a worker successfully.`),t.page=null}));const t=[];for(let o=0;o{pool.release(e)})),log(3,"[pool] The pool is ready"+(t.length?` with ${t.length} initial resources waiting.`:"."))}catch(e){throw new ExportError("[pool] Could not configure and create the pool of workers.",500).setError(e)}}async function killPool(){if(log(3,"[pool] Killing pool with all workers and closing browser."),pool){for(const e of pool.used)pool.release(e.resource);pool.destroyed||(await pool.destroy(),log(4,"[pool] Destroyed the pool of resources.")),pool=null}await closeBrowser()}async function postWork(e){let t;try{if(log(4,"[pool] Work received, starting to process."),++poolStats.exportsAttempted,e.pool.benchmarking&&getPoolInfo(),!pool)throw new ExportError("[pool] Work received, but pool has not been started.",500);const o=measureTime();try{log(4,"[pool] Acquiring a worker handle."),t=await pool.acquire().promise,e.server.benchmarking&&log(5,"[benchmark] "+(e.requestId?`Request [${e.requestId}] - `:""),`Acquiring a worker handle took ${o()}ms.`)}catch(t){throw new ExportError(`[pool] ${e.requestId?`Request [${e.requestId}] - `:""}Error encountered when acquiring an available entry: ${o()}ms.`,400).setError(t)}if(log(4,"[pool] Acquired a worker handle."),!t.page)throw t.workCount=e.pool.workLimit+1,new ExportError("[pool] Resolved worker page is invalid: the pool setup is wonky.",400);const r=getNewDateTime();log(4,`[pool] Pool resource [${t.id}] - Starting work on this pool entry.`);const i=measureTime(),n=await puppeteerExport(t.page,e.export,e.customLogic);if(n instanceof Error)throw"Rasterization timeout"===n.message&&(t.workCount=e.pool.workLimit+1,t.page=null),"TimeoutError"===n.name||"Rasterization timeout"===n.message?new ExportError(`[pool] ${e.requestId?`Request [${e.requestId}] - `:""}Rasterization timeout: your chart may be too complex or large, and failed to render within the allotted time.`).setError(n):new ExportError(`[pool] ${e.requestId?`Request [${e.requestId}] - `:""}Error encountered during export: ${i()}ms.`).setError(n);e.server.benchmarking&&log(5,"[benchmark] "+(e.requestId?`Request [${e.requestId}] - `:""),`Exporting a chart sucessfully took ${i()}ms.`),pool.release(t);const s=getNewDateTime()-r;return poolStats.timeSpent+=s,poolStats.timeSpentAverage=poolStats.timeSpent/++poolStats.exportsPerformed,log(4,`[pool] Work completed in ${s}ms.`),{result:n,options:e}}catch(e){throw++poolStats.exportsDropped,t&&pool.release(t),e}}function getPoolStats(){return poolStats}function getPoolInfoJSON(){return{min:pool.min,max:pool.max,used:pool.numUsed(),available:pool.numFree(),allCreated:pool.numUsed()+pool.numFree(),pendingAcquires:pool.numPendingAcquires(),pendingCreates:pool.numPendingCreates(),pendingValidations:pool.numPendingValidations(),pendingDestroys:pool.pendingDestroys.length,absoluteAll:pool.numUsed()+pool.numFree()+pool.numPendingAcquires()+pool.numPendingCreates()+pool.numPendingValidations()+pool.pendingDestroys.length}}function getPoolInfo(){const{min:e,max:t,used:o,available:r,allCreated:i,pendingAcquires:n,pendingCreates:s,pendingValidations:a,pendingDestroys:l,absoluteAll:c}=getPoolInfoJSON();log(5,`[pool] The minimum number of resources allowed by pool: ${e}.`),log(5,`[pool] The maximum number of resources allowed by pool: ${t}.`),log(5,`[pool] The number of used resources: ${o}.`),log(5,`[pool] The number of free resources: ${r}.`),log(5,`[pool] The number of all created (used and free) resources: ${i}.`),log(5,`[pool] The number of resources waiting to be acquired: ${n}.`),log(5,`[pool] The number of resources waiting to be created: ${s}.`),log(5,`[pool] The number of resources waiting to be validated: ${a}.`),log(5,`[pool] The number of resources waiting to be destroyed: ${l}.`),log(5,`[pool] The number of all resources: ${c}.`)}function _factory(e){return{create:async()=>{const t={id:uuid.v4(),workCount:Math.round(Math.random()*(e.workLimit/2))};try{const e=getNewDateTime();return await newPage(t),log(3,`[pool] Pool resource [${t.id}] - Successfully created a worker, took ${getNewDateTime()-e}ms.`),t}catch(e){throw log(3,`[pool] Pool resource [${t.id}] - Error encountered when creating a new page.`),e}},validate:async t=>t.page?t.page.isClosed()?(log(3,`[pool] Pool resource [${t.id}] - Validation failed (page is closed or invalid).`),!1):t.page.mainFrame().detached?(log(3,`[pool] Pool resource [${t.id}] - Validation failed (page's frame is detached).`),!1):!(e.workLimit&&++t.workCount>e.workLimit)||(log(3,`[pool] Pool resource [${t.id}] - Validation failed (exceeded the ${e.workLimit} works per resource limit).`),!1):(log(3,`[pool] Pool resource [${t.id}] - Validation failed (no valid page is found).`),!1),destroy:async e=>{if(log(3,`[pool] Pool resource [${e.id}] - Destroying a worker.`),e.page&&!e.page.isClosed())try{e.page.removeAllListeners("pageerror"),e.page.removeAllListeners("console"),e.page.removeAllListeners("framedetached"),await e.page.close()}catch(t){throw log(3,`[pool] Pool resource [${e.id}] - Page could not be closed upon destroying.`),t}}}}function sanitize(e){const t=new jsdom.JSDOM("").window;return DOMPurify(t).sanitize(e,{ADD_TAGS:["foreignObject"]})}let allowCodeExecution=!1;async function singleExport(e){if(!e||!e.export)throw new ExportError("[chart] No expected `export` options were found. Please provide one of the following options: `infile`, `instr`, `options`, or `svg` to generate a valid image.",400);e=validateOptions(e),await startExport({export:e.export,customLogic:e.customLogic},(async(e,t)=>{if(e)throw e;const{b64:o,outfile:r,type:i}=t.options.export;try{o?fs.writeFileSync(`${r.split(".").shift()||"chart"}.txt`,getBase64(t.result,i)):fs.writeFileSync(r||`chart.${i}`,"svg"!==i?Buffer.from(t.result,"base64"):t.result)}catch(e){throw new ExportError("[chart] Error while saving a chart.",500).setError(e)}await killPool()}))}async function batchExport(e){if(!(e&&e.export&&e.export.batch))throw new ExportError("[chart] No expected `export` options were found. Please provide the `batch` option to generate valid images.",400);{e=validateOptions(e);const t=[];for(let o of e.export.batch.split(";")||[])o=o.split("="),2===o.length?t.push(startExport({export:{...e.export,infile:o[0],outfile:o[1]},customLogic:e.customLogic},((e,t)=>{if(e)throw e;const{b64:o,outfile:r,type:i}=t.options.export;try{o?fs.writeFileSync(`${r.split(".").shift()||"chart"}.txt`,getBase64(t.result,i)):fs.writeFileSync(r,"svg"!==i?Buffer.from(t.result,"base64"):t.result)}catch(e){throw new ExportError("[chart] Error while saving a chart.",500).setError(e)}}))):log(2,"[chart] No correct pair found for the batch export.");const o=await Promise.allSettled(t);await killPool(),o.forEach(((e,t)=>{e.reason&&logWithStack(1,e.reason,`[chart] Batch export number ${t+1} could not be correctly completed.`)}))}}async function startExport(e,t){try{if(!isObject(e))throw new ExportError("[chart] Incorrect value of the provided `exportingOptions`. Needs to be an object.",400);const o=mergeOptions(deepCopy(getOptions()),{export:e.export,customLogic:e.customLogic}),r=o.export;if(log(4,"[chart] Starting the exporting process."),null!==r.infile){let e;log(4,"[chart] Attempting to export from a file input.");try{e=fs.readFileSync(getAbsolutePath(r.infile),"utf8")}catch(e){throw new ExportError("[chart] Error loading content from a file input.",400).setError(e)}if(r.infile.endsWith(".svg"))r.svg=validateOption("svg",e);else{if(!r.infile.endsWith(".json"))throw new ExportError("[chart] Incorrect value of the `infile` option.",400);r.instr=validateOption("instr",e)}}if(null!==r.svg){log(4,"[chart] Attempting to export from an SVG input."),++getPoolStats().exportsFromSvgAttempts;const e=await _exportFromSvg(sanitize(r.svg),o);return++getPoolStats().exportsFromSvg,t(null,e)}if(null!==r.instr||null!==r.options){log(4,"[chart] Attempting to export from options input."),++getPoolStats().exportsFromOptionsAttempts;const e=await _exportFromOptions(r.instr||r.options,o);return++getPoolStats().exportsFromOptions,t(null,e)}return t(new ExportError("[chart] No valid input specified. Check if at least one of the following parameters is correctly set: 'infile', 'instr', 'options', or 'svg'.",400))}catch(e){return t(e)}}function getAllowCodeExecution(){return allowCodeExecution}function setAllowCodeExecution(e){allowCodeExecution=e}async function _exportFromSvg(e,t){if("string"==typeof e&&(e.indexOf("=0||e.indexOf("=0))return log(4,"[chart] Parsing input as SVG."),t.export.svg=e,t.export.instr=null,t.export.options=null,_prepareExport(t);throw new ExportError("[chart] Not a correct SVG input.",400)}async function _exportFromOptions(e,t){log(4,"[chart] Parsing input from options.");const o=isAllowedConfig(e,!0,t.customLogic.allowCodeExecution);if(null===o||"string"!=typeof o||!o.startsWith("{")||!o.endsWith("}"))throw new ExportError("[chart] Invalid configuration provided - Only options configurations and SVG are allowed for this server. If this is your server, JavaScript custom code can be enabled by starting the server with the `allowCodeExecution` options set to true.",403);return t.export.instr=o,t.export.svg=null,_prepareExport(t)}async function _prepareExport(e){const{export:t,customLogic:o}=e;return t.type=fixType(t.type,t.outfile),t.outfile=fixOutfile(t.type,t.outfile),t.constr=fixConstr(t.constr),log(3,`[chart] The custom logic is ${o.allowCodeExecution?"allowed":"disallowed"}.`),_handleCustomLogic(o,o.allowCodeExecution),_handleGlobalAndTheme(t,o.allowFileResources,o.allowCodeExecution),e.export={...t,..._findChartSize(t)},postWork(e)}function _findChartSize(e){const{chart:t,exporting:o}=e.options||isAllowedConfig(e.instr)||!1,{chart:r,exporting:i}=isAllowedConfig(e.globalOptions)||!1,{chart:n,exporting:s}=isAllowedConfig(e.themeOptions)||!1,a=roundNumber(Math.max(.1,Math.min(e.scale||o?.scale||i?.scale||s?.scale||e.defaultScale||1,5)),2),l={height:e.height||o?.sourceHeight||t?.height||i?.sourceHeight||r?.height||s?.sourceHeight||n?.height||e.defaultHeight||400,width:e.width||o?.sourceWidth||t?.width||i?.sourceWidth||r?.width||s?.sourceWidth||n?.width||e.defaultWidth||600,scale:a};for(let[e,t]of Object.entries(l))l[e]="string"==typeof t?+t.replace(/px|%/gi,""):t;return l}function _handleCustomLogic(e,t){if(t){if("string"==typeof e.resources)e.resources=_handleResources(e.resources,e.allowFileResources,!0);else if(!e.resources)try{e.resources=_handleResources(fs.readFileSync(getAbsolutePath("resources.json"),"utf8"),e.allowFileResources,!0)}catch(e){log(2,"[chart] Unable to load the default `resources.json` file.")}try{e.customCode=wrapAround(e.customCode,e.allowFileResources),e.customCode=validateOption("customCode",e.customCode)}catch(t){logWithStack(2,t,"[chart] The `customCode` cannot be loaded."),e.customCode=null}try{e.callback=wrapAround(e.callback,e.allowFileResources,!0),e.callback=validateOption("callback",e.callback)}catch(t){logWithStack(2,t,"[chart] The `callback` cannot be loaded."),e.callback=null}[null,void 0].includes(e.customCode)&&log(3,"[chart] No value for the `customCode` option found."),[null,void 0].includes(e.callback)&&log(3,"[chart] No value for the `callback` option found."),[null,void 0].includes(e.resources)&&log(3,"[chart] No value for the `resources` option found.")}else if(e.callback||e.resources||e.customCode)throw e.callback=null,e.resources=null,e.customCode=null,new ExportError("[chart] The 'callback', 'resources', and 'customCode' options have been disabled for this server.",403)}function _handleResources(e=null,t,o){const r=["js","css","files"];let i=e,n=!1;if(t&&e.endsWith(".json"))try{i=isAllowedConfig(fs.readFileSync(getAbsolutePath(e),"utf8"),!1,o)}catch{return null}else i=isAllowedConfig(e,!1,o),i&&!t&&delete i.files;for(const e in i)r.includes(e)?n||(n=!0):delete i[e];return n?(i.files&&(i.files=i.files.map((e=>e.trim())),(!i.files||i.files.length<=0)&&delete i.files),i=validateOption("resources",i),i):null}function _handleGlobalAndTheme(e,t,o){["globalOptions","themeOptions"].forEach((r=>{try{e[r]&&(t&&"string"==typeof e[r]&&e[r].endsWith(".json")?e[r]=isAllowedConfig(fs.readFileSync(getAbsolutePath(e[r]),"utf8"),!0,o):e[r]=isAllowedConfig(e[r],!0,o),e[r]=validateOption(r,e[r]))}catch(t){logWithStack(2,t,`[chart] The \`${r}\` cannot be loaded.`),e[r]=null}})),[null,void 0].includes(e.globalOptions)&&log(3,"[chart] No value for the `globalOptions` option found."),[null,void 0].includes(e.themeOptions)&&log(3,"[chart] No value for the `themeOptions` option found.")}const timerIds=[];function addTimer(e){timerIds.push(e)}function clearAllTimers(){log(4,"[timer] Clearing all registered intervals and timeouts.");for(const e of timerIds)clearInterval(e),clearTimeout(e)}function logErrorMiddleware(e,t,o,r){return logWithStack(1,e),"development"!==getOptions().other.nodeEnv&&delete e.stack,r(e)}function returnErrorMiddleware(e,t,o,r){const{message:i,stack:n}=e,s=e.statusCode||400;o.status(s).json({statusCode:s,message:i,stack:n})}function errorMiddleware(e){e.use(logErrorMiddleware),e.use(returnErrorMiddleware)}function rateLimitingMiddleware(e,t){try{if(t.enable){const o="Too many requests, you have been rate limited. Please try again later.",r={window:t.window||1,maxRequests:t.maxRequests||30,delay:t.delay||0,trustProxy:t.trustProxy||!1,skipKey:t.skipKey||null,skipToken:t.skipToken||null};r.trustProxy&&e.enable("trust proxy");const i=rateLimit({windowMs:60*r.window*1e3,limit:r.maxRequests,delayMs:r.delay,handler:(e,t)=>{t.format({json:()=>{t.status(429).send({message:o})},default:()=>{t.status(429).send(o)}})},skip:e=>null!==r.skipKey&&null!==r.skipToken&&e.query.key===r.skipKey&&e.query.access_token===r.skipToken&&(log(4,"[rate limiting] Skipping rate limiter."),!0)});e.use(i),log(3,`[rate limiting] Enabled rate limiting with ${r.maxRequests} requests per ${r.window} minute for each IP, trusting proxy: ${r.trustProxy}.`)}}catch(e){throw new ExportError("[rate limiting] Could not configure and set the rate limiting options.",500).setError(e)}}function contentTypeMiddleware(e,t,o){try{const t=e.headers["content-type"]||"";if(!t.includes("application/json")&&!t.includes("application/x-www-form-urlencoded")&&!t.includes("multipart/form-data"))throw new ExportError("[validation] Content-Type must be application/json, application/x-www-form-urlencoded, or multipart/form-data.",415);return o()}catch(e){return o(e)}}function requestBodyMiddleware(e,t,o){try{const t=e.body,r=uuid.v4();if(!t||isObjectEmpty(t))throw log(2,`[validation] Request [${r}] - The request from ${e.headers["x-forwarded-for"]||e.connection.remoteAddress} was incorrect. Received payload is empty.`),new ExportError(`[validation] Request [${r}] - The request body is required. Please ensure that your Content-Type header is correct. Accepted types are 'application/json' and 'multipart/form-data'.`,400);const i=getAllowCodeExecution(),n=isAllowedConfig(t.instr||t.options||t.infile||t.data,!0,i);if(null===n&&!t.svg)throw log(2,`[validation] Request [${r}] - The request from ${e.headers["x-forwarded-for"]||e.connection.remoteAddress} was incorrect. Received payload is missing correct chart data for export: ${JSON.stringify(t)}.`),new ExportError(`Request [${r}] - [validation] No correct chart data found. Ensure that you are using either application/json or multipart/form-data headers. If sending JSON, make sure the chart data is in the 'infile', 'options', or 'data' attribute. If sending SVG, ensure it is in the 'svg' attribute.`,400);if(t.svg&&isPrivateRangeUrlFound(t.svg))throw new ExportError(`Request [${r}] - [validation] SVG potentially contain at least one forbidden URL in 'xlink:href' element. Please review the SVG content and ensure that all referenced URLs comply with security policies.`,400);return e.validatedOptions=validateOptions({requestId:r,export:{instr:n,svg:t.svg,outfile:t.outfile||`${e.params.filename||"chart"}.${t.type||"png"}`,type:t.type,constr:t.constr,b64:t.b64,noDownload:t.noDownload,height:t.height,width:t.width,scale:t.scale,globalOptions:isAllowedConfig(t.globalOptions,!0,i),themeOptions:isAllowedConfig(t.themeOptions,!0,i)},customLogic:{allowCodeExecution:i,allowFileResources:!1,customCode:t.customCode,callback:t.callback,resources:isAllowedConfig(t.resources,!0,i)}}),o()}catch(e){return o(e)}}function validationMiddleware(e){e.post(["/","/:filename"],contentTypeMiddleware),e.post(["/","/:filename"],requestBodyMiddleware)}const reversedMime={png:"image/png",jpeg:"image/jpeg",gif:"image/gif",pdf:"application/pdf",svg:"image/svg+xml"};async function requestExport(e,t,o){try{const o=measureTime();let r=!1;e.socket.on("close",(e=>{e&&(r=!0)}));const i=e.validatedOptions,n=i.requestId;log(4,`[export] Request [${n}] - Got an incoming HTTP request.`),await startExport(i,((i,s)=>{if(e.socket.removeAllListeners("close"),r)log(3,`[export] Request [${n}] - The client closed the connection before the chart finished processing.`);else{if(i)throw i;if(!s||!s.result)throw log(2,`[export] Request [${n}] - Request from ${e.headers["x-forwarded-for"]||e.connection.remoteAddress} was incorrect. Received result is ${s.result}.`),new ExportError(`[export] Request [${n}] - Unexpected return of the export result from the chart generation. Please check your request data.`,400);if(s.result){log(3,`[export] Request [${n}] - The whole exporting process took ${o()}ms.`);const{type:e,b64:r,noDownload:i,outfile:a}=s.options.export;return r?t.send(getBase64(s.result,e)):(t.header("Content-Type",reversedMime[e]||"image/png"),i||t.attachment(a),"svg"===e?t.send(s.result):t.send(Buffer.from(s.result,"base64")))}}}))}catch(e){return o(e)}}function exportRoutes(e){e.post("/",requestExport),e.post("/:filename",requestExport)}const serverStartTime=new Date,packageFile=JSON.parse(fs.readFileSync(path.join(__dirname$1,"package.json"),"utf8")),successRates=[],recordInterval=6e4,windowSize=30;function _calculateMovingAverage(){return successRates.reduce(((e,t)=>e+t),0)/successRates.length}function _startSuccessRate(){return setInterval((()=>{const e=getPoolStats(),t=0===e.exportsAttempted?1:e.exportsPerformed/e.exportsAttempted*100;successRates.push(t),successRates.length>windowSize&&successRates.shift()}),recordInterval)}function healthRoutes(e){addTimer(_startSuccessRate()),e.get("/health",((e,t,o)=>{try{log(4,"[health] Returning server health.");const e=getPoolStats(),o=successRates.length,r=_calculateMovingAverage();t.send({status:"OK",bootTime:serverStartTime,uptime:`${Math.floor((getNewDateTime()-serverStartTime.getTime())/1e3/60)} minutes`,serverVersion:packageFile.version,highchartsVersion:getHighchartsVersion(),averageExportTime:e.timeSpentAverage,attemptedExports:e.exportsAttempted,performedExports:e.exportsPerformed,failedExports:e.exportsDropped,sucessRatio:e.exportsPerformed/e.exportsAttempted*100,pool:getPoolInfoJSON(),period:o,movingAverage:r,message:isNaN(r)||!successRates.length?"Too early to report. No exports made yet. Please check back soon.":`Last ${o} minutes had a success rate of ${r.toFixed(2)}%.`,svgExports:e.exportsFromSvg,jsonExports:e.exportsFromOptions,svgExportsAttempts:e.exportsFromSvgAttempts,jsonExportsAttempts:e.exportsFromOptionsAttempts})}catch(e){return o(e)}}))}function uiRoutes(e){e.get(getOptions().ui.route||"/",((e,t,o)=>{try{log(4,"[ui] Returning UI for the export."),t.sendFile(path.join(__dirname$1,"public","index.html"),{acceptRanges:!1})}catch(e){return o(e)}}))}function versionChangeRoutes(e){e.post("/version_change/:newVersion",(async(e,t,o)=>{try{log(4,"[version] Changing Highcharts version.");const o=envs.HIGHCHARTS_ADMIN_TOKEN;if(!o||!o.length)throw new ExportError("[version] The server is not configured to perform run-time version changes: HIGHCHARTS_ADMIN_TOKEN is not set.",401);const r=e.get("hc-auth");if(!r||r!==o)throw new ExportError("[version] Invalid or missing token: Set the token in the hc-auth header.",401);let i=e.params.newVersion;try{i=validateOption("version",e.params.newVersion)}catch(e){throw new ExportError(`[version] Version is incorrect: ${e.message}`,400).setError(e)}if(!i)throw new ExportError("[version] No new version supplied.",400);try{await updateHighchartsVersion(i)}catch(e){throw new ExportError(`[version] Version change: ${e.message}`,400).setError(e)}t.status(200).send({statusCode:200,highchartsVersion:getHighchartsVersion(),message:`Successfully updated Highcharts to version: ${i}.`})}catch(e){return o(e)}}))}const activeServers=new Map,app=express();async function startServer(e){try{const t=updateOptions(validateOptions({server:e}));if(!(e=t.server).enable||!app)throw new ExportError("[server] Server cannot be started (not enabled or no correct Express app found).",500);const o=1024*e.uploadLimit*1024,r=multer.memoryStorage(),i=multer({storage:r,limits:{fieldSize:o}});if(app.disable("x-powered-by"),app.use(cors({methods:["POST","GET","OPTIONS"]})),app.use(((e,t,o)=>{t.set("Accept-Ranges","none"),o()})),app.use(express.json({limit:o})),app.use(express.urlencoded({extended:!0,limit:o})),app.use(i.none()),app.use(express.static(path.join(__dirname$1,"public"))),!e.ssl.force){const t=http.createServer(app);_attachServerErrorHandlers(t),t.listen(e.port,e.host,(()=>{activeServers.set(e.port,t),log(3,`[server] Started HTTP server on ${e.host}:${e.port}.`)}))}if(e.ssl.enable){let t,o;try{t=await promises.readFile(path.join(getAbsolutePath(e.ssl.certPath),"server.key"),"utf8"),o=await promises.readFile(path.join(getAbsolutePath(e.ssl.certPath),"server.crt"),"utf8")}catch(t){log(2,`[server] Unable to load key/certificate from the '${e.ssl.certPath}' path. Could not run secured layer server.`)}if(t&&o){const r=https.createServer({key:t,cert:o},app);_attachServerErrorHandlers(r),r.listen(e.ssl.port,e.host,(()=>{activeServers.set(e.ssl.port,r),log(3,`[server] Started HTTPS server on ${e.host}:${e.ssl.port}.`)}))}}rateLimitingMiddleware(app,e.rateLimiting),validationMiddleware(app),exportRoutes(app),healthRoutes(app),uiRoutes(app),versionChangeRoutes(app),errorMiddleware(app)}catch(e){throw new ExportError("[server] Could not configure and start the server.",500).setError(e)}}function closeServers(){if(activeServers.size>0){log(4,"[server] Closing all servers.");for(const[e,t]of activeServers)t.close((()=>{activeServers.delete(e),log(4,`[server] Closed server on port: ${e}.`)}))}}function getServers(){return activeServers}function getExpress(){return express}function getApp(){return app}function enableRateLimiting(e){const t=updateOptions(validateOptions({server:{rateLimiting:e}}));rateLimitingMiddleware(app,t.server.rateLimitingOptions)}function use(e,...t){app.use(e,...t)}function get(e,...t){app.get(e,...t)}function post(e,...t){app.post(e,...t)}function _attachServerErrorHandlers(e){e.on("clientError",((e,t)=>{logWithStack(1,e,`[server] Client error: ${e.message}, destroying socket.`),t.destroy()})),e.on("error",(e=>{logWithStack(1,e,`[server] Server error: ${e.message}`)})),e.on("connection",(e=>{e.on("error",(e=>{logWithStack(1,e,`[server] Socket error: ${e.message}`)}))}))}var server={startServer:startServer,closeServers:closeServers,getServers:getServers,getExpress:getExpress,getApp:getApp,enableRateLimiting:enableRateLimiting,use:use,get:get,post:post};async function shutdownCleanUp(e=0){await Promise.allSettled([clearAllTimers(),closeServers(),killPool()]),process.exit(e)}async function initExport(e={}){const t=updateOptions(validateOptions(e),!0);setAllowCodeExecution(t.customLogic.allowCodeExecution),initLogging(t.logging),t.other.listenToProcessExits&&_attachProcessExitListeners(),await checkAndUpdateCache(t.highcharts,t.server.proxy),await initPool(t.pool,t.puppeteer.args)}function _attachProcessExitListeners(){log(3,"[process] Attaching exit listeners to the process."),process.on("exit",(e=>{log(4,`[process] Process exited with code ${e}.`)})),process.on("SIGINT",(async(e,t)=>{log(4,`[process] The ${e} event with code: ${t}.`),await shutdownCleanUp()})),process.on("SIGTERM",(async(e,t)=>{log(4,`[process] The ${e} event with code: ${t}.`),await shutdownCleanUp()})),process.on("SIGHUP",(async(e,t)=>{log(4,`[process] The ${e} event with code: ${t}.`),await shutdownCleanUp()})),process.on("uncaughtException",(async(e,t)=>{logWithStack(1,e,`[process] The ${t} error.`),await shutdownCleanUp(1)}))}var index={...server,getOptions:getOptions,setGlobalOptions:setGlobalOptions,mapToNewOptions:mapToNewOptions,validateOption:validateOption,validateOptions:validateOptions,initExport:initExport,singleExport:singleExport,batchExport:batchExport,startExport:startExport,killPool:killPool,shutdownCleanUp:shutdownCleanUp,log:log,logWithStack:logWithStack,logZodIssues:logZodIssues,setLogLevel:function(e){setLogLevel(updateOptions(validateOptions({logging:{level:e}})).logging.level)},enableConsoleLogging:function(e){enableConsoleLogging(updateOptions(validateOptions({logging:{toConsole:e}})).logging.toConsole)},enableFileLogging:function(e,t,o){const r=updateOptions(validateOptions({logging:{dest:e,file:t,toFile:o}}));enableFileLogging(r.logging.dest,r.logging.file,r.logging.toFile)}};exports.default=index,exports.initExport=initExport; -//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguY2pzIiwic291cmNlcyI6WyIuLi9saWIvdXRpbHMuanMiLCIuLi9saWIvbG9nZ2VyLmpzIiwiLi4vbGliL3NjaGVtYXMvY29uZmlnLmpzIiwiLi4vbGliL3ZhbGlkYXRpb24uanMiLCIuLi9saWIvZXJyb3JzL0V4cG9ydEVycm9yLmpzIiwiLi4vbGliL2NvbmZpZy5qcyIsIi4uL2xpYi9mZXRjaC5qcyIsIi4uL2xpYi9jYWNoZS5qcyIsIi4uL2xpYi9oaWdoY2hhcnRzLmpzIiwiLi4vbGliL2Jyb3dzZXIuanMiLCIuLi90ZW1wbGF0ZXMvc3ZnRXhwb3J0L2Nzcy5qcyIsIi4uL3RlbXBsYXRlcy9zdmdFeHBvcnQvc3ZnRXhwb3J0LmpzIiwiLi4vbGliL2V4cG9ydC5qcyIsIi4uL2xpYi9wb29sLmpzIiwiLi4vbGliL3Nhbml0aXplLmpzIiwiLi4vbGliL2NoYXJ0LmpzIiwiLi4vbGliL3RpbWVyLmpzIiwiLi4vbGliL3NlcnZlci9taWRkbGV3YXJlcy9lcnJvci5qcyIsIi4uL2xpYi9zZXJ2ZXIvbWlkZGxld2FyZXMvcmF0ZUxpbWl0aW5nLmpzIiwiLi4vbGliL3NlcnZlci9taWRkbGV3YXJlcy92YWxpZGF0aW9uLmpzIiwiLi4vbGliL3NlcnZlci9yb3V0ZXMvZXhwb3J0LmpzIiwiLi4vbGliL3NlcnZlci9yb3V0ZXMvaGVhbHRoLmpzIiwiLi4vbGliL3NlcnZlci9yb3V0ZXMvdWkuanMiLCIuLi9saWIvc2VydmVyL3JvdXRlcy92ZXJzaW9uQ2hhbmdlLmpzIiwiLi4vbGliL3NlcnZlci9zZXJ2ZXIuanMiLCIuLi9saWIvcmVzb3VyY2VSZWxlYXNlLmpzIiwiLi4vbGliL2luZGV4LmpzIl0sInNvdXJjZXNDb250ZW50IjpbIi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXHJcblxyXG5IaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXJcclxuXHJcbkNvcHlyaWdodCAoYykgMjAxNi0yMDI1LCBIaWdoc29mdFxyXG5cclxuTGljZW5jZWQgdW5kZXIgdGhlIE1JVCBsaWNlbmNlLlxyXG5cclxuQWRkaXRpb25hbGx5IGEgdmFsaWQgSGlnaGNoYXJ0cyBsaWNlbnNlIGlzIHJlcXVpcmVkIGZvciB1c2UuXHJcblxyXG5TZWUgTElDRU5TRSBmaWxlIGluIHJvb3QgZm9yIGRldGFpbHMuXHJcblxyXG4qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xyXG5cclxuLyoqXHJcbiAqIEBvdmVydmlldyBUaGUgSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyIHV0aWxpdHkgbW9kdWxlIHByb3ZpZGVzXHJcbiAqIGEgY29tcHJlaGVuc2l2ZSBzZXQgb2YgaGVscGVyIGZ1bmN0aW9ucyBhbmQgY29uc3RhbnRzIGRlc2lnbmVkIHRvIHN0cmVhbWxpbmVcclxuICogYW5kIGVuaGFuY2UgdmFyaW91cyBvcGVyYXRpb25zIHJlcXVpcmVkIGZvciBIaWdoY2hhcnRzIGV4cG9ydCB0YXNrcy5cclxuICovXHJcblxyXG5pbXBvcnQgeyByZWFkRmlsZVN5bmMgfSBmcm9tICdmcyc7XHJcbmltcG9ydCB7IGlzQWJzb2x1dGUsIGpvaW4gfSBmcm9tICdwYXRoJztcclxuaW1wb3J0IHsgZmlsZVVSTFRvUGF0aCB9IGZyb20gJ3VybCc7XHJcblxyXG5jb25zdCBNQVhfQkFDS09GRl9BVFRFTVBUUyA9IDY7XHJcblxyXG4vLyBUaGUgZGlyZWN0b3J5IHBhdGhcclxuZXhwb3J0IGNvbnN0IF9fZGlybmFtZSA9IGZpbGVVUkxUb1BhdGgobmV3IFVSTCgnLi4vLicsIGltcG9ydC5tZXRhLnVybCkpO1xyXG5cclxuLyoqXHJcbiAqIENsZWFycyBhbmQgc3RhbmRhcmRpemVzIHRleHQgYnkgcmVwbGFjaW5nIG11bHRpcGxlIGNvbnNlY3V0aXZlIHdoaXRlc3BhY2VcclxuICogY2hhcmFjdGVycyB3aXRoIGEgc2luZ2xlIHNwYWNlIGFuZCB0cmltbWluZyBhbnkgbGVhZGluZyBvciB0cmFpbGluZ1xyXG4gKiB3aGl0ZXNwYWNlLlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gY2xlYXJUZXh0XHJcbiAqXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSB0ZXh0IC0gVGhlIGlucHV0IHRleHQgdG8gYmUgY2xlYXJlZC5cclxuICogQHBhcmFtIHtSZWdFeHB9IFtydWxlPS9cXHNcXHMrL2ddIC0gVGhlIHJlZ3VsYXIgZXhwcmVzc2lvbiBydWxlIHRvIG1hdGNoXHJcbiAqIG11bHRpcGxlIGNvbnNlY3V0aXZlIHdoaXRlc3BhY2UgY2hhcmFjdGVycy4gVGhlIGRlZmF1bHQgdmFsdWVcclxuICogaXMgdGhlICcvXFxzXFxzKy9nJyBSZWdFeHAuXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSBbcmVwbGFjZXI9JyAnXSAtIFRoZSBzdHJpbmcgdXNlZCB0byByZXBsYWNlIG11bHRpcGxlXHJcbiAqIGNvbnNlY3V0aXZlIHdoaXRlc3BhY2UgY2hhcmFjdGVycy4gVGhlIGRlZmF1bHQgdmFsdWUgaXMgdGhlICcgJyBzdHJpbmcuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtzdHJpbmd9IFRoZSBjbGVhcmVkIGFuZCBzdGFuZGFyZGl6ZWQgdGV4dC5cclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiBjbGVhclRleHQodGV4dCwgcnVsZSA9IC9cXHNcXHMrL2csIHJlcGxhY2VyID0gJyAnKSB7XHJcbiAgcmV0dXJuIHRleHQucmVwbGFjZUFsbChydWxlLCByZXBsYWNlcikudHJpbSgpO1xyXG59XHJcblxyXG4vKipcclxuICogQ3JlYXRlcyBhIGRlZXAgY29weSBvZiB0aGUgZ2l2ZW4gb2JqZWN0IG9yIGFycmF5LlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gZGVlcENvcHlcclxuICpcclxuICogQHBhcmFtIHsoT2JqZWN0fEFycmF5KX0gb2JqQXJyIC0gVGhlIG9iamVjdCBvciBhcnJheSB0byBiZSBkZWVwbHkgY29waWVkLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7KE9iamVjdHxBcnJheSl9IFRoZSBkZWVwIGNvcHkgb2YgdGhlIHByb3ZpZGVkIG9iamVjdCBvciBhcnJheS5cclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiBkZWVwQ29weShvYmpBcnIpIHtcclxuICAvLyBJZiB0aGUgYG9iakFycmAgaXMgbnVsbCBvciBub3Qgb2YgdGhlIGBvYmplY3RgIHR5cGUsIHJldHVybiBpdFxyXG4gIGlmIChvYmpBcnIgPT09IG51bGwgfHwgdHlwZW9mIG9iakFyciAhPT0gJ29iamVjdCcpIHtcclxuICAgIHJldHVybiBvYmpBcnI7XHJcbiAgfVxyXG5cclxuICAvLyBQcmVwYXJlIGVpdGhlciBhIG5ldyBhcnJheSBvciBhIG5ldyBvYmplY3RcclxuICBjb25zdCBvYmpBcnJDb3B5ID0gQXJyYXkuaXNBcnJheShvYmpBcnIpID8gW10gOiB7fTtcclxuXHJcbiAgLy8gUmVjdXJzaXZlbHkgY29weSBlYWNoIHByb3BlcnR5XHJcbiAgZm9yIChjb25zdCBrZXkgaW4gb2JqQXJyKSB7XHJcbiAgICBpZiAoT2JqZWN0LnByb3RvdHlwZS5oYXNPd25Qcm9wZXJ0eS5jYWxsKG9iakFyciwga2V5KSkge1xyXG4gICAgICBvYmpBcnJDb3B5W2tleV0gPSBkZWVwQ29weShvYmpBcnJba2V5XSk7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICAvLyBSZXR1cm4gdGhlIGNvcGllZCBvYmplY3RcclxuICByZXR1cm4gb2JqQXJyQ29weTtcclxufVxyXG5cclxuLyoqXHJcbiAqIEltcGxlbWVudHMgYW4gZXhwb25lbnRpYWwgYmFja29mZiBzdHJhdGVneSBmb3IgcmV0cnlpbmcgYSBmdW5jdGlvbiB1bnRpbFxyXG4gKiBhIGNlcnRhaW4gbnVtYmVyIG9mIGF0dGVtcHRzIGFyZSByZWFjaGVkLlxyXG4gKlxyXG4gKiBAYXN5bmNcclxuICogQGZ1bmN0aW9uIGV4cEJhY2tvZmZcclxuICpcclxuICogQHBhcmFtIHtGdW5jdGlvbn0gZm4gLSBUaGUgZnVuY3Rpb24gdG8gYmUgcmV0cmllZC5cclxuICogQHBhcmFtIHtudW1iZXJ9IFthdHRlbXB0PTBdIC0gVGhlIGN1cnJlbnQgYXR0ZW1wdCBudW1iZXIuIFRoZSBkZWZhdWx0IHZhbHVlXHJcbiAqIGlzIGAwYC5cclxuICogQHBhcmFtIHsuLi51bmtub3dufSBhcmdzIC0gQXJndW1lbnRzIHRvIGJlIHBhc3NlZCB0byB0aGUgZnVuY3Rpb24uXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtQcm9taXNlPHVua25vd24+fSBBIFByb21pc2UgdGhhdCByZXNvbHZlcyB0byB0aGUgcmVzdWx0XHJcbiAqIG9mIHRoZSBmdW5jdGlvbiBpZiBzdWNjZXNzZnVsLlxyXG4gKlxyXG4gKiBAdGhyb3dzIHtFcnJvcn0gVGhyb3dzIGFuIGBFcnJvcmAgaWYgdGhlIG1heGltdW0gbnVtYmVyIG9mIGF0dGVtcHRzXHJcbiAqIGlzIHJlYWNoZWQuXHJcbiAqL1xyXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gZXhwQmFja29mZihmbiwgYXR0ZW1wdCA9IDAsIC4uLmFyZ3MpIHtcclxuICB0cnkge1xyXG4gICAgLy8gVHJ5IHRvIGNhbGwgdGhlIGZ1bmN0aW9uXHJcbiAgICByZXR1cm4gYXdhaXQgZm4oLi4uYXJncyk7XHJcbiAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgIC8vIENhbGN1bGF0ZSBkZWxheSBpbiBtc1xyXG4gICAgY29uc3QgZGVsYXlJbk1zID0gMiAqKiBhdHRlbXB0ICogMTAwMDtcclxuXHJcbiAgICAvLyBJZiB0aGUgYXR0ZW1wdCBleGNlZWRzIHRoZSBtYXhpbXVtIGF0dGVtcHRzIG9mIHJlcGVhdCwgdGhyb3cgYW4gZXJyb3JcclxuICAgIGlmICgrK2F0dGVtcHQgPj0gTUFYX0JBQ0tPRkZfQVRURU1QVFMpIHtcclxuICAgICAgdGhyb3cgZXJyb3I7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gV2FpdCBnaXZlbiBhbW91bnQgb2YgdGltZVxyXG4gICAgYXdhaXQgbmV3IFByb21pc2UoKHJlc3BvbnNlKSA9PiBzZXRUaW1lb3V0KHJlc3BvbnNlLCBkZWxheUluTXMpKTtcclxuXHJcbiAgICAvLy8gVE8gRE86IENvcnJlY3RcclxuICAgIC8vIC8vIEluZm9ybWF0aW9uIGFib3V0IHRoZSByZXNvdXJjZSB0aW1lb3V0XHJcbiAgICAvLyBsb2coXHJcbiAgICAvLyAgIDMsXHJcbiAgICAvLyAgIGBbdXRpbHNdIFdhaXRlZCAke2RlbGF5SW5Nc31tcyB1bnRpbCBuZXh0IGNhbGwgZm9yIHRoZSByZXNvdXJjZSBvZiBJRDogJHthcmdzWzBdfS5gXHJcbiAgICAvLyApO1xyXG5cclxuICAgIC8vIFRyeSBhZ2FpblxyXG4gICAgcmV0dXJuIGV4cEJhY2tvZmYoZm4sIGF0dGVtcHQsIC4uLmFyZ3MpO1xyXG4gIH1cclxufVxyXG5cclxuLyoqXHJcbiAqIEFkanVzdHMgdGhlIGNvbnN0cnVjdG9yIG5hbWUgYnkgdHJhbnNmb3JtaW5nIGFuZCBub3JtYWxpemluZyBpdCBiYXNlZFxyXG4gKiBvbiBjb21tb24gY2hhcnQgdHlwZXMuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBmaXhDb25zdHJcclxuICpcclxuICogQHBhcmFtIHtzdHJpbmd9IGNvbnN0ciAtIFRoZSBvcmlnaW5hbCBjb25zdHJ1Y3RvciBuYW1lIHRvIGJlIGZpeGVkLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7c3RyaW5nfSBUaGUgY29ycmVjdGVkIGNvbnN0cnVjdG9yIG5hbWUsIG9yICdjaGFydCcgaWYgdGhlIGlucHV0XHJcbiAqIGlzIG5vdCByZWNvZ25pemVkLlxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIGZpeENvbnN0cihjb25zdHIpIHtcclxuICB0cnkge1xyXG4gICAgLy8gRml4IHRoZSBjb25zdHJ1Y3RvciBieSBsb3dlcmluZyBjYXNpbmdcclxuICAgIGNvbnN0IGZpeGVkQ29uc3RyID0gYCR7Y29uc3RyLnRvTG93ZXJDYXNlKCkucmVwbGFjZSgnY2hhcnQnLCAnJyl9Q2hhcnRgO1xyXG5cclxuICAgIC8vIEhhbmRsZSB0aGUgY2FzZSB3aGVyZSB0aGUgcmVzdWx0IGlzIGp1c3QgJ0NoYXJ0J1xyXG4gICAgaWYgKGZpeGVkQ29uc3RyID09PSAnQ2hhcnQnKSB7XHJcbiAgICAgIGZpeGVkQ29uc3RyLnRvTG93ZXJDYXNlKCk7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gUmV0dXJuIHRoZSBjb3JyZWN0ZWQgY29uc3RydWN0b3IsIG90aGVyd2lzZSBkZWZhdWx0IHRvICdjaGFydCdcclxuICAgIHJldHVybiBbJ2NoYXJ0JywgJ3N0b2NrQ2hhcnQnLCAnbWFwQ2hhcnQnLCAnZ2FudHRDaGFydCddLmluY2x1ZGVzKFxyXG4gICAgICBmaXhlZENvbnN0clxyXG4gICAgKVxyXG4gICAgICA/IGZpeGVkQ29uc3RyXHJcbiAgICAgIDogJ2NoYXJ0JztcclxuICB9IGNhdGNoIHtcclxuICAgIC8vIERlZmF1bHQgdG8gJ2NoYXJ0JyBpbiBjYXNlIG9mIGFueSBlcnJvclxyXG4gICAgcmV0dXJuICdjaGFydCc7XHJcbiAgfVxyXG59XHJcblxyXG4vKipcclxuICogRml4ZXMgdGhlIG91dGZpbGUgYmFzZWQgb24gcHJvdmlkZWQgdHlwZS5cclxuICpcclxuICogQGZ1bmN0aW9uIGZpeE91dGZpbGVcclxuICpcclxuICogQHBhcmFtIHtzdHJpbmd9IHR5cGUgLSBUaGUgb3JpZ2luYWwgZXhwb3J0IHR5cGUuXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSBvdXRmaWxlIC0gVGhlIGZpbGUgcGF0aCBvciBuYW1lLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7c3RyaW5nfSBUaGUgY29ycmVjdGVkIG91dGZpbGUuXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gZml4T3V0ZmlsZSh0eXBlLCBvdXRmaWxlKSB7XHJcbiAgLy8gR2V0IHRoZSBmaWxlIG5hbWUgZnJvbSB0aGUgYG91dGZpbGVgIG9wdGlvblxyXG4gIGNvbnN0IGZpbGVOYW1lID0gZ2V0QWJzb2x1dGVQYXRoKG91dGZpbGUgfHwgJ2NoYXJ0JylcclxuICAgIC5zcGxpdCgnLicpXHJcbiAgICAuc2hpZnQoKTtcclxuXHJcbiAgLy8gUmV0dXJuIGEgY29ycmVjdCBvdXRmaWxlXHJcbiAgcmV0dXJuIGAke2ZpbGVOYW1lfS4ke3R5cGV9YDtcclxufVxyXG5cclxuLyoqXHJcbiAqIEZpeGVzIHRoZSBleHBvcnQgdHlwZSBiYXNlZCBvbiBNSU1FIHR5cGVzIGFuZCBmaWxlIGV4dGVuc2lvbnMuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBmaXhUeXBlXHJcbiAqXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSB0eXBlIC0gVGhlIG9yaWdpbmFsIGV4cG9ydCB0eXBlLlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gW291dGZpbGU9bnVsbF0gLSBUaGUgZmlsZSBwYXRoIG9yIG5hbWUuIFRoZSBkZWZhdWx0IHZhbHVlXHJcbiAqIGlzIGBudWxsYC5cclxuICpcclxuICogQHJldHVybnMge3N0cmluZ30gVGhlIGNvcnJlY3RlZCBleHBvcnQgdHlwZS5cclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiBmaXhUeXBlKHR5cGUsIG91dGZpbGUgPSBudWxsKSB7XHJcbiAgLy8gTUlNRSB0eXBlc1xyXG4gIGNvbnN0IG1pbWVUeXBlcyA9IHtcclxuICAgICdpbWFnZS9wbmcnOiAncG5nJyxcclxuICAgICdpbWFnZS9qcGVnJzogJ2pwZWcnLFxyXG4gICAgJ2FwcGxpY2F0aW9uL3BkZic6ICdwZGYnLFxyXG4gICAgJ2ltYWdlL3N2Zyt4bWwnOiAnc3ZnJ1xyXG4gIH07XHJcblxyXG4gIC8vIEdldCBmb3JtYXRzXHJcbiAgY29uc3QgZm9ybWF0cyA9IE9iamVjdC52YWx1ZXMobWltZVR5cGVzKTtcclxuXHJcbiAgLy8gQ2hlY2sgaWYgdHlwZSBhbmQgb3V0ZmlsZSdzIGV4dGVuc2lvbnMgYXJlIHRoZSBzYW1lXHJcbiAgaWYgKG91dGZpbGUpIHtcclxuICAgIGNvbnN0IG91dFR5cGUgPSBvdXRmaWxlLnNwbGl0KCcuJykucG9wKCk7XHJcblxyXG4gICAgLy8gU3VwcG9ydCB0aGUgSlBHIHR5cGVcclxuICAgIGlmIChvdXRUeXBlID09PSAnanBnJykge1xyXG4gICAgICB0eXBlID0gJ2pwZWcnO1xyXG4gICAgfSBlbHNlIGlmIChmb3JtYXRzLmluY2x1ZGVzKG91dFR5cGUpICYmIHR5cGUgIT09IG91dFR5cGUpIHtcclxuICAgICAgdHlwZSA9IG91dFR5cGU7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICAvLyBSZXR1cm4gYSBjb3JyZWN0IHR5cGVcclxuICByZXR1cm4gbWltZVR5cGVzW3R5cGVdIHx8IGZvcm1hdHMuZmluZCgodCkgPT4gdCA9PT0gdHlwZSkgfHwgJ3BuZyc7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBDaGVja3MgaWYgdGhlIGdpdmVuIHBhdGggaXMgcmVsYXRpdmUgb3IgYWJzb2x1dGUgYW5kIHJldHVybnMgdGhlIGNvcnJlY3RlZCxcclxuICogYWJzb2x1dGUgcGF0aC5cclxuICpcclxuICogQGZ1bmN0aW9uIGlzQWJzb2x1dGVQYXRoXHJcbiAqXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSBwYXRoIC0gVGhlIHBhdGggdG8gYmUgY2hlY2tlZCBvbi5cclxuICpcclxuICogQHJldHVybnMge3N0cmluZ30gVGhlIGFic29sdXRlIHBhdGguXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gZ2V0QWJzb2x1dGVQYXRoKHBhdGgpIHtcclxuICByZXR1cm4gaXNBYnNvbHV0ZShwYXRoKSA/IHBhdGggOiBqb2luKF9fZGlybmFtZSwgcGF0aCk7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBDb252ZXJ0cyBpbnB1dCBkYXRhIHRvIGEgQmFzZTY0IHN0cmluZyBiYXNlZCBvbiB0aGUgZXhwb3J0IHR5cGUuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBnZXRCYXNlNjRcclxuICpcclxuICogQHBhcmFtIHtzdHJpbmd9IGlucHV0IC0gVGhlIGlucHV0IHRvIGJlIHRyYW5zZm9ybWVkIHRvIEJhc2U2NCBmb3JtYXQuXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSB0eXBlIC0gVGhlIG9yaWdpbmFsIGV4cG9ydCB0eXBlLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7c3RyaW5nfSBUaGUgQmFzZTY0IHN0cmluZyByZXByZXNlbnRhdGlvbiBvZiB0aGUgaW5wdXQuXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gZ2V0QmFzZTY0KGlucHV0LCB0eXBlKSB7XHJcbiAgLy8gRm9yIHBkZiBhbmQgc3ZnIHR5cGVzIHRoZSBpbnB1dCBtdXN0IGJlIHRyYW5zZm9ybWVkIHRvIEJhc2U2NCBmcm9tIGEgYnVmZmVyXHJcbiAgaWYgKHR5cGUgPT09ICdwZGYnIHx8IHR5cGUgPT0gJ3N2ZycpIHtcclxuICAgIHJldHVybiBCdWZmZXIuZnJvbShpbnB1dCwgJ3V0ZjgnKS50b1N0cmluZygnYmFzZTY0Jyk7XHJcbiAgfVxyXG5cclxuICAvLyBGb3IgcG5nIGFuZCBqcGVnIGlucHV0IGlzIGFscmVhZHkgYSBCYXNlNjQgc3RyaW5nXHJcbiAgcmV0dXJuIGlucHV0O1xyXG59XHJcblxyXG4vKipcclxuICogUmV0dXJucyBzdHJpbmdpZmllZCBkYXRlIHdpdGhvdXQgdGhlIEdNVCB0ZXh0IGluZm9ybWF0aW9uLlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gZ2V0TmV3RGF0ZVxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIGdldE5ld0RhdGUoKSB7XHJcbiAgLy8gR2V0IHJpZCBvZiB0aGUgR01UIHRleHQgaW5mb3JtYXRpb25cclxuICByZXR1cm4gbmV3IERhdGUoKS50b1N0cmluZygpLnNwbGl0KCcoJylbMF0udHJpbSgpO1xyXG59XHJcblxyXG4vKipcclxuICogUmV0dXJucyB0aGUgc3RvcmVkIHRpbWUgdmFsdWUgaW4gbWlsbGlzZWNvbmRzLlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gZ2V0TmV3RGF0ZVRpbWVcclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiBnZXROZXdEYXRlVGltZSgpIHtcclxuICByZXR1cm4gbmV3IERhdGUoKS5nZXRUaW1lKCk7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBDaGVja3MgaWYgdGhlIGdpdmVuIGl0ZW0gaXMgYW4gb2JqZWN0LlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gaXNPYmplY3RcclxuICpcclxuICogQHBhcmFtIHt1bmtub3dufSBpdGVtIC0gVGhlIGl0ZW0gdG8gYmUgY2hlY2tlZC5cclxuICpcclxuICogQHJldHVybnMge2Jvb2xlYW59IFRydWUgaWYgdGhlIGl0ZW0gaXMgYW4gb2JqZWN0LCBmYWxzZSBvdGhlcndpc2UuXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gaXNPYmplY3QoaXRlbSkge1xyXG4gIHJldHVybiBPYmplY3QucHJvdG90eXBlLnRvU3RyaW5nLmNhbGwoaXRlbSkgPT09ICdbb2JqZWN0IE9iamVjdF0nO1xyXG59XHJcblxyXG4vKipcclxuICogQ2hlY2tzIGlmIHRoZSBnaXZlbiBvYmplY3QgaXMgZW1wdHkuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBpc09iamVjdEVtcHR5XHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBpdGVtIC0gVGhlIG9iamVjdCB0byBiZSBjaGVja2VkLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7Ym9vbGVhbn0gVHJ1ZSBpZiB0aGUgb2JqZWN0IGlzIGVtcHR5LCBmYWxzZSBvdGhlcndpc2UuXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gaXNPYmplY3RFbXB0eShpdGVtKSB7XHJcbiAgcmV0dXJuIChcclxuICAgIHR5cGVvZiBpdGVtID09PSAnb2JqZWN0JyAmJlxyXG4gICAgIUFycmF5LmlzQXJyYXkoaXRlbSkgJiZcclxuICAgIGl0ZW0gIT09IG51bGwgJiZcclxuICAgIE9iamVjdC5rZXlzKGl0ZW0pLmxlbmd0aCA9PT0gMFxyXG4gICk7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBDaGVja3MgaWYgYSBwcml2YXRlIElQIHJhbmdlIFVSTCBpcyBmb3VuZCBpbiB0aGUgZ2l2ZW4gc3RyaW5nLlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gaXNQcml2YXRlUmFuZ2VVcmxGb3VuZFxyXG4gKlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gaXRlbSAtIFRoZSBzdHJpbmcgdG8gYmUgY2hlY2tlZCBmb3IgYSBwcml2YXRlIElQIHJhbmdlIFVSTC5cclxuICpcclxuICogQHJldHVybnMge2Jvb2xlYW59IFRydWUgaWYgYSBwcml2YXRlIElQIHJhbmdlIFVSTCBpcyBmb3VuZCwgZmFsc2Ugb3RoZXJ3aXNlLlxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIGlzUHJpdmF0ZVJhbmdlVXJsRm91bmQoaXRlbSkge1xyXG4gIGNvbnN0IHJlZ2V4UGF0dGVybnMgPSBbXHJcbiAgICAveGxpbms6aHJlZj1cIig/Omh0dHA6XFwvXFwvfGh0dHBzOlxcL1xcLyk/bG9jYWxob3N0XFxiLyxcclxuICAgIC94bGluazpocmVmPVwiKD86aHR0cDpcXC9cXC98aHR0cHM6XFwvXFwvKT8xMFxcLlxcZHsxLDN9XFwuXFxkezEsM31cXC5cXGR7MSwzfVxcYi8sXHJcbiAgICAveGxpbms6aHJlZj1cIig/Omh0dHA6XFwvXFwvfGh0dHBzOlxcL1xcLyk/MTI3XFwuXFxkezEsM31cXC5cXGR7MSwzfVxcLlxcZHsxLDN9XFxiLyxcclxuICAgIC94bGluazpocmVmPVwiKD86aHR0cDpcXC9cXC98aHR0cHM6XFwvXFwvKT8xNzJcXC4oMVs2LTldfDJbMC05XXwzWzAtMV0pXFwuXFxkezEsM31cXC5cXGR7MSwzfVxcYi8sXHJcbiAgICAveGxpbms6aHJlZj1cIig/Omh0dHA6XFwvXFwvfGh0dHBzOlxcL1xcLyk/MTkyXFwuMTY4XFwuXFxkezEsM31cXC5cXGR7MSwzfVxcYi9cclxuICBdO1xyXG5cclxuICByZXR1cm4gcmVnZXhQYXR0ZXJucy5zb21lKChwYXR0ZXJuKSA9PiBwYXR0ZXJuLnRlc3QoaXRlbSkpO1xyXG59XHJcblxyXG4vKipcclxuICogVXRpbGl0eSB0byBtZWFzdXJlIGVsYXBzZWQgdGltZSB1c2luZyB0aGUgTm9kZS5qcyBgcHJvY2Vzcy5ocnRpbWUoKWAgbWV0aG9kLlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gbWVhc3VyZVRpbWVcclxuICpcclxuICogQHJldHVybnMge0Z1bmN0aW9ufSBBIGZ1bmN0aW9uIHRvIGNhbGN1bGF0ZSB0aGUgZWxhcHNlZCB0aW1lIGluIG1pbGxpc2Vjb25kcy5cclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiBtZWFzdXJlVGltZSgpIHtcclxuICBjb25zdCBzdGFydCA9IHByb2Nlc3MuaHJ0aW1lLmJpZ2ludCgpO1xyXG4gIHJldHVybiAoKSA9PiBOdW1iZXIocHJvY2Vzcy5ocnRpbWUuYmlnaW50KCkgLSBzdGFydCkgLyAxMDAwMDAwO1xyXG59XHJcblxyXG4vKipcclxuICogUm91bmRzIGEgbnVtYmVyIHRvIHRoZSBzcGVjaWZpZWQgcHJlY2lzaW9uLlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gcm91bmROdW1iZXJcclxuICpcclxuICogQHBhcmFtIHtudW1iZXJ9IHZhbHVlIC0gVGhlIG51bWJlciB0byBiZSByb3VuZGVkLlxyXG4gKiBAcGFyYW0ge251bWJlcn0gcHJlY2lzaW9uIC0gVGhlIG51bWJlciBvZiBkZWNpbWFsIHBsYWNlcyB0byByb3VuZCB0by5cclxuICpcclxuICogQHJldHVybnMge251bWJlcn0gVGhlIHJvdW5kZWQgbnVtYmVyLlxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIHJvdW5kTnVtYmVyKHZhbHVlLCBwcmVjaXNpb24gPSAxKSB7XHJcbiAgY29uc3QgbXVsdGlwbGllciA9IE1hdGgucG93KDEwLCBwcmVjaXNpb24gfHwgMCk7XHJcbiAgcmV0dXJuIE1hdGgucm91bmQoK3ZhbHVlICogbXVsdGlwbGllcikgLyBtdWx0aXBsaWVyO1xyXG59XHJcblxyXG4vKipcclxuICogQ29udmVydHMgYSB2YWx1ZSB0byBhIGJvb2xlYW4uXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiB0b0Jvb2xlYW5cclxuICpcclxuICogQHBhcmFtIHt1bmtub3dufSBpdGVtIC0gVGhlIHZhbHVlIHRvIGJlIGNvbnZlcnRlZCB0byBhIGJvb2xlYW4uXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtib29sZWFufSBUaGUgYm9vbGVhbiByZXByZXNlbnRhdGlvbiBvZiB0aGUgaW5wdXQgdmFsdWUuXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gdG9Cb29sZWFuKGl0ZW0pIHtcclxuICByZXR1cm4gWydmYWxzZScsICd1bmRlZmluZWQnLCAnbnVsbCcsICdOYU4nLCAnMCcsICcnXS5pbmNsdWRlcyhpdGVtKVxyXG4gICAgPyBmYWxzZVxyXG4gICAgOiAhIWl0ZW07XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBXcmFwcyBjdXN0b20gY29kZSB0byBleGVjdXRlIGl0IHNhZmVseS5cclxuICpcclxuICogQGZ1bmN0aW9uIHdyYXBBcm91bmRcclxuICpcclxuICogQHBhcmFtIHtzdHJpbmd9IGN1c3RvbUNvZGUgLSBUaGUgY3VzdG9tIGNvZGUgdG8gYmUgd3JhcHBlZC5cclxuICogQHBhcmFtIHtib29sZWFufSBhbGxvd0ZpbGVSZXNvdXJjZXMgLSBGbGFnIHRvIGFsbG93IGxvYWRpbmcgY29kZSBmcm9tIGEgZmlsZS5cclxuICogQHBhcmFtIHtib29sZWFufSBbaXNDYWxsYmFjaz1mYWxzZV0gLSBGbGFnIHRoYXQgaW5kaWNhdGVzIHRoZSByZXR1cm5lZCBjb2RlXHJcbiAqIG11c3QgYmUgaW4gYSBjYWxsYmFjayBmb3JtYXQuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHsoc3RyaW5nfG51bGwpfSBUaGUgd3JhcHBlZCBjdXN0b20gY29kZSBvciBudWxsIGlmIHdyYXBwaW5nIGZhaWxzLlxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIHdyYXBBcm91bmQoY3VzdG9tQ29kZSwgYWxsb3dGaWxlUmVzb3VyY2VzLCBpc0NhbGxiYWNrID0gZmFsc2UpIHtcclxuICBpZiAoY3VzdG9tQ29kZSAmJiB0eXBlb2YgY3VzdG9tQ29kZSA9PT0gJ3N0cmluZycpIHtcclxuICAgIGN1c3RvbUNvZGUgPSBjdXN0b21Db2RlLnRyaW0oKTtcclxuXHJcbiAgICBpZiAoY3VzdG9tQ29kZS5lbmRzV2l0aCgnLmpzJykpIHtcclxuICAgICAgLy8gTG9hZCBhIGZpbGUgaWYgdGhlIGZpbGUgcmVzb3VyY2VzIGFyZSBhbGxvd2VkXHJcbiAgICAgIHJldHVybiBhbGxvd0ZpbGVSZXNvdXJjZXNcclxuICAgICAgICA/IHdyYXBBcm91bmQoXHJcbiAgICAgICAgICAgIHJlYWRGaWxlU3luYyhnZXRBYnNvbHV0ZVBhdGgoY3VzdG9tQ29kZSksICd1dGY4JyksXHJcbiAgICAgICAgICAgIGFsbG93RmlsZVJlc291cmNlcyxcclxuICAgICAgICAgICAgaXNDYWxsYmFja1xyXG4gICAgICAgICAgKVxyXG4gICAgICAgIDogbnVsbDtcclxuICAgIH0gZWxzZSBpZiAoXHJcbiAgICAgICFpc0NhbGxiYWNrICYmXHJcbiAgICAgIChjdXN0b21Db2RlLnN0YXJ0c1dpdGgoJ2Z1bmN0aW9uKCknKSB8fFxyXG4gICAgICAgIGN1c3RvbUNvZGUuc3RhcnRzV2l0aCgnZnVuY3Rpb24gKCknKSB8fFxyXG4gICAgICAgIGN1c3RvbUNvZGUuc3RhcnRzV2l0aCgnKCk9PicpIHx8XHJcbiAgICAgICAgY3VzdG9tQ29kZS5zdGFydHNXaXRoKCcoKSA9PicpKVxyXG4gICAgKSB7XHJcbiAgICAgIC8vIFRyZWF0IGEgZnVuY3Rpb24gYXMgYSBzZWxmLWludm9raW5nIGV4cHJlc3Npb25cclxuICAgICAgcmV0dXJuIGAoJHtjdXN0b21Db2RlfSkoKWA7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gT3IgcmV0dXJuIGFzIGEgc3RyaW5naWZpZWQgY29kZVxyXG4gICAgcmV0dXJuIGN1c3RvbUNvZGUucmVwbGFjZSgvOyQvLCAnJyk7XHJcbiAgfVxyXG59XHJcblxyXG5leHBvcnQgZGVmYXVsdCB7XHJcbiAgX19kaXJuYW1lLFxyXG4gIGNsZWFyVGV4dCxcclxuICBkZWVwQ29weSxcclxuICBleHBCYWNrb2ZmLFxyXG4gIGZpeENvbnN0cixcclxuICBmaXhPdXRmaWxlLFxyXG4gIGZpeFR5cGUsXHJcbiAgZ2V0QWJzb2x1dGVQYXRoLFxyXG4gIGdldEJhc2U2NCxcclxuICBnZXROZXdEYXRlLFxyXG4gIGdldE5ld0RhdGVUaW1lLFxyXG4gIGlzT2JqZWN0LFxyXG4gIGlzT2JqZWN0RW1wdHksXHJcbiAgaXNQcml2YXRlUmFuZ2VVcmxGb3VuZCxcclxuICBtZWFzdXJlVGltZSxcclxuICByb3VuZE51bWJlcixcclxuICB0b0Jvb2xlYW4sXHJcbiAgd3JhcEFyb3VuZFxyXG59O1xyXG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxyXG5cclxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXHJcblxyXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNSwgSGlnaHNvZnRcclxuXHJcbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cclxuXHJcbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxyXG5cclxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxyXG5cclxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cclxuXHJcbi8qKlxyXG4gKiBAb3ZlcnZpZXcgQSBtb2R1bGUgZm9yIG1hbmFnaW5nIGxvZ2dpbmcgZnVuY3Rpb25hbGl0eSB3aXRoIGN1c3RvbWl6YWJsZVxyXG4gKiBsb2cgbGV2ZWxzLCBjb25zb2xlIGFuZCBmaWxlIGxvZ2dpbmcgb3B0aW9ucywgYW5kIGVycm9yIGhhbmRsaW5nIHN1cHBvcnQuXHJcbiAqIFRoZSBtb2R1bGUgYWxzbyBlbnN1cmVzIHRoYXQgZmlsZS1iYXNlZCBsb2dzIGFyZSBzdG9yZWQgaW4gYSBzdHJ1Y3R1cmVkXHJcbiAqIGRpcmVjdG9yeSwgY3JlYXRpbmcgdGhlIG5lY2Vzc2FyeSBwYXRocyBhdXRvbWF0aWNhbGx5IGlmIHRoZXkgZG8gbm90IGV4aXN0LlxyXG4gKi9cclxuXHJcbmltcG9ydCB7IGFwcGVuZEZpbGUsIGV4aXN0c1N5bmMsIG1rZGlyU3luYyB9IGZyb20gJ2ZzJztcclxuaW1wb3J0IHsgam9pbiB9IGZyb20gJ3BhdGgnO1xyXG5cclxuaW1wb3J0IHsgZ2V0QWJzb2x1dGVQYXRoLCBnZXROZXdEYXRlIH0gZnJvbSAnLi91dGlscy5qcyc7XHJcblxyXG4vLyBUaGUgYXZhaWxhYmxlIGNvbG9yc1xyXG5jb25zdCBjb2xvcnMgPSBbJ3JlZCcsICd5ZWxsb3cnLCAnYmx1ZScsICdncmF5JywgJ2dyZWVuJ107XHJcblxyXG4vLyBUaGUgZGVmYXVsdCBsb2dnaW5nIGNvbmZpZ1xyXG5jb25zdCBsb2dnaW5nID0ge1xyXG4gIC8vIEZsYWdzIGZvciBsb2dnaW5nIHN0YXR1c1xyXG4gIHRvQ29uc29sZTogdHJ1ZSxcclxuICB0b0ZpbGU6IGZhbHNlLFxyXG4gIHBhdGhDcmVhdGVkOiBmYWxzZSxcclxuICAvLyBGdWxsIHBhdGggdG8gdGhlIGxvZyBmaWxlXHJcbiAgcGF0aFRvTG9nOiAnJyxcclxuICAvLyBMb2cgbGV2ZWxzXHJcbiAgbGV2ZWxzRGVzYzogW1xyXG4gICAge1xyXG4gICAgICB0aXRsZTogJ2Vycm9yJyxcclxuICAgICAgY29sb3I6IGNvbG9yc1swXVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdGl0bGU6ICd3YXJuaW5nJyxcclxuICAgICAgY29sb3I6IGNvbG9yc1sxXVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdGl0bGU6ICdub3RpY2UnLFxyXG4gICAgICBjb2xvcjogY29sb3JzWzJdXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0aXRsZTogJ3ZlcmJvc2UnLFxyXG4gICAgICBjb2xvcjogY29sb3JzWzNdXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0aXRsZTogJ2JlbmNobWFyaycsXHJcbiAgICAgIGNvbG9yOiBjb2xvcnNbNF1cclxuICAgIH1cclxuICBdXHJcbn07XHJcblxyXG4vKipcclxuICogTG9ncyBhIG1lc3NhZ2Ugd2l0aCBhIHNwZWNpZmllZCBsb2cgbGV2ZWwuIEFjY2VwdHMgYSB2YXJpYWJsZSBudW1iZXJcclxuICogb2YgYXJndW1lbnRzLiBUaGUgYXJndW1lbnRzIGFmdGVyIHRoZSBgbGV2ZWxgIGFyZSBwYXNzZWQgdG8gYGNvbnNvbGUubG9nYFxyXG4gKiBhbmQvb3IgdXNlZCB0byBjb25zdHJ1Y3QgYW5kIGFwcGVuZCBtZXNzYWdlcyB0byBhIGxvZyBmaWxlLlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gbG9nXHJcbiAqXHJcbiAqIEBwYXJhbSB7Li4udW5rbm93bn0gYXJncyAtIEFuIGFycmF5IG9mIGFyZ3VtZW50cyB3aGVyZSB0aGUgZmlyc3QgaXMgdGhlIGxvZ1xyXG4gKiBsZXZlbCBhbmQgdGhlIHJlbWFpbmluZyBhcmUgc3RyaW5ncyB1c2VkIHRvIGJ1aWxkIHRoZSBsb2cgbWVzc2FnZS5cclxuICpcclxuICogQHJldHVybnMge3ZvaWR9IEV4aXRzIHRoZSBmdW5jdGlvbiBleGVjdXRpb24gaWYgYXR0ZW1wdGluZyB0byBsb2cgYXQgYSBsZXZlbFxyXG4gKiBoaWdoZXIgdGhhbiBhbGxvd2VkLlxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIGxvZyguLi5hcmdzKSB7XHJcbiAgY29uc3QgW25ld0xldmVsLCAuLi50ZXh0c10gPSBhcmdzO1xyXG5cclxuICAvLyBDdXJyZW50IGxvZ2dpbmcgb3B0aW9uc1xyXG4gIGNvbnN0IHsgbGV2ZWxzRGVzYywgbGV2ZWwgfSA9IGxvZ2dpbmc7XHJcblxyXG4gIC8vIENoZWNrIGlmIHRoZSBsb2cgbGV2ZWwgaXMgd2l0aGluIGEgY29ycmVjdCByYW5nZSBvciBpcyBpdCBhIGJlbmNobWFyayBsb2dcclxuICBpZiAoXHJcbiAgICBuZXdMZXZlbCAhPT0gNSAmJlxyXG4gICAgKG5ld0xldmVsID09PSAwIHx8IG5ld0xldmVsID4gbGV2ZWwgfHwgbGV2ZWwgPiBsZXZlbHNEZXNjLmxlbmd0aClcclxuICApIHtcclxuICAgIHJldHVybjtcclxuICB9XHJcblxyXG4gIC8vIENyZWF0ZSBhIG1lc3NhZ2UncyBwcmVmaXhcclxuICBjb25zdCBwcmVmaXggPSBgJHtnZXROZXdEYXRlKCl9IFske2xldmVsc0Rlc2NbbmV3TGV2ZWwgLSAxXS50aXRsZX1dIC1gO1xyXG5cclxuICAvLyBMb2cgdG8gZmlsZVxyXG4gIGlmIChsb2dnaW5nLnRvRmlsZSkge1xyXG4gICAgX2xvZ1RvRmlsZSh0ZXh0cywgcHJlZml4KTtcclxuICB9XHJcblxyXG4gIC8vIExvZyB0byBjb25zb2xlXHJcbiAgaWYgKGxvZ2dpbmcudG9Db25zb2xlKSB7XHJcbiAgICBjb25zb2xlLmxvZy5hcHBseShcclxuICAgICAgdW5kZWZpbmVkLFxyXG4gICAgICBbcHJlZml4LnRvU3RyaW5nKClbbG9nZ2luZy5sZXZlbHNEZXNjW25ld0xldmVsIC0gMV0uY29sb3JdXS5jb25jYXQodGV4dHMpXHJcbiAgICApO1xyXG4gIH1cclxufVxyXG5cclxuLyoqXHJcbiAqIExvZ3MgYW4gZXJyb3IgbWVzc2FnZSBhbG9uZyB3aXRoIGl0cyBzdGFjayB0cmFjZS4gT3B0aW9uYWxseSwgYSBjdXN0b20gbWVzc2FnZVxyXG4gKiBjYW4gYmUgcHJvdmlkZWQuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBsb2dXaXRoU3RhY2tcclxuICpcclxuICogQHBhcmFtIHtudW1iZXJ9IG5ld0xldmVsIC0gVGhlIGxvZyBsZXZlbC5cclxuICogQHBhcmFtIHtFcnJvcn0gZXJyb3IgLSBUaGUgZXJyb3Igb2JqZWN0IGNvbnRhaW5pbmcgdGhlIHN0YWNrIHRyYWNlLlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gY3VzdG9tTWVzc2FnZSAtIEFuIG9wdGlvbmFsIGN1c3RvbSBtZXNzYWdlIHRvIGJlIGluY2x1ZGVkXHJcbiAqIGluIHRoZSBsb2cgYWxvbmdzaWRlIHRoZSBlcnJvci5cclxuICpcclxuICogQHJldHVybnMge3ZvaWR9IEV4aXRzIHRoZSBmdW5jdGlvbiBleGVjdXRpb24gaWYgYXR0ZW1wdGluZyB0byBsb2cgYXQgYSBsZXZlbFxyXG4gKiBoaWdoZXIgdGhhbiBhbGxvd2VkLlxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIGxvZ1dpdGhTdGFjayhuZXdMZXZlbCwgZXJyb3IsIGN1c3RvbU1lc3NhZ2UpIHtcclxuICAvLyBHZXQgdGhlIG1haW4gbWVzc2FnZVxyXG4gIGNvbnN0IG1haW5NZXNzYWdlID0gY3VzdG9tTWVzc2FnZSB8fCAoZXJyb3IgJiYgZXJyb3IubWVzc2FnZSkgfHwgJyc7XHJcblxyXG4gIC8vIEN1cnJlbnQgbG9nZ2luZyBvcHRpb25zXHJcbiAgY29uc3QgeyBsZXZlbCwgbGV2ZWxzRGVzYyB9ID0gbG9nZ2luZztcclxuXHJcbiAgLy8gQ2hlY2sgaWYgdGhlIGxvZyBsZXZlbCBpcyB3aXRoaW4gYSBjb3JyZWN0IHJhbmdlXHJcbiAgaWYgKG5ld0xldmVsID09PSAwIHx8IG5ld0xldmVsID4gbGV2ZWwgfHwgbGV2ZWwgPiBsZXZlbHNEZXNjLmxlbmd0aCkge1xyXG4gICAgcmV0dXJuO1xyXG4gIH1cclxuXHJcbiAgLy8gQ3JlYXRlIGEgbWVzc2FnZSdzIHByZWZpeFxyXG4gIGNvbnN0IHByZWZpeCA9IGAke2dldE5ld0RhdGUoKX0gWyR7bGV2ZWxzRGVzY1tuZXdMZXZlbCAtIDFdLnRpdGxlfV0gLWA7XHJcblxyXG4gIC8vIEFkZCB0aGUgd2hvbGUgc3RhY2sgbWVzc2FnZVxyXG4gIGNvbnN0IHN0YWNrTWVzc2FnZSA9IGVycm9yICYmIGVycm9yLnN0YWNrO1xyXG5cclxuICAvLyBDb21iaW5lIGN1c3RvbSBtZXNzYWdlIG9yIGVycm9yIG1lc3NhZ2Ugd2l0aCBlcnJvciBzdGFjayBtZXNzYWdlLCBpZiBleGlzdHNcclxuICBjb25zdCB0ZXh0cyA9IFttYWluTWVzc2FnZV07XHJcbiAgaWYgKHN0YWNrTWVzc2FnZSkge1xyXG4gICAgdGV4dHMucHVzaCgnXFxuJywgc3RhY2tNZXNzYWdlKTtcclxuICB9XHJcblxyXG4gIC8vIExvZyB0byBmaWxlXHJcbiAgaWYgKGxvZ2dpbmcudG9GaWxlKSB7XHJcbiAgICBfbG9nVG9GaWxlKHRleHRzLCBwcmVmaXgpO1xyXG4gIH1cclxuXHJcbiAgLy8gTG9nIHRvIGNvbnNvbGVcclxuICBpZiAobG9nZ2luZy50b0NvbnNvbGUpIHtcclxuICAgIGNvbnNvbGUubG9nLmFwcGx5KFxyXG4gICAgICB1bmRlZmluZWQsXHJcbiAgICAgIFtwcmVmaXgudG9TdHJpbmcoKVtsb2dnaW5nLmxldmVsc0Rlc2NbbmV3TGV2ZWwgLSAxXS5jb2xvcl1dLmNvbmNhdChbXHJcbiAgICAgICAgdGV4dHMuc2hpZnQoKVtjb2xvcnNbbmV3TGV2ZWwgLSAxXV0sXHJcbiAgICAgICAgLi4udGV4dHNcclxuICAgICAgXSlcclxuICAgICk7XHJcbiAgfVxyXG59XHJcblxyXG4vKipcclxuICogTG9ncyBhbiBlcnJvciBtZXNzYWdlIHJlbGF0ZWQgdG8gWm9kIHZhbGlkYXRpb24gaXNzdWVzLiBPcHRpb25hbGx5LCBhIGN1c3RvbVxyXG4gKiBtZXNzYWdlIGNhbiBiZSBwcm92aWRlZC5cclxuICpcclxuICogQGZ1bmN0aW9uIGxvZ1pvZElzc3Vlc1xyXG4gKlxyXG4gKiBAcGFyYW0ge251bWJlcn0gbmV3TGV2ZWwgLSBUaGUgbG9nIGxldmVsLlxyXG4gKiBAcGFyYW0ge0Vycm9yW119IGlzc3VlcyAtIEFuIGFycmF5IG9mIFpvZCB2YWxpZGF0aW9uIGlzc3Vlcy5cclxuICogQHBhcmFtIHtzdHJpbmd9IGN1c3RvbU1lc3NhZ2UgLSBBbiBvcHRpb25hbCBjdXN0b20gbWVzc2FnZSB0byBiZSBpbmNsdWRlZFxyXG4gKiBpbiB0aGUgbG9nIGFsb25nc2lkZSB0aGUgZXJyb3IuXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gbG9nWm9kSXNzdWVzKG5ld0xldmVsLCBpc3N1ZXMsIGN1c3RvbU1lc3NhZ2UpIHtcclxuICBsb2dXaXRoU3RhY2soXHJcbiAgICBuZXdMZXZlbCxcclxuICAgIG51bGwsXHJcbiAgICBbXHJcbiAgICAgIGAke2N1c3RvbU1lc3NhZ2UgfHwgJ1t2YWxpZGF0aW9uXSBWYWxpZGF0aW9uIGVycm9yJ30gLSB0aGUgZm9sbG93aW5nIFpvZCBpc3N1ZXMgb2NjdXJlZDpgLFxyXG4gICAgICAuLi4oaXNzdWVzIHx8IFtdKS5tYXAoKGlzc3VlKSA9PiBgLSAke2lzc3VlLm1lc3NhZ2V9YClcclxuICAgIF0uam9pbignXFxuJylcclxuICApO1xyXG59XHJcblxyXG4vKipcclxuICogSW5pdGlhbGl6ZXMgbG9nZ2luZyB3aXRoIHRoZSBzcGVjaWZpZWQgbG9nZ2luZyBjb25maWd1cmF0aW9uLlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gaW5pdExvZ2dpbmdcclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IGxvZ2dpbmdPcHRpb25zIC0gVGhlIGNvbmZpZ3VyYXRpb24gb2JqZWN0IGNvbnRhaW5pbmdcclxuICogYGxvZ2dpbmdgIG9wdGlvbnMuXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gaW5pdExvZ2dpbmcobG9nZ2luZ09wdGlvbnMpIHtcclxuICAvLyBHZXQgb3B0aW9ucyBmcm9tIHRoZSBgbG9nZ2luZ09wdGlvbnNgIG9iamVjdFxyXG4gIGNvbnN0IHsgbGV2ZWwsIGRlc3QsIGZpbGUsIHRvQ29uc29sZSwgdG9GaWxlIH0gPSBsb2dnaW5nT3B0aW9ucztcclxuXHJcbiAgLy8gUmVzZXQgZmxhZ3MgdG8gdGhlIGRlZmF1bHQgdmFsdWVzXHJcbiAgbG9nZ2luZy5wYXRoQ3JlYXRlZCA9IGZhbHNlO1xyXG4gIGxvZ2dpbmcucGF0aFRvTG9nID0gJyc7XHJcblxyXG4gIC8vIFNldCB0aGUgbG9nZ2luZyBsZXZlbFxyXG4gIHNldExvZ0xldmVsKGxldmVsKTtcclxuXHJcbiAgLy8gU2V0IHRoZSBjb25zb2xlIGxvZ2dpbmdcclxuICBlbmFibGVDb25zb2xlTG9nZ2luZyh0b0NvbnNvbGUpO1xyXG5cclxuICAvLyBTZXQgdGhlIGZpbGUgbG9nZ2luZ1xyXG4gIGVuYWJsZUZpbGVMb2dnaW5nKGRlc3QsIGZpbGUsIHRvRmlsZSk7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBTZXRzIHRoZSBsb2cgbGV2ZWwgdG8gdGhlIHNwZWNpZmllZCB2YWx1ZS4gTG9nIGxldmVscyBhcmUgKGAwYCA9IG5vIGxvZ2dpbmcsXHJcbiAqIGAxYCA9IGVycm9yLCBgMmAgPSB3YXJuaW5nLCBgM2AgPSBub3RpY2UsIGA0YCA9IHZlcmJvc2UsIG9yIGA1YCA9IGJlbmNobWFyaykuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBzZXRMb2dMZXZlbFxyXG4gKlxyXG4gKiBAcGFyYW0ge251bWJlcn0gbGV2ZWwgLSBUaGUgbG9nIGxldmVsIHRvIGJlIHNldC5cclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiBzZXRMb2dMZXZlbChsZXZlbCkge1xyXG4gIGlmIChcclxuICAgIE51bWJlci5pc0ludGVnZXIobGV2ZWwpICYmXHJcbiAgICBsZXZlbCA+PSAwICYmXHJcbiAgICBsZXZlbCA8PSBsb2dnaW5nLmxldmVsc0Rlc2MubGVuZ3RoXHJcbiAgKSB7XHJcbiAgICAvLyBVcGRhdGUgdGhlIG1vZHVsZSBsb2dnaW5nJ3MgYGxldmVsYCBvcHRpb25cclxuICAgIGxvZ2dpbmcubGV2ZWwgPSBsZXZlbDtcclxuICB9XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBFbmFibGVzIGNvbnNvbGUgbG9nZ2luZy5cclxuICpcclxuICogQGZ1bmN0aW9uIGVuYWJsZUNvbnNvbGVMb2dnaW5nXHJcbiAqXHJcbiAqIEBwYXJhbSB7Ym9vbGVhbn0gdG9Db25zb2xlIC0gVGhlIGZsYWcgZm9yIHNldHRpbmcgdGhlIGxvZ2dpbmcgdG8gdGhlIGNvbnNvbGUuXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gZW5hYmxlQ29uc29sZUxvZ2dpbmcodG9Db25zb2xlKSB7XHJcbiAgLy8gVXBkYXRlIHRoZSBtb2R1bGUgbG9nZ2luZydzIGB0b0NvbnNvbGVgIG9wdGlvblxyXG4gIGxvZ2dpbmcudG9Db25zb2xlID0gISF0b0NvbnNvbGU7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBFbmFibGVzIGZpbGUgbG9nZ2luZyB3aXRoIHRoZSBzcGVjaWZpZWQgZGVzdGluYXRpb24gYW5kIGxvZyBmaWxlIG5hbWUuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBlbmFibGVGaWxlTG9nZ2luZ1xyXG4gKlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gZGVzdCAtIFRoZSBkZXN0aW5hdGlvbiBwYXRoIHdoZXJlIHRoZSBsb2cgZmlsZSBzaG91bGRcclxuICogYmUgc2F2ZWQuXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSBmaWxlIC0gVGhlIG5hbWUgb2YgdGhlIGxvZyBmaWxlLlxyXG4gKiBAcGFyYW0ge2Jvb2xlYW59IHRvRmlsZSAtIEEgZmxhZyBpbmRpY2F0aW5nIHdoZXRoZXIgbG9nZ2luZyBzaG91bGRcclxuICogYmUgZGlyZWN0ZWQgdG8gYSBmaWxlLlxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIGVuYWJsZUZpbGVMb2dnaW5nKGRlc3QsIGZpbGUsIHRvRmlsZSkge1xyXG4gIC8vIFVwZGF0ZSB0aGUgbW9kdWxlIGxvZ2dpbmcncyBgdG9GaWxlYCBvcHRpb25cclxuICBsb2dnaW5nLnRvRmlsZSA9ICEhdG9GaWxlO1xyXG5cclxuICAvLyBTZXQgdGhlIGBkZXN0YCBhbmQgYGZpbGVgIG9wdGlvbnMgb25seSBpZiB0aGUgZmlsZSBsb2dnaW5nIGlzIGVuYWJsZWRcclxuICBpZiAobG9nZ2luZy50b0ZpbGUpIHtcclxuICAgIGxvZ2dpbmcuZGVzdCA9IGRlc3QgfHwgJyc7XHJcbiAgICBsb2dnaW5nLmZpbGUgPSBmaWxlIHx8ICcnO1xyXG4gIH1cclxufVxyXG5cclxuLyoqXHJcbiAqIExvZ3MgdGhlIHByb3ZpZGVkIHRleHRzIHRvIGEgZmlsZSwgaWYgZmlsZSBsb2dnaW5nIGlzIGVuYWJsZWQuIEl0IGNyZWF0ZXNcclxuICogdGhlIG5lY2Vzc2FyeSBkaXJlY3Rvcnkgc3RydWN0dXJlIGlmIG5vdCBhbHJlYWR5IGNyZWF0ZWQgYW5kIGFwcGVuZHNcclxuICogdGhlIGNvbnRlbnQsIGluY2x1ZGluZyBhbiBvcHRpb25hbCBwcmVmaXgsIHRvIHRoZSBzcGVjaWZpZWQgbG9nIGZpbGUuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBfbG9nVG9GaWxlXHJcbiAqXHJcbiAqIEBwYXJhbSB7QXJyYXkuPHN0cmluZz59IHRleHRzIC0gQW4gYXJyYXkgb2YgdGV4dHMgdG8gYmUgbG9nZ2VkLlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gcHJlZml4IC0gQW4gb3B0aW9uYWwgcHJlZml4IHRvIGJlIGFkZGVkIHRvIGVhY2ggbG9nIGVudHJ5LlxyXG4gKi9cclxuZnVuY3Rpb24gX2xvZ1RvRmlsZSh0ZXh0cywgcHJlZml4KSB7XHJcbiAgaWYgKCFsb2dnaW5nLnBhdGhDcmVhdGVkKSB7XHJcbiAgICAvLyBDcmVhdGUgaWYgZG9lcyBub3QgZXhpc3RcclxuICAgICFleGlzdHNTeW5jKGdldEFic29sdXRlUGF0aChsb2dnaW5nLmRlc3QpKSAmJlxyXG4gICAgICBta2RpclN5bmMoZ2V0QWJzb2x1dGVQYXRoKGxvZ2dpbmcuZGVzdCkpO1xyXG5cclxuICAgIC8vIENyZWF0ZSB0aGUgZnVsbCBwYXRoXHJcbiAgICBsb2dnaW5nLnBhdGhUb0xvZyA9IGdldEFic29sdXRlUGF0aChqb2luKGxvZ2dpbmcuZGVzdCwgbG9nZ2luZy5maWxlKSk7XHJcblxyXG4gICAgLy8gV2Ugbm93IGFzc3VtZSB0aGUgcGF0aCBpcyBhdmFpbGFibGUsIGUuZy4gaXQncyB0aGUgcmVzcG9uc2liaWxpdHlcclxuICAgIC8vIG9mIHRoZSB1c2VyIHRvIGNyZWF0ZSB0aGUgcGF0aCB3aXRoIHRoZSBjb3JyZWN0IGFjY2VzcyByaWdodHMuXHJcbiAgICBsb2dnaW5nLnBhdGhDcmVhdGVkID0gdHJ1ZTtcclxuICB9XHJcblxyXG4gIC8vIEFkZCB0aGUgY29udGVudCB0byBhIGZpbGVcclxuICBhcHBlbmRGaWxlKFxyXG4gICAgbG9nZ2luZy5wYXRoVG9Mb2csXHJcbiAgICBbcHJlZml4XS5jb25jYXQodGV4dHMpLmpvaW4oJyAnKSArICdcXG4nLFxyXG4gICAgKGVycm9yKSA9PiB7XHJcbiAgICAgIGlmIChlcnJvciAmJiBsb2dnaW5nLnRvRmlsZSAmJiBsb2dnaW5nLnBhdGhDcmVhdGVkKSB7XHJcbiAgICAgICAgbG9nZ2luZy50b0ZpbGUgPSBmYWxzZTtcclxuICAgICAgICBsb2dnaW5nLnBhdGhDcmVhdGVkID0gZmFsc2U7XHJcbiAgICAgICAgbG9nV2l0aFN0YWNrKDIsIGVycm9yLCBgW2xvZ2dlcl0gVW5hYmxlIHRvIHdyaXRlIHRvIGxvZyBmaWxlLmApO1xyXG4gICAgICB9XHJcbiAgICB9XHJcbiAgKTtcclxufVxyXG5cclxuZXhwb3J0IGRlZmF1bHQge1xyXG4gIGxvZyxcclxuICBsb2dXaXRoU3RhY2ssXHJcbiAgbG9nWm9kSXNzdWVzLFxyXG4gIGluaXRMb2dnaW5nLFxyXG4gIHNldExvZ0xldmVsLFxyXG4gIGVuYWJsZUNvbnNvbGVMb2dnaW5nLFxyXG4gIGVuYWJsZUZpbGVMb2dnaW5nXHJcbn07XHJcbiIsIi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXHJcblxyXG5IaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXJcclxuXHJcbkNvcHlyaWdodCAoYykgMjAxNi0yMDI1LCBIaWdoc29mdFxyXG5cclxuTGljZW5jZWQgdW5kZXIgdGhlIE1JVCBsaWNlbmNlLlxyXG5cclxuQWRkaXRpb25hbGx5IGEgdmFsaWQgSGlnaGNoYXJ0cyBsaWNlbnNlIGlzIHJlcXVpcmVkIGZvciB1c2UuXHJcblxyXG5TZWUgTElDRU5TRSBmaWxlIGluIHJvb3QgZm9yIGRldGFpbHMuXHJcblxyXG4qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xyXG5cclxuLyoqXHJcbiAqIEBvdmVydmlldyBDb25maWd1cmF0aW9uIG1hbmFnZW1lbnQgbW9kdWxlIGZvciB0aGUgSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyLlxyXG4gKiBQcm92aWRlcyBkZWZhdWx0IGNvbmZpZ3VyYXRpb25zIHRoYXQgc3VwcG9ydCBlbnZpcm9ubWVudCB2YXJpYWJsZXMsIENMSVxyXG4gKiBhcmd1bWVudHMsIGFuZCBpbnRlcmFjdGl2ZSBwcm9tcHRzIGZvciBjdXN0b21pemF0aW9uIG9mIG9wdGlvbnMgYW5kIGZlYXR1cmVzLlxyXG4gKiBBZGRpdGlvbmFsbHksIGl0IG1hcHMgbGVnYWN5IG9wdGlvbnMgdG8gbW9kZXJuIHN0cnVjdHVyZXMsIGdlbmVyYXRlcyBuZXN0ZWRcclxuICogYXJndW1lbnQgbWFwcGluZ3MsIGFuZCBkaXNwbGF5cyBDTEkgdXNhZ2UgaW5mb3JtYXRpb24uXHJcbiAqL1xyXG5cclxuLyoqXHJcbiAqIFRoZSBjb25maWd1cmF0aW9uIG9iamVjdCBjb250YWluaW5nIGFsbCBhdmFpbGFibGUgb3B0aW9ucywgb3JnYW5pemVkXHJcbiAqIGJ5IHNlY3Rpb25zLlxyXG4gKlxyXG4gKiBUaGlzIG9iamVjdCBpbmNsdWRlczpcclxuICogLSBEZWZhdWx0IHZhbHVlcyBmb3IgZWFjaCBvcHRpb25cclxuICogLSBEYXRhIHR5cGVzIGZvciB2YWxpZGF0aW9uXHJcbiAqIC0gTmFtZXMgb2YgY29ycmVzcG9uZGluZyBlbnZpcm9ubWVudCB2YXJpYWJsZXNcclxuICogLSBEZXNjcmlwdGlvbnMgb2YgZWFjaCBwcm9wZXJ0eVxyXG4gKiAtIEluZm9ybWF0aW9uIHVzZWQgZm9yIHByb21wdHMgaW4gaW50ZXJhY3RpdmUgY29uZmlndXJhdGlvblxyXG4gKiAtIFtPcHRpb25hbF0gQ29ycmVzcG9uZGluZyBDTEkgYXJndW1lbnQgbmFtZXMgZm9yIENMSSB1c2FnZVxyXG4gKiAtIFtPcHRpb25hbF0gTGVnYWN5IG5hbWVzIGZyb20gdGhlIHByZXZpb3VzIFBoYW50b21KUy1iYXNlZCBzZXJ2ZXJcclxuICovXHJcbmV4cG9ydCBjb25zdCBkZWZhdWx0Q29uZmlnID0ge1xyXG4gIHB1cHBldGVlcjoge1xyXG4gICAgYXJnczoge1xyXG4gICAgICB2YWx1ZTogW1xyXG4gICAgICAgICctLWFsbG93LXJ1bm5pbmctaW5zZWN1cmUtY29udGVudCcsXHJcbiAgICAgICAgJy0tYXNoLW5vLW51ZGdlcycsXHJcbiAgICAgICAgJy0tYXV0b3BsYXktcG9saWN5PXVzZXItZ2VzdHVyZS1yZXF1aXJlZCcsXHJcbiAgICAgICAgJy0tYmxvY2stbmV3LXdlYi1jb250ZW50cycsXHJcbiAgICAgICAgJy0tZGlzYWJsZS1hY2NlbGVyYXRlZC0yZC1jYW52YXMnLFxyXG4gICAgICAgICctLWRpc2FibGUtYmFja2dyb3VuZC1uZXR3b3JraW5nJyxcclxuICAgICAgICAnLS1kaXNhYmxlLWJhY2tncm91bmQtdGltZXItdGhyb3R0bGluZycsXHJcbiAgICAgICAgJy0tZGlzYWJsZS1iYWNrZ3JvdW5kaW5nLW9jY2x1ZGVkLXdpbmRvd3MnLFxyXG4gICAgICAgICctLWRpc2FibGUtYnJlYWtwYWQnLFxyXG4gICAgICAgICctLWRpc2FibGUtY2hlY2tlci1pbWFnaW5nJyxcclxuICAgICAgICAnLS1kaXNhYmxlLWNsaWVudC1zaWRlLXBoaXNoaW5nLWRldGVjdGlvbicsXHJcbiAgICAgICAgJy0tZGlzYWJsZS1jb21wb25lbnQtZXh0ZW5zaW9ucy13aXRoLWJhY2tncm91bmQtcGFnZXMnLFxyXG4gICAgICAgICctLWRpc2FibGUtY29tcG9uZW50LXVwZGF0ZScsXHJcbiAgICAgICAgJy0tZGlzYWJsZS1kZWZhdWx0LWFwcHMnLFxyXG4gICAgICAgICctLWRpc2FibGUtZGV2LXNobS11c2FnZScsXHJcbiAgICAgICAgJy0tZGlzYWJsZS1kb21haW4tcmVsaWFiaWxpdHknLFxyXG4gICAgICAgICctLWRpc2FibGUtZXh0ZW5zaW9ucycsXHJcbiAgICAgICAgJy0tZGlzYWJsZS1mZWF0dXJlcz1DYWxjdWxhdGVOYXRpdmVXaW5PY2NsdXNpb24sSW50ZXJlc3RGZWVkQ29udGVudFN1Z2dlc3Rpb25zLFdlYk9UUCcsXHJcbiAgICAgICAgJy0tZGlzYWJsZS1oYW5nLW1vbml0b3InLFxyXG4gICAgICAgICctLWRpc2FibGUtaXBjLWZsb29kaW5nLXByb3RlY3Rpb24nLFxyXG4gICAgICAgICctLWRpc2FibGUtbG9nZ2luZycsXHJcbiAgICAgICAgJy0tZGlzYWJsZS1ub3RpZmljYXRpb25zJyxcclxuICAgICAgICAnLS1kaXNhYmxlLW9mZmVyLXN0b3JlLXVubWFza2VkLXdhbGxldC1jYXJkcycsXHJcbiAgICAgICAgJy0tZGlzYWJsZS1wb3B1cC1ibG9ja2luZycsXHJcbiAgICAgICAgJy0tZGlzYWJsZS1wcmludC1wcmV2aWV3JyxcclxuICAgICAgICAnLS1kaXNhYmxlLXByb21wdC1vbi1yZXBvc3QnLFxyXG4gICAgICAgICctLWRpc2FibGUtcmVuZGVyZXItYmFja2dyb3VuZGluZycsXHJcbiAgICAgICAgJy0tZGlzYWJsZS1zZWFyY2gtZW5naW5lLWNob2ljZS1zY3JlZW4nLFxyXG4gICAgICAgICctLWRpc2FibGUtc2Vzc2lvbi1jcmFzaGVkLWJ1YmJsZScsXHJcbiAgICAgICAgJy0tZGlzYWJsZS1zZXR1aWQtc2FuZGJveCcsXHJcbiAgICAgICAgJy0tZGlzYWJsZS1zaXRlLWlzb2xhdGlvbi10cmlhbHMnLFxyXG4gICAgICAgICctLWRpc2FibGUtc3BlZWNoLWFwaScsXHJcbiAgICAgICAgJy0tZGlzYWJsZS1zeW5jJyxcclxuICAgICAgICAnLS1lbmFibGUtdW5zYWZlLXdlYmdwdScsXHJcbiAgICAgICAgJy0taGlkZS1jcmFzaC1yZXN0b3JlLWJ1YmJsZScsXHJcbiAgICAgICAgJy0taGlkZS1zY3JvbGxiYXJzJyxcclxuICAgICAgICAnLS1tZXRyaWNzLXJlY29yZGluZy1vbmx5JyxcclxuICAgICAgICAnLS1tdXRlLWF1ZGlvJyxcclxuICAgICAgICAnLS1uby1kZWZhdWx0LWJyb3dzZXItY2hlY2snLFxyXG4gICAgICAgICctLW5vLWZpcnN0LXJ1bicsXHJcbiAgICAgICAgJy0tbm8tcGluZ3MnLFxyXG4gICAgICAgICctLW5vLXNhbmRib3gnLFxyXG4gICAgICAgICctLW5vLXN0YXJ0dXAtd2luZG93JyxcclxuICAgICAgICAnLS1uby16eWdvdGUnLFxyXG4gICAgICAgICctLXBhc3N3b3JkLXN0b3JlPWJhc2ljJyxcclxuICAgICAgICAnLS1wcm9jZXNzLXBlci10YWInLFxyXG4gICAgICAgICctLXVzZS1tb2NrLWtleWNoYWluJ1xyXG4gICAgICBdLFxyXG4gICAgICB0eXBlczogWydzdHJpbmdbXSddLFxyXG4gICAgICBlbnZMaW5rOiAnUFVQUEVURUVSX0FSR1MnLFxyXG4gICAgICBjbGlOYW1lOiAncHVwcGV0ZWVyQXJncycsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnQXJyYXkgb2YgUHVwcGV0ZWVyIGFyZ3VtZW50cycsXHJcbiAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICB0eXBlOiAnbGlzdCcsXHJcbiAgICAgICAgc2VwYXJhdG9yOiAnOydcclxuICAgICAgfVxyXG4gICAgfVxyXG4gIH0sXHJcbiAgaGlnaGNoYXJ0czoge1xyXG4gICAgdmVyc2lvbjoge1xyXG4gICAgICB2YWx1ZTogJ2xhdGVzdCcsXHJcbiAgICAgIHR5cGVzOiBbJ3N0cmluZyddLFxyXG4gICAgICBlbnZMaW5rOiAnSElHSENIQVJUU19WRVJTSU9OJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdIaWdoY2hhcnRzIHZlcnNpb24nLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ3RleHQnXHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICBjZG5Vcmw6IHtcclxuICAgICAgdmFsdWU6ICdodHRwczovL2NvZGUuaGlnaGNoYXJ0cy5jb20nLFxyXG4gICAgICB0eXBlczogWydzdHJpbmcnXSxcclxuICAgICAgZW52TGluazogJ0hJR0hDSEFSVFNfQ0ROX1VSTCcsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnQ0ROIFVSTCBmb3IgSGlnaGNoYXJ0cyBzY3JpcHRzJyxcclxuICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgIHR5cGU6ICd0ZXh0J1xyXG4gICAgICB9XHJcbiAgICB9LFxyXG4gICAgZm9yY2VGZXRjaDoge1xyXG4gICAgICB2YWx1ZTogZmFsc2UsXHJcbiAgICAgIHR5cGVzOiBbJ2Jvb2xlYW4nXSxcclxuICAgICAgZW52TGluazogJ0hJR0hDSEFSVFNfRk9SQ0VfRkVUQ0gnLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ0ZsYWcgdG8gcmVmZXRjaCBzY3JpcHRzIGFmdGVyIGVhY2ggc2VydmVyIHJlcnVuJyxcclxuICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgIHR5cGU6ICd0b2dnbGUnXHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICBjYWNoZVBhdGg6IHtcclxuICAgICAgdmFsdWU6ICcuY2FjaGUnLFxyXG4gICAgICB0eXBlczogWydzdHJpbmcnXSxcclxuICAgICAgZW52TGluazogJ0hJR0hDSEFSVFNfQ0FDSEVfUEFUSCcsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnRGlyZWN0b3J5IHBhdGggZm9yIGNhY2hlZCBIaWdoY2hhcnRzIHNjcmlwdHMnLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ3RleHQnXHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICBjb3JlU2NyaXB0czoge1xyXG4gICAgICB2YWx1ZTogWydoaWdoY2hhcnRzJywgJ2hpZ2hjaGFydHMtbW9yZScsICdoaWdoY2hhcnRzLTNkJ10sXHJcbiAgICAgIHR5cGVzOiBbJ3N0cmluZ1tdJ10sXHJcbiAgICAgIGVudkxpbms6ICdISUdIQ0hBUlRTX0NPUkVfU0NSSVBUUycsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnSGlnaGNoYXJ0cyBjb3JlIHNjcmlwdHMgdG8gZmV0Y2gnLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ211bHRpc2VsZWN0JyxcclxuICAgICAgICBpbnN0cnVjdGlvbnM6ICdTcGFjZTogU2VsZWN0IHNwZWNpZmljLCBBOiBTZWxlY3QgYWxsLCBFbnRlcjogQ29uZmlybSdcclxuICAgICAgfVxyXG4gICAgfSxcclxuICAgIG1vZHVsZVNjcmlwdHM6IHtcclxuICAgICAgdmFsdWU6IFtcclxuICAgICAgICAnc3RvY2snLFxyXG4gICAgICAgICdtYXAnLFxyXG4gICAgICAgICdnYW50dCcsXHJcbiAgICAgICAgJ2V4cG9ydGluZycsXHJcbiAgICAgICAgJ3BhcmFsbGVsLWNvb3JkaW5hdGVzJyxcclxuICAgICAgICAnYWNjZXNzaWJpbGl0eScsXHJcbiAgICAgICAgLy8gJ2Fubm90YXRpb25zLWFkdmFuY2VkJyxcclxuICAgICAgICAnYm9vc3QtY2FudmFzJyxcclxuICAgICAgICAnYm9vc3QnLFxyXG4gICAgICAgICdkYXRhJyxcclxuICAgICAgICAnZGF0YS10b29scycsXHJcbiAgICAgICAgJ2RyYWdnYWJsZS1wb2ludHMnLFxyXG4gICAgICAgICdzdGF0aWMtc2NhbGUnLFxyXG4gICAgICAgICdicm9rZW4tYXhpcycsXHJcbiAgICAgICAgJ2hlYXRtYXAnLFxyXG4gICAgICAgICd0aWxlbWFwJyxcclxuICAgICAgICAndGlsZWR3ZWJtYXAnLFxyXG4gICAgICAgICd0aW1lbGluZScsXHJcbiAgICAgICAgJ3RyZWVtYXAnLFxyXG4gICAgICAgICd0cmVlZ3JhcGgnLFxyXG4gICAgICAgICdpdGVtLXNlcmllcycsXHJcbiAgICAgICAgJ2RyaWxsZG93bicsXHJcbiAgICAgICAgJ2hpc3RvZ3JhbS1iZWxsY3VydmUnLFxyXG4gICAgICAgICdidWxsZXQnLFxyXG4gICAgICAgICdmdW5uZWwnLFxyXG4gICAgICAgICdmdW5uZWwzZCcsXHJcbiAgICAgICAgJ2dlb2hlYXRtYXAnLFxyXG4gICAgICAgICdweXJhbWlkM2QnLFxyXG4gICAgICAgICduZXR3b3JrZ3JhcGgnLFxyXG4gICAgICAgICdvdmVybGFwcGluZy1kYXRhbGFiZWxzJyxcclxuICAgICAgICAncGFyZXRvJyxcclxuICAgICAgICAncGF0dGVybi1maWxsJyxcclxuICAgICAgICAncGljdG9yaWFsJyxcclxuICAgICAgICAncHJpY2UtaW5kaWNhdG9yJyxcclxuICAgICAgICAnc2Fua2V5JyxcclxuICAgICAgICAnYXJjLWRpYWdyYW0nLFxyXG4gICAgICAgICdkZXBlbmRlbmN5LXdoZWVsJyxcclxuICAgICAgICAnc2VyaWVzLWxhYmVsJyxcclxuICAgICAgICAnc2VyaWVzLW9uLXBvaW50JyxcclxuICAgICAgICAnc29saWQtZ2F1Z2UnLFxyXG4gICAgICAgICdzb25pZmljYXRpb24nLFxyXG4gICAgICAgIC8vICdzdG9jay10b29scycsXHJcbiAgICAgICAgJ3N0cmVhbWdyYXBoJyxcclxuICAgICAgICAnc3VuYnVyc3QnLFxyXG4gICAgICAgICd2YXJpYWJsZS1waWUnLFxyXG4gICAgICAgICd2YXJpd2lkZScsXHJcbiAgICAgICAgJ3ZlY3RvcicsXHJcbiAgICAgICAgJ3Zlbm4nLFxyXG4gICAgICAgICd3aW5kYmFyYicsXHJcbiAgICAgICAgJ3dvcmRjbG91ZCcsXHJcbiAgICAgICAgJ3hyYW5nZScsXHJcbiAgICAgICAgJ25vLWRhdGEtdG8tZGlzcGxheScsXHJcbiAgICAgICAgJ2RyYWctcGFuZXMnLFxyXG4gICAgICAgICdkZWJ1Z2dlcicsXHJcbiAgICAgICAgJ2R1bWJiZWxsJyxcclxuICAgICAgICAnbG9sbGlwb3AnLFxyXG4gICAgICAgICdjeWxpbmRlcicsXHJcbiAgICAgICAgJ29yZ2FuaXphdGlvbicsXHJcbiAgICAgICAgJ2RvdHBsb3QnLFxyXG4gICAgICAgICdtYXJrZXItY2x1c3RlcnMnLFxyXG4gICAgICAgICdob2xsb3djYW5kbGVzdGljaycsXHJcbiAgICAgICAgJ2hlaWtpbmFzaGknLFxyXG4gICAgICAgICdmbG93bWFwJyxcclxuICAgICAgICAnZXhwb3J0LWRhdGEnLFxyXG4gICAgICAgICduYXZpZ2F0b3InLFxyXG4gICAgICAgICd0ZXh0cGF0aCdcclxuICAgICAgXSxcclxuICAgICAgdHlwZXM6IFsnc3RyaW5nW10nXSxcclxuICAgICAgZW52TGluazogJ0hJR0hDSEFSVFNfTU9EVUxFX1NDUklQVFMnLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ0hpZ2hjaGFydHMgbW9kdWxlIHNjcmlwdHMgdG8gZmV0Y2gnLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ211bHRpc2VsZWN0JyxcclxuICAgICAgICBpbnN0cnVjdGlvbnM6ICdTcGFjZTogU2VsZWN0IHNwZWNpZmljLCBBOiBTZWxlY3QgYWxsLCBFbnRlcjogQ29uZmlybSdcclxuICAgICAgfVxyXG4gICAgfSxcclxuICAgIGluZGljYXRvclNjcmlwdHM6IHtcclxuICAgICAgdmFsdWU6IFsnaW5kaWNhdG9ycy1hbGwnXSxcclxuICAgICAgdHlwZXM6IFsnc3RyaW5nW10nXSxcclxuICAgICAgZW52TGluazogJ0hJR0hDSEFSVFNfSU5ESUNBVE9SX1NDUklQVFMnLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ0hpZ2hjaGFydHMgaW5kaWNhdG9yIHNjcmlwdHMgdG8gZmV0Y2gnLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ211bHRpc2VsZWN0JyxcclxuICAgICAgICBpbnN0cnVjdGlvbnM6ICdTcGFjZTogU2VsZWN0IHNwZWNpZmljLCBBOiBTZWxlY3QgYWxsLCBFbnRlcjogQ29uZmlybSdcclxuICAgICAgfVxyXG4gICAgfSxcclxuICAgIGN1c3RvbVNjcmlwdHM6IHtcclxuICAgICAgdmFsdWU6IFtcclxuICAgICAgICAnaHR0cHM6Ly9jZG5qcy5jbG91ZGZsYXJlLmNvbS9hamF4L2xpYnMvbW9tZW50LmpzLzIuMzAuMS9tb21lbnQubWluLmpzJyxcclxuICAgICAgICAnaHR0cHM6Ly9jZG5qcy5jbG91ZGZsYXJlLmNvbS9hamF4L2xpYnMvbW9tZW50LXRpbWV6b25lLzAuNS40NS9tb21lbnQtdGltZXpvbmUtd2l0aC1kYXRhLm1pbi5qcydcclxuICAgICAgXSxcclxuICAgICAgdHlwZXM6IFsnc3RyaW5nW10nXSxcclxuICAgICAgZW52TGluazogJ0hJR0hDSEFSVFNfQ1VTVE9NX1NDUklQVFMnLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ0FkZGl0aW9uYWwgY3VzdG9tIHNjcmlwdHMgb3IgZGVwZW5kZW5jaWVzIHRvIGZldGNoJyxcclxuICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgIHR5cGU6ICdsaXN0JyxcclxuICAgICAgICBzZXBhcmF0b3I6ICc7J1xyXG4gICAgICB9XHJcbiAgICB9XHJcbiAgfSxcclxuICBleHBvcnQ6IHtcclxuICAgIGluZmlsZToge1xyXG4gICAgICB2YWx1ZTogbnVsbCxcclxuICAgICAgdHlwZXM6IFsnc3RyaW5nJywgJ251bGwnXSxcclxuICAgICAgZW52TGluazogJ0VYUE9SVF9JTkZJTEUnLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnSW5wdXQgZmlsZW5hbWUgd2l0aCB0eXBlLCBmb3JtYXR0ZWQgY29ycmVjdGx5IGFzIEpTT04gb3IgU1ZHJyxcclxuICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgIHR5cGU6ICd0ZXh0J1xyXG4gICAgICB9XHJcbiAgICB9LFxyXG4gICAgaW5zdHI6IHtcclxuICAgICAgdmFsdWU6IG51bGwsXHJcbiAgICAgIHR5cGVzOiBbJ09iamVjdCcsICdzdHJpbmcnLCAnbnVsbCddLFxyXG4gICAgICBlbnZMaW5rOiAnRVhQT1JUX0lOU1RSJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ092ZXJyaWRlcyB0aGUgYGluZmlsZWAgd2l0aCBKU09OLCBzdHJpbmdpZmllZCBKU09OLCBvciBTVkcgaW5wdXQnLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ3RleHQnXHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICBvcHRpb25zOiB7XHJcbiAgICAgIHZhbHVlOiBudWxsLFxyXG4gICAgICB0eXBlczogWydPYmplY3QnLCAnc3RyaW5nJywgJ251bGwnXSxcclxuICAgICAgZW52TGluazogJ0VYUE9SVF9PUFRJT05TJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdBbGlhcyBmb3IgdGhlIGBpbnN0cmAgb3B0aW9uJyxcclxuICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgIHR5cGU6ICd0ZXh0J1xyXG4gICAgICB9XHJcbiAgICB9LFxyXG4gICAgc3ZnOiB7XHJcbiAgICAgIHZhbHVlOiBudWxsLFxyXG4gICAgICB0eXBlczogWydzdHJpbmcnLCAnbnVsbCddLFxyXG4gICAgICBlbnZMaW5rOiAnRVhQT1JUX1NWRycsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnU1ZHIHN0cmluZyByZXByZXNlbnRhdGlvbiBvZiB0aGUgY2hhcnQgdG8gcmVuZGVyJyxcclxuICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgIHR5cGU6ICd0ZXh0J1xyXG4gICAgICB9XHJcbiAgICB9LFxyXG4gICAgYmF0Y2g6IHtcclxuICAgICAgdmFsdWU6IG51bGwsXHJcbiAgICAgIHR5cGVzOiBbJ3N0cmluZycsICdudWxsJ10sXHJcbiAgICAgIGVudkxpbms6ICdFWFBPUlRfQkFUQ0gnLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnQmF0Y2ggam9iIHN0cmluZyB3aXRoIGlucHV0L291dHB1dCBwYWlyczogXCJpbj1vdXQ7aW49b3V0Oy4uLlwiJyxcclxuICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgIHR5cGU6ICd0ZXh0J1xyXG4gICAgICB9XHJcbiAgICB9LFxyXG4gICAgb3V0ZmlsZToge1xyXG4gICAgICB2YWx1ZTogbnVsbCxcclxuICAgICAgdHlwZXM6IFsnc3RyaW5nJywgJ251bGwnXSxcclxuICAgICAgZW52TGluazogJ0VYUE9SVF9PVVRGSUxFJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ091dHB1dCBmaWxlbmFtZSB3aXRoIHR5cGUuIENhbiBiZSBqcGVnLCBwbmcsIHBkZiwgb3Igc3ZnIGFuZCBpZ25vcmVzIGB0eXBlYCBvcHRpb24nLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ3RleHQnXHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICB0eXBlOiB7XHJcbiAgICAgIHZhbHVlOiAncG5nJyxcclxuICAgICAgdHlwZXM6IFsnc3RyaW5nJ10sXHJcbiAgICAgIGVudkxpbms6ICdFWFBPUlRfVFlQRScsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnRmlsZSBleHBvcnQgZm9ybWF0LiBDYW4gYmUganBlZywgcG5nLCBwZGYsIG9yIHN2ZycsXHJcbiAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICB0eXBlOiAnc2VsZWN0JyxcclxuICAgICAgICBoaW50OiAnRGVmYXVsdDogcG5nJyxcclxuICAgICAgICBjaG9pY2VzOiBbJ3BuZycsICdqcGVnJywgJ3BkZicsICdzdmcnXVxyXG4gICAgICB9XHJcbiAgICB9LFxyXG4gICAgY29uc3RyOiB7XHJcbiAgICAgIHZhbHVlOiAnY2hhcnQnLFxyXG4gICAgICB0eXBlczogWydzdHJpbmcnXSxcclxuICAgICAgZW52TGluazogJ0VYUE9SVF9DT05TVFInLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnQ2hhcnQgY29uc3RydWN0b3IuIENhbiBiZSBjaGFydCwgc3RvY2tDaGFydCwgbWFwQ2hhcnQsIG9yIGdhbnR0Q2hhcnQnLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ3NlbGVjdCcsXHJcbiAgICAgICAgaGludDogJ0RlZmF1bHQ6IGNoYXJ0JyxcclxuICAgICAgICBjaG9pY2VzOiBbJ2NoYXJ0JywgJ3N0b2NrQ2hhcnQnLCAnbWFwQ2hhcnQnLCAnZ2FudHRDaGFydCddXHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICBiNjQ6IHtcclxuICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICB0eXBlczogWydib29sZWFuJ10sXHJcbiAgICAgIGVudkxpbms6ICdFWFBPUlRfQjY0JyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ1doZXRoZXIgb3Igbm90IHRvIHRoZSBjaGFydCBzaG91bGQgYmUgcmVjZWl2ZWQgaW4gQmFzZTY0IGZvcm1hdCBpbnN0ZWFkIG9mIGJpbmFyeScsXHJcbiAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICB0eXBlOiAndG9nZ2xlJ1xyXG4gICAgICB9XHJcbiAgICB9LFxyXG4gICAgbm9Eb3dubG9hZDoge1xyXG4gICAgICB2YWx1ZTogZmFsc2UsXHJcbiAgICAgIHR5cGVzOiBbJ2Jvb2xlYW4nXSxcclxuICAgICAgZW52TGluazogJ0VYUE9SVF9OT19ET1dOTE9BRCcsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdXaGV0aGVyIG9yIG5vdCB0byBpbmNsdWRlIG9yIGV4Y2x1ZGUgYXR0YWNobWVudCBoZWFkZXJzIGluIHRoZSByZXNwb25zZScsXHJcbiAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICB0eXBlOiAndG9nZ2xlJ1xyXG4gICAgICB9XHJcbiAgICB9LFxyXG4gICAgaGVpZ2h0OiB7XHJcbiAgICAgIHZhbHVlOiBudWxsLFxyXG4gICAgICB0eXBlczogWydudW1iZXInLCAnbnVsbCddLFxyXG4gICAgICBlbnZMaW5rOiAnRVhQT1JUX0hFSUdIVCcsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnSGVpZ2h0IG9mIHRoZSBleHBvcnRlZCBjaGFydCwgb3ZlcnJpZGVzIGNoYXJ0IHNldHRpbmdzJyxcclxuICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgIHR5cGU6ICdudW1iZXInXHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICB3aWR0aDoge1xyXG4gICAgICB2YWx1ZTogbnVsbCxcclxuICAgICAgdHlwZXM6IFsnbnVtYmVyJywgJ251bGwnXSxcclxuICAgICAgZW52TGluazogJ0VYUE9SVF9XSURUSCcsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnV2lkdGggb2YgdGhlIGV4cG9ydGVkIGNoYXJ0LCBvdmVycmlkZXMgY2hhcnQgc2V0dGluZ3MnLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ251bWJlcidcclxuICAgICAgfVxyXG4gICAgfSxcclxuICAgIHNjYWxlOiB7XHJcbiAgICAgIHZhbHVlOiBudWxsLFxyXG4gICAgICB0eXBlczogWydudW1iZXInLCAnbnVsbCddLFxyXG4gICAgICBlbnZMaW5rOiAnRVhQT1JUX1NDQUxFJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ1NjYWxlIG9mIHRoZSBleHBvcnRlZCBjaGFydCwgb3ZlcnJpZGVzIGNoYXJ0IHNldHRpbmdzLiBSYW5nZXMgZnJvbSAwLjEgdG8gNS4wJyxcclxuICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgIHR5cGU6ICdudW1iZXInXHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICBkZWZhdWx0SGVpZ2h0OiB7XHJcbiAgICAgIHZhbHVlOiA0MDAsXHJcbiAgICAgIHR5cGVzOiBbJ251bWJlciddLFxyXG4gICAgICBlbnZMaW5rOiAnRVhQT1JUX0RFRkFVTFRfSEVJR0hUJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdEZWZhdWx0IGhlaWdodCBvZiB0aGUgZXhwb3J0ZWQgY2hhcnQgaWYgbm90IHNldCcsXHJcbiAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICB0eXBlOiAnbnVtYmVyJ1xyXG4gICAgICB9XHJcbiAgICB9LFxyXG4gICAgZGVmYXVsdFdpZHRoOiB7XHJcbiAgICAgIHZhbHVlOiA2MDAsXHJcbiAgICAgIHR5cGVzOiBbJ251bWJlciddLFxyXG4gICAgICBlbnZMaW5rOiAnRVhQT1JUX0RFRkFVTFRfV0lEVEgnLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ0RlZmF1bHQgd2lkdGggb2YgdGhlIGV4cG9ydGVkIGNoYXJ0IGlmIG5vdCBzZXQnLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ251bWJlcidcclxuICAgICAgfVxyXG4gICAgfSxcclxuICAgIGRlZmF1bHRTY2FsZToge1xyXG4gICAgICB2YWx1ZTogMSxcclxuICAgICAgdHlwZXM6IFsnbnVtYmVyJ10sXHJcbiAgICAgIGVudkxpbms6ICdFWFBPUlRfREVGQVVMVF9TQ0FMRScsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdEZWZhdWx0IHNjYWxlIG9mIHRoZSBleHBvcnRlZCBjaGFydCBpZiBub3Qgc2V0LiBSYW5nZXMgZnJvbSAwLjEgdG8gNS4wJyxcclxuICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICAgIG1pbjogMC4xLFxyXG4gICAgICAgIG1heDogNVxyXG4gICAgICB9XHJcbiAgICB9LFxyXG4gICAgZ2xvYmFsT3B0aW9uczoge1xyXG4gICAgICB2YWx1ZTogbnVsbCxcclxuICAgICAgdHlwZXM6IFsnT2JqZWN0JywgJ3N0cmluZycsICdudWxsJ10sXHJcbiAgICAgIGVudkxpbms6ICdFWFBPUlRfR0xPQkFMX09QVElPTlMnLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnSlNPTiwgc3RyaW5naWZpZWQgSlNPTiBvciBmaWxlbmFtZSB3aXRoIGdsb2JhbCBvcHRpb25zIGZvciBIaWdoY2hhcnRzLnNldE9wdGlvbnMnLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ3RleHQnXHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICB0aGVtZU9wdGlvbnM6IHtcclxuICAgICAgdmFsdWU6IG51bGwsXHJcbiAgICAgIHR5cGVzOiBbJ09iamVjdCcsICdzdHJpbmcnLCAnbnVsbCddLFxyXG4gICAgICBlbnZMaW5rOiAnRVhQT1JUX1RIRU1FX09QVElPTlMnLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnSlNPTiwgc3RyaW5naWZpZWQgSlNPTiBvciBmaWxlbmFtZSB3aXRoIHRoZW1lIG9wdGlvbnMgZm9yIEhpZ2hjaGFydHMuc2V0T3B0aW9ucycsXHJcbiAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICB0eXBlOiAndGV4dCdcclxuICAgICAgfVxyXG4gICAgfSxcclxuICAgIHJhc3Rlcml6YXRpb25UaW1lb3V0OiB7XHJcbiAgICAgIHZhbHVlOiAxNTAwLFxyXG4gICAgICB0eXBlczogWydudW1iZXInXSxcclxuICAgICAgZW52TGluazogJ0VYUE9SVF9SQVNURVJJWkFUSU9OX1RJTUVPVVQnLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ01pbGxpc2Vjb25kcyB0byB3YWl0IGZvciB3ZWJwYWdlIHJlbmRlcmluZycsXHJcbiAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICB0eXBlOiAnbnVtYmVyJ1xyXG4gICAgICB9XHJcbiAgICB9XHJcbiAgfSxcclxuICBjdXN0b21Mb2dpYzoge1xyXG4gICAgYWxsb3dDb2RlRXhlY3V0aW9uOiB7XHJcbiAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgdHlwZXM6IFsnYm9vbGVhbiddLFxyXG4gICAgICBlbnZMaW5rOiAnQ1VTVE9NX0xPR0lDX0FMTE9XX0NPREVfRVhFQ1VUSU9OJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ0FsbG93cyBvciBkaXNhbGxvd3MgZXhlY3V0aW9uIG9mIGFyYml0cmFyeSBjb2RlIGR1cmluZyBleHBvcnRpbmcnLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ3RvZ2dsZSdcclxuICAgICAgfVxyXG4gICAgfSxcclxuICAgIGFsbG93RmlsZVJlc291cmNlczoge1xyXG4gICAgICB2YWx1ZTogZmFsc2UsXHJcbiAgICAgIHR5cGVzOiBbJ2Jvb2xlYW4nXSxcclxuICAgICAgZW52TGluazogJ0NVU1RPTV9MT0dJQ19BTExPV19GSUxFX1JFU09VUkNFUycsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdBbGxvd3Mgb3IgZGlzYWxsb3dzIGluamVjdGlvbiBvZiBmaWxlc3lzdGVtIHJlc291cmNlcyAoZGlzYWJsZWQgaW4gc2VydmVyIG1vZGUpJyxcclxuICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgIHR5cGU6ICd0b2dnbGUnXHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICBjdXN0b21Db2RlOiB7XHJcbiAgICAgIHZhbHVlOiBudWxsLFxyXG4gICAgICB0eXBlczogWydzdHJpbmcnLCAnbnVsbCddLFxyXG4gICAgICBlbnZMaW5rOiAnQ1VTVE9NX0xPR0lDX0NVU1RPTV9DT0RFJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ0N1c3RvbSBjb2RlIHRvIGV4ZWN1dGUgYmVmb3JlIGNoYXJ0IGluaXRpYWxpemF0aW9uLiBDYW4gYmUgYSBmdW5jdGlvbiwgY29kZSB3cmFwcGVkIGluIGEgZnVuY3Rpb24sIG9yIGEgLmpzIGZpbGVuYW1lJyxcclxuICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgIHR5cGU6ICd0ZXh0J1xyXG4gICAgICB9XHJcbiAgICB9LFxyXG4gICAgY2FsbGJhY2s6IHtcclxuICAgICAgdmFsdWU6IG51bGwsXHJcbiAgICAgIHR5cGVzOiBbJ3N0cmluZycsICdudWxsJ10sXHJcbiAgICAgIGVudkxpbms6ICdDVVNUT01fTE9HSUNfQ0FMTEJBQ0snLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnSmF2YVNjcmlwdCBjb2RlIHRvIHJ1biBkdXJpbmcgY29uc3RydWN0aW9uLiBDYW4gYmUgYSBmdW5jdGlvbiBvciBhIC5qcyBmaWxlbmFtZScsXHJcbiAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICB0eXBlOiAndGV4dCdcclxuICAgICAgfVxyXG4gICAgfSxcclxuICAgIHJlc291cmNlczoge1xyXG4gICAgICB2YWx1ZTogbnVsbCxcclxuICAgICAgdHlwZXM6IFsnT2JqZWN0JywgJ3N0cmluZycsICdudWxsJ10sXHJcbiAgICAgIGVudkxpbms6ICdDVVNUT01fTE9HSUNfUkVTT1VSQ0VTJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ0FkZGl0aW9uYWwgcmVzb3VyY2VzIGFzIEpTT04sIHN0cmluZ2lmaWVkIEpTT04sIG9yIGZpbGVuYW1lLCBjb250YWluaW5nIGZpbGVzLCBqcywgYW5kIGNzcyBzZWN0aW9ucycsXHJcbiAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICB0eXBlOiAndGV4dCdcclxuICAgICAgfVxyXG4gICAgfSxcclxuICAgIGxvYWRDb25maWc6IHtcclxuICAgICAgdmFsdWU6IG51bGwsXHJcbiAgICAgIHR5cGVzOiBbJ3N0cmluZycsICdudWxsJ10sXHJcbiAgICAgIGVudkxpbms6ICdDVVNUT01fTE9HSUNfTE9BRF9DT05GSUcnLFxyXG4gICAgICBsZWdhY3lOYW1lOiAnZnJvbUZpbGUnLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ0ZpbGUgd2l0aCBhIHByZS1kZWZpbmVkIGNvbmZpZ3VyYXRpb24gdG8gdXNlJyxcclxuICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgIHR5cGU6ICd0ZXh0J1xyXG4gICAgICB9XHJcbiAgICB9LFxyXG4gICAgY3JlYXRlQ29uZmlnOiB7XHJcbiAgICAgIHZhbHVlOiBudWxsLFxyXG4gICAgICB0eXBlczogWydzdHJpbmcnLCAnbnVsbCddLFxyXG4gICAgICBlbnZMaW5rOiAnQ1VTVE9NX0xPR0lDX0NSRUFURV9DT05GSUcnLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnUHJvbXB0LWJhc2VkIG9wdGlvbiBzZXR0aW5nLCBzYXZlZCB0byBhIHByb3ZpZGVkIGNvbmZpZyBmaWxlJyxcclxuICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgIHR5cGU6ICd0ZXh0J1xyXG4gICAgICB9XHJcbiAgICB9XHJcbiAgfSxcclxuICBzZXJ2ZXI6IHtcclxuICAgIGVuYWJsZToge1xyXG4gICAgICB2YWx1ZTogZmFsc2UsXHJcbiAgICAgIHR5cGVzOiBbJ2Jvb2xlYW4nXSxcclxuICAgICAgZW52TGluazogJ1NFUlZFUl9FTkFCTEUnLFxyXG4gICAgICBjbGlOYW1lOiAnZW5hYmxlU2VydmVyJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdTdGFydHMgdGhlIHNlcnZlciB3aGVuIHRydWUnLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ3RvZ2dsZSdcclxuICAgICAgfVxyXG4gICAgfSxcclxuICAgIGhvc3Q6IHtcclxuICAgICAgdmFsdWU6ICcwLjAuMC4wJyxcclxuICAgICAgdHlwZXM6IFsnc3RyaW5nJ10sXHJcbiAgICAgIGVudkxpbms6ICdTRVJWRVJfSE9TVCcsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnSG9zdG5hbWUgb2YgdGhlIHNlcnZlcicsXHJcbiAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICB0eXBlOiAndGV4dCdcclxuICAgICAgfVxyXG4gICAgfSxcclxuICAgIHBvcnQ6IHtcclxuICAgICAgdmFsdWU6IDc4MDEsXHJcbiAgICAgIHR5cGVzOiBbJ251bWJlciddLFxyXG4gICAgICBlbnZMaW5rOiAnU0VSVkVSX1BPUlQnLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ1BvcnQgbnVtYmVyIGZvciB0aGUgc2VydmVyJyxcclxuICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgIHR5cGU6ICdudW1iZXInXHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICB1cGxvYWRMaW1pdDoge1xyXG4gICAgICB2YWx1ZTogMyxcclxuICAgICAgdHlwZXM6IFsnbnVtYmVyJ10sXHJcbiAgICAgIGVudkxpbms6ICdTRVJWRVJfVVBMT0FEX0xJTUlUJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdNYXhpbXVtIHJlcXVlc3QgYm9keSBzaXplIGluIE1CJyxcclxuICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgIHR5cGU6ICdudW1iZXInXHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICBiZW5jaG1hcmtpbmc6IHtcclxuICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICB0eXBlczogWydib29sZWFuJ10sXHJcbiAgICAgIGVudkxpbms6ICdTRVJWRVJfQkVOQ0hNQVJLSU5HJyxcclxuICAgICAgY2xpTmFtZTogJ3NlcnZlckJlbmNobWFya2luZycsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdEaXNwbGF5cyBvciBub3QgYWN0aW9uIGR1cmF0aW9ucyBpbiBtaWxsaXNlY29uZHMgZHVyaW5nIHNlcnZlciByZXF1ZXN0cycsXHJcbiAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICB0eXBlOiAndG9nZ2xlJ1xyXG4gICAgICB9XHJcbiAgICB9LFxyXG4gICAgcHJveHk6IHtcclxuICAgICAgaG9zdDoge1xyXG4gICAgICAgIHZhbHVlOiBudWxsLFxyXG4gICAgICAgIHR5cGVzOiBbJ3N0cmluZycsICdudWxsJ10sXHJcbiAgICAgICAgZW52TGluazogJ1NFUlZFUl9QUk9YWV9IT1NUJyxcclxuICAgICAgICBjbGlOYW1lOiAncHJveHlIb3N0JyxcclxuICAgICAgICBkZXNjcmlwdGlvbjogJ0hvc3Qgb2YgdGhlIHByb3h5IHNlcnZlciwgaWYgYXBwbGljYWJsZScsXHJcbiAgICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgICAgdHlwZTogJ3RleHQnXHJcbiAgICAgICAgfVxyXG4gICAgICB9LFxyXG4gICAgICBwb3J0OiB7XHJcbiAgICAgICAgdmFsdWU6IG51bGwsXHJcbiAgICAgICAgdHlwZXM6IFsnbnVtYmVyJywgJ251bGwnXSxcclxuICAgICAgICBlbnZMaW5rOiAnU0VSVkVSX1BST1hZX1BPUlQnLFxyXG4gICAgICAgIGNsaU5hbWU6ICdwcm94eVBvcnQnLFxyXG4gICAgICAgIGRlc2NyaXB0aW9uOiAnUG9ydCBvZiB0aGUgcHJveHkgc2VydmVyLCBpZiBhcHBsaWNhYmxlJyxcclxuICAgICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgICB0eXBlOiAnbnVtYmVyJ1xyXG4gICAgICAgIH1cclxuICAgICAgfSxcclxuICAgICAgdGltZW91dDoge1xyXG4gICAgICAgIHZhbHVlOiA1MDAwLFxyXG4gICAgICAgIHR5cGVzOiBbJ251bWJlciddLFxyXG4gICAgICAgIGVudkxpbms6ICdTRVJWRVJfUFJPWFlfVElNRU9VVCcsXHJcbiAgICAgICAgY2xpTmFtZTogJ3Byb3h5VGltZW91dCcsXHJcbiAgICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgICAnVGltZW91dCBpbiBtaWxsaXNlY29uZHMgZm9yIHRoZSBwcm94eSBzZXJ2ZXIsIGlmIGFwcGxpY2FibGUnLFxyXG4gICAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICAgIHR5cGU6ICdudW1iZXInXHJcbiAgICAgICAgfVxyXG4gICAgICB9XHJcbiAgICB9LFxyXG4gICAgcmF0ZUxpbWl0aW5nOiB7XHJcbiAgICAgIGVuYWJsZToge1xyXG4gICAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgICB0eXBlczogWydib29sZWFuJ10sXHJcbiAgICAgICAgZW52TGluazogJ1NFUlZFUl9SQVRFX0xJTUlUSU5HX0VOQUJMRScsXHJcbiAgICAgICAgY2xpTmFtZTogJ2VuYWJsZVJhdGVMaW1pdGluZycsXHJcbiAgICAgICAgZGVzY3JpcHRpb246ICdFbmFibGVzIG9yIGRpc2FibGVzIHJhdGUgbGltaXRpbmcgb24gdGhlIHNlcnZlcicsXHJcbiAgICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgICAgdHlwZTogJ3RvZ2dsZSdcclxuICAgICAgICB9XHJcbiAgICAgIH0sXHJcbiAgICAgIG1heFJlcXVlc3RzOiB7XHJcbiAgICAgICAgdmFsdWU6IDEwLFxyXG4gICAgICAgIHR5cGVzOiBbJ251bWJlciddLFxyXG4gICAgICAgIGVudkxpbms6ICdTRVJWRVJfUkFURV9MSU1JVElOR19NQVhfUkVRVUVTVFMnLFxyXG4gICAgICAgIGxlZ2FjeU5hbWU6ICdyYXRlTGltaXQnLFxyXG4gICAgICAgIGRlc2NyaXB0aW9uOiAnTWF4aW11bSBudW1iZXIgb2YgcmVxdWVzdHMgYWxsb3dlZCBwZXIgbWludXRlJyxcclxuICAgICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgICB0eXBlOiAnbnVtYmVyJ1xyXG4gICAgICAgIH1cclxuICAgICAgfSxcclxuICAgICAgd2luZG93OiB7XHJcbiAgICAgICAgdmFsdWU6IDEsXHJcbiAgICAgICAgdHlwZXM6IFsnbnVtYmVyJ10sXHJcbiAgICAgICAgZW52TGluazogJ1NFUlZFUl9SQVRFX0xJTUlUSU5HX1dJTkRPVycsXHJcbiAgICAgICAgZGVzY3JpcHRpb246ICdUaW1lIHdpbmRvdyBpbiBtaW51dGVzIGZvciByYXRlIGxpbWl0aW5nJyxcclxuICAgICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgICB0eXBlOiAnbnVtYmVyJ1xyXG4gICAgICAgIH1cclxuICAgICAgfSxcclxuICAgICAgZGVsYXk6IHtcclxuICAgICAgICB2YWx1ZTogMCxcclxuICAgICAgICB0eXBlczogWydudW1iZXInXSxcclxuICAgICAgICBlbnZMaW5rOiAnU0VSVkVSX1JBVEVfTElNSVRJTkdfREVMQVknLFxyXG4gICAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICAgJ0RlbGF5IGR1cmF0aW9uIGJldHdlZW4gc3VjY2Vzc2l2ZSByZXF1ZXN0cyBiZWZvcmUgcmVhY2hpbmcgdGhlIGxpbWl0JyxcclxuICAgICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgICB0eXBlOiAnbnVtYmVyJ1xyXG4gICAgICAgIH1cclxuICAgICAgfSxcclxuICAgICAgdHJ1c3RQcm94eToge1xyXG4gICAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgICB0eXBlczogWydib29sZWFuJ10sXHJcbiAgICAgICAgZW52TGluazogJ1NFUlZFUl9SQVRFX0xJTUlUSU5HX1RSVVNUX1BST1hZJyxcclxuICAgICAgICBkZXNjcmlwdGlvbjogJ1NldCB0byB0cnVlIGlmIHRoZSBzZXJ2ZXIgaXMgYmVoaW5kIGEgbG9hZCBiYWxhbmNlcicsXHJcbiAgICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgICAgdHlwZTogJ3RvZ2dsZSdcclxuICAgICAgICB9XHJcbiAgICAgIH0sXHJcbiAgICAgIHNraXBLZXk6IHtcclxuICAgICAgICB2YWx1ZTogbnVsbCxcclxuICAgICAgICB0eXBlczogWydzdHJpbmcnLCAnbnVsbCddLFxyXG4gICAgICAgIGVudkxpbms6ICdTRVJWRVJfUkFURV9MSU1JVElOR19TS0lQX0tFWScsXHJcbiAgICAgICAgZGVzY3JpcHRpb246ICdLZXkgdG8gYnlwYXNzIHRoZSByYXRlIGxpbWl0ZXIsIHVzZWQgd2l0aCBgc2tpcFRva2VuYCcsXHJcbiAgICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgICAgdHlwZTogJ3RleHQnXHJcbiAgICAgICAgfVxyXG4gICAgICB9LFxyXG4gICAgICBza2lwVG9rZW46IHtcclxuICAgICAgICB2YWx1ZTogbnVsbCxcclxuICAgICAgICB0eXBlczogWydzdHJpbmcnLCAnbnVsbCddLFxyXG4gICAgICAgIGVudkxpbms6ICdTRVJWRVJfUkFURV9MSU1JVElOR19TS0lQX1RPS0VOJyxcclxuICAgICAgICBkZXNjcmlwdGlvbjogJ1Rva2VuIHRvIGJ5cGFzcyB0aGUgcmF0ZSBsaW1pdGVyLCB1c2VkIHdpdGggYHNraXBLZXlgJyxcclxuICAgICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgICB0eXBlOiAndGV4dCdcclxuICAgICAgICB9XHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICBzc2w6IHtcclxuICAgICAgZW5hYmxlOiB7XHJcbiAgICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICAgIHR5cGVzOiBbJ2Jvb2xlYW4nXSxcclxuICAgICAgICBlbnZMaW5rOiAnU0VSVkVSX1NTTF9FTkFCTEUnLFxyXG4gICAgICAgIGNsaU5hbWU6ICdlbmFibGVTc2wnLFxyXG4gICAgICAgIGRlc2NyaXB0aW9uOiAnRW5hYmxlcyBvciBkaXNhYmxlcyBTU0wgcHJvdG9jb2wnLFxyXG4gICAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICAgIHR5cGU6ICd0b2dnbGUnXHJcbiAgICAgICAgfVxyXG4gICAgICB9LFxyXG4gICAgICBmb3JjZToge1xyXG4gICAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgICB0eXBlczogWydib29sZWFuJ10sXHJcbiAgICAgICAgZW52TGluazogJ1NFUlZFUl9TU0xfRk9SQ0UnLFxyXG4gICAgICAgIGNsaU5hbWU6ICdzc2xGb3JjZScsXHJcbiAgICAgICAgbGVnYWN5TmFtZTogJ3NzbE9ubHknLFxyXG4gICAgICAgIGRlc2NyaXB0aW9uOiAnRm9yY2VzIHRoZSBzZXJ2ZXIgdG8gdXNlIEhUVFBTIG9ubHkgd2hlbiB0cnVlJyxcclxuICAgICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgICB0eXBlOiAndG9nZ2xlJ1xyXG4gICAgICAgIH1cclxuICAgICAgfSxcclxuICAgICAgcG9ydDoge1xyXG4gICAgICAgIHZhbHVlOiA0NDMsXHJcbiAgICAgICAgdHlwZXM6IFsnbnVtYmVyJ10sXHJcbiAgICAgICAgZW52TGluazogJ1NFUlZFUl9TU0xfUE9SVCcsXHJcbiAgICAgICAgY2xpTmFtZTogJ3NzbFBvcnQnLFxyXG4gICAgICAgIGRlc2NyaXB0aW9uOiAnUG9ydCBmb3IgdGhlIFNTTCBzZXJ2ZXInLFxyXG4gICAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICAgIHR5cGU6ICdudW1iZXInXHJcbiAgICAgICAgfVxyXG4gICAgICB9LFxyXG4gICAgICBjZXJ0UGF0aDoge1xyXG4gICAgICAgIHZhbHVlOiBudWxsLFxyXG4gICAgICAgIHR5cGVzOiBbJ3N0cmluZycsICdudWxsJ10sXHJcbiAgICAgICAgZW52TGluazogJ1NFUlZFUl9TU0xfQ0VSVF9QQVRIJyxcclxuICAgICAgICBjbGlOYW1lOiAnc3NsQ2VydFBhdGgnLFxyXG4gICAgICAgIGxlZ2FjeU5hbWU6ICdzc2xQYXRoJyxcclxuICAgICAgICBkZXNjcmlwdGlvbjogJ1BhdGggdG8gdGhlIFNTTCBjZXJ0aWZpY2F0ZS9rZXkgZmlsZScsXHJcbiAgICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgICAgdHlwZTogJ3RleHQnXHJcbiAgICAgICAgfVxyXG4gICAgICB9XHJcbiAgICB9XHJcbiAgfSxcclxuICBwb29sOiB7XHJcbiAgICBtaW5Xb3JrZXJzOiB7XHJcbiAgICAgIHZhbHVlOiA0LFxyXG4gICAgICB0eXBlczogWydudW1iZXInXSxcclxuICAgICAgZW52TGluazogJ1BPT0xfTUlOX1dPUktFUlMnLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ01pbmltdW0gYW5kIGluaXRpYWwgbnVtYmVyIG9mIHBvb2wgd29ya2VycyB0byBzcGF3bicsXHJcbiAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICB0eXBlOiAnbnVtYmVyJ1xyXG4gICAgICB9XHJcbiAgICB9LFxyXG4gICAgbWF4V29ya2Vyczoge1xyXG4gICAgICB2YWx1ZTogOCxcclxuICAgICAgdHlwZXM6IFsnbnVtYmVyJ10sXHJcbiAgICAgIGVudkxpbms6ICdQT09MX01BWF9XT1JLRVJTJyxcclxuICAgICAgbGVnYWN5TmFtZTogJ3dvcmtlcnMnLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ01heGltdW0gbnVtYmVyIG9mIHBvb2wgd29ya2VycyB0byBzcGF3bicsXHJcbiAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICB0eXBlOiAnbnVtYmVyJ1xyXG4gICAgICB9XHJcbiAgICB9LFxyXG4gICAgd29ya0xpbWl0OiB7XHJcbiAgICAgIHZhbHVlOiA0MCxcclxuICAgICAgdHlwZXM6IFsnbnVtYmVyJ10sXHJcbiAgICAgIGVudkxpbms6ICdQT09MX1dPUktfTElNSVQnLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ051bWJlciBvZiB0YXNrcyBhIHdvcmtlciBjYW4gaGFuZGxlIGJlZm9yZSByZXN0YXJ0aW5nJyxcclxuICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgIHR5cGU6ICdudW1iZXInXHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICBhY3F1aXJlVGltZW91dDoge1xyXG4gICAgICB2YWx1ZTogNTAwMCxcclxuICAgICAgdHlwZXM6IFsnbnVtYmVyJ10sXHJcbiAgICAgIGVudkxpbms6ICdQT09MX0FDUVVJUkVfVElNRU9VVCcsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnVGltZW91dCBpbiBtaWxsaXNlY29uZHMgZm9yIGFjcXVpcmluZyBhIHJlc291cmNlJyxcclxuICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgIHR5cGU6ICdudW1iZXInXHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICBjcmVhdGVUaW1lb3V0OiB7XHJcbiAgICAgIHZhbHVlOiA1MDAwLFxyXG4gICAgICB0eXBlczogWydudW1iZXInXSxcclxuICAgICAgZW52TGluazogJ1BPT0xfQ1JFQVRFX1RJTUVPVVQnLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ1RpbWVvdXQgaW4gbWlsbGlzZWNvbmRzIGZvciBjcmVhdGluZyBhIHJlc291cmNlJyxcclxuICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgIHR5cGU6ICdudW1iZXInXHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICBkZXN0cm95VGltZW91dDoge1xyXG4gICAgICB2YWx1ZTogNTAwMCxcclxuICAgICAgdHlwZXM6IFsnbnVtYmVyJ10sXHJcbiAgICAgIGVudkxpbms6ICdQT09MX0RFU1RST1lfVElNRU9VVCcsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnVGltZW91dCBpbiBtaWxsaXNlY29uZHMgZm9yIGRlc3Ryb3lpbmcgYSByZXNvdXJjZScsXHJcbiAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICB0eXBlOiAnbnVtYmVyJ1xyXG4gICAgICB9XHJcbiAgICB9LFxyXG4gICAgaWRsZVRpbWVvdXQ6IHtcclxuICAgICAgdmFsdWU6IDMwMDAwLFxyXG4gICAgICB0eXBlczogWydudW1iZXInXSxcclxuICAgICAgZW52TGluazogJ1BPT0xfSURMRV9USU1FT1VUJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdUaW1lb3V0IGluIG1pbGxpc2Vjb25kcyBmb3IgZGVzdHJveWluZyBpZGxlIHJlc291cmNlcycsXHJcbiAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICB0eXBlOiAnbnVtYmVyJ1xyXG4gICAgICB9XHJcbiAgICB9LFxyXG4gICAgY3JlYXRlUmV0cnlJbnRlcnZhbDoge1xyXG4gICAgICB2YWx1ZTogMjAwLFxyXG4gICAgICB0eXBlczogWydudW1iZXInXSxcclxuICAgICAgZW52TGluazogJ1BPT0xfQ1JFQVRFX1JFVFJZX0lOVEVSVkFMJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ0ludGVydmFsIGluIG1pbGxpc2Vjb25kcyBiZWZvcmUgcmV0cnlpbmcgcmVzb3VyY2UgY3JlYXRpb24gb24gZmFpbHVyZScsXHJcbiAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICB0eXBlOiAnbnVtYmVyJ1xyXG4gICAgICB9XHJcbiAgICB9LFxyXG4gICAgcmVhcGVySW50ZXJ2YWw6IHtcclxuICAgICAgdmFsdWU6IDEwMDAsXHJcbiAgICAgIHR5cGVzOiBbJ251bWJlciddLFxyXG4gICAgICBlbnZMaW5rOiAnUE9PTF9SRUFQRVJfSU5URVJWQUwnLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnSW50ZXJ2YWwgaW4gbWlsbGlzZWNvbmRzIHRvIGNoZWNrIGFuZCBkZXN0cm95IGlkbGUgcmVzb3VyY2VzJyxcclxuICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgIHR5cGU6ICdudW1iZXInXHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICBiZW5jaG1hcmtpbmc6IHtcclxuICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICB0eXBlczogWydib29sZWFuJ10sXHJcbiAgICAgIGVudkxpbms6ICdQT09MX0JFTkNITUFSS0lORycsXHJcbiAgICAgIGNsaU5hbWU6ICdwb29sQmVuY2htYXJraW5nJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdTaG93cyBzdGF0aXN0aWNzIGZvciB0aGUgcG9vbCBvZiByZXNvdXJjZXMnLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ3RvZ2dsZSdcclxuICAgICAgfVxyXG4gICAgfVxyXG4gIH0sXHJcbiAgbG9nZ2luZzoge1xyXG4gICAgbGV2ZWw6IHtcclxuICAgICAgdmFsdWU6IDQsXHJcbiAgICAgIHR5cGVzOiBbJ251bWJlciddLFxyXG4gICAgICBlbnZMaW5rOiAnTE9HR0lOR19MRVZFTCcsXHJcbiAgICAgIGNsaU5hbWU6ICdsb2dMZXZlbCcsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnTG9nZ2luZyB2ZXJib3NpdHkgbGV2ZWwnLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgICAgcm91bmQ6IDAsXHJcbiAgICAgICAgbWluOiAwLFxyXG4gICAgICAgIG1heDogNVxyXG4gICAgICB9XHJcbiAgICB9LFxyXG4gICAgZmlsZToge1xyXG4gICAgICB2YWx1ZTogJ2hpZ2hjaGFydHMtZXhwb3J0LXNlcnZlci5sb2cnLFxyXG4gICAgICB0eXBlczogWydzdHJpbmcnXSxcclxuICAgICAgZW52TGluazogJ0xPR0dJTkdfRklMRScsXHJcbiAgICAgIGNsaU5hbWU6ICdsb2dGaWxlJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ0xvZyBmaWxlIG5hbWUuIFJlcXVpcmVzIGBsb2dUb0ZpbGVgIGFuZCBgbG9nRGVzdGAgdG8gYmUgc2V0JyxcclxuICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgIHR5cGU6ICd0ZXh0J1xyXG4gICAgICB9XHJcbiAgICB9LFxyXG4gICAgZGVzdDoge1xyXG4gICAgICB2YWx1ZTogJ2xvZycsXHJcbiAgICAgIHR5cGVzOiBbJ3N0cmluZyddLFxyXG4gICAgICBlbnZMaW5rOiAnTE9HR0lOR19ERVNUJyxcclxuICAgICAgY2xpTmFtZTogJ2xvZ0Rlc3QnLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ1BhdGggdG8gc3RvcmUgbG9nIGZpbGVzLiBSZXF1aXJlcyBgbG9nVG9GaWxlYCB0byBiZSBzZXQnLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ3RleHQnXHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICB0b0NvbnNvbGU6IHtcclxuICAgICAgdmFsdWU6IHRydWUsXHJcbiAgICAgIHR5cGVzOiBbJ2Jvb2xlYW4nXSxcclxuICAgICAgZW52TGluazogJ0xPR0dJTkdfVE9fQ09OU09MRScsXHJcbiAgICAgIGNsaU5hbWU6ICdsb2dUb0NvbnNvbGUnLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ0VuYWJsZXMgb3IgZGlzYWJsZXMgY29uc29sZSBsb2dnaW5nJyxcclxuICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgIHR5cGU6ICd0b2dnbGUnXHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICB0b0ZpbGU6IHtcclxuICAgICAgdmFsdWU6IHRydWUsXHJcbiAgICAgIHR5cGVzOiBbJ2Jvb2xlYW4nXSxcclxuICAgICAgZW52TGluazogJ0xPR0dJTkdfVE9fRklMRScsXHJcbiAgICAgIGNsaU5hbWU6ICdsb2dUb0ZpbGUnLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ0VuYWJsZXMgb3IgZGlzYWJsZXMgbG9nZ2luZyB0byBhIGZpbGUnLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ3RvZ2dsZSdcclxuICAgICAgfVxyXG4gICAgfVxyXG4gIH0sXHJcbiAgdWk6IHtcclxuICAgIGVuYWJsZToge1xyXG4gICAgICB2YWx1ZTogZmFsc2UsXHJcbiAgICAgIHR5cGVzOiBbJ2Jvb2xlYW4nXSxcclxuICAgICAgZW52TGluazogJ1VJX0VOQUJMRScsXHJcbiAgICAgIGNsaU5hbWU6ICdlbmFibGVVaScsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnRW5hYmxlcyBvciBkaXNhYmxlcyB0aGUgVUkgZm9yIHRoZSBleHBvcnQgc2VydmVyJyxcclxuICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgIHR5cGU6ICd0b2dnbGUnXHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICByb3V0ZToge1xyXG4gICAgICB2YWx1ZTogJy8nLFxyXG4gICAgICB0eXBlczogWydzdHJpbmcnXSxcclxuICAgICAgZW52TGluazogJ1VJX1JPVVRFJyxcclxuICAgICAgY2xpTmFtZTogJ3VpUm91dGUnLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ1RoZSBlbmRwb2ludCByb3V0ZSBmb3IgdGhlIFVJJyxcclxuICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgIHR5cGU6ICd0ZXh0J1xyXG4gICAgICB9XHJcbiAgICB9XHJcbiAgfSxcclxuICBvdGhlcjoge1xyXG4gICAgbm9kZUVudjoge1xyXG4gICAgICB2YWx1ZTogJ3Byb2R1Y3Rpb24nLFxyXG4gICAgICB0eXBlczogWydzdHJpbmcnXSxcclxuICAgICAgZW52TGluazogJ09USEVSX05PREVfRU5WJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdUaGUgTm9kZS5qcyBlbnZpcm9ubWVudCB0eXBlJyxcclxuICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgIHR5cGU6ICd0ZXh0J1xyXG4gICAgICB9XHJcbiAgICB9LFxyXG4gICAgbGlzdGVuVG9Qcm9jZXNzRXhpdHM6IHtcclxuICAgICAgdmFsdWU6IHRydWUsXHJcbiAgICAgIHR5cGVzOiBbJ2Jvb2xlYW4nXSxcclxuICAgICAgZW52TGluazogJ09USEVSX0xJU1RFTl9UT19QUk9DRVNTX0VYSVRTJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdXaGV0aGVyIG9yIG5vdCB0byBhdHRhY2ggcHJvY2Vzcy5leGl0IGhhbmRsZXJzJyxcclxuICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgIHR5cGU6ICd0b2dnbGUnXHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICBub0xvZ286IHtcclxuICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICB0eXBlczogWydib29sZWFuJ10sXHJcbiAgICAgIGVudkxpbms6ICdPVEhFUl9OT19MT0dPJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdEaXNwbGF5IG9yIHNraXAgcHJpbnRpbmcgdGhlIGxvZ28gb24gc3RhcnR1cCcsXHJcbiAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICB0eXBlOiAndG9nZ2xlJ1xyXG4gICAgICB9XHJcbiAgICB9LFxyXG4gICAgaGFyZFJlc2V0UGFnZToge1xyXG4gICAgICB2YWx1ZTogZmFsc2UsXHJcbiAgICAgIHR5cGVzOiBbJ2Jvb2xlYW4nXSxcclxuICAgICAgZW52TGluazogJ09USEVSX0hBUkRfUkVTRVRfUEFHRScsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnV2hldGhlciBvciBub3QgdG8gcmVzZXQgdGhlIHBhZ2UgY29udGVudCBlbnRpcmVseScsXHJcbiAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICB0eXBlOiAndG9nZ2xlJ1xyXG4gICAgICB9XHJcbiAgICB9LFxyXG4gICAgYnJvd3NlclNoZWxsTW9kZToge1xyXG4gICAgICB2YWx1ZTogdHJ1ZSxcclxuICAgICAgdHlwZXM6IFsnYm9vbGVhbiddLFxyXG4gICAgICBlbnZMaW5rOiAnT1RIRVJfQlJPV1NFUl9TSEVMTF9NT0RFJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdXaGV0aGVyIG9yIG5vdCB0byBzZXQgdGhlIGJyb3dzZXIgdG8gcnVuIGluIHNoZWxsIG1vZGUnLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ3RvZ2dsZSdcclxuICAgICAgfVxyXG4gICAgfSxcclxuICAgIHZhbGlkYXRpb246IHtcclxuICAgICAgdmFsdWU6IHRydWUsXHJcbiAgICAgIHR5cGVzOiBbJ2Jvb2xlYW4nXSxcclxuICAgICAgZW52TGluazogJ09USEVSX1ZBTElEQVRJT04nLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ1doZXRoZXIgb3Igbm90IHRvIGVuYWJsZSB2YWxpZGF0aW9uIG9mIG9wdGlvbnMgdHlwZXMnLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ3RvZ2dsZSdcclxuICAgICAgfVxyXG4gICAgfVxyXG4gIH0sXHJcbiAgZGVidWc6IHtcclxuICAgIGVuYWJsZToge1xyXG4gICAgICB2YWx1ZTogZmFsc2UsXHJcbiAgICAgIHR5cGVzOiBbJ2Jvb2xlYW4nXSxcclxuICAgICAgZW52TGluazogJ0RFQlVHX0VOQUJMRScsXHJcbiAgICAgIGNsaU5hbWU6ICdlbmFibGVEZWJ1ZycsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnRW5hYmxlcyBvciBkaXNhYmxlcyBkZWJ1ZyBtb2RlIGZvciB0aGUgdW5kZXJseWluZyBicm93c2VyJyxcclxuICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgIHR5cGU6ICd0b2dnbGUnXHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICBoZWFkbGVzczoge1xyXG4gICAgICB2YWx1ZTogZmFsc2UsXHJcbiAgICAgIHR5cGVzOiBbJ2Jvb2xlYW4nXSxcclxuICAgICAgZW52TGluazogJ0RFQlVHX0hFQURMRVNTJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ1doZXRoZXIgb3Igbm90IHRvIHNldCB0aGUgYnJvd3NlciB0byBydW4gaW4gaGVhZGxlc3MgbW9kZSBkdXJpbmcgZGVidWdnaW5nJyxcclxuICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgIHR5cGU6ICd0b2dnbGUnXHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICBkZXZ0b29sczoge1xyXG4gICAgICB2YWx1ZTogZmFsc2UsXHJcbiAgICAgIHR5cGVzOiBbJ2Jvb2xlYW4nXSxcclxuICAgICAgZW52TGluazogJ0RFQlVHX0RFVlRPT0xTJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdFbmFibGVzIG9yIGRpc2FibGVzIERldlRvb2xzIGluIGhlYWRmdWwgbW9kZScsXHJcbiAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICB0eXBlOiAndG9nZ2xlJ1xyXG4gICAgICB9XHJcbiAgICB9LFxyXG4gICAgbGlzdGVuVG9Db25zb2xlOiB7XHJcbiAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgdHlwZXM6IFsnYm9vbGVhbiddLFxyXG4gICAgICBlbnZMaW5rOiAnREVCVUdfTElTVEVOX1RPX0NPTlNPTEUnLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnRW5hYmxlcyBvciBkaXNhYmxlcyBsaXN0ZW5pbmcgdG8gY29uc29sZSBtZXNzYWdlcyBmcm9tIHRoZSBicm93c2VyJyxcclxuICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgIHR5cGU6ICd0b2dnbGUnXHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICBkdW1waW86IHtcclxuICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICB0eXBlczogWydib29sZWFuJ10sXHJcbiAgICAgIGVudkxpbms6ICdERUJVR19EVU1QSU8nLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnUmVkaXJlY3RzIG9yIG5vdCBicm93c2VyIHN0ZG91dCBhbmQgc3RkZXJyIHRvIHByb2Nlc3Muc3Rkb3V0IGFuZCBwcm9jZXNzLnN0ZGVycicsXHJcbiAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICB0eXBlOiAndG9nZ2xlJ1xyXG4gICAgICB9XHJcbiAgICB9LFxyXG4gICAgc2xvd01vOiB7XHJcbiAgICAgIHZhbHVlOiAwLFxyXG4gICAgICB0eXBlczogWydudW1iZXInXSxcclxuICAgICAgZW52TGluazogJ0RFQlVHX1NMT1dfTU8nLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ0RlbGF5cyBQdXBwZXRlZXIgb3BlcmF0aW9ucyBieSB0aGUgc3BlY2lmaWVkIG1pbGxpc2Vjb25kcycsXHJcbiAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICB0eXBlOiAnbnVtYmVyJ1xyXG4gICAgICB9XHJcbiAgICB9LFxyXG4gICAgZGVidWdnaW5nUG9ydDoge1xyXG4gICAgICB2YWx1ZTogOTIyMixcclxuICAgICAgdHlwZXM6IFsnbnVtYmVyJ10sXHJcbiAgICAgIGVudkxpbms6ICdERUJVR19ERUJVR0dJTkdfUE9SVCcsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnUG9ydCB1c2VkIGZvciBkZWJ1Z2dpbmcnLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ251bWJlcidcclxuICAgICAgfVxyXG4gICAgfVxyXG4gIH1cclxufTtcclxuXHJcbi8vIFByb3BlcnRpZXMgbmVzdGluZyBsZXZlbCBvZiBhbGwgb3B0aW9uc1xyXG5leHBvcnQgY29uc3QgbmVzdGVkUHJvcHMgPSBfY3JlYXRlTmVzdGVkUHJvcHMoZGVmYXVsdENvbmZpZyk7XHJcblxyXG4vLyBQcm9wZXJ0aWVzIG5hbWVzIHRoYXQgc2hvdWxkIG5vdCBiZSByZWN1cnNpdmVseSBtZXJnZWRcclxuZXhwb3J0IGNvbnN0IGFic29sdXRlUHJvcHMgPSBfY3JlYXRlQWJzb2x1dGVQcm9wcyhkZWZhdWx0Q29uZmlnKTtcclxuXHJcbi8qKlxyXG4gKiBSZWN1cnNpdmVseSBnZW5lcmF0ZXMgYSBtYXBwaW5nIG9mIG5lc3RlZCBhcmd1bWVudCBjaGFpbnMgZnJvbSBhIG5lc3RlZFxyXG4gKiBjb25maWcgb2JqZWN0LiBUaGlzIGZ1bmN0aW9uIHRyYXZlcnNlcyBhIG5lc3RlZCBvYmplY3QgYW5kIGNyZWF0ZXMgYSBtYXBwaW5nXHJcbiAqIHdoZXJlIGVhY2gga2V5IGlzIGFuIGFyZ3VtZW50IG5hbWUgKGVpdGhlciBmcm9tIGBjbGlOYW1lYCwgYGxlZ2FjeU5hbWVgLFxyXG4gKiBvciB0aGUgb3JpZ2luYWwga2V5KSBhbmQgZWFjaCB2YWx1ZSBpcyBhIHN0cmluZyByZXByZXNlbnRpbmcgdGhlIGNoYWluXHJcbiAqIG9mIG5lc3RlZCBwcm9wZXJ0aWVzIGxlYWRpbmcgdG8gdGhhdCBhcmd1bWVudC5cclxuICpcclxuICogQGZ1bmN0aW9uIF9jcmVhdGVOZXN0ZWRQcm9wc1xyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gY29uZmlnIC0gVGhlIGNvbmZpZ3VyYXRpb24gb2JqZWN0LlxyXG4gKiBAcGFyYW0ge09iamVjdH0gW25lc3RlZFByb3BzPXt9XSAtIFRoZSBhY2N1bXVsYXRvciBvYmplY3QgZm9yIHN0b3JpbmdcclxuICogdGhlIHJlc3VsdGluZyBhcmd1bWVudHMgY2hhaW5zLiAgVGhlIGRlZmF1bHQgdmFsdWUgaXMgYW4gZW1wdHkgb2JqZWN0LlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gW3Byb3BDaGFpbj0nJ10gLSBUaGUgY3VycmVudCBjaGFpbiBvZiBuZXN0ZWQgcHJvcGVydGllcyxcclxuICogdXNlZCBpbnRlcm5hbGx5IGR1cmluZyByZWN1cnNpb24uICBUaGUgZGVmYXVsdCB2YWx1ZSBpcyBhbiBlbXB0eSBzdHJpbmcuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtPYmplY3R9IEFuIG9iamVjdCBtYXBwaW5nIGFyZ3VtZW50IG5hbWVzIHRvIHRoZWlyIGNvcnJlc3BvbmRpbmdcclxuICogbmVzdGVkIHByb3BlcnR5IGNoYWlucy5cclxuICovXHJcbmZ1bmN0aW9uIF9jcmVhdGVOZXN0ZWRQcm9wcyhjb25maWcsIG5lc3RlZFByb3BzID0ge30sIHByb3BDaGFpbiA9ICcnKSB7XHJcbiAgT2JqZWN0LmtleXMoY29uZmlnKS5mb3JFYWNoKChrZXkpID0+IHtcclxuICAgIC8vIEdldCB0aGUgc3BlY2lmaWMgc2VjdGlvblxyXG4gICAgY29uc3QgZW50cnkgPSBjb25maWdba2V5XTtcclxuXHJcbiAgICAvLyBDaGVjayBpZiB0aGVyZSBpcyBzdGlsbCBtb3JlIGRlcHRoIHRvIHRyYXZlcnNlXHJcbiAgICBpZiAodHlwZW9mIGVudHJ5LnZhbHVlID09PSAndW5kZWZpbmVkJykge1xyXG4gICAgICAvLyBSZWN1cnNlIGludG8gZGVlcGVyIGxldmVscyBvZiBuZXN0ZWQgYXJndW1lbnRzXHJcbiAgICAgIF9jcmVhdGVOZXN0ZWRQcm9wcyhlbnRyeSwgbmVzdGVkUHJvcHMsIGAke3Byb3BDaGFpbn0uJHtrZXl9YCk7XHJcbiAgICB9IGVsc2Uge1xyXG4gICAgICAvLyBDcmVhdGUgdGhlIGNoYWluIG9mIG5lc3RlZCBhcmd1bWVudHNcclxuICAgICAgbmVzdGVkUHJvcHNbZW50cnkuY2xpTmFtZSB8fCBrZXldID0gYCR7cHJvcENoYWlufS4ke2tleX1gLnN1YnN0cmluZygxKTtcclxuXHJcbiAgICAgIC8vIFN1cHBvcnQgZm9yIHRoZSBsZWdhY3ksIFBoYW50b21KUyBwcm9wZXJ0aWVzIG5hbWVzXHJcbiAgICAgIGlmIChlbnRyeS5sZWdhY3lOYW1lICE9PSB1bmRlZmluZWQpIHtcclxuICAgICAgICBuZXN0ZWRQcm9wc1tlbnRyeS5sZWdhY3lOYW1lXSA9IGAke3Byb3BDaGFpbn0uJHtrZXl9YC5zdWJzdHJpbmcoMSk7XHJcbiAgICAgIH1cclxuICAgIH1cclxuICB9KTtcclxuXHJcbiAgLy8gUmV0dXJuIHRoZSBvYmplY3Qgd2l0aCBuZXN0ZWQgYXJndW1lbnQgY2hhaW5zXHJcbiAgcmV0dXJuIG5lc3RlZFByb3BzO1xyXG59XHJcblxyXG4vKipcclxuICogUmVjdXJzaXZlbHkgZ2F0aGVycyB0aGUgbmFtZXMgb2YgcHJvcGVydGllcyBmcm9tIGEgY29uZmlndXJhdGlvbiBvYmplY3QgdGhhdFxyXG4gKiBjYW4gYmUgdHJlYXRlZCBhcyBhYnNvbHV0ZSBwcm9wZXJ0aWVzLiBUaGVzZSBwcm9wZXJ0aWVzIGhhdmUgdmFsdWVzIHRoYXRcclxuICogYXJlIG9iamVjdHMgYW5kIGRvIG5vdCBjb250YWluIGZ1cnRoZXIgbmVzdGVkIGRlcHRoIHdoZW4gbWVyZ2luZyBhbiBvYmplY3RcclxuICogY29udGFpbmluZyB0aGVzZSBvcHRpb25zLlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gX2NyZWF0ZUFic29sdXRlUHJvcHNcclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IGNvbmZpZyAtIFRoZSBjb25maWd1cmF0aW9uIG9iamVjdC5cclxuICogQHBhcmFtIHtBcnJheS48c3RyaW5nPn0gW2Fic29sdXRlUHJvcHM9W11dIC0gQW4gYXJyYXkgdG8gY29sbGVjdCB0aGUgbmFtZXNcclxuICogb2YgYWJzb2x1dGUgcHJvcGVydGllcy4gVGhlIGRlZmF1bHQgdmFsdWUgaXMgYW4gZW1wdHkgYXJyYXkuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtBcnJheS48c3RyaW5nPn0gQW4gYXJyYXkgY29udGFpbmluZyB0aGUgbmFtZXMgb2YgYWJzb2x1dGVcclxuICogcHJvcGVydGllcy5cclxuICovXHJcbmZ1bmN0aW9uIF9jcmVhdGVBYnNvbHV0ZVByb3BzKGNvbmZpZywgYWJzb2x1dGVQcm9wcyA9IFtdKSB7XHJcbiAgT2JqZWN0LmtleXMoY29uZmlnKS5mb3JFYWNoKChrZXkpID0+IHtcclxuICAgIC8vIEdldCB0aGUgc3BlY2lmaWMgc2VjdGlvblxyXG4gICAgY29uc3QgZW50cnkgPSBjb25maWdba2V5XTtcclxuXHJcbiAgICAvLyBDaGVjayBpZiB0aGVyZSBpcyBzdGlsbCBtb3JlIGRlcHRoIHRvIHRyYXZlcnNlXHJcbiAgICBpZiAodHlwZW9mIGVudHJ5LnR5cGVzID09PSAndW5kZWZpbmVkJykge1xyXG4gICAgICAvLyBSZWN1cnNlIGludG8gZGVlcGVyIGxldmVsc1xyXG4gICAgICBfY3JlYXRlQWJzb2x1dGVQcm9wcyhlbnRyeSwgYWJzb2x1dGVQcm9wcyk7XHJcbiAgICB9IGVsc2Uge1xyXG4gICAgICAvLyBJZiB0aGUgb3B0aW9uIGNhbiBiZSBhbiBvYmplY3QsIHNhdmUgaXRzIHR5cGUgaW4gdGhlIGFycmF5XHJcbiAgICAgIGlmIChlbnRyeS50eXBlcy5pbmNsdWRlcygnT2JqZWN0JykpIHtcclxuICAgICAgICBhYnNvbHV0ZVByb3BzLnB1c2goa2V5KTtcclxuICAgICAgfVxyXG4gICAgfVxyXG4gIH0pO1xyXG5cclxuICAvLyBSZXR1cm4gdGhlIGFycmF5IHdpdGggdGhlIG5hbWVzIG9mIGFic29sdXRlIHByb3BlcnRpZXNcclxuICByZXR1cm4gYWJzb2x1dGVQcm9wcztcclxufVxyXG5cclxuZXhwb3J0IGRlZmF1bHQge1xyXG4gIGRlZmF1bHRDb25maWcsXHJcbiAgbmVzdGVkUHJvcHMsXHJcbiAgYWJzb2x1dGVQcm9wc1xyXG59O1xyXG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxyXG5cclxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXHJcblxyXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNSwgSGlnaHNvZnRcclxuXHJcbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cclxuXHJcbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxyXG5cclxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxyXG5cclxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cclxuXHJcbi8qKlxyXG4gKiBAb3ZlcnZpZXcgVGhpcyBmaWxlIGhhbmRsZXMgcGFyc2luZyBhbmQgdmFsaWRhdGluZyBvcHRpb25zIGZyb20gbXVsdGlwbGVcclxuICogc291cmNlcyAodGhlIGNvbmZpZyBmaWxlLCBjdXN0b20gSlNPTiwgZW52aXJvbm1lbnQgdmFyaWFibGVzLCBDTEkgYXJndW1lbnRzLFxyXG4gKiBhbmQgcmVxdWVzdCBwYXlsb2FkKSB1c2luZyB0aGUgJ3pvZCcgbGlicmFyeS5cclxuICpcclxuICogRW52aXJvbm1lbnQgdmFyaWFibGVzIGFyZSBwYXJzZWQgYW5kIHZhbGlkYXRlZCBvbmx5IG9uY2UgYXQgYXBwbGljYXRpb25cclxuICogc3RhcnR1cCwgYW5kIHRoZSB2YWxpZGF0ZWQgcmVzdWx0cyBhcmUgZXhwb3J0ZWQgYXMgYGVudnNgIGZvciB1c2UgdGhyb3VnaG91dFxyXG4gKiB0aGUgYXBwbGljYXRpb24uXHJcbiAqXHJcbiAqIE9wdGlvbnMgZnJvbSBvdGhlciBzb3VyY2VzLCBob3dldmVyLCBhcmUgcGFyc2VkIGFuZCB2YWxpZGF0ZWQgb24gZGVtYW5kLFxyXG4gKiBlYWNoIHRpbWUgYW4gZXhwb3J0IGlzIGF0dGVtcHRlZC5cclxuICovXHJcblxyXG5pbXBvcnQgZG90ZW52IGZyb20gJ2RvdGVudic7XHJcbmltcG9ydCB7IHogfSBmcm9tICd6b2QnO1xyXG5cclxuaW1wb3J0IHsgZGVmYXVsdENvbmZpZyB9IGZyb20gJy4vc2NoZW1hcy9jb25maWcuanMnO1xyXG5cclxuLy8gTG9hZCB0aGUgLmVudiBpbnRvIGVudmlyb25tZW50IHZhcmlhYmxlc1xyXG5kb3RlbnYuY29uZmlnKCk7XHJcblxyXG4vLyBHZXQgc2NyaXB0cyBuYW1lcyBvZiBlYWNoIGNhdGVnb3J5IGZyb20gdGhlIGRlZmF1bHQgY29uZmlnXHJcbmNvbnN0IHsgY29yZVNjcmlwdHMsIG1vZHVsZVNjcmlwdHMsIGluZGljYXRvclNjcmlwdHMgfSA9XHJcbiAgZGVmYXVsdENvbmZpZy5oaWdoY2hhcnRzO1xyXG5cclxuLy8gU2V0cyB0aGUgY3VzdG9tIGVycm9yIG1hcCBnbG9iYWxseVxyXG56LnNldEVycm9yTWFwKF9jdXN0b21FcnJvck1hcCk7XHJcblxyXG4vKipcclxuICogT2JqZWN0IGNvbnRhaW5pbmcgY3VzdG9tIGdlbmVyYWwgdmFsaWRhdG9ycyBhbmQgcGFyc2VycyB0byBhdm9pZCByZXBldGl0aW9uXHJcbiAqIGluIHNjaGVtYSBvYmplY3RzLiBBbGwgdmFsaWRhdG9ycyBhcHBseSB0byB2YWx1ZXMgZnJvbSB2YXJpb3VzIHNvdXJjZXMsXHJcbiAqIGluY2x1ZGluZyB0aGUgZGVmYXVsdCBjb25maWcgZmlsZSwgYSBjdXN0b20gSlNPTiBmaWxlIGxvYWRlZCB3aXRoIHRoZSBvcHRpb25cclxuICogY2FsbGVkIGBsb2FkQ29uZmlnYCwgdGhlIC5lbnYgZmlsZSwgQ0xJIGFyZ3VtZW50cywgYW5kIHRoZSByZXF1ZXN0IHBheWxvYWQuXHJcbiAqIFRoZSBgc3RyaWN0Q2hlY2tgIGZsYWcgZW5hYmxlcyBzdHJpY3RlciB2YWxpZGF0aW9uIGFuZCBwYXJzaW5nIHJ1bGVzLiBUaGlzXHJcbiAqIGZsYWcgaXMgc2V0IHRvIGZhbHNlIGZvciB2YWx1ZXMgdGhhdCBjb21lIGZyb20gdGhlIC5lbnYgZmlsZSBvciBDTEkgYXJndW1lbnRzXHJcbiAqIGJlY2F1c2UgdGhleSBhcmUgcHJvdmlkZWQgYXMgc3RyaW5ncyBhbmQgbmVlZCB0byBiZSBwYXJzZWQgYWNjb3JkaW5nbHkgZmlyc3QuXHJcbiAqL1xyXG5jb25zdCB2ID0ge1xyXG4gIC8qKlxyXG4gICAqIFRoZSBgYm9vbGVhbmAgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbCBzdHJpY3RlclxyXG4gICAqIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoYXQ6XHJcbiAgICpcclxuICAgKiAtIFdoZW4gYHN0cmljdENoZWNrYCBpcyB0cnVlLCB0aGUgc2NoZW1hIHdpbGwgYWNjZXB0IHZhbHVlcyBhcmUgdHJ1ZVxyXG4gICAqIGFuZCBmYWxzZSBhbmQgdGhlIHNjaGVtYSB3aWxsIHZhbGlkYXRlIGFnYWluc3QgdGhlIGRlZmF1bHQgYm9vbGVhblxyXG4gICAqIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIC0gV2hlbiBgc3RyaWN0Q2hlY2tgIGlzIGZhbHNlLCB0aGUgc2NoZW1hIHdpbGwgYWNjZXB0IHZhbHVlcyBhcmUgdHJ1ZSxcclxuICAgKiBmYWxzZSwgbnVsbCwgJ3RydWUnLCAnMScsICdmYWxzZScsICcwJywgJ3VuZGVmaW5lZCcsICdudWxsJywgYW5kICcnLlxyXG4gICAqIFRoZSBzdHJpbmdzICd1bmRlZmluZWQnLCAnbnVsbCcsIGFuZCAnJyB3aWxsIGJlIHRyYW5zZm9ybWVkIHRvIG51bGwsXHJcbiAgICogdGhlIHN0cmluZyAndHJ1ZScgd2lsbCBiZSB0cmFuc2Zvcm1lZCB0byB0aGUgYm9vbGVhbiB2YWx1ZSB0cnVlLFxyXG4gICAqIGFuZCAnZmFsc2UnIHdpbGwgYmUgdHJhbnNmb3JtZWQgdG8gdGhlIGJvb2xlYW4gdmFsdWUgZmFsc2UuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gYm9vbGVhblxyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nIGJvb2xlYW4gdmFsdWVzLlxyXG4gICAqL1xyXG4gIGJvb2xlYW4oc3RyaWN0Q2hlY2spIHtcclxuICAgIHJldHVybiBzdHJpY3RDaGVja1xyXG4gICAgICA/IHouYm9vbGVhbigpXHJcbiAgICAgIDogelxyXG4gICAgICAgICAgLnVuaW9uKFtcclxuICAgICAgICAgICAgelxyXG4gICAgICAgICAgICAgIC5lbnVtKFsndHJ1ZScsICcxJywgJ2ZhbHNlJywgJzAnLCAndW5kZWZpbmVkJywgJ251bGwnLCAnJ10pXHJcbiAgICAgICAgICAgICAgLnRyYW5zZm9ybSgodmFsdWUpID0+XHJcbiAgICAgICAgICAgICAgICAhWyd1bmRlZmluZWQnLCAnbnVsbCcsICcnXS5pbmNsdWRlcyh2YWx1ZSlcclxuICAgICAgICAgICAgICAgICAgPyB2YWx1ZSA9PT0gJ3RydWUnIHx8IHZhbHVlID09PSAnMSdcclxuICAgICAgICAgICAgICAgICAgOiBudWxsXHJcbiAgICAgICAgICAgICAgKSxcclxuICAgICAgICAgICAgei5ib29sZWFuKClcclxuICAgICAgICAgIF0pXHJcbiAgICAgICAgICAubnVsbGFibGUoKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYHN0cmluZ2AgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbCBzdHJpY3RlclxyXG4gICAqIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoYXQ6XHJcbiAgICpcclxuICAgKiAtIFdoZW4gYHN0cmljdENoZWNrYCBpcyB0cnVlLCB0aGUgc2NoZW1hIHdpbGwgYWNjZXB0IHRyaW1tZWQgc3RyaW5ncyBleGNlcHRcclxuICAgKiB0aGUgZm9yYmlkZGVuIHZhbHVlczogJ2ZhbHNlJywgJ3VuZGVmaW5lZCcsICdudWxsJywgYW5kICcnLlxyXG4gICAqXHJcbiAgICogLSBXaGVuIGBzdHJpY3RDaGVja2AgaXMgZmFsc2UsIHRoZSBzY2hlbWEgd2lsbCBhY2NlcHQgdHJpbW1lZCBzdHJpbmdzXHJcbiAgICogYW5kIG51bGwuIFRoZSBmb3JiaWRkZW4gdmFsdWVzOiAnZmFsc2UnLCAndW5kZWZpbmVkJywgJ251bGwnLCBhbmQgJycgd2lsbFxyXG4gICAqIGJlIHRyYW5zZm9ybWVkIHRvIG51bGwuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gc3RyaW5nXHJcbiAgICpcclxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IHN0cmljdENoZWNrIC0gRGV0ZXJtaW5lcyBpZiBzdHJpY3RlciB2YWxpZGF0aW9uIHNob3VsZFxyXG4gICAqIGJlIGFwcGxpZWQuXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9IEEgWm9kIHNjaGVtYSBvYmplY3QgZm9yIHZhbGlkYXRpbmcgc3RyaW5nIHZhbHVlcy5cclxuICAgKi9cclxuICBzdHJpbmcoc3RyaWN0Q2hlY2spIHtcclxuICAgIHJldHVybiBzdHJpY3RDaGVja1xyXG4gICAgICA/IHpcclxuICAgICAgICAgIC5zdHJpbmcoKVxyXG4gICAgICAgICAgLnRyaW0oKVxyXG4gICAgICAgICAgLnJlZmluZShcclxuICAgICAgICAgICAgKHZhbHVlKSA9PiAhWydmYWxzZScsICd1bmRlZmluZWQnLCAnbnVsbCcsICcnXS5pbmNsdWRlcyh2YWx1ZSksXHJcbiAgICAgICAgICAgIHtcclxuICAgICAgICAgICAgICBwYXJhbXM6IHtcclxuICAgICAgICAgICAgICAgIGVycm9yTWVzc2FnZTogJ1RoZSBzdHJpbmcgY29udGFpbnMgYSBmb3JiaWRkZW4gdmFsdWUnXHJcbiAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICB9XHJcbiAgICAgICAgICApXHJcbiAgICAgIDogelxyXG4gICAgICAgICAgLnN0cmluZygpXHJcbiAgICAgICAgICAudHJpbSgpXHJcbiAgICAgICAgICAudHJhbnNmb3JtKCh2YWx1ZSkgPT5cclxuICAgICAgICAgICAgIVsnZmFsc2UnLCAndW5kZWZpbmVkJywgJ251bGwnLCAnJ10uaW5jbHVkZXModmFsdWUpID8gdmFsdWUgOiBudWxsXHJcbiAgICAgICAgICApXHJcbiAgICAgICAgICAubnVsbGFibGUoKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYGVudW1gIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGggYW4gb3B0aW9uYWwgc3RyaWN0ZXJcclxuICAgKiBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgc2NoZW1hIHdpbGwgdmFsaWRhdGUgYWdhaW5zdCB0aGUgcHJvdmlkZWQgYHZhbHVlc2AgYXJyYXkuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGF0OlxyXG4gICAqXHJcbiAgICogLSBXaGVuIGBzdHJpY3RDaGVja2AgaXMgdHJ1ZSwgdGhlIHNjaGVtYSB3aWxsIHZhbGlkYXRlIGFnYWluc3QgdGhlIGB2YWx1ZXNgXHJcbiAgICogYXJyYXkgd2l0aCB0aGUgZGVmYXVsdCBlbnVtIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIC0gV2hlbiBgc3RyaWN0Q2hlY2tgIGlzIGZhbHNlLCB0aGUgc2NoZW1hIHdpbGwgYWNjZXB0IGFsc28gbnVsbCxcclxuICAgKiAndW5kZWZpbmVkJywgJ251bGwnLCBhbmQgJycsIHdoaWNoIHdpbGwgYmUgdHJhbnNmb3JtZWQgdG8gbnVsbC5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiBlbnVtXHJcbiAgICpcclxuICAgKiBAcGFyYW0ge0FycmF5LjxzdHJpbmc+fSB2YWx1ZXMgLSBBbiBhcnJheSBvZiB2YWxpZCBzdHJpbmcgdmFsdWVzXHJcbiAgICogZm9yIHRoZSBlbnVtLlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZyBlbnVtIHZhbHVlcy5cclxuICAgKi9cclxuICBlbnVtKHZhbHVlcywgc3RyaWN0Q2hlY2spIHtcclxuICAgIHJldHVybiBzdHJpY3RDaGVja1xyXG4gICAgICA/IHouZW51bShbLi4udmFsdWVzXSlcclxuICAgICAgOiB6XHJcbiAgICAgICAgICAuZW51bShbLi4udmFsdWVzLCAndW5kZWZpbmVkJywgJ251bGwnLCAnJ10pXHJcbiAgICAgICAgICAudHJhbnNmb3JtKCh2YWx1ZSkgPT5cclxuICAgICAgICAgICAgIVsndW5kZWZpbmVkJywgJ251bGwnLCAnJ10uaW5jbHVkZXModmFsdWUpID8gdmFsdWUgOiBudWxsXHJcbiAgICAgICAgICApXHJcbiAgICAgICAgICAubnVsbGFibGUoKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYHN0cmluZ0FycmF5YCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoIGFuIG9wdGlvbmFsXHJcbiAgICogc3RyaWN0ZXIgY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhhdDpcclxuICAgKlxyXG4gICAqIC0gV2hlbiBgc3RyaWN0Q2hlY2tgIGlzIHRydWUsIHRoZSBzY2hlbWEgd2lsbCBhY2NlcHQgYW4gYXJyYXkgb2YgdHJpbW1lZFxyXG4gICAqIHN0cmluZyB2YWx1ZXMgZmlsdGVyZWQgYnkgdGhlIGxvZ2ljIHByb3ZpZGVkIHRocm91Z2ggdGhlIGBmaWx0ZXJDYWxsYmFja2AuXHJcbiAgICpcclxuICAgKiAtIFdoZW4gYHN0cmljdENoZWNrYCBpcyBmYWxzZSwgdGhlIHNjaGVtYSB3aWxsIGFjY2VwdCBudWxsIGFuZCB0cmltbWVkXHJcbiAgICogc3RyaW5nIHZhbHVlcyB3aGljaCB3aWxsIGJlIHNwbGl0dGVkIGludG8gYW4gYXJyYXkgb2Ygc3RyaW5ncyBhbmQgZmlsdGVyZWRcclxuICAgKiBmcm9tIHRoZSAnWycgYW5kICddJyBjaGFyYWN0ZXJzIGFuZCBieSB0aGUgbG9naWMgcHJvdmlkZWQgdGhyb3VnaFxyXG4gICAqIHRoZSBgZmlsdGVyQ2FsbGJhY2tgLiBJZiB0aGUgYXJyYXkgaXMgZW1wdHksIGl0IHdpbGwgYmUgdHJhbnNmb3JtZWRcclxuICAgKiB0byBudWxsLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIHN0cmluZ0FycmF5XHJcbiAgICpcclxuICAgKiBAcGFyYW0ge2Z1bmN0aW9ufSBmaWx0ZXJDYWxsYmFjayAtIFRoZSBmaWx0ZXIgY2FsbGJhY2suXHJcbiAgICogQHBhcmFtIHtzdHJpbmd9IHNlcGFyYXRvciAtIFRoZSBzZXBhcmF0b3IgZm9yIHNwbGl0aW5nIGEgc3RyaW5nLlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZyBhcnJheSBvZiBzdHJpbmdcclxuICAgKiB2YWx1ZXMuXHJcbiAgICovXHJcbiAgc3RyaW5nQXJyYXkoZmlsdGVyQ2FsbGJhY2ssIHNlcGFyYXRvciwgc3RyaWN0Q2hlY2spIHtcclxuICAgIGNvbnN0IGFycmF5U2NoZW1hID0gei5zdHJpbmcoKS50cmltKCkuYXJyYXkoKTtcclxuICAgIGNvbnN0IHN0cmluZ1NjaGVtYSA9IHpcclxuICAgICAgLnN0cmluZygpXHJcbiAgICAgIC50cmltKClcclxuICAgICAgLnRyYW5zZm9ybSgodmFsdWUpID0+IHtcclxuICAgICAgICBpZiAodmFsdWUuc3RhcnRzV2l0aCgnWycpKSB7XHJcbiAgICAgICAgICB2YWx1ZSA9IHZhbHVlLnNsaWNlKDEpO1xyXG4gICAgICAgIH1cclxuICAgICAgICBpZiAodmFsdWUuZW5kc1dpdGgoJ10nKSkge1xyXG4gICAgICAgICAgdmFsdWUgPSB2YWx1ZS5zbGljZSgwLCAtMSk7XHJcbiAgICAgICAgfVxyXG4gICAgICAgIHJldHVybiB2YWx1ZS5zcGxpdChzZXBhcmF0b3IpO1xyXG4gICAgICB9KTtcclxuXHJcbiAgICBjb25zdCB0cmFuc2Zvcm1DYWxsYmFjayA9ICh2YWx1ZSkgPT5cclxuICAgICAgdmFsdWUubWFwKCh2YWx1ZSkgPT4gdmFsdWUudHJpbSgpKS5maWx0ZXIoZmlsdGVyQ2FsbGJhY2spO1xyXG5cclxuICAgIHJldHVybiBzdHJpY3RDaGVja1xyXG4gICAgICA/IGFycmF5U2NoZW1hLnRyYW5zZm9ybSh0cmFuc2Zvcm1DYWxsYmFjaylcclxuICAgICAgOiB6XHJcbiAgICAgICAgICAudW5pb24oW3N0cmluZ1NjaGVtYSwgYXJyYXlTY2hlbWFdKVxyXG4gICAgICAgICAgLnRyYW5zZm9ybSh0cmFuc2Zvcm1DYWxsYmFjaylcclxuICAgICAgICAgIC50cmFuc2Zvcm0oKHZhbHVlKSA9PiAodmFsdWUubGVuZ3RoID8gdmFsdWUgOiBudWxsKSlcclxuICAgICAgICAgIC5udWxsYWJsZSgpO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgcG9zaXRpdmVOdW1gIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGggYW4gb3B0aW9uYWxcclxuICAgKiBzdHJpY3RlciBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGF0OlxyXG4gICAqXHJcbiAgICogLSBXaGVuIGBzdHJpY3RDaGVja2AgaXMgdHJ1ZSwgdGhlIHNjaGVtYSB3aWxsIGFjY2VwdCBwb3NpdGl2ZSBudW1iZXIgdmFsdWVzXHJcbiAgICogYW5kIHZhbGlkYXRlIGFnYWluc3QgdGhlIGRlZmF1bHQgcG9zaXRpdmUgbnVtYmVyIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIC0gV2hlbiBgc3RyaWN0Q2hlY2tgIGlzIGZhbHNlLCB0aGUgc2NoZW1hIHdpbGwgYWNjZXB0IHBvc2l0aXZlIG51bWJlclxyXG4gICAqIHZhbHVlcywgbnVsbCwgYW5kIHRyaW1tZWQgc3RyaW5nIHZhbHVlcyB0aGF0IGNhbiBlaXRoZXIgYmUgJ3VuZGVmaW5lZCcsXHJcbiAgICogJ251bGwnLCAnJywgb3IgcmVwcmVzZW50IGEgcG9zaXRpdmUgbnVtYmVyLiBJdCB3aWxsIHRyYW5zZm9ybSB0aGUgc3RyaW5nXHJcbiAgICogdG8gYSBwb3NpdGl2ZSBudW1iZXIsIG9yIHRvIG51bGwgaWYgaXQgaXMgJ3VuZGVmaW5lZCcsICdudWxsJywgb3IgJycuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gcG9zaXRpdmVOdW1cclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZyBwb3NpdGl2ZSBudW1iZXJcclxuICAgKiB2YWx1ZXMuXHJcbiAgICovXHJcbiAgcG9zaXRpdmVOdW0oc3RyaWN0Q2hlY2spIHtcclxuICAgIHJldHVybiBzdHJpY3RDaGVja1xyXG4gICAgICA/IHoubnVtYmVyKCkucG9zaXRpdmUoKVxyXG4gICAgICA6IHpcclxuICAgICAgICAgIC51bmlvbihbXHJcbiAgICAgICAgICAgIHpcclxuICAgICAgICAgICAgICAuc3RyaW5nKClcclxuICAgICAgICAgICAgICAudHJpbSgpXHJcbiAgICAgICAgICAgICAgLnJlZmluZShcclxuICAgICAgICAgICAgICAgICh2YWx1ZSkgPT5cclxuICAgICAgICAgICAgICAgICAgKCFpc05hTihOdW1iZXIodmFsdWUpKSAmJiBOdW1iZXIodmFsdWUpID4gMCkgfHxcclxuICAgICAgICAgICAgICAgICAgWyd1bmRlZmluZWQnLCAnbnVsbCcsICcnXS5pbmNsdWRlcyh2YWx1ZSksXHJcbiAgICAgICAgICAgICAgICB7XHJcbiAgICAgICAgICAgICAgICAgIHBhcmFtczoge1xyXG4gICAgICAgICAgICAgICAgICAgIGVycm9yTWVzc2FnZTogJ1RoZSB2YWx1ZSBtdXN0IGJlIG51bWVyaWMgYW5kIHBvc2l0aXZlJ1xyXG4gICAgICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgICAgKVxyXG4gICAgICAgICAgICAgIC50cmFuc2Zvcm0oKHZhbHVlKSA9PlxyXG4gICAgICAgICAgICAgICAgIVsndW5kZWZpbmVkJywgJ251bGwnLCAnJ10uaW5jbHVkZXModmFsdWUpXHJcbiAgICAgICAgICAgICAgICAgID8gTnVtYmVyKHZhbHVlKVxyXG4gICAgICAgICAgICAgICAgICA6IG51bGxcclxuICAgICAgICAgICAgICApLFxyXG4gICAgICAgICAgICB6Lm51bWJlcigpLnBvc2l0aXZlKClcclxuICAgICAgICAgIF0pXHJcbiAgICAgICAgICAubnVsbGFibGUoKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYG5vbk5lZ2F0aXZlTnVtYCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoIGFuIG9wdGlvbmFsXHJcbiAgICogc3RyaWN0ZXIgY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhhdDpcclxuICAgKlxyXG4gICAqIC0gV2hlbiBgc3RyaWN0Q2hlY2tgIGlzIHRydWUsIHRoZSBzY2hlbWEgd2lsbCBhY2NlcHQgbm9uLW5lZ2F0aXZlIG51bWJlclxyXG4gICAqIHZhbHVlcyBhbmQgdmFsaWRhdGUgYWdhaW5zdCB0aGUgZGVmYXVsdCBub24tbmVnYXRpdmUgbnVtYmVyIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIC0gV2hlbiBgc3RyaWN0Q2hlY2tgIGlzIGZhbHNlLCB0aGUgc2NoZW1hIHdpbGwgYWNjZXB0IG5vbi1uZWdhdGl2ZSBudW1iZXJcclxuICAgKiB2YWx1ZXMsIG51bGwsIGFuZCB0cmltbWVkIHN0cmluZyB2YWx1ZXMgdGhhdCBjYW4gZWl0aGVyIGJlICd1bmRlZmluZWQnLFxyXG4gICAqICdudWxsJywgJycsIG9yIHJlcHJlc2VudCBhIG5vbi1uZWdhdGl2ZSBudW1iZXIuIEl0IHdpbGwgdHJhbnNmb3JtXHJcbiAgICogdGhlIHN0cmluZyB0byBhIG5vbi1uZWdhdGl2ZSBudW1iZXIsIG9yIHRvIG51bGwgaWYgaXQgaXMgJ3VuZGVmaW5lZCcsXHJcbiAgICogJ251bGwnLCBvciAnJy5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiBub25OZWdhdGl2ZU51bVxyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nIG5vbi1uZWdhdGl2ZVxyXG4gICAqIG51bWJlciB2YWx1ZXMuXHJcbiAgICovXHJcbiAgbm9uTmVnYXRpdmVOdW0oc3RyaWN0Q2hlY2spIHtcclxuICAgIHJldHVybiBzdHJpY3RDaGVja1xyXG4gICAgICA/IHoubnVtYmVyKCkubm9ubmVnYXRpdmUoKVxyXG4gICAgICA6IHpcclxuICAgICAgICAgIC51bmlvbihbXHJcbiAgICAgICAgICAgIHpcclxuICAgICAgICAgICAgICAuc3RyaW5nKClcclxuICAgICAgICAgICAgICAudHJpbSgpXHJcbiAgICAgICAgICAgICAgLnJlZmluZShcclxuICAgICAgICAgICAgICAgICh2YWx1ZSkgPT5cclxuICAgICAgICAgICAgICAgICAgKCFpc05hTihOdW1iZXIodmFsdWUpKSAmJiBOdW1iZXIodmFsdWUpID49IDApIHx8XHJcbiAgICAgICAgICAgICAgICAgIFsndW5kZWZpbmVkJywgJ251bGwnLCAnJ10uaW5jbHVkZXModmFsdWUpLFxyXG4gICAgICAgICAgICAgICAge1xyXG4gICAgICAgICAgICAgICAgICBwYXJhbXM6IHtcclxuICAgICAgICAgICAgICAgICAgICBlcnJvck1lc3NhZ2U6ICdUaGUgdmFsdWUgbXVzdCBiZSBudW1lcmljIGFuZCBub24tbmVnYXRpdmUnXHJcbiAgICAgICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgICApXHJcbiAgICAgICAgICAgICAgLnRyYW5zZm9ybSgodmFsdWUpID0+XHJcbiAgICAgICAgICAgICAgICAhWyd1bmRlZmluZWQnLCAnbnVsbCcsICcnXS5pbmNsdWRlcyh2YWx1ZSlcclxuICAgICAgICAgICAgICAgICAgPyBOdW1iZXIodmFsdWUpXHJcbiAgICAgICAgICAgICAgICAgIDogbnVsbFxyXG4gICAgICAgICAgICAgICksXHJcbiAgICAgICAgICAgIHoubnVtYmVyKCkubm9ubmVnYXRpdmUoKVxyXG4gICAgICAgICAgXSlcclxuICAgICAgICAgIC5udWxsYWJsZSgpO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgc3RhcnRzV2l0aGAgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbFxyXG4gICAqIHN0cmljdGVyIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSBzY2hlbWEgd2lsbCB2YWxpZGF0ZSBhZ2FpbnN0IHRoZSBwcm92aWRlZCBgcHJlZml4ZXNgIGFycmF5IHRvIGNoZWNrXHJcbiAgICogd2hldGhlciBhIHN0cmluZyB2YWx1ZSBzdGFydHMgd2l0aCBhbnkgb2YgdGhlIHZhbHVlcyBwcm92aWRlZFxyXG4gICAqIGluIHRoZSBgcHJlZml4ZXNgIGFycmF5LlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhhdDpcclxuICAgKlxyXG4gICAqIC0gV2hlbiBgc3RyaWN0Q2hlY2tgIGlzIHRydWUsIHRoZSBzY2hlbWEgd2lsbCBhY2NlcHQgdHJpbW1lZCBzdHJpbmcgdmFsdWVzXHJcbiAgICogdGhhdCBzdGFydCB3aXRoIHZhbHVlcyBmcm9tIHRoZSBwcmVmaXhlcyBhcnJheS5cclxuICAgKlxyXG4gICAqIC0gV2hlbiBgc3RyaWN0Q2hlY2tgIGlzIGZhbHNlLCB0aGUgc2NoZW1hIHdpbGwgYWNjZXB0IHRyaW1tZWQgc3RyaW5nIHZhbHVlc1xyXG4gICAqIHRoYXQgc3RhcnQgd2l0aCB2YWx1ZXMgZnJvbSB0aGUgcHJlZml4ZXMgYXJyYXksIG51bGwsICd1bmRlZmluZWQnLCAnbnVsbCcsXHJcbiAgICogYW5kICcnIHdoZXJlIHRoZSBzY2hlbWEgd2lsbCB0cmFuc2Zvcm0gdGhlbSB0byBudWxsLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIHN0YXJ0c1dpdGhcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7QXJyYXkuPHN0cmluZz59IHByZWZpeGVzIC0gQW4gYXJyYXkgb2YgcHJlZml4ZXMgdG8gdmFsaWRhdGVcclxuICAgKiB0aGUgc3RyaW5nIGFnYWluc3QuXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nIHN0cmluZ3MgdGhhdFxyXG4gICAqIHN0YXJ0cyB3aXRoIHZhbHVlcy5cclxuICAgKi9cclxuICBzdGFydHNXaXRoKHByZWZpeGVzLCBzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHN0cmljdENoZWNrXHJcbiAgICAgID8gelxyXG4gICAgICAgICAgLnN0cmluZygpXHJcbiAgICAgICAgICAudHJpbSgpXHJcbiAgICAgICAgICAucmVmaW5lKFxyXG4gICAgICAgICAgICAodmFsdWUpID0+IHByZWZpeGVzLnNvbWUoKHByZWZpeCkgPT4gdmFsdWUuc3RhcnRzV2l0aChwcmVmaXgpKSxcclxuICAgICAgICAgICAge1xyXG4gICAgICAgICAgICAgIHBhcmFtczoge1xyXG4gICAgICAgICAgICAgICAgZXJyb3JNZXNzYWdlOiBgVGhlIHZhbHVlIG11c3QgYmUgYSBzdHJpbmcgdGhhdCBzdGFydHMgd2l0aCAke3ByZWZpeGVzLmpvaW4oJywgJyl9YFxyXG4gICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgfVxyXG4gICAgICAgICAgKVxyXG4gICAgICA6IHpcclxuICAgICAgICAgIC5zdHJpbmcoKVxyXG4gICAgICAgICAgLnRyaW0oKVxyXG4gICAgICAgICAgLnJlZmluZShcclxuICAgICAgICAgICAgKHZhbHVlKSA9PlxyXG4gICAgICAgICAgICAgIHByZWZpeGVzLnNvbWUoKHByZWZpeCkgPT4gdmFsdWUuc3RhcnRzV2l0aChwcmVmaXgpKSB8fFxyXG4gICAgICAgICAgICAgIFsndW5kZWZpbmVkJywgJ251bGwnLCAnJ10uaW5jbHVkZXModmFsdWUpLFxyXG4gICAgICAgICAgICB7XHJcbiAgICAgICAgICAgICAgcGFyYW1zOiB7XHJcbiAgICAgICAgICAgICAgICBlcnJvck1lc3NhZ2U6IGBUaGUgdmFsdWUgbXVzdCBiZSBhIHN0cmluZyB0aGF0IHN0YXJ0cyB3aXRoICR7cHJlZml4ZXMuam9pbignLCAnKX1gXHJcbiAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICB9XHJcbiAgICAgICAgICApXHJcbiAgICAgICAgICAudHJhbnNmb3JtKCh2YWx1ZSkgPT5cclxuICAgICAgICAgICAgIVsndW5kZWZpbmVkJywgJ251bGwnLCAnJ10uaW5jbHVkZXModmFsdWUpID8gdmFsdWUgOiBudWxsXHJcbiAgICAgICAgICApXHJcbiAgICAgICAgICAubnVsbGFibGUoKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYGNoYXJ0Q29uZmlnYCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYS5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoYXQgdGhlIHNjaGVtYSB3aWxsIGFjY2VwdCBvYmplY3QgdmFsdWVzXHJcbiAgICogb3IgdHJpbW1lZCBzdHJpbmcgdmFsdWVzIHRoYXQgY29udGFpbiAnPHN2Zycgb3IgJzw/eG1sJyBlbGVtZW50cywgc3RhcnRcclxuICAgKiB3aXRoIHRoZSAneycgYW5kIGVuZCB3aXRoIHRoZSAnfScsIGFuZCBudWxsLiBUaGUgJ3VuZGVmaW5lZCcsICdudWxsJyxcclxuICAgKiBhbmQgJycgdmFsdWVzIHdpbGwgYmUgdHJhbnNmb3JtZWQgdG8gbnVsbC5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiBjaGFydENvbmZpZ1xyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nIGNoYXJ0XHJcbiAgICogY29uZmlndXJhdGlvbiB2YWx1ZS5cclxuICAgKi9cclxuICBjaGFydENvbmZpZygpIHtcclxuICAgIHJldHVybiB6XHJcbiAgICAgIC51bmlvbihbXHJcbiAgICAgICAgelxyXG4gICAgICAgICAgLnN0cmluZygpXHJcbiAgICAgICAgICAudHJpbSgpXHJcbiAgICAgICAgICAucmVmaW5lKFxyXG4gICAgICAgICAgICAodmFsdWUpID0+XHJcbiAgICAgICAgICAgICAgKHZhbHVlLnN0YXJ0c1dpdGgoJ3snKSAmJiB2YWx1ZS5lbmRzV2l0aCgnfScpKSB8fFxyXG4gICAgICAgICAgICAgIFsndW5kZWZpbmVkJywgJ251bGwnLCAnJ10uaW5jbHVkZXModmFsdWUpLFxyXG4gICAgICAgICAgICB7XHJcbiAgICAgICAgICAgICAgcGFyYW1zOiB7XHJcbiAgICAgICAgICAgICAgICBlcnJvck1lc3NhZ2U6XHJcbiAgICAgICAgICAgICAgICAgIFwiVGhlIHZhbHVlIG11c3QgYmUgYSBzdHJpbmcgdGhhdCBzdGFydHMgd2l0aCAneycgYW5kIGVuZHMgd2l0aCAnfSdcIlxyXG4gICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgfVxyXG4gICAgICAgICAgKVxyXG4gICAgICAgICAgLnRyYW5zZm9ybSgodmFsdWUpID0+XHJcbiAgICAgICAgICAgICFbJ3VuZGVmaW5lZCcsICdudWxsJywgJyddLmluY2x1ZGVzKHZhbHVlKSA/IHZhbHVlIDogbnVsbFxyXG4gICAgICAgICAgKSxcclxuICAgICAgICB6Lm9iamVjdCh7fSkucGFzc3Rocm91Z2goKVxyXG4gICAgICBdKVxyXG4gICAgICAubnVsbGFibGUoKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYGFkZGl0aW9uYWxPcHRpb25zYCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYS5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoYXQgdGhlIHNjaGVtYSB3aWxsIGFjY2VwdCBvYmplY3QgdmFsdWVzXHJcbiAgICogb3IgdHJpbW1lZCBzdHJpbmcgdmFsdWVzIHRoYXQgZW5kIHdpdGggJy5qc29uJyBhbmQgYXJlIGF0IGxlYXN0IG9uZVxyXG4gICAqIGNoYXJhY3RlciBsb25nIGV4Y2x1ZGluZyB0aGUgZXh0ZW5zaW9uLCBzdGFydCB3aXRoIHRoZSAneycgYW5kIGVuZFxyXG4gICAqIHdpdGggdGhlICd9JywgYW5kIG51bGwuIFRoZSAndW5kZWZpbmVkJywgJ251bGwnLCBhbmQgJycgdmFsdWVzIHdpbGxcclxuICAgKiBiZSB0cmFuc2Zvcm1lZCB0byBudWxsLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIGFkZGl0aW9uYWxPcHRpb25zXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9ICBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nIGFkZGl0aW9uYWwgY2hhcnRcclxuICAgKiBvcHRpb25zIHZhbHVlLlxyXG4gICAqL1xyXG4gIGFkZGl0aW9uYWxPcHRpb25zKCkge1xyXG4gICAgcmV0dXJuIHpcclxuICAgICAgLnVuaW9uKFtcclxuICAgICAgICB6XHJcbiAgICAgICAgICAuc3RyaW5nKClcclxuICAgICAgICAgIC50cmltKClcclxuICAgICAgICAgIC5yZWZpbmUoXHJcbiAgICAgICAgICAgICh2YWx1ZSkgPT5cclxuICAgICAgICAgICAgICAodmFsdWUubGVuZ3RoID49IDYgJiYgdmFsdWUuZW5kc1dpdGgoJy5qc29uJykpIHx8XHJcbiAgICAgICAgICAgICAgKHZhbHVlLnN0YXJ0c1dpdGgoJ3snKSAmJiB2YWx1ZS5lbmRzV2l0aCgnfScpKSB8fFxyXG4gICAgICAgICAgICAgIFsndW5kZWZpbmVkJywgJ251bGwnLCAnJ10uaW5jbHVkZXModmFsdWUpLFxyXG4gICAgICAgICAgICB7XHJcbiAgICAgICAgICAgICAgcGFyYW1zOiB7XHJcbiAgICAgICAgICAgICAgICBlcnJvck1lc3NhZ2U6XHJcbiAgICAgICAgICAgICAgICAgIFwiVGhlIHZhbHVlIG11c3QgYmUgYSBzdHJpbmcgdGhhdCBlbmRzIHdpdGggJy5qc29uJyBvciBzdGFydHMgd2l0aCAneycgYW5kIGVuZHMgd2l0aCAnfSdcIlxyXG4gICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgfVxyXG4gICAgICAgICAgKVxyXG4gICAgICAgICAgLnRyYW5zZm9ybSgodmFsdWUpID0+XHJcbiAgICAgICAgICAgICFbJ3VuZGVmaW5lZCcsICdudWxsJywgJyddLmluY2x1ZGVzKHZhbHVlKSA/IHZhbHVlIDogbnVsbFxyXG4gICAgICAgICAgKSxcclxuICAgICAgICB6Lm9iamVjdCh7fSkucGFzc3Rocm91Z2goKVxyXG4gICAgICBdKVxyXG4gICAgICAubnVsbGFibGUoKTtcclxuICB9XHJcbn07XHJcblxyXG4vKipcclxuICogT2JqZWN0IGNvbnRhaW5pbmcgY3VzdG9tIGNvbmZpZyB2YWxpZGF0b3JzIGFuZCBwYXJzZXJzIHRvIGF2b2lkIHJlcGV0aXRpb25cclxuICogaW4gc2NoZW1hIG9iamVjdHMuIEFsbCB2YWxpZGF0b3JzIGFwcGx5IHRvIHZhbHVlcyBmcm9tIHZhcmlvdXMgc291cmNlcyxcclxuICogaW5jbHVkaW5nIHRoZSBkZWZhdWx0IGNvbmZpZyBmaWxlLCBhIGN1c3RvbSBKU09OIGZpbGUgbG9hZGVkIHdpdGggdGhlIG9wdGlvblxyXG4gKiBjYWxsZWQgYGxvYWRDb25maWdgLCB0aGUgLmVudiBmaWxlLCBDTEkgYXJndW1lbnRzLCBhbmQgdGhlIHJlcXVlc3QgcGF5bG9hZC5cclxuICogVGhlIGBzdHJpY3RDaGVja2AgZmxhZyBlbmFibGVzIHN0cmljdGVyIHZhbGlkYXRpb24gYW5kIHBhcnNpbmcgcnVsZXMuIFRoaXNcclxuICogZmxhZyBpcyBzZXQgdG8gZmFsc2UgZm9yIHZhbHVlcyB0aGF0IGNvbWUgZnJvbSB0aGUgLmVudiBmaWxlIG9yIENMSSBhcmd1bWVudHNcclxuICogYmVjYXVzZSB0aGV5IGFyZSBwcm92aWRlZCBhcyBzdHJpbmdzIGFuZCBuZWVkIHRvIGJlIHBhcnNlZCBhY2NvcmRpbmdseSBmaXJzdC5cclxuICovXHJcbmV4cG9ydCBjb25zdCB2YWxpZGF0b3JzID0ge1xyXG4gIC8qKlxyXG4gICAqIFRoZSBgYXJnc2AgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbCBzdHJpY3RlclxyXG4gICAqIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgdGhlIGBzdHJpbmdBcnJheWAgdmFsaWRhdG9yLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIGFyZ3NcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZyB0aGUgYGFyZ3NgXHJcbiAgICogb3B0aW9uLlxyXG4gICAqL1xyXG4gIGFyZ3Moc3RyaWN0Q2hlY2spIHtcclxuICAgIHJldHVybiB2LnN0cmluZ0FycmF5KFxyXG4gICAgICAodmFsdWUpID0+ICFbJ2ZhbHNlJywgJ3VuZGVmaW5lZCcsICdudWxsJywgJyddLmluY2x1ZGVzKHZhbHVlKSxcclxuICAgICAgJzsnLFxyXG4gICAgICBzdHJpY3RDaGVja1xyXG4gICAgKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYHZlcnNpb25gIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGggYW4gb3B0aW9uYWwgc3RyaWN0ZXJcclxuICAgKiBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGF0OlxyXG4gICAqXHJcbiAgICogLSBXaGVuIGBzdHJpY3RDaGVja2AgaXMgdHJ1ZSwgdGhlIHNjaGVtYSB3aWxsIGFjY2VwdCB0cmltbWVkIHN0cmluZyB2YWx1ZXNcclxuICAgKiB0aGF0IGFyZSBhIFJlZ0V4cC1iYXNlZCB0aGF0IGFsbG93cyB0byBiZSAnbGF0ZXN0Jywgb3IgaW4gdGhlIGZvcm1hdCBYWCxcclxuICAgKiBYWC5ZWSwgb3IgWFguWVkuWlosIHdoZXJlIFhYLCBZWSwgYW5kIFpaIGFyZSBudW1lcmljIGZvciB0aGUgSGlnaGNoYXJ0c1xyXG4gICAqIHZlcnNpb24gb3B0aW9uLlxyXG4gICAqXHJcbiAgICogLSBXaGVuIGBzdHJpY3RDaGVja2AgaXMgZmFsc2UsIHRoZSBzY2hlbWEgd2lsbCBhY2NlcHQgYWxzbyBudWxsLFxyXG4gICAqICd1bmRlZmluZWQnLCAnbnVsbCcsIG9yICcnIGFuZCBpbiBhbGwgY2FzZXMgdGhlIHNjaGVtYSB3aWxsIHRyYW5zZm9ybSB0aGVtXHJcbiAgICogdG8gbnVsbC5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiB2ZXJzaW9uXHJcbiAgICpcclxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IHN0cmljdENoZWNrIC0gRGV0ZXJtaW5lcyBpZiBzdHJpY3RlciB2YWxpZGF0aW9uIHNob3VsZFxyXG4gICAqIGJlIGFwcGxpZWQuXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9IEEgWm9kIHNjaGVtYSBvYmplY3QgZm9yIHZhbGlkYXRpbmcgdGhlIGB2ZXJzaW9uYFxyXG4gICAqIG9wdGlvbi5cclxuICAgKi9cclxuICB2ZXJzaW9uKHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gc3RyaWN0Q2hlY2tcclxuICAgICAgPyB6XHJcbiAgICAgICAgICAuc3RyaW5nKClcclxuICAgICAgICAgIC50cmltKClcclxuICAgICAgICAgIC5yZWZpbmUoKHZhbHVlKSA9PiAvXihsYXRlc3R8XFxkezEsMn0oXFwuXFxkezEsMn0pezAsMn0pJC8udGVzdCh2YWx1ZSksIHtcclxuICAgICAgICAgICAgcGFyYW1zOiB7XHJcbiAgICAgICAgICAgICAgZXJyb3JNZXNzYWdlOlxyXG4gICAgICAgICAgICAgICAgXCJUaGUgdmFsdWUgbXVzdCBiZSAnbGF0ZXN0JywgYSBtYWpvciB2ZXJzaW9uLCBvciBpbiB0aGUgZm9ybSBYWC5ZWS5aWlwiXHJcbiAgICAgICAgICAgIH1cclxuICAgICAgICAgIH0pXHJcbiAgICAgIDogelxyXG4gICAgICAgICAgLnN0cmluZygpXHJcbiAgICAgICAgICAudHJpbSgpXHJcbiAgICAgICAgICAucmVmaW5lKFxyXG4gICAgICAgICAgICAodmFsdWUpID0+XHJcbiAgICAgICAgICAgICAgL14obGF0ZXN0fFxcZHsxLDJ9KFxcLlxcZHsxLDJ9KXswLDJ9KSQvLnRlc3QodmFsdWUpIHx8XHJcbiAgICAgICAgICAgICAgWyd1bmRlZmluZWQnLCAnbnVsbCcsICcnXS5pbmNsdWRlcyh2YWx1ZSksXHJcbiAgICAgICAgICAgIHtcclxuICAgICAgICAgICAgICBwYXJhbXM6IHtcclxuICAgICAgICAgICAgICAgIGVycm9yTWVzc2FnZTpcclxuICAgICAgICAgICAgICAgICAgXCJUaGUgdmFsdWUgbXVzdCBiZSAnbGF0ZXN0JywgYSBtYWpvciB2ZXJzaW9uLCBvciBpbiB0aGUgZm9ybSBYWC5ZWS5aWlwiXHJcbiAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICB9XHJcbiAgICAgICAgICApXHJcbiAgICAgICAgICAudHJhbnNmb3JtKCh2YWx1ZSkgPT5cclxuICAgICAgICAgICAgIVsndW5kZWZpbmVkJywgJ251bGwnLCAnJ10uaW5jbHVkZXModmFsdWUpID8gdmFsdWUgOiBudWxsXHJcbiAgICAgICAgICApXHJcbiAgICAgICAgICAubnVsbGFibGUoKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYGNkblVybGAgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbCBzdHJpY3RlclxyXG4gICAqIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgdGhlIGBzdGFydHNXaXRoYCB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gY2RuVXJsXHJcbiAgICpcclxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IHN0cmljdENoZWNrIC0gRGV0ZXJtaW5lcyBpZiBzdHJpY3RlciB2YWxpZGF0aW9uIHNob3VsZFxyXG4gICAqIGJlIGFwcGxpZWQuXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9IEEgWm9kIHNjaGVtYSBvYmplY3QgZm9yIHZhbGlkYXRpbmcgdGhlIGBjZG5VcmxgXHJcbiAgICogb3B0aW9uLlxyXG4gICAqL1xyXG4gIGNkblVybChzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHYuc3RhcnRzV2l0aChbJ2h0dHA6Ly8nLCAnaHR0cHM6Ly8nXSwgc3RyaWN0Q2hlY2spO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgZm9yY2VGZXRjaGAgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbFxyXG4gICAqIHN0cmljdGVyIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgdGhlIGBib29sZWFuYCB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gZm9yY2VGZXRjaFxyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nIHRoZSBgZm9yY2VGZXRjaGBcclxuICAgKiBvcHRpb24uXHJcbiAgICovXHJcbiAgZm9yY2VGZXRjaChzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHYuYm9vbGVhbihzdHJpY3RDaGVjayk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGBjYWNoZVBhdGhgIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGggYW4gb3B0aW9uYWxcclxuICAgKiBzdHJpY3RlciBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGUgc2FtZSB3b3JrIGFzIHRoZSBgc3RyaW5nYCB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gY2FjaGVQYXRoXHJcbiAgICpcclxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IHN0cmljdENoZWNrIC0gRGV0ZXJtaW5lcyBpZiBzdHJpY3RlciB2YWxpZGF0aW9uIHNob3VsZFxyXG4gICAqIGJlIGFwcGxpZWQuXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9IEEgWm9kIHNjaGVtYSBvYmplY3QgZm9yIHZhbGlkYXRpbmcgdGhlIGBjYWNoZVBhdGhgXHJcbiAgICogb3B0aW9uLlxyXG4gICAqL1xyXG4gIGNhY2hlUGF0aChzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHYuc3RyaW5nKHN0cmljdENoZWNrKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYGFkbWluVG9rZW5gIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGggYW4gb3B0aW9uYWxcclxuICAgKiBzdHJpY3RlciBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGUgc2FtZSB3b3JrIGFzIHRoZSBgc3RyaW5nYCB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gYWRtaW5Ub2tlblxyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nIHRoZSBgYWRtaW5Ub2tlbmBcclxuICAgKiBvcHRpb24uXHJcbiAgICovXHJcbiAgYWRtaW5Ub2tlbihzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHYuc3RyaW5nKHN0cmljdENoZWNrKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYGNvcmVTY3JpcHRzYCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoIGFuIG9wdGlvbmFsXHJcbiAgICogc3RyaWN0ZXIgY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhlIHNhbWUgd29yayBhcyB0aGUgYHN0cmluZ0FycmF5YCB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gY29yZVNjcmlwdHNcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZyB0aGUgYGNvcmVTY3JpcHRzYFxyXG4gICAqIG9wdGlvbi5cclxuICAgKi9cclxuICBjb3JlU2NyaXB0cyhzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHYuc3RyaW5nQXJyYXkoXHJcbiAgICAgICh2YWx1ZSkgPT4gY29yZVNjcmlwdHMudmFsdWUuaW5jbHVkZXModmFsdWUpLFxyXG4gICAgICAnLCcsXHJcbiAgICAgIHN0cmljdENoZWNrXHJcbiAgICApO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgbW9kdWxlU2NyaXB0c2AgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbFxyXG4gICAqIHN0cmljdGVyIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgdGhlIGBzdHJpbmdBcnJheWAgdmFsaWRhdG9yLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIG1vZHVsZVNjcmlwdHNcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZ1xyXG4gICAqIHRoZSBgbW9kdWxlU2NyaXB0c2Agb3B0aW9uLlxyXG4gICAqL1xyXG4gIG1vZHVsZVNjcmlwdHMoc3RyaWN0Q2hlY2spIHtcclxuICAgIHJldHVybiB2LnN0cmluZ0FycmF5KFxyXG4gICAgICAodmFsdWUpID0+IG1vZHVsZVNjcmlwdHMudmFsdWUuaW5jbHVkZXModmFsdWUpLFxyXG4gICAgICAnLCcsXHJcbiAgICAgIHN0cmljdENoZWNrXHJcbiAgICApO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgaW5kaWNhdG9yU2NyaXB0c2AgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbFxyXG4gICAqIHN0cmljdGVyIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgdGhlIGBzdHJpbmdBcnJheWAgdmFsaWRhdG9yLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIGluZGljYXRvclNjcmlwdHNcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZ1xyXG4gICAqIHRoZSBgaW5kaWNhdG9yU2NyaXB0c2Agb3B0aW9uLlxyXG4gICAqL1xyXG4gIGluZGljYXRvclNjcmlwdHMoc3RyaWN0Q2hlY2spIHtcclxuICAgIHJldHVybiB2LnN0cmluZ0FycmF5KFxyXG4gICAgICAodmFsdWUpID0+IGluZGljYXRvclNjcmlwdHMudmFsdWUuaW5jbHVkZXModmFsdWUpLFxyXG4gICAgICAnLCcsXHJcbiAgICAgIHN0cmljdENoZWNrXHJcbiAgICApO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgY3VzdG9tU2NyaXB0c2AgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbFxyXG4gICAqIHN0cmljdGVyIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgdGhlIGBzdHJpbmdBcnJheWAgdmFsaWRhdG9yLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIGN1c3RvbVNjcmlwdHNcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZ1xyXG4gICAqIHRoZSBgY3VzdG9tU2NyaXB0c2Agb3B0aW9uLlxyXG4gICAqL1xyXG4gIGN1c3RvbVNjcmlwdHMoc3RyaWN0Q2hlY2spIHtcclxuICAgIHJldHVybiB2LnN0cmluZ0FycmF5KFxyXG4gICAgICAodmFsdWUpID0+IHZhbHVlLnN0YXJ0c1dpdGgoJ2h0dHBzOi8vJykgfHwgdmFsdWUuc3RhcnRzV2l0aCgnaHR0cDovLycpLFxyXG4gICAgICAnLCcsXHJcbiAgICAgIHN0cmljdENoZWNrXHJcbiAgICApO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgaW5maWxlYCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoIGFuIG9wdGlvbmFsIHN0cmljdGVyXHJcbiAgICogY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhhdDpcclxuICAgKlxyXG4gICAqIC0gV2hlbiBgc3RyaWN0Q2hlY2tgIGlzIHRydWUsIHRoZSBzY2hlbWEgd2lsbCBhY2NlcHQgdHJpbW1lZCBzdHJpbmcgdmFsdWVzXHJcbiAgICogdGhhdCBlbmQgd2l0aCAnLmpzb24nIG9yICcuc3ZnJywgYXJlIGF0IGxlYXN0IG9uZSBjaGFyYWN0ZXIgbG9uZyBleGNsdWRpbmdcclxuICAgKiB0aGUgZXh0ZW5zaW9uLCBvciBudWxsLlxyXG4gICAqXHJcbiAgICogLSBXaGVuIGBzdHJpY3RDaGVja2AgaXMgZmFsc2UsIHRoZSBzY2hlbWEgd2lsbCBhY2NlcHQgdHJpbW1lZCBzdHJpbmcgdmFsdWVzXHJcbiAgICogdGhhdCBlbmQgd2l0aCAnLmpzb24nIG9yICcuc3ZnJywgYXJlIGF0IGxlYXN0IG9uZSBjaGFyYWN0ZXIgbG9uZyBleGNsdWRpbmdcclxuICAgKiB0aGUgZXh0ZW5zaW9uIGFuZCB3aWxsIGJlIG51bGwgaWYgdGhlIHByb3ZpZGVkIHZhbHVlIGlzIG51bGwsICd1bmRlZmluZWQnLFxyXG4gICAqICdudWxsJywgb3IgJycuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gaW5maWxlXHJcbiAgICpcclxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IHN0cmljdENoZWNrIC0gRGV0ZXJtaW5lcyBpZiBzdHJpY3RlciB2YWxpZGF0aW9uIHNob3VsZFxyXG4gICAqIGJlIGFwcGxpZWQuXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9IEEgWm9kIHNjaGVtYSBvYmplY3QgZm9yIHZhbGlkYXRpbmcgdGhlIGBpbmZpbGVgXHJcbiAgICogb3B0aW9uLlxyXG4gICAqL1xyXG4gIGluZmlsZShzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHN0cmljdENoZWNrXHJcbiAgICAgID8gelxyXG4gICAgICAgICAgLnN0cmluZygpXHJcbiAgICAgICAgICAudHJpbSgpXHJcbiAgICAgICAgICAucmVmaW5lKFxyXG4gICAgICAgICAgICAodmFsdWUpID0+XHJcbiAgICAgICAgICAgICAgKHZhbHVlLmxlbmd0aCA+PSA2ICYmIHZhbHVlLmVuZHNXaXRoKCcuanNvbicpKSB8fFxyXG4gICAgICAgICAgICAgICh2YWx1ZS5sZW5ndGggPj0gNSAmJiB2YWx1ZS5lbmRzV2l0aCgnLnN2ZycpKSxcclxuICAgICAgICAgICAge1xyXG4gICAgICAgICAgICAgIHBhcmFtczoge1xyXG4gICAgICAgICAgICAgICAgZXJyb3JNZXNzYWdlOlxyXG4gICAgICAgICAgICAgICAgICAnVGhlIHZhbHVlIG11c3QgYmUgYSBzdHJpbmcgdGhhdCBlbmRzIHdpdGggLmpzb24gb3IgLnN2ZydcclxuICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgIH1cclxuICAgICAgICAgIClcclxuICAgICAgICAgIC5udWxsYWJsZSgpXHJcbiAgICAgIDogelxyXG4gICAgICAgICAgLnN0cmluZygpXHJcbiAgICAgICAgICAudHJpbSgpXHJcbiAgICAgICAgICAucmVmaW5lKFxyXG4gICAgICAgICAgICAodmFsdWUpID0+XHJcbiAgICAgICAgICAgICAgKHZhbHVlLmxlbmd0aCA+PSA2ICYmIHZhbHVlLmVuZHNXaXRoKCcuanNvbicpKSB8fFxyXG4gICAgICAgICAgICAgICh2YWx1ZS5sZW5ndGggPj0gNSAmJiB2YWx1ZS5lbmRzV2l0aCgnLnN2ZycpKSB8fFxyXG4gICAgICAgICAgICAgIFsndW5kZWZpbmVkJywgJ251bGwnLCAnJ10uaW5jbHVkZXModmFsdWUpLFxyXG4gICAgICAgICAgICB7XHJcbiAgICAgICAgICAgICAgcGFyYW1zOiB7XHJcbiAgICAgICAgICAgICAgICBlcnJvck1lc3NhZ2U6XHJcbiAgICAgICAgICAgICAgICAgICdUaGUgdmFsdWUgbXVzdCBiZSBhIHN0cmluZyB0aGF0IGVuZHMgd2l0aCAuanNvbiBvciAuc3ZnJ1xyXG4gICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgfVxyXG4gICAgICAgICAgKVxyXG4gICAgICAgICAgLnRyYW5zZm9ybSgodmFsdWUpID0+XHJcbiAgICAgICAgICAgICFbJ3VuZGVmaW5lZCcsICdudWxsJywgJyddLmluY2x1ZGVzKHZhbHVlKSA/IHZhbHVlIDogbnVsbFxyXG4gICAgICAgICAgKVxyXG4gICAgICAgICAgLm51bGxhYmxlKCk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGBpbnN0cmAgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGUgc2FtZSB3b3JrIGFzIHRoZSBgb3B0aW9uc2AgdmFsaWRhdG9yLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIGluc3RyXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9IEEgWm9kIHNjaGVtYSBvYmplY3QgZm9yIHZhbGlkYXRpbmcgdGhlIGBpbnN0cmBcclxuICAgKiBvcHRpb24uXHJcbiAgICovXHJcbiAgaW5zdHIoKSB7XHJcbiAgICByZXR1cm4gdi5jaGFydENvbmZpZygpO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgb3B0aW9uc2AgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGUgc2FtZSB3b3JrIGFzIHRoZSBgb3B0aW9uc2AgdmFsaWRhdG9yLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIG9wdGlvbnNcclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZyB0aGUgYG9wdGlvbnNgXHJcbiAgICogb3B0aW9uLlxyXG4gICAqL1xyXG4gIG9wdGlvbnMoKSB7XHJcbiAgICByZXR1cm4gdi5jaGFydENvbmZpZygpO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgc3ZnYCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYS5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoYXQgdGhlIHNjaGVtYSB3aWxsIGFjY2VwdCBvYmplY3QgdmFsdWVzXHJcbiAgICogb3IgdHJpbW1lZCBzdHJpbmcgdmFsdWVzIHRoYXQgY29udGFpbiAnPHN2Zycgb3IgJzw/eG1sJyBlbGVtZW50cyBhbmQgbnVsbC5cclxuICAgKiBUaGUgJ3VuZGVmaW5lZCcsICdudWxsJywgYW5kICcnIHZhbHVlcyB3aWxsIGJlIHRyYW5zZm9ybWVkIHRvIG51bGwuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gc3ZnXHJcbiAgICpcclxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IHN0cmljdENoZWNrIC0gRGV0ZXJtaW5lcyBpZiBzdHJpY3RlciB2YWxpZGF0aW9uIHNob3VsZFxyXG4gICAqIGJlIGFwcGxpZWQuXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9IEEgWm9kIHNjaGVtYSBvYmplY3QgZm9yIHZhbGlkYXRpbmcgdGhlIGBzdmdgIG9wdGlvbi5cclxuICAgKi9cclxuICBzdmcoKSB7XHJcbiAgICByZXR1cm4gelxyXG4gICAgICAuc3RyaW5nKClcclxuICAgICAgLnRyaW0oKVxyXG4gICAgICAucmVmaW5lKFxyXG4gICAgICAgICh2YWx1ZSkgPT5cclxuICAgICAgICAgIHZhbHVlLmluZGV4T2YoJzxzdmcnKSA+PSAwIHx8XHJcbiAgICAgICAgICB2YWx1ZS5pbmRleE9mKCc8P3htbCcpID49IDAgfHxcclxuICAgICAgICAgIFsnZmFsc2UnLCAndW5kZWZpbmVkJywgJ251bGwnLCAnJ10uaW5jbHVkZXModmFsdWUpLFxyXG4gICAgICAgIHtcclxuICAgICAgICAgIHBhcmFtczoge1xyXG4gICAgICAgICAgICBlcnJvck1lc3NhZ2U6XHJcbiAgICAgICAgICAgICAgXCJUaGUgdmFsdWUgbXVzdCBiZSBhIHN0cmluZyB0aGF0IGNvbnRhaW5zICc8c3ZnJyBvciAnPD94bWwnXCJcclxuICAgICAgICAgIH1cclxuICAgICAgICB9XHJcbiAgICAgIClcclxuICAgICAgLnRyYW5zZm9ybSgodmFsdWUpID0+XHJcbiAgICAgICAgIVsnZmFsc2UnLCAndW5kZWZpbmVkJywgJ251bGwnLCAnJ10uaW5jbHVkZXModmFsdWUpID8gdmFsdWUgOiBudWxsXHJcbiAgICAgIClcclxuICAgICAgLm51bGxhYmxlKCk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGBvdXRmaWxlYCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoIGFuIG9wdGlvbmFsIHN0cmljdGVyXHJcbiAgICogY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhhdDpcclxuICAgKlxyXG4gICAqIC0gV2hlbiBgc3RyaWN0Q2hlY2tgIGlzIHRydWUsIHRoZSBzY2hlbWEgd2lsbCBhY2NlcHQgdHJpbW1lZCBzdHJpbmcgdmFsdWVzXHJcbiAgICogdGhhdCBlbmQgd2l0aCAnLmpwZWcnLCAnLmpwZycsICcucG5nJywgJy5wZGYnLCBvciAnLnN2ZycsIGFyZSBhdCBsZWFzdCBvbmVcclxuICAgKiBjaGFyYWN0ZXIgbG9uZyBleGNsdWRpbmcgdGhlIGV4dGVuc2lvbiwgb3IgbnVsbC5cclxuICAgKlxyXG4gICAqIC0gV2hlbiBgc3RyaWN0Q2hlY2tgIGlzIGZhbHNlLCB0aGUgc2NoZW1hIHdpbGwgYWNjZXB0IHRyaW1tZWQgc3RyaW5nIHZhbHVlc1xyXG4gICAqIHRoYXQgZW5kIHdpdGggJy5qcGVnJywgJy5qcGcnLCAnLnBuZycsICcucGRmJywgb3IgJy5zdmcnLCBhcmUgYXQgbGVhc3Qgb25lXHJcbiAgICogY2hhcmFjdGVyIGxvbmcgZXhjbHVkaW5nIHRoZSBleHRlbnNpb24gYW5kIHdpbGwgYmUgbnVsbCBpZiB0aGUgcHJvdmlkZWRcclxuICAgKiB2YWx1ZSBpcyBudWxsLCAndW5kZWZpbmVkJywgJ251bGwnLCBvciAnJy5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiBvdXRmaWxlXHJcbiAgICpcclxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IHN0cmljdENoZWNrIC0gRGV0ZXJtaW5lcyBpZiBzdHJpY3RlciB2YWxpZGF0aW9uIHNob3VsZFxyXG4gICAqIGJlIGFwcGxpZWQuXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9IEEgWm9kIHNjaGVtYSBvYmplY3QgZm9yIHZhbGlkYXRpbmcgdGhlIGBvdXRmaWxlYFxyXG4gICAqIG9wdGlvbi5cclxuICAgKi9cclxuICBvdXRmaWxlKHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gc3RyaWN0Q2hlY2tcclxuICAgICAgPyB6XHJcbiAgICAgICAgICAuc3RyaW5nKClcclxuICAgICAgICAgIC50cmltKClcclxuICAgICAgICAgIC5yZWZpbmUoXHJcbiAgICAgICAgICAgICh2YWx1ZSkgPT5cclxuICAgICAgICAgICAgICAodmFsdWUubGVuZ3RoID49IDYgJiYgdmFsdWUuZW5kc1dpdGgoJy5qcGVnJykpIHx8XHJcbiAgICAgICAgICAgICAgKHZhbHVlLmxlbmd0aCA+PSA1ICYmXHJcbiAgICAgICAgICAgICAgICAodmFsdWUuZW5kc1dpdGgoJy5qcGcnKSB8fFxyXG4gICAgICAgICAgICAgICAgICB2YWx1ZS5lbmRzV2l0aCgnLnBuZycpIHx8XHJcbiAgICAgICAgICAgICAgICAgIHZhbHVlLmVuZHNXaXRoKCcucGRmJykgfHxcclxuICAgICAgICAgICAgICAgICAgdmFsdWUuZW5kc1dpdGgoJy5zdmcnKSkpLFxyXG4gICAgICAgICAgICB7XHJcbiAgICAgICAgICAgICAgcGFyYW1zOiB7XHJcbiAgICAgICAgICAgICAgICBlcnJvck1lc3NhZ2U6XHJcbiAgICAgICAgICAgICAgICAgICdUaGUgdmFsdWUgbXVzdCBiZSBhIHN0cmluZyB0aGF0IGVuZHMgd2l0aCAuanBlZywgLmpwZywgLnBuZywgLnBkZiwgb3IgLnN2ZydcclxuICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgIH1cclxuICAgICAgICAgIClcclxuICAgICAgICAgIC5udWxsYWJsZSgpXHJcbiAgICAgIDogelxyXG4gICAgICAgICAgLnN0cmluZygpXHJcbiAgICAgICAgICAudHJpbSgpXHJcbiAgICAgICAgICAucmVmaW5lKFxyXG4gICAgICAgICAgICAodmFsdWUpID0+XHJcbiAgICAgICAgICAgICAgKHZhbHVlLmxlbmd0aCA+PSA2ICYmIHZhbHVlLmVuZHNXaXRoKCcuanBlZycpKSB8fFxyXG4gICAgICAgICAgICAgICh2YWx1ZS5sZW5ndGggPj0gNSAmJlxyXG4gICAgICAgICAgICAgICAgKHZhbHVlLmVuZHNXaXRoKCcuanBnJykgfHxcclxuICAgICAgICAgICAgICAgICAgdmFsdWUuZW5kc1dpdGgoJy5wbmcnKSB8fFxyXG4gICAgICAgICAgICAgICAgICB2YWx1ZS5lbmRzV2l0aCgnLnBkZicpIHx8XHJcbiAgICAgICAgICAgICAgICAgIHZhbHVlLmVuZHNXaXRoKCcuc3ZnJykpKSB8fFxyXG4gICAgICAgICAgICAgIFsndW5kZWZpbmVkJywgJ251bGwnLCAnJ10uaW5jbHVkZXModmFsdWUpLFxyXG4gICAgICAgICAgICB7XHJcbiAgICAgICAgICAgICAgcGFyYW1zOiB7XHJcbiAgICAgICAgICAgICAgICBlcnJvck1lc3NhZ2U6XHJcbiAgICAgICAgICAgICAgICAgICdUaGUgdmFsdWUgbXVzdCBiZSBhIHN0cmluZyB0aGF0IGVuZHMgd2l0aCAuanBlZywgLmpwZywgLnBuZywgLnBkZiwgb3IgLnN2ZydcclxuICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgIH1cclxuICAgICAgICAgIClcclxuICAgICAgICAgIC50cmFuc2Zvcm0oKHZhbHVlKSA9PlxyXG4gICAgICAgICAgICAhWyd1bmRlZmluZWQnLCAnbnVsbCcsICcnXS5pbmNsdWRlcyh2YWx1ZSkgPyB2YWx1ZSA6IG51bGxcclxuICAgICAgICAgIClcclxuICAgICAgICAgIC5udWxsYWJsZSgpO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgdHlwZWAgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbCBzdHJpY3RlclxyXG4gICAqIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgdGhlIGBlbnVtYCB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gdHlwZVxyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nIHRoZSBgdHlwZWBcclxuICAgKiBvcHRpb24uXHJcbiAgICovXHJcbiAgdHlwZShzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHYuZW51bShbJ2pwZWcnLCAnanBnJywgJ3BuZycsICdwZGYnLCAnc3ZnJ10sIHN0cmljdENoZWNrKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYGNvbnN0cmAgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbCBzdHJpY3RlclxyXG4gICAqIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgdGhlIGBlbnVtYCB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gY29uc3RyXHJcbiAgICpcclxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IHN0cmljdENoZWNrIC0gRGV0ZXJtaW5lcyBpZiBzdHJpY3RlciB2YWxpZGF0aW9uIHNob3VsZFxyXG4gICAqIGJlIGFwcGxpZWQuXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9IEEgWm9kIHNjaGVtYSBvYmplY3QgZm9yIHZhbGlkYXRpbmcgdGhlIGBjb25zdHJgXHJcbiAgICogb3B0aW9uLlxyXG4gICAqL1xyXG4gIGNvbnN0cihzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHYuZW51bShcclxuICAgICAgWydjaGFydCcsICdzdG9ja0NoYXJ0JywgJ21hcENoYXJ0JywgJ2dhbnR0Q2hhcnQnXSxcclxuICAgICAgc3RyaWN0Q2hlY2tcclxuICAgICk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGBiNjRgIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGggYW4gb3B0aW9uYWwgc3RyaWN0ZXJcclxuICAgKiBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGUgc2FtZSB3b3JrIGFzIHRoZSBgYm9vbGVhbmAgdmFsaWRhdG9yLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIGI2NFxyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nIHRoZSBgYjY0YCBvcHRpb24uXHJcbiAgICovXHJcbiAgYjY0KHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gdi5ib29sZWFuKHN0cmljdENoZWNrKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYG5vRG93bmxvYWRgIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGggYW4gb3B0aW9uYWxcclxuICAgKiBzdHJpY3RlciBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGUgc2FtZSB3b3JrIGFzIHRoZSBgYm9vbGVhbmAgdmFsaWRhdG9yLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIG5vRG93bmxvYWRcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZyB0aGUgYG5vRG93bmxvYWRgXHJcbiAgICogb3B0aW9uLlxyXG4gICAqL1xyXG4gIG5vRG93bmxvYWQoc3RyaWN0Q2hlY2spIHtcclxuICAgIHJldHVybiB2LmJvb2xlYW4oc3RyaWN0Q2hlY2spO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgZGVmYXVsdEhlaWdodGAgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbFxyXG4gICAqIHN0cmljdGVyIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgdGhlIGBwb3NpdGl2ZU51bWAgdmFsaWRhdG9yLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIGRlZmF1bHRIZWlnaHRcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZ1xyXG4gICAqIHRoZSBgZGVmYXVsdEhlaWdodGAgb3B0aW9uLlxyXG4gICAqL1xyXG4gIGRlZmF1bHRIZWlnaHQoc3RyaWN0Q2hlY2spIHtcclxuICAgIHJldHVybiB2LnBvc2l0aXZlTnVtKHN0cmljdENoZWNrKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYGRlZmF1bHRXaWR0aGAgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbFxyXG4gICAqIHN0cmljdGVyIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgdGhlIGBwb3NpdGl2ZU51bWAgdmFsaWRhdG9yLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIGRlZmF1bHRXaWR0aFxyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nXHJcbiAgICogdGhlIGBkZWZhdWx0V2lkdGhgIG9wdGlvbi5cclxuICAgKi9cclxuICBkZWZhdWx0V2lkdGgoc3RyaWN0Q2hlY2spIHtcclxuICAgIHJldHVybiB2LnBvc2l0aXZlTnVtKHN0cmljdENoZWNrKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYGRlZmF1bHRTY2FsZWAgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbFxyXG4gICAqIHN0cmljdGVyIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoYXQ6XHJcbiAgICpcclxuICAgKiAtIFdoZW4gYHN0cmljdENoZWNrYCBpcyB0cnVlLCB0aGUgc2NoZW1hIHdpbGwgYWNjZXB0IG51bWJlciB2YWx1ZXMgdGhhdFxyXG4gICAqIGFyZSBiZXR3ZWVuIDAuMSBhbmQgNSAoaW5jbHVzaXZlKS5cclxuICAgKlxyXG4gICAqIC0gV2hlbiBgc3RyaWN0Q2hlY2tgIGlzIGZhbHNlLCB0aGUgc2NoZW1hIHdpbGwgYWNjZXB0IG51bWJlciB2YWx1ZXNcclxuICAgKiBhbmQgc3RyaW5naWZpZWQgbnVtYmVyIHZhbHVlcyB0aGF0IGFyZSBiZXR3ZWVuIDAuMSBhbmQgNSAoaW5jbHVzaXZlKSwgbnVsbCxcclxuICAgKiAndW5kZWZpbmVkJywgJ251bGwnLCBhbmQgJycgd2hpY2ggd2lsbCBiZSB0cmFuc2Zvcm1lZCB0byBudWxsLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIGRlZmF1bHRTY2FsZVxyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nXHJcbiAgICogdGhlIGBkZWZhdWx0U2NhbGVgIG9wdGlvbi5cclxuICAgKi9cclxuICBkZWZhdWx0U2NhbGUoc3RyaWN0Q2hlY2spIHtcclxuICAgIHJldHVybiBzdHJpY3RDaGVja1xyXG4gICAgICA/IHoubnVtYmVyKCkuZ3RlKDAuMSkubHRlKDUpXHJcbiAgICAgIDogelxyXG4gICAgICAgICAgLnVuaW9uKFtcclxuICAgICAgICAgICAgelxyXG4gICAgICAgICAgICAgIC5zdHJpbmcoKVxyXG4gICAgICAgICAgICAgIC50cmltKClcclxuICAgICAgICAgICAgICAucmVmaW5lKFxyXG4gICAgICAgICAgICAgICAgKHZhbHVlKSA9PlxyXG4gICAgICAgICAgICAgICAgICAoIWlzTmFOKE51bWJlcih2YWx1ZSkpICYmXHJcbiAgICAgICAgICAgICAgICAgICAgdmFsdWUgIT09IHRydWUgJiZcclxuICAgICAgICAgICAgICAgICAgICAhdmFsdWUuc3RhcnRzV2l0aCgnWycpICYmXHJcbiAgICAgICAgICAgICAgICAgICAgTnVtYmVyKHZhbHVlKSA+PSAwLjEgJiZcclxuICAgICAgICAgICAgICAgICAgICBOdW1iZXIodmFsdWUpIDw9IDUpIHx8XHJcbiAgICAgICAgICAgICAgICAgIFsndW5kZWZpbmVkJywgJ251bGwnLCAnJ10uaW5jbHVkZXModmFsdWUpLFxyXG4gICAgICAgICAgICAgICAge1xyXG4gICAgICAgICAgICAgICAgICBwYXJhbXM6IHtcclxuICAgICAgICAgICAgICAgICAgICBlcnJvck1lc3NhZ2U6ICdUaGUgdmFsdWUgbXVzdCBiZSB3aXRoaW4gYSAwLjEgYW5kIDUuMCByYW5nZSdcclxuICAgICAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICAgIClcclxuICAgICAgICAgICAgICAudHJhbnNmb3JtKCh2YWx1ZSkgPT5cclxuICAgICAgICAgICAgICAgICFbJ3VuZGVmaW5lZCcsICdudWxsJywgJyddLmluY2x1ZGVzKHZhbHVlKVxyXG4gICAgICAgICAgICAgICAgICA/IE51bWJlcih2YWx1ZSlcclxuICAgICAgICAgICAgICAgICAgOiBudWxsXHJcbiAgICAgICAgICAgICAgKSxcclxuICAgICAgICAgICAgei5udW1iZXIoKS5ndGUoMC4xKS5sdGUoNSlcclxuICAgICAgICAgIF0pXHJcbiAgICAgICAgICAubnVsbGFibGUoKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYGhlaWdodGAgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbCBzdHJpY3RlclxyXG4gICAqIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgYSBudWxsYWJsZSBgZGVmYXVsdEhlaWdodGBcclxuICAgKiB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gaGVpZ2h0XHJcbiAgICpcclxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IHN0cmljdENoZWNrIC0gRGV0ZXJtaW5lcyBpZiBzdHJpY3RlciB2YWxpZGF0aW9uIHNob3VsZFxyXG4gICAqIGJlIGFwcGxpZWQuXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9IEEgWm9kIHNjaGVtYSBvYmplY3QgZm9yIHZhbGlkYXRpbmcgdGhlIGBoZWlnaHRgXHJcbiAgICogb3B0aW9uLlxyXG4gICAqL1xyXG4gIGhlaWdodChzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHRoaXMuZGVmYXVsdEhlaWdodChzdHJpY3RDaGVjaykubnVsbGFibGUoKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYHdpZHRoYCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoIGFuIG9wdGlvbmFsIHN0cmljdGVyXHJcbiAgICogY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhlIHNhbWUgd29yayBhcyBhIG51bGxhYmxlIGBkZWZhdWx0V2lkdGhgXHJcbiAgICogdmFsaWRhdG9yLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIHdpZHRoXHJcbiAgICpcclxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IHN0cmljdENoZWNrIC0gRGV0ZXJtaW5lcyBpZiBzdHJpY3RlciB2YWxpZGF0aW9uIHNob3VsZFxyXG4gICAqIGJlIGFwcGxpZWQuXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9IEEgWm9kIHNjaGVtYSBvYmplY3QgZm9yIHZhbGlkYXRpbmcgdGhlIGB3aWR0aGBcclxuICAgKiBvcHRpb24uXHJcbiAgICovXHJcbiAgd2lkdGgoc3RyaWN0Q2hlY2spIHtcclxuICAgIHJldHVybiB0aGlzLmRlZmF1bHRXaWR0aChzdHJpY3RDaGVjaykubnVsbGFibGUoKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYHNjYWxlYCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoIGFuIG9wdGlvbmFsIHN0cmljdGVyXHJcbiAgICogY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhlIHNhbWUgd29yayBhcyBhIG51bGxhYmxlIGBkZWZhdWx0U2NhbGVgXHJcbiAgICogdmFsaWRhdG9yLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIHNjYWxlXHJcbiAgICpcclxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IHN0cmljdENoZWNrIC0gRGV0ZXJtaW5lcyBpZiBzdHJpY3RlciB2YWxpZGF0aW9uIHNob3VsZFxyXG4gICAqIGJlIGFwcGxpZWQuXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9IEEgWm9kIHNjaGVtYSBvYmplY3QgZm9yIHZhbGlkYXRpbmcgdGhlIGBzY2FsZWBcclxuICAgKiBvcHRpb24uXHJcbiAgICovXHJcbiAgc2NhbGUoc3RyaWN0Q2hlY2spIHtcclxuICAgIHJldHVybiB0aGlzLmRlZmF1bHRTY2FsZShzdHJpY3RDaGVjaykubnVsbGFibGUoKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYGdsb2JhbE9wdGlvbnNgIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhlIHNhbWUgd29yayBhcyB0aGUgYGFkZGl0aW9uYWxPcHRpb25zYFxyXG4gICAqIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiBnbG9iYWxPcHRpb25zXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9IEEgWm9kIHNjaGVtYSBvYmplY3QgZm9yIHZhbGlkYXRpbmdcclxuICAgKiB0aGUgYGdsb2JhbE9wdGlvbnNgIG9wdGlvbi5cclxuICAgKi9cclxuICBnbG9iYWxPcHRpb25zKCkge1xyXG4gICAgcmV0dXJuIHYuYWRkaXRpb25hbE9wdGlvbnMoKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYHRoZW1lT3B0aW9uc2AgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGUgc2FtZSB3b3JrIGFzIHRoZSBgYWRkaXRpb25hbE9wdGlvbnNgXHJcbiAgICogdmFsaWRhdG9yLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIHRoZW1lT3B0aW9uc1xyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nXHJcbiAgICogdGhlIGB0aGVtZU9wdGlvbnNgIG9wdGlvbi5cclxuICAgKi9cclxuICB0aGVtZU9wdGlvbnMoKSB7XHJcbiAgICByZXR1cm4gdi5hZGRpdGlvbmFsT3B0aW9ucygpO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgYmF0Y2hgIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGggYW4gb3B0aW9uYWwgc3RyaWN0ZXJcclxuICAgKiBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGUgc2FtZSB3b3JrIGFzIHRoZSBgc3RyaW5nYCB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gYmF0Y2hcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZyB0aGUgYGJhdGNoYFxyXG4gICAqIG9wdGlvbi5cclxuICAgKi9cclxuICBiYXRjaChzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHYuc3RyaW5nKHN0cmljdENoZWNrKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYHJhc3Rlcml6YXRpb25UaW1lb3V0YCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoXHJcbiAgICogYW4gb3B0aW9uYWwgc3RyaWN0ZXIgY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhlIHNhbWUgd29yayBhcyB0aGUgYG5vbk5lZ2F0aXZlTnVtYFxyXG4gICAqIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiByYXN0ZXJpemF0aW9uVGltZW91dFxyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nXHJcbiAgICogdGhlIGByYXN0ZXJpemF0aW9uVGltZW91dGAgb3B0aW9uLlxyXG4gICAqL1xyXG4gIHJhc3Rlcml6YXRpb25UaW1lb3V0KHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gdi5ub25OZWdhdGl2ZU51bShzdHJpY3RDaGVjayk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGBhbGxvd0NvZGVFeGVjdXRpb25gIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGhcclxuICAgKiBhbiBvcHRpb25hbCBzdHJpY3RlciBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGUgc2FtZSB3b3JrIGFzIHRoZSBgYm9vbGVhbmAgdmFsaWRhdG9yLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIGFsbG93Q29kZUV4ZWN1dGlvblxyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nXHJcbiAgICogdGhlIGBhbGxvd0NvZGVFeGVjdXRpb25gIG9wdGlvbi5cclxuICAgKi9cclxuICBhbGxvd0NvZGVFeGVjdXRpb24oc3RyaWN0Q2hlY2spIHtcclxuICAgIHJldHVybiB2LmJvb2xlYW4oc3RyaWN0Q2hlY2spO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgYWxsb3dGaWxlUmVzb3VyY2VzYCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoXHJcbiAgICogYW4gb3B0aW9uYWwgc3RyaWN0ZXIgY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhlIHNhbWUgd29yayBhcyB0aGUgYGJvb2xlYW5gIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiBhbGxvd0ZpbGVSZXNvdXJjZXNcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZ1xyXG4gICAqIHRoZSBgYWxsb3dGaWxlUmVzb3VyY2VzYCBvcHRpb24uXHJcbiAgICovXHJcbiAgYWxsb3dGaWxlUmVzb3VyY2VzKHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gdi5ib29sZWFuKHN0cmljdENoZWNrKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYGN1c3RvbUNvZGVgIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGggYW4gb3B0aW9uYWxcclxuICAgKiBzdHJpY3RlciBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGUgc2FtZSB3b3JrIGFzIHRoZSBgc3RyaW5nYCB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gY3VzdG9tQ29kZVxyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nIHRoZSBgY3VzdG9tQ29kZWBcclxuICAgKiBvcHRpb24uXHJcbiAgICovXHJcbiAgY3VzdG9tQ29kZShzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHYuc3RyaW5nKHN0cmljdENoZWNrKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYGNhbGxiYWNrYCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoIGFuIG9wdGlvbmFsXHJcbiAgICogc3RyaWN0ZXIgY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhlIHNhbWUgd29yayBhcyB0aGUgYHN0cmluZ2AgdmFsaWRhdG9yLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIGNhbGxiYWNrXHJcbiAgICpcclxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IHN0cmljdENoZWNrIC0gRGV0ZXJtaW5lcyBpZiBzdHJpY3RlciB2YWxpZGF0aW9uIHNob3VsZFxyXG4gICAqIGJlIGFwcGxpZWQuXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9IEEgWm9kIHNjaGVtYSBvYmplY3QgZm9yIHZhbGlkYXRpbmcgdGhlIGBjYWxsYmFja2BcclxuICAgKiBvcHRpb24uXHJcbiAgICovXHJcbiAgY2FsbGJhY2soc3RyaWN0Q2hlY2spIHtcclxuICAgIHJldHVybiB2LnN0cmluZyhzdHJpY3RDaGVjayk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGByZXNvdXJjZXNgIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGggYW4gb3B0aW9uYWxcclxuICAgKiBzdHJpY3RlciBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGF0OlxyXG4gICAqXHJcbiAgICogLSBXaGVuIGBzdHJpY3RDaGVja2AgaXMgdHJ1ZSwgdGhlIHNjaGVtYSB3aWxsIGFjY2VwdCBhIHBhcnRpYWwgb2JqZWN0XHJcbiAgICogd2l0aCBhbGxvd2VkIHByb3BlcnRpZXMgYGpzYCwgYGNzc2AsIGFuZCBgZmlsZXNgIHdoZXJlIGVhY2ggb2YgdGhlIGFsbG93ZWRcclxuICAgKiBwcm9wZXJ0aWVzIGNhbiBiZSBudWxsLCBzdHJpbmdpZmllZCB2ZXJzaW9uIG9mIHRoZSBvYmplY3QsIHN0cmluZyB0aGF0IGVuZHNcclxuICAgKiB3aXRoIHRoZSAnLmpzb24nLCBhbmQgbnVsbC5cclxuICAgKlxyXG4gICAqIC0gV2hlbiBgc3RyaWN0Q2hlY2tgIGlzIGZhbHNlLCB0aGUgc2NoZW1hIHdpbGwgYWNjZXB0IGEgc3RyaW5naWZpZWQgdmVyc2lvblxyXG4gICAqIG9mIGEgcGFydGlhbCBvYmplY3Qgd2l0aCBhbGxvd2VkIHByb3BlcnRpZXMgYGpzYCwgYGNzc2AsIGFuZCBgZmlsZXNgIHdoZXJlXHJcbiAgICogZWFjaCBvZiB0aGUgYWxsb3dlZCBwcm9wZXJ0aWVzIGNhbiBiZSBudWxsLCBzdHJpbmcgdGhhdCBlbmRzIHdpdGggdGhlXHJcbiAgICogJy5qc29uJywgYW5kIHdpbGwgYmUgbnVsbCBpZiB0aGUgcHJvdmlkZWQgdmFsdWUgaXMgJ3VuZGVmaW5lZCcsICdudWxsJ1xyXG4gICAqIG9yICcnLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIHJlc291cmNlc1xyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nIHRoZSBgcmVzb3VyY2VzYFxyXG4gICAqIG9wdGlvbi5cclxuICAgKi9cclxuICByZXNvdXJjZXMoc3RyaWN0Q2hlY2spIHtcclxuICAgIGNvbnN0IG9iamVjdFNjaGVtYSA9IHpcclxuICAgICAgLm9iamVjdCh7XHJcbiAgICAgICAganM6IHYuc3RyaW5nKGZhbHNlKSxcclxuICAgICAgICBjc3M6IHYuc3RyaW5nKGZhbHNlKSxcclxuICAgICAgICBmaWxlczogdlxyXG4gICAgICAgICAgLnN0cmluZ0FycmF5KFxyXG4gICAgICAgICAgICAodmFsdWUpID0+ICFbJ3VuZGVmaW5lZCcsICdudWxsJywgJyddLmluY2x1ZGVzKHZhbHVlKSxcclxuICAgICAgICAgICAgJywnLFxyXG4gICAgICAgICAgICB0cnVlXHJcbiAgICAgICAgICApXHJcbiAgICAgICAgICAubnVsbGFibGUoKVxyXG4gICAgICB9KVxyXG4gICAgICAucGFydGlhbCgpO1xyXG5cclxuICAgIGNvbnN0IHN0cmluZ1NjaGVtYTEgPSB6XHJcbiAgICAgIC5zdHJpbmcoKVxyXG4gICAgICAudHJpbSgpXHJcbiAgICAgIC5yZWZpbmUoXHJcbiAgICAgICAgKHZhbHVlKSA9PlxyXG4gICAgICAgICAgKHZhbHVlLnN0YXJ0c1dpdGgoJ3snKSAmJiB2YWx1ZS5lbmRzV2l0aCgnfScpKSB8fFxyXG4gICAgICAgICAgKHZhbHVlLmxlbmd0aCA+PSA2ICYmIHZhbHVlLmVuZHNXaXRoKCcuanNvbicpKSxcclxuICAgICAgICB7XHJcbiAgICAgICAgICBwYXJhbXM6IHtcclxuICAgICAgICAgICAgZXJyb3JNZXNzYWdlOlxyXG4gICAgICAgICAgICAgIFwiVGhlIHZhbHVlIG11c3QgYmUgYSBzdHJpbmcgdGhhdCBzdGFydHMgd2l0aCAneycgYW5kIGVuZHMgd2l0aCAnfVwiXHJcbiAgICAgICAgICB9XHJcbiAgICAgICAgfVxyXG4gICAgICApO1xyXG5cclxuICAgIGNvbnN0IHN0cmluZ1NjaGVtYTIgPSB6XHJcbiAgICAgIC5zdHJpbmcoKVxyXG4gICAgICAudHJpbSgpXHJcbiAgICAgIC5yZWZpbmUoXHJcbiAgICAgICAgKHZhbHVlKSA9PlxyXG4gICAgICAgICAgKHZhbHVlLnN0YXJ0c1dpdGgoJ3snKSAmJiB2YWx1ZS5lbmRzV2l0aCgnfScpKSB8fFxyXG4gICAgICAgICAgKHZhbHVlLmxlbmd0aCA+PSA2ICYmIHZhbHVlLmVuZHNXaXRoKCcuanNvbicpKSB8fFxyXG4gICAgICAgICAgWyd1bmRlZmluZWQnLCAnbnVsbCcsICcnXS5pbmNsdWRlcyh2YWx1ZSksXHJcbiAgICAgICAge1xyXG4gICAgICAgICAgcGFyYW1zOiB7XHJcbiAgICAgICAgICAgIGVycm9yTWVzc2FnZTogJ1RoZSB2YWx1ZSBtdXN0IGJlIGEgc3RyaW5nIHRoYXQgZW5kcyB3aXRoIC5qc29uJ1xyXG4gICAgICAgICAgfVxyXG4gICAgICAgIH1cclxuICAgICAgKVxyXG4gICAgICAudHJhbnNmb3JtKCh2YWx1ZSkgPT5cclxuICAgICAgICAhWyd1bmRlZmluZWQnLCAnbnVsbCcsICcnXS5pbmNsdWRlcyh2YWx1ZSkgPyB2YWx1ZSA6IG51bGxcclxuICAgICAgKTtcclxuXHJcbiAgICByZXR1cm4gc3RyaWN0Q2hlY2tcclxuICAgICAgPyB6LnVuaW9uKFtvYmplY3RTY2hlbWEsIHN0cmluZ1NjaGVtYTFdKS5udWxsYWJsZSgpXHJcbiAgICAgIDogei51bmlvbihbb2JqZWN0U2NoZW1hLCBzdHJpbmdTY2hlbWEyXSkubnVsbGFibGUoKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYGxvYWRDb25maWdgIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGggYW4gb3B0aW9uYWxcclxuICAgKiBzdHJpY3RlciBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGUgc2FtZSB3b3JrIGFzIHRoZSBgc3RyaW5nYCB2YWxpZGF0b3IuXHJcbiAgICogQWRkaXRpb25hbGx5LCBpdCBtdXN0IGJlIGEgc3RyaW5nIHRoYXQgZW5kcyB3aXRoICcuanNvbicuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gbG9hZENvbmZpZ1xyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nIHRoZSBgbG9hZENvbmZpZ2BcclxuICAgKiBvcHRpb24uXHJcbiAgICovXHJcbiAgbG9hZENvbmZpZyhzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHZcclxuICAgICAgLnN0cmluZyhzdHJpY3RDaGVjaylcclxuICAgICAgLnJlZmluZShcclxuICAgICAgICAodmFsdWUpID0+XHJcbiAgICAgICAgICB2YWx1ZSA9PT0gbnVsbCB8fCAodmFsdWUubGVuZ3RoID49IDYgJiYgdmFsdWUuZW5kc1dpdGgoJy5qc29uJykpLFxyXG4gICAgICAgIHtcclxuICAgICAgICAgIHBhcmFtczoge1xyXG4gICAgICAgICAgICBlcnJvck1lc3NhZ2U6ICdUaGUgdmFsdWUgbXVzdCBiZSBhIHN0cmluZyB0aGF0IGVuZHMgd2l0aCAuanNvbidcclxuICAgICAgICAgIH1cclxuICAgICAgICB9XHJcbiAgICAgICk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGBjcmVhdGVDb25maWdgIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGggYW4gb3B0aW9uYWxcclxuICAgKiBzdHJpY3RlciBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGUgc2FtZSB3b3JrIGFzIHRoZSBgbG9hZENvbmZpZ2AgdmFsaWRhdG9yLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIGNyZWF0ZUNvbmZpZ1xyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nXHJcbiAgICogdGhlIGBjcmVhdGVDb25maWdgIG9wdGlvbi5cclxuICAgKi9cclxuICBjcmVhdGVDb25maWcoc3RyaWN0Q2hlY2spIHtcclxuICAgIHJldHVybiB0aGlzLmxvYWRDb25maWcoc3RyaWN0Q2hlY2spO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgZW5hYmxlU2VydmVyYCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoIGFuIG9wdGlvbmFsXHJcbiAgICogc3RyaWN0ZXIgY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhlIHNhbWUgd29yayBhcyB0aGUgYGJvb2xlYW5gIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiBlbmFibGVTZXJ2ZXJcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZ1xyXG4gICAqIHRoZSBgZW5hYmxlU2VydmVyYCBvcHRpb24uXHJcbiAgICovXHJcbiAgZW5hYmxlU2VydmVyKHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gdi5ib29sZWFuKHN0cmljdENoZWNrKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYGhvc3RgIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGggYW4gb3B0aW9uYWwgc3RyaWN0ZXJcclxuICAgKiBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGUgc2FtZSB3b3JrIGFzIHRoZSBgc3RyaW5nYCB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gaG9zdFxyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nIHRoZSBgaG9zdGBcclxuICAgKiBvcHRpb24uXHJcbiAgICovXHJcbiAgaG9zdChzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHYuc3RyaW5nKHN0cmljdENoZWNrKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYHBvcnRgIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGggYW4gb3B0aW9uYWwgc3RyaWN0ZXJcclxuICAgKiBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGUgc2FtZSB3b3JrIGFzIHRoZSBgbm9uTmVnYXRpdmVOdW1gXHJcbiAgICogdmFsaWRhdG9yLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIHBvcnRcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZyB0aGUgYHBvcnRgXHJcbiAgICogb3B0aW9uLlxyXG4gICAqL1xyXG4gIHBvcnQoc3RyaWN0Q2hlY2spIHtcclxuICAgIHJldHVybiB2Lm5vbk5lZ2F0aXZlTnVtKHN0cmljdENoZWNrKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYHVwbG9hZExpbWl0YCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoIGFuIG9wdGlvbmFsXHJcbiAgICogc3RyaWN0ZXIgY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhlIHNhbWUgd29yayBhcyB0aGUgYHBvc2l0aXZlTnVtYCB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gdXBsb2FkTGltaXRcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZyB0aGUgYHVwbG9hZExpbWl0YFxyXG4gICAqIG9wdGlvbi5cclxuICAgKi9cclxuICB1cGxvYWRMaW1pdChzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHYucG9zaXRpdmVOdW0oc3RyaWN0Q2hlY2spO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgc2VydmVyQmVuY2htYXJraW5nYCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoXHJcbiAgICogYW4gb3B0aW9uYWwgc3RyaWN0ZXIgY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhlIHNhbWUgd29yayBhcyB0aGUgYGJvb2xlYW5gIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiBzZXJ2ZXJCZW5jaG1hcmtpbmdcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZ1xyXG4gICAqIHRoZSBgc2VydmVyQmVuY2htYXJraW5nYCBvcHRpb24uXHJcbiAgICovXHJcbiAgc2VydmVyQmVuY2htYXJraW5nKHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gdi5ib29sZWFuKHN0cmljdENoZWNrKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYHByb3h5SG9zdGAgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbFxyXG4gICAqIHN0cmljdGVyIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgdGhlIGBzdHJpbmdgIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiBwcm94eUhvc3RcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZyB0aGUgYHByb3h5SG9zdGBcclxuICAgKiBvcHRpb24uXHJcbiAgICovXHJcbiAgcHJveHlIb3N0KHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gdi5zdHJpbmcoc3RyaWN0Q2hlY2spO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgcHJveHlQb3J0YCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoIGFuIG9wdGlvbmFsXHJcbiAgICogc3RyaWN0ZXIgY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhlIHNhbWUgd29yayBhcyBhIG51bGxhYmxlIGBub25OZWdhdGl2ZU51bWBcclxuICAgKiB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gcHJveHlQb3J0XHJcbiAgICpcclxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IHN0cmljdENoZWNrIC0gRGV0ZXJtaW5lcyBpZiBzdHJpY3RlciB2YWxpZGF0aW9uIHNob3VsZFxyXG4gICAqIGJlIGFwcGxpZWQuXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9IEEgWm9kIHNjaGVtYSBvYmplY3QgZm9yIHZhbGlkYXRpbmcgdGhlIGBwcm94eVBvcnRgXHJcbiAgICogb3B0aW9uLlxyXG4gICAqL1xyXG4gIHByb3h5UG9ydChzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHYubm9uTmVnYXRpdmVOdW0oc3RyaWN0Q2hlY2spLm51bGxhYmxlKCk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGBwcm94eVRpbWVvdXRgIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGggYW4gb3B0aW9uYWxcclxuICAgKiBzdHJpY3RlciBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGUgc2FtZSB3b3JrIGFzIHRoZSBgbm9uTmVnYXRpdmVOdW1gXHJcbiAgICogdmFsaWRhdG9yLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIHByb3h5VGltZW91dFxyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nXHJcbiAgICogdGhlIGBwcm94eVRpbWVvdXRgIG9wdGlvbi5cclxuICAgKi9cclxuICBwcm94eVRpbWVvdXQoc3RyaWN0Q2hlY2spIHtcclxuICAgIHJldHVybiB2Lm5vbk5lZ2F0aXZlTnVtKHN0cmljdENoZWNrKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYGVuYWJsZVJhdGVMaW1pdGluZ2AgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aFxyXG4gICAqIGFuIG9wdGlvbmFsIHN0cmljdGVyIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgdGhlIGBib29sZWFuYCB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gZW5hYmxlUmF0ZUxpbWl0aW5nXHJcbiAgICpcclxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IHN0cmljdENoZWNrIC0gRGV0ZXJtaW5lcyBpZiBzdHJpY3RlciB2YWxpZGF0aW9uIHNob3VsZFxyXG4gICAqIGJlIGFwcGxpZWQuXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9IEEgWm9kIHNjaGVtYSBvYmplY3QgZm9yIHZhbGlkYXRpbmdcclxuICAgKiB0aGUgYGVuYWJsZVJhdGVMaW1pdGluZ2Agb3B0aW9uLlxyXG4gICAqL1xyXG4gIGVuYWJsZVJhdGVMaW1pdGluZyhzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHYuYm9vbGVhbihzdHJpY3RDaGVjayk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGBtYXhSZXF1ZXN0c2AgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbFxyXG4gICAqIHN0cmljdGVyIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgdGhlIGBub25OZWdhdGl2ZU51bWBcclxuICAgKiB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gbWF4UmVxdWVzdHNcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZyB0aGUgYG1heFJlcXVlc3RzYFxyXG4gICAqIG9wdGlvbi5cclxuICAgKi9cclxuICBtYXhSZXF1ZXN0cyhzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHYubm9uTmVnYXRpdmVOdW0oc3RyaWN0Q2hlY2spO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgd2luZG93YCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoIGFuIG9wdGlvbmFsIHN0cmljdGVyXHJcbiAgICogY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhlIHNhbWUgd29yayBhcyB0aGUgYG5vbk5lZ2F0aXZlTnVtYFxyXG4gICAqIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiB3aW5kb3dcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZyB0aGUgYHdpbmRvd2BcclxuICAgKiBvcHRpb24uXHJcbiAgICovXHJcbiAgd2luZG93KHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gdi5ub25OZWdhdGl2ZU51bShzdHJpY3RDaGVjayk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGBkZWxheWAgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbCBzdHJpY3RlclxyXG4gICAqIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgdGhlIGBub25OZWdhdGl2ZU51bWBcclxuICAgKiB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gZGVsYXlcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZyB0aGUgYGRlbGF5YFxyXG4gICAqIG9wdGlvbi5cclxuICAgKi9cclxuICBkZWxheShzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHYubm9uTmVnYXRpdmVOdW0oc3RyaWN0Q2hlY2spO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgdHJ1c3RQcm94eWAgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbFxyXG4gICAqIHN0cmljdGVyIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgdGhlIGBib29sZWFuYCB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gdHJ1c3RQcm94eVxyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nIHRoZSBgdHJ1c3RQcm94eWBcclxuICAgKiBvcHRpb24uXHJcbiAgICovXHJcbiAgdHJ1c3RQcm94eShzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHYuYm9vbGVhbihzdHJpY3RDaGVjayk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGBza2lwS2V5YCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoIGFuIG9wdGlvbmFsIHN0cmljdGVyXHJcbiAgICogY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhlIHNhbWUgd29yayBhcyB0aGUgYHN0cmluZ2AgdmFsaWRhdG9yLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIHNraXBLZXlcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZyB0aGUgYHNraXBLZXlgXHJcbiAgICogb3B0aW9uLlxyXG4gICAqL1xyXG4gIHNraXBLZXkoc3RyaWN0Q2hlY2spIHtcclxuICAgIHJldHVybiB2LnN0cmluZyhzdHJpY3RDaGVjayk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGBza2lwVG9rZW5gIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGggYW4gb3B0aW9uYWxcclxuICAgKiBzdHJpY3RlciBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGUgc2FtZSB3b3JrIGFzIHRoZSBgc3RyaW5nYCB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gc2tpcFRva2VuXHJcbiAgICpcclxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IHN0cmljdENoZWNrIC0gRGV0ZXJtaW5lcyBpZiBzdHJpY3RlciB2YWxpZGF0aW9uIHNob3VsZFxyXG4gICAqIGJlIGFwcGxpZWQuXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9IEEgWm9kIHNjaGVtYSBvYmplY3QgZm9yIHZhbGlkYXRpbmcgdGhlIGBza2lwVG9rZW5gXHJcbiAgICogb3B0aW9uLlxyXG4gICAqL1xyXG4gIHNraXBUb2tlbihzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHYuc3RyaW5nKHN0cmljdENoZWNrKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYGVuYWJsZVNzbGAgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbFxyXG4gICAqIHN0cmljdGVyIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgdGhlIGBib29sZWFuYCB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gZW5hYmxlU3NsXHJcbiAgICpcclxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IHN0cmljdENoZWNrIC0gRGV0ZXJtaW5lcyBpZiBzdHJpY3RlciB2YWxpZGF0aW9uIHNob3VsZFxyXG4gICAqIGJlIGFwcGxpZWQuXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9IEEgWm9kIHNjaGVtYSBvYmplY3QgZm9yIHZhbGlkYXRpbmcgdGhlIGBlbmFibGVTc2xgXHJcbiAgICogb3B0aW9uLlxyXG4gICAqL1xyXG4gIGVuYWJsZVNzbChzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHYuYm9vbGVhbihzdHJpY3RDaGVjayk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGBzc2xGb3JjZWAgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbFxyXG4gICAqIHN0cmljdGVyIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgdGhlIGBib29sZWFuYCB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gc3NsRm9yY2VcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZyB0aGUgYHNzbEZvcmNlYFxyXG4gICAqIG9wdGlvbi5cclxuICAgKi9cclxuICBzc2xGb3JjZShzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHYuYm9vbGVhbihzdHJpY3RDaGVjayk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGBzc2xQb3J0YCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoIGFuIG9wdGlvbmFsIHN0cmljdGVyXHJcbiAgICogY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhlIHNhbWUgd29yayBhcyB0aGUgYG5vbk5lZ2F0aXZlTnVtYFxyXG4gICAqIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiBzc2xQb3J0XHJcbiAgICpcclxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IHN0cmljdENoZWNrIC0gRGV0ZXJtaW5lcyBpZiBzdHJpY3RlciB2YWxpZGF0aW9uIHNob3VsZFxyXG4gICAqIGJlIGFwcGxpZWQuXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9IEEgWm9kIHNjaGVtYSBvYmplY3QgZm9yIHZhbGlkYXRpbmcgdGhlIGBzc2xQb3J0YFxyXG4gICAqIG9wdGlvbi5cclxuICAgKi9cclxuICBzc2xQb3J0KHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gdi5ub25OZWdhdGl2ZU51bShzdHJpY3RDaGVjayk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGBzc2xDZXJ0UGF0aGAgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbFxyXG4gICAqIHN0cmljdGVyIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgdGhlIGBzdHJpbmdgIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiBzc2xDZXJ0UGF0aFxyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nIHRoZSBgc3NsQ2VydFBhdGhgXHJcbiAgICogb3B0aW9uLlxyXG4gICAqL1xyXG4gIHNzbENlcnRQYXRoKHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gdi5zdHJpbmcoc3RyaWN0Q2hlY2spO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgbWluV29ya2Vyc2AgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbFxyXG4gICAqIHN0cmljdGVyIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgdGhlIGBwb3NpdGl2ZU51bWAgdmFsaWRhdG9yLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIG1pbldvcmtlcnNcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZyB0aGUgYG1pbldvcmtlcnNgXHJcbiAgICogb3B0aW9uLlxyXG4gICAqL1xyXG4gIG1pbldvcmtlcnMoc3RyaWN0Q2hlY2spIHtcclxuICAgIHJldHVybiB2LnBvc2l0aXZlTnVtKHN0cmljdENoZWNrKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYG1heFdvcmtlcnNgIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGggYW4gb3B0aW9uYWxcclxuICAgKiBzdHJpY3RlciBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGUgc2FtZSB3b3JrIGFzIHRoZSBgcG9zaXRpdmVOdW1gIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiBtYXhXb3JrZXJzXHJcbiAgICpcclxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IHN0cmljdENoZWNrIC0gRGV0ZXJtaW5lcyBpZiBzdHJpY3RlciB2YWxpZGF0aW9uIHNob3VsZFxyXG4gICAqIGJlIGFwcGxpZWQuXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9IEEgWm9kIHNjaGVtYSBvYmplY3QgZm9yIHZhbGlkYXRpbmcgdGhlIGBtYXhXb3JrZXJzYFxyXG4gICAqIG9wdGlvbi5cclxuICAgKi9cclxuICBtYXhXb3JrZXJzKHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gdi5wb3NpdGl2ZU51bShzdHJpY3RDaGVjayk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGB3b3JrTGltaXRgIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGggYW4gb3B0aW9uYWxcclxuICAgKiBzdHJpY3RlciBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGUgc2FtZSB3b3JrIGFzIHRoZSBgcG9zaXRpdmVOdW1gIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiB3b3JrTGltaXRcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZyB0aGUgYHdvcmtMaW1pdGBcclxuICAgKiBvcHRpb24uXHJcbiAgICovXHJcbiAgd29ya0xpbWl0KHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gdi5wb3NpdGl2ZU51bShzdHJpY3RDaGVjayk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGBhY3F1aXJlVGltZW91dGAgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbFxyXG4gICAqIHN0cmljdGVyIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgdGhlIGBub25OZWdhdGl2ZU51bWBcclxuICAgKiB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gYWNxdWlyZVRpbWVvdXRcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZ1xyXG4gICAqIHRoZSBgYWNxdWlyZVRpbWVvdXRgIG9wdGlvbi5cclxuICAgKi9cclxuICBhY3F1aXJlVGltZW91dChzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHYubm9uTmVnYXRpdmVOdW0oc3RyaWN0Q2hlY2spO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgY3JlYXRlVGltZW91dGAgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbFxyXG4gICAqIHN0cmljdGVyIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgdGhlIGBub25OZWdhdGl2ZU51bWBcclxuICAgKiB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gY3JlYXRlVGltZW91dFxyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nXHJcbiAgICogdGhlIGBjcmVhdGVUaW1lb3V0YCBvcHRpb24uXHJcbiAgICovXHJcbiAgY3JlYXRlVGltZW91dChzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHYubm9uTmVnYXRpdmVOdW0oc3RyaWN0Q2hlY2spO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgZGVzdHJveVRpbWVvdXRgIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGggYW4gb3B0aW9uYWxcclxuICAgKiBzdHJpY3RlciBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGUgc2FtZSB3b3JrIGFzIHRoZSBgbm9uTmVnYXRpdmVOdW1gXHJcbiAgICogdmFsaWRhdG9yLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIGRlc3Ryb3lUaW1lb3V0XHJcbiAgICpcclxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IHN0cmljdENoZWNrIC0gRGV0ZXJtaW5lcyBpZiBzdHJpY3RlciB2YWxpZGF0aW9uIHNob3VsZFxyXG4gICAqIGJlIGFwcGxpZWQuXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9IEEgWm9kIHNjaGVtYSBvYmplY3QgZm9yIHZhbGlkYXRpbmdcclxuICAgKiB0aGUgYGRlc3Ryb3lUaW1lb3V0YCBvcHRpb24uXHJcbiAgICovXHJcbiAgZGVzdHJveVRpbWVvdXQoc3RyaWN0Q2hlY2spIHtcclxuICAgIHJldHVybiB2Lm5vbk5lZ2F0aXZlTnVtKHN0cmljdENoZWNrKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYGlkbGVUaW1lb3V0YCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoIGFuIG9wdGlvbmFsXHJcbiAgICogc3RyaWN0ZXIgY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhlIHNhbWUgd29yayBhcyB0aGUgYG5vbk5lZ2F0aXZlTnVtYFxyXG4gICAqIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiBpZGxlVGltZW91dFxyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nXHJcbiAgICogdGhlIGBpZGxlVGltZW91dGAgb3B0aW9uLlxyXG4gICAqL1xyXG4gIGlkbGVUaW1lb3V0KHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gdi5ub25OZWdhdGl2ZU51bShzdHJpY3RDaGVjayk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGBjcmVhdGVSZXRyeUludGVydmFsYCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoXHJcbiAgICogYW4gb3B0aW9uYWwgc3RyaWN0ZXIgY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhlIHNhbWUgd29yayBhcyB0aGUgYG5vbk5lZ2F0aXZlTnVtYFxyXG4gICAqIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiBjcmVhdGVSZXRyeUludGVydmFsXHJcbiAgICpcclxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IHN0cmljdENoZWNrIC0gRGV0ZXJtaW5lcyBpZiBzdHJpY3RlciB2YWxpZGF0aW9uIHNob3VsZFxyXG4gICAqIGJlIGFwcGxpZWQuXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9IEEgWm9kIHNjaGVtYSBvYmplY3QgZm9yIHZhbGlkYXRpbmdcclxuICAgKiB0aGUgYGNyZWF0ZVJldHJ5SW50ZXJ2YWxgIG9wdGlvbi5cclxuICAgKi9cclxuICBjcmVhdGVSZXRyeUludGVydmFsKHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gdi5ub25OZWdhdGl2ZU51bShzdHJpY3RDaGVjayk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGByZWFwZXJJbnRlcnZhbGAgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbFxyXG4gICAqIHN0cmljdGVyIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgdGhlIGBub25OZWdhdGl2ZU51bWBcclxuICAgKiB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gcmVhcGVySW50ZXJ2YWxcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZ1xyXG4gICAqIHRoZSBgcmVhcGVySW50ZXJ2YWxgIG9wdGlvbi5cclxuICAgKi9cclxuICByZWFwZXJJbnRlcnZhbChzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHYubm9uTmVnYXRpdmVOdW0oc3RyaWN0Q2hlY2spO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgcG9vbEJlbmNobWFya2luZ2AgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbFxyXG4gICAqIHN0cmljdGVyIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgdGhlIGBib29sZWFuYCB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gcG9vbEJlbmNobWFya2luZ1xyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nXHJcbiAgICogdGhlIGBwb29sQmVuY2htYXJraW5nYCBvcHRpb24uXHJcbiAgICovXHJcbiAgcG9vbEJlbmNobWFya2luZyhzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHYuYm9vbGVhbihzdHJpY3RDaGVjayk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGByZXNvdXJjZXNJbnRlcnZhbGAgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aFxyXG4gICAqIGFuIG9wdGlvbmFsIHN0cmljdGVyIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgdGhlIGBub25OZWdhdGl2ZU51bWBcclxuICAgKiB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gcmVzb3VyY2VzSW50ZXJ2YWxcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZ1xyXG4gICAqIHRoZSBgcmVzb3VyY2VzSW50ZXJ2YWxgIG9wdGlvbi5cclxuICAgKi9cclxuICByZXNvdXJjZXNJbnRlcnZhbChzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHYubm9uTmVnYXRpdmVOdW0oc3RyaWN0Q2hlY2spO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgbG9nTGV2ZWxgIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGggYW4gb3B0aW9uYWxcclxuICAgKiBzdHJpY3RlciBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGF0OlxyXG4gICAqXHJcbiAgICogLSBXaGVuIGBzdHJpY3RDaGVja2AgaXMgdHJ1ZSwgdGhlIHNjaGVtYSB3aWxsIGFjY2VwdCBpbnRlZ2VyIG51bWJlciB2YWx1ZXNcclxuICAgKiB0aGF0IGFyZSBiZXR3ZWVuIDAgYW5kIDUgKGluY2x1c2l2ZSkuXHJcbiAgICpcclxuICAgKiAtIFdoZW4gYHN0cmljdENoZWNrYCBpcyBmYWxzZSwgdGhlIHNjaGVtYSB3aWxsIGFjY2VwdCBpbnRlZ2VyIG51bWJlciB2YWx1ZXNcclxuICAgKiBhbmQgc3RyaW5naWZpZWQgaW50ZWdlciBudW1iZXIgdmFsdWVzIHRoYXQgYXJlIGJldHdlZW4gMSBhbmQgNSAoaW5jbHVzaXZlKSxcclxuICAgKiBudWxsLCAndW5kZWZpbmVkJywgJ251bGwnLCBhbmQgJycgd2hpY2ggd2lsbCBiZSB0cmFuc2Zvcm1lZCB0byBudWxsLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIGxvZ0xldmVsXHJcbiAgICpcclxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IHN0cmljdENoZWNrIC0gRGV0ZXJtaW5lcyBpZiBzdHJpY3RlciB2YWxpZGF0aW9uIHNob3VsZFxyXG4gICAqIGJlIGFwcGxpZWQuXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9IEEgWm9kIHNjaGVtYSBvYmplY3QgZm9yIHZhbGlkYXRpbmcgdGhlIGBsb2dMZXZlbGBcclxuICAgKiBvcHRpb24uXHJcbiAgICovXHJcbiAgbG9nTGV2ZWwoc3RyaWN0Q2hlY2spIHtcclxuICAgIHJldHVybiBzdHJpY3RDaGVja1xyXG4gICAgICA/IHoubnVtYmVyKCkuaW50KCkuZ3RlKDApLmx0ZSg1KVxyXG4gICAgICA6IHpcclxuICAgICAgICAgIC51bmlvbihbXHJcbiAgICAgICAgICAgIHpcclxuICAgICAgICAgICAgICAuc3RyaW5nKClcclxuICAgICAgICAgICAgICAudHJpbSgpXHJcbiAgICAgICAgICAgICAgLnJlZmluZShcclxuICAgICAgICAgICAgICAgICh2YWx1ZSkgPT5cclxuICAgICAgICAgICAgICAgICAgKCFpc05hTihOdW1iZXIodmFsdWUpKSAmJlxyXG4gICAgICAgICAgICAgICAgICAgIHZhbHVlICE9PSB0cnVlICYmXHJcbiAgICAgICAgICAgICAgICAgICAgIXZhbHVlLnN0YXJ0c1dpdGgoJ1snKSAmJlxyXG4gICAgICAgICAgICAgICAgICAgIE51bWJlci5pc0ludGVnZXIoTnVtYmVyKHZhbHVlKSkgJiZcclxuICAgICAgICAgICAgICAgICAgICBOdW1iZXIodmFsdWUpID49IDAgJiZcclxuICAgICAgICAgICAgICAgICAgICBOdW1iZXIodmFsdWUpIDw9IDUpIHx8XHJcbiAgICAgICAgICAgICAgICAgIFsndW5kZWZpbmVkJywgJ251bGwnLCAnJ10uaW5jbHVkZXModmFsdWUpLFxyXG4gICAgICAgICAgICAgICAge1xyXG4gICAgICAgICAgICAgICAgICBwYXJhbXM6IHtcclxuICAgICAgICAgICAgICAgICAgICBlcnJvck1lc3NhZ2U6ICdUaGUgdmFsdWUgbXVzdCBiZSB3aXRoaW4gYSAwIGFuZCA1IHJhbmdlJ1xyXG4gICAgICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgICAgKVxyXG4gICAgICAgICAgICAgIC50cmFuc2Zvcm0oKHZhbHVlKSA9PlxyXG4gICAgICAgICAgICAgICAgIVsndW5kZWZpbmVkJywgJ251bGwnLCAnJ10uaW5jbHVkZXModmFsdWUpXHJcbiAgICAgICAgICAgICAgICAgID8gTnVtYmVyKHZhbHVlKVxyXG4gICAgICAgICAgICAgICAgICA6IG51bGxcclxuICAgICAgICAgICAgICApLFxyXG4gICAgICAgICAgICB6Lm51bWJlcigpLmludCgpLmd0ZSgwKS5sdGUoNSlcclxuICAgICAgICAgIF0pXHJcbiAgICAgICAgICAubnVsbGFibGUoKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYGxvZ0ZpbGVgIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGggYW4gb3B0aW9uYWwgc3RyaWN0ZXJcclxuICAgKiBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGUgc2FtZSB3b3JrIGFzIHRoZSBgc3RyaW5nYCB2YWxpZGF0b3IuXHJcbiAgICogQWRkaXRpb25hbGx5LCBpdCBtdXN0IGJlIGEgc3RyaW5nIHRoYXQgZW5kcyB3aXRoICcubG9nJy5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiBsb2dGaWxlXHJcbiAgICpcclxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IHN0cmljdENoZWNrIC0gRGV0ZXJtaW5lcyBpZiBzdHJpY3RlciB2YWxpZGF0aW9uIHNob3VsZFxyXG4gICAqIGJlIGFwcGxpZWQuXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9IEEgWm9kIHNjaGVtYSBvYmplY3QgZm9yIHZhbGlkYXRpbmcgdGhlIGBsb2dGaWxlYFxyXG4gICAqIG9wdGlvbi5cclxuICAgKi9cclxuICBsb2dGaWxlKHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gdlxyXG4gICAgICAuc3RyaW5nKHN0cmljdENoZWNrKVxyXG4gICAgICAucmVmaW5lKFxyXG4gICAgICAgICh2YWx1ZSkgPT5cclxuICAgICAgICAgIHZhbHVlID09PSBudWxsIHx8ICh2YWx1ZS5sZW5ndGggPj0gNSAmJiB2YWx1ZS5lbmRzV2l0aCgnLmxvZycpKSxcclxuICAgICAgICB7XHJcbiAgICAgICAgICBwYXJhbXM6IHtcclxuICAgICAgICAgICAgZXJyb3JNZXNzYWdlOiAnVGhlIHZhbHVlIG11c3QgYmUgYSBzdHJpbmcgdGhhdCBlbmRzIHdpdGggLmxvZydcclxuICAgICAgICAgIH1cclxuICAgICAgICB9XHJcbiAgICAgICk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGBsb2dEZXN0YCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoIGFuIG9wdGlvbmFsIHN0cmljdGVyXHJcbiAgICogY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhlIHNhbWUgd29yayBhcyB0aGUgYHN0cmluZ2AgdmFsaWRhdG9yLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIGxvZ0Rlc3RcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZyB0aGUgYGxvZ0Rlc3RgXHJcbiAgICogb3B0aW9uLlxyXG4gICAqL1xyXG4gIGxvZ0Rlc3Qoc3RyaWN0Q2hlY2spIHtcclxuICAgIHJldHVybiB2LnN0cmluZyhzdHJpY3RDaGVjayk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGBsb2dUb0NvbnNvbGVgIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGggYW4gb3B0aW9uYWxcclxuICAgKiBzdHJpY3RlciBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGUgc2FtZSB3b3JrIGFzIHRoZSBgYm9vbGVhbmAgdmFsaWRhdG9yLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIGxvZ1RvQ29uc29sZVxyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nXHJcbiAgICogdGhlIGBsb2dUb0NvbnNvbGVgIG9wdGlvbi5cclxuICAgKi9cclxuICBsb2dUb0NvbnNvbGUoc3RyaWN0Q2hlY2spIHtcclxuICAgIHJldHVybiB2LmJvb2xlYW4oc3RyaWN0Q2hlY2spO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgbG9nVG9GaWxlYCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoIGFuIG9wdGlvbmFsXHJcbiAgICogc3RyaWN0ZXIgY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhlIHNhbWUgd29yayBhcyB0aGUgYGJvb2xlYW5gIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiBsb2dUb0ZpbGVcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZyB0aGUgYGxvZ1RvRmlsZWBcclxuICAgKiBvcHRpb24uXHJcbiAgICovXHJcbiAgbG9nVG9GaWxlKHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gdi5ib29sZWFuKHN0cmljdENoZWNrKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYGVuYWJsZVVpYCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoIGFuIG9wdGlvbmFsXHJcbiAgICogc3RyaWN0ZXIgY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhlIHNhbWUgd29yayBhcyB0aGUgYGJvb2xlYW5gIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiBlbmFibGVVaVxyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nIHRoZSBgZW5hYmxlVWlgXHJcbiAgICogb3B0aW9uLlxyXG4gICAqL1xyXG4gIGVuYWJsZVVpKHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gdi5ib29sZWFuKHN0cmljdENoZWNrKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYHVpUm91dGVgIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGggYW4gb3B0aW9uYWxcclxuICAgKiBzdHJpY3RlciBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGUgc2FtZSB3b3JrIGFzIHRoZSBgc3RhcnRzV2l0aGAgdmFsaWRhdG9yLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIHVpUm91dGVcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZyB0aGUgYHVpUm91dGVgXHJcbiAgICogb3B0aW9uLlxyXG4gICAqL1xyXG4gIHVpUm91dGUoc3RyaWN0Q2hlY2spIHtcclxuICAgIHJldHVybiB2LnN0YXJ0c1dpdGgoWycvJ10sIHN0cmljdENoZWNrKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYG5vZGVFbnZgIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGggYW4gb3B0aW9uYWxcclxuICAgKiBzdHJpY3RlciBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGUgc2FtZSB3b3JrIGFzIHRoZSBgZW51bWAgdmFsaWRhdG9yLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIG5vZGVFbnZcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZyB0aGUgYG5vZGVFbnZgXHJcbiAgICogb3B0aW9uLlxyXG4gICAqL1xyXG4gIG5vZGVFbnYoc3RyaWN0Q2hlY2spIHtcclxuICAgIHJldHVybiB2LmVudW0oWydkZXZlbG9wbWVudCcsICdwcm9kdWN0aW9uJywgJ3Rlc3QnXSwgc3RyaWN0Q2hlY2spO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgbGlzdGVuVG9Qcm9jZXNzRXhpdHNgIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGhcclxuICAgKiBhbiBvcHRpb25hbCBzdHJpY3RlciBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGUgc2FtZSB3b3JrIGFzIHRoZSBgYm9vbGVhbmAgdmFsaWRhdG9yLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIGxpc3RlblRvUHJvY2Vzc0V4aXRzXHJcbiAgICpcclxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IHN0cmljdENoZWNrIC0gRGV0ZXJtaW5lcyBpZiBzdHJpY3RlciB2YWxpZGF0aW9uIHNob3VsZFxyXG4gICAqIGJlIGFwcGxpZWQuXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9IEEgWm9kIHNjaGVtYSBvYmplY3QgZm9yIHZhbGlkYXRpbmdcclxuICAgKiB0aGUgYGxpc3RlblRvUHJvY2Vzc0V4aXRzYCBvcHRpb24uXHJcbiAgICovXHJcbiAgbGlzdGVuVG9Qcm9jZXNzRXhpdHMoc3RyaWN0Q2hlY2spIHtcclxuICAgIHJldHVybiB2LmJvb2xlYW4oc3RyaWN0Q2hlY2spO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgbm9Mb2dvYCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoIGFuIG9wdGlvbmFsXHJcbiAgICogc3RyaWN0ZXIgY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhlIHNhbWUgd29yayBhcyB0aGUgYGJvb2xlYW5gIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiBub0xvZ29cclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZyB0aGUgYG5vTG9nb2BcclxuICAgKiBvcHRpb24uXHJcbiAgICovXHJcbiAgbm9Mb2dvKHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gdi5ib29sZWFuKHN0cmljdENoZWNrKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYGhhcmRSZXNldFBhZ2VgIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGggYW4gb3B0aW9uYWxcclxuICAgKiBzdHJpY3RlciBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGUgc2FtZSB3b3JrIGFzIHRoZSBgYm9vbGVhbmAgdmFsaWRhdG9yLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIGhhcmRSZXNldFBhZ2VcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZ1xyXG4gICAqIHRoZSBgaGFyZFJlc2V0UGFnZWAgb3B0aW9uLlxyXG4gICAqL1xyXG4gIGhhcmRSZXNldFBhZ2Uoc3RyaWN0Q2hlY2spIHtcclxuICAgIHJldHVybiB2LmJvb2xlYW4oc3RyaWN0Q2hlY2spO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgYnJvd3NlclNoZWxsTW9kZWAgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbFxyXG4gICAqIHN0cmljdGVyIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgdGhlIGBib29sZWFuYCB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gYnJvd3NlclNoZWxsTW9kZVxyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nXHJcbiAgICogdGhlIGBicm93c2VyU2hlbGxNb2RlYCBvcHRpb24uXHJcbiAgICovXHJcbiAgYnJvd3NlclNoZWxsTW9kZShzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHYuYm9vbGVhbihzdHJpY3RDaGVjayk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGB2YWxpZGF0aW9uYCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoIGFuIG9wdGlvbmFsXHJcbiAgICogc3RyaWN0ZXIgY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhlIHNhbWUgd29yayBhcyB0aGUgYGJvb2xlYW5gIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiB2YWxpZGF0aW9uXHJcbiAgICpcclxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IHN0cmljdENoZWNrIC0gRGV0ZXJtaW5lcyBpZiBzdHJpY3RlciB2YWxpZGF0aW9uIHNob3VsZFxyXG4gICAqIGJlIGFwcGxpZWQuXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9IEEgWm9kIHNjaGVtYSBvYmplY3QgZm9yIHZhbGlkYXRpbmcgdGhlIGB2YWxpZGF0aW9uYFxyXG4gICAqIG9wdGlvbi5cclxuICAgKi9cclxuICB2YWxpZGF0aW9uKHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gdi5ib29sZWFuKHN0cmljdENoZWNrKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYGVuYWJsZURlYnVnYCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoIGFuIG9wdGlvbmFsXHJcbiAgICogc3RyaWN0ZXIgY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhlIHNhbWUgd29yayBhcyB0aGUgYGJvb2xlYW5gIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiBlbmFibGVEZWJ1Z1xyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nIHRoZSBgZW5hYmxlRGVidWdgXHJcbiAgICogb3B0aW9uLlxyXG4gICAqL1xyXG4gIGVuYWJsZURlYnVnKHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gdi5ib29sZWFuKHN0cmljdENoZWNrKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYGhlYWRsZXNzYCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoIGFuIG9wdGlvbmFsXHJcbiAgICogc3RyaWN0ZXIgY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhlIHNhbWUgd29yayBhcyB0aGUgYGJvb2xlYW5gIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiBoZWFkbGVzc1xyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nIHRoZSBgaGVhZGxlc3NgXHJcbiAgICogb3B0aW9uLlxyXG4gICAqL1xyXG4gIGhlYWRsZXNzKHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gdi5ib29sZWFuKHN0cmljdENoZWNrKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYGRldnRvb2xzYCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoIGFuIG9wdGlvbmFsXHJcbiAgICogc3RyaWN0ZXIgY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhlIHNhbWUgd29yayBhcyB0aGUgYGJvb2xlYW5gIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiBkZXZ0b29sc1xyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nIHRoZSBgZGV2dG9vbHNgXHJcbiAgICogb3B0aW9uLlxyXG4gICAqL1xyXG4gIGRldnRvb2xzKHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gdi5ib29sZWFuKHN0cmljdENoZWNrKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYGxpc3RlblRvQ29uc29sZWAgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbFxyXG4gICAqIHN0cmljdGVyIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgdGhlIGBib29sZWFuYCB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gbGlzdGVuVG9Db25zb2xlXHJcbiAgICpcclxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IHN0cmljdENoZWNrIC0gRGV0ZXJtaW5lcyBpZiBzdHJpY3RlciB2YWxpZGF0aW9uIHNob3VsZFxyXG4gICAqIGJlIGFwcGxpZWQuXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9IEEgWm9kIHNjaGVtYSBvYmplY3QgZm9yIHZhbGlkYXRpbmdcclxuICAgKiB0aGUgYGxpc3RlblRvQ29uc29sZWAgb3B0aW9uLlxyXG4gICAqL1xyXG4gIGxpc3RlblRvQ29uc29sZShzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHYuYm9vbGVhbihzdHJpY3RDaGVjayk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGBkdW1waW9gIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGggYW4gb3B0aW9uYWwgc3RyaWN0ZXJcclxuICAgKiBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGUgc2FtZSB3b3JrIGFzIHRoZSBgYm9vbGVhbmAgdmFsaWRhdG9yLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIGR1bXBpb1xyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nIHRoZSBgZHVtcGlvYFxyXG4gICAqIG9wdGlvbi5cclxuICAgKi9cclxuICBkdW1waW8oc3RyaWN0Q2hlY2spIHtcclxuICAgIHJldHVybiB2LmJvb2xlYW4oc3RyaWN0Q2hlY2spO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgc2xvd01vYCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoIGFuIG9wdGlvbmFsIHN0cmljdGVyXHJcbiAgICogY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhlIHNhbWUgd29yayBhcyB0aGUgYG5vbk5lZ2F0aXZlTnVtYFxyXG4gICAqIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiBzbG93TW9cclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZyB0aGUgYHNsb3dNb2BcclxuICAgKiBvcHRpb24uXHJcbiAgICovXHJcbiAgc2xvd01vKHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gdi5ub25OZWdhdGl2ZU51bShzdHJpY3RDaGVjayk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGBkZWJ1Z2dpbmdQb3J0YCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoIGFuIG9wdGlvbmFsXHJcbiAgICogc3RyaWN0ZXIgY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhlIHNhbWUgd29yayBhcyB0aGUgYG5vbk5lZ2F0aXZlTnVtYFxyXG4gICAqIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiBkZWJ1Z2dpbmdQb3J0XHJcbiAgICpcclxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IHN0cmljdENoZWNrIC0gRGV0ZXJtaW5lcyBpZiBzdHJpY3RlciB2YWxpZGF0aW9uIHNob3VsZFxyXG4gICAqIGJlIGFwcGxpZWQuXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9IEEgWm9kIHNjaGVtYSBvYmplY3QgZm9yIHZhbGlkYXRpbmdcclxuICAgKiB0aGUgYGRlYnVnZ2luZ1BvcnRgIG9wdGlvbi5cclxuICAgKi9cclxuICBkZWJ1Z2dpbmdQb3J0KHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gdi5ub25OZWdhdGl2ZU51bShzdHJpY3RDaGVjayk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGByZXF1ZXN0SWRgIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGggYW4gb3B0aW9uYWxcclxuICAgKiBzdHJpY3RlciBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGUgc2FtZSB3b3JrIGFzIHRoZSBgc3RyaW5nYCB2YWxpZGF0b3IuXHJcbiAgICogQWRkaXRpb25hbGx5LCBpdCBtdXN0IGJlIGEgc3RyaW5naWZpZWQgVVVJRCBvciBjYW4gYmUgbnVsbC5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiByZXF1ZXN0SWRcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZyB0aGUgYHJlcXVlc3RJZGBcclxuICAgKiBvcHRpb24uXHJcbiAgICovXHJcbiAgcmVxdWVzdElkKCkge1xyXG4gICAgcmV0dXJuIHpcclxuICAgICAgLnN0cmluZygpXHJcbiAgICAgIC51dWlkKHsgbWVzc2FnZTogJ1RoZSB2YWx1ZSBtdXN0IGJlIGEgc3RyaW5naWZpZWQgVVVJRCcgfSlcclxuICAgICAgLm51bGxhYmxlKCk7XHJcbiAgfVxyXG59O1xyXG5cclxuLy8gU2NoZW1hIGZvciB0aGUgcHVwcGV0ZWVyIHNlY3Rpb24gb2Ygb3B0aW9uc1xyXG5jb25zdCBQdXBwZXRlZXJTY2hlbWEgPSAoc3RyaWN0Q2hlY2spID0+XHJcbiAgelxyXG4gICAgLm9iamVjdCh7XHJcbiAgICAgIGFyZ3M6IHZhbGlkYXRvcnMuYXJncyhzdHJpY3RDaGVjaylcclxuICAgIH0pXHJcbiAgICAucGFydGlhbCgpO1xyXG5cclxuLy8gU2NoZW1hIGZvciB0aGUgaGlnaGNoYXJ0cyBzZWN0aW9uIG9mIG9wdGlvbnNcclxuY29uc3QgSGlnaGNoYXJ0c1NjaGVtYSA9IChzdHJpY3RDaGVjaykgPT5cclxuICB6XHJcbiAgICAub2JqZWN0KHtcclxuICAgICAgdmVyc2lvbjogdmFsaWRhdG9ycy52ZXJzaW9uKHN0cmljdENoZWNrKSxcclxuICAgICAgY2RuVXJsOiB2YWxpZGF0b3JzLmNkblVybChzdHJpY3RDaGVjayksXHJcbiAgICAgIGZvcmNlRmV0Y2g6IHZhbGlkYXRvcnMuZm9yY2VGZXRjaChzdHJpY3RDaGVjayksXHJcbiAgICAgIGNhY2hlUGF0aDogdmFsaWRhdG9ycy5jYWNoZVBhdGgoc3RyaWN0Q2hlY2spLFxyXG4gICAgICBjb3JlU2NyaXB0czogdmFsaWRhdG9ycy5jb3JlU2NyaXB0cyhzdHJpY3RDaGVjayksXHJcbiAgICAgIG1vZHVsZVNjcmlwdHM6IHZhbGlkYXRvcnMubW9kdWxlU2NyaXB0cyhzdHJpY3RDaGVjayksXHJcbiAgICAgIGluZGljYXRvclNjcmlwdHM6IHZhbGlkYXRvcnMuaW5kaWNhdG9yU2NyaXB0cyhzdHJpY3RDaGVjayksXHJcbiAgICAgIGN1c3RvbVNjcmlwdHM6IHZhbGlkYXRvcnMuY3VzdG9tU2NyaXB0cyhzdHJpY3RDaGVjaylcclxuICAgIH0pXHJcbiAgICAucGFydGlhbCgpO1xyXG5cclxuLy8gU2NoZW1hIGZvciB0aGUgZXhwb3J0IHNlY3Rpb24gb2Ygb3B0aW9uc1xyXG5jb25zdCBFeHBvcnRTY2hlbWEgPSAoc3RyaWN0Q2hlY2spID0+XHJcbiAgelxyXG4gICAgLm9iamVjdCh7XHJcbiAgICAgIGluZmlsZTogdmFsaWRhdG9ycy5pbmZpbGUoc3RyaWN0Q2hlY2spLFxyXG4gICAgICBpbnN0cjogdmFsaWRhdG9ycy5pbnN0cigpLFxyXG4gICAgICBvcHRpb25zOiB2YWxpZGF0b3JzLm9wdGlvbnMoKSxcclxuICAgICAgc3ZnOiB2YWxpZGF0b3JzLnN2ZygpLFxyXG4gICAgICBvdXRmaWxlOiB2YWxpZGF0b3JzLm91dGZpbGUoc3RyaWN0Q2hlY2spLFxyXG4gICAgICB0eXBlOiB2YWxpZGF0b3JzLnR5cGUoc3RyaWN0Q2hlY2spLFxyXG4gICAgICBjb25zdHI6IHZhbGlkYXRvcnMuY29uc3RyKHN0cmljdENoZWNrKSxcclxuICAgICAgYjY0OiB2YWxpZGF0b3JzLmI2NChzdHJpY3RDaGVjayksXHJcbiAgICAgIG5vRG93bmxvYWQ6IHZhbGlkYXRvcnMubm9Eb3dubG9hZChzdHJpY3RDaGVjayksXHJcbiAgICAgIGRlZmF1bHRIZWlnaHQ6IHZhbGlkYXRvcnMuZGVmYXVsdEhlaWdodChzdHJpY3RDaGVjayksXHJcbiAgICAgIGRlZmF1bHRXaWR0aDogdmFsaWRhdG9ycy5kZWZhdWx0V2lkdGgoc3RyaWN0Q2hlY2spLFxyXG4gICAgICBkZWZhdWx0U2NhbGU6IHZhbGlkYXRvcnMuZGVmYXVsdFNjYWxlKHN0cmljdENoZWNrKSxcclxuICAgICAgaGVpZ2h0OiB2YWxpZGF0b3JzLmhlaWdodChzdHJpY3RDaGVjayksXHJcbiAgICAgIHdpZHRoOiB2YWxpZGF0b3JzLndpZHRoKHN0cmljdENoZWNrKSxcclxuICAgICAgc2NhbGU6IHZhbGlkYXRvcnMuc2NhbGUoc3RyaWN0Q2hlY2spLFxyXG4gICAgICBnbG9iYWxPcHRpb25zOiB2YWxpZGF0b3JzLmdsb2JhbE9wdGlvbnMoKSxcclxuICAgICAgdGhlbWVPcHRpb25zOiB2YWxpZGF0b3JzLnRoZW1lT3B0aW9ucygpLFxyXG4gICAgICBiYXRjaDogdmFsaWRhdG9ycy5iYXRjaChmYWxzZSksXHJcbiAgICAgIHJhc3Rlcml6YXRpb25UaW1lb3V0OiB2YWxpZGF0b3JzLnJhc3Rlcml6YXRpb25UaW1lb3V0KHN0cmljdENoZWNrKVxyXG4gICAgfSlcclxuICAgIC5wYXJ0aWFsKCk7XHJcblxyXG4vLyBTY2hlbWEgZm9yIHRoZSBjdXN0b21Mb2dpYyBzZWN0aW9uIG9mIG9wdGlvbnNcclxuY29uc3QgQ3VzdG9tTG9naWNTY2hlbWEgPSAoc3RyaWN0Q2hlY2spID0+XHJcbiAgelxyXG4gICAgLm9iamVjdCh7XHJcbiAgICAgIGFsbG93Q29kZUV4ZWN1dGlvbjogdmFsaWRhdG9ycy5hbGxvd0NvZGVFeGVjdXRpb24oc3RyaWN0Q2hlY2spLFxyXG4gICAgICBhbGxvd0ZpbGVSZXNvdXJjZXM6IHZhbGlkYXRvcnMuYWxsb3dGaWxlUmVzb3VyY2VzKHN0cmljdENoZWNrKSxcclxuICAgICAgY3VzdG9tQ29kZTogdmFsaWRhdG9ycy5jdXN0b21Db2RlKGZhbHNlKSxcclxuICAgICAgY2FsbGJhY2s6IHZhbGlkYXRvcnMuY2FsbGJhY2soZmFsc2UpLFxyXG4gICAgICByZXNvdXJjZXM6IHZhbGlkYXRvcnMucmVzb3VyY2VzKHN0cmljdENoZWNrKSxcclxuICAgICAgbG9hZENvbmZpZzogdmFsaWRhdG9ycy5sb2FkQ29uZmlnKGZhbHNlKSxcclxuICAgICAgY3JlYXRlQ29uZmlnOiB2YWxpZGF0b3JzLmNyZWF0ZUNvbmZpZyhmYWxzZSlcclxuICAgIH0pXHJcbiAgICAucGFydGlhbCgpO1xyXG5cclxuLy8gU2NoZW1hIGZvciB0aGUgc2VydmVyLnByb3h5IHNlY3Rpb24gb2Ygb3B0aW9uc1xyXG5jb25zdCBQcm94eVNjaGVtYSA9IChzdHJpY3RDaGVjaykgPT5cclxuICB6XHJcbiAgICAub2JqZWN0KHtcclxuICAgICAgaG9zdDogdmFsaWRhdG9ycy5wcm94eUhvc3QoZmFsc2UpLFxyXG4gICAgICBwb3J0OiB2YWxpZGF0b3JzLnByb3h5UG9ydChzdHJpY3RDaGVjayksXHJcbiAgICAgIHRpbWVvdXQ6IHZhbGlkYXRvcnMucHJveHlUaW1lb3V0KHN0cmljdENoZWNrKVxyXG4gICAgfSlcclxuICAgIC5wYXJ0aWFsKCk7XHJcblxyXG4vLyBTY2hlbWEgZm9yIHRoZSBzZXJ2ZXIucmF0ZUxpbWl0aW5nIHNlY3Rpb24gb2Ygb3B0aW9uc1xyXG5jb25zdCBSYXRlTGltaXRpbmdTY2hlbWEgPSAoc3RyaWN0Q2hlY2spID0+XHJcbiAgelxyXG4gICAgLm9iamVjdCh7XHJcbiAgICAgIGVuYWJsZTogdmFsaWRhdG9ycy5lbmFibGVSYXRlTGltaXRpbmcoc3RyaWN0Q2hlY2spLFxyXG4gICAgICBtYXhSZXF1ZXN0czogdmFsaWRhdG9ycy5tYXhSZXF1ZXN0cyhzdHJpY3RDaGVjayksXHJcbiAgICAgIHdpbmRvdzogdmFsaWRhdG9ycy53aW5kb3coc3RyaWN0Q2hlY2spLFxyXG4gICAgICBkZWxheTogdmFsaWRhdG9ycy5kZWxheShzdHJpY3RDaGVjayksXHJcbiAgICAgIHRydXN0UHJveHk6IHZhbGlkYXRvcnMudHJ1c3RQcm94eShzdHJpY3RDaGVjayksXHJcbiAgICAgIHNraXBLZXk6IHZhbGlkYXRvcnMuc2tpcEtleShmYWxzZSksXHJcbiAgICAgIHNraXBUb2tlbjogdmFsaWRhdG9ycy5za2lwVG9rZW4oZmFsc2UpXHJcbiAgICB9KVxyXG4gICAgLnBhcnRpYWwoKTtcclxuXHJcbi8vIFNjaGVtYSBmb3IgdGhlIHNlcnZlci5zc2wgc2VjdGlvbiBvZiBvcHRpb25zXHJcbmNvbnN0IFNzbFNjaGVtYSA9IChzdHJpY3RDaGVjaykgPT5cclxuICB6XHJcbiAgICAub2JqZWN0KHtcclxuICAgICAgZW5hYmxlOiB2YWxpZGF0b3JzLmVuYWJsZVNzbChzdHJpY3RDaGVjayksXHJcbiAgICAgIGZvcmNlOiB2YWxpZGF0b3JzLnNzbEZvcmNlKHN0cmljdENoZWNrKSxcclxuICAgICAgcG9ydDogdmFsaWRhdG9ycy5zc2xQb3J0KHN0cmljdENoZWNrKSxcclxuICAgICAgY2VydFBhdGg6IHZhbGlkYXRvcnMuc3NsQ2VydFBhdGgoZmFsc2UpXHJcbiAgICB9KVxyXG4gICAgLnBhcnRpYWwoKTtcclxuXHJcbi8vIFNjaGVtYSBmb3IgdGhlIHNlcnZlciBzZWN0aW9uIG9mIG9wdGlvbnNcclxuY29uc3QgU2VydmVyU2NoZW1hID0gKHN0cmljdENoZWNrKSA9PlxyXG4gIHoub2JqZWN0KHtcclxuICAgIGVuYWJsZTogdmFsaWRhdG9ycy5lbmFibGVTZXJ2ZXIoc3RyaWN0Q2hlY2spLm9wdGlvbmFsKCksXHJcbiAgICBob3N0OiB2YWxpZGF0b3JzLmhvc3Qoc3RyaWN0Q2hlY2spLm9wdGlvbmFsKCksXHJcbiAgICBwb3J0OiB2YWxpZGF0b3JzLnBvcnQoc3RyaWN0Q2hlY2spLm9wdGlvbmFsKCksXHJcbiAgICB1cGxvYWRMaW1pdDogdmFsaWRhdG9ycy51cGxvYWRMaW1pdChzdHJpY3RDaGVjaykub3B0aW9uYWwoKSxcclxuICAgIGJlbmNobWFya2luZzogdmFsaWRhdG9ycy5zZXJ2ZXJCZW5jaG1hcmtpbmcoc3RyaWN0Q2hlY2spLm9wdGlvbmFsKCksXHJcbiAgICBwcm94eTogUHJveHlTY2hlbWEoc3RyaWN0Q2hlY2spLm9wdGlvbmFsKCksXHJcbiAgICByYXRlTGltaXRpbmc6IFJhdGVMaW1pdGluZ1NjaGVtYShzdHJpY3RDaGVjaykub3B0aW9uYWwoKSxcclxuICAgIHNzbDogU3NsU2NoZW1hKHN0cmljdENoZWNrKS5vcHRpb25hbCgpXHJcbiAgfSk7XHJcblxyXG4vLyBTY2hlbWEgZm9yIHRoZSBwb29sIHNlY3Rpb24gb2Ygb3B0aW9uc1xyXG5jb25zdCBQb29sU2NoZW1hID0gKHN0cmljdENoZWNrKSA9PlxyXG4gIHpcclxuICAgIC5vYmplY3Qoe1xyXG4gICAgICBtaW5Xb3JrZXJzOiB2YWxpZGF0b3JzLm1pbldvcmtlcnMoc3RyaWN0Q2hlY2spLFxyXG4gICAgICBtYXhXb3JrZXJzOiB2YWxpZGF0b3JzLm1heFdvcmtlcnMoc3RyaWN0Q2hlY2spLFxyXG4gICAgICB3b3JrTGltaXQ6IHZhbGlkYXRvcnMud29ya0xpbWl0KHN0cmljdENoZWNrKSxcclxuICAgICAgYWNxdWlyZVRpbWVvdXQ6IHZhbGlkYXRvcnMuYWNxdWlyZVRpbWVvdXQoc3RyaWN0Q2hlY2spLFxyXG4gICAgICBjcmVhdGVUaW1lb3V0OiB2YWxpZGF0b3JzLmNyZWF0ZVRpbWVvdXQoc3RyaWN0Q2hlY2spLFxyXG4gICAgICBkZXN0cm95VGltZW91dDogdmFsaWRhdG9ycy5kZXN0cm95VGltZW91dChzdHJpY3RDaGVjayksXHJcbiAgICAgIGlkbGVUaW1lb3V0OiB2YWxpZGF0b3JzLmlkbGVUaW1lb3V0KHN0cmljdENoZWNrKSxcclxuICAgICAgY3JlYXRlUmV0cnlJbnRlcnZhbDogdmFsaWRhdG9ycy5jcmVhdGVSZXRyeUludGVydmFsKHN0cmljdENoZWNrKSxcclxuICAgICAgcmVhcGVySW50ZXJ2YWw6IHZhbGlkYXRvcnMucmVhcGVySW50ZXJ2YWwoc3RyaWN0Q2hlY2spLFxyXG4gICAgICBiZW5jaG1hcmtpbmc6IHZhbGlkYXRvcnMucG9vbEJlbmNobWFya2luZyhzdHJpY3RDaGVjaylcclxuICAgIH0pXHJcbiAgICAucGFydGlhbCgpO1xyXG5cclxuLy8gU2NoZW1hIGZvciB0aGUgbG9nZ2luZyBzZWN0aW9uIG9mIG9wdGlvbnNcclxuY29uc3QgTG9nZ2luZ1NjaGVtYSA9IChzdHJpY3RDaGVjaykgPT5cclxuICB6XHJcbiAgICAub2JqZWN0KHtcclxuICAgICAgbGV2ZWw6IHZhbGlkYXRvcnMubG9nTGV2ZWwoc3RyaWN0Q2hlY2spLFxyXG4gICAgICBmaWxlOiB2YWxpZGF0b3JzLmxvZ0ZpbGUoc3RyaWN0Q2hlY2spLFxyXG4gICAgICBkZXN0OiB2YWxpZGF0b3JzLmxvZ0Rlc3Qoc3RyaWN0Q2hlY2spLFxyXG4gICAgICB0b0NvbnNvbGU6IHZhbGlkYXRvcnMubG9nVG9Db25zb2xlKHN0cmljdENoZWNrKSxcclxuICAgICAgdG9GaWxlOiB2YWxpZGF0b3JzLmxvZ1RvRmlsZShzdHJpY3RDaGVjaylcclxuICAgIH0pXHJcbiAgICAucGFydGlhbCgpO1xyXG5cclxuLy8gU2NoZW1hIGZvciB0aGUgdWkgc2VjdGlvbiBvZiBvcHRpb25zXHJcbmNvbnN0IFVpU2NoZW1hID0gKHN0cmljdENoZWNrKSA9PlxyXG4gIHpcclxuICAgIC5vYmplY3Qoe1xyXG4gICAgICBlbmFibGU6IHZhbGlkYXRvcnMuZW5hYmxlVWkoc3RyaWN0Q2hlY2spLFxyXG4gICAgICByb3V0ZTogdmFsaWRhdG9ycy51aVJvdXRlKHN0cmljdENoZWNrKVxyXG4gICAgfSlcclxuICAgIC5wYXJ0aWFsKCk7XHJcblxyXG4vLyBTY2hlbWEgZm9yIHRoZSBvdGhlciBzZWN0aW9uIG9mIG9wdGlvbnNcclxuY29uc3QgT3RoZXJTY2hlbWEgPSAoc3RyaWN0Q2hlY2spID0+XHJcbiAgelxyXG4gICAgLm9iamVjdCh7XHJcbiAgICAgIG5vZGVFbnY6IHZhbGlkYXRvcnMubm9kZUVudihzdHJpY3RDaGVjayksXHJcbiAgICAgIGxpc3RlblRvUHJvY2Vzc0V4aXRzOiB2YWxpZGF0b3JzLmxpc3RlblRvUHJvY2Vzc0V4aXRzKHN0cmljdENoZWNrKSxcclxuICAgICAgbm9Mb2dvOiB2YWxpZGF0b3JzLm5vTG9nbyhzdHJpY3RDaGVjayksXHJcbiAgICAgIGhhcmRSZXNldFBhZ2U6IHZhbGlkYXRvcnMuaGFyZFJlc2V0UGFnZShzdHJpY3RDaGVjayksXHJcbiAgICAgIGJyb3dzZXJTaGVsbE1vZGU6IHZhbGlkYXRvcnMuYnJvd3NlclNoZWxsTW9kZShzdHJpY3RDaGVjayksXHJcbiAgICAgIHZhbGlkYXRpb246IHZhbGlkYXRvcnMudmFsaWRhdGlvbihzdHJpY3RDaGVjaylcclxuICAgIH0pXHJcbiAgICAucGFydGlhbCgpO1xyXG5cclxuLy8gU2NoZW1hIGZvciB0aGUgZGVidWcgc2VjdGlvbiBvZiBvcHRpb25zXHJcbmNvbnN0IERlYnVnU2NoZW1hID0gKHN0cmljdENoZWNrKSA9PlxyXG4gIHpcclxuICAgIC5vYmplY3Qoe1xyXG4gICAgICBlbmFibGU6IHZhbGlkYXRvcnMuZW5hYmxlRGVidWcoc3RyaWN0Q2hlY2spLFxyXG4gICAgICBoZWFkbGVzczogdmFsaWRhdG9ycy5oZWFkbGVzcyhzdHJpY3RDaGVjayksXHJcbiAgICAgIGRldnRvb2xzOiB2YWxpZGF0b3JzLmRldnRvb2xzKHN0cmljdENoZWNrKSxcclxuICAgICAgbGlzdGVuVG9Db25zb2xlOiB2YWxpZGF0b3JzLmxpc3RlblRvQ29uc29sZShzdHJpY3RDaGVjayksXHJcbiAgICAgIGR1bXBpbzogdmFsaWRhdG9ycy5kdW1waW8oc3RyaWN0Q2hlY2spLFxyXG4gICAgICBzbG93TW86IHZhbGlkYXRvcnMuc2xvd01vKHN0cmljdENoZWNrKSxcclxuICAgICAgZGVidWdnaW5nUG9ydDogdmFsaWRhdG9ycy5kZWJ1Z2dpbmdQb3J0KHN0cmljdENoZWNrKVxyXG4gICAgfSlcclxuICAgIC5wYXJ0aWFsKCk7XHJcblxyXG4vLyBTdHJpY3Qgc2NoZW1hIGZvciB0aGUgY29uZmlnXHJcbmV4cG9ydCBjb25zdCBTdHJpY3RDb25maWdTY2hlbWEgPSB6Lm9iamVjdCh7XHJcbiAgcmVxdWVzdElkOiB2YWxpZGF0b3JzLnJlcXVlc3RJZCgpLFxyXG4gIHB1cHBldGVlcjogUHVwcGV0ZWVyU2NoZW1hKHRydWUpLFxyXG4gIGhpZ2hjaGFydHM6IEhpZ2hjaGFydHNTY2hlbWEodHJ1ZSksXHJcbiAgZXhwb3J0OiBFeHBvcnRTY2hlbWEodHJ1ZSksXHJcbiAgY3VzdG9tTG9naWM6IEN1c3RvbUxvZ2ljU2NoZW1hKHRydWUpLFxyXG4gIHNlcnZlcjogU2VydmVyU2NoZW1hKHRydWUpLFxyXG4gIHBvb2w6IFBvb2xTY2hlbWEodHJ1ZSksXHJcbiAgbG9nZ2luZzogTG9nZ2luZ1NjaGVtYSh0cnVlKSxcclxuICB1aTogVWlTY2hlbWEodHJ1ZSksXHJcbiAgb3RoZXI6IE90aGVyU2NoZW1hKHRydWUpLFxyXG4gIGRlYnVnOiBEZWJ1Z1NjaGVtYSh0cnVlKVxyXG59KTtcclxuXHJcbi8vIExvb3NlIHNjaGVtYSBmb3IgdGhlIGNvbmZpZ1xyXG5leHBvcnQgY29uc3QgTG9vc2VDb25maWdTY2hlbWEgPSB6Lm9iamVjdCh7XHJcbiAgcmVxdWVzdElkOiB2YWxpZGF0b3JzLnJlcXVlc3RJZCgpLFxyXG4gIHB1cHBldGVlcjogUHVwcGV0ZWVyU2NoZW1hKGZhbHNlKSxcclxuICBoaWdoY2hhcnRzOiBIaWdoY2hhcnRzU2NoZW1hKGZhbHNlKSxcclxuICBleHBvcnQ6IEV4cG9ydFNjaGVtYShmYWxzZSksXHJcbiAgY3VzdG9tTG9naWM6IEN1c3RvbUxvZ2ljU2NoZW1hKGZhbHNlKSxcclxuICBzZXJ2ZXI6IFNlcnZlclNjaGVtYShmYWxzZSksXHJcbiAgcG9vbDogUG9vbFNjaGVtYShmYWxzZSksXHJcbiAgbG9nZ2luZzogTG9nZ2luZ1NjaGVtYShmYWxzZSksXHJcbiAgdWk6IFVpU2NoZW1hKGZhbHNlKSxcclxuICBvdGhlcjogT3RoZXJTY2hlbWEoZmFsc2UpLFxyXG4gIGRlYnVnOiBEZWJ1Z1NjaGVtYShmYWxzZSlcclxufSk7XHJcblxyXG4vLyBTY2hlbWEgZm9yIHRoZSBlbnZpcm9ubWVudCB2YXJpYWJsZXMgY29uZmlnXHJcbmV4cG9ydCBjb25zdCBFbnZTY2hlbWEgPSB6Lm9iamVjdCh7XHJcbiAgLy8gcHVwcGV0ZWVyXHJcbiAgUFVQUEVURUVSX0FSR1M6IHZhbGlkYXRvcnMuYXJncyhmYWxzZSksXHJcblxyXG4gIC8vIGhpZ2hjaGFydHNcclxuICBISUdIQ0hBUlRTX1ZFUlNJT046IHZhbGlkYXRvcnMudmVyc2lvbihmYWxzZSksXHJcbiAgSElHSENIQVJUU19DRE5fVVJMOiB2YWxpZGF0b3JzLmNkblVybChmYWxzZSksXHJcbiAgSElHSENIQVJUU19GT1JDRV9GRVRDSDogdmFsaWRhdG9ycy5mb3JjZUZldGNoKGZhbHNlKSxcclxuICBISUdIQ0hBUlRTX0NBQ0hFX1BBVEg6IHZhbGlkYXRvcnMuY2FjaGVQYXRoKGZhbHNlKSxcclxuICBISUdIQ0hBUlRTX0FETUlOX1RPS0VOOiB2YWxpZGF0b3JzLmFkbWluVG9rZW4oZmFsc2UpLFxyXG4gIEhJR0hDSEFSVFNfQ09SRV9TQ1JJUFRTOiB2YWxpZGF0b3JzLmNvcmVTY3JpcHRzKGZhbHNlKSxcclxuICBISUdIQ0hBUlRTX01PRFVMRV9TQ1JJUFRTOiB2YWxpZGF0b3JzLm1vZHVsZVNjcmlwdHMoZmFsc2UpLFxyXG4gIEhJR0hDSEFSVFNfSU5ESUNBVE9SX1NDUklQVFM6IHZhbGlkYXRvcnMuaW5kaWNhdG9yU2NyaXB0cyhmYWxzZSksXHJcbiAgSElHSENIQVJUU19DVVNUT01fU0NSSVBUUzogdmFsaWRhdG9ycy5jdXN0b21TY3JpcHRzKGZhbHNlKSxcclxuXHJcbiAgLy8gZXhwb3J0XHJcbiAgRVhQT1JUX0lORklMRTogdmFsaWRhdG9ycy5pbmZpbGUoZmFsc2UpLFxyXG4gIEVYUE9SVF9JTlNUUjogdmFsaWRhdG9ycy5pbnN0cigpLFxyXG4gIEVYUE9SVF9PUFRJT05TOiB2YWxpZGF0b3JzLm9wdGlvbnMoKSxcclxuICBFWFBPUlRfU1ZHOiB2YWxpZGF0b3JzLnN2ZygpLFxyXG4gIEVYUE9SVF9CQVRDSDogdmFsaWRhdG9ycy5iYXRjaChmYWxzZSksXHJcbiAgRVhQT1JUX09VVEZJTEU6IHZhbGlkYXRvcnMub3V0ZmlsZShmYWxzZSksXHJcbiAgRVhQT1JUX1RZUEU6IHZhbGlkYXRvcnMudHlwZShmYWxzZSksXHJcbiAgRVhQT1JUX0NPTlNUUjogdmFsaWRhdG9ycy5jb25zdHIoZmFsc2UpLFxyXG4gIEVYUE9SVF9CNjQ6IHZhbGlkYXRvcnMuYjY0KGZhbHNlKSxcclxuICBFWFBPUlRfTk9fRE9XTkxPQUQ6IHZhbGlkYXRvcnMubm9Eb3dubG9hZChmYWxzZSksXHJcbiAgRVhQT1JUX0hFSUdIVDogdmFsaWRhdG9ycy5oZWlnaHQoZmFsc2UpLFxyXG4gIEVYUE9SVF9XSURUSDogdmFsaWRhdG9ycy53aWR0aChmYWxzZSksXHJcbiAgRVhQT1JUX1NDQUxFOiB2YWxpZGF0b3JzLnNjYWxlKGZhbHNlKSxcclxuICBFWFBPUlRfREVGQVVMVF9IRUlHSFQ6IHZhbGlkYXRvcnMuZGVmYXVsdEhlaWdodChmYWxzZSksXHJcbiAgRVhQT1JUX0RFRkFVTFRfV0lEVEg6IHZhbGlkYXRvcnMuZGVmYXVsdFdpZHRoKGZhbHNlKSxcclxuICBFWFBPUlRfREVGQVVMVF9TQ0FMRTogdmFsaWRhdG9ycy5kZWZhdWx0U2NhbGUoZmFsc2UpLFxyXG4gIEVYUE9SVF9HTE9CQUxfT1BUSU9OUzogdmFsaWRhdG9ycy5nbG9iYWxPcHRpb25zKCksXHJcbiAgRVhQT1JUX1RIRU1FX09QVElPTlM6IHZhbGlkYXRvcnMudGhlbWVPcHRpb25zKCksXHJcbiAgRVhQT1JUX1JBU1RFUklaQVRJT05fVElNRU9VVDogdmFsaWRhdG9ycy5yYXN0ZXJpemF0aW9uVGltZW91dChmYWxzZSksXHJcblxyXG4gIC8vIGN1c3RvbVxyXG4gIENVU1RPTV9MT0dJQ19BTExPV19DT0RFX0VYRUNVVElPTjogdmFsaWRhdG9ycy5hbGxvd0NvZGVFeGVjdXRpb24oZmFsc2UpLFxyXG4gIENVU1RPTV9MT0dJQ19BTExPV19GSUxFX1JFU09VUkNFUzogdmFsaWRhdG9ycy5hbGxvd0ZpbGVSZXNvdXJjZXMoZmFsc2UpLFxyXG4gIENVU1RPTV9MT0dJQ19DVVNUT01fQ09ERTogdmFsaWRhdG9ycy5jdXN0b21Db2RlKGZhbHNlKSxcclxuICBDVVNUT01fTE9HSUNfQ0FMTEJBQ0s6IHZhbGlkYXRvcnMuY2FsbGJhY2soZmFsc2UpLFxyXG4gIENVU1RPTV9MT0dJQ19SRVNPVVJDRVM6IHZhbGlkYXRvcnMucmVzb3VyY2VzKGZhbHNlKSxcclxuICBDVVNUT01fTE9HSUNfTE9BRF9DT05GSUc6IHZhbGlkYXRvcnMubG9hZENvbmZpZyhmYWxzZSksXHJcbiAgQ1VTVE9NX0xPR0lDX0NSRUFURV9DT05GSUc6IHZhbGlkYXRvcnMuY3JlYXRlQ29uZmlnKGZhbHNlKSxcclxuXHJcbiAgLy8gc2VydmVyXHJcbiAgU0VSVkVSX0VOQUJMRTogdmFsaWRhdG9ycy5lbmFibGVTZXJ2ZXIoZmFsc2UpLFxyXG4gIFNFUlZFUl9IT1NUOiB2YWxpZGF0b3JzLmhvc3QoZmFsc2UpLFxyXG4gIFNFUlZFUl9QT1JUOiB2YWxpZGF0b3JzLnBvcnQoZmFsc2UpLFxyXG4gIFNFUlZFUl9VUExPQURfTElNSVQ6IHZhbGlkYXRvcnMudXBsb2FkTGltaXQoZmFsc2UpLFxyXG4gIFNFUlZFUl9CRU5DSE1BUktJTkc6IHZhbGlkYXRvcnMuc2VydmVyQmVuY2htYXJraW5nKGZhbHNlKSxcclxuXHJcbiAgLy8gc2VydmVyIHByb3h5XHJcbiAgU0VSVkVSX1BST1hZX0hPU1Q6IHZhbGlkYXRvcnMucHJveHlIb3N0KGZhbHNlKSxcclxuICBTRVJWRVJfUFJPWFlfUE9SVDogdmFsaWRhdG9ycy5wcm94eVBvcnQoZmFsc2UpLFxyXG4gIFNFUlZFUl9QUk9YWV9USU1FT1VUOiB2YWxpZGF0b3JzLnByb3h5VGltZW91dChmYWxzZSksXHJcblxyXG4gIC8vIHNlcnZlciByYXRlIGxpbWl0aW5nXHJcbiAgU0VSVkVSX1JBVEVfTElNSVRJTkdfRU5BQkxFOiB2YWxpZGF0b3JzLmVuYWJsZVJhdGVMaW1pdGluZyhmYWxzZSksXHJcbiAgU0VSVkVSX1JBVEVfTElNSVRJTkdfTUFYX1JFUVVFU1RTOiB2YWxpZGF0b3JzLm1heFJlcXVlc3RzKGZhbHNlKSxcclxuICBTRVJWRVJfUkFURV9MSU1JVElOR19XSU5ET1c6IHZhbGlkYXRvcnMud2luZG93KGZhbHNlKSxcclxuICBTRVJWRVJfUkFURV9MSU1JVElOR19ERUxBWTogdmFsaWRhdG9ycy5kZWxheShmYWxzZSksXHJcbiAgU0VSVkVSX1JBVEVfTElNSVRJTkdfVFJVU1RfUFJPWFk6IHZhbGlkYXRvcnMudHJ1c3RQcm94eShmYWxzZSksXHJcbiAgU0VSVkVSX1JBVEVfTElNSVRJTkdfU0tJUF9LRVk6IHZhbGlkYXRvcnMuc2tpcEtleShmYWxzZSksXHJcbiAgU0VSVkVSX1JBVEVfTElNSVRJTkdfU0tJUF9UT0tFTjogdmFsaWRhdG9ycy5za2lwVG9rZW4oZmFsc2UpLFxyXG5cclxuICAvLyBzZXJ2ZXIgc3NsXHJcbiAgU0VSVkVSX1NTTF9FTkFCTEU6IHZhbGlkYXRvcnMuZW5hYmxlU3NsKGZhbHNlKSxcclxuICBTRVJWRVJfU1NMX0ZPUkNFOiB2YWxpZGF0b3JzLnNzbEZvcmNlKGZhbHNlKSxcclxuICBTRVJWRVJfU1NMX1BPUlQ6IHZhbGlkYXRvcnMuc3NsUG9ydChmYWxzZSksXHJcbiAgU0VSVkVSX1NTTF9DRVJUX1BBVEg6IHZhbGlkYXRvcnMuc3NsQ2VydFBhdGgoZmFsc2UpLFxyXG5cclxuICAvLyBwb29sXHJcbiAgUE9PTF9NSU5fV09SS0VSUzogdmFsaWRhdG9ycy5taW5Xb3JrZXJzKGZhbHNlKSxcclxuICBQT09MX01BWF9XT1JLRVJTOiB2YWxpZGF0b3JzLm1heFdvcmtlcnMoZmFsc2UpLFxyXG4gIFBPT0xfV09SS19MSU1JVDogdmFsaWRhdG9ycy53b3JrTGltaXQoZmFsc2UpLFxyXG4gIFBPT0xfQUNRVUlSRV9USU1FT1VUOiB2YWxpZGF0b3JzLmFjcXVpcmVUaW1lb3V0KGZhbHNlKSxcclxuICBQT09MX0NSRUFURV9USU1FT1VUOiB2YWxpZGF0b3JzLmNyZWF0ZVRpbWVvdXQoZmFsc2UpLFxyXG4gIFBPT0xfREVTVFJPWV9USU1FT1VUOiB2YWxpZGF0b3JzLmRlc3Ryb3lUaW1lb3V0KGZhbHNlKSxcclxuICBQT09MX0lETEVfVElNRU9VVDogdmFsaWRhdG9ycy5pZGxlVGltZW91dChmYWxzZSksXHJcbiAgUE9PTF9DUkVBVEVfUkVUUllfSU5URVJWQUw6IHZhbGlkYXRvcnMuY3JlYXRlUmV0cnlJbnRlcnZhbChmYWxzZSksXHJcbiAgUE9PTF9SRUFQRVJfSU5URVJWQUw6IHZhbGlkYXRvcnMucmVhcGVySW50ZXJ2YWwoZmFsc2UpLFxyXG4gIFBPT0xfQkVOQ0hNQVJLSU5HOiB2YWxpZGF0b3JzLnBvb2xCZW5jaG1hcmtpbmcoZmFsc2UpLFxyXG5cclxuICAvLyBsb2dnaW5nXHJcbiAgTE9HR0lOR19MRVZFTDogdmFsaWRhdG9ycy5sb2dMZXZlbChmYWxzZSksXHJcbiAgTE9HR0lOR19GSUxFOiB2YWxpZGF0b3JzLmxvZ0ZpbGUoZmFsc2UpLFxyXG4gIExPR0dJTkdfREVTVDogdmFsaWRhdG9ycy5sb2dEZXN0KGZhbHNlKSxcclxuICBMT0dHSU5HX1RPX0NPTlNPTEU6IHZhbGlkYXRvcnMubG9nVG9Db25zb2xlKGZhbHNlKSxcclxuICBMT0dHSU5HX1RPX0ZJTEU6IHZhbGlkYXRvcnMubG9nVG9GaWxlKGZhbHNlKSxcclxuXHJcbiAgLy8gdWlcclxuICBVSV9FTkFCTEU6IHZhbGlkYXRvcnMuZW5hYmxlVWkoZmFsc2UpLFxyXG4gIFVJX1JPVVRFOiB2YWxpZGF0b3JzLnVpUm91dGUoZmFsc2UpLFxyXG5cclxuICAvLyBvdGhlclxyXG4gIE9USEVSX05PREVfRU5WOiB2YWxpZGF0b3JzLm5vZGVFbnYoZmFsc2UpLFxyXG4gIE9USEVSX0xJU1RFTl9UT19QUk9DRVNTX0VYSVRTOiB2YWxpZGF0b3JzLmxpc3RlblRvUHJvY2Vzc0V4aXRzKGZhbHNlKSxcclxuICBPVEhFUl9OT19MT0dPOiB2YWxpZGF0b3JzLm5vTG9nbyhmYWxzZSksXHJcbiAgT1RIRVJfSEFSRF9SRVNFVF9QQUdFOiB2YWxpZGF0b3JzLmhhcmRSZXNldFBhZ2UoZmFsc2UpLFxyXG4gIE9USEVSX0JST1dTRVJfU0hFTExfTU9ERTogdmFsaWRhdG9ycy5icm93c2VyU2hlbGxNb2RlKGZhbHNlKSxcclxuICBPVEhFUl9WQUxJREFUSU9OOiB2YWxpZGF0b3JzLnZhbGlkYXRpb24oZmFsc2UpLFxyXG5cclxuICAvLyBkZWJ1Z2dlclxyXG4gIERFQlVHX0VOQUJMRTogdmFsaWRhdG9ycy5lbmFibGVEZWJ1ZyhmYWxzZSksXHJcbiAgREVCVUdfSEVBRExFU1M6IHZhbGlkYXRvcnMuaGVhZGxlc3MoZmFsc2UpLFxyXG4gIERFQlVHX0RFVlRPT0xTOiB2YWxpZGF0b3JzLmRldnRvb2xzKGZhbHNlKSxcclxuICBERUJVR19MSVNURU5fVE9fQ09OU09MRTogdmFsaWRhdG9ycy5saXN0ZW5Ub0NvbnNvbGUoZmFsc2UpLFxyXG4gIERFQlVHX0RVTVBJTzogdmFsaWRhdG9ycy5kdW1waW8oZmFsc2UpLFxyXG4gIERFQlVHX1NMT1dfTU86IHZhbGlkYXRvcnMuc2xvd01vKGZhbHNlKSxcclxuICBERUJVR19ERUJVR0dJTkdfUE9SVDogdmFsaWRhdG9ycy5kZWJ1Z2dpbmdQb3J0KGZhbHNlKVxyXG59KTtcclxuXHJcbi8qKlxyXG4gKiBWYWxpZGF0ZXMgdGhlIGVudmlyb25tZW50IHZhcmlhYmxlcyBvcHRpb25zIHVzaW5nIHRoZSBFbnZTY2hlbWEuXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBwcm9jZXNzLmVudiAtIFRoZSBjb25maWd1cmF0aW9uIG9wdGlvbnMgZnJvbSBlbnZpcm9ubWVudFxyXG4gKiB2YXJpYWJsZXMgZmlsZSB0byB2YWxpZGF0ZS5cclxuICpcclxuICogQHJldHVybnMge09iamVjdH0gVGhlIHBhcnNlZCBhbmQgdmFsaWRhdGVkIGVudmlyb25tZW50IHZhcmlhYmxlcy5cclxuICovXHJcbmV4cG9ydCBjb25zdCBlbnZzID0gRW52U2NoZW1hLnBhcnRpYWwoKS5wYXJzZShwcm9jZXNzLmVudik7XHJcblxyXG4vKipcclxuICogVmFsaWRhdGVzIHRoZSBjb25maWd1cmF0aW9uIG9wdGlvbnMgdXNpbmcgdGhlIGBTdHJpY3RDb25maWdTY2hlbWFgLlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gc3RyaWN0VmFsaWRhdGVcclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IGNvbmZpZ09wdGlvbnMgLSBUaGUgY29uZmlndXJhdGlvbiBvcHRpb25zIHRvIHZhbGlkYXRlLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7T2JqZWN0fSBUaGUgcGFyc2VkIGFuZCB2YWxpZGF0ZWQgY29uZmlndXJhdGlvbiBvcHRpb25zLlxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIHN0cmljdFZhbGlkYXRlKGNvbmZpZ09wdGlvbnMpIHtcclxuICByZXR1cm4gU3RyaWN0Q29uZmlnU2NoZW1hLnBhcnRpYWwoKS5wYXJzZShjb25maWdPcHRpb25zKTtcclxufVxyXG5cclxuLyoqXHJcbiAqIFZhbGlkYXRlcyB0aGUgY29uZmlndXJhdGlvbiBvcHRpb25zIHVzaW5nIHRoZSBgTG9vc2VDb25maWdTY2hlbWFgLlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gbG9vc2VWYWxpZGF0ZVxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gY29uZmlnT3B0aW9ucyAtIFRoZSBjb25maWd1cmF0aW9uIG9wdGlvbnMgdG8gdmFsaWRhdGUuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtPYmplY3R9IFRoZSBwYXJzZWQgYW5kIHZhbGlkYXRlZCBjb25maWd1cmF0aW9uIG9wdGlvbnMuXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gbG9vc2VWYWxpZGF0ZShjb25maWdPcHRpb25zKSB7XHJcbiAgcmV0dXJuIExvb3NlQ29uZmlnU2NoZW1hLnBhcnRpYWwoKS5wYXJzZShjb25maWdPcHRpb25zKTtcclxufVxyXG5cclxuLyoqXHJcbiAqIEN1c3RvbSBlcnJvciBtYXBwaW5nIGZ1bmN0aW9uIGZvciBab2Qgc2NoZW1hIHZhbGlkYXRpb24uXHJcbiAqXHJcbiAqIFRoaXMgZnVuY3Rpb24gY3VzdG9taXplcyB0aGUgZXJyb3IgbWVzc2FnZXMgcHJvZHVjZWQgYnkgWm9kIHNjaGVtYVxyXG4gKiB2YWxpZGF0aW9uLCBwcm92aWRpbmcgbW9yZSBzcGVjaWZpYyBhbmQgdXNlci1mcmllbmRseSBmZWVkYmFjayBiYXNlZCBvbiB0aGVcclxuICogaXNzdWUgdHlwZSBhbmQgY29udGV4dC5cclxuICpcclxuICogVGhlIGZ1bmN0aW9uIG1vZGlmaWVzIHRoZSBlcnJvciBtZXNzYWdlcyBhcyBmb2xsb3dzOlxyXG4gKlxyXG4gKiAtIEZvciBtaXNzaW5nIHJlcXVpcmVkIHZhbHVlcyAodW5kZWZpbmVkKSwgaXQgcmV0dXJucyBhIG1lc3NhZ2UgaW5kaWNhdGluZ1xyXG4gKiB0aGF0IG5vIHZhbHVlIHdhcyBwcm92aWRlZCBmb3IgdGhlIHNwZWNpZmljIHByb3BlcnR5LlxyXG4gKlxyXG4gKiAtIEZvciBjdXN0b20gdmFsaWRhdGlvbiBlcnJvcnMsIGlmIGEgY3VzdG9tIGVycm9yIG1lc3NhZ2UgaXMgcHJvdmlkZWQgaW4gdGhlXHJcbiAqIGlzc3VlIHBhcmFtZXRlcnMsIGl0IGluY2x1ZGVzIHRoaXMgbWVzc2FnZSBhbG9uZyB3aXRoIHRoZSBpbnZhbGlkIGRhdGFcclxuICogcmVjZWl2ZWQuXHJcbiAqXHJcbiAqIC0gRm9yIGFsbCBvdGhlciBlcnJvcnMsIGl0IGFwcGVuZHMgcHJvcGVydHktc3BlY2lmaWMgaW5mb3JtYXRpb24gdG8gdGhlXHJcbiAqIGRlZmF1bHQgZXJyb3IgbWVzc2FnZSBwcm92aWRlZCBieSBab2QuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBfY3VzdG9tRXJyb3JNYXBcclxuICpcclxuICogQHBhcmFtIHt6LlpvZElzc3VlfSBpc3N1ZSAtIFRoZSBpc3N1ZSBvYmplY3QgcmVwcmVzZW50aW5nIHRoZSB2YWxpZGF0aW9uXHJcbiAqIGVycm9yLlxyXG4gKiBAcGFyYW0ge09iamVjdH0gY29udGV4dCAtIFRoZSBjb250ZXh0IG9iamVjdCBwcm92aWRpbmcgYWRkaXRpb25hbCBpbmZvcm1hdGlvblxyXG4gKiBhYm91dCB0aGUgdmFsaWRhdGlvbiBlcnJvci5cclxuICpcclxuICogQHJldHVybnMge09iamVjdH0gQW4gb2JqZWN0IGNvbnRhaW5pbmcgdGhlIGN1c3RvbWl6ZWQgZXJyb3IgbWVzc2FnZS5cclxuICovXHJcbmZ1bmN0aW9uIF9jdXN0b21FcnJvck1hcChpc3N1ZSwgY29udGV4dCkge1xyXG4gIC8vIEdldCB0aGUgY2hhaW4gb2YgcHJvcGVydGllcyB3aGljaCBlcnJvciBkaXJlY3RseSByZWZlcnMgdG9cclxuICBjb25zdCBwcm9wZXJ0eU5hbWUgPSBpc3N1ZS5wYXRoLmpvaW4oJy4nKTtcclxuXHJcbiAgLy8gQ3JlYXRlIHRoZSBmaXJzdCBwYXJ0IG9mIHRoZSBtZXNzYWdlIGFib3V0IHRoZSBwcm9wZXJ0eSBpbmZvcm1hdGlvblxyXG4gIGNvbnN0IHByb3BlcnR5SW5mbyA9IGBJbnZhbGlkIHZhbHVlIGZvciB0aGUgJHtwcm9wZXJ0eU5hbWV9YDtcclxuXHJcbiAgLy8gTW9kaWZpZWQgbWVzc2FnZSBmb3IgdGhlIGludmFsaWQgdHlwZVxyXG4gIGlmIChpc3N1ZS5jb2RlID09PSB6LlpvZElzc3VlQ29kZS5pbnZhbGlkX3R5cGUpIHtcclxuICAgIC8vIE1vZGlmaWVkIG1lc3NhZ2UgZm9yIHRoZSByZXF1aXJlZCB2YWx1ZXNcclxuICAgIGlmIChpc3N1ZS5yZWNlaXZlZCA9PT0gei5ab2RQYXJzZWRUeXBlLnVuZGVmaW5lZCkge1xyXG4gICAgICByZXR1cm4ge1xyXG4gICAgICAgIG1lc3NhZ2U6IGAke3Byb3BlcnR5SW5mb30gLSBObyB2YWx1ZSB3YXMgcHJvdmlkZWQuYFxyXG4gICAgICB9O1xyXG4gICAgfVxyXG5cclxuICAgIC8vIE1vZGlmaWVkIG1lc3NhZ2UgZm9yIHRoZSBzcGVjaWZpYyBpbnZhbGlkIHR5cGUgd2hlbiB2YWx1ZXMgZXhpc3RcclxuICAgIHJldHVybiB7XHJcbiAgICAgIG1lc3NhZ2U6IGAke3Byb3BlcnR5SW5mb30gLSBJbnZhbGlkIHR5cGUuICR7Y29udGV4dC5kZWZhdWx0RXJyb3J9LmBcclxuICAgIH07XHJcbiAgfVxyXG5cclxuICAvLyBNb2RpZmllZCBtZXNzYWdlIGZvciB0aGUgY3VzdG9tIHZhbGlkYXRpb25cclxuICBpZiAoaXNzdWUuY29kZSA9PT0gei5ab2RJc3N1ZUNvZGUuY3VzdG9tKSB7XHJcbiAgICAvLyBJZiB0aGUgY3VzdG9tIG1lc3NhZ2UgZm9yIGVycm9yIGV4aXN0LCBpbmNsdWRlIGl0XHJcbiAgICBpZiAoaXNzdWUucGFyYW1zPy5lcnJvck1lc3NhZ2UpIHtcclxuICAgICAgcmV0dXJuIHtcclxuICAgICAgICBtZXNzYWdlOiBgJHtwcm9wZXJ0eUluZm99IC0gJHtpc3N1ZS5wYXJhbXM/LmVycm9yTWVzc2FnZX0sIHJlY2VpdmVkICcke2NvbnRleHQuZGF0YX0nLmBcclxuICAgICAgfTtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIC8vIE1vZGlmaWVkIG1lc3NhZ2UgZm9yIHRoZSBpbnZhbGlkIHVuaW9uIGVycm9yXHJcbiAgaWYgKGlzc3VlLmNvZGUgPT09IHouWm9kSXNzdWVDb2RlLmludmFsaWRfdW5pb24pIHtcclxuICAgIC8vIENyZWF0ZSB0aGUgZmlyc3QgcGFydCBvZiB0aGUgbWVzc2FnZSBhYm91dCB0aGUgbXVsdGlwbGUgZXJyb3JzXHJcbiAgICBsZXQgbWVzc2FnZSA9IGBNdWx0aXBsZSBlcnJvcnMgb2NjdXJyZWQgZm9yIHRoZSAke3Byb3BlcnR5TmFtZX06XFxuYDtcclxuXHJcbiAgICAvLyBDeWNsZSB0aHJvdWdoIGFsbCBlcnJvcnMgYW5kIGNyZWF0ZSBhIGNvcnJlY3QgbWVzc2FnZVxyXG4gICAgaXNzdWUudW5pb25FcnJvcnMuZm9yRWFjaCgodmFsdWUpID0+IHtcclxuICAgICAgY29uc3QgaW5kZXggPSB2YWx1ZS5pc3N1ZXNbMF0ubWVzc2FnZS5pbmRleE9mKCctJyk7XHJcbiAgICAgIG1lc3NhZ2UgKz1cclxuICAgICAgICBpbmRleCAhPT0gLTFcclxuICAgICAgICAgID8gYCR7dmFsdWUuaXNzdWVzWzBdLm1lc3NhZ2V9XFxuYC5zdWJzdHJpbmcoaW5kZXgpXHJcbiAgICAgICAgICA6IGAke3ZhbHVlLmlzc3Vlc1swXS5tZXNzYWdlfVxcbmA7XHJcbiAgICB9KTtcclxuXHJcbiAgICAvLyBSZXR1cm4gdGhlIGZpbmFsIG1lc3NhZ2UgZm9yIHRoZSBpbnZhbGlkIHVuaW9uIGVycm9yXHJcbiAgICByZXR1cm4ge1xyXG4gICAgICBtZXNzYWdlXHJcbiAgICB9O1xyXG4gIH1cclxuXHJcbiAgLy8gUmV0dXJuIHRoZSBkZWZhdWx0IGVycm9yIG1lc3NhZ2UsIGV4dGVuZGVkIGJ5IHRoZSBpbmZvIGFib3V0IHRoZSBwcm9wZXJ0eVxyXG4gIHJldHVybiB7XHJcbiAgICBtZXNzYWdlOiBgJHtwcm9wZXJ0eUluZm99IC0gJHtjb250ZXh0LmRlZmF1bHRFcnJvcn0uYFxyXG4gIH07XHJcbn1cclxuXHJcbmV4cG9ydCBkZWZhdWx0IHtcclxuICB2YWxpZGF0b3JzLFxyXG4gIFN0cmljdENvbmZpZ1NjaGVtYSxcclxuICBMb29zZUNvbmZpZ1NjaGVtYSxcclxuICBFbnZTY2hlbWEsXHJcbiAgZW52cyxcclxuICBzdHJpY3RWYWxpZGF0ZSxcclxuICBsb29zZVZhbGlkYXRlXHJcbn07XHJcbiIsIi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXHJcblxyXG5IaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXJcclxuXHJcbkNvcHlyaWdodCAoYykgMjAxNi0yMDI1LCBIaWdoc29mdFxyXG5cclxuTGljZW5jZWQgdW5kZXIgdGhlIE1JVCBsaWNlbmNlLlxyXG5cclxuQWRkaXRpb25hbGx5IGEgdmFsaWQgSGlnaGNoYXJ0cyBsaWNlbnNlIGlzIHJlcXVpcmVkIGZvciB1c2UuXHJcblxyXG5TZWUgTElDRU5TRSBmaWxlIGluIHJvb3QgZm9yIGRldGFpbHMuXHJcblxyXG4qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xyXG5cclxuLyoqXHJcbiAqIEEgY3VzdG9tIGVycm9yIGNsYXNzIGZvciBoYW5kbGluZyBleHBvcnQtcmVsYXRlZCBlcnJvcnMuIEV4dGVuZHMgdGhlIG5hdGl2ZVxyXG4gKiBgRXJyb3JgIGNsYXNzIHRvIGluY2x1ZGUgYWRkaXRpb25hbCBwcm9wZXJ0aWVzIGxpa2Ugc3RhdHVzIGNvZGUgYW5kIHN0YWNrXHJcbiAqIHRyYWNlIGRldGFpbHMuXHJcbiAqL1xyXG5jbGFzcyBFeHBvcnRFcnJvciBleHRlbmRzIEVycm9yIHtcclxuICAvKipcclxuICAgKiBDcmVhdGVzIGFuIGluc3RhbmNlIG9mIHRoZSBgRXhwb3J0RXJyb3JgLlxyXG4gICAqXHJcbiAgICogQHBhcmFtIHtzdHJpbmd9IG1lc3NhZ2UgLSBUaGUgZXJyb3IgbWVzc2FnZSB0byBiZSBkaXNwbGF5ZWQuXHJcbiAgICogQHBhcmFtIHtudW1iZXJ9IHN0YXR1c0NvZGUgLSBPcHRpb25hbCBIVFRQIHN0YXR1cyBjb2RlIGFzc29jaWF0ZWRcclxuICAgKiB3aXRoIHRoZSBlcnJvciAoZS5nLiwgNDAwLCA1MDApLlxyXG4gICAqL1xyXG4gIGNvbnN0cnVjdG9yKG1lc3NhZ2UsIHN0YXR1c0NvZGUpIHtcclxuICAgIHN1cGVyKCk7XHJcblxyXG4gICAgdGhpcy5tZXNzYWdlID0gbWVzc2FnZTtcclxuICAgIHRoaXMuc3RhY2tNZXNzYWdlID0gbWVzc2FnZTtcclxuXHJcbiAgICBpZiAoc3RhdHVzQ29kZSkge1xyXG4gICAgICB0aGlzLnN0YXR1c0NvZGUgPSBzdGF0dXNDb2RlO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgLyoqXHJcbiAgICogU2V0cyBvciB1cGRhdGVzIHRoZSBIVFRQIHN0YXR1cyBjb2RlIGZvciB0aGUgZXJyb3IuXHJcbiAgICpcclxuICAgKiBAcGFyYW0ge251bWJlcn0gc3RhdHVzQ29kZSAtIFRoZSBIVFRQIHN0YXR1cyBjb2RlIHRvIGFzc2lnbiB0byB0aGUgZXJyb3IuXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7RXhwb3J0RXJyb3J9IFRoZSB1cGRhdGVkIGluc3RhbmNlIG9mIHRoZSBgRXhwb3J0RXJyb3JgIGNsYXNzLlxyXG4gICAqL1xyXG4gIHNldFN0YXR1cyhzdGF0dXNDb2RlKSB7XHJcbiAgICB0aGlzLnN0YXR1c0NvZGUgPSBzdGF0dXNDb2RlO1xyXG5cclxuICAgIHJldHVybiB0aGlzO1xyXG4gIH1cclxuXHJcbiAgLyoqXHJcbiAgICogU2V0cyBhZGRpdGlvbmFsIGVycm9yIGRldGFpbHMgYmFzZWQgb24gYW4gZXhpc3RpbmcgZXJyb3Igb2JqZWN0LlxyXG4gICAqXHJcbiAgICogQHBhcmFtIHtFcnJvcn0gZXJyb3IgLSBBbiBlcnJvciBvYmplY3QgY29udGFpbmluZyBkZXRhaWxzIHRvIHBvcHVsYXRlXHJcbiAgICogdGhlIGBFeHBvcnRFcnJvcmAgaW5zdGFuY2UuXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7RXhwb3J0RXJyb3J9IFRoZSB1cGRhdGVkIGluc3RhbmNlIG9mIHRoZSBgRXhwb3J0RXJyb3JgIGNsYXNzLlxyXG4gICAqL1xyXG4gIHNldEVycm9yKGVycm9yKSB7XHJcbiAgICB0aGlzLmVycm9yID0gZXJyb3I7XHJcblxyXG4gICAgaWYgKGVycm9yLm5hbWUpIHtcclxuICAgICAgdGhpcy5uYW1lID0gZXJyb3IubmFtZTtcclxuICAgIH1cclxuXHJcbiAgICBpZiAoZXJyb3Iuc3RhdHVzQ29kZSkge1xyXG4gICAgICB0aGlzLnN0YXR1c0NvZGUgPSBlcnJvci5zdGF0dXNDb2RlO1xyXG4gICAgfVxyXG5cclxuICAgIGlmIChlcnJvci5zdGFjaykge1xyXG4gICAgICB0aGlzLnN0YWNrTWVzc2FnZSA9IGVycm9yLm1lc3NhZ2U7XHJcbiAgICAgIHRoaXMuc3RhY2sgPSBlcnJvci5zdGFjaztcclxuICAgIH1cclxuXHJcbiAgICByZXR1cm4gdGhpcztcclxuICB9XHJcbn1cclxuXHJcbmV4cG9ydCBkZWZhdWx0IEV4cG9ydEVycm9yO1xyXG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxyXG5cclxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXHJcblxyXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNSwgSGlnaHNvZnRcclxuXHJcbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cclxuXHJcbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxyXG5cclxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxyXG5cclxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cclxuXHJcbi8qKlxyXG4gKiBAb3ZlcnZpZXcgTWFuYWdlcyBjb25maWd1cmF0aW9uIGZvciB0aGUgSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyIGJ5IGxvYWRpbmdcclxuICogYW5kIG1lcmdpbmcgb3B0aW9ucyBmcm9tIG11bHRpcGxlIHNvdXJjZXMsIHN1Y2ggYXMgZGVmYXVsdCBzZXR0aW5ncyxcclxuICogZW52aXJvbm1lbnQgdmFyaWFibGVzLCB1c2VyLXByb3ZpZGVkIG9wdGlvbnMsIGFuZCBjb21tYW5kLWxpbmUgYXJndW1lbnRzLlxyXG4gKiBFbnN1cmVzIHRoZSBnbG9iYWwgb3B0aW9ucyBhcmUgdXAtdG8tZGF0ZSB3aXRoIHRoZSBoaWdoZXN0IHByaW9yaXR5IHZhbHVlcy5cclxuICogUHJvdmlkZXMgZnVuY3Rpb25zIGZvciBhY2Nlc3NpbmcgYW5kIHVwZGF0aW5nIGNvbmZpZ3VyYXRpb24uXHJcbiAqL1xyXG5cclxuaW1wb3J0IHsgcmVhZEZpbGVTeW5jIH0gZnJvbSAnZnMnO1xyXG5pbXBvcnQgeyBqb2luIH0gZnJvbSAncGF0aCc7XHJcblxyXG5pbXBvcnQgeyBsb2csIGxvZ1dpdGhTdGFjaywgbG9nWm9kSXNzdWVzIH0gZnJvbSAnLi9sb2dnZXIuanMnO1xyXG5pbXBvcnQgeyBfX2Rpcm5hbWUsIGlzT2JqZWN0LCBkZWVwQ29weSwgZ2V0QWJzb2x1dGVQYXRoIH0gZnJvbSAnLi91dGlscy5qcyc7XHJcbmltcG9ydCB7XHJcbiAgZW52cyxcclxuICBsb29zZVZhbGlkYXRlLFxyXG4gIHN0cmljdFZhbGlkYXRlLFxyXG4gIHZhbGlkYXRvcnNcclxufSBmcm9tICcuL3ZhbGlkYXRpb24uanMnO1xyXG5cclxuaW1wb3J0IHsgZGVmYXVsdENvbmZpZywgbmVzdGVkUHJvcHMsIGFic29sdXRlUHJvcHMgfSBmcm9tICcuL3NjaGVtYXMvY29uZmlnLmpzJztcclxuXHJcbmltcG9ydCBFeHBvcnRFcnJvciBmcm9tICcuL2Vycm9ycy9FeHBvcnRFcnJvci5qcyc7XHJcblxyXG4vLyBTZXRzIHRoZSBnbG9iYWwgb3B0aW9ucyB3aXRoIGluaXRpYWwgdmFsdWVzIGZyb20gdGhlIGRlZmF1bHQgY29uZmlnXHJcbmNvbnN0IGdsb2JhbE9wdGlvbnMgPSBfaW5pdEdsb2JhbE9wdGlvbnMoZGVmYXVsdENvbmZpZyk7XHJcblxyXG4vLyBBbiBvYmplY3QgZm9yIHRoZSBpbnN0YW5jZSBvcHRpb25zLCBjcmVhdGVkIGVhY2ggdGltZSB0aGUgYGluaXRFeHBvcnRgIG9jY3Vyc1xyXG5jb25zdCBpbnN0YW5jZU9wdGlvbnMgPSBkZWVwQ29weShnbG9iYWxPcHRpb25zKTtcclxuXHJcbi8qKlxyXG4gKiBSZXRyaWV2ZXMgYSByZWZlcmVuY2UgdG8gdGhlIG9wdGlvbnMgb2JqZWN0LiBEZXBlbmRpbmcgb24gdGhlIGBnZXRJbnN0YW5jZWBcclxuICogcGFyYW1ldGVyLCBpdCByZXR1cm5zIGVpdGhlciB0aGUgZ2xvYmFsIG9wdGlvbnMgb3IgdGhlIGluc3RhbmNlLXNwZWNpZmljXHJcbiAqIG9wdGlvbnMgb2JqZWN0LlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gZ2V0T3B0aW9uc1xyXG4gKlxyXG4gKiBAcGFyYW0ge2Jvb2xlYW59IFtnZXRJbnN0YW5jZT10cnVlXSAtIE9wdGlvbmFsIHBhcmFtZXRlciB0aGF0IGRlY2lkZXMgd2hldGhlclxyXG4gKiB0byByZXR1cm4gdGhlIGluc3RhbmNlLXNwZWNpZmljIG9wdGlvbnMgKHdoZW4gYHRydWVgKSBvciB0aGUgZ2xvYmFsIG9wdGlvbnNcclxuICogKHdoZW4gYGZhbHNlYCkuIFRoZSBkZWZhdWx0IHZhbHVlIGlzIGB0cnVlYC5cclxuICpcclxuICogQHJldHVybnMge09iamVjdH0gQSByZWZlcmVuY2UgdG8gZWl0aGVyIHRoZSBnbG9iYWwgb3B0aW9uc1xyXG4gKiBvciB0aGUgaW5zdGFuY2Utc3BlY2lmaWMgb3B0aW9ucywgYmFzZWQgb24gdGhlIGBnZXRJbnN0YW5jZWAgcGFyYW1ldGVyLlxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIGdldE9wdGlvbnMoZ2V0SW5zdGFuY2UgPSB0cnVlKSB7XHJcbiAgcmV0dXJuIGdldEluc3RhbmNlID8gaW5zdGFuY2VPcHRpb25zIDogZ2xvYmFsT3B0aW9ucztcclxufVxyXG5cclxuLyoqXHJcbiAqIFNldHMgdGhlIGdsb2JhbCBvcHRpb25zIG9mIHRoZSBleHBvcnQgc2VydmVyLCBrZWVwaW5nIHRoZSBwcmluY2lwbGVcclxuICogb2YgdGhlIG9wdGlvbnMgbG9hZCBwcmlvcml0eSBmcm9tIGFsbCBhdmFpbGFibGUgc291cmNlcy4gSXQgYWNjZXB0cyBvcHRpb25hbFxyXG4gKiBgY3VzdG9tT3B0aW9uc2Agb2JqZWN0IGFuZCBgY2xpQXJnc2AgYXJyYXkgd2l0aCBhcmd1bWVudHMgZnJvbSB0aGUgQ0xJLiBUaGVzZVxyXG4gKiBvcHRpb25zIHdpbGwgYmUgdmFsaWRhdGVkIGFuZCBhcHBsaWVkIGlmIHByb3ZpZGVkLlxyXG4gKlxyXG4gKiBUaGUgcHJpb3JpdHkgb3JkZXIgb2Ygc2V0dGluZyB2YWx1ZXMgaXM6XHJcbiAqXHJcbiAqIDEuIE9wdGlvbnMgZnJvbSB0aGUgYGxpYi9zY2hlbWFzL2NvbmZpZy5qc2AgZmlsZSAoZGVmYXVsdCB2YWx1ZXMpLlxyXG4gKiAyLiBPcHRpb25zIGZyb20gYSBjdXN0b20gSlNPTiBmaWxlIChsb2FkZWQgYnkgdGhlIGBsb2FkQ29uZmlnYCBvcHRpb24pLlxyXG4gKiAzLiBPcHRpb25zIGZyb20gdGhlIGVudmlyb25tZW50IHZhcmlhYmxlcyAodGhlIGAuZW52YCBmaWxlKS5cclxuICogNC4gT3B0aW9ucyBmcm9tIHRoZSBjb21tYW5kIGxpbmUgaW50ZXJmYWNlIChDTEkpLlxyXG4gKiA1LiBPcHRpb25zIGZyb20gdGhlIGZpcnN0IHBhcmFtZXRlciAodGhlIGBjdXN0b21PcHRpb25zYCBpcyBieSBkZWZhdWx0XHJcbiAqIGFuIGVtcHR5IG9iamVjdCkuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBzZXRHbG9iYWxPcHRpb25zXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBbY3VzdG9tT3B0aW9ucz17fV0gLSBPcHRpb25hbCBjdXN0b20gb3B0aW9ucyBmb3IgYWRkaXRpb25hbFxyXG4gKiBjb25maWd1cmF0aW9uLiBUaGUgZGVmYXVsdCB2YWx1ZSBpcyBhbiBlbXB0eSBvYmplY3QuXHJcbiAqIEBwYXJhbSB7QXJyYXkuPHN0cmluZz59IFtjbGlBcmdzPVtdXSAtIE9wdGlvbmFsIGNvbW1hbmQgbGluZSBhcmd1bWVudHNcclxuICogZm9yIGFkZGl0aW9uYWwgY29uZmlndXJhdGlvbi4gVGhlIGRlZmF1bHQgdmFsdWUgaXMgYW4gZW1wdHkgYXJyYXkuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtPYmplY3R9IFRoZSB1cGRhdGVkIGdsb2JhbCBvcHRpb25zIG9iamVjdCwgcmVmbGVjdGluZyB0aGUgbWVyZ2VkXHJcbiAqIGNvbmZpZ3VyYXRpb24gZnJvbSBhbGwgYXZhaWxhYmxlIHNvdXJjZXMuXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gc2V0R2xvYmFsT3B0aW9ucyhjdXN0b21PcHRpb25zID0ge30sIGNsaUFyZ3MgPSBbXSkge1xyXG4gIC8vIE9iamVjdCBmb3Igb3B0aW9ucyBsb2FkZWQgdmlhIHRoZSBgbG9hZENvbmZpZ2Agb3B0aW9uXHJcbiAgbGV0IGNvbmZpZ09wdGlvbnMgPSB7fTtcclxuXHJcbiAgLy8gT2JqZWN0IGZvciBvcHRpb25zIGZyb20gdGhlIENMSVxyXG4gIGxldCBjbGlPcHRpb25zID0ge307XHJcblxyXG4gIC8vIE9ubHkgZm9yIHRoZSBDTEkgdXNhZ2VcclxuICBpZiAoY2xpQXJncyAmJiBBcnJheS5pc0FycmF5KGNsaUFyZ3MpICYmIGNsaUFyZ3MubGVuZ3RoKSB7XHJcbiAgICB0cnkge1xyXG4gICAgICAvLyBWYWxpZGF0ZSBvcHRpb25zIGZyb20gdGhlIGN1c3RvbSBKU09OIGxvYWRlZCB2aWEgdGhlIGBsb2FkQ29uZmlnYFxyXG4gICAgICBjb25maWdPcHRpb25zID0gc3RyaWN0VmFsaWRhdGUoXHJcbiAgICAgICAgX2xvYWRDb25maWdGaWxlKGNsaUFyZ3MsIGdsb2JhbE9wdGlvbnMuY3VzdG9tTG9naWMpXHJcbiAgICAgICk7XHJcbiAgICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgICBsb2dab2RJc3N1ZXMoXHJcbiAgICAgICAgMSxcclxuICAgICAgICBlcnJvci5pc3N1ZXMsXHJcbiAgICAgICAgJ1t2YWxpZGF0aW9uXSBDdXN0b20gb3B0aW9ucyBmcm9tIHRoZSBgbG9hZENvbmZpZ2Agb3B0aW9uIHZhbGlkYXRpb24gZXJyb3InXHJcbiAgICAgICk7XHJcbiAgICB9XHJcblxyXG4gICAgdHJ5IHtcclxuICAgICAgLy8gVmFsaWRhdGUgb3B0aW9ucyBmcm9tIHRoZSBDTElcclxuICAgICAgY2xpT3B0aW9ucyA9IGxvb3NlVmFsaWRhdGUoX3BhaXJBcmd1bWVudFZhbHVlKG5lc3RlZFByb3BzLCBjbGlBcmdzKSk7XHJcbiAgICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgICBsb2dab2RJc3N1ZXMoXHJcbiAgICAgICAgMSxcclxuICAgICAgICBlcnJvci5pc3N1ZXMsXHJcbiAgICAgICAgJ1t2YWxpZGF0aW9uXSBDTEkgb3B0aW9ucyB2YWxpZGF0aW9uIGVycm9yJ1xyXG4gICAgICApO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgLy8gQXBwbHkgY3VzdG9tIG9wdGlvbnMgaWYgdGhlcmUgYXJlIGFueVxyXG4gIGlmIChcclxuICAgIGN1c3RvbU9wdGlvbnMgJiZcclxuICAgIGlzT2JqZWN0KGN1c3RvbU9wdGlvbnMpICYmXHJcbiAgICBPYmplY3Qua2V5cyhjdXN0b21PcHRpb25zKS5sZW5ndGhcclxuICApIHtcclxuICAgIHRyeSB7XHJcbiAgICAgIC8vIFZhbGlkYXRlIGN1c3RvbSBvcHRpb25zIHByb3ZpZGVkIGJ5IHRoZSB1c2VyXHJcbiAgICAgIGN1c3RvbU9wdGlvbnMgPSBzdHJpY3RWYWxpZGF0ZShjdXN0b21PcHRpb25zKTtcclxuICAgIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICAgIGxvZ1pvZElzc3VlcyhcclxuICAgICAgICAxLFxyXG4gICAgICAgIGVycm9yLmlzc3VlcyxcclxuICAgICAgICAnW3ZhbGlkYXRpb25dIEN1c3RvbSBvcHRpb25zIHZhbGlkYXRpb24gZXJyb3InXHJcbiAgICAgICk7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICAvLyBVcGRhdGUgdmFsdWVzIG9mIHRoZSBnbG9iYWwgb3B0aW9ucyB3aXRoIHZhbHVlcyBmcm9tIGVhY2ggc291cmNlIHBvc3NpYmxlXHJcbiAgX3VwZGF0ZUdsb2JhbE9wdGlvbnMoXHJcbiAgICBkZWZhdWx0Q29uZmlnLFxyXG4gICAgZ2xvYmFsT3B0aW9ucyxcclxuICAgIGNvbmZpZ09wdGlvbnMsXHJcbiAgICBjbGlPcHRpb25zLFxyXG4gICAgY3VzdG9tT3B0aW9uc1xyXG4gICk7XHJcblxyXG4gIC8vIFJldHVybiB1cGRhdGVkIGdsb2JhbCBvcHRpb25zXHJcbiAgcmV0dXJuIGdsb2JhbE9wdGlvbnM7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBVcGRhdGVzIHRoZSBpbnN0YW5jZSBvcHRpb25zIHdpdGggYWRkaXRpb25hbCBvcHRpb25zLiBJdCBvcHRpb25hbGx5IGFsbG93c1xyXG4gKiB0byByZWluaXRpYWxpemUgdGhlIGluc3RhbmNlIG9wdGlvbnMgd2l0aCB0aGUgdmFsdWVzIG9mIGEgY3VycmVudCBnbG9iYWxcclxuICogb3B0aW9ucyBvYmplY3QuXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSB1cGRhdGVPcHRpb25zIC0gVGhlIHVwZGF0ZSBvcHRpb25zIHRvIG1lcmdlIGludG8gdGhlIGluc3RhbmNlXHJcbiAqIG9wdGlvbnMuXHJcbiAqIEBwYXJhbSB7Ym9vbGVhbn0gW25ld0luc3RhbmNlPWZhbHNlXSAtIEEgZmxhZyB0byBpbmRpY2F0ZSB3aGV0aGVyIHRvIGluaXRcclxuICogb3B0aW9ucyBmb3IgYSBuZXcgaW5zdGFuY2UuIElmIGB0cnVlYCwgdGhlIGV4aXN0aW5nIGluc3RhbmNlIG9wdGlvbnMgd2lsbFxyXG4gKiBiZSBjbGVhcmVkIGFuZCByZWluaXRpYWxpemVkIGJhc2VkIG9uIHRoZSBnbG9iYWwgb3B0aW9ucy5cclxuICpcclxuICogQHJldHVybnMge09iamVjdH0gLSBUaGUgdXBkYXRlZCBpbnN0YW5jZSBvcHRpb25zLlxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIHVwZGF0ZU9wdGlvbnModXBkYXRlT3B0aW9ucywgbmV3SW5zdGFuY2UgPSBmYWxzZSkge1xyXG4gIC8vIENoZWNrIGlmIG9wdGlvbnMgbmVlZCB0byBiZSBjcmVhdGVkIGZvciBhIG5ldyBpbnN0YW5jZVxyXG4gIGlmIChuZXdJbnN0YW5jZSkge1xyXG4gICAgLy8gR2V0IHJpZCBvZiB0aGUgb2xkIGluc3RhbmNlIG9wdGlvbnNcclxuICAgIE9iamVjdC5rZXlzKGluc3RhbmNlT3B0aW9ucykuZm9yRWFjaCgoa2V5KSA9PiB7XHJcbiAgICAgIGRlbGV0ZSBpbnN0YW5jZU9wdGlvbnNba2V5XTtcclxuICAgIH0pO1xyXG5cclxuICAgIC8vIEluaXQgdGhlIG5ldyBpbnN0YW5jZSBvcHRpb25zIGJhc2VkIG9uIHRoZSBnbG9iYWwgb3B0aW9uc1xyXG4gICAgbWVyZ2VPcHRpb25zKGluc3RhbmNlT3B0aW9ucywgZGVlcENvcHkoZ2xvYmFsT3B0aW9ucykpO1xyXG4gIH1cclxuXHJcbiAgLy8gTWVyZ2UgYWRkaXRpb25hbCBvcHRpb25zIHRvIHRoZSBpbnN0YW5jZSBvcHRpb25zXHJcbiAgbWVyZ2VPcHRpb25zKGluc3RhbmNlT3B0aW9ucywgdXBkYXRlT3B0aW9ucyk7XHJcblxyXG4gIC8vIFJldHVybiB0aGUgcmVmZXJlbmNlIHRvIHRoZSBpbnN0YW5jZSBvcHRpb25zIG9iamVjdFxyXG4gIHJldHVybiBpbnN0YW5jZU9wdGlvbnM7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBNZXJnZXMgdHdvIHNldHMgb2YgY29uZmlndXJhdGlvbiBvcHRpb25zLCBjb25zaWRlcmluZyBhYnNvbHV0ZSBwcm9wZXJ0aWVzLlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gbWVyZ2VPcHRpb25zXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBvcmlnaW5hbE9wdGlvbnMgLSBPcmlnaW5hbCBjb25maWd1cmF0aW9uIG9wdGlvbnMuXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBuZXdPcHRpb25zIC0gTmV3IGNvbmZpZ3VyYXRpb24gb3B0aW9ucyB0byBiZSBtZXJnZWQuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtPYmplY3R9IE1lcmdlZCBjb25maWd1cmF0aW9uIG9wdGlvbnMuXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gbWVyZ2VPcHRpb25zKG9yaWdpbmFsT3B0aW9ucywgbmV3T3B0aW9ucykge1xyXG4gIC8vIENoZWNrIGlmIHRoZSBgb3JpZ2luYWxPcHRpb25zYCBhbmQgYG5ld09wdGlvbnNgIGFyZSBjb3JyZWN0IG9iamVjdHNcclxuICBpZiAoaXNPYmplY3Qob3JpZ2luYWxPcHRpb25zKSAmJiBpc09iamVjdChuZXdPcHRpb25zKSkge1xyXG4gICAgZm9yIChjb25zdCBba2V5LCB2YWx1ZV0gb2YgT2JqZWN0LmVudHJpZXMobmV3T3B0aW9ucykpIHtcclxuICAgICAgb3JpZ2luYWxPcHRpb25zW2tleV0gPVxyXG4gICAgICAgIGlzT2JqZWN0KHZhbHVlKSAmJlxyXG4gICAgICAgICFhYnNvbHV0ZVByb3BzLmluY2x1ZGVzKGtleSkgJiZcclxuICAgICAgICBvcmlnaW5hbE9wdGlvbnNba2V5XSAhPT0gdW5kZWZpbmVkXHJcbiAgICAgICAgICA/IG1lcmdlT3B0aW9ucyhvcmlnaW5hbE9wdGlvbnNba2V5XSwgdmFsdWUpXHJcbiAgICAgICAgICA6IHZhbHVlICE9PSB1bmRlZmluZWRcclxuICAgICAgICAgICAgPyB2YWx1ZVxyXG4gICAgICAgICAgICA6IG9yaWdpbmFsT3B0aW9uc1trZXldIHx8IG51bGw7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICAvLyBSZXR1cm4gdGhlIG9yaWdpbmFsIChtb2RpZmllZCBvciBub3QpIG9wdGlvbnNcclxuICByZXR1cm4gb3JpZ2luYWxPcHRpb25zO1xyXG59XHJcblxyXG4vKipcclxuICogTWFwcyBvbGQtc3RydWN0dXJlZCBjb25maWd1cmF0aW9uIG9wdGlvbnMgKFBoYW50b21KUykgdG8gYSBuZXcgZm9ybWF0XHJcbiAqIChQdXBwZXRlZXIpLiBUaGlzIGZ1bmN0aW9uIGNvbnZlcnRzIGZsYXQsIG9sZC1zdHJ1Y3R1cmVkIG9wdGlvbnMgaW50b1xyXG4gKiBhIG5ldywgbmVzdGVkIGNvbmZpZ3VyYXRpb24gZm9ybWF0IGJhc2VkIG9uIGEgcHJlZGVmaW5lZCBtYXBwaW5nXHJcbiAqIChgbmVzdGVkUHJvcHNgKS4gVGhlIG5ldyBmb3JtYXQgaXMgdXNlZCBmb3IgUHVwcGV0ZWVyLCB3aGlsZSB0aGUgb2xkIGZvcm1hdFxyXG4gKiB3YXMgdXNlZCBmb3IgUGhhbnRvbUpTLlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gbWFwVG9OZXdPcHRpb25zXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBvbGRPcHRpb25zIC0gVGhlIG9sZCwgZmxhdCBjb25maWd1cmF0aW9uIG9wdGlvbnNcclxuICogdG8gYmUgY29udmVydGVkLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7T2JqZWN0fSBBIG5ldyBvYmplY3QgY29udGFpbmluZyBvcHRpb25zIHN0cnVjdHVyZWQgYWNjb3JkaW5nXHJcbiAqIHRvIHRoZSBtYXBwaW5nIGRlZmluZWQgaW4gYG5lc3RlZFByb3BzYCBvciBhbiBlbXB0eSBvYmplY3QgaWYgdGhlIHByb3ZpZGVkXHJcbiAqIGBvbGRPcHRpb25zYCBpcyBub3QgYSBjb3JyZWN0IG9iamVjdC5cclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiBtYXBUb05ld09wdGlvbnMob2xkT3B0aW9ucykge1xyXG4gIC8vIEFuIG9iamVjdCBmb3IgdGhlIG5ldyBzdHJ1Y3R1cmVkIG9wdGlvbnNcclxuICBjb25zdCBuZXdPcHRpb25zID0ge307XHJcblxyXG4gIC8vIENoZWNrIGlmIHByb3ZpZGVkIHZhbHVlIGlzIGEgY29ycmVjdCBvYmplY3RcclxuICBpZiAoaXNPYmplY3Qob2xkT3B0aW9ucykpIHtcclxuICAgIC8vIEl0ZXJhdGUgb3ZlciBlYWNoIGtleS12YWx1ZSBwYWlyIGluIHRoZSBvbGQtc3RydWN0dXJlZCBvcHRpb25zXHJcbiAgICBmb3IgKGNvbnN0IFtrZXksIHZhbHVlXSBvZiBPYmplY3QuZW50cmllcyhvbGRPcHRpb25zKSkge1xyXG4gICAgICAvLyBJZiB0aGVyZSBpcyBhIG5lc3RlZCBtYXBwaW5nLCBzcGxpdCBpdCBpbnRvIGEgcHJvcGVydGllcyBjaGFpblxyXG4gICAgICBjb25zdCBwcm9wZXJ0aWVzQ2hhaW4gPSBuZXN0ZWRQcm9wc1trZXldXHJcbiAgICAgICAgPyBuZXN0ZWRQcm9wc1trZXldLnNwbGl0KCcuJylcclxuICAgICAgICA6IFtdO1xyXG5cclxuICAgICAgLy8gSWYgaXQgaXMgdGhlIGxhc3QgcHJvcGVydHkgaW4gdGhlIGNoYWluLCBhc3NpZ24gdGhlIHZhbHVlLCBvdGhlcndpc2UsXHJcbiAgICAgIC8vIGNyZWF0ZSBvciByZXVzZSB0aGUgbmVzdGVkIG9iamVjdFxyXG4gICAgICBwcm9wZXJ0aWVzQ2hhaW4ucmVkdWNlKFxyXG4gICAgICAgIChvYmosIHByb3AsIGluZGV4KSA9PlxyXG4gICAgICAgICAgKG9ialtwcm9wXSA9XHJcbiAgICAgICAgICAgIHByb3BlcnRpZXNDaGFpbi5sZW5ndGggLSAxID09PSBpbmRleCA/IHZhbHVlIDogb2JqW3Byb3BdIHx8IHt9KSxcclxuICAgICAgICBuZXdPcHRpb25zXHJcbiAgICAgICk7XHJcbiAgICB9XHJcbiAgfSBlbHNlIHtcclxuICAgIGxvZyhcclxuICAgICAgMixcclxuICAgICAgJ1tjb25maWddIE5vIGNvcnJlY3Qgb2JqZWN0IHdpdGggb3B0aW9ucyB3YXMgcHJvdmlkZWQuIFJldHVybmluZyBhbiBlbXB0eSBhcnJheS4nXHJcbiAgICApO1xyXG4gIH1cclxuXHJcbiAgLy8gUmV0dXJuIHRoZSBuZXcsIHN0cnVjdHVyZWQgb3B0aW9ucyBvYmplY3RcclxuICByZXR1cm4gbmV3T3B0aW9ucztcclxufVxyXG5cclxuLyoqXHJcbiAqIFZhbGlkYXRlcyBhIHNwZWNpZmllZCBvcHRpb24gdXNpbmcgdGhlIGNvcnJlc3BvbmRpbmcgdmFsaWRhdG9yIGZyb20gdGhlXHJcbiAqIGNvbmZpZ3VyYXRpb24gb2JqZWN0LiBSZXR1cm5zIHRoZSBvcmlnaW5hbCBvcHRpb24gaWYgdGhlIHZhbGlkYXRpb25cclxuICogaXMgZGlzYWJsZWQgZ2xvYmFsbHkuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiB2YWxpZGF0ZU9wdGlvblxyXG4gKlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gbmFtZSAtIFRoZSBuYW1lIG9mIHRoZSBvcHRpb24gdG8gdmFsaWRhdGUuXHJcbiAqIEBwYXJhbSB7YW55fSBjb25maWdPcHRpb24gLSBUaGUgdmFsdWUgb2YgdGhlIG9wdGlvbiB0byB2YWxpZGF0ZS5cclxuICogQHBhcmFtIHtib29sZWFufSBbc3RyaWN0Q2hlY2s9dHJ1ZV0gLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb25cclxuICogc2hvdWxkIGJlIGFwcGxpZWQuIFRoZSBkZWZhdWx0IHZhbHVlIGlzIGB0cnVlYC5cclxuICpcclxuICogQHJldHVybnMge2FueX0gVGhlIHBhcnNlZCBhbmQgdmFsaWRhdGVkIHZhbHVlIG9mIHRoZSBvcHRpb24uXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gdmFsaWRhdGVPcHRpb24obmFtZSwgY29uZmlnT3B0aW9uLCBzdHJpY3RDaGVjayA9IHRydWUpIHtcclxuICAvLyBSZXR1cm4gdGhlIG9yaWdpbmFsIG9wdGlvbiBpZiB0aGUgdmFsaWRhdGlvbiBpcyBkaXNhYmxlZFxyXG4gIGlmICghZ2V0T3B0aW9ucygpLm90aGVyLnZhbGlkYXRpb24pIHtcclxuICAgIHJldHVybiBjb25maWdPcHRpb247XHJcbiAgfVxyXG5cclxuICB0cnkge1xyXG4gICAgLy8gUmV0dXJuIHZhbGlkYXRlZCBvcHRpb25cclxuICAgIHJldHVybiB2YWxpZGF0b3JzW25hbWVdKHN0cmljdENoZWNrKS5wYXJzZShjb25maWdPcHRpb24pO1xyXG4gIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICAvLyBMb2cgWm9kIGlzc3Vlc1xyXG4gICAgbG9nWm9kSXNzdWVzKFxyXG4gICAgICAxLFxyXG4gICAgICBlcnJvci5pc3N1ZXMsXHJcbiAgICAgIGBbdmFsaWRhdGlvbl0gVGhlICR7bmFtZX0gb3B0aW9uIHZhbGlkYXRpb24gZXJyb3JgXHJcbiAgICApO1xyXG5cclxuICAgIC8vIFRocm93IHZhbGlkYXRpb24gZXJyb3JcclxuICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcihcclxuICAgICAgYFt2YWxpZGF0aW9uXSBUaGUgJHtuYW1lfSBvcHRpb24gdmFsaWRhdGlvbiBlcnJvcmAsXHJcbiAgICAgIDQwMFxyXG4gICAgKTtcclxuICB9XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBWYWxpZGF0ZXMgdGhlIHByb3ZpZGVkIGNvbmZpZ3VyYXRpb24gb3B0aW9ucyBmb3IgdGhlIGV4cG9ydGluZyBwcm9jZXNzLlxyXG4gKiBSZXR1cm5zIHRoZSBvcmlnaW5hbCBvcHRpb24gaWYgdGhlIHZhbGlkYXRpb24gaXMgZGlzYWJsZWQgZ2xvYmFsbHkuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiB2YWxpZGF0ZU9wdGlvbnNcclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IGNvbmZpZ09wdGlvbnMgLSBUaGUgY29uZmlndXJhdGlvbiBvcHRpb25zIHRvIGJlIHZhbGlkYXRlZC5cclxuICogQHBhcmFtIHtib29sZWFufSBbc3RyaWN0Q2hlY2s9dHJ1ZV0gLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb25cclxuICogc2hvdWxkIGJlIGFwcGxpZWQuIFRoZSBkZWZhdWx0IHZhbHVlIGlzIGB0cnVlYC5cclxuICpcclxuICogQHJldHVybnMge09iamVjdH0gVGhlIHBhcnNlZCBhbmQgdmFsaWRhdGVkIGNvbmZpZ3VyYXRpb24gb3B0aW9ucyBvYmplY3QuXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gdmFsaWRhdGVPcHRpb25zKGNvbmZpZ09wdGlvbnMsIHN0cmljdENoZWNrID0gdHJ1ZSkge1xyXG4gIC8vIFJldHVybiB0aGUgb3JpZ2luYWwgY29uZmlnIGlmIHRoZSB2YWxpZGF0aW9uIGlzIGRpc2FibGVkXHJcbiAgaWYgKCFnZXRPcHRpb25zKCkub3RoZXIudmFsaWRhdGlvbikge1xyXG4gICAgcmV0dXJuIGNvbmZpZ09wdGlvbnM7XHJcbiAgfVxyXG5cclxuICB0cnkge1xyXG4gICAgLy8gUmV0dXJuIHZhbGlkYXRlZCBvcHRpb25zXHJcbiAgICByZXR1cm4gc3RyaWN0Q2hlY2tcclxuICAgICAgPyBzdHJpY3RWYWxpZGF0ZShjb25maWdPcHRpb25zKVxyXG4gICAgICA6IGxvb3NlVmFsaWRhdGUoY29uZmlnT3B0aW9ucyk7XHJcbiAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgIC8vIExvZyBab2QgaXNzdWVzXHJcbiAgICBsb2dab2RJc3N1ZXMoMSwgZXJyb3IuaXNzdWVzLCAnW3ZhbGlkYXRpb25dIE9wdGlvbnMgdmFsaWRhdGlvbiBlcnJvcicpO1xyXG5cclxuICAgIC8vIFRocm93IHZhbGlkYXRpb24gZXJyb3JcclxuICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcignW3ZhbGlkYXRpb25dIE9wdGlvbnMgdmFsaWRhdGlvbiBlcnJvcicsIDQwMCk7XHJcbiAgfVxyXG59XHJcblxyXG4vKipcclxuICogVmFsaWRhdGVzLCBwYXJzZXMsIGFuZCBjaGVja3MgaWYgdGhlIHByb3ZpZGVkIGNvbmZpZyBpcyBhbGxvd2VkIHNldFxyXG4gKiBvZiBvcHRpb25zLlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gaXNBbGxvd2VkQ29uZmlnXHJcbiAqXHJcbiAqIEBwYXJhbSB7dW5rbm93bn0gY29uZmlnIC0gVGhlIGNvbmZpZyB0byBiZSB2YWxpZGF0ZWQgYW5kIHBhcnNlZCBhcyBhIHNldFxyXG4gKiBvZiBvcHRpb25zLiBNdXN0IGJlIGVpdGhlciBhbiBvYmplY3Qgb3IgYSBzdHJpbmcuXHJcbiAqIEBwYXJhbSB7Ym9vbGVhbn0gW3RvU3RyaW5nPWZhbHNlXSAtIFdoZXRoZXIgdG8gcmV0dXJuIGEgc3RyaW5naWZpZWQgdmVyc2lvblxyXG4gKiBvZiB0aGUgcGFyc2VkIGNvbmZpZy4gVGhlIGRlZmF1bHQgdmFsdWUgaXMgYGZhbHNlYC5cclxuICogQHBhcmFtIHtib29sZWFufSBbYWxsb3dGdW5jdGlvbnM9ZmFsc2VdIC0gV2hldGhlciB0byBhbGxvdyBmdW5jdGlvbnNcclxuICogaW4gdGhlIHBhcnNlZCBjb25maWcuIElmIHRydWUsIGZ1bmN0aW9ucyBhcmUgcHJlc2VydmVkLiBPdGhlcndpc2UsIHdoZW5cclxuICogYSBmdW5jdGlvbiBpcyBmb3VuZCwgbnVsbCBpcyByZXR1cm5lZC4gVGhlIGRlZmF1bHQgdmFsdWUgaXMgYGZhbHNlYC5cclxuICpcclxuICogQHJldHVybnMgeyhPYmplY3R8c3RyaW5nfG51bGwpfSBSZXR1cm5zIGEgcGFyc2VkIHNldCBvZiBvcHRpb25zIG9iamVjdCxcclxuICogYSBzdHJpbmdpZmllZCBzZXQgb2Ygb3B0aW9ucyBvYmplY3QgaWYgdGhlIGB0b1N0cmluZ2AgaXMgdHJ1ZSwgYW5kIG51bGxcclxuICogaWYgdGhlIGNvbmZpZyBpcyBub3QgYSB2YWxpZCBzZXQgb2Ygb3B0aW9ucyBvciBwYXJzaW5nIGZhaWxzLlxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIGlzQWxsb3dlZENvbmZpZyhcclxuICBjb25maWcsXHJcbiAgdG9TdHJpbmcgPSBmYWxzZSxcclxuICBhbGxvd0Z1bmN0aW9ucyA9IGZhbHNlXHJcbikge1xyXG4gIHRyeSB7XHJcbiAgICAvLyBBY2NlcHQgb25seSBvYmplY3RzIGFuZCBzdHJpbmdzXHJcbiAgICBpZiAoIWlzT2JqZWN0KGNvbmZpZykgJiYgdHlwZW9mIGNvbmZpZyAhPT0gJ3N0cmluZycpIHtcclxuICAgICAgLy8gUmV0dXJuIG51bGwgaWYgYW55IG90aGVyIHR5cGVcclxuICAgICAgcmV0dXJuIG51bGw7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gR2V0IHRoZSBvYmplY3QgcmVwcmVzZW50YXRpb24gb2YgdGhlIG9yaWdpbmFsIGNvbmZpZ1xyXG4gICAgY29uc3Qgb2JqZWN0Q29uZmlnID1cclxuICAgICAgdHlwZW9mIGNvbmZpZyA9PT0gJ3N0cmluZydcclxuICAgICAgICA/IGFsbG93RnVuY3Rpb25zXHJcbiAgICAgICAgICA/IGV2YWwoYCgke2NvbmZpZ30pYClcclxuICAgICAgICAgIDogSlNPTi5wYXJzZShjb25maWcpXHJcbiAgICAgICAgOiBjb25maWc7XHJcblxyXG4gICAgLy8gUHJlc2VydmUgb3IgcmVtb3ZlIHBvdGVudGlhbCBmdW5jdGlvbnMgYmFzZWQgb24gdGhlIGBhbGxvd0Z1bmN0aW9uc2AgZmxhZ1xyXG4gICAgY29uc3Qgc3RyaW5naWZpZWRPcHRpb25zID0gX29wdGlvbnNTdHJpbmdpZnkoXHJcbiAgICAgIG9iamVjdENvbmZpZyxcclxuICAgICAgYWxsb3dGdW5jdGlvbnMsXHJcbiAgICAgIGZhbHNlXHJcbiAgICApO1xyXG5cclxuICAgIC8vIFBhcnNlIHRoZSBjb25maWcgdG8gY2hlY2sgaWYgaXQgaXMgdmFsaWQgc2V0IG9mIG9wdGlvbnNcclxuICAgIGNvbnN0IHBhcnNlZE9wdGlvbnMgPSBhbGxvd0Z1bmN0aW9uc1xyXG4gICAgICA/IEpTT04ucGFyc2UoXHJcbiAgICAgICAgICBfb3B0aW9uc1N0cmluZ2lmeShvYmplY3RDb25maWcsIGFsbG93RnVuY3Rpb25zLCB0cnVlKSxcclxuICAgICAgICAgIChfLCB2YWx1ZSkgPT5cclxuICAgICAgICAgICAgdHlwZW9mIHZhbHVlID09PSAnc3RyaW5nJyAmJiB2YWx1ZS5zdGFydHNXaXRoKCdmdW5jdGlvbicpXHJcbiAgICAgICAgICAgICAgPyBldmFsKGAoJHt2YWx1ZX0pYClcclxuICAgICAgICAgICAgICA6IHZhbHVlXHJcbiAgICAgICAgKVxyXG4gICAgICA6IEpTT04ucGFyc2Uoc3RyaW5naWZpZWRPcHRpb25zKTtcclxuXHJcbiAgICAvLyBSZXR1cm4gc3RyaW5naWZpZWQgb3Igb2JqZWN0IG9wdGlvbnMgYmFzZWQgb24gdGhlIGB0b1N0cmluZ2AgZmxhZ1xyXG4gICAgcmV0dXJuIHRvU3RyaW5nID8gc3RyaW5naWZpZWRPcHRpb25zIDogcGFyc2VkT3B0aW9ucztcclxuICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgLy8gUmV0dXJuIG51bGwgaWYgcGFyc2luZyBmYWlsc1xyXG4gICAgcmV0dXJuIG51bGw7XHJcbiAgfVxyXG59XHJcblxyXG4vKipcclxuICogUHJpbnRzIHRoZSBIaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXIgbG9nbywgdmVyc2lvbiwgYW5kIGxpY2Vuc2UgaW5mb3JtYXRpb24uXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBwcmludExpY2Vuc2VcclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiBwcmludExpY2Vuc2UoKSB7XHJcbiAgLy8gUHJpbnQgdGhlIGxvZ28gYW5kIHZlcnNpb24gaW5mb3JtYXRpb25cclxuICBwcmludFZlcnNpb24oKTtcclxuXHJcbiAgLy8gUHJpbnQgdGhlIGxpY2Vuc2UgaW5mb3JtYXRpb25cclxuICBjb25zb2xlLmxvZyhcclxuICAgICdUaGlzIHNvZnR3YXJlIHJlcXVpcmVzIGEgdmFsaWQgSGlnaGNoYXJ0cyBsaWNlbnNlIGZvciBjb21tZXJjaWFsIHVzZS5cXG4nXHJcbiAgICAgIC55ZWxsb3csXHJcbiAgICAnXFxuRm9yIGEgZnVsbCBsaXN0IG9mIENMSSBvcHRpb25zLCB0eXBlOicsXHJcbiAgICAnXFxuaGlnaGNoYXJ0cy1leHBvcnQtc2VydmVyIC0taGVscFxcbicuZ3JlZW4sXHJcbiAgICAnXFxuSWYgeW91IGRvIG5vdCBoYXZlIGEgbGljZW5zZSwgb25lIGNhbiBiZSBvYnRhaW5lZCBoZXJlOicsXHJcbiAgICAnXFxuaHR0cHM6Ly9zaG9wLmhpZ2hzb2Z0LmNvbS9cXG4nLmdyZWVuLFxyXG4gICAgJ1xcblRvIGN1c3RvbWl6ZSB5b3VyIGluc3RhbGxhdGlvbiwgcGxlYXNlIHJlZmVyIHRvIHRoZSBSRUFETUUgZmlsZSBhdDonLFxyXG4gICAgJ1xcbmh0dHBzOi8vZ2l0aHViLmNvbS9oaWdoY2hhcnRzL25vZGUtZXhwb3J0LXNlcnZlciNyZWFkbWVcXG4nLmdyZWVuXHJcbiAgKTtcclxufVxyXG5cclxuLyoqXHJcbiAqIFByaW50cyB1c2FnZSBpbmZvcm1hdGlvbiBmb3IgQ0xJIGFyZ3VtZW50cywgZGlzcGxheWluZyBhdmFpbGFibGUgb3B0aW9uc1xyXG4gKiBhbmQgdGhlaXIgZGVzY3JpcHRpb25zLiBJdCBjYW4gbGlzdCBwcm9wZXJ0aWVzIHJlY3Vyc2l2ZWx5IGlmIGNhdGVnb3JpZXNcclxuICogY29udGFpbiBuZXN0ZWQgb3B0aW9ucy5cclxuICpcclxuICogQGZ1bmN0aW9uIHByaW50VXNhZ2VcclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiBwcmludFVzYWdlKCkge1xyXG4gIC8vIERpc3BsYXkgUkVBRE1FIGFuZCBnZW5lcmFsIHVzYWdlIGluZm9ybWF0aW9uXHJcbiAgY29uc29sZS5sb2coXHJcbiAgICAnXFxuVXNhZ2Ugb2YgQ0xJIGFyZ3VtZW50czonLmJvbGQsXHJcbiAgICAnXFxuLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0nLFxyXG4gICAgYFxcbkZvciBtb3JlIGRldGFpbGVkIGluZm9ybWF0aW9uLCB2aXNpdCB0aGUgUkVBRE1FIGZpbGUgYXQ6ICR7J2h0dHBzOi8vZ2l0aHViLmNvbS9oaWdoY2hhcnRzL25vZGUtZXhwb3J0LXNlcnZlciNyZWFkbWUnLmdyZWVufS5cXG5gXHJcbiAgKTtcclxuXHJcbiAgLy8gSXRlcmF0ZSB0aHJvdWdoIGVhY2ggY2F0ZWdvcnkgaW4gdGhlIGBkZWZhdWx0Q29uZmlnYCBhbmQgZGlzcGxheSB1c2FnZSBpbmZvXHJcbiAgT2JqZWN0LmtleXMoZGVmYXVsdENvbmZpZykuZm9yRWFjaCgoY2F0ZWdvcnkpID0+IHtcclxuICAgIGNvbnNvbGUubG9nKGAke2NhdGVnb3J5LnRvVXBwZXJDYXNlKCl9YC5ib2xkLnJlZCk7XHJcbiAgICBfY3ljbGVDYXRlZ29yaWVzKGRlZmF1bHRDb25maWdbY2F0ZWdvcnldKTtcclxuICAgIGNvbnNvbGUubG9nKCcnKTtcclxuICB9KTtcclxufVxyXG5cclxuLyoqXHJcbiAqIFByaW50cyB0aGUgSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyIGxvZ28gb3IgdGV4dCB3aXRoIHRoZSB2ZXJzaW9uXHJcbiAqIGluZm9ybWF0aW9uLlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gcHJpbnRWZXJzaW9uXHJcbiAqXHJcbiAqIEBwYXJhbSB7Ym9vbGVhbn0gW25vTG9nbz1mYWxzZV0gLSBJZiB0cnVlLCBvbmx5IHByaW50cyB0ZXh0IHdpdGggdGhlIHZlcnNpb25cclxuICogaW5mb3JtYXRpb24sIHdpdGhvdXQgdGhlIGxvZ28uIFRoZSBkZWZhdWx0IHZhbHVlIGlzIGBmYWxzZWAuXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gcHJpbnRWZXJzaW9uKG5vTG9nbyA9IGZhbHNlKSB7XHJcbiAgLy8gR2V0IHBhY2thZ2UgdmVyc2lvbiBlaXRoZXIgZnJvbSBgLmVudmAgb3IgZnJvbSBgcGFja2FnZS5qc29uYFxyXG4gIGNvbnN0IHBhY2thZ2VWZXJzaW9uID0gSlNPTi5wYXJzZShcclxuICAgIHJlYWRGaWxlU3luYyhqb2luKF9fZGlybmFtZSwgJ3BhY2thZ2UuanNvbicpLCAndXRmOCcpXHJcbiAgKS52ZXJzaW9uO1xyXG5cclxuICAvLyBQcmludCB0ZXh0IG9ubHlcclxuICBpZiAobm9Mb2dvKSB7XHJcbiAgICBjb25zb2xlLmxvZyhgSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyIHYke3BhY2thZ2VWZXJzaW9ufWApO1xyXG4gIH0gZWxzZSB7XHJcbiAgICAvLyBQcmludCB0aGUgbG9nb1xyXG4gICAgY29uc29sZS5sb2coXHJcbiAgICAgIHJlYWRGaWxlU3luYyhqb2luKF9fZGlybmFtZSwgJ21zZycsICdzdGFydHVwLm1zZycpLCAndXRmOCcpLnRvU3RyaW5nKClcclxuICAgICAgICAuYm9sZC55ZWxsb3csXHJcbiAgICAgIGB2JHtwYWNrYWdlVmVyc2lvbn1cXG5gLmJvbGRcclxuICAgICk7XHJcbiAgfVxyXG59XHJcblxyXG4vKipcclxuICogSW5pdGlhbGl6ZXMgYW5kIHJldHVybnMgZ2xvYmFsIG9wdGlvbnMgb2JqZWN0IGJhc2VkIG9uIHByb3ZpZGVkXHJcbiAqIGNvbmZpZ3VyYXRpb24sIHNldHRpbmcgdmFsdWVzIGZyb20gbmVzdGVkIHByb3BlcnRpZXMgcmVjdXJzaXZlbHkuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBfaW5pdEdsb2JhbE9wdGlvbnNcclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IGNvbmZpZyAtIFRoZSBjb25maWd1cmF0aW9uIG9iamVjdCB0byBiZSB1c2VkIGZvciBpbml0aWFsaXppbmdcclxuICogb3B0aW9ucy5cclxuICpcclxuICogQHJldHVybnMge09iamVjdH0gSW5pdGlhbGl6ZWQgb3B0aW9ucyBvYmplY3QuXHJcbiAqL1xyXG5mdW5jdGlvbiBfaW5pdEdsb2JhbE9wdGlvbnMoY29uZmlnKSB7XHJcbiAgY29uc3Qgb3B0aW9ucyA9IHt9O1xyXG5cclxuICAvLyBTdGFydCBpbml0aWFsaXppbmcgdGhlIGBvcHRpb25zYCBvYmplY3QgcmVjdXJzaXZlbHlcclxuICBmb3IgKGNvbnN0IFtuYW1lLCBpdGVtXSBvZiBPYmplY3QuZW50cmllcyhjb25maWcpKSB7XHJcbiAgICBpZiAoT2JqZWN0LnByb3RvdHlwZS5oYXNPd25Qcm9wZXJ0eS5jYWxsKGl0ZW0sICd2YWx1ZScpKSB7XHJcbiAgICAgIC8vIElmIGEgdmFsdWUgZnJvbSBlbnZpcm9ubWVudCB2YXJpYWJsZXMgZXhpc3RzLCBpdCB0YWtlcyBwcmVjZWRlbmNlXHJcbiAgICAgIGNvbnN0IGVudlZhbCA9IGVudnNbaXRlbS5lbnZMaW5rXTtcclxuICAgICAgaWYgKGVudlZhbCAhPT0gdW5kZWZpbmVkICYmIGVudlZhbCAhPT0gbnVsbCkge1xyXG4gICAgICAgIG9wdGlvbnNbbmFtZV0gPSBlbnZWYWw7XHJcbiAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgb3B0aW9uc1tuYW1lXSA9IGl0ZW0udmFsdWU7XHJcbiAgICAgIH1cclxuICAgIH0gZWxzZSB7XHJcbiAgICAgIG9wdGlvbnNbbmFtZV0gPSBfaW5pdEdsb2JhbE9wdGlvbnMoaXRlbSk7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICAvLyBSZXR1cm4gdGhlIGNyZWF0ZWQgYG9wdGlvbnNgIG9iamVjdFxyXG4gIHJldHVybiBvcHRpb25zO1xyXG59XHJcblxyXG4vKipcclxuICogVXBkYXRlcyBnbG9iYWwgb3B0aW9ucyBvYmplY3Qgd2l0aCB2YWx1ZXMgZnJvbSB2YXJpb3VzIHNvdXJjZXMsIGZvbGxvd2luZ1xyXG4gKiBhIHNwZWNpZmljIHByaW9yaXRpemF0aW9uIG9yZGVyLiBUaGUgZnVuY3Rpb24gY2hlY2tzIGZvciB2YWx1ZXMgaW4gdGhlIG9yZGVyXHJcbiAqIG9mIHByZWNlZGVuY2U6IHRoZSBgbG9hZENvbmZpZ2AgY29uZmlndXJhdGlvbiBvcHRpb25zLCBlbnZpcm9ubWVudCB2YXJpYWJsZXMsXHJcbiAqIGN1c3RvbSBvcHRpb25zLCBhbmQgQ0xJIG9wdGlvbnMuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBfdXBkYXRlR2xvYmFsT3B0aW9uc1xyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gY29uZmlnIC0gVGhlIGNvbmZpZ3VyYXRpb24gb2JqZWN0LCB3aGljaCBpbmNsdWRlcyB0aGUgaW5pdGlhbFxyXG4gKiBzZXR0aW5ncyBhbmQgbWV0YWRhdGEgZm9yIGVhY2ggb3B0aW9uLiBUaGlzIG9iamVjdCBpcyB1c2VkIHRvIGRldGVybWluZVxyXG4gKiB0aGUgc3RydWN0dXJlIGFuZCBkZWZhdWx0IHZhbHVlcyBmb3IgdGhlIG9wdGlvbnMuXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBvcHRpb25zIC0gVGhlIGdsb2JhbCBvcHRpb25zIG9iamVjdCB0aGF0IHdpbGwgYmUgdXBkYXRlZFxyXG4gKiB3aXRoIHZhbHVlcyBmcm9tIG90aGVyIHNvdXJjZXMuXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBjb25maWdPcHQgLSBUaGUgY29uZmlndXJhdGlvbiBvcHRpb25zIG9iamVjdCwgbG9hZGVkIHdpdGhcclxuICogdGhlIGBsb2FkQ29uZmlnYCBvcHRpb24sIHdoaWNoIG1heSBwcm92aWRlIHZhbHVlcyB0byBvdmVycmlkZSBkZWZhdWx0cy5cclxuICogQHBhcmFtIHtPYmplY3R9IGNsaU9wdCAtIFRoZSBDTEkgb3B0aW9ucyBvYmplY3QsIHdoaWNoIG1heSBpbmNsdWRlIHZhbHVlc1xyXG4gKiBwcm92aWRlZCB0aHJvdWdoIGNvbW1hbmQtbGluZSBhcmd1bWVudHMgYW5kIG1heSBvdmVycmlkZSBjb25maWd1cmF0aW9uXHJcbiAqIG9wdGlvbnMuXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBjdXN0b21PcHQgLSBUaGUgY3VzdG9tIG9wdGlvbnMgb2JqZWN0LCB0eXBpY2FsbHkgY29udGFpbmluZ1xyXG4gKiBhZGRpdGlvbmFsIGFuZCB1c2VyLWRlZmluZWQgdmFsdWVzLCB3aGljaCBoYXMgdGhlIGhpZ2hlc3QgcHJlY2VkZW5jZSBhbW9uZ1xyXG4gKiBvcHRpb25zLlxyXG4gKi9cclxuZnVuY3Rpb24gX3VwZGF0ZUdsb2JhbE9wdGlvbnMoY29uZmlnLCBvcHRpb25zLCBjb25maWdPcHQsIGNsaU9wdCwgY3VzdG9tT3B0KSB7XHJcbiAgT2JqZWN0LmtleXMoY29uZmlnKS5mb3JFYWNoKChrZXkpID0+IHtcclxuICAgIC8vIEdldCB0aGUgY29uZmlnIGVudHJ5IG9mIGEgc3BlY2lmaWMgb3B0aW9uXHJcbiAgICBjb25zdCBlbnRyeSA9IGNvbmZpZ1trZXldO1xyXG5cclxuICAgIC8vIEdhdGhlciB2YWx1ZXMgZm9yIHRoZSBvcHRpb25zIGZyb20gZXZlcnkgcG9zc2libGUgc291cmNlLCBpZiBleGlzdHNcclxuICAgIGNvbnN0IGNvbmZpZ1ZhbCA9IGNvbmZpZ09wdCAmJiBjb25maWdPcHRba2V5XTtcclxuICAgIGNvbnN0IGNsaVZhbCA9IGNsaU9wdCAmJiBjbGlPcHRba2V5XTtcclxuICAgIGNvbnN0IGN1c3RvbVZhbCA9IGN1c3RvbU9wdCAmJiBjdXN0b21PcHRba2V5XTtcclxuXHJcbiAgICAvLyBJZiB0aGUgdmFsdWUgbm90IGZvdW5kLCBuZWVkIHRvIGdvIGRlZXBlclxyXG4gICAgaWYgKHR5cGVvZiBlbnRyeS52YWx1ZSA9PT0gJ3VuZGVmaW5lZCcpIHtcclxuICAgICAgX3VwZGF0ZUdsb2JhbE9wdGlvbnMoZW50cnksIG9wdGlvbnNba2V5XSwgY29uZmlnVmFsLCBjbGlWYWwsIGN1c3RvbVZhbCk7XHJcbiAgICB9IGVsc2Uge1xyXG4gICAgICAvLyBJZiBhIHZhbHVlIGZyb20gY3VzdG9tIEpTT04gb3B0aW9ucyBleGlzdHMsIGl0IHRha2VzIHByZWNlZGVuY2VcclxuICAgICAgaWYgKGNvbmZpZ1ZhbCAhPT0gdW5kZWZpbmVkICYmIGNvbmZpZ1ZhbCAhPT0gbnVsbCkge1xyXG4gICAgICAgIG9wdGlvbnNba2V5XSA9IGNvbmZpZ1ZhbDtcclxuICAgICAgfVxyXG5cclxuICAgICAgLy8gSWYgYSB2YWx1ZSBmcm9tIGVudmlyb25tZW50IHZhcmlhYmxlcyBleGlzdHMsIGl0IHRha2VzIHByZWNlZGVuY2VcclxuICAgICAgY29uc3QgZW52VmFsID0gZW52c1tlbnRyeS5lbnZMaW5rXTtcclxuICAgICAgaWYgKGVudHJ5LmVudkxpbmsgaW4gZW52cyAmJiBlbnZWYWwgIT09IHVuZGVmaW5lZCAmJiBlbnZWYWwgIT09IG51bGwpIHtcclxuICAgICAgICBvcHRpb25zW2tleV0gPSBlbnZWYWw7XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIC8vIElmIGEgdmFsdWUgZnJvbSBDTEkgb3B0aW9ucyBleGlzdHMsIGl0IHRha2VzIHByZWNlZGVuY2VcclxuICAgICAgaWYgKGNsaVZhbCAhPT0gdW5kZWZpbmVkICYmIGNsaVZhbCAhPT0gbnVsbCkge1xyXG4gICAgICAgIG9wdGlvbnNba2V5XSA9IGNsaVZhbDtcclxuICAgICAgfVxyXG5cclxuICAgICAgLy8gSWYgYSB2YWx1ZSBmcm9tIHVzZXIgb3B0aW9ucyBleGlzdHMsIGl0IHRha2VzIHByZWNlZGVuY2VcclxuICAgICAgaWYgKGN1c3RvbVZhbCAhPT0gdW5kZWZpbmVkICYmIGN1c3RvbVZhbCAhPT0gbnVsbCkge1xyXG4gICAgICAgIG9wdGlvbnNba2V5XSA9IGN1c3RvbVZhbDtcclxuICAgICAgfVxyXG4gICAgfVxyXG4gIH0pO1xyXG59XHJcblxyXG4vKipcclxuICogQ29udmVydHMgdGhlIHByb3ZpZGVkIG9wdGlvbnMgb2JqZWN0IHRvIGEgSlNPTi1mb3JtYXR0ZWQgc3RyaW5nXHJcbiAqIHdpdGggdGhlIG9wdGlvbiB0byBwcmVzZXJ2ZSBmdW5jdGlvbnMuIEluIG9yZGVyIGZvciBhIGZ1bmN0aW9uXHJcbiAqIHRvIGJlIHByZXNlcnZlZCwgaXQgbmVlZHMgdG8gZm9sbG93IHRoZSBmb3JtYXQgYGZ1bmN0aW9uICguLi4pIHsuLi59YC5cclxuICogU3VjaCBhIGZ1bmN0aW9uIGNhbiBhbHNvIGJlIHN0cmluZ2lmaWVkLlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gX29wdGlvbnNTdHJpbmdpZnlcclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IG9wdGlvbnMgLSBUaGUgb3B0aW9ucyBvYmplY3QgdG8gYmUgY29udmVydGVkIHRvIGEgc3RyaW5nLlxyXG4gKiBAcGFyYW0ge2Jvb2xlYW59IGFsbG93RnVuY3Rpb25zIC0gSWYgc2V0IHRvIHRydWUsIGZ1bmN0aW9ucyBhcmUgcHJlc2VydmVkXHJcbiAqIGluIHRoZSBvdXRwdXQuIE90aGVyd2lzZSBhbiBlcnJvciBpcyB0aHJvd24uXHJcbiAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaW5naWZ5RnVuY3Rpb25zIC0gSWYgc2V0IHRvIHRydWUsIGZ1bmN0aW9ucyBhcmUgc2F2ZWRcclxuICogYXMgc3RyaW5ncy4gVGhlIGBhbGxvd0Z1bmN0aW9uc2AgbXVzdCBiZSBzZXQgdG8gdHJ1ZSBhcyB3ZWxsIGZvciB0aGlzIHRvIHRha2VcclxuICogYW4gZWZmZWN0LlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7c3RyaW5nfSBUaGUgSlNPTi1mb3JtYXR0ZWQgc3RyaW5nIHJlcHJlc2VudGluZyB0aGUgb3B0aW9ucy5cclxuICpcclxuICogQHRocm93cyB7RXJyb3J9IFRocm93cyBhbiBgRXJyb3JgIHdoZW4gZnVuY3Rpb25zIGFyZSBub3QgYWxsb3dlZCBidXQgYXJlXHJcbiAqIGZvdW5kIGluIHByb3ZpZGVkIG9wdGlvbnMgb2JqZWN0LlxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIF9vcHRpb25zU3RyaW5naWZ5KG9wdGlvbnMsIGFsbG93RnVuY3Rpb25zLCBzdHJpbmdpZnlGdW5jdGlvbnMpIHtcclxuICBjb25zdCByZXBsYWNlckNhbGxiYWNrID0gKF8sIHZhbHVlKSA9PiB7XHJcbiAgICAvLyBUcmltIHN0cmluZyB2YWx1ZXNcclxuICAgIGlmICh0eXBlb2YgdmFsdWUgPT09ICdzdHJpbmcnKSB7XHJcbiAgICAgIHZhbHVlID0gdmFsdWUudHJpbSgpO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIElmIHZhbHVlIGlzIGEgZnVuY3Rpb24gb3Igc3RyaW5naWZpZWQgZnVuY3Rpb25cclxuICAgIGlmIChcclxuICAgICAgdHlwZW9mIHZhbHVlID09PSAnZnVuY3Rpb24nIHx8XHJcbiAgICAgICh0eXBlb2YgdmFsdWUgPT09ICdzdHJpbmcnICYmXHJcbiAgICAgICAgdmFsdWUuc3RhcnRzV2l0aCgnZnVuY3Rpb24nKSAmJlxyXG4gICAgICAgIHZhbHVlLmVuZHNXaXRoKCd9JykpXHJcbiAgICApIHtcclxuICAgICAgLy8gSWYgYWxsb3dGdW5jdGlvbnMgaXMgc2V0IHRvIHRydWUsIHByZXNlcnZlIGZ1bmN0aW9uc1xyXG4gICAgICBpZiAoYWxsb3dGdW5jdGlvbnMpIHtcclxuICAgICAgICAvLyBCYXNlZCBvbiB0aGUgYHN0cmluZ2lmeUZ1bmN0aW9uc2Agb3B0aW9ucywgc2V0IGZ1bmN0aW9uIHZhbHVlc1xyXG4gICAgICAgIHJldHVybiBzdHJpbmdpZnlGdW5jdGlvbnNcclxuICAgICAgICAgID8gLy8gQXMgc3RyaW5naWZpZWQgZnVuY3Rpb25zXHJcbiAgICAgICAgICAgIGBcIkVYUF9GVU4keyh2YWx1ZSArICcnKS5yZXBsYWNlQWxsKC9cXHMrL2csICcgJyl9RVhQX0ZVTlwiYFxyXG4gICAgICAgICAgOiAvLyBBcyBmdW5jdGlvbnNcclxuICAgICAgICAgICAgYEVYUF9GVU4keyh2YWx1ZSArICcnKS5yZXBsYWNlQWxsKC9cXHMrL2csICcgJyl9RVhQX0ZVTmA7XHJcbiAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgLy8gVGhyb3cgYW4gZXJyb3Igb3RoZXJ3aXNlXHJcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKCk7XHJcbiAgICAgIH1cclxuICAgIH1cclxuXHJcbiAgICAvLyBJbiBhbGwgb3RoZXIgY2FzZXMsIHNpbXBseSByZXR1cm4gdGhlIHZhbHVlXHJcbiAgICByZXR1cm4gdmFsdWU7XHJcbiAgfTtcclxuXHJcbiAgLy8gU3RyaW5naWZ5IG9wdGlvbnMgYW5kIGlmIHJlcXVpcmVkLCByZXBsYWNlIHNwZWNpYWwgZnVuY3Rpb25zIG1hcmtzXHJcbiAgcmV0dXJuIEpTT04uc3RyaW5naWZ5KG9wdGlvbnMsIHJlcGxhY2VyQ2FsbGJhY2spLnJlcGxhY2VBbGwoXHJcbiAgICBzdHJpbmdpZnlGdW5jdGlvbnMgPyAvXFxcXFwiRVhQX0ZVTnxFWFBfRlVOXFxcXFwiL2cgOiAvXCJFWFBfRlVOfEVYUF9GVU5cIi9nLFxyXG4gICAgJydcclxuICApO1xyXG59XHJcblxyXG4vKipcclxuICogTG9hZHMgYWRkaXRpb25hbCBjb25maWd1cmF0aW9uIGZyb20gYSBzcGVjaWZpZWQgZmlsZSBwcm92aWRlZCB2aWFcclxuICogdGhlIGBsb2FkQ29uZmlnYCBvcHRpb24gaW4gdGhlIGNvbW1hbmQtbGluZSBhcmd1bWVudHMuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBfbG9hZENvbmZpZ0ZpbGVcclxuICpcclxuICogQHBhcmFtIHtBcnJheS48c3RyaW5nPn0gY2xpQXJncyAtIENvbW1hbmQtbGluZSBhcmd1bWVudHMgdG8gc2VhcmNoXHJcbiAqIGZvciB0aGUgYGxvYWRDb25maWdgIG9wdGlvbiBhbmQgdGhlIGNvcnJlc3BvbmRpbmcgZmlsZSBwYXRoLlxyXG4gKiBAcGFyYW0ge09iamVjdH0gY3VzdG9tTG9naWNPcHRpb25zIC0gVGhlIGNvbmZpZ3VyYXRpb24gb2JqZWN0IGNvbnRhaW5pbmdcclxuICogYGN1c3RvbUxvZ2ljYCBvcHRpb25zLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7T2JqZWN0fSBUaGUgYWRkaXRpb25hbCBjb25maWd1cmF0aW9uIGxvYWRlZCBmcm9tIHRoZSBzcGVjaWZpZWRcclxuICogZmlsZSwgb3IgYW4gZW1wdHkgb2JqZWN0IGlmIHRoZSBmaWxlIGlzIG5vdCBmb3VuZCwgaW52YWxpZCwgb3IgYW4gZXJyb3JcclxuICogb2NjdXJzLlxyXG4gKi9cclxuZnVuY3Rpb24gX2xvYWRDb25maWdGaWxlKGNsaUFyZ3MsIGN1c3RvbUxvZ2ljT3B0aW9ucykge1xyXG4gIC8vIENoZWNrIGlmIHRoZSBgbG9hZENvbmZpZ2Agb3B0aW9uIHdhcyB1c2VkXHJcbiAgY29uc3QgY29uZmlnSW5kZXggPSBjbGlBcmdzLmZpbmRJbmRleChcclxuICAgIChhcmcpID0+IGFyZy5yZXBsYWNlKC8tL2csICcnKSA9PT0gJ2xvYWRDb25maWcnXHJcbiAgKTtcclxuXHJcbiAgLy8gR2V0IHRoZSBgbG9hZENvbmZpZ2Agb3B0aW9uIHZhbHVlXHJcbiAgY29uc3QgY29uZmlnRmlsZU5hbWUgPSBjb25maWdJbmRleCA+IC0xICYmIGNsaUFyZ3NbY29uZmlnSW5kZXggKyAxXTtcclxuXHJcbiAgLy8gQ2hlY2sgaWYgdGhlIGBsb2FkQ29uZmlnYCBpcyBwcmVzZW50IGFuZCBoYXMgYSBjb3JyZWN0IHZhbHVlXHJcbiAgaWYgKGNvbmZpZ0ZpbGVOYW1lICYmIGN1c3RvbUxvZ2ljT3B0aW9ucy5hbGxvd0ZpbGVSZXNvdXJjZXMpIHtcclxuICAgIHRyeSB7XHJcbiAgICAgIC8vIExvYWQgYW4gb3B0aW9uYWwgY3VzdG9tIEpTT04gY29uZmlnIGZpbGVcclxuICAgICAgcmV0dXJuIGlzQWxsb3dlZENvbmZpZyhcclxuICAgICAgICByZWFkRmlsZVN5bmMoZ2V0QWJzb2x1dGVQYXRoKGNvbmZpZ0ZpbGVOYW1lKSwgJ3V0ZjgnKSxcclxuICAgICAgICBmYWxzZSxcclxuICAgICAgICBjdXN0b21Mb2dpY09wdGlvbnMuYWxsb3dDb2RlRXhlY3V0aW9uXHJcbiAgICAgICk7XHJcbiAgICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgICBsb2dXaXRoU3RhY2soXHJcbiAgICAgICAgMixcclxuICAgICAgICBlcnJvcixcclxuICAgICAgICBgW2NvbmZpZ10gVW5hYmxlIHRvIGxvYWQgdGhlIGNvbmZpZ3VyYXRpb24gZnJvbSB0aGUgJHtjb25maWdGaWxlTmFtZX0gZmlsZS5gXHJcbiAgICAgICk7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICAvLyBObyBhZGRpdGlvbmFsIG9wdGlvbnMgdG8gcmV0dXJuXHJcbiAgcmV0dXJuIHt9O1xyXG59XHJcblxyXG4vKipcclxuICogUGFyc2VzIGNvbW1hbmQtbGluZSBhcmd1bWVudHMgYW5kIHBhaXJzIGVhY2ggYXJndW1lbnQgd2l0aCBpdHMgY29ycmVzcG9uZGluZ1xyXG4gKiBvcHRpb24gaW4gdGhlIGNvbmZpZ3VyYXRpb24uIFRoZSB2YWx1ZXMgYXJlIHN0cnVjdHVyZWQgaW50byBhIG5lc3RlZCBvcHRpb25zXHJcbiAqIG9iamVjdCwgYmFzZWQgb24gcHJlZGVmaW5lZCBtYXBwaW5ncy5cclxuICpcclxuICogQGZ1bmN0aW9uIF9wYWlyQXJndW1lbnRWYWx1ZVxyXG4gKlxyXG4gKiBAcGFyYW0ge0FycmF5LjxzdHJpbmc+fSBuZXN0ZWRQcm9wcyAtIEFuIGFycmF5IG9mIG5lc3RpbmcgbGV2ZWwgZm9yIGFsbFxyXG4gKiBvcHRpb25zLlxyXG4gKiBAcGFyYW0ge0FycmF5LjxzdHJpbmc+fSBjbGlBcmdzIC0gQW4gYXJyYXkgb2YgY29tbWFuZC1saW5lIGFyZ3VtZW50c1xyXG4gKiBjb250YWluaW5nIG9wdGlvbnMgYW5kIHRoZWlyIGFzc29jaWF0ZWQgdmFsdWVzLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7T2JqZWN0fSBBbiB1cGRhdGVkIG9wdGlvbnMgb2JqZWN0IHdoZXJlIGVhY2ggb3B0aW9uIGZyb21cclxuICogdGhlIGNvbW1hbmQtbGluZSBpcyBwYWlyZWQgd2l0aCBpdHMgdmFsdWUsIHN0cnVjdHVyZWQgaW50byBuZXN0ZWQgb2JqZWN0c1xyXG4gKiBhcyBkZWZpbmVkLlxyXG4gKi9cclxuZnVuY3Rpb24gX3BhaXJBcmd1bWVudFZhbHVlKG5lc3RlZFByb3BzLCBjbGlBcmdzKSB7XHJcbiAgLy8gQW4gZW1wdHkgb2JqZWN0IHRvIGNvbGxlY3QgYW5kIHN0cnVjdHVyaXplIGRhdGEgZnJvbSB0aGUgYXJnc1xyXG4gIGNvbnN0IGNsaU9wdGlvbnMgPSB7fTtcclxuXHJcbiAgLy8gQ3ljbGUgdGhyb3VnaCBhbGwgQ0xJIGFyZ3MgYW5kIGZpbHRlciB0aGVtXHJcbiAgZm9yIChsZXQgaSA9IDA7IGkgPCBjbGlBcmdzLmxlbmd0aDsgaSsrKSB7XHJcbiAgICBjb25zdCBvcHRpb24gPSBjbGlBcmdzW2ldLnJlcGxhY2UoLy0vZywgJycpO1xyXG5cclxuICAgIC8vIEZpbmQgdGhlIHJpZ2h0IHBsYWNlIGZvciBwcm9wZXJ0eSdzIHZhbHVlXHJcbiAgICBjb25zdCBwcm9wZXJ0aWVzQ2hhaW4gPSBuZXN0ZWRQcm9wc1tvcHRpb25dXHJcbiAgICAgID8gbmVzdGVkUHJvcHNbb3B0aW9uXS5zcGxpdCgnLicpXHJcbiAgICAgIDogW107XHJcblxyXG4gICAgLy8gQ3JlYXRlIG9wdGlvbnMgb2JqZWN0IHdpdGggdmFsdWVzIGZyb20gQ0xJIGZvciBsYXRlciBwYXJzaW5nIGFuZCBtZXJnaW5nXHJcbiAgICBwcm9wZXJ0aWVzQ2hhaW4ucmVkdWNlKChvYmosIHByb3AsIGluZGV4KSA9PiB7XHJcbiAgICAgIGlmIChwcm9wZXJ0aWVzQ2hhaW4ubGVuZ3RoIC0gMSA9PT0gaW5kZXgpIHtcclxuICAgICAgICBjb25zdCB2YWx1ZSA9IGNsaUFyZ3NbKytpXTtcclxuICAgICAgICBpZiAoIXZhbHVlKSB7XHJcbiAgICAgICAgICBsb2coXHJcbiAgICAgICAgICAgIDIsXHJcbiAgICAgICAgICAgIGBbY29uZmlnXSBNaXNzaW5nIHZhbHVlIGZvciB0aGUgQ0xJICctLSR7b3B0aW9ufScgYXJndW1lbnQuIFVzaW5nIHRoZSBkZWZhdWx0IHZhbHVlLmBcclxuICAgICAgICAgICk7XHJcbiAgICAgICAgfVxyXG4gICAgICAgIG9ialtwcm9wXSA9IHZhbHVlIHx8IG51bGw7XHJcbiAgICAgIH0gZWxzZSBpZiAob2JqW3Byb3BdID09PSB1bmRlZmluZWQpIHtcclxuICAgICAgICBvYmpbcHJvcF0gPSB7fTtcclxuICAgICAgfVxyXG4gICAgICByZXR1cm4gb2JqW3Byb3BdO1xyXG4gICAgfSwgY2xpT3B0aW9ucyk7XHJcbiAgfVxyXG5cclxuICAvLyBSZXR1cm4gcGFyc2VkIENMSSBvcHRpb25zXHJcbiAgcmV0dXJuIGNsaU9wdGlvbnM7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBSZWN1cnNpdmVseSB0cmF2ZXJzZXMgdGhlIG9wdGlvbnMgb2JqZWN0IHRvIHByaW50IHRoZSB1c2FnZSBpbmZvcm1hdGlvblxyXG4gKiBmb3IgZWFjaCBvcHRpb24gY2F0ZWdvcnkgYW5kIGluZGl2aWR1YWwgb3B0aW9uLlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gX2N5Y2xlQ2F0ZWdvcmllc1xyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gb3B0aW9ucyAtIFRoZSBvcHRpb25zIG9iamVjdCBjb250YWluaW5nIENMSSBvcHRpb25zLiBJdCBtYXlcclxuICogaW5jbHVkZSBuZXN0ZWQgY2F0ZWdvcmllcyBhbmQgaW5kaXZpZHVhbCBvcHRpb25zLlxyXG4gKi9cclxuZnVuY3Rpb24gX2N5Y2xlQ2F0ZWdvcmllcyhvcHRpb25zKSB7XHJcbiAgZm9yIChjb25zdCBbbmFtZSwgb3B0aW9uXSBvZiBPYmplY3QuZW50cmllcyhvcHRpb25zKSkge1xyXG4gICAgLy8gSWYgdGhlIGN1cnJlbnQgZW50cnkgaXMgYSBjYXRlZ29yeSBhbmQgbm90IGEgbGVhZiBvcHRpb24sIHJlY3Vyc2UgaW50byBpdFxyXG4gICAgaWYgKCFPYmplY3QucHJvdG90eXBlLmhhc093blByb3BlcnR5LmNhbGwob3B0aW9uLCAndmFsdWUnKSkge1xyXG4gICAgICBfY3ljbGVDYXRlZ29yaWVzKG9wdGlvbik7XHJcbiAgICB9IGVsc2Uge1xyXG4gICAgICAvLyBQcmVwYXJlIGRlc2NyaXB0aW9uXHJcbiAgICAgIGNvbnN0IGRlc2NOYW1lID0gYCAtLSR7b3B0aW9uLmNsaU5hbWUgfHwgbmFtZX1gO1xyXG5cclxuICAgICAgLy8gR2V0IHRoZSB2YWx1ZVxyXG4gICAgICBsZXQgb3B0aW9uVmFsdWUgPSBvcHRpb24udmFsdWU7XHJcblxyXG4gICAgICAvLyBQcmVwYXJlIHZhbHVlIGZvciBvcHRpb24gdGhhdCBpcyBub3QgbnVsbCBhbmQgaXMgYXJyYXkgb2Ygc3RyaW5nc1xyXG4gICAgICBpZiAob3B0aW9uVmFsdWUgIT09IG51bGwgJiYgb3B0aW9uLnR5cGVzLmluY2x1ZGVzKCdzdHJpbmdbXScpKSB7XHJcbiAgICAgICAgb3B0aW9uVmFsdWUgPVxyXG4gICAgICAgICAgJ1snICsgb3B0aW9uVmFsdWUubWFwKChpdGVtKSA9PiBgJyR7aXRlbX0nYCkuam9pbignLCAnKSArICddJztcclxuICAgICAgfVxyXG5cclxuICAgICAgLy8gUHJlcGFyZSB2YWx1ZSBmb3Igb3B0aW9uIHRoYXQgaXMgbm90IG51bGwgYW5kIGlzIGEgc3RyaW5nXHJcbiAgICAgIGlmIChvcHRpb25WYWx1ZSAhPT0gbnVsbCAmJiBvcHRpb24udHlwZXMuaW5jbHVkZXMoJ3N0cmluZycpKSB7XHJcbiAgICAgICAgb3B0aW9uVmFsdWUgPSBgJyR7b3B0aW9uVmFsdWV9J2A7XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIC8vIERpc3BsYXkgY29ycmVjdGx5IGFsaWduZWQgbWVzc2FnZXNcclxuICAgICAgY29uc29sZS5sb2coXHJcbiAgICAgICAgZGVzY05hbWUuZ3JlZW4sXHJcbiAgICAgICAgYCR7KCc8JyArIG9wdGlvbi50eXBlcy5qb2luKCd8JykgKyAnPicpLnllbGxvd31gLFxyXG4gICAgICAgIGAke1N0cmluZyhvcHRpb25WYWx1ZSkuYm9sZH1gLmJsdWUsXHJcbiAgICAgICAgYC0gJHtvcHRpb24uZGVzY3JpcHRpb259LmBcclxuICAgICAgKTtcclxuICAgIH1cclxuICB9XHJcbn1cclxuXHJcbmV4cG9ydCBkZWZhdWx0IHtcclxuICBnZXRPcHRpb25zLFxyXG4gIHNldEdsb2JhbE9wdGlvbnMsXHJcbiAgdXBkYXRlT3B0aW9ucyxcclxuICBtZXJnZU9wdGlvbnMsXHJcbiAgbWFwVG9OZXdPcHRpb25zLFxyXG4gIHZhbGlkYXRlT3B0aW9uLFxyXG4gIHZhbGlkYXRlT3B0aW9ucyxcclxuICBpc0FsbG93ZWRDb25maWcsXHJcbiAgcHJpbnRMaWNlbnNlLFxyXG4gIHByaW50VXNhZ2UsXHJcbiAgcHJpbnRWZXJzaW9uXHJcbn07XHJcbiIsIi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXHJcblxyXG5IaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXJcclxuXHJcbkNvcHlyaWdodCAoYykgMjAxNi0yMDI1LCBIaWdoc29mdFxyXG5cclxuTGljZW5jZWQgdW5kZXIgdGhlIE1JVCBsaWNlbmNlLlxyXG5cclxuQWRkaXRpb25hbGx5IGEgdmFsaWQgSGlnaGNoYXJ0cyBsaWNlbnNlIGlzIHJlcXVpcmVkIGZvciB1c2UuXHJcblxyXG5TZWUgTElDRU5TRSBmaWxlIGluIHJvb3QgZm9yIGRldGFpbHMuXHJcblxyXG4qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xyXG5cclxuLyoqXHJcbiAqIEBvdmVydmlldyBIVFRQIHV0aWxpdHkgbW9kdWxlIGZvciBmZXRjaGluZyBhbmQgcG9zdGluZyBkYXRhLiBTdXBwb3J0cyBib3RoXHJcbiAqIEhUVFAgYW5kIEhUVFBTIHByb3RvY29scywgcHJvdmlkaW5nIG1ldGhvZHMgdG8gbWFrZSBHRVQgYW5kIFBPU1QgcmVxdWVzdHNcclxuICogd2l0aCBjdXN0b21pemFibGUgb3B0aW9ucy4gSW5jbHVkZXMgcHJvdG9jb2wgZGV0ZXJtaW5hdGlvbiBiYXNlZCBvbiBVUkxcclxuICogYW5kIGF1Z21lbnRzIHJlc3BvbnNlIG9iamVjdHMgd2l0aCBhICd0ZXh0JyBwcm9wZXJ0eSBmb3IgZWFzaWVyIGRhdGEgYWNjZXNzLlxyXG4gKi9cclxuXHJcbmltcG9ydCBodHRwIGZyb20gJ2h0dHAnO1xyXG5pbXBvcnQgaHR0cHMgZnJvbSAnaHR0cHMnO1xyXG5cclxuLyoqXHJcbiAqIEZldGNoZXMgZGF0YSBmcm9tIHRoZSBzcGVjaWZpZWQgVVJMIHVzaW5nIGVpdGhlciBIVFRQIG9yIEhUVFBTIHByb3RvY29sLlxyXG4gKlxyXG4gKiBAYXN5bmNcclxuICogQGZ1bmN0aW9uIGZldGNoXHJcbiAqXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSB1cmwgLSBUaGUgVVJMIHRvIGZldGNoIGRhdGEgZnJvbS5cclxuICogQHBhcmFtIHtPYmplY3R9IFtyZXF1ZXN0T3B0aW9ucz17fV0gLSBPcHRpb25zIGZvciB0aGUgSFRUUC9IVFRQUyByZXF1ZXN0LlxyXG4gKiBUaGUgZGVmYXVsdCB2YWx1ZSBpcyBhbiBlbXB0eSBvYmplY3QuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtQcm9taXNlPE9iamVjdD59IEEgUHJvbWlzZSB0aGF0IHJlc29sdmVzIHRvIHRoZSBIVFRQL0hUVFBTIHJlc3BvbnNlXHJcbiAqIG9iamVjdCB3aXRoIGFkZGVkICd0ZXh0JyBwcm9wZXJ0eSBvciByZWplY3Rpbmcgd2l0aCBhbiBlcnJvci5cclxuICovXHJcbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBmZXRjaCh1cmwsIHJlcXVlc3RPcHRpb25zID0ge30pIHtcclxuICByZXR1cm4gbmV3IFByb21pc2UoKHJlc29sdmUsIHJlamVjdCkgPT4ge1xyXG4gICAgX2dldFByb3RvY29sTW9kdWxlKHVybClcclxuICAgICAgLmdldCh1cmwsIHJlcXVlc3RPcHRpb25zLCAocmVzcG9uc2UpID0+IHtcclxuICAgICAgICBsZXQgcmVzcG9uc2VEYXRhID0gJyc7XHJcblxyXG4gICAgICAgIC8vIEEgY2h1bmsgb2YgZGF0YSBoYXMgYmVlbiByZWNlaXZlZFxyXG4gICAgICAgIHJlc3BvbnNlLm9uKCdkYXRhJywgKGNodW5rKSA9PiB7XHJcbiAgICAgICAgICByZXNwb25zZURhdGEgKz0gY2h1bms7XHJcbiAgICAgICAgfSk7XHJcblxyXG4gICAgICAgIC8vIFRoZSB3aG9sZSByZXNwb25zZSBoYXMgYmVlbiByZWNlaXZlZFxyXG4gICAgICAgIHJlc3BvbnNlLm9uKCdlbmQnLCAoKSA9PiB7XHJcbiAgICAgICAgICBpZiAoIXJlc3BvbnNlRGF0YSkge1xyXG4gICAgICAgICAgICByZWplY3QoJ05vdGhpbmcgd2FzIGZldGNoZWQgZnJvbSB0aGUgVVJMLicpO1xyXG4gICAgICAgICAgfVxyXG4gICAgICAgICAgcmVzcG9uc2UudGV4dCA9IHJlc3BvbnNlRGF0YTtcclxuICAgICAgICAgIHJlc29sdmUocmVzcG9uc2UpO1xyXG4gICAgICAgIH0pO1xyXG4gICAgICB9KVxyXG4gICAgICAub24oJ2Vycm9yJywgKGVycm9yKSA9PiB7XHJcbiAgICAgICAgcmVqZWN0KGVycm9yKTtcclxuICAgICAgfSk7XHJcbiAgfSk7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBTZW5kcyBhIFBPU1QgcmVxdWVzdCB0byB0aGUgc3BlY2lmaWVkIFVSTCB3aXRoIHRoZSBwcm92aWRlZCBKU09OIGJvZHkgdXNpbmdcclxuICogZWl0aGVyIEhUVFAgb3IgSFRUUFMgcHJvdG9jb2wuXHJcbiAqXHJcbiAqIEBhc3luY1xyXG4gKiBAZnVuY3Rpb24gcG9zdFxyXG4gKlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gdXJsIC0gVGhlIFVSTCB0byBzZW5kIHRoZSBQT1NUIHJlcXVlc3QgdG8uXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBbYm9keT17fV0gLSBUaGUgSlNPTiBib2R5IHRvIGluY2x1ZGUgaW4gdGhlIFBPU1QgcmVxdWVzdC5cclxuICogVGhlIGRlZmF1bHQgdmFsdWUgaXMgYW4gZW1wdHkgb2JqZWN0LlxyXG4gKiBAcGFyYW0ge09iamVjdH0gW3JlcXVlc3RPcHRpb25zPXt9XSAtIE9wdGlvbnMgZm9yIHRoZSBIVFRQL0hUVFBTIHJlcXVlc3QuXHJcbiAqIFRoZSBkZWZhdWx0IHZhbHVlIGlzIGFuIGVtcHR5IG9iamVjdC5cclxuICpcclxuICogQHJldHVybnMge1Byb21pc2U8T2JqZWN0Pn0gQSBQcm9taXNlIHRoYXQgcmVzb2x2ZXMgdG8gdGhlIEhUVFAvSFRUUFMgcmVzcG9uc2VcclxuICogb2JqZWN0IHdpdGggYWRkZWQgJ3RleHQnIHByb3BlcnR5IG9yIHJlamVjdGluZyB3aXRoIGFuIGVycm9yLlxyXG4gKi9cclxuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIHBvc3QodXJsLCBib2R5ID0ge30sIHJlcXVlc3RPcHRpb25zID0ge30pIHtcclxuICByZXR1cm4gbmV3IFByb21pc2UoKHJlc29sdmUsIHJlamVjdCkgPT4ge1xyXG4gICAgY29uc3QgZGF0YSA9IEpTT04uc3RyaW5naWZ5KGJvZHkpO1xyXG5cclxuICAgIC8vIFNldCBkZWZhdWx0IGhlYWRlcnMgYW5kIG1lcmdlIHdpdGggcmVxdWVzdE9wdGlvbnNcclxuICAgIGNvbnN0IG9wdGlvbnMgPSBPYmplY3QuYXNzaWduKFxyXG4gICAgICB7XHJcbiAgICAgICAgbWV0aG9kOiAnUE9TVCcsXHJcbiAgICAgICAgaGVhZGVyczoge1xyXG4gICAgICAgICAgJ0NvbnRlbnQtVHlwZSc6ICdhcHBsaWNhdGlvbi9qc29uJyxcclxuICAgICAgICAgICdDb250ZW50LUxlbmd0aCc6IGRhdGEubGVuZ3RoXHJcbiAgICAgICAgfVxyXG4gICAgICB9LFxyXG4gICAgICByZXF1ZXN0T3B0aW9uc1xyXG4gICAgKTtcclxuXHJcbiAgICBjb25zdCByZXF1ZXN0ID0gX2dldFByb3RvY29sTW9kdWxlKHVybClcclxuICAgICAgLnJlcXVlc3QodXJsLCBvcHRpb25zLCAocmVzcG9uc2UpID0+IHtcclxuICAgICAgICBsZXQgcmVzcG9uc2VEYXRhID0gJyc7XHJcblxyXG4gICAgICAgIC8vIEEgY2h1bmsgb2YgZGF0YSBoYXMgYmVlbiByZWNlaXZlZFxyXG4gICAgICAgIHJlc3BvbnNlLm9uKCdkYXRhJywgKGNodW5rKSA9PiB7XHJcbiAgICAgICAgICByZXNwb25zZURhdGEgKz0gY2h1bms7XHJcbiAgICAgICAgfSk7XHJcblxyXG4gICAgICAgIC8vIFRoZSB3aG9sZSByZXNwb25zZSBoYXMgYmVlbiByZWNlaXZlZFxyXG4gICAgICAgIHJlc3BvbnNlLm9uKCdlbmQnLCAoKSA9PiB7XHJcbiAgICAgICAgICB0cnkge1xyXG4gICAgICAgICAgICByZXNwb25zZS50ZXh0ID0gcmVzcG9uc2VEYXRhO1xyXG4gICAgICAgICAgICByZXNvbHZlKHJlc3BvbnNlKTtcclxuICAgICAgICAgIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICAgICAgICAgIHJlamVjdChlcnJvcik7XHJcbiAgICAgICAgICB9XHJcbiAgICAgICAgfSk7XHJcbiAgICAgIH0pXHJcbiAgICAgIC5vbignZXJyb3InLCAoZXJyb3IpID0+IHtcclxuICAgICAgICByZWplY3QoZXJyb3IpO1xyXG4gICAgICB9KTtcclxuXHJcbiAgICAvLyBXcml0ZSB0aGUgcmVxdWVzdCBib2R5IGFuZCBlbmQgdGhlIHJlcXVlc3RcclxuICAgIHJlcXVlc3Qud3JpdGUoZGF0YSk7XHJcbiAgICByZXF1ZXN0LmVuZCgpO1xyXG4gIH0pO1xyXG59XHJcblxyXG4vKipcclxuICogUmV0dXJucyB0aGUgSFRUUCBvciBIVFRQUyBwcm90b2NvbCBtb2R1bGUgYmFzZWQgb24gdGhlIHByb3ZpZGVkIFVSTC5cclxuICpcclxuICogQGZ1bmN0aW9uIF9nZXRQcm90b2NvbE1vZHVsZVxyXG4gKlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gdXJsIC0gVGhlIFVSTCB0byBkZXRlcm1pbmUgdGhlIHByb3RvY29sLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7T2JqZWN0fSBUaGUgSFRUUCBvciBIVFRQUyBwcm90b2NvbCBtb2R1bGUgKGh0dHAgb3IgaHR0cHMpLlxyXG4gKi9cclxuZnVuY3Rpb24gX2dldFByb3RvY29sTW9kdWxlKHVybCkge1xyXG4gIHJldHVybiB1cmwuc3RhcnRzV2l0aCgnaHR0cHMnKSA/IGh0dHBzIDogaHR0cDtcclxufVxyXG5cclxuZXhwb3J0IGRlZmF1bHQge1xyXG4gIGZldGNoLFxyXG4gIHBvc3RcclxufTtcclxuIiwiLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcclxuXHJcbkhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlclxyXG5cclxuQ29weXJpZ2h0IChjKSAyMDE2LTIwMjUsIEhpZ2hzb2Z0XHJcblxyXG5MaWNlbmNlZCB1bmRlciB0aGUgTUlUIGxpY2VuY2UuXHJcblxyXG5BZGRpdGlvbmFsbHkgYSB2YWxpZCBIaWdoY2hhcnRzIGxpY2Vuc2UgaXMgcmVxdWlyZWQgZm9yIHVzZS5cclxuXHJcblNlZSBMSUNFTlNFIGZpbGUgaW4gcm9vdCBmb3IgZGV0YWlscy5cclxuXHJcbioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXHJcblxyXG4vKipcclxuICogQG92ZXJ2aWV3IFRoZSBjYWNoZSBtYW5hZ2VyIGlzIHJlc3BvbnNpYmxlIGZvciBoYW5kbGluZyBhbmQgbWFuYWdpbmdcclxuICogdGhlIEhpZ2hjaGFydHMgbGlicmFyeSBhbG9uZyB3aXRoIGl0cyBkZXBlbmRlbmNpZXMuIEl0IGVuc3VyZXMgdGhhdCB0aGVzZVxyXG4gKiByZXNvdXJjZXMgYXJlIHN0b3JlZCBhbmQgcmV0cmlldmVkIGVmZmljaWVudGx5IHRvIG9wdGltaXplIHBlcmZvcm1hbmNlXHJcbiAqIGFuZCByZWR1Y2UgcmVkdW5kYW50IG5ldHdvcmsgcmVxdWVzdHMuIFRoZSBjYWNoZSBpcyBzdG9yZWQgaW4gdGhlIGAuY2FjaGVgXHJcbiAqIGRpcmVjdG9yeSBieSBkZWZhdWx0LCB3aGljaCBzZXJ2ZXMgYXMgYSBkZWRpY2F0ZWQgZm9sZGVyIGZvciBrZWVwaW5nIGNhY2hlZFxyXG4gKiBmaWxlcy5cclxuICovXHJcblxyXG5pbXBvcnQgeyBleGlzdHNTeW5jLCBta2RpclN5bmMsIHJlYWRGaWxlU3luYywgd3JpdGVGaWxlU3luYyB9IGZyb20gJ2ZzJztcclxuaW1wb3J0IHsgam9pbiB9IGZyb20gJ3BhdGgnO1xyXG5cclxuaW1wb3J0IHsgSHR0cHNQcm94eUFnZW50IH0gZnJvbSAnaHR0cHMtcHJveHktYWdlbnQnO1xyXG5cclxuaW1wb3J0IHsgZ2V0T3B0aW9ucyB9IGZyb20gJy4vY29uZmlnLmpzJztcclxuaW1wb3J0IHsgZmV0Y2ggfSBmcm9tICcuL2ZldGNoLmpzJztcclxuaW1wb3J0IHsgbG9nIH0gZnJvbSAnLi9sb2dnZXIuanMnO1xyXG5pbXBvcnQgeyBfX2Rpcm5hbWUsIGdldEFic29sdXRlUGF0aCB9IGZyb20gJy4vdXRpbHMuanMnO1xyXG5cclxuaW1wb3J0IEV4cG9ydEVycm9yIGZyb20gJy4vZXJyb3JzL0V4cG9ydEVycm9yLmpzJztcclxuXHJcbi8vIFRoZSBpbml0aWFsIGNhY2hlIHRlbXBsYXRlXHJcbmNvbnN0IGNhY2hlID0ge1xyXG4gIGNkblVybDogJ2h0dHBzOi8vY29kZS5oaWdoY2hhcnRzLmNvbScsXHJcbiAgYWN0aXZlTWFuaWZlc3Q6IHt9LFxyXG4gIHNvdXJjZXM6ICcnLFxyXG4gIGhjVmVyc2lvbjogJydcclxufTtcclxuXHJcbi8qKlxyXG4gKiBDaGVja3MgdGhlIGNhY2hlIGZvciBIaWdoY2hhcnRzIGRlcGVuZGVuY2llcywgdXBkYXRlcyB0aGUgY2FjaGUgaWYgbmVlZGVkLFxyXG4gKiBhbmQgbG9hZHMgdGhlIHNvdXJjZXMuXHJcbiAqXHJcbiAqIEBhc3luY1xyXG4gKiBAZnVuY3Rpb24gY2hlY2tBbmRVcGRhdGVDYWNoZVxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gaGlnaGNoYXJ0c09wdGlvbnMgLSBUaGUgY29uZmlndXJhdGlvbiBvYmplY3QgY29udGFpbmluZ1xyXG4gKiBgaGlnaGNoYXJ0c2Agb3B0aW9ucy5cclxuICogQHBhcmFtIHtPYmplY3R9IHNlcnZlclByb3h5T3B0aW9ucy0gVGhlIGNvbmZpZ3VyYXRpb24gb2JqZWN0IGNvbnRhaW5pbmdcclxuICogYHNlcnZlci5wcm94eWAgb3B0aW9ucy5cclxuICovXHJcbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBjaGVja0FuZFVwZGF0ZUNhY2hlKFxyXG4gIGhpZ2hjaGFydHNPcHRpb25zLFxyXG4gIHNlcnZlclByb3h5T3B0aW9uc1xyXG4pIHtcclxuICB0cnkge1xyXG4gICAgbGV0IGZldGNoZWRNb2R1bGVzO1xyXG5cclxuICAgIC8vIEdldCB0aGUgY2FjaGUgcGF0aFxyXG4gICAgY29uc3QgY2FjaGVQYXRoID0gZ2V0Q2FjaGVQYXRoKCk7XHJcblxyXG4gICAgLy8gUHJlcGFyZSBwYXRocyB0byBtYW5pZmVzdCBhbmQgc291cmNlcyBmcm9tIHRoZSBjYWNoZSBmb2xkZXJcclxuICAgIGNvbnN0IG1hbmlmZXN0UGF0aCA9IGpvaW4oY2FjaGVQYXRoLCAnbWFuaWZlc3QuanNvbicpO1xyXG4gICAgY29uc3Qgc291cmNlUGF0aCA9IGpvaW4oY2FjaGVQYXRoLCAnc291cmNlcy5qcycpO1xyXG5cclxuICAgIC8vIENyZWF0ZSB0aGUgY2FjaGUgZGVzdGluYXRpb24gaWYgaXQgZG9lc24ndCBleGlzdCBhbHJlYWR5XHJcbiAgICAhZXhpc3RzU3luYyhjYWNoZVBhdGgpICYmIG1rZGlyU3luYyhjYWNoZVBhdGgsIHsgcmVjdXJzaXZlOiB0cnVlIH0pO1xyXG5cclxuICAgIC8vIEZldGNoIGFsbCB0aGUgc2NyaXB0cyBlaXRoZXIgaWYgdGhlIGBtYW5pZmVzdC5qc29uYCBkb2VzIG5vdCBleGlzdFxyXG4gICAgLy8gb3IgaWYgdGhlIGBmb3JjZUZldGNoYCBvcHRpb24gaXMgZW5hYmxlZFxyXG4gICAgaWYgKCFleGlzdHNTeW5jKG1hbmlmZXN0UGF0aCkgfHwgaGlnaGNoYXJ0c09wdGlvbnMuZm9yY2VGZXRjaCkge1xyXG4gICAgICBsb2coMywgJ1tjYWNoZV0gRmV0Y2hpbmcgYW5kIGNhY2hpbmcgSGlnaGNoYXJ0cyBkZXBlbmRlbmNpZXMuJyk7XHJcbiAgICAgIGZldGNoZWRNb2R1bGVzID0gYXdhaXQgX3VwZGF0ZUNhY2hlKFxyXG4gICAgICAgIGhpZ2hjaGFydHNPcHRpb25zLFxyXG4gICAgICAgIHNlcnZlclByb3h5T3B0aW9ucyxcclxuICAgICAgICBzb3VyY2VQYXRoXHJcbiAgICAgICk7XHJcbiAgICB9IGVsc2Uge1xyXG4gICAgICBsZXQgcmVxdWVzdFVwZGF0ZSA9IGZhbHNlO1xyXG5cclxuICAgICAgLy8gUmVhZCB0aGUgbWFuaWZlc3QgSlNPTlxyXG4gICAgICBjb25zdCBtYW5pZmVzdCA9IEpTT04ucGFyc2UocmVhZEZpbGVTeW5jKG1hbmlmZXN0UGF0aCksICd1dGY4Jyk7XHJcblxyXG4gICAgICAvLyBDaGVjayBpZiB0aGUgbW9kdWxlcyBpcyBhbiBhcnJheSwgaWYgc28sIHdlIHJld3JpdGUgaXQgdG8gYSBtYXAgdG8gbWFrZVxyXG4gICAgICAvLyBpdCBlYXNpZXIgdG8gcmVzb2x2ZSBtb2R1bGVzLlxyXG4gICAgICBpZiAobWFuaWZlc3QubW9kdWxlcyAmJiBBcnJheS5pc0FycmF5KG1hbmlmZXN0Lm1vZHVsZXMpKSB7XHJcbiAgICAgICAgY29uc3QgbW9kdWxlTWFwID0ge307XHJcbiAgICAgICAgbWFuaWZlc3QubW9kdWxlcy5mb3JFYWNoKChtKSA9PiAobW9kdWxlTWFwW21dID0gMSkpO1xyXG4gICAgICAgIG1hbmlmZXN0Lm1vZHVsZXMgPSBtb2R1bGVNYXA7XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIC8vIEdldCB0aGUgYWN0dWFsIG51bWJlciBvZiBzY3JpcHRzIHRvIGJlIGZldGNoZWRcclxuICAgICAgY29uc3QgeyBjb3JlU2NyaXB0cywgbW9kdWxlU2NyaXB0cywgaW5kaWNhdG9yU2NyaXB0cyB9ID1cclxuICAgICAgICBoaWdoY2hhcnRzT3B0aW9ucztcclxuICAgICAgY29uc3QgbnVtYmVyT2ZNb2R1bGVzID1cclxuICAgICAgICBjb3JlU2NyaXB0cy5sZW5ndGggKyBtb2R1bGVTY3JpcHRzLmxlbmd0aCArIGluZGljYXRvclNjcmlwdHMubGVuZ3RoO1xyXG5cclxuICAgICAgLy8gQ29tcGFyZSB0aGUgbG9hZGVkIGhpZ2hjaGFydHMgY29uZmlnIHdpdGggdGhlIGNvbnRlbnRzIGluIGNhY2hlLlxyXG4gICAgICAvLyBJZiB0aGVyZSBhcmUgY2hhbmdlcywgZmV0Y2ggcmVxdWVzdGVkIG1vZHVsZXMgYW5kIHByb2R1Y3RzLFxyXG4gICAgICAvLyBhbmQgYmFrZSB0aGVtIGludG8gYSBnaWFudCBibG9iLiBTYXZlIHRoZSBibG9iLlxyXG4gICAgICBpZiAobWFuaWZlc3QudmVyc2lvbiAhPT0gaGlnaGNoYXJ0c09wdGlvbnMudmVyc2lvbikge1xyXG4gICAgICAgIGxvZyhcclxuICAgICAgICAgIDIsXHJcbiAgICAgICAgICAnW2NhY2hlXSBBIEhpZ2hjaGFydHMgdmVyc2lvbiBtaXNtYXRjaCBpbiB0aGUgY2FjaGUsIG5lZWQgdG8gcmUtZmV0Y2guJ1xyXG4gICAgICAgICk7XHJcbiAgICAgICAgcmVxdWVzdFVwZGF0ZSA9IHRydWU7XHJcbiAgICAgIH0gZWxzZSBpZiAoXHJcbiAgICAgICAgT2JqZWN0LmtleXMobWFuaWZlc3QubW9kdWxlcyB8fCB7fSkubGVuZ3RoICE9PSBudW1iZXJPZk1vZHVsZXNcclxuICAgICAgKSB7XHJcbiAgICAgICAgbG9nKFxyXG4gICAgICAgICAgMixcclxuICAgICAgICAgICdbY2FjaGVdIFRoZSBjYWNoZSBhbmQgdGhlIHJlcXVlc3RlZCBtb2R1bGVzIGRvIG5vdCBtYXRjaCwgbmVlZCB0byByZS1mZXRjaC4nXHJcbiAgICAgICAgKTtcclxuICAgICAgICByZXF1ZXN0VXBkYXRlID0gdHJ1ZTtcclxuICAgICAgfSBlbHNlIHtcclxuICAgICAgICAvLyBDaGVjayBlYWNoIG1vZHVsZSwgaWYgYW55dGhpbmcgaXMgbWlzc2luZyByZWZldGNoIGV2ZXJ5dGhpbmdcclxuICAgICAgICByZXF1ZXN0VXBkYXRlID0gKG1vZHVsZVNjcmlwdHMgfHwgW10pLnNvbWUoKG1vZHVsZU5hbWUpID0+IHtcclxuICAgICAgICAgIGlmICghbWFuaWZlc3QubW9kdWxlc1ttb2R1bGVOYW1lXSkge1xyXG4gICAgICAgICAgICBsb2coXHJcbiAgICAgICAgICAgICAgMixcclxuICAgICAgICAgICAgICBgW2NhY2hlXSBUaGUgJHttb2R1bGVOYW1lfSBpcyBtaXNzaW5nIGluIHRoZSBjYWNoZSwgbmVlZCB0byByZS1mZXRjaC5gXHJcbiAgICAgICAgICAgICk7XHJcbiAgICAgICAgICAgIHJldHVybiB0cnVlO1xyXG4gICAgICAgICAgfVxyXG4gICAgICAgIH0pO1xyXG4gICAgICB9XHJcblxyXG4gICAgICAvLyBVcGRhdGUgY2FjaGUgaWYgbmVlZGVkXHJcbiAgICAgIGlmIChyZXF1ZXN0VXBkYXRlKSB7XHJcbiAgICAgICAgZmV0Y2hlZE1vZHVsZXMgPSBhd2FpdCBfdXBkYXRlQ2FjaGUoXHJcbiAgICAgICAgICBoaWdoY2hhcnRzT3B0aW9ucyxcclxuICAgICAgICAgIHNlcnZlclByb3h5T3B0aW9ucyxcclxuICAgICAgICAgIHNvdXJjZVBhdGhcclxuICAgICAgICApO1xyXG4gICAgICB9IGVsc2Uge1xyXG4gICAgICAgIGxvZygzLCAnW2NhY2hlXSBEZXBlbmRlbmN5IGNhY2hlIGlzIHVwIHRvIGRhdGUsIHByb2NlZWRpbmcuJyk7XHJcblxyXG4gICAgICAgIC8vIExvYWQgdGhlIHNvdXJjZXNcclxuICAgICAgICBjYWNoZS5zb3VyY2VzID0gcmVhZEZpbGVTeW5jKHNvdXJjZVBhdGgsICd1dGY4Jyk7XHJcblxyXG4gICAgICAgIC8vIEdldCBjdXJyZW50IG1vZHVsZXMgbWFwXHJcbiAgICAgICAgZmV0Y2hlZE1vZHVsZXMgPSBtYW5pZmVzdC5tb2R1bGVzO1xyXG5cclxuICAgICAgICAvLyBFeHRyYWN0IGFuZCBzYXZlIHZlcnNpb24gb2YgY3VycmVudGx5IHVzZWQgSGlnaGNoYXJ0c1xyXG4gICAgICAgIGNhY2hlLmhjVmVyc2lvbiA9IGV4dHJhY3RWZXJzaW9uKGNhY2hlLnNvdXJjZXMpO1xyXG4gICAgICB9XHJcbiAgICB9XHJcblxyXG4gICAgLy8gRmluYWxseSwgc2F2ZSB0aGUgbmV3IG1hbmlmZXN0LCB3aGljaCBpcyBiYXNpY2FsbHkgb3VyIGN1cnJlbnQgY29uZmlnXHJcbiAgICAvLyBpbiBhIHNsaWdodGx5IGRpZmZlcmVudCBmb3JtYXRcclxuICAgIGF3YWl0IF9zYXZlQ29uZmlnVG9NYW5pZmVzdChoaWdoY2hhcnRzT3B0aW9ucywgZmV0Y2hlZE1vZHVsZXMpO1xyXG4gIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoXHJcbiAgICAgICdbY2FjaGVdIENvdWxkIG5vdCBjb25maWd1cmUgY2FjaGUgYW5kIGNyZWF0ZSBvciB1cGRhdGUgdGhlIGNvbmZpZyBtYW5pZmVzdC4nLFxyXG4gICAgICA1MDBcclxuICAgICkuc2V0RXJyb3IoZXJyb3IpO1xyXG4gIH1cclxufVxyXG5cclxuLyoqXHJcbiAqIEdldHMgdGhlIHZlcnNpb24gb2YgSGlnaGNoYXJ0cyBmcm9tIHRoZSBjYWNoZS5cclxuICpcclxuICogQGZ1bmN0aW9uIGdldEhpZ2hjaGFydHNWZXJzaW9uXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtzdHJpbmd9IFRoZSBjYWNoZWQgSGlnaGNoYXJ0cyB2ZXJzaW9uLlxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIGdldEhpZ2hjaGFydHNWZXJzaW9uKCkge1xyXG4gIHJldHVybiBjYWNoZS5oY1ZlcnNpb247XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBVcGRhdGVzIHRoZSBIaWdoY2hhcnRzIHZlcnNpb24gaW4gdGhlIGFwcGxpZWQgY29uZmlndXJhdGlvbiBhbmQgY2hlY2tzXHJcbiAqIHRoZSBjYWNoZSBmb3IgdGhlIG5ldyB2ZXJzaW9uLlxyXG4gKlxyXG4gKiBAYXN5bmNcclxuICogQGZ1bmN0aW9uIHVwZGF0ZUhpZ2hjaGFydHNWZXJzaW9uXHJcbiAqXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSBuZXdWZXJzaW9uIC0gVGhlIG5ldyBIaWdoY2hhcnRzIHZlcnNpb24gdG8gYmUgYXBwbGllZC5cclxuICovXHJcbmV4cG9ydCBhc3luYyBmdW5jdGlvbiB1cGRhdGVIaWdoY2hhcnRzVmVyc2lvbihuZXdWZXJzaW9uKSB7XHJcbiAgLy8gR2V0IHRoZSByZWZlcmVuY2UgdG8gdGhlIGdsb2JhbCBvcHRpb25zIHRvIHVwZGF0ZSB0byB0aGUgbmV3IHZlcnNpb25cclxuICBjb25zdCBvcHRpb25zID0gZ2V0T3B0aW9ucygpO1xyXG5cclxuICAvLyBTZXQgdG8gdGhlIG5ldyB2ZXJzaW9uXHJcbiAgb3B0aW9ucy5oaWdoY2hhcnRzLnZlcnNpb24gPSBuZXdWZXJzaW9uO1xyXG5cclxuICAvLyBDaGVjayBpZiBjYWNoZSBuZWVkcyB0byBiZSB1cGRhdGVkXHJcbiAgYXdhaXQgY2hlY2tBbmRVcGRhdGVDYWNoZShvcHRpb25zLmhpZ2hjaGFydHMsIG9wdGlvbnMuc2VydmVyLnByb3h5KTtcclxufVxyXG5cclxuLyoqXHJcbiAqIEV4dHJhY3RzIEhpZ2hjaGFydHMgdmVyc2lvbiBmcm9tIHRoZSBjYWNoZSdzIHNvdXJjZXMgc3RyaW5nLlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gZXh0cmFjdFZlcnNpb25cclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IGNhY2hlU291cmNlcyAtIFRoZSBjYWNoZSBzb3VyY2VzIG9iamVjdC5cclxuICpcclxuICogQHJldHVybnMge3N0cmluZ30gVGhlIGV4dHJhY3RlZCBIaWdoY2hhcnRzIHZlcnNpb24uXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gZXh0cmFjdFZlcnNpb24oY2FjaGVTb3VyY2VzKSB7XHJcbiAgcmV0dXJuIGNhY2hlU291cmNlc1xyXG4gICAgLnN1YnN0cmluZygwLCBjYWNoZVNvdXJjZXMuaW5kZXhPZignKi8nKSlcclxuICAgIC5yZXBsYWNlKCcvKicsICcnKVxyXG4gICAgLnJlcGxhY2UoJyovJywgJycpXHJcbiAgICAucmVwbGFjZSgvXFxuL2csICcnKVxyXG4gICAgLnRyaW0oKTtcclxufVxyXG5cclxuLyoqXHJcbiAqIEV4dHJhY3RzIHRoZSBIaWdoY2hhcnRzIG1vZHVsZSBuYW1lIGJhc2VkIG9uIHRoZSBzY3JpcHRQYXRoLlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gZXh0cmFjdE1vZHVsZU5hbWVcclxuICpcclxuICogQHBhcmFtIHtzdHJpbmd9IHNjcmlwdFBhdGggLSBUaGUgcGF0aCBvZiB0aGUgc2NyaXB0IGZyb20gd2hpY2ggdGhlIG1vZHVsZVxyXG4gKiBuYW1lIHdpbGwgYmUgZXh0cmFjdGVkLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7c3RyaW5nfSBUaGUgZXh0cmFjdGVkIG1vZHVsZSBuYW1lLlxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIGV4dHJhY3RNb2R1bGVOYW1lKHNjcmlwdFBhdGgpIHtcclxuICByZXR1cm4gc2NyaXB0UGF0aC5yZXBsYWNlKFxyXG4gICAgLyguKilcXC98KC4qKW1vZHVsZXNcXC98c3RvY2tcXC8oLiopaW5kaWNhdG9yc1xcL3xtYXBzXFwvKC4qKW1vZHVsZXNcXC8vZ2ksXHJcbiAgICAnJ1xyXG4gICk7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBSZXRyaWV2ZXMgdGhlIGN1cnJlbnQgY2FjaGUgb2JqZWN0LlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gZ2V0Q2FjaGVcclxuICpcclxuICogQHJldHVybnMge09iamVjdH0gVGhlIGNhY2hlIG9iamVjdCBjb250YWluaW5nIHZhcmlvdXMgY2FjaGVkIGRhdGEuXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gZ2V0Q2FjaGUoKSB7XHJcbiAgcmV0dXJuIGNhY2hlO1xyXG59XHJcblxyXG4vKipcclxuICogR2V0cyB0aGUgY2FjaGUgcGF0aCBmb3IgSGlnaGNoYXJ0cy5cclxuICpcclxuICogQGZ1bmN0aW9uIGdldENhY2hlUGF0aFxyXG4gKlxyXG4gKiBAcmV0dXJucyB7c3RyaW5nfSBUaGUgYWJzb2x1dGUgcGF0aCB0byB0aGUgY2FjaGUgZGlyZWN0b3J5IGZvciBIaWdoY2hhcnRzLlxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIGdldENhY2hlUGF0aCgpIHtcclxuICByZXR1cm4gZ2V0QWJzb2x1dGVQYXRoKGdldE9wdGlvbnMoKS5oaWdoY2hhcnRzLmNhY2hlUGF0aCwgJ3V0ZjgnKTsgLy8gIzU2MlxyXG59XHJcblxyXG4vKipcclxuICogRmV0Y2hlcyBhIHNpbmdsZSBzY3JpcHQgYW5kIHVwZGF0ZXMgdGhlIGBmZXRjaGVkTW9kdWxlc2AgYWNjb3JkaW5nbHkuXHJcbiAqXHJcbiAqIEBhc3luY1xyXG4gKiBAZnVuY3Rpb24gX2ZldGNoQW5kUHJvY2Vzc1NjcmlwdFxyXG4gKlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gc2NyaXB0IC0gQSBwYXRoIHRvIHNjcmlwdCB0byBnZXQuXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSByZXF1ZXN0T3B0aW9ucyAtIEFkZGl0aW9uYWwgb3B0aW9ucyBmb3IgdGhlIHByb3h5IGFnZW50XHJcbiAqIHRvIHVzZSBmb3IgYSByZXF1ZXN0LlxyXG4gKiBAcGFyYW0ge09iamVjdH0gZmV0Y2hlZE1vZHVsZXMgLSBBbiBvYmplY3Qgd2hpY2ggdHJhY2tzIHdoaWNoIEhpZ2hjaGFydHNcclxuICogbW9kdWxlcyBoYXZlIGJlZW4gZmV0Y2hlZC5cclxuICogQHBhcmFtIHtib29sZWFufSBbc2hvdWxkVGhyb3dFcnJvcj1mYWxzZV0gLSBBIGZsYWcgdG8gaW5kaWNhdGUgaWYgdGhlIGVycm9yXHJcbiAqIHNob3VsZCBiZSB0aHJvd24uIFRoaXMgc2hvdWxkIGJlIHVzZWQgb25seSBmb3IgdGhlIGNvcmUgc2NyaXB0cy4gVGhlIGRlZmF1bHRcclxuICogdmFsdWUgaXMgYGZhbHNlYC5cclxuICpcclxuICogQHJldHVybnMge1Byb21pc2U8c3RyaW5nPn0gQSBQcm9taXNlIHRoYXQgcmVzb2x2ZXMgdG8gdGhlIHRleHQgcmVwcmVzZW50YXRpb25cclxuICogb2YgdGhlIGZldGNoZWQgc2NyaXB0LlxyXG4gKlxyXG4gKiBAdGhyb3dzIHtFeHBvcnRFcnJvcn0gVGhyb3dzIGFuIGBFeHBvcnRFcnJvcmAgaWYgdGhlcmUgaXMgYSBwcm9ibGVtXHJcbiAqIHdpdGggZmV0Y2hpbmcgdGhlIHNjcmlwdC5cclxuICovXHJcbmFzeW5jIGZ1bmN0aW9uIF9mZXRjaEFuZFByb2Nlc3NTY3JpcHQoXHJcbiAgc2NyaXB0LFxyXG4gIHJlcXVlc3RPcHRpb25zLFxyXG4gIGZldGNoZWRNb2R1bGVzLFxyXG4gIHNob3VsZFRocm93RXJyb3IgPSBmYWxzZVxyXG4pIHtcclxuICAvLyBHZXQgcmlkIG9mIHRoZSAuanMgZnJvbSB0aGUgY3VzdG9tIHN0cmluZ3NcclxuICBpZiAoc2NyaXB0LmVuZHNXaXRoKCcuanMnKSkge1xyXG4gICAgc2NyaXB0ID0gc2NyaXB0LnN1YnN0cmluZygwLCBzY3JpcHQubGVuZ3RoIC0gMyk7XHJcbiAgfVxyXG4gIGxvZyg0LCBgW2NhY2hlXSBGZXRjaGluZyBzY3JpcHQgLSAke3NjcmlwdH0uanNgKTtcclxuXHJcbiAgLy8gRmV0Y2ggdGhlIHNjcmlwdFxyXG4gIGNvbnN0IHJlc3BvbnNlID0gYXdhaXQgZmV0Y2goYCR7c2NyaXB0fS5qc2AsIHJlcXVlc3RPcHRpb25zKTtcclxuXHJcbiAgLy8gSWYgT0ssIHJldHVybiBpdHMgdGV4dCByZXByZXNlbnRhdGlvblxyXG4gIGlmIChyZXNwb25zZS5zdGF0dXNDb2RlID09PSAyMDAgJiYgdHlwZW9mIHJlc3BvbnNlLnRleHQgPT0gJ3N0cmluZycpIHtcclxuICAgIGlmIChmZXRjaGVkTW9kdWxlcykge1xyXG4gICAgICBjb25zdCBtb2R1bGVOYW1lID0gZXh0cmFjdE1vZHVsZU5hbWUoc2NyaXB0KTtcclxuICAgICAgZmV0Y2hlZE1vZHVsZXNbbW9kdWxlTmFtZV0gPSAxO1xyXG4gICAgfVxyXG4gICAgcmV0dXJuIHJlc3BvbnNlLnRleHQ7XHJcbiAgfVxyXG5cclxuICAvLyBCYXNlZCBvbiB0aGUgYHNob3VsZFRocm93RXJyb3JgIGZsYWcsIGRlY2lkZSBob3cgdG8gc2VydmUgZXJyb3IgbWVzc2FnZVxyXG4gIGlmIChzaG91bGRUaHJvd0Vycm9yKSB7XHJcbiAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoXHJcbiAgICAgIGBbY2FjaGVdIENvdWxkIG5vdCBmZXRjaCB0aGUgJHtzY3JpcHR9LmpzLiBUaGUgc2NyaXB0IG1pZ2h0IG5vdCBleGlzdCBpbiB0aGUgcmVxdWVzdGVkIHZlcnNpb24gKHN0YXR1cyBjb2RlOiAke3Jlc3BvbnNlLnN0YXR1c0NvZGV9KS5gLFxyXG4gICAgICA0MDRcclxuICAgICkuc2V0RXJyb3IocmVzcG9uc2UpO1xyXG4gIH0gZWxzZSB7XHJcbiAgICBsb2coXHJcbiAgICAgIDIsXHJcbiAgICAgIGBbY2FjaGVdIENvdWxkIG5vdCBmZXRjaCB0aGUgJHtzY3JpcHR9LmpzLiBUaGUgc2NyaXB0IG1pZ2h0IG5vdCBleGlzdCBpbiB0aGUgcmVxdWVzdGVkIHZlcnNpb24uYFxyXG4gICAgKTtcclxuICB9XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBTYXZlcyB0aGUgcHJvdmlkZWQgY29uZmlndXJhdGlvbiBhbmQgZmV0Y2hlZCBtb2R1bGVzIHRvIHRoZSBjYWNoZSBtYW5pZmVzdFxyXG4gKiBmaWxlLlxyXG4gKlxyXG4gKiBAYXN5bmNcclxuICogQGZ1bmN0aW9uIF9zYXZlQ29uZmlnVG9NYW5pZmVzdFxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gaGlnaGNoYXJ0c09wdGlvbnMgLSBUaGUgY29uZmlndXJhdGlvbiBvYmplY3QgY29udGFpbmluZ1xyXG4gKiBgaGlnaGNoYXJ0c2Agb3B0aW9ucy5cclxuICogQHBhcmFtIHtPYmplY3R9IFtmZXRjaGVkTW9kdWxlcz17fV0gLSBBbiBvYmplY3Qgd2hpY2ggdHJhY2tzIHdoaWNoIEhpZ2hjaGFydHNcclxuICogbW9kdWxlcyBoYXZlIGJlZW4gZmV0Y2hlZC4gVGhlIGRlZmF1bHQgdmFsdWUgaXMgYW4gZW1wdHkgb2JqZWN0LlxyXG4gKlxyXG4gKiBAdGhyb3dzIHtFeHBvcnRFcnJvcn0gVGhyb3dzIGFuIGBFeHBvcnRFcnJvcmAgaWYgYW4gZXJyb3Igb2NjdXJzIHdoaWxlXHJcbiAqIHdyaXRpbmcgdGhlIGNhY2hlIG1hbmlmZXN0LlxyXG4gKi9cclxuYXN5bmMgZnVuY3Rpb24gX3NhdmVDb25maWdUb01hbmlmZXN0KGhpZ2hjaGFydHNPcHRpb25zLCBmZXRjaGVkTW9kdWxlcyA9IHt9KSB7XHJcbiAgY29uc3QgbmV3TWFuaWZlc3QgPSB7XHJcbiAgICB2ZXJzaW9uOiBoaWdoY2hhcnRzT3B0aW9ucy52ZXJzaW9uLFxyXG4gICAgbW9kdWxlczogZmV0Y2hlZE1vZHVsZXNcclxuICB9O1xyXG5cclxuICAvLyBVcGRhdGUgY2FjaGUgb2JqZWN0IHdpdGggdGhlIGN1cnJlbnQgbW9kdWxlc1xyXG4gIGNhY2hlLmFjdGl2ZU1hbmlmZXN0ID0gbmV3TWFuaWZlc3Q7XHJcblxyXG4gIGxvZygzLCAnW2NhY2hlXSBXcml0aW5nIGEgbmV3IG1hbmlmZXN0LicpO1xyXG4gIHRyeSB7XHJcbiAgICB3cml0ZUZpbGVTeW5jKFxyXG4gICAgICBqb2luKGdldENhY2hlUGF0aCgpLCAnbWFuaWZlc3QuanNvbicpLFxyXG4gICAgICBKU09OLnN0cmluZ2lmeShuZXdNYW5pZmVzdCksXHJcbiAgICAgICd1dGY4J1xyXG4gICAgKTtcclxuICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgdGhyb3cgbmV3IEV4cG9ydEVycm9yKFxyXG4gICAgICAnW2NhY2hlXSBFcnJvciB3cml0aW5nIHRoZSBjYWNoZSBtYW5pZmVzdC4nLFxyXG4gICAgICA1MDBcclxuICAgICkuc2V0RXJyb3IoZXJyb3IpO1xyXG4gIH1cclxufVxyXG5cclxuLyoqXHJcbiAqIEZldGNoZXMgSGlnaGNoYXJ0cyBgc2NyaXB0c2AgYW5kIGBjdXN0b21TY3JpcHRzYCBmcm9tIHRoZSBnaXZlbiBDRE5zLlxyXG4gKlxyXG4gKiBAYXN5bmNcclxuICogQGZ1bmN0aW9uIF9mZXRjaFNjcmlwdHNcclxuICpcclxuICogQHBhcmFtIHtBcnJheS48c3RyaW5nPn0gY29yZVNjcmlwdHMgLSBIaWdoY2hhcnRzIGNvcmUgc2NyaXB0cyB0byBmZXRjaC5cclxuICogQHBhcmFtIHtBcnJheS48c3RyaW5nPn0gbW9kdWxlU2NyaXB0cyAtIEhpZ2hjaGFydHMgbW9kdWxlcyB0byBmZXRjaC5cclxuICogQHBhcmFtIHtBcnJheS48c3RyaW5nPn0gY3VzdG9tU2NyaXB0cyAtIEN1c3RvbSBzY3JpcHQgcGF0aHMgdG8gZmV0Y2ggKGZ1bGxcclxuICogVVJMcykuXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBzZXJ2ZXJQcm94eU9wdGlvbnMgLSBUaGUgY29uZmlndXJhdGlvbiBvYmplY3QgY29udGFpbmluZ1xyXG4gKiBgc2VydmVyLnByb3h5YCBvcHRpb25zLlxyXG4gKiBAcGFyYW0ge09iamVjdH0gZmV0Y2hlZE1vZHVsZXMgLSBBbiBvYmplY3Qgd2hpY2ggdHJhY2tzIHdoaWNoIEhpZ2hjaGFydHNcclxuICogbW9kdWxlcyBoYXZlIGJlZW4gZmV0Y2hlZC5cclxuICpcclxuICogQHJldHVybnMge1Byb21pc2U8c3RyaW5nPn0gQSBQcm9taXNlIHRoYXQgcmVzb2x2ZXMgdG8gdGhlIGZldGNoZWQgc2NyaXB0c1xyXG4gKiBjb250ZW50IGpvaW5lZC5cclxuICpcclxuICogQHRocm93cyB7RXhwb3J0RXJyb3J9IFRocm93cyBhbiBgRXhwb3J0RXJyb3JgIGlmIGFuIGVycm9yIG9jY3VycyB3aGlsZVxyXG4gKiBzZXR0aW5nIGFuIEhUVFAgQWdlbnQgZm9yIHByb3h5LlxyXG4gKi9cclxuYXN5bmMgZnVuY3Rpb24gX2ZldGNoU2NyaXB0cyhcclxuICBjb3JlU2NyaXB0cyxcclxuICBtb2R1bGVTY3JpcHRzLFxyXG4gIGN1c3RvbVNjcmlwdHMsXHJcbiAgc2VydmVyUHJveHlPcHRpb25zLFxyXG4gIGZldGNoZWRNb2R1bGVzXHJcbikge1xyXG4gIC8vIENvbmZpZ3VyZSBwcm94eSBpZiBleGlzdHNcclxuICBsZXQgcHJveHlBZ2VudDtcclxuICBjb25zdCBwcm94eUhvc3QgPSBzZXJ2ZXJQcm94eU9wdGlvbnMuaG9zdDtcclxuICBjb25zdCBwcm94eVBvcnQgPSBzZXJ2ZXJQcm94eU9wdGlvbnMucG9ydDtcclxuXHJcbiAgLy8gVHJ5IHRvIGNyZWF0ZSBhIFByb3h5IEFnZW50XHJcbiAgaWYgKHByb3h5SG9zdCAmJiBwcm94eVBvcnQpIHtcclxuICAgIHRyeSB7XHJcbiAgICAgIHByb3h5QWdlbnQgPSBuZXcgSHR0cHNQcm94eUFnZW50KHtcclxuICAgICAgICBob3N0OiBwcm94eUhvc3QsXHJcbiAgICAgICAgcG9ydDogcHJveHlQb3J0XHJcbiAgICAgIH0pO1xyXG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICAgdGhyb3cgbmV3IEV4cG9ydEVycm9yKFxyXG4gICAgICAgICdbY2FjaGVdIENvdWxkIG5vdCBjcmVhdGUgYSBQcm94eSBBZ2VudC4nLFxyXG4gICAgICAgIDUwMFxyXG4gICAgICApLnNldEVycm9yKGVycm9yKTtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIC8vIElmIGV4aXN0cywgYWRkIHByb3h5IGFnZW50IHRvIHJlcXVlc3Qgb3B0aW9uc1xyXG4gIGNvbnN0IHJlcXVlc3RPcHRpb25zID0gcHJveHlBZ2VudFxyXG4gICAgPyB7XHJcbiAgICAgICAgYWdlbnQ6IHByb3h5QWdlbnQsXHJcbiAgICAgICAgdGltZW91dDogc2VydmVyUHJveHlPcHRpb25zLnRpbWVvdXRcclxuICAgICAgfVxyXG4gICAgOiB7fTtcclxuXHJcbiAgY29uc3QgYWxsRmV0Y2hQcm9taXNlcyA9IFtcclxuICAgIC4uLmNvcmVTY3JpcHRzLm1hcCgoc2NyaXB0KSA9PlxyXG4gICAgICBfZmV0Y2hBbmRQcm9jZXNzU2NyaXB0KGAke3NjcmlwdH1gLCByZXF1ZXN0T3B0aW9ucywgZmV0Y2hlZE1vZHVsZXMsIHRydWUpXHJcbiAgICApLFxyXG4gICAgLi4ubW9kdWxlU2NyaXB0cy5tYXAoKHNjcmlwdCkgPT5cclxuICAgICAgX2ZldGNoQW5kUHJvY2Vzc1NjcmlwdChgJHtzY3JpcHR9YCwgcmVxdWVzdE9wdGlvbnMsIGZldGNoZWRNb2R1bGVzKVxyXG4gICAgKSxcclxuICAgIC4uLmN1c3RvbVNjcmlwdHMubWFwKChzY3JpcHQpID0+XHJcbiAgICAgIF9mZXRjaEFuZFByb2Nlc3NTY3JpcHQoYCR7c2NyaXB0fWAsIHJlcXVlc3RPcHRpb25zKVxyXG4gICAgKVxyXG4gIF07XHJcblxyXG4gIGNvbnN0IGZldGNoZWRTY3JpcHRzID0gYXdhaXQgUHJvbWlzZS5hbGwoYWxsRmV0Y2hQcm9taXNlcyk7XHJcbiAgcmV0dXJuIGZldGNoZWRTY3JpcHRzLmpvaW4oJztcXG4nKTtcclxufVxyXG5cclxuLyoqXHJcbiAqIFVwZGF0ZXMgdGhlIGxvY2FsIGNhY2hlIHdpdGggSGlnaGNoYXJ0cyBzY3JpcHRzIGFuZCB0aGVpciB2ZXJzaW9ucy5cclxuICpcclxuICogQGFzeW5jXHJcbiAqIEBmdW5jdGlvbiBfdXBkYXRlQ2FjaGVcclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IGhpZ2hjaGFydHNPcHRpb25zIC0gVGhlIGNvbmZpZ3VyYXRpb24gb2JqZWN0IGNvbnRhaW5pbmdcclxuICogYGhpZ2hjaGFydHNgIG9wdGlvbnMuXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBzZXJ2ZXJQcm94eU9wdGlvbnMgLSBUaGUgY29uZmlndXJhdGlvbiBvYmplY3QgY29udGFpbmluZ1xyXG4gKiBgc2VydmVyLnByb3h5YCBvcHRpb25zLlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gc291cmNlUGF0aCAtIFRoZSBwYXRoIHRvIHRoZSBzb3VyY2UgZmlsZSBpbiB0aGUgY2FjaGUuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtQcm9taXNlPE9iamVjdD59IEEgUHJvbWlzZSB0aGF0IHJlc29sdmVzIHRvIGFuIG9iamVjdCByZXByZXNlbnRpbmdcclxuICogdGhlIGZldGNoZWQgbW9kdWxlcy5cclxuICpcclxuICogQHRocm93cyB7RXhwb3J0RXJyb3J9IFRocm93cyBhbiBgRXhwb3J0RXJyb3JgIGlmIHRoZXJlIGlzIGFuIGlzc3VlIHVwZGF0aW5nXHJcbiAqIHRoZSBsb2NhbCBIaWdoY2hhcnRzIGNhY2hlLlxyXG4gKi9cclxuYXN5bmMgZnVuY3Rpb24gX3VwZGF0ZUNhY2hlKGhpZ2hjaGFydHNPcHRpb25zLCBzZXJ2ZXJQcm94eU9wdGlvbnMsIHNvdXJjZVBhdGgpIHtcclxuICAvLyBHZXQgSGlnaGNoYXJ0cyB2ZXJzaW9uIGZvciBzY3JpcHRzXHJcbiAgY29uc3QgaGNWZXJzaW9uID1cclxuICAgIGhpZ2hjaGFydHNPcHRpb25zLnZlcnNpb24gPT09ICdsYXRlc3QnXHJcbiAgICAgID8gbnVsbFxyXG4gICAgICA6IGAke2hpZ2hjaGFydHNPcHRpb25zLnZlcnNpb259YDtcclxuXHJcbiAgLy8gR2V0IHRoZSBDRE4gdXJsIGZvciBzY3JpcHRzXHJcbiAgY29uc3QgY2RuVXJsID0gaGlnaGNoYXJ0c09wdGlvbnMuY2RuVXJsIHx8IGNhY2hlLmNkblVybDtcclxuXHJcbiAgdHJ5IHtcclxuICAgIGNvbnN0IGZldGNoZWRNb2R1bGVzID0ge307XHJcblxyXG4gICAgbG9nKFxyXG4gICAgICAzLFxyXG4gICAgICBgW2NhY2hlXSBVcGRhdGluZyBjYWNoZSB2ZXJzaW9uIHRvIEhpZ2hjaGFydHM6ICR7aGNWZXJzaW9uIHx8ICdsYXRlc3QnfS5gXHJcbiAgICApO1xyXG5cclxuICAgIGNhY2hlLnNvdXJjZXMgPSBhd2FpdCBfZmV0Y2hTY3JpcHRzKFxyXG4gICAgICBbXHJcbiAgICAgICAgLi4uaGlnaGNoYXJ0c09wdGlvbnMuY29yZVNjcmlwdHMubWFwKChjKSA9PlxyXG4gICAgICAgICAgaGNWZXJzaW9uID8gYCR7Y2RuVXJsfS8ke2hjVmVyc2lvbn0vJHtjfWAgOiBgJHtjZG5Vcmx9LyR7Y31gXHJcbiAgICAgICAgKVxyXG4gICAgICBdLFxyXG4gICAgICBbXHJcbiAgICAgICAgLi4uaGlnaGNoYXJ0c09wdGlvbnMubW9kdWxlU2NyaXB0cy5tYXAoKG0pID0+XHJcbiAgICAgICAgICBtID09PSAnbWFwJ1xyXG4gICAgICAgICAgICA/IGhjVmVyc2lvblxyXG4gICAgICAgICAgICAgID8gYCR7Y2RuVXJsfS9tYXBzLyR7aGNWZXJzaW9ufS9tb2R1bGVzLyR7bX1gXHJcbiAgICAgICAgICAgICAgOiBgJHtjZG5Vcmx9L21hcHMvbW9kdWxlcy8ke219YFxyXG4gICAgICAgICAgICA6IGhjVmVyc2lvblxyXG4gICAgICAgICAgICAgID8gYCR7Y2RuVXJsfS8ke2hjVmVyc2lvbn0vbW9kdWxlcy8ke219YFxyXG4gICAgICAgICAgICAgIDogYCR7Y2RuVXJsfS9tb2R1bGVzLyR7bX1gXHJcbiAgICAgICAgKSxcclxuICAgICAgICAuLi5oaWdoY2hhcnRzT3B0aW9ucy5pbmRpY2F0b3JTY3JpcHRzLm1hcCgoaSkgPT5cclxuICAgICAgICAgIGhjVmVyc2lvblxyXG4gICAgICAgICAgICA/IGAke2NkblVybH0vc3RvY2svJHtoY1ZlcnNpb259L2luZGljYXRvcnMvJHtpfWBcclxuICAgICAgICAgICAgOiBgJHtjZG5Vcmx9L3N0b2NrL2luZGljYXRvcnMvJHtpfWBcclxuICAgICAgICApXHJcbiAgICAgIF0sXHJcbiAgICAgIGhpZ2hjaGFydHNPcHRpb25zLmN1c3RvbVNjcmlwdHMsXHJcbiAgICAgIHNlcnZlclByb3h5T3B0aW9ucyxcclxuICAgICAgZmV0Y2hlZE1vZHVsZXNcclxuICAgICk7XHJcblxyXG4gICAgLy8gRXh0cmFjdCBhbmQgc2F2ZSB2ZXJzaW9uIG9mIGN1cnJlbnRseSB1c2VkIEhpZ2hjaGFydHNcclxuICAgIGNhY2hlLmhjVmVyc2lvbiA9IGV4dHJhY3RWZXJzaW9uKGNhY2hlLnNvdXJjZXMpO1xyXG5cclxuICAgIC8vIFNhdmUgdGhlIGZldGNoZWQgbW9kdWxlcyBpbnRvIGNhY2hlcycgc291cmNlIEpTT05cclxuICAgIHdyaXRlRmlsZVN5bmMoc291cmNlUGF0aCwgY2FjaGUuc291cmNlcyk7XHJcbiAgICByZXR1cm4gZmV0Y2hlZE1vZHVsZXM7XHJcbiAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcihcclxuICAgICAgJ1tjYWNoZV0gVW5hYmxlIHRvIHVwZGF0ZSB0aGUgbG9jYWwgSGlnaGNoYXJ0cyBjYWNoZS4nLFxyXG4gICAgICA1MDBcclxuICAgICkuc2V0RXJyb3IoZXJyb3IpO1xyXG4gIH1cclxufVxyXG5cclxuZXhwb3J0IGRlZmF1bHQge1xyXG4gIGNoZWNrQW5kVXBkYXRlQ2FjaGUsXHJcbiAgZ2V0SGlnaGNoYXJ0c1ZlcnNpb24sXHJcbiAgdXBkYXRlSGlnaGNoYXJ0c1ZlcnNpb24sXHJcbiAgZXh0cmFjdFZlcnNpb24sXHJcbiAgZXh0cmFjdE1vZHVsZU5hbWUsXHJcbiAgZ2V0Q2FjaGUsXHJcbiAgZ2V0Q2FjaGVQYXRoXHJcbn07XHJcbiIsIi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXHJcblxyXG5IaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXJcclxuXHJcbkNvcHlyaWdodCAoYykgMjAxNi0yMDI1LCBIaWdoc29mdFxyXG5cclxuTGljZW5jZWQgdW5kZXIgdGhlIE1JVCBsaWNlbmNlLlxyXG5cclxuQWRkaXRpb25hbGx5IGEgdmFsaWQgSGlnaGNoYXJ0cyBsaWNlbnNlIGlzIHJlcXVpcmVkIGZvciB1c2UuXHJcblxyXG5TZWUgTElDRU5TRSBmaWxlIGluIHJvb3QgZm9yIGRldGFpbHMuXHJcblxyXG4qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xyXG5cclxuLyoqXHJcbiAqIEBvdmVydmlldyBQcm92aWRlcyBtZXRob2RzIGZvciBpbml0aWFsaXppbmcgSGlnaGNoYXJ0cyB3aXRoIGN1c3RvbWl6ZWRcclxuICogYW5pbWF0aW9uIHNldHRpbmdzIGFuZCB0cmlnZ2VyaW5nIHRoZSBjcmVhdGlvbiBvZiBIaWdoY2hhcnRzIGNoYXJ0cyB3aXRoXHJcbiAqIGV4cG9ydC1zcGVjaWZpYyBjb25maWd1cmF0aW9ucyBpbiB0aGUgcGFnZSBjb250ZXh0LiBTdXBwb3J0cyBkeW5hbWljIG9wdGlvblxyXG4gKiBtZXJnaW5nLCBjdXN0b20gbG9naWMgaW5qZWN0aW9uLCBhbmQgY29udHJvbCBvdmVyIHJlbmRlcmluZyBiZWhhdmlvcnMuIFVzZWRcclxuICogYnkgdGhlIFB1cHBldGVlciBwYWdlLlxyXG4gKi9cclxuXHJcbi8qIGVzbGludC1kaXNhYmxlIG5vLXVuZGVmICovXHJcblxyXG4vKipcclxuICogU2V0dGluZyB0aGUgYEhpZ2hjaGFydHMuYW5pbU9iamVjdGAgZnVuY3Rpb24uIENhbGxlZCB3aGVuIGluaXRpbmcgdGhlIHBhZ2UuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBzZXR1cEhpZ2hjaGFydHNcclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiBzZXR1cEhpZ2hjaGFydHMoKSB7XHJcbiAgSGlnaGNoYXJ0cy5hbmltT2JqZWN0ID0gZnVuY3Rpb24gKCkge1xyXG4gICAgcmV0dXJuIHsgZHVyYXRpb246IDAgfTtcclxuICB9O1xyXG59XHJcblxyXG4vKipcclxuICogQ3JlYXRlcyB0aGUgYWN0dWFsIEhpZ2hjaGFydHMgY2hhcnQgb24gYSBwYWdlLlxyXG4gKlxyXG4gKiBAYXN5bmNcclxuICogQGZ1bmN0aW9uIGNyZWF0ZUNoYXJ0XHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBleHBvcnRPcHRpb25zIC0gVGhlIGNvbmZpZ3VyYXRpb24gb2JqZWN0IGNvbnRhaW5pbmcgYGV4cG9ydGBcclxuICogb3B0aW9ucy5cclxuICogQHBhcmFtIHtPYmplY3R9IGN1c3RvbUxvZ2ljT3B0aW9ucyAtIFRoZSBjb25maWd1cmF0aW9uIG9iamVjdCBjb250YWluaW5nXHJcbiAqIGBjdXN0b21Mb2dpY2Agb3B0aW9ucy5cclxuICpcclxuICovXHJcbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBjcmVhdGVDaGFydChleHBvcnRPcHRpb25zLCBjdXN0b21Mb2dpY09wdGlvbnMpIHtcclxuICAvLyBHZXQgcmVxdWlyZWQgZnVuY3Rpb25zXHJcbiAgY29uc3QgeyBnZXRPcHRpb25zLCBzZXRPcHRpb25zLCBtZXJnZSwgd3JhcCB9ID0gSGlnaGNoYXJ0cztcclxuXHJcbiAgLy8gQ3JlYXRlIGEgc2VwYXJhdGUgb2JqZWN0IGZvciBhIHBvdGVudGlhbCBgc2V0T3B0aW9uc2AgdXNhZ2VzIGluIG9yZGVyXHJcbiAgLy8gdG8gcHJldmVudCBmcm9tIHBvbGx1dGluZyBvdGhlciBleHBvcnRzIHRoYXQgY2FuIGhhcHBlbiBvbiB0aGUgc2FtZSBwYWdlXHJcbiAgSGlnaGNoYXJ0cy5zZXRPcHRpb25zT2JqID0gbWVyZ2UoZmFsc2UsIHt9LCBnZXRPcHRpb25zKCkpO1xyXG5cclxuICAvLyBOT1RFOiBJcyB0aGlzIHVzZWQgZm9yIGFueXRoaW5nIHVzZWZ1bD9cclxuICB3aW5kb3cuaXNSZW5kZXJDb21wbGV0ZSA9IGZhbHNlO1xyXG4gIHdyYXAoSGlnaGNoYXJ0cy5DaGFydC5wcm90b3R5cGUsICdpbml0JywgZnVuY3Rpb24gKHByb2NlZWQsIHVzZXJPcHRpb25zLCBjYikge1xyXG4gICAgLy8gT3ZlcnJpZGUgdGhlIGB1c2VyT3B0aW9uc2Agd2l0aCBpbWFnZSBmcmllbmRseSBvcHRpb25zXHJcbiAgICB1c2VyT3B0aW9ucyA9IG1lcmdlKHVzZXJPcHRpb25zLCB7XHJcbiAgICAgIGV4cG9ydGluZzoge1xyXG4gICAgICAgIGVuYWJsZWQ6IGZhbHNlXHJcbiAgICAgIH0sXHJcbiAgICAgIHBsb3RPcHRpb25zOiB7XHJcbiAgICAgICAgc2VyaWVzOiB7XHJcbiAgICAgICAgICBsYWJlbDoge1xyXG4gICAgICAgICAgICBlbmFibGVkOiBmYWxzZVxyXG4gICAgICAgICAgfVxyXG4gICAgICAgIH1cclxuICAgICAgfSxcclxuICAgICAgLyogRXhwZWN0cyB0b29sdGlwIGluIHRoZSBgdXNlck9wdGlvbnNgIHdoZW4gYGZvckV4cG9ydGAgaXMgdHJ1ZS5cclxuICAgICAgICBodHRwczovL2dpdGh1Yi5jb20vaGlnaGNoYXJ0cy9oaWdoY2hhcnRzL2Jsb2IvM2FkNDMwYTM1M2I4MDU2YjllNzY0YWE0ZTVjZDY4MjhhYTQ3OWRiMi9qcy9wYXJ0cy9DaGFydC5qcyNMMjQxXHJcbiAgICAgICAgKi9cclxuICAgICAgdG9vbHRpcDoge31cclxuICAgIH0pO1xyXG5cclxuICAgICh1c2VyT3B0aW9ucy5zZXJpZXMgfHwgW10pLmZvckVhY2goZnVuY3Rpb24gKHNlcmllcykge1xyXG4gICAgICBzZXJpZXMuYW5pbWF0aW9uID0gZmFsc2U7XHJcbiAgICB9KTtcclxuXHJcbiAgICAvLyBBZGQgZmxhZyB0byBrbm93IGlmIGNoYXJ0IHJlbmRlciBoYXMgYmVlbiBjYWxsZWQuXHJcbiAgICBpZiAoIXdpbmRvdy5vbkhpZ2hjaGFydHNSZW5kZXIpIHtcclxuICAgICAgd2luZG93Lm9uSGlnaGNoYXJ0c1JlbmRlciA9IEhpZ2hjaGFydHMuYWRkRXZlbnQodGhpcywgJ3JlbmRlcicsICgpID0+IHtcclxuICAgICAgICB3aW5kb3cuaXNSZW5kZXJDb21wbGV0ZSA9IHRydWU7XHJcbiAgICAgIH0pO1xyXG4gICAgfVxyXG5cclxuICAgIHByb2NlZWQuYXBwbHkodGhpcywgW3VzZXJPcHRpb25zLCBjYl0pO1xyXG4gIH0pO1xyXG5cclxuICB3cmFwKEhpZ2hjaGFydHMuU2VyaWVzLnByb3RvdHlwZSwgJ2luaXQnLCBmdW5jdGlvbiAocHJvY2VlZCwgY2hhcnQsIG9wdGlvbnMpIHtcclxuICAgIHByb2NlZWQuYXBwbHkodGhpcywgW2NoYXJ0LCBvcHRpb25zXSk7XHJcbiAgfSk7XHJcblxyXG4gIC8vIFNvbWUgbWFuZGF0b3J5IGFkZGl0aW9uYWwgYGNoYXJ0YCBhbmQgYGV4cG9ydGluZ2Agb3B0aW9uc1xyXG4gIGNvbnN0IGFkZGl0aW9uYWxPcHRpb25zID0ge1xyXG4gICAgY2hhcnQ6IHtcclxuICAgICAgLy8gQnkgZGVmYXVsdCBhbmltYXRpb24gaXMgZGlzYWJsZWRcclxuICAgICAgYW5pbWF0aW9uOiBmYWxzZSxcclxuICAgICAgLy8gR2V0IHRoZSByaWdodCBzaXplIHZhbHVlc1xyXG4gICAgICBoZWlnaHQ6IGV4cG9ydE9wdGlvbnMuaGVpZ2h0LFxyXG4gICAgICB3aWR0aDogZXhwb3J0T3B0aW9ucy53aWR0aFxyXG4gICAgfSxcclxuICAgIGV4cG9ydGluZzoge1xyXG4gICAgICAvLyBObyBuZWVkIGZvciB0aGUgZXhwb3J0aW5nIGJ1dHRvblxyXG4gICAgICBlbmFibGVkOiBmYWxzZVxyXG4gICAgfVxyXG4gIH07XHJcblxyXG4gIC8vIEdldCB0aGUgaW5wdXQgdG8gZXhwb3J0IGZyb20gdGhlIGBpbnN0cmAgb3B0aW9uXHJcbiAgY29uc3QgdXNlck9wdGlvbnMgPSBuZXcgRnVuY3Rpb24oYHJldHVybiAke2V4cG9ydE9wdGlvbnMuaW5zdHJ9YCkoKTtcclxuXHJcbiAgLy8gR2V0IHRoZSBgdGhlbWVPcHRpb25zYCBvcHRpb25cclxuICBjb25zdCB0aGVtZU9wdGlvbnMgPSBuZXcgRnVuY3Rpb24oYHJldHVybiAke2V4cG9ydE9wdGlvbnMudGhlbWVPcHRpb25zfWApKCk7XHJcblxyXG4gIC8vIEdldCB0aGUgYGdsb2JhbE9wdGlvbnNgIG9wdGlvblxyXG4gIGNvbnN0IGdsb2JhbE9wdGlvbnMgPSBuZXcgRnVuY3Rpb24oYHJldHVybiAke2V4cG9ydE9wdGlvbnMuZ2xvYmFsT3B0aW9uc31gKSgpO1xyXG5cclxuICAvLyBNZXJnZSB0aGUgZm9sbG93aW5nIG9wdGlvbnMgb2JqZWN0cyB0byBjcmVhdGUgZmluYWwgb3B0aW9uc1xyXG4gIGNvbnN0IGZpbmFsT3B0aW9ucyA9IG1lcmdlKFxyXG4gICAgZmFsc2UsXHJcbiAgICB0aGVtZU9wdGlvbnMsXHJcbiAgICB1c2VyT3B0aW9ucyxcclxuICAgIC8vIFBsYWNlZCBpdCBoZXJlIGluc3RlYWQgaW4gdGhlIGluaXQgYmVjYXVzZSBvZiB0aGUgc2l6ZSBpc3N1ZXNcclxuICAgIGFkZGl0aW9uYWxPcHRpb25zXHJcbiAgKTtcclxuXHJcbiAgLy8gUHJlcGFyZSB0aGUgYGNhbGxiYWNrYCBvcHRpb25cclxuICBjb25zdCBmaW5hbENhbGxiYWNrID0gY3VzdG9tTG9naWNPcHRpb25zLmNhbGxiYWNrXHJcbiAgICA/IG5ldyBGdW5jdGlvbihgcmV0dXJuICR7Y3VzdG9tTG9naWNPcHRpb25zLmNhbGxiYWNrfWApKClcclxuICAgIDogbnVsbDtcclxuXHJcbiAgLy8gVHJpZ2dlciB0aGUgYGN1c3RvbUNvZGVgIG9wdGlvblxyXG4gIGlmIChjdXN0b21Mb2dpY09wdGlvbnMuY3VzdG9tQ29kZSkge1xyXG4gICAgbmV3IEZ1bmN0aW9uKCdvcHRpb25zJywgY3VzdG9tTG9naWNPcHRpb25zLmN1c3RvbUNvZGUpKHVzZXJPcHRpb25zKTtcclxuICB9XHJcblxyXG4gIC8vIFNldCB0aGUgZ2xvYmFsIG9wdGlvbnMgaWYgZXhpc3RcclxuICBpZiAoZ2xvYmFsT3B0aW9ucykge1xyXG4gICAgc2V0T3B0aW9ucyhnbG9iYWxPcHRpb25zKTtcclxuICB9XHJcblxyXG4gIC8vIENhbGwgdGhlIGNoYXJ0IGNyZWF0aW9uXHJcbiAgSGlnaGNoYXJ0c1tleHBvcnRPcHRpb25zLmNvbnN0cl0oJ2NvbnRhaW5lcicsIGZpbmFsT3B0aW9ucywgZmluYWxDYWxsYmFjayk7XHJcblxyXG4gIC8vIEdldCB0aGUgY3VycmVudCBnbG9iYWwgb3B0aW9uc1xyXG4gIGNvbnN0IGRlZmF1bHRPcHRpb25zID0gZ2V0T3B0aW9ucygpO1xyXG5cclxuICAvLyBDbGVhciBpdCBqdXN0IGluIGNhc2UgKGUuZy4gdGhlIGBzZXRPcHRpb25zYCB3YXMgdXNlZCBpbiB0aGUgYGN1c3RvbUNvZGVgKVxyXG4gIGZvciAoY29uc3QgcHJvcCBpbiBkZWZhdWx0T3B0aW9ucykge1xyXG4gICAgaWYgKHR5cGVvZiBkZWZhdWx0T3B0aW9uc1twcm9wXSAhPT0gJ2Z1bmN0aW9uJykge1xyXG4gICAgICBkZWxldGUgZGVmYXVsdE9wdGlvbnNbcHJvcF07XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICAvLyBTZXQgdGhlIGRlZmF1bHQgb3B0aW9ucyBiYWNrXHJcbiAgc2V0T3B0aW9ucyhIaWdoY2hhcnRzLnNldE9wdGlvbnNPYmopO1xyXG5cclxuICAvLyBFbXB0eSB0aGUgY3VzdG9tIGdsb2JhbCBvcHRpb25zIG9iamVjdFxyXG4gIEhpZ2hjaGFydHMuc2V0T3B0aW9uc09iaiA9IHt9O1xyXG59XHJcblxyXG5leHBvcnQgZGVmYXVsdCB7XHJcbiAgc2V0dXBIaWdoY2hhcnRzLFxyXG4gIGNyZWF0ZUNoYXJ0XHJcbn07XHJcbiIsIi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXHJcblxyXG5IaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXJcclxuXHJcbkNvcHlyaWdodCAoYykgMjAxNi0yMDI1LCBIaWdoc29mdFxyXG5cclxuTGljZW5jZWQgdW5kZXIgdGhlIE1JVCBsaWNlbmNlLlxyXG5cclxuQWRkaXRpb25hbGx5IGEgdmFsaWQgSGlnaGNoYXJ0cyBsaWNlbnNlIGlzIHJlcXVpcmVkIGZvciB1c2UuXHJcblxyXG5TZWUgTElDRU5TRSBmaWxlIGluIHJvb3QgZm9yIGRldGFpbHMuXHJcblxyXG4qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xyXG5cclxuLyoqXHJcbiAqIEBvdmVydmlldyBUaGlzIG1vZHVsZSBwcm92aWRlcyBmdW5jdGlvbnMgZm9yIG1hbmFnaW5nIFB1cHBldGVlciBicm93c2VyXHJcbiAqIGluc3RhbmNlLCBjcmVhdGluZyBhbmQgY2xlYXJpbmcgcGFnZXMsIGluamVjdGluZyBjdXN0b20gcmVzb3VyY2VzLFxyXG4gKiBhbmQgc2V0dGluZyB1cCBIaWdoY2hhcnRzIGZvciBzZXJ2ZXItc2lkZSByZW5kZXJpbmcuIFRoZSBtb2R1bGUgZW5zdXJlc1xyXG4gKiB0aGF0IHJlc291cmNlcyBhcmUgY29ycmVjdGx5IG1hbmFnZWQgYW5kIGNhbiBoYW5kbGUgZmFpbHVyZXMgZHVyaW5nXHJcbiAqIG9wZXJhdGlvbnMgbGlrZSBsYXVuY2hpbmcgdGhlIGJyb3dzZXIgb3IgY3JlYXRpbmcgbmV3IHBhZ2VzLlxyXG4gKi9cclxuXHJcbmltcG9ydCB7IHJlYWRGaWxlU3luYyB9IGZyb20gJ2ZzJztcclxuaW1wb3J0IHsgam9pbiB9IGZyb20gJ3BhdGgnO1xyXG5cclxuaW1wb3J0IHB1cHBldGVlciBmcm9tICdwdXBwZXRlZXInO1xyXG5cclxuaW1wb3J0IHsgZ2V0Q2FjaGVQYXRoIH0gZnJvbSAnLi9jYWNoZS5qcyc7XHJcbmltcG9ydCB7IGdldE9wdGlvbnMgfSBmcm9tICcuL2NvbmZpZy5qcyc7XHJcbmltcG9ydCB7IHNldHVwSGlnaGNoYXJ0cyB9IGZyb20gJy4vaGlnaGNoYXJ0cy5qcyc7XHJcbmltcG9ydCB7IGxvZywgbG9nV2l0aFN0YWNrIH0gZnJvbSAnLi9sb2dnZXIuanMnO1xyXG5pbXBvcnQgeyBfX2Rpcm5hbWUsIGdldEFic29sdXRlUGF0aCB9IGZyb20gJy4vdXRpbHMuanMnO1xyXG5cclxuaW1wb3J0IEV4cG9ydEVycm9yIGZyb20gJy4vZXJyb3JzL0V4cG9ydEVycm9yLmpzJztcclxuXHJcbi8vIEdldCB0aGUgdGVtcGxhdGUgZm9yIHBhZ2VzXHJcbmNvbnN0IHRlbXBsYXRlID0gcmVhZEZpbGVTeW5jKFxyXG4gIGpvaW4oX19kaXJuYW1lLCAndGVtcGxhdGVzJywgJ3RlbXBsYXRlLmh0bWwnKSxcclxuICAndXRmOCdcclxuKTtcclxuXHJcbi8vIFRvIHNhdmUgdGhlIGJyb3dzZXJcclxubGV0IGJyb3dzZXIgPSBudWxsO1xyXG5cclxuLyoqXHJcbiAqIFJldHJpZXZlcyB0aGUgZXhpc3RpbmcgUHVwcGV0ZWVyIGJyb3dzZXIgaW5zdGFuY2UuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBnZXRCcm93c2VyXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtPYmplY3R9IFRoZSBQdXBwZXRlZXIgYnJvd3NlciBpbnN0YW5jZS5cclxuICpcclxuICogQHRocm93cyB7RXhwb3J0RXJyb3J9IFRocm93cyBhbiBgRXhwb3J0RXJyb3JgIGlmIG5vIHZhbGlkIGJyb3dzZXJcclxuICogaGFzIGJlZW4gY3JlYXRlZC5cclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiBnZXRCcm93c2VyKCkge1xyXG4gIGlmICghYnJvd3Nlcikge1xyXG4gICAgdGhyb3cgbmV3IEV4cG9ydEVycm9yKCdbYnJvd3Nlcl0gTm8gdmFsaWQgYnJvd3NlciBoYXMgYmVlbiBjcmVhdGVkLicsIDUwMCk7XHJcbiAgfVxyXG4gIHJldHVybiBicm93c2VyO1xyXG59XHJcblxyXG4vKipcclxuICogQ3JlYXRlcyBhIFB1cHBldGVlciBicm93c2VyIGluc3RhbmNlIHdpdGggdGhlIHNwZWNpZmllZCBhcmd1bWVudHMuXHJcbiAqXHJcbiAqIEBhc3luY1xyXG4gKiBAZnVuY3Rpb24gY3JlYXRlQnJvd3NlclxyXG4gKlxyXG4gKiBAcGFyYW0ge0FycmF5LjxzdHJpbmc+fSBwdXBwZXRlZXJBcmdzIC0gQWRkaXRpb25hbCBhcmd1bWVudHMgZm9yIFB1cHBldGVlclxyXG4gKiBsYXVuY2guXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtQcm9taXNlPE9iamVjdD59IEEgUHJvbWlzZSB0aGF0IHJlc29sdmVzIHRvIHRoZSBjcmVhdGVkIFB1cHBldGVlclxyXG4gKiBicm93c2VyIGluc3RhbmNlLlxyXG4gKlxyXG4gKiBAdGhyb3dzIHtFeHBvcnRFcnJvcn0gVGhyb3dzIGFuIGBFeHBvcnRFcnJvcmAgaWYgbWF4IHJldHJpZXMgdG8gb3BlblxyXG4gKiBhIGJyb3dzZXIgaW5zdGFuY2UgYXJlIHJlYWNoZWQsIG9yIGlmIG5vIGJyb3dzZXIgaW5zdGFuY2UgaXMgZm91bmQgYWZ0ZXJcclxuICogcmV0cmllcy5cclxuICovXHJcbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBjcmVhdGVCcm93c2VyKHB1cHBldGVlckFyZ3MpIHtcclxuICAvLyBHZXQgYGRlYnVnYCBhbmQgYG90aGVyYCBvcHRpb25zXHJcbiAgY29uc3QgeyBkZWJ1Zywgb3RoZXIgfSA9IGdldE9wdGlvbnMoKTtcclxuXHJcbiAgLy8gR2V0IHRoZSBgZGVidWdgIG9wdGlvbnNcclxuICBjb25zdCB7IGVuYWJsZTogZW5hYmxlZERlYnVnLCAuLi5kZWJ1Z09wdGlvbnMgfSA9IGRlYnVnO1xyXG5cclxuICAvLyBMYXVuY2ggb3B0aW9ucyBmb3IgdGhlIGJyb3dzZXIgaW5zdGFuY2VcclxuICBjb25zdCBsYXVuY2hPcHRpb25zID0ge1xyXG4gICAgaGVhZGxlc3M6IG90aGVyLmJyb3dzZXJTaGVsbE1vZGUgPyAnc2hlbGwnIDogdHJ1ZSxcclxuICAgIHVzZXJEYXRhRGlyOiAndG1wJyxcclxuICAgIGFyZ3M6IHB1cHBldGVlckFyZ3MgfHwgW10sXHJcbiAgICBoYW5kbGVTSUdJTlQ6IGZhbHNlLFxyXG4gICAgaGFuZGxlU0lHVEVSTTogZmFsc2UsXHJcbiAgICBoYW5kbGVTSUdIVVA6IGZhbHNlLFxyXG4gICAgd2FpdEZvckluaXRpYWxQYWdlOiBmYWxzZSxcclxuICAgIGRlZmF1bHRWaWV3cG9ydDogbnVsbCxcclxuICAgIC4uLihlbmFibGVkRGVidWcgJiYgZGVidWdPcHRpb25zKVxyXG4gIH07XHJcblxyXG4gIC8vIENyZWF0ZSBhIGJyb3dzZXJcclxuICBpZiAoIWJyb3dzZXIpIHtcclxuICAgIC8vIEEgY291bnRlciBmb3IgdGhlIGJyb3dzZXIncyBsYXVuY2ggcmV0cmllc1xyXG4gICAgbGV0IHRyeUNvdW50ID0gMDtcclxuXHJcbiAgICBjb25zdCBvcGVuID0gYXN5bmMgKCkgPT4ge1xyXG4gICAgICB0cnkge1xyXG4gICAgICAgIGxvZyhcclxuICAgICAgICAgIDMsXHJcbiAgICAgICAgICBgW2Jyb3dzZXJdIEF0dGVtcHRpbmcgdG8gZ2V0IGEgYnJvd3NlciBpbnN0YW5jZSAodHJ5ICR7Kyt0cnlDb3VudH0pLmBcclxuICAgICAgICApO1xyXG5cclxuICAgICAgICAvLyBMYXVuY2ggdGhlIGJyb3dzZXJcclxuICAgICAgICBicm93c2VyID0gYXdhaXQgcHVwcGV0ZWVyLmxhdW5jaChsYXVuY2hPcHRpb25zKTtcclxuICAgICAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICAgICBsb2dXaXRoU3RhY2soXHJcbiAgICAgICAgICAxLFxyXG4gICAgICAgICAgZXJyb3IsXHJcbiAgICAgICAgICAnW2Jyb3dzZXJdIEZhaWxlZCB0byBsYXVuY2ggYSBicm93c2VyIGluc3RhbmNlLidcclxuICAgICAgICApO1xyXG5cclxuICAgICAgICAvLyBSZXRyeSB0byBsYXVuY2ggYnJvd3NlciB1bnRpbCByZWFjaGluZyBtYXggYXR0ZW1wdHNcclxuICAgICAgICBpZiAodHJ5Q291bnQgPCAyNSkge1xyXG4gICAgICAgICAgbG9nKDMsIGBbYnJvd3Nlcl0gUmV0cnkgdG8gb3BlbiBhIGJyb3dzZXIgKCR7dHJ5Q291bnR9IG91dCBvZiAyNSkuYCk7XHJcblxyXG4gICAgICAgICAgLy8gV2FpdCBmb3IgYSA0IHNlY29uZHMgYmVmb3JlIHRyeWluZyBhZ2FpblxyXG4gICAgICAgICAgYXdhaXQgbmV3IFByb21pc2UoKHJlc3BvbnNlKSA9PiBzZXRUaW1lb3V0KHJlc3BvbnNlLCA0MDAwKSk7XHJcbiAgICAgICAgICBhd2FpdCBvcGVuKCk7XHJcbiAgICAgICAgfSBlbHNlIHtcclxuICAgICAgICAgIHRocm93IGVycm9yO1xyXG4gICAgICAgIH1cclxuICAgICAgfVxyXG4gICAgfTtcclxuXHJcbiAgICB0cnkge1xyXG4gICAgICBhd2FpdCBvcGVuKCk7XHJcblxyXG4gICAgICAvLyBTaGVsbCBtb2RlIGluZm9ybVxyXG4gICAgICBpZiAobGF1bmNoT3B0aW9ucy5oZWFkbGVzcyA9PT0gJ3NoZWxsJykge1xyXG4gICAgICAgIGxvZygzLCBgW2Jyb3dzZXJdIExhdW5jaGVkIGJyb3dzZXIgaW4gc2hlbGwgbW9kZS5gKTtcclxuICAgICAgfVxyXG5cclxuICAgICAgLy8gRGVidWcgbW9kZSBpbmZvcm1cclxuICAgICAgaWYgKGVuYWJsZWREZWJ1Zykge1xyXG4gICAgICAgIGxvZygzLCBgW2Jyb3dzZXJdIExhdW5jaGVkIGJyb3dzZXIgaW4gZGVidWcgbW9kZS5gKTtcclxuICAgICAgfVxyXG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICAgdGhyb3cgbmV3IEV4cG9ydEVycm9yKFxyXG4gICAgICAgICdbYnJvd3Nlcl0gTWF4aW11bSByZXRyaWVzIHRvIG9wZW4gYSBicm93c2VyIGluc3RhbmNlIHJlYWNoZWQuJyxcclxuICAgICAgICA1MDBcclxuICAgICAgKS5zZXRFcnJvcihlcnJvcik7XHJcbiAgICB9XHJcblxyXG4gICAgaWYgKCFicm93c2VyKSB7XHJcbiAgICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcignW2Jyb3dzZXJdIENhbm5vdCBmaW5kIGEgYnJvd3NlciB0byBvcGVuLicsIDUwMCk7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICAvLyBSZXR1cm4gYSBicm93c2VyIGluc3RhbmNlXHJcbiAgcmV0dXJuIGJyb3dzZXI7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBDbG9zZXMgdGhlIFB1cHBldGVlciBicm93c2VyIGluc3RhbmNlIGlmIGl0IGlzIGNvbm5lY3RlZC5cclxuICpcclxuICogQGFzeW5jXHJcbiAqIEBmdW5jdGlvbiBjbG9zZUJyb3dzZXJcclxuICovXHJcbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBjbG9zZUJyb3dzZXIoKSB7XHJcbiAgLy8gQ2xvc2UgdGhlIGJyb3dzZXIgd2hlbiBjb25uZWN0ZWRcclxuICBpZiAoYnJvd3NlciAmJiBicm93c2VyLmNvbm5lY3RlZCkge1xyXG4gICAgYXdhaXQgYnJvd3Nlci5jbG9zZSgpO1xyXG4gIH1cclxuICBicm93c2VyID0gbnVsbDtcclxuICBsb2coNCwgJ1ticm93c2VyXSBDbG9zZWQgdGhlIGJyb3dzZXIuJyk7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBDcmVhdGVzIGEgbmV3IFB1cHBldGVlciBwYWdlIHdpdGhpbiBhbiBleGlzdGluZyBicm93c2VyIGluc3RhbmNlLlxyXG4gKiBUaGUgZnVuY3Rpb24gY3JlYXRlcyBhIG5ldyBwYWdlLCBkaXNhYmxlcyBjYWNoaW5nLCBzZXRzIGNvbnRlbnQgdXNpbmdcclxuICogdGhlIGBfc2V0UGFnZUNvbnRlbnQoKWAsIGFuZCByZXR1cm5zIHRoZSBjcmVhdGVkIFB1cHBldGVlciBwYWdlLlxyXG4gKlxyXG4gKiBAYXN5bmNcclxuICogQGZ1bmN0aW9uIG5ld1BhZ2VcclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IHBvb2xSZXNvdXJjZSAtIFRoZSBwb29sIHJlc291cmNlIHRoYXQgY29udGFpbnMgYGlkYCxcclxuICogYHdvcmtDb3VudGAsIGFuZCBgcGFnZWAuXHJcbiAqXHJcbiAqIEB0aHJvd3Mge0V4cG9ydEVycm9yfSBUaHJvd3MgYW4gYEV4cG9ydEVycm9yYCBpZiBubyB2YWxpZCBicm93c2VyXHJcbiAqIGhhcyBiZWVuIGNvbm5lY3RlZCBvciBpZiBhIHBhZ2UgaXMgaW52YWxpZCBvciBjbG9zZWQuXHJcbiAqL1xyXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gbmV3UGFnZShwb29sUmVzb3VyY2UpIHtcclxuICAvLyBFcnJvciBpbiBjYXNlIG9mIG5vIGNvbm5lY3RlZCBicm93c2VyXHJcbiAgaWYgKCFicm93c2VyIHx8ICFicm93c2VyLmNvbm5lY3RlZCkge1xyXG4gICAgdGhyb3cgbmV3IEV4cG9ydEVycm9yKGBbYnJvd3Nlcl0gQnJvd3NlciBpcyBub3QgeWV0IGNvbm5lY3RlZC5gLCA1MDApO1xyXG4gIH1cclxuXHJcbiAgLy8gQ3JlYXRlIGEgcGFnZVxyXG4gIHBvb2xSZXNvdXJjZS5wYWdlID0gYXdhaXQgYnJvd3Nlci5uZXdQYWdlKCk7XHJcblxyXG4gIC8vIERpc2FibGUgY2FjaGVcclxuICBhd2FpdCBwb29sUmVzb3VyY2UucGFnZS5zZXRDYWNoZUVuYWJsZWQoZmFsc2UpO1xyXG5cclxuICAvLyBTZXQgdGhlIGNvbnRlbnRcclxuICBhd2FpdCBfc2V0UGFnZUNvbnRlbnQocG9vbFJlc291cmNlLnBhZ2UpO1xyXG5cclxuICAvLyBTZXQgcGFnZSBldmVudHNcclxuICBfc2V0UGFnZUV2ZW50cyhwb29sUmVzb3VyY2UucGFnZSk7XHJcblxyXG4gIC8vIENoZWNrIGlmIHRoZSBwYWdlIGlzIGNvcnJlY3RseSBjcmVhdGVkXHJcbiAgaWYgKCFwb29sUmVzb3VyY2UucGFnZSB8fCBwb29sUmVzb3VyY2UucGFnZS5pc0Nsb3NlZCgpKSB7XHJcbiAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoJ1ticm93c2VyXSBUaGUgcGFnZSBpcyBpbnZhbGlkIG9yIGNsb3NlZC4nLCA0MDApO1xyXG4gIH1cclxufVxyXG5cclxuLyoqXHJcbiAqIENsZWFycyB0aGUgY29udGVudCBvZiBhIFB1cHBldGVlciBQYWdlIGJhc2VkIG9uIHRoZSBzcGVjaWZpZWQgbW9kZS4gTG9nc1xyXG4gKiB0aHJvd24gZXJyb3IgaWYgY2xlYXJpbmcgb2YgYSBwYWdlJ3MgY29udGVudCBmYWlscy5cclxuICpcclxuICogQGFzeW5jXHJcbiAqIEBmdW5jdGlvbiBjbGVhclBhZ2VcclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IHBvb2xSZXNvdXJjZSAtIFRoZSBwb29sIHJlc291cmNlIHRoYXQgY29udGFpbnMgcGFnZSBhbmQgaWQuXHJcbiAqIEBwYXJhbSB7Ym9vbGVhbn0gW2hhcmRSZXNldD1mYWxzZV0gLSBBIGZsYWcgaW5kaWNhdGluZyB0aGUgdHlwZSBvZiBjbGVhcmluZ1xyXG4gKiB0byBiZSBwZXJmb3JtZWQuIElmIHRydWUsIG5hdmlnYXRlcyB0byBgYWJvdXQ6YmxhbmtgIGFuZCByZXNldHMgY29udGVudFxyXG4gKiBhbmQgc2NyaXB0cy4gSWYgZmFsc2UsIGNsZWFycyB0aGUgYm9keSBjb250ZW50IGJ5IHNldHRpbmcgYSBwcmVkZWZpbmVkIEhUTUxcclxuICogc3RydWN0dXJlLiBUaGUgZGVmYXVsdCB2YWx1ZSBpcyBgZmFsc2VgLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7UHJvbWlzZTxib29sZWFuPn0gQSBQcm9taXNlIHRoYXQgcmVzb2x2ZXMgdG8gdHJ1ZSB3aGVuIHBhZ2VcclxuICogaXMgY29ycmVjdGx5IGNsZWFyZWQgYW5kIGZhbHNlIHdoZW4gaXQgaXMgbm90LlxyXG4gKi9cclxuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIGNsZWFyUGFnZShwb29sUmVzb3VyY2UsIGhhcmRSZXNldCA9IGZhbHNlKSB7XHJcbiAgdHJ5IHtcclxuICAgIGlmIChwb29sUmVzb3VyY2UucGFnZSAmJiAhcG9vbFJlc291cmNlLnBhZ2UuaXNDbG9zZWQoKSkge1xyXG4gICAgICBpZiAoaGFyZFJlc2V0KSB7XHJcbiAgICAgICAgLy8gTmF2aWdhdGUgdG8gYGFib3V0OmJsYW5rYFxyXG4gICAgICAgIGF3YWl0IHBvb2xSZXNvdXJjZS5wYWdlLmdvdG8oJ2Fib3V0OmJsYW5rJywge1xyXG4gICAgICAgICAgd2FpdFVudGlsOiAnZG9tY29udGVudGxvYWRlZCdcclxuICAgICAgICB9KTtcclxuXHJcbiAgICAgICAgLy8gU2V0IHRoZSBjb250ZW50IGFuZCBhbmQgc2NyaXB0cyBhZ2FpblxyXG4gICAgICAgIGF3YWl0IF9zZXRQYWdlQ29udGVudChwb29sUmVzb3VyY2UucGFnZSk7XHJcbiAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgLy8gQ2xlYXIgYm9keSBjb250ZW50XHJcbiAgICAgICAgYXdhaXQgcG9vbFJlc291cmNlLnBhZ2UuZXZhbHVhdGUoKCkgPT4ge1xyXG4gICAgICAgICAgZG9jdW1lbnQuYm9keS5pbm5lckhUTUwgPVxyXG4gICAgICAgICAgICAnPGRpdiBpZD1cImNoYXJ0LWNvbnRhaW5lclwiPjxkaXYgaWQ9XCJjb250YWluZXJcIj48L2Rpdj48L2Rpdj4nO1xyXG4gICAgICAgIH0pO1xyXG4gICAgICB9XHJcbiAgICAgIHJldHVybiB0cnVlO1xyXG4gICAgfVxyXG4gIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICBsb2dXaXRoU3RhY2soXHJcbiAgICAgIDIsXHJcbiAgICAgIGVycm9yLFxyXG4gICAgICBgW3Bvb2xdIFBvb2wgcmVzb3VyY2UgWyR7cG9vbFJlc291cmNlLmlkfV0gLSBDb250ZW50IG9mIHRoZSBwYWdlIGNvdWxkIG5vdCBiZSBjbGVhcmVkLmBcclxuICAgICk7XHJcblxyXG4gICAgLy8gU2V0IHRoZSBgd29ya0xpbWl0YCB0byBleGNlZWRlZCBpbiBvcmRlciB0byByZWNyZWF0ZSB0aGUgcmVzb3VyY2VcclxuICAgIHBvb2xSZXNvdXJjZS53b3JrQ291bnQgPSBnZXRPcHRpb25zKCkucG9vbC53b3JrTGltaXQgKyAxO1xyXG4gIH1cclxuICByZXR1cm4gZmFsc2U7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBBZGRzIGN1c3RvbSBKUyBhbmQgQ1NTIHJlc291cmNlcyB0byBhIFB1cHBldGVlciBQYWdlIGJhc2VkIG9uIHRoZSBzcGVjaWZpZWRcclxuICogb3B0aW9ucy5cclxuICpcclxuICogQGFzeW5jXHJcbiAqIEBmdW5jdGlvbiBhZGRQYWdlUmVzb3VyY2VzXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBwYWdlIC0gVGhlIFB1cHBldGVlciBwYWdlIG9iamVjdCB0byB3aGljaCByZXNvdXJjZXMgd2lsbFxyXG4gKiBiZSBhZGRlZC5cclxuICogQHBhcmFtIHtPYmplY3R9IGN1c3RvbUxvZ2ljT3B0aW9ucyAtIFRoZSBjb25maWd1cmF0aW9uIG9iamVjdCBjb250YWluaW5nXHJcbiAqIGBjdXN0b21Mb2dpY2Agb3B0aW9ucy5cclxuICpcclxuICogQHJldHVybnMge1Byb21pc2U8QXJyYXkuPE9iamVjdD4+fSBBIFByb21pc2UgdGhhdCByZXNvbHZlcyB0byBhbiBhcnJheVxyXG4gKiBvZiBpbmplY3RlZCByZXNvdXJjZXMuXHJcbiAqL1xyXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gYWRkUGFnZVJlc291cmNlcyhwYWdlLCBjdXN0b21Mb2dpY09wdGlvbnMpIHtcclxuICAvLyBJbmplY3RlZCByZXNvdXJjZXMgYXJyYXlcclxuICBjb25zdCBpbmplY3RlZFJlc291cmNlcyA9IFtdO1xyXG5cclxuICAvLyBVc2UgcmVzb3VyY2VzXHJcbiAgY29uc3QgcmVzb3VyY2VzID0gY3VzdG9tTG9naWNPcHRpb25zLnJlc291cmNlcztcclxuICBpZiAocmVzb3VyY2VzKSB7XHJcbiAgICBjb25zdCBpbmplY3RlZEpzID0gW107XHJcblxyXG4gICAgLy8gTG9hZCBjdXN0b20gSlMgY29kZVxyXG4gICAgaWYgKHJlc291cmNlcy5qcykge1xyXG4gICAgICBpbmplY3RlZEpzLnB1c2goe1xyXG4gICAgICAgIGNvbnRlbnQ6IHJlc291cmNlcy5qc1xyXG4gICAgICB9KTtcclxuICAgIH1cclxuXHJcbiAgICAvLyBMb2FkIHNjcmlwdHMgZnJvbSBhbGwgY3VzdG9tIGZpbGVzXHJcbiAgICBpZiAocmVzb3VyY2VzLmZpbGVzKSB7XHJcbiAgICAgIGZvciAoY29uc3QgZmlsZSBvZiByZXNvdXJjZXMuZmlsZXMpIHtcclxuICAgICAgICBjb25zdCBpc0xvY2FsID0gIWZpbGUuc3RhcnRzV2l0aCgnaHR0cCcpID8gdHJ1ZSA6IGZhbHNlO1xyXG5cclxuICAgICAgICAvLyBBZGQgZWFjaCBjdXN0b20gc2NyaXB0IGZyb20gcmVzb3VyY2VzJyBmaWxlc1xyXG4gICAgICAgIGluamVjdGVkSnMucHVzaChcclxuICAgICAgICAgIGlzTG9jYWxcclxuICAgICAgICAgICAgPyB7XHJcbiAgICAgICAgICAgICAgICBjb250ZW50OiByZWFkRmlsZVN5bmMoZ2V0QWJzb2x1dGVQYXRoKGZpbGUpLCAndXRmOCcpXHJcbiAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICA6IHtcclxuICAgICAgICAgICAgICAgIHVybDogZmlsZVxyXG4gICAgICAgICAgICAgIH1cclxuICAgICAgICApO1xyXG4gICAgICB9XHJcbiAgICB9XHJcblxyXG4gICAgZm9yIChjb25zdCBqc1Jlc291cmNlIG9mIGluamVjdGVkSnMpIHtcclxuICAgICAgdHJ5IHtcclxuICAgICAgICBpbmplY3RlZFJlc291cmNlcy5wdXNoKGF3YWl0IHBhZ2UuYWRkU2NyaXB0VGFnKGpzUmVzb3VyY2UpKTtcclxuICAgICAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICAgICBsb2dXaXRoU3RhY2soMiwgZXJyb3IsIGBbYnJvd3Nlcl0gVGhlIEpTIHJlc291cmNlIGNhbm5vdCBiZSBsb2FkZWQuYCk7XHJcbiAgICAgIH1cclxuICAgIH1cclxuICAgIGluamVjdGVkSnMubGVuZ3RoID0gMDtcclxuXHJcbiAgICAvLyBMb2FkIENTU1xyXG4gICAgY29uc3QgaW5qZWN0ZWRDc3MgPSBbXTtcclxuICAgIGlmIChyZXNvdXJjZXMuY3NzKSB7XHJcbiAgICAgIGxldCBjc3NJbXBvcnRzID0gcmVzb3VyY2VzLmNzcy5tYXRjaCgvQGltcG9ydFxccyooW147XSopOy9nKTtcclxuICAgICAgaWYgKGNzc0ltcG9ydHMpIHtcclxuICAgICAgICAvLyBIYW5kbGUgY3NzIHNlY3Rpb25cclxuICAgICAgICBmb3IgKGxldCBjc3NJbXBvcnRQYXRoIG9mIGNzc0ltcG9ydHMpIHtcclxuICAgICAgICAgIGlmIChjc3NJbXBvcnRQYXRoKSB7XHJcbiAgICAgICAgICAgIGNzc0ltcG9ydFBhdGggPSBjc3NJbXBvcnRQYXRoXHJcbiAgICAgICAgICAgICAgLnJlcGxhY2UoJ3VybCgnLCAnJylcclxuICAgICAgICAgICAgICAucmVwbGFjZSgnQGltcG9ydCcsICcnKVxyXG4gICAgICAgICAgICAgIC5yZXBsYWNlKC9cIi9nLCAnJylcclxuICAgICAgICAgICAgICAucmVwbGFjZSgvJy9nLCAnJylcclxuICAgICAgICAgICAgICAucmVwbGFjZSgvOy8sICcnKVxyXG4gICAgICAgICAgICAgIC5yZXBsYWNlKC9cXCkvZywgJycpXHJcbiAgICAgICAgICAgICAgLnRyaW0oKTtcclxuXHJcbiAgICAgICAgICAgIC8vIEFkZCBlYWNoIGN1c3RvbSBjc3MgZnJvbSByZXNvdXJjZXNcclxuICAgICAgICAgICAgaWYgKGNzc0ltcG9ydFBhdGguc3RhcnRzV2l0aCgnaHR0cCcpKSB7XHJcbiAgICAgICAgICAgICAgaW5qZWN0ZWRDc3MucHVzaCh7XHJcbiAgICAgICAgICAgICAgICB1cmw6IGNzc0ltcG9ydFBhdGhcclxuICAgICAgICAgICAgICB9KTtcclxuICAgICAgICAgICAgfSBlbHNlIGlmIChjdXN0b21Mb2dpY09wdGlvbnMuYWxsb3dGaWxlUmVzb3VyY2VzKSB7XHJcbiAgICAgICAgICAgICAgaW5qZWN0ZWRDc3MucHVzaCh7XHJcbiAgICAgICAgICAgICAgICBwYXRoOiBqb2luKF9fZGlybmFtZSwgY3NzSW1wb3J0UGF0aClcclxuICAgICAgICAgICAgICB9KTtcclxuICAgICAgICAgICAgfVxyXG4gICAgICAgICAgfVxyXG4gICAgICAgIH1cclxuICAgICAgfVxyXG5cclxuICAgICAgLy8gVGhlIHJlc3Qgb2YgdGhlIENTUyBzZWN0aW9uIHdpbGwgYmUgY29udGVudCBieSBub3dcclxuICAgICAgaW5qZWN0ZWRDc3MucHVzaCh7XHJcbiAgICAgICAgY29udGVudDogcmVzb3VyY2VzLmNzcy5yZXBsYWNlKC9AaW1wb3J0XFxzKihbXjtdKik7L2csICcnKSB8fCAnICdcclxuICAgICAgfSk7XHJcblxyXG4gICAgICBmb3IgKGNvbnN0IGNzc1Jlc291cmNlIG9mIGluamVjdGVkQ3NzKSB7XHJcbiAgICAgICAgdHJ5IHtcclxuICAgICAgICAgIGluamVjdGVkUmVzb3VyY2VzLnB1c2goYXdhaXQgcGFnZS5hZGRTdHlsZVRhZyhjc3NSZXNvdXJjZSkpO1xyXG4gICAgICAgIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICAgICAgICBsb2dXaXRoU3RhY2soXHJcbiAgICAgICAgICAgIDIsXHJcbiAgICAgICAgICAgIGVycm9yLFxyXG4gICAgICAgICAgICBgW2Jyb3dzZXJdIFRoZSBDU1MgcmVzb3VyY2UgY2Fubm90IGJlIGxvYWRlZC5gXHJcbiAgICAgICAgICApO1xyXG4gICAgICAgIH1cclxuICAgICAgfVxyXG4gICAgICBpbmplY3RlZENzcy5sZW5ndGggPSAwO1xyXG4gICAgfVxyXG4gIH1cclxuICByZXR1cm4gaW5qZWN0ZWRSZXNvdXJjZXM7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBDbGVhcnMgb3V0IGFsbCBzdGF0ZSBzZXQgb24gdGhlIHBhZ2Ugd2l0aCBgYWRkU2NyaXB0VGFnYCBhbmQgYGFkZFN0eWxlVGFnYC5cclxuICogUmVtb3ZlcyBpbmplY3RlZCByZXNvdXJjZXMgYW5kIHJlc2V0cyBDU1MgYW5kIHNjcmlwdCB0YWdzIG9uIHRoZSBwYWdlLlxyXG4gKiBBZGRpdGlvbmFsbHksIGl0IGRlc3Ryb3lzIHByZXZpb3VzbHkgZXhpc3RpbmcgY2hhcnRzLlxyXG4gKlxyXG4gKiBAYXN5bmNcclxuICogQGZ1bmN0aW9uIGNsZWFyUGFnZVJlc291cmNlc1xyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gcGFnZSAtIFRoZSBQdXBwZXRlZXIgcGFnZSBvYmplY3QgZnJvbSB3aGljaCByZXNvdXJjZXMgd2lsbFxyXG4gKiBiZSBjbGVhcmVkLlxyXG4gKiBAcGFyYW0ge0FycmF5LjxPYmplY3Q+fSBpbmplY3RlZFJlc291cmNlcyAtIEFycmF5IG9mIGluamVjdGVkIHJlc291cmNlc1xyXG4gKiB0byBiZSBjbGVhcmVkLlxyXG4gKi9cclxuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIGNsZWFyUGFnZVJlc291cmNlcyhwYWdlLCBpbmplY3RlZFJlc291cmNlcykge1xyXG4gIHRyeSB7XHJcbiAgICBmb3IgKGNvbnN0IHJlc291cmNlIG9mIGluamVjdGVkUmVzb3VyY2VzKSB7XHJcbiAgICAgIGF3YWl0IHJlc291cmNlLmRpc3Bvc2UoKTtcclxuICAgIH1cclxuXHJcbiAgICAvLyBEZXN0cm95IG9sZCBjaGFydHMgYWZ0ZXIgZXhwb3J0IGlzIGRvbmUgYW5kIHJlc2V0IGFsbCBDU1MgYW5kIHNjcmlwdCB0YWdzXHJcbiAgICBhd2FpdCBwYWdlLmV2YWx1YXRlKCgpID0+IHtcclxuICAgICAgLy8gV2UgYXJlIG5vdCBndWFyYW50ZWVkIHRoYXQgSGlnaGNoYXJ0cyBpcyBsb2FkZWQsIHdoZW4gZG9pbmcgU1ZHIGV4cG9ydHNcclxuICAgICAgaWYgKHR5cGVvZiBIaWdoY2hhcnRzICE9PSAndW5kZWZpbmVkJykge1xyXG4gICAgICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBuby11bmRlZlxyXG4gICAgICAgIGNvbnN0IG9sZENoYXJ0cyA9IEhpZ2hjaGFydHMuY2hhcnRzO1xyXG5cclxuICAgICAgICAvLyBDaGVjayBpbiBhbnkgYWxyZWFkeSBleGlzdGluZyBjaGFydHNcclxuICAgICAgICBpZiAoQXJyYXkuaXNBcnJheShvbGRDaGFydHMpICYmIG9sZENoYXJ0cy5sZW5ndGgpIHtcclxuICAgICAgICAgIC8vIERlc3Ryb3kgb2xkIGNoYXJ0c1xyXG4gICAgICAgICAgZm9yIChjb25zdCBvbGRDaGFydCBvZiBvbGRDaGFydHMpIHtcclxuICAgICAgICAgICAgb2xkQ2hhcnQgJiYgb2xkQ2hhcnQuZGVzdHJveSgpO1xyXG4gICAgICAgICAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgbm8tdW5kZWZcclxuICAgICAgICAgICAgSGlnaGNoYXJ0cy5jaGFydHMuc2hpZnQoKTtcclxuICAgICAgICAgIH1cclxuICAgICAgICB9XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBuby11bmRlZlxyXG4gICAgICBjb25zdCBbLi4uc2NyaXB0c1RvUmVtb3ZlXSA9IGRvY3VtZW50LmdldEVsZW1lbnRzQnlUYWdOYW1lKCdzY3JpcHQnKTtcclxuICAgICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIG5vLXVuZGVmXHJcbiAgICAgIGNvbnN0IFssIC4uLnN0eWxlc1RvUmVtb3ZlXSA9IGRvY3VtZW50LmdldEVsZW1lbnRzQnlUYWdOYW1lKCdzdHlsZScpO1xyXG4gICAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgbm8tdW5kZWZcclxuICAgICAgY29uc3QgWy4uLmxpbmtzVG9SZW1vdmVdID0gZG9jdW1lbnQuZ2V0RWxlbWVudHNCeVRhZ05hbWUoJ2xpbmsnKTtcclxuXHJcbiAgICAgIC8vIFJlbW92ZSB0YWdzXHJcbiAgICAgIGZvciAoY29uc3QgZWxlbWVudCBvZiBbXHJcbiAgICAgICAgLi4uc2NyaXB0c1RvUmVtb3ZlLFxyXG4gICAgICAgIC4uLnN0eWxlc1RvUmVtb3ZlLFxyXG4gICAgICAgIC4uLmxpbmtzVG9SZW1vdmVcclxuICAgICAgXSkge1xyXG4gICAgICAgIGVsZW1lbnQucmVtb3ZlKCk7XHJcbiAgICAgIH1cclxuICAgIH0pO1xyXG4gIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICBsb2dXaXRoU3RhY2soMiwgZXJyb3IsIGBbYnJvd3Nlcl0gQ291bGQgbm90IGNsZWFyIHBhZ2UncyByZXNvdXJjZXMuYCk7XHJcbiAgfVxyXG59XHJcblxyXG4vKipcclxuICogU2V0cyB0aGUgY29udGVudCBmb3IgYSBQdXBwZXRlZXIgUGFnZSB1c2luZyBhIHByZWRlZmluZWQgdGVtcGxhdGVcclxuICogYW5kIGFkZGl0aW9uYWwgc2NyaXB0cy5cclxuICpcclxuICogQGFzeW5jXHJcbiAqIEBmdW5jdGlvbiBfc2V0UGFnZUNvbnRlbnRcclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IHBhZ2UgLSBUaGUgUHVwcGV0ZWVyIHBhZ2Ugb2JqZWN0IHRvIHdoaWNoIHRoZSBjb250ZW50XHJcbiAqIGlzIGJlaW5nIHNldC5cclxuICovXHJcbmFzeW5jIGZ1bmN0aW9uIF9zZXRQYWdlQ29udGVudChwYWdlKSB7XHJcbiAgLy8gU2V0IHRoZSBpbml0aWFsIHBhZ2UgY29udGVudFxyXG4gIGF3YWl0IHBhZ2Uuc2V0Q29udGVudCh0ZW1wbGF0ZSwgeyB3YWl0VW50aWw6ICdkb21jb250ZW50bG9hZGVkJyB9KTtcclxuXHJcbiAgLy8gQWRkIGFsbCByZWdpc3RlcmVkIEhpZ2NoYXJ0cyBzY3JpcHRzLCBxdWl0ZSBkZW1hbmRpbmdcclxuICBhd2FpdCBwYWdlLmFkZFNjcmlwdFRhZyh7IHBhdGg6IGpvaW4oZ2V0Q2FjaGVQYXRoKCksICdzb3VyY2VzLmpzJykgfSk7XHJcblxyXG4gIC8vIFNldCB0aGUgaW5pdGlhbCBgYW5pbU9iamVjdGAgZm9yIEhpZ2hjaGFydHNcclxuICBhd2FpdCBwYWdlLmV2YWx1YXRlKHNldHVwSGlnaGNoYXJ0cyk7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBTZXQgZXZlbnRzIChsaWtlIGBwYWdlZXJyb3JgIGFuZCBgY29uc29sZWApIGZvciBhIFB1cHBldGVlciBQYWdlIGluIG9yZGVyXHJcbiAqIHRvIGNhdGNoIGFuZCBkaXNwbGF5IGVycm9ycyBhbmQgY29uc29sZSBsb2dzIGZyb20gdGhlIHdpbmRvdyBjb250ZXh0LlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gX3NldFBhZ2VFdmVudHNcclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IHBhZ2UgLSBUaGUgUHVwcGV0ZWVyIHBhZ2Ugb2JqZWN0IHRvIHdoaWNoIHRoZSBsaXN0ZW5lcnNcclxuICogYXJlIGJlaW5nIHNldC5cclxuICovXHJcbmZ1bmN0aW9uIF9zZXRQYWdlRXZlbnRzKHBhZ2UpIHtcclxuICAvLyBHZXQgYGRlYnVnYCBvcHRpb25zXHJcbiAgY29uc3QgeyBkZWJ1ZyB9ID0gZ2V0T3B0aW9ucygpO1xyXG5cclxuICAvLyBTZXQgdGhlIGBwYWdlZXJyb3JgIGxpc3RlbmVyXHJcbiAgcGFnZS5vbigncGFnZWVycm9yJywgYXN5bmMgKCkgPT4ge1xyXG4gICAgLy8gSXQgd291bGQgc2VlbSBsaWtlIHRoaXMgbWF5IGZpcmUgYXQgdGhlIHNhbWUgdGltZSBvciBzaG9ydGx5IGJlZm9yZVxyXG4gICAgLy8gYSBwYWdlIGlzIGNsb3NlZC5cclxuICAgIGlmIChwYWdlLmlzQ2xvc2VkKCkpIHtcclxuICAgICAgcmV0dXJuO1xyXG4gICAgfVxyXG4gIH0pO1xyXG5cclxuICAvLyBTZXQgdGhlIGBjb25zb2xlYCBsaXN0ZW5lciwgaWYgbmVlZGVkXHJcbiAgaWYgKGRlYnVnLmVuYWJsZSAmJiBkZWJ1Zy5saXN0ZW5Ub0NvbnNvbGUpIHtcclxuICAgIHBhZ2Uub24oJ2NvbnNvbGUnLCAobWVzc2FnZSkgPT4ge1xyXG4gICAgICBjb25zb2xlLmxvZyhgW2RlYnVnXSAke21lc3NhZ2UudGV4dCgpfWApO1xyXG4gICAgfSk7XHJcbiAgfVxyXG59XHJcblxyXG5leHBvcnQgZGVmYXVsdCB7XHJcbiAgZ2V0QnJvd3NlcixcclxuICBjcmVhdGVCcm93c2VyLFxyXG4gIGNsb3NlQnJvd3NlcixcclxuICBuZXdQYWdlLFxyXG4gIGNsZWFyUGFnZSxcclxuICBhZGRQYWdlUmVzb3VyY2VzLFxyXG4gIGNsZWFyUGFnZVJlc291cmNlc1xyXG59O1xyXG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxyXG5cclxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXHJcblxyXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNSwgSGlnaHNvZnRcclxuXHJcbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cclxuXHJcbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxyXG5cclxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxyXG5cclxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cclxuXHJcbi8qKlxyXG4gKiBUaGUgQ1NTIHRvIGJlIHVzZWQgb24gdGhlIGV4cG9ydGVkIHBhZ2UuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtzdHJpbmd9IFRoZSBDU1MgY29uZmlndXJhdGlvbi5cclxuICovXHJcbmV4cG9ydCBkZWZhdWx0ICgpID0+IGBcclxuXHJcbmh0bWwsIGJvZHkge1xyXG4gIG1hcmdpbjogMDtcclxuICBwYWRkaW5nOiAwO1xyXG4gIGJveC1zaXppbmc6IGJvcmRlci1ib3g7XHJcbn1cclxuXHJcbiN0YWJsZS1kaXYsICNzbGlkZXJzLCAjZGF0YXRhYmxlLCAjY29udHJvbHMsIC5sZC1yb3cge1xyXG4gIGRpc3BsYXk6IG5vbmU7XHJcbiAgaGVpZ2h0OiAwO1xyXG59XHJcblxyXG4jY2hhcnQtY29udGFpbmVyIHtcclxuICBib3gtc2l6aW5nOiBib3JkZXItYm94O1xyXG4gIG1hcmdpbjogMDtcclxuICBvdmVyZmxvdzogYXV0bztcclxuICBmb250LXNpemU6IDA7XHJcbn1cclxuXHJcbiNjaGFydC1jb250YWluZXIgPiBmaWd1cmUsIGRpdiB7XHJcbiAgbWFyZ2luLXRvcDogMCAhaW1wb3J0YW50O1xyXG4gIG1hcmdpbi1ib3R0b206IDAgIWltcG9ydGFudDtcclxufVxyXG5cclxuYDtcclxuIiwiLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcclxuXHJcbkhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlclxyXG5cclxuQ29weXJpZ2h0IChjKSAyMDE2LTIwMjUsIEhpZ2hzb2Z0XHJcblxyXG5MaWNlbmNlZCB1bmRlciB0aGUgTUlUIGxpY2VuY2UuXHJcblxyXG5BZGRpdGlvbmFsbHkgYSB2YWxpZCBIaWdoY2hhcnRzIGxpY2Vuc2UgaXMgcmVxdWlyZWQgZm9yIHVzZS5cclxuXHJcblNlZSBMSUNFTlNFIGZpbGUgaW4gcm9vdCBmb3IgZGV0YWlscy5cclxuXHJcbioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXHJcblxyXG5pbXBvcnQgY3NzVGVtcGxhdGUgZnJvbSAnLi9jc3MuanMnO1xyXG5cclxuLyoqXHJcbiAqIFRoZSBTVkcgdGVtcGxhdGUgdG8gdXNlIHdoZW4gbG9hZGluZyBTVkcgY29udGVudCB0byBiZSBleHBvcnRlZC5cclxuICpcclxuICogQHBhcmFtIHtzdHJpbmd9IHN2ZyAtIFRoZSBTVkcgaW5wdXQgY29udGVudCB0byBiZSBleHBvcnRlZC5cclxuICpcclxuICogQHJldHVybnMge3N0cmluZ30gVGhlIFNWRyB0ZW1wbGF0ZS5cclxuICovXHJcbmV4cG9ydCBkZWZhdWx0IChzdmcpID0+IGBcclxuPCFET0NUWVBFIGh0bWw+XHJcbjxodG1sIGxhbmc9J2VuLVVTJz5cclxuICA8aGVhZD5cclxuICAgIDxtZXRhIGh0dHAtZXF1aXY9XCJDb250ZW50LVR5cGVcIiBjb250ZW50PVwidGV4dC9odG1sOyBjaGFyc2V0PXV0Zi04XCI+XHJcbiAgICA8dGl0bGU+SGlnaGNoYXJ0cyBFeHBvcnQ8L3RpdGxlPlxyXG4gIDwvaGVhZD5cclxuICA8c3R5bGU+XHJcbiAgICAke2Nzc1RlbXBsYXRlKCl9XHJcbiAgPC9zdHlsZT5cclxuICA8Ym9keT5cclxuICAgIDxkaXYgaWQ9XCJjaGFydC1jb250YWluZXJcIj5cclxuICAgICAgJHtzdmd9XHJcbiAgICA8L2Rpdj5cclxuICA8L2JvZHk+XHJcbjwvaHRtbD5cclxuXHJcbmA7XHJcbiIsIi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXHJcblxyXG5IaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXJcclxuXHJcbkNvcHlyaWdodCAoYykgMjAxNi0yMDI1LCBIaWdoc29mdFxyXG5cclxuTGljZW5jZWQgdW5kZXIgdGhlIE1JVCBsaWNlbmNlLlxyXG5cclxuQWRkaXRpb25hbGx5IGEgdmFsaWQgSGlnaGNoYXJ0cyBsaWNlbnNlIGlzIHJlcXVpcmVkIGZvciB1c2UuXHJcblxyXG5TZWUgTElDRU5TRSBmaWxlIGluIHJvb3QgZm9yIGRldGFpbHMuXHJcblxyXG4qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xyXG5cclxuLyoqXHJcbiAqIEBvdmVydmlldyBUaGlzIG1vZHVsZSBoYW5kbGVzIGNoYXJ0IGV4cG9ydCBmdW5jdGlvbmFsaXR5IHVzaW5nIFB1cHBldGVlci5cclxuICogSXQgc3VwcG9ydHMgZXhwb3J0aW5nIGNoYXJ0cyBhcyBTVkcsIFBORywgSlBFRywgYW5kIFBERiBmb3JtYXRzLiBUaGUgbW9kdWxlXHJcbiAqIG1hbmFnZXMgcGFnZSByZXNvdXJjZXMsIHNldHMgdXAgdGhlIGV4cG9ydCBlbnZpcm9ubWVudCwgYW5kIHByb2Nlc3NlcyBjaGFydFxyXG4gKiBjb25maWd1cmF0aW9ucyBvciBTVkcgaW5wdXRzIGZvciByZW5kZXJpbmcuIEV4cG9ydHMgdG8gYSBjaGFydCBmcm9tIGEgcGFnZVxyXG4gKiB1c2luZyBQdXBwZXRlZXIuXHJcbiAqL1xyXG5cclxuaW1wb3J0IHsgYWRkUGFnZVJlc291cmNlcywgY2xlYXJQYWdlUmVzb3VyY2VzIH0gZnJvbSAnLi9icm93c2VyLmpzJztcclxuaW1wb3J0IHsgY3JlYXRlQ2hhcnQgfSBmcm9tICcuL2hpZ2hjaGFydHMuanMnO1xyXG5pbXBvcnQgeyBsb2cgfSBmcm9tICcuL2xvZ2dlci5qcyc7XHJcblxyXG5pbXBvcnQgc3ZnVGVtcGxhdGUgZnJvbSAnLi4vdGVtcGxhdGVzL3N2Z0V4cG9ydC9zdmdFeHBvcnQuanMnO1xyXG5cclxuaW1wb3J0IEV4cG9ydEVycm9yIGZyb20gJy4vZXJyb3JzL0V4cG9ydEVycm9yLmpzJztcclxuXHJcbi8qKlxyXG4gKiBFeHBvcnRzIHRvIGEgY2hhcnQgZnJvbSBhIHBhZ2UgdXNpbmcgUHVwcGV0ZWVyLlxyXG4gKlxyXG4gKiBAYXN5bmNcclxuICogQGZ1bmN0aW9uIHB1cHBldGVlckV4cG9ydFxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gcGFnZSAtIFB1cHBldGVlciBwYWdlIG9iamVjdC5cclxuICogQHBhcmFtIHtPYmplY3R9IGV4cG9ydE9wdGlvbnMgLSBUaGUgY29uZmlndXJhdGlvbiBvYmplY3QgY29udGFpbmluZyBgZXhwb3J0YFxyXG4gKiBvcHRpb25zLlxyXG4gKiBAcGFyYW0ge09iamVjdH0gY3VzdG9tTG9naWNPcHRpb25zIC0gVGhlIGNvbmZpZ3VyYXRpb24gb2JqZWN0IGNvbnRhaW5pbmdcclxuICogYGN1c3RvbUxvZ2ljYCBvcHRpb25zLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7UHJvbWlzZTwoc3RyaW5nfEJ1ZmZlcnxFeHBvcnRFcnJvcik+fSBBIFByb21pc2UgdGhhdCByZXNvbHZlc1xyXG4gKiB0byB0aGUgZXhwb3J0ZWQgZGF0YSBvciByZWplY3Rpbmcgd2l0aCBhbiBgRXhwb3J0RXJyb3JgLlxyXG4gKlxyXG4gKiBAdGhyb3dzIHtFeHBvcnRFcnJvcn0gVGhyb3dzIGFuIGBFeHBvcnRFcnJvcmAgaWYgZXhwb3J0IHRvIGFuIHVuc3VwcG9ydGVkXHJcbiAqIG91dHB1dCBmb3JtYXQgb2NjdXJzLlxyXG4gKi9cclxuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIHB1cHBldGVlckV4cG9ydChwYWdlLCBleHBvcnRPcHRpb25zLCBjdXN0b21Mb2dpY09wdGlvbnMpIHtcclxuICAvLyBJbmplY3RlZCByZXNvdXJjZXMgYXJyYXkgKGFkZGl0aW9uYWwgSlMgYW5kIENTUylcclxuICBjb25zdCBpbmplY3RlZFJlc291cmNlcyA9IFtdO1xyXG5cclxuICB0cnkge1xyXG4gICAgbGV0IGlzU1ZHID0gZmFsc2U7XHJcblxyXG4gICAgLy8gRGVjaWRlIG9uIHRoZSBleHBvcnQgbWV0aG9kXHJcbiAgICBpZiAoZXhwb3J0T3B0aW9ucy5zdmcpIHtcclxuICAgICAgbG9nKDQsICdbZXhwb3J0XSBUcmVhdGluZyBhcyBTVkcgaW5wdXQuJyk7XHJcblxyXG4gICAgICAvLyBJZiB0aGUgYHR5cGVgIGlzIGFsc28gU1ZHLCByZXR1cm4gdGhlIGlucHV0XHJcbiAgICAgIGlmIChleHBvcnRPcHRpb25zLnR5cGUgPT09ICdzdmcnKSB7XHJcbiAgICAgICAgcmV0dXJuIGV4cG9ydE9wdGlvbnMuc3ZnO1xyXG4gICAgICB9XHJcblxyXG4gICAgICAvLyBNYXJrIGFzIFNWRyBleHBvcnQgZm9yIHRoZSBsYXRlciBzaXplIGNvcnJlY3Rpb25zXHJcbiAgICAgIGlzU1ZHID0gdHJ1ZTtcclxuXHJcbiAgICAgIC8vIFNWRyBleHBvcnRcclxuICAgICAgYXdhaXQgcGFnZS5zZXRDb250ZW50KHN2Z1RlbXBsYXRlKGV4cG9ydE9wdGlvbnMuc3ZnKSwge1xyXG4gICAgICAgIHdhaXRVbnRpbDogJ2RvbWNvbnRlbnRsb2FkZWQnXHJcbiAgICAgIH0pO1xyXG4gICAgfSBlbHNlIHtcclxuICAgICAgbG9nKDQsICdbZXhwb3J0XSBUcmVhdGluZyBhcyBKU09OIGNvbmZpZy4nKTtcclxuXHJcbiAgICAgIC8vIE9wdGlvbnMgZXhwb3J0XHJcbiAgICAgIGF3YWl0IHBhZ2UuZXZhbHVhdGUoY3JlYXRlQ2hhcnQsIGV4cG9ydE9wdGlvbnMsIGN1c3RvbUxvZ2ljT3B0aW9ucyk7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gS2VlcHMgdHJhY2sgb2YgYWxsIHJlc291cmNlcyBhZGRlZCBvbiB0aGUgcGFnZSB3aXRoIGFkZFhYWFRhZy4gZXRjXHJcbiAgICAvLyBJdCdzIFZJVEFMIHRoYXQgYWxsIGFkZGVkIHJlc291cmNlcyBlbmRzIHVwIGhlcmUgc28gd2UgY2FuIGNsZWFyIHRoaW5nc1xyXG4gICAgLy8gb3V0IHdoZW4gZG9pbmcgYSBuZXcgZXhwb3J0IGluIHRoZSBzYW1lIHBhZ2UhXHJcbiAgICBpbmplY3RlZFJlc291cmNlcy5wdXNoKFxyXG4gICAgICAuLi4oYXdhaXQgYWRkUGFnZVJlc291cmNlcyhwYWdlLCBjdXN0b21Mb2dpY09wdGlvbnMpKVxyXG4gICAgKTtcclxuXHJcbiAgICAvLyBHZXQgdGhlIHJlYWwgY2hhcnQgc2l6ZSBhbmQgc2V0IHRoZSB6b29tIGFjY29yZGluZ2x5XHJcbiAgICBjb25zdCBzaXplID0gaXNTVkdcclxuICAgICAgPyBhd2FpdCBwYWdlLmV2YWx1YXRlKChzY2FsZSkgPT4ge1xyXG4gICAgICAgICAgY29uc3Qgc3ZnRWxlbWVudCA9IGRvY3VtZW50LnF1ZXJ5U2VsZWN0b3IoXHJcbiAgICAgICAgICAgICcjY2hhcnQtY29udGFpbmVyIHN2ZzpmaXJzdC1vZi10eXBlJ1xyXG4gICAgICAgICAgKTtcclxuXHJcbiAgICAgICAgICAvLyBHZXQgdGhlIHZhbHVlcyBjb3JyZWN0bHkgc2NhbGVkXHJcbiAgICAgICAgICBjb25zdCBjaGFydEhlaWdodCA9IHN2Z0VsZW1lbnQuaGVpZ2h0LmJhc2VWYWwudmFsdWUgKiBzY2FsZTtcclxuICAgICAgICAgIGNvbnN0IGNoYXJ0V2lkdGggPSBzdmdFbGVtZW50LndpZHRoLmJhc2VWYWwudmFsdWUgKiBzY2FsZTtcclxuXHJcbiAgICAgICAgICAvLyBJbiBjYXNlIG9mIFNWRyB0aGUgem9vbSBtdXN0IGJlIHNldCBkaXJlY3RseSBmb3IgYm9keSBhcyBzY2FsZVxyXG4gICAgICAgICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIG5vLXVuZGVmXHJcbiAgICAgICAgICBkb2N1bWVudC5ib2R5LnN0eWxlLnpvb20gPSBzY2FsZTtcclxuXHJcbiAgICAgICAgICAvLyBTZXQgdGhlIG1hcmdpbiB0byAwcHhcclxuICAgICAgICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBuby11bmRlZlxyXG4gICAgICAgICAgZG9jdW1lbnQuYm9keS5zdHlsZS5tYXJnaW4gPSAnMHB4JztcclxuXHJcbiAgICAgICAgICByZXR1cm4ge1xyXG4gICAgICAgICAgICBjaGFydEhlaWdodCxcclxuICAgICAgICAgICAgY2hhcnRXaWR0aFxyXG4gICAgICAgICAgfTtcclxuICAgICAgICB9LCBwYXJzZUZsb2F0KGV4cG9ydE9wdGlvbnMuc2NhbGUpKVxyXG4gICAgICA6IGF3YWl0IHBhZ2UuZXZhbHVhdGUoKCkgPT4ge1xyXG4gICAgICAgICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIG5vLXVuZGVmXHJcbiAgICAgICAgICBjb25zdCB7IGNoYXJ0SGVpZ2h0LCBjaGFydFdpZHRoIH0gPSB3aW5kb3cuSGlnaGNoYXJ0cy5jaGFydHNbMF07XHJcblxyXG4gICAgICAgICAgLy8gTm8gbmVlZCBmb3Igc3VjaCBzY2FsZSBtYW5pcHVsYXRpb24gaW4gY2FzZSBvZiBvdGhlciB0eXBlc1xyXG4gICAgICAgICAgLy8gb2YgZXhwb3J0cy4gUmVzZXQgdGhlIHpvb20gZm9yIG90aGVyIGV4cG9ydHMgdGhhbiB0byBTVkdzXHJcbiAgICAgICAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgbm8tdW5kZWZcclxuICAgICAgICAgIGRvY3VtZW50LmJvZHkuc3R5bGUuem9vbSA9IDE7XHJcblxyXG4gICAgICAgICAgcmV0dXJuIHtcclxuICAgICAgICAgICAgY2hhcnRIZWlnaHQsXHJcbiAgICAgICAgICAgIGNoYXJ0V2lkdGhcclxuICAgICAgICAgIH07XHJcbiAgICAgICAgfSk7XHJcblxyXG4gICAgLy8gR2V0IHRoZSBjbGlwIHJlZ2lvbiBmb3IgdGhlIHBhZ2VcclxuICAgIGNvbnN0IHsgeCwgeSB9ID0gYXdhaXQgX2dldENsaXBSZWdpb24ocGFnZSk7XHJcblxyXG4gICAgLy8gU2V0IGZpbmFsIGBoZWlnaHRgIGZvciB2aWV3cG9ydFxyXG4gICAgY29uc3Qgdmlld3BvcnRIZWlnaHQgPSBNYXRoLmFicyhcclxuICAgICAgTWF0aC5jZWlsKHNpemUuY2hhcnRIZWlnaHQgfHwgZXhwb3J0T3B0aW9ucy5oZWlnaHQpXHJcbiAgICApO1xyXG5cclxuICAgIC8vIFNldCBmaW5hbCBgd2lkdGhgIGZvciB2aWV3cG9ydFxyXG4gICAgY29uc3Qgdmlld3BvcnRXaWR0aCA9IE1hdGguYWJzKFxyXG4gICAgICBNYXRoLmNlaWwoc2l6ZS5jaGFydFdpZHRoIHx8IGV4cG9ydE9wdGlvbnMud2lkdGgpXHJcbiAgICApO1xyXG5cclxuICAgIC8vIFNldCB0aGUgZmluYWwgdmlld3BvcnQgbm93IHRoYXQgd2UgaGF2ZSB0aGUgcmVhbCBoZWlnaHRcclxuICAgIGF3YWl0IHBhZ2Uuc2V0Vmlld3BvcnQoe1xyXG4gICAgICBoZWlnaHQ6IHZpZXdwb3J0SGVpZ2h0LFxyXG4gICAgICB3aWR0aDogdmlld3BvcnRXaWR0aCxcclxuICAgICAgZGV2aWNlU2NhbGVGYWN0b3I6IGlzU1ZHID8gMSA6IHBhcnNlRmxvYXQoZXhwb3J0T3B0aW9ucy5zY2FsZSlcclxuICAgIH0pO1xyXG5cclxuICAgIGxldCByZXN1bHQ7XHJcbiAgICAvLyBSYXN0ZXJpemF0aW9uIHByb2Nlc3NcclxuICAgIHN3aXRjaCAoZXhwb3J0T3B0aW9ucy50eXBlKSB7XHJcbiAgICAgIGNhc2UgJ3N2Zyc6XHJcbiAgICAgICAgcmVzdWx0ID0gYXdhaXQgX2NyZWF0ZVNWRyhwYWdlKTtcclxuICAgICAgICBicmVhaztcclxuICAgICAgY2FzZSAncG5nJzpcclxuICAgICAgY2FzZSAnanBlZyc6XHJcbiAgICAgICAgcmVzdWx0ID0gYXdhaXQgX2NyZWF0ZUltYWdlKFxyXG4gICAgICAgICAgcGFnZSxcclxuICAgICAgICAgIGV4cG9ydE9wdGlvbnMudHlwZSxcclxuICAgICAgICAgIHtcclxuICAgICAgICAgICAgd2lkdGg6IHZpZXdwb3J0V2lkdGgsXHJcbiAgICAgICAgICAgIGhlaWdodDogdmlld3BvcnRIZWlnaHQsXHJcbiAgICAgICAgICAgIHgsXHJcbiAgICAgICAgICAgIHlcclxuICAgICAgICAgIH0sXHJcbiAgICAgICAgICBleHBvcnRPcHRpb25zLnJhc3Rlcml6YXRpb25UaW1lb3V0XHJcbiAgICAgICAgKTtcclxuICAgICAgICBicmVhaztcclxuICAgICAgY2FzZSAncGRmJzpcclxuICAgICAgICByZXN1bHQgPSBhd2FpdCBfY3JlYXRlUERGKFxyXG4gICAgICAgICAgcGFnZSxcclxuICAgICAgICAgIHZpZXdwb3J0SGVpZ2h0LFxyXG4gICAgICAgICAgdmlld3BvcnRXaWR0aCxcclxuICAgICAgICAgIGV4cG9ydE9wdGlvbnMucmFzdGVyaXphdGlvblRpbWVvdXRcclxuICAgICAgICApO1xyXG4gICAgICAgIGJyZWFrO1xyXG4gICAgICBkZWZhdWx0OlxyXG4gICAgICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcihcclxuICAgICAgICAgIGBbZXhwb3J0XSBVbnN1cHBvcnRlZCBvdXRwdXQgZm9ybWF0OiAke2V4cG9ydE9wdGlvbnMudHlwZX0uYCxcclxuICAgICAgICAgIDQwMFxyXG4gICAgICAgICk7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gQ2xlYXIgcHJldmlvdXNseSBpbmplY3RlZCBKUyBhbmQgQ1NTIHJlc291cmNlc1xyXG4gICAgYXdhaXQgY2xlYXJQYWdlUmVzb3VyY2VzKHBhZ2UsIGluamVjdGVkUmVzb3VyY2VzKTtcclxuICAgIHJldHVybiByZXN1bHQ7XHJcbiAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgIGF3YWl0IGNsZWFyUGFnZVJlc291cmNlcyhwYWdlLCBpbmplY3RlZFJlc291cmNlcyk7XHJcbiAgICByZXR1cm4gZXJyb3I7XHJcbiAgfVxyXG59XHJcblxyXG4vKipcclxuICogUmV0cmlldmVzIHRoZSBjbGlwcGluZyByZWdpb24gY29vcmRpbmF0ZXMgb2YgdGhlIHNwZWNpZmllZCBwYWdlIGVsZW1lbnRcclxuICogd2l0aCB0aGUgJ2NoYXJ0LWNvbnRhaW5lcicgaWQuXHJcbiAqXHJcbiAqIEBhc3luY1xyXG4gKiBAZnVuY3Rpb24gX2dldENsaXBSZWdpb25cclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IHBhZ2UgLSBQdXBwZXRlZXIgcGFnZSBvYmplY3QuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtQcm9taXNlPE9iamVjdD59IEEgUHJvbWlzZSB0aGF0IHJlc29sdmVzIHRvIGFuIG9iamVjdCBjb250YWluaW5nXHJcbiAqIGB4YCwgYHlgLCBgd2lkdGhgLCBhbmQgYGhlaWdodGAgcHJvcGVydGllcy5cclxuICovXHJcbmFzeW5jIGZ1bmN0aW9uIF9nZXRDbGlwUmVnaW9uKHBhZ2UpIHtcclxuICByZXR1cm4gcGFnZS4kZXZhbCgnI2NoYXJ0LWNvbnRhaW5lcicsIChlbGVtZW50KSA9PiB7XHJcbiAgICBjb25zdCB7IHgsIHksIHdpZHRoLCBoZWlnaHQgfSA9IGVsZW1lbnQuZ2V0Qm91bmRpbmdDbGllbnRSZWN0KCk7XHJcbiAgICByZXR1cm4ge1xyXG4gICAgICB4LFxyXG4gICAgICB5LFxyXG4gICAgICB3aWR0aCxcclxuICAgICAgaGVpZ2h0OiBNYXRoLnRydW5jKGhlaWdodCA+IDEgPyBoZWlnaHQgOiA1MDApXHJcbiAgICB9O1xyXG4gIH0pO1xyXG59XHJcblxyXG4vKipcclxuICogQ3JlYXRlcyBhbiBTVkcgYnkgZXZhbHVhdGluZyB0aGUgYG91dGVySFRNTGAgb2YgdGhlIGZpcnN0ICdzdmcnIGVsZW1lbnRcclxuICogaW5zaWRlIGFuIGVsZW1lbnQgd2l0aCB0aGUgaWQgJ2NvbnRhaW5lcicuXHJcbiAqXHJcbiAqIEBhc3luY1xyXG4gKiBAZnVuY3Rpb24gX2NyZWF0ZVNWR1xyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gcGFnZSAtIFB1cHBldGVlciBwYWdlIG9iamVjdC5cclxuICpcclxuICogQHJldHVybnMge1Byb21pc2U8c3RyaW5nPn0gQSBQcm9taXNlIHRoYXQgcmVzb2x2ZXMgdG8gdGhlIFNWRyBzdHJpbmcuXHJcbiAqL1xyXG5hc3luYyBmdW5jdGlvbiBfY3JlYXRlU1ZHKHBhZ2UpIHtcclxuICByZXR1cm4gcGFnZS4kZXZhbChcclxuICAgICcjY29udGFpbmVyIHN2ZzpmaXJzdC1vZi10eXBlJyxcclxuICAgIChlbGVtZW50KSA9PiBlbGVtZW50Lm91dGVySFRNTFxyXG4gICk7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBDcmVhdGVzIGFuIGltYWdlIHVzaW5nIFB1cHBldGVlcidzIHBhZ2UgYHNjcmVlbnNob3RgIGZ1bmN0aW9uYWxpdHkgd2l0aFxyXG4gKiBzcGVjaWZpZWQgb3B0aW9ucy5cclxuICpcclxuICogQGFzeW5jXHJcbiAqIEBmdW5jdGlvbiBfY3JlYXRlSW1hZ2VcclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IHBhZ2UgLSBQdXBwZXRlZXIgcGFnZSBvYmplY3QuXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSB0eXBlIC0gSW1hZ2UgdHlwZS5cclxuICogQHBhcmFtIHtPYmplY3R9IGNsaXAgLSBDbGlwcGluZyByZWdpb24gY29vcmRpbmF0ZXMuXHJcbiAqIEBwYXJhbSB7bnVtYmVyfSByYXN0ZXJpemF0aW9uVGltZW91dCAtIFRpbWVvdXQgZm9yIHJhc3Rlcml6YXRpb25cclxuICogaW4gbWlsbGlzZWNvbmRzLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7UHJvbWlzZTxCdWZmZXI+fSBBIFByb21pc2UgdGhhdCByZXNvbHZlcyB0byB0aGUgaW1hZ2UgYnVmZmVyXHJcbiAqIG9yIHJlamVjdGluZyB3aXRoIGFuIGBFeHBvcnRFcnJvcmAgZm9yIHRpbWVvdXQuXHJcbiAqL1xyXG5hc3luYyBmdW5jdGlvbiBfY3JlYXRlSW1hZ2UocGFnZSwgdHlwZSwgY2xpcCwgcmFzdGVyaXphdGlvblRpbWVvdXQpIHtcclxuICByZXR1cm4gUHJvbWlzZS5yYWNlKFtcclxuICAgIHBhZ2Uuc2NyZWVuc2hvdCh7XHJcbiAgICAgIHR5cGUsXHJcbiAgICAgIGNsaXAsXHJcbiAgICAgIGVuY29kaW5nOiAnYmFzZTY0JyxcclxuICAgICAgZnVsbFBhZ2U6IGZhbHNlLFxyXG4gICAgICBvcHRpbWl6ZUZvclNwZWVkOiB0cnVlLFxyXG4gICAgICBjYXB0dXJlQmV5b25kVmlld3BvcnQ6IHRydWUsXHJcbiAgICAgIC4uLih0eXBlICE9PSAncG5nJyA/IHsgcXVhbGl0eTogODAgfSA6IHt9KSxcclxuICAgICAgLy8gQWx3YXlzIHJlbmRlciBvbiBhIHRyYW5zcGFyZW50IHBhZ2UgaWYgdGhlIGV4cGVjdGVkIHR5cGUgZm9ybWF0IGlzIFBOR1xyXG4gICAgICBvbWl0QmFja2dyb3VuZDogdHlwZSA9PSAncG5nJyAvLyAjNDQ3LCAjNDYzXHJcbiAgICB9KSxcclxuICAgIG5ldyBQcm9taXNlKChfcmVzb2x2ZSwgcmVqZWN0KSA9PlxyXG4gICAgICBzZXRUaW1lb3V0KFxyXG4gICAgICAgICgpID0+IHJlamVjdChuZXcgRXhwb3J0RXJyb3IoJ1Jhc3Rlcml6YXRpb24gdGltZW91dCcsIDQwOCkpLFxyXG4gICAgICAgIHJhc3Rlcml6YXRpb25UaW1lb3V0IHx8IDE1MDBcclxuICAgICAgKVxyXG4gICAgKVxyXG4gIF0pO1xyXG59XHJcblxyXG4vKipcclxuICogQ3JlYXRlcyBhIFBERiB1c2luZyBQdXBwZXRlZXIncyBwYWdlIGBwZGZgIGZ1bmN0aW9uYWxpdHkgd2l0aCBzcGVjaWZpZWRcclxuICogb3B0aW9ucy5cclxuICpcclxuICogQGFzeW5jXHJcbiAqIEBmdW5jdGlvbiBfY3JlYXRlUERGXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBwYWdlIC0gUHVwcGV0ZWVyIHBhZ2Ugb2JqZWN0LlxyXG4gKiBAcGFyYW0ge251bWJlcn0gaGVpZ2h0IC0gUERGIGhlaWdodC5cclxuICogQHBhcmFtIHtudW1iZXJ9IHdpZHRoIC0gUERGIHdpZHRoLlxyXG4gKiBAcGFyYW0ge251bWJlcn0gcmFzdGVyaXphdGlvblRpbWVvdXQgLSBUaW1lb3V0IGZvciByYXN0ZXJpemF0aW9uXHJcbiAqIGluIG1pbGxpc2Vjb25kcy5cclxuICpcclxuICogQHJldHVybnMge1Byb21pc2U8QnVmZmVyPn0gQSBQcm9taXNlIHRoYXQgcmVzb2x2ZXMgdG8gdGhlIFBERiBidWZmZXIuXHJcbiAqL1xyXG5hc3luYyBmdW5jdGlvbiBfY3JlYXRlUERGKHBhZ2UsIGhlaWdodCwgd2lkdGgsIHJhc3Rlcml6YXRpb25UaW1lb3V0KSB7XHJcbiAgYXdhaXQgcGFnZS5lbXVsYXRlTWVkaWFUeXBlKCdzY3JlZW4nKTtcclxuICByZXR1cm4gcGFnZS5wZGYoe1xyXG4gICAgLy8gVGhpcyB3aWxsIHJlbW92ZSBhbiBleHRyYSBlbXB0eSBwYWdlIGluIFBERiBleHBvcnRzXHJcbiAgICBoZWlnaHQ6IGhlaWdodCArIDEsXHJcbiAgICB3aWR0aCxcclxuICAgIGVuY29kaW5nOiAnYmFzZTY0JyxcclxuICAgIHRpbWVvdXQ6IHJhc3Rlcml6YXRpb25UaW1lb3V0IHx8IDE1MDBcclxuICB9KTtcclxufVxyXG5cclxuZXhwb3J0IGRlZmF1bHQge1xyXG4gIHB1cHBldGVlckV4cG9ydFxyXG59O1xyXG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxyXG5cclxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXHJcblxyXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNSwgSGlnaHNvZnRcclxuXHJcbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cclxuXHJcbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxyXG5cclxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxyXG5cclxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cclxuXHJcbi8qKlxyXG4gKiBAb3ZlcnZpZXcgVGhpcyBtb2R1bGUgcHJvdmlkZXMgYSB3b3JrZXIgcG9vbCBpbXBsZW1lbnRhdGlvbiBmb3IgbWFuYWdpbmdcclxuICogdGhlIGJyb3dzZXIgaW5zdGFuY2UgYW5kIHBhZ2VzLCBzcGVjaWZpY2FsbHkgZGVzaWduZWQgZm9yIHVzZSB3aXRoXHJcbiAqIHRoZSBIaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXIuIEl0IG9wdGltaXplcyByZXNvdXJjZXMgdXNhZ2UgYW5kIHBlcmZvcm1hbmNlXHJcbiAqIGJ5IG1haW50YWluaW5nIGEgcG9vbCBvZiB3b3JrZXJzIHRoYXQgY2FuIGhhbmRsZSBjb25jdXJyZW50IGV4cG9ydCB0YXNrc1xyXG4gKiB1c2luZyBQdXBwZXRlZXIuXHJcbiAqL1xyXG5cclxuaW1wb3J0IHsgUG9vbCB9IGZyb20gJ3Rhcm4nO1xyXG5pbXBvcnQgeyB2NCBhcyB1dWlkIH0gZnJvbSAndXVpZCc7XHJcblxyXG5pbXBvcnQgeyBjcmVhdGVCcm93c2VyLCBjbG9zZUJyb3dzZXIsIG5ld1BhZ2UsIGNsZWFyUGFnZSB9IGZyb20gJy4vYnJvd3Nlci5qcyc7XHJcbmltcG9ydCB7IHB1cHBldGVlckV4cG9ydCB9IGZyb20gJy4vZXhwb3J0LmpzJztcclxuaW1wb3J0IHsgbG9nLCBsb2dXaXRoU3RhY2sgfSBmcm9tICcuL2xvZ2dlci5qcyc7XHJcbmltcG9ydCB7IGdldE5ld0RhdGVUaW1lLCBtZWFzdXJlVGltZSB9IGZyb20gJy4vdXRpbHMuanMnO1xyXG5cclxuaW1wb3J0IEV4cG9ydEVycm9yIGZyb20gJy4vZXJyb3JzL0V4cG9ydEVycm9yLmpzJztcclxuXHJcbi8vIFRoZSBwb29sIGluc3RhbmNlXHJcbmxldCBwb29sID0gbnVsbDtcclxuXHJcbi8vIFBvb2wgc3RhdGlzdGljc1xyXG5jb25zdCBwb29sU3RhdHMgPSB7XHJcbiAgZXhwb3J0c0F0dGVtcHRlZDogMCxcclxuICBleHBvcnRzUGVyZm9ybWVkOiAwLFxyXG4gIGV4cG9ydHNEcm9wcGVkOiAwLFxyXG4gIGV4cG9ydHNGcm9tU3ZnOiAwLFxyXG4gIGV4cG9ydHNGcm9tT3B0aW9uczogMCxcclxuICBleHBvcnRzRnJvbVN2Z0F0dGVtcHRzOiAwLFxyXG4gIGV4cG9ydHNGcm9tT3B0aW9uc0F0dGVtcHRzOiAwLFxyXG4gIHRpbWVTcGVudDogMCxcclxuICB0aW1lU3BlbnRBdmVyYWdlOiAwXHJcbn07XHJcblxyXG4vKipcclxuICogSW5pdGlhbGl6ZXMgdGhlIGV4cG9ydCBwb29sIHdpdGggdGhlIHByb3ZpZGVkIGNvbmZpZ3VyYXRpb24sIGNyZWF0aW5nXHJcbiAqIGEgYnJvd3NlciBpbnN0YW5jZSBhbmQgc2V0dGluZyB1cCB3b3JrZXIgcmVzb3VyY2VzLlxyXG4gKlxyXG4gKiBAYXN5bmNcclxuICogQGZ1bmN0aW9uIGluaXRQb29sXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBwb29sT3B0aW9ucyAtIFRoZSBjb25maWd1cmF0aW9uIG9iamVjdCBjb250YWluaW5nIGBwb29sYFxyXG4gKiBvcHRpb25zLlxyXG4gKiBAcGFyYW0ge0FycmF5LjxzdHJpbmc+fSBwdXBwZXRlZXJBcmdzIC0gQWRkaXRpb25hbCBhcmd1bWVudHMgZm9yIFB1cHBldGVlclxyXG4gKiBsYXVuY2guXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtQcm9taXNlPHZvaWQ+fSBBIFByb21pc2UgdGhhdCByZXNvbHZlcyB0byBlbmRpbmcgdGhlIGZ1bmN0aW9uXHJcbiAqIGV4ZWN1dGlvbiB3aGVuIGFuIGFscmVhZHkgaW5pdGlhbGl6ZWQgcG9vbCBvZiByZXNvdXJjZXMgaXMgZm91bmQuXHJcbiAqXHJcbiAqIEB0aHJvd3Mge0V4cG9ydEVycm9yfSBUaHJvd3MgYW4gYEV4cG9ydEVycm9yYCBpZiBjb3VsZCBub3QgY3JlYXRlIHRoZSBwb29sXHJcbiAqIG9mIHdvcmtlcnMuXHJcbiAqL1xyXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gaW5pdFBvb2wocG9vbE9wdGlvbnMsIHB1cHBldGVlckFyZ3MpIHtcclxuICAvLyBDcmVhdGUgYSBicm93c2VyIGluc3RhbmNlIHdpdGggdGhlIHB1cHBldGVlciBhcmd1bWVudHNcclxuICBhd2FpdCBjcmVhdGVCcm93c2VyKHB1cHBldGVlckFyZ3MpO1xyXG5cclxuICB0cnkge1xyXG4gICAgbG9nKFxyXG4gICAgICAzLFxyXG4gICAgICBgW3Bvb2xdIEluaXRpYWxpemluZyBwb29sIHdpdGggd29ya2VyczogbWluICR7cG9vbE9wdGlvbnMubWluV29ya2Vyc30sIG1heCAke3Bvb2xPcHRpb25zLm1heFdvcmtlcnN9LmBcclxuICAgICk7XHJcblxyXG4gICAgaWYgKHBvb2wpIHtcclxuICAgICAgbG9nKFxyXG4gICAgICAgIDQsXHJcbiAgICAgICAgJ1twb29sXSBBbHJlYWR5IGluaXRpYWxpemVkLCBwbGVhc2Uga2lsbCBpdCBiZWZvcmUgY3JlYXRpbmcgYSBuZXcgb25lLidcclxuICAgICAgKTtcclxuICAgICAgcmV0dXJuO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIEtlZXAgYW4gZXllIG9uIGEgY29ycmVjdCBtaW4gYW5kIG1heCB3b3JrZXJzIG51bWJlclxyXG4gICAgaWYgKHBvb2xPcHRpb25zLm1pbldvcmtlcnMgPiBwb29sT3B0aW9ucy5tYXhXb3JrZXJzKSB7XHJcbiAgICAgIHBvb2xPcHRpb25zLm1pbldvcmtlcnMgPSBwb29sT3B0aW9ucy5tYXhXb3JrZXJzO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIENyZWF0ZSBhIHBvb2wgYWxvbmcgd2l0aCBhIG1pbmltYWwgbnVtYmVyIG9mIHJlc291cmNlc1xyXG4gICAgcG9vbCA9IG5ldyBQb29sKHtcclxuICAgICAgLy8gR2V0IHRoZSBgY3JlYXRlYCwgYHZhbGlkYXRlYCwgYW5kIGBkZXN0cm95YCBmdW5jdGlvbnNcclxuICAgICAgLi4uX2ZhY3RvcnkocG9vbE9wdGlvbnMpLFxyXG4gICAgICBtaW46IHBvb2xPcHRpb25zLm1pbldvcmtlcnMsXHJcbiAgICAgIG1heDogcG9vbE9wdGlvbnMubWF4V29ya2VycyxcclxuICAgICAgYWNxdWlyZVRpbWVvdXRNaWxsaXM6IHBvb2xPcHRpb25zLmFjcXVpcmVUaW1lb3V0LFxyXG4gICAgICBjcmVhdGVUaW1lb3V0TWlsbGlzOiBwb29sT3B0aW9ucy5jcmVhdGVUaW1lb3V0LFxyXG4gICAgICBkZXN0cm95VGltZW91dE1pbGxpczogcG9vbE9wdGlvbnMuZGVzdHJveVRpbWVvdXQsXHJcbiAgICAgIGlkbGVUaW1lb3V0TWlsbGlzOiBwb29sT3B0aW9ucy5pZGxlVGltZW91dCxcclxuICAgICAgY3JlYXRlUmV0cnlJbnRlcnZhbE1pbGxpczogcG9vbE9wdGlvbnMuY3JlYXRlUmV0cnlJbnRlcnZhbCxcclxuICAgICAgcmVhcEludGVydmFsTWlsbGlzOiBwb29sT3B0aW9ucy5yZWFwZXJJbnRlcnZhbCxcclxuICAgICAgcHJvcGFnYXRlQ3JlYXRlRXJyb3I6IGZhbHNlXHJcbiAgICB9KTtcclxuXHJcbiAgICAvLyBTZXQgZXZlbnRzXHJcbiAgICBwb29sLm9uKCdyZWxlYXNlJywgYXN5bmMgKHJlc291cmNlKSA9PiB7XHJcbiAgICAgIC8vIENsZWFyIHBhZ2VcclxuICAgICAgY29uc3QgY2xlYXJTdGF0dXMgPSBhd2FpdCBjbGVhclBhZ2UocmVzb3VyY2UsIGZhbHNlKTtcclxuICAgICAgbG9nKFxyXG4gICAgICAgIDQsXHJcbiAgICAgICAgYFtwb29sXSBQb29sIHJlc291cmNlIFske3Jlc291cmNlLmlkfV0gLSBSZWxlYXNpbmcgYSB3b3JrZXIuIENsZWFyIHBhZ2Ugc3RhdHVzOiAke2NsZWFyU3RhdHVzfS5gXHJcbiAgICAgICk7XHJcbiAgICB9KTtcclxuXHJcbiAgICBwb29sLm9uKCdkZXN0cm95U3VjY2VzcycsIChfZXZlbnRJZCwgcmVzb3VyY2UpID0+IHtcclxuICAgICAgbG9nKFxyXG4gICAgICAgIDQsXHJcbiAgICAgICAgYFtwb29sXSBQb29sIHJlc291cmNlIFske3Jlc291cmNlLmlkfV0gLSBEZXN0cm95ZWQgYSB3b3JrZXIgc3VjY2Vzc2Z1bGx5LmBcclxuICAgICAgKTtcclxuICAgICAgcmVzb3VyY2UucGFnZSA9IG51bGw7XHJcbiAgICB9KTtcclxuXHJcbiAgICBjb25zdCBpbml0aWFsUmVzb3VyY2VzID0gW107XHJcbiAgICAvLyBDcmVhdGUgYW4gaW5pdGlhbCBudW1iZXIgb2YgcmVzb3VyY2VzXHJcbiAgICBmb3IgKGxldCBpID0gMDsgaSA8IHBvb2xPcHRpb25zLm1pbldvcmtlcnM7IGkrKykge1xyXG4gICAgICB0cnkge1xyXG4gICAgICAgIGNvbnN0IHJlc291cmNlID0gYXdhaXQgcG9vbC5hY3F1aXJlKCkucHJvbWlzZTtcclxuICAgICAgICBpbml0aWFsUmVzb3VyY2VzLnB1c2gocmVzb3VyY2UpO1xyXG4gICAgICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgICAgIGxvZ1dpdGhTdGFjaygyLCBlcnJvciwgJ1twb29sXSBDb3VsZCBub3QgY3JlYXRlIGFuIGluaXRpYWwgcmVzb3VyY2UuJyk7XHJcbiAgICAgIH1cclxuICAgIH1cclxuXHJcbiAgICAvLyBSZWxlYXNlIHRoZSBpbml0aWFsIG51bWJlciBvZiByZXNvdXJjZXMgYmFjayB0byB0aGUgcG9vbFxyXG4gICAgaW5pdGlhbFJlc291cmNlcy5mb3JFYWNoKChyZXNvdXJjZSkgPT4ge1xyXG4gICAgICBwb29sLnJlbGVhc2UocmVzb3VyY2UpO1xyXG4gICAgfSk7XHJcblxyXG4gICAgbG9nKFxyXG4gICAgICAzLFxyXG4gICAgICBgW3Bvb2xdIFRoZSBwb29sIGlzIHJlYWR5JHtpbml0aWFsUmVzb3VyY2VzLmxlbmd0aCA/IGAgd2l0aCAke2luaXRpYWxSZXNvdXJjZXMubGVuZ3RofSBpbml0aWFsIHJlc291cmNlcyB3YWl0aW5nLmAgOiAnLid9YFxyXG4gICAgKTtcclxuICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgdGhyb3cgbmV3IEV4cG9ydEVycm9yKFxyXG4gICAgICAnW3Bvb2xdIENvdWxkIG5vdCBjb25maWd1cmUgYW5kIGNyZWF0ZSB0aGUgcG9vbCBvZiB3b3JrZXJzLicsXHJcbiAgICAgIDUwMFxyXG4gICAgKS5zZXRFcnJvcihlcnJvcik7XHJcbiAgfVxyXG59XHJcblxyXG4vKipcclxuICogVGVybWluYXRlcyBhbGwgd29ya2VycyBpbiB0aGUgcG9vbCwgZGVzdHJveXMgdGhlIHBvb2wsIGFuZCBjbG9zZXMgdGhlIGJyb3dzZXJcclxuICogaW5zdGFuY2UuXHJcbiAqXHJcbiAqIEBhc3luY1xyXG4gKiBAZnVuY3Rpb24ga2lsbFBvb2xcclxuICpcclxuICogQHJldHVybnMge1Byb21pc2U8dm9pZD59IEEgUHJvbWlzZSB0aGF0IHJlc29sdmVzIG9uY2UgYWxsIHdvcmtlcnMgYXJlXHJcbiAqIHRlcm1pbmF0ZWQsIHRoZSBwb29sIGlzIGRlc3Ryb3llZCwgYW5kIHRoZSBicm93c2VyIGlzIHN1Y2Nlc3NmdWxseSBjbG9zZWQuXHJcbiAqL1xyXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24ga2lsbFBvb2woKSB7XHJcbiAgbG9nKDMsICdbcG9vbF0gS2lsbGluZyBwb29sIHdpdGggYWxsIHdvcmtlcnMgYW5kIGNsb3NpbmcgYnJvd3Nlci4nKTtcclxuXHJcbiAgLy8gSWYgc3RpbGwgYWxpdmUsIGRlc3Ryb3kgdGhlIHBvb2wgb2YgcGFnZXMgYmVmb3JlIGNsb3NpbmcgYSBicm93c2VyXHJcbiAgaWYgKHBvb2wpIHtcclxuICAgIC8vIEZyZWUgdXAgbm90IHJlbGVhc2VkIHdvcmtlcnNcclxuICAgIGZvciAoY29uc3Qgd29ya2VyIG9mIHBvb2wudXNlZCkge1xyXG4gICAgICBwb29sLnJlbGVhc2Uod29ya2VyLnJlc291cmNlKTtcclxuICAgIH1cclxuXHJcbiAgICAvLyBEZXN0cm95IHRoZSBwb29sIGlmIGl0IGlzIHN0aWxsIGF2YWlsYWJsZVxyXG4gICAgaWYgKCFwb29sLmRlc3Ryb3llZCkge1xyXG4gICAgICBhd2FpdCBwb29sLmRlc3Ryb3koKTtcclxuICAgICAgbG9nKDQsICdbcG9vbF0gRGVzdHJveWVkIHRoZSBwb29sIG9mIHJlc291cmNlcy4nKTtcclxuICAgIH1cclxuICAgIHBvb2wgPSBudWxsO1xyXG4gIH1cclxuXHJcbiAgLy8gQ2xvc2UgdGhlIGJyb3dzZXIgaW5zdGFuY2VcclxuICBhd2FpdCBjbG9zZUJyb3dzZXIoKTtcclxufVxyXG5cclxuLyoqXHJcbiAqIFByb2Nlc3NlcyB0aGUgZXhwb3J0IHdvcmsgdXNpbmcgYSB3b3JrZXIgZnJvbSB0aGUgcG9vbC4gQWNxdWlyZXMgYSB3b3JrZXJcclxuICogaGFuZGxlIGZyb20gdGhlIHBvb2wsIHBlcmZvcm1zIHRoZSBleHBvcnQgdXNpbmcgcHVwcGV0ZWVyLCBhbmQgcmVsZWFzZXNcclxuICogdGhlIHdvcmtlciBoYW5kbGUgYmFjayB0byB0aGUgcG9vbC5cclxuICpcclxuICogQGFzeW5jXHJcbiAqIEBmdW5jdGlvbiBwb3N0V29ya1xyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gb3B0aW9ucyAtIFRoZSBjb25maWd1cmF0aW9uIG9iamVjdCBjb250YWluaW5nIGNvbXBsZXRlIHNldFxyXG4gKiBvZiBvcHRpb25zLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7UHJvbWlzZTxPYmplY3Q+fSBBIFByb21pc2UgdGhhdCByZXNvbHZlcyB0byB0aGUgZXhwb3J0IHJlc3VsdFxyXG4gKiBhbmQgb3B0aW9ucy5cclxuICpcclxuICogQHRocm93cyB7RXhwb3J0RXJyb3J9IFRocm93cyBhbiBgRXhwb3J0RXJyb3JgIGlmIGFuIGVycm9yIG9jY3VycyBkdXJpbmdcclxuICogdGhlIGV4cG9ydCBwcm9jZXNzLlxyXG4gKi9cclxuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIHBvc3RXb3JrKG9wdGlvbnMpIHtcclxuICBsZXQgd29ya2VySGFuZGxlO1xyXG5cclxuICB0cnkge1xyXG4gICAgbG9nKDQsICdbcG9vbF0gV29yayByZWNlaXZlZCwgc3RhcnRpbmcgdG8gcHJvY2Vzcy4nKTtcclxuXHJcbiAgICAvLyBBbiBleHBvcnQgYXR0ZW1wdCBjb3VudGVkXHJcbiAgICArK3Bvb2xTdGF0cy5leHBvcnRzQXR0ZW1wdGVkO1xyXG5cclxuICAgIC8vIERpc3BsYXkgdGhlIHBvb2wgaW5mb3JtYXRpb24gaWYgbmVlZGVkXHJcbiAgICBpZiAob3B0aW9ucy5wb29sLmJlbmNobWFya2luZykge1xyXG4gICAgICBnZXRQb29sSW5mbygpO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIFRocm93IGFuIGVycm9yIGluIGNhc2Ugb2YgbGFja2luZyB0aGUgcG9vbCBpbnN0YW5jZVxyXG4gICAgaWYgKCFwb29sKSB7XHJcbiAgICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcihcclxuICAgICAgICAnW3Bvb2xdIFdvcmsgcmVjZWl2ZWQsIGJ1dCBwb29sIGhhcyBub3QgYmVlbiBzdGFydGVkLicsXHJcbiAgICAgICAgNTAwXHJcbiAgICAgICk7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gVGhlIGFjcXVpcmUgY291bnRlclxyXG4gICAgY29uc3QgYWNxdWlyZUNvdW50ZXIgPSBtZWFzdXJlVGltZSgpO1xyXG5cclxuICAgIC8vIFRyeSB0byBhY3F1aXJlIHRoZSB3b3JrZXIgYWxvbmcgd2l0aCB0aGUgaWQsIHdvcmtzIGNvdW50IGFuZCBwYWdlXHJcbiAgICB0cnkge1xyXG4gICAgICBsb2coNCwgJ1twb29sXSBBY3F1aXJpbmcgYSB3b3JrZXIgaGFuZGxlLicpO1xyXG5cclxuICAgICAgLy8gQWNxdWlyZSBhIHBvb2wgcmVzb3VyY2VcclxuICAgICAgd29ya2VySGFuZGxlID0gYXdhaXQgcG9vbC5hY3F1aXJlKCkucHJvbWlzZTtcclxuXHJcbiAgICAgIC8vIENoZWNrIHRoZSBwYWdlIGFjcXVpcmUgdGltZVxyXG4gICAgICBpZiAob3B0aW9ucy5zZXJ2ZXIuYmVuY2htYXJraW5nKSB7XHJcbiAgICAgICAgbG9nKFxyXG4gICAgICAgICAgNSxcclxuICAgICAgICAgIGBbYmVuY2htYXJrXSAke29wdGlvbnMucmVxdWVzdElkID8gYFJlcXVlc3QgWyR7b3B0aW9ucy5yZXF1ZXN0SWR9XSAtIGAgOiAnJ31gLFxyXG4gICAgICAgICAgYEFjcXVpcmluZyBhIHdvcmtlciBoYW5kbGUgdG9vayAke2FjcXVpcmVDb3VudGVyKCl9bXMuYFxyXG4gICAgICAgICk7XHJcbiAgICAgIH1cclxuICAgIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcihcclxuICAgICAgICBgW3Bvb2xdICR7XHJcbiAgICAgICAgICBvcHRpb25zLnJlcXVlc3RJZCA/IGBSZXF1ZXN0IFske29wdGlvbnMucmVxdWVzdElkfV0gLSBgIDogJydcclxuICAgICAgICB9RXJyb3IgZW5jb3VudGVyZWQgd2hlbiBhY3F1aXJpbmcgYW4gYXZhaWxhYmxlIGVudHJ5OiAke2FjcXVpcmVDb3VudGVyKCl9bXMuYCxcclxuICAgICAgICA0MDBcclxuICAgICAgKS5zZXRFcnJvcihlcnJvcik7XHJcbiAgICB9XHJcbiAgICBsb2coNCwgJ1twb29sXSBBY3F1aXJlZCBhIHdvcmtlciBoYW5kbGUuJyk7XHJcblxyXG4gICAgaWYgKCF3b3JrZXJIYW5kbGUucGFnZSkge1xyXG4gICAgICAvLyBTZXQgdGhlIGB3b3JrTGltaXRgIHRvIGV4Y2VlZGVkIGluIG9yZGVyIHRvIHJlY3JlYXRlIHRoZSByZXNvdXJjZVxyXG4gICAgICB3b3JrZXJIYW5kbGUud29ya0NvdW50ID0gb3B0aW9ucy5wb29sLndvcmtMaW1pdCArIDE7XHJcbiAgICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcihcclxuICAgICAgICAnW3Bvb2xdIFJlc29sdmVkIHdvcmtlciBwYWdlIGlzIGludmFsaWQ6IHRoZSBwb29sIHNldHVwIGlzIHdvbmt5LicsXHJcbiAgICAgICAgNDAwXHJcbiAgICAgICk7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gU2F2ZSB0aGUgc3RhcnQgdGltZVxyXG4gICAgY29uc3Qgd29ya1N0YXJ0ID0gZ2V0TmV3RGF0ZVRpbWUoKTtcclxuXHJcbiAgICBsb2coXHJcbiAgICAgIDQsXHJcbiAgICAgIGBbcG9vbF0gUG9vbCByZXNvdXJjZSBbJHt3b3JrZXJIYW5kbGUuaWR9XSAtIFN0YXJ0aW5nIHdvcmsgb24gdGhpcyBwb29sIGVudHJ5LmBcclxuICAgICk7XHJcblxyXG4gICAgLy8gU3RhcnQgbWVhc3VyaW5nIGV4cG9ydCB0aW1lXHJcbiAgICBjb25zdCBleHBvcnRDb3VudGVyID0gbWVhc3VyZVRpbWUoKTtcclxuXHJcbiAgICAvLyBQZXJmb3JtIGFuIGV4cG9ydCBvbiBhIHB1cHBldGVlciBsZXZlbFxyXG4gICAgY29uc3QgcmVzdWx0ID0gYXdhaXQgcHVwcGV0ZWVyRXhwb3J0KFxyXG4gICAgICB3b3JrZXJIYW5kbGUucGFnZSxcclxuICAgICAgb3B0aW9ucy5leHBvcnQsXHJcbiAgICAgIG9wdGlvbnMuY3VzdG9tTG9naWNcclxuICAgICk7XHJcblxyXG4gICAgLy8gQ2hlY2sgaWYgaXQncyBhbiBlcnJvclxyXG4gICAgaWYgKHJlc3VsdCBpbnN0YW5jZW9mIEVycm9yKSB7XHJcbiAgICAgIC8vIE5PVEU6XHJcbiAgICAgIC8vIElmIHRoZXJlJ3MgYSByYXN0ZXJpemF0aW9uIHRpbWVvdXQsIHdlIHdhbnQgbmVlZCB0byBmbHVzaCB0aGUgcGFnZS5cclxuICAgICAgLy8gVGhpcyBpcyBiZWNhdXNlIHRoZSBwYWdlIG1heSBiZSBpbiBhIHN0YXRlIHdoZXJlIGl0J3Mgd2FpdGluZyBmb3JcclxuICAgICAgLy8gdGhlIHNjcmVlbnNob3QgdG8gZmluaXNoIGV2ZW4gdGhvdWdoIHRoZSB0aW1lb3V0IGhhcyBvY2N1cmVkLlxyXG4gICAgICAvLyBXaGljaCBvZiBjb3Vyc2UgY2F1c2VzIGEgbG90IG9mIGlzc3VlcyB3aXRoIHRoZSBldmVudCBzeXN0ZW0sXHJcbiAgICAgIC8vIGFuZCBwYWdlIGNvbnNpc3RlbmN5LlxyXG4gICAgICAvL1xyXG4gICAgICAvLyBOT1RFOlxyXG4gICAgICAvLyBPbmx5IHBhZ2Uuc2NyZWVuc2hvdCB3aWxsIHRocm93IHRoaXMsIHRpbWVvdXRzIGZvciBQREYncyBhcmVcclxuICAgICAgLy8gaGFuZGxlZCBieSB0aGUgcGFnZS5wZGYgZnVuY3Rpb24gaXRzZWxmLlxyXG4gICAgICAvL1xyXG4gICAgICAvLyAuLi55ZXMsIHRoaXMgaXMgdWdseS5cclxuICAgICAgaWYgKHJlc3VsdC5tZXNzYWdlID09PSAnUmFzdGVyaXphdGlvbiB0aW1lb3V0Jykge1xyXG4gICAgICAgIC8vIFNldCB0aGUgYHdvcmtMaW1pdGAgdG8gZXhjZWVkZWQgaW4gb3JkZXIgdG8gcmVjcmVhdGUgdGhlIHJlc291cmNlXHJcbiAgICAgICAgd29ya2VySGFuZGxlLndvcmtDb3VudCA9IG9wdGlvbnMucG9vbC53b3JrTGltaXQgKyAxO1xyXG4gICAgICAgIHdvcmtlckhhbmRsZS5wYWdlID0gbnVsbDtcclxuICAgICAgfVxyXG5cclxuICAgICAgaWYgKFxyXG4gICAgICAgIHJlc3VsdC5uYW1lID09PSAnVGltZW91dEVycm9yJyB8fFxyXG4gICAgICAgIHJlc3VsdC5tZXNzYWdlID09PSAnUmFzdGVyaXphdGlvbiB0aW1lb3V0J1xyXG4gICAgICApIHtcclxuICAgICAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoXHJcbiAgICAgICAgICBgW3Bvb2xdICR7XHJcbiAgICAgICAgICAgIG9wdGlvbnMucmVxdWVzdElkID8gYFJlcXVlc3QgWyR7b3B0aW9ucy5yZXF1ZXN0SWR9XSAtIGAgOiAnJ1xyXG4gICAgICAgICAgfVJhc3Rlcml6YXRpb24gdGltZW91dDogeW91ciBjaGFydCBtYXkgYmUgdG9vIGNvbXBsZXggb3IgbGFyZ2UsIGFuZCBmYWlsZWQgdG8gcmVuZGVyIHdpdGhpbiB0aGUgYWxsb3R0ZWQgdGltZS5gXHJcbiAgICAgICAgKS5zZXRFcnJvcihyZXN1bHQpO1xyXG4gICAgICB9IGVsc2Uge1xyXG4gICAgICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcihcclxuICAgICAgICAgIGBbcG9vbF0gJHtcclxuICAgICAgICAgICAgb3B0aW9ucy5yZXF1ZXN0SWQgPyBgUmVxdWVzdCBbJHtvcHRpb25zLnJlcXVlc3RJZH1dIC0gYCA6ICcnXHJcbiAgICAgICAgICB9RXJyb3IgZW5jb3VudGVyZWQgZHVyaW5nIGV4cG9ydDogJHtleHBvcnRDb3VudGVyKCl9bXMuYFxyXG4gICAgICAgICkuc2V0RXJyb3IocmVzdWx0KTtcclxuICAgICAgfVxyXG4gICAgfVxyXG5cclxuICAgIC8vIENoZWNrIHRoZSBQdXBwZXRlZXIgZXhwb3J0IHRpbWVcclxuICAgIGlmIChvcHRpb25zLnNlcnZlci5iZW5jaG1hcmtpbmcpIHtcclxuICAgICAgbG9nKFxyXG4gICAgICAgIDUsXHJcbiAgICAgICAgYFtiZW5jaG1hcmtdICR7b3B0aW9ucy5yZXF1ZXN0SWQgPyBgUmVxdWVzdCBbJHtvcHRpb25zLnJlcXVlc3RJZH1dIC0gYCA6ICcnfWAsXHJcbiAgICAgICAgYEV4cG9ydGluZyBhIGNoYXJ0IHN1Y2Vzc2Z1bGx5IHRvb2sgJHtleHBvcnRDb3VudGVyKCl9bXMuYFxyXG4gICAgICApO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIFJlbGVhc2UgdGhlIHJlc291cmNlIGJhY2sgdG8gdGhlIHBvb2xcclxuICAgIHBvb2wucmVsZWFzZSh3b3JrZXJIYW5kbGUpO1xyXG5cclxuICAgIC8vIFVzZWQgZm9yIHN0YXRpc3RpY3MgaW4gYXZlcmFnZVRpbWUgYW5kIHByb2Nlc3NlZFdvcmtDb3VudCwgd2hpY2hcclxuICAgIC8vIGluIHR1cm4gaXMgdXNlZCBieSB0aGUgL2hlYWx0aCByb3V0ZS5cclxuICAgIGNvbnN0IHdvcmtFbmQgPSBnZXROZXdEYXRlVGltZSgpO1xyXG4gICAgY29uc3QgZXhwb3J0VGltZSA9IHdvcmtFbmQgLSB3b3JrU3RhcnQ7XHJcblxyXG4gICAgcG9vbFN0YXRzLnRpbWVTcGVudCArPSBleHBvcnRUaW1lO1xyXG4gICAgcG9vbFN0YXRzLnRpbWVTcGVudEF2ZXJhZ2UgPVxyXG4gICAgICBwb29sU3RhdHMudGltZVNwZW50IC8gKytwb29sU3RhdHMuZXhwb3J0c1BlcmZvcm1lZDtcclxuXHJcbiAgICBsb2coNCwgYFtwb29sXSBXb3JrIGNvbXBsZXRlZCBpbiAke2V4cG9ydFRpbWV9bXMuYCk7XHJcblxyXG4gICAgLy8gT3RoZXJ3aXNlIHJldHVybiB0aGUgcmVzdWx0XHJcbiAgICByZXR1cm4ge1xyXG4gICAgICByZXN1bHQsXHJcbiAgICAgIG9wdGlvbnNcclxuICAgIH07XHJcbiAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICsrcG9vbFN0YXRzLmV4cG9ydHNEcm9wcGVkO1xyXG5cclxuICAgIGlmICh3b3JrZXJIYW5kbGUpIHtcclxuICAgICAgcG9vbC5yZWxlYXNlKHdvcmtlckhhbmRsZSk7XHJcbiAgICB9XHJcblxyXG4gICAgdGhyb3cgZXJyb3I7XHJcbiAgfVxyXG59XHJcblxyXG4vKipcclxuICogUmV0cmlldmVzIHRoZSBjdXJyZW50IHBvb2wgaW5zdGFuY2UuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBnZXRQb29sXHJcbiAqXHJcbiAqIEByZXR1cm5zIHsoT2JqZWN0fG51bGwpfSBUaGUgY3VycmVudCBwb29sIGluc3RhbmNlIGlmIGluaXRpYWxpemVkLCBvciBudWxsXHJcbiAqIGlmIHRoZSBwb29sIGhhcyBub3QgYmVlbiBjcmVhdGVkLlxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIGdldFBvb2woKSB7XHJcbiAgcmV0dXJuIHBvb2w7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBHZXRzIHRoZSBzdGF0aXN0aWMgb2YgYSBwb29sIGluc3RhY2UgYWJvdXQgZXhwb3J0cy5cclxuICpcclxuICogQGZ1bmN0aW9uIGdldFBvb2xTdGF0c1xyXG4gKlxyXG4gKiBAcmV0dXJucyB7T2JqZWN0fSBUaGUgY3VycmVudCBwb29sIHN0YXRpc3RpY3MuXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gZ2V0UG9vbFN0YXRzKCkge1xyXG4gIHJldHVybiBwb29sU3RhdHM7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBSZXRyaWV2ZXMgcG9vbCBpbmZvcm1hdGlvbiBpbiBKU09OIGZvcm1hdCwgaW5jbHVkaW5nIG1pbmltdW0gYW5kIG1heGltdW1cclxuICogd29ya2VycywgYXZhaWxhYmxlIHdvcmtlcnMsIHdvcmtlcnMgaW4gdXNlLCBhbmQgcGVuZGluZyBhY3F1aXJlIHJlcXVlc3RzLlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gZ2V0UG9vbEluZm9KU09OXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtPYmplY3R9IFBvb2wgaW5mb3JtYXRpb24gaW4gSlNPTiBmb3JtYXQuXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gZ2V0UG9vbEluZm9KU09OKCkge1xyXG4gIHJldHVybiB7XHJcbiAgICBtaW46IHBvb2wubWluLFxyXG4gICAgbWF4OiBwb29sLm1heCxcclxuICAgIHVzZWQ6IHBvb2wubnVtVXNlZCgpLFxyXG4gICAgYXZhaWxhYmxlOiBwb29sLm51bUZyZWUoKSxcclxuICAgIGFsbENyZWF0ZWQ6IHBvb2wubnVtVXNlZCgpICsgcG9vbC5udW1GcmVlKCksXHJcbiAgICBwZW5kaW5nQWNxdWlyZXM6IHBvb2wubnVtUGVuZGluZ0FjcXVpcmVzKCksXHJcbiAgICBwZW5kaW5nQ3JlYXRlczogcG9vbC5udW1QZW5kaW5nQ3JlYXRlcygpLFxyXG4gICAgcGVuZGluZ1ZhbGlkYXRpb25zOiBwb29sLm51bVBlbmRpbmdWYWxpZGF0aW9ucygpLFxyXG4gICAgcGVuZGluZ0Rlc3Ryb3lzOiBwb29sLnBlbmRpbmdEZXN0cm95cy5sZW5ndGgsXHJcbiAgICBhYnNvbHV0ZUFsbDpcclxuICAgICAgcG9vbC5udW1Vc2VkKCkgK1xyXG4gICAgICBwb29sLm51bUZyZWUoKSArXHJcbiAgICAgIHBvb2wubnVtUGVuZGluZ0FjcXVpcmVzKCkgK1xyXG4gICAgICBwb29sLm51bVBlbmRpbmdDcmVhdGVzKCkgK1xyXG4gICAgICBwb29sLm51bVBlbmRpbmdWYWxpZGF0aW9ucygpICtcclxuICAgICAgcG9vbC5wZW5kaW5nRGVzdHJveXMubGVuZ3RoXHJcbiAgfTtcclxufVxyXG5cclxuLyoqXHJcbiAqIExvZ3MgaW5mb3JtYXRpb24gYWJvdXQgdGhlIGN1cnJlbnQgc3RhdGUgb2YgdGhlIHBvb2wsIGluY2x1ZGluZyB0aGUgbWluaW11bVxyXG4gKiBhbmQgbWF4aW11bSB3b3JrZXJzLCBhdmFpbGFibGUgd29ya2Vycywgd29ya2VycyBpbiB1c2UsIGFuZCBwZW5kaW5nIGFjcXVpcmVcclxuICogcmVxdWVzdHMuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBnZXRQb29sSW5mb1xyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIGdldFBvb2xJbmZvKCkge1xyXG4gIGNvbnN0IHtcclxuICAgIG1pbixcclxuICAgIG1heCxcclxuICAgIHVzZWQsXHJcbiAgICBhdmFpbGFibGUsXHJcbiAgICBhbGxDcmVhdGVkLFxyXG4gICAgcGVuZGluZ0FjcXVpcmVzLFxyXG4gICAgcGVuZGluZ0NyZWF0ZXMsXHJcbiAgICBwZW5kaW5nVmFsaWRhdGlvbnMsXHJcbiAgICBwZW5kaW5nRGVzdHJveXMsXHJcbiAgICBhYnNvbHV0ZUFsbFxyXG4gIH0gPSBnZXRQb29sSW5mb0pTT04oKTtcclxuXHJcbiAgbG9nKDUsIGBbcG9vbF0gVGhlIG1pbmltdW0gbnVtYmVyIG9mIHJlc291cmNlcyBhbGxvd2VkIGJ5IHBvb2w6ICR7bWlufS5gKTtcclxuICBsb2coNSwgYFtwb29sXSBUaGUgbWF4aW11bSBudW1iZXIgb2YgcmVzb3VyY2VzIGFsbG93ZWQgYnkgcG9vbDogJHttYXh9LmApO1xyXG4gIGxvZyg1LCBgW3Bvb2xdIFRoZSBudW1iZXIgb2YgdXNlZCByZXNvdXJjZXM6ICR7dXNlZH0uYCk7XHJcbiAgbG9nKDUsIGBbcG9vbF0gVGhlIG51bWJlciBvZiBmcmVlIHJlc291cmNlczogJHthdmFpbGFibGV9LmApO1xyXG4gIGxvZyhcclxuICAgIDUsXHJcbiAgICBgW3Bvb2xdIFRoZSBudW1iZXIgb2YgYWxsIGNyZWF0ZWQgKHVzZWQgYW5kIGZyZWUpIHJlc291cmNlczogJHthbGxDcmVhdGVkfS5gXHJcbiAgKTtcclxuICBsb2coXHJcbiAgICA1LFxyXG4gICAgYFtwb29sXSBUaGUgbnVtYmVyIG9mIHJlc291cmNlcyB3YWl0aW5nIHRvIGJlIGFjcXVpcmVkOiAke3BlbmRpbmdBY3F1aXJlc30uYFxyXG4gICk7XHJcbiAgbG9nKFxyXG4gICAgNSxcclxuICAgIGBbcG9vbF0gVGhlIG51bWJlciBvZiByZXNvdXJjZXMgd2FpdGluZyB0byBiZSBjcmVhdGVkOiAke3BlbmRpbmdDcmVhdGVzfS5gXHJcbiAgKTtcclxuICBsb2coXHJcbiAgICA1LFxyXG4gICAgYFtwb29sXSBUaGUgbnVtYmVyIG9mIHJlc291cmNlcyB3YWl0aW5nIHRvIGJlIHZhbGlkYXRlZDogJHtwZW5kaW5nVmFsaWRhdGlvbnN9LmBcclxuICApO1xyXG4gIGxvZyhcclxuICAgIDUsXHJcbiAgICBgW3Bvb2xdIFRoZSBudW1iZXIgb2YgcmVzb3VyY2VzIHdhaXRpbmcgdG8gYmUgZGVzdHJveWVkOiAke3BlbmRpbmdEZXN0cm95c30uYFxyXG4gICk7XHJcbiAgbG9nKDUsIGBbcG9vbF0gVGhlIG51bWJlciBvZiBhbGwgcmVzb3VyY2VzOiAke2Fic29sdXRlQWxsfS5gKTtcclxufVxyXG5cclxuLyoqXHJcbiAqIEZhY3RvcnkgZnVuY3Rpb24gdGhhdCByZXR1cm5zIGFuIG9iamVjdCB3aXRoIGBjcmVhdGVgLCBgdmFsaWRhdGVgLFxyXG4gKiBhbmQgYGRlc3Ryb3lgIGZ1bmN0aW9ucyBmb3IgdGhlIHBvb2wgaW5zdGFuY2UuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBfZmFjdG9yeVxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gcG9vbE9wdGlvbnMgLSBUaGUgY29uZmlndXJhdGlvbiBvYmplY3QgY29udGFpbmluZyBgcG9vbGBcclxuICogb3B0aW9ucy5cclxuICovXHJcbmZ1bmN0aW9uIF9mYWN0b3J5KHBvb2xPcHRpb25zKSB7XHJcbiAgcmV0dXJuIHtcclxuICAgIC8qKlxyXG4gICAgICogQ3JlYXRlcyBhIG5ldyB3b3JrZXIgcGFnZSBmb3IgdGhlIGV4cG9ydCBwb29sLlxyXG4gICAgICpcclxuICAgICAqIEBhc3luY1xyXG4gICAgICogQGZ1bmN0aW9uIGNyZWF0ZVxyXG4gICAgICpcclxuICAgICAqIEByZXR1cm5zIHtQcm9taXNlPE9iamVjdD59IEEgUHJvbWlzZSB0aGF0IHJlc29sdmVzIHRvIGFuIG9iamVjdFxyXG4gICAgICogY29udGFpbmluZyB0aGUgd29ya2VyIElELCBhIHJlZmVyZW5jZSB0byB0aGUgYnJvd3NlciBwYWdlLCBhbmQgaW5pdGlhbFxyXG4gICAgICogd29yayBjb3VudC5cclxuICAgICAqXHJcbiAgICAgKiBAdGhyb3dzIHtFeHBvcnRFcnJvcn0gVGhyb3dzIGFuIGBFeHBvcnRFcnJvcmAgaWYgdGhlcmUgaXMgYW4gZXJyb3IgZHVyaW5nXHJcbiAgICAgKiB0aGUgY3JlYXRpb24gb2YgdGhlIG5ldyBwYWdlLlxyXG4gICAgICovXHJcbiAgICBjcmVhdGU6IGFzeW5jICgpID0+IHtcclxuICAgICAgLy8gSW5pdCB0aGUgcmVzb3VyY2Ugd2l0aCB1bmlxdWUgaWQgYW5kIHdvcmsgY291bnRcclxuICAgICAgY29uc3QgcG9vbFJlc291cmNlID0ge1xyXG4gICAgICAgIGlkOiB1dWlkKCksXHJcbiAgICAgICAgLy8gVHJ5IHRvIGRpc3RyaWJ1dGUgdGhlIGluaXRpYWwgd29yayBjb3VudFxyXG4gICAgICAgIHdvcmtDb3VudDogTWF0aC5yb3VuZChNYXRoLnJhbmRvbSgpICogKHBvb2xPcHRpb25zLndvcmtMaW1pdCAvIDIpKVxyXG4gICAgICB9O1xyXG5cclxuICAgICAgdHJ5IHtcclxuICAgICAgICAvLyBTdGFydCBtZWFzdXJpbmcgYSBwYWdlIGNyZWF0aW9uIHRpbWVcclxuICAgICAgICBjb25zdCBzdGFydERhdGUgPSBnZXROZXdEYXRlVGltZSgpO1xyXG5cclxuICAgICAgICAvLyBDcmVhdGUgYSBuZXcgcGFnZVxyXG4gICAgICAgIGF3YWl0IG5ld1BhZ2UocG9vbFJlc291cmNlKTtcclxuXHJcbiAgICAgICAgLy8gTWVhc3VyZSB0aGUgdGltZSBvZiBmdWxsIGNyZWF0aW9uIGFuZCBjb25maWd1cmF0aW9uIG9mIGEgcGFnZVxyXG4gICAgICAgIGxvZyhcclxuICAgICAgICAgIDMsXHJcbiAgICAgICAgICBgW3Bvb2xdIFBvb2wgcmVzb3VyY2UgWyR7cG9vbFJlc291cmNlLmlkfV0gLSBTdWNjZXNzZnVsbHkgY3JlYXRlZCBhIHdvcmtlciwgdG9vayAke1xyXG4gICAgICAgICAgICBnZXROZXdEYXRlVGltZSgpIC0gc3RhcnREYXRlXHJcbiAgICAgICAgICB9bXMuYFxyXG4gICAgICAgICk7XHJcblxyXG4gICAgICAgIC8vIFJldHVybiByZWFkeSBwb29sIHJlc291cmNlXHJcbiAgICAgICAgcmV0dXJuIHBvb2xSZXNvdXJjZTtcclxuICAgICAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICAgICBsb2coXHJcbiAgICAgICAgICAzLFxyXG4gICAgICAgICAgYFtwb29sXSBQb29sIHJlc291cmNlIFske3Bvb2xSZXNvdXJjZS5pZH1dIC0gRXJyb3IgZW5jb3VudGVyZWQgd2hlbiBjcmVhdGluZyBhIG5ldyBwYWdlLmBcclxuICAgICAgICApO1xyXG4gICAgICAgIHRocm93IGVycm9yO1xyXG4gICAgICB9XHJcbiAgICB9LFxyXG5cclxuICAgIC8qKlxyXG4gICAgICogVmFsaWRhdGVzIGEgd29ya2VyIHBhZ2UgaW4gdGhlIGV4cG9ydCBwb29sLCBjaGVja2luZyBpZiBpdCBoYXMgZXhjZWVkZWRcclxuICAgICAqIHRoZSB3b3JrIGxpbWl0LlxyXG4gICAgICpcclxuICAgICAqIEBhc3luY1xyXG4gICAgICogQGZ1bmN0aW9uIHZhbGlkYXRlXHJcbiAgICAgKlxyXG4gICAgICogQHBhcmFtIHtPYmplY3R9IHBvb2xSZXNvdXJjZSAtIFRoZSBoYW5kbGUgdG8gdGhlIHdvcmtlciwgY29udGFpbmluZ1xyXG4gICAgICogdGhlIHdvcmtlcidzIElELCBhIHJlZmVyZW5jZSB0byB0aGUgYnJvd3NlciBwYWdlLCBhbmQgd29yayBjb3VudC5cclxuICAgICAqXHJcbiAgICAgKiBAcmV0dXJucyB7UHJvbWlzZTxib29sZWFuPn0gQSBQcm9taXNlIHRoYXQgcmVzb2x2ZXMgdG8gdHJ1ZSBpZiB0aGUgd29ya2VyXHJcbiAgICAgKiBpcyB2YWxpZCBhbmQgd2l0aGluIHRoZSB3b3JrIGxpbWl0OyBvdGhlcndpc2UsIHRvIGZhbHNlLlxyXG4gICAgICovXHJcbiAgICB2YWxpZGF0ZTogYXN5bmMgKHBvb2xSZXNvdXJjZSkgPT4ge1xyXG4gICAgICAvLyBOT1RFOlxyXG4gICAgICAvLyBJbiBjZXJ0YWluIGNhc2VzIGFjcXVpcmluZyB0aHJvd3MgYSBUYXJnZXRDbG9zZUVycm9yLCB3aGljaCBtYXlcclxuICAgICAgLy8gYmUgY2F1c2VkIGJ5IHR3byB0aGluZ3M6XHJcbiAgICAgIC8vIC0gVGhlIHBhZ2UgaXMgY2xvc2VkIGFuZCBhdHRlbXB0ZWQgdG8gYmUgcmV1c2VkLlxyXG4gICAgICAvLyAtIExvc3QgY29udGFjdCB3aXRoIHRoZSBicm93c2VyLlxyXG4gICAgICAvL1xyXG4gICAgICAvLyBXaGF0IHdlJ3JlIHNlZWluZyBpbiBsb2dzIGlzIHRoYXQgc3VjY2Vzc2l2ZSBleHBvcnRzIHR5cGljYWxseVxyXG4gICAgICAvLyBzdWNjZWVkcywgYW5kIHRoZSBzZXJ2ZXIgcmVjb3ZlcnMsIGluZGljYXRpbmcgdGhhdCBpdCdzIGxpa2VseVxyXG4gICAgICAvLyB0aGUgZmlyc3QgY2FzZS4gVGhpcyBpcyBhbiBhdHRlbXB0IGF0IGFsbGlldmF0aW5nIHRoZSBpc3N1ZSBieVxyXG4gICAgICAvLyBzaW1wbHkgbm90IHZhbGlkYXRpbmcgdGhlIHdvcmtlciBpZiB0aGUgcGFnZSBpcyBudWxsIG9yIGNsb3NlZC5cclxuICAgICAgLy9cclxuICAgICAgLy8gVGhlIGFjdHVhbCByZXN1bHQgZnJvbSB3aGVuIHRoaXMgaGFwcGVuZWQsIHdhcyB0aGF0IGEgd29ya2VyIHdvdWxkXHJcbiAgICAgIC8vIGJlIGNvbXBsZXRlbHkgbG9ja2VkLCBzdG9wcGluZyBpdCBmcm9tIGJlaW5nIGFjcXVpcmVkIHVudGlsXHJcbiAgICAgIC8vIGl0cyB3b3JrIGNvdW50IHJlYWNoZWQgdGhlIGxpbWl0LlxyXG5cclxuICAgICAgLy8gQ2hlY2sgaWYgdGhlIGBwYWdlYCBpcyB2YWxpZFxyXG4gICAgICBpZiAoIXBvb2xSZXNvdXJjZS5wYWdlKSB7XHJcbiAgICAgICAgbG9nKFxyXG4gICAgICAgICAgMyxcclxuICAgICAgICAgIGBbcG9vbF0gUG9vbCByZXNvdXJjZSBbJHtwb29sUmVzb3VyY2UuaWR9XSAtIFZhbGlkYXRpb24gZmFpbGVkIChubyB2YWxpZCBwYWdlIGlzIGZvdW5kKS5gXHJcbiAgICAgICAgKTtcclxuICAgICAgICByZXR1cm4gZmFsc2U7XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIC8vIENoZWNrIGlmIHRoZSBgcGFnZWAgaXMgY2xvc2VkXHJcbiAgICAgIGlmIChwb29sUmVzb3VyY2UucGFnZS5pc0Nsb3NlZCgpKSB7XHJcbiAgICAgICAgbG9nKFxyXG4gICAgICAgICAgMyxcclxuICAgICAgICAgIGBbcG9vbF0gUG9vbCByZXNvdXJjZSBbJHtwb29sUmVzb3VyY2UuaWR9XSAtIFZhbGlkYXRpb24gZmFpbGVkIChwYWdlIGlzIGNsb3NlZCBvciBpbnZhbGlkKS5gXHJcbiAgICAgICAgKTtcclxuICAgICAgICByZXR1cm4gZmFsc2U7XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIC8vIENoZWNrIGlmIHRoZSBgbWFpbkZyYW1lYCBpcyBkZXRhY2hlZFxyXG4gICAgICBpZiAocG9vbFJlc291cmNlLnBhZ2UubWFpbkZyYW1lKCkuZGV0YWNoZWQpIHtcclxuICAgICAgICBsb2coXHJcbiAgICAgICAgICAzLFxyXG4gICAgICAgICAgYFtwb29sXSBQb29sIHJlc291cmNlIFske3Bvb2xSZXNvdXJjZS5pZH1dIC0gVmFsaWRhdGlvbiBmYWlsZWQgKHBhZ2UncyBmcmFtZSBpcyBkZXRhY2hlZCkuYFxyXG4gICAgICAgICk7XHJcbiAgICAgICAgcmV0dXJuIGZhbHNlO1xyXG4gICAgICB9XHJcblxyXG4gICAgICAvLyBDaGVjayBpZiB0aGUgYHdvcmtMaW1pdGAgaXMgZXhjZWVkZWRcclxuICAgICAgaWYgKFxyXG4gICAgICAgIHBvb2xPcHRpb25zLndvcmtMaW1pdCAmJlxyXG4gICAgICAgICsrcG9vbFJlc291cmNlLndvcmtDb3VudCA+IHBvb2xPcHRpb25zLndvcmtMaW1pdFxyXG4gICAgICApIHtcclxuICAgICAgICBsb2coXHJcbiAgICAgICAgICAzLFxyXG4gICAgICAgICAgYFtwb29sXSBQb29sIHJlc291cmNlIFske3Bvb2xSZXNvdXJjZS5pZH1dIC0gVmFsaWRhdGlvbiBmYWlsZWQgKGV4Y2VlZGVkIHRoZSAke3Bvb2xPcHRpb25zLndvcmtMaW1pdH0gd29ya3MgcGVyIHJlc291cmNlIGxpbWl0KS5gXHJcbiAgICAgICAgKTtcclxuICAgICAgICByZXR1cm4gZmFsc2U7XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIC8vIFRoZSBgcG9vbFJlc291cmNlYCBpcyB2YWxpZGF0ZWRcclxuICAgICAgcmV0dXJuIHRydWU7XHJcbiAgICB9LFxyXG5cclxuICAgIC8qKlxyXG4gICAgICogRGVzdHJveXMgYSB3b3JrZXIgZW50cnkgaW4gdGhlIGV4cG9ydCBwb29sLCBjbG9zaW5nIGl0cyBhc3NvY2lhdGVkIHBhZ2UuXHJcbiAgICAgKlxyXG4gICAgICogQGFzeW5jXHJcbiAgICAgKiBAZnVuY3Rpb24gZGVzdHJveVxyXG4gICAgICpcclxuICAgICAqIEBwYXJhbSB7T2JqZWN0fSBwb29sUmVzb3VyY2UgLSBUaGUgaGFuZGxlIHRvIHRoZSB3b3JrZXIsIGNvbnRhaW5pbmdcclxuICAgICAqIHRoZSB3b3JrZXIncyBJRCwgYSByZWZlcmVuY2UgdG8gdGhlIGJyb3dzZXIgcGFnZSwgYW5kIHdvcmsgY291bnQuXHJcbiAgICAgKi9cclxuICAgIGRlc3Ryb3k6IGFzeW5jIChwb29sUmVzb3VyY2UpID0+IHtcclxuICAgICAgbG9nKFxyXG4gICAgICAgIDMsXHJcbiAgICAgICAgYFtwb29sXSBQb29sIHJlc291cmNlIFske3Bvb2xSZXNvdXJjZS5pZH1dIC0gRGVzdHJveWluZyBhIHdvcmtlci5gXHJcbiAgICAgICk7XHJcblxyXG4gICAgICBpZiAocG9vbFJlc291cmNlLnBhZ2UgJiYgIXBvb2xSZXNvdXJjZS5wYWdlLmlzQ2xvc2VkKCkpIHtcclxuICAgICAgICB0cnkge1xyXG4gICAgICAgICAgLy8gUmVtb3ZlIGFsbCBhdHRhY2hlZCBldmVudCBsaXN0ZW5lcnMgZnJvbSB0aGUgcmVzb3VyY2VcclxuICAgICAgICAgIHBvb2xSZXNvdXJjZS5wYWdlLnJlbW92ZUFsbExpc3RlbmVycygncGFnZWVycm9yJyk7XHJcbiAgICAgICAgICBwb29sUmVzb3VyY2UucGFnZS5yZW1vdmVBbGxMaXN0ZW5lcnMoJ2NvbnNvbGUnKTtcclxuICAgICAgICAgIHBvb2xSZXNvdXJjZS5wYWdlLnJlbW92ZUFsbExpc3RlbmVycygnZnJhbWVkZXRhY2hlZCcpO1xyXG5cclxuICAgICAgICAgIC8vIFdlIG5lZWQgdG8gd2FpdCBhcm91bmQgZm9yIHRoaXNcclxuICAgICAgICAgIGF3YWl0IHBvb2xSZXNvdXJjZS5wYWdlLmNsb3NlKCk7XHJcbiAgICAgICAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICAgICAgIGxvZyhcclxuICAgICAgICAgICAgMyxcclxuICAgICAgICAgICAgYFtwb29sXSBQb29sIHJlc291cmNlIFske3Bvb2xSZXNvdXJjZS5pZH1dIC0gUGFnZSBjb3VsZCBub3QgYmUgY2xvc2VkIHVwb24gZGVzdHJveWluZy5gXHJcbiAgICAgICAgICApO1xyXG4gICAgICAgICAgdGhyb3cgZXJyb3I7XHJcbiAgICAgICAgfVxyXG4gICAgICB9XHJcbiAgICB9XHJcbiAgfTtcclxufVxyXG5cclxuZXhwb3J0IGRlZmF1bHQge1xyXG4gIGluaXRQb29sLFxyXG4gIGtpbGxQb29sLFxyXG4gIHBvc3RXb3JrLFxyXG4gIGdldFBvb2wsXHJcbiAgZ2V0UG9vbFN0YXRzLFxyXG4gIGdldFBvb2xJbmZvLFxyXG4gIGdldFBvb2xJbmZvSlNPTlxyXG59O1xyXG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxyXG5cclxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXHJcblxyXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNSwgSGlnaHNvZnRcclxuXHJcbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cclxuXHJcbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxyXG5cclxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxyXG5cclxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cclxuXHJcbi8qKlxyXG4gKiBAb3ZlcnZpZXcgVXNlZCB0byBzYW5pdGl6ZSB0aGUgc3RyaW5ncyBjb21pbmcgZnJvbSB0aGUgZXhwb3J0aW5nIG1vZHVsZVxyXG4gKiB0byBwcmV2ZW50IFhTUyBhdHRhY2tzICh3aXRoIHRoZSBET01QdXJpZnkgbGlicmFyeSkuXHJcbiAqL1xyXG5cclxuaW1wb3J0IERPTVB1cmlmeSBmcm9tICdkb21wdXJpZnknO1xyXG5pbXBvcnQgeyBKU0RPTSB9IGZyb20gJ2pzZG9tJztcclxuXHJcbi8qKlxyXG4gKiBTYW5pdGl6ZXMgYSBnaXZlbiBIVE1MIHN0cmluZyBieSByZW1vdmluZyA8c2NyaXB0PiB0YWdzLiBUaGlzIGZ1bmN0aW9uIHVzZXNcclxuICogYSByZWd1bGFyIGV4cHJlc3Npb24gdG8gZmluZCBhbmQgcmVtb3ZlIGFsbCBvY2N1cnJlbmNlcyBvZiA8c2NyaXB0Pjwvc2NyaXB0PlxyXG4gKiB0YWdzIGFuZCBhbnkgY29udGVudCB3aXRoaW4gdGhlbS5cclxuICpcclxuICogQGZ1bmN0aW9uIHNhbml0aXplXHJcbiAqXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSBpbnB1dCAtIFRoZSBIVE1MIHN0cmluZyB0byBiZSBzYW5pdGl6ZWQuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtzdHJpbmd9IFRoZSBzYW5pdGl6ZWQgSFRNTCBzdHJpbmcuXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gc2FuaXRpemUoaW5wdXQpIHtcclxuICAvLyBHZXQgdGhlIHZpcnR1YWwgRE9NXHJcbiAgY29uc3Qgd2luZG93ID0gbmV3IEpTRE9NKCcnKS53aW5kb3c7XHJcblxyXG4gIC8vIENyZWF0ZSBhIHB1cmlmeWluZyBpbnN0YW5jZVxyXG4gIGNvbnN0IHB1cmlmeSA9IERPTVB1cmlmeSh3aW5kb3cpO1xyXG5cclxuICAvLyBSZXR1cm4gc2FuaXRpemVkIGlucHV0XHJcbiAgcmV0dXJuIHB1cmlmeS5zYW5pdGl6ZShpbnB1dCwgeyBBRERfVEFHUzogWydmb3JlaWduT2JqZWN0J10gfSk7XHJcbn1cclxuXHJcbmV4cG9ydCBkZWZhdWx0IHtcclxuICBzYW5pdGl6ZVxyXG59O1xyXG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxyXG5cclxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXHJcblxyXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNSwgSGlnaHNvZnRcclxuXHJcbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cclxuXHJcbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxyXG5cclxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxyXG5cclxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cclxuXHJcbi8qKlxyXG4gKiBAb3ZlcnZpZXcgVGhpcyBtb2R1bGUgcHJvdmlkZXMgZnVuY3Rpb25zIHRvIHByZXBhcmUgZm9yIHRoZSBleHBvcnRpbmcgY2hhcnRzXHJcbiAqIGludG8gdmFyaW91cyBpbWFnZSBvdXRwdXQgZm9ybWF0cyBzdWNoIGFzIEpQRUcsIFBORywgUERGLCBhbmQgU1ZHcy5cclxuICogSXQgc3VwcG9ydHMgc2luZ2xlIGFuZCBiYXRjaCBleHBvcnQgb3BlcmF0aW9ucyBhbmQgYWxsb3dzIGN1c3RvbWl6YXRpb25cclxuICogdGhyb3VnaCBvcHRpb25zIHBhc3NlZCBmcm9tIGNvbmZpZ3VyYXRpb25zIG9yIEFQSXMuXHJcbiAqL1xyXG5cclxuaW1wb3J0IHsgcmVhZEZpbGVTeW5jLCB3cml0ZUZpbGVTeW5jIH0gZnJvbSAnZnMnO1xyXG5cclxuaW1wb3J0IHtcclxuICBnZXRPcHRpb25zLFxyXG4gIGlzQWxsb3dlZENvbmZpZyxcclxuICBtZXJnZU9wdGlvbnMsXHJcbiAgdmFsaWRhdGVPcHRpb24sXHJcbiAgdmFsaWRhdGVPcHRpb25zXHJcbn0gZnJvbSAnLi9jb25maWcuanMnO1xyXG5pbXBvcnQgeyBsb2csIGxvZ1dpdGhTdGFjayB9IGZyb20gJy4vbG9nZ2VyLmpzJztcclxuaW1wb3J0IHsgZ2V0UG9vbFN0YXRzLCBraWxsUG9vbCwgcG9zdFdvcmsgfSBmcm9tICcuL3Bvb2wuanMnO1xyXG5pbXBvcnQgeyBzYW5pdGl6ZSB9IGZyb20gJy4vc2FuaXRpemUuanMnO1xyXG5pbXBvcnQge1xyXG4gIGRlZXBDb3B5LFxyXG4gIGZpeENvbnN0cixcclxuICBmaXhPdXRmaWxlLFxyXG4gIGZpeFR5cGUsXHJcbiAgZ2V0QWJzb2x1dGVQYXRoLFxyXG4gIGdldEJhc2U2NCxcclxuICBpc09iamVjdCxcclxuICByb3VuZE51bWJlcixcclxuICB3cmFwQXJvdW5kXHJcbn0gZnJvbSAnLi91dGlscy5qcyc7XHJcblxyXG5pbXBvcnQgRXhwb3J0RXJyb3IgZnJvbSAnLi9lcnJvcnMvRXhwb3J0RXJyb3IuanMnO1xyXG5cclxuLy8gVGhlIGdsb2JhbCBmbGFnIGZvciB0aGUgY29kZSBleGVjdXRpb24gcGVybWlzc2lvblxyXG5sZXQgYWxsb3dDb2RlRXhlY3V0aW9uID0gZmFsc2U7XHJcblxyXG4vKipcclxuICogU3RhcnRzIGEgc2luZ2xlIGV4cG9ydCBwcm9jZXNzIGJhc2VkIG9uIHRoZSBzcGVjaWZpZWQgb3B0aW9ucyBhbmQgc2F2ZXNcclxuICogdGhlIHJlc3VsdGluZyBpbWFnZSB0byB0aGUgcHJvdmlkZWQgb3V0cHV0IGZpbGUuXHJcbiAqXHJcbiAqIEBhc3luY1xyXG4gKiBAZnVuY3Rpb24gc2luZ2xlRXhwb3J0XHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBvcHRpb25zIC0gVGhlIGBvcHRpb25zYCBvYmplY3QsIHdoaWNoIHNob3VsZCBpbmNsdWRlIHNldHRpbmdzXHJcbiAqIGZyb20gdGhlIGBleHBvcnRgIGFuZCBgY3VzdG9tTG9naWNgIHNlY3Rpb25zLiBJdCBjYW4gYmUgYSBwYXJ0aWFsIG9yIGNvbXBsZXRlXHJcbiAqIHNldCBvZiBvcHRpb25zIGZyb20gdGhlc2Ugc2VjdGlvbnMuIFRoZSBvYmplY3QgbXVzdCBjb250YWluIGF0IGxlYXN0IG9uZVxyXG4gKiBvZiB0aGUgZm9sbG93aW5nIGBleHBvcnRgIHByb3BlcnRpZXM6IGBpbmZpbGVgLCBgaW5zdHJgLCBgb3B0aW9uc2AsIG9yIGBzdmdgXHJcbiAqIHRvIGdlbmVyYXRlIGEgdmFsaWQgaW1hZ2UuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtQcm9taXNlPHZvaWQ+fSBBIFByb21pc2UgdGhhdCByZXNvbHZlcyBvbmNlIHRoZSBzaW5nbGUgZXhwb3J0XHJcbiAqIHByb2Nlc3MgaXMgY29tcGxldGVkLlxyXG4gKlxyXG4gKiBAdGhyb3dzIHtFeHBvcnRFcnJvcn0gVGhyb3dzIGFuIGBFeHBvcnRFcnJvcmAgaWYgYW4gZXJyb3Igb2NjdXJzIGR1cmluZ1xyXG4gKiB0aGUgc2luZ2xlIGV4cG9ydCBwcm9jZXNzLlxyXG4gKi9cclxuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIHNpbmdsZUV4cG9ydChvcHRpb25zKSB7XHJcbiAgLy8gQ2hlY2sgaWYgdGhlIGV4cG9ydCBtYWtlcyBzZW5zZVxyXG4gIGlmIChvcHRpb25zICYmIG9wdGlvbnMuZXhwb3J0KSB7XHJcbiAgICAvLyBWYWxpZGF0ZSBzaW5nbGUgZXhwb3J0IG9wdGlvbnNcclxuICAgIG9wdGlvbnMgPSB2YWxpZGF0ZU9wdGlvbnMob3B0aW9ucyk7XHJcblxyXG4gICAgLy8gUGVyZm9ybSBhbiBleHBvcnRcclxuICAgIGF3YWl0IHN0YXJ0RXhwb3J0KFxyXG4gICAgICB7IGV4cG9ydDogb3B0aW9ucy5leHBvcnQsIGN1c3RvbUxvZ2ljOiBvcHRpb25zLmN1c3RvbUxvZ2ljIH0sXHJcbiAgICAgIGFzeW5jIChlcnJvciwgZGF0YSkgPT4ge1xyXG4gICAgICAgIC8vIEV4aXQgcHJvY2VzcyB3aGVuIGVycm9yIGV4aXN0c1xyXG4gICAgICAgIGlmIChlcnJvcikge1xyXG4gICAgICAgICAgdGhyb3cgZXJyb3I7XHJcbiAgICAgICAgfVxyXG5cclxuICAgICAgICAvLyBHZXQgdGhlIGBiNjRgLCBgb3V0ZmlsZWAsIGFuZCBgdHlwZWAgZm9yIGEgY2hhcnRcclxuICAgICAgICBjb25zdCB7IGI2NCwgb3V0ZmlsZSwgdHlwZSB9ID0gZGF0YS5vcHRpb25zLmV4cG9ydDtcclxuXHJcbiAgICAgICAgLy8gU2F2ZSB0aGUgcmVzdWx0XHJcbiAgICAgICAgdHJ5IHtcclxuICAgICAgICAgIGlmIChiNjQpIHtcclxuICAgICAgICAgICAgLy8gQXMgYSBCYXNlNjQgc3RyaW5nIHRvIGEgdHh0IGZpbGVcclxuICAgICAgICAgICAgd3JpdGVGaWxlU3luYyhcclxuICAgICAgICAgICAgICBgJHtvdXRmaWxlLnNwbGl0KCcuJykuc2hpZnQoKSB8fCAnY2hhcnQnfS50eHRgLFxyXG4gICAgICAgICAgICAgIGdldEJhc2U2NChkYXRhLnJlc3VsdCwgdHlwZSlcclxuICAgICAgICAgICAgKTtcclxuICAgICAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgICAgIC8vIEFzIGEgY29ycmVjdCBpbWFnZSBmb3JtYXRcclxuICAgICAgICAgICAgd3JpdGVGaWxlU3luYyhcclxuICAgICAgICAgICAgICBvdXRmaWxlIHx8IGBjaGFydC4ke3R5cGV9YCxcclxuICAgICAgICAgICAgICB0eXBlICE9PSAnc3ZnJyA/IEJ1ZmZlci5mcm9tKGRhdGEucmVzdWx0LCAnYmFzZTY0JykgOiBkYXRhLnJlc3VsdFxyXG4gICAgICAgICAgICApO1xyXG4gICAgICAgICAgfVxyXG4gICAgICAgIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICAgICAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoXHJcbiAgICAgICAgICAgICdbY2hhcnRdIEVycm9yIHdoaWxlIHNhdmluZyBhIGNoYXJ0LicsXHJcbiAgICAgICAgICAgIDUwMFxyXG4gICAgICAgICAgKS5zZXRFcnJvcihlcnJvcik7XHJcbiAgICAgICAgfVxyXG5cclxuICAgICAgICAvLyBLaWxsIHBvb2wgYW5kIGNsb3NlIGJyb3dzZXIgYWZ0ZXIgZmluaXNoaW5nIHNpbmdsZSBleHBvcnRcclxuICAgICAgICBhd2FpdCBraWxsUG9vbCgpO1xyXG4gICAgICB9XHJcbiAgICApO1xyXG4gIH0gZWxzZSB7XHJcbiAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoXHJcbiAgICAgICdbY2hhcnRdIE5vIGV4cGVjdGVkIGBleHBvcnRgIG9wdGlvbnMgd2VyZSBmb3VuZC4gUGxlYXNlIHByb3ZpZGUgb25lIG9mIHRoZSBmb2xsb3dpbmcgb3B0aW9uczogYGluZmlsZWAsIGBpbnN0cmAsIGBvcHRpb25zYCwgb3IgYHN2Z2AgdG8gZ2VuZXJhdGUgYSB2YWxpZCBpbWFnZS4nLFxyXG4gICAgICA0MDBcclxuICAgICk7XHJcbiAgfVxyXG59XHJcblxyXG4vKipcclxuICogU3RhcnRzIGEgYmF0Y2ggZXhwb3J0IHByb2Nlc3MgZm9yIG11bHRpcGxlIGNoYXJ0cyBiYXNlZCBvbiBpbmZvcm1hdGlvblxyXG4gKiBwcm92aWRlZCBpbiB0aGUgYGJhdGNoYCBvcHRpb24uIFRoZSBgYmF0Y2hgIGlzIGEgc3RyaW5nIGluIHRoZSBmb2xsb3dpbmdcclxuICogZm9ybWF0OiBcImluZmlsZTEuanNvbj1vdXRmaWxlMS5wbmc7aW5maWxlMi5qc29uPW91dGZpbGUyLnBuZzsuLi5cIi4gUmVzdWx0c1xyXG4gKiBhcmUgc2F2ZWQgdG8gdGhlIHNwZWNpZmllZCBvdXRwdXQgZmlsZXMuXHJcbiAqXHJcbiAqIEBhc3luY1xyXG4gKiBAZnVuY3Rpb24gYmF0Y2hFeHBvcnRcclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IG9wdGlvbnMgLSBUaGUgYG9wdGlvbnNgIG9iamVjdCwgd2hpY2ggc2hvdWxkIGluY2x1ZGUgc2V0dGluZ3NcclxuICogZnJvbSB0aGUgYGV4cG9ydGAgYW5kIGBjdXN0b21Mb2dpY2Agc2VjdGlvbnMuIEl0IGNhbiBiZSBhIHBhcnRpYWwgb3IgY29tcGxldGVcclxuICogc2V0IG9mIG9wdGlvbnMgZnJvbSB0aGVzZSBzZWN0aW9ucy4gSXQgbXVzdCBjb250YWluIHRoZSBgYmF0Y2hgIG9wdGlvbiBmcm9tXHJcbiAqIHRoZSBgZXhwb3J0YCBzZWN0aW9uIHRvIGdlbmVyYXRlIHZhbGlkIGltYWdlcy5cclxuICpcclxuICogQHJldHVybnMge1Byb21pc2U8dm9pZD59IEEgUHJvbWlzZSB0aGF0IHJlc29sdmVzIG9uY2UgdGhlIGJhdGNoIGV4cG9ydFxyXG4gKiBwcm9jZXNzZXMgYXJlIGNvbXBsZXRlZC5cclxuICpcclxuICogQHRocm93cyB7RXhwb3J0RXJyb3J9IFRocm93cyBhbiBgRXhwb3J0RXJyb3JgIGlmIGFuIGVycm9yIG9jY3VycyBkdXJpbmdcclxuICogYW55IG9mIHRoZSBiYXRjaCBleHBvcnQgcHJvY2Vzcy5cclxuICovXHJcbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBiYXRjaEV4cG9ydChvcHRpb25zKSB7XHJcbiAgLy8gQ2hlY2sgaWYgdGhlIGV4cG9ydCBtYWtlcyBzZW5zZVxyXG4gIGlmIChvcHRpb25zICYmIG9wdGlvbnMuZXhwb3J0ICYmIG9wdGlvbnMuZXhwb3J0LmJhdGNoKSB7XHJcbiAgICAvLyBWYWxpZGF0ZSBiYXRjaCBleHBvcnQgb3B0aW9uc1xyXG4gICAgb3B0aW9ucyA9IHZhbGlkYXRlT3B0aW9ucyhvcHRpb25zKTtcclxuXHJcbiAgICAvLyBBbiBhcnJheSBmb3IgY29sbGVjdGluZyBiYXRjaCBleHBvcnRzXHJcbiAgICBjb25zdCBiYXRjaEZ1bmN0aW9ucyA9IFtdO1xyXG5cclxuICAgIC8vIFNwbGl0IGFuZCBwYWlyIHRoZSBgYmF0Y2hgIGFyZ3VtZW50c1xyXG4gICAgZm9yIChsZXQgcGFpciBvZiBvcHRpb25zLmV4cG9ydC5iYXRjaC5zcGxpdCgnOycpIHx8IFtdKSB7XHJcbiAgICAgIHBhaXIgPSBwYWlyLnNwbGl0KCc9Jyk7XHJcbiAgICAgIGlmIChwYWlyLmxlbmd0aCA9PT0gMikge1xyXG4gICAgICAgIGJhdGNoRnVuY3Rpb25zLnB1c2goXHJcbiAgICAgICAgICBzdGFydEV4cG9ydChcclxuICAgICAgICAgICAge1xyXG4gICAgICAgICAgICAgIGV4cG9ydDoge1xyXG4gICAgICAgICAgICAgICAgLi4ub3B0aW9ucy5leHBvcnQsXHJcbiAgICAgICAgICAgICAgICBpbmZpbGU6IHBhaXJbMF0sXHJcbiAgICAgICAgICAgICAgICBvdXRmaWxlOiBwYWlyWzFdXHJcbiAgICAgICAgICAgICAgfSxcclxuICAgICAgICAgICAgICBjdXN0b21Mb2dpYzogb3B0aW9ucy5jdXN0b21Mb2dpY1xyXG4gICAgICAgICAgICB9LFxyXG4gICAgICAgICAgICAoZXJyb3IsIGRhdGEpID0+IHtcclxuICAgICAgICAgICAgICAvLyBFeGl0IHByb2Nlc3Mgd2hlbiBlcnJvciBleGlzdHNcclxuICAgICAgICAgICAgICBpZiAoZXJyb3IpIHtcclxuICAgICAgICAgICAgICAgIHRocm93IGVycm9yO1xyXG4gICAgICAgICAgICAgIH1cclxuXHJcbiAgICAgICAgICAgICAgLy8gR2V0IHRoZSBgYjY0YCwgYG91dGZpbGVgLCBhbmQgYHR5cGVgIGZvciBhIGNoYXJ0XHJcbiAgICAgICAgICAgICAgY29uc3QgeyBiNjQsIG91dGZpbGUsIHR5cGUgfSA9IGRhdGEub3B0aW9ucy5leHBvcnQ7XHJcblxyXG4gICAgICAgICAgICAgIC8vIFNhdmUgdGhlIHJlc3VsdFxyXG4gICAgICAgICAgICAgIHRyeSB7XHJcbiAgICAgICAgICAgICAgICBpZiAoYjY0KSB7XHJcbiAgICAgICAgICAgICAgICAgIC8vIEFzIGEgQmFzZTY0IHN0cmluZyB0byBhIHR4dCBmaWxlXHJcbiAgICAgICAgICAgICAgICAgIHdyaXRlRmlsZVN5bmMoXHJcbiAgICAgICAgICAgICAgICAgICAgYCR7b3V0ZmlsZS5zcGxpdCgnLicpLnNoaWZ0KCkgfHwgJ2NoYXJ0J30udHh0YCxcclxuICAgICAgICAgICAgICAgICAgICBnZXRCYXNlNjQoZGF0YS5yZXN1bHQsIHR5cGUpXHJcbiAgICAgICAgICAgICAgICAgICk7XHJcbiAgICAgICAgICAgICAgICB9IGVsc2Uge1xyXG4gICAgICAgICAgICAgICAgICAvLyBBcyBhIGNvcnJlY3QgaW1hZ2UgZm9ybWF0XHJcbiAgICAgICAgICAgICAgICAgIHdyaXRlRmlsZVN5bmMoXHJcbiAgICAgICAgICAgICAgICAgICAgb3V0ZmlsZSxcclxuICAgICAgICAgICAgICAgICAgICB0eXBlICE9PSAnc3ZnJ1xyXG4gICAgICAgICAgICAgICAgICAgICAgPyBCdWZmZXIuZnJvbShkYXRhLnJlc3VsdCwgJ2Jhc2U2NCcpXHJcbiAgICAgICAgICAgICAgICAgICAgICA6IGRhdGEucmVzdWx0XHJcbiAgICAgICAgICAgICAgICAgICk7XHJcbiAgICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgICAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICAgICAgICAgICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcihcclxuICAgICAgICAgICAgICAgICAgJ1tjaGFydF0gRXJyb3Igd2hpbGUgc2F2aW5nIGEgY2hhcnQuJyxcclxuICAgICAgICAgICAgICAgICAgNTAwXHJcbiAgICAgICAgICAgICAgICApLnNldEVycm9yKGVycm9yKTtcclxuICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgIH1cclxuICAgICAgICAgIClcclxuICAgICAgICApO1xyXG4gICAgICB9IGVsc2Uge1xyXG4gICAgICAgIGxvZygyLCAnW2NoYXJ0XSBObyBjb3JyZWN0IHBhaXIgZm91bmQgZm9yIHRoZSBiYXRjaCBleHBvcnQuJyk7XHJcbiAgICAgIH1cclxuICAgIH1cclxuXHJcbiAgICAvLyBBd2FpdCBhbGwgZXhwb3J0cyBhcmUgZG9uZVxyXG4gICAgY29uc3QgYmF0Y2hSZXN1bHRzID0gYXdhaXQgUHJvbWlzZS5hbGxTZXR0bGVkKGJhdGNoRnVuY3Rpb25zKTtcclxuXHJcbiAgICAvLyBLaWxsIHBvb2wgYW5kIGNsb3NlIGJyb3dzZXIgYWZ0ZXIgZmluaXNoaW5nIGJhdGNoIGV4cG9ydFxyXG4gICAgYXdhaXQga2lsbFBvb2woKTtcclxuXHJcbiAgICAvLyBMb2cgZXJyb3JzIGlmIGZvdW5kXHJcbiAgICBiYXRjaFJlc3VsdHMuZm9yRWFjaCgocmVzdWx0LCBpbmRleCkgPT4ge1xyXG4gICAgICAvLyBMb2cgdGhlIGVycm9yIHdpdGggc3RhY2sgYWJvdXQgdGhlIHNwZWNpZmljIGJhdGNoIGV4cG9ydFxyXG4gICAgICBpZiAocmVzdWx0LnJlYXNvbikge1xyXG4gICAgICAgIGxvZ1dpdGhTdGFjayhcclxuICAgICAgICAgIDEsXHJcbiAgICAgICAgICByZXN1bHQucmVhc29uLFxyXG4gICAgICAgICAgYFtjaGFydF0gQmF0Y2ggZXhwb3J0IG51bWJlciAke2luZGV4ICsgMX0gY291bGQgbm90IGJlIGNvcnJlY3RseSBjb21wbGV0ZWQuYFxyXG4gICAgICAgICk7XHJcbiAgICAgIH1cclxuICAgIH0pO1xyXG4gIH0gZWxzZSB7XHJcbiAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoXHJcbiAgICAgICdbY2hhcnRdIE5vIGV4cGVjdGVkIGBleHBvcnRgIG9wdGlvbnMgd2VyZSBmb3VuZC4gUGxlYXNlIHByb3ZpZGUgdGhlIGBiYXRjaGAgb3B0aW9uIHRvIGdlbmVyYXRlIHZhbGlkIGltYWdlcy4nLFxyXG4gICAgICA0MDBcclxuICAgICk7XHJcbiAgfVxyXG59XHJcblxyXG4vKipcclxuICogU3RhcnRzIGFuIGV4cG9ydCBwcm9jZXNzLiBUaGUgYGV4cG9ydGluZ09wdGlvbnNgIHBhcmFtZXRlciBpcyBhbiBvYmplY3QgdGhhdFxyXG4gKiBzaG91bGQgaW5jbHVkZSBzZXR0aW5ncyBmcm9tIHRoZSBgZXhwb3J0YCBhbmQgYGN1c3RvbUxvZ2ljYCBzZWN0aW9ucy4gSXQgY2FuXHJcbiAqIGJlIGEgcGFydGlhbCBvciBjb21wbGV0ZSBzZXQgb2Ygb3B0aW9ucyBmcm9tIHRoZXNlIHNlY3Rpb25zLiBJZiBwYXJ0aWFsXHJcbiAqIG9wdGlvbnMgYXJlIHByb3ZpZGVkLCBtaXNzaW5nIHZhbHVlcyB3aWxsIGJlIG1lcmdlZCB3aXRoIHRoZSBjdXJyZW50IGdsb2JhbFxyXG4gKiBvcHRpb25zLlxyXG4gKlxyXG4gKiBUaGUgYGVuZENhbGxiYWNrYCBmdW5jdGlvbiBpcyBpbnZva2VkIHVwb24gdGhlIGNvbXBsZXRpb24gb2YgdGhlIGV4cG9ydCxcclxuICogZWl0aGVyIHN1Y2Nlc3NmdWxseSBvciB3aXRoIGFuIGVycm9yLiBUaGUgYGVycm9yYCBvYmplY3QgaXMgcHJvdmlkZWRcclxuICogYXMgdGhlIGZpcnN0IGFyZ3VtZW50LCBhbmQgdGhlIGBkYXRhYCBvYmplY3QgaXMgdGhlIHNlY29uZCwgY29udGFpbmluZ1xyXG4gKiB0aGUgQmFzZTY0IHJlcHJlc2VudGF0aW9uIG9mIHRoZSBjaGFydCBpbiB0aGUgYHJlc3VsdGAgcHJvcGVydHlcclxuICogYW5kIHRoZSBjb21wbGV0ZSBzZXQgb2Ygb3B0aW9ucyBpbiB0aGUgYG9wdGlvbnNgIHByb3BlcnR5LlxyXG4gKlxyXG4gKiBAYXN5bmNcclxuICogQGZ1bmN0aW9uIHN0YXJ0RXhwb3J0XHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBleHBvcnRpbmdPcHRpb25zIC0gVGhlIGBleHBvcnRpbmdPcHRpb25zYCBvYmplY3QsIHdoaWNoXHJcbiAqIHNob3VsZCBpbmNsdWRlIHNldHRpbmdzIGZyb20gdGhlIGBleHBvcnRgIGFuZCBgY3VzdG9tTG9naWNgIHNlY3Rpb25zLiBJdCBjYW5cclxuICogYmUgYSBwYXJ0aWFsIG9yIGNvbXBsZXRlIHNldCBvZiBvcHRpb25zIGZyb20gdGhlc2Ugc2VjdGlvbnMuIElmIHRoZSBwcm92aWRlZFxyXG4gKiBvcHRpb25zIGFyZSBwYXJ0aWFsLCBtaXNzaW5nIHZhbHVlcyB3aWxsIGJlIG1lcmdlZCB3aXRoIHRoZSBjdXJyZW50IGdsb2JhbFxyXG4gKiBvcHRpb25zLlxyXG4gKiBAcGFyYW0ge0Z1bmN0aW9ufSBlbmRDYWxsYmFjayAtIFRoZSBjYWxsYmFjayBmdW5jdGlvbiB0byBiZSBpbnZva2VkIHVwb25cclxuICogZmluYWxpemluZyB0aGUgZXhwb3J0IHByb2Nlc3Mgb3IgdXBvbiBlbmNvdW50ZXJpbmcgYW4gZXJyb3IuIFRoZSBmaXJzdFxyXG4gKiBhcmd1bWVudCBpcyB0aGUgYGVycm9yYCBvYmplY3QsIGFuZCB0aGUgc2Vjb25kIGFyZ3VtZW50IGlzIHRoZSBgZGF0YWAgb2JqZWN0LFxyXG4gKiB3aGljaCBpbmNsdWRlcyB0aGUgQmFzZTY0IHJlcHJlc2VudGF0aW9uIG9mIHRoZSBjaGFydCBpbiB0aGUgYHJlc3VsdGBcclxuICogcHJvcGVydHkgYW5kIHRoZSBmdWxsIHNldCBvZiBvcHRpb25zIGluIHRoZSBgb3B0aW9uc2AgcHJvcGVydHkuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtQcm9taXNlPHZvaWQ+fSBUaGlzIGZ1bmN0aW9uIGRvZXMgbm90IHJldHVybiBhIHZhbHVlIGRpcmVjdGx5LlxyXG4gKiBJbnN0ZWFkLCBpdCBjb21tdW5pY2F0ZXMgcmVzdWx0cyB2aWEgdGhlIGBlbmRDYWxsYmFja2AuXHJcbiAqXHJcbiAqIEB0aHJvd3Mge0V4cG9ydEVycm9yfSBUaHJvd3MgYW4gYEV4cG9ydEVycm9yYCBpZiB0aGVyZSBpcyBhIHByb2JsZW0gd2l0aFxyXG4gKiBwcm9jZXNzaW5nIGlucHV0IG9mIGFueSB0eXBlLiBUaGUgZXJyb3IgaXMgcGFzc2VkIGludG8gdGhlIGBlbmRDYWxsYmFja2BcclxuICogZnVuY3Rpb24gYW5kIHByb2Nlc3NlZCB0aGVyZS5cclxuICovXHJcbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBzdGFydEV4cG9ydChleHBvcnRpbmdPcHRpb25zLCBlbmRDYWxsYmFjaykge1xyXG4gIHRyeSB7XHJcbiAgICAvLyBDaGVjayBpZiBwcm92aWRlZCBvcHRpb25zIGlzIGFuIG9iamVjdFxyXG4gICAgaWYgKCFpc09iamVjdChleHBvcnRpbmdPcHRpb25zKSkge1xyXG4gICAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoXHJcbiAgICAgICAgJ1tjaGFydF0gSW5jb3JyZWN0IHZhbHVlIG9mIHRoZSBwcm92aWRlZCBgZXhwb3J0aW5nT3B0aW9uc2AuIE5lZWRzIHRvIGJlIGFuIG9iamVjdC4nLFxyXG4gICAgICAgIDQwMFxyXG4gICAgICApO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIE1lcmdlIGFkZGl0aW9uYWwgb3B0aW9ucyB0byB0aGUgY29weSBvZiB0aGUgaW5zdGFuY2Ugb3B0aW9uc1xyXG4gICAgY29uc3Qgb3B0aW9ucyA9IG1lcmdlT3B0aW9ucyhkZWVwQ29weShnZXRPcHRpb25zKCkpLCB7XHJcbiAgICAgIGV4cG9ydDogZXhwb3J0aW5nT3B0aW9ucy5leHBvcnQsXHJcbiAgICAgIGN1c3RvbUxvZ2ljOiBleHBvcnRpbmdPcHRpb25zLmN1c3RvbUxvZ2ljXHJcbiAgICB9KTtcclxuXHJcbiAgICAvLyBHZXQgdGhlIGBleHBvcnRgIG9wdGlvbnNcclxuICAgIGNvbnN0IGV4cG9ydE9wdGlvbnMgPSBvcHRpb25zLmV4cG9ydDtcclxuXHJcbiAgICAvLyBTdGFydGluZyBleHBvcnRpbmcgcHJvY2VzcyBtZXNzYWdlXHJcbiAgICBsb2coNCwgJ1tjaGFydF0gU3RhcnRpbmcgdGhlIGV4cG9ydGluZyBwcm9jZXNzLicpO1xyXG5cclxuICAgIC8vIEV4cG9ydCB1c2luZyBvcHRpb25zIGZyb20gdGhlIGZpbGUgYXMgYW4gaW5wdXRcclxuICAgIGlmIChleHBvcnRPcHRpb25zLmluZmlsZSAhPT0gbnVsbCkge1xyXG4gICAgICBsb2coNCwgJ1tjaGFydF0gQXR0ZW1wdGluZyB0byBleHBvcnQgZnJvbSBhIGZpbGUgaW5wdXQuJyk7XHJcblxyXG4gICAgICBsZXQgZmlsZUNvbnRlbnQ7XHJcbiAgICAgIHRyeSB7XHJcbiAgICAgICAgLy8gVHJ5IHRvIHJlYWQgdGhlIGZpbGUgdG8gZ2V0IHRoZSBzdHJpbmcgcmVwcmVzZW50YXRpb25cclxuICAgICAgICBmaWxlQ29udGVudCA9IHJlYWRGaWxlU3luYyhcclxuICAgICAgICAgIGdldEFic29sdXRlUGF0aChleHBvcnRPcHRpb25zLmluZmlsZSksXHJcbiAgICAgICAgICAndXRmOCdcclxuICAgICAgICApO1xyXG4gICAgICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcihcclxuICAgICAgICAgICdbY2hhcnRdIEVycm9yIGxvYWRpbmcgY29udGVudCBmcm9tIGEgZmlsZSBpbnB1dC4nLFxyXG4gICAgICAgICAgNDAwXHJcbiAgICAgICAgKS5zZXRFcnJvcihlcnJvcik7XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIC8vIENoZWNrIHRoZSBmaWxlJ3MgZXh0ZW5zaW9uXHJcbiAgICAgIGlmIChleHBvcnRPcHRpb25zLmluZmlsZS5lbmRzV2l0aCgnLnN2ZycpKSB7XHJcbiAgICAgICAgLy8gU2V0IHRvIHRoZSBgc3ZnYCBvcHRpb25cclxuICAgICAgICBleHBvcnRPcHRpb25zLnN2ZyA9IHZhbGlkYXRlT3B0aW9uKCdzdmcnLCBmaWxlQ29udGVudCk7XHJcbiAgICAgIH0gZWxzZSBpZiAoZXhwb3J0T3B0aW9ucy5pbmZpbGUuZW5kc1dpdGgoJy5qc29uJykpIHtcclxuICAgICAgICAvLyBTZXQgdG8gdGhlIGBpbnN0cmAgb3B0aW9uXHJcbiAgICAgICAgZXhwb3J0T3B0aW9ucy5pbnN0ciA9IHZhbGlkYXRlT3B0aW9uKCdpbnN0cicsIGZpbGVDb250ZW50KTtcclxuICAgICAgfSBlbHNlIHtcclxuICAgICAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoXHJcbiAgICAgICAgICAnW2NoYXJ0XSBJbmNvcnJlY3QgdmFsdWUgb2YgdGhlIGBpbmZpbGVgIG9wdGlvbi4nLFxyXG4gICAgICAgICAgNDAwXHJcbiAgICAgICAgKTtcclxuICAgICAgfVxyXG4gICAgfVxyXG5cclxuICAgIC8vIEV4cG9ydCB1c2luZyBTVkcgYXMgYW4gaW5wdXRcclxuICAgIGlmIChleHBvcnRPcHRpb25zLnN2ZyAhPT0gbnVsbCkge1xyXG4gICAgICBsb2coNCwgJ1tjaGFydF0gQXR0ZW1wdGluZyB0byBleHBvcnQgZnJvbSBhbiBTVkcgaW5wdXQuJyk7XHJcblxyXG4gICAgICAvLyBTVkcgZXhwb3J0cyBhdHRlbXB0cyBjb3VudGVyXHJcbiAgICAgICsrZ2V0UG9vbFN0YXRzKCkuZXhwb3J0c0Zyb21TdmdBdHRlbXB0cztcclxuXHJcbiAgICAgIC8vIEV4cG9ydCBmcm9tIGFuIFNWRyBzdHJpbmdcclxuICAgICAgY29uc3QgcmVzdWx0ID0gYXdhaXQgX2V4cG9ydEZyb21TdmcoXHJcbiAgICAgICAgc2FuaXRpemUoZXhwb3J0T3B0aW9ucy5zdmcpLCAvLyAjMjA5XHJcbiAgICAgICAgb3B0aW9uc1xyXG4gICAgICApO1xyXG5cclxuICAgICAgLy8gU1ZHIGV4cG9ydHMgY291bnRlclxyXG4gICAgICArK2dldFBvb2xTdGF0cygpLmV4cG9ydHNGcm9tU3ZnO1xyXG5cclxuICAgICAgLy8gUGFzcyBTVkcgZXhwb3J0IHJlc3VsdCB0byB0aGUgZW5kIGNhbGxiYWNrXHJcbiAgICAgIHJldHVybiBlbmRDYWxsYmFjayhudWxsLCByZXN1bHQpO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIEV4cG9ydCB1c2luZyBvcHRpb25zIGFzIGFuIGlucHV0XHJcbiAgICBpZiAoZXhwb3J0T3B0aW9ucy5pbnN0ciAhPT0gbnVsbCB8fCBleHBvcnRPcHRpb25zLm9wdGlvbnMgIT09IG51bGwpIHtcclxuICAgICAgbG9nKDQsICdbY2hhcnRdIEF0dGVtcHRpbmcgdG8gZXhwb3J0IGZyb20gb3B0aW9ucyBpbnB1dC4nKTtcclxuXHJcbiAgICAgIC8vIE9wdGlvbnMgZXhwb3J0cyBhdHRlbXB0cyBjb3VudGVyXHJcbiAgICAgICsrZ2V0UG9vbFN0YXRzKCkuZXhwb3J0c0Zyb21PcHRpb25zQXR0ZW1wdHM7XHJcblxyXG4gICAgICAvLyBFeHBvcnQgZnJvbSBvcHRpb25zXHJcbiAgICAgIGNvbnN0IHJlc3VsdCA9IGF3YWl0IF9leHBvcnRGcm9tT3B0aW9ucyhcclxuICAgICAgICBleHBvcnRPcHRpb25zLmluc3RyIHx8IGV4cG9ydE9wdGlvbnMub3B0aW9ucyxcclxuICAgICAgICBvcHRpb25zXHJcbiAgICAgICk7XHJcblxyXG4gICAgICAvLyBPcHRpb25zIGV4cG9ydHMgY291bnRlclxyXG4gICAgICArK2dldFBvb2xTdGF0cygpLmV4cG9ydHNGcm9tT3B0aW9ucztcclxuXHJcbiAgICAgIC8vIFBhc3Mgb3B0aW9ucyBleHBvcnQgcmVzdWx0IHRvIHRoZSBlbmQgY2FsbGJhY2tcclxuICAgICAgcmV0dXJuIGVuZENhbGxiYWNrKG51bGwsIHJlc3VsdCk7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gTm8gaW5wdXQgc3BlY2lmaWVkLCBwYXNzIGFuIGVycm9yIG1lc3NhZ2UgdG8gdGhlIGNhbGxiYWNrXHJcbiAgICByZXR1cm4gZW5kQ2FsbGJhY2soXHJcbiAgICAgIG5ldyBFeHBvcnRFcnJvcihcclxuICAgICAgICBgW2NoYXJ0XSBObyB2YWxpZCBpbnB1dCBzcGVjaWZpZWQuIENoZWNrIGlmIGF0IGxlYXN0IG9uZSBvZiB0aGUgZm9sbG93aW5nIHBhcmFtZXRlcnMgaXMgY29ycmVjdGx5IHNldDogJ2luZmlsZScsICdpbnN0cicsICdvcHRpb25zJywgb3IgJ3N2ZycuYCxcclxuICAgICAgICA0MDBcclxuICAgICAgKVxyXG4gICAgKTtcclxuICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgcmV0dXJuIGVuZENhbGxiYWNrKGVycm9yKTtcclxuICB9XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBSZXRyaWV2ZXMgYW5kIHJldHVybnMgdGhlIGN1cnJlbnQgc3RhdHVzIG9mIHRoZSBjb2RlIGV4ZWN1dGlvbiBwZXJtaXNzaW9uLlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gZ2V0QWxsb3dDb2RlRXhlY3V0aW9uXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtib29sZWFufSBUaGUgdmFsdWUgb2YgdGhlIGdsb2JhbCBgYWxsb3dDb2RlRXhlY3V0aW9uYCBvcHRpb24uXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gZ2V0QWxsb3dDb2RlRXhlY3V0aW9uKCkge1xyXG4gIHJldHVybiBhbGxvd0NvZGVFeGVjdXRpb247XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBTZXRzIHRoZSBjb2RlIGV4ZWN1dGlvbiBwZXJtaXNzaW9uIGJhc2VkIG9uIHRoZSBwcm92aWRlZCBib29sZWFuIHZhbHVlLlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gc2V0QWxsb3dDb2RlRXhlY3V0aW9uXHJcbiAqXHJcbiAqIEBwYXJhbSB7Ym9vbGVhbn0gdmFsdWUgLSBUaGUgYm9vbGVhbiB2YWx1ZSB0byBiZSBhc3NpZ25lZCB0byB0aGUgZ2xvYmFsXHJcbiAqIGBhbGxvd0NvZGVFeGVjdXRpb25gIG9wdGlvbi5cclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiBzZXRBbGxvd0NvZGVFeGVjdXRpb24odmFsdWUpIHtcclxuICBhbGxvd0NvZGVFeGVjdXRpb24gPSB2YWx1ZTtcclxufVxyXG5cclxuLyoqXHJcbiAqIEV4cG9ydHMgZnJvbSBhbiBTVkcgYmFzZWQgaW5wdXQgd2l0aCB0aGUgcHJvdmlkZWQgb3B0aW9ucy5cclxuICpcclxuICogQGFzeW5jXHJcbiAqIEBmdW5jdGlvbiBfZXhwb3J0RnJvbVN2Z1xyXG4gKlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gaW5wdXRUb0V4cG9ydCAtIFRoZSBTVkcgYmFzZWQgaW5wdXQgdG8gYmUgZXhwb3J0ZWQuXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBvcHRpb25zIC0gVGhlIGNvbmZpZ3VyYXRpb24gb2JqZWN0IGNvbnRhaW5pbmcgY29tcGxldGUgc2V0XHJcbiAqIG9mIG9wdGlvbnMuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtQcm9taXNlPHVua25vd24+fSBBIFByb21pc2UgdGhhdCByZXNvbHZlcyB0byBhIHJlc3VsdCBvZiB0aGUgZXhwb3J0XHJcbiAqIHByb2Nlc3MuXHJcbiAqXHJcbiAqIEB0aHJvd3Mge0V4cG9ydEVycm9yfSBUaHJvd3MgYW4gYEV4cG9ydEVycm9yYCBpZiB0aGVyZSBpcyBub3QgYSBjb3JyZWN0IFNWR1xyXG4gKiBpbnB1dC5cclxuICovXHJcbmFzeW5jIGZ1bmN0aW9uIF9leHBvcnRGcm9tU3ZnKGlucHV0VG9FeHBvcnQsIG9wdGlvbnMpIHtcclxuICAvLyBDaGVjayBpZiBpdCBpcyBTVkdcclxuICBpZiAoXHJcbiAgICB0eXBlb2YgaW5wdXRUb0V4cG9ydCA9PT0gJ3N0cmluZycgJiZcclxuICAgIChpbnB1dFRvRXhwb3J0LmluZGV4T2YoJzxzdmcnKSA+PSAwIHx8IGlucHV0VG9FeHBvcnQuaW5kZXhPZignPD94bWwnKSA+PSAwKVxyXG4gICkge1xyXG4gICAgbG9nKDQsICdbY2hhcnRdIFBhcnNpbmcgaW5wdXQgYXMgU1ZHLicpO1xyXG5cclxuICAgIC8vIFNldCB0aGUgZXhwb3J0IGlucHV0IGFzIFNWR1xyXG4gICAgb3B0aW9ucy5leHBvcnQuc3ZnID0gaW5wdXRUb0V4cG9ydDtcclxuXHJcbiAgICAvLyBSZXNldCB0aGUgcmVzdCBvZiB0aGUgZXhwb3J0IGlucHV0IG9wdGlvbnNcclxuICAgIG9wdGlvbnMuZXhwb3J0Lmluc3RyID0gbnVsbDtcclxuICAgIG9wdGlvbnMuZXhwb3J0Lm9wdGlvbnMgPSBudWxsO1xyXG5cclxuICAgIC8vIENhbGwgdGhlIGZ1bmN0aW9uIHdpdGggYW4gU1ZHIHN0cmluZyBhcyBhbiBleHBvcnQgaW5wdXRcclxuICAgIHJldHVybiBfcHJlcGFyZUV4cG9ydChvcHRpb25zKTtcclxuICB9IGVsc2Uge1xyXG4gICAgdGhyb3cgbmV3IEV4cG9ydEVycm9yKCdbY2hhcnRdIE5vdCBhIGNvcnJlY3QgU1ZHIGlucHV0LicsIDQwMCk7XHJcbiAgfVxyXG59XHJcblxyXG4vKipcclxuICogRXhwb3J0cyBmcm9tIGFuIG9wdGlvbnMgYmFzZWQgaW5wdXQgd2l0aCB0aGUgcHJvdmlkZWQgb3B0aW9ucy5cclxuICpcclxuICogQGFzeW5jXHJcbiAqIEBmdW5jdGlvbiBfZXhwb3J0RnJvbU9wdGlvbnNcclxuICpcclxuICogQHBhcmFtIHtzdHJpbmd9IGlucHV0VG9FeHBvcnQgLSBUaGUgb3B0aW9ucyBiYXNlZCBpbnB1dCB0byBiZSBleHBvcnRlZC5cclxuICogQHBhcmFtIHtPYmplY3R9IG9wdGlvbnMgLSBUaGUgY29uZmlndXJhdGlvbiBvYmplY3QgY29udGFpbmluZyBjb21wbGV0ZSBzZXRcclxuICogb2Ygb3B0aW9ucy5cclxuICpcclxuICogQHJldHVybnMge1Byb21pc2U8dW5rbm93bj59IEEgUHJvbWlzZSB0aGF0IHJlc29sdmVzIHRvIGEgcmVzdWx0IG9mIHRoZSBleHBvcnRcclxuICogcHJvY2Vzcy5cclxuICpcclxuICogQHRocm93cyB7RXhwb3J0RXJyb3J9IFRocm93cyBhbiBgRXhwb3J0RXJyb3JgIGlmIHRoZXJlIGlzIG5vdCBhIGNvcnJlY3RcclxuICogY2hhcnQgb3B0aW9ucyBpbnB1dC5cclxuICovXHJcbmFzeW5jIGZ1bmN0aW9uIF9leHBvcnRGcm9tT3B0aW9ucyhpbnB1dFRvRXhwb3J0LCBvcHRpb25zKSB7XHJcbiAgbG9nKDQsICdbY2hhcnRdIFBhcnNpbmcgaW5wdXQgZnJvbSBvcHRpb25zLicpO1xyXG5cclxuICAvLyBUcnkgdG8gY2hlY2ssIHZhbGlkYXRlIGFuZCBwYXJzZSB0byBzdHJpbmdpZmllZCBvcHRpb25zXHJcbiAgY29uc3Qgc3RyaW5naWZpZWRPcHRpb25zID0gaXNBbGxvd2VkQ29uZmlnKFxyXG4gICAgaW5wdXRUb0V4cG9ydCxcclxuICAgIHRydWUsXHJcbiAgICBvcHRpb25zLmN1c3RvbUxvZ2ljLmFsbG93Q29kZUV4ZWN1dGlvblxyXG4gICk7XHJcblxyXG4gIC8vIENoZWNrIGlmIGEgY29ycmVjdCBzdHJpbmdpZmllZCBvcHRpb25zXHJcbiAgaWYgKFxyXG4gICAgc3RyaW5naWZpZWRPcHRpb25zID09PSBudWxsIHx8XHJcbiAgICB0eXBlb2Ygc3RyaW5naWZpZWRPcHRpb25zICE9PSAnc3RyaW5nJyB8fFxyXG4gICAgIXN0cmluZ2lmaWVkT3B0aW9ucy5zdGFydHNXaXRoKCd7JykgfHxcclxuICAgICFzdHJpbmdpZmllZE9wdGlvbnMuZW5kc1dpdGgoJ30nKVxyXG4gICkge1xyXG4gICAgdGhyb3cgbmV3IEV4cG9ydEVycm9yKFxyXG4gICAgICAnW2NoYXJ0XSBJbnZhbGlkIGNvbmZpZ3VyYXRpb24gcHJvdmlkZWQgLSBPbmx5IG9wdGlvbnMgY29uZmlndXJhdGlvbnMgYW5kIFNWRyBhcmUgYWxsb3dlZCBmb3IgdGhpcyBzZXJ2ZXIuIElmIHRoaXMgaXMgeW91ciBzZXJ2ZXIsIEphdmFTY3JpcHQgY3VzdG9tIGNvZGUgY2FuIGJlIGVuYWJsZWQgYnkgc3RhcnRpbmcgdGhlIHNlcnZlciB3aXRoIHRoZSBgYWxsb3dDb2RlRXhlY3V0aW9uYCBvcHRpb25zIHNldCB0byB0cnVlLicsXHJcbiAgICAgIDQwM1xyXG4gICAgKTtcclxuICB9XHJcblxyXG4gIC8vIFNldCB0aGUgZXhwb3J0IGlucHV0IGFzIGEgc3RyaW5naWZpZWQgY2hhcnQgb3B0aW9uc1xyXG4gIG9wdGlvbnMuZXhwb3J0Lmluc3RyID0gc3RyaW5naWZpZWRPcHRpb25zO1xyXG5cclxuICAvLyBSZXNldCB0aGUgcmVzdCBvZiB0aGUgZXhwb3J0IGlucHV0IG9wdGlvbnNcclxuICBvcHRpb25zLmV4cG9ydC5zdmcgPSBudWxsO1xyXG5cclxuICAvLyBDYWxsIHRoZSBmdW5jdGlvbiB3aXRoIGEgc3RyaW5naWZpZWQgY2hhcnQgb3B0aW9uc1xyXG4gIHJldHVybiBfcHJlcGFyZUV4cG9ydChvcHRpb25zKTtcclxufVxyXG5cclxuLyoqXHJcbiAqIEZ1bmN0aW9uIGZvciBmaW5hbGl6aW5nIG9wdGlvbnMgYW5kIGNvbmZpZ3VyYXRpb25zIGJlZm9yZSBleHBvcnQuXHJcbiAqXHJcbiAqIEBhc3luY1xyXG4gKiBAZnVuY3Rpb24gX3ByZXBhcmVFeHBvcnRcclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IG9wdGlvbnMgLSBUaGUgY29uZmlndXJhdGlvbiBvYmplY3QgY29udGFpbmluZyBjb21wbGV0ZSBzZXRcclxuICogb2Ygb3B0aW9ucy5cclxuICpcclxuICogQHJldHVybnMge1Byb21pc2U8dW5rbm93bj59IEEgUHJvbWlzZSB0aGF0IHJlc29sdmVzIHRvIGEgcmVzdWx0IG9mIHRoZSBleHBvcnRcclxuICogcHJvY2Vzcy5cclxuICovXHJcbmFzeW5jIGZ1bmN0aW9uIF9wcmVwYXJlRXhwb3J0KG9wdGlvbnMpIHtcclxuICBjb25zdCB7IGV4cG9ydDogZXhwb3J0T3B0aW9ucywgY3VzdG9tTG9naWM6IGN1c3RvbUxvZ2ljT3B0aW9ucyB9ID0gb3B0aW9ucztcclxuXHJcbiAgLy8gUHJlcGFyZSB0aGUgYHR5cGVgIG9wdGlvblxyXG4gIGV4cG9ydE9wdGlvbnMudHlwZSA9IGZpeFR5cGUoZXhwb3J0T3B0aW9ucy50eXBlLCBleHBvcnRPcHRpb25zLm91dGZpbGUpO1xyXG5cclxuICAvLyBQcmVwYXJlIHRoZSBgb3V0ZmlsZWAgb3B0aW9uXHJcbiAgZXhwb3J0T3B0aW9ucy5vdXRmaWxlID0gZml4T3V0ZmlsZShleHBvcnRPcHRpb25zLnR5cGUsIGV4cG9ydE9wdGlvbnMub3V0ZmlsZSk7XHJcblxyXG4gIC8vIFByZXBhcmUgdGhlIGBjb25zdHJgIG9wdGlvblxyXG4gIGV4cG9ydE9wdGlvbnMuY29uc3RyID0gZml4Q29uc3RyKGV4cG9ydE9wdGlvbnMuY29uc3RyKTtcclxuXHJcbiAgLy8gTm90aWZ5IGFib3V0IHRoZSBjdXN0b20gbG9naWMgdXNhZ2Ugc3RhdHVzXHJcbiAgbG9nKFxyXG4gICAgMyxcclxuICAgIGBbY2hhcnRdIFRoZSBjdXN0b20gbG9naWMgaXMgJHtjdXN0b21Mb2dpY09wdGlvbnMuYWxsb3dDb2RlRXhlY3V0aW9uID8gJ2FsbG93ZWQnIDogJ2Rpc2FsbG93ZWQnfS5gXHJcbiAgKTtcclxuXHJcbiAgLy8gUHJlcGFyZSB0aGUgY3VzdG9tIGxvZ2ljIG9wdGlvbnMgKGBjdXN0b21Db2RlYCwgYGNhbGxiYWNrYCwgYHJlc291cmNlc2ApXHJcbiAgX2hhbmRsZUN1c3RvbUxvZ2ljKGN1c3RvbUxvZ2ljT3B0aW9ucywgY3VzdG9tTG9naWNPcHRpb25zLmFsbG93Q29kZUV4ZWN1dGlvbik7XHJcblxyXG4gIC8vIFByZXBhcmUgdGhlIGBnbG9iYWxPcHRpb25zYCBhbmQgYHRoZW1lT3B0aW9uc2Agb3B0aW9uc1xyXG4gIF9oYW5kbGVHbG9iYWxBbmRUaGVtZShcclxuICAgIGV4cG9ydE9wdGlvbnMsXHJcbiAgICBjdXN0b21Mb2dpY09wdGlvbnMuYWxsb3dGaWxlUmVzb3VyY2VzLFxyXG4gICAgY3VzdG9tTG9naWNPcHRpb25zLmFsbG93Q29kZUV4ZWN1dGlvblxyXG4gICk7XHJcblxyXG4gIC8vIFByZXBhcmUgdGhlIGBoZWlnaHRgLCBgd2lkdGhgLCBhbmQgYHNjYWxlYCBvcHRpb25zXHJcbiAgb3B0aW9ucy5leHBvcnQgPSB7XHJcbiAgICAuLi5leHBvcnRPcHRpb25zLFxyXG4gICAgLi4uX2ZpbmRDaGFydFNpemUoZXhwb3J0T3B0aW9ucylcclxuICB9O1xyXG5cclxuICAvLyBQb3N0IHRoZSB3b3JrIHRvIHRoZSBwb29sXHJcbiAgcmV0dXJuIHBvc3RXb3JrKG9wdGlvbnMpO1xyXG59XHJcblxyXG4vKipcclxuICogQ2FsY3VsYXRlcyB0aGUgYGhlaWdodGAsIGB3aWR0aGAgYW5kIGBzY2FsZWAgZm9yIGNoYXJ0IGV4cG9ydHMgYmFzZWRcclxuICogb24gdGhlIHByb3ZpZGVkIGV4cG9ydCBvcHRpb25zLlxyXG4gKlxyXG4gKiBUaGUgZnVuY3Rpb24gcHJpb3JpdGl6ZXMgdmFsdWVzIGluIHRoZSBmb2xsb3dpbmcgb3JkZXI6XHJcbiAqIDEuIFRoZSBgaGVpZ2h0YCwgYHdpZHRoYCwgYHNjYWxlYCBmcm9tIHRoZSBgZXhwb3J0T3B0aW9uc2AuXHJcbiAqIDIuIE9wdGlvbnMgZnJvbSB0aGUgY2hhcnQgY29uZmlndXJhdGlvbiAoZnJvbSBgZXhwb3J0aW5nYCBhbmQgYGNoYXJ0YCkuXHJcbiAqIDMuIE9wdGlvbnMgZnJvbSB0aGUgZ2xvYmFsIG9wdGlvbnMgKGZyb20gYGV4cG9ydGluZ2AgYW5kIGBjaGFydGApLlxyXG4gKiA0LiBPcHRpb25zIGZyb20gdGhlIHRoZW1lIG9wdGlvbnMgKGZyb20gYGV4cG9ydGluZ2AgYW5kIGBjaGFydGAgc2VjdGlvbnMpLlxyXG4gKiA1LiBGYWxsYmFjayBkZWZhdWx0IHZhbHVlcyAoYGhlaWdodCA9IDQwMGAsIGB3aWR0aCA9IDYwMGAsIGBzY2FsZSA9IDFgKS5cclxuICpcclxuICogQGZ1bmN0aW9uIF9maW5kQ2hhcnRTaXplXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBleHBvcnRPcHRpb25zIC0gVGhlIGNvbmZpZ3VyYXRpb24gb2JqZWN0IGNvbnRhaW5pbmcgYGV4cG9ydGBcclxuICogb3B0aW9ucy5cclxuICpcclxuICogQHJldHVybnMge09iamVjdH0gVGhlIG9iamVjdCBjb250YWluaW5nIGNhbGN1bGF0ZWQgYGhlaWdodGAsIGB3aWR0aGBcclxuICogYW5kIGBzY2FsZWAgdmFsdWVzIGZvciB0aGUgY2hhcnQgZXhwb3J0LlxyXG4gKi9cclxuZnVuY3Rpb24gX2ZpbmRDaGFydFNpemUoZXhwb3J0T3B0aW9ucykge1xyXG4gIC8vIENoZWNrIHRoZSBgb3B0aW9uc2AgYW5kIGBpbnN0cmAgZm9yIGNoYXJ0IGFuZCBleHBvcnRpbmcgc2VjdGlvbnNcclxuICBjb25zdCB7IGNoYXJ0OiBvcHRpb25zQ2hhcnQsIGV4cG9ydGluZzogb3B0aW9uc0V4cG9ydGluZyB9ID1cclxuICAgIGV4cG9ydE9wdGlvbnMub3B0aW9ucyB8fCBpc0FsbG93ZWRDb25maWcoZXhwb3J0T3B0aW9ucy5pbnN0cikgfHwgZmFsc2U7XHJcblxyXG4gIC8vIENoZWNrIHRoZSBgZ2xvYmFsT3B0aW9uc2AgZm9yIGNoYXJ0IGFuZCBleHBvcnRpbmcgc2VjdGlvbnNcclxuICBjb25zdCB7IGNoYXJ0OiBnbG9iYWxPcHRpb25zQ2hhcnQsIGV4cG9ydGluZzogZ2xvYmFsT3B0aW9uc0V4cG9ydGluZyB9ID1cclxuICAgIGlzQWxsb3dlZENvbmZpZyhleHBvcnRPcHRpb25zLmdsb2JhbE9wdGlvbnMpIHx8IGZhbHNlO1xyXG5cclxuICAvLyBDaGVjayB0aGUgYHRoZW1lT3B0aW9uc2AgZm9yIGNoYXJ0IGFuZCBleHBvcnRpbmcgc2VjdGlvbnNcclxuICBjb25zdCB7IGNoYXJ0OiB0aGVtZU9wdGlvbnNDaGFydCwgZXhwb3J0aW5nOiB0aGVtZU9wdGlvbnNFeHBvcnRpbmcgfSA9XHJcbiAgICBpc0FsbG93ZWRDb25maWcoZXhwb3J0T3B0aW9ucy50aGVtZU9wdGlvbnMpIHx8IGZhbHNlO1xyXG5cclxuICAvLyBGaW5kIHRoZSBgc2NhbGVgIHZhbHVlOlxyXG4gIC8vIC0gSXQgY2Fubm90IGJlIGxvd2VyIHRoYW4gMC4xXHJcbiAgLy8gLSBJdCBjYW5ub3QgYmUgaGlnaGVyIHRoYW4gNS4wXHJcbiAgLy8gLSBJdCBtdXN0IGJlIHJvdW5kZWQgdG8gMiBkZWNpbWFsIHBsYWNlcyAoZS5nLiAwLjIzMjM0IC0+IDAuMjMpXHJcbiAgY29uc3Qgc2NhbGUgPSByb3VuZE51bWJlcihcclxuICAgIE1hdGgubWF4KFxyXG4gICAgICAwLjEsXHJcbiAgICAgIE1hdGgubWluKFxyXG4gICAgICAgIGV4cG9ydE9wdGlvbnMuc2NhbGUgfHxcclxuICAgICAgICAgIG9wdGlvbnNFeHBvcnRpbmc/LnNjYWxlIHx8XHJcbiAgICAgICAgICBnbG9iYWxPcHRpb25zRXhwb3J0aW5nPy5zY2FsZSB8fFxyXG4gICAgICAgICAgdGhlbWVPcHRpb25zRXhwb3J0aW5nPy5zY2FsZSB8fFxyXG4gICAgICAgICAgZXhwb3J0T3B0aW9ucy5kZWZhdWx0U2NhbGUgfHxcclxuICAgICAgICAgIDEsXHJcbiAgICAgICAgNS4wXHJcbiAgICAgIClcclxuICAgICksXHJcbiAgICAyXHJcbiAgKTtcclxuXHJcbiAgLy8gRmluZCB0aGUgYGhlaWdodGAgdmFsdWVcclxuICBjb25zdCBoZWlnaHQgPVxyXG4gICAgZXhwb3J0T3B0aW9ucy5oZWlnaHQgfHxcclxuICAgIG9wdGlvbnNFeHBvcnRpbmc/LnNvdXJjZUhlaWdodCB8fFxyXG4gICAgb3B0aW9uc0NoYXJ0Py5oZWlnaHQgfHxcclxuICAgIGdsb2JhbE9wdGlvbnNFeHBvcnRpbmc/LnNvdXJjZUhlaWdodCB8fFxyXG4gICAgZ2xvYmFsT3B0aW9uc0NoYXJ0Py5oZWlnaHQgfHxcclxuICAgIHRoZW1lT3B0aW9uc0V4cG9ydGluZz8uc291cmNlSGVpZ2h0IHx8XHJcbiAgICB0aGVtZU9wdGlvbnNDaGFydD8uaGVpZ2h0IHx8XHJcbiAgICBleHBvcnRPcHRpb25zLmRlZmF1bHRIZWlnaHQgfHxcclxuICAgIDQwMDtcclxuXHJcbiAgLy8gRmluZCB0aGUgYHdpZHRoYCB2YWx1ZVxyXG4gIGNvbnN0IHdpZHRoID1cclxuICAgIGV4cG9ydE9wdGlvbnMud2lkdGggfHxcclxuICAgIG9wdGlvbnNFeHBvcnRpbmc/LnNvdXJjZVdpZHRoIHx8XHJcbiAgICBvcHRpb25zQ2hhcnQ/LndpZHRoIHx8XHJcbiAgICBnbG9iYWxPcHRpb25zRXhwb3J0aW5nPy5zb3VyY2VXaWR0aCB8fFxyXG4gICAgZ2xvYmFsT3B0aW9uc0NoYXJ0Py53aWR0aCB8fFxyXG4gICAgdGhlbWVPcHRpb25zRXhwb3J0aW5nPy5zb3VyY2VXaWR0aCB8fFxyXG4gICAgdGhlbWVPcHRpb25zQ2hhcnQ/LndpZHRoIHx8XHJcbiAgICBleHBvcnRPcHRpb25zLmRlZmF1bHRXaWR0aCB8fFxyXG4gICAgNjAwO1xyXG5cclxuICAvLyBHYXRoZXIgYGhlaWdodGAsIGB3aWR0aGAgYW5kIGBzY2FsZWAgaW5mb3JtYXRpb24gaW4gb25lIG9iamVjdFxyXG4gIGNvbnN0IHNpemUgPSB7IGhlaWdodCwgd2lkdGgsIHNjYWxlIH07XHJcblxyXG4gIC8vIEdldCByaWQgb2YgcG90ZW50aWFsIGBweGAgYW5kIGAlYFxyXG4gIGZvciAobGV0IFtwYXJhbSwgdmFsdWVdIG9mIE9iamVjdC5lbnRyaWVzKHNpemUpKSB7XHJcbiAgICBzaXplW3BhcmFtXSA9XHJcbiAgICAgIHR5cGVvZiB2YWx1ZSA9PT0gJ3N0cmluZycgPyArdmFsdWUucmVwbGFjZSgvcHh8JS9naSwgJycpIDogdmFsdWU7XHJcbiAgfVxyXG5cclxuICAvLyBSZXR1cm4gdGhlIHNpemUgb2JqZWN0XHJcbiAgcmV0dXJuIHNpemU7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBIYW5kbGVzIHRoZSBleGVjdXRpb24gb2YgY3VzdG9tIGxvZ2ljIG9wdGlvbnMsIGluY2x1ZGluZyBsb2FkaW5nIGByZXNvdXJjZXNgLFxyXG4gKiBgY3VzdG9tQ29kZWAsIGFuZCBgY2FsbGJhY2tgLiBJZiBjb2RlIGV4ZWN1dGlvbiBpcyBhbGxvd2VkLCBpdCBwcm9jZXNzZXNcclxuICogdGhlIGN1c3RvbSBsb2dpYyBvcHRpb25zIGFjY29yZGluZ2x5LiBJZiBjb2RlIGV4ZWN1dGlvbiBpcyBub3QgYWxsb3dlZCxcclxuICogaXQgZGlzYWJsZXMgdGhlIHVzYWdlIG9mIHJlc291cmNlcywgY3VzdG9tIGNvZGUgYW5kIGNhbGxiYWNrLlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gX2hhbmRsZUN1c3RvbUxvZ2ljXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBjdXN0b21Mb2dpY09wdGlvbnMgLSBUaGUgY29uZmlndXJhdGlvbiBvYmplY3QgY29udGFpbmluZ1xyXG4gKiBgY3VzdG9tTG9naWNgIG9wdGlvbnMuXHJcbiAqIEBwYXJhbSB7Ym9vbGVhbn0gYWxsb3dDb2RlRXhlY3V0aW9uIC0gQSBmbGFnIGluZGljYXRpbmcgd2hldGhlciBjb2RlXHJcbiAqIGV4ZWN1dGlvbiBpcyBhbGxvd2VkLlxyXG4gKlxyXG4gKiBAdGhyb3dzIHtFeHBvcnRFcnJvcn0gVGhyb3dzIGFuIGBFeHBvcnRFcnJvcmAgaWYgY29kZSBleGVjdXRpb25cclxuICogaXMgbm90IGFsbG93ZWQgYnV0IGN1c3RvbSBsb2dpYyBvcHRpb25zIGFyZSBzdGlsbCBwcm92aWRlZC5cclxuICovXHJcbmZ1bmN0aW9uIF9oYW5kbGVDdXN0b21Mb2dpYyhjdXN0b21Mb2dpY09wdGlvbnMsIGFsbG93Q29kZUV4ZWN1dGlvbikge1xyXG4gIC8vIEluIGNhc2Ugb2YgYWxsb3dpbmcgY29kZSBleGVjdXRpb25cclxuICBpZiAoYWxsb3dDb2RlRXhlY3V0aW9uKSB7XHJcbiAgICAvLyBQcm9jZXNzIHRoZSBgcmVzb3VyY2VzYCBvcHRpb25cclxuICAgIGlmICh0eXBlb2YgY3VzdG9tTG9naWNPcHRpb25zLnJlc291cmNlcyA9PT0gJ3N0cmluZycpIHtcclxuICAgICAgLy8gQ3VzdG9tIHN0cmluZ2lmaWVkIHJlc291cmNlc1xyXG4gICAgICBjdXN0b21Mb2dpY09wdGlvbnMucmVzb3VyY2VzID0gX2hhbmRsZVJlc291cmNlcyhcclxuICAgICAgICBjdXN0b21Mb2dpY09wdGlvbnMucmVzb3VyY2VzLFxyXG4gICAgICAgIGN1c3RvbUxvZ2ljT3B0aW9ucy5hbGxvd0ZpbGVSZXNvdXJjZXMsXHJcbiAgICAgICAgdHJ1ZVxyXG4gICAgICApO1xyXG4gICAgfSBlbHNlIGlmICghY3VzdG9tTG9naWNPcHRpb25zLnJlc291cmNlcykge1xyXG4gICAgICB0cnkge1xyXG4gICAgICAgIC8vIExvYWQgdGhlIGRlZmF1bHQgb25lXHJcbiAgICAgICAgY3VzdG9tTG9naWNPcHRpb25zLnJlc291cmNlcyA9IF9oYW5kbGVSZXNvdXJjZXMoXHJcbiAgICAgICAgICByZWFkRmlsZVN5bmMoZ2V0QWJzb2x1dGVQYXRoKCdyZXNvdXJjZXMuanNvbicpLCAndXRmOCcpLFxyXG4gICAgICAgICAgY3VzdG9tTG9naWNPcHRpb25zLmFsbG93RmlsZVJlc291cmNlcyxcclxuICAgICAgICAgIHRydWVcclxuICAgICAgICApO1xyXG4gICAgICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgICAgIGxvZygyLCAnW2NoYXJ0XSBVbmFibGUgdG8gbG9hZCB0aGUgZGVmYXVsdCBgcmVzb3VyY2VzLmpzb25gIGZpbGUuJyk7XHJcbiAgICAgIH1cclxuICAgIH1cclxuXHJcbiAgICAvLyBQcm9jZXNzIHRoZSBgY3VzdG9tQ29kZWAgb3B0aW9uXHJcbiAgICB0cnkge1xyXG4gICAgICAvLyBUcnkgdG8gbG9hZCBjdXN0b20gY29kZSBhbmQgd3JhcCBhcm91bmQgaXQgaW4gYSBzZWxmIGludm9raW5nIGZ1bmN0aW9uXHJcbiAgICAgIGN1c3RvbUxvZ2ljT3B0aW9ucy5jdXN0b21Db2RlID0gd3JhcEFyb3VuZChcclxuICAgICAgICBjdXN0b21Mb2dpY09wdGlvbnMuY3VzdG9tQ29kZSxcclxuICAgICAgICBjdXN0b21Mb2dpY09wdGlvbnMuYWxsb3dGaWxlUmVzb3VyY2VzXHJcbiAgICAgICk7XHJcblxyXG4gICAgICAvLyBWYWxpZGF0ZSB0aGUgb3B0aW9uXHJcbiAgICAgIGN1c3RvbUxvZ2ljT3B0aW9ucy5jdXN0b21Db2RlID0gdmFsaWRhdGVPcHRpb24oXHJcbiAgICAgICAgJ2N1c3RvbUNvZGUnLFxyXG4gICAgICAgIGN1c3RvbUxvZ2ljT3B0aW9ucy5jdXN0b21Db2RlXHJcbiAgICAgICk7XHJcbiAgICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgICBsb2dXaXRoU3RhY2soMiwgZXJyb3IsICdbY2hhcnRdIFRoZSBgY3VzdG9tQ29kZWAgY2Fubm90IGJlIGxvYWRlZC4nKTtcclxuXHJcbiAgICAgIC8vIEluIGNhc2Ugb2YgYW4gZXJyb3IsIHNldCB0aGUgb3B0aW9uIHdpdGggbnVsbFxyXG4gICAgICBjdXN0b21Mb2dpY09wdGlvbnMuY3VzdG9tQ29kZSA9IG51bGw7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gUHJvY2VzcyB0aGUgYGNhbGxiYWNrYCBvcHRpb25cclxuICAgIHRyeSB7XHJcbiAgICAgIC8vIFRyeSB0byBsb2FkIGNhbGxiYWNrIGZ1bmN0aW9uXHJcbiAgICAgIGN1c3RvbUxvZ2ljT3B0aW9ucy5jYWxsYmFjayA9IHdyYXBBcm91bmQoXHJcbiAgICAgICAgY3VzdG9tTG9naWNPcHRpb25zLmNhbGxiYWNrLFxyXG4gICAgICAgIGN1c3RvbUxvZ2ljT3B0aW9ucy5hbGxvd0ZpbGVSZXNvdXJjZXMsXHJcbiAgICAgICAgdHJ1ZVxyXG4gICAgICApO1xyXG5cclxuICAgICAgLy8gVmFsaWRhdGUgdGhlIG9wdGlvblxyXG4gICAgICBjdXN0b21Mb2dpY09wdGlvbnMuY2FsbGJhY2sgPSB2YWxpZGF0ZU9wdGlvbihcclxuICAgICAgICAnY2FsbGJhY2snLFxyXG4gICAgICAgIGN1c3RvbUxvZ2ljT3B0aW9ucy5jYWxsYmFja1xyXG4gICAgICApO1xyXG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICAgbG9nV2l0aFN0YWNrKDIsIGVycm9yLCAnW2NoYXJ0XSBUaGUgYGNhbGxiYWNrYCBjYW5ub3QgYmUgbG9hZGVkLicpO1xyXG5cclxuICAgICAgLy8gSW4gY2FzZSBvZiBhbiBlcnJvciwgc2V0IHRoZSBvcHRpb24gd2l0aCBudWxsXHJcbiAgICAgIGN1c3RvbUxvZ2ljT3B0aW9ucy5jYWxsYmFjayA9IG51bGw7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gQ2hlY2sgaWYgdGhlcmUgaXMgdGhlIGBjdXN0b21Db2RlYCBwcmVzZW50XHJcbiAgICBpZiAoW251bGwsIHVuZGVmaW5lZF0uaW5jbHVkZXMoY3VzdG9tTG9naWNPcHRpb25zLmN1c3RvbUNvZGUpKSB7XHJcbiAgICAgIGxvZygzLCAnW2NoYXJ0XSBObyB2YWx1ZSBmb3IgdGhlIGBjdXN0b21Db2RlYCBvcHRpb24gZm91bmQuJyk7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gQ2hlY2sgaWYgdGhlcmUgaXMgdGhlIGBjYWxsYmFja2AgcHJlc2VudFxyXG4gICAgaWYgKFtudWxsLCB1bmRlZmluZWRdLmluY2x1ZGVzKGN1c3RvbUxvZ2ljT3B0aW9ucy5jYWxsYmFjaykpIHtcclxuICAgICAgbG9nKDMsICdbY2hhcnRdIE5vIHZhbHVlIGZvciB0aGUgYGNhbGxiYWNrYCBvcHRpb24gZm91bmQuJyk7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gQ2hlY2sgaWYgdGhlcmUgaXMgdGhlIGByZXNvdXJjZXNgIHByZXNlbnRcclxuICAgIGlmIChbbnVsbCwgdW5kZWZpbmVkXS5pbmNsdWRlcyhjdXN0b21Mb2dpY09wdGlvbnMucmVzb3VyY2VzKSkge1xyXG4gICAgICBsb2coMywgJ1tjaGFydF0gTm8gdmFsdWUgZm9yIHRoZSBgcmVzb3VyY2VzYCBvcHRpb24gZm91bmQuJyk7XHJcbiAgICB9XHJcbiAgfSBlbHNlIHtcclxuICAgIC8vIElmIHRoZSBgYWxsb3dDb2RlRXhlY3V0aW9uYCBmbGFnIGlzIHNldCB0byBmYWxzZSwgd2Ugc2hvdWxkIHJlZnVzZVxyXG4gICAgLy8gdGhlIHVzYWdlIG9mIHRoZSBgY2FsbGJhY2tgLCBgcmVzb3VyY2VzYCwgYW5kIGBjdXN0b21Db2RlYCBvcHRpb25zLlxyXG4gICAgLy8gQWRkaXRpb25hbGx5LCB0aGUgd29ya2VyIHdpbGwgcmVmdXNlIHRvIHJ1biBhcmJpdHJhcnkgSmF2YVNjcmlwdC5cclxuICAgIGlmIChcclxuICAgICAgY3VzdG9tTG9naWNPcHRpb25zLmNhbGxiYWNrIHx8XHJcbiAgICAgIGN1c3RvbUxvZ2ljT3B0aW9ucy5yZXNvdXJjZXMgfHxcclxuICAgICAgY3VzdG9tTG9naWNPcHRpb25zLmN1c3RvbUNvZGVcclxuICAgICkge1xyXG4gICAgICAvLyBSZXNldCBhbGwgY3VzdG9tIGNvZGUgb3B0aW9uc1xyXG4gICAgICBjdXN0b21Mb2dpY09wdGlvbnMuY2FsbGJhY2sgPSBudWxsO1xyXG4gICAgICBjdXN0b21Mb2dpY09wdGlvbnMucmVzb3VyY2VzID0gbnVsbDtcclxuICAgICAgY3VzdG9tTG9naWNPcHRpb25zLmN1c3RvbUNvZGUgPSBudWxsO1xyXG5cclxuICAgICAgLy8gU2VuZCBhIG1lc3NhZ2Ugc2F5aW5nIHRoYXQgdGhlIGV4cG9ydGVyIGRvZXMgbm90IHN1cHBvcnQgdGhlc2Ugc2V0dGluZ3NcclxuICAgICAgdGhyb3cgbmV3IEV4cG9ydEVycm9yKFxyXG4gICAgICAgIGBbY2hhcnRdIFRoZSAnY2FsbGJhY2snLCAncmVzb3VyY2VzJywgYW5kICdjdXN0b21Db2RlJyBvcHRpb25zIGhhdmUgYmVlbiBkaXNhYmxlZCBmb3IgdGhpcyBzZXJ2ZXIuYCxcclxuICAgICAgICA0MDNcclxuICAgICAgKTtcclxuICAgIH1cclxuICB9XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBIYW5kbGVzIGFuZCB2YWxpZGF0ZXMgcmVzb3VyY2VzIGZyb20gdGhlIGByZXNvdXJjZXNgIG9wdGlvbiBmb3IgZXhwb3J0LlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gX2hhbmRsZVJlc291cmNlc1xyXG4gKlxyXG4gKiBAcGFyYW0geyhPYmplY3R8c3RyaW5nfG51bGwpfSBbcmVzb3VyY2VzPW51bGxdIC0gVGhlIHJlc291cmNlcyB0byBiZSBoYW5kbGVkLlxyXG4gKiBDYW4gYmUgZWl0aGVyIGEgSlNPTiBvYmplY3QsIHN0cmluZ2lmaWVkIEpTT04sIGEgcGF0aCB0byBhIEpTT04gZmlsZSxcclxuICogb3IgbnVsbC4gVGhlIGRlZmF1bHQgdmFsdWUgaXMgYG51bGxgLlxyXG4gKiBAcGFyYW0ge2Jvb2xlYW59IGFsbG93RmlsZVJlc291cmNlcyAtIEEgZmxhZyBpbmRpY2F0aW5nIHdoZXRoZXIgbG9hZGluZ1xyXG4gKiByZXNvdXJjZXMgZnJvbSBmaWxlcyBpcyBhbGxvd2VkLlxyXG4gKiBAcGFyYW0ge2Jvb2xlYW59IGFsbG93Q29kZUV4ZWN1dGlvbiAtIEEgZmxhZyBpbmRpY2F0aW5nIHdoZXRoZXIgY29kZVxyXG4gKiBleGVjdXRpb24gaXMgYWxsb3dlZC5cclxuICpcclxuICogQHJldHVybnMgeyhPYmplY3R8bnVsbCl9IFRoZSBoYW5kbGVkIHJlc291cmNlcyBvciBudWxsIGlmIG5vIHZhbGlkIHJlc291cmNlc1xyXG4gKiBhcmUgZm91bmQuXHJcbiAqL1xyXG5mdW5jdGlvbiBfaGFuZGxlUmVzb3VyY2VzKFxyXG4gIHJlc291cmNlcyA9IG51bGwsXHJcbiAgYWxsb3dGaWxlUmVzb3VyY2VzLFxyXG4gIGFsbG93Q29kZUV4ZWN1dGlvblxyXG4pIHtcclxuICAvLyBMaXN0IG9mIGFsbG93ZWQgc2VjdGlvbnMgaW4gdGhlIHJlc291cmNlcyBKU09OXHJcbiAgY29uc3QgYWxsb3dlZFByb3BzID0gWydqcycsICdjc3MnLCAnZmlsZXMnXTtcclxuXHJcbiAgbGV0IGhhbmRsZWRSZXNvdXJjZXMgPSByZXNvdXJjZXM7XHJcbiAgbGV0IGNvcnJlY3RSZXNvdXJjZXMgPSBmYWxzZTtcclxuXHJcbiAgLy8gVHJ5IHRvIGxvYWQgcmVzb3VyY2VzIGZyb20gYSBmaWxlXHJcbiAgaWYgKGFsbG93RmlsZVJlc291cmNlcyAmJiByZXNvdXJjZXMuZW5kc1dpdGgoJy5qc29uJykpIHtcclxuICAgIHRyeSB7XHJcbiAgICAgIGhhbmRsZWRSZXNvdXJjZXMgPSBpc0FsbG93ZWRDb25maWcoXHJcbiAgICAgICAgcmVhZEZpbGVTeW5jKGdldEFic29sdXRlUGF0aChyZXNvdXJjZXMpLCAndXRmOCcpLFxyXG4gICAgICAgIGZhbHNlLFxyXG4gICAgICAgIGFsbG93Q29kZUV4ZWN1dGlvblxyXG4gICAgICApO1xyXG4gICAgfSBjYXRjaCB7XHJcbiAgICAgIHJldHVybiBudWxsO1xyXG4gICAgfVxyXG4gIH0gZWxzZSB7XHJcbiAgICAvLyBUcnkgdG8gZ2V0IEpTT05cclxuICAgIGhhbmRsZWRSZXNvdXJjZXMgPSBpc0FsbG93ZWRDb25maWcocmVzb3VyY2VzLCBmYWxzZSwgYWxsb3dDb2RlRXhlY3V0aW9uKTtcclxuXHJcbiAgICAvLyBHZXQgcmlkIG9mIHRoZSBmaWxlcyBzZWN0aW9uXHJcbiAgICBpZiAoaGFuZGxlZFJlc291cmNlcyAmJiAhYWxsb3dGaWxlUmVzb3VyY2VzKSB7XHJcbiAgICAgIGRlbGV0ZSBoYW5kbGVkUmVzb3VyY2VzLmZpbGVzO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgLy8gRmlsdGVyIGZyb20gdW5uZWNlc3NhcnkgcHJvcGVydGllc1xyXG4gIGZvciAoY29uc3QgcHJvcE5hbWUgaW4gaGFuZGxlZFJlc291cmNlcykge1xyXG4gICAgaWYgKCFhbGxvd2VkUHJvcHMuaW5jbHVkZXMocHJvcE5hbWUpKSB7XHJcbiAgICAgIGRlbGV0ZSBoYW5kbGVkUmVzb3VyY2VzW3Byb3BOYW1lXTtcclxuICAgIH0gZWxzZSBpZiAoIWNvcnJlY3RSZXNvdXJjZXMpIHtcclxuICAgICAgY29ycmVjdFJlc291cmNlcyA9IHRydWU7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICAvLyBDaGVjayBpZiBhdCBsZWFzdCBvbmUgb2YgYWxsb3dlZCBwcm9wZXJ0aWVzIGlzIHByZXNlbnRcclxuICBpZiAoIWNvcnJlY3RSZXNvdXJjZXMpIHtcclxuICAgIHJldHVybiBudWxsO1xyXG4gIH1cclxuXHJcbiAgLy8gSGFuZGxlIGZpbGVzIHNlY3Rpb25cclxuICBpZiAoaGFuZGxlZFJlc291cmNlcy5maWxlcykge1xyXG4gICAgaGFuZGxlZFJlc291cmNlcy5maWxlcyA9IGhhbmRsZWRSZXNvdXJjZXMuZmlsZXMubWFwKChpdGVtKSA9PiBpdGVtLnRyaW0oKSk7XHJcbiAgICBpZiAoIWhhbmRsZWRSZXNvdXJjZXMuZmlsZXMgfHwgaGFuZGxlZFJlc291cmNlcy5maWxlcy5sZW5ndGggPD0gMCkge1xyXG4gICAgICBkZWxldGUgaGFuZGxlZFJlc291cmNlcy5maWxlcztcclxuICAgIH1cclxuICB9XHJcblxyXG4gIC8vIFZhbGlkYXRlIG9wdGlvblxyXG4gIGhhbmRsZWRSZXNvdXJjZXMgPSB2YWxpZGF0ZU9wdGlvbigncmVzb3VyY2VzJywgaGFuZGxlZFJlc291cmNlcyk7XHJcblxyXG4gIC8vIFJldHVybiByZXNvdXJjZXNcclxuICByZXR1cm4gaGFuZGxlZFJlc291cmNlcztcclxufVxyXG5cclxuLyoqXHJcbiAqIEhhbmRsZXMgdGhlIGxvYWRpbmcgYW5kIHZhbGlkYXRpb24gb2YgdGhlIGBnbG9iYWxPcHRpb25zYCBhbmQgYHRoZW1lT3B0aW9uc2BcclxuICogaW4gdGhlIGV4cG9ydCBvcHRpb25zLiBJZiB0aGUgb3B0aW9uIGlzIGEgc3RyaW5nIGFuZCByZWZlcmVuY2VzIGEgSlNPTiBmaWxlXHJcbiAqICh3aGVuIHRoZSBgYWxsb3dGaWxlUmVzb3VyY2VzYCBpcyB0cnVlKSwgaXQgcmVhZHMgYW5kIHBhcnNlcyB0aGUgZmlsZS5cclxuICogT3RoZXJ3aXNlLCBpdCBhdHRlbXB0cyB0byBwYXJzZSB0aGUgc3RyaW5nIG9yIG9iamVjdCBhcyBKU09OLiBJZiBhbnkgZXJyb3JzXHJcbiAqIG9jY3VyIGR1cmluZyB0aGlzIHByb2Nlc3MsIHRoZSBvcHRpb24gaXMgc2V0IHRvIG51bGwuIElmIHRoZXJlIGlzIGFuIGVycm9yXHJcbiAqIGxvYWRpbmcgb3IgcGFyc2luZyB0aGUgYGdsb2JhbE9wdGlvbnNgIG9yIGB0aGVtZU9wdGlvbnNgLCB0aGUgZXJyb3IgaXMgbG9nZ2VkXHJcbiAqIGFuZCB0aGUgb3B0aW9uIGlzIHNldCB0byBudWxsLlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gX2hhbmRsZUdsb2JhbEFuZFRoZW1lXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBleHBvcnRPcHRpb25zIC0gVGhlIGNvbmZpZ3VyYXRpb24gb2JqZWN0IGNvbnRhaW5pbmcgYGV4cG9ydGBcclxuICogb3B0aW9ucy5cclxuICogQHBhcmFtIHtib29sZWFufSBhbGxvd0ZpbGVSZXNvdXJjZXMgLSBBIGZsYWcgaW5kaWNhdGluZyB3aGV0aGVyIGxvYWRpbmdcclxuICogcmVzb3VyY2VzIGZyb20gZmlsZXMgaXMgYWxsb3dlZC5cclxuICogQHBhcmFtIHtib29sZWFufSBhbGxvd0NvZGVFeGVjdXRpb24gLSBBIGZsYWcgaW5kaWNhdGluZyB3aGV0aGVyIGNvZGVcclxuICogZXhlY3V0aW9uIGlzIGFsbG93ZWQuXHJcbiAqL1xyXG5mdW5jdGlvbiBfaGFuZGxlR2xvYmFsQW5kVGhlbWUoXHJcbiAgZXhwb3J0T3B0aW9ucyxcclxuICBhbGxvd0ZpbGVSZXNvdXJjZXMsXHJcbiAgYWxsb3dDb2RlRXhlY3V0aW9uXHJcbikge1xyXG4gIC8vIENoZWNrIHRoZSBgZ2xvYmFsT3B0aW9uc2AgYW5kIGB0aGVtZU9wdGlvbnNgIG9wdGlvbnNcclxuICBbJ2dsb2JhbE9wdGlvbnMnLCAndGhlbWVPcHRpb25zJ10uZm9yRWFjaCgob3B0aW9uc05hbWUpID0+IHtcclxuICAgIHRyeSB7XHJcbiAgICAgIC8vIENoZWNrIGlmIHRoZSBvcHRpb24gZXhpc3RzXHJcbiAgICAgIGlmIChleHBvcnRPcHRpb25zW29wdGlvbnNOYW1lXSkge1xyXG4gICAgICAgIC8vIENoZWNrIGlmIGl0IGlzIGEgc3RyaW5nIGFuZCBhIGZpbGUgbmFtZSB3aXRoIHRoZSBgLmpzb25gIGV4dGVuc2lvblxyXG4gICAgICAgIGlmIChcclxuICAgICAgICAgIGFsbG93RmlsZVJlc291cmNlcyAmJlxyXG4gICAgICAgICAgdHlwZW9mIGV4cG9ydE9wdGlvbnNbb3B0aW9uc05hbWVdID09PSAnc3RyaW5nJyAmJlxyXG4gICAgICAgICAgZXhwb3J0T3B0aW9uc1tvcHRpb25zTmFtZV0uZW5kc1dpdGgoJy5qc29uJylcclxuICAgICAgICApIHtcclxuICAgICAgICAgIC8vIENoZWNrIGlmIHRoZSBmaWxlIGNvbnRlbnQgY2FuIGJlIGEgY29uZmlnLCBhbmQgc2F2ZSBpdCBhcyBhIHN0cmluZ1xyXG4gICAgICAgICAgZXhwb3J0T3B0aW9uc1tvcHRpb25zTmFtZV0gPSBpc0FsbG93ZWRDb25maWcoXHJcbiAgICAgICAgICAgIHJlYWRGaWxlU3luYyhnZXRBYnNvbHV0ZVBhdGgoZXhwb3J0T3B0aW9uc1tvcHRpb25zTmFtZV0pLCAndXRmOCcpLFxyXG4gICAgICAgICAgICB0cnVlLFxyXG4gICAgICAgICAgICBhbGxvd0NvZGVFeGVjdXRpb25cclxuICAgICAgICAgICk7XHJcbiAgICAgICAgfSBlbHNlIHtcclxuICAgICAgICAgIC8vIENoZWNrIGlmIHRoZSB2YWx1ZSBjYW4gYmUgYSBjb25maWcsIGFuZCBzYXZlIGl0IGFzIGEgc3RyaW5nXHJcbiAgICAgICAgICBleHBvcnRPcHRpb25zW29wdGlvbnNOYW1lXSA9IGlzQWxsb3dlZENvbmZpZyhcclxuICAgICAgICAgICAgZXhwb3J0T3B0aW9uc1tvcHRpb25zTmFtZV0sXHJcbiAgICAgICAgICAgIHRydWUsXHJcbiAgICAgICAgICAgIGFsbG93Q29kZUV4ZWN1dGlvblxyXG4gICAgICAgICAgKTtcclxuICAgICAgICB9XHJcblxyXG4gICAgICAgIC8vIFZhbGlkYXRlIHRoZSBvcHRpb25cclxuICAgICAgICBleHBvcnRPcHRpb25zW29wdGlvbnNOYW1lXSA9IHZhbGlkYXRlT3B0aW9uKFxyXG4gICAgICAgICAgb3B0aW9uc05hbWUsXHJcbiAgICAgICAgICBleHBvcnRPcHRpb25zW29wdGlvbnNOYW1lXVxyXG4gICAgICAgICk7XHJcbiAgICAgIH1cclxuICAgIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICAgIGxvZ1dpdGhTdGFjayhcclxuICAgICAgICAyLFxyXG4gICAgICAgIGVycm9yLFxyXG4gICAgICAgIGBbY2hhcnRdIFRoZSBcXGAke29wdGlvbnNOYW1lfVxcYCBjYW5ub3QgYmUgbG9hZGVkLmBcclxuICAgICAgKTtcclxuXHJcbiAgICAgIC8vIEluIGNhc2Ugb2YgYW4gZXJyb3IsIHNldCB0aGUgb3B0aW9uIHdpdGggbnVsbFxyXG4gICAgICBleHBvcnRPcHRpb25zW29wdGlvbnNOYW1lXSA9IG51bGw7XHJcbiAgICB9XHJcbiAgfSk7XHJcblxyXG4gIC8vIENoZWNrIGlmIHRoZXJlIGlzIHRoZSBgZ2xvYmFsT3B0aW9uc2AgcHJlc2VudFxyXG4gIGlmIChbbnVsbCwgdW5kZWZpbmVkXS5pbmNsdWRlcyhleHBvcnRPcHRpb25zLmdsb2JhbE9wdGlvbnMpKSB7XHJcbiAgICBsb2coMywgJ1tjaGFydF0gTm8gdmFsdWUgZm9yIHRoZSBgZ2xvYmFsT3B0aW9uc2Agb3B0aW9uIGZvdW5kLicpO1xyXG4gIH1cclxuXHJcbiAgLy8gQ2hlY2sgaWYgdGhlcmUgaXMgdGhlIGB0aGVtZU9wdGlvbnNgIHByZXNlbnRcclxuICBpZiAoW251bGwsIHVuZGVmaW5lZF0uaW5jbHVkZXMoZXhwb3J0T3B0aW9ucy50aGVtZU9wdGlvbnMpKSB7XHJcbiAgICBsb2coMywgJ1tjaGFydF0gTm8gdmFsdWUgZm9yIHRoZSBgdGhlbWVPcHRpb25zYCBvcHRpb24gZm91bmQuJyk7XHJcbiAgfVxyXG59XHJcblxyXG5leHBvcnQgZGVmYXVsdCB7XHJcbiAgc2luZ2xlRXhwb3J0LFxyXG4gIGJhdGNoRXhwb3J0LFxyXG4gIHN0YXJ0RXhwb3J0LFxyXG4gIGdldEFsbG93Q29kZUV4ZWN1dGlvbixcclxuICBzZXRBbGxvd0NvZGVFeGVjdXRpb25cclxufTtcclxuIiwiLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcclxuXHJcbkhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlclxyXG5cclxuQ29weXJpZ2h0IChjKSAyMDE2LTIwMjUsIEhpZ2hzb2Z0XHJcblxyXG5MaWNlbmNlZCB1bmRlciB0aGUgTUlUIGxpY2VuY2UuXHJcblxyXG5BZGRpdGlvbmFsbHkgYSB2YWxpZCBIaWdoY2hhcnRzIGxpY2Vuc2UgaXMgcmVxdWlyZWQgZm9yIHVzZS5cclxuXHJcblNlZSBMSUNFTlNFIGZpbGUgaW4gcm9vdCBmb3IgZGV0YWlscy5cclxuXHJcbioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXHJcblxyXG4vKipcclxuICogQG92ZXJ2aWV3IFRoaXMgbW9kdWxlIHByb3ZpZGVzIHV0aWxpdHkgZnVuY3Rpb25zIGZvciBtYW5hZ2luZyBpbnRlcnZhbHNcclxuICogYW5kIHRpbWVvdXRzIGluIGEgY2VudHJhbGl6ZWQgbWFubmVyLiBJdCBtYWludGFpbnMgYSByZWdpc3RyeSBvZiBhbGwgYWN0aXZlXHJcbiAqIHRpbWVycyBhbmQgYWxsb3dzIGZvciB0aGVpciBlZmZpY2llbnQgY2xlYW51cCB3aGVuIG5lZWRlZC4gVGhpcyBjYW4gYmUgdXNlZnVsXHJcbiAqIGluIGFwcGxpY2F0aW9ucyB3aGVyZSBwcm9wZXIgcmVzb3VyY2UgbWFuYWdlbWVudCBhbmQgY2xlYW4gc2h1dGRvd24gb2YgdGltZXJzXHJcbiAqIGFyZSBjcml0aWNhbCB0byBhdm9pZCBtZW1vcnkgbGVha3Mgb3IgdW5pbnRlbmRlZCBiZWhhdmlvci5cclxuICovXHJcblxyXG5pbXBvcnQgeyBsb2cgfSBmcm9tICcuL2xvZ2dlci5qcyc7XHJcblxyXG4vLyBBcnJheSB0aGF0IGNvbnRhaW5zIGlkcyBvZiBhbGwgb25nb2luZyBpbnRlcnZhbHMgYW5kIHRpbWVvdXRzXHJcbmNvbnN0IHRpbWVySWRzID0gW107XHJcblxyXG4vKipcclxuICogQWRkcyBpZCBvZiB0aGUgYHNldEludGVydmFsYCBvciBgc2V0VGltZW91dGAgYW5kIHRvIHRoZSBgdGltZXJJZHNgIGFycmF5LlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gYWRkVGltZXJcclxuICpcclxuICogQHBhcmFtIHtOb2RlSlMuVGltZW91dH0gaWQgLSBJZCBvZiBhbiBpbnRlcnZhbCBvciBhIHRpbWVvdXQuXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gYWRkVGltZXIoaWQpIHtcclxuICB0aW1lcklkcy5wdXNoKGlkKTtcclxufVxyXG5cclxuLyoqXHJcbiAqIENsZWFycyBhbGwgb2Ygb25nb2luZyBpbnRlcnZhbHMgYW5kIHRpbWVvdXRzIGJ5IGlkcyBnYXRoZXJlZFxyXG4gKiBpbiB0aGUgYHRpbWVySWRzYCBhcnJheS5cclxuICpcclxuICogQGZ1bmN0aW9uIGNsZWFyQWxsVGltZXJzXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gY2xlYXJBbGxUaW1lcnMoKSB7XHJcbiAgbG9nKDQsIGBbdGltZXJdIENsZWFyaW5nIGFsbCByZWdpc3RlcmVkIGludGVydmFscyBhbmQgdGltZW91dHMuYCk7XHJcbiAgZm9yIChjb25zdCBpZCBvZiB0aW1lcklkcykge1xyXG4gICAgY2xlYXJJbnRlcnZhbChpZCk7XHJcbiAgICBjbGVhclRpbWVvdXQoaWQpO1xyXG4gIH1cclxufVxyXG5cclxuZXhwb3J0IGRlZmF1bHQge1xyXG4gIGFkZFRpbWVyLFxyXG4gIGNsZWFyQWxsVGltZXJzXHJcbn07XHJcbiIsIi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXHJcblxyXG5IaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXJcclxuXHJcbkNvcHlyaWdodCAoYykgMjAxNi0yMDI1LCBIaWdoc29mdFxyXG5cclxuTGljZW5jZWQgdW5kZXIgdGhlIE1JVCBsaWNlbmNlLlxyXG5cclxuQWRkaXRpb25hbGx5IGEgdmFsaWQgSGlnaGNoYXJ0cyBsaWNlbnNlIGlzIHJlcXVpcmVkIGZvciB1c2UuXHJcblxyXG5TZWUgTElDRU5TRSBmaWxlIGluIHJvb3QgZm9yIGRldGFpbHMuXHJcblxyXG4qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xyXG5cclxuLyoqXHJcbiAqIEBvdmVydmlldyBQcm92aWRlcyBtaWRkbGV3YXJlIGZ1bmN0aW9ucyBmb3IgbG9nZ2luZyBlcnJvcnMgd2l0aCBzdGFjayB0cmFjZXNcclxuICogYW5kIGhhbmRsaW5nIGVycm9yIHJlc3BvbnNlcyBpbiBhbiBFeHByZXNzIGFwcGxpY2F0aW9uLlxyXG4gKi9cclxuXHJcbmltcG9ydCB7IGdldE9wdGlvbnMgfSBmcm9tICcuLi8uLi9jb25maWcuanMnO1xyXG5pbXBvcnQgeyBsb2dXaXRoU3RhY2sgfSBmcm9tICcuLi8uLi9sb2dnZXIuanMnO1xyXG5cclxuLyoqXHJcbiAqIE1pZGRsZXdhcmUgZm9yIGxvZ2dpbmcgZXJyb3JzIHdpdGggc3RhY2sgdHJhY2UgYW5kIGhhbmRsaW5nIGVycm9yIHJlc3BvbnNlLlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gbG9nRXJyb3JNaWRkbGV3YXJlXHJcbiAqXHJcbiAqIEBwYXJhbSB7RXJyb3J9IGVycm9yIC0gVGhlIGVycm9yIG9iamVjdC5cclxuICogQHBhcmFtIHtFeHByZXNzLlJlcXVlc3R9IHJlcXVlc3QgLSBUaGUgRXhwcmVzcyByZXF1ZXN0IG9iamVjdC5cclxuICogQHBhcmFtIHtFeHByZXNzLlJlc3BvbnNlfSByZXNwb25zZSAtIFRoZSBFeHByZXNzIHJlc3BvbnNlIG9iamVjdC5cclxuICogQHBhcmFtIHtGdW5jdGlvbn0gbmV4dCAtIFRoZSBuZXh0IG1pZGRsZXdhcmUgZnVuY3Rpb24uXHJcbiAqXHJcbiAqIEByZXR1cm5zIHt1bmRlZmluZWR9IFRoZSBjYWxsIHRvIHRoZSBuZXh0IG1pZGRsZXdhcmUgZnVuY3Rpb24gd2l0aFxyXG4gKiB0aGUgcGFzc2VkIGVycm9yLlxyXG4gKi9cclxuZnVuY3Rpb24gbG9nRXJyb3JNaWRkbGV3YXJlKGVycm9yLCByZXF1ZXN0LCByZXNwb25zZSwgbmV4dCkge1xyXG4gIC8vIERpc3BsYXkgdGhlIGVycm9yIHdpdGggc3RhY2sgaW4gYSBjb3JyZWN0IGZvcm1hdFxyXG4gIGxvZ1dpdGhTdGFjaygxLCBlcnJvcik7XHJcblxyXG4gIC8vIERlbGV0ZSB0aGUgc3RhY2sgZm9yIHRoZSBlbnZpcm9ubWVudCBvdGhlciB0aGFuIHRoZSBkZXZlbG9wbWVudFxyXG4gIGlmIChnZXRPcHRpb25zKCkub3RoZXIubm9kZUVudiAhPT0gJ2RldmVsb3BtZW50Jykge1xyXG4gICAgZGVsZXRlIGVycm9yLnN0YWNrO1xyXG4gIH1cclxuXHJcbiAgLy8gQ2FsbCB0aGUgYHJldHVybkVycm9yTWlkZGxld2FyZWAgbWlkZGxld2FyZVxyXG4gIHJldHVybiBuZXh0KGVycm9yKTtcclxufVxyXG5cclxuLyoqXHJcbiAqIE1pZGRsZXdhcmUgZm9yIHJldHVybmluZyBlcnJvciByZXNwb25zZS5cclxuICpcclxuICogQGZ1bmN0aW9uIHJldHVybkVycm9yTWlkZGxld2FyZVxyXG4gKlxyXG4gKiBAcGFyYW0ge0Vycm9yfSBlcnJvciAtIFRoZSBlcnJvciBvYmplY3QuXHJcbiAqIEBwYXJhbSB7RXhwcmVzcy5SZXF1ZXN0fSByZXF1ZXN0IC0gVGhlIEV4cHJlc3MgcmVxdWVzdCBvYmplY3QuXHJcbiAqIEBwYXJhbSB7RXhwcmVzcy5SZXNwb25zZX0gcmVzcG9uc2UgLSBUaGUgRXhwcmVzcyByZXNwb25zZSBvYmplY3QuXHJcbiAqIEBwYXJhbSB7RnVuY3Rpb259IG5leHQgLSBUaGUgbmV4dCBtaWRkbGV3YXJlIGZ1bmN0aW9uLlxyXG4gKi9cclxuZnVuY3Rpb24gcmV0dXJuRXJyb3JNaWRkbGV3YXJlKGVycm9yLCByZXF1ZXN0LCByZXNwb25zZSwgbmV4dCkge1xyXG4gIC8vIEdhdGhlciBhbGwgcmVxdWllZCBpbmZvcm1hdGlvbiBmb3IgdGhlIHJlc3BvbnNlXHJcbiAgY29uc3QgeyBtZXNzYWdlLCBzdGFjayB9ID0gZXJyb3I7XHJcblxyXG4gIC8vIFVzZSB0aGUgZXJyb3IncyBzdGF0dXMgY29kZSBvciB0aGUgZGVmYXVsdCA0MDBcclxuICBjb25zdCBzdGF0dXNDb2RlID0gZXJyb3Iuc3RhdHVzQ29kZSB8fCA0MDA7XHJcblxyXG4gIC8vIFNldCBhbmQgcmV0dXJuIHJlc3BvbnNlXHJcbiAgcmVzcG9uc2Uuc3RhdHVzKHN0YXR1c0NvZGUpLmpzb24oeyBzdGF0dXNDb2RlLCBtZXNzYWdlLCBzdGFjayB9KTtcclxufVxyXG5cclxuLyoqXHJcbiAqIEFkZHMgdGhlIGVycm9yIG1pZGRsZXdhcmVzIHRvIHRoZSBwYXNzZWQgZXhwcmVzcyBhcHAgaW5zdGFuY2UuXHJcbiAqXHJcbiAqIEBwYXJhbSB7RXhwcmVzc30gYXBwIC0gVGhlIEV4cHJlc3MgYXBwIGluc3RhbmNlLlxyXG4gKi9cclxuZXhwb3J0IGRlZmF1bHQgZnVuY3Rpb24gZXJyb3JNaWRkbGV3YXJlKGFwcCkge1xyXG4gIC8vIEFkZCBsb2cgZXJyb3IgbWlkZGxld2FyZVxyXG4gIGFwcC51c2UobG9nRXJyb3JNaWRkbGV3YXJlKTtcclxuXHJcbiAgLy8gQWRkIHNldCBzdGF0dXMgYW5kIHJldHVybiBlcnJvciBtaWRkbGV3YXJlXHJcbiAgYXBwLnVzZShyZXR1cm5FcnJvck1pZGRsZXdhcmUpO1xyXG59XHJcbiIsIi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXHJcblxyXG5IaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXJcclxuXHJcbkNvcHlyaWdodCAoYykgMjAxNi0yMDI1LCBIaWdoc29mdFxyXG5cclxuTGljZW5jZWQgdW5kZXIgdGhlIE1JVCBsaWNlbmNlLlxyXG5cclxuQWRkaXRpb25hbGx5IGEgdmFsaWQgSGlnaGNoYXJ0cyBsaWNlbnNlIGlzIHJlcXVpcmVkIGZvciB1c2UuXHJcblxyXG5TZWUgTElDRU5TRSBmaWxlIGluIHJvb3QgZm9yIGRldGFpbHMuXHJcblxyXG4qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xyXG5cclxuLyoqXHJcbiAqIEBvdmVydmlldyBQcm92aWRlcyBtaWRkbGV3YXJlIGZ1bmN0aW9ucyBmb3IgY29uZmlndXJpbmcgYW5kIGVuYWJsaW5nIHJhdGVcclxuICogbGltaXRpbmcgaW4gYW4gRXhwcmVzcyBhcHBsaWNhdGlvbi5cclxuICovXHJcblxyXG5pbXBvcnQgcmF0ZUxpbWl0IGZyb20gJ2V4cHJlc3MtcmF0ZS1saW1pdCc7XHJcblxyXG5pbXBvcnQgeyBsb2cgfSBmcm9tICcuLi8uLi9sb2dnZXIuanMnO1xyXG5cclxuaW1wb3J0IEV4cG9ydEVycm9yIGZyb20gJy4uLy4uL2Vycm9ycy9FeHBvcnRFcnJvci5qcyc7XHJcblxyXG4vKipcclxuICogTWlkZGxld2FyZSBmb3IgZW5hYmxpbmcgcmF0ZSBsaW1pdGluZyBvbiB0aGUgc3BlY2lmaWVkIEV4cHJlc3MgYXBwLlxyXG4gKlxyXG4gKiBAcGFyYW0ge0V4cHJlc3N9IGFwcCAtIFRoZSBFeHByZXNzIGFwcCBpbnN0YW5jZS5cclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IHJhdGVMaW1pdGluZ09wdGlvbnMgLSBUaGUgY29uZmlndXJhdGlvbiBvYmplY3QgY29udGFpbmluZ1xyXG4gKiBgcmF0ZUxpbWl0aW5nYCBvcHRpb25zLlxyXG4gKlxyXG4gKiBAdGhyb3dzIHtFeHBvcnRFcnJvcn0gVGhyb3dzIGFuIGBFeHBvcnRFcnJvcmAgaWYgY291bGQgbm90IGNvbmZpZ3VyZSBhbmQgc2V0XHJcbiAqIHRoZSByYXRlIGxpbWl0aW5nIG9wdGlvbnMuXHJcbiAqL1xyXG5leHBvcnQgZGVmYXVsdCBmdW5jdGlvbiByYXRlTGltaXRpbmdNaWRkbGV3YXJlKGFwcCwgcmF0ZUxpbWl0aW5nT3B0aW9ucykge1xyXG4gIHRyeSB7XHJcbiAgICAvLyBDaGVjayBpZiB0aGUgcmF0ZSBsaW1pdGluZyBpcyBlbmFibGVkXHJcbiAgICBpZiAocmF0ZUxpbWl0aW5nT3B0aW9ucy5lbmFibGUpIHtcclxuICAgICAgY29uc3QgbWVzc2FnZSA9XHJcbiAgICAgICAgJ1RvbyBtYW55IHJlcXVlc3RzLCB5b3UgaGF2ZSBiZWVuIHJhdGUgbGltaXRlZC4gUGxlYXNlIHRyeSBhZ2FpbiBsYXRlci4nO1xyXG5cclxuICAgICAgLy8gT3B0aW9ucyBmb3IgdGhlIHJhdGUgbGltaXRlclxyXG4gICAgICBjb25zdCByYXRlT3B0aW9ucyA9IHtcclxuICAgICAgICB3aW5kb3c6IHJhdGVMaW1pdGluZ09wdGlvbnMud2luZG93IHx8IDEsXHJcbiAgICAgICAgbWF4UmVxdWVzdHM6IHJhdGVMaW1pdGluZ09wdGlvbnMubWF4UmVxdWVzdHMgfHwgMzAsXHJcbiAgICAgICAgZGVsYXk6IHJhdGVMaW1pdGluZ09wdGlvbnMuZGVsYXkgfHwgMCxcclxuICAgICAgICB0cnVzdFByb3h5OiByYXRlTGltaXRpbmdPcHRpb25zLnRydXN0UHJveHkgfHwgZmFsc2UsXHJcbiAgICAgICAgc2tpcEtleTogcmF0ZUxpbWl0aW5nT3B0aW9ucy5za2lwS2V5IHx8IG51bGwsXHJcbiAgICAgICAgc2tpcFRva2VuOiByYXRlTGltaXRpbmdPcHRpb25zLnNraXBUb2tlbiB8fCBudWxsXHJcbiAgICAgIH07XHJcblxyXG4gICAgICAvLyBTZXQgaWYgYmVoaW5kIGEgcHJveHlcclxuICAgICAgaWYgKHJhdGVPcHRpb25zLnRydXN0UHJveHkpIHtcclxuICAgICAgICBhcHAuZW5hYmxlKCd0cnVzdCBwcm94eScpO1xyXG4gICAgICB9XHJcblxyXG4gICAgICAvLyBDcmVhdGUgYSBsaW1pdGVyXHJcbiAgICAgIGNvbnN0IGxpbWl0ZXIgPSByYXRlTGltaXQoe1xyXG4gICAgICAgIC8vIFRpbWUgZnJhbWUgZm9yIHdoaWNoIHJlcXVlc3RzIGFyZSBjaGVja2VkIGFuZCByZW1lbWJlcmVkXHJcbiAgICAgICAgd2luZG93TXM6IHJhdGVPcHRpb25zLndpbmRvdyAqIDYwICogMTAwMCxcclxuICAgICAgICAvLyBMaW1pdCBlYWNoIElQIHRvIDEwMCByZXF1ZXN0cyBwZXIgYHdpbmRvd01zYFxyXG4gICAgICAgIGxpbWl0OiByYXRlT3B0aW9ucy5tYXhSZXF1ZXN0cyxcclxuICAgICAgICAvLyBEaXNhYmxlIGRlbGF5aW5nLCBmdWxsIHNwZWVkIHVudGlsIHRoZSBtYXggbGltaXQgaXMgcmVhY2hlZFxyXG4gICAgICAgIGRlbGF5TXM6IHJhdGVPcHRpb25zLmRlbGF5LFxyXG4gICAgICAgIGhhbmRsZXI6IChyZXF1ZXN0LCByZXNwb25zZSkgPT4ge1xyXG4gICAgICAgICAgcmVzcG9uc2UuZm9ybWF0KHtcclxuICAgICAgICAgICAganNvbjogKCkgPT4ge1xyXG4gICAgICAgICAgICAgIHJlc3BvbnNlLnN0YXR1cyg0MjkpLnNlbmQoeyBtZXNzYWdlIH0pO1xyXG4gICAgICAgICAgICB9LFxyXG4gICAgICAgICAgICBkZWZhdWx0OiAoKSA9PiB7XHJcbiAgICAgICAgICAgICAgcmVzcG9uc2Uuc3RhdHVzKDQyOSkuc2VuZChtZXNzYWdlKTtcclxuICAgICAgICAgICAgfVxyXG4gICAgICAgICAgfSk7XHJcbiAgICAgICAgfSxcclxuICAgICAgICBza2lwOiAocmVxdWVzdCkgPT4ge1xyXG4gICAgICAgICAgLy8gQWxsb3cgYnlwYXNzaW5nIHRoZSBsaW1pdGVyIGlmIGEgdmFsaWQga2V5L3Rva2VuIGhhcyBiZWVuIHNlbnRcclxuICAgICAgICAgIGlmIChcclxuICAgICAgICAgICAgcmF0ZU9wdGlvbnMuc2tpcEtleSAhPT0gbnVsbCAmJlxyXG4gICAgICAgICAgICByYXRlT3B0aW9ucy5za2lwVG9rZW4gIT09IG51bGwgJiZcclxuICAgICAgICAgICAgcmVxdWVzdC5xdWVyeS5rZXkgPT09IHJhdGVPcHRpb25zLnNraXBLZXkgJiZcclxuICAgICAgICAgICAgcmVxdWVzdC5xdWVyeS5hY2Nlc3NfdG9rZW4gPT09IHJhdGVPcHRpb25zLnNraXBUb2tlblxyXG4gICAgICAgICAgKSB7XHJcbiAgICAgICAgICAgIGxvZyg0LCAnW3JhdGUgbGltaXRpbmddIFNraXBwaW5nIHJhdGUgbGltaXRlci4nKTtcclxuICAgICAgICAgICAgcmV0dXJuIHRydWU7XHJcbiAgICAgICAgICB9XHJcbiAgICAgICAgICByZXR1cm4gZmFsc2U7XHJcbiAgICAgICAgfVxyXG4gICAgICB9KTtcclxuXHJcbiAgICAgIC8vIFVzZSBhIGxpbWl0ZXIgYXMgYSBtaWRkbGV3YXJlXHJcbiAgICAgIGFwcC51c2UobGltaXRlcik7XHJcblxyXG4gICAgICBsb2coXHJcbiAgICAgICAgMyxcclxuICAgICAgICBgW3JhdGUgbGltaXRpbmddIEVuYWJsZWQgcmF0ZSBsaW1pdGluZyB3aXRoICR7cmF0ZU9wdGlvbnMubWF4UmVxdWVzdHN9IHJlcXVlc3RzIHBlciAke3JhdGVPcHRpb25zLndpbmRvd30gbWludXRlIGZvciBlYWNoIElQLCB0cnVzdGluZyBwcm94eTogJHtyYXRlT3B0aW9ucy50cnVzdFByb3h5fS5gXHJcbiAgICAgICk7XHJcbiAgICB9XHJcbiAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcihcclxuICAgICAgJ1tyYXRlIGxpbWl0aW5nXSBDb3VsZCBub3QgY29uZmlndXJlIGFuZCBzZXQgdGhlIHJhdGUgbGltaXRpbmcgb3B0aW9ucy4nLFxyXG4gICAgICA1MDBcclxuICAgICkuc2V0RXJyb3IoZXJyb3IpO1xyXG4gIH1cclxufVxyXG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxyXG5cclxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXHJcblxyXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNSwgSGlnaHNvZnRcclxuXHJcbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cclxuXHJcbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxyXG5cclxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxyXG5cclxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cclxuXHJcbi8qKlxyXG4gKiBAb3ZlcnZpZXcgUHJvdmlkZXMgbWlkZGxld2FyZSBmdW5jdGlvbnMgZm9yIHZhbGlkYXRpbmcgaW5jb21pbmcgSFRUUCByZXF1ZXN0c1xyXG4gKiBpbiBhbiBFeHByZXNzIGFwcGxpY2F0aW9uLiBUaGlzIG1vZHVsZSBlbnN1cmVzIHRoYXQgcmVxdWVzdHMgY29udGFpblxyXG4gKiBhcHByb3ByaWF0ZSBjb250ZW50IHR5cGVzIGFuZCB2YWxpZCByZXF1ZXN0IGJvZGllcywgaW5jbHVkaW5nIHByb3BlciBKU09OXHJcbiAqIHN0cnVjdHVyZXMgYW5kIGNoYXJ0IGRhdGEgZm9yIGV4cG9ydHMuIEl0IGNoZWNrcyBmb3IgcG90ZW50aWFsIGlzc3VlcyBzdWNoXHJcbiAqIGFzIG1pc3Npbmcgb3IgbWFsZm9ybWVkIGRhdGEsIHByaXZhdGUgcmFuZ2UgVVJMcyBpbiBTVkcgcGF5bG9hZHMsIGFuZCBhbGxvd3NcclxuICogZm9yIGZsZXhpYmxlIG9wdGlvbnMgdmFsaWRhdGlvbi4gVGhlIG1pZGRsZXdhcmUgbG9ncyBkZXRhaWxlZCBpbmZvcm1hdGlvblxyXG4gKiBhbmQgaGFuZGxlcyBlcnJvcnMgcmVsYXRlZCB0byBpbmNvcnJlY3QgcGF5bG9hZHMsIGNoYXJ0IGRhdGEsIGFuZCBwcml2YXRlIFVSTFxyXG4gKiB1c2FnZS5cclxuICovXHJcblxyXG5pbXBvcnQgeyB2NCBhcyB1dWlkIH0gZnJvbSAndXVpZCc7XHJcblxyXG5pbXBvcnQgeyBnZXRBbGxvd0NvZGVFeGVjdXRpb24gfSBmcm9tICcuLi8uLi9jaGFydC5qcyc7XHJcbmltcG9ydCB7IGlzQWxsb3dlZENvbmZpZywgdmFsaWRhdGVPcHRpb25zIH0gZnJvbSAnLi4vLi4vY29uZmlnLmpzJztcclxuaW1wb3J0IHsgbG9nLCBsb2dab2RJc3N1ZXMgfSBmcm9tICcuLi8uLi9sb2dnZXIuanMnO1xyXG5pbXBvcnQge1xyXG4gIGZpeENvbnN0cixcclxuICBmaXhUeXBlLFxyXG4gIGlzT2JqZWN0RW1wdHksXHJcbiAgaXNQcml2YXRlUmFuZ2VVcmxGb3VuZFxyXG59IGZyb20gJy4uLy4uL3V0aWxzLmpzJztcclxuaW1wb3J0IHsgbG9vc2VWYWxpZGF0ZSB9IGZyb20gJy4uLy4uL3ZhbGlkYXRpb24uanMnO1xyXG5cclxuaW1wb3J0IEV4cG9ydEVycm9yIGZyb20gJy4uLy4uL2Vycm9ycy9FeHBvcnRFcnJvci5qcyc7XHJcblxyXG4vKipcclxuICogTWlkZGxld2FyZSBmb3IgdmFsaWRhdGluZyB0aGUgY29udGVudC10eXBlIGhlYWRlci5cclxuICpcclxuICogQGZ1bmN0aW9uIGNvbnRlbnRUeXBlTWlkZGxld2FyZVxyXG4gKlxyXG4gKiBAcGFyYW0ge0V4cHJlc3MuUmVxdWVzdH0gcmVxdWVzdCAtIFRoZSBFeHByZXNzIHJlcXVlc3Qgb2JqZWN0LlxyXG4gKiBAcGFyYW0ge0V4cHJlc3MuUmVzcG9uc2V9IHJlc3BvbnNlIC0gVGhlIEV4cHJlc3MgcmVzcG9uc2Ugb2JqZWN0LlxyXG4gKiBAcGFyYW0ge0Z1bmN0aW9ufSBuZXh0IC0gVGhlIG5leHQgbWlkZGxld2FyZSBmdW5jdGlvbi5cclxuICpcclxuICogQHJldHVybnMge3VuZGVmaW5lZH0gVGhlIGNhbGwgdG8gdGhlIG5leHQgbWlkZGxld2FyZSBmdW5jdGlvbi5cclxuICpcclxuICogQHRocm93cyB7RXhwb3J0RXJyb3J9IFRocm93cyBhbiBgRXhwb3J0RXJyb3JgIGlmIHRoZSBjb250ZW50LXR5cGVcclxuICogaXMgbm90IGNvcnJlY3QuXHJcbiAqL1xyXG5mdW5jdGlvbiBjb250ZW50VHlwZU1pZGRsZXdhcmUocmVxdWVzdCwgcmVzcG9uc2UsIG5leHQpIHtcclxuICB0cnkge1xyXG4gICAgLy8gR2V0IHRoZSBjb250ZW50IHR5cGUgaGVhZGVyXHJcbiAgICBjb25zdCBjb250ZW50VHlwZSA9IHJlcXVlc3QuaGVhZGVyc1snY29udGVudC10eXBlJ10gfHwgJyc7XHJcblxyXG4gICAgLy8gQWxsb3cgb25seSBKU09OLCBVUkwtZW5jb2RlZCBhbmQgZm9ybSBkYXRhIHdpdGhvdXQgZmlsZXMgdHlwZXMgb2YgZGF0YVxyXG4gICAgaWYgKFxyXG4gICAgICAhY29udGVudFR5cGUuaW5jbHVkZXMoJ2FwcGxpY2F0aW9uL2pzb24nKSAmJlxyXG4gICAgICAhY29udGVudFR5cGUuaW5jbHVkZXMoJ2FwcGxpY2F0aW9uL3gtd3d3LWZvcm0tdXJsZW5jb2RlZCcpICYmXHJcbiAgICAgICFjb250ZW50VHlwZS5pbmNsdWRlcygnbXVsdGlwYXJ0L2Zvcm0tZGF0YScpXHJcbiAgICApIHtcclxuICAgICAgdGhyb3cgbmV3IEV4cG9ydEVycm9yKFxyXG4gICAgICAgICdbdmFsaWRhdGlvbl0gQ29udGVudC1UeXBlIG11c3QgYmUgYXBwbGljYXRpb24vanNvbiwgYXBwbGljYXRpb24veC13d3ctZm9ybS11cmxlbmNvZGVkLCBvciBtdWx0aXBhcnQvZm9ybS1kYXRhLicsXHJcbiAgICAgICAgNDE1XHJcbiAgICAgICk7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gQ2FsbCB0aGUgYHJlcXVlc3RCb2R5TWlkZGxld2FyZWAgbWlkZGxld2FyZVxyXG4gICAgcmV0dXJuIG5leHQoKTtcclxuICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgcmV0dXJuIG5leHQoZXJyb3IpO1xyXG4gIH1cclxufVxyXG5cclxuLyoqXHJcbiAqIE1pZGRsZXdhcmUgZm9yIHZhbGlkYXRpbmcgdGhlIHJlcXVlc3QncyBib2R5LlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gcmVxdWVzdEJvZHlNaWRkbGV3YXJlXHJcbiAqXHJcbiAqIEBwYXJhbSB7RXhwcmVzcy5SZXF1ZXN0fSByZXF1ZXN0IC0gVGhlIEV4cHJlc3MgcmVxdWVzdCBvYmplY3QuXHJcbiAqIEBwYXJhbSB7RXhwcmVzcy5SZXNwb25zZX0gcmVzcG9uc2UgLSBUaGUgRXhwcmVzcyByZXNwb25zZSBvYmplY3QuXHJcbiAqIEBwYXJhbSB7RnVuY3Rpb259IG5leHQgLSBUaGUgbmV4dCBtaWRkbGV3YXJlIGZ1bmN0aW9uLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7dW5kZWZpbmVkfSBUaGUgY2FsbCB0byB0aGUgbmV4dCBtaWRkbGV3YXJlIGZ1bmN0aW9uLlxyXG4gKlxyXG4gKiBAdGhyb3dzIHtFeHBvcnRFcnJvcn0gVGhyb3dzIGFuIGBFeHBvcnRFcnJvcmAgaWYgdGhlIGJvZHkgaXMgbm90IGNvcnJlY3QuXHJcbiAqIEB0aHJvd3Mge0V4cG9ydEVycm9yfSBUaHJvd3MgYW4gYEV4cG9ydEVycm9yYCBpZiB0aGUgY2hhcnQgZGF0YSBmcm9tIHRoZSBib2R5XHJcbiAqIGlzIG5vdCBjb3JyZWN0LlxyXG4gKiBAdGhyb3dzIHtFeHBvcnRFcnJvcn0gVGhyb3dzIGFuIGBFeHBvcnRFcnJvcmAgaW4gY2FzZSBvZiB0aGUgcHJpdmF0ZSByYW5nZVxyXG4gKiB1cmwgZXJyb3IuXHJcbiAqL1xyXG5mdW5jdGlvbiByZXF1ZXN0Qm9keU1pZGRsZXdhcmUocmVxdWVzdCwgcmVzcG9uc2UsIG5leHQpIHtcclxuICB0cnkge1xyXG4gICAgLy8gR2V0IHRoZSByZXF1ZXN0IGJvZHlcclxuICAgIGNvbnN0IGJvZHkgPSByZXF1ZXN0LmJvZHk7XHJcblxyXG4gICAgLy8gQ3JlYXRlIGEgdW5pcXVlIElEIGZvciBhIHJlcXVlc3RcclxuICAgIGNvbnN0IHJlcXVlc3RJZCA9IHV1aWQoKTtcclxuXHJcbiAgICAvLyBUaHJvdyBhbiBlcnJvciBpZiB0aGVyZSBpcyBubyBjb3JyZWN0IGJvZHlcclxuICAgIGlmICghYm9keSB8fCBpc09iamVjdEVtcHR5KGJvZHkpKSB7XHJcbiAgICAgIGxvZyhcclxuICAgICAgICAyLFxyXG4gICAgICAgIGBbdmFsaWRhdGlvbl0gUmVxdWVzdCBbJHtyZXF1ZXN0SWR9XSAtIFRoZSByZXF1ZXN0IGZyb20gJHtcclxuICAgICAgICAgIHJlcXVlc3QuaGVhZGVyc1sneC1mb3J3YXJkZWQtZm9yJ10gfHwgcmVxdWVzdC5jb25uZWN0aW9uLnJlbW90ZUFkZHJlc3NcclxuICAgICAgICB9IHdhcyBpbmNvcnJlY3QuIFJlY2VpdmVkIHBheWxvYWQgaXMgZW1wdHkuYFxyXG4gICAgICApO1xyXG5cclxuICAgICAgdGhyb3cgbmV3IEV4cG9ydEVycm9yKFxyXG4gICAgICAgIGBbdmFsaWRhdGlvbl0gUmVxdWVzdCBbJHtyZXF1ZXN0SWR9XSAtIFRoZSByZXF1ZXN0IGJvZHkgaXMgcmVxdWlyZWQuIFBsZWFzZSBlbnN1cmUgdGhhdCB5b3VyIENvbnRlbnQtVHlwZSBoZWFkZXIgaXMgY29ycmVjdC4gQWNjZXB0ZWQgdHlwZXMgYXJlICdhcHBsaWNhdGlvbi9qc29uJyBhbmQgJ211bHRpcGFydC9mb3JtLWRhdGEnLmAsXHJcbiAgICAgICAgNDAwXHJcbiAgICAgICk7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gR2V0IHRoZSBgYWxsb3dDb2RlRXhlY3V0aW9uYCBvcHRpb24gZm9yIHRoZSBzZXJ2ZXJcclxuICAgIGNvbnN0IGFsbG93Q29kZUV4ZWN1dGlvbiA9IGdldEFsbG93Q29kZUV4ZWN1dGlvbigpO1xyXG5cclxuICAgIC8vIEZpbmQgYSBjb3JyZWN0IGNoYXJ0IG9wdGlvbnNcclxuICAgIGNvbnN0IGluc3RyID0gaXNBbGxvd2VkQ29uZmlnKFxyXG4gICAgICAvLyBVc2Ugb25lIG9mIHRoZSBiZWxvd1xyXG4gICAgICBib2R5Lmluc3RyIHx8IGJvZHkub3B0aW9ucyB8fCBib2R5LmluZmlsZSB8fCBib2R5LmRhdGEsXHJcbiAgICAgIC8vIFN0cmluZ2lmeSBvcHRpb25zXHJcbiAgICAgIHRydWUsXHJcbiAgICAgIC8vIEFsbG93IG9yIGRpc2FsbG93IGZ1bmN0aW9uc1xyXG4gICAgICBhbGxvd0NvZGVFeGVjdXRpb25cclxuICAgICk7XHJcblxyXG4gICAgLy8gVGhyb3cgYW4gZXJyb3IgaWYgdGhlcmUgaXMgbm8gY29ycmVjdCBjaGFydCBkYXRhXHJcbiAgICBpZiAoaW5zdHIgPT09IG51bGwgJiYgIWJvZHkuc3ZnKSB7XHJcbiAgICAgIGxvZyhcclxuICAgICAgICAyLFxyXG4gICAgICAgIGBbdmFsaWRhdGlvbl0gUmVxdWVzdCBbJHtyZXF1ZXN0SWR9XSAtIFRoZSByZXF1ZXN0IGZyb20gJHtcclxuICAgICAgICAgIHJlcXVlc3QuaGVhZGVyc1sneC1mb3J3YXJkZWQtZm9yJ10gfHwgcmVxdWVzdC5jb25uZWN0aW9uLnJlbW90ZUFkZHJlc3NcclxuICAgICAgICB9IHdhcyBpbmNvcnJlY3QuIFJlY2VpdmVkIHBheWxvYWQgaXMgbWlzc2luZyBjb3JyZWN0IGNoYXJ0IGRhdGEgZm9yIGV4cG9ydDogJHtKU09OLnN0cmluZ2lmeShib2R5KX0uYFxyXG4gICAgICApO1xyXG5cclxuICAgICAgdGhyb3cgbmV3IEV4cG9ydEVycm9yKFxyXG4gICAgICAgIGBSZXF1ZXN0IFske3JlcXVlc3RJZH1dIC0gW3ZhbGlkYXRpb25dIE5vIGNvcnJlY3QgY2hhcnQgZGF0YSBmb3VuZC4gRW5zdXJlIHRoYXQgeW91IGFyZSB1c2luZyBlaXRoZXIgYXBwbGljYXRpb24vanNvbiBvciBtdWx0aXBhcnQvZm9ybS1kYXRhIGhlYWRlcnMuIElmIHNlbmRpbmcgSlNPTiwgbWFrZSBzdXJlIHRoZSBjaGFydCBkYXRhIGlzIGluIHRoZSAnaW5maWxlJywgJ29wdGlvbnMnLCBvciAnZGF0YScgYXR0cmlidXRlLiBJZiBzZW5kaW5nIFNWRywgZW5zdXJlIGl0IGlzIGluIHRoZSAnc3ZnJyBhdHRyaWJ1dGUuYCxcclxuICAgICAgICA0MDBcclxuICAgICAgKTtcclxuICAgIH1cclxuXHJcbiAgICAvLyBUaHJvdyBhbiBlcnJvciBpZiB0ZXN0IG9mIHhsaW5rOmhyZWYgZWxlbWVudHMgZnJvbSBwYXlsb2FkJ3MgU1ZHIGZhaWxzXHJcbiAgICBpZiAoYm9keS5zdmcgJiYgaXNQcml2YXRlUmFuZ2VVcmxGb3VuZChib2R5LnN2ZykpIHtcclxuICAgICAgdGhyb3cgbmV3IEV4cG9ydEVycm9yKFxyXG4gICAgICAgIGBSZXF1ZXN0IFske3JlcXVlc3RJZH1dIC0gW3ZhbGlkYXRpb25dIFNWRyBwb3RlbnRpYWxseSBjb250YWluIGF0IGxlYXN0IG9uZSBmb3JiaWRkZW4gVVJMIGluICd4bGluazpocmVmJyBlbGVtZW50LiBQbGVhc2UgcmV2aWV3IHRoZSBTVkcgY29udGVudCBhbmQgZW5zdXJlIHRoYXQgYWxsIHJlZmVyZW5jZWQgVVJMcyBjb21wbHkgd2l0aCBzZWN1cml0eSBwb2xpY2llcy5gLFxyXG4gICAgICAgIDQwMFxyXG4gICAgICApO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIFZhbGlkYXRlIHRoZSByZXF1ZXN0IG9wdGlvbnMgYW5kIHN0b3JlIHBhcnNlZCBzdHJ1Y3R1cmUgaW4gdGhlIHJlcXVlc3RcclxuICAgIHJlcXVlc3QudmFsaWRhdGVkT3B0aW9ucyA9IHZhbGlkYXRlT3B0aW9ucyh7XHJcbiAgICAgIC8vIFNldCB0aGUgY3JlYXRlZCBJRCBhcyBhIGByZXF1ZXN0SWRgIHByb3BlcnR5IGluIHRoZSBvcHRpb25zXHJcbiAgICAgIHJlcXVlc3RJZCxcclxuICAgICAgZXhwb3J0OiB7XHJcbiAgICAgICAgaW5zdHIsXHJcbiAgICAgICAgc3ZnOiBib2R5LnN2ZyxcclxuICAgICAgICBvdXRmaWxlOlxyXG4gICAgICAgICAgYm9keS5vdXRmaWxlIHx8XHJcbiAgICAgICAgICBgJHtyZXF1ZXN0LnBhcmFtcy5maWxlbmFtZSB8fCAnY2hhcnQnfS4ke2JvZHkudHlwZSB8fCAncG5nJ31gLFxyXG4gICAgICAgIHR5cGU6IGJvZHkudHlwZSxcclxuICAgICAgICBjb25zdHI6IGJvZHkuY29uc3RyLFxyXG4gICAgICAgIGI2NDogYm9keS5iNjQsXHJcbiAgICAgICAgbm9Eb3dubG9hZDogYm9keS5ub0Rvd25sb2FkLFxyXG4gICAgICAgIGhlaWdodDogYm9keS5oZWlnaHQsXHJcbiAgICAgICAgd2lkdGg6IGJvZHkud2lkdGgsXHJcbiAgICAgICAgc2NhbGU6IGJvZHkuc2NhbGUsXHJcbiAgICAgICAgZ2xvYmFsT3B0aW9uczogaXNBbGxvd2VkQ29uZmlnKFxyXG4gICAgICAgICAgYm9keS5nbG9iYWxPcHRpb25zLFxyXG4gICAgICAgICAgdHJ1ZSxcclxuICAgICAgICAgIGFsbG93Q29kZUV4ZWN1dGlvblxyXG4gICAgICAgICksXHJcbiAgICAgICAgdGhlbWVPcHRpb25zOiBpc0FsbG93ZWRDb25maWcoXHJcbiAgICAgICAgICBib2R5LnRoZW1lT3B0aW9ucyxcclxuICAgICAgICAgIHRydWUsXHJcbiAgICAgICAgICBhbGxvd0NvZGVFeGVjdXRpb25cclxuICAgICAgICApXHJcbiAgICAgIH0sXHJcbiAgICAgIGN1c3RvbUxvZ2ljOiB7XHJcbiAgICAgICAgYWxsb3dDb2RlRXhlY3V0aW9uLFxyXG4gICAgICAgIGFsbG93RmlsZVJlc291cmNlczogZmFsc2UsXHJcbiAgICAgICAgY3VzdG9tQ29kZTogYm9keS5jdXN0b21Db2RlLFxyXG4gICAgICAgIGNhbGxiYWNrOiBib2R5LmNhbGxiYWNrLFxyXG4gICAgICAgIHJlc291cmNlczogaXNBbGxvd2VkQ29uZmlnKGJvZHkucmVzb3VyY2VzLCB0cnVlLCBhbGxvd0NvZGVFeGVjdXRpb24pXHJcbiAgICAgIH1cclxuICAgIH0pO1xyXG5cclxuICAgIC8vIENhbGwgdGhlIG5leHQgbWlkZGxld2FyZVxyXG4gICAgcmV0dXJuIG5leHQoKTtcclxuICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgcmV0dXJuIG5leHQoZXJyb3IpO1xyXG4gIH1cclxufVxyXG5cclxuLyoqXHJcbiAqIEFkZHMgdGhlIHZhbGlkYXRpb24gbWlkZGxld2FyZXMgdG8gdGhlIHBhc3NlZCBleHByZXNzIGFwcCBpbnN0YW5jZS5cclxuICpcclxuICogQHBhcmFtIHtFeHByZXNzfSBhcHAgLSBUaGUgRXhwcmVzcyBhcHAgaW5zdGFuY2UuXHJcbiAqL1xyXG5leHBvcnQgZGVmYXVsdCBmdW5jdGlvbiB2YWxpZGF0aW9uTWlkZGxld2FyZShhcHApIHtcclxuICAvLyBBZGQgY29udGVudCB0eXBlIHZhbGlkYXRpb24gbWlkZGxld2FyZVxyXG4gIGFwcC5wb3N0KFsnLycsICcvOmZpbGVuYW1lJ10sIGNvbnRlbnRUeXBlTWlkZGxld2FyZSk7XHJcblxyXG4gIC8vIEFkZCByZXF1ZXN0IGJvZHkgcmVxdWVzdCB2YWxpZGF0aW9uIG1pZGRsZXdhcmVcclxuICBhcHAucG9zdChbJy8nLCAnLzpmaWxlbmFtZSddLCByZXF1ZXN0Qm9keU1pZGRsZXdhcmUpO1xyXG59XHJcbiIsIi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXHJcblxyXG5IaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXJcclxuXHJcbkNvcHlyaWdodCAoYykgMjAxNi0yMDI1LCBIaWdoc29mdFxyXG5cclxuTGljZW5jZWQgdW5kZXIgdGhlIE1JVCBsaWNlbmNlLlxyXG5cclxuQWRkaXRpb25hbGx5IGEgdmFsaWQgSGlnaGNoYXJ0cyBsaWNlbnNlIGlzIHJlcXVpcmVkIGZvciB1c2UuXHJcblxyXG5TZWUgTElDRU5TRSBmaWxlIGluIHJvb3QgZm9yIGRldGFpbHMuXHJcblxyXG4qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xyXG5cclxuLyoqXHJcbiAqIEBvdmVydmlldyBEZWZpbmVzIHRoZSBleHBvcnQgcm91dGVzIGFuZCBsb2dpYyBmb3IgaGFuZGxpbmcgY2hhcnQgZXhwb3J0XHJcbiAqIHJlcXVlc3RzIGluIGFuIEV4cHJlc3Mgc2VydmVyLiBUaGlzIG1vZHVsZSBwcm9jZXNzZXMgaW5jb21pbmcgcmVxdWVzdHNcclxuICogdG8gZXhwb3J0IGNoYXJ0cyBpbiB2YXJpb3VzIGZvcm1hdHMgKGUuZy4gSlBFRywgUE5HLCBQREYsIFNWRykuIEl0IGludGVncmF0ZXNcclxuICogd2l0aCBIaWdoY2hhcnRzJyBjb3JlIGZ1bmN0aW9uYWxpdGllcyBhbmQgc3VwcG9ydHMgYm90aCBpbW1lZGlhdGUgZG93bmxvYWRcclxuICogcmVzcG9uc2VzIGFuZCBCYXNlNjQtZW5jb2RlZCBjb250ZW50IHJldHVybnMuIFRoZSBjb2RlIGFsc28gZmVhdHVyZXNcclxuICogYmVuY2htYXJraW5nIGZvciBwZXJmb3JtYW5jZSBtb25pdG9yaW5nLlxyXG4gKi9cclxuXHJcbmltcG9ydCB7IHN0YXJ0RXhwb3J0IH0gZnJvbSAnLi4vLi4vY2hhcnQuanMnO1xyXG5pbXBvcnQgeyBsb2cgfSBmcm9tICcuLi8uLi9sb2dnZXIuanMnO1xyXG5pbXBvcnQgeyBnZXRCYXNlNjQsIG1lYXN1cmVUaW1lIH0gZnJvbSAnLi4vLi4vdXRpbHMuanMnO1xyXG5cclxuaW1wb3J0IEV4cG9ydEVycm9yIGZyb20gJy4uLy4uL2Vycm9ycy9FeHBvcnRFcnJvci5qcyc7XHJcblxyXG4vLyBSZXZlcnNlZCBNSU1FIHR5cGVzXHJcbmNvbnN0IHJldmVyc2VkTWltZSA9IHtcclxuICBwbmc6ICdpbWFnZS9wbmcnLFxyXG4gIGpwZWc6ICdpbWFnZS9qcGVnJyxcclxuICBnaWY6ICdpbWFnZS9naWYnLFxyXG4gIHBkZjogJ2FwcGxpY2F0aW9uL3BkZicsXHJcbiAgc3ZnOiAnaW1hZ2Uvc3ZnK3htbCdcclxufTtcclxuXHJcbi8qKlxyXG4gKiBIYW5kbGVzIHRoZSBleHBvcnQgcmVxdWVzdHMgZnJvbSB0aGUgY2xpZW50LlxyXG4gKlxyXG4gKiBAYXN5bmNcclxuICogQGZ1bmN0aW9uIHJlcXVlc3RFeHBvcnRcclxuICpcclxuICogQHBhcmFtIHtFeHByZXNzLlJlcXVlc3R9IHJlcXVlc3QgLSBUaGUgRXhwcmVzcyByZXF1ZXN0IG9iamVjdC5cclxuICogQHBhcmFtIHtFeHByZXNzLlJlc3BvbnNlfSByZXNwb25zZSAtIFRoZSBFeHByZXNzIHJlc3BvbnNlIG9iamVjdC5cclxuICogQHBhcmFtIHtGdW5jdGlvbn0gbmV4dCAtIFRoZSBuZXh0IG1pZGRsZXdhcmUgZnVuY3Rpb24uXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtQcm9taXNlPHZvaWQ+fSBBIFByb21pc2UgdGhhdCByZXNvbHZlcyBvbmNlIHRoZSBleHBvcnQgcHJvY2Vzc1xyXG4gKiBpcyBjb21wbGV0ZS5cclxuICovXHJcbmFzeW5jIGZ1bmN0aW9uIHJlcXVlc3RFeHBvcnQocmVxdWVzdCwgcmVzcG9uc2UsIG5leHQpIHtcclxuICB0cnkge1xyXG4gICAgLy8gU3RhcnQgY291bnRpbmcgdGltZSBmb3IgYSByZXF1ZXN0XHJcbiAgICBjb25zdCByZXF1ZXN0Q291bnRlciA9IG1lYXN1cmVUaW1lKCk7XHJcblxyXG4gICAgLy8gSW4gY2FzZSB0aGUgY29ubmVjdGlvbiBpcyBjbG9zZWQsIGZvcmNlIHRvIGFib3J0IGZ1cnRoZXIgYWN0aW9uc1xyXG4gICAgbGV0IGNvbm5lY3Rpb25BYm9ydGVkID0gZmFsc2U7XHJcbiAgICByZXF1ZXN0LnNvY2tldC5vbignY2xvc2UnLCAoaGFkRXJyb3JzKSA9PiB7XHJcbiAgICAgIGlmIChoYWRFcnJvcnMpIHtcclxuICAgICAgICBjb25uZWN0aW9uQWJvcnRlZCA9IHRydWU7XHJcbiAgICAgIH1cclxuICAgIH0pO1xyXG5cclxuICAgIC8vIEdldCB0aGUgb3B0aW9ucyBwcmV2aW91c2x5IHZhbGlkYXRlZCBpbiB0aGUgdmFsaWRhdGlvbiBtaWRkbGV3YXJlXHJcbiAgICBjb25zdCByZXF1ZXN0T3B0aW9ucyA9IHJlcXVlc3QudmFsaWRhdGVkT3B0aW9ucztcclxuXHJcbiAgICAvLyBHZXQgdGhlIHJlcXVlc3QgaWRcclxuICAgIGNvbnN0IHJlcXVlc3RJZCA9IHJlcXVlc3RPcHRpb25zLnJlcXVlc3RJZDtcclxuXHJcbiAgICAvLyBJbmZvIGFib3V0IGFuIGluY29taW5nIHJlcXVlc3Qgd2l0aCBjb3JyZWN0IGRhdGFcclxuICAgIGxvZyg0LCBgW2V4cG9ydF0gUmVxdWVzdCBbJHtyZXF1ZXN0SWR9XSAtIEdvdCBhbiBpbmNvbWluZyBIVFRQIHJlcXVlc3QuYCk7XHJcblxyXG4gICAgLy8gU3RhcnQgdGhlIGV4cG9ydCBwcm9jZXNzXHJcbiAgICBhd2FpdCBzdGFydEV4cG9ydChyZXF1ZXN0T3B0aW9ucywgKGVycm9yLCBkYXRhKSA9PiB7XHJcbiAgICAgIC8vIFJlbW92ZSB0aGUgY2xvc2UgZXZlbnQgZnJvbSB0aGUgc29ja2V0XHJcbiAgICAgIHJlcXVlc3Quc29ja2V0LnJlbW92ZUFsbExpc3RlbmVycygnY2xvc2UnKTtcclxuXHJcbiAgICAgIC8vIElmIHRoZSBjb25uZWN0aW9uIHdhcyBjbG9zZWQsIGRvIG5vdGhpbmdcclxuICAgICAgaWYgKGNvbm5lY3Rpb25BYm9ydGVkKSB7XHJcbiAgICAgICAgbG9nKFxyXG4gICAgICAgICAgMyxcclxuICAgICAgICAgIGBbZXhwb3J0XSBSZXF1ZXN0IFske3JlcXVlc3RJZH1dIC0gVGhlIGNsaWVudCBjbG9zZWQgdGhlIGNvbm5lY3Rpb24gYmVmb3JlIHRoZSBjaGFydCBmaW5pc2hlZCBwcm9jZXNzaW5nLmBcclxuICAgICAgICApO1xyXG4gICAgICAgIHJldHVybjtcclxuICAgICAgfVxyXG5cclxuICAgICAgLy8gSWYgZXJyb3IsIGxvZyBpdCBhbmQgc2VuZCBpdCB0byB0aGUgZXJyb3IgbWlkZGxld2FyZVxyXG4gICAgICBpZiAoZXJyb3IpIHtcclxuICAgICAgICB0aHJvdyBlcnJvcjtcclxuICAgICAgfVxyXG5cclxuICAgICAgLy8gSWYgZGF0YSBpcyBtaXNzaW5nLCBsb2cgdGhlIG1lc3NhZ2UgYW5kIHNlbmQgaXQgdG8gdGhlIGVycm9yIG1pZGRsZXdhcmVcclxuICAgICAgaWYgKCFkYXRhIHx8ICFkYXRhLnJlc3VsdCkge1xyXG4gICAgICAgIGxvZyhcclxuICAgICAgICAgIDIsXHJcbiAgICAgICAgICBgW2V4cG9ydF0gUmVxdWVzdCBbJHtyZXF1ZXN0SWR9XSAtIFJlcXVlc3QgZnJvbSAke1xyXG4gICAgICAgICAgICByZXF1ZXN0LmhlYWRlcnNbJ3gtZm9yd2FyZGVkLWZvciddIHx8XHJcbiAgICAgICAgICAgIHJlcXVlc3QuY29ubmVjdGlvbi5yZW1vdGVBZGRyZXNzXHJcbiAgICAgICAgICB9IHdhcyBpbmNvcnJlY3QuIFJlY2VpdmVkIHJlc3VsdCBpcyAke2RhdGEucmVzdWx0fS5gXHJcbiAgICAgICAgKTtcclxuXHJcbiAgICAgICAgdGhyb3cgbmV3IEV4cG9ydEVycm9yKFxyXG4gICAgICAgICAgYFtleHBvcnRdIFJlcXVlc3QgWyR7cmVxdWVzdElkfV0gLSBVbmV4cGVjdGVkIHJldHVybiBvZiB0aGUgZXhwb3J0IHJlc3VsdCBmcm9tIHRoZSBjaGFydCBnZW5lcmF0aW9uLiBQbGVhc2UgY2hlY2sgeW91ciByZXF1ZXN0IGRhdGEuYCxcclxuICAgICAgICAgIDQwMFxyXG4gICAgICAgICk7XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIC8vIFJldHVybiB0aGUgcmVzdWx0IGluIGFuIGFwcHJvcHJpYXRlIGZvcm1hdFxyXG4gICAgICBpZiAoZGF0YS5yZXN1bHQpIHtcclxuICAgICAgICBsb2coXHJcbiAgICAgICAgICAzLFxyXG4gICAgICAgICAgYFtleHBvcnRdIFJlcXVlc3QgWyR7cmVxdWVzdElkfV0gLSBUaGUgd2hvbGUgZXhwb3J0aW5nIHByb2Nlc3MgdG9vayAke3JlcXVlc3RDb3VudGVyKCl9bXMuYFxyXG4gICAgICAgICk7XHJcblxyXG4gICAgICAgIC8vIEdldCB0aGUgYHR5cGVgLCBgYjY0YCwgYG5vRG93bmxvYWRgLCBhbmQgYG91dGZpbGVgIGZyb20gb3B0aW9uc1xyXG4gICAgICAgIGNvbnN0IHsgdHlwZSwgYjY0LCBub0Rvd25sb2FkLCBvdXRmaWxlIH0gPSBkYXRhLm9wdGlvbnMuZXhwb3J0O1xyXG5cclxuICAgICAgICAvLyBJZiBvbmx5IEJhc2U2NCBpcyByZXF1aXJlZCwgcmV0dXJuIGl0XHJcbiAgICAgICAgaWYgKGI2NCkge1xyXG4gICAgICAgICAgcmV0dXJuIHJlc3BvbnNlLnNlbmQoZ2V0QmFzZTY0KGRhdGEucmVzdWx0LCB0eXBlKSk7XHJcbiAgICAgICAgfVxyXG5cclxuICAgICAgICAvLyBTZXQgY29ycmVjdCBjb250ZW50IHR5cGVcclxuICAgICAgICByZXNwb25zZS5oZWFkZXIoJ0NvbnRlbnQtVHlwZScsIHJldmVyc2VkTWltZVt0eXBlXSB8fCAnaW1hZ2UvcG5nJyk7XHJcblxyXG4gICAgICAgIC8vIERlY2lkZSB3aGV0aGVyIHRvIGRvd25sb2FkIG9yIG5vdCBjaGFydCBmaWxlXHJcbiAgICAgICAgaWYgKCFub0Rvd25sb2FkKSB7XHJcbiAgICAgICAgICByZXNwb25zZS5hdHRhY2htZW50KG91dGZpbGUpO1xyXG4gICAgICAgIH1cclxuXHJcbiAgICAgICAgLy8gSWYgU1ZHLCByZXR1cm4gcGxhaW4gY29udGVudCwgb3RoZXJ3aXNlIGEgYjY0IHN0cmluZyBmcm9tIGEgYnVmZmVyXHJcbiAgICAgICAgcmV0dXJuIHR5cGUgPT09ICdzdmcnXHJcbiAgICAgICAgICA/IHJlc3BvbnNlLnNlbmQoZGF0YS5yZXN1bHQpXHJcbiAgICAgICAgICA6IHJlc3BvbnNlLnNlbmQoQnVmZmVyLmZyb20oZGF0YS5yZXN1bHQsICdiYXNlNjQnKSk7XHJcbiAgICAgIH1cclxuICAgIH0pO1xyXG4gIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICByZXR1cm4gbmV4dChlcnJvcik7XHJcbiAgfVxyXG59XHJcblxyXG4vKipcclxuICogQWRkcyB0aGUgYGV4cG9ydGAgcm91dGVzLlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gZXhwb3J0Um91dGVzXHJcbiAqXHJcbiAqIEBwYXJhbSB7RXhwcmVzc30gYXBwIC0gVGhlIEV4cHJlc3MgYXBwIGluc3RhbmNlLlxyXG4gKi9cclxuZXhwb3J0IGRlZmF1bHQgZnVuY3Rpb24gZXhwb3J0Um91dGVzKGFwcCkge1xyXG4gIC8qKlxyXG4gICAqIEFkZHMgdGhlIFBPU1QgJy8nIC0gQSByb3V0ZSBmb3IgaGFuZGxpbmcgUE9TVCByZXF1ZXN0cyBhdCB0aGUgcm9vdFxyXG4gICAqIGVuZHBvaW50LlxyXG4gICAqL1xyXG4gIGFwcC5wb3N0KCcvJywgcmVxdWVzdEV4cG9ydCk7XHJcblxyXG4gIC8qKlxyXG4gICAqIEFkZHMgdGhlIFBPU1QgJy86ZmlsZW5hbWUnIC0gQSByb3V0ZSBmb3IgaGFuZGxpbmcgUE9TVCByZXF1ZXN0cyB3aXRoXHJcbiAgICogYSBzcGVjaWZpZWQgZmlsZW5hbWUgcGFyYW1ldGVyLlxyXG4gICAqL1xyXG4gIGFwcC5wb3N0KCcvOmZpbGVuYW1lJywgcmVxdWVzdEV4cG9ydCk7XHJcbn1cclxuIiwiLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcclxuXHJcbkhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlclxyXG5cclxuQ29weXJpZ2h0IChjKSAyMDE2LTIwMjUsIEhpZ2hzb2Z0XHJcblxyXG5MaWNlbmNlZCB1bmRlciB0aGUgTUlUIGxpY2VuY2UuXHJcblxyXG5BZGRpdGlvbmFsbHkgYSB2YWxpZCBIaWdoY2hhcnRzIGxpY2Vuc2UgaXMgcmVxdWlyZWQgZm9yIHVzZS5cclxuXHJcblNlZSBMSUNFTlNFIGZpbGUgaW4gcm9vdCBmb3IgZGV0YWlscy5cclxuXHJcbioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXHJcblxyXG4vKipcclxuICogQG92ZXJ2aWV3IERlZmluZXMgYW4gRXhwcmVzcyByb3V0ZSBmb3Igc2VydmVyIGhlYWx0aCBtb25pdG9yaW5nLCBpbmNsdWRpbmdcclxuICogdXB0aW1lLCBzdWNjZXNzIHJhdGVzLCBhbmQgb3RoZXIgc2VydmVyIHN0YXRpc3RpY3MuXHJcbiAqL1xyXG5cclxuaW1wb3J0IHsgcmVhZEZpbGVTeW5jIH0gZnJvbSAnZnMnO1xyXG5pbXBvcnQgeyBqb2luIH0gZnJvbSAncGF0aCc7XHJcblxyXG5pbXBvcnQgeyBnZXRIaWdoY2hhcnRzVmVyc2lvbiB9IGZyb20gJy4uLy4uL2NhY2hlLmpzJztcclxuaW1wb3J0IHsgbG9nIH0gZnJvbSAnLi4vLi4vbG9nZ2VyLmpzJztcclxuaW1wb3J0IHsgZ2V0UG9vbFN0YXRzLCBnZXRQb29sSW5mb0pTT04gfSBmcm9tICcuLi8uLi9wb29sLmpzJztcclxuaW1wb3J0IHsgYWRkVGltZXIgfSBmcm9tICcuLi8uLi90aW1lci5qcyc7XHJcbmltcG9ydCB7IF9fZGlybmFtZSwgZ2V0TmV3RGF0ZVRpbWUgfSBmcm9tICcuLi8uLi91dGlscy5qcyc7XHJcblxyXG4vLyBTZXQgdGhlIHN0YXJ0IGRhdGUgb2YgdGhlIHNlcnZlclxyXG5jb25zdCBzZXJ2ZXJTdGFydFRpbWUgPSBuZXcgRGF0ZSgpO1xyXG5cclxuLy8gR2V0IHRoZSBgcGFja2FnZS5qc29uYCBjb250ZW50XHJcbmNvbnN0IHBhY2thZ2VGaWxlID0gSlNPTi5wYXJzZShcclxuICByZWFkRmlsZVN5bmMoam9pbihfX2Rpcm5hbWUsICdwYWNrYWdlLmpzb24nKSwgJ3V0ZjgnKVxyXG4pO1xyXG5cclxuLy8gQW4gYXJyYXkgZm9yIHN1Y2Nlc3MgcmF0ZSByYXRpb3NcclxuY29uc3Qgc3VjY2Vzc1JhdGVzID0gW107XHJcblxyXG4vLyBSZWNvcmQgZXZlcnkgbWludXRlXHJcbmNvbnN0IHJlY29yZEludGVydmFsID0gNjAgKiAxMDAwO1xyXG5cclxuLy8gMzAgbWludXRlc1xyXG5jb25zdCB3aW5kb3dTaXplID0gMzA7XHJcblxyXG4vKipcclxuICogQ2FsY3VsYXRlcyBtb3ZpbmcgYXZlcmFnZSBpbmRpY2F0b3IgYmFzZWQgb24gdGhlIGRhdGEgZnJvbSB0aGUgYHN1Y2Nlc3NSYXRlc2BcclxuICogYXJyYXkuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBfY2FsY3VsYXRlTW92aW5nQXZlcmFnZVxyXG4gKlxyXG4gKiBAcmV0dXJucyB7bnVtYmVyfSBBIG1vdmluZyBhdmVyYWdlIGZvciBzdWNjZXNzIHJhdGlvIG9mIHRoZSBzZXJ2ZXIgZXhwb3J0cy5cclxuICovXHJcbmZ1bmN0aW9uIF9jYWxjdWxhdGVNb3ZpbmdBdmVyYWdlKCkge1xyXG4gIHJldHVybiBzdWNjZXNzUmF0ZXMucmVkdWNlKChhLCBiKSA9PiBhICsgYiwgMCkgLyBzdWNjZXNzUmF0ZXMubGVuZ3RoO1xyXG59XHJcblxyXG4vKipcclxuICogU3RhcnRzIHRoZSBpbnRlcnZhbCByZXNwb25zaWJsZSBmb3IgY2FsY3VsYXRpbmcgY3VycmVudCBzdWNjZXNzIHJhdGUgcmF0aW9cclxuICogYW5kIGNvbGxlY3RzIHJlY29yZHMgdG8gdGhlIGBzdWNjZXNzUmF0ZXNgIGFycmF5LlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gX3N0YXJ0U3VjY2Vzc1JhdGVcclxuICpcclxuICogQHJldHVybnMge05vZGVKUy5UaW1lb3V0fSBJZCBvZiBhbiBpbnRlcnZhbC5cclxuICovXHJcbmZ1bmN0aW9uIF9zdGFydFN1Y2Nlc3NSYXRlKCkge1xyXG4gIHJldHVybiBzZXRJbnRlcnZhbCgoKSA9PiB7XHJcbiAgICBjb25zdCBzdGF0cyA9IGdldFBvb2xTdGF0cygpO1xyXG4gICAgY29uc3Qgc3VjY2Vzc1JhdGlvID1cclxuICAgICAgc3RhdHMuZXhwb3J0c0F0dGVtcHRlZCA9PT0gMFxyXG4gICAgICAgID8gMVxyXG4gICAgICAgIDogKHN0YXRzLmV4cG9ydHNQZXJmb3JtZWQgLyBzdGF0cy5leHBvcnRzQXR0ZW1wdGVkKSAqIDEwMDtcclxuXHJcbiAgICBzdWNjZXNzUmF0ZXMucHVzaChzdWNjZXNzUmF0aW8pO1xyXG4gICAgaWYgKHN1Y2Nlc3NSYXRlcy5sZW5ndGggPiB3aW5kb3dTaXplKSB7XHJcbiAgICAgIHN1Y2Nlc3NSYXRlcy5zaGlmdCgpO1xyXG4gICAgfVxyXG4gIH0sIHJlY29yZEludGVydmFsKTtcclxufVxyXG5cclxuLyoqXHJcbiAqIEFkZHMgdGhlIGBoZWFsdGhgIHJvdXRlcy5cclxuICpcclxuICogQGZ1bmN0aW9uIGhlYWx0aFJvdXRlc1xyXG4gKlxyXG4gKiBAcGFyYW0ge0V4cHJlc3N9IGFwcCAtIFRoZSBFeHByZXNzIGFwcCBpbnN0YW5jZS5cclxuICovXHJcbmV4cG9ydCBkZWZhdWx0IGZ1bmN0aW9uIGhlYWx0aFJvdXRlcyhhcHApIHtcclxuICAvLyBTdGFydCBwcm9jZXNzaW5nIHN1Y2Nlc3MgcmF0ZSByYXRpbyBpbnRlcnZhbCBhbmQgc2F2ZSBpdHMgaWQgdG8gdGhlIGFycmF5XHJcbiAgLy8gZm9yIHRoZSBncmFjZWZ1bCBjbGVhcmluZyBvbiBzaHV0ZG93biB3aXRoIGluamVjdGVkIGBhZGRUaW1lcmAgZnVudGlvblxyXG4gIGFkZFRpbWVyKF9zdGFydFN1Y2Nlc3NSYXRlKCkpO1xyXG5cclxuICAvKipcclxuICAgKiBBZGRzIHRoZSBHRVQgJy9oZWFsdGgnIC0gQSByb3V0ZSBmb3IgZ2V0dGluZyB0aGUgYmFzaWMgc3RhdHMgb2YgdGhlIHNlcnZlci5cclxuICAgKi9cclxuICBhcHAuZ2V0KCcvaGVhbHRoJywgKHJlcXVlc3QsIHJlc3BvbnNlLCBuZXh0KSA9PiB7XHJcbiAgICB0cnkge1xyXG4gICAgICBsb2coNCwgJ1toZWFsdGhdIFJldHVybmluZyBzZXJ2ZXIgaGVhbHRoLicpO1xyXG5cclxuICAgICAgY29uc3Qgc3RhdHMgPSBnZXRQb29sU3RhdHMoKTtcclxuICAgICAgY29uc3QgcGVyaW9kID0gc3VjY2Vzc1JhdGVzLmxlbmd0aDtcclxuICAgICAgY29uc3QgbW92aW5nQXZlcmFnZSA9IF9jYWxjdWxhdGVNb3ZpbmdBdmVyYWdlKCk7XHJcblxyXG4gICAgICAvLyBTZW5kIHRoZSBzZXJ2ZXIncyBzdGF0aXN0aWNzXHJcbiAgICAgIHJlc3BvbnNlLnNlbmQoe1xyXG4gICAgICAgIC8vIFN0YXR1cyBhbmQgdGltZXNcclxuICAgICAgICBzdGF0dXM6ICdPSycsXHJcbiAgICAgICAgYm9vdFRpbWU6IHNlcnZlclN0YXJ0VGltZSxcclxuICAgICAgICB1cHRpbWU6IGAke01hdGguZmxvb3IoKGdldE5ld0RhdGVUaW1lKCkgLSBzZXJ2ZXJTdGFydFRpbWUuZ2V0VGltZSgpKSAvIDEwMDAgLyA2MCl9IG1pbnV0ZXNgLFxyXG5cclxuICAgICAgICAvLyBWZXJzaW9uc1xyXG4gICAgICAgIHNlcnZlclZlcnNpb246IHBhY2thZ2VGaWxlLnZlcnNpb24sXHJcbiAgICAgICAgaGlnaGNoYXJ0c1ZlcnNpb246IGdldEhpZ2hjaGFydHNWZXJzaW9uKCksXHJcblxyXG4gICAgICAgIC8vIEV4cG9ydHNcclxuICAgICAgICBhdmVyYWdlRXhwb3J0VGltZTogc3RhdHMudGltZVNwZW50QXZlcmFnZSxcclxuICAgICAgICBhdHRlbXB0ZWRFeHBvcnRzOiBzdGF0cy5leHBvcnRzQXR0ZW1wdGVkLFxyXG4gICAgICAgIHBlcmZvcm1lZEV4cG9ydHM6IHN0YXRzLmV4cG9ydHNQZXJmb3JtZWQsXHJcbiAgICAgICAgZmFpbGVkRXhwb3J0czogc3RhdHMuZXhwb3J0c0Ryb3BwZWQsXHJcbiAgICAgICAgc3VjZXNzUmF0aW86IChzdGF0cy5leHBvcnRzUGVyZm9ybWVkIC8gc3RhdHMuZXhwb3J0c0F0dGVtcHRlZCkgKiAxMDAsXHJcblxyXG4gICAgICAgIC8vIFBvb2xcclxuICAgICAgICBwb29sOiBnZXRQb29sSW5mb0pTT04oKSxcclxuXHJcbiAgICAgICAgLy8gTW92aW5nIGF2ZXJhZ2VcclxuICAgICAgICBwZXJpb2QsXHJcbiAgICAgICAgbW92aW5nQXZlcmFnZSxcclxuICAgICAgICBtZXNzYWdlOlxyXG4gICAgICAgICAgaXNOYU4obW92aW5nQXZlcmFnZSkgfHwgIXN1Y2Nlc3NSYXRlcy5sZW5ndGhcclxuICAgICAgICAgICAgPyAnVG9vIGVhcmx5IHRvIHJlcG9ydC4gTm8gZXhwb3J0cyBtYWRlIHlldC4gUGxlYXNlIGNoZWNrIGJhY2sgc29vbi4nXHJcbiAgICAgICAgICAgIDogYExhc3QgJHtwZXJpb2R9IG1pbnV0ZXMgaGFkIGEgc3VjY2VzcyByYXRlIG9mICR7bW92aW5nQXZlcmFnZS50b0ZpeGVkKDIpfSUuYCxcclxuXHJcbiAgICAgICAgLy8gU1ZHIGFuZCBKU09OIGV4cG9ydHNcclxuICAgICAgICBzdmdFeHBvcnRzOiBzdGF0cy5leHBvcnRzRnJvbVN2ZyxcclxuICAgICAgICBqc29uRXhwb3J0czogc3RhdHMuZXhwb3J0c0Zyb21PcHRpb25zLFxyXG4gICAgICAgIHN2Z0V4cG9ydHNBdHRlbXB0czogc3RhdHMuZXhwb3J0c0Zyb21TdmdBdHRlbXB0cyxcclxuICAgICAgICBqc29uRXhwb3J0c0F0dGVtcHRzOiBzdGF0cy5leHBvcnRzRnJvbU9wdGlvbnNBdHRlbXB0c1xyXG4gICAgICB9KTtcclxuICAgIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICAgIHJldHVybiBuZXh0KGVycm9yKTtcclxuICAgIH1cclxuICB9KTtcclxufVxyXG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxyXG5cclxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXHJcblxyXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNSwgSGlnaHNvZnRcclxuXHJcbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cclxuXHJcbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxyXG5cclxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxyXG5cclxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cclxuXHJcbi8qKlxyXG4gKiBAb3ZlcnZpZXcgRGVmaW5lcyBhbiBFeHByZXNzIHJvdXRlIGZvciBzZXJ2aW5nIHRoZSBVSSBmb3IgdGhlIGV4cG9ydCBzZXJ2ZXJcclxuICogd2hlbiBlbmFibGVkLlxyXG4gKi9cclxuXHJcbmltcG9ydCB7IGpvaW4gfSBmcm9tICdwYXRoJztcclxuXHJcbmltcG9ydCB7IGdldE9wdGlvbnMgfSBmcm9tICcuLi8uLi9jb25maWcuanMnO1xyXG5pbXBvcnQgeyBsb2cgfSBmcm9tICcuLi8uLi9sb2dnZXIuanMnO1xyXG5pbXBvcnQgeyBfX2Rpcm5hbWUgfSBmcm9tICcuLi8uLi91dGlscy5qcyc7XHJcblxyXG4vKipcclxuICogQWRkcyB0aGUgYHVpYCByb3V0ZXMuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiB1aVJvdXRlc1xyXG4gKlxyXG4gKiBAcGFyYW0ge0V4cHJlc3N9IGFwcCAtIFRoZSBFeHByZXNzIGFwcCBpbnN0YW5jZS5cclxuICovXHJcbmV4cG9ydCBkZWZhdWx0IGZ1bmN0aW9uIHVpUm91dGVzKGFwcCkge1xyXG4gIC8qKlxyXG4gICAqIEFkZHMgdGhlIEdFVCAnLycgLSBBIHJvdXRlIGZvciBhIFVJIHdoZW4gZW5hYmxlZCBvbiB0aGUgZXhwb3J0IHNlcnZlci5cclxuICAgKi9cclxuICBhcHAuZ2V0KGdldE9wdGlvbnMoKS51aS5yb3V0ZSB8fCAnLycsIChyZXF1ZXN0LCByZXNwb25zZSwgbmV4dCkgPT4ge1xyXG4gICAgdHJ5IHtcclxuICAgICAgbG9nKDQsICdbdWldIFJldHVybmluZyBVSSBmb3IgdGhlIGV4cG9ydC4nKTtcclxuXHJcbiAgICAgIHJlc3BvbnNlLnNlbmRGaWxlKGpvaW4oX19kaXJuYW1lLCAncHVibGljJywgJ2luZGV4Lmh0bWwnKSwge1xyXG4gICAgICAgIGFjY2VwdFJhbmdlczogZmFsc2VcclxuICAgICAgfSk7XHJcbiAgICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgICByZXR1cm4gbmV4dChlcnJvcik7XHJcbiAgICB9XHJcbiAgfSk7XHJcbn1cclxuIiwiLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcclxuXHJcbkhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlclxyXG5cclxuQ29weXJpZ2h0IChjKSAyMDE2LTIwMjUsIEhpZ2hzb2Z0XHJcblxyXG5MaWNlbmNlZCB1bmRlciB0aGUgTUlUIGxpY2VuY2UuXHJcblxyXG5BZGRpdGlvbmFsbHkgYSB2YWxpZCBIaWdoY2hhcnRzIGxpY2Vuc2UgaXMgcmVxdWlyZWQgZm9yIHVzZS5cclxuXHJcblNlZSBMSUNFTlNFIGZpbGUgaW4gcm9vdCBmb3IgZGV0YWlscy5cclxuXHJcbioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXHJcblxyXG4vKipcclxuICogQG92ZXJ2aWV3IERlZmluZXMgYW4gRXhwcmVzcyByb3V0ZSBmb3IgdXBkYXRpbmcgdGhlIEhpZ2hjaGFydHMgdmVyc2lvblxyXG4gKiBvbiB0aGUgc2VydmVyLCB3aXRoIGF1dGhlbnRpY2F0aW9uIGFuZCB2YWxpZGF0aW9uLlxyXG4gKi9cclxuXHJcbmltcG9ydCB7IHVwZGF0ZUhpZ2hjaGFydHNWZXJzaW9uLCBnZXRIaWdoY2hhcnRzVmVyc2lvbiB9IGZyb20gJy4uLy4uL2NhY2hlLmpzJztcclxuaW1wb3J0IHsgdmFsaWRhdGVPcHRpb24gfSBmcm9tICcuLi8uLi9jb25maWcuanMnO1xyXG5pbXBvcnQgeyBsb2cgfSBmcm9tICcuLi8uLi9sb2dnZXIuanMnO1xyXG5pbXBvcnQgeyBlbnZzIH0gZnJvbSAnLi4vLi4vdmFsaWRhdGlvbi5qcyc7XHJcblxyXG5pbXBvcnQgRXhwb3J0RXJyb3IgZnJvbSAnLi4vLi4vZXJyb3JzL0V4cG9ydEVycm9yLmpzJztcclxuXHJcbi8qKlxyXG4gKiBBZGRzIHRoZSBgdmVyc2lvbl9jaGFuZ2VgIHJvdXRlcy5cclxuICpcclxuICogQGZ1bmN0aW9uIHZlcnNpb25DaGFuZ2VSb3V0ZXNcclxuICpcclxuICogQHBhcmFtIHtFeHByZXNzfSBhcHAgLSBUaGUgRXhwcmVzcyBhcHAgaW5zdGFuY2UuXHJcbiAqL1xyXG5leHBvcnQgZGVmYXVsdCBmdW5jdGlvbiB2ZXJzaW9uQ2hhbmdlUm91dGVzKGFwcCkge1xyXG4gIC8qKlxyXG4gICAqIEFkZHMgdGhlIFBPU1QgJy92ZXJzaW9uX2NoYW5nZS86bmV3VmVyc2lvbicgLSBBIHJvdXRlIGZvciBjaGFuZ2luZ1xyXG4gICAqIHRoZSBIaWdoY2hhcnRzIHZlcnNpb24gb24gdGhlIHNlcnZlci5cclxuICAgKi9cclxuICBhcHAucG9zdCgnL3ZlcnNpb25fY2hhbmdlLzpuZXdWZXJzaW9uJywgYXN5bmMgKHJlcXVlc3QsIHJlc3BvbnNlLCBuZXh0KSA9PiB7XHJcbiAgICB0cnkge1xyXG4gICAgICBsb2coNCwgJ1t2ZXJzaW9uXSBDaGFuZ2luZyBIaWdoY2hhcnRzIHZlcnNpb24uJyk7XHJcblxyXG4gICAgICAvLyBHZXQgdGhlIHRva2VuIGRpcmVjdGx5IGZyb20gZW52c1xyXG4gICAgICBjb25zdCBhZG1pblRva2VuID0gZW52cy5ISUdIQ0hBUlRTX0FETUlOX1RPS0VOO1xyXG5cclxuICAgICAgLy8gQ2hlY2sgdGhlIGV4aXN0ZW5jZSBvZiB0aGUgdG9rZW5cclxuICAgICAgaWYgKCFhZG1pblRva2VuIHx8ICFhZG1pblRva2VuLmxlbmd0aCkge1xyXG4gICAgICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcihcclxuICAgICAgICAgICdbdmVyc2lvbl0gVGhlIHNlcnZlciBpcyBub3QgY29uZmlndXJlZCB0byBwZXJmb3JtIHJ1bi10aW1lIHZlcnNpb24gY2hhbmdlczogSElHSENIQVJUU19BRE1JTl9UT0tFTiBpcyBub3Qgc2V0LicsXHJcbiAgICAgICAgICA0MDFcclxuICAgICAgICApO1xyXG4gICAgICB9XHJcblxyXG4gICAgICAvLyBHZXQgdGhlIHRva2VuIGZyb20gdGhlIGhjLWF1dGggaGVhZGVyXHJcbiAgICAgIGNvbnN0IHRva2VuID0gcmVxdWVzdC5nZXQoJ2hjLWF1dGgnKTtcclxuXHJcbiAgICAgIC8vIENoZWNrIGlmIHRoZSBoYy1hdXRoIGhlYWRlciBjb250YWluIGEgY29ycmVjdCB0b2tlblxyXG4gICAgICBpZiAoIXRva2VuIHx8IHRva2VuICE9PSBhZG1pblRva2VuKSB7XHJcbiAgICAgICAgdGhyb3cgbmV3IEV4cG9ydEVycm9yKFxyXG4gICAgICAgICAgJ1t2ZXJzaW9uXSBJbnZhbGlkIG9yIG1pc3NpbmcgdG9rZW46IFNldCB0aGUgdG9rZW4gaW4gdGhlIGhjLWF1dGggaGVhZGVyLicsXHJcbiAgICAgICAgICA0MDFcclxuICAgICAgICApO1xyXG4gICAgICB9XHJcblxyXG4gICAgICAvLyBDb21wYXJlIHZlcnNpb25zXHJcbiAgICAgIGxldCBuZXdWZXJzaW9uID0gcmVxdWVzdC5wYXJhbXMubmV3VmVyc2lvbjtcclxuXHJcbiAgICAgIC8vIFZhbGlkYXRlIHRoZSB2ZXJzaW9uXHJcbiAgICAgIHRyeSB7XHJcbiAgICAgICAgbmV3VmVyc2lvbiA9IHZhbGlkYXRlT3B0aW9uKCd2ZXJzaW9uJywgcmVxdWVzdC5wYXJhbXMubmV3VmVyc2lvbik7XHJcbiAgICAgIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICAgICAgdGhyb3cgbmV3IEV4cG9ydEVycm9yKFxyXG4gICAgICAgICAgYFt2ZXJzaW9uXSBWZXJzaW9uIGlzIGluY29ycmVjdDogJHtlcnJvci5tZXNzYWdlfWAsXHJcbiAgICAgICAgICA0MDBcclxuICAgICAgICApLnNldEVycm9yKGVycm9yKTtcclxuICAgICAgfVxyXG5cclxuICAgICAgLy8gV2hlbiBhIGNvcnJlY3QgdmFsdWUgZm91bmRcclxuICAgICAgaWYgKG5ld1ZlcnNpb24pIHtcclxuICAgICAgICB0cnkge1xyXG4gICAgICAgICAgLy8gVXBkYXRlIHZlcnNpb25cclxuICAgICAgICAgIGF3YWl0IHVwZGF0ZUhpZ2hjaGFydHNWZXJzaW9uKG5ld1ZlcnNpb24pO1xyXG4gICAgICAgIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICAgICAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoXHJcbiAgICAgICAgICAgIGBbdmVyc2lvbl0gVmVyc2lvbiBjaGFuZ2U6ICR7ZXJyb3IubWVzc2FnZX1gLFxyXG4gICAgICAgICAgICA0MDBcclxuICAgICAgICAgICkuc2V0RXJyb3IoZXJyb3IpO1xyXG4gICAgICAgIH1cclxuXHJcbiAgICAgICAgLy8gU3VjY2Vzc1xyXG4gICAgICAgIHJlc3BvbnNlLnN0YXR1cygyMDApLnNlbmQoe1xyXG4gICAgICAgICAgc3RhdHVzQ29kZTogMjAwLFxyXG4gICAgICAgICAgaGlnaGNoYXJ0c1ZlcnNpb246IGdldEhpZ2hjaGFydHNWZXJzaW9uKCksXHJcbiAgICAgICAgICBtZXNzYWdlOiBgU3VjY2Vzc2Z1bGx5IHVwZGF0ZWQgSGlnaGNoYXJ0cyB0byB2ZXJzaW9uOiAke25ld1ZlcnNpb259LmBcclxuICAgICAgICB9KTtcclxuICAgICAgfSBlbHNlIHtcclxuICAgICAgICAvLyBObyB2ZXJzaW9uIHNwZWNpZmllZFxyXG4gICAgICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcignW3ZlcnNpb25dIE5vIG5ldyB2ZXJzaW9uIHN1cHBsaWVkLicsIDQwMCk7XHJcbiAgICAgIH1cclxuICAgIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICAgIHJldHVybiBuZXh0KGVycm9yKTtcclxuICAgIH1cclxuICB9KTtcclxufVxyXG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxyXG5cclxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXHJcblxyXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNSwgSGlnaHNvZnRcclxuXHJcbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cclxuXHJcbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxyXG5cclxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxyXG5cclxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cclxuXHJcbi8qKlxyXG4gKiBAb3ZlcnZpZXcgQSBtb2R1bGUgdGhhdCBzZXRzIHVwIGFuZCBtYW5hZ2VzIEhUVFAgYW5kIEhUVFBTIHNlcnZlcnNcclxuICogZm9yIHRoZSBIaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXIuIEl0IGhhbmRsZXMgc2VydmVyIGluaXRpYWxpemF0aW9uLFxyXG4gKiBjb25maWd1cmF0aW9uLCBlcnJvciBoYW5kbGluZywgbWlkZGxld2FyZSBzZXR1cCwgcm91dGUgZGVmaW5pdGlvbiwgYW5kIHJhdGVcclxuICogbGltaXRpbmcuIFRoZSBtb2R1bGUgZXhwb3J0cyBmdW5jdGlvbnMgdG8gc3RhcnQsIHN0b3AsIGFuZCBtYW5hZ2Ugc2VydmVyXHJcbiAqIGluc3RhbmNlcywgYXMgd2VsbCBhcyB1dGlsaXR5IGZ1bmN0aW9ucyBmb3IgZGVmaW5pbmcgcm91dGVzIGFuZCBhdHRhY2hpbmdcclxuICogbWlkZGxld2FyZXMuXHJcbiAqL1xyXG5cclxuaW1wb3J0IHsgcmVhZEZpbGUgfSBmcm9tICdmcy9wcm9taXNlcyc7XHJcbmltcG9ydCB7IGpvaW4gfSBmcm9tICdwYXRoJztcclxuXHJcbmltcG9ydCBjb3JzIGZyb20gJ2NvcnMnO1xyXG5pbXBvcnQgZXhwcmVzcyBmcm9tICdleHByZXNzJztcclxuaW1wb3J0IGh0dHAgZnJvbSAnaHR0cCc7XHJcbmltcG9ydCBodHRwcyBmcm9tICdodHRwcyc7XHJcbmltcG9ydCBtdWx0ZXIgZnJvbSAnbXVsdGVyJztcclxuXHJcbmltcG9ydCB7IHVwZGF0ZU9wdGlvbnMsIHZhbGlkYXRlT3B0aW9ucyB9IGZyb20gJy4uL2NvbmZpZy5qcyc7XHJcbmltcG9ydCB7IGxvZywgbG9nV2l0aFN0YWNrIH0gZnJvbSAnLi4vbG9nZ2VyLmpzJztcclxuaW1wb3J0IHsgX19kaXJuYW1lLCBnZXRBYnNvbHV0ZVBhdGggfSBmcm9tICcuLi91dGlscy5qcyc7XHJcblxyXG5pbXBvcnQgZXJyb3JNaWRkbGV3YXJlIGZyb20gJy4vbWlkZGxld2FyZXMvZXJyb3IuanMnO1xyXG5pbXBvcnQgcmF0ZUxpbWl0aW5nTWlkZGxld2FyZSBmcm9tICcuL21pZGRsZXdhcmVzL3JhdGVMaW1pdGluZy5qcyc7XHJcbmltcG9ydCB2YWxpZGF0aW9uTWlkZGxld2FyZSBmcm9tICcuL21pZGRsZXdhcmVzL3ZhbGlkYXRpb24uanMnO1xyXG5cclxuaW1wb3J0IGV4cG9ydFJvdXRlcyBmcm9tICcuL3JvdXRlcy9leHBvcnQuanMnO1xyXG5pbXBvcnQgaGVhbHRoUm91dGVzIGZyb20gJy4vcm91dGVzL2hlYWx0aC5qcyc7XHJcbmltcG9ydCB1aVJvdXRlcyBmcm9tICcuL3JvdXRlcy91aS5qcyc7XHJcbmltcG9ydCB2ZXJzaW9uQ2hhbmdlUm91dGVzIGZyb20gJy4vcm91dGVzL3ZlcnNpb25DaGFuZ2UuanMnO1xyXG5cclxuaW1wb3J0IEV4cG9ydEVycm9yIGZyb20gJy4uL2Vycm9ycy9FeHBvcnRFcnJvci5qcyc7XHJcblxyXG4vLyBBcnJheSBvZiBhbiBhY3RpdmUgc2VydmVyc1xyXG5jb25zdCBhY3RpdmVTZXJ2ZXJzID0gbmV3IE1hcCgpO1xyXG5cclxuLy8gQ3JlYXRlIGV4cHJlc3MgYXBwXHJcbmNvbnN0IGFwcCA9IGV4cHJlc3MoKTtcclxuXHJcbi8qKlxyXG4gKiBTdGFydHMgYW4gSFRUUCBhbmQvb3IgSFRUUFMgc2VydmVyIGJhc2VkIG9uIHRoZSBwcm92aWRlZCBjb25maWd1cmF0aW9uLlxyXG4gKiBUaGUgYHNlcnZlck9wdGlvbnNgIG9iamVjdCBjb250YWlucyBzZXJ2ZXItcmVsYXRlZCBwcm9wZXJ0aWVzIChyZWZlclxyXG4gKiB0byB0aGUgYHNlcnZlcmAgc2VjdGlvbiBpbiB0aGUgYGxpYi9zY2hlbWFzL2NvbmZpZy5qc2AgZmlsZSBmb3IgZGV0YWlscykuXHJcbiAqXHJcbiAqIEBhc3luY1xyXG4gKiBAZnVuY3Rpb24gc3RhcnRTZXJ2ZXJcclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IHNlcnZlck9wdGlvbnMgLSBUaGUgY29uZmlndXJhdGlvbiBvYmplY3QgY29udGFpbmluZyBgc2VydmVyYFxyXG4gKiBvcHRpb25zLiBUaGlzIG9iamVjdCBtYXkgaW5jbHVkZSBhIHBhcnRpYWwgb3IgY29tcGxldGUgc2V0IG9mIHRoZSBgc2VydmVyYFxyXG4gKiBvcHRpb25zLiBJZiB0aGUgb3B0aW9ucyBhcmUgcGFydGlhbCwgbWlzc2luZyB2YWx1ZXMgd2lsbCBkZWZhdWx0XHJcbiAqIHRvIHRoZSBjdXJyZW50IGdsb2JhbCBjb25maWd1cmF0aW9uLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7UHJvbWlzZTx2b2lkPn0gQSBQcm9taXNlIHRoYXQgcmVzb2x2ZXMgd2hlbiB0aGUgc2VydmVyIGlzIGVpdGhlclxyXG4gKiBub3QgZW5hYmxlZCBvciBubyB2YWxpZCBFeHByZXNzIGFwcCBpcyBmb3VuZCwgc2lnbmFsaW5nIHRoZSBlbmQgb2YgdGhlXHJcbiAqIGZ1bmN0aW9uJ3MgZXhlY3V0aW9uLlxyXG4gKlxyXG4gKiBAdGhyb3dzIHtFeHBvcnRFcnJvcn0gVGhyb3dzIGFuIGBFeHBvcnRFcnJvcmAgaWYgdGhlIHNlcnZlciBjYW5ub3RcclxuICogYmUgY29uZmlndXJlZCBhbmQgc3RhcnRlZC5cclxuICovXHJcbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBzdGFydFNlcnZlcihzZXJ2ZXJPcHRpb25zKSB7XHJcbiAgdHJ5IHtcclxuICAgIC8vIFVwZGF0ZSB0aGUgaW5zdGFuY2Ugb3B0aW9ucyBvYmplY3RcclxuICAgIGNvbnN0IG9wdGlvbnMgPSB1cGRhdGVPcHRpb25zKFxyXG4gICAgICB2YWxpZGF0ZU9wdGlvbnMoe1xyXG4gICAgICAgIHNlcnZlcjogc2VydmVyT3B0aW9uc1xyXG4gICAgICB9KVxyXG4gICAgKTtcclxuXHJcbiAgICAvLyBVc2UgdmFsaWRhdGVkIG9wdGlvbnNcclxuICAgIHNlcnZlck9wdGlvbnMgPSBvcHRpb25zLnNlcnZlcjtcclxuXHJcbiAgICAvLyBTdG9wIGlmIG5vdCBlbmFibGVkXHJcbiAgICBpZiAoIXNlcnZlck9wdGlvbnMuZW5hYmxlIHx8ICFhcHApIHtcclxuICAgICAgdGhyb3cgbmV3IEV4cG9ydEVycm9yKFxyXG4gICAgICAgICdbc2VydmVyXSBTZXJ2ZXIgY2Fubm90IGJlIHN0YXJ0ZWQgKG5vdCBlbmFibGVkIG9yIG5vIGNvcnJlY3QgRXhwcmVzcyBhcHAgZm91bmQpLicsXHJcbiAgICAgICAgNTAwXHJcbiAgICAgICk7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gVG9vIGJpZyBsaW1pdHMgbGVhZCB0byB0aW1lb3V0cyBpbiB0aGUgZXhwb3J0IHByb2Nlc3Mgd2hlblxyXG4gICAgLy8gdGhlIHJhc3Rlcml6YXRpb24gdGltZW91dCBpcyBzZXQgdG9vIGxvd1xyXG4gICAgY29uc3QgdXBsb2FkTGltaXRCeXRlcyA9IHNlcnZlck9wdGlvbnMudXBsb2FkTGltaXQgKiAxMDI0ICogMTAyNDtcclxuXHJcbiAgICAvLyBNZW1vcnkgc3RvcmFnZSBmb3IgbXVsdGVyIHBhY2thZ2VcclxuICAgIGNvbnN0IHN0b3JhZ2UgPSBtdWx0ZXIubWVtb3J5U3RvcmFnZSgpO1xyXG5cclxuICAgIC8vIEVuYWJsZSBwYXJzaW5nIG9mIGZvcm0gZGF0YSAoZmlsZXMpIHdpdGggbXVsdGVyIHBhY2thZ2VcclxuICAgIGNvbnN0IHVwbG9hZCA9IG11bHRlcih7XHJcbiAgICAgIHN0b3JhZ2UsXHJcbiAgICAgIGxpbWl0czoge1xyXG4gICAgICAgIGZpZWxkU2l6ZTogdXBsb2FkTGltaXRCeXRlc1xyXG4gICAgICB9XHJcbiAgICB9KTtcclxuXHJcbiAgICAvLyBEaXNhYmxlIHRoZSBYLVBvd2VyZWQtQnkgaGVhZGVyXHJcbiAgICBhcHAuZGlzYWJsZSgneC1wb3dlcmVkLWJ5Jyk7XHJcblxyXG4gICAgLy8gRW5hYmxlIENPUlMgc3VwcG9ydFxyXG4gICAgYXBwLnVzZShcclxuICAgICAgY29ycyh7XHJcbiAgICAgICAgbWV0aG9kczogWydQT1NUJywgJ0dFVCcsICdPUFRJT05TJ11cclxuICAgICAgfSlcclxuICAgICk7XHJcblxyXG4gICAgLy8gR2V0dGluZyBhIGxvdCBvZiBgUmFuZ2VOb3RTYXRpc2ZpYWJsZUVycm9yYCBleGNlcHRpb25zIChldmVuIHRob3VnaCB0aGlzXHJcbiAgICAvLyBpcyBhIGRlcHJlY2F0ZWQgb3B0aW9ucywgbGV0J3MgdHJ5IHRvIHNldCBpdCB0byBmYWxzZSlcclxuICAgIGFwcC51c2UoKHJlcXVlc3QsIHJlc3BvbnNlLCBuZXh0KSA9PiB7XHJcbiAgICAgIHJlc3BvbnNlLnNldCgnQWNjZXB0LVJhbmdlcycsICdub25lJyk7XHJcbiAgICAgIG5leHQoKTtcclxuICAgIH0pO1xyXG5cclxuICAgIC8vIEVuYWJsZSBib2R5IHBhcnNlciBmb3IgSlNPTiBkYXRhXHJcbiAgICBhcHAudXNlKFxyXG4gICAgICBleHByZXNzLmpzb24oe1xyXG4gICAgICAgIGxpbWl0OiB1cGxvYWRMaW1pdEJ5dGVzXHJcbiAgICAgIH0pXHJcbiAgICApO1xyXG5cclxuICAgIC8vIEVuYWJsZSBib2R5IHBhcnNlciBmb3IgVVJMLWVuY29kZWQgZm9ybSBkYXRhXHJcbiAgICBhcHAudXNlKFxyXG4gICAgICBleHByZXNzLnVybGVuY29kZWQoe1xyXG4gICAgICAgIGV4dGVuZGVkOiB0cnVlLFxyXG4gICAgICAgIGxpbWl0OiB1cGxvYWRMaW1pdEJ5dGVzXHJcbiAgICAgIH0pXHJcbiAgICApO1xyXG5cclxuICAgIC8vIFVzZSBvbmx5IG5vbi1maWxlIG11bHRpcGFydCBmb3JtIGZpZWxkc1xyXG4gICAgYXBwLnVzZSh1cGxvYWQubm9uZSgpKTtcclxuXHJcbiAgICAvLyBTZXQgdXAgc3RhdGljIGZvbGRlcidzIHJvdXRlXHJcbiAgICBhcHAudXNlKGV4cHJlc3Muc3RhdGljKGpvaW4oX19kaXJuYW1lLCAncHVibGljJykpKTtcclxuXHJcbiAgICAvLyBMaXN0ZW4gSFRUUCBzZXJ2ZXJcclxuICAgIGlmICghc2VydmVyT3B0aW9ucy5zc2wuZm9yY2UpIHtcclxuICAgICAgLy8gTWFpbiBzZXJ2ZXIgaW5zdGFuY2UgKEhUVFApXHJcbiAgICAgIGNvbnN0IGh0dHBTZXJ2ZXIgPSBodHRwLmNyZWF0ZVNlcnZlcihhcHApO1xyXG5cclxuICAgICAgLy8gQXR0YWNoIGVycm9yIGhhbmRsZXJzIGFuZCBsaXN0ZW4gdG8gdGhlIHNlcnZlclxyXG4gICAgICBfYXR0YWNoU2VydmVyRXJyb3JIYW5kbGVycyhodHRwU2VydmVyKTtcclxuXHJcbiAgICAgIC8vIExpc3RlblxyXG4gICAgICBodHRwU2VydmVyLmxpc3RlbihzZXJ2ZXJPcHRpb25zLnBvcnQsIHNlcnZlck9wdGlvbnMuaG9zdCwgKCkgPT4ge1xyXG4gICAgICAgIC8vIFNhdmUgdGhlIHJlZmVyZW5jZSB0byBIVFRQIHNlcnZlclxyXG4gICAgICAgIGFjdGl2ZVNlcnZlcnMuc2V0KHNlcnZlck9wdGlvbnMucG9ydCwgaHR0cFNlcnZlcik7XHJcblxyXG4gICAgICAgIGxvZyhcclxuICAgICAgICAgIDMsXHJcbiAgICAgICAgICBgW3NlcnZlcl0gU3RhcnRlZCBIVFRQIHNlcnZlciBvbiAke3NlcnZlck9wdGlvbnMuaG9zdH06JHtzZXJ2ZXJPcHRpb25zLnBvcnR9LmBcclxuICAgICAgICApO1xyXG4gICAgICB9KTtcclxuICAgIH1cclxuXHJcbiAgICAvLyBMaXN0ZW4gSFRUUFMgc2VydmVyXHJcbiAgICBpZiAoc2VydmVyT3B0aW9ucy5zc2wuZW5hYmxlKSB7XHJcbiAgICAgIC8vIFNldCB1cCBhbiBTU0wgc2VydmVyIGFsc29cclxuICAgICAgbGV0IGtleSwgY2VydDtcclxuXHJcbiAgICAgIHRyeSB7XHJcbiAgICAgICAgLy8gR2V0IHRoZSBTU0wga2V5XHJcbiAgICAgICAga2V5ID0gYXdhaXQgcmVhZEZpbGUoXHJcbiAgICAgICAgICBqb2luKGdldEFic29sdXRlUGF0aChzZXJ2ZXJPcHRpb25zLnNzbC5jZXJ0UGF0aCksICdzZXJ2ZXIua2V5JyksXHJcbiAgICAgICAgICAndXRmOCdcclxuICAgICAgICApO1xyXG5cclxuICAgICAgICAvLyBHZXQgdGhlIFNTTCBjZXJ0aWZpY2F0ZVxyXG4gICAgICAgIGNlcnQgPSBhd2FpdCByZWFkRmlsZShcclxuICAgICAgICAgIGpvaW4oZ2V0QWJzb2x1dGVQYXRoKHNlcnZlck9wdGlvbnMuc3NsLmNlcnRQYXRoKSwgJ3NlcnZlci5jcnQnKSxcclxuICAgICAgICAgICd1dGY4J1xyXG4gICAgICAgICk7XHJcbiAgICAgIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICAgICAgbG9nKFxyXG4gICAgICAgICAgMixcclxuICAgICAgICAgIGBbc2VydmVyXSBVbmFibGUgdG8gbG9hZCBrZXkvY2VydGlmaWNhdGUgZnJvbSB0aGUgJyR7c2VydmVyT3B0aW9ucy5zc2wuY2VydFBhdGh9JyBwYXRoLiBDb3VsZCBub3QgcnVuIHNlY3VyZWQgbGF5ZXIgc2VydmVyLmBcclxuICAgICAgICApO1xyXG4gICAgICB9XHJcblxyXG4gICAgICBpZiAoa2V5ICYmIGNlcnQpIHtcclxuICAgICAgICAvLyBNYWluIHNlcnZlciBpbnN0YW5jZSAoSFRUUFMpXHJcbiAgICAgICAgY29uc3QgaHR0cHNTZXJ2ZXIgPSBodHRwcy5jcmVhdGVTZXJ2ZXIoeyBrZXksIGNlcnQgfSwgYXBwKTtcclxuXHJcbiAgICAgICAgLy8gQXR0YWNoIGVycm9yIGhhbmRsZXJzIGFuZCBsaXN0ZW4gdG8gdGhlIHNlcnZlclxyXG4gICAgICAgIF9hdHRhY2hTZXJ2ZXJFcnJvckhhbmRsZXJzKGh0dHBzU2VydmVyKTtcclxuXHJcbiAgICAgICAgLy8gTGlzdGVuXHJcbiAgICAgICAgaHR0cHNTZXJ2ZXIubGlzdGVuKHNlcnZlck9wdGlvbnMuc3NsLnBvcnQsIHNlcnZlck9wdGlvbnMuaG9zdCwgKCkgPT4ge1xyXG4gICAgICAgICAgLy8gU2F2ZSB0aGUgcmVmZXJlbmNlIHRvIEhUVFBTIHNlcnZlclxyXG4gICAgICAgICAgYWN0aXZlU2VydmVycy5zZXQoc2VydmVyT3B0aW9ucy5zc2wucG9ydCwgaHR0cHNTZXJ2ZXIpO1xyXG5cclxuICAgICAgICAgIGxvZyhcclxuICAgICAgICAgICAgMyxcclxuICAgICAgICAgICAgYFtzZXJ2ZXJdIFN0YXJ0ZWQgSFRUUFMgc2VydmVyIG9uICR7c2VydmVyT3B0aW9ucy5ob3N0fToke3NlcnZlck9wdGlvbnMuc3NsLnBvcnR9LmBcclxuICAgICAgICAgICk7XHJcbiAgICAgICAgfSk7XHJcbiAgICAgIH1cclxuICAgIH1cclxuXHJcbiAgICAvLyBTZXQgdXAgdGhlIHJhdGUgbGltaXRlclxyXG4gICAgcmF0ZUxpbWl0aW5nTWlkZGxld2FyZShhcHAsIHNlcnZlck9wdGlvbnMucmF0ZUxpbWl0aW5nKTtcclxuXHJcbiAgICAvLyBTZXQgdXAgdGhlIHZhbGlkYXRpb24gaGFuZGxlclxyXG4gICAgdmFsaWRhdGlvbk1pZGRsZXdhcmUoYXBwKTtcclxuXHJcbiAgICAvLyBTZXQgdXAgcm91dGVzXHJcbiAgICBleHBvcnRSb3V0ZXMoYXBwKTtcclxuICAgIGhlYWx0aFJvdXRlcyhhcHApO1xyXG4gICAgdWlSb3V0ZXMoYXBwKTtcclxuICAgIHZlcnNpb25DaGFuZ2VSb3V0ZXMoYXBwKTtcclxuXHJcbiAgICAvLyBTZXQgdXAgdGhlIGNlbnRyYWxpemVkIGVycm9yIGhhbmRsZXJcclxuICAgIGVycm9yTWlkZGxld2FyZShhcHApO1xyXG4gIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoXHJcbiAgICAgICdbc2VydmVyXSBDb3VsZCBub3QgY29uZmlndXJlIGFuZCBzdGFydCB0aGUgc2VydmVyLicsXHJcbiAgICAgIDUwMFxyXG4gICAgKS5zZXRFcnJvcihlcnJvcik7XHJcbiAgfVxyXG59XHJcblxyXG4vKipcclxuICogQ2xvc2VzIGFsbCBzZXJ2ZXJzIGFzc29jaWF0ZWQgd2l0aCBFeHByZXNzIGFwcCBpbnN0YW5jZS5cclxuICpcclxuICogQGZ1bmN0aW9uIGNsb3NlU2VydmVyc1xyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIGNsb3NlU2VydmVycygpIHtcclxuICAvLyBDaGVjayBpZiB0aGVyZSBhcmUgc2VydmVycyB3b3JraW5nXHJcbiAgaWYgKGFjdGl2ZVNlcnZlcnMuc2l6ZSA+IDApIHtcclxuICAgIGxvZyg0LCBgW3NlcnZlcl0gQ2xvc2luZyBhbGwgc2VydmVycy5gKTtcclxuXHJcbiAgICAvLyBDbG9zZSBlYWNoIG9uZSBvZiBzZXJ2ZXJzXHJcbiAgICBmb3IgKGNvbnN0IFtwb3J0LCBzZXJ2ZXJdIG9mIGFjdGl2ZVNlcnZlcnMpIHtcclxuICAgICAgc2VydmVyLmNsb3NlKCgpID0+IHtcclxuICAgICAgICBhY3RpdmVTZXJ2ZXJzLmRlbGV0ZShwb3J0KTtcclxuICAgICAgICBsb2coNCwgYFtzZXJ2ZXJdIENsb3NlZCBzZXJ2ZXIgb24gcG9ydDogJHtwb3J0fS5gKTtcclxuICAgICAgfSk7XHJcbiAgICB9XHJcbiAgfVxyXG59XHJcblxyXG4vKipcclxuICogR2V0IGFsbCBzZXJ2ZXJzIGFzc29jaWF0ZWQgd2l0aCBFeHByZXNzIGFwcCBpbnN0YW5jZS5cclxuICpcclxuICogQGZ1bmN0aW9uIGdldFNlcnZlcnNcclxuICpcclxuICogQHJldHVybnMge0FycmF5LjxPYmplY3Q+fSBTZXJ2ZXJzIGFzc29jaWF0ZWQgd2l0aCBFeHByZXNzIGFwcCBpbnN0YW5jZS5cclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiBnZXRTZXJ2ZXJzKCkge1xyXG4gIHJldHVybiBhY3RpdmVTZXJ2ZXJzO1xyXG59XHJcblxyXG4vKipcclxuICogR2V0IHRoZSBFeHByZXNzIGluc3RhbmNlLlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gZ2V0RXhwcmVzc1xyXG4gKlxyXG4gKiBAcmV0dXJucyB7RXhwcmVzc30gVGhlIEV4cHJlc3MgaW5zdGFuY2UuXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gZ2V0RXhwcmVzcygpIHtcclxuICByZXR1cm4gZXhwcmVzcztcclxufVxyXG5cclxuLyoqXHJcbiAqIEdldCB0aGUgRXhwcmVzcyBhcHAgaW5zdGFuY2UuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBnZXRBcHBcclxuICpcclxuICogQHJldHVybnMge0V4cHJlc3N9IFRoZSBFeHByZXNzIGFwcCBpbnN0YW5jZS5cclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiBnZXRBcHAoKSB7XHJcbiAgcmV0dXJuIGFwcDtcclxufVxyXG5cclxuLyoqXHJcbiAqIEVuYWJsZSByYXRlIGxpbWl0aW5nIGZvciB0aGUgc2VydmVyLlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gZW5hYmxlUmF0ZUxpbWl0aW5nXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSByYXRlTGltaXRpbmdPcHRpb25zIC0gVGhlIGNvbmZpZ3VyYXRpb24gb2JqZWN0IGNvbnRhaW5pbmdcclxuICogYHJhdGVMaW1pdGluZ2Agb3B0aW9ucy4gVGhpcyBvYmplY3QgbWF5IGluY2x1ZGUgYSBwYXJ0aWFsIG9yIGNvbXBsZXRlIHNldFxyXG4gKiBvZiB0aGUgYHJhdGVMaW1pdGluZ2Agb3B0aW9ucy4gSWYgdGhlIG9wdGlvbnMgYXJlIHBhcnRpYWwsIG1pc3NpbmcgdmFsdWVzXHJcbiAqIHdpbGwgZGVmYXVsdCB0byB0aGUgY3VycmVudCBnbG9iYWwgY29uZmlndXJhdGlvbi5cclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiBlbmFibGVSYXRlTGltaXRpbmcocmF0ZUxpbWl0aW5nT3B0aW9ucykge1xyXG4gIC8vIFVwZGF0ZSB0aGUgaW5zdGFuY2Ugb3B0aW9ucyBvYmplY3RcclxuICBjb25zdCBvcHRpb25zID0gdXBkYXRlT3B0aW9ucyhcclxuICAgIHZhbGlkYXRlT3B0aW9ucyh7XHJcbiAgICAgIHNlcnZlcjoge1xyXG4gICAgICAgIHJhdGVMaW1pdGluZzogcmF0ZUxpbWl0aW5nT3B0aW9uc1xyXG4gICAgICB9XHJcbiAgICB9KVxyXG4gICk7XHJcblxyXG4gIC8vIFNldCB0aGUgcmF0ZSBsaW1pdGluZyBvcHRpb25zXHJcbiAgcmF0ZUxpbWl0aW5nTWlkZGxld2FyZShhcHAsIG9wdGlvbnMuc2VydmVyLnJhdGVMaW1pdGluZ09wdGlvbnMpO1xyXG59XHJcblxyXG4vKipcclxuICogQXBwbHkgbWlkZGxld2FyZShzKSB0byBhIHNwZWNpZmljIHBhdGguXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiB1c2VcclxuICpcclxuICogQHBhcmFtIHtzdHJpbmd9IHBhdGggLSBUaGUgcGF0aCB0byB3aGljaCB0aGUgbWlkZGxld2FyZShzKSBzaG91bGQgYmUgYXBwbGllZC5cclxuICogQHBhcmFtIHsuLi5GdW5jdGlvbn0gbWlkZGxld2FyZXMgLSBUaGUgbWlkZGxld2FyZSBmdW5jdGlvbihzKSB0byBiZSBhcHBsaWVkLlxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIHVzZShwYXRoLCAuLi5taWRkbGV3YXJlcykge1xyXG4gIGFwcC51c2UocGF0aCwgLi4ubWlkZGxld2FyZXMpO1xyXG59XHJcblxyXG4vKipcclxuICogU2V0IHVwIGEgcm91dGUgd2l0aCBHRVQgbWV0aG9kIGFuZCBhcHBseSBtaWRkbGV3YXJlKHMpLlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gZ2V0XHJcbiAqXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSBwYXRoIC0gVGhlIHBhdGggdG8gd2hpY2ggdGhlIG1pZGRsZXdhcmUocykgc2hvdWxkIGJlIGFwcGxpZWQuXHJcbiAqIEBwYXJhbSB7Li4uRnVuY3Rpb259IG1pZGRsZXdhcmVzIC0gVGhlIG1pZGRsZXdhcmUgZnVuY3Rpb24ocykgdG8gYmUgYXBwbGllZC5cclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiBnZXQocGF0aCwgLi4ubWlkZGxld2FyZXMpIHtcclxuICBhcHAuZ2V0KHBhdGgsIC4uLm1pZGRsZXdhcmVzKTtcclxufVxyXG5cclxuLyoqXHJcbiAqIFNldCB1cCBhIHJvdXRlIHdpdGggUE9TVCBtZXRob2QgYW5kIGFwcGx5IG1pZGRsZXdhcmUocykuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBwb3N0XHJcbiAqXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSBwYXRoIC0gVGhlIHBhdGggdG8gd2hpY2ggdGhlIG1pZGRsZXdhcmUocykgc2hvdWxkIGJlIGFwcGxpZWQuXHJcbiAqIEBwYXJhbSB7Li4uRnVuY3Rpb259IG1pZGRsZXdhcmVzIC0gVGhlIG1pZGRsZXdhcmUgZnVuY3Rpb24ocykgdG8gYmUgYXBwbGllZC5cclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiBwb3N0KHBhdGgsIC4uLm1pZGRsZXdhcmVzKSB7XHJcbiAgYXBwLnBvc3QocGF0aCwgLi4ubWlkZGxld2FyZXMpO1xyXG59XHJcblxyXG4vKipcclxuICogQXR0YWNoIGVycm9yIGhhbmRsZXJzIHRvIHRoZSBzZXJ2ZXIuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBfYXR0YWNoU2VydmVyRXJyb3JIYW5kbGVyc1xyXG4gKlxyXG4gKiBAcGFyYW0geyhodHRwLlNlcnZlcnxodHRwcy5TZXJ2ZXIpfSBzZXJ2ZXIgLSBUaGUgSFRUUC9IVFRQUyBzZXJ2ZXIgaW5zdGFuY2UuXHJcbiAqL1xyXG5mdW5jdGlvbiBfYXR0YWNoU2VydmVyRXJyb3JIYW5kbGVycyhzZXJ2ZXIpIHtcclxuICBzZXJ2ZXIub24oJ2NsaWVudEVycm9yJywgKGVycm9yLCBzb2NrZXQpID0+IHtcclxuICAgIGxvZ1dpdGhTdGFjayhcclxuICAgICAgMSxcclxuICAgICAgZXJyb3IsXHJcbiAgICAgIGBbc2VydmVyXSBDbGllbnQgZXJyb3I6ICR7ZXJyb3IubWVzc2FnZX0sIGRlc3Ryb3lpbmcgc29ja2V0LmBcclxuICAgICk7XHJcbiAgICBzb2NrZXQuZGVzdHJveSgpO1xyXG4gIH0pO1xyXG5cclxuICBzZXJ2ZXIub24oJ2Vycm9yJywgKGVycm9yKSA9PiB7XHJcbiAgICBsb2dXaXRoU3RhY2soMSwgZXJyb3IsIGBbc2VydmVyXSBTZXJ2ZXIgZXJyb3I6ICR7ZXJyb3IubWVzc2FnZX1gKTtcclxuICB9KTtcclxuXHJcbiAgc2VydmVyLm9uKCdjb25uZWN0aW9uJywgKHNvY2tldCkgPT4ge1xyXG4gICAgc29ja2V0Lm9uKCdlcnJvcicsIChlcnJvcikgPT4ge1xyXG4gICAgICBsb2dXaXRoU3RhY2soMSwgZXJyb3IsIGBbc2VydmVyXSBTb2NrZXQgZXJyb3I6ICR7ZXJyb3IubWVzc2FnZX1gKTtcclxuICAgIH0pO1xyXG4gIH0pO1xyXG59XHJcblxyXG5leHBvcnQgZGVmYXVsdCB7XHJcbiAgc3RhcnRTZXJ2ZXIsXHJcbiAgY2xvc2VTZXJ2ZXJzLFxyXG4gIGdldFNlcnZlcnMsXHJcbiAgZ2V0RXhwcmVzcyxcclxuICBnZXRBcHAsXHJcbiAgZW5hYmxlUmF0ZUxpbWl0aW5nLFxyXG4gIHVzZSxcclxuICBnZXQsXHJcbiAgcG9zdFxyXG59O1xyXG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxyXG5cclxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXHJcblxyXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNSwgSGlnaHNvZnRcclxuXHJcbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cclxuXHJcbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxyXG5cclxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxyXG5cclxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cclxuXHJcbi8qKlxyXG4gKiBAb3ZlcnZpZXcgSGFuZGxlcyBncmFjZWZ1bCBzaHV0ZG93biBvZiB0aGUgSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyLCBlbnN1cmluZ1xyXG4gKiBwcm9wZXIgY2xlYW51cCBvZiByZXNvdXJjZXMgc3VjaCBhcyBicm93c2VyLCBwYWdlcywgc2VydmVycywgYW5kIHRpbWVycy5cclxuICovXHJcblxyXG5pbXBvcnQgeyBraWxsUG9vbCB9IGZyb20gJy4vcG9vbC5qcyc7XHJcbmltcG9ydCB7IGNsZWFyQWxsVGltZXJzIH0gZnJvbSAnLi90aW1lci5qcyc7XHJcblxyXG5pbXBvcnQgeyBjbG9zZVNlcnZlcnMgfSBmcm9tICcuL3NlcnZlci9zZXJ2ZXIuanMnO1xyXG5cclxuLyoqXHJcbiAqIFBlcmZvcm1zIGNsZWFudXAgb3BlcmF0aW9ucyB0byBlbnN1cmUgYSBncmFjZWZ1bCBzaHV0ZG93biBvZiB0aGUgcHJvY2Vzcy5cclxuICogVGhpcyBpbmNsdWRlcyBjbGVhcmluZyBhbGwgcmVnaXN0ZXJlZCB0aW1lb3V0cy9pbnRlcnZhbHMsIGNsb3NpbmcgYWN0aXZlXHJcbiAqIHNlcnZlcnMsIHRlcm1pbmF0aW5nIHJlc291cmNlcyAocGFnZXMpIG9mIHRoZSBwb29sLCBwb29sIGl0c2VsZiwgYW5kIGNsb3NpbmdcclxuICogdGhlIGJyb3dzZXIuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBzaHV0ZG93bkNsZWFuVXBcclxuICpcclxuICogQHBhcmFtIHtudW1iZXJ9IFtleGl0Q29kZT0wXSAtIFRoZSBleGl0IGNvZGUgdG8gdXNlIHdpdGggYHByb2Nlc3MuZXhpdCgpYC5cclxuICogVGhlIGRlZmF1bHQgdmFsdWUgaXMgYDBgLlxyXG4gKi9cclxuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIHNodXRkb3duQ2xlYW5VcChleGl0Q29kZSA9IDApIHtcclxuICAvLyBBd2FpdCBmcmVlaW5nIGFsbCByZXNvdXJjZXNcclxuICBhd2FpdCBQcm9taXNlLmFsbFNldHRsZWQoW1xyXG4gICAgLy8gQ2xlYXIgYWxsIG9uZ29pbmcgaW50ZXJ2YWxzXHJcbiAgICBjbGVhckFsbFRpbWVycygpLFxyXG5cclxuICAgIC8vIEdldCBhdmFpbGFibGUgc2VydmVyIGluc3RhbmNlcyAoSFRUUC9IVFRQUykgYW5kIGNsb3NlIHRoZW1cclxuICAgIGNsb3NlU2VydmVycygpLFxyXG5cclxuICAgIC8vIENsb3NlIGFuIGFjdGl2ZSBwb29sIGFsb25nIHdpdGggaXRzIHdvcmtlcnMgYW5kIHRoZSBicm93c2VyIGluc3RhbmNlXHJcbiAgICBraWxsUG9vbCgpXHJcbiAgXSk7XHJcblxyXG4gIC8vIEV4aXQgcHJvY2VzcyB3aXRoIGEgY29ycmVjdCBjb2RlXHJcbiAgcHJvY2Vzcy5leGl0KGV4aXRDb2RlKTtcclxufVxyXG5cclxuZXhwb3J0IGRlZmF1bHQge1xyXG4gIHNodXRkb3duQ2xlYW5VcFxyXG59O1xyXG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxyXG5cclxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXHJcblxyXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNSwgSGlnaHNvZnRcclxuXHJcbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cclxuXHJcbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxyXG5cclxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxyXG5cclxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cclxuXHJcbi8qKlxyXG4gKiBAb3ZlcnZpZXcgQ29yZSBtb2R1bGUgZm9yIGluaXRpYWxpemluZyBhbmQgbWFuYWdpbmcgdGhlIEhpZ2hjaGFydHMgRXhwb3J0XHJcbiAqIFNlcnZlci4gUHJvdmlkZXMgZnVuY3Rpb25hbGl0aWVzIGZvciBjb25maWd1cmluZyBleHBvcnRzLCBzZXR0aW5nIHVwIHNlcnZlclxyXG4gKiBvcGVyYXRpb25zLCBsb2dnaW5nLCBzY3JpcHRzIGNhY2hpbmcsIHJlc291cmNlIHBvb2xpbmcsIGFuZCBncmFjZWZ1bCBwcm9jZXNzXHJcbiAqIGNsZWFudXAuXHJcbiAqL1xyXG5cclxuaW1wb3J0ICdjb2xvcnMnO1xyXG5cclxuaW1wb3J0IHsgY2hlY2tBbmRVcGRhdGVDYWNoZSB9IGZyb20gJy4vY2FjaGUuanMnO1xyXG5pbXBvcnQge1xyXG4gIHNpbmdsZUV4cG9ydCxcclxuICBiYXRjaEV4cG9ydCxcclxuICBzdGFydEV4cG9ydCxcclxuICBzZXRBbGxvd0NvZGVFeGVjdXRpb25cclxufSBmcm9tICcuL2NoYXJ0LmpzJztcclxuaW1wb3J0IHtcclxuICBnZXRPcHRpb25zLFxyXG4gIHVwZGF0ZU9wdGlvbnMsXHJcbiAgc2V0R2xvYmFsT3B0aW9ucyxcclxuICBtYXBUb05ld09wdGlvbnMsXHJcbiAgdmFsaWRhdGVPcHRpb24sXHJcbiAgdmFsaWRhdGVPcHRpb25zXHJcbn0gZnJvbSAnLi9jb25maWcuanMnO1xyXG5pbXBvcnQge1xyXG4gIGxvZyxcclxuICBsb2dXaXRoU3RhY2ssXHJcbiAgbG9nWm9kSXNzdWVzLFxyXG4gIGluaXRMb2dnaW5nLFxyXG4gIGVuYWJsZUNvbnNvbGVMb2dnaW5nLFxyXG4gIGVuYWJsZUZpbGVMb2dnaW5nLFxyXG4gIHNldExvZ0xldmVsXHJcbn0gZnJvbSAnLi9sb2dnZXIuanMnO1xyXG5pbXBvcnQgeyBpbml0UG9vbCwga2lsbFBvb2wgfSBmcm9tICcuL3Bvb2wuanMnO1xyXG5pbXBvcnQgeyBzaHV0ZG93bkNsZWFuVXAgfSBmcm9tICcuL3Jlc291cmNlUmVsZWFzZS5qcyc7XHJcblxyXG5pbXBvcnQgc2VydmVyIGZyb20gJy4vc2VydmVyL3NlcnZlci5qcyc7XHJcblxyXG4vKipcclxuICogSW5pdGlhbGl6ZXMgdGhlIGV4cG9ydCBwcm9jZXNzLiBUYXNrcyBzdWNoIGFzIGNvbmZpZ3VyaW5nIGxvZ2dpbmcsIGNoZWNraW5nXHJcbiAqIHRoZSBjYWNoZSBhbmQgc291cmNlcywgYW5kIGluaXRpYWxpemluZyB0aGUgcmVzb3VyY2UgcG9vbCBvY2N1ciBkdXJpbmcgdGhpc1xyXG4gKiBzdGFnZS5cclxuICpcclxuICogVGhpcyBmdW5jdGlvbiBtdXN0IGJlIGNhbGxlZCBiZWZvcmUgYXR0ZW1wdGluZyB0byBleHBvcnQgY2hhcnRzIG9yIHNldFxyXG4gKiB1cCBhIHNlcnZlci5cclxuICpcclxuICogQGFzeW5jXHJcbiAqIEBmdW5jdGlvbiBpbml0RXhwb3J0XHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBbaW5pdE9wdGlvbnM9e31dIC0gVGhlIGBpbml0T3B0aW9uc2Agb2JqZWN0LCB3aGljaCBtYXlcclxuICogYmUgYSBwYXJ0aWFsIG9yIGNvbXBsZXRlIHNldCBvZiBvcHRpb25zLiBJZiB0aGUgb3B0aW9ucyBhcmUgcGFydGlhbCwgbWlzc2luZ1xyXG4gKiB2YWx1ZXMgd2lsbCBkZWZhdWx0IHRvIHRoZSBjdXJyZW50IGdsb2JhbCBjb25maWd1cmF0aW9uLiBUaGUgZGVmYXVsdCB2YWx1ZVxyXG4gKiBpcyBhbiBlbXB0eSBvYmplY3QuXHJcbiAqL1xyXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gaW5pdEV4cG9ydChpbml0T3B0aW9ucyA9IHt9KSB7XHJcbiAgLy8gSW5pdCwgdmFsaWRhdGUgYW5kIHVwZGF0ZSB0aGUgaW5zdGFuY2Ugb3B0aW9ucyBvYmplY3RcclxuICBjb25zdCBvcHRpb25zID0gdXBkYXRlT3B0aW9ucyh2YWxpZGF0ZU9wdGlvbnMoaW5pdE9wdGlvbnMpLCB0cnVlKTtcclxuXHJcbiAgLy8gU2V0IHRoZSBgYWxsb3dDb2RlRXhlY3V0aW9uYCBwZXIgZXhwb3J0IG1vZHVsZSBzY29wZVxyXG4gIHNldEFsbG93Q29kZUV4ZWN1dGlvbihvcHRpb25zLmN1c3RvbUxvZ2ljLmFsbG93Q29kZUV4ZWN1dGlvbik7XHJcblxyXG4gIC8vIEluaXQgdGhlIGxvZ2dpbmdcclxuICBpbml0TG9nZ2luZyhvcHRpb25zLmxvZ2dpbmcpO1xyXG5cclxuICAvLyBBdHRhY2ggcHJvY2VzcycgZXhpdCBsaXN0ZW5lcnNcclxuICBpZiAob3B0aW9ucy5vdGhlci5saXN0ZW5Ub1Byb2Nlc3NFeGl0cykge1xyXG4gICAgX2F0dGFjaFByb2Nlc3NFeGl0TGlzdGVuZXJzKCk7XHJcbiAgfVxyXG5cclxuICAvLyBDaGVjayBpZiBjYWNoZSBuZWVkcyB0byBiZSB1cGRhdGVkXHJcbiAgYXdhaXQgY2hlY2tBbmRVcGRhdGVDYWNoZShvcHRpb25zLmhpZ2hjaGFydHMsIG9wdGlvbnMuc2VydmVyLnByb3h5KTtcclxuXHJcbiAgLy8gSW5pdCB0aGUgcG9vbFxyXG4gIGF3YWl0IGluaXRQb29sKG9wdGlvbnMucG9vbCwgb3B0aW9ucy5wdXBwZXRlZXIuYXJncyk7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBBdHRhY2hlcyBleGl0IGxpc3RlbmVycyB0byB0aGUgcHJvY2VzcywgZW5zdXJpbmcgcHJvcGVyIGNsZWFudXAgb2YgcmVzb3VyY2VzXHJcbiAqIGFuZCB0ZXJtaW5hdGlvbiBvbiBleGl0IHNpZ25hbHMuIEhhbmRsZXMgJ2V4aXQnLCAnU0lHSU5UJywgJ1NJR1RFUk0nXHJcbiAqIGFuZCAndW5jYXVnaHRFeGNlcHRpb24nIGV2ZW50cy5cclxuICpcclxuICogQGZ1bmN0aW9uIF9hdHRhY2hQcm9jZXNzRXhpdExpc3RlbmVyc1xyXG4gKi9cclxuZnVuY3Rpb24gX2F0dGFjaFByb2Nlc3NFeGl0TGlzdGVuZXJzKCkge1xyXG4gIGxvZygzLCAnW3Byb2Nlc3NdIEF0dGFjaGluZyBleGl0IGxpc3RlbmVycyB0byB0aGUgcHJvY2Vzcy4nKTtcclxuXHJcbiAgLy8gSGFuZGxlciBmb3IgdGhlICdleGl0J1xyXG4gIHByb2Nlc3Mub24oJ2V4aXQnLCAoY29kZSkgPT4ge1xyXG4gICAgbG9nKDQsIGBbcHJvY2Vzc10gUHJvY2VzcyBleGl0ZWQgd2l0aCBjb2RlICR7Y29kZX0uYCk7XHJcbiAgfSk7XHJcblxyXG4gIC8vIEhhbmRsZXIgZm9yIHRoZSAnU0lHSU5UJ1xyXG4gIHByb2Nlc3Mub24oJ1NJR0lOVCcsIGFzeW5jIChuYW1lLCBjb2RlKSA9PiB7XHJcbiAgICBsb2coNCwgYFtwcm9jZXNzXSBUaGUgJHtuYW1lfSBldmVudCB3aXRoIGNvZGU6ICR7Y29kZX0uYCk7XHJcbiAgICBhd2FpdCBzaHV0ZG93bkNsZWFuVXAoKTtcclxuICB9KTtcclxuXHJcbiAgLy8gSGFuZGxlciBmb3IgdGhlICdTSUdURVJNJ1xyXG4gIHByb2Nlc3Mub24oJ1NJR1RFUk0nLCBhc3luYyAobmFtZSwgY29kZSkgPT4ge1xyXG4gICAgbG9nKDQsIGBbcHJvY2Vzc10gVGhlICR7bmFtZX0gZXZlbnQgd2l0aCBjb2RlOiAke2NvZGV9LmApO1xyXG4gICAgYXdhaXQgc2h1dGRvd25DbGVhblVwKCk7XHJcbiAgfSk7XHJcblxyXG4gIC8vIEhhbmRsZXIgZm9yIHRoZSAnU0lHSFVQJ1xyXG4gIHByb2Nlc3Mub24oJ1NJR0hVUCcsIGFzeW5jIChuYW1lLCBjb2RlKSA9PiB7XHJcbiAgICBsb2coNCwgYFtwcm9jZXNzXSBUaGUgJHtuYW1lfSBldmVudCB3aXRoIGNvZGU6ICR7Y29kZX0uYCk7XHJcbiAgICBhd2FpdCBzaHV0ZG93bkNsZWFuVXAoKTtcclxuICB9KTtcclxuXHJcbiAgLy8gSGFuZGxlciBmb3IgdGhlICd1bmNhdWdodEV4Y2VwdGlvbidcclxuICBwcm9jZXNzLm9uKCd1bmNhdWdodEV4Y2VwdGlvbicsIGFzeW5jIChlcnJvciwgbmFtZSkgPT4ge1xyXG4gICAgbG9nV2l0aFN0YWNrKDEsIGVycm9yLCBgW3Byb2Nlc3NdIFRoZSAke25hbWV9IGVycm9yLmApO1xyXG4gICAgYXdhaXQgc2h1dGRvd25DbGVhblVwKDEpO1xyXG4gIH0pO1xyXG59XHJcblxyXG5leHBvcnQgZGVmYXVsdCB7XHJcbiAgLy8gU2VydmVyXHJcbiAgLi4uc2VydmVyLFxyXG5cclxuICAvLyBPcHRpb25zXHJcbiAgZ2V0T3B0aW9ucyxcclxuICBzZXRHbG9iYWxPcHRpb25zLFxyXG4gIG1hcFRvTmV3T3B0aW9ucyxcclxuXHJcbiAgLy8gVmFsaWRhdGlvblxyXG4gIHZhbGlkYXRlT3B0aW9uLFxyXG4gIHZhbGlkYXRlT3B0aW9ucyxcclxuXHJcbiAgLy8gRXhwb3J0aW5nXHJcbiAgaW5pdEV4cG9ydCxcclxuICBzaW5nbGVFeHBvcnQsXHJcbiAgYmF0Y2hFeHBvcnQsXHJcbiAgc3RhcnRFeHBvcnQsXHJcblxyXG4gIC8vIFJlbGVhc2VcclxuICBraWxsUG9vbCxcclxuICBzaHV0ZG93bkNsZWFuVXAsXHJcblxyXG4gIC8vIExvZ3NcclxuICBsb2csXHJcbiAgbG9nV2l0aFN0YWNrLFxyXG4gIGxvZ1pvZElzc3VlcyxcclxuICBzZXRMb2dMZXZlbDogZnVuY3Rpb24gKGxldmVsKSB7XHJcbiAgICAvLyBVcGRhdGUgdGhlIGluc3RhbmNlIG9wdGlvbnMgb2JqZWN0XHJcbiAgICBjb25zdCBvcHRpb25zID0gdXBkYXRlT3B0aW9ucyhcclxuICAgICAgdmFsaWRhdGVPcHRpb25zKHtcclxuICAgICAgICBsb2dnaW5nOiB7XHJcbiAgICAgICAgICBsZXZlbFxyXG4gICAgICAgIH1cclxuICAgICAgfSlcclxuICAgICk7XHJcblxyXG4gICAgLy8gQ2FsbCB0aGUgZnVuY3Rpb25cclxuICAgIHNldExvZ0xldmVsKG9wdGlvbnMubG9nZ2luZy5sZXZlbCk7XHJcbiAgfSxcclxuICBlbmFibGVDb25zb2xlTG9nZ2luZzogZnVuY3Rpb24gKHRvQ29uc29sZSkge1xyXG4gICAgLy8gVXBkYXRlIHRoZSBpbnN0YW5jZSBvcHRpb25zIG9iamVjdFxyXG4gICAgY29uc3Qgb3B0aW9ucyA9IHVwZGF0ZU9wdGlvbnMoXHJcbiAgICAgIHZhbGlkYXRlT3B0aW9ucyh7XHJcbiAgICAgICAgbG9nZ2luZzoge1xyXG4gICAgICAgICAgdG9Db25zb2xlXHJcbiAgICAgICAgfVxyXG4gICAgICB9KVxyXG4gICAgKTtcclxuXHJcbiAgICAvLyBDYWxsIHRoZSBmdW5jdGlvblxyXG4gICAgZW5hYmxlQ29uc29sZUxvZ2dpbmcob3B0aW9ucy5sb2dnaW5nLnRvQ29uc29sZSk7XHJcbiAgfSxcclxuICBlbmFibGVGaWxlTG9nZ2luZzogZnVuY3Rpb24gKGRlc3QsIGZpbGUsIHRvRmlsZSkge1xyXG4gICAgLy8gVXBkYXRlIHRoZSBpbnN0YW5jZSBvcHRpb25zIG9iamVjdFxyXG4gICAgY29uc3Qgb3B0aW9ucyA9IHVwZGF0ZU9wdGlvbnMoXHJcbiAgICAgIHZhbGlkYXRlT3B0aW9ucyh7XHJcbiAgICAgICAgbG9nZ2luZzoge1xyXG4gICAgICAgICAgZGVzdCxcclxuICAgICAgICAgIGZpbGUsXHJcbiAgICAgICAgICB0b0ZpbGVcclxuICAgICAgICB9XHJcbiAgICAgIH0pXHJcbiAgICApO1xyXG5cclxuICAgIC8vIENhbGwgdGhlIGZ1bmN0aW9uXHJcbiAgICBlbmFibGVGaWxlTG9nZ2luZyhcclxuICAgICAgb3B0aW9ucy5sb2dnaW5nLmRlc3QsXHJcbiAgICAgIG9wdGlvbnMubG9nZ2luZy5maWxlLFxyXG4gICAgICBvcHRpb25zLmxvZ2dpbmcudG9GaWxlXHJcbiAgICApO1xyXG4gIH1cclxufTtcclxuIl0sIm5hbWVzIjpbIl9fZGlybmFtZSIsImZpbGVVUkxUb1BhdGgiLCJVUkwiLCJkb2N1bWVudCIsInJlcXVpcmUiLCJwYXRoVG9GaWxlVVJMIiwiX19maWxlbmFtZSIsImhyZWYiLCJfZG9jdW1lbnRDdXJyZW50U2NyaXB0IiwidGFnTmFtZSIsInRvVXBwZXJDYXNlIiwic3JjIiwiYmFzZVVSSSIsImRlZXBDb3B5Iiwib2JqQXJyIiwib2JqQXJyQ29weSIsIkFycmF5IiwiaXNBcnJheSIsImtleSIsIk9iamVjdCIsInByb3RvdHlwZSIsImhhc093blByb3BlcnR5IiwiY2FsbCIsImZpeENvbnN0ciIsImNvbnN0ciIsImZpeGVkQ29uc3RyIiwidG9Mb3dlckNhc2UiLCJyZXBsYWNlIiwiaW5jbHVkZXMiLCJmaXhPdXRmaWxlIiwidHlwZSIsIm91dGZpbGUiLCJnZXRBYnNvbHV0ZVBhdGgiLCJzcGxpdCIsInNoaWZ0IiwiZml4VHlwZSIsIm1pbWVUeXBlcyIsImZvcm1hdHMiLCJ2YWx1ZXMiLCJvdXRUeXBlIiwicG9wIiwiZmluZCIsInQiLCJwYXRoIiwiaXNBYnNvbHV0ZSIsImpvaW4iLCJnZXRCYXNlNjQiLCJpbnB1dCIsIkJ1ZmZlciIsImZyb20iLCJ0b1N0cmluZyIsImdldE5ld0RhdGUiLCJEYXRlIiwidHJpbSIsImdldE5ld0RhdGVUaW1lIiwiZ2V0VGltZSIsImlzT2JqZWN0IiwiaXRlbSIsImlzT2JqZWN0RW1wdHkiLCJrZXlzIiwibGVuZ3RoIiwiaXNQcml2YXRlUmFuZ2VVcmxGb3VuZCIsInNvbWUiLCJwYXR0ZXJuIiwidGVzdCIsIm1lYXN1cmVUaW1lIiwic3RhcnQiLCJwcm9jZXNzIiwiaHJ0aW1lIiwiYmlnaW50IiwiTnVtYmVyIiwicm91bmROdW1iZXIiLCJ2YWx1ZSIsInByZWNpc2lvbiIsIm11bHRpcGxpZXIiLCJNYXRoIiwicG93Iiwicm91bmQiLCJ3cmFwQXJvdW5kIiwiY3VzdG9tQ29kZSIsImFsbG93RmlsZVJlc291cmNlcyIsImlzQ2FsbGJhY2siLCJlbmRzV2l0aCIsInJlYWRGaWxlU3luYyIsInN0YXJ0c1dpdGgiLCJjb2xvcnMiLCJsb2dnaW5nIiwidG9Db25zb2xlIiwidG9GaWxlIiwicGF0aENyZWF0ZWQiLCJwYXRoVG9Mb2ciLCJsZXZlbHNEZXNjIiwidGl0bGUiLCJjb2xvciIsImxvZyIsImFyZ3MiLCJuZXdMZXZlbCIsInRleHRzIiwibGV2ZWwiLCJwcmVmaXgiLCJfbG9nVG9GaWxlIiwiY29uc29sZSIsImFwcGx5IiwidW5kZWZpbmVkIiwiY29uY2F0IiwibG9nV2l0aFN0YWNrIiwiZXJyb3IiLCJjdXN0b21NZXNzYWdlIiwibWFpbk1lc3NhZ2UiLCJtZXNzYWdlIiwic3RhY2tNZXNzYWdlIiwic3RhY2siLCJwdXNoIiwibG9nWm9kSXNzdWVzIiwiaXNzdWVzIiwibWFwIiwiaXNzdWUiLCJpbml0TG9nZ2luZyIsImxvZ2dpbmdPcHRpb25zIiwiZGVzdCIsImZpbGUiLCJzZXRMb2dMZXZlbCIsImVuYWJsZUNvbnNvbGVMb2dnaW5nIiwiZW5hYmxlRmlsZUxvZ2dpbmciLCJpc0ludGVnZXIiLCJleGlzdHNTeW5jIiwibWtkaXJTeW5jIiwiYXBwZW5kRmlsZSIsImRlZmF1bHRDb25maWciLCJwdXBwZXRlZXIiLCJ0eXBlcyIsImVudkxpbmsiLCJjbGlOYW1lIiwiZGVzY3JpcHRpb24iLCJwcm9tcHRPcHRpb25zIiwic2VwYXJhdG9yIiwiaGlnaGNoYXJ0cyIsInZlcnNpb24iLCJjZG5VcmwiLCJmb3JjZUZldGNoIiwiY2FjaGVQYXRoIiwiY29yZVNjcmlwdHMiLCJpbnN0cnVjdGlvbnMiLCJtb2R1bGVTY3JpcHRzIiwiaW5kaWNhdG9yU2NyaXB0cyIsImN1c3RvbVNjcmlwdHMiLCJleHBvcnQiLCJpbmZpbGUiLCJpbnN0ciIsIm9wdGlvbnMiLCJzdmciLCJiYXRjaCIsImhpbnQiLCJjaG9pY2VzIiwiYjY0Iiwibm9Eb3dubG9hZCIsImhlaWdodCIsIndpZHRoIiwic2NhbGUiLCJkZWZhdWx0SGVpZ2h0IiwiZGVmYXVsdFdpZHRoIiwiZGVmYXVsdFNjYWxlIiwibWluIiwibWF4IiwiZ2xvYmFsT3B0aW9ucyIsInRoZW1lT3B0aW9ucyIsInJhc3Rlcml6YXRpb25UaW1lb3V0IiwiY3VzdG9tTG9naWMiLCJhbGxvd0NvZGVFeGVjdXRpb24iLCJjYWxsYmFjayIsInJlc291cmNlcyIsImxvYWRDb25maWciLCJsZWdhY3lOYW1lIiwiY3JlYXRlQ29uZmlnIiwic2VydmVyIiwiZW5hYmxlIiwiaG9zdCIsInBvcnQiLCJ1cGxvYWRMaW1pdCIsImJlbmNobWFya2luZyIsInByb3h5IiwidGltZW91dCIsInJhdGVMaW1pdGluZyIsIm1heFJlcXVlc3RzIiwid2luZG93IiwiZGVsYXkiLCJ0cnVzdFByb3h5Iiwic2tpcEtleSIsInNraXBUb2tlbiIsInNzbCIsImZvcmNlIiwiY2VydFBhdGgiLCJwb29sIiwibWluV29ya2VycyIsIm1heFdvcmtlcnMiLCJ3b3JrTGltaXQiLCJhY3F1aXJlVGltZW91dCIsImNyZWF0ZVRpbWVvdXQiLCJkZXN0cm95VGltZW91dCIsImlkbGVUaW1lb3V0IiwiY3JlYXRlUmV0cnlJbnRlcnZhbCIsInJlYXBlckludGVydmFsIiwidWkiLCJyb3V0ZSIsIm90aGVyIiwibm9kZUVudiIsImxpc3RlblRvUHJvY2Vzc0V4aXRzIiwibm9Mb2dvIiwiaGFyZFJlc2V0UGFnZSIsImJyb3dzZXJTaGVsbE1vZGUiLCJ2YWxpZGF0aW9uIiwiZGVidWciLCJoZWFkbGVzcyIsImRldnRvb2xzIiwibGlzdGVuVG9Db25zb2xlIiwiZHVtcGlvIiwic2xvd01vIiwiZGVidWdnaW5nUG9ydCIsIm5lc3RlZFByb3BzIiwiX2NyZWF0ZU5lc3RlZFByb3BzIiwiYWJzb2x1dGVQcm9wcyIsIl9jcmVhdGVBYnNvbHV0ZVByb3BzIiwiY29uZmlnIiwicHJvcENoYWluIiwiZm9yRWFjaCIsImVudHJ5Iiwic3Vic3RyaW5nIiwiZG90ZW52IiwieiIsInNldEVycm9yTWFwIiwiX2N1c3RvbUVycm9yTWFwIiwidiIsImJvb2xlYW4iLCJzdHJpY3RDaGVjayIsInVuaW9uIiwiZW51bSIsInRyYW5zZm9ybSIsIm51bGxhYmxlIiwic3RyaW5nIiwicmVmaW5lIiwicGFyYW1zIiwiZXJyb3JNZXNzYWdlIiwic3RyaW5nQXJyYXkiLCJmaWx0ZXJDYWxsYmFjayIsImFycmF5U2NoZW1hIiwiYXJyYXkiLCJzdHJpbmdTY2hlbWEiLCJzbGljZSIsInRyYW5zZm9ybUNhbGxiYWNrIiwiZmlsdGVyIiwicG9zaXRpdmVOdW0iLCJudW1iZXIiLCJwb3NpdGl2ZSIsImlzTmFOIiwibm9uTmVnYXRpdmVOdW0iLCJub25uZWdhdGl2ZSIsInByZWZpeGVzIiwiY2hhcnRDb25maWciLCJvYmplY3QiLCJwYXNzdGhyb3VnaCIsImFkZGl0aW9uYWxPcHRpb25zIiwidmFsaWRhdG9ycyIsImFkbWluVG9rZW4iLCJpbmRleE9mIiwiZ3RlIiwibHRlIiwidGhpcyIsIm9iamVjdFNjaGVtYSIsImpzIiwiY3NzIiwiZmlsZXMiLCJwYXJ0aWFsIiwic3RyaW5nU2NoZW1hMSIsInN0cmluZ1NjaGVtYTIiLCJlbmFibGVTZXJ2ZXIiLCJzZXJ2ZXJCZW5jaG1hcmtpbmciLCJwcm94eUhvc3QiLCJwcm94eVBvcnQiLCJwcm94eVRpbWVvdXQiLCJlbmFibGVSYXRlTGltaXRpbmciLCJlbmFibGVTc2wiLCJzc2xGb3JjZSIsInNzbFBvcnQiLCJzc2xDZXJ0UGF0aCIsInBvb2xCZW5jaG1hcmtpbmciLCJyZXNvdXJjZXNJbnRlcnZhbCIsImxvZ0xldmVsIiwiaW50IiwibG9nRmlsZSIsImxvZ0Rlc3QiLCJsb2dUb0NvbnNvbGUiLCJsb2dUb0ZpbGUiLCJlbmFibGVVaSIsInVpUm91dGUiLCJlbmFibGVEZWJ1ZyIsInJlcXVlc3RJZCIsInV1aWQiLCJQdXBwZXRlZXJTY2hlbWEiLCJIaWdoY2hhcnRzU2NoZW1hIiwiRXhwb3J0U2NoZW1hIiwiQ3VzdG9tTG9naWNTY2hlbWEiLCJQcm94eVNjaGVtYSIsIlJhdGVMaW1pdGluZ1NjaGVtYSIsIlNzbFNjaGVtYSIsIlNlcnZlclNjaGVtYSIsIm9wdGlvbmFsIiwiUG9vbFNjaGVtYSIsIkxvZ2dpbmdTY2hlbWEiLCJVaVNjaGVtYSIsIk90aGVyU2NoZW1hIiwiRGVidWdTY2hlbWEiLCJTdHJpY3RDb25maWdTY2hlbWEiLCJMb29zZUNvbmZpZ1NjaGVtYSIsIkVudlNjaGVtYSIsIlBVUFBFVEVFUl9BUkdTIiwiSElHSENIQVJUU19WRVJTSU9OIiwiSElHSENIQVJUU19DRE5fVVJMIiwiSElHSENIQVJUU19GT1JDRV9GRVRDSCIsIkhJR0hDSEFSVFNfQ0FDSEVfUEFUSCIsIkhJR0hDSEFSVFNfQURNSU5fVE9LRU4iLCJISUdIQ0hBUlRTX0NPUkVfU0NSSVBUUyIsIkhJR0hDSEFSVFNfTU9EVUxFX1NDUklQVFMiLCJISUdIQ0hBUlRTX0lORElDQVRPUl9TQ1JJUFRTIiwiSElHSENIQVJUU19DVVNUT01fU0NSSVBUUyIsIkVYUE9SVF9JTkZJTEUiLCJFWFBPUlRfSU5TVFIiLCJFWFBPUlRfT1BUSU9OUyIsIkVYUE9SVF9TVkciLCJFWFBPUlRfQkFUQ0giLCJFWFBPUlRfT1VURklMRSIsIkVYUE9SVF9UWVBFIiwiRVhQT1JUX0NPTlNUUiIsIkVYUE9SVF9CNjQiLCJFWFBPUlRfTk9fRE9XTkxPQUQiLCJFWFBPUlRfSEVJR0hUIiwiRVhQT1JUX1dJRFRIIiwiRVhQT1JUX1NDQUxFIiwiRVhQT1JUX0RFRkFVTFRfSEVJR0hUIiwiRVhQT1JUX0RFRkFVTFRfV0lEVEgiLCJFWFBPUlRfREVGQVVMVF9TQ0FMRSIsIkVYUE9SVF9HTE9CQUxfT1BUSU9OUyIsIkVYUE9SVF9USEVNRV9PUFRJT05TIiwiRVhQT1JUX1JBU1RFUklaQVRJT05fVElNRU9VVCIsIkNVU1RPTV9MT0dJQ19BTExPV19DT0RFX0VYRUNVVElPTiIsIkNVU1RPTV9MT0dJQ19BTExPV19GSUxFX1JFU09VUkNFUyIsIkNVU1RPTV9MT0dJQ19DVVNUT01fQ09ERSIsIkNVU1RPTV9MT0dJQ19DQUxMQkFDSyIsIkNVU1RPTV9MT0dJQ19SRVNPVVJDRVMiLCJDVVNUT01fTE9HSUNfTE9BRF9DT05GSUciLCJDVVNUT01fTE9HSUNfQ1JFQVRFX0NPTkZJRyIsIlNFUlZFUl9FTkFCTEUiLCJTRVJWRVJfSE9TVCIsIlNFUlZFUl9QT1JUIiwiU0VSVkVSX1VQTE9BRF9MSU1JVCIsIlNFUlZFUl9CRU5DSE1BUktJTkciLCJTRVJWRVJfUFJPWFlfSE9TVCIsIlNFUlZFUl9QUk9YWV9QT1JUIiwiU0VSVkVSX1BST1hZX1RJTUVPVVQiLCJTRVJWRVJfUkFURV9MSU1JVElOR19FTkFCTEUiLCJTRVJWRVJfUkFURV9MSU1JVElOR19NQVhfUkVRVUVTVFMiLCJTRVJWRVJfUkFURV9MSU1JVElOR19XSU5ET1ciLCJTRVJWRVJfUkFURV9MSU1JVElOR19ERUxBWSIsIlNFUlZFUl9SQVRFX0xJTUlUSU5HX1RSVVNUX1BST1hZIiwiU0VSVkVSX1JBVEVfTElNSVRJTkdfU0tJUF9LRVkiLCJTRVJWRVJfUkFURV9MSU1JVElOR19TS0lQX1RPS0VOIiwiU0VSVkVSX1NTTF9FTkFCTEUiLCJTRVJWRVJfU1NMX0ZPUkNFIiwiU0VSVkVSX1NTTF9QT1JUIiwiU0VSVkVSX1NTTF9DRVJUX1BBVEgiLCJQT09MX01JTl9XT1JLRVJTIiwiUE9PTF9NQVhfV09SS0VSUyIsIlBPT0xfV09SS19MSU1JVCIsIlBPT0xfQUNRVUlSRV9USU1FT1VUIiwiUE9PTF9DUkVBVEVfVElNRU9VVCIsIlBPT0xfREVTVFJPWV9USU1FT1VUIiwiUE9PTF9JRExFX1RJTUVPVVQiLCJQT09MX0NSRUFURV9SRVRSWV9JTlRFUlZBTCIsIlBPT0xfUkVBUEVSX0lOVEVSVkFMIiwiUE9PTF9CRU5DSE1BUktJTkciLCJMT0dHSU5HX0xFVkVMIiwiTE9HR0lOR19GSUxFIiwiTE9HR0lOR19ERVNUIiwiTE9HR0lOR19UT19DT05TT0xFIiwiTE9HR0lOR19UT19GSUxFIiwiVUlfRU5BQkxFIiwiVUlfUk9VVEUiLCJPVEhFUl9OT0RFX0VOViIsIk9USEVSX0xJU1RFTl9UT19QUk9DRVNTX0VYSVRTIiwiT1RIRVJfTk9fTE9HTyIsIk9USEVSX0hBUkRfUkVTRVRfUEFHRSIsIk9USEVSX0JST1dTRVJfU0hFTExfTU9ERSIsIk9USEVSX1ZBTElEQVRJT04iLCJERUJVR19FTkFCTEUiLCJERUJVR19IRUFETEVTUyIsIkRFQlVHX0RFVlRPT0xTIiwiREVCVUdfTElTVEVOX1RPX0NPTlNPTEUiLCJERUJVR19EVU1QSU8iLCJERUJVR19TTE9XX01PIiwiREVCVUdfREVCVUdHSU5HX1BPUlQiLCJlbnZzIiwicGFyc2UiLCJlbnYiLCJzdHJpY3RWYWxpZGF0ZSIsImNvbmZpZ09wdGlvbnMiLCJsb29zZVZhbGlkYXRlIiwiY29udGV4dCIsInByb3BlcnR5TmFtZSIsInByb3BlcnR5SW5mbyIsImNvZGUiLCJab2RJc3N1ZUNvZGUiLCJpbnZhbGlkX3R5cGUiLCJyZWNlaXZlZCIsIlpvZFBhcnNlZFR5cGUiLCJkZWZhdWx0RXJyb3IiLCJjdXN0b20iLCJkYXRhIiwiaW52YWxpZF91bmlvbiIsInVuaW9uRXJyb3JzIiwiaW5kZXgiLCJFeHBvcnRFcnJvciIsIkVycm9yIiwiY29uc3RydWN0b3IiLCJzdGF0dXNDb2RlIiwic3VwZXIiLCJzZXRTdGF0dXMiLCJzZXRFcnJvciIsIm5hbWUiLCJfaW5pdEdsb2JhbE9wdGlvbnMiLCJpbnN0YW5jZU9wdGlvbnMiLCJnZXRPcHRpb25zIiwiZ2V0SW5zdGFuY2UiLCJzZXRHbG9iYWxPcHRpb25zIiwiY3VzdG9tT3B0aW9ucyIsImNsaUFyZ3MiLCJjbGlPcHRpb25zIiwiX2xvYWRDb25maWdGaWxlIiwiX3BhaXJBcmd1bWVudFZhbHVlIiwiX3VwZGF0ZUdsb2JhbE9wdGlvbnMiLCJ1cGRhdGVPcHRpb25zIiwibmV3SW5zdGFuY2UiLCJtZXJnZU9wdGlvbnMiLCJvcmlnaW5hbE9wdGlvbnMiLCJuZXdPcHRpb25zIiwiZW50cmllcyIsIm1hcFRvTmV3T3B0aW9ucyIsIm9sZE9wdGlvbnMiLCJwcm9wZXJ0aWVzQ2hhaW4iLCJyZWR1Y2UiLCJvYmoiLCJwcm9wIiwidmFsaWRhdGVPcHRpb24iLCJjb25maWdPcHRpb24iLCJ2YWxpZGF0ZU9wdGlvbnMiLCJpc0FsbG93ZWRDb25maWciLCJhbGxvd0Z1bmN0aW9ucyIsIm9iamVjdENvbmZpZyIsImV2YWwiLCJKU09OIiwic3RyaW5naWZpZWRPcHRpb25zIiwiX29wdGlvbnNTdHJpbmdpZnkiLCJwYXJzZWRPcHRpb25zIiwiXyIsImVudlZhbCIsImNvbmZpZ09wdCIsImNsaU9wdCIsImN1c3RvbU9wdCIsImNvbmZpZ1ZhbCIsImNsaVZhbCIsImN1c3RvbVZhbCIsInN0cmluZ2lmeUZ1bmN0aW9ucyIsInN0cmluZ2lmeSIsInJlcGxhY2VBbGwiLCJjdXN0b21Mb2dpY09wdGlvbnMiLCJjb25maWdJbmRleCIsImZpbmRJbmRleCIsImFyZyIsImNvbmZpZ0ZpbGVOYW1lIiwiaSIsIm9wdGlvbiIsImFzeW5jIiwiZmV0Y2giLCJ1cmwiLCJyZXF1ZXN0T3B0aW9ucyIsIlByb21pc2UiLCJyZXNvbHZlIiwicmVqZWN0IiwiX2dldFByb3RvY29sTW9kdWxlIiwiZ2V0IiwicmVzcG9uc2UiLCJyZXNwb25zZURhdGEiLCJvbiIsImNodW5rIiwidGV4dCIsImh0dHBzIiwiaHR0cCIsImNhY2hlIiwiYWN0aXZlTWFuaWZlc3QiLCJzb3VyY2VzIiwiaGNWZXJzaW9uIiwiY2hlY2tBbmRVcGRhdGVDYWNoZSIsImhpZ2hjaGFydHNPcHRpb25zIiwic2VydmVyUHJveHlPcHRpb25zIiwiZmV0Y2hlZE1vZHVsZXMiLCJnZXRDYWNoZVBhdGgiLCJtYW5pZmVzdFBhdGgiLCJzb3VyY2VQYXRoIiwicmVjdXJzaXZlIiwiX3VwZGF0ZUNhY2hlIiwicmVxdWVzdFVwZGF0ZSIsIm1hbmlmZXN0IiwibW9kdWxlcyIsIm1vZHVsZU1hcCIsIm0iLCJudW1iZXJPZk1vZHVsZXMiLCJtb2R1bGVOYW1lIiwiZXh0cmFjdFZlcnNpb24iLCJfc2F2ZUNvbmZpZ1RvTWFuaWZlc3QiLCJnZXRIaWdoY2hhcnRzVmVyc2lvbiIsInVwZGF0ZUhpZ2hjaGFydHNWZXJzaW9uIiwibmV3VmVyc2lvbiIsImNhY2hlU291cmNlcyIsImV4dHJhY3RNb2R1bGVOYW1lIiwic2NyaXB0UGF0aCIsIl9mZXRjaEFuZFByb2Nlc3NTY3JpcHQiLCJzY3JpcHQiLCJzaG91bGRUaHJvd0Vycm9yIiwibmV3TWFuaWZlc3QiLCJ3cml0ZUZpbGVTeW5jIiwiX2ZldGNoU2NyaXB0cyIsInByb3h5QWdlbnQiLCJIdHRwc1Byb3h5QWdlbnQiLCJhZ2VudCIsImFsbEZldGNoUHJvbWlzZXMiLCJhbGwiLCJjIiwic2V0dXBIaWdoY2hhcnRzIiwiSGlnaGNoYXJ0cyIsImFuaW1PYmplY3QiLCJkdXJhdGlvbiIsImNyZWF0ZUNoYXJ0IiwiZXhwb3J0T3B0aW9ucyIsInNldE9wdGlvbnMiLCJtZXJnZSIsIndyYXAiLCJzZXRPcHRpb25zT2JqIiwiaXNSZW5kZXJDb21wbGV0ZSIsIkNoYXJ0IiwicHJvY2VlZCIsInVzZXJPcHRpb25zIiwiY2IiLCJleHBvcnRpbmciLCJlbmFibGVkIiwicGxvdE9wdGlvbnMiLCJzZXJpZXMiLCJsYWJlbCIsInRvb2x0aXAiLCJhbmltYXRpb24iLCJvbkhpZ2hjaGFydHNSZW5kZXIiLCJhZGRFdmVudCIsIlNlcmllcyIsImNoYXJ0IiwiRnVuY3Rpb24iLCJmaW5hbE9wdGlvbnMiLCJmaW5hbENhbGxiYWNrIiwiZGVmYXVsdE9wdGlvbnMiLCJ0ZW1wbGF0ZSIsImJyb3dzZXIiLCJjcmVhdGVCcm93c2VyIiwicHVwcGV0ZWVyQXJncyIsImVuYWJsZWREZWJ1ZyIsImRlYnVnT3B0aW9ucyIsImxhdW5jaE9wdGlvbnMiLCJ1c2VyRGF0YURpciIsImhhbmRsZVNJR0lOVCIsImhhbmRsZVNJR1RFUk0iLCJoYW5kbGVTSUdIVVAiLCJ3YWl0Rm9ySW5pdGlhbFBhZ2UiLCJkZWZhdWx0Vmlld3BvcnQiLCJ0cnlDb3VudCIsIm9wZW4iLCJsYXVuY2giLCJzZXRUaW1lb3V0IiwiY2xvc2VCcm93c2VyIiwiY29ubmVjdGVkIiwiY2xvc2UiLCJuZXdQYWdlIiwicG9vbFJlc291cmNlIiwicGFnZSIsInNldENhY2hlRW5hYmxlZCIsIl9zZXRQYWdlQ29udGVudCIsIl9zZXRQYWdlRXZlbnRzIiwiaXNDbG9zZWQiLCJjbGVhclBhZ2UiLCJoYXJkUmVzZXQiLCJnb3RvIiwid2FpdFVudGlsIiwiZXZhbHVhdGUiLCJib2R5IiwiaW5uZXJIVE1MIiwiaWQiLCJ3b3JrQ291bnQiLCJhZGRQYWdlUmVzb3VyY2VzIiwiaW5qZWN0ZWRSZXNvdXJjZXMiLCJpbmplY3RlZEpzIiwiY29udGVudCIsImlzTG9jYWwiLCJqc1Jlc291cmNlIiwiYWRkU2NyaXB0VGFnIiwiaW5qZWN0ZWRDc3MiLCJjc3NJbXBvcnRzIiwibWF0Y2giLCJjc3NJbXBvcnRQYXRoIiwiY3NzUmVzb3VyY2UiLCJhZGRTdHlsZVRhZyIsImNsZWFyUGFnZVJlc291cmNlcyIsInJlc291cmNlIiwiZGlzcG9zZSIsIm9sZENoYXJ0cyIsImNoYXJ0cyIsIm9sZENoYXJ0IiwiZGVzdHJveSIsInNjcmlwdHNUb1JlbW92ZSIsImdldEVsZW1lbnRzQnlUYWdOYW1lIiwic3R5bGVzVG9SZW1vdmUiLCJsaW5rc1RvUmVtb3ZlIiwiZWxlbWVudCIsInJlbW92ZSIsInNldENvbnRlbnQiLCJjc3NUZW1wbGF0ZSIsInN2Z1RlbXBsYXRlIiwicHVwcGV0ZWVyRXhwb3J0IiwiaXNTVkciLCJzaXplIiwic3ZnRWxlbWVudCIsInF1ZXJ5U2VsZWN0b3IiLCJjaGFydEhlaWdodCIsImJhc2VWYWwiLCJjaGFydFdpZHRoIiwic3R5bGUiLCJ6b29tIiwibWFyZ2luIiwicGFyc2VGbG9hdCIsIngiLCJ5IiwiX2dldENsaXBSZWdpb24iLCJ2aWV3cG9ydEhlaWdodCIsImFicyIsImNlaWwiLCJ2aWV3cG9ydFdpZHRoIiwicmVzdWx0Iiwic2V0Vmlld3BvcnQiLCJkZXZpY2VTY2FsZUZhY3RvciIsIl9jcmVhdGVTVkciLCJfY3JlYXRlSW1hZ2UiLCJfY3JlYXRlUERGIiwiJGV2YWwiLCJnZXRCb3VuZGluZ0NsaWVudFJlY3QiLCJ0cnVuYyIsIm91dGVySFRNTCIsImNsaXAiLCJyYWNlIiwic2NyZWVuc2hvdCIsImVuY29kaW5nIiwiZnVsbFBhZ2UiLCJvcHRpbWl6ZUZvclNwZWVkIiwiY2FwdHVyZUJleW9uZFZpZXdwb3J0IiwicXVhbGl0eSIsIm9taXRCYWNrZ3JvdW5kIiwiX3Jlc29sdmUiLCJlbXVsYXRlTWVkaWFUeXBlIiwicGRmIiwicG9vbFN0YXRzIiwiZXhwb3J0c0F0dGVtcHRlZCIsImV4cG9ydHNQZXJmb3JtZWQiLCJleHBvcnRzRHJvcHBlZCIsImV4cG9ydHNGcm9tU3ZnIiwiZXhwb3J0c0Zyb21PcHRpb25zIiwiZXhwb3J0c0Zyb21TdmdBdHRlbXB0cyIsImV4cG9ydHNGcm9tT3B0aW9uc0F0dGVtcHRzIiwidGltZVNwZW50IiwidGltZVNwZW50QXZlcmFnZSIsImluaXRQb29sIiwicG9vbE9wdGlvbnMiLCJQb29sIiwiX2ZhY3RvcnkiLCJhY3F1aXJlVGltZW91dE1pbGxpcyIsImNyZWF0ZVRpbWVvdXRNaWxsaXMiLCJkZXN0cm95VGltZW91dE1pbGxpcyIsImlkbGVUaW1lb3V0TWlsbGlzIiwiY3JlYXRlUmV0cnlJbnRlcnZhbE1pbGxpcyIsInJlYXBJbnRlcnZhbE1pbGxpcyIsInByb3BhZ2F0ZUNyZWF0ZUVycm9yIiwiY2xlYXJTdGF0dXMiLCJfZXZlbnRJZCIsImluaXRpYWxSZXNvdXJjZXMiLCJhY3F1aXJlIiwicHJvbWlzZSIsInJlbGVhc2UiLCJraWxsUG9vbCIsIndvcmtlciIsInVzZWQiLCJkZXN0cm95ZWQiLCJwb3N0V29yayIsIndvcmtlckhhbmRsZSIsImdldFBvb2xJbmZvIiwiYWNxdWlyZUNvdW50ZXIiLCJ3b3JrU3RhcnQiLCJleHBvcnRDb3VudGVyIiwiZXhwb3J0VGltZSIsImdldFBvb2xTdGF0cyIsImdldFBvb2xJbmZvSlNPTiIsIm51bVVzZWQiLCJhdmFpbGFibGUiLCJudW1GcmVlIiwiYWxsQ3JlYXRlZCIsInBlbmRpbmdBY3F1aXJlcyIsIm51bVBlbmRpbmdBY3F1aXJlcyIsInBlbmRpbmdDcmVhdGVzIiwibnVtUGVuZGluZ0NyZWF0ZXMiLCJwZW5kaW5nVmFsaWRhdGlvbnMiLCJudW1QZW5kaW5nVmFsaWRhdGlvbnMiLCJwZW5kaW5nRGVzdHJveXMiLCJhYnNvbHV0ZUFsbCIsImNyZWF0ZSIsInJhbmRvbSIsInN0YXJ0RGF0ZSIsInZhbGlkYXRlIiwibWFpbkZyYW1lIiwiZGV0YWNoZWQiLCJyZW1vdmVBbGxMaXN0ZW5lcnMiLCJzYW5pdGl6ZSIsIkpTRE9NIiwiRE9NUHVyaWZ5IiwiQUREX1RBR1MiLCJzaW5nbGVFeHBvcnQiLCJzdGFydEV4cG9ydCIsImJhdGNoRXhwb3J0IiwiYmF0Y2hGdW5jdGlvbnMiLCJwYWlyIiwiYmF0Y2hSZXN1bHRzIiwiYWxsU2V0dGxlZCIsInJlYXNvbiIsImV4cG9ydGluZ09wdGlvbnMiLCJlbmRDYWxsYmFjayIsImZpbGVDb250ZW50IiwiX2V4cG9ydEZyb21TdmciLCJfZXhwb3J0RnJvbU9wdGlvbnMiLCJnZXRBbGxvd0NvZGVFeGVjdXRpb24iLCJzZXRBbGxvd0NvZGVFeGVjdXRpb24iLCJpbnB1dFRvRXhwb3J0IiwiX3ByZXBhcmVFeHBvcnQiLCJfaGFuZGxlQ3VzdG9tTG9naWMiLCJfaGFuZGxlR2xvYmFsQW5kVGhlbWUiLCJfZmluZENoYXJ0U2l6ZSIsIm9wdGlvbnNDaGFydCIsIm9wdGlvbnNFeHBvcnRpbmciLCJnbG9iYWxPcHRpb25zQ2hhcnQiLCJnbG9iYWxPcHRpb25zRXhwb3J0aW5nIiwidGhlbWVPcHRpb25zQ2hhcnQiLCJ0aGVtZU9wdGlvbnNFeHBvcnRpbmciLCJzb3VyY2VIZWlnaHQiLCJzb3VyY2VXaWR0aCIsInBhcmFtIiwiX2hhbmRsZVJlc291cmNlcyIsImFsbG93ZWRQcm9wcyIsImhhbmRsZWRSZXNvdXJjZXMiLCJjb3JyZWN0UmVzb3VyY2VzIiwicHJvcE5hbWUiLCJvcHRpb25zTmFtZSIsInRpbWVySWRzIiwiYWRkVGltZXIiLCJjbGVhckFsbFRpbWVycyIsImNsZWFySW50ZXJ2YWwiLCJjbGVhclRpbWVvdXQiLCJsb2dFcnJvck1pZGRsZXdhcmUiLCJyZXF1ZXN0IiwibmV4dCIsInJldHVybkVycm9yTWlkZGxld2FyZSIsInN0YXR1cyIsImpzb24iLCJlcnJvck1pZGRsZXdhcmUiLCJhcHAiLCJ1c2UiLCJyYXRlTGltaXRpbmdNaWRkbGV3YXJlIiwicmF0ZUxpbWl0aW5nT3B0aW9ucyIsInJhdGVPcHRpb25zIiwibGltaXRlciIsInJhdGVMaW1pdCIsIndpbmRvd01zIiwibGltaXQiLCJkZWxheU1zIiwiaGFuZGxlciIsImZvcm1hdCIsInNlbmQiLCJkZWZhdWx0Iiwic2tpcCIsInF1ZXJ5IiwiYWNjZXNzX3Rva2VuIiwiY29udGVudFR5cGVNaWRkbGV3YXJlIiwiY29udGVudFR5cGUiLCJoZWFkZXJzIiwicmVxdWVzdEJvZHlNaWRkbGV3YXJlIiwiY29ubmVjdGlvbiIsInJlbW90ZUFkZHJlc3MiLCJ2YWxpZGF0ZWRPcHRpb25zIiwiZmlsZW5hbWUiLCJ2YWxpZGF0aW9uTWlkZGxld2FyZSIsInBvc3QiLCJyZXZlcnNlZE1pbWUiLCJwbmciLCJqcGVnIiwiZ2lmIiwicmVxdWVzdEV4cG9ydCIsInJlcXVlc3RDb3VudGVyIiwiY29ubmVjdGlvbkFib3J0ZWQiLCJzb2NrZXQiLCJoYWRFcnJvcnMiLCJoZWFkZXIiLCJhdHRhY2htZW50IiwiZXhwb3J0Um91dGVzIiwic2VydmVyU3RhcnRUaW1lIiwicGFja2FnZUZpbGUiLCJzdWNjZXNzUmF0ZXMiLCJyZWNvcmRJbnRlcnZhbCIsIndpbmRvd1NpemUiLCJfY2FsY3VsYXRlTW92aW5nQXZlcmFnZSIsImEiLCJiIiwiX3N0YXJ0U3VjY2Vzc1JhdGUiLCJzZXRJbnRlcnZhbCIsInN0YXRzIiwic3VjY2Vzc1JhdGlvIiwiaGVhbHRoUm91dGVzIiwicGVyaW9kIiwibW92aW5nQXZlcmFnZSIsImJvb3RUaW1lIiwidXB0aW1lIiwiZmxvb3IiLCJzZXJ2ZXJWZXJzaW9uIiwiaGlnaGNoYXJ0c1ZlcnNpb24iLCJhdmVyYWdlRXhwb3J0VGltZSIsImF0dGVtcHRlZEV4cG9ydHMiLCJwZXJmb3JtZWRFeHBvcnRzIiwiZmFpbGVkRXhwb3J0cyIsInN1Y2Vzc1JhdGlvIiwidG9GaXhlZCIsInN2Z0V4cG9ydHMiLCJqc29uRXhwb3J0cyIsInN2Z0V4cG9ydHNBdHRlbXB0cyIsImpzb25FeHBvcnRzQXR0ZW1wdHMiLCJ1aVJvdXRlcyIsInNlbmRGaWxlIiwiYWNjZXB0UmFuZ2VzIiwidmVyc2lvbkNoYW5nZVJvdXRlcyIsInRva2VuIiwiYWN0aXZlU2VydmVycyIsIk1hcCIsImV4cHJlc3MiLCJzdGFydFNlcnZlciIsInNlcnZlck9wdGlvbnMiLCJ1cGxvYWRMaW1pdEJ5dGVzIiwic3RvcmFnZSIsIm11bHRlciIsIm1lbW9yeVN0b3JhZ2UiLCJ1cGxvYWQiLCJsaW1pdHMiLCJmaWVsZFNpemUiLCJkaXNhYmxlIiwiY29ycyIsIm1ldGhvZHMiLCJzZXQiLCJ1cmxlbmNvZGVkIiwiZXh0ZW5kZWQiLCJub25lIiwic3RhdGljIiwiaHR0cFNlcnZlciIsImNyZWF0ZVNlcnZlciIsIl9hdHRhY2hTZXJ2ZXJFcnJvckhhbmRsZXJzIiwibGlzdGVuIiwiY2VydCIsInJlYWRGaWxlIiwiaHR0cHNTZXJ2ZXIiLCJjbG9zZVNlcnZlcnMiLCJkZWxldGUiLCJnZXRTZXJ2ZXJzIiwiZ2V0RXhwcmVzcyIsImdldEFwcCIsIm1pZGRsZXdhcmVzIiwic2h1dGRvd25DbGVhblVwIiwiZXhpdENvZGUiLCJleGl0IiwiaW5pdEV4cG9ydCIsImluaXRPcHRpb25zIiwiX2F0dGFjaFByb2Nlc3NFeGl0TGlzdGVuZXJzIl0sIm1hcHBpbmdzIjoid25CQTJCTyxNQUFNQSxZQUFZQyxJQUFhQSxjQUFDLElBQUlDLElBQUksT0FBUSxvQkFBQUMsU0FBQUMsUUFBQSxPQUFBQyxjQUFBQyxZQUFBQyxLQUFBQyx3QkFBQSxXQUFBQSx1QkFBQUMsUUFBQUMsZUFBQUYsdUJBQUFHLEtBQUEsSUFBQVQsSUFBQSxZQUFBQyxTQUFBUyxTQUFBTCxPQStCaEQsU0FBU00sU0FBU0MsR0FFdkIsR0FBZSxPQUFYQSxHQUFxQyxpQkFBWEEsRUFDNUIsT0FBT0EsRUFJVCxNQUFNQyxFQUFhQyxNQUFNQyxRQUFRSCxHQUFVLEdBQUssR0FHaEQsSUFBSyxNQUFNSSxLQUFPSixFQUNaSyxPQUFPQyxVQUFVQyxlQUFlQyxLQUFLUixFQUFRSSxLQUMvQ0gsRUFBV0csR0FBT0wsU0FBU0MsRUFBT0ksS0FLdEMsT0FBT0gsQ0FDVCxDQTJETyxTQUFTUSxVQUFVQyxHQUN4QixJQUVFLE1BQU1DLEVBQWMsR0FBR0QsRUFBT0UsY0FBY0MsUUFBUSxRQUFTLFdBUTdELE1BTG9CLFVBQWhCRixHQUNGQSxFQUFZQyxjQUlQLENBQUMsUUFBUyxhQUFjLFdBQVksY0FBY0UsU0FDdkRILEdBRUVBLEVBQ0EsT0FDUixDQUFJLE1BRUEsTUFBTyxPQUNSLENBQ0gsQ0FZTyxTQUFTSSxXQUFXQyxFQUFNQyxHQU8vQixNQUFPLEdBTFVDLGdCQUFnQkQsR0FBVyxTQUN6Q0UsTUFBTSxLQUNOQyxXQUdtQkosR0FDeEIsQ0FhTyxTQUFTSyxRQUFRTCxFQUFNQyxFQUFVLE1BRXRDLE1BQU1LLEVBQVksQ0FDaEIsWUFBYSxNQUNiLGFBQWMsT0FDZCxrQkFBbUIsTUFDbkIs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 +//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguY2pzIiwic291cmNlcyI6WyIuLi9saWIvdXRpbHMuanMiLCIuLi9saWIvbG9nZ2VyLmpzIiwiLi4vbGliL3NjaGVtYXMvY29uZmlnLmpzIiwiLi4vbGliL3ZhbGlkYXRpb24uanMiLCIuLi9saWIvZXJyb3JzL0V4cG9ydEVycm9yLmpzIiwiLi4vbGliL2NvbmZpZy5qcyIsIi4uL2xpYi9mZXRjaC5qcyIsIi4uL2xpYi9jYWNoZS5qcyIsIi4uL2xpYi9oaWdoY2hhcnRzLmpzIiwiLi4vbGliL2Jyb3dzZXIuanMiLCIuLi90ZW1wbGF0ZXMvc3ZnRXhwb3J0L2Nzcy5qcyIsIi4uL3RlbXBsYXRlcy9zdmdFeHBvcnQvc3ZnRXhwb3J0LmpzIiwiLi4vbGliL2V4cG9ydC5qcyIsIi4uL2xpYi9wb29sLmpzIiwiLi4vbGliL3Nhbml0aXplLmpzIiwiLi4vbGliL2NoYXJ0LmpzIiwiLi4vbGliL3RpbWVyLmpzIiwiLi4vbGliL3NlcnZlci9taWRkbGV3YXJlcy9lcnJvci5qcyIsIi4uL2xpYi9zZXJ2ZXIvbWlkZGxld2FyZXMvcmF0ZUxpbWl0aW5nLmpzIiwiLi4vbGliL3NlcnZlci9taWRkbGV3YXJlcy92YWxpZGF0aW9uLmpzIiwiLi4vbGliL3NlcnZlci9yb3V0ZXMvZXhwb3J0LmpzIiwiLi4vbGliL3NlcnZlci9yb3V0ZXMvaGVhbHRoLmpzIiwiLi4vbGliL3NlcnZlci9yb3V0ZXMvdWkuanMiLCIuLi9saWIvc2VydmVyL3JvdXRlcy92ZXJzaW9uQ2hhbmdlLmpzIiwiLi4vbGliL3NlcnZlci9zZXJ2ZXIuanMiLCIuLi9saWIvcmVzb3VyY2VSZWxlYXNlLmpzIiwiLi4vbGliL2luZGV4LmpzIl0sInNvdXJjZXNDb250ZW50IjpbIi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXHJcblxyXG5IaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXJcclxuXHJcbkNvcHlyaWdodCAoYykgMjAxNi0yMDI1LCBIaWdoc29mdFxyXG5cclxuTGljZW5jZWQgdW5kZXIgdGhlIE1JVCBsaWNlbmNlLlxyXG5cclxuQWRkaXRpb25hbGx5IGEgdmFsaWQgSGlnaGNoYXJ0cyBsaWNlbnNlIGlzIHJlcXVpcmVkIGZvciB1c2UuXHJcblxyXG5TZWUgTElDRU5TRSBmaWxlIGluIHJvb3QgZm9yIGRldGFpbHMuXHJcblxyXG4qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xyXG5cclxuLyoqXHJcbiAqIEBvdmVydmlldyBUaGUgSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyIHV0aWxpdHkgbW9kdWxlIHByb3ZpZGVzXHJcbiAqIGEgY29tcHJlaGVuc2l2ZSBzZXQgb2YgaGVscGVyIGZ1bmN0aW9ucyBhbmQgY29uc3RhbnRzIGRlc2lnbmVkIHRvIHN0cmVhbWxpbmVcclxuICogYW5kIGVuaGFuY2UgdmFyaW91cyBvcGVyYXRpb25zIHJlcXVpcmVkIGZvciBIaWdoY2hhcnRzIGV4cG9ydCB0YXNrcy5cclxuICovXHJcblxyXG5pbXBvcnQgeyByZWFkRmlsZVN5bmMgfSBmcm9tICdmcyc7XHJcbmltcG9ydCB7IGlzQWJzb2x1dGUsIGpvaW4gfSBmcm9tICdwYXRoJztcclxuaW1wb3J0IHsgZmlsZVVSTFRvUGF0aCB9IGZyb20gJ3VybCc7XHJcblxyXG5jb25zdCBNQVhfQkFDS09GRl9BVFRFTVBUUyA9IDY7XHJcblxyXG4vLyBUaGUgZGlyZWN0b3J5IHBhdGhcclxuZXhwb3J0IGNvbnN0IF9fZGlybmFtZSA9IGZpbGVVUkxUb1BhdGgobmV3IFVSTCgnLi4vLicsIGltcG9ydC5tZXRhLnVybCkpO1xyXG5cclxuLyoqXHJcbiAqIENsZWFycyBhbmQgc3RhbmRhcmRpemVzIHRleHQgYnkgcmVwbGFjaW5nIG11bHRpcGxlIGNvbnNlY3V0aXZlIHdoaXRlc3BhY2VcclxuICogY2hhcmFjdGVycyB3aXRoIGEgc2luZ2xlIHNwYWNlIGFuZCB0cmltbWluZyBhbnkgbGVhZGluZyBvciB0cmFpbGluZ1xyXG4gKiB3aGl0ZXNwYWNlLlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gY2xlYXJUZXh0XHJcbiAqXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSB0ZXh0IC0gVGhlIGlucHV0IHRleHQgdG8gYmUgY2xlYXJlZC5cclxuICogQHBhcmFtIHtSZWdFeHB9IFtydWxlPS9cXHNcXHMrL2ddIC0gVGhlIHJlZ3VsYXIgZXhwcmVzc2lvbiBydWxlIHRvIG1hdGNoXHJcbiAqIG11bHRpcGxlIGNvbnNlY3V0aXZlIHdoaXRlc3BhY2UgY2hhcmFjdGVycy4gVGhlIGRlZmF1bHQgdmFsdWVcclxuICogaXMgdGhlICcvXFxzXFxzKy9nJyBSZWdFeHAuXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSBbcmVwbGFjZXI9JyAnXSAtIFRoZSBzdHJpbmcgdXNlZCB0byByZXBsYWNlIG11bHRpcGxlXHJcbiAqIGNvbnNlY3V0aXZlIHdoaXRlc3BhY2UgY2hhcmFjdGVycy4gVGhlIGRlZmF1bHQgdmFsdWUgaXMgdGhlICcgJyBzdHJpbmcuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtzdHJpbmd9IFRoZSBjbGVhcmVkIGFuZCBzdGFuZGFyZGl6ZWQgdGV4dC5cclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiBjbGVhclRleHQodGV4dCwgcnVsZSA9IC9cXHNcXHMrL2csIHJlcGxhY2VyID0gJyAnKSB7XHJcbiAgcmV0dXJuIHRleHQucmVwbGFjZUFsbChydWxlLCByZXBsYWNlcikudHJpbSgpO1xyXG59XHJcblxyXG4vKipcclxuICogQ3JlYXRlcyBhIGRlZXAgY29weSBvZiB0aGUgZ2l2ZW4gb2JqZWN0IG9yIGFycmF5LlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gZGVlcENvcHlcclxuICpcclxuICogQHBhcmFtIHsoT2JqZWN0fEFycmF5KX0gb2JqQXJyIC0gVGhlIG9iamVjdCBvciBhcnJheSB0byBiZSBkZWVwbHkgY29waWVkLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7KE9iamVjdHxBcnJheSl9IFRoZSBkZWVwIGNvcHkgb2YgdGhlIHByb3ZpZGVkIG9iamVjdCBvciBhcnJheS5cclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiBkZWVwQ29weShvYmpBcnIpIHtcclxuICAvLyBJZiB0aGUgYG9iakFycmAgaXMgbnVsbCBvciBub3Qgb2YgdGhlIGBvYmplY3RgIHR5cGUsIHJldHVybiBpdFxyXG4gIGlmIChvYmpBcnIgPT09IG51bGwgfHwgdHlwZW9mIG9iakFyciAhPT0gJ29iamVjdCcpIHtcclxuICAgIHJldHVybiBvYmpBcnI7XHJcbiAgfVxyXG5cclxuICAvLyBQcmVwYXJlIGVpdGhlciBhIG5ldyBhcnJheSBvciBhIG5ldyBvYmplY3RcclxuICBjb25zdCBvYmpBcnJDb3B5ID0gQXJyYXkuaXNBcnJheShvYmpBcnIpID8gW10gOiB7fTtcclxuXHJcbiAgLy8gUmVjdXJzaXZlbHkgY29weSBlYWNoIHByb3BlcnR5XHJcbiAgZm9yIChjb25zdCBrZXkgaW4gb2JqQXJyKSB7XHJcbiAgICBpZiAoT2JqZWN0LnByb3RvdHlwZS5oYXNPd25Qcm9wZXJ0eS5jYWxsKG9iakFyciwga2V5KSkge1xyXG4gICAgICBvYmpBcnJDb3B5W2tleV0gPSBkZWVwQ29weShvYmpBcnJba2V5XSk7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICAvLyBSZXR1cm4gdGhlIGNvcGllZCBvYmplY3RcclxuICByZXR1cm4gb2JqQXJyQ29weTtcclxufVxyXG5cclxuLyoqXHJcbiAqIEltcGxlbWVudHMgYW4gZXhwb25lbnRpYWwgYmFja29mZiBzdHJhdGVneSBmb3IgcmV0cnlpbmcgYSBmdW5jdGlvbiB1bnRpbFxyXG4gKiBhIGNlcnRhaW4gbnVtYmVyIG9mIGF0dGVtcHRzIGFyZSByZWFjaGVkLlxyXG4gKlxyXG4gKiBAYXN5bmNcclxuICogQGZ1bmN0aW9uIGV4cEJhY2tvZmZcclxuICpcclxuICogQHBhcmFtIHtGdW5jdGlvbn0gZm4gLSBUaGUgZnVuY3Rpb24gdG8gYmUgcmV0cmllZC5cclxuICogQHBhcmFtIHtudW1iZXJ9IFthdHRlbXB0PTBdIC0gVGhlIGN1cnJlbnQgYXR0ZW1wdCBudW1iZXIuIFRoZSBkZWZhdWx0IHZhbHVlXHJcbiAqIGlzIGAwYC5cclxuICogQHBhcmFtIHsuLi51bmtub3dufSBhcmdzIC0gQXJndW1lbnRzIHRvIGJlIHBhc3NlZCB0byB0aGUgZnVuY3Rpb24uXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtQcm9taXNlPHVua25vd24+fSBBIFByb21pc2UgdGhhdCByZXNvbHZlcyB0byB0aGUgcmVzdWx0XHJcbiAqIG9mIHRoZSBmdW5jdGlvbiBpZiBzdWNjZXNzZnVsLlxyXG4gKlxyXG4gKiBAdGhyb3dzIHtFcnJvcn0gVGhyb3dzIGFuIGBFcnJvcmAgaWYgdGhlIG1heGltdW0gbnVtYmVyIG9mIGF0dGVtcHRzXHJcbiAqIGlzIHJlYWNoZWQuXHJcbiAqL1xyXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gZXhwQmFja29mZihmbiwgYXR0ZW1wdCA9IDAsIC4uLmFyZ3MpIHtcclxuICB0cnkge1xyXG4gICAgLy8gVHJ5IHRvIGNhbGwgdGhlIGZ1bmN0aW9uXHJcbiAgICByZXR1cm4gYXdhaXQgZm4oLi4uYXJncyk7XHJcbiAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgIC8vIENhbGN1bGF0ZSBkZWxheSBpbiBtc1xyXG4gICAgY29uc3QgZGVsYXlJbk1zID0gMiAqKiBhdHRlbXB0ICogMTAwMDtcclxuXHJcbiAgICAvLyBJZiB0aGUgYXR0ZW1wdCBleGNlZWRzIHRoZSBtYXhpbXVtIGF0dGVtcHRzIG9mIHJlcGVhdCwgdGhyb3cgYW4gZXJyb3JcclxuICAgIGlmICgrK2F0dGVtcHQgPj0gTUFYX0JBQ0tPRkZfQVRURU1QVFMpIHtcclxuICAgICAgdGhyb3cgZXJyb3I7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gV2FpdCBnaXZlbiBhbW91bnQgb2YgdGltZVxyXG4gICAgYXdhaXQgbmV3IFByb21pc2UoKHJlc3BvbnNlKSA9PiBzZXRUaW1lb3V0KHJlc3BvbnNlLCBkZWxheUluTXMpKTtcclxuXHJcbiAgICAvLy8gVE8gRE86IENvcnJlY3RcclxuICAgIC8vIC8vIEluZm9ybWF0aW9uIGFib3V0IHRoZSByZXNvdXJjZSB0aW1lb3V0XHJcbiAgICAvLyBsb2coXHJcbiAgICAvLyAgIDMsXHJcbiAgICAvLyAgIGBbdXRpbHNdIFdhaXRlZCAke2RlbGF5SW5Nc31tcyB1bnRpbCBuZXh0IGNhbGwgZm9yIHRoZSByZXNvdXJjZSBvZiBJRDogJHthcmdzWzBdfS5gXHJcbiAgICAvLyApO1xyXG5cclxuICAgIC8vIFRyeSBhZ2FpblxyXG4gICAgcmV0dXJuIGV4cEJhY2tvZmYoZm4sIGF0dGVtcHQsIC4uLmFyZ3MpO1xyXG4gIH1cclxufVxyXG5cclxuLyoqXHJcbiAqIEFkanVzdHMgdGhlIGNvbnN0cnVjdG9yIG5hbWUgYnkgdHJhbnNmb3JtaW5nIGFuZCBub3JtYWxpemluZyBpdCBiYXNlZFxyXG4gKiBvbiBjb21tb24gY2hhcnQgdHlwZXMuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBmaXhDb25zdHJcclxuICpcclxuICogQHBhcmFtIHtzdHJpbmd9IGNvbnN0ciAtIFRoZSBvcmlnaW5hbCBjb25zdHJ1Y3RvciBuYW1lIHRvIGJlIGZpeGVkLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7c3RyaW5nfSBUaGUgY29ycmVjdGVkIGNvbnN0cnVjdG9yIG5hbWUsIG9yICdjaGFydCcgaWYgdGhlIGlucHV0XHJcbiAqIGlzIG5vdCByZWNvZ25pemVkLlxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIGZpeENvbnN0cihjb25zdHIpIHtcclxuICB0cnkge1xyXG4gICAgLy8gRml4IHRoZSBjb25zdHJ1Y3RvciBieSBsb3dlcmluZyBjYXNpbmdcclxuICAgIGNvbnN0IGZpeGVkQ29uc3RyID0gYCR7Y29uc3RyLnRvTG93ZXJDYXNlKCkucmVwbGFjZSgnY2hhcnQnLCAnJyl9Q2hhcnRgO1xyXG5cclxuICAgIC8vIEhhbmRsZSB0aGUgY2FzZSB3aGVyZSB0aGUgcmVzdWx0IGlzIGp1c3QgJ0NoYXJ0J1xyXG4gICAgaWYgKGZpeGVkQ29uc3RyID09PSAnQ2hhcnQnKSB7XHJcbiAgICAgIGZpeGVkQ29uc3RyLnRvTG93ZXJDYXNlKCk7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gUmV0dXJuIHRoZSBjb3JyZWN0ZWQgY29uc3RydWN0b3IsIG90aGVyd2lzZSBkZWZhdWx0IHRvICdjaGFydCdcclxuICAgIHJldHVybiBbJ2NoYXJ0JywgJ3N0b2NrQ2hhcnQnLCAnbWFwQ2hhcnQnLCAnZ2FudHRDaGFydCddLmluY2x1ZGVzKFxyXG4gICAgICBmaXhlZENvbnN0clxyXG4gICAgKVxyXG4gICAgICA/IGZpeGVkQ29uc3RyXHJcbiAgICAgIDogJ2NoYXJ0JztcclxuICB9IGNhdGNoIHtcclxuICAgIC8vIERlZmF1bHQgdG8gJ2NoYXJ0JyBpbiBjYXNlIG9mIGFueSBlcnJvclxyXG4gICAgcmV0dXJuICdjaGFydCc7XHJcbiAgfVxyXG59XHJcblxyXG4vKipcclxuICogRml4ZXMgdGhlIG91dGZpbGUgYmFzZWQgb24gcHJvdmlkZWQgdHlwZS5cclxuICpcclxuICogQGZ1bmN0aW9uIGZpeE91dGZpbGVcclxuICpcclxuICogQHBhcmFtIHtzdHJpbmd9IHR5cGUgLSBUaGUgb3JpZ2luYWwgZXhwb3J0IHR5cGUuXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSBvdXRmaWxlIC0gVGhlIGZpbGUgcGF0aCBvciBuYW1lLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7c3RyaW5nfSBUaGUgY29ycmVjdGVkIG91dGZpbGUuXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gZml4T3V0ZmlsZSh0eXBlLCBvdXRmaWxlKSB7XHJcbiAgLy8gR2V0IHRoZSBmaWxlIG5hbWUgZnJvbSB0aGUgYG91dGZpbGVgIG9wdGlvblxyXG4gIGNvbnN0IGZpbGVOYW1lID0gZ2V0QWJzb2x1dGVQYXRoKG91dGZpbGUgfHwgJ2NoYXJ0JylcclxuICAgIC5zcGxpdCgnLicpXHJcbiAgICAuc2hpZnQoKTtcclxuXHJcbiAgLy8gUmV0dXJuIGEgY29ycmVjdCBvdXRmaWxlXHJcbiAgcmV0dXJuIGAke2ZpbGVOYW1lfS4ke3R5cGV9YDtcclxufVxyXG5cclxuLyoqXHJcbiAqIEZpeGVzIHRoZSBleHBvcnQgdHlwZSBiYXNlZCBvbiBNSU1FIHR5cGVzIGFuZCBmaWxlIGV4dGVuc2lvbnMuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBmaXhUeXBlXHJcbiAqXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSB0eXBlIC0gVGhlIG9yaWdpbmFsIGV4cG9ydCB0eXBlLlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gW291dGZpbGU9bnVsbF0gLSBUaGUgZmlsZSBwYXRoIG9yIG5hbWUuIFRoZSBkZWZhdWx0IHZhbHVlXHJcbiAqIGlzIGBudWxsYC5cclxuICpcclxuICogQHJldHVybnMge3N0cmluZ30gVGhlIGNvcnJlY3RlZCBleHBvcnQgdHlwZS5cclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiBmaXhUeXBlKHR5cGUsIG91dGZpbGUgPSBudWxsKSB7XHJcbiAgLy8gTUlNRSB0eXBlc1xyXG4gIGNvbnN0IG1pbWVUeXBlcyA9IHtcclxuICAgICdpbWFnZS9wbmcnOiAncG5nJyxcclxuICAgICdpbWFnZS9qcGVnJzogJ2pwZWcnLFxyXG4gICAgJ2FwcGxpY2F0aW9uL3BkZic6ICdwZGYnLFxyXG4gICAgJ2ltYWdlL3N2Zyt4bWwnOiAnc3ZnJ1xyXG4gIH07XHJcblxyXG4gIC8vIEdldCBmb3JtYXRzXHJcbiAgY29uc3QgZm9ybWF0cyA9IE9iamVjdC52YWx1ZXMobWltZVR5cGVzKTtcclxuXHJcbiAgLy8gQ2hlY2sgaWYgdHlwZSBhbmQgb3V0ZmlsZSdzIGV4dGVuc2lvbnMgYXJlIHRoZSBzYW1lXHJcbiAgaWYgKG91dGZpbGUpIHtcclxuICAgIGNvbnN0IG91dFR5cGUgPSBvdXRmaWxlLnNwbGl0KCcuJykucG9wKCk7XHJcblxyXG4gICAgLy8gU3VwcG9ydCB0aGUgSlBHIHR5cGVcclxuICAgIGlmIChvdXRUeXBlID09PSAnanBnJykge1xyXG4gICAgICB0eXBlID0gJ2pwZWcnO1xyXG4gICAgfSBlbHNlIGlmIChmb3JtYXRzLmluY2x1ZGVzKG91dFR5cGUpICYmIHR5cGUgIT09IG91dFR5cGUpIHtcclxuICAgICAgdHlwZSA9IG91dFR5cGU7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICAvLyBSZXR1cm4gYSBjb3JyZWN0IHR5cGVcclxuICByZXR1cm4gbWltZVR5cGVzW3R5cGVdIHx8IGZvcm1hdHMuZmluZCgodCkgPT4gdCA9PT0gdHlwZSkgfHwgJ3BuZyc7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBDaGVja3MgaWYgdGhlIGdpdmVuIHBhdGggaXMgcmVsYXRpdmUgb3IgYWJzb2x1dGUgYW5kIHJldHVybnMgdGhlIGNvcnJlY3RlZCxcclxuICogYWJzb2x1dGUgcGF0aC5cclxuICpcclxuICogQGZ1bmN0aW9uIGlzQWJzb2x1dGVQYXRoXHJcbiAqXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSBwYXRoIC0gVGhlIHBhdGggdG8gYmUgY2hlY2tlZCBvbi5cclxuICpcclxuICogQHJldHVybnMge3N0cmluZ30gVGhlIGFic29sdXRlIHBhdGguXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gZ2V0QWJzb2x1dGVQYXRoKHBhdGgpIHtcclxuICByZXR1cm4gaXNBYnNvbHV0ZShwYXRoKSA/IHBhdGggOiBqb2luKF9fZGlybmFtZSwgcGF0aCk7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBDb252ZXJ0cyBpbnB1dCBkYXRhIHRvIGEgQmFzZTY0IHN0cmluZyBiYXNlZCBvbiB0aGUgZXhwb3J0IHR5cGUuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBnZXRCYXNlNjRcclxuICpcclxuICogQHBhcmFtIHtzdHJpbmd9IGlucHV0IC0gVGhlIGlucHV0IHRvIGJlIHRyYW5zZm9ybWVkIHRvIEJhc2U2NCBmb3JtYXQuXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSB0eXBlIC0gVGhlIG9yaWdpbmFsIGV4cG9ydCB0eXBlLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7c3RyaW5nfSBUaGUgQmFzZTY0IHN0cmluZyByZXByZXNlbnRhdGlvbiBvZiB0aGUgaW5wdXQuXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gZ2V0QmFzZTY0KGlucHV0LCB0eXBlKSB7XHJcbiAgLy8gRm9yIHBkZiBhbmQgc3ZnIHR5cGVzIHRoZSBpbnB1dCBtdXN0IGJlIHRyYW5zZm9ybWVkIHRvIEJhc2U2NCBmcm9tIGEgYnVmZmVyXHJcbiAgaWYgKHR5cGUgPT09ICdwZGYnIHx8IHR5cGUgPT0gJ3N2ZycpIHtcclxuICAgIHJldHVybiBCdWZmZXIuZnJvbShpbnB1dCwgJ3V0ZjgnKS50b1N0cmluZygnYmFzZTY0Jyk7XHJcbiAgfVxyXG5cclxuICAvLyBGb3IgcG5nIGFuZCBqcGVnIGlucHV0IGlzIGFscmVhZHkgYSBCYXNlNjQgc3RyaW5nXHJcbiAgcmV0dXJuIGlucHV0O1xyXG59XHJcblxyXG4vKipcclxuICogUmV0dXJucyBzdHJpbmdpZmllZCBkYXRlIHdpdGhvdXQgdGhlIEdNVCB0ZXh0IGluZm9ybWF0aW9uLlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gZ2V0TmV3RGF0ZVxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIGdldE5ld0RhdGUoKSB7XHJcbiAgLy8gR2V0IHJpZCBvZiB0aGUgR01UIHRleHQgaW5mb3JtYXRpb25cclxuICByZXR1cm4gbmV3IERhdGUoKS50b1N0cmluZygpLnNwbGl0KCcoJylbMF0udHJpbSgpO1xyXG59XHJcblxyXG4vKipcclxuICogUmV0dXJucyB0aGUgc3RvcmVkIHRpbWUgdmFsdWUgaW4gbWlsbGlzZWNvbmRzLlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gZ2V0TmV3RGF0ZVRpbWVcclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiBnZXROZXdEYXRlVGltZSgpIHtcclxuICByZXR1cm4gbmV3IERhdGUoKS5nZXRUaW1lKCk7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBDaGVja3MgaWYgdGhlIGdpdmVuIGl0ZW0gaXMgYW4gb2JqZWN0LlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gaXNPYmplY3RcclxuICpcclxuICogQHBhcmFtIHt1bmtub3dufSBpdGVtIC0gVGhlIGl0ZW0gdG8gYmUgY2hlY2tlZC5cclxuICpcclxuICogQHJldHVybnMge2Jvb2xlYW59IFRydWUgaWYgdGhlIGl0ZW0gaXMgYW4gb2JqZWN0LCBmYWxzZSBvdGhlcndpc2UuXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gaXNPYmplY3QoaXRlbSkge1xyXG4gIHJldHVybiBPYmplY3QucHJvdG90eXBlLnRvU3RyaW5nLmNhbGwoaXRlbSkgPT09ICdbb2JqZWN0IE9iamVjdF0nO1xyXG59XHJcblxyXG4vKipcclxuICogQ2hlY2tzIGlmIHRoZSBnaXZlbiBvYmplY3QgaXMgZW1wdHkuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBpc09iamVjdEVtcHR5XHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBpdGVtIC0gVGhlIG9iamVjdCB0byBiZSBjaGVja2VkLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7Ym9vbGVhbn0gVHJ1ZSBpZiB0aGUgb2JqZWN0IGlzIGVtcHR5LCBmYWxzZSBvdGhlcndpc2UuXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gaXNPYmplY3RFbXB0eShpdGVtKSB7XHJcbiAgcmV0dXJuIChcclxuICAgIHR5cGVvZiBpdGVtID09PSAnb2JqZWN0JyAmJlxyXG4gICAgIUFycmF5LmlzQXJyYXkoaXRlbSkgJiZcclxuICAgIGl0ZW0gIT09IG51bGwgJiZcclxuICAgIE9iamVjdC5rZXlzKGl0ZW0pLmxlbmd0aCA9PT0gMFxyXG4gICk7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBDaGVja3MgaWYgYSBwcml2YXRlIElQIHJhbmdlIFVSTCBpcyBmb3VuZCBpbiB0aGUgZ2l2ZW4gc3RyaW5nLlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gaXNQcml2YXRlUmFuZ2VVcmxGb3VuZFxyXG4gKlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gaXRlbSAtIFRoZSBzdHJpbmcgdG8gYmUgY2hlY2tlZCBmb3IgYSBwcml2YXRlIElQIHJhbmdlIFVSTC5cclxuICpcclxuICogQHJldHVybnMge2Jvb2xlYW59IFRydWUgaWYgYSBwcml2YXRlIElQIHJhbmdlIFVSTCBpcyBmb3VuZCwgZmFsc2Ugb3RoZXJ3aXNlLlxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIGlzUHJpdmF0ZVJhbmdlVXJsRm91bmQoaXRlbSkge1xyXG4gIGNvbnN0IHJlZ2V4UGF0dGVybnMgPSBbXHJcbiAgICAveGxpbms6aHJlZj1cIig/Omh0dHA6XFwvXFwvfGh0dHBzOlxcL1xcLyk/bG9jYWxob3N0XFxiLyxcclxuICAgIC94bGluazpocmVmPVwiKD86aHR0cDpcXC9cXC98aHR0cHM6XFwvXFwvKT8xMFxcLlxcZHsxLDN9XFwuXFxkezEsM31cXC5cXGR7MSwzfVxcYi8sXHJcbiAgICAveGxpbms6aHJlZj1cIig/Omh0dHA6XFwvXFwvfGh0dHBzOlxcL1xcLyk/MTI3XFwuXFxkezEsM31cXC5cXGR7MSwzfVxcLlxcZHsxLDN9XFxiLyxcclxuICAgIC94bGluazpocmVmPVwiKD86aHR0cDpcXC9cXC98aHR0cHM6XFwvXFwvKT8xNzJcXC4oMVs2LTldfDJbMC05XXwzWzAtMV0pXFwuXFxkezEsM31cXC5cXGR7MSwzfVxcYi8sXHJcbiAgICAveGxpbms6aHJlZj1cIig/Omh0dHA6XFwvXFwvfGh0dHBzOlxcL1xcLyk/MTkyXFwuMTY4XFwuXFxkezEsM31cXC5cXGR7MSwzfVxcYi9cclxuICBdO1xyXG5cclxuICByZXR1cm4gcmVnZXhQYXR0ZXJucy5zb21lKChwYXR0ZXJuKSA9PiBwYXR0ZXJuLnRlc3QoaXRlbSkpO1xyXG59XHJcblxyXG4vKipcclxuICogVXRpbGl0eSB0byBtZWFzdXJlIGVsYXBzZWQgdGltZSB1c2luZyB0aGUgTm9kZS5qcyBgcHJvY2Vzcy5ocnRpbWUoKWAgbWV0aG9kLlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gbWVhc3VyZVRpbWVcclxuICpcclxuICogQHJldHVybnMge0Z1bmN0aW9ufSBBIGZ1bmN0aW9uIHRvIGNhbGN1bGF0ZSB0aGUgZWxhcHNlZCB0aW1lIGluIG1pbGxpc2Vjb25kcy5cclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiBtZWFzdXJlVGltZSgpIHtcclxuICBjb25zdCBzdGFydCA9IHByb2Nlc3MuaHJ0aW1lLmJpZ2ludCgpO1xyXG4gIHJldHVybiAoKSA9PiBOdW1iZXIocHJvY2Vzcy5ocnRpbWUuYmlnaW50KCkgLSBzdGFydCkgLyAxMDAwMDAwO1xyXG59XHJcblxyXG4vKipcclxuICogUm91bmRzIGEgbnVtYmVyIHRvIHRoZSBzcGVjaWZpZWQgcHJlY2lzaW9uLlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gcm91bmROdW1iZXJcclxuICpcclxuICogQHBhcmFtIHtudW1iZXJ9IHZhbHVlIC0gVGhlIG51bWJlciB0byBiZSByb3VuZGVkLlxyXG4gKiBAcGFyYW0ge251bWJlcn0gcHJlY2lzaW9uIC0gVGhlIG51bWJlciBvZiBkZWNpbWFsIHBsYWNlcyB0byByb3VuZCB0by5cclxuICpcclxuICogQHJldHVybnMge251bWJlcn0gVGhlIHJvdW5kZWQgbnVtYmVyLlxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIHJvdW5kTnVtYmVyKHZhbHVlLCBwcmVjaXNpb24gPSAxKSB7XHJcbiAgY29uc3QgbXVsdGlwbGllciA9IE1hdGgucG93KDEwLCBwcmVjaXNpb24gfHwgMCk7XHJcbiAgcmV0dXJuIE1hdGgucm91bmQoK3ZhbHVlICogbXVsdGlwbGllcikgLyBtdWx0aXBsaWVyO1xyXG59XHJcblxyXG4vKipcclxuICogQ29udmVydHMgYSB2YWx1ZSB0byBhIGJvb2xlYW4uXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiB0b0Jvb2xlYW5cclxuICpcclxuICogQHBhcmFtIHt1bmtub3dufSBpdGVtIC0gVGhlIHZhbHVlIHRvIGJlIGNvbnZlcnRlZCB0byBhIGJvb2xlYW4uXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtib29sZWFufSBUaGUgYm9vbGVhbiByZXByZXNlbnRhdGlvbiBvZiB0aGUgaW5wdXQgdmFsdWUuXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gdG9Cb29sZWFuKGl0ZW0pIHtcclxuICByZXR1cm4gWydmYWxzZScsICd1bmRlZmluZWQnLCAnbnVsbCcsICdOYU4nLCAnMCcsICcnXS5pbmNsdWRlcyhpdGVtKVxyXG4gICAgPyBmYWxzZVxyXG4gICAgOiAhIWl0ZW07XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBXcmFwcyBjdXN0b20gY29kZSB0byBleGVjdXRlIGl0IHNhZmVseS5cclxuICpcclxuICogQGZ1bmN0aW9uIHdyYXBBcm91bmRcclxuICpcclxuICogQHBhcmFtIHtzdHJpbmd9IGN1c3RvbUNvZGUgLSBUaGUgY3VzdG9tIGNvZGUgdG8gYmUgd3JhcHBlZC5cclxuICogQHBhcmFtIHtib29sZWFufSBhbGxvd0ZpbGVSZXNvdXJjZXMgLSBGbGFnIHRvIGFsbG93IGxvYWRpbmcgY29kZSBmcm9tIGEgZmlsZS5cclxuICogQHBhcmFtIHtib29sZWFufSBbaXNDYWxsYmFjaz1mYWxzZV0gLSBGbGFnIHRoYXQgaW5kaWNhdGVzIHRoZSByZXR1cm5lZCBjb2RlXHJcbiAqIG11c3QgYmUgaW4gYSBjYWxsYmFjayBmb3JtYXQuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHsoc3RyaW5nfG51bGwpfSBUaGUgd3JhcHBlZCBjdXN0b20gY29kZSBvciBudWxsIGlmIHdyYXBwaW5nIGZhaWxzLlxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIHdyYXBBcm91bmQoY3VzdG9tQ29kZSwgYWxsb3dGaWxlUmVzb3VyY2VzLCBpc0NhbGxiYWNrID0gZmFsc2UpIHtcclxuICBpZiAoY3VzdG9tQ29kZSAmJiB0eXBlb2YgY3VzdG9tQ29kZSA9PT0gJ3N0cmluZycpIHtcclxuICAgIGN1c3RvbUNvZGUgPSBjdXN0b21Db2RlLnRyaW0oKTtcclxuXHJcbiAgICBpZiAoY3VzdG9tQ29kZS5lbmRzV2l0aCgnLmpzJykpIHtcclxuICAgICAgLy8gTG9hZCBhIGZpbGUgaWYgdGhlIGZpbGUgcmVzb3VyY2VzIGFyZSBhbGxvd2VkXHJcbiAgICAgIHJldHVybiBhbGxvd0ZpbGVSZXNvdXJjZXNcclxuICAgICAgICA/IHdyYXBBcm91bmQoXHJcbiAgICAgICAgICAgIHJlYWRGaWxlU3luYyhnZXRBYnNvbHV0ZVBhdGgoY3VzdG9tQ29kZSksICd1dGY4JyksXHJcbiAgICAgICAgICAgIGFsbG93RmlsZVJlc291cmNlcyxcclxuICAgICAgICAgICAgaXNDYWxsYmFja1xyXG4gICAgICAgICAgKVxyXG4gICAgICAgIDogbnVsbDtcclxuICAgIH0gZWxzZSBpZiAoXHJcbiAgICAgICFpc0NhbGxiYWNrICYmXHJcbiAgICAgIChjdXN0b21Db2RlLnN0YXJ0c1dpdGgoJ2Z1bmN0aW9uKCknKSB8fFxyXG4gICAgICAgIGN1c3RvbUNvZGUuc3RhcnRzV2l0aCgnZnVuY3Rpb24gKCknKSB8fFxyXG4gICAgICAgIGN1c3RvbUNvZGUuc3RhcnRzV2l0aCgnKCk9PicpIHx8XHJcbiAgICAgICAgY3VzdG9tQ29kZS5zdGFydHNXaXRoKCcoKSA9PicpKVxyXG4gICAgKSB7XHJcbiAgICAgIC8vIFRyZWF0IGEgZnVuY3Rpb24gYXMgYSBzZWxmLWludm9raW5nIGV4cHJlc3Npb25cclxuICAgICAgcmV0dXJuIGAoJHtjdXN0b21Db2RlfSkoKWA7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gT3IgcmV0dXJuIGFzIGEgc3RyaW5naWZpZWQgY29kZVxyXG4gICAgcmV0dXJuIGN1c3RvbUNvZGUucmVwbGFjZSgvOyQvLCAnJyk7XHJcbiAgfVxyXG59XHJcblxyXG5leHBvcnQgZGVmYXVsdCB7XHJcbiAgX19kaXJuYW1lLFxyXG4gIGNsZWFyVGV4dCxcclxuICBkZWVwQ29weSxcclxuICBleHBCYWNrb2ZmLFxyXG4gIGZpeENvbnN0cixcclxuICBmaXhPdXRmaWxlLFxyXG4gIGZpeFR5cGUsXHJcbiAgZ2V0QWJzb2x1dGVQYXRoLFxyXG4gIGdldEJhc2U2NCxcclxuICBnZXROZXdEYXRlLFxyXG4gIGdldE5ld0RhdGVUaW1lLFxyXG4gIGlzT2JqZWN0LFxyXG4gIGlzT2JqZWN0RW1wdHksXHJcbiAgaXNQcml2YXRlUmFuZ2VVcmxGb3VuZCxcclxuICBtZWFzdXJlVGltZSxcclxuICByb3VuZE51bWJlcixcclxuICB0b0Jvb2xlYW4sXHJcbiAgd3JhcEFyb3VuZFxyXG59O1xyXG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxyXG5cclxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXHJcblxyXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNSwgSGlnaHNvZnRcclxuXHJcbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cclxuXHJcbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxyXG5cclxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxyXG5cclxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cclxuXHJcbi8qKlxyXG4gKiBAb3ZlcnZpZXcgQSBtb2R1bGUgZm9yIG1hbmFnaW5nIGxvZ2dpbmcgZnVuY3Rpb25hbGl0eSB3aXRoIGN1c3RvbWl6YWJsZVxyXG4gKiBsb2cgbGV2ZWxzLCBjb25zb2xlIGFuZCBmaWxlIGxvZ2dpbmcgb3B0aW9ucywgYW5kIGVycm9yIGhhbmRsaW5nIHN1cHBvcnQuXHJcbiAqIFRoZSBtb2R1bGUgYWxzbyBlbnN1cmVzIHRoYXQgZmlsZS1iYXNlZCBsb2dzIGFyZSBzdG9yZWQgaW4gYSBzdHJ1Y3R1cmVkXHJcbiAqIGRpcmVjdG9yeSwgY3JlYXRpbmcgdGhlIG5lY2Vzc2FyeSBwYXRocyBhdXRvbWF0aWNhbGx5IGlmIHRoZXkgZG8gbm90IGV4aXN0LlxyXG4gKi9cclxuXHJcbmltcG9ydCB7IGFwcGVuZEZpbGUsIGV4aXN0c1N5bmMsIG1rZGlyU3luYyB9IGZyb20gJ2ZzJztcclxuaW1wb3J0IHsgam9pbiB9IGZyb20gJ3BhdGgnO1xyXG5cclxuaW1wb3J0IHsgZ2V0QWJzb2x1dGVQYXRoLCBnZXROZXdEYXRlIH0gZnJvbSAnLi91dGlscy5qcyc7XHJcblxyXG4vLyBUaGUgYXZhaWxhYmxlIGNvbG9yc1xyXG5jb25zdCBjb2xvcnMgPSBbJ3JlZCcsICd5ZWxsb3cnLCAnYmx1ZScsICdncmF5JywgJ2dyZWVuJ107XHJcblxyXG4vLyBUaGUgZGVmYXVsdCBsb2dnaW5nIGNvbmZpZ1xyXG5jb25zdCBsb2dnaW5nID0ge1xyXG4gIC8vIEZsYWdzIGZvciBsb2dnaW5nIHN0YXR1c1xyXG4gIHRvQ29uc29sZTogdHJ1ZSxcclxuICB0b0ZpbGU6IGZhbHNlLFxyXG4gIHBhdGhDcmVhdGVkOiBmYWxzZSxcclxuICAvLyBGdWxsIHBhdGggdG8gdGhlIGxvZyBmaWxlXHJcbiAgcGF0aFRvTG9nOiAnJyxcclxuICAvLyBMb2cgbGV2ZWxzXHJcbiAgbGV2ZWxzRGVzYzogW1xyXG4gICAge1xyXG4gICAgICB0aXRsZTogJ2Vycm9yJyxcclxuICAgICAgY29sb3I6IGNvbG9yc1swXVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdGl0bGU6ICd3YXJuaW5nJyxcclxuICAgICAgY29sb3I6IGNvbG9yc1sxXVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdGl0bGU6ICdub3RpY2UnLFxyXG4gICAgICBjb2xvcjogY29sb3JzWzJdXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0aXRsZTogJ3ZlcmJvc2UnLFxyXG4gICAgICBjb2xvcjogY29sb3JzWzNdXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0aXRsZTogJ2JlbmNobWFyaycsXHJcbiAgICAgIGNvbG9yOiBjb2xvcnNbNF1cclxuICAgIH1cclxuICBdXHJcbn07XHJcblxyXG4vKipcclxuICogTG9ncyBhIG1lc3NhZ2Ugd2l0aCBhIHNwZWNpZmllZCBsb2cgbGV2ZWwuIEFjY2VwdHMgYSB2YXJpYWJsZSBudW1iZXJcclxuICogb2YgYXJndW1lbnRzLiBUaGUgYXJndW1lbnRzIGFmdGVyIHRoZSBgbGV2ZWxgIGFyZSBwYXNzZWQgdG8gYGNvbnNvbGUubG9nYFxyXG4gKiBhbmQvb3IgdXNlZCB0byBjb25zdHJ1Y3QgYW5kIGFwcGVuZCBtZXNzYWdlcyB0byBhIGxvZyBmaWxlLlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gbG9nXHJcbiAqXHJcbiAqIEBwYXJhbSB7Li4udW5rbm93bn0gYXJncyAtIEFuIGFycmF5IG9mIGFyZ3VtZW50cyB3aGVyZSB0aGUgZmlyc3QgaXMgdGhlIGxvZ1xyXG4gKiBsZXZlbCBhbmQgdGhlIHJlbWFpbmluZyBhcmUgc3RyaW5ncyB1c2VkIHRvIGJ1aWxkIHRoZSBsb2cgbWVzc2FnZS5cclxuICpcclxuICogQHJldHVybnMge3ZvaWR9IEV4aXRzIHRoZSBmdW5jdGlvbiBleGVjdXRpb24gaWYgYXR0ZW1wdGluZyB0byBsb2cgYXQgYSBsZXZlbFxyXG4gKiBoaWdoZXIgdGhhbiBhbGxvd2VkLlxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIGxvZyguLi5hcmdzKSB7XHJcbiAgY29uc3QgW25ld0xldmVsLCAuLi50ZXh0c10gPSBhcmdzO1xyXG5cclxuICAvLyBDdXJyZW50IGxvZ2dpbmcgb3B0aW9uc1xyXG4gIGNvbnN0IHsgbGV2ZWxzRGVzYywgbGV2ZWwgfSA9IGxvZ2dpbmc7XHJcblxyXG4gIC8vIENoZWNrIGlmIHRoZSBsb2cgbGV2ZWwgaXMgd2l0aGluIGEgY29ycmVjdCByYW5nZSBvciBpcyBpdCBhIGJlbmNobWFyayBsb2dcclxuICBpZiAoXHJcbiAgICBuZXdMZXZlbCAhPT0gNSAmJlxyXG4gICAgKG5ld0xldmVsID09PSAwIHx8IG5ld0xldmVsID4gbGV2ZWwgfHwgbGV2ZWwgPiBsZXZlbHNEZXNjLmxlbmd0aClcclxuICApIHtcclxuICAgIHJldHVybjtcclxuICB9XHJcblxyXG4gIC8vIENyZWF0ZSBhIG1lc3NhZ2UncyBwcmVmaXhcclxuICBjb25zdCBwcmVmaXggPSBgJHtnZXROZXdEYXRlKCl9IFske2xldmVsc0Rlc2NbbmV3TGV2ZWwgLSAxXS50aXRsZX1dIC1gO1xyXG5cclxuICAvLyBMb2cgdG8gZmlsZVxyXG4gIGlmIChsb2dnaW5nLnRvRmlsZSkge1xyXG4gICAgX2xvZ1RvRmlsZSh0ZXh0cywgcHJlZml4KTtcclxuICB9XHJcblxyXG4gIC8vIExvZyB0byBjb25zb2xlXHJcbiAgaWYgKGxvZ2dpbmcudG9Db25zb2xlKSB7XHJcbiAgICBjb25zb2xlLmxvZy5hcHBseShcclxuICAgICAgdW5kZWZpbmVkLFxyXG4gICAgICBbcHJlZml4LnRvU3RyaW5nKClbbG9nZ2luZy5sZXZlbHNEZXNjW25ld0xldmVsIC0gMV0uY29sb3JdXS5jb25jYXQodGV4dHMpXHJcbiAgICApO1xyXG4gIH1cclxufVxyXG5cclxuLyoqXHJcbiAqIExvZ3MgYW4gZXJyb3IgbWVzc2FnZSBhbG9uZyB3aXRoIGl0cyBzdGFjayB0cmFjZS4gT3B0aW9uYWxseSwgYSBjdXN0b20gbWVzc2FnZVxyXG4gKiBjYW4gYmUgcHJvdmlkZWQuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBsb2dXaXRoU3RhY2tcclxuICpcclxuICogQHBhcmFtIHtudW1iZXJ9IG5ld0xldmVsIC0gVGhlIGxvZyBsZXZlbC5cclxuICogQHBhcmFtIHtFcnJvcn0gZXJyb3IgLSBUaGUgZXJyb3Igb2JqZWN0IGNvbnRhaW5pbmcgdGhlIHN0YWNrIHRyYWNlLlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gY3VzdG9tTWVzc2FnZSAtIEFuIG9wdGlvbmFsIGN1c3RvbSBtZXNzYWdlIHRvIGJlIGluY2x1ZGVkXHJcbiAqIGluIHRoZSBsb2cgYWxvbmdzaWRlIHRoZSBlcnJvci5cclxuICpcclxuICogQHJldHVybnMge3ZvaWR9IEV4aXRzIHRoZSBmdW5jdGlvbiBleGVjdXRpb24gaWYgYXR0ZW1wdGluZyB0byBsb2cgYXQgYSBsZXZlbFxyXG4gKiBoaWdoZXIgdGhhbiBhbGxvd2VkLlxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIGxvZ1dpdGhTdGFjayhuZXdMZXZlbCwgZXJyb3IsIGN1c3RvbU1lc3NhZ2UpIHtcclxuICAvLyBHZXQgdGhlIG1haW4gbWVzc2FnZVxyXG4gIGNvbnN0IG1haW5NZXNzYWdlID0gY3VzdG9tTWVzc2FnZSB8fCAoZXJyb3IgJiYgZXJyb3IubWVzc2FnZSkgfHwgJyc7XHJcblxyXG4gIC8vIEN1cnJlbnQgbG9nZ2luZyBvcHRpb25zXHJcbiAgY29uc3QgeyBsZXZlbCwgbGV2ZWxzRGVzYyB9ID0gbG9nZ2luZztcclxuXHJcbiAgLy8gQ2hlY2sgaWYgdGhlIGxvZyBsZXZlbCBpcyB3aXRoaW4gYSBjb3JyZWN0IHJhbmdlXHJcbiAgaWYgKG5ld0xldmVsID09PSAwIHx8IG5ld0xldmVsID4gbGV2ZWwgfHwgbGV2ZWwgPiBsZXZlbHNEZXNjLmxlbmd0aCkge1xyXG4gICAgcmV0dXJuO1xyXG4gIH1cclxuXHJcbiAgLy8gQ3JlYXRlIGEgbWVzc2FnZSdzIHByZWZpeFxyXG4gIGNvbnN0IHByZWZpeCA9IGAke2dldE5ld0RhdGUoKX0gWyR7bGV2ZWxzRGVzY1tuZXdMZXZlbCAtIDFdLnRpdGxlfV0gLWA7XHJcblxyXG4gIC8vIEFkZCB0aGUgd2hvbGUgc3RhY2sgbWVzc2FnZVxyXG4gIGNvbnN0IHN0YWNrTWVzc2FnZSA9IGVycm9yICYmIGVycm9yLnN0YWNrO1xyXG5cclxuICAvLyBDb21iaW5lIGN1c3RvbSBtZXNzYWdlIG9yIGVycm9yIG1lc3NhZ2Ugd2l0aCBlcnJvciBzdGFjayBtZXNzYWdlLCBpZiBleGlzdHNcclxuICBjb25zdCB0ZXh0cyA9IFttYWluTWVzc2FnZV07XHJcbiAgaWYgKHN0YWNrTWVzc2FnZSkge1xyXG4gICAgdGV4dHMucHVzaCgnXFxuJywgc3RhY2tNZXNzYWdlKTtcclxuICB9XHJcblxyXG4gIC8vIExvZyB0byBmaWxlXHJcbiAgaWYgKGxvZ2dpbmcudG9GaWxlKSB7XHJcbiAgICBfbG9nVG9GaWxlKHRleHRzLCBwcmVmaXgpO1xyXG4gIH1cclxuXHJcbiAgLy8gTG9nIHRvIGNvbnNvbGVcclxuICBpZiAobG9nZ2luZy50b0NvbnNvbGUpIHtcclxuICAgIGNvbnNvbGUubG9nLmFwcGx5KFxyXG4gICAgICB1bmRlZmluZWQsXHJcbiAgICAgIFtwcmVmaXgudG9TdHJpbmcoKVtsb2dnaW5nLmxldmVsc0Rlc2NbbmV3TGV2ZWwgLSAxXS5jb2xvcl1dLmNvbmNhdChbXHJcbiAgICAgICAgdGV4dHMuc2hpZnQoKVtjb2xvcnNbbmV3TGV2ZWwgLSAxXV0sXHJcbiAgICAgICAgLi4udGV4dHNcclxuICAgICAgXSlcclxuICAgICk7XHJcbiAgfVxyXG59XHJcblxyXG4vKipcclxuICogTG9ncyBhbiBlcnJvciBtZXNzYWdlIHJlbGF0ZWQgdG8gWm9kIHZhbGlkYXRpb24gaXNzdWVzLiBPcHRpb25hbGx5LCBhIGN1c3RvbVxyXG4gKiBtZXNzYWdlIGNhbiBiZSBwcm92aWRlZC5cclxuICpcclxuICogQGZ1bmN0aW9uIGxvZ1pvZElzc3Vlc1xyXG4gKlxyXG4gKiBAcGFyYW0ge251bWJlcn0gbmV3TGV2ZWwgLSBUaGUgbG9nIGxldmVsLlxyXG4gKiBAcGFyYW0ge0Vycm9yW119IGlzc3VlcyAtIEFuIGFycmF5IG9mIFpvZCB2YWxpZGF0aW9uIGlzc3Vlcy5cclxuICogQHBhcmFtIHtzdHJpbmd9IGN1c3RvbU1lc3NhZ2UgLSBBbiBvcHRpb25hbCBjdXN0b20gbWVzc2FnZSB0byBiZSBpbmNsdWRlZFxyXG4gKiBpbiB0aGUgbG9nIGFsb25nc2lkZSB0aGUgZXJyb3IuXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gbG9nWm9kSXNzdWVzKG5ld0xldmVsLCBpc3N1ZXMsIGN1c3RvbU1lc3NhZ2UpIHtcclxuICBsb2dXaXRoU3RhY2soXHJcbiAgICBuZXdMZXZlbCxcclxuICAgIG51bGwsXHJcbiAgICBbXHJcbiAgICAgIGAke2N1c3RvbU1lc3NhZ2UgfHwgJ1t2YWxpZGF0aW9uXSBWYWxpZGF0aW9uIGVycm9yJ30gLSB0aGUgZm9sbG93aW5nIFpvZCBpc3N1ZXMgb2NjdXJlZDpgLFxyXG4gICAgICAuLi4oaXNzdWVzIHx8IFtdKS5tYXAoKGlzc3VlKSA9PiBgLSAke2lzc3VlLm1lc3NhZ2V9YClcclxuICAgIF0uam9pbignXFxuJylcclxuICApO1xyXG59XHJcblxyXG4vKipcclxuICogSW5pdGlhbGl6ZXMgbG9nZ2luZyB3aXRoIHRoZSBzcGVjaWZpZWQgbG9nZ2luZyBjb25maWd1cmF0aW9uLlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gaW5pdExvZ2dpbmdcclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IGxvZ2dpbmdPcHRpb25zIC0gVGhlIGNvbmZpZ3VyYXRpb24gb2JqZWN0IGNvbnRhaW5pbmdcclxuICogYGxvZ2dpbmdgIG9wdGlvbnMuXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gaW5pdExvZ2dpbmcobG9nZ2luZ09wdGlvbnMpIHtcclxuICAvLyBHZXQgb3B0aW9ucyBmcm9tIHRoZSBgbG9nZ2luZ09wdGlvbnNgIG9iamVjdFxyXG4gIGNvbnN0IHsgbGV2ZWwsIGRlc3QsIGZpbGUsIHRvQ29uc29sZSwgdG9GaWxlIH0gPSBsb2dnaW5nT3B0aW9ucztcclxuXHJcbiAgLy8gUmVzZXQgZmxhZ3MgdG8gdGhlIGRlZmF1bHQgdmFsdWVzXHJcbiAgbG9nZ2luZy5wYXRoQ3JlYXRlZCA9IGZhbHNlO1xyXG4gIGxvZ2dpbmcucGF0aFRvTG9nID0gJyc7XHJcblxyXG4gIC8vIFNldCB0aGUgbG9nZ2luZyBsZXZlbFxyXG4gIHNldExvZ0xldmVsKGxldmVsKTtcclxuXHJcbiAgLy8gU2V0IHRoZSBjb25zb2xlIGxvZ2dpbmdcclxuICBlbmFibGVDb25zb2xlTG9nZ2luZyh0b0NvbnNvbGUpO1xyXG5cclxuICAvLyBTZXQgdGhlIGZpbGUgbG9nZ2luZ1xyXG4gIGVuYWJsZUZpbGVMb2dnaW5nKGRlc3QsIGZpbGUsIHRvRmlsZSk7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBTZXRzIHRoZSBsb2cgbGV2ZWwgdG8gdGhlIHNwZWNpZmllZCB2YWx1ZS4gTG9nIGxldmVscyBhcmUgKGAwYCA9IG5vIGxvZ2dpbmcsXHJcbiAqIGAxYCA9IGVycm9yLCBgMmAgPSB3YXJuaW5nLCBgM2AgPSBub3RpY2UsIGA0YCA9IHZlcmJvc2UsIG9yIGA1YCA9IGJlbmNobWFyaykuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBzZXRMb2dMZXZlbFxyXG4gKlxyXG4gKiBAcGFyYW0ge251bWJlcn0gbGV2ZWwgLSBUaGUgbG9nIGxldmVsIHRvIGJlIHNldC5cclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiBzZXRMb2dMZXZlbChsZXZlbCkge1xyXG4gIGlmIChcclxuICAgIE51bWJlci5pc0ludGVnZXIobGV2ZWwpICYmXHJcbiAgICBsZXZlbCA+PSAwICYmXHJcbiAgICBsZXZlbCA8PSBsb2dnaW5nLmxldmVsc0Rlc2MubGVuZ3RoXHJcbiAgKSB7XHJcbiAgICAvLyBVcGRhdGUgdGhlIG1vZHVsZSBsb2dnaW5nJ3MgYGxldmVsYCBvcHRpb25cclxuICAgIGxvZ2dpbmcubGV2ZWwgPSBsZXZlbDtcclxuICB9XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBFbmFibGVzIGNvbnNvbGUgbG9nZ2luZy5cclxuICpcclxuICogQGZ1bmN0aW9uIGVuYWJsZUNvbnNvbGVMb2dnaW5nXHJcbiAqXHJcbiAqIEBwYXJhbSB7Ym9vbGVhbn0gdG9Db25zb2xlIC0gVGhlIGZsYWcgZm9yIHNldHRpbmcgdGhlIGxvZ2dpbmcgdG8gdGhlIGNvbnNvbGUuXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gZW5hYmxlQ29uc29sZUxvZ2dpbmcodG9Db25zb2xlKSB7XHJcbiAgLy8gVXBkYXRlIHRoZSBtb2R1bGUgbG9nZ2luZydzIGB0b0NvbnNvbGVgIG9wdGlvblxyXG4gIGxvZ2dpbmcudG9Db25zb2xlID0gISF0b0NvbnNvbGU7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBFbmFibGVzIGZpbGUgbG9nZ2luZyB3aXRoIHRoZSBzcGVjaWZpZWQgZGVzdGluYXRpb24gYW5kIGxvZyBmaWxlIG5hbWUuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBlbmFibGVGaWxlTG9nZ2luZ1xyXG4gKlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gZGVzdCAtIFRoZSBkZXN0aW5hdGlvbiBwYXRoIHdoZXJlIHRoZSBsb2cgZmlsZSBzaG91bGRcclxuICogYmUgc2F2ZWQuXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSBmaWxlIC0gVGhlIG5hbWUgb2YgdGhlIGxvZyBmaWxlLlxyXG4gKiBAcGFyYW0ge2Jvb2xlYW59IHRvRmlsZSAtIEEgZmxhZyBpbmRpY2F0aW5nIHdoZXRoZXIgbG9nZ2luZyBzaG91bGRcclxuICogYmUgZGlyZWN0ZWQgdG8gYSBmaWxlLlxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIGVuYWJsZUZpbGVMb2dnaW5nKGRlc3QsIGZpbGUsIHRvRmlsZSkge1xyXG4gIC8vIFVwZGF0ZSB0aGUgbW9kdWxlIGxvZ2dpbmcncyBgdG9GaWxlYCBvcHRpb25cclxuICBsb2dnaW5nLnRvRmlsZSA9ICEhdG9GaWxlO1xyXG5cclxuICAvLyBTZXQgdGhlIGBkZXN0YCBhbmQgYGZpbGVgIG9wdGlvbnMgb25seSBpZiB0aGUgZmlsZSBsb2dnaW5nIGlzIGVuYWJsZWRcclxuICBpZiAobG9nZ2luZy50b0ZpbGUpIHtcclxuICAgIGxvZ2dpbmcuZGVzdCA9IGRlc3QgfHwgJyc7XHJcbiAgICBsb2dnaW5nLmZpbGUgPSBmaWxlIHx8ICcnO1xyXG4gIH1cclxufVxyXG5cclxuLyoqXHJcbiAqIExvZ3MgdGhlIHByb3ZpZGVkIHRleHRzIHRvIGEgZmlsZSwgaWYgZmlsZSBsb2dnaW5nIGlzIGVuYWJsZWQuIEl0IGNyZWF0ZXNcclxuICogdGhlIG5lY2Vzc2FyeSBkaXJlY3Rvcnkgc3RydWN0dXJlIGlmIG5vdCBhbHJlYWR5IGNyZWF0ZWQgYW5kIGFwcGVuZHNcclxuICogdGhlIGNvbnRlbnQsIGluY2x1ZGluZyBhbiBvcHRpb25hbCBwcmVmaXgsIHRvIHRoZSBzcGVjaWZpZWQgbG9nIGZpbGUuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBfbG9nVG9GaWxlXHJcbiAqXHJcbiAqIEBwYXJhbSB7QXJyYXkuPHN0cmluZz59IHRleHRzIC0gQW4gYXJyYXkgb2YgdGV4dHMgdG8gYmUgbG9nZ2VkLlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gcHJlZml4IC0gQW4gb3B0aW9uYWwgcHJlZml4IHRvIGJlIGFkZGVkIHRvIGVhY2ggbG9nIGVudHJ5LlxyXG4gKi9cclxuZnVuY3Rpb24gX2xvZ1RvRmlsZSh0ZXh0cywgcHJlZml4KSB7XHJcbiAgaWYgKCFsb2dnaW5nLnBhdGhDcmVhdGVkKSB7XHJcbiAgICAvLyBDcmVhdGUgaWYgZG9lcyBub3QgZXhpc3RcclxuICAgICFleGlzdHNTeW5jKGdldEFic29sdXRlUGF0aChsb2dnaW5nLmRlc3QpKSAmJlxyXG4gICAgICBta2RpclN5bmMoZ2V0QWJzb2x1dGVQYXRoKGxvZ2dpbmcuZGVzdCkpO1xyXG5cclxuICAgIC8vIENyZWF0ZSB0aGUgZnVsbCBwYXRoXHJcbiAgICBsb2dnaW5nLnBhdGhUb0xvZyA9IGdldEFic29sdXRlUGF0aChqb2luKGxvZ2dpbmcuZGVzdCwgbG9nZ2luZy5maWxlKSk7XHJcblxyXG4gICAgLy8gV2Ugbm93IGFzc3VtZSB0aGUgcGF0aCBpcyBhdmFpbGFibGUsIGUuZy4gaXQncyB0aGUgcmVzcG9uc2liaWxpdHlcclxuICAgIC8vIG9mIHRoZSB1c2VyIHRvIGNyZWF0ZSB0aGUgcGF0aCB3aXRoIHRoZSBjb3JyZWN0IGFjY2VzcyByaWdodHMuXHJcbiAgICBsb2dnaW5nLnBhdGhDcmVhdGVkID0gdHJ1ZTtcclxuICB9XHJcblxyXG4gIC8vIEFkZCB0aGUgY29udGVudCB0byBhIGZpbGVcclxuICBhcHBlbmRGaWxlKFxyXG4gICAgbG9nZ2luZy5wYXRoVG9Mb2csXHJcbiAgICBbcHJlZml4XS5jb25jYXQodGV4dHMpLmpvaW4oJyAnKSArICdcXG4nLFxyXG4gICAgKGVycm9yKSA9PiB7XHJcbiAgICAgIGlmIChlcnJvciAmJiBsb2dnaW5nLnRvRmlsZSAmJiBsb2dnaW5nLnBhdGhDcmVhdGVkKSB7XHJcbiAgICAgICAgbG9nZ2luZy50b0ZpbGUgPSBmYWxzZTtcclxuICAgICAgICBsb2dnaW5nLnBhdGhDcmVhdGVkID0gZmFsc2U7XHJcbiAgICAgICAgbG9nV2l0aFN0YWNrKDIsIGVycm9yLCBgW2xvZ2dlcl0gVW5hYmxlIHRvIHdyaXRlIHRvIGxvZyBmaWxlLmApO1xyXG4gICAgICB9XHJcbiAgICB9XHJcbiAgKTtcclxufVxyXG5cclxuZXhwb3J0IGRlZmF1bHQge1xyXG4gIGxvZyxcclxuICBsb2dXaXRoU3RhY2ssXHJcbiAgbG9nWm9kSXNzdWVzLFxyXG4gIGluaXRMb2dnaW5nLFxyXG4gIHNldExvZ0xldmVsLFxyXG4gIGVuYWJsZUNvbnNvbGVMb2dnaW5nLFxyXG4gIGVuYWJsZUZpbGVMb2dnaW5nXHJcbn07XHJcbiIsIi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXHJcblxyXG5IaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXJcclxuXHJcbkNvcHlyaWdodCAoYykgMjAxNi0yMDI1LCBIaWdoc29mdFxyXG5cclxuTGljZW5jZWQgdW5kZXIgdGhlIE1JVCBsaWNlbmNlLlxyXG5cclxuQWRkaXRpb25hbGx5IGEgdmFsaWQgSGlnaGNoYXJ0cyBsaWNlbnNlIGlzIHJlcXVpcmVkIGZvciB1c2UuXHJcblxyXG5TZWUgTElDRU5TRSBmaWxlIGluIHJvb3QgZm9yIGRldGFpbHMuXHJcblxyXG4qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xyXG5cclxuLyoqXHJcbiAqIEBvdmVydmlldyBDb25maWd1cmF0aW9uIG1hbmFnZW1lbnQgbW9kdWxlIGZvciB0aGUgSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyLlxyXG4gKiBQcm92aWRlcyBkZWZhdWx0IGNvbmZpZ3VyYXRpb25zIHRoYXQgc3VwcG9ydCBlbnZpcm9ubWVudCB2YXJpYWJsZXMsIENMSVxyXG4gKiBhcmd1bWVudHMsIGFuZCBpbnRlcmFjdGl2ZSBwcm9tcHRzIGZvciBjdXN0b21pemF0aW9uIG9mIG9wdGlvbnMgYW5kIGZlYXR1cmVzLlxyXG4gKiBBZGRpdGlvbmFsbHksIGl0IG1hcHMgbGVnYWN5IG9wdGlvbnMgdG8gbW9kZXJuIHN0cnVjdHVyZXMsIGdlbmVyYXRlcyBuZXN0ZWRcclxuICogYXJndW1lbnQgbWFwcGluZ3MsIGFuZCBkaXNwbGF5cyBDTEkgdXNhZ2UgaW5mb3JtYXRpb24uXHJcbiAqL1xyXG5cclxuLyoqXHJcbiAqIFRoZSBjb25maWd1cmF0aW9uIG9iamVjdCBjb250YWluaW5nIGFsbCBhdmFpbGFibGUgb3B0aW9ucywgb3JnYW5pemVkXHJcbiAqIGJ5IHNlY3Rpb25zLlxyXG4gKlxyXG4gKiBUaGlzIG9iamVjdCBpbmNsdWRlczpcclxuICogLSBEZWZhdWx0IHZhbHVlcyBmb3IgZWFjaCBvcHRpb25cclxuICogLSBEYXRhIHR5cGVzIGZvciB2YWxpZGF0aW9uXHJcbiAqIC0gTmFtZXMgb2YgY29ycmVzcG9uZGluZyBlbnZpcm9ubWVudCB2YXJpYWJsZXNcclxuICogLSBEZXNjcmlwdGlvbnMgb2YgZWFjaCBwcm9wZXJ0eVxyXG4gKiAtIEluZm9ybWF0aW9uIHVzZWQgZm9yIHByb21wdHMgaW4gaW50ZXJhY3RpdmUgY29uZmlndXJhdGlvblxyXG4gKiAtIFtPcHRpb25hbF0gQ29ycmVzcG9uZGluZyBDTEkgYXJndW1lbnQgbmFtZXMgZm9yIENMSSB1c2FnZVxyXG4gKiAtIFtPcHRpb25hbF0gTGVnYWN5IG5hbWVzIGZyb20gdGhlIHByZXZpb3VzIFBoYW50b21KUy1iYXNlZCBzZXJ2ZXJcclxuICovXHJcbmV4cG9ydCBjb25zdCBkZWZhdWx0Q29uZmlnID0ge1xyXG4gIHB1cHBldGVlcjoge1xyXG4gICAgYXJnczoge1xyXG4gICAgICB2YWx1ZTogW1xyXG4gICAgICAgICctLWFsbG93LXJ1bm5pbmctaW5zZWN1cmUtY29udGVudCcsXHJcbiAgICAgICAgJy0tYXNoLW5vLW51ZGdlcycsXHJcbiAgICAgICAgJy0tYXV0b3BsYXktcG9saWN5PXVzZXItZ2VzdHVyZS1yZXF1aXJlZCcsXHJcbiAgICAgICAgJy0tYmxvY2stbmV3LXdlYi1jb250ZW50cycsXHJcbiAgICAgICAgJy0tZGlzYWJsZS1hY2NlbGVyYXRlZC0yZC1jYW52YXMnLFxyXG4gICAgICAgICctLWRpc2FibGUtYmFja2dyb3VuZC1uZXR3b3JraW5nJyxcclxuICAgICAgICAnLS1kaXNhYmxlLWJhY2tncm91bmQtdGltZXItdGhyb3R0bGluZycsXHJcbiAgICAgICAgJy0tZGlzYWJsZS1iYWNrZ3JvdW5kaW5nLW9jY2x1ZGVkLXdpbmRvd3MnLFxyXG4gICAgICAgICctLWRpc2FibGUtYnJlYWtwYWQnLFxyXG4gICAgICAgICctLWRpc2FibGUtY2hlY2tlci1pbWFnaW5nJyxcclxuICAgICAgICAnLS1kaXNhYmxlLWNsaWVudC1zaWRlLXBoaXNoaW5nLWRldGVjdGlvbicsXHJcbiAgICAgICAgJy0tZGlzYWJsZS1jb21wb25lbnQtZXh0ZW5zaW9ucy13aXRoLWJhY2tncm91bmQtcGFnZXMnLFxyXG4gICAgICAgICctLWRpc2FibGUtY29tcG9uZW50LXVwZGF0ZScsXHJcbiAgICAgICAgJy0tZGlzYWJsZS1kZWZhdWx0LWFwcHMnLFxyXG4gICAgICAgICctLWRpc2FibGUtZGV2LXNobS11c2FnZScsXHJcbiAgICAgICAgJy0tZGlzYWJsZS1kb21haW4tcmVsaWFiaWxpdHknLFxyXG4gICAgICAgICctLWRpc2FibGUtZXh0ZW5zaW9ucycsXHJcbiAgICAgICAgJy0tZGlzYWJsZS1mZWF0dXJlcz1DYWxjdWxhdGVOYXRpdmVXaW5PY2NsdXNpb24sSW50ZXJlc3RGZWVkQ29udGVudFN1Z2dlc3Rpb25zLFdlYk9UUCcsXHJcbiAgICAgICAgJy0tZGlzYWJsZS1oYW5nLW1vbml0b3InLFxyXG4gICAgICAgICctLWRpc2FibGUtaXBjLWZsb29kaW5nLXByb3RlY3Rpb24nLFxyXG4gICAgICAgICctLWRpc2FibGUtbG9nZ2luZycsXHJcbiAgICAgICAgJy0tZGlzYWJsZS1ub3RpZmljYXRpb25zJyxcclxuICAgICAgICAnLS1kaXNhYmxlLW9mZmVyLXN0b3JlLXVubWFza2VkLXdhbGxldC1jYXJkcycsXHJcbiAgICAgICAgJy0tZGlzYWJsZS1wb3B1cC1ibG9ja2luZycsXHJcbiAgICAgICAgJy0tZGlzYWJsZS1wcmludC1wcmV2aWV3JyxcclxuICAgICAgICAnLS1kaXNhYmxlLXByb21wdC1vbi1yZXBvc3QnLFxyXG4gICAgICAgICctLWRpc2FibGUtcmVuZGVyZXItYmFja2dyb3VuZGluZycsXHJcbiAgICAgICAgJy0tZGlzYWJsZS1zZWFyY2gtZW5naW5lLWNob2ljZS1zY3JlZW4nLFxyXG4gICAgICAgICctLWRpc2FibGUtc2Vzc2lvbi1jcmFzaGVkLWJ1YmJsZScsXHJcbiAgICAgICAgJy0tZGlzYWJsZS1zZXR1aWQtc2FuZGJveCcsXHJcbiAgICAgICAgJy0tZGlzYWJsZS1zaXRlLWlzb2xhdGlvbi10cmlhbHMnLFxyXG4gICAgICAgICctLWRpc2FibGUtc3BlZWNoLWFwaScsXHJcbiAgICAgICAgJy0tZGlzYWJsZS1zeW5jJyxcclxuICAgICAgICAnLS1lbmFibGUtdW5zYWZlLXdlYmdwdScsXHJcbiAgICAgICAgJy0taGlkZS1jcmFzaC1yZXN0b3JlLWJ1YmJsZScsXHJcbiAgICAgICAgJy0taGlkZS1zY3JvbGxiYXJzJyxcclxuICAgICAgICAnLS1tZXRyaWNzLXJlY29yZGluZy1vbmx5JyxcclxuICAgICAgICAnLS1tdXRlLWF1ZGlvJyxcclxuICAgICAgICAnLS1uby1kZWZhdWx0LWJyb3dzZXItY2hlY2snLFxyXG4gICAgICAgICctLW5vLWZpcnN0LXJ1bicsXHJcbiAgICAgICAgJy0tbm8tcGluZ3MnLFxyXG4gICAgICAgICctLW5vLXNhbmRib3gnLFxyXG4gICAgICAgICctLW5vLXN0YXJ0dXAtd2luZG93JyxcclxuICAgICAgICAnLS1uby16eWdvdGUnLFxyXG4gICAgICAgICctLXBhc3N3b3JkLXN0b3JlPWJhc2ljJyxcclxuICAgICAgICAnLS1wcm9jZXNzLXBlci10YWInLFxyXG4gICAgICAgICctLXVzZS1tb2NrLWtleWNoYWluJ1xyXG4gICAgICBdLFxyXG4gICAgICB0eXBlczogWydzdHJpbmdbXSddLFxyXG4gICAgICBlbnZMaW5rOiAnUFVQUEVURUVSX0FSR1MnLFxyXG4gICAgICBjbGlOYW1lOiAncHVwcGV0ZWVyQXJncycsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnQXJyYXkgb2YgUHVwcGV0ZWVyIGFyZ3VtZW50cycsXHJcbiAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICB0eXBlOiAnbGlzdCcsXHJcbiAgICAgICAgc2VwYXJhdG9yOiAnOydcclxuICAgICAgfVxyXG4gICAgfVxyXG4gIH0sXHJcbiAgaGlnaGNoYXJ0czoge1xyXG4gICAgdmVyc2lvbjoge1xyXG4gICAgICB2YWx1ZTogJ2xhdGVzdCcsXHJcbiAgICAgIHR5cGVzOiBbJ3N0cmluZyddLFxyXG4gICAgICBlbnZMaW5rOiAnSElHSENIQVJUU19WRVJTSU9OJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdIaWdoY2hhcnRzIHZlcnNpb24nLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ3RleHQnXHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICBjZG5Vcmw6IHtcclxuICAgICAgdmFsdWU6ICdodHRwczovL2NvZGUuaGlnaGNoYXJ0cy5jb20nLFxyXG4gICAgICB0eXBlczogWydzdHJpbmcnXSxcclxuICAgICAgZW52TGluazogJ0hJR0hDSEFSVFNfQ0ROX1VSTCcsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnQ0ROIFVSTCBmb3IgSGlnaGNoYXJ0cyBzY3JpcHRzJyxcclxuICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgIHR5cGU6ICd0ZXh0J1xyXG4gICAgICB9XHJcbiAgICB9LFxyXG4gICAgZm9yY2VGZXRjaDoge1xyXG4gICAgICB2YWx1ZTogZmFsc2UsXHJcbiAgICAgIHR5cGVzOiBbJ2Jvb2xlYW4nXSxcclxuICAgICAgZW52TGluazogJ0hJR0hDSEFSVFNfRk9SQ0VfRkVUQ0gnLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ0ZsYWcgdG8gcmVmZXRjaCBzY3JpcHRzIGFmdGVyIGVhY2ggc2VydmVyIHJlcnVuJyxcclxuICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgIHR5cGU6ICd0b2dnbGUnXHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICBjYWNoZVBhdGg6IHtcclxuICAgICAgdmFsdWU6ICcuY2FjaGUnLFxyXG4gICAgICB0eXBlczogWydzdHJpbmcnXSxcclxuICAgICAgZW52TGluazogJ0hJR0hDSEFSVFNfQ0FDSEVfUEFUSCcsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnRGlyZWN0b3J5IHBhdGggZm9yIGNhY2hlZCBIaWdoY2hhcnRzIHNjcmlwdHMnLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ3RleHQnXHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICBjb3JlU2NyaXB0czoge1xyXG4gICAgICB2YWx1ZTogWydoaWdoY2hhcnRzJywgJ2hpZ2hjaGFydHMtbW9yZScsICdoaWdoY2hhcnRzLTNkJ10sXHJcbiAgICAgIHR5cGVzOiBbJ3N0cmluZ1tdJ10sXHJcbiAgICAgIGVudkxpbms6ICdISUdIQ0hBUlRTX0NPUkVfU0NSSVBUUycsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnSGlnaGNoYXJ0cyBjb3JlIHNjcmlwdHMgdG8gZmV0Y2gnLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ211bHRpc2VsZWN0JyxcclxuICAgICAgICBpbnN0cnVjdGlvbnM6ICdTcGFjZTogU2VsZWN0IHNwZWNpZmljLCBBOiBTZWxlY3QgYWxsLCBFbnRlcjogQ29uZmlybSdcclxuICAgICAgfVxyXG4gICAgfSxcclxuICAgIG1vZHVsZVNjcmlwdHM6IHtcclxuICAgICAgdmFsdWU6IFtcclxuICAgICAgICAnc3RvY2snLFxyXG4gICAgICAgICdtYXAnLFxyXG4gICAgICAgICdnYW50dCcsXHJcbiAgICAgICAgJ2V4cG9ydGluZycsXHJcbiAgICAgICAgJ3BhcmFsbGVsLWNvb3JkaW5hdGVzJyxcclxuICAgICAgICAnYWNjZXNzaWJpbGl0eScsXHJcbiAgICAgICAgLy8gJ2Fubm90YXRpb25zLWFkdmFuY2VkJyxcclxuICAgICAgICAnYm9vc3QtY2FudmFzJyxcclxuICAgICAgICAnYm9vc3QnLFxyXG4gICAgICAgICdkYXRhJyxcclxuICAgICAgICAnZGF0YS10b29scycsXHJcbiAgICAgICAgJ2RyYWdnYWJsZS1wb2ludHMnLFxyXG4gICAgICAgICdzdGF0aWMtc2NhbGUnLFxyXG4gICAgICAgICdicm9rZW4tYXhpcycsXHJcbiAgICAgICAgJ2hlYXRtYXAnLFxyXG4gICAgICAgICd0aWxlbWFwJyxcclxuICAgICAgICAndGlsZWR3ZWJtYXAnLFxyXG4gICAgICAgICd0aW1lbGluZScsXHJcbiAgICAgICAgJ3RyZWVtYXAnLFxyXG4gICAgICAgICd0cmVlZ3JhcGgnLFxyXG4gICAgICAgICdpdGVtLXNlcmllcycsXHJcbiAgICAgICAgJ2RyaWxsZG93bicsXHJcbiAgICAgICAgJ2hpc3RvZ3JhbS1iZWxsY3VydmUnLFxyXG4gICAgICAgICdidWxsZXQnLFxyXG4gICAgICAgICdmdW5uZWwnLFxyXG4gICAgICAgICdmdW5uZWwzZCcsXHJcbiAgICAgICAgJ2dlb2hlYXRtYXAnLFxyXG4gICAgICAgICdweXJhbWlkM2QnLFxyXG4gICAgICAgICduZXR3b3JrZ3JhcGgnLFxyXG4gICAgICAgICdvdmVybGFwcGluZy1kYXRhbGFiZWxzJyxcclxuICAgICAgICAncGFyZXRvJyxcclxuICAgICAgICAncGF0dGVybi1maWxsJyxcclxuICAgICAgICAncGljdG9yaWFsJyxcclxuICAgICAgICAncHJpY2UtaW5kaWNhdG9yJyxcclxuICAgICAgICAnc2Fua2V5JyxcclxuICAgICAgICAnYXJjLWRpYWdyYW0nLFxyXG4gICAgICAgICdkZXBlbmRlbmN5LXdoZWVsJyxcclxuICAgICAgICAnc2VyaWVzLWxhYmVsJyxcclxuICAgICAgICAnc2VyaWVzLW9uLXBvaW50JyxcclxuICAgICAgICAnc29saWQtZ2F1Z2UnLFxyXG4gICAgICAgICdzb25pZmljYXRpb24nLFxyXG4gICAgICAgIC8vICdzdG9jay10b29scycsXHJcbiAgICAgICAgJ3N0cmVhbWdyYXBoJyxcclxuICAgICAgICAnc3VuYnVyc3QnLFxyXG4gICAgICAgICd2YXJpYWJsZS1waWUnLFxyXG4gICAgICAgICd2YXJpd2lkZScsXHJcbiAgICAgICAgJ3ZlY3RvcicsXHJcbiAgICAgICAgJ3Zlbm4nLFxyXG4gICAgICAgICd3aW5kYmFyYicsXHJcbiAgICAgICAgJ3dvcmRjbG91ZCcsXHJcbiAgICAgICAgJ3hyYW5nZScsXHJcbiAgICAgICAgJ25vLWRhdGEtdG8tZGlzcGxheScsXHJcbiAgICAgICAgJ2RyYWctcGFuZXMnLFxyXG4gICAgICAgICdkZWJ1Z2dlcicsXHJcbiAgICAgICAgJ2R1bWJiZWxsJyxcclxuICAgICAgICAnbG9sbGlwb3AnLFxyXG4gICAgICAgICdjeWxpbmRlcicsXHJcbiAgICAgICAgJ29yZ2FuaXphdGlvbicsXHJcbiAgICAgICAgJ2RvdHBsb3QnLFxyXG4gICAgICAgICdtYXJrZXItY2x1c3RlcnMnLFxyXG4gICAgICAgICdob2xsb3djYW5kbGVzdGljaycsXHJcbiAgICAgICAgJ2hlaWtpbmFzaGknLFxyXG4gICAgICAgICdmbG93bWFwJyxcclxuICAgICAgICAnZXhwb3J0LWRhdGEnLFxyXG4gICAgICAgICduYXZpZ2F0b3InLFxyXG4gICAgICAgICd0ZXh0cGF0aCdcclxuICAgICAgXSxcclxuICAgICAgdHlwZXM6IFsnc3RyaW5nW10nXSxcclxuICAgICAgZW52TGluazogJ0hJR0hDSEFSVFNfTU9EVUxFX1NDUklQVFMnLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ0hpZ2hjaGFydHMgbW9kdWxlIHNjcmlwdHMgdG8gZmV0Y2gnLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ211bHRpc2VsZWN0JyxcclxuICAgICAgICBpbnN0cnVjdGlvbnM6ICdTcGFjZTogU2VsZWN0IHNwZWNpZmljLCBBOiBTZWxlY3QgYWxsLCBFbnRlcjogQ29uZmlybSdcclxuICAgICAgfVxyXG4gICAgfSxcclxuICAgIGluZGljYXRvclNjcmlwdHM6IHtcclxuICAgICAgdmFsdWU6IFsnaW5kaWNhdG9ycy1hbGwnXSxcclxuICAgICAgdHlwZXM6IFsnc3RyaW5nW10nXSxcclxuICAgICAgZW52TGluazogJ0hJR0hDSEFSVFNfSU5ESUNBVE9SX1NDUklQVFMnLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ0hpZ2hjaGFydHMgaW5kaWNhdG9yIHNjcmlwdHMgdG8gZmV0Y2gnLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ211bHRpc2VsZWN0JyxcclxuICAgICAgICBpbnN0cnVjdGlvbnM6ICdTcGFjZTogU2VsZWN0IHNwZWNpZmljLCBBOiBTZWxlY3QgYWxsLCBFbnRlcjogQ29uZmlybSdcclxuICAgICAgfVxyXG4gICAgfSxcclxuICAgIGN1c3RvbVNjcmlwdHM6IHtcclxuICAgICAgdmFsdWU6IFtcclxuICAgICAgICAnaHR0cHM6Ly9jZG5qcy5jbG91ZGZsYXJlLmNvbS9hamF4L2xpYnMvbW9tZW50LmpzLzIuMzAuMS9tb21lbnQubWluLmpzJyxcclxuICAgICAgICAnaHR0cHM6Ly9jZG5qcy5jbG91ZGZsYXJlLmNvbS9hamF4L2xpYnMvbW9tZW50LXRpbWV6b25lLzAuNS40NS9tb21lbnQtdGltZXpvbmUtd2l0aC1kYXRhLm1pbi5qcydcclxuICAgICAgXSxcclxuICAgICAgdHlwZXM6IFsnc3RyaW5nW10nXSxcclxuICAgICAgZW52TGluazogJ0hJR0hDSEFSVFNfQ1VTVE9NX1NDUklQVFMnLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ0FkZGl0aW9uYWwgY3VzdG9tIHNjcmlwdHMgb3IgZGVwZW5kZW5jaWVzIHRvIGZldGNoJyxcclxuICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgIHR5cGU6ICdsaXN0JyxcclxuICAgICAgICBzZXBhcmF0b3I6ICc7J1xyXG4gICAgICB9XHJcbiAgICB9XHJcbiAgfSxcclxuICBleHBvcnQ6IHtcclxuICAgIGluZmlsZToge1xyXG4gICAgICB2YWx1ZTogbnVsbCxcclxuICAgICAgdHlwZXM6IFsnc3RyaW5nJywgJ251bGwnXSxcclxuICAgICAgZW52TGluazogJ0VYUE9SVF9JTkZJTEUnLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnSW5wdXQgZmlsZW5hbWUgd2l0aCB0eXBlLCBmb3JtYXR0ZWQgY29ycmVjdGx5IGFzIEpTT04gb3IgU1ZHJyxcclxuICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgIHR5cGU6ICd0ZXh0J1xyXG4gICAgICB9XHJcbiAgICB9LFxyXG4gICAgaW5zdHI6IHtcclxuICAgICAgdmFsdWU6IG51bGwsXHJcbiAgICAgIHR5cGVzOiBbJ09iamVjdCcsICdzdHJpbmcnLCAnbnVsbCddLFxyXG4gICAgICBlbnZMaW5rOiAnRVhQT1JUX0lOU1RSJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ092ZXJyaWRlcyB0aGUgYGluZmlsZWAgd2l0aCBKU09OLCBzdHJpbmdpZmllZCBKU09OLCBvciBTVkcgaW5wdXQnLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ3RleHQnXHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICBvcHRpb25zOiB7XHJcbiAgICAgIHZhbHVlOiBudWxsLFxyXG4gICAgICB0eXBlczogWydPYmplY3QnLCAnc3RyaW5nJywgJ251bGwnXSxcclxuICAgICAgZW52TGluazogJ0VYUE9SVF9PUFRJT05TJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdBbGlhcyBmb3IgdGhlIGBpbnN0cmAgb3B0aW9uJyxcclxuICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgIHR5cGU6ICd0ZXh0J1xyXG4gICAgICB9XHJcbiAgICB9LFxyXG4gICAgc3ZnOiB7XHJcbiAgICAgIHZhbHVlOiBudWxsLFxyXG4gICAgICB0eXBlczogWydzdHJpbmcnLCAnbnVsbCddLFxyXG4gICAgICBlbnZMaW5rOiAnRVhQT1JUX1NWRycsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnU1ZHIHN0cmluZyByZXByZXNlbnRhdGlvbiBvZiB0aGUgY2hhcnQgdG8gcmVuZGVyJyxcclxuICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgIHR5cGU6ICd0ZXh0J1xyXG4gICAgICB9XHJcbiAgICB9LFxyXG4gICAgYmF0Y2g6IHtcclxuICAgICAgdmFsdWU6IG51bGwsXHJcbiAgICAgIHR5cGVzOiBbJ3N0cmluZycsICdudWxsJ10sXHJcbiAgICAgIGVudkxpbms6ICdFWFBPUlRfQkFUQ0gnLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnQmF0Y2ggam9iIHN0cmluZyB3aXRoIGlucHV0L291dHB1dCBwYWlyczogXCJpbj1vdXQ7aW49b3V0Oy4uLlwiJyxcclxuICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgIHR5cGU6ICd0ZXh0J1xyXG4gICAgICB9XHJcbiAgICB9LFxyXG4gICAgb3V0ZmlsZToge1xyXG4gICAgICB2YWx1ZTogbnVsbCxcclxuICAgICAgdHlwZXM6IFsnc3RyaW5nJywgJ251bGwnXSxcclxuICAgICAgZW52TGluazogJ0VYUE9SVF9PVVRGSUxFJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ091dHB1dCBmaWxlbmFtZSB3aXRoIHR5cGUuIENhbiBiZSBqcGVnLCBwbmcsIHBkZiwgb3Igc3ZnIGFuZCBpZ25vcmVzIGB0eXBlYCBvcHRpb24nLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ3RleHQnXHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICB0eXBlOiB7XHJcbiAgICAgIHZhbHVlOiAncG5nJyxcclxuICAgICAgdHlwZXM6IFsnc3RyaW5nJ10sXHJcbiAgICAgIGVudkxpbms6ICdFWFBPUlRfVFlQRScsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnRmlsZSBleHBvcnQgZm9ybWF0LiBDYW4gYmUganBlZywgcG5nLCBwZGYsIG9yIHN2ZycsXHJcbiAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICB0eXBlOiAnc2VsZWN0JyxcclxuICAgICAgICBoaW50OiAnRGVmYXVsdDogcG5nJyxcclxuICAgICAgICBjaG9pY2VzOiBbJ3BuZycsICdqcGVnJywgJ3BkZicsICdzdmcnXVxyXG4gICAgICB9XHJcbiAgICB9LFxyXG4gICAgY29uc3RyOiB7XHJcbiAgICAgIHZhbHVlOiAnY2hhcnQnLFxyXG4gICAgICB0eXBlczogWydzdHJpbmcnXSxcclxuICAgICAgZW52TGluazogJ0VYUE9SVF9DT05TVFInLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnQ2hhcnQgY29uc3RydWN0b3IuIENhbiBiZSBjaGFydCwgc3RvY2tDaGFydCwgbWFwQ2hhcnQsIG9yIGdhbnR0Q2hhcnQnLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ3NlbGVjdCcsXHJcbiAgICAgICAgaGludDogJ0RlZmF1bHQ6IGNoYXJ0JyxcclxuICAgICAgICBjaG9pY2VzOiBbJ2NoYXJ0JywgJ3N0b2NrQ2hhcnQnLCAnbWFwQ2hhcnQnLCAnZ2FudHRDaGFydCddXHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICBiNjQ6IHtcclxuICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICB0eXBlczogWydib29sZWFuJ10sXHJcbiAgICAgIGVudkxpbms6ICdFWFBPUlRfQjY0JyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ1doZXRoZXIgb3Igbm90IHRvIHRoZSBjaGFydCBzaG91bGQgYmUgcmVjZWl2ZWQgaW4gQmFzZTY0IGZvcm1hdCBpbnN0ZWFkIG9mIGJpbmFyeScsXHJcbiAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICB0eXBlOiAndG9nZ2xlJ1xyXG4gICAgICB9XHJcbiAgICB9LFxyXG4gICAgbm9Eb3dubG9hZDoge1xyXG4gICAgICB2YWx1ZTogZmFsc2UsXHJcbiAgICAgIHR5cGVzOiBbJ2Jvb2xlYW4nXSxcclxuICAgICAgZW52TGluazogJ0VYUE9SVF9OT19ET1dOTE9BRCcsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdXaGV0aGVyIG9yIG5vdCB0byBpbmNsdWRlIG9yIGV4Y2x1ZGUgYXR0YWNobWVudCBoZWFkZXJzIGluIHRoZSByZXNwb25zZScsXHJcbiAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICB0eXBlOiAndG9nZ2xlJ1xyXG4gICAgICB9XHJcbiAgICB9LFxyXG4gICAgaGVpZ2h0OiB7XHJcbiAgICAgIHZhbHVlOiBudWxsLFxyXG4gICAgICB0eXBlczogWydudW1iZXInLCAnbnVsbCddLFxyXG4gICAgICBlbnZMaW5rOiAnRVhQT1JUX0hFSUdIVCcsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnSGVpZ2h0IG9mIHRoZSBleHBvcnRlZCBjaGFydCwgb3ZlcnJpZGVzIGNoYXJ0IHNldHRpbmdzJyxcclxuICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgIHR5cGU6ICdudW1iZXInXHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICB3aWR0aDoge1xyXG4gICAgICB2YWx1ZTogbnVsbCxcclxuICAgICAgdHlwZXM6IFsnbnVtYmVyJywgJ251bGwnXSxcclxuICAgICAgZW52TGluazogJ0VYUE9SVF9XSURUSCcsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnV2lkdGggb2YgdGhlIGV4cG9ydGVkIGNoYXJ0LCBvdmVycmlkZXMgY2hhcnQgc2V0dGluZ3MnLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ251bWJlcidcclxuICAgICAgfVxyXG4gICAgfSxcclxuICAgIHNjYWxlOiB7XHJcbiAgICAgIHZhbHVlOiBudWxsLFxyXG4gICAgICB0eXBlczogWydudW1iZXInLCAnbnVsbCddLFxyXG4gICAgICBlbnZMaW5rOiAnRVhQT1JUX1NDQUxFJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ1NjYWxlIG9mIHRoZSBleHBvcnRlZCBjaGFydCwgb3ZlcnJpZGVzIGNoYXJ0IHNldHRpbmdzLiBSYW5nZXMgZnJvbSAwLjEgdG8gNS4wJyxcclxuICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgIHR5cGU6ICdudW1iZXInXHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICBkZWZhdWx0SGVpZ2h0OiB7XHJcbiAgICAgIHZhbHVlOiA0MDAsXHJcbiAgICAgIHR5cGVzOiBbJ251bWJlciddLFxyXG4gICAgICBlbnZMaW5rOiAnRVhQT1JUX0RFRkFVTFRfSEVJR0hUJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdEZWZhdWx0IGhlaWdodCBvZiB0aGUgZXhwb3J0ZWQgY2hhcnQgaWYgbm90IHNldCcsXHJcbiAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICB0eXBlOiAnbnVtYmVyJ1xyXG4gICAgICB9XHJcbiAgICB9LFxyXG4gICAgZGVmYXVsdFdpZHRoOiB7XHJcbiAgICAgIHZhbHVlOiA2MDAsXHJcbiAgICAgIHR5cGVzOiBbJ251bWJlciddLFxyXG4gICAgICBlbnZMaW5rOiAnRVhQT1JUX0RFRkFVTFRfV0lEVEgnLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ0RlZmF1bHQgd2lkdGggb2YgdGhlIGV4cG9ydGVkIGNoYXJ0IGlmIG5vdCBzZXQnLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ251bWJlcidcclxuICAgICAgfVxyXG4gICAgfSxcclxuICAgIGRlZmF1bHRTY2FsZToge1xyXG4gICAgICB2YWx1ZTogMSxcclxuICAgICAgdHlwZXM6IFsnbnVtYmVyJ10sXHJcbiAgICAgIGVudkxpbms6ICdFWFBPUlRfREVGQVVMVF9TQ0FMRScsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdEZWZhdWx0IHNjYWxlIG9mIHRoZSBleHBvcnRlZCBjaGFydCBpZiBub3Qgc2V0LiBSYW5nZXMgZnJvbSAwLjEgdG8gNS4wJyxcclxuICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICAgIG1pbjogMC4xLFxyXG4gICAgICAgIG1heDogNVxyXG4gICAgICB9XHJcbiAgICB9LFxyXG4gICAgZ2xvYmFsT3B0aW9uczoge1xyXG4gICAgICB2YWx1ZTogbnVsbCxcclxuICAgICAgdHlwZXM6IFsnT2JqZWN0JywgJ3N0cmluZycsICdudWxsJ10sXHJcbiAgICAgIGVudkxpbms6ICdFWFBPUlRfR0xPQkFMX09QVElPTlMnLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnSlNPTiwgc3RyaW5naWZpZWQgSlNPTiBvciBmaWxlbmFtZSB3aXRoIGdsb2JhbCBvcHRpb25zIGZvciBIaWdoY2hhcnRzLnNldE9wdGlvbnMnLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ3RleHQnXHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICB0aGVtZU9wdGlvbnM6IHtcclxuICAgICAgdmFsdWU6IG51bGwsXHJcbiAgICAgIHR5cGVzOiBbJ09iamVjdCcsICdzdHJpbmcnLCAnbnVsbCddLFxyXG4gICAgICBlbnZMaW5rOiAnRVhQT1JUX1RIRU1FX09QVElPTlMnLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnSlNPTiwgc3RyaW5naWZpZWQgSlNPTiBvciBmaWxlbmFtZSB3aXRoIHRoZW1lIG9wdGlvbnMgZm9yIEhpZ2hjaGFydHMuc2V0T3B0aW9ucycsXHJcbiAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICB0eXBlOiAndGV4dCdcclxuICAgICAgfVxyXG4gICAgfSxcclxuICAgIHJhc3Rlcml6YXRpb25UaW1lb3V0OiB7XHJcbiAgICAgIHZhbHVlOiAxNTAwLFxyXG4gICAgICB0eXBlczogWydudW1iZXInXSxcclxuICAgICAgZW52TGluazogJ0VYUE9SVF9SQVNURVJJWkFUSU9OX1RJTUVPVVQnLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ01pbGxpc2Vjb25kcyB0byB3YWl0IGZvciB3ZWJwYWdlIHJlbmRlcmluZycsXHJcbiAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICB0eXBlOiAnbnVtYmVyJ1xyXG4gICAgICB9XHJcbiAgICB9XHJcbiAgfSxcclxuICBjdXN0b21Mb2dpYzoge1xyXG4gICAgYWxsb3dDb2RlRXhlY3V0aW9uOiB7XHJcbiAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgdHlwZXM6IFsnYm9vbGVhbiddLFxyXG4gICAgICBlbnZMaW5rOiAnQ1VTVE9NX0xPR0lDX0FMTE9XX0NPREVfRVhFQ1VUSU9OJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ0FsbG93cyBvciBkaXNhbGxvd3MgZXhlY3V0aW9uIG9mIGFyYml0cmFyeSBjb2RlIGR1cmluZyBleHBvcnRpbmcnLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ3RvZ2dsZSdcclxuICAgICAgfVxyXG4gICAgfSxcclxuICAgIGFsbG93RmlsZVJlc291cmNlczoge1xyXG4gICAgICB2YWx1ZTogZmFsc2UsXHJcbiAgICAgIHR5cGVzOiBbJ2Jvb2xlYW4nXSxcclxuICAgICAgZW52TGluazogJ0NVU1RPTV9MT0dJQ19BTExPV19GSUxFX1JFU09VUkNFUycsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdBbGxvd3Mgb3IgZGlzYWxsb3dzIGluamVjdGlvbiBvZiBmaWxlc3lzdGVtIHJlc291cmNlcyAoZGlzYWJsZWQgaW4gc2VydmVyIG1vZGUpJyxcclxuICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgIHR5cGU6ICd0b2dnbGUnXHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICBjdXN0b21Db2RlOiB7XHJcbiAgICAgIHZhbHVlOiBudWxsLFxyXG4gICAgICB0eXBlczogWydzdHJpbmcnLCAnbnVsbCddLFxyXG4gICAgICBlbnZMaW5rOiAnQ1VTVE9NX0xPR0lDX0NVU1RPTV9DT0RFJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ0N1c3RvbSBjb2RlIHRvIGV4ZWN1dGUgYmVmb3JlIGNoYXJ0IGluaXRpYWxpemF0aW9uLiBDYW4gYmUgYSBmdW5jdGlvbiwgY29kZSB3cmFwcGVkIGluIGEgZnVuY3Rpb24sIG9yIGEgLmpzIGZpbGVuYW1lJyxcclxuICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgIHR5cGU6ICd0ZXh0J1xyXG4gICAgICB9XHJcbiAgICB9LFxyXG4gICAgY2FsbGJhY2s6IHtcclxuICAgICAgdmFsdWU6IG51bGwsXHJcbiAgICAgIHR5cGVzOiBbJ3N0cmluZycsICdudWxsJ10sXHJcbiAgICAgIGVudkxpbms6ICdDVVNUT01fTE9HSUNfQ0FMTEJBQ0snLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnSmF2YVNjcmlwdCBjb2RlIHRvIHJ1biBkdXJpbmcgY29uc3RydWN0aW9uLiBDYW4gYmUgYSBmdW5jdGlvbiBvciBhIC5qcyBmaWxlbmFtZScsXHJcbiAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICB0eXBlOiAndGV4dCdcclxuICAgICAgfVxyXG4gICAgfSxcclxuICAgIHJlc291cmNlczoge1xyXG4gICAgICB2YWx1ZTogbnVsbCxcclxuICAgICAgdHlwZXM6IFsnT2JqZWN0JywgJ3N0cmluZycsICdudWxsJ10sXHJcbiAgICAgIGVudkxpbms6ICdDVVNUT01fTE9HSUNfUkVTT1VSQ0VTJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ0FkZGl0aW9uYWwgcmVzb3VyY2VzIGFzIEpTT04sIHN0cmluZ2lmaWVkIEpTT04sIG9yIGZpbGVuYW1lLCBjb250YWluaW5nIGZpbGVzLCBqcywgYW5kIGNzcyBzZWN0aW9ucycsXHJcbiAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICB0eXBlOiAndGV4dCdcclxuICAgICAgfVxyXG4gICAgfSxcclxuICAgIGxvYWRDb25maWc6IHtcclxuICAgICAgdmFsdWU6IG51bGwsXHJcbiAgICAgIHR5cGVzOiBbJ3N0cmluZycsICdudWxsJ10sXHJcbiAgICAgIGVudkxpbms6ICdDVVNUT01fTE9HSUNfTE9BRF9DT05GSUcnLFxyXG4gICAgICBsZWdhY3lOYW1lOiAnZnJvbUZpbGUnLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ0ZpbGUgd2l0aCBhIHByZS1kZWZpbmVkIGNvbmZpZ3VyYXRpb24gdG8gdXNlJyxcclxuICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgIHR5cGU6ICd0ZXh0J1xyXG4gICAgICB9XHJcbiAgICB9LFxyXG4gICAgY3JlYXRlQ29uZmlnOiB7XHJcbiAgICAgIHZhbHVlOiBudWxsLFxyXG4gICAgICB0eXBlczogWydzdHJpbmcnLCAnbnVsbCddLFxyXG4gICAgICBlbnZMaW5rOiAnQ1VTVE9NX0xPR0lDX0NSRUFURV9DT05GSUcnLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnUHJvbXB0LWJhc2VkIG9wdGlvbiBzZXR0aW5nLCBzYXZlZCB0byBhIHByb3ZpZGVkIGNvbmZpZyBmaWxlJyxcclxuICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgIHR5cGU6ICd0ZXh0J1xyXG4gICAgICB9XHJcbiAgICB9XHJcbiAgfSxcclxuICBzZXJ2ZXI6IHtcclxuICAgIGVuYWJsZToge1xyXG4gICAgICB2YWx1ZTogZmFsc2UsXHJcbiAgICAgIHR5cGVzOiBbJ2Jvb2xlYW4nXSxcclxuICAgICAgZW52TGluazogJ1NFUlZFUl9FTkFCTEUnLFxyXG4gICAgICBjbGlOYW1lOiAnZW5hYmxlU2VydmVyJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdTdGFydHMgdGhlIHNlcnZlciB3aGVuIHRydWUnLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ3RvZ2dsZSdcclxuICAgICAgfVxyXG4gICAgfSxcclxuICAgIGhvc3Q6IHtcclxuICAgICAgdmFsdWU6ICcwLjAuMC4wJyxcclxuICAgICAgdHlwZXM6IFsnc3RyaW5nJ10sXHJcbiAgICAgIGVudkxpbms6ICdTRVJWRVJfSE9TVCcsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnSG9zdG5hbWUgb2YgdGhlIHNlcnZlcicsXHJcbiAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICB0eXBlOiAndGV4dCdcclxuICAgICAgfVxyXG4gICAgfSxcclxuICAgIHBvcnQ6IHtcclxuICAgICAgdmFsdWU6IDc4MDEsXHJcbiAgICAgIHR5cGVzOiBbJ251bWJlciddLFxyXG4gICAgICBlbnZMaW5rOiAnU0VSVkVSX1BPUlQnLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ1BvcnQgbnVtYmVyIGZvciB0aGUgc2VydmVyJyxcclxuICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgIHR5cGU6ICdudW1iZXInXHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICB1cGxvYWRMaW1pdDoge1xyXG4gICAgICB2YWx1ZTogMyxcclxuICAgICAgdHlwZXM6IFsnbnVtYmVyJ10sXHJcbiAgICAgIGVudkxpbms6ICdTRVJWRVJfVVBMT0FEX0xJTUlUJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdNYXhpbXVtIHJlcXVlc3QgYm9keSBzaXplIGluIE1CJyxcclxuICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgIHR5cGU6ICdudW1iZXInXHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICBiZW5jaG1hcmtpbmc6IHtcclxuICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICB0eXBlczogWydib29sZWFuJ10sXHJcbiAgICAgIGVudkxpbms6ICdTRVJWRVJfQkVOQ0hNQVJLSU5HJyxcclxuICAgICAgY2xpTmFtZTogJ3NlcnZlckJlbmNobWFya2luZycsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdEaXNwbGF5cyBvciBub3QgYWN0aW9uIGR1cmF0aW9ucyBpbiBtaWxsaXNlY29uZHMgZHVyaW5nIHNlcnZlciByZXF1ZXN0cycsXHJcbiAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICB0eXBlOiAndG9nZ2xlJ1xyXG4gICAgICB9XHJcbiAgICB9LFxyXG4gICAgcHJveHk6IHtcclxuICAgICAgaG9zdDoge1xyXG4gICAgICAgIHZhbHVlOiBudWxsLFxyXG4gICAgICAgIHR5cGVzOiBbJ3N0cmluZycsICdudWxsJ10sXHJcbiAgICAgICAgZW52TGluazogJ1NFUlZFUl9QUk9YWV9IT1NUJyxcclxuICAgICAgICBjbGlOYW1lOiAncHJveHlIb3N0JyxcclxuICAgICAgICBkZXNjcmlwdGlvbjogJ0hvc3Qgb2YgdGhlIHByb3h5IHNlcnZlciwgaWYgYXBwbGljYWJsZScsXHJcbiAgICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgICAgdHlwZTogJ3RleHQnXHJcbiAgICAgICAgfVxyXG4gICAgICB9LFxyXG4gICAgICBwb3J0OiB7XHJcbiAgICAgICAgdmFsdWU6IG51bGwsXHJcbiAgICAgICAgdHlwZXM6IFsnbnVtYmVyJywgJ251bGwnXSxcclxuICAgICAgICBlbnZMaW5rOiAnU0VSVkVSX1BST1hZX1BPUlQnLFxyXG4gICAgICAgIGNsaU5hbWU6ICdwcm94eVBvcnQnLFxyXG4gICAgICAgIGRlc2NyaXB0aW9uOiAnUG9ydCBvZiB0aGUgcHJveHkgc2VydmVyLCBpZiBhcHBsaWNhYmxlJyxcclxuICAgICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgICB0eXBlOiAnbnVtYmVyJ1xyXG4gICAgICAgIH1cclxuICAgICAgfSxcclxuICAgICAgdGltZW91dDoge1xyXG4gICAgICAgIHZhbHVlOiA1MDAwLFxyXG4gICAgICAgIHR5cGVzOiBbJ251bWJlciddLFxyXG4gICAgICAgIGVudkxpbms6ICdTRVJWRVJfUFJPWFlfVElNRU9VVCcsXHJcbiAgICAgICAgY2xpTmFtZTogJ3Byb3h5VGltZW91dCcsXHJcbiAgICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgICAnVGltZW91dCBpbiBtaWxsaXNlY29uZHMgZm9yIHRoZSBwcm94eSBzZXJ2ZXIsIGlmIGFwcGxpY2FibGUnLFxyXG4gICAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICAgIHR5cGU6ICdudW1iZXInXHJcbiAgICAgICAgfVxyXG4gICAgICB9XHJcbiAgICB9LFxyXG4gICAgcmF0ZUxpbWl0aW5nOiB7XHJcbiAgICAgIGVuYWJsZToge1xyXG4gICAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgICB0eXBlczogWydib29sZWFuJ10sXHJcbiAgICAgICAgZW52TGluazogJ1NFUlZFUl9SQVRFX0xJTUlUSU5HX0VOQUJMRScsXHJcbiAgICAgICAgY2xpTmFtZTogJ2VuYWJsZVJhdGVMaW1pdGluZycsXHJcbiAgICAgICAgZGVzY3JpcHRpb246ICdFbmFibGVzIG9yIGRpc2FibGVzIHJhdGUgbGltaXRpbmcgb24gdGhlIHNlcnZlcicsXHJcbiAgICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgICAgdHlwZTogJ3RvZ2dsZSdcclxuICAgICAgICB9XHJcbiAgICAgIH0sXHJcbiAgICAgIG1heFJlcXVlc3RzOiB7XHJcbiAgICAgICAgdmFsdWU6IDEwLFxyXG4gICAgICAgIHR5cGVzOiBbJ251bWJlciddLFxyXG4gICAgICAgIGVudkxpbms6ICdTRVJWRVJfUkFURV9MSU1JVElOR19NQVhfUkVRVUVTVFMnLFxyXG4gICAgICAgIGxlZ2FjeU5hbWU6ICdyYXRlTGltaXQnLFxyXG4gICAgICAgIGRlc2NyaXB0aW9uOiAnTWF4aW11bSBudW1iZXIgb2YgcmVxdWVzdHMgYWxsb3dlZCBwZXIgbWludXRlJyxcclxuICAgICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgICB0eXBlOiAnbnVtYmVyJ1xyXG4gICAgICAgIH1cclxuICAgICAgfSxcclxuICAgICAgd2luZG93OiB7XHJcbiAgICAgICAgdmFsdWU6IDEsXHJcbiAgICAgICAgdHlwZXM6IFsnbnVtYmVyJ10sXHJcbiAgICAgICAgZW52TGluazogJ1NFUlZFUl9SQVRFX0xJTUlUSU5HX1dJTkRPVycsXHJcbiAgICAgICAgZGVzY3JpcHRpb246ICdUaW1lIHdpbmRvdyBpbiBtaW51dGVzIGZvciByYXRlIGxpbWl0aW5nJyxcclxuICAgICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgICB0eXBlOiAnbnVtYmVyJ1xyXG4gICAgICAgIH1cclxuICAgICAgfSxcclxuICAgICAgZGVsYXk6IHtcclxuICAgICAgICB2YWx1ZTogMCxcclxuICAgICAgICB0eXBlczogWydudW1iZXInXSxcclxuICAgICAgICBlbnZMaW5rOiAnU0VSVkVSX1JBVEVfTElNSVRJTkdfREVMQVknLFxyXG4gICAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICAgJ0RlbGF5IGR1cmF0aW9uIGJldHdlZW4gc3VjY2Vzc2l2ZSByZXF1ZXN0cyBiZWZvcmUgcmVhY2hpbmcgdGhlIGxpbWl0JyxcclxuICAgICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgICB0eXBlOiAnbnVtYmVyJ1xyXG4gICAgICAgIH1cclxuICAgICAgfSxcclxuICAgICAgdHJ1c3RQcm94eToge1xyXG4gICAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgICB0eXBlczogWydib29sZWFuJ10sXHJcbiAgICAgICAgZW52TGluazogJ1NFUlZFUl9SQVRFX0xJTUlUSU5HX1RSVVNUX1BST1hZJyxcclxuICAgICAgICBkZXNjcmlwdGlvbjogJ1NldCB0byB0cnVlIGlmIHRoZSBzZXJ2ZXIgaXMgYmVoaW5kIGEgbG9hZCBiYWxhbmNlcicsXHJcbiAgICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgICAgdHlwZTogJ3RvZ2dsZSdcclxuICAgICAgICB9XHJcbiAgICAgIH0sXHJcbiAgICAgIHNraXBLZXk6IHtcclxuICAgICAgICB2YWx1ZTogbnVsbCxcclxuICAgICAgICB0eXBlczogWydzdHJpbmcnLCAnbnVsbCddLFxyXG4gICAgICAgIGVudkxpbms6ICdTRVJWRVJfUkFURV9MSU1JVElOR19TS0lQX0tFWScsXHJcbiAgICAgICAgZGVzY3JpcHRpb246ICdLZXkgdG8gYnlwYXNzIHRoZSByYXRlIGxpbWl0ZXIsIHVzZWQgd2l0aCBgc2tpcFRva2VuYCcsXHJcbiAgICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgICAgdHlwZTogJ3RleHQnXHJcbiAgICAgICAgfVxyXG4gICAgICB9LFxyXG4gICAgICBza2lwVG9rZW46IHtcclxuICAgICAgICB2YWx1ZTogbnVsbCxcclxuICAgICAgICB0eXBlczogWydzdHJpbmcnLCAnbnVsbCddLFxyXG4gICAgICAgIGVudkxpbms6ICdTRVJWRVJfUkFURV9MSU1JVElOR19TS0lQX1RPS0VOJyxcclxuICAgICAgICBkZXNjcmlwdGlvbjogJ1Rva2VuIHRvIGJ5cGFzcyB0aGUgcmF0ZSBsaW1pdGVyLCB1c2VkIHdpdGggYHNraXBLZXlgJyxcclxuICAgICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgICB0eXBlOiAndGV4dCdcclxuICAgICAgICB9XHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICBzc2w6IHtcclxuICAgICAgZW5hYmxlOiB7XHJcbiAgICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICAgIHR5cGVzOiBbJ2Jvb2xlYW4nXSxcclxuICAgICAgICBlbnZMaW5rOiAnU0VSVkVSX1NTTF9FTkFCTEUnLFxyXG4gICAgICAgIGNsaU5hbWU6ICdlbmFibGVTc2wnLFxyXG4gICAgICAgIGRlc2NyaXB0aW9uOiAnRW5hYmxlcyBvciBkaXNhYmxlcyBTU0wgcHJvdG9jb2wnLFxyXG4gICAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICAgIHR5cGU6ICd0b2dnbGUnXHJcbiAgICAgICAgfVxyXG4gICAgICB9LFxyXG4gICAgICBmb3JjZToge1xyXG4gICAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgICB0eXBlczogWydib29sZWFuJ10sXHJcbiAgICAgICAgZW52TGluazogJ1NFUlZFUl9TU0xfRk9SQ0UnLFxyXG4gICAgICAgIGNsaU5hbWU6ICdzc2xGb3JjZScsXHJcbiAgICAgICAgbGVnYWN5TmFtZTogJ3NzbE9ubHknLFxyXG4gICAgICAgIGRlc2NyaXB0aW9uOiAnRm9yY2VzIHRoZSBzZXJ2ZXIgdG8gdXNlIEhUVFBTIG9ubHkgd2hlbiB0cnVlJyxcclxuICAgICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgICB0eXBlOiAndG9nZ2xlJ1xyXG4gICAgICAgIH1cclxuICAgICAgfSxcclxuICAgICAgcG9ydDoge1xyXG4gICAgICAgIHZhbHVlOiA0NDMsXHJcbiAgICAgICAgdHlwZXM6IFsnbnVtYmVyJ10sXHJcbiAgICAgICAgZW52TGluazogJ1NFUlZFUl9TU0xfUE9SVCcsXHJcbiAgICAgICAgY2xpTmFtZTogJ3NzbFBvcnQnLFxyXG4gICAgICAgIGRlc2NyaXB0aW9uOiAnUG9ydCBmb3IgdGhlIFNTTCBzZXJ2ZXInLFxyXG4gICAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICAgIHR5cGU6ICdudW1iZXInXHJcbiAgICAgICAgfVxyXG4gICAgICB9LFxyXG4gICAgICBjZXJ0UGF0aDoge1xyXG4gICAgICAgIHZhbHVlOiBudWxsLFxyXG4gICAgICAgIHR5cGVzOiBbJ3N0cmluZycsICdudWxsJ10sXHJcbiAgICAgICAgZW52TGluazogJ1NFUlZFUl9TU0xfQ0VSVF9QQVRIJyxcclxuICAgICAgICBjbGlOYW1lOiAnc3NsQ2VydFBhdGgnLFxyXG4gICAgICAgIGxlZ2FjeU5hbWU6ICdzc2xQYXRoJyxcclxuICAgICAgICBkZXNjcmlwdGlvbjogJ1BhdGggdG8gdGhlIFNTTCBjZXJ0aWZpY2F0ZS9rZXkgZmlsZScsXHJcbiAgICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgICAgdHlwZTogJ3RleHQnXHJcbiAgICAgICAgfVxyXG4gICAgICB9XHJcbiAgICB9XHJcbiAgfSxcclxuICBwb29sOiB7XHJcbiAgICBtaW5Xb3JrZXJzOiB7XHJcbiAgICAgIHZhbHVlOiA0LFxyXG4gICAgICB0eXBlczogWydudW1iZXInXSxcclxuICAgICAgZW52TGluazogJ1BPT0xfTUlOX1dPUktFUlMnLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ01pbmltdW0gYW5kIGluaXRpYWwgbnVtYmVyIG9mIHBvb2wgd29ya2VycyB0byBzcGF3bicsXHJcbiAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICB0eXBlOiAnbnVtYmVyJ1xyXG4gICAgICB9XHJcbiAgICB9LFxyXG4gICAgbWF4V29ya2Vyczoge1xyXG4gICAgICB2YWx1ZTogOCxcclxuICAgICAgdHlwZXM6IFsnbnVtYmVyJ10sXHJcbiAgICAgIGVudkxpbms6ICdQT09MX01BWF9XT1JLRVJTJyxcclxuICAgICAgbGVnYWN5TmFtZTogJ3dvcmtlcnMnLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ01heGltdW0gbnVtYmVyIG9mIHBvb2wgd29ya2VycyB0byBzcGF3bicsXHJcbiAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICB0eXBlOiAnbnVtYmVyJ1xyXG4gICAgICB9XHJcbiAgICB9LFxyXG4gICAgd29ya0xpbWl0OiB7XHJcbiAgICAgIHZhbHVlOiA0MCxcclxuICAgICAgdHlwZXM6IFsnbnVtYmVyJ10sXHJcbiAgICAgIGVudkxpbms6ICdQT09MX1dPUktfTElNSVQnLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ051bWJlciBvZiB0YXNrcyBhIHdvcmtlciBjYW4gaGFuZGxlIGJlZm9yZSByZXN0YXJ0aW5nJyxcclxuICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgIHR5cGU6ICdudW1iZXInXHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICBhY3F1aXJlVGltZW91dDoge1xyXG4gICAgICB2YWx1ZTogNTAwMCxcclxuICAgICAgdHlwZXM6IFsnbnVtYmVyJ10sXHJcbiAgICAgIGVudkxpbms6ICdQT09MX0FDUVVJUkVfVElNRU9VVCcsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnVGltZW91dCBpbiBtaWxsaXNlY29uZHMgZm9yIGFjcXVpcmluZyBhIHJlc291cmNlJyxcclxuICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgIHR5cGU6ICdudW1iZXInXHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICBjcmVhdGVUaW1lb3V0OiB7XHJcbiAgICAgIHZhbHVlOiA1MDAwLFxyXG4gICAgICB0eXBlczogWydudW1iZXInXSxcclxuICAgICAgZW52TGluazogJ1BPT0xfQ1JFQVRFX1RJTUVPVVQnLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ1RpbWVvdXQgaW4gbWlsbGlzZWNvbmRzIGZvciBjcmVhdGluZyBhIHJlc291cmNlJyxcclxuICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgIHR5cGU6ICdudW1iZXInXHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICBkZXN0cm95VGltZW91dDoge1xyXG4gICAgICB2YWx1ZTogNTAwMCxcclxuICAgICAgdHlwZXM6IFsnbnVtYmVyJ10sXHJcbiAgICAgIGVudkxpbms6ICdQT09MX0RFU1RST1lfVElNRU9VVCcsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnVGltZW91dCBpbiBtaWxsaXNlY29uZHMgZm9yIGRlc3Ryb3lpbmcgYSByZXNvdXJjZScsXHJcbiAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICB0eXBlOiAnbnVtYmVyJ1xyXG4gICAgICB9XHJcbiAgICB9LFxyXG4gICAgaWRsZVRpbWVvdXQ6IHtcclxuICAgICAgdmFsdWU6IDMwMDAwLFxyXG4gICAgICB0eXBlczogWydudW1iZXInXSxcclxuICAgICAgZW52TGluazogJ1BPT0xfSURMRV9USU1FT1VUJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdUaW1lb3V0IGluIG1pbGxpc2Vjb25kcyBmb3IgZGVzdHJveWluZyBpZGxlIHJlc291cmNlcycsXHJcbiAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICB0eXBlOiAnbnVtYmVyJ1xyXG4gICAgICB9XHJcbiAgICB9LFxyXG4gICAgY3JlYXRlUmV0cnlJbnRlcnZhbDoge1xyXG4gICAgICB2YWx1ZTogMjAwLFxyXG4gICAgICB0eXBlczogWydudW1iZXInXSxcclxuICAgICAgZW52TGluazogJ1BPT0xfQ1JFQVRFX1JFVFJZX0lOVEVSVkFMJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ0ludGVydmFsIGluIG1pbGxpc2Vjb25kcyBiZWZvcmUgcmV0cnlpbmcgcmVzb3VyY2UgY3JlYXRpb24gb24gZmFpbHVyZScsXHJcbiAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICB0eXBlOiAnbnVtYmVyJ1xyXG4gICAgICB9XHJcbiAgICB9LFxyXG4gICAgcmVhcGVySW50ZXJ2YWw6IHtcclxuICAgICAgdmFsdWU6IDEwMDAsXHJcbiAgICAgIHR5cGVzOiBbJ251bWJlciddLFxyXG4gICAgICBlbnZMaW5rOiAnUE9PTF9SRUFQRVJfSU5URVJWQUwnLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnSW50ZXJ2YWwgaW4gbWlsbGlzZWNvbmRzIHRvIGNoZWNrIGFuZCBkZXN0cm95IGlkbGUgcmVzb3VyY2VzJyxcclxuICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgIHR5cGU6ICdudW1iZXInXHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICBiZW5jaG1hcmtpbmc6IHtcclxuICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICB0eXBlczogWydib29sZWFuJ10sXHJcbiAgICAgIGVudkxpbms6ICdQT09MX0JFTkNITUFSS0lORycsXHJcbiAgICAgIGNsaU5hbWU6ICdwb29sQmVuY2htYXJraW5nJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdTaG93cyBzdGF0aXN0aWNzIGZvciB0aGUgcG9vbCBvZiByZXNvdXJjZXMnLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ3RvZ2dsZSdcclxuICAgICAgfVxyXG4gICAgfVxyXG4gIH0sXHJcbiAgbG9nZ2luZzoge1xyXG4gICAgbGV2ZWw6IHtcclxuICAgICAgdmFsdWU6IDQsXHJcbiAgICAgIHR5cGVzOiBbJ251bWJlciddLFxyXG4gICAgICBlbnZMaW5rOiAnTE9HR0lOR19MRVZFTCcsXHJcbiAgICAgIGNsaU5hbWU6ICdsb2dMZXZlbCcsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnTG9nZ2luZyB2ZXJib3NpdHkgbGV2ZWwnLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgICAgcm91bmQ6IDAsXHJcbiAgICAgICAgbWluOiAwLFxyXG4gICAgICAgIG1heDogNVxyXG4gICAgICB9XHJcbiAgICB9LFxyXG4gICAgZmlsZToge1xyXG4gICAgICB2YWx1ZTogJ2hpZ2hjaGFydHMtZXhwb3J0LXNlcnZlci5sb2cnLFxyXG4gICAgICB0eXBlczogWydzdHJpbmcnXSxcclxuICAgICAgZW52TGluazogJ0xPR0dJTkdfRklMRScsXHJcbiAgICAgIGNsaU5hbWU6ICdsb2dGaWxlJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ0xvZyBmaWxlIG5hbWUuIFJlcXVpcmVzIGBsb2dUb0ZpbGVgIGFuZCBgbG9nRGVzdGAgdG8gYmUgc2V0JyxcclxuICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgIHR5cGU6ICd0ZXh0J1xyXG4gICAgICB9XHJcbiAgICB9LFxyXG4gICAgZGVzdDoge1xyXG4gICAgICB2YWx1ZTogJ2xvZycsXHJcbiAgICAgIHR5cGVzOiBbJ3N0cmluZyddLFxyXG4gICAgICBlbnZMaW5rOiAnTE9HR0lOR19ERVNUJyxcclxuICAgICAgY2xpTmFtZTogJ2xvZ0Rlc3QnLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ1BhdGggdG8gc3RvcmUgbG9nIGZpbGVzLiBSZXF1aXJlcyBgbG9nVG9GaWxlYCB0byBiZSBzZXQnLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ3RleHQnXHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICB0b0NvbnNvbGU6IHtcclxuICAgICAgdmFsdWU6IHRydWUsXHJcbiAgICAgIHR5cGVzOiBbJ2Jvb2xlYW4nXSxcclxuICAgICAgZW52TGluazogJ0xPR0dJTkdfVE9fQ09OU09MRScsXHJcbiAgICAgIGNsaU5hbWU6ICdsb2dUb0NvbnNvbGUnLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ0VuYWJsZXMgb3IgZGlzYWJsZXMgY29uc29sZSBsb2dnaW5nJyxcclxuICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgIHR5cGU6ICd0b2dnbGUnXHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICB0b0ZpbGU6IHtcclxuICAgICAgdmFsdWU6IHRydWUsXHJcbiAgICAgIHR5cGVzOiBbJ2Jvb2xlYW4nXSxcclxuICAgICAgZW52TGluazogJ0xPR0dJTkdfVE9fRklMRScsXHJcbiAgICAgIGNsaU5hbWU6ICdsb2dUb0ZpbGUnLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ0VuYWJsZXMgb3IgZGlzYWJsZXMgbG9nZ2luZyB0byBhIGZpbGUnLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ3RvZ2dsZSdcclxuICAgICAgfVxyXG4gICAgfVxyXG4gIH0sXHJcbiAgdWk6IHtcclxuICAgIGVuYWJsZToge1xyXG4gICAgICB2YWx1ZTogZmFsc2UsXHJcbiAgICAgIHR5cGVzOiBbJ2Jvb2xlYW4nXSxcclxuICAgICAgZW52TGluazogJ1VJX0VOQUJMRScsXHJcbiAgICAgIGNsaU5hbWU6ICdlbmFibGVVaScsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnRW5hYmxlcyBvciBkaXNhYmxlcyB0aGUgVUkgZm9yIHRoZSBleHBvcnQgc2VydmVyJyxcclxuICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgIHR5cGU6ICd0b2dnbGUnXHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICByb3V0ZToge1xyXG4gICAgICB2YWx1ZTogJy8nLFxyXG4gICAgICB0eXBlczogWydzdHJpbmcnXSxcclxuICAgICAgZW52TGluazogJ1VJX1JPVVRFJyxcclxuICAgICAgY2xpTmFtZTogJ3VpUm91dGUnLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ1RoZSBlbmRwb2ludCByb3V0ZSBmb3IgdGhlIFVJJyxcclxuICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgIHR5cGU6ICd0ZXh0J1xyXG4gICAgICB9XHJcbiAgICB9XHJcbiAgfSxcclxuICBvdGhlcjoge1xyXG4gICAgbm9kZUVudjoge1xyXG4gICAgICB2YWx1ZTogJ3Byb2R1Y3Rpb24nLFxyXG4gICAgICB0eXBlczogWydzdHJpbmcnXSxcclxuICAgICAgZW52TGluazogJ09USEVSX05PREVfRU5WJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdUaGUgTm9kZS5qcyBlbnZpcm9ubWVudCB0eXBlJyxcclxuICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgIHR5cGU6ICd0ZXh0J1xyXG4gICAgICB9XHJcbiAgICB9LFxyXG4gICAgbGlzdGVuVG9Qcm9jZXNzRXhpdHM6IHtcclxuICAgICAgdmFsdWU6IHRydWUsXHJcbiAgICAgIHR5cGVzOiBbJ2Jvb2xlYW4nXSxcclxuICAgICAgZW52TGluazogJ09USEVSX0xJU1RFTl9UT19QUk9DRVNTX0VYSVRTJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdXaGV0aGVyIG9yIG5vdCB0byBhdHRhY2ggcHJvY2Vzcy5leGl0IGhhbmRsZXJzJyxcclxuICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgIHR5cGU6ICd0b2dnbGUnXHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICBub0xvZ286IHtcclxuICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICB0eXBlczogWydib29sZWFuJ10sXHJcbiAgICAgIGVudkxpbms6ICdPVEhFUl9OT19MT0dPJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdEaXNwbGF5IG9yIHNraXAgcHJpbnRpbmcgdGhlIGxvZ28gb24gc3RhcnR1cCcsXHJcbiAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICB0eXBlOiAndG9nZ2xlJ1xyXG4gICAgICB9XHJcbiAgICB9LFxyXG4gICAgaGFyZFJlc2V0UGFnZToge1xyXG4gICAgICB2YWx1ZTogZmFsc2UsXHJcbiAgICAgIHR5cGVzOiBbJ2Jvb2xlYW4nXSxcclxuICAgICAgZW52TGluazogJ09USEVSX0hBUkRfUkVTRVRfUEFHRScsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnV2hldGhlciBvciBub3QgdG8gcmVzZXQgdGhlIHBhZ2UgY29udGVudCBlbnRpcmVseScsXHJcbiAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICB0eXBlOiAndG9nZ2xlJ1xyXG4gICAgICB9XHJcbiAgICB9LFxyXG4gICAgYnJvd3NlclNoZWxsTW9kZToge1xyXG4gICAgICB2YWx1ZTogdHJ1ZSxcclxuICAgICAgdHlwZXM6IFsnYm9vbGVhbiddLFxyXG4gICAgICBlbnZMaW5rOiAnT1RIRVJfQlJPV1NFUl9TSEVMTF9NT0RFJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdXaGV0aGVyIG9yIG5vdCB0byBzZXQgdGhlIGJyb3dzZXIgdG8gcnVuIGluIHNoZWxsIG1vZGUnLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ3RvZ2dsZSdcclxuICAgICAgfVxyXG4gICAgfSxcclxuICAgIHZhbGlkYXRpb246IHtcclxuICAgICAgdmFsdWU6IHRydWUsXHJcbiAgICAgIHR5cGVzOiBbJ2Jvb2xlYW4nXSxcclxuICAgICAgZW52TGluazogJ09USEVSX1ZBTElEQVRJT04nLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ1doZXRoZXIgb3Igbm90IHRvIGVuYWJsZSB2YWxpZGF0aW9uIG9mIG9wdGlvbnMgdHlwZXMnLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ3RvZ2dsZSdcclxuICAgICAgfVxyXG4gICAgfVxyXG4gIH0sXHJcbiAgZGVidWc6IHtcclxuICAgIGVuYWJsZToge1xyXG4gICAgICB2YWx1ZTogZmFsc2UsXHJcbiAgICAgIHR5cGVzOiBbJ2Jvb2xlYW4nXSxcclxuICAgICAgZW52TGluazogJ0RFQlVHX0VOQUJMRScsXHJcbiAgICAgIGNsaU5hbWU6ICdlbmFibGVEZWJ1ZycsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnRW5hYmxlcyBvciBkaXNhYmxlcyBkZWJ1ZyBtb2RlIGZvciB0aGUgdW5kZXJseWluZyBicm93c2VyJyxcclxuICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgIHR5cGU6ICd0b2dnbGUnXHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICBoZWFkbGVzczoge1xyXG4gICAgICB2YWx1ZTogZmFsc2UsXHJcbiAgICAgIHR5cGVzOiBbJ2Jvb2xlYW4nXSxcclxuICAgICAgZW52TGluazogJ0RFQlVHX0hFQURMRVNTJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ1doZXRoZXIgb3Igbm90IHRvIHNldCB0aGUgYnJvd3NlciB0byBydW4gaW4gaGVhZGxlc3MgbW9kZSBkdXJpbmcgZGVidWdnaW5nJyxcclxuICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgIHR5cGU6ICd0b2dnbGUnXHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICBkZXZ0b29sczoge1xyXG4gICAgICB2YWx1ZTogZmFsc2UsXHJcbiAgICAgIHR5cGVzOiBbJ2Jvb2xlYW4nXSxcclxuICAgICAgZW52TGluazogJ0RFQlVHX0RFVlRPT0xTJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdFbmFibGVzIG9yIGRpc2FibGVzIERldlRvb2xzIGluIGhlYWRmdWwgbW9kZScsXHJcbiAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICB0eXBlOiAndG9nZ2xlJ1xyXG4gICAgICB9XHJcbiAgICB9LFxyXG4gICAgbGlzdGVuVG9Db25zb2xlOiB7XHJcbiAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgdHlwZXM6IFsnYm9vbGVhbiddLFxyXG4gICAgICBlbnZMaW5rOiAnREVCVUdfTElTVEVOX1RPX0NPTlNPTEUnLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnRW5hYmxlcyBvciBkaXNhYmxlcyBsaXN0ZW5pbmcgdG8gY29uc29sZSBtZXNzYWdlcyBmcm9tIHRoZSBicm93c2VyJyxcclxuICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgIHR5cGU6ICd0b2dnbGUnXHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICBkdW1waW86IHtcclxuICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICB0eXBlczogWydib29sZWFuJ10sXHJcbiAgICAgIGVudkxpbms6ICdERUJVR19EVU1QSU8nLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnUmVkaXJlY3RzIG9yIG5vdCBicm93c2VyIHN0ZG91dCBhbmQgc3RkZXJyIHRvIHByb2Nlc3Muc3Rkb3V0IGFuZCBwcm9jZXNzLnN0ZGVycicsXHJcbiAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICB0eXBlOiAndG9nZ2xlJ1xyXG4gICAgICB9XHJcbiAgICB9LFxyXG4gICAgc2xvd01vOiB7XHJcbiAgICAgIHZhbHVlOiAwLFxyXG4gICAgICB0eXBlczogWydudW1iZXInXSxcclxuICAgICAgZW52TGluazogJ0RFQlVHX1NMT1dfTU8nLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ0RlbGF5cyBQdXBwZXRlZXIgb3BlcmF0aW9ucyBieSB0aGUgc3BlY2lmaWVkIG1pbGxpc2Vjb25kcycsXHJcbiAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICB0eXBlOiAnbnVtYmVyJ1xyXG4gICAgICB9XHJcbiAgICB9LFxyXG4gICAgZGVidWdnaW5nUG9ydDoge1xyXG4gICAgICB2YWx1ZTogOTIyMixcclxuICAgICAgdHlwZXM6IFsnbnVtYmVyJ10sXHJcbiAgICAgIGVudkxpbms6ICdERUJVR19ERUJVR0dJTkdfUE9SVCcsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnUG9ydCB1c2VkIGZvciBkZWJ1Z2dpbmcnLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ251bWJlcidcclxuICAgICAgfVxyXG4gICAgfVxyXG4gIH1cclxufTtcclxuXHJcbi8vIFByb3BlcnRpZXMgbmVzdGluZyBsZXZlbCBvZiBhbGwgb3B0aW9uc1xyXG5leHBvcnQgY29uc3QgbmVzdGVkUHJvcHMgPSBfY3JlYXRlTmVzdGVkUHJvcHMoZGVmYXVsdENvbmZpZyk7XHJcblxyXG4vLyBQcm9wZXJ0aWVzIG5hbWVzIHRoYXQgc2hvdWxkIG5vdCBiZSByZWN1cnNpdmVseSBtZXJnZWRcclxuZXhwb3J0IGNvbnN0IGFic29sdXRlUHJvcHMgPSBfY3JlYXRlQWJzb2x1dGVQcm9wcyhkZWZhdWx0Q29uZmlnKTtcclxuXHJcbi8qKlxyXG4gKiBSZWN1cnNpdmVseSBnZW5lcmF0ZXMgYSBtYXBwaW5nIG9mIG5lc3RlZCBhcmd1bWVudCBjaGFpbnMgZnJvbSBhIG5lc3RlZFxyXG4gKiBjb25maWcgb2JqZWN0LiBUaGlzIGZ1bmN0aW9uIHRyYXZlcnNlcyBhIG5lc3RlZCBvYmplY3QgYW5kIGNyZWF0ZXMgYSBtYXBwaW5nXHJcbiAqIHdoZXJlIGVhY2gga2V5IGlzIGFuIGFyZ3VtZW50IG5hbWUgKGVpdGhlciBmcm9tIGBjbGlOYW1lYCwgYGxlZ2FjeU5hbWVgLFxyXG4gKiBvciB0aGUgb3JpZ2luYWwga2V5KSBhbmQgZWFjaCB2YWx1ZSBpcyBhIHN0cmluZyByZXByZXNlbnRpbmcgdGhlIGNoYWluXHJcbiAqIG9mIG5lc3RlZCBwcm9wZXJ0aWVzIGxlYWRpbmcgdG8gdGhhdCBhcmd1bWVudC5cclxuICpcclxuICogQGZ1bmN0aW9uIF9jcmVhdGVOZXN0ZWRQcm9wc1xyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gY29uZmlnIC0gVGhlIGNvbmZpZ3VyYXRpb24gb2JqZWN0LlxyXG4gKiBAcGFyYW0ge09iamVjdH0gW25lc3RlZFByb3BzPXt9XSAtIFRoZSBhY2N1bXVsYXRvciBvYmplY3QgZm9yIHN0b3JpbmdcclxuICogdGhlIHJlc3VsdGluZyBhcmd1bWVudHMgY2hhaW5zLiAgVGhlIGRlZmF1bHQgdmFsdWUgaXMgYW4gZW1wdHkgb2JqZWN0LlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gW3Byb3BDaGFpbj0nJ10gLSBUaGUgY3VycmVudCBjaGFpbiBvZiBuZXN0ZWQgcHJvcGVydGllcyxcclxuICogdXNlZCBpbnRlcm5hbGx5IGR1cmluZyByZWN1cnNpb24uICBUaGUgZGVmYXVsdCB2YWx1ZSBpcyBhbiBlbXB0eSBzdHJpbmcuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtPYmplY3R9IEFuIG9iamVjdCBtYXBwaW5nIGFyZ3VtZW50IG5hbWVzIHRvIHRoZWlyIGNvcnJlc3BvbmRpbmdcclxuICogbmVzdGVkIHByb3BlcnR5IGNoYWlucy5cclxuICovXHJcbmZ1bmN0aW9uIF9jcmVhdGVOZXN0ZWRQcm9wcyhjb25maWcsIG5lc3RlZFByb3BzID0ge30sIHByb3BDaGFpbiA9ICcnKSB7XHJcbiAgT2JqZWN0LmtleXMoY29uZmlnKS5mb3JFYWNoKChrZXkpID0+IHtcclxuICAgIC8vIEdldCB0aGUgc3BlY2lmaWMgc2VjdGlvblxyXG4gICAgY29uc3QgZW50cnkgPSBjb25maWdba2V5XTtcclxuXHJcbiAgICAvLyBDaGVjayBpZiB0aGVyZSBpcyBzdGlsbCBtb3JlIGRlcHRoIHRvIHRyYXZlcnNlXHJcbiAgICBpZiAodHlwZW9mIGVudHJ5LnZhbHVlID09PSAndW5kZWZpbmVkJykge1xyXG4gICAgICAvLyBSZWN1cnNlIGludG8gZGVlcGVyIGxldmVscyBvZiBuZXN0ZWQgYXJndW1lbnRzXHJcbiAgICAgIF9jcmVhdGVOZXN0ZWRQcm9wcyhlbnRyeSwgbmVzdGVkUHJvcHMsIGAke3Byb3BDaGFpbn0uJHtrZXl9YCk7XHJcbiAgICB9IGVsc2Uge1xyXG4gICAgICAvLyBDcmVhdGUgdGhlIGNoYWluIG9mIG5lc3RlZCBhcmd1bWVudHNcclxuICAgICAgbmVzdGVkUHJvcHNbZW50cnkuY2xpTmFtZSB8fCBrZXldID0gYCR7cHJvcENoYWlufS4ke2tleX1gLnN1YnN0cmluZygxKTtcclxuXHJcbiAgICAgIC8vIFN1cHBvcnQgZm9yIHRoZSBsZWdhY3ksIFBoYW50b21KUyBwcm9wZXJ0aWVzIG5hbWVzXHJcbiAgICAgIGlmIChlbnRyeS5sZWdhY3lOYW1lICE9PSB1bmRlZmluZWQpIHtcclxuICAgICAgICBuZXN0ZWRQcm9wc1tlbnRyeS5sZWdhY3lOYW1lXSA9IGAke3Byb3BDaGFpbn0uJHtrZXl9YC5zdWJzdHJpbmcoMSk7XHJcbiAgICAgIH1cclxuICAgIH1cclxuICB9KTtcclxuXHJcbiAgLy8gUmV0dXJuIHRoZSBvYmplY3Qgd2l0aCBuZXN0ZWQgYXJndW1lbnQgY2hhaW5zXHJcbiAgcmV0dXJuIG5lc3RlZFByb3BzO1xyXG59XHJcblxyXG4vKipcclxuICogUmVjdXJzaXZlbHkgZ2F0aGVycyB0aGUgbmFtZXMgb2YgcHJvcGVydGllcyBmcm9tIGEgY29uZmlndXJhdGlvbiBvYmplY3QgdGhhdFxyXG4gKiBjYW4gYmUgdHJlYXRlZCBhcyBhYnNvbHV0ZSBwcm9wZXJ0aWVzLiBUaGVzZSBwcm9wZXJ0aWVzIGhhdmUgdmFsdWVzIHRoYXRcclxuICogYXJlIG9iamVjdHMgYW5kIGRvIG5vdCBjb250YWluIGZ1cnRoZXIgbmVzdGVkIGRlcHRoIHdoZW4gbWVyZ2luZyBhbiBvYmplY3RcclxuICogY29udGFpbmluZyB0aGVzZSBvcHRpb25zLlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gX2NyZWF0ZUFic29sdXRlUHJvcHNcclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IGNvbmZpZyAtIFRoZSBjb25maWd1cmF0aW9uIG9iamVjdC5cclxuICogQHBhcmFtIHtBcnJheS48c3RyaW5nPn0gW2Fic29sdXRlUHJvcHM9W11dIC0gQW4gYXJyYXkgdG8gY29sbGVjdCB0aGUgbmFtZXNcclxuICogb2YgYWJzb2x1dGUgcHJvcGVydGllcy4gVGhlIGRlZmF1bHQgdmFsdWUgaXMgYW4gZW1wdHkgYXJyYXkuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtBcnJheS48c3RyaW5nPn0gQW4gYXJyYXkgY29udGFpbmluZyB0aGUgbmFtZXMgb2YgYWJzb2x1dGVcclxuICogcHJvcGVydGllcy5cclxuICovXHJcbmZ1bmN0aW9uIF9jcmVhdGVBYnNvbHV0ZVByb3BzKGNvbmZpZywgYWJzb2x1dGVQcm9wcyA9IFtdKSB7XHJcbiAgT2JqZWN0LmtleXMoY29uZmlnKS5mb3JFYWNoKChrZXkpID0+IHtcclxuICAgIC8vIEdldCB0aGUgc3BlY2lmaWMgc2VjdGlvblxyXG4gICAgY29uc3QgZW50cnkgPSBjb25maWdba2V5XTtcclxuXHJcbiAgICAvLyBDaGVjayBpZiB0aGVyZSBpcyBzdGlsbCBtb3JlIGRlcHRoIHRvIHRyYXZlcnNlXHJcbiAgICBpZiAodHlwZW9mIGVudHJ5LnR5cGVzID09PSAndW5kZWZpbmVkJykge1xyXG4gICAgICAvLyBSZWN1cnNlIGludG8gZGVlcGVyIGxldmVsc1xyXG4gICAgICBfY3JlYXRlQWJzb2x1dGVQcm9wcyhlbnRyeSwgYWJzb2x1dGVQcm9wcyk7XHJcbiAgICB9IGVsc2Uge1xyXG4gICAgICAvLyBJZiB0aGUgb3B0aW9uIGNhbiBiZSBhbiBvYmplY3QsIHNhdmUgaXRzIHR5cGUgaW4gdGhlIGFycmF5XHJcbiAgICAgIGlmIChlbnRyeS50eXBlcy5pbmNsdWRlcygnT2JqZWN0JykpIHtcclxuICAgICAgICBhYnNvbHV0ZVByb3BzLnB1c2goa2V5KTtcclxuICAgICAgfVxyXG4gICAgfVxyXG4gIH0pO1xyXG5cclxuICAvLyBSZXR1cm4gdGhlIGFycmF5IHdpdGggdGhlIG5hbWVzIG9mIGFic29sdXRlIHByb3BlcnRpZXNcclxuICByZXR1cm4gYWJzb2x1dGVQcm9wcztcclxufVxyXG5cclxuZXhwb3J0IGRlZmF1bHQge1xyXG4gIGRlZmF1bHRDb25maWcsXHJcbiAgbmVzdGVkUHJvcHMsXHJcbiAgYWJzb2x1dGVQcm9wc1xyXG59O1xyXG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxyXG5cclxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXHJcblxyXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNSwgSGlnaHNvZnRcclxuXHJcbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cclxuXHJcbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxyXG5cclxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxyXG5cclxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cclxuXHJcbi8qKlxyXG4gKiBAb3ZlcnZpZXcgVGhpcyBmaWxlIGhhbmRsZXMgcGFyc2luZyBhbmQgdmFsaWRhdGluZyBvcHRpb25zIGZyb20gbXVsdGlwbGVcclxuICogc291cmNlcyAodGhlIGNvbmZpZyBmaWxlLCBjdXN0b20gSlNPTiwgZW52aXJvbm1lbnQgdmFyaWFibGVzLCBDTEkgYXJndW1lbnRzLFxyXG4gKiBhbmQgcmVxdWVzdCBwYXlsb2FkKSB1c2luZyB0aGUgJ3pvZCcgbGlicmFyeS5cclxuICpcclxuICogRW52aXJvbm1lbnQgdmFyaWFibGVzIGFyZSBwYXJzZWQgYW5kIHZhbGlkYXRlZCBvbmx5IG9uY2UgYXQgYXBwbGljYXRpb25cclxuICogc3RhcnR1cCwgYW5kIHRoZSB2YWxpZGF0ZWQgcmVzdWx0cyBhcmUgZXhwb3J0ZWQgYXMgYGVudnNgIGZvciB1c2UgdGhyb3VnaG91dFxyXG4gKiB0aGUgYXBwbGljYXRpb24uXHJcbiAqXHJcbiAqIE9wdGlvbnMgZnJvbSBvdGhlciBzb3VyY2VzLCBob3dldmVyLCBhcmUgcGFyc2VkIGFuZCB2YWxpZGF0ZWQgb24gZGVtYW5kLFxyXG4gKiBlYWNoIHRpbWUgYW4gZXhwb3J0IGlzIGF0dGVtcHRlZC5cclxuICovXHJcblxyXG5pbXBvcnQgZG90ZW52IGZyb20gJ2RvdGVudic7XHJcbmltcG9ydCB7IHogfSBmcm9tICd6b2QnO1xyXG5cclxuaW1wb3J0IHsgZGVmYXVsdENvbmZpZyB9IGZyb20gJy4vc2NoZW1hcy9jb25maWcuanMnO1xyXG5cclxuLy8gTG9hZCB0aGUgLmVudiBpbnRvIGVudmlyb25tZW50IHZhcmlhYmxlc1xyXG5kb3RlbnYuY29uZmlnKCk7XHJcblxyXG4vLyBHZXQgc2NyaXB0cyBuYW1lcyBvZiBlYWNoIGNhdGVnb3J5IGZyb20gdGhlIGRlZmF1bHQgY29uZmlnXHJcbmNvbnN0IHsgY29yZVNjcmlwdHMsIG1vZHVsZVNjcmlwdHMsIGluZGljYXRvclNjcmlwdHMgfSA9XHJcbiAgZGVmYXVsdENvbmZpZy5oaWdoY2hhcnRzO1xyXG5cclxuLy8gU2V0cyB0aGUgY3VzdG9tIGVycm9yIG1hcCBnbG9iYWxseVxyXG56LnNldEVycm9yTWFwKF9jdXN0b21FcnJvck1hcCk7XHJcblxyXG4vKipcclxuICogT2JqZWN0IGNvbnRhaW5pbmcgY3VzdG9tIGdlbmVyYWwgdmFsaWRhdG9ycyBhbmQgcGFyc2VycyB0byBhdm9pZCByZXBldGl0aW9uXHJcbiAqIGluIHNjaGVtYSBvYmplY3RzLiBBbGwgdmFsaWRhdG9ycyBhcHBseSB0byB2YWx1ZXMgZnJvbSB2YXJpb3VzIHNvdXJjZXMsXHJcbiAqIGluY2x1ZGluZyB0aGUgZGVmYXVsdCBjb25maWcgZmlsZSwgYSBjdXN0b20gSlNPTiBmaWxlIGxvYWRlZCB3aXRoIHRoZSBvcHRpb25cclxuICogY2FsbGVkIGBsb2FkQ29uZmlnYCwgdGhlIC5lbnYgZmlsZSwgQ0xJIGFyZ3VtZW50cywgYW5kIHRoZSByZXF1ZXN0IHBheWxvYWQuXHJcbiAqIFRoZSBgc3RyaWN0Q2hlY2tgIGZsYWcgZW5hYmxlcyBzdHJpY3RlciB2YWxpZGF0aW9uIGFuZCBwYXJzaW5nIHJ1bGVzLiBUaGlzXHJcbiAqIGZsYWcgaXMgc2V0IHRvIGZhbHNlIGZvciB2YWx1ZXMgdGhhdCBjb21lIGZyb20gdGhlIC5lbnYgZmlsZSBvciBDTEkgYXJndW1lbnRzXHJcbiAqIGJlY2F1c2UgdGhleSBhcmUgcHJvdmlkZWQgYXMgc3RyaW5ncyBhbmQgbmVlZCB0byBiZSBwYXJzZWQgYWNjb3JkaW5nbHkgZmlyc3QuXHJcbiAqL1xyXG5jb25zdCB2ID0ge1xyXG4gIC8qKlxyXG4gICAqIFRoZSBgYm9vbGVhbmAgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbCBzdHJpY3RlclxyXG4gICAqIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoYXQ6XHJcbiAgICpcclxuICAgKiAtIFdoZW4gYHN0cmljdENoZWNrYCBpcyB0cnVlLCB0aGUgc2NoZW1hIHdpbGwgYWNjZXB0IHZhbHVlcyBhcmUgdHJ1ZVxyXG4gICAqIGFuZCBmYWxzZSBhbmQgdGhlIHNjaGVtYSB3aWxsIHZhbGlkYXRlIGFnYWluc3QgdGhlIGRlZmF1bHQgYm9vbGVhblxyXG4gICAqIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIC0gV2hlbiBgc3RyaWN0Q2hlY2tgIGlzIGZhbHNlLCB0aGUgc2NoZW1hIHdpbGwgYWNjZXB0IHZhbHVlcyBhcmUgdHJ1ZSxcclxuICAgKiBmYWxzZSwgbnVsbCwgJ3RydWUnLCAnMScsICdmYWxzZScsICcwJywgJ3VuZGVmaW5lZCcsICdudWxsJywgYW5kICcnLlxyXG4gICAqIFRoZSBzdHJpbmdzICd1bmRlZmluZWQnLCAnbnVsbCcsIGFuZCAnJyB3aWxsIGJlIHRyYW5zZm9ybWVkIHRvIG51bGwsXHJcbiAgICogdGhlIHN0cmluZyAndHJ1ZScgd2lsbCBiZSB0cmFuc2Zvcm1lZCB0byB0aGUgYm9vbGVhbiB2YWx1ZSB0cnVlLFxyXG4gICAqIGFuZCAnZmFsc2UnIHdpbGwgYmUgdHJhbnNmb3JtZWQgdG8gdGhlIGJvb2xlYW4gdmFsdWUgZmFsc2UuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gYm9vbGVhblxyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nIGJvb2xlYW4gdmFsdWVzLlxyXG4gICAqL1xyXG4gIGJvb2xlYW4oc3RyaWN0Q2hlY2spIHtcclxuICAgIHJldHVybiBzdHJpY3RDaGVja1xyXG4gICAgICA/IHouYm9vbGVhbigpXHJcbiAgICAgIDogelxyXG4gICAgICAgICAgLnVuaW9uKFtcclxuICAgICAgICAgICAgelxyXG4gICAgICAgICAgICAgIC5lbnVtKFsndHJ1ZScsICcxJywgJ2ZhbHNlJywgJzAnLCAndW5kZWZpbmVkJywgJ251bGwnLCAnJ10pXHJcbiAgICAgICAgICAgICAgLnRyYW5zZm9ybSgodmFsdWUpID0+XHJcbiAgICAgICAgICAgICAgICAhWyd1bmRlZmluZWQnLCAnbnVsbCcsICcnXS5pbmNsdWRlcyh2YWx1ZSlcclxuICAgICAgICAgICAgICAgICAgPyB2YWx1ZSA9PT0gJ3RydWUnIHx8IHZhbHVlID09PSAnMSdcclxuICAgICAgICAgICAgICAgICAgOiBudWxsXHJcbiAgICAgICAgICAgICAgKSxcclxuICAgICAgICAgICAgei5ib29sZWFuKClcclxuICAgICAgICAgIF0pXHJcbiAgICAgICAgICAubnVsbGFibGUoKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYHN0cmluZ2AgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbCBzdHJpY3RlclxyXG4gICAqIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoYXQ6XHJcbiAgICpcclxuICAgKiAtIFdoZW4gYHN0cmljdENoZWNrYCBpcyB0cnVlLCB0aGUgc2NoZW1hIHdpbGwgYWNjZXB0IHRyaW1tZWQgc3RyaW5ncyBleGNlcHRcclxuICAgKiB0aGUgZm9yYmlkZGVuIHZhbHVlczogJ2ZhbHNlJywgJ3VuZGVmaW5lZCcsICdudWxsJywgYW5kICcnLlxyXG4gICAqXHJcbiAgICogLSBXaGVuIGBzdHJpY3RDaGVja2AgaXMgZmFsc2UsIHRoZSBzY2hlbWEgd2lsbCBhY2NlcHQgdHJpbW1lZCBzdHJpbmdzXHJcbiAgICogYW5kIG51bGwuIFRoZSBmb3JiaWRkZW4gdmFsdWVzOiAnZmFsc2UnLCAndW5kZWZpbmVkJywgJ251bGwnLCBhbmQgJycgd2lsbFxyXG4gICAqIGJlIHRyYW5zZm9ybWVkIHRvIG51bGwuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gc3RyaW5nXHJcbiAgICpcclxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IHN0cmljdENoZWNrIC0gRGV0ZXJtaW5lcyBpZiBzdHJpY3RlciB2YWxpZGF0aW9uIHNob3VsZFxyXG4gICAqIGJlIGFwcGxpZWQuXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9IEEgWm9kIHNjaGVtYSBvYmplY3QgZm9yIHZhbGlkYXRpbmcgc3RyaW5nIHZhbHVlcy5cclxuICAgKi9cclxuICBzdHJpbmcoc3RyaWN0Q2hlY2spIHtcclxuICAgIHJldHVybiBzdHJpY3RDaGVja1xyXG4gICAgICA/IHpcclxuICAgICAgICAgIC5zdHJpbmcoKVxyXG4gICAgICAgICAgLnRyaW0oKVxyXG4gICAgICAgICAgLnJlZmluZShcclxuICAgICAgICAgICAgKHZhbHVlKSA9PiAhWydmYWxzZScsICd1bmRlZmluZWQnLCAnbnVsbCcsICcnXS5pbmNsdWRlcyh2YWx1ZSksXHJcbiAgICAgICAgICAgIHtcclxuICAgICAgICAgICAgICBwYXJhbXM6IHtcclxuICAgICAgICAgICAgICAgIGVycm9yTWVzc2FnZTogJ1RoZSBzdHJpbmcgY29udGFpbnMgYSBmb3JiaWRkZW4gdmFsdWUnXHJcbiAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICB9XHJcbiAgICAgICAgICApXHJcbiAgICAgIDogelxyXG4gICAgICAgICAgLnN0cmluZygpXHJcbiAgICAgICAgICAudHJpbSgpXHJcbiAgICAgICAgICAudHJhbnNmb3JtKCh2YWx1ZSkgPT5cclxuICAgICAgICAgICAgIVsnZmFsc2UnLCAndW5kZWZpbmVkJywgJ251bGwnLCAnJ10uaW5jbHVkZXModmFsdWUpID8gdmFsdWUgOiBudWxsXHJcbiAgICAgICAgICApXHJcbiAgICAgICAgICAubnVsbGFibGUoKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYGVudW1gIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGggYW4gb3B0aW9uYWwgc3RyaWN0ZXJcclxuICAgKiBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgc2NoZW1hIHdpbGwgdmFsaWRhdGUgYWdhaW5zdCB0aGUgcHJvdmlkZWQgYHZhbHVlc2AgYXJyYXkuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGF0OlxyXG4gICAqXHJcbiAgICogLSBXaGVuIGBzdHJpY3RDaGVja2AgaXMgdHJ1ZSwgdGhlIHNjaGVtYSB3aWxsIHZhbGlkYXRlIGFnYWluc3QgdGhlIGB2YWx1ZXNgXHJcbiAgICogYXJyYXkgd2l0aCB0aGUgZGVmYXVsdCBlbnVtIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIC0gV2hlbiBgc3RyaWN0Q2hlY2tgIGlzIGZhbHNlLCB0aGUgc2NoZW1hIHdpbGwgYWNjZXB0IGFsc28gbnVsbCxcclxuICAgKiAndW5kZWZpbmVkJywgJ251bGwnLCBhbmQgJycsIHdoaWNoIHdpbGwgYmUgdHJhbnNmb3JtZWQgdG8gbnVsbC5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiBlbnVtXHJcbiAgICpcclxuICAgKiBAcGFyYW0ge0FycmF5LjxzdHJpbmc+fSB2YWx1ZXMgLSBBbiBhcnJheSBvZiB2YWxpZCBzdHJpbmcgdmFsdWVzXHJcbiAgICogZm9yIHRoZSBlbnVtLlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZyBlbnVtIHZhbHVlcy5cclxuICAgKi9cclxuICBlbnVtKHZhbHVlcywgc3RyaWN0Q2hlY2spIHtcclxuICAgIHJldHVybiBzdHJpY3RDaGVja1xyXG4gICAgICA/IHouZW51bShbLi4udmFsdWVzXSlcclxuICAgICAgOiB6XHJcbiAgICAgICAgICAuZW51bShbLi4udmFsdWVzLCAndW5kZWZpbmVkJywgJ251bGwnLCAnJ10pXHJcbiAgICAgICAgICAudHJhbnNmb3JtKCh2YWx1ZSkgPT5cclxuICAgICAgICAgICAgIVsndW5kZWZpbmVkJywgJ251bGwnLCAnJ10uaW5jbHVkZXModmFsdWUpID8gdmFsdWUgOiBudWxsXHJcbiAgICAgICAgICApXHJcbiAgICAgICAgICAubnVsbGFibGUoKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYHN0cmluZ0FycmF5YCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoIGFuIG9wdGlvbmFsXHJcbiAgICogc3RyaWN0ZXIgY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhhdDpcclxuICAgKlxyXG4gICAqIC0gV2hlbiBgc3RyaWN0Q2hlY2tgIGlzIHRydWUsIHRoZSBzY2hlbWEgd2lsbCBhY2NlcHQgYW4gYXJyYXkgb2YgdHJpbW1lZFxyXG4gICAqIHN0cmluZyB2YWx1ZXMgZmlsdGVyZWQgYnkgdGhlIGxvZ2ljIHByb3ZpZGVkIHRocm91Z2ggdGhlIGBmaWx0ZXJDYWxsYmFja2AuXHJcbiAgICpcclxuICAgKiAtIFdoZW4gYHN0cmljdENoZWNrYCBpcyBmYWxzZSwgdGhlIHNjaGVtYSB3aWxsIGFjY2VwdCBudWxsIGFuZCB0cmltbWVkXHJcbiAgICogc3RyaW5nIHZhbHVlcyB3aGljaCB3aWxsIGJlIHNwbGl0dGVkIGludG8gYW4gYXJyYXkgb2Ygc3RyaW5ncyBhbmQgZmlsdGVyZWRcclxuICAgKiBmcm9tIHRoZSAnWycgYW5kICddJyBjaGFyYWN0ZXJzIGFuZCBieSB0aGUgbG9naWMgcHJvdmlkZWQgdGhyb3VnaFxyXG4gICAqIHRoZSBgZmlsdGVyQ2FsbGJhY2tgLiBJZiB0aGUgYXJyYXkgaXMgZW1wdHksIGl0IHdpbGwgYmUgdHJhbnNmb3JtZWRcclxuICAgKiB0byBudWxsLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIHN0cmluZ0FycmF5XHJcbiAgICpcclxuICAgKiBAcGFyYW0ge2Z1bmN0aW9ufSBmaWx0ZXJDYWxsYmFjayAtIFRoZSBmaWx0ZXIgY2FsbGJhY2suXHJcbiAgICogQHBhcmFtIHtzdHJpbmd9IHNlcGFyYXRvciAtIFRoZSBzZXBhcmF0b3IgZm9yIHNwbGl0aW5nIGEgc3RyaW5nLlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZyBhcnJheSBvZiBzdHJpbmdcclxuICAgKiB2YWx1ZXMuXHJcbiAgICovXHJcbiAgc3RyaW5nQXJyYXkoZmlsdGVyQ2FsbGJhY2ssIHNlcGFyYXRvciwgc3RyaWN0Q2hlY2spIHtcclxuICAgIGNvbnN0IGFycmF5U2NoZW1hID0gei5zdHJpbmcoKS50cmltKCkuYXJyYXkoKTtcclxuICAgIGNvbnN0IHN0cmluZ1NjaGVtYSA9IHpcclxuICAgICAgLnN0cmluZygpXHJcbiAgICAgIC50cmltKClcclxuICAgICAgLnRyYW5zZm9ybSgodmFsdWUpID0+IHtcclxuICAgICAgICBpZiAodmFsdWUuc3RhcnRzV2l0aCgnWycpKSB7XHJcbiAgICAgICAgICB2YWx1ZSA9IHZhbHVlLnNsaWNlKDEpO1xyXG4gICAgICAgIH1cclxuICAgICAgICBpZiAodmFsdWUuZW5kc1dpdGgoJ10nKSkge1xyXG4gICAgICAgICAgdmFsdWUgPSB2YWx1ZS5zbGljZSgwLCAtMSk7XHJcbiAgICAgICAgfVxyXG4gICAgICAgIHJldHVybiB2YWx1ZS5zcGxpdChzZXBhcmF0b3IpO1xyXG4gICAgICB9KTtcclxuXHJcbiAgICBjb25zdCB0cmFuc2Zvcm1DYWxsYmFjayA9ICh2YWx1ZSkgPT5cclxuICAgICAgdmFsdWUubWFwKCh2YWx1ZSkgPT4gdmFsdWUudHJpbSgpKS5maWx0ZXIoZmlsdGVyQ2FsbGJhY2spO1xyXG5cclxuICAgIHJldHVybiBzdHJpY3RDaGVja1xyXG4gICAgICA/IGFycmF5U2NoZW1hLnRyYW5zZm9ybSh0cmFuc2Zvcm1DYWxsYmFjaylcclxuICAgICAgOiB6XHJcbiAgICAgICAgICAudW5pb24oW3N0cmluZ1NjaGVtYSwgYXJyYXlTY2hlbWFdKVxyXG4gICAgICAgICAgLnRyYW5zZm9ybSh0cmFuc2Zvcm1DYWxsYmFjaylcclxuICAgICAgICAgIC50cmFuc2Zvcm0oKHZhbHVlKSA9PiAodmFsdWUubGVuZ3RoID8gdmFsdWUgOiBudWxsKSlcclxuICAgICAgICAgIC5udWxsYWJsZSgpO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgcG9zaXRpdmVOdW1gIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGggYW4gb3B0aW9uYWxcclxuICAgKiBzdHJpY3RlciBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGF0OlxyXG4gICAqXHJcbiAgICogLSBXaGVuIGBzdHJpY3RDaGVja2AgaXMgdHJ1ZSwgdGhlIHNjaGVtYSB3aWxsIGFjY2VwdCBwb3NpdGl2ZSBudW1iZXIgdmFsdWVzXHJcbiAgICogYW5kIHZhbGlkYXRlIGFnYWluc3QgdGhlIGRlZmF1bHQgcG9zaXRpdmUgbnVtYmVyIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIC0gV2hlbiBgc3RyaWN0Q2hlY2tgIGlzIGZhbHNlLCB0aGUgc2NoZW1hIHdpbGwgYWNjZXB0IHBvc2l0aXZlIG51bWJlclxyXG4gICAqIHZhbHVlcywgbnVsbCwgYW5kIHRyaW1tZWQgc3RyaW5nIHZhbHVlcyB0aGF0IGNhbiBlaXRoZXIgYmUgJ3VuZGVmaW5lZCcsXHJcbiAgICogJ251bGwnLCAnJywgb3IgcmVwcmVzZW50IGEgcG9zaXRpdmUgbnVtYmVyLiBJdCB3aWxsIHRyYW5zZm9ybSB0aGUgc3RyaW5nXHJcbiAgICogdG8gYSBwb3NpdGl2ZSBudW1iZXIsIG9yIHRvIG51bGwgaWYgaXQgaXMgJ3VuZGVmaW5lZCcsICdudWxsJywgb3IgJycuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gcG9zaXRpdmVOdW1cclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZyBwb3NpdGl2ZSBudW1iZXJcclxuICAgKiB2YWx1ZXMuXHJcbiAgICovXHJcbiAgcG9zaXRpdmVOdW0oc3RyaWN0Q2hlY2spIHtcclxuICAgIHJldHVybiBzdHJpY3RDaGVja1xyXG4gICAgICA/IHoubnVtYmVyKCkucG9zaXRpdmUoKVxyXG4gICAgICA6IHpcclxuICAgICAgICAgIC51bmlvbihbXHJcbiAgICAgICAgICAgIHpcclxuICAgICAgICAgICAgICAuc3RyaW5nKClcclxuICAgICAgICAgICAgICAudHJpbSgpXHJcbiAgICAgICAgICAgICAgLnJlZmluZShcclxuICAgICAgICAgICAgICAgICh2YWx1ZSkgPT5cclxuICAgICAgICAgICAgICAgICAgKCFpc05hTihOdW1iZXIodmFsdWUpKSAmJiBOdW1iZXIodmFsdWUpID4gMCkgfHxcclxuICAgICAgICAgICAgICAgICAgWyd1bmRlZmluZWQnLCAnbnVsbCcsICcnXS5pbmNsdWRlcyh2YWx1ZSksXHJcbiAgICAgICAgICAgICAgICB7XHJcbiAgICAgICAgICAgICAgICAgIHBhcmFtczoge1xyXG4gICAgICAgICAgICAgICAgICAgIGVycm9yTWVzc2FnZTogJ1RoZSB2YWx1ZSBtdXN0IGJlIG51bWVyaWMgYW5kIHBvc2l0aXZlJ1xyXG4gICAgICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgICAgKVxyXG4gICAgICAgICAgICAgIC50cmFuc2Zvcm0oKHZhbHVlKSA9PlxyXG4gICAgICAgICAgICAgICAgIVsndW5kZWZpbmVkJywgJ251bGwnLCAnJ10uaW5jbHVkZXModmFsdWUpXHJcbiAgICAgICAgICAgICAgICAgID8gTnVtYmVyKHZhbHVlKVxyXG4gICAgICAgICAgICAgICAgICA6IG51bGxcclxuICAgICAgICAgICAgICApLFxyXG4gICAgICAgICAgICB6Lm51bWJlcigpLnBvc2l0aXZlKClcclxuICAgICAgICAgIF0pXHJcbiAgICAgICAgICAubnVsbGFibGUoKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYG5vbk5lZ2F0aXZlTnVtYCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoIGFuIG9wdGlvbmFsXHJcbiAgICogc3RyaWN0ZXIgY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhhdDpcclxuICAgKlxyXG4gICAqIC0gV2hlbiBgc3RyaWN0Q2hlY2tgIGlzIHRydWUsIHRoZSBzY2hlbWEgd2lsbCBhY2NlcHQgbm9uLW5lZ2F0aXZlIG51bWJlclxyXG4gICAqIHZhbHVlcyBhbmQgdmFsaWRhdGUgYWdhaW5zdCB0aGUgZGVmYXVsdCBub24tbmVnYXRpdmUgbnVtYmVyIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIC0gV2hlbiBgc3RyaWN0Q2hlY2tgIGlzIGZhbHNlLCB0aGUgc2NoZW1hIHdpbGwgYWNjZXB0IG5vbi1uZWdhdGl2ZSBudW1iZXJcclxuICAgKiB2YWx1ZXMsIG51bGwsIGFuZCB0cmltbWVkIHN0cmluZyB2YWx1ZXMgdGhhdCBjYW4gZWl0aGVyIGJlICd1bmRlZmluZWQnLFxyXG4gICAqICdudWxsJywgJycsIG9yIHJlcHJlc2VudCBhIG5vbi1uZWdhdGl2ZSBudW1iZXIuIEl0IHdpbGwgdHJhbnNmb3JtXHJcbiAgICogdGhlIHN0cmluZyB0byBhIG5vbi1uZWdhdGl2ZSBudW1iZXIsIG9yIHRvIG51bGwgaWYgaXQgaXMgJ3VuZGVmaW5lZCcsXHJcbiAgICogJ251bGwnLCBvciAnJy5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiBub25OZWdhdGl2ZU51bVxyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nIG5vbi1uZWdhdGl2ZVxyXG4gICAqIG51bWJlciB2YWx1ZXMuXHJcbiAgICovXHJcbiAgbm9uTmVnYXRpdmVOdW0oc3RyaWN0Q2hlY2spIHtcclxuICAgIHJldHVybiBzdHJpY3RDaGVja1xyXG4gICAgICA/IHoubnVtYmVyKCkubm9ubmVnYXRpdmUoKVxyXG4gICAgICA6IHpcclxuICAgICAgICAgIC51bmlvbihbXHJcbiAgICAgICAgICAgIHpcclxuICAgICAgICAgICAgICAuc3RyaW5nKClcclxuICAgICAgICAgICAgICAudHJpbSgpXHJcbiAgICAgICAgICAgICAgLnJlZmluZShcclxuICAgICAgICAgICAgICAgICh2YWx1ZSkgPT5cclxuICAgICAgICAgICAgICAgICAgKCFpc05hTihOdW1iZXIodmFsdWUpKSAmJiBOdW1iZXIodmFsdWUpID49IDApIHx8XHJcbiAgICAgICAgICAgICAgICAgIFsndW5kZWZpbmVkJywgJ251bGwnLCAnJ10uaW5jbHVkZXModmFsdWUpLFxyXG4gICAgICAgICAgICAgICAge1xyXG4gICAgICAgICAgICAgICAgICBwYXJhbXM6IHtcclxuICAgICAgICAgICAgICAgICAgICBlcnJvck1lc3NhZ2U6ICdUaGUgdmFsdWUgbXVzdCBiZSBudW1lcmljIGFuZCBub24tbmVnYXRpdmUnXHJcbiAgICAgICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgICApXHJcbiAgICAgICAgICAgICAgLnRyYW5zZm9ybSgodmFsdWUpID0+XHJcbiAgICAgICAgICAgICAgICAhWyd1bmRlZmluZWQnLCAnbnVsbCcsICcnXS5pbmNsdWRlcyh2YWx1ZSlcclxuICAgICAgICAgICAgICAgICAgPyBOdW1iZXIodmFsdWUpXHJcbiAgICAgICAgICAgICAgICAgIDogbnVsbFxyXG4gICAgICAgICAgICAgICksXHJcbiAgICAgICAgICAgIHoubnVtYmVyKCkubm9ubmVnYXRpdmUoKVxyXG4gICAgICAgICAgXSlcclxuICAgICAgICAgIC5udWxsYWJsZSgpO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgc3RhcnRzV2l0aGAgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbFxyXG4gICAqIHN0cmljdGVyIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSBzY2hlbWEgd2lsbCB2YWxpZGF0ZSBhZ2FpbnN0IHRoZSBwcm92aWRlZCBgcHJlZml4ZXNgIGFycmF5IHRvIGNoZWNrXHJcbiAgICogd2hldGhlciBhIHN0cmluZyB2YWx1ZSBzdGFydHMgd2l0aCBhbnkgb2YgdGhlIHZhbHVlcyBwcm92aWRlZFxyXG4gICAqIGluIHRoZSBgcHJlZml4ZXNgIGFycmF5LlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhhdDpcclxuICAgKlxyXG4gICAqIC0gV2hlbiBgc3RyaWN0Q2hlY2tgIGlzIHRydWUsIHRoZSBzY2hlbWEgd2lsbCBhY2NlcHQgdHJpbW1lZCBzdHJpbmcgdmFsdWVzXHJcbiAgICogdGhhdCBzdGFydCB3aXRoIHZhbHVlcyBmcm9tIHRoZSBwcmVmaXhlcyBhcnJheS5cclxuICAgKlxyXG4gICAqIC0gV2hlbiBgc3RyaWN0Q2hlY2tgIGlzIGZhbHNlLCB0aGUgc2NoZW1hIHdpbGwgYWNjZXB0IHRyaW1tZWQgc3RyaW5nIHZhbHVlc1xyXG4gICAqIHRoYXQgc3RhcnQgd2l0aCB2YWx1ZXMgZnJvbSB0aGUgcHJlZml4ZXMgYXJyYXksIG51bGwsICd1bmRlZmluZWQnLCAnbnVsbCcsXHJcbiAgICogYW5kICcnIHdoZXJlIHRoZSBzY2hlbWEgd2lsbCB0cmFuc2Zvcm0gdGhlbSB0byBudWxsLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIHN0YXJ0c1dpdGhcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7QXJyYXkuPHN0cmluZz59IHByZWZpeGVzIC0gQW4gYXJyYXkgb2YgcHJlZml4ZXMgdG8gdmFsaWRhdGVcclxuICAgKiB0aGUgc3RyaW5nIGFnYWluc3QuXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nIHN0cmluZ3MgdGhhdFxyXG4gICAqIHN0YXJ0cyB3aXRoIHZhbHVlcy5cclxuICAgKi9cclxuICBzdGFydHNXaXRoKHByZWZpeGVzLCBzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHN0cmljdENoZWNrXHJcbiAgICAgID8gelxyXG4gICAgICAgICAgLnN0cmluZygpXHJcbiAgICAgICAgICAudHJpbSgpXHJcbiAgICAgICAgICAucmVmaW5lKFxyXG4gICAgICAgICAgICAodmFsdWUpID0+IHByZWZpeGVzLnNvbWUoKHByZWZpeCkgPT4gdmFsdWUuc3RhcnRzV2l0aChwcmVmaXgpKSxcclxuICAgICAgICAgICAge1xyXG4gICAgICAgICAgICAgIHBhcmFtczoge1xyXG4gICAgICAgICAgICAgICAgZXJyb3JNZXNzYWdlOiBgVGhlIHZhbHVlIG11c3QgYmUgYSBzdHJpbmcgdGhhdCBzdGFydHMgd2l0aCAke3ByZWZpeGVzLmpvaW4oJywgJyl9YFxyXG4gICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgfVxyXG4gICAgICAgICAgKVxyXG4gICAgICA6IHpcclxuICAgICAgICAgIC5zdHJpbmcoKVxyXG4gICAgICAgICAgLnRyaW0oKVxyXG4gICAgICAgICAgLnJlZmluZShcclxuICAgICAgICAgICAgKHZhbHVlKSA9PlxyXG4gICAgICAgICAgICAgIHByZWZpeGVzLnNvbWUoKHByZWZpeCkgPT4gdmFsdWUuc3RhcnRzV2l0aChwcmVmaXgpKSB8fFxyXG4gICAgICAgICAgICAgIFsndW5kZWZpbmVkJywgJ251bGwnLCAnJ10uaW5jbHVkZXModmFsdWUpLFxyXG4gICAgICAgICAgICB7XHJcbiAgICAgICAgICAgICAgcGFyYW1zOiB7XHJcbiAgICAgICAgICAgICAgICBlcnJvck1lc3NhZ2U6IGBUaGUgdmFsdWUgbXVzdCBiZSBhIHN0cmluZyB0aGF0IHN0YXJ0cyB3aXRoICR7cHJlZml4ZXMuam9pbignLCAnKX1gXHJcbiAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICB9XHJcbiAgICAgICAgICApXHJcbiAgICAgICAgICAudHJhbnNmb3JtKCh2YWx1ZSkgPT5cclxuICAgICAgICAgICAgIVsndW5kZWZpbmVkJywgJ251bGwnLCAnJ10uaW5jbHVkZXModmFsdWUpID8gdmFsdWUgOiBudWxsXHJcbiAgICAgICAgICApXHJcbiAgICAgICAgICAubnVsbGFibGUoKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYGNoYXJ0Q29uZmlnYCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYS5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoYXQgdGhlIHNjaGVtYSB3aWxsIGFjY2VwdCBvYmplY3QgdmFsdWVzXHJcbiAgICogb3IgdHJpbW1lZCBzdHJpbmcgdmFsdWVzIHRoYXQgY29udGFpbiAnPHN2Zycgb3IgJzw/eG1sJyBlbGVtZW50cywgc3RhcnRcclxuICAgKiB3aXRoIHRoZSAneycgYW5kIGVuZCB3aXRoIHRoZSAnfScsIGFuZCBudWxsLiBUaGUgJ3VuZGVmaW5lZCcsICdudWxsJyxcclxuICAgKiBhbmQgJycgdmFsdWVzIHdpbGwgYmUgdHJhbnNmb3JtZWQgdG8gbnVsbC5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiBjaGFydENvbmZpZ1xyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nIGNoYXJ0XHJcbiAgICogY29uZmlndXJhdGlvbiB2YWx1ZS5cclxuICAgKi9cclxuICBjaGFydENvbmZpZygpIHtcclxuICAgIHJldHVybiB6XHJcbiAgICAgIC51bmlvbihbXHJcbiAgICAgICAgelxyXG4gICAgICAgICAgLnN0cmluZygpXHJcbiAgICAgICAgICAudHJpbSgpXHJcbiAgICAgICAgICAucmVmaW5lKFxyXG4gICAgICAgICAgICAodmFsdWUpID0+XHJcbiAgICAgICAgICAgICAgKHZhbHVlLnN0YXJ0c1dpdGgoJ3snKSAmJiB2YWx1ZS5lbmRzV2l0aCgnfScpKSB8fFxyXG4gICAgICAgICAgICAgIFsndW5kZWZpbmVkJywgJ251bGwnLCAnJ10uaW5jbHVkZXModmFsdWUpLFxyXG4gICAgICAgICAgICB7XHJcbiAgICAgICAgICAgICAgcGFyYW1zOiB7XHJcbiAgICAgICAgICAgICAgICBlcnJvck1lc3NhZ2U6XHJcbiAgICAgICAgICAgICAgICAgIFwiVGhlIHZhbHVlIG11c3QgYmUgYSBzdHJpbmcgdGhhdCBzdGFydHMgd2l0aCAneycgYW5kIGVuZHMgd2l0aCAnfSdcIlxyXG4gICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgfVxyXG4gICAgICAgICAgKVxyXG4gICAgICAgICAgLnRyYW5zZm9ybSgodmFsdWUpID0+XHJcbiAgICAgICAgICAgICFbJ3VuZGVmaW5lZCcsICdudWxsJywgJyddLmluY2x1ZGVzKHZhbHVlKSA/IHZhbHVlIDogbnVsbFxyXG4gICAgICAgICAgKSxcclxuICAgICAgICB6Lm9iamVjdCh7fSkucGFzc3Rocm91Z2goKVxyXG4gICAgICBdKVxyXG4gICAgICAubnVsbGFibGUoKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYGFkZGl0aW9uYWxPcHRpb25zYCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYS5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoYXQgdGhlIHNjaGVtYSB3aWxsIGFjY2VwdCBvYmplY3QgdmFsdWVzXHJcbiAgICogb3IgdHJpbW1lZCBzdHJpbmcgdmFsdWVzIHRoYXQgZW5kIHdpdGggJy5qc29uJyBhbmQgYXJlIGF0IGxlYXN0IG9uZVxyXG4gICAqIGNoYXJhY3RlciBsb25nIGV4Y2x1ZGluZyB0aGUgZXh0ZW5zaW9uLCBzdGFydCB3aXRoIHRoZSAneycgYW5kIGVuZFxyXG4gICAqIHdpdGggdGhlICd9JywgYW5kIG51bGwuIFRoZSAndW5kZWZpbmVkJywgJ251bGwnLCBhbmQgJycgdmFsdWVzIHdpbGxcclxuICAgKiBiZSB0cmFuc2Zvcm1lZCB0byBudWxsLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIGFkZGl0aW9uYWxPcHRpb25zXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9ICBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nIGFkZGl0aW9uYWwgY2hhcnRcclxuICAgKiBvcHRpb25zIHZhbHVlLlxyXG4gICAqL1xyXG4gIGFkZGl0aW9uYWxPcHRpb25zKCkge1xyXG4gICAgcmV0dXJuIHpcclxuICAgICAgLnVuaW9uKFtcclxuICAgICAgICB6XHJcbiAgICAgICAgICAuc3RyaW5nKClcclxuICAgICAgICAgIC50cmltKClcclxuICAgICAgICAgIC5yZWZpbmUoXHJcbiAgICAgICAgICAgICh2YWx1ZSkgPT5cclxuICAgICAgICAgICAgICAodmFsdWUubGVuZ3RoID49IDYgJiYgdmFsdWUuZW5kc1dpdGgoJy5qc29uJykpIHx8XHJcbiAgICAgICAgICAgICAgKHZhbHVlLnN0YXJ0c1dpdGgoJ3snKSAmJiB2YWx1ZS5lbmRzV2l0aCgnfScpKSB8fFxyXG4gICAgICAgICAgICAgIFsndW5kZWZpbmVkJywgJ251bGwnLCAnJ10uaW5jbHVkZXModmFsdWUpLFxyXG4gICAgICAgICAgICB7XHJcbiAgICAgICAgICAgICAgcGFyYW1zOiB7XHJcbiAgICAgICAgICAgICAgICBlcnJvck1lc3NhZ2U6XHJcbiAgICAgICAgICAgICAgICAgIFwiVGhlIHZhbHVlIG11c3QgYmUgYSBzdHJpbmcgdGhhdCBlbmRzIHdpdGggJy5qc29uJyBvciBzdGFydHMgd2l0aCAneycgYW5kIGVuZHMgd2l0aCAnfSdcIlxyXG4gICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgfVxyXG4gICAgICAgICAgKVxyXG4gICAgICAgICAgLnRyYW5zZm9ybSgodmFsdWUpID0+XHJcbiAgICAgICAgICAgICFbJ3VuZGVmaW5lZCcsICdudWxsJywgJyddLmluY2x1ZGVzKHZhbHVlKSA/IHZhbHVlIDogbnVsbFxyXG4gICAgICAgICAgKSxcclxuICAgICAgICB6Lm9iamVjdCh7fSkucGFzc3Rocm91Z2goKVxyXG4gICAgICBdKVxyXG4gICAgICAubnVsbGFibGUoKTtcclxuICB9XHJcbn07XHJcblxyXG4vKipcclxuICogT2JqZWN0IGNvbnRhaW5pbmcgY3VzdG9tIGNvbmZpZyB2YWxpZGF0b3JzIGFuZCBwYXJzZXJzIHRvIGF2b2lkIHJlcGV0aXRpb25cclxuICogaW4gc2NoZW1hIG9iamVjdHMuIEFsbCB2YWxpZGF0b3JzIGFwcGx5IHRvIHZhbHVlcyBmcm9tIHZhcmlvdXMgc291cmNlcyxcclxuICogaW5jbHVkaW5nIHRoZSBkZWZhdWx0IGNvbmZpZyBmaWxlLCBhIGN1c3RvbSBKU09OIGZpbGUgbG9hZGVkIHdpdGggdGhlIG9wdGlvblxyXG4gKiBjYWxsZWQgYGxvYWRDb25maWdgLCB0aGUgLmVudiBmaWxlLCBDTEkgYXJndW1lbnRzLCBhbmQgdGhlIHJlcXVlc3QgcGF5bG9hZC5cclxuICogVGhlIGBzdHJpY3RDaGVja2AgZmxhZyBlbmFibGVzIHN0cmljdGVyIHZhbGlkYXRpb24gYW5kIHBhcnNpbmcgcnVsZXMuIFRoaXNcclxuICogZmxhZyBpcyBzZXQgdG8gZmFsc2UgZm9yIHZhbHVlcyB0aGF0IGNvbWUgZnJvbSB0aGUgLmVudiBmaWxlIG9yIENMSSBhcmd1bWVudHNcclxuICogYmVjYXVzZSB0aGV5IGFyZSBwcm92aWRlZCBhcyBzdHJpbmdzIGFuZCBuZWVkIHRvIGJlIHBhcnNlZCBhY2NvcmRpbmdseSBmaXJzdC5cclxuICovXHJcbmV4cG9ydCBjb25zdCB2YWxpZGF0b3JzID0ge1xyXG4gIC8qKlxyXG4gICAqIFRoZSBgYXJnc2AgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbCBzdHJpY3RlclxyXG4gICAqIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgdGhlIGBzdHJpbmdBcnJheWAgdmFsaWRhdG9yLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIGFyZ3NcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZyB0aGUgYGFyZ3NgXHJcbiAgICogb3B0aW9uLlxyXG4gICAqL1xyXG4gIGFyZ3Moc3RyaWN0Q2hlY2spIHtcclxuICAgIHJldHVybiB2LnN0cmluZ0FycmF5KFxyXG4gICAgICAodmFsdWUpID0+ICFbJ2ZhbHNlJywgJ3VuZGVmaW5lZCcsICdudWxsJywgJyddLmluY2x1ZGVzKHZhbHVlKSxcclxuICAgICAgJzsnLFxyXG4gICAgICBzdHJpY3RDaGVja1xyXG4gICAgKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYHZlcnNpb25gIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGggYW4gb3B0aW9uYWwgc3RyaWN0ZXJcclxuICAgKiBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGF0OlxyXG4gICAqXHJcbiAgICogLSBXaGVuIGBzdHJpY3RDaGVja2AgaXMgdHJ1ZSwgdGhlIHNjaGVtYSB3aWxsIGFjY2VwdCB0cmltbWVkIHN0cmluZyB2YWx1ZXNcclxuICAgKiB0aGF0IGFyZSBhIFJlZ0V4cC1iYXNlZCB0aGF0IGFsbG93cyB0byBiZSAnbGF0ZXN0Jywgb3IgaW4gdGhlIGZvcm1hdCBYWCxcclxuICAgKiBYWC5ZWSwgb3IgWFguWVkuWlosIHdoZXJlIFhYLCBZWSwgYW5kIFpaIGFyZSBudW1lcmljIGZvciB0aGUgSGlnaGNoYXJ0c1xyXG4gICAqIHZlcnNpb24gb3B0aW9uLlxyXG4gICAqXHJcbiAgICogLSBXaGVuIGBzdHJpY3RDaGVja2AgaXMgZmFsc2UsIHRoZSBzY2hlbWEgd2lsbCBhY2NlcHQgYWxzbyBudWxsLFxyXG4gICAqICd1bmRlZmluZWQnLCAnbnVsbCcsIG9yICcnIGFuZCBpbiBhbGwgY2FzZXMgdGhlIHNjaGVtYSB3aWxsIHRyYW5zZm9ybSB0aGVtXHJcbiAgICogdG8gbnVsbC5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiB2ZXJzaW9uXHJcbiAgICpcclxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IHN0cmljdENoZWNrIC0gRGV0ZXJtaW5lcyBpZiBzdHJpY3RlciB2YWxpZGF0aW9uIHNob3VsZFxyXG4gICAqIGJlIGFwcGxpZWQuXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9IEEgWm9kIHNjaGVtYSBvYmplY3QgZm9yIHZhbGlkYXRpbmcgdGhlIGB2ZXJzaW9uYFxyXG4gICAqIG9wdGlvbi5cclxuICAgKi9cclxuICB2ZXJzaW9uKHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gc3RyaWN0Q2hlY2tcclxuICAgICAgPyB6XHJcbiAgICAgICAgICAuc3RyaW5nKClcclxuICAgICAgICAgIC50cmltKClcclxuICAgICAgICAgIC5yZWZpbmUoKHZhbHVlKSA9PiAvXihsYXRlc3R8XFxkezEsMn0oXFwuXFxkezEsMn0pezAsMn0pJC8udGVzdCh2YWx1ZSksIHtcclxuICAgICAgICAgICAgcGFyYW1zOiB7XHJcbiAgICAgICAgICAgICAgZXJyb3JNZXNzYWdlOlxyXG4gICAgICAgICAgICAgICAgXCJUaGUgdmFsdWUgbXVzdCBiZSAnbGF0ZXN0JywgYSBtYWpvciB2ZXJzaW9uLCBvciBpbiB0aGUgZm9ybSBYWC5ZWS5aWlwiXHJcbiAgICAgICAgICAgIH1cclxuICAgICAgICAgIH0pXHJcbiAgICAgIDogelxyXG4gICAgICAgICAgLnN0cmluZygpXHJcbiAgICAgICAgICAudHJpbSgpXHJcbiAgICAgICAgICAucmVmaW5lKFxyXG4gICAgICAgICAgICAodmFsdWUpID0+XHJcbiAgICAgICAgICAgICAgL14obGF0ZXN0fFxcZHsxLDJ9KFxcLlxcZHsxLDJ9KXswLDJ9KSQvLnRlc3QodmFsdWUpIHx8XHJcbiAgICAgICAgICAgICAgWyd1bmRlZmluZWQnLCAnbnVsbCcsICcnXS5pbmNsdWRlcyh2YWx1ZSksXHJcbiAgICAgICAgICAgIHtcclxuICAgICAgICAgICAgICBwYXJhbXM6IHtcclxuICAgICAgICAgICAgICAgIGVycm9yTWVzc2FnZTpcclxuICAgICAgICAgICAgICAgICAgXCJUaGUgdmFsdWUgbXVzdCBiZSAnbGF0ZXN0JywgYSBtYWpvciB2ZXJzaW9uLCBvciBpbiB0aGUgZm9ybSBYWC5ZWS5aWlwiXHJcbiAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICB9XHJcbiAgICAgICAgICApXHJcbiAgICAgICAgICAudHJhbnNmb3JtKCh2YWx1ZSkgPT5cclxuICAgICAgICAgICAgIVsndW5kZWZpbmVkJywgJ251bGwnLCAnJ10uaW5jbHVkZXModmFsdWUpID8gdmFsdWUgOiBudWxsXHJcbiAgICAgICAgICApXHJcbiAgICAgICAgICAubnVsbGFibGUoKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYGNkblVybGAgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbCBzdHJpY3RlclxyXG4gICAqIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgdGhlIGBzdGFydHNXaXRoYCB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gY2RuVXJsXHJcbiAgICpcclxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IHN0cmljdENoZWNrIC0gRGV0ZXJtaW5lcyBpZiBzdHJpY3RlciB2YWxpZGF0aW9uIHNob3VsZFxyXG4gICAqIGJlIGFwcGxpZWQuXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9IEEgWm9kIHNjaGVtYSBvYmplY3QgZm9yIHZhbGlkYXRpbmcgdGhlIGBjZG5VcmxgXHJcbiAgICogb3B0aW9uLlxyXG4gICAqL1xyXG4gIGNkblVybChzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHYuc3RhcnRzV2l0aChbJ2h0dHA6Ly8nLCAnaHR0cHM6Ly8nXSwgc3RyaWN0Q2hlY2spO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgZm9yY2VGZXRjaGAgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbFxyXG4gICAqIHN0cmljdGVyIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgdGhlIGBib29sZWFuYCB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gZm9yY2VGZXRjaFxyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nIHRoZSBgZm9yY2VGZXRjaGBcclxuICAgKiBvcHRpb24uXHJcbiAgICovXHJcbiAgZm9yY2VGZXRjaChzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHYuYm9vbGVhbihzdHJpY3RDaGVjayk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGBjYWNoZVBhdGhgIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGggYW4gb3B0aW9uYWxcclxuICAgKiBzdHJpY3RlciBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGUgc2FtZSB3b3JrIGFzIHRoZSBgc3RyaW5nYCB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gY2FjaGVQYXRoXHJcbiAgICpcclxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IHN0cmljdENoZWNrIC0gRGV0ZXJtaW5lcyBpZiBzdHJpY3RlciB2YWxpZGF0aW9uIHNob3VsZFxyXG4gICAqIGJlIGFwcGxpZWQuXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9IEEgWm9kIHNjaGVtYSBvYmplY3QgZm9yIHZhbGlkYXRpbmcgdGhlIGBjYWNoZVBhdGhgXHJcbiAgICogb3B0aW9uLlxyXG4gICAqL1xyXG4gIGNhY2hlUGF0aChzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHYuc3RyaW5nKHN0cmljdENoZWNrKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYGFkbWluVG9rZW5gIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGggYW4gb3B0aW9uYWxcclxuICAgKiBzdHJpY3RlciBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGUgc2FtZSB3b3JrIGFzIHRoZSBgc3RyaW5nYCB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gYWRtaW5Ub2tlblxyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nIHRoZSBgYWRtaW5Ub2tlbmBcclxuICAgKiBvcHRpb24uXHJcbiAgICovXHJcbiAgYWRtaW5Ub2tlbihzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHYuc3RyaW5nKHN0cmljdENoZWNrKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYGNvcmVTY3JpcHRzYCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoIGFuIG9wdGlvbmFsXHJcbiAgICogc3RyaWN0ZXIgY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhlIHNhbWUgd29yayBhcyB0aGUgYHN0cmluZ0FycmF5YCB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gY29yZVNjcmlwdHNcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZyB0aGUgYGNvcmVTY3JpcHRzYFxyXG4gICAqIG9wdGlvbi5cclxuICAgKi9cclxuICBjb3JlU2NyaXB0cyhzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHYuc3RyaW5nQXJyYXkoXHJcbiAgICAgICh2YWx1ZSkgPT4gY29yZVNjcmlwdHMudmFsdWUuaW5jbHVkZXModmFsdWUpLFxyXG4gICAgICAnLCcsXHJcbiAgICAgIHN0cmljdENoZWNrXHJcbiAgICApO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgbW9kdWxlU2NyaXB0c2AgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbFxyXG4gICAqIHN0cmljdGVyIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgdGhlIGBzdHJpbmdBcnJheWAgdmFsaWRhdG9yLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIG1vZHVsZVNjcmlwdHNcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZ1xyXG4gICAqIHRoZSBgbW9kdWxlU2NyaXB0c2Agb3B0aW9uLlxyXG4gICAqL1xyXG4gIG1vZHVsZVNjcmlwdHMoc3RyaWN0Q2hlY2spIHtcclxuICAgIHJldHVybiB2LnN0cmluZ0FycmF5KFxyXG4gICAgICAodmFsdWUpID0+IG1vZHVsZVNjcmlwdHMudmFsdWUuaW5jbHVkZXModmFsdWUpLFxyXG4gICAgICAnLCcsXHJcbiAgICAgIHN0cmljdENoZWNrXHJcbiAgICApO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgaW5kaWNhdG9yU2NyaXB0c2AgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbFxyXG4gICAqIHN0cmljdGVyIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgdGhlIGBzdHJpbmdBcnJheWAgdmFsaWRhdG9yLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIGluZGljYXRvclNjcmlwdHNcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZ1xyXG4gICAqIHRoZSBgaW5kaWNhdG9yU2NyaXB0c2Agb3B0aW9uLlxyXG4gICAqL1xyXG4gIGluZGljYXRvclNjcmlwdHMoc3RyaWN0Q2hlY2spIHtcclxuICAgIHJldHVybiB2LnN0cmluZ0FycmF5KFxyXG4gICAgICAodmFsdWUpID0+IGluZGljYXRvclNjcmlwdHMudmFsdWUuaW5jbHVkZXModmFsdWUpLFxyXG4gICAgICAnLCcsXHJcbiAgICAgIHN0cmljdENoZWNrXHJcbiAgICApO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgY3VzdG9tU2NyaXB0c2AgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbFxyXG4gICAqIHN0cmljdGVyIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgdGhlIGBzdHJpbmdBcnJheWAgdmFsaWRhdG9yLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIGN1c3RvbVNjcmlwdHNcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZ1xyXG4gICAqIHRoZSBgY3VzdG9tU2NyaXB0c2Agb3B0aW9uLlxyXG4gICAqL1xyXG4gIGN1c3RvbVNjcmlwdHMoc3RyaWN0Q2hlY2spIHtcclxuICAgIHJldHVybiB2LnN0cmluZ0FycmF5KFxyXG4gICAgICAodmFsdWUpID0+IHZhbHVlLnN0YXJ0c1dpdGgoJ2h0dHBzOi8vJykgfHwgdmFsdWUuc3RhcnRzV2l0aCgnaHR0cDovLycpLFxyXG4gICAgICAnLCcsXHJcbiAgICAgIHN0cmljdENoZWNrXHJcbiAgICApO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgaW5maWxlYCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoIGFuIG9wdGlvbmFsIHN0cmljdGVyXHJcbiAgICogY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhhdDpcclxuICAgKlxyXG4gICAqIC0gV2hlbiBgc3RyaWN0Q2hlY2tgIGlzIHRydWUsIHRoZSBzY2hlbWEgd2lsbCBhY2NlcHQgdHJpbW1lZCBzdHJpbmcgdmFsdWVzXHJcbiAgICogdGhhdCBlbmQgd2l0aCAnLmpzb24nIG9yICcuc3ZnJywgYXJlIGF0IGxlYXN0IG9uZSBjaGFyYWN0ZXIgbG9uZyBleGNsdWRpbmdcclxuICAgKiB0aGUgZXh0ZW5zaW9uLCBvciBudWxsLlxyXG4gICAqXHJcbiAgICogLSBXaGVuIGBzdHJpY3RDaGVja2AgaXMgZmFsc2UsIHRoZSBzY2hlbWEgd2lsbCBhY2NlcHQgdHJpbW1lZCBzdHJpbmcgdmFsdWVzXHJcbiAgICogdGhhdCBlbmQgd2l0aCAnLmpzb24nIG9yICcuc3ZnJywgYXJlIGF0IGxlYXN0IG9uZSBjaGFyYWN0ZXIgbG9uZyBleGNsdWRpbmdcclxuICAgKiB0aGUgZXh0ZW5zaW9uIGFuZCB3aWxsIGJlIG51bGwgaWYgdGhlIHByb3ZpZGVkIHZhbHVlIGlzIG51bGwsICd1bmRlZmluZWQnLFxyXG4gICAqICdudWxsJywgb3IgJycuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gaW5maWxlXHJcbiAgICpcclxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IHN0cmljdENoZWNrIC0gRGV0ZXJtaW5lcyBpZiBzdHJpY3RlciB2YWxpZGF0aW9uIHNob3VsZFxyXG4gICAqIGJlIGFwcGxpZWQuXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9IEEgWm9kIHNjaGVtYSBvYmplY3QgZm9yIHZhbGlkYXRpbmcgdGhlIGBpbmZpbGVgXHJcbiAgICogb3B0aW9uLlxyXG4gICAqL1xyXG4gIGluZmlsZShzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHN0cmljdENoZWNrXHJcbiAgICAgID8gelxyXG4gICAgICAgICAgLnN0cmluZygpXHJcbiAgICAgICAgICAudHJpbSgpXHJcbiAgICAgICAgICAucmVmaW5lKFxyXG4gICAgICAgICAgICAodmFsdWUpID0+XHJcbiAgICAgICAgICAgICAgKHZhbHVlLmxlbmd0aCA+PSA2ICYmIHZhbHVlLmVuZHNXaXRoKCcuanNvbicpKSB8fFxyXG4gICAgICAgICAgICAgICh2YWx1ZS5sZW5ndGggPj0gNSAmJiB2YWx1ZS5lbmRzV2l0aCgnLnN2ZycpKSxcclxuICAgICAgICAgICAge1xyXG4gICAgICAgICAgICAgIHBhcmFtczoge1xyXG4gICAgICAgICAgICAgICAgZXJyb3JNZXNzYWdlOlxyXG4gICAgICAgICAgICAgICAgICAnVGhlIHZhbHVlIG11c3QgYmUgYSBzdHJpbmcgdGhhdCBlbmRzIHdpdGggLmpzb24gb3IgLnN2ZydcclxuICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgIH1cclxuICAgICAgICAgIClcclxuICAgICAgICAgIC5udWxsYWJsZSgpXHJcbiAgICAgIDogelxyXG4gICAgICAgICAgLnN0cmluZygpXHJcbiAgICAgICAgICAudHJpbSgpXHJcbiAgICAgICAgICAucmVmaW5lKFxyXG4gICAgICAgICAgICAodmFsdWUpID0+XHJcbiAgICAgICAgICAgICAgKHZhbHVlLmxlbmd0aCA+PSA2ICYmIHZhbHVlLmVuZHNXaXRoKCcuanNvbicpKSB8fFxyXG4gICAgICAgICAgICAgICh2YWx1ZS5sZW5ndGggPj0gNSAmJiB2YWx1ZS5lbmRzV2l0aCgnLnN2ZycpKSB8fFxyXG4gICAgICAgICAgICAgIFsndW5kZWZpbmVkJywgJ251bGwnLCAnJ10uaW5jbHVkZXModmFsdWUpLFxyXG4gICAgICAgICAgICB7XHJcbiAgICAgICAgICAgICAgcGFyYW1zOiB7XHJcbiAgICAgICAgICAgICAgICBlcnJvck1lc3NhZ2U6XHJcbiAgICAgICAgICAgICAgICAgICdUaGUgdmFsdWUgbXVzdCBiZSBhIHN0cmluZyB0aGF0IGVuZHMgd2l0aCAuanNvbiBvciAuc3ZnJ1xyXG4gICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgfVxyXG4gICAgICAgICAgKVxyXG4gICAgICAgICAgLnRyYW5zZm9ybSgodmFsdWUpID0+XHJcbiAgICAgICAgICAgICFbJ3VuZGVmaW5lZCcsICdudWxsJywgJyddLmluY2x1ZGVzKHZhbHVlKSA/IHZhbHVlIDogbnVsbFxyXG4gICAgICAgICAgKVxyXG4gICAgICAgICAgLm51bGxhYmxlKCk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGBpbnN0cmAgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGUgc2FtZSB3b3JrIGFzIHRoZSBgb3B0aW9uc2AgdmFsaWRhdG9yLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIGluc3RyXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9IEEgWm9kIHNjaGVtYSBvYmplY3QgZm9yIHZhbGlkYXRpbmcgdGhlIGBpbnN0cmBcclxuICAgKiBvcHRpb24uXHJcbiAgICovXHJcbiAgaW5zdHIoKSB7XHJcbiAgICByZXR1cm4gdi5jaGFydENvbmZpZygpO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgb3B0aW9uc2AgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGUgc2FtZSB3b3JrIGFzIHRoZSBgb3B0aW9uc2AgdmFsaWRhdG9yLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIG9wdGlvbnNcclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZyB0aGUgYG9wdGlvbnNgXHJcbiAgICogb3B0aW9uLlxyXG4gICAqL1xyXG4gIG9wdGlvbnMoKSB7XHJcbiAgICByZXR1cm4gdi5jaGFydENvbmZpZygpO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgc3ZnYCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYS5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoYXQgdGhlIHNjaGVtYSB3aWxsIGFjY2VwdCBvYmplY3QgdmFsdWVzXHJcbiAgICogb3IgdHJpbW1lZCBzdHJpbmcgdmFsdWVzIHRoYXQgY29udGFpbiAnPHN2Zycgb3IgJzw/eG1sJyBlbGVtZW50cyBhbmQgbnVsbC5cclxuICAgKiBUaGUgJ3VuZGVmaW5lZCcsICdudWxsJywgYW5kICcnIHZhbHVlcyB3aWxsIGJlIHRyYW5zZm9ybWVkIHRvIG51bGwuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gc3ZnXHJcbiAgICpcclxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IHN0cmljdENoZWNrIC0gRGV0ZXJtaW5lcyBpZiBzdHJpY3RlciB2YWxpZGF0aW9uIHNob3VsZFxyXG4gICAqIGJlIGFwcGxpZWQuXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9IEEgWm9kIHNjaGVtYSBvYmplY3QgZm9yIHZhbGlkYXRpbmcgdGhlIGBzdmdgIG9wdGlvbi5cclxuICAgKi9cclxuICBzdmcoKSB7XHJcbiAgICByZXR1cm4gelxyXG4gICAgICAuc3RyaW5nKClcclxuICAgICAgLnRyaW0oKVxyXG4gICAgICAucmVmaW5lKFxyXG4gICAgICAgICh2YWx1ZSkgPT5cclxuICAgICAgICAgIHZhbHVlLmluZGV4T2YoJzxzdmcnKSA+PSAwIHx8XHJcbiAgICAgICAgICB2YWx1ZS5pbmRleE9mKCc8P3htbCcpID49IDAgfHxcclxuICAgICAgICAgIFsnZmFsc2UnLCAndW5kZWZpbmVkJywgJ251bGwnLCAnJ10uaW5jbHVkZXModmFsdWUpLFxyXG4gICAgICAgIHtcclxuICAgICAgICAgIHBhcmFtczoge1xyXG4gICAgICAgICAgICBlcnJvck1lc3NhZ2U6XHJcbiAgICAgICAgICAgICAgXCJUaGUgdmFsdWUgbXVzdCBiZSBhIHN0cmluZyB0aGF0IGNvbnRhaW5zICc8c3ZnJyBvciAnPD94bWwnXCJcclxuICAgICAgICAgIH1cclxuICAgICAgICB9XHJcbiAgICAgIClcclxuICAgICAgLnRyYW5zZm9ybSgodmFsdWUpID0+XHJcbiAgICAgICAgIVsnZmFsc2UnLCAndW5kZWZpbmVkJywgJ251bGwnLCAnJ10uaW5jbHVkZXModmFsdWUpID8gdmFsdWUgOiBudWxsXHJcbiAgICAgIClcclxuICAgICAgLm51bGxhYmxlKCk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGBvdXRmaWxlYCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoIGFuIG9wdGlvbmFsIHN0cmljdGVyXHJcbiAgICogY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhhdDpcclxuICAgKlxyXG4gICAqIC0gV2hlbiBgc3RyaWN0Q2hlY2tgIGlzIHRydWUsIHRoZSBzY2hlbWEgd2lsbCBhY2NlcHQgdHJpbW1lZCBzdHJpbmcgdmFsdWVzXHJcbiAgICogdGhhdCBlbmQgd2l0aCAnLmpwZWcnLCAnLmpwZycsICcucG5nJywgJy5wZGYnLCBvciAnLnN2ZycsIGFyZSBhdCBsZWFzdCBvbmVcclxuICAgKiBjaGFyYWN0ZXIgbG9uZyBleGNsdWRpbmcgdGhlIGV4dGVuc2lvbiwgb3IgbnVsbC5cclxuICAgKlxyXG4gICAqIC0gV2hlbiBgc3RyaWN0Q2hlY2tgIGlzIGZhbHNlLCB0aGUgc2NoZW1hIHdpbGwgYWNjZXB0IHRyaW1tZWQgc3RyaW5nIHZhbHVlc1xyXG4gICAqIHRoYXQgZW5kIHdpdGggJy5qcGVnJywgJy5qcGcnLCAnLnBuZycsICcucGRmJywgb3IgJy5zdmcnLCBhcmUgYXQgbGVhc3Qgb25lXHJcbiAgICogY2hhcmFjdGVyIGxvbmcgZXhjbHVkaW5nIHRoZSBleHRlbnNpb24gYW5kIHdpbGwgYmUgbnVsbCBpZiB0aGUgcHJvdmlkZWRcclxuICAgKiB2YWx1ZSBpcyBudWxsLCAndW5kZWZpbmVkJywgJ251bGwnLCBvciAnJy5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiBvdXRmaWxlXHJcbiAgICpcclxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IHN0cmljdENoZWNrIC0gRGV0ZXJtaW5lcyBpZiBzdHJpY3RlciB2YWxpZGF0aW9uIHNob3VsZFxyXG4gICAqIGJlIGFwcGxpZWQuXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9IEEgWm9kIHNjaGVtYSBvYmplY3QgZm9yIHZhbGlkYXRpbmcgdGhlIGBvdXRmaWxlYFxyXG4gICAqIG9wdGlvbi5cclxuICAgKi9cclxuICBvdXRmaWxlKHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gc3RyaWN0Q2hlY2tcclxuICAgICAgPyB6XHJcbiAgICAgICAgICAuc3RyaW5nKClcclxuICAgICAgICAgIC50cmltKClcclxuICAgICAgICAgIC5yZWZpbmUoXHJcbiAgICAgICAgICAgICh2YWx1ZSkgPT5cclxuICAgICAgICAgICAgICAodmFsdWUubGVuZ3RoID49IDYgJiYgdmFsdWUuZW5kc1dpdGgoJy5qcGVnJykpIHx8XHJcbiAgICAgICAgICAgICAgKHZhbHVlLmxlbmd0aCA+PSA1ICYmXHJcbiAgICAgICAgICAgICAgICAodmFsdWUuZW5kc1dpdGgoJy5qcGcnKSB8fFxyXG4gICAgICAgICAgICAgICAgICB2YWx1ZS5lbmRzV2l0aCgnLnBuZycpIHx8XHJcbiAgICAgICAgICAgICAgICAgIHZhbHVlLmVuZHNXaXRoKCcucGRmJykgfHxcclxuICAgICAgICAgICAgICAgICAgdmFsdWUuZW5kc1dpdGgoJy5zdmcnKSkpLFxyXG4gICAgICAgICAgICB7XHJcbiAgICAgICAgICAgICAgcGFyYW1zOiB7XHJcbiAgICAgICAgICAgICAgICBlcnJvck1lc3NhZ2U6XHJcbiAgICAgICAgICAgICAgICAgICdUaGUgdmFsdWUgbXVzdCBiZSBhIHN0cmluZyB0aGF0IGVuZHMgd2l0aCAuanBlZywgLmpwZywgLnBuZywgLnBkZiwgb3IgLnN2ZydcclxuICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgIH1cclxuICAgICAgICAgIClcclxuICAgICAgICAgIC5udWxsYWJsZSgpXHJcbiAgICAgIDogelxyXG4gICAgICAgICAgLnN0cmluZygpXHJcbiAgICAgICAgICAudHJpbSgpXHJcbiAgICAgICAgICAucmVmaW5lKFxyXG4gICAgICAgICAgICAodmFsdWUpID0+XHJcbiAgICAgICAgICAgICAgKHZhbHVlLmxlbmd0aCA+PSA2ICYmIHZhbHVlLmVuZHNXaXRoKCcuanBlZycpKSB8fFxyXG4gICAgICAgICAgICAgICh2YWx1ZS5sZW5ndGggPj0gNSAmJlxyXG4gICAgICAgICAgICAgICAgKHZhbHVlLmVuZHNXaXRoKCcuanBnJykgfHxcclxuICAgICAgICAgICAgICAgICAgdmFsdWUuZW5kc1dpdGgoJy5wbmcnKSB8fFxyXG4gICAgICAgICAgICAgICAgICB2YWx1ZS5lbmRzV2l0aCgnLnBkZicpIHx8XHJcbiAgICAgICAgICAgICAgICAgIHZhbHVlLmVuZHNXaXRoKCcuc3ZnJykpKSB8fFxyXG4gICAgICAgICAgICAgIFsndW5kZWZpbmVkJywgJ251bGwnLCAnJ10uaW5jbHVkZXModmFsdWUpLFxyXG4gICAgICAgICAgICB7XHJcbiAgICAgICAgICAgICAgcGFyYW1zOiB7XHJcbiAgICAgICAgICAgICAgICBlcnJvck1lc3NhZ2U6XHJcbiAgICAgICAgICAgICAgICAgICdUaGUgdmFsdWUgbXVzdCBiZSBhIHN0cmluZyB0aGF0IGVuZHMgd2l0aCAuanBlZywgLmpwZywgLnBuZywgLnBkZiwgb3IgLnN2ZydcclxuICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgIH1cclxuICAgICAgICAgIClcclxuICAgICAgICAgIC50cmFuc2Zvcm0oKHZhbHVlKSA9PlxyXG4gICAgICAgICAgICAhWyd1bmRlZmluZWQnLCAnbnVsbCcsICcnXS5pbmNsdWRlcyh2YWx1ZSkgPyB2YWx1ZSA6IG51bGxcclxuICAgICAgICAgIClcclxuICAgICAgICAgIC5udWxsYWJsZSgpO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgdHlwZWAgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbCBzdHJpY3RlclxyXG4gICAqIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgdGhlIGBlbnVtYCB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gdHlwZVxyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nIHRoZSBgdHlwZWBcclxuICAgKiBvcHRpb24uXHJcbiAgICovXHJcbiAgdHlwZShzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHYuZW51bShbJ2pwZWcnLCAnanBnJywgJ3BuZycsICdwZGYnLCAnc3ZnJ10sIHN0cmljdENoZWNrKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYGNvbnN0cmAgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbCBzdHJpY3RlclxyXG4gICAqIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgdGhlIGBlbnVtYCB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gY29uc3RyXHJcbiAgICpcclxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IHN0cmljdENoZWNrIC0gRGV0ZXJtaW5lcyBpZiBzdHJpY3RlciB2YWxpZGF0aW9uIHNob3VsZFxyXG4gICAqIGJlIGFwcGxpZWQuXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9IEEgWm9kIHNjaGVtYSBvYmplY3QgZm9yIHZhbGlkYXRpbmcgdGhlIGBjb25zdHJgXHJcbiAgICogb3B0aW9uLlxyXG4gICAqL1xyXG4gIGNvbnN0cihzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHYuZW51bShcclxuICAgICAgWydjaGFydCcsICdzdG9ja0NoYXJ0JywgJ21hcENoYXJ0JywgJ2dhbnR0Q2hhcnQnXSxcclxuICAgICAgc3RyaWN0Q2hlY2tcclxuICAgICk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGBiNjRgIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGggYW4gb3B0aW9uYWwgc3RyaWN0ZXJcclxuICAgKiBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGUgc2FtZSB3b3JrIGFzIHRoZSBgYm9vbGVhbmAgdmFsaWRhdG9yLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIGI2NFxyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nIHRoZSBgYjY0YCBvcHRpb24uXHJcbiAgICovXHJcbiAgYjY0KHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gdi5ib29sZWFuKHN0cmljdENoZWNrKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYG5vRG93bmxvYWRgIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGggYW4gb3B0aW9uYWxcclxuICAgKiBzdHJpY3RlciBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGUgc2FtZSB3b3JrIGFzIHRoZSBgYm9vbGVhbmAgdmFsaWRhdG9yLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIG5vRG93bmxvYWRcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZyB0aGUgYG5vRG93bmxvYWRgXHJcbiAgICogb3B0aW9uLlxyXG4gICAqL1xyXG4gIG5vRG93bmxvYWQoc3RyaWN0Q2hlY2spIHtcclxuICAgIHJldHVybiB2LmJvb2xlYW4oc3RyaWN0Q2hlY2spO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgZGVmYXVsdEhlaWdodGAgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbFxyXG4gICAqIHN0cmljdGVyIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgdGhlIGBwb3NpdGl2ZU51bWAgdmFsaWRhdG9yLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIGRlZmF1bHRIZWlnaHRcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZ1xyXG4gICAqIHRoZSBgZGVmYXVsdEhlaWdodGAgb3B0aW9uLlxyXG4gICAqL1xyXG4gIGRlZmF1bHRIZWlnaHQoc3RyaWN0Q2hlY2spIHtcclxuICAgIHJldHVybiB2LnBvc2l0aXZlTnVtKHN0cmljdENoZWNrKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYGRlZmF1bHRXaWR0aGAgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbFxyXG4gICAqIHN0cmljdGVyIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgdGhlIGBwb3NpdGl2ZU51bWAgdmFsaWRhdG9yLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIGRlZmF1bHRXaWR0aFxyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nXHJcbiAgICogdGhlIGBkZWZhdWx0V2lkdGhgIG9wdGlvbi5cclxuICAgKi9cclxuICBkZWZhdWx0V2lkdGgoc3RyaWN0Q2hlY2spIHtcclxuICAgIHJldHVybiB2LnBvc2l0aXZlTnVtKHN0cmljdENoZWNrKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYGRlZmF1bHRTY2FsZWAgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbFxyXG4gICAqIHN0cmljdGVyIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoYXQ6XHJcbiAgICpcclxuICAgKiAtIFdoZW4gYHN0cmljdENoZWNrYCBpcyB0cnVlLCB0aGUgc2NoZW1hIHdpbGwgYWNjZXB0IG51bWJlciB2YWx1ZXMgdGhhdFxyXG4gICAqIGFyZSBiZXR3ZWVuIDAuMSBhbmQgNSAoaW5jbHVzaXZlKS5cclxuICAgKlxyXG4gICAqIC0gV2hlbiBgc3RyaWN0Q2hlY2tgIGlzIGZhbHNlLCB0aGUgc2NoZW1hIHdpbGwgYWNjZXB0IG51bWJlciB2YWx1ZXNcclxuICAgKiBhbmQgc3RyaW5naWZpZWQgbnVtYmVyIHZhbHVlcyB0aGF0IGFyZSBiZXR3ZWVuIDAuMSBhbmQgNSAoaW5jbHVzaXZlKSwgbnVsbCxcclxuICAgKiAndW5kZWZpbmVkJywgJ251bGwnLCBhbmQgJycgd2hpY2ggd2lsbCBiZSB0cmFuc2Zvcm1lZCB0byBudWxsLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIGRlZmF1bHRTY2FsZVxyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nXHJcbiAgICogdGhlIGBkZWZhdWx0U2NhbGVgIG9wdGlvbi5cclxuICAgKi9cclxuICBkZWZhdWx0U2NhbGUoc3RyaWN0Q2hlY2spIHtcclxuICAgIHJldHVybiBzdHJpY3RDaGVja1xyXG4gICAgICA/IHoubnVtYmVyKCkuZ3RlKDAuMSkubHRlKDUpXHJcbiAgICAgIDogelxyXG4gICAgICAgICAgLnVuaW9uKFtcclxuICAgICAgICAgICAgelxyXG4gICAgICAgICAgICAgIC5zdHJpbmcoKVxyXG4gICAgICAgICAgICAgIC50cmltKClcclxuICAgICAgICAgICAgICAucmVmaW5lKFxyXG4gICAgICAgICAgICAgICAgKHZhbHVlKSA9PlxyXG4gICAgICAgICAgICAgICAgICAoIWlzTmFOKE51bWJlcih2YWx1ZSkpICYmXHJcbiAgICAgICAgICAgICAgICAgICAgdmFsdWUgIT09IHRydWUgJiZcclxuICAgICAgICAgICAgICAgICAgICAhdmFsdWUuc3RhcnRzV2l0aCgnWycpICYmXHJcbiAgICAgICAgICAgICAgICAgICAgTnVtYmVyKHZhbHVlKSA+PSAwLjEgJiZcclxuICAgICAgICAgICAgICAgICAgICBOdW1iZXIodmFsdWUpIDw9IDUpIHx8XHJcbiAgICAgICAgICAgICAgICAgIFsndW5kZWZpbmVkJywgJ251bGwnLCAnJ10uaW5jbHVkZXModmFsdWUpLFxyXG4gICAgICAgICAgICAgICAge1xyXG4gICAgICAgICAgICAgICAgICBwYXJhbXM6IHtcclxuICAgICAgICAgICAgICAgICAgICBlcnJvck1lc3NhZ2U6ICdUaGUgdmFsdWUgbXVzdCBiZSB3aXRoaW4gYSAwLjEgYW5kIDUuMCByYW5nZSdcclxuICAgICAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICAgIClcclxuICAgICAgICAgICAgICAudHJhbnNmb3JtKCh2YWx1ZSkgPT5cclxuICAgICAgICAgICAgICAgICFbJ3VuZGVmaW5lZCcsICdudWxsJywgJyddLmluY2x1ZGVzKHZhbHVlKVxyXG4gICAgICAgICAgICAgICAgICA/IE51bWJlcih2YWx1ZSlcclxuICAgICAgICAgICAgICAgICAgOiBudWxsXHJcbiAgICAgICAgICAgICAgKSxcclxuICAgICAgICAgICAgei5udW1iZXIoKS5ndGUoMC4xKS5sdGUoNSlcclxuICAgICAgICAgIF0pXHJcbiAgICAgICAgICAubnVsbGFibGUoKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYGhlaWdodGAgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbCBzdHJpY3RlclxyXG4gICAqIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgYSBudWxsYWJsZSBgZGVmYXVsdEhlaWdodGBcclxuICAgKiB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gaGVpZ2h0XHJcbiAgICpcclxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IHN0cmljdENoZWNrIC0gRGV0ZXJtaW5lcyBpZiBzdHJpY3RlciB2YWxpZGF0aW9uIHNob3VsZFxyXG4gICAqIGJlIGFwcGxpZWQuXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9IEEgWm9kIHNjaGVtYSBvYmplY3QgZm9yIHZhbGlkYXRpbmcgdGhlIGBoZWlnaHRgXHJcbiAgICogb3B0aW9uLlxyXG4gICAqL1xyXG4gIGhlaWdodChzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHRoaXMuZGVmYXVsdEhlaWdodChzdHJpY3RDaGVjaykubnVsbGFibGUoKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYHdpZHRoYCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoIGFuIG9wdGlvbmFsIHN0cmljdGVyXHJcbiAgICogY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhlIHNhbWUgd29yayBhcyBhIG51bGxhYmxlIGBkZWZhdWx0V2lkdGhgXHJcbiAgICogdmFsaWRhdG9yLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIHdpZHRoXHJcbiAgICpcclxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IHN0cmljdENoZWNrIC0gRGV0ZXJtaW5lcyBpZiBzdHJpY3RlciB2YWxpZGF0aW9uIHNob3VsZFxyXG4gICAqIGJlIGFwcGxpZWQuXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9IEEgWm9kIHNjaGVtYSBvYmplY3QgZm9yIHZhbGlkYXRpbmcgdGhlIGB3aWR0aGBcclxuICAgKiBvcHRpb24uXHJcbiAgICovXHJcbiAgd2lkdGgoc3RyaWN0Q2hlY2spIHtcclxuICAgIHJldHVybiB0aGlzLmRlZmF1bHRXaWR0aChzdHJpY3RDaGVjaykubnVsbGFibGUoKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYHNjYWxlYCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoIGFuIG9wdGlvbmFsIHN0cmljdGVyXHJcbiAgICogY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhlIHNhbWUgd29yayBhcyBhIG51bGxhYmxlIGBkZWZhdWx0U2NhbGVgXHJcbiAgICogdmFsaWRhdG9yLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIHNjYWxlXHJcbiAgICpcclxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IHN0cmljdENoZWNrIC0gRGV0ZXJtaW5lcyBpZiBzdHJpY3RlciB2YWxpZGF0aW9uIHNob3VsZFxyXG4gICAqIGJlIGFwcGxpZWQuXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9IEEgWm9kIHNjaGVtYSBvYmplY3QgZm9yIHZhbGlkYXRpbmcgdGhlIGBzY2FsZWBcclxuICAgKiBvcHRpb24uXHJcbiAgICovXHJcbiAgc2NhbGUoc3RyaWN0Q2hlY2spIHtcclxuICAgIHJldHVybiB0aGlzLmRlZmF1bHRTY2FsZShzdHJpY3RDaGVjaykubnVsbGFibGUoKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYGdsb2JhbE9wdGlvbnNgIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhlIHNhbWUgd29yayBhcyB0aGUgYGFkZGl0aW9uYWxPcHRpb25zYFxyXG4gICAqIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiBnbG9iYWxPcHRpb25zXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9IEEgWm9kIHNjaGVtYSBvYmplY3QgZm9yIHZhbGlkYXRpbmdcclxuICAgKiB0aGUgYGdsb2JhbE9wdGlvbnNgIG9wdGlvbi5cclxuICAgKi9cclxuICBnbG9iYWxPcHRpb25zKCkge1xyXG4gICAgcmV0dXJuIHYuYWRkaXRpb25hbE9wdGlvbnMoKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYHRoZW1lT3B0aW9uc2AgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGUgc2FtZSB3b3JrIGFzIHRoZSBgYWRkaXRpb25hbE9wdGlvbnNgXHJcbiAgICogdmFsaWRhdG9yLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIHRoZW1lT3B0aW9uc1xyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nXHJcbiAgICogdGhlIGB0aGVtZU9wdGlvbnNgIG9wdGlvbi5cclxuICAgKi9cclxuICB0aGVtZU9wdGlvbnMoKSB7XHJcbiAgICByZXR1cm4gdi5hZGRpdGlvbmFsT3B0aW9ucygpO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgYmF0Y2hgIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGggYW4gb3B0aW9uYWwgc3RyaWN0ZXJcclxuICAgKiBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGUgc2FtZSB3b3JrIGFzIHRoZSBgc3RyaW5nYCB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gYmF0Y2hcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZyB0aGUgYGJhdGNoYFxyXG4gICAqIG9wdGlvbi5cclxuICAgKi9cclxuICBiYXRjaChzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHYuc3RyaW5nKHN0cmljdENoZWNrKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYHJhc3Rlcml6YXRpb25UaW1lb3V0YCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoXHJcbiAgICogYW4gb3B0aW9uYWwgc3RyaWN0ZXIgY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhlIHNhbWUgd29yayBhcyB0aGUgYG5vbk5lZ2F0aXZlTnVtYFxyXG4gICAqIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiByYXN0ZXJpemF0aW9uVGltZW91dFxyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nXHJcbiAgICogdGhlIGByYXN0ZXJpemF0aW9uVGltZW91dGAgb3B0aW9uLlxyXG4gICAqL1xyXG4gIHJhc3Rlcml6YXRpb25UaW1lb3V0KHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gdi5ub25OZWdhdGl2ZU51bShzdHJpY3RDaGVjayk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGBhbGxvd0NvZGVFeGVjdXRpb25gIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGhcclxuICAgKiBhbiBvcHRpb25hbCBzdHJpY3RlciBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGUgc2FtZSB3b3JrIGFzIHRoZSBgYm9vbGVhbmAgdmFsaWRhdG9yLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIGFsbG93Q29kZUV4ZWN1dGlvblxyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nXHJcbiAgICogdGhlIGBhbGxvd0NvZGVFeGVjdXRpb25gIG9wdGlvbi5cclxuICAgKi9cclxuICBhbGxvd0NvZGVFeGVjdXRpb24oc3RyaWN0Q2hlY2spIHtcclxuICAgIHJldHVybiB2LmJvb2xlYW4oc3RyaWN0Q2hlY2spO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgYWxsb3dGaWxlUmVzb3VyY2VzYCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoXHJcbiAgICogYW4gb3B0aW9uYWwgc3RyaWN0ZXIgY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhlIHNhbWUgd29yayBhcyB0aGUgYGJvb2xlYW5gIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiBhbGxvd0ZpbGVSZXNvdXJjZXNcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZ1xyXG4gICAqIHRoZSBgYWxsb3dGaWxlUmVzb3VyY2VzYCBvcHRpb24uXHJcbiAgICovXHJcbiAgYWxsb3dGaWxlUmVzb3VyY2VzKHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gdi5ib29sZWFuKHN0cmljdENoZWNrKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYGN1c3RvbUNvZGVgIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGggYW4gb3B0aW9uYWxcclxuICAgKiBzdHJpY3RlciBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGUgc2FtZSB3b3JrIGFzIHRoZSBgc3RyaW5nYCB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gY3VzdG9tQ29kZVxyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nIHRoZSBgY3VzdG9tQ29kZWBcclxuICAgKiBvcHRpb24uXHJcbiAgICovXHJcbiAgY3VzdG9tQ29kZShzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHYuc3RyaW5nKHN0cmljdENoZWNrKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYGNhbGxiYWNrYCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoIGFuIG9wdGlvbmFsXHJcbiAgICogc3RyaWN0ZXIgY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhlIHNhbWUgd29yayBhcyB0aGUgYHN0cmluZ2AgdmFsaWRhdG9yLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIGNhbGxiYWNrXHJcbiAgICpcclxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IHN0cmljdENoZWNrIC0gRGV0ZXJtaW5lcyBpZiBzdHJpY3RlciB2YWxpZGF0aW9uIHNob3VsZFxyXG4gICAqIGJlIGFwcGxpZWQuXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9IEEgWm9kIHNjaGVtYSBvYmplY3QgZm9yIHZhbGlkYXRpbmcgdGhlIGBjYWxsYmFja2BcclxuICAgKiBvcHRpb24uXHJcbiAgICovXHJcbiAgY2FsbGJhY2soc3RyaWN0Q2hlY2spIHtcclxuICAgIHJldHVybiB2LnN0cmluZyhzdHJpY3RDaGVjayk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGByZXNvdXJjZXNgIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGggYW4gb3B0aW9uYWxcclxuICAgKiBzdHJpY3RlciBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGF0OlxyXG4gICAqXHJcbiAgICogLSBXaGVuIGBzdHJpY3RDaGVja2AgaXMgdHJ1ZSwgdGhlIHNjaGVtYSB3aWxsIGFjY2VwdCBhIHBhcnRpYWwgb2JqZWN0XHJcbiAgICogd2l0aCBhbGxvd2VkIHByb3BlcnRpZXMgYGpzYCwgYGNzc2AsIGFuZCBgZmlsZXNgIHdoZXJlIGVhY2ggb2YgdGhlIGFsbG93ZWRcclxuICAgKiBwcm9wZXJ0aWVzIGNhbiBiZSBudWxsLCBzdHJpbmdpZmllZCB2ZXJzaW9uIG9mIHRoZSBvYmplY3QsIHN0cmluZyB0aGF0IGVuZHNcclxuICAgKiB3aXRoIHRoZSAnLmpzb24nLCBhbmQgbnVsbC5cclxuICAgKlxyXG4gICAqIC0gV2hlbiBgc3RyaWN0Q2hlY2tgIGlzIGZhbHNlLCB0aGUgc2NoZW1hIHdpbGwgYWNjZXB0IGEgc3RyaW5naWZpZWQgdmVyc2lvblxyXG4gICAqIG9mIGEgcGFydGlhbCBvYmplY3Qgd2l0aCBhbGxvd2VkIHByb3BlcnRpZXMgYGpzYCwgYGNzc2AsIGFuZCBgZmlsZXNgIHdoZXJlXHJcbiAgICogZWFjaCBvZiB0aGUgYWxsb3dlZCBwcm9wZXJ0aWVzIGNhbiBiZSBudWxsLCBzdHJpbmcgdGhhdCBlbmRzIHdpdGggdGhlXHJcbiAgICogJy5qc29uJywgYW5kIHdpbGwgYmUgbnVsbCBpZiB0aGUgcHJvdmlkZWQgdmFsdWUgaXMgJ3VuZGVmaW5lZCcsICdudWxsJ1xyXG4gICAqIG9yICcnLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIHJlc291cmNlc1xyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nIHRoZSBgcmVzb3VyY2VzYFxyXG4gICAqIG9wdGlvbi5cclxuICAgKi9cclxuICByZXNvdXJjZXMoc3RyaWN0Q2hlY2spIHtcclxuICAgIGNvbnN0IG9iamVjdFNjaGVtYSA9IHpcclxuICAgICAgLm9iamVjdCh7XHJcbiAgICAgICAganM6IHYuc3RyaW5nKGZhbHNlKSxcclxuICAgICAgICBjc3M6IHYuc3RyaW5nKGZhbHNlKSxcclxuICAgICAgICBmaWxlczogdlxyXG4gICAgICAgICAgLnN0cmluZ0FycmF5KFxyXG4gICAgICAgICAgICAodmFsdWUpID0+ICFbJ3VuZGVmaW5lZCcsICdudWxsJywgJyddLmluY2x1ZGVzKHZhbHVlKSxcclxuICAgICAgICAgICAgJywnLFxyXG4gICAgICAgICAgICB0cnVlXHJcbiAgICAgICAgICApXHJcbiAgICAgICAgICAubnVsbGFibGUoKVxyXG4gICAgICB9KVxyXG4gICAgICAucGFydGlhbCgpO1xyXG5cclxuICAgIGNvbnN0IHN0cmluZ1NjaGVtYTEgPSB6XHJcbiAgICAgIC5zdHJpbmcoKVxyXG4gICAgICAudHJpbSgpXHJcbiAgICAgIC5yZWZpbmUoXHJcbiAgICAgICAgKHZhbHVlKSA9PlxyXG4gICAgICAgICAgKHZhbHVlLnN0YXJ0c1dpdGgoJ3snKSAmJiB2YWx1ZS5lbmRzV2l0aCgnfScpKSB8fFxyXG4gICAgICAgICAgKHZhbHVlLmxlbmd0aCA+PSA2ICYmIHZhbHVlLmVuZHNXaXRoKCcuanNvbicpKSxcclxuICAgICAgICB7XHJcbiAgICAgICAgICBwYXJhbXM6IHtcclxuICAgICAgICAgICAgZXJyb3JNZXNzYWdlOlxyXG4gICAgICAgICAgICAgIFwiVGhlIHZhbHVlIG11c3QgYmUgYSBzdHJpbmcgdGhhdCBzdGFydHMgd2l0aCAneycgYW5kIGVuZHMgd2l0aCAnfVwiXHJcbiAgICAgICAgICB9XHJcbiAgICAgICAgfVxyXG4gICAgICApO1xyXG5cclxuICAgIGNvbnN0IHN0cmluZ1NjaGVtYTIgPSB6XHJcbiAgICAgIC5zdHJpbmcoKVxyXG4gICAgICAudHJpbSgpXHJcbiAgICAgIC5yZWZpbmUoXHJcbiAgICAgICAgKHZhbHVlKSA9PlxyXG4gICAgICAgICAgKHZhbHVlLnN0YXJ0c1dpdGgoJ3snKSAmJiB2YWx1ZS5lbmRzV2l0aCgnfScpKSB8fFxyXG4gICAgICAgICAgKHZhbHVlLmxlbmd0aCA+PSA2ICYmIHZhbHVlLmVuZHNXaXRoKCcuanNvbicpKSB8fFxyXG4gICAgICAgICAgWyd1bmRlZmluZWQnLCAnbnVsbCcsICcnXS5pbmNsdWRlcyh2YWx1ZSksXHJcbiAgICAgICAge1xyXG4gICAgICAgICAgcGFyYW1zOiB7XHJcbiAgICAgICAgICAgIGVycm9yTWVzc2FnZTogJ1RoZSB2YWx1ZSBtdXN0IGJlIGEgc3RyaW5nIHRoYXQgZW5kcyB3aXRoIC5qc29uJ1xyXG4gICAgICAgICAgfVxyXG4gICAgICAgIH1cclxuICAgICAgKVxyXG4gICAgICAudHJhbnNmb3JtKCh2YWx1ZSkgPT5cclxuICAgICAgICAhWyd1bmRlZmluZWQnLCAnbnVsbCcsICcnXS5pbmNsdWRlcyh2YWx1ZSkgPyB2YWx1ZSA6IG51bGxcclxuICAgICAgKTtcclxuXHJcbiAgICByZXR1cm4gc3RyaWN0Q2hlY2tcclxuICAgICAgPyB6LnVuaW9uKFtvYmplY3RTY2hlbWEsIHN0cmluZ1NjaGVtYTFdKS5udWxsYWJsZSgpXHJcbiAgICAgIDogei51bmlvbihbb2JqZWN0U2NoZW1hLCBzdHJpbmdTY2hlbWEyXSkubnVsbGFibGUoKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYGxvYWRDb25maWdgIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGggYW4gb3B0aW9uYWxcclxuICAgKiBzdHJpY3RlciBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGUgc2FtZSB3b3JrIGFzIHRoZSBgc3RyaW5nYCB2YWxpZGF0b3IuXHJcbiAgICogQWRkaXRpb25hbGx5LCBpdCBtdXN0IGJlIGEgc3RyaW5nIHRoYXQgZW5kcyB3aXRoICcuanNvbicuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gbG9hZENvbmZpZ1xyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nIHRoZSBgbG9hZENvbmZpZ2BcclxuICAgKiBvcHRpb24uXHJcbiAgICovXHJcbiAgbG9hZENvbmZpZyhzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHZcclxuICAgICAgLnN0cmluZyhzdHJpY3RDaGVjaylcclxuICAgICAgLnJlZmluZShcclxuICAgICAgICAodmFsdWUpID0+XHJcbiAgICAgICAgICB2YWx1ZSA9PT0gbnVsbCB8fCAodmFsdWUubGVuZ3RoID49IDYgJiYgdmFsdWUuZW5kc1dpdGgoJy5qc29uJykpLFxyXG4gICAgICAgIHtcclxuICAgICAgICAgIHBhcmFtczoge1xyXG4gICAgICAgICAgICBlcnJvck1lc3NhZ2U6ICdUaGUgdmFsdWUgbXVzdCBiZSBhIHN0cmluZyB0aGF0IGVuZHMgd2l0aCAuanNvbidcclxuICAgICAgICAgIH1cclxuICAgICAgICB9XHJcbiAgICAgICk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGBjcmVhdGVDb25maWdgIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGggYW4gb3B0aW9uYWxcclxuICAgKiBzdHJpY3RlciBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGUgc2FtZSB3b3JrIGFzIHRoZSBgbG9hZENvbmZpZ2AgdmFsaWRhdG9yLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIGNyZWF0ZUNvbmZpZ1xyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nXHJcbiAgICogdGhlIGBjcmVhdGVDb25maWdgIG9wdGlvbi5cclxuICAgKi9cclxuICBjcmVhdGVDb25maWcoc3RyaWN0Q2hlY2spIHtcclxuICAgIHJldHVybiB0aGlzLmxvYWRDb25maWcoc3RyaWN0Q2hlY2spO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgZW5hYmxlU2VydmVyYCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoIGFuIG9wdGlvbmFsXHJcbiAgICogc3RyaWN0ZXIgY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhlIHNhbWUgd29yayBhcyB0aGUgYGJvb2xlYW5gIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiBlbmFibGVTZXJ2ZXJcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZ1xyXG4gICAqIHRoZSBgZW5hYmxlU2VydmVyYCBvcHRpb24uXHJcbiAgICovXHJcbiAgZW5hYmxlU2VydmVyKHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gdi5ib29sZWFuKHN0cmljdENoZWNrKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYGhvc3RgIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGggYW4gb3B0aW9uYWwgc3RyaWN0ZXJcclxuICAgKiBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGUgc2FtZSB3b3JrIGFzIHRoZSBgc3RyaW5nYCB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gaG9zdFxyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nIHRoZSBgaG9zdGBcclxuICAgKiBvcHRpb24uXHJcbiAgICovXHJcbiAgaG9zdChzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHYuc3RyaW5nKHN0cmljdENoZWNrKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYHBvcnRgIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGggYW4gb3B0aW9uYWwgc3RyaWN0ZXJcclxuICAgKiBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGUgc2FtZSB3b3JrIGFzIHRoZSBgbm9uTmVnYXRpdmVOdW1gXHJcbiAgICogdmFsaWRhdG9yLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIHBvcnRcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZyB0aGUgYHBvcnRgXHJcbiAgICogb3B0aW9uLlxyXG4gICAqL1xyXG4gIHBvcnQoc3RyaWN0Q2hlY2spIHtcclxuICAgIHJldHVybiB2Lm5vbk5lZ2F0aXZlTnVtKHN0cmljdENoZWNrKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYHVwbG9hZExpbWl0YCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoIGFuIG9wdGlvbmFsXHJcbiAgICogc3RyaWN0ZXIgY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhlIHNhbWUgd29yayBhcyB0aGUgYHBvc2l0aXZlTnVtYCB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gdXBsb2FkTGltaXRcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZyB0aGUgYHVwbG9hZExpbWl0YFxyXG4gICAqIG9wdGlvbi5cclxuICAgKi9cclxuICB1cGxvYWRMaW1pdChzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHYucG9zaXRpdmVOdW0oc3RyaWN0Q2hlY2spO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgc2VydmVyQmVuY2htYXJraW5nYCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoXHJcbiAgICogYW4gb3B0aW9uYWwgc3RyaWN0ZXIgY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhlIHNhbWUgd29yayBhcyB0aGUgYGJvb2xlYW5gIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiBzZXJ2ZXJCZW5jaG1hcmtpbmdcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZ1xyXG4gICAqIHRoZSBgc2VydmVyQmVuY2htYXJraW5nYCBvcHRpb24uXHJcbiAgICovXHJcbiAgc2VydmVyQmVuY2htYXJraW5nKHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gdi5ib29sZWFuKHN0cmljdENoZWNrKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYHByb3h5SG9zdGAgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbFxyXG4gICAqIHN0cmljdGVyIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgdGhlIGBzdHJpbmdgIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiBwcm94eUhvc3RcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZyB0aGUgYHByb3h5SG9zdGBcclxuICAgKiBvcHRpb24uXHJcbiAgICovXHJcbiAgcHJveHlIb3N0KHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gdi5zdHJpbmcoc3RyaWN0Q2hlY2spO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgcHJveHlQb3J0YCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoIGFuIG9wdGlvbmFsXHJcbiAgICogc3RyaWN0ZXIgY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhlIHNhbWUgd29yayBhcyBhIG51bGxhYmxlIGBub25OZWdhdGl2ZU51bWBcclxuICAgKiB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gcHJveHlQb3J0XHJcbiAgICpcclxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IHN0cmljdENoZWNrIC0gRGV0ZXJtaW5lcyBpZiBzdHJpY3RlciB2YWxpZGF0aW9uIHNob3VsZFxyXG4gICAqIGJlIGFwcGxpZWQuXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9IEEgWm9kIHNjaGVtYSBvYmplY3QgZm9yIHZhbGlkYXRpbmcgdGhlIGBwcm94eVBvcnRgXHJcbiAgICogb3B0aW9uLlxyXG4gICAqL1xyXG4gIHByb3h5UG9ydChzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHYubm9uTmVnYXRpdmVOdW0oc3RyaWN0Q2hlY2spLm51bGxhYmxlKCk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGBwcm94eVRpbWVvdXRgIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGggYW4gb3B0aW9uYWxcclxuICAgKiBzdHJpY3RlciBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGUgc2FtZSB3b3JrIGFzIHRoZSBgbm9uTmVnYXRpdmVOdW1gXHJcbiAgICogdmFsaWRhdG9yLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIHByb3h5VGltZW91dFxyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nXHJcbiAgICogdGhlIGBwcm94eVRpbWVvdXRgIG9wdGlvbi5cclxuICAgKi9cclxuICBwcm94eVRpbWVvdXQoc3RyaWN0Q2hlY2spIHtcclxuICAgIHJldHVybiB2Lm5vbk5lZ2F0aXZlTnVtKHN0cmljdENoZWNrKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYGVuYWJsZVJhdGVMaW1pdGluZ2AgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aFxyXG4gICAqIGFuIG9wdGlvbmFsIHN0cmljdGVyIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgdGhlIGBib29sZWFuYCB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gZW5hYmxlUmF0ZUxpbWl0aW5nXHJcbiAgICpcclxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IHN0cmljdENoZWNrIC0gRGV0ZXJtaW5lcyBpZiBzdHJpY3RlciB2YWxpZGF0aW9uIHNob3VsZFxyXG4gICAqIGJlIGFwcGxpZWQuXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9IEEgWm9kIHNjaGVtYSBvYmplY3QgZm9yIHZhbGlkYXRpbmdcclxuICAgKiB0aGUgYGVuYWJsZVJhdGVMaW1pdGluZ2Agb3B0aW9uLlxyXG4gICAqL1xyXG4gIGVuYWJsZVJhdGVMaW1pdGluZyhzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHYuYm9vbGVhbihzdHJpY3RDaGVjayk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGBtYXhSZXF1ZXN0c2AgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbFxyXG4gICAqIHN0cmljdGVyIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgdGhlIGBub25OZWdhdGl2ZU51bWBcclxuICAgKiB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gbWF4UmVxdWVzdHNcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZyB0aGUgYG1heFJlcXVlc3RzYFxyXG4gICAqIG9wdGlvbi5cclxuICAgKi9cclxuICBtYXhSZXF1ZXN0cyhzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHYubm9uTmVnYXRpdmVOdW0oc3RyaWN0Q2hlY2spO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgd2luZG93YCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoIGFuIG9wdGlvbmFsIHN0cmljdGVyXHJcbiAgICogY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhlIHNhbWUgd29yayBhcyB0aGUgYG5vbk5lZ2F0aXZlTnVtYFxyXG4gICAqIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiB3aW5kb3dcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZyB0aGUgYHdpbmRvd2BcclxuICAgKiBvcHRpb24uXHJcbiAgICovXHJcbiAgd2luZG93KHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gdi5ub25OZWdhdGl2ZU51bShzdHJpY3RDaGVjayk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGBkZWxheWAgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbCBzdHJpY3RlclxyXG4gICAqIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgdGhlIGBub25OZWdhdGl2ZU51bWBcclxuICAgKiB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gZGVsYXlcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZyB0aGUgYGRlbGF5YFxyXG4gICAqIG9wdGlvbi5cclxuICAgKi9cclxuICBkZWxheShzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHYubm9uTmVnYXRpdmVOdW0oc3RyaWN0Q2hlY2spO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgdHJ1c3RQcm94eWAgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbFxyXG4gICAqIHN0cmljdGVyIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgdGhlIGBib29sZWFuYCB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gdHJ1c3RQcm94eVxyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nIHRoZSBgdHJ1c3RQcm94eWBcclxuICAgKiBvcHRpb24uXHJcbiAgICovXHJcbiAgdHJ1c3RQcm94eShzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHYuYm9vbGVhbihzdHJpY3RDaGVjayk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGBza2lwS2V5YCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoIGFuIG9wdGlvbmFsIHN0cmljdGVyXHJcbiAgICogY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhlIHNhbWUgd29yayBhcyB0aGUgYHN0cmluZ2AgdmFsaWRhdG9yLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIHNraXBLZXlcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZyB0aGUgYHNraXBLZXlgXHJcbiAgICogb3B0aW9uLlxyXG4gICAqL1xyXG4gIHNraXBLZXkoc3RyaWN0Q2hlY2spIHtcclxuICAgIHJldHVybiB2LnN0cmluZyhzdHJpY3RDaGVjayk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGBza2lwVG9rZW5gIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGggYW4gb3B0aW9uYWxcclxuICAgKiBzdHJpY3RlciBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGUgc2FtZSB3b3JrIGFzIHRoZSBgc3RyaW5nYCB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gc2tpcFRva2VuXHJcbiAgICpcclxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IHN0cmljdENoZWNrIC0gRGV0ZXJtaW5lcyBpZiBzdHJpY3RlciB2YWxpZGF0aW9uIHNob3VsZFxyXG4gICAqIGJlIGFwcGxpZWQuXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9IEEgWm9kIHNjaGVtYSBvYmplY3QgZm9yIHZhbGlkYXRpbmcgdGhlIGBza2lwVG9rZW5gXHJcbiAgICogb3B0aW9uLlxyXG4gICAqL1xyXG4gIHNraXBUb2tlbihzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHYuc3RyaW5nKHN0cmljdENoZWNrKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYGVuYWJsZVNzbGAgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbFxyXG4gICAqIHN0cmljdGVyIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgdGhlIGBib29sZWFuYCB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gZW5hYmxlU3NsXHJcbiAgICpcclxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IHN0cmljdENoZWNrIC0gRGV0ZXJtaW5lcyBpZiBzdHJpY3RlciB2YWxpZGF0aW9uIHNob3VsZFxyXG4gICAqIGJlIGFwcGxpZWQuXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9IEEgWm9kIHNjaGVtYSBvYmplY3QgZm9yIHZhbGlkYXRpbmcgdGhlIGBlbmFibGVTc2xgXHJcbiAgICogb3B0aW9uLlxyXG4gICAqL1xyXG4gIGVuYWJsZVNzbChzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHYuYm9vbGVhbihzdHJpY3RDaGVjayk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGBzc2xGb3JjZWAgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbFxyXG4gICAqIHN0cmljdGVyIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgdGhlIGBib29sZWFuYCB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gc3NsRm9yY2VcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZyB0aGUgYHNzbEZvcmNlYFxyXG4gICAqIG9wdGlvbi5cclxuICAgKi9cclxuICBzc2xGb3JjZShzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHYuYm9vbGVhbihzdHJpY3RDaGVjayk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGBzc2xQb3J0YCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoIGFuIG9wdGlvbmFsIHN0cmljdGVyXHJcbiAgICogY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhlIHNhbWUgd29yayBhcyB0aGUgYG5vbk5lZ2F0aXZlTnVtYFxyXG4gICAqIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiBzc2xQb3J0XHJcbiAgICpcclxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IHN0cmljdENoZWNrIC0gRGV0ZXJtaW5lcyBpZiBzdHJpY3RlciB2YWxpZGF0aW9uIHNob3VsZFxyXG4gICAqIGJlIGFwcGxpZWQuXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9IEEgWm9kIHNjaGVtYSBvYmplY3QgZm9yIHZhbGlkYXRpbmcgdGhlIGBzc2xQb3J0YFxyXG4gICAqIG9wdGlvbi5cclxuICAgKi9cclxuICBzc2xQb3J0KHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gdi5ub25OZWdhdGl2ZU51bShzdHJpY3RDaGVjayk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGBzc2xDZXJ0UGF0aGAgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbFxyXG4gICAqIHN0cmljdGVyIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgdGhlIGBzdHJpbmdgIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiBzc2xDZXJ0UGF0aFxyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nIHRoZSBgc3NsQ2VydFBhdGhgXHJcbiAgICogb3B0aW9uLlxyXG4gICAqL1xyXG4gIHNzbENlcnRQYXRoKHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gdi5zdHJpbmcoc3RyaWN0Q2hlY2spO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgbWluV29ya2Vyc2AgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbFxyXG4gICAqIHN0cmljdGVyIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgdGhlIGBwb3NpdGl2ZU51bWAgdmFsaWRhdG9yLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIG1pbldvcmtlcnNcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZyB0aGUgYG1pbldvcmtlcnNgXHJcbiAgICogb3B0aW9uLlxyXG4gICAqL1xyXG4gIG1pbldvcmtlcnMoc3RyaWN0Q2hlY2spIHtcclxuICAgIHJldHVybiB2LnBvc2l0aXZlTnVtKHN0cmljdENoZWNrKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYG1heFdvcmtlcnNgIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGggYW4gb3B0aW9uYWxcclxuICAgKiBzdHJpY3RlciBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGUgc2FtZSB3b3JrIGFzIHRoZSBgcG9zaXRpdmVOdW1gIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiBtYXhXb3JrZXJzXHJcbiAgICpcclxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IHN0cmljdENoZWNrIC0gRGV0ZXJtaW5lcyBpZiBzdHJpY3RlciB2YWxpZGF0aW9uIHNob3VsZFxyXG4gICAqIGJlIGFwcGxpZWQuXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9IEEgWm9kIHNjaGVtYSBvYmplY3QgZm9yIHZhbGlkYXRpbmcgdGhlIGBtYXhXb3JrZXJzYFxyXG4gICAqIG9wdGlvbi5cclxuICAgKi9cclxuICBtYXhXb3JrZXJzKHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gdi5wb3NpdGl2ZU51bShzdHJpY3RDaGVjayk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGB3b3JrTGltaXRgIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGggYW4gb3B0aW9uYWxcclxuICAgKiBzdHJpY3RlciBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGUgc2FtZSB3b3JrIGFzIHRoZSBgcG9zaXRpdmVOdW1gIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiB3b3JrTGltaXRcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZyB0aGUgYHdvcmtMaW1pdGBcclxuICAgKiBvcHRpb24uXHJcbiAgICovXHJcbiAgd29ya0xpbWl0KHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gdi5wb3NpdGl2ZU51bShzdHJpY3RDaGVjayk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGBhY3F1aXJlVGltZW91dGAgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbFxyXG4gICAqIHN0cmljdGVyIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgdGhlIGBub25OZWdhdGl2ZU51bWBcclxuICAgKiB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gYWNxdWlyZVRpbWVvdXRcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZ1xyXG4gICAqIHRoZSBgYWNxdWlyZVRpbWVvdXRgIG9wdGlvbi5cclxuICAgKi9cclxuICBhY3F1aXJlVGltZW91dChzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHYubm9uTmVnYXRpdmVOdW0oc3RyaWN0Q2hlY2spO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgY3JlYXRlVGltZW91dGAgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbFxyXG4gICAqIHN0cmljdGVyIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgdGhlIGBub25OZWdhdGl2ZU51bWBcclxuICAgKiB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gY3JlYXRlVGltZW91dFxyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nXHJcbiAgICogdGhlIGBjcmVhdGVUaW1lb3V0YCBvcHRpb24uXHJcbiAgICovXHJcbiAgY3JlYXRlVGltZW91dChzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHYubm9uTmVnYXRpdmVOdW0oc3RyaWN0Q2hlY2spO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgZGVzdHJveVRpbWVvdXRgIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGggYW4gb3B0aW9uYWxcclxuICAgKiBzdHJpY3RlciBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGUgc2FtZSB3b3JrIGFzIHRoZSBgbm9uTmVnYXRpdmVOdW1gXHJcbiAgICogdmFsaWRhdG9yLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIGRlc3Ryb3lUaW1lb3V0XHJcbiAgICpcclxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IHN0cmljdENoZWNrIC0gRGV0ZXJtaW5lcyBpZiBzdHJpY3RlciB2YWxpZGF0aW9uIHNob3VsZFxyXG4gICAqIGJlIGFwcGxpZWQuXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9IEEgWm9kIHNjaGVtYSBvYmplY3QgZm9yIHZhbGlkYXRpbmdcclxuICAgKiB0aGUgYGRlc3Ryb3lUaW1lb3V0YCBvcHRpb24uXHJcbiAgICovXHJcbiAgZGVzdHJveVRpbWVvdXQoc3RyaWN0Q2hlY2spIHtcclxuICAgIHJldHVybiB2Lm5vbk5lZ2F0aXZlTnVtKHN0cmljdENoZWNrKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYGlkbGVUaW1lb3V0YCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoIGFuIG9wdGlvbmFsXHJcbiAgICogc3RyaWN0ZXIgY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhlIHNhbWUgd29yayBhcyB0aGUgYG5vbk5lZ2F0aXZlTnVtYFxyXG4gICAqIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiBpZGxlVGltZW91dFxyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nXHJcbiAgICogdGhlIGBpZGxlVGltZW91dGAgb3B0aW9uLlxyXG4gICAqL1xyXG4gIGlkbGVUaW1lb3V0KHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gdi5ub25OZWdhdGl2ZU51bShzdHJpY3RDaGVjayk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGBjcmVhdGVSZXRyeUludGVydmFsYCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoXHJcbiAgICogYW4gb3B0aW9uYWwgc3RyaWN0ZXIgY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhlIHNhbWUgd29yayBhcyB0aGUgYG5vbk5lZ2F0aXZlTnVtYFxyXG4gICAqIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiBjcmVhdGVSZXRyeUludGVydmFsXHJcbiAgICpcclxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IHN0cmljdENoZWNrIC0gRGV0ZXJtaW5lcyBpZiBzdHJpY3RlciB2YWxpZGF0aW9uIHNob3VsZFxyXG4gICAqIGJlIGFwcGxpZWQuXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9IEEgWm9kIHNjaGVtYSBvYmplY3QgZm9yIHZhbGlkYXRpbmdcclxuICAgKiB0aGUgYGNyZWF0ZVJldHJ5SW50ZXJ2YWxgIG9wdGlvbi5cclxuICAgKi9cclxuICBjcmVhdGVSZXRyeUludGVydmFsKHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gdi5ub25OZWdhdGl2ZU51bShzdHJpY3RDaGVjayk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGByZWFwZXJJbnRlcnZhbGAgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbFxyXG4gICAqIHN0cmljdGVyIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgdGhlIGBub25OZWdhdGl2ZU51bWBcclxuICAgKiB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gcmVhcGVySW50ZXJ2YWxcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZ1xyXG4gICAqIHRoZSBgcmVhcGVySW50ZXJ2YWxgIG9wdGlvbi5cclxuICAgKi9cclxuICByZWFwZXJJbnRlcnZhbChzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHYubm9uTmVnYXRpdmVOdW0oc3RyaWN0Q2hlY2spO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgcG9vbEJlbmNobWFya2luZ2AgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbFxyXG4gICAqIHN0cmljdGVyIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgdGhlIGBib29sZWFuYCB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gcG9vbEJlbmNobWFya2luZ1xyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nXHJcbiAgICogdGhlIGBwb29sQmVuY2htYXJraW5nYCBvcHRpb24uXHJcbiAgICovXHJcbiAgcG9vbEJlbmNobWFya2luZyhzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHYuYm9vbGVhbihzdHJpY3RDaGVjayk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGByZXNvdXJjZXNJbnRlcnZhbGAgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aFxyXG4gICAqIGFuIG9wdGlvbmFsIHN0cmljdGVyIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgdGhlIGBub25OZWdhdGl2ZU51bWBcclxuICAgKiB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gcmVzb3VyY2VzSW50ZXJ2YWxcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZ1xyXG4gICAqIHRoZSBgcmVzb3VyY2VzSW50ZXJ2YWxgIG9wdGlvbi5cclxuICAgKi9cclxuICByZXNvdXJjZXNJbnRlcnZhbChzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHYubm9uTmVnYXRpdmVOdW0oc3RyaWN0Q2hlY2spO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgbG9nTGV2ZWxgIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGggYW4gb3B0aW9uYWxcclxuICAgKiBzdHJpY3RlciBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGF0OlxyXG4gICAqXHJcbiAgICogLSBXaGVuIGBzdHJpY3RDaGVja2AgaXMgdHJ1ZSwgdGhlIHNjaGVtYSB3aWxsIGFjY2VwdCBpbnRlZ2VyIG51bWJlciB2YWx1ZXNcclxuICAgKiB0aGF0IGFyZSBiZXR3ZWVuIDAgYW5kIDUgKGluY2x1c2l2ZSkuXHJcbiAgICpcclxuICAgKiAtIFdoZW4gYHN0cmljdENoZWNrYCBpcyBmYWxzZSwgdGhlIHNjaGVtYSB3aWxsIGFjY2VwdCBpbnRlZ2VyIG51bWJlciB2YWx1ZXNcclxuICAgKiBhbmQgc3RyaW5naWZpZWQgaW50ZWdlciBudW1iZXIgdmFsdWVzIHRoYXQgYXJlIGJldHdlZW4gMSBhbmQgNSAoaW5jbHVzaXZlKSxcclxuICAgKiBudWxsLCAndW5kZWZpbmVkJywgJ251bGwnLCBhbmQgJycgd2hpY2ggd2lsbCBiZSB0cmFuc2Zvcm1lZCB0byBudWxsLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIGxvZ0xldmVsXHJcbiAgICpcclxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IHN0cmljdENoZWNrIC0gRGV0ZXJtaW5lcyBpZiBzdHJpY3RlciB2YWxpZGF0aW9uIHNob3VsZFxyXG4gICAqIGJlIGFwcGxpZWQuXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9IEEgWm9kIHNjaGVtYSBvYmplY3QgZm9yIHZhbGlkYXRpbmcgdGhlIGBsb2dMZXZlbGBcclxuICAgKiBvcHRpb24uXHJcbiAgICovXHJcbiAgbG9nTGV2ZWwoc3RyaWN0Q2hlY2spIHtcclxuICAgIHJldHVybiBzdHJpY3RDaGVja1xyXG4gICAgICA/IHoubnVtYmVyKCkuaW50KCkuZ3RlKDApLmx0ZSg1KVxyXG4gICAgICA6IHpcclxuICAgICAgICAgIC51bmlvbihbXHJcbiAgICAgICAgICAgIHpcclxuICAgICAgICAgICAgICAuc3RyaW5nKClcclxuICAgICAgICAgICAgICAudHJpbSgpXHJcbiAgICAgICAgICAgICAgLnJlZmluZShcclxuICAgICAgICAgICAgICAgICh2YWx1ZSkgPT5cclxuICAgICAgICAgICAgICAgICAgKCFpc05hTihOdW1iZXIodmFsdWUpKSAmJlxyXG4gICAgICAgICAgICAgICAgICAgIHZhbHVlICE9PSB0cnVlICYmXHJcbiAgICAgICAgICAgICAgICAgICAgIXZhbHVlLnN0YXJ0c1dpdGgoJ1snKSAmJlxyXG4gICAgICAgICAgICAgICAgICAgIE51bWJlci5pc0ludGVnZXIoTnVtYmVyKHZhbHVlKSkgJiZcclxuICAgICAgICAgICAgICAgICAgICBOdW1iZXIodmFsdWUpID49IDAgJiZcclxuICAgICAgICAgICAgICAgICAgICBOdW1iZXIodmFsdWUpIDw9IDUpIHx8XHJcbiAgICAgICAgICAgICAgICAgIFsndW5kZWZpbmVkJywgJ251bGwnLCAnJ10uaW5jbHVkZXModmFsdWUpLFxyXG4gICAgICAgICAgICAgICAge1xyXG4gICAgICAgICAgICAgICAgICBwYXJhbXM6IHtcclxuICAgICAgICAgICAgICAgICAgICBlcnJvck1lc3NhZ2U6ICdUaGUgdmFsdWUgbXVzdCBiZSB3aXRoaW4gYSAwIGFuZCA1IHJhbmdlJ1xyXG4gICAgICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgICAgKVxyXG4gICAgICAgICAgICAgIC50cmFuc2Zvcm0oKHZhbHVlKSA9PlxyXG4gICAgICAgICAgICAgICAgIVsndW5kZWZpbmVkJywgJ251bGwnLCAnJ10uaW5jbHVkZXModmFsdWUpXHJcbiAgICAgICAgICAgICAgICAgID8gTnVtYmVyKHZhbHVlKVxyXG4gICAgICAgICAgICAgICAgICA6IG51bGxcclxuICAgICAgICAgICAgICApLFxyXG4gICAgICAgICAgICB6Lm51bWJlcigpLmludCgpLmd0ZSgwKS5sdGUoNSlcclxuICAgICAgICAgIF0pXHJcbiAgICAgICAgICAubnVsbGFibGUoKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYGxvZ0ZpbGVgIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGggYW4gb3B0aW9uYWwgc3RyaWN0ZXJcclxuICAgKiBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGUgc2FtZSB3b3JrIGFzIHRoZSBgc3RyaW5nYCB2YWxpZGF0b3IuXHJcbiAgICogQWRkaXRpb25hbGx5LCBpdCBtdXN0IGJlIGEgc3RyaW5nIHRoYXQgZW5kcyB3aXRoICcubG9nJy5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiBsb2dGaWxlXHJcbiAgICpcclxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IHN0cmljdENoZWNrIC0gRGV0ZXJtaW5lcyBpZiBzdHJpY3RlciB2YWxpZGF0aW9uIHNob3VsZFxyXG4gICAqIGJlIGFwcGxpZWQuXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9IEEgWm9kIHNjaGVtYSBvYmplY3QgZm9yIHZhbGlkYXRpbmcgdGhlIGBsb2dGaWxlYFxyXG4gICAqIG9wdGlvbi5cclxuICAgKi9cclxuICBsb2dGaWxlKHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gdlxyXG4gICAgICAuc3RyaW5nKHN0cmljdENoZWNrKVxyXG4gICAgICAucmVmaW5lKFxyXG4gICAgICAgICh2YWx1ZSkgPT5cclxuICAgICAgICAgIHZhbHVlID09PSBudWxsIHx8ICh2YWx1ZS5sZW5ndGggPj0gNSAmJiB2YWx1ZS5lbmRzV2l0aCgnLmxvZycpKSxcclxuICAgICAgICB7XHJcbiAgICAgICAgICBwYXJhbXM6IHtcclxuICAgICAgICAgICAgZXJyb3JNZXNzYWdlOiAnVGhlIHZhbHVlIG11c3QgYmUgYSBzdHJpbmcgdGhhdCBlbmRzIHdpdGggLmxvZydcclxuICAgICAgICAgIH1cclxuICAgICAgICB9XHJcbiAgICAgICk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGBsb2dEZXN0YCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoIGFuIG9wdGlvbmFsIHN0cmljdGVyXHJcbiAgICogY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhlIHNhbWUgd29yayBhcyB0aGUgYHN0cmluZ2AgdmFsaWRhdG9yLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIGxvZ0Rlc3RcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZyB0aGUgYGxvZ0Rlc3RgXHJcbiAgICogb3B0aW9uLlxyXG4gICAqL1xyXG4gIGxvZ0Rlc3Qoc3RyaWN0Q2hlY2spIHtcclxuICAgIHJldHVybiB2LnN0cmluZyhzdHJpY3RDaGVjayk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGBsb2dUb0NvbnNvbGVgIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGggYW4gb3B0aW9uYWxcclxuICAgKiBzdHJpY3RlciBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGUgc2FtZSB3b3JrIGFzIHRoZSBgYm9vbGVhbmAgdmFsaWRhdG9yLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIGxvZ1RvQ29uc29sZVxyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nXHJcbiAgICogdGhlIGBsb2dUb0NvbnNvbGVgIG9wdGlvbi5cclxuICAgKi9cclxuICBsb2dUb0NvbnNvbGUoc3RyaWN0Q2hlY2spIHtcclxuICAgIHJldHVybiB2LmJvb2xlYW4oc3RyaWN0Q2hlY2spO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgbG9nVG9GaWxlYCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoIGFuIG9wdGlvbmFsXHJcbiAgICogc3RyaWN0ZXIgY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhlIHNhbWUgd29yayBhcyB0aGUgYGJvb2xlYW5gIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiBsb2dUb0ZpbGVcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZyB0aGUgYGxvZ1RvRmlsZWBcclxuICAgKiBvcHRpb24uXHJcbiAgICovXHJcbiAgbG9nVG9GaWxlKHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gdi5ib29sZWFuKHN0cmljdENoZWNrKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYGVuYWJsZVVpYCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoIGFuIG9wdGlvbmFsXHJcbiAgICogc3RyaWN0ZXIgY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhlIHNhbWUgd29yayBhcyB0aGUgYGJvb2xlYW5gIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiBlbmFibGVVaVxyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nIHRoZSBgZW5hYmxlVWlgXHJcbiAgICogb3B0aW9uLlxyXG4gICAqL1xyXG4gIGVuYWJsZVVpKHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gdi5ib29sZWFuKHN0cmljdENoZWNrKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYHVpUm91dGVgIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGggYW4gb3B0aW9uYWxcclxuICAgKiBzdHJpY3RlciBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGUgc2FtZSB3b3JrIGFzIHRoZSBgc3RhcnRzV2l0aGAgdmFsaWRhdG9yLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIHVpUm91dGVcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZyB0aGUgYHVpUm91dGVgXHJcbiAgICogb3B0aW9uLlxyXG4gICAqL1xyXG4gIHVpUm91dGUoc3RyaWN0Q2hlY2spIHtcclxuICAgIHJldHVybiB2LnN0YXJ0c1dpdGgoWycvJ10sIHN0cmljdENoZWNrKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYG5vZGVFbnZgIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGggYW4gb3B0aW9uYWxcclxuICAgKiBzdHJpY3RlciBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGUgc2FtZSB3b3JrIGFzIHRoZSBgZW51bWAgdmFsaWRhdG9yLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIG5vZGVFbnZcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZyB0aGUgYG5vZGVFbnZgXHJcbiAgICogb3B0aW9uLlxyXG4gICAqL1xyXG4gIG5vZGVFbnYoc3RyaWN0Q2hlY2spIHtcclxuICAgIHJldHVybiB2LmVudW0oWydkZXZlbG9wbWVudCcsICdwcm9kdWN0aW9uJywgJ3Rlc3QnXSwgc3RyaWN0Q2hlY2spO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgbGlzdGVuVG9Qcm9jZXNzRXhpdHNgIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGhcclxuICAgKiBhbiBvcHRpb25hbCBzdHJpY3RlciBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGUgc2FtZSB3b3JrIGFzIHRoZSBgYm9vbGVhbmAgdmFsaWRhdG9yLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIGxpc3RlblRvUHJvY2Vzc0V4aXRzXHJcbiAgICpcclxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IHN0cmljdENoZWNrIC0gRGV0ZXJtaW5lcyBpZiBzdHJpY3RlciB2YWxpZGF0aW9uIHNob3VsZFxyXG4gICAqIGJlIGFwcGxpZWQuXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9IEEgWm9kIHNjaGVtYSBvYmplY3QgZm9yIHZhbGlkYXRpbmdcclxuICAgKiB0aGUgYGxpc3RlblRvUHJvY2Vzc0V4aXRzYCBvcHRpb24uXHJcbiAgICovXHJcbiAgbGlzdGVuVG9Qcm9jZXNzRXhpdHMoc3RyaWN0Q2hlY2spIHtcclxuICAgIHJldHVybiB2LmJvb2xlYW4oc3RyaWN0Q2hlY2spO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgbm9Mb2dvYCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoIGFuIG9wdGlvbmFsXHJcbiAgICogc3RyaWN0ZXIgY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhlIHNhbWUgd29yayBhcyB0aGUgYGJvb2xlYW5gIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiBub0xvZ29cclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZyB0aGUgYG5vTG9nb2BcclxuICAgKiBvcHRpb24uXHJcbiAgICovXHJcbiAgbm9Mb2dvKHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gdi5ib29sZWFuKHN0cmljdENoZWNrKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYGhhcmRSZXNldFBhZ2VgIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGggYW4gb3B0aW9uYWxcclxuICAgKiBzdHJpY3RlciBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGUgc2FtZSB3b3JrIGFzIHRoZSBgYm9vbGVhbmAgdmFsaWRhdG9yLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIGhhcmRSZXNldFBhZ2VcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZ1xyXG4gICAqIHRoZSBgaGFyZFJlc2V0UGFnZWAgb3B0aW9uLlxyXG4gICAqL1xyXG4gIGhhcmRSZXNldFBhZ2Uoc3RyaWN0Q2hlY2spIHtcclxuICAgIHJldHVybiB2LmJvb2xlYW4oc3RyaWN0Q2hlY2spO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgYnJvd3NlclNoZWxsTW9kZWAgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbFxyXG4gICAqIHN0cmljdGVyIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgdGhlIGBib29sZWFuYCB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gYnJvd3NlclNoZWxsTW9kZVxyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nXHJcbiAgICogdGhlIGBicm93c2VyU2hlbGxNb2RlYCBvcHRpb24uXHJcbiAgICovXHJcbiAgYnJvd3NlclNoZWxsTW9kZShzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHYuYm9vbGVhbihzdHJpY3RDaGVjayk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGB2YWxpZGF0aW9uYCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoIGFuIG9wdGlvbmFsXHJcbiAgICogc3RyaWN0ZXIgY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhlIHNhbWUgd29yayBhcyB0aGUgYGJvb2xlYW5gIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiB2YWxpZGF0aW9uXHJcbiAgICpcclxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IHN0cmljdENoZWNrIC0gRGV0ZXJtaW5lcyBpZiBzdHJpY3RlciB2YWxpZGF0aW9uIHNob3VsZFxyXG4gICAqIGJlIGFwcGxpZWQuXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9IEEgWm9kIHNjaGVtYSBvYmplY3QgZm9yIHZhbGlkYXRpbmcgdGhlIGB2YWxpZGF0aW9uYFxyXG4gICAqIG9wdGlvbi5cclxuICAgKi9cclxuICB2YWxpZGF0aW9uKHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gdi5ib29sZWFuKHN0cmljdENoZWNrKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYGVuYWJsZURlYnVnYCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoIGFuIG9wdGlvbmFsXHJcbiAgICogc3RyaWN0ZXIgY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhlIHNhbWUgd29yayBhcyB0aGUgYGJvb2xlYW5gIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiBlbmFibGVEZWJ1Z1xyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nIHRoZSBgZW5hYmxlRGVidWdgXHJcbiAgICogb3B0aW9uLlxyXG4gICAqL1xyXG4gIGVuYWJsZURlYnVnKHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gdi5ib29sZWFuKHN0cmljdENoZWNrKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYGhlYWRsZXNzYCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoIGFuIG9wdGlvbmFsXHJcbiAgICogc3RyaWN0ZXIgY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhlIHNhbWUgd29yayBhcyB0aGUgYGJvb2xlYW5gIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiBoZWFkbGVzc1xyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nIHRoZSBgaGVhZGxlc3NgXHJcbiAgICogb3B0aW9uLlxyXG4gICAqL1xyXG4gIGhlYWRsZXNzKHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gdi5ib29sZWFuKHN0cmljdENoZWNrKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYGRldnRvb2xzYCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoIGFuIG9wdGlvbmFsXHJcbiAgICogc3RyaWN0ZXIgY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhlIHNhbWUgd29yayBhcyB0aGUgYGJvb2xlYW5gIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiBkZXZ0b29sc1xyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nIHRoZSBgZGV2dG9vbHNgXHJcbiAgICogb3B0aW9uLlxyXG4gICAqL1xyXG4gIGRldnRvb2xzKHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gdi5ib29sZWFuKHN0cmljdENoZWNrKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYGxpc3RlblRvQ29uc29sZWAgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbFxyXG4gICAqIHN0cmljdGVyIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgdGhlIGBib29sZWFuYCB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gbGlzdGVuVG9Db25zb2xlXHJcbiAgICpcclxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IHN0cmljdENoZWNrIC0gRGV0ZXJtaW5lcyBpZiBzdHJpY3RlciB2YWxpZGF0aW9uIHNob3VsZFxyXG4gICAqIGJlIGFwcGxpZWQuXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9IEEgWm9kIHNjaGVtYSBvYmplY3QgZm9yIHZhbGlkYXRpbmdcclxuICAgKiB0aGUgYGxpc3RlblRvQ29uc29sZWAgb3B0aW9uLlxyXG4gICAqL1xyXG4gIGxpc3RlblRvQ29uc29sZShzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHYuYm9vbGVhbihzdHJpY3RDaGVjayk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGBkdW1waW9gIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGggYW4gb3B0aW9uYWwgc3RyaWN0ZXJcclxuICAgKiBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGUgc2FtZSB3b3JrIGFzIHRoZSBgYm9vbGVhbmAgdmFsaWRhdG9yLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIGR1bXBpb1xyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nIHRoZSBgZHVtcGlvYFxyXG4gICAqIG9wdGlvbi5cclxuICAgKi9cclxuICBkdW1waW8oc3RyaWN0Q2hlY2spIHtcclxuICAgIHJldHVybiB2LmJvb2xlYW4oc3RyaWN0Q2hlY2spO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgc2xvd01vYCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoIGFuIG9wdGlvbmFsIHN0cmljdGVyXHJcbiAgICogY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhlIHNhbWUgd29yayBhcyB0aGUgYG5vbk5lZ2F0aXZlTnVtYFxyXG4gICAqIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiBzbG93TW9cclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZyB0aGUgYHNsb3dNb2BcclxuICAgKiBvcHRpb24uXHJcbiAgICovXHJcbiAgc2xvd01vKHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gdi5ub25OZWdhdGl2ZU51bShzdHJpY3RDaGVjayk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGBkZWJ1Z2dpbmdQb3J0YCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoIGFuIG9wdGlvbmFsXHJcbiAgICogc3RyaWN0ZXIgY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhlIHNhbWUgd29yayBhcyB0aGUgYG5vbk5lZ2F0aXZlTnVtYFxyXG4gICAqIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiBkZWJ1Z2dpbmdQb3J0XHJcbiAgICpcclxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IHN0cmljdENoZWNrIC0gRGV0ZXJtaW5lcyBpZiBzdHJpY3RlciB2YWxpZGF0aW9uIHNob3VsZFxyXG4gICAqIGJlIGFwcGxpZWQuXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9IEEgWm9kIHNjaGVtYSBvYmplY3QgZm9yIHZhbGlkYXRpbmdcclxuICAgKiB0aGUgYGRlYnVnZ2luZ1BvcnRgIG9wdGlvbi5cclxuICAgKi9cclxuICBkZWJ1Z2dpbmdQb3J0KHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gdi5ub25OZWdhdGl2ZU51bShzdHJpY3RDaGVjayk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGByZXF1ZXN0SWRgIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGggYW4gb3B0aW9uYWxcclxuICAgKiBzdHJpY3RlciBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGUgc2FtZSB3b3JrIGFzIHRoZSBgc3RyaW5nYCB2YWxpZGF0b3IuXHJcbiAgICogQWRkaXRpb25hbGx5LCBpdCBtdXN0IGJlIGEgc3RyaW5naWZpZWQgVVVJRCBvciBjYW4gYmUgbnVsbC5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiByZXF1ZXN0SWRcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZyB0aGUgYHJlcXVlc3RJZGBcclxuICAgKiBvcHRpb24uXHJcbiAgICovXHJcbiAgcmVxdWVzdElkKCkge1xyXG4gICAgcmV0dXJuIHpcclxuICAgICAgLnN0cmluZygpXHJcbiAgICAgIC51dWlkKHsgbWVzc2FnZTogJ1RoZSB2YWx1ZSBtdXN0IGJlIGEgc3RyaW5naWZpZWQgVVVJRCcgfSlcclxuICAgICAgLm51bGxhYmxlKCk7XHJcbiAgfVxyXG59O1xyXG5cclxuLy8gU2NoZW1hIGZvciB0aGUgcHVwcGV0ZWVyIHNlY3Rpb24gb2Ygb3B0aW9uc1xyXG5jb25zdCBQdXBwZXRlZXJTY2hlbWEgPSAoc3RyaWN0Q2hlY2spID0+XHJcbiAgelxyXG4gICAgLm9iamVjdCh7XHJcbiAgICAgIGFyZ3M6IHZhbGlkYXRvcnMuYXJncyhzdHJpY3RDaGVjaylcclxuICAgIH0pXHJcbiAgICAucGFydGlhbCgpO1xyXG5cclxuLy8gU2NoZW1hIGZvciB0aGUgaGlnaGNoYXJ0cyBzZWN0aW9uIG9mIG9wdGlvbnNcclxuY29uc3QgSGlnaGNoYXJ0c1NjaGVtYSA9IChzdHJpY3RDaGVjaykgPT5cclxuICB6XHJcbiAgICAub2JqZWN0KHtcclxuICAgICAgdmVyc2lvbjogdmFsaWRhdG9ycy52ZXJzaW9uKHN0cmljdENoZWNrKSxcclxuICAgICAgY2RuVXJsOiB2YWxpZGF0b3JzLmNkblVybChzdHJpY3RDaGVjayksXHJcbiAgICAgIGZvcmNlRmV0Y2g6IHZhbGlkYXRvcnMuZm9yY2VGZXRjaChzdHJpY3RDaGVjayksXHJcbiAgICAgIGNhY2hlUGF0aDogdmFsaWRhdG9ycy5jYWNoZVBhdGgoc3RyaWN0Q2hlY2spLFxyXG4gICAgICBjb3JlU2NyaXB0czogdmFsaWRhdG9ycy5jb3JlU2NyaXB0cyhzdHJpY3RDaGVjayksXHJcbiAgICAgIG1vZHVsZVNjcmlwdHM6IHZhbGlkYXRvcnMubW9kdWxlU2NyaXB0cyhzdHJpY3RDaGVjayksXHJcbiAgICAgIGluZGljYXRvclNjcmlwdHM6IHZhbGlkYXRvcnMuaW5kaWNhdG9yU2NyaXB0cyhzdHJpY3RDaGVjayksXHJcbiAgICAgIGN1c3RvbVNjcmlwdHM6IHZhbGlkYXRvcnMuY3VzdG9tU2NyaXB0cyhzdHJpY3RDaGVjaylcclxuICAgIH0pXHJcbiAgICAucGFydGlhbCgpO1xyXG5cclxuLy8gU2NoZW1hIGZvciB0aGUgZXhwb3J0IHNlY3Rpb24gb2Ygb3B0aW9uc1xyXG5jb25zdCBFeHBvcnRTY2hlbWEgPSAoc3RyaWN0Q2hlY2spID0+XHJcbiAgelxyXG4gICAgLm9iamVjdCh7XHJcbiAgICAgIGluZmlsZTogdmFsaWRhdG9ycy5pbmZpbGUoc3RyaWN0Q2hlY2spLFxyXG4gICAgICBpbnN0cjogdmFsaWRhdG9ycy5pbnN0cigpLFxyXG4gICAgICBvcHRpb25zOiB2YWxpZGF0b3JzLm9wdGlvbnMoKSxcclxuICAgICAgc3ZnOiB2YWxpZGF0b3JzLnN2ZygpLFxyXG4gICAgICBvdXRmaWxlOiB2YWxpZGF0b3JzLm91dGZpbGUoc3RyaWN0Q2hlY2spLFxyXG4gICAgICB0eXBlOiB2YWxpZGF0b3JzLnR5cGUoc3RyaWN0Q2hlY2spLFxyXG4gICAgICBjb25zdHI6IHZhbGlkYXRvcnMuY29uc3RyKHN0cmljdENoZWNrKSxcclxuICAgICAgYjY0OiB2YWxpZGF0b3JzLmI2NChzdHJpY3RDaGVjayksXHJcbiAgICAgIG5vRG93bmxvYWQ6IHZhbGlkYXRvcnMubm9Eb3dubG9hZChzdHJpY3RDaGVjayksXHJcbiAgICAgIGRlZmF1bHRIZWlnaHQ6IHZhbGlkYXRvcnMuZGVmYXVsdEhlaWdodChzdHJpY3RDaGVjayksXHJcbiAgICAgIGRlZmF1bHRXaWR0aDogdmFsaWRhdG9ycy5kZWZhdWx0V2lkdGgoc3RyaWN0Q2hlY2spLFxyXG4gICAgICBkZWZhdWx0U2NhbGU6IHZhbGlkYXRvcnMuZGVmYXVsdFNjYWxlKHN0cmljdENoZWNrKSxcclxuICAgICAgaGVpZ2h0OiB2YWxpZGF0b3JzLmhlaWdodChzdHJpY3RDaGVjayksXHJcbiAgICAgIHdpZHRoOiB2YWxpZGF0b3JzLndpZHRoKHN0cmljdENoZWNrKSxcclxuICAgICAgc2NhbGU6IHZhbGlkYXRvcnMuc2NhbGUoc3RyaWN0Q2hlY2spLFxyXG4gICAgICBnbG9iYWxPcHRpb25zOiB2YWxpZGF0b3JzLmdsb2JhbE9wdGlvbnMoKSxcclxuICAgICAgdGhlbWVPcHRpb25zOiB2YWxpZGF0b3JzLnRoZW1lT3B0aW9ucygpLFxyXG4gICAgICBiYXRjaDogdmFsaWRhdG9ycy5iYXRjaChmYWxzZSksXHJcbiAgICAgIHJhc3Rlcml6YXRpb25UaW1lb3V0OiB2YWxpZGF0b3JzLnJhc3Rlcml6YXRpb25UaW1lb3V0KHN0cmljdENoZWNrKVxyXG4gICAgfSlcclxuICAgIC5wYXJ0aWFsKCk7XHJcblxyXG4vLyBTY2hlbWEgZm9yIHRoZSBjdXN0b21Mb2dpYyBzZWN0aW9uIG9mIG9wdGlvbnNcclxuY29uc3QgQ3VzdG9tTG9naWNTY2hlbWEgPSAoc3RyaWN0Q2hlY2spID0+XHJcbiAgelxyXG4gICAgLm9iamVjdCh7XHJcbiAgICAgIGFsbG93Q29kZUV4ZWN1dGlvbjogdmFsaWRhdG9ycy5hbGxvd0NvZGVFeGVjdXRpb24oc3RyaWN0Q2hlY2spLFxyXG4gICAgICBhbGxvd0ZpbGVSZXNvdXJjZXM6IHZhbGlkYXRvcnMuYWxsb3dGaWxlUmVzb3VyY2VzKHN0cmljdENoZWNrKSxcclxuICAgICAgY3VzdG9tQ29kZTogdmFsaWRhdG9ycy5jdXN0b21Db2RlKGZhbHNlKSxcclxuICAgICAgY2FsbGJhY2s6IHZhbGlkYXRvcnMuY2FsbGJhY2soZmFsc2UpLFxyXG4gICAgICByZXNvdXJjZXM6IHZhbGlkYXRvcnMucmVzb3VyY2VzKHN0cmljdENoZWNrKSxcclxuICAgICAgbG9hZENvbmZpZzogdmFsaWRhdG9ycy5sb2FkQ29uZmlnKGZhbHNlKSxcclxuICAgICAgY3JlYXRlQ29uZmlnOiB2YWxpZGF0b3JzLmNyZWF0ZUNvbmZpZyhmYWxzZSlcclxuICAgIH0pXHJcbiAgICAucGFydGlhbCgpO1xyXG5cclxuLy8gU2NoZW1hIGZvciB0aGUgc2VydmVyLnByb3h5IHNlY3Rpb24gb2Ygb3B0aW9uc1xyXG5jb25zdCBQcm94eVNjaGVtYSA9IChzdHJpY3RDaGVjaykgPT5cclxuICB6XHJcbiAgICAub2JqZWN0KHtcclxuICAgICAgaG9zdDogdmFsaWRhdG9ycy5wcm94eUhvc3QoZmFsc2UpLFxyXG4gICAgICBwb3J0OiB2YWxpZGF0b3JzLnByb3h5UG9ydChzdHJpY3RDaGVjayksXHJcbiAgICAgIHRpbWVvdXQ6IHZhbGlkYXRvcnMucHJveHlUaW1lb3V0KHN0cmljdENoZWNrKVxyXG4gICAgfSlcclxuICAgIC5wYXJ0aWFsKCk7XHJcblxyXG4vLyBTY2hlbWEgZm9yIHRoZSBzZXJ2ZXIucmF0ZUxpbWl0aW5nIHNlY3Rpb24gb2Ygb3B0aW9uc1xyXG5jb25zdCBSYXRlTGltaXRpbmdTY2hlbWEgPSAoc3RyaWN0Q2hlY2spID0+XHJcbiAgelxyXG4gICAgLm9iamVjdCh7XHJcbiAgICAgIGVuYWJsZTogdmFsaWRhdG9ycy5lbmFibGVSYXRlTGltaXRpbmcoc3RyaWN0Q2hlY2spLFxyXG4gICAgICBtYXhSZXF1ZXN0czogdmFsaWRhdG9ycy5tYXhSZXF1ZXN0cyhzdHJpY3RDaGVjayksXHJcbiAgICAgIHdpbmRvdzogdmFsaWRhdG9ycy53aW5kb3coc3RyaWN0Q2hlY2spLFxyXG4gICAgICBkZWxheTogdmFsaWRhdG9ycy5kZWxheShzdHJpY3RDaGVjayksXHJcbiAgICAgIHRydXN0UHJveHk6IHZhbGlkYXRvcnMudHJ1c3RQcm94eShzdHJpY3RDaGVjayksXHJcbiAgICAgIHNraXBLZXk6IHZhbGlkYXRvcnMuc2tpcEtleShmYWxzZSksXHJcbiAgICAgIHNraXBUb2tlbjogdmFsaWRhdG9ycy5za2lwVG9rZW4oZmFsc2UpXHJcbiAgICB9KVxyXG4gICAgLnBhcnRpYWwoKTtcclxuXHJcbi8vIFNjaGVtYSBmb3IgdGhlIHNlcnZlci5zc2wgc2VjdGlvbiBvZiBvcHRpb25zXHJcbmNvbnN0IFNzbFNjaGVtYSA9IChzdHJpY3RDaGVjaykgPT5cclxuICB6XHJcbiAgICAub2JqZWN0KHtcclxuICAgICAgZW5hYmxlOiB2YWxpZGF0b3JzLmVuYWJsZVNzbChzdHJpY3RDaGVjayksXHJcbiAgICAgIGZvcmNlOiB2YWxpZGF0b3JzLnNzbEZvcmNlKHN0cmljdENoZWNrKSxcclxuICAgICAgcG9ydDogdmFsaWRhdG9ycy5zc2xQb3J0KHN0cmljdENoZWNrKSxcclxuICAgICAgY2VydFBhdGg6IHZhbGlkYXRvcnMuc3NsQ2VydFBhdGgoZmFsc2UpXHJcbiAgICB9KVxyXG4gICAgLnBhcnRpYWwoKTtcclxuXHJcbi8vIFNjaGVtYSBmb3IgdGhlIHNlcnZlciBzZWN0aW9uIG9mIG9wdGlvbnNcclxuY29uc3QgU2VydmVyU2NoZW1hID0gKHN0cmljdENoZWNrKSA9PlxyXG4gIHoub2JqZWN0KHtcclxuICAgIGVuYWJsZTogdmFsaWRhdG9ycy5lbmFibGVTZXJ2ZXIoc3RyaWN0Q2hlY2spLm9wdGlvbmFsKCksXHJcbiAgICBob3N0OiB2YWxpZGF0b3JzLmhvc3Qoc3RyaWN0Q2hlY2spLm9wdGlvbmFsKCksXHJcbiAgICBwb3J0OiB2YWxpZGF0b3JzLnBvcnQoc3RyaWN0Q2hlY2spLm9wdGlvbmFsKCksXHJcbiAgICB1cGxvYWRMaW1pdDogdmFsaWRhdG9ycy51cGxvYWRMaW1pdChzdHJpY3RDaGVjaykub3B0aW9uYWwoKSxcclxuICAgIGJlbmNobWFya2luZzogdmFsaWRhdG9ycy5zZXJ2ZXJCZW5jaG1hcmtpbmcoc3RyaWN0Q2hlY2spLm9wdGlvbmFsKCksXHJcbiAgICBwcm94eTogUHJveHlTY2hlbWEoc3RyaWN0Q2hlY2spLm9wdGlvbmFsKCksXHJcbiAgICByYXRlTGltaXRpbmc6IFJhdGVMaW1pdGluZ1NjaGVtYShzdHJpY3RDaGVjaykub3B0aW9uYWwoKSxcclxuICAgIHNzbDogU3NsU2NoZW1hKHN0cmljdENoZWNrKS5vcHRpb25hbCgpXHJcbiAgfSk7XHJcblxyXG4vLyBTY2hlbWEgZm9yIHRoZSBwb29sIHNlY3Rpb24gb2Ygb3B0aW9uc1xyXG5jb25zdCBQb29sU2NoZW1hID0gKHN0cmljdENoZWNrKSA9PlxyXG4gIHpcclxuICAgIC5vYmplY3Qoe1xyXG4gICAgICBtaW5Xb3JrZXJzOiB2YWxpZGF0b3JzLm1pbldvcmtlcnMoc3RyaWN0Q2hlY2spLFxyXG4gICAgICBtYXhXb3JrZXJzOiB2YWxpZGF0b3JzLm1heFdvcmtlcnMoc3RyaWN0Q2hlY2spLFxyXG4gICAgICB3b3JrTGltaXQ6IHZhbGlkYXRvcnMud29ya0xpbWl0KHN0cmljdENoZWNrKSxcclxuICAgICAgYWNxdWlyZVRpbWVvdXQ6IHZhbGlkYXRvcnMuYWNxdWlyZVRpbWVvdXQoc3RyaWN0Q2hlY2spLFxyXG4gICAgICBjcmVhdGVUaW1lb3V0OiB2YWxpZGF0b3JzLmNyZWF0ZVRpbWVvdXQoc3RyaWN0Q2hlY2spLFxyXG4gICAgICBkZXN0cm95VGltZW91dDogdmFsaWRhdG9ycy5kZXN0cm95VGltZW91dChzdHJpY3RDaGVjayksXHJcbiAgICAgIGlkbGVUaW1lb3V0OiB2YWxpZGF0b3JzLmlkbGVUaW1lb3V0KHN0cmljdENoZWNrKSxcclxuICAgICAgY3JlYXRlUmV0cnlJbnRlcnZhbDogdmFsaWRhdG9ycy5jcmVhdGVSZXRyeUludGVydmFsKHN0cmljdENoZWNrKSxcclxuICAgICAgcmVhcGVySW50ZXJ2YWw6IHZhbGlkYXRvcnMucmVhcGVySW50ZXJ2YWwoc3RyaWN0Q2hlY2spLFxyXG4gICAgICBiZW5jaG1hcmtpbmc6IHZhbGlkYXRvcnMucG9vbEJlbmNobWFya2luZyhzdHJpY3RDaGVjaylcclxuICAgIH0pXHJcbiAgICAucGFydGlhbCgpO1xyXG5cclxuLy8gU2NoZW1hIGZvciB0aGUgbG9nZ2luZyBzZWN0aW9uIG9mIG9wdGlvbnNcclxuY29uc3QgTG9nZ2luZ1NjaGVtYSA9IChzdHJpY3RDaGVjaykgPT5cclxuICB6XHJcbiAgICAub2JqZWN0KHtcclxuICAgICAgbGV2ZWw6IHZhbGlkYXRvcnMubG9nTGV2ZWwoc3RyaWN0Q2hlY2spLFxyXG4gICAgICBmaWxlOiB2YWxpZGF0b3JzLmxvZ0ZpbGUoc3RyaWN0Q2hlY2spLFxyXG4gICAgICBkZXN0OiB2YWxpZGF0b3JzLmxvZ0Rlc3Qoc3RyaWN0Q2hlY2spLFxyXG4gICAgICB0b0NvbnNvbGU6IHZhbGlkYXRvcnMubG9nVG9Db25zb2xlKHN0cmljdENoZWNrKSxcclxuICAgICAgdG9GaWxlOiB2YWxpZGF0b3JzLmxvZ1RvRmlsZShzdHJpY3RDaGVjaylcclxuICAgIH0pXHJcbiAgICAucGFydGlhbCgpO1xyXG5cclxuLy8gU2NoZW1hIGZvciB0aGUgdWkgc2VjdGlvbiBvZiBvcHRpb25zXHJcbmNvbnN0IFVpU2NoZW1hID0gKHN0cmljdENoZWNrKSA9PlxyXG4gIHpcclxuICAgIC5vYmplY3Qoe1xyXG4gICAgICBlbmFibGU6IHZhbGlkYXRvcnMuZW5hYmxlVWkoc3RyaWN0Q2hlY2spLFxyXG4gICAgICByb3V0ZTogdmFsaWRhdG9ycy51aVJvdXRlKHN0cmljdENoZWNrKVxyXG4gICAgfSlcclxuICAgIC5wYXJ0aWFsKCk7XHJcblxyXG4vLyBTY2hlbWEgZm9yIHRoZSBvdGhlciBzZWN0aW9uIG9mIG9wdGlvbnNcclxuY29uc3QgT3RoZXJTY2hlbWEgPSAoc3RyaWN0Q2hlY2spID0+XHJcbiAgelxyXG4gICAgLm9iamVjdCh7XHJcbiAgICAgIG5vZGVFbnY6IHZhbGlkYXRvcnMubm9kZUVudihzdHJpY3RDaGVjayksXHJcbiAgICAgIGxpc3RlblRvUHJvY2Vzc0V4aXRzOiB2YWxpZGF0b3JzLmxpc3RlblRvUHJvY2Vzc0V4aXRzKHN0cmljdENoZWNrKSxcclxuICAgICAgbm9Mb2dvOiB2YWxpZGF0b3JzLm5vTG9nbyhzdHJpY3RDaGVjayksXHJcbiAgICAgIGhhcmRSZXNldFBhZ2U6IHZhbGlkYXRvcnMuaGFyZFJlc2V0UGFnZShzdHJpY3RDaGVjayksXHJcbiAgICAgIGJyb3dzZXJTaGVsbE1vZGU6IHZhbGlkYXRvcnMuYnJvd3NlclNoZWxsTW9kZShzdHJpY3RDaGVjayksXHJcbiAgICAgIHZhbGlkYXRpb246IHZhbGlkYXRvcnMudmFsaWRhdGlvbihzdHJpY3RDaGVjaylcclxuICAgIH0pXHJcbiAgICAucGFydGlhbCgpO1xyXG5cclxuLy8gU2NoZW1hIGZvciB0aGUgZGVidWcgc2VjdGlvbiBvZiBvcHRpb25zXHJcbmNvbnN0IERlYnVnU2NoZW1hID0gKHN0cmljdENoZWNrKSA9PlxyXG4gIHpcclxuICAgIC5vYmplY3Qoe1xyXG4gICAgICBlbmFibGU6IHZhbGlkYXRvcnMuZW5hYmxlRGVidWcoc3RyaWN0Q2hlY2spLFxyXG4gICAgICBoZWFkbGVzczogdmFsaWRhdG9ycy5oZWFkbGVzcyhzdHJpY3RDaGVjayksXHJcbiAgICAgIGRldnRvb2xzOiB2YWxpZGF0b3JzLmRldnRvb2xzKHN0cmljdENoZWNrKSxcclxuICAgICAgbGlzdGVuVG9Db25zb2xlOiB2YWxpZGF0b3JzLmxpc3RlblRvQ29uc29sZShzdHJpY3RDaGVjayksXHJcbiAgICAgIGR1bXBpbzogdmFsaWRhdG9ycy5kdW1waW8oc3RyaWN0Q2hlY2spLFxyXG4gICAgICBzbG93TW86IHZhbGlkYXRvcnMuc2xvd01vKHN0cmljdENoZWNrKSxcclxuICAgICAgZGVidWdnaW5nUG9ydDogdmFsaWRhdG9ycy5kZWJ1Z2dpbmdQb3J0KHN0cmljdENoZWNrKVxyXG4gICAgfSlcclxuICAgIC5wYXJ0aWFsKCk7XHJcblxyXG4vLyBTdHJpY3Qgc2NoZW1hIGZvciB0aGUgY29uZmlnXHJcbmV4cG9ydCBjb25zdCBTdHJpY3RDb25maWdTY2hlbWEgPSB6Lm9iamVjdCh7XHJcbiAgcmVxdWVzdElkOiB2YWxpZGF0b3JzLnJlcXVlc3RJZCgpLFxyXG4gIHB1cHBldGVlcjogUHVwcGV0ZWVyU2NoZW1hKHRydWUpLFxyXG4gIGhpZ2hjaGFydHM6IEhpZ2hjaGFydHNTY2hlbWEodHJ1ZSksXHJcbiAgZXhwb3J0OiBFeHBvcnRTY2hlbWEodHJ1ZSksXHJcbiAgY3VzdG9tTG9naWM6IEN1c3RvbUxvZ2ljU2NoZW1hKHRydWUpLFxyXG4gIHNlcnZlcjogU2VydmVyU2NoZW1hKHRydWUpLFxyXG4gIHBvb2w6IFBvb2xTY2hlbWEodHJ1ZSksXHJcbiAgbG9nZ2luZzogTG9nZ2luZ1NjaGVtYSh0cnVlKSxcclxuICB1aTogVWlTY2hlbWEodHJ1ZSksXHJcbiAgb3RoZXI6IE90aGVyU2NoZW1hKHRydWUpLFxyXG4gIGRlYnVnOiBEZWJ1Z1NjaGVtYSh0cnVlKVxyXG59KTtcclxuXHJcbi8vIExvb3NlIHNjaGVtYSBmb3IgdGhlIGNvbmZpZ1xyXG5leHBvcnQgY29uc3QgTG9vc2VDb25maWdTY2hlbWEgPSB6Lm9iamVjdCh7XHJcbiAgcmVxdWVzdElkOiB2YWxpZGF0b3JzLnJlcXVlc3RJZCgpLFxyXG4gIHB1cHBldGVlcjogUHVwcGV0ZWVyU2NoZW1hKGZhbHNlKSxcclxuICBoaWdoY2hhcnRzOiBIaWdoY2hhcnRzU2NoZW1hKGZhbHNlKSxcclxuICBleHBvcnQ6IEV4cG9ydFNjaGVtYShmYWxzZSksXHJcbiAgY3VzdG9tTG9naWM6IEN1c3RvbUxvZ2ljU2NoZW1hKGZhbHNlKSxcclxuICBzZXJ2ZXI6IFNlcnZlclNjaGVtYShmYWxzZSksXHJcbiAgcG9vbDogUG9vbFNjaGVtYShmYWxzZSksXHJcbiAgbG9nZ2luZzogTG9nZ2luZ1NjaGVtYShmYWxzZSksXHJcbiAgdWk6IFVpU2NoZW1hKGZhbHNlKSxcclxuICBvdGhlcjogT3RoZXJTY2hlbWEoZmFsc2UpLFxyXG4gIGRlYnVnOiBEZWJ1Z1NjaGVtYShmYWxzZSlcclxufSk7XHJcblxyXG4vLyBTY2hlbWEgZm9yIHRoZSBlbnZpcm9ubWVudCB2YXJpYWJsZXMgY29uZmlnXHJcbmV4cG9ydCBjb25zdCBFbnZTY2hlbWEgPSB6Lm9iamVjdCh7XHJcbiAgLy8gcHVwcGV0ZWVyXHJcbiAgUFVQUEVURUVSX0FSR1M6IHZhbGlkYXRvcnMuYXJncyhmYWxzZSksXHJcblxyXG4gIC8vIGhpZ2hjaGFydHNcclxuICBISUdIQ0hBUlRTX1ZFUlNJT046IHZhbGlkYXRvcnMudmVyc2lvbihmYWxzZSksXHJcbiAgSElHSENIQVJUU19DRE5fVVJMOiB2YWxpZGF0b3JzLmNkblVybChmYWxzZSksXHJcbiAgSElHSENIQVJUU19GT1JDRV9GRVRDSDogdmFsaWRhdG9ycy5mb3JjZUZldGNoKGZhbHNlKSxcclxuICBISUdIQ0hBUlRTX0NBQ0hFX1BBVEg6IHZhbGlkYXRvcnMuY2FjaGVQYXRoKGZhbHNlKSxcclxuICBISUdIQ0hBUlRTX0FETUlOX1RPS0VOOiB2YWxpZGF0b3JzLmFkbWluVG9rZW4oZmFsc2UpLFxyXG4gIEhJR0hDSEFSVFNfQ09SRV9TQ1JJUFRTOiB2YWxpZGF0b3JzLmNvcmVTY3JpcHRzKGZhbHNlKSxcclxuICBISUdIQ0hBUlRTX01PRFVMRV9TQ1JJUFRTOiB2YWxpZGF0b3JzLm1vZHVsZVNjcmlwdHMoZmFsc2UpLFxyXG4gIEhJR0hDSEFSVFNfSU5ESUNBVE9SX1NDUklQVFM6IHZhbGlkYXRvcnMuaW5kaWNhdG9yU2NyaXB0cyhmYWxzZSksXHJcbiAgSElHSENIQVJUU19DVVNUT01fU0NSSVBUUzogdmFsaWRhdG9ycy5jdXN0b21TY3JpcHRzKGZhbHNlKSxcclxuXHJcbiAgLy8gZXhwb3J0XHJcbiAgRVhQT1JUX0lORklMRTogdmFsaWRhdG9ycy5pbmZpbGUoZmFsc2UpLFxyXG4gIEVYUE9SVF9JTlNUUjogdmFsaWRhdG9ycy5pbnN0cigpLFxyXG4gIEVYUE9SVF9PUFRJT05TOiB2YWxpZGF0b3JzLm9wdGlvbnMoKSxcclxuICBFWFBPUlRfU1ZHOiB2YWxpZGF0b3JzLnN2ZygpLFxyXG4gIEVYUE9SVF9CQVRDSDogdmFsaWRhdG9ycy5iYXRjaChmYWxzZSksXHJcbiAgRVhQT1JUX09VVEZJTEU6IHZhbGlkYXRvcnMub3V0ZmlsZShmYWxzZSksXHJcbiAgRVhQT1JUX1RZUEU6IHZhbGlkYXRvcnMudHlwZShmYWxzZSksXHJcbiAgRVhQT1JUX0NPTlNUUjogdmFsaWRhdG9ycy5jb25zdHIoZmFsc2UpLFxyXG4gIEVYUE9SVF9CNjQ6IHZhbGlkYXRvcnMuYjY0KGZhbHNlKSxcclxuICBFWFBPUlRfTk9fRE9XTkxPQUQ6IHZhbGlkYXRvcnMubm9Eb3dubG9hZChmYWxzZSksXHJcbiAgRVhQT1JUX0hFSUdIVDogdmFsaWRhdG9ycy5oZWlnaHQoZmFsc2UpLFxyXG4gIEVYUE9SVF9XSURUSDogdmFsaWRhdG9ycy53aWR0aChmYWxzZSksXHJcbiAgRVhQT1JUX1NDQUxFOiB2YWxpZGF0b3JzLnNjYWxlKGZhbHNlKSxcclxuICBFWFBPUlRfREVGQVVMVF9IRUlHSFQ6IHZhbGlkYXRvcnMuZGVmYXVsdEhlaWdodChmYWxzZSksXHJcbiAgRVhQT1JUX0RFRkFVTFRfV0lEVEg6IHZhbGlkYXRvcnMuZGVmYXVsdFdpZHRoKGZhbHNlKSxcclxuICBFWFBPUlRfREVGQVVMVF9TQ0FMRTogdmFsaWRhdG9ycy5kZWZhdWx0U2NhbGUoZmFsc2UpLFxyXG4gIEVYUE9SVF9HTE9CQUxfT1BUSU9OUzogdmFsaWRhdG9ycy5nbG9iYWxPcHRpb25zKCksXHJcbiAgRVhQT1JUX1RIRU1FX09QVElPTlM6IHZhbGlkYXRvcnMudGhlbWVPcHRpb25zKCksXHJcbiAgRVhQT1JUX1JBU1RFUklaQVRJT05fVElNRU9VVDogdmFsaWRhdG9ycy5yYXN0ZXJpemF0aW9uVGltZW91dChmYWxzZSksXHJcblxyXG4gIC8vIGN1c3RvbVxyXG4gIENVU1RPTV9MT0dJQ19BTExPV19DT0RFX0VYRUNVVElPTjogdmFsaWRhdG9ycy5hbGxvd0NvZGVFeGVjdXRpb24oZmFsc2UpLFxyXG4gIENVU1RPTV9MT0dJQ19BTExPV19GSUxFX1JFU09VUkNFUzogdmFsaWRhdG9ycy5hbGxvd0ZpbGVSZXNvdXJjZXMoZmFsc2UpLFxyXG4gIENVU1RPTV9MT0dJQ19DVVNUT01fQ09ERTogdmFsaWRhdG9ycy5jdXN0b21Db2RlKGZhbHNlKSxcclxuICBDVVNUT01fTE9HSUNfQ0FMTEJBQ0s6IHZhbGlkYXRvcnMuY2FsbGJhY2soZmFsc2UpLFxyXG4gIENVU1RPTV9MT0dJQ19SRVNPVVJDRVM6IHZhbGlkYXRvcnMucmVzb3VyY2VzKGZhbHNlKSxcclxuICBDVVNUT01fTE9HSUNfTE9BRF9DT05GSUc6IHZhbGlkYXRvcnMubG9hZENvbmZpZyhmYWxzZSksXHJcbiAgQ1VTVE9NX0xPR0lDX0NSRUFURV9DT05GSUc6IHZhbGlkYXRvcnMuY3JlYXRlQ29uZmlnKGZhbHNlKSxcclxuXHJcbiAgLy8gc2VydmVyXHJcbiAgU0VSVkVSX0VOQUJMRTogdmFsaWRhdG9ycy5lbmFibGVTZXJ2ZXIoZmFsc2UpLFxyXG4gIFNFUlZFUl9IT1NUOiB2YWxpZGF0b3JzLmhvc3QoZmFsc2UpLFxyXG4gIFNFUlZFUl9QT1JUOiB2YWxpZGF0b3JzLnBvcnQoZmFsc2UpLFxyXG4gIFNFUlZFUl9VUExPQURfTElNSVQ6IHZhbGlkYXRvcnMudXBsb2FkTGltaXQoZmFsc2UpLFxyXG4gIFNFUlZFUl9CRU5DSE1BUktJTkc6IHZhbGlkYXRvcnMuc2VydmVyQmVuY2htYXJraW5nKGZhbHNlKSxcclxuXHJcbiAgLy8gc2VydmVyIHByb3h5XHJcbiAgU0VSVkVSX1BST1hZX0hPU1Q6IHZhbGlkYXRvcnMucHJveHlIb3N0KGZhbHNlKSxcclxuICBTRVJWRVJfUFJPWFlfUE9SVDogdmFsaWRhdG9ycy5wcm94eVBvcnQoZmFsc2UpLFxyXG4gIFNFUlZFUl9QUk9YWV9USU1FT1VUOiB2YWxpZGF0b3JzLnByb3h5VGltZW91dChmYWxzZSksXHJcblxyXG4gIC8vIHNlcnZlciByYXRlIGxpbWl0aW5nXHJcbiAgU0VSVkVSX1JBVEVfTElNSVRJTkdfRU5BQkxFOiB2YWxpZGF0b3JzLmVuYWJsZVJhdGVMaW1pdGluZyhmYWxzZSksXHJcbiAgU0VSVkVSX1JBVEVfTElNSVRJTkdfTUFYX1JFUVVFU1RTOiB2YWxpZGF0b3JzLm1heFJlcXVlc3RzKGZhbHNlKSxcclxuICBTRVJWRVJfUkFURV9MSU1JVElOR19XSU5ET1c6IHZhbGlkYXRvcnMud2luZG93KGZhbHNlKSxcclxuICBTRVJWRVJfUkFURV9MSU1JVElOR19ERUxBWTogdmFsaWRhdG9ycy5kZWxheShmYWxzZSksXHJcbiAgU0VSVkVSX1JBVEVfTElNSVRJTkdfVFJVU1RfUFJPWFk6IHZhbGlkYXRvcnMudHJ1c3RQcm94eShmYWxzZSksXHJcbiAgU0VSVkVSX1JBVEVfTElNSVRJTkdfU0tJUF9LRVk6IHZhbGlkYXRvcnMuc2tpcEtleShmYWxzZSksXHJcbiAgU0VSVkVSX1JBVEVfTElNSVRJTkdfU0tJUF9UT0tFTjogdmFsaWRhdG9ycy5za2lwVG9rZW4oZmFsc2UpLFxyXG5cclxuICAvLyBzZXJ2ZXIgc3NsXHJcbiAgU0VSVkVSX1NTTF9FTkFCTEU6IHZhbGlkYXRvcnMuZW5hYmxlU3NsKGZhbHNlKSxcclxuICBTRVJWRVJfU1NMX0ZPUkNFOiB2YWxpZGF0b3JzLnNzbEZvcmNlKGZhbHNlKSxcclxuICBTRVJWRVJfU1NMX1BPUlQ6IHZhbGlkYXRvcnMuc3NsUG9ydChmYWxzZSksXHJcbiAgU0VSVkVSX1NTTF9DRVJUX1BBVEg6IHZhbGlkYXRvcnMuc3NsQ2VydFBhdGgoZmFsc2UpLFxyXG5cclxuICAvLyBwb29sXHJcbiAgUE9PTF9NSU5fV09SS0VSUzogdmFsaWRhdG9ycy5taW5Xb3JrZXJzKGZhbHNlKSxcclxuICBQT09MX01BWF9XT1JLRVJTOiB2YWxpZGF0b3JzLm1heFdvcmtlcnMoZmFsc2UpLFxyXG4gIFBPT0xfV09SS19MSU1JVDogdmFsaWRhdG9ycy53b3JrTGltaXQoZmFsc2UpLFxyXG4gIFBPT0xfQUNRVUlSRV9USU1FT1VUOiB2YWxpZGF0b3JzLmFjcXVpcmVUaW1lb3V0KGZhbHNlKSxcclxuICBQT09MX0NSRUFURV9USU1FT1VUOiB2YWxpZGF0b3JzLmNyZWF0ZVRpbWVvdXQoZmFsc2UpLFxyXG4gIFBPT0xfREVTVFJPWV9USU1FT1VUOiB2YWxpZGF0b3JzLmRlc3Ryb3lUaW1lb3V0KGZhbHNlKSxcclxuICBQT09MX0lETEVfVElNRU9VVDogdmFsaWRhdG9ycy5pZGxlVGltZW91dChmYWxzZSksXHJcbiAgUE9PTF9DUkVBVEVfUkVUUllfSU5URVJWQUw6IHZhbGlkYXRvcnMuY3JlYXRlUmV0cnlJbnRlcnZhbChmYWxzZSksXHJcbiAgUE9PTF9SRUFQRVJfSU5URVJWQUw6IHZhbGlkYXRvcnMucmVhcGVySW50ZXJ2YWwoZmFsc2UpLFxyXG4gIFBPT0xfQkVOQ0hNQVJLSU5HOiB2YWxpZGF0b3JzLnBvb2xCZW5jaG1hcmtpbmcoZmFsc2UpLFxyXG5cclxuICAvLyBsb2dnaW5nXHJcbiAgTE9HR0lOR19MRVZFTDogdmFsaWRhdG9ycy5sb2dMZXZlbChmYWxzZSksXHJcbiAgTE9HR0lOR19GSUxFOiB2YWxpZGF0b3JzLmxvZ0ZpbGUoZmFsc2UpLFxyXG4gIExPR0dJTkdfREVTVDogdmFsaWRhdG9ycy5sb2dEZXN0KGZhbHNlKSxcclxuICBMT0dHSU5HX1RPX0NPTlNPTEU6IHZhbGlkYXRvcnMubG9nVG9Db25zb2xlKGZhbHNlKSxcclxuICBMT0dHSU5HX1RPX0ZJTEU6IHZhbGlkYXRvcnMubG9nVG9GaWxlKGZhbHNlKSxcclxuXHJcbiAgLy8gdWlcclxuICBVSV9FTkFCTEU6IHZhbGlkYXRvcnMuZW5hYmxlVWkoZmFsc2UpLFxyXG4gIFVJX1JPVVRFOiB2YWxpZGF0b3JzLnVpUm91dGUoZmFsc2UpLFxyXG5cclxuICAvLyBvdGhlclxyXG4gIE9USEVSX05PREVfRU5WOiB2YWxpZGF0b3JzLm5vZGVFbnYoZmFsc2UpLFxyXG4gIE9USEVSX0xJU1RFTl9UT19QUk9DRVNTX0VYSVRTOiB2YWxpZGF0b3JzLmxpc3RlblRvUHJvY2Vzc0V4aXRzKGZhbHNlKSxcclxuICBPVEhFUl9OT19MT0dPOiB2YWxpZGF0b3JzLm5vTG9nbyhmYWxzZSksXHJcbiAgT1RIRVJfSEFSRF9SRVNFVF9QQUdFOiB2YWxpZGF0b3JzLmhhcmRSZXNldFBhZ2UoZmFsc2UpLFxyXG4gIE9USEVSX0JST1dTRVJfU0hFTExfTU9ERTogdmFsaWRhdG9ycy5icm93c2VyU2hlbGxNb2RlKGZhbHNlKSxcclxuICBPVEhFUl9WQUxJREFUSU9OOiB2YWxpZGF0b3JzLnZhbGlkYXRpb24oZmFsc2UpLFxyXG5cclxuICAvLyBkZWJ1Z2dlclxyXG4gIERFQlVHX0VOQUJMRTogdmFsaWRhdG9ycy5lbmFibGVEZWJ1ZyhmYWxzZSksXHJcbiAgREVCVUdfSEVBRExFU1M6IHZhbGlkYXRvcnMuaGVhZGxlc3MoZmFsc2UpLFxyXG4gIERFQlVHX0RFVlRPT0xTOiB2YWxpZGF0b3JzLmRldnRvb2xzKGZhbHNlKSxcclxuICBERUJVR19MSVNURU5fVE9fQ09OU09MRTogdmFsaWRhdG9ycy5saXN0ZW5Ub0NvbnNvbGUoZmFsc2UpLFxyXG4gIERFQlVHX0RVTVBJTzogdmFsaWRhdG9ycy5kdW1waW8oZmFsc2UpLFxyXG4gIERFQlVHX1NMT1dfTU86IHZhbGlkYXRvcnMuc2xvd01vKGZhbHNlKSxcclxuICBERUJVR19ERUJVR0dJTkdfUE9SVDogdmFsaWRhdG9ycy5kZWJ1Z2dpbmdQb3J0KGZhbHNlKVxyXG59KTtcclxuXHJcbi8qKlxyXG4gKiBWYWxpZGF0ZXMgdGhlIGVudmlyb25tZW50IHZhcmlhYmxlcyBvcHRpb25zIHVzaW5nIHRoZSBFbnZTY2hlbWEuXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBwcm9jZXNzLmVudiAtIFRoZSBjb25maWd1cmF0aW9uIG9wdGlvbnMgZnJvbSBlbnZpcm9ubWVudFxyXG4gKiB2YXJpYWJsZXMgZmlsZSB0byB2YWxpZGF0ZS5cclxuICpcclxuICogQHJldHVybnMge09iamVjdH0gVGhlIHBhcnNlZCBhbmQgdmFsaWRhdGVkIGVudmlyb25tZW50IHZhcmlhYmxlcy5cclxuICovXHJcbmV4cG9ydCBjb25zdCBlbnZzID0gRW52U2NoZW1hLnBhcnRpYWwoKS5wYXJzZShwcm9jZXNzLmVudik7XHJcblxyXG4vKipcclxuICogVmFsaWRhdGVzIHRoZSBjb25maWd1cmF0aW9uIG9wdGlvbnMgdXNpbmcgdGhlIGBTdHJpY3RDb25maWdTY2hlbWFgLlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gc3RyaWN0VmFsaWRhdGVcclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IGNvbmZpZ09wdGlvbnMgLSBUaGUgY29uZmlndXJhdGlvbiBvcHRpb25zIHRvIHZhbGlkYXRlLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7T2JqZWN0fSBUaGUgcGFyc2VkIGFuZCB2YWxpZGF0ZWQgY29uZmlndXJhdGlvbiBvcHRpb25zLlxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIHN0cmljdFZhbGlkYXRlKGNvbmZpZ09wdGlvbnMpIHtcclxuICByZXR1cm4gU3RyaWN0Q29uZmlnU2NoZW1hLnBhcnRpYWwoKS5wYXJzZShjb25maWdPcHRpb25zKTtcclxufVxyXG5cclxuLyoqXHJcbiAqIFZhbGlkYXRlcyB0aGUgY29uZmlndXJhdGlvbiBvcHRpb25zIHVzaW5nIHRoZSBgTG9vc2VDb25maWdTY2hlbWFgLlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gbG9vc2VWYWxpZGF0ZVxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gY29uZmlnT3B0aW9ucyAtIFRoZSBjb25maWd1cmF0aW9uIG9wdGlvbnMgdG8gdmFsaWRhdGUuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtPYmplY3R9IFRoZSBwYXJzZWQgYW5kIHZhbGlkYXRlZCBjb25maWd1cmF0aW9uIG9wdGlvbnMuXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gbG9vc2VWYWxpZGF0ZShjb25maWdPcHRpb25zKSB7XHJcbiAgcmV0dXJuIExvb3NlQ29uZmlnU2NoZW1hLnBhcnRpYWwoKS5wYXJzZShjb25maWdPcHRpb25zKTtcclxufVxyXG5cclxuLyoqXHJcbiAqIEN1c3RvbSBlcnJvciBtYXBwaW5nIGZ1bmN0aW9uIGZvciBab2Qgc2NoZW1hIHZhbGlkYXRpb24uXHJcbiAqXHJcbiAqIFRoaXMgZnVuY3Rpb24gY3VzdG9taXplcyB0aGUgZXJyb3IgbWVzc2FnZXMgcHJvZHVjZWQgYnkgWm9kIHNjaGVtYVxyXG4gKiB2YWxpZGF0aW9uLCBwcm92aWRpbmcgbW9yZSBzcGVjaWZpYyBhbmQgdXNlci1mcmllbmRseSBmZWVkYmFjayBiYXNlZCBvbiB0aGVcclxuICogaXNzdWUgdHlwZSBhbmQgY29udGV4dC5cclxuICpcclxuICogVGhlIGZ1bmN0aW9uIG1vZGlmaWVzIHRoZSBlcnJvciBtZXNzYWdlcyBhcyBmb2xsb3dzOlxyXG4gKlxyXG4gKiAtIEZvciBtaXNzaW5nIHJlcXVpcmVkIHZhbHVlcyAodW5kZWZpbmVkKSwgaXQgcmV0dXJucyBhIG1lc3NhZ2UgaW5kaWNhdGluZ1xyXG4gKiB0aGF0IG5vIHZhbHVlIHdhcyBwcm92aWRlZCBmb3IgdGhlIHNwZWNpZmljIHByb3BlcnR5LlxyXG4gKlxyXG4gKiAtIEZvciBjdXN0b20gdmFsaWRhdGlvbiBlcnJvcnMsIGlmIGEgY3VzdG9tIGVycm9yIG1lc3NhZ2UgaXMgcHJvdmlkZWQgaW4gdGhlXHJcbiAqIGlzc3VlIHBhcmFtZXRlcnMsIGl0IGluY2x1ZGVzIHRoaXMgbWVzc2FnZSBhbG9uZyB3aXRoIHRoZSBpbnZhbGlkIGRhdGFcclxuICogcmVjZWl2ZWQuXHJcbiAqXHJcbiAqIC0gRm9yIGFsbCBvdGhlciBlcnJvcnMsIGl0IGFwcGVuZHMgcHJvcGVydHktc3BlY2lmaWMgaW5mb3JtYXRpb24gdG8gdGhlXHJcbiAqIGRlZmF1bHQgZXJyb3IgbWVzc2FnZSBwcm92aWRlZCBieSBab2QuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBfY3VzdG9tRXJyb3JNYXBcclxuICpcclxuICogQHBhcmFtIHt6LlpvZElzc3VlfSBpc3N1ZSAtIFRoZSBpc3N1ZSBvYmplY3QgcmVwcmVzZW50aW5nIHRoZSB2YWxpZGF0aW9uXHJcbiAqIGVycm9yLlxyXG4gKiBAcGFyYW0ge09iamVjdH0gY29udGV4dCAtIFRoZSBjb250ZXh0IG9iamVjdCBwcm92aWRpbmcgYWRkaXRpb25hbCBpbmZvcm1hdGlvblxyXG4gKiBhYm91dCB0aGUgdmFsaWRhdGlvbiBlcnJvci5cclxuICpcclxuICogQHJldHVybnMge09iamVjdH0gQW4gb2JqZWN0IGNvbnRhaW5pbmcgdGhlIGN1c3RvbWl6ZWQgZXJyb3IgbWVzc2FnZS5cclxuICovXHJcbmZ1bmN0aW9uIF9jdXN0b21FcnJvck1hcChpc3N1ZSwgY29udGV4dCkge1xyXG4gIC8vIEdldCB0aGUgY2hhaW4gb2YgcHJvcGVydGllcyB3aGljaCBlcnJvciBkaXJlY3RseSByZWZlcnMgdG9cclxuICBjb25zdCBwcm9wZXJ0eU5hbWUgPSBpc3N1ZS5wYXRoLmpvaW4oJy4nKTtcclxuXHJcbiAgLy8gQ3JlYXRlIHRoZSBmaXJzdCBwYXJ0IG9mIHRoZSBtZXNzYWdlIGFib3V0IHRoZSBwcm9wZXJ0eSBpbmZvcm1hdGlvblxyXG4gIGNvbnN0IHByb3BlcnR5SW5mbyA9IGBJbnZhbGlkIHZhbHVlIGZvciB0aGUgJHtwcm9wZXJ0eU5hbWV9YDtcclxuXHJcbiAgLy8gTW9kaWZpZWQgbWVzc2FnZSBmb3IgdGhlIGludmFsaWQgdHlwZVxyXG4gIGlmIChpc3N1ZS5jb2RlID09PSB6LlpvZElzc3VlQ29kZS5pbnZhbGlkX3R5cGUpIHtcclxuICAgIC8vIE1vZGlmaWVkIG1lc3NhZ2UgZm9yIHRoZSByZXF1aXJlZCB2YWx1ZXNcclxuICAgIGlmIChpc3N1ZS5yZWNlaXZlZCA9PT0gei5ab2RQYXJzZWRUeXBlLnVuZGVmaW5lZCkge1xyXG4gICAgICByZXR1cm4ge1xyXG4gICAgICAgIG1lc3NhZ2U6IGAke3Byb3BlcnR5SW5mb30gLSBObyB2YWx1ZSB3YXMgcHJvdmlkZWQuYFxyXG4gICAgICB9O1xyXG4gICAgfVxyXG5cclxuICAgIC8vIE1vZGlmaWVkIG1lc3NhZ2UgZm9yIHRoZSBzcGVjaWZpYyBpbnZhbGlkIHR5cGUgd2hlbiB2YWx1ZXMgZXhpc3RcclxuICAgIHJldHVybiB7XHJcbiAgICAgIG1lc3NhZ2U6IGAke3Byb3BlcnR5SW5mb30gLSBJbnZhbGlkIHR5cGUuICR7Y29udGV4dC5kZWZhdWx0RXJyb3J9LmBcclxuICAgIH07XHJcbiAgfVxyXG5cclxuICAvLyBNb2RpZmllZCBtZXNzYWdlIGZvciB0aGUgY3VzdG9tIHZhbGlkYXRpb25cclxuICBpZiAoaXNzdWUuY29kZSA9PT0gei5ab2RJc3N1ZUNvZGUuY3VzdG9tKSB7XHJcbiAgICAvLyBJZiB0aGUgY3VzdG9tIG1lc3NhZ2UgZm9yIGVycm9yIGV4aXN0LCBpbmNsdWRlIGl0XHJcbiAgICBpZiAoaXNzdWUucGFyYW1zPy5lcnJvck1lc3NhZ2UpIHtcclxuICAgICAgcmV0dXJuIHtcclxuICAgICAgICBtZXNzYWdlOiBgJHtwcm9wZXJ0eUluZm99IC0gJHtpc3N1ZS5wYXJhbXM/LmVycm9yTWVzc2FnZX0sIHJlY2VpdmVkICcke2NvbnRleHQuZGF0YX0nLmBcclxuICAgICAgfTtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIC8vIE1vZGlmaWVkIG1lc3NhZ2UgZm9yIHRoZSBpbnZhbGlkIHVuaW9uIGVycm9yXHJcbiAgaWYgKGlzc3VlLmNvZGUgPT09IHouWm9kSXNzdWVDb2RlLmludmFsaWRfdW5pb24pIHtcclxuICAgIC8vIENyZWF0ZSB0aGUgZmlyc3QgcGFydCBvZiB0aGUgbWVzc2FnZSBhYm91dCB0aGUgbXVsdGlwbGUgZXJyb3JzXHJcbiAgICBsZXQgbWVzc2FnZSA9IGBNdWx0aXBsZSBlcnJvcnMgb2NjdXJyZWQgZm9yIHRoZSAke3Byb3BlcnR5TmFtZX06XFxuYDtcclxuXHJcbiAgICAvLyBDeWNsZSB0aHJvdWdoIGFsbCBlcnJvcnMgYW5kIGNyZWF0ZSBhIGNvcnJlY3QgbWVzc2FnZVxyXG4gICAgaXNzdWUudW5pb25FcnJvcnMuZm9yRWFjaCgodmFsdWUpID0+IHtcclxuICAgICAgY29uc3QgaW5kZXggPSB2YWx1ZS5pc3N1ZXNbMF0ubWVzc2FnZS5pbmRleE9mKCctJyk7XHJcbiAgICAgIG1lc3NhZ2UgKz1cclxuICAgICAgICBpbmRleCAhPT0gLTFcclxuICAgICAgICAgID8gYCR7dmFsdWUuaXNzdWVzWzBdLm1lc3NhZ2V9XFxuYC5zdWJzdHJpbmcoaW5kZXgpXHJcbiAgICAgICAgICA6IGAke3ZhbHVlLmlzc3Vlc1swXS5tZXNzYWdlfVxcbmA7XHJcbiAgICB9KTtcclxuXHJcbiAgICAvLyBSZXR1cm4gdGhlIGZpbmFsIG1lc3NhZ2UgZm9yIHRoZSBpbnZhbGlkIHVuaW9uIGVycm9yXHJcbiAgICByZXR1cm4ge1xyXG4gICAgICBtZXNzYWdlXHJcbiAgICB9O1xyXG4gIH1cclxuXHJcbiAgLy8gUmV0dXJuIHRoZSBkZWZhdWx0IGVycm9yIG1lc3NhZ2UsIGV4dGVuZGVkIGJ5IHRoZSBpbmZvIGFib3V0IHRoZSBwcm9wZXJ0eVxyXG4gIHJldHVybiB7XHJcbiAgICBtZXNzYWdlOiBgJHtwcm9wZXJ0eUluZm99IC0gJHtjb250ZXh0LmRlZmF1bHRFcnJvcn0uYFxyXG4gIH07XHJcbn1cclxuXHJcbmV4cG9ydCBkZWZhdWx0IHtcclxuICB2YWxpZGF0b3JzLFxyXG4gIFN0cmljdENvbmZpZ1NjaGVtYSxcclxuICBMb29zZUNvbmZpZ1NjaGVtYSxcclxuICBFbnZTY2hlbWEsXHJcbiAgZW52cyxcclxuICBzdHJpY3RWYWxpZGF0ZSxcclxuICBsb29zZVZhbGlkYXRlXHJcbn07XHJcbiIsIi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXHJcblxyXG5IaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXJcclxuXHJcbkNvcHlyaWdodCAoYykgMjAxNi0yMDI1LCBIaWdoc29mdFxyXG5cclxuTGljZW5jZWQgdW5kZXIgdGhlIE1JVCBsaWNlbmNlLlxyXG5cclxuQWRkaXRpb25hbGx5IGEgdmFsaWQgSGlnaGNoYXJ0cyBsaWNlbnNlIGlzIHJlcXVpcmVkIGZvciB1c2UuXHJcblxyXG5TZWUgTElDRU5TRSBmaWxlIGluIHJvb3QgZm9yIGRldGFpbHMuXHJcblxyXG4qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xyXG5cclxuLyoqXHJcbiAqIEEgY3VzdG9tIGVycm9yIGNsYXNzIGZvciBoYW5kbGluZyBleHBvcnQtcmVsYXRlZCBlcnJvcnMuIEV4dGVuZHMgdGhlIG5hdGl2ZVxyXG4gKiBgRXJyb3JgIGNsYXNzIHRvIGluY2x1ZGUgYWRkaXRpb25hbCBwcm9wZXJ0aWVzIGxpa2Ugc3RhdHVzIGNvZGUgYW5kIHN0YWNrXHJcbiAqIHRyYWNlIGRldGFpbHMuXHJcbiAqL1xyXG5jbGFzcyBFeHBvcnRFcnJvciBleHRlbmRzIEVycm9yIHtcclxuICAvKipcclxuICAgKiBDcmVhdGVzIGFuIGluc3RhbmNlIG9mIHRoZSBgRXhwb3J0RXJyb3JgLlxyXG4gICAqXHJcbiAgICogQHBhcmFtIHtzdHJpbmd9IG1lc3NhZ2UgLSBUaGUgZXJyb3IgbWVzc2FnZSB0byBiZSBkaXNwbGF5ZWQuXHJcbiAgICogQHBhcmFtIHtudW1iZXJ9IHN0YXR1c0NvZGUgLSBPcHRpb25hbCBIVFRQIHN0YXR1cyBjb2RlIGFzc29jaWF0ZWRcclxuICAgKiB3aXRoIHRoZSBlcnJvciAoZS5nLiwgNDAwLCA1MDApLlxyXG4gICAqL1xyXG4gIGNvbnN0cnVjdG9yKG1lc3NhZ2UsIHN0YXR1c0NvZGUpIHtcclxuICAgIHN1cGVyKCk7XHJcblxyXG4gICAgdGhpcy5tZXNzYWdlID0gbWVzc2FnZTtcclxuICAgIHRoaXMuc3RhY2tNZXNzYWdlID0gbWVzc2FnZTtcclxuXHJcbiAgICBpZiAoc3RhdHVzQ29kZSkge1xyXG4gICAgICB0aGlzLnN0YXR1c0NvZGUgPSBzdGF0dXNDb2RlO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgLyoqXHJcbiAgICogU2V0cyBvciB1cGRhdGVzIHRoZSBIVFRQIHN0YXR1cyBjb2RlIGZvciB0aGUgZXJyb3IuXHJcbiAgICpcclxuICAgKiBAcGFyYW0ge251bWJlcn0gc3RhdHVzQ29kZSAtIFRoZSBIVFRQIHN0YXR1cyBjb2RlIHRvIGFzc2lnbiB0byB0aGUgZXJyb3IuXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7RXhwb3J0RXJyb3J9IFRoZSB1cGRhdGVkIGluc3RhbmNlIG9mIHRoZSBgRXhwb3J0RXJyb3JgIGNsYXNzLlxyXG4gICAqL1xyXG4gIHNldFN0YXR1cyhzdGF0dXNDb2RlKSB7XHJcbiAgICB0aGlzLnN0YXR1c0NvZGUgPSBzdGF0dXNDb2RlO1xyXG5cclxuICAgIHJldHVybiB0aGlzO1xyXG4gIH1cclxuXHJcbiAgLyoqXHJcbiAgICogU2V0cyBhZGRpdGlvbmFsIGVycm9yIGRldGFpbHMgYmFzZWQgb24gYW4gZXhpc3RpbmcgZXJyb3Igb2JqZWN0LlxyXG4gICAqXHJcbiAgICogQHBhcmFtIHtFcnJvcn0gZXJyb3IgLSBBbiBlcnJvciBvYmplY3QgY29udGFpbmluZyBkZXRhaWxzIHRvIHBvcHVsYXRlXHJcbiAgICogdGhlIGBFeHBvcnRFcnJvcmAgaW5zdGFuY2UuXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7RXhwb3J0RXJyb3J9IFRoZSB1cGRhdGVkIGluc3RhbmNlIG9mIHRoZSBgRXhwb3J0RXJyb3JgIGNsYXNzLlxyXG4gICAqL1xyXG4gIHNldEVycm9yKGVycm9yKSB7XHJcbiAgICB0aGlzLmVycm9yID0gZXJyb3I7XHJcblxyXG4gICAgaWYgKGVycm9yLm5hbWUpIHtcclxuICAgICAgdGhpcy5uYW1lID0gZXJyb3IubmFtZTtcclxuICAgIH1cclxuXHJcbiAgICBpZiAoZXJyb3Iuc3RhdHVzQ29kZSkge1xyXG4gICAgICB0aGlzLnN0YXR1c0NvZGUgPSBlcnJvci5zdGF0dXNDb2RlO1xyXG4gICAgfVxyXG5cclxuICAgIGlmIChlcnJvci5zdGFjaykge1xyXG4gICAgICB0aGlzLnN0YWNrTWVzc2FnZSA9IGVycm9yLm1lc3NhZ2U7XHJcbiAgICAgIHRoaXMuc3RhY2sgPSBlcnJvci5zdGFjaztcclxuICAgIH1cclxuXHJcbiAgICByZXR1cm4gdGhpcztcclxuICB9XHJcbn1cclxuXHJcbmV4cG9ydCBkZWZhdWx0IEV4cG9ydEVycm9yO1xyXG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxyXG5cclxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXHJcblxyXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNSwgSGlnaHNvZnRcclxuXHJcbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cclxuXHJcbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxyXG5cclxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxyXG5cclxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cclxuXHJcbi8qKlxyXG4gKiBAb3ZlcnZpZXcgTWFuYWdlcyBjb25maWd1cmF0aW9uIGZvciB0aGUgSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyIGJ5IGxvYWRpbmdcclxuICogYW5kIG1lcmdpbmcgb3B0aW9ucyBmcm9tIG11bHRpcGxlIHNvdXJjZXMsIHN1Y2ggYXMgZGVmYXVsdCBzZXR0aW5ncyxcclxuICogZW52aXJvbm1lbnQgdmFyaWFibGVzLCB1c2VyLXByb3ZpZGVkIG9wdGlvbnMsIGFuZCBjb21tYW5kLWxpbmUgYXJndW1lbnRzLlxyXG4gKiBFbnN1cmVzIHRoZSBnbG9iYWwgb3B0aW9ucyBhcmUgdXAtdG8tZGF0ZSB3aXRoIHRoZSBoaWdoZXN0IHByaW9yaXR5IHZhbHVlcy5cclxuICogUHJvdmlkZXMgZnVuY3Rpb25zIGZvciBhY2Nlc3NpbmcgYW5kIHVwZGF0aW5nIGNvbmZpZ3VyYXRpb24uXHJcbiAqL1xyXG5cclxuaW1wb3J0IHsgcmVhZEZpbGVTeW5jIH0gZnJvbSAnZnMnO1xyXG5pbXBvcnQgeyBqb2luIH0gZnJvbSAncGF0aCc7XHJcblxyXG5pbXBvcnQgeyBsb2csIGxvZ1dpdGhTdGFjaywgbG9nWm9kSXNzdWVzIH0gZnJvbSAnLi9sb2dnZXIuanMnO1xyXG5pbXBvcnQgeyBfX2Rpcm5hbWUsIGRlZXBDb3B5LCBnZXRBYnNvbHV0ZVBhdGgsIGlzT2JqZWN0IH0gZnJvbSAnLi91dGlscy5qcyc7XHJcbmltcG9ydCB7XHJcbiAgZW52cyxcclxuICBsb29zZVZhbGlkYXRlLFxyXG4gIHN0cmljdFZhbGlkYXRlLFxyXG4gIHZhbGlkYXRvcnNcclxufSBmcm9tICcuL3ZhbGlkYXRpb24uanMnO1xyXG5cclxuaW1wb3J0IHsgZGVmYXVsdENvbmZpZywgYWJzb2x1dGVQcm9wcywgbmVzdGVkUHJvcHMgfSBmcm9tICcuL3NjaGVtYXMvY29uZmlnLmpzJztcclxuXHJcbmltcG9ydCBFeHBvcnRFcnJvciBmcm9tICcuL2Vycm9ycy9FeHBvcnRFcnJvci5qcyc7XHJcblxyXG4vLyBTZXRzIHRoZSBnbG9iYWwgb3B0aW9ucyB3aXRoIGluaXRpYWwgdmFsdWVzIGZyb20gdGhlIGRlZmF1bHQgY29uZmlnXHJcbmNvbnN0IGdsb2JhbE9wdGlvbnMgPSBfaW5pdEdsb2JhbE9wdGlvbnMoZGVmYXVsdENvbmZpZyk7XHJcblxyXG4vLyBBbiBvYmplY3QgZm9yIHRoZSBpbnN0YW5jZSBvcHRpb25zLCBjcmVhdGVkIGVhY2ggdGltZSB0aGUgYGluaXRFeHBvcnRgIG9jY3Vyc1xyXG5jb25zdCBpbnN0YW5jZU9wdGlvbnMgPSBkZWVwQ29weShnbG9iYWxPcHRpb25zKTtcclxuXHJcbi8qKlxyXG4gKiBSZXRyaWV2ZXMgYSByZWZlcmVuY2UgdG8gdGhlIG9wdGlvbnMgb2JqZWN0LiBEZXBlbmRpbmcgb24gdGhlIGBnZXRJbnN0YW5jZWBcclxuICogcGFyYW1ldGVyLCBpdCByZXR1cm5zIGVpdGhlciB0aGUgZ2xvYmFsIG9wdGlvbnMgb3IgdGhlIGluc3RhbmNlLXNwZWNpZmljXHJcbiAqIG9wdGlvbnMgb2JqZWN0LlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gZ2V0T3B0aW9uc1xyXG4gKlxyXG4gKiBAcGFyYW0ge2Jvb2xlYW59IFtnZXRJbnN0YW5jZT10cnVlXSAtIE9wdGlvbmFsIHBhcmFtZXRlciB0aGF0IGRlY2lkZXMgd2hldGhlclxyXG4gKiB0byByZXR1cm4gdGhlIGluc3RhbmNlLXNwZWNpZmljIG9wdGlvbnMgKHdoZW4gYHRydWVgKSBvciB0aGUgZ2xvYmFsIG9wdGlvbnNcclxuICogKHdoZW4gYGZhbHNlYCkuIFRoZSBkZWZhdWx0IHZhbHVlIGlzIGB0cnVlYC5cclxuICpcclxuICogQHJldHVybnMge09iamVjdH0gQSByZWZlcmVuY2UgdG8gZWl0aGVyIHRoZSBnbG9iYWwgb3B0aW9uc1xyXG4gKiBvciB0aGUgaW5zdGFuY2Utc3BlY2lmaWMgb3B0aW9ucywgYmFzZWQgb24gdGhlIGBnZXRJbnN0YW5jZWAgcGFyYW1ldGVyLlxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIGdldE9wdGlvbnMoZ2V0SW5zdGFuY2UgPSB0cnVlKSB7XHJcbiAgcmV0dXJuIGdldEluc3RhbmNlID8gaW5zdGFuY2VPcHRpb25zIDogZ2xvYmFsT3B0aW9ucztcclxufVxyXG5cclxuLyoqXHJcbiAqIFNldHMgdGhlIGdsb2JhbCBvcHRpb25zIG9mIHRoZSBleHBvcnQgc2VydmVyLCBrZWVwaW5nIHRoZSBwcmluY2lwbGVcclxuICogb2YgdGhlIG9wdGlvbnMgbG9hZCBwcmlvcml0eSBmcm9tIGFsbCBhdmFpbGFibGUgc291cmNlcy4gSXQgYWNjZXB0cyBvcHRpb25hbFxyXG4gKiBgY3VzdG9tT3B0aW9uc2Agb2JqZWN0IGFuZCBgY2xpQXJnc2AgYXJyYXkgd2l0aCBhcmd1bWVudHMgZnJvbSB0aGUgQ0xJLiBUaGVzZVxyXG4gKiBvcHRpb25zIHdpbGwgYmUgdmFsaWRhdGVkIGFuZCBhcHBsaWVkIGlmIHByb3ZpZGVkLlxyXG4gKlxyXG4gKiBUaGUgcHJpb3JpdHkgb3JkZXIgb2Ygc2V0dGluZyB2YWx1ZXMgaXM6XHJcbiAqXHJcbiAqIDEuIE9wdGlvbnMgZnJvbSB0aGUgYGxpYi9zY2hlbWFzL2NvbmZpZy5qc2AgZmlsZSAoZGVmYXVsdCB2YWx1ZXMpLlxyXG4gKiAyLiBPcHRpb25zIGZyb20gYSBjdXN0b20gSlNPTiBmaWxlIChsb2FkZWQgYnkgdGhlIGBsb2FkQ29uZmlnYCBvcHRpb24pLlxyXG4gKiAzLiBPcHRpb25zIGZyb20gdGhlIGVudmlyb25tZW50IHZhcmlhYmxlcyAodGhlIGAuZW52YCBmaWxlKS5cclxuICogNC4gT3B0aW9ucyBmcm9tIHRoZSBjb21tYW5kIGxpbmUgaW50ZXJmYWNlIChDTEkpLlxyXG4gKiA1LiBPcHRpb25zIGZyb20gdGhlIGZpcnN0IHBhcmFtZXRlciAodGhlIGBjdXN0b21PcHRpb25zYCBpcyBieSBkZWZhdWx0XHJcbiAqIGFuIGVtcHR5IG9iamVjdCkuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBzZXRHbG9iYWxPcHRpb25zXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBbY3VzdG9tT3B0aW9ucz17fV0gLSBPcHRpb25hbCBjdXN0b20gb3B0aW9ucyBmb3IgYWRkaXRpb25hbFxyXG4gKiBjb25maWd1cmF0aW9uLiBUaGUgZGVmYXVsdCB2YWx1ZSBpcyBhbiBlbXB0eSBvYmplY3QuXHJcbiAqIEBwYXJhbSB7QXJyYXkuPHN0cmluZz59IFtjbGlBcmdzPVtdXSAtIE9wdGlvbmFsIGNvbW1hbmQgbGluZSBhcmd1bWVudHNcclxuICogZm9yIGFkZGl0aW9uYWwgY29uZmlndXJhdGlvbi4gVGhlIGRlZmF1bHQgdmFsdWUgaXMgYW4gZW1wdHkgYXJyYXkuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtPYmplY3R9IFRoZSB1cGRhdGVkIGdsb2JhbCBvcHRpb25zIG9iamVjdCwgcmVmbGVjdGluZyB0aGUgbWVyZ2VkXHJcbiAqIGNvbmZpZ3VyYXRpb24gZnJvbSBhbGwgYXZhaWxhYmxlIHNvdXJjZXMuXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gc2V0R2xvYmFsT3B0aW9ucyhjdXN0b21PcHRpb25zID0ge30sIGNsaUFyZ3MgPSBbXSkge1xyXG4gIC8vIE9iamVjdCBmb3Igb3B0aW9ucyBsb2FkZWQgdmlhIHRoZSBgbG9hZENvbmZpZ2Agb3B0aW9uXHJcbiAgbGV0IGNvbmZpZ09wdGlvbnMgPSB7fTtcclxuXHJcbiAgLy8gT2JqZWN0IGZvciBvcHRpb25zIGZyb20gdGhlIENMSVxyXG4gIGxldCBjbGlPcHRpb25zID0ge307XHJcblxyXG4gIC8vIE9ubHkgZm9yIHRoZSBDTEkgdXNhZ2VcclxuICBpZiAoY2xpQXJncyAmJiBBcnJheS5pc0FycmF5KGNsaUFyZ3MpICYmIGNsaUFyZ3MubGVuZ3RoKSB7XHJcbiAgICB0cnkge1xyXG4gICAgICAvLyBWYWxpZGF0ZSBvcHRpb25zIGZyb20gdGhlIGN1c3RvbSBKU09OIGxvYWRlZCB2aWEgdGhlIGBsb2FkQ29uZmlnYFxyXG4gICAgICBjb25maWdPcHRpb25zID0gc3RyaWN0VmFsaWRhdGUoXHJcbiAgICAgICAgX2xvYWRDb25maWdGaWxlKGNsaUFyZ3MsIGdsb2JhbE9wdGlvbnMuY3VzdG9tTG9naWMpXHJcbiAgICAgICk7XHJcbiAgICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgICBsb2dab2RJc3N1ZXMoXHJcbiAgICAgICAgMSxcclxuICAgICAgICBlcnJvci5pc3N1ZXMsXHJcbiAgICAgICAgJ1t2YWxpZGF0aW9uXSBDdXN0b20gb3B0aW9ucyBmcm9tIHRoZSBgbG9hZENvbmZpZ2Agb3B0aW9uIHZhbGlkYXRpb24gZXJyb3InXHJcbiAgICAgICk7XHJcbiAgICB9XHJcblxyXG4gICAgdHJ5IHtcclxuICAgICAgLy8gVmFsaWRhdGUgb3B0aW9ucyBmcm9tIHRoZSBDTElcclxuICAgICAgY2xpT3B0aW9ucyA9IGxvb3NlVmFsaWRhdGUoX3BhaXJBcmd1bWVudFZhbHVlKG5lc3RlZFByb3BzLCBjbGlBcmdzKSk7XHJcbiAgICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgICBsb2dab2RJc3N1ZXMoXHJcbiAgICAgICAgMSxcclxuICAgICAgICBlcnJvci5pc3N1ZXMsXHJcbiAgICAgICAgJ1t2YWxpZGF0aW9uXSBDTEkgb3B0aW9ucyB2YWxpZGF0aW9uIGVycm9yJ1xyXG4gICAgICApO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgLy8gQXBwbHkgY3VzdG9tIG9wdGlvbnMgaWYgdGhlcmUgYXJlIGFueVxyXG4gIGlmIChcclxuICAgIGN1c3RvbU9wdGlvbnMgJiZcclxuICAgIGlzT2JqZWN0KGN1c3RvbU9wdGlvbnMpICYmXHJcbiAgICBPYmplY3Qua2V5cyhjdXN0b21PcHRpb25zKS5sZW5ndGhcclxuICApIHtcclxuICAgIHRyeSB7XHJcbiAgICAgIC8vIFZhbGlkYXRlIGN1c3RvbSBvcHRpb25zIHByb3ZpZGVkIGJ5IHRoZSB1c2VyXHJcbiAgICAgIGN1c3RvbU9wdGlvbnMgPSBzdHJpY3RWYWxpZGF0ZShjdXN0b21PcHRpb25zKTtcclxuICAgIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICAgIGxvZ1pvZElzc3VlcyhcclxuICAgICAgICAxLFxyXG4gICAgICAgIGVycm9yLmlzc3VlcyxcclxuICAgICAgICAnW3ZhbGlkYXRpb25dIEN1c3RvbSBvcHRpb25zIHZhbGlkYXRpb24gZXJyb3InXHJcbiAgICAgICk7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICAvLyBVcGRhdGUgdmFsdWVzIG9mIHRoZSBnbG9iYWwgb3B0aW9ucyB3aXRoIHZhbHVlcyBmcm9tIGVhY2ggc291cmNlIHBvc3NpYmxlXHJcbiAgX3VwZGF0ZUdsb2JhbE9wdGlvbnMoXHJcbiAgICBkZWZhdWx0Q29uZmlnLFxyXG4gICAgZ2xvYmFsT3B0aW9ucyxcclxuICAgIGNvbmZpZ09wdGlvbnMsXHJcbiAgICBjbGlPcHRpb25zLFxyXG4gICAgY3VzdG9tT3B0aW9uc1xyXG4gICk7XHJcblxyXG4gIC8vIFJldHVybiB1cGRhdGVkIGdsb2JhbCBvcHRpb25zXHJcbiAgcmV0dXJuIGdsb2JhbE9wdGlvbnM7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBVcGRhdGVzIHRoZSBpbnN0YW5jZSBvcHRpb25zIHdpdGggYWRkaXRpb25hbCBvcHRpb25zLiBJdCBvcHRpb25hbGx5IGFsbG93c1xyXG4gKiB0byByZWluaXRpYWxpemUgdGhlIGluc3RhbmNlIG9wdGlvbnMgd2l0aCB0aGUgdmFsdWVzIG9mIGEgY3VycmVudCBnbG9iYWxcclxuICogb3B0aW9ucyBvYmplY3QuXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSB1cGRhdGVPcHRpb25zIC0gVGhlIHVwZGF0ZSBvcHRpb25zIHRvIG1lcmdlIGludG8gdGhlIGluc3RhbmNlXHJcbiAqIG9wdGlvbnMuXHJcbiAqIEBwYXJhbSB7Ym9vbGVhbn0gW25ld0luc3RhbmNlPWZhbHNlXSAtIEEgZmxhZyB0byBpbmRpY2F0ZSB3aGV0aGVyIHRvIGluaXRcclxuICogb3B0aW9ucyBmb3IgYSBuZXcgaW5zdGFuY2UuIElmIGB0cnVlYCwgdGhlIGV4aXN0aW5nIGluc3RhbmNlIG9wdGlvbnMgd2lsbFxyXG4gKiBiZSBjbGVhcmVkIGFuZCByZWluaXRpYWxpemVkIGJhc2VkIG9uIHRoZSBnbG9iYWwgb3B0aW9ucy5cclxuICpcclxuICogQHJldHVybnMge09iamVjdH0gLSBUaGUgdXBkYXRlZCBpbnN0YW5jZSBvcHRpb25zLlxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIHVwZGF0ZU9wdGlvbnModXBkYXRlT3B0aW9ucywgbmV3SW5zdGFuY2UgPSBmYWxzZSkge1xyXG4gIC8vIENoZWNrIGlmIG9wdGlvbnMgbmVlZCB0byBiZSBjcmVhdGVkIGZvciBhIG5ldyBpbnN0YW5jZVxyXG4gIGlmIChuZXdJbnN0YW5jZSkge1xyXG4gICAgLy8gR2V0IHJpZCBvZiB0aGUgb2xkIGluc3RhbmNlIG9wdGlvbnNcclxuICAgIE9iamVjdC5rZXlzKGluc3RhbmNlT3B0aW9ucykuZm9yRWFjaCgoa2V5KSA9PiB7XHJcbiAgICAgIGRlbGV0ZSBpbnN0YW5jZU9wdGlvbnNba2V5XTtcclxuICAgIH0pO1xyXG5cclxuICAgIC8vIEluaXQgdGhlIG5ldyBpbnN0YW5jZSBvcHRpb25zIGJhc2VkIG9uIHRoZSBnbG9iYWwgb3B0aW9uc1xyXG4gICAgbWVyZ2VPcHRpb25zKGluc3RhbmNlT3B0aW9ucywgZGVlcENvcHkoZ2xvYmFsT3B0aW9ucykpO1xyXG4gIH1cclxuXHJcbiAgLy8gTWVyZ2UgYWRkaXRpb25hbCBvcHRpb25zIHRvIHRoZSBpbnN0YW5jZSBvcHRpb25zXHJcbiAgbWVyZ2VPcHRpb25zKGluc3RhbmNlT3B0aW9ucywgdXBkYXRlT3B0aW9ucyk7XHJcblxyXG4gIC8vIFJldHVybiB0aGUgcmVmZXJlbmNlIHRvIHRoZSBpbnN0YW5jZSBvcHRpb25zIG9iamVjdFxyXG4gIHJldHVybiBpbnN0YW5jZU9wdGlvbnM7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBNZXJnZXMgdHdvIHNldHMgb2YgY29uZmlndXJhdGlvbiBvcHRpb25zLCBjb25zaWRlcmluZyBhYnNvbHV0ZSBwcm9wZXJ0aWVzLlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gbWVyZ2VPcHRpb25zXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBvcmlnaW5hbE9wdGlvbnMgLSBPcmlnaW5hbCBjb25maWd1cmF0aW9uIG9wdGlvbnMuXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBuZXdPcHRpb25zIC0gTmV3IGNvbmZpZ3VyYXRpb24gb3B0aW9ucyB0byBiZSBtZXJnZWQuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtPYmplY3R9IE1lcmdlZCBjb25maWd1cmF0aW9uIG9wdGlvbnMuXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gbWVyZ2VPcHRpb25zKG9yaWdpbmFsT3B0aW9ucywgbmV3T3B0aW9ucykge1xyXG4gIC8vIENoZWNrIGlmIHRoZSBgb3JpZ2luYWxPcHRpb25zYCBhbmQgYG5ld09wdGlvbnNgIGFyZSBjb3JyZWN0IG9iamVjdHNcclxuICBpZiAoaXNPYmplY3Qob3JpZ2luYWxPcHRpb25zKSAmJiBpc09iamVjdChuZXdPcHRpb25zKSkge1xyXG4gICAgZm9yIChjb25zdCBba2V5LCB2YWx1ZV0gb2YgT2JqZWN0LmVudHJpZXMobmV3T3B0aW9ucykpIHtcclxuICAgICAgb3JpZ2luYWxPcHRpb25zW2tleV0gPVxyXG4gICAgICAgIGlzT2JqZWN0KHZhbHVlKSAmJlxyXG4gICAgICAgICFhYnNvbHV0ZVByb3BzLmluY2x1ZGVzKGtleSkgJiZcclxuICAgICAgICBvcmlnaW5hbE9wdGlvbnNba2V5XSAhPT0gdW5kZWZpbmVkXHJcbiAgICAgICAgICA/IG1lcmdlT3B0aW9ucyhvcmlnaW5hbE9wdGlvbnNba2V5XSwgdmFsdWUpXHJcbiAgICAgICAgICA6IHZhbHVlICE9PSB1bmRlZmluZWRcclxuICAgICAgICAgICAgPyB2YWx1ZVxyXG4gICAgICAgICAgICA6IG9yaWdpbmFsT3B0aW9uc1trZXldIHx8IG51bGw7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICAvLyBSZXR1cm4gdGhlIG9yaWdpbmFsIChtb2RpZmllZCBvciBub3QpIG9wdGlvbnNcclxuICByZXR1cm4gb3JpZ2luYWxPcHRpb25zO1xyXG59XHJcblxyXG4vKipcclxuICogTWFwcyBvbGQtc3RydWN0dXJlZCBjb25maWd1cmF0aW9uIG9wdGlvbnMgKFBoYW50b21KUykgdG8gYSBuZXcgZm9ybWF0XHJcbiAqIChQdXBwZXRlZXIpLiBUaGlzIGZ1bmN0aW9uIGNvbnZlcnRzIGZsYXQsIG9sZC1zdHJ1Y3R1cmVkIG9wdGlvbnMgaW50b1xyXG4gKiBhIG5ldywgbmVzdGVkIGNvbmZpZ3VyYXRpb24gZm9ybWF0IGJhc2VkIG9uIGEgcHJlZGVmaW5lZCBtYXBwaW5nXHJcbiAqIChgbmVzdGVkUHJvcHNgKS4gVGhlIG5ldyBmb3JtYXQgaXMgdXNlZCBmb3IgUHVwcGV0ZWVyLCB3aGlsZSB0aGUgb2xkIGZvcm1hdFxyXG4gKiB3YXMgdXNlZCBmb3IgUGhhbnRvbUpTLlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gbWFwVG9OZXdPcHRpb25zXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBvbGRPcHRpb25zIC0gVGhlIG9sZCwgZmxhdCBjb25maWd1cmF0aW9uIG9wdGlvbnNcclxuICogdG8gYmUgY29udmVydGVkLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7T2JqZWN0fSBBIG5ldyBvYmplY3QgY29udGFpbmluZyBvcHRpb25zIHN0cnVjdHVyZWQgYWNjb3JkaW5nXHJcbiAqIHRvIHRoZSBtYXBwaW5nIGRlZmluZWQgaW4gYG5lc3RlZFByb3BzYCBvciBhbiBlbXB0eSBvYmplY3QgaWYgdGhlIHByb3ZpZGVkXHJcbiAqIGBvbGRPcHRpb25zYCBpcyBub3QgYSBjb3JyZWN0IG9iamVjdC5cclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiBtYXBUb05ld09wdGlvbnMob2xkT3B0aW9ucykge1xyXG4gIC8vIEFuIG9iamVjdCBmb3IgdGhlIG5ldyBzdHJ1Y3R1cmVkIG9wdGlvbnNcclxuICBjb25zdCBuZXdPcHRpb25zID0ge307XHJcblxyXG4gIC8vIENoZWNrIGlmIHByb3ZpZGVkIHZhbHVlIGlzIGEgY29ycmVjdCBvYmplY3RcclxuICBpZiAoaXNPYmplY3Qob2xkT3B0aW9ucykpIHtcclxuICAgIC8vIEl0ZXJhdGUgb3ZlciBlYWNoIGtleS12YWx1ZSBwYWlyIGluIHRoZSBvbGQtc3RydWN0dXJlZCBvcHRpb25zXHJcbiAgICBmb3IgKGNvbnN0IFtrZXksIHZhbHVlXSBvZiBPYmplY3QuZW50cmllcyhvbGRPcHRpb25zKSkge1xyXG4gICAgICAvLyBJZiB0aGVyZSBpcyBhIG5lc3RlZCBtYXBwaW5nLCBzcGxpdCBpdCBpbnRvIGEgcHJvcGVydGllcyBjaGFpblxyXG4gICAgICBjb25zdCBwcm9wZXJ0aWVzQ2hhaW4gPSBuZXN0ZWRQcm9wc1trZXldXHJcbiAgICAgICAgPyBuZXN0ZWRQcm9wc1trZXldLnNwbGl0KCcuJylcclxuICAgICAgICA6IFtdO1xyXG5cclxuICAgICAgLy8gSWYgaXQgaXMgdGhlIGxhc3QgcHJvcGVydHkgaW4gdGhlIGNoYWluLCBhc3NpZ24gdGhlIHZhbHVlLCBvdGhlcndpc2UsXHJcbiAgICAgIC8vIGNyZWF0ZSBvciByZXVzZSB0aGUgbmVzdGVkIG9iamVjdFxyXG4gICAgICBwcm9wZXJ0aWVzQ2hhaW4ucmVkdWNlKFxyXG4gICAgICAgIChvYmosIHByb3AsIGluZGV4KSA9PlxyXG4gICAgICAgICAgKG9ialtwcm9wXSA9XHJcbiAgICAgICAgICAgIHByb3BlcnRpZXNDaGFpbi5sZW5ndGggLSAxID09PSBpbmRleCA/IHZhbHVlIDogb2JqW3Byb3BdIHx8IHt9KSxcclxuICAgICAgICBuZXdPcHRpb25zXHJcbiAgICAgICk7XHJcbiAgICB9XHJcbiAgfSBlbHNlIHtcclxuICAgIGxvZyhcclxuICAgICAgMixcclxuICAgICAgJ1tjb25maWddIE5vIGNvcnJlY3Qgb2JqZWN0IHdpdGggb3B0aW9ucyB3YXMgcHJvdmlkZWQuIFJldHVybmluZyBhbiBlbXB0eSBhcnJheS4nXHJcbiAgICApO1xyXG4gIH1cclxuXHJcbiAgLy8gUmV0dXJuIHRoZSBuZXcsIHN0cnVjdHVyZWQgb3B0aW9ucyBvYmplY3RcclxuICByZXR1cm4gbmV3T3B0aW9ucztcclxufVxyXG5cclxuLyoqXHJcbiAqIFZhbGlkYXRlcyBhIHNwZWNpZmllZCBvcHRpb24gdXNpbmcgdGhlIGNvcnJlc3BvbmRpbmcgdmFsaWRhdG9yIGZyb20gdGhlXHJcbiAqIGNvbmZpZ3VyYXRpb24gb2JqZWN0LiBSZXR1cm5zIHRoZSBvcmlnaW5hbCBvcHRpb24gaWYgdGhlIHZhbGlkYXRpb25cclxuICogaXMgZGlzYWJsZWQgZ2xvYmFsbHkuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiB2YWxpZGF0ZU9wdGlvblxyXG4gKlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gbmFtZSAtIFRoZSBuYW1lIG9mIHRoZSBvcHRpb24gdG8gdmFsaWRhdGUuXHJcbiAqIEBwYXJhbSB7YW55fSBjb25maWdPcHRpb24gLSBUaGUgdmFsdWUgb2YgdGhlIG9wdGlvbiB0byB2YWxpZGF0ZS5cclxuICogQHBhcmFtIHtib29sZWFufSBbc3RyaWN0Q2hlY2s9dHJ1ZV0gLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb25cclxuICogc2hvdWxkIGJlIGFwcGxpZWQuIFRoZSBkZWZhdWx0IHZhbHVlIGlzIGB0cnVlYC5cclxuICpcclxuICogQHJldHVybnMge2FueX0gVGhlIHBhcnNlZCBhbmQgdmFsaWRhdGVkIHZhbHVlIG9mIHRoZSBvcHRpb24uXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gdmFsaWRhdGVPcHRpb24obmFtZSwgY29uZmlnT3B0aW9uLCBzdHJpY3RDaGVjayA9IHRydWUpIHtcclxuICAvLyBSZXR1cm4gdGhlIG9yaWdpbmFsIG9wdGlvbiBpZiB0aGUgdmFsaWRhdGlvbiBpcyBkaXNhYmxlZFxyXG4gIGlmICghZ2V0T3B0aW9ucygpLm90aGVyLnZhbGlkYXRpb24pIHtcclxuICAgIHJldHVybiBjb25maWdPcHRpb247XHJcbiAgfVxyXG5cclxuICB0cnkge1xyXG4gICAgLy8gUmV0dXJuIHZhbGlkYXRlZCBvcHRpb25cclxuICAgIHJldHVybiB2YWxpZGF0b3JzW25hbWVdKHN0cmljdENoZWNrKS5wYXJzZShjb25maWdPcHRpb24pO1xyXG4gIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICAvLyBMb2cgWm9kIGlzc3Vlc1xyXG4gICAgbG9nWm9kSXNzdWVzKFxyXG4gICAgICAxLFxyXG4gICAgICBlcnJvci5pc3N1ZXMsXHJcbiAgICAgIGBbdmFsaWRhdGlvbl0gVGhlICR7bmFtZX0gb3B0aW9uIHZhbGlkYXRpb24gZXJyb3JgXHJcbiAgICApO1xyXG5cclxuICAgIC8vIFRocm93IHZhbGlkYXRpb24gZXJyb3JcclxuICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcihcclxuICAgICAgYFt2YWxpZGF0aW9uXSBUaGUgJHtuYW1lfSBvcHRpb24gdmFsaWRhdGlvbiBlcnJvcmAsXHJcbiAgICAgIDQwMFxyXG4gICAgKTtcclxuICB9XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBWYWxpZGF0ZXMgdGhlIHByb3ZpZGVkIGNvbmZpZ3VyYXRpb24gb3B0aW9ucyBmb3IgdGhlIGV4cG9ydGluZyBwcm9jZXNzLlxyXG4gKiBSZXR1cm5zIHRoZSBvcmlnaW5hbCBvcHRpb24gaWYgdGhlIHZhbGlkYXRpb24gaXMgZGlzYWJsZWQgZ2xvYmFsbHkuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiB2YWxpZGF0ZU9wdGlvbnNcclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IGNvbmZpZ09wdGlvbnMgLSBUaGUgY29uZmlndXJhdGlvbiBvcHRpb25zIHRvIGJlIHZhbGlkYXRlZC5cclxuICogQHBhcmFtIHtib29sZWFufSBbc3RyaWN0Q2hlY2s9dHJ1ZV0gLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb25cclxuICogc2hvdWxkIGJlIGFwcGxpZWQuIFRoZSBkZWZhdWx0IHZhbHVlIGlzIGB0cnVlYC5cclxuICpcclxuICogQHJldHVybnMge09iamVjdH0gVGhlIHBhcnNlZCBhbmQgdmFsaWRhdGVkIGNvbmZpZ3VyYXRpb24gb3B0aW9ucyBvYmplY3QuXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gdmFsaWRhdGVPcHRpb25zKGNvbmZpZ09wdGlvbnMsIHN0cmljdENoZWNrID0gdHJ1ZSkge1xyXG4gIC8vIFJldHVybiB0aGUgb3JpZ2luYWwgY29uZmlnIGlmIHRoZSB2YWxpZGF0aW9uIGlzIGRpc2FibGVkXHJcbiAgaWYgKCFnZXRPcHRpb25zKCkub3RoZXIudmFsaWRhdGlvbikge1xyXG4gICAgcmV0dXJuIGNvbmZpZ09wdGlvbnM7XHJcbiAgfVxyXG5cclxuICB0cnkge1xyXG4gICAgLy8gUmV0dXJuIHZhbGlkYXRlZCBvcHRpb25zXHJcbiAgICByZXR1cm4gc3RyaWN0Q2hlY2tcclxuICAgICAgPyBzdHJpY3RWYWxpZGF0ZShjb25maWdPcHRpb25zKVxyXG4gICAgICA6IGxvb3NlVmFsaWRhdGUoY29uZmlnT3B0aW9ucyk7XHJcbiAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgIC8vIExvZyBab2QgaXNzdWVzXHJcbiAgICBsb2dab2RJc3N1ZXMoMSwgZXJyb3IuaXNzdWVzLCAnW3ZhbGlkYXRpb25dIE9wdGlvbnMgdmFsaWRhdGlvbiBlcnJvcicpO1xyXG5cclxuICAgIC8vIFRocm93IHZhbGlkYXRpb24gZXJyb3JcclxuICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcignW3ZhbGlkYXRpb25dIE9wdGlvbnMgdmFsaWRhdGlvbiBlcnJvcicsIDQwMCk7XHJcbiAgfVxyXG59XHJcblxyXG4vKipcclxuICogVmFsaWRhdGVzLCBwYXJzZXMsIGFuZCBjaGVja3MgaWYgdGhlIHByb3ZpZGVkIGNvbmZpZyBpcyBhbGxvd2VkIHNldFxyXG4gKiBvZiBvcHRpb25zLlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gaXNBbGxvd2VkQ29uZmlnXHJcbiAqXHJcbiAqIEBwYXJhbSB7dW5rbm93bn0gY29uZmlnIC0gVGhlIGNvbmZpZyB0byBiZSB2YWxpZGF0ZWQgYW5kIHBhcnNlZCBhcyBhIHNldFxyXG4gKiBvZiBvcHRpb25zLiBNdXN0IGJlIGVpdGhlciBhbiBvYmplY3Qgb3IgYSBzdHJpbmcuXHJcbiAqIEBwYXJhbSB7Ym9vbGVhbn0gW3RvU3RyaW5nPWZhbHNlXSAtIFdoZXRoZXIgdG8gcmV0dXJuIGEgc3RyaW5naWZpZWQgdmVyc2lvblxyXG4gKiBvZiB0aGUgcGFyc2VkIGNvbmZpZy4gVGhlIGRlZmF1bHQgdmFsdWUgaXMgYGZhbHNlYC5cclxuICogQHBhcmFtIHtib29sZWFufSBbYWxsb3dGdW5jdGlvbnM9ZmFsc2VdIC0gV2hldGhlciB0byBhbGxvdyBmdW5jdGlvbnNcclxuICogaW4gdGhlIHBhcnNlZCBjb25maWcuIElmIHRydWUsIGZ1bmN0aW9ucyBhcmUgcHJlc2VydmVkLiBPdGhlcndpc2UsIHdoZW5cclxuICogYSBmdW5jdGlvbiBpcyBmb3VuZCwgbnVsbCBpcyByZXR1cm5lZC4gVGhlIGRlZmF1bHQgdmFsdWUgaXMgYGZhbHNlYC5cclxuICpcclxuICogQHJldHVybnMgeyhPYmplY3R8c3RyaW5nfG51bGwpfSBSZXR1cm5zIGEgcGFyc2VkIHNldCBvZiBvcHRpb25zIG9iamVjdCxcclxuICogYSBzdHJpbmdpZmllZCBzZXQgb2Ygb3B0aW9ucyBvYmplY3QgaWYgdGhlIGB0b1N0cmluZ2AgaXMgdHJ1ZSwgYW5kIG51bGxcclxuICogaWYgdGhlIGNvbmZpZyBpcyBub3QgYSB2YWxpZCBzZXQgb2Ygb3B0aW9ucyBvciBwYXJzaW5nIGZhaWxzLlxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIGlzQWxsb3dlZENvbmZpZyhcclxuICBjb25maWcsXHJcbiAgdG9TdHJpbmcgPSBmYWxzZSxcclxuICBhbGxvd0Z1bmN0aW9ucyA9IGZhbHNlXHJcbikge1xyXG4gIHRyeSB7XHJcbiAgICAvLyBBY2NlcHQgb25seSBvYmplY3RzIGFuZCBzdHJpbmdzXHJcbiAgICBpZiAoIWlzT2JqZWN0KGNvbmZpZykgJiYgdHlwZW9mIGNvbmZpZyAhPT0gJ3N0cmluZycpIHtcclxuICAgICAgLy8gUmV0dXJuIG51bGwgaWYgYW55IG90aGVyIHR5cGVcclxuICAgICAgcmV0dXJuIG51bGw7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gR2V0IHRoZSBvYmplY3QgcmVwcmVzZW50YXRpb24gb2YgdGhlIG9yaWdpbmFsIGNvbmZpZ1xyXG4gICAgY29uc3Qgb2JqZWN0Q29uZmlnID1cclxuICAgICAgdHlwZW9mIGNvbmZpZyA9PT0gJ3N0cmluZydcclxuICAgICAgICA/IGFsbG93RnVuY3Rpb25zXHJcbiAgICAgICAgICA/IGV2YWwoYCgke2NvbmZpZ30pYClcclxuICAgICAgICAgIDogSlNPTi5wYXJzZShjb25maWcpXHJcbiAgICAgICAgOiBjb25maWc7XHJcblxyXG4gICAgLy8gUHJlc2VydmUgb3IgcmVtb3ZlIHBvdGVudGlhbCBmdW5jdGlvbnMgYmFzZWQgb24gdGhlIGBhbGxvd0Z1bmN0aW9uc2AgZmxhZ1xyXG4gICAgY29uc3Qgc3RyaW5naWZpZWRPcHRpb25zID0gX29wdGlvbnNTdHJpbmdpZnkoXHJcbiAgICAgIG9iamVjdENvbmZpZyxcclxuICAgICAgYWxsb3dGdW5jdGlvbnMsXHJcbiAgICAgIGZhbHNlXHJcbiAgICApO1xyXG5cclxuICAgIC8vIFBhcnNlIHRoZSBjb25maWcgdG8gY2hlY2sgaWYgaXQgaXMgdmFsaWQgc2V0IG9mIG9wdGlvbnNcclxuICAgIGNvbnN0IHBhcnNlZE9wdGlvbnMgPSBhbGxvd0Z1bmN0aW9uc1xyXG4gICAgICA/IEpTT04ucGFyc2UoXHJcbiAgICAgICAgICBfb3B0aW9uc1N0cmluZ2lmeShvYmplY3RDb25maWcsIGFsbG93RnVuY3Rpb25zLCB0cnVlKSxcclxuICAgICAgICAgIChfLCB2YWx1ZSkgPT5cclxuICAgICAgICAgICAgdHlwZW9mIHZhbHVlID09PSAnc3RyaW5nJyAmJiB2YWx1ZS5zdGFydHNXaXRoKCdmdW5jdGlvbicpXHJcbiAgICAgICAgICAgICAgPyBldmFsKGAoJHt2YWx1ZX0pYClcclxuICAgICAgICAgICAgICA6IHZhbHVlXHJcbiAgICAgICAgKVxyXG4gICAgICA6IEpTT04ucGFyc2Uoc3RyaW5naWZpZWRPcHRpb25zKTtcclxuXHJcbiAgICAvLyBSZXR1cm4gc3RyaW5naWZpZWQgb3Igb2JqZWN0IG9wdGlvbnMgYmFzZWQgb24gdGhlIGB0b1N0cmluZ2AgZmxhZ1xyXG4gICAgcmV0dXJuIHRvU3RyaW5nID8gc3RyaW5naWZpZWRPcHRpb25zIDogcGFyc2VkT3B0aW9ucztcclxuICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgLy8gUmV0dXJuIG51bGwgaWYgcGFyc2luZyBmYWlsc1xyXG4gICAgcmV0dXJuIG51bGw7XHJcbiAgfVxyXG59XHJcblxyXG4vKipcclxuICogUHJpbnRzIHRoZSBIaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXIgbG9nbywgdmVyc2lvbiwgYW5kIGxpY2Vuc2UgaW5mb3JtYXRpb24uXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBwcmludExpY2Vuc2VcclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiBwcmludExpY2Vuc2UoKSB7XHJcbiAgLy8gUHJpbnQgdGhlIGxvZ28gYW5kIHZlcnNpb24gaW5mb3JtYXRpb25cclxuICBwcmludFZlcnNpb24oKTtcclxuXHJcbiAgLy8gUHJpbnQgdGhlIGxpY2Vuc2UgaW5mb3JtYXRpb25cclxuICBjb25zb2xlLmxvZyhcclxuICAgICdUaGlzIHNvZnR3YXJlIHJlcXVpcmVzIGEgdmFsaWQgSGlnaGNoYXJ0cyBsaWNlbnNlIGZvciBjb21tZXJjaWFsIHVzZS5cXG4nXHJcbiAgICAgIC55ZWxsb3csXHJcbiAgICAnXFxuRm9yIGEgZnVsbCBsaXN0IG9mIENMSSBvcHRpb25zLCB0eXBlOicsXHJcbiAgICAnXFxuaGlnaGNoYXJ0cy1leHBvcnQtc2VydmVyIC0taGVscFxcbicuZ3JlZW4sXHJcbiAgICAnXFxuSWYgeW91IGRvIG5vdCBoYXZlIGEgbGljZW5zZSwgb25lIGNhbiBiZSBvYnRhaW5lZCBoZXJlOicsXHJcbiAgICAnXFxuaHR0cHM6Ly9zaG9wLmhpZ2hzb2Z0LmNvbS9cXG4nLmdyZWVuLFxyXG4gICAgJ1xcblRvIGN1c3RvbWl6ZSB5b3VyIGluc3RhbGxhdGlvbiwgcGxlYXNlIHJlZmVyIHRvIHRoZSBSRUFETUUgZmlsZSBhdDonLFxyXG4gICAgJ1xcbmh0dHBzOi8vZ2l0aHViLmNvbS9oaWdoY2hhcnRzL25vZGUtZXhwb3J0LXNlcnZlciNyZWFkbWVcXG4nLmdyZWVuXHJcbiAgKTtcclxufVxyXG5cclxuLyoqXHJcbiAqIFByaW50cyB1c2FnZSBpbmZvcm1hdGlvbiBmb3IgQ0xJIGFyZ3VtZW50cywgZGlzcGxheWluZyBhdmFpbGFibGUgb3B0aW9uc1xyXG4gKiBhbmQgdGhlaXIgZGVzY3JpcHRpb25zLiBJdCBjYW4gbGlzdCBwcm9wZXJ0aWVzIHJlY3Vyc2l2ZWx5IGlmIGNhdGVnb3JpZXNcclxuICogY29udGFpbiBuZXN0ZWQgb3B0aW9ucy5cclxuICpcclxuICogQGZ1bmN0aW9uIHByaW50VXNhZ2VcclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiBwcmludFVzYWdlKCkge1xyXG4gIC8vIERpc3BsYXkgUkVBRE1FIGFuZCBnZW5lcmFsIHVzYWdlIGluZm9ybWF0aW9uXHJcbiAgY29uc29sZS5sb2coXHJcbiAgICAnXFxuVXNhZ2Ugb2YgQ0xJIGFyZ3VtZW50czonLmJvbGQsXHJcbiAgICAnXFxuLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0nLFxyXG4gICAgYFxcbkZvciBtb3JlIGRldGFpbGVkIGluZm9ybWF0aW9uLCB2aXNpdCB0aGUgUkVBRE1FIGZpbGUgYXQ6ICR7J2h0dHBzOi8vZ2l0aHViLmNvbS9oaWdoY2hhcnRzL25vZGUtZXhwb3J0LXNlcnZlciNyZWFkbWUnLmdyZWVufS5cXG5gXHJcbiAgKTtcclxuXHJcbiAgLy8gSXRlcmF0ZSB0aHJvdWdoIGVhY2ggY2F0ZWdvcnkgaW4gdGhlIGBkZWZhdWx0Q29uZmlnYCBhbmQgZGlzcGxheSB1c2FnZSBpbmZvXHJcbiAgT2JqZWN0LmtleXMoZGVmYXVsdENvbmZpZykuZm9yRWFjaCgoY2F0ZWdvcnkpID0+IHtcclxuICAgIGNvbnNvbGUubG9nKGAke2NhdGVnb3J5LnRvVXBwZXJDYXNlKCl9YC5ib2xkLnJlZCk7XHJcbiAgICBfY3ljbGVDYXRlZ29yaWVzKGRlZmF1bHRDb25maWdbY2F0ZWdvcnldKTtcclxuICAgIGNvbnNvbGUubG9nKCcnKTtcclxuICB9KTtcclxufVxyXG5cclxuLyoqXHJcbiAqIFByaW50cyB0aGUgSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyIGxvZ28gb3IgdGV4dCB3aXRoIHRoZSB2ZXJzaW9uXHJcbiAqIGluZm9ybWF0aW9uLlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gcHJpbnRWZXJzaW9uXHJcbiAqXHJcbiAqIEBwYXJhbSB7Ym9vbGVhbn0gW25vTG9nbz1mYWxzZV0gLSBJZiB0cnVlLCBvbmx5IHByaW50cyB0ZXh0IHdpdGggdGhlIHZlcnNpb25cclxuICogaW5mb3JtYXRpb24sIHdpdGhvdXQgdGhlIGxvZ28uIFRoZSBkZWZhdWx0IHZhbHVlIGlzIGBmYWxzZWAuXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gcHJpbnRWZXJzaW9uKG5vTG9nbyA9IGZhbHNlKSB7XHJcbiAgLy8gR2V0IHBhY2thZ2UgdmVyc2lvbiBlaXRoZXIgZnJvbSBgLmVudmAgb3IgZnJvbSBgcGFja2FnZS5qc29uYFxyXG4gIGNvbnN0IHBhY2thZ2VWZXJzaW9uID0gSlNPTi5wYXJzZShcclxuICAgIHJlYWRGaWxlU3luYyhqb2luKF9fZGlybmFtZSwgJ3BhY2thZ2UuanNvbicpLCAndXRmOCcpXHJcbiAgKS52ZXJzaW9uO1xyXG5cclxuICAvLyBQcmludCB0ZXh0IG9ubHlcclxuICBpZiAobm9Mb2dvKSB7XHJcbiAgICBjb25zb2xlLmxvZyhgSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyIHYke3BhY2thZ2VWZXJzaW9ufWApO1xyXG4gIH0gZWxzZSB7XHJcbiAgICAvLyBQcmludCB0aGUgbG9nb1xyXG4gICAgY29uc29sZS5sb2coXHJcbiAgICAgIHJlYWRGaWxlU3luYyhqb2luKF9fZGlybmFtZSwgJ21zZycsICdzdGFydHVwLm1zZycpLCAndXRmOCcpLnRvU3RyaW5nKClcclxuICAgICAgICAuYm9sZC55ZWxsb3csXHJcbiAgICAgIGB2JHtwYWNrYWdlVmVyc2lvbn1cXG5gLmJvbGRcclxuICAgICk7XHJcbiAgfVxyXG59XHJcblxyXG4vKipcclxuICogSW5pdGlhbGl6ZXMgYW5kIHJldHVybnMgZ2xvYmFsIG9wdGlvbnMgb2JqZWN0IGJhc2VkIG9uIHByb3ZpZGVkXHJcbiAqIGNvbmZpZ3VyYXRpb24sIHNldHRpbmcgdmFsdWVzIGZyb20gbmVzdGVkIHByb3BlcnRpZXMgcmVjdXJzaXZlbHkuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBfaW5pdEdsb2JhbE9wdGlvbnNcclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IGNvbmZpZyAtIFRoZSBjb25maWd1cmF0aW9uIG9iamVjdCB0byBiZSB1c2VkIGZvciBpbml0aWFsaXppbmdcclxuICogb3B0aW9ucy5cclxuICpcclxuICogQHJldHVybnMge09iamVjdH0gSW5pdGlhbGl6ZWQgb3B0aW9ucyBvYmplY3QuXHJcbiAqL1xyXG5mdW5jdGlvbiBfaW5pdEdsb2JhbE9wdGlvbnMoY29uZmlnKSB7XHJcbiAgY29uc3Qgb3B0aW9ucyA9IHt9O1xyXG5cclxuICAvLyBTdGFydCBpbml0aWFsaXppbmcgdGhlIGBvcHRpb25zYCBvYmplY3QgcmVjdXJzaXZlbHlcclxuICBmb3IgKGNvbnN0IFtuYW1lLCBpdGVtXSBvZiBPYmplY3QuZW50cmllcyhjb25maWcpKSB7XHJcbiAgICBpZiAoT2JqZWN0LnByb3RvdHlwZS5oYXNPd25Qcm9wZXJ0eS5jYWxsKGl0ZW0sICd2YWx1ZScpKSB7XHJcbiAgICAgIC8vIElmIGEgdmFsdWUgZnJvbSBlbnZpcm9ubWVudCB2YXJpYWJsZXMgZXhpc3RzLCBpdCB0YWtlcyBwcmVjZWRlbmNlXHJcbiAgICAgIGNvbnN0IGVudlZhbCA9IGVudnNbaXRlbS5lbnZMaW5rXTtcclxuICAgICAgaWYgKGVudlZhbCAhPT0gdW5kZWZpbmVkICYmIGVudlZhbCAhPT0gbnVsbCkge1xyXG4gICAgICAgIG9wdGlvbnNbbmFtZV0gPSBlbnZWYWw7XHJcbiAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgb3B0aW9uc1tuYW1lXSA9IGl0ZW0udmFsdWU7XHJcbiAgICAgIH1cclxuICAgIH0gZWxzZSB7XHJcbiAgICAgIG9wdGlvbnNbbmFtZV0gPSBfaW5pdEdsb2JhbE9wdGlvbnMoaXRlbSk7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICAvLyBSZXR1cm4gdGhlIGNyZWF0ZWQgYG9wdGlvbnNgIG9iamVjdFxyXG4gIHJldHVybiBvcHRpb25zO1xyXG59XHJcblxyXG4vKipcclxuICogVXBkYXRlcyBnbG9iYWwgb3B0aW9ucyBvYmplY3Qgd2l0aCB2YWx1ZXMgZnJvbSB2YXJpb3VzIHNvdXJjZXMsIGZvbGxvd2luZ1xyXG4gKiBhIHNwZWNpZmljIHByaW9yaXRpemF0aW9uIG9yZGVyLiBUaGUgZnVuY3Rpb24gY2hlY2tzIGZvciB2YWx1ZXMgaW4gdGhlIG9yZGVyXHJcbiAqIG9mIHByZWNlZGVuY2U6IHRoZSBgbG9hZENvbmZpZ2AgY29uZmlndXJhdGlvbiBvcHRpb25zLCBlbnZpcm9ubWVudCB2YXJpYWJsZXMsXHJcbiAqIGN1c3RvbSBvcHRpb25zLCBhbmQgQ0xJIG9wdGlvbnMuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBfdXBkYXRlR2xvYmFsT3B0aW9uc1xyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gY29uZmlnIC0gVGhlIGNvbmZpZ3VyYXRpb24gb2JqZWN0LCB3aGljaCBpbmNsdWRlcyB0aGUgaW5pdGlhbFxyXG4gKiBzZXR0aW5ncyBhbmQgbWV0YWRhdGEgZm9yIGVhY2ggb3B0aW9uLiBUaGlzIG9iamVjdCBpcyB1c2VkIHRvIGRldGVybWluZVxyXG4gKiB0aGUgc3RydWN0dXJlIGFuZCBkZWZhdWx0IHZhbHVlcyBmb3IgdGhlIG9wdGlvbnMuXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBvcHRpb25zIC0gVGhlIGdsb2JhbCBvcHRpb25zIG9iamVjdCB0aGF0IHdpbGwgYmUgdXBkYXRlZFxyXG4gKiB3aXRoIHZhbHVlcyBmcm9tIG90aGVyIHNvdXJjZXMuXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBjb25maWdPcHQgLSBUaGUgY29uZmlndXJhdGlvbiBvcHRpb25zIG9iamVjdCwgbG9hZGVkIHdpdGhcclxuICogdGhlIGBsb2FkQ29uZmlnYCBvcHRpb24sIHdoaWNoIG1heSBwcm92aWRlIHZhbHVlcyB0byBvdmVycmlkZSBkZWZhdWx0cy5cclxuICogQHBhcmFtIHtPYmplY3R9IGNsaU9wdCAtIFRoZSBDTEkgb3B0aW9ucyBvYmplY3QsIHdoaWNoIG1heSBpbmNsdWRlIHZhbHVlc1xyXG4gKiBwcm92aWRlZCB0aHJvdWdoIGNvbW1hbmQtbGluZSBhcmd1bWVudHMgYW5kIG1heSBvdmVycmlkZSBjb25maWd1cmF0aW9uXHJcbiAqIG9wdGlvbnMuXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBjdXN0b21PcHQgLSBUaGUgY3VzdG9tIG9wdGlvbnMgb2JqZWN0LCB0eXBpY2FsbHkgY29udGFpbmluZ1xyXG4gKiBhZGRpdGlvbmFsIGFuZCB1c2VyLWRlZmluZWQgdmFsdWVzLCB3aGljaCBoYXMgdGhlIGhpZ2hlc3QgcHJlY2VkZW5jZSBhbW9uZ1xyXG4gKiBvcHRpb25zLlxyXG4gKi9cclxuZnVuY3Rpb24gX3VwZGF0ZUdsb2JhbE9wdGlvbnMoY29uZmlnLCBvcHRpb25zLCBjb25maWdPcHQsIGNsaU9wdCwgY3VzdG9tT3B0KSB7XHJcbiAgT2JqZWN0LmtleXMoY29uZmlnKS5mb3JFYWNoKChrZXkpID0+IHtcclxuICAgIC8vIEdldCB0aGUgY29uZmlnIGVudHJ5IG9mIGEgc3BlY2lmaWMgb3B0aW9uXHJcbiAgICBjb25zdCBlbnRyeSA9IGNvbmZpZ1trZXldO1xyXG5cclxuICAgIC8vIEdhdGhlciB2YWx1ZXMgZm9yIHRoZSBvcHRpb25zIGZyb20gZXZlcnkgcG9zc2libGUgc291cmNlLCBpZiBleGlzdHNcclxuICAgIGNvbnN0IGNvbmZpZ1ZhbCA9IGNvbmZpZ09wdCAmJiBjb25maWdPcHRba2V5XTtcclxuICAgIGNvbnN0IGNsaVZhbCA9IGNsaU9wdCAmJiBjbGlPcHRba2V5XTtcclxuICAgIGNvbnN0IGN1c3RvbVZhbCA9IGN1c3RvbU9wdCAmJiBjdXN0b21PcHRba2V5XTtcclxuXHJcbiAgICAvLyBJZiB0aGUgdmFsdWUgbm90IGZvdW5kLCBuZWVkIHRvIGdvIGRlZXBlclxyXG4gICAgaWYgKHR5cGVvZiBlbnRyeS52YWx1ZSA9PT0gJ3VuZGVmaW5lZCcpIHtcclxuICAgICAgX3VwZGF0ZUdsb2JhbE9wdGlvbnMoZW50cnksIG9wdGlvbnNba2V5XSwgY29uZmlnVmFsLCBjbGlWYWwsIGN1c3RvbVZhbCk7XHJcbiAgICB9IGVsc2Uge1xyXG4gICAgICAvLyBJZiBhIHZhbHVlIGZyb20gY3VzdG9tIEpTT04gb3B0aW9ucyBleGlzdHMsIGl0IHRha2VzIHByZWNlZGVuY2VcclxuICAgICAgaWYgKGNvbmZpZ1ZhbCAhPT0gdW5kZWZpbmVkICYmIGNvbmZpZ1ZhbCAhPT0gbnVsbCkge1xyXG4gICAgICAgIG9wdGlvbnNba2V5XSA9IGNvbmZpZ1ZhbDtcclxuICAgICAgfVxyXG5cclxuICAgICAgLy8gSWYgYSB2YWx1ZSBmcm9tIGVudmlyb25tZW50IHZhcmlhYmxlcyBleGlzdHMsIGl0IHRha2VzIHByZWNlZGVuY2VcclxuICAgICAgY29uc3QgZW52VmFsID0gZW52c1tlbnRyeS5lbnZMaW5rXTtcclxuICAgICAgaWYgKGVudHJ5LmVudkxpbmsgaW4gZW52cyAmJiBlbnZWYWwgIT09IHVuZGVmaW5lZCAmJiBlbnZWYWwgIT09IG51bGwpIHtcclxuICAgICAgICBvcHRpb25zW2tleV0gPSBlbnZWYWw7XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIC8vIElmIGEgdmFsdWUgZnJvbSBDTEkgb3B0aW9ucyBleGlzdHMsIGl0IHRha2VzIHByZWNlZGVuY2VcclxuICAgICAgaWYgKGNsaVZhbCAhPT0gdW5kZWZpbmVkICYmIGNsaVZhbCAhPT0gbnVsbCkge1xyXG4gICAgICAgIG9wdGlvbnNba2V5XSA9IGNsaVZhbDtcclxuICAgICAgfVxyXG5cclxuICAgICAgLy8gSWYgYSB2YWx1ZSBmcm9tIHVzZXIgb3B0aW9ucyBleGlzdHMsIGl0IHRha2VzIHByZWNlZGVuY2VcclxuICAgICAgaWYgKGN1c3RvbVZhbCAhPT0gdW5kZWZpbmVkICYmIGN1c3RvbVZhbCAhPT0gbnVsbCkge1xyXG4gICAgICAgIG9wdGlvbnNba2V5XSA9IGN1c3RvbVZhbDtcclxuICAgICAgfVxyXG4gICAgfVxyXG4gIH0pO1xyXG59XHJcblxyXG4vKipcclxuICogQ29udmVydHMgdGhlIHByb3ZpZGVkIG9wdGlvbnMgb2JqZWN0IHRvIGEgSlNPTi1mb3JtYXR0ZWQgc3RyaW5nXHJcbiAqIHdpdGggdGhlIG9wdGlvbiB0byBwcmVzZXJ2ZSBmdW5jdGlvbnMuIEluIG9yZGVyIGZvciBhIGZ1bmN0aW9uXHJcbiAqIHRvIGJlIHByZXNlcnZlZCwgaXQgbmVlZHMgdG8gZm9sbG93IHRoZSBmb3JtYXQgYGZ1bmN0aW9uICguLi4pIHsuLi59YC5cclxuICogU3VjaCBhIGZ1bmN0aW9uIGNhbiBhbHNvIGJlIHN0cmluZ2lmaWVkLlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gX29wdGlvbnNTdHJpbmdpZnlcclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IG9wdGlvbnMgLSBUaGUgb3B0aW9ucyBvYmplY3QgdG8gYmUgY29udmVydGVkIHRvIGEgc3RyaW5nLlxyXG4gKiBAcGFyYW0ge2Jvb2xlYW59IGFsbG93RnVuY3Rpb25zIC0gSWYgc2V0IHRvIHRydWUsIGZ1bmN0aW9ucyBhcmUgcHJlc2VydmVkXHJcbiAqIGluIHRoZSBvdXRwdXQuIE90aGVyd2lzZSBhbiBlcnJvciBpcyB0aHJvd24uXHJcbiAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaW5naWZ5RnVuY3Rpb25zIC0gSWYgc2V0IHRvIHRydWUsIGZ1bmN0aW9ucyBhcmUgc2F2ZWRcclxuICogYXMgc3RyaW5ncy4gVGhlIGBhbGxvd0Z1bmN0aW9uc2AgbXVzdCBiZSBzZXQgdG8gdHJ1ZSBhcyB3ZWxsIGZvciB0aGlzIHRvIHRha2VcclxuICogYW4gZWZmZWN0LlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7c3RyaW5nfSBUaGUgSlNPTi1mb3JtYXR0ZWQgc3RyaW5nIHJlcHJlc2VudGluZyB0aGUgb3B0aW9ucy5cclxuICpcclxuICogQHRocm93cyB7RXJyb3J9IFRocm93cyBhbiBgRXJyb3JgIHdoZW4gZnVuY3Rpb25zIGFyZSBub3QgYWxsb3dlZCBidXQgYXJlXHJcbiAqIGZvdW5kIGluIHByb3ZpZGVkIG9wdGlvbnMgb2JqZWN0LlxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIF9vcHRpb25zU3RyaW5naWZ5KG9wdGlvbnMsIGFsbG93RnVuY3Rpb25zLCBzdHJpbmdpZnlGdW5jdGlvbnMpIHtcclxuICBjb25zdCByZXBsYWNlckNhbGxiYWNrID0gKF8sIHZhbHVlKSA9PiB7XHJcbiAgICAvLyBUcmltIHN0cmluZyB2YWx1ZXNcclxuICAgIGlmICh0eXBlb2YgdmFsdWUgPT09ICdzdHJpbmcnKSB7XHJcbiAgICAgIHZhbHVlID0gdmFsdWUudHJpbSgpO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIElmIHZhbHVlIGlzIGEgZnVuY3Rpb24gb3Igc3RyaW5naWZpZWQgZnVuY3Rpb25cclxuICAgIGlmIChcclxuICAgICAgdHlwZW9mIHZhbHVlID09PSAnZnVuY3Rpb24nIHx8XHJcbiAgICAgICh0eXBlb2YgdmFsdWUgPT09ICdzdHJpbmcnICYmXHJcbiAgICAgICAgdmFsdWUuc3RhcnRzV2l0aCgnZnVuY3Rpb24nKSAmJlxyXG4gICAgICAgIHZhbHVlLmVuZHNXaXRoKCd9JykpXHJcbiAgICApIHtcclxuICAgICAgLy8gSWYgYWxsb3dGdW5jdGlvbnMgaXMgc2V0IHRvIHRydWUsIHByZXNlcnZlIGZ1bmN0aW9uc1xyXG4gICAgICBpZiAoYWxsb3dGdW5jdGlvbnMpIHtcclxuICAgICAgICAvLyBCYXNlZCBvbiB0aGUgYHN0cmluZ2lmeUZ1bmN0aW9uc2Agb3B0aW9ucywgc2V0IGZ1bmN0aW9uIHZhbHVlc1xyXG4gICAgICAgIHJldHVybiBzdHJpbmdpZnlGdW5jdGlvbnNcclxuICAgICAgICAgID8gLy8gQXMgc3RyaW5naWZpZWQgZnVuY3Rpb25zXHJcbiAgICAgICAgICAgIGBcIkVYUF9GVU4keyh2YWx1ZSArICcnKS5yZXBsYWNlQWxsKC9cXHMrL2csICcgJyl9RVhQX0ZVTlwiYFxyXG4gICAgICAgICAgOiAvLyBBcyBmdW5jdGlvbnNcclxuICAgICAgICAgICAgYEVYUF9GVU4keyh2YWx1ZSArICcnKS5yZXBsYWNlQWxsKC9cXHMrL2csICcgJyl9RVhQX0ZVTmA7XHJcbiAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgLy8gVGhyb3cgYW4gZXJyb3Igb3RoZXJ3aXNlXHJcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKCk7XHJcbiAgICAgIH1cclxuICAgIH1cclxuXHJcbiAgICAvLyBJbiBhbGwgb3RoZXIgY2FzZXMsIHNpbXBseSByZXR1cm4gdGhlIHZhbHVlXHJcbiAgICByZXR1cm4gdmFsdWU7XHJcbiAgfTtcclxuXHJcbiAgLy8gU3RyaW5naWZ5IG9wdGlvbnMgYW5kIGlmIHJlcXVpcmVkLCByZXBsYWNlIHNwZWNpYWwgZnVuY3Rpb25zIG1hcmtzXHJcbiAgcmV0dXJuIEpTT04uc3RyaW5naWZ5KG9wdGlvbnMsIHJlcGxhY2VyQ2FsbGJhY2spLnJlcGxhY2VBbGwoXHJcbiAgICBzdHJpbmdpZnlGdW5jdGlvbnMgPyAvXFxcXFwiRVhQX0ZVTnxFWFBfRlVOXFxcXFwiL2cgOiAvXCJFWFBfRlVOfEVYUF9GVU5cIi9nLFxyXG4gICAgJydcclxuICApO1xyXG59XHJcblxyXG4vKipcclxuICogTG9hZHMgYWRkaXRpb25hbCBjb25maWd1cmF0aW9uIGZyb20gYSBzcGVjaWZpZWQgZmlsZSBwcm92aWRlZCB2aWFcclxuICogdGhlIGBsb2FkQ29uZmlnYCBvcHRpb24gaW4gdGhlIGNvbW1hbmQtbGluZSBhcmd1bWVudHMuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBfbG9hZENvbmZpZ0ZpbGVcclxuICpcclxuICogQHBhcmFtIHtBcnJheS48c3RyaW5nPn0gY2xpQXJncyAtIENvbW1hbmQtbGluZSBhcmd1bWVudHMgdG8gc2VhcmNoXHJcbiAqIGZvciB0aGUgYGxvYWRDb25maWdgIG9wdGlvbiBhbmQgdGhlIGNvcnJlc3BvbmRpbmcgZmlsZSBwYXRoLlxyXG4gKiBAcGFyYW0ge09iamVjdH0gY3VzdG9tTG9naWNPcHRpb25zIC0gVGhlIGNvbmZpZ3VyYXRpb24gb2JqZWN0IGNvbnRhaW5pbmdcclxuICogYGN1c3RvbUxvZ2ljYCBvcHRpb25zLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7T2JqZWN0fSBUaGUgYWRkaXRpb25hbCBjb25maWd1cmF0aW9uIGxvYWRlZCBmcm9tIHRoZSBzcGVjaWZpZWRcclxuICogZmlsZSwgb3IgYW4gZW1wdHkgb2JqZWN0IGlmIHRoZSBmaWxlIGlzIG5vdCBmb3VuZCwgaW52YWxpZCwgb3IgYW4gZXJyb3JcclxuICogb2NjdXJzLlxyXG4gKi9cclxuZnVuY3Rpb24gX2xvYWRDb25maWdGaWxlKGNsaUFyZ3MsIGN1c3RvbUxvZ2ljT3B0aW9ucykge1xyXG4gIC8vIENoZWNrIGlmIHRoZSBgbG9hZENvbmZpZ2Agb3B0aW9uIHdhcyB1c2VkXHJcbiAgY29uc3QgY29uZmlnSW5kZXggPSBjbGlBcmdzLmZpbmRJbmRleChcclxuICAgIChhcmcpID0+IGFyZy5yZXBsYWNlKC8tL2csICcnKSA9PT0gJ2xvYWRDb25maWcnXHJcbiAgKTtcclxuXHJcbiAgLy8gR2V0IHRoZSBgbG9hZENvbmZpZ2Agb3B0aW9uIHZhbHVlXHJcbiAgY29uc3QgY29uZmlnRmlsZU5hbWUgPSBjb25maWdJbmRleCA+IC0xICYmIGNsaUFyZ3NbY29uZmlnSW5kZXggKyAxXTtcclxuXHJcbiAgLy8gQ2hlY2sgaWYgdGhlIGBsb2FkQ29uZmlnYCBpcyBwcmVzZW50IGFuZCBoYXMgYSBjb3JyZWN0IHZhbHVlXHJcbiAgaWYgKGNvbmZpZ0ZpbGVOYW1lICYmIGN1c3RvbUxvZ2ljT3B0aW9ucy5hbGxvd0ZpbGVSZXNvdXJjZXMpIHtcclxuICAgIHRyeSB7XHJcbiAgICAgIC8vIExvYWQgYW4gb3B0aW9uYWwgY3VzdG9tIEpTT04gY29uZmlnIGZpbGVcclxuICAgICAgcmV0dXJuIGlzQWxsb3dlZENvbmZpZyhcclxuICAgICAgICByZWFkRmlsZVN5bmMoZ2V0QWJzb2x1dGVQYXRoKGNvbmZpZ0ZpbGVOYW1lKSwgJ3V0ZjgnKSxcclxuICAgICAgICBmYWxzZSxcclxuICAgICAgICBjdXN0b21Mb2dpY09wdGlvbnMuYWxsb3dDb2RlRXhlY3V0aW9uXHJcbiAgICAgICk7XHJcbiAgICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgICBsb2dXaXRoU3RhY2soXHJcbiAgICAgICAgMixcclxuICAgICAgICBlcnJvcixcclxuICAgICAgICBgW2NvbmZpZ10gVW5hYmxlIHRvIGxvYWQgdGhlIGNvbmZpZ3VyYXRpb24gZnJvbSB0aGUgJHtjb25maWdGaWxlTmFtZX0gZmlsZS5gXHJcbiAgICAgICk7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICAvLyBObyBhZGRpdGlvbmFsIG9wdGlvbnMgdG8gcmV0dXJuXHJcbiAgcmV0dXJuIHt9O1xyXG59XHJcblxyXG4vKipcclxuICogUGFyc2VzIGNvbW1hbmQtbGluZSBhcmd1bWVudHMgYW5kIHBhaXJzIGVhY2ggYXJndW1lbnQgd2l0aCBpdHMgY29ycmVzcG9uZGluZ1xyXG4gKiBvcHRpb24gaW4gdGhlIGNvbmZpZ3VyYXRpb24uIFRoZSB2YWx1ZXMgYXJlIHN0cnVjdHVyZWQgaW50byBhIG5lc3RlZCBvcHRpb25zXHJcbiAqIG9iamVjdCwgYmFzZWQgb24gcHJlZGVmaW5lZCBtYXBwaW5ncy5cclxuICpcclxuICogQGZ1bmN0aW9uIF9wYWlyQXJndW1lbnRWYWx1ZVxyXG4gKlxyXG4gKiBAcGFyYW0ge0FycmF5LjxzdHJpbmc+fSBuZXN0ZWRQcm9wcyAtIEFuIGFycmF5IG9mIG5lc3RpbmcgbGV2ZWwgZm9yIGFsbFxyXG4gKiBvcHRpb25zLlxyXG4gKiBAcGFyYW0ge0FycmF5LjxzdHJpbmc+fSBjbGlBcmdzIC0gQW4gYXJyYXkgb2YgY29tbWFuZC1saW5lIGFyZ3VtZW50c1xyXG4gKiBjb250YWluaW5nIG9wdGlvbnMgYW5kIHRoZWlyIGFzc29jaWF0ZWQgdmFsdWVzLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7T2JqZWN0fSBBbiB1cGRhdGVkIG9wdGlvbnMgb2JqZWN0IHdoZXJlIGVhY2ggb3B0aW9uIGZyb21cclxuICogdGhlIGNvbW1hbmQtbGluZSBpcyBwYWlyZWQgd2l0aCBpdHMgdmFsdWUsIHN0cnVjdHVyZWQgaW50byBuZXN0ZWQgb2JqZWN0c1xyXG4gKiBhcyBkZWZpbmVkLlxyXG4gKi9cclxuZnVuY3Rpb24gX3BhaXJBcmd1bWVudFZhbHVlKG5lc3RlZFByb3BzLCBjbGlBcmdzKSB7XHJcbiAgLy8gQW4gZW1wdHkgb2JqZWN0IHRvIGNvbGxlY3QgYW5kIHN0cnVjdHVyaXplIGRhdGEgZnJvbSB0aGUgYXJnc1xyXG4gIGNvbnN0IGNsaU9wdGlvbnMgPSB7fTtcclxuXHJcbiAgLy8gQ3ljbGUgdGhyb3VnaCBhbGwgQ0xJIGFyZ3MgYW5kIGZpbHRlciB0aGVtXHJcbiAgZm9yIChsZXQgaSA9IDA7IGkgPCBjbGlBcmdzLmxlbmd0aDsgaSsrKSB7XHJcbiAgICBjb25zdCBvcHRpb24gPSBjbGlBcmdzW2ldLnJlcGxhY2UoLy0vZywgJycpO1xyXG5cclxuICAgIC8vIEZpbmQgdGhlIHJpZ2h0IHBsYWNlIGZvciBwcm9wZXJ0eSdzIHZhbHVlXHJcbiAgICBjb25zdCBwcm9wZXJ0aWVzQ2hhaW4gPSBuZXN0ZWRQcm9wc1tvcHRpb25dXHJcbiAgICAgID8gbmVzdGVkUHJvcHNbb3B0aW9uXS5zcGxpdCgnLicpXHJcbiAgICAgIDogW107XHJcblxyXG4gICAgLy8gQ3JlYXRlIG9wdGlvbnMgb2JqZWN0IHdpdGggdmFsdWVzIGZyb20gQ0xJIGZvciBsYXRlciBwYXJzaW5nIGFuZCBtZXJnaW5nXHJcbiAgICBwcm9wZXJ0aWVzQ2hhaW4ucmVkdWNlKChvYmosIHByb3AsIGluZGV4KSA9PiB7XHJcbiAgICAgIGlmIChwcm9wZXJ0aWVzQ2hhaW4ubGVuZ3RoIC0gMSA9PT0gaW5kZXgpIHtcclxuICAgICAgICBjb25zdCB2YWx1ZSA9IGNsaUFyZ3NbKytpXTtcclxuICAgICAgICBpZiAoIXZhbHVlKSB7XHJcbiAgICAgICAgICBsb2coXHJcbiAgICAgICAgICAgIDIsXHJcbiAgICAgICAgICAgIGBbY29uZmlnXSBNaXNzaW5nIHZhbHVlIGZvciB0aGUgQ0xJICctLSR7b3B0aW9ufScgYXJndW1lbnQuIFVzaW5nIHRoZSBkZWZhdWx0IHZhbHVlLmBcclxuICAgICAgICAgICk7XHJcbiAgICAgICAgfVxyXG4gICAgICAgIG9ialtwcm9wXSA9IHZhbHVlIHx8IG51bGw7XHJcbiAgICAgIH0gZWxzZSBpZiAob2JqW3Byb3BdID09PSB1bmRlZmluZWQpIHtcclxuICAgICAgICBvYmpbcHJvcF0gPSB7fTtcclxuICAgICAgfVxyXG4gICAgICByZXR1cm4gb2JqW3Byb3BdO1xyXG4gICAgfSwgY2xpT3B0aW9ucyk7XHJcbiAgfVxyXG5cclxuICAvLyBSZXR1cm4gcGFyc2VkIENMSSBvcHRpb25zXHJcbiAgcmV0dXJuIGNsaU9wdGlvbnM7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBSZWN1cnNpdmVseSB0cmF2ZXJzZXMgdGhlIG9wdGlvbnMgb2JqZWN0IHRvIHByaW50IHRoZSB1c2FnZSBpbmZvcm1hdGlvblxyXG4gKiBmb3IgZWFjaCBvcHRpb24gY2F0ZWdvcnkgYW5kIGluZGl2aWR1YWwgb3B0aW9uLlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gX2N5Y2xlQ2F0ZWdvcmllc1xyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gb3B0aW9ucyAtIFRoZSBvcHRpb25zIG9iamVjdCBjb250YWluaW5nIENMSSBvcHRpb25zLiBJdCBtYXlcclxuICogaW5jbHVkZSBuZXN0ZWQgY2F0ZWdvcmllcyBhbmQgaW5kaXZpZHVhbCBvcHRpb25zLlxyXG4gKi9cclxuZnVuY3Rpb24gX2N5Y2xlQ2F0ZWdvcmllcyhvcHRpb25zKSB7XHJcbiAgZm9yIChjb25zdCBbbmFtZSwgb3B0aW9uXSBvZiBPYmplY3QuZW50cmllcyhvcHRpb25zKSkge1xyXG4gICAgLy8gSWYgdGhlIGN1cnJlbnQgZW50cnkgaXMgYSBjYXRlZ29yeSBhbmQgbm90IGEgbGVhZiBvcHRpb24sIHJlY3Vyc2UgaW50byBpdFxyXG4gICAgaWYgKCFPYmplY3QucHJvdG90eXBlLmhhc093blByb3BlcnR5LmNhbGwob3B0aW9uLCAndmFsdWUnKSkge1xyXG4gICAgICBfY3ljbGVDYXRlZ29yaWVzKG9wdGlvbik7XHJcbiAgICB9IGVsc2Uge1xyXG4gICAgICAvLyBQcmVwYXJlIGRlc2NyaXB0aW9uXHJcbiAgICAgIGNvbnN0IGRlc2NOYW1lID0gYCAtLSR7b3B0aW9uLmNsaU5hbWUgfHwgbmFtZX1gO1xyXG5cclxuICAgICAgLy8gR2V0IHRoZSB2YWx1ZVxyXG4gICAgICBsZXQgb3B0aW9uVmFsdWUgPSBvcHRpb24udmFsdWU7XHJcblxyXG4gICAgICAvLyBQcmVwYXJlIHZhbHVlIGZvciBvcHRpb24gdGhhdCBpcyBub3QgbnVsbCBhbmQgaXMgYXJyYXkgb2Ygc3RyaW5nc1xyXG4gICAgICBpZiAob3B0aW9uVmFsdWUgIT09IG51bGwgJiYgb3B0aW9uLnR5cGVzLmluY2x1ZGVzKCdzdHJpbmdbXScpKSB7XHJcbiAgICAgICAgb3B0aW9uVmFsdWUgPVxyXG4gICAgICAgICAgJ1snICsgb3B0aW9uVmFsdWUubWFwKChpdGVtKSA9PiBgJyR7aXRlbX0nYCkuam9pbignLCAnKSArICddJztcclxuICAgICAgfVxyXG5cclxuICAgICAgLy8gUHJlcGFyZSB2YWx1ZSBmb3Igb3B0aW9uIHRoYXQgaXMgbm90IG51bGwgYW5kIGlzIGEgc3RyaW5nXHJcbiAgICAgIGlmIChvcHRpb25WYWx1ZSAhPT0gbnVsbCAmJiBvcHRpb24udHlwZXMuaW5jbHVkZXMoJ3N0cmluZycpKSB7XHJcbiAgICAgICAgb3B0aW9uVmFsdWUgPSBgJyR7b3B0aW9uVmFsdWV9J2A7XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIC8vIERpc3BsYXkgY29ycmVjdGx5IGFsaWduZWQgbWVzc2FnZXNcclxuICAgICAgY29uc29sZS5sb2coXHJcbiAgICAgICAgZGVzY05hbWUuZ3JlZW4sXHJcbiAgICAgICAgYCR7KCc8JyArIG9wdGlvbi50eXBlcy5qb2luKCd8JykgKyAnPicpLnllbGxvd31gLFxyXG4gICAgICAgIGAke1N0cmluZyhvcHRpb25WYWx1ZSkuYm9sZH1gLmJsdWUsXHJcbiAgICAgICAgYC0gJHtvcHRpb24uZGVzY3JpcHRpb259LmBcclxuICAgICAgKTtcclxuICAgIH1cclxuICB9XHJcbn1cclxuXHJcbmV4cG9ydCBkZWZhdWx0IHtcclxuICBnZXRPcHRpb25zLFxyXG4gIHNldEdsb2JhbE9wdGlvbnMsXHJcbiAgdXBkYXRlT3B0aW9ucyxcclxuICBtZXJnZU9wdGlvbnMsXHJcbiAgbWFwVG9OZXdPcHRpb25zLFxyXG4gIHZhbGlkYXRlT3B0aW9uLFxyXG4gIHZhbGlkYXRlT3B0aW9ucyxcclxuICBpc0FsbG93ZWRDb25maWcsXHJcbiAgcHJpbnRMaWNlbnNlLFxyXG4gIHByaW50VXNhZ2UsXHJcbiAgcHJpbnRWZXJzaW9uXHJcbn07XHJcbiIsIi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXHJcblxyXG5IaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXJcclxuXHJcbkNvcHlyaWdodCAoYykgMjAxNi0yMDI1LCBIaWdoc29mdFxyXG5cclxuTGljZW5jZWQgdW5kZXIgdGhlIE1JVCBsaWNlbmNlLlxyXG5cclxuQWRkaXRpb25hbGx5IGEgdmFsaWQgSGlnaGNoYXJ0cyBsaWNlbnNlIGlzIHJlcXVpcmVkIGZvciB1c2UuXHJcblxyXG5TZWUgTElDRU5TRSBmaWxlIGluIHJvb3QgZm9yIGRldGFpbHMuXHJcblxyXG4qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xyXG5cclxuLyoqXHJcbiAqIEBvdmVydmlldyBIVFRQIHV0aWxpdHkgbW9kdWxlIGZvciBmZXRjaGluZyBhbmQgcG9zdGluZyBkYXRhLiBTdXBwb3J0cyBib3RoXHJcbiAqIEhUVFAgYW5kIEhUVFBTIHByb3RvY29scywgcHJvdmlkaW5nIG1ldGhvZHMgdG8gbWFrZSBHRVQgYW5kIFBPU1QgcmVxdWVzdHNcclxuICogd2l0aCBjdXN0b21pemFibGUgb3B0aW9ucy4gSW5jbHVkZXMgcHJvdG9jb2wgZGV0ZXJtaW5hdGlvbiBiYXNlZCBvbiBVUkxcclxuICogYW5kIGF1Z21lbnRzIHJlc3BvbnNlIG9iamVjdHMgd2l0aCBhICd0ZXh0JyBwcm9wZXJ0eSBmb3IgZWFzaWVyIGRhdGEgYWNjZXNzLlxyXG4gKi9cclxuXHJcbmltcG9ydCBodHRwIGZyb20gJ2h0dHAnO1xyXG5pbXBvcnQgaHR0cHMgZnJvbSAnaHR0cHMnO1xyXG5cclxuLyoqXHJcbiAqIEZldGNoZXMgZGF0YSBmcm9tIHRoZSBzcGVjaWZpZWQgVVJMIHVzaW5nIGVpdGhlciBIVFRQIG9yIEhUVFBTIHByb3RvY29sLlxyXG4gKlxyXG4gKiBAYXN5bmNcclxuICogQGZ1bmN0aW9uIGZldGNoXHJcbiAqXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSB1cmwgLSBUaGUgVVJMIHRvIGZldGNoIGRhdGEgZnJvbS5cclxuICogQHBhcmFtIHtPYmplY3R9IFtyZXF1ZXN0T3B0aW9ucz17fV0gLSBPcHRpb25zIGZvciB0aGUgSFRUUC9IVFRQUyByZXF1ZXN0LlxyXG4gKiBUaGUgZGVmYXVsdCB2YWx1ZSBpcyBhbiBlbXB0eSBvYmplY3QuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtQcm9taXNlPE9iamVjdD59IEEgUHJvbWlzZSB0aGF0IHJlc29sdmVzIHRvIHRoZSBIVFRQL0hUVFBTIHJlc3BvbnNlXHJcbiAqIG9iamVjdCB3aXRoIGFkZGVkICd0ZXh0JyBwcm9wZXJ0eSBvciByZWplY3Rpbmcgd2l0aCBhbiBlcnJvci5cclxuICovXHJcbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBmZXRjaCh1cmwsIHJlcXVlc3RPcHRpb25zID0ge30pIHtcclxuICByZXR1cm4gbmV3IFByb21pc2UoKHJlc29sdmUsIHJlamVjdCkgPT4ge1xyXG4gICAgX2dldFByb3RvY29sTW9kdWxlKHVybClcclxuICAgICAgLmdldCh1cmwsIHJlcXVlc3RPcHRpb25zLCAocmVzcG9uc2UpID0+IHtcclxuICAgICAgICBsZXQgcmVzcG9uc2VEYXRhID0gJyc7XHJcblxyXG4gICAgICAgIC8vIEEgY2h1bmsgb2YgZGF0YSBoYXMgYmVlbiByZWNlaXZlZFxyXG4gICAgICAgIHJlc3BvbnNlLm9uKCdkYXRhJywgKGNodW5rKSA9PiB7XHJcbiAgICAgICAgICByZXNwb25zZURhdGEgKz0gY2h1bms7XHJcbiAgICAgICAgfSk7XHJcblxyXG4gICAgICAgIC8vIFRoZSB3aG9sZSByZXNwb25zZSBoYXMgYmVlbiByZWNlaXZlZFxyXG4gICAgICAgIHJlc3BvbnNlLm9uKCdlbmQnLCAoKSA9PiB7XHJcbiAgICAgICAgICBpZiAoIXJlc3BvbnNlRGF0YSkge1xyXG4gICAgICAgICAgICByZWplY3QoJ05vdGhpbmcgd2FzIGZldGNoZWQgZnJvbSB0aGUgVVJMLicpO1xyXG4gICAgICAgICAgfVxyXG4gICAgICAgICAgcmVzcG9uc2UudGV4dCA9IHJlc3BvbnNlRGF0YTtcclxuICAgICAgICAgIHJlc29sdmUocmVzcG9uc2UpO1xyXG4gICAgICAgIH0pO1xyXG4gICAgICB9KVxyXG4gICAgICAub24oJ2Vycm9yJywgKGVycm9yKSA9PiB7XHJcbiAgICAgICAgcmVqZWN0KGVycm9yKTtcclxuICAgICAgfSk7XHJcbiAgfSk7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBTZW5kcyBhIFBPU1QgcmVxdWVzdCB0byB0aGUgc3BlY2lmaWVkIFVSTCB3aXRoIHRoZSBwcm92aWRlZCBKU09OIGJvZHkgdXNpbmdcclxuICogZWl0aGVyIEhUVFAgb3IgSFRUUFMgcHJvdG9jb2wuXHJcbiAqXHJcbiAqIEBhc3luY1xyXG4gKiBAZnVuY3Rpb24gcG9zdFxyXG4gKlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gdXJsIC0gVGhlIFVSTCB0byBzZW5kIHRoZSBQT1NUIHJlcXVlc3QgdG8uXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBbYm9keT17fV0gLSBUaGUgSlNPTiBib2R5IHRvIGluY2x1ZGUgaW4gdGhlIFBPU1QgcmVxdWVzdC5cclxuICogVGhlIGRlZmF1bHQgdmFsdWUgaXMgYW4gZW1wdHkgb2JqZWN0LlxyXG4gKiBAcGFyYW0ge09iamVjdH0gW3JlcXVlc3RPcHRpb25zPXt9XSAtIE9wdGlvbnMgZm9yIHRoZSBIVFRQL0hUVFBTIHJlcXVlc3QuXHJcbiAqIFRoZSBkZWZhdWx0IHZhbHVlIGlzIGFuIGVtcHR5IG9iamVjdC5cclxuICpcclxuICogQHJldHVybnMge1Byb21pc2U8T2JqZWN0Pn0gQSBQcm9taXNlIHRoYXQgcmVzb2x2ZXMgdG8gdGhlIEhUVFAvSFRUUFMgcmVzcG9uc2VcclxuICogb2JqZWN0IHdpdGggYWRkZWQgJ3RleHQnIHByb3BlcnR5IG9yIHJlamVjdGluZyB3aXRoIGFuIGVycm9yLlxyXG4gKi9cclxuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIHBvc3QodXJsLCBib2R5ID0ge30sIHJlcXVlc3RPcHRpb25zID0ge30pIHtcclxuICByZXR1cm4gbmV3IFByb21pc2UoKHJlc29sdmUsIHJlamVjdCkgPT4ge1xyXG4gICAgY29uc3QgZGF0YSA9IEpTT04uc3RyaW5naWZ5KGJvZHkpO1xyXG5cclxuICAgIC8vIFNldCBkZWZhdWx0IGhlYWRlcnMgYW5kIG1lcmdlIHdpdGggcmVxdWVzdE9wdGlvbnNcclxuICAgIGNvbnN0IG9wdGlvbnMgPSBPYmplY3QuYXNzaWduKFxyXG4gICAgICB7XHJcbiAgICAgICAgbWV0aG9kOiAnUE9TVCcsXHJcbiAgICAgICAgaGVhZGVyczoge1xyXG4gICAgICAgICAgJ0NvbnRlbnQtVHlwZSc6ICdhcHBsaWNhdGlvbi9qc29uJyxcclxuICAgICAgICAgICdDb250ZW50LUxlbmd0aCc6IGRhdGEubGVuZ3RoXHJcbiAgICAgICAgfVxyXG4gICAgICB9LFxyXG4gICAgICByZXF1ZXN0T3B0aW9uc1xyXG4gICAgKTtcclxuXHJcbiAgICBjb25zdCByZXF1ZXN0ID0gX2dldFByb3RvY29sTW9kdWxlKHVybClcclxuICAgICAgLnJlcXVlc3QodXJsLCBvcHRpb25zLCAocmVzcG9uc2UpID0+IHtcclxuICAgICAgICBsZXQgcmVzcG9uc2VEYXRhID0gJyc7XHJcblxyXG4gICAgICAgIC8vIEEgY2h1bmsgb2YgZGF0YSBoYXMgYmVlbiByZWNlaXZlZFxyXG4gICAgICAgIHJlc3BvbnNlLm9uKCdkYXRhJywgKGNodW5rKSA9PiB7XHJcbiAgICAgICAgICByZXNwb25zZURhdGEgKz0gY2h1bms7XHJcbiAgICAgICAgfSk7XHJcblxyXG4gICAgICAgIC8vIFRoZSB3aG9sZSByZXNwb25zZSBoYXMgYmVlbiByZWNlaXZlZFxyXG4gICAgICAgIHJlc3BvbnNlLm9uKCdlbmQnLCAoKSA9PiB7XHJcbiAgICAgICAgICB0cnkge1xyXG4gICAgICAgICAgICByZXNwb25zZS50ZXh0ID0gcmVzcG9uc2VEYXRhO1xyXG4gICAgICAgICAgICByZXNvbHZlKHJlc3BvbnNlKTtcclxuICAgICAgICAgIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICAgICAgICAgIHJlamVjdChlcnJvcik7XHJcbiAgICAgICAgICB9XHJcbiAgICAgICAgfSk7XHJcbiAgICAgIH0pXHJcbiAgICAgIC5vbignZXJyb3InLCAoZXJyb3IpID0+IHtcclxuICAgICAgICByZWplY3QoZXJyb3IpO1xyXG4gICAgICB9KTtcclxuXHJcbiAgICAvLyBXcml0ZSB0aGUgcmVxdWVzdCBib2R5IGFuZCBlbmQgdGhlIHJlcXVlc3RcclxuICAgIHJlcXVlc3Qud3JpdGUoZGF0YSk7XHJcbiAgICByZXF1ZXN0LmVuZCgpO1xyXG4gIH0pO1xyXG59XHJcblxyXG4vKipcclxuICogUmV0dXJucyB0aGUgSFRUUCBvciBIVFRQUyBwcm90b2NvbCBtb2R1bGUgYmFzZWQgb24gdGhlIHByb3ZpZGVkIFVSTC5cclxuICpcclxuICogQGZ1bmN0aW9uIF9nZXRQcm90b2NvbE1vZHVsZVxyXG4gKlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gdXJsIC0gVGhlIFVSTCB0byBkZXRlcm1pbmUgdGhlIHByb3RvY29sLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7T2JqZWN0fSBUaGUgSFRUUCBvciBIVFRQUyBwcm90b2NvbCBtb2R1bGUgKGh0dHAgb3IgaHR0cHMpLlxyXG4gKi9cclxuZnVuY3Rpb24gX2dldFByb3RvY29sTW9kdWxlKHVybCkge1xyXG4gIHJldHVybiB1cmwuc3RhcnRzV2l0aCgnaHR0cHMnKSA/IGh0dHBzIDogaHR0cDtcclxufVxyXG5cclxuZXhwb3J0IGRlZmF1bHQge1xyXG4gIGZldGNoLFxyXG4gIHBvc3RcclxufTtcclxuIiwiLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcclxuXHJcbkhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlclxyXG5cclxuQ29weXJpZ2h0IChjKSAyMDE2LTIwMjUsIEhpZ2hzb2Z0XHJcblxyXG5MaWNlbmNlZCB1bmRlciB0aGUgTUlUIGxpY2VuY2UuXHJcblxyXG5BZGRpdGlvbmFsbHkgYSB2YWxpZCBIaWdoY2hhcnRzIGxpY2Vuc2UgaXMgcmVxdWlyZWQgZm9yIHVzZS5cclxuXHJcblNlZSBMSUNFTlNFIGZpbGUgaW4gcm9vdCBmb3IgZGV0YWlscy5cclxuXHJcbioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXHJcblxyXG4vKipcclxuICogQG92ZXJ2aWV3IFRoZSBjYWNoZSBtYW5hZ2VyIGlzIHJlc3BvbnNpYmxlIGZvciBoYW5kbGluZyBhbmQgbWFuYWdpbmdcclxuICogdGhlIEhpZ2hjaGFydHMgbGlicmFyeSBhbG9uZyB3aXRoIGl0cyBkZXBlbmRlbmNpZXMuIEl0IGVuc3VyZXMgdGhhdCB0aGVzZVxyXG4gKiByZXNvdXJjZXMgYXJlIHN0b3JlZCBhbmQgcmV0cmlldmVkIGVmZmljaWVudGx5IHRvIG9wdGltaXplIHBlcmZvcm1hbmNlXHJcbiAqIGFuZCByZWR1Y2UgcmVkdW5kYW50IG5ldHdvcmsgcmVxdWVzdHMuIFRoZSBjYWNoZSBpcyBzdG9yZWQgaW4gdGhlIGAuY2FjaGVgXHJcbiAqIGRpcmVjdG9yeSBieSBkZWZhdWx0LCB3aGljaCBzZXJ2ZXMgYXMgYSBkZWRpY2F0ZWQgZm9sZGVyIGZvciBrZWVwaW5nIGNhY2hlZFxyXG4gKiBmaWxlcy5cclxuICovXHJcblxyXG5pbXBvcnQgeyBleGlzdHNTeW5jLCBta2RpclN5bmMsIHJlYWRGaWxlU3luYywgd3JpdGVGaWxlU3luYyB9IGZyb20gJ2ZzJztcclxuaW1wb3J0IHsgam9pbiB9IGZyb20gJ3BhdGgnO1xyXG5cclxuaW1wb3J0IHsgSHR0cHNQcm94eUFnZW50IH0gZnJvbSAnaHR0cHMtcHJveHktYWdlbnQnO1xyXG5cclxuaW1wb3J0IHsgZ2V0T3B0aW9ucyB9IGZyb20gJy4vY29uZmlnLmpzJztcclxuaW1wb3J0IHsgZmV0Y2ggfSBmcm9tICcuL2ZldGNoLmpzJztcclxuaW1wb3J0IHsgbG9nIH0gZnJvbSAnLi9sb2dnZXIuanMnO1xyXG5pbXBvcnQgeyBfX2Rpcm5hbWUsIGdldEFic29sdXRlUGF0aCB9IGZyb20gJy4vdXRpbHMuanMnO1xyXG5cclxuaW1wb3J0IEV4cG9ydEVycm9yIGZyb20gJy4vZXJyb3JzL0V4cG9ydEVycm9yLmpzJztcclxuXHJcbi8vIFRoZSBpbml0aWFsIGNhY2hlIHRlbXBsYXRlXHJcbmNvbnN0IGNhY2hlID0ge1xyXG4gIGNkblVybDogJ2h0dHBzOi8vY29kZS5oaWdoY2hhcnRzLmNvbScsXHJcbiAgYWN0aXZlTWFuaWZlc3Q6IHt9LFxyXG4gIHNvdXJjZXM6ICcnLFxyXG4gIGhjVmVyc2lvbjogJydcclxufTtcclxuXHJcbi8qKlxyXG4gKiBDaGVja3MgdGhlIGNhY2hlIGZvciBIaWdoY2hhcnRzIGRlcGVuZGVuY2llcywgdXBkYXRlcyB0aGUgY2FjaGUgaWYgbmVlZGVkLFxyXG4gKiBhbmQgbG9hZHMgdGhlIHNvdXJjZXMuXHJcbiAqXHJcbiAqIEBhc3luY1xyXG4gKiBAZnVuY3Rpb24gY2hlY2tBbmRVcGRhdGVDYWNoZVxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gaGlnaGNoYXJ0c09wdGlvbnMgLSBUaGUgY29uZmlndXJhdGlvbiBvYmplY3QgY29udGFpbmluZ1xyXG4gKiBgaGlnaGNoYXJ0c2Agb3B0aW9ucy5cclxuICogQHBhcmFtIHtPYmplY3R9IHNlcnZlclByb3h5T3B0aW9ucy0gVGhlIGNvbmZpZ3VyYXRpb24gb2JqZWN0IGNvbnRhaW5pbmdcclxuICogYHNlcnZlci5wcm94eWAgb3B0aW9ucy5cclxuICovXHJcbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBjaGVja0FuZFVwZGF0ZUNhY2hlKFxyXG4gIGhpZ2hjaGFydHNPcHRpb25zLFxyXG4gIHNlcnZlclByb3h5T3B0aW9uc1xyXG4pIHtcclxuICB0cnkge1xyXG4gICAgbGV0IGZldGNoZWRNb2R1bGVzO1xyXG5cclxuICAgIC8vIEdldCB0aGUgY2FjaGUgcGF0aFxyXG4gICAgY29uc3QgY2FjaGVQYXRoID0gZ2V0Q2FjaGVQYXRoKCk7XHJcblxyXG4gICAgLy8gUHJlcGFyZSBwYXRocyB0byBtYW5pZmVzdCBhbmQgc291cmNlcyBmcm9tIHRoZSBjYWNoZSBmb2xkZXJcclxuICAgIGNvbnN0IG1hbmlmZXN0UGF0aCA9IGpvaW4oY2FjaGVQYXRoLCAnbWFuaWZlc3QuanNvbicpO1xyXG4gICAgY29uc3Qgc291cmNlUGF0aCA9IGpvaW4oY2FjaGVQYXRoLCAnc291cmNlcy5qcycpO1xyXG5cclxuICAgIC8vIENyZWF0ZSB0aGUgY2FjaGUgZGVzdGluYXRpb24gaWYgaXQgZG9lc24ndCBleGlzdCBhbHJlYWR5XHJcbiAgICAhZXhpc3RzU3luYyhjYWNoZVBhdGgpICYmIG1rZGlyU3luYyhjYWNoZVBhdGgsIHsgcmVjdXJzaXZlOiB0cnVlIH0pO1xyXG5cclxuICAgIC8vIEZldGNoIGFsbCB0aGUgc2NyaXB0cyBlaXRoZXIgaWYgdGhlIGBtYW5pZmVzdC5qc29uYCBkb2VzIG5vdCBleGlzdFxyXG4gICAgLy8gb3IgaWYgdGhlIGBmb3JjZUZldGNoYCBvcHRpb24gaXMgZW5hYmxlZFxyXG4gICAgaWYgKCFleGlzdHNTeW5jKG1hbmlmZXN0UGF0aCkgfHwgaGlnaGNoYXJ0c09wdGlvbnMuZm9yY2VGZXRjaCkge1xyXG4gICAgICBsb2coMywgJ1tjYWNoZV0gRmV0Y2hpbmcgYW5kIGNhY2hpbmcgSGlnaGNoYXJ0cyBkZXBlbmRlbmNpZXMuJyk7XHJcbiAgICAgIGZldGNoZWRNb2R1bGVzID0gYXdhaXQgX3VwZGF0ZUNhY2hlKFxyXG4gICAgICAgIGhpZ2hjaGFydHNPcHRpb25zLFxyXG4gICAgICAgIHNlcnZlclByb3h5T3B0aW9ucyxcclxuICAgICAgICBzb3VyY2VQYXRoXHJcbiAgICAgICk7XHJcbiAgICB9IGVsc2Uge1xyXG4gICAgICBsZXQgcmVxdWVzdFVwZGF0ZSA9IGZhbHNlO1xyXG5cclxuICAgICAgLy8gUmVhZCB0aGUgbWFuaWZlc3QgSlNPTlxyXG4gICAgICBjb25zdCBtYW5pZmVzdCA9IEpTT04ucGFyc2UocmVhZEZpbGVTeW5jKG1hbmlmZXN0UGF0aCksICd1dGY4Jyk7XHJcblxyXG4gICAgICAvLyBDaGVjayBpZiB0aGUgbW9kdWxlcyBpcyBhbiBhcnJheSwgaWYgc28sIHdlIHJld3JpdGUgaXQgdG8gYSBtYXAgdG8gbWFrZVxyXG4gICAgICAvLyBpdCBlYXNpZXIgdG8gcmVzb2x2ZSBtb2R1bGVzLlxyXG4gICAgICBpZiAobWFuaWZlc3QubW9kdWxlcyAmJiBBcnJheS5pc0FycmF5KG1hbmlmZXN0Lm1vZHVsZXMpKSB7XHJcbiAgICAgICAgY29uc3QgbW9kdWxlTWFwID0ge307XHJcbiAgICAgICAgbWFuaWZlc3QubW9kdWxlcy5mb3JFYWNoKChtKSA9PiAobW9kdWxlTWFwW21dID0gMSkpO1xyXG4gICAgICAgIG1hbmlmZXN0Lm1vZHVsZXMgPSBtb2R1bGVNYXA7XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIC8vIEdldCB0aGUgYWN0dWFsIG51bWJlciBvZiBzY3JpcHRzIHRvIGJlIGZldGNoZWRcclxuICAgICAgY29uc3QgeyBjb3JlU2NyaXB0cywgbW9kdWxlU2NyaXB0cywgaW5kaWNhdG9yU2NyaXB0cyB9ID1cclxuICAgICAgICBoaWdoY2hhcnRzT3B0aW9ucztcclxuICAgICAgY29uc3QgbnVtYmVyT2ZNb2R1bGVzID1cclxuICAgICAgICBjb3JlU2NyaXB0cy5sZW5ndGggKyBtb2R1bGVTY3JpcHRzLmxlbmd0aCArIGluZGljYXRvclNjcmlwdHMubGVuZ3RoO1xyXG5cclxuICAgICAgLy8gQ29tcGFyZSB0aGUgbG9hZGVkIGhpZ2hjaGFydHMgY29uZmlnIHdpdGggdGhlIGNvbnRlbnRzIGluIGNhY2hlLlxyXG4gICAgICAvLyBJZiB0aGVyZSBhcmUgY2hhbmdlcywgZmV0Y2ggcmVxdWVzdGVkIG1vZHVsZXMgYW5kIHByb2R1Y3RzLFxyXG4gICAgICAvLyBhbmQgYmFrZSB0aGVtIGludG8gYSBnaWFudCBibG9iLiBTYXZlIHRoZSBibG9iLlxyXG4gICAgICBpZiAobWFuaWZlc3QudmVyc2lvbiAhPT0gaGlnaGNoYXJ0c09wdGlvbnMudmVyc2lvbikge1xyXG4gICAgICAgIGxvZyhcclxuICAgICAgICAgIDIsXHJcbiAgICAgICAgICAnW2NhY2hlXSBBIEhpZ2hjaGFydHMgdmVyc2lvbiBtaXNtYXRjaCBpbiB0aGUgY2FjaGUsIG5lZWQgdG8gcmUtZmV0Y2guJ1xyXG4gICAgICAgICk7XHJcbiAgICAgICAgcmVxdWVzdFVwZGF0ZSA9IHRydWU7XHJcbiAgICAgIH0gZWxzZSBpZiAoXHJcbiAgICAgICAgT2JqZWN0LmtleXMobWFuaWZlc3QubW9kdWxlcyB8fCB7fSkubGVuZ3RoICE9PSBudW1iZXJPZk1vZHVsZXNcclxuICAgICAgKSB7XHJcbiAgICAgICAgbG9nKFxyXG4gICAgICAgICAgMixcclxuICAgICAgICAgICdbY2FjaGVdIFRoZSBjYWNoZSBhbmQgdGhlIHJlcXVlc3RlZCBtb2R1bGVzIGRvIG5vdCBtYXRjaCwgbmVlZCB0byByZS1mZXRjaC4nXHJcbiAgICAgICAgKTtcclxuICAgICAgICByZXF1ZXN0VXBkYXRlID0gdHJ1ZTtcclxuICAgICAgfSBlbHNlIHtcclxuICAgICAgICAvLyBDaGVjayBlYWNoIG1vZHVsZSwgaWYgYW55dGhpbmcgaXMgbWlzc2luZyByZWZldGNoIGV2ZXJ5dGhpbmdcclxuICAgICAgICByZXF1ZXN0VXBkYXRlID0gKG1vZHVsZVNjcmlwdHMgfHwgW10pLnNvbWUoKG1vZHVsZU5hbWUpID0+IHtcclxuICAgICAgICAgIGlmICghbWFuaWZlc3QubW9kdWxlc1ttb2R1bGVOYW1lXSkge1xyXG4gICAgICAgICAgICBsb2coXHJcbiAgICAgICAgICAgICAgMixcclxuICAgICAgICAgICAgICBgW2NhY2hlXSBUaGUgJHttb2R1bGVOYW1lfSBpcyBtaXNzaW5nIGluIHRoZSBjYWNoZSwgbmVlZCB0byByZS1mZXRjaC5gXHJcbiAgICAgICAgICAgICk7XHJcbiAgICAgICAgICAgIHJldHVybiB0cnVlO1xyXG4gICAgICAgICAgfVxyXG4gICAgICAgIH0pO1xyXG4gICAgICB9XHJcblxyXG4gICAgICAvLyBVcGRhdGUgY2FjaGUgaWYgbmVlZGVkXHJcbiAgICAgIGlmIChyZXF1ZXN0VXBkYXRlKSB7XHJcbiAgICAgICAgZmV0Y2hlZE1vZHVsZXMgPSBhd2FpdCBfdXBkYXRlQ2FjaGUoXHJcbiAgICAgICAgICBoaWdoY2hhcnRzT3B0aW9ucyxcclxuICAgICAgICAgIHNlcnZlclByb3h5T3B0aW9ucyxcclxuICAgICAgICAgIHNvdXJjZVBhdGhcclxuICAgICAgICApO1xyXG4gICAgICB9IGVsc2Uge1xyXG4gICAgICAgIGxvZygzLCAnW2NhY2hlXSBEZXBlbmRlbmN5IGNhY2hlIGlzIHVwIHRvIGRhdGUsIHByb2NlZWRpbmcuJyk7XHJcblxyXG4gICAgICAgIC8vIExvYWQgdGhlIHNvdXJjZXNcclxuICAgICAgICBjYWNoZS5zb3VyY2VzID0gcmVhZEZpbGVTeW5jKHNvdXJjZVBhdGgsICd1dGY4Jyk7XHJcblxyXG4gICAgICAgIC8vIEdldCBjdXJyZW50IG1vZHVsZXMgbWFwXHJcbiAgICAgICAgZmV0Y2hlZE1vZHVsZXMgPSBtYW5pZmVzdC5tb2R1bGVzO1xyXG5cclxuICAgICAgICAvLyBFeHRyYWN0IGFuZCBzYXZlIHZlcnNpb24gb2YgY3VycmVudGx5IHVzZWQgSGlnaGNoYXJ0c1xyXG4gICAgICAgIGNhY2hlLmhjVmVyc2lvbiA9IGV4dHJhY3RWZXJzaW9uKGNhY2hlLnNvdXJjZXMpO1xyXG4gICAgICB9XHJcbiAgICB9XHJcblxyXG4gICAgLy8gRmluYWxseSwgc2F2ZSB0aGUgbmV3IG1hbmlmZXN0LCB3aGljaCBpcyBiYXNpY2FsbHkgb3VyIGN1cnJlbnQgY29uZmlnXHJcbiAgICAvLyBpbiBhIHNsaWdodGx5IGRpZmZlcmVudCBmb3JtYXRcclxuICAgIGF3YWl0IF9zYXZlQ29uZmlnVG9NYW5pZmVzdChoaWdoY2hhcnRzT3B0aW9ucywgZmV0Y2hlZE1vZHVsZXMpO1xyXG4gIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoXHJcbiAgICAgICdbY2FjaGVdIENvdWxkIG5vdCBjb25maWd1cmUgY2FjaGUgYW5kIGNyZWF0ZSBvciB1cGRhdGUgdGhlIGNvbmZpZyBtYW5pZmVzdC4nLFxyXG4gICAgICA1MDBcclxuICAgICkuc2V0RXJyb3IoZXJyb3IpO1xyXG4gIH1cclxufVxyXG5cclxuLyoqXHJcbiAqIEdldHMgdGhlIHZlcnNpb24gb2YgSGlnaGNoYXJ0cyBmcm9tIHRoZSBjYWNoZS5cclxuICpcclxuICogQGZ1bmN0aW9uIGdldEhpZ2hjaGFydHNWZXJzaW9uXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtzdHJpbmd9IFRoZSBjYWNoZWQgSGlnaGNoYXJ0cyB2ZXJzaW9uLlxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIGdldEhpZ2hjaGFydHNWZXJzaW9uKCkge1xyXG4gIHJldHVybiBjYWNoZS5oY1ZlcnNpb247XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBVcGRhdGVzIHRoZSBIaWdoY2hhcnRzIHZlcnNpb24gaW4gdGhlIGFwcGxpZWQgY29uZmlndXJhdGlvbiBhbmQgY2hlY2tzXHJcbiAqIHRoZSBjYWNoZSBmb3IgdGhlIG5ldyB2ZXJzaW9uLlxyXG4gKlxyXG4gKiBAYXN5bmNcclxuICogQGZ1bmN0aW9uIHVwZGF0ZUhpZ2hjaGFydHNWZXJzaW9uXHJcbiAqXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSBuZXdWZXJzaW9uIC0gVGhlIG5ldyBIaWdoY2hhcnRzIHZlcnNpb24gdG8gYmUgYXBwbGllZC5cclxuICovXHJcbmV4cG9ydCBhc3luYyBmdW5jdGlvbiB1cGRhdGVIaWdoY2hhcnRzVmVyc2lvbihuZXdWZXJzaW9uKSB7XHJcbiAgLy8gR2V0IHRoZSByZWZlcmVuY2UgdG8gdGhlIGdsb2JhbCBvcHRpb25zIHRvIHVwZGF0ZSB0byB0aGUgbmV3IHZlcnNpb25cclxuICBjb25zdCBvcHRpb25zID0gZ2V0T3B0aW9ucygpO1xyXG5cclxuICAvLyBTZXQgdG8gdGhlIG5ldyB2ZXJzaW9uXHJcbiAgb3B0aW9ucy5oaWdoY2hhcnRzLnZlcnNpb24gPSBuZXdWZXJzaW9uO1xyXG5cclxuICAvLyBDaGVjayBpZiBjYWNoZSBuZWVkcyB0byBiZSB1cGRhdGVkXHJcbiAgYXdhaXQgY2hlY2tBbmRVcGRhdGVDYWNoZShvcHRpb25zLmhpZ2hjaGFydHMsIG9wdGlvbnMuc2VydmVyLnByb3h5KTtcclxufVxyXG5cclxuLyoqXHJcbiAqIEV4dHJhY3RzIEhpZ2hjaGFydHMgdmVyc2lvbiBmcm9tIHRoZSBjYWNoZSdzIHNvdXJjZXMgc3RyaW5nLlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gZXh0cmFjdFZlcnNpb25cclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IGNhY2hlU291cmNlcyAtIFRoZSBjYWNoZSBzb3VyY2VzIG9iamVjdC5cclxuICpcclxuICogQHJldHVybnMge3N0cmluZ30gVGhlIGV4dHJhY3RlZCBIaWdoY2hhcnRzIHZlcnNpb24uXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gZXh0cmFjdFZlcnNpb24oY2FjaGVTb3VyY2VzKSB7XHJcbiAgcmV0dXJuIGNhY2hlU291cmNlc1xyXG4gICAgLnN1YnN0cmluZygwLCBjYWNoZVNvdXJjZXMuaW5kZXhPZignKi8nKSlcclxuICAgIC5yZXBsYWNlKCcvKicsICcnKVxyXG4gICAgLnJlcGxhY2UoJyovJywgJycpXHJcbiAgICAucmVwbGFjZSgvXFxuL2csICcnKVxyXG4gICAgLnRyaW0oKTtcclxufVxyXG5cclxuLyoqXHJcbiAqIEV4dHJhY3RzIHRoZSBIaWdoY2hhcnRzIG1vZHVsZSBuYW1lIGJhc2VkIG9uIHRoZSBzY3JpcHRQYXRoLlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gZXh0cmFjdE1vZHVsZU5hbWVcclxuICpcclxuICogQHBhcmFtIHtzdHJpbmd9IHNjcmlwdFBhdGggLSBUaGUgcGF0aCBvZiB0aGUgc2NyaXB0IGZyb20gd2hpY2ggdGhlIG1vZHVsZVxyXG4gKiBuYW1lIHdpbGwgYmUgZXh0cmFjdGVkLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7c3RyaW5nfSBUaGUgZXh0cmFjdGVkIG1vZHVsZSBuYW1lLlxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIGV4dHJhY3RNb2R1bGVOYW1lKHNjcmlwdFBhdGgpIHtcclxuICByZXR1cm4gc2NyaXB0UGF0aC5yZXBsYWNlKFxyXG4gICAgLyguKilcXC98KC4qKW1vZHVsZXNcXC98c3RvY2tcXC8oLiopaW5kaWNhdG9yc1xcL3xtYXBzXFwvKC4qKW1vZHVsZXNcXC8vZ2ksXHJcbiAgICAnJ1xyXG4gICk7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBSZXRyaWV2ZXMgdGhlIGN1cnJlbnQgY2FjaGUgb2JqZWN0LlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gZ2V0Q2FjaGVcclxuICpcclxuICogQHJldHVybnMge09iamVjdH0gVGhlIGNhY2hlIG9iamVjdCBjb250YWluaW5nIHZhcmlvdXMgY2FjaGVkIGRhdGEuXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gZ2V0Q2FjaGUoKSB7XHJcbiAgcmV0dXJuIGNhY2hlO1xyXG59XHJcblxyXG4vKipcclxuICogR2V0cyB0aGUgY2FjaGUgcGF0aCBmb3IgSGlnaGNoYXJ0cy5cclxuICpcclxuICogQGZ1bmN0aW9uIGdldENhY2hlUGF0aFxyXG4gKlxyXG4gKiBAcmV0dXJucyB7c3RyaW5nfSBUaGUgYWJzb2x1dGUgcGF0aCB0byB0aGUgY2FjaGUgZGlyZWN0b3J5IGZvciBIaWdoY2hhcnRzLlxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIGdldENhY2hlUGF0aCgpIHtcclxuICByZXR1cm4gZ2V0QWJzb2x1dGVQYXRoKGdldE9wdGlvbnMoKS5oaWdoY2hhcnRzLmNhY2hlUGF0aCwgJ3V0ZjgnKTsgLy8gIzU2MlxyXG59XHJcblxyXG4vKipcclxuICogRmV0Y2hlcyBhIHNpbmdsZSBzY3JpcHQgYW5kIHVwZGF0ZXMgdGhlIGBmZXRjaGVkTW9kdWxlc2AgYWNjb3JkaW5nbHkuXHJcbiAqXHJcbiAqIEBhc3luY1xyXG4gKiBAZnVuY3Rpb24gX2ZldGNoQW5kUHJvY2Vzc1NjcmlwdFxyXG4gKlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gc2NyaXB0IC0gQSBwYXRoIHRvIHNjcmlwdCB0byBnZXQuXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSByZXF1ZXN0T3B0aW9ucyAtIEFkZGl0aW9uYWwgb3B0aW9ucyBmb3IgdGhlIHByb3h5IGFnZW50XHJcbiAqIHRvIHVzZSBmb3IgYSByZXF1ZXN0LlxyXG4gKiBAcGFyYW0ge09iamVjdH0gZmV0Y2hlZE1vZHVsZXMgLSBBbiBvYmplY3Qgd2hpY2ggdHJhY2tzIHdoaWNoIEhpZ2hjaGFydHNcclxuICogbW9kdWxlcyBoYXZlIGJlZW4gZmV0Y2hlZC5cclxuICogQHBhcmFtIHtib29sZWFufSBbc2hvdWxkVGhyb3dFcnJvcj1mYWxzZV0gLSBBIGZsYWcgdG8gaW5kaWNhdGUgaWYgdGhlIGVycm9yXHJcbiAqIHNob3VsZCBiZSB0aHJvd24uIFRoaXMgc2hvdWxkIGJlIHVzZWQgb25seSBmb3IgdGhlIGNvcmUgc2NyaXB0cy4gVGhlIGRlZmF1bHRcclxuICogdmFsdWUgaXMgYGZhbHNlYC5cclxuICpcclxuICogQHJldHVybnMge1Byb21pc2U8c3RyaW5nPn0gQSBQcm9taXNlIHRoYXQgcmVzb2x2ZXMgdG8gdGhlIHRleHQgcmVwcmVzZW50YXRpb25cclxuICogb2YgdGhlIGZldGNoZWQgc2NyaXB0LlxyXG4gKlxyXG4gKiBAdGhyb3dzIHtFeHBvcnRFcnJvcn0gVGhyb3dzIGFuIGBFeHBvcnRFcnJvcmAgaWYgdGhlcmUgaXMgYSBwcm9ibGVtXHJcbiAqIHdpdGggZmV0Y2hpbmcgdGhlIHNjcmlwdC5cclxuICovXHJcbmFzeW5jIGZ1bmN0aW9uIF9mZXRjaEFuZFByb2Nlc3NTY3JpcHQoXHJcbiAgc2NyaXB0LFxyXG4gIHJlcXVlc3RPcHRpb25zLFxyXG4gIGZldGNoZWRNb2R1bGVzLFxyXG4gIHNob3VsZFRocm93RXJyb3IgPSBmYWxzZVxyXG4pIHtcclxuICAvLyBHZXQgcmlkIG9mIHRoZSAuanMgZnJvbSB0aGUgY3VzdG9tIHN0cmluZ3NcclxuICBpZiAoc2NyaXB0LmVuZHNXaXRoKCcuanMnKSkge1xyXG4gICAgc2NyaXB0ID0gc2NyaXB0LnN1YnN0cmluZygwLCBzY3JpcHQubGVuZ3RoIC0gMyk7XHJcbiAgfVxyXG4gIGxvZyg0LCBgW2NhY2hlXSBGZXRjaGluZyBzY3JpcHQgLSAke3NjcmlwdH0uanNgKTtcclxuXHJcbiAgLy8gRmV0Y2ggdGhlIHNjcmlwdFxyXG4gIGNvbnN0IHJlc3BvbnNlID0gYXdhaXQgZmV0Y2goYCR7c2NyaXB0fS5qc2AsIHJlcXVlc3RPcHRpb25zKTtcclxuXHJcbiAgLy8gSWYgT0ssIHJldHVybiBpdHMgdGV4dCByZXByZXNlbnRhdGlvblxyXG4gIGlmIChyZXNwb25zZS5zdGF0dXNDb2RlID09PSAyMDAgJiYgdHlwZW9mIHJlc3BvbnNlLnRleHQgPT0gJ3N0cmluZycpIHtcclxuICAgIGlmIChmZXRjaGVkTW9kdWxlcykge1xyXG4gICAgICBjb25zdCBtb2R1bGVOYW1lID0gZXh0cmFjdE1vZHVsZU5hbWUoc2NyaXB0KTtcclxuICAgICAgZmV0Y2hlZE1vZHVsZXNbbW9kdWxlTmFtZV0gPSAxO1xyXG4gICAgfVxyXG4gICAgcmV0dXJuIHJlc3BvbnNlLnRleHQ7XHJcbiAgfVxyXG5cclxuICAvLyBCYXNlZCBvbiB0aGUgYHNob3VsZFRocm93RXJyb3JgIGZsYWcsIGRlY2lkZSBob3cgdG8gc2VydmUgZXJyb3IgbWVzc2FnZVxyXG4gIGlmIChzaG91bGRUaHJvd0Vycm9yKSB7XHJcbiAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoXHJcbiAgICAgIGBbY2FjaGVdIENvdWxkIG5vdCBmZXRjaCB0aGUgJHtzY3JpcHR9LmpzLiBUaGUgc2NyaXB0IG1pZ2h0IG5vdCBleGlzdCBpbiB0aGUgcmVxdWVzdGVkIHZlcnNpb24gKHN0YXR1cyBjb2RlOiAke3Jlc3BvbnNlLnN0YXR1c0NvZGV9KS5gLFxyXG4gICAgICA0MDRcclxuICAgICkuc2V0RXJyb3IocmVzcG9uc2UpO1xyXG4gIH0gZWxzZSB7XHJcbiAgICBsb2coXHJcbiAgICAgIDIsXHJcbiAgICAgIGBbY2FjaGVdIENvdWxkIG5vdCBmZXRjaCB0aGUgJHtzY3JpcHR9LmpzLiBUaGUgc2NyaXB0IG1pZ2h0IG5vdCBleGlzdCBpbiB0aGUgcmVxdWVzdGVkIHZlcnNpb24uYFxyXG4gICAgKTtcclxuICB9XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBTYXZlcyB0aGUgcHJvdmlkZWQgY29uZmlndXJhdGlvbiBhbmQgZmV0Y2hlZCBtb2R1bGVzIHRvIHRoZSBjYWNoZSBtYW5pZmVzdFxyXG4gKiBmaWxlLlxyXG4gKlxyXG4gKiBAYXN5bmNcclxuICogQGZ1bmN0aW9uIF9zYXZlQ29uZmlnVG9NYW5pZmVzdFxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gaGlnaGNoYXJ0c09wdGlvbnMgLSBUaGUgY29uZmlndXJhdGlvbiBvYmplY3QgY29udGFpbmluZ1xyXG4gKiBgaGlnaGNoYXJ0c2Agb3B0aW9ucy5cclxuICogQHBhcmFtIHtPYmplY3R9IFtmZXRjaGVkTW9kdWxlcz17fV0gLSBBbiBvYmplY3Qgd2hpY2ggdHJhY2tzIHdoaWNoIEhpZ2hjaGFydHNcclxuICogbW9kdWxlcyBoYXZlIGJlZW4gZmV0Y2hlZC4gVGhlIGRlZmF1bHQgdmFsdWUgaXMgYW4gZW1wdHkgb2JqZWN0LlxyXG4gKlxyXG4gKiBAdGhyb3dzIHtFeHBvcnRFcnJvcn0gVGhyb3dzIGFuIGBFeHBvcnRFcnJvcmAgaWYgYW4gZXJyb3Igb2NjdXJzIHdoaWxlXHJcbiAqIHdyaXRpbmcgdGhlIGNhY2hlIG1hbmlmZXN0LlxyXG4gKi9cclxuYXN5bmMgZnVuY3Rpb24gX3NhdmVDb25maWdUb01hbmlmZXN0KGhpZ2hjaGFydHNPcHRpb25zLCBmZXRjaGVkTW9kdWxlcyA9IHt9KSB7XHJcbiAgY29uc3QgbmV3TWFuaWZlc3QgPSB7XHJcbiAgICB2ZXJzaW9uOiBoaWdoY2hhcnRzT3B0aW9ucy52ZXJzaW9uLFxyXG4gICAgbW9kdWxlczogZmV0Y2hlZE1vZHVsZXNcclxuICB9O1xyXG5cclxuICAvLyBVcGRhdGUgY2FjaGUgb2JqZWN0IHdpdGggdGhlIGN1cnJlbnQgbW9kdWxlc1xyXG4gIGNhY2hlLmFjdGl2ZU1hbmlmZXN0ID0gbmV3TWFuaWZlc3Q7XHJcblxyXG4gIGxvZygzLCAnW2NhY2hlXSBXcml0aW5nIGEgbmV3IG1hbmlmZXN0LicpO1xyXG4gIHRyeSB7XHJcbiAgICB3cml0ZUZpbGVTeW5jKFxyXG4gICAgICBqb2luKGdldENhY2hlUGF0aCgpLCAnbWFuaWZlc3QuanNvbicpLFxyXG4gICAgICBKU09OLnN0cmluZ2lmeShuZXdNYW5pZmVzdCksXHJcbiAgICAgICd1dGY4J1xyXG4gICAgKTtcclxuICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgdGhyb3cgbmV3IEV4cG9ydEVycm9yKFxyXG4gICAgICAnW2NhY2hlXSBFcnJvciB3cml0aW5nIHRoZSBjYWNoZSBtYW5pZmVzdC4nLFxyXG4gICAgICA1MDBcclxuICAgICkuc2V0RXJyb3IoZXJyb3IpO1xyXG4gIH1cclxufVxyXG5cclxuLyoqXHJcbiAqIEZldGNoZXMgSGlnaGNoYXJ0cyBgc2NyaXB0c2AgYW5kIGBjdXN0b21TY3JpcHRzYCBmcm9tIHRoZSBnaXZlbiBDRE5zLlxyXG4gKlxyXG4gKiBAYXN5bmNcclxuICogQGZ1bmN0aW9uIF9mZXRjaFNjcmlwdHNcclxuICpcclxuICogQHBhcmFtIHtBcnJheS48c3RyaW5nPn0gY29yZVNjcmlwdHMgLSBIaWdoY2hhcnRzIGNvcmUgc2NyaXB0cyB0byBmZXRjaC5cclxuICogQHBhcmFtIHtBcnJheS48c3RyaW5nPn0gbW9kdWxlU2NyaXB0cyAtIEhpZ2hjaGFydHMgbW9kdWxlcyB0byBmZXRjaC5cclxuICogQHBhcmFtIHtBcnJheS48c3RyaW5nPn0gY3VzdG9tU2NyaXB0cyAtIEN1c3RvbSBzY3JpcHQgcGF0aHMgdG8gZmV0Y2ggKGZ1bGxcclxuICogVVJMcykuXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBzZXJ2ZXJQcm94eU9wdGlvbnMgLSBUaGUgY29uZmlndXJhdGlvbiBvYmplY3QgY29udGFpbmluZ1xyXG4gKiBgc2VydmVyLnByb3h5YCBvcHRpb25zLlxyXG4gKiBAcGFyYW0ge09iamVjdH0gZmV0Y2hlZE1vZHVsZXMgLSBBbiBvYmplY3Qgd2hpY2ggdHJhY2tzIHdoaWNoIEhpZ2hjaGFydHNcclxuICogbW9kdWxlcyBoYXZlIGJlZW4gZmV0Y2hlZC5cclxuICpcclxuICogQHJldHVybnMge1Byb21pc2U8c3RyaW5nPn0gQSBQcm9taXNlIHRoYXQgcmVzb2x2ZXMgdG8gdGhlIGZldGNoZWQgc2NyaXB0c1xyXG4gKiBjb250ZW50IGpvaW5lZC5cclxuICpcclxuICogQHRocm93cyB7RXhwb3J0RXJyb3J9IFRocm93cyBhbiBgRXhwb3J0RXJyb3JgIGlmIGFuIGVycm9yIG9jY3VycyB3aGlsZVxyXG4gKiBzZXR0aW5nIGFuIEhUVFAgQWdlbnQgZm9yIHByb3h5LlxyXG4gKi9cclxuYXN5bmMgZnVuY3Rpb24gX2ZldGNoU2NyaXB0cyhcclxuICBjb3JlU2NyaXB0cyxcclxuICBtb2R1bGVTY3JpcHRzLFxyXG4gIGN1c3RvbVNjcmlwdHMsXHJcbiAgc2VydmVyUHJveHlPcHRpb25zLFxyXG4gIGZldGNoZWRNb2R1bGVzXHJcbikge1xyXG4gIC8vIENvbmZpZ3VyZSBwcm94eSBpZiBleGlzdHNcclxuICBsZXQgcHJveHlBZ2VudDtcclxuICBjb25zdCBwcm94eUhvc3QgPSBzZXJ2ZXJQcm94eU9wdGlvbnMuaG9zdDtcclxuICBjb25zdCBwcm94eVBvcnQgPSBzZXJ2ZXJQcm94eU9wdGlvbnMucG9ydDtcclxuXHJcbiAgLy8gVHJ5IHRvIGNyZWF0ZSBhIFByb3h5IEFnZW50XHJcbiAgaWYgKHByb3h5SG9zdCAmJiBwcm94eVBvcnQpIHtcclxuICAgIHRyeSB7XHJcbiAgICAgIHByb3h5QWdlbnQgPSBuZXcgSHR0cHNQcm94eUFnZW50KHtcclxuICAgICAgICBob3N0OiBwcm94eUhvc3QsXHJcbiAgICAgICAgcG9ydDogcHJveHlQb3J0XHJcbiAgICAgIH0pO1xyXG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICAgdGhyb3cgbmV3IEV4cG9ydEVycm9yKFxyXG4gICAgICAgICdbY2FjaGVdIENvdWxkIG5vdCBjcmVhdGUgYSBQcm94eSBBZ2VudC4nLFxyXG4gICAgICAgIDUwMFxyXG4gICAgICApLnNldEVycm9yKGVycm9yKTtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIC8vIElmIGV4aXN0cywgYWRkIHByb3h5IGFnZW50IHRvIHJlcXVlc3Qgb3B0aW9uc1xyXG4gIGNvbnN0IHJlcXVlc3RPcHRpb25zID0gcHJveHlBZ2VudFxyXG4gICAgPyB7XHJcbiAgICAgICAgYWdlbnQ6IHByb3h5QWdlbnQsXHJcbiAgICAgICAgdGltZW91dDogc2VydmVyUHJveHlPcHRpb25zLnRpbWVvdXRcclxuICAgICAgfVxyXG4gICAgOiB7fTtcclxuXHJcbiAgY29uc3QgYWxsRmV0Y2hQcm9taXNlcyA9IFtcclxuICAgIC4uLmNvcmVTY3JpcHRzLm1hcCgoc2NyaXB0KSA9PlxyXG4gICAgICBfZmV0Y2hBbmRQcm9jZXNzU2NyaXB0KGAke3NjcmlwdH1gLCByZXF1ZXN0T3B0aW9ucywgZmV0Y2hlZE1vZHVsZXMsIHRydWUpXHJcbiAgICApLFxyXG4gICAgLi4ubW9kdWxlU2NyaXB0cy5tYXAoKHNjcmlwdCkgPT5cclxuICAgICAgX2ZldGNoQW5kUHJvY2Vzc1NjcmlwdChgJHtzY3JpcHR9YCwgcmVxdWVzdE9wdGlvbnMsIGZldGNoZWRNb2R1bGVzKVxyXG4gICAgKSxcclxuICAgIC4uLmN1c3RvbVNjcmlwdHMubWFwKChzY3JpcHQpID0+XHJcbiAgICAgIF9mZXRjaEFuZFByb2Nlc3NTY3JpcHQoYCR7c2NyaXB0fWAsIHJlcXVlc3RPcHRpb25zKVxyXG4gICAgKVxyXG4gIF07XHJcblxyXG4gIGNvbnN0IGZldGNoZWRTY3JpcHRzID0gYXdhaXQgUHJvbWlzZS5hbGwoYWxsRmV0Y2hQcm9taXNlcyk7XHJcbiAgcmV0dXJuIGZldGNoZWRTY3JpcHRzLmpvaW4oJztcXG4nKTtcclxufVxyXG5cclxuLyoqXHJcbiAqIFVwZGF0ZXMgdGhlIGxvY2FsIGNhY2hlIHdpdGggSGlnaGNoYXJ0cyBzY3JpcHRzIGFuZCB0aGVpciB2ZXJzaW9ucy5cclxuICpcclxuICogQGFzeW5jXHJcbiAqIEBmdW5jdGlvbiBfdXBkYXRlQ2FjaGVcclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IGhpZ2hjaGFydHNPcHRpb25zIC0gVGhlIGNvbmZpZ3VyYXRpb24gb2JqZWN0IGNvbnRhaW5pbmdcclxuICogYGhpZ2hjaGFydHNgIG9wdGlvbnMuXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBzZXJ2ZXJQcm94eU9wdGlvbnMgLSBUaGUgY29uZmlndXJhdGlvbiBvYmplY3QgY29udGFpbmluZ1xyXG4gKiBgc2VydmVyLnByb3h5YCBvcHRpb25zLlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gc291cmNlUGF0aCAtIFRoZSBwYXRoIHRvIHRoZSBzb3VyY2UgZmlsZSBpbiB0aGUgY2FjaGUuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtQcm9taXNlPE9iamVjdD59IEEgUHJvbWlzZSB0aGF0IHJlc29sdmVzIHRvIGFuIG9iamVjdCByZXByZXNlbnRpbmdcclxuICogdGhlIGZldGNoZWQgbW9kdWxlcy5cclxuICpcclxuICogQHRocm93cyB7RXhwb3J0RXJyb3J9IFRocm93cyBhbiBgRXhwb3J0RXJyb3JgIGlmIHRoZXJlIGlzIGFuIGlzc3VlIHVwZGF0aW5nXHJcbiAqIHRoZSBsb2NhbCBIaWdoY2hhcnRzIGNhY2hlLlxyXG4gKi9cclxuYXN5bmMgZnVuY3Rpb24gX3VwZGF0ZUNhY2hlKGhpZ2hjaGFydHNPcHRpb25zLCBzZXJ2ZXJQcm94eU9wdGlvbnMsIHNvdXJjZVBhdGgpIHtcclxuICAvLyBHZXQgSGlnaGNoYXJ0cyB2ZXJzaW9uIGZvciBzY3JpcHRzXHJcbiAgY29uc3QgaGNWZXJzaW9uID1cclxuICAgIGhpZ2hjaGFydHNPcHRpb25zLnZlcnNpb24gPT09ICdsYXRlc3QnXHJcbiAgICAgID8gbnVsbFxyXG4gICAgICA6IGAke2hpZ2hjaGFydHNPcHRpb25zLnZlcnNpb259YDtcclxuXHJcbiAgLy8gR2V0IHRoZSBDRE4gdXJsIGZvciBzY3JpcHRzXHJcbiAgY29uc3QgY2RuVXJsID0gaGlnaGNoYXJ0c09wdGlvbnMuY2RuVXJsIHx8IGNhY2hlLmNkblVybDtcclxuXHJcbiAgdHJ5IHtcclxuICAgIGNvbnN0IGZldGNoZWRNb2R1bGVzID0ge307XHJcblxyXG4gICAgbG9nKFxyXG4gICAgICAzLFxyXG4gICAgICBgW2NhY2hlXSBVcGRhdGluZyBjYWNoZSB2ZXJzaW9uIHRvIEhpZ2hjaGFydHM6ICR7aGNWZXJzaW9uIHx8ICdsYXRlc3QnfS5gXHJcbiAgICApO1xyXG5cclxuICAgIGNhY2hlLnNvdXJjZXMgPSBhd2FpdCBfZmV0Y2hTY3JpcHRzKFxyXG4gICAgICBbXHJcbiAgICAgICAgLi4uaGlnaGNoYXJ0c09wdGlvbnMuY29yZVNjcmlwdHMubWFwKChjKSA9PlxyXG4gICAgICAgICAgaGNWZXJzaW9uID8gYCR7Y2RuVXJsfS8ke2hjVmVyc2lvbn0vJHtjfWAgOiBgJHtjZG5Vcmx9LyR7Y31gXHJcbiAgICAgICAgKVxyXG4gICAgICBdLFxyXG4gICAgICBbXHJcbiAgICAgICAgLi4uaGlnaGNoYXJ0c09wdGlvbnMubW9kdWxlU2NyaXB0cy5tYXAoKG0pID0+XHJcbiAgICAgICAgICBtID09PSAnbWFwJ1xyXG4gICAgICAgICAgICA/IGhjVmVyc2lvblxyXG4gICAgICAgICAgICAgID8gYCR7Y2RuVXJsfS9tYXBzLyR7aGNWZXJzaW9ufS9tb2R1bGVzLyR7bX1gXHJcbiAgICAgICAgICAgICAgOiBgJHtjZG5Vcmx9L21hcHMvbW9kdWxlcy8ke219YFxyXG4gICAgICAgICAgICA6IGhjVmVyc2lvblxyXG4gICAgICAgICAgICAgID8gYCR7Y2RuVXJsfS8ke2hjVmVyc2lvbn0vbW9kdWxlcy8ke219YFxyXG4gICAgICAgICAgICAgIDogYCR7Y2RuVXJsfS9tb2R1bGVzLyR7bX1gXHJcbiAgICAgICAgKSxcclxuICAgICAgICAuLi5oaWdoY2hhcnRzT3B0aW9ucy5pbmRpY2F0b3JTY3JpcHRzLm1hcCgoaSkgPT5cclxuICAgICAgICAgIGhjVmVyc2lvblxyXG4gICAgICAgICAgICA/IGAke2NkblVybH0vc3RvY2svJHtoY1ZlcnNpb259L2luZGljYXRvcnMvJHtpfWBcclxuICAgICAgICAgICAgOiBgJHtjZG5Vcmx9L3N0b2NrL2luZGljYXRvcnMvJHtpfWBcclxuICAgICAgICApXHJcbiAgICAgIF0sXHJcbiAgICAgIGhpZ2hjaGFydHNPcHRpb25zLmN1c3RvbVNjcmlwdHMsXHJcbiAgICAgIHNlcnZlclByb3h5T3B0aW9ucyxcclxuICAgICAgZmV0Y2hlZE1vZHVsZXNcclxuICAgICk7XHJcblxyXG4gICAgLy8gRXh0cmFjdCBhbmQgc2F2ZSB2ZXJzaW9uIG9mIGN1cnJlbnRseSB1c2VkIEhpZ2hjaGFydHNcclxuICAgIGNhY2hlLmhjVmVyc2lvbiA9IGV4dHJhY3RWZXJzaW9uKGNhY2hlLnNvdXJjZXMpO1xyXG5cclxuICAgIC8vIFNhdmUgdGhlIGZldGNoZWQgbW9kdWxlcyBpbnRvIGNhY2hlcycgc291cmNlIEpTT05cclxuICAgIHdyaXRlRmlsZVN5bmMoc291cmNlUGF0aCwgY2FjaGUuc291cmNlcyk7XHJcbiAgICByZXR1cm4gZmV0Y2hlZE1vZHVsZXM7XHJcbiAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcihcclxuICAgICAgJ1tjYWNoZV0gVW5hYmxlIHRvIHVwZGF0ZSB0aGUgbG9jYWwgSGlnaGNoYXJ0cyBjYWNoZS4nLFxyXG4gICAgICA1MDBcclxuICAgICkuc2V0RXJyb3IoZXJyb3IpO1xyXG4gIH1cclxufVxyXG5cclxuZXhwb3J0IGRlZmF1bHQge1xyXG4gIGNoZWNrQW5kVXBkYXRlQ2FjaGUsXHJcbiAgZ2V0SGlnaGNoYXJ0c1ZlcnNpb24sXHJcbiAgdXBkYXRlSGlnaGNoYXJ0c1ZlcnNpb24sXHJcbiAgZXh0cmFjdFZlcnNpb24sXHJcbiAgZXh0cmFjdE1vZHVsZU5hbWUsXHJcbiAgZ2V0Q2FjaGUsXHJcbiAgZ2V0Q2FjaGVQYXRoXHJcbn07XHJcbiIsIi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXHJcblxyXG5IaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXJcclxuXHJcbkNvcHlyaWdodCAoYykgMjAxNi0yMDI1LCBIaWdoc29mdFxyXG5cclxuTGljZW5jZWQgdW5kZXIgdGhlIE1JVCBsaWNlbmNlLlxyXG5cclxuQWRkaXRpb25hbGx5IGEgdmFsaWQgSGlnaGNoYXJ0cyBsaWNlbnNlIGlzIHJlcXVpcmVkIGZvciB1c2UuXHJcblxyXG5TZWUgTElDRU5TRSBmaWxlIGluIHJvb3QgZm9yIGRldGFpbHMuXHJcblxyXG4qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xyXG5cclxuLyoqXHJcbiAqIEBvdmVydmlldyBQcm92aWRlcyBtZXRob2RzIGZvciBpbml0aWFsaXppbmcgSGlnaGNoYXJ0cyB3aXRoIGN1c3RvbWl6ZWRcclxuICogYW5pbWF0aW9uIHNldHRpbmdzIGFuZCB0cmlnZ2VyaW5nIHRoZSBjcmVhdGlvbiBvZiBIaWdoY2hhcnRzIGNoYXJ0cyB3aXRoXHJcbiAqIGV4cG9ydC1zcGVjaWZpYyBjb25maWd1cmF0aW9ucyBpbiB0aGUgcGFnZSBjb250ZXh0LiBTdXBwb3J0cyBkeW5hbWljIG9wdGlvblxyXG4gKiBtZXJnaW5nLCBjdXN0b20gbG9naWMgaW5qZWN0aW9uLCBhbmQgY29udHJvbCBvdmVyIHJlbmRlcmluZyBiZWhhdmlvcnMuIFVzZWRcclxuICogYnkgdGhlIFB1cHBldGVlciBwYWdlLlxyXG4gKi9cclxuXHJcbi8qIGVzbGludC1kaXNhYmxlIG5vLXVuZGVmICovXHJcblxyXG4vKipcclxuICogU2V0dGluZyB0aGUgYEhpZ2hjaGFydHMuYW5pbU9iamVjdGAgZnVuY3Rpb24uIENhbGxlZCB3aGVuIGluaXRpbmcgdGhlIHBhZ2UuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBzZXR1cEhpZ2hjaGFydHNcclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiBzZXR1cEhpZ2hjaGFydHMoKSB7XHJcbiAgSGlnaGNoYXJ0cy5hbmltT2JqZWN0ID0gZnVuY3Rpb24gKCkge1xyXG4gICAgcmV0dXJuIHsgZHVyYXRpb246IDAgfTtcclxuICB9O1xyXG59XHJcblxyXG4vKipcclxuICogQ3JlYXRlcyB0aGUgYWN0dWFsIEhpZ2hjaGFydHMgY2hhcnQgb24gYSBwYWdlLlxyXG4gKlxyXG4gKiBAYXN5bmNcclxuICogQGZ1bmN0aW9uIGNyZWF0ZUNoYXJ0XHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBleHBvcnRPcHRpb25zIC0gVGhlIGNvbmZpZ3VyYXRpb24gb2JqZWN0IGNvbnRhaW5pbmcgYGV4cG9ydGBcclxuICogb3B0aW9ucy5cclxuICogQHBhcmFtIHtPYmplY3R9IGN1c3RvbUxvZ2ljT3B0aW9ucyAtIFRoZSBjb25maWd1cmF0aW9uIG9iamVjdCBjb250YWluaW5nXHJcbiAqIGBjdXN0b21Mb2dpY2Agb3B0aW9ucy5cclxuICpcclxuICovXHJcbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBjcmVhdGVDaGFydChleHBvcnRPcHRpb25zLCBjdXN0b21Mb2dpY09wdGlvbnMpIHtcclxuICAvLyBHZXQgcmVxdWlyZWQgZnVuY3Rpb25zXHJcbiAgY29uc3QgeyBnZXRPcHRpb25zLCBzZXRPcHRpb25zLCBtZXJnZSwgd3JhcCB9ID0gSGlnaGNoYXJ0cztcclxuXHJcbiAgLy8gQ3JlYXRlIGEgc2VwYXJhdGUgb2JqZWN0IGZvciBhIHBvdGVudGlhbCBgc2V0T3B0aW9uc2AgdXNhZ2VzIGluIG9yZGVyXHJcbiAgLy8gdG8gcHJldmVudCBmcm9tIHBvbGx1dGluZyBvdGhlciBleHBvcnRzIHRoYXQgY2FuIGhhcHBlbiBvbiB0aGUgc2FtZSBwYWdlXHJcbiAgSGlnaGNoYXJ0cy5zZXRPcHRpb25zT2JqID0gbWVyZ2UoZmFsc2UsIHt9LCBnZXRPcHRpb25zKCkpO1xyXG5cclxuICAvLyBOT1RFOiBJcyB0aGlzIHVzZWQgZm9yIGFueXRoaW5nIHVzZWZ1bD9cclxuICB3aW5kb3cuaXNSZW5kZXJDb21wbGV0ZSA9IGZhbHNlO1xyXG4gIHdyYXAoSGlnaGNoYXJ0cy5DaGFydC5wcm90b3R5cGUsICdpbml0JywgZnVuY3Rpb24gKHByb2NlZWQsIHVzZXJPcHRpb25zLCBjYikge1xyXG4gICAgLy8gT3ZlcnJpZGUgdGhlIGB1c2VyT3B0aW9uc2Agd2l0aCBpbWFnZSBmcmllbmRseSBvcHRpb25zXHJcbiAgICB1c2VyT3B0aW9ucyA9IG1lcmdlKHVzZXJPcHRpb25zLCB7XHJcbiAgICAgIGV4cG9ydGluZzoge1xyXG4gICAgICAgIGVuYWJsZWQ6IGZhbHNlXHJcbiAgICAgIH0sXHJcbiAgICAgIHBsb3RPcHRpb25zOiB7XHJcbiAgICAgICAgc2VyaWVzOiB7XHJcbiAgICAgICAgICBsYWJlbDoge1xyXG4gICAgICAgICAgICBlbmFibGVkOiBmYWxzZVxyXG4gICAgICAgICAgfVxyXG4gICAgICAgIH1cclxuICAgICAgfSxcclxuICAgICAgLyogRXhwZWN0cyB0b29sdGlwIGluIHRoZSBgdXNlck9wdGlvbnNgIHdoZW4gYGZvckV4cG9ydGAgaXMgdHJ1ZS5cclxuICAgICAgICBodHRwczovL2dpdGh1Yi5jb20vaGlnaGNoYXJ0cy9oaWdoY2hhcnRzL2Jsb2IvM2FkNDMwYTM1M2I4MDU2YjllNzY0YWE0ZTVjZDY4MjhhYTQ3OWRiMi9qcy9wYXJ0cy9DaGFydC5qcyNMMjQxXHJcbiAgICAgICAgKi9cclxuICAgICAgdG9vbHRpcDoge31cclxuICAgIH0pO1xyXG5cclxuICAgICh1c2VyT3B0aW9ucy5zZXJpZXMgfHwgW10pLmZvckVhY2goZnVuY3Rpb24gKHNlcmllcykge1xyXG4gICAgICBzZXJpZXMuYW5pbWF0aW9uID0gZmFsc2U7XHJcbiAgICB9KTtcclxuXHJcbiAgICAvLyBBZGQgZmxhZyB0byBrbm93IGlmIGNoYXJ0IHJlbmRlciBoYXMgYmVlbiBjYWxsZWQuXHJcbiAgICBpZiAoIXdpbmRvdy5vbkhpZ2hjaGFydHNSZW5kZXIpIHtcclxuICAgICAgd2luZG93Lm9uSGlnaGNoYXJ0c1JlbmRlciA9IEhpZ2hjaGFydHMuYWRkRXZlbnQodGhpcywgJ3JlbmRlcicsICgpID0+IHtcclxuICAgICAgICB3aW5kb3cuaXNSZW5kZXJDb21wbGV0ZSA9IHRydWU7XHJcbiAgICAgIH0pO1xyXG4gICAgfVxyXG5cclxuICAgIHByb2NlZWQuYXBwbHkodGhpcywgW3VzZXJPcHRpb25zLCBjYl0pO1xyXG4gIH0pO1xyXG5cclxuICB3cmFwKEhpZ2hjaGFydHMuU2VyaWVzLnByb3RvdHlwZSwgJ2luaXQnLCBmdW5jdGlvbiAocHJvY2VlZCwgY2hhcnQsIG9wdGlvbnMpIHtcclxuICAgIHByb2NlZWQuYXBwbHkodGhpcywgW2NoYXJ0LCBvcHRpb25zXSk7XHJcbiAgfSk7XHJcblxyXG4gIC8vIFNvbWUgbWFuZGF0b3J5IGFkZGl0aW9uYWwgYGNoYXJ0YCBhbmQgYGV4cG9ydGluZ2Agb3B0aW9uc1xyXG4gIGNvbnN0IGFkZGl0aW9uYWxPcHRpb25zID0ge1xyXG4gICAgY2hhcnQ6IHtcclxuICAgICAgLy8gQnkgZGVmYXVsdCBhbmltYXRpb24gaXMgZGlzYWJsZWRcclxuICAgICAgYW5pbWF0aW9uOiBmYWxzZSxcclxuICAgICAgLy8gR2V0IHRoZSByaWdodCBzaXplIHZhbHVlc1xyXG4gICAgICBoZWlnaHQ6IGV4cG9ydE9wdGlvbnMuaGVpZ2h0LFxyXG4gICAgICB3aWR0aDogZXhwb3J0T3B0aW9ucy53aWR0aFxyXG4gICAgfSxcclxuICAgIGV4cG9ydGluZzoge1xyXG4gICAgICAvLyBObyBuZWVkIGZvciB0aGUgZXhwb3J0aW5nIGJ1dHRvblxyXG4gICAgICBlbmFibGVkOiBmYWxzZVxyXG4gICAgfVxyXG4gIH07XHJcblxyXG4gIC8vIEdldCB0aGUgaW5wdXQgdG8gZXhwb3J0IGZyb20gdGhlIGBpbnN0cmAgb3B0aW9uXHJcbiAgY29uc3QgdXNlck9wdGlvbnMgPSBuZXcgRnVuY3Rpb24oYHJldHVybiAke2V4cG9ydE9wdGlvbnMuaW5zdHJ9YCkoKTtcclxuXHJcbiAgLy8gR2V0IHRoZSBgdGhlbWVPcHRpb25zYCBvcHRpb25cclxuICBjb25zdCB0aGVtZU9wdGlvbnMgPSBuZXcgRnVuY3Rpb24oYHJldHVybiAke2V4cG9ydE9wdGlvbnMudGhlbWVPcHRpb25zfWApKCk7XHJcblxyXG4gIC8vIEdldCB0aGUgYGdsb2JhbE9wdGlvbnNgIG9wdGlvblxyXG4gIGNvbnN0IGdsb2JhbE9wdGlvbnMgPSBuZXcgRnVuY3Rpb24oYHJldHVybiAke2V4cG9ydE9wdGlvbnMuZ2xvYmFsT3B0aW9uc31gKSgpO1xyXG5cclxuICAvLyBNZXJnZSB0aGUgZm9sbG93aW5nIG9wdGlvbnMgb2JqZWN0cyB0byBjcmVhdGUgZmluYWwgb3B0aW9uc1xyXG4gIGNvbnN0IGZpbmFsT3B0aW9ucyA9IG1lcmdlKFxyXG4gICAgZmFsc2UsXHJcbiAgICB0aGVtZU9wdGlvbnMsXHJcbiAgICB1c2VyT3B0aW9ucyxcclxuICAgIC8vIFBsYWNlZCBpdCBoZXJlIGluc3RlYWQgaW4gdGhlIGluaXQgYmVjYXVzZSBvZiB0aGUgc2l6ZSBpc3N1ZXNcclxuICAgIGFkZGl0aW9uYWxPcHRpb25zXHJcbiAgKTtcclxuXHJcbiAgLy8gUHJlcGFyZSB0aGUgYGNhbGxiYWNrYCBvcHRpb25cclxuICBjb25zdCBmaW5hbENhbGxiYWNrID0gY3VzdG9tTG9naWNPcHRpb25zLmNhbGxiYWNrXHJcbiAgICA/IG5ldyBGdW5jdGlvbihgcmV0dXJuICR7Y3VzdG9tTG9naWNPcHRpb25zLmNhbGxiYWNrfWApKClcclxuICAgIDogbnVsbDtcclxuXHJcbiAgLy8gVHJpZ2dlciB0aGUgYGN1c3RvbUNvZGVgIG9wdGlvblxyXG4gIGlmIChjdXN0b21Mb2dpY09wdGlvbnMuY3VzdG9tQ29kZSkge1xyXG4gICAgbmV3IEZ1bmN0aW9uKCdvcHRpb25zJywgY3VzdG9tTG9naWNPcHRpb25zLmN1c3RvbUNvZGUpKHVzZXJPcHRpb25zKTtcclxuICB9XHJcblxyXG4gIC8vIFNldCB0aGUgZ2xvYmFsIG9wdGlvbnMgaWYgZXhpc3RcclxuICBpZiAoZ2xvYmFsT3B0aW9ucykge1xyXG4gICAgc2V0T3B0aW9ucyhnbG9iYWxPcHRpb25zKTtcclxuICB9XHJcblxyXG4gIC8vIENhbGwgdGhlIGNoYXJ0IGNyZWF0aW9uXHJcbiAgSGlnaGNoYXJ0c1tleHBvcnRPcHRpb25zLmNvbnN0cl0oJ2NvbnRhaW5lcicsIGZpbmFsT3B0aW9ucywgZmluYWxDYWxsYmFjayk7XHJcblxyXG4gIC8vIEdldCB0aGUgY3VycmVudCBnbG9iYWwgb3B0aW9uc1xyXG4gIGNvbnN0IGRlZmF1bHRPcHRpb25zID0gZ2V0T3B0aW9ucygpO1xyXG5cclxuICAvLyBDbGVhciBpdCBqdXN0IGluIGNhc2UgKGUuZy4gdGhlIGBzZXRPcHRpb25zYCB3YXMgdXNlZCBpbiB0aGUgYGN1c3RvbUNvZGVgKVxyXG4gIGZvciAoY29uc3QgcHJvcCBpbiBkZWZhdWx0T3B0aW9ucykge1xyXG4gICAgaWYgKHR5cGVvZiBkZWZhdWx0T3B0aW9uc1twcm9wXSAhPT0gJ2Z1bmN0aW9uJykge1xyXG4gICAgICBkZWxldGUgZGVmYXVsdE9wdGlvbnNbcHJvcF07XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICAvLyBTZXQgdGhlIGRlZmF1bHQgb3B0aW9ucyBiYWNrXHJcbiAgc2V0T3B0aW9ucyhIaWdoY2hhcnRzLnNldE9wdGlvbnNPYmopO1xyXG5cclxuICAvLyBFbXB0eSB0aGUgY3VzdG9tIGdsb2JhbCBvcHRpb25zIG9iamVjdFxyXG4gIEhpZ2hjaGFydHMuc2V0T3B0aW9uc09iaiA9IHt9O1xyXG59XHJcblxyXG5leHBvcnQgZGVmYXVsdCB7XHJcbiAgc2V0dXBIaWdoY2hhcnRzLFxyXG4gIGNyZWF0ZUNoYXJ0XHJcbn07XHJcbiIsIi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXHJcblxyXG5IaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXJcclxuXHJcbkNvcHlyaWdodCAoYykgMjAxNi0yMDI1LCBIaWdoc29mdFxyXG5cclxuTGljZW5jZWQgdW5kZXIgdGhlIE1JVCBsaWNlbmNlLlxyXG5cclxuQWRkaXRpb25hbGx5IGEgdmFsaWQgSGlnaGNoYXJ0cyBsaWNlbnNlIGlzIHJlcXVpcmVkIGZvciB1c2UuXHJcblxyXG5TZWUgTElDRU5TRSBmaWxlIGluIHJvb3QgZm9yIGRldGFpbHMuXHJcblxyXG4qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xyXG5cclxuLyoqXHJcbiAqIEBvdmVydmlldyBUaGlzIG1vZHVsZSBwcm92aWRlcyBmdW5jdGlvbnMgZm9yIG1hbmFnaW5nIFB1cHBldGVlciBicm93c2VyXHJcbiAqIGluc3RhbmNlLCBjcmVhdGluZyBhbmQgY2xlYXJpbmcgcGFnZXMsIGluamVjdGluZyBjdXN0b20gcmVzb3VyY2VzLFxyXG4gKiBhbmQgc2V0dGluZyB1cCBIaWdoY2hhcnRzIGZvciBzZXJ2ZXItc2lkZSByZW5kZXJpbmcuIFRoZSBtb2R1bGUgZW5zdXJlc1xyXG4gKiB0aGF0IHJlc291cmNlcyBhcmUgY29ycmVjdGx5IG1hbmFnZWQgYW5kIGNhbiBoYW5kbGUgZmFpbHVyZXMgZHVyaW5nXHJcbiAqIG9wZXJhdGlvbnMgbGlrZSBsYXVuY2hpbmcgdGhlIGJyb3dzZXIgb3IgY3JlYXRpbmcgbmV3IHBhZ2VzLlxyXG4gKi9cclxuXHJcbmltcG9ydCB7IHJlYWRGaWxlU3luYyB9IGZyb20gJ2ZzJztcclxuaW1wb3J0IHsgam9pbiB9IGZyb20gJ3BhdGgnO1xyXG5cclxuaW1wb3J0IHB1cHBldGVlciBmcm9tICdwdXBwZXRlZXInO1xyXG5cclxuaW1wb3J0IHsgZ2V0Q2FjaGVQYXRoIH0gZnJvbSAnLi9jYWNoZS5qcyc7XHJcbmltcG9ydCB7IGdldE9wdGlvbnMgfSBmcm9tICcuL2NvbmZpZy5qcyc7XHJcbmltcG9ydCB7IHNldHVwSGlnaGNoYXJ0cyB9IGZyb20gJy4vaGlnaGNoYXJ0cy5qcyc7XHJcbmltcG9ydCB7IGxvZywgbG9nV2l0aFN0YWNrIH0gZnJvbSAnLi9sb2dnZXIuanMnO1xyXG5pbXBvcnQgeyBfX2Rpcm5hbWUsIGdldEFic29sdXRlUGF0aCB9IGZyb20gJy4vdXRpbHMuanMnO1xyXG5cclxuaW1wb3J0IEV4cG9ydEVycm9yIGZyb20gJy4vZXJyb3JzL0V4cG9ydEVycm9yLmpzJztcclxuXHJcbi8vIEdldCB0aGUgdGVtcGxhdGUgZm9yIHBhZ2VzXHJcbmNvbnN0IHRlbXBsYXRlID0gcmVhZEZpbGVTeW5jKFxyXG4gIGpvaW4oX19kaXJuYW1lLCAndGVtcGxhdGVzJywgJ3RlbXBsYXRlLmh0bWwnKSxcclxuICAndXRmOCdcclxuKTtcclxuXHJcbi8vIFRvIHNhdmUgdGhlIGJyb3dzZXJcclxubGV0IGJyb3dzZXIgPSBudWxsO1xyXG5cclxuLyoqXHJcbiAqIFJldHJpZXZlcyB0aGUgZXhpc3RpbmcgUHVwcGV0ZWVyIGJyb3dzZXIgaW5zdGFuY2UuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBnZXRCcm93c2VyXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtPYmplY3R9IFRoZSBQdXBwZXRlZXIgYnJvd3NlciBpbnN0YW5jZS5cclxuICpcclxuICogQHRocm93cyB7RXhwb3J0RXJyb3J9IFRocm93cyBhbiBgRXhwb3J0RXJyb3JgIGlmIG5vIHZhbGlkIGJyb3dzZXJcclxuICogaGFzIGJlZW4gY3JlYXRlZC5cclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiBnZXRCcm93c2VyKCkge1xyXG4gIGlmICghYnJvd3Nlcikge1xyXG4gICAgdGhyb3cgbmV3IEV4cG9ydEVycm9yKCdbYnJvd3Nlcl0gTm8gdmFsaWQgYnJvd3NlciBoYXMgYmVlbiBjcmVhdGVkLicsIDUwMCk7XHJcbiAgfVxyXG4gIHJldHVybiBicm93c2VyO1xyXG59XHJcblxyXG4vKipcclxuICogQ3JlYXRlcyBhIFB1cHBldGVlciBicm93c2VyIGluc3RhbmNlIHdpdGggdGhlIHNwZWNpZmllZCBhcmd1bWVudHMuXHJcbiAqXHJcbiAqIEBhc3luY1xyXG4gKiBAZnVuY3Rpb24gY3JlYXRlQnJvd3NlclxyXG4gKlxyXG4gKiBAcGFyYW0ge0FycmF5LjxzdHJpbmc+fSBwdXBwZXRlZXJBcmdzIC0gQWRkaXRpb25hbCBhcmd1bWVudHMgZm9yIFB1cHBldGVlclxyXG4gKiBsYXVuY2guXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtQcm9taXNlPE9iamVjdD59IEEgUHJvbWlzZSB0aGF0IHJlc29sdmVzIHRvIHRoZSBjcmVhdGVkIFB1cHBldGVlclxyXG4gKiBicm93c2VyIGluc3RhbmNlLlxyXG4gKlxyXG4gKiBAdGhyb3dzIHtFeHBvcnRFcnJvcn0gVGhyb3dzIGFuIGBFeHBvcnRFcnJvcmAgaWYgbWF4IHJldHJpZXMgdG8gb3BlblxyXG4gKiBhIGJyb3dzZXIgaW5zdGFuY2UgYXJlIHJlYWNoZWQsIG9yIGlmIG5vIGJyb3dzZXIgaW5zdGFuY2UgaXMgZm91bmQgYWZ0ZXJcclxuICogcmV0cmllcy5cclxuICovXHJcbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBjcmVhdGVCcm93c2VyKHB1cHBldGVlckFyZ3MpIHtcclxuICAvLyBHZXQgYGRlYnVnYCBhbmQgYG90aGVyYCBvcHRpb25zXHJcbiAgY29uc3QgeyBkZWJ1Zywgb3RoZXIgfSA9IGdldE9wdGlvbnMoKTtcclxuXHJcbiAgLy8gR2V0IHRoZSBgZGVidWdgIG9wdGlvbnNcclxuICBjb25zdCB7IGVuYWJsZTogZW5hYmxlZERlYnVnLCAuLi5kZWJ1Z09wdGlvbnMgfSA9IGRlYnVnO1xyXG5cclxuICAvLyBMYXVuY2ggb3B0aW9ucyBmb3IgdGhlIGJyb3dzZXIgaW5zdGFuY2VcclxuICBjb25zdCBsYXVuY2hPcHRpb25zID0ge1xyXG4gICAgaGVhZGxlc3M6IG90aGVyLmJyb3dzZXJTaGVsbE1vZGUgPyAnc2hlbGwnIDogdHJ1ZSxcclxuICAgIHVzZXJEYXRhRGlyOiAndG1wJyxcclxuICAgIGFyZ3M6IHB1cHBldGVlckFyZ3MgfHwgW10sXHJcbiAgICBoYW5kbGVTSUdJTlQ6IGZhbHNlLFxyXG4gICAgaGFuZGxlU0lHVEVSTTogZmFsc2UsXHJcbiAgICBoYW5kbGVTSUdIVVA6IGZhbHNlLFxyXG4gICAgd2FpdEZvckluaXRpYWxQYWdlOiBmYWxzZSxcclxuICAgIGRlZmF1bHRWaWV3cG9ydDogbnVsbCxcclxuICAgIC4uLihlbmFibGVkRGVidWcgJiYgZGVidWdPcHRpb25zKVxyXG4gIH07XHJcblxyXG4gIC8vIENyZWF0ZSBhIGJyb3dzZXJcclxuICBpZiAoIWJyb3dzZXIpIHtcclxuICAgIC8vIEEgY291bnRlciBmb3IgdGhlIGJyb3dzZXIncyBsYXVuY2ggcmV0cmllc1xyXG4gICAgbGV0IHRyeUNvdW50ID0gMDtcclxuXHJcbiAgICBjb25zdCBvcGVuID0gYXN5bmMgKCkgPT4ge1xyXG4gICAgICB0cnkge1xyXG4gICAgICAgIGxvZyhcclxuICAgICAgICAgIDMsXHJcbiAgICAgICAgICBgW2Jyb3dzZXJdIEF0dGVtcHRpbmcgdG8gZ2V0IGEgYnJvd3NlciBpbnN0YW5jZSAodHJ5ICR7Kyt0cnlDb3VudH0pLmBcclxuICAgICAgICApO1xyXG5cclxuICAgICAgICAvLyBMYXVuY2ggdGhlIGJyb3dzZXJcclxuICAgICAgICBicm93c2VyID0gYXdhaXQgcHVwcGV0ZWVyLmxhdW5jaChsYXVuY2hPcHRpb25zKTtcclxuICAgICAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICAgICBsb2dXaXRoU3RhY2soXHJcbiAgICAgICAgICAxLFxyXG4gICAgICAgICAgZXJyb3IsXHJcbiAgICAgICAgICAnW2Jyb3dzZXJdIEZhaWxlZCB0byBsYXVuY2ggYSBicm93c2VyIGluc3RhbmNlLidcclxuICAgICAgICApO1xyXG5cclxuICAgICAgICAvLyBSZXRyeSB0byBsYXVuY2ggYnJvd3NlciB1bnRpbCByZWFjaGluZyBtYXggYXR0ZW1wdHNcclxuICAgICAgICBpZiAodHJ5Q291bnQgPCAyNSkge1xyXG4gICAgICAgICAgbG9nKDMsIGBbYnJvd3Nlcl0gUmV0cnkgdG8gb3BlbiBhIGJyb3dzZXIgKCR7dHJ5Q291bnR9IG91dCBvZiAyNSkuYCk7XHJcblxyXG4gICAgICAgICAgLy8gV2FpdCBmb3IgYSA0IHNlY29uZHMgYmVmb3JlIHRyeWluZyBhZ2FpblxyXG4gICAgICAgICAgYXdhaXQgbmV3IFByb21pc2UoKHJlc3BvbnNlKSA9PiBzZXRUaW1lb3V0KHJlc3BvbnNlLCA0MDAwKSk7XHJcbiAgICAgICAgICBhd2FpdCBvcGVuKCk7XHJcbiAgICAgICAgfSBlbHNlIHtcclxuICAgICAgICAgIHRocm93IGVycm9yO1xyXG4gICAgICAgIH1cclxuICAgICAgfVxyXG4gICAgfTtcclxuXHJcbiAgICB0cnkge1xyXG4gICAgICBhd2FpdCBvcGVuKCk7XHJcblxyXG4gICAgICAvLyBTaGVsbCBtb2RlIGluZm9ybVxyXG4gICAgICBpZiAobGF1bmNoT3B0aW9ucy5oZWFkbGVzcyA9PT0gJ3NoZWxsJykge1xyXG4gICAgICAgIGxvZygzLCBgW2Jyb3dzZXJdIExhdW5jaGVkIGJyb3dzZXIgaW4gc2hlbGwgbW9kZS5gKTtcclxuICAgICAgfVxyXG5cclxuICAgICAgLy8gRGVidWcgbW9kZSBpbmZvcm1cclxuICAgICAgaWYgKGVuYWJsZWREZWJ1Zykge1xyXG4gICAgICAgIGxvZygzLCBgW2Jyb3dzZXJdIExhdW5jaGVkIGJyb3dzZXIgaW4gZGVidWcgbW9kZS5gKTtcclxuICAgICAgfVxyXG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICAgdGhyb3cgbmV3IEV4cG9ydEVycm9yKFxyXG4gICAgICAgICdbYnJvd3Nlcl0gTWF4aW11bSByZXRyaWVzIHRvIG9wZW4gYSBicm93c2VyIGluc3RhbmNlIHJlYWNoZWQuJyxcclxuICAgICAgICA1MDBcclxuICAgICAgKS5zZXRFcnJvcihlcnJvcik7XHJcbiAgICB9XHJcblxyXG4gICAgaWYgKCFicm93c2VyKSB7XHJcbiAgICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcignW2Jyb3dzZXJdIENhbm5vdCBmaW5kIGEgYnJvd3NlciB0byBvcGVuLicsIDUwMCk7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICAvLyBSZXR1cm4gYSBicm93c2VyIGluc3RhbmNlXHJcbiAgcmV0dXJuIGJyb3dzZXI7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBDbG9zZXMgdGhlIFB1cHBldGVlciBicm93c2VyIGluc3RhbmNlIGlmIGl0IGlzIGNvbm5lY3RlZC5cclxuICpcclxuICogQGFzeW5jXHJcbiAqIEBmdW5jdGlvbiBjbG9zZUJyb3dzZXJcclxuICovXHJcbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBjbG9zZUJyb3dzZXIoKSB7XHJcbiAgLy8gQ2xvc2UgdGhlIGJyb3dzZXIgd2hlbiBjb25uZWN0ZWRcclxuICBpZiAoYnJvd3NlciAmJiBicm93c2VyLmNvbm5lY3RlZCkge1xyXG4gICAgYXdhaXQgYnJvd3Nlci5jbG9zZSgpO1xyXG4gIH1cclxuICBicm93c2VyID0gbnVsbDtcclxuICBsb2coNCwgJ1ticm93c2VyXSBDbG9zZWQgdGhlIGJyb3dzZXIuJyk7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBDcmVhdGVzIGEgbmV3IFB1cHBldGVlciBwYWdlIHdpdGhpbiBhbiBleGlzdGluZyBicm93c2VyIGluc3RhbmNlLlxyXG4gKiBUaGUgZnVuY3Rpb24gY3JlYXRlcyBhIG5ldyBwYWdlLCBkaXNhYmxlcyBjYWNoaW5nLCBzZXRzIGNvbnRlbnQgdXNpbmdcclxuICogdGhlIGBfc2V0UGFnZUNvbnRlbnQoKWAsIGFuZCByZXR1cm5zIHRoZSBjcmVhdGVkIFB1cHBldGVlciBwYWdlLlxyXG4gKlxyXG4gKiBAYXN5bmNcclxuICogQGZ1bmN0aW9uIG5ld1BhZ2VcclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IHBvb2xSZXNvdXJjZSAtIFRoZSBwb29sIHJlc291cmNlIHRoYXQgY29udGFpbnMgYGlkYCxcclxuICogYHdvcmtDb3VudGAsIGFuZCBgcGFnZWAuXHJcbiAqXHJcbiAqIEB0aHJvd3Mge0V4cG9ydEVycm9yfSBUaHJvd3MgYW4gYEV4cG9ydEVycm9yYCBpZiBubyB2YWxpZCBicm93c2VyXHJcbiAqIGhhcyBiZWVuIGNvbm5lY3RlZCBvciBpZiBhIHBhZ2UgaXMgaW52YWxpZCBvciBjbG9zZWQuXHJcbiAqL1xyXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gbmV3UGFnZShwb29sUmVzb3VyY2UpIHtcclxuICAvLyBFcnJvciBpbiBjYXNlIG9mIG5vIGNvbm5lY3RlZCBicm93c2VyXHJcbiAgaWYgKCFicm93c2VyIHx8ICFicm93c2VyLmNvbm5lY3RlZCkge1xyXG4gICAgdGhyb3cgbmV3IEV4cG9ydEVycm9yKGBbYnJvd3Nlcl0gQnJvd3NlciBpcyBub3QgeWV0IGNvbm5lY3RlZC5gLCA1MDApO1xyXG4gIH1cclxuXHJcbiAgLy8gQ3JlYXRlIGEgcGFnZVxyXG4gIHBvb2xSZXNvdXJjZS5wYWdlID0gYXdhaXQgYnJvd3Nlci5uZXdQYWdlKCk7XHJcblxyXG4gIC8vIERpc2FibGUgY2FjaGVcclxuICBhd2FpdCBwb29sUmVzb3VyY2UucGFnZS5zZXRDYWNoZUVuYWJsZWQoZmFsc2UpO1xyXG5cclxuICAvLyBTZXQgdGhlIGNvbnRlbnRcclxuICBhd2FpdCBfc2V0UGFnZUNvbnRlbnQocG9vbFJlc291cmNlLnBhZ2UpO1xyXG5cclxuICAvLyBTZXQgcGFnZSBldmVudHNcclxuICBfc2V0UGFnZUV2ZW50cyhwb29sUmVzb3VyY2UucGFnZSk7XHJcblxyXG4gIC8vIENoZWNrIGlmIHRoZSBwYWdlIGlzIGNvcnJlY3RseSBjcmVhdGVkXHJcbiAgaWYgKCFwb29sUmVzb3VyY2UucGFnZSB8fCBwb29sUmVzb3VyY2UucGFnZS5pc0Nsb3NlZCgpKSB7XHJcbiAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoJ1ticm93c2VyXSBUaGUgcGFnZSBpcyBpbnZhbGlkIG9yIGNsb3NlZC4nLCA0MDApO1xyXG4gIH1cclxufVxyXG5cclxuLyoqXHJcbiAqIENsZWFycyB0aGUgY29udGVudCBvZiBhIFB1cHBldGVlciBQYWdlIGJhc2VkIG9uIHRoZSBzcGVjaWZpZWQgbW9kZS4gTG9nc1xyXG4gKiB0aHJvd24gZXJyb3IgaWYgY2xlYXJpbmcgb2YgYSBwYWdlJ3MgY29udGVudCBmYWlscy5cclxuICpcclxuICogQGFzeW5jXHJcbiAqIEBmdW5jdGlvbiBjbGVhclBhZ2VcclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IHBvb2xSZXNvdXJjZSAtIFRoZSBwb29sIHJlc291cmNlIHRoYXQgY29udGFpbnMgcGFnZSBhbmQgaWQuXHJcbiAqIEBwYXJhbSB7Ym9vbGVhbn0gW2hhcmRSZXNldD1mYWxzZV0gLSBBIGZsYWcgaW5kaWNhdGluZyB0aGUgdHlwZSBvZiBjbGVhcmluZ1xyXG4gKiB0byBiZSBwZXJmb3JtZWQuIElmIHRydWUsIG5hdmlnYXRlcyB0byBgYWJvdXQ6YmxhbmtgIGFuZCByZXNldHMgY29udGVudFxyXG4gKiBhbmQgc2NyaXB0cy4gSWYgZmFsc2UsIGNsZWFycyB0aGUgYm9keSBjb250ZW50IGJ5IHNldHRpbmcgYSBwcmVkZWZpbmVkIEhUTUxcclxuICogc3RydWN0dXJlLiBUaGUgZGVmYXVsdCB2YWx1ZSBpcyBgZmFsc2VgLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7UHJvbWlzZTxib29sZWFuPn0gQSBQcm9taXNlIHRoYXQgcmVzb2x2ZXMgdG8gdHJ1ZSB3aGVuIHBhZ2VcclxuICogaXMgY29ycmVjdGx5IGNsZWFyZWQgYW5kIGZhbHNlIHdoZW4gaXQgaXMgbm90LlxyXG4gKi9cclxuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIGNsZWFyUGFnZShwb29sUmVzb3VyY2UsIGhhcmRSZXNldCA9IGZhbHNlKSB7XHJcbiAgdHJ5IHtcclxuICAgIGlmIChwb29sUmVzb3VyY2UucGFnZSAmJiAhcG9vbFJlc291cmNlLnBhZ2UuaXNDbG9zZWQoKSkge1xyXG4gICAgICBpZiAoaGFyZFJlc2V0KSB7XHJcbiAgICAgICAgLy8gTmF2aWdhdGUgdG8gYGFib3V0OmJsYW5rYFxyXG4gICAgICAgIGF3YWl0IHBvb2xSZXNvdXJjZS5wYWdlLmdvdG8oJ2Fib3V0OmJsYW5rJywge1xyXG4gICAgICAgICAgd2FpdFVudGlsOiAnZG9tY29udGVudGxvYWRlZCdcclxuICAgICAgICB9KTtcclxuXHJcbiAgICAgICAgLy8gU2V0IHRoZSBjb250ZW50IGFuZCBhbmQgc2NyaXB0cyBhZ2FpblxyXG4gICAgICAgIGF3YWl0IF9zZXRQYWdlQ29udGVudChwb29sUmVzb3VyY2UucGFnZSk7XHJcbiAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgLy8gQ2xlYXIgYm9keSBjb250ZW50XHJcbiAgICAgICAgYXdhaXQgcG9vbFJlc291cmNlLnBhZ2UuZXZhbHVhdGUoKCkgPT4ge1xyXG4gICAgICAgICAgZG9jdW1lbnQuYm9keS5pbm5lckhUTUwgPVxyXG4gICAgICAgICAgICAnPGRpdiBpZD1cImNoYXJ0LWNvbnRhaW5lclwiPjxkaXYgaWQ9XCJjb250YWluZXJcIj48L2Rpdj48L2Rpdj4nO1xyXG4gICAgICAgIH0pO1xyXG4gICAgICB9XHJcbiAgICAgIHJldHVybiB0cnVlO1xyXG4gICAgfVxyXG4gIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICBsb2dXaXRoU3RhY2soXHJcbiAgICAgIDIsXHJcbiAgICAgIGVycm9yLFxyXG4gICAgICBgW3Bvb2xdIFBvb2wgcmVzb3VyY2UgWyR7cG9vbFJlc291cmNlLmlkfV0gLSBDb250ZW50IG9mIHRoZSBwYWdlIGNvdWxkIG5vdCBiZSBjbGVhcmVkLmBcclxuICAgICk7XHJcblxyXG4gICAgLy8gU2V0IHRoZSBgd29ya0xpbWl0YCB0byBleGNlZWRlZCBpbiBvcmRlciB0byByZWNyZWF0ZSB0aGUgcmVzb3VyY2VcclxuICAgIHBvb2xSZXNvdXJjZS53b3JrQ291bnQgPSBnZXRPcHRpb25zKCkucG9vbC53b3JrTGltaXQgKyAxO1xyXG4gIH1cclxuICByZXR1cm4gZmFsc2U7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBBZGRzIGN1c3RvbSBKUyBhbmQgQ1NTIHJlc291cmNlcyB0byBhIFB1cHBldGVlciBQYWdlIGJhc2VkIG9uIHRoZSBzcGVjaWZpZWRcclxuICogb3B0aW9ucy5cclxuICpcclxuICogQGFzeW5jXHJcbiAqIEBmdW5jdGlvbiBhZGRQYWdlUmVzb3VyY2VzXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBwYWdlIC0gVGhlIFB1cHBldGVlciBwYWdlIG9iamVjdCB0byB3aGljaCByZXNvdXJjZXMgd2lsbFxyXG4gKiBiZSBhZGRlZC5cclxuICogQHBhcmFtIHtPYmplY3R9IGN1c3RvbUxvZ2ljT3B0aW9ucyAtIFRoZSBjb25maWd1cmF0aW9uIG9iamVjdCBjb250YWluaW5nXHJcbiAqIGBjdXN0b21Mb2dpY2Agb3B0aW9ucy5cclxuICpcclxuICogQHJldHVybnMge1Byb21pc2U8QXJyYXkuPE9iamVjdD4+fSBBIFByb21pc2UgdGhhdCByZXNvbHZlcyB0byBhbiBhcnJheVxyXG4gKiBvZiBpbmplY3RlZCByZXNvdXJjZXMuXHJcbiAqL1xyXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gYWRkUGFnZVJlc291cmNlcyhwYWdlLCBjdXN0b21Mb2dpY09wdGlvbnMpIHtcclxuICAvLyBJbmplY3RlZCByZXNvdXJjZXMgYXJyYXlcclxuICBjb25zdCBpbmplY3RlZFJlc291cmNlcyA9IFtdO1xyXG5cclxuICAvLyBVc2UgcmVzb3VyY2VzXHJcbiAgY29uc3QgcmVzb3VyY2VzID0gY3VzdG9tTG9naWNPcHRpb25zLnJlc291cmNlcztcclxuICBpZiAocmVzb3VyY2VzKSB7XHJcbiAgICBjb25zdCBpbmplY3RlZEpzID0gW107XHJcblxyXG4gICAgLy8gTG9hZCBjdXN0b20gSlMgY29kZVxyXG4gICAgaWYgKHJlc291cmNlcy5qcykge1xyXG4gICAgICBpbmplY3RlZEpzLnB1c2goe1xyXG4gICAgICAgIGNvbnRlbnQ6IHJlc291cmNlcy5qc1xyXG4gICAgICB9KTtcclxuICAgIH1cclxuXHJcbiAgICAvLyBMb2FkIHNjcmlwdHMgZnJvbSBhbGwgY3VzdG9tIGZpbGVzXHJcbiAgICBpZiAocmVzb3VyY2VzLmZpbGVzKSB7XHJcbiAgICAgIGZvciAoY29uc3QgZmlsZSBvZiByZXNvdXJjZXMuZmlsZXMpIHtcclxuICAgICAgICBjb25zdCBpc0xvY2FsID0gIWZpbGUuc3RhcnRzV2l0aCgnaHR0cCcpID8gdHJ1ZSA6IGZhbHNlO1xyXG5cclxuICAgICAgICAvLyBBZGQgZWFjaCBjdXN0b20gc2NyaXB0IGZyb20gcmVzb3VyY2VzJyBmaWxlc1xyXG4gICAgICAgIGluamVjdGVkSnMucHVzaChcclxuICAgICAgICAgIGlzTG9jYWxcclxuICAgICAgICAgICAgPyB7XHJcbiAgICAgICAgICAgICAgICBjb250ZW50OiByZWFkRmlsZVN5bmMoZ2V0QWJzb2x1dGVQYXRoKGZpbGUpLCAndXRmOCcpXHJcbiAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICA6IHtcclxuICAgICAgICAgICAgICAgIHVybDogZmlsZVxyXG4gICAgICAgICAgICAgIH1cclxuICAgICAgICApO1xyXG4gICAgICB9XHJcbiAgICB9XHJcblxyXG4gICAgZm9yIChjb25zdCBqc1Jlc291cmNlIG9mIGluamVjdGVkSnMpIHtcclxuICAgICAgdHJ5IHtcclxuICAgICAgICBpbmplY3RlZFJlc291cmNlcy5wdXNoKGF3YWl0IHBhZ2UuYWRkU2NyaXB0VGFnKGpzUmVzb3VyY2UpKTtcclxuICAgICAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICAgICBsb2dXaXRoU3RhY2soMiwgZXJyb3IsIGBbYnJvd3Nlcl0gVGhlIEpTIHJlc291cmNlIGNhbm5vdCBiZSBsb2FkZWQuYCk7XHJcbiAgICAgIH1cclxuICAgIH1cclxuICAgIGluamVjdGVkSnMubGVuZ3RoID0gMDtcclxuXHJcbiAgICAvLyBMb2FkIENTU1xyXG4gICAgY29uc3QgaW5qZWN0ZWRDc3MgPSBbXTtcclxuICAgIGlmIChyZXNvdXJjZXMuY3NzKSB7XHJcbiAgICAgIGxldCBjc3NJbXBvcnRzID0gcmVzb3VyY2VzLmNzcy5tYXRjaCgvQGltcG9ydFxccyooW147XSopOy9nKTtcclxuICAgICAgaWYgKGNzc0ltcG9ydHMpIHtcclxuICAgICAgICAvLyBIYW5kbGUgY3NzIHNlY3Rpb25cclxuICAgICAgICBmb3IgKGxldCBjc3NJbXBvcnRQYXRoIG9mIGNzc0ltcG9ydHMpIHtcclxuICAgICAgICAgIGlmIChjc3NJbXBvcnRQYXRoKSB7XHJcbiAgICAgICAgICAgIGNzc0ltcG9ydFBhdGggPSBjc3NJbXBvcnRQYXRoXHJcbiAgICAgICAgICAgICAgLnJlcGxhY2UoJ3VybCgnLCAnJylcclxuICAgICAgICAgICAgICAucmVwbGFjZSgnQGltcG9ydCcsICcnKVxyXG4gICAgICAgICAgICAgIC5yZXBsYWNlKC9cIi9nLCAnJylcclxuICAgICAgICAgICAgICAucmVwbGFjZSgvJy9nLCAnJylcclxuICAgICAgICAgICAgICAucmVwbGFjZSgvOy8sICcnKVxyXG4gICAgICAgICAgICAgIC5yZXBsYWNlKC9cXCkvZywgJycpXHJcbiAgICAgICAgICAgICAgLnRyaW0oKTtcclxuXHJcbiAgICAgICAgICAgIC8vIEFkZCBlYWNoIGN1c3RvbSBjc3MgZnJvbSByZXNvdXJjZXNcclxuICAgICAgICAgICAgaWYgKGNzc0ltcG9ydFBhdGguc3RhcnRzV2l0aCgnaHR0cCcpKSB7XHJcbiAgICAgICAgICAgICAgaW5qZWN0ZWRDc3MucHVzaCh7XHJcbiAgICAgICAgICAgICAgICB1cmw6IGNzc0ltcG9ydFBhdGhcclxuICAgICAgICAgICAgICB9KTtcclxuICAgICAgICAgICAgfSBlbHNlIGlmIChjdXN0b21Mb2dpY09wdGlvbnMuYWxsb3dGaWxlUmVzb3VyY2VzKSB7XHJcbiAgICAgICAgICAgICAgaW5qZWN0ZWRDc3MucHVzaCh7XHJcbiAgICAgICAgICAgICAgICBwYXRoOiBqb2luKF9fZGlybmFtZSwgY3NzSW1wb3J0UGF0aClcclxuICAgICAgICAgICAgICB9KTtcclxuICAgICAgICAgICAgfVxyXG4gICAgICAgICAgfVxyXG4gICAgICAgIH1cclxuICAgICAgfVxyXG5cclxuICAgICAgLy8gVGhlIHJlc3Qgb2YgdGhlIENTUyBzZWN0aW9uIHdpbGwgYmUgY29udGVudCBieSBub3dcclxuICAgICAgaW5qZWN0ZWRDc3MucHVzaCh7XHJcbiAgICAgICAgY29udGVudDogcmVzb3VyY2VzLmNzcy5yZXBsYWNlKC9AaW1wb3J0XFxzKihbXjtdKik7L2csICcnKSB8fCAnICdcclxuICAgICAgfSk7XHJcblxyXG4gICAgICBmb3IgKGNvbnN0IGNzc1Jlc291cmNlIG9mIGluamVjdGVkQ3NzKSB7XHJcbiAgICAgICAgdHJ5IHtcclxuICAgICAgICAgIGluamVjdGVkUmVzb3VyY2VzLnB1c2goYXdhaXQgcGFnZS5hZGRTdHlsZVRhZyhjc3NSZXNvdXJjZSkpO1xyXG4gICAgICAgIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICAgICAgICBsb2dXaXRoU3RhY2soXHJcbiAgICAgICAgICAgIDIsXHJcbiAgICAgICAgICAgIGVycm9yLFxyXG4gICAgICAgICAgICBgW2Jyb3dzZXJdIFRoZSBDU1MgcmVzb3VyY2UgY2Fubm90IGJlIGxvYWRlZC5gXHJcbiAgICAgICAgICApO1xyXG4gICAgICAgIH1cclxuICAgICAgfVxyXG4gICAgICBpbmplY3RlZENzcy5sZW5ndGggPSAwO1xyXG4gICAgfVxyXG4gIH1cclxuICByZXR1cm4gaW5qZWN0ZWRSZXNvdXJjZXM7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBDbGVhcnMgb3V0IGFsbCBzdGF0ZSBzZXQgb24gdGhlIHBhZ2Ugd2l0aCBgYWRkU2NyaXB0VGFnYCBhbmQgYGFkZFN0eWxlVGFnYC5cclxuICogUmVtb3ZlcyBpbmplY3RlZCByZXNvdXJjZXMgYW5kIHJlc2V0cyBDU1MgYW5kIHNjcmlwdCB0YWdzIG9uIHRoZSBwYWdlLlxyXG4gKiBBZGRpdGlvbmFsbHksIGl0IGRlc3Ryb3lzIHByZXZpb3VzbHkgZXhpc3RpbmcgY2hhcnRzLlxyXG4gKlxyXG4gKiBAYXN5bmNcclxuICogQGZ1bmN0aW9uIGNsZWFyUGFnZVJlc291cmNlc1xyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gcGFnZSAtIFRoZSBQdXBwZXRlZXIgcGFnZSBvYmplY3QgZnJvbSB3aGljaCByZXNvdXJjZXMgd2lsbFxyXG4gKiBiZSBjbGVhcmVkLlxyXG4gKiBAcGFyYW0ge0FycmF5LjxPYmplY3Q+fSBpbmplY3RlZFJlc291cmNlcyAtIEFycmF5IG9mIGluamVjdGVkIHJlc291cmNlc1xyXG4gKiB0byBiZSBjbGVhcmVkLlxyXG4gKi9cclxuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIGNsZWFyUGFnZVJlc291cmNlcyhwYWdlLCBpbmplY3RlZFJlc291cmNlcykge1xyXG4gIHRyeSB7XHJcbiAgICBmb3IgKGNvbnN0IHJlc291cmNlIG9mIGluamVjdGVkUmVzb3VyY2VzKSB7XHJcbiAgICAgIGF3YWl0IHJlc291cmNlLmRpc3Bvc2UoKTtcclxuICAgIH1cclxuXHJcbiAgICAvLyBEZXN0cm95IG9sZCBjaGFydHMgYWZ0ZXIgZXhwb3J0IGlzIGRvbmUgYW5kIHJlc2V0IGFsbCBDU1MgYW5kIHNjcmlwdCB0YWdzXHJcbiAgICBhd2FpdCBwYWdlLmV2YWx1YXRlKCgpID0+IHtcclxuICAgICAgLy8gV2UgYXJlIG5vdCBndWFyYW50ZWVkIHRoYXQgSGlnaGNoYXJ0cyBpcyBsb2FkZWQsIHdoZW4gZG9pbmcgU1ZHIGV4cG9ydHNcclxuICAgICAgaWYgKHR5cGVvZiBIaWdoY2hhcnRzICE9PSAndW5kZWZpbmVkJykge1xyXG4gICAgICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBuby11bmRlZlxyXG4gICAgICAgIGNvbnN0IG9sZENoYXJ0cyA9IEhpZ2hjaGFydHMuY2hhcnRzO1xyXG5cclxuICAgICAgICAvLyBDaGVjayBpbiBhbnkgYWxyZWFkeSBleGlzdGluZyBjaGFydHNcclxuICAgICAgICBpZiAoQXJyYXkuaXNBcnJheShvbGRDaGFydHMpICYmIG9sZENoYXJ0cy5sZW5ndGgpIHtcclxuICAgICAgICAgIC8vIERlc3Ryb3kgb2xkIGNoYXJ0c1xyXG4gICAgICAgICAgZm9yIChjb25zdCBvbGRDaGFydCBvZiBvbGRDaGFydHMpIHtcclxuICAgICAgICAgICAgb2xkQ2hhcnQgJiYgb2xkQ2hhcnQuZGVzdHJveSgpO1xyXG4gICAgICAgICAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgbm8tdW5kZWZcclxuICAgICAgICAgICAgSGlnaGNoYXJ0cy5jaGFydHMuc2hpZnQoKTtcclxuICAgICAgICAgIH1cclxuICAgICAgICB9XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBuby11bmRlZlxyXG4gICAgICBjb25zdCBbLi4uc2NyaXB0c1RvUmVtb3ZlXSA9IGRvY3VtZW50LmdldEVsZW1lbnRzQnlUYWdOYW1lKCdzY3JpcHQnKTtcclxuICAgICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIG5vLXVuZGVmXHJcbiAgICAgIGNvbnN0IFssIC4uLnN0eWxlc1RvUmVtb3ZlXSA9IGRvY3VtZW50LmdldEVsZW1lbnRzQnlUYWdOYW1lKCdzdHlsZScpO1xyXG4gICAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgbm8tdW5kZWZcclxuICAgICAgY29uc3QgWy4uLmxpbmtzVG9SZW1vdmVdID0gZG9jdW1lbnQuZ2V0RWxlbWVudHNCeVRhZ05hbWUoJ2xpbmsnKTtcclxuXHJcbiAgICAgIC8vIFJlbW92ZSB0YWdzXHJcbiAgICAgIGZvciAoY29uc3QgZWxlbWVudCBvZiBbXHJcbiAgICAgICAgLi4uc2NyaXB0c1RvUmVtb3ZlLFxyXG4gICAgICAgIC4uLnN0eWxlc1RvUmVtb3ZlLFxyXG4gICAgICAgIC4uLmxpbmtzVG9SZW1vdmVcclxuICAgICAgXSkge1xyXG4gICAgICAgIGVsZW1lbnQucmVtb3ZlKCk7XHJcbiAgICAgIH1cclxuICAgIH0pO1xyXG4gIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICBsb2dXaXRoU3RhY2soMiwgZXJyb3IsIGBbYnJvd3Nlcl0gQ291bGQgbm90IGNsZWFyIHBhZ2UncyByZXNvdXJjZXMuYCk7XHJcbiAgfVxyXG59XHJcblxyXG4vKipcclxuICogU2V0cyB0aGUgY29udGVudCBmb3IgYSBQdXBwZXRlZXIgUGFnZSB1c2luZyBhIHByZWRlZmluZWQgdGVtcGxhdGVcclxuICogYW5kIGFkZGl0aW9uYWwgc2NyaXB0cy5cclxuICpcclxuICogQGFzeW5jXHJcbiAqIEBmdW5jdGlvbiBfc2V0UGFnZUNvbnRlbnRcclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IHBhZ2UgLSBUaGUgUHVwcGV0ZWVyIHBhZ2Ugb2JqZWN0IHRvIHdoaWNoIHRoZSBjb250ZW50XHJcbiAqIGlzIGJlaW5nIHNldC5cclxuICovXHJcbmFzeW5jIGZ1bmN0aW9uIF9zZXRQYWdlQ29udGVudChwYWdlKSB7XHJcbiAgLy8gU2V0IHRoZSBpbml0aWFsIHBhZ2UgY29udGVudFxyXG4gIGF3YWl0IHBhZ2Uuc2V0Q29udGVudCh0ZW1wbGF0ZSwgeyB3YWl0VW50aWw6ICdkb21jb250ZW50bG9hZGVkJyB9KTtcclxuXHJcbiAgLy8gQWRkIGFsbCByZWdpc3RlcmVkIEhpZ2NoYXJ0cyBzY3JpcHRzLCBxdWl0ZSBkZW1hbmRpbmdcclxuICBhd2FpdCBwYWdlLmFkZFNjcmlwdFRhZyh7IHBhdGg6IGpvaW4oZ2V0Q2FjaGVQYXRoKCksICdzb3VyY2VzLmpzJykgfSk7XHJcblxyXG4gIC8vIFNldCB0aGUgaW5pdGlhbCBgYW5pbU9iamVjdGAgZm9yIEhpZ2hjaGFydHNcclxuICBhd2FpdCBwYWdlLmV2YWx1YXRlKHNldHVwSGlnaGNoYXJ0cyk7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBTZXQgZXZlbnRzIChsaWtlIGBwYWdlZXJyb3JgIGFuZCBgY29uc29sZWApIGZvciBhIFB1cHBldGVlciBQYWdlIGluIG9yZGVyXHJcbiAqIHRvIGNhdGNoIGFuZCBkaXNwbGF5IGVycm9ycyBhbmQgY29uc29sZSBsb2dzIGZyb20gdGhlIHdpbmRvdyBjb250ZXh0LlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gX3NldFBhZ2VFdmVudHNcclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IHBhZ2UgLSBUaGUgUHVwcGV0ZWVyIHBhZ2Ugb2JqZWN0IHRvIHdoaWNoIHRoZSBsaXN0ZW5lcnNcclxuICogYXJlIGJlaW5nIHNldC5cclxuICovXHJcbmZ1bmN0aW9uIF9zZXRQYWdlRXZlbnRzKHBhZ2UpIHtcclxuICAvLyBHZXQgYGRlYnVnYCBvcHRpb25zXHJcbiAgY29uc3QgeyBkZWJ1ZyB9ID0gZ2V0T3B0aW9ucygpO1xyXG5cclxuICAvLyBTZXQgdGhlIGBwYWdlZXJyb3JgIGxpc3RlbmVyXHJcbiAgcGFnZS5vbigncGFnZWVycm9yJywgYXN5bmMgKCkgPT4ge1xyXG4gICAgLy8gSXQgd291bGQgc2VlbSBsaWtlIHRoaXMgbWF5IGZpcmUgYXQgdGhlIHNhbWUgdGltZSBvciBzaG9ydGx5IGJlZm9yZVxyXG4gICAgLy8gYSBwYWdlIGlzIGNsb3NlZC5cclxuICAgIGlmIChwYWdlLmlzQ2xvc2VkKCkpIHtcclxuICAgICAgcmV0dXJuO1xyXG4gICAgfVxyXG4gIH0pO1xyXG5cclxuICAvLyBTZXQgdGhlIGBjb25zb2xlYCBsaXN0ZW5lciwgaWYgbmVlZGVkXHJcbiAgaWYgKGRlYnVnLmVuYWJsZSAmJiBkZWJ1Zy5saXN0ZW5Ub0NvbnNvbGUpIHtcclxuICAgIHBhZ2Uub24oJ2NvbnNvbGUnLCAobWVzc2FnZSkgPT4ge1xyXG4gICAgICBjb25zb2xlLmxvZyhgW2RlYnVnXSAke21lc3NhZ2UudGV4dCgpfWApO1xyXG4gICAgfSk7XHJcbiAgfVxyXG59XHJcblxyXG5leHBvcnQgZGVmYXVsdCB7XHJcbiAgZ2V0QnJvd3NlcixcclxuICBjcmVhdGVCcm93c2VyLFxyXG4gIGNsb3NlQnJvd3NlcixcclxuICBuZXdQYWdlLFxyXG4gIGNsZWFyUGFnZSxcclxuICBhZGRQYWdlUmVzb3VyY2VzLFxyXG4gIGNsZWFyUGFnZVJlc291cmNlc1xyXG59O1xyXG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxyXG5cclxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXHJcblxyXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNSwgSGlnaHNvZnRcclxuXHJcbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cclxuXHJcbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxyXG5cclxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxyXG5cclxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cclxuXHJcbi8qKlxyXG4gKiBUaGUgQ1NTIHRvIGJlIHVzZWQgb24gdGhlIGV4cG9ydGVkIHBhZ2UuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtzdHJpbmd9IFRoZSBDU1MgY29uZmlndXJhdGlvbi5cclxuICovXHJcbmV4cG9ydCBkZWZhdWx0ICgpID0+IGBcclxuXHJcbmh0bWwsIGJvZHkge1xyXG4gIG1hcmdpbjogMDtcclxuICBwYWRkaW5nOiAwO1xyXG4gIGJveC1zaXppbmc6IGJvcmRlci1ib3g7XHJcbn1cclxuXHJcbiN0YWJsZS1kaXYsICNzbGlkZXJzLCAjZGF0YXRhYmxlLCAjY29udHJvbHMsIC5sZC1yb3cge1xyXG4gIGRpc3BsYXk6IG5vbmU7XHJcbiAgaGVpZ2h0OiAwO1xyXG59XHJcblxyXG4jY2hhcnQtY29udGFpbmVyIHtcclxuICBib3gtc2l6aW5nOiBib3JkZXItYm94O1xyXG4gIG1hcmdpbjogMDtcclxuICBvdmVyZmxvdzogYXV0bztcclxuICBmb250LXNpemU6IDA7XHJcbn1cclxuXHJcbiNjaGFydC1jb250YWluZXIgPiBmaWd1cmUsIGRpdiB7XHJcbiAgbWFyZ2luLXRvcDogMCAhaW1wb3J0YW50O1xyXG4gIG1hcmdpbi1ib3R0b206IDAgIWltcG9ydGFudDtcclxufVxyXG5cclxuYDtcclxuIiwiLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcclxuXHJcbkhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlclxyXG5cclxuQ29weXJpZ2h0IChjKSAyMDE2LTIwMjUsIEhpZ2hzb2Z0XHJcblxyXG5MaWNlbmNlZCB1bmRlciB0aGUgTUlUIGxpY2VuY2UuXHJcblxyXG5BZGRpdGlvbmFsbHkgYSB2YWxpZCBIaWdoY2hhcnRzIGxpY2Vuc2UgaXMgcmVxdWlyZWQgZm9yIHVzZS5cclxuXHJcblNlZSBMSUNFTlNFIGZpbGUgaW4gcm9vdCBmb3IgZGV0YWlscy5cclxuXHJcbioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXHJcblxyXG5pbXBvcnQgY3NzVGVtcGxhdGUgZnJvbSAnLi9jc3MuanMnO1xyXG5cclxuLyoqXHJcbiAqIFRoZSBTVkcgdGVtcGxhdGUgdG8gdXNlIHdoZW4gbG9hZGluZyBTVkcgY29udGVudCB0byBiZSBleHBvcnRlZC5cclxuICpcclxuICogQHBhcmFtIHtzdHJpbmd9IHN2ZyAtIFRoZSBTVkcgaW5wdXQgY29udGVudCB0byBiZSBleHBvcnRlZC5cclxuICpcclxuICogQHJldHVybnMge3N0cmluZ30gVGhlIFNWRyB0ZW1wbGF0ZS5cclxuICovXHJcbmV4cG9ydCBkZWZhdWx0IChzdmcpID0+IGBcclxuPCFET0NUWVBFIGh0bWw+XHJcbjxodG1sIGxhbmc9J2VuLVVTJz5cclxuICA8aGVhZD5cclxuICAgIDxtZXRhIGh0dHAtZXF1aXY9XCJDb250ZW50LVR5cGVcIiBjb250ZW50PVwidGV4dC9odG1sOyBjaGFyc2V0PXV0Zi04XCI+XHJcbiAgICA8dGl0bGU+SGlnaGNoYXJ0cyBFeHBvcnQ8L3RpdGxlPlxyXG4gIDwvaGVhZD5cclxuICA8c3R5bGU+XHJcbiAgICAke2Nzc1RlbXBsYXRlKCl9XHJcbiAgPC9zdHlsZT5cclxuICA8Ym9keT5cclxuICAgIDxkaXYgaWQ9XCJjaGFydC1jb250YWluZXJcIj5cclxuICAgICAgJHtzdmd9XHJcbiAgICA8L2Rpdj5cclxuICA8L2JvZHk+XHJcbjwvaHRtbD5cclxuXHJcbmA7XHJcbiIsIi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXHJcblxyXG5IaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXJcclxuXHJcbkNvcHlyaWdodCAoYykgMjAxNi0yMDI1LCBIaWdoc29mdFxyXG5cclxuTGljZW5jZWQgdW5kZXIgdGhlIE1JVCBsaWNlbmNlLlxyXG5cclxuQWRkaXRpb25hbGx5IGEgdmFsaWQgSGlnaGNoYXJ0cyBsaWNlbnNlIGlzIHJlcXVpcmVkIGZvciB1c2UuXHJcblxyXG5TZWUgTElDRU5TRSBmaWxlIGluIHJvb3QgZm9yIGRldGFpbHMuXHJcblxyXG4qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xyXG5cclxuLyoqXHJcbiAqIEBvdmVydmlldyBUaGlzIG1vZHVsZSBoYW5kbGVzIGNoYXJ0IGV4cG9ydCBmdW5jdGlvbmFsaXR5IHVzaW5nIFB1cHBldGVlci5cclxuICogSXQgc3VwcG9ydHMgZXhwb3J0aW5nIGNoYXJ0cyBhcyBTVkcsIFBORywgSlBFRywgYW5kIFBERiBmb3JtYXRzLiBUaGUgbW9kdWxlXHJcbiAqIG1hbmFnZXMgcGFnZSByZXNvdXJjZXMsIHNldHMgdXAgdGhlIGV4cG9ydCBlbnZpcm9ubWVudCwgYW5kIHByb2Nlc3NlcyBjaGFydFxyXG4gKiBjb25maWd1cmF0aW9ucyBvciBTVkcgaW5wdXRzIGZvciByZW5kZXJpbmcuIEV4cG9ydHMgdG8gYSBjaGFydCBmcm9tIGEgcGFnZVxyXG4gKiB1c2luZyBQdXBwZXRlZXIuXHJcbiAqL1xyXG5cclxuaW1wb3J0IHsgYWRkUGFnZVJlc291cmNlcywgY2xlYXJQYWdlUmVzb3VyY2VzIH0gZnJvbSAnLi9icm93c2VyLmpzJztcclxuaW1wb3J0IHsgY3JlYXRlQ2hhcnQgfSBmcm9tICcuL2hpZ2hjaGFydHMuanMnO1xyXG5pbXBvcnQgeyBsb2cgfSBmcm9tICcuL2xvZ2dlci5qcyc7XHJcblxyXG5pbXBvcnQgc3ZnVGVtcGxhdGUgZnJvbSAnLi4vdGVtcGxhdGVzL3N2Z0V4cG9ydC9zdmdFeHBvcnQuanMnO1xyXG5cclxuaW1wb3J0IEV4cG9ydEVycm9yIGZyb20gJy4vZXJyb3JzL0V4cG9ydEVycm9yLmpzJztcclxuXHJcbi8qKlxyXG4gKiBFeHBvcnRzIHRvIGEgY2hhcnQgZnJvbSBhIHBhZ2UgdXNpbmcgUHVwcGV0ZWVyLlxyXG4gKlxyXG4gKiBAYXN5bmNcclxuICogQGZ1bmN0aW9uIHB1cHBldGVlckV4cG9ydFxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gcGFnZSAtIFB1cHBldGVlciBwYWdlIG9iamVjdC5cclxuICogQHBhcmFtIHtPYmplY3R9IGV4cG9ydE9wdGlvbnMgLSBUaGUgY29uZmlndXJhdGlvbiBvYmplY3QgY29udGFpbmluZyBgZXhwb3J0YFxyXG4gKiBvcHRpb25zLlxyXG4gKiBAcGFyYW0ge09iamVjdH0gY3VzdG9tTG9naWNPcHRpb25zIC0gVGhlIGNvbmZpZ3VyYXRpb24gb2JqZWN0IGNvbnRhaW5pbmdcclxuICogYGN1c3RvbUxvZ2ljYCBvcHRpb25zLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7UHJvbWlzZTwoc3RyaW5nfEJ1ZmZlcnxFeHBvcnRFcnJvcik+fSBBIFByb21pc2UgdGhhdCByZXNvbHZlc1xyXG4gKiB0byB0aGUgZXhwb3J0ZWQgZGF0YSBvciByZWplY3Rpbmcgd2l0aCBhbiBgRXhwb3J0RXJyb3JgLlxyXG4gKlxyXG4gKiBAdGhyb3dzIHtFeHBvcnRFcnJvcn0gVGhyb3dzIGFuIGBFeHBvcnRFcnJvcmAgaWYgZXhwb3J0IHRvIGFuIHVuc3VwcG9ydGVkXHJcbiAqIG91dHB1dCBmb3JtYXQgb2NjdXJzLlxyXG4gKi9cclxuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIHB1cHBldGVlckV4cG9ydChwYWdlLCBleHBvcnRPcHRpb25zLCBjdXN0b21Mb2dpY09wdGlvbnMpIHtcclxuICAvLyBJbmplY3RlZCByZXNvdXJjZXMgYXJyYXkgKGFkZGl0aW9uYWwgSlMgYW5kIENTUylcclxuICBjb25zdCBpbmplY3RlZFJlc291cmNlcyA9IFtdO1xyXG5cclxuICB0cnkge1xyXG4gICAgbGV0IGlzU1ZHID0gZmFsc2U7XHJcblxyXG4gICAgLy8gRGVjaWRlIG9uIHRoZSBleHBvcnQgbWV0aG9kXHJcbiAgICBpZiAoZXhwb3J0T3B0aW9ucy5zdmcpIHtcclxuICAgICAgbG9nKDQsICdbZXhwb3J0XSBUcmVhdGluZyBhcyBTVkcgaW5wdXQuJyk7XHJcblxyXG4gICAgICAvLyBJZiB0aGUgYHR5cGVgIGlzIGFsc28gU1ZHLCByZXR1cm4gdGhlIGlucHV0XHJcbiAgICAgIGlmIChleHBvcnRPcHRpb25zLnR5cGUgPT09ICdzdmcnKSB7XHJcbiAgICAgICAgcmV0dXJuIGV4cG9ydE9wdGlvbnMuc3ZnO1xyXG4gICAgICB9XHJcblxyXG4gICAgICAvLyBNYXJrIGFzIFNWRyBleHBvcnQgZm9yIHRoZSBsYXRlciBzaXplIGNvcnJlY3Rpb25zXHJcbiAgICAgIGlzU1ZHID0gdHJ1ZTtcclxuXHJcbiAgICAgIC8vIFNWRyBleHBvcnRcclxuICAgICAgYXdhaXQgcGFnZS5zZXRDb250ZW50KHN2Z1RlbXBsYXRlKGV4cG9ydE9wdGlvbnMuc3ZnKSwge1xyXG4gICAgICAgIHdhaXRVbnRpbDogJ2RvbWNvbnRlbnRsb2FkZWQnXHJcbiAgICAgIH0pO1xyXG4gICAgfSBlbHNlIHtcclxuICAgICAgbG9nKDQsICdbZXhwb3J0XSBUcmVhdGluZyBhcyBKU09OIGNvbmZpZy4nKTtcclxuXHJcbiAgICAgIC8vIE9wdGlvbnMgZXhwb3J0XHJcbiAgICAgIGF3YWl0IHBhZ2UuZXZhbHVhdGUoY3JlYXRlQ2hhcnQsIGV4cG9ydE9wdGlvbnMsIGN1c3RvbUxvZ2ljT3B0aW9ucyk7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gS2VlcHMgdHJhY2sgb2YgYWxsIHJlc291cmNlcyBhZGRlZCBvbiB0aGUgcGFnZSB3aXRoIGFkZFhYWFRhZy4gZXRjXHJcbiAgICAvLyBJdCdzIFZJVEFMIHRoYXQgYWxsIGFkZGVkIHJlc291cmNlcyBlbmRzIHVwIGhlcmUgc28gd2UgY2FuIGNsZWFyIHRoaW5nc1xyXG4gICAgLy8gb3V0IHdoZW4gZG9pbmcgYSBuZXcgZXhwb3J0IGluIHRoZSBzYW1lIHBhZ2UhXHJcbiAgICBpbmplY3RlZFJlc291cmNlcy5wdXNoKFxyXG4gICAgICAuLi4oYXdhaXQgYWRkUGFnZVJlc291cmNlcyhwYWdlLCBjdXN0b21Mb2dpY09wdGlvbnMpKVxyXG4gICAgKTtcclxuXHJcbiAgICAvLyBHZXQgdGhlIHJlYWwgY2hhcnQgc2l6ZSBhbmQgc2V0IHRoZSB6b29tIGFjY29yZGluZ2x5XHJcbiAgICBjb25zdCBzaXplID0gaXNTVkdcclxuICAgICAgPyBhd2FpdCBwYWdlLmV2YWx1YXRlKChzY2FsZSkgPT4ge1xyXG4gICAgICAgICAgY29uc3Qgc3ZnRWxlbWVudCA9IGRvY3VtZW50LnF1ZXJ5U2VsZWN0b3IoXHJcbiAgICAgICAgICAgICcjY2hhcnQtY29udGFpbmVyIHN2ZzpmaXJzdC1vZi10eXBlJ1xyXG4gICAgICAgICAgKTtcclxuXHJcbiAgICAgICAgICAvLyBHZXQgdGhlIHZhbHVlcyBjb3JyZWN0bHkgc2NhbGVkXHJcbiAgICAgICAgICBjb25zdCBjaGFydEhlaWdodCA9IHN2Z0VsZW1lbnQuaGVpZ2h0LmJhc2VWYWwudmFsdWUgKiBzY2FsZTtcclxuICAgICAgICAgIGNvbnN0IGNoYXJ0V2lkdGggPSBzdmdFbGVtZW50LndpZHRoLmJhc2VWYWwudmFsdWUgKiBzY2FsZTtcclxuXHJcbiAgICAgICAgICAvLyBJbiBjYXNlIG9mIFNWRyB0aGUgem9vbSBtdXN0IGJlIHNldCBkaXJlY3RseSBmb3IgYm9keSBhcyBzY2FsZVxyXG4gICAgICAgICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIG5vLXVuZGVmXHJcbiAgICAgICAgICBkb2N1bWVudC5ib2R5LnN0eWxlLnpvb20gPSBzY2FsZTtcclxuXHJcbiAgICAgICAgICAvLyBTZXQgdGhlIG1hcmdpbiB0byAwcHhcclxuICAgICAgICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBuby11bmRlZlxyXG4gICAgICAgICAgZG9jdW1lbnQuYm9keS5zdHlsZS5tYXJnaW4gPSAnMHB4JztcclxuXHJcbiAgICAgICAgICByZXR1cm4ge1xyXG4gICAgICAgICAgICBjaGFydEhlaWdodCxcclxuICAgICAgICAgICAgY2hhcnRXaWR0aFxyXG4gICAgICAgICAgfTtcclxuICAgICAgICB9LCBwYXJzZUZsb2F0KGV4cG9ydE9wdGlvbnMuc2NhbGUpKVxyXG4gICAgICA6IGF3YWl0IHBhZ2UuZXZhbHVhdGUoKCkgPT4ge1xyXG4gICAgICAgICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIG5vLXVuZGVmXHJcbiAgICAgICAgICBjb25zdCB7IGNoYXJ0SGVpZ2h0LCBjaGFydFdpZHRoIH0gPSB3aW5kb3cuSGlnaGNoYXJ0cy5jaGFydHNbMF07XHJcblxyXG4gICAgICAgICAgLy8gTm8gbmVlZCBmb3Igc3VjaCBzY2FsZSBtYW5pcHVsYXRpb24gaW4gY2FzZSBvZiBvdGhlciB0eXBlc1xyXG4gICAgICAgICAgLy8gb2YgZXhwb3J0cy4gUmVzZXQgdGhlIHpvb20gZm9yIG90aGVyIGV4cG9ydHMgdGhhbiB0byBTVkdzXHJcbiAgICAgICAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgbm8tdW5kZWZcclxuICAgICAgICAgIGRvY3VtZW50LmJvZHkuc3R5bGUuem9vbSA9IDE7XHJcblxyXG4gICAgICAgICAgcmV0dXJuIHtcclxuICAgICAgICAgICAgY2hhcnRIZWlnaHQsXHJcbiAgICAgICAgICAgIGNoYXJ0V2lkdGhcclxuICAgICAgICAgIH07XHJcbiAgICAgICAgfSk7XHJcblxyXG4gICAgLy8gR2V0IHRoZSBjbGlwIHJlZ2lvbiBmb3IgdGhlIHBhZ2VcclxuICAgIGNvbnN0IHsgeCwgeSB9ID0gYXdhaXQgX2dldENsaXBSZWdpb24ocGFnZSk7XHJcblxyXG4gICAgLy8gU2V0IGZpbmFsIGBoZWlnaHRgIGZvciB2aWV3cG9ydFxyXG4gICAgY29uc3Qgdmlld3BvcnRIZWlnaHQgPSBNYXRoLmFicyhcclxuICAgICAgTWF0aC5jZWlsKHNpemUuY2hhcnRIZWlnaHQgfHwgZXhwb3J0T3B0aW9ucy5oZWlnaHQpXHJcbiAgICApO1xyXG5cclxuICAgIC8vIFNldCBmaW5hbCBgd2lkdGhgIGZvciB2aWV3cG9ydFxyXG4gICAgY29uc3Qgdmlld3BvcnRXaWR0aCA9IE1hdGguYWJzKFxyXG4gICAgICBNYXRoLmNlaWwoc2l6ZS5jaGFydFdpZHRoIHx8IGV4cG9ydE9wdGlvbnMud2lkdGgpXHJcbiAgICApO1xyXG5cclxuICAgIC8vIFNldCB0aGUgZmluYWwgdmlld3BvcnQgbm93IHRoYXQgd2UgaGF2ZSB0aGUgcmVhbCBoZWlnaHRcclxuICAgIGF3YWl0IHBhZ2Uuc2V0Vmlld3BvcnQoe1xyXG4gICAgICBoZWlnaHQ6IHZpZXdwb3J0SGVpZ2h0LFxyXG4gICAgICB3aWR0aDogdmlld3BvcnRXaWR0aCxcclxuICAgICAgZGV2aWNlU2NhbGVGYWN0b3I6IGlzU1ZHID8gMSA6IHBhcnNlRmxvYXQoZXhwb3J0T3B0aW9ucy5zY2FsZSlcclxuICAgIH0pO1xyXG5cclxuICAgIGxldCByZXN1bHQ7XHJcbiAgICAvLyBSYXN0ZXJpemF0aW9uIHByb2Nlc3NcclxuICAgIHN3aXRjaCAoZXhwb3J0T3B0aW9ucy50eXBlKSB7XHJcbiAgICAgIGNhc2UgJ3N2Zyc6XHJcbiAgICAgICAgcmVzdWx0ID0gYXdhaXQgX2NyZWF0ZVNWRyhwYWdlKTtcclxuICAgICAgICBicmVhaztcclxuICAgICAgY2FzZSAncG5nJzpcclxuICAgICAgY2FzZSAnanBlZyc6XHJcbiAgICAgICAgcmVzdWx0ID0gYXdhaXQgX2NyZWF0ZUltYWdlKFxyXG4gICAgICAgICAgcGFnZSxcclxuICAgICAgICAgIGV4cG9ydE9wdGlvbnMudHlwZSxcclxuICAgICAgICAgIHtcclxuICAgICAgICAgICAgd2lkdGg6IHZpZXdwb3J0V2lkdGgsXHJcbiAgICAgICAgICAgIGhlaWdodDogdmlld3BvcnRIZWlnaHQsXHJcbiAgICAgICAgICAgIHgsXHJcbiAgICAgICAgICAgIHlcclxuICAgICAgICAgIH0sXHJcbiAgICAgICAgICBleHBvcnRPcHRpb25zLnJhc3Rlcml6YXRpb25UaW1lb3V0XHJcbiAgICAgICAgKTtcclxuICAgICAgICBicmVhaztcclxuICAgICAgY2FzZSAncGRmJzpcclxuICAgICAgICByZXN1bHQgPSBhd2FpdCBfY3JlYXRlUERGKFxyXG4gICAgICAgICAgcGFnZSxcclxuICAgICAgICAgIHZpZXdwb3J0SGVpZ2h0LFxyXG4gICAgICAgICAgdmlld3BvcnRXaWR0aCxcclxuICAgICAgICAgIGV4cG9ydE9wdGlvbnMucmFzdGVyaXphdGlvblRpbWVvdXRcclxuICAgICAgICApO1xyXG4gICAgICAgIGJyZWFrO1xyXG4gICAgICBkZWZhdWx0OlxyXG4gICAgICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcihcclxuICAgICAgICAgIGBbZXhwb3J0XSBVbnN1cHBvcnRlZCBvdXRwdXQgZm9ybWF0OiAke2V4cG9ydE9wdGlvbnMudHlwZX0uYCxcclxuICAgICAgICAgIDQwMFxyXG4gICAgICAgICk7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gQ2xlYXIgcHJldmlvdXNseSBpbmplY3RlZCBKUyBhbmQgQ1NTIHJlc291cmNlc1xyXG4gICAgYXdhaXQgY2xlYXJQYWdlUmVzb3VyY2VzKHBhZ2UsIGluamVjdGVkUmVzb3VyY2VzKTtcclxuICAgIHJldHVybiByZXN1bHQ7XHJcbiAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgIGF3YWl0IGNsZWFyUGFnZVJlc291cmNlcyhwYWdlLCBpbmplY3RlZFJlc291cmNlcyk7XHJcbiAgICByZXR1cm4gZXJyb3I7XHJcbiAgfVxyXG59XHJcblxyXG4vKipcclxuICogUmV0cmlldmVzIHRoZSBjbGlwcGluZyByZWdpb24gY29vcmRpbmF0ZXMgb2YgdGhlIHNwZWNpZmllZCBwYWdlIGVsZW1lbnRcclxuICogd2l0aCB0aGUgJ2NoYXJ0LWNvbnRhaW5lcicgaWQuXHJcbiAqXHJcbiAqIEBhc3luY1xyXG4gKiBAZnVuY3Rpb24gX2dldENsaXBSZWdpb25cclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IHBhZ2UgLSBQdXBwZXRlZXIgcGFnZSBvYmplY3QuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtQcm9taXNlPE9iamVjdD59IEEgUHJvbWlzZSB0aGF0IHJlc29sdmVzIHRvIGFuIG9iamVjdCBjb250YWluaW5nXHJcbiAqIGB4YCwgYHlgLCBgd2lkdGhgLCBhbmQgYGhlaWdodGAgcHJvcGVydGllcy5cclxuICovXHJcbmFzeW5jIGZ1bmN0aW9uIF9nZXRDbGlwUmVnaW9uKHBhZ2UpIHtcclxuICByZXR1cm4gcGFnZS4kZXZhbCgnI2NoYXJ0LWNvbnRhaW5lcicsIChlbGVtZW50KSA9PiB7XHJcbiAgICBjb25zdCB7IHgsIHksIHdpZHRoLCBoZWlnaHQgfSA9IGVsZW1lbnQuZ2V0Qm91bmRpbmdDbGllbnRSZWN0KCk7XHJcbiAgICByZXR1cm4ge1xyXG4gICAgICB4LFxyXG4gICAgICB5LFxyXG4gICAgICB3aWR0aCxcclxuICAgICAgaGVpZ2h0OiBNYXRoLnRydW5jKGhlaWdodCA+IDEgPyBoZWlnaHQgOiA1MDApXHJcbiAgICB9O1xyXG4gIH0pO1xyXG59XHJcblxyXG4vKipcclxuICogQ3JlYXRlcyBhbiBTVkcgYnkgZXZhbHVhdGluZyB0aGUgYG91dGVySFRNTGAgb2YgdGhlIGZpcnN0ICdzdmcnIGVsZW1lbnRcclxuICogaW5zaWRlIGFuIGVsZW1lbnQgd2l0aCB0aGUgaWQgJ2NvbnRhaW5lcicuXHJcbiAqXHJcbiAqIEBhc3luY1xyXG4gKiBAZnVuY3Rpb24gX2NyZWF0ZVNWR1xyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gcGFnZSAtIFB1cHBldGVlciBwYWdlIG9iamVjdC5cclxuICpcclxuICogQHJldHVybnMge1Byb21pc2U8c3RyaW5nPn0gQSBQcm9taXNlIHRoYXQgcmVzb2x2ZXMgdG8gdGhlIFNWRyBzdHJpbmcuXHJcbiAqL1xyXG5hc3luYyBmdW5jdGlvbiBfY3JlYXRlU1ZHKHBhZ2UpIHtcclxuICByZXR1cm4gcGFnZS4kZXZhbChcclxuICAgICcjY29udGFpbmVyIHN2ZzpmaXJzdC1vZi10eXBlJyxcclxuICAgIChlbGVtZW50KSA9PiBlbGVtZW50Lm91dGVySFRNTFxyXG4gICk7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBDcmVhdGVzIGFuIGltYWdlIHVzaW5nIFB1cHBldGVlcidzIHBhZ2UgYHNjcmVlbnNob3RgIGZ1bmN0aW9uYWxpdHkgd2l0aFxyXG4gKiBzcGVjaWZpZWQgb3B0aW9ucy5cclxuICpcclxuICogQGFzeW5jXHJcbiAqIEBmdW5jdGlvbiBfY3JlYXRlSW1hZ2VcclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IHBhZ2UgLSBQdXBwZXRlZXIgcGFnZSBvYmplY3QuXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSB0eXBlIC0gSW1hZ2UgdHlwZS5cclxuICogQHBhcmFtIHtPYmplY3R9IGNsaXAgLSBDbGlwcGluZyByZWdpb24gY29vcmRpbmF0ZXMuXHJcbiAqIEBwYXJhbSB7bnVtYmVyfSByYXN0ZXJpemF0aW9uVGltZW91dCAtIFRpbWVvdXQgZm9yIHJhc3Rlcml6YXRpb25cclxuICogaW4gbWlsbGlzZWNvbmRzLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7UHJvbWlzZTxCdWZmZXI+fSBBIFByb21pc2UgdGhhdCByZXNvbHZlcyB0byB0aGUgaW1hZ2UgYnVmZmVyXHJcbiAqIG9yIHJlamVjdGluZyB3aXRoIGFuIGBFeHBvcnRFcnJvcmAgZm9yIHRpbWVvdXQuXHJcbiAqL1xyXG5hc3luYyBmdW5jdGlvbiBfY3JlYXRlSW1hZ2UocGFnZSwgdHlwZSwgY2xpcCwgcmFzdGVyaXphdGlvblRpbWVvdXQpIHtcclxuICByZXR1cm4gUHJvbWlzZS5yYWNlKFtcclxuICAgIHBhZ2Uuc2NyZWVuc2hvdCh7XHJcbiAgICAgIHR5cGUsXHJcbiAgICAgIGNsaXAsXHJcbiAgICAgIGVuY29kaW5nOiAnYmFzZTY0JyxcclxuICAgICAgZnVsbFBhZ2U6IGZhbHNlLFxyXG4gICAgICBvcHRpbWl6ZUZvclNwZWVkOiB0cnVlLFxyXG4gICAgICBjYXB0dXJlQmV5b25kVmlld3BvcnQ6IHRydWUsXHJcbiAgICAgIC4uLih0eXBlICE9PSAncG5nJyA/IHsgcXVhbGl0eTogODAgfSA6IHt9KSxcclxuICAgICAgLy8gQWx3YXlzIHJlbmRlciBvbiBhIHRyYW5zcGFyZW50IHBhZ2UgaWYgdGhlIGV4cGVjdGVkIHR5cGUgZm9ybWF0IGlzIFBOR1xyXG4gICAgICBvbWl0QmFja2dyb3VuZDogdHlwZSA9PSAncG5nJyAvLyAjNDQ3LCAjNDYzXHJcbiAgICB9KSxcclxuICAgIG5ldyBQcm9taXNlKChfcmVzb2x2ZSwgcmVqZWN0KSA9PlxyXG4gICAgICBzZXRUaW1lb3V0KFxyXG4gICAgICAgICgpID0+IHJlamVjdChuZXcgRXhwb3J0RXJyb3IoJ1Jhc3Rlcml6YXRpb24gdGltZW91dCcsIDQwOCkpLFxyXG4gICAgICAgIHJhc3Rlcml6YXRpb25UaW1lb3V0IHx8IDE1MDBcclxuICAgICAgKVxyXG4gICAgKVxyXG4gIF0pO1xyXG59XHJcblxyXG4vKipcclxuICogQ3JlYXRlcyBhIFBERiB1c2luZyBQdXBwZXRlZXIncyBwYWdlIGBwZGZgIGZ1bmN0aW9uYWxpdHkgd2l0aCBzcGVjaWZpZWRcclxuICogb3B0aW9ucy5cclxuICpcclxuICogQGFzeW5jXHJcbiAqIEBmdW5jdGlvbiBfY3JlYXRlUERGXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBwYWdlIC0gUHVwcGV0ZWVyIHBhZ2Ugb2JqZWN0LlxyXG4gKiBAcGFyYW0ge251bWJlcn0gaGVpZ2h0IC0gUERGIGhlaWdodC5cclxuICogQHBhcmFtIHtudW1iZXJ9IHdpZHRoIC0gUERGIHdpZHRoLlxyXG4gKiBAcGFyYW0ge251bWJlcn0gcmFzdGVyaXphdGlvblRpbWVvdXQgLSBUaW1lb3V0IGZvciByYXN0ZXJpemF0aW9uXHJcbiAqIGluIG1pbGxpc2Vjb25kcy5cclxuICpcclxuICogQHJldHVybnMge1Byb21pc2U8QnVmZmVyPn0gQSBQcm9taXNlIHRoYXQgcmVzb2x2ZXMgdG8gdGhlIFBERiBidWZmZXIuXHJcbiAqL1xyXG5hc3luYyBmdW5jdGlvbiBfY3JlYXRlUERGKHBhZ2UsIGhlaWdodCwgd2lkdGgsIHJhc3Rlcml6YXRpb25UaW1lb3V0KSB7XHJcbiAgYXdhaXQgcGFnZS5lbXVsYXRlTWVkaWFUeXBlKCdzY3JlZW4nKTtcclxuICByZXR1cm4gcGFnZS5wZGYoe1xyXG4gICAgLy8gVGhpcyB3aWxsIHJlbW92ZSBhbiBleHRyYSBlbXB0eSBwYWdlIGluIFBERiBleHBvcnRzXHJcbiAgICBoZWlnaHQ6IGhlaWdodCArIDEsXHJcbiAgICB3aWR0aCxcclxuICAgIGVuY29kaW5nOiAnYmFzZTY0JyxcclxuICAgIHRpbWVvdXQ6IHJhc3Rlcml6YXRpb25UaW1lb3V0IHx8IDE1MDBcclxuICB9KTtcclxufVxyXG5cclxuZXhwb3J0IGRlZmF1bHQge1xyXG4gIHB1cHBldGVlckV4cG9ydFxyXG59O1xyXG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxyXG5cclxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXHJcblxyXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNSwgSGlnaHNvZnRcclxuXHJcbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cclxuXHJcbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxyXG5cclxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxyXG5cclxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cclxuXHJcbi8qKlxyXG4gKiBAb3ZlcnZpZXcgVGhpcyBtb2R1bGUgcHJvdmlkZXMgYSB3b3JrZXIgcG9vbCBpbXBsZW1lbnRhdGlvbiBmb3IgbWFuYWdpbmdcclxuICogdGhlIGJyb3dzZXIgaW5zdGFuY2UgYW5kIHBhZ2VzLCBzcGVjaWZpY2FsbHkgZGVzaWduZWQgZm9yIHVzZSB3aXRoXHJcbiAqIHRoZSBIaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXIuIEl0IG9wdGltaXplcyByZXNvdXJjZXMgdXNhZ2UgYW5kIHBlcmZvcm1hbmNlXHJcbiAqIGJ5IG1haW50YWluaW5nIGEgcG9vbCBvZiB3b3JrZXJzIHRoYXQgY2FuIGhhbmRsZSBjb25jdXJyZW50IGV4cG9ydCB0YXNrc1xyXG4gKiB1c2luZyBQdXBwZXRlZXIuXHJcbiAqL1xyXG5cclxuaW1wb3J0IHsgUG9vbCB9IGZyb20gJ3Rhcm4nO1xyXG5pbXBvcnQgeyB2NCBhcyB1dWlkIH0gZnJvbSAndXVpZCc7XHJcblxyXG5pbXBvcnQgeyBjbGVhclBhZ2UsIGNyZWF0ZUJyb3dzZXIsIGNsb3NlQnJvd3NlciwgbmV3UGFnZSB9IGZyb20gJy4vYnJvd3Nlci5qcyc7XHJcbmltcG9ydCB7IHB1cHBldGVlckV4cG9ydCB9IGZyb20gJy4vZXhwb3J0LmpzJztcclxuaW1wb3J0IHsgbG9nLCBsb2dXaXRoU3RhY2sgfSBmcm9tICcuL2xvZ2dlci5qcyc7XHJcbmltcG9ydCB7IGdldE5ld0RhdGVUaW1lLCBtZWFzdXJlVGltZSB9IGZyb20gJy4vdXRpbHMuanMnO1xyXG5cclxuaW1wb3J0IEV4cG9ydEVycm9yIGZyb20gJy4vZXJyb3JzL0V4cG9ydEVycm9yLmpzJztcclxuXHJcbi8vIFRoZSBwb29sIGluc3RhbmNlXHJcbmxldCBwb29sID0gbnVsbDtcclxuXHJcbi8vIFBvb2wgc3RhdGlzdGljc1xyXG5jb25zdCBwb29sU3RhdHMgPSB7XHJcbiAgZXhwb3J0c0F0dGVtcHRlZDogMCxcclxuICBleHBvcnRzUGVyZm9ybWVkOiAwLFxyXG4gIGV4cG9ydHNEcm9wcGVkOiAwLFxyXG4gIGV4cG9ydHNGcm9tU3ZnOiAwLFxyXG4gIGV4cG9ydHNGcm9tT3B0aW9uczogMCxcclxuICBleHBvcnRzRnJvbVN2Z0F0dGVtcHRzOiAwLFxyXG4gIGV4cG9ydHNGcm9tT3B0aW9uc0F0dGVtcHRzOiAwLFxyXG4gIHRpbWVTcGVudDogMCxcclxuICB0aW1lU3BlbnRBdmVyYWdlOiAwXHJcbn07XHJcblxyXG4vKipcclxuICogSW5pdGlhbGl6ZXMgdGhlIGV4cG9ydCBwb29sIHdpdGggdGhlIHByb3ZpZGVkIGNvbmZpZ3VyYXRpb24sIGNyZWF0aW5nXHJcbiAqIGEgYnJvd3NlciBpbnN0YW5jZSBhbmQgc2V0dGluZyB1cCB3b3JrZXIgcmVzb3VyY2VzLlxyXG4gKlxyXG4gKiBAYXN5bmNcclxuICogQGZ1bmN0aW9uIGluaXRQb29sXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBwb29sT3B0aW9ucyAtIFRoZSBjb25maWd1cmF0aW9uIG9iamVjdCBjb250YWluaW5nIGBwb29sYFxyXG4gKiBvcHRpb25zLlxyXG4gKiBAcGFyYW0ge0FycmF5LjxzdHJpbmc+fSBwdXBwZXRlZXJBcmdzIC0gQWRkaXRpb25hbCBhcmd1bWVudHMgZm9yIFB1cHBldGVlclxyXG4gKiBsYXVuY2guXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtQcm9taXNlPHZvaWQ+fSBBIFByb21pc2UgdGhhdCByZXNvbHZlcyB0byBlbmRpbmcgdGhlIGZ1bmN0aW9uXHJcbiAqIGV4ZWN1dGlvbiB3aGVuIGFuIGFscmVhZHkgaW5pdGlhbGl6ZWQgcG9vbCBvZiByZXNvdXJjZXMgaXMgZm91bmQuXHJcbiAqXHJcbiAqIEB0aHJvd3Mge0V4cG9ydEVycm9yfSBUaHJvd3MgYW4gYEV4cG9ydEVycm9yYCBpZiBjb3VsZCBub3QgY3JlYXRlIHRoZSBwb29sXHJcbiAqIG9mIHdvcmtlcnMuXHJcbiAqL1xyXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gaW5pdFBvb2wocG9vbE9wdGlvbnMsIHB1cHBldGVlckFyZ3MpIHtcclxuICAvLyBDcmVhdGUgYSBicm93c2VyIGluc3RhbmNlIHdpdGggdGhlIHB1cHBldGVlciBhcmd1bWVudHNcclxuICBhd2FpdCBjcmVhdGVCcm93c2VyKHB1cHBldGVlckFyZ3MpO1xyXG5cclxuICB0cnkge1xyXG4gICAgbG9nKFxyXG4gICAgICAzLFxyXG4gICAgICBgW3Bvb2xdIEluaXRpYWxpemluZyBwb29sIHdpdGggd29ya2VyczogbWluICR7cG9vbE9wdGlvbnMubWluV29ya2Vyc30sIG1heCAke3Bvb2xPcHRpb25zLm1heFdvcmtlcnN9LmBcclxuICAgICk7XHJcblxyXG4gICAgaWYgKHBvb2wpIHtcclxuICAgICAgbG9nKFxyXG4gICAgICAgIDQsXHJcbiAgICAgICAgJ1twb29sXSBBbHJlYWR5IGluaXRpYWxpemVkLCBwbGVhc2Uga2lsbCBpdCBiZWZvcmUgY3JlYXRpbmcgYSBuZXcgb25lLidcclxuICAgICAgKTtcclxuICAgICAgcmV0dXJuO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIEtlZXAgYW4gZXllIG9uIGEgY29ycmVjdCBtaW4gYW5kIG1heCB3b3JrZXJzIG51bWJlclxyXG4gICAgaWYgKHBvb2xPcHRpb25zLm1pbldvcmtlcnMgPiBwb29sT3B0aW9ucy5tYXhXb3JrZXJzKSB7XHJcbiAgICAgIHBvb2xPcHRpb25zLm1pbldvcmtlcnMgPSBwb29sT3B0aW9ucy5tYXhXb3JrZXJzO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIENyZWF0ZSBhIHBvb2wgYWxvbmcgd2l0aCBhIG1pbmltYWwgbnVtYmVyIG9mIHJlc291cmNlc1xyXG4gICAgcG9vbCA9IG5ldyBQb29sKHtcclxuICAgICAgLy8gR2V0IHRoZSBgY3JlYXRlYCwgYHZhbGlkYXRlYCwgYW5kIGBkZXN0cm95YCBmdW5jdGlvbnNcclxuICAgICAgLi4uX2ZhY3RvcnkocG9vbE9wdGlvbnMpLFxyXG4gICAgICBtaW46IHBvb2xPcHRpb25zLm1pbldvcmtlcnMsXHJcbiAgICAgIG1heDogcG9vbE9wdGlvbnMubWF4V29ya2VycyxcclxuICAgICAgYWNxdWlyZVRpbWVvdXRNaWxsaXM6IHBvb2xPcHRpb25zLmFjcXVpcmVUaW1lb3V0LFxyXG4gICAgICBjcmVhdGVUaW1lb3V0TWlsbGlzOiBwb29sT3B0aW9ucy5jcmVhdGVUaW1lb3V0LFxyXG4gICAgICBkZXN0cm95VGltZW91dE1pbGxpczogcG9vbE9wdGlvbnMuZGVzdHJveVRpbWVvdXQsXHJcbiAgICAgIGlkbGVUaW1lb3V0TWlsbGlzOiBwb29sT3B0aW9ucy5pZGxlVGltZW91dCxcclxuICAgICAgY3JlYXRlUmV0cnlJbnRlcnZhbE1pbGxpczogcG9vbE9wdGlvbnMuY3JlYXRlUmV0cnlJbnRlcnZhbCxcclxuICAgICAgcmVhcEludGVydmFsTWlsbGlzOiBwb29sT3B0aW9ucy5yZWFwZXJJbnRlcnZhbCxcclxuICAgICAgcHJvcGFnYXRlQ3JlYXRlRXJyb3I6IGZhbHNlXHJcbiAgICB9KTtcclxuXHJcbiAgICAvLyBTZXQgZXZlbnRzXHJcbiAgICBwb29sLm9uKCdyZWxlYXNlJywgYXN5bmMgKHJlc291cmNlKSA9PiB7XHJcbiAgICAgIC8vIENsZWFyIHBhZ2VcclxuICAgICAgY29uc3QgY2xlYXJTdGF0dXMgPSBhd2FpdCBjbGVhclBhZ2UocmVzb3VyY2UsIGZhbHNlKTtcclxuICAgICAgbG9nKFxyXG4gICAgICAgIDQsXHJcbiAgICAgICAgYFtwb29sXSBQb29sIHJlc291cmNlIFske3Jlc291cmNlLmlkfV0gLSBSZWxlYXNpbmcgYSB3b3JrZXIuIENsZWFyIHBhZ2Ugc3RhdHVzOiAke2NsZWFyU3RhdHVzfS5gXHJcbiAgICAgICk7XHJcbiAgICB9KTtcclxuXHJcbiAgICBwb29sLm9uKCdkZXN0cm95U3VjY2VzcycsIChfZXZlbnRJZCwgcmVzb3VyY2UpID0+IHtcclxuICAgICAgbG9nKFxyXG4gICAgICAgIDQsXHJcbiAgICAgICAgYFtwb29sXSBQb29sIHJlc291cmNlIFske3Jlc291cmNlLmlkfV0gLSBEZXN0cm95ZWQgYSB3b3JrZXIgc3VjY2Vzc2Z1bGx5LmBcclxuICAgICAgKTtcclxuICAgICAgcmVzb3VyY2UucGFnZSA9IG51bGw7XHJcbiAgICB9KTtcclxuXHJcbiAgICBjb25zdCBpbml0aWFsUmVzb3VyY2VzID0gW107XHJcbiAgICAvLyBDcmVhdGUgYW4gaW5pdGlhbCBudW1iZXIgb2YgcmVzb3VyY2VzXHJcbiAgICBmb3IgKGxldCBpID0gMDsgaSA8IHBvb2xPcHRpb25zLm1pbldvcmtlcnM7IGkrKykge1xyXG4gICAgICB0cnkge1xyXG4gICAgICAgIGNvbnN0IHJlc291cmNlID0gYXdhaXQgcG9vbC5hY3F1aXJlKCkucHJvbWlzZTtcclxuICAgICAgICBpbml0aWFsUmVzb3VyY2VzLnB1c2gocmVzb3VyY2UpO1xyXG4gICAgICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgICAgIGxvZ1dpdGhTdGFjaygyLCBlcnJvciwgJ1twb29sXSBDb3VsZCBub3QgY3JlYXRlIGFuIGluaXRpYWwgcmVzb3VyY2UuJyk7XHJcbiAgICAgIH1cclxuICAgIH1cclxuXHJcbiAgICAvLyBSZWxlYXNlIHRoZSBpbml0aWFsIG51bWJlciBvZiByZXNvdXJjZXMgYmFjayB0byB0aGUgcG9vbFxyXG4gICAgaW5pdGlhbFJlc291cmNlcy5mb3JFYWNoKChyZXNvdXJjZSkgPT4ge1xyXG4gICAgICBwb29sLnJlbGVhc2UocmVzb3VyY2UpO1xyXG4gICAgfSk7XHJcblxyXG4gICAgbG9nKFxyXG4gICAgICAzLFxyXG4gICAgICBgW3Bvb2xdIFRoZSBwb29sIGlzIHJlYWR5JHtpbml0aWFsUmVzb3VyY2VzLmxlbmd0aCA/IGAgd2l0aCAke2luaXRpYWxSZXNvdXJjZXMubGVuZ3RofSBpbml0aWFsIHJlc291cmNlcyB3YWl0aW5nLmAgOiAnLid9YFxyXG4gICAgKTtcclxuICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgdGhyb3cgbmV3IEV4cG9ydEVycm9yKFxyXG4gICAgICAnW3Bvb2xdIENvdWxkIG5vdCBjb25maWd1cmUgYW5kIGNyZWF0ZSB0aGUgcG9vbCBvZiB3b3JrZXJzLicsXHJcbiAgICAgIDUwMFxyXG4gICAgKS5zZXRFcnJvcihlcnJvcik7XHJcbiAgfVxyXG59XHJcblxyXG4vKipcclxuICogVGVybWluYXRlcyBhbGwgd29ya2VycyBpbiB0aGUgcG9vbCwgZGVzdHJveXMgdGhlIHBvb2wsIGFuZCBjbG9zZXMgdGhlIGJyb3dzZXJcclxuICogaW5zdGFuY2UuXHJcbiAqXHJcbiAqIEBhc3luY1xyXG4gKiBAZnVuY3Rpb24ga2lsbFBvb2xcclxuICpcclxuICogQHJldHVybnMge1Byb21pc2U8dm9pZD59IEEgUHJvbWlzZSB0aGF0IHJlc29sdmVzIG9uY2UgYWxsIHdvcmtlcnMgYXJlXHJcbiAqIHRlcm1pbmF0ZWQsIHRoZSBwb29sIGlzIGRlc3Ryb3llZCwgYW5kIHRoZSBicm93c2VyIGlzIHN1Y2Nlc3NmdWxseSBjbG9zZWQuXHJcbiAqL1xyXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24ga2lsbFBvb2woKSB7XHJcbiAgbG9nKDMsICdbcG9vbF0gS2lsbGluZyBwb29sIHdpdGggYWxsIHdvcmtlcnMgYW5kIGNsb3NpbmcgYnJvd3Nlci4nKTtcclxuXHJcbiAgLy8gSWYgc3RpbGwgYWxpdmUsIGRlc3Ryb3kgdGhlIHBvb2wgb2YgcGFnZXMgYmVmb3JlIGNsb3NpbmcgYSBicm93c2VyXHJcbiAgaWYgKHBvb2wpIHtcclxuICAgIC8vIEZyZWUgdXAgbm90IHJlbGVhc2VkIHdvcmtlcnNcclxuICAgIGZvciAoY29uc3Qgd29ya2VyIG9mIHBvb2wudXNlZCkge1xyXG4gICAgICBwb29sLnJlbGVhc2Uod29ya2VyLnJlc291cmNlKTtcclxuICAgIH1cclxuXHJcbiAgICAvLyBEZXN0cm95IHRoZSBwb29sIGlmIGl0IGlzIHN0aWxsIGF2YWlsYWJsZVxyXG4gICAgaWYgKCFwb29sLmRlc3Ryb3llZCkge1xyXG4gICAgICBhd2FpdCBwb29sLmRlc3Ryb3koKTtcclxuICAgICAgbG9nKDQsICdbcG9vbF0gRGVzdHJveWVkIHRoZSBwb29sIG9mIHJlc291cmNlcy4nKTtcclxuICAgIH1cclxuICAgIHBvb2wgPSBudWxsO1xyXG4gIH1cclxuXHJcbiAgLy8gQ2xvc2UgdGhlIGJyb3dzZXIgaW5zdGFuY2VcclxuICBhd2FpdCBjbG9zZUJyb3dzZXIoKTtcclxufVxyXG5cclxuLyoqXHJcbiAqIFByb2Nlc3NlcyB0aGUgZXhwb3J0IHdvcmsgdXNpbmcgYSB3b3JrZXIgZnJvbSB0aGUgcG9vbC4gQWNxdWlyZXMgYSB3b3JrZXJcclxuICogaGFuZGxlIGZyb20gdGhlIHBvb2wsIHBlcmZvcm1zIHRoZSBleHBvcnQgdXNpbmcgcHVwcGV0ZWVyLCBhbmQgcmVsZWFzZXNcclxuICogdGhlIHdvcmtlciBoYW5kbGUgYmFjayB0byB0aGUgcG9vbC5cclxuICpcclxuICogQGFzeW5jXHJcbiAqIEBmdW5jdGlvbiBwb3N0V29ya1xyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gb3B0aW9ucyAtIFRoZSBjb25maWd1cmF0aW9uIG9iamVjdCBjb250YWluaW5nIGNvbXBsZXRlIHNldFxyXG4gKiBvZiBvcHRpb25zLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7UHJvbWlzZTxPYmplY3Q+fSBBIFByb21pc2UgdGhhdCByZXNvbHZlcyB0byB0aGUgZXhwb3J0IHJlc3VsdFxyXG4gKiBhbmQgb3B0aW9ucy5cclxuICpcclxuICogQHRocm93cyB7RXhwb3J0RXJyb3J9IFRocm93cyBhbiBgRXhwb3J0RXJyb3JgIGlmIGFuIGVycm9yIG9jY3VycyBkdXJpbmdcclxuICogdGhlIGV4cG9ydCBwcm9jZXNzLlxyXG4gKi9cclxuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIHBvc3RXb3JrKG9wdGlvbnMpIHtcclxuICBsZXQgd29ya2VySGFuZGxlO1xyXG5cclxuICB0cnkge1xyXG4gICAgbG9nKDQsICdbcG9vbF0gV29yayByZWNlaXZlZCwgc3RhcnRpbmcgdG8gcHJvY2Vzcy4nKTtcclxuXHJcbiAgICAvLyBBbiBleHBvcnQgYXR0ZW1wdCBjb3VudGVkXHJcbiAgICArK3Bvb2xTdGF0cy5leHBvcnRzQXR0ZW1wdGVkO1xyXG5cclxuICAgIC8vIERpc3BsYXkgdGhlIHBvb2wgaW5mb3JtYXRpb24gaWYgbmVlZGVkXHJcbiAgICBpZiAob3B0aW9ucy5wb29sLmJlbmNobWFya2luZykge1xyXG4gICAgICBnZXRQb29sSW5mbygpO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIFRocm93IGFuIGVycm9yIGluIGNhc2Ugb2YgbGFja2luZyB0aGUgcG9vbCBpbnN0YW5jZVxyXG4gICAgaWYgKCFwb29sKSB7XHJcbiAgICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcihcclxuICAgICAgICAnW3Bvb2xdIFdvcmsgcmVjZWl2ZWQsIGJ1dCBwb29sIGhhcyBub3QgYmVlbiBzdGFydGVkLicsXHJcbiAgICAgICAgNTAwXHJcbiAgICAgICk7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gVGhlIGFjcXVpcmUgY291bnRlclxyXG4gICAgY29uc3QgYWNxdWlyZUNvdW50ZXIgPSBtZWFzdXJlVGltZSgpO1xyXG5cclxuICAgIC8vIFRyeSB0byBhY3F1aXJlIHRoZSB3b3JrZXIgYWxvbmcgd2l0aCB0aGUgaWQsIHdvcmtzIGNvdW50IGFuZCBwYWdlXHJcbiAgICB0cnkge1xyXG4gICAgICBsb2coNCwgJ1twb29sXSBBY3F1aXJpbmcgYSB3b3JrZXIgaGFuZGxlLicpO1xyXG5cclxuICAgICAgLy8gQWNxdWlyZSBhIHBvb2wgcmVzb3VyY2VcclxuICAgICAgd29ya2VySGFuZGxlID0gYXdhaXQgcG9vbC5hY3F1aXJlKCkucHJvbWlzZTtcclxuXHJcbiAgICAgIC8vIENoZWNrIHRoZSBwYWdlIGFjcXVpcmUgdGltZVxyXG4gICAgICBpZiAob3B0aW9ucy5zZXJ2ZXIuYmVuY2htYXJraW5nKSB7XHJcbiAgICAgICAgbG9nKFxyXG4gICAgICAgICAgNSxcclxuICAgICAgICAgIGBbYmVuY2htYXJrXSAke29wdGlvbnMucmVxdWVzdElkID8gYFJlcXVlc3QgWyR7b3B0aW9ucy5yZXF1ZXN0SWR9XSAtIGAgOiAnJ31gLFxyXG4gICAgICAgICAgYEFjcXVpcmluZyBhIHdvcmtlciBoYW5kbGUgdG9vayAke2FjcXVpcmVDb3VudGVyKCl9bXMuYFxyXG4gICAgICAgICk7XHJcbiAgICAgIH1cclxuICAgIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcihcclxuICAgICAgICBgW3Bvb2xdICR7XHJcbiAgICAgICAgICBvcHRpb25zLnJlcXVlc3RJZCA/IGBSZXF1ZXN0IFske29wdGlvbnMucmVxdWVzdElkfV0gLSBgIDogJydcclxuICAgICAgICB9RXJyb3IgZW5jb3VudGVyZWQgd2hlbiBhY3F1aXJpbmcgYW4gYXZhaWxhYmxlIGVudHJ5OiAke2FjcXVpcmVDb3VudGVyKCl9bXMuYCxcclxuICAgICAgICA0MDBcclxuICAgICAgKS5zZXRFcnJvcihlcnJvcik7XHJcbiAgICB9XHJcbiAgICBsb2coNCwgJ1twb29sXSBBY3F1aXJlZCBhIHdvcmtlciBoYW5kbGUuJyk7XHJcblxyXG4gICAgaWYgKCF3b3JrZXJIYW5kbGUucGFnZSkge1xyXG4gICAgICAvLyBTZXQgdGhlIGB3b3JrTGltaXRgIHRvIGV4Y2VlZGVkIGluIG9yZGVyIHRvIHJlY3JlYXRlIHRoZSByZXNvdXJjZVxyXG4gICAgICB3b3JrZXJIYW5kbGUud29ya0NvdW50ID0gb3B0aW9ucy5wb29sLndvcmtMaW1pdCArIDE7XHJcbiAgICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcihcclxuICAgICAgICAnW3Bvb2xdIFJlc29sdmVkIHdvcmtlciBwYWdlIGlzIGludmFsaWQ6IHRoZSBwb29sIHNldHVwIGlzIHdvbmt5LicsXHJcbiAgICAgICAgNDAwXHJcbiAgICAgICk7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gU2F2ZSB0aGUgc3RhcnQgdGltZVxyXG4gICAgY29uc3Qgd29ya1N0YXJ0ID0gZ2V0TmV3RGF0ZVRpbWUoKTtcclxuXHJcbiAgICBsb2coXHJcbiAgICAgIDQsXHJcbiAgICAgIGBbcG9vbF0gUG9vbCByZXNvdXJjZSBbJHt3b3JrZXJIYW5kbGUuaWR9XSAtIFN0YXJ0aW5nIHdvcmsgb24gdGhpcyBwb29sIGVudHJ5LmBcclxuICAgICk7XHJcblxyXG4gICAgLy8gU3RhcnQgbWVhc3VyaW5nIGV4cG9ydCB0aW1lXHJcbiAgICBjb25zdCBleHBvcnRDb3VudGVyID0gbWVhc3VyZVRpbWUoKTtcclxuXHJcbiAgICAvLyBQZXJmb3JtIGFuIGV4cG9ydCBvbiBhIHB1cHBldGVlciBsZXZlbFxyXG4gICAgY29uc3QgcmVzdWx0ID0gYXdhaXQgcHVwcGV0ZWVyRXhwb3J0KFxyXG4gICAgICB3b3JrZXJIYW5kbGUucGFnZSxcclxuICAgICAgb3B0aW9ucy5leHBvcnQsXHJcbiAgICAgIG9wdGlvbnMuY3VzdG9tTG9naWNcclxuICAgICk7XHJcblxyXG4gICAgLy8gQ2hlY2sgaWYgaXQncyBhbiBlcnJvclxyXG4gICAgaWYgKHJlc3VsdCBpbnN0YW5jZW9mIEVycm9yKSB7XHJcbiAgICAgIC8vIE5PVEU6XHJcbiAgICAgIC8vIElmIHRoZXJlJ3MgYSByYXN0ZXJpemF0aW9uIHRpbWVvdXQsIHdlIHdhbnQgbmVlZCB0byBmbHVzaCB0aGUgcGFnZS5cclxuICAgICAgLy8gVGhpcyBpcyBiZWNhdXNlIHRoZSBwYWdlIG1heSBiZSBpbiBhIHN0YXRlIHdoZXJlIGl0J3Mgd2FpdGluZyBmb3JcclxuICAgICAgLy8gdGhlIHNjcmVlbnNob3QgdG8gZmluaXNoIGV2ZW4gdGhvdWdoIHRoZSB0aW1lb3V0IGhhcyBvY2N1cmVkLlxyXG4gICAgICAvLyBXaGljaCBvZiBjb3Vyc2UgY2F1c2VzIGEgbG90IG9mIGlzc3VlcyB3aXRoIHRoZSBldmVudCBzeXN0ZW0sXHJcbiAgICAgIC8vIGFuZCBwYWdlIGNvbnNpc3RlbmN5LlxyXG4gICAgICAvL1xyXG4gICAgICAvLyBOT1RFOlxyXG4gICAgICAvLyBPbmx5IHBhZ2Uuc2NyZWVuc2hvdCB3aWxsIHRocm93IHRoaXMsIHRpbWVvdXRzIGZvciBQREYncyBhcmVcclxuICAgICAgLy8gaGFuZGxlZCBieSB0aGUgcGFnZS5wZGYgZnVuY3Rpb24gaXRzZWxmLlxyXG4gICAgICAvL1xyXG4gICAgICAvLyAuLi55ZXMsIHRoaXMgaXMgdWdseS5cclxuICAgICAgaWYgKHJlc3VsdC5tZXNzYWdlID09PSAnUmFzdGVyaXphdGlvbiB0aW1lb3V0Jykge1xyXG4gICAgICAgIC8vIFNldCB0aGUgYHdvcmtMaW1pdGAgdG8gZXhjZWVkZWQgaW4gb3JkZXIgdG8gcmVjcmVhdGUgdGhlIHJlc291cmNlXHJcbiAgICAgICAgd29ya2VySGFuZGxlLndvcmtDb3VudCA9IG9wdGlvbnMucG9vbC53b3JrTGltaXQgKyAxO1xyXG4gICAgICAgIHdvcmtlckhhbmRsZS5wYWdlID0gbnVsbDtcclxuICAgICAgfVxyXG5cclxuICAgICAgaWYgKFxyXG4gICAgICAgIHJlc3VsdC5uYW1lID09PSAnVGltZW91dEVycm9yJyB8fFxyXG4gICAgICAgIHJlc3VsdC5tZXNzYWdlID09PSAnUmFzdGVyaXphdGlvbiB0aW1lb3V0J1xyXG4gICAgICApIHtcclxuICAgICAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoXHJcbiAgICAgICAgICBgW3Bvb2xdICR7XHJcbiAgICAgICAgICAgIG9wdGlvbnMucmVxdWVzdElkID8gYFJlcXVlc3QgWyR7b3B0aW9ucy5yZXF1ZXN0SWR9XSAtIGAgOiAnJ1xyXG4gICAgICAgICAgfVJhc3Rlcml6YXRpb24gdGltZW91dDogeW91ciBjaGFydCBtYXkgYmUgdG9vIGNvbXBsZXggb3IgbGFyZ2UsIGFuZCBmYWlsZWQgdG8gcmVuZGVyIHdpdGhpbiB0aGUgYWxsb3R0ZWQgdGltZS5gXHJcbiAgICAgICAgKS5zZXRFcnJvcihyZXN1bHQpO1xyXG4gICAgICB9IGVsc2Uge1xyXG4gICAgICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcihcclxuICAgICAgICAgIGBbcG9vbF0gJHtcclxuICAgICAgICAgICAgb3B0aW9ucy5yZXF1ZXN0SWQgPyBgUmVxdWVzdCBbJHtvcHRpb25zLnJlcXVlc3RJZH1dIC0gYCA6ICcnXHJcbiAgICAgICAgICB9RXJyb3IgZW5jb3VudGVyZWQgZHVyaW5nIGV4cG9ydDogJHtleHBvcnRDb3VudGVyKCl9bXMuYFxyXG4gICAgICAgICkuc2V0RXJyb3IocmVzdWx0KTtcclxuICAgICAgfVxyXG4gICAgfVxyXG5cclxuICAgIC8vIENoZWNrIHRoZSBQdXBwZXRlZXIgZXhwb3J0IHRpbWVcclxuICAgIGlmIChvcHRpb25zLnNlcnZlci5iZW5jaG1hcmtpbmcpIHtcclxuICAgICAgbG9nKFxyXG4gICAgICAgIDUsXHJcbiAgICAgICAgYFtiZW5jaG1hcmtdICR7b3B0aW9ucy5yZXF1ZXN0SWQgPyBgUmVxdWVzdCBbJHtvcHRpb25zLnJlcXVlc3RJZH1dIC0gYCA6ICcnfWAsXHJcbiAgICAgICAgYEV4cG9ydGluZyBhIGNoYXJ0IHN1Y2Vzc2Z1bGx5IHRvb2sgJHtleHBvcnRDb3VudGVyKCl9bXMuYFxyXG4gICAgICApO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIFJlbGVhc2UgdGhlIHJlc291cmNlIGJhY2sgdG8gdGhlIHBvb2xcclxuICAgIHBvb2wucmVsZWFzZSh3b3JrZXJIYW5kbGUpO1xyXG5cclxuICAgIC8vIFVzZWQgZm9yIHN0YXRpc3RpY3MgaW4gYXZlcmFnZVRpbWUgYW5kIHByb2Nlc3NlZFdvcmtDb3VudCwgd2hpY2hcclxuICAgIC8vIGluIHR1cm4gaXMgdXNlZCBieSB0aGUgL2hlYWx0aCByb3V0ZS5cclxuICAgIGNvbnN0IHdvcmtFbmQgPSBnZXROZXdEYXRlVGltZSgpO1xyXG4gICAgY29uc3QgZXhwb3J0VGltZSA9IHdvcmtFbmQgLSB3b3JrU3RhcnQ7XHJcblxyXG4gICAgcG9vbFN0YXRzLnRpbWVTcGVudCArPSBleHBvcnRUaW1lO1xyXG4gICAgcG9vbFN0YXRzLnRpbWVTcGVudEF2ZXJhZ2UgPVxyXG4gICAgICBwb29sU3RhdHMudGltZVNwZW50IC8gKytwb29sU3RhdHMuZXhwb3J0c1BlcmZvcm1lZDtcclxuXHJcbiAgICBsb2coNCwgYFtwb29sXSBXb3JrIGNvbXBsZXRlZCBpbiAke2V4cG9ydFRpbWV9bXMuYCk7XHJcblxyXG4gICAgLy8gT3RoZXJ3aXNlIHJldHVybiB0aGUgcmVzdWx0XHJcbiAgICByZXR1cm4ge1xyXG4gICAgICByZXN1bHQsXHJcbiAgICAgIG9wdGlvbnNcclxuICAgIH07XHJcbiAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICsrcG9vbFN0YXRzLmV4cG9ydHNEcm9wcGVkO1xyXG5cclxuICAgIGlmICh3b3JrZXJIYW5kbGUpIHtcclxuICAgICAgcG9vbC5yZWxlYXNlKHdvcmtlckhhbmRsZSk7XHJcbiAgICB9XHJcblxyXG4gICAgdGhyb3cgZXJyb3I7XHJcbiAgfVxyXG59XHJcblxyXG4vKipcclxuICogUmV0cmlldmVzIHRoZSBjdXJyZW50IHBvb2wgaW5zdGFuY2UuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBnZXRQb29sXHJcbiAqXHJcbiAqIEByZXR1cm5zIHsoT2JqZWN0fG51bGwpfSBUaGUgY3VycmVudCBwb29sIGluc3RhbmNlIGlmIGluaXRpYWxpemVkLCBvciBudWxsXHJcbiAqIGlmIHRoZSBwb29sIGhhcyBub3QgYmVlbiBjcmVhdGVkLlxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIGdldFBvb2woKSB7XHJcbiAgcmV0dXJuIHBvb2w7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBHZXRzIHRoZSBzdGF0aXN0aWMgb2YgYSBwb29sIGluc3RhY2UgYWJvdXQgZXhwb3J0cy5cclxuICpcclxuICogQGZ1bmN0aW9uIGdldFBvb2xTdGF0c1xyXG4gKlxyXG4gKiBAcmV0dXJucyB7T2JqZWN0fSBUaGUgY3VycmVudCBwb29sIHN0YXRpc3RpY3MuXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gZ2V0UG9vbFN0YXRzKCkge1xyXG4gIHJldHVybiBwb29sU3RhdHM7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBSZXRyaWV2ZXMgcG9vbCBpbmZvcm1hdGlvbiBpbiBKU09OIGZvcm1hdCwgaW5jbHVkaW5nIG1pbmltdW0gYW5kIG1heGltdW1cclxuICogd29ya2VycywgYXZhaWxhYmxlIHdvcmtlcnMsIHdvcmtlcnMgaW4gdXNlLCBhbmQgcGVuZGluZyBhY3F1aXJlIHJlcXVlc3RzLlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gZ2V0UG9vbEluZm9KU09OXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtPYmplY3R9IFBvb2wgaW5mb3JtYXRpb24gaW4gSlNPTiBmb3JtYXQuXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gZ2V0UG9vbEluZm9KU09OKCkge1xyXG4gIHJldHVybiB7XHJcbiAgICBtaW46IHBvb2wubWluLFxyXG4gICAgbWF4OiBwb29sLm1heCxcclxuICAgIHVzZWQ6IHBvb2wubnVtVXNlZCgpLFxyXG4gICAgYXZhaWxhYmxlOiBwb29sLm51bUZyZWUoKSxcclxuICAgIGFsbENyZWF0ZWQ6IHBvb2wubnVtVXNlZCgpICsgcG9vbC5udW1GcmVlKCksXHJcbiAgICBwZW5kaW5nQWNxdWlyZXM6IHBvb2wubnVtUGVuZGluZ0FjcXVpcmVzKCksXHJcbiAgICBwZW5kaW5nQ3JlYXRlczogcG9vbC5udW1QZW5kaW5nQ3JlYXRlcygpLFxyXG4gICAgcGVuZGluZ1ZhbGlkYXRpb25zOiBwb29sLm51bVBlbmRpbmdWYWxpZGF0aW9ucygpLFxyXG4gICAgcGVuZGluZ0Rlc3Ryb3lzOiBwb29sLnBlbmRpbmdEZXN0cm95cy5sZW5ndGgsXHJcbiAgICBhYnNvbHV0ZUFsbDpcclxuICAgICAgcG9vbC5udW1Vc2VkKCkgK1xyXG4gICAgICBwb29sLm51bUZyZWUoKSArXHJcbiAgICAgIHBvb2wubnVtUGVuZGluZ0FjcXVpcmVzKCkgK1xyXG4gICAgICBwb29sLm51bVBlbmRpbmdDcmVhdGVzKCkgK1xyXG4gICAgICBwb29sLm51bVBlbmRpbmdWYWxpZGF0aW9ucygpICtcclxuICAgICAgcG9vbC5wZW5kaW5nRGVzdHJveXMubGVuZ3RoXHJcbiAgfTtcclxufVxyXG5cclxuLyoqXHJcbiAqIExvZ3MgaW5mb3JtYXRpb24gYWJvdXQgdGhlIGN1cnJlbnQgc3RhdGUgb2YgdGhlIHBvb2wsIGluY2x1ZGluZyB0aGUgbWluaW11bVxyXG4gKiBhbmQgbWF4aW11bSB3b3JrZXJzLCBhdmFpbGFibGUgd29ya2Vycywgd29ya2VycyBpbiB1c2UsIGFuZCBwZW5kaW5nIGFjcXVpcmVcclxuICogcmVxdWVzdHMuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBnZXRQb29sSW5mb1xyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIGdldFBvb2xJbmZvKCkge1xyXG4gIGNvbnN0IHtcclxuICAgIG1pbixcclxuICAgIG1heCxcclxuICAgIHVzZWQsXHJcbiAgICBhdmFpbGFibGUsXHJcbiAgICBhbGxDcmVhdGVkLFxyXG4gICAgcGVuZGluZ0FjcXVpcmVzLFxyXG4gICAgcGVuZGluZ0NyZWF0ZXMsXHJcbiAgICBwZW5kaW5nVmFsaWRhdGlvbnMsXHJcbiAgICBwZW5kaW5nRGVzdHJveXMsXHJcbiAgICBhYnNvbHV0ZUFsbFxyXG4gIH0gPSBnZXRQb29sSW5mb0pTT04oKTtcclxuXHJcbiAgbG9nKDUsIGBbcG9vbF0gVGhlIG1pbmltdW0gbnVtYmVyIG9mIHJlc291cmNlcyBhbGxvd2VkIGJ5IHBvb2w6ICR7bWlufS5gKTtcclxuICBsb2coNSwgYFtwb29sXSBUaGUgbWF4aW11bSBudW1iZXIgb2YgcmVzb3VyY2VzIGFsbG93ZWQgYnkgcG9vbDogJHttYXh9LmApO1xyXG4gIGxvZyg1LCBgW3Bvb2xdIFRoZSBudW1iZXIgb2YgdXNlZCByZXNvdXJjZXM6ICR7dXNlZH0uYCk7XHJcbiAgbG9nKDUsIGBbcG9vbF0gVGhlIG51bWJlciBvZiBmcmVlIHJlc291cmNlczogJHthdmFpbGFibGV9LmApO1xyXG4gIGxvZyhcclxuICAgIDUsXHJcbiAgICBgW3Bvb2xdIFRoZSBudW1iZXIgb2YgYWxsIGNyZWF0ZWQgKHVzZWQgYW5kIGZyZWUpIHJlc291cmNlczogJHthbGxDcmVhdGVkfS5gXHJcbiAgKTtcclxuICBsb2coXHJcbiAgICA1LFxyXG4gICAgYFtwb29sXSBUaGUgbnVtYmVyIG9mIHJlc291cmNlcyB3YWl0aW5nIHRvIGJlIGFjcXVpcmVkOiAke3BlbmRpbmdBY3F1aXJlc30uYFxyXG4gICk7XHJcbiAgbG9nKFxyXG4gICAgNSxcclxuICAgIGBbcG9vbF0gVGhlIG51bWJlciBvZiByZXNvdXJjZXMgd2FpdGluZyB0byBiZSBjcmVhdGVkOiAke3BlbmRpbmdDcmVhdGVzfS5gXHJcbiAgKTtcclxuICBsb2coXHJcbiAgICA1LFxyXG4gICAgYFtwb29sXSBUaGUgbnVtYmVyIG9mIHJlc291cmNlcyB3YWl0aW5nIHRvIGJlIHZhbGlkYXRlZDogJHtwZW5kaW5nVmFsaWRhdGlvbnN9LmBcclxuICApO1xyXG4gIGxvZyhcclxuICAgIDUsXHJcbiAgICBgW3Bvb2xdIFRoZSBudW1iZXIgb2YgcmVzb3VyY2VzIHdhaXRpbmcgdG8gYmUgZGVzdHJveWVkOiAke3BlbmRpbmdEZXN0cm95c30uYFxyXG4gICk7XHJcbiAgbG9nKDUsIGBbcG9vbF0gVGhlIG51bWJlciBvZiBhbGwgcmVzb3VyY2VzOiAke2Fic29sdXRlQWxsfS5gKTtcclxufVxyXG5cclxuLyoqXHJcbiAqIEZhY3RvcnkgZnVuY3Rpb24gdGhhdCByZXR1cm5zIGFuIG9iamVjdCB3aXRoIGBjcmVhdGVgLCBgdmFsaWRhdGVgLFxyXG4gKiBhbmQgYGRlc3Ryb3lgIGZ1bmN0aW9ucyBmb3IgdGhlIHBvb2wgaW5zdGFuY2UuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBfZmFjdG9yeVxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gcG9vbE9wdGlvbnMgLSBUaGUgY29uZmlndXJhdGlvbiBvYmplY3QgY29udGFpbmluZyBgcG9vbGBcclxuICogb3B0aW9ucy5cclxuICovXHJcbmZ1bmN0aW9uIF9mYWN0b3J5KHBvb2xPcHRpb25zKSB7XHJcbiAgcmV0dXJuIHtcclxuICAgIC8qKlxyXG4gICAgICogQ3JlYXRlcyBhIG5ldyB3b3JrZXIgcGFnZSBmb3IgdGhlIGV4cG9ydCBwb29sLlxyXG4gICAgICpcclxuICAgICAqIEBhc3luY1xyXG4gICAgICogQGZ1bmN0aW9uIGNyZWF0ZVxyXG4gICAgICpcclxuICAgICAqIEByZXR1cm5zIHtQcm9taXNlPE9iamVjdD59IEEgUHJvbWlzZSB0aGF0IHJlc29sdmVzIHRvIGFuIG9iamVjdFxyXG4gICAgICogY29udGFpbmluZyB0aGUgd29ya2VyIElELCBhIHJlZmVyZW5jZSB0byB0aGUgYnJvd3NlciBwYWdlLCBhbmQgaW5pdGlhbFxyXG4gICAgICogd29yayBjb3VudC5cclxuICAgICAqXHJcbiAgICAgKiBAdGhyb3dzIHtFeHBvcnRFcnJvcn0gVGhyb3dzIGFuIGBFeHBvcnRFcnJvcmAgaWYgdGhlcmUgaXMgYW4gZXJyb3IgZHVyaW5nXHJcbiAgICAgKiB0aGUgY3JlYXRpb24gb2YgdGhlIG5ldyBwYWdlLlxyXG4gICAgICovXHJcbiAgICBjcmVhdGU6IGFzeW5jICgpID0+IHtcclxuICAgICAgLy8gSW5pdCB0aGUgcmVzb3VyY2Ugd2l0aCB1bmlxdWUgaWQgYW5kIHdvcmsgY291bnRcclxuICAgICAgY29uc3QgcG9vbFJlc291cmNlID0ge1xyXG4gICAgICAgIGlkOiB1dWlkKCksXHJcbiAgICAgICAgLy8gVHJ5IHRvIGRpc3RyaWJ1dGUgdGhlIGluaXRpYWwgd29yayBjb3VudFxyXG4gICAgICAgIHdvcmtDb3VudDogTWF0aC5yb3VuZChNYXRoLnJhbmRvbSgpICogKHBvb2xPcHRpb25zLndvcmtMaW1pdCAvIDIpKVxyXG4gICAgICB9O1xyXG5cclxuICAgICAgdHJ5IHtcclxuICAgICAgICAvLyBTdGFydCBtZWFzdXJpbmcgYSBwYWdlIGNyZWF0aW9uIHRpbWVcclxuICAgICAgICBjb25zdCBzdGFydERhdGUgPSBnZXROZXdEYXRlVGltZSgpO1xyXG5cclxuICAgICAgICAvLyBDcmVhdGUgYSBuZXcgcGFnZVxyXG4gICAgICAgIGF3YWl0IG5ld1BhZ2UocG9vbFJlc291cmNlKTtcclxuXHJcbiAgICAgICAgLy8gTWVhc3VyZSB0aGUgdGltZSBvZiBmdWxsIGNyZWF0aW9uIGFuZCBjb25maWd1cmF0aW9uIG9mIGEgcGFnZVxyXG4gICAgICAgIGxvZyhcclxuICAgICAgICAgIDMsXHJcbiAgICAgICAgICBgW3Bvb2xdIFBvb2wgcmVzb3VyY2UgWyR7cG9vbFJlc291cmNlLmlkfV0gLSBTdWNjZXNzZnVsbHkgY3JlYXRlZCBhIHdvcmtlciwgdG9vayAke1xyXG4gICAgICAgICAgICBnZXROZXdEYXRlVGltZSgpIC0gc3RhcnREYXRlXHJcbiAgICAgICAgICB9bXMuYFxyXG4gICAgICAgICk7XHJcblxyXG4gICAgICAgIC8vIFJldHVybiByZWFkeSBwb29sIHJlc291cmNlXHJcbiAgICAgICAgcmV0dXJuIHBvb2xSZXNvdXJjZTtcclxuICAgICAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICAgICBsb2coXHJcbiAgICAgICAgICAzLFxyXG4gICAgICAgICAgYFtwb29sXSBQb29sIHJlc291cmNlIFske3Bvb2xSZXNvdXJjZS5pZH1dIC0gRXJyb3IgZW5jb3VudGVyZWQgd2hlbiBjcmVhdGluZyBhIG5ldyBwYWdlLmBcclxuICAgICAgICApO1xyXG4gICAgICAgIHRocm93IGVycm9yO1xyXG4gICAgICB9XHJcbiAgICB9LFxyXG5cclxuICAgIC8qKlxyXG4gICAgICogVmFsaWRhdGVzIGEgd29ya2VyIHBhZ2UgaW4gdGhlIGV4cG9ydCBwb29sLCBjaGVja2luZyBpZiBpdCBoYXMgZXhjZWVkZWRcclxuICAgICAqIHRoZSB3b3JrIGxpbWl0LlxyXG4gICAgICpcclxuICAgICAqIEBhc3luY1xyXG4gICAgICogQGZ1bmN0aW9uIHZhbGlkYXRlXHJcbiAgICAgKlxyXG4gICAgICogQHBhcmFtIHtPYmplY3R9IHBvb2xSZXNvdXJjZSAtIFRoZSBoYW5kbGUgdG8gdGhlIHdvcmtlciwgY29udGFpbmluZ1xyXG4gICAgICogdGhlIHdvcmtlcidzIElELCBhIHJlZmVyZW5jZSB0byB0aGUgYnJvd3NlciBwYWdlLCBhbmQgd29yayBjb3VudC5cclxuICAgICAqXHJcbiAgICAgKiBAcmV0dXJucyB7UHJvbWlzZTxib29sZWFuPn0gQSBQcm9taXNlIHRoYXQgcmVzb2x2ZXMgdG8gdHJ1ZSBpZiB0aGUgd29ya2VyXHJcbiAgICAgKiBpcyB2YWxpZCBhbmQgd2l0aGluIHRoZSB3b3JrIGxpbWl0OyBvdGhlcndpc2UsIHRvIGZhbHNlLlxyXG4gICAgICovXHJcbiAgICB2YWxpZGF0ZTogYXN5bmMgKHBvb2xSZXNvdXJjZSkgPT4ge1xyXG4gICAgICAvLyBOT1RFOlxyXG4gICAgICAvLyBJbiBjZXJ0YWluIGNhc2VzIGFjcXVpcmluZyB0aHJvd3MgYSBUYXJnZXRDbG9zZUVycm9yLCB3aGljaCBtYXlcclxuICAgICAgLy8gYmUgY2F1c2VkIGJ5IHR3byB0aGluZ3M6XHJcbiAgICAgIC8vIC0gVGhlIHBhZ2UgaXMgY2xvc2VkIGFuZCBhdHRlbXB0ZWQgdG8gYmUgcmV1c2VkLlxyXG4gICAgICAvLyAtIExvc3QgY29udGFjdCB3aXRoIHRoZSBicm93c2VyLlxyXG4gICAgICAvL1xyXG4gICAgICAvLyBXaGF0IHdlJ3JlIHNlZWluZyBpbiBsb2dzIGlzIHRoYXQgc3VjY2Vzc2l2ZSBleHBvcnRzIHR5cGljYWxseVxyXG4gICAgICAvLyBzdWNjZWVkcywgYW5kIHRoZSBzZXJ2ZXIgcmVjb3ZlcnMsIGluZGljYXRpbmcgdGhhdCBpdCdzIGxpa2VseVxyXG4gICAgICAvLyB0aGUgZmlyc3QgY2FzZS4gVGhpcyBpcyBhbiBhdHRlbXB0IGF0IGFsbGlldmF0aW5nIHRoZSBpc3N1ZSBieVxyXG4gICAgICAvLyBzaW1wbHkgbm90IHZhbGlkYXRpbmcgdGhlIHdvcmtlciBpZiB0aGUgcGFnZSBpcyBudWxsIG9yIGNsb3NlZC5cclxuICAgICAgLy9cclxuICAgICAgLy8gVGhlIGFjdHVhbCByZXN1bHQgZnJvbSB3aGVuIHRoaXMgaGFwcGVuZWQsIHdhcyB0aGF0IGEgd29ya2VyIHdvdWxkXHJcbiAgICAgIC8vIGJlIGNvbXBsZXRlbHkgbG9ja2VkLCBzdG9wcGluZyBpdCBmcm9tIGJlaW5nIGFjcXVpcmVkIHVudGlsXHJcbiAgICAgIC8vIGl0cyB3b3JrIGNvdW50IHJlYWNoZWQgdGhlIGxpbWl0LlxyXG5cclxuICAgICAgLy8gQ2hlY2sgaWYgdGhlIGBwYWdlYCBpcyB2YWxpZFxyXG4gICAgICBpZiAoIXBvb2xSZXNvdXJjZS5wYWdlKSB7XHJcbiAgICAgICAgbG9nKFxyXG4gICAgICAgICAgMyxcclxuICAgICAgICAgIGBbcG9vbF0gUG9vbCByZXNvdXJjZSBbJHtwb29sUmVzb3VyY2UuaWR9XSAtIFZhbGlkYXRpb24gZmFpbGVkIChubyB2YWxpZCBwYWdlIGlzIGZvdW5kKS5gXHJcbiAgICAgICAgKTtcclxuICAgICAgICByZXR1cm4gZmFsc2U7XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIC8vIENoZWNrIGlmIHRoZSBgcGFnZWAgaXMgY2xvc2VkXHJcbiAgICAgIGlmIChwb29sUmVzb3VyY2UucGFnZS5pc0Nsb3NlZCgpKSB7XHJcbiAgICAgICAgbG9nKFxyXG4gICAgICAgICAgMyxcclxuICAgICAgICAgIGBbcG9vbF0gUG9vbCByZXNvdXJjZSBbJHtwb29sUmVzb3VyY2UuaWR9XSAtIFZhbGlkYXRpb24gZmFpbGVkIChwYWdlIGlzIGNsb3NlZCBvciBpbnZhbGlkKS5gXHJcbiAgICAgICAgKTtcclxuICAgICAgICByZXR1cm4gZmFsc2U7XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIC8vIENoZWNrIGlmIHRoZSBgbWFpbkZyYW1lYCBpcyBkZXRhY2hlZFxyXG4gICAgICBpZiAocG9vbFJlc291cmNlLnBhZ2UubWFpbkZyYW1lKCkuZGV0YWNoZWQpIHtcclxuICAgICAgICBsb2coXHJcbiAgICAgICAgICAzLFxyXG4gICAgICAgICAgYFtwb29sXSBQb29sIHJlc291cmNlIFske3Bvb2xSZXNvdXJjZS5pZH1dIC0gVmFsaWRhdGlvbiBmYWlsZWQgKHBhZ2UncyBmcmFtZSBpcyBkZXRhY2hlZCkuYFxyXG4gICAgICAgICk7XHJcbiAgICAgICAgcmV0dXJuIGZhbHNlO1xyXG4gICAgICB9XHJcblxyXG4gICAgICAvLyBDaGVjayBpZiB0aGUgYHdvcmtMaW1pdGAgaXMgZXhjZWVkZWRcclxuICAgICAgaWYgKFxyXG4gICAgICAgIHBvb2xPcHRpb25zLndvcmtMaW1pdCAmJlxyXG4gICAgICAgICsrcG9vbFJlc291cmNlLndvcmtDb3VudCA+IHBvb2xPcHRpb25zLndvcmtMaW1pdFxyXG4gICAgICApIHtcclxuICAgICAgICBsb2coXHJcbiAgICAgICAgICAzLFxyXG4gICAgICAgICAgYFtwb29sXSBQb29sIHJlc291cmNlIFske3Bvb2xSZXNvdXJjZS5pZH1dIC0gVmFsaWRhdGlvbiBmYWlsZWQgKGV4Y2VlZGVkIHRoZSAke3Bvb2xPcHRpb25zLndvcmtMaW1pdH0gd29ya3MgcGVyIHJlc291cmNlIGxpbWl0KS5gXHJcbiAgICAgICAgKTtcclxuICAgICAgICByZXR1cm4gZmFsc2U7XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIC8vIFRoZSBgcG9vbFJlc291cmNlYCBpcyB2YWxpZGF0ZWRcclxuICAgICAgcmV0dXJuIHRydWU7XHJcbiAgICB9LFxyXG5cclxuICAgIC8qKlxyXG4gICAgICogRGVzdHJveXMgYSB3b3JrZXIgZW50cnkgaW4gdGhlIGV4cG9ydCBwb29sLCBjbG9zaW5nIGl0cyBhc3NvY2lhdGVkIHBhZ2UuXHJcbiAgICAgKlxyXG4gICAgICogQGFzeW5jXHJcbiAgICAgKiBAZnVuY3Rpb24gZGVzdHJveVxyXG4gICAgICpcclxuICAgICAqIEBwYXJhbSB7T2JqZWN0fSBwb29sUmVzb3VyY2UgLSBUaGUgaGFuZGxlIHRvIHRoZSB3b3JrZXIsIGNvbnRhaW5pbmdcclxuICAgICAqIHRoZSB3b3JrZXIncyBJRCwgYSByZWZlcmVuY2UgdG8gdGhlIGJyb3dzZXIgcGFnZSwgYW5kIHdvcmsgY291bnQuXHJcbiAgICAgKi9cclxuICAgIGRlc3Ryb3k6IGFzeW5jIChwb29sUmVzb3VyY2UpID0+IHtcclxuICAgICAgbG9nKFxyXG4gICAgICAgIDMsXHJcbiAgICAgICAgYFtwb29sXSBQb29sIHJlc291cmNlIFske3Bvb2xSZXNvdXJjZS5pZH1dIC0gRGVzdHJveWluZyBhIHdvcmtlci5gXHJcbiAgICAgICk7XHJcblxyXG4gICAgICBpZiAocG9vbFJlc291cmNlLnBhZ2UgJiYgIXBvb2xSZXNvdXJjZS5wYWdlLmlzQ2xvc2VkKCkpIHtcclxuICAgICAgICB0cnkge1xyXG4gICAgICAgICAgLy8gUmVtb3ZlIGFsbCBhdHRhY2hlZCBldmVudCBsaXN0ZW5lcnMgZnJvbSB0aGUgcmVzb3VyY2VcclxuICAgICAgICAgIHBvb2xSZXNvdXJjZS5wYWdlLnJlbW92ZUFsbExpc3RlbmVycygncGFnZWVycm9yJyk7XHJcbiAgICAgICAgICBwb29sUmVzb3VyY2UucGFnZS5yZW1vdmVBbGxMaXN0ZW5lcnMoJ2NvbnNvbGUnKTtcclxuICAgICAgICAgIHBvb2xSZXNvdXJjZS5wYWdlLnJlbW92ZUFsbExpc3RlbmVycygnZnJhbWVkZXRhY2hlZCcpO1xyXG5cclxuICAgICAgICAgIC8vIFdlIG5lZWQgdG8gd2FpdCBhcm91bmQgZm9yIHRoaXNcclxuICAgICAgICAgIGF3YWl0IHBvb2xSZXNvdXJjZS5wYWdlLmNsb3NlKCk7XHJcbiAgICAgICAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICAgICAgIGxvZyhcclxuICAgICAgICAgICAgMyxcclxuICAgICAgICAgICAgYFtwb29sXSBQb29sIHJlc291cmNlIFske3Bvb2xSZXNvdXJjZS5pZH1dIC0gUGFnZSBjb3VsZCBub3QgYmUgY2xvc2VkIHVwb24gZGVzdHJveWluZy5gXHJcbiAgICAgICAgICApO1xyXG4gICAgICAgICAgdGhyb3cgZXJyb3I7XHJcbiAgICAgICAgfVxyXG4gICAgICB9XHJcbiAgICB9XHJcbiAgfTtcclxufVxyXG5cclxuZXhwb3J0IGRlZmF1bHQge1xyXG4gIGluaXRQb29sLFxyXG4gIGtpbGxQb29sLFxyXG4gIHBvc3RXb3JrLFxyXG4gIGdldFBvb2wsXHJcbiAgZ2V0UG9vbFN0YXRzLFxyXG4gIGdldFBvb2xJbmZvLFxyXG4gIGdldFBvb2xJbmZvSlNPTlxyXG59O1xyXG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxyXG5cclxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXHJcblxyXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNSwgSGlnaHNvZnRcclxuXHJcbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cclxuXHJcbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxyXG5cclxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxyXG5cclxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cclxuXHJcbi8qKlxyXG4gKiBAb3ZlcnZpZXcgVXNlZCB0byBzYW5pdGl6ZSB0aGUgc3RyaW5ncyBjb21pbmcgZnJvbSB0aGUgZXhwb3J0aW5nIG1vZHVsZVxyXG4gKiB0byBwcmV2ZW50IFhTUyBhdHRhY2tzICh3aXRoIHRoZSBET01QdXJpZnkgbGlicmFyeSkuXHJcbiAqL1xyXG5cclxuaW1wb3J0IERPTVB1cmlmeSBmcm9tICdkb21wdXJpZnknO1xyXG5pbXBvcnQgeyBKU0RPTSB9IGZyb20gJ2pzZG9tJztcclxuXHJcbi8qKlxyXG4gKiBTYW5pdGl6ZXMgYSBnaXZlbiBIVE1MIHN0cmluZyBieSByZW1vdmluZyA8c2NyaXB0PiB0YWdzLiBUaGlzIGZ1bmN0aW9uIHVzZXNcclxuICogYSByZWd1bGFyIGV4cHJlc3Npb24gdG8gZmluZCBhbmQgcmVtb3ZlIGFsbCBvY2N1cnJlbmNlcyBvZiA8c2NyaXB0Pjwvc2NyaXB0PlxyXG4gKiB0YWdzIGFuZCBhbnkgY29udGVudCB3aXRoaW4gdGhlbS5cclxuICpcclxuICogQGZ1bmN0aW9uIHNhbml0aXplXHJcbiAqXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSBpbnB1dCAtIFRoZSBIVE1MIHN0cmluZyB0byBiZSBzYW5pdGl6ZWQuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtzdHJpbmd9IFRoZSBzYW5pdGl6ZWQgSFRNTCBzdHJpbmcuXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gc2FuaXRpemUoaW5wdXQpIHtcclxuICAvLyBHZXQgdGhlIHZpcnR1YWwgRE9NXHJcbiAgY29uc3Qgd2luZG93ID0gbmV3IEpTRE9NKCcnKS53aW5kb3c7XHJcblxyXG4gIC8vIENyZWF0ZSBhIHB1cmlmeWluZyBpbnN0YW5jZVxyXG4gIGNvbnN0IHB1cmlmeSA9IERPTVB1cmlmeSh3aW5kb3cpO1xyXG5cclxuICAvLyBSZXR1cm4gc2FuaXRpemVkIGlucHV0XHJcbiAgcmV0dXJuIHB1cmlmeS5zYW5pdGl6ZShpbnB1dCwgeyBBRERfVEFHUzogWydmb3JlaWduT2JqZWN0J10gfSk7XHJcbn1cclxuXHJcbmV4cG9ydCBkZWZhdWx0IHtcclxuICBzYW5pdGl6ZVxyXG59O1xyXG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxyXG5cclxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXHJcblxyXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNSwgSGlnaHNvZnRcclxuXHJcbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cclxuXHJcbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxyXG5cclxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxyXG5cclxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cclxuXHJcbi8qKlxyXG4gKiBAb3ZlcnZpZXcgVGhpcyBtb2R1bGUgcHJvdmlkZXMgZnVuY3Rpb25zIHRvIHByZXBhcmUgZm9yIHRoZSBleHBvcnRpbmcgY2hhcnRzXHJcbiAqIGludG8gdmFyaW91cyBpbWFnZSBvdXRwdXQgZm9ybWF0cyBzdWNoIGFzIEpQRUcsIFBORywgUERGLCBhbmQgU1ZHcy5cclxuICogSXQgc3VwcG9ydHMgc2luZ2xlIGFuZCBiYXRjaCBleHBvcnQgb3BlcmF0aW9ucyBhbmQgYWxsb3dzIGN1c3RvbWl6YXRpb25cclxuICogdGhyb3VnaCBvcHRpb25zIHBhc3NlZCBmcm9tIGNvbmZpZ3VyYXRpb25zIG9yIEFQSXMuXHJcbiAqL1xyXG5cclxuaW1wb3J0IHsgcmVhZEZpbGVTeW5jLCB3cml0ZUZpbGVTeW5jIH0gZnJvbSAnZnMnO1xyXG5cclxuaW1wb3J0IHtcclxuICBnZXRPcHRpb25zLFxyXG4gIGlzQWxsb3dlZENvbmZpZyxcclxuICBtZXJnZU9wdGlvbnMsXHJcbiAgdmFsaWRhdGVPcHRpb24sXHJcbiAgdmFsaWRhdGVPcHRpb25zXHJcbn0gZnJvbSAnLi9jb25maWcuanMnO1xyXG5pbXBvcnQgeyBsb2csIGxvZ1dpdGhTdGFjayB9IGZyb20gJy4vbG9nZ2VyLmpzJztcclxuaW1wb3J0IHsgZ2V0UG9vbFN0YXRzLCBraWxsUG9vbCwgcG9zdFdvcmsgfSBmcm9tICcuL3Bvb2wuanMnO1xyXG5pbXBvcnQgeyBzYW5pdGl6ZSB9IGZyb20gJy4vc2FuaXRpemUuanMnO1xyXG5pbXBvcnQge1xyXG4gIGRlZXBDb3B5LFxyXG4gIGZpeENvbnN0cixcclxuICBmaXhPdXRmaWxlLFxyXG4gIGZpeFR5cGUsXHJcbiAgZ2V0QWJzb2x1dGVQYXRoLFxyXG4gIGdldEJhc2U2NCxcclxuICBpc09iamVjdCxcclxuICByb3VuZE51bWJlcixcclxuICB3cmFwQXJvdW5kXHJcbn0gZnJvbSAnLi91dGlscy5qcyc7XHJcblxyXG5pbXBvcnQgRXhwb3J0RXJyb3IgZnJvbSAnLi9lcnJvcnMvRXhwb3J0RXJyb3IuanMnO1xyXG5cclxuLy8gVGhlIGdsb2JhbCBmbGFnIGZvciB0aGUgY29kZSBleGVjdXRpb24gcGVybWlzc2lvblxyXG5sZXQgYWxsb3dDb2RlRXhlY3V0aW9uID0gZmFsc2U7XHJcblxyXG4vKipcclxuICogU3RhcnRzIGEgc2luZ2xlIGV4cG9ydCBwcm9jZXNzIGJhc2VkIG9uIHRoZSBzcGVjaWZpZWQgb3B0aW9ucyBhbmQgc2F2ZXNcclxuICogdGhlIHJlc3VsdGluZyBpbWFnZSB0byB0aGUgcHJvdmlkZWQgb3V0cHV0IGZpbGUuXHJcbiAqXHJcbiAqIEBhc3luY1xyXG4gKiBAZnVuY3Rpb24gc2luZ2xlRXhwb3J0XHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBvcHRpb25zIC0gVGhlIGBvcHRpb25zYCBvYmplY3QsIHdoaWNoIHNob3VsZCBpbmNsdWRlIHNldHRpbmdzXHJcbiAqIGZyb20gdGhlIGBleHBvcnRgIGFuZCBgY3VzdG9tTG9naWNgIHNlY3Rpb25zLiBJdCBjYW4gYmUgYSBwYXJ0aWFsIG9yIGNvbXBsZXRlXHJcbiAqIHNldCBvZiBvcHRpb25zIGZyb20gdGhlc2Ugc2VjdGlvbnMuIFRoZSBvYmplY3QgbXVzdCBjb250YWluIGF0IGxlYXN0IG9uZVxyXG4gKiBvZiB0aGUgZm9sbG93aW5nIGBleHBvcnRgIHByb3BlcnRpZXM6IGBpbmZpbGVgLCBgaW5zdHJgLCBgb3B0aW9uc2AsIG9yIGBzdmdgXHJcbiAqIHRvIGdlbmVyYXRlIGEgdmFsaWQgaW1hZ2UuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtQcm9taXNlPHZvaWQ+fSBBIFByb21pc2UgdGhhdCByZXNvbHZlcyBvbmNlIHRoZSBzaW5nbGUgZXhwb3J0XHJcbiAqIHByb2Nlc3MgaXMgY29tcGxldGVkLlxyXG4gKlxyXG4gKiBAdGhyb3dzIHtFeHBvcnRFcnJvcn0gVGhyb3dzIGFuIGBFeHBvcnRFcnJvcmAgaWYgYW4gZXJyb3Igb2NjdXJzIGR1cmluZ1xyXG4gKiB0aGUgc2luZ2xlIGV4cG9ydCBwcm9jZXNzLlxyXG4gKi9cclxuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIHNpbmdsZUV4cG9ydChvcHRpb25zKSB7XHJcbiAgLy8gQ2hlY2sgaWYgdGhlIGV4cG9ydCBtYWtlcyBzZW5zZVxyXG4gIGlmIChvcHRpb25zICYmIG9wdGlvbnMuZXhwb3J0KSB7XHJcbiAgICAvLyBWYWxpZGF0ZSBzaW5nbGUgZXhwb3J0IG9wdGlvbnNcclxuICAgIG9wdGlvbnMgPSB2YWxpZGF0ZU9wdGlvbnMob3B0aW9ucyk7XHJcblxyXG4gICAgLy8gUGVyZm9ybSBhbiBleHBvcnRcclxuICAgIGF3YWl0IHN0YXJ0RXhwb3J0KFxyXG4gICAgICB7IGV4cG9ydDogb3B0aW9ucy5leHBvcnQsIGN1c3RvbUxvZ2ljOiBvcHRpb25zLmN1c3RvbUxvZ2ljIH0sXHJcbiAgICAgIGFzeW5jIChlcnJvciwgZGF0YSkgPT4ge1xyXG4gICAgICAgIC8vIEV4aXQgcHJvY2VzcyB3aGVuIGVycm9yIGV4aXN0c1xyXG4gICAgICAgIGlmIChlcnJvcikge1xyXG4gICAgICAgICAgdGhyb3cgZXJyb3I7XHJcbiAgICAgICAgfVxyXG5cclxuICAgICAgICAvLyBHZXQgdGhlIGBiNjRgLCBgb3V0ZmlsZWAsIGFuZCBgdHlwZWAgZm9yIGEgY2hhcnRcclxuICAgICAgICBjb25zdCB7IGI2NCwgb3V0ZmlsZSwgdHlwZSB9ID0gZGF0YS5vcHRpb25zLmV4cG9ydDtcclxuXHJcbiAgICAgICAgLy8gU2F2ZSB0aGUgcmVzdWx0XHJcbiAgICAgICAgdHJ5IHtcclxuICAgICAgICAgIGlmIChiNjQpIHtcclxuICAgICAgICAgICAgLy8gQXMgYSBCYXNlNjQgc3RyaW5nIHRvIGEgdHh0IGZpbGVcclxuICAgICAgICAgICAgd3JpdGVGaWxlU3luYyhcclxuICAgICAgICAgICAgICBgJHtvdXRmaWxlLnNwbGl0KCcuJykuc2hpZnQoKSB8fCAnY2hhcnQnfS50eHRgLFxyXG4gICAgICAgICAgICAgIGdldEJhc2U2NChkYXRhLnJlc3VsdCwgdHlwZSlcclxuICAgICAgICAgICAgKTtcclxuICAgICAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgICAgIC8vIEFzIGEgY29ycmVjdCBpbWFnZSBmb3JtYXRcclxuICAgICAgICAgICAgd3JpdGVGaWxlU3luYyhcclxuICAgICAgICAgICAgICBvdXRmaWxlIHx8IGBjaGFydC4ke3R5cGV9YCxcclxuICAgICAgICAgICAgICB0eXBlICE9PSAnc3ZnJyA/IEJ1ZmZlci5mcm9tKGRhdGEucmVzdWx0LCAnYmFzZTY0JykgOiBkYXRhLnJlc3VsdFxyXG4gICAgICAgICAgICApO1xyXG4gICAgICAgICAgfVxyXG4gICAgICAgIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICAgICAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoXHJcbiAgICAgICAgICAgICdbY2hhcnRdIEVycm9yIHdoaWxlIHNhdmluZyBhIGNoYXJ0LicsXHJcbiAgICAgICAgICAgIDUwMFxyXG4gICAgICAgICAgKS5zZXRFcnJvcihlcnJvcik7XHJcbiAgICAgICAgfVxyXG5cclxuICAgICAgICAvLyBLaWxsIHBvb2wgYW5kIGNsb3NlIGJyb3dzZXIgYWZ0ZXIgZmluaXNoaW5nIHNpbmdsZSBleHBvcnRcclxuICAgICAgICBhd2FpdCBraWxsUG9vbCgpO1xyXG4gICAgICB9XHJcbiAgICApO1xyXG4gIH0gZWxzZSB7XHJcbiAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoXHJcbiAgICAgICdbY2hhcnRdIE5vIGV4cGVjdGVkIGBleHBvcnRgIG9wdGlvbnMgd2VyZSBmb3VuZC4gUGxlYXNlIHByb3ZpZGUgb25lIG9mIHRoZSBmb2xsb3dpbmcgb3B0aW9uczogYGluZmlsZWAsIGBpbnN0cmAsIGBvcHRpb25zYCwgb3IgYHN2Z2AgdG8gZ2VuZXJhdGUgYSB2YWxpZCBpbWFnZS4nLFxyXG4gICAgICA0MDBcclxuICAgICk7XHJcbiAgfVxyXG59XHJcblxyXG4vKipcclxuICogU3RhcnRzIGEgYmF0Y2ggZXhwb3J0IHByb2Nlc3MgZm9yIG11bHRpcGxlIGNoYXJ0cyBiYXNlZCBvbiBpbmZvcm1hdGlvblxyXG4gKiBwcm92aWRlZCBpbiB0aGUgYGJhdGNoYCBvcHRpb24uIFRoZSBgYmF0Y2hgIGlzIGEgc3RyaW5nIGluIHRoZSBmb2xsb3dpbmdcclxuICogZm9ybWF0OiBcImluZmlsZTEuanNvbj1vdXRmaWxlMS5wbmc7aW5maWxlMi5qc29uPW91dGZpbGUyLnBuZzsuLi5cIi4gUmVzdWx0c1xyXG4gKiBhcmUgc2F2ZWQgdG8gdGhlIHNwZWNpZmllZCBvdXRwdXQgZmlsZXMuXHJcbiAqXHJcbiAqIEBhc3luY1xyXG4gKiBAZnVuY3Rpb24gYmF0Y2hFeHBvcnRcclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IG9wdGlvbnMgLSBUaGUgYG9wdGlvbnNgIG9iamVjdCwgd2hpY2ggc2hvdWxkIGluY2x1ZGUgc2V0dGluZ3NcclxuICogZnJvbSB0aGUgYGV4cG9ydGAgYW5kIGBjdXN0b21Mb2dpY2Agc2VjdGlvbnMuIEl0IGNhbiBiZSBhIHBhcnRpYWwgb3IgY29tcGxldGVcclxuICogc2V0IG9mIG9wdGlvbnMgZnJvbSB0aGVzZSBzZWN0aW9ucy4gSXQgbXVzdCBjb250YWluIHRoZSBgYmF0Y2hgIG9wdGlvbiBmcm9tXHJcbiAqIHRoZSBgZXhwb3J0YCBzZWN0aW9uIHRvIGdlbmVyYXRlIHZhbGlkIGltYWdlcy5cclxuICpcclxuICogQHJldHVybnMge1Byb21pc2U8dm9pZD59IEEgUHJvbWlzZSB0aGF0IHJlc29sdmVzIG9uY2UgdGhlIGJhdGNoIGV4cG9ydFxyXG4gKiBwcm9jZXNzZXMgYXJlIGNvbXBsZXRlZC5cclxuICpcclxuICogQHRocm93cyB7RXhwb3J0RXJyb3J9IFRocm93cyBhbiBgRXhwb3J0RXJyb3JgIGlmIGFuIGVycm9yIG9jY3VycyBkdXJpbmdcclxuICogYW55IG9mIHRoZSBiYXRjaCBleHBvcnQgcHJvY2Vzcy5cclxuICovXHJcbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBiYXRjaEV4cG9ydChvcHRpb25zKSB7XHJcbiAgLy8gQ2hlY2sgaWYgdGhlIGV4cG9ydCBtYWtlcyBzZW5zZVxyXG4gIGlmIChvcHRpb25zICYmIG9wdGlvbnMuZXhwb3J0ICYmIG9wdGlvbnMuZXhwb3J0LmJhdGNoKSB7XHJcbiAgICAvLyBWYWxpZGF0ZSBiYXRjaCBleHBvcnQgb3B0aW9uc1xyXG4gICAgb3B0aW9ucyA9IHZhbGlkYXRlT3B0aW9ucyhvcHRpb25zKTtcclxuXHJcbiAgICAvLyBBbiBhcnJheSBmb3IgY29sbGVjdGluZyBiYXRjaCBleHBvcnRzXHJcbiAgICBjb25zdCBiYXRjaEZ1bmN0aW9ucyA9IFtdO1xyXG5cclxuICAgIC8vIFNwbGl0IGFuZCBwYWlyIHRoZSBgYmF0Y2hgIGFyZ3VtZW50c1xyXG4gICAgZm9yIChsZXQgcGFpciBvZiBvcHRpb25zLmV4cG9ydC5iYXRjaC5zcGxpdCgnOycpIHx8IFtdKSB7XHJcbiAgICAgIHBhaXIgPSBwYWlyLnNwbGl0KCc9Jyk7XHJcbiAgICAgIGlmIChwYWlyLmxlbmd0aCA9PT0gMikge1xyXG4gICAgICAgIGJhdGNoRnVuY3Rpb25zLnB1c2goXHJcbiAgICAgICAgICBzdGFydEV4cG9ydChcclxuICAgICAgICAgICAge1xyXG4gICAgICAgICAgICAgIGV4cG9ydDoge1xyXG4gICAgICAgICAgICAgICAgLi4ub3B0aW9ucy5leHBvcnQsXHJcbiAgICAgICAgICAgICAgICBpbmZpbGU6IHBhaXJbMF0sXHJcbiAgICAgICAgICAgICAgICBvdXRmaWxlOiBwYWlyWzFdXHJcbiAgICAgICAgICAgICAgfSxcclxuICAgICAgICAgICAgICBjdXN0b21Mb2dpYzogb3B0aW9ucy5jdXN0b21Mb2dpY1xyXG4gICAgICAgICAgICB9LFxyXG4gICAgICAgICAgICAoZXJyb3IsIGRhdGEpID0+IHtcclxuICAgICAgICAgICAgICAvLyBFeGl0IHByb2Nlc3Mgd2hlbiBlcnJvciBleGlzdHNcclxuICAgICAgICAgICAgICBpZiAoZXJyb3IpIHtcclxuICAgICAgICAgICAgICAgIHRocm93IGVycm9yO1xyXG4gICAgICAgICAgICAgIH1cclxuXHJcbiAgICAgICAgICAgICAgLy8gR2V0IHRoZSBgYjY0YCwgYG91dGZpbGVgLCBhbmQgYHR5cGVgIGZvciBhIGNoYXJ0XHJcbiAgICAgICAgICAgICAgY29uc3QgeyBiNjQsIG91dGZpbGUsIHR5cGUgfSA9IGRhdGEub3B0aW9ucy5leHBvcnQ7XHJcblxyXG4gICAgICAgICAgICAgIC8vIFNhdmUgdGhlIHJlc3VsdFxyXG4gICAgICAgICAgICAgIHRyeSB7XHJcbiAgICAgICAgICAgICAgICBpZiAoYjY0KSB7XHJcbiAgICAgICAgICAgICAgICAgIC8vIEFzIGEgQmFzZTY0IHN0cmluZyB0byBhIHR4dCBmaWxlXHJcbiAgICAgICAgICAgICAgICAgIHdyaXRlRmlsZVN5bmMoXHJcbiAgICAgICAgICAgICAgICAgICAgYCR7b3V0ZmlsZS5zcGxpdCgnLicpLnNoaWZ0KCkgfHwgJ2NoYXJ0J30udHh0YCxcclxuICAgICAgICAgICAgICAgICAgICBnZXRCYXNlNjQoZGF0YS5yZXN1bHQsIHR5cGUpXHJcbiAgICAgICAgICAgICAgICAgICk7XHJcbiAgICAgICAgICAgICAgICB9IGVsc2Uge1xyXG4gICAgICAgICAgICAgICAgICAvLyBBcyBhIGNvcnJlY3QgaW1hZ2UgZm9ybWF0XHJcbiAgICAgICAgICAgICAgICAgIHdyaXRlRmlsZVN5bmMoXHJcbiAgICAgICAgICAgICAgICAgICAgb3V0ZmlsZSxcclxuICAgICAgICAgICAgICAgICAgICB0eXBlICE9PSAnc3ZnJ1xyXG4gICAgICAgICAgICAgICAgICAgICAgPyBCdWZmZXIuZnJvbShkYXRhLnJlc3VsdCwgJ2Jhc2U2NCcpXHJcbiAgICAgICAgICAgICAgICAgICAgICA6IGRhdGEucmVzdWx0XHJcbiAgICAgICAgICAgICAgICAgICk7XHJcbiAgICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgICAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICAgICAgICAgICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcihcclxuICAgICAgICAgICAgICAgICAgJ1tjaGFydF0gRXJyb3Igd2hpbGUgc2F2aW5nIGEgY2hhcnQuJyxcclxuICAgICAgICAgICAgICAgICAgNTAwXHJcbiAgICAgICAgICAgICAgICApLnNldEVycm9yKGVycm9yKTtcclxuICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgIH1cclxuICAgICAgICAgIClcclxuICAgICAgICApO1xyXG4gICAgICB9IGVsc2Uge1xyXG4gICAgICAgIGxvZygyLCAnW2NoYXJ0XSBObyBjb3JyZWN0IHBhaXIgZm91bmQgZm9yIHRoZSBiYXRjaCBleHBvcnQuJyk7XHJcbiAgICAgIH1cclxuICAgIH1cclxuXHJcbiAgICAvLyBBd2FpdCBhbGwgZXhwb3J0cyBhcmUgZG9uZVxyXG4gICAgY29uc3QgYmF0Y2hSZXN1bHRzID0gYXdhaXQgUHJvbWlzZS5hbGxTZXR0bGVkKGJhdGNoRnVuY3Rpb25zKTtcclxuXHJcbiAgICAvLyBLaWxsIHBvb2wgYW5kIGNsb3NlIGJyb3dzZXIgYWZ0ZXIgZmluaXNoaW5nIGJhdGNoIGV4cG9ydFxyXG4gICAgYXdhaXQga2lsbFBvb2woKTtcclxuXHJcbiAgICAvLyBMb2cgZXJyb3JzIGlmIGZvdW5kXHJcbiAgICBiYXRjaFJlc3VsdHMuZm9yRWFjaCgocmVzdWx0LCBpbmRleCkgPT4ge1xyXG4gICAgICAvLyBMb2cgdGhlIGVycm9yIHdpdGggc3RhY2sgYWJvdXQgdGhlIHNwZWNpZmljIGJhdGNoIGV4cG9ydFxyXG4gICAgICBpZiAocmVzdWx0LnJlYXNvbikge1xyXG4gICAgICAgIGxvZ1dpdGhTdGFjayhcclxuICAgICAgICAgIDEsXHJcbiAgICAgICAgICByZXN1bHQucmVhc29uLFxyXG4gICAgICAgICAgYFtjaGFydF0gQmF0Y2ggZXhwb3J0IG51bWJlciAke2luZGV4ICsgMX0gY291bGQgbm90IGJlIGNvcnJlY3RseSBjb21wbGV0ZWQuYFxyXG4gICAgICAgICk7XHJcbiAgICAgIH1cclxuICAgIH0pO1xyXG4gIH0gZWxzZSB7XHJcbiAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoXHJcbiAgICAgICdbY2hhcnRdIE5vIGV4cGVjdGVkIGBleHBvcnRgIG9wdGlvbnMgd2VyZSBmb3VuZC4gUGxlYXNlIHByb3ZpZGUgdGhlIGBiYXRjaGAgb3B0aW9uIHRvIGdlbmVyYXRlIHZhbGlkIGltYWdlcy4nLFxyXG4gICAgICA0MDBcclxuICAgICk7XHJcbiAgfVxyXG59XHJcblxyXG4vKipcclxuICogU3RhcnRzIGFuIGV4cG9ydCBwcm9jZXNzLiBUaGUgYGV4cG9ydGluZ09wdGlvbnNgIHBhcmFtZXRlciBpcyBhbiBvYmplY3QgdGhhdFxyXG4gKiBzaG91bGQgaW5jbHVkZSBzZXR0aW5ncyBmcm9tIHRoZSBgZXhwb3J0YCBhbmQgYGN1c3RvbUxvZ2ljYCBzZWN0aW9ucy4gSXQgY2FuXHJcbiAqIGJlIGEgcGFydGlhbCBvciBjb21wbGV0ZSBzZXQgb2Ygb3B0aW9ucyBmcm9tIHRoZXNlIHNlY3Rpb25zLiBJZiBwYXJ0aWFsXHJcbiAqIG9wdGlvbnMgYXJlIHByb3ZpZGVkLCBtaXNzaW5nIHZhbHVlcyB3aWxsIGJlIG1lcmdlZCB3aXRoIHRoZSBjdXJyZW50IGdsb2JhbFxyXG4gKiBvcHRpb25zLlxyXG4gKlxyXG4gKiBUaGUgYGVuZENhbGxiYWNrYCBmdW5jdGlvbiBpcyBpbnZva2VkIHVwb24gdGhlIGNvbXBsZXRpb24gb2YgdGhlIGV4cG9ydCxcclxuICogZWl0aGVyIHN1Y2Nlc3NmdWxseSBvciB3aXRoIGFuIGVycm9yLiBUaGUgYGVycm9yYCBvYmplY3QgaXMgcHJvdmlkZWRcclxuICogYXMgdGhlIGZpcnN0IGFyZ3VtZW50LCBhbmQgdGhlIGBkYXRhYCBvYmplY3QgaXMgdGhlIHNlY29uZCwgY29udGFpbmluZ1xyXG4gKiB0aGUgQmFzZTY0IHJlcHJlc2VudGF0aW9uIG9mIHRoZSBjaGFydCBpbiB0aGUgYHJlc3VsdGAgcHJvcGVydHlcclxuICogYW5kIHRoZSBjb21wbGV0ZSBzZXQgb2Ygb3B0aW9ucyBpbiB0aGUgYG9wdGlvbnNgIHByb3BlcnR5LlxyXG4gKlxyXG4gKiBAYXN5bmNcclxuICogQGZ1bmN0aW9uIHN0YXJ0RXhwb3J0XHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBleHBvcnRpbmdPcHRpb25zIC0gVGhlIGBleHBvcnRpbmdPcHRpb25zYCBvYmplY3QsIHdoaWNoXHJcbiAqIHNob3VsZCBpbmNsdWRlIHNldHRpbmdzIGZyb20gdGhlIGBleHBvcnRgIGFuZCBgY3VzdG9tTG9naWNgIHNlY3Rpb25zLiBJdCBjYW5cclxuICogYmUgYSBwYXJ0aWFsIG9yIGNvbXBsZXRlIHNldCBvZiBvcHRpb25zIGZyb20gdGhlc2Ugc2VjdGlvbnMuIElmIHRoZSBwcm92aWRlZFxyXG4gKiBvcHRpb25zIGFyZSBwYXJ0aWFsLCBtaXNzaW5nIHZhbHVlcyB3aWxsIGJlIG1lcmdlZCB3aXRoIHRoZSBjdXJyZW50IGdsb2JhbFxyXG4gKiBvcHRpb25zLlxyXG4gKiBAcGFyYW0ge0Z1bmN0aW9ufSBlbmRDYWxsYmFjayAtIFRoZSBjYWxsYmFjayBmdW5jdGlvbiB0byBiZSBpbnZva2VkIHVwb25cclxuICogZmluYWxpemluZyB0aGUgZXhwb3J0IHByb2Nlc3Mgb3IgdXBvbiBlbmNvdW50ZXJpbmcgYW4gZXJyb3IuIFRoZSBmaXJzdFxyXG4gKiBhcmd1bWVudCBpcyB0aGUgYGVycm9yYCBvYmplY3QsIGFuZCB0aGUgc2Vjb25kIGFyZ3VtZW50IGlzIHRoZSBgZGF0YWAgb2JqZWN0LFxyXG4gKiB3aGljaCBpbmNsdWRlcyB0aGUgQmFzZTY0IHJlcHJlc2VudGF0aW9uIG9mIHRoZSBjaGFydCBpbiB0aGUgYHJlc3VsdGBcclxuICogcHJvcGVydHkgYW5kIHRoZSBmdWxsIHNldCBvZiBvcHRpb25zIGluIHRoZSBgb3B0aW9uc2AgcHJvcGVydHkuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtQcm9taXNlPHZvaWQ+fSBUaGlzIGZ1bmN0aW9uIGRvZXMgbm90IHJldHVybiBhIHZhbHVlIGRpcmVjdGx5LlxyXG4gKiBJbnN0ZWFkLCBpdCBjb21tdW5pY2F0ZXMgcmVzdWx0cyB2aWEgdGhlIGBlbmRDYWxsYmFja2AuXHJcbiAqXHJcbiAqIEB0aHJvd3Mge0V4cG9ydEVycm9yfSBUaHJvd3MgYW4gYEV4cG9ydEVycm9yYCBpZiB0aGVyZSBpcyBhIHByb2JsZW0gd2l0aFxyXG4gKiBwcm9jZXNzaW5nIGlucHV0IG9mIGFueSB0eXBlLiBUaGUgZXJyb3IgaXMgcGFzc2VkIGludG8gdGhlIGBlbmRDYWxsYmFja2BcclxuICogZnVuY3Rpb24gYW5kIHByb2Nlc3NlZCB0aGVyZS5cclxuICovXHJcbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBzdGFydEV4cG9ydChleHBvcnRpbmdPcHRpb25zLCBlbmRDYWxsYmFjaykge1xyXG4gIHRyeSB7XHJcbiAgICAvLyBDaGVjayBpZiBwcm92aWRlZCBvcHRpb25zIGlzIGFuIG9iamVjdFxyXG4gICAgaWYgKCFpc09iamVjdChleHBvcnRpbmdPcHRpb25zKSkge1xyXG4gICAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoXHJcbiAgICAgICAgJ1tjaGFydF0gSW5jb3JyZWN0IHZhbHVlIG9mIHRoZSBwcm92aWRlZCBgZXhwb3J0aW5nT3B0aW9uc2AuIE5lZWRzIHRvIGJlIGFuIG9iamVjdC4nLFxyXG4gICAgICAgIDQwMFxyXG4gICAgICApO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIE1lcmdlIGFkZGl0aW9uYWwgb3B0aW9ucyB0byB0aGUgY29weSBvZiB0aGUgaW5zdGFuY2Ugb3B0aW9uc1xyXG4gICAgY29uc3Qgb3B0aW9ucyA9IG1lcmdlT3B0aW9ucyhkZWVwQ29weShnZXRPcHRpb25zKCkpLCB7XHJcbiAgICAgIGV4cG9ydDogZXhwb3J0aW5nT3B0aW9ucy5leHBvcnQsXHJcbiAgICAgIGN1c3RvbUxvZ2ljOiBleHBvcnRpbmdPcHRpb25zLmN1c3RvbUxvZ2ljXHJcbiAgICB9KTtcclxuXHJcbiAgICAvLyBHZXQgdGhlIGBleHBvcnRgIG9wdGlvbnNcclxuICAgIGNvbnN0IGV4cG9ydE9wdGlvbnMgPSBvcHRpb25zLmV4cG9ydDtcclxuXHJcbiAgICAvLyBTdGFydGluZyBleHBvcnRpbmcgcHJvY2VzcyBtZXNzYWdlXHJcbiAgICBsb2coNCwgJ1tjaGFydF0gU3RhcnRpbmcgdGhlIGV4cG9ydGluZyBwcm9jZXNzLicpO1xyXG5cclxuICAgIC8vIEV4cG9ydCB1c2luZyBvcHRpb25zIGZyb20gdGhlIGZpbGUgYXMgYW4gaW5wdXRcclxuICAgIGlmIChleHBvcnRPcHRpb25zLmluZmlsZSAhPT0gbnVsbCkge1xyXG4gICAgICBsb2coNCwgJ1tjaGFydF0gQXR0ZW1wdGluZyB0byBleHBvcnQgZnJvbSBhIGZpbGUgaW5wdXQuJyk7XHJcblxyXG4gICAgICBsZXQgZmlsZUNvbnRlbnQ7XHJcbiAgICAgIHRyeSB7XHJcbiAgICAgICAgLy8gVHJ5IHRvIHJlYWQgdGhlIGZpbGUgdG8gZ2V0IHRoZSBzdHJpbmcgcmVwcmVzZW50YXRpb25cclxuICAgICAgICBmaWxlQ29udGVudCA9IHJlYWRGaWxlU3luYyhcclxuICAgICAgICAgIGdldEFic29sdXRlUGF0aChleHBvcnRPcHRpb25zLmluZmlsZSksXHJcbiAgICAgICAgICAndXRmOCdcclxuICAgICAgICApO1xyXG4gICAgICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcihcclxuICAgICAgICAgICdbY2hhcnRdIEVycm9yIGxvYWRpbmcgY29udGVudCBmcm9tIGEgZmlsZSBpbnB1dC4nLFxyXG4gICAgICAgICAgNDAwXHJcbiAgICAgICAgKS5zZXRFcnJvcihlcnJvcik7XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIC8vIENoZWNrIHRoZSBmaWxlJ3MgZXh0ZW5zaW9uXHJcbiAgICAgIGlmIChleHBvcnRPcHRpb25zLmluZmlsZS5lbmRzV2l0aCgnLnN2ZycpKSB7XHJcbiAgICAgICAgLy8gU2V0IHRvIHRoZSBgc3ZnYCBvcHRpb25cclxuICAgICAgICBleHBvcnRPcHRpb25zLnN2ZyA9IHZhbGlkYXRlT3B0aW9uKCdzdmcnLCBmaWxlQ29udGVudCk7XHJcbiAgICAgIH0gZWxzZSBpZiAoZXhwb3J0T3B0aW9ucy5pbmZpbGUuZW5kc1dpdGgoJy5qc29uJykpIHtcclxuICAgICAgICAvLyBTZXQgdG8gdGhlIGBpbnN0cmAgb3B0aW9uXHJcbiAgICAgICAgZXhwb3J0T3B0aW9ucy5pbnN0ciA9IHZhbGlkYXRlT3B0aW9uKCdpbnN0cicsIGZpbGVDb250ZW50KTtcclxuICAgICAgfSBlbHNlIHtcclxuICAgICAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoXHJcbiAgICAgICAgICAnW2NoYXJ0XSBJbmNvcnJlY3QgdmFsdWUgb2YgdGhlIGBpbmZpbGVgIG9wdGlvbi4nLFxyXG4gICAgICAgICAgNDAwXHJcbiAgICAgICAgKTtcclxuICAgICAgfVxyXG4gICAgfVxyXG5cclxuICAgIC8vIEV4cG9ydCB1c2luZyBTVkcgYXMgYW4gaW5wdXRcclxuICAgIGlmIChleHBvcnRPcHRpb25zLnN2ZyAhPT0gbnVsbCkge1xyXG4gICAgICBsb2coNCwgJ1tjaGFydF0gQXR0ZW1wdGluZyB0byBleHBvcnQgZnJvbSBhbiBTVkcgaW5wdXQuJyk7XHJcblxyXG4gICAgICAvLyBTVkcgZXhwb3J0cyBhdHRlbXB0cyBjb3VudGVyXHJcbiAgICAgICsrZ2V0UG9vbFN0YXRzKCkuZXhwb3J0c0Zyb21TdmdBdHRlbXB0cztcclxuXHJcbiAgICAgIC8vIEV4cG9ydCBmcm9tIGFuIFNWRyBzdHJpbmdcclxuICAgICAgY29uc3QgcmVzdWx0ID0gYXdhaXQgX2V4cG9ydEZyb21TdmcoXHJcbiAgICAgICAgc2FuaXRpemUoZXhwb3J0T3B0aW9ucy5zdmcpLCAvLyAjMjA5XHJcbiAgICAgICAgb3B0aW9uc1xyXG4gICAgICApO1xyXG5cclxuICAgICAgLy8gU1ZHIGV4cG9ydHMgY291bnRlclxyXG4gICAgICArK2dldFBvb2xTdGF0cygpLmV4cG9ydHNGcm9tU3ZnO1xyXG5cclxuICAgICAgLy8gUGFzcyBTVkcgZXhwb3J0IHJlc3VsdCB0byB0aGUgZW5kIGNhbGxiYWNrXHJcbiAgICAgIHJldHVybiBlbmRDYWxsYmFjayhudWxsLCByZXN1bHQpO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIEV4cG9ydCB1c2luZyBvcHRpb25zIGFzIGFuIGlucHV0XHJcbiAgICBpZiAoZXhwb3J0T3B0aW9ucy5pbnN0ciAhPT0gbnVsbCB8fCBleHBvcnRPcHRpb25zLm9wdGlvbnMgIT09IG51bGwpIHtcclxuICAgICAgbG9nKDQsICdbY2hhcnRdIEF0dGVtcHRpbmcgdG8gZXhwb3J0IGZyb20gb3B0aW9ucyBpbnB1dC4nKTtcclxuXHJcbiAgICAgIC8vIE9wdGlvbnMgZXhwb3J0cyBhdHRlbXB0cyBjb3VudGVyXHJcbiAgICAgICsrZ2V0UG9vbFN0YXRzKCkuZXhwb3J0c0Zyb21PcHRpb25zQXR0ZW1wdHM7XHJcblxyXG4gICAgICAvLyBFeHBvcnQgZnJvbSBvcHRpb25zXHJcbiAgICAgIGNvbnN0IHJlc3VsdCA9IGF3YWl0IF9leHBvcnRGcm9tT3B0aW9ucyhcclxuICAgICAgICBleHBvcnRPcHRpb25zLmluc3RyIHx8IGV4cG9ydE9wdGlvbnMub3B0aW9ucyxcclxuICAgICAgICBvcHRpb25zXHJcbiAgICAgICk7XHJcblxyXG4gICAgICAvLyBPcHRpb25zIGV4cG9ydHMgY291bnRlclxyXG4gICAgICArK2dldFBvb2xTdGF0cygpLmV4cG9ydHNGcm9tT3B0aW9ucztcclxuXHJcbiAgICAgIC8vIFBhc3Mgb3B0aW9ucyBleHBvcnQgcmVzdWx0IHRvIHRoZSBlbmQgY2FsbGJhY2tcclxuICAgICAgcmV0dXJuIGVuZENhbGxiYWNrKG51bGwsIHJlc3VsdCk7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gTm8gaW5wdXQgc3BlY2lmaWVkLCBwYXNzIGFuIGVycm9yIG1lc3NhZ2UgdG8gdGhlIGNhbGxiYWNrXHJcbiAgICByZXR1cm4gZW5kQ2FsbGJhY2soXHJcbiAgICAgIG5ldyBFeHBvcnRFcnJvcihcclxuICAgICAgICBgW2NoYXJ0XSBObyB2YWxpZCBpbnB1dCBzcGVjaWZpZWQuIENoZWNrIGlmIGF0IGxlYXN0IG9uZSBvZiB0aGUgZm9sbG93aW5nIHBhcmFtZXRlcnMgaXMgY29ycmVjdGx5IHNldDogJ2luZmlsZScsICdpbnN0cicsICdvcHRpb25zJywgb3IgJ3N2ZycuYCxcclxuICAgICAgICA0MDBcclxuICAgICAgKVxyXG4gICAgKTtcclxuICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgcmV0dXJuIGVuZENhbGxiYWNrKGVycm9yKTtcclxuICB9XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBSZXRyaWV2ZXMgYW5kIHJldHVybnMgdGhlIGN1cnJlbnQgc3RhdHVzIG9mIHRoZSBjb2RlIGV4ZWN1dGlvbiBwZXJtaXNzaW9uLlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gZ2V0QWxsb3dDb2RlRXhlY3V0aW9uXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtib29sZWFufSBUaGUgdmFsdWUgb2YgdGhlIGdsb2JhbCBgYWxsb3dDb2RlRXhlY3V0aW9uYCBvcHRpb24uXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gZ2V0QWxsb3dDb2RlRXhlY3V0aW9uKCkge1xyXG4gIHJldHVybiBhbGxvd0NvZGVFeGVjdXRpb247XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBTZXRzIHRoZSBjb2RlIGV4ZWN1dGlvbiBwZXJtaXNzaW9uIGJhc2VkIG9uIHRoZSBwcm92aWRlZCBib29sZWFuIHZhbHVlLlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gc2V0QWxsb3dDb2RlRXhlY3V0aW9uXHJcbiAqXHJcbiAqIEBwYXJhbSB7Ym9vbGVhbn0gdmFsdWUgLSBUaGUgYm9vbGVhbiB2YWx1ZSB0byBiZSBhc3NpZ25lZCB0byB0aGUgZ2xvYmFsXHJcbiAqIGBhbGxvd0NvZGVFeGVjdXRpb25gIG9wdGlvbi5cclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiBzZXRBbGxvd0NvZGVFeGVjdXRpb24odmFsdWUpIHtcclxuICBhbGxvd0NvZGVFeGVjdXRpb24gPSB2YWx1ZTtcclxufVxyXG5cclxuLyoqXHJcbiAqIEV4cG9ydHMgZnJvbSBhbiBTVkcgYmFzZWQgaW5wdXQgd2l0aCB0aGUgcHJvdmlkZWQgb3B0aW9ucy5cclxuICpcclxuICogQGFzeW5jXHJcbiAqIEBmdW5jdGlvbiBfZXhwb3J0RnJvbVN2Z1xyXG4gKlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gaW5wdXRUb0V4cG9ydCAtIFRoZSBTVkcgYmFzZWQgaW5wdXQgdG8gYmUgZXhwb3J0ZWQuXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBvcHRpb25zIC0gVGhlIGNvbmZpZ3VyYXRpb24gb2JqZWN0IGNvbnRhaW5pbmcgY29tcGxldGUgc2V0XHJcbiAqIG9mIG9wdGlvbnMuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtQcm9taXNlPHVua25vd24+fSBBIFByb21pc2UgdGhhdCByZXNvbHZlcyB0byBhIHJlc3VsdCBvZiB0aGUgZXhwb3J0XHJcbiAqIHByb2Nlc3MuXHJcbiAqXHJcbiAqIEB0aHJvd3Mge0V4cG9ydEVycm9yfSBUaHJvd3MgYW4gYEV4cG9ydEVycm9yYCBpZiB0aGVyZSBpcyBub3QgYSBjb3JyZWN0IFNWR1xyXG4gKiBpbnB1dC5cclxuICovXHJcbmFzeW5jIGZ1bmN0aW9uIF9leHBvcnRGcm9tU3ZnKGlucHV0VG9FeHBvcnQsIG9wdGlvbnMpIHtcclxuICAvLyBDaGVjayBpZiBpdCBpcyBTVkdcclxuICBpZiAoXHJcbiAgICB0eXBlb2YgaW5wdXRUb0V4cG9ydCA9PT0gJ3N0cmluZycgJiZcclxuICAgIChpbnB1dFRvRXhwb3J0LmluZGV4T2YoJzxzdmcnKSA+PSAwIHx8IGlucHV0VG9FeHBvcnQuaW5kZXhPZignPD94bWwnKSA+PSAwKVxyXG4gICkge1xyXG4gICAgbG9nKDQsICdbY2hhcnRdIFBhcnNpbmcgaW5wdXQgYXMgU1ZHLicpO1xyXG5cclxuICAgIC8vIFNldCB0aGUgZXhwb3J0IGlucHV0IGFzIFNWR1xyXG4gICAgb3B0aW9ucy5leHBvcnQuc3ZnID0gaW5wdXRUb0V4cG9ydDtcclxuXHJcbiAgICAvLyBSZXNldCB0aGUgcmVzdCBvZiB0aGUgZXhwb3J0IGlucHV0IG9wdGlvbnNcclxuICAgIG9wdGlvbnMuZXhwb3J0Lmluc3RyID0gbnVsbDtcclxuICAgIG9wdGlvbnMuZXhwb3J0Lm9wdGlvbnMgPSBudWxsO1xyXG5cclxuICAgIC8vIENhbGwgdGhlIGZ1bmN0aW9uIHdpdGggYW4gU1ZHIHN0cmluZyBhcyBhbiBleHBvcnQgaW5wdXRcclxuICAgIHJldHVybiBfcHJlcGFyZUV4cG9ydChvcHRpb25zKTtcclxuICB9IGVsc2Uge1xyXG4gICAgdGhyb3cgbmV3IEV4cG9ydEVycm9yKCdbY2hhcnRdIE5vdCBhIGNvcnJlY3QgU1ZHIGlucHV0LicsIDQwMCk7XHJcbiAgfVxyXG59XHJcblxyXG4vKipcclxuICogRXhwb3J0cyBmcm9tIGFuIG9wdGlvbnMgYmFzZWQgaW5wdXQgd2l0aCB0aGUgcHJvdmlkZWQgb3B0aW9ucy5cclxuICpcclxuICogQGFzeW5jXHJcbiAqIEBmdW5jdGlvbiBfZXhwb3J0RnJvbU9wdGlvbnNcclxuICpcclxuICogQHBhcmFtIHtzdHJpbmd9IGlucHV0VG9FeHBvcnQgLSBUaGUgb3B0aW9ucyBiYXNlZCBpbnB1dCB0byBiZSBleHBvcnRlZC5cclxuICogQHBhcmFtIHtPYmplY3R9IG9wdGlvbnMgLSBUaGUgY29uZmlndXJhdGlvbiBvYmplY3QgY29udGFpbmluZyBjb21wbGV0ZSBzZXRcclxuICogb2Ygb3B0aW9ucy5cclxuICpcclxuICogQHJldHVybnMge1Byb21pc2U8dW5rbm93bj59IEEgUHJvbWlzZSB0aGF0IHJlc29sdmVzIHRvIGEgcmVzdWx0IG9mIHRoZSBleHBvcnRcclxuICogcHJvY2Vzcy5cclxuICpcclxuICogQHRocm93cyB7RXhwb3J0RXJyb3J9IFRocm93cyBhbiBgRXhwb3J0RXJyb3JgIGlmIHRoZXJlIGlzIG5vdCBhIGNvcnJlY3RcclxuICogY2hhcnQgb3B0aW9ucyBpbnB1dC5cclxuICovXHJcbmFzeW5jIGZ1bmN0aW9uIF9leHBvcnRGcm9tT3B0aW9ucyhpbnB1dFRvRXhwb3J0LCBvcHRpb25zKSB7XHJcbiAgbG9nKDQsICdbY2hhcnRdIFBhcnNpbmcgaW5wdXQgZnJvbSBvcHRpb25zLicpO1xyXG5cclxuICAvLyBUcnkgdG8gY2hlY2ssIHZhbGlkYXRlIGFuZCBwYXJzZSB0byBzdHJpbmdpZmllZCBvcHRpb25zXHJcbiAgY29uc3Qgc3RyaW5naWZpZWRPcHRpb25zID0gaXNBbGxvd2VkQ29uZmlnKFxyXG4gICAgaW5wdXRUb0V4cG9ydCxcclxuICAgIHRydWUsXHJcbiAgICBvcHRpb25zLmN1c3RvbUxvZ2ljLmFsbG93Q29kZUV4ZWN1dGlvblxyXG4gICk7XHJcblxyXG4gIC8vIENoZWNrIGlmIGEgY29ycmVjdCBzdHJpbmdpZmllZCBvcHRpb25zXHJcbiAgaWYgKFxyXG4gICAgc3RyaW5naWZpZWRPcHRpb25zID09PSBudWxsIHx8XHJcbiAgICB0eXBlb2Ygc3RyaW5naWZpZWRPcHRpb25zICE9PSAnc3RyaW5nJyB8fFxyXG4gICAgIXN0cmluZ2lmaWVkT3B0aW9ucy5zdGFydHNXaXRoKCd7JykgfHxcclxuICAgICFzdHJpbmdpZmllZE9wdGlvbnMuZW5kc1dpdGgoJ30nKVxyXG4gICkge1xyXG4gICAgdGhyb3cgbmV3IEV4cG9ydEVycm9yKFxyXG4gICAgICAnW2NoYXJ0XSBJbnZhbGlkIGNvbmZpZ3VyYXRpb24gcHJvdmlkZWQgLSBPbmx5IG9wdGlvbnMgY29uZmlndXJhdGlvbnMgYW5kIFNWRyBhcmUgYWxsb3dlZCBmb3IgdGhpcyBzZXJ2ZXIuIElmIHRoaXMgaXMgeW91ciBzZXJ2ZXIsIEphdmFTY3JpcHQgY3VzdG9tIGNvZGUgY2FuIGJlIGVuYWJsZWQgYnkgc3RhcnRpbmcgdGhlIHNlcnZlciB3aXRoIHRoZSBgYWxsb3dDb2RlRXhlY3V0aW9uYCBvcHRpb25zIHNldCB0byB0cnVlLicsXHJcbiAgICAgIDQwM1xyXG4gICAgKTtcclxuICB9XHJcblxyXG4gIC8vIFNldCB0aGUgZXhwb3J0IGlucHV0IGFzIGEgc3RyaW5naWZpZWQgY2hhcnQgb3B0aW9uc1xyXG4gIG9wdGlvbnMuZXhwb3J0Lmluc3RyID0gc3RyaW5naWZpZWRPcHRpb25zO1xyXG5cclxuICAvLyBSZXNldCB0aGUgcmVzdCBvZiB0aGUgZXhwb3J0IGlucHV0IG9wdGlvbnNcclxuICBvcHRpb25zLmV4cG9ydC5zdmcgPSBudWxsO1xyXG5cclxuICAvLyBDYWxsIHRoZSBmdW5jdGlvbiB3aXRoIGEgc3RyaW5naWZpZWQgY2hhcnQgb3B0aW9uc1xyXG4gIHJldHVybiBfcHJlcGFyZUV4cG9ydChvcHRpb25zKTtcclxufVxyXG5cclxuLyoqXHJcbiAqIEZ1bmN0aW9uIGZvciBmaW5hbGl6aW5nIG9wdGlvbnMgYW5kIGNvbmZpZ3VyYXRpb25zIGJlZm9yZSBleHBvcnQuXHJcbiAqXHJcbiAqIEBhc3luY1xyXG4gKiBAZnVuY3Rpb24gX3ByZXBhcmVFeHBvcnRcclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IG9wdGlvbnMgLSBUaGUgY29uZmlndXJhdGlvbiBvYmplY3QgY29udGFpbmluZyBjb21wbGV0ZSBzZXRcclxuICogb2Ygb3B0aW9ucy5cclxuICpcclxuICogQHJldHVybnMge1Byb21pc2U8dW5rbm93bj59IEEgUHJvbWlzZSB0aGF0IHJlc29sdmVzIHRvIGEgcmVzdWx0IG9mIHRoZSBleHBvcnRcclxuICogcHJvY2Vzcy5cclxuICovXHJcbmFzeW5jIGZ1bmN0aW9uIF9wcmVwYXJlRXhwb3J0KG9wdGlvbnMpIHtcclxuICBjb25zdCB7IGV4cG9ydDogZXhwb3J0T3B0aW9ucywgY3VzdG9tTG9naWM6IGN1c3RvbUxvZ2ljT3B0aW9ucyB9ID0gb3B0aW9ucztcclxuXHJcbiAgLy8gUHJlcGFyZSB0aGUgYHR5cGVgIG9wdGlvblxyXG4gIGV4cG9ydE9wdGlvbnMudHlwZSA9IGZpeFR5cGUoZXhwb3J0T3B0aW9ucy50eXBlLCBleHBvcnRPcHRpb25zLm91dGZpbGUpO1xyXG5cclxuICAvLyBQcmVwYXJlIHRoZSBgb3V0ZmlsZWAgb3B0aW9uXHJcbiAgZXhwb3J0T3B0aW9ucy5vdXRmaWxlID0gZml4T3V0ZmlsZShleHBvcnRPcHRpb25zLnR5cGUsIGV4cG9ydE9wdGlvbnMub3V0ZmlsZSk7XHJcblxyXG4gIC8vIFByZXBhcmUgdGhlIGBjb25zdHJgIG9wdGlvblxyXG4gIGV4cG9ydE9wdGlvbnMuY29uc3RyID0gZml4Q29uc3RyKGV4cG9ydE9wdGlvbnMuY29uc3RyKTtcclxuXHJcbiAgLy8gTm90aWZ5IGFib3V0IHRoZSBjdXN0b20gbG9naWMgdXNhZ2Ugc3RhdHVzXHJcbiAgbG9nKFxyXG4gICAgMyxcclxuICAgIGBbY2hhcnRdIFRoZSBjdXN0b20gbG9naWMgaXMgJHtjdXN0b21Mb2dpY09wdGlvbnMuYWxsb3dDb2RlRXhlY3V0aW9uID8gJ2FsbG93ZWQnIDogJ2Rpc2FsbG93ZWQnfS5gXHJcbiAgKTtcclxuXHJcbiAgLy8gUHJlcGFyZSB0aGUgY3VzdG9tIGxvZ2ljIG9wdGlvbnMgKGBjdXN0b21Db2RlYCwgYGNhbGxiYWNrYCwgYHJlc291cmNlc2ApXHJcbiAgX2hhbmRsZUN1c3RvbUxvZ2ljKGN1c3RvbUxvZ2ljT3B0aW9ucywgY3VzdG9tTG9naWNPcHRpb25zLmFsbG93Q29kZUV4ZWN1dGlvbik7XHJcblxyXG4gIC8vIFByZXBhcmUgdGhlIGBnbG9iYWxPcHRpb25zYCBhbmQgYHRoZW1lT3B0aW9uc2Agb3B0aW9uc1xyXG4gIF9oYW5kbGVHbG9iYWxBbmRUaGVtZShcclxuICAgIGV4cG9ydE9wdGlvbnMsXHJcbiAgICBjdXN0b21Mb2dpY09wdGlvbnMuYWxsb3dGaWxlUmVzb3VyY2VzLFxyXG4gICAgY3VzdG9tTG9naWNPcHRpb25zLmFsbG93Q29kZUV4ZWN1dGlvblxyXG4gICk7XHJcblxyXG4gIC8vIFByZXBhcmUgdGhlIGBoZWlnaHRgLCBgd2lkdGhgLCBhbmQgYHNjYWxlYCBvcHRpb25zXHJcbiAgb3B0aW9ucy5leHBvcnQgPSB7XHJcbiAgICAuLi5leHBvcnRPcHRpb25zLFxyXG4gICAgLi4uX2ZpbmRDaGFydFNpemUoZXhwb3J0T3B0aW9ucylcclxuICB9O1xyXG5cclxuICAvLyBQb3N0IHRoZSB3b3JrIHRvIHRoZSBwb29sXHJcbiAgcmV0dXJuIHBvc3RXb3JrKG9wdGlvbnMpO1xyXG59XHJcblxyXG4vKipcclxuICogQ2FsY3VsYXRlcyB0aGUgYGhlaWdodGAsIGB3aWR0aGAgYW5kIGBzY2FsZWAgZm9yIGNoYXJ0IGV4cG9ydHMgYmFzZWRcclxuICogb24gdGhlIHByb3ZpZGVkIGV4cG9ydCBvcHRpb25zLlxyXG4gKlxyXG4gKiBUaGUgZnVuY3Rpb24gcHJpb3JpdGl6ZXMgdmFsdWVzIGluIHRoZSBmb2xsb3dpbmcgb3JkZXI6XHJcbiAqIDEuIFRoZSBgaGVpZ2h0YCwgYHdpZHRoYCwgYHNjYWxlYCBmcm9tIHRoZSBgZXhwb3J0T3B0aW9uc2AuXHJcbiAqIDIuIE9wdGlvbnMgZnJvbSB0aGUgY2hhcnQgY29uZmlndXJhdGlvbiAoZnJvbSBgZXhwb3J0aW5nYCBhbmQgYGNoYXJ0YCkuXHJcbiAqIDMuIE9wdGlvbnMgZnJvbSB0aGUgZ2xvYmFsIG9wdGlvbnMgKGZyb20gYGV4cG9ydGluZ2AgYW5kIGBjaGFydGApLlxyXG4gKiA0LiBPcHRpb25zIGZyb20gdGhlIHRoZW1lIG9wdGlvbnMgKGZyb20gYGV4cG9ydGluZ2AgYW5kIGBjaGFydGAgc2VjdGlvbnMpLlxyXG4gKiA1LiBGYWxsYmFjayBkZWZhdWx0IHZhbHVlcyAoYGhlaWdodCA9IDQwMGAsIGB3aWR0aCA9IDYwMGAsIGBzY2FsZSA9IDFgKS5cclxuICpcclxuICogQGZ1bmN0aW9uIF9maW5kQ2hhcnRTaXplXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBleHBvcnRPcHRpb25zIC0gVGhlIGNvbmZpZ3VyYXRpb24gb2JqZWN0IGNvbnRhaW5pbmcgYGV4cG9ydGBcclxuICogb3B0aW9ucy5cclxuICpcclxuICogQHJldHVybnMge09iamVjdH0gVGhlIG9iamVjdCBjb250YWluaW5nIGNhbGN1bGF0ZWQgYGhlaWdodGAsIGB3aWR0aGBcclxuICogYW5kIGBzY2FsZWAgdmFsdWVzIGZvciB0aGUgY2hhcnQgZXhwb3J0LlxyXG4gKi9cclxuZnVuY3Rpb24gX2ZpbmRDaGFydFNpemUoZXhwb3J0T3B0aW9ucykge1xyXG4gIC8vIENoZWNrIHRoZSBgb3B0aW9uc2AgYW5kIGBpbnN0cmAgZm9yIGNoYXJ0IGFuZCBleHBvcnRpbmcgc2VjdGlvbnNcclxuICBjb25zdCB7IGNoYXJ0OiBvcHRpb25zQ2hhcnQsIGV4cG9ydGluZzogb3B0aW9uc0V4cG9ydGluZyB9ID1cclxuICAgIGV4cG9ydE9wdGlvbnMub3B0aW9ucyB8fCBpc0FsbG93ZWRDb25maWcoZXhwb3J0T3B0aW9ucy5pbnN0cikgfHwgZmFsc2U7XHJcblxyXG4gIC8vIENoZWNrIHRoZSBgZ2xvYmFsT3B0aW9uc2AgZm9yIGNoYXJ0IGFuZCBleHBvcnRpbmcgc2VjdGlvbnNcclxuICBjb25zdCB7IGNoYXJ0OiBnbG9iYWxPcHRpb25zQ2hhcnQsIGV4cG9ydGluZzogZ2xvYmFsT3B0aW9uc0V4cG9ydGluZyB9ID1cclxuICAgIGlzQWxsb3dlZENvbmZpZyhleHBvcnRPcHRpb25zLmdsb2JhbE9wdGlvbnMpIHx8IGZhbHNlO1xyXG5cclxuICAvLyBDaGVjayB0aGUgYHRoZW1lT3B0aW9uc2AgZm9yIGNoYXJ0IGFuZCBleHBvcnRpbmcgc2VjdGlvbnNcclxuICBjb25zdCB7IGNoYXJ0OiB0aGVtZU9wdGlvbnNDaGFydCwgZXhwb3J0aW5nOiB0aGVtZU9wdGlvbnNFeHBvcnRpbmcgfSA9XHJcbiAgICBpc0FsbG93ZWRDb25maWcoZXhwb3J0T3B0aW9ucy50aGVtZU9wdGlvbnMpIHx8IGZhbHNlO1xyXG5cclxuICAvLyBGaW5kIHRoZSBgc2NhbGVgIHZhbHVlOlxyXG4gIC8vIC0gSXQgY2Fubm90IGJlIGxvd2VyIHRoYW4gMC4xXHJcbiAgLy8gLSBJdCBjYW5ub3QgYmUgaGlnaGVyIHRoYW4gNS4wXHJcbiAgLy8gLSBJdCBtdXN0IGJlIHJvdW5kZWQgdG8gMiBkZWNpbWFsIHBsYWNlcyAoZS5nLiAwLjIzMjM0IC0+IDAuMjMpXHJcbiAgY29uc3Qgc2NhbGUgPSByb3VuZE51bWJlcihcclxuICAgIE1hdGgubWF4KFxyXG4gICAgICAwLjEsXHJcbiAgICAgIE1hdGgubWluKFxyXG4gICAgICAgIGV4cG9ydE9wdGlvbnMuc2NhbGUgfHxcclxuICAgICAgICAgIG9wdGlvbnNFeHBvcnRpbmc/LnNjYWxlIHx8XHJcbiAgICAgICAgICBnbG9iYWxPcHRpb25zRXhwb3J0aW5nPy5zY2FsZSB8fFxyXG4gICAgICAgICAgdGhlbWVPcHRpb25zRXhwb3J0aW5nPy5zY2FsZSB8fFxyXG4gICAgICAgICAgZXhwb3J0T3B0aW9ucy5kZWZhdWx0U2NhbGUgfHxcclxuICAgICAgICAgIDEsXHJcbiAgICAgICAgNS4wXHJcbiAgICAgIClcclxuICAgICksXHJcbiAgICAyXHJcbiAgKTtcclxuXHJcbiAgLy8gRmluZCB0aGUgYGhlaWdodGAgdmFsdWVcclxuICBjb25zdCBoZWlnaHQgPVxyXG4gICAgZXhwb3J0T3B0aW9ucy5oZWlnaHQgfHxcclxuICAgIG9wdGlvbnNFeHBvcnRpbmc/LnNvdXJjZUhlaWdodCB8fFxyXG4gICAgb3B0aW9uc0NoYXJ0Py5oZWlnaHQgfHxcclxuICAgIGdsb2JhbE9wdGlvbnNFeHBvcnRpbmc/LnNvdXJjZUhlaWdodCB8fFxyXG4gICAgZ2xvYmFsT3B0aW9uc0NoYXJ0Py5oZWlnaHQgfHxcclxuICAgIHRoZW1lT3B0aW9uc0V4cG9ydGluZz8uc291cmNlSGVpZ2h0IHx8XHJcbiAgICB0aGVtZU9wdGlvbnNDaGFydD8uaGVpZ2h0IHx8XHJcbiAgICBleHBvcnRPcHRpb25zLmRlZmF1bHRIZWlnaHQgfHxcclxuICAgIDQwMDtcclxuXHJcbiAgLy8gRmluZCB0aGUgYHdpZHRoYCB2YWx1ZVxyXG4gIGNvbnN0IHdpZHRoID1cclxuICAgIGV4cG9ydE9wdGlvbnMud2lkdGggfHxcclxuICAgIG9wdGlvbnNFeHBvcnRpbmc/LnNvdXJjZVdpZHRoIHx8XHJcbiAgICBvcHRpb25zQ2hhcnQ/LndpZHRoIHx8XHJcbiAgICBnbG9iYWxPcHRpb25zRXhwb3J0aW5nPy5zb3VyY2VXaWR0aCB8fFxyXG4gICAgZ2xvYmFsT3B0aW9uc0NoYXJ0Py53aWR0aCB8fFxyXG4gICAgdGhlbWVPcHRpb25zRXhwb3J0aW5nPy5zb3VyY2VXaWR0aCB8fFxyXG4gICAgdGhlbWVPcHRpb25zQ2hhcnQ/LndpZHRoIHx8XHJcbiAgICBleHBvcnRPcHRpb25zLmRlZmF1bHRXaWR0aCB8fFxyXG4gICAgNjAwO1xyXG5cclxuICAvLyBHYXRoZXIgYGhlaWdodGAsIGB3aWR0aGAgYW5kIGBzY2FsZWAgaW5mb3JtYXRpb24gaW4gb25lIG9iamVjdFxyXG4gIGNvbnN0IHNpemUgPSB7IGhlaWdodCwgd2lkdGgsIHNjYWxlIH07XHJcblxyXG4gIC8vIEdldCByaWQgb2YgcG90ZW50aWFsIGBweGAgYW5kIGAlYFxyXG4gIGZvciAobGV0IFtwYXJhbSwgdmFsdWVdIG9mIE9iamVjdC5lbnRyaWVzKHNpemUpKSB7XHJcbiAgICBzaXplW3BhcmFtXSA9XHJcbiAgICAgIHR5cGVvZiB2YWx1ZSA9PT0gJ3N0cmluZycgPyArdmFsdWUucmVwbGFjZSgvcHh8JS9naSwgJycpIDogdmFsdWU7XHJcbiAgfVxyXG5cclxuICAvLyBSZXR1cm4gdGhlIHNpemUgb2JqZWN0XHJcbiAgcmV0dXJuIHNpemU7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBIYW5kbGVzIHRoZSBleGVjdXRpb24gb2YgY3VzdG9tIGxvZ2ljIG9wdGlvbnMsIGluY2x1ZGluZyBsb2FkaW5nIGByZXNvdXJjZXNgLFxyXG4gKiBgY3VzdG9tQ29kZWAsIGFuZCBgY2FsbGJhY2tgLiBJZiBjb2RlIGV4ZWN1dGlvbiBpcyBhbGxvd2VkLCBpdCBwcm9jZXNzZXNcclxuICogdGhlIGN1c3RvbSBsb2dpYyBvcHRpb25zIGFjY29yZGluZ2x5LiBJZiBjb2RlIGV4ZWN1dGlvbiBpcyBub3QgYWxsb3dlZCxcclxuICogaXQgZGlzYWJsZXMgdGhlIHVzYWdlIG9mIHJlc291cmNlcywgY3VzdG9tIGNvZGUgYW5kIGNhbGxiYWNrLlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gX2hhbmRsZUN1c3RvbUxvZ2ljXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBjdXN0b21Mb2dpY09wdGlvbnMgLSBUaGUgY29uZmlndXJhdGlvbiBvYmplY3QgY29udGFpbmluZ1xyXG4gKiBgY3VzdG9tTG9naWNgIG9wdGlvbnMuXHJcbiAqIEBwYXJhbSB7Ym9vbGVhbn0gYWxsb3dDb2RlRXhlY3V0aW9uIC0gQSBmbGFnIGluZGljYXRpbmcgd2hldGhlciBjb2RlXHJcbiAqIGV4ZWN1dGlvbiBpcyBhbGxvd2VkLlxyXG4gKlxyXG4gKiBAdGhyb3dzIHtFeHBvcnRFcnJvcn0gVGhyb3dzIGFuIGBFeHBvcnRFcnJvcmAgaWYgY29kZSBleGVjdXRpb25cclxuICogaXMgbm90IGFsbG93ZWQgYnV0IGN1c3RvbSBsb2dpYyBvcHRpb25zIGFyZSBzdGlsbCBwcm92aWRlZC5cclxuICovXHJcbmZ1bmN0aW9uIF9oYW5kbGVDdXN0b21Mb2dpYyhjdXN0b21Mb2dpY09wdGlvbnMsIGFsbG93Q29kZUV4ZWN1dGlvbikge1xyXG4gIC8vIEluIGNhc2Ugb2YgYWxsb3dpbmcgY29kZSBleGVjdXRpb25cclxuICBpZiAoYWxsb3dDb2RlRXhlY3V0aW9uKSB7XHJcbiAgICAvLyBQcm9jZXNzIHRoZSBgcmVzb3VyY2VzYCBvcHRpb25cclxuICAgIGlmICh0eXBlb2YgY3VzdG9tTG9naWNPcHRpb25zLnJlc291cmNlcyA9PT0gJ3N0cmluZycpIHtcclxuICAgICAgLy8gQ3VzdG9tIHN0cmluZ2lmaWVkIHJlc291cmNlc1xyXG4gICAgICBjdXN0b21Mb2dpY09wdGlvbnMucmVzb3VyY2VzID0gX2hhbmRsZVJlc291cmNlcyhcclxuICAgICAgICBjdXN0b21Mb2dpY09wdGlvbnMucmVzb3VyY2VzLFxyXG4gICAgICAgIGN1c3RvbUxvZ2ljT3B0aW9ucy5hbGxvd0ZpbGVSZXNvdXJjZXMsXHJcbiAgICAgICAgdHJ1ZVxyXG4gICAgICApO1xyXG4gICAgfSBlbHNlIGlmICghY3VzdG9tTG9naWNPcHRpb25zLnJlc291cmNlcykge1xyXG4gICAgICB0cnkge1xyXG4gICAgICAgIC8vIExvYWQgdGhlIGRlZmF1bHQgb25lXHJcbiAgICAgICAgY3VzdG9tTG9naWNPcHRpb25zLnJlc291cmNlcyA9IF9oYW5kbGVSZXNvdXJjZXMoXHJcbiAgICAgICAgICByZWFkRmlsZVN5bmMoZ2V0QWJzb2x1dGVQYXRoKCdyZXNvdXJjZXMuanNvbicpLCAndXRmOCcpLFxyXG4gICAgICAgICAgY3VzdG9tTG9naWNPcHRpb25zLmFsbG93RmlsZVJlc291cmNlcyxcclxuICAgICAgICAgIHRydWVcclxuICAgICAgICApO1xyXG4gICAgICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgICAgIGxvZygyLCAnW2NoYXJ0XSBVbmFibGUgdG8gbG9hZCB0aGUgZGVmYXVsdCBgcmVzb3VyY2VzLmpzb25gIGZpbGUuJyk7XHJcbiAgICAgIH1cclxuICAgIH1cclxuXHJcbiAgICAvLyBQcm9jZXNzIHRoZSBgY3VzdG9tQ29kZWAgb3B0aW9uXHJcbiAgICB0cnkge1xyXG4gICAgICAvLyBUcnkgdG8gbG9hZCBjdXN0b20gY29kZSBhbmQgd3JhcCBhcm91bmQgaXQgaW4gYSBzZWxmIGludm9raW5nIGZ1bmN0aW9uXHJcbiAgICAgIGN1c3RvbUxvZ2ljT3B0aW9ucy5jdXN0b21Db2RlID0gd3JhcEFyb3VuZChcclxuICAgICAgICBjdXN0b21Mb2dpY09wdGlvbnMuY3VzdG9tQ29kZSxcclxuICAgICAgICBjdXN0b21Mb2dpY09wdGlvbnMuYWxsb3dGaWxlUmVzb3VyY2VzXHJcbiAgICAgICk7XHJcblxyXG4gICAgICAvLyBWYWxpZGF0ZSB0aGUgb3B0aW9uXHJcbiAgICAgIGN1c3RvbUxvZ2ljT3B0aW9ucy5jdXN0b21Db2RlID0gdmFsaWRhdGVPcHRpb24oXHJcbiAgICAgICAgJ2N1c3RvbUNvZGUnLFxyXG4gICAgICAgIGN1c3RvbUxvZ2ljT3B0aW9ucy5jdXN0b21Db2RlXHJcbiAgICAgICk7XHJcbiAgICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgICBsb2dXaXRoU3RhY2soMiwgZXJyb3IsICdbY2hhcnRdIFRoZSBgY3VzdG9tQ29kZWAgY2Fubm90IGJlIGxvYWRlZC4nKTtcclxuXHJcbiAgICAgIC8vIEluIGNhc2Ugb2YgYW4gZXJyb3IsIHNldCB0aGUgb3B0aW9uIHdpdGggbnVsbFxyXG4gICAgICBjdXN0b21Mb2dpY09wdGlvbnMuY3VzdG9tQ29kZSA9IG51bGw7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gUHJvY2VzcyB0aGUgYGNhbGxiYWNrYCBvcHRpb25cclxuICAgIHRyeSB7XHJcbiAgICAgIC8vIFRyeSB0byBsb2FkIGNhbGxiYWNrIGZ1bmN0aW9uXHJcbiAgICAgIGN1c3RvbUxvZ2ljT3B0aW9ucy5jYWxsYmFjayA9IHdyYXBBcm91bmQoXHJcbiAgICAgICAgY3VzdG9tTG9naWNPcHRpb25zLmNhbGxiYWNrLFxyXG4gICAgICAgIGN1c3RvbUxvZ2ljT3B0aW9ucy5hbGxvd0ZpbGVSZXNvdXJjZXMsXHJcbiAgICAgICAgdHJ1ZVxyXG4gICAgICApO1xyXG5cclxuICAgICAgLy8gVmFsaWRhdGUgdGhlIG9wdGlvblxyXG4gICAgICBjdXN0b21Mb2dpY09wdGlvbnMuY2FsbGJhY2sgPSB2YWxpZGF0ZU9wdGlvbihcclxuICAgICAgICAnY2FsbGJhY2snLFxyXG4gICAgICAgIGN1c3RvbUxvZ2ljT3B0aW9ucy5jYWxsYmFja1xyXG4gICAgICApO1xyXG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICAgbG9nV2l0aFN0YWNrKDIsIGVycm9yLCAnW2NoYXJ0XSBUaGUgYGNhbGxiYWNrYCBjYW5ub3QgYmUgbG9hZGVkLicpO1xyXG5cclxuICAgICAgLy8gSW4gY2FzZSBvZiBhbiBlcnJvciwgc2V0IHRoZSBvcHRpb24gd2l0aCBudWxsXHJcbiAgICAgIGN1c3RvbUxvZ2ljT3B0aW9ucy5jYWxsYmFjayA9IG51bGw7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gQ2hlY2sgaWYgdGhlcmUgaXMgdGhlIGBjdXN0b21Db2RlYCBwcmVzZW50XHJcbiAgICBpZiAoW251bGwsIHVuZGVmaW5lZF0uaW5jbHVkZXMoY3VzdG9tTG9naWNPcHRpb25zLmN1c3RvbUNvZGUpKSB7XHJcbiAgICAgIGxvZygzLCAnW2NoYXJ0XSBObyB2YWx1ZSBmb3IgdGhlIGBjdXN0b21Db2RlYCBvcHRpb24gZm91bmQuJyk7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gQ2hlY2sgaWYgdGhlcmUgaXMgdGhlIGBjYWxsYmFja2AgcHJlc2VudFxyXG4gICAgaWYgKFtudWxsLCB1bmRlZmluZWRdLmluY2x1ZGVzKGN1c3RvbUxvZ2ljT3B0aW9ucy5jYWxsYmFjaykpIHtcclxuICAgICAgbG9nKDMsICdbY2hhcnRdIE5vIHZhbHVlIGZvciB0aGUgYGNhbGxiYWNrYCBvcHRpb24gZm91bmQuJyk7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gQ2hlY2sgaWYgdGhlcmUgaXMgdGhlIGByZXNvdXJjZXNgIHByZXNlbnRcclxuICAgIGlmIChbbnVsbCwgdW5kZWZpbmVkXS5pbmNsdWRlcyhjdXN0b21Mb2dpY09wdGlvbnMucmVzb3VyY2VzKSkge1xyXG4gICAgICBsb2coMywgJ1tjaGFydF0gTm8gdmFsdWUgZm9yIHRoZSBgcmVzb3VyY2VzYCBvcHRpb24gZm91bmQuJyk7XHJcbiAgICB9XHJcbiAgfSBlbHNlIHtcclxuICAgIC8vIElmIHRoZSBgYWxsb3dDb2RlRXhlY3V0aW9uYCBmbGFnIGlzIHNldCB0byBmYWxzZSwgd2Ugc2hvdWxkIHJlZnVzZVxyXG4gICAgLy8gdGhlIHVzYWdlIG9mIHRoZSBgY2FsbGJhY2tgLCBgcmVzb3VyY2VzYCwgYW5kIGBjdXN0b21Db2RlYCBvcHRpb25zLlxyXG4gICAgLy8gQWRkaXRpb25hbGx5LCB0aGUgd29ya2VyIHdpbGwgcmVmdXNlIHRvIHJ1biBhcmJpdHJhcnkgSmF2YVNjcmlwdC5cclxuICAgIGlmIChcclxuICAgICAgY3VzdG9tTG9naWNPcHRpb25zLmNhbGxiYWNrIHx8XHJcbiAgICAgIGN1c3RvbUxvZ2ljT3B0aW9ucy5yZXNvdXJjZXMgfHxcclxuICAgICAgY3VzdG9tTG9naWNPcHRpb25zLmN1c3RvbUNvZGVcclxuICAgICkge1xyXG4gICAgICAvLyBSZXNldCBhbGwgY3VzdG9tIGNvZGUgb3B0aW9uc1xyXG4gICAgICBjdXN0b21Mb2dpY09wdGlvbnMuY2FsbGJhY2sgPSBudWxsO1xyXG4gICAgICBjdXN0b21Mb2dpY09wdGlvbnMucmVzb3VyY2VzID0gbnVsbDtcclxuICAgICAgY3VzdG9tTG9naWNPcHRpb25zLmN1c3RvbUNvZGUgPSBudWxsO1xyXG5cclxuICAgICAgLy8gU2VuZCBhIG1lc3NhZ2Ugc2F5aW5nIHRoYXQgdGhlIGV4cG9ydGVyIGRvZXMgbm90IHN1cHBvcnQgdGhlc2Ugc2V0dGluZ3NcclxuICAgICAgdGhyb3cgbmV3IEV4cG9ydEVycm9yKFxyXG4gICAgICAgIGBbY2hhcnRdIFRoZSAnY2FsbGJhY2snLCAncmVzb3VyY2VzJywgYW5kICdjdXN0b21Db2RlJyBvcHRpb25zIGhhdmUgYmVlbiBkaXNhYmxlZCBmb3IgdGhpcyBzZXJ2ZXIuYCxcclxuICAgICAgICA0MDNcclxuICAgICAgKTtcclxuICAgIH1cclxuICB9XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBIYW5kbGVzIGFuZCB2YWxpZGF0ZXMgcmVzb3VyY2VzIGZyb20gdGhlIGByZXNvdXJjZXNgIG9wdGlvbiBmb3IgZXhwb3J0LlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gX2hhbmRsZVJlc291cmNlc1xyXG4gKlxyXG4gKiBAcGFyYW0geyhPYmplY3R8c3RyaW5nfG51bGwpfSBbcmVzb3VyY2VzPW51bGxdIC0gVGhlIHJlc291cmNlcyB0byBiZSBoYW5kbGVkLlxyXG4gKiBDYW4gYmUgZWl0aGVyIGEgSlNPTiBvYmplY3QsIHN0cmluZ2lmaWVkIEpTT04sIGEgcGF0aCB0byBhIEpTT04gZmlsZSxcclxuICogb3IgbnVsbC4gVGhlIGRlZmF1bHQgdmFsdWUgaXMgYG51bGxgLlxyXG4gKiBAcGFyYW0ge2Jvb2xlYW59IGFsbG93RmlsZVJlc291cmNlcyAtIEEgZmxhZyBpbmRpY2F0aW5nIHdoZXRoZXIgbG9hZGluZ1xyXG4gKiByZXNvdXJjZXMgZnJvbSBmaWxlcyBpcyBhbGxvd2VkLlxyXG4gKiBAcGFyYW0ge2Jvb2xlYW59IGFsbG93Q29kZUV4ZWN1dGlvbiAtIEEgZmxhZyBpbmRpY2F0aW5nIHdoZXRoZXIgY29kZVxyXG4gKiBleGVjdXRpb24gaXMgYWxsb3dlZC5cclxuICpcclxuICogQHJldHVybnMgeyhPYmplY3R8bnVsbCl9IFRoZSBoYW5kbGVkIHJlc291cmNlcyBvciBudWxsIGlmIG5vIHZhbGlkIHJlc291cmNlc1xyXG4gKiBhcmUgZm91bmQuXHJcbiAqL1xyXG5mdW5jdGlvbiBfaGFuZGxlUmVzb3VyY2VzKFxyXG4gIHJlc291cmNlcyA9IG51bGwsXHJcbiAgYWxsb3dGaWxlUmVzb3VyY2VzLFxyXG4gIGFsbG93Q29kZUV4ZWN1dGlvblxyXG4pIHtcclxuICAvLyBMaXN0IG9mIGFsbG93ZWQgc2VjdGlvbnMgaW4gdGhlIHJlc291cmNlcyBKU09OXHJcbiAgY29uc3QgYWxsb3dlZFByb3BzID0gWydqcycsICdjc3MnLCAnZmlsZXMnXTtcclxuXHJcbiAgbGV0IGhhbmRsZWRSZXNvdXJjZXMgPSByZXNvdXJjZXM7XHJcbiAgbGV0IGNvcnJlY3RSZXNvdXJjZXMgPSBmYWxzZTtcclxuXHJcbiAgLy8gVHJ5IHRvIGxvYWQgcmVzb3VyY2VzIGZyb20gYSBmaWxlXHJcbiAgaWYgKGFsbG93RmlsZVJlc291cmNlcyAmJiByZXNvdXJjZXMuZW5kc1dpdGgoJy5qc29uJykpIHtcclxuICAgIHRyeSB7XHJcbiAgICAgIGhhbmRsZWRSZXNvdXJjZXMgPSBpc0FsbG93ZWRDb25maWcoXHJcbiAgICAgICAgcmVhZEZpbGVTeW5jKGdldEFic29sdXRlUGF0aChyZXNvdXJjZXMpLCAndXRmOCcpLFxyXG4gICAgICAgIGZhbHNlLFxyXG4gICAgICAgIGFsbG93Q29kZUV4ZWN1dGlvblxyXG4gICAgICApO1xyXG4gICAgfSBjYXRjaCB7XHJcbiAgICAgIHJldHVybiBudWxsO1xyXG4gICAgfVxyXG4gIH0gZWxzZSB7XHJcbiAgICAvLyBUcnkgdG8gZ2V0IEpTT05cclxuICAgIGhhbmRsZWRSZXNvdXJjZXMgPSBpc0FsbG93ZWRDb25maWcocmVzb3VyY2VzLCBmYWxzZSwgYWxsb3dDb2RlRXhlY3V0aW9uKTtcclxuXHJcbiAgICAvLyBHZXQgcmlkIG9mIHRoZSBmaWxlcyBzZWN0aW9uXHJcbiAgICBpZiAoaGFuZGxlZFJlc291cmNlcyAmJiAhYWxsb3dGaWxlUmVzb3VyY2VzKSB7XHJcbiAgICAgIGRlbGV0ZSBoYW5kbGVkUmVzb3VyY2VzLmZpbGVzO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgLy8gRmlsdGVyIGZyb20gdW5uZWNlc3NhcnkgcHJvcGVydGllc1xyXG4gIGZvciAoY29uc3QgcHJvcE5hbWUgaW4gaGFuZGxlZFJlc291cmNlcykge1xyXG4gICAgaWYgKCFhbGxvd2VkUHJvcHMuaW5jbHVkZXMocHJvcE5hbWUpKSB7XHJcbiAgICAgIGRlbGV0ZSBoYW5kbGVkUmVzb3VyY2VzW3Byb3BOYW1lXTtcclxuICAgIH0gZWxzZSBpZiAoIWNvcnJlY3RSZXNvdXJjZXMpIHtcclxuICAgICAgY29ycmVjdFJlc291cmNlcyA9IHRydWU7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICAvLyBDaGVjayBpZiBhdCBsZWFzdCBvbmUgb2YgYWxsb3dlZCBwcm9wZXJ0aWVzIGlzIHByZXNlbnRcclxuICBpZiAoIWNvcnJlY3RSZXNvdXJjZXMpIHtcclxuICAgIHJldHVybiBudWxsO1xyXG4gIH1cclxuXHJcbiAgLy8gSGFuZGxlIGZpbGVzIHNlY3Rpb25cclxuICBpZiAoaGFuZGxlZFJlc291cmNlcy5maWxlcykge1xyXG4gICAgaGFuZGxlZFJlc291cmNlcy5maWxlcyA9IGhhbmRsZWRSZXNvdXJjZXMuZmlsZXMubWFwKChpdGVtKSA9PiBpdGVtLnRyaW0oKSk7XHJcbiAgICBpZiAoIWhhbmRsZWRSZXNvdXJjZXMuZmlsZXMgfHwgaGFuZGxlZFJlc291cmNlcy5maWxlcy5sZW5ndGggPD0gMCkge1xyXG4gICAgICBkZWxldGUgaGFuZGxlZFJlc291cmNlcy5maWxlcztcclxuICAgIH1cclxuICB9XHJcblxyXG4gIC8vIFZhbGlkYXRlIG9wdGlvblxyXG4gIGhhbmRsZWRSZXNvdXJjZXMgPSB2YWxpZGF0ZU9wdGlvbigncmVzb3VyY2VzJywgaGFuZGxlZFJlc291cmNlcyk7XHJcblxyXG4gIC8vIFJldHVybiByZXNvdXJjZXNcclxuICByZXR1cm4gaGFuZGxlZFJlc291cmNlcztcclxufVxyXG5cclxuLyoqXHJcbiAqIEhhbmRsZXMgdGhlIGxvYWRpbmcgYW5kIHZhbGlkYXRpb24gb2YgdGhlIGBnbG9iYWxPcHRpb25zYCBhbmQgYHRoZW1lT3B0aW9uc2BcclxuICogaW4gdGhlIGV4cG9ydCBvcHRpb25zLiBJZiB0aGUgb3B0aW9uIGlzIGEgc3RyaW5nIGFuZCByZWZlcmVuY2VzIGEgSlNPTiBmaWxlXHJcbiAqICh3aGVuIHRoZSBgYWxsb3dGaWxlUmVzb3VyY2VzYCBpcyB0cnVlKSwgaXQgcmVhZHMgYW5kIHBhcnNlcyB0aGUgZmlsZS5cclxuICogT3RoZXJ3aXNlLCBpdCBhdHRlbXB0cyB0byBwYXJzZSB0aGUgc3RyaW5nIG9yIG9iamVjdCBhcyBKU09OLiBJZiBhbnkgZXJyb3JzXHJcbiAqIG9jY3VyIGR1cmluZyB0aGlzIHByb2Nlc3MsIHRoZSBvcHRpb24gaXMgc2V0IHRvIG51bGwuIElmIHRoZXJlIGlzIGFuIGVycm9yXHJcbiAqIGxvYWRpbmcgb3IgcGFyc2luZyB0aGUgYGdsb2JhbE9wdGlvbnNgIG9yIGB0aGVtZU9wdGlvbnNgLCB0aGUgZXJyb3IgaXMgbG9nZ2VkXHJcbiAqIGFuZCB0aGUgb3B0aW9uIGlzIHNldCB0byBudWxsLlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gX2hhbmRsZUdsb2JhbEFuZFRoZW1lXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBleHBvcnRPcHRpb25zIC0gVGhlIGNvbmZpZ3VyYXRpb24gb2JqZWN0IGNvbnRhaW5pbmcgYGV4cG9ydGBcclxuICogb3B0aW9ucy5cclxuICogQHBhcmFtIHtib29sZWFufSBhbGxvd0ZpbGVSZXNvdXJjZXMgLSBBIGZsYWcgaW5kaWNhdGluZyB3aGV0aGVyIGxvYWRpbmdcclxuICogcmVzb3VyY2VzIGZyb20gZmlsZXMgaXMgYWxsb3dlZC5cclxuICogQHBhcmFtIHtib29sZWFufSBhbGxvd0NvZGVFeGVjdXRpb24gLSBBIGZsYWcgaW5kaWNhdGluZyB3aGV0aGVyIGNvZGVcclxuICogZXhlY3V0aW9uIGlzIGFsbG93ZWQuXHJcbiAqL1xyXG5mdW5jdGlvbiBfaGFuZGxlR2xvYmFsQW5kVGhlbWUoXHJcbiAgZXhwb3J0T3B0aW9ucyxcclxuICBhbGxvd0ZpbGVSZXNvdXJjZXMsXHJcbiAgYWxsb3dDb2RlRXhlY3V0aW9uXHJcbikge1xyXG4gIC8vIENoZWNrIHRoZSBgZ2xvYmFsT3B0aW9uc2AgYW5kIGB0aGVtZU9wdGlvbnNgIG9wdGlvbnNcclxuICBbJ2dsb2JhbE9wdGlvbnMnLCAndGhlbWVPcHRpb25zJ10uZm9yRWFjaCgob3B0aW9uc05hbWUpID0+IHtcclxuICAgIHRyeSB7XHJcbiAgICAgIC8vIENoZWNrIGlmIHRoZSBvcHRpb24gZXhpc3RzXHJcbiAgICAgIGlmIChleHBvcnRPcHRpb25zW29wdGlvbnNOYW1lXSkge1xyXG4gICAgICAgIC8vIENoZWNrIGlmIGl0IGlzIGEgc3RyaW5nIGFuZCBhIGZpbGUgbmFtZSB3aXRoIHRoZSBgLmpzb25gIGV4dGVuc2lvblxyXG4gICAgICAgIGlmIChcclxuICAgICAgICAgIGFsbG93RmlsZVJlc291cmNlcyAmJlxyXG4gICAgICAgICAgdHlwZW9mIGV4cG9ydE9wdGlvbnNbb3B0aW9uc05hbWVdID09PSAnc3RyaW5nJyAmJlxyXG4gICAgICAgICAgZXhwb3J0T3B0aW9uc1tvcHRpb25zTmFtZV0uZW5kc1dpdGgoJy5qc29uJylcclxuICAgICAgICApIHtcclxuICAgICAgICAgIC8vIENoZWNrIGlmIHRoZSBmaWxlIGNvbnRlbnQgY2FuIGJlIGEgY29uZmlnLCBhbmQgc2F2ZSBpdCBhcyBhIHN0cmluZ1xyXG4gICAgICAgICAgZXhwb3J0T3B0aW9uc1tvcHRpb25zTmFtZV0gPSBpc0FsbG93ZWRDb25maWcoXHJcbiAgICAgICAgICAgIHJlYWRGaWxlU3luYyhnZXRBYnNvbHV0ZVBhdGgoZXhwb3J0T3B0aW9uc1tvcHRpb25zTmFtZV0pLCAndXRmOCcpLFxyXG4gICAgICAgICAgICB0cnVlLFxyXG4gICAgICAgICAgICBhbGxvd0NvZGVFeGVjdXRpb25cclxuICAgICAgICAgICk7XHJcbiAgICAgICAgfSBlbHNlIHtcclxuICAgICAgICAgIC8vIENoZWNrIGlmIHRoZSB2YWx1ZSBjYW4gYmUgYSBjb25maWcsIGFuZCBzYXZlIGl0IGFzIGEgc3RyaW5nXHJcbiAgICAgICAgICBleHBvcnRPcHRpb25zW29wdGlvbnNOYW1lXSA9IGlzQWxsb3dlZENvbmZpZyhcclxuICAgICAgICAgICAgZXhwb3J0T3B0aW9uc1tvcHRpb25zTmFtZV0sXHJcbiAgICAgICAgICAgIHRydWUsXHJcbiAgICAgICAgICAgIGFsbG93Q29kZUV4ZWN1dGlvblxyXG4gICAgICAgICAgKTtcclxuICAgICAgICB9XHJcblxyXG4gICAgICAgIC8vIFZhbGlkYXRlIHRoZSBvcHRpb25cclxuICAgICAgICBleHBvcnRPcHRpb25zW29wdGlvbnNOYW1lXSA9IHZhbGlkYXRlT3B0aW9uKFxyXG4gICAgICAgICAgb3B0aW9uc05hbWUsXHJcbiAgICAgICAgICBleHBvcnRPcHRpb25zW29wdGlvbnNOYW1lXVxyXG4gICAgICAgICk7XHJcbiAgICAgIH1cclxuICAgIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICAgIGxvZ1dpdGhTdGFjayhcclxuICAgICAgICAyLFxyXG4gICAgICAgIGVycm9yLFxyXG4gICAgICAgIGBbY2hhcnRdIFRoZSBcXGAke29wdGlvbnNOYW1lfVxcYCBjYW5ub3QgYmUgbG9hZGVkLmBcclxuICAgICAgKTtcclxuXHJcbiAgICAgIC8vIEluIGNhc2Ugb2YgYW4gZXJyb3IsIHNldCB0aGUgb3B0aW9uIHdpdGggbnVsbFxyXG4gICAgICBleHBvcnRPcHRpb25zW29wdGlvbnNOYW1lXSA9IG51bGw7XHJcbiAgICB9XHJcbiAgfSk7XHJcblxyXG4gIC8vIENoZWNrIGlmIHRoZXJlIGlzIHRoZSBgZ2xvYmFsT3B0aW9uc2AgcHJlc2VudFxyXG4gIGlmIChbbnVsbCwgdW5kZWZpbmVkXS5pbmNsdWRlcyhleHBvcnRPcHRpb25zLmdsb2JhbE9wdGlvbnMpKSB7XHJcbiAgICBsb2coMywgJ1tjaGFydF0gTm8gdmFsdWUgZm9yIHRoZSBgZ2xvYmFsT3B0aW9uc2Agb3B0aW9uIGZvdW5kLicpO1xyXG4gIH1cclxuXHJcbiAgLy8gQ2hlY2sgaWYgdGhlcmUgaXMgdGhlIGB0aGVtZU9wdGlvbnNgIHByZXNlbnRcclxuICBpZiAoW251bGwsIHVuZGVmaW5lZF0uaW5jbHVkZXMoZXhwb3J0T3B0aW9ucy50aGVtZU9wdGlvbnMpKSB7XHJcbiAgICBsb2coMywgJ1tjaGFydF0gTm8gdmFsdWUgZm9yIHRoZSBgdGhlbWVPcHRpb25zYCBvcHRpb24gZm91bmQuJyk7XHJcbiAgfVxyXG59XHJcblxyXG5leHBvcnQgZGVmYXVsdCB7XHJcbiAgc2luZ2xlRXhwb3J0LFxyXG4gIGJhdGNoRXhwb3J0LFxyXG4gIHN0YXJ0RXhwb3J0LFxyXG4gIGdldEFsbG93Q29kZUV4ZWN1dGlvbixcclxuICBzZXRBbGxvd0NvZGVFeGVjdXRpb25cclxufTtcclxuIiwiLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcclxuXHJcbkhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlclxyXG5cclxuQ29weXJpZ2h0IChjKSAyMDE2LTIwMjUsIEhpZ2hzb2Z0XHJcblxyXG5MaWNlbmNlZCB1bmRlciB0aGUgTUlUIGxpY2VuY2UuXHJcblxyXG5BZGRpdGlvbmFsbHkgYSB2YWxpZCBIaWdoY2hhcnRzIGxpY2Vuc2UgaXMgcmVxdWlyZWQgZm9yIHVzZS5cclxuXHJcblNlZSBMSUNFTlNFIGZpbGUgaW4gcm9vdCBmb3IgZGV0YWlscy5cclxuXHJcbioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXHJcblxyXG4vKipcclxuICogQG92ZXJ2aWV3IFRoaXMgbW9kdWxlIHByb3ZpZGVzIHV0aWxpdHkgZnVuY3Rpb25zIGZvciBtYW5hZ2luZyBpbnRlcnZhbHNcclxuICogYW5kIHRpbWVvdXRzIGluIGEgY2VudHJhbGl6ZWQgbWFubmVyLiBJdCBtYWludGFpbnMgYSByZWdpc3RyeSBvZiBhbGwgYWN0aXZlXHJcbiAqIHRpbWVycyBhbmQgYWxsb3dzIGZvciB0aGVpciBlZmZpY2llbnQgY2xlYW51cCB3aGVuIG5lZWRlZC4gVGhpcyBjYW4gYmUgdXNlZnVsXHJcbiAqIGluIGFwcGxpY2F0aW9ucyB3aGVyZSBwcm9wZXIgcmVzb3VyY2UgbWFuYWdlbWVudCBhbmQgY2xlYW4gc2h1dGRvd24gb2YgdGltZXJzXHJcbiAqIGFyZSBjcml0aWNhbCB0byBhdm9pZCBtZW1vcnkgbGVha3Mgb3IgdW5pbnRlbmRlZCBiZWhhdmlvci5cclxuICovXHJcblxyXG5pbXBvcnQgeyBsb2cgfSBmcm9tICcuL2xvZ2dlci5qcyc7XHJcblxyXG4vLyBBcnJheSB0aGF0IGNvbnRhaW5zIGlkcyBvZiBhbGwgb25nb2luZyBpbnRlcnZhbHMgYW5kIHRpbWVvdXRzXHJcbmNvbnN0IHRpbWVySWRzID0gW107XHJcblxyXG4vKipcclxuICogQWRkcyBpZCBvZiB0aGUgYHNldEludGVydmFsYCBvciBgc2V0VGltZW91dGAgYW5kIHRvIHRoZSBgdGltZXJJZHNgIGFycmF5LlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gYWRkVGltZXJcclxuICpcclxuICogQHBhcmFtIHtOb2RlSlMuVGltZW91dH0gaWQgLSBJZCBvZiBhbiBpbnRlcnZhbCBvciBhIHRpbWVvdXQuXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gYWRkVGltZXIoaWQpIHtcclxuICB0aW1lcklkcy5wdXNoKGlkKTtcclxufVxyXG5cclxuLyoqXHJcbiAqIENsZWFycyBhbGwgb2Ygb25nb2luZyBpbnRlcnZhbHMgYW5kIHRpbWVvdXRzIGJ5IGlkcyBnYXRoZXJlZFxyXG4gKiBpbiB0aGUgYHRpbWVySWRzYCBhcnJheS5cclxuICpcclxuICogQGZ1bmN0aW9uIGNsZWFyQWxsVGltZXJzXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gY2xlYXJBbGxUaW1lcnMoKSB7XHJcbiAgbG9nKDQsIGBbdGltZXJdIENsZWFyaW5nIGFsbCByZWdpc3RlcmVkIGludGVydmFscyBhbmQgdGltZW91dHMuYCk7XHJcbiAgZm9yIChjb25zdCBpZCBvZiB0aW1lcklkcykge1xyXG4gICAgY2xlYXJJbnRlcnZhbChpZCk7XHJcbiAgICBjbGVhclRpbWVvdXQoaWQpO1xyXG4gIH1cclxufVxyXG5cclxuZXhwb3J0IGRlZmF1bHQge1xyXG4gIGFkZFRpbWVyLFxyXG4gIGNsZWFyQWxsVGltZXJzXHJcbn07XHJcbiIsIi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXHJcblxyXG5IaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXJcclxuXHJcbkNvcHlyaWdodCAoYykgMjAxNi0yMDI1LCBIaWdoc29mdFxyXG5cclxuTGljZW5jZWQgdW5kZXIgdGhlIE1JVCBsaWNlbmNlLlxyXG5cclxuQWRkaXRpb25hbGx5IGEgdmFsaWQgSGlnaGNoYXJ0cyBsaWNlbnNlIGlzIHJlcXVpcmVkIGZvciB1c2UuXHJcblxyXG5TZWUgTElDRU5TRSBmaWxlIGluIHJvb3QgZm9yIGRldGFpbHMuXHJcblxyXG4qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xyXG5cclxuLyoqXHJcbiAqIEBvdmVydmlldyBQcm92aWRlcyBtaWRkbGV3YXJlIGZ1bmN0aW9ucyBmb3IgbG9nZ2luZyBlcnJvcnMgd2l0aCBzdGFjayB0cmFjZXNcclxuICogYW5kIGhhbmRsaW5nIGVycm9yIHJlc3BvbnNlcyBpbiBhbiBFeHByZXNzIGFwcGxpY2F0aW9uLlxyXG4gKi9cclxuXHJcbmltcG9ydCB7IGdldE9wdGlvbnMgfSBmcm9tICcuLi8uLi9jb25maWcuanMnO1xyXG5pbXBvcnQgeyBsb2dXaXRoU3RhY2sgfSBmcm9tICcuLi8uLi9sb2dnZXIuanMnO1xyXG5cclxuLyoqXHJcbiAqIE1pZGRsZXdhcmUgZm9yIGxvZ2dpbmcgZXJyb3JzIHdpdGggc3RhY2sgdHJhY2UgYW5kIGhhbmRsaW5nIGVycm9yIHJlc3BvbnNlLlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gbG9nRXJyb3JNaWRkbGV3YXJlXHJcbiAqXHJcbiAqIEBwYXJhbSB7RXJyb3J9IGVycm9yIC0gVGhlIGVycm9yIG9iamVjdC5cclxuICogQHBhcmFtIHtFeHByZXNzLlJlcXVlc3R9IHJlcXVlc3QgLSBUaGUgRXhwcmVzcyByZXF1ZXN0IG9iamVjdC5cclxuICogQHBhcmFtIHtFeHByZXNzLlJlc3BvbnNlfSByZXNwb25zZSAtIFRoZSBFeHByZXNzIHJlc3BvbnNlIG9iamVjdC5cclxuICogQHBhcmFtIHtGdW5jdGlvbn0gbmV4dCAtIFRoZSBuZXh0IG1pZGRsZXdhcmUgZnVuY3Rpb24uXHJcbiAqXHJcbiAqIEByZXR1cm5zIHt1bmRlZmluZWR9IFRoZSBjYWxsIHRvIHRoZSBuZXh0IG1pZGRsZXdhcmUgZnVuY3Rpb24gd2l0aFxyXG4gKiB0aGUgcGFzc2VkIGVycm9yLlxyXG4gKi9cclxuZnVuY3Rpb24gbG9nRXJyb3JNaWRkbGV3YXJlKGVycm9yLCByZXF1ZXN0LCByZXNwb25zZSwgbmV4dCkge1xyXG4gIC8vIERpc3BsYXkgdGhlIGVycm9yIHdpdGggc3RhY2sgaW4gYSBjb3JyZWN0IGZvcm1hdFxyXG4gIGxvZ1dpdGhTdGFjaygxLCBlcnJvcik7XHJcblxyXG4gIC8vIERlbGV0ZSB0aGUgc3RhY2sgZm9yIHRoZSBlbnZpcm9ubWVudCBvdGhlciB0aGFuIHRoZSBkZXZlbG9wbWVudFxyXG4gIGlmIChnZXRPcHRpb25zKCkub3RoZXIubm9kZUVudiAhPT0gJ2RldmVsb3BtZW50Jykge1xyXG4gICAgZGVsZXRlIGVycm9yLnN0YWNrO1xyXG4gIH1cclxuXHJcbiAgLy8gQ2FsbCB0aGUgYHJldHVybkVycm9yTWlkZGxld2FyZWAgbWlkZGxld2FyZVxyXG4gIHJldHVybiBuZXh0KGVycm9yKTtcclxufVxyXG5cclxuLyoqXHJcbiAqIE1pZGRsZXdhcmUgZm9yIHJldHVybmluZyBlcnJvciByZXNwb25zZS5cclxuICpcclxuICogQGZ1bmN0aW9uIHJldHVybkVycm9yTWlkZGxld2FyZVxyXG4gKlxyXG4gKiBAcGFyYW0ge0Vycm9yfSBlcnJvciAtIFRoZSBlcnJvciBvYmplY3QuXHJcbiAqIEBwYXJhbSB7RXhwcmVzcy5SZXF1ZXN0fSByZXF1ZXN0IC0gVGhlIEV4cHJlc3MgcmVxdWVzdCBvYmplY3QuXHJcbiAqIEBwYXJhbSB7RXhwcmVzcy5SZXNwb25zZX0gcmVzcG9uc2UgLSBUaGUgRXhwcmVzcyByZXNwb25zZSBvYmplY3QuXHJcbiAqIEBwYXJhbSB7RnVuY3Rpb259IG5leHQgLSBUaGUgbmV4dCBtaWRkbGV3YXJlIGZ1bmN0aW9uLlxyXG4gKi9cclxuZnVuY3Rpb24gcmV0dXJuRXJyb3JNaWRkbGV3YXJlKGVycm9yLCByZXF1ZXN0LCByZXNwb25zZSwgbmV4dCkge1xyXG4gIC8vIEdhdGhlciBhbGwgcmVxdWllZCBpbmZvcm1hdGlvbiBmb3IgdGhlIHJlc3BvbnNlXHJcbiAgY29uc3QgeyBtZXNzYWdlLCBzdGFjayB9ID0gZXJyb3I7XHJcblxyXG4gIC8vIFVzZSB0aGUgZXJyb3IncyBzdGF0dXMgY29kZSBvciB0aGUgZGVmYXVsdCA0MDBcclxuICBjb25zdCBzdGF0dXNDb2RlID0gZXJyb3Iuc3RhdHVzQ29kZSB8fCA0MDA7XHJcblxyXG4gIC8vIFNldCBhbmQgcmV0dXJuIHJlc3BvbnNlXHJcbiAgcmVzcG9uc2Uuc3RhdHVzKHN0YXR1c0NvZGUpLmpzb24oeyBzdGF0dXNDb2RlLCBtZXNzYWdlLCBzdGFjayB9KTtcclxufVxyXG5cclxuLyoqXHJcbiAqIEFkZHMgdGhlIGVycm9yIG1pZGRsZXdhcmVzIHRvIHRoZSBwYXNzZWQgZXhwcmVzcyBhcHAgaW5zdGFuY2UuXHJcbiAqXHJcbiAqIEBwYXJhbSB7RXhwcmVzc30gYXBwIC0gVGhlIEV4cHJlc3MgYXBwIGluc3RhbmNlLlxyXG4gKi9cclxuZXhwb3J0IGRlZmF1bHQgZnVuY3Rpb24gZXJyb3JNaWRkbGV3YXJlKGFwcCkge1xyXG4gIC8vIEFkZCBsb2cgZXJyb3IgbWlkZGxld2FyZVxyXG4gIGFwcC51c2UobG9nRXJyb3JNaWRkbGV3YXJlKTtcclxuXHJcbiAgLy8gQWRkIHNldCBzdGF0dXMgYW5kIHJldHVybiBlcnJvciBtaWRkbGV3YXJlXHJcbiAgYXBwLnVzZShyZXR1cm5FcnJvck1pZGRsZXdhcmUpO1xyXG59XHJcbiIsIi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXHJcblxyXG5IaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXJcclxuXHJcbkNvcHlyaWdodCAoYykgMjAxNi0yMDI1LCBIaWdoc29mdFxyXG5cclxuTGljZW5jZWQgdW5kZXIgdGhlIE1JVCBsaWNlbmNlLlxyXG5cclxuQWRkaXRpb25hbGx5IGEgdmFsaWQgSGlnaGNoYXJ0cyBsaWNlbnNlIGlzIHJlcXVpcmVkIGZvciB1c2UuXHJcblxyXG5TZWUgTElDRU5TRSBmaWxlIGluIHJvb3QgZm9yIGRldGFpbHMuXHJcblxyXG4qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xyXG5cclxuLyoqXHJcbiAqIEBvdmVydmlldyBQcm92aWRlcyBtaWRkbGV3YXJlIGZ1bmN0aW9ucyBmb3IgY29uZmlndXJpbmcgYW5kIGVuYWJsaW5nIHJhdGVcclxuICogbGltaXRpbmcgaW4gYW4gRXhwcmVzcyBhcHBsaWNhdGlvbi5cclxuICovXHJcblxyXG5pbXBvcnQgcmF0ZUxpbWl0IGZyb20gJ2V4cHJlc3MtcmF0ZS1saW1pdCc7XHJcblxyXG5pbXBvcnQgeyBsb2cgfSBmcm9tICcuLi8uLi9sb2dnZXIuanMnO1xyXG5cclxuaW1wb3J0IEV4cG9ydEVycm9yIGZyb20gJy4uLy4uL2Vycm9ycy9FeHBvcnRFcnJvci5qcyc7XHJcblxyXG4vKipcclxuICogTWlkZGxld2FyZSBmb3IgZW5hYmxpbmcgcmF0ZSBsaW1pdGluZyBvbiB0aGUgc3BlY2lmaWVkIEV4cHJlc3MgYXBwLlxyXG4gKlxyXG4gKiBAcGFyYW0ge0V4cHJlc3N9IGFwcCAtIFRoZSBFeHByZXNzIGFwcCBpbnN0YW5jZS5cclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IHJhdGVMaW1pdGluZ09wdGlvbnMgLSBUaGUgY29uZmlndXJhdGlvbiBvYmplY3QgY29udGFpbmluZ1xyXG4gKiBgcmF0ZUxpbWl0aW5nYCBvcHRpb25zLlxyXG4gKlxyXG4gKiBAdGhyb3dzIHtFeHBvcnRFcnJvcn0gVGhyb3dzIGFuIGBFeHBvcnRFcnJvcmAgaWYgY291bGQgbm90IGNvbmZpZ3VyZSBhbmQgc2V0XHJcbiAqIHRoZSByYXRlIGxpbWl0aW5nIG9wdGlvbnMuXHJcbiAqL1xyXG5leHBvcnQgZGVmYXVsdCBmdW5jdGlvbiByYXRlTGltaXRpbmdNaWRkbGV3YXJlKGFwcCwgcmF0ZUxpbWl0aW5nT3B0aW9ucykge1xyXG4gIHRyeSB7XHJcbiAgICAvLyBDaGVjayBpZiB0aGUgcmF0ZSBsaW1pdGluZyBpcyBlbmFibGVkXHJcbiAgICBpZiAocmF0ZUxpbWl0aW5nT3B0aW9ucy5lbmFibGUpIHtcclxuICAgICAgY29uc3QgbWVzc2FnZSA9XHJcbiAgICAgICAgJ1RvbyBtYW55IHJlcXVlc3RzLCB5b3UgaGF2ZSBiZWVuIHJhdGUgbGltaXRlZC4gUGxlYXNlIHRyeSBhZ2FpbiBsYXRlci4nO1xyXG5cclxuICAgICAgLy8gT3B0aW9ucyBmb3IgdGhlIHJhdGUgbGltaXRlclxyXG4gICAgICBjb25zdCByYXRlT3B0aW9ucyA9IHtcclxuICAgICAgICB3aW5kb3c6IHJhdGVMaW1pdGluZ09wdGlvbnMud2luZG93IHx8IDEsXHJcbiAgICAgICAgbWF4UmVxdWVzdHM6IHJhdGVMaW1pdGluZ09wdGlvbnMubWF4UmVxdWVzdHMgfHwgMzAsXHJcbiAgICAgICAgZGVsYXk6IHJhdGVMaW1pdGluZ09wdGlvbnMuZGVsYXkgfHwgMCxcclxuICAgICAgICB0cnVzdFByb3h5OiByYXRlTGltaXRpbmdPcHRpb25zLnRydXN0UHJveHkgfHwgZmFsc2UsXHJcbiAgICAgICAgc2tpcEtleTogcmF0ZUxpbWl0aW5nT3B0aW9ucy5za2lwS2V5IHx8IG51bGwsXHJcbiAgICAgICAgc2tpcFRva2VuOiByYXRlTGltaXRpbmdPcHRpb25zLnNraXBUb2tlbiB8fCBudWxsXHJcbiAgICAgIH07XHJcblxyXG4gICAgICAvLyBTZXQgaWYgYmVoaW5kIGEgcHJveHlcclxuICAgICAgaWYgKHJhdGVPcHRpb25zLnRydXN0UHJveHkpIHtcclxuICAgICAgICBhcHAuZW5hYmxlKCd0cnVzdCBwcm94eScpO1xyXG4gICAgICB9XHJcblxyXG4gICAgICAvLyBDcmVhdGUgYSBsaW1pdGVyXHJcbiAgICAgIGNvbnN0IGxpbWl0ZXIgPSByYXRlTGltaXQoe1xyXG4gICAgICAgIC8vIFRpbWUgZnJhbWUgZm9yIHdoaWNoIHJlcXVlc3RzIGFyZSBjaGVja2VkIGFuZCByZW1lbWJlcmVkXHJcbiAgICAgICAgd2luZG93TXM6IHJhdGVPcHRpb25zLndpbmRvdyAqIDYwICogMTAwMCxcclxuICAgICAgICAvLyBMaW1pdCBlYWNoIElQIHRvIDEwMCByZXF1ZXN0cyBwZXIgYHdpbmRvd01zYFxyXG4gICAgICAgIGxpbWl0OiByYXRlT3B0aW9ucy5tYXhSZXF1ZXN0cyxcclxuICAgICAgICAvLyBEaXNhYmxlIGRlbGF5aW5nLCBmdWxsIHNwZWVkIHVudGlsIHRoZSBtYXggbGltaXQgaXMgcmVhY2hlZFxyXG4gICAgICAgIGRlbGF5TXM6IHJhdGVPcHRpb25zLmRlbGF5LFxyXG4gICAgICAgIGhhbmRsZXI6IChyZXF1ZXN0LCByZXNwb25zZSkgPT4ge1xyXG4gICAgICAgICAgcmVzcG9uc2UuZm9ybWF0KHtcclxuICAgICAgICAgICAganNvbjogKCkgPT4ge1xyXG4gICAgICAgICAgICAgIHJlc3BvbnNlLnN0YXR1cyg0MjkpLnNlbmQoeyBtZXNzYWdlIH0pO1xyXG4gICAgICAgICAgICB9LFxyXG4gICAgICAgICAgICBkZWZhdWx0OiAoKSA9PiB7XHJcbiAgICAgICAgICAgICAgcmVzcG9uc2Uuc3RhdHVzKDQyOSkuc2VuZChtZXNzYWdlKTtcclxuICAgICAgICAgICAgfVxyXG4gICAgICAgICAgfSk7XHJcbiAgICAgICAgfSxcclxuICAgICAgICBza2lwOiAocmVxdWVzdCkgPT4ge1xyXG4gICAgICAgICAgLy8gQWxsb3cgYnlwYXNzaW5nIHRoZSBsaW1pdGVyIGlmIGEgdmFsaWQga2V5L3Rva2VuIGhhcyBiZWVuIHNlbnRcclxuICAgICAgICAgIGlmIChcclxuICAgICAgICAgICAgcmF0ZU9wdGlvbnMuc2tpcEtleSAhPT0gbnVsbCAmJlxyXG4gICAgICAgICAgICByYXRlT3B0aW9ucy5za2lwVG9rZW4gIT09IG51bGwgJiZcclxuICAgICAgICAgICAgcmVxdWVzdC5xdWVyeS5rZXkgPT09IHJhdGVPcHRpb25zLnNraXBLZXkgJiZcclxuICAgICAgICAgICAgcmVxdWVzdC5xdWVyeS5hY2Nlc3NfdG9rZW4gPT09IHJhdGVPcHRpb25zLnNraXBUb2tlblxyXG4gICAgICAgICAgKSB7XHJcbiAgICAgICAgICAgIGxvZyg0LCAnW3JhdGUgbGltaXRpbmddIFNraXBwaW5nIHJhdGUgbGltaXRlci4nKTtcclxuICAgICAgICAgICAgcmV0dXJuIHRydWU7XHJcbiAgICAgICAgICB9XHJcbiAgICAgICAgICByZXR1cm4gZmFsc2U7XHJcbiAgICAgICAgfVxyXG4gICAgICB9KTtcclxuXHJcbiAgICAgIC8vIFVzZSBhIGxpbWl0ZXIgYXMgYSBtaWRkbGV3YXJlXHJcbiAgICAgIGFwcC51c2UobGltaXRlcik7XHJcblxyXG4gICAgICBsb2coXHJcbiAgICAgICAgMyxcclxuICAgICAgICBgW3JhdGUgbGltaXRpbmddIEVuYWJsZWQgcmF0ZSBsaW1pdGluZyB3aXRoICR7cmF0ZU9wdGlvbnMubWF4UmVxdWVzdHN9IHJlcXVlc3RzIHBlciAke3JhdGVPcHRpb25zLndpbmRvd30gbWludXRlIGZvciBlYWNoIElQLCB0cnVzdGluZyBwcm94eTogJHtyYXRlT3B0aW9ucy50cnVzdFByb3h5fS5gXHJcbiAgICAgICk7XHJcbiAgICB9XHJcbiAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcihcclxuICAgICAgJ1tyYXRlIGxpbWl0aW5nXSBDb3VsZCBub3QgY29uZmlndXJlIGFuZCBzZXQgdGhlIHJhdGUgbGltaXRpbmcgb3B0aW9ucy4nLFxyXG4gICAgICA1MDBcclxuICAgICkuc2V0RXJyb3IoZXJyb3IpO1xyXG4gIH1cclxufVxyXG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxyXG5cclxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXHJcblxyXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNSwgSGlnaHNvZnRcclxuXHJcbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cclxuXHJcbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxyXG5cclxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxyXG5cclxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cclxuXHJcbi8qKlxyXG4gKiBAb3ZlcnZpZXcgUHJvdmlkZXMgbWlkZGxld2FyZSBmdW5jdGlvbnMgZm9yIHZhbGlkYXRpbmcgaW5jb21pbmcgSFRUUCByZXF1ZXN0c1xyXG4gKiBpbiBhbiBFeHByZXNzIGFwcGxpY2F0aW9uLiBUaGlzIG1vZHVsZSBlbnN1cmVzIHRoYXQgcmVxdWVzdHMgY29udGFpblxyXG4gKiBhcHByb3ByaWF0ZSBjb250ZW50IHR5cGVzIGFuZCB2YWxpZCByZXF1ZXN0IGJvZGllcywgaW5jbHVkaW5nIHByb3BlciBKU09OXHJcbiAqIHN0cnVjdHVyZXMgYW5kIGNoYXJ0IGRhdGEgZm9yIGV4cG9ydHMuIEl0IGNoZWNrcyBmb3IgcG90ZW50aWFsIGlzc3VlcyBzdWNoXHJcbiAqIGFzIG1pc3Npbmcgb3IgbWFsZm9ybWVkIGRhdGEsIHByaXZhdGUgcmFuZ2UgVVJMcyBpbiBTVkcgcGF5bG9hZHMsIGFuZCBhbGxvd3NcclxuICogZm9yIGZsZXhpYmxlIG9wdGlvbnMgdmFsaWRhdGlvbi4gVGhlIG1pZGRsZXdhcmUgbG9ncyBkZXRhaWxlZCBpbmZvcm1hdGlvblxyXG4gKiBhbmQgaGFuZGxlcyBlcnJvcnMgcmVsYXRlZCB0byBpbmNvcnJlY3QgcGF5bG9hZHMsIGNoYXJ0IGRhdGEsIGFuZCBwcml2YXRlIFVSTFxyXG4gKiB1c2FnZS5cclxuICovXHJcblxyXG5pbXBvcnQgeyB2NCBhcyB1dWlkIH0gZnJvbSAndXVpZCc7XHJcblxyXG5pbXBvcnQgeyBnZXRBbGxvd0NvZGVFeGVjdXRpb24gfSBmcm9tICcuLi8uLi9jaGFydC5qcyc7XHJcbmltcG9ydCB7IGlzQWxsb3dlZENvbmZpZywgdmFsaWRhdGVPcHRpb25zIH0gZnJvbSAnLi4vLi4vY29uZmlnLmpzJztcclxuaW1wb3J0IHsgbG9nIH0gZnJvbSAnLi4vLi4vbG9nZ2VyLmpzJztcclxuaW1wb3J0IHsgaXNPYmplY3RFbXB0eSwgaXNQcml2YXRlUmFuZ2VVcmxGb3VuZCB9IGZyb20gJy4uLy4uL3V0aWxzLmpzJztcclxuXHJcbmltcG9ydCBFeHBvcnRFcnJvciBmcm9tICcuLi8uLi9lcnJvcnMvRXhwb3J0RXJyb3IuanMnO1xyXG5cclxuLyoqXHJcbiAqIE1pZGRsZXdhcmUgZm9yIHZhbGlkYXRpbmcgdGhlIGNvbnRlbnQtdHlwZSBoZWFkZXIuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBjb250ZW50VHlwZU1pZGRsZXdhcmVcclxuICpcclxuICogQHBhcmFtIHtFeHByZXNzLlJlcXVlc3R9IHJlcXVlc3QgLSBUaGUgRXhwcmVzcyByZXF1ZXN0IG9iamVjdC5cclxuICogQHBhcmFtIHtFeHByZXNzLlJlc3BvbnNlfSByZXNwb25zZSAtIFRoZSBFeHByZXNzIHJlc3BvbnNlIG9iamVjdC5cclxuICogQHBhcmFtIHtGdW5jdGlvbn0gbmV4dCAtIFRoZSBuZXh0IG1pZGRsZXdhcmUgZnVuY3Rpb24uXHJcbiAqXHJcbiAqIEByZXR1cm5zIHt1bmRlZmluZWR9IFRoZSBjYWxsIHRvIHRoZSBuZXh0IG1pZGRsZXdhcmUgZnVuY3Rpb24uXHJcbiAqXHJcbiAqIEB0aHJvd3Mge0V4cG9ydEVycm9yfSBUaHJvd3MgYW4gYEV4cG9ydEVycm9yYCBpZiB0aGUgY29udGVudC10eXBlXHJcbiAqIGlzIG5vdCBjb3JyZWN0LlxyXG4gKi9cclxuZnVuY3Rpb24gY29udGVudFR5cGVNaWRkbGV3YXJlKHJlcXVlc3QsIHJlc3BvbnNlLCBuZXh0KSB7XHJcbiAgdHJ5IHtcclxuICAgIC8vIEdldCB0aGUgY29udGVudCB0eXBlIGhlYWRlclxyXG4gICAgY29uc3QgY29udGVudFR5cGUgPSByZXF1ZXN0LmhlYWRlcnNbJ2NvbnRlbnQtdHlwZSddIHx8ICcnO1xyXG5cclxuICAgIC8vIEFsbG93IG9ubHkgSlNPTiwgVVJMLWVuY29kZWQgYW5kIGZvcm0gZGF0YSB3aXRob3V0IGZpbGVzIHR5cGVzIG9mIGRhdGFcclxuICAgIGlmIChcclxuICAgICAgIWNvbnRlbnRUeXBlLmluY2x1ZGVzKCdhcHBsaWNhdGlvbi9qc29uJykgJiZcclxuICAgICAgIWNvbnRlbnRUeXBlLmluY2x1ZGVzKCdhcHBsaWNhdGlvbi94LXd3dy1mb3JtLXVybGVuY29kZWQnKSAmJlxyXG4gICAgICAhY29udGVudFR5cGUuaW5jbHVkZXMoJ211bHRpcGFydC9mb3JtLWRhdGEnKVxyXG4gICAgKSB7XHJcbiAgICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcihcclxuICAgICAgICAnW3ZhbGlkYXRpb25dIENvbnRlbnQtVHlwZSBtdXN0IGJlIGFwcGxpY2F0aW9uL2pzb24sIGFwcGxpY2F0aW9uL3gtd3d3LWZvcm0tdXJsZW5jb2RlZCwgb3IgbXVsdGlwYXJ0L2Zvcm0tZGF0YS4nLFxyXG4gICAgICAgIDQxNVxyXG4gICAgICApO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIENhbGwgdGhlIGByZXF1ZXN0Qm9keU1pZGRsZXdhcmVgIG1pZGRsZXdhcmVcclxuICAgIHJldHVybiBuZXh0KCk7XHJcbiAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgIHJldHVybiBuZXh0KGVycm9yKTtcclxuICB9XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBNaWRkbGV3YXJlIGZvciB2YWxpZGF0aW5nIHRoZSByZXF1ZXN0J3MgYm9keS5cclxuICpcclxuICogQGZ1bmN0aW9uIHJlcXVlc3RCb2R5TWlkZGxld2FyZVxyXG4gKlxyXG4gKiBAcGFyYW0ge0V4cHJlc3MuUmVxdWVzdH0gcmVxdWVzdCAtIFRoZSBFeHByZXNzIHJlcXVlc3Qgb2JqZWN0LlxyXG4gKiBAcGFyYW0ge0V4cHJlc3MuUmVzcG9uc2V9IHJlc3BvbnNlIC0gVGhlIEV4cHJlc3MgcmVzcG9uc2Ugb2JqZWN0LlxyXG4gKiBAcGFyYW0ge0Z1bmN0aW9ufSBuZXh0IC0gVGhlIG5leHQgbWlkZGxld2FyZSBmdW5jdGlvbi5cclxuICpcclxuICogQHJldHVybnMge3VuZGVmaW5lZH0gVGhlIGNhbGwgdG8gdGhlIG5leHQgbWlkZGxld2FyZSBmdW5jdGlvbi5cclxuICpcclxuICogQHRocm93cyB7RXhwb3J0RXJyb3J9IFRocm93cyBhbiBgRXhwb3J0RXJyb3JgIGlmIHRoZSBib2R5IGlzIG5vdCBjb3JyZWN0LlxyXG4gKiBAdGhyb3dzIHtFeHBvcnRFcnJvcn0gVGhyb3dzIGFuIGBFeHBvcnRFcnJvcmAgaWYgdGhlIGNoYXJ0IGRhdGEgZnJvbSB0aGUgYm9keVxyXG4gKiBpcyBub3QgY29ycmVjdC5cclxuICogQHRocm93cyB7RXhwb3J0RXJyb3J9IFRocm93cyBhbiBgRXhwb3J0RXJyb3JgIGluIGNhc2Ugb2YgdGhlIHByaXZhdGUgcmFuZ2VcclxuICogdXJsIGVycm9yLlxyXG4gKi9cclxuZnVuY3Rpb24gcmVxdWVzdEJvZHlNaWRkbGV3YXJlKHJlcXVlc3QsIHJlc3BvbnNlLCBuZXh0KSB7XHJcbiAgdHJ5IHtcclxuICAgIC8vIEdldCB0aGUgcmVxdWVzdCBib2R5XHJcbiAgICBjb25zdCBib2R5ID0gcmVxdWVzdC5ib2R5O1xyXG5cclxuICAgIC8vIENyZWF0ZSBhIHVuaXF1ZSBJRCBmb3IgYSByZXF1ZXN0XHJcbiAgICBjb25zdCByZXF1ZXN0SWQgPSB1dWlkKCk7XHJcblxyXG4gICAgLy8gVGhyb3cgYW4gZXJyb3IgaWYgdGhlcmUgaXMgbm8gY29ycmVjdCBib2R5XHJcbiAgICBpZiAoIWJvZHkgfHwgaXNPYmplY3RFbXB0eShib2R5KSkge1xyXG4gICAgICBsb2coXHJcbiAgICAgICAgMixcclxuICAgICAgICBgW3ZhbGlkYXRpb25dIFJlcXVlc3QgWyR7cmVxdWVzdElkfV0gLSBUaGUgcmVxdWVzdCBmcm9tICR7XHJcbiAgICAgICAgICByZXF1ZXN0LmhlYWRlcnNbJ3gtZm9yd2FyZGVkLWZvciddIHx8IHJlcXVlc3QuY29ubmVjdGlvbi5yZW1vdGVBZGRyZXNzXHJcbiAgICAgICAgfSB3YXMgaW5jb3JyZWN0LiBSZWNlaXZlZCBwYXlsb2FkIGlzIGVtcHR5LmBcclxuICAgICAgKTtcclxuXHJcbiAgICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcihcclxuICAgICAgICBgW3ZhbGlkYXRpb25dIFJlcXVlc3QgWyR7cmVxdWVzdElkfV0gLSBUaGUgcmVxdWVzdCBib2R5IGlzIHJlcXVpcmVkLiBQbGVhc2UgZW5zdXJlIHRoYXQgeW91ciBDb250ZW50LVR5cGUgaGVhZGVyIGlzIGNvcnJlY3QuIEFjY2VwdGVkIHR5cGVzIGFyZSAnYXBwbGljYXRpb24vanNvbicgYW5kICdtdWx0aXBhcnQvZm9ybS1kYXRhJy5gLFxyXG4gICAgICAgIDQwMFxyXG4gICAgICApO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIEdldCB0aGUgYGFsbG93Q29kZUV4ZWN1dGlvbmAgb3B0aW9uIGZvciB0aGUgc2VydmVyXHJcbiAgICBjb25zdCBhbGxvd0NvZGVFeGVjdXRpb24gPSBnZXRBbGxvd0NvZGVFeGVjdXRpb24oKTtcclxuXHJcbiAgICAvLyBGaW5kIGEgY29ycmVjdCBjaGFydCBvcHRpb25zXHJcbiAgICBjb25zdCBpbnN0ciA9IGlzQWxsb3dlZENvbmZpZyhcclxuICAgICAgLy8gVXNlIG9uZSBvZiB0aGUgYmVsb3dcclxuICAgICAgYm9keS5pbnN0ciB8fCBib2R5Lm9wdGlvbnMgfHwgYm9keS5pbmZpbGUgfHwgYm9keS5kYXRhLFxyXG4gICAgICAvLyBTdHJpbmdpZnkgb3B0aW9uc1xyXG4gICAgICB0cnVlLFxyXG4gICAgICAvLyBBbGxvdyBvciBkaXNhbGxvdyBmdW5jdGlvbnNcclxuICAgICAgYWxsb3dDb2RlRXhlY3V0aW9uXHJcbiAgICApO1xyXG5cclxuICAgIC8vIFRocm93IGFuIGVycm9yIGlmIHRoZXJlIGlzIG5vIGNvcnJlY3QgY2hhcnQgZGF0YVxyXG4gICAgaWYgKGluc3RyID09PSBudWxsICYmICFib2R5LnN2Zykge1xyXG4gICAgICBsb2coXHJcbiAgICAgICAgMixcclxuICAgICAgICBgW3ZhbGlkYXRpb25dIFJlcXVlc3QgWyR7cmVxdWVzdElkfV0gLSBUaGUgcmVxdWVzdCBmcm9tICR7XHJcbiAgICAgICAgICByZXF1ZXN0LmhlYWRlcnNbJ3gtZm9yd2FyZGVkLWZvciddIHx8IHJlcXVlc3QuY29ubmVjdGlvbi5yZW1vdGVBZGRyZXNzXHJcbiAgICAgICAgfSB3YXMgaW5jb3JyZWN0LiBSZWNlaXZlZCBwYXlsb2FkIGlzIG1pc3NpbmcgY29ycmVjdCBjaGFydCBkYXRhIGZvciBleHBvcnQ6ICR7SlNPTi5zdHJpbmdpZnkoYm9keSl9LmBcclxuICAgICAgKTtcclxuXHJcbiAgICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcihcclxuICAgICAgICBgUmVxdWVzdCBbJHtyZXF1ZXN0SWR9XSAtIFt2YWxpZGF0aW9uXSBObyBjb3JyZWN0IGNoYXJ0IGRhdGEgZm91bmQuIEVuc3VyZSB0aGF0IHlvdSBhcmUgdXNpbmcgZWl0aGVyIGFwcGxpY2F0aW9uL2pzb24gb3IgbXVsdGlwYXJ0L2Zvcm0tZGF0YSBoZWFkZXJzLiBJZiBzZW5kaW5nIEpTT04sIG1ha2Ugc3VyZSB0aGUgY2hhcnQgZGF0YSBpcyBpbiB0aGUgJ2luZmlsZScsICdvcHRpb25zJywgb3IgJ2RhdGEnIGF0dHJpYnV0ZS4gSWYgc2VuZGluZyBTVkcsIGVuc3VyZSBpdCBpcyBpbiB0aGUgJ3N2ZycgYXR0cmlidXRlLmAsXHJcbiAgICAgICAgNDAwXHJcbiAgICAgICk7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gVGhyb3cgYW4gZXJyb3IgaWYgdGVzdCBvZiB4bGluazpocmVmIGVsZW1lbnRzIGZyb20gcGF5bG9hZCdzIFNWRyBmYWlsc1xyXG4gICAgaWYgKGJvZHkuc3ZnICYmIGlzUHJpdmF0ZVJhbmdlVXJsRm91bmQoYm9keS5zdmcpKSB7XHJcbiAgICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcihcclxuICAgICAgICBgUmVxdWVzdCBbJHtyZXF1ZXN0SWR9XSAtIFt2YWxpZGF0aW9uXSBTVkcgcG90ZW50aWFsbHkgY29udGFpbiBhdCBsZWFzdCBvbmUgZm9yYmlkZGVuIFVSTCBpbiAneGxpbms6aHJlZicgZWxlbWVudC4gUGxlYXNlIHJldmlldyB0aGUgU1ZHIGNvbnRlbnQgYW5kIGVuc3VyZSB0aGF0IGFsbCByZWZlcmVuY2VkIFVSTHMgY29tcGx5IHdpdGggc2VjdXJpdHkgcG9saWNpZXMuYCxcclxuICAgICAgICA0MDBcclxuICAgICAgKTtcclxuICAgIH1cclxuXHJcbiAgICAvLyBWYWxpZGF0ZSB0aGUgcmVxdWVzdCBvcHRpb25zIGFuZCBzdG9yZSBwYXJzZWQgc3RydWN0dXJlIGluIHRoZSByZXF1ZXN0XHJcbiAgICByZXF1ZXN0LnZhbGlkYXRlZE9wdGlvbnMgPSB2YWxpZGF0ZU9wdGlvbnMoe1xyXG4gICAgICAvLyBTZXQgdGhlIGNyZWF0ZWQgSUQgYXMgYSBgcmVxdWVzdElkYCBwcm9wZXJ0eSBpbiB0aGUgb3B0aW9uc1xyXG4gICAgICByZXF1ZXN0SWQsXHJcbiAgICAgIGV4cG9ydDoge1xyXG4gICAgICAgIGluc3RyLFxyXG4gICAgICAgIHN2ZzogYm9keS5zdmcsXHJcbiAgICAgICAgb3V0ZmlsZTpcclxuICAgICAgICAgIGJvZHkub3V0ZmlsZSB8fFxyXG4gICAgICAgICAgYCR7cmVxdWVzdC5wYXJhbXMuZmlsZW5hbWUgfHwgJ2NoYXJ0J30uJHtib2R5LnR5cGUgfHwgJ3BuZyd9YCxcclxuICAgICAgICB0eXBlOiBib2R5LnR5cGUsXHJcbiAgICAgICAgY29uc3RyOiBib2R5LmNvbnN0cixcclxuICAgICAgICBiNjQ6IGJvZHkuYjY0LFxyXG4gICAgICAgIG5vRG93bmxvYWQ6IGJvZHkubm9Eb3dubG9hZCxcclxuICAgICAgICBoZWlnaHQ6IGJvZHkuaGVpZ2h0LFxyXG4gICAgICAgIHdpZHRoOiBib2R5LndpZHRoLFxyXG4gICAgICAgIHNjYWxlOiBib2R5LnNjYWxlLFxyXG4gICAgICAgIGdsb2JhbE9wdGlvbnM6IGlzQWxsb3dlZENvbmZpZyhcclxuICAgICAgICAgIGJvZHkuZ2xvYmFsT3B0aW9ucyxcclxuICAgICAgICAgIHRydWUsXHJcbiAgICAgICAgICBhbGxvd0NvZGVFeGVjdXRpb25cclxuICAgICAgICApLFxyXG4gICAgICAgIHRoZW1lT3B0aW9uczogaXNBbGxvd2VkQ29uZmlnKFxyXG4gICAgICAgICAgYm9keS50aGVtZU9wdGlvbnMsXHJcbiAgICAgICAgICB0cnVlLFxyXG4gICAgICAgICAgYWxsb3dDb2RlRXhlY3V0aW9uXHJcbiAgICAgICAgKVxyXG4gICAgICB9LFxyXG4gICAgICBjdXN0b21Mb2dpYzoge1xyXG4gICAgICAgIGFsbG93Q29kZUV4ZWN1dGlvbixcclxuICAgICAgICBhbGxvd0ZpbGVSZXNvdXJjZXM6IGZhbHNlLFxyXG4gICAgICAgIGN1c3RvbUNvZGU6IGJvZHkuY3VzdG9tQ29kZSxcclxuICAgICAgICBjYWxsYmFjazogYm9keS5jYWxsYmFjayxcclxuICAgICAgICByZXNvdXJjZXM6IGlzQWxsb3dlZENvbmZpZyhib2R5LnJlc291cmNlcywgdHJ1ZSwgYWxsb3dDb2RlRXhlY3V0aW9uKVxyXG4gICAgICB9XHJcbiAgICB9KTtcclxuXHJcbiAgICAvLyBDYWxsIHRoZSBuZXh0IG1pZGRsZXdhcmVcclxuICAgIHJldHVybiBuZXh0KCk7XHJcbiAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgIHJldHVybiBuZXh0KGVycm9yKTtcclxuICB9XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBBZGRzIHRoZSB2YWxpZGF0aW9uIG1pZGRsZXdhcmVzIHRvIHRoZSBwYXNzZWQgZXhwcmVzcyBhcHAgaW5zdGFuY2UuXHJcbiAqXHJcbiAqIEBwYXJhbSB7RXhwcmVzc30gYXBwIC0gVGhlIEV4cHJlc3MgYXBwIGluc3RhbmNlLlxyXG4gKi9cclxuZXhwb3J0IGRlZmF1bHQgZnVuY3Rpb24gdmFsaWRhdGlvbk1pZGRsZXdhcmUoYXBwKSB7XHJcbiAgLy8gQWRkIGNvbnRlbnQgdHlwZSB2YWxpZGF0aW9uIG1pZGRsZXdhcmVcclxuICBhcHAucG9zdChbJy8nLCAnLzpmaWxlbmFtZSddLCBjb250ZW50VHlwZU1pZGRsZXdhcmUpO1xyXG5cclxuICAvLyBBZGQgcmVxdWVzdCBib2R5IHJlcXVlc3QgdmFsaWRhdGlvbiBtaWRkbGV3YXJlXHJcbiAgYXBwLnBvc3QoWycvJywgJy86ZmlsZW5hbWUnXSwgcmVxdWVzdEJvZHlNaWRkbGV3YXJlKTtcclxufVxyXG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxyXG5cclxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXHJcblxyXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNSwgSGlnaHNvZnRcclxuXHJcbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cclxuXHJcbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxyXG5cclxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxyXG5cclxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cclxuXHJcbi8qKlxyXG4gKiBAb3ZlcnZpZXcgRGVmaW5lcyB0aGUgZXhwb3J0IHJvdXRlcyBhbmQgbG9naWMgZm9yIGhhbmRsaW5nIGNoYXJ0IGV4cG9ydFxyXG4gKiByZXF1ZXN0cyBpbiBhbiBFeHByZXNzIHNlcnZlci4gVGhpcyBtb2R1bGUgcHJvY2Vzc2VzIGluY29taW5nIHJlcXVlc3RzXHJcbiAqIHRvIGV4cG9ydCBjaGFydHMgaW4gdmFyaW91cyBmb3JtYXRzIChlLmcuIEpQRUcsIFBORywgUERGLCBTVkcpLiBJdCBpbnRlZ3JhdGVzXHJcbiAqIHdpdGggSGlnaGNoYXJ0cycgY29yZSBmdW5jdGlvbmFsaXRpZXMgYW5kIHN1cHBvcnRzIGJvdGggaW1tZWRpYXRlIGRvd25sb2FkXHJcbiAqIHJlc3BvbnNlcyBhbmQgQmFzZTY0LWVuY29kZWQgY29udGVudCByZXR1cm5zLiBUaGUgY29kZSBhbHNvIGZlYXR1cmVzXHJcbiAqIGJlbmNobWFya2luZyBmb3IgcGVyZm9ybWFuY2UgbW9uaXRvcmluZy5cclxuICovXHJcblxyXG5pbXBvcnQgeyBzdGFydEV4cG9ydCB9IGZyb20gJy4uLy4uL2NoYXJ0LmpzJztcclxuaW1wb3J0IHsgbG9nIH0gZnJvbSAnLi4vLi4vbG9nZ2VyLmpzJztcclxuaW1wb3J0IHsgZ2V0QmFzZTY0LCBtZWFzdXJlVGltZSB9IGZyb20gJy4uLy4uL3V0aWxzLmpzJztcclxuXHJcbmltcG9ydCBFeHBvcnRFcnJvciBmcm9tICcuLi8uLi9lcnJvcnMvRXhwb3J0RXJyb3IuanMnO1xyXG5cclxuLy8gUmV2ZXJzZWQgTUlNRSB0eXBlc1xyXG5jb25zdCByZXZlcnNlZE1pbWUgPSB7XHJcbiAgcG5nOiAnaW1hZ2UvcG5nJyxcclxuICBqcGVnOiAnaW1hZ2UvanBlZycsXHJcbiAgZ2lmOiAnaW1hZ2UvZ2lmJyxcclxuICBwZGY6ICdhcHBsaWNhdGlvbi9wZGYnLFxyXG4gIHN2ZzogJ2ltYWdlL3N2Zyt4bWwnXHJcbn07XHJcblxyXG4vKipcclxuICogSGFuZGxlcyB0aGUgZXhwb3J0IHJlcXVlc3RzIGZyb20gdGhlIGNsaWVudC5cclxuICpcclxuICogQGFzeW5jXHJcbiAqIEBmdW5jdGlvbiByZXF1ZXN0RXhwb3J0XHJcbiAqXHJcbiAqIEBwYXJhbSB7RXhwcmVzcy5SZXF1ZXN0fSByZXF1ZXN0IC0gVGhlIEV4cHJlc3MgcmVxdWVzdCBvYmplY3QuXHJcbiAqIEBwYXJhbSB7RXhwcmVzcy5SZXNwb25zZX0gcmVzcG9uc2UgLSBUaGUgRXhwcmVzcyByZXNwb25zZSBvYmplY3QuXHJcbiAqIEBwYXJhbSB7RnVuY3Rpb259IG5leHQgLSBUaGUgbmV4dCBtaWRkbGV3YXJlIGZ1bmN0aW9uLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7UHJvbWlzZTx2b2lkPn0gQSBQcm9taXNlIHRoYXQgcmVzb2x2ZXMgb25jZSB0aGUgZXhwb3J0IHByb2Nlc3NcclxuICogaXMgY29tcGxldGUuXHJcbiAqL1xyXG5hc3luYyBmdW5jdGlvbiByZXF1ZXN0RXhwb3J0KHJlcXVlc3QsIHJlc3BvbnNlLCBuZXh0KSB7XHJcbiAgdHJ5IHtcclxuICAgIC8vIFN0YXJ0IGNvdW50aW5nIHRpbWUgZm9yIGEgcmVxdWVzdFxyXG4gICAgY29uc3QgcmVxdWVzdENvdW50ZXIgPSBtZWFzdXJlVGltZSgpO1xyXG5cclxuICAgIC8vIEluIGNhc2UgdGhlIGNvbm5lY3Rpb24gaXMgY2xvc2VkLCBmb3JjZSB0byBhYm9ydCBmdXJ0aGVyIGFjdGlvbnNcclxuICAgIGxldCBjb25uZWN0aW9uQWJvcnRlZCA9IGZhbHNlO1xyXG4gICAgcmVxdWVzdC5zb2NrZXQub24oJ2Nsb3NlJywgKGhhZEVycm9ycykgPT4ge1xyXG4gICAgICBpZiAoaGFkRXJyb3JzKSB7XHJcbiAgICAgICAgY29ubmVjdGlvbkFib3J0ZWQgPSB0cnVlO1xyXG4gICAgICB9XHJcbiAgICB9KTtcclxuXHJcbiAgICAvLyBHZXQgdGhlIG9wdGlvbnMgcHJldmlvdXNseSB2YWxpZGF0ZWQgaW4gdGhlIHZhbGlkYXRpb24gbWlkZGxld2FyZVxyXG4gICAgY29uc3QgcmVxdWVzdE9wdGlvbnMgPSByZXF1ZXN0LnZhbGlkYXRlZE9wdGlvbnM7XHJcblxyXG4gICAgLy8gR2V0IHRoZSByZXF1ZXN0IGlkXHJcbiAgICBjb25zdCByZXF1ZXN0SWQgPSByZXF1ZXN0T3B0aW9ucy5yZXF1ZXN0SWQ7XHJcblxyXG4gICAgLy8gSW5mbyBhYm91dCBhbiBpbmNvbWluZyByZXF1ZXN0IHdpdGggY29ycmVjdCBkYXRhXHJcbiAgICBsb2coNCwgYFtleHBvcnRdIFJlcXVlc3QgWyR7cmVxdWVzdElkfV0gLSBHb3QgYW4gaW5jb21pbmcgSFRUUCByZXF1ZXN0LmApO1xyXG5cclxuICAgIC8vIFN0YXJ0IHRoZSBleHBvcnQgcHJvY2Vzc1xyXG4gICAgYXdhaXQgc3RhcnRFeHBvcnQocmVxdWVzdE9wdGlvbnMsIChlcnJvciwgZGF0YSkgPT4ge1xyXG4gICAgICAvLyBSZW1vdmUgdGhlIGNsb3NlIGV2ZW50IGZyb20gdGhlIHNvY2tldFxyXG4gICAgICByZXF1ZXN0LnNvY2tldC5yZW1vdmVBbGxMaXN0ZW5lcnMoJ2Nsb3NlJyk7XHJcblxyXG4gICAgICAvLyBJZiB0aGUgY29ubmVjdGlvbiB3YXMgY2xvc2VkLCBkbyBub3RoaW5nXHJcbiAgICAgIGlmIChjb25uZWN0aW9uQWJvcnRlZCkge1xyXG4gICAgICAgIGxvZyhcclxuICAgICAgICAgIDMsXHJcbiAgICAgICAgICBgW2V4cG9ydF0gUmVxdWVzdCBbJHtyZXF1ZXN0SWR9XSAtIFRoZSBjbGllbnQgY2xvc2VkIHRoZSBjb25uZWN0aW9uIGJlZm9yZSB0aGUgY2hhcnQgZmluaXNoZWQgcHJvY2Vzc2luZy5gXHJcbiAgICAgICAgKTtcclxuICAgICAgICByZXR1cm47XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIC8vIElmIGVycm9yLCBsb2cgaXQgYW5kIHNlbmQgaXQgdG8gdGhlIGVycm9yIG1pZGRsZXdhcmVcclxuICAgICAgaWYgKGVycm9yKSB7XHJcbiAgICAgICAgdGhyb3cgZXJyb3I7XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIC8vIElmIGRhdGEgaXMgbWlzc2luZywgbG9nIHRoZSBtZXNzYWdlIGFuZCBzZW5kIGl0IHRvIHRoZSBlcnJvciBtaWRkbGV3YXJlXHJcbiAgICAgIGlmICghZGF0YSB8fCAhZGF0YS5yZXN1bHQpIHtcclxuICAgICAgICBsb2coXHJcbiAgICAgICAgICAyLFxyXG4gICAgICAgICAgYFtleHBvcnRdIFJlcXVlc3QgWyR7cmVxdWVzdElkfV0gLSBSZXF1ZXN0IGZyb20gJHtcclxuICAgICAgICAgICAgcmVxdWVzdC5oZWFkZXJzWyd4LWZvcndhcmRlZC1mb3InXSB8fFxyXG4gICAgICAgICAgICByZXF1ZXN0LmNvbm5lY3Rpb24ucmVtb3RlQWRkcmVzc1xyXG4gICAgICAgICAgfSB3YXMgaW5jb3JyZWN0LiBSZWNlaXZlZCByZXN1bHQgaXMgJHtkYXRhLnJlc3VsdH0uYFxyXG4gICAgICAgICk7XHJcblxyXG4gICAgICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcihcclxuICAgICAgICAgIGBbZXhwb3J0XSBSZXF1ZXN0IFske3JlcXVlc3RJZH1dIC0gVW5leHBlY3RlZCByZXR1cm4gb2YgdGhlIGV4cG9ydCByZXN1bHQgZnJvbSB0aGUgY2hhcnQgZ2VuZXJhdGlvbi4gUGxlYXNlIGNoZWNrIHlvdXIgcmVxdWVzdCBkYXRhLmAsXHJcbiAgICAgICAgICA0MDBcclxuICAgICAgICApO1xyXG4gICAgICB9XHJcblxyXG4gICAgICAvLyBSZXR1cm4gdGhlIHJlc3VsdCBpbiBhbiBhcHByb3ByaWF0ZSBmb3JtYXRcclxuICAgICAgaWYgKGRhdGEucmVzdWx0KSB7XHJcbiAgICAgICAgbG9nKFxyXG4gICAgICAgICAgMyxcclxuICAgICAgICAgIGBbZXhwb3J0XSBSZXF1ZXN0IFske3JlcXVlc3RJZH1dIC0gVGhlIHdob2xlIGV4cG9ydGluZyBwcm9jZXNzIHRvb2sgJHtyZXF1ZXN0Q291bnRlcigpfW1zLmBcclxuICAgICAgICApO1xyXG5cclxuICAgICAgICAvLyBHZXQgdGhlIGB0eXBlYCwgYGI2NGAsIGBub0Rvd25sb2FkYCwgYW5kIGBvdXRmaWxlYCBmcm9tIG9wdGlvbnNcclxuICAgICAgICBjb25zdCB7IHR5cGUsIGI2NCwgbm9Eb3dubG9hZCwgb3V0ZmlsZSB9ID0gZGF0YS5vcHRpb25zLmV4cG9ydDtcclxuXHJcbiAgICAgICAgLy8gSWYgb25seSBCYXNlNjQgaXMgcmVxdWlyZWQsIHJldHVybiBpdFxyXG4gICAgICAgIGlmIChiNjQpIHtcclxuICAgICAgICAgIHJldHVybiByZXNwb25zZS5zZW5kKGdldEJhc2U2NChkYXRhLnJlc3VsdCwgdHlwZSkpO1xyXG4gICAgICAgIH1cclxuXHJcbiAgICAgICAgLy8gU2V0IGNvcnJlY3QgY29udGVudCB0eXBlXHJcbiAgICAgICAgcmVzcG9uc2UuaGVhZGVyKCdDb250ZW50LVR5cGUnLCByZXZlcnNlZE1pbWVbdHlwZV0gfHwgJ2ltYWdlL3BuZycpO1xyXG5cclxuICAgICAgICAvLyBEZWNpZGUgd2hldGhlciB0byBkb3dubG9hZCBvciBub3QgY2hhcnQgZmlsZVxyXG4gICAgICAgIGlmICghbm9Eb3dubG9hZCkge1xyXG4gICAgICAgICAgcmVzcG9uc2UuYXR0YWNobWVudChvdXRmaWxlKTtcclxuICAgICAgICB9XHJcblxyXG4gICAgICAgIC8vIElmIFNWRywgcmV0dXJuIHBsYWluIGNvbnRlbnQsIG90aGVyd2lzZSBhIGI2NCBzdHJpbmcgZnJvbSBhIGJ1ZmZlclxyXG4gICAgICAgIHJldHVybiB0eXBlID09PSAnc3ZnJ1xyXG4gICAgICAgICAgPyByZXNwb25zZS5zZW5kKGRhdGEucmVzdWx0KVxyXG4gICAgICAgICAgOiByZXNwb25zZS5zZW5kKEJ1ZmZlci5mcm9tKGRhdGEucmVzdWx0LCAnYmFzZTY0JykpO1xyXG4gICAgICB9XHJcbiAgICB9KTtcclxuICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgcmV0dXJuIG5leHQoZXJyb3IpO1xyXG4gIH1cclxufVxyXG5cclxuLyoqXHJcbiAqIEFkZHMgdGhlIGBleHBvcnRgIHJvdXRlcy5cclxuICpcclxuICogQGZ1bmN0aW9uIGV4cG9ydFJvdXRlc1xyXG4gKlxyXG4gKiBAcGFyYW0ge0V4cHJlc3N9IGFwcCAtIFRoZSBFeHByZXNzIGFwcCBpbnN0YW5jZS5cclxuICovXHJcbmV4cG9ydCBkZWZhdWx0IGZ1bmN0aW9uIGV4cG9ydFJvdXRlcyhhcHApIHtcclxuICAvKipcclxuICAgKiBBZGRzIHRoZSBQT1NUICcvJyAtIEEgcm91dGUgZm9yIGhhbmRsaW5nIFBPU1QgcmVxdWVzdHMgYXQgdGhlIHJvb3RcclxuICAgKiBlbmRwb2ludC5cclxuICAgKi9cclxuICBhcHAucG9zdCgnLycsIHJlcXVlc3RFeHBvcnQpO1xyXG5cclxuICAvKipcclxuICAgKiBBZGRzIHRoZSBQT1NUICcvOmZpbGVuYW1lJyAtIEEgcm91dGUgZm9yIGhhbmRsaW5nIFBPU1QgcmVxdWVzdHMgd2l0aFxyXG4gICAqIGEgc3BlY2lmaWVkIGZpbGVuYW1lIHBhcmFtZXRlci5cclxuICAgKi9cclxuICBhcHAucG9zdCgnLzpmaWxlbmFtZScsIHJlcXVlc3RFeHBvcnQpO1xyXG59XHJcbiIsIi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXHJcblxyXG5IaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXJcclxuXHJcbkNvcHlyaWdodCAoYykgMjAxNi0yMDI1LCBIaWdoc29mdFxyXG5cclxuTGljZW5jZWQgdW5kZXIgdGhlIE1JVCBsaWNlbmNlLlxyXG5cclxuQWRkaXRpb25hbGx5IGEgdmFsaWQgSGlnaGNoYXJ0cyBsaWNlbnNlIGlzIHJlcXVpcmVkIGZvciB1c2UuXHJcblxyXG5TZWUgTElDRU5TRSBmaWxlIGluIHJvb3QgZm9yIGRldGFpbHMuXHJcblxyXG4qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xyXG5cclxuLyoqXHJcbiAqIEBvdmVydmlldyBEZWZpbmVzIGFuIEV4cHJlc3Mgcm91dGUgZm9yIHNlcnZlciBoZWFsdGggbW9uaXRvcmluZywgaW5jbHVkaW5nXHJcbiAqIHVwdGltZSwgc3VjY2VzcyByYXRlcywgYW5kIG90aGVyIHNlcnZlciBzdGF0aXN0aWNzLlxyXG4gKi9cclxuXHJcbmltcG9ydCB7IHJlYWRGaWxlU3luYyB9IGZyb20gJ2ZzJztcclxuaW1wb3J0IHsgam9pbiB9IGZyb20gJ3BhdGgnO1xyXG5cclxuaW1wb3J0IHsgZ2V0SGlnaGNoYXJ0c1ZlcnNpb24gfSBmcm9tICcuLi8uLi9jYWNoZS5qcyc7XHJcbmltcG9ydCB7IGxvZyB9IGZyb20gJy4uLy4uL2xvZ2dlci5qcyc7XHJcbmltcG9ydCB7IGdldFBvb2xJbmZvSlNPTiwgZ2V0UG9vbFN0YXRzIH0gZnJvbSAnLi4vLi4vcG9vbC5qcyc7XHJcbmltcG9ydCB7IGFkZFRpbWVyIH0gZnJvbSAnLi4vLi4vdGltZXIuanMnO1xyXG5pbXBvcnQgeyBfX2Rpcm5hbWUsIGdldE5ld0RhdGVUaW1lIH0gZnJvbSAnLi4vLi4vdXRpbHMuanMnO1xyXG5cclxuLy8gU2V0IHRoZSBzdGFydCBkYXRlIG9mIHRoZSBzZXJ2ZXJcclxuY29uc3Qgc2VydmVyU3RhcnRUaW1lID0gbmV3IERhdGUoKTtcclxuXHJcbi8vIEdldCB0aGUgYHBhY2thZ2UuanNvbmAgY29udGVudFxyXG5jb25zdCBwYWNrYWdlRmlsZSA9IEpTT04ucGFyc2UoXHJcbiAgcmVhZEZpbGVTeW5jKGpvaW4oX19kaXJuYW1lLCAncGFja2FnZS5qc29uJyksICd1dGY4JylcclxuKTtcclxuXHJcbi8vIEFuIGFycmF5IGZvciBzdWNjZXNzIHJhdGUgcmF0aW9zXHJcbmNvbnN0IHN1Y2Nlc3NSYXRlcyA9IFtdO1xyXG5cclxuLy8gUmVjb3JkIGV2ZXJ5IG1pbnV0ZVxyXG5jb25zdCByZWNvcmRJbnRlcnZhbCA9IDYwICogMTAwMDtcclxuXHJcbi8vIDMwIG1pbnV0ZXNcclxuY29uc3Qgd2luZG93U2l6ZSA9IDMwO1xyXG5cclxuLyoqXHJcbiAqIENhbGN1bGF0ZXMgbW92aW5nIGF2ZXJhZ2UgaW5kaWNhdG9yIGJhc2VkIG9uIHRoZSBkYXRhIGZyb20gdGhlIGBzdWNjZXNzUmF0ZXNgXHJcbiAqIGFycmF5LlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gX2NhbGN1bGF0ZU1vdmluZ0F2ZXJhZ2VcclxuICpcclxuICogQHJldHVybnMge251bWJlcn0gQSBtb3ZpbmcgYXZlcmFnZSBmb3Igc3VjY2VzcyByYXRpbyBvZiB0aGUgc2VydmVyIGV4cG9ydHMuXHJcbiAqL1xyXG5mdW5jdGlvbiBfY2FsY3VsYXRlTW92aW5nQXZlcmFnZSgpIHtcclxuICByZXR1cm4gc3VjY2Vzc1JhdGVzLnJlZHVjZSgoYSwgYikgPT4gYSArIGIsIDApIC8gc3VjY2Vzc1JhdGVzLmxlbmd0aDtcclxufVxyXG5cclxuLyoqXHJcbiAqIFN0YXJ0cyB0aGUgaW50ZXJ2YWwgcmVzcG9uc2libGUgZm9yIGNhbGN1bGF0aW5nIGN1cnJlbnQgc3VjY2VzcyByYXRlIHJhdGlvXHJcbiAqIGFuZCBjb2xsZWN0cyByZWNvcmRzIHRvIHRoZSBgc3VjY2Vzc1JhdGVzYCBhcnJheS5cclxuICpcclxuICogQGZ1bmN0aW9uIF9zdGFydFN1Y2Nlc3NSYXRlXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtOb2RlSlMuVGltZW91dH0gSWQgb2YgYW4gaW50ZXJ2YWwuXHJcbiAqL1xyXG5mdW5jdGlvbiBfc3RhcnRTdWNjZXNzUmF0ZSgpIHtcclxuICByZXR1cm4gc2V0SW50ZXJ2YWwoKCkgPT4ge1xyXG4gICAgY29uc3Qgc3RhdHMgPSBnZXRQb29sU3RhdHMoKTtcclxuICAgIGNvbnN0IHN1Y2Nlc3NSYXRpbyA9XHJcbiAgICAgIHN0YXRzLmV4cG9ydHNBdHRlbXB0ZWQgPT09IDBcclxuICAgICAgICA/IDFcclxuICAgICAgICA6IChzdGF0cy5leHBvcnRzUGVyZm9ybWVkIC8gc3RhdHMuZXhwb3J0c0F0dGVtcHRlZCkgKiAxMDA7XHJcblxyXG4gICAgc3VjY2Vzc1JhdGVzLnB1c2goc3VjY2Vzc1JhdGlvKTtcclxuICAgIGlmIChzdWNjZXNzUmF0ZXMubGVuZ3RoID4gd2luZG93U2l6ZSkge1xyXG4gICAgICBzdWNjZXNzUmF0ZXMuc2hpZnQoKTtcclxuICAgIH1cclxuICB9LCByZWNvcmRJbnRlcnZhbCk7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBBZGRzIHRoZSBgaGVhbHRoYCByb3V0ZXMuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBoZWFsdGhSb3V0ZXNcclxuICpcclxuICogQHBhcmFtIHtFeHByZXNzfSBhcHAgLSBUaGUgRXhwcmVzcyBhcHAgaW5zdGFuY2UuXHJcbiAqL1xyXG5leHBvcnQgZGVmYXVsdCBmdW5jdGlvbiBoZWFsdGhSb3V0ZXMoYXBwKSB7XHJcbiAgLy8gU3RhcnQgcHJvY2Vzc2luZyBzdWNjZXNzIHJhdGUgcmF0aW8gaW50ZXJ2YWwgYW5kIHNhdmUgaXRzIGlkIHRvIHRoZSBhcnJheVxyXG4gIC8vIGZvciB0aGUgZ3JhY2VmdWwgY2xlYXJpbmcgb24gc2h1dGRvd24gd2l0aCBpbmplY3RlZCBgYWRkVGltZXJgIGZ1bnRpb25cclxuICBhZGRUaW1lcihfc3RhcnRTdWNjZXNzUmF0ZSgpKTtcclxuXHJcbiAgLyoqXHJcbiAgICogQWRkcyB0aGUgR0VUICcvaGVhbHRoJyAtIEEgcm91dGUgZm9yIGdldHRpbmcgdGhlIGJhc2ljIHN0YXRzIG9mIHRoZSBzZXJ2ZXIuXHJcbiAgICovXHJcbiAgYXBwLmdldCgnL2hlYWx0aCcsIChyZXF1ZXN0LCByZXNwb25zZSwgbmV4dCkgPT4ge1xyXG4gICAgdHJ5IHtcclxuICAgICAgbG9nKDQsICdbaGVhbHRoXSBSZXR1cm5pbmcgc2VydmVyIGhlYWx0aC4nKTtcclxuXHJcbiAgICAgIGNvbnN0IHN0YXRzID0gZ2V0UG9vbFN0YXRzKCk7XHJcbiAgICAgIGNvbnN0IHBlcmlvZCA9IHN1Y2Nlc3NSYXRlcy5sZW5ndGg7XHJcbiAgICAgIGNvbnN0IG1vdmluZ0F2ZXJhZ2UgPSBfY2FsY3VsYXRlTW92aW5nQXZlcmFnZSgpO1xyXG5cclxuICAgICAgLy8gU2VuZCB0aGUgc2VydmVyJ3Mgc3RhdGlzdGljc1xyXG4gICAgICByZXNwb25zZS5zZW5kKHtcclxuICAgICAgICAvLyBTdGF0dXMgYW5kIHRpbWVzXHJcbiAgICAgICAgc3RhdHVzOiAnT0snLFxyXG4gICAgICAgIGJvb3RUaW1lOiBzZXJ2ZXJTdGFydFRpbWUsXHJcbiAgICAgICAgdXB0aW1lOiBgJHtNYXRoLmZsb29yKChnZXROZXdEYXRlVGltZSgpIC0gc2VydmVyU3RhcnRUaW1lLmdldFRpbWUoKSkgLyAxMDAwIC8gNjApfSBtaW51dGVzYCxcclxuXHJcbiAgICAgICAgLy8gVmVyc2lvbnNcclxuICAgICAgICBzZXJ2ZXJWZXJzaW9uOiBwYWNrYWdlRmlsZS52ZXJzaW9uLFxyXG4gICAgICAgIGhpZ2hjaGFydHNWZXJzaW9uOiBnZXRIaWdoY2hhcnRzVmVyc2lvbigpLFxyXG5cclxuICAgICAgICAvLyBFeHBvcnRzXHJcbiAgICAgICAgYXZlcmFnZUV4cG9ydFRpbWU6IHN0YXRzLnRpbWVTcGVudEF2ZXJhZ2UsXHJcbiAgICAgICAgYXR0ZW1wdGVkRXhwb3J0czogc3RhdHMuZXhwb3J0c0F0dGVtcHRlZCxcclxuICAgICAgICBwZXJmb3JtZWRFeHBvcnRzOiBzdGF0cy5leHBvcnRzUGVyZm9ybWVkLFxyXG4gICAgICAgIGZhaWxlZEV4cG9ydHM6IHN0YXRzLmV4cG9ydHNEcm9wcGVkLFxyXG4gICAgICAgIHN1Y2Vzc1JhdGlvOiAoc3RhdHMuZXhwb3J0c1BlcmZvcm1lZCAvIHN0YXRzLmV4cG9ydHNBdHRlbXB0ZWQpICogMTAwLFxyXG5cclxuICAgICAgICAvLyBQb29sXHJcbiAgICAgICAgcG9vbDogZ2V0UG9vbEluZm9KU09OKCksXHJcblxyXG4gICAgICAgIC8vIE1vdmluZyBhdmVyYWdlXHJcbiAgICAgICAgcGVyaW9kLFxyXG4gICAgICAgIG1vdmluZ0F2ZXJhZ2UsXHJcbiAgICAgICAgbWVzc2FnZTpcclxuICAgICAgICAgIGlzTmFOKG1vdmluZ0F2ZXJhZ2UpIHx8ICFzdWNjZXNzUmF0ZXMubGVuZ3RoXHJcbiAgICAgICAgICAgID8gJ1RvbyBlYXJseSB0byByZXBvcnQuIE5vIGV4cG9ydHMgbWFkZSB5ZXQuIFBsZWFzZSBjaGVjayBiYWNrIHNvb24uJ1xyXG4gICAgICAgICAgICA6IGBMYXN0ICR7cGVyaW9kfSBtaW51dGVzIGhhZCBhIHN1Y2Nlc3MgcmF0ZSBvZiAke21vdmluZ0F2ZXJhZ2UudG9GaXhlZCgyKX0lLmAsXHJcblxyXG4gICAgICAgIC8vIFNWRyBhbmQgSlNPTiBleHBvcnRzXHJcbiAgICAgICAgc3ZnRXhwb3J0czogc3RhdHMuZXhwb3J0c0Zyb21TdmcsXHJcbiAgICAgICAganNvbkV4cG9ydHM6IHN0YXRzLmV4cG9ydHNGcm9tT3B0aW9ucyxcclxuICAgICAgICBzdmdFeHBvcnRzQXR0ZW1wdHM6IHN0YXRzLmV4cG9ydHNGcm9tU3ZnQXR0ZW1wdHMsXHJcbiAgICAgICAganNvbkV4cG9ydHNBdHRlbXB0czogc3RhdHMuZXhwb3J0c0Zyb21PcHRpb25zQXR0ZW1wdHNcclxuICAgICAgfSk7XHJcbiAgICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgICByZXR1cm4gbmV4dChlcnJvcik7XHJcbiAgICB9XHJcbiAgfSk7XHJcbn1cclxuIiwiLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcclxuXHJcbkhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlclxyXG5cclxuQ29weXJpZ2h0IChjKSAyMDE2LTIwMjUsIEhpZ2hzb2Z0XHJcblxyXG5MaWNlbmNlZCB1bmRlciB0aGUgTUlUIGxpY2VuY2UuXHJcblxyXG5BZGRpdGlvbmFsbHkgYSB2YWxpZCBIaWdoY2hhcnRzIGxpY2Vuc2UgaXMgcmVxdWlyZWQgZm9yIHVzZS5cclxuXHJcblNlZSBMSUNFTlNFIGZpbGUgaW4gcm9vdCBmb3IgZGV0YWlscy5cclxuXHJcbioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXHJcblxyXG4vKipcclxuICogQG92ZXJ2aWV3IERlZmluZXMgYW4gRXhwcmVzcyByb3V0ZSBmb3Igc2VydmluZyB0aGUgVUkgZm9yIHRoZSBleHBvcnQgc2VydmVyXHJcbiAqIHdoZW4gZW5hYmxlZC5cclxuICovXHJcblxyXG5pbXBvcnQgeyBqb2luIH0gZnJvbSAncGF0aCc7XHJcblxyXG5pbXBvcnQgeyBnZXRPcHRpb25zIH0gZnJvbSAnLi4vLi4vY29uZmlnLmpzJztcclxuaW1wb3J0IHsgbG9nIH0gZnJvbSAnLi4vLi4vbG9nZ2VyLmpzJztcclxuaW1wb3J0IHsgX19kaXJuYW1lIH0gZnJvbSAnLi4vLi4vdXRpbHMuanMnO1xyXG5cclxuLyoqXHJcbiAqIEFkZHMgdGhlIGB1aWAgcm91dGVzLlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gdWlSb3V0ZXNcclxuICpcclxuICogQHBhcmFtIHtFeHByZXNzfSBhcHAgLSBUaGUgRXhwcmVzcyBhcHAgaW5zdGFuY2UuXHJcbiAqL1xyXG5leHBvcnQgZGVmYXVsdCBmdW5jdGlvbiB1aVJvdXRlcyhhcHApIHtcclxuICAvKipcclxuICAgKiBBZGRzIHRoZSBHRVQgJy8nIC0gQSByb3V0ZSBmb3IgYSBVSSB3aGVuIGVuYWJsZWQgb24gdGhlIGV4cG9ydCBzZXJ2ZXIuXHJcbiAgICovXHJcbiAgYXBwLmdldChnZXRPcHRpb25zKCkudWkucm91dGUgfHwgJy8nLCAocmVxdWVzdCwgcmVzcG9uc2UsIG5leHQpID0+IHtcclxuICAgIHRyeSB7XHJcbiAgICAgIGxvZyg0LCAnW3VpXSBSZXR1cm5pbmcgVUkgZm9yIHRoZSBleHBvcnQuJyk7XHJcblxyXG4gICAgICByZXNwb25zZS5zZW5kRmlsZShqb2luKF9fZGlybmFtZSwgJ3B1YmxpYycsICdpbmRleC5odG1sJyksIHtcclxuICAgICAgICBhY2NlcHRSYW5nZXM6IGZhbHNlXHJcbiAgICAgIH0pO1xyXG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICAgcmV0dXJuIG5leHQoZXJyb3IpO1xyXG4gICAgfVxyXG4gIH0pO1xyXG59XHJcbiIsIi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXHJcblxyXG5IaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXJcclxuXHJcbkNvcHlyaWdodCAoYykgMjAxNi0yMDI1LCBIaWdoc29mdFxyXG5cclxuTGljZW5jZWQgdW5kZXIgdGhlIE1JVCBsaWNlbmNlLlxyXG5cclxuQWRkaXRpb25hbGx5IGEgdmFsaWQgSGlnaGNoYXJ0cyBsaWNlbnNlIGlzIHJlcXVpcmVkIGZvciB1c2UuXHJcblxyXG5TZWUgTElDRU5TRSBmaWxlIGluIHJvb3QgZm9yIGRldGFpbHMuXHJcblxyXG4qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xyXG5cclxuLyoqXHJcbiAqIEBvdmVydmlldyBEZWZpbmVzIGFuIEV4cHJlc3Mgcm91dGUgZm9yIHVwZGF0aW5nIHRoZSBIaWdoY2hhcnRzIHZlcnNpb25cclxuICogb24gdGhlIHNlcnZlciwgd2l0aCBhdXRoZW50aWNhdGlvbiBhbmQgdmFsaWRhdGlvbi5cclxuICovXHJcblxyXG5pbXBvcnQgeyBnZXRIaWdoY2hhcnRzVmVyc2lvbiwgdXBkYXRlSGlnaGNoYXJ0c1ZlcnNpb24gfSBmcm9tICcuLi8uLi9jYWNoZS5qcyc7XHJcbmltcG9ydCB7IHZhbGlkYXRlT3B0aW9uIH0gZnJvbSAnLi4vLi4vY29uZmlnLmpzJztcclxuaW1wb3J0IHsgbG9nIH0gZnJvbSAnLi4vLi4vbG9nZ2VyLmpzJztcclxuaW1wb3J0IHsgZW52cyB9IGZyb20gJy4uLy4uL3ZhbGlkYXRpb24uanMnO1xyXG5cclxuaW1wb3J0IEV4cG9ydEVycm9yIGZyb20gJy4uLy4uL2Vycm9ycy9FeHBvcnRFcnJvci5qcyc7XHJcblxyXG4vKipcclxuICogQWRkcyB0aGUgYHZlcnNpb25fY2hhbmdlYCByb3V0ZXMuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiB2ZXJzaW9uQ2hhbmdlUm91dGVzXHJcbiAqXHJcbiAqIEBwYXJhbSB7RXhwcmVzc30gYXBwIC0gVGhlIEV4cHJlc3MgYXBwIGluc3RhbmNlLlxyXG4gKi9cclxuZXhwb3J0IGRlZmF1bHQgZnVuY3Rpb24gdmVyc2lvbkNoYW5nZVJvdXRlcyhhcHApIHtcclxuICAvKipcclxuICAgKiBBZGRzIHRoZSBQT1NUICcvdmVyc2lvbl9jaGFuZ2UvOm5ld1ZlcnNpb24nIC0gQSByb3V0ZSBmb3IgY2hhbmdpbmdcclxuICAgKiB0aGUgSGlnaGNoYXJ0cyB2ZXJzaW9uIG9uIHRoZSBzZXJ2ZXIuXHJcbiAgICovXHJcbiAgYXBwLnBvc3QoJy92ZXJzaW9uX2NoYW5nZS86bmV3VmVyc2lvbicsIGFzeW5jIChyZXF1ZXN0LCByZXNwb25zZSwgbmV4dCkgPT4ge1xyXG4gICAgdHJ5IHtcclxuICAgICAgbG9nKDQsICdbdmVyc2lvbl0gQ2hhbmdpbmcgSGlnaGNoYXJ0cyB2ZXJzaW9uLicpO1xyXG5cclxuICAgICAgLy8gR2V0IHRoZSB0b2tlbiBkaXJlY3RseSBmcm9tIGVudnNcclxuICAgICAgY29uc3QgYWRtaW5Ub2tlbiA9IGVudnMuSElHSENIQVJUU19BRE1JTl9UT0tFTjtcclxuXHJcbiAgICAgIC8vIENoZWNrIHRoZSBleGlzdGVuY2Ugb2YgdGhlIHRva2VuXHJcbiAgICAgIGlmICghYWRtaW5Ub2tlbiB8fCAhYWRtaW5Ub2tlbi5sZW5ndGgpIHtcclxuICAgICAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoXHJcbiAgICAgICAgICAnW3ZlcnNpb25dIFRoZSBzZXJ2ZXIgaXMgbm90IGNvbmZpZ3VyZWQgdG8gcGVyZm9ybSBydW4tdGltZSB2ZXJzaW9uIGNoYW5nZXM6IEhJR0hDSEFSVFNfQURNSU5fVE9LRU4gaXMgbm90IHNldC4nLFxyXG4gICAgICAgICAgNDAxXHJcbiAgICAgICAgKTtcclxuICAgICAgfVxyXG5cclxuICAgICAgLy8gR2V0IHRoZSB0b2tlbiBmcm9tIHRoZSBoYy1hdXRoIGhlYWRlclxyXG4gICAgICBjb25zdCB0b2tlbiA9IHJlcXVlc3QuZ2V0KCdoYy1hdXRoJyk7XHJcblxyXG4gICAgICAvLyBDaGVjayBpZiB0aGUgaGMtYXV0aCBoZWFkZXIgY29udGFpbiBhIGNvcnJlY3QgdG9rZW5cclxuICAgICAgaWYgKCF0b2tlbiB8fCB0b2tlbiAhPT0gYWRtaW5Ub2tlbikge1xyXG4gICAgICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcihcclxuICAgICAgICAgICdbdmVyc2lvbl0gSW52YWxpZCBvciBtaXNzaW5nIHRva2VuOiBTZXQgdGhlIHRva2VuIGluIHRoZSBoYy1hdXRoIGhlYWRlci4nLFxyXG4gICAgICAgICAgNDAxXHJcbiAgICAgICAgKTtcclxuICAgICAgfVxyXG5cclxuICAgICAgLy8gQ29tcGFyZSB2ZXJzaW9uc1xyXG4gICAgICBsZXQgbmV3VmVyc2lvbiA9IHJlcXVlc3QucGFyYW1zLm5ld1ZlcnNpb247XHJcblxyXG4gICAgICAvLyBWYWxpZGF0ZSB0aGUgdmVyc2lvblxyXG4gICAgICB0cnkge1xyXG4gICAgICAgIG5ld1ZlcnNpb24gPSB2YWxpZGF0ZU9wdGlvbigndmVyc2lvbicsIHJlcXVlc3QucGFyYW1zLm5ld1ZlcnNpb24pO1xyXG4gICAgICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcihcclxuICAgICAgICAgIGBbdmVyc2lvbl0gVmVyc2lvbiBpcyBpbmNvcnJlY3Q6ICR7ZXJyb3IubWVzc2FnZX1gLFxyXG4gICAgICAgICAgNDAwXHJcbiAgICAgICAgKS5zZXRFcnJvcihlcnJvcik7XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIC8vIFdoZW4gYSBjb3JyZWN0IHZhbHVlIGZvdW5kXHJcbiAgICAgIGlmIChuZXdWZXJzaW9uKSB7XHJcbiAgICAgICAgdHJ5IHtcclxuICAgICAgICAgIC8vIFVwZGF0ZSB2ZXJzaW9uXHJcbiAgICAgICAgICBhd2FpdCB1cGRhdGVIaWdoY2hhcnRzVmVyc2lvbihuZXdWZXJzaW9uKTtcclxuICAgICAgICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgICAgICAgdGhyb3cgbmV3IEV4cG9ydEVycm9yKFxyXG4gICAgICAgICAgICBgW3ZlcnNpb25dIFZlcnNpb24gY2hhbmdlOiAke2Vycm9yLm1lc3NhZ2V9YCxcclxuICAgICAgICAgICAgNDAwXHJcbiAgICAgICAgICApLnNldEVycm9yKGVycm9yKTtcclxuICAgICAgICB9XHJcblxyXG4gICAgICAgIC8vIFN1Y2Nlc3NcclxuICAgICAgICByZXNwb25zZS5zdGF0dXMoMjAwKS5zZW5kKHtcclxuICAgICAgICAgIHN0YXR1c0NvZGU6IDIwMCxcclxuICAgICAgICAgIGhpZ2hjaGFydHNWZXJzaW9uOiBnZXRIaWdoY2hhcnRzVmVyc2lvbigpLFxyXG4gICAgICAgICAgbWVzc2FnZTogYFN1Y2Nlc3NmdWxseSB1cGRhdGVkIEhpZ2hjaGFydHMgdG8gdmVyc2lvbjogJHtuZXdWZXJzaW9ufS5gXHJcbiAgICAgICAgfSk7XHJcbiAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgLy8gTm8gdmVyc2lvbiBzcGVjaWZpZWRcclxuICAgICAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoJ1t2ZXJzaW9uXSBObyBuZXcgdmVyc2lvbiBzdXBwbGllZC4nLCA0MDApO1xyXG4gICAgICB9XHJcbiAgICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgICByZXR1cm4gbmV4dChlcnJvcik7XHJcbiAgICB9XHJcbiAgfSk7XHJcbn1cclxuIiwiLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcclxuXHJcbkhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlclxyXG5cclxuQ29weXJpZ2h0IChjKSAyMDE2LTIwMjUsIEhpZ2hzb2Z0XHJcblxyXG5MaWNlbmNlZCB1bmRlciB0aGUgTUlUIGxpY2VuY2UuXHJcblxyXG5BZGRpdGlvbmFsbHkgYSB2YWxpZCBIaWdoY2hhcnRzIGxpY2Vuc2UgaXMgcmVxdWlyZWQgZm9yIHVzZS5cclxuXHJcblNlZSBMSUNFTlNFIGZpbGUgaW4gcm9vdCBmb3IgZGV0YWlscy5cclxuXHJcbioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXHJcblxyXG4vKipcclxuICogQG92ZXJ2aWV3IEEgbW9kdWxlIHRoYXQgc2V0cyB1cCBhbmQgbWFuYWdlcyBIVFRQIGFuZCBIVFRQUyBzZXJ2ZXJzXHJcbiAqIGZvciB0aGUgSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyLiBJdCBoYW5kbGVzIHNlcnZlciBpbml0aWFsaXphdGlvbixcclxuICogY29uZmlndXJhdGlvbiwgZXJyb3IgaGFuZGxpbmcsIG1pZGRsZXdhcmUgc2V0dXAsIHJvdXRlIGRlZmluaXRpb24sIGFuZCByYXRlXHJcbiAqIGxpbWl0aW5nLiBUaGUgbW9kdWxlIGV4cG9ydHMgZnVuY3Rpb25zIHRvIHN0YXJ0LCBzdG9wLCBhbmQgbWFuYWdlIHNlcnZlclxyXG4gKiBpbnN0YW5jZXMsIGFzIHdlbGwgYXMgdXRpbGl0eSBmdW5jdGlvbnMgZm9yIGRlZmluaW5nIHJvdXRlcyBhbmQgYXR0YWNoaW5nXHJcbiAqIG1pZGRsZXdhcmVzLlxyXG4gKi9cclxuXHJcbmltcG9ydCB7IHJlYWRGaWxlIH0gZnJvbSAnZnMvcHJvbWlzZXMnO1xyXG5pbXBvcnQgeyBqb2luIH0gZnJvbSAncGF0aCc7XHJcblxyXG5pbXBvcnQgY29ycyBmcm9tICdjb3JzJztcclxuaW1wb3J0IGV4cHJlc3MgZnJvbSAnZXhwcmVzcyc7XHJcbmltcG9ydCBodHRwIGZyb20gJ2h0dHAnO1xyXG5pbXBvcnQgaHR0cHMgZnJvbSAnaHR0cHMnO1xyXG5pbXBvcnQgbXVsdGVyIGZyb20gJ211bHRlcic7XHJcblxyXG5pbXBvcnQgeyB1cGRhdGVPcHRpb25zLCB2YWxpZGF0ZU9wdGlvbnMgfSBmcm9tICcuLi9jb25maWcuanMnO1xyXG5pbXBvcnQgeyBsb2csIGxvZ1dpdGhTdGFjayB9IGZyb20gJy4uL2xvZ2dlci5qcyc7XHJcbmltcG9ydCB7IF9fZGlybmFtZSwgZ2V0QWJzb2x1dGVQYXRoIH0gZnJvbSAnLi4vdXRpbHMuanMnO1xyXG5cclxuaW1wb3J0IGVycm9yTWlkZGxld2FyZSBmcm9tICcuL21pZGRsZXdhcmVzL2Vycm9yLmpzJztcclxuaW1wb3J0IHJhdGVMaW1pdGluZ01pZGRsZXdhcmUgZnJvbSAnLi9taWRkbGV3YXJlcy9yYXRlTGltaXRpbmcuanMnO1xyXG5pbXBvcnQgdmFsaWRhdGlvbk1pZGRsZXdhcmUgZnJvbSAnLi9taWRkbGV3YXJlcy92YWxpZGF0aW9uLmpzJztcclxuXHJcbmltcG9ydCBleHBvcnRSb3V0ZXMgZnJvbSAnLi9yb3V0ZXMvZXhwb3J0LmpzJztcclxuaW1wb3J0IGhlYWx0aFJvdXRlcyBmcm9tICcuL3JvdXRlcy9oZWFsdGguanMnO1xyXG5pbXBvcnQgdWlSb3V0ZXMgZnJvbSAnLi9yb3V0ZXMvdWkuanMnO1xyXG5pbXBvcnQgdmVyc2lvbkNoYW5nZVJvdXRlcyBmcm9tICcuL3JvdXRlcy92ZXJzaW9uQ2hhbmdlLmpzJztcclxuXHJcbmltcG9ydCBFeHBvcnRFcnJvciBmcm9tICcuLi9lcnJvcnMvRXhwb3J0RXJyb3IuanMnO1xyXG5cclxuLy8gQXJyYXkgb2YgYW4gYWN0aXZlIHNlcnZlcnNcclxuY29uc3QgYWN0aXZlU2VydmVycyA9IG5ldyBNYXAoKTtcclxuXHJcbi8vIENyZWF0ZSBleHByZXNzIGFwcFxyXG5jb25zdCBhcHAgPSBleHByZXNzKCk7XHJcblxyXG4vKipcclxuICogU3RhcnRzIGFuIEhUVFAgYW5kL29yIEhUVFBTIHNlcnZlciBiYXNlZCBvbiB0aGUgcHJvdmlkZWQgY29uZmlndXJhdGlvbi5cclxuICogVGhlIGBzZXJ2ZXJPcHRpb25zYCBvYmplY3QgY29udGFpbnMgc2VydmVyLXJlbGF0ZWQgcHJvcGVydGllcyAocmVmZXJcclxuICogdG8gdGhlIGBzZXJ2ZXJgIHNlY3Rpb24gaW4gdGhlIGBsaWIvc2NoZW1hcy9jb25maWcuanNgIGZpbGUgZm9yIGRldGFpbHMpLlxyXG4gKlxyXG4gKiBAYXN5bmNcclxuICogQGZ1bmN0aW9uIHN0YXJ0U2VydmVyXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBzZXJ2ZXJPcHRpb25zIC0gVGhlIGNvbmZpZ3VyYXRpb24gb2JqZWN0IGNvbnRhaW5pbmcgYHNlcnZlcmBcclxuICogb3B0aW9ucy4gVGhpcyBvYmplY3QgbWF5IGluY2x1ZGUgYSBwYXJ0aWFsIG9yIGNvbXBsZXRlIHNldCBvZiB0aGUgYHNlcnZlcmBcclxuICogb3B0aW9ucy4gSWYgdGhlIG9wdGlvbnMgYXJlIHBhcnRpYWwsIG1pc3NpbmcgdmFsdWVzIHdpbGwgZGVmYXVsdFxyXG4gKiB0byB0aGUgY3VycmVudCBnbG9iYWwgY29uZmlndXJhdGlvbi5cclxuICpcclxuICogQHJldHVybnMge1Byb21pc2U8dm9pZD59IEEgUHJvbWlzZSB0aGF0IHJlc29sdmVzIHdoZW4gdGhlIHNlcnZlciBpcyBlaXRoZXJcclxuICogbm90IGVuYWJsZWQgb3Igbm8gdmFsaWQgRXhwcmVzcyBhcHAgaXMgZm91bmQsIHNpZ25hbGluZyB0aGUgZW5kIG9mIHRoZVxyXG4gKiBmdW5jdGlvbidzIGV4ZWN1dGlvbi5cclxuICpcclxuICogQHRocm93cyB7RXhwb3J0RXJyb3J9IFRocm93cyBhbiBgRXhwb3J0RXJyb3JgIGlmIHRoZSBzZXJ2ZXIgY2Fubm90XHJcbiAqIGJlIGNvbmZpZ3VyZWQgYW5kIHN0YXJ0ZWQuXHJcbiAqL1xyXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gc3RhcnRTZXJ2ZXIoc2VydmVyT3B0aW9ucykge1xyXG4gIHRyeSB7XHJcbiAgICAvLyBVcGRhdGUgdGhlIGluc3RhbmNlIG9wdGlvbnMgb2JqZWN0XHJcbiAgICBjb25zdCBvcHRpb25zID0gdXBkYXRlT3B0aW9ucyhcclxuICAgICAgdmFsaWRhdGVPcHRpb25zKHtcclxuICAgICAgICBzZXJ2ZXI6IHNlcnZlck9wdGlvbnNcclxuICAgICAgfSlcclxuICAgICk7XHJcblxyXG4gICAgLy8gVXNlIHZhbGlkYXRlZCBvcHRpb25zXHJcbiAgICBzZXJ2ZXJPcHRpb25zID0gb3B0aW9ucy5zZXJ2ZXI7XHJcblxyXG4gICAgLy8gU3RvcCBpZiBub3QgZW5hYmxlZFxyXG4gICAgaWYgKCFzZXJ2ZXJPcHRpb25zLmVuYWJsZSB8fCAhYXBwKSB7XHJcbiAgICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcihcclxuICAgICAgICAnW3NlcnZlcl0gU2VydmVyIGNhbm5vdCBiZSBzdGFydGVkIChub3QgZW5hYmxlZCBvciBubyBjb3JyZWN0IEV4cHJlc3MgYXBwIGZvdW5kKS4nLFxyXG4gICAgICAgIDUwMFxyXG4gICAgICApO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIFRvbyBiaWcgbGltaXRzIGxlYWQgdG8gdGltZW91dHMgaW4gdGhlIGV4cG9ydCBwcm9jZXNzIHdoZW5cclxuICAgIC8vIHRoZSByYXN0ZXJpemF0aW9uIHRpbWVvdXQgaXMgc2V0IHRvbyBsb3dcclxuICAgIGNvbnN0IHVwbG9hZExpbWl0Qnl0ZXMgPSBzZXJ2ZXJPcHRpb25zLnVwbG9hZExpbWl0ICogMTAyNCAqIDEwMjQ7XHJcblxyXG4gICAgLy8gTWVtb3J5IHN0b3JhZ2UgZm9yIG11bHRlciBwYWNrYWdlXHJcbiAgICBjb25zdCBzdG9yYWdlID0gbXVsdGVyLm1lbW9yeVN0b3JhZ2UoKTtcclxuXHJcbiAgICAvLyBFbmFibGUgcGFyc2luZyBvZiBmb3JtIGRhdGEgKGZpbGVzKSB3aXRoIG11bHRlciBwYWNrYWdlXHJcbiAgICBjb25zdCB1cGxvYWQgPSBtdWx0ZXIoe1xyXG4gICAgICBzdG9yYWdlLFxyXG4gICAgICBsaW1pdHM6IHtcclxuICAgICAgICBmaWVsZFNpemU6IHVwbG9hZExpbWl0Qnl0ZXNcclxuICAgICAgfVxyXG4gICAgfSk7XHJcblxyXG4gICAgLy8gRGlzYWJsZSB0aGUgWC1Qb3dlcmVkLUJ5IGhlYWRlclxyXG4gICAgYXBwLmRpc2FibGUoJ3gtcG93ZXJlZC1ieScpO1xyXG5cclxuICAgIC8vIEVuYWJsZSBDT1JTIHN1cHBvcnRcclxuICAgIGFwcC51c2UoXHJcbiAgICAgIGNvcnMoe1xyXG4gICAgICAgIG1ldGhvZHM6IFsnUE9TVCcsICdHRVQnLCAnT1BUSU9OUyddXHJcbiAgICAgIH0pXHJcbiAgICApO1xyXG5cclxuICAgIC8vIEdldHRpbmcgYSBsb3Qgb2YgYFJhbmdlTm90U2F0aXNmaWFibGVFcnJvcmAgZXhjZXB0aW9ucyAoZXZlbiB0aG91Z2ggdGhpc1xyXG4gICAgLy8gaXMgYSBkZXByZWNhdGVkIG9wdGlvbnMsIGxldCdzIHRyeSB0byBzZXQgaXQgdG8gZmFsc2UpXHJcbiAgICBhcHAudXNlKChyZXF1ZXN0LCByZXNwb25zZSwgbmV4dCkgPT4ge1xyXG4gICAgICByZXNwb25zZS5zZXQoJ0FjY2VwdC1SYW5nZXMnLCAnbm9uZScpO1xyXG4gICAgICBuZXh0KCk7XHJcbiAgICB9KTtcclxuXHJcbiAgICAvLyBFbmFibGUgYm9keSBwYXJzZXIgZm9yIEpTT04gZGF0YVxyXG4gICAgYXBwLnVzZShcclxuICAgICAgZXhwcmVzcy5qc29uKHtcclxuICAgICAgICBsaW1pdDogdXBsb2FkTGltaXRCeXRlc1xyXG4gICAgICB9KVxyXG4gICAgKTtcclxuXHJcbiAgICAvLyBFbmFibGUgYm9keSBwYXJzZXIgZm9yIFVSTC1lbmNvZGVkIGZvcm0gZGF0YVxyXG4gICAgYXBwLnVzZShcclxuICAgICAgZXhwcmVzcy51cmxlbmNvZGVkKHtcclxuICAgICAgICBleHRlbmRlZDogdHJ1ZSxcclxuICAgICAgICBsaW1pdDogdXBsb2FkTGltaXRCeXRlc1xyXG4gICAgICB9KVxyXG4gICAgKTtcclxuXHJcbiAgICAvLyBVc2Ugb25seSBub24tZmlsZSBtdWx0aXBhcnQgZm9ybSBmaWVsZHNcclxuICAgIGFwcC51c2UodXBsb2FkLm5vbmUoKSk7XHJcblxyXG4gICAgLy8gU2V0IHVwIHN0YXRpYyBmb2xkZXIncyByb3V0ZVxyXG4gICAgYXBwLnVzZShleHByZXNzLnN0YXRpYyhqb2luKF9fZGlybmFtZSwgJ3B1YmxpYycpKSk7XHJcblxyXG4gICAgLy8gTGlzdGVuIEhUVFAgc2VydmVyXHJcbiAgICBpZiAoIXNlcnZlck9wdGlvbnMuc3NsLmZvcmNlKSB7XHJcbiAgICAgIC8vIE1haW4gc2VydmVyIGluc3RhbmNlIChIVFRQKVxyXG4gICAgICBjb25zdCBodHRwU2VydmVyID0gaHR0cC5jcmVhdGVTZXJ2ZXIoYXBwKTtcclxuXHJcbiAgICAgIC8vIEF0dGFjaCBlcnJvciBoYW5kbGVycyBhbmQgbGlzdGVuIHRvIHRoZSBzZXJ2ZXJcclxuICAgICAgX2F0dGFjaFNlcnZlckVycm9ySGFuZGxlcnMoaHR0cFNlcnZlcik7XHJcblxyXG4gICAgICAvLyBMaXN0ZW5cclxuICAgICAgaHR0cFNlcnZlci5saXN0ZW4oc2VydmVyT3B0aW9ucy5wb3J0LCBzZXJ2ZXJPcHRpb25zLmhvc3QsICgpID0+IHtcclxuICAgICAgICAvLyBTYXZlIHRoZSByZWZlcmVuY2UgdG8gSFRUUCBzZXJ2ZXJcclxuICAgICAgICBhY3RpdmVTZXJ2ZXJzLnNldChzZXJ2ZXJPcHRpb25zLnBvcnQsIGh0dHBTZXJ2ZXIpO1xyXG5cclxuICAgICAgICBsb2coXHJcbiAgICAgICAgICAzLFxyXG4gICAgICAgICAgYFtzZXJ2ZXJdIFN0YXJ0ZWQgSFRUUCBzZXJ2ZXIgb24gJHtzZXJ2ZXJPcHRpb25zLmhvc3R9OiR7c2VydmVyT3B0aW9ucy5wb3J0fS5gXHJcbiAgICAgICAgKTtcclxuICAgICAgfSk7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gTGlzdGVuIEhUVFBTIHNlcnZlclxyXG4gICAgaWYgKHNlcnZlck9wdGlvbnMuc3NsLmVuYWJsZSkge1xyXG4gICAgICAvLyBTZXQgdXAgYW4gU1NMIHNlcnZlciBhbHNvXHJcbiAgICAgIGxldCBrZXksIGNlcnQ7XHJcblxyXG4gICAgICB0cnkge1xyXG4gICAgICAgIC8vIEdldCB0aGUgU1NMIGtleVxyXG4gICAgICAgIGtleSA9IGF3YWl0IHJlYWRGaWxlKFxyXG4gICAgICAgICAgam9pbihnZXRBYnNvbHV0ZVBhdGgoc2VydmVyT3B0aW9ucy5zc2wuY2VydFBhdGgpLCAnc2VydmVyLmtleScpLFxyXG4gICAgICAgICAgJ3V0ZjgnXHJcbiAgICAgICAgKTtcclxuXHJcbiAgICAgICAgLy8gR2V0IHRoZSBTU0wgY2VydGlmaWNhdGVcclxuICAgICAgICBjZXJ0ID0gYXdhaXQgcmVhZEZpbGUoXHJcbiAgICAgICAgICBqb2luKGdldEFic29sdXRlUGF0aChzZXJ2ZXJPcHRpb25zLnNzbC5jZXJ0UGF0aCksICdzZXJ2ZXIuY3J0JyksXHJcbiAgICAgICAgICAndXRmOCdcclxuICAgICAgICApO1xyXG4gICAgICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgICAgIGxvZyhcclxuICAgICAgICAgIDIsXHJcbiAgICAgICAgICBgW3NlcnZlcl0gVW5hYmxlIHRvIGxvYWQga2V5L2NlcnRpZmljYXRlIGZyb20gdGhlICcke3NlcnZlck9wdGlvbnMuc3NsLmNlcnRQYXRofScgcGF0aC4gQ291bGQgbm90IHJ1biBzZWN1cmVkIGxheWVyIHNlcnZlci5gXHJcbiAgICAgICAgKTtcclxuICAgICAgfVxyXG5cclxuICAgICAgaWYgKGtleSAmJiBjZXJ0KSB7XHJcbiAgICAgICAgLy8gTWFpbiBzZXJ2ZXIgaW5zdGFuY2UgKEhUVFBTKVxyXG4gICAgICAgIGNvbnN0IGh0dHBzU2VydmVyID0gaHR0cHMuY3JlYXRlU2VydmVyKHsga2V5LCBjZXJ0IH0sIGFwcCk7XHJcblxyXG4gICAgICAgIC8vIEF0dGFjaCBlcnJvciBoYW5kbGVycyBhbmQgbGlzdGVuIHRvIHRoZSBzZXJ2ZXJcclxuICAgICAgICBfYXR0YWNoU2VydmVyRXJyb3JIYW5kbGVycyhodHRwc1NlcnZlcik7XHJcblxyXG4gICAgICAgIC8vIExpc3RlblxyXG4gICAgICAgIGh0dHBzU2VydmVyLmxpc3RlbihzZXJ2ZXJPcHRpb25zLnNzbC5wb3J0LCBzZXJ2ZXJPcHRpb25zLmhvc3QsICgpID0+IHtcclxuICAgICAgICAgIC8vIFNhdmUgdGhlIHJlZmVyZW5jZSB0byBIVFRQUyBzZXJ2ZXJcclxuICAgICAgICAgIGFjdGl2ZVNlcnZlcnMuc2V0KHNlcnZlck9wdGlvbnMuc3NsLnBvcnQsIGh0dHBzU2VydmVyKTtcclxuXHJcbiAgICAgICAgICBsb2coXHJcbiAgICAgICAgICAgIDMsXHJcbiAgICAgICAgICAgIGBbc2VydmVyXSBTdGFydGVkIEhUVFBTIHNlcnZlciBvbiAke3NlcnZlck9wdGlvbnMuaG9zdH06JHtzZXJ2ZXJPcHRpb25zLnNzbC5wb3J0fS5gXHJcbiAgICAgICAgICApO1xyXG4gICAgICAgIH0pO1xyXG4gICAgICB9XHJcbiAgICB9XHJcblxyXG4gICAgLy8gU2V0IHVwIHRoZSByYXRlIGxpbWl0ZXJcclxuICAgIHJhdGVMaW1pdGluZ01pZGRsZXdhcmUoYXBwLCBzZXJ2ZXJPcHRpb25zLnJhdGVMaW1pdGluZyk7XHJcblxyXG4gICAgLy8gU2V0IHVwIHRoZSB2YWxpZGF0aW9uIGhhbmRsZXJcclxuICAgIHZhbGlkYXRpb25NaWRkbGV3YXJlKGFwcCk7XHJcblxyXG4gICAgLy8gU2V0IHVwIHJvdXRlc1xyXG4gICAgZXhwb3J0Um91dGVzKGFwcCk7XHJcbiAgICBoZWFsdGhSb3V0ZXMoYXBwKTtcclxuICAgIHVpUm91dGVzKGFwcCk7XHJcbiAgICB2ZXJzaW9uQ2hhbmdlUm91dGVzKGFwcCk7XHJcblxyXG4gICAgLy8gU2V0IHVwIHRoZSBjZW50cmFsaXplZCBlcnJvciBoYW5kbGVyXHJcbiAgICBlcnJvck1pZGRsZXdhcmUoYXBwKTtcclxuICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgdGhyb3cgbmV3IEV4cG9ydEVycm9yKFxyXG4gICAgICAnW3NlcnZlcl0gQ291bGQgbm90IGNvbmZpZ3VyZSBhbmQgc3RhcnQgdGhlIHNlcnZlci4nLFxyXG4gICAgICA1MDBcclxuICAgICkuc2V0RXJyb3IoZXJyb3IpO1xyXG4gIH1cclxufVxyXG5cclxuLyoqXHJcbiAqIENsb3NlcyBhbGwgc2VydmVycyBhc3NvY2lhdGVkIHdpdGggRXhwcmVzcyBhcHAgaW5zdGFuY2UuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBjbG9zZVNlcnZlcnNcclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiBjbG9zZVNlcnZlcnMoKSB7XHJcbiAgLy8gQ2hlY2sgaWYgdGhlcmUgYXJlIHNlcnZlcnMgd29ya2luZ1xyXG4gIGlmIChhY3RpdmVTZXJ2ZXJzLnNpemUgPiAwKSB7XHJcbiAgICBsb2coNCwgYFtzZXJ2ZXJdIENsb3NpbmcgYWxsIHNlcnZlcnMuYCk7XHJcblxyXG4gICAgLy8gQ2xvc2UgZWFjaCBvbmUgb2Ygc2VydmVyc1xyXG4gICAgZm9yIChjb25zdCBbcG9ydCwgc2VydmVyXSBvZiBhY3RpdmVTZXJ2ZXJzKSB7XHJcbiAgICAgIHNlcnZlci5jbG9zZSgoKSA9PiB7XHJcbiAgICAgICAgYWN0aXZlU2VydmVycy5kZWxldGUocG9ydCk7XHJcbiAgICAgICAgbG9nKDQsIGBbc2VydmVyXSBDbG9zZWQgc2VydmVyIG9uIHBvcnQ6ICR7cG9ydH0uYCk7XHJcbiAgICAgIH0pO1xyXG4gICAgfVxyXG4gIH1cclxufVxyXG5cclxuLyoqXHJcbiAqIEdldCBhbGwgc2VydmVycyBhc3NvY2lhdGVkIHdpdGggRXhwcmVzcyBhcHAgaW5zdGFuY2UuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBnZXRTZXJ2ZXJzXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtBcnJheS48T2JqZWN0Pn0gU2VydmVycyBhc3NvY2lhdGVkIHdpdGggRXhwcmVzcyBhcHAgaW5zdGFuY2UuXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gZ2V0U2VydmVycygpIHtcclxuICByZXR1cm4gYWN0aXZlU2VydmVycztcclxufVxyXG5cclxuLyoqXHJcbiAqIEdldCB0aGUgRXhwcmVzcyBpbnN0YW5jZS5cclxuICpcclxuICogQGZ1bmN0aW9uIGdldEV4cHJlc3NcclxuICpcclxuICogQHJldHVybnMge0V4cHJlc3N9IFRoZSBFeHByZXNzIGluc3RhbmNlLlxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIGdldEV4cHJlc3MoKSB7XHJcbiAgcmV0dXJuIGV4cHJlc3M7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBHZXQgdGhlIEV4cHJlc3MgYXBwIGluc3RhbmNlLlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gZ2V0QXBwXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtFeHByZXNzfSBUaGUgRXhwcmVzcyBhcHAgaW5zdGFuY2UuXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gZ2V0QXBwKCkge1xyXG4gIHJldHVybiBhcHA7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBFbmFibGUgcmF0ZSBsaW1pdGluZyBmb3IgdGhlIHNlcnZlci5cclxuICpcclxuICogQGZ1bmN0aW9uIGVuYWJsZVJhdGVMaW1pdGluZ1xyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gcmF0ZUxpbWl0aW5nT3B0aW9ucyAtIFRoZSBjb25maWd1cmF0aW9uIG9iamVjdCBjb250YWluaW5nXHJcbiAqIGByYXRlTGltaXRpbmdgIG9wdGlvbnMuIFRoaXMgb2JqZWN0IG1heSBpbmNsdWRlIGEgcGFydGlhbCBvciBjb21wbGV0ZSBzZXRcclxuICogb2YgdGhlIGByYXRlTGltaXRpbmdgIG9wdGlvbnMuIElmIHRoZSBvcHRpb25zIGFyZSBwYXJ0aWFsLCBtaXNzaW5nIHZhbHVlc1xyXG4gKiB3aWxsIGRlZmF1bHQgdG8gdGhlIGN1cnJlbnQgZ2xvYmFsIGNvbmZpZ3VyYXRpb24uXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gZW5hYmxlUmF0ZUxpbWl0aW5nKHJhdGVMaW1pdGluZ09wdGlvbnMpIHtcclxuICAvLyBVcGRhdGUgdGhlIGluc3RhbmNlIG9wdGlvbnMgb2JqZWN0XHJcbiAgY29uc3Qgb3B0aW9ucyA9IHVwZGF0ZU9wdGlvbnMoXHJcbiAgICB2YWxpZGF0ZU9wdGlvbnMoe1xyXG4gICAgICBzZXJ2ZXI6IHtcclxuICAgICAgICByYXRlTGltaXRpbmc6IHJhdGVMaW1pdGluZ09wdGlvbnNcclxuICAgICAgfVxyXG4gICAgfSlcclxuICApO1xyXG5cclxuICAvLyBTZXQgdGhlIHJhdGUgbGltaXRpbmcgb3B0aW9uc1xyXG4gIHJhdGVMaW1pdGluZ01pZGRsZXdhcmUoYXBwLCBvcHRpb25zLnNlcnZlci5yYXRlTGltaXRpbmdPcHRpb25zKTtcclxufVxyXG5cclxuLyoqXHJcbiAqIEFwcGx5IG1pZGRsZXdhcmUocykgdG8gYSBzcGVjaWZpYyBwYXRoLlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gdXNlXHJcbiAqXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSBwYXRoIC0gVGhlIHBhdGggdG8gd2hpY2ggdGhlIG1pZGRsZXdhcmUocykgc2hvdWxkIGJlIGFwcGxpZWQuXHJcbiAqIEBwYXJhbSB7Li4uRnVuY3Rpb259IG1pZGRsZXdhcmVzIC0gVGhlIG1pZGRsZXdhcmUgZnVuY3Rpb24ocykgdG8gYmUgYXBwbGllZC5cclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiB1c2UocGF0aCwgLi4ubWlkZGxld2FyZXMpIHtcclxuICBhcHAudXNlKHBhdGgsIC4uLm1pZGRsZXdhcmVzKTtcclxufVxyXG5cclxuLyoqXHJcbiAqIFNldCB1cCBhIHJvdXRlIHdpdGggR0VUIG1ldGhvZCBhbmQgYXBwbHkgbWlkZGxld2FyZShzKS5cclxuICpcclxuICogQGZ1bmN0aW9uIGdldFxyXG4gKlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gcGF0aCAtIFRoZSBwYXRoIHRvIHdoaWNoIHRoZSBtaWRkbGV3YXJlKHMpIHNob3VsZCBiZSBhcHBsaWVkLlxyXG4gKiBAcGFyYW0gey4uLkZ1bmN0aW9ufSBtaWRkbGV3YXJlcyAtIFRoZSBtaWRkbGV3YXJlIGZ1bmN0aW9uKHMpIHRvIGJlIGFwcGxpZWQuXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gZ2V0KHBhdGgsIC4uLm1pZGRsZXdhcmVzKSB7XHJcbiAgYXBwLmdldChwYXRoLCAuLi5taWRkbGV3YXJlcyk7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBTZXQgdXAgYSByb3V0ZSB3aXRoIFBPU1QgbWV0aG9kIGFuZCBhcHBseSBtaWRkbGV3YXJlKHMpLlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gcG9zdFxyXG4gKlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gcGF0aCAtIFRoZSBwYXRoIHRvIHdoaWNoIHRoZSBtaWRkbGV3YXJlKHMpIHNob3VsZCBiZSBhcHBsaWVkLlxyXG4gKiBAcGFyYW0gey4uLkZ1bmN0aW9ufSBtaWRkbGV3YXJlcyAtIFRoZSBtaWRkbGV3YXJlIGZ1bmN0aW9uKHMpIHRvIGJlIGFwcGxpZWQuXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gcG9zdChwYXRoLCAuLi5taWRkbGV3YXJlcykge1xyXG4gIGFwcC5wb3N0KHBhdGgsIC4uLm1pZGRsZXdhcmVzKTtcclxufVxyXG5cclxuLyoqXHJcbiAqIEF0dGFjaCBlcnJvciBoYW5kbGVycyB0byB0aGUgc2VydmVyLlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gX2F0dGFjaFNlcnZlckVycm9ySGFuZGxlcnNcclxuICpcclxuICogQHBhcmFtIHsoaHR0cC5TZXJ2ZXJ8aHR0cHMuU2VydmVyKX0gc2VydmVyIC0gVGhlIEhUVFAvSFRUUFMgc2VydmVyIGluc3RhbmNlLlxyXG4gKi9cclxuZnVuY3Rpb24gX2F0dGFjaFNlcnZlckVycm9ySGFuZGxlcnMoc2VydmVyKSB7XHJcbiAgc2VydmVyLm9uKCdjbGllbnRFcnJvcicsIChlcnJvciwgc29ja2V0KSA9PiB7XHJcbiAgICBsb2dXaXRoU3RhY2soXHJcbiAgICAgIDEsXHJcbiAgICAgIGVycm9yLFxyXG4gICAgICBgW3NlcnZlcl0gQ2xpZW50IGVycm9yOiAke2Vycm9yLm1lc3NhZ2V9LCBkZXN0cm95aW5nIHNvY2tldC5gXHJcbiAgICApO1xyXG4gICAgc29ja2V0LmRlc3Ryb3koKTtcclxuICB9KTtcclxuXHJcbiAgc2VydmVyLm9uKCdlcnJvcicsIChlcnJvcikgPT4ge1xyXG4gICAgbG9nV2l0aFN0YWNrKDEsIGVycm9yLCBgW3NlcnZlcl0gU2VydmVyIGVycm9yOiAke2Vycm9yLm1lc3NhZ2V9YCk7XHJcbiAgfSk7XHJcblxyXG4gIHNlcnZlci5vbignY29ubmVjdGlvbicsIChzb2NrZXQpID0+IHtcclxuICAgIHNvY2tldC5vbignZXJyb3InLCAoZXJyb3IpID0+IHtcclxuICAgICAgbG9nV2l0aFN0YWNrKDEsIGVycm9yLCBgW3NlcnZlcl0gU29ja2V0IGVycm9yOiAke2Vycm9yLm1lc3NhZ2V9YCk7XHJcbiAgICB9KTtcclxuICB9KTtcclxufVxyXG5cclxuZXhwb3J0IGRlZmF1bHQge1xyXG4gIHN0YXJ0U2VydmVyLFxyXG4gIGNsb3NlU2VydmVycyxcclxuICBnZXRTZXJ2ZXJzLFxyXG4gIGdldEV4cHJlc3MsXHJcbiAgZ2V0QXBwLFxyXG4gIGVuYWJsZVJhdGVMaW1pdGluZyxcclxuICB1c2UsXHJcbiAgZ2V0LFxyXG4gIHBvc3RcclxufTtcclxuIiwiLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcclxuXHJcbkhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlclxyXG5cclxuQ29weXJpZ2h0IChjKSAyMDE2LTIwMjUsIEhpZ2hzb2Z0XHJcblxyXG5MaWNlbmNlZCB1bmRlciB0aGUgTUlUIGxpY2VuY2UuXHJcblxyXG5BZGRpdGlvbmFsbHkgYSB2YWxpZCBIaWdoY2hhcnRzIGxpY2Vuc2UgaXMgcmVxdWlyZWQgZm9yIHVzZS5cclxuXHJcblNlZSBMSUNFTlNFIGZpbGUgaW4gcm9vdCBmb3IgZGV0YWlscy5cclxuXHJcbioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXHJcblxyXG4vKipcclxuICogQG92ZXJ2aWV3IEhhbmRsZXMgZ3JhY2VmdWwgc2h1dGRvd24gb2YgdGhlIEhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlciwgZW5zdXJpbmdcclxuICogcHJvcGVyIGNsZWFudXAgb2YgcmVzb3VyY2VzIHN1Y2ggYXMgYnJvd3NlciwgcGFnZXMsIHNlcnZlcnMsIGFuZCB0aW1lcnMuXHJcbiAqL1xyXG5cclxuaW1wb3J0IHsga2lsbFBvb2wgfSBmcm9tICcuL3Bvb2wuanMnO1xyXG5pbXBvcnQgeyBjbGVhckFsbFRpbWVycyB9IGZyb20gJy4vdGltZXIuanMnO1xyXG5cclxuaW1wb3J0IHsgY2xvc2VTZXJ2ZXJzIH0gZnJvbSAnLi9zZXJ2ZXIvc2VydmVyLmpzJztcclxuXHJcbi8qKlxyXG4gKiBQZXJmb3JtcyBjbGVhbnVwIG9wZXJhdGlvbnMgdG8gZW5zdXJlIGEgZ3JhY2VmdWwgc2h1dGRvd24gb2YgdGhlIHByb2Nlc3MuXHJcbiAqIFRoaXMgaW5jbHVkZXMgY2xlYXJpbmcgYWxsIHJlZ2lzdGVyZWQgdGltZW91dHMvaW50ZXJ2YWxzLCBjbG9zaW5nIGFjdGl2ZVxyXG4gKiBzZXJ2ZXJzLCB0ZXJtaW5hdGluZyByZXNvdXJjZXMgKHBhZ2VzKSBvZiB0aGUgcG9vbCwgcG9vbCBpdHNlbGYsIGFuZCBjbG9zaW5nXHJcbiAqIHRoZSBicm93c2VyLlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gc2h1dGRvd25DbGVhblVwXHJcbiAqXHJcbiAqIEBwYXJhbSB7bnVtYmVyfSBbZXhpdENvZGU9MF0gLSBUaGUgZXhpdCBjb2RlIHRvIHVzZSB3aXRoIGBwcm9jZXNzLmV4aXQoKWAuXHJcbiAqIFRoZSBkZWZhdWx0IHZhbHVlIGlzIGAwYC5cclxuICovXHJcbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBzaHV0ZG93bkNsZWFuVXAoZXhpdENvZGUgPSAwKSB7XHJcbiAgLy8gQXdhaXQgZnJlZWluZyBhbGwgcmVzb3VyY2VzXHJcbiAgYXdhaXQgUHJvbWlzZS5hbGxTZXR0bGVkKFtcclxuICAgIC8vIENsZWFyIGFsbCBvbmdvaW5nIGludGVydmFsc1xyXG4gICAgY2xlYXJBbGxUaW1lcnMoKSxcclxuXHJcbiAgICAvLyBHZXQgYXZhaWxhYmxlIHNlcnZlciBpbnN0YW5jZXMgKEhUVFAvSFRUUFMpIGFuZCBjbG9zZSB0aGVtXHJcbiAgICBjbG9zZVNlcnZlcnMoKSxcclxuXHJcbiAgICAvLyBDbG9zZSBhbiBhY3RpdmUgcG9vbCBhbG9uZyB3aXRoIGl0cyB3b3JrZXJzIGFuZCB0aGUgYnJvd3NlciBpbnN0YW5jZVxyXG4gICAga2lsbFBvb2woKVxyXG4gIF0pO1xyXG5cclxuICAvLyBFeGl0IHByb2Nlc3Mgd2l0aCBhIGNvcnJlY3QgY29kZVxyXG4gIHByb2Nlc3MuZXhpdChleGl0Q29kZSk7XHJcbn1cclxuXHJcbmV4cG9ydCBkZWZhdWx0IHtcclxuICBzaHV0ZG93bkNsZWFuVXBcclxufTtcclxuIiwiLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcclxuXHJcbkhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlclxyXG5cclxuQ29weXJpZ2h0IChjKSAyMDE2LTIwMjUsIEhpZ2hzb2Z0XHJcblxyXG5MaWNlbmNlZCB1bmRlciB0aGUgTUlUIGxpY2VuY2UuXHJcblxyXG5BZGRpdGlvbmFsbHkgYSB2YWxpZCBIaWdoY2hhcnRzIGxpY2Vuc2UgaXMgcmVxdWlyZWQgZm9yIHVzZS5cclxuXHJcblNlZSBMSUNFTlNFIGZpbGUgaW4gcm9vdCBmb3IgZGV0YWlscy5cclxuXHJcbioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXHJcblxyXG4vKipcclxuICogQG92ZXJ2aWV3IENvcmUgbW9kdWxlIGZvciBpbml0aWFsaXppbmcgYW5kIG1hbmFnaW5nIHRoZSBIaWdoY2hhcnRzIEV4cG9ydFxyXG4gKiBTZXJ2ZXIuIFByb3ZpZGVzIGZ1bmN0aW9uYWxpdGllcyBmb3IgY29uZmlndXJpbmcgZXhwb3J0cywgc2V0dGluZyB1cCBzZXJ2ZXJcclxuICogb3BlcmF0aW9ucywgbG9nZ2luZywgc2NyaXB0cyBjYWNoaW5nLCByZXNvdXJjZSBwb29saW5nLCBhbmQgZ3JhY2VmdWwgcHJvY2Vzc1xyXG4gKiBjbGVhbnVwLlxyXG4gKi9cclxuXHJcbmltcG9ydCAnY29sb3JzJztcclxuXHJcbmltcG9ydCB7IGNoZWNrQW5kVXBkYXRlQ2FjaGUgfSBmcm9tICcuL2NhY2hlLmpzJztcclxuaW1wb3J0IHtcclxuICBzaW5nbGVFeHBvcnQsXHJcbiAgYmF0Y2hFeHBvcnQsXHJcbiAgc3RhcnRFeHBvcnQsXHJcbiAgc2V0QWxsb3dDb2RlRXhlY3V0aW9uXHJcbn0gZnJvbSAnLi9jaGFydC5qcyc7XHJcbmltcG9ydCB7XHJcbiAgZ2V0T3B0aW9ucyxcclxuICBzZXRHbG9iYWxPcHRpb25zLFxyXG4gIG1hcFRvTmV3T3B0aW9ucyxcclxuICB1cGRhdGVPcHRpb25zLFxyXG4gIHZhbGlkYXRlT3B0aW9uLFxyXG4gIHZhbGlkYXRlT3B0aW9uc1xyXG59IGZyb20gJy4vY29uZmlnLmpzJztcclxuaW1wb3J0IHtcclxuICBsb2csXHJcbiAgbG9nV2l0aFN0YWNrLFxyXG4gIGxvZ1pvZElzc3VlcyxcclxuICBpbml0TG9nZ2luZyxcclxuICBlbmFibGVDb25zb2xlTG9nZ2luZyxcclxuICBlbmFibGVGaWxlTG9nZ2luZyxcclxuICBzZXRMb2dMZXZlbFxyXG59IGZyb20gJy4vbG9nZ2VyLmpzJztcclxuaW1wb3J0IHsgaW5pdFBvb2wsIGtpbGxQb29sIH0gZnJvbSAnLi9wb29sLmpzJztcclxuaW1wb3J0IHsgc2h1dGRvd25DbGVhblVwIH0gZnJvbSAnLi9yZXNvdXJjZVJlbGVhc2UuanMnO1xyXG5cclxuaW1wb3J0IHNlcnZlciBmcm9tICcuL3NlcnZlci9zZXJ2ZXIuanMnO1xyXG5cclxuLyoqXHJcbiAqIEluaXRpYWxpemVzIHRoZSBleHBvcnQgcHJvY2Vzcy4gVGFza3Mgc3VjaCBhcyBjb25maWd1cmluZyBsb2dnaW5nLCBjaGVja2luZ1xyXG4gKiB0aGUgY2FjaGUgYW5kIHNvdXJjZXMsIGFuZCBpbml0aWFsaXppbmcgdGhlIHJlc291cmNlIHBvb2wgb2NjdXIgZHVyaW5nIHRoaXNcclxuICogc3RhZ2UuXHJcbiAqXHJcbiAqIFRoaXMgZnVuY3Rpb24gbXVzdCBiZSBjYWxsZWQgYmVmb3JlIGF0dGVtcHRpbmcgdG8gZXhwb3J0IGNoYXJ0cyBvciBzZXRcclxuICogdXAgYSBzZXJ2ZXIuXHJcbiAqXHJcbiAqIEBhc3luY1xyXG4gKiBAZnVuY3Rpb24gaW5pdEV4cG9ydFxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gW2luaXRPcHRpb25zPXt9XSAtIFRoZSBgaW5pdE9wdGlvbnNgIG9iamVjdCwgd2hpY2ggbWF5XHJcbiAqIGJlIGEgcGFydGlhbCBvciBjb21wbGV0ZSBzZXQgb2Ygb3B0aW9ucy4gSWYgdGhlIG9wdGlvbnMgYXJlIHBhcnRpYWwsIG1pc3NpbmdcclxuICogdmFsdWVzIHdpbGwgZGVmYXVsdCB0byB0aGUgY3VycmVudCBnbG9iYWwgY29uZmlndXJhdGlvbi4gVGhlIGRlZmF1bHQgdmFsdWVcclxuICogaXMgYW4gZW1wdHkgb2JqZWN0LlxyXG4gKi9cclxuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIGluaXRFeHBvcnQoaW5pdE9wdGlvbnMgPSB7fSkge1xyXG4gIC8vIEluaXQsIHZhbGlkYXRlIGFuZCB1cGRhdGUgdGhlIGluc3RhbmNlIG9wdGlvbnMgb2JqZWN0XHJcbiAgY29uc3Qgb3B0aW9ucyA9IHVwZGF0ZU9wdGlvbnModmFsaWRhdGVPcHRpb25zKGluaXRPcHRpb25zKSwgdHJ1ZSk7XHJcblxyXG4gIC8vIFNldCB0aGUgYGFsbG93Q29kZUV4ZWN1dGlvbmAgcGVyIGV4cG9ydCBtb2R1bGUgc2NvcGVcclxuICBzZXRBbGxvd0NvZGVFeGVjdXRpb24ob3B0aW9ucy5jdXN0b21Mb2dpYy5hbGxvd0NvZGVFeGVjdXRpb24pO1xyXG5cclxuICAvLyBJbml0IHRoZSBsb2dnaW5nXHJcbiAgaW5pdExvZ2dpbmcob3B0aW9ucy5sb2dnaW5nKTtcclxuXHJcbiAgLy8gQXR0YWNoIHByb2Nlc3MnIGV4aXQgbGlzdGVuZXJzXHJcbiAgaWYgKG9wdGlvbnMub3RoZXIubGlzdGVuVG9Qcm9jZXNzRXhpdHMpIHtcclxuICAgIF9hdHRhY2hQcm9jZXNzRXhpdExpc3RlbmVycygpO1xyXG4gIH1cclxuXHJcbiAgLy8gQ2hlY2sgaWYgY2FjaGUgbmVlZHMgdG8gYmUgdXBkYXRlZFxyXG4gIGF3YWl0IGNoZWNrQW5kVXBkYXRlQ2FjaGUob3B0aW9ucy5oaWdoY2hhcnRzLCBvcHRpb25zLnNlcnZlci5wcm94eSk7XHJcblxyXG4gIC8vIEluaXQgdGhlIHBvb2xcclxuICBhd2FpdCBpbml0UG9vbChvcHRpb25zLnBvb2wsIG9wdGlvbnMucHVwcGV0ZWVyLmFyZ3MpO1xyXG59XHJcblxyXG4vKipcclxuICogQXR0YWNoZXMgZXhpdCBsaXN0ZW5lcnMgdG8gdGhlIHByb2Nlc3MsIGVuc3VyaW5nIHByb3BlciBjbGVhbnVwIG9mIHJlc291cmNlc1xyXG4gKiBhbmQgdGVybWluYXRpb24gb24gZXhpdCBzaWduYWxzLiBIYW5kbGVzICdleGl0JywgJ1NJR0lOVCcsICdTSUdURVJNJ1xyXG4gKiBhbmQgJ3VuY2F1Z2h0RXhjZXB0aW9uJyBldmVudHMuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBfYXR0YWNoUHJvY2Vzc0V4aXRMaXN0ZW5lcnNcclxuICovXHJcbmZ1bmN0aW9uIF9hdHRhY2hQcm9jZXNzRXhpdExpc3RlbmVycygpIHtcclxuICBsb2coMywgJ1twcm9jZXNzXSBBdHRhY2hpbmcgZXhpdCBsaXN0ZW5lcnMgdG8gdGhlIHByb2Nlc3MuJyk7XHJcblxyXG4gIC8vIEhhbmRsZXIgZm9yIHRoZSAnZXhpdCdcclxuICBwcm9jZXNzLm9uKCdleGl0JywgKGNvZGUpID0+IHtcclxuICAgIGxvZyg0LCBgW3Byb2Nlc3NdIFByb2Nlc3MgZXhpdGVkIHdpdGggY29kZSAke2NvZGV9LmApO1xyXG4gIH0pO1xyXG5cclxuICAvLyBIYW5kbGVyIGZvciB0aGUgJ1NJR0lOVCdcclxuICBwcm9jZXNzLm9uKCdTSUdJTlQnLCBhc3luYyAobmFtZSwgY29kZSkgPT4ge1xyXG4gICAgbG9nKDQsIGBbcHJvY2Vzc10gVGhlICR7bmFtZX0gZXZlbnQgd2l0aCBjb2RlOiAke2NvZGV9LmApO1xyXG4gICAgYXdhaXQgc2h1dGRvd25DbGVhblVwKCk7XHJcbiAgfSk7XHJcblxyXG4gIC8vIEhhbmRsZXIgZm9yIHRoZSAnU0lHVEVSTSdcclxuICBwcm9jZXNzLm9uKCdTSUdURVJNJywgYXN5bmMgKG5hbWUsIGNvZGUpID0+IHtcclxuICAgIGxvZyg0LCBgW3Byb2Nlc3NdIFRoZSAke25hbWV9IGV2ZW50IHdpdGggY29kZTogJHtjb2RlfS5gKTtcclxuICAgIGF3YWl0IHNodXRkb3duQ2xlYW5VcCgpO1xyXG4gIH0pO1xyXG5cclxuICAvLyBIYW5kbGVyIGZvciB0aGUgJ1NJR0hVUCdcclxuICBwcm9jZXNzLm9uKCdTSUdIVVAnLCBhc3luYyAobmFtZSwgY29kZSkgPT4ge1xyXG4gICAgbG9nKDQsIGBbcHJvY2Vzc10gVGhlICR7bmFtZX0gZXZlbnQgd2l0aCBjb2RlOiAke2NvZGV9LmApO1xyXG4gICAgYXdhaXQgc2h1dGRvd25DbGVhblVwKCk7XHJcbiAgfSk7XHJcblxyXG4gIC8vIEhhbmRsZXIgZm9yIHRoZSAndW5jYXVnaHRFeGNlcHRpb24nXHJcbiAgcHJvY2Vzcy5vbigndW5jYXVnaHRFeGNlcHRpb24nLCBhc3luYyAoZXJyb3IsIG5hbWUpID0+IHtcclxuICAgIGxvZ1dpdGhTdGFjaygxLCBlcnJvciwgYFtwcm9jZXNzXSBUaGUgJHtuYW1lfSBlcnJvci5gKTtcclxuICAgIGF3YWl0IHNodXRkb3duQ2xlYW5VcCgxKTtcclxuICB9KTtcclxufVxyXG5cclxuZXhwb3J0IGRlZmF1bHQge1xyXG4gIC8vIFNlcnZlclxyXG4gIC4uLnNlcnZlcixcclxuXHJcbiAgLy8gT3B0aW9uc1xyXG4gIGdldE9wdGlvbnMsXHJcbiAgc2V0R2xvYmFsT3B0aW9ucyxcclxuICBtYXBUb05ld09wdGlvbnMsXHJcblxyXG4gIC8vIFZhbGlkYXRpb25cclxuICB2YWxpZGF0ZU9wdGlvbixcclxuICB2YWxpZGF0ZU9wdGlvbnMsXHJcblxyXG4gIC8vIEV4cG9ydGluZ1xyXG4gIGluaXRFeHBvcnQsXHJcbiAgc2luZ2xlRXhwb3J0LFxyXG4gIGJhdGNoRXhwb3J0LFxyXG4gIHN0YXJ0RXhwb3J0LFxyXG5cclxuICAvLyBSZWxlYXNlXHJcbiAga2lsbFBvb2wsXHJcbiAgc2h1dGRvd25DbGVhblVwLFxyXG5cclxuICAvLyBMb2dzXHJcbiAgbG9nLFxyXG4gIGxvZ1dpdGhTdGFjayxcclxuICBsb2dab2RJc3N1ZXMsXHJcbiAgc2V0TG9nTGV2ZWw6IGZ1bmN0aW9uIChsZXZlbCkge1xyXG4gICAgLy8gVXBkYXRlIHRoZSBpbnN0YW5jZSBvcHRpb25zIG9iamVjdFxyXG4gICAgY29uc3Qgb3B0aW9ucyA9IHVwZGF0ZU9wdGlvbnMoXHJcbiAgICAgIHZhbGlkYXRlT3B0aW9ucyh7XHJcbiAgICAgICAgbG9nZ2luZzoge1xyXG4gICAgICAgICAgbGV2ZWxcclxuICAgICAgICB9XHJcbiAgICAgIH0pXHJcbiAgICApO1xyXG5cclxuICAgIC8vIENhbGwgdGhlIGZ1bmN0aW9uXHJcbiAgICBzZXRMb2dMZXZlbChvcHRpb25zLmxvZ2dpbmcubGV2ZWwpO1xyXG4gIH0sXHJcbiAgZW5hYmxlQ29uc29sZUxvZ2dpbmc6IGZ1bmN0aW9uICh0b0NvbnNvbGUpIHtcclxuICAgIC8vIFVwZGF0ZSB0aGUgaW5zdGFuY2Ugb3B0aW9ucyBvYmplY3RcclxuICAgIGNvbnN0IG9wdGlvbnMgPSB1cGRhdGVPcHRpb25zKFxyXG4gICAgICB2YWxpZGF0ZU9wdGlvbnMoe1xyXG4gICAgICAgIGxvZ2dpbmc6IHtcclxuICAgICAgICAgIHRvQ29uc29sZVxyXG4gICAgICAgIH1cclxuICAgICAgfSlcclxuICAgICk7XHJcblxyXG4gICAgLy8gQ2FsbCB0aGUgZnVuY3Rpb25cclxuICAgIGVuYWJsZUNvbnNvbGVMb2dnaW5nKG9wdGlvbnMubG9nZ2luZy50b0NvbnNvbGUpO1xyXG4gIH0sXHJcbiAgZW5hYmxlRmlsZUxvZ2dpbmc6IGZ1bmN0aW9uIChkZXN0LCBmaWxlLCB0b0ZpbGUpIHtcclxuICAgIC8vIFVwZGF0ZSB0aGUgaW5zdGFuY2Ugb3B0aW9ucyBvYmplY3RcclxuICAgIGNvbnN0IG9wdGlvbnMgPSB1cGRhdGVPcHRpb25zKFxyXG4gICAgICB2YWxpZGF0ZU9wdGlvbnMoe1xyXG4gICAgICAgIGxvZ2dpbmc6IHtcclxuICAgICAgICAgIGRlc3QsXHJcbiAgICAgICAgICBmaWxlLFxyXG4gICAgICAgICAgdG9GaWxlXHJcbiAgICAgICAgfVxyXG4gICAgICB9KVxyXG4gICAgKTtcclxuXHJcbiAgICAvLyBDYWxsIHRoZSBmdW5jdGlvblxyXG4gICAgZW5hYmxlRmlsZUxvZ2dpbmcoXHJcbiAgICAgIG9wdGlvbnMubG9nZ2luZy5kZXN0LFxyXG4gICAgICBvcHRpb25zLmxvZ2dpbmcuZmlsZSxcclxuICAgICAgb3B0aW9ucy5sb2dnaW5nLnRvRmlsZVxyXG4gICAgKTtcclxuICB9XHJcbn07XHJcbiJdLCJuYW1lcyI6WyJfX2Rpcm5hbWUiLCJmaWxlVVJMVG9QYXRoIiwiVVJMIiwiZG9jdW1lbnQiLCJyZXF1aXJlIiwicGF0aFRvRmlsZVVSTCIsIl9fZmlsZW5hbWUiLCJocmVmIiwiX2RvY3VtZW50Q3VycmVudFNjcmlwdCIsInRhZ05hbWUiLCJ0b1VwcGVyQ2FzZSIsInNyYyIsImJhc2VVUkkiLCJkZWVwQ29weSIsIm9iakFyciIsIm9iakFyckNvcHkiLCJBcnJheSIsImlzQXJyYXkiLCJrZXkiLCJPYmplY3QiLCJwcm90b3R5cGUiLCJoYXNPd25Qcm9wZXJ0eSIsImNhbGwiLCJmaXhDb25zdHIiLCJjb25zdHIiLCJmaXhlZENvbnN0ciIsInRvTG93ZXJDYXNlIiwicmVwbGFjZSIsImluY2x1ZGVzIiwiZml4T3V0ZmlsZSIsInR5cGUiLCJvdXRmaWxlIiwiZ2V0QWJzb2x1dGVQYXRoIiwic3BsaXQiLCJzaGlmdCIsImZpeFR5cGUiLCJtaW1lVHlwZXMiLCJmb3JtYXRzIiwidmFsdWVzIiwib3V0VHlwZSIsInBvcCIsImZpbmQiLCJ0IiwicGF0aCIsImlzQWJzb2x1dGUiLCJqb2luIiwiZ2V0QmFzZTY0IiwiaW5wdXQiLCJCdWZmZXIiLCJmcm9tIiwidG9TdHJpbmciLCJnZXROZXdEYXRlIiwiRGF0ZSIsInRyaW0iLCJnZXROZXdEYXRlVGltZSIsImdldFRpbWUiLCJpc09iamVjdCIsIml0ZW0iLCJpc09iamVjdEVtcHR5Iiwia2V5cyIsImxlbmd0aCIsImlzUHJpdmF0ZVJhbmdlVXJsRm91bmQiLCJzb21lIiwicGF0dGVybiIsInRlc3QiLCJtZWFzdXJlVGltZSIsInN0YXJ0IiwicHJvY2VzcyIsImhydGltZSIsImJpZ2ludCIsIk51bWJlciIsInJvdW5kTnVtYmVyIiwidmFsdWUiLCJwcmVjaXNpb24iLCJtdWx0aXBsaWVyIiwiTWF0aCIsInBvdyIsInJvdW5kIiwid3JhcEFyb3VuZCIsImN1c3RvbUNvZGUiLCJhbGxvd0ZpbGVSZXNvdXJjZXMiLCJpc0NhbGxiYWNrIiwiZW5kc1dpdGgiLCJyZWFkRmlsZVN5bmMiLCJzdGFydHNXaXRoIiwiY29sb3JzIiwibG9nZ2luZyIsInRvQ29uc29sZSIsInRvRmlsZSIsInBhdGhDcmVhdGVkIiwicGF0aFRvTG9nIiwibGV2ZWxzRGVzYyIsInRpdGxlIiwiY29sb3IiLCJsb2ciLCJhcmdzIiwibmV3TGV2ZWwiLCJ0ZXh0cyIsImxldmVsIiwicHJlZml4IiwiX2xvZ1RvRmlsZSIsImNvbnNvbGUiLCJhcHBseSIsInVuZGVmaW5lZCIsImNvbmNhdCIsImxvZ1dpdGhTdGFjayIsImVycm9yIiwiY3VzdG9tTWVzc2FnZSIsIm1haW5NZXNzYWdlIiwibWVzc2FnZSIsInN0YWNrTWVzc2FnZSIsInN0YWNrIiwicHVzaCIsImxvZ1pvZElzc3VlcyIsImlzc3VlcyIsIm1hcCIsImlzc3VlIiwiaW5pdExvZ2dpbmciLCJsb2dnaW5nT3B0aW9ucyIsImRlc3QiLCJmaWxlIiwic2V0TG9nTGV2ZWwiLCJlbmFibGVDb25zb2xlTG9nZ2luZyIsImVuYWJsZUZpbGVMb2dnaW5nIiwiaXNJbnRlZ2VyIiwiZXhpc3RzU3luYyIsIm1rZGlyU3luYyIsImFwcGVuZEZpbGUiLCJkZWZhdWx0Q29uZmlnIiwicHVwcGV0ZWVyIiwidHlwZXMiLCJlbnZMaW5rIiwiY2xpTmFtZSIsImRlc2NyaXB0aW9uIiwicHJvbXB0T3B0aW9ucyIsInNlcGFyYXRvciIsImhpZ2hjaGFydHMiLCJ2ZXJzaW9uIiwiY2RuVXJsIiwiZm9yY2VGZXRjaCIsImNhY2hlUGF0aCIsImNvcmVTY3JpcHRzIiwiaW5zdHJ1Y3Rpb25zIiwibW9kdWxlU2NyaXB0cyIsImluZGljYXRvclNjcmlwdHMiLCJjdXN0b21TY3JpcHRzIiwiZXhwb3J0IiwiaW5maWxlIiwiaW5zdHIiLCJvcHRpb25zIiwic3ZnIiwiYmF0Y2giLCJoaW50IiwiY2hvaWNlcyIsImI2NCIsIm5vRG93bmxvYWQiLCJoZWlnaHQiLCJ3aWR0aCIsInNjYWxlIiwiZGVmYXVsdEhlaWdodCIsImRlZmF1bHRXaWR0aCIsImRlZmF1bHRTY2FsZSIsIm1pbiIsIm1heCIsImdsb2JhbE9wdGlvbnMiLCJ0aGVtZU9wdGlvbnMiLCJyYXN0ZXJpemF0aW9uVGltZW91dCIsImN1c3RvbUxvZ2ljIiwiYWxsb3dDb2RlRXhlY3V0aW9uIiwiY2FsbGJhY2siLCJyZXNvdXJjZXMiLCJsb2FkQ29uZmlnIiwibGVnYWN5TmFtZSIsImNyZWF0ZUNvbmZpZyIsInNlcnZlciIsImVuYWJsZSIsImhvc3QiLCJwb3J0IiwidXBsb2FkTGltaXQiLCJiZW5jaG1hcmtpbmciLCJwcm94eSIsInRpbWVvdXQiLCJyYXRlTGltaXRpbmciLCJtYXhSZXF1ZXN0cyIsIndpbmRvdyIsImRlbGF5IiwidHJ1c3RQcm94eSIsInNraXBLZXkiLCJza2lwVG9rZW4iLCJzc2wiLCJmb3JjZSIsImNlcnRQYXRoIiwicG9vbCIsIm1pbldvcmtlcnMiLCJtYXhXb3JrZXJzIiwid29ya0xpbWl0IiwiYWNxdWlyZVRpbWVvdXQiLCJjcmVhdGVUaW1lb3V0IiwiZGVzdHJveVRpbWVvdXQiLCJpZGxlVGltZW91dCIsImNyZWF0ZVJldHJ5SW50ZXJ2YWwiLCJyZWFwZXJJbnRlcnZhbCIsInVpIiwicm91dGUiLCJvdGhlciIsIm5vZGVFbnYiLCJsaXN0ZW5Ub1Byb2Nlc3NFeGl0cyIsIm5vTG9nbyIsImhhcmRSZXNldFBhZ2UiLCJicm93c2VyU2hlbGxNb2RlIiwidmFsaWRhdGlvbiIsImRlYnVnIiwiaGVhZGxlc3MiLCJkZXZ0b29scyIsImxpc3RlblRvQ29uc29sZSIsImR1bXBpbyIsInNsb3dNbyIsImRlYnVnZ2luZ1BvcnQiLCJuZXN0ZWRQcm9wcyIsIl9jcmVhdGVOZXN0ZWRQcm9wcyIsImFic29sdXRlUHJvcHMiLCJfY3JlYXRlQWJzb2x1dGVQcm9wcyIsImNvbmZpZyIsInByb3BDaGFpbiIsImZvckVhY2giLCJlbnRyeSIsInN1YnN0cmluZyIsImRvdGVudiIsInoiLCJzZXRFcnJvck1hcCIsIl9jdXN0b21FcnJvck1hcCIsInYiLCJib29sZWFuIiwic3RyaWN0Q2hlY2siLCJ1bmlvbiIsImVudW0iLCJ0cmFuc2Zvcm0iLCJudWxsYWJsZSIsInN0cmluZyIsInJlZmluZSIsInBhcmFtcyIsImVycm9yTWVzc2FnZSIsInN0cmluZ0FycmF5IiwiZmlsdGVyQ2FsbGJhY2siLCJhcnJheVNjaGVtYSIsImFycmF5Iiwic3RyaW5nU2NoZW1hIiwic2xpY2UiLCJ0cmFuc2Zvcm1DYWxsYmFjayIsImZpbHRlciIsInBvc2l0aXZlTnVtIiwibnVtYmVyIiwicG9zaXRpdmUiLCJpc05hTiIsIm5vbk5lZ2F0aXZlTnVtIiwibm9ubmVnYXRpdmUiLCJwcmVmaXhlcyIsImNoYXJ0Q29uZmlnIiwib2JqZWN0IiwicGFzc3Rocm91Z2giLCJhZGRpdGlvbmFsT3B0aW9ucyIsInZhbGlkYXRvcnMiLCJhZG1pblRva2VuIiwiaW5kZXhPZiIsImd0ZSIsImx0ZSIsInRoaXMiLCJvYmplY3RTY2hlbWEiLCJqcyIsImNzcyIsImZpbGVzIiwicGFydGlhbCIsInN0cmluZ1NjaGVtYTEiLCJzdHJpbmdTY2hlbWEyIiwiZW5hYmxlU2VydmVyIiwic2VydmVyQmVuY2htYXJraW5nIiwicHJveHlIb3N0IiwicHJveHlQb3J0IiwicHJveHlUaW1lb3V0IiwiZW5hYmxlUmF0ZUxpbWl0aW5nIiwiZW5hYmxlU3NsIiwic3NsRm9yY2UiLCJzc2xQb3J0Iiwic3NsQ2VydFBhdGgiLCJwb29sQmVuY2htYXJraW5nIiwicmVzb3VyY2VzSW50ZXJ2YWwiLCJsb2dMZXZlbCIsImludCIsImxvZ0ZpbGUiLCJsb2dEZXN0IiwibG9nVG9Db25zb2xlIiwibG9nVG9GaWxlIiwiZW5hYmxlVWkiLCJ1aVJvdXRlIiwiZW5hYmxlRGVidWciLCJyZXF1ZXN0SWQiLCJ1dWlkIiwiUHVwcGV0ZWVyU2NoZW1hIiwiSGlnaGNoYXJ0c1NjaGVtYSIsIkV4cG9ydFNjaGVtYSIsIkN1c3RvbUxvZ2ljU2NoZW1hIiwiUHJveHlTY2hlbWEiLCJSYXRlTGltaXRpbmdTY2hlbWEiLCJTc2xTY2hlbWEiLCJTZXJ2ZXJTY2hlbWEiLCJvcHRpb25hbCIsIlBvb2xTY2hlbWEiLCJMb2dnaW5nU2NoZW1hIiwiVWlTY2hlbWEiLCJPdGhlclNjaGVtYSIsIkRlYnVnU2NoZW1hIiwiU3RyaWN0Q29uZmlnU2NoZW1hIiwiTG9vc2VDb25maWdTY2hlbWEiLCJFbnZTY2hlbWEiLCJQVVBQRVRFRVJfQVJHUyIsIkhJR0hDSEFSVFNfVkVSU0lPTiIsIkhJR0hDSEFSVFNfQ0ROX1VSTCIsIkhJR0hDSEFSVFNfRk9SQ0VfRkVUQ0giLCJISUdIQ0hBUlRTX0NBQ0hFX1BBVEgiLCJISUdIQ0hBUlRTX0FETUlOX1RPS0VOIiwiSElHSENIQVJUU19DT1JFX1NDUklQVFMiLCJISUdIQ0hBUlRTX01PRFVMRV9TQ1JJUFRTIiwiSElHSENIQVJUU19JTkRJQ0FUT1JfU0NSSVBUUyIsIkhJR0hDSEFSVFNfQ1VTVE9NX1NDUklQVFMiLCJFWFBPUlRfSU5GSUxFIiwiRVhQT1JUX0lOU1RSIiwiRVhQT1JUX09QVElPTlMiLCJFWFBPUlRfU1ZHIiwiRVhQT1JUX0JBVENIIiwiRVhQT1JUX09VVEZJTEUiLCJFWFBPUlRfVFlQRSIsIkVYUE9SVF9DT05TVFIiLCJFWFBPUlRfQjY0IiwiRVhQT1JUX05PX0RPV05MT0FEIiwiRVhQT1JUX0hFSUdIVCIsIkVYUE9SVF9XSURUSCIsIkVYUE9SVF9TQ0FMRSIsIkVYUE9SVF9ERUZBVUxUX0hFSUdIVCIsIkVYUE9SVF9ERUZBVUxUX1dJRFRIIiwiRVhQT1JUX0RFRkFVTFRfU0NBTEUiLCJFWFBPUlRfR0xPQkFMX09QVElPTlMiLCJFWFBPUlRfVEhFTUVfT1BUSU9OUyIsIkVYUE9SVF9SQVNURVJJWkFUSU9OX1RJTUVPVVQiLCJDVVNUT01fTE9HSUNfQUxMT1dfQ09ERV9FWEVDVVRJT04iLCJDVVNUT01fTE9HSUNfQUxMT1dfRklMRV9SRVNPVVJDRVMiLCJDVVNUT01fTE9HSUNfQ1VTVE9NX0NPREUiLCJDVVNUT01fTE9HSUNfQ0FMTEJBQ0siLCJDVVNUT01fTE9HSUNfUkVTT1VSQ0VTIiwiQ1VTVE9NX0xPR0lDX0xPQURfQ09ORklHIiwiQ1VTVE9NX0xPR0lDX0NSRUFURV9DT05GSUciLCJTRVJWRVJfRU5BQkxFIiwiU0VSVkVSX0hPU1QiLCJTRVJWRVJfUE9SVCIsIlNFUlZFUl9VUExPQURfTElNSVQiLCJTRVJWRVJfQkVOQ0hNQVJLSU5HIiwiU0VSVkVSX1BST1hZX0hPU1QiLCJTRVJWRVJfUFJPWFlfUE9SVCIsIlNFUlZFUl9QUk9YWV9USU1FT1VUIiwiU0VSVkVSX1JBVEVfTElNSVRJTkdfRU5BQkxFIiwiU0VSVkVSX1JBVEVfTElNSVRJTkdfTUFYX1JFUVVFU1RTIiwiU0VSVkVSX1JBVEVfTElNSVRJTkdfV0lORE9XIiwiU0VSVkVSX1JBVEVfTElNSVRJTkdfREVMQVkiLCJTRVJWRVJfUkFURV9MSU1JVElOR19UUlVTVF9QUk9YWSIsIlNFUlZFUl9SQVRFX0xJTUlUSU5HX1NLSVBfS0VZIiwiU0VSVkVSX1JBVEVfTElNSVRJTkdfU0tJUF9UT0tFTiIsIlNFUlZFUl9TU0xfRU5BQkxFIiwiU0VSVkVSX1NTTF9GT1JDRSIsIlNFUlZFUl9TU0xfUE9SVCIsIlNFUlZFUl9TU0xfQ0VSVF9QQVRIIiwiUE9PTF9NSU5fV09SS0VSUyIsIlBPT0xfTUFYX1dPUktFUlMiLCJQT09MX1dPUktfTElNSVQiLCJQT09MX0FDUVVJUkVfVElNRU9VVCIsIlBPT0xfQ1JFQVRFX1RJTUVPVVQiLCJQT09MX0RFU1RST1lfVElNRU9VVCIsIlBPT0xfSURMRV9USU1FT1VUIiwiUE9PTF9DUkVBVEVfUkVUUllfSU5URVJWQUwiLCJQT09MX1JFQVBFUl9JTlRFUlZBTCIsIlBPT0xfQkVOQ0hNQVJLSU5HIiwiTE9HR0lOR19MRVZFTCIsIkxPR0dJTkdfRklMRSIsIkxPR0dJTkdfREVTVCIsIkxPR0dJTkdfVE9fQ09OU09MRSIsIkxPR0dJTkdfVE9fRklMRSIsIlVJX0VOQUJMRSIsIlVJX1JPVVRFIiwiT1RIRVJfTk9ERV9FTlYiLCJPVEhFUl9MSVNURU5fVE9fUFJPQ0VTU19FWElUUyIsIk9USEVSX05PX0xPR08iLCJPVEhFUl9IQVJEX1JFU0VUX1BBR0UiLCJPVEhFUl9CUk9XU0VSX1NIRUxMX01PREUiLCJPVEhFUl9WQUxJREFUSU9OIiwiREVCVUdfRU5BQkxFIiwiREVCVUdfSEVBRExFU1MiLCJERUJVR19ERVZUT09MUyIsIkRFQlVHX0xJU1RFTl9UT19DT05TT0xFIiwiREVCVUdfRFVNUElPIiwiREVCVUdfU0xPV19NTyIsIkRFQlVHX0RFQlVHR0lOR19QT1JUIiwiZW52cyIsInBhcnNlIiwiZW52Iiwic3RyaWN0VmFsaWRhdGUiLCJjb25maWdPcHRpb25zIiwibG9vc2VWYWxpZGF0ZSIsImNvbnRleHQiLCJwcm9wZXJ0eU5hbWUiLCJwcm9wZXJ0eUluZm8iLCJjb2RlIiwiWm9kSXNzdWVDb2RlIiwiaW52YWxpZF90eXBlIiwicmVjZWl2ZWQiLCJab2RQYXJzZWRUeXBlIiwiZGVmYXVsdEVycm9yIiwiY3VzdG9tIiwiZGF0YSIsImludmFsaWRfdW5pb24iLCJ1bmlvbkVycm9ycyIsImluZGV4IiwiRXhwb3J0RXJyb3IiLCJFcnJvciIsImNvbnN0cnVjdG9yIiwic3RhdHVzQ29kZSIsInN1cGVyIiwic2V0U3RhdHVzIiwic2V0RXJyb3IiLCJuYW1lIiwiX2luaXRHbG9iYWxPcHRpb25zIiwiaW5zdGFuY2VPcHRpb25zIiwiZ2V0T3B0aW9ucyIsImdldEluc3RhbmNlIiwic2V0R2xvYmFsT3B0aW9ucyIsImN1c3RvbU9wdGlvbnMiLCJjbGlBcmdzIiwiY2xpT3B0aW9ucyIsIl9sb2FkQ29uZmlnRmlsZSIsIl9wYWlyQXJndW1lbnRWYWx1ZSIsIl91cGRhdGVHbG9iYWxPcHRpb25zIiwidXBkYXRlT3B0aW9ucyIsIm5ld0luc3RhbmNlIiwibWVyZ2VPcHRpb25zIiwib3JpZ2luYWxPcHRpb25zIiwibmV3T3B0aW9ucyIsImVudHJpZXMiLCJtYXBUb05ld09wdGlvbnMiLCJvbGRPcHRpb25zIiwicHJvcGVydGllc0NoYWluIiwicmVkdWNlIiwib2JqIiwicHJvcCIsInZhbGlkYXRlT3B0aW9uIiwiY29uZmlnT3B0aW9uIiwidmFsaWRhdGVPcHRpb25zIiwiaXNBbGxvd2VkQ29uZmlnIiwiYWxsb3dGdW5jdGlvbnMiLCJvYmplY3RDb25maWciLCJldmFsIiwiSlNPTiIsInN0cmluZ2lmaWVkT3B0aW9ucyIsIl9vcHRpb25zU3RyaW5naWZ5IiwicGFyc2VkT3B0aW9ucyIsIl8iLCJlbnZWYWwiLCJjb25maWdPcHQiLCJjbGlPcHQiLCJjdXN0b21PcHQiLCJjb25maWdWYWwiLCJjbGlWYWwiLCJjdXN0b21WYWwiLCJzdHJpbmdpZnlGdW5jdGlvbnMiLCJzdHJpbmdpZnkiLCJyZXBsYWNlQWxsIiwiY3VzdG9tTG9naWNPcHRpb25zIiwiY29uZmlnSW5kZXgiLCJmaW5kSW5kZXgiLCJhcmciLCJjb25maWdGaWxlTmFtZSIsImkiLCJvcHRpb24iLCJhc3luYyIsImZldGNoIiwidXJsIiwicmVxdWVzdE9wdGlvbnMiLCJQcm9taXNlIiwicmVzb2x2ZSIsInJlamVjdCIsIl9nZXRQcm90b2NvbE1vZHVsZSIsImdldCIsInJlc3BvbnNlIiwicmVzcG9uc2VEYXRhIiwib24iLCJjaHVuayIsInRleHQiLCJodHRwcyIsImh0dHAiLCJjYWNoZSIsImFjdGl2ZU1hbmlmZXN0Iiwic291cmNlcyIsImhjVmVyc2lvbiIsImNoZWNrQW5kVXBkYXRlQ2FjaGUiLCJoaWdoY2hhcnRzT3B0aW9ucyIsInNlcnZlclByb3h5T3B0aW9ucyIsImZldGNoZWRNb2R1bGVzIiwiZ2V0Q2FjaGVQYXRoIiwibWFuaWZlc3RQYXRoIiwic291cmNlUGF0aCIsInJlY3Vyc2l2ZSIsIl91cGRhdGVDYWNoZSIsInJlcXVlc3RVcGRhdGUiLCJtYW5pZmVzdCIsIm1vZHVsZXMiLCJtb2R1bGVNYXAiLCJtIiwibnVtYmVyT2ZNb2R1bGVzIiwibW9kdWxlTmFtZSIsImV4dHJhY3RWZXJzaW9uIiwiX3NhdmVDb25maWdUb01hbmlmZXN0IiwiZ2V0SGlnaGNoYXJ0c1ZlcnNpb24iLCJ1cGRhdGVIaWdoY2hhcnRzVmVyc2lvbiIsIm5ld1ZlcnNpb24iLCJjYWNoZVNvdXJjZXMiLCJleHRyYWN0TW9kdWxlTmFtZSIsInNjcmlwdFBhdGgiLCJfZmV0Y2hBbmRQcm9jZXNzU2NyaXB0Iiwic2NyaXB0Iiwic2hvdWxkVGhyb3dFcnJvciIsIm5ld01hbmlmZXN0Iiwid3JpdGVGaWxlU3luYyIsIl9mZXRjaFNjcmlwdHMiLCJwcm94eUFnZW50IiwiSHR0cHNQcm94eUFnZW50IiwiYWdlbnQiLCJhbGxGZXRjaFByb21pc2VzIiwiYWxsIiwiYyIsInNldHVwSGlnaGNoYXJ0cyIsIkhpZ2hjaGFydHMiLCJhbmltT2JqZWN0IiwiZHVyYXRpb24iLCJjcmVhdGVDaGFydCIsImV4cG9ydE9wdGlvbnMiLCJzZXRPcHRpb25zIiwibWVyZ2UiLCJ3cmFwIiwic2V0T3B0aW9uc09iaiIsImlzUmVuZGVyQ29tcGxldGUiLCJDaGFydCIsInByb2NlZWQiLCJ1c2VyT3B0aW9ucyIsImNiIiwiZXhwb3J0aW5nIiwiZW5hYmxlZCIsInBsb3RPcHRpb25zIiwic2VyaWVzIiwibGFiZWwiLCJ0b29sdGlwIiwiYW5pbWF0aW9uIiwib25IaWdoY2hhcnRzUmVuZGVyIiwiYWRkRXZlbnQiLCJTZXJpZXMiLCJjaGFydCIsIkZ1bmN0aW9uIiwiZmluYWxPcHRpb25zIiwiZmluYWxDYWxsYmFjayIsImRlZmF1bHRPcHRpb25zIiwidGVtcGxhdGUiLCJicm93c2VyIiwiY3JlYXRlQnJvd3NlciIsInB1cHBldGVlckFyZ3MiLCJlbmFibGVkRGVidWciLCJkZWJ1Z09wdGlvbnMiLCJsYXVuY2hPcHRpb25zIiwidXNlckRhdGFEaXIiLCJoYW5kbGVTSUdJTlQiLCJoYW5kbGVTSUdURVJNIiwiaGFuZGxlU0lHSFVQIiwid2FpdEZvckluaXRpYWxQYWdlIiwiZGVmYXVsdFZpZXdwb3J0IiwidHJ5Q291bnQiLCJvcGVuIiwibGF1bmNoIiwic2V0VGltZW91dCIsImNsb3NlQnJvd3NlciIsImNvbm5lY3RlZCIsImNsb3NlIiwibmV3UGFnZSIsInBvb2xSZXNvdXJjZSIsInBhZ2UiLCJzZXRDYWNoZUVuYWJsZWQiLCJfc2V0UGFnZUNvbnRlbnQiLCJfc2V0UGFnZUV2ZW50cyIsImlzQ2xvc2VkIiwiY2xlYXJQYWdlIiwiaGFyZFJlc2V0IiwiZ290byIsIndhaXRVbnRpbCIsImV2YWx1YXRlIiwiYm9keSIsImlubmVySFRNTCIsImlkIiwid29ya0NvdW50IiwiYWRkUGFnZVJlc291cmNlcyIsImluamVjdGVkUmVzb3VyY2VzIiwiaW5qZWN0ZWRKcyIsImNvbnRlbnQiLCJpc0xvY2FsIiwianNSZXNvdXJjZSIsImFkZFNjcmlwdFRhZyIsImluamVjdGVkQ3NzIiwiY3NzSW1wb3J0cyIsIm1hdGNoIiwiY3NzSW1wb3J0UGF0aCIsImNzc1Jlc291cmNlIiwiYWRkU3R5bGVUYWciLCJjbGVhclBhZ2VSZXNvdXJjZXMiLCJyZXNvdXJjZSIsImRpc3Bvc2UiLCJvbGRDaGFydHMiLCJjaGFydHMiLCJvbGRDaGFydCIsImRlc3Ryb3kiLCJzY3JpcHRzVG9SZW1vdmUiLCJnZXRFbGVtZW50c0J5VGFnTmFtZSIsInN0eWxlc1RvUmVtb3ZlIiwibGlua3NUb1JlbW92ZSIsImVsZW1lbnQiLCJyZW1vdmUiLCJzZXRDb250ZW50IiwiY3NzVGVtcGxhdGUiLCJzdmdUZW1wbGF0ZSIsInB1cHBldGVlckV4cG9ydCIsImlzU1ZHIiwic2l6ZSIsInN2Z0VsZW1lbnQiLCJxdWVyeVNlbGVjdG9yIiwiY2hhcnRIZWlnaHQiLCJiYXNlVmFsIiwiY2hhcnRXaWR0aCIsInN0eWxlIiwiem9vbSIsIm1hcmdpbiIsInBhcnNlRmxvYXQiLCJ4IiwieSIsIl9nZXRDbGlwUmVnaW9uIiwidmlld3BvcnRIZWlnaHQiLCJhYnMiLCJjZWlsIiwidmlld3BvcnRXaWR0aCIsInJlc3VsdCIsInNldFZpZXdwb3J0IiwiZGV2aWNlU2NhbGVGYWN0b3IiLCJfY3JlYXRlU1ZHIiwiX2NyZWF0ZUltYWdlIiwiX2NyZWF0ZVBERiIsIiRldmFsIiwiZ2V0Qm91bmRpbmdDbGllbnRSZWN0IiwidHJ1bmMiLCJvdXRlckhUTUwiLCJjbGlwIiwicmFjZSIsInNjcmVlbnNob3QiLCJlbmNvZGluZyIsImZ1bGxQYWdlIiwib3B0aW1pemVGb3JTcGVlZCIsImNhcHR1cmVCZXlvbmRWaWV3cG9ydCIsInF1YWxpdHkiLCJvbWl0QmFja2dyb3VuZCIsIl9yZXNvbHZlIiwiZW11bGF0ZU1lZGlhVHlwZSIsInBkZiIsInBvb2xTdGF0cyIsImV4cG9ydHNBdHRlbXB0ZWQiLCJleHBvcnRzUGVyZm9ybWVkIiwiZXhwb3J0c0Ryb3BwZWQiLCJleHBvcnRzRnJvbVN2ZyIsImV4cG9ydHNGcm9tT3B0aW9ucyIsImV4cG9ydHNGcm9tU3ZnQXR0ZW1wdHMiLCJleHBvcnRzRnJvbU9wdGlvbnNBdHRlbXB0cyIsInRpbWVTcGVudCIsInRpbWVTcGVudEF2ZXJhZ2UiLCJpbml0UG9vbCIsInBvb2xPcHRpb25zIiwiUG9vbCIsIl9mYWN0b3J5IiwiYWNxdWlyZVRpbWVvdXRNaWxsaXMiLCJjcmVhdGVUaW1lb3V0TWlsbGlzIiwiZGVzdHJveVRpbWVvdXRNaWxsaXMiLCJpZGxlVGltZW91dE1pbGxpcyIsImNyZWF0ZVJldHJ5SW50ZXJ2YWxNaWxsaXMiLCJyZWFwSW50ZXJ2YWxNaWxsaXMiLCJwcm9wYWdhdGVDcmVhdGVFcnJvciIsImNsZWFyU3RhdHVzIiwiX2V2ZW50SWQiLCJpbml0aWFsUmVzb3VyY2VzIiwiYWNxdWlyZSIsInByb21pc2UiLCJyZWxlYXNlIiwia2lsbFBvb2wiLCJ3b3JrZXIiLCJ1c2VkIiwiZGVzdHJveWVkIiwicG9zdFdvcmsiLCJ3b3JrZXJIYW5kbGUiLCJnZXRQb29sSW5mbyIsImFjcXVpcmVDb3VudGVyIiwid29ya1N0YXJ0IiwiZXhwb3J0Q291bnRlciIsImV4cG9ydFRpbWUiLCJnZXRQb29sU3RhdHMiLCJnZXRQb29sSW5mb0pTT04iLCJudW1Vc2VkIiwiYXZhaWxhYmxlIiwibnVtRnJlZSIsImFsbENyZWF0ZWQiLCJwZW5kaW5nQWNxdWlyZXMiLCJudW1QZW5kaW5nQWNxdWlyZXMiLCJwZW5kaW5nQ3JlYXRlcyIsIm51bVBlbmRpbmdDcmVhdGVzIiwicGVuZGluZ1ZhbGlkYXRpb25zIiwibnVtUGVuZGluZ1ZhbGlkYXRpb25zIiwicGVuZGluZ0Rlc3Ryb3lzIiwiYWJzb2x1dGVBbGwiLCJjcmVhdGUiLCJyYW5kb20iLCJzdGFydERhdGUiLCJ2YWxpZGF0ZSIsIm1haW5GcmFtZSIsImRldGFjaGVkIiwicmVtb3ZlQWxsTGlzdGVuZXJzIiwic2FuaXRpemUiLCJKU0RPTSIsIkRPTVB1cmlmeSIsIkFERF9UQUdTIiwic2luZ2xlRXhwb3J0Iiwic3RhcnRFeHBvcnQiLCJiYXRjaEV4cG9ydCIsImJhdGNoRnVuY3Rpb25zIiwicGFpciIsImJhdGNoUmVzdWx0cyIsImFsbFNldHRsZWQiLCJyZWFzb24iLCJleHBvcnRpbmdPcHRpb25zIiwiZW5kQ2FsbGJhY2siLCJmaWxlQ29udGVudCIsIl9leHBvcnRGcm9tU3ZnIiwiX2V4cG9ydEZyb21PcHRpb25zIiwiZ2V0QWxsb3dDb2RlRXhlY3V0aW9uIiwic2V0QWxsb3dDb2RlRXhlY3V0aW9uIiwiaW5wdXRUb0V4cG9ydCIsIl9wcmVwYXJlRXhwb3J0IiwiX2hhbmRsZUN1c3RvbUxvZ2ljIiwiX2hhbmRsZUdsb2JhbEFuZFRoZW1lIiwiX2ZpbmRDaGFydFNpemUiLCJvcHRpb25zQ2hhcnQiLCJvcHRpb25zRXhwb3J0aW5nIiwiZ2xvYmFsT3B0aW9uc0NoYXJ0IiwiZ2xvYmFsT3B0aW9uc0V4cG9ydGluZyIsInRoZW1lT3B0aW9uc0NoYXJ0IiwidGhlbWVPcHRpb25zRXhwb3J0aW5nIiwic291cmNlSGVpZ2h0Iiwic291cmNlV2lkdGgiLCJwYXJhbSIsIl9oYW5kbGVSZXNvdXJjZXMiLCJhbGxvd2VkUHJvcHMiLCJoYW5kbGVkUmVzb3VyY2VzIiwiY29ycmVjdFJlc291cmNlcyIsInByb3BOYW1lIiwib3B0aW9uc05hbWUiLCJ0aW1lcklkcyIsImFkZFRpbWVyIiwiY2xlYXJBbGxUaW1lcnMiLCJjbGVhckludGVydmFsIiwiY2xlYXJUaW1lb3V0IiwibG9nRXJyb3JNaWRkbGV3YXJlIiwicmVxdWVzdCIsIm5leHQiLCJyZXR1cm5FcnJvck1pZGRsZXdhcmUiLCJzdGF0dXMiLCJqc29uIiwiZXJyb3JNaWRkbGV3YXJlIiwiYXBwIiwidXNlIiwicmF0ZUxpbWl0aW5nTWlkZGxld2FyZSIsInJhdGVMaW1pdGluZ09wdGlvbnMiLCJyYXRlT3B0aW9ucyIsImxpbWl0ZXIiLCJyYXRlTGltaXQiLCJ3aW5kb3dNcyIsImxpbWl0IiwiZGVsYXlNcyIsImhhbmRsZXIiLCJmb3JtYXQiLCJzZW5kIiwiZGVmYXVsdCIsInNraXAiLCJxdWVyeSIsImFjY2Vzc190b2tlbiIsImNvbnRlbnRUeXBlTWlkZGxld2FyZSIsImNvbnRlbnRUeXBlIiwiaGVhZGVycyIsInJlcXVlc3RCb2R5TWlkZGxld2FyZSIsImNvbm5lY3Rpb24iLCJyZW1vdGVBZGRyZXNzIiwidmFsaWRhdGVkT3B0aW9ucyIsImZpbGVuYW1lIiwidmFsaWRhdGlvbk1pZGRsZXdhcmUiLCJwb3N0IiwicmV2ZXJzZWRNaW1lIiwicG5nIiwianBlZyIsImdpZiIsInJlcXVlc3RFeHBvcnQiLCJyZXF1ZXN0Q291bnRlciIsImNvbm5lY3Rpb25BYm9ydGVkIiwic29ja2V0IiwiaGFkRXJyb3JzIiwiaGVhZGVyIiwiYXR0YWNobWVudCIsImV4cG9ydFJvdXRlcyIsInNlcnZlclN0YXJ0VGltZSIsInBhY2thZ2VGaWxlIiwic3VjY2Vzc1JhdGVzIiwicmVjb3JkSW50ZXJ2YWwiLCJ3aW5kb3dTaXplIiwiX2NhbGN1bGF0ZU1vdmluZ0F2ZXJhZ2UiLCJhIiwiYiIsIl9zdGFydFN1Y2Nlc3NSYXRlIiwic2V0SW50ZXJ2YWwiLCJzdGF0cyIsInN1Y2Nlc3NSYXRpbyIsImhlYWx0aFJvdXRlcyIsInBlcmlvZCIsIm1vdmluZ0F2ZXJhZ2UiLCJib290VGltZSIsInVwdGltZSIsImZsb29yIiwic2VydmVyVmVyc2lvbiIsImhpZ2hjaGFydHNWZXJzaW9uIiwiYXZlcmFnZUV4cG9ydFRpbWUiLCJhdHRlbXB0ZWRFeHBvcnRzIiwicGVyZm9ybWVkRXhwb3J0cyIsImZhaWxlZEV4cG9ydHMiLCJzdWNlc3NSYXRpbyIsInRvRml4ZWQiLCJzdmdFeHBvcnRzIiwianNvbkV4cG9ydHMiLCJzdmdFeHBvcnRzQXR0ZW1wdHMiLCJqc29uRXhwb3J0c0F0dGVtcHRzIiwidWlSb3V0ZXMiLCJzZW5kRmlsZSIsImFjY2VwdFJhbmdlcyIsInZlcnNpb25DaGFuZ2VSb3V0ZXMiLCJ0b2tlbiIsImFjdGl2ZVNlcnZlcnMiLCJNYXAiLCJleHByZXNzIiwic3RhcnRTZXJ2ZXIiLCJzZXJ2ZXJPcHRpb25zIiwidXBsb2FkTGltaXRCeXRlcyIsInN0b3JhZ2UiLCJtdWx0ZXIiLCJtZW1vcnlTdG9yYWdlIiwidXBsb2FkIiwibGltaXRzIiwiZmllbGRTaXplIiwiZGlzYWJsZSIsImNvcnMiLCJtZXRob2RzIiwic2V0IiwidXJsZW5jb2RlZCIsImV4dGVuZGVkIiwibm9uZSIsInN0YXRpYyIsImh0dHBTZXJ2ZXIiLCJjcmVhdGVTZXJ2ZXIiLCJfYXR0YWNoU2VydmVyRXJyb3JIYW5kbGVycyIsImxpc3RlbiIsImNlcnQiLCJyZWFkRmlsZSIsImh0dHBzU2VydmVyIiwiY2xvc2VTZXJ2ZXJzIiwiZGVsZXRlIiwiZ2V0U2VydmVycyIsImdldEV4cHJlc3MiLCJnZXRBcHAiLCJtaWRkbGV3YXJlcyIsInNodXRkb3duQ2xlYW5VcCIsImV4aXRDb2RlIiwiZXhpdCIsImluaXRFeHBvcnQiLCJpbml0T3B0aW9ucyIsIl9hdHRhY2hQcm9jZXNzRXhpdExpc3RlbmVycyJdLCJtYXBwaW5ncyI6InduQkEyQk8sTUFBTUEsWUFBWUMsSUFBYUEsY0FBQyxJQUFJQyxJQUFJLE9BQVEsb0JBQUFDLFNBQUFDLFFBQUEsT0FBQUMsY0FBQUMsWUFBQUMsS0FBQUMsd0JBQUEsV0FBQUEsdUJBQUFDLFFBQUFDLGVBQUFGLHVCQUFBRyxLQUFBLElBQUFULElBQUEsWUFBQUMsU0FBQVMsU0FBQUwsT0ErQmhELFNBQVNNLFNBQVNDLEdBRXZCLEdBQWUsT0FBWEEsR0FBcUMsaUJBQVhBLEVBQzVCLE9BQU9BLEVBSVQsTUFBTUMsRUFBYUMsTUFBTUMsUUFBUUgsR0FBVSxHQUFLLEdBR2hELElBQUssTUFBTUksS0FBT0osRUFDWkssT0FBT0MsVUFBVUMsZUFBZUMsS0FBS1IsRUFBUUksS0FDL0NILEVBQVdHLEdBQU9MLFNBQVNDLEVBQU9JLEtBS3RDLE9BQU9ILENBQ1QsQ0EyRE8sU0FBU1EsVUFBVUMsR0FDeEIsSUFFRSxNQUFNQyxFQUFjLEdBQUdELEVBQU9FLGNBQWNDLFFBQVEsUUFBUyxXQVE3RCxNQUxvQixVQUFoQkYsR0FDRkEsRUFBWUMsY0FJUCxDQUFDLFFBQVMsYUFBYyxXQUFZLGNBQWNFLFNBQ3ZESCxHQUVFQSxFQUNBLE9BQ1IsQ0FBSSxNQUVBLE1BQU8sT0FDUixDQUNILENBWU8sU0FBU0ksV0FBV0MsRUFBTUMsR0FPL0IsTUFBTyxHQUxVQyxnQkFBZ0JELEdBQVcsU0FDekNFLE1BQU0sS0FDTkMsV0FHbUJKLEdBQ3hCLENBYU8sU0FBU0ssUUFBUUwsRUFBTUMsRUFBVSxNQUV0QyxNQUFNSyxFQUFZLENBQ2hCLFlBQWEsTUFDYixhQUFjLE9BQ2Qsa0JBQW1CLE1BQ25CLGdCQUFpQixPQUliQyxFQUFVbEIsT0FBT21CLE9BQU9GLEdBRzlCLEdBQUlMLEVBQVMsQ0FDWCxNQUFNUSxFQUFVUixFQUFRRSxNQUFNLEtBQUtPLE1BR25CLFFBQVpELEVBQ0ZULEVBQU8sT0FDRU8s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 diff --git a/dist/index.esm.js.map b/dist/index.esm.js.map index dd3f1f3e..ce7aeed8 100644 --- a/dist/index.esm.js.map +++ b/dist/index.esm.js.map @@ -1 +1 @@ -{"version":3,"file":"index.esm.js","sources":["../lib/utils.js","../lib/logger.js","../lib/schemas/config.js","../lib/validation.js","../lib/errors/ExportError.js","../lib/config.js","../lib/fetch.js","../lib/cache.js","../lib/highcharts.js","../lib/browser.js","../templates/svgExport/css.js","../templates/svgExport/svgExport.js","../lib/export.js","../lib/pool.js","../lib/sanitize.js","../lib/chart.js","../lib/timer.js","../lib/server/middlewares/error.js","../lib/server/middlewares/rateLimiting.js","../lib/server/middlewares/validation.js","../lib/server/routes/export.js","../lib/server/routes/health.js","../lib/server/routes/ui.js","../lib/server/routes/versionChange.js","../lib/server/server.js","../lib/resourceRelease.js","../lib/index.js"],"sourcesContent":["/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * @overview The Highcharts Export Server utility module provides\r\n * a comprehensive set of helper functions and constants designed to streamline\r\n * and enhance various operations required for Highcharts export tasks.\r\n */\r\n\r\nimport { readFileSync } from 'fs';\r\nimport { isAbsolute, join } from 'path';\r\nimport { fileURLToPath } from 'url';\r\n\r\nconst MAX_BACKOFF_ATTEMPTS = 6;\r\n\r\n// The directory path\r\nexport const __dirname = fileURLToPath(new URL('../.', import.meta.url));\r\n\r\n/**\r\n * Clears and standardizes text by replacing multiple consecutive whitespace\r\n * characters with a single space and trimming any leading or trailing\r\n * whitespace.\r\n *\r\n * @function clearText\r\n *\r\n * @param {string} text - The input text to be cleared.\r\n * @param {RegExp} [rule=/\\s\\s+/g] - The regular expression rule to match\r\n * multiple consecutive whitespace characters. The default value\r\n * is the '/\\s\\s+/g' RegExp.\r\n * @param {string} [replacer=' '] - The string used to replace multiple\r\n * consecutive whitespace characters. The default value is the ' ' string.\r\n *\r\n * @returns {string} The cleared and standardized text.\r\n */\r\nexport function clearText(text, rule = /\\s\\s+/g, replacer = ' ') {\r\n return text.replaceAll(rule, replacer).trim();\r\n}\r\n\r\n/**\r\n * Creates a deep copy of the given object or array.\r\n *\r\n * @function deepCopy\r\n *\r\n * @param {(Object|Array)} objArr - The object or array to be deeply copied.\r\n *\r\n * @returns {(Object|Array)} The deep copy of the provided object or array.\r\n */\r\nexport function deepCopy(objArr) {\r\n // If the `objArr` is null or not of the `object` type, return it\r\n if (objArr === null || typeof objArr !== 'object') {\r\n return objArr;\r\n }\r\n\r\n // Prepare either a new array or a new object\r\n const objArrCopy = Array.isArray(objArr) ? [] : {};\r\n\r\n // Recursively copy each property\r\n for (const key in objArr) {\r\n if (Object.prototype.hasOwnProperty.call(objArr, key)) {\r\n objArrCopy[key] = deepCopy(objArr[key]);\r\n }\r\n }\r\n\r\n // Return the copied object\r\n return objArrCopy;\r\n}\r\n\r\n/**\r\n * Implements an exponential backoff strategy for retrying a function until\r\n * a certain number of attempts are reached.\r\n *\r\n * @async\r\n * @function expBackoff\r\n *\r\n * @param {Function} fn - The function to be retried.\r\n * @param {number} [attempt=0] - The current attempt number. The default value\r\n * is `0`.\r\n * @param {...unknown} args - Arguments to be passed to the function.\r\n *\r\n * @returns {Promise} A Promise that resolves to the result\r\n * of the function if successful.\r\n *\r\n * @throws {Error} Throws an `Error` if the maximum number of attempts\r\n * is reached.\r\n */\r\nexport async function expBackoff(fn, attempt = 0, ...args) {\r\n try {\r\n // Try to call the function\r\n return await fn(...args);\r\n } catch (error) {\r\n // Calculate delay in ms\r\n const delayInMs = 2 ** attempt * 1000;\r\n\r\n // If the attempt exceeds the maximum attempts of repeat, throw an error\r\n if (++attempt >= MAX_BACKOFF_ATTEMPTS) {\r\n throw error;\r\n }\r\n\r\n // Wait given amount of time\r\n await new Promise((response) => setTimeout(response, delayInMs));\r\n\r\n /// TO DO: Correct\r\n // // Information about the resource timeout\r\n // log(\r\n // 3,\r\n // `[utils] Waited ${delayInMs}ms until next call for the resource of ID: ${args[0]}.`\r\n // );\r\n\r\n // Try again\r\n return expBackoff(fn, attempt, ...args);\r\n }\r\n}\r\n\r\n/**\r\n * Adjusts the constructor name by transforming and normalizing it based\r\n * on common chart types.\r\n *\r\n * @function fixConstr\r\n *\r\n * @param {string} constr - The original constructor name to be fixed.\r\n *\r\n * @returns {string} The corrected constructor name, or 'chart' if the input\r\n * is not recognized.\r\n */\r\nexport function fixConstr(constr) {\r\n try {\r\n // Fix the constructor by lowering casing\r\n const fixedConstr = `${constr.toLowerCase().replace('chart', '')}Chart`;\r\n\r\n // Handle the case where the result is just 'Chart'\r\n if (fixedConstr === 'Chart') {\r\n fixedConstr.toLowerCase();\r\n }\r\n\r\n // Return the corrected constructor, otherwise default to 'chart'\r\n return ['chart', 'stockChart', 'mapChart', 'ganttChart'].includes(\r\n fixedConstr\r\n )\r\n ? fixedConstr\r\n : 'chart';\r\n } catch {\r\n // Default to 'chart' in case of any error\r\n return 'chart';\r\n }\r\n}\r\n\r\n/**\r\n * Fixes the outfile based on provided type.\r\n *\r\n * @function fixOutfile\r\n *\r\n * @param {string} type - The original export type.\r\n * @param {string} outfile - The file path or name.\r\n *\r\n * @returns {string} The corrected outfile.\r\n */\r\nexport function fixOutfile(type, outfile) {\r\n // Get the file name from the `outfile` option\r\n const fileName = getAbsolutePath(outfile || 'chart')\r\n .split('.')\r\n .shift();\r\n\r\n // Return a correct outfile\r\n return `${fileName}.${type}`;\r\n}\r\n\r\n/**\r\n * Fixes the export type based on MIME types and file extensions.\r\n *\r\n * @function fixType\r\n *\r\n * @param {string} type - The original export type.\r\n * @param {string} [outfile=null] - The file path or name. The default value\r\n * is `null`.\r\n *\r\n * @returns {string} The corrected export type.\r\n */\r\nexport function fixType(type, outfile = null) {\r\n // MIME types\r\n const mimeTypes = {\r\n 'image/png': 'png',\r\n 'image/jpeg': 'jpeg',\r\n 'application/pdf': 'pdf',\r\n 'image/svg+xml': 'svg'\r\n };\r\n\r\n // Get formats\r\n const formats = Object.values(mimeTypes);\r\n\r\n // Check if type and outfile's extensions are the same\r\n if (outfile) {\r\n const outType = outfile.split('.').pop();\r\n\r\n // Support the JPG type\r\n if (outType === 'jpg') {\r\n type = 'jpeg';\r\n } else if (formats.includes(outType) && type !== outType) {\r\n type = outType;\r\n }\r\n }\r\n\r\n // Return a correct type\r\n return mimeTypes[type] || formats.find((t) => t === type) || 'png';\r\n}\r\n\r\n/**\r\n * Checks if the given path is relative or absolute and returns the corrected,\r\n * absolute path.\r\n *\r\n * @function isAbsolutePath\r\n *\r\n * @param {string} path - The path to be checked on.\r\n *\r\n * @returns {string} The absolute path.\r\n */\r\nexport function getAbsolutePath(path) {\r\n return isAbsolute(path) ? path : join(__dirname, path);\r\n}\r\n\r\n/**\r\n * Converts input data to a Base64 string based on the export type.\r\n *\r\n * @function getBase64\r\n *\r\n * @param {string} input - The input to be transformed to Base64 format.\r\n * @param {string} type - The original export type.\r\n *\r\n * @returns {string} The Base64 string representation of the input.\r\n */\r\nexport function getBase64(input, type) {\r\n // For pdf and svg types the input must be transformed to Base64 from a buffer\r\n if (type === 'pdf' || type == 'svg') {\r\n return Buffer.from(input, 'utf8').toString('base64');\r\n }\r\n\r\n // For png and jpeg input is already a Base64 string\r\n return input;\r\n}\r\n\r\n/**\r\n * Returns stringified date without the GMT text information.\r\n *\r\n * @function getNewDate\r\n */\r\nexport function getNewDate() {\r\n // Get rid of the GMT text information\r\n return new Date().toString().split('(')[0].trim();\r\n}\r\n\r\n/**\r\n * Returns the stored time value in milliseconds.\r\n *\r\n * @function getNewDateTime\r\n */\r\nexport function getNewDateTime() {\r\n return new Date().getTime();\r\n}\r\n\r\n/**\r\n * Checks if the given item is an object.\r\n *\r\n * @function isObject\r\n *\r\n * @param {unknown} item - The item to be checked.\r\n *\r\n * @returns {boolean} True if the item is an object, false otherwise.\r\n */\r\nexport function isObject(item) {\r\n return Object.prototype.toString.call(item) === '[object Object]';\r\n}\r\n\r\n/**\r\n * Checks if the given object is empty.\r\n *\r\n * @function isObjectEmpty\r\n *\r\n * @param {Object} item - The object to be checked.\r\n *\r\n * @returns {boolean} True if the object is empty, false otherwise.\r\n */\r\nexport function isObjectEmpty(item) {\r\n return (\r\n typeof item === 'object' &&\r\n !Array.isArray(item) &&\r\n item !== null &&\r\n Object.keys(item).length === 0\r\n );\r\n}\r\n\r\n/**\r\n * Checks if a private IP range URL is found in the given string.\r\n *\r\n * @function isPrivateRangeUrlFound\r\n *\r\n * @param {string} item - The string to be checked for a private IP range URL.\r\n *\r\n * @returns {boolean} True if a private IP range URL is found, false otherwise.\r\n */\r\nexport function isPrivateRangeUrlFound(item) {\r\n const regexPatterns = [\r\n /xlink:href=\"(?:http:\\/\\/|https:\\/\\/)?localhost\\b/,\r\n /xlink:href=\"(?:http:\\/\\/|https:\\/\\/)?10\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\b/,\r\n /xlink:href=\"(?:http:\\/\\/|https:\\/\\/)?127\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\b/,\r\n /xlink:href=\"(?:http:\\/\\/|https:\\/\\/)?172\\.(1[6-9]|2[0-9]|3[0-1])\\.\\d{1,3}\\.\\d{1,3}\\b/,\r\n /xlink:href=\"(?:http:\\/\\/|https:\\/\\/)?192\\.168\\.\\d{1,3}\\.\\d{1,3}\\b/\r\n ];\r\n\r\n return regexPatterns.some((pattern) => pattern.test(item));\r\n}\r\n\r\n/**\r\n * Utility to measure elapsed time using the Node.js `process.hrtime()` method.\r\n *\r\n * @function measureTime\r\n *\r\n * @returns {Function} A function to calculate the elapsed time in milliseconds.\r\n */\r\nexport function measureTime() {\r\n const start = process.hrtime.bigint();\r\n return () => Number(process.hrtime.bigint() - start) / 1000000;\r\n}\r\n\r\n/**\r\n * Rounds a number to the specified precision.\r\n *\r\n * @function roundNumber\r\n *\r\n * @param {number} value - The number to be rounded.\r\n * @param {number} precision - The number of decimal places to round to.\r\n *\r\n * @returns {number} The rounded number.\r\n */\r\nexport function roundNumber(value, precision = 1) {\r\n const multiplier = Math.pow(10, precision || 0);\r\n return Math.round(+value * multiplier) / multiplier;\r\n}\r\n\r\n/**\r\n * Converts a value to a boolean.\r\n *\r\n * @function toBoolean\r\n *\r\n * @param {unknown} item - The value to be converted to a boolean.\r\n *\r\n * @returns {boolean} The boolean representation of the input value.\r\n */\r\nexport function toBoolean(item) {\r\n return ['false', 'undefined', 'null', 'NaN', '0', ''].includes(item)\r\n ? false\r\n : !!item;\r\n}\r\n\r\n/**\r\n * Wraps custom code to execute it safely.\r\n *\r\n * @function wrapAround\r\n *\r\n * @param {string} customCode - The custom code to be wrapped.\r\n * @param {boolean} allowFileResources - Flag to allow loading code from a file.\r\n * @param {boolean} [isCallback=false] - Flag that indicates the returned code\r\n * must be in a callback format.\r\n *\r\n * @returns {(string|null)} The wrapped custom code or null if wrapping fails.\r\n */\r\nexport function wrapAround(customCode, allowFileResources, isCallback = false) {\r\n if (customCode && typeof customCode === 'string') {\r\n customCode = customCode.trim();\r\n\r\n if (customCode.endsWith('.js')) {\r\n // Load a file if the file resources are allowed\r\n return allowFileResources\r\n ? wrapAround(\r\n readFileSync(getAbsolutePath(customCode), 'utf8'),\r\n allowFileResources,\r\n isCallback\r\n )\r\n : null;\r\n } else if (\r\n !isCallback &&\r\n (customCode.startsWith('function()') ||\r\n customCode.startsWith('function ()') ||\r\n customCode.startsWith('()=>') ||\r\n customCode.startsWith('() =>'))\r\n ) {\r\n // Treat a function as a self-invoking expression\r\n return `(${customCode})()`;\r\n }\r\n\r\n // Or return as a stringified code\r\n return customCode.replace(/;$/, '');\r\n }\r\n}\r\n\r\nexport default {\r\n __dirname,\r\n clearText,\r\n deepCopy,\r\n expBackoff,\r\n fixConstr,\r\n fixOutfile,\r\n fixType,\r\n getAbsolutePath,\r\n getBase64,\r\n getNewDate,\r\n getNewDateTime,\r\n isObject,\r\n isObjectEmpty,\r\n isPrivateRangeUrlFound,\r\n measureTime,\r\n roundNumber,\r\n toBoolean,\r\n wrapAround\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * @overview A module for managing logging functionality with customizable\r\n * log levels, console and file logging options, and error handling support.\r\n * The module also ensures that file-based logs are stored in a structured\r\n * directory, creating the necessary paths automatically if they do not exist.\r\n */\r\n\r\nimport { appendFile, existsSync, mkdirSync } from 'fs';\r\nimport { join } from 'path';\r\n\r\nimport { getAbsolutePath, getNewDate } from './utils.js';\r\n\r\n// The available colors\r\nconst colors = ['red', 'yellow', 'blue', 'gray', 'green'];\r\n\r\n// The default logging config\r\nconst logging = {\r\n // Flags for logging status\r\n toConsole: true,\r\n toFile: false,\r\n pathCreated: false,\r\n // Full path to the log file\r\n pathToLog: '',\r\n // Log levels\r\n levelsDesc: [\r\n {\r\n title: 'error',\r\n color: colors[0]\r\n },\r\n {\r\n title: 'warning',\r\n color: colors[1]\r\n },\r\n {\r\n title: 'notice',\r\n color: colors[2]\r\n },\r\n {\r\n title: 'verbose',\r\n color: colors[3]\r\n },\r\n {\r\n title: 'benchmark',\r\n color: colors[4]\r\n }\r\n ]\r\n};\r\n\r\n/**\r\n * Logs a message with a specified log level. Accepts a variable number\r\n * of arguments. The arguments after the `level` are passed to `console.log`\r\n * and/or used to construct and append messages to a log file.\r\n *\r\n * @function log\r\n *\r\n * @param {...unknown} args - An array of arguments where the first is the log\r\n * level and the remaining are strings used to build the log message.\r\n *\r\n * @returns {void} Exits the function execution if attempting to log at a level\r\n * higher than allowed.\r\n */\r\nexport function log(...args) {\r\n const [newLevel, ...texts] = args;\r\n\r\n // Current logging options\r\n const { levelsDesc, level } = logging;\r\n\r\n // Check if the log level is within a correct range or is it a benchmark log\r\n if (\r\n newLevel !== 5 &&\r\n (newLevel === 0 || newLevel > level || level > levelsDesc.length)\r\n ) {\r\n return;\r\n }\r\n\r\n // Create a message's prefix\r\n const prefix = `${getNewDate()} [${levelsDesc[newLevel - 1].title}] -`;\r\n\r\n // Log to file\r\n if (logging.toFile) {\r\n _logToFile(texts, prefix);\r\n }\r\n\r\n // Log to console\r\n if (logging.toConsole) {\r\n console.log.apply(\r\n undefined,\r\n [prefix.toString()[logging.levelsDesc[newLevel - 1].color]].concat(texts)\r\n );\r\n }\r\n}\r\n\r\n/**\r\n * Logs an error message along with its stack trace. Optionally, a custom message\r\n * can be provided.\r\n *\r\n * @function logWithStack\r\n *\r\n * @param {number} newLevel - The log level.\r\n * @param {Error} error - The error object containing the stack trace.\r\n * @param {string} customMessage - An optional custom message to be included\r\n * in the log alongside the error.\r\n *\r\n * @returns {void} Exits the function execution if attempting to log at a level\r\n * higher than allowed.\r\n */\r\nexport function logWithStack(newLevel, error, customMessage) {\r\n // Get the main message\r\n const mainMessage = customMessage || (error && error.message) || '';\r\n\r\n // Current logging options\r\n const { level, levelsDesc } = logging;\r\n\r\n // Check if the log level is within a correct range\r\n if (newLevel === 0 || newLevel > level || level > levelsDesc.length) {\r\n return;\r\n }\r\n\r\n // Create a message's prefix\r\n const prefix = `${getNewDate()} [${levelsDesc[newLevel - 1].title}] -`;\r\n\r\n // Add the whole stack message\r\n const stackMessage = error && error.stack;\r\n\r\n // Combine custom message or error message with error stack message, if exists\r\n const texts = [mainMessage];\r\n if (stackMessage) {\r\n texts.push('\\n', stackMessage);\r\n }\r\n\r\n // Log to file\r\n if (logging.toFile) {\r\n _logToFile(texts, prefix);\r\n }\r\n\r\n // Log to console\r\n if (logging.toConsole) {\r\n console.log.apply(\r\n undefined,\r\n [prefix.toString()[logging.levelsDesc[newLevel - 1].color]].concat([\r\n texts.shift()[colors[newLevel - 1]],\r\n ...texts\r\n ])\r\n );\r\n }\r\n}\r\n\r\n/**\r\n * Logs an error message related to Zod validation issues. Optionally, a custom\r\n * message can be provided.\r\n *\r\n * @function logZodIssues\r\n *\r\n * @param {number} newLevel - The log level.\r\n * @param {Error[]} issues - An array of Zod validation issues.\r\n * @param {string} customMessage - An optional custom message to be included\r\n * in the log alongside the error.\r\n */\r\nexport function logZodIssues(newLevel, issues, customMessage) {\r\n logWithStack(\r\n newLevel,\r\n null,\r\n [\r\n `${customMessage || '[validation] Validation error'} - the following Zod issues occured:`,\r\n ...(issues || []).map((issue) => `- ${issue.message}`)\r\n ].join('\\n')\r\n );\r\n}\r\n\r\n/**\r\n * Initializes logging with the specified logging configuration.\r\n *\r\n * @function initLogging\r\n *\r\n * @param {Object} loggingOptions - The configuration object containing\r\n * `logging` options.\r\n */\r\nexport function initLogging(loggingOptions) {\r\n // Get options from the `loggingOptions` object\r\n const { level, dest, file, toConsole, toFile } = loggingOptions;\r\n\r\n // Reset flags to the default values\r\n logging.pathCreated = false;\r\n logging.pathToLog = '';\r\n\r\n // Set the logging level\r\n setLogLevel(level);\r\n\r\n // Set the console logging\r\n enableConsoleLogging(toConsole);\r\n\r\n // Set the file logging\r\n enableFileLogging(dest, file, toFile);\r\n}\r\n\r\n/**\r\n * Sets the log level to the specified value. Log levels are (`0` = no logging,\r\n * `1` = error, `2` = warning, `3` = notice, `4` = verbose, or `5` = benchmark).\r\n *\r\n * @function setLogLevel\r\n *\r\n * @param {number} level - The log level to be set.\r\n */\r\nexport function setLogLevel(level) {\r\n if (\r\n Number.isInteger(level) &&\r\n level >= 0 &&\r\n level <= logging.levelsDesc.length\r\n ) {\r\n // Update the module logging's `level` option\r\n logging.level = level;\r\n }\r\n}\r\n\r\n/**\r\n * Enables console logging.\r\n *\r\n * @function enableConsoleLogging\r\n *\r\n * @param {boolean} toConsole - The flag for setting the logging to the console.\r\n */\r\nexport function enableConsoleLogging(toConsole) {\r\n // Update the module logging's `toConsole` option\r\n logging.toConsole = !!toConsole;\r\n}\r\n\r\n/**\r\n * Enables file logging with the specified destination and log file name.\r\n *\r\n * @function enableFileLogging\r\n *\r\n * @param {string} dest - The destination path where the log file should\r\n * be saved.\r\n * @param {string} file - The name of the log file.\r\n * @param {boolean} toFile - A flag indicating whether logging should\r\n * be directed to a file.\r\n */\r\nexport function enableFileLogging(dest, file, toFile) {\r\n // Update the module logging's `toFile` option\r\n logging.toFile = !!toFile;\r\n\r\n // Set the `dest` and `file` options only if the file logging is enabled\r\n if (logging.toFile) {\r\n logging.dest = dest || '';\r\n logging.file = file || '';\r\n }\r\n}\r\n\r\n/**\r\n * Logs the provided texts to a file, if file logging is enabled. It creates\r\n * the necessary directory structure if not already created and appends\r\n * the content, including an optional prefix, to the specified log file.\r\n *\r\n * @function _logToFile\r\n *\r\n * @param {Array.} texts - An array of texts to be logged.\r\n * @param {string} prefix - An optional prefix to be added to each log entry.\r\n */\r\nfunction _logToFile(texts, prefix) {\r\n if (!logging.pathCreated) {\r\n // Create if does not exist\r\n !existsSync(getAbsolutePath(logging.dest)) &&\r\n mkdirSync(getAbsolutePath(logging.dest));\r\n\r\n // Create the full path\r\n logging.pathToLog = getAbsolutePath(join(logging.dest, logging.file));\r\n\r\n // We now assume the path is available, e.g. it's the responsibility\r\n // of the user to create the path with the correct access rights.\r\n logging.pathCreated = true;\r\n }\r\n\r\n // Add the content to a file\r\n appendFile(\r\n logging.pathToLog,\r\n [prefix].concat(texts).join(' ') + '\\n',\r\n (error) => {\r\n if (error && logging.toFile && logging.pathCreated) {\r\n logging.toFile = false;\r\n logging.pathCreated = false;\r\n logWithStack(2, error, `[logger] Unable to write to log file.`);\r\n }\r\n }\r\n );\r\n}\r\n\r\nexport default {\r\n log,\r\n logWithStack,\r\n logZodIssues,\r\n initLogging,\r\n setLogLevel,\r\n enableConsoleLogging,\r\n enableFileLogging\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * @overview Configuration management module for the Highcharts Export Server.\r\n * Provides default configurations that support environment variables, CLI\r\n * arguments, and interactive prompts for customization of options and features.\r\n * Additionally, it maps legacy options to modern structures, generates nested\r\n * argument mappings, and displays CLI usage information.\r\n */\r\n\r\n/**\r\n * The configuration object containing all available options, organized\r\n * by sections.\r\n *\r\n * This object includes:\r\n * - Default values for each option\r\n * - Data types for validation\r\n * - Names of corresponding environment variables\r\n * - Descriptions of each property\r\n * - Information used for prompts in interactive configuration\r\n * - [Optional] Corresponding CLI argument names for CLI usage\r\n * - [Optional] Legacy names from the previous PhantomJS-based server\r\n */\r\nexport const defaultConfig = {\r\n puppeteer: {\r\n args: {\r\n value: [\r\n '--allow-running-insecure-content',\r\n '--ash-no-nudges',\r\n '--autoplay-policy=user-gesture-required',\r\n '--block-new-web-contents',\r\n '--disable-accelerated-2d-canvas',\r\n '--disable-background-networking',\r\n '--disable-background-timer-throttling',\r\n '--disable-backgrounding-occluded-windows',\r\n '--disable-breakpad',\r\n '--disable-checker-imaging',\r\n '--disable-client-side-phishing-detection',\r\n '--disable-component-extensions-with-background-pages',\r\n '--disable-component-update',\r\n '--disable-default-apps',\r\n '--disable-dev-shm-usage',\r\n '--disable-domain-reliability',\r\n '--disable-extensions',\r\n '--disable-features=CalculateNativeWinOcclusion,InterestFeedContentSuggestions,WebOTP',\r\n '--disable-hang-monitor',\r\n '--disable-ipc-flooding-protection',\r\n '--disable-logging',\r\n '--disable-notifications',\r\n '--disable-offer-store-unmasked-wallet-cards',\r\n '--disable-popup-blocking',\r\n '--disable-print-preview',\r\n '--disable-prompt-on-repost',\r\n '--disable-renderer-backgrounding',\r\n '--disable-search-engine-choice-screen',\r\n '--disable-session-crashed-bubble',\r\n '--disable-setuid-sandbox',\r\n '--disable-site-isolation-trials',\r\n '--disable-speech-api',\r\n '--disable-sync',\r\n '--enable-unsafe-webgpu',\r\n '--hide-crash-restore-bubble',\r\n '--hide-scrollbars',\r\n '--metrics-recording-only',\r\n '--mute-audio',\r\n '--no-default-browser-check',\r\n '--no-first-run',\r\n '--no-pings',\r\n '--no-sandbox',\r\n '--no-startup-window',\r\n '--no-zygote',\r\n '--password-store=basic',\r\n '--process-per-tab',\r\n '--use-mock-keychain'\r\n ],\r\n types: ['string[]'],\r\n envLink: 'PUPPETEER_ARGS',\r\n cliName: 'puppeteerArgs',\r\n description: 'Array of Puppeteer arguments',\r\n promptOptions: {\r\n type: 'list',\r\n separator: ';'\r\n }\r\n }\r\n },\r\n highcharts: {\r\n version: {\r\n value: 'latest',\r\n types: ['string'],\r\n envLink: 'HIGHCHARTS_VERSION',\r\n description: 'Highcharts version',\r\n promptOptions: {\r\n type: 'text'\r\n }\r\n },\r\n cdnUrl: {\r\n value: 'https://code.highcharts.com',\r\n types: ['string'],\r\n envLink: 'HIGHCHARTS_CDN_URL',\r\n description: 'CDN URL for Highcharts scripts',\r\n promptOptions: {\r\n type: 'text'\r\n }\r\n },\r\n forceFetch: {\r\n value: false,\r\n types: ['boolean'],\r\n envLink: 'HIGHCHARTS_FORCE_FETCH',\r\n description: 'Flag to refetch scripts after each server rerun',\r\n promptOptions: {\r\n type: 'toggle'\r\n }\r\n },\r\n cachePath: {\r\n value: '.cache',\r\n types: ['string'],\r\n envLink: 'HIGHCHARTS_CACHE_PATH',\r\n description: 'Directory path for cached Highcharts scripts',\r\n promptOptions: {\r\n type: 'text'\r\n }\r\n },\r\n coreScripts: {\r\n value: ['highcharts', 'highcharts-more', 'highcharts-3d'],\r\n types: ['string[]'],\r\n envLink: 'HIGHCHARTS_CORE_SCRIPTS',\r\n description: 'Highcharts core scripts to fetch',\r\n promptOptions: {\r\n type: 'multiselect',\r\n instructions: 'Space: Select specific, A: Select all, Enter: Confirm'\r\n }\r\n },\r\n moduleScripts: {\r\n value: [\r\n 'stock',\r\n 'map',\r\n 'gantt',\r\n 'exporting',\r\n 'parallel-coordinates',\r\n 'accessibility',\r\n // 'annotations-advanced',\r\n 'boost-canvas',\r\n 'boost',\r\n 'data',\r\n 'data-tools',\r\n 'draggable-points',\r\n 'static-scale',\r\n 'broken-axis',\r\n 'heatmap',\r\n 'tilemap',\r\n 'tiledwebmap',\r\n 'timeline',\r\n 'treemap',\r\n 'treegraph',\r\n 'item-series',\r\n 'drilldown',\r\n 'histogram-bellcurve',\r\n 'bullet',\r\n 'funnel',\r\n 'funnel3d',\r\n 'geoheatmap',\r\n 'pyramid3d',\r\n 'networkgraph',\r\n 'overlapping-datalabels',\r\n 'pareto',\r\n 'pattern-fill',\r\n 'pictorial',\r\n 'price-indicator',\r\n 'sankey',\r\n 'arc-diagram',\r\n 'dependency-wheel',\r\n 'series-label',\r\n 'series-on-point',\r\n 'solid-gauge',\r\n 'sonification',\r\n // 'stock-tools',\r\n 'streamgraph',\r\n 'sunburst',\r\n 'variable-pie',\r\n 'variwide',\r\n 'vector',\r\n 'venn',\r\n 'windbarb',\r\n 'wordcloud',\r\n 'xrange',\r\n 'no-data-to-display',\r\n 'drag-panes',\r\n 'debugger',\r\n 'dumbbell',\r\n 'lollipop',\r\n 'cylinder',\r\n 'organization',\r\n 'dotplot',\r\n 'marker-clusters',\r\n 'hollowcandlestick',\r\n 'heikinashi',\r\n 'flowmap',\r\n 'export-data',\r\n 'navigator',\r\n 'textpath'\r\n ],\r\n types: ['string[]'],\r\n envLink: 'HIGHCHARTS_MODULE_SCRIPTS',\r\n description: 'Highcharts module scripts to fetch',\r\n promptOptions: {\r\n type: 'multiselect',\r\n instructions: 'Space: Select specific, A: Select all, Enter: Confirm'\r\n }\r\n },\r\n indicatorScripts: {\r\n value: ['indicators-all'],\r\n types: ['string[]'],\r\n envLink: 'HIGHCHARTS_INDICATOR_SCRIPTS',\r\n description: 'Highcharts indicator scripts to fetch',\r\n promptOptions: {\r\n type: 'multiselect',\r\n instructions: 'Space: Select specific, A: Select all, Enter: Confirm'\r\n }\r\n },\r\n customScripts: {\r\n value: [\r\n 'https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.30.1/moment.min.js',\r\n 'https://cdnjs.cloudflare.com/ajax/libs/moment-timezone/0.5.45/moment-timezone-with-data.min.js'\r\n ],\r\n types: ['string[]'],\r\n envLink: 'HIGHCHARTS_CUSTOM_SCRIPTS',\r\n description: 'Additional custom scripts or dependencies to fetch',\r\n promptOptions: {\r\n type: 'list',\r\n separator: ';'\r\n }\r\n }\r\n },\r\n export: {\r\n infile: {\r\n value: null,\r\n types: ['string', 'null'],\r\n envLink: 'EXPORT_INFILE',\r\n description:\r\n 'Input filename with type, formatted correctly as JSON or SVG',\r\n promptOptions: {\r\n type: 'text'\r\n }\r\n },\r\n instr: {\r\n value: null,\r\n types: ['Object', 'string', 'null'],\r\n envLink: 'EXPORT_INSTR',\r\n description:\r\n 'Overrides the `infile` with JSON, stringified JSON, or SVG input',\r\n promptOptions: {\r\n type: 'text'\r\n }\r\n },\r\n options: {\r\n value: null,\r\n types: ['Object', 'string', 'null'],\r\n envLink: 'EXPORT_OPTIONS',\r\n description: 'Alias for the `instr` option',\r\n promptOptions: {\r\n type: 'text'\r\n }\r\n },\r\n svg: {\r\n value: null,\r\n types: ['string', 'null'],\r\n envLink: 'EXPORT_SVG',\r\n description: 'SVG string representation of the chart to render',\r\n promptOptions: {\r\n type: 'text'\r\n }\r\n },\r\n batch: {\r\n value: null,\r\n types: ['string', 'null'],\r\n envLink: 'EXPORT_BATCH',\r\n description:\r\n 'Batch job string with input/output pairs: \"in=out;in=out;...\"',\r\n promptOptions: {\r\n type: 'text'\r\n }\r\n },\r\n outfile: {\r\n value: null,\r\n types: ['string', 'null'],\r\n envLink: 'EXPORT_OUTFILE',\r\n description:\r\n 'Output filename with type. Can be jpeg, png, pdf, or svg and ignores `type` option',\r\n promptOptions: {\r\n type: 'text'\r\n }\r\n },\r\n type: {\r\n value: 'png',\r\n types: ['string'],\r\n envLink: 'EXPORT_TYPE',\r\n description: 'File export format. Can be jpeg, png, pdf, or svg',\r\n promptOptions: {\r\n type: 'select',\r\n hint: 'Default: png',\r\n choices: ['png', 'jpeg', 'pdf', 'svg']\r\n }\r\n },\r\n constr: {\r\n value: 'chart',\r\n types: ['string'],\r\n envLink: 'EXPORT_CONSTR',\r\n description:\r\n 'Chart constructor. Can be chart, stockChart, mapChart, or ganttChart',\r\n promptOptions: {\r\n type: 'select',\r\n hint: 'Default: chart',\r\n choices: ['chart', 'stockChart', 'mapChart', 'ganttChart']\r\n }\r\n },\r\n b64: {\r\n value: false,\r\n types: ['boolean'],\r\n envLink: 'EXPORT_B64',\r\n description:\r\n 'Whether or not to the chart should be received in Base64 format instead of binary',\r\n promptOptions: {\r\n type: 'toggle'\r\n }\r\n },\r\n noDownload: {\r\n value: false,\r\n types: ['boolean'],\r\n envLink: 'EXPORT_NO_DOWNLOAD',\r\n description:\r\n 'Whether or not to include or exclude attachment headers in the response',\r\n promptOptions: {\r\n type: 'toggle'\r\n }\r\n },\r\n height: {\r\n value: null,\r\n types: ['number', 'null'],\r\n envLink: 'EXPORT_HEIGHT',\r\n description: 'Height of the exported chart, overrides chart settings',\r\n promptOptions: {\r\n type: 'number'\r\n }\r\n },\r\n width: {\r\n value: null,\r\n types: ['number', 'null'],\r\n envLink: 'EXPORT_WIDTH',\r\n description: 'Width of the exported chart, overrides chart settings',\r\n promptOptions: {\r\n type: 'number'\r\n }\r\n },\r\n scale: {\r\n value: null,\r\n types: ['number', 'null'],\r\n envLink: 'EXPORT_SCALE',\r\n description:\r\n 'Scale of the exported chart, overrides chart settings. Ranges from 0.1 to 5.0',\r\n promptOptions: {\r\n type: 'number'\r\n }\r\n },\r\n defaultHeight: {\r\n value: 400,\r\n types: ['number'],\r\n envLink: 'EXPORT_DEFAULT_HEIGHT',\r\n description: 'Default height of the exported chart if not set',\r\n promptOptions: {\r\n type: 'number'\r\n }\r\n },\r\n defaultWidth: {\r\n value: 600,\r\n types: ['number'],\r\n envLink: 'EXPORT_DEFAULT_WIDTH',\r\n description: 'Default width of the exported chart if not set',\r\n promptOptions: {\r\n type: 'number'\r\n }\r\n },\r\n defaultScale: {\r\n value: 1,\r\n types: ['number'],\r\n envLink: 'EXPORT_DEFAULT_SCALE',\r\n description:\r\n 'Default scale of the exported chart if not set. Ranges from 0.1 to 5.0',\r\n promptOptions: {\r\n type: 'number',\r\n min: 0.1,\r\n max: 5\r\n }\r\n },\r\n globalOptions: {\r\n value: null,\r\n types: ['Object', 'string', 'null'],\r\n envLink: 'EXPORT_GLOBAL_OPTIONS',\r\n description:\r\n 'JSON, stringified JSON or filename with global options for Highcharts.setOptions',\r\n promptOptions: {\r\n type: 'text'\r\n }\r\n },\r\n themeOptions: {\r\n value: null,\r\n types: ['Object', 'string', 'null'],\r\n envLink: 'EXPORT_THEME_OPTIONS',\r\n description:\r\n 'JSON, stringified JSON or filename with theme options for Highcharts.setOptions',\r\n promptOptions: {\r\n type: 'text'\r\n }\r\n },\r\n rasterizationTimeout: {\r\n value: 1500,\r\n types: ['number'],\r\n envLink: 'EXPORT_RASTERIZATION_TIMEOUT',\r\n description: 'Milliseconds to wait for webpage rendering',\r\n promptOptions: {\r\n type: 'number'\r\n }\r\n }\r\n },\r\n customLogic: {\r\n allowCodeExecution: {\r\n value: false,\r\n types: ['boolean'],\r\n envLink: 'CUSTOM_LOGIC_ALLOW_CODE_EXECUTION',\r\n description:\r\n 'Allows or disallows execution of arbitrary code during exporting',\r\n promptOptions: {\r\n type: 'toggle'\r\n }\r\n },\r\n allowFileResources: {\r\n value: false,\r\n types: ['boolean'],\r\n envLink: 'CUSTOM_LOGIC_ALLOW_FILE_RESOURCES',\r\n description:\r\n 'Allows or disallows injection of filesystem resources (disabled in server mode)',\r\n promptOptions: {\r\n type: 'toggle'\r\n }\r\n },\r\n customCode: {\r\n value: null,\r\n types: ['string', 'null'],\r\n envLink: 'CUSTOM_LOGIC_CUSTOM_CODE',\r\n description:\r\n 'Custom code to execute before chart initialization. Can be a function, code wrapped in a function, or a .js filename',\r\n promptOptions: {\r\n type: 'text'\r\n }\r\n },\r\n callback: {\r\n value: null,\r\n types: ['string', 'null'],\r\n envLink: 'CUSTOM_LOGIC_CALLBACK',\r\n description:\r\n 'JavaScript code to run during construction. Can be a function or a .js filename',\r\n promptOptions: {\r\n type: 'text'\r\n }\r\n },\r\n resources: {\r\n value: null,\r\n types: ['Object', 'string', 'null'],\r\n envLink: 'CUSTOM_LOGIC_RESOURCES',\r\n description:\r\n 'Additional resources as JSON, stringified JSON, or filename, containing files, js, and css sections',\r\n promptOptions: {\r\n type: 'text'\r\n }\r\n },\r\n loadConfig: {\r\n value: null,\r\n types: ['string', 'null'],\r\n envLink: 'CUSTOM_LOGIC_LOAD_CONFIG',\r\n legacyName: 'fromFile',\r\n description: 'File with a pre-defined configuration to use',\r\n promptOptions: {\r\n type: 'text'\r\n }\r\n },\r\n createConfig: {\r\n value: null,\r\n types: ['string', 'null'],\r\n envLink: 'CUSTOM_LOGIC_CREATE_CONFIG',\r\n description:\r\n 'Prompt-based option setting, saved to a provided config file',\r\n promptOptions: {\r\n type: 'text'\r\n }\r\n }\r\n },\r\n server: {\r\n enable: {\r\n value: false,\r\n types: ['boolean'],\r\n envLink: 'SERVER_ENABLE',\r\n cliName: 'enableServer',\r\n description: 'Starts the server when true',\r\n promptOptions: {\r\n type: 'toggle'\r\n }\r\n },\r\n host: {\r\n value: '0.0.0.0',\r\n types: ['string'],\r\n envLink: 'SERVER_HOST',\r\n description: 'Hostname of the server',\r\n promptOptions: {\r\n type: 'text'\r\n }\r\n },\r\n port: {\r\n value: 7801,\r\n types: ['number'],\r\n envLink: 'SERVER_PORT',\r\n description: 'Port number for the server',\r\n promptOptions: {\r\n type: 'number'\r\n }\r\n },\r\n uploadLimit: {\r\n value: 3,\r\n types: ['number'],\r\n envLink: 'SERVER_UPLOAD_LIMIT',\r\n description: 'Maximum request body size in MB',\r\n promptOptions: {\r\n type: 'number'\r\n }\r\n },\r\n benchmarking: {\r\n value: false,\r\n types: ['boolean'],\r\n envLink: 'SERVER_BENCHMARKING',\r\n cliName: 'serverBenchmarking',\r\n description:\r\n 'Displays or not action durations in milliseconds during server requests',\r\n promptOptions: {\r\n type: 'toggle'\r\n }\r\n },\r\n proxy: {\r\n host: {\r\n value: null,\r\n types: ['string', 'null'],\r\n envLink: 'SERVER_PROXY_HOST',\r\n cliName: 'proxyHost',\r\n description: 'Host of the proxy server, if applicable',\r\n promptOptions: {\r\n type: 'text'\r\n }\r\n },\r\n port: {\r\n value: null,\r\n types: ['number', 'null'],\r\n envLink: 'SERVER_PROXY_PORT',\r\n cliName: 'proxyPort',\r\n description: 'Port of the proxy server, if applicable',\r\n promptOptions: {\r\n type: 'number'\r\n }\r\n },\r\n timeout: {\r\n value: 5000,\r\n types: ['number'],\r\n envLink: 'SERVER_PROXY_TIMEOUT',\r\n cliName: 'proxyTimeout',\r\n description:\r\n 'Timeout in milliseconds for the proxy server, if applicable',\r\n promptOptions: {\r\n type: 'number'\r\n }\r\n }\r\n },\r\n rateLimiting: {\r\n enable: {\r\n value: false,\r\n types: ['boolean'],\r\n envLink: 'SERVER_RATE_LIMITING_ENABLE',\r\n cliName: 'enableRateLimiting',\r\n description: 'Enables or disables rate limiting on the server',\r\n promptOptions: {\r\n type: 'toggle'\r\n }\r\n },\r\n maxRequests: {\r\n value: 10,\r\n types: ['number'],\r\n envLink: 'SERVER_RATE_LIMITING_MAX_REQUESTS',\r\n legacyName: 'rateLimit',\r\n description: 'Maximum number of requests allowed per minute',\r\n promptOptions: {\r\n type: 'number'\r\n }\r\n },\r\n window: {\r\n value: 1,\r\n types: ['number'],\r\n envLink: 'SERVER_RATE_LIMITING_WINDOW',\r\n description: 'Time window in minutes for rate limiting',\r\n promptOptions: {\r\n type: 'number'\r\n }\r\n },\r\n delay: {\r\n value: 0,\r\n types: ['number'],\r\n envLink: 'SERVER_RATE_LIMITING_DELAY',\r\n description:\r\n 'Delay duration between successive requests before reaching the limit',\r\n promptOptions: {\r\n type: 'number'\r\n }\r\n },\r\n trustProxy: {\r\n value: false,\r\n types: ['boolean'],\r\n envLink: 'SERVER_RATE_LIMITING_TRUST_PROXY',\r\n description: 'Set to true if the server is behind a load balancer',\r\n promptOptions: {\r\n type: 'toggle'\r\n }\r\n },\r\n skipKey: {\r\n value: null,\r\n types: ['string', 'null'],\r\n envLink: 'SERVER_RATE_LIMITING_SKIP_KEY',\r\n description: 'Key to bypass the rate limiter, used with `skipToken`',\r\n promptOptions: {\r\n type: 'text'\r\n }\r\n },\r\n skipToken: {\r\n value: null,\r\n types: ['string', 'null'],\r\n envLink: 'SERVER_RATE_LIMITING_SKIP_TOKEN',\r\n description: 'Token to bypass the rate limiter, used with `skipKey`',\r\n promptOptions: {\r\n type: 'text'\r\n }\r\n }\r\n },\r\n ssl: {\r\n enable: {\r\n value: false,\r\n types: ['boolean'],\r\n envLink: 'SERVER_SSL_ENABLE',\r\n cliName: 'enableSsl',\r\n description: 'Enables or disables SSL protocol',\r\n promptOptions: {\r\n type: 'toggle'\r\n }\r\n },\r\n force: {\r\n value: false,\r\n types: ['boolean'],\r\n envLink: 'SERVER_SSL_FORCE',\r\n cliName: 'sslForce',\r\n legacyName: 'sslOnly',\r\n description: 'Forces the server to use HTTPS only when true',\r\n promptOptions: {\r\n type: 'toggle'\r\n }\r\n },\r\n port: {\r\n value: 443,\r\n types: ['number'],\r\n envLink: 'SERVER_SSL_PORT',\r\n cliName: 'sslPort',\r\n description: 'Port for the SSL server',\r\n promptOptions: {\r\n type: 'number'\r\n }\r\n },\r\n certPath: {\r\n value: null,\r\n types: ['string', 'null'],\r\n envLink: 'SERVER_SSL_CERT_PATH',\r\n cliName: 'sslCertPath',\r\n legacyName: 'sslPath',\r\n description: 'Path to the SSL certificate/key file',\r\n promptOptions: {\r\n type: 'text'\r\n }\r\n }\r\n }\r\n },\r\n pool: {\r\n minWorkers: {\r\n value: 4,\r\n types: ['number'],\r\n envLink: 'POOL_MIN_WORKERS',\r\n description: 'Minimum and initial number of pool workers to spawn',\r\n promptOptions: {\r\n type: 'number'\r\n }\r\n },\r\n maxWorkers: {\r\n value: 8,\r\n types: ['number'],\r\n envLink: 'POOL_MAX_WORKERS',\r\n legacyName: 'workers',\r\n description: 'Maximum number of pool workers to spawn',\r\n promptOptions: {\r\n type: 'number'\r\n }\r\n },\r\n workLimit: {\r\n value: 40,\r\n types: ['number'],\r\n envLink: 'POOL_WORK_LIMIT',\r\n description: 'Number of tasks a worker can handle before restarting',\r\n promptOptions: {\r\n type: 'number'\r\n }\r\n },\r\n acquireTimeout: {\r\n value: 5000,\r\n types: ['number'],\r\n envLink: 'POOL_ACQUIRE_TIMEOUT',\r\n description: 'Timeout in milliseconds for acquiring a resource',\r\n promptOptions: {\r\n type: 'number'\r\n }\r\n },\r\n createTimeout: {\r\n value: 5000,\r\n types: ['number'],\r\n envLink: 'POOL_CREATE_TIMEOUT',\r\n description: 'Timeout in milliseconds for creating a resource',\r\n promptOptions: {\r\n type: 'number'\r\n }\r\n },\r\n destroyTimeout: {\r\n value: 5000,\r\n types: ['number'],\r\n envLink: 'POOL_DESTROY_TIMEOUT',\r\n description: 'Timeout in milliseconds for destroying a resource',\r\n promptOptions: {\r\n type: 'number'\r\n }\r\n },\r\n idleTimeout: {\r\n value: 30000,\r\n types: ['number'],\r\n envLink: 'POOL_IDLE_TIMEOUT',\r\n description: 'Timeout in milliseconds for destroying idle resources',\r\n promptOptions: {\r\n type: 'number'\r\n }\r\n },\r\n createRetryInterval: {\r\n value: 200,\r\n types: ['number'],\r\n envLink: 'POOL_CREATE_RETRY_INTERVAL',\r\n description:\r\n 'Interval in milliseconds before retrying resource creation on failure',\r\n promptOptions: {\r\n type: 'number'\r\n }\r\n },\r\n reaperInterval: {\r\n value: 1000,\r\n types: ['number'],\r\n envLink: 'POOL_REAPER_INTERVAL',\r\n description:\r\n 'Interval in milliseconds to check and destroy idle resources',\r\n promptOptions: {\r\n type: 'number'\r\n }\r\n },\r\n benchmarking: {\r\n value: false,\r\n types: ['boolean'],\r\n envLink: 'POOL_BENCHMARKING',\r\n cliName: 'poolBenchmarking',\r\n description: 'Shows statistics for the pool of resources',\r\n promptOptions: {\r\n type: 'toggle'\r\n }\r\n }\r\n },\r\n logging: {\r\n level: {\r\n value: 4,\r\n types: ['number'],\r\n envLink: 'LOGGING_LEVEL',\r\n cliName: 'logLevel',\r\n description: 'Logging verbosity level',\r\n promptOptions: {\r\n type: 'number',\r\n round: 0,\r\n min: 0,\r\n max: 5\r\n }\r\n },\r\n file: {\r\n value: 'highcharts-export-server.log',\r\n types: ['string'],\r\n envLink: 'LOGGING_FILE',\r\n cliName: 'logFile',\r\n description:\r\n 'Log file name. Requires `logToFile` and `logDest` to be set',\r\n promptOptions: {\r\n type: 'text'\r\n }\r\n },\r\n dest: {\r\n value: 'log',\r\n types: ['string'],\r\n envLink: 'LOGGING_DEST',\r\n cliName: 'logDest',\r\n description: 'Path to store log files. Requires `logToFile` to be set',\r\n promptOptions: {\r\n type: 'text'\r\n }\r\n },\r\n toConsole: {\r\n value: true,\r\n types: ['boolean'],\r\n envLink: 'LOGGING_TO_CONSOLE',\r\n cliName: 'logToConsole',\r\n description: 'Enables or disables console logging',\r\n promptOptions: {\r\n type: 'toggle'\r\n }\r\n },\r\n toFile: {\r\n value: true,\r\n types: ['boolean'],\r\n envLink: 'LOGGING_TO_FILE',\r\n cliName: 'logToFile',\r\n description: 'Enables or disables logging to a file',\r\n promptOptions: {\r\n type: 'toggle'\r\n }\r\n }\r\n },\r\n ui: {\r\n enable: {\r\n value: false,\r\n types: ['boolean'],\r\n envLink: 'UI_ENABLE',\r\n cliName: 'enableUi',\r\n description: 'Enables or disables the UI for the export server',\r\n promptOptions: {\r\n type: 'toggle'\r\n }\r\n },\r\n route: {\r\n value: '/',\r\n types: ['string'],\r\n envLink: 'UI_ROUTE',\r\n cliName: 'uiRoute',\r\n description: 'The endpoint route for the UI',\r\n promptOptions: {\r\n type: 'text'\r\n }\r\n }\r\n },\r\n other: {\r\n nodeEnv: {\r\n value: 'production',\r\n types: ['string'],\r\n envLink: 'OTHER_NODE_ENV',\r\n description: 'The Node.js environment type',\r\n promptOptions: {\r\n type: 'text'\r\n }\r\n },\r\n listenToProcessExits: {\r\n value: true,\r\n types: ['boolean'],\r\n envLink: 'OTHER_LISTEN_TO_PROCESS_EXITS',\r\n description: 'Whether or not to attach process.exit handlers',\r\n promptOptions: {\r\n type: 'toggle'\r\n }\r\n },\r\n noLogo: {\r\n value: false,\r\n types: ['boolean'],\r\n envLink: 'OTHER_NO_LOGO',\r\n description: 'Display or skip printing the logo on startup',\r\n promptOptions: {\r\n type: 'toggle'\r\n }\r\n },\r\n hardResetPage: {\r\n value: false,\r\n types: ['boolean'],\r\n envLink: 'OTHER_HARD_RESET_PAGE',\r\n description: 'Whether or not to reset the page content entirely',\r\n promptOptions: {\r\n type: 'toggle'\r\n }\r\n },\r\n browserShellMode: {\r\n value: true,\r\n types: ['boolean'],\r\n envLink: 'OTHER_BROWSER_SHELL_MODE',\r\n description: 'Whether or not to set the browser to run in shell mode',\r\n promptOptions: {\r\n type: 'toggle'\r\n }\r\n },\r\n validation: {\r\n value: true,\r\n types: ['boolean'],\r\n envLink: 'OTHER_VALIDATION',\r\n description: 'Whether or not to enable validation of options types',\r\n promptOptions: {\r\n type: 'toggle'\r\n }\r\n }\r\n },\r\n debug: {\r\n enable: {\r\n value: false,\r\n types: ['boolean'],\r\n envLink: 'DEBUG_ENABLE',\r\n cliName: 'enableDebug',\r\n description: 'Enables or disables debug mode for the underlying browser',\r\n promptOptions: {\r\n type: 'toggle'\r\n }\r\n },\r\n headless: {\r\n value: false,\r\n types: ['boolean'],\r\n envLink: 'DEBUG_HEADLESS',\r\n description:\r\n 'Whether or not to set the browser to run in headless mode during debugging',\r\n promptOptions: {\r\n type: 'toggle'\r\n }\r\n },\r\n devtools: {\r\n value: false,\r\n types: ['boolean'],\r\n envLink: 'DEBUG_DEVTOOLS',\r\n description: 'Enables or disables DevTools in headful mode',\r\n promptOptions: {\r\n type: 'toggle'\r\n }\r\n },\r\n listenToConsole: {\r\n value: false,\r\n types: ['boolean'],\r\n envLink: 'DEBUG_LISTEN_TO_CONSOLE',\r\n description:\r\n 'Enables or disables listening to console messages from the browser',\r\n promptOptions: {\r\n type: 'toggle'\r\n }\r\n },\r\n dumpio: {\r\n value: false,\r\n types: ['boolean'],\r\n envLink: 'DEBUG_DUMPIO',\r\n description:\r\n 'Redirects or not browser stdout and stderr to process.stdout and process.stderr',\r\n promptOptions: {\r\n type: 'toggle'\r\n }\r\n },\r\n slowMo: {\r\n value: 0,\r\n types: ['number'],\r\n envLink: 'DEBUG_SLOW_MO',\r\n description: 'Delays Puppeteer operations by the specified milliseconds',\r\n promptOptions: {\r\n type: 'number'\r\n }\r\n },\r\n debuggingPort: {\r\n value: 9222,\r\n types: ['number'],\r\n envLink: 'DEBUG_DEBUGGING_PORT',\r\n description: 'Port used for debugging',\r\n promptOptions: {\r\n type: 'number'\r\n }\r\n }\r\n }\r\n};\r\n\r\n// Properties nesting level of all options\r\nexport const nestedProps = _createNestedProps(defaultConfig);\r\n\r\n// Properties names that should not be recursively merged\r\nexport const absoluteProps = _createAbsoluteProps(defaultConfig);\r\n\r\n/**\r\n * Recursively generates a mapping of nested argument chains from a nested\r\n * config object. This function traverses a nested object and creates a mapping\r\n * where each key is an argument name (either from `cliName`, `legacyName`,\r\n * or the original key) and each value is a string representing the chain\r\n * of nested properties leading to that argument.\r\n *\r\n * @function _createNestedProps\r\n *\r\n * @param {Object} config - The configuration object.\r\n * @param {Object} [nestedProps={}] - The accumulator object for storing\r\n * the resulting arguments chains. The default value is an empty object.\r\n * @param {string} [propChain=''] - The current chain of nested properties,\r\n * used internally during recursion. The default value is an empty string.\r\n *\r\n * @returns {Object} An object mapping argument names to their corresponding\r\n * nested property chains.\r\n */\r\nfunction _createNestedProps(config, nestedProps = {}, propChain = '') {\r\n Object.keys(config).forEach((key) => {\r\n // Get the specific section\r\n const entry = config[key];\r\n\r\n // Check if there is still more depth to traverse\r\n if (typeof entry.value === 'undefined') {\r\n // Recurse into deeper levels of nested arguments\r\n _createNestedProps(entry, nestedProps, `${propChain}.${key}`);\r\n } else {\r\n // Create the chain of nested arguments\r\n nestedProps[entry.cliName || key] = `${propChain}.${key}`.substring(1);\r\n\r\n // Support for the legacy, PhantomJS properties names\r\n if (entry.legacyName !== undefined) {\r\n nestedProps[entry.legacyName] = `${propChain}.${key}`.substring(1);\r\n }\r\n }\r\n });\r\n\r\n // Return the object with nested argument chains\r\n return nestedProps;\r\n}\r\n\r\n/**\r\n * Recursively gathers the names of properties from a configuration object that\r\n * can be treated as absolute properties. These properties have values that\r\n * are objects and do not contain further nested depth when merging an object\r\n * containing these options.\r\n *\r\n * @function _createAbsoluteProps\r\n *\r\n * @param {Object} config - The configuration object.\r\n * @param {Array.} [absoluteProps=[]] - An array to collect the names\r\n * of absolute properties. The default value is an empty array.\r\n *\r\n * @returns {Array.} An array containing the names of absolute\r\n * properties.\r\n */\r\nfunction _createAbsoluteProps(config, absoluteProps = []) {\r\n Object.keys(config).forEach((key) => {\r\n // Get the specific section\r\n const entry = config[key];\r\n\r\n // Check if there is still more depth to traverse\r\n if (typeof entry.types === 'undefined') {\r\n // Recurse into deeper levels\r\n _createAbsoluteProps(entry, absoluteProps);\r\n } else {\r\n // If the option can be an object, save its type in the array\r\n if (entry.types.includes('Object')) {\r\n absoluteProps.push(key);\r\n }\r\n }\r\n });\r\n\r\n // Return the array with the names of absolute properties\r\n return absoluteProps;\r\n}\r\n\r\nexport default {\r\n defaultConfig,\r\n nestedProps,\r\n absoluteProps\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * @overview This file handles parsing and validating options from multiple\r\n * sources (the config file, custom JSON, environment variables, CLI arguments,\r\n * and request payload) using the 'zod' library.\r\n *\r\n * Environment variables are parsed and validated only once at application\r\n * startup, and the validated results are exported as `envs` for use throughout\r\n * the application.\r\n *\r\n * Options from other sources, however, are parsed and validated on demand,\r\n * each time an export is attempted.\r\n */\r\n\r\nimport dotenv from 'dotenv';\r\nimport { z } from 'zod';\r\n\r\nimport { defaultConfig } from './schemas/config.js';\r\n\r\n// Load the .env into environment variables\r\ndotenv.config();\r\n\r\n// Get scripts names of each category from the default config\r\nconst { coreScripts, moduleScripts, indicatorScripts } =\r\n defaultConfig.highcharts;\r\n\r\n// Sets the custom error map globally\r\nz.setErrorMap(_customErrorMap);\r\n\r\n/**\r\n * Object containing custom general validators and parsers to avoid repetition\r\n * in schema objects. All validators apply to values from various sources,\r\n * including the default config file, a custom JSON file loaded with the option\r\n * called `loadConfig`, the .env file, CLI arguments, and the request payload.\r\n * The `strictCheck` flag enables stricter validation and parsing rules. This\r\n * flag is set to false for values that come from the .env file or CLI arguments\r\n * because they are provided as strings and need to be parsed accordingly first.\r\n */\r\nconst v = {\r\n /**\r\n * The `boolean` validator that returns a Zod schema with an optional stricter\r\n * check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures that:\r\n *\r\n * - When `strictCheck` is true, the schema will accept values are true\r\n * and false and the schema will validate against the default boolean\r\n * validator.\r\n *\r\n * - When `strictCheck` is false, the schema will accept values are true,\r\n * false, null, 'true', '1', 'false', '0', 'undefined', 'null', and ''.\r\n * The strings 'undefined', 'null', and '' will be transformed to null,\r\n * the string 'true' will be transformed to the boolean value true,\r\n * and 'false' will be transformed to the boolean value false.\r\n *\r\n * @function boolean\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating boolean values.\r\n */\r\n boolean(strictCheck) {\r\n return strictCheck\r\n ? z.boolean()\r\n : z\r\n .union([\r\n z\r\n .enum(['true', '1', 'false', '0', 'undefined', 'null', ''])\r\n .transform((value) =>\r\n !['undefined', 'null', ''].includes(value)\r\n ? value === 'true' || value === '1'\r\n : null\r\n ),\r\n z.boolean()\r\n ])\r\n .nullable();\r\n },\r\n\r\n /**\r\n * The `string` validator that returns a Zod schema with an optional stricter\r\n * check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures that:\r\n *\r\n * - When `strictCheck` is true, the schema will accept trimmed strings except\r\n * the forbidden values: 'false', 'undefined', 'null', and ''.\r\n *\r\n * - When `strictCheck` is false, the schema will accept trimmed strings\r\n * and null. The forbidden values: 'false', 'undefined', 'null', and '' will\r\n * be transformed to null.\r\n *\r\n * @function string\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating string values.\r\n */\r\n string(strictCheck) {\r\n return strictCheck\r\n ? z\r\n .string()\r\n .trim()\r\n .refine(\r\n (value) => !['false', 'undefined', 'null', ''].includes(value),\r\n {\r\n params: {\r\n errorMessage: 'The string contains a forbidden value'\r\n }\r\n }\r\n )\r\n : z\r\n .string()\r\n .trim()\r\n .transform((value) =>\r\n !['false', 'undefined', 'null', ''].includes(value) ? value : null\r\n )\r\n .nullable();\r\n },\r\n\r\n /**\r\n * The `enum` validator that returns a Zod schema with an optional stricter\r\n * check based on the `strictCheck` parameter.\r\n *\r\n * The schema will validate against the provided `values` array.\r\n *\r\n * The validation schema ensures that:\r\n *\r\n * - When `strictCheck` is true, the schema will validate against the `values`\r\n * array with the default enum validator.\r\n *\r\n * - When `strictCheck` is false, the schema will accept also null,\r\n * 'undefined', 'null', and '', which will be transformed to null.\r\n *\r\n * @function enum\r\n *\r\n * @param {Array.} values - An array of valid string values\r\n * for the enum.\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating enum values.\r\n */\r\n enum(values, strictCheck) {\r\n return strictCheck\r\n ? z.enum([...values])\r\n : z\r\n .enum([...values, 'undefined', 'null', ''])\r\n .transform((value) =>\r\n !['undefined', 'null', ''].includes(value) ? value : null\r\n )\r\n .nullable();\r\n },\r\n\r\n /**\r\n * The `stringArray` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures that:\r\n *\r\n * - When `strictCheck` is true, the schema will accept an array of trimmed\r\n * string values filtered by the logic provided through the `filterCallback`.\r\n *\r\n * - When `strictCheck` is false, the schema will accept null and trimmed\r\n * string values which will be splitted into an array of strings and filtered\r\n * from the '[' and ']' characters and by the logic provided through\r\n * the `filterCallback`. If the array is empty, it will be transformed\r\n * to null.\r\n *\r\n * @function stringArray\r\n *\r\n * @param {function} filterCallback - The filter callback.\r\n * @param {string} separator - The separator for spliting a string.\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating array of string\r\n * values.\r\n */\r\n stringArray(filterCallback, separator, strictCheck) {\r\n const arraySchema = z.string().trim().array();\r\n const stringSchema = z\r\n .string()\r\n .trim()\r\n .transform((value) => {\r\n if (value.startsWith('[')) {\r\n value = value.slice(1);\r\n }\r\n if (value.endsWith(']')) {\r\n value = value.slice(0, -1);\r\n }\r\n return value.split(separator);\r\n });\r\n\r\n const transformCallback = (value) =>\r\n value.map((value) => value.trim()).filter(filterCallback);\r\n\r\n return strictCheck\r\n ? arraySchema.transform(transformCallback)\r\n : z\r\n .union([stringSchema, arraySchema])\r\n .transform(transformCallback)\r\n .transform((value) => (value.length ? value : null))\r\n .nullable();\r\n },\r\n\r\n /**\r\n * The `positiveNum` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures that:\r\n *\r\n * - When `strictCheck` is true, the schema will accept positive number values\r\n * and validate against the default positive number validator.\r\n *\r\n * - When `strictCheck` is false, the schema will accept positive number\r\n * values, null, and trimmed string values that can either be 'undefined',\r\n * 'null', '', or represent a positive number. It will transform the string\r\n * to a positive number, or to null if it is 'undefined', 'null', or ''.\r\n *\r\n * @function positiveNum\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating positive number\r\n * values.\r\n */\r\n positiveNum(strictCheck) {\r\n return strictCheck\r\n ? z.number().positive()\r\n : z\r\n .union([\r\n z\r\n .string()\r\n .trim()\r\n .refine(\r\n (value) =>\r\n (!isNaN(Number(value)) && Number(value) > 0) ||\r\n ['undefined', 'null', ''].includes(value),\r\n {\r\n params: {\r\n errorMessage: 'The value must be numeric and positive'\r\n }\r\n }\r\n )\r\n .transform((value) =>\r\n !['undefined', 'null', ''].includes(value)\r\n ? Number(value)\r\n : null\r\n ),\r\n z.number().positive()\r\n ])\r\n .nullable();\r\n },\r\n\r\n /**\r\n * The `nonNegativeNum` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures that:\r\n *\r\n * - When `strictCheck` is true, the schema will accept non-negative number\r\n * values and validate against the default non-negative number validator.\r\n *\r\n * - When `strictCheck` is false, the schema will accept non-negative number\r\n * values, null, and trimmed string values that can either be 'undefined',\r\n * 'null', '', or represent a non-negative number. It will transform\r\n * the string to a non-negative number, or to null if it is 'undefined',\r\n * 'null', or ''.\r\n *\r\n * @function nonNegativeNum\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating non-negative\r\n * number values.\r\n */\r\n nonNegativeNum(strictCheck) {\r\n return strictCheck\r\n ? z.number().nonnegative()\r\n : z\r\n .union([\r\n z\r\n .string()\r\n .trim()\r\n .refine(\r\n (value) =>\r\n (!isNaN(Number(value)) && Number(value) >= 0) ||\r\n ['undefined', 'null', ''].includes(value),\r\n {\r\n params: {\r\n errorMessage: 'The value must be numeric and non-negative'\r\n }\r\n }\r\n )\r\n .transform((value) =>\r\n !['undefined', 'null', ''].includes(value)\r\n ? Number(value)\r\n : null\r\n ),\r\n z.number().nonnegative()\r\n ])\r\n .nullable();\r\n },\r\n\r\n /**\r\n * The `startsWith` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The schema will validate against the provided `prefixes` array to check\r\n * whether a string value starts with any of the values provided\r\n * in the `prefixes` array.\r\n *\r\n * The validation schema ensures that:\r\n *\r\n * - When `strictCheck` is true, the schema will accept trimmed string values\r\n * that start with values from the prefixes array.\r\n *\r\n * - When `strictCheck` is false, the schema will accept trimmed string values\r\n * that start with values from the prefixes array, null, 'undefined', 'null',\r\n * and '' where the schema will transform them to null.\r\n *\r\n * @function startsWith\r\n *\r\n * @param {Array.} prefixes - An array of prefixes to validate\r\n * the string against.\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating strings that\r\n * starts with values.\r\n */\r\n startsWith(prefixes, strictCheck) {\r\n return strictCheck\r\n ? z\r\n .string()\r\n .trim()\r\n .refine(\r\n (value) => prefixes.some((prefix) => value.startsWith(prefix)),\r\n {\r\n params: {\r\n errorMessage: `The value must be a string that starts with ${prefixes.join(', ')}`\r\n }\r\n }\r\n )\r\n : z\r\n .string()\r\n .trim()\r\n .refine(\r\n (value) =>\r\n prefixes.some((prefix) => value.startsWith(prefix)) ||\r\n ['undefined', 'null', ''].includes(value),\r\n {\r\n params: {\r\n errorMessage: `The value must be a string that starts with ${prefixes.join(', ')}`\r\n }\r\n }\r\n )\r\n .transform((value) =>\r\n !['undefined', 'null', ''].includes(value) ? value : null\r\n )\r\n .nullable();\r\n },\r\n\r\n /**\r\n * The `chartConfig` validator that returns a Zod schema.\r\n *\r\n * The validation schema ensures that the schema will accept object values\r\n * or trimmed string values that contain '\r\n (value.startsWith('{') && value.endsWith('}')) ||\r\n ['undefined', 'null', ''].includes(value),\r\n {\r\n params: {\r\n errorMessage:\r\n \"The value must be a string that starts with '{' and ends with '}'\"\r\n }\r\n }\r\n )\r\n .transform((value) =>\r\n !['undefined', 'null', ''].includes(value) ? value : null\r\n ),\r\n z.object({}).passthrough()\r\n ])\r\n .nullable();\r\n },\r\n\r\n /**\r\n * The `additionalOptions` validator that returns a Zod schema.\r\n *\r\n * The validation schema ensures that the schema will accept object values\r\n * or trimmed string values that end with '.json' and are at least one\r\n * character long excluding the extension, start with the '{' and end\r\n * with the '}', and null. The 'undefined', 'null', and '' values will\r\n * be transformed to null.\r\n *\r\n * @function additionalOptions\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating additional chart\r\n * options value.\r\n */\r\n additionalOptions() {\r\n return z\r\n .union([\r\n z\r\n .string()\r\n .trim()\r\n .refine(\r\n (value) =>\r\n (value.length >= 6 && value.endsWith('.json')) ||\r\n (value.startsWith('{') && value.endsWith('}')) ||\r\n ['undefined', 'null', ''].includes(value),\r\n {\r\n params: {\r\n errorMessage:\r\n \"The value must be a string that ends with '.json' or starts with '{' and ends with '}'\"\r\n }\r\n }\r\n )\r\n .transform((value) =>\r\n !['undefined', 'null', ''].includes(value) ? value : null\r\n ),\r\n z.object({}).passthrough()\r\n ])\r\n .nullable();\r\n }\r\n};\r\n\r\n/**\r\n * Object containing custom config validators and parsers to avoid repetition\r\n * in schema objects. All validators apply to values from various sources,\r\n * including the default config file, a custom JSON file loaded with the option\r\n * called `loadConfig`, the .env file, CLI arguments, and the request payload.\r\n * The `strictCheck` flag enables stricter validation and parsing rules. This\r\n * flag is set to false for values that come from the .env file or CLI arguments\r\n * because they are provided as strings and need to be parsed accordingly first.\r\n */\r\nexport const validators = {\r\n /**\r\n * The `args` validator that returns a Zod schema with an optional stricter\r\n * check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `stringArray` validator.\r\n *\r\n * @function args\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `args`\r\n * option.\r\n */\r\n args(strictCheck) {\r\n return v.stringArray(\r\n (value) => !['false', 'undefined', 'null', ''].includes(value),\r\n ';',\r\n strictCheck\r\n );\r\n },\r\n\r\n /**\r\n * The `version` validator that returns a Zod schema with an optional stricter\r\n * check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures that:\r\n *\r\n * - When `strictCheck` is true, the schema will accept trimmed string values\r\n * that are a RegExp-based that allows to be 'latest', or in the format XX,\r\n * XX.YY, or XX.YY.ZZ, where XX, YY, and ZZ are numeric for the Highcharts\r\n * version option.\r\n *\r\n * - When `strictCheck` is false, the schema will accept also null,\r\n * 'undefined', 'null', or '' and in all cases the schema will transform them\r\n * to null.\r\n *\r\n * @function version\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `version`\r\n * option.\r\n */\r\n version(strictCheck) {\r\n return strictCheck\r\n ? z\r\n .string()\r\n .trim()\r\n .refine((value) => /^(latest|\\d{1,2}(\\.\\d{1,2}){0,2})$/.test(value), {\r\n params: {\r\n errorMessage:\r\n \"The value must be 'latest', a major version, or in the form XX.YY.ZZ\"\r\n }\r\n })\r\n : z\r\n .string()\r\n .trim()\r\n .refine(\r\n (value) =>\r\n /^(latest|\\d{1,2}(\\.\\d{1,2}){0,2})$/.test(value) ||\r\n ['undefined', 'null', ''].includes(value),\r\n {\r\n params: {\r\n errorMessage:\r\n \"The value must be 'latest', a major version, or in the form XX.YY.ZZ\"\r\n }\r\n }\r\n )\r\n .transform((value) =>\r\n !['undefined', 'null', ''].includes(value) ? value : null\r\n )\r\n .nullable();\r\n },\r\n\r\n /**\r\n * The `cdnUrl` validator that returns a Zod schema with an optional stricter\r\n * check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `startsWith` validator.\r\n *\r\n * @function cdnUrl\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `cdnUrl`\r\n * option.\r\n */\r\n cdnUrl(strictCheck) {\r\n return v.startsWith(['http://', 'https://'], strictCheck);\r\n },\r\n\r\n /**\r\n * The `forceFetch` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `boolean` validator.\r\n *\r\n * @function forceFetch\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `forceFetch`\r\n * option.\r\n */\r\n forceFetch(strictCheck) {\r\n return v.boolean(strictCheck);\r\n },\r\n\r\n /**\r\n * The `cachePath` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `string` validator.\r\n *\r\n * @function cachePath\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `cachePath`\r\n * option.\r\n */\r\n cachePath(strictCheck) {\r\n return v.string(strictCheck);\r\n },\r\n\r\n /**\r\n * The `adminToken` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `string` validator.\r\n *\r\n * @function adminToken\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `adminToken`\r\n * option.\r\n */\r\n adminToken(strictCheck) {\r\n return v.string(strictCheck);\r\n },\r\n\r\n /**\r\n * The `coreScripts` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `stringArray` validator.\r\n *\r\n * @function coreScripts\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `coreScripts`\r\n * option.\r\n */\r\n coreScripts(strictCheck) {\r\n return v.stringArray(\r\n (value) => coreScripts.value.includes(value),\r\n ',',\r\n strictCheck\r\n );\r\n },\r\n\r\n /**\r\n * The `moduleScripts` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `stringArray` validator.\r\n *\r\n * @function moduleScripts\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating\r\n * the `moduleScripts` option.\r\n */\r\n moduleScripts(strictCheck) {\r\n return v.stringArray(\r\n (value) => moduleScripts.value.includes(value),\r\n ',',\r\n strictCheck\r\n );\r\n },\r\n\r\n /**\r\n * The `indicatorScripts` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `stringArray` validator.\r\n *\r\n * @function indicatorScripts\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating\r\n * the `indicatorScripts` option.\r\n */\r\n indicatorScripts(strictCheck) {\r\n return v.stringArray(\r\n (value) => indicatorScripts.value.includes(value),\r\n ',',\r\n strictCheck\r\n );\r\n },\r\n\r\n /**\r\n * The `customScripts` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `stringArray` validator.\r\n *\r\n * @function customScripts\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating\r\n * the `customScripts` option.\r\n */\r\n customScripts(strictCheck) {\r\n return v.stringArray(\r\n (value) => value.startsWith('https://') || value.startsWith('http://'),\r\n ',',\r\n strictCheck\r\n );\r\n },\r\n\r\n /**\r\n * The `infile` validator that returns a Zod schema with an optional stricter\r\n * check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures that:\r\n *\r\n * - When `strictCheck` is true, the schema will accept trimmed string values\r\n * that end with '.json' or '.svg', are at least one character long excluding\r\n * the extension, or null.\r\n *\r\n * - When `strictCheck` is false, the schema will accept trimmed string values\r\n * that end with '.json' or '.svg', are at least one character long excluding\r\n * the extension and will be null if the provided value is null, 'undefined',\r\n * 'null', or ''.\r\n *\r\n * @function infile\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `infile`\r\n * option.\r\n */\r\n infile(strictCheck) {\r\n return strictCheck\r\n ? z\r\n .string()\r\n .trim()\r\n .refine(\r\n (value) =>\r\n (value.length >= 6 && value.endsWith('.json')) ||\r\n (value.length >= 5 && value.endsWith('.svg')),\r\n {\r\n params: {\r\n errorMessage:\r\n 'The value must be a string that ends with .json or .svg'\r\n }\r\n }\r\n )\r\n .nullable()\r\n : z\r\n .string()\r\n .trim()\r\n .refine(\r\n (value) =>\r\n (value.length >= 6 && value.endsWith('.json')) ||\r\n (value.length >= 5 && value.endsWith('.svg')) ||\r\n ['undefined', 'null', ''].includes(value),\r\n {\r\n params: {\r\n errorMessage:\r\n 'The value must be a string that ends with .json or .svg'\r\n }\r\n }\r\n )\r\n .transform((value) =>\r\n !['undefined', 'null', ''].includes(value) ? value : null\r\n )\r\n .nullable();\r\n },\r\n\r\n /**\r\n * The `instr` validator that returns a Zod schema.\r\n *\r\n * The validation schema ensures the same work as the `options` validator.\r\n *\r\n * @function instr\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `instr`\r\n * option.\r\n */\r\n instr() {\r\n return v.chartConfig();\r\n },\r\n\r\n /**\r\n * The `options` validator that returns a Zod schema.\r\n *\r\n * The validation schema ensures the same work as the `options` validator.\r\n *\r\n * @function options\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `options`\r\n * option.\r\n */\r\n options() {\r\n return v.chartConfig();\r\n },\r\n\r\n /**\r\n * The `svg` validator that returns a Zod schema.\r\n *\r\n * The validation schema ensures that the schema will accept object values\r\n * or trimmed string values that contain '\r\n value.indexOf('= 0 ||\r\n value.indexOf('= 0 ||\r\n ['false', 'undefined', 'null', ''].includes(value),\r\n {\r\n params: {\r\n errorMessage:\r\n \"The value must be a string that contains '\r\n !['false', 'undefined', 'null', ''].includes(value) ? value : null\r\n )\r\n .nullable();\r\n },\r\n\r\n /**\r\n * The `outfile` validator that returns a Zod schema with an optional stricter\r\n * check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures that:\r\n *\r\n * - When `strictCheck` is true, the schema will accept trimmed string values\r\n * that end with '.jpeg', '.jpg', '.png', '.pdf', or '.svg', are at least one\r\n * character long excluding the extension, or null.\r\n *\r\n * - When `strictCheck` is false, the schema will accept trimmed string values\r\n * that end with '.jpeg', '.jpg', '.png', '.pdf', or '.svg', are at least one\r\n * character long excluding the extension and will be null if the provided\r\n * value is null, 'undefined', 'null', or ''.\r\n *\r\n * @function outfile\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `outfile`\r\n * option.\r\n */\r\n outfile(strictCheck) {\r\n return strictCheck\r\n ? z\r\n .string()\r\n .trim()\r\n .refine(\r\n (value) =>\r\n (value.length >= 6 && value.endsWith('.jpeg')) ||\r\n (value.length >= 5 &&\r\n (value.endsWith('.jpg') ||\r\n value.endsWith('.png') ||\r\n value.endsWith('.pdf') ||\r\n value.endsWith('.svg'))),\r\n {\r\n params: {\r\n errorMessage:\r\n 'The value must be a string that ends with .jpeg, .jpg, .png, .pdf, or .svg'\r\n }\r\n }\r\n )\r\n .nullable()\r\n : z\r\n .string()\r\n .trim()\r\n .refine(\r\n (value) =>\r\n (value.length >= 6 && value.endsWith('.jpeg')) ||\r\n (value.length >= 5 &&\r\n (value.endsWith('.jpg') ||\r\n value.endsWith('.png') ||\r\n value.endsWith('.pdf') ||\r\n value.endsWith('.svg'))) ||\r\n ['undefined', 'null', ''].includes(value),\r\n {\r\n params: {\r\n errorMessage:\r\n 'The value must be a string that ends with .jpeg, .jpg, .png, .pdf, or .svg'\r\n }\r\n }\r\n )\r\n .transform((value) =>\r\n !['undefined', 'null', ''].includes(value) ? value : null\r\n )\r\n .nullable();\r\n },\r\n\r\n /**\r\n * The `type` validator that returns a Zod schema with an optional stricter\r\n * check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `enum` validator.\r\n *\r\n * @function type\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `type`\r\n * option.\r\n */\r\n type(strictCheck) {\r\n return v.enum(['jpeg', 'jpg', 'png', 'pdf', 'svg'], strictCheck);\r\n },\r\n\r\n /**\r\n * The `constr` validator that returns a Zod schema with an optional stricter\r\n * check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `enum` validator.\r\n *\r\n * @function constr\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `constr`\r\n * option.\r\n */\r\n constr(strictCheck) {\r\n return v.enum(\r\n ['chart', 'stockChart', 'mapChart', 'ganttChart'],\r\n strictCheck\r\n );\r\n },\r\n\r\n /**\r\n * The `b64` validator that returns a Zod schema with an optional stricter\r\n * check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `boolean` validator.\r\n *\r\n * @function b64\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `b64` option.\r\n */\r\n b64(strictCheck) {\r\n return v.boolean(strictCheck);\r\n },\r\n\r\n /**\r\n * The `noDownload` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `boolean` validator.\r\n *\r\n * @function noDownload\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `noDownload`\r\n * option.\r\n */\r\n noDownload(strictCheck) {\r\n return v.boolean(strictCheck);\r\n },\r\n\r\n /**\r\n * The `defaultHeight` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `positiveNum` validator.\r\n *\r\n * @function defaultHeight\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating\r\n * the `defaultHeight` option.\r\n */\r\n defaultHeight(strictCheck) {\r\n return v.positiveNum(strictCheck);\r\n },\r\n\r\n /**\r\n * The `defaultWidth` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `positiveNum` validator.\r\n *\r\n * @function defaultWidth\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating\r\n * the `defaultWidth` option.\r\n */\r\n defaultWidth(strictCheck) {\r\n return v.positiveNum(strictCheck);\r\n },\r\n\r\n /**\r\n * The `defaultScale` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures that:\r\n *\r\n * - When `strictCheck` is true, the schema will accept number values that\r\n * are between 0.1 and 5 (inclusive).\r\n *\r\n * - When `strictCheck` is false, the schema will accept number values\r\n * and stringified number values that are between 0.1 and 5 (inclusive), null,\r\n * 'undefined', 'null', and '' which will be transformed to null.\r\n *\r\n * @function defaultScale\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating\r\n * the `defaultScale` option.\r\n */\r\n defaultScale(strictCheck) {\r\n return strictCheck\r\n ? z.number().gte(0.1).lte(5)\r\n : z\r\n .union([\r\n z\r\n .string()\r\n .trim()\r\n .refine(\r\n (value) =>\r\n (!isNaN(Number(value)) &&\r\n value !== true &&\r\n !value.startsWith('[') &&\r\n Number(value) >= 0.1 &&\r\n Number(value) <= 5) ||\r\n ['undefined', 'null', ''].includes(value),\r\n {\r\n params: {\r\n errorMessage: 'The value must be within a 0.1 and 5.0 range'\r\n }\r\n }\r\n )\r\n .transform((value) =>\r\n !['undefined', 'null', ''].includes(value)\r\n ? Number(value)\r\n : null\r\n ),\r\n z.number().gte(0.1).lte(5)\r\n ])\r\n .nullable();\r\n },\r\n\r\n /**\r\n * The `height` validator that returns a Zod schema with an optional stricter\r\n * check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as a nullable `defaultHeight`\r\n * validator.\r\n *\r\n * @function height\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `height`\r\n * option.\r\n */\r\n height(strictCheck) {\r\n return this.defaultHeight(strictCheck).nullable();\r\n },\r\n\r\n /**\r\n * The `width` validator that returns a Zod schema with an optional stricter\r\n * check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as a nullable `defaultWidth`\r\n * validator.\r\n *\r\n * @function width\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `width`\r\n * option.\r\n */\r\n width(strictCheck) {\r\n return this.defaultWidth(strictCheck).nullable();\r\n },\r\n\r\n /**\r\n * The `scale` validator that returns a Zod schema with an optional stricter\r\n * check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as a nullable `defaultScale`\r\n * validator.\r\n *\r\n * @function scale\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `scale`\r\n * option.\r\n */\r\n scale(strictCheck) {\r\n return this.defaultScale(strictCheck).nullable();\r\n },\r\n\r\n /**\r\n * The `globalOptions` validator that returns a Zod schema.\r\n *\r\n * The validation schema ensures the same work as the `additionalOptions`\r\n * validator.\r\n *\r\n * @function globalOptions\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating\r\n * the `globalOptions` option.\r\n */\r\n globalOptions() {\r\n return v.additionalOptions();\r\n },\r\n\r\n /**\r\n * The `themeOptions` validator that returns a Zod schema.\r\n *\r\n * The validation schema ensures the same work as the `additionalOptions`\r\n * validator.\r\n *\r\n * @function themeOptions\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating\r\n * the `themeOptions` option.\r\n */\r\n themeOptions() {\r\n return v.additionalOptions();\r\n },\r\n\r\n /**\r\n * The `batch` validator that returns a Zod schema with an optional stricter\r\n * check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `string` validator.\r\n *\r\n * @function batch\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `batch`\r\n * option.\r\n */\r\n batch(strictCheck) {\r\n return v.string(strictCheck);\r\n },\r\n\r\n /**\r\n * The `rasterizationTimeout` validator that returns a Zod schema with\r\n * an optional stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `nonNegativeNum`\r\n * validator.\r\n *\r\n * @function rasterizationTimeout\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating\r\n * the `rasterizationTimeout` option.\r\n */\r\n rasterizationTimeout(strictCheck) {\r\n return v.nonNegativeNum(strictCheck);\r\n },\r\n\r\n /**\r\n * The `allowCodeExecution` validator that returns a Zod schema with\r\n * an optional stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `boolean` validator.\r\n *\r\n * @function allowCodeExecution\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating\r\n * the `allowCodeExecution` option.\r\n */\r\n allowCodeExecution(strictCheck) {\r\n return v.boolean(strictCheck);\r\n },\r\n\r\n /**\r\n * The `allowFileResources` validator that returns a Zod schema with\r\n * an optional stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `boolean` validator.\r\n *\r\n * @function allowFileResources\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating\r\n * the `allowFileResources` option.\r\n */\r\n allowFileResources(strictCheck) {\r\n return v.boolean(strictCheck);\r\n },\r\n\r\n /**\r\n * The `customCode` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `string` validator.\r\n *\r\n * @function customCode\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `customCode`\r\n * option.\r\n */\r\n customCode(strictCheck) {\r\n return v.string(strictCheck);\r\n },\r\n\r\n /**\r\n * The `callback` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `string` validator.\r\n *\r\n * @function callback\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `callback`\r\n * option.\r\n */\r\n callback(strictCheck) {\r\n return v.string(strictCheck);\r\n },\r\n\r\n /**\r\n * The `resources` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures that:\r\n *\r\n * - When `strictCheck` is true, the schema will accept a partial object\r\n * with allowed properties `js`, `css`, and `files` where each of the allowed\r\n * properties can be null, stringified version of the object, string that ends\r\n * with the '.json', and null.\r\n *\r\n * - When `strictCheck` is false, the schema will accept a stringified version\r\n * of a partial object with allowed properties `js`, `css`, and `files` where\r\n * each of the allowed properties can be null, string that ends with the\r\n * '.json', and will be null if the provided value is 'undefined', 'null'\r\n * or ''.\r\n *\r\n * @function resources\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `resources`\r\n * option.\r\n */\r\n resources(strictCheck) {\r\n const objectSchema = z\r\n .object({\r\n js: v.string(false),\r\n css: v.string(false),\r\n files: v\r\n .stringArray(\r\n (value) => !['undefined', 'null', ''].includes(value),\r\n ',',\r\n true\r\n )\r\n .nullable()\r\n })\r\n .partial();\r\n\r\n const stringSchema1 = z\r\n .string()\r\n .trim()\r\n .refine(\r\n (value) =>\r\n (value.startsWith('{') && value.endsWith('}')) ||\r\n (value.length >= 6 && value.endsWith('.json')),\r\n {\r\n params: {\r\n errorMessage:\r\n \"The value must be a string that starts with '{' and ends with '}\"\r\n }\r\n }\r\n );\r\n\r\n const stringSchema2 = z\r\n .string()\r\n .trim()\r\n .refine(\r\n (value) =>\r\n (value.startsWith('{') && value.endsWith('}')) ||\r\n (value.length >= 6 && value.endsWith('.json')) ||\r\n ['undefined', 'null', ''].includes(value),\r\n {\r\n params: {\r\n errorMessage: 'The value must be a string that ends with .json'\r\n }\r\n }\r\n )\r\n .transform((value) =>\r\n !['undefined', 'null', ''].includes(value) ? value : null\r\n );\r\n\r\n return strictCheck\r\n ? z.union([objectSchema, stringSchema1]).nullable()\r\n : z.union([objectSchema, stringSchema2]).nullable();\r\n },\r\n\r\n /**\r\n * The `loadConfig` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `string` validator.\r\n * Additionally, it must be a string that ends with '.json'.\r\n *\r\n * @function loadConfig\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `loadConfig`\r\n * option.\r\n */\r\n loadConfig(strictCheck) {\r\n return v\r\n .string(strictCheck)\r\n .refine(\r\n (value) =>\r\n value === null || (value.length >= 6 && value.endsWith('.json')),\r\n {\r\n params: {\r\n errorMessage: 'The value must be a string that ends with .json'\r\n }\r\n }\r\n );\r\n },\r\n\r\n /**\r\n * The `createConfig` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `loadConfig` validator.\r\n *\r\n * @function createConfig\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating\r\n * the `createConfig` option.\r\n */\r\n createConfig(strictCheck) {\r\n return this.loadConfig(strictCheck);\r\n },\r\n\r\n /**\r\n * The `enableServer` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `boolean` validator.\r\n *\r\n * @function enableServer\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating\r\n * the `enableServer` option.\r\n */\r\n enableServer(strictCheck) {\r\n return v.boolean(strictCheck);\r\n },\r\n\r\n /**\r\n * The `host` validator that returns a Zod schema with an optional stricter\r\n * check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `string` validator.\r\n *\r\n * @function host\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `host`\r\n * option.\r\n */\r\n host(strictCheck) {\r\n return v.string(strictCheck);\r\n },\r\n\r\n /**\r\n * The `port` validator that returns a Zod schema with an optional stricter\r\n * check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `nonNegativeNum`\r\n * validator.\r\n *\r\n * @function port\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `port`\r\n * option.\r\n */\r\n port(strictCheck) {\r\n return v.nonNegativeNum(strictCheck);\r\n },\r\n\r\n /**\r\n * The `uploadLimit` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `positiveNum` validator.\r\n *\r\n * @function uploadLimit\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `uploadLimit`\r\n * option.\r\n */\r\n uploadLimit(strictCheck) {\r\n return v.positiveNum(strictCheck);\r\n },\r\n\r\n /**\r\n * The `serverBenchmarking` validator that returns a Zod schema with\r\n * an optional stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `boolean` validator.\r\n *\r\n * @function serverBenchmarking\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating\r\n * the `serverBenchmarking` option.\r\n */\r\n serverBenchmarking(strictCheck) {\r\n return v.boolean(strictCheck);\r\n },\r\n\r\n /**\r\n * The `proxyHost` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `string` validator.\r\n *\r\n * @function proxyHost\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `proxyHost`\r\n * option.\r\n */\r\n proxyHost(strictCheck) {\r\n return v.string(strictCheck);\r\n },\r\n\r\n /**\r\n * The `proxyPort` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as a nullable `nonNegativeNum`\r\n * validator.\r\n *\r\n * @function proxyPort\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `proxyPort`\r\n * option.\r\n */\r\n proxyPort(strictCheck) {\r\n return v.nonNegativeNum(strictCheck).nullable();\r\n },\r\n\r\n /**\r\n * The `proxyTimeout` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `nonNegativeNum`\r\n * validator.\r\n *\r\n * @function proxyTimeout\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating\r\n * the `proxyTimeout` option.\r\n */\r\n proxyTimeout(strictCheck) {\r\n return v.nonNegativeNum(strictCheck);\r\n },\r\n\r\n /**\r\n * The `enableRateLimiting` validator that returns a Zod schema with\r\n * an optional stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `boolean` validator.\r\n *\r\n * @function enableRateLimiting\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating\r\n * the `enableRateLimiting` option.\r\n */\r\n enableRateLimiting(strictCheck) {\r\n return v.boolean(strictCheck);\r\n },\r\n\r\n /**\r\n * The `maxRequests` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `nonNegativeNum`\r\n * validator.\r\n *\r\n * @function maxRequests\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `maxRequests`\r\n * option.\r\n */\r\n maxRequests(strictCheck) {\r\n return v.nonNegativeNum(strictCheck);\r\n },\r\n\r\n /**\r\n * The `window` validator that returns a Zod schema with an optional stricter\r\n * check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `nonNegativeNum`\r\n * validator.\r\n *\r\n * @function window\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `window`\r\n * option.\r\n */\r\n window(strictCheck) {\r\n return v.nonNegativeNum(strictCheck);\r\n },\r\n\r\n /**\r\n * The `delay` validator that returns a Zod schema with an optional stricter\r\n * check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `nonNegativeNum`\r\n * validator.\r\n *\r\n * @function delay\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `delay`\r\n * option.\r\n */\r\n delay(strictCheck) {\r\n return v.nonNegativeNum(strictCheck);\r\n },\r\n\r\n /**\r\n * The `trustProxy` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `boolean` validator.\r\n *\r\n * @function trustProxy\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `trustProxy`\r\n * option.\r\n */\r\n trustProxy(strictCheck) {\r\n return v.boolean(strictCheck);\r\n },\r\n\r\n /**\r\n * The `skipKey` validator that returns a Zod schema with an optional stricter\r\n * check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `string` validator.\r\n *\r\n * @function skipKey\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `skipKey`\r\n * option.\r\n */\r\n skipKey(strictCheck) {\r\n return v.string(strictCheck);\r\n },\r\n\r\n /**\r\n * The `skipToken` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `string` validator.\r\n *\r\n * @function skipToken\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `skipToken`\r\n * option.\r\n */\r\n skipToken(strictCheck) {\r\n return v.string(strictCheck);\r\n },\r\n\r\n /**\r\n * The `enableSsl` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `boolean` validator.\r\n *\r\n * @function enableSsl\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `enableSsl`\r\n * option.\r\n */\r\n enableSsl(strictCheck) {\r\n return v.boolean(strictCheck);\r\n },\r\n\r\n /**\r\n * The `sslForce` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `boolean` validator.\r\n *\r\n * @function sslForce\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `sslForce`\r\n * option.\r\n */\r\n sslForce(strictCheck) {\r\n return v.boolean(strictCheck);\r\n },\r\n\r\n /**\r\n * The `sslPort` validator that returns a Zod schema with an optional stricter\r\n * check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `nonNegativeNum`\r\n * validator.\r\n *\r\n * @function sslPort\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `sslPort`\r\n * option.\r\n */\r\n sslPort(strictCheck) {\r\n return v.nonNegativeNum(strictCheck);\r\n },\r\n\r\n /**\r\n * The `sslCertPath` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `string` validator.\r\n *\r\n * @function sslCertPath\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `sslCertPath`\r\n * option.\r\n */\r\n sslCertPath(strictCheck) {\r\n return v.string(strictCheck);\r\n },\r\n\r\n /**\r\n * The `minWorkers` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `positiveNum` validator.\r\n *\r\n * @function minWorkers\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `minWorkers`\r\n * option.\r\n */\r\n minWorkers(strictCheck) {\r\n return v.positiveNum(strictCheck);\r\n },\r\n\r\n /**\r\n * The `maxWorkers` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `positiveNum` validator.\r\n *\r\n * @function maxWorkers\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `maxWorkers`\r\n * option.\r\n */\r\n maxWorkers(strictCheck) {\r\n return v.positiveNum(strictCheck);\r\n },\r\n\r\n /**\r\n * The `workLimit` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `positiveNum` validator.\r\n *\r\n * @function workLimit\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `workLimit`\r\n * option.\r\n */\r\n workLimit(strictCheck) {\r\n return v.positiveNum(strictCheck);\r\n },\r\n\r\n /**\r\n * The `acquireTimeout` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `nonNegativeNum`\r\n * validator.\r\n *\r\n * @function acquireTimeout\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating\r\n * the `acquireTimeout` option.\r\n */\r\n acquireTimeout(strictCheck) {\r\n return v.nonNegativeNum(strictCheck);\r\n },\r\n\r\n /**\r\n * The `createTimeout` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `nonNegativeNum`\r\n * validator.\r\n *\r\n * @function createTimeout\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating\r\n * the `createTimeout` option.\r\n */\r\n createTimeout(strictCheck) {\r\n return v.nonNegativeNum(strictCheck);\r\n },\r\n\r\n /**\r\n * The `destroyTimeout` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `nonNegativeNum`\r\n * validator.\r\n *\r\n * @function destroyTimeout\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating\r\n * the `destroyTimeout` option.\r\n */\r\n destroyTimeout(strictCheck) {\r\n return v.nonNegativeNum(strictCheck);\r\n },\r\n\r\n /**\r\n * The `idleTimeout` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `nonNegativeNum`\r\n * validator.\r\n *\r\n * @function idleTimeout\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating\r\n * the `idleTimeout` option.\r\n */\r\n idleTimeout(strictCheck) {\r\n return v.nonNegativeNum(strictCheck);\r\n },\r\n\r\n /**\r\n * The `createRetryInterval` validator that returns a Zod schema with\r\n * an optional stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `nonNegativeNum`\r\n * validator.\r\n *\r\n * @function createRetryInterval\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating\r\n * the `createRetryInterval` option.\r\n */\r\n createRetryInterval(strictCheck) {\r\n return v.nonNegativeNum(strictCheck);\r\n },\r\n\r\n /**\r\n * The `reaperInterval` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `nonNegativeNum`\r\n * validator.\r\n *\r\n * @function reaperInterval\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating\r\n * the `reaperInterval` option.\r\n */\r\n reaperInterval(strictCheck) {\r\n return v.nonNegativeNum(strictCheck);\r\n },\r\n\r\n /**\r\n * The `poolBenchmarking` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `boolean` validator.\r\n *\r\n * @function poolBenchmarking\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating\r\n * the `poolBenchmarking` option.\r\n */\r\n poolBenchmarking(strictCheck) {\r\n return v.boolean(strictCheck);\r\n },\r\n\r\n /**\r\n * The `resourcesInterval` validator that returns a Zod schema with\r\n * an optional stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `nonNegativeNum`\r\n * validator.\r\n *\r\n * @function resourcesInterval\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating\r\n * the `resourcesInterval` option.\r\n */\r\n resourcesInterval(strictCheck) {\r\n return v.nonNegativeNum(strictCheck);\r\n },\r\n\r\n /**\r\n * The `logLevel` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures that:\r\n *\r\n * - When `strictCheck` is true, the schema will accept integer number values\r\n * that are between 0 and 5 (inclusive).\r\n *\r\n * - When `strictCheck` is false, the schema will accept integer number values\r\n * and stringified integer number values that are between 1 and 5 (inclusive),\r\n * null, 'undefined', 'null', and '' which will be transformed to null.\r\n *\r\n * @function logLevel\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `logLevel`\r\n * option.\r\n */\r\n logLevel(strictCheck) {\r\n return strictCheck\r\n ? z.number().int().gte(0).lte(5)\r\n : z\r\n .union([\r\n z\r\n .string()\r\n .trim()\r\n .refine(\r\n (value) =>\r\n (!isNaN(Number(value)) &&\r\n value !== true &&\r\n !value.startsWith('[') &&\r\n Number.isInteger(Number(value)) &&\r\n Number(value) >= 0 &&\r\n Number(value) <= 5) ||\r\n ['undefined', 'null', ''].includes(value),\r\n {\r\n params: {\r\n errorMessage: 'The value must be within a 0 and 5 range'\r\n }\r\n }\r\n )\r\n .transform((value) =>\r\n !['undefined', 'null', ''].includes(value)\r\n ? Number(value)\r\n : null\r\n ),\r\n z.number().int().gte(0).lte(5)\r\n ])\r\n .nullable();\r\n },\r\n\r\n /**\r\n * The `logFile` validator that returns a Zod schema with an optional stricter\r\n * check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `string` validator.\r\n * Additionally, it must be a string that ends with '.log'.\r\n *\r\n * @function logFile\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `logFile`\r\n * option.\r\n */\r\n logFile(strictCheck) {\r\n return v\r\n .string(strictCheck)\r\n .refine(\r\n (value) =>\r\n value === null || (value.length >= 5 && value.endsWith('.log')),\r\n {\r\n params: {\r\n errorMessage: 'The value must be a string that ends with .log'\r\n }\r\n }\r\n );\r\n },\r\n\r\n /**\r\n * The `logDest` validator that returns a Zod schema with an optional stricter\r\n * check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `string` validator.\r\n *\r\n * @function logDest\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `logDest`\r\n * option.\r\n */\r\n logDest(strictCheck) {\r\n return v.string(strictCheck);\r\n },\r\n\r\n /**\r\n * The `logToConsole` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `boolean` validator.\r\n *\r\n * @function logToConsole\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating\r\n * the `logToConsole` option.\r\n */\r\n logToConsole(strictCheck) {\r\n return v.boolean(strictCheck);\r\n },\r\n\r\n /**\r\n * The `logToFile` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `boolean` validator.\r\n *\r\n * @function logToFile\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `logToFile`\r\n * option.\r\n */\r\n logToFile(strictCheck) {\r\n return v.boolean(strictCheck);\r\n },\r\n\r\n /**\r\n * The `enableUi` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `boolean` validator.\r\n *\r\n * @function enableUi\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `enableUi`\r\n * option.\r\n */\r\n enableUi(strictCheck) {\r\n return v.boolean(strictCheck);\r\n },\r\n\r\n /**\r\n * The `uiRoute` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `startsWith` validator.\r\n *\r\n * @function uiRoute\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `uiRoute`\r\n * option.\r\n */\r\n uiRoute(strictCheck) {\r\n return v.startsWith(['/'], strictCheck);\r\n },\r\n\r\n /**\r\n * The `nodeEnv` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `enum` validator.\r\n *\r\n * @function nodeEnv\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `nodeEnv`\r\n * option.\r\n */\r\n nodeEnv(strictCheck) {\r\n return v.enum(['development', 'production', 'test'], strictCheck);\r\n },\r\n\r\n /**\r\n * The `listenToProcessExits` validator that returns a Zod schema with\r\n * an optional stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `boolean` validator.\r\n *\r\n * @function listenToProcessExits\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating\r\n * the `listenToProcessExits` option.\r\n */\r\n listenToProcessExits(strictCheck) {\r\n return v.boolean(strictCheck);\r\n },\r\n\r\n /**\r\n * The `noLogo` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `boolean` validator.\r\n *\r\n * @function noLogo\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `noLogo`\r\n * option.\r\n */\r\n noLogo(strictCheck) {\r\n return v.boolean(strictCheck);\r\n },\r\n\r\n /**\r\n * The `hardResetPage` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `boolean` validator.\r\n *\r\n * @function hardResetPage\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating\r\n * the `hardResetPage` option.\r\n */\r\n hardResetPage(strictCheck) {\r\n return v.boolean(strictCheck);\r\n },\r\n\r\n /**\r\n * The `browserShellMode` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `boolean` validator.\r\n *\r\n * @function browserShellMode\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating\r\n * the `browserShellMode` option.\r\n */\r\n browserShellMode(strictCheck) {\r\n return v.boolean(strictCheck);\r\n },\r\n\r\n /**\r\n * The `validation` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `boolean` validator.\r\n *\r\n * @function validation\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `validation`\r\n * option.\r\n */\r\n validation(strictCheck) {\r\n return v.boolean(strictCheck);\r\n },\r\n\r\n /**\r\n * The `enableDebug` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `boolean` validator.\r\n *\r\n * @function enableDebug\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `enableDebug`\r\n * option.\r\n */\r\n enableDebug(strictCheck) {\r\n return v.boolean(strictCheck);\r\n },\r\n\r\n /**\r\n * The `headless` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `boolean` validator.\r\n *\r\n * @function headless\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `headless`\r\n * option.\r\n */\r\n headless(strictCheck) {\r\n return v.boolean(strictCheck);\r\n },\r\n\r\n /**\r\n * The `devtools` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `boolean` validator.\r\n *\r\n * @function devtools\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `devtools`\r\n * option.\r\n */\r\n devtools(strictCheck) {\r\n return v.boolean(strictCheck);\r\n },\r\n\r\n /**\r\n * The `listenToConsole` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `boolean` validator.\r\n *\r\n * @function listenToConsole\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating\r\n * the `listenToConsole` option.\r\n */\r\n listenToConsole(strictCheck) {\r\n return v.boolean(strictCheck);\r\n },\r\n\r\n /**\r\n * The `dumpio` validator that returns a Zod schema with an optional stricter\r\n * check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `boolean` validator.\r\n *\r\n * @function dumpio\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `dumpio`\r\n * option.\r\n */\r\n dumpio(strictCheck) {\r\n return v.boolean(strictCheck);\r\n },\r\n\r\n /**\r\n * The `slowMo` validator that returns a Zod schema with an optional stricter\r\n * check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `nonNegativeNum`\r\n * validator.\r\n *\r\n * @function slowMo\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `slowMo`\r\n * option.\r\n */\r\n slowMo(strictCheck) {\r\n return v.nonNegativeNum(strictCheck);\r\n },\r\n\r\n /**\r\n * The `debuggingPort` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `nonNegativeNum`\r\n * validator.\r\n *\r\n * @function debuggingPort\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating\r\n * the `debuggingPort` option.\r\n */\r\n debuggingPort(strictCheck) {\r\n return v.nonNegativeNum(strictCheck);\r\n },\r\n\r\n /**\r\n * The `requestId` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `string` validator.\r\n * Additionally, it must be a stringified UUID or can be null.\r\n *\r\n * @function requestId\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `requestId`\r\n * option.\r\n */\r\n requestId() {\r\n return z\r\n .string()\r\n .uuid({ message: 'The value must be a stringified UUID' })\r\n .nullable();\r\n }\r\n};\r\n\r\n// Schema for the puppeteer section of options\r\nconst PuppeteerSchema = (strictCheck) =>\r\n z\r\n .object({\r\n args: validators.args(strictCheck)\r\n })\r\n .partial();\r\n\r\n// Schema for the highcharts section of options\r\nconst HighchartsSchema = (strictCheck) =>\r\n z\r\n .object({\r\n version: validators.version(strictCheck),\r\n cdnUrl: validators.cdnUrl(strictCheck),\r\n forceFetch: validators.forceFetch(strictCheck),\r\n cachePath: validators.cachePath(strictCheck),\r\n coreScripts: validators.coreScripts(strictCheck),\r\n moduleScripts: validators.moduleScripts(strictCheck),\r\n indicatorScripts: validators.indicatorScripts(strictCheck),\r\n customScripts: validators.customScripts(strictCheck)\r\n })\r\n .partial();\r\n\r\n// Schema for the export section of options\r\nconst ExportSchema = (strictCheck) =>\r\n z\r\n .object({\r\n infile: validators.infile(strictCheck),\r\n instr: validators.instr(),\r\n options: validators.options(),\r\n svg: validators.svg(),\r\n outfile: validators.outfile(strictCheck),\r\n type: validators.type(strictCheck),\r\n constr: validators.constr(strictCheck),\r\n b64: validators.b64(strictCheck),\r\n noDownload: validators.noDownload(strictCheck),\r\n defaultHeight: validators.defaultHeight(strictCheck),\r\n defaultWidth: validators.defaultWidth(strictCheck),\r\n defaultScale: validators.defaultScale(strictCheck),\r\n height: validators.height(strictCheck),\r\n width: validators.width(strictCheck),\r\n scale: validators.scale(strictCheck),\r\n globalOptions: validators.globalOptions(),\r\n themeOptions: validators.themeOptions(),\r\n batch: validators.batch(false),\r\n rasterizationTimeout: validators.rasterizationTimeout(strictCheck)\r\n })\r\n .partial();\r\n\r\n// Schema for the customLogic section of options\r\nconst CustomLogicSchema = (strictCheck) =>\r\n z\r\n .object({\r\n allowCodeExecution: validators.allowCodeExecution(strictCheck),\r\n allowFileResources: validators.allowFileResources(strictCheck),\r\n customCode: validators.customCode(false),\r\n callback: validators.callback(false),\r\n resources: validators.resources(strictCheck),\r\n loadConfig: validators.loadConfig(false),\r\n createConfig: validators.createConfig(false)\r\n })\r\n .partial();\r\n\r\n// Schema for the server.proxy section of options\r\nconst ProxySchema = (strictCheck) =>\r\n z\r\n .object({\r\n host: validators.proxyHost(false),\r\n port: validators.proxyPort(strictCheck),\r\n timeout: validators.proxyTimeout(strictCheck)\r\n })\r\n .partial();\r\n\r\n// Schema for the server.rateLimiting section of options\r\nconst RateLimitingSchema = (strictCheck) =>\r\n z\r\n .object({\r\n enable: validators.enableRateLimiting(strictCheck),\r\n maxRequests: validators.maxRequests(strictCheck),\r\n window: validators.window(strictCheck),\r\n delay: validators.delay(strictCheck),\r\n trustProxy: validators.trustProxy(strictCheck),\r\n skipKey: validators.skipKey(false),\r\n skipToken: validators.skipToken(false)\r\n })\r\n .partial();\r\n\r\n// Schema for the server.ssl section of options\r\nconst SslSchema = (strictCheck) =>\r\n z\r\n .object({\r\n enable: validators.enableSsl(strictCheck),\r\n force: validators.sslForce(strictCheck),\r\n port: validators.sslPort(strictCheck),\r\n certPath: validators.sslCertPath(false)\r\n })\r\n .partial();\r\n\r\n// Schema for the server section of options\r\nconst ServerSchema = (strictCheck) =>\r\n z.object({\r\n enable: validators.enableServer(strictCheck).optional(),\r\n host: validators.host(strictCheck).optional(),\r\n port: validators.port(strictCheck).optional(),\r\n uploadLimit: validators.uploadLimit(strictCheck).optional(),\r\n benchmarking: validators.serverBenchmarking(strictCheck).optional(),\r\n proxy: ProxySchema(strictCheck).optional(),\r\n rateLimiting: RateLimitingSchema(strictCheck).optional(),\r\n ssl: SslSchema(strictCheck).optional()\r\n });\r\n\r\n// Schema for the pool section of options\r\nconst PoolSchema = (strictCheck) =>\r\n z\r\n .object({\r\n minWorkers: validators.minWorkers(strictCheck),\r\n maxWorkers: validators.maxWorkers(strictCheck),\r\n workLimit: validators.workLimit(strictCheck),\r\n acquireTimeout: validators.acquireTimeout(strictCheck),\r\n createTimeout: validators.createTimeout(strictCheck),\r\n destroyTimeout: validators.destroyTimeout(strictCheck),\r\n idleTimeout: validators.idleTimeout(strictCheck),\r\n createRetryInterval: validators.createRetryInterval(strictCheck),\r\n reaperInterval: validators.reaperInterval(strictCheck),\r\n benchmarking: validators.poolBenchmarking(strictCheck)\r\n })\r\n .partial();\r\n\r\n// Schema for the logging section of options\r\nconst LoggingSchema = (strictCheck) =>\r\n z\r\n .object({\r\n level: validators.logLevel(strictCheck),\r\n file: validators.logFile(strictCheck),\r\n dest: validators.logDest(strictCheck),\r\n toConsole: validators.logToConsole(strictCheck),\r\n toFile: validators.logToFile(strictCheck)\r\n })\r\n .partial();\r\n\r\n// Schema for the ui section of options\r\nconst UiSchema = (strictCheck) =>\r\n z\r\n .object({\r\n enable: validators.enableUi(strictCheck),\r\n route: validators.uiRoute(strictCheck)\r\n })\r\n .partial();\r\n\r\n// Schema for the other section of options\r\nconst OtherSchema = (strictCheck) =>\r\n z\r\n .object({\r\n nodeEnv: validators.nodeEnv(strictCheck),\r\n listenToProcessExits: validators.listenToProcessExits(strictCheck),\r\n noLogo: validators.noLogo(strictCheck),\r\n hardResetPage: validators.hardResetPage(strictCheck),\r\n browserShellMode: validators.browserShellMode(strictCheck),\r\n validation: validators.validation(strictCheck)\r\n })\r\n .partial();\r\n\r\n// Schema for the debug section of options\r\nconst DebugSchema = (strictCheck) =>\r\n z\r\n .object({\r\n enable: validators.enableDebug(strictCheck),\r\n headless: validators.headless(strictCheck),\r\n devtools: validators.devtools(strictCheck),\r\n listenToConsole: validators.listenToConsole(strictCheck),\r\n dumpio: validators.dumpio(strictCheck),\r\n slowMo: validators.slowMo(strictCheck),\r\n debuggingPort: validators.debuggingPort(strictCheck)\r\n })\r\n .partial();\r\n\r\n// Strict schema for the config\r\nexport const StrictConfigSchema = z.object({\r\n requestId: validators.requestId(),\r\n puppeteer: PuppeteerSchema(true),\r\n highcharts: HighchartsSchema(true),\r\n export: ExportSchema(true),\r\n customLogic: CustomLogicSchema(true),\r\n server: ServerSchema(true),\r\n pool: PoolSchema(true),\r\n logging: LoggingSchema(true),\r\n ui: UiSchema(true),\r\n other: OtherSchema(true),\r\n debug: DebugSchema(true)\r\n});\r\n\r\n// Loose schema for the config\r\nexport const LooseConfigSchema = z.object({\r\n requestId: validators.requestId(),\r\n puppeteer: PuppeteerSchema(false),\r\n highcharts: HighchartsSchema(false),\r\n export: ExportSchema(false),\r\n customLogic: CustomLogicSchema(false),\r\n server: ServerSchema(false),\r\n pool: PoolSchema(false),\r\n logging: LoggingSchema(false),\r\n ui: UiSchema(false),\r\n other: OtherSchema(false),\r\n debug: DebugSchema(false)\r\n});\r\n\r\n// Schema for the environment variables config\r\nexport const EnvSchema = z.object({\r\n // puppeteer\r\n PUPPETEER_ARGS: validators.args(false),\r\n\r\n // highcharts\r\n HIGHCHARTS_VERSION: validators.version(false),\r\n HIGHCHARTS_CDN_URL: validators.cdnUrl(false),\r\n HIGHCHARTS_FORCE_FETCH: validators.forceFetch(false),\r\n HIGHCHARTS_CACHE_PATH: validators.cachePath(false),\r\n HIGHCHARTS_ADMIN_TOKEN: validators.adminToken(false),\r\n HIGHCHARTS_CORE_SCRIPTS: validators.coreScripts(false),\r\n HIGHCHARTS_MODULE_SCRIPTS: validators.moduleScripts(false),\r\n HIGHCHARTS_INDICATOR_SCRIPTS: validators.indicatorScripts(false),\r\n HIGHCHARTS_CUSTOM_SCRIPTS: validators.customScripts(false),\r\n\r\n // export\r\n EXPORT_INFILE: validators.infile(false),\r\n EXPORT_INSTR: validators.instr(),\r\n EXPORT_OPTIONS: validators.options(),\r\n EXPORT_SVG: validators.svg(),\r\n EXPORT_BATCH: validators.batch(false),\r\n EXPORT_OUTFILE: validators.outfile(false),\r\n EXPORT_TYPE: validators.type(false),\r\n EXPORT_CONSTR: validators.constr(false),\r\n EXPORT_B64: validators.b64(false),\r\n EXPORT_NO_DOWNLOAD: validators.noDownload(false),\r\n EXPORT_HEIGHT: validators.height(false),\r\n EXPORT_WIDTH: validators.width(false),\r\n EXPORT_SCALE: validators.scale(false),\r\n EXPORT_DEFAULT_HEIGHT: validators.defaultHeight(false),\r\n EXPORT_DEFAULT_WIDTH: validators.defaultWidth(false),\r\n EXPORT_DEFAULT_SCALE: validators.defaultScale(false),\r\n EXPORT_GLOBAL_OPTIONS: validators.globalOptions(),\r\n EXPORT_THEME_OPTIONS: validators.themeOptions(),\r\n EXPORT_RASTERIZATION_TIMEOUT: validators.rasterizationTimeout(false),\r\n\r\n // custom\r\n CUSTOM_LOGIC_ALLOW_CODE_EXECUTION: validators.allowCodeExecution(false),\r\n CUSTOM_LOGIC_ALLOW_FILE_RESOURCES: validators.allowFileResources(false),\r\n CUSTOM_LOGIC_CUSTOM_CODE: validators.customCode(false),\r\n CUSTOM_LOGIC_CALLBACK: validators.callback(false),\r\n CUSTOM_LOGIC_RESOURCES: validators.resources(false),\r\n CUSTOM_LOGIC_LOAD_CONFIG: validators.loadConfig(false),\r\n CUSTOM_LOGIC_CREATE_CONFIG: validators.createConfig(false),\r\n\r\n // server\r\n SERVER_ENABLE: validators.enableServer(false),\r\n SERVER_HOST: validators.host(false),\r\n SERVER_PORT: validators.port(false),\r\n SERVER_UPLOAD_LIMIT: validators.uploadLimit(false),\r\n SERVER_BENCHMARKING: validators.serverBenchmarking(false),\r\n\r\n // server proxy\r\n SERVER_PROXY_HOST: validators.proxyHost(false),\r\n SERVER_PROXY_PORT: validators.proxyPort(false),\r\n SERVER_PROXY_TIMEOUT: validators.proxyTimeout(false),\r\n\r\n // server rate limiting\r\n SERVER_RATE_LIMITING_ENABLE: validators.enableRateLimiting(false),\r\n SERVER_RATE_LIMITING_MAX_REQUESTS: validators.maxRequests(false),\r\n SERVER_RATE_LIMITING_WINDOW: validators.window(false),\r\n SERVER_RATE_LIMITING_DELAY: validators.delay(false),\r\n SERVER_RATE_LIMITING_TRUST_PROXY: validators.trustProxy(false),\r\n SERVER_RATE_LIMITING_SKIP_KEY: validators.skipKey(false),\r\n SERVER_RATE_LIMITING_SKIP_TOKEN: validators.skipToken(false),\r\n\r\n // server ssl\r\n SERVER_SSL_ENABLE: validators.enableSsl(false),\r\n SERVER_SSL_FORCE: validators.sslForce(false),\r\n SERVER_SSL_PORT: validators.sslPort(false),\r\n SERVER_SSL_CERT_PATH: validators.sslCertPath(false),\r\n\r\n // pool\r\n POOL_MIN_WORKERS: validators.minWorkers(false),\r\n POOL_MAX_WORKERS: validators.maxWorkers(false),\r\n POOL_WORK_LIMIT: validators.workLimit(false),\r\n POOL_ACQUIRE_TIMEOUT: validators.acquireTimeout(false),\r\n POOL_CREATE_TIMEOUT: validators.createTimeout(false),\r\n POOL_DESTROY_TIMEOUT: validators.destroyTimeout(false),\r\n POOL_IDLE_TIMEOUT: validators.idleTimeout(false),\r\n POOL_CREATE_RETRY_INTERVAL: validators.createRetryInterval(false),\r\n POOL_REAPER_INTERVAL: validators.reaperInterval(false),\r\n POOL_BENCHMARKING: validators.poolBenchmarking(false),\r\n\r\n // logging\r\n LOGGING_LEVEL: validators.logLevel(false),\r\n LOGGING_FILE: validators.logFile(false),\r\n LOGGING_DEST: validators.logDest(false),\r\n LOGGING_TO_CONSOLE: validators.logToConsole(false),\r\n LOGGING_TO_FILE: validators.logToFile(false),\r\n\r\n // ui\r\n UI_ENABLE: validators.enableUi(false),\r\n UI_ROUTE: validators.uiRoute(false),\r\n\r\n // other\r\n OTHER_NODE_ENV: validators.nodeEnv(false),\r\n OTHER_LISTEN_TO_PROCESS_EXITS: validators.listenToProcessExits(false),\r\n OTHER_NO_LOGO: validators.noLogo(false),\r\n OTHER_HARD_RESET_PAGE: validators.hardResetPage(false),\r\n OTHER_BROWSER_SHELL_MODE: validators.browserShellMode(false),\r\n OTHER_VALIDATION: validators.validation(false),\r\n\r\n // debugger\r\n DEBUG_ENABLE: validators.enableDebug(false),\r\n DEBUG_HEADLESS: validators.headless(false),\r\n DEBUG_DEVTOOLS: validators.devtools(false),\r\n DEBUG_LISTEN_TO_CONSOLE: validators.listenToConsole(false),\r\n DEBUG_DUMPIO: validators.dumpio(false),\r\n DEBUG_SLOW_MO: validators.slowMo(false),\r\n DEBUG_DEBUGGING_PORT: validators.debuggingPort(false)\r\n});\r\n\r\n/**\r\n * Validates the environment variables options using the EnvSchema.\r\n *\r\n * @param {Object} process.env - The configuration options from environment\r\n * variables file to validate.\r\n *\r\n * @returns {Object} The parsed and validated environment variables.\r\n */\r\nexport const envs = EnvSchema.partial().parse(process.env);\r\n\r\n/**\r\n * Validates the configuration options using the `StrictConfigSchema`.\r\n *\r\n * @function strictValidate\r\n *\r\n * @param {Object} configOptions - The configuration options to validate.\r\n *\r\n * @returns {Object} The parsed and validated configuration options.\r\n */\r\nexport function strictValidate(configOptions) {\r\n return StrictConfigSchema.partial().parse(configOptions);\r\n}\r\n\r\n/**\r\n * Validates the configuration options using the `LooseConfigSchema`.\r\n *\r\n * @function looseValidate\r\n *\r\n * @param {Object} configOptions - The configuration options to validate.\r\n *\r\n * @returns {Object} The parsed and validated configuration options.\r\n */\r\nexport function looseValidate(configOptions) {\r\n return LooseConfigSchema.partial().parse(configOptions);\r\n}\r\n\r\n/**\r\n * Custom error mapping function for Zod schema validation.\r\n *\r\n * This function customizes the error messages produced by Zod schema\r\n * validation, providing more specific and user-friendly feedback based on the\r\n * issue type and context.\r\n *\r\n * The function modifies the error messages as follows:\r\n *\r\n * - For missing required values (undefined), it returns a message indicating\r\n * that no value was provided for the specific property.\r\n *\r\n * - For custom validation errors, if a custom error message is provided in the\r\n * issue parameters, it includes this message along with the invalid data\r\n * received.\r\n *\r\n * - For all other errors, it appends property-specific information to the\r\n * default error message provided by Zod.\r\n *\r\n * @function _customErrorMap\r\n *\r\n * @param {z.ZodIssue} issue - The issue object representing the validation\r\n * error.\r\n * @param {Object} context - The context object providing additional information\r\n * about the validation error.\r\n *\r\n * @returns {Object} An object containing the customized error message.\r\n */\r\nfunction _customErrorMap(issue, context) {\r\n // Get the chain of properties which error directly refers to\r\n const propertyName = issue.path.join('.');\r\n\r\n // Create the first part of the message about the property information\r\n const propertyInfo = `Invalid value for the ${propertyName}`;\r\n\r\n // Modified message for the invalid type\r\n if (issue.code === z.ZodIssueCode.invalid_type) {\r\n // Modified message for the required values\r\n if (issue.received === z.ZodParsedType.undefined) {\r\n return {\r\n message: `${propertyInfo} - No value was provided.`\r\n };\r\n }\r\n\r\n // Modified message for the specific invalid type when values exist\r\n return {\r\n message: `${propertyInfo} - Invalid type. ${context.defaultError}.`\r\n };\r\n }\r\n\r\n // Modified message for the custom validation\r\n if (issue.code === z.ZodIssueCode.custom) {\r\n // If the custom message for error exist, include it\r\n if (issue.params?.errorMessage) {\r\n return {\r\n message: `${propertyInfo} - ${issue.params?.errorMessage}, received '${context.data}'.`\r\n };\r\n }\r\n }\r\n\r\n // Modified message for the invalid union error\r\n if (issue.code === z.ZodIssueCode.invalid_union) {\r\n // Create the first part of the message about the multiple errors\r\n let message = `Multiple errors occurred for the ${propertyName}:\\n`;\r\n\r\n // Cycle through all errors and create a correct message\r\n issue.unionErrors.forEach((value) => {\r\n const index = value.issues[0].message.indexOf('-');\r\n message +=\r\n index !== -1\r\n ? `${value.issues[0].message}\\n`.substring(index)\r\n : `${value.issues[0].message}\\n`;\r\n });\r\n\r\n // Return the final message for the invalid union error\r\n return {\r\n message\r\n };\r\n }\r\n\r\n // Return the default error message, extended by the info about the property\r\n return {\r\n message: `${propertyInfo} - ${context.defaultError}.`\r\n };\r\n}\r\n\r\nexport default {\r\n validators,\r\n StrictConfigSchema,\r\n LooseConfigSchema,\r\n EnvSchema,\r\n envs,\r\n strictValidate,\r\n looseValidate\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * A custom error class for handling export-related errors. Extends the native\r\n * `Error` class to include additional properties like status code and stack\r\n * trace details.\r\n */\r\nclass ExportError extends Error {\r\n /**\r\n * Creates an instance of the `ExportError`.\r\n *\r\n * @param {string} message - The error message to be displayed.\r\n * @param {number} statusCode - Optional HTTP status code associated\r\n * with the error (e.g., 400, 500).\r\n */\r\n constructor(message, statusCode) {\r\n super();\r\n\r\n this.message = message;\r\n this.stackMessage = message;\r\n\r\n if (statusCode) {\r\n this.statusCode = statusCode;\r\n }\r\n }\r\n\r\n /**\r\n * Sets or updates the HTTP status code for the error.\r\n *\r\n * @param {number} statusCode - The HTTP status code to assign to the error.\r\n *\r\n * @returns {ExportError} The updated instance of the `ExportError` class.\r\n */\r\n setStatus(statusCode) {\r\n this.statusCode = statusCode;\r\n\r\n return this;\r\n }\r\n\r\n /**\r\n * Sets additional error details based on an existing error object.\r\n *\r\n * @param {Error} error - An error object containing details to populate\r\n * the `ExportError` instance.\r\n *\r\n * @returns {ExportError} The updated instance of the `ExportError` class.\r\n */\r\n setError(error) {\r\n this.error = error;\r\n\r\n if (error.name) {\r\n this.name = error.name;\r\n }\r\n\r\n if (error.statusCode) {\r\n this.statusCode = error.statusCode;\r\n }\r\n\r\n if (error.stack) {\r\n this.stackMessage = error.message;\r\n this.stack = error.stack;\r\n }\r\n\r\n return this;\r\n }\r\n}\r\n\r\nexport default ExportError;\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * @overview Manages configuration for the Highcharts Export Server by loading\r\n * and merging options from multiple sources, such as default settings,\r\n * environment variables, user-provided options, and command-line arguments.\r\n * Ensures the global options are up-to-date with the highest priority values.\r\n * Provides functions for accessing and updating configuration.\r\n */\r\n\r\nimport { readFileSync } from 'fs';\r\nimport { join } from 'path';\r\n\r\nimport { log, logWithStack, logZodIssues } from './logger.js';\r\nimport { __dirname, isObject, deepCopy, getAbsolutePath } from './utils.js';\r\nimport {\r\n envs,\r\n looseValidate,\r\n strictValidate,\r\n validators\r\n} from './validation.js';\r\n\r\nimport { defaultConfig, nestedProps, absoluteProps } from './schemas/config.js';\r\n\r\nimport ExportError from './errors/ExportError.js';\r\n\r\n// Sets the global options with initial values from the default config\r\nconst globalOptions = _initGlobalOptions(defaultConfig);\r\n\r\n// An object for the instance options, created each time the `initExport` occurs\r\nconst instanceOptions = deepCopy(globalOptions);\r\n\r\n/**\r\n * Retrieves a reference to the options object. Depending on the `getInstance`\r\n * parameter, it returns either the global options or the instance-specific\r\n * options object.\r\n *\r\n * @function getOptions\r\n *\r\n * @param {boolean} [getInstance=true] - Optional parameter that decides whether\r\n * to return the instance-specific options (when `true`) or the global options\r\n * (when `false`). The default value is `true`.\r\n *\r\n * @returns {Object} A reference to either the global options\r\n * or the instance-specific options, based on the `getInstance` parameter.\r\n */\r\nexport function getOptions(getInstance = true) {\r\n return getInstance ? instanceOptions : globalOptions;\r\n}\r\n\r\n/**\r\n * Sets the global options of the export server, keeping the principle\r\n * of the options load priority from all available sources. It accepts optional\r\n * `customOptions` object and `cliArgs` array with arguments from the CLI. These\r\n * options will be validated and applied if provided.\r\n *\r\n * The priority order of setting values is:\r\n *\r\n * 1. Options from the `lib/schemas/config.js` file (default values).\r\n * 2. Options from a custom JSON file (loaded by the `loadConfig` option).\r\n * 3. Options from the environment variables (the `.env` file).\r\n * 4. Options from the command line interface (CLI).\r\n * 5. Options from the first parameter (the `customOptions` is by default\r\n * an empty object).\r\n *\r\n * @function setGlobalOptions\r\n *\r\n * @param {Object} [customOptions={}] - Optional custom options for additional\r\n * configuration. The default value is an empty object.\r\n * @param {Array.} [cliArgs=[]] - Optional command line arguments\r\n * for additional configuration. The default value is an empty array.\r\n *\r\n * @returns {Object} The updated global options object, reflecting the merged\r\n * configuration from all available sources.\r\n */\r\nexport function setGlobalOptions(customOptions = {}, cliArgs = []) {\r\n // Object for options loaded via the `loadConfig` option\r\n let configOptions = {};\r\n\r\n // Object for options from the CLI\r\n let cliOptions = {};\r\n\r\n // Only for the CLI usage\r\n if (cliArgs && Array.isArray(cliArgs) && cliArgs.length) {\r\n try {\r\n // Validate options from the custom JSON loaded via the `loadConfig`\r\n configOptions = strictValidate(\r\n _loadConfigFile(cliArgs, globalOptions.customLogic)\r\n );\r\n } catch (error) {\r\n logZodIssues(\r\n 1,\r\n error.issues,\r\n '[validation] Custom options from the `loadConfig` option validation error'\r\n );\r\n }\r\n\r\n try {\r\n // Validate options from the CLI\r\n cliOptions = looseValidate(_pairArgumentValue(nestedProps, cliArgs));\r\n } catch (error) {\r\n logZodIssues(\r\n 1,\r\n error.issues,\r\n '[validation] CLI options validation error'\r\n );\r\n }\r\n }\r\n\r\n // Apply custom options if there are any\r\n if (\r\n customOptions &&\r\n isObject(customOptions) &&\r\n Object.keys(customOptions).length\r\n ) {\r\n try {\r\n // Validate custom options provided by the user\r\n customOptions = strictValidate(customOptions);\r\n } catch (error) {\r\n logZodIssues(\r\n 1,\r\n error.issues,\r\n '[validation] Custom options validation error'\r\n );\r\n }\r\n }\r\n\r\n // Update values of the global options with values from each source possible\r\n _updateGlobalOptions(\r\n defaultConfig,\r\n globalOptions,\r\n configOptions,\r\n cliOptions,\r\n customOptions\r\n );\r\n\r\n // Return updated global options\r\n return globalOptions;\r\n}\r\n\r\n/**\r\n * Updates the instance options with additional options. It optionally allows\r\n * to reinitialize the instance options with the values of a current global\r\n * options object.\r\n *\r\n * @param {Object} updateOptions - The update options to merge into the instance\r\n * options.\r\n * @param {boolean} [newInstance=false] - A flag to indicate whether to init\r\n * options for a new instance. If `true`, the existing instance options will\r\n * be cleared and reinitialized based on the global options.\r\n *\r\n * @returns {Object} - The updated instance options.\r\n */\r\nexport function updateOptions(updateOptions, newInstance = false) {\r\n // Check if options need to be created for a new instance\r\n if (newInstance) {\r\n // Get rid of the old instance options\r\n Object.keys(instanceOptions).forEach((key) => {\r\n delete instanceOptions[key];\r\n });\r\n\r\n // Init the new instance options based on the global options\r\n mergeOptions(instanceOptions, deepCopy(globalOptions));\r\n }\r\n\r\n // Merge additional options to the instance options\r\n mergeOptions(instanceOptions, updateOptions);\r\n\r\n // Return the reference to the instance options object\r\n return instanceOptions;\r\n}\r\n\r\n/**\r\n * Merges two sets of configuration options, considering absolute properties.\r\n *\r\n * @function mergeOptions\r\n *\r\n * @param {Object} originalOptions - Original configuration options.\r\n * @param {Object} newOptions - New configuration options to be merged.\r\n *\r\n * @returns {Object} Merged configuration options.\r\n */\r\nexport function mergeOptions(originalOptions, newOptions) {\r\n // Check if the `originalOptions` and `newOptions` are correct objects\r\n if (isObject(originalOptions) && isObject(newOptions)) {\r\n for (const [key, value] of Object.entries(newOptions)) {\r\n originalOptions[key] =\r\n isObject(value) &&\r\n !absoluteProps.includes(key) &&\r\n originalOptions[key] !== undefined\r\n ? mergeOptions(originalOptions[key], value)\r\n : value !== undefined\r\n ? value\r\n : originalOptions[key] || null;\r\n }\r\n }\r\n\r\n // Return the original (modified or not) options\r\n return originalOptions;\r\n}\r\n\r\n/**\r\n * Maps old-structured configuration options (PhantomJS) to a new format\r\n * (Puppeteer). This function converts flat, old-structured options into\r\n * a new, nested configuration format based on a predefined mapping\r\n * (`nestedProps`). The new format is used for Puppeteer, while the old format\r\n * was used for PhantomJS.\r\n *\r\n * @function mapToNewOptions\r\n *\r\n * @param {Object} oldOptions - The old, flat configuration options\r\n * to be converted.\r\n *\r\n * @returns {Object} A new object containing options structured according\r\n * to the mapping defined in `nestedProps` or an empty object if the provided\r\n * `oldOptions` is not a correct object.\r\n */\r\nexport function mapToNewOptions(oldOptions) {\r\n // An object for the new structured options\r\n const newOptions = {};\r\n\r\n // Check if provided value is a correct object\r\n if (isObject(oldOptions)) {\r\n // Iterate over each key-value pair in the old-structured options\r\n for (const [key, value] of Object.entries(oldOptions)) {\r\n // If there is a nested mapping, split it into a properties chain\r\n const propertiesChain = nestedProps[key]\r\n ? nestedProps[key].split('.')\r\n : [];\r\n\r\n // If it is the last property in the chain, assign the value, otherwise,\r\n // create or reuse the nested object\r\n propertiesChain.reduce(\r\n (obj, prop, index) =>\r\n (obj[prop] =\r\n propertiesChain.length - 1 === index ? value : obj[prop] || {}),\r\n newOptions\r\n );\r\n }\r\n } else {\r\n log(\r\n 2,\r\n '[config] No correct object with options was provided. Returning an empty array.'\r\n );\r\n }\r\n\r\n // Return the new, structured options object\r\n return newOptions;\r\n}\r\n\r\n/**\r\n * Validates a specified option using the corresponding validator from the\r\n * configuration object. Returns the original option if the validation\r\n * is disabled globally.\r\n *\r\n * @function validateOption\r\n *\r\n * @param {string} name - The name of the option to validate.\r\n * @param {any} configOption - The value of the option to validate.\r\n * @param {boolean} [strictCheck=true] - Determines if stricter validation\r\n * should be applied. The default value is `true`.\r\n *\r\n * @returns {any} The parsed and validated value of the option.\r\n */\r\nexport function validateOption(name, configOption, strictCheck = true) {\r\n // Return the original option if the validation is disabled\r\n if (!getOptions().other.validation) {\r\n return configOption;\r\n }\r\n\r\n try {\r\n // Return validated option\r\n return validators[name](strictCheck).parse(configOption);\r\n } catch (error) {\r\n // Log Zod issues\r\n logZodIssues(\r\n 1,\r\n error.issues,\r\n `[validation] The ${name} option validation error`\r\n );\r\n\r\n // Throw validation error\r\n throw new ExportError(\r\n `[validation] The ${name} option validation error`,\r\n 400\r\n );\r\n }\r\n}\r\n\r\n/**\r\n * Validates the provided configuration options for the exporting process.\r\n * Returns the original option if the validation is disabled globally.\r\n *\r\n * @function validateOptions\r\n *\r\n * @param {Object} configOptions - The configuration options to be validated.\r\n * @param {boolean} [strictCheck=true] - Determines if stricter validation\r\n * should be applied. The default value is `true`.\r\n *\r\n * @returns {Object} The parsed and validated configuration options object.\r\n */\r\nexport function validateOptions(configOptions, strictCheck = true) {\r\n // Return the original config if the validation is disabled\r\n if (!getOptions().other.validation) {\r\n return configOptions;\r\n }\r\n\r\n try {\r\n // Return validated options\r\n return strictCheck\r\n ? strictValidate(configOptions)\r\n : looseValidate(configOptions);\r\n } catch (error) {\r\n // Log Zod issues\r\n logZodIssues(1, error.issues, '[validation] Options validation error');\r\n\r\n // Throw validation error\r\n throw new ExportError('[validation] Options validation error', 400);\r\n }\r\n}\r\n\r\n/**\r\n * Validates, parses, and checks if the provided config is allowed set\r\n * of options.\r\n *\r\n * @function isAllowedConfig\r\n *\r\n * @param {unknown} config - The config to be validated and parsed as a set\r\n * of options. Must be either an object or a string.\r\n * @param {boolean} [toString=false] - Whether to return a stringified version\r\n * of the parsed config. The default value is `false`.\r\n * @param {boolean} [allowFunctions=false] - Whether to allow functions\r\n * in the parsed config. If true, functions are preserved. Otherwise, when\r\n * a function is found, null is returned. The default value is `false`.\r\n *\r\n * @returns {(Object|string|null)} Returns a parsed set of options object,\r\n * a stringified set of options object if the `toString` is true, and null\r\n * if the config is not a valid set of options or parsing fails.\r\n */\r\nexport function isAllowedConfig(\r\n config,\r\n toString = false,\r\n allowFunctions = false\r\n) {\r\n try {\r\n // Accept only objects and strings\r\n if (!isObject(config) && typeof config !== 'string') {\r\n // Return null if any other type\r\n return null;\r\n }\r\n\r\n // Get the object representation of the original config\r\n const objectConfig =\r\n typeof config === 'string'\r\n ? allowFunctions\r\n ? eval(`(${config})`)\r\n : JSON.parse(config)\r\n : config;\r\n\r\n // Preserve or remove potential functions based on the `allowFunctions` flag\r\n const stringifiedOptions = _optionsStringify(\r\n objectConfig,\r\n allowFunctions,\r\n false\r\n );\r\n\r\n // Parse the config to check if it is valid set of options\r\n const parsedOptions = allowFunctions\r\n ? JSON.parse(\r\n _optionsStringify(objectConfig, allowFunctions, true),\r\n (_, value) =>\r\n typeof value === 'string' && value.startsWith('function')\r\n ? eval(`(${value})`)\r\n : value\r\n )\r\n : JSON.parse(stringifiedOptions);\r\n\r\n // Return stringified or object options based on the `toString` flag\r\n return toString ? stringifiedOptions : parsedOptions;\r\n } catch (error) {\r\n // Return null if parsing fails\r\n return null;\r\n }\r\n}\r\n\r\n/**\r\n * Prints the Highcharts Export Server logo, version, and license information.\r\n *\r\n * @function printLicense\r\n */\r\nexport function printLicense() {\r\n // Print the logo and version information\r\n printVersion();\r\n\r\n // Print the license information\r\n console.log(\r\n 'This software requires a valid Highcharts license for commercial use.\\n'\r\n .yellow,\r\n '\\nFor a full list of CLI options, type:',\r\n '\\nhighcharts-export-server --help\\n'.green,\r\n '\\nIf you do not have a license, one can be obtained here:',\r\n '\\nhttps://shop.highsoft.com/\\n'.green,\r\n '\\nTo customize your installation, please refer to the README file at:',\r\n '\\nhttps://github.com/highcharts/node-export-server#readme\\n'.green\r\n );\r\n}\r\n\r\n/**\r\n * Prints usage information for CLI arguments, displaying available options\r\n * and their descriptions. It can list properties recursively if categories\r\n * contain nested options.\r\n *\r\n * @function printUsage\r\n */\r\nexport function printUsage() {\r\n // Display README and general usage information\r\n console.log(\r\n '\\nUsage of CLI arguments:'.bold,\r\n '\\n-----------------------',\r\n `\\nFor more detailed information, visit the README file at: ${'https://github.com/highcharts/node-export-server#readme'.green}.\\n`\r\n );\r\n\r\n // Iterate through each category in the `defaultConfig` and display usage info\r\n Object.keys(defaultConfig).forEach((category) => {\r\n console.log(`${category.toUpperCase()}`.bold.red);\r\n _cycleCategories(defaultConfig[category]);\r\n console.log('');\r\n });\r\n}\r\n\r\n/**\r\n * Prints the Highcharts Export Server logo or text with the version\r\n * information.\r\n *\r\n * @function printVersion\r\n *\r\n * @param {boolean} [noLogo=false] - If true, only prints text with the version\r\n * information, without the logo. The default value is `false`.\r\n */\r\nexport function printVersion(noLogo = false) {\r\n // Get package version either from `.env` or from `package.json`\r\n const packageVersion = JSON.parse(\r\n readFileSync(join(__dirname, 'package.json'), 'utf8')\r\n ).version;\r\n\r\n // Print text only\r\n if (noLogo) {\r\n console.log(`Highcharts Export Server v${packageVersion}`);\r\n } else {\r\n // Print the logo\r\n console.log(\r\n readFileSync(join(__dirname, 'msg', 'startup.msg'), 'utf8').toString()\r\n .bold.yellow,\r\n `v${packageVersion}\\n`.bold\r\n );\r\n }\r\n}\r\n\r\n/**\r\n * Initializes and returns global options object based on provided\r\n * configuration, setting values from nested properties recursively.\r\n *\r\n * @function _initGlobalOptions\r\n *\r\n * @param {Object} config - The configuration object to be used for initializing\r\n * options.\r\n *\r\n * @returns {Object} Initialized options object.\r\n */\r\nfunction _initGlobalOptions(config) {\r\n const options = {};\r\n\r\n // Start initializing the `options` object recursively\r\n for (const [name, item] of Object.entries(config)) {\r\n if (Object.prototype.hasOwnProperty.call(item, 'value')) {\r\n // If a value from environment variables exists, it takes precedence\r\n const envVal = envs[item.envLink];\r\n if (envVal !== undefined && envVal !== null) {\r\n options[name] = envVal;\r\n } else {\r\n options[name] = item.value;\r\n }\r\n } else {\r\n options[name] = _initGlobalOptions(item);\r\n }\r\n }\r\n\r\n // Return the created `options` object\r\n return options;\r\n}\r\n\r\n/**\r\n * Updates global options object with values from various sources, following\r\n * a specific prioritization order. The function checks for values in the order\r\n * of precedence: the `loadConfig` configuration options, environment variables,\r\n * custom options, and CLI options.\r\n *\r\n * @function _updateGlobalOptions\r\n *\r\n * @param {Object} config - The configuration object, which includes the initial\r\n * settings and metadata for each option. This object is used to determine\r\n * the structure and default values for the options.\r\n * @param {Object} options - The global options object that will be updated\r\n * with values from other sources.\r\n * @param {Object} configOpt - The configuration options object, loaded with\r\n * the `loadConfig` option, which may provide values to override defaults.\r\n * @param {Object} cliOpt - The CLI options object, which may include values\r\n * provided through command-line arguments and may override configuration\r\n * options.\r\n * @param {Object} customOpt - The custom options object, typically containing\r\n * additional and user-defined values, which has the highest precedence among\r\n * options.\r\n */\r\nfunction _updateGlobalOptions(config, options, configOpt, cliOpt, customOpt) {\r\n Object.keys(config).forEach((key) => {\r\n // Get the config entry of a specific option\r\n const entry = config[key];\r\n\r\n // Gather values for the options from every possible source, if exists\r\n const configVal = configOpt && configOpt[key];\r\n const cliVal = cliOpt && cliOpt[key];\r\n const customVal = customOpt && customOpt[key];\r\n\r\n // If the value not found, need to go deeper\r\n if (typeof entry.value === 'undefined') {\r\n _updateGlobalOptions(entry, options[key], configVal, cliVal, customVal);\r\n } else {\r\n // If a value from custom JSON options exists, it takes precedence\r\n if (configVal !== undefined && configVal !== null) {\r\n options[key] = configVal;\r\n }\r\n\r\n // If a value from environment variables exists, it takes precedence\r\n const envVal = envs[entry.envLink];\r\n if (entry.envLink in envs && envVal !== undefined && envVal !== null) {\r\n options[key] = envVal;\r\n }\r\n\r\n // If a value from CLI options exists, it takes precedence\r\n if (cliVal !== undefined && cliVal !== null) {\r\n options[key] = cliVal;\r\n }\r\n\r\n // If a value from user options exists, it takes precedence\r\n if (customVal !== undefined && customVal !== null) {\r\n options[key] = customVal;\r\n }\r\n }\r\n });\r\n}\r\n\r\n/**\r\n * Converts the provided options object to a JSON-formatted string\r\n * with the option to preserve functions. In order for a function\r\n * to be preserved, it needs to follow the format `function (...) {...}`.\r\n * Such a function can also be stringified.\r\n *\r\n * @function _optionsStringify\r\n *\r\n * @param {Object} options - The options object to be converted to a string.\r\n * @param {boolean} allowFunctions - If set to true, functions are preserved\r\n * in the output. Otherwise an error is thrown.\r\n * @param {boolean} stringifyFunctions - If set to true, functions are saved\r\n * as strings. The `allowFunctions` must be set to true as well for this to take\r\n * an effect.\r\n *\r\n * @returns {string} The JSON-formatted string representing the options.\r\n *\r\n * @throws {Error} Throws an `Error` when functions are not allowed but are\r\n * found in provided options object.\r\n */\r\nexport function _optionsStringify(options, allowFunctions, stringifyFunctions) {\r\n const replacerCallback = (_, value) => {\r\n // Trim string values\r\n if (typeof value === 'string') {\r\n value = value.trim();\r\n }\r\n\r\n // If value is a function or stringified function\r\n if (\r\n typeof value === 'function' ||\r\n (typeof value === 'string' &&\r\n value.startsWith('function') &&\r\n value.endsWith('}'))\r\n ) {\r\n // If allowFunctions is set to true, preserve functions\r\n if (allowFunctions) {\r\n // Based on the `stringifyFunctions` options, set function values\r\n return stringifyFunctions\r\n ? // As stringified functions\r\n `\"EXP_FUN${(value + '').replaceAll(/\\s+/g, ' ')}EXP_FUN\"`\r\n : // As functions\r\n `EXP_FUN${(value + '').replaceAll(/\\s+/g, ' ')}EXP_FUN`;\r\n } else {\r\n // Throw an error otherwise\r\n throw new Error();\r\n }\r\n }\r\n\r\n // In all other cases, simply return the value\r\n return value;\r\n };\r\n\r\n // Stringify options and if required, replace special functions marks\r\n return JSON.stringify(options, replacerCallback).replaceAll(\r\n stringifyFunctions ? /\\\\\"EXP_FUN|EXP_FUN\\\\\"/g : /\"EXP_FUN|EXP_FUN\"/g,\r\n ''\r\n );\r\n}\r\n\r\n/**\r\n * Loads additional configuration from a specified file provided via\r\n * the `loadConfig` option in the command-line arguments.\r\n *\r\n * @function _loadConfigFile\r\n *\r\n * @param {Array.} cliArgs - Command-line arguments to search\r\n * for the `loadConfig` option and the corresponding file path.\r\n * @param {Object} customLogicOptions - The configuration object containing\r\n * `customLogic` options.\r\n *\r\n * @returns {Object} The additional configuration loaded from the specified\r\n * file, or an empty object if the file is not found, invalid, or an error\r\n * occurs.\r\n */\r\nfunction _loadConfigFile(cliArgs, customLogicOptions) {\r\n // Check if the `loadConfig` option was used\r\n const configIndex = cliArgs.findIndex(\r\n (arg) => arg.replace(/-/g, '') === 'loadConfig'\r\n );\r\n\r\n // Get the `loadConfig` option value\r\n const configFileName = configIndex > -1 && cliArgs[configIndex + 1];\r\n\r\n // Check if the `loadConfig` is present and has a correct value\r\n if (configFileName && customLogicOptions.allowFileResources) {\r\n try {\r\n // Load an optional custom JSON config file\r\n return isAllowedConfig(\r\n readFileSync(getAbsolutePath(configFileName), 'utf8'),\r\n false,\r\n customLogicOptions.allowCodeExecution\r\n );\r\n } catch (error) {\r\n logWithStack(\r\n 2,\r\n error,\r\n `[config] Unable to load the configuration from the ${configFileName} file.`\r\n );\r\n }\r\n }\r\n\r\n // No additional options to return\r\n return {};\r\n}\r\n\r\n/**\r\n * Parses command-line arguments and pairs each argument with its corresponding\r\n * option in the configuration. The values are structured into a nested options\r\n * object, based on predefined mappings.\r\n *\r\n * @function _pairArgumentValue\r\n *\r\n * @param {Array.} nestedProps - An array of nesting level for all\r\n * options.\r\n * @param {Array.} cliArgs - An array of command-line arguments\r\n * containing options and their associated values.\r\n *\r\n * @returns {Object} An updated options object where each option from\r\n * the command-line is paired with its value, structured into nested objects\r\n * as defined.\r\n */\r\nfunction _pairArgumentValue(nestedProps, cliArgs) {\r\n // An empty object to collect and structurize data from the args\r\n const cliOptions = {};\r\n\r\n // Cycle through all CLI args and filter them\r\n for (let i = 0; i < cliArgs.length; i++) {\r\n const option = cliArgs[i].replace(/-/g, '');\r\n\r\n // Find the right place for property's value\r\n const propertiesChain = nestedProps[option]\r\n ? nestedProps[option].split('.')\r\n : [];\r\n\r\n // Create options object with values from CLI for later parsing and merging\r\n propertiesChain.reduce((obj, prop, index) => {\r\n if (propertiesChain.length - 1 === index) {\r\n const value = cliArgs[++i];\r\n if (!value) {\r\n log(\r\n 2,\r\n `[config] Missing value for the CLI '--${option}' argument. Using the default value.`\r\n );\r\n }\r\n obj[prop] = value || null;\r\n } else if (obj[prop] === undefined) {\r\n obj[prop] = {};\r\n }\r\n return obj[prop];\r\n }, cliOptions);\r\n }\r\n\r\n // Return parsed CLI options\r\n return cliOptions;\r\n}\r\n\r\n/**\r\n * Recursively traverses the options object to print the usage information\r\n * for each option category and individual option.\r\n *\r\n * @function _cycleCategories\r\n *\r\n * @param {Object} options - The options object containing CLI options. It may\r\n * include nested categories and individual options.\r\n */\r\nfunction _cycleCategories(options) {\r\n for (const [name, option] of Object.entries(options)) {\r\n // If the current entry is a category and not a leaf option, recurse into it\r\n if (!Object.prototype.hasOwnProperty.call(option, 'value')) {\r\n _cycleCategories(option);\r\n } else {\r\n // Prepare description\r\n const descName = ` --${option.cliName || name}`;\r\n\r\n // Get the value\r\n let optionValue = option.value;\r\n\r\n // Prepare value for option that is not null and is array of strings\r\n if (optionValue !== null && option.types.includes('string[]')) {\r\n optionValue =\r\n '[' + optionValue.map((item) => `'${item}'`).join(', ') + ']';\r\n }\r\n\r\n // Prepare value for option that is not null and is a string\r\n if (optionValue !== null && option.types.includes('string')) {\r\n optionValue = `'${optionValue}'`;\r\n }\r\n\r\n // Display correctly aligned messages\r\n console.log(\r\n descName.green,\r\n `${('<' + option.types.join('|') + '>').yellow}`,\r\n `${String(optionValue).bold}`.blue,\r\n `- ${option.description}.`\r\n );\r\n }\r\n }\r\n}\r\n\r\nexport default {\r\n getOptions,\r\n setGlobalOptions,\r\n updateOptions,\r\n mergeOptions,\r\n mapToNewOptions,\r\n validateOption,\r\n validateOptions,\r\n isAllowedConfig,\r\n printLicense,\r\n printUsage,\r\n printVersion\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * @overview HTTP utility module for fetching and posting data. Supports both\r\n * HTTP and HTTPS protocols, providing methods to make GET and POST requests\r\n * with customizable options. Includes protocol determination based on URL\r\n * and augments response objects with a 'text' property for easier data access.\r\n */\r\n\r\nimport http from 'http';\r\nimport https from 'https';\r\n\r\n/**\r\n * Fetches data from the specified URL using either HTTP or HTTPS protocol.\r\n *\r\n * @async\r\n * @function fetch\r\n *\r\n * @param {string} url - The URL to fetch data from.\r\n * @param {Object} [requestOptions={}] - Options for the HTTP/HTTPS request.\r\n * The default value is an empty object.\r\n *\r\n * @returns {Promise} A Promise that resolves to the HTTP/HTTPS response\r\n * object with added 'text' property or rejecting with an error.\r\n */\r\nexport async function fetch(url, requestOptions = {}) {\r\n return new Promise((resolve, reject) => {\r\n _getProtocolModule(url)\r\n .get(url, requestOptions, (response) => {\r\n let responseData = '';\r\n\r\n // A chunk of data has been received\r\n response.on('data', (chunk) => {\r\n responseData += chunk;\r\n });\r\n\r\n // The whole response has been received\r\n response.on('end', () => {\r\n if (!responseData) {\r\n reject('Nothing was fetched from the URL.');\r\n }\r\n response.text = responseData;\r\n resolve(response);\r\n });\r\n })\r\n .on('error', (error) => {\r\n reject(error);\r\n });\r\n });\r\n}\r\n\r\n/**\r\n * Sends a POST request to the specified URL with the provided JSON body using\r\n * either HTTP or HTTPS protocol.\r\n *\r\n * @async\r\n * @function post\r\n *\r\n * @param {string} url - The URL to send the POST request to.\r\n * @param {Object} [body={}] - The JSON body to include in the POST request.\r\n * The default value is an empty object.\r\n * @param {Object} [requestOptions={}] - Options for the HTTP/HTTPS request.\r\n * The default value is an empty object.\r\n *\r\n * @returns {Promise} A Promise that resolves to the HTTP/HTTPS response\r\n * object with added 'text' property or rejecting with an error.\r\n */\r\nexport async function post(url, body = {}, requestOptions = {}) {\r\n return new Promise((resolve, reject) => {\r\n const data = JSON.stringify(body);\r\n\r\n // Set default headers and merge with requestOptions\r\n const options = Object.assign(\r\n {\r\n method: 'POST',\r\n headers: {\r\n 'Content-Type': 'application/json',\r\n 'Content-Length': data.length\r\n }\r\n },\r\n requestOptions\r\n );\r\n\r\n const request = _getProtocolModule(url)\r\n .request(url, options, (response) => {\r\n let responseData = '';\r\n\r\n // A chunk of data has been received\r\n response.on('data', (chunk) => {\r\n responseData += chunk;\r\n });\r\n\r\n // The whole response has been received\r\n response.on('end', () => {\r\n try {\r\n response.text = responseData;\r\n resolve(response);\r\n } catch (error) {\r\n reject(error);\r\n }\r\n });\r\n })\r\n .on('error', (error) => {\r\n reject(error);\r\n });\r\n\r\n // Write the request body and end the request\r\n request.write(data);\r\n request.end();\r\n });\r\n}\r\n\r\n/**\r\n * Returns the HTTP or HTTPS protocol module based on the provided URL.\r\n *\r\n * @function _getProtocolModule\r\n *\r\n * @param {string} url - The URL to determine the protocol.\r\n *\r\n * @returns {Object} The HTTP or HTTPS protocol module (http or https).\r\n */\r\nfunction _getProtocolModule(url) {\r\n return url.startsWith('https') ? https : http;\r\n}\r\n\r\nexport default {\r\n fetch,\r\n post\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * @overview The cache manager is responsible for handling and managing\r\n * the Highcharts library along with its dependencies. It ensures that these\r\n * resources are stored and retrieved efficiently to optimize performance\r\n * and reduce redundant network requests. The cache is stored in the `.cache`\r\n * directory by default, which serves as a dedicated folder for keeping cached\r\n * files.\r\n */\r\n\r\nimport { existsSync, mkdirSync, readFileSync, writeFileSync } from 'fs';\r\nimport { join } from 'path';\r\n\r\nimport { HttpsProxyAgent } from 'https-proxy-agent';\r\n\r\nimport { getOptions } from './config.js';\r\nimport { fetch } from './fetch.js';\r\nimport { log } from './logger.js';\r\nimport { __dirname, getAbsolutePath } from './utils.js';\r\n\r\nimport ExportError from './errors/ExportError.js';\r\n\r\n// The initial cache template\r\nconst cache = {\r\n cdnUrl: 'https://code.highcharts.com',\r\n activeManifest: {},\r\n sources: '',\r\n hcVersion: ''\r\n};\r\n\r\n/**\r\n * Checks the cache for Highcharts dependencies, updates the cache if needed,\r\n * and loads the sources.\r\n *\r\n * @async\r\n * @function checkAndUpdateCache\r\n *\r\n * @param {Object} highchartsOptions - The configuration object containing\r\n * `highcharts` options.\r\n * @param {Object} serverProxyOptions- The configuration object containing\r\n * `server.proxy` options.\r\n */\r\nexport async function checkAndUpdateCache(\r\n highchartsOptions,\r\n serverProxyOptions\r\n) {\r\n try {\r\n let fetchedModules;\r\n\r\n // Get the cache path\r\n const cachePath = getCachePath();\r\n\r\n // Prepare paths to manifest and sources from the cache folder\r\n const manifestPath = join(cachePath, 'manifest.json');\r\n const sourcePath = join(cachePath, 'sources.js');\r\n\r\n // Create the cache destination if it doesn't exist already\r\n !existsSync(cachePath) && mkdirSync(cachePath, { recursive: true });\r\n\r\n // Fetch all the scripts either if the `manifest.json` does not exist\r\n // or if the `forceFetch` option is enabled\r\n if (!existsSync(manifestPath) || highchartsOptions.forceFetch) {\r\n log(3, '[cache] Fetching and caching Highcharts dependencies.');\r\n fetchedModules = await _updateCache(\r\n highchartsOptions,\r\n serverProxyOptions,\r\n sourcePath\r\n );\r\n } else {\r\n let requestUpdate = false;\r\n\r\n // Read the manifest JSON\r\n const manifest = JSON.parse(readFileSync(manifestPath), 'utf8');\r\n\r\n // Check if the modules is an array, if so, we rewrite it to a map to make\r\n // it easier to resolve modules.\r\n if (manifest.modules && Array.isArray(manifest.modules)) {\r\n const moduleMap = {};\r\n manifest.modules.forEach((m) => (moduleMap[m] = 1));\r\n manifest.modules = moduleMap;\r\n }\r\n\r\n // Get the actual number of scripts to be fetched\r\n const { coreScripts, moduleScripts, indicatorScripts } =\r\n highchartsOptions;\r\n const numberOfModules =\r\n coreScripts.length + moduleScripts.length + indicatorScripts.length;\r\n\r\n // Compare the loaded highcharts config with the contents in cache.\r\n // If there are changes, fetch requested modules and products,\r\n // and bake them into a giant blob. Save the blob.\r\n if (manifest.version !== highchartsOptions.version) {\r\n log(\r\n 2,\r\n '[cache] A Highcharts version mismatch in the cache, need to re-fetch.'\r\n );\r\n requestUpdate = true;\r\n } else if (\r\n Object.keys(manifest.modules || {}).length !== numberOfModules\r\n ) {\r\n log(\r\n 2,\r\n '[cache] The cache and the requested modules do not match, need to re-fetch.'\r\n );\r\n requestUpdate = true;\r\n } else {\r\n // Check each module, if anything is missing refetch everything\r\n requestUpdate = (moduleScripts || []).some((moduleName) => {\r\n if (!manifest.modules[moduleName]) {\r\n log(\r\n 2,\r\n `[cache] The ${moduleName} is missing in the cache, need to re-fetch.`\r\n );\r\n return true;\r\n }\r\n });\r\n }\r\n\r\n // Update cache if needed\r\n if (requestUpdate) {\r\n fetchedModules = await _updateCache(\r\n highchartsOptions,\r\n serverProxyOptions,\r\n sourcePath\r\n );\r\n } else {\r\n log(3, '[cache] Dependency cache is up to date, proceeding.');\r\n\r\n // Load the sources\r\n cache.sources = readFileSync(sourcePath, 'utf8');\r\n\r\n // Get current modules map\r\n fetchedModules = manifest.modules;\r\n\r\n // Extract and save version of currently used Highcharts\r\n cache.hcVersion = extractVersion(cache.sources);\r\n }\r\n }\r\n\r\n // Finally, save the new manifest, which is basically our current config\r\n // in a slightly different format\r\n await _saveConfigToManifest(highchartsOptions, fetchedModules);\r\n } catch (error) {\r\n throw new ExportError(\r\n '[cache] Could not configure cache and create or update the config manifest.',\r\n 500\r\n ).setError(error);\r\n }\r\n}\r\n\r\n/**\r\n * Gets the version of Highcharts from the cache.\r\n *\r\n * @function getHighchartsVersion\r\n *\r\n * @returns {string} The cached Highcharts version.\r\n */\r\nexport function getHighchartsVersion() {\r\n return cache.hcVersion;\r\n}\r\n\r\n/**\r\n * Updates the Highcharts version in the applied configuration and checks\r\n * the cache for the new version.\r\n *\r\n * @async\r\n * @function updateHighchartsVersion\r\n *\r\n * @param {string} newVersion - The new Highcharts version to be applied.\r\n */\r\nexport async function updateHighchartsVersion(newVersion) {\r\n // Get the reference to the global options to update to the new version\r\n const options = getOptions();\r\n\r\n // Set to the new version\r\n options.highcharts.version = newVersion;\r\n\r\n // Check if cache needs to be updated\r\n await checkAndUpdateCache(options.highcharts, options.server.proxy);\r\n}\r\n\r\n/**\r\n * Extracts Highcharts version from the cache's sources string.\r\n *\r\n * @function extractVersion\r\n *\r\n * @param {Object} cacheSources - The cache sources object.\r\n *\r\n * @returns {string} The extracted Highcharts version.\r\n */\r\nexport function extractVersion(cacheSources) {\r\n return cacheSources\r\n .substring(0, cacheSources.indexOf('*/'))\r\n .replace('/*', '')\r\n .replace('*/', '')\r\n .replace(/\\n/g, '')\r\n .trim();\r\n}\r\n\r\n/**\r\n * Extracts the Highcharts module name based on the scriptPath.\r\n *\r\n * @function extractModuleName\r\n *\r\n * @param {string} scriptPath - The path of the script from which the module\r\n * name will be extracted.\r\n *\r\n * @returns {string} The extracted module name.\r\n */\r\nexport function extractModuleName(scriptPath) {\r\n return scriptPath.replace(\r\n /(.*)\\/|(.*)modules\\/|stock\\/(.*)indicators\\/|maps\\/(.*)modules\\//gi,\r\n ''\r\n );\r\n}\r\n\r\n/**\r\n * Retrieves the current cache object.\r\n *\r\n * @function getCache\r\n *\r\n * @returns {Object} The cache object containing various cached data.\r\n */\r\nexport function getCache() {\r\n return cache;\r\n}\r\n\r\n/**\r\n * Gets the cache path for Highcharts.\r\n *\r\n * @function getCachePath\r\n *\r\n * @returns {string} The absolute path to the cache directory for Highcharts.\r\n */\r\nexport function getCachePath() {\r\n return getAbsolutePath(getOptions().highcharts.cachePath, 'utf8'); // #562\r\n}\r\n\r\n/**\r\n * Fetches a single script and updates the `fetchedModules` accordingly.\r\n *\r\n * @async\r\n * @function _fetchAndProcessScript\r\n *\r\n * @param {string} script - A path to script to get.\r\n * @param {Object} requestOptions - Additional options for the proxy agent\r\n * to use for a request.\r\n * @param {Object} fetchedModules - An object which tracks which Highcharts\r\n * modules have been fetched.\r\n * @param {boolean} [shouldThrowError=false] - A flag to indicate if the error\r\n * should be thrown. This should be used only for the core scripts. The default\r\n * value is `false`.\r\n *\r\n * @returns {Promise} A Promise that resolves to the text representation\r\n * of the fetched script.\r\n *\r\n * @throws {ExportError} Throws an `ExportError` if there is a problem\r\n * with fetching the script.\r\n */\r\nasync function _fetchAndProcessScript(\r\n script,\r\n requestOptions,\r\n fetchedModules,\r\n shouldThrowError = false\r\n) {\r\n // Get rid of the .js from the custom strings\r\n if (script.endsWith('.js')) {\r\n script = script.substring(0, script.length - 3);\r\n }\r\n log(4, `[cache] Fetching script - ${script}.js`);\r\n\r\n // Fetch the script\r\n const response = await fetch(`${script}.js`, requestOptions);\r\n\r\n // If OK, return its text representation\r\n if (response.statusCode === 200 && typeof response.text == 'string') {\r\n if (fetchedModules) {\r\n const moduleName = extractModuleName(script);\r\n fetchedModules[moduleName] = 1;\r\n }\r\n return response.text;\r\n }\r\n\r\n // Based on the `shouldThrowError` flag, decide how to serve error message\r\n if (shouldThrowError) {\r\n throw new ExportError(\r\n `[cache] Could not fetch the ${script}.js. The script might not exist in the requested version (status code: ${response.statusCode}).`,\r\n 404\r\n ).setError(response);\r\n } else {\r\n log(\r\n 2,\r\n `[cache] Could not fetch the ${script}.js. The script might not exist in the requested version.`\r\n );\r\n }\r\n}\r\n\r\n/**\r\n * Saves the provided configuration and fetched modules to the cache manifest\r\n * file.\r\n *\r\n * @async\r\n * @function _saveConfigToManifest\r\n *\r\n * @param {Object} highchartsOptions - The configuration object containing\r\n * `highcharts` options.\r\n * @param {Object} [fetchedModules={}] - An object which tracks which Highcharts\r\n * modules have been fetched. The default value is an empty object.\r\n *\r\n * @throws {ExportError} Throws an `ExportError` if an error occurs while\r\n * writing the cache manifest.\r\n */\r\nasync function _saveConfigToManifest(highchartsOptions, fetchedModules = {}) {\r\n const newManifest = {\r\n version: highchartsOptions.version,\r\n modules: fetchedModules\r\n };\r\n\r\n // Update cache object with the current modules\r\n cache.activeManifest = newManifest;\r\n\r\n log(3, '[cache] Writing a new manifest.');\r\n try {\r\n writeFileSync(\r\n join(getCachePath(), 'manifest.json'),\r\n JSON.stringify(newManifest),\r\n 'utf8'\r\n );\r\n } catch (error) {\r\n throw new ExportError(\r\n '[cache] Error writing the cache manifest.',\r\n 500\r\n ).setError(error);\r\n }\r\n}\r\n\r\n/**\r\n * Fetches Highcharts `scripts` and `customScripts` from the given CDNs.\r\n *\r\n * @async\r\n * @function _fetchScripts\r\n *\r\n * @param {Array.} coreScripts - Highcharts core scripts to fetch.\r\n * @param {Array.} moduleScripts - Highcharts modules to fetch.\r\n * @param {Array.} customScripts - Custom script paths to fetch (full\r\n * URLs).\r\n * @param {Object} serverProxyOptions - The configuration object containing\r\n * `server.proxy` options.\r\n * @param {Object} fetchedModules - An object which tracks which Highcharts\r\n * modules have been fetched.\r\n *\r\n * @returns {Promise} A Promise that resolves to the fetched scripts\r\n * content joined.\r\n *\r\n * @throws {ExportError} Throws an `ExportError` if an error occurs while\r\n * setting an HTTP Agent for proxy.\r\n */\r\nasync function _fetchScripts(\r\n coreScripts,\r\n moduleScripts,\r\n customScripts,\r\n serverProxyOptions,\r\n fetchedModules\r\n) {\r\n // Configure proxy if exists\r\n let proxyAgent;\r\n const proxyHost = serverProxyOptions.host;\r\n const proxyPort = serverProxyOptions.port;\r\n\r\n // Try to create a Proxy Agent\r\n if (proxyHost && proxyPort) {\r\n try {\r\n proxyAgent = new HttpsProxyAgent({\r\n host: proxyHost,\r\n port: proxyPort\r\n });\r\n } catch (error) {\r\n throw new ExportError(\r\n '[cache] Could not create a Proxy Agent.',\r\n 500\r\n ).setError(error);\r\n }\r\n }\r\n\r\n // If exists, add proxy agent to request options\r\n const requestOptions = proxyAgent\r\n ? {\r\n agent: proxyAgent,\r\n timeout: serverProxyOptions.timeout\r\n }\r\n : {};\r\n\r\n const allFetchPromises = [\r\n ...coreScripts.map((script) =>\r\n _fetchAndProcessScript(`${script}`, requestOptions, fetchedModules, true)\r\n ),\r\n ...moduleScripts.map((script) =>\r\n _fetchAndProcessScript(`${script}`, requestOptions, fetchedModules)\r\n ),\r\n ...customScripts.map((script) =>\r\n _fetchAndProcessScript(`${script}`, requestOptions)\r\n )\r\n ];\r\n\r\n const fetchedScripts = await Promise.all(allFetchPromises);\r\n return fetchedScripts.join(';\\n');\r\n}\r\n\r\n/**\r\n * Updates the local cache with Highcharts scripts and their versions.\r\n *\r\n * @async\r\n * @function _updateCache\r\n *\r\n * @param {Object} highchartsOptions - The configuration object containing\r\n * `highcharts` options.\r\n * @param {Object} serverProxyOptions - The configuration object containing\r\n * `server.proxy` options.\r\n * @param {string} sourcePath - The path to the source file in the cache.\r\n *\r\n * @returns {Promise} A Promise that resolves to an object representing\r\n * the fetched modules.\r\n *\r\n * @throws {ExportError} Throws an `ExportError` if there is an issue updating\r\n * the local Highcharts cache.\r\n */\r\nasync function _updateCache(highchartsOptions, serverProxyOptions, sourcePath) {\r\n // Get Highcharts version for scripts\r\n const hcVersion =\r\n highchartsOptions.version === 'latest'\r\n ? null\r\n : `${highchartsOptions.version}`;\r\n\r\n // Get the CDN url for scripts\r\n const cdnUrl = highchartsOptions.cdnUrl || cache.cdnUrl;\r\n\r\n try {\r\n const fetchedModules = {};\r\n\r\n log(\r\n 3,\r\n `[cache] Updating cache version to Highcharts: ${hcVersion || 'latest'}.`\r\n );\r\n\r\n cache.sources = await _fetchScripts(\r\n [\r\n ...highchartsOptions.coreScripts.map((c) =>\r\n hcVersion ? `${cdnUrl}/${hcVersion}/${c}` : `${cdnUrl}/${c}`\r\n )\r\n ],\r\n [\r\n ...highchartsOptions.moduleScripts.map((m) =>\r\n m === 'map'\r\n ? hcVersion\r\n ? `${cdnUrl}/maps/${hcVersion}/modules/${m}`\r\n : `${cdnUrl}/maps/modules/${m}`\r\n : hcVersion\r\n ? `${cdnUrl}/${hcVersion}/modules/${m}`\r\n : `${cdnUrl}/modules/${m}`\r\n ),\r\n ...highchartsOptions.indicatorScripts.map((i) =>\r\n hcVersion\r\n ? `${cdnUrl}/stock/${hcVersion}/indicators/${i}`\r\n : `${cdnUrl}/stock/indicators/${i}`\r\n )\r\n ],\r\n highchartsOptions.customScripts,\r\n serverProxyOptions,\r\n fetchedModules\r\n );\r\n\r\n // Extract and save version of currently used Highcharts\r\n cache.hcVersion = extractVersion(cache.sources);\r\n\r\n // Save the fetched modules into caches' source JSON\r\n writeFileSync(sourcePath, cache.sources);\r\n return fetchedModules;\r\n } catch (error) {\r\n throw new ExportError(\r\n '[cache] Unable to update the local Highcharts cache.',\r\n 500\r\n ).setError(error);\r\n }\r\n}\r\n\r\nexport default {\r\n checkAndUpdateCache,\r\n getHighchartsVersion,\r\n updateHighchartsVersion,\r\n extractVersion,\r\n extractModuleName,\r\n getCache,\r\n getCachePath\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * @overview Provides methods for initializing Highcharts with customized\r\n * animation settings and triggering the creation of Highcharts charts with\r\n * export-specific configurations in the page context. Supports dynamic option\r\n * merging, custom logic injection, and control over rendering behaviors. Used\r\n * by the Puppeteer page.\r\n */\r\n\r\n/* eslint-disable no-undef */\r\n\r\n/**\r\n * Setting the `Highcharts.animObject` function. Called when initing the page.\r\n *\r\n * @function setupHighcharts\r\n */\r\nexport function setupHighcharts() {\r\n Highcharts.animObject = function () {\r\n return { duration: 0 };\r\n };\r\n}\r\n\r\n/**\r\n * Creates the actual Highcharts chart on a page.\r\n *\r\n * @async\r\n * @function createChart\r\n *\r\n * @param {Object} exportOptions - The configuration object containing `export`\r\n * options.\r\n * @param {Object} customLogicOptions - The configuration object containing\r\n * `customLogic` options.\r\n *\r\n */\r\nexport async function createChart(exportOptions, customLogicOptions) {\r\n // Get required functions\r\n const { getOptions, setOptions, merge, wrap } = Highcharts;\r\n\r\n // Create a separate object for a potential `setOptions` usages in order\r\n // to prevent from polluting other exports that can happen on the same page\r\n Highcharts.setOptionsObj = merge(false, {}, getOptions());\r\n\r\n // NOTE: Is this used for anything useful?\r\n window.isRenderComplete = false;\r\n wrap(Highcharts.Chart.prototype, 'init', function (proceed, userOptions, cb) {\r\n // Override the `userOptions` with image friendly options\r\n userOptions = merge(userOptions, {\r\n exporting: {\r\n enabled: false\r\n },\r\n plotOptions: {\r\n series: {\r\n label: {\r\n enabled: false\r\n }\r\n }\r\n },\r\n /* Expects tooltip in the `userOptions` when `forExport` is true.\r\n https://github.com/highcharts/highcharts/blob/3ad430a353b8056b9e764aa4e5cd6828aa479db2/js/parts/Chart.js#L241\r\n */\r\n tooltip: {}\r\n });\r\n\r\n (userOptions.series || []).forEach(function (series) {\r\n series.animation = false;\r\n });\r\n\r\n // Add flag to know if chart render has been called.\r\n if (!window.onHighchartsRender) {\r\n window.onHighchartsRender = Highcharts.addEvent(this, 'render', () => {\r\n window.isRenderComplete = true;\r\n });\r\n }\r\n\r\n proceed.apply(this, [userOptions, cb]);\r\n });\r\n\r\n wrap(Highcharts.Series.prototype, 'init', function (proceed, chart, options) {\r\n proceed.apply(this, [chart, options]);\r\n });\r\n\r\n // Some mandatory additional `chart` and `exporting` options\r\n const additionalOptions = {\r\n chart: {\r\n // By default animation is disabled\r\n animation: false,\r\n // Get the right size values\r\n height: exportOptions.height,\r\n width: exportOptions.width\r\n },\r\n exporting: {\r\n // No need for the exporting button\r\n enabled: false\r\n }\r\n };\r\n\r\n // Get the input to export from the `instr` option\r\n const userOptions = new Function(`return ${exportOptions.instr}`)();\r\n\r\n // Get the `themeOptions` option\r\n const themeOptions = new Function(`return ${exportOptions.themeOptions}`)();\r\n\r\n // Get the `globalOptions` option\r\n const globalOptions = new Function(`return ${exportOptions.globalOptions}`)();\r\n\r\n // Merge the following options objects to create final options\r\n const finalOptions = merge(\r\n false,\r\n themeOptions,\r\n userOptions,\r\n // Placed it here instead in the init because of the size issues\r\n additionalOptions\r\n );\r\n\r\n // Prepare the `callback` option\r\n const finalCallback = customLogicOptions.callback\r\n ? new Function(`return ${customLogicOptions.callback}`)()\r\n : null;\r\n\r\n // Trigger the `customCode` option\r\n if (customLogicOptions.customCode) {\r\n new Function('options', customLogicOptions.customCode)(userOptions);\r\n }\r\n\r\n // Set the global options if exist\r\n if (globalOptions) {\r\n setOptions(globalOptions);\r\n }\r\n\r\n // Call the chart creation\r\n Highcharts[exportOptions.constr]('container', finalOptions, finalCallback);\r\n\r\n // Get the current global options\r\n const defaultOptions = getOptions();\r\n\r\n // Clear it just in case (e.g. the `setOptions` was used in the `customCode`)\r\n for (const prop in defaultOptions) {\r\n if (typeof defaultOptions[prop] !== 'function') {\r\n delete defaultOptions[prop];\r\n }\r\n }\r\n\r\n // Set the default options back\r\n setOptions(Highcharts.setOptionsObj);\r\n\r\n // Empty the custom global options object\r\n Highcharts.setOptionsObj = {};\r\n}\r\n\r\nexport default {\r\n setupHighcharts,\r\n createChart\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * @overview This module provides functions for managing Puppeteer browser\r\n * instance, creating and clearing pages, injecting custom resources,\r\n * and setting up Highcharts for server-side rendering. The module ensures\r\n * that resources are correctly managed and can handle failures during\r\n * operations like launching the browser or creating new pages.\r\n */\r\n\r\nimport { readFileSync } from 'fs';\r\nimport { join } from 'path';\r\n\r\nimport puppeteer from 'puppeteer';\r\n\r\nimport { getCachePath } from './cache.js';\r\nimport { getOptions } from './config.js';\r\nimport { setupHighcharts } from './highcharts.js';\r\nimport { log, logWithStack } from './logger.js';\r\nimport { __dirname, getAbsolutePath } from './utils.js';\r\n\r\nimport ExportError from './errors/ExportError.js';\r\n\r\n// Get the template for pages\r\nconst template = readFileSync(\r\n join(__dirname, 'templates', 'template.html'),\r\n 'utf8'\r\n);\r\n\r\n// To save the browser\r\nlet browser = null;\r\n\r\n/**\r\n * Retrieves the existing Puppeteer browser instance.\r\n *\r\n * @function getBrowser\r\n *\r\n * @returns {Object} The Puppeteer browser instance.\r\n *\r\n * @throws {ExportError} Throws an `ExportError` if no valid browser\r\n * has been created.\r\n */\r\nexport function getBrowser() {\r\n if (!browser) {\r\n throw new ExportError('[browser] No valid browser has been created.', 500);\r\n }\r\n return browser;\r\n}\r\n\r\n/**\r\n * Creates a Puppeteer browser instance with the specified arguments.\r\n *\r\n * @async\r\n * @function createBrowser\r\n *\r\n * @param {Array.} puppeteerArgs - Additional arguments for Puppeteer\r\n * launch.\r\n *\r\n * @returns {Promise} A Promise that resolves to the created Puppeteer\r\n * browser instance.\r\n *\r\n * @throws {ExportError} Throws an `ExportError` if max retries to open\r\n * a browser instance are reached, or if no browser instance is found after\r\n * retries.\r\n */\r\nexport async function createBrowser(puppeteerArgs) {\r\n // Get `debug` and `other` options\r\n const { debug, other } = getOptions();\r\n\r\n // Get the `debug` options\r\n const { enable: enabledDebug, ...debugOptions } = debug;\r\n\r\n // Launch options for the browser instance\r\n const launchOptions = {\r\n headless: other.browserShellMode ? 'shell' : true,\r\n userDataDir: 'tmp',\r\n args: puppeteerArgs || [],\r\n handleSIGINT: false,\r\n handleSIGTERM: false,\r\n handleSIGHUP: false,\r\n waitForInitialPage: false,\r\n defaultViewport: null,\r\n ...(enabledDebug && debugOptions)\r\n };\r\n\r\n // Create a browser\r\n if (!browser) {\r\n // A counter for the browser's launch retries\r\n let tryCount = 0;\r\n\r\n const open = async () => {\r\n try {\r\n log(\r\n 3,\r\n `[browser] Attempting to get a browser instance (try ${++tryCount}).`\r\n );\r\n\r\n // Launch the browser\r\n browser = await puppeteer.launch(launchOptions);\r\n } catch (error) {\r\n logWithStack(\r\n 1,\r\n error,\r\n '[browser] Failed to launch a browser instance.'\r\n );\r\n\r\n // Retry to launch browser until reaching max attempts\r\n if (tryCount < 25) {\r\n log(3, `[browser] Retry to open a browser (${tryCount} out of 25).`);\r\n\r\n // Wait for a 4 seconds before trying again\r\n await new Promise((response) => setTimeout(response, 4000));\r\n await open();\r\n } else {\r\n throw error;\r\n }\r\n }\r\n };\r\n\r\n try {\r\n await open();\r\n\r\n // Shell mode inform\r\n if (launchOptions.headless === 'shell') {\r\n log(3, `[browser] Launched browser in shell mode.`);\r\n }\r\n\r\n // Debug mode inform\r\n if (enabledDebug) {\r\n log(3, `[browser] Launched browser in debug mode.`);\r\n }\r\n } catch (error) {\r\n throw new ExportError(\r\n '[browser] Maximum retries to open a browser instance reached.',\r\n 500\r\n ).setError(error);\r\n }\r\n\r\n if (!browser) {\r\n throw new ExportError('[browser] Cannot find a browser to open.', 500);\r\n }\r\n }\r\n\r\n // Return a browser instance\r\n return browser;\r\n}\r\n\r\n/**\r\n * Closes the Puppeteer browser instance if it is connected.\r\n *\r\n * @async\r\n * @function closeBrowser\r\n */\r\nexport async function closeBrowser() {\r\n // Close the browser when connected\r\n if (browser && browser.connected) {\r\n await browser.close();\r\n }\r\n browser = null;\r\n log(4, '[browser] Closed the browser.');\r\n}\r\n\r\n/**\r\n * Creates a new Puppeteer page within an existing browser instance.\r\n * The function creates a new page, disables caching, sets content using\r\n * the `_setPageContent()`, and returns the created Puppeteer page.\r\n *\r\n * @async\r\n * @function newPage\r\n *\r\n * @param {Object} poolResource - The pool resource that contains `id`,\r\n * `workCount`, and `page`.\r\n *\r\n * @throws {ExportError} Throws an `ExportError` if no valid browser\r\n * has been connected or if a page is invalid or closed.\r\n */\r\nexport async function newPage(poolResource) {\r\n // Error in case of no connected browser\r\n if (!browser || !browser.connected) {\r\n throw new ExportError(`[browser] Browser is not yet connected.`, 500);\r\n }\r\n\r\n // Create a page\r\n poolResource.page = await browser.newPage();\r\n\r\n // Disable cache\r\n await poolResource.page.setCacheEnabled(false);\r\n\r\n // Set the content\r\n await _setPageContent(poolResource.page);\r\n\r\n // Set page events\r\n _setPageEvents(poolResource.page);\r\n\r\n // Check if the page is correctly created\r\n if (!poolResource.page || poolResource.page.isClosed()) {\r\n throw new ExportError('[browser] The page is invalid or closed.', 400);\r\n }\r\n}\r\n\r\n/**\r\n * Clears the content of a Puppeteer Page based on the specified mode. Logs\r\n * thrown error if clearing of a page's content fails.\r\n *\r\n * @async\r\n * @function clearPage\r\n *\r\n * @param {Object} poolResource - The pool resource that contains page and id.\r\n * @param {boolean} [hardReset=false] - A flag indicating the type of clearing\r\n * to be performed. If true, navigates to `about:blank` and resets content\r\n * and scripts. If false, clears the body content by setting a predefined HTML\r\n * structure. The default value is `false`.\r\n *\r\n * @returns {Promise} A Promise that resolves to true when page\r\n * is correctly cleared and false when it is not.\r\n */\r\nexport async function clearPage(poolResource, hardReset = false) {\r\n try {\r\n if (poolResource.page && !poolResource.page.isClosed()) {\r\n if (hardReset) {\r\n // Navigate to `about:blank`\r\n await poolResource.page.goto('about:blank', {\r\n waitUntil: 'domcontentloaded'\r\n });\r\n\r\n // Set the content and and scripts again\r\n await _setPageContent(poolResource.page);\r\n } else {\r\n // Clear body content\r\n await poolResource.page.evaluate(() => {\r\n document.body.innerHTML =\r\n '
';\r\n });\r\n }\r\n return true;\r\n }\r\n } catch (error) {\r\n logWithStack(\r\n 2,\r\n error,\r\n `[pool] Pool resource [${poolResource.id}] - Content of the page could not be cleared.`\r\n );\r\n\r\n // Set the `workLimit` to exceeded in order to recreate the resource\r\n poolResource.workCount = getOptions().pool.workLimit + 1;\r\n }\r\n return false;\r\n}\r\n\r\n/**\r\n * Adds custom JS and CSS resources to a Puppeteer Page based on the specified\r\n * options.\r\n *\r\n * @async\r\n * @function addPageResources\r\n *\r\n * @param {Object} page - The Puppeteer page object to which resources will\r\n * be added.\r\n * @param {Object} customLogicOptions - The configuration object containing\r\n * `customLogic` options.\r\n *\r\n * @returns {Promise>} A Promise that resolves to an array\r\n * of injected resources.\r\n */\r\nexport async function addPageResources(page, customLogicOptions) {\r\n // Injected resources array\r\n const injectedResources = [];\r\n\r\n // Use resources\r\n const resources = customLogicOptions.resources;\r\n if (resources) {\r\n const injectedJs = [];\r\n\r\n // Load custom JS code\r\n if (resources.js) {\r\n injectedJs.push({\r\n content: resources.js\r\n });\r\n }\r\n\r\n // Load scripts from all custom files\r\n if (resources.files) {\r\n for (const file of resources.files) {\r\n const isLocal = !file.startsWith('http') ? true : false;\r\n\r\n // Add each custom script from resources' files\r\n injectedJs.push(\r\n isLocal\r\n ? {\r\n content: readFileSync(getAbsolutePath(file), 'utf8')\r\n }\r\n : {\r\n url: file\r\n }\r\n );\r\n }\r\n }\r\n\r\n for (const jsResource of injectedJs) {\r\n try {\r\n injectedResources.push(await page.addScriptTag(jsResource));\r\n } catch (error) {\r\n logWithStack(2, error, `[browser] The JS resource cannot be loaded.`);\r\n }\r\n }\r\n injectedJs.length = 0;\r\n\r\n // Load CSS\r\n const injectedCss = [];\r\n if (resources.css) {\r\n let cssImports = resources.css.match(/@import\\s*([^;]*);/g);\r\n if (cssImports) {\r\n // Handle css section\r\n for (let cssImportPath of cssImports) {\r\n if (cssImportPath) {\r\n cssImportPath = cssImportPath\r\n .replace('url(', '')\r\n .replace('@import', '')\r\n .replace(/\"/g, '')\r\n .replace(/'/g, '')\r\n .replace(/;/, '')\r\n .replace(/\\)/g, '')\r\n .trim();\r\n\r\n // Add each custom css from resources\r\n if (cssImportPath.startsWith('http')) {\r\n injectedCss.push({\r\n url: cssImportPath\r\n });\r\n } else if (customLogicOptions.allowFileResources) {\r\n injectedCss.push({\r\n path: join(__dirname, cssImportPath)\r\n });\r\n }\r\n }\r\n }\r\n }\r\n\r\n // The rest of the CSS section will be content by now\r\n injectedCss.push({\r\n content: resources.css.replace(/@import\\s*([^;]*);/g, '') || ' '\r\n });\r\n\r\n for (const cssResource of injectedCss) {\r\n try {\r\n injectedResources.push(await page.addStyleTag(cssResource));\r\n } catch (error) {\r\n logWithStack(\r\n 2,\r\n error,\r\n `[browser] The CSS resource cannot be loaded.`\r\n );\r\n }\r\n }\r\n injectedCss.length = 0;\r\n }\r\n }\r\n return injectedResources;\r\n}\r\n\r\n/**\r\n * Clears out all state set on the page with `addScriptTag` and `addStyleTag`.\r\n * Removes injected resources and resets CSS and script tags on the page.\r\n * Additionally, it destroys previously existing charts.\r\n *\r\n * @async\r\n * @function clearPageResources\r\n *\r\n * @param {Object} page - The Puppeteer page object from which resources will\r\n * be cleared.\r\n * @param {Array.} injectedResources - Array of injected resources\r\n * to be cleared.\r\n */\r\nexport async function clearPageResources(page, injectedResources) {\r\n try {\r\n for (const resource of injectedResources) {\r\n await resource.dispose();\r\n }\r\n\r\n // Destroy old charts after export is done and reset all CSS and script tags\r\n await page.evaluate(() => {\r\n // We are not guaranteed that Highcharts is loaded, when doing SVG exports\r\n if (typeof Highcharts !== 'undefined') {\r\n // eslint-disable-next-line no-undef\r\n const oldCharts = Highcharts.charts;\r\n\r\n // Check in any already existing charts\r\n if (Array.isArray(oldCharts) && oldCharts.length) {\r\n // Destroy old charts\r\n for (const oldChart of oldCharts) {\r\n oldChart && oldChart.destroy();\r\n // eslint-disable-next-line no-undef\r\n Highcharts.charts.shift();\r\n }\r\n }\r\n }\r\n\r\n // eslint-disable-next-line no-undef\r\n const [...scriptsToRemove] = document.getElementsByTagName('script');\r\n // eslint-disable-next-line no-undef\r\n const [, ...stylesToRemove] = document.getElementsByTagName('style');\r\n // eslint-disable-next-line no-undef\r\n const [...linksToRemove] = document.getElementsByTagName('link');\r\n\r\n // Remove tags\r\n for (const element of [\r\n ...scriptsToRemove,\r\n ...stylesToRemove,\r\n ...linksToRemove\r\n ]) {\r\n element.remove();\r\n }\r\n });\r\n } catch (error) {\r\n logWithStack(2, error, `[browser] Could not clear page's resources.`);\r\n }\r\n}\r\n\r\n/**\r\n * Sets the content for a Puppeteer Page using a predefined template\r\n * and additional scripts.\r\n *\r\n * @async\r\n * @function _setPageContent\r\n *\r\n * @param {Object} page - The Puppeteer page object to which the content\r\n * is being set.\r\n */\r\nasync function _setPageContent(page) {\r\n // Set the initial page content\r\n await page.setContent(template, { waitUntil: 'domcontentloaded' });\r\n\r\n // Add all registered Higcharts scripts, quite demanding\r\n await page.addScriptTag({ path: join(getCachePath(), 'sources.js') });\r\n\r\n // Set the initial `animObject` for Highcharts\r\n await page.evaluate(setupHighcharts);\r\n}\r\n\r\n/**\r\n * Set events (like `pageerror` and `console`) for a Puppeteer Page in order\r\n * to catch and display errors and console logs from the window context.\r\n *\r\n * @function _setPageEvents\r\n *\r\n * @param {Object} page - The Puppeteer page object to which the listeners\r\n * are being set.\r\n */\r\nfunction _setPageEvents(page) {\r\n // Get `debug` options\r\n const { debug } = getOptions();\r\n\r\n // Set the `pageerror` listener\r\n page.on('pageerror', async () => {\r\n // It would seem like this may fire at the same time or shortly before\r\n // a page is closed.\r\n if (page.isClosed()) {\r\n return;\r\n }\r\n });\r\n\r\n // Set the `console` listener, if needed\r\n if (debug.enable && debug.listenToConsole) {\r\n page.on('console', (message) => {\r\n console.log(`[debug] ${message.text()}`);\r\n });\r\n }\r\n}\r\n\r\nexport default {\r\n getBrowser,\r\n createBrowser,\r\n closeBrowser,\r\n newPage,\r\n clearPage,\r\n addPageResources,\r\n clearPageResources\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * The CSS to be used on the exported page.\r\n *\r\n * @returns {string} The CSS configuration.\r\n */\r\nexport default () => `\r\n\r\nhtml, body {\r\n margin: 0;\r\n padding: 0;\r\n box-sizing: border-box;\r\n}\r\n\r\n#table-div, #sliders, #datatable, #controls, .ld-row {\r\n display: none;\r\n height: 0;\r\n}\r\n\r\n#chart-container {\r\n box-sizing: border-box;\r\n margin: 0;\r\n overflow: auto;\r\n font-size: 0;\r\n}\r\n\r\n#chart-container > figure, div {\r\n margin-top: 0 !important;\r\n margin-bottom: 0 !important;\r\n}\r\n\r\n`;\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\nimport cssTemplate from './css.js';\r\n\r\n/**\r\n * The SVG template to use when loading SVG content to be exported.\r\n *\r\n * @param {string} svg - The SVG input content to be exported.\r\n *\r\n * @returns {string} The SVG template.\r\n */\r\nexport default (svg) => `\r\n\r\n\r\n \r\n \r\n Highcharts Export\r\n \r\n \r\n \r\n
\r\n ${svg}\r\n
\r\n \r\n\r\n\r\n`;\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * @overview This module handles chart export functionality using Puppeteer.\r\n * It supports exporting charts as SVG, PNG, JPEG, and PDF formats. The module\r\n * manages page resources, sets up the export environment, and processes chart\r\n * configurations or SVG inputs for rendering. Exports to a chart from a page\r\n * using Puppeteer.\r\n */\r\n\r\nimport { addPageResources, clearPageResources } from './browser.js';\r\nimport { createChart } from './highcharts.js';\r\nimport { log } from './logger.js';\r\n\r\nimport svgTemplate from '../templates/svgExport/svgExport.js';\r\n\r\nimport ExportError from './errors/ExportError.js';\r\n\r\n/**\r\n * Exports to a chart from a page using Puppeteer.\r\n *\r\n * @async\r\n * @function puppeteerExport\r\n *\r\n * @param {Object} page - Puppeteer page object.\r\n * @param {Object} exportOptions - The configuration object containing `export`\r\n * options.\r\n * @param {Object} customLogicOptions - The configuration object containing\r\n * `customLogic` options.\r\n *\r\n * @returns {Promise<(string|Buffer|ExportError)>} A Promise that resolves\r\n * to the exported data or rejecting with an `ExportError`.\r\n *\r\n * @throws {ExportError} Throws an `ExportError` if export to an unsupported\r\n * output format occurs.\r\n */\r\nexport async function puppeteerExport(page, exportOptions, customLogicOptions) {\r\n // Injected resources array (additional JS and CSS)\r\n const injectedResources = [];\r\n\r\n try {\r\n let isSVG = false;\r\n\r\n // Decide on the export method\r\n if (exportOptions.svg) {\r\n log(4, '[export] Treating as SVG input.');\r\n\r\n // If the `type` is also SVG, return the input\r\n if (exportOptions.type === 'svg') {\r\n return exportOptions.svg;\r\n }\r\n\r\n // Mark as SVG export for the later size corrections\r\n isSVG = true;\r\n\r\n // SVG export\r\n await page.setContent(svgTemplate(exportOptions.svg), {\r\n waitUntil: 'domcontentloaded'\r\n });\r\n } else {\r\n log(4, '[export] Treating as JSON config.');\r\n\r\n // Options export\r\n await page.evaluate(createChart, exportOptions, customLogicOptions);\r\n }\r\n\r\n // Keeps track of all resources added on the page with addXXXTag. etc\r\n // It's VITAL that all added resources ends up here so we can clear things\r\n // out when doing a new export in the same page!\r\n injectedResources.push(\r\n ...(await addPageResources(page, customLogicOptions))\r\n );\r\n\r\n // Get the real chart size and set the zoom accordingly\r\n const size = isSVG\r\n ? await page.evaluate((scale) => {\r\n const svgElement = document.querySelector(\r\n '#chart-container svg:first-of-type'\r\n );\r\n\r\n // Get the values correctly scaled\r\n const chartHeight = svgElement.height.baseVal.value * scale;\r\n const chartWidth = svgElement.width.baseVal.value * scale;\r\n\r\n // In case of SVG the zoom must be set directly for body as scale\r\n // eslint-disable-next-line no-undef\r\n document.body.style.zoom = scale;\r\n\r\n // Set the margin to 0px\r\n // eslint-disable-next-line no-undef\r\n document.body.style.margin = '0px';\r\n\r\n return {\r\n chartHeight,\r\n chartWidth\r\n };\r\n }, parseFloat(exportOptions.scale))\r\n : await page.evaluate(() => {\r\n // eslint-disable-next-line no-undef\r\n const { chartHeight, chartWidth } = window.Highcharts.charts[0];\r\n\r\n // No need for such scale manipulation in case of other types\r\n // of exports. Reset the zoom for other exports than to SVGs\r\n // eslint-disable-next-line no-undef\r\n document.body.style.zoom = 1;\r\n\r\n return {\r\n chartHeight,\r\n chartWidth\r\n };\r\n });\r\n\r\n // Get the clip region for the page\r\n const { x, y } = await _getClipRegion(page);\r\n\r\n // Set final `height` for viewport\r\n const viewportHeight = Math.abs(\r\n Math.ceil(size.chartHeight || exportOptions.height)\r\n );\r\n\r\n // Set final `width` for viewport\r\n const viewportWidth = Math.abs(\r\n Math.ceil(size.chartWidth || exportOptions.width)\r\n );\r\n\r\n // Set the final viewport now that we have the real height\r\n await page.setViewport({\r\n height: viewportHeight,\r\n width: viewportWidth,\r\n deviceScaleFactor: isSVG ? 1 : parseFloat(exportOptions.scale)\r\n });\r\n\r\n let result;\r\n // Rasterization process\r\n switch (exportOptions.type) {\r\n case 'svg':\r\n result = await _createSVG(page);\r\n break;\r\n case 'png':\r\n case 'jpeg':\r\n result = await _createImage(\r\n page,\r\n exportOptions.type,\r\n {\r\n width: viewportWidth,\r\n height: viewportHeight,\r\n x,\r\n y\r\n },\r\n exportOptions.rasterizationTimeout\r\n );\r\n break;\r\n case 'pdf':\r\n result = await _createPDF(\r\n page,\r\n viewportHeight,\r\n viewportWidth,\r\n exportOptions.rasterizationTimeout\r\n );\r\n break;\r\n default:\r\n throw new ExportError(\r\n `[export] Unsupported output format: ${exportOptions.type}.`,\r\n 400\r\n );\r\n }\r\n\r\n // Clear previously injected JS and CSS resources\r\n await clearPageResources(page, injectedResources);\r\n return result;\r\n } catch (error) {\r\n await clearPageResources(page, injectedResources);\r\n return error;\r\n }\r\n}\r\n\r\n/**\r\n * Retrieves the clipping region coordinates of the specified page element\r\n * with the 'chart-container' id.\r\n *\r\n * @async\r\n * @function _getClipRegion\r\n *\r\n * @param {Object} page - Puppeteer page object.\r\n *\r\n * @returns {Promise} A Promise that resolves to an object containing\r\n * `x`, `y`, `width`, and `height` properties.\r\n */\r\nasync function _getClipRegion(page) {\r\n return page.$eval('#chart-container', (element) => {\r\n const { x, y, width, height } = element.getBoundingClientRect();\r\n return {\r\n x,\r\n y,\r\n width,\r\n height: Math.trunc(height > 1 ? height : 500)\r\n };\r\n });\r\n}\r\n\r\n/**\r\n * Creates an SVG by evaluating the `outerHTML` of the first 'svg' element\r\n * inside an element with the id 'container'.\r\n *\r\n * @async\r\n * @function _createSVG\r\n *\r\n * @param {Object} page - Puppeteer page object.\r\n *\r\n * @returns {Promise} A Promise that resolves to the SVG string.\r\n */\r\nasync function _createSVG(page) {\r\n return page.$eval(\r\n '#container svg:first-of-type',\r\n (element) => element.outerHTML\r\n );\r\n}\r\n\r\n/**\r\n * Creates an image using Puppeteer's page `screenshot` functionality with\r\n * specified options.\r\n *\r\n * @async\r\n * @function _createImage\r\n *\r\n * @param {Object} page - Puppeteer page object.\r\n * @param {string} type - Image type.\r\n * @param {Object} clip - Clipping region coordinates.\r\n * @param {number} rasterizationTimeout - Timeout for rasterization\r\n * in milliseconds.\r\n *\r\n * @returns {Promise} A Promise that resolves to the image buffer\r\n * or rejecting with an `ExportError` for timeout.\r\n */\r\nasync function _createImage(page, type, clip, rasterizationTimeout) {\r\n return Promise.race([\r\n page.screenshot({\r\n type,\r\n clip,\r\n encoding: 'base64',\r\n fullPage: false,\r\n optimizeForSpeed: true,\r\n captureBeyondViewport: true,\r\n ...(type !== 'png' ? { quality: 80 } : {}),\r\n // Always render on a transparent page if the expected type format is PNG\r\n omitBackground: type == 'png' // #447, #463\r\n }),\r\n new Promise((_resolve, reject) =>\r\n setTimeout(\r\n () => reject(new ExportError('Rasterization timeout', 408)),\r\n rasterizationTimeout || 1500\r\n )\r\n )\r\n ]);\r\n}\r\n\r\n/**\r\n * Creates a PDF using Puppeteer's page `pdf` functionality with specified\r\n * options.\r\n *\r\n * @async\r\n * @function _createPDF\r\n *\r\n * @param {Object} page - Puppeteer page object.\r\n * @param {number} height - PDF height.\r\n * @param {number} width - PDF width.\r\n * @param {number} rasterizationTimeout - Timeout for rasterization\r\n * in milliseconds.\r\n *\r\n * @returns {Promise} A Promise that resolves to the PDF buffer.\r\n */\r\nasync function _createPDF(page, height, width, rasterizationTimeout) {\r\n await page.emulateMediaType('screen');\r\n return page.pdf({\r\n // This will remove an extra empty page in PDF exports\r\n height: height + 1,\r\n width,\r\n encoding: 'base64',\r\n timeout: rasterizationTimeout || 1500\r\n });\r\n}\r\n\r\nexport default {\r\n puppeteerExport\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * @overview This module provides a worker pool implementation for managing\r\n * the browser instance and pages, specifically designed for use with\r\n * the Highcharts Export Server. It optimizes resources usage and performance\r\n * by maintaining a pool of workers that can handle concurrent export tasks\r\n * using Puppeteer.\r\n */\r\n\r\nimport { Pool } from 'tarn';\r\nimport { v4 as uuid } from 'uuid';\r\n\r\nimport { createBrowser, closeBrowser, newPage, clearPage } from './browser.js';\r\nimport { puppeteerExport } from './export.js';\r\nimport { log, logWithStack } from './logger.js';\r\nimport { getNewDateTime, measureTime } from './utils.js';\r\n\r\nimport ExportError from './errors/ExportError.js';\r\n\r\n// The pool instance\r\nlet pool = null;\r\n\r\n// Pool statistics\r\nconst poolStats = {\r\n exportsAttempted: 0,\r\n exportsPerformed: 0,\r\n exportsDropped: 0,\r\n exportsFromSvg: 0,\r\n exportsFromOptions: 0,\r\n exportsFromSvgAttempts: 0,\r\n exportsFromOptionsAttempts: 0,\r\n timeSpent: 0,\r\n timeSpentAverage: 0\r\n};\r\n\r\n/**\r\n * Initializes the export pool with the provided configuration, creating\r\n * a browser instance and setting up worker resources.\r\n *\r\n * @async\r\n * @function initPool\r\n *\r\n * @param {Object} poolOptions - The configuration object containing `pool`\r\n * options.\r\n * @param {Array.} puppeteerArgs - Additional arguments for Puppeteer\r\n * launch.\r\n *\r\n * @returns {Promise} A Promise that resolves to ending the function\r\n * execution when an already initialized pool of resources is found.\r\n *\r\n * @throws {ExportError} Throws an `ExportError` if could not create the pool\r\n * of workers.\r\n */\r\nexport async function initPool(poolOptions, puppeteerArgs) {\r\n // Create a browser instance with the puppeteer arguments\r\n await createBrowser(puppeteerArgs);\r\n\r\n try {\r\n log(\r\n 3,\r\n `[pool] Initializing pool with workers: min ${poolOptions.minWorkers}, max ${poolOptions.maxWorkers}.`\r\n );\r\n\r\n if (pool) {\r\n log(\r\n 4,\r\n '[pool] Already initialized, please kill it before creating a new one.'\r\n );\r\n return;\r\n }\r\n\r\n // Keep an eye on a correct min and max workers number\r\n if (poolOptions.minWorkers > poolOptions.maxWorkers) {\r\n poolOptions.minWorkers = poolOptions.maxWorkers;\r\n }\r\n\r\n // Create a pool along with a minimal number of resources\r\n pool = new Pool({\r\n // Get the `create`, `validate`, and `destroy` functions\r\n ..._factory(poolOptions),\r\n min: poolOptions.minWorkers,\r\n max: poolOptions.maxWorkers,\r\n acquireTimeoutMillis: poolOptions.acquireTimeout,\r\n createTimeoutMillis: poolOptions.createTimeout,\r\n destroyTimeoutMillis: poolOptions.destroyTimeout,\r\n idleTimeoutMillis: poolOptions.idleTimeout,\r\n createRetryIntervalMillis: poolOptions.createRetryInterval,\r\n reapIntervalMillis: poolOptions.reaperInterval,\r\n propagateCreateError: false\r\n });\r\n\r\n // Set events\r\n pool.on('release', async (resource) => {\r\n // Clear page\r\n const clearStatus = await clearPage(resource, false);\r\n log(\r\n 4,\r\n `[pool] Pool resource [${resource.id}] - Releasing a worker. Clear page status: ${clearStatus}.`\r\n );\r\n });\r\n\r\n pool.on('destroySuccess', (_eventId, resource) => {\r\n log(\r\n 4,\r\n `[pool] Pool resource [${resource.id}] - Destroyed a worker successfully.`\r\n );\r\n resource.page = null;\r\n });\r\n\r\n const initialResources = [];\r\n // Create an initial number of resources\r\n for (let i = 0; i < poolOptions.minWorkers; i++) {\r\n try {\r\n const resource = await pool.acquire().promise;\r\n initialResources.push(resource);\r\n } catch (error) {\r\n logWithStack(2, error, '[pool] Could not create an initial resource.');\r\n }\r\n }\r\n\r\n // Release the initial number of resources back to the pool\r\n initialResources.forEach((resource) => {\r\n pool.release(resource);\r\n });\r\n\r\n log(\r\n 3,\r\n `[pool] The pool is ready${initialResources.length ? ` with ${initialResources.length} initial resources waiting.` : '.'}`\r\n );\r\n } catch (error) {\r\n throw new ExportError(\r\n '[pool] Could not configure and create the pool of workers.',\r\n 500\r\n ).setError(error);\r\n }\r\n}\r\n\r\n/**\r\n * Terminates all workers in the pool, destroys the pool, and closes the browser\r\n * instance.\r\n *\r\n * @async\r\n * @function killPool\r\n *\r\n * @returns {Promise} A Promise that resolves once all workers are\r\n * terminated, the pool is destroyed, and the browser is successfully closed.\r\n */\r\nexport async function killPool() {\r\n log(3, '[pool] Killing pool with all workers and closing browser.');\r\n\r\n // If still alive, destroy the pool of pages before closing a browser\r\n if (pool) {\r\n // Free up not released workers\r\n for (const worker of pool.used) {\r\n pool.release(worker.resource);\r\n }\r\n\r\n // Destroy the pool if it is still available\r\n if (!pool.destroyed) {\r\n await pool.destroy();\r\n log(4, '[pool] Destroyed the pool of resources.');\r\n }\r\n pool = null;\r\n }\r\n\r\n // Close the browser instance\r\n await closeBrowser();\r\n}\r\n\r\n/**\r\n * Processes the export work using a worker from the pool. Acquires a worker\r\n * handle from the pool, performs the export using puppeteer, and releases\r\n * the worker handle back to the pool.\r\n *\r\n * @async\r\n * @function postWork\r\n *\r\n * @param {Object} options - The configuration object containing complete set\r\n * of options.\r\n *\r\n * @returns {Promise} A Promise that resolves to the export result\r\n * and options.\r\n *\r\n * @throws {ExportError} Throws an `ExportError` if an error occurs during\r\n * the export process.\r\n */\r\nexport async function postWork(options) {\r\n let workerHandle;\r\n\r\n try {\r\n log(4, '[pool] Work received, starting to process.');\r\n\r\n // An export attempt counted\r\n ++poolStats.exportsAttempted;\r\n\r\n // Display the pool information if needed\r\n if (options.pool.benchmarking) {\r\n getPoolInfo();\r\n }\r\n\r\n // Throw an error in case of lacking the pool instance\r\n if (!pool) {\r\n throw new ExportError(\r\n '[pool] Work received, but pool has not been started.',\r\n 500\r\n );\r\n }\r\n\r\n // The acquire counter\r\n const acquireCounter = measureTime();\r\n\r\n // Try to acquire the worker along with the id, works count and page\r\n try {\r\n log(4, '[pool] Acquiring a worker handle.');\r\n\r\n // Acquire a pool resource\r\n workerHandle = await pool.acquire().promise;\r\n\r\n // Check the page acquire time\r\n if (options.server.benchmarking) {\r\n log(\r\n 5,\r\n `[benchmark] ${options.requestId ? `Request [${options.requestId}] - ` : ''}`,\r\n `Acquiring a worker handle took ${acquireCounter()}ms.`\r\n );\r\n }\r\n } catch (error) {\r\n throw new ExportError(\r\n `[pool] ${\r\n options.requestId ? `Request [${options.requestId}] - ` : ''\r\n }Error encountered when acquiring an available entry: ${acquireCounter()}ms.`,\r\n 400\r\n ).setError(error);\r\n }\r\n log(4, '[pool] Acquired a worker handle.');\r\n\r\n if (!workerHandle.page) {\r\n // Set the `workLimit` to exceeded in order to recreate the resource\r\n workerHandle.workCount = options.pool.workLimit + 1;\r\n throw new ExportError(\r\n '[pool] Resolved worker page is invalid: the pool setup is wonky.',\r\n 400\r\n );\r\n }\r\n\r\n // Save the start time\r\n const workStart = getNewDateTime();\r\n\r\n log(\r\n 4,\r\n `[pool] Pool resource [${workerHandle.id}] - Starting work on this pool entry.`\r\n );\r\n\r\n // Start measuring export time\r\n const exportCounter = measureTime();\r\n\r\n // Perform an export on a puppeteer level\r\n const result = await puppeteerExport(\r\n workerHandle.page,\r\n options.export,\r\n options.customLogic\r\n );\r\n\r\n // Check if it's an error\r\n if (result instanceof Error) {\r\n // NOTE:\r\n // If there's a rasterization timeout, we want need to flush the page.\r\n // This is because the page may be in a state where it's waiting for\r\n // the screenshot to finish even though the timeout has occured.\r\n // Which of course causes a lot of issues with the event system,\r\n // and page consistency.\r\n //\r\n // NOTE:\r\n // Only page.screenshot will throw this, timeouts for PDF's are\r\n // handled by the page.pdf function itself.\r\n //\r\n // ...yes, this is ugly.\r\n if (result.message === 'Rasterization timeout') {\r\n // Set the `workLimit` to exceeded in order to recreate the resource\r\n workerHandle.workCount = options.pool.workLimit + 1;\r\n workerHandle.page = null;\r\n }\r\n\r\n if (\r\n result.name === 'TimeoutError' ||\r\n result.message === 'Rasterization timeout'\r\n ) {\r\n throw new ExportError(\r\n `[pool] ${\r\n options.requestId ? `Request [${options.requestId}] - ` : ''\r\n }Rasterization timeout: your chart may be too complex or large, and failed to render within the allotted time.`\r\n ).setError(result);\r\n } else {\r\n throw new ExportError(\r\n `[pool] ${\r\n options.requestId ? `Request [${options.requestId}] - ` : ''\r\n }Error encountered during export: ${exportCounter()}ms.`\r\n ).setError(result);\r\n }\r\n }\r\n\r\n // Check the Puppeteer export time\r\n if (options.server.benchmarking) {\r\n log(\r\n 5,\r\n `[benchmark] ${options.requestId ? `Request [${options.requestId}] - ` : ''}`,\r\n `Exporting a chart sucessfully took ${exportCounter()}ms.`\r\n );\r\n }\r\n\r\n // Release the resource back to the pool\r\n pool.release(workerHandle);\r\n\r\n // Used for statistics in averageTime and processedWorkCount, which\r\n // in turn is used by the /health route.\r\n const workEnd = getNewDateTime();\r\n const exportTime = workEnd - workStart;\r\n\r\n poolStats.timeSpent += exportTime;\r\n poolStats.timeSpentAverage =\r\n poolStats.timeSpent / ++poolStats.exportsPerformed;\r\n\r\n log(4, `[pool] Work completed in ${exportTime}ms.`);\r\n\r\n // Otherwise return the result\r\n return {\r\n result,\r\n options\r\n };\r\n } catch (error) {\r\n ++poolStats.exportsDropped;\r\n\r\n if (workerHandle) {\r\n pool.release(workerHandle);\r\n }\r\n\r\n throw error;\r\n }\r\n}\r\n\r\n/**\r\n * Retrieves the current pool instance.\r\n *\r\n * @function getPool\r\n *\r\n * @returns {(Object|null)} The current pool instance if initialized, or null\r\n * if the pool has not been created.\r\n */\r\nexport function getPool() {\r\n return pool;\r\n}\r\n\r\n/**\r\n * Gets the statistic of a pool instace about exports.\r\n *\r\n * @function getPoolStats\r\n *\r\n * @returns {Object} The current pool statistics.\r\n */\r\nexport function getPoolStats() {\r\n return poolStats;\r\n}\r\n\r\n/**\r\n * Retrieves pool information in JSON format, including minimum and maximum\r\n * workers, available workers, workers in use, and pending acquire requests.\r\n *\r\n * @function getPoolInfoJSON\r\n *\r\n * @returns {Object} Pool information in JSON format.\r\n */\r\nexport function getPoolInfoJSON() {\r\n return {\r\n min: pool.min,\r\n max: pool.max,\r\n used: pool.numUsed(),\r\n available: pool.numFree(),\r\n allCreated: pool.numUsed() + pool.numFree(),\r\n pendingAcquires: pool.numPendingAcquires(),\r\n pendingCreates: pool.numPendingCreates(),\r\n pendingValidations: pool.numPendingValidations(),\r\n pendingDestroys: pool.pendingDestroys.length,\r\n absoluteAll:\r\n pool.numUsed() +\r\n pool.numFree() +\r\n pool.numPendingAcquires() +\r\n pool.numPendingCreates() +\r\n pool.numPendingValidations() +\r\n pool.pendingDestroys.length\r\n };\r\n}\r\n\r\n/**\r\n * Logs information about the current state of the pool, including the minimum\r\n * and maximum workers, available workers, workers in use, and pending acquire\r\n * requests.\r\n *\r\n * @function getPoolInfo\r\n */\r\nexport function getPoolInfo() {\r\n const {\r\n min,\r\n max,\r\n used,\r\n available,\r\n allCreated,\r\n pendingAcquires,\r\n pendingCreates,\r\n pendingValidations,\r\n pendingDestroys,\r\n absoluteAll\r\n } = getPoolInfoJSON();\r\n\r\n log(5, `[pool] The minimum number of resources allowed by pool: ${min}.`);\r\n log(5, `[pool] The maximum number of resources allowed by pool: ${max}.`);\r\n log(5, `[pool] The number of used resources: ${used}.`);\r\n log(5, `[pool] The number of free resources: ${available}.`);\r\n log(\r\n 5,\r\n `[pool] The number of all created (used and free) resources: ${allCreated}.`\r\n );\r\n log(\r\n 5,\r\n `[pool] The number of resources waiting to be acquired: ${pendingAcquires}.`\r\n );\r\n log(\r\n 5,\r\n `[pool] The number of resources waiting to be created: ${pendingCreates}.`\r\n );\r\n log(\r\n 5,\r\n `[pool] The number of resources waiting to be validated: ${pendingValidations}.`\r\n );\r\n log(\r\n 5,\r\n `[pool] The number of resources waiting to be destroyed: ${pendingDestroys}.`\r\n );\r\n log(5, `[pool] The number of all resources: ${absoluteAll}.`);\r\n}\r\n\r\n/**\r\n * Factory function that returns an object with `create`, `validate`,\r\n * and `destroy` functions for the pool instance.\r\n *\r\n * @function _factory\r\n *\r\n * @param {Object} poolOptions - The configuration object containing `pool`\r\n * options.\r\n */\r\nfunction _factory(poolOptions) {\r\n return {\r\n /**\r\n * Creates a new worker page for the export pool.\r\n *\r\n * @async\r\n * @function create\r\n *\r\n * @returns {Promise} A Promise that resolves to an object\r\n * containing the worker ID, a reference to the browser page, and initial\r\n * work count.\r\n *\r\n * @throws {ExportError} Throws an `ExportError` if there is an error during\r\n * the creation of the new page.\r\n */\r\n create: async () => {\r\n // Init the resource with unique id and work count\r\n const poolResource = {\r\n id: uuid(),\r\n // Try to distribute the initial work count\r\n workCount: Math.round(Math.random() * (poolOptions.workLimit / 2))\r\n };\r\n\r\n try {\r\n // Start measuring a page creation time\r\n const startDate = getNewDateTime();\r\n\r\n // Create a new page\r\n await newPage(poolResource);\r\n\r\n // Measure the time of full creation and configuration of a page\r\n log(\r\n 3,\r\n `[pool] Pool resource [${poolResource.id}] - Successfully created a worker, took ${\r\n getNewDateTime() - startDate\r\n }ms.`\r\n );\r\n\r\n // Return ready pool resource\r\n return poolResource;\r\n } catch (error) {\r\n log(\r\n 3,\r\n `[pool] Pool resource [${poolResource.id}] - Error encountered when creating a new page.`\r\n );\r\n throw error;\r\n }\r\n },\r\n\r\n /**\r\n * Validates a worker page in the export pool, checking if it has exceeded\r\n * the work limit.\r\n *\r\n * @async\r\n * @function validate\r\n *\r\n * @param {Object} poolResource - The handle to the worker, containing\r\n * the worker's ID, a reference to the browser page, and work count.\r\n *\r\n * @returns {Promise} A Promise that resolves to true if the worker\r\n * is valid and within the work limit; otherwise, to false.\r\n */\r\n validate: async (poolResource) => {\r\n // NOTE:\r\n // In certain cases acquiring throws a TargetCloseError, which may\r\n // be caused by two things:\r\n // - The page is closed and attempted to be reused.\r\n // - Lost contact with the browser.\r\n //\r\n // What we're seeing in logs is that successive exports typically\r\n // succeeds, and the server recovers, indicating that it's likely\r\n // the first case. This is an attempt at allievating the issue by\r\n // simply not validating the worker if the page is null or closed.\r\n //\r\n // The actual result from when this happened, was that a worker would\r\n // be completely locked, stopping it from being acquired until\r\n // its work count reached the limit.\r\n\r\n // Check if the `page` is valid\r\n if (!poolResource.page) {\r\n log(\r\n 3,\r\n `[pool] Pool resource [${poolResource.id}] - Validation failed (no valid page is found).`\r\n );\r\n return false;\r\n }\r\n\r\n // Check if the `page` is closed\r\n if (poolResource.page.isClosed()) {\r\n log(\r\n 3,\r\n `[pool] Pool resource [${poolResource.id}] - Validation failed (page is closed or invalid).`\r\n );\r\n return false;\r\n }\r\n\r\n // Check if the `mainFrame` is detached\r\n if (poolResource.page.mainFrame().detached) {\r\n log(\r\n 3,\r\n `[pool] Pool resource [${poolResource.id}] - Validation failed (page's frame is detached).`\r\n );\r\n return false;\r\n }\r\n\r\n // Check if the `workLimit` is exceeded\r\n if (\r\n poolOptions.workLimit &&\r\n ++poolResource.workCount > poolOptions.workLimit\r\n ) {\r\n log(\r\n 3,\r\n `[pool] Pool resource [${poolResource.id}] - Validation failed (exceeded the ${poolOptions.workLimit} works per resource limit).`\r\n );\r\n return false;\r\n }\r\n\r\n // The `poolResource` is validated\r\n return true;\r\n },\r\n\r\n /**\r\n * Destroys a worker entry in the export pool, closing its associated page.\r\n *\r\n * @async\r\n * @function destroy\r\n *\r\n * @param {Object} poolResource - The handle to the worker, containing\r\n * the worker's ID, a reference to the browser page, and work count.\r\n */\r\n destroy: async (poolResource) => {\r\n log(\r\n 3,\r\n `[pool] Pool resource [${poolResource.id}] - Destroying a worker.`\r\n );\r\n\r\n if (poolResource.page && !poolResource.page.isClosed()) {\r\n try {\r\n // Remove all attached event listeners from the resource\r\n poolResource.page.removeAllListeners('pageerror');\r\n poolResource.page.removeAllListeners('console');\r\n poolResource.page.removeAllListeners('framedetached');\r\n\r\n // We need to wait around for this\r\n await poolResource.page.close();\r\n } catch (error) {\r\n log(\r\n 3,\r\n `[pool] Pool resource [${poolResource.id}] - Page could not be closed upon destroying.`\r\n );\r\n throw error;\r\n }\r\n }\r\n }\r\n };\r\n}\r\n\r\nexport default {\r\n initPool,\r\n killPool,\r\n postWork,\r\n getPool,\r\n getPoolStats,\r\n getPoolInfo,\r\n getPoolInfoJSON\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * @overview Used to sanitize the strings coming from the exporting module\r\n * to prevent XSS attacks (with the DOMPurify library).\r\n */\r\n\r\nimport DOMPurify from 'dompurify';\r\nimport { JSDOM } from 'jsdom';\r\n\r\n/**\r\n * Sanitizes a given HTML string by removing \r\n * tags and any content within them.\r\n *\r\n * @function sanitize\r\n *\r\n * @param {string} input - The HTML string to be sanitized.\r\n *\r\n * @returns {string} The sanitized HTML string.\r\n */\r\nexport function sanitize(input) {\r\n // Get the virtual DOM\r\n const window = new JSDOM('').window;\r\n\r\n // Create a purifying instance\r\n const purify = DOMPurify(window);\r\n\r\n // Return sanitized input\r\n return purify.sanitize(input, { ADD_TAGS: ['foreignObject'] });\r\n}\r\n\r\nexport default {\r\n sanitize\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * @overview This module provides functions to prepare for the exporting charts\r\n * into various image output formats such as JPEG, PNG, PDF, and SVGs.\r\n * It supports single and batch export operations and allows customization\r\n * through options passed from configurations or APIs.\r\n */\r\n\r\nimport { readFileSync, writeFileSync } from 'fs';\r\n\r\nimport {\r\n getOptions,\r\n isAllowedConfig,\r\n mergeOptions,\r\n validateOption,\r\n validateOptions\r\n} from './config.js';\r\nimport { log, logWithStack } from './logger.js';\r\nimport { getPoolStats, killPool, postWork } from './pool.js';\r\nimport { sanitize } from './sanitize.js';\r\nimport {\r\n deepCopy,\r\n fixConstr,\r\n fixOutfile,\r\n fixType,\r\n getAbsolutePath,\r\n getBase64,\r\n isObject,\r\n roundNumber,\r\n wrapAround\r\n} from './utils.js';\r\n\r\nimport ExportError from './errors/ExportError.js';\r\n\r\n// The global flag for the code execution permission\r\nlet allowCodeExecution = false;\r\n\r\n/**\r\n * Starts a single export process based on the specified options and saves\r\n * the resulting image to the provided output file.\r\n *\r\n * @async\r\n * @function singleExport\r\n *\r\n * @param {Object} options - The `options` object, which should include settings\r\n * from the `export` and `customLogic` sections. It can be a partial or complete\r\n * set of options from these sections. The object must contain at least one\r\n * of the following `export` properties: `infile`, `instr`, `options`, or `svg`\r\n * to generate a valid image.\r\n *\r\n * @returns {Promise} A Promise that resolves once the single export\r\n * process is completed.\r\n *\r\n * @throws {ExportError} Throws an `ExportError` if an error occurs during\r\n * the single export process.\r\n */\r\nexport async function singleExport(options) {\r\n // Check if the export makes sense\r\n if (options && options.export) {\r\n // Validate single export options\r\n options = validateOptions(options);\r\n\r\n // Perform an export\r\n await startExport(\r\n { export: options.export, customLogic: options.customLogic },\r\n async (error, data) => {\r\n // Exit process when error exists\r\n if (error) {\r\n throw error;\r\n }\r\n\r\n // Get the `b64`, `outfile`, and `type` for a chart\r\n const { b64, outfile, type } = data.options.export;\r\n\r\n // Save the result\r\n try {\r\n if (b64) {\r\n // As a Base64 string to a txt file\r\n writeFileSync(\r\n `${outfile.split('.').shift() || 'chart'}.txt`,\r\n getBase64(data.result, type)\r\n );\r\n } else {\r\n // As a correct image format\r\n writeFileSync(\r\n outfile || `chart.${type}`,\r\n type !== 'svg' ? Buffer.from(data.result, 'base64') : data.result\r\n );\r\n }\r\n } catch (error) {\r\n throw new ExportError(\r\n '[chart] Error while saving a chart.',\r\n 500\r\n ).setError(error);\r\n }\r\n\r\n // Kill pool and close browser after finishing single export\r\n await killPool();\r\n }\r\n );\r\n } else {\r\n throw new ExportError(\r\n '[chart] No expected `export` options were found. Please provide one of the following options: `infile`, `instr`, `options`, or `svg` to generate a valid image.',\r\n 400\r\n );\r\n }\r\n}\r\n\r\n/**\r\n * Starts a batch export process for multiple charts based on information\r\n * provided in the `batch` option. The `batch` is a string in the following\r\n * format: \"infile1.json=outfile1.png;infile2.json=outfile2.png;...\". Results\r\n * are saved to the specified output files.\r\n *\r\n * @async\r\n * @function batchExport\r\n *\r\n * @param {Object} options - The `options` object, which should include settings\r\n * from the `export` and `customLogic` sections. It can be a partial or complete\r\n * set of options from these sections. It must contain the `batch` option from\r\n * the `export` section to generate valid images.\r\n *\r\n * @returns {Promise} A Promise that resolves once the batch export\r\n * processes are completed.\r\n *\r\n * @throws {ExportError} Throws an `ExportError` if an error occurs during\r\n * any of the batch export process.\r\n */\r\nexport async function batchExport(options) {\r\n // Check if the export makes sense\r\n if (options && options.export && options.export.batch) {\r\n // Validate batch export options\r\n options = validateOptions(options);\r\n\r\n // An array for collecting batch exports\r\n const batchFunctions = [];\r\n\r\n // Split and pair the `batch` arguments\r\n for (let pair of options.export.batch.split(';') || []) {\r\n pair = pair.split('=');\r\n if (pair.length === 2) {\r\n batchFunctions.push(\r\n startExport(\r\n {\r\n export: {\r\n ...options.export,\r\n infile: pair[0],\r\n outfile: pair[1]\r\n },\r\n customLogic: options.customLogic\r\n },\r\n (error, data) => {\r\n // Exit process when error exists\r\n if (error) {\r\n throw error;\r\n }\r\n\r\n // Get the `b64`, `outfile`, and `type` for a chart\r\n const { b64, outfile, type } = data.options.export;\r\n\r\n // Save the result\r\n try {\r\n if (b64) {\r\n // As a Base64 string to a txt file\r\n writeFileSync(\r\n `${outfile.split('.').shift() || 'chart'}.txt`,\r\n getBase64(data.result, type)\r\n );\r\n } else {\r\n // As a correct image format\r\n writeFileSync(\r\n outfile,\r\n type !== 'svg'\r\n ? Buffer.from(data.result, 'base64')\r\n : data.result\r\n );\r\n }\r\n } catch (error) {\r\n throw new ExportError(\r\n '[chart] Error while saving a chart.',\r\n 500\r\n ).setError(error);\r\n }\r\n }\r\n )\r\n );\r\n } else {\r\n log(2, '[chart] No correct pair found for the batch export.');\r\n }\r\n }\r\n\r\n // Await all exports are done\r\n const batchResults = await Promise.allSettled(batchFunctions);\r\n\r\n // Kill pool and close browser after finishing batch export\r\n await killPool();\r\n\r\n // Log errors if found\r\n batchResults.forEach((result, index) => {\r\n // Log the error with stack about the specific batch export\r\n if (result.reason) {\r\n logWithStack(\r\n 1,\r\n result.reason,\r\n `[chart] Batch export number ${index + 1} could not be correctly completed.`\r\n );\r\n }\r\n });\r\n } else {\r\n throw new ExportError(\r\n '[chart] No expected `export` options were found. Please provide the `batch` option to generate valid images.',\r\n 400\r\n );\r\n }\r\n}\r\n\r\n/**\r\n * Starts an export process. The `exportingOptions` parameter is an object that\r\n * should include settings from the `export` and `customLogic` sections. It can\r\n * be a partial or complete set of options from these sections. If partial\r\n * options are provided, missing values will be merged with the current global\r\n * options.\r\n *\r\n * The `endCallback` function is invoked upon the completion of the export,\r\n * either successfully or with an error. The `error` object is provided\r\n * as the first argument, and the `data` object is the second, containing\r\n * the Base64 representation of the chart in the `result` property\r\n * and the complete set of options in the `options` property.\r\n *\r\n * @async\r\n * @function startExport\r\n *\r\n * @param {Object} exportingOptions - The `exportingOptions` object, which\r\n * should include settings from the `export` and `customLogic` sections. It can\r\n * be a partial or complete set of options from these sections. If the provided\r\n * options are partial, missing values will be merged with the current global\r\n * options.\r\n * @param {Function} endCallback - The callback function to be invoked upon\r\n * finalizing the export process or upon encountering an error. The first\r\n * argument is the `error` object, and the second argument is the `data` object,\r\n * which includes the Base64 representation of the chart in the `result`\r\n * property and the full set of options in the `options` property.\r\n *\r\n * @returns {Promise} This function does not return a value directly.\r\n * Instead, it communicates results via the `endCallback`.\r\n *\r\n * @throws {ExportError} Throws an `ExportError` if there is a problem with\r\n * processing input of any type. The error is passed into the `endCallback`\r\n * function and processed there.\r\n */\r\nexport async function startExport(exportingOptions, endCallback) {\r\n try {\r\n // Check if provided options is an object\r\n if (!isObject(exportingOptions)) {\r\n throw new ExportError(\r\n '[chart] Incorrect value of the provided `exportingOptions`. Needs to be an object.',\r\n 400\r\n );\r\n }\r\n\r\n // Merge additional options to the copy of the instance options\r\n const options = mergeOptions(deepCopy(getOptions()), {\r\n export: exportingOptions.export,\r\n customLogic: exportingOptions.customLogic\r\n });\r\n\r\n // Get the `export` options\r\n const exportOptions = options.export;\r\n\r\n // Starting exporting process message\r\n log(4, '[chart] Starting the exporting process.');\r\n\r\n // Export using options from the file as an input\r\n if (exportOptions.infile !== null) {\r\n log(4, '[chart] Attempting to export from a file input.');\r\n\r\n let fileContent;\r\n try {\r\n // Try to read the file to get the string representation\r\n fileContent = readFileSync(\r\n getAbsolutePath(exportOptions.infile),\r\n 'utf8'\r\n );\r\n } catch (error) {\r\n throw new ExportError(\r\n '[chart] Error loading content from a file input.',\r\n 400\r\n ).setError(error);\r\n }\r\n\r\n // Check the file's extension\r\n if (exportOptions.infile.endsWith('.svg')) {\r\n // Set to the `svg` option\r\n exportOptions.svg = validateOption('svg', fileContent);\r\n } else if (exportOptions.infile.endsWith('.json')) {\r\n // Set to the `instr` option\r\n exportOptions.instr = validateOption('instr', fileContent);\r\n } else {\r\n throw new ExportError(\r\n '[chart] Incorrect value of the `infile` option.',\r\n 400\r\n );\r\n }\r\n }\r\n\r\n // Export using SVG as an input\r\n if (exportOptions.svg !== null) {\r\n log(4, '[chart] Attempting to export from an SVG input.');\r\n\r\n // SVG exports attempts counter\r\n ++getPoolStats().exportsFromSvgAttempts;\r\n\r\n // Export from an SVG string\r\n const result = await _exportFromSvg(\r\n sanitize(exportOptions.svg), // #209\r\n options\r\n );\r\n\r\n // SVG exports counter\r\n ++getPoolStats().exportsFromSvg;\r\n\r\n // Pass SVG export result to the end callback\r\n return endCallback(null, result);\r\n }\r\n\r\n // Export using options as an input\r\n if (exportOptions.instr !== null || exportOptions.options !== null) {\r\n log(4, '[chart] Attempting to export from options input.');\r\n\r\n // Options exports attempts counter\r\n ++getPoolStats().exportsFromOptionsAttempts;\r\n\r\n // Export from options\r\n const result = await _exportFromOptions(\r\n exportOptions.instr || exportOptions.options,\r\n options\r\n );\r\n\r\n // Options exports counter\r\n ++getPoolStats().exportsFromOptions;\r\n\r\n // Pass options export result to the end callback\r\n return endCallback(null, result);\r\n }\r\n\r\n // No input specified, pass an error message to the callback\r\n return endCallback(\r\n new ExportError(\r\n `[chart] No valid input specified. Check if at least one of the following parameters is correctly set: 'infile', 'instr', 'options', or 'svg'.`,\r\n 400\r\n )\r\n );\r\n } catch (error) {\r\n return endCallback(error);\r\n }\r\n}\r\n\r\n/**\r\n * Retrieves and returns the current status of the code execution permission.\r\n *\r\n * @function getAllowCodeExecution\r\n *\r\n * @returns {boolean} The value of the global `allowCodeExecution` option.\r\n */\r\nexport function getAllowCodeExecution() {\r\n return allowCodeExecution;\r\n}\r\n\r\n/**\r\n * Sets the code execution permission based on the provided boolean value.\r\n *\r\n * @function setAllowCodeExecution\r\n *\r\n * @param {boolean} value - The boolean value to be assigned to the global\r\n * `allowCodeExecution` option.\r\n */\r\nexport function setAllowCodeExecution(value) {\r\n allowCodeExecution = value;\r\n}\r\n\r\n/**\r\n * Exports from an SVG based input with the provided options.\r\n *\r\n * @async\r\n * @function _exportFromSvg\r\n *\r\n * @param {string} inputToExport - The SVG based input to be exported.\r\n * @param {Object} options - The configuration object containing complete set\r\n * of options.\r\n *\r\n * @returns {Promise} A Promise that resolves to a result of the export\r\n * process.\r\n *\r\n * @throws {ExportError} Throws an `ExportError` if there is not a correct SVG\r\n * input.\r\n */\r\nasync function _exportFromSvg(inputToExport, options) {\r\n // Check if it is SVG\r\n if (\r\n typeof inputToExport === 'string' &&\r\n (inputToExport.indexOf('= 0 || inputToExport.indexOf('= 0)\r\n ) {\r\n log(4, '[chart] Parsing input as SVG.');\r\n\r\n // Set the export input as SVG\r\n options.export.svg = inputToExport;\r\n\r\n // Reset the rest of the export input options\r\n options.export.instr = null;\r\n options.export.options = null;\r\n\r\n // Call the function with an SVG string as an export input\r\n return _prepareExport(options);\r\n } else {\r\n throw new ExportError('[chart] Not a correct SVG input.', 400);\r\n }\r\n}\r\n\r\n/**\r\n * Exports from an options based input with the provided options.\r\n *\r\n * @async\r\n * @function _exportFromOptions\r\n *\r\n * @param {string} inputToExport - The options based input to be exported.\r\n * @param {Object} options - The configuration object containing complete set\r\n * of options.\r\n *\r\n * @returns {Promise} A Promise that resolves to a result of the export\r\n * process.\r\n *\r\n * @throws {ExportError} Throws an `ExportError` if there is not a correct\r\n * chart options input.\r\n */\r\nasync function _exportFromOptions(inputToExport, options) {\r\n log(4, '[chart] Parsing input from options.');\r\n\r\n // Try to check, validate and parse to stringified options\r\n const stringifiedOptions = isAllowedConfig(\r\n inputToExport,\r\n true,\r\n options.customLogic.allowCodeExecution\r\n );\r\n\r\n // Check if a correct stringified options\r\n if (\r\n stringifiedOptions === null ||\r\n typeof stringifiedOptions !== 'string' ||\r\n !stringifiedOptions.startsWith('{') ||\r\n !stringifiedOptions.endsWith('}')\r\n ) {\r\n throw new ExportError(\r\n '[chart] Invalid configuration provided - Only options configurations and SVG are allowed for this server. If this is your server, JavaScript custom code can be enabled by starting the server with the `allowCodeExecution` options set to true.',\r\n 403\r\n );\r\n }\r\n\r\n // Set the export input as a stringified chart options\r\n options.export.instr = stringifiedOptions;\r\n\r\n // Reset the rest of the export input options\r\n options.export.svg = null;\r\n\r\n // Call the function with a stringified chart options\r\n return _prepareExport(options);\r\n}\r\n\r\n/**\r\n * Function for finalizing options and configurations before export.\r\n *\r\n * @async\r\n * @function _prepareExport\r\n *\r\n * @param {Object} options - The configuration object containing complete set\r\n * of options.\r\n *\r\n * @returns {Promise} A Promise that resolves to a result of the export\r\n * process.\r\n */\r\nasync function _prepareExport(options) {\r\n const { export: exportOptions, customLogic: customLogicOptions } = options;\r\n\r\n // Prepare the `type` option\r\n exportOptions.type = fixType(exportOptions.type, exportOptions.outfile);\r\n\r\n // Prepare the `outfile` option\r\n exportOptions.outfile = fixOutfile(exportOptions.type, exportOptions.outfile);\r\n\r\n // Prepare the `constr` option\r\n exportOptions.constr = fixConstr(exportOptions.constr);\r\n\r\n // Notify about the custom logic usage status\r\n log(\r\n 3,\r\n `[chart] The custom logic is ${customLogicOptions.allowCodeExecution ? 'allowed' : 'disallowed'}.`\r\n );\r\n\r\n // Prepare the custom logic options (`customCode`, `callback`, `resources`)\r\n _handleCustomLogic(customLogicOptions, customLogicOptions.allowCodeExecution);\r\n\r\n // Prepare the `globalOptions` and `themeOptions` options\r\n _handleGlobalAndTheme(\r\n exportOptions,\r\n customLogicOptions.allowFileResources,\r\n customLogicOptions.allowCodeExecution\r\n );\r\n\r\n // Prepare the `height`, `width`, and `scale` options\r\n options.export = {\r\n ...exportOptions,\r\n ..._findChartSize(exportOptions)\r\n };\r\n\r\n // Post the work to the pool\r\n return postWork(options);\r\n}\r\n\r\n/**\r\n * Calculates the `height`, `width` and `scale` for chart exports based\r\n * on the provided export options.\r\n *\r\n * The function prioritizes values in the following order:\r\n * 1. The `height`, `width`, `scale` from the `exportOptions`.\r\n * 2. Options from the chart configuration (from `exporting` and `chart`).\r\n * 3. Options from the global options (from `exporting` and `chart`).\r\n * 4. Options from the theme options (from `exporting` and `chart` sections).\r\n * 5. Fallback default values (`height = 400`, `width = 600`, `scale = 1`).\r\n *\r\n * @function _findChartSize\r\n *\r\n * @param {Object} exportOptions - The configuration object containing `export`\r\n * options.\r\n *\r\n * @returns {Object} The object containing calculated `height`, `width`\r\n * and `scale` values for the chart export.\r\n */\r\nfunction _findChartSize(exportOptions) {\r\n // Check the `options` and `instr` for chart and exporting sections\r\n const { chart: optionsChart, exporting: optionsExporting } =\r\n exportOptions.options || isAllowedConfig(exportOptions.instr) || false;\r\n\r\n // Check the `globalOptions` for chart and exporting sections\r\n const { chart: globalOptionsChart, exporting: globalOptionsExporting } =\r\n isAllowedConfig(exportOptions.globalOptions) || false;\r\n\r\n // Check the `themeOptions` for chart and exporting sections\r\n const { chart: themeOptionsChart, exporting: themeOptionsExporting } =\r\n isAllowedConfig(exportOptions.themeOptions) || false;\r\n\r\n // Find the `scale` value:\r\n // - It cannot be lower than 0.1\r\n // - It cannot be higher than 5.0\r\n // - It must be rounded to 2 decimal places (e.g. 0.23234 -> 0.23)\r\n const scale = roundNumber(\r\n Math.max(\r\n 0.1,\r\n Math.min(\r\n exportOptions.scale ||\r\n optionsExporting?.scale ||\r\n globalOptionsExporting?.scale ||\r\n themeOptionsExporting?.scale ||\r\n exportOptions.defaultScale ||\r\n 1,\r\n 5.0\r\n )\r\n ),\r\n 2\r\n );\r\n\r\n // Find the `height` value\r\n const height =\r\n exportOptions.height ||\r\n optionsExporting?.sourceHeight ||\r\n optionsChart?.height ||\r\n globalOptionsExporting?.sourceHeight ||\r\n globalOptionsChart?.height ||\r\n themeOptionsExporting?.sourceHeight ||\r\n themeOptionsChart?.height ||\r\n exportOptions.defaultHeight ||\r\n 400;\r\n\r\n // Find the `width` value\r\n const width =\r\n exportOptions.width ||\r\n optionsExporting?.sourceWidth ||\r\n optionsChart?.width ||\r\n globalOptionsExporting?.sourceWidth ||\r\n globalOptionsChart?.width ||\r\n themeOptionsExporting?.sourceWidth ||\r\n themeOptionsChart?.width ||\r\n exportOptions.defaultWidth ||\r\n 600;\r\n\r\n // Gather `height`, `width` and `scale` information in one object\r\n const size = { height, width, scale };\r\n\r\n // Get rid of potential `px` and `%`\r\n for (let [param, value] of Object.entries(size)) {\r\n size[param] =\r\n typeof value === 'string' ? +value.replace(/px|%/gi, '') : value;\r\n }\r\n\r\n // Return the size object\r\n return size;\r\n}\r\n\r\n/**\r\n * Handles the execution of custom logic options, including loading `resources`,\r\n * `customCode`, and `callback`. If code execution is allowed, it processes\r\n * the custom logic options accordingly. If code execution is not allowed,\r\n * it disables the usage of resources, custom code and callback.\r\n *\r\n * @function _handleCustomLogic\r\n *\r\n * @param {Object} customLogicOptions - The configuration object containing\r\n * `customLogic` options.\r\n * @param {boolean} allowCodeExecution - A flag indicating whether code\r\n * execution is allowed.\r\n *\r\n * @throws {ExportError} Throws an `ExportError` if code execution\r\n * is not allowed but custom logic options are still provided.\r\n */\r\nfunction _handleCustomLogic(customLogicOptions, allowCodeExecution) {\r\n // In case of allowing code execution\r\n if (allowCodeExecution) {\r\n // Process the `resources` option\r\n if (typeof customLogicOptions.resources === 'string') {\r\n // Custom stringified resources\r\n customLogicOptions.resources = _handleResources(\r\n customLogicOptions.resources,\r\n customLogicOptions.allowFileResources,\r\n true\r\n );\r\n } else if (!customLogicOptions.resources) {\r\n try {\r\n // Load the default one\r\n customLogicOptions.resources = _handleResources(\r\n readFileSync(getAbsolutePath('resources.json'), 'utf8'),\r\n customLogicOptions.allowFileResources,\r\n true\r\n );\r\n } catch (error) {\r\n log(2, '[chart] Unable to load the default `resources.json` file.');\r\n }\r\n }\r\n\r\n // Process the `customCode` option\r\n try {\r\n // Try to load custom code and wrap around it in a self invoking function\r\n customLogicOptions.customCode = wrapAround(\r\n customLogicOptions.customCode,\r\n customLogicOptions.allowFileResources\r\n );\r\n\r\n // Validate the option\r\n customLogicOptions.customCode = validateOption(\r\n 'customCode',\r\n customLogicOptions.customCode\r\n );\r\n } catch (error) {\r\n logWithStack(2, error, '[chart] The `customCode` cannot be loaded.');\r\n\r\n // In case of an error, set the option with null\r\n customLogicOptions.customCode = null;\r\n }\r\n\r\n // Process the `callback` option\r\n try {\r\n // Try to load callback function\r\n customLogicOptions.callback = wrapAround(\r\n customLogicOptions.callback,\r\n customLogicOptions.allowFileResources,\r\n true\r\n );\r\n\r\n // Validate the option\r\n customLogicOptions.callback = validateOption(\r\n 'callback',\r\n customLogicOptions.callback\r\n );\r\n } catch (error) {\r\n logWithStack(2, error, '[chart] The `callback` cannot be loaded.');\r\n\r\n // In case of an error, set the option with null\r\n customLogicOptions.callback = null;\r\n }\r\n\r\n // Check if there is the `customCode` present\r\n if ([null, undefined].includes(customLogicOptions.customCode)) {\r\n log(3, '[chart] No value for the `customCode` option found.');\r\n }\r\n\r\n // Check if there is the `callback` present\r\n if ([null, undefined].includes(customLogicOptions.callback)) {\r\n log(3, '[chart] No value for the `callback` option found.');\r\n }\r\n\r\n // Check if there is the `resources` present\r\n if ([null, undefined].includes(customLogicOptions.resources)) {\r\n log(3, '[chart] No value for the `resources` option found.');\r\n }\r\n } else {\r\n // If the `allowCodeExecution` flag is set to false, we should refuse\r\n // the usage of the `callback`, `resources`, and `customCode` options.\r\n // Additionally, the worker will refuse to run arbitrary JavaScript.\r\n if (\r\n customLogicOptions.callback ||\r\n customLogicOptions.resources ||\r\n customLogicOptions.customCode\r\n ) {\r\n // Reset all custom code options\r\n customLogicOptions.callback = null;\r\n customLogicOptions.resources = null;\r\n customLogicOptions.customCode = null;\r\n\r\n // Send a message saying that the exporter does not support these settings\r\n throw new ExportError(\r\n `[chart] The 'callback', 'resources', and 'customCode' options have been disabled for this server.`,\r\n 403\r\n );\r\n }\r\n }\r\n}\r\n\r\n/**\r\n * Handles and validates resources from the `resources` option for export.\r\n *\r\n * @function _handleResources\r\n *\r\n * @param {(Object|string|null)} [resources=null] - The resources to be handled.\r\n * Can be either a JSON object, stringified JSON, a path to a JSON file,\r\n * or null. The default value is `null`.\r\n * @param {boolean} allowFileResources - A flag indicating whether loading\r\n * resources from files is allowed.\r\n * @param {boolean} allowCodeExecution - A flag indicating whether code\r\n * execution is allowed.\r\n *\r\n * @returns {(Object|null)} The handled resources or null if no valid resources\r\n * are found.\r\n */\r\nfunction _handleResources(\r\n resources = null,\r\n allowFileResources,\r\n allowCodeExecution\r\n) {\r\n // List of allowed sections in the resources JSON\r\n const allowedProps = ['js', 'css', 'files'];\r\n\r\n let handledResources = resources;\r\n let correctResources = false;\r\n\r\n // Try to load resources from a file\r\n if (allowFileResources && resources.endsWith('.json')) {\r\n try {\r\n handledResources = isAllowedConfig(\r\n readFileSync(getAbsolutePath(resources), 'utf8'),\r\n false,\r\n allowCodeExecution\r\n );\r\n } catch {\r\n return null;\r\n }\r\n } else {\r\n // Try to get JSON\r\n handledResources = isAllowedConfig(resources, false, allowCodeExecution);\r\n\r\n // Get rid of the files section\r\n if (handledResources && !allowFileResources) {\r\n delete handledResources.files;\r\n }\r\n }\r\n\r\n // Filter from unnecessary properties\r\n for (const propName in handledResources) {\r\n if (!allowedProps.includes(propName)) {\r\n delete handledResources[propName];\r\n } else if (!correctResources) {\r\n correctResources = true;\r\n }\r\n }\r\n\r\n // Check if at least one of allowed properties is present\r\n if (!correctResources) {\r\n return null;\r\n }\r\n\r\n // Handle files section\r\n if (handledResources.files) {\r\n handledResources.files = handledResources.files.map((item) => item.trim());\r\n if (!handledResources.files || handledResources.files.length <= 0) {\r\n delete handledResources.files;\r\n }\r\n }\r\n\r\n // Validate option\r\n handledResources = validateOption('resources', handledResources);\r\n\r\n // Return resources\r\n return handledResources;\r\n}\r\n\r\n/**\r\n * Handles the loading and validation of the `globalOptions` and `themeOptions`\r\n * in the export options. If the option is a string and references a JSON file\r\n * (when the `allowFileResources` is true), it reads and parses the file.\r\n * Otherwise, it attempts to parse the string or object as JSON. If any errors\r\n * occur during this process, the option is set to null. If there is an error\r\n * loading or parsing the `globalOptions` or `themeOptions`, the error is logged\r\n * and the option is set to null.\r\n *\r\n * @function _handleGlobalAndTheme\r\n *\r\n * @param {Object} exportOptions - The configuration object containing `export`\r\n * options.\r\n * @param {boolean} allowFileResources - A flag indicating whether loading\r\n * resources from files is allowed.\r\n * @param {boolean} allowCodeExecution - A flag indicating whether code\r\n * execution is allowed.\r\n */\r\nfunction _handleGlobalAndTheme(\r\n exportOptions,\r\n allowFileResources,\r\n allowCodeExecution\r\n) {\r\n // Check the `globalOptions` and `themeOptions` options\r\n ['globalOptions', 'themeOptions'].forEach((optionsName) => {\r\n try {\r\n // Check if the option exists\r\n if (exportOptions[optionsName]) {\r\n // Check if it is a string and a file name with the `.json` extension\r\n if (\r\n allowFileResources &&\r\n typeof exportOptions[optionsName] === 'string' &&\r\n exportOptions[optionsName].endsWith('.json')\r\n ) {\r\n // Check if the file content can be a config, and save it as a string\r\n exportOptions[optionsName] = isAllowedConfig(\r\n readFileSync(getAbsolutePath(exportOptions[optionsName]), 'utf8'),\r\n true,\r\n allowCodeExecution\r\n );\r\n } else {\r\n // Check if the value can be a config, and save it as a string\r\n exportOptions[optionsName] = isAllowedConfig(\r\n exportOptions[optionsName],\r\n true,\r\n allowCodeExecution\r\n );\r\n }\r\n\r\n // Validate the option\r\n exportOptions[optionsName] = validateOption(\r\n optionsName,\r\n exportOptions[optionsName]\r\n );\r\n }\r\n } catch (error) {\r\n logWithStack(\r\n 2,\r\n error,\r\n `[chart] The \\`${optionsName}\\` cannot be loaded.`\r\n );\r\n\r\n // In case of an error, set the option with null\r\n exportOptions[optionsName] = null;\r\n }\r\n });\r\n\r\n // Check if there is the `globalOptions` present\r\n if ([null, undefined].includes(exportOptions.globalOptions)) {\r\n log(3, '[chart] No value for the `globalOptions` option found.');\r\n }\r\n\r\n // Check if there is the `themeOptions` present\r\n if ([null, undefined].includes(exportOptions.themeOptions)) {\r\n log(3, '[chart] No value for the `themeOptions` option found.');\r\n }\r\n}\r\n\r\nexport default {\r\n singleExport,\r\n batchExport,\r\n startExport,\r\n getAllowCodeExecution,\r\n setAllowCodeExecution\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * @overview This module provides utility functions for managing intervals\r\n * and timeouts in a centralized manner. It maintains a registry of all active\r\n * timers and allows for their efficient cleanup when needed. This can be useful\r\n * in applications where proper resource management and clean shutdown of timers\r\n * are critical to avoid memory leaks or unintended behavior.\r\n */\r\n\r\nimport { log } from './logger.js';\r\n\r\n// Array that contains ids of all ongoing intervals and timeouts\r\nconst timerIds = [];\r\n\r\n/**\r\n * Adds id of the `setInterval` or `setTimeout` and to the `timerIds` array.\r\n *\r\n * @function addTimer\r\n *\r\n * @param {NodeJS.Timeout} id - Id of an interval or a timeout.\r\n */\r\nexport function addTimer(id) {\r\n timerIds.push(id);\r\n}\r\n\r\n/**\r\n * Clears all of ongoing intervals and timeouts by ids gathered\r\n * in the `timerIds` array.\r\n *\r\n * @function clearAllTimers\r\n */\r\nexport function clearAllTimers() {\r\n log(4, `[timer] Clearing all registered intervals and timeouts.`);\r\n for (const id of timerIds) {\r\n clearInterval(id);\r\n clearTimeout(id);\r\n }\r\n}\r\n\r\nexport default {\r\n addTimer,\r\n clearAllTimers\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * @overview Provides middleware functions for logging errors with stack traces\r\n * and handling error responses in an Express application.\r\n */\r\n\r\nimport { getOptions } from '../../config.js';\r\nimport { logWithStack } from '../../logger.js';\r\n\r\n/**\r\n * Middleware for logging errors with stack trace and handling error response.\r\n *\r\n * @function logErrorMiddleware\r\n *\r\n * @param {Error} error - The error object.\r\n * @param {Express.Request} request - The Express request object.\r\n * @param {Express.Response} response - The Express response object.\r\n * @param {Function} next - The next middleware function.\r\n *\r\n * @returns {undefined} The call to the next middleware function with\r\n * the passed error.\r\n */\r\nfunction logErrorMiddleware(error, request, response, next) {\r\n // Display the error with stack in a correct format\r\n logWithStack(1, error);\r\n\r\n // Delete the stack for the environment other than the development\r\n if (getOptions().other.nodeEnv !== 'development') {\r\n delete error.stack;\r\n }\r\n\r\n // Call the `returnErrorMiddleware` middleware\r\n return next(error);\r\n}\r\n\r\n/**\r\n * Middleware for returning error response.\r\n *\r\n * @function returnErrorMiddleware\r\n *\r\n * @param {Error} error - The error object.\r\n * @param {Express.Request} request - The Express request object.\r\n * @param {Express.Response} response - The Express response object.\r\n * @param {Function} next - The next middleware function.\r\n */\r\nfunction returnErrorMiddleware(error, request, response, next) {\r\n // Gather all requied information for the response\r\n const { message, stack } = error;\r\n\r\n // Use the error's status code or the default 400\r\n const statusCode = error.statusCode || 400;\r\n\r\n // Set and return response\r\n response.status(statusCode).json({ statusCode, message, stack });\r\n}\r\n\r\n/**\r\n * Adds the error middlewares to the passed express app instance.\r\n *\r\n * @param {Express} app - The Express app instance.\r\n */\r\nexport default function errorMiddleware(app) {\r\n // Add log error middleware\r\n app.use(logErrorMiddleware);\r\n\r\n // Add set status and return error middleware\r\n app.use(returnErrorMiddleware);\r\n}\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * @overview Provides middleware functions for configuring and enabling rate\r\n * limiting in an Express application.\r\n */\r\n\r\nimport rateLimit from 'express-rate-limit';\r\n\r\nimport { log } from '../../logger.js';\r\n\r\nimport ExportError from '../../errors/ExportError.js';\r\n\r\n/**\r\n * Middleware for enabling rate limiting on the specified Express app.\r\n *\r\n * @param {Express} app - The Express app instance.\r\n *\r\n * @param {Object} rateLimitingOptions - The configuration object containing\r\n * `rateLimiting` options.\r\n *\r\n * @throws {ExportError} Throws an `ExportError` if could not configure and set\r\n * the rate limiting options.\r\n */\r\nexport default function rateLimitingMiddleware(app, rateLimitingOptions) {\r\n try {\r\n // Check if the rate limiting is enabled\r\n if (rateLimitingOptions.enable) {\r\n const message =\r\n 'Too many requests, you have been rate limited. Please try again later.';\r\n\r\n // Options for the rate limiter\r\n const rateOptions = {\r\n window: rateLimitingOptions.window || 1,\r\n maxRequests: rateLimitingOptions.maxRequests || 30,\r\n delay: rateLimitingOptions.delay || 0,\r\n trustProxy: rateLimitingOptions.trustProxy || false,\r\n skipKey: rateLimitingOptions.skipKey || null,\r\n skipToken: rateLimitingOptions.skipToken || null\r\n };\r\n\r\n // Set if behind a proxy\r\n if (rateOptions.trustProxy) {\r\n app.enable('trust proxy');\r\n }\r\n\r\n // Create a limiter\r\n const limiter = rateLimit({\r\n // Time frame for which requests are checked and remembered\r\n windowMs: rateOptions.window * 60 * 1000,\r\n // Limit each IP to 100 requests per `windowMs`\r\n limit: rateOptions.maxRequests,\r\n // Disable delaying, full speed until the max limit is reached\r\n delayMs: rateOptions.delay,\r\n handler: (request, response) => {\r\n response.format({\r\n json: () => {\r\n response.status(429).send({ message });\r\n },\r\n default: () => {\r\n response.status(429).send(message);\r\n }\r\n });\r\n },\r\n skip: (request) => {\r\n // Allow bypassing the limiter if a valid key/token has been sent\r\n if (\r\n rateOptions.skipKey !== null &&\r\n rateOptions.skipToken !== null &&\r\n request.query.key === rateOptions.skipKey &&\r\n request.query.access_token === rateOptions.skipToken\r\n ) {\r\n log(4, '[rate limiting] Skipping rate limiter.');\r\n return true;\r\n }\r\n return false;\r\n }\r\n });\r\n\r\n // Use a limiter as a middleware\r\n app.use(limiter);\r\n\r\n log(\r\n 3,\r\n `[rate limiting] Enabled rate limiting with ${rateOptions.maxRequests} requests per ${rateOptions.window} minute for each IP, trusting proxy: ${rateOptions.trustProxy}.`\r\n );\r\n }\r\n } catch (error) {\r\n throw new ExportError(\r\n '[rate limiting] Could not configure and set the rate limiting options.',\r\n 500\r\n ).setError(error);\r\n }\r\n}\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * @overview Provides middleware functions for validating incoming HTTP requests\r\n * in an Express application. This module ensures that requests contain\r\n * appropriate content types and valid request bodies, including proper JSON\r\n * structures and chart data for exports. It checks for potential issues such\r\n * as missing or malformed data, private range URLs in SVG payloads, and allows\r\n * for flexible options validation. The middleware logs detailed information\r\n * and handles errors related to incorrect payloads, chart data, and private URL\r\n * usage.\r\n */\r\n\r\nimport { v4 as uuid } from 'uuid';\r\n\r\nimport { getAllowCodeExecution } from '../../chart.js';\r\nimport { isAllowedConfig, validateOptions } from '../../config.js';\r\nimport { log, logZodIssues } from '../../logger.js';\r\nimport {\r\n fixConstr,\r\n fixType,\r\n isObjectEmpty,\r\n isPrivateRangeUrlFound\r\n} from '../../utils.js';\r\nimport { looseValidate } from '../../validation.js';\r\n\r\nimport ExportError from '../../errors/ExportError.js';\r\n\r\n/**\r\n * Middleware for validating the content-type header.\r\n *\r\n * @function contentTypeMiddleware\r\n *\r\n * @param {Express.Request} request - The Express request object.\r\n * @param {Express.Response} response - The Express response object.\r\n * @param {Function} next - The next middleware function.\r\n *\r\n * @returns {undefined} The call to the next middleware function.\r\n *\r\n * @throws {ExportError} Throws an `ExportError` if the content-type\r\n * is not correct.\r\n */\r\nfunction contentTypeMiddleware(request, response, next) {\r\n try {\r\n // Get the content type header\r\n const contentType = request.headers['content-type'] || '';\r\n\r\n // Allow only JSON, URL-encoded and form data without files types of data\r\n if (\r\n !contentType.includes('application/json') &&\r\n !contentType.includes('application/x-www-form-urlencoded') &&\r\n !contentType.includes('multipart/form-data')\r\n ) {\r\n throw new ExportError(\r\n '[validation] Content-Type must be application/json, application/x-www-form-urlencoded, or multipart/form-data.',\r\n 415\r\n );\r\n }\r\n\r\n // Call the `requestBodyMiddleware` middleware\r\n return next();\r\n } catch (error) {\r\n return next(error);\r\n }\r\n}\r\n\r\n/**\r\n * Middleware for validating the request's body.\r\n *\r\n * @function requestBodyMiddleware\r\n *\r\n * @param {Express.Request} request - The Express request object.\r\n * @param {Express.Response} response - The Express response object.\r\n * @param {Function} next - The next middleware function.\r\n *\r\n * @returns {undefined} The call to the next middleware function.\r\n *\r\n * @throws {ExportError} Throws an `ExportError` if the body is not correct.\r\n * @throws {ExportError} Throws an `ExportError` if the chart data from the body\r\n * is not correct.\r\n * @throws {ExportError} Throws an `ExportError` in case of the private range\r\n * url error.\r\n */\r\nfunction requestBodyMiddleware(request, response, next) {\r\n try {\r\n // Get the request body\r\n const body = request.body;\r\n\r\n // Create a unique ID for a request\r\n const requestId = uuid();\r\n\r\n // Throw an error if there is no correct body\r\n if (!body || isObjectEmpty(body)) {\r\n log(\r\n 2,\r\n `[validation] Request [${requestId}] - The request from ${\r\n request.headers['x-forwarded-for'] || request.connection.remoteAddress\r\n } was incorrect. Received payload is empty.`\r\n );\r\n\r\n throw new ExportError(\r\n `[validation] Request [${requestId}] - The request body is required. Please ensure that your Content-Type header is correct. Accepted types are 'application/json' and 'multipart/form-data'.`,\r\n 400\r\n );\r\n }\r\n\r\n // Get the `allowCodeExecution` option for the server\r\n const allowCodeExecution = getAllowCodeExecution();\r\n\r\n // Find a correct chart options\r\n const instr = isAllowedConfig(\r\n // Use one of the below\r\n body.instr || body.options || body.infile || body.data,\r\n // Stringify options\r\n true,\r\n // Allow or disallow functions\r\n allowCodeExecution\r\n );\r\n\r\n // Throw an error if there is no correct chart data\r\n if (instr === null && !body.svg) {\r\n log(\r\n 2,\r\n `[validation] Request [${requestId}] - The request from ${\r\n request.headers['x-forwarded-for'] || request.connection.remoteAddress\r\n } was incorrect. Received payload is missing correct chart data for export: ${JSON.stringify(body)}.`\r\n );\r\n\r\n throw new ExportError(\r\n `Request [${requestId}] - [validation] No correct chart data found. Ensure that you are using either application/json or multipart/form-data headers. If sending JSON, make sure the chart data is in the 'infile', 'options', or 'data' attribute. If sending SVG, ensure it is in the 'svg' attribute.`,\r\n 400\r\n );\r\n }\r\n\r\n // Throw an error if test of xlink:href elements from payload's SVG fails\r\n if (body.svg && isPrivateRangeUrlFound(body.svg)) {\r\n throw new ExportError(\r\n `Request [${requestId}] - [validation] SVG potentially contain at least one forbidden URL in 'xlink:href' element. Please review the SVG content and ensure that all referenced URLs comply with security policies.`,\r\n 400\r\n );\r\n }\r\n\r\n // Validate the request options and store parsed structure in the request\r\n request.validatedOptions = validateOptions({\r\n // Set the created ID as a `requestId` property in the options\r\n requestId,\r\n export: {\r\n instr,\r\n svg: body.svg,\r\n outfile:\r\n body.outfile ||\r\n `${request.params.filename || 'chart'}.${body.type || 'png'}`,\r\n type: body.type,\r\n constr: body.constr,\r\n b64: body.b64,\r\n noDownload: body.noDownload,\r\n height: body.height,\r\n width: body.width,\r\n scale: body.scale,\r\n globalOptions: isAllowedConfig(\r\n body.globalOptions,\r\n true,\r\n allowCodeExecution\r\n ),\r\n themeOptions: isAllowedConfig(\r\n body.themeOptions,\r\n true,\r\n allowCodeExecution\r\n )\r\n },\r\n customLogic: {\r\n allowCodeExecution,\r\n allowFileResources: false,\r\n customCode: body.customCode,\r\n callback: body.callback,\r\n resources: isAllowedConfig(body.resources, true, allowCodeExecution)\r\n }\r\n });\r\n\r\n // Call the next middleware\r\n return next();\r\n } catch (error) {\r\n return next(error);\r\n }\r\n}\r\n\r\n/**\r\n * Adds the validation middlewares to the passed express app instance.\r\n *\r\n * @param {Express} app - The Express app instance.\r\n */\r\nexport default function validationMiddleware(app) {\r\n // Add content type validation middleware\r\n app.post(['/', '/:filename'], contentTypeMiddleware);\r\n\r\n // Add request body request validation middleware\r\n app.post(['/', '/:filename'], requestBodyMiddleware);\r\n}\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * @overview Defines the export routes and logic for handling chart export\r\n * requests in an Express server. This module processes incoming requests\r\n * to export charts in various formats (e.g. JPEG, PNG, PDF, SVG). It integrates\r\n * with Highcharts' core functionalities and supports both immediate download\r\n * responses and Base64-encoded content returns. The code also features\r\n * benchmarking for performance monitoring.\r\n */\r\n\r\nimport { startExport } from '../../chart.js';\r\nimport { log } from '../../logger.js';\r\nimport { getBase64, measureTime } from '../../utils.js';\r\n\r\nimport ExportError from '../../errors/ExportError.js';\r\n\r\n// Reversed MIME types\r\nconst reversedMime = {\r\n png: 'image/png',\r\n jpeg: 'image/jpeg',\r\n gif: 'image/gif',\r\n pdf: 'application/pdf',\r\n svg: 'image/svg+xml'\r\n};\r\n\r\n/**\r\n * Handles the export requests from the client.\r\n *\r\n * @async\r\n * @function requestExport\r\n *\r\n * @param {Express.Request} request - The Express request object.\r\n * @param {Express.Response} response - The Express response object.\r\n * @param {Function} next - The next middleware function.\r\n *\r\n * @returns {Promise} A Promise that resolves once the export process\r\n * is complete.\r\n */\r\nasync function requestExport(request, response, next) {\r\n try {\r\n // Start counting time for a request\r\n const requestCounter = measureTime();\r\n\r\n // In case the connection is closed, force to abort further actions\r\n let connectionAborted = false;\r\n request.socket.on('close', (hadErrors) => {\r\n if (hadErrors) {\r\n connectionAborted = true;\r\n }\r\n });\r\n\r\n // Get the options previously validated in the validation middleware\r\n const requestOptions = request.validatedOptions;\r\n\r\n // Get the request id\r\n const requestId = requestOptions.requestId;\r\n\r\n // Info about an incoming request with correct data\r\n log(4, `[export] Request [${requestId}] - Got an incoming HTTP request.`);\r\n\r\n // Start the export process\r\n await startExport(requestOptions, (error, data) => {\r\n // Remove the close event from the socket\r\n request.socket.removeAllListeners('close');\r\n\r\n // If the connection was closed, do nothing\r\n if (connectionAborted) {\r\n log(\r\n 3,\r\n `[export] Request [${requestId}] - The client closed the connection before the chart finished processing.`\r\n );\r\n return;\r\n }\r\n\r\n // If error, log it and send it to the error middleware\r\n if (error) {\r\n throw error;\r\n }\r\n\r\n // If data is missing, log the message and send it to the error middleware\r\n if (!data || !data.result) {\r\n log(\r\n 2,\r\n `[export] Request [${requestId}] - Request from ${\r\n request.headers['x-forwarded-for'] ||\r\n request.connection.remoteAddress\r\n } was incorrect. Received result is ${data.result}.`\r\n );\r\n\r\n throw new ExportError(\r\n `[export] Request [${requestId}] - Unexpected return of the export result from the chart generation. Please check your request data.`,\r\n 400\r\n );\r\n }\r\n\r\n // Return the result in an appropriate format\r\n if (data.result) {\r\n log(\r\n 3,\r\n `[export] Request [${requestId}] - The whole exporting process took ${requestCounter()}ms.`\r\n );\r\n\r\n // Get the `type`, `b64`, `noDownload`, and `outfile` from options\r\n const { type, b64, noDownload, outfile } = data.options.export;\r\n\r\n // If only Base64 is required, return it\r\n if (b64) {\r\n return response.send(getBase64(data.result, type));\r\n }\r\n\r\n // Set correct content type\r\n response.header('Content-Type', reversedMime[type] || 'image/png');\r\n\r\n // Decide whether to download or not chart file\r\n if (!noDownload) {\r\n response.attachment(outfile);\r\n }\r\n\r\n // If SVG, return plain content, otherwise a b64 string from a buffer\r\n return type === 'svg'\r\n ? response.send(data.result)\r\n : response.send(Buffer.from(data.result, 'base64'));\r\n }\r\n });\r\n } catch (error) {\r\n return next(error);\r\n }\r\n}\r\n\r\n/**\r\n * Adds the `export` routes.\r\n *\r\n * @function exportRoutes\r\n *\r\n * @param {Express} app - The Express app instance.\r\n */\r\nexport default function exportRoutes(app) {\r\n /**\r\n * Adds the POST '/' - A route for handling POST requests at the root\r\n * endpoint.\r\n */\r\n app.post('/', requestExport);\r\n\r\n /**\r\n * Adds the POST '/:filename' - A route for handling POST requests with\r\n * a specified filename parameter.\r\n */\r\n app.post('/:filename', requestExport);\r\n}\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * @overview Defines an Express route for server health monitoring, including\r\n * uptime, success rates, and other server statistics.\r\n */\r\n\r\nimport { readFileSync } from 'fs';\r\nimport { join } from 'path';\r\n\r\nimport { getHighchartsVersion } from '../../cache.js';\r\nimport { log } from '../../logger.js';\r\nimport { getPoolStats, getPoolInfoJSON } from '../../pool.js';\r\nimport { addTimer } from '../../timer.js';\r\nimport { __dirname, getNewDateTime } from '../../utils.js';\r\n\r\n// Set the start date of the server\r\nconst serverStartTime = new Date();\r\n\r\n// Get the `package.json` content\r\nconst packageFile = JSON.parse(\r\n readFileSync(join(__dirname, 'package.json'), 'utf8')\r\n);\r\n\r\n// An array for success rate ratios\r\nconst successRates = [];\r\n\r\n// Record every minute\r\nconst recordInterval = 60 * 1000;\r\n\r\n// 30 minutes\r\nconst windowSize = 30;\r\n\r\n/**\r\n * Calculates moving average indicator based on the data from the `successRates`\r\n * array.\r\n *\r\n * @function _calculateMovingAverage\r\n *\r\n * @returns {number} A moving average for success ratio of the server exports.\r\n */\r\nfunction _calculateMovingAverage() {\r\n return successRates.reduce((a, b) => a + b, 0) / successRates.length;\r\n}\r\n\r\n/**\r\n * Starts the interval responsible for calculating current success rate ratio\r\n * and collects records to the `successRates` array.\r\n *\r\n * @function _startSuccessRate\r\n *\r\n * @returns {NodeJS.Timeout} Id of an interval.\r\n */\r\nfunction _startSuccessRate() {\r\n return setInterval(() => {\r\n const stats = getPoolStats();\r\n const successRatio =\r\n stats.exportsAttempted === 0\r\n ? 1\r\n : (stats.exportsPerformed / stats.exportsAttempted) * 100;\r\n\r\n successRates.push(successRatio);\r\n if (successRates.length > windowSize) {\r\n successRates.shift();\r\n }\r\n }, recordInterval);\r\n}\r\n\r\n/**\r\n * Adds the `health` routes.\r\n *\r\n * @function healthRoutes\r\n *\r\n * @param {Express} app - The Express app instance.\r\n */\r\nexport default function healthRoutes(app) {\r\n // Start processing success rate ratio interval and save its id to the array\r\n // for the graceful clearing on shutdown with injected `addTimer` funtion\r\n addTimer(_startSuccessRate());\r\n\r\n /**\r\n * Adds the GET '/health' - A route for getting the basic stats of the server.\r\n */\r\n app.get('/health', (request, response, next) => {\r\n try {\r\n log(4, '[health] Returning server health.');\r\n\r\n const stats = getPoolStats();\r\n const period = successRates.length;\r\n const movingAverage = _calculateMovingAverage();\r\n\r\n // Send the server's statistics\r\n response.send({\r\n // Status and times\r\n status: 'OK',\r\n bootTime: serverStartTime,\r\n uptime: `${Math.floor((getNewDateTime() - serverStartTime.getTime()) / 1000 / 60)} minutes`,\r\n\r\n // Versions\r\n serverVersion: packageFile.version,\r\n highchartsVersion: getHighchartsVersion(),\r\n\r\n // Exports\r\n averageExportTime: stats.timeSpentAverage,\r\n attemptedExports: stats.exportsAttempted,\r\n performedExports: stats.exportsPerformed,\r\n failedExports: stats.exportsDropped,\r\n sucessRatio: (stats.exportsPerformed / stats.exportsAttempted) * 100,\r\n\r\n // Pool\r\n pool: getPoolInfoJSON(),\r\n\r\n // Moving average\r\n period,\r\n movingAverage,\r\n message:\r\n isNaN(movingAverage) || !successRates.length\r\n ? 'Too early to report. No exports made yet. Please check back soon.'\r\n : `Last ${period} minutes had a success rate of ${movingAverage.toFixed(2)}%.`,\r\n\r\n // SVG and JSON exports\r\n svgExports: stats.exportsFromSvg,\r\n jsonExports: stats.exportsFromOptions,\r\n svgExportsAttempts: stats.exportsFromSvgAttempts,\r\n jsonExportsAttempts: stats.exportsFromOptionsAttempts\r\n });\r\n } catch (error) {\r\n return next(error);\r\n }\r\n });\r\n}\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * @overview Defines an Express route for serving the UI for the export server\r\n * when enabled.\r\n */\r\n\r\nimport { join } from 'path';\r\n\r\nimport { getOptions } from '../../config.js';\r\nimport { log } from '../../logger.js';\r\nimport { __dirname } from '../../utils.js';\r\n\r\n/**\r\n * Adds the `ui` routes.\r\n *\r\n * @function uiRoutes\r\n *\r\n * @param {Express} app - The Express app instance.\r\n */\r\nexport default function uiRoutes(app) {\r\n /**\r\n * Adds the GET '/' - A route for a UI when enabled on the export server.\r\n */\r\n app.get(getOptions().ui.route || '/', (request, response, next) => {\r\n try {\r\n log(4, '[ui] Returning UI for the export.');\r\n\r\n response.sendFile(join(__dirname, 'public', 'index.html'), {\r\n acceptRanges: false\r\n });\r\n } catch (error) {\r\n return next(error);\r\n }\r\n });\r\n}\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * @overview Defines an Express route for updating the Highcharts version\r\n * on the server, with authentication and validation.\r\n */\r\n\r\nimport { updateHighchartsVersion, getHighchartsVersion } from '../../cache.js';\r\nimport { validateOption } from '../../config.js';\r\nimport { log } from '../../logger.js';\r\nimport { envs } from '../../validation.js';\r\n\r\nimport ExportError from '../../errors/ExportError.js';\r\n\r\n/**\r\n * Adds the `version_change` routes.\r\n *\r\n * @function versionChangeRoutes\r\n *\r\n * @param {Express} app - The Express app instance.\r\n */\r\nexport default function versionChangeRoutes(app) {\r\n /**\r\n * Adds the POST '/version_change/:newVersion' - A route for changing\r\n * the Highcharts version on the server.\r\n */\r\n app.post('/version_change/:newVersion', async (request, response, next) => {\r\n try {\r\n log(4, '[version] Changing Highcharts version.');\r\n\r\n // Get the token directly from envs\r\n const adminToken = envs.HIGHCHARTS_ADMIN_TOKEN;\r\n\r\n // Check the existence of the token\r\n if (!adminToken || !adminToken.length) {\r\n throw new ExportError(\r\n '[version] The server is not configured to perform run-time version changes: HIGHCHARTS_ADMIN_TOKEN is not set.',\r\n 401\r\n );\r\n }\r\n\r\n // Get the token from the hc-auth header\r\n const token = request.get('hc-auth');\r\n\r\n // Check if the hc-auth header contain a correct token\r\n if (!token || token !== adminToken) {\r\n throw new ExportError(\r\n '[version] Invalid or missing token: Set the token in the hc-auth header.',\r\n 401\r\n );\r\n }\r\n\r\n // Compare versions\r\n let newVersion = request.params.newVersion;\r\n\r\n // Validate the version\r\n try {\r\n newVersion = validateOption('version', request.params.newVersion);\r\n } catch (error) {\r\n throw new ExportError(\r\n `[version] Version is incorrect: ${error.message}`,\r\n 400\r\n ).setError(error);\r\n }\r\n\r\n // When a correct value found\r\n if (newVersion) {\r\n try {\r\n // Update version\r\n await updateHighchartsVersion(newVersion);\r\n } catch (error) {\r\n throw new ExportError(\r\n `[version] Version change: ${error.message}`,\r\n 400\r\n ).setError(error);\r\n }\r\n\r\n // Success\r\n response.status(200).send({\r\n statusCode: 200,\r\n highchartsVersion: getHighchartsVersion(),\r\n message: `Successfully updated Highcharts to version: ${newVersion}.`\r\n });\r\n } else {\r\n // No version specified\r\n throw new ExportError('[version] No new version supplied.', 400);\r\n }\r\n } catch (error) {\r\n return next(error);\r\n }\r\n });\r\n}\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * @overview A module that sets up and manages HTTP and HTTPS servers\r\n * for the Highcharts Export Server. It handles server initialization,\r\n * configuration, error handling, middleware setup, route definition, and rate\r\n * limiting. The module exports functions to start, stop, and manage server\r\n * instances, as well as utility functions for defining routes and attaching\r\n * middlewares.\r\n */\r\n\r\nimport { readFile } from 'fs/promises';\r\nimport { join } from 'path';\r\n\r\nimport cors from 'cors';\r\nimport express from 'express';\r\nimport http from 'http';\r\nimport https from 'https';\r\nimport multer from 'multer';\r\n\r\nimport { updateOptions, validateOptions } from '../config.js';\r\nimport { log, logWithStack } from '../logger.js';\r\nimport { __dirname, getAbsolutePath } from '../utils.js';\r\n\r\nimport errorMiddleware from './middlewares/error.js';\r\nimport rateLimitingMiddleware from './middlewares/rateLimiting.js';\r\nimport validationMiddleware from './middlewares/validation.js';\r\n\r\nimport exportRoutes from './routes/export.js';\r\nimport healthRoutes from './routes/health.js';\r\nimport uiRoutes from './routes/ui.js';\r\nimport versionChangeRoutes from './routes/versionChange.js';\r\n\r\nimport ExportError from '../errors/ExportError.js';\r\n\r\n// Array of an active servers\r\nconst activeServers = new Map();\r\n\r\n// Create express app\r\nconst app = express();\r\n\r\n/**\r\n * Starts an HTTP and/or HTTPS server based on the provided configuration.\r\n * The `serverOptions` object contains server-related properties (refer\r\n * to the `server` section in the `lib/schemas/config.js` file for details).\r\n *\r\n * @async\r\n * @function startServer\r\n *\r\n * @param {Object} serverOptions - The configuration object containing `server`\r\n * options. This object may include a partial or complete set of the `server`\r\n * options. If the options are partial, missing values will default\r\n * to the current global configuration.\r\n *\r\n * @returns {Promise} A Promise that resolves when the server is either\r\n * not enabled or no valid Express app is found, signaling the end of the\r\n * function's execution.\r\n *\r\n * @throws {ExportError} Throws an `ExportError` if the server cannot\r\n * be configured and started.\r\n */\r\nexport async function startServer(serverOptions) {\r\n try {\r\n // Update the instance options object\r\n const options = updateOptions(\r\n validateOptions({\r\n server: serverOptions\r\n })\r\n );\r\n\r\n // Use validated options\r\n serverOptions = options.server;\r\n\r\n // Stop if not enabled\r\n if (!serverOptions.enable || !app) {\r\n throw new ExportError(\r\n '[server] Server cannot be started (not enabled or no correct Express app found).',\r\n 500\r\n );\r\n }\r\n\r\n // Too big limits lead to timeouts in the export process when\r\n // the rasterization timeout is set too low\r\n const uploadLimitBytes = serverOptions.uploadLimit * 1024 * 1024;\r\n\r\n // Memory storage for multer package\r\n const storage = multer.memoryStorage();\r\n\r\n // Enable parsing of form data (files) with multer package\r\n const upload = multer({\r\n storage,\r\n limits: {\r\n fieldSize: uploadLimitBytes\r\n }\r\n });\r\n\r\n // Disable the X-Powered-By header\r\n app.disable('x-powered-by');\r\n\r\n // Enable CORS support\r\n app.use(\r\n cors({\r\n methods: ['POST', 'GET', 'OPTIONS']\r\n })\r\n );\r\n\r\n // Getting a lot of `RangeNotSatisfiableError` exceptions (even though this\r\n // is a deprecated options, let's try to set it to false)\r\n app.use((request, response, next) => {\r\n response.set('Accept-Ranges', 'none');\r\n next();\r\n });\r\n\r\n // Enable body parser for JSON data\r\n app.use(\r\n express.json({\r\n limit: uploadLimitBytes\r\n })\r\n );\r\n\r\n // Enable body parser for URL-encoded form data\r\n app.use(\r\n express.urlencoded({\r\n extended: true,\r\n limit: uploadLimitBytes\r\n })\r\n );\r\n\r\n // Use only non-file multipart form fields\r\n app.use(upload.none());\r\n\r\n // Set up static folder's route\r\n app.use(express.static(join(__dirname, 'public')));\r\n\r\n // Listen HTTP server\r\n if (!serverOptions.ssl.force) {\r\n // Main server instance (HTTP)\r\n const httpServer = http.createServer(app);\r\n\r\n // Attach error handlers and listen to the server\r\n _attachServerErrorHandlers(httpServer);\r\n\r\n // Listen\r\n httpServer.listen(serverOptions.port, serverOptions.host, () => {\r\n // Save the reference to HTTP server\r\n activeServers.set(serverOptions.port, httpServer);\r\n\r\n log(\r\n 3,\r\n `[server] Started HTTP server on ${serverOptions.host}:${serverOptions.port}.`\r\n );\r\n });\r\n }\r\n\r\n // Listen HTTPS server\r\n if (serverOptions.ssl.enable) {\r\n // Set up an SSL server also\r\n let key, cert;\r\n\r\n try {\r\n // Get the SSL key\r\n key = await readFile(\r\n join(getAbsolutePath(serverOptions.ssl.certPath), 'server.key'),\r\n 'utf8'\r\n );\r\n\r\n // Get the SSL certificate\r\n cert = await readFile(\r\n join(getAbsolutePath(serverOptions.ssl.certPath), 'server.crt'),\r\n 'utf8'\r\n );\r\n } catch (error) {\r\n log(\r\n 2,\r\n `[server] Unable to load key/certificate from the '${serverOptions.ssl.certPath}' path. Could not run secured layer server.`\r\n );\r\n }\r\n\r\n if (key && cert) {\r\n // Main server instance (HTTPS)\r\n const httpsServer = https.createServer({ key, cert }, app);\r\n\r\n // Attach error handlers and listen to the server\r\n _attachServerErrorHandlers(httpsServer);\r\n\r\n // Listen\r\n httpsServer.listen(serverOptions.ssl.port, serverOptions.host, () => {\r\n // Save the reference to HTTPS server\r\n activeServers.set(serverOptions.ssl.port, httpsServer);\r\n\r\n log(\r\n 3,\r\n `[server] Started HTTPS server on ${serverOptions.host}:${serverOptions.ssl.port}.`\r\n );\r\n });\r\n }\r\n }\r\n\r\n // Set up the rate limiter\r\n rateLimitingMiddleware(app, serverOptions.rateLimiting);\r\n\r\n // Set up the validation handler\r\n validationMiddleware(app);\r\n\r\n // Set up routes\r\n exportRoutes(app);\r\n healthRoutes(app);\r\n uiRoutes(app);\r\n versionChangeRoutes(app);\r\n\r\n // Set up the centralized error handler\r\n errorMiddleware(app);\r\n } catch (error) {\r\n throw new ExportError(\r\n '[server] Could not configure and start the server.',\r\n 500\r\n ).setError(error);\r\n }\r\n}\r\n\r\n/**\r\n * Closes all servers associated with Express app instance.\r\n *\r\n * @function closeServers\r\n */\r\nexport function closeServers() {\r\n // Check if there are servers working\r\n if (activeServers.size > 0) {\r\n log(4, `[server] Closing all servers.`);\r\n\r\n // Close each one of servers\r\n for (const [port, server] of activeServers) {\r\n server.close(() => {\r\n activeServers.delete(port);\r\n log(4, `[server] Closed server on port: ${port}.`);\r\n });\r\n }\r\n }\r\n}\r\n\r\n/**\r\n * Get all servers associated with Express app instance.\r\n *\r\n * @function getServers\r\n *\r\n * @returns {Array.} Servers associated with Express app instance.\r\n */\r\nexport function getServers() {\r\n return activeServers;\r\n}\r\n\r\n/**\r\n * Get the Express instance.\r\n *\r\n * @function getExpress\r\n *\r\n * @returns {Express} The Express instance.\r\n */\r\nexport function getExpress() {\r\n return express;\r\n}\r\n\r\n/**\r\n * Get the Express app instance.\r\n *\r\n * @function getApp\r\n *\r\n * @returns {Express} The Express app instance.\r\n */\r\nexport function getApp() {\r\n return app;\r\n}\r\n\r\n/**\r\n * Enable rate limiting for the server.\r\n *\r\n * @function enableRateLimiting\r\n *\r\n * @param {Object} rateLimitingOptions - The configuration object containing\r\n * `rateLimiting` options. This object may include a partial or complete set\r\n * of the `rateLimiting` options. If the options are partial, missing values\r\n * will default to the current global configuration.\r\n */\r\nexport function enableRateLimiting(rateLimitingOptions) {\r\n // Update the instance options object\r\n const options = updateOptions(\r\n validateOptions({\r\n server: {\r\n rateLimiting: rateLimitingOptions\r\n }\r\n })\r\n );\r\n\r\n // Set the rate limiting options\r\n rateLimitingMiddleware(app, options.server.rateLimitingOptions);\r\n}\r\n\r\n/**\r\n * Apply middleware(s) to a specific path.\r\n *\r\n * @function use\r\n *\r\n * @param {string} path - The path to which the middleware(s) should be applied.\r\n * @param {...Function} middlewares - The middleware function(s) to be applied.\r\n */\r\nexport function use(path, ...middlewares) {\r\n app.use(path, ...middlewares);\r\n}\r\n\r\n/**\r\n * Set up a route with GET method and apply middleware(s).\r\n *\r\n * @function get\r\n *\r\n * @param {string} path - The path to which the middleware(s) should be applied.\r\n * @param {...Function} middlewares - The middleware function(s) to be applied.\r\n */\r\nexport function get(path, ...middlewares) {\r\n app.get(path, ...middlewares);\r\n}\r\n\r\n/**\r\n * Set up a route with POST method and apply middleware(s).\r\n *\r\n * @function post\r\n *\r\n * @param {string} path - The path to which the middleware(s) should be applied.\r\n * @param {...Function} middlewares - The middleware function(s) to be applied.\r\n */\r\nexport function post(path, ...middlewares) {\r\n app.post(path, ...middlewares);\r\n}\r\n\r\n/**\r\n * Attach error handlers to the server.\r\n *\r\n * @function _attachServerErrorHandlers\r\n *\r\n * @param {(http.Server|https.Server)} server - The HTTP/HTTPS server instance.\r\n */\r\nfunction _attachServerErrorHandlers(server) {\r\n server.on('clientError', (error, socket) => {\r\n logWithStack(\r\n 1,\r\n error,\r\n `[server] Client error: ${error.message}, destroying socket.`\r\n );\r\n socket.destroy();\r\n });\r\n\r\n server.on('error', (error) => {\r\n logWithStack(1, error, `[server] Server error: ${error.message}`);\r\n });\r\n\r\n server.on('connection', (socket) => {\r\n socket.on('error', (error) => {\r\n logWithStack(1, error, `[server] Socket error: ${error.message}`);\r\n });\r\n });\r\n}\r\n\r\nexport default {\r\n startServer,\r\n closeServers,\r\n getServers,\r\n getExpress,\r\n getApp,\r\n enableRateLimiting,\r\n use,\r\n get,\r\n post\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * @overview Handles graceful shutdown of the Highcharts Export Server, ensuring\r\n * proper cleanup of resources such as browser, pages, servers, and timers.\r\n */\r\n\r\nimport { killPool } from './pool.js';\r\nimport { clearAllTimers } from './timer.js';\r\n\r\nimport { closeServers } from './server/server.js';\r\n\r\n/**\r\n * Performs cleanup operations to ensure a graceful shutdown of the process.\r\n * This includes clearing all registered timeouts/intervals, closing active\r\n * servers, terminating resources (pages) of the pool, pool itself, and closing\r\n * the browser.\r\n *\r\n * @function shutdownCleanUp\r\n *\r\n * @param {number} [exitCode=0] - The exit code to use with `process.exit()`.\r\n * The default value is `0`.\r\n */\r\nexport async function shutdownCleanUp(exitCode = 0) {\r\n // Await freeing all resources\r\n await Promise.allSettled([\r\n // Clear all ongoing intervals\r\n clearAllTimers(),\r\n\r\n // Get available server instances (HTTP/HTTPS) and close them\r\n closeServers(),\r\n\r\n // Close an active pool along with its workers and the browser instance\r\n killPool()\r\n ]);\r\n\r\n // Exit process with a correct code\r\n process.exit(exitCode);\r\n}\r\n\r\nexport default {\r\n shutdownCleanUp\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * @overview Core module for initializing and managing the Highcharts Export\r\n * Server. Provides functionalities for configuring exports, setting up server\r\n * operations, logging, scripts caching, resource pooling, and graceful process\r\n * cleanup.\r\n */\r\n\r\nimport 'colors';\r\n\r\nimport { checkAndUpdateCache } from './cache.js';\r\nimport {\r\n singleExport,\r\n batchExport,\r\n startExport,\r\n setAllowCodeExecution\r\n} from './chart.js';\r\nimport {\r\n getOptions,\r\n updateOptions,\r\n setGlobalOptions,\r\n mapToNewOptions,\r\n validateOption,\r\n validateOptions\r\n} from './config.js';\r\nimport {\r\n log,\r\n logWithStack,\r\n logZodIssues,\r\n initLogging,\r\n enableConsoleLogging,\r\n enableFileLogging,\r\n setLogLevel\r\n} from './logger.js';\r\nimport { initPool, killPool } from './pool.js';\r\nimport { shutdownCleanUp } from './resourceRelease.js';\r\n\r\nimport server from './server/server.js';\r\n\r\n/**\r\n * Initializes the export process. Tasks such as configuring logging, checking\r\n * the cache and sources, and initializing the resource pool occur during this\r\n * stage.\r\n *\r\n * This function must be called before attempting to export charts or set\r\n * up a server.\r\n *\r\n * @async\r\n * @function initExport\r\n *\r\n * @param {Object} [initOptions={}] - The `initOptions` object, which may\r\n * be a partial or complete set of options. If the options are partial, missing\r\n * values will default to the current global configuration. The default value\r\n * is an empty object.\r\n */\r\nexport async function initExport(initOptions = {}) {\r\n // Init, validate and update the instance options object\r\n const options = updateOptions(validateOptions(initOptions), true);\r\n\r\n // Set the `allowCodeExecution` per export module scope\r\n setAllowCodeExecution(options.customLogic.allowCodeExecution);\r\n\r\n // Init the logging\r\n initLogging(options.logging);\r\n\r\n // Attach process' exit listeners\r\n if (options.other.listenToProcessExits) {\r\n _attachProcessExitListeners();\r\n }\r\n\r\n // Check if cache needs to be updated\r\n await checkAndUpdateCache(options.highcharts, options.server.proxy);\r\n\r\n // Init the pool\r\n await initPool(options.pool, options.puppeteer.args);\r\n}\r\n\r\n/**\r\n * Attaches exit listeners to the process, ensuring proper cleanup of resources\r\n * and termination on exit signals. Handles 'exit', 'SIGINT', 'SIGTERM'\r\n * and 'uncaughtException' events.\r\n *\r\n * @function _attachProcessExitListeners\r\n */\r\nfunction _attachProcessExitListeners() {\r\n log(3, '[process] Attaching exit listeners to the process.');\r\n\r\n // Handler for the 'exit'\r\n process.on('exit', (code) => {\r\n log(4, `[process] Process exited with code ${code}.`);\r\n });\r\n\r\n // Handler for the 'SIGINT'\r\n process.on('SIGINT', async (name, code) => {\r\n log(4, `[process] The ${name} event with code: ${code}.`);\r\n await shutdownCleanUp();\r\n });\r\n\r\n // Handler for the 'SIGTERM'\r\n process.on('SIGTERM', async (name, code) => {\r\n log(4, `[process] The ${name} event with code: ${code}.`);\r\n await shutdownCleanUp();\r\n });\r\n\r\n // Handler for the 'SIGHUP'\r\n process.on('SIGHUP', async (name, code) => {\r\n log(4, `[process] The ${name} event with code: ${code}.`);\r\n await shutdownCleanUp();\r\n });\r\n\r\n // Handler for the 'uncaughtException'\r\n process.on('uncaughtException', async (error, name) => {\r\n logWithStack(1, error, `[process] The ${name} error.`);\r\n await shutdownCleanUp(1);\r\n });\r\n}\r\n\r\nexport default {\r\n // Server\r\n ...server,\r\n\r\n // Options\r\n getOptions,\r\n setGlobalOptions,\r\n mapToNewOptions,\r\n\r\n // Validation\r\n validateOption,\r\n validateOptions,\r\n\r\n // Exporting\r\n initExport,\r\n singleExport,\r\n batchExport,\r\n startExport,\r\n\r\n // Release\r\n killPool,\r\n shutdownCleanUp,\r\n\r\n // Logs\r\n log,\r\n logWithStack,\r\n logZodIssues,\r\n setLogLevel: function (level) {\r\n // Update the instance options object\r\n const options = updateOptions(\r\n validateOptions({\r\n logging: {\r\n level\r\n }\r\n })\r\n );\r\n\r\n // Call the function\r\n setLogLevel(options.logging.level);\r\n },\r\n enableConsoleLogging: function (toConsole) {\r\n // Update the instance options object\r\n const options = updateOptions(\r\n validateOptions({\r\n logging: {\r\n toConsole\r\n }\r\n })\r\n );\r\n\r\n // Call the function\r\n enableConsoleLogging(options.logging.toConsole);\r\n },\r\n enableFileLogging: function (dest, file, toFile) {\r\n // Update the instance options object\r\n const options = updateOptions(\r\n validateOptions({\r\n logging: {\r\n dest,\r\n file,\r\n toFile\r\n }\r\n })\r\n );\r\n\r\n // Call the function\r\n enableFileLogging(\r\n options.logging.dest,\r\n options.logging.file,\r\n options.logging.toFile\r\n );\r\n }\r\n};\r\n"],"names":["__dirname","fileURLToPath","URL","url","deepCopy","objArr","objArrCopy","Array","isArray","key","Object","prototype","hasOwnProperty","call","fixConstr","constr","fixedConstr","toLowerCase","replace","includes","fixOutfile","type","outfile","getAbsolutePath","split","shift","fixType","mimeTypes","formats","values","outType","pop","find","t","path","isAbsolute","join","getBase64","input","Buffer","from","toString","getNewDate","Date","trim","getNewDateTime","getTime","isObject","item","isObjectEmpty","keys","length","isPrivateRangeUrlFound","some","pattern","test","measureTime","start","process","hrtime","bigint","Number","roundNumber","value","precision","multiplier","Math","pow","round","wrapAround","customCode","allowFileResources","isCallback","endsWith","readFileSync","startsWith","colors","logging","toConsole","toFile","pathCreated","pathToLog","levelsDesc","title","color","log","args","newLevel","texts","level","prefix","_logToFile","console","apply","undefined","concat","logWithStack","error","customMessage","mainMessage","message","stackMessage","stack","push","logZodIssues","issues","map","issue","initLogging","loggingOptions","dest","file","setLogLevel","enableConsoleLogging","enableFileLogging","isInteger","existsSync","mkdirSync","appendFile","defaultConfig","puppeteer","types","envLink","cliName","description","promptOptions","separator","highcharts","version","cdnUrl","forceFetch","cachePath","coreScripts","instructions","moduleScripts","indicatorScripts","customScripts","export","infile","instr","options","svg","batch","hint","choices","b64","noDownload","height","width","scale","defaultHeight","defaultWidth","defaultScale","min","max","globalOptions","themeOptions","rasterizationTimeout","customLogic","allowCodeExecution","callback","resources","loadConfig","legacyName","createConfig","server","enable","host","port","uploadLimit","benchmarking","proxy","timeout","rateLimiting","maxRequests","window","delay","trustProxy","skipKey","skipToken","ssl","force","certPath","pool","minWorkers","maxWorkers","workLimit","acquireTimeout","createTimeout","destroyTimeout","idleTimeout","createRetryInterval","reaperInterval","ui","route","other","nodeEnv","listenToProcessExits","noLogo","hardResetPage","browserShellMode","validation","debug","headless","devtools","listenToConsole","dumpio","slowMo","debuggingPort","nestedProps","_createNestedProps","absoluteProps","_createAbsoluteProps","config","propChain","forEach","entry","substring","dotenv","z","setErrorMap","_customErrorMap","v","boolean","strictCheck","union","enum","transform","nullable","string","refine","params","errorMessage","stringArray","filterCallback","arraySchema","array","stringSchema","slice","transformCallback","filter","positiveNum","number","positive","isNaN","nonNegativeNum","nonnegative","prefixes","chartConfig","object","passthrough","additionalOptions","validators","adminToken","indexOf","gte","lte","this","objectSchema","js","css","files","partial","stringSchema1","stringSchema2","enableServer","serverBenchmarking","proxyHost","proxyPort","proxyTimeout","enableRateLimiting","enableSsl","sslForce","sslPort","sslCertPath","poolBenchmarking","resourcesInterval","logLevel","int","logFile","logDest","logToConsole","logToFile","enableUi","uiRoute","enableDebug","requestId","uuid","PuppeteerSchema","HighchartsSchema","ExportSchema","CustomLogicSchema","ProxySchema","RateLimitingSchema","SslSchema","ServerSchema","optional","PoolSchema","LoggingSchema","UiSchema","OtherSchema","DebugSchema","StrictConfigSchema","LooseConfigSchema","EnvSchema","PUPPETEER_ARGS","HIGHCHARTS_VERSION","HIGHCHARTS_CDN_URL","HIGHCHARTS_FORCE_FETCH","HIGHCHARTS_CACHE_PATH","HIGHCHARTS_ADMIN_TOKEN","HIGHCHARTS_CORE_SCRIPTS","HIGHCHARTS_MODULE_SCRIPTS","HIGHCHARTS_INDICATOR_SCRIPTS","HIGHCHARTS_CUSTOM_SCRIPTS","EXPORT_INFILE","EXPORT_INSTR","EXPORT_OPTIONS","EXPORT_SVG","EXPORT_BATCH","EXPORT_OUTFILE","EXPORT_TYPE","EXPORT_CONSTR","EXPORT_B64","EXPORT_NO_DOWNLOAD","EXPORT_HEIGHT","EXPORT_WIDTH","EXPORT_SCALE","EXPORT_DEFAULT_HEIGHT","EXPORT_DEFAULT_WIDTH","EXPORT_DEFAULT_SCALE","EXPORT_GLOBAL_OPTIONS","EXPORT_THEME_OPTIONS","EXPORT_RASTERIZATION_TIMEOUT","CUSTOM_LOGIC_ALLOW_CODE_EXECUTION","CUSTOM_LOGIC_ALLOW_FILE_RESOURCES","CUSTOM_LOGIC_CUSTOM_CODE","CUSTOM_LOGIC_CALLBACK","CUSTOM_LOGIC_RESOURCES","CUSTOM_LOGIC_LOAD_CONFIG","CUSTOM_LOGIC_CREATE_CONFIG","SERVER_ENABLE","SERVER_HOST","SERVER_PORT","SERVER_UPLOAD_LIMIT","SERVER_BENCHMARKING","SERVER_PROXY_HOST","SERVER_PROXY_PORT","SERVER_PROXY_TIMEOUT","SERVER_RATE_LIMITING_ENABLE","SERVER_RATE_LIMITING_MAX_REQUESTS","SERVER_RATE_LIMITING_WINDOW","SERVER_RATE_LIMITING_DELAY","SERVER_RATE_LIMITING_TRUST_PROXY","SERVER_RATE_LIMITING_SKIP_KEY","SERVER_RATE_LIMITING_SKIP_TOKEN","SERVER_SSL_ENABLE","SERVER_SSL_FORCE","SERVER_SSL_PORT","SERVER_SSL_CERT_PATH","POOL_MIN_WORKERS","POOL_MAX_WORKERS","POOL_WORK_LIMIT","POOL_ACQUIRE_TIMEOUT","POOL_CREATE_TIMEOUT","POOL_DESTROY_TIMEOUT","POOL_IDLE_TIMEOUT","POOL_CREATE_RETRY_INTERVAL","POOL_REAPER_INTERVAL","POOL_BENCHMARKING","LOGGING_LEVEL","LOGGING_FILE","LOGGING_DEST","LOGGING_TO_CONSOLE","LOGGING_TO_FILE","UI_ENABLE","UI_ROUTE","OTHER_NODE_ENV","OTHER_LISTEN_TO_PROCESS_EXITS","OTHER_NO_LOGO","OTHER_HARD_RESET_PAGE","OTHER_BROWSER_SHELL_MODE","OTHER_VALIDATION","DEBUG_ENABLE","DEBUG_HEADLESS","DEBUG_DEVTOOLS","DEBUG_LISTEN_TO_CONSOLE","DEBUG_DUMPIO","DEBUG_SLOW_MO","DEBUG_DEBUGGING_PORT","envs","parse","env","strictValidate","configOptions","looseValidate","context","propertyName","propertyInfo","code","ZodIssueCode","invalid_type","received","ZodParsedType","defaultError","custom","data","invalid_union","unionErrors","index","ExportError","Error","constructor","statusCode","super","setStatus","setError","name","_initGlobalOptions","instanceOptions","getOptions","getInstance","setGlobalOptions","customOptions","cliArgs","cliOptions","_loadConfigFile","_pairArgumentValue","_updateGlobalOptions","updateOptions","newInstance","mergeOptions","originalOptions","newOptions","entries","mapToNewOptions","oldOptions","propertiesChain","reduce","obj","prop","validateOption","configOption","validateOptions","isAllowedConfig","allowFunctions","objectConfig","eval","JSON","stringifiedOptions","_optionsStringify","parsedOptions","_","envVal","configOpt","cliOpt","customOpt","configVal","cliVal","customVal","stringifyFunctions","stringify","replaceAll","customLogicOptions","configIndex","findIndex","arg","configFileName","i","option","async","fetch","requestOptions","Promise","resolve","reject","_getProtocolModule","get","response","responseData","on","chunk","text","https","http","cache","activeManifest","sources","hcVersion","checkAndUpdateCache","highchartsOptions","serverProxyOptions","fetchedModules","getCachePath","manifestPath","sourcePath","recursive","_updateCache","requestUpdate","manifest","modules","moduleMap","m","numberOfModules","moduleName","extractVersion","_saveConfigToManifest","getHighchartsVersion","updateHighchartsVersion","newVersion","cacheSources","extractModuleName","scriptPath","_fetchAndProcessScript","script","shouldThrowError","newManifest","writeFileSync","_fetchScripts","proxyAgent","HttpsProxyAgent","agent","allFetchPromises","all","c","setupHighcharts","Highcharts","animObject","duration","createChart","exportOptions","setOptions","merge","wrap","setOptionsObj","isRenderComplete","Chart","proceed","userOptions","cb","exporting","enabled","plotOptions","series","label","tooltip","animation","onHighchartsRender","addEvent","Series","chart","Function","finalOptions","finalCallback","defaultOptions","template","browser","createBrowser","puppeteerArgs","enabledDebug","debugOptions","launchOptions","userDataDir","handleSIGINT","handleSIGTERM","handleSIGHUP","waitForInitialPage","defaultViewport","tryCount","open","launch","setTimeout","closeBrowser","connected","close","newPage","poolResource","page","setCacheEnabled","_setPageContent","_setPageEvents","isClosed","clearPage","hardReset","goto","waitUntil","evaluate","document","body","innerHTML","id","workCount","addPageResources","injectedResources","injectedJs","content","isLocal","jsResource","addScriptTag","injectedCss","cssImports","match","cssImportPath","cssResource","addStyleTag","clearPageResources","resource","dispose","oldCharts","charts","oldChart","destroy","scriptsToRemove","getElementsByTagName","stylesToRemove","linksToRemove","element","remove","setContent","cssTemplate","svgTemplate","puppeteerExport","isSVG","size","svgElement","querySelector","chartHeight","baseVal","chartWidth","style","zoom","margin","parseFloat","x","y","_getClipRegion","viewportHeight","abs","ceil","viewportWidth","result","setViewport","deviceScaleFactor","_createSVG","_createImage","_createPDF","$eval","getBoundingClientRect","trunc","outerHTML","clip","race","screenshot","encoding","fullPage","optimizeForSpeed","captureBeyondViewport","quality","omitBackground","_resolve","emulateMediaType","pdf","poolStats","exportsAttempted","exportsPerformed","exportsDropped","exportsFromSvg","exportsFromOptions","exportsFromSvgAttempts","exportsFromOptionsAttempts","timeSpent","timeSpentAverage","initPool","poolOptions","Pool","_factory","acquireTimeoutMillis","createTimeoutMillis","destroyTimeoutMillis","idleTimeoutMillis","createRetryIntervalMillis","reapIntervalMillis","propagateCreateError","clearStatus","_eventId","initialResources","acquire","promise","release","killPool","worker","used","destroyed","postWork","workerHandle","getPoolInfo","acquireCounter","workStart","exportCounter","exportTime","getPoolStats","getPoolInfoJSON","numUsed","available","numFree","allCreated","pendingAcquires","numPendingAcquires","pendingCreates","numPendingCreates","pendingValidations","numPendingValidations","pendingDestroys","absoluteAll","create","random","startDate","validate","mainFrame","detached","removeAllListeners","sanitize","JSDOM","DOMPurify","ADD_TAGS","singleExport","startExport","batchExport","batchFunctions","pair","batchResults","allSettled","reason","exportingOptions","endCallback","fileContent","_exportFromSvg","_exportFromOptions","getAllowCodeExecution","setAllowCodeExecution","inputToExport","_prepareExport","_handleCustomLogic","_handleGlobalAndTheme","_findChartSize","optionsChart","optionsExporting","globalOptionsChart","globalOptionsExporting","themeOptionsChart","themeOptionsExporting","sourceHeight","sourceWidth","param","_handleResources","allowedProps","handledResources","correctResources","propName","optionsName","timerIds","addTimer","clearAllTimers","clearInterval","clearTimeout","logErrorMiddleware","request","next","returnErrorMiddleware","status","json","errorMiddleware","app","use","rateLimitingMiddleware","rateLimitingOptions","rateOptions","limiter","rateLimit","windowMs","limit","delayMs","handler","format","send","default","skip","query","access_token","contentTypeMiddleware","contentType","headers","requestBodyMiddleware","connection","remoteAddress","validatedOptions","filename","validationMiddleware","post","reversedMime","png","jpeg","gif","requestExport","requestCounter","connectionAborted","socket","hadErrors","header","attachment","exportRoutes","serverStartTime","packageFile","successRates","recordInterval","windowSize","_calculateMovingAverage","a","b","_startSuccessRate","setInterval","stats","successRatio","healthRoutes","period","movingAverage","bootTime","uptime","floor","serverVersion","highchartsVersion","averageExportTime","attemptedExports","performedExports","failedExports","sucessRatio","toFixed","svgExports","jsonExports","svgExportsAttempts","jsonExportsAttempts","uiRoutes","sendFile","acceptRanges","versionChangeRoutes","token","activeServers","Map","express","startServer","serverOptions","uploadLimitBytes","storage","multer","memoryStorage","upload","limits","fieldSize","disable","cors","methods","set","urlencoded","extended","none","static","httpServer","createServer","_attachServerErrorHandlers","listen","cert","readFile","httpsServer","closeServers","delete","getServers","getExpress","getApp","middlewares","shutdownCleanUp","exitCode","exit","initExport","initOptions","_attachProcessExitListeners"],"mappings":"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ACA,QACA,OACA,aACA,mBACA,eACA,cACA,UACA,UACA,cACA,WACA,UACA,YACA,cACA,YACA,sBACA,SACA,SACA,WACA,aACA,YACA,eACA,yBACA,SACA,eACA,YACA,kBACA,SACA,cACA,mBACA,eACA,kBACA,cACA,eAEA,cACA,WACA,eACA,WACA,SACA,OACA,WACA,YACA,SACA,qBACA,aACA,WACA,WACA,WACA,WACA,eACA,UACA,kBACA,oBACA,aACA,UACA,cACA,YACA,YAEF0D,MAAO,CAAC,YACRC,QAAS,4BACTE,YAAa,qCACbC,cAAe,CACbxG,KAAM,cACNgH,aAAc,0DAGlBE,iBAAkB,CAChBxE,MAAO,CAAC,kBACR0D,MAAO,CAAC,YACRC,QAAS,+BACTE,YAAa,wCACbC,cAAe,CACbxG,KAAM,cACNgH,aAAc,0DAGlBG,cAAe,CACbzE,MAAO,CACL,wEACA,kGAEF0D,MAAO,CAAC,YACRC,QAAS,4BACTE,YAAa,qDACbC,cAAe,CACbxG,KAAM,OACNyG,UAAW,OAIjBW,OAAQ,CACNC,OAAQ,CACN3E,MAAO,KACP0D,MAAO,CAAC,SAAU,QAClBC,QAAS,gBACTE,YACE,+DACFC,cAAe,CACbxG,KAAM,SAGVsH,MAAO,CACL5E,MAAO,KACP0D,MAAO,CAAC,SAAU,SAAU,QAC5BC,QAAS,eACTE,YACE,mEACFC,cAAe,CACbxG,KAAM,SAGVuH,QAAS,CACP7E,MAAO,KACP0D,MAAO,CAAC,SAAU,SAAU,QAC5BC,QAAS,iBACTE,YAAa,+BACbC,cAAe,CACbxG,KAAM,SAGVwH,IAAK,CACH9E,MAAO,KACP0D,MAAO,CAAC,SAAU,QAClBC,QAAS,aACTE,YAAa,mDACbC,cAAe,CACbxG,KAAM,SAGVyH,MAAO,CACL/E,MAAO,KACP0D,MAAO,CAAC,SAAU,QAClBC,QAAS,eACTE,YACE,gEACFC,cAAe,CACbxG,KAAM,SAGVC,QAAS,CACPyC,MAAO,KACP0D,MAAO,CAAC,SAAU,QAClBC,QAAS,iBACTE,YACE,qFACFC,cAAe,CACbxG,KAAM,SAGVA,KAAM,CACJ0C,MAAO,MACP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"} \ No newline at end of file +{"version":3,"file":"index.esm.js","sources":["../lib/utils.js","../lib/logger.js","../lib/schemas/config.js","../lib/validation.js","../lib/errors/ExportError.js","../lib/config.js","../lib/fetch.js","../lib/cache.js","../lib/highcharts.js","../lib/browser.js","../templates/svgExport/css.js","../templates/svgExport/svgExport.js","../lib/export.js","../lib/pool.js","../lib/sanitize.js","../lib/chart.js","../lib/timer.js","../lib/server/middlewares/error.js","../lib/server/middlewares/rateLimiting.js","../lib/server/middlewares/validation.js","../lib/server/routes/export.js","../lib/server/routes/health.js","../lib/server/routes/ui.js","../lib/server/routes/versionChange.js","../lib/server/server.js","../lib/resourceRelease.js","../lib/index.js"],"sourcesContent":["/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * @overview The Highcharts Export Server utility module provides\r\n * a comprehensive set of helper functions and constants designed to streamline\r\n * and enhance various operations required for Highcharts export tasks.\r\n */\r\n\r\nimport { readFileSync } from 'fs';\r\nimport { isAbsolute, join } from 'path';\r\nimport { fileURLToPath } from 'url';\r\n\r\nconst MAX_BACKOFF_ATTEMPTS = 6;\r\n\r\n// The directory path\r\nexport const __dirname = fileURLToPath(new URL('../.', import.meta.url));\r\n\r\n/**\r\n * Clears and standardizes text by replacing multiple consecutive whitespace\r\n * characters with a single space and trimming any leading or trailing\r\n * whitespace.\r\n *\r\n * @function clearText\r\n *\r\n * @param {string} text - The input text to be cleared.\r\n * @param {RegExp} [rule=/\\s\\s+/g] - The regular expression rule to match\r\n * multiple consecutive whitespace characters. The default value\r\n * is the '/\\s\\s+/g' RegExp.\r\n * @param {string} [replacer=' '] - The string used to replace multiple\r\n * consecutive whitespace characters. The default value is the ' ' string.\r\n *\r\n * @returns {string} The cleared and standardized text.\r\n */\r\nexport function clearText(text, rule = /\\s\\s+/g, replacer = ' ') {\r\n return text.replaceAll(rule, replacer).trim();\r\n}\r\n\r\n/**\r\n * Creates a deep copy of the given object or array.\r\n *\r\n * @function deepCopy\r\n *\r\n * @param {(Object|Array)} objArr - The object or array to be deeply copied.\r\n *\r\n * @returns {(Object|Array)} The deep copy of the provided object or array.\r\n */\r\nexport function deepCopy(objArr) {\r\n // If the `objArr` is null or not of the `object` type, return it\r\n if (objArr === null || typeof objArr !== 'object') {\r\n return objArr;\r\n }\r\n\r\n // Prepare either a new array or a new object\r\n const objArrCopy = Array.isArray(objArr) ? [] : {};\r\n\r\n // Recursively copy each property\r\n for (const key in objArr) {\r\n if (Object.prototype.hasOwnProperty.call(objArr, key)) {\r\n objArrCopy[key] = deepCopy(objArr[key]);\r\n }\r\n }\r\n\r\n // Return the copied object\r\n return objArrCopy;\r\n}\r\n\r\n/**\r\n * Implements an exponential backoff strategy for retrying a function until\r\n * a certain number of attempts are reached.\r\n *\r\n * @async\r\n * @function expBackoff\r\n *\r\n * @param {Function} fn - The function to be retried.\r\n * @param {number} [attempt=0] - The current attempt number. The default value\r\n * is `0`.\r\n * @param {...unknown} args - Arguments to be passed to the function.\r\n *\r\n * @returns {Promise} A Promise that resolves to the result\r\n * of the function if successful.\r\n *\r\n * @throws {Error} Throws an `Error` if the maximum number of attempts\r\n * is reached.\r\n */\r\nexport async function expBackoff(fn, attempt = 0, ...args) {\r\n try {\r\n // Try to call the function\r\n return await fn(...args);\r\n } catch (error) {\r\n // Calculate delay in ms\r\n const delayInMs = 2 ** attempt * 1000;\r\n\r\n // If the attempt exceeds the maximum attempts of repeat, throw an error\r\n if (++attempt >= MAX_BACKOFF_ATTEMPTS) {\r\n throw error;\r\n }\r\n\r\n // Wait given amount of time\r\n await new Promise((response) => setTimeout(response, delayInMs));\r\n\r\n /// TO DO: Correct\r\n // // Information about the resource timeout\r\n // log(\r\n // 3,\r\n // `[utils] Waited ${delayInMs}ms until next call for the resource of ID: ${args[0]}.`\r\n // );\r\n\r\n // Try again\r\n return expBackoff(fn, attempt, ...args);\r\n }\r\n}\r\n\r\n/**\r\n * Adjusts the constructor name by transforming and normalizing it based\r\n * on common chart types.\r\n *\r\n * @function fixConstr\r\n *\r\n * @param {string} constr - The original constructor name to be fixed.\r\n *\r\n * @returns {string} The corrected constructor name, or 'chart' if the input\r\n * is not recognized.\r\n */\r\nexport function fixConstr(constr) {\r\n try {\r\n // Fix the constructor by lowering casing\r\n const fixedConstr = `${constr.toLowerCase().replace('chart', '')}Chart`;\r\n\r\n // Handle the case where the result is just 'Chart'\r\n if (fixedConstr === 'Chart') {\r\n fixedConstr.toLowerCase();\r\n }\r\n\r\n // Return the corrected constructor, otherwise default to 'chart'\r\n return ['chart', 'stockChart', 'mapChart', 'ganttChart'].includes(\r\n fixedConstr\r\n )\r\n ? fixedConstr\r\n : 'chart';\r\n } catch {\r\n // Default to 'chart' in case of any error\r\n return 'chart';\r\n }\r\n}\r\n\r\n/**\r\n * Fixes the outfile based on provided type.\r\n *\r\n * @function fixOutfile\r\n *\r\n * @param {string} type - The original export type.\r\n * @param {string} outfile - The file path or name.\r\n *\r\n * @returns {string} The corrected outfile.\r\n */\r\nexport function fixOutfile(type, outfile) {\r\n // Get the file name from the `outfile` option\r\n const fileName = getAbsolutePath(outfile || 'chart')\r\n .split('.')\r\n .shift();\r\n\r\n // Return a correct outfile\r\n return `${fileName}.${type}`;\r\n}\r\n\r\n/**\r\n * Fixes the export type based on MIME types and file extensions.\r\n *\r\n * @function fixType\r\n *\r\n * @param {string} type - The original export type.\r\n * @param {string} [outfile=null] - The file path or name. The default value\r\n * is `null`.\r\n *\r\n * @returns {string} The corrected export type.\r\n */\r\nexport function fixType(type, outfile = null) {\r\n // MIME types\r\n const mimeTypes = {\r\n 'image/png': 'png',\r\n 'image/jpeg': 'jpeg',\r\n 'application/pdf': 'pdf',\r\n 'image/svg+xml': 'svg'\r\n };\r\n\r\n // Get formats\r\n const formats = Object.values(mimeTypes);\r\n\r\n // Check if type and outfile's extensions are the same\r\n if (outfile) {\r\n const outType = outfile.split('.').pop();\r\n\r\n // Support the JPG type\r\n if (outType === 'jpg') {\r\n type = 'jpeg';\r\n } else if (formats.includes(outType) && type !== outType) {\r\n type = outType;\r\n }\r\n }\r\n\r\n // Return a correct type\r\n return mimeTypes[type] || formats.find((t) => t === type) || 'png';\r\n}\r\n\r\n/**\r\n * Checks if the given path is relative or absolute and returns the corrected,\r\n * absolute path.\r\n *\r\n * @function isAbsolutePath\r\n *\r\n * @param {string} path - The path to be checked on.\r\n *\r\n * @returns {string} The absolute path.\r\n */\r\nexport function getAbsolutePath(path) {\r\n return isAbsolute(path) ? path : join(__dirname, path);\r\n}\r\n\r\n/**\r\n * Converts input data to a Base64 string based on the export type.\r\n *\r\n * @function getBase64\r\n *\r\n * @param {string} input - The input to be transformed to Base64 format.\r\n * @param {string} type - The original export type.\r\n *\r\n * @returns {string} The Base64 string representation of the input.\r\n */\r\nexport function getBase64(input, type) {\r\n // For pdf and svg types the input must be transformed to Base64 from a buffer\r\n if (type === 'pdf' || type == 'svg') {\r\n return Buffer.from(input, 'utf8').toString('base64');\r\n }\r\n\r\n // For png and jpeg input is already a Base64 string\r\n return input;\r\n}\r\n\r\n/**\r\n * Returns stringified date without the GMT text information.\r\n *\r\n * @function getNewDate\r\n */\r\nexport function getNewDate() {\r\n // Get rid of the GMT text information\r\n return new Date().toString().split('(')[0].trim();\r\n}\r\n\r\n/**\r\n * Returns the stored time value in milliseconds.\r\n *\r\n * @function getNewDateTime\r\n */\r\nexport function getNewDateTime() {\r\n return new Date().getTime();\r\n}\r\n\r\n/**\r\n * Checks if the given item is an object.\r\n *\r\n * @function isObject\r\n *\r\n * @param {unknown} item - The item to be checked.\r\n *\r\n * @returns {boolean} True if the item is an object, false otherwise.\r\n */\r\nexport function isObject(item) {\r\n return Object.prototype.toString.call(item) === '[object Object]';\r\n}\r\n\r\n/**\r\n * Checks if the given object is empty.\r\n *\r\n * @function isObjectEmpty\r\n *\r\n * @param {Object} item - The object to be checked.\r\n *\r\n * @returns {boolean} True if the object is empty, false otherwise.\r\n */\r\nexport function isObjectEmpty(item) {\r\n return (\r\n typeof item === 'object' &&\r\n !Array.isArray(item) &&\r\n item !== null &&\r\n Object.keys(item).length === 0\r\n );\r\n}\r\n\r\n/**\r\n * Checks if a private IP range URL is found in the given string.\r\n *\r\n * @function isPrivateRangeUrlFound\r\n *\r\n * @param {string} item - The string to be checked for a private IP range URL.\r\n *\r\n * @returns {boolean} True if a private IP range URL is found, false otherwise.\r\n */\r\nexport function isPrivateRangeUrlFound(item) {\r\n const regexPatterns = [\r\n /xlink:href=\"(?:http:\\/\\/|https:\\/\\/)?localhost\\b/,\r\n /xlink:href=\"(?:http:\\/\\/|https:\\/\\/)?10\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\b/,\r\n /xlink:href=\"(?:http:\\/\\/|https:\\/\\/)?127\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\b/,\r\n /xlink:href=\"(?:http:\\/\\/|https:\\/\\/)?172\\.(1[6-9]|2[0-9]|3[0-1])\\.\\d{1,3}\\.\\d{1,3}\\b/,\r\n /xlink:href=\"(?:http:\\/\\/|https:\\/\\/)?192\\.168\\.\\d{1,3}\\.\\d{1,3}\\b/\r\n ];\r\n\r\n return regexPatterns.some((pattern) => pattern.test(item));\r\n}\r\n\r\n/**\r\n * Utility to measure elapsed time using the Node.js `process.hrtime()` method.\r\n *\r\n * @function measureTime\r\n *\r\n * @returns {Function} A function to calculate the elapsed time in milliseconds.\r\n */\r\nexport function measureTime() {\r\n const start = process.hrtime.bigint();\r\n return () => Number(process.hrtime.bigint() - start) / 1000000;\r\n}\r\n\r\n/**\r\n * Rounds a number to the specified precision.\r\n *\r\n * @function roundNumber\r\n *\r\n * @param {number} value - The number to be rounded.\r\n * @param {number} precision - The number of decimal places to round to.\r\n *\r\n * @returns {number} The rounded number.\r\n */\r\nexport function roundNumber(value, precision = 1) {\r\n const multiplier = Math.pow(10, precision || 0);\r\n return Math.round(+value * multiplier) / multiplier;\r\n}\r\n\r\n/**\r\n * Converts a value to a boolean.\r\n *\r\n * @function toBoolean\r\n *\r\n * @param {unknown} item - The value to be converted to a boolean.\r\n *\r\n * @returns {boolean} The boolean representation of the input value.\r\n */\r\nexport function toBoolean(item) {\r\n return ['false', 'undefined', 'null', 'NaN', '0', ''].includes(item)\r\n ? false\r\n : !!item;\r\n}\r\n\r\n/**\r\n * Wraps custom code to execute it safely.\r\n *\r\n * @function wrapAround\r\n *\r\n * @param {string} customCode - The custom code to be wrapped.\r\n * @param {boolean} allowFileResources - Flag to allow loading code from a file.\r\n * @param {boolean} [isCallback=false] - Flag that indicates the returned code\r\n * must be in a callback format.\r\n *\r\n * @returns {(string|null)} The wrapped custom code or null if wrapping fails.\r\n */\r\nexport function wrapAround(customCode, allowFileResources, isCallback = false) {\r\n if (customCode && typeof customCode === 'string') {\r\n customCode = customCode.trim();\r\n\r\n if (customCode.endsWith('.js')) {\r\n // Load a file if the file resources are allowed\r\n return allowFileResources\r\n ? wrapAround(\r\n readFileSync(getAbsolutePath(customCode), 'utf8'),\r\n allowFileResources,\r\n isCallback\r\n )\r\n : null;\r\n } else if (\r\n !isCallback &&\r\n (customCode.startsWith('function()') ||\r\n customCode.startsWith('function ()') ||\r\n customCode.startsWith('()=>') ||\r\n customCode.startsWith('() =>'))\r\n ) {\r\n // Treat a function as a self-invoking expression\r\n return `(${customCode})()`;\r\n }\r\n\r\n // Or return as a stringified code\r\n return customCode.replace(/;$/, '');\r\n }\r\n}\r\n\r\nexport default {\r\n __dirname,\r\n clearText,\r\n deepCopy,\r\n expBackoff,\r\n fixConstr,\r\n fixOutfile,\r\n fixType,\r\n getAbsolutePath,\r\n getBase64,\r\n getNewDate,\r\n getNewDateTime,\r\n isObject,\r\n isObjectEmpty,\r\n isPrivateRangeUrlFound,\r\n measureTime,\r\n roundNumber,\r\n toBoolean,\r\n wrapAround\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * @overview A module for managing logging functionality with customizable\r\n * log levels, console and file logging options, and error handling support.\r\n * The module also ensures that file-based logs are stored in a structured\r\n * directory, creating the necessary paths automatically if they do not exist.\r\n */\r\n\r\nimport { appendFile, existsSync, mkdirSync } from 'fs';\r\nimport { join } from 'path';\r\n\r\nimport { getAbsolutePath, getNewDate } from './utils.js';\r\n\r\n// The available colors\r\nconst colors = ['red', 'yellow', 'blue', 'gray', 'green'];\r\n\r\n// The default logging config\r\nconst logging = {\r\n // Flags for logging status\r\n toConsole: true,\r\n toFile: false,\r\n pathCreated: false,\r\n // Full path to the log file\r\n pathToLog: '',\r\n // Log levels\r\n levelsDesc: [\r\n {\r\n title: 'error',\r\n color: colors[0]\r\n },\r\n {\r\n title: 'warning',\r\n color: colors[1]\r\n },\r\n {\r\n title: 'notice',\r\n color: colors[2]\r\n },\r\n {\r\n title: 'verbose',\r\n color: colors[3]\r\n },\r\n {\r\n title: 'benchmark',\r\n color: colors[4]\r\n }\r\n ]\r\n};\r\n\r\n/**\r\n * Logs a message with a specified log level. Accepts a variable number\r\n * of arguments. The arguments after the `level` are passed to `console.log`\r\n * and/or used to construct and append messages to a log file.\r\n *\r\n * @function log\r\n *\r\n * @param {...unknown} args - An array of arguments where the first is the log\r\n * level and the remaining are strings used to build the log message.\r\n *\r\n * @returns {void} Exits the function execution if attempting to log at a level\r\n * higher than allowed.\r\n */\r\nexport function log(...args) {\r\n const [newLevel, ...texts] = args;\r\n\r\n // Current logging options\r\n const { levelsDesc, level } = logging;\r\n\r\n // Check if the log level is within a correct range or is it a benchmark log\r\n if (\r\n newLevel !== 5 &&\r\n (newLevel === 0 || newLevel > level || level > levelsDesc.length)\r\n ) {\r\n return;\r\n }\r\n\r\n // Create a message's prefix\r\n const prefix = `${getNewDate()} [${levelsDesc[newLevel - 1].title}] -`;\r\n\r\n // Log to file\r\n if (logging.toFile) {\r\n _logToFile(texts, prefix);\r\n }\r\n\r\n // Log to console\r\n if (logging.toConsole) {\r\n console.log.apply(\r\n undefined,\r\n [prefix.toString()[logging.levelsDesc[newLevel - 1].color]].concat(texts)\r\n );\r\n }\r\n}\r\n\r\n/**\r\n * Logs an error message along with its stack trace. Optionally, a custom message\r\n * can be provided.\r\n *\r\n * @function logWithStack\r\n *\r\n * @param {number} newLevel - The log level.\r\n * @param {Error} error - The error object containing the stack trace.\r\n * @param {string} customMessage - An optional custom message to be included\r\n * in the log alongside the error.\r\n *\r\n * @returns {void} Exits the function execution if attempting to log at a level\r\n * higher than allowed.\r\n */\r\nexport function logWithStack(newLevel, error, customMessage) {\r\n // Get the main message\r\n const mainMessage = customMessage || (error && error.message) || '';\r\n\r\n // Current logging options\r\n const { level, levelsDesc } = logging;\r\n\r\n // Check if the log level is within a correct range\r\n if (newLevel === 0 || newLevel > level || level > levelsDesc.length) {\r\n return;\r\n }\r\n\r\n // Create a message's prefix\r\n const prefix = `${getNewDate()} [${levelsDesc[newLevel - 1].title}] -`;\r\n\r\n // Add the whole stack message\r\n const stackMessage = error && error.stack;\r\n\r\n // Combine custom message or error message with error stack message, if exists\r\n const texts = [mainMessage];\r\n if (stackMessage) {\r\n texts.push('\\n', stackMessage);\r\n }\r\n\r\n // Log to file\r\n if (logging.toFile) {\r\n _logToFile(texts, prefix);\r\n }\r\n\r\n // Log to console\r\n if (logging.toConsole) {\r\n console.log.apply(\r\n undefined,\r\n [prefix.toString()[logging.levelsDesc[newLevel - 1].color]].concat([\r\n texts.shift()[colors[newLevel - 1]],\r\n ...texts\r\n ])\r\n );\r\n }\r\n}\r\n\r\n/**\r\n * Logs an error message related to Zod validation issues. Optionally, a custom\r\n * message can be provided.\r\n *\r\n * @function logZodIssues\r\n *\r\n * @param {number} newLevel - The log level.\r\n * @param {Error[]} issues - An array of Zod validation issues.\r\n * @param {string} customMessage - An optional custom message to be included\r\n * in the log alongside the error.\r\n */\r\nexport function logZodIssues(newLevel, issues, customMessage) {\r\n logWithStack(\r\n newLevel,\r\n null,\r\n [\r\n `${customMessage || '[validation] Validation error'} - the following Zod issues occured:`,\r\n ...(issues || []).map((issue) => `- ${issue.message}`)\r\n ].join('\\n')\r\n );\r\n}\r\n\r\n/**\r\n * Initializes logging with the specified logging configuration.\r\n *\r\n * @function initLogging\r\n *\r\n * @param {Object} loggingOptions - The configuration object containing\r\n * `logging` options.\r\n */\r\nexport function initLogging(loggingOptions) {\r\n // Get options from the `loggingOptions` object\r\n const { level, dest, file, toConsole, toFile } = loggingOptions;\r\n\r\n // Reset flags to the default values\r\n logging.pathCreated = false;\r\n logging.pathToLog = '';\r\n\r\n // Set the logging level\r\n setLogLevel(level);\r\n\r\n // Set the console logging\r\n enableConsoleLogging(toConsole);\r\n\r\n // Set the file logging\r\n enableFileLogging(dest, file, toFile);\r\n}\r\n\r\n/**\r\n * Sets the log level to the specified value. Log levels are (`0` = no logging,\r\n * `1` = error, `2` = warning, `3` = notice, `4` = verbose, or `5` = benchmark).\r\n *\r\n * @function setLogLevel\r\n *\r\n * @param {number} level - The log level to be set.\r\n */\r\nexport function setLogLevel(level) {\r\n if (\r\n Number.isInteger(level) &&\r\n level >= 0 &&\r\n level <= logging.levelsDesc.length\r\n ) {\r\n // Update the module logging's `level` option\r\n logging.level = level;\r\n }\r\n}\r\n\r\n/**\r\n * Enables console logging.\r\n *\r\n * @function enableConsoleLogging\r\n *\r\n * @param {boolean} toConsole - The flag for setting the logging to the console.\r\n */\r\nexport function enableConsoleLogging(toConsole) {\r\n // Update the module logging's `toConsole` option\r\n logging.toConsole = !!toConsole;\r\n}\r\n\r\n/**\r\n * Enables file logging with the specified destination and log file name.\r\n *\r\n * @function enableFileLogging\r\n *\r\n * @param {string} dest - The destination path where the log file should\r\n * be saved.\r\n * @param {string} file - The name of the log file.\r\n * @param {boolean} toFile - A flag indicating whether logging should\r\n * be directed to a file.\r\n */\r\nexport function enableFileLogging(dest, file, toFile) {\r\n // Update the module logging's `toFile` option\r\n logging.toFile = !!toFile;\r\n\r\n // Set the `dest` and `file` options only if the file logging is enabled\r\n if (logging.toFile) {\r\n logging.dest = dest || '';\r\n logging.file = file || '';\r\n }\r\n}\r\n\r\n/**\r\n * Logs the provided texts to a file, if file logging is enabled. It creates\r\n * the necessary directory structure if not already created and appends\r\n * the content, including an optional prefix, to the specified log file.\r\n *\r\n * @function _logToFile\r\n *\r\n * @param {Array.} texts - An array of texts to be logged.\r\n * @param {string} prefix - An optional prefix to be added to each log entry.\r\n */\r\nfunction _logToFile(texts, prefix) {\r\n if (!logging.pathCreated) {\r\n // Create if does not exist\r\n !existsSync(getAbsolutePath(logging.dest)) &&\r\n mkdirSync(getAbsolutePath(logging.dest));\r\n\r\n // Create the full path\r\n logging.pathToLog = getAbsolutePath(join(logging.dest, logging.file));\r\n\r\n // We now assume the path is available, e.g. it's the responsibility\r\n // of the user to create the path with the correct access rights.\r\n logging.pathCreated = true;\r\n }\r\n\r\n // Add the content to a file\r\n appendFile(\r\n logging.pathToLog,\r\n [prefix].concat(texts).join(' ') + '\\n',\r\n (error) => {\r\n if (error && logging.toFile && logging.pathCreated) {\r\n logging.toFile = false;\r\n logging.pathCreated = false;\r\n logWithStack(2, error, `[logger] Unable to write to log file.`);\r\n }\r\n }\r\n );\r\n}\r\n\r\nexport default {\r\n log,\r\n logWithStack,\r\n logZodIssues,\r\n initLogging,\r\n setLogLevel,\r\n enableConsoleLogging,\r\n enableFileLogging\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * @overview Configuration management module for the Highcharts Export Server.\r\n * Provides default configurations that support environment variables, CLI\r\n * arguments, and interactive prompts for customization of options and features.\r\n * Additionally, it maps legacy options to modern structures, generates nested\r\n * argument mappings, and displays CLI usage information.\r\n */\r\n\r\n/**\r\n * The configuration object containing all available options, organized\r\n * by sections.\r\n *\r\n * This object includes:\r\n * - Default values for each option\r\n * - Data types for validation\r\n * - Names of corresponding environment variables\r\n * - Descriptions of each property\r\n * - Information used for prompts in interactive configuration\r\n * - [Optional] Corresponding CLI argument names for CLI usage\r\n * - [Optional] Legacy names from the previous PhantomJS-based server\r\n */\r\nexport const defaultConfig = {\r\n puppeteer: {\r\n args: {\r\n value: [\r\n '--allow-running-insecure-content',\r\n '--ash-no-nudges',\r\n '--autoplay-policy=user-gesture-required',\r\n '--block-new-web-contents',\r\n '--disable-accelerated-2d-canvas',\r\n '--disable-background-networking',\r\n '--disable-background-timer-throttling',\r\n '--disable-backgrounding-occluded-windows',\r\n '--disable-breakpad',\r\n '--disable-checker-imaging',\r\n '--disable-client-side-phishing-detection',\r\n '--disable-component-extensions-with-background-pages',\r\n '--disable-component-update',\r\n '--disable-default-apps',\r\n '--disable-dev-shm-usage',\r\n '--disable-domain-reliability',\r\n '--disable-extensions',\r\n '--disable-features=CalculateNativeWinOcclusion,InterestFeedContentSuggestions,WebOTP',\r\n '--disable-hang-monitor',\r\n '--disable-ipc-flooding-protection',\r\n '--disable-logging',\r\n '--disable-notifications',\r\n '--disable-offer-store-unmasked-wallet-cards',\r\n '--disable-popup-blocking',\r\n '--disable-print-preview',\r\n '--disable-prompt-on-repost',\r\n '--disable-renderer-backgrounding',\r\n '--disable-search-engine-choice-screen',\r\n '--disable-session-crashed-bubble',\r\n '--disable-setuid-sandbox',\r\n '--disable-site-isolation-trials',\r\n '--disable-speech-api',\r\n '--disable-sync',\r\n '--enable-unsafe-webgpu',\r\n '--hide-crash-restore-bubble',\r\n '--hide-scrollbars',\r\n '--metrics-recording-only',\r\n '--mute-audio',\r\n '--no-default-browser-check',\r\n '--no-first-run',\r\n '--no-pings',\r\n '--no-sandbox',\r\n '--no-startup-window',\r\n '--no-zygote',\r\n '--password-store=basic',\r\n '--process-per-tab',\r\n '--use-mock-keychain'\r\n ],\r\n types: ['string[]'],\r\n envLink: 'PUPPETEER_ARGS',\r\n cliName: 'puppeteerArgs',\r\n description: 'Array of Puppeteer arguments',\r\n promptOptions: {\r\n type: 'list',\r\n separator: ';'\r\n }\r\n }\r\n },\r\n highcharts: {\r\n version: {\r\n value: 'latest',\r\n types: ['string'],\r\n envLink: 'HIGHCHARTS_VERSION',\r\n description: 'Highcharts version',\r\n promptOptions: {\r\n type: 'text'\r\n }\r\n },\r\n cdnUrl: {\r\n value: 'https://code.highcharts.com',\r\n types: ['string'],\r\n envLink: 'HIGHCHARTS_CDN_URL',\r\n description: 'CDN URL for Highcharts scripts',\r\n promptOptions: {\r\n type: 'text'\r\n }\r\n },\r\n forceFetch: {\r\n value: false,\r\n types: ['boolean'],\r\n envLink: 'HIGHCHARTS_FORCE_FETCH',\r\n description: 'Flag to refetch scripts after each server rerun',\r\n promptOptions: {\r\n type: 'toggle'\r\n }\r\n },\r\n cachePath: {\r\n value: '.cache',\r\n types: ['string'],\r\n envLink: 'HIGHCHARTS_CACHE_PATH',\r\n description: 'Directory path for cached Highcharts scripts',\r\n promptOptions: {\r\n type: 'text'\r\n }\r\n },\r\n coreScripts: {\r\n value: ['highcharts', 'highcharts-more', 'highcharts-3d'],\r\n types: ['string[]'],\r\n envLink: 'HIGHCHARTS_CORE_SCRIPTS',\r\n description: 'Highcharts core scripts to fetch',\r\n promptOptions: {\r\n type: 'multiselect',\r\n instructions: 'Space: Select specific, A: Select all, Enter: Confirm'\r\n }\r\n },\r\n moduleScripts: {\r\n value: [\r\n 'stock',\r\n 'map',\r\n 'gantt',\r\n 'exporting',\r\n 'parallel-coordinates',\r\n 'accessibility',\r\n // 'annotations-advanced',\r\n 'boost-canvas',\r\n 'boost',\r\n 'data',\r\n 'data-tools',\r\n 'draggable-points',\r\n 'static-scale',\r\n 'broken-axis',\r\n 'heatmap',\r\n 'tilemap',\r\n 'tiledwebmap',\r\n 'timeline',\r\n 'treemap',\r\n 'treegraph',\r\n 'item-series',\r\n 'drilldown',\r\n 'histogram-bellcurve',\r\n 'bullet',\r\n 'funnel',\r\n 'funnel3d',\r\n 'geoheatmap',\r\n 'pyramid3d',\r\n 'networkgraph',\r\n 'overlapping-datalabels',\r\n 'pareto',\r\n 'pattern-fill',\r\n 'pictorial',\r\n 'price-indicator',\r\n 'sankey',\r\n 'arc-diagram',\r\n 'dependency-wheel',\r\n 'series-label',\r\n 'series-on-point',\r\n 'solid-gauge',\r\n 'sonification',\r\n // 'stock-tools',\r\n 'streamgraph',\r\n 'sunburst',\r\n 'variable-pie',\r\n 'variwide',\r\n 'vector',\r\n 'venn',\r\n 'windbarb',\r\n 'wordcloud',\r\n 'xrange',\r\n 'no-data-to-display',\r\n 'drag-panes',\r\n 'debugger',\r\n 'dumbbell',\r\n 'lollipop',\r\n 'cylinder',\r\n 'organization',\r\n 'dotplot',\r\n 'marker-clusters',\r\n 'hollowcandlestick',\r\n 'heikinashi',\r\n 'flowmap',\r\n 'export-data',\r\n 'navigator',\r\n 'textpath'\r\n ],\r\n types: ['string[]'],\r\n envLink: 'HIGHCHARTS_MODULE_SCRIPTS',\r\n description: 'Highcharts module scripts to fetch',\r\n promptOptions: {\r\n type: 'multiselect',\r\n instructions: 'Space: Select specific, A: Select all, Enter: Confirm'\r\n }\r\n },\r\n indicatorScripts: {\r\n value: ['indicators-all'],\r\n types: ['string[]'],\r\n envLink: 'HIGHCHARTS_INDICATOR_SCRIPTS',\r\n description: 'Highcharts indicator scripts to fetch',\r\n promptOptions: {\r\n type: 'multiselect',\r\n instructions: 'Space: Select specific, A: Select all, Enter: Confirm'\r\n }\r\n },\r\n customScripts: {\r\n value: [\r\n 'https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.30.1/moment.min.js',\r\n 'https://cdnjs.cloudflare.com/ajax/libs/moment-timezone/0.5.45/moment-timezone-with-data.min.js'\r\n ],\r\n types: ['string[]'],\r\n envLink: 'HIGHCHARTS_CUSTOM_SCRIPTS',\r\n description: 'Additional custom scripts or dependencies to fetch',\r\n promptOptions: {\r\n type: 'list',\r\n separator: ';'\r\n }\r\n }\r\n },\r\n export: {\r\n infile: {\r\n value: null,\r\n types: ['string', 'null'],\r\n envLink: 'EXPORT_INFILE',\r\n description:\r\n 'Input filename with type, formatted correctly as JSON or SVG',\r\n promptOptions: {\r\n type: 'text'\r\n }\r\n },\r\n instr: {\r\n value: null,\r\n types: ['Object', 'string', 'null'],\r\n envLink: 'EXPORT_INSTR',\r\n description:\r\n 'Overrides the `infile` with JSON, stringified JSON, or SVG input',\r\n promptOptions: {\r\n type: 'text'\r\n }\r\n },\r\n options: {\r\n value: null,\r\n types: ['Object', 'string', 'null'],\r\n envLink: 'EXPORT_OPTIONS',\r\n description: 'Alias for the `instr` option',\r\n promptOptions: {\r\n type: 'text'\r\n }\r\n },\r\n svg: {\r\n value: null,\r\n types: ['string', 'null'],\r\n envLink: 'EXPORT_SVG',\r\n description: 'SVG string representation of the chart to render',\r\n promptOptions: {\r\n type: 'text'\r\n }\r\n },\r\n batch: {\r\n value: null,\r\n types: ['string', 'null'],\r\n envLink: 'EXPORT_BATCH',\r\n description:\r\n 'Batch job string with input/output pairs: \"in=out;in=out;...\"',\r\n promptOptions: {\r\n type: 'text'\r\n }\r\n },\r\n outfile: {\r\n value: null,\r\n types: ['string', 'null'],\r\n envLink: 'EXPORT_OUTFILE',\r\n description:\r\n 'Output filename with type. Can be jpeg, png, pdf, or svg and ignores `type` option',\r\n promptOptions: {\r\n type: 'text'\r\n }\r\n },\r\n type: {\r\n value: 'png',\r\n types: ['string'],\r\n envLink: 'EXPORT_TYPE',\r\n description: 'File export format. Can be jpeg, png, pdf, or svg',\r\n promptOptions: {\r\n type: 'select',\r\n hint: 'Default: png',\r\n choices: ['png', 'jpeg', 'pdf', 'svg']\r\n }\r\n },\r\n constr: {\r\n value: 'chart',\r\n types: ['string'],\r\n envLink: 'EXPORT_CONSTR',\r\n description:\r\n 'Chart constructor. Can be chart, stockChart, mapChart, or ganttChart',\r\n promptOptions: {\r\n type: 'select',\r\n hint: 'Default: chart',\r\n choices: ['chart', 'stockChart', 'mapChart', 'ganttChart']\r\n }\r\n },\r\n b64: {\r\n value: false,\r\n types: ['boolean'],\r\n envLink: 'EXPORT_B64',\r\n description:\r\n 'Whether or not to the chart should be received in Base64 format instead of binary',\r\n promptOptions: {\r\n type: 'toggle'\r\n }\r\n },\r\n noDownload: {\r\n value: false,\r\n types: ['boolean'],\r\n envLink: 'EXPORT_NO_DOWNLOAD',\r\n description:\r\n 'Whether or not to include or exclude attachment headers in the response',\r\n promptOptions: {\r\n type: 'toggle'\r\n }\r\n },\r\n height: {\r\n value: null,\r\n types: ['number', 'null'],\r\n envLink: 'EXPORT_HEIGHT',\r\n description: 'Height of the exported chart, overrides chart settings',\r\n promptOptions: {\r\n type: 'number'\r\n }\r\n },\r\n width: {\r\n value: null,\r\n types: ['number', 'null'],\r\n envLink: 'EXPORT_WIDTH',\r\n description: 'Width of the exported chart, overrides chart settings',\r\n promptOptions: {\r\n type: 'number'\r\n }\r\n },\r\n scale: {\r\n value: null,\r\n types: ['number', 'null'],\r\n envLink: 'EXPORT_SCALE',\r\n description:\r\n 'Scale of the exported chart, overrides chart settings. Ranges from 0.1 to 5.0',\r\n promptOptions: {\r\n type: 'number'\r\n }\r\n },\r\n defaultHeight: {\r\n value: 400,\r\n types: ['number'],\r\n envLink: 'EXPORT_DEFAULT_HEIGHT',\r\n description: 'Default height of the exported chart if not set',\r\n promptOptions: {\r\n type: 'number'\r\n }\r\n },\r\n defaultWidth: {\r\n value: 600,\r\n types: ['number'],\r\n envLink: 'EXPORT_DEFAULT_WIDTH',\r\n description: 'Default width of the exported chart if not set',\r\n promptOptions: {\r\n type: 'number'\r\n }\r\n },\r\n defaultScale: {\r\n value: 1,\r\n types: ['number'],\r\n envLink: 'EXPORT_DEFAULT_SCALE',\r\n description:\r\n 'Default scale of the exported chart if not set. Ranges from 0.1 to 5.0',\r\n promptOptions: {\r\n type: 'number',\r\n min: 0.1,\r\n max: 5\r\n }\r\n },\r\n globalOptions: {\r\n value: null,\r\n types: ['Object', 'string', 'null'],\r\n envLink: 'EXPORT_GLOBAL_OPTIONS',\r\n description:\r\n 'JSON, stringified JSON or filename with global options for Highcharts.setOptions',\r\n promptOptions: {\r\n type: 'text'\r\n }\r\n },\r\n themeOptions: {\r\n value: null,\r\n types: ['Object', 'string', 'null'],\r\n envLink: 'EXPORT_THEME_OPTIONS',\r\n description:\r\n 'JSON, stringified JSON or filename with theme options for Highcharts.setOptions',\r\n promptOptions: {\r\n type: 'text'\r\n }\r\n },\r\n rasterizationTimeout: {\r\n value: 1500,\r\n types: ['number'],\r\n envLink: 'EXPORT_RASTERIZATION_TIMEOUT',\r\n description: 'Milliseconds to wait for webpage rendering',\r\n promptOptions: {\r\n type: 'number'\r\n }\r\n }\r\n },\r\n customLogic: {\r\n allowCodeExecution: {\r\n value: false,\r\n types: ['boolean'],\r\n envLink: 'CUSTOM_LOGIC_ALLOW_CODE_EXECUTION',\r\n description:\r\n 'Allows or disallows execution of arbitrary code during exporting',\r\n promptOptions: {\r\n type: 'toggle'\r\n }\r\n },\r\n allowFileResources: {\r\n value: false,\r\n types: ['boolean'],\r\n envLink: 'CUSTOM_LOGIC_ALLOW_FILE_RESOURCES',\r\n description:\r\n 'Allows or disallows injection of filesystem resources (disabled in server mode)',\r\n promptOptions: {\r\n type: 'toggle'\r\n }\r\n },\r\n customCode: {\r\n value: null,\r\n types: ['string', 'null'],\r\n envLink: 'CUSTOM_LOGIC_CUSTOM_CODE',\r\n description:\r\n 'Custom code to execute before chart initialization. Can be a function, code wrapped in a function, or a .js filename',\r\n promptOptions: {\r\n type: 'text'\r\n }\r\n },\r\n callback: {\r\n value: null,\r\n types: ['string', 'null'],\r\n envLink: 'CUSTOM_LOGIC_CALLBACK',\r\n description:\r\n 'JavaScript code to run during construction. Can be a function or a .js filename',\r\n promptOptions: {\r\n type: 'text'\r\n }\r\n },\r\n resources: {\r\n value: null,\r\n types: ['Object', 'string', 'null'],\r\n envLink: 'CUSTOM_LOGIC_RESOURCES',\r\n description:\r\n 'Additional resources as JSON, stringified JSON, or filename, containing files, js, and css sections',\r\n promptOptions: {\r\n type: 'text'\r\n }\r\n },\r\n loadConfig: {\r\n value: null,\r\n types: ['string', 'null'],\r\n envLink: 'CUSTOM_LOGIC_LOAD_CONFIG',\r\n legacyName: 'fromFile',\r\n description: 'File with a pre-defined configuration to use',\r\n promptOptions: {\r\n type: 'text'\r\n }\r\n },\r\n createConfig: {\r\n value: null,\r\n types: ['string', 'null'],\r\n envLink: 'CUSTOM_LOGIC_CREATE_CONFIG',\r\n description:\r\n 'Prompt-based option setting, saved to a provided config file',\r\n promptOptions: {\r\n type: 'text'\r\n }\r\n }\r\n },\r\n server: {\r\n enable: {\r\n value: false,\r\n types: ['boolean'],\r\n envLink: 'SERVER_ENABLE',\r\n cliName: 'enableServer',\r\n description: 'Starts the server when true',\r\n promptOptions: {\r\n type: 'toggle'\r\n }\r\n },\r\n host: {\r\n value: '0.0.0.0',\r\n types: ['string'],\r\n envLink: 'SERVER_HOST',\r\n description: 'Hostname of the server',\r\n promptOptions: {\r\n type: 'text'\r\n }\r\n },\r\n port: {\r\n value: 7801,\r\n types: ['number'],\r\n envLink: 'SERVER_PORT',\r\n description: 'Port number for the server',\r\n promptOptions: {\r\n type: 'number'\r\n }\r\n },\r\n uploadLimit: {\r\n value: 3,\r\n types: ['number'],\r\n envLink: 'SERVER_UPLOAD_LIMIT',\r\n description: 'Maximum request body size in MB',\r\n promptOptions: {\r\n type: 'number'\r\n }\r\n },\r\n benchmarking: {\r\n value: false,\r\n types: ['boolean'],\r\n envLink: 'SERVER_BENCHMARKING',\r\n cliName: 'serverBenchmarking',\r\n description:\r\n 'Displays or not action durations in milliseconds during server requests',\r\n promptOptions: {\r\n type: 'toggle'\r\n }\r\n },\r\n proxy: {\r\n host: {\r\n value: null,\r\n types: ['string', 'null'],\r\n envLink: 'SERVER_PROXY_HOST',\r\n cliName: 'proxyHost',\r\n description: 'Host of the proxy server, if applicable',\r\n promptOptions: {\r\n type: 'text'\r\n }\r\n },\r\n port: {\r\n value: null,\r\n types: ['number', 'null'],\r\n envLink: 'SERVER_PROXY_PORT',\r\n cliName: 'proxyPort',\r\n description: 'Port of the proxy server, if applicable',\r\n promptOptions: {\r\n type: 'number'\r\n }\r\n },\r\n timeout: {\r\n value: 5000,\r\n types: ['number'],\r\n envLink: 'SERVER_PROXY_TIMEOUT',\r\n cliName: 'proxyTimeout',\r\n description:\r\n 'Timeout in milliseconds for the proxy server, if applicable',\r\n promptOptions: {\r\n type: 'number'\r\n }\r\n }\r\n },\r\n rateLimiting: {\r\n enable: {\r\n value: false,\r\n types: ['boolean'],\r\n envLink: 'SERVER_RATE_LIMITING_ENABLE',\r\n cliName: 'enableRateLimiting',\r\n description: 'Enables or disables rate limiting on the server',\r\n promptOptions: {\r\n type: 'toggle'\r\n }\r\n },\r\n maxRequests: {\r\n value: 10,\r\n types: ['number'],\r\n envLink: 'SERVER_RATE_LIMITING_MAX_REQUESTS',\r\n legacyName: 'rateLimit',\r\n description: 'Maximum number of requests allowed per minute',\r\n promptOptions: {\r\n type: 'number'\r\n }\r\n },\r\n window: {\r\n value: 1,\r\n types: ['number'],\r\n envLink: 'SERVER_RATE_LIMITING_WINDOW',\r\n description: 'Time window in minutes for rate limiting',\r\n promptOptions: {\r\n type: 'number'\r\n }\r\n },\r\n delay: {\r\n value: 0,\r\n types: ['number'],\r\n envLink: 'SERVER_RATE_LIMITING_DELAY',\r\n description:\r\n 'Delay duration between successive requests before reaching the limit',\r\n promptOptions: {\r\n type: 'number'\r\n }\r\n },\r\n trustProxy: {\r\n value: false,\r\n types: ['boolean'],\r\n envLink: 'SERVER_RATE_LIMITING_TRUST_PROXY',\r\n description: 'Set to true if the server is behind a load balancer',\r\n promptOptions: {\r\n type: 'toggle'\r\n }\r\n },\r\n skipKey: {\r\n value: null,\r\n types: ['string', 'null'],\r\n envLink: 'SERVER_RATE_LIMITING_SKIP_KEY',\r\n description: 'Key to bypass the rate limiter, used with `skipToken`',\r\n promptOptions: {\r\n type: 'text'\r\n }\r\n },\r\n skipToken: {\r\n value: null,\r\n types: ['string', 'null'],\r\n envLink: 'SERVER_RATE_LIMITING_SKIP_TOKEN',\r\n description: 'Token to bypass the rate limiter, used with `skipKey`',\r\n promptOptions: {\r\n type: 'text'\r\n }\r\n }\r\n },\r\n ssl: {\r\n enable: {\r\n value: false,\r\n types: ['boolean'],\r\n envLink: 'SERVER_SSL_ENABLE',\r\n cliName: 'enableSsl',\r\n description: 'Enables or disables SSL protocol',\r\n promptOptions: {\r\n type: 'toggle'\r\n }\r\n },\r\n force: {\r\n value: false,\r\n types: ['boolean'],\r\n envLink: 'SERVER_SSL_FORCE',\r\n cliName: 'sslForce',\r\n legacyName: 'sslOnly',\r\n description: 'Forces the server to use HTTPS only when true',\r\n promptOptions: {\r\n type: 'toggle'\r\n }\r\n },\r\n port: {\r\n value: 443,\r\n types: ['number'],\r\n envLink: 'SERVER_SSL_PORT',\r\n cliName: 'sslPort',\r\n description: 'Port for the SSL server',\r\n promptOptions: {\r\n type: 'number'\r\n }\r\n },\r\n certPath: {\r\n value: null,\r\n types: ['string', 'null'],\r\n envLink: 'SERVER_SSL_CERT_PATH',\r\n cliName: 'sslCertPath',\r\n legacyName: 'sslPath',\r\n description: 'Path to the SSL certificate/key file',\r\n promptOptions: {\r\n type: 'text'\r\n }\r\n }\r\n }\r\n },\r\n pool: {\r\n minWorkers: {\r\n value: 4,\r\n types: ['number'],\r\n envLink: 'POOL_MIN_WORKERS',\r\n description: 'Minimum and initial number of pool workers to spawn',\r\n promptOptions: {\r\n type: 'number'\r\n }\r\n },\r\n maxWorkers: {\r\n value: 8,\r\n types: ['number'],\r\n envLink: 'POOL_MAX_WORKERS',\r\n legacyName: 'workers',\r\n description: 'Maximum number of pool workers to spawn',\r\n promptOptions: {\r\n type: 'number'\r\n }\r\n },\r\n workLimit: {\r\n value: 40,\r\n types: ['number'],\r\n envLink: 'POOL_WORK_LIMIT',\r\n description: 'Number of tasks a worker can handle before restarting',\r\n promptOptions: {\r\n type: 'number'\r\n }\r\n },\r\n acquireTimeout: {\r\n value: 5000,\r\n types: ['number'],\r\n envLink: 'POOL_ACQUIRE_TIMEOUT',\r\n description: 'Timeout in milliseconds for acquiring a resource',\r\n promptOptions: {\r\n type: 'number'\r\n }\r\n },\r\n createTimeout: {\r\n value: 5000,\r\n types: ['number'],\r\n envLink: 'POOL_CREATE_TIMEOUT',\r\n description: 'Timeout in milliseconds for creating a resource',\r\n promptOptions: {\r\n type: 'number'\r\n }\r\n },\r\n destroyTimeout: {\r\n value: 5000,\r\n types: ['number'],\r\n envLink: 'POOL_DESTROY_TIMEOUT',\r\n description: 'Timeout in milliseconds for destroying a resource',\r\n promptOptions: {\r\n type: 'number'\r\n }\r\n },\r\n idleTimeout: {\r\n value: 30000,\r\n types: ['number'],\r\n envLink: 'POOL_IDLE_TIMEOUT',\r\n description: 'Timeout in milliseconds for destroying idle resources',\r\n promptOptions: {\r\n type: 'number'\r\n }\r\n },\r\n createRetryInterval: {\r\n value: 200,\r\n types: ['number'],\r\n envLink: 'POOL_CREATE_RETRY_INTERVAL',\r\n description:\r\n 'Interval in milliseconds before retrying resource creation on failure',\r\n promptOptions: {\r\n type: 'number'\r\n }\r\n },\r\n reaperInterval: {\r\n value: 1000,\r\n types: ['number'],\r\n envLink: 'POOL_REAPER_INTERVAL',\r\n description:\r\n 'Interval in milliseconds to check and destroy idle resources',\r\n promptOptions: {\r\n type: 'number'\r\n }\r\n },\r\n benchmarking: {\r\n value: false,\r\n types: ['boolean'],\r\n envLink: 'POOL_BENCHMARKING',\r\n cliName: 'poolBenchmarking',\r\n description: 'Shows statistics for the pool of resources',\r\n promptOptions: {\r\n type: 'toggle'\r\n }\r\n }\r\n },\r\n logging: {\r\n level: {\r\n value: 4,\r\n types: ['number'],\r\n envLink: 'LOGGING_LEVEL',\r\n cliName: 'logLevel',\r\n description: 'Logging verbosity level',\r\n promptOptions: {\r\n type: 'number',\r\n round: 0,\r\n min: 0,\r\n max: 5\r\n }\r\n },\r\n file: {\r\n value: 'highcharts-export-server.log',\r\n types: ['string'],\r\n envLink: 'LOGGING_FILE',\r\n cliName: 'logFile',\r\n description:\r\n 'Log file name. Requires `logToFile` and `logDest` to be set',\r\n promptOptions: {\r\n type: 'text'\r\n }\r\n },\r\n dest: {\r\n value: 'log',\r\n types: ['string'],\r\n envLink: 'LOGGING_DEST',\r\n cliName: 'logDest',\r\n description: 'Path to store log files. Requires `logToFile` to be set',\r\n promptOptions: {\r\n type: 'text'\r\n }\r\n },\r\n toConsole: {\r\n value: true,\r\n types: ['boolean'],\r\n envLink: 'LOGGING_TO_CONSOLE',\r\n cliName: 'logToConsole',\r\n description: 'Enables or disables console logging',\r\n promptOptions: {\r\n type: 'toggle'\r\n }\r\n },\r\n toFile: {\r\n value: true,\r\n types: ['boolean'],\r\n envLink: 'LOGGING_TO_FILE',\r\n cliName: 'logToFile',\r\n description: 'Enables or disables logging to a file',\r\n promptOptions: {\r\n type: 'toggle'\r\n }\r\n }\r\n },\r\n ui: {\r\n enable: {\r\n value: false,\r\n types: ['boolean'],\r\n envLink: 'UI_ENABLE',\r\n cliName: 'enableUi',\r\n description: 'Enables or disables the UI for the export server',\r\n promptOptions: {\r\n type: 'toggle'\r\n }\r\n },\r\n route: {\r\n value: '/',\r\n types: ['string'],\r\n envLink: 'UI_ROUTE',\r\n cliName: 'uiRoute',\r\n description: 'The endpoint route for the UI',\r\n promptOptions: {\r\n type: 'text'\r\n }\r\n }\r\n },\r\n other: {\r\n nodeEnv: {\r\n value: 'production',\r\n types: ['string'],\r\n envLink: 'OTHER_NODE_ENV',\r\n description: 'The Node.js environment type',\r\n promptOptions: {\r\n type: 'text'\r\n }\r\n },\r\n listenToProcessExits: {\r\n value: true,\r\n types: ['boolean'],\r\n envLink: 'OTHER_LISTEN_TO_PROCESS_EXITS',\r\n description: 'Whether or not to attach process.exit handlers',\r\n promptOptions: {\r\n type: 'toggle'\r\n }\r\n },\r\n noLogo: {\r\n value: false,\r\n types: ['boolean'],\r\n envLink: 'OTHER_NO_LOGO',\r\n description: 'Display or skip printing the logo on startup',\r\n promptOptions: {\r\n type: 'toggle'\r\n }\r\n },\r\n hardResetPage: {\r\n value: false,\r\n types: ['boolean'],\r\n envLink: 'OTHER_HARD_RESET_PAGE',\r\n description: 'Whether or not to reset the page content entirely',\r\n promptOptions: {\r\n type: 'toggle'\r\n }\r\n },\r\n browserShellMode: {\r\n value: true,\r\n types: ['boolean'],\r\n envLink: 'OTHER_BROWSER_SHELL_MODE',\r\n description: 'Whether or not to set the browser to run in shell mode',\r\n promptOptions: {\r\n type: 'toggle'\r\n }\r\n },\r\n validation: {\r\n value: true,\r\n types: ['boolean'],\r\n envLink: 'OTHER_VALIDATION',\r\n description: 'Whether or not to enable validation of options types',\r\n promptOptions: {\r\n type: 'toggle'\r\n }\r\n }\r\n },\r\n debug: {\r\n enable: {\r\n value: false,\r\n types: ['boolean'],\r\n envLink: 'DEBUG_ENABLE',\r\n cliName: 'enableDebug',\r\n description: 'Enables or disables debug mode for the underlying browser',\r\n promptOptions: {\r\n type: 'toggle'\r\n }\r\n },\r\n headless: {\r\n value: false,\r\n types: ['boolean'],\r\n envLink: 'DEBUG_HEADLESS',\r\n description:\r\n 'Whether or not to set the browser to run in headless mode during debugging',\r\n promptOptions: {\r\n type: 'toggle'\r\n }\r\n },\r\n devtools: {\r\n value: false,\r\n types: ['boolean'],\r\n envLink: 'DEBUG_DEVTOOLS',\r\n description: 'Enables or disables DevTools in headful mode',\r\n promptOptions: {\r\n type: 'toggle'\r\n }\r\n },\r\n listenToConsole: {\r\n value: false,\r\n types: ['boolean'],\r\n envLink: 'DEBUG_LISTEN_TO_CONSOLE',\r\n description:\r\n 'Enables or disables listening to console messages from the browser',\r\n promptOptions: {\r\n type: 'toggle'\r\n }\r\n },\r\n dumpio: {\r\n value: false,\r\n types: ['boolean'],\r\n envLink: 'DEBUG_DUMPIO',\r\n description:\r\n 'Redirects or not browser stdout and stderr to process.stdout and process.stderr',\r\n promptOptions: {\r\n type: 'toggle'\r\n }\r\n },\r\n slowMo: {\r\n value: 0,\r\n types: ['number'],\r\n envLink: 'DEBUG_SLOW_MO',\r\n description: 'Delays Puppeteer operations by the specified milliseconds',\r\n promptOptions: {\r\n type: 'number'\r\n }\r\n },\r\n debuggingPort: {\r\n value: 9222,\r\n types: ['number'],\r\n envLink: 'DEBUG_DEBUGGING_PORT',\r\n description: 'Port used for debugging',\r\n promptOptions: {\r\n type: 'number'\r\n }\r\n }\r\n }\r\n};\r\n\r\n// Properties nesting level of all options\r\nexport const nestedProps = _createNestedProps(defaultConfig);\r\n\r\n// Properties names that should not be recursively merged\r\nexport const absoluteProps = _createAbsoluteProps(defaultConfig);\r\n\r\n/**\r\n * Recursively generates a mapping of nested argument chains from a nested\r\n * config object. This function traverses a nested object and creates a mapping\r\n * where each key is an argument name (either from `cliName`, `legacyName`,\r\n * or the original key) and each value is a string representing the chain\r\n * of nested properties leading to that argument.\r\n *\r\n * @function _createNestedProps\r\n *\r\n * @param {Object} config - The configuration object.\r\n * @param {Object} [nestedProps={}] - The accumulator object for storing\r\n * the resulting arguments chains. The default value is an empty object.\r\n * @param {string} [propChain=''] - The current chain of nested properties,\r\n * used internally during recursion. The default value is an empty string.\r\n *\r\n * @returns {Object} An object mapping argument names to their corresponding\r\n * nested property chains.\r\n */\r\nfunction _createNestedProps(config, nestedProps = {}, propChain = '') {\r\n Object.keys(config).forEach((key) => {\r\n // Get the specific section\r\n const entry = config[key];\r\n\r\n // Check if there is still more depth to traverse\r\n if (typeof entry.value === 'undefined') {\r\n // Recurse into deeper levels of nested arguments\r\n _createNestedProps(entry, nestedProps, `${propChain}.${key}`);\r\n } else {\r\n // Create the chain of nested arguments\r\n nestedProps[entry.cliName || key] = `${propChain}.${key}`.substring(1);\r\n\r\n // Support for the legacy, PhantomJS properties names\r\n if (entry.legacyName !== undefined) {\r\n nestedProps[entry.legacyName] = `${propChain}.${key}`.substring(1);\r\n }\r\n }\r\n });\r\n\r\n // Return the object with nested argument chains\r\n return nestedProps;\r\n}\r\n\r\n/**\r\n * Recursively gathers the names of properties from a configuration object that\r\n * can be treated as absolute properties. These properties have values that\r\n * are objects and do not contain further nested depth when merging an object\r\n * containing these options.\r\n *\r\n * @function _createAbsoluteProps\r\n *\r\n * @param {Object} config - The configuration object.\r\n * @param {Array.} [absoluteProps=[]] - An array to collect the names\r\n * of absolute properties. The default value is an empty array.\r\n *\r\n * @returns {Array.} An array containing the names of absolute\r\n * properties.\r\n */\r\nfunction _createAbsoluteProps(config, absoluteProps = []) {\r\n Object.keys(config).forEach((key) => {\r\n // Get the specific section\r\n const entry = config[key];\r\n\r\n // Check if there is still more depth to traverse\r\n if (typeof entry.types === 'undefined') {\r\n // Recurse into deeper levels\r\n _createAbsoluteProps(entry, absoluteProps);\r\n } else {\r\n // If the option can be an object, save its type in the array\r\n if (entry.types.includes('Object')) {\r\n absoluteProps.push(key);\r\n }\r\n }\r\n });\r\n\r\n // Return the array with the names of absolute properties\r\n return absoluteProps;\r\n}\r\n\r\nexport default {\r\n defaultConfig,\r\n nestedProps,\r\n absoluteProps\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * @overview This file handles parsing and validating options from multiple\r\n * sources (the config file, custom JSON, environment variables, CLI arguments,\r\n * and request payload) using the 'zod' library.\r\n *\r\n * Environment variables are parsed and validated only once at application\r\n * startup, and the validated results are exported as `envs` for use throughout\r\n * the application.\r\n *\r\n * Options from other sources, however, are parsed and validated on demand,\r\n * each time an export is attempted.\r\n */\r\n\r\nimport dotenv from 'dotenv';\r\nimport { z } from 'zod';\r\n\r\nimport { defaultConfig } from './schemas/config.js';\r\n\r\n// Load the .env into environment variables\r\ndotenv.config();\r\n\r\n// Get scripts names of each category from the default config\r\nconst { coreScripts, moduleScripts, indicatorScripts } =\r\n defaultConfig.highcharts;\r\n\r\n// Sets the custom error map globally\r\nz.setErrorMap(_customErrorMap);\r\n\r\n/**\r\n * Object containing custom general validators and parsers to avoid repetition\r\n * in schema objects. All validators apply to values from various sources,\r\n * including the default config file, a custom JSON file loaded with the option\r\n * called `loadConfig`, the .env file, CLI arguments, and the request payload.\r\n * The `strictCheck` flag enables stricter validation and parsing rules. This\r\n * flag is set to false for values that come from the .env file or CLI arguments\r\n * because they are provided as strings and need to be parsed accordingly first.\r\n */\r\nconst v = {\r\n /**\r\n * The `boolean` validator that returns a Zod schema with an optional stricter\r\n * check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures that:\r\n *\r\n * - When `strictCheck` is true, the schema will accept values are true\r\n * and false and the schema will validate against the default boolean\r\n * validator.\r\n *\r\n * - When `strictCheck` is false, the schema will accept values are true,\r\n * false, null, 'true', '1', 'false', '0', 'undefined', 'null', and ''.\r\n * The strings 'undefined', 'null', and '' will be transformed to null,\r\n * the string 'true' will be transformed to the boolean value true,\r\n * and 'false' will be transformed to the boolean value false.\r\n *\r\n * @function boolean\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating boolean values.\r\n */\r\n boolean(strictCheck) {\r\n return strictCheck\r\n ? z.boolean()\r\n : z\r\n .union([\r\n z\r\n .enum(['true', '1', 'false', '0', 'undefined', 'null', ''])\r\n .transform((value) =>\r\n !['undefined', 'null', ''].includes(value)\r\n ? value === 'true' || value === '1'\r\n : null\r\n ),\r\n z.boolean()\r\n ])\r\n .nullable();\r\n },\r\n\r\n /**\r\n * The `string` validator that returns a Zod schema with an optional stricter\r\n * check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures that:\r\n *\r\n * - When `strictCheck` is true, the schema will accept trimmed strings except\r\n * the forbidden values: 'false', 'undefined', 'null', and ''.\r\n *\r\n * - When `strictCheck` is false, the schema will accept trimmed strings\r\n * and null. The forbidden values: 'false', 'undefined', 'null', and '' will\r\n * be transformed to null.\r\n *\r\n * @function string\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating string values.\r\n */\r\n string(strictCheck) {\r\n return strictCheck\r\n ? z\r\n .string()\r\n .trim()\r\n .refine(\r\n (value) => !['false', 'undefined', 'null', ''].includes(value),\r\n {\r\n params: {\r\n errorMessage: 'The string contains a forbidden value'\r\n }\r\n }\r\n )\r\n : z\r\n .string()\r\n .trim()\r\n .transform((value) =>\r\n !['false', 'undefined', 'null', ''].includes(value) ? value : null\r\n )\r\n .nullable();\r\n },\r\n\r\n /**\r\n * The `enum` validator that returns a Zod schema with an optional stricter\r\n * check based on the `strictCheck` parameter.\r\n *\r\n * The schema will validate against the provided `values` array.\r\n *\r\n * The validation schema ensures that:\r\n *\r\n * - When `strictCheck` is true, the schema will validate against the `values`\r\n * array with the default enum validator.\r\n *\r\n * - When `strictCheck` is false, the schema will accept also null,\r\n * 'undefined', 'null', and '', which will be transformed to null.\r\n *\r\n * @function enum\r\n *\r\n * @param {Array.} values - An array of valid string values\r\n * for the enum.\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating enum values.\r\n */\r\n enum(values, strictCheck) {\r\n return strictCheck\r\n ? z.enum([...values])\r\n : z\r\n .enum([...values, 'undefined', 'null', ''])\r\n .transform((value) =>\r\n !['undefined', 'null', ''].includes(value) ? value : null\r\n )\r\n .nullable();\r\n },\r\n\r\n /**\r\n * The `stringArray` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures that:\r\n *\r\n * - When `strictCheck` is true, the schema will accept an array of trimmed\r\n * string values filtered by the logic provided through the `filterCallback`.\r\n *\r\n * - When `strictCheck` is false, the schema will accept null and trimmed\r\n * string values which will be splitted into an array of strings and filtered\r\n * from the '[' and ']' characters and by the logic provided through\r\n * the `filterCallback`. If the array is empty, it will be transformed\r\n * to null.\r\n *\r\n * @function stringArray\r\n *\r\n * @param {function} filterCallback - The filter callback.\r\n * @param {string} separator - The separator for spliting a string.\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating array of string\r\n * values.\r\n */\r\n stringArray(filterCallback, separator, strictCheck) {\r\n const arraySchema = z.string().trim().array();\r\n const stringSchema = z\r\n .string()\r\n .trim()\r\n .transform((value) => {\r\n if (value.startsWith('[')) {\r\n value = value.slice(1);\r\n }\r\n if (value.endsWith(']')) {\r\n value = value.slice(0, -1);\r\n }\r\n return value.split(separator);\r\n });\r\n\r\n const transformCallback = (value) =>\r\n value.map((value) => value.trim()).filter(filterCallback);\r\n\r\n return strictCheck\r\n ? arraySchema.transform(transformCallback)\r\n : z\r\n .union([stringSchema, arraySchema])\r\n .transform(transformCallback)\r\n .transform((value) => (value.length ? value : null))\r\n .nullable();\r\n },\r\n\r\n /**\r\n * The `positiveNum` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures that:\r\n *\r\n * - When `strictCheck` is true, the schema will accept positive number values\r\n * and validate against the default positive number validator.\r\n *\r\n * - When `strictCheck` is false, the schema will accept positive number\r\n * values, null, and trimmed string values that can either be 'undefined',\r\n * 'null', '', or represent a positive number. It will transform the string\r\n * to a positive number, or to null if it is 'undefined', 'null', or ''.\r\n *\r\n * @function positiveNum\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating positive number\r\n * values.\r\n */\r\n positiveNum(strictCheck) {\r\n return strictCheck\r\n ? z.number().positive()\r\n : z\r\n .union([\r\n z\r\n .string()\r\n .trim()\r\n .refine(\r\n (value) =>\r\n (!isNaN(Number(value)) && Number(value) > 0) ||\r\n ['undefined', 'null', ''].includes(value),\r\n {\r\n params: {\r\n errorMessage: 'The value must be numeric and positive'\r\n }\r\n }\r\n )\r\n .transform((value) =>\r\n !['undefined', 'null', ''].includes(value)\r\n ? Number(value)\r\n : null\r\n ),\r\n z.number().positive()\r\n ])\r\n .nullable();\r\n },\r\n\r\n /**\r\n * The `nonNegativeNum` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures that:\r\n *\r\n * - When `strictCheck` is true, the schema will accept non-negative number\r\n * values and validate against the default non-negative number validator.\r\n *\r\n * - When `strictCheck` is false, the schema will accept non-negative number\r\n * values, null, and trimmed string values that can either be 'undefined',\r\n * 'null', '', or represent a non-negative number. It will transform\r\n * the string to a non-negative number, or to null if it is 'undefined',\r\n * 'null', or ''.\r\n *\r\n * @function nonNegativeNum\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating non-negative\r\n * number values.\r\n */\r\n nonNegativeNum(strictCheck) {\r\n return strictCheck\r\n ? z.number().nonnegative()\r\n : z\r\n .union([\r\n z\r\n .string()\r\n .trim()\r\n .refine(\r\n (value) =>\r\n (!isNaN(Number(value)) && Number(value) >= 0) ||\r\n ['undefined', 'null', ''].includes(value),\r\n {\r\n params: {\r\n errorMessage: 'The value must be numeric and non-negative'\r\n }\r\n }\r\n )\r\n .transform((value) =>\r\n !['undefined', 'null', ''].includes(value)\r\n ? Number(value)\r\n : null\r\n ),\r\n z.number().nonnegative()\r\n ])\r\n .nullable();\r\n },\r\n\r\n /**\r\n * The `startsWith` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The schema will validate against the provided `prefixes` array to check\r\n * whether a string value starts with any of the values provided\r\n * in the `prefixes` array.\r\n *\r\n * The validation schema ensures that:\r\n *\r\n * - When `strictCheck` is true, the schema will accept trimmed string values\r\n * that start with values from the prefixes array.\r\n *\r\n * - When `strictCheck` is false, the schema will accept trimmed string values\r\n * that start with values from the prefixes array, null, 'undefined', 'null',\r\n * and '' where the schema will transform them to null.\r\n *\r\n * @function startsWith\r\n *\r\n * @param {Array.} prefixes - An array of prefixes to validate\r\n * the string against.\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating strings that\r\n * starts with values.\r\n */\r\n startsWith(prefixes, strictCheck) {\r\n return strictCheck\r\n ? z\r\n .string()\r\n .trim()\r\n .refine(\r\n (value) => prefixes.some((prefix) => value.startsWith(prefix)),\r\n {\r\n params: {\r\n errorMessage: `The value must be a string that starts with ${prefixes.join(', ')}`\r\n }\r\n }\r\n )\r\n : z\r\n .string()\r\n .trim()\r\n .refine(\r\n (value) =>\r\n prefixes.some((prefix) => value.startsWith(prefix)) ||\r\n ['undefined', 'null', ''].includes(value),\r\n {\r\n params: {\r\n errorMessage: `The value must be a string that starts with ${prefixes.join(', ')}`\r\n }\r\n }\r\n )\r\n .transform((value) =>\r\n !['undefined', 'null', ''].includes(value) ? value : null\r\n )\r\n .nullable();\r\n },\r\n\r\n /**\r\n * The `chartConfig` validator that returns a Zod schema.\r\n *\r\n * The validation schema ensures that the schema will accept object values\r\n * or trimmed string values that contain '\r\n (value.startsWith('{') && value.endsWith('}')) ||\r\n ['undefined', 'null', ''].includes(value),\r\n {\r\n params: {\r\n errorMessage:\r\n \"The value must be a string that starts with '{' and ends with '}'\"\r\n }\r\n }\r\n )\r\n .transform((value) =>\r\n !['undefined', 'null', ''].includes(value) ? value : null\r\n ),\r\n z.object({}).passthrough()\r\n ])\r\n .nullable();\r\n },\r\n\r\n /**\r\n * The `additionalOptions` validator that returns a Zod schema.\r\n *\r\n * The validation schema ensures that the schema will accept object values\r\n * or trimmed string values that end with '.json' and are at least one\r\n * character long excluding the extension, start with the '{' and end\r\n * with the '}', and null. The 'undefined', 'null', and '' values will\r\n * be transformed to null.\r\n *\r\n * @function additionalOptions\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating additional chart\r\n * options value.\r\n */\r\n additionalOptions() {\r\n return z\r\n .union([\r\n z\r\n .string()\r\n .trim()\r\n .refine(\r\n (value) =>\r\n (value.length >= 6 && value.endsWith('.json')) ||\r\n (value.startsWith('{') && value.endsWith('}')) ||\r\n ['undefined', 'null', ''].includes(value),\r\n {\r\n params: {\r\n errorMessage:\r\n \"The value must be a string that ends with '.json' or starts with '{' and ends with '}'\"\r\n }\r\n }\r\n )\r\n .transform((value) =>\r\n !['undefined', 'null', ''].includes(value) ? value : null\r\n ),\r\n z.object({}).passthrough()\r\n ])\r\n .nullable();\r\n }\r\n};\r\n\r\n/**\r\n * Object containing custom config validators and parsers to avoid repetition\r\n * in schema objects. All validators apply to values from various sources,\r\n * including the default config file, a custom JSON file loaded with the option\r\n * called `loadConfig`, the .env file, CLI arguments, and the request payload.\r\n * The `strictCheck` flag enables stricter validation and parsing rules. This\r\n * flag is set to false for values that come from the .env file or CLI arguments\r\n * because they are provided as strings and need to be parsed accordingly first.\r\n */\r\nexport const validators = {\r\n /**\r\n * The `args` validator that returns a Zod schema with an optional stricter\r\n * check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `stringArray` validator.\r\n *\r\n * @function args\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `args`\r\n * option.\r\n */\r\n args(strictCheck) {\r\n return v.stringArray(\r\n (value) => !['false', 'undefined', 'null', ''].includes(value),\r\n ';',\r\n strictCheck\r\n );\r\n },\r\n\r\n /**\r\n * The `version` validator that returns a Zod schema with an optional stricter\r\n * check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures that:\r\n *\r\n * - When `strictCheck` is true, the schema will accept trimmed string values\r\n * that are a RegExp-based that allows to be 'latest', or in the format XX,\r\n * XX.YY, or XX.YY.ZZ, where XX, YY, and ZZ are numeric for the Highcharts\r\n * version option.\r\n *\r\n * - When `strictCheck` is false, the schema will accept also null,\r\n * 'undefined', 'null', or '' and in all cases the schema will transform them\r\n * to null.\r\n *\r\n * @function version\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `version`\r\n * option.\r\n */\r\n version(strictCheck) {\r\n return strictCheck\r\n ? z\r\n .string()\r\n .trim()\r\n .refine((value) => /^(latest|\\d{1,2}(\\.\\d{1,2}){0,2})$/.test(value), {\r\n params: {\r\n errorMessage:\r\n \"The value must be 'latest', a major version, or in the form XX.YY.ZZ\"\r\n }\r\n })\r\n : z\r\n .string()\r\n .trim()\r\n .refine(\r\n (value) =>\r\n /^(latest|\\d{1,2}(\\.\\d{1,2}){0,2})$/.test(value) ||\r\n ['undefined', 'null', ''].includes(value),\r\n {\r\n params: {\r\n errorMessage:\r\n \"The value must be 'latest', a major version, or in the form XX.YY.ZZ\"\r\n }\r\n }\r\n )\r\n .transform((value) =>\r\n !['undefined', 'null', ''].includes(value) ? value : null\r\n )\r\n .nullable();\r\n },\r\n\r\n /**\r\n * The `cdnUrl` validator that returns a Zod schema with an optional stricter\r\n * check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `startsWith` validator.\r\n *\r\n * @function cdnUrl\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `cdnUrl`\r\n * option.\r\n */\r\n cdnUrl(strictCheck) {\r\n return v.startsWith(['http://', 'https://'], strictCheck);\r\n },\r\n\r\n /**\r\n * The `forceFetch` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `boolean` validator.\r\n *\r\n * @function forceFetch\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `forceFetch`\r\n * option.\r\n */\r\n forceFetch(strictCheck) {\r\n return v.boolean(strictCheck);\r\n },\r\n\r\n /**\r\n * The `cachePath` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `string` validator.\r\n *\r\n * @function cachePath\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `cachePath`\r\n * option.\r\n */\r\n cachePath(strictCheck) {\r\n return v.string(strictCheck);\r\n },\r\n\r\n /**\r\n * The `adminToken` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `string` validator.\r\n *\r\n * @function adminToken\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `adminToken`\r\n * option.\r\n */\r\n adminToken(strictCheck) {\r\n return v.string(strictCheck);\r\n },\r\n\r\n /**\r\n * The `coreScripts` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `stringArray` validator.\r\n *\r\n * @function coreScripts\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `coreScripts`\r\n * option.\r\n */\r\n coreScripts(strictCheck) {\r\n return v.stringArray(\r\n (value) => coreScripts.value.includes(value),\r\n ',',\r\n strictCheck\r\n );\r\n },\r\n\r\n /**\r\n * The `moduleScripts` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `stringArray` validator.\r\n *\r\n * @function moduleScripts\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating\r\n * the `moduleScripts` option.\r\n */\r\n moduleScripts(strictCheck) {\r\n return v.stringArray(\r\n (value) => moduleScripts.value.includes(value),\r\n ',',\r\n strictCheck\r\n );\r\n },\r\n\r\n /**\r\n * The `indicatorScripts` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `stringArray` validator.\r\n *\r\n * @function indicatorScripts\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating\r\n * the `indicatorScripts` option.\r\n */\r\n indicatorScripts(strictCheck) {\r\n return v.stringArray(\r\n (value) => indicatorScripts.value.includes(value),\r\n ',',\r\n strictCheck\r\n );\r\n },\r\n\r\n /**\r\n * The `customScripts` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `stringArray` validator.\r\n *\r\n * @function customScripts\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating\r\n * the `customScripts` option.\r\n */\r\n customScripts(strictCheck) {\r\n return v.stringArray(\r\n (value) => value.startsWith('https://') || value.startsWith('http://'),\r\n ',',\r\n strictCheck\r\n );\r\n },\r\n\r\n /**\r\n * The `infile` validator that returns a Zod schema with an optional stricter\r\n * check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures that:\r\n *\r\n * - When `strictCheck` is true, the schema will accept trimmed string values\r\n * that end with '.json' or '.svg', are at least one character long excluding\r\n * the extension, or null.\r\n *\r\n * - When `strictCheck` is false, the schema will accept trimmed string values\r\n * that end with '.json' or '.svg', are at least one character long excluding\r\n * the extension and will be null if the provided value is null, 'undefined',\r\n * 'null', or ''.\r\n *\r\n * @function infile\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `infile`\r\n * option.\r\n */\r\n infile(strictCheck) {\r\n return strictCheck\r\n ? z\r\n .string()\r\n .trim()\r\n .refine(\r\n (value) =>\r\n (value.length >= 6 && value.endsWith('.json')) ||\r\n (value.length >= 5 && value.endsWith('.svg')),\r\n {\r\n params: {\r\n errorMessage:\r\n 'The value must be a string that ends with .json or .svg'\r\n }\r\n }\r\n )\r\n .nullable()\r\n : z\r\n .string()\r\n .trim()\r\n .refine(\r\n (value) =>\r\n (value.length >= 6 && value.endsWith('.json')) ||\r\n (value.length >= 5 && value.endsWith('.svg')) ||\r\n ['undefined', 'null', ''].includes(value),\r\n {\r\n params: {\r\n errorMessage:\r\n 'The value must be a string that ends with .json or .svg'\r\n }\r\n }\r\n )\r\n .transform((value) =>\r\n !['undefined', 'null', ''].includes(value) ? value : null\r\n )\r\n .nullable();\r\n },\r\n\r\n /**\r\n * The `instr` validator that returns a Zod schema.\r\n *\r\n * The validation schema ensures the same work as the `options` validator.\r\n *\r\n * @function instr\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `instr`\r\n * option.\r\n */\r\n instr() {\r\n return v.chartConfig();\r\n },\r\n\r\n /**\r\n * The `options` validator that returns a Zod schema.\r\n *\r\n * The validation schema ensures the same work as the `options` validator.\r\n *\r\n * @function options\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `options`\r\n * option.\r\n */\r\n options() {\r\n return v.chartConfig();\r\n },\r\n\r\n /**\r\n * The `svg` validator that returns a Zod schema.\r\n *\r\n * The validation schema ensures that the schema will accept object values\r\n * or trimmed string values that contain '\r\n value.indexOf('= 0 ||\r\n value.indexOf('= 0 ||\r\n ['false', 'undefined', 'null', ''].includes(value),\r\n {\r\n params: {\r\n errorMessage:\r\n \"The value must be a string that contains '\r\n !['false', 'undefined', 'null', ''].includes(value) ? value : null\r\n )\r\n .nullable();\r\n },\r\n\r\n /**\r\n * The `outfile` validator that returns a Zod schema with an optional stricter\r\n * check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures that:\r\n *\r\n * - When `strictCheck` is true, the schema will accept trimmed string values\r\n * that end with '.jpeg', '.jpg', '.png', '.pdf', or '.svg', are at least one\r\n * character long excluding the extension, or null.\r\n *\r\n * - When `strictCheck` is false, the schema will accept trimmed string values\r\n * that end with '.jpeg', '.jpg', '.png', '.pdf', or '.svg', are at least one\r\n * character long excluding the extension and will be null if the provided\r\n * value is null, 'undefined', 'null', or ''.\r\n *\r\n * @function outfile\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `outfile`\r\n * option.\r\n */\r\n outfile(strictCheck) {\r\n return strictCheck\r\n ? z\r\n .string()\r\n .trim()\r\n .refine(\r\n (value) =>\r\n (value.length >= 6 && value.endsWith('.jpeg')) ||\r\n (value.length >= 5 &&\r\n (value.endsWith('.jpg') ||\r\n value.endsWith('.png') ||\r\n value.endsWith('.pdf') ||\r\n value.endsWith('.svg'))),\r\n {\r\n params: {\r\n errorMessage:\r\n 'The value must be a string that ends with .jpeg, .jpg, .png, .pdf, or .svg'\r\n }\r\n }\r\n )\r\n .nullable()\r\n : z\r\n .string()\r\n .trim()\r\n .refine(\r\n (value) =>\r\n (value.length >= 6 && value.endsWith('.jpeg')) ||\r\n (value.length >= 5 &&\r\n (value.endsWith('.jpg') ||\r\n value.endsWith('.png') ||\r\n value.endsWith('.pdf') ||\r\n value.endsWith('.svg'))) ||\r\n ['undefined', 'null', ''].includes(value),\r\n {\r\n params: {\r\n errorMessage:\r\n 'The value must be a string that ends with .jpeg, .jpg, .png, .pdf, or .svg'\r\n }\r\n }\r\n )\r\n .transform((value) =>\r\n !['undefined', 'null', ''].includes(value) ? value : null\r\n )\r\n .nullable();\r\n },\r\n\r\n /**\r\n * The `type` validator that returns a Zod schema with an optional stricter\r\n * check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `enum` validator.\r\n *\r\n * @function type\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `type`\r\n * option.\r\n */\r\n type(strictCheck) {\r\n return v.enum(['jpeg', 'jpg', 'png', 'pdf', 'svg'], strictCheck);\r\n },\r\n\r\n /**\r\n * The `constr` validator that returns a Zod schema with an optional stricter\r\n * check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `enum` validator.\r\n *\r\n * @function constr\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `constr`\r\n * option.\r\n */\r\n constr(strictCheck) {\r\n return v.enum(\r\n ['chart', 'stockChart', 'mapChart', 'ganttChart'],\r\n strictCheck\r\n );\r\n },\r\n\r\n /**\r\n * The `b64` validator that returns a Zod schema with an optional stricter\r\n * check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `boolean` validator.\r\n *\r\n * @function b64\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `b64` option.\r\n */\r\n b64(strictCheck) {\r\n return v.boolean(strictCheck);\r\n },\r\n\r\n /**\r\n * The `noDownload` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `boolean` validator.\r\n *\r\n * @function noDownload\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `noDownload`\r\n * option.\r\n */\r\n noDownload(strictCheck) {\r\n return v.boolean(strictCheck);\r\n },\r\n\r\n /**\r\n * The `defaultHeight` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `positiveNum` validator.\r\n *\r\n * @function defaultHeight\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating\r\n * the `defaultHeight` option.\r\n */\r\n defaultHeight(strictCheck) {\r\n return v.positiveNum(strictCheck);\r\n },\r\n\r\n /**\r\n * The `defaultWidth` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `positiveNum` validator.\r\n *\r\n * @function defaultWidth\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating\r\n * the `defaultWidth` option.\r\n */\r\n defaultWidth(strictCheck) {\r\n return v.positiveNum(strictCheck);\r\n },\r\n\r\n /**\r\n * The `defaultScale` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures that:\r\n *\r\n * - When `strictCheck` is true, the schema will accept number values that\r\n * are between 0.1 and 5 (inclusive).\r\n *\r\n * - When `strictCheck` is false, the schema will accept number values\r\n * and stringified number values that are between 0.1 and 5 (inclusive), null,\r\n * 'undefined', 'null', and '' which will be transformed to null.\r\n *\r\n * @function defaultScale\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating\r\n * the `defaultScale` option.\r\n */\r\n defaultScale(strictCheck) {\r\n return strictCheck\r\n ? z.number().gte(0.1).lte(5)\r\n : z\r\n .union([\r\n z\r\n .string()\r\n .trim()\r\n .refine(\r\n (value) =>\r\n (!isNaN(Number(value)) &&\r\n value !== true &&\r\n !value.startsWith('[') &&\r\n Number(value) >= 0.1 &&\r\n Number(value) <= 5) ||\r\n ['undefined', 'null', ''].includes(value),\r\n {\r\n params: {\r\n errorMessage: 'The value must be within a 0.1 and 5.0 range'\r\n }\r\n }\r\n )\r\n .transform((value) =>\r\n !['undefined', 'null', ''].includes(value)\r\n ? Number(value)\r\n : null\r\n ),\r\n z.number().gte(0.1).lte(5)\r\n ])\r\n .nullable();\r\n },\r\n\r\n /**\r\n * The `height` validator that returns a Zod schema with an optional stricter\r\n * check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as a nullable `defaultHeight`\r\n * validator.\r\n *\r\n * @function height\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `height`\r\n * option.\r\n */\r\n height(strictCheck) {\r\n return this.defaultHeight(strictCheck).nullable();\r\n },\r\n\r\n /**\r\n * The `width` validator that returns a Zod schema with an optional stricter\r\n * check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as a nullable `defaultWidth`\r\n * validator.\r\n *\r\n * @function width\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `width`\r\n * option.\r\n */\r\n width(strictCheck) {\r\n return this.defaultWidth(strictCheck).nullable();\r\n },\r\n\r\n /**\r\n * The `scale` validator that returns a Zod schema with an optional stricter\r\n * check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as a nullable `defaultScale`\r\n * validator.\r\n *\r\n * @function scale\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `scale`\r\n * option.\r\n */\r\n scale(strictCheck) {\r\n return this.defaultScale(strictCheck).nullable();\r\n },\r\n\r\n /**\r\n * The `globalOptions` validator that returns a Zod schema.\r\n *\r\n * The validation schema ensures the same work as the `additionalOptions`\r\n * validator.\r\n *\r\n * @function globalOptions\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating\r\n * the `globalOptions` option.\r\n */\r\n globalOptions() {\r\n return v.additionalOptions();\r\n },\r\n\r\n /**\r\n * The `themeOptions` validator that returns a Zod schema.\r\n *\r\n * The validation schema ensures the same work as the `additionalOptions`\r\n * validator.\r\n *\r\n * @function themeOptions\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating\r\n * the `themeOptions` option.\r\n */\r\n themeOptions() {\r\n return v.additionalOptions();\r\n },\r\n\r\n /**\r\n * The `batch` validator that returns a Zod schema with an optional stricter\r\n * check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `string` validator.\r\n *\r\n * @function batch\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `batch`\r\n * option.\r\n */\r\n batch(strictCheck) {\r\n return v.string(strictCheck);\r\n },\r\n\r\n /**\r\n * The `rasterizationTimeout` validator that returns a Zod schema with\r\n * an optional stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `nonNegativeNum`\r\n * validator.\r\n *\r\n * @function rasterizationTimeout\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating\r\n * the `rasterizationTimeout` option.\r\n */\r\n rasterizationTimeout(strictCheck) {\r\n return v.nonNegativeNum(strictCheck);\r\n },\r\n\r\n /**\r\n * The `allowCodeExecution` validator that returns a Zod schema with\r\n * an optional stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `boolean` validator.\r\n *\r\n * @function allowCodeExecution\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating\r\n * the `allowCodeExecution` option.\r\n */\r\n allowCodeExecution(strictCheck) {\r\n return v.boolean(strictCheck);\r\n },\r\n\r\n /**\r\n * The `allowFileResources` validator that returns a Zod schema with\r\n * an optional stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `boolean` validator.\r\n *\r\n * @function allowFileResources\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating\r\n * the `allowFileResources` option.\r\n */\r\n allowFileResources(strictCheck) {\r\n return v.boolean(strictCheck);\r\n },\r\n\r\n /**\r\n * The `customCode` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `string` validator.\r\n *\r\n * @function customCode\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `customCode`\r\n * option.\r\n */\r\n customCode(strictCheck) {\r\n return v.string(strictCheck);\r\n },\r\n\r\n /**\r\n * The `callback` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `string` validator.\r\n *\r\n * @function callback\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `callback`\r\n * option.\r\n */\r\n callback(strictCheck) {\r\n return v.string(strictCheck);\r\n },\r\n\r\n /**\r\n * The `resources` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures that:\r\n *\r\n * - When `strictCheck` is true, the schema will accept a partial object\r\n * with allowed properties `js`, `css`, and `files` where each of the allowed\r\n * properties can be null, stringified version of the object, string that ends\r\n * with the '.json', and null.\r\n *\r\n * - When `strictCheck` is false, the schema will accept a stringified version\r\n * of a partial object with allowed properties `js`, `css`, and `files` where\r\n * each of the allowed properties can be null, string that ends with the\r\n * '.json', and will be null if the provided value is 'undefined', 'null'\r\n * or ''.\r\n *\r\n * @function resources\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `resources`\r\n * option.\r\n */\r\n resources(strictCheck) {\r\n const objectSchema = z\r\n .object({\r\n js: v.string(false),\r\n css: v.string(false),\r\n files: v\r\n .stringArray(\r\n (value) => !['undefined', 'null', ''].includes(value),\r\n ',',\r\n true\r\n )\r\n .nullable()\r\n })\r\n .partial();\r\n\r\n const stringSchema1 = z\r\n .string()\r\n .trim()\r\n .refine(\r\n (value) =>\r\n (value.startsWith('{') && value.endsWith('}')) ||\r\n (value.length >= 6 && value.endsWith('.json')),\r\n {\r\n params: {\r\n errorMessage:\r\n \"The value must be a string that starts with '{' and ends with '}\"\r\n }\r\n }\r\n );\r\n\r\n const stringSchema2 = z\r\n .string()\r\n .trim()\r\n .refine(\r\n (value) =>\r\n (value.startsWith('{') && value.endsWith('}')) ||\r\n (value.length >= 6 && value.endsWith('.json')) ||\r\n ['undefined', 'null', ''].includes(value),\r\n {\r\n params: {\r\n errorMessage: 'The value must be a string that ends with .json'\r\n }\r\n }\r\n )\r\n .transform((value) =>\r\n !['undefined', 'null', ''].includes(value) ? value : null\r\n );\r\n\r\n return strictCheck\r\n ? z.union([objectSchema, stringSchema1]).nullable()\r\n : z.union([objectSchema, stringSchema2]).nullable();\r\n },\r\n\r\n /**\r\n * The `loadConfig` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `string` validator.\r\n * Additionally, it must be a string that ends with '.json'.\r\n *\r\n * @function loadConfig\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `loadConfig`\r\n * option.\r\n */\r\n loadConfig(strictCheck) {\r\n return v\r\n .string(strictCheck)\r\n .refine(\r\n (value) =>\r\n value === null || (value.length >= 6 && value.endsWith('.json')),\r\n {\r\n params: {\r\n errorMessage: 'The value must be a string that ends with .json'\r\n }\r\n }\r\n );\r\n },\r\n\r\n /**\r\n * The `createConfig` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `loadConfig` validator.\r\n *\r\n * @function createConfig\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating\r\n * the `createConfig` option.\r\n */\r\n createConfig(strictCheck) {\r\n return this.loadConfig(strictCheck);\r\n },\r\n\r\n /**\r\n * The `enableServer` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `boolean` validator.\r\n *\r\n * @function enableServer\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating\r\n * the `enableServer` option.\r\n */\r\n enableServer(strictCheck) {\r\n return v.boolean(strictCheck);\r\n },\r\n\r\n /**\r\n * The `host` validator that returns a Zod schema with an optional stricter\r\n * check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `string` validator.\r\n *\r\n * @function host\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `host`\r\n * option.\r\n */\r\n host(strictCheck) {\r\n return v.string(strictCheck);\r\n },\r\n\r\n /**\r\n * The `port` validator that returns a Zod schema with an optional stricter\r\n * check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `nonNegativeNum`\r\n * validator.\r\n *\r\n * @function port\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `port`\r\n * option.\r\n */\r\n port(strictCheck) {\r\n return v.nonNegativeNum(strictCheck);\r\n },\r\n\r\n /**\r\n * The `uploadLimit` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `positiveNum` validator.\r\n *\r\n * @function uploadLimit\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `uploadLimit`\r\n * option.\r\n */\r\n uploadLimit(strictCheck) {\r\n return v.positiveNum(strictCheck);\r\n },\r\n\r\n /**\r\n * The `serverBenchmarking` validator that returns a Zod schema with\r\n * an optional stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `boolean` validator.\r\n *\r\n * @function serverBenchmarking\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating\r\n * the `serverBenchmarking` option.\r\n */\r\n serverBenchmarking(strictCheck) {\r\n return v.boolean(strictCheck);\r\n },\r\n\r\n /**\r\n * The `proxyHost` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `string` validator.\r\n *\r\n * @function proxyHost\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `proxyHost`\r\n * option.\r\n */\r\n proxyHost(strictCheck) {\r\n return v.string(strictCheck);\r\n },\r\n\r\n /**\r\n * The `proxyPort` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as a nullable `nonNegativeNum`\r\n * validator.\r\n *\r\n * @function proxyPort\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `proxyPort`\r\n * option.\r\n */\r\n proxyPort(strictCheck) {\r\n return v.nonNegativeNum(strictCheck).nullable();\r\n },\r\n\r\n /**\r\n * The `proxyTimeout` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `nonNegativeNum`\r\n * validator.\r\n *\r\n * @function proxyTimeout\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating\r\n * the `proxyTimeout` option.\r\n */\r\n proxyTimeout(strictCheck) {\r\n return v.nonNegativeNum(strictCheck);\r\n },\r\n\r\n /**\r\n * The `enableRateLimiting` validator that returns a Zod schema with\r\n * an optional stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `boolean` validator.\r\n *\r\n * @function enableRateLimiting\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating\r\n * the `enableRateLimiting` option.\r\n */\r\n enableRateLimiting(strictCheck) {\r\n return v.boolean(strictCheck);\r\n },\r\n\r\n /**\r\n * The `maxRequests` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `nonNegativeNum`\r\n * validator.\r\n *\r\n * @function maxRequests\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `maxRequests`\r\n * option.\r\n */\r\n maxRequests(strictCheck) {\r\n return v.nonNegativeNum(strictCheck);\r\n },\r\n\r\n /**\r\n * The `window` validator that returns a Zod schema with an optional stricter\r\n * check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `nonNegativeNum`\r\n * validator.\r\n *\r\n * @function window\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `window`\r\n * option.\r\n */\r\n window(strictCheck) {\r\n return v.nonNegativeNum(strictCheck);\r\n },\r\n\r\n /**\r\n * The `delay` validator that returns a Zod schema with an optional stricter\r\n * check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `nonNegativeNum`\r\n * validator.\r\n *\r\n * @function delay\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `delay`\r\n * option.\r\n */\r\n delay(strictCheck) {\r\n return v.nonNegativeNum(strictCheck);\r\n },\r\n\r\n /**\r\n * The `trustProxy` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `boolean` validator.\r\n *\r\n * @function trustProxy\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `trustProxy`\r\n * option.\r\n */\r\n trustProxy(strictCheck) {\r\n return v.boolean(strictCheck);\r\n },\r\n\r\n /**\r\n * The `skipKey` validator that returns a Zod schema with an optional stricter\r\n * check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `string` validator.\r\n *\r\n * @function skipKey\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `skipKey`\r\n * option.\r\n */\r\n skipKey(strictCheck) {\r\n return v.string(strictCheck);\r\n },\r\n\r\n /**\r\n * The `skipToken` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `string` validator.\r\n *\r\n * @function skipToken\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `skipToken`\r\n * option.\r\n */\r\n skipToken(strictCheck) {\r\n return v.string(strictCheck);\r\n },\r\n\r\n /**\r\n * The `enableSsl` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `boolean` validator.\r\n *\r\n * @function enableSsl\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `enableSsl`\r\n * option.\r\n */\r\n enableSsl(strictCheck) {\r\n return v.boolean(strictCheck);\r\n },\r\n\r\n /**\r\n * The `sslForce` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `boolean` validator.\r\n *\r\n * @function sslForce\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `sslForce`\r\n * option.\r\n */\r\n sslForce(strictCheck) {\r\n return v.boolean(strictCheck);\r\n },\r\n\r\n /**\r\n * The `sslPort` validator that returns a Zod schema with an optional stricter\r\n * check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `nonNegativeNum`\r\n * validator.\r\n *\r\n * @function sslPort\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `sslPort`\r\n * option.\r\n */\r\n sslPort(strictCheck) {\r\n return v.nonNegativeNum(strictCheck);\r\n },\r\n\r\n /**\r\n * The `sslCertPath` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `string` validator.\r\n *\r\n * @function sslCertPath\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `sslCertPath`\r\n * option.\r\n */\r\n sslCertPath(strictCheck) {\r\n return v.string(strictCheck);\r\n },\r\n\r\n /**\r\n * The `minWorkers` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `positiveNum` validator.\r\n *\r\n * @function minWorkers\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `minWorkers`\r\n * option.\r\n */\r\n minWorkers(strictCheck) {\r\n return v.positiveNum(strictCheck);\r\n },\r\n\r\n /**\r\n * The `maxWorkers` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `positiveNum` validator.\r\n *\r\n * @function maxWorkers\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `maxWorkers`\r\n * option.\r\n */\r\n maxWorkers(strictCheck) {\r\n return v.positiveNum(strictCheck);\r\n },\r\n\r\n /**\r\n * The `workLimit` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `positiveNum` validator.\r\n *\r\n * @function workLimit\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `workLimit`\r\n * option.\r\n */\r\n workLimit(strictCheck) {\r\n return v.positiveNum(strictCheck);\r\n },\r\n\r\n /**\r\n * The `acquireTimeout` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `nonNegativeNum`\r\n * validator.\r\n *\r\n * @function acquireTimeout\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating\r\n * the `acquireTimeout` option.\r\n */\r\n acquireTimeout(strictCheck) {\r\n return v.nonNegativeNum(strictCheck);\r\n },\r\n\r\n /**\r\n * The `createTimeout` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `nonNegativeNum`\r\n * validator.\r\n *\r\n * @function createTimeout\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating\r\n * the `createTimeout` option.\r\n */\r\n createTimeout(strictCheck) {\r\n return v.nonNegativeNum(strictCheck);\r\n },\r\n\r\n /**\r\n * The `destroyTimeout` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `nonNegativeNum`\r\n * validator.\r\n *\r\n * @function destroyTimeout\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating\r\n * the `destroyTimeout` option.\r\n */\r\n destroyTimeout(strictCheck) {\r\n return v.nonNegativeNum(strictCheck);\r\n },\r\n\r\n /**\r\n * The `idleTimeout` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `nonNegativeNum`\r\n * validator.\r\n *\r\n * @function idleTimeout\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating\r\n * the `idleTimeout` option.\r\n */\r\n idleTimeout(strictCheck) {\r\n return v.nonNegativeNum(strictCheck);\r\n },\r\n\r\n /**\r\n * The `createRetryInterval` validator that returns a Zod schema with\r\n * an optional stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `nonNegativeNum`\r\n * validator.\r\n *\r\n * @function createRetryInterval\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating\r\n * the `createRetryInterval` option.\r\n */\r\n createRetryInterval(strictCheck) {\r\n return v.nonNegativeNum(strictCheck);\r\n },\r\n\r\n /**\r\n * The `reaperInterval` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `nonNegativeNum`\r\n * validator.\r\n *\r\n * @function reaperInterval\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating\r\n * the `reaperInterval` option.\r\n */\r\n reaperInterval(strictCheck) {\r\n return v.nonNegativeNum(strictCheck);\r\n },\r\n\r\n /**\r\n * The `poolBenchmarking` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `boolean` validator.\r\n *\r\n * @function poolBenchmarking\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating\r\n * the `poolBenchmarking` option.\r\n */\r\n poolBenchmarking(strictCheck) {\r\n return v.boolean(strictCheck);\r\n },\r\n\r\n /**\r\n * The `resourcesInterval` validator that returns a Zod schema with\r\n * an optional stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `nonNegativeNum`\r\n * validator.\r\n *\r\n * @function resourcesInterval\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating\r\n * the `resourcesInterval` option.\r\n */\r\n resourcesInterval(strictCheck) {\r\n return v.nonNegativeNum(strictCheck);\r\n },\r\n\r\n /**\r\n * The `logLevel` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures that:\r\n *\r\n * - When `strictCheck` is true, the schema will accept integer number values\r\n * that are between 0 and 5 (inclusive).\r\n *\r\n * - When `strictCheck` is false, the schema will accept integer number values\r\n * and stringified integer number values that are between 1 and 5 (inclusive),\r\n * null, 'undefined', 'null', and '' which will be transformed to null.\r\n *\r\n * @function logLevel\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `logLevel`\r\n * option.\r\n */\r\n logLevel(strictCheck) {\r\n return strictCheck\r\n ? z.number().int().gte(0).lte(5)\r\n : z\r\n .union([\r\n z\r\n .string()\r\n .trim()\r\n .refine(\r\n (value) =>\r\n (!isNaN(Number(value)) &&\r\n value !== true &&\r\n !value.startsWith('[') &&\r\n Number.isInteger(Number(value)) &&\r\n Number(value) >= 0 &&\r\n Number(value) <= 5) ||\r\n ['undefined', 'null', ''].includes(value),\r\n {\r\n params: {\r\n errorMessage: 'The value must be within a 0 and 5 range'\r\n }\r\n }\r\n )\r\n .transform((value) =>\r\n !['undefined', 'null', ''].includes(value)\r\n ? Number(value)\r\n : null\r\n ),\r\n z.number().int().gte(0).lte(5)\r\n ])\r\n .nullable();\r\n },\r\n\r\n /**\r\n * The `logFile` validator that returns a Zod schema with an optional stricter\r\n * check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `string` validator.\r\n * Additionally, it must be a string that ends with '.log'.\r\n *\r\n * @function logFile\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `logFile`\r\n * option.\r\n */\r\n logFile(strictCheck) {\r\n return v\r\n .string(strictCheck)\r\n .refine(\r\n (value) =>\r\n value === null || (value.length >= 5 && value.endsWith('.log')),\r\n {\r\n params: {\r\n errorMessage: 'The value must be a string that ends with .log'\r\n }\r\n }\r\n );\r\n },\r\n\r\n /**\r\n * The `logDest` validator that returns a Zod schema with an optional stricter\r\n * check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `string` validator.\r\n *\r\n * @function logDest\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `logDest`\r\n * option.\r\n */\r\n logDest(strictCheck) {\r\n return v.string(strictCheck);\r\n },\r\n\r\n /**\r\n * The `logToConsole` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `boolean` validator.\r\n *\r\n * @function logToConsole\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating\r\n * the `logToConsole` option.\r\n */\r\n logToConsole(strictCheck) {\r\n return v.boolean(strictCheck);\r\n },\r\n\r\n /**\r\n * The `logToFile` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `boolean` validator.\r\n *\r\n * @function logToFile\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `logToFile`\r\n * option.\r\n */\r\n logToFile(strictCheck) {\r\n return v.boolean(strictCheck);\r\n },\r\n\r\n /**\r\n * The `enableUi` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `boolean` validator.\r\n *\r\n * @function enableUi\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `enableUi`\r\n * option.\r\n */\r\n enableUi(strictCheck) {\r\n return v.boolean(strictCheck);\r\n },\r\n\r\n /**\r\n * The `uiRoute` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `startsWith` validator.\r\n *\r\n * @function uiRoute\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `uiRoute`\r\n * option.\r\n */\r\n uiRoute(strictCheck) {\r\n return v.startsWith(['/'], strictCheck);\r\n },\r\n\r\n /**\r\n * The `nodeEnv` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `enum` validator.\r\n *\r\n * @function nodeEnv\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `nodeEnv`\r\n * option.\r\n */\r\n nodeEnv(strictCheck) {\r\n return v.enum(['development', 'production', 'test'], strictCheck);\r\n },\r\n\r\n /**\r\n * The `listenToProcessExits` validator that returns a Zod schema with\r\n * an optional stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `boolean` validator.\r\n *\r\n * @function listenToProcessExits\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating\r\n * the `listenToProcessExits` option.\r\n */\r\n listenToProcessExits(strictCheck) {\r\n return v.boolean(strictCheck);\r\n },\r\n\r\n /**\r\n * The `noLogo` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `boolean` validator.\r\n *\r\n * @function noLogo\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `noLogo`\r\n * option.\r\n */\r\n noLogo(strictCheck) {\r\n return v.boolean(strictCheck);\r\n },\r\n\r\n /**\r\n * The `hardResetPage` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `boolean` validator.\r\n *\r\n * @function hardResetPage\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating\r\n * the `hardResetPage` option.\r\n */\r\n hardResetPage(strictCheck) {\r\n return v.boolean(strictCheck);\r\n },\r\n\r\n /**\r\n * The `browserShellMode` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `boolean` validator.\r\n *\r\n * @function browserShellMode\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating\r\n * the `browserShellMode` option.\r\n */\r\n browserShellMode(strictCheck) {\r\n return v.boolean(strictCheck);\r\n },\r\n\r\n /**\r\n * The `validation` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `boolean` validator.\r\n *\r\n * @function validation\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `validation`\r\n * option.\r\n */\r\n validation(strictCheck) {\r\n return v.boolean(strictCheck);\r\n },\r\n\r\n /**\r\n * The `enableDebug` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `boolean` validator.\r\n *\r\n * @function enableDebug\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `enableDebug`\r\n * option.\r\n */\r\n enableDebug(strictCheck) {\r\n return v.boolean(strictCheck);\r\n },\r\n\r\n /**\r\n * The `headless` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `boolean` validator.\r\n *\r\n * @function headless\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `headless`\r\n * option.\r\n */\r\n headless(strictCheck) {\r\n return v.boolean(strictCheck);\r\n },\r\n\r\n /**\r\n * The `devtools` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `boolean` validator.\r\n *\r\n * @function devtools\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `devtools`\r\n * option.\r\n */\r\n devtools(strictCheck) {\r\n return v.boolean(strictCheck);\r\n },\r\n\r\n /**\r\n * The `listenToConsole` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `boolean` validator.\r\n *\r\n * @function listenToConsole\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating\r\n * the `listenToConsole` option.\r\n */\r\n listenToConsole(strictCheck) {\r\n return v.boolean(strictCheck);\r\n },\r\n\r\n /**\r\n * The `dumpio` validator that returns a Zod schema with an optional stricter\r\n * check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `boolean` validator.\r\n *\r\n * @function dumpio\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `dumpio`\r\n * option.\r\n */\r\n dumpio(strictCheck) {\r\n return v.boolean(strictCheck);\r\n },\r\n\r\n /**\r\n * The `slowMo` validator that returns a Zod schema with an optional stricter\r\n * check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `nonNegativeNum`\r\n * validator.\r\n *\r\n * @function slowMo\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `slowMo`\r\n * option.\r\n */\r\n slowMo(strictCheck) {\r\n return v.nonNegativeNum(strictCheck);\r\n },\r\n\r\n /**\r\n * The `debuggingPort` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `nonNegativeNum`\r\n * validator.\r\n *\r\n * @function debuggingPort\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating\r\n * the `debuggingPort` option.\r\n */\r\n debuggingPort(strictCheck) {\r\n return v.nonNegativeNum(strictCheck);\r\n },\r\n\r\n /**\r\n * The `requestId` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `string` validator.\r\n * Additionally, it must be a stringified UUID or can be null.\r\n *\r\n * @function requestId\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `requestId`\r\n * option.\r\n */\r\n requestId() {\r\n return z\r\n .string()\r\n .uuid({ message: 'The value must be a stringified UUID' })\r\n .nullable();\r\n }\r\n};\r\n\r\n// Schema for the puppeteer section of options\r\nconst PuppeteerSchema = (strictCheck) =>\r\n z\r\n .object({\r\n args: validators.args(strictCheck)\r\n })\r\n .partial();\r\n\r\n// Schema for the highcharts section of options\r\nconst HighchartsSchema = (strictCheck) =>\r\n z\r\n .object({\r\n version: validators.version(strictCheck),\r\n cdnUrl: validators.cdnUrl(strictCheck),\r\n forceFetch: validators.forceFetch(strictCheck),\r\n cachePath: validators.cachePath(strictCheck),\r\n coreScripts: validators.coreScripts(strictCheck),\r\n moduleScripts: validators.moduleScripts(strictCheck),\r\n indicatorScripts: validators.indicatorScripts(strictCheck),\r\n customScripts: validators.customScripts(strictCheck)\r\n })\r\n .partial();\r\n\r\n// Schema for the export section of options\r\nconst ExportSchema = (strictCheck) =>\r\n z\r\n .object({\r\n infile: validators.infile(strictCheck),\r\n instr: validators.instr(),\r\n options: validators.options(),\r\n svg: validators.svg(),\r\n outfile: validators.outfile(strictCheck),\r\n type: validators.type(strictCheck),\r\n constr: validators.constr(strictCheck),\r\n b64: validators.b64(strictCheck),\r\n noDownload: validators.noDownload(strictCheck),\r\n defaultHeight: validators.defaultHeight(strictCheck),\r\n defaultWidth: validators.defaultWidth(strictCheck),\r\n defaultScale: validators.defaultScale(strictCheck),\r\n height: validators.height(strictCheck),\r\n width: validators.width(strictCheck),\r\n scale: validators.scale(strictCheck),\r\n globalOptions: validators.globalOptions(),\r\n themeOptions: validators.themeOptions(),\r\n batch: validators.batch(false),\r\n rasterizationTimeout: validators.rasterizationTimeout(strictCheck)\r\n })\r\n .partial();\r\n\r\n// Schema for the customLogic section of options\r\nconst CustomLogicSchema = (strictCheck) =>\r\n z\r\n .object({\r\n allowCodeExecution: validators.allowCodeExecution(strictCheck),\r\n allowFileResources: validators.allowFileResources(strictCheck),\r\n customCode: validators.customCode(false),\r\n callback: validators.callback(false),\r\n resources: validators.resources(strictCheck),\r\n loadConfig: validators.loadConfig(false),\r\n createConfig: validators.createConfig(false)\r\n })\r\n .partial();\r\n\r\n// Schema for the server.proxy section of options\r\nconst ProxySchema = (strictCheck) =>\r\n z\r\n .object({\r\n host: validators.proxyHost(false),\r\n port: validators.proxyPort(strictCheck),\r\n timeout: validators.proxyTimeout(strictCheck)\r\n })\r\n .partial();\r\n\r\n// Schema for the server.rateLimiting section of options\r\nconst RateLimitingSchema = (strictCheck) =>\r\n z\r\n .object({\r\n enable: validators.enableRateLimiting(strictCheck),\r\n maxRequests: validators.maxRequests(strictCheck),\r\n window: validators.window(strictCheck),\r\n delay: validators.delay(strictCheck),\r\n trustProxy: validators.trustProxy(strictCheck),\r\n skipKey: validators.skipKey(false),\r\n skipToken: validators.skipToken(false)\r\n })\r\n .partial();\r\n\r\n// Schema for the server.ssl section of options\r\nconst SslSchema = (strictCheck) =>\r\n z\r\n .object({\r\n enable: validators.enableSsl(strictCheck),\r\n force: validators.sslForce(strictCheck),\r\n port: validators.sslPort(strictCheck),\r\n certPath: validators.sslCertPath(false)\r\n })\r\n .partial();\r\n\r\n// Schema for the server section of options\r\nconst ServerSchema = (strictCheck) =>\r\n z.object({\r\n enable: validators.enableServer(strictCheck).optional(),\r\n host: validators.host(strictCheck).optional(),\r\n port: validators.port(strictCheck).optional(),\r\n uploadLimit: validators.uploadLimit(strictCheck).optional(),\r\n benchmarking: validators.serverBenchmarking(strictCheck).optional(),\r\n proxy: ProxySchema(strictCheck).optional(),\r\n rateLimiting: RateLimitingSchema(strictCheck).optional(),\r\n ssl: SslSchema(strictCheck).optional()\r\n });\r\n\r\n// Schema for the pool section of options\r\nconst PoolSchema = (strictCheck) =>\r\n z\r\n .object({\r\n minWorkers: validators.minWorkers(strictCheck),\r\n maxWorkers: validators.maxWorkers(strictCheck),\r\n workLimit: validators.workLimit(strictCheck),\r\n acquireTimeout: validators.acquireTimeout(strictCheck),\r\n createTimeout: validators.createTimeout(strictCheck),\r\n destroyTimeout: validators.destroyTimeout(strictCheck),\r\n idleTimeout: validators.idleTimeout(strictCheck),\r\n createRetryInterval: validators.createRetryInterval(strictCheck),\r\n reaperInterval: validators.reaperInterval(strictCheck),\r\n benchmarking: validators.poolBenchmarking(strictCheck)\r\n })\r\n .partial();\r\n\r\n// Schema for the logging section of options\r\nconst LoggingSchema = (strictCheck) =>\r\n z\r\n .object({\r\n level: validators.logLevel(strictCheck),\r\n file: validators.logFile(strictCheck),\r\n dest: validators.logDest(strictCheck),\r\n toConsole: validators.logToConsole(strictCheck),\r\n toFile: validators.logToFile(strictCheck)\r\n })\r\n .partial();\r\n\r\n// Schema for the ui section of options\r\nconst UiSchema = (strictCheck) =>\r\n z\r\n .object({\r\n enable: validators.enableUi(strictCheck),\r\n route: validators.uiRoute(strictCheck)\r\n })\r\n .partial();\r\n\r\n// Schema for the other section of options\r\nconst OtherSchema = (strictCheck) =>\r\n z\r\n .object({\r\n nodeEnv: validators.nodeEnv(strictCheck),\r\n listenToProcessExits: validators.listenToProcessExits(strictCheck),\r\n noLogo: validators.noLogo(strictCheck),\r\n hardResetPage: validators.hardResetPage(strictCheck),\r\n browserShellMode: validators.browserShellMode(strictCheck),\r\n validation: validators.validation(strictCheck)\r\n })\r\n .partial();\r\n\r\n// Schema for the debug section of options\r\nconst DebugSchema = (strictCheck) =>\r\n z\r\n .object({\r\n enable: validators.enableDebug(strictCheck),\r\n headless: validators.headless(strictCheck),\r\n devtools: validators.devtools(strictCheck),\r\n listenToConsole: validators.listenToConsole(strictCheck),\r\n dumpio: validators.dumpio(strictCheck),\r\n slowMo: validators.slowMo(strictCheck),\r\n debuggingPort: validators.debuggingPort(strictCheck)\r\n })\r\n .partial();\r\n\r\n// Strict schema for the config\r\nexport const StrictConfigSchema = z.object({\r\n requestId: validators.requestId(),\r\n puppeteer: PuppeteerSchema(true),\r\n highcharts: HighchartsSchema(true),\r\n export: ExportSchema(true),\r\n customLogic: CustomLogicSchema(true),\r\n server: ServerSchema(true),\r\n pool: PoolSchema(true),\r\n logging: LoggingSchema(true),\r\n ui: UiSchema(true),\r\n other: OtherSchema(true),\r\n debug: DebugSchema(true)\r\n});\r\n\r\n// Loose schema for the config\r\nexport const LooseConfigSchema = z.object({\r\n requestId: validators.requestId(),\r\n puppeteer: PuppeteerSchema(false),\r\n highcharts: HighchartsSchema(false),\r\n export: ExportSchema(false),\r\n customLogic: CustomLogicSchema(false),\r\n server: ServerSchema(false),\r\n pool: PoolSchema(false),\r\n logging: LoggingSchema(false),\r\n ui: UiSchema(false),\r\n other: OtherSchema(false),\r\n debug: DebugSchema(false)\r\n});\r\n\r\n// Schema for the environment variables config\r\nexport const EnvSchema = z.object({\r\n // puppeteer\r\n PUPPETEER_ARGS: validators.args(false),\r\n\r\n // highcharts\r\n HIGHCHARTS_VERSION: validators.version(false),\r\n HIGHCHARTS_CDN_URL: validators.cdnUrl(false),\r\n HIGHCHARTS_FORCE_FETCH: validators.forceFetch(false),\r\n HIGHCHARTS_CACHE_PATH: validators.cachePath(false),\r\n HIGHCHARTS_ADMIN_TOKEN: validators.adminToken(false),\r\n HIGHCHARTS_CORE_SCRIPTS: validators.coreScripts(false),\r\n HIGHCHARTS_MODULE_SCRIPTS: validators.moduleScripts(false),\r\n HIGHCHARTS_INDICATOR_SCRIPTS: validators.indicatorScripts(false),\r\n HIGHCHARTS_CUSTOM_SCRIPTS: validators.customScripts(false),\r\n\r\n // export\r\n EXPORT_INFILE: validators.infile(false),\r\n EXPORT_INSTR: validators.instr(),\r\n EXPORT_OPTIONS: validators.options(),\r\n EXPORT_SVG: validators.svg(),\r\n EXPORT_BATCH: validators.batch(false),\r\n EXPORT_OUTFILE: validators.outfile(false),\r\n EXPORT_TYPE: validators.type(false),\r\n EXPORT_CONSTR: validators.constr(false),\r\n EXPORT_B64: validators.b64(false),\r\n EXPORT_NO_DOWNLOAD: validators.noDownload(false),\r\n EXPORT_HEIGHT: validators.height(false),\r\n EXPORT_WIDTH: validators.width(false),\r\n EXPORT_SCALE: validators.scale(false),\r\n EXPORT_DEFAULT_HEIGHT: validators.defaultHeight(false),\r\n EXPORT_DEFAULT_WIDTH: validators.defaultWidth(false),\r\n EXPORT_DEFAULT_SCALE: validators.defaultScale(false),\r\n EXPORT_GLOBAL_OPTIONS: validators.globalOptions(),\r\n EXPORT_THEME_OPTIONS: validators.themeOptions(),\r\n EXPORT_RASTERIZATION_TIMEOUT: validators.rasterizationTimeout(false),\r\n\r\n // custom\r\n CUSTOM_LOGIC_ALLOW_CODE_EXECUTION: validators.allowCodeExecution(false),\r\n CUSTOM_LOGIC_ALLOW_FILE_RESOURCES: validators.allowFileResources(false),\r\n CUSTOM_LOGIC_CUSTOM_CODE: validators.customCode(false),\r\n CUSTOM_LOGIC_CALLBACK: validators.callback(false),\r\n CUSTOM_LOGIC_RESOURCES: validators.resources(false),\r\n CUSTOM_LOGIC_LOAD_CONFIG: validators.loadConfig(false),\r\n CUSTOM_LOGIC_CREATE_CONFIG: validators.createConfig(false),\r\n\r\n // server\r\n SERVER_ENABLE: validators.enableServer(false),\r\n SERVER_HOST: validators.host(false),\r\n SERVER_PORT: validators.port(false),\r\n SERVER_UPLOAD_LIMIT: validators.uploadLimit(false),\r\n SERVER_BENCHMARKING: validators.serverBenchmarking(false),\r\n\r\n // server proxy\r\n SERVER_PROXY_HOST: validators.proxyHost(false),\r\n SERVER_PROXY_PORT: validators.proxyPort(false),\r\n SERVER_PROXY_TIMEOUT: validators.proxyTimeout(false),\r\n\r\n // server rate limiting\r\n SERVER_RATE_LIMITING_ENABLE: validators.enableRateLimiting(false),\r\n SERVER_RATE_LIMITING_MAX_REQUESTS: validators.maxRequests(false),\r\n SERVER_RATE_LIMITING_WINDOW: validators.window(false),\r\n SERVER_RATE_LIMITING_DELAY: validators.delay(false),\r\n SERVER_RATE_LIMITING_TRUST_PROXY: validators.trustProxy(false),\r\n SERVER_RATE_LIMITING_SKIP_KEY: validators.skipKey(false),\r\n SERVER_RATE_LIMITING_SKIP_TOKEN: validators.skipToken(false),\r\n\r\n // server ssl\r\n SERVER_SSL_ENABLE: validators.enableSsl(false),\r\n SERVER_SSL_FORCE: validators.sslForce(false),\r\n SERVER_SSL_PORT: validators.sslPort(false),\r\n SERVER_SSL_CERT_PATH: validators.sslCertPath(false),\r\n\r\n // pool\r\n POOL_MIN_WORKERS: validators.minWorkers(false),\r\n POOL_MAX_WORKERS: validators.maxWorkers(false),\r\n POOL_WORK_LIMIT: validators.workLimit(false),\r\n POOL_ACQUIRE_TIMEOUT: validators.acquireTimeout(false),\r\n POOL_CREATE_TIMEOUT: validators.createTimeout(false),\r\n POOL_DESTROY_TIMEOUT: validators.destroyTimeout(false),\r\n POOL_IDLE_TIMEOUT: validators.idleTimeout(false),\r\n POOL_CREATE_RETRY_INTERVAL: validators.createRetryInterval(false),\r\n POOL_REAPER_INTERVAL: validators.reaperInterval(false),\r\n POOL_BENCHMARKING: validators.poolBenchmarking(false),\r\n\r\n // logging\r\n LOGGING_LEVEL: validators.logLevel(false),\r\n LOGGING_FILE: validators.logFile(false),\r\n LOGGING_DEST: validators.logDest(false),\r\n LOGGING_TO_CONSOLE: validators.logToConsole(false),\r\n LOGGING_TO_FILE: validators.logToFile(false),\r\n\r\n // ui\r\n UI_ENABLE: validators.enableUi(false),\r\n UI_ROUTE: validators.uiRoute(false),\r\n\r\n // other\r\n OTHER_NODE_ENV: validators.nodeEnv(false),\r\n OTHER_LISTEN_TO_PROCESS_EXITS: validators.listenToProcessExits(false),\r\n OTHER_NO_LOGO: validators.noLogo(false),\r\n OTHER_HARD_RESET_PAGE: validators.hardResetPage(false),\r\n OTHER_BROWSER_SHELL_MODE: validators.browserShellMode(false),\r\n OTHER_VALIDATION: validators.validation(false),\r\n\r\n // debugger\r\n DEBUG_ENABLE: validators.enableDebug(false),\r\n DEBUG_HEADLESS: validators.headless(false),\r\n DEBUG_DEVTOOLS: validators.devtools(false),\r\n DEBUG_LISTEN_TO_CONSOLE: validators.listenToConsole(false),\r\n DEBUG_DUMPIO: validators.dumpio(false),\r\n DEBUG_SLOW_MO: validators.slowMo(false),\r\n DEBUG_DEBUGGING_PORT: validators.debuggingPort(false)\r\n});\r\n\r\n/**\r\n * Validates the environment variables options using the EnvSchema.\r\n *\r\n * @param {Object} process.env - The configuration options from environment\r\n * variables file to validate.\r\n *\r\n * @returns {Object} The parsed and validated environment variables.\r\n */\r\nexport const envs = EnvSchema.partial().parse(process.env);\r\n\r\n/**\r\n * Validates the configuration options using the `StrictConfigSchema`.\r\n *\r\n * @function strictValidate\r\n *\r\n * @param {Object} configOptions - The configuration options to validate.\r\n *\r\n * @returns {Object} The parsed and validated configuration options.\r\n */\r\nexport function strictValidate(configOptions) {\r\n return StrictConfigSchema.partial().parse(configOptions);\r\n}\r\n\r\n/**\r\n * Validates the configuration options using the `LooseConfigSchema`.\r\n *\r\n * @function looseValidate\r\n *\r\n * @param {Object} configOptions - The configuration options to validate.\r\n *\r\n * @returns {Object} The parsed and validated configuration options.\r\n */\r\nexport function looseValidate(configOptions) {\r\n return LooseConfigSchema.partial().parse(configOptions);\r\n}\r\n\r\n/**\r\n * Custom error mapping function for Zod schema validation.\r\n *\r\n * This function customizes the error messages produced by Zod schema\r\n * validation, providing more specific and user-friendly feedback based on the\r\n * issue type and context.\r\n *\r\n * The function modifies the error messages as follows:\r\n *\r\n * - For missing required values (undefined), it returns a message indicating\r\n * that no value was provided for the specific property.\r\n *\r\n * - For custom validation errors, if a custom error message is provided in the\r\n * issue parameters, it includes this message along with the invalid data\r\n * received.\r\n *\r\n * - For all other errors, it appends property-specific information to the\r\n * default error message provided by Zod.\r\n *\r\n * @function _customErrorMap\r\n *\r\n * @param {z.ZodIssue} issue - The issue object representing the validation\r\n * error.\r\n * @param {Object} context - The context object providing additional information\r\n * about the validation error.\r\n *\r\n * @returns {Object} An object containing the customized error message.\r\n */\r\nfunction _customErrorMap(issue, context) {\r\n // Get the chain of properties which error directly refers to\r\n const propertyName = issue.path.join('.');\r\n\r\n // Create the first part of the message about the property information\r\n const propertyInfo = `Invalid value for the ${propertyName}`;\r\n\r\n // Modified message for the invalid type\r\n if (issue.code === z.ZodIssueCode.invalid_type) {\r\n // Modified message for the required values\r\n if (issue.received === z.ZodParsedType.undefined) {\r\n return {\r\n message: `${propertyInfo} - No value was provided.`\r\n };\r\n }\r\n\r\n // Modified message for the specific invalid type when values exist\r\n return {\r\n message: `${propertyInfo} - Invalid type. ${context.defaultError}.`\r\n };\r\n }\r\n\r\n // Modified message for the custom validation\r\n if (issue.code === z.ZodIssueCode.custom) {\r\n // If the custom message for error exist, include it\r\n if (issue.params?.errorMessage) {\r\n return {\r\n message: `${propertyInfo} - ${issue.params?.errorMessage}, received '${context.data}'.`\r\n };\r\n }\r\n }\r\n\r\n // Modified message for the invalid union error\r\n if (issue.code === z.ZodIssueCode.invalid_union) {\r\n // Create the first part of the message about the multiple errors\r\n let message = `Multiple errors occurred for the ${propertyName}:\\n`;\r\n\r\n // Cycle through all errors and create a correct message\r\n issue.unionErrors.forEach((value) => {\r\n const index = value.issues[0].message.indexOf('-');\r\n message +=\r\n index !== -1\r\n ? `${value.issues[0].message}\\n`.substring(index)\r\n : `${value.issues[0].message}\\n`;\r\n });\r\n\r\n // Return the final message for the invalid union error\r\n return {\r\n message\r\n };\r\n }\r\n\r\n // Return the default error message, extended by the info about the property\r\n return {\r\n message: `${propertyInfo} - ${context.defaultError}.`\r\n };\r\n}\r\n\r\nexport default {\r\n validators,\r\n StrictConfigSchema,\r\n LooseConfigSchema,\r\n EnvSchema,\r\n envs,\r\n strictValidate,\r\n looseValidate\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * A custom error class for handling export-related errors. Extends the native\r\n * `Error` class to include additional properties like status code and stack\r\n * trace details.\r\n */\r\nclass ExportError extends Error {\r\n /**\r\n * Creates an instance of the `ExportError`.\r\n *\r\n * @param {string} message - The error message to be displayed.\r\n * @param {number} statusCode - Optional HTTP status code associated\r\n * with the error (e.g., 400, 500).\r\n */\r\n constructor(message, statusCode) {\r\n super();\r\n\r\n this.message = message;\r\n this.stackMessage = message;\r\n\r\n if (statusCode) {\r\n this.statusCode = statusCode;\r\n }\r\n }\r\n\r\n /**\r\n * Sets or updates the HTTP status code for the error.\r\n *\r\n * @param {number} statusCode - The HTTP status code to assign to the error.\r\n *\r\n * @returns {ExportError} The updated instance of the `ExportError` class.\r\n */\r\n setStatus(statusCode) {\r\n this.statusCode = statusCode;\r\n\r\n return this;\r\n }\r\n\r\n /**\r\n * Sets additional error details based on an existing error object.\r\n *\r\n * @param {Error} error - An error object containing details to populate\r\n * the `ExportError` instance.\r\n *\r\n * @returns {ExportError} The updated instance of the `ExportError` class.\r\n */\r\n setError(error) {\r\n this.error = error;\r\n\r\n if (error.name) {\r\n this.name = error.name;\r\n }\r\n\r\n if (error.statusCode) {\r\n this.statusCode = error.statusCode;\r\n }\r\n\r\n if (error.stack) {\r\n this.stackMessage = error.message;\r\n this.stack = error.stack;\r\n }\r\n\r\n return this;\r\n }\r\n}\r\n\r\nexport default ExportError;\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * @overview Manages configuration for the Highcharts Export Server by loading\r\n * and merging options from multiple sources, such as default settings,\r\n * environment variables, user-provided options, and command-line arguments.\r\n * Ensures the global options are up-to-date with the highest priority values.\r\n * Provides functions for accessing and updating configuration.\r\n */\r\n\r\nimport { readFileSync } from 'fs';\r\nimport { join } from 'path';\r\n\r\nimport { log, logWithStack, logZodIssues } from './logger.js';\r\nimport { __dirname, deepCopy, getAbsolutePath, isObject } from './utils.js';\r\nimport {\r\n envs,\r\n looseValidate,\r\n strictValidate,\r\n validators\r\n} from './validation.js';\r\n\r\nimport { defaultConfig, absoluteProps, nestedProps } from './schemas/config.js';\r\n\r\nimport ExportError from './errors/ExportError.js';\r\n\r\n// Sets the global options with initial values from the default config\r\nconst globalOptions = _initGlobalOptions(defaultConfig);\r\n\r\n// An object for the instance options, created each time the `initExport` occurs\r\nconst instanceOptions = deepCopy(globalOptions);\r\n\r\n/**\r\n * Retrieves a reference to the options object. Depending on the `getInstance`\r\n * parameter, it returns either the global options or the instance-specific\r\n * options object.\r\n *\r\n * @function getOptions\r\n *\r\n * @param {boolean} [getInstance=true] - Optional parameter that decides whether\r\n * to return the instance-specific options (when `true`) or the global options\r\n * (when `false`). The default value is `true`.\r\n *\r\n * @returns {Object} A reference to either the global options\r\n * or the instance-specific options, based on the `getInstance` parameter.\r\n */\r\nexport function getOptions(getInstance = true) {\r\n return getInstance ? instanceOptions : globalOptions;\r\n}\r\n\r\n/**\r\n * Sets the global options of the export server, keeping the principle\r\n * of the options load priority from all available sources. It accepts optional\r\n * `customOptions` object and `cliArgs` array with arguments from the CLI. These\r\n * options will be validated and applied if provided.\r\n *\r\n * The priority order of setting values is:\r\n *\r\n * 1. Options from the `lib/schemas/config.js` file (default values).\r\n * 2. Options from a custom JSON file (loaded by the `loadConfig` option).\r\n * 3. Options from the environment variables (the `.env` file).\r\n * 4. Options from the command line interface (CLI).\r\n * 5. Options from the first parameter (the `customOptions` is by default\r\n * an empty object).\r\n *\r\n * @function setGlobalOptions\r\n *\r\n * @param {Object} [customOptions={}] - Optional custom options for additional\r\n * configuration. The default value is an empty object.\r\n * @param {Array.} [cliArgs=[]] - Optional command line arguments\r\n * for additional configuration. The default value is an empty array.\r\n *\r\n * @returns {Object} The updated global options object, reflecting the merged\r\n * configuration from all available sources.\r\n */\r\nexport function setGlobalOptions(customOptions = {}, cliArgs = []) {\r\n // Object for options loaded via the `loadConfig` option\r\n let configOptions = {};\r\n\r\n // Object for options from the CLI\r\n let cliOptions = {};\r\n\r\n // Only for the CLI usage\r\n if (cliArgs && Array.isArray(cliArgs) && cliArgs.length) {\r\n try {\r\n // Validate options from the custom JSON loaded via the `loadConfig`\r\n configOptions = strictValidate(\r\n _loadConfigFile(cliArgs, globalOptions.customLogic)\r\n );\r\n } catch (error) {\r\n logZodIssues(\r\n 1,\r\n error.issues,\r\n '[validation] Custom options from the `loadConfig` option validation error'\r\n );\r\n }\r\n\r\n try {\r\n // Validate options from the CLI\r\n cliOptions = looseValidate(_pairArgumentValue(nestedProps, cliArgs));\r\n } catch (error) {\r\n logZodIssues(\r\n 1,\r\n error.issues,\r\n '[validation] CLI options validation error'\r\n );\r\n }\r\n }\r\n\r\n // Apply custom options if there are any\r\n if (\r\n customOptions &&\r\n isObject(customOptions) &&\r\n Object.keys(customOptions).length\r\n ) {\r\n try {\r\n // Validate custom options provided by the user\r\n customOptions = strictValidate(customOptions);\r\n } catch (error) {\r\n logZodIssues(\r\n 1,\r\n error.issues,\r\n '[validation] Custom options validation error'\r\n );\r\n }\r\n }\r\n\r\n // Update values of the global options with values from each source possible\r\n _updateGlobalOptions(\r\n defaultConfig,\r\n globalOptions,\r\n configOptions,\r\n cliOptions,\r\n customOptions\r\n );\r\n\r\n // Return updated global options\r\n return globalOptions;\r\n}\r\n\r\n/**\r\n * Updates the instance options with additional options. It optionally allows\r\n * to reinitialize the instance options with the values of a current global\r\n * options object.\r\n *\r\n * @param {Object} updateOptions - The update options to merge into the instance\r\n * options.\r\n * @param {boolean} [newInstance=false] - A flag to indicate whether to init\r\n * options for a new instance. If `true`, the existing instance options will\r\n * be cleared and reinitialized based on the global options.\r\n *\r\n * @returns {Object} - The updated instance options.\r\n */\r\nexport function updateOptions(updateOptions, newInstance = false) {\r\n // Check if options need to be created for a new instance\r\n if (newInstance) {\r\n // Get rid of the old instance options\r\n Object.keys(instanceOptions).forEach((key) => {\r\n delete instanceOptions[key];\r\n });\r\n\r\n // Init the new instance options based on the global options\r\n mergeOptions(instanceOptions, deepCopy(globalOptions));\r\n }\r\n\r\n // Merge additional options to the instance options\r\n mergeOptions(instanceOptions, updateOptions);\r\n\r\n // Return the reference to the instance options object\r\n return instanceOptions;\r\n}\r\n\r\n/**\r\n * Merges two sets of configuration options, considering absolute properties.\r\n *\r\n * @function mergeOptions\r\n *\r\n * @param {Object} originalOptions - Original configuration options.\r\n * @param {Object} newOptions - New configuration options to be merged.\r\n *\r\n * @returns {Object} Merged configuration options.\r\n */\r\nexport function mergeOptions(originalOptions, newOptions) {\r\n // Check if the `originalOptions` and `newOptions` are correct objects\r\n if (isObject(originalOptions) && isObject(newOptions)) {\r\n for (const [key, value] of Object.entries(newOptions)) {\r\n originalOptions[key] =\r\n isObject(value) &&\r\n !absoluteProps.includes(key) &&\r\n originalOptions[key] !== undefined\r\n ? mergeOptions(originalOptions[key], value)\r\n : value !== undefined\r\n ? value\r\n : originalOptions[key] || null;\r\n }\r\n }\r\n\r\n // Return the original (modified or not) options\r\n return originalOptions;\r\n}\r\n\r\n/**\r\n * Maps old-structured configuration options (PhantomJS) to a new format\r\n * (Puppeteer). This function converts flat, old-structured options into\r\n * a new, nested configuration format based on a predefined mapping\r\n * (`nestedProps`). The new format is used for Puppeteer, while the old format\r\n * was used for PhantomJS.\r\n *\r\n * @function mapToNewOptions\r\n *\r\n * @param {Object} oldOptions - The old, flat configuration options\r\n * to be converted.\r\n *\r\n * @returns {Object} A new object containing options structured according\r\n * to the mapping defined in `nestedProps` or an empty object if the provided\r\n * `oldOptions` is not a correct object.\r\n */\r\nexport function mapToNewOptions(oldOptions) {\r\n // An object for the new structured options\r\n const newOptions = {};\r\n\r\n // Check if provided value is a correct object\r\n if (isObject(oldOptions)) {\r\n // Iterate over each key-value pair in the old-structured options\r\n for (const [key, value] of Object.entries(oldOptions)) {\r\n // If there is a nested mapping, split it into a properties chain\r\n const propertiesChain = nestedProps[key]\r\n ? nestedProps[key].split('.')\r\n : [];\r\n\r\n // If it is the last property in the chain, assign the value, otherwise,\r\n // create or reuse the nested object\r\n propertiesChain.reduce(\r\n (obj, prop, index) =>\r\n (obj[prop] =\r\n propertiesChain.length - 1 === index ? value : obj[prop] || {}),\r\n newOptions\r\n );\r\n }\r\n } else {\r\n log(\r\n 2,\r\n '[config] No correct object with options was provided. Returning an empty array.'\r\n );\r\n }\r\n\r\n // Return the new, structured options object\r\n return newOptions;\r\n}\r\n\r\n/**\r\n * Validates a specified option using the corresponding validator from the\r\n * configuration object. Returns the original option if the validation\r\n * is disabled globally.\r\n *\r\n * @function validateOption\r\n *\r\n * @param {string} name - The name of the option to validate.\r\n * @param {any} configOption - The value of the option to validate.\r\n * @param {boolean} [strictCheck=true] - Determines if stricter validation\r\n * should be applied. The default value is `true`.\r\n *\r\n * @returns {any} The parsed and validated value of the option.\r\n */\r\nexport function validateOption(name, configOption, strictCheck = true) {\r\n // Return the original option if the validation is disabled\r\n if (!getOptions().other.validation) {\r\n return configOption;\r\n }\r\n\r\n try {\r\n // Return validated option\r\n return validators[name](strictCheck).parse(configOption);\r\n } catch (error) {\r\n // Log Zod issues\r\n logZodIssues(\r\n 1,\r\n error.issues,\r\n `[validation] The ${name} option validation error`\r\n );\r\n\r\n // Throw validation error\r\n throw new ExportError(\r\n `[validation] The ${name} option validation error`,\r\n 400\r\n );\r\n }\r\n}\r\n\r\n/**\r\n * Validates the provided configuration options for the exporting process.\r\n * Returns the original option if the validation is disabled globally.\r\n *\r\n * @function validateOptions\r\n *\r\n * @param {Object} configOptions - The configuration options to be validated.\r\n * @param {boolean} [strictCheck=true] - Determines if stricter validation\r\n * should be applied. The default value is `true`.\r\n *\r\n * @returns {Object} The parsed and validated configuration options object.\r\n */\r\nexport function validateOptions(configOptions, strictCheck = true) {\r\n // Return the original config if the validation is disabled\r\n if (!getOptions().other.validation) {\r\n return configOptions;\r\n }\r\n\r\n try {\r\n // Return validated options\r\n return strictCheck\r\n ? strictValidate(configOptions)\r\n : looseValidate(configOptions);\r\n } catch (error) {\r\n // Log Zod issues\r\n logZodIssues(1, error.issues, '[validation] Options validation error');\r\n\r\n // Throw validation error\r\n throw new ExportError('[validation] Options validation error', 400);\r\n }\r\n}\r\n\r\n/**\r\n * Validates, parses, and checks if the provided config is allowed set\r\n * of options.\r\n *\r\n * @function isAllowedConfig\r\n *\r\n * @param {unknown} config - The config to be validated and parsed as a set\r\n * of options. Must be either an object or a string.\r\n * @param {boolean} [toString=false] - Whether to return a stringified version\r\n * of the parsed config. The default value is `false`.\r\n * @param {boolean} [allowFunctions=false] - Whether to allow functions\r\n * in the parsed config. If true, functions are preserved. Otherwise, when\r\n * a function is found, null is returned. The default value is `false`.\r\n *\r\n * @returns {(Object|string|null)} Returns a parsed set of options object,\r\n * a stringified set of options object if the `toString` is true, and null\r\n * if the config is not a valid set of options or parsing fails.\r\n */\r\nexport function isAllowedConfig(\r\n config,\r\n toString = false,\r\n allowFunctions = false\r\n) {\r\n try {\r\n // Accept only objects and strings\r\n if (!isObject(config) && typeof config !== 'string') {\r\n // Return null if any other type\r\n return null;\r\n }\r\n\r\n // Get the object representation of the original config\r\n const objectConfig =\r\n typeof config === 'string'\r\n ? allowFunctions\r\n ? eval(`(${config})`)\r\n : JSON.parse(config)\r\n : config;\r\n\r\n // Preserve or remove potential functions based on the `allowFunctions` flag\r\n const stringifiedOptions = _optionsStringify(\r\n objectConfig,\r\n allowFunctions,\r\n false\r\n );\r\n\r\n // Parse the config to check if it is valid set of options\r\n const parsedOptions = allowFunctions\r\n ? JSON.parse(\r\n _optionsStringify(objectConfig, allowFunctions, true),\r\n (_, value) =>\r\n typeof value === 'string' && value.startsWith('function')\r\n ? eval(`(${value})`)\r\n : value\r\n )\r\n : JSON.parse(stringifiedOptions);\r\n\r\n // Return stringified or object options based on the `toString` flag\r\n return toString ? stringifiedOptions : parsedOptions;\r\n } catch (error) {\r\n // Return null if parsing fails\r\n return null;\r\n }\r\n}\r\n\r\n/**\r\n * Prints the Highcharts Export Server logo, version, and license information.\r\n *\r\n * @function printLicense\r\n */\r\nexport function printLicense() {\r\n // Print the logo and version information\r\n printVersion();\r\n\r\n // Print the license information\r\n console.log(\r\n 'This software requires a valid Highcharts license for commercial use.\\n'\r\n .yellow,\r\n '\\nFor a full list of CLI options, type:',\r\n '\\nhighcharts-export-server --help\\n'.green,\r\n '\\nIf you do not have a license, one can be obtained here:',\r\n '\\nhttps://shop.highsoft.com/\\n'.green,\r\n '\\nTo customize your installation, please refer to the README file at:',\r\n '\\nhttps://github.com/highcharts/node-export-server#readme\\n'.green\r\n );\r\n}\r\n\r\n/**\r\n * Prints usage information for CLI arguments, displaying available options\r\n * and their descriptions. It can list properties recursively if categories\r\n * contain nested options.\r\n *\r\n * @function printUsage\r\n */\r\nexport function printUsage() {\r\n // Display README and general usage information\r\n console.log(\r\n '\\nUsage of CLI arguments:'.bold,\r\n '\\n-----------------------',\r\n `\\nFor more detailed information, visit the README file at: ${'https://github.com/highcharts/node-export-server#readme'.green}.\\n`\r\n );\r\n\r\n // Iterate through each category in the `defaultConfig` and display usage info\r\n Object.keys(defaultConfig).forEach((category) => {\r\n console.log(`${category.toUpperCase()}`.bold.red);\r\n _cycleCategories(defaultConfig[category]);\r\n console.log('');\r\n });\r\n}\r\n\r\n/**\r\n * Prints the Highcharts Export Server logo or text with the version\r\n * information.\r\n *\r\n * @function printVersion\r\n *\r\n * @param {boolean} [noLogo=false] - If true, only prints text with the version\r\n * information, without the logo. The default value is `false`.\r\n */\r\nexport function printVersion(noLogo = false) {\r\n // Get package version either from `.env` or from `package.json`\r\n const packageVersion = JSON.parse(\r\n readFileSync(join(__dirname, 'package.json'), 'utf8')\r\n ).version;\r\n\r\n // Print text only\r\n if (noLogo) {\r\n console.log(`Highcharts Export Server v${packageVersion}`);\r\n } else {\r\n // Print the logo\r\n console.log(\r\n readFileSync(join(__dirname, 'msg', 'startup.msg'), 'utf8').toString()\r\n .bold.yellow,\r\n `v${packageVersion}\\n`.bold\r\n );\r\n }\r\n}\r\n\r\n/**\r\n * Initializes and returns global options object based on provided\r\n * configuration, setting values from nested properties recursively.\r\n *\r\n * @function _initGlobalOptions\r\n *\r\n * @param {Object} config - The configuration object to be used for initializing\r\n * options.\r\n *\r\n * @returns {Object} Initialized options object.\r\n */\r\nfunction _initGlobalOptions(config) {\r\n const options = {};\r\n\r\n // Start initializing the `options` object recursively\r\n for (const [name, item] of Object.entries(config)) {\r\n if (Object.prototype.hasOwnProperty.call(item, 'value')) {\r\n // If a value from environment variables exists, it takes precedence\r\n const envVal = envs[item.envLink];\r\n if (envVal !== undefined && envVal !== null) {\r\n options[name] = envVal;\r\n } else {\r\n options[name] = item.value;\r\n }\r\n } else {\r\n options[name] = _initGlobalOptions(item);\r\n }\r\n }\r\n\r\n // Return the created `options` object\r\n return options;\r\n}\r\n\r\n/**\r\n * Updates global options object with values from various sources, following\r\n * a specific prioritization order. The function checks for values in the order\r\n * of precedence: the `loadConfig` configuration options, environment variables,\r\n * custom options, and CLI options.\r\n *\r\n * @function _updateGlobalOptions\r\n *\r\n * @param {Object} config - The configuration object, which includes the initial\r\n * settings and metadata for each option. This object is used to determine\r\n * the structure and default values for the options.\r\n * @param {Object} options - The global options object that will be updated\r\n * with values from other sources.\r\n * @param {Object} configOpt - The configuration options object, loaded with\r\n * the `loadConfig` option, which may provide values to override defaults.\r\n * @param {Object} cliOpt - The CLI options object, which may include values\r\n * provided through command-line arguments and may override configuration\r\n * options.\r\n * @param {Object} customOpt - The custom options object, typically containing\r\n * additional and user-defined values, which has the highest precedence among\r\n * options.\r\n */\r\nfunction _updateGlobalOptions(config, options, configOpt, cliOpt, customOpt) {\r\n Object.keys(config).forEach((key) => {\r\n // Get the config entry of a specific option\r\n const entry = config[key];\r\n\r\n // Gather values for the options from every possible source, if exists\r\n const configVal = configOpt && configOpt[key];\r\n const cliVal = cliOpt && cliOpt[key];\r\n const customVal = customOpt && customOpt[key];\r\n\r\n // If the value not found, need to go deeper\r\n if (typeof entry.value === 'undefined') {\r\n _updateGlobalOptions(entry, options[key], configVal, cliVal, customVal);\r\n } else {\r\n // If a value from custom JSON options exists, it takes precedence\r\n if (configVal !== undefined && configVal !== null) {\r\n options[key] = configVal;\r\n }\r\n\r\n // If a value from environment variables exists, it takes precedence\r\n const envVal = envs[entry.envLink];\r\n if (entry.envLink in envs && envVal !== undefined && envVal !== null) {\r\n options[key] = envVal;\r\n }\r\n\r\n // If a value from CLI options exists, it takes precedence\r\n if (cliVal !== undefined && cliVal !== null) {\r\n options[key] = cliVal;\r\n }\r\n\r\n // If a value from user options exists, it takes precedence\r\n if (customVal !== undefined && customVal !== null) {\r\n options[key] = customVal;\r\n }\r\n }\r\n });\r\n}\r\n\r\n/**\r\n * Converts the provided options object to a JSON-formatted string\r\n * with the option to preserve functions. In order for a function\r\n * to be preserved, it needs to follow the format `function (...) {...}`.\r\n * Such a function can also be stringified.\r\n *\r\n * @function _optionsStringify\r\n *\r\n * @param {Object} options - The options object to be converted to a string.\r\n * @param {boolean} allowFunctions - If set to true, functions are preserved\r\n * in the output. Otherwise an error is thrown.\r\n * @param {boolean} stringifyFunctions - If set to true, functions are saved\r\n * as strings. The `allowFunctions` must be set to true as well for this to take\r\n * an effect.\r\n *\r\n * @returns {string} The JSON-formatted string representing the options.\r\n *\r\n * @throws {Error} Throws an `Error` when functions are not allowed but are\r\n * found in provided options object.\r\n */\r\nexport function _optionsStringify(options, allowFunctions, stringifyFunctions) {\r\n const replacerCallback = (_, value) => {\r\n // Trim string values\r\n if (typeof value === 'string') {\r\n value = value.trim();\r\n }\r\n\r\n // If value is a function or stringified function\r\n if (\r\n typeof value === 'function' ||\r\n (typeof value === 'string' &&\r\n value.startsWith('function') &&\r\n value.endsWith('}'))\r\n ) {\r\n // If allowFunctions is set to true, preserve functions\r\n if (allowFunctions) {\r\n // Based on the `stringifyFunctions` options, set function values\r\n return stringifyFunctions\r\n ? // As stringified functions\r\n `\"EXP_FUN${(value + '').replaceAll(/\\s+/g, ' ')}EXP_FUN\"`\r\n : // As functions\r\n `EXP_FUN${(value + '').replaceAll(/\\s+/g, ' ')}EXP_FUN`;\r\n } else {\r\n // Throw an error otherwise\r\n throw new Error();\r\n }\r\n }\r\n\r\n // In all other cases, simply return the value\r\n return value;\r\n };\r\n\r\n // Stringify options and if required, replace special functions marks\r\n return JSON.stringify(options, replacerCallback).replaceAll(\r\n stringifyFunctions ? /\\\\\"EXP_FUN|EXP_FUN\\\\\"/g : /\"EXP_FUN|EXP_FUN\"/g,\r\n ''\r\n );\r\n}\r\n\r\n/**\r\n * Loads additional configuration from a specified file provided via\r\n * the `loadConfig` option in the command-line arguments.\r\n *\r\n * @function _loadConfigFile\r\n *\r\n * @param {Array.} cliArgs - Command-line arguments to search\r\n * for the `loadConfig` option and the corresponding file path.\r\n * @param {Object} customLogicOptions - The configuration object containing\r\n * `customLogic` options.\r\n *\r\n * @returns {Object} The additional configuration loaded from the specified\r\n * file, or an empty object if the file is not found, invalid, or an error\r\n * occurs.\r\n */\r\nfunction _loadConfigFile(cliArgs, customLogicOptions) {\r\n // Check if the `loadConfig` option was used\r\n const configIndex = cliArgs.findIndex(\r\n (arg) => arg.replace(/-/g, '') === 'loadConfig'\r\n );\r\n\r\n // Get the `loadConfig` option value\r\n const configFileName = configIndex > -1 && cliArgs[configIndex + 1];\r\n\r\n // Check if the `loadConfig` is present and has a correct value\r\n if (configFileName && customLogicOptions.allowFileResources) {\r\n try {\r\n // Load an optional custom JSON config file\r\n return isAllowedConfig(\r\n readFileSync(getAbsolutePath(configFileName), 'utf8'),\r\n false,\r\n customLogicOptions.allowCodeExecution\r\n );\r\n } catch (error) {\r\n logWithStack(\r\n 2,\r\n error,\r\n `[config] Unable to load the configuration from the ${configFileName} file.`\r\n );\r\n }\r\n }\r\n\r\n // No additional options to return\r\n return {};\r\n}\r\n\r\n/**\r\n * Parses command-line arguments and pairs each argument with its corresponding\r\n * option in the configuration. The values are structured into a nested options\r\n * object, based on predefined mappings.\r\n *\r\n * @function _pairArgumentValue\r\n *\r\n * @param {Array.} nestedProps - An array of nesting level for all\r\n * options.\r\n * @param {Array.} cliArgs - An array of command-line arguments\r\n * containing options and their associated values.\r\n *\r\n * @returns {Object} An updated options object where each option from\r\n * the command-line is paired with its value, structured into nested objects\r\n * as defined.\r\n */\r\nfunction _pairArgumentValue(nestedProps, cliArgs) {\r\n // An empty object to collect and structurize data from the args\r\n const cliOptions = {};\r\n\r\n // Cycle through all CLI args and filter them\r\n for (let i = 0; i < cliArgs.length; i++) {\r\n const option = cliArgs[i].replace(/-/g, '');\r\n\r\n // Find the right place for property's value\r\n const propertiesChain = nestedProps[option]\r\n ? nestedProps[option].split('.')\r\n : [];\r\n\r\n // Create options object with values from CLI for later parsing and merging\r\n propertiesChain.reduce((obj, prop, index) => {\r\n if (propertiesChain.length - 1 === index) {\r\n const value = cliArgs[++i];\r\n if (!value) {\r\n log(\r\n 2,\r\n `[config] Missing value for the CLI '--${option}' argument. Using the default value.`\r\n );\r\n }\r\n obj[prop] = value || null;\r\n } else if (obj[prop] === undefined) {\r\n obj[prop] = {};\r\n }\r\n return obj[prop];\r\n }, cliOptions);\r\n }\r\n\r\n // Return parsed CLI options\r\n return cliOptions;\r\n}\r\n\r\n/**\r\n * Recursively traverses the options object to print the usage information\r\n * for each option category and individual option.\r\n *\r\n * @function _cycleCategories\r\n *\r\n * @param {Object} options - The options object containing CLI options. It may\r\n * include nested categories and individual options.\r\n */\r\nfunction _cycleCategories(options) {\r\n for (const [name, option] of Object.entries(options)) {\r\n // If the current entry is a category and not a leaf option, recurse into it\r\n if (!Object.prototype.hasOwnProperty.call(option, 'value')) {\r\n _cycleCategories(option);\r\n } else {\r\n // Prepare description\r\n const descName = ` --${option.cliName || name}`;\r\n\r\n // Get the value\r\n let optionValue = option.value;\r\n\r\n // Prepare value for option that is not null and is array of strings\r\n if (optionValue !== null && option.types.includes('string[]')) {\r\n optionValue =\r\n '[' + optionValue.map((item) => `'${item}'`).join(', ') + ']';\r\n }\r\n\r\n // Prepare value for option that is not null and is a string\r\n if (optionValue !== null && option.types.includes('string')) {\r\n optionValue = `'${optionValue}'`;\r\n }\r\n\r\n // Display correctly aligned messages\r\n console.log(\r\n descName.green,\r\n `${('<' + option.types.join('|') + '>').yellow}`,\r\n `${String(optionValue).bold}`.blue,\r\n `- ${option.description}.`\r\n );\r\n }\r\n }\r\n}\r\n\r\nexport default {\r\n getOptions,\r\n setGlobalOptions,\r\n updateOptions,\r\n mergeOptions,\r\n mapToNewOptions,\r\n validateOption,\r\n validateOptions,\r\n isAllowedConfig,\r\n printLicense,\r\n printUsage,\r\n printVersion\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * @overview HTTP utility module for fetching and posting data. Supports both\r\n * HTTP and HTTPS protocols, providing methods to make GET and POST requests\r\n * with customizable options. Includes protocol determination based on URL\r\n * and augments response objects with a 'text' property for easier data access.\r\n */\r\n\r\nimport http from 'http';\r\nimport https from 'https';\r\n\r\n/**\r\n * Fetches data from the specified URL using either HTTP or HTTPS protocol.\r\n *\r\n * @async\r\n * @function fetch\r\n *\r\n * @param {string} url - The URL to fetch data from.\r\n * @param {Object} [requestOptions={}] - Options for the HTTP/HTTPS request.\r\n * The default value is an empty object.\r\n *\r\n * @returns {Promise} A Promise that resolves to the HTTP/HTTPS response\r\n * object with added 'text' property or rejecting with an error.\r\n */\r\nexport async function fetch(url, requestOptions = {}) {\r\n return new Promise((resolve, reject) => {\r\n _getProtocolModule(url)\r\n .get(url, requestOptions, (response) => {\r\n let responseData = '';\r\n\r\n // A chunk of data has been received\r\n response.on('data', (chunk) => {\r\n responseData += chunk;\r\n });\r\n\r\n // The whole response has been received\r\n response.on('end', () => {\r\n if (!responseData) {\r\n reject('Nothing was fetched from the URL.');\r\n }\r\n response.text = responseData;\r\n resolve(response);\r\n });\r\n })\r\n .on('error', (error) => {\r\n reject(error);\r\n });\r\n });\r\n}\r\n\r\n/**\r\n * Sends a POST request to the specified URL with the provided JSON body using\r\n * either HTTP or HTTPS protocol.\r\n *\r\n * @async\r\n * @function post\r\n *\r\n * @param {string} url - The URL to send the POST request to.\r\n * @param {Object} [body={}] - The JSON body to include in the POST request.\r\n * The default value is an empty object.\r\n * @param {Object} [requestOptions={}] - Options for the HTTP/HTTPS request.\r\n * The default value is an empty object.\r\n *\r\n * @returns {Promise} A Promise that resolves to the HTTP/HTTPS response\r\n * object with added 'text' property or rejecting with an error.\r\n */\r\nexport async function post(url, body = {}, requestOptions = {}) {\r\n return new Promise((resolve, reject) => {\r\n const data = JSON.stringify(body);\r\n\r\n // Set default headers and merge with requestOptions\r\n const options = Object.assign(\r\n {\r\n method: 'POST',\r\n headers: {\r\n 'Content-Type': 'application/json',\r\n 'Content-Length': data.length\r\n }\r\n },\r\n requestOptions\r\n );\r\n\r\n const request = _getProtocolModule(url)\r\n .request(url, options, (response) => {\r\n let responseData = '';\r\n\r\n // A chunk of data has been received\r\n response.on('data', (chunk) => {\r\n responseData += chunk;\r\n });\r\n\r\n // The whole response has been received\r\n response.on('end', () => {\r\n try {\r\n response.text = responseData;\r\n resolve(response);\r\n } catch (error) {\r\n reject(error);\r\n }\r\n });\r\n })\r\n .on('error', (error) => {\r\n reject(error);\r\n });\r\n\r\n // Write the request body and end the request\r\n request.write(data);\r\n request.end();\r\n });\r\n}\r\n\r\n/**\r\n * Returns the HTTP or HTTPS protocol module based on the provided URL.\r\n *\r\n * @function _getProtocolModule\r\n *\r\n * @param {string} url - The URL to determine the protocol.\r\n *\r\n * @returns {Object} The HTTP or HTTPS protocol module (http or https).\r\n */\r\nfunction _getProtocolModule(url) {\r\n return url.startsWith('https') ? https : http;\r\n}\r\n\r\nexport default {\r\n fetch,\r\n post\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * @overview The cache manager is responsible for handling and managing\r\n * the Highcharts library along with its dependencies. It ensures that these\r\n * resources are stored and retrieved efficiently to optimize performance\r\n * and reduce redundant network requests. The cache is stored in the `.cache`\r\n * directory by default, which serves as a dedicated folder for keeping cached\r\n * files.\r\n */\r\n\r\nimport { existsSync, mkdirSync, readFileSync, writeFileSync } from 'fs';\r\nimport { join } from 'path';\r\n\r\nimport { HttpsProxyAgent } from 'https-proxy-agent';\r\n\r\nimport { getOptions } from './config.js';\r\nimport { fetch } from './fetch.js';\r\nimport { log } from './logger.js';\r\nimport { __dirname, getAbsolutePath } from './utils.js';\r\n\r\nimport ExportError from './errors/ExportError.js';\r\n\r\n// The initial cache template\r\nconst cache = {\r\n cdnUrl: 'https://code.highcharts.com',\r\n activeManifest: {},\r\n sources: '',\r\n hcVersion: ''\r\n};\r\n\r\n/**\r\n * Checks the cache for Highcharts dependencies, updates the cache if needed,\r\n * and loads the sources.\r\n *\r\n * @async\r\n * @function checkAndUpdateCache\r\n *\r\n * @param {Object} highchartsOptions - The configuration object containing\r\n * `highcharts` options.\r\n * @param {Object} serverProxyOptions- The configuration object containing\r\n * `server.proxy` options.\r\n */\r\nexport async function checkAndUpdateCache(\r\n highchartsOptions,\r\n serverProxyOptions\r\n) {\r\n try {\r\n let fetchedModules;\r\n\r\n // Get the cache path\r\n const cachePath = getCachePath();\r\n\r\n // Prepare paths to manifest and sources from the cache folder\r\n const manifestPath = join(cachePath, 'manifest.json');\r\n const sourcePath = join(cachePath, 'sources.js');\r\n\r\n // Create the cache destination if it doesn't exist already\r\n !existsSync(cachePath) && mkdirSync(cachePath, { recursive: true });\r\n\r\n // Fetch all the scripts either if the `manifest.json` does not exist\r\n // or if the `forceFetch` option is enabled\r\n if (!existsSync(manifestPath) || highchartsOptions.forceFetch) {\r\n log(3, '[cache] Fetching and caching Highcharts dependencies.');\r\n fetchedModules = await _updateCache(\r\n highchartsOptions,\r\n serverProxyOptions,\r\n sourcePath\r\n );\r\n } else {\r\n let requestUpdate = false;\r\n\r\n // Read the manifest JSON\r\n const manifest = JSON.parse(readFileSync(manifestPath), 'utf8');\r\n\r\n // Check if the modules is an array, if so, we rewrite it to a map to make\r\n // it easier to resolve modules.\r\n if (manifest.modules && Array.isArray(manifest.modules)) {\r\n const moduleMap = {};\r\n manifest.modules.forEach((m) => (moduleMap[m] = 1));\r\n manifest.modules = moduleMap;\r\n }\r\n\r\n // Get the actual number of scripts to be fetched\r\n const { coreScripts, moduleScripts, indicatorScripts } =\r\n highchartsOptions;\r\n const numberOfModules =\r\n coreScripts.length + moduleScripts.length + indicatorScripts.length;\r\n\r\n // Compare the loaded highcharts config with the contents in cache.\r\n // If there are changes, fetch requested modules and products,\r\n // and bake them into a giant blob. Save the blob.\r\n if (manifest.version !== highchartsOptions.version) {\r\n log(\r\n 2,\r\n '[cache] A Highcharts version mismatch in the cache, need to re-fetch.'\r\n );\r\n requestUpdate = true;\r\n } else if (\r\n Object.keys(manifest.modules || {}).length !== numberOfModules\r\n ) {\r\n log(\r\n 2,\r\n '[cache] The cache and the requested modules do not match, need to re-fetch.'\r\n );\r\n requestUpdate = true;\r\n } else {\r\n // Check each module, if anything is missing refetch everything\r\n requestUpdate = (moduleScripts || []).some((moduleName) => {\r\n if (!manifest.modules[moduleName]) {\r\n log(\r\n 2,\r\n `[cache] The ${moduleName} is missing in the cache, need to re-fetch.`\r\n );\r\n return true;\r\n }\r\n });\r\n }\r\n\r\n // Update cache if needed\r\n if (requestUpdate) {\r\n fetchedModules = await _updateCache(\r\n highchartsOptions,\r\n serverProxyOptions,\r\n sourcePath\r\n );\r\n } else {\r\n log(3, '[cache] Dependency cache is up to date, proceeding.');\r\n\r\n // Load the sources\r\n cache.sources = readFileSync(sourcePath, 'utf8');\r\n\r\n // Get current modules map\r\n fetchedModules = manifest.modules;\r\n\r\n // Extract and save version of currently used Highcharts\r\n cache.hcVersion = extractVersion(cache.sources);\r\n }\r\n }\r\n\r\n // Finally, save the new manifest, which is basically our current config\r\n // in a slightly different format\r\n await _saveConfigToManifest(highchartsOptions, fetchedModules);\r\n } catch (error) {\r\n throw new ExportError(\r\n '[cache] Could not configure cache and create or update the config manifest.',\r\n 500\r\n ).setError(error);\r\n }\r\n}\r\n\r\n/**\r\n * Gets the version of Highcharts from the cache.\r\n *\r\n * @function getHighchartsVersion\r\n *\r\n * @returns {string} The cached Highcharts version.\r\n */\r\nexport function getHighchartsVersion() {\r\n return cache.hcVersion;\r\n}\r\n\r\n/**\r\n * Updates the Highcharts version in the applied configuration and checks\r\n * the cache for the new version.\r\n *\r\n * @async\r\n * @function updateHighchartsVersion\r\n *\r\n * @param {string} newVersion - The new Highcharts version to be applied.\r\n */\r\nexport async function updateHighchartsVersion(newVersion) {\r\n // Get the reference to the global options to update to the new version\r\n const options = getOptions();\r\n\r\n // Set to the new version\r\n options.highcharts.version = newVersion;\r\n\r\n // Check if cache needs to be updated\r\n await checkAndUpdateCache(options.highcharts, options.server.proxy);\r\n}\r\n\r\n/**\r\n * Extracts Highcharts version from the cache's sources string.\r\n *\r\n * @function extractVersion\r\n *\r\n * @param {Object} cacheSources - The cache sources object.\r\n *\r\n * @returns {string} The extracted Highcharts version.\r\n */\r\nexport function extractVersion(cacheSources) {\r\n return cacheSources\r\n .substring(0, cacheSources.indexOf('*/'))\r\n .replace('/*', '')\r\n .replace('*/', '')\r\n .replace(/\\n/g, '')\r\n .trim();\r\n}\r\n\r\n/**\r\n * Extracts the Highcharts module name based on the scriptPath.\r\n *\r\n * @function extractModuleName\r\n *\r\n * @param {string} scriptPath - The path of the script from which the module\r\n * name will be extracted.\r\n *\r\n * @returns {string} The extracted module name.\r\n */\r\nexport function extractModuleName(scriptPath) {\r\n return scriptPath.replace(\r\n /(.*)\\/|(.*)modules\\/|stock\\/(.*)indicators\\/|maps\\/(.*)modules\\//gi,\r\n ''\r\n );\r\n}\r\n\r\n/**\r\n * Retrieves the current cache object.\r\n *\r\n * @function getCache\r\n *\r\n * @returns {Object} The cache object containing various cached data.\r\n */\r\nexport function getCache() {\r\n return cache;\r\n}\r\n\r\n/**\r\n * Gets the cache path for Highcharts.\r\n *\r\n * @function getCachePath\r\n *\r\n * @returns {string} The absolute path to the cache directory for Highcharts.\r\n */\r\nexport function getCachePath() {\r\n return getAbsolutePath(getOptions().highcharts.cachePath, 'utf8'); // #562\r\n}\r\n\r\n/**\r\n * Fetches a single script and updates the `fetchedModules` accordingly.\r\n *\r\n * @async\r\n * @function _fetchAndProcessScript\r\n *\r\n * @param {string} script - A path to script to get.\r\n * @param {Object} requestOptions - Additional options for the proxy agent\r\n * to use for a request.\r\n * @param {Object} fetchedModules - An object which tracks which Highcharts\r\n * modules have been fetched.\r\n * @param {boolean} [shouldThrowError=false] - A flag to indicate if the error\r\n * should be thrown. This should be used only for the core scripts. The default\r\n * value is `false`.\r\n *\r\n * @returns {Promise} A Promise that resolves to the text representation\r\n * of the fetched script.\r\n *\r\n * @throws {ExportError} Throws an `ExportError` if there is a problem\r\n * with fetching the script.\r\n */\r\nasync function _fetchAndProcessScript(\r\n script,\r\n requestOptions,\r\n fetchedModules,\r\n shouldThrowError = false\r\n) {\r\n // Get rid of the .js from the custom strings\r\n if (script.endsWith('.js')) {\r\n script = script.substring(0, script.length - 3);\r\n }\r\n log(4, `[cache] Fetching script - ${script}.js`);\r\n\r\n // Fetch the script\r\n const response = await fetch(`${script}.js`, requestOptions);\r\n\r\n // If OK, return its text representation\r\n if (response.statusCode === 200 && typeof response.text == 'string') {\r\n if (fetchedModules) {\r\n const moduleName = extractModuleName(script);\r\n fetchedModules[moduleName] = 1;\r\n }\r\n return response.text;\r\n }\r\n\r\n // Based on the `shouldThrowError` flag, decide how to serve error message\r\n if (shouldThrowError) {\r\n throw new ExportError(\r\n `[cache] Could not fetch the ${script}.js. The script might not exist in the requested version (status code: ${response.statusCode}).`,\r\n 404\r\n ).setError(response);\r\n } else {\r\n log(\r\n 2,\r\n `[cache] Could not fetch the ${script}.js. The script might not exist in the requested version.`\r\n );\r\n }\r\n}\r\n\r\n/**\r\n * Saves the provided configuration and fetched modules to the cache manifest\r\n * file.\r\n *\r\n * @async\r\n * @function _saveConfigToManifest\r\n *\r\n * @param {Object} highchartsOptions - The configuration object containing\r\n * `highcharts` options.\r\n * @param {Object} [fetchedModules={}] - An object which tracks which Highcharts\r\n * modules have been fetched. The default value is an empty object.\r\n *\r\n * @throws {ExportError} Throws an `ExportError` if an error occurs while\r\n * writing the cache manifest.\r\n */\r\nasync function _saveConfigToManifest(highchartsOptions, fetchedModules = {}) {\r\n const newManifest = {\r\n version: highchartsOptions.version,\r\n modules: fetchedModules\r\n };\r\n\r\n // Update cache object with the current modules\r\n cache.activeManifest = newManifest;\r\n\r\n log(3, '[cache] Writing a new manifest.');\r\n try {\r\n writeFileSync(\r\n join(getCachePath(), 'manifest.json'),\r\n JSON.stringify(newManifest),\r\n 'utf8'\r\n );\r\n } catch (error) {\r\n throw new ExportError(\r\n '[cache] Error writing the cache manifest.',\r\n 500\r\n ).setError(error);\r\n }\r\n}\r\n\r\n/**\r\n * Fetches Highcharts `scripts` and `customScripts` from the given CDNs.\r\n *\r\n * @async\r\n * @function _fetchScripts\r\n *\r\n * @param {Array.} coreScripts - Highcharts core scripts to fetch.\r\n * @param {Array.} moduleScripts - Highcharts modules to fetch.\r\n * @param {Array.} customScripts - Custom script paths to fetch (full\r\n * URLs).\r\n * @param {Object} serverProxyOptions - The configuration object containing\r\n * `server.proxy` options.\r\n * @param {Object} fetchedModules - An object which tracks which Highcharts\r\n * modules have been fetched.\r\n *\r\n * @returns {Promise} A Promise that resolves to the fetched scripts\r\n * content joined.\r\n *\r\n * @throws {ExportError} Throws an `ExportError` if an error occurs while\r\n * setting an HTTP Agent for proxy.\r\n */\r\nasync function _fetchScripts(\r\n coreScripts,\r\n moduleScripts,\r\n customScripts,\r\n serverProxyOptions,\r\n fetchedModules\r\n) {\r\n // Configure proxy if exists\r\n let proxyAgent;\r\n const proxyHost = serverProxyOptions.host;\r\n const proxyPort = serverProxyOptions.port;\r\n\r\n // Try to create a Proxy Agent\r\n if (proxyHost && proxyPort) {\r\n try {\r\n proxyAgent = new HttpsProxyAgent({\r\n host: proxyHost,\r\n port: proxyPort\r\n });\r\n } catch (error) {\r\n throw new ExportError(\r\n '[cache] Could not create a Proxy Agent.',\r\n 500\r\n ).setError(error);\r\n }\r\n }\r\n\r\n // If exists, add proxy agent to request options\r\n const requestOptions = proxyAgent\r\n ? {\r\n agent: proxyAgent,\r\n timeout: serverProxyOptions.timeout\r\n }\r\n : {};\r\n\r\n const allFetchPromises = [\r\n ...coreScripts.map((script) =>\r\n _fetchAndProcessScript(`${script}`, requestOptions, fetchedModules, true)\r\n ),\r\n ...moduleScripts.map((script) =>\r\n _fetchAndProcessScript(`${script}`, requestOptions, fetchedModules)\r\n ),\r\n ...customScripts.map((script) =>\r\n _fetchAndProcessScript(`${script}`, requestOptions)\r\n )\r\n ];\r\n\r\n const fetchedScripts = await Promise.all(allFetchPromises);\r\n return fetchedScripts.join(';\\n');\r\n}\r\n\r\n/**\r\n * Updates the local cache with Highcharts scripts and their versions.\r\n *\r\n * @async\r\n * @function _updateCache\r\n *\r\n * @param {Object} highchartsOptions - The configuration object containing\r\n * `highcharts` options.\r\n * @param {Object} serverProxyOptions - The configuration object containing\r\n * `server.proxy` options.\r\n * @param {string} sourcePath - The path to the source file in the cache.\r\n *\r\n * @returns {Promise} A Promise that resolves to an object representing\r\n * the fetched modules.\r\n *\r\n * @throws {ExportError} Throws an `ExportError` if there is an issue updating\r\n * the local Highcharts cache.\r\n */\r\nasync function _updateCache(highchartsOptions, serverProxyOptions, sourcePath) {\r\n // Get Highcharts version for scripts\r\n const hcVersion =\r\n highchartsOptions.version === 'latest'\r\n ? null\r\n : `${highchartsOptions.version}`;\r\n\r\n // Get the CDN url for scripts\r\n const cdnUrl = highchartsOptions.cdnUrl || cache.cdnUrl;\r\n\r\n try {\r\n const fetchedModules = {};\r\n\r\n log(\r\n 3,\r\n `[cache] Updating cache version to Highcharts: ${hcVersion || 'latest'}.`\r\n );\r\n\r\n cache.sources = await _fetchScripts(\r\n [\r\n ...highchartsOptions.coreScripts.map((c) =>\r\n hcVersion ? `${cdnUrl}/${hcVersion}/${c}` : `${cdnUrl}/${c}`\r\n )\r\n ],\r\n [\r\n ...highchartsOptions.moduleScripts.map((m) =>\r\n m === 'map'\r\n ? hcVersion\r\n ? `${cdnUrl}/maps/${hcVersion}/modules/${m}`\r\n : `${cdnUrl}/maps/modules/${m}`\r\n : hcVersion\r\n ? `${cdnUrl}/${hcVersion}/modules/${m}`\r\n : `${cdnUrl}/modules/${m}`\r\n ),\r\n ...highchartsOptions.indicatorScripts.map((i) =>\r\n hcVersion\r\n ? `${cdnUrl}/stock/${hcVersion}/indicators/${i}`\r\n : `${cdnUrl}/stock/indicators/${i}`\r\n )\r\n ],\r\n highchartsOptions.customScripts,\r\n serverProxyOptions,\r\n fetchedModules\r\n );\r\n\r\n // Extract and save version of currently used Highcharts\r\n cache.hcVersion = extractVersion(cache.sources);\r\n\r\n // Save the fetched modules into caches' source JSON\r\n writeFileSync(sourcePath, cache.sources);\r\n return fetchedModules;\r\n } catch (error) {\r\n throw new ExportError(\r\n '[cache] Unable to update the local Highcharts cache.',\r\n 500\r\n ).setError(error);\r\n }\r\n}\r\n\r\nexport default {\r\n checkAndUpdateCache,\r\n getHighchartsVersion,\r\n updateHighchartsVersion,\r\n extractVersion,\r\n extractModuleName,\r\n getCache,\r\n getCachePath\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * @overview Provides methods for initializing Highcharts with customized\r\n * animation settings and triggering the creation of Highcharts charts with\r\n * export-specific configurations in the page context. Supports dynamic option\r\n * merging, custom logic injection, and control over rendering behaviors. Used\r\n * by the Puppeteer page.\r\n */\r\n\r\n/* eslint-disable no-undef */\r\n\r\n/**\r\n * Setting the `Highcharts.animObject` function. Called when initing the page.\r\n *\r\n * @function setupHighcharts\r\n */\r\nexport function setupHighcharts() {\r\n Highcharts.animObject = function () {\r\n return { duration: 0 };\r\n };\r\n}\r\n\r\n/**\r\n * Creates the actual Highcharts chart on a page.\r\n *\r\n * @async\r\n * @function createChart\r\n *\r\n * @param {Object} exportOptions - The configuration object containing `export`\r\n * options.\r\n * @param {Object} customLogicOptions - The configuration object containing\r\n * `customLogic` options.\r\n *\r\n */\r\nexport async function createChart(exportOptions, customLogicOptions) {\r\n // Get required functions\r\n const { getOptions, setOptions, merge, wrap } = Highcharts;\r\n\r\n // Create a separate object for a potential `setOptions` usages in order\r\n // to prevent from polluting other exports that can happen on the same page\r\n Highcharts.setOptionsObj = merge(false, {}, getOptions());\r\n\r\n // NOTE: Is this used for anything useful?\r\n window.isRenderComplete = false;\r\n wrap(Highcharts.Chart.prototype, 'init', function (proceed, userOptions, cb) {\r\n // Override the `userOptions` with image friendly options\r\n userOptions = merge(userOptions, {\r\n exporting: {\r\n enabled: false\r\n },\r\n plotOptions: {\r\n series: {\r\n label: {\r\n enabled: false\r\n }\r\n }\r\n },\r\n /* Expects tooltip in the `userOptions` when `forExport` is true.\r\n https://github.com/highcharts/highcharts/blob/3ad430a353b8056b9e764aa4e5cd6828aa479db2/js/parts/Chart.js#L241\r\n */\r\n tooltip: {}\r\n });\r\n\r\n (userOptions.series || []).forEach(function (series) {\r\n series.animation = false;\r\n });\r\n\r\n // Add flag to know if chart render has been called.\r\n if (!window.onHighchartsRender) {\r\n window.onHighchartsRender = Highcharts.addEvent(this, 'render', () => {\r\n window.isRenderComplete = true;\r\n });\r\n }\r\n\r\n proceed.apply(this, [userOptions, cb]);\r\n });\r\n\r\n wrap(Highcharts.Series.prototype, 'init', function (proceed, chart, options) {\r\n proceed.apply(this, [chart, options]);\r\n });\r\n\r\n // Some mandatory additional `chart` and `exporting` options\r\n const additionalOptions = {\r\n chart: {\r\n // By default animation is disabled\r\n animation: false,\r\n // Get the right size values\r\n height: exportOptions.height,\r\n width: exportOptions.width\r\n },\r\n exporting: {\r\n // No need for the exporting button\r\n enabled: false\r\n }\r\n };\r\n\r\n // Get the input to export from the `instr` option\r\n const userOptions = new Function(`return ${exportOptions.instr}`)();\r\n\r\n // Get the `themeOptions` option\r\n const themeOptions = new Function(`return ${exportOptions.themeOptions}`)();\r\n\r\n // Get the `globalOptions` option\r\n const globalOptions = new Function(`return ${exportOptions.globalOptions}`)();\r\n\r\n // Merge the following options objects to create final options\r\n const finalOptions = merge(\r\n false,\r\n themeOptions,\r\n userOptions,\r\n // Placed it here instead in the init because of the size issues\r\n additionalOptions\r\n );\r\n\r\n // Prepare the `callback` option\r\n const finalCallback = customLogicOptions.callback\r\n ? new Function(`return ${customLogicOptions.callback}`)()\r\n : null;\r\n\r\n // Trigger the `customCode` option\r\n if (customLogicOptions.customCode) {\r\n new Function('options', customLogicOptions.customCode)(userOptions);\r\n }\r\n\r\n // Set the global options if exist\r\n if (globalOptions) {\r\n setOptions(globalOptions);\r\n }\r\n\r\n // Call the chart creation\r\n Highcharts[exportOptions.constr]('container', finalOptions, finalCallback);\r\n\r\n // Get the current global options\r\n const defaultOptions = getOptions();\r\n\r\n // Clear it just in case (e.g. the `setOptions` was used in the `customCode`)\r\n for (const prop in defaultOptions) {\r\n if (typeof defaultOptions[prop] !== 'function') {\r\n delete defaultOptions[prop];\r\n }\r\n }\r\n\r\n // Set the default options back\r\n setOptions(Highcharts.setOptionsObj);\r\n\r\n // Empty the custom global options object\r\n Highcharts.setOptionsObj = {};\r\n}\r\n\r\nexport default {\r\n setupHighcharts,\r\n createChart\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * @overview This module provides functions for managing Puppeteer browser\r\n * instance, creating and clearing pages, injecting custom resources,\r\n * and setting up Highcharts for server-side rendering. The module ensures\r\n * that resources are correctly managed and can handle failures during\r\n * operations like launching the browser or creating new pages.\r\n */\r\n\r\nimport { readFileSync } from 'fs';\r\nimport { join } from 'path';\r\n\r\nimport puppeteer from 'puppeteer';\r\n\r\nimport { getCachePath } from './cache.js';\r\nimport { getOptions } from './config.js';\r\nimport { setupHighcharts } from './highcharts.js';\r\nimport { log, logWithStack } from './logger.js';\r\nimport { __dirname, getAbsolutePath } from './utils.js';\r\n\r\nimport ExportError from './errors/ExportError.js';\r\n\r\n// Get the template for pages\r\nconst template = readFileSync(\r\n join(__dirname, 'templates', 'template.html'),\r\n 'utf8'\r\n);\r\n\r\n// To save the browser\r\nlet browser = null;\r\n\r\n/**\r\n * Retrieves the existing Puppeteer browser instance.\r\n *\r\n * @function getBrowser\r\n *\r\n * @returns {Object} The Puppeteer browser instance.\r\n *\r\n * @throws {ExportError} Throws an `ExportError` if no valid browser\r\n * has been created.\r\n */\r\nexport function getBrowser() {\r\n if (!browser) {\r\n throw new ExportError('[browser] No valid browser has been created.', 500);\r\n }\r\n return browser;\r\n}\r\n\r\n/**\r\n * Creates a Puppeteer browser instance with the specified arguments.\r\n *\r\n * @async\r\n * @function createBrowser\r\n *\r\n * @param {Array.} puppeteerArgs - Additional arguments for Puppeteer\r\n * launch.\r\n *\r\n * @returns {Promise} A Promise that resolves to the created Puppeteer\r\n * browser instance.\r\n *\r\n * @throws {ExportError} Throws an `ExportError` if max retries to open\r\n * a browser instance are reached, or if no browser instance is found after\r\n * retries.\r\n */\r\nexport async function createBrowser(puppeteerArgs) {\r\n // Get `debug` and `other` options\r\n const { debug, other } = getOptions();\r\n\r\n // Get the `debug` options\r\n const { enable: enabledDebug, ...debugOptions } = debug;\r\n\r\n // Launch options for the browser instance\r\n const launchOptions = {\r\n headless: other.browserShellMode ? 'shell' : true,\r\n userDataDir: 'tmp',\r\n args: puppeteerArgs || [],\r\n handleSIGINT: false,\r\n handleSIGTERM: false,\r\n handleSIGHUP: false,\r\n waitForInitialPage: false,\r\n defaultViewport: null,\r\n ...(enabledDebug && debugOptions)\r\n };\r\n\r\n // Create a browser\r\n if (!browser) {\r\n // A counter for the browser's launch retries\r\n let tryCount = 0;\r\n\r\n const open = async () => {\r\n try {\r\n log(\r\n 3,\r\n `[browser] Attempting to get a browser instance (try ${++tryCount}).`\r\n );\r\n\r\n // Launch the browser\r\n browser = await puppeteer.launch(launchOptions);\r\n } catch (error) {\r\n logWithStack(\r\n 1,\r\n error,\r\n '[browser] Failed to launch a browser instance.'\r\n );\r\n\r\n // Retry to launch browser until reaching max attempts\r\n if (tryCount < 25) {\r\n log(3, `[browser] Retry to open a browser (${tryCount} out of 25).`);\r\n\r\n // Wait for a 4 seconds before trying again\r\n await new Promise((response) => setTimeout(response, 4000));\r\n await open();\r\n } else {\r\n throw error;\r\n }\r\n }\r\n };\r\n\r\n try {\r\n await open();\r\n\r\n // Shell mode inform\r\n if (launchOptions.headless === 'shell') {\r\n log(3, `[browser] Launched browser in shell mode.`);\r\n }\r\n\r\n // Debug mode inform\r\n if (enabledDebug) {\r\n log(3, `[browser] Launched browser in debug mode.`);\r\n }\r\n } catch (error) {\r\n throw new ExportError(\r\n '[browser] Maximum retries to open a browser instance reached.',\r\n 500\r\n ).setError(error);\r\n }\r\n\r\n if (!browser) {\r\n throw new ExportError('[browser] Cannot find a browser to open.', 500);\r\n }\r\n }\r\n\r\n // Return a browser instance\r\n return browser;\r\n}\r\n\r\n/**\r\n * Closes the Puppeteer browser instance if it is connected.\r\n *\r\n * @async\r\n * @function closeBrowser\r\n */\r\nexport async function closeBrowser() {\r\n // Close the browser when connected\r\n if (browser && browser.connected) {\r\n await browser.close();\r\n }\r\n browser = null;\r\n log(4, '[browser] Closed the browser.');\r\n}\r\n\r\n/**\r\n * Creates a new Puppeteer page within an existing browser instance.\r\n * The function creates a new page, disables caching, sets content using\r\n * the `_setPageContent()`, and returns the created Puppeteer page.\r\n *\r\n * @async\r\n * @function newPage\r\n *\r\n * @param {Object} poolResource - The pool resource that contains `id`,\r\n * `workCount`, and `page`.\r\n *\r\n * @throws {ExportError} Throws an `ExportError` if no valid browser\r\n * has been connected or if a page is invalid or closed.\r\n */\r\nexport async function newPage(poolResource) {\r\n // Error in case of no connected browser\r\n if (!browser || !browser.connected) {\r\n throw new ExportError(`[browser] Browser is not yet connected.`, 500);\r\n }\r\n\r\n // Create a page\r\n poolResource.page = await browser.newPage();\r\n\r\n // Disable cache\r\n await poolResource.page.setCacheEnabled(false);\r\n\r\n // Set the content\r\n await _setPageContent(poolResource.page);\r\n\r\n // Set page events\r\n _setPageEvents(poolResource.page);\r\n\r\n // Check if the page is correctly created\r\n if (!poolResource.page || poolResource.page.isClosed()) {\r\n throw new ExportError('[browser] The page is invalid or closed.', 400);\r\n }\r\n}\r\n\r\n/**\r\n * Clears the content of a Puppeteer Page based on the specified mode. Logs\r\n * thrown error if clearing of a page's content fails.\r\n *\r\n * @async\r\n * @function clearPage\r\n *\r\n * @param {Object} poolResource - The pool resource that contains page and id.\r\n * @param {boolean} [hardReset=false] - A flag indicating the type of clearing\r\n * to be performed. If true, navigates to `about:blank` and resets content\r\n * and scripts. If false, clears the body content by setting a predefined HTML\r\n * structure. The default value is `false`.\r\n *\r\n * @returns {Promise} A Promise that resolves to true when page\r\n * is correctly cleared and false when it is not.\r\n */\r\nexport async function clearPage(poolResource, hardReset = false) {\r\n try {\r\n if (poolResource.page && !poolResource.page.isClosed()) {\r\n if (hardReset) {\r\n // Navigate to `about:blank`\r\n await poolResource.page.goto('about:blank', {\r\n waitUntil: 'domcontentloaded'\r\n });\r\n\r\n // Set the content and and scripts again\r\n await _setPageContent(poolResource.page);\r\n } else {\r\n // Clear body content\r\n await poolResource.page.evaluate(() => {\r\n document.body.innerHTML =\r\n '
';\r\n });\r\n }\r\n return true;\r\n }\r\n } catch (error) {\r\n logWithStack(\r\n 2,\r\n error,\r\n `[pool] Pool resource [${poolResource.id}] - Content of the page could not be cleared.`\r\n );\r\n\r\n // Set the `workLimit` to exceeded in order to recreate the resource\r\n poolResource.workCount = getOptions().pool.workLimit + 1;\r\n }\r\n return false;\r\n}\r\n\r\n/**\r\n * Adds custom JS and CSS resources to a Puppeteer Page based on the specified\r\n * options.\r\n *\r\n * @async\r\n * @function addPageResources\r\n *\r\n * @param {Object} page - The Puppeteer page object to which resources will\r\n * be added.\r\n * @param {Object} customLogicOptions - The configuration object containing\r\n * `customLogic` options.\r\n *\r\n * @returns {Promise>} A Promise that resolves to an array\r\n * of injected resources.\r\n */\r\nexport async function addPageResources(page, customLogicOptions) {\r\n // Injected resources array\r\n const injectedResources = [];\r\n\r\n // Use resources\r\n const resources = customLogicOptions.resources;\r\n if (resources) {\r\n const injectedJs = [];\r\n\r\n // Load custom JS code\r\n if (resources.js) {\r\n injectedJs.push({\r\n content: resources.js\r\n });\r\n }\r\n\r\n // Load scripts from all custom files\r\n if (resources.files) {\r\n for (const file of resources.files) {\r\n const isLocal = !file.startsWith('http') ? true : false;\r\n\r\n // Add each custom script from resources' files\r\n injectedJs.push(\r\n isLocal\r\n ? {\r\n content: readFileSync(getAbsolutePath(file), 'utf8')\r\n }\r\n : {\r\n url: file\r\n }\r\n );\r\n }\r\n }\r\n\r\n for (const jsResource of injectedJs) {\r\n try {\r\n injectedResources.push(await page.addScriptTag(jsResource));\r\n } catch (error) {\r\n logWithStack(2, error, `[browser] The JS resource cannot be loaded.`);\r\n }\r\n }\r\n injectedJs.length = 0;\r\n\r\n // Load CSS\r\n const injectedCss = [];\r\n if (resources.css) {\r\n let cssImports = resources.css.match(/@import\\s*([^;]*);/g);\r\n if (cssImports) {\r\n // Handle css section\r\n for (let cssImportPath of cssImports) {\r\n if (cssImportPath) {\r\n cssImportPath = cssImportPath\r\n .replace('url(', '')\r\n .replace('@import', '')\r\n .replace(/\"/g, '')\r\n .replace(/'/g, '')\r\n .replace(/;/, '')\r\n .replace(/\\)/g, '')\r\n .trim();\r\n\r\n // Add each custom css from resources\r\n if (cssImportPath.startsWith('http')) {\r\n injectedCss.push({\r\n url: cssImportPath\r\n });\r\n } else if (customLogicOptions.allowFileResources) {\r\n injectedCss.push({\r\n path: join(__dirname, cssImportPath)\r\n });\r\n }\r\n }\r\n }\r\n }\r\n\r\n // The rest of the CSS section will be content by now\r\n injectedCss.push({\r\n content: resources.css.replace(/@import\\s*([^;]*);/g, '') || ' '\r\n });\r\n\r\n for (const cssResource of injectedCss) {\r\n try {\r\n injectedResources.push(await page.addStyleTag(cssResource));\r\n } catch (error) {\r\n logWithStack(\r\n 2,\r\n error,\r\n `[browser] The CSS resource cannot be loaded.`\r\n );\r\n }\r\n }\r\n injectedCss.length = 0;\r\n }\r\n }\r\n return injectedResources;\r\n}\r\n\r\n/**\r\n * Clears out all state set on the page with `addScriptTag` and `addStyleTag`.\r\n * Removes injected resources and resets CSS and script tags on the page.\r\n * Additionally, it destroys previously existing charts.\r\n *\r\n * @async\r\n * @function clearPageResources\r\n *\r\n * @param {Object} page - The Puppeteer page object from which resources will\r\n * be cleared.\r\n * @param {Array.} injectedResources - Array of injected resources\r\n * to be cleared.\r\n */\r\nexport async function clearPageResources(page, injectedResources) {\r\n try {\r\n for (const resource of injectedResources) {\r\n await resource.dispose();\r\n }\r\n\r\n // Destroy old charts after export is done and reset all CSS and script tags\r\n await page.evaluate(() => {\r\n // We are not guaranteed that Highcharts is loaded, when doing SVG exports\r\n if (typeof Highcharts !== 'undefined') {\r\n // eslint-disable-next-line no-undef\r\n const oldCharts = Highcharts.charts;\r\n\r\n // Check in any already existing charts\r\n if (Array.isArray(oldCharts) && oldCharts.length) {\r\n // Destroy old charts\r\n for (const oldChart of oldCharts) {\r\n oldChart && oldChart.destroy();\r\n // eslint-disable-next-line no-undef\r\n Highcharts.charts.shift();\r\n }\r\n }\r\n }\r\n\r\n // eslint-disable-next-line no-undef\r\n const [...scriptsToRemove] = document.getElementsByTagName('script');\r\n // eslint-disable-next-line no-undef\r\n const [, ...stylesToRemove] = document.getElementsByTagName('style');\r\n // eslint-disable-next-line no-undef\r\n const [...linksToRemove] = document.getElementsByTagName('link');\r\n\r\n // Remove tags\r\n for (const element of [\r\n ...scriptsToRemove,\r\n ...stylesToRemove,\r\n ...linksToRemove\r\n ]) {\r\n element.remove();\r\n }\r\n });\r\n } catch (error) {\r\n logWithStack(2, error, `[browser] Could not clear page's resources.`);\r\n }\r\n}\r\n\r\n/**\r\n * Sets the content for a Puppeteer Page using a predefined template\r\n * and additional scripts.\r\n *\r\n * @async\r\n * @function _setPageContent\r\n *\r\n * @param {Object} page - The Puppeteer page object to which the content\r\n * is being set.\r\n */\r\nasync function _setPageContent(page) {\r\n // Set the initial page content\r\n await page.setContent(template, { waitUntil: 'domcontentloaded' });\r\n\r\n // Add all registered Higcharts scripts, quite demanding\r\n await page.addScriptTag({ path: join(getCachePath(), 'sources.js') });\r\n\r\n // Set the initial `animObject` for Highcharts\r\n await page.evaluate(setupHighcharts);\r\n}\r\n\r\n/**\r\n * Set events (like `pageerror` and `console`) for a Puppeteer Page in order\r\n * to catch and display errors and console logs from the window context.\r\n *\r\n * @function _setPageEvents\r\n *\r\n * @param {Object} page - The Puppeteer page object to which the listeners\r\n * are being set.\r\n */\r\nfunction _setPageEvents(page) {\r\n // Get `debug` options\r\n const { debug } = getOptions();\r\n\r\n // Set the `pageerror` listener\r\n page.on('pageerror', async () => {\r\n // It would seem like this may fire at the same time or shortly before\r\n // a page is closed.\r\n if (page.isClosed()) {\r\n return;\r\n }\r\n });\r\n\r\n // Set the `console` listener, if needed\r\n if (debug.enable && debug.listenToConsole) {\r\n page.on('console', (message) => {\r\n console.log(`[debug] ${message.text()}`);\r\n });\r\n }\r\n}\r\n\r\nexport default {\r\n getBrowser,\r\n createBrowser,\r\n closeBrowser,\r\n newPage,\r\n clearPage,\r\n addPageResources,\r\n clearPageResources\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * The CSS to be used on the exported page.\r\n *\r\n * @returns {string} The CSS configuration.\r\n */\r\nexport default () => `\r\n\r\nhtml, body {\r\n margin: 0;\r\n padding: 0;\r\n box-sizing: border-box;\r\n}\r\n\r\n#table-div, #sliders, #datatable, #controls, .ld-row {\r\n display: none;\r\n height: 0;\r\n}\r\n\r\n#chart-container {\r\n box-sizing: border-box;\r\n margin: 0;\r\n overflow: auto;\r\n font-size: 0;\r\n}\r\n\r\n#chart-container > figure, div {\r\n margin-top: 0 !important;\r\n margin-bottom: 0 !important;\r\n}\r\n\r\n`;\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\nimport cssTemplate from './css.js';\r\n\r\n/**\r\n * The SVG template to use when loading SVG content to be exported.\r\n *\r\n * @param {string} svg - The SVG input content to be exported.\r\n *\r\n * @returns {string} The SVG template.\r\n */\r\nexport default (svg) => `\r\n\r\n\r\n \r\n \r\n Highcharts Export\r\n \r\n \r\n \r\n
\r\n ${svg}\r\n
\r\n \r\n\r\n\r\n`;\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * @overview This module handles chart export functionality using Puppeteer.\r\n * It supports exporting charts as SVG, PNG, JPEG, and PDF formats. The module\r\n * manages page resources, sets up the export environment, and processes chart\r\n * configurations or SVG inputs for rendering. Exports to a chart from a page\r\n * using Puppeteer.\r\n */\r\n\r\nimport { addPageResources, clearPageResources } from './browser.js';\r\nimport { createChart } from './highcharts.js';\r\nimport { log } from './logger.js';\r\n\r\nimport svgTemplate from '../templates/svgExport/svgExport.js';\r\n\r\nimport ExportError from './errors/ExportError.js';\r\n\r\n/**\r\n * Exports to a chart from a page using Puppeteer.\r\n *\r\n * @async\r\n * @function puppeteerExport\r\n *\r\n * @param {Object} page - Puppeteer page object.\r\n * @param {Object} exportOptions - The configuration object containing `export`\r\n * options.\r\n * @param {Object} customLogicOptions - The configuration object containing\r\n * `customLogic` options.\r\n *\r\n * @returns {Promise<(string|Buffer|ExportError)>} A Promise that resolves\r\n * to the exported data or rejecting with an `ExportError`.\r\n *\r\n * @throws {ExportError} Throws an `ExportError` if export to an unsupported\r\n * output format occurs.\r\n */\r\nexport async function puppeteerExport(page, exportOptions, customLogicOptions) {\r\n // Injected resources array (additional JS and CSS)\r\n const injectedResources = [];\r\n\r\n try {\r\n let isSVG = false;\r\n\r\n // Decide on the export method\r\n if (exportOptions.svg) {\r\n log(4, '[export] Treating as SVG input.');\r\n\r\n // If the `type` is also SVG, return the input\r\n if (exportOptions.type === 'svg') {\r\n return exportOptions.svg;\r\n }\r\n\r\n // Mark as SVG export for the later size corrections\r\n isSVG = true;\r\n\r\n // SVG export\r\n await page.setContent(svgTemplate(exportOptions.svg), {\r\n waitUntil: 'domcontentloaded'\r\n });\r\n } else {\r\n log(4, '[export] Treating as JSON config.');\r\n\r\n // Options export\r\n await page.evaluate(createChart, exportOptions, customLogicOptions);\r\n }\r\n\r\n // Keeps track of all resources added on the page with addXXXTag. etc\r\n // It's VITAL that all added resources ends up here so we can clear things\r\n // out when doing a new export in the same page!\r\n injectedResources.push(\r\n ...(await addPageResources(page, customLogicOptions))\r\n );\r\n\r\n // Get the real chart size and set the zoom accordingly\r\n const size = isSVG\r\n ? await page.evaluate((scale) => {\r\n const svgElement = document.querySelector(\r\n '#chart-container svg:first-of-type'\r\n );\r\n\r\n // Get the values correctly scaled\r\n const chartHeight = svgElement.height.baseVal.value * scale;\r\n const chartWidth = svgElement.width.baseVal.value * scale;\r\n\r\n // In case of SVG the zoom must be set directly for body as scale\r\n // eslint-disable-next-line no-undef\r\n document.body.style.zoom = scale;\r\n\r\n // Set the margin to 0px\r\n // eslint-disable-next-line no-undef\r\n document.body.style.margin = '0px';\r\n\r\n return {\r\n chartHeight,\r\n chartWidth\r\n };\r\n }, parseFloat(exportOptions.scale))\r\n : await page.evaluate(() => {\r\n // eslint-disable-next-line no-undef\r\n const { chartHeight, chartWidth } = window.Highcharts.charts[0];\r\n\r\n // No need for such scale manipulation in case of other types\r\n // of exports. Reset the zoom for other exports than to SVGs\r\n // eslint-disable-next-line no-undef\r\n document.body.style.zoom = 1;\r\n\r\n return {\r\n chartHeight,\r\n chartWidth\r\n };\r\n });\r\n\r\n // Get the clip region for the page\r\n const { x, y } = await _getClipRegion(page);\r\n\r\n // Set final `height` for viewport\r\n const viewportHeight = Math.abs(\r\n Math.ceil(size.chartHeight || exportOptions.height)\r\n );\r\n\r\n // Set final `width` for viewport\r\n const viewportWidth = Math.abs(\r\n Math.ceil(size.chartWidth || exportOptions.width)\r\n );\r\n\r\n // Set the final viewport now that we have the real height\r\n await page.setViewport({\r\n height: viewportHeight,\r\n width: viewportWidth,\r\n deviceScaleFactor: isSVG ? 1 : parseFloat(exportOptions.scale)\r\n });\r\n\r\n let result;\r\n // Rasterization process\r\n switch (exportOptions.type) {\r\n case 'svg':\r\n result = await _createSVG(page);\r\n break;\r\n case 'png':\r\n case 'jpeg':\r\n result = await _createImage(\r\n page,\r\n exportOptions.type,\r\n {\r\n width: viewportWidth,\r\n height: viewportHeight,\r\n x,\r\n y\r\n },\r\n exportOptions.rasterizationTimeout\r\n );\r\n break;\r\n case 'pdf':\r\n result = await _createPDF(\r\n page,\r\n viewportHeight,\r\n viewportWidth,\r\n exportOptions.rasterizationTimeout\r\n );\r\n break;\r\n default:\r\n throw new ExportError(\r\n `[export] Unsupported output format: ${exportOptions.type}.`,\r\n 400\r\n );\r\n }\r\n\r\n // Clear previously injected JS and CSS resources\r\n await clearPageResources(page, injectedResources);\r\n return result;\r\n } catch (error) {\r\n await clearPageResources(page, injectedResources);\r\n return error;\r\n }\r\n}\r\n\r\n/**\r\n * Retrieves the clipping region coordinates of the specified page element\r\n * with the 'chart-container' id.\r\n *\r\n * @async\r\n * @function _getClipRegion\r\n *\r\n * @param {Object} page - Puppeteer page object.\r\n *\r\n * @returns {Promise} A Promise that resolves to an object containing\r\n * `x`, `y`, `width`, and `height` properties.\r\n */\r\nasync function _getClipRegion(page) {\r\n return page.$eval('#chart-container', (element) => {\r\n const { x, y, width, height } = element.getBoundingClientRect();\r\n return {\r\n x,\r\n y,\r\n width,\r\n height: Math.trunc(height > 1 ? height : 500)\r\n };\r\n });\r\n}\r\n\r\n/**\r\n * Creates an SVG by evaluating the `outerHTML` of the first 'svg' element\r\n * inside an element with the id 'container'.\r\n *\r\n * @async\r\n * @function _createSVG\r\n *\r\n * @param {Object} page - Puppeteer page object.\r\n *\r\n * @returns {Promise} A Promise that resolves to the SVG string.\r\n */\r\nasync function _createSVG(page) {\r\n return page.$eval(\r\n '#container svg:first-of-type',\r\n (element) => element.outerHTML\r\n );\r\n}\r\n\r\n/**\r\n * Creates an image using Puppeteer's page `screenshot` functionality with\r\n * specified options.\r\n *\r\n * @async\r\n * @function _createImage\r\n *\r\n * @param {Object} page - Puppeteer page object.\r\n * @param {string} type - Image type.\r\n * @param {Object} clip - Clipping region coordinates.\r\n * @param {number} rasterizationTimeout - Timeout for rasterization\r\n * in milliseconds.\r\n *\r\n * @returns {Promise} A Promise that resolves to the image buffer\r\n * or rejecting with an `ExportError` for timeout.\r\n */\r\nasync function _createImage(page, type, clip, rasterizationTimeout) {\r\n return Promise.race([\r\n page.screenshot({\r\n type,\r\n clip,\r\n encoding: 'base64',\r\n fullPage: false,\r\n optimizeForSpeed: true,\r\n captureBeyondViewport: true,\r\n ...(type !== 'png' ? { quality: 80 } : {}),\r\n // Always render on a transparent page if the expected type format is PNG\r\n omitBackground: type == 'png' // #447, #463\r\n }),\r\n new Promise((_resolve, reject) =>\r\n setTimeout(\r\n () => reject(new ExportError('Rasterization timeout', 408)),\r\n rasterizationTimeout || 1500\r\n )\r\n )\r\n ]);\r\n}\r\n\r\n/**\r\n * Creates a PDF using Puppeteer's page `pdf` functionality with specified\r\n * options.\r\n *\r\n * @async\r\n * @function _createPDF\r\n *\r\n * @param {Object} page - Puppeteer page object.\r\n * @param {number} height - PDF height.\r\n * @param {number} width - PDF width.\r\n * @param {number} rasterizationTimeout - Timeout for rasterization\r\n * in milliseconds.\r\n *\r\n * @returns {Promise} A Promise that resolves to the PDF buffer.\r\n */\r\nasync function _createPDF(page, height, width, rasterizationTimeout) {\r\n await page.emulateMediaType('screen');\r\n return page.pdf({\r\n // This will remove an extra empty page in PDF exports\r\n height: height + 1,\r\n width,\r\n encoding: 'base64',\r\n timeout: rasterizationTimeout || 1500\r\n });\r\n}\r\n\r\nexport default {\r\n puppeteerExport\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * @overview This module provides a worker pool implementation for managing\r\n * the browser instance and pages, specifically designed for use with\r\n * the Highcharts Export Server. It optimizes resources usage and performance\r\n * by maintaining a pool of workers that can handle concurrent export tasks\r\n * using Puppeteer.\r\n */\r\n\r\nimport { Pool } from 'tarn';\r\nimport { v4 as uuid } from 'uuid';\r\n\r\nimport { clearPage, createBrowser, closeBrowser, newPage } from './browser.js';\r\nimport { puppeteerExport } from './export.js';\r\nimport { log, logWithStack } from './logger.js';\r\nimport { getNewDateTime, measureTime } from './utils.js';\r\n\r\nimport ExportError from './errors/ExportError.js';\r\n\r\n// The pool instance\r\nlet pool = null;\r\n\r\n// Pool statistics\r\nconst poolStats = {\r\n exportsAttempted: 0,\r\n exportsPerformed: 0,\r\n exportsDropped: 0,\r\n exportsFromSvg: 0,\r\n exportsFromOptions: 0,\r\n exportsFromSvgAttempts: 0,\r\n exportsFromOptionsAttempts: 0,\r\n timeSpent: 0,\r\n timeSpentAverage: 0\r\n};\r\n\r\n/**\r\n * Initializes the export pool with the provided configuration, creating\r\n * a browser instance and setting up worker resources.\r\n *\r\n * @async\r\n * @function initPool\r\n *\r\n * @param {Object} poolOptions - The configuration object containing `pool`\r\n * options.\r\n * @param {Array.} puppeteerArgs - Additional arguments for Puppeteer\r\n * launch.\r\n *\r\n * @returns {Promise} A Promise that resolves to ending the function\r\n * execution when an already initialized pool of resources is found.\r\n *\r\n * @throws {ExportError} Throws an `ExportError` if could not create the pool\r\n * of workers.\r\n */\r\nexport async function initPool(poolOptions, puppeteerArgs) {\r\n // Create a browser instance with the puppeteer arguments\r\n await createBrowser(puppeteerArgs);\r\n\r\n try {\r\n log(\r\n 3,\r\n `[pool] Initializing pool with workers: min ${poolOptions.minWorkers}, max ${poolOptions.maxWorkers}.`\r\n );\r\n\r\n if (pool) {\r\n log(\r\n 4,\r\n '[pool] Already initialized, please kill it before creating a new one.'\r\n );\r\n return;\r\n }\r\n\r\n // Keep an eye on a correct min and max workers number\r\n if (poolOptions.minWorkers > poolOptions.maxWorkers) {\r\n poolOptions.minWorkers = poolOptions.maxWorkers;\r\n }\r\n\r\n // Create a pool along with a minimal number of resources\r\n pool = new Pool({\r\n // Get the `create`, `validate`, and `destroy` functions\r\n ..._factory(poolOptions),\r\n min: poolOptions.minWorkers,\r\n max: poolOptions.maxWorkers,\r\n acquireTimeoutMillis: poolOptions.acquireTimeout,\r\n createTimeoutMillis: poolOptions.createTimeout,\r\n destroyTimeoutMillis: poolOptions.destroyTimeout,\r\n idleTimeoutMillis: poolOptions.idleTimeout,\r\n createRetryIntervalMillis: poolOptions.createRetryInterval,\r\n reapIntervalMillis: poolOptions.reaperInterval,\r\n propagateCreateError: false\r\n });\r\n\r\n // Set events\r\n pool.on('release', async (resource) => {\r\n // Clear page\r\n const clearStatus = await clearPage(resource, false);\r\n log(\r\n 4,\r\n `[pool] Pool resource [${resource.id}] - Releasing a worker. Clear page status: ${clearStatus}.`\r\n );\r\n });\r\n\r\n pool.on('destroySuccess', (_eventId, resource) => {\r\n log(\r\n 4,\r\n `[pool] Pool resource [${resource.id}] - Destroyed a worker successfully.`\r\n );\r\n resource.page = null;\r\n });\r\n\r\n const initialResources = [];\r\n // Create an initial number of resources\r\n for (let i = 0; i < poolOptions.minWorkers; i++) {\r\n try {\r\n const resource = await pool.acquire().promise;\r\n initialResources.push(resource);\r\n } catch (error) {\r\n logWithStack(2, error, '[pool] Could not create an initial resource.');\r\n }\r\n }\r\n\r\n // Release the initial number of resources back to the pool\r\n initialResources.forEach((resource) => {\r\n pool.release(resource);\r\n });\r\n\r\n log(\r\n 3,\r\n `[pool] The pool is ready${initialResources.length ? ` with ${initialResources.length} initial resources waiting.` : '.'}`\r\n );\r\n } catch (error) {\r\n throw new ExportError(\r\n '[pool] Could not configure and create the pool of workers.',\r\n 500\r\n ).setError(error);\r\n }\r\n}\r\n\r\n/**\r\n * Terminates all workers in the pool, destroys the pool, and closes the browser\r\n * instance.\r\n *\r\n * @async\r\n * @function killPool\r\n *\r\n * @returns {Promise} A Promise that resolves once all workers are\r\n * terminated, the pool is destroyed, and the browser is successfully closed.\r\n */\r\nexport async function killPool() {\r\n log(3, '[pool] Killing pool with all workers and closing browser.');\r\n\r\n // If still alive, destroy the pool of pages before closing a browser\r\n if (pool) {\r\n // Free up not released workers\r\n for (const worker of pool.used) {\r\n pool.release(worker.resource);\r\n }\r\n\r\n // Destroy the pool if it is still available\r\n if (!pool.destroyed) {\r\n await pool.destroy();\r\n log(4, '[pool] Destroyed the pool of resources.');\r\n }\r\n pool = null;\r\n }\r\n\r\n // Close the browser instance\r\n await closeBrowser();\r\n}\r\n\r\n/**\r\n * Processes the export work using a worker from the pool. Acquires a worker\r\n * handle from the pool, performs the export using puppeteer, and releases\r\n * the worker handle back to the pool.\r\n *\r\n * @async\r\n * @function postWork\r\n *\r\n * @param {Object} options - The configuration object containing complete set\r\n * of options.\r\n *\r\n * @returns {Promise} A Promise that resolves to the export result\r\n * and options.\r\n *\r\n * @throws {ExportError} Throws an `ExportError` if an error occurs during\r\n * the export process.\r\n */\r\nexport async function postWork(options) {\r\n let workerHandle;\r\n\r\n try {\r\n log(4, '[pool] Work received, starting to process.');\r\n\r\n // An export attempt counted\r\n ++poolStats.exportsAttempted;\r\n\r\n // Display the pool information if needed\r\n if (options.pool.benchmarking) {\r\n getPoolInfo();\r\n }\r\n\r\n // Throw an error in case of lacking the pool instance\r\n if (!pool) {\r\n throw new ExportError(\r\n '[pool] Work received, but pool has not been started.',\r\n 500\r\n );\r\n }\r\n\r\n // The acquire counter\r\n const acquireCounter = measureTime();\r\n\r\n // Try to acquire the worker along with the id, works count and page\r\n try {\r\n log(4, '[pool] Acquiring a worker handle.');\r\n\r\n // Acquire a pool resource\r\n workerHandle = await pool.acquire().promise;\r\n\r\n // Check the page acquire time\r\n if (options.server.benchmarking) {\r\n log(\r\n 5,\r\n `[benchmark] ${options.requestId ? `Request [${options.requestId}] - ` : ''}`,\r\n `Acquiring a worker handle took ${acquireCounter()}ms.`\r\n );\r\n }\r\n } catch (error) {\r\n throw new ExportError(\r\n `[pool] ${\r\n options.requestId ? `Request [${options.requestId}] - ` : ''\r\n }Error encountered when acquiring an available entry: ${acquireCounter()}ms.`,\r\n 400\r\n ).setError(error);\r\n }\r\n log(4, '[pool] Acquired a worker handle.');\r\n\r\n if (!workerHandle.page) {\r\n // Set the `workLimit` to exceeded in order to recreate the resource\r\n workerHandle.workCount = options.pool.workLimit + 1;\r\n throw new ExportError(\r\n '[pool] Resolved worker page is invalid: the pool setup is wonky.',\r\n 400\r\n );\r\n }\r\n\r\n // Save the start time\r\n const workStart = getNewDateTime();\r\n\r\n log(\r\n 4,\r\n `[pool] Pool resource [${workerHandle.id}] - Starting work on this pool entry.`\r\n );\r\n\r\n // Start measuring export time\r\n const exportCounter = measureTime();\r\n\r\n // Perform an export on a puppeteer level\r\n const result = await puppeteerExport(\r\n workerHandle.page,\r\n options.export,\r\n options.customLogic\r\n );\r\n\r\n // Check if it's an error\r\n if (result instanceof Error) {\r\n // NOTE:\r\n // If there's a rasterization timeout, we want need to flush the page.\r\n // This is because the page may be in a state where it's waiting for\r\n // the screenshot to finish even though the timeout has occured.\r\n // Which of course causes a lot of issues with the event system,\r\n // and page consistency.\r\n //\r\n // NOTE:\r\n // Only page.screenshot will throw this, timeouts for PDF's are\r\n // handled by the page.pdf function itself.\r\n //\r\n // ...yes, this is ugly.\r\n if (result.message === 'Rasterization timeout') {\r\n // Set the `workLimit` to exceeded in order to recreate the resource\r\n workerHandle.workCount = options.pool.workLimit + 1;\r\n workerHandle.page = null;\r\n }\r\n\r\n if (\r\n result.name === 'TimeoutError' ||\r\n result.message === 'Rasterization timeout'\r\n ) {\r\n throw new ExportError(\r\n `[pool] ${\r\n options.requestId ? `Request [${options.requestId}] - ` : ''\r\n }Rasterization timeout: your chart may be too complex or large, and failed to render within the allotted time.`\r\n ).setError(result);\r\n } else {\r\n throw new ExportError(\r\n `[pool] ${\r\n options.requestId ? `Request [${options.requestId}] - ` : ''\r\n }Error encountered during export: ${exportCounter()}ms.`\r\n ).setError(result);\r\n }\r\n }\r\n\r\n // Check the Puppeteer export time\r\n if (options.server.benchmarking) {\r\n log(\r\n 5,\r\n `[benchmark] ${options.requestId ? `Request [${options.requestId}] - ` : ''}`,\r\n `Exporting a chart sucessfully took ${exportCounter()}ms.`\r\n );\r\n }\r\n\r\n // Release the resource back to the pool\r\n pool.release(workerHandle);\r\n\r\n // Used for statistics in averageTime and processedWorkCount, which\r\n // in turn is used by the /health route.\r\n const workEnd = getNewDateTime();\r\n const exportTime = workEnd - workStart;\r\n\r\n poolStats.timeSpent += exportTime;\r\n poolStats.timeSpentAverage =\r\n poolStats.timeSpent / ++poolStats.exportsPerformed;\r\n\r\n log(4, `[pool] Work completed in ${exportTime}ms.`);\r\n\r\n // Otherwise return the result\r\n return {\r\n result,\r\n options\r\n };\r\n } catch (error) {\r\n ++poolStats.exportsDropped;\r\n\r\n if (workerHandle) {\r\n pool.release(workerHandle);\r\n }\r\n\r\n throw error;\r\n }\r\n}\r\n\r\n/**\r\n * Retrieves the current pool instance.\r\n *\r\n * @function getPool\r\n *\r\n * @returns {(Object|null)} The current pool instance if initialized, or null\r\n * if the pool has not been created.\r\n */\r\nexport function getPool() {\r\n return pool;\r\n}\r\n\r\n/**\r\n * Gets the statistic of a pool instace about exports.\r\n *\r\n * @function getPoolStats\r\n *\r\n * @returns {Object} The current pool statistics.\r\n */\r\nexport function getPoolStats() {\r\n return poolStats;\r\n}\r\n\r\n/**\r\n * Retrieves pool information in JSON format, including minimum and maximum\r\n * workers, available workers, workers in use, and pending acquire requests.\r\n *\r\n * @function getPoolInfoJSON\r\n *\r\n * @returns {Object} Pool information in JSON format.\r\n */\r\nexport function getPoolInfoJSON() {\r\n return {\r\n min: pool.min,\r\n max: pool.max,\r\n used: pool.numUsed(),\r\n available: pool.numFree(),\r\n allCreated: pool.numUsed() + pool.numFree(),\r\n pendingAcquires: pool.numPendingAcquires(),\r\n pendingCreates: pool.numPendingCreates(),\r\n pendingValidations: pool.numPendingValidations(),\r\n pendingDestroys: pool.pendingDestroys.length,\r\n absoluteAll:\r\n pool.numUsed() +\r\n pool.numFree() +\r\n pool.numPendingAcquires() +\r\n pool.numPendingCreates() +\r\n pool.numPendingValidations() +\r\n pool.pendingDestroys.length\r\n };\r\n}\r\n\r\n/**\r\n * Logs information about the current state of the pool, including the minimum\r\n * and maximum workers, available workers, workers in use, and pending acquire\r\n * requests.\r\n *\r\n * @function getPoolInfo\r\n */\r\nexport function getPoolInfo() {\r\n const {\r\n min,\r\n max,\r\n used,\r\n available,\r\n allCreated,\r\n pendingAcquires,\r\n pendingCreates,\r\n pendingValidations,\r\n pendingDestroys,\r\n absoluteAll\r\n } = getPoolInfoJSON();\r\n\r\n log(5, `[pool] The minimum number of resources allowed by pool: ${min}.`);\r\n log(5, `[pool] The maximum number of resources allowed by pool: ${max}.`);\r\n log(5, `[pool] The number of used resources: ${used}.`);\r\n log(5, `[pool] The number of free resources: ${available}.`);\r\n log(\r\n 5,\r\n `[pool] The number of all created (used and free) resources: ${allCreated}.`\r\n );\r\n log(\r\n 5,\r\n `[pool] The number of resources waiting to be acquired: ${pendingAcquires}.`\r\n );\r\n log(\r\n 5,\r\n `[pool] The number of resources waiting to be created: ${pendingCreates}.`\r\n );\r\n log(\r\n 5,\r\n `[pool] The number of resources waiting to be validated: ${pendingValidations}.`\r\n );\r\n log(\r\n 5,\r\n `[pool] The number of resources waiting to be destroyed: ${pendingDestroys}.`\r\n );\r\n log(5, `[pool] The number of all resources: ${absoluteAll}.`);\r\n}\r\n\r\n/**\r\n * Factory function that returns an object with `create`, `validate`,\r\n * and `destroy` functions for the pool instance.\r\n *\r\n * @function _factory\r\n *\r\n * @param {Object} poolOptions - The configuration object containing `pool`\r\n * options.\r\n */\r\nfunction _factory(poolOptions) {\r\n return {\r\n /**\r\n * Creates a new worker page for the export pool.\r\n *\r\n * @async\r\n * @function create\r\n *\r\n * @returns {Promise} A Promise that resolves to an object\r\n * containing the worker ID, a reference to the browser page, and initial\r\n * work count.\r\n *\r\n * @throws {ExportError} Throws an `ExportError` if there is an error during\r\n * the creation of the new page.\r\n */\r\n create: async () => {\r\n // Init the resource with unique id and work count\r\n const poolResource = {\r\n id: uuid(),\r\n // Try to distribute the initial work count\r\n workCount: Math.round(Math.random() * (poolOptions.workLimit / 2))\r\n };\r\n\r\n try {\r\n // Start measuring a page creation time\r\n const startDate = getNewDateTime();\r\n\r\n // Create a new page\r\n await newPage(poolResource);\r\n\r\n // Measure the time of full creation and configuration of a page\r\n log(\r\n 3,\r\n `[pool] Pool resource [${poolResource.id}] - Successfully created a worker, took ${\r\n getNewDateTime() - startDate\r\n }ms.`\r\n );\r\n\r\n // Return ready pool resource\r\n return poolResource;\r\n } catch (error) {\r\n log(\r\n 3,\r\n `[pool] Pool resource [${poolResource.id}] - Error encountered when creating a new page.`\r\n );\r\n throw error;\r\n }\r\n },\r\n\r\n /**\r\n * Validates a worker page in the export pool, checking if it has exceeded\r\n * the work limit.\r\n *\r\n * @async\r\n * @function validate\r\n *\r\n * @param {Object} poolResource - The handle to the worker, containing\r\n * the worker's ID, a reference to the browser page, and work count.\r\n *\r\n * @returns {Promise} A Promise that resolves to true if the worker\r\n * is valid and within the work limit; otherwise, to false.\r\n */\r\n validate: async (poolResource) => {\r\n // NOTE:\r\n // In certain cases acquiring throws a TargetCloseError, which may\r\n // be caused by two things:\r\n // - The page is closed and attempted to be reused.\r\n // - Lost contact with the browser.\r\n //\r\n // What we're seeing in logs is that successive exports typically\r\n // succeeds, and the server recovers, indicating that it's likely\r\n // the first case. This is an attempt at allievating the issue by\r\n // simply not validating the worker if the page is null or closed.\r\n //\r\n // The actual result from when this happened, was that a worker would\r\n // be completely locked, stopping it from being acquired until\r\n // its work count reached the limit.\r\n\r\n // Check if the `page` is valid\r\n if (!poolResource.page) {\r\n log(\r\n 3,\r\n `[pool] Pool resource [${poolResource.id}] - Validation failed (no valid page is found).`\r\n );\r\n return false;\r\n }\r\n\r\n // Check if the `page` is closed\r\n if (poolResource.page.isClosed()) {\r\n log(\r\n 3,\r\n `[pool] Pool resource [${poolResource.id}] - Validation failed (page is closed or invalid).`\r\n );\r\n return false;\r\n }\r\n\r\n // Check if the `mainFrame` is detached\r\n if (poolResource.page.mainFrame().detached) {\r\n log(\r\n 3,\r\n `[pool] Pool resource [${poolResource.id}] - Validation failed (page's frame is detached).`\r\n );\r\n return false;\r\n }\r\n\r\n // Check if the `workLimit` is exceeded\r\n if (\r\n poolOptions.workLimit &&\r\n ++poolResource.workCount > poolOptions.workLimit\r\n ) {\r\n log(\r\n 3,\r\n `[pool] Pool resource [${poolResource.id}] - Validation failed (exceeded the ${poolOptions.workLimit} works per resource limit).`\r\n );\r\n return false;\r\n }\r\n\r\n // The `poolResource` is validated\r\n return true;\r\n },\r\n\r\n /**\r\n * Destroys a worker entry in the export pool, closing its associated page.\r\n *\r\n * @async\r\n * @function destroy\r\n *\r\n * @param {Object} poolResource - The handle to the worker, containing\r\n * the worker's ID, a reference to the browser page, and work count.\r\n */\r\n destroy: async (poolResource) => {\r\n log(\r\n 3,\r\n `[pool] Pool resource [${poolResource.id}] - Destroying a worker.`\r\n );\r\n\r\n if (poolResource.page && !poolResource.page.isClosed()) {\r\n try {\r\n // Remove all attached event listeners from the resource\r\n poolResource.page.removeAllListeners('pageerror');\r\n poolResource.page.removeAllListeners('console');\r\n poolResource.page.removeAllListeners('framedetached');\r\n\r\n // We need to wait around for this\r\n await poolResource.page.close();\r\n } catch (error) {\r\n log(\r\n 3,\r\n `[pool] Pool resource [${poolResource.id}] - Page could not be closed upon destroying.`\r\n );\r\n throw error;\r\n }\r\n }\r\n }\r\n };\r\n}\r\n\r\nexport default {\r\n initPool,\r\n killPool,\r\n postWork,\r\n getPool,\r\n getPoolStats,\r\n getPoolInfo,\r\n getPoolInfoJSON\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * @overview Used to sanitize the strings coming from the exporting module\r\n * to prevent XSS attacks (with the DOMPurify library).\r\n */\r\n\r\nimport DOMPurify from 'dompurify';\r\nimport { JSDOM } from 'jsdom';\r\n\r\n/**\r\n * Sanitizes a given HTML string by removing \r\n * tags and any content within them.\r\n *\r\n * @function sanitize\r\n *\r\n * @param {string} input - The HTML string to be sanitized.\r\n *\r\n * @returns {string} The sanitized HTML string.\r\n */\r\nexport function sanitize(input) {\r\n // Get the virtual DOM\r\n const window = new JSDOM('').window;\r\n\r\n // Create a purifying instance\r\n const purify = DOMPurify(window);\r\n\r\n // Return sanitized input\r\n return purify.sanitize(input, { ADD_TAGS: ['foreignObject'] });\r\n}\r\n\r\nexport default {\r\n sanitize\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * @overview This module provides functions to prepare for the exporting charts\r\n * into various image output formats such as JPEG, PNG, PDF, and SVGs.\r\n * It supports single and batch export operations and allows customization\r\n * through options passed from configurations or APIs.\r\n */\r\n\r\nimport { readFileSync, writeFileSync } from 'fs';\r\n\r\nimport {\r\n getOptions,\r\n isAllowedConfig,\r\n mergeOptions,\r\n validateOption,\r\n validateOptions\r\n} from './config.js';\r\nimport { log, logWithStack } from './logger.js';\r\nimport { getPoolStats, killPool, postWork } from './pool.js';\r\nimport { sanitize } from './sanitize.js';\r\nimport {\r\n deepCopy,\r\n fixConstr,\r\n fixOutfile,\r\n fixType,\r\n getAbsolutePath,\r\n getBase64,\r\n isObject,\r\n roundNumber,\r\n wrapAround\r\n} from './utils.js';\r\n\r\nimport ExportError from './errors/ExportError.js';\r\n\r\n// The global flag for the code execution permission\r\nlet allowCodeExecution = false;\r\n\r\n/**\r\n * Starts a single export process based on the specified options and saves\r\n * the resulting image to the provided output file.\r\n *\r\n * @async\r\n * @function singleExport\r\n *\r\n * @param {Object} options - The `options` object, which should include settings\r\n * from the `export` and `customLogic` sections. It can be a partial or complete\r\n * set of options from these sections. The object must contain at least one\r\n * of the following `export` properties: `infile`, `instr`, `options`, or `svg`\r\n * to generate a valid image.\r\n *\r\n * @returns {Promise} A Promise that resolves once the single export\r\n * process is completed.\r\n *\r\n * @throws {ExportError} Throws an `ExportError` if an error occurs during\r\n * the single export process.\r\n */\r\nexport async function singleExport(options) {\r\n // Check if the export makes sense\r\n if (options && options.export) {\r\n // Validate single export options\r\n options = validateOptions(options);\r\n\r\n // Perform an export\r\n await startExport(\r\n { export: options.export, customLogic: options.customLogic },\r\n async (error, data) => {\r\n // Exit process when error exists\r\n if (error) {\r\n throw error;\r\n }\r\n\r\n // Get the `b64`, `outfile`, and `type` for a chart\r\n const { b64, outfile, type } = data.options.export;\r\n\r\n // Save the result\r\n try {\r\n if (b64) {\r\n // As a Base64 string to a txt file\r\n writeFileSync(\r\n `${outfile.split('.').shift() || 'chart'}.txt`,\r\n getBase64(data.result, type)\r\n );\r\n } else {\r\n // As a correct image format\r\n writeFileSync(\r\n outfile || `chart.${type}`,\r\n type !== 'svg' ? Buffer.from(data.result, 'base64') : data.result\r\n );\r\n }\r\n } catch (error) {\r\n throw new ExportError(\r\n '[chart] Error while saving a chart.',\r\n 500\r\n ).setError(error);\r\n }\r\n\r\n // Kill pool and close browser after finishing single export\r\n await killPool();\r\n }\r\n );\r\n } else {\r\n throw new ExportError(\r\n '[chart] No expected `export` options were found. Please provide one of the following options: `infile`, `instr`, `options`, or `svg` to generate a valid image.',\r\n 400\r\n );\r\n }\r\n}\r\n\r\n/**\r\n * Starts a batch export process for multiple charts based on information\r\n * provided in the `batch` option. The `batch` is a string in the following\r\n * format: \"infile1.json=outfile1.png;infile2.json=outfile2.png;...\". Results\r\n * are saved to the specified output files.\r\n *\r\n * @async\r\n * @function batchExport\r\n *\r\n * @param {Object} options - The `options` object, which should include settings\r\n * from the `export` and `customLogic` sections. It can be a partial or complete\r\n * set of options from these sections. It must contain the `batch` option from\r\n * the `export` section to generate valid images.\r\n *\r\n * @returns {Promise} A Promise that resolves once the batch export\r\n * processes are completed.\r\n *\r\n * @throws {ExportError} Throws an `ExportError` if an error occurs during\r\n * any of the batch export process.\r\n */\r\nexport async function batchExport(options) {\r\n // Check if the export makes sense\r\n if (options && options.export && options.export.batch) {\r\n // Validate batch export options\r\n options = validateOptions(options);\r\n\r\n // An array for collecting batch exports\r\n const batchFunctions = [];\r\n\r\n // Split and pair the `batch` arguments\r\n for (let pair of options.export.batch.split(';') || []) {\r\n pair = pair.split('=');\r\n if (pair.length === 2) {\r\n batchFunctions.push(\r\n startExport(\r\n {\r\n export: {\r\n ...options.export,\r\n infile: pair[0],\r\n outfile: pair[1]\r\n },\r\n customLogic: options.customLogic\r\n },\r\n (error, data) => {\r\n // Exit process when error exists\r\n if (error) {\r\n throw error;\r\n }\r\n\r\n // Get the `b64`, `outfile`, and `type` for a chart\r\n const { b64, outfile, type } = data.options.export;\r\n\r\n // Save the result\r\n try {\r\n if (b64) {\r\n // As a Base64 string to a txt file\r\n writeFileSync(\r\n `${outfile.split('.').shift() || 'chart'}.txt`,\r\n getBase64(data.result, type)\r\n );\r\n } else {\r\n // As a correct image format\r\n writeFileSync(\r\n outfile,\r\n type !== 'svg'\r\n ? Buffer.from(data.result, 'base64')\r\n : data.result\r\n );\r\n }\r\n } catch (error) {\r\n throw new ExportError(\r\n '[chart] Error while saving a chart.',\r\n 500\r\n ).setError(error);\r\n }\r\n }\r\n )\r\n );\r\n } else {\r\n log(2, '[chart] No correct pair found for the batch export.');\r\n }\r\n }\r\n\r\n // Await all exports are done\r\n const batchResults = await Promise.allSettled(batchFunctions);\r\n\r\n // Kill pool and close browser after finishing batch export\r\n await killPool();\r\n\r\n // Log errors if found\r\n batchResults.forEach((result, index) => {\r\n // Log the error with stack about the specific batch export\r\n if (result.reason) {\r\n logWithStack(\r\n 1,\r\n result.reason,\r\n `[chart] Batch export number ${index + 1} could not be correctly completed.`\r\n );\r\n }\r\n });\r\n } else {\r\n throw new ExportError(\r\n '[chart] No expected `export` options were found. Please provide the `batch` option to generate valid images.',\r\n 400\r\n );\r\n }\r\n}\r\n\r\n/**\r\n * Starts an export process. The `exportingOptions` parameter is an object that\r\n * should include settings from the `export` and `customLogic` sections. It can\r\n * be a partial or complete set of options from these sections. If partial\r\n * options are provided, missing values will be merged with the current global\r\n * options.\r\n *\r\n * The `endCallback` function is invoked upon the completion of the export,\r\n * either successfully or with an error. The `error` object is provided\r\n * as the first argument, and the `data` object is the second, containing\r\n * the Base64 representation of the chart in the `result` property\r\n * and the complete set of options in the `options` property.\r\n *\r\n * @async\r\n * @function startExport\r\n *\r\n * @param {Object} exportingOptions - The `exportingOptions` object, which\r\n * should include settings from the `export` and `customLogic` sections. It can\r\n * be a partial or complete set of options from these sections. If the provided\r\n * options are partial, missing values will be merged with the current global\r\n * options.\r\n * @param {Function} endCallback - The callback function to be invoked upon\r\n * finalizing the export process or upon encountering an error. The first\r\n * argument is the `error` object, and the second argument is the `data` object,\r\n * which includes the Base64 representation of the chart in the `result`\r\n * property and the full set of options in the `options` property.\r\n *\r\n * @returns {Promise} This function does not return a value directly.\r\n * Instead, it communicates results via the `endCallback`.\r\n *\r\n * @throws {ExportError} Throws an `ExportError` if there is a problem with\r\n * processing input of any type. The error is passed into the `endCallback`\r\n * function and processed there.\r\n */\r\nexport async function startExport(exportingOptions, endCallback) {\r\n try {\r\n // Check if provided options is an object\r\n if (!isObject(exportingOptions)) {\r\n throw new ExportError(\r\n '[chart] Incorrect value of the provided `exportingOptions`. Needs to be an object.',\r\n 400\r\n );\r\n }\r\n\r\n // Merge additional options to the copy of the instance options\r\n const options = mergeOptions(deepCopy(getOptions()), {\r\n export: exportingOptions.export,\r\n customLogic: exportingOptions.customLogic\r\n });\r\n\r\n // Get the `export` options\r\n const exportOptions = options.export;\r\n\r\n // Starting exporting process message\r\n log(4, '[chart] Starting the exporting process.');\r\n\r\n // Export using options from the file as an input\r\n if (exportOptions.infile !== null) {\r\n log(4, '[chart] Attempting to export from a file input.');\r\n\r\n let fileContent;\r\n try {\r\n // Try to read the file to get the string representation\r\n fileContent = readFileSync(\r\n getAbsolutePath(exportOptions.infile),\r\n 'utf8'\r\n );\r\n } catch (error) {\r\n throw new ExportError(\r\n '[chart] Error loading content from a file input.',\r\n 400\r\n ).setError(error);\r\n }\r\n\r\n // Check the file's extension\r\n if (exportOptions.infile.endsWith('.svg')) {\r\n // Set to the `svg` option\r\n exportOptions.svg = validateOption('svg', fileContent);\r\n } else if (exportOptions.infile.endsWith('.json')) {\r\n // Set to the `instr` option\r\n exportOptions.instr = validateOption('instr', fileContent);\r\n } else {\r\n throw new ExportError(\r\n '[chart] Incorrect value of the `infile` option.',\r\n 400\r\n );\r\n }\r\n }\r\n\r\n // Export using SVG as an input\r\n if (exportOptions.svg !== null) {\r\n log(4, '[chart] Attempting to export from an SVG input.');\r\n\r\n // SVG exports attempts counter\r\n ++getPoolStats().exportsFromSvgAttempts;\r\n\r\n // Export from an SVG string\r\n const result = await _exportFromSvg(\r\n sanitize(exportOptions.svg), // #209\r\n options\r\n );\r\n\r\n // SVG exports counter\r\n ++getPoolStats().exportsFromSvg;\r\n\r\n // Pass SVG export result to the end callback\r\n return endCallback(null, result);\r\n }\r\n\r\n // Export using options as an input\r\n if (exportOptions.instr !== null || exportOptions.options !== null) {\r\n log(4, '[chart] Attempting to export from options input.');\r\n\r\n // Options exports attempts counter\r\n ++getPoolStats().exportsFromOptionsAttempts;\r\n\r\n // Export from options\r\n const result = await _exportFromOptions(\r\n exportOptions.instr || exportOptions.options,\r\n options\r\n );\r\n\r\n // Options exports counter\r\n ++getPoolStats().exportsFromOptions;\r\n\r\n // Pass options export result to the end callback\r\n return endCallback(null, result);\r\n }\r\n\r\n // No input specified, pass an error message to the callback\r\n return endCallback(\r\n new ExportError(\r\n `[chart] No valid input specified. Check if at least one of the following parameters is correctly set: 'infile', 'instr', 'options', or 'svg'.`,\r\n 400\r\n )\r\n );\r\n } catch (error) {\r\n return endCallback(error);\r\n }\r\n}\r\n\r\n/**\r\n * Retrieves and returns the current status of the code execution permission.\r\n *\r\n * @function getAllowCodeExecution\r\n *\r\n * @returns {boolean} The value of the global `allowCodeExecution` option.\r\n */\r\nexport function getAllowCodeExecution() {\r\n return allowCodeExecution;\r\n}\r\n\r\n/**\r\n * Sets the code execution permission based on the provided boolean value.\r\n *\r\n * @function setAllowCodeExecution\r\n *\r\n * @param {boolean} value - The boolean value to be assigned to the global\r\n * `allowCodeExecution` option.\r\n */\r\nexport function setAllowCodeExecution(value) {\r\n allowCodeExecution = value;\r\n}\r\n\r\n/**\r\n * Exports from an SVG based input with the provided options.\r\n *\r\n * @async\r\n * @function _exportFromSvg\r\n *\r\n * @param {string} inputToExport - The SVG based input to be exported.\r\n * @param {Object} options - The configuration object containing complete set\r\n * of options.\r\n *\r\n * @returns {Promise} A Promise that resolves to a result of the export\r\n * process.\r\n *\r\n * @throws {ExportError} Throws an `ExportError` if there is not a correct SVG\r\n * input.\r\n */\r\nasync function _exportFromSvg(inputToExport, options) {\r\n // Check if it is SVG\r\n if (\r\n typeof inputToExport === 'string' &&\r\n (inputToExport.indexOf('= 0 || inputToExport.indexOf('= 0)\r\n ) {\r\n log(4, '[chart] Parsing input as SVG.');\r\n\r\n // Set the export input as SVG\r\n options.export.svg = inputToExport;\r\n\r\n // Reset the rest of the export input options\r\n options.export.instr = null;\r\n options.export.options = null;\r\n\r\n // Call the function with an SVG string as an export input\r\n return _prepareExport(options);\r\n } else {\r\n throw new ExportError('[chart] Not a correct SVG input.', 400);\r\n }\r\n}\r\n\r\n/**\r\n * Exports from an options based input with the provided options.\r\n *\r\n * @async\r\n * @function _exportFromOptions\r\n *\r\n * @param {string} inputToExport - The options based input to be exported.\r\n * @param {Object} options - The configuration object containing complete set\r\n * of options.\r\n *\r\n * @returns {Promise} A Promise that resolves to a result of the export\r\n * process.\r\n *\r\n * @throws {ExportError} Throws an `ExportError` if there is not a correct\r\n * chart options input.\r\n */\r\nasync function _exportFromOptions(inputToExport, options) {\r\n log(4, '[chart] Parsing input from options.');\r\n\r\n // Try to check, validate and parse to stringified options\r\n const stringifiedOptions = isAllowedConfig(\r\n inputToExport,\r\n true,\r\n options.customLogic.allowCodeExecution\r\n );\r\n\r\n // Check if a correct stringified options\r\n if (\r\n stringifiedOptions === null ||\r\n typeof stringifiedOptions !== 'string' ||\r\n !stringifiedOptions.startsWith('{') ||\r\n !stringifiedOptions.endsWith('}')\r\n ) {\r\n throw new ExportError(\r\n '[chart] Invalid configuration provided - Only options configurations and SVG are allowed for this server. If this is your server, JavaScript custom code can be enabled by starting the server with the `allowCodeExecution` options set to true.',\r\n 403\r\n );\r\n }\r\n\r\n // Set the export input as a stringified chart options\r\n options.export.instr = stringifiedOptions;\r\n\r\n // Reset the rest of the export input options\r\n options.export.svg = null;\r\n\r\n // Call the function with a stringified chart options\r\n return _prepareExport(options);\r\n}\r\n\r\n/**\r\n * Function for finalizing options and configurations before export.\r\n *\r\n * @async\r\n * @function _prepareExport\r\n *\r\n * @param {Object} options - The configuration object containing complete set\r\n * of options.\r\n *\r\n * @returns {Promise} A Promise that resolves to a result of the export\r\n * process.\r\n */\r\nasync function _prepareExport(options) {\r\n const { export: exportOptions, customLogic: customLogicOptions } = options;\r\n\r\n // Prepare the `type` option\r\n exportOptions.type = fixType(exportOptions.type, exportOptions.outfile);\r\n\r\n // Prepare the `outfile` option\r\n exportOptions.outfile = fixOutfile(exportOptions.type, exportOptions.outfile);\r\n\r\n // Prepare the `constr` option\r\n exportOptions.constr = fixConstr(exportOptions.constr);\r\n\r\n // Notify about the custom logic usage status\r\n log(\r\n 3,\r\n `[chart] The custom logic is ${customLogicOptions.allowCodeExecution ? 'allowed' : 'disallowed'}.`\r\n );\r\n\r\n // Prepare the custom logic options (`customCode`, `callback`, `resources`)\r\n _handleCustomLogic(customLogicOptions, customLogicOptions.allowCodeExecution);\r\n\r\n // Prepare the `globalOptions` and `themeOptions` options\r\n _handleGlobalAndTheme(\r\n exportOptions,\r\n customLogicOptions.allowFileResources,\r\n customLogicOptions.allowCodeExecution\r\n );\r\n\r\n // Prepare the `height`, `width`, and `scale` options\r\n options.export = {\r\n ...exportOptions,\r\n ..._findChartSize(exportOptions)\r\n };\r\n\r\n // Post the work to the pool\r\n return postWork(options);\r\n}\r\n\r\n/**\r\n * Calculates the `height`, `width` and `scale` for chart exports based\r\n * on the provided export options.\r\n *\r\n * The function prioritizes values in the following order:\r\n * 1. The `height`, `width`, `scale` from the `exportOptions`.\r\n * 2. Options from the chart configuration (from `exporting` and `chart`).\r\n * 3. Options from the global options (from `exporting` and `chart`).\r\n * 4. Options from the theme options (from `exporting` and `chart` sections).\r\n * 5. Fallback default values (`height = 400`, `width = 600`, `scale = 1`).\r\n *\r\n * @function _findChartSize\r\n *\r\n * @param {Object} exportOptions - The configuration object containing `export`\r\n * options.\r\n *\r\n * @returns {Object} The object containing calculated `height`, `width`\r\n * and `scale` values for the chart export.\r\n */\r\nfunction _findChartSize(exportOptions) {\r\n // Check the `options` and `instr` for chart and exporting sections\r\n const { chart: optionsChart, exporting: optionsExporting } =\r\n exportOptions.options || isAllowedConfig(exportOptions.instr) || false;\r\n\r\n // Check the `globalOptions` for chart and exporting sections\r\n const { chart: globalOptionsChart, exporting: globalOptionsExporting } =\r\n isAllowedConfig(exportOptions.globalOptions) || false;\r\n\r\n // Check the `themeOptions` for chart and exporting sections\r\n const { chart: themeOptionsChart, exporting: themeOptionsExporting } =\r\n isAllowedConfig(exportOptions.themeOptions) || false;\r\n\r\n // Find the `scale` value:\r\n // - It cannot be lower than 0.1\r\n // - It cannot be higher than 5.0\r\n // - It must be rounded to 2 decimal places (e.g. 0.23234 -> 0.23)\r\n const scale = roundNumber(\r\n Math.max(\r\n 0.1,\r\n Math.min(\r\n exportOptions.scale ||\r\n optionsExporting?.scale ||\r\n globalOptionsExporting?.scale ||\r\n themeOptionsExporting?.scale ||\r\n exportOptions.defaultScale ||\r\n 1,\r\n 5.0\r\n )\r\n ),\r\n 2\r\n );\r\n\r\n // Find the `height` value\r\n const height =\r\n exportOptions.height ||\r\n optionsExporting?.sourceHeight ||\r\n optionsChart?.height ||\r\n globalOptionsExporting?.sourceHeight ||\r\n globalOptionsChart?.height ||\r\n themeOptionsExporting?.sourceHeight ||\r\n themeOptionsChart?.height ||\r\n exportOptions.defaultHeight ||\r\n 400;\r\n\r\n // Find the `width` value\r\n const width =\r\n exportOptions.width ||\r\n optionsExporting?.sourceWidth ||\r\n optionsChart?.width ||\r\n globalOptionsExporting?.sourceWidth ||\r\n globalOptionsChart?.width ||\r\n themeOptionsExporting?.sourceWidth ||\r\n themeOptionsChart?.width ||\r\n exportOptions.defaultWidth ||\r\n 600;\r\n\r\n // Gather `height`, `width` and `scale` information in one object\r\n const size = { height, width, scale };\r\n\r\n // Get rid of potential `px` and `%`\r\n for (let [param, value] of Object.entries(size)) {\r\n size[param] =\r\n typeof value === 'string' ? +value.replace(/px|%/gi, '') : value;\r\n }\r\n\r\n // Return the size object\r\n return size;\r\n}\r\n\r\n/**\r\n * Handles the execution of custom logic options, including loading `resources`,\r\n * `customCode`, and `callback`. If code execution is allowed, it processes\r\n * the custom logic options accordingly. If code execution is not allowed,\r\n * it disables the usage of resources, custom code and callback.\r\n *\r\n * @function _handleCustomLogic\r\n *\r\n * @param {Object} customLogicOptions - The configuration object containing\r\n * `customLogic` options.\r\n * @param {boolean} allowCodeExecution - A flag indicating whether code\r\n * execution is allowed.\r\n *\r\n * @throws {ExportError} Throws an `ExportError` if code execution\r\n * is not allowed but custom logic options are still provided.\r\n */\r\nfunction _handleCustomLogic(customLogicOptions, allowCodeExecution) {\r\n // In case of allowing code execution\r\n if (allowCodeExecution) {\r\n // Process the `resources` option\r\n if (typeof customLogicOptions.resources === 'string') {\r\n // Custom stringified resources\r\n customLogicOptions.resources = _handleResources(\r\n customLogicOptions.resources,\r\n customLogicOptions.allowFileResources,\r\n true\r\n );\r\n } else if (!customLogicOptions.resources) {\r\n try {\r\n // Load the default one\r\n customLogicOptions.resources = _handleResources(\r\n readFileSync(getAbsolutePath('resources.json'), 'utf8'),\r\n customLogicOptions.allowFileResources,\r\n true\r\n );\r\n } catch (error) {\r\n log(2, '[chart] Unable to load the default `resources.json` file.');\r\n }\r\n }\r\n\r\n // Process the `customCode` option\r\n try {\r\n // Try to load custom code and wrap around it in a self invoking function\r\n customLogicOptions.customCode = wrapAround(\r\n customLogicOptions.customCode,\r\n customLogicOptions.allowFileResources\r\n );\r\n\r\n // Validate the option\r\n customLogicOptions.customCode = validateOption(\r\n 'customCode',\r\n customLogicOptions.customCode\r\n );\r\n } catch (error) {\r\n logWithStack(2, error, '[chart] The `customCode` cannot be loaded.');\r\n\r\n // In case of an error, set the option with null\r\n customLogicOptions.customCode = null;\r\n }\r\n\r\n // Process the `callback` option\r\n try {\r\n // Try to load callback function\r\n customLogicOptions.callback = wrapAround(\r\n customLogicOptions.callback,\r\n customLogicOptions.allowFileResources,\r\n true\r\n );\r\n\r\n // Validate the option\r\n customLogicOptions.callback = validateOption(\r\n 'callback',\r\n customLogicOptions.callback\r\n );\r\n } catch (error) {\r\n logWithStack(2, error, '[chart] The `callback` cannot be loaded.');\r\n\r\n // In case of an error, set the option with null\r\n customLogicOptions.callback = null;\r\n }\r\n\r\n // Check if there is the `customCode` present\r\n if ([null, undefined].includes(customLogicOptions.customCode)) {\r\n log(3, '[chart] No value for the `customCode` option found.');\r\n }\r\n\r\n // Check if there is the `callback` present\r\n if ([null, undefined].includes(customLogicOptions.callback)) {\r\n log(3, '[chart] No value for the `callback` option found.');\r\n }\r\n\r\n // Check if there is the `resources` present\r\n if ([null, undefined].includes(customLogicOptions.resources)) {\r\n log(3, '[chart] No value for the `resources` option found.');\r\n }\r\n } else {\r\n // If the `allowCodeExecution` flag is set to false, we should refuse\r\n // the usage of the `callback`, `resources`, and `customCode` options.\r\n // Additionally, the worker will refuse to run arbitrary JavaScript.\r\n if (\r\n customLogicOptions.callback ||\r\n customLogicOptions.resources ||\r\n customLogicOptions.customCode\r\n ) {\r\n // Reset all custom code options\r\n customLogicOptions.callback = null;\r\n customLogicOptions.resources = null;\r\n customLogicOptions.customCode = null;\r\n\r\n // Send a message saying that the exporter does not support these settings\r\n throw new ExportError(\r\n `[chart] The 'callback', 'resources', and 'customCode' options have been disabled for this server.`,\r\n 403\r\n );\r\n }\r\n }\r\n}\r\n\r\n/**\r\n * Handles and validates resources from the `resources` option for export.\r\n *\r\n * @function _handleResources\r\n *\r\n * @param {(Object|string|null)} [resources=null] - The resources to be handled.\r\n * Can be either a JSON object, stringified JSON, a path to a JSON file,\r\n * or null. The default value is `null`.\r\n * @param {boolean} allowFileResources - A flag indicating whether loading\r\n * resources from files is allowed.\r\n * @param {boolean} allowCodeExecution - A flag indicating whether code\r\n * execution is allowed.\r\n *\r\n * @returns {(Object|null)} The handled resources or null if no valid resources\r\n * are found.\r\n */\r\nfunction _handleResources(\r\n resources = null,\r\n allowFileResources,\r\n allowCodeExecution\r\n) {\r\n // List of allowed sections in the resources JSON\r\n const allowedProps = ['js', 'css', 'files'];\r\n\r\n let handledResources = resources;\r\n let correctResources = false;\r\n\r\n // Try to load resources from a file\r\n if (allowFileResources && resources.endsWith('.json')) {\r\n try {\r\n handledResources = isAllowedConfig(\r\n readFileSync(getAbsolutePath(resources), 'utf8'),\r\n false,\r\n allowCodeExecution\r\n );\r\n } catch {\r\n return null;\r\n }\r\n } else {\r\n // Try to get JSON\r\n handledResources = isAllowedConfig(resources, false, allowCodeExecution);\r\n\r\n // Get rid of the files section\r\n if (handledResources && !allowFileResources) {\r\n delete handledResources.files;\r\n }\r\n }\r\n\r\n // Filter from unnecessary properties\r\n for (const propName in handledResources) {\r\n if (!allowedProps.includes(propName)) {\r\n delete handledResources[propName];\r\n } else if (!correctResources) {\r\n correctResources = true;\r\n }\r\n }\r\n\r\n // Check if at least one of allowed properties is present\r\n if (!correctResources) {\r\n return null;\r\n }\r\n\r\n // Handle files section\r\n if (handledResources.files) {\r\n handledResources.files = handledResources.files.map((item) => item.trim());\r\n if (!handledResources.files || handledResources.files.length <= 0) {\r\n delete handledResources.files;\r\n }\r\n }\r\n\r\n // Validate option\r\n handledResources = validateOption('resources', handledResources);\r\n\r\n // Return resources\r\n return handledResources;\r\n}\r\n\r\n/**\r\n * Handles the loading and validation of the `globalOptions` and `themeOptions`\r\n * in the export options. If the option is a string and references a JSON file\r\n * (when the `allowFileResources` is true), it reads and parses the file.\r\n * Otherwise, it attempts to parse the string or object as JSON. If any errors\r\n * occur during this process, the option is set to null. If there is an error\r\n * loading or parsing the `globalOptions` or `themeOptions`, the error is logged\r\n * and the option is set to null.\r\n *\r\n * @function _handleGlobalAndTheme\r\n *\r\n * @param {Object} exportOptions - The configuration object containing `export`\r\n * options.\r\n * @param {boolean} allowFileResources - A flag indicating whether loading\r\n * resources from files is allowed.\r\n * @param {boolean} allowCodeExecution - A flag indicating whether code\r\n * execution is allowed.\r\n */\r\nfunction _handleGlobalAndTheme(\r\n exportOptions,\r\n allowFileResources,\r\n allowCodeExecution\r\n) {\r\n // Check the `globalOptions` and `themeOptions` options\r\n ['globalOptions', 'themeOptions'].forEach((optionsName) => {\r\n try {\r\n // Check if the option exists\r\n if (exportOptions[optionsName]) {\r\n // Check if it is a string and a file name with the `.json` extension\r\n if (\r\n allowFileResources &&\r\n typeof exportOptions[optionsName] === 'string' &&\r\n exportOptions[optionsName].endsWith('.json')\r\n ) {\r\n // Check if the file content can be a config, and save it as a string\r\n exportOptions[optionsName] = isAllowedConfig(\r\n readFileSync(getAbsolutePath(exportOptions[optionsName]), 'utf8'),\r\n true,\r\n allowCodeExecution\r\n );\r\n } else {\r\n // Check if the value can be a config, and save it as a string\r\n exportOptions[optionsName] = isAllowedConfig(\r\n exportOptions[optionsName],\r\n true,\r\n allowCodeExecution\r\n );\r\n }\r\n\r\n // Validate the option\r\n exportOptions[optionsName] = validateOption(\r\n optionsName,\r\n exportOptions[optionsName]\r\n );\r\n }\r\n } catch (error) {\r\n logWithStack(\r\n 2,\r\n error,\r\n `[chart] The \\`${optionsName}\\` cannot be loaded.`\r\n );\r\n\r\n // In case of an error, set the option with null\r\n exportOptions[optionsName] = null;\r\n }\r\n });\r\n\r\n // Check if there is the `globalOptions` present\r\n if ([null, undefined].includes(exportOptions.globalOptions)) {\r\n log(3, '[chart] No value for the `globalOptions` option found.');\r\n }\r\n\r\n // Check if there is the `themeOptions` present\r\n if ([null, undefined].includes(exportOptions.themeOptions)) {\r\n log(3, '[chart] No value for the `themeOptions` option found.');\r\n }\r\n}\r\n\r\nexport default {\r\n singleExport,\r\n batchExport,\r\n startExport,\r\n getAllowCodeExecution,\r\n setAllowCodeExecution\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * @overview This module provides utility functions for managing intervals\r\n * and timeouts in a centralized manner. It maintains a registry of all active\r\n * timers and allows for their efficient cleanup when needed. This can be useful\r\n * in applications where proper resource management and clean shutdown of timers\r\n * are critical to avoid memory leaks or unintended behavior.\r\n */\r\n\r\nimport { log } from './logger.js';\r\n\r\n// Array that contains ids of all ongoing intervals and timeouts\r\nconst timerIds = [];\r\n\r\n/**\r\n * Adds id of the `setInterval` or `setTimeout` and to the `timerIds` array.\r\n *\r\n * @function addTimer\r\n *\r\n * @param {NodeJS.Timeout} id - Id of an interval or a timeout.\r\n */\r\nexport function addTimer(id) {\r\n timerIds.push(id);\r\n}\r\n\r\n/**\r\n * Clears all of ongoing intervals and timeouts by ids gathered\r\n * in the `timerIds` array.\r\n *\r\n * @function clearAllTimers\r\n */\r\nexport function clearAllTimers() {\r\n log(4, `[timer] Clearing all registered intervals and timeouts.`);\r\n for (const id of timerIds) {\r\n clearInterval(id);\r\n clearTimeout(id);\r\n }\r\n}\r\n\r\nexport default {\r\n addTimer,\r\n clearAllTimers\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * @overview Provides middleware functions for logging errors with stack traces\r\n * and handling error responses in an Express application.\r\n */\r\n\r\nimport { getOptions } from '../../config.js';\r\nimport { logWithStack } from '../../logger.js';\r\n\r\n/**\r\n * Middleware for logging errors with stack trace and handling error response.\r\n *\r\n * @function logErrorMiddleware\r\n *\r\n * @param {Error} error - The error object.\r\n * @param {Express.Request} request - The Express request object.\r\n * @param {Express.Response} response - The Express response object.\r\n * @param {Function} next - The next middleware function.\r\n *\r\n * @returns {undefined} The call to the next middleware function with\r\n * the passed error.\r\n */\r\nfunction logErrorMiddleware(error, request, response, next) {\r\n // Display the error with stack in a correct format\r\n logWithStack(1, error);\r\n\r\n // Delete the stack for the environment other than the development\r\n if (getOptions().other.nodeEnv !== 'development') {\r\n delete error.stack;\r\n }\r\n\r\n // Call the `returnErrorMiddleware` middleware\r\n return next(error);\r\n}\r\n\r\n/**\r\n * Middleware for returning error response.\r\n *\r\n * @function returnErrorMiddleware\r\n *\r\n * @param {Error} error - The error object.\r\n * @param {Express.Request} request - The Express request object.\r\n * @param {Express.Response} response - The Express response object.\r\n * @param {Function} next - The next middleware function.\r\n */\r\nfunction returnErrorMiddleware(error, request, response, next) {\r\n // Gather all requied information for the response\r\n const { message, stack } = error;\r\n\r\n // Use the error's status code or the default 400\r\n const statusCode = error.statusCode || 400;\r\n\r\n // Set and return response\r\n response.status(statusCode).json({ statusCode, message, stack });\r\n}\r\n\r\n/**\r\n * Adds the error middlewares to the passed express app instance.\r\n *\r\n * @param {Express} app - The Express app instance.\r\n */\r\nexport default function errorMiddleware(app) {\r\n // Add log error middleware\r\n app.use(logErrorMiddleware);\r\n\r\n // Add set status and return error middleware\r\n app.use(returnErrorMiddleware);\r\n}\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * @overview Provides middleware functions for configuring and enabling rate\r\n * limiting in an Express application.\r\n */\r\n\r\nimport rateLimit from 'express-rate-limit';\r\n\r\nimport { log } from '../../logger.js';\r\n\r\nimport ExportError from '../../errors/ExportError.js';\r\n\r\n/**\r\n * Middleware for enabling rate limiting on the specified Express app.\r\n *\r\n * @param {Express} app - The Express app instance.\r\n *\r\n * @param {Object} rateLimitingOptions - The configuration object containing\r\n * `rateLimiting` options.\r\n *\r\n * @throws {ExportError} Throws an `ExportError` if could not configure and set\r\n * the rate limiting options.\r\n */\r\nexport default function rateLimitingMiddleware(app, rateLimitingOptions) {\r\n try {\r\n // Check if the rate limiting is enabled\r\n if (rateLimitingOptions.enable) {\r\n const message =\r\n 'Too many requests, you have been rate limited. Please try again later.';\r\n\r\n // Options for the rate limiter\r\n const rateOptions = {\r\n window: rateLimitingOptions.window || 1,\r\n maxRequests: rateLimitingOptions.maxRequests || 30,\r\n delay: rateLimitingOptions.delay || 0,\r\n trustProxy: rateLimitingOptions.trustProxy || false,\r\n skipKey: rateLimitingOptions.skipKey || null,\r\n skipToken: rateLimitingOptions.skipToken || null\r\n };\r\n\r\n // Set if behind a proxy\r\n if (rateOptions.trustProxy) {\r\n app.enable('trust proxy');\r\n }\r\n\r\n // Create a limiter\r\n const limiter = rateLimit({\r\n // Time frame for which requests are checked and remembered\r\n windowMs: rateOptions.window * 60 * 1000,\r\n // Limit each IP to 100 requests per `windowMs`\r\n limit: rateOptions.maxRequests,\r\n // Disable delaying, full speed until the max limit is reached\r\n delayMs: rateOptions.delay,\r\n handler: (request, response) => {\r\n response.format({\r\n json: () => {\r\n response.status(429).send({ message });\r\n },\r\n default: () => {\r\n response.status(429).send(message);\r\n }\r\n });\r\n },\r\n skip: (request) => {\r\n // Allow bypassing the limiter if a valid key/token has been sent\r\n if (\r\n rateOptions.skipKey !== null &&\r\n rateOptions.skipToken !== null &&\r\n request.query.key === rateOptions.skipKey &&\r\n request.query.access_token === rateOptions.skipToken\r\n ) {\r\n log(4, '[rate limiting] Skipping rate limiter.');\r\n return true;\r\n }\r\n return false;\r\n }\r\n });\r\n\r\n // Use a limiter as a middleware\r\n app.use(limiter);\r\n\r\n log(\r\n 3,\r\n `[rate limiting] Enabled rate limiting with ${rateOptions.maxRequests} requests per ${rateOptions.window} minute for each IP, trusting proxy: ${rateOptions.trustProxy}.`\r\n );\r\n }\r\n } catch (error) {\r\n throw new ExportError(\r\n '[rate limiting] Could not configure and set the rate limiting options.',\r\n 500\r\n ).setError(error);\r\n }\r\n}\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * @overview Provides middleware functions for validating incoming HTTP requests\r\n * in an Express application. This module ensures that requests contain\r\n * appropriate content types and valid request bodies, including proper JSON\r\n * structures and chart data for exports. It checks for potential issues such\r\n * as missing or malformed data, private range URLs in SVG payloads, and allows\r\n * for flexible options validation. The middleware logs detailed information\r\n * and handles errors related to incorrect payloads, chart data, and private URL\r\n * usage.\r\n */\r\n\r\nimport { v4 as uuid } from 'uuid';\r\n\r\nimport { getAllowCodeExecution } from '../../chart.js';\r\nimport { isAllowedConfig, validateOptions } from '../../config.js';\r\nimport { log } from '../../logger.js';\r\nimport { isObjectEmpty, isPrivateRangeUrlFound } from '../../utils.js';\r\n\r\nimport ExportError from '../../errors/ExportError.js';\r\n\r\n/**\r\n * Middleware for validating the content-type header.\r\n *\r\n * @function contentTypeMiddleware\r\n *\r\n * @param {Express.Request} request - The Express request object.\r\n * @param {Express.Response} response - The Express response object.\r\n * @param {Function} next - The next middleware function.\r\n *\r\n * @returns {undefined} The call to the next middleware function.\r\n *\r\n * @throws {ExportError} Throws an `ExportError` if the content-type\r\n * is not correct.\r\n */\r\nfunction contentTypeMiddleware(request, response, next) {\r\n try {\r\n // Get the content type header\r\n const contentType = request.headers['content-type'] || '';\r\n\r\n // Allow only JSON, URL-encoded and form data without files types of data\r\n if (\r\n !contentType.includes('application/json') &&\r\n !contentType.includes('application/x-www-form-urlencoded') &&\r\n !contentType.includes('multipart/form-data')\r\n ) {\r\n throw new ExportError(\r\n '[validation] Content-Type must be application/json, application/x-www-form-urlencoded, or multipart/form-data.',\r\n 415\r\n );\r\n }\r\n\r\n // Call the `requestBodyMiddleware` middleware\r\n return next();\r\n } catch (error) {\r\n return next(error);\r\n }\r\n}\r\n\r\n/**\r\n * Middleware for validating the request's body.\r\n *\r\n * @function requestBodyMiddleware\r\n *\r\n * @param {Express.Request} request - The Express request object.\r\n * @param {Express.Response} response - The Express response object.\r\n * @param {Function} next - The next middleware function.\r\n *\r\n * @returns {undefined} The call to the next middleware function.\r\n *\r\n * @throws {ExportError} Throws an `ExportError` if the body is not correct.\r\n * @throws {ExportError} Throws an `ExportError` if the chart data from the body\r\n * is not correct.\r\n * @throws {ExportError} Throws an `ExportError` in case of the private range\r\n * url error.\r\n */\r\nfunction requestBodyMiddleware(request, response, next) {\r\n try {\r\n // Get the request body\r\n const body = request.body;\r\n\r\n // Create a unique ID for a request\r\n const requestId = uuid();\r\n\r\n // Throw an error if there is no correct body\r\n if (!body || isObjectEmpty(body)) {\r\n log(\r\n 2,\r\n `[validation] Request [${requestId}] - The request from ${\r\n request.headers['x-forwarded-for'] || request.connection.remoteAddress\r\n } was incorrect. Received payload is empty.`\r\n );\r\n\r\n throw new ExportError(\r\n `[validation] Request [${requestId}] - The request body is required. Please ensure that your Content-Type header is correct. Accepted types are 'application/json' and 'multipart/form-data'.`,\r\n 400\r\n );\r\n }\r\n\r\n // Get the `allowCodeExecution` option for the server\r\n const allowCodeExecution = getAllowCodeExecution();\r\n\r\n // Find a correct chart options\r\n const instr = isAllowedConfig(\r\n // Use one of the below\r\n body.instr || body.options || body.infile || body.data,\r\n // Stringify options\r\n true,\r\n // Allow or disallow functions\r\n allowCodeExecution\r\n );\r\n\r\n // Throw an error if there is no correct chart data\r\n if (instr === null && !body.svg) {\r\n log(\r\n 2,\r\n `[validation] Request [${requestId}] - The request from ${\r\n request.headers['x-forwarded-for'] || request.connection.remoteAddress\r\n } was incorrect. Received payload is missing correct chart data for export: ${JSON.stringify(body)}.`\r\n );\r\n\r\n throw new ExportError(\r\n `Request [${requestId}] - [validation] No correct chart data found. Ensure that you are using either application/json or multipart/form-data headers. If sending JSON, make sure the chart data is in the 'infile', 'options', or 'data' attribute. If sending SVG, ensure it is in the 'svg' attribute.`,\r\n 400\r\n );\r\n }\r\n\r\n // Throw an error if test of xlink:href elements from payload's SVG fails\r\n if (body.svg && isPrivateRangeUrlFound(body.svg)) {\r\n throw new ExportError(\r\n `Request [${requestId}] - [validation] SVG potentially contain at least one forbidden URL in 'xlink:href' element. Please review the SVG content and ensure that all referenced URLs comply with security policies.`,\r\n 400\r\n );\r\n }\r\n\r\n // Validate the request options and store parsed structure in the request\r\n request.validatedOptions = validateOptions({\r\n // Set the created ID as a `requestId` property in the options\r\n requestId,\r\n export: {\r\n instr,\r\n svg: body.svg,\r\n outfile:\r\n body.outfile ||\r\n `${request.params.filename || 'chart'}.${body.type || 'png'}`,\r\n type: body.type,\r\n constr: body.constr,\r\n b64: body.b64,\r\n noDownload: body.noDownload,\r\n height: body.height,\r\n width: body.width,\r\n scale: body.scale,\r\n globalOptions: isAllowedConfig(\r\n body.globalOptions,\r\n true,\r\n allowCodeExecution\r\n ),\r\n themeOptions: isAllowedConfig(\r\n body.themeOptions,\r\n true,\r\n allowCodeExecution\r\n )\r\n },\r\n customLogic: {\r\n allowCodeExecution,\r\n allowFileResources: false,\r\n customCode: body.customCode,\r\n callback: body.callback,\r\n resources: isAllowedConfig(body.resources, true, allowCodeExecution)\r\n }\r\n });\r\n\r\n // Call the next middleware\r\n return next();\r\n } catch (error) {\r\n return next(error);\r\n }\r\n}\r\n\r\n/**\r\n * Adds the validation middlewares to the passed express app instance.\r\n *\r\n * @param {Express} app - The Express app instance.\r\n */\r\nexport default function validationMiddleware(app) {\r\n // Add content type validation middleware\r\n app.post(['/', '/:filename'], contentTypeMiddleware);\r\n\r\n // Add request body request validation middleware\r\n app.post(['/', '/:filename'], requestBodyMiddleware);\r\n}\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * @overview Defines the export routes and logic for handling chart export\r\n * requests in an Express server. This module processes incoming requests\r\n * to export charts in various formats (e.g. JPEG, PNG, PDF, SVG). It integrates\r\n * with Highcharts' core functionalities and supports both immediate download\r\n * responses and Base64-encoded content returns. The code also features\r\n * benchmarking for performance monitoring.\r\n */\r\n\r\nimport { startExport } from '../../chart.js';\r\nimport { log } from '../../logger.js';\r\nimport { getBase64, measureTime } from '../../utils.js';\r\n\r\nimport ExportError from '../../errors/ExportError.js';\r\n\r\n// Reversed MIME types\r\nconst reversedMime = {\r\n png: 'image/png',\r\n jpeg: 'image/jpeg',\r\n gif: 'image/gif',\r\n pdf: 'application/pdf',\r\n svg: 'image/svg+xml'\r\n};\r\n\r\n/**\r\n * Handles the export requests from the client.\r\n *\r\n * @async\r\n * @function requestExport\r\n *\r\n * @param {Express.Request} request - The Express request object.\r\n * @param {Express.Response} response - The Express response object.\r\n * @param {Function} next - The next middleware function.\r\n *\r\n * @returns {Promise} A Promise that resolves once the export process\r\n * is complete.\r\n */\r\nasync function requestExport(request, response, next) {\r\n try {\r\n // Start counting time for a request\r\n const requestCounter = measureTime();\r\n\r\n // In case the connection is closed, force to abort further actions\r\n let connectionAborted = false;\r\n request.socket.on('close', (hadErrors) => {\r\n if (hadErrors) {\r\n connectionAborted = true;\r\n }\r\n });\r\n\r\n // Get the options previously validated in the validation middleware\r\n const requestOptions = request.validatedOptions;\r\n\r\n // Get the request id\r\n const requestId = requestOptions.requestId;\r\n\r\n // Info about an incoming request with correct data\r\n log(4, `[export] Request [${requestId}] - Got an incoming HTTP request.`);\r\n\r\n // Start the export process\r\n await startExport(requestOptions, (error, data) => {\r\n // Remove the close event from the socket\r\n request.socket.removeAllListeners('close');\r\n\r\n // If the connection was closed, do nothing\r\n if (connectionAborted) {\r\n log(\r\n 3,\r\n `[export] Request [${requestId}] - The client closed the connection before the chart finished processing.`\r\n );\r\n return;\r\n }\r\n\r\n // If error, log it and send it to the error middleware\r\n if (error) {\r\n throw error;\r\n }\r\n\r\n // If data is missing, log the message and send it to the error middleware\r\n if (!data || !data.result) {\r\n log(\r\n 2,\r\n `[export] Request [${requestId}] - Request from ${\r\n request.headers['x-forwarded-for'] ||\r\n request.connection.remoteAddress\r\n } was incorrect. Received result is ${data.result}.`\r\n );\r\n\r\n throw new ExportError(\r\n `[export] Request [${requestId}] - Unexpected return of the export result from the chart generation. Please check your request data.`,\r\n 400\r\n );\r\n }\r\n\r\n // Return the result in an appropriate format\r\n if (data.result) {\r\n log(\r\n 3,\r\n `[export] Request [${requestId}] - The whole exporting process took ${requestCounter()}ms.`\r\n );\r\n\r\n // Get the `type`, `b64`, `noDownload`, and `outfile` from options\r\n const { type, b64, noDownload, outfile } = data.options.export;\r\n\r\n // If only Base64 is required, return it\r\n if (b64) {\r\n return response.send(getBase64(data.result, type));\r\n }\r\n\r\n // Set correct content type\r\n response.header('Content-Type', reversedMime[type] || 'image/png');\r\n\r\n // Decide whether to download or not chart file\r\n if (!noDownload) {\r\n response.attachment(outfile);\r\n }\r\n\r\n // If SVG, return plain content, otherwise a b64 string from a buffer\r\n return type === 'svg'\r\n ? response.send(data.result)\r\n : response.send(Buffer.from(data.result, 'base64'));\r\n }\r\n });\r\n } catch (error) {\r\n return next(error);\r\n }\r\n}\r\n\r\n/**\r\n * Adds the `export` routes.\r\n *\r\n * @function exportRoutes\r\n *\r\n * @param {Express} app - The Express app instance.\r\n */\r\nexport default function exportRoutes(app) {\r\n /**\r\n * Adds the POST '/' - A route for handling POST requests at the root\r\n * endpoint.\r\n */\r\n app.post('/', requestExport);\r\n\r\n /**\r\n * Adds the POST '/:filename' - A route for handling POST requests with\r\n * a specified filename parameter.\r\n */\r\n app.post('/:filename', requestExport);\r\n}\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * @overview Defines an Express route for server health monitoring, including\r\n * uptime, success rates, and other server statistics.\r\n */\r\n\r\nimport { readFileSync } from 'fs';\r\nimport { join } from 'path';\r\n\r\nimport { getHighchartsVersion } from '../../cache.js';\r\nimport { log } from '../../logger.js';\r\nimport { getPoolInfoJSON, getPoolStats } from '../../pool.js';\r\nimport { addTimer } from '../../timer.js';\r\nimport { __dirname, getNewDateTime } from '../../utils.js';\r\n\r\n// Set the start date of the server\r\nconst serverStartTime = new Date();\r\n\r\n// Get the `package.json` content\r\nconst packageFile = JSON.parse(\r\n readFileSync(join(__dirname, 'package.json'), 'utf8')\r\n);\r\n\r\n// An array for success rate ratios\r\nconst successRates = [];\r\n\r\n// Record every minute\r\nconst recordInterval = 60 * 1000;\r\n\r\n// 30 minutes\r\nconst windowSize = 30;\r\n\r\n/**\r\n * Calculates moving average indicator based on the data from the `successRates`\r\n * array.\r\n *\r\n * @function _calculateMovingAverage\r\n *\r\n * @returns {number} A moving average for success ratio of the server exports.\r\n */\r\nfunction _calculateMovingAverage() {\r\n return successRates.reduce((a, b) => a + b, 0) / successRates.length;\r\n}\r\n\r\n/**\r\n * Starts the interval responsible for calculating current success rate ratio\r\n * and collects records to the `successRates` array.\r\n *\r\n * @function _startSuccessRate\r\n *\r\n * @returns {NodeJS.Timeout} Id of an interval.\r\n */\r\nfunction _startSuccessRate() {\r\n return setInterval(() => {\r\n const stats = getPoolStats();\r\n const successRatio =\r\n stats.exportsAttempted === 0\r\n ? 1\r\n : (stats.exportsPerformed / stats.exportsAttempted) * 100;\r\n\r\n successRates.push(successRatio);\r\n if (successRates.length > windowSize) {\r\n successRates.shift();\r\n }\r\n }, recordInterval);\r\n}\r\n\r\n/**\r\n * Adds the `health` routes.\r\n *\r\n * @function healthRoutes\r\n *\r\n * @param {Express} app - The Express app instance.\r\n */\r\nexport default function healthRoutes(app) {\r\n // Start processing success rate ratio interval and save its id to the array\r\n // for the graceful clearing on shutdown with injected `addTimer` funtion\r\n addTimer(_startSuccessRate());\r\n\r\n /**\r\n * Adds the GET '/health' - A route for getting the basic stats of the server.\r\n */\r\n app.get('/health', (request, response, next) => {\r\n try {\r\n log(4, '[health] Returning server health.');\r\n\r\n const stats = getPoolStats();\r\n const period = successRates.length;\r\n const movingAverage = _calculateMovingAverage();\r\n\r\n // Send the server's statistics\r\n response.send({\r\n // Status and times\r\n status: 'OK',\r\n bootTime: serverStartTime,\r\n uptime: `${Math.floor((getNewDateTime() - serverStartTime.getTime()) / 1000 / 60)} minutes`,\r\n\r\n // Versions\r\n serverVersion: packageFile.version,\r\n highchartsVersion: getHighchartsVersion(),\r\n\r\n // Exports\r\n averageExportTime: stats.timeSpentAverage,\r\n attemptedExports: stats.exportsAttempted,\r\n performedExports: stats.exportsPerformed,\r\n failedExports: stats.exportsDropped,\r\n sucessRatio: (stats.exportsPerformed / stats.exportsAttempted) * 100,\r\n\r\n // Pool\r\n pool: getPoolInfoJSON(),\r\n\r\n // Moving average\r\n period,\r\n movingAverage,\r\n message:\r\n isNaN(movingAverage) || !successRates.length\r\n ? 'Too early to report. No exports made yet. Please check back soon.'\r\n : `Last ${period} minutes had a success rate of ${movingAverage.toFixed(2)}%.`,\r\n\r\n // SVG and JSON exports\r\n svgExports: stats.exportsFromSvg,\r\n jsonExports: stats.exportsFromOptions,\r\n svgExportsAttempts: stats.exportsFromSvgAttempts,\r\n jsonExportsAttempts: stats.exportsFromOptionsAttempts\r\n });\r\n } catch (error) {\r\n return next(error);\r\n }\r\n });\r\n}\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * @overview Defines an Express route for serving the UI for the export server\r\n * when enabled.\r\n */\r\n\r\nimport { join } from 'path';\r\n\r\nimport { getOptions } from '../../config.js';\r\nimport { log } from '../../logger.js';\r\nimport { __dirname } from '../../utils.js';\r\n\r\n/**\r\n * Adds the `ui` routes.\r\n *\r\n * @function uiRoutes\r\n *\r\n * @param {Express} app - The Express app instance.\r\n */\r\nexport default function uiRoutes(app) {\r\n /**\r\n * Adds the GET '/' - A route for a UI when enabled on the export server.\r\n */\r\n app.get(getOptions().ui.route || '/', (request, response, next) => {\r\n try {\r\n log(4, '[ui] Returning UI for the export.');\r\n\r\n response.sendFile(join(__dirname, 'public', 'index.html'), {\r\n acceptRanges: false\r\n });\r\n } catch (error) {\r\n return next(error);\r\n }\r\n });\r\n}\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * @overview Defines an Express route for updating the Highcharts version\r\n * on the server, with authentication and validation.\r\n */\r\n\r\nimport { getHighchartsVersion, updateHighchartsVersion } from '../../cache.js';\r\nimport { validateOption } from '../../config.js';\r\nimport { log } from '../../logger.js';\r\nimport { envs } from '../../validation.js';\r\n\r\nimport ExportError from '../../errors/ExportError.js';\r\n\r\n/**\r\n * Adds the `version_change` routes.\r\n *\r\n * @function versionChangeRoutes\r\n *\r\n * @param {Express} app - The Express app instance.\r\n */\r\nexport default function versionChangeRoutes(app) {\r\n /**\r\n * Adds the POST '/version_change/:newVersion' - A route for changing\r\n * the Highcharts version on the server.\r\n */\r\n app.post('/version_change/:newVersion', async (request, response, next) => {\r\n try {\r\n log(4, '[version] Changing Highcharts version.');\r\n\r\n // Get the token directly from envs\r\n const adminToken = envs.HIGHCHARTS_ADMIN_TOKEN;\r\n\r\n // Check the existence of the token\r\n if (!adminToken || !adminToken.length) {\r\n throw new ExportError(\r\n '[version] The server is not configured to perform run-time version changes: HIGHCHARTS_ADMIN_TOKEN is not set.',\r\n 401\r\n );\r\n }\r\n\r\n // Get the token from the hc-auth header\r\n const token = request.get('hc-auth');\r\n\r\n // Check if the hc-auth header contain a correct token\r\n if (!token || token !== adminToken) {\r\n throw new ExportError(\r\n '[version] Invalid or missing token: Set the token in the hc-auth header.',\r\n 401\r\n );\r\n }\r\n\r\n // Compare versions\r\n let newVersion = request.params.newVersion;\r\n\r\n // Validate the version\r\n try {\r\n newVersion = validateOption('version', request.params.newVersion);\r\n } catch (error) {\r\n throw new ExportError(\r\n `[version] Version is incorrect: ${error.message}`,\r\n 400\r\n ).setError(error);\r\n }\r\n\r\n // When a correct value found\r\n if (newVersion) {\r\n try {\r\n // Update version\r\n await updateHighchartsVersion(newVersion);\r\n } catch (error) {\r\n throw new ExportError(\r\n `[version] Version change: ${error.message}`,\r\n 400\r\n ).setError(error);\r\n }\r\n\r\n // Success\r\n response.status(200).send({\r\n statusCode: 200,\r\n highchartsVersion: getHighchartsVersion(),\r\n message: `Successfully updated Highcharts to version: ${newVersion}.`\r\n });\r\n } else {\r\n // No version specified\r\n throw new ExportError('[version] No new version supplied.', 400);\r\n }\r\n } catch (error) {\r\n return next(error);\r\n }\r\n });\r\n}\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * @overview A module that sets up and manages HTTP and HTTPS servers\r\n * for the Highcharts Export Server. It handles server initialization,\r\n * configuration, error handling, middleware setup, route definition, and rate\r\n * limiting. The module exports functions to start, stop, and manage server\r\n * instances, as well as utility functions for defining routes and attaching\r\n * middlewares.\r\n */\r\n\r\nimport { readFile } from 'fs/promises';\r\nimport { join } from 'path';\r\n\r\nimport cors from 'cors';\r\nimport express from 'express';\r\nimport http from 'http';\r\nimport https from 'https';\r\nimport multer from 'multer';\r\n\r\nimport { updateOptions, validateOptions } from '../config.js';\r\nimport { log, logWithStack } from '../logger.js';\r\nimport { __dirname, getAbsolutePath } from '../utils.js';\r\n\r\nimport errorMiddleware from './middlewares/error.js';\r\nimport rateLimitingMiddleware from './middlewares/rateLimiting.js';\r\nimport validationMiddleware from './middlewares/validation.js';\r\n\r\nimport exportRoutes from './routes/export.js';\r\nimport healthRoutes from './routes/health.js';\r\nimport uiRoutes from './routes/ui.js';\r\nimport versionChangeRoutes from './routes/versionChange.js';\r\n\r\nimport ExportError from '../errors/ExportError.js';\r\n\r\n// Array of an active servers\r\nconst activeServers = new Map();\r\n\r\n// Create express app\r\nconst app = express();\r\n\r\n/**\r\n * Starts an HTTP and/or HTTPS server based on the provided configuration.\r\n * The `serverOptions` object contains server-related properties (refer\r\n * to the `server` section in the `lib/schemas/config.js` file for details).\r\n *\r\n * @async\r\n * @function startServer\r\n *\r\n * @param {Object} serverOptions - The configuration object containing `server`\r\n * options. This object may include a partial or complete set of the `server`\r\n * options. If the options are partial, missing values will default\r\n * to the current global configuration.\r\n *\r\n * @returns {Promise} A Promise that resolves when the server is either\r\n * not enabled or no valid Express app is found, signaling the end of the\r\n * function's execution.\r\n *\r\n * @throws {ExportError} Throws an `ExportError` if the server cannot\r\n * be configured and started.\r\n */\r\nexport async function startServer(serverOptions) {\r\n try {\r\n // Update the instance options object\r\n const options = updateOptions(\r\n validateOptions({\r\n server: serverOptions\r\n })\r\n );\r\n\r\n // Use validated options\r\n serverOptions = options.server;\r\n\r\n // Stop if not enabled\r\n if (!serverOptions.enable || !app) {\r\n throw new ExportError(\r\n '[server] Server cannot be started (not enabled or no correct Express app found).',\r\n 500\r\n );\r\n }\r\n\r\n // Too big limits lead to timeouts in the export process when\r\n // the rasterization timeout is set too low\r\n const uploadLimitBytes = serverOptions.uploadLimit * 1024 * 1024;\r\n\r\n // Memory storage for multer package\r\n const storage = multer.memoryStorage();\r\n\r\n // Enable parsing of form data (files) with multer package\r\n const upload = multer({\r\n storage,\r\n limits: {\r\n fieldSize: uploadLimitBytes\r\n }\r\n });\r\n\r\n // Disable the X-Powered-By header\r\n app.disable('x-powered-by');\r\n\r\n // Enable CORS support\r\n app.use(\r\n cors({\r\n methods: ['POST', 'GET', 'OPTIONS']\r\n })\r\n );\r\n\r\n // Getting a lot of `RangeNotSatisfiableError` exceptions (even though this\r\n // is a deprecated options, let's try to set it to false)\r\n app.use((request, response, next) => {\r\n response.set('Accept-Ranges', 'none');\r\n next();\r\n });\r\n\r\n // Enable body parser for JSON data\r\n app.use(\r\n express.json({\r\n limit: uploadLimitBytes\r\n })\r\n );\r\n\r\n // Enable body parser for URL-encoded form data\r\n app.use(\r\n express.urlencoded({\r\n extended: true,\r\n limit: uploadLimitBytes\r\n })\r\n );\r\n\r\n // Use only non-file multipart form fields\r\n app.use(upload.none());\r\n\r\n // Set up static folder's route\r\n app.use(express.static(join(__dirname, 'public')));\r\n\r\n // Listen HTTP server\r\n if (!serverOptions.ssl.force) {\r\n // Main server instance (HTTP)\r\n const httpServer = http.createServer(app);\r\n\r\n // Attach error handlers and listen to the server\r\n _attachServerErrorHandlers(httpServer);\r\n\r\n // Listen\r\n httpServer.listen(serverOptions.port, serverOptions.host, () => {\r\n // Save the reference to HTTP server\r\n activeServers.set(serverOptions.port, httpServer);\r\n\r\n log(\r\n 3,\r\n `[server] Started HTTP server on ${serverOptions.host}:${serverOptions.port}.`\r\n );\r\n });\r\n }\r\n\r\n // Listen HTTPS server\r\n if (serverOptions.ssl.enable) {\r\n // Set up an SSL server also\r\n let key, cert;\r\n\r\n try {\r\n // Get the SSL key\r\n key = await readFile(\r\n join(getAbsolutePath(serverOptions.ssl.certPath), 'server.key'),\r\n 'utf8'\r\n );\r\n\r\n // Get the SSL certificate\r\n cert = await readFile(\r\n join(getAbsolutePath(serverOptions.ssl.certPath), 'server.crt'),\r\n 'utf8'\r\n );\r\n } catch (error) {\r\n log(\r\n 2,\r\n `[server] Unable to load key/certificate from the '${serverOptions.ssl.certPath}' path. Could not run secured layer server.`\r\n );\r\n }\r\n\r\n if (key && cert) {\r\n // Main server instance (HTTPS)\r\n const httpsServer = https.createServer({ key, cert }, app);\r\n\r\n // Attach error handlers and listen to the server\r\n _attachServerErrorHandlers(httpsServer);\r\n\r\n // Listen\r\n httpsServer.listen(serverOptions.ssl.port, serverOptions.host, () => {\r\n // Save the reference to HTTPS server\r\n activeServers.set(serverOptions.ssl.port, httpsServer);\r\n\r\n log(\r\n 3,\r\n `[server] Started HTTPS server on ${serverOptions.host}:${serverOptions.ssl.port}.`\r\n );\r\n });\r\n }\r\n }\r\n\r\n // Set up the rate limiter\r\n rateLimitingMiddleware(app, serverOptions.rateLimiting);\r\n\r\n // Set up the validation handler\r\n validationMiddleware(app);\r\n\r\n // Set up routes\r\n exportRoutes(app);\r\n healthRoutes(app);\r\n uiRoutes(app);\r\n versionChangeRoutes(app);\r\n\r\n // Set up the centralized error handler\r\n errorMiddleware(app);\r\n } catch (error) {\r\n throw new ExportError(\r\n '[server] Could not configure and start the server.',\r\n 500\r\n ).setError(error);\r\n }\r\n}\r\n\r\n/**\r\n * Closes all servers associated with Express app instance.\r\n *\r\n * @function closeServers\r\n */\r\nexport function closeServers() {\r\n // Check if there are servers working\r\n if (activeServers.size > 0) {\r\n log(4, `[server] Closing all servers.`);\r\n\r\n // Close each one of servers\r\n for (const [port, server] of activeServers) {\r\n server.close(() => {\r\n activeServers.delete(port);\r\n log(4, `[server] Closed server on port: ${port}.`);\r\n });\r\n }\r\n }\r\n}\r\n\r\n/**\r\n * Get all servers associated with Express app instance.\r\n *\r\n * @function getServers\r\n *\r\n * @returns {Array.} Servers associated with Express app instance.\r\n */\r\nexport function getServers() {\r\n return activeServers;\r\n}\r\n\r\n/**\r\n * Get the Express instance.\r\n *\r\n * @function getExpress\r\n *\r\n * @returns {Express} The Express instance.\r\n */\r\nexport function getExpress() {\r\n return express;\r\n}\r\n\r\n/**\r\n * Get the Express app instance.\r\n *\r\n * @function getApp\r\n *\r\n * @returns {Express} The Express app instance.\r\n */\r\nexport function getApp() {\r\n return app;\r\n}\r\n\r\n/**\r\n * Enable rate limiting for the server.\r\n *\r\n * @function enableRateLimiting\r\n *\r\n * @param {Object} rateLimitingOptions - The configuration object containing\r\n * `rateLimiting` options. This object may include a partial or complete set\r\n * of the `rateLimiting` options. If the options are partial, missing values\r\n * will default to the current global configuration.\r\n */\r\nexport function enableRateLimiting(rateLimitingOptions) {\r\n // Update the instance options object\r\n const options = updateOptions(\r\n validateOptions({\r\n server: {\r\n rateLimiting: rateLimitingOptions\r\n }\r\n })\r\n );\r\n\r\n // Set the rate limiting options\r\n rateLimitingMiddleware(app, options.server.rateLimitingOptions);\r\n}\r\n\r\n/**\r\n * Apply middleware(s) to a specific path.\r\n *\r\n * @function use\r\n *\r\n * @param {string} path - The path to which the middleware(s) should be applied.\r\n * @param {...Function} middlewares - The middleware function(s) to be applied.\r\n */\r\nexport function use(path, ...middlewares) {\r\n app.use(path, ...middlewares);\r\n}\r\n\r\n/**\r\n * Set up a route with GET method and apply middleware(s).\r\n *\r\n * @function get\r\n *\r\n * @param {string} path - The path to which the middleware(s) should be applied.\r\n * @param {...Function} middlewares - The middleware function(s) to be applied.\r\n */\r\nexport function get(path, ...middlewares) {\r\n app.get(path, ...middlewares);\r\n}\r\n\r\n/**\r\n * Set up a route with POST method and apply middleware(s).\r\n *\r\n * @function post\r\n *\r\n * @param {string} path - The path to which the middleware(s) should be applied.\r\n * @param {...Function} middlewares - The middleware function(s) to be applied.\r\n */\r\nexport function post(path, ...middlewares) {\r\n app.post(path, ...middlewares);\r\n}\r\n\r\n/**\r\n * Attach error handlers to the server.\r\n *\r\n * @function _attachServerErrorHandlers\r\n *\r\n * @param {(http.Server|https.Server)} server - The HTTP/HTTPS server instance.\r\n */\r\nfunction _attachServerErrorHandlers(server) {\r\n server.on('clientError', (error, socket) => {\r\n logWithStack(\r\n 1,\r\n error,\r\n `[server] Client error: ${error.message}, destroying socket.`\r\n );\r\n socket.destroy();\r\n });\r\n\r\n server.on('error', (error) => {\r\n logWithStack(1, error, `[server] Server error: ${error.message}`);\r\n });\r\n\r\n server.on('connection', (socket) => {\r\n socket.on('error', (error) => {\r\n logWithStack(1, error, `[server] Socket error: ${error.message}`);\r\n });\r\n });\r\n}\r\n\r\nexport default {\r\n startServer,\r\n closeServers,\r\n getServers,\r\n getExpress,\r\n getApp,\r\n enableRateLimiting,\r\n use,\r\n get,\r\n post\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * @overview Handles graceful shutdown of the Highcharts Export Server, ensuring\r\n * proper cleanup of resources such as browser, pages, servers, and timers.\r\n */\r\n\r\nimport { killPool } from './pool.js';\r\nimport { clearAllTimers } from './timer.js';\r\n\r\nimport { closeServers } from './server/server.js';\r\n\r\n/**\r\n * Performs cleanup operations to ensure a graceful shutdown of the process.\r\n * This includes clearing all registered timeouts/intervals, closing active\r\n * servers, terminating resources (pages) of the pool, pool itself, and closing\r\n * the browser.\r\n *\r\n * @function shutdownCleanUp\r\n *\r\n * @param {number} [exitCode=0] - The exit code to use with `process.exit()`.\r\n * The default value is `0`.\r\n */\r\nexport async function shutdownCleanUp(exitCode = 0) {\r\n // Await freeing all resources\r\n await Promise.allSettled([\r\n // Clear all ongoing intervals\r\n clearAllTimers(),\r\n\r\n // Get available server instances (HTTP/HTTPS) and close them\r\n closeServers(),\r\n\r\n // Close an active pool along with its workers and the browser instance\r\n killPool()\r\n ]);\r\n\r\n // Exit process with a correct code\r\n process.exit(exitCode);\r\n}\r\n\r\nexport default {\r\n shutdownCleanUp\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * @overview Core module for initializing and managing the Highcharts Export\r\n * Server. Provides functionalities for configuring exports, setting up server\r\n * operations, logging, scripts caching, resource pooling, and graceful process\r\n * cleanup.\r\n */\r\n\r\nimport 'colors';\r\n\r\nimport { checkAndUpdateCache } from './cache.js';\r\nimport {\r\n singleExport,\r\n batchExport,\r\n startExport,\r\n setAllowCodeExecution\r\n} from './chart.js';\r\nimport {\r\n getOptions,\r\n setGlobalOptions,\r\n mapToNewOptions,\r\n updateOptions,\r\n validateOption,\r\n validateOptions\r\n} from './config.js';\r\nimport {\r\n log,\r\n logWithStack,\r\n logZodIssues,\r\n initLogging,\r\n enableConsoleLogging,\r\n enableFileLogging,\r\n setLogLevel\r\n} from './logger.js';\r\nimport { initPool, killPool } from './pool.js';\r\nimport { shutdownCleanUp } from './resourceRelease.js';\r\n\r\nimport server from './server/server.js';\r\n\r\n/**\r\n * Initializes the export process. Tasks such as configuring logging, checking\r\n * the cache and sources, and initializing the resource pool occur during this\r\n * stage.\r\n *\r\n * This function must be called before attempting to export charts or set\r\n * up a server.\r\n *\r\n * @async\r\n * @function initExport\r\n *\r\n * @param {Object} [initOptions={}] - The `initOptions` object, which may\r\n * be a partial or complete set of options. If the options are partial, missing\r\n * values will default to the current global configuration. The default value\r\n * is an empty object.\r\n */\r\nexport async function initExport(initOptions = {}) {\r\n // Init, validate and update the instance options object\r\n const options = updateOptions(validateOptions(initOptions), true);\r\n\r\n // Set the `allowCodeExecution` per export module scope\r\n setAllowCodeExecution(options.customLogic.allowCodeExecution);\r\n\r\n // Init the logging\r\n initLogging(options.logging);\r\n\r\n // Attach process' exit listeners\r\n if (options.other.listenToProcessExits) {\r\n _attachProcessExitListeners();\r\n }\r\n\r\n // Check if cache needs to be updated\r\n await checkAndUpdateCache(options.highcharts, options.server.proxy);\r\n\r\n // Init the pool\r\n await initPool(options.pool, options.puppeteer.args);\r\n}\r\n\r\n/**\r\n * Attaches exit listeners to the process, ensuring proper cleanup of resources\r\n * and termination on exit signals. Handles 'exit', 'SIGINT', 'SIGTERM'\r\n * and 'uncaughtException' events.\r\n *\r\n * @function _attachProcessExitListeners\r\n */\r\nfunction _attachProcessExitListeners() {\r\n log(3, '[process] Attaching exit listeners to the process.');\r\n\r\n // Handler for the 'exit'\r\n process.on('exit', (code) => {\r\n log(4, `[process] Process exited with code ${code}.`);\r\n });\r\n\r\n // Handler for the 'SIGINT'\r\n process.on('SIGINT', async (name, code) => {\r\n log(4, `[process] The ${name} event with code: ${code}.`);\r\n await shutdownCleanUp();\r\n });\r\n\r\n // Handler for the 'SIGTERM'\r\n process.on('SIGTERM', async (name, code) => {\r\n log(4, `[process] The ${name} event with code: ${code}.`);\r\n await shutdownCleanUp();\r\n });\r\n\r\n // Handler for the 'SIGHUP'\r\n process.on('SIGHUP', async (name, code) => {\r\n log(4, `[process] The ${name} event with code: ${code}.`);\r\n await shutdownCleanUp();\r\n });\r\n\r\n // Handler for the 'uncaughtException'\r\n process.on('uncaughtException', async (error, name) => {\r\n logWithStack(1, error, `[process] The ${name} error.`);\r\n await shutdownCleanUp(1);\r\n });\r\n}\r\n\r\nexport default {\r\n // Server\r\n ...server,\r\n\r\n // Options\r\n getOptions,\r\n setGlobalOptions,\r\n mapToNewOptions,\r\n\r\n // Validation\r\n validateOption,\r\n validateOptions,\r\n\r\n // Exporting\r\n initExport,\r\n singleExport,\r\n batchExport,\r\n startExport,\r\n\r\n // Release\r\n killPool,\r\n shutdownCleanUp,\r\n\r\n // Logs\r\n log,\r\n logWithStack,\r\n logZodIssues,\r\n setLogLevel: function (level) {\r\n // Update the instance options object\r\n const options = updateOptions(\r\n validateOptions({\r\n logging: {\r\n level\r\n }\r\n })\r\n );\r\n\r\n // Call the function\r\n setLogLevel(options.logging.level);\r\n },\r\n enableConsoleLogging: function (toConsole) {\r\n // Update the instance options object\r\n const options = updateOptions(\r\n validateOptions({\r\n logging: {\r\n toConsole\r\n }\r\n })\r\n );\r\n\r\n // Call the function\r\n enableConsoleLogging(options.logging.toConsole);\r\n },\r\n enableFileLogging: function (dest, file, toFile) {\r\n // Update the instance options object\r\n const options = updateOptions(\r\n validateOptions({\r\n logging: {\r\n dest,\r\n file,\r\n toFile\r\n }\r\n })\r\n );\r\n\r\n // Call the function\r\n enableFileLogging(\r\n options.logging.dest,\r\n options.logging.file,\r\n options.logging.toFile\r\n );\r\n }\r\n};\r\n"],"names":["__dirname","fileURLToPath","URL","url","deepCopy","objArr","objArrCopy","Array","isArray","key","Object","prototype","hasOwnProperty","call","fixConstr","constr","fixedConstr","toLowerCase","replace","includes","fixOutfile","type","outfile","getAbsolutePath","split","shift","fixType","mimeTypes","formats","values","outType","pop","find","t","path","isAbsolute","join","getBase64","input","Buffer","from","toString","getNewDate","Date","trim","getNewDateTime","getTime","isObject","item","isObjectEmpty","keys","length","isPrivateRangeUrlFound","some","pattern","test","measureTime","start","process","hrtime","bigint","Number","roundNumber","value","precision","multiplier","Math","pow","round","wrapAround","customCode","allowFileResources","isCallback","endsWith","readFileSync","startsWith","colors","logging","toConsole","toFile","pathCreated","pathToLog","levelsDesc","title","color","log","args","newLevel","texts","level","prefix","_logToFile","console","apply","undefined","concat","logWithStack","error","customMessage","mainMessage","message","stackMessage","stack","push","logZodIssues","issues","map","issue","initLogging","loggingOptions","dest","file","setLogLevel","enableConsoleLogging","enableFileLogging","isInteger","existsSync","mkdirSync","appendFile","defaultConfig","puppeteer","types","envLink","cliName","description","promptOptions","separator","highcharts","version","cdnUrl","forceFetch","cachePath","coreScripts","instructions","moduleScripts","indicatorScripts","customScripts","export","infile","instr","options","svg","batch","hint","choices","b64","noDownload","height","width","scale","defaultHeight","defaultWidth","defaultScale","min","max","globalOptions","themeOptions","rasterizationTimeout","customLogic","allowCodeExecution","callback","resources","loadConfig","legacyName","createConfig","server","enable","host","port","uploadLimit","benchmarking","proxy","timeout","rateLimiting","maxRequests","window","delay","trustProxy","skipKey","skipToken","ssl","force","certPath","pool","minWorkers","maxWorkers","workLimit","acquireTimeout","createTimeout","destroyTimeout","idleTimeout","createRetryInterval","reaperInterval","ui","route","other","nodeEnv","listenToProcessExits","noLogo","hardResetPage","browserShellMode","validation","debug","headless","devtools","listenToConsole","dumpio","slowMo","debuggingPort","nestedProps","_createNestedProps","absoluteProps","_createAbsoluteProps","config","propChain","forEach","entry","substring","dotenv","z","setErrorMap","_customErrorMap","v","boolean","strictCheck","union","enum","transform","nullable","string","refine","params","errorMessage","stringArray","filterCallback","arraySchema","array","stringSchema","slice","transformCallback","filter","positiveNum","number","positive","isNaN","nonNegativeNum","nonnegative","prefixes","chartConfig","object","passthrough","additionalOptions","validators","adminToken","indexOf","gte","lte","this","objectSchema","js","css","files","partial","stringSchema1","stringSchema2","enableServer","serverBenchmarking","proxyHost","proxyPort","proxyTimeout","enableRateLimiting","enableSsl","sslForce","sslPort","sslCertPath","poolBenchmarking","resourcesInterval","logLevel","int","logFile","logDest","logToConsole","logToFile","enableUi","uiRoute","enableDebug","requestId","uuid","PuppeteerSchema","HighchartsSchema","ExportSchema","CustomLogicSchema","ProxySchema","RateLimitingSchema","SslSchema","ServerSchema","optional","PoolSchema","LoggingSchema","UiSchema","OtherSchema","DebugSchema","StrictConfigSchema","LooseConfigSchema","EnvSchema","PUPPETEER_ARGS","HIGHCHARTS_VERSION","HIGHCHARTS_CDN_URL","HIGHCHARTS_FORCE_FETCH","HIGHCHARTS_CACHE_PATH","HIGHCHARTS_ADMIN_TOKEN","HIGHCHARTS_CORE_SCRIPTS","HIGHCHARTS_MODULE_SCRIPTS","HIGHCHARTS_INDICATOR_SCRIPTS","HIGHCHARTS_CUSTOM_SCRIPTS","EXPORT_INFILE","EXPORT_INSTR","EXPORT_OPTIONS","EXPORT_SVG","EXPORT_BATCH","EXPORT_OUTFILE","EXPORT_TYPE","EXPORT_CONSTR","EXPORT_B64","EXPORT_NO_DOWNLOAD","EXPORT_HEIGHT","EXPORT_WIDTH","EXPORT_SCALE","EXPORT_DEFAULT_HEIGHT","EXPORT_DEFAULT_WIDTH","EXPORT_DEFAULT_SCALE","EXPORT_GLOBAL_OPTIONS","EXPORT_THEME_OPTIONS","EXPORT_RASTERIZATION_TIMEOUT","CUSTOM_LOGIC_ALLOW_CODE_EXECUTION","CUSTOM_LOGIC_ALLOW_FILE_RESOURCES","CUSTOM_LOGIC_CUSTOM_CODE","CUSTOM_LOGIC_CALLBACK","CUSTOM_LOGIC_RESOURCES","CUSTOM_LOGIC_LOAD_CONFIG","CUSTOM_LOGIC_CREATE_CONFIG","SERVER_ENABLE","SERVER_HOST","SERVER_PORT","SERVER_UPLOAD_LIMIT","SERVER_BENCHMARKING","SERVER_PROXY_HOST","SERVER_PROXY_PORT","SERVER_PROXY_TIMEOUT","SERVER_RATE_LIMITING_ENABLE","SERVER_RATE_LIMITING_MAX_REQUESTS","SERVER_RATE_LIMITING_WINDOW","SERVER_RATE_LIMITING_DELAY","SERVER_RATE_LIMITING_TRUST_PROXY","SERVER_RATE_LIMITING_SKIP_KEY","SERVER_RATE_LIMITING_SKIP_TOKEN","SERVER_SSL_ENABLE","SERVER_SSL_FORCE","SERVER_SSL_PORT","SERVER_SSL_CERT_PATH","POOL_MIN_WORKERS","POOL_MAX_WORKERS","POOL_WORK_LIMIT","POOL_ACQUIRE_TIMEOUT","POOL_CREATE_TIMEOUT","POOL_DESTROY_TIMEOUT","POOL_IDLE_TIMEOUT","POOL_CREATE_RETRY_INTERVAL","POOL_REAPER_INTERVAL","POOL_BENCHMARKING","LOGGING_LEVEL","LOGGING_FILE","LOGGING_DEST","LOGGING_TO_CONSOLE","LOGGING_TO_FILE","UI_ENABLE","UI_ROUTE","OTHER_NODE_ENV","OTHER_LISTEN_TO_PROCESS_EXITS","OTHER_NO_LOGO","OTHER_HARD_RESET_PAGE","OTHER_BROWSER_SHELL_MODE","OTHER_VALIDATION","DEBUG_ENABLE","DEBUG_HEADLESS","DEBUG_DEVTOOLS","DEBUG_LISTEN_TO_CONSOLE","DEBUG_DUMPIO","DEBUG_SLOW_MO","DEBUG_DEBUGGING_PORT","envs","parse","env","strictValidate","configOptions","looseValidate","context","propertyName","propertyInfo","code","ZodIssueCode","invalid_type","received","ZodParsedType","defaultError","custom","data","invalid_union","unionErrors","index","ExportError","Error","constructor","statusCode","super","setStatus","setError","name","_initGlobalOptions","instanceOptions","getOptions","getInstance","setGlobalOptions","customOptions","cliArgs","cliOptions","_loadConfigFile","_pairArgumentValue","_updateGlobalOptions","updateOptions","newInstance","mergeOptions","originalOptions","newOptions","entries","mapToNewOptions","oldOptions","propertiesChain","reduce","obj","prop","validateOption","configOption","validateOptions","isAllowedConfig","allowFunctions","objectConfig","eval","JSON","stringifiedOptions","_optionsStringify","parsedOptions","_","envVal","configOpt","cliOpt","customOpt","configVal","cliVal","customVal","stringifyFunctions","stringify","replaceAll","customLogicOptions","configIndex","findIndex","arg","configFileName","i","option","async","fetch","requestOptions","Promise","resolve","reject","_getProtocolModule","get","response","responseData","on","chunk","text","https","http","cache","activeManifest","sources","hcVersion","checkAndUpdateCache","highchartsOptions","serverProxyOptions","fetchedModules","getCachePath","manifestPath","sourcePath","recursive","_updateCache","requestUpdate","manifest","modules","moduleMap","m","numberOfModules","moduleName","extractVersion","_saveConfigToManifest","getHighchartsVersion","updateHighchartsVersion","newVersion","cacheSources","extractModuleName","scriptPath","_fetchAndProcessScript","script","shouldThrowError","newManifest","writeFileSync","_fetchScripts","proxyAgent","HttpsProxyAgent","agent","allFetchPromises","all","c","setupHighcharts","Highcharts","animObject","duration","createChart","exportOptions","setOptions","merge","wrap","setOptionsObj","isRenderComplete","Chart","proceed","userOptions","cb","exporting","enabled","plotOptions","series","label","tooltip","animation","onHighchartsRender","addEvent","Series","chart","Function","finalOptions","finalCallback","defaultOptions","template","browser","createBrowser","puppeteerArgs","enabledDebug","debugOptions","launchOptions","userDataDir","handleSIGINT","handleSIGTERM","handleSIGHUP","waitForInitialPage","defaultViewport","tryCount","open","launch","setTimeout","closeBrowser","connected","close","newPage","poolResource","page","setCacheEnabled","_setPageContent","_setPageEvents","isClosed","clearPage","hardReset","goto","waitUntil","evaluate","document","body","innerHTML","id","workCount","addPageResources","injectedResources","injectedJs","content","isLocal","jsResource","addScriptTag","injectedCss","cssImports","match","cssImportPath","cssResource","addStyleTag","clearPageResources","resource","dispose","oldCharts","charts","oldChart","destroy","scriptsToRemove","getElementsByTagName","stylesToRemove","linksToRemove","element","remove","setContent","cssTemplate","svgTemplate","puppeteerExport","isSVG","size","svgElement","querySelector","chartHeight","baseVal","chartWidth","style","zoom","margin","parseFloat","x","y","_getClipRegion","viewportHeight","abs","ceil","viewportWidth","result","setViewport","deviceScaleFactor","_createSVG","_createImage","_createPDF","$eval","getBoundingClientRect","trunc","outerHTML","clip","race","screenshot","encoding","fullPage","optimizeForSpeed","captureBeyondViewport","quality","omitBackground","_resolve","emulateMediaType","pdf","poolStats","exportsAttempted","exportsPerformed","exportsDropped","exportsFromSvg","exportsFromOptions","exportsFromSvgAttempts","exportsFromOptionsAttempts","timeSpent","timeSpentAverage","initPool","poolOptions","Pool","_factory","acquireTimeoutMillis","createTimeoutMillis","destroyTimeoutMillis","idleTimeoutMillis","createRetryIntervalMillis","reapIntervalMillis","propagateCreateError","clearStatus","_eventId","initialResources","acquire","promise","release","killPool","worker","used","destroyed","postWork","workerHandle","getPoolInfo","acquireCounter","workStart","exportCounter","exportTime","getPoolStats","getPoolInfoJSON","numUsed","available","numFree","allCreated","pendingAcquires","numPendingAcquires","pendingCreates","numPendingCreates","pendingValidations","numPendingValidations","pendingDestroys","absoluteAll","create","random","startDate","validate","mainFrame","detached","removeAllListeners","sanitize","JSDOM","DOMPurify","ADD_TAGS","singleExport","startExport","batchExport","batchFunctions","pair","batchResults","allSettled","reason","exportingOptions","endCallback","fileContent","_exportFromSvg","_exportFromOptions","getAllowCodeExecution","setAllowCodeExecution","inputToExport","_prepareExport","_handleCustomLogic","_handleGlobalAndTheme","_findChartSize","optionsChart","optionsExporting","globalOptionsChart","globalOptionsExporting","themeOptionsChart","themeOptionsExporting","sourceHeight","sourceWidth","param","_handleResources","allowedProps","handledResources","correctResources","propName","optionsName","timerIds","addTimer","clearAllTimers","clearInterval","clearTimeout","logErrorMiddleware","request","next","returnErrorMiddleware","status","json","errorMiddleware","app","use","rateLimitingMiddleware","rateLimitingOptions","rateOptions","limiter","rateLimit","windowMs","limit","delayMs","handler","format","send","default","skip","query","access_token","contentTypeMiddleware","contentType","headers","requestBodyMiddleware","connection","remoteAddress","validatedOptions","filename","validationMiddleware","post","reversedMime","png","jpeg","gif","requestExport","requestCounter","connectionAborted","socket","hadErrors","header","attachment","exportRoutes","serverStartTime","packageFile","successRates","recordInterval","windowSize","_calculateMovingAverage","a","b","_startSuccessRate","setInterval","stats","successRatio","healthRoutes","period","movingAverage","bootTime","uptime","floor","serverVersion","highchartsVersion","averageExportTime","attemptedExports","performedExports","failedExports","sucessRatio","toFixed","svgExports","jsonExports","svgExportsAttempts","jsonExportsAttempts","uiRoutes","sendFile","acceptRanges","versionChangeRoutes","token","activeServers","Map","express","startServer","serverOptions","uploadLimitBytes","storage","multer","memoryStorage","upload","limits","fieldSize","disable","cors","methods","set","urlencoded","extended","none","static","httpServer","createServer","_attachServerErrorHandlers","listen","cert","readFile","httpsServer","closeServers","delete","getServers","getExpress","getApp","middlewares","shutdownCleanUp","exitCode","exit","initExport","initOptions","_attachProcessExitListeners"],"mappings":"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ACA,QACA,OACA,aACA,mBACA,eACA,cACA,UACA,UACA,cACA,WACA,UACA,YACA,cACA,YACA,sBACA,SACA,SACA,WACA,aACA,YACA,eACA,yBACA,SACA,eACA,YACA,kBACA,SACA,cACA,mBACA,eACA,kBACA,cACA,eAEA,cACA,WACA,eACA,WACA,SACA,OACA,WACA,YACA,SACA,qBACA,aACA,WACA,WACA,WACA,WACA,eACA,UACA,kBACA,oBACA,aACA,UACA,cACA,YACA,YAEF0D,MAAO,CAAC,YACRC,QAAS,4BACTE,YAAa,qCACbC,cAAe,CACbxG,KAAM,cACNgH,aAAc,0DAGlBE,iBAAkB,CAChBxE,MAAO,CAAC,kBACR0D,MAAO,CAAC,YACRC,QAAS,+BACTE,YAAa,wCACbC,cAAe,CACbxG,KAAM,cACNgH,aAAc,0DAGlBG,cAAe,CACbzE,MAAO,CACL,wEACA,kGAEF0D,MAAO,CAAC,YACRC,QAAS,4BACTE,YAAa,qDACbC,cAAe,CACbxG,KAAM,OACNyG,UAAW,OAIjBW,OAAQ,CACNC,OAAQ,CACN3E,MAAO,KACP0D,MAAO,CAAC,SAAU,QAClBC,QAAS,gBACTE,YACE,+DACFC,cAAe,CACbxG,KAAM,SAGVsH,MAAO,CACL5E,MAAO,KACP0D,MAAO,CAAC,SAAU,SAAU,QAC5BC,QAAS,eACTE,YACE,mEACFC,cAAe,CACbxG,KAAM,SAGVuH,QAAS,CACP7E,MAAO,KACP0D,MAAO,CAAC,SAAU,SAAU,QAC5BC,QAAS,iBACTE,YAAa,+BACbC,cAAe,CACbxG,KAAM,SAGVwH,IAAK,CACH9E,MAAO,KACP0D,MAAO,CAAC,SAAU,QAClBC,QAAS,aACTE,YAAa,mDACbC,cAAe,CACbxG,KAAM,SAGVyH,MAAO,CACL/E,MAAO,KACP0D,MAAO,CAAC,SAAU,QAClBC,QAAS,eACTE,YACE,gEACFC,cAAe,CACbxG,KAAM,SAGVC,QAAS,CACPyC,MAAO,KACP0D,MAAO,CAAC,SAAU,QAClBC,QAAS,iBACTE,YACE,qFACFC,cAAe,CACbxG,KAAM,SAGVA,KAAM,CACJ0C,MAAO,MACP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"} \ No newline at end of file diff --git a/lib/config.js b/lib/config.js index 4014901a..6aed4344 100644 --- a/lib/config.js +++ b/lib/config.js @@ -24,7 +24,7 @@ import { readFileSync } from 'fs'; import { join } from 'path'; import { log, logWithStack, logZodIssues } from './logger.js'; -import { __dirname, isObject, deepCopy, getAbsolutePath } from './utils.js'; +import { __dirname, deepCopy, getAbsolutePath, isObject } from './utils.js'; import { envs, looseValidate, @@ -32,7 +32,7 @@ import { validators } from './validation.js'; -import { defaultConfig, nestedProps, absoluteProps } from './schemas/config.js'; +import { defaultConfig, absoluteProps, nestedProps } from './schemas/config.js'; import ExportError from './errors/ExportError.js'; diff --git a/lib/index.js b/lib/index.js index 3edeb8f4..e716c7c3 100644 --- a/lib/index.js +++ b/lib/index.js @@ -30,9 +30,9 @@ import { } from './chart.js'; import { getOptions, - updateOptions, setGlobalOptions, mapToNewOptions, + updateOptions, validateOption, validateOptions } from './config.js'; diff --git a/lib/pool.js b/lib/pool.js index a67766b2..bea9f25f 100644 --- a/lib/pool.js +++ b/lib/pool.js @@ -23,7 +23,7 @@ See LICENSE file in root for details. import { Pool } from 'tarn'; import { v4 as uuid } from 'uuid'; -import { createBrowser, closeBrowser, newPage, clearPage } from './browser.js'; +import { clearPage, createBrowser, closeBrowser, newPage } from './browser.js'; import { puppeteerExport } from './export.js'; import { log, logWithStack } from './logger.js'; import { getNewDateTime, measureTime } from './utils.js'; diff --git a/lib/server/middlewares/validation.js b/lib/server/middlewares/validation.js index 4af2496e..551d1337 100644 --- a/lib/server/middlewares/validation.js +++ b/lib/server/middlewares/validation.js @@ -27,14 +27,8 @@ import { v4 as uuid } from 'uuid'; import { getAllowCodeExecution } from '../../chart.js'; import { isAllowedConfig, validateOptions } from '../../config.js'; -import { log, logZodIssues } from '../../logger.js'; -import { - fixConstr, - fixType, - isObjectEmpty, - isPrivateRangeUrlFound -} from '../../utils.js'; -import { looseValidate } from '../../validation.js'; +import { log } from '../../logger.js'; +import { isObjectEmpty, isPrivateRangeUrlFound } from '../../utils.js'; import ExportError from '../../errors/ExportError.js'; diff --git a/lib/server/routes/health.js b/lib/server/routes/health.js index 1e50ab42..4a6d4d9b 100644 --- a/lib/server/routes/health.js +++ b/lib/server/routes/health.js @@ -22,7 +22,7 @@ import { join } from 'path'; import { getHighchartsVersion } from '../../cache.js'; import { log } from '../../logger.js'; -import { getPoolStats, getPoolInfoJSON } from '../../pool.js'; +import { getPoolInfoJSON, getPoolStats } from '../../pool.js'; import { addTimer } from '../../timer.js'; import { __dirname, getNewDateTime } from '../../utils.js'; diff --git a/lib/server/routes/versionChange.js b/lib/server/routes/versionChange.js index f8512576..d5db30f9 100644 --- a/lib/server/routes/versionChange.js +++ b/lib/server/routes/versionChange.js @@ -17,7 +17,7 @@ See LICENSE file in root for details. * on the server, with authentication and validation. */ -import { updateHighchartsVersion, getHighchartsVersion } from '../../cache.js'; +import { getHighchartsVersion, updateHighchartsVersion } from '../../cache.js'; import { validateOption } from '../../config.js'; import { log } from '../../logger.js'; import { envs } from '../../validation.js'; From ee8a7eaed7db6516bcc8e6af607c881cf8b81d91 Mon Sep 17 00:00:00 2001 From: PaulDalek Date: Thu, 23 Jan 2025 03:29:29 +0100 Subject: [PATCH 16/19] Improved options validation by moving it into the updateOptions function. --- README.md | 7 ++++- dist/index.cjs | 4 +-- dist/index.esm.js | 2 +- dist/index.esm.js.map | 2 +- lib/chart.js | 13 +------- lib/config.js | 44 +++++++++++++--------------- lib/index.js | 42 ++++++++++++-------------- lib/server/middlewares/validation.js | 8 ++--- lib/server/routes/versionChange.js | 13 +------- lib/server/server.js | 22 ++++++-------- 10 files changed, 64 insertions(+), 93 deletions(-) diff --git a/README.md b/README.md index 8225db05..c7ee2421 100644 --- a/README.md +++ b/README.md @@ -115,6 +115,10 @@ The `singleExport()`, `batchExport()`, and `startExport()` functions must be pro Essentially, all options can be configured through `.env`, the CLI, and prompts, with one exception: the `HIGHCHARTS_ADMIN_TOKEN`, which is only available as an environment variable. +## Options Validation + +By default, options validation is enabled, and it is recommended to keep it enabled to ensure that the provided options are correctly checked, validated, and parsed, allowing the exporting process to function without issues. However, it is possible to disable validation (by setting the `validation` option to **false**) if you are confident in the accuracy of the data you provide. Additionaly, when used as a Node.js module, each API function that updates global options with the provided data also offers the ability to validate the data. + ## Default JSON Config The JSON below represents the default configuration stored in the `./lib/schemas/config.js` file. If no `.env` file is found (more details on the file and environment variables below), these options will be used. The configuration is not recommended to be modified directly, as it can typically be managed through other sources. @@ -766,10 +770,11 @@ This package supports both CommonJS and ES modules. - `@returns {Object}` A copy of the global options object, or a reference to the global options object. -- `function updateOptions(newOptions, getCopy = false)`: Updates a copy of the global options object or a reference to the global options object, based on the `getCopy` flag. +- `function updateOptions(newOptions, getCopy = false, strictCheck = true)`: Updates either a copy of the global options object or a reference to the global options object, depending on the getCopy flag, using the provided newOptions, which may or may not be validated. - `@param {Object} newOptions` - An object containing the new options to be merged into the global options. - `@param {boolean} [getCopy=false]` - Determines whether to merge the new options into a copy of the global options object (`true`) or directly into the global options object (`false`). The default value is `false`. + - `@param {boolean} [strictCheck=true]` - Determines if stricter validation should be applied. The default value is `true`. - `@returns {Object}` The updated options object, either the modified global options or a modified copy, based on the value of `getCopy`. diff --git a/dist/index.cjs b/dist/index.cjs index 3bff04ac..1624bfe6 100644 --- a/dist/index.cjs +++ b/dist/index.cjs @@ -1,2 +1,2 @@ -"use strict";Object.defineProperty(exports,"__esModule",{value:!0}),require("colors");var fs=require("fs"),path=require("path"),httpsProxyAgent=require("https-proxy-agent"),url=require("url"),dotenv=require("dotenv"),zod=require("zod"),http=require("http"),https=require("https"),tarn=require("tarn"),uuid=require("uuid"),puppeteer=require("puppeteer"),DOMPurify=require("dompurify"),jsdom=require("jsdom"),cors=require("cors"),express=require("express"),multer=require("multer"),rateLimit=require("express-rate-limit"),_documentCurrentScript="undefined"!=typeof document?document.currentScript:null;const __dirname$1=url.fileURLToPath(new URL("../.","undefined"==typeof document?require("url").pathToFileURL(__filename).href:_documentCurrentScript&&"SCRIPT"===_documentCurrentScript.tagName.toUpperCase()&&_documentCurrentScript.src||new URL("index.cjs",document.baseURI).href));function deepCopy(e){if(null===e||"object"!=typeof e)return e;const t=Array.isArray(e)?[]:{};for(const o in e)Object.prototype.hasOwnProperty.call(e,o)&&(t[o]=deepCopy(e[o]));return t}function fixConstr(e){try{const t=`${e.toLowerCase().replace("chart","")}Chart`;return"Chart"===t&&t.toLowerCase(),["chart","stockChart","mapChart","ganttChart"].includes(t)?t:"chart"}catch{return"chart"}}function fixOutfile(e,t){return`${getAbsolutePath(t||"chart").split(".").shift()}.${e}`}function fixType(e,t=null){const o={"image/png":"png","image/jpeg":"jpeg","application/pdf":"pdf","image/svg+xml":"svg"},r=Object.values(o);if(t){const o=t.split(".").pop();"jpg"===o?e="jpeg":r.includes(o)&&e!==o&&(e=o)}return o[e]||r.find((t=>t===e))||"png"}function getAbsolutePath(e){return path.isAbsolute(e)?path.normalize(e):path.resolve(e)}function getBase64(e,t){return"pdf"===t||"svg"==t?Buffer.from(e,"utf8").toString("base64"):e}function getNewDate(){return(new Date).toString().split("(")[0].trim()}function getNewDateTime(){return(new Date).getTime()}function isObject(e){return"[object Object]"===Object.prototype.toString.call(e)}function isObjectEmpty(e){return"object"==typeof e&&!Array.isArray(e)&&null!==e&&0===Object.keys(e).length}function isPrivateRangeUrlFound(e){return[/xlink:href="(?:http:\/\/|https:\/\/)?localhost\b/,/xlink:href="(?:http:\/\/|https:\/\/)?10\.\d{1,3}\.\d{1,3}\.\d{1,3}\b/,/xlink:href="(?:http:\/\/|https:\/\/)?127\.\d{1,3}\.\d{1,3}\.\d{1,3}\b/,/xlink:href="(?:http:\/\/|https:\/\/)?172\.(1[6-9]|2[0-9]|3[0-1])\.\d{1,3}\.\d{1,3}\b/,/xlink:href="(?:http:\/\/|https:\/\/)?192\.168\.\d{1,3}\.\d{1,3}\b/].some((t=>t.test(e)))}function measureTime(){const e=process.hrtime.bigint();return()=>Number(process.hrtime.bigint()-e)/1e6}function roundNumber(e,t=1){const o=Math.pow(10,t||0);return Math.round(+e*o)/o}function wrapAround(e,t,o=!1){if(e&&"string"==typeof e)return(e=e.trim()).endsWith(".js")?t?wrapAround(fs.readFileSync(getAbsolutePath(e),"utf8"),t,o):null:!o&&(e.startsWith("function()")||e.startsWith("function ()")||e.startsWith("()=>")||e.startsWith("() =>"))?`(${e})()`:e.replace(/;$/,"")}const colors=["red","yellow","blue","gray","green"],logging={toConsole:!0,toFile:!1,pathCreated:!1,pathToLog:"",levelsDesc:[{title:"error",color:colors[0]},{title:"warning",color:colors[1]},{title:"notice",color:colors[2]},{title:"verbose",color:colors[3]},{title:"benchmark",color:colors[4]}]};function log(...e){const[t,...o]=e,{levelsDesc:r,level:i}=logging;if(5!==t&&(0===t||t>i||i>r.length))return;const n=`${getNewDate()} [${r[t-1].title}] -`;logging.toFile&&_logToFile(o,n),logging.toConsole&&console.log.apply(void 0,[n.toString()[logging.levelsDesc[t-1].color]].concat(o))}function logWithStack(e,t,o){const r=o||t&&t.message||"",{level:i,levelsDesc:n}=logging;if(0===e||e>i||i>n.length)return;const s=`${getNewDate()} [${n[e-1].title}] -`,a=t&&t.stack,l=[r];a&&l.push("\n",a),logging.toFile&&_logToFile(l,s),logging.toConsole&&console.log.apply(void 0,[s.toString()[logging.levelsDesc[e-1].color]].concat([l.shift()[colors[e-1]],...l]))}function logZodIssues(e,t,o){logWithStack(e,null,[`${o||"[validation] Validation error"} - the following Zod issues occured:`,...(t||[]).map((e=>`- ${e.message}`))].join("\n"))}function initLogging(e){const{level:t,dest:o,file:r,toConsole:i,toFile:n}=e;logging.pathCreated=!1,logging.pathToLog="",setLogLevel(t),enableConsoleLogging(i),enableFileLogging(o,r,n)}function setLogLevel(e){Number.isInteger(e)&&e>=0&&e<=logging.levelsDesc.length&&(logging.level=e)}function enableConsoleLogging(e){logging.toConsole=!!e}function enableFileLogging(e,t,o){logging.toFile=!!o,logging.toFile&&(logging.dest=e||"",logging.file=t||"")}function _logToFile(e,t){logging.pathCreated||(!fs.existsSync(getAbsolutePath(logging.dest))&&fs.mkdirSync(getAbsolutePath(logging.dest)),logging.pathToLog=getAbsolutePath(path.join(logging.dest,logging.file)),logging.pathCreated=!0),fs.appendFile(logging.pathToLog,[t].concat(e).join(" ")+"\n",(e=>{e&&logging.toFile&&logging.pathCreated&&(logging.toFile=!1,logging.pathCreated=!1,logWithStack(2,e,"[logger] Unable to write to log file."))}))}const defaultConfig={puppeteer:{args:{value:["--allow-running-insecure-content","--ash-no-nudges","--autoplay-policy=user-gesture-required","--block-new-web-contents","--disable-accelerated-2d-canvas","--disable-background-networking","--disable-background-timer-throttling","--disable-backgrounding-occluded-windows","--disable-breakpad","--disable-checker-imaging","--disable-client-side-phishing-detection","--disable-component-extensions-with-background-pages","--disable-component-update","--disable-default-apps","--disable-dev-shm-usage","--disable-domain-reliability","--disable-extensions","--disable-features=CalculateNativeWinOcclusion,InterestFeedContentSuggestions,WebOTP","--disable-hang-monitor","--disable-ipc-flooding-protection","--disable-logging","--disable-notifications","--disable-offer-store-unmasked-wallet-cards","--disable-popup-blocking","--disable-print-preview","--disable-prompt-on-repost","--disable-renderer-backgrounding","--disable-search-engine-choice-screen","--disable-session-crashed-bubble","--disable-setuid-sandbox","--disable-site-isolation-trials","--disable-speech-api","--disable-sync","--enable-unsafe-webgpu","--hide-crash-restore-bubble","--hide-scrollbars","--metrics-recording-only","--mute-audio","--no-default-browser-check","--no-first-run","--no-pings","--no-sandbox","--no-startup-window","--no-zygote","--password-store=basic","--process-per-tab","--use-mock-keychain"],types:["string[]"],envLink:"PUPPETEER_ARGS",cliName:"puppeteerArgs",description:"Array of Puppeteer arguments",promptOptions:{type:"list",separator:";"}}},highcharts:{version:{value:"latest",types:["string"],envLink:"HIGHCHARTS_VERSION",description:"Highcharts version",promptOptions:{type:"text"}},cdnUrl:{value:"https://code.highcharts.com",types:["string"],envLink:"HIGHCHARTS_CDN_URL",description:"CDN URL for Highcharts scripts",promptOptions:{type:"text"}},forceFetch:{value:!1,types:["boolean"],envLink:"HIGHCHARTS_FORCE_FETCH",description:"Flag to refetch scripts after each server rerun",promptOptions:{type:"toggle"}},cachePath:{value:".cache",types:["string"],envLink:"HIGHCHARTS_CACHE_PATH",description:"Directory path for cached Highcharts scripts",promptOptions:{type:"text"}},coreScripts:{value:["highcharts","highcharts-more","highcharts-3d"],types:["string[]"],envLink:"HIGHCHARTS_CORE_SCRIPTS",description:"Highcharts core scripts to fetch",promptOptions:{type:"multiselect",instructions:"Space: Select specific, A: Select all, Enter: Confirm"}},moduleScripts:{value:["stock","map","gantt","exporting","parallel-coordinates","accessibility","boost-canvas","boost","data","data-tools","draggable-points","static-scale","broken-axis","heatmap","tilemap","tiledwebmap","timeline","treemap","treegraph","item-series","drilldown","histogram-bellcurve","bullet","funnel","funnel3d","geoheatmap","pyramid3d","networkgraph","overlapping-datalabels","pareto","pattern-fill","pictorial","price-indicator","sankey","arc-diagram","dependency-wheel","series-label","series-on-point","solid-gauge","sonification","streamgraph","sunburst","variable-pie","variwide","vector","venn","windbarb","wordcloud","xrange","no-data-to-display","drag-panes","debugger","dumbbell","lollipop","cylinder","organization","dotplot","marker-clusters","hollowcandlestick","heikinashi","flowmap","export-data","navigator","textpath"],types:["string[]"],envLink:"HIGHCHARTS_MODULE_SCRIPTS",description:"Highcharts module scripts to fetch",promptOptions:{type:"multiselect",instructions:"Space: Select specific, A: Select all, Enter: Confirm"}},indicatorScripts:{value:["indicators-all"],types:["string[]"],envLink:"HIGHCHARTS_INDICATOR_SCRIPTS",description:"Highcharts indicator scripts to fetch",promptOptions:{type:"multiselect",instructions:"Space: Select specific, A: Select all, Enter: Confirm"}},customScripts:{value:["https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.30.1/moment.min.js","https://cdnjs.cloudflare.com/ajax/libs/moment-timezone/0.5.45/moment-timezone-with-data.min.js"],types:["string[]"],envLink:"HIGHCHARTS_CUSTOM_SCRIPTS",description:"Additional custom scripts or dependencies to fetch",promptOptions:{type:"list",separator:";"}}},export:{infile:{value:null,types:["string","null"],envLink:"EXPORT_INFILE",description:"Input filename with type, formatted correctly as JSON or SVG",promptOptions:{type:"text"}},instr:{value:null,types:["Object","string","null"],envLink:"EXPORT_INSTR",description:"Overrides the `infile` with JSON, stringified JSON, or SVG input",promptOptions:{type:"text"}},options:{value:null,types:["Object","string","null"],envLink:"EXPORT_OPTIONS",description:"Alias for the `instr` option",promptOptions:{type:"text"}},svg:{value:null,types:["string","null"],envLink:"EXPORT_SVG",description:"SVG string representation of the chart to render",promptOptions:{type:"text"}},batch:{value:null,types:["string","null"],envLink:"EXPORT_BATCH",description:'Batch job string with input/output pairs: "in=out;in=out;..."',promptOptions:{type:"text"}},outfile:{value:null,types:["string","null"],envLink:"EXPORT_OUTFILE",description:"Output filename with type. Can be jpeg, png, pdf, or svg and ignores `type` option",promptOptions:{type:"text"}},type:{value:"png",types:["string"],envLink:"EXPORT_TYPE",description:"File export format. Can be jpeg, png, pdf, or svg",promptOptions:{type:"select",hint:"Default: png",choices:["png","jpeg","pdf","svg"]}},constr:{value:"chart",types:["string"],envLink:"EXPORT_CONSTR",description:"Chart constructor. Can be chart, stockChart, mapChart, or ganttChart",promptOptions:{type:"select",hint:"Default: chart",choices:["chart","stockChart","mapChart","ganttChart"]}},b64:{value:!1,types:["boolean"],envLink:"EXPORT_B64",description:"Whether or not to the chart should be received in Base64 format instead of binary",promptOptions:{type:"toggle"}},noDownload:{value:!1,types:["boolean"],envLink:"EXPORT_NO_DOWNLOAD",description:"Whether or not to include or exclude attachment headers in the response",promptOptions:{type:"toggle"}},height:{value:null,types:["number","null"],envLink:"EXPORT_HEIGHT",description:"Height of the exported chart, overrides chart settings",promptOptions:{type:"number"}},width:{value:null,types:["number","null"],envLink:"EXPORT_WIDTH",description:"Width of the exported chart, overrides chart settings",promptOptions:{type:"number"}},scale:{value:null,types:["number","null"],envLink:"EXPORT_SCALE",description:"Scale of the exported chart, overrides chart settings. Ranges from 0.1 to 5.0",promptOptions:{type:"number"}},defaultHeight:{value:400,types:["number"],envLink:"EXPORT_DEFAULT_HEIGHT",description:"Default height of the exported chart if not set",promptOptions:{type:"number"}},defaultWidth:{value:600,types:["number"],envLink:"EXPORT_DEFAULT_WIDTH",description:"Default width of the exported chart if not set",promptOptions:{type:"number"}},defaultScale:{value:1,types:["number"],envLink:"EXPORT_DEFAULT_SCALE",description:"Default scale of the exported chart if not set. Ranges from 0.1 to 5.0",promptOptions:{type:"number",min:.1,max:5}},globalOptions:{value:null,types:["Object","string","null"],envLink:"EXPORT_GLOBAL_OPTIONS",description:"JSON, stringified JSON or filename with global options for Highcharts.setOptions",promptOptions:{type:"text"}},themeOptions:{value:null,types:["Object","string","null"],envLink:"EXPORT_THEME_OPTIONS",description:"JSON, stringified JSON or filename with theme options for Highcharts.setOptions",promptOptions:{type:"text"}},rasterizationTimeout:{value:1500,types:["number"],envLink:"EXPORT_RASTERIZATION_TIMEOUT",description:"Milliseconds to wait for webpage rendering",promptOptions:{type:"number"}}},customLogic:{allowCodeExecution:{value:!1,types:["boolean"],envLink:"CUSTOM_LOGIC_ALLOW_CODE_EXECUTION",description:"Allows or disallows execution of arbitrary code during exporting",promptOptions:{type:"toggle"}},allowFileResources:{value:!1,types:["boolean"],envLink:"CUSTOM_LOGIC_ALLOW_FILE_RESOURCES",description:"Allows or disallows injection of filesystem resources (disabled in server mode)",promptOptions:{type:"toggle"}},customCode:{value:null,types:["string","null"],envLink:"CUSTOM_LOGIC_CUSTOM_CODE",description:"Custom code to execute before chart initialization. Can be a function, code wrapped in a function, or a .js filename",promptOptions:{type:"text"}},callback:{value:null,types:["string","null"],envLink:"CUSTOM_LOGIC_CALLBACK",description:"JavaScript code to run during construction. Can be a function or a .js filename",promptOptions:{type:"text"}},resources:{value:null,types:["Object","string","null"],envLink:"CUSTOM_LOGIC_RESOURCES",description:"Additional resources as JSON, stringified JSON, or filename, containing files, js, and css sections",promptOptions:{type:"text"}},loadConfig:{value:null,types:["string","null"],envLink:"CUSTOM_LOGIC_LOAD_CONFIG",legacyName:"fromFile",description:"File with a pre-defined configuration to use",promptOptions:{type:"text"}},createConfig:{value:null,types:["string","null"],envLink:"CUSTOM_LOGIC_CREATE_CONFIG",description:"Prompt-based option setting, saved to a provided config file",promptOptions:{type:"text"}}},server:{enable:{value:!1,types:["boolean"],envLink:"SERVER_ENABLE",cliName:"enableServer",description:"Starts the server when true",promptOptions:{type:"toggle"}},host:{value:"0.0.0.0",types:["string"],envLink:"SERVER_HOST",description:"Hostname of the server",promptOptions:{type:"text"}},port:{value:7801,types:["number"],envLink:"SERVER_PORT",description:"Port number for the server",promptOptions:{type:"number"}},uploadLimit:{value:3,types:["number"],envLink:"SERVER_UPLOAD_LIMIT",description:"Maximum request body size in MB",promptOptions:{type:"number"}},benchmarking:{value:!1,types:["boolean"],envLink:"SERVER_BENCHMARKING",cliName:"serverBenchmarking",description:"Displays or not action durations in milliseconds during server requests",promptOptions:{type:"toggle"}},proxy:{host:{value:null,types:["string","null"],envLink:"SERVER_PROXY_HOST",cliName:"proxyHost",description:"Host of the proxy server, if applicable",promptOptions:{type:"text"}},port:{value:null,types:["number","null"],envLink:"SERVER_PROXY_PORT",cliName:"proxyPort",description:"Port of the proxy server, if applicable",promptOptions:{type:"number"}},timeout:{value:5e3,types:["number"],envLink:"SERVER_PROXY_TIMEOUT",cliName:"proxyTimeout",description:"Timeout in milliseconds for the proxy server, if applicable",promptOptions:{type:"number"}}},rateLimiting:{enable:{value:!1,types:["boolean"],envLink:"SERVER_RATE_LIMITING_ENABLE",cliName:"enableRateLimiting",description:"Enables or disables rate limiting on the server",promptOptions:{type:"toggle"}},maxRequests:{value:10,types:["number"],envLink:"SERVER_RATE_LIMITING_MAX_REQUESTS",legacyName:"rateLimit",description:"Maximum number of requests allowed per minute",promptOptions:{type:"number"}},window:{value:1,types:["number"],envLink:"SERVER_RATE_LIMITING_WINDOW",description:"Time window in minutes for rate limiting",promptOptions:{type:"number"}},delay:{value:0,types:["number"],envLink:"SERVER_RATE_LIMITING_DELAY",description:"Delay duration between successive requests before reaching the limit",promptOptions:{type:"number"}},trustProxy:{value:!1,types:["boolean"],envLink:"SERVER_RATE_LIMITING_TRUST_PROXY",description:"Set to true if the server is behind a load balancer",promptOptions:{type:"toggle"}},skipKey:{value:null,types:["string","null"],envLink:"SERVER_RATE_LIMITING_SKIP_KEY",description:"Key to bypass the rate limiter, used with `skipToken`",promptOptions:{type:"text"}},skipToken:{value:null,types:["string","null"],envLink:"SERVER_RATE_LIMITING_SKIP_TOKEN",description:"Token to bypass the rate limiter, used with `skipKey`",promptOptions:{type:"text"}}},ssl:{enable:{value:!1,types:["boolean"],envLink:"SERVER_SSL_ENABLE",cliName:"enableSsl",description:"Enables or disables SSL protocol",promptOptions:{type:"toggle"}},force:{value:!1,types:["boolean"],envLink:"SERVER_SSL_FORCE",cliName:"sslForce",legacyName:"sslOnly",description:"Forces the server to use HTTPS only when true",promptOptions:{type:"toggle"}},port:{value:443,types:["number"],envLink:"SERVER_SSL_PORT",cliName:"sslPort",description:"Port for the SSL server",promptOptions:{type:"number"}},certPath:{value:null,types:["string","null"],envLink:"SERVER_SSL_CERT_PATH",cliName:"sslCertPath",legacyName:"sslPath",description:"Path to the SSL certificate/key file",promptOptions:{type:"text"}}}},pool:{minWorkers:{value:4,types:["number"],envLink:"POOL_MIN_WORKERS",description:"Minimum and initial number of pool workers to spawn",promptOptions:{type:"number"}},maxWorkers:{value:8,types:["number"],envLink:"POOL_MAX_WORKERS",legacyName:"workers",description:"Maximum number of pool workers to spawn",promptOptions:{type:"number"}},workLimit:{value:40,types:["number"],envLink:"POOL_WORK_LIMIT",description:"Number of tasks a worker can handle before restarting",promptOptions:{type:"number"}},acquireTimeout:{value:5e3,types:["number"],envLink:"POOL_ACQUIRE_TIMEOUT",description:"Timeout in milliseconds for acquiring a resource",promptOptions:{type:"number"}},createTimeout:{value:5e3,types:["number"],envLink:"POOL_CREATE_TIMEOUT",description:"Timeout in milliseconds for creating a resource",promptOptions:{type:"number"}},destroyTimeout:{value:5e3,types:["number"],envLink:"POOL_DESTROY_TIMEOUT",description:"Timeout in milliseconds for destroying a resource",promptOptions:{type:"number"}},idleTimeout:{value:3e4,types:["number"],envLink:"POOL_IDLE_TIMEOUT",description:"Timeout in milliseconds for destroying idle resources",promptOptions:{type:"number"}},createRetryInterval:{value:200,types:["number"],envLink:"POOL_CREATE_RETRY_INTERVAL",description:"Interval in milliseconds before retrying resource creation on failure",promptOptions:{type:"number"}},reaperInterval:{value:1e3,types:["number"],envLink:"POOL_REAPER_INTERVAL",description:"Interval in milliseconds to check and destroy idle resources",promptOptions:{type:"number"}},benchmarking:{value:!1,types:["boolean"],envLink:"POOL_BENCHMARKING",cliName:"poolBenchmarking",description:"Shows statistics for the pool of resources",promptOptions:{type:"toggle"}}},logging:{level:{value:4,types:["number"],envLink:"LOGGING_LEVEL",cliName:"logLevel",description:"Logging verbosity level",promptOptions:{type:"number",round:0,min:0,max:5}},file:{value:"highcharts-export-server.log",types:["string"],envLink:"LOGGING_FILE",cliName:"logFile",description:"Log file name. Requires `logToFile` and `logDest` to be set",promptOptions:{type:"text"}},dest:{value:"log",types:["string"],envLink:"LOGGING_DEST",cliName:"logDest",description:"Path to store log files. Requires `logToFile` to be set",promptOptions:{type:"text"}},toConsole:{value:!0,types:["boolean"],envLink:"LOGGING_TO_CONSOLE",cliName:"logToConsole",description:"Enables or disables console logging",promptOptions:{type:"toggle"}},toFile:{value:!0,types:["boolean"],envLink:"LOGGING_TO_FILE",cliName:"logToFile",description:"Enables or disables logging to a file",promptOptions:{type:"toggle"}}},ui:{enable:{value:!1,types:["boolean"],envLink:"UI_ENABLE",cliName:"enableUi",description:"Enables or disables the UI for the export server",promptOptions:{type:"toggle"}},route:{value:"/",types:["string"],envLink:"UI_ROUTE",cliName:"uiRoute",description:"The endpoint route for the UI",promptOptions:{type:"text"}}},other:{nodeEnv:{value:"production",types:["string"],envLink:"OTHER_NODE_ENV",description:"The Node.js environment type",promptOptions:{type:"text"}},listenToProcessExits:{value:!0,types:["boolean"],envLink:"OTHER_LISTEN_TO_PROCESS_EXITS",description:"Whether or not to attach process.exit handlers",promptOptions:{type:"toggle"}},noLogo:{value:!1,types:["boolean"],envLink:"OTHER_NO_LOGO",description:"Display or skip printing the logo on startup",promptOptions:{type:"toggle"}},hardResetPage:{value:!1,types:["boolean"],envLink:"OTHER_HARD_RESET_PAGE",description:"Whether or not to reset the page content entirely",promptOptions:{type:"toggle"}},browserShellMode:{value:!0,types:["boolean"],envLink:"OTHER_BROWSER_SHELL_MODE",description:"Whether or not to set the browser to run in shell mode",promptOptions:{type:"toggle"}},validation:{value:!0,types:["boolean"],envLink:"OTHER_VALIDATION",description:"Whether or not to enable validation of options types",promptOptions:{type:"toggle"}}},debug:{enable:{value:!1,types:["boolean"],envLink:"DEBUG_ENABLE",cliName:"enableDebug",description:"Enables or disables debug mode for the underlying browser",promptOptions:{type:"toggle"}},headless:{value:!1,types:["boolean"],envLink:"DEBUG_HEADLESS",description:"Whether or not to set the browser to run in headless mode during debugging",promptOptions:{type:"toggle"}},devtools:{value:!1,types:["boolean"],envLink:"DEBUG_DEVTOOLS",description:"Enables or disables DevTools in headful mode",promptOptions:{type:"toggle"}},listenToConsole:{value:!1,types:["boolean"],envLink:"DEBUG_LISTEN_TO_CONSOLE",description:"Enables or disables listening to console messages from the browser",promptOptions:{type:"toggle"}},dumpio:{value:!1,types:["boolean"],envLink:"DEBUG_DUMPIO",description:"Redirects or not browser stdout and stderr to process.stdout and process.stderr",promptOptions:{type:"toggle"}},slowMo:{value:0,types:["number"],envLink:"DEBUG_SLOW_MO",description:"Delays Puppeteer operations by the specified milliseconds",promptOptions:{type:"number"}},debuggingPort:{value:9222,types:["number"],envLink:"DEBUG_DEBUGGING_PORT",description:"Port used for debugging",promptOptions:{type:"number"}}}},nestedProps=_createNestedProps(defaultConfig),absoluteProps=_createAbsoluteProps(defaultConfig);function _createNestedProps(e,t={},o=""){return Object.keys(e).forEach((r=>{const i=e[r];void 0===i.value?_createNestedProps(i,t,`${o}.${r}`):(t[i.cliName||r]=`${o}.${r}`.substring(1),void 0!==i.legacyName&&(t[i.legacyName]=`${o}.${r}`.substring(1)))})),t}function _createAbsoluteProps(e,t=[]){return Object.keys(e).forEach((o=>{const r=e[o];void 0===r.types?_createAbsoluteProps(r,t):r.types.includes("Object")&&t.push(o)})),t}dotenv.config();const{coreScripts:coreScripts,moduleScripts:moduleScripts,indicatorScripts:indicatorScripts}=defaultConfig.highcharts;zod.z.setErrorMap(_customErrorMap);const v={boolean:e=>e?zod.z.boolean():zod.z.union([zod.z.enum(["true","1","false","0","undefined","null",""]).transform((e=>["undefined","null",""].includes(e)?null:"true"===e||"1"===e)),zod.z.boolean()]).nullable(),string:e=>e?zod.z.string().trim().refine((e=>!["false","undefined","null",""].includes(e)),{params:{errorMessage:"The string contains a forbidden value"}}):zod.z.string().trim().transform((e=>["false","undefined","null",""].includes(e)?null:e)).nullable(),enum:(e,t)=>t?zod.z.enum([...e]):zod.z.enum([...e,"undefined","null",""]).transform((e=>["undefined","null",""].includes(e)?null:e)).nullable(),stringArray(e,t,o){const r=zod.z.string().trim().array(),i=zod.z.string().trim().transform((e=>(e.startsWith("[")&&(e=e.slice(1)),e.endsWith("]")&&(e=e.slice(0,-1)),e.split(t)))),n=t=>t.map((e=>e.trim())).filter(e);return o?r.transform(n):zod.z.union([i,r]).transform(n).transform((e=>e.length?e:null)).nullable()},positiveNum:e=>e?zod.z.number().positive():zod.z.union([zod.z.string().trim().refine((e=>!isNaN(Number(e))&&Number(e)>0||["undefined","null",""].includes(e)),{params:{errorMessage:"The value must be numeric and positive"}}).transform((e=>["undefined","null",""].includes(e)?null:Number(e))),zod.z.number().positive()]).nullable(),nonNegativeNum:e=>e?zod.z.number().nonnegative():zod.z.union([zod.z.string().trim().refine((e=>!isNaN(Number(e))&&Number(e)>=0||["undefined","null",""].includes(e)),{params:{errorMessage:"The value must be numeric and non-negative"}}).transform((e=>["undefined","null",""].includes(e)?null:Number(e))),zod.z.number().nonnegative()]).nullable(),startsWith:(e,t)=>t?zod.z.string().trim().refine((t=>e.some((e=>t.startsWith(e)))),{params:{errorMessage:`The value must be a string that starts with ${e.join(", ")}`}}):zod.z.string().trim().refine((t=>e.some((e=>t.startsWith(e)))||["undefined","null",""].includes(t)),{params:{errorMessage:`The value must be a string that starts with ${e.join(", ")}`}}).transform((e=>["undefined","null",""].includes(e)?null:e)).nullable(),chartConfig:()=>zod.z.union([zod.z.string().trim().refine((e=>e.startsWith("{")&&e.endsWith("}")||["undefined","null",""].includes(e)),{params:{errorMessage:"The value must be a string that starts with '{' and ends with '}'"}}).transform((e=>["undefined","null",""].includes(e)?null:e)),zod.z.object({}).passthrough()]).nullable(),additionalOptions:()=>zod.z.union([zod.z.string().trim().refine((e=>e.length>=6&&e.endsWith(".json")||e.startsWith("{")&&e.endsWith("}")||["undefined","null",""].includes(e)),{params:{errorMessage:"The value must be a string that ends with '.json' or starts with '{' and ends with '}'"}}).transform((e=>["undefined","null",""].includes(e)?null:e)),zod.z.object({}).passthrough()]).nullable()},validators={args:e=>v.stringArray((e=>!["false","undefined","null",""].includes(e)),";",e),version:e=>e?zod.z.string().trim().refine((e=>/^(latest|\d{1,2}(\.\d{1,2}){0,2})$/.test(e)),{params:{errorMessage:"The value must be 'latest', a major version, or in the form XX.YY.ZZ"}}):zod.z.string().trim().refine((e=>/^(latest|\d{1,2}(\.\d{1,2}){0,2})$/.test(e)||["undefined","null",""].includes(e)),{params:{errorMessage:"The value must be 'latest', a major version, or in the form XX.YY.ZZ"}}).transform((e=>["undefined","null",""].includes(e)?null:e)).nullable(),cdnUrl:e=>v.startsWith(["http://","https://"],e),forceFetch:e=>v.boolean(e),cachePath:e=>v.string(e),adminToken:e=>v.string(e),coreScripts:e=>v.stringArray((e=>coreScripts.value.includes(e)),",",e),moduleScripts:e=>v.stringArray((e=>moduleScripts.value.includes(e)),",",e),indicatorScripts:e=>v.stringArray((e=>indicatorScripts.value.includes(e)),",",e),customScripts:e=>v.stringArray((e=>e.startsWith("https://")||e.startsWith("http://")),",",e),infile:e=>e?zod.z.string().trim().refine((e=>e.length>=6&&e.endsWith(".json")||e.length>=5&&e.endsWith(".svg")),{params:{errorMessage:"The value must be a string that ends with .json or .svg"}}).nullable():zod.z.string().trim().refine((e=>e.length>=6&&e.endsWith(".json")||e.length>=5&&e.endsWith(".svg")||["undefined","null",""].includes(e)),{params:{errorMessage:"The value must be a string that ends with .json or .svg"}}).transform((e=>["undefined","null",""].includes(e)?null:e)).nullable(),instr:()=>v.chartConfig(),options:()=>v.chartConfig(),svg:()=>zod.z.string().trim().refine((e=>e.indexOf("=0||e.indexOf("=0||["false","undefined","null",""].includes(e)),{params:{errorMessage:"The value must be a string that contains '["false","undefined","null",""].includes(e)?null:e)).nullable(),outfile:e=>e?zod.z.string().trim().refine((e=>e.length>=6&&e.endsWith(".jpeg")||e.length>=5&&(e.endsWith(".jpg")||e.endsWith(".png")||e.endsWith(".pdf")||e.endsWith(".svg"))),{params:{errorMessage:"The value must be a string that ends with .jpeg, .jpg, .png, .pdf, or .svg"}}).nullable():zod.z.string().trim().refine((e=>e.length>=6&&e.endsWith(".jpeg")||e.length>=5&&(e.endsWith(".jpg")||e.endsWith(".png")||e.endsWith(".pdf")||e.endsWith(".svg"))||["undefined","null",""].includes(e)),{params:{errorMessage:"The value must be a string that ends with .jpeg, .jpg, .png, .pdf, or .svg"}}).transform((e=>["undefined","null",""].includes(e)?null:e)).nullable(),type:e=>v.enum(["jpeg","jpg","png","pdf","svg"],e),constr:e=>v.enum(["chart","stockChart","mapChart","ganttChart"],e),b64:e=>v.boolean(e),noDownload:e=>v.boolean(e),defaultHeight:e=>v.positiveNum(e),defaultWidth:e=>v.positiveNum(e),defaultScale:e=>e?zod.z.number().gte(.1).lte(5):zod.z.union([zod.z.string().trim().refine((e=>!isNaN(Number(e))&&!0!==e&&!e.startsWith("[")&&Number(e)>=.1&&Number(e)<=5||["undefined","null",""].includes(e)),{params:{errorMessage:"The value must be within a 0.1 and 5.0 range"}}).transform((e=>["undefined","null",""].includes(e)?null:Number(e))),zod.z.number().gte(.1).lte(5)]).nullable(),height(e){return this.defaultHeight(e).nullable()},width(e){return this.defaultWidth(e).nullable()},scale(e){return this.defaultScale(e).nullable()},globalOptions:()=>v.additionalOptions(),themeOptions:()=>v.additionalOptions(),batch:e=>v.string(e),rasterizationTimeout:e=>v.nonNegativeNum(e),allowCodeExecution:e=>v.boolean(e),allowFileResources:e=>v.boolean(e),customCode:e=>v.string(e),callback:e=>v.string(e),resources(e){const t=zod.z.object({js:v.string(!1),css:v.string(!1),files:v.stringArray((e=>!["undefined","null",""].includes(e)),",",!0).nullable()}).partial(),o=zod.z.string().trim().refine((e=>e.startsWith("{")&&e.endsWith("}")||e.length>=6&&e.endsWith(".json")),{params:{errorMessage:"The value must be a string that starts with '{' and ends with '}"}}),r=zod.z.string().trim().refine((e=>e.startsWith("{")&&e.endsWith("}")||e.length>=6&&e.endsWith(".json")||["undefined","null",""].includes(e)),{params:{errorMessage:"The value must be a string that ends with .json"}}).transform((e=>["undefined","null",""].includes(e)?null:e));return e?zod.z.union([t,o]).nullable():zod.z.union([t,r]).nullable()},loadConfig:e=>v.string(e).refine((e=>null===e||e.length>=6&&e.endsWith(".json")),{params:{errorMessage:"The value must be a string that ends with .json"}}),createConfig(e){return this.loadConfig(e)},enableServer:e=>v.boolean(e),host:e=>v.string(e),port:e=>v.nonNegativeNum(e),uploadLimit:e=>v.positiveNum(e),serverBenchmarking:e=>v.boolean(e),proxyHost:e=>v.string(e),proxyPort:e=>v.nonNegativeNum(e).nullable(),proxyTimeout:e=>v.nonNegativeNum(e),enableRateLimiting:e=>v.boolean(e),maxRequests:e=>v.nonNegativeNum(e),window:e=>v.nonNegativeNum(e),delay:e=>v.nonNegativeNum(e),trustProxy:e=>v.boolean(e),skipKey:e=>v.string(e),skipToken:e=>v.string(e),enableSsl:e=>v.boolean(e),sslForce:e=>v.boolean(e),sslPort:e=>v.nonNegativeNum(e),sslCertPath:e=>v.string(e),minWorkers:e=>v.positiveNum(e),maxWorkers:e=>v.positiveNum(e),workLimit:e=>v.positiveNum(e),acquireTimeout:e=>v.nonNegativeNum(e),createTimeout:e=>v.nonNegativeNum(e),destroyTimeout:e=>v.nonNegativeNum(e),idleTimeout:e=>v.nonNegativeNum(e),createRetryInterval:e=>v.nonNegativeNum(e),reaperInterval:e=>v.nonNegativeNum(e),poolBenchmarking:e=>v.boolean(e),resourcesInterval:e=>v.nonNegativeNum(e),logLevel:e=>e?zod.z.number().int().gte(0).lte(5):zod.z.union([zod.z.string().trim().refine((e=>!isNaN(Number(e))&&!0!==e&&!e.startsWith("[")&&Number.isInteger(Number(e))&&Number(e)>=0&&Number(e)<=5||["undefined","null",""].includes(e)),{params:{errorMessage:"The value must be within a 0 and 5 range"}}).transform((e=>["undefined","null",""].includes(e)?null:Number(e))),zod.z.number().int().gte(0).lte(5)]).nullable(),logFile:e=>v.string(e).refine((e=>null===e||e.length>=5&&e.endsWith(".log")),{params:{errorMessage:"The value must be a string that ends with .log"}}),logDest:e=>v.string(e),logToConsole:e=>v.boolean(e),logToFile:e=>v.boolean(e),enableUi:e=>v.boolean(e),uiRoute:e=>v.startsWith(["/"],e),nodeEnv:e=>v.enum(["development","production","test"],e),listenToProcessExits:e=>v.boolean(e),noLogo:e=>v.boolean(e),hardResetPage:e=>v.boolean(e),browserShellMode:e=>v.boolean(e),validation:e=>v.boolean(e),enableDebug:e=>v.boolean(e),headless:e=>v.boolean(e),devtools:e=>v.boolean(e),listenToConsole:e=>v.boolean(e),dumpio:e=>v.boolean(e),slowMo:e=>v.nonNegativeNum(e),debuggingPort:e=>v.nonNegativeNum(e),requestId:()=>zod.z.string().uuid({message:"The value must be a stringified UUID"}).nullable()},PuppeteerSchema=e=>zod.z.object({args:validators.args(e)}).partial(),HighchartsSchema=e=>zod.z.object({version:validators.version(e),cdnUrl:validators.cdnUrl(e),forceFetch:validators.forceFetch(e),cachePath:validators.cachePath(e),coreScripts:validators.coreScripts(e),moduleScripts:validators.moduleScripts(e),indicatorScripts:validators.indicatorScripts(e),customScripts:validators.customScripts(e)}).partial(),ExportSchema=e=>zod.z.object({infile:validators.infile(e),instr:validators.instr(),options:validators.options(),svg:validators.svg(),outfile:validators.outfile(e),type:validators.type(e),constr:validators.constr(e),b64:validators.b64(e),noDownload:validators.noDownload(e),defaultHeight:validators.defaultHeight(e),defaultWidth:validators.defaultWidth(e),defaultScale:validators.defaultScale(e),height:validators.height(e),width:validators.width(e),scale:validators.scale(e),globalOptions:validators.globalOptions(),themeOptions:validators.themeOptions(),batch:validators.batch(!1),rasterizationTimeout:validators.rasterizationTimeout(e)}).partial(),CustomLogicSchema=e=>zod.z.object({allowCodeExecution:validators.allowCodeExecution(e),allowFileResources:validators.allowFileResources(e),customCode:validators.customCode(!1),callback:validators.callback(!1),resources:validators.resources(e),loadConfig:validators.loadConfig(!1),createConfig:validators.createConfig(!1)}).partial(),ProxySchema=e=>zod.z.object({host:validators.proxyHost(!1),port:validators.proxyPort(e),timeout:validators.proxyTimeout(e)}).partial(),RateLimitingSchema=e=>zod.z.object({enable:validators.enableRateLimiting(e),maxRequests:validators.maxRequests(e),window:validators.window(e),delay:validators.delay(e),trustProxy:validators.trustProxy(e),skipKey:validators.skipKey(!1),skipToken:validators.skipToken(!1)}).partial(),SslSchema=e=>zod.z.object({enable:validators.enableSsl(e),force:validators.sslForce(e),port:validators.sslPort(e),certPath:validators.sslCertPath(!1)}).partial(),ServerSchema=e=>zod.z.object({enable:validators.enableServer(e).optional(),host:validators.host(e).optional(),port:validators.port(e).optional(),uploadLimit:validators.uploadLimit(e).optional(),benchmarking:validators.serverBenchmarking(e).optional(),proxy:ProxySchema(e).optional(),rateLimiting:RateLimitingSchema(e).optional(),ssl:SslSchema(e).optional()}),PoolSchema=e=>zod.z.object({minWorkers:validators.minWorkers(e),maxWorkers:validators.maxWorkers(e),workLimit:validators.workLimit(e),acquireTimeout:validators.acquireTimeout(e),createTimeout:validators.createTimeout(e),destroyTimeout:validators.destroyTimeout(e),idleTimeout:validators.idleTimeout(e),createRetryInterval:validators.createRetryInterval(e),reaperInterval:validators.reaperInterval(e),benchmarking:validators.poolBenchmarking(e)}).partial(),LoggingSchema=e=>zod.z.object({level:validators.logLevel(e),file:validators.logFile(e),dest:validators.logDest(e),toConsole:validators.logToConsole(e),toFile:validators.logToFile(e)}).partial(),UiSchema=e=>zod.z.object({enable:validators.enableUi(e),route:validators.uiRoute(e)}).partial(),OtherSchema=e=>zod.z.object({nodeEnv:validators.nodeEnv(e),listenToProcessExits:validators.listenToProcessExits(e),noLogo:validators.noLogo(e),hardResetPage:validators.hardResetPage(e),browserShellMode:validators.browserShellMode(e),validation:validators.validation(e)}).partial(),DebugSchema=e=>zod.z.object({enable:validators.enableDebug(e),headless:validators.headless(e),devtools:validators.devtools(e),listenToConsole:validators.listenToConsole(e),dumpio:validators.dumpio(e),slowMo:validators.slowMo(e),debuggingPort:validators.debuggingPort(e)}).partial(),StrictConfigSchema=zod.z.object({requestId:validators.requestId(),puppeteer:PuppeteerSchema(!0),highcharts:HighchartsSchema(!0),export:ExportSchema(!0),customLogic:CustomLogicSchema(!0),server:ServerSchema(!0),pool:PoolSchema(!0),logging:LoggingSchema(!0),ui:UiSchema(!0),other:OtherSchema(!0),debug:DebugSchema(!0)}),LooseConfigSchema=zod.z.object({requestId:validators.requestId(),puppeteer:PuppeteerSchema(!1),highcharts:HighchartsSchema(!1),export:ExportSchema(!1),customLogic:CustomLogicSchema(!1),server:ServerSchema(!1),pool:PoolSchema(!1),logging:LoggingSchema(!1),ui:UiSchema(!1),other:OtherSchema(!1),debug:DebugSchema(!1)}),EnvSchema=zod.z.object({PUPPETEER_ARGS:validators.args(!1),HIGHCHARTS_VERSION:validators.version(!1),HIGHCHARTS_CDN_URL:validators.cdnUrl(!1),HIGHCHARTS_FORCE_FETCH:validators.forceFetch(!1),HIGHCHARTS_CACHE_PATH:validators.cachePath(!1),HIGHCHARTS_ADMIN_TOKEN:validators.adminToken(!1),HIGHCHARTS_CORE_SCRIPTS:validators.coreScripts(!1),HIGHCHARTS_MODULE_SCRIPTS:validators.moduleScripts(!1),HIGHCHARTS_INDICATOR_SCRIPTS:validators.indicatorScripts(!1),HIGHCHARTS_CUSTOM_SCRIPTS:validators.customScripts(!1),EXPORT_INFILE:validators.infile(!1),EXPORT_INSTR:validators.instr(),EXPORT_OPTIONS:validators.options(),EXPORT_SVG:validators.svg(),EXPORT_BATCH:validators.batch(!1),EXPORT_OUTFILE:validators.outfile(!1),EXPORT_TYPE:validators.type(!1),EXPORT_CONSTR:validators.constr(!1),EXPORT_B64:validators.b64(!1),EXPORT_NO_DOWNLOAD:validators.noDownload(!1),EXPORT_HEIGHT:validators.height(!1),EXPORT_WIDTH:validators.width(!1),EXPORT_SCALE:validators.scale(!1),EXPORT_DEFAULT_HEIGHT:validators.defaultHeight(!1),EXPORT_DEFAULT_WIDTH:validators.defaultWidth(!1),EXPORT_DEFAULT_SCALE:validators.defaultScale(!1),EXPORT_GLOBAL_OPTIONS:validators.globalOptions(),EXPORT_THEME_OPTIONS:validators.themeOptions(),EXPORT_RASTERIZATION_TIMEOUT:validators.rasterizationTimeout(!1),CUSTOM_LOGIC_ALLOW_CODE_EXECUTION:validators.allowCodeExecution(!1),CUSTOM_LOGIC_ALLOW_FILE_RESOURCES:validators.allowFileResources(!1),CUSTOM_LOGIC_CUSTOM_CODE:validators.customCode(!1),CUSTOM_LOGIC_CALLBACK:validators.callback(!1),CUSTOM_LOGIC_RESOURCES:validators.resources(!1),CUSTOM_LOGIC_LOAD_CONFIG:validators.loadConfig(!1),CUSTOM_LOGIC_CREATE_CONFIG:validators.createConfig(!1),SERVER_ENABLE:validators.enableServer(!1),SERVER_HOST:validators.host(!1),SERVER_PORT:validators.port(!1),SERVER_UPLOAD_LIMIT:validators.uploadLimit(!1),SERVER_BENCHMARKING:validators.serverBenchmarking(!1),SERVER_PROXY_HOST:validators.proxyHost(!1),SERVER_PROXY_PORT:validators.proxyPort(!1),SERVER_PROXY_TIMEOUT:validators.proxyTimeout(!1),SERVER_RATE_LIMITING_ENABLE:validators.enableRateLimiting(!1),SERVER_RATE_LIMITING_MAX_REQUESTS:validators.maxRequests(!1),SERVER_RATE_LIMITING_WINDOW:validators.window(!1),SERVER_RATE_LIMITING_DELAY:validators.delay(!1),SERVER_RATE_LIMITING_TRUST_PROXY:validators.trustProxy(!1),SERVER_RATE_LIMITING_SKIP_KEY:validators.skipKey(!1),SERVER_RATE_LIMITING_SKIP_TOKEN:validators.skipToken(!1),SERVER_SSL_ENABLE:validators.enableSsl(!1),SERVER_SSL_FORCE:validators.sslForce(!1),SERVER_SSL_PORT:validators.sslPort(!1),SERVER_SSL_CERT_PATH:validators.sslCertPath(!1),POOL_MIN_WORKERS:validators.minWorkers(!1),POOL_MAX_WORKERS:validators.maxWorkers(!1),POOL_WORK_LIMIT:validators.workLimit(!1),POOL_ACQUIRE_TIMEOUT:validators.acquireTimeout(!1),POOL_CREATE_TIMEOUT:validators.createTimeout(!1),POOL_DESTROY_TIMEOUT:validators.destroyTimeout(!1),POOL_IDLE_TIMEOUT:validators.idleTimeout(!1),POOL_CREATE_RETRY_INTERVAL:validators.createRetryInterval(!1),POOL_REAPER_INTERVAL:validators.reaperInterval(!1),POOL_BENCHMARKING:validators.poolBenchmarking(!1),LOGGING_LEVEL:validators.logLevel(!1),LOGGING_FILE:validators.logFile(!1),LOGGING_DEST:validators.logDest(!1),LOGGING_TO_CONSOLE:validators.logToConsole(!1),LOGGING_TO_FILE:validators.logToFile(!1),UI_ENABLE:validators.enableUi(!1),UI_ROUTE:validators.uiRoute(!1),OTHER_NODE_ENV:validators.nodeEnv(!1),OTHER_LISTEN_TO_PROCESS_EXITS:validators.listenToProcessExits(!1),OTHER_NO_LOGO:validators.noLogo(!1),OTHER_HARD_RESET_PAGE:validators.hardResetPage(!1),OTHER_BROWSER_SHELL_MODE:validators.browserShellMode(!1),OTHER_VALIDATION:validators.validation(!1),DEBUG_ENABLE:validators.enableDebug(!1),DEBUG_HEADLESS:validators.headless(!1),DEBUG_DEVTOOLS:validators.devtools(!1),DEBUG_LISTEN_TO_CONSOLE:validators.listenToConsole(!1),DEBUG_DUMPIO:validators.dumpio(!1),DEBUG_SLOW_MO:validators.slowMo(!1),DEBUG_DEBUGGING_PORT:validators.debuggingPort(!1)}),envs=EnvSchema.partial().parse(process.env);function strictValidate(e){return StrictConfigSchema.partial().parse(e)}function looseValidate(e){return LooseConfigSchema.partial().parse(e)}function _customErrorMap(e,t){const o=e.path.join("."),r=`Invalid value for the ${o}`;if(e.code===zod.z.ZodIssueCode.invalid_type)return e.received===zod.z.ZodParsedType.undefined?{message:`${r} - No value was provided.`}:{message:`${r} - Invalid type. ${t.defaultError}.`};if(e.code===zod.z.ZodIssueCode.custom&&e.params?.errorMessage)return{message:`${r} - ${e.params?.errorMessage}, received '${t.data}'.`};if(e.code===zod.z.ZodIssueCode.invalid_union){let t=`Multiple errors occurred for the ${o}:\n`;return e.unionErrors.forEach((e=>{const o=e.issues[0].message.indexOf("-");t+=-1!==o?`${e.issues[0].message}\n`.substring(o):`${e.issues[0].message}\n`})),{message:t}}return{message:`${r} - ${t.defaultError}.`}}class ExportError extends Error{constructor(e,t){super(),this.message=e,this.stackMessage=e,t&&(this.statusCode=t)}setStatus(e){return this.statusCode=e,this}setError(e){return this.error=e,e.name&&(this.name=e.name),e.statusCode&&(this.statusCode=e.statusCode),e.stack&&(this.stackMessage=e.message,this.stack=e.stack),this}}const globalOptions=_initOptions(defaultConfig);function getOptions(e=!0){return e?deepCopy(globalOptions):globalOptions}function updateOptions(e,t=!1){return _mergeOptions(getOptions(t),e)}function mapToNewOptions(e){const t={};if(isObject(e))for(const[o,r]of Object.entries(e)){const e=nestedProps[o]?nestedProps[o].split("."):[];e.reduce(((t,o,i)=>t[o]=e.length-1===i?r:t[o]||{}),t)}else log(2,"[config] No correct object with options was provided. Returning an empty array.");return t}function validateOption(e,t,o=!0){if(!getOptions().other.validation)return t;try{return validators[e](o).parse(t)}catch(t){throw logZodIssues(1,t.issues,`[validation] The ${e} option validation error`),new ExportError(`[validation] The ${e} option validation error`,400)}}function validateOptions(e,t=!0){if(!getOptions().other.validation)return e;try{return t?strictValidate(e):looseValidate(e)}catch(e){throw logZodIssues(1,e.issues,"[validation] Options validation error"),new ExportError("[validation] Options validation error",400)}}function isAllowedConfig(config,toString=!1,allowFunctions=!1){try{if(!isObject(config)&&"string"!=typeof config)return null;const objectConfig="string"==typeof config?allowFunctions?eval(`(${config})`):JSON.parse(config):config,stringifiedOptions=_optionsStringify(objectConfig,allowFunctions,!1),parsedOptions=allowFunctions?JSON.parse(_optionsStringify(objectConfig,allowFunctions,!0),((_,value)=>"string"==typeof value&&value.startsWith("function")?eval(`(${value})`):value)):JSON.parse(stringifiedOptions);return toString?stringifiedOptions:parsedOptions}catch(e){return null}}function _initOptions(e){const t={};for(const[o,r]of Object.entries(e))Object.prototype.hasOwnProperty.call(r,"value")?void 0!==envs[r.envLink]&&null!==envs[r.envLink]?t[o]=envs[r.envLink]:t[o]=r.value:t[o]=_initOptions(r);return t}function _mergeOptions(e,t){if(isObject(e)&&isObject(t))for(const[o,r]of Object.entries(t))e[o]=isObject(r)&&!absoluteProps.includes(o)&&void 0!==e[o]?_mergeOptions(e[o],r):void 0!==r?r:e[o]||null;return e}function _optionsStringify(e,t,o){return JSON.stringify(e,((e,r)=>{if("string"==typeof r&&(r=r.trim()),"function"==typeof r||"string"==typeof r&&r.startsWith("function")&&r.endsWith("}")){if(t)return o?`"EXP_FUN${(r+"").replaceAll(/\s+/g," ")}EXP_FUN"`:`EXP_FUN${(r+"").replaceAll(/\s+/g," ")}EXP_FUN`;throw new Error}return r})).replaceAll(o?/\\"EXP_FUN|EXP_FUN\\"/g:/"EXP_FUN|EXP_FUN"/g,"")}async function fetch(e,t={}){return new Promise(((o,r)=>{_getProtocolModule(e).get(e,t,(e=>{let t="";e.on("data",(e=>{t+=e})),e.on("end",(()=>{t||r("Nothing was fetched from the URL."),e.text=t,o(e)}))})).on("error",(e=>{r(e)}))}))}function _getProtocolModule(e){return e.startsWith("https")?https:http}const cache={cdnUrl:"https://code.highcharts.com",activeManifest:{},sources:"",hcVersion:""};async function checkAndUpdateCache(e,t){try{let o;const r=getCachePath(),i=path.join(r,"manifest.json"),n=path.join(r,"sources.js");if(!fs.existsSync(r)&&fs.mkdirSync(r,{recursive:!0}),!fs.existsSync(i)||e.forceFetch)log(3,"[cache] Fetching and caching Highcharts dependencies."),o=await _updateCache(e,t,n);else{let r=!1;const s=JSON.parse(fs.readFileSync(i),"utf8");if(s.modules&&Array.isArray(s.modules)){const e={};s.modules.forEach((t=>e[t]=1)),s.modules=e}const{coreScripts:a,moduleScripts:l,indicatorScripts:c}=e,p=a.length+l.length+c.length;s.version!==e.version?(log(2,"[cache] A Highcharts version mismatch in the cache, need to re-fetch."),r=!0):Object.keys(s.modules||{}).length!==p?(log(2,"[cache] The cache and the requested modules do not match, need to re-fetch."),r=!0):r=(l||[]).some((e=>{if(!s.modules[e])return log(2,`[cache] The ${e} is missing in the cache, need to re-fetch.`),!0})),r?o=await _updateCache(e,t,n):(log(3,"[cache] Dependency cache is up to date, proceeding."),cache.sources=fs.readFileSync(n,"utf8"),o=s.modules,cache.hcVersion=extractVersion(cache.sources))}await _saveConfigToManifest(e,o)}catch(e){throw new ExportError("[cache] Could not configure cache and create or update the config manifest.",500).setError(e)}}function getHighchartsVersion(){return cache.hcVersion}async function updateHighchartsVersion(e){const t=updateOptions({highcharts:{version:e}});await checkAndUpdateCache(t.highcharts,t.server.proxy)}function extractVersion(e){return e.substring(0,e.indexOf("*/")).replace("/*","").replace("*/","").replace(/\n/g,"").trim()}function extractModuleName(e){return e.replace(/(.*)\/|(.*)modules\/|stock\/(.*)indicators\/|maps\/(.*)modules\//gi,"")}function getCachePath(){return getAbsolutePath(getOptions().highcharts.cachePath)}async function _fetchAndProcessScript(e,t,o,r=!1){e.endsWith(".js")&&(e=e.substring(0,e.length-3)),log(4,`[cache] Fetching script - ${e}.js`);const i=await fetch(`${e}.js`,t);if(200===i.statusCode&&"string"==typeof i.text){if(o){o[extractModuleName(e)]=1}return i.text}if(r)throw new ExportError(`[cache] Could not fetch the ${e}.js. The script might not exist in the requested version (status code: ${i.statusCode}).`,404).setError(i);log(2,`[cache] Could not fetch the ${e}.js. The script might not exist in the requested version.`)}async function _saveConfigToManifest(e,t={}){const o={version:e.version,modules:t};cache.activeManifest=o,log(3,"[cache] Writing a new manifest.");try{fs.writeFileSync(path.join(getCachePath(),"manifest.json"),JSON.stringify(o),"utf8")}catch(e){throw new ExportError("[cache] Error writing the cache manifest.",500).setError(e)}}async function _fetchScripts(e,t,o,r,i){let n;const s=r.host,a=r.port;if(s&&a)try{n=new httpsProxyAgent.HttpsProxyAgent({host:s,port:a})}catch(e){throw new ExportError("[cache] Could not create a Proxy Agent.",500).setError(e)}const l=n?{agent:n,timeout:r.timeout}:{},c=[...e.map((e=>_fetchAndProcessScript(`${e}`,l,i,!0))),...t.map((e=>_fetchAndProcessScript(`${e}`,l,i))),...o.map((e=>_fetchAndProcessScript(`${e}`,l)))];return(await Promise.all(c)).join(";\n")}async function _updateCache(e,t,o){const r="latest"===e.version?null:`${e.version}`,i=e.cdnUrl||cache.cdnUrl;try{const n={};return log(3,`[cache] Updating cache version to Highcharts: ${r||"latest"}.`),cache.sources=await _fetchScripts([...e.coreScripts.map((e=>r?`${i}/${r}/${e}`:`${i}/${e}`))],[...e.moduleScripts.map((e=>"map"===e?r?`${i}/maps/${r}/modules/${e}`:`${i}/maps/modules/${e}`:r?`${i}/${r}/modules/${e}`:`${i}/modules/${e}`)),...e.indicatorScripts.map((e=>r?`${i}/stock/${r}/indicators/${e}`:`${i}/stock/indicators/${e}`))],e.customScripts,t,n),cache.hcVersion=extractVersion(cache.sources),fs.writeFileSync(o,cache.sources),n}catch(e){throw new ExportError("[cache] Unable to update the local Highcharts cache.",500).setError(e)}}function setupHighcharts(){Highcharts.animObject=function(){return{duration:0}}}async function createChart(e,t){const{getOptions:o,setOptions:r,merge:i,wrap:n}=Highcharts;Highcharts.setOptionsObj=i(!1,{},o()),window.isRenderComplete=!1,n(Highcharts.Chart.prototype,"init",(function(e,t,o){((t=i(t,{exporting:{enabled:!1},plotOptions:{series:{label:{enabled:!1}}},tooltip:{}})).series||[]).forEach((function(e){e.animation=!1})),window.onHighchartsRender||(window.onHighchartsRender=Highcharts.addEvent(this,"render",(()=>{window.isRenderComplete=!0}))),e.apply(this,[t,o])})),n(Highcharts.Series.prototype,"init",(function(e,t,o){e.apply(this,[t,o])}));const s={chart:{animation:!1,height:e.height,width:e.width},exporting:{enabled:!1}},a=new Function(`return ${e.instr}`)(),l=new Function(`return ${e.themeOptions}`)(),c=new Function(`return ${e.globalOptions}`)(),p=i(!1,l,a,s),u=t.callback?new Function(`return ${t.callback}`)():null;t.customCode&&new Function("options",t.customCode)(a),c&&r(c),Highcharts[e.constr]("container",p,u);const d=o();for(const e in d)"function"!=typeof d[e]&&delete d[e];r(Highcharts.setOptionsObj),Highcharts.setOptionsObj={}}const template=fs.readFileSync(path.join(__dirname$1,"templates","template.html"),"utf8");let browser=null;async function createBrowser(e){const{debug:t,other:o}=getOptions(),{enable:r,...i}=t,n={headless:!o.browserShellMode||"shell",userDataDir:"tmp",args:e||[],handleSIGINT:!1,handleSIGTERM:!1,handleSIGHUP:!1,waitForInitialPage:!1,defaultViewport:null,...r&&i};if(!browser){let e=0;const t=async()=>{try{log(3,`[browser] Attempting to get a browser instance (try ${++e}).`),browser=await puppeteer.launch(n)}catch(o){if(logWithStack(1,o,"[browser] Failed to launch a browser instance."),!(e<25))throw o;log(3,`[browser] Retry to open a browser (${e} out of 25).`),await new Promise((e=>setTimeout(e,4e3))),await t()}};try{await t(),"shell"===n.headless&&log(3,"[browser] Launched browser in shell mode."),r&&log(3,"[browser] Launched browser in debug mode.")}catch(e){throw new ExportError("[browser] Maximum retries to open a browser instance reached.",500).setError(e)}if(!browser)throw new ExportError("[browser] Cannot find a browser to open.",500)}return browser}async function closeBrowser(){browser&&browser.connected&&await browser.close(),browser=null,log(4,"[browser] Closed the browser.")}async function newPage(e){if(!browser||!browser.connected)throw new ExportError("[browser] Browser is not yet connected.",500);if(e.page=await browser.newPage(),await e.page.setCacheEnabled(!1),await _setPageContent(e.page),_setPageEvents(e.page),!e.page||e.page.isClosed())throw new ExportError("[browser] The page is invalid or closed.",400)}async function clearPage(e,t=!1){try{if(e.page&&!e.page.isClosed())return t?(await e.page.goto("about:blank",{waitUntil:"domcontentloaded"}),await _setPageContent(e.page)):await e.page.evaluate((()=>{document.body.innerHTML='
'})),!0}catch(t){logWithStack(2,t,`[pool] Pool resource [${e.id}] - Content of the page could not be cleared.`),e.workCount=getOptions().pool.workLimit+1}return!1}async function addPageResources(e,t){const o=[],r=t.resources;if(r){const i=[];if(r.js&&i.push({content:r.js}),r.files)for(const e of r.files){const t=!e.startsWith("http");i.push(t?{content:fs.readFileSync(getAbsolutePath(e),"utf8")}:{url:e})}for(const t of i)try{o.push(await e.addScriptTag(t))}catch(e){logWithStack(2,e,"[browser] The JS resource cannot be loaded.")}i.length=0;const n=[];if(r.css){let i=r.css.match(/@import\s*([^;]*);/g);if(i)for(let e of i)e&&(e=e.replace("url(","").replace("@import","").replace(/"/g,"").replace(/'/g,"").replace(/;/,"").replace(/\)/g,"").trim(),e.startsWith("http")?n.push({url:e}):t.allowFileResources&&n.push({path:getAbsolutePath(e)}));n.push({content:r.css.replace(/@import\s*([^;]*);/g,"")||" "});for(const t of n)try{o.push(await e.addStyleTag(t))}catch(e){logWithStack(2,e,"[browser] The CSS resource cannot be loaded.")}n.length=0}}return o}async function clearPageResources(e,t){try{for(const e of t)await e.dispose();await e.evaluate((()=>{if("undefined"!=typeof Highcharts){const e=Highcharts.charts;if(Array.isArray(e)&&e.length)for(const t of e)t&&t.destroy(),Highcharts.charts.shift()}const[...e]=document.getElementsByTagName("script"),[,...t]=document.getElementsByTagName("style"),[...o]=document.getElementsByTagName("link");for(const r of[...e,...t,...o])r.remove()}))}catch(e){logWithStack(2,e,"[browser] Could not clear page's resources.")}}async function _setPageContent(e){await e.setContent(template,{waitUntil:"domcontentloaded"}),await e.addScriptTag({path:path.join(getCachePath(),"sources.js")}),await e.evaluate(setupHighcharts)}function _setPageEvents(e){const{debug:t}=getOptions();e.on("pageerror",(async()=>{e.isClosed()})),t.enable&&t.listenToConsole&&e.on("console",(e=>{console.log(`[debug] ${e.text()}`)}))}var cssTemplate=()=>"\n\nhtml, body {\n margin: 0;\n padding: 0;\n box-sizing: border-box;\n}\n\n#table-div, #sliders, #datatable, #controls, .ld-row {\n display: none;\n height: 0;\n}\n\n#chart-container {\n box-sizing: border-box;\n margin: 0;\n overflow: auto;\n font-size: 0;\n}\n\n#chart-container > figure, div {\n margin-top: 0 !important;\n margin-bottom: 0 !important;\n}\n\n",svgTemplate=e=>`\n\n\n \n \n Highcharts Export\n \n \n \n
\n ${e}\n
\n \n\n\n`;async function puppeteerExport(e,t,o){const r=[];try{let i=!1;if(t.svg){if(log(4,"[export] Treating as SVG input."),"svg"===t.type)return t.svg;i=!0,await e.setContent(svgTemplate(t.svg),{waitUntil:"domcontentloaded"})}else log(4,"[export] Treating as JSON config."),await e.evaluate(createChart,t,o);r.push(...await addPageResources(e,o));const n=i?await e.evaluate((e=>{const t=document.querySelector("#chart-container svg:first-of-type"),o=t.height.baseVal.value*e,r=t.width.baseVal.value*e;return document.body.style.zoom=e,document.body.style.margin="0px",{chartHeight:o,chartWidth:r}}),parseFloat(t.scale)):await e.evaluate((()=>{const{chartHeight:e,chartWidth:t}=window.Highcharts.charts[0];return document.body.style.zoom=1,{chartHeight:e,chartWidth:t}})),{x:s,y:a}=await _getClipRegion(e),l=Math.abs(Math.ceil(n.chartHeight||t.height)),c=Math.abs(Math.ceil(n.chartWidth||t.width));let p;switch(await e.setViewport({height:l,width:c,deviceScaleFactor:i?1:parseFloat(t.scale)}),t.type){case"svg":p=await _createSVG(e);break;case"png":case"jpeg":p=await _createImage(e,t.type,{width:c,height:l,x:s,y:a},t.rasterizationTimeout);break;case"pdf":p=await _createPDF(e,l,c,t.rasterizationTimeout);break;default:throw new ExportError(`[export] Unsupported output format: ${t.type}.`,400)}return await clearPageResources(e,r),p}catch(t){return await clearPageResources(e,r),t}}async function _getClipRegion(e){return e.$eval("#chart-container",(e=>{const{x:t,y:o,width:r,height:i}=e.getBoundingClientRect();return{x:t,y:o,width:r,height:Math.trunc(i>1?i:500)}}))}async function _createSVG(e){return e.$eval("#container svg:first-of-type",(e=>e.outerHTML))}async function _createImage(e,t,o,r){return Promise.race([e.screenshot({type:t,clip:o,encoding:"base64",fullPage:!1,optimizeForSpeed:!0,captureBeyondViewport:!0,..."png"!==t?{quality:80}:{},omitBackground:"png"==t}),new Promise(((e,t)=>setTimeout((()=>t(new ExportError("Rasterization timeout",408))),r||1500)))])}async function _createPDF(e,t,o,r){return await e.emulateMediaType("screen"),e.pdf({height:t+1,width:o,encoding:"base64",timeout:r||1500})}let pool=null;const poolStats={exportsAttempted:0,exportsPerformed:0,exportsDropped:0,exportsFromSvg:0,exportsFromOptions:0,exportsFromSvgAttempts:0,exportsFromOptionsAttempts:0,timeSpent:0,timeSpentAverage:0};async function initPool(e,t){await createBrowser(t);try{if(log(3,`[pool] Initializing pool with workers: min ${e.minWorkers}, max ${e.maxWorkers}.`),pool)return void log(4,"[pool] Already initialized, please kill it before creating a new one.");e.minWorkers>e.maxWorkers&&(e.minWorkers=e.maxWorkers),pool=new tarn.Pool({..._factory(e),min:e.minWorkers,max:e.maxWorkers,acquireTimeoutMillis:e.acquireTimeout,createTimeoutMillis:e.createTimeout,destroyTimeoutMillis:e.destroyTimeout,idleTimeoutMillis:e.idleTimeout,createRetryIntervalMillis:e.createRetryInterval,reapIntervalMillis:e.reaperInterval,propagateCreateError:!1}),pool.on("release",(async e=>{const t=await clearPage(e,!1);log(4,`[pool] Pool resource [${e.id}] - Releasing a worker. Clear page status: ${t}.`)})),pool.on("destroySuccess",((e,t)=>{log(4,`[pool] Pool resource [${t.id}] - Destroyed a worker successfully.`),t.page=null}));const t=[];for(let o=0;o{pool.release(e)})),log(3,"[pool] The pool is ready"+(t.length?` with ${t.length} initial resources waiting.`:"."))}catch(e){throw new ExportError("[pool] Could not configure and create the pool of workers.",500).setError(e)}}async function killPool(){if(log(3,"[pool] Killing pool with all workers and closing browser."),pool){for(const e of pool.used)pool.release(e.resource);pool.destroyed||(await pool.destroy(),log(4,"[pool] Destroyed the pool of resources.")),pool=null}await closeBrowser()}async function postWork(e){let t;try{if(log(4,"[pool] Work received, starting to process."),++poolStats.exportsAttempted,e.pool.benchmarking&&getPoolInfo(),!pool)throw new ExportError("[pool] Work received, but pool has not been started.",500);const o=measureTime();try{log(4,"[pool] Acquiring a worker handle."),t=await pool.acquire().promise,e.server.benchmarking&&log(5,"[benchmark] "+(e.requestId?`Request [${e.requestId}] - `:""),`Acquiring a worker handle took ${o()}ms.`)}catch(t){throw new ExportError(`[pool] ${e.requestId?`Request [${e.requestId}] - `:""}Error encountered when acquiring an available entry: ${o()}ms.`,400).setError(t)}if(log(4,"[pool] Acquired a worker handle."),!t.page)throw t.workCount=e.pool.workLimit+1,new ExportError("[pool] Resolved worker page is invalid: the pool setup is wonky.",400);const r=getNewDateTime();log(4,`[pool] Pool resource [${t.id}] - Starting work on this pool entry.`);const i=measureTime(),n=await puppeteerExport(t.page,e.export,e.customLogic);if(n instanceof Error)throw"Rasterization timeout"===n.message&&(t.workCount=e.pool.workLimit+1,t.page=null),"TimeoutError"===n.name||"Rasterization timeout"===n.message?new ExportError(`[pool] ${e.requestId?`Request [${e.requestId}] - `:""}Rasterization timeout: your chart may be too complex or large, and failed to render within the allotted time.`).setError(n):new ExportError(`[pool] ${e.requestId?`Request [${e.requestId}] - `:""}Error encountered during export: ${i()}ms.`).setError(n);e.server.benchmarking&&log(5,"[benchmark] "+(e.requestId?`Request [${e.requestId}] - `:""),`Exporting a chart sucessfully took ${i()}ms.`),pool.release(t);const s=getNewDateTime()-r;return poolStats.timeSpent+=s,poolStats.timeSpentAverage=poolStats.timeSpent/++poolStats.exportsPerformed,log(4,`[pool] Work completed in ${s}ms.`),{result:n,options:e}}catch(e){throw++poolStats.exportsDropped,t&&pool.release(t),e}}function getPoolStats(){return poolStats}function getPoolInfoJSON(){return{min:pool.min,max:pool.max,used:pool.numUsed(),available:pool.numFree(),allCreated:pool.numUsed()+pool.numFree(),pendingAcquires:pool.numPendingAcquires(),pendingCreates:pool.numPendingCreates(),pendingValidations:pool.numPendingValidations(),pendingDestroys:pool.pendingDestroys.length,absoluteAll:pool.numUsed()+pool.numFree()+pool.numPendingAcquires()+pool.numPendingCreates()+pool.numPendingValidations()+pool.pendingDestroys.length}}function getPoolInfo(){const{min:e,max:t,used:o,available:r,allCreated:i,pendingAcquires:n,pendingCreates:s,pendingValidations:a,pendingDestroys:l,absoluteAll:c}=getPoolInfoJSON();log(5,`[pool] The minimum number of resources allowed by pool: ${e}.`),log(5,`[pool] The maximum number of resources allowed by pool: ${t}.`),log(5,`[pool] The number of used resources: ${o}.`),log(5,`[pool] The number of free resources: ${r}.`),log(5,`[pool] The number of all created (used and free) resources: ${i}.`),log(5,`[pool] The number of resources waiting to be acquired: ${n}.`),log(5,`[pool] The number of resources waiting to be created: ${s}.`),log(5,`[pool] The number of resources waiting to be validated: ${a}.`),log(5,`[pool] The number of resources waiting to be destroyed: ${l}.`),log(5,`[pool] The number of all resources: ${c}.`)}function _factory(e){return{create:async()=>{const t={id:uuid.v4(),workCount:Math.round(Math.random()*(e.workLimit/2))};try{const e=getNewDateTime();return await newPage(t),log(3,`[pool] Pool resource [${t.id}] - Successfully created a worker, took ${getNewDateTime()-e}ms.`),t}catch(e){throw log(3,`[pool] Pool resource [${t.id}] - Error encountered when creating a new page.`),e}},validate:async t=>t.page?t.page.isClosed()?(log(3,`[pool] Pool resource [${t.id}] - Validation failed (page is closed or invalid).`),!1):t.page.mainFrame().detached?(log(3,`[pool] Pool resource [${t.id}] - Validation failed (page's frame is detached).`),!1):!(e.workLimit&&++t.workCount>e.workLimit)||(log(3,`[pool] Pool resource [${t.id}] - Validation failed (exceeded the ${e.workLimit} works per resource limit).`),!1):(log(3,`[pool] Pool resource [${t.id}] - Validation failed (no valid page is found).`),!1),destroy:async e=>{if(log(3,`[pool] Pool resource [${e.id}] - Destroying a worker.`),e.page&&!e.page.isClosed())try{e.page.removeAllListeners("pageerror"),e.page.removeAllListeners("console"),e.page.removeAllListeners("framedetached"),await e.page.close()}catch(t){throw log(3,`[pool] Pool resource [${e.id}] - Page could not be closed upon destroying.`),t}}}}function sanitize(e){const t=new jsdom.JSDOM("").window;return DOMPurify(t).sanitize(e,{ADD_TAGS:["foreignObject"]})}let allowCodeExecution=!1;async function singleExport(e){if(!e||!e.export)throw new ExportError("[chart] No expected `export` options were found. Please provide one of the following options: `infile`, `instr`, `options`, or `svg` to generate a valid image.",400);e=validateOptions(e),await startExport({export:e.export,customLogic:e.customLogic},(async(e,t)=>{if(e)throw e;const{b64:o,outfile:r,type:i}=t.options.export;try{o?fs.writeFileSync(`${r.split(".").shift()||"chart"}.txt`,getBase64(t.result,i)):fs.writeFileSync(r||`chart.${i}`,"svg"!==i?Buffer.from(t.result,"base64"):t.result)}catch(e){throw new ExportError("[chart] Error while saving a chart.",500).setError(e)}await killPool()}))}async function batchExport(e){if(!(e&&e.export&&e.export.batch))throw new ExportError("[chart] No expected `export` options were found. Please provide the `batch` option to generate valid images.",400);{e=validateOptions(e);const t=[];for(let o of e.export.batch.split(";")||[])o=o.split("="),2===o.length?t.push(startExport({export:{...e.export,infile:o[0],outfile:o[1]},customLogic:e.customLogic},((e,t)=>{if(e)throw e;const{b64:o,outfile:r,type:i}=t.options.export;try{o?fs.writeFileSync(`${r.split(".").shift()||"chart"}.txt`,getBase64(t.result,i)):fs.writeFileSync(r,"svg"!==i?Buffer.from(t.result,"base64"):t.result)}catch(e){throw new ExportError("[chart] Error while saving a chart.",500).setError(e)}}))):log(2,"[chart] No correct pair found for the batch export.");const o=await Promise.allSettled(t);await killPool(),o.forEach(((e,t)=>{e.reason&&logWithStack(1,e.reason,`[chart] Batch export number ${t+1} could not be correctly completed.`)}))}}async function startExport(e,t){try{if(!isObject(e))throw new ExportError("[chart] Incorrect value of the provided `imageOptions`. Needs to be an object.",400);const o=updateOptions({export:e.export,customLogic:e.customLogic},!0),r=o.export;if(log(4,"[chart] Starting the exporting process."),null!==r.infile){let e;log(4,"[chart] Attempting to export from a file input.");try{e=fs.readFileSync(getAbsolutePath(r.infile),"utf8")}catch(e){throw new ExportError("[chart] Error loading content from a file input.",400).setError(e)}if(r.infile.endsWith(".svg"))r.svg=validateOption("svg",e);else{if(!r.infile.endsWith(".json"))throw new ExportError("[chart] Incorrect value of the `infile` option.",400);r.instr=validateOption("instr",e)}}if(null!==r.svg){log(4,"[chart] Attempting to export from an SVG input."),++getPoolStats().exportsFromSvgAttempts;const e=await _exportFromSvg(sanitize(r.svg),o);return++getPoolStats().exportsFromSvg,t(null,e)}if(null!==r.instr||null!==r.options){log(4,"[chart] Attempting to export from options input."),++getPoolStats().exportsFromOptionsAttempts;const e=await _exportFromOptions(r.instr||r.options,o);return++getPoolStats().exportsFromOptions,t(null,e)}return t(new ExportError("[chart] No valid input specified. Check if at least one of the following parameters is correctly set: 'infile', 'instr', 'options', or 'svg'.",400))}catch(e){return t(e)}}function getAllowCodeExecution(){return allowCodeExecution}function setAllowCodeExecution(e){allowCodeExecution=e}async function _exportFromSvg(e,t){if("string"==typeof e&&(e.indexOf("=0||e.indexOf("=0))return log(4,"[chart] Parsing input as SVG."),t.export.svg=e,t.export.instr=null,t.export.options=null,_prepareExport(t);throw new ExportError("[chart] Not a correct SVG input.",400)}async function _exportFromOptions(e,t){log(4,"[chart] Parsing input from options.");const o=isAllowedConfig(e,!0,t.customLogic.allowCodeExecution);if(null===o||"string"!=typeof o||!o.startsWith("{")||!o.endsWith("}"))throw new ExportError("[chart] Invalid configuration provided - Only options configurations and SVG are allowed for this server. If this is your server, JavaScript custom code can be enabled by starting the server with the `allowCodeExecution` options set to true.",403);return t.export.instr=o,t.export.svg=null,_prepareExport(t)}async function _prepareExport(e){const{export:t,customLogic:o}=e;return t.type=fixType(t.type,t.outfile),t.outfile=fixOutfile(t.type,t.outfile),t.constr=fixConstr(t.constr),log(3,`[chart] The custom logic is ${o.allowCodeExecution?"allowed":"disallowed"}.`),_handleCustomLogic(o,o.allowCodeExecution),_handleGlobalAndTheme(t,o.allowFileResources,o.allowCodeExecution),e.export={...t,..._findChartSize(t)},postWork(e)}function _findChartSize(e){const{chart:t,exporting:o}=e.options||isAllowedConfig(e.instr)||!1,{chart:r,exporting:i}=isAllowedConfig(e.globalOptions)||!1,{chart:n,exporting:s}=isAllowedConfig(e.themeOptions)||!1,a=roundNumber(Math.max(.1,Math.min(e.scale||o?.scale||i?.scale||s?.scale||e.defaultScale||1,5)),2),l={height:e.height||o?.sourceHeight||t?.height||i?.sourceHeight||r?.height||s?.sourceHeight||n?.height||e.defaultHeight||400,width:e.width||o?.sourceWidth||t?.width||i?.sourceWidth||r?.width||s?.sourceWidth||n?.width||e.defaultWidth||600,scale:a};for(let[e,t]of Object.entries(l))l[e]="string"==typeof t?+t.replace(/px|%/gi,""):t;return l}function _handleCustomLogic(e,t){if(t){if("string"==typeof e.resources)e.resources=_handleResources(e.resources,e.allowFileResources,!0);else if(!e.resources)try{e.resources=_handleResources(fs.readFileSync(getAbsolutePath("resources.json"),"utf8"),e.allowFileResources,!0)}catch(e){log(2,"[chart] Unable to load the default `resources.json` file.")}try{e.customCode=wrapAround(e.customCode,e.allowFileResources),e.customCode=validateOption("customCode",e.customCode)}catch(t){logWithStack(2,t,"[chart] The `customCode` cannot be loaded."),e.customCode=null}try{e.callback=wrapAround(e.callback,e.allowFileResources,!0),e.callback=validateOption("callback",e.callback)}catch(t){logWithStack(2,t,"[chart] The `callback` cannot be loaded."),e.callback=null}[null,void 0].includes(e.customCode)&&log(3,"[chart] No value for the `customCode` option found."),[null,void 0].includes(e.callback)&&log(3,"[chart] No value for the `callback` option found."),[null,void 0].includes(e.resources)&&log(3,"[chart] No value for the `resources` option found.")}else if(e.callback||e.resources||e.customCode)throw e.callback=null,e.resources=null,e.customCode=null,new ExportError("[chart] The 'callback', 'resources', and 'customCode' options have been disabled for this server.",403)}function _handleResources(e=null,t,o){const r=["js","css","files"];let i=e,n=!1;if(t&&e.endsWith(".json"))try{i=isAllowedConfig(fs.readFileSync(getAbsolutePath(e),"utf8"),!1,o)}catch{return null}else i=isAllowedConfig(e,!1,o),i&&!t&&delete i.files;for(const e in i)r.includes(e)?n||(n=!0):delete i[e];return n?(i.files&&(i.files=i.files.map((e=>e.trim())),(!i.files||i.files.length<=0)&&delete i.files),i=validateOption("resources",i),i):null}function _handleGlobalAndTheme(e,t,o){["globalOptions","themeOptions"].forEach((r=>{try{e[r]&&(t&&"string"==typeof e[r]&&e[r].endsWith(".json")?e[r]=isAllowedConfig(fs.readFileSync(getAbsolutePath(e[r]),"utf8"),!0,o):e[r]=isAllowedConfig(e[r],!0,o),e[r]=validateOption(r,e[r]))}catch(t){logWithStack(2,t,`[chart] The \`${r}\` cannot be loaded.`),e[r]=null}})),[null,void 0].includes(e.globalOptions)&&log(3,"[chart] No value for the `globalOptions` option found."),[null,void 0].includes(e.themeOptions)&&log(3,"[chart] No value for the `themeOptions` option found.")}const timerIds=[];function addTimer(e){timerIds.push(e)}function clearAllTimers(){log(4,"[timer] Clearing all registered intervals and timeouts.");for(const e of timerIds)clearInterval(e),clearTimeout(e)}function logErrorMiddleware(e,t,o,r){return logWithStack(1,e),"development"!==getOptions().other.nodeEnv&&delete e.stack,r(e)}function returnErrorMiddleware(e,t,o,r){const{message:i,stack:n}=e,s=e.statusCode||400;o.status(s).json({statusCode:s,message:i,stack:n})}function errorMiddleware(e){e.use(logErrorMiddleware),e.use(returnErrorMiddleware)}function rateLimitingMiddleware(e,t){try{if(e&&t.enable){const o="Too many requests, you have been rate limited. Please try again later.",r={window:t.window||1,maxRequests:t.maxRequests||30,delay:t.delay||0,trustProxy:t.trustProxy||!1,skipKey:t.skipKey||null,skipToken:t.skipToken||null};r.trustProxy&&e.enable("trust proxy");const i=rateLimit({windowMs:60*r.window*1e3,limit:r.maxRequests,delayMs:r.delay,handler:(e,t)=>{t.format({json:()=>{t.status(429).send({message:o})},default:()=>{t.status(429).send(o)}})},skip:e=>null!==r.skipKey&&null!==r.skipToken&&e.query.key===r.skipKey&&e.query.access_token===r.skipToken&&(log(4,"[rate limiting] Skipping rate limiter."),!0)});e.use(i),log(3,`[rate limiting] Enabled rate limiting with ${r.maxRequests} requests per ${r.window} minute for each IP, trusting proxy: ${r.trustProxy}.`)}}catch(e){throw new ExportError("[rate limiting] Could not configure and set the rate limiting options.",500).setError(e)}}function contentTypeMiddleware(e,t,o){try{const t=e.headers["content-type"]||"";if(!t.includes("application/json")&&!t.includes("application/x-www-form-urlencoded")&&!t.includes("multipart/form-data"))throw new ExportError("[validation] Content-Type must be application/json, application/x-www-form-urlencoded, or multipart/form-data.",415);return o()}catch(e){return o(e)}}function requestBodyMiddleware(e,t,o){try{const t=e.body,r=uuid.v4();if(!t||isObjectEmpty(t))throw log(2,`[validation] Request [${r}] - The request from ${e.headers["x-forwarded-for"]||e.connection.remoteAddress} was incorrect. Received payload is empty.`),new ExportError(`[validation] Request [${r}] - The request body is required. Please ensure that your Content-Type header is correct. Accepted types are 'application/json' and 'multipart/form-data'.`,400);const i=getAllowCodeExecution(),n=isAllowedConfig(t.instr||t.options||t.infile||t.data,!0,i);if(null===n&&!t.svg)throw log(2,`[validation] Request [${r}] - The request from ${e.headers["x-forwarded-for"]||e.connection.remoteAddress} was incorrect. Received payload is missing correct chart data for export: ${JSON.stringify(t)}.`),new ExportError(`Request [${r}] - [validation] No correct chart data found. Ensure that you are using either application/json or multipart/form-data headers. If sending JSON, make sure the chart data is in the 'infile', 'options', or 'data' attribute. If sending SVG, ensure it is in the 'svg' attribute.`,400);if(t.svg&&isPrivateRangeUrlFound(t.svg))throw new ExportError(`Request [${r}] - [validation] SVG potentially contain at least one forbidden URL in 'xlink:href' element. Please review the SVG content and ensure that all referenced URLs comply with security policies.`,400);return e.validatedOptions=validateOptions({requestId:r,export:{instr:n,svg:t.svg,outfile:t.outfile||`${e.params.filename||"chart"}.${t.type||"png"}`,type:t.type,constr:t.constr,b64:t.b64,noDownload:t.noDownload,height:t.height,width:t.width,scale:t.scale,globalOptions:isAllowedConfig(t.globalOptions,!0,i),themeOptions:isAllowedConfig(t.themeOptions,!0,i)},customLogic:{allowCodeExecution:i,allowFileResources:!1,customCode:t.customCode,callback:t.callback,resources:isAllowedConfig(t.resources,!0,i)}}),o()}catch(e){return o(e)}}function validationMiddleware(e){e.post(["/","/:filename"],contentTypeMiddleware),e.post(["/","/:filename"],requestBodyMiddleware)}const reversedMime={png:"image/png",jpeg:"image/jpeg",gif:"image/gif",pdf:"application/pdf",svg:"image/svg+xml"};async function requestExport(e,t,o){try{const o=measureTime();let r=!1;e.socket.on("close",(e=>{e&&(r=!0)}));const i=e.validatedOptions,n=i.requestId;log(4,`[export] Request [${n}] - Got an incoming HTTP request.`),await startExport(i,((i,s)=>{if(e.socket.removeAllListeners("close"),r)log(3,`[export] Request [${n}] - The client closed the connection before the chart finished processing.`);else{if(i)throw i;if(!s||!s.result)throw log(2,`[export] Request [${n}] - Request from ${e.headers["x-forwarded-for"]||e.connection.remoteAddress} was incorrect. Received result is ${s.result}.`),new ExportError(`[export] Request [${n}] - Unexpected return of the export result from the chart generation. Please check your request data.`,400);if(s.result){log(3,`[export] Request [${n}] - The whole exporting process took ${o()}ms.`);const{type:e,b64:r,noDownload:i,outfile:a}=s.options.export;return r?t.send(getBase64(s.result,e)):(t.header("Content-Type",reversedMime[e]||"image/png"),i||t.attachment(a),"svg"===e?t.send(s.result):t.send(Buffer.from(s.result,"base64")))}}}))}catch(e){return o(e)}}function exportRoutes(e){e.post("/",requestExport),e.post("/:filename",requestExport)}const serverStartTime=new Date,packageFile=JSON.parse(fs.readFileSync(path.join(__dirname$1,"package.json"),"utf8")),successRates=[],recordInterval=6e4,windowSize=30;function _calculateMovingAverage(){return successRates.reduce(((e,t)=>e+t),0)/successRates.length}function _startSuccessRate(){return setInterval((()=>{const e=getPoolStats(),t=0===e.exportsAttempted?1:e.exportsPerformed/e.exportsAttempted*100;successRates.push(t),successRates.length>windowSize&&successRates.shift()}),recordInterval)}function healthRoutes(e){addTimer(_startSuccessRate()),e.get("/health",((e,t,o)=>{try{log(4,"[health] Returning server health.");const e=getPoolStats(),o=successRates.length,r=_calculateMovingAverage();t.send({status:"OK",bootTime:serverStartTime,uptime:`${Math.floor((getNewDateTime()-serverStartTime.getTime())/1e3/60)} minutes`,serverVersion:packageFile.version,highchartsVersion:getHighchartsVersion(),averageExportTime:e.timeSpentAverage,attemptedExports:e.exportsAttempted,performedExports:e.exportsPerformed,failedExports:e.exportsDropped,sucessRatio:e.exportsPerformed/e.exportsAttempted*100,pool:getPoolInfoJSON(),period:o,movingAverage:r,message:isNaN(r)||!successRates.length?"Too early to report. No exports made yet. Please check back soon.":`Last ${o} minutes had a success rate of ${r.toFixed(2)}%.`,svgExports:e.exportsFromSvg,jsonExports:e.exportsFromOptions,svgExportsAttempts:e.exportsFromSvgAttempts,jsonExportsAttempts:e.exportsFromOptionsAttempts})}catch(e){return o(e)}}))}function uiRoutes(e){e.get(getOptions().ui.route||"/",((e,t,o)=>{try{log(4,"[ui] Returning UI for the export."),t.sendFile(path.join(__dirname$1,"public","index.html"),{acceptRanges:!1})}catch(e){return o(e)}}))}function versionChangeRoutes(e){e.post("/version_change/:newVersion",(async(e,t,o)=>{try{log(4,"[version] Changing Highcharts version.");const o=envs.HIGHCHARTS_ADMIN_TOKEN;if(!o||!o.length)throw new ExportError("[version] The server is not configured to perform run-time version changes: HIGHCHARTS_ADMIN_TOKEN is not set.",401);const r=e.get("hc-auth");if(!r||r!==o)throw new ExportError("[version] Invalid or missing token: Set the token in the hc-auth header.",401);let i=e.params.newVersion;try{i=validateOption("version",e.params.newVersion)}catch(e){throw new ExportError(`[version] Version is incorrect: ${e.message}`,400).setError(e)}if(!i)throw new ExportError("[version] No new version supplied.",400);try{await updateHighchartsVersion(i)}catch(e){throw new ExportError(`[version] Version change: ${e.message}`,400).setError(e)}t.status(200).send({statusCode:200,highchartsVersion:getHighchartsVersion(),message:`Successfully updated Highcharts to version: ${i}.`})}catch(e){return o(e)}}))}const activeServers=new Map,app=express();async function startServer(e){try{const t=updateOptions(validateOptions({server:e}));if(!(e=t.server).enable||!app)throw new ExportError("[server] Server cannot be started (not enabled or no correct Express app found).",500);const o=1024*e.uploadLimit*1024,r=multer.memoryStorage(),i=multer({storage:r,limits:{fieldSize:o}});if(app.disable("x-powered-by"),app.use(cors({methods:["POST","GET","OPTIONS"]})),app.use(((e,t,o)=>{t.set("Accept-Ranges","none"),o()})),app.use(express.json({limit:o})),app.use(express.urlencoded({extended:!0,limit:o})),app.use(i.none()),app.use(express.static(path.join(__dirname$1,"public"))),!e.ssl.force){const t=http.createServer(app);_attachServerErrorHandlers(t),t.listen(e.port,e.host,(()=>{activeServers.set(e.port,t),log(3,`[server] Started HTTP server on ${e.host}:${e.port}.`)}))}if(e.ssl.enable){let t,o;try{t=fs.readFileSync(path.join(getAbsolutePath(e.ssl.certPath),"server.key"),"utf8"),o=fs.readFileSync(path.join(getAbsolutePath(e.ssl.certPath),"server.crt"),"utf8")}catch(t){log(2,`[server] Unable to load key/certificate from the '${e.ssl.certPath}' path. Could not run secured layer server.`)}if(t&&o){const r=https.createServer({key:t,cert:o},app);_attachServerErrorHandlers(r),r.listen(e.ssl.port,e.host,(()=>{activeServers.set(e.ssl.port,r),log(3,`[server] Started HTTPS server on ${e.host}:${e.ssl.port}.`)}))}}rateLimitingMiddleware(app,e.rateLimiting),validationMiddleware(app),exportRoutes(app),healthRoutes(app),uiRoutes(app),versionChangeRoutes(app),errorMiddleware(app)}catch(e){throw new ExportError("[server] Could not configure and start the server.",500).setError(e)}}function closeServers(){if(activeServers.size>0){log(4,"[server] Closing all servers.");for(const[e,t]of activeServers)t.close((()=>{activeServers.delete(e),log(4,`[server] Closed server on port: ${e}.`)}))}}function getServers(){return activeServers}function getExpress(){return express}function getApp(){return app}function enableRateLimiting(e){const t=updateOptions(validateOptions({server:{rateLimiting:e}}));rateLimitingMiddleware(app,t.server.rateLimitingOptions)}function use(e,...t){app.use(e,...t)}function get(e,...t){app.get(e,...t)}function post(e,...t){app.post(e,...t)}function _attachServerErrorHandlers(e){e.on("clientError",((e,t)=>{logWithStack(1,e,`[server] Client error: ${e.message}, destroying socket.`),t.destroy()})),e.on("error",(e=>{logWithStack(1,e,`[server] Server error: ${e.message}`)})),e.on("connection",(e=>{e.on("error",(e=>{logWithStack(1,e,`[server] Socket error: ${e.message}`)}))}))}var server={startServer:startServer,closeServers:closeServers,getServers:getServers,getExpress:getExpress,getApp:getApp,enableRateLimiting:enableRateLimiting,use:use,get:get,post:post};async function shutdownCleanUp(e=0){await Promise.allSettled([clearAllTimers(),closeServers(),killPool()]),process.exit(e)}async function initExport(e){const t=updateOptions(validateOptions(e));setAllowCodeExecution(t.customLogic.allowCodeExecution),initLogging(t.logging),t.other.listenToProcessExits&&_attachProcessExitListeners(),await checkAndUpdateCache(t.highcharts,t.server.proxy),await initPool(t.pool,t.puppeteer.args)}function _attachProcessExitListeners(){log(3,"[process] Attaching exit listeners to the process."),process.on("exit",(e=>{log(4,`[process] Process exited with code ${e}.`)})),process.on("SIGINT",(async(e,t)=>{log(4,`[process] The ${e} event with code: ${t}.`),await shutdownCleanUp()})),process.on("SIGTERM",(async(e,t)=>{log(4,`[process] The ${e} event with code: ${t}.`),await shutdownCleanUp()})),process.on("SIGHUP",(async(e,t)=>{log(4,`[process] The ${e} event with code: ${t}.`),await shutdownCleanUp()})),process.on("uncaughtException",(async(e,t)=>{logWithStack(1,e,`[process] The ${t} error.`),await shutdownCleanUp(1)}))}var index={...server,getOptions:getOptions,updateOptions:updateOptions,mapToNewOptions:mapToNewOptions,validateOption:validateOption,validateOptions:validateOptions,initExport:initExport,singleExport:singleExport,batchExport:batchExport,startExport:startExport,killPool:killPool,shutdownCleanUp:shutdownCleanUp,log:log,logWithStack:logWithStack,logZodIssues:logZodIssues,setLogLevel:function(e){setLogLevel(updateOptions(validateOptions({logging:{level:e}})).logging.level)},enableConsoleLogging:function(e){enableConsoleLogging(updateOptions(validateOptions({logging:{toConsole:e}})).logging.toConsole)},enableFileLogging:function(e,t,o){const r=updateOptions(validateOptions({logging:{dest:e,file:t,toFile:o}}));enableFileLogging(r.logging.dest,r.logging.file,r.logging.toFile)}};exports.default=index,exports.initExport=initExport; -//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguY2pzIiwic291cmNlcyI6WyIuLi9saWIvdXRpbHMuanMiLCIuLi9saWIvbG9nZ2VyLmpzIiwiLi4vbGliL3NjaGVtYXMvY29uZmlnLmpzIiwiLi4vbGliL3ZhbGlkYXRpb24uanMiLCIuLi9saWIvZXJyb3JzL0V4cG9ydEVycm9yLmpzIiwiLi4vbGliL2NvbmZpZy5qcyIsIi4uL2xpYi9mZXRjaC5qcyIsIi4uL2xpYi9jYWNoZS5qcyIsIi4uL2xpYi9oaWdoY2hhcnRzLmpzIiwiLi4vbGliL2Jyb3dzZXIuanMiLCIuLi90ZW1wbGF0ZXMvc3ZnRXhwb3J0L2Nzcy5qcyIsIi4uL3RlbXBsYXRlcy9zdmdFeHBvcnQvc3ZnRXhwb3J0LmpzIiwiLi4vbGliL2V4cG9ydC5qcyIsIi4uL2xpYi9wb29sLmpzIiwiLi4vbGliL3Nhbml0aXplLmpzIiwiLi4vbGliL2NoYXJ0LmpzIiwiLi4vbGliL3RpbWVyLmpzIiwiLi4vbGliL3NlcnZlci9taWRkbGV3YXJlcy9lcnJvci5qcyIsIi4uL2xpYi9zZXJ2ZXIvbWlkZGxld2FyZXMvcmF0ZUxpbWl0aW5nLmpzIiwiLi4vbGliL3NlcnZlci9taWRkbGV3YXJlcy92YWxpZGF0aW9uLmpzIiwiLi4vbGliL3NlcnZlci9yb3V0ZXMvZXhwb3J0LmpzIiwiLi4vbGliL3NlcnZlci9yb3V0ZXMvaGVhbHRoLmpzIiwiLi4vbGliL3NlcnZlci9yb3V0ZXMvdWkuanMiLCIuLi9saWIvc2VydmVyL3JvdXRlcy92ZXJzaW9uQ2hhbmdlLmpzIiwiLi4vbGliL3NlcnZlci9zZXJ2ZXIuanMiLCIuLi9saWIvcmVzb3VyY2VSZWxlYXNlLmpzIiwiLi4vbGliL2luZGV4LmpzIl0sInNvdXJjZXNDb250ZW50IjpbIi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXHJcblxyXG5IaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXJcclxuXHJcbkNvcHlyaWdodCAoYykgMjAxNi0yMDI1LCBIaWdoc29mdFxyXG5cclxuTGljZW5jZWQgdW5kZXIgdGhlIE1JVCBsaWNlbmNlLlxyXG5cclxuQWRkaXRpb25hbGx5IGEgdmFsaWQgSGlnaGNoYXJ0cyBsaWNlbnNlIGlzIHJlcXVpcmVkIGZvciB1c2UuXHJcblxyXG5TZWUgTElDRU5TRSBmaWxlIGluIHJvb3QgZm9yIGRldGFpbHMuXHJcblxyXG4qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xyXG5cclxuLyoqXHJcbiAqIEBvdmVydmlldyBUaGUgSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyIHV0aWxpdHkgbW9kdWxlIHByb3ZpZGVzXHJcbiAqIGEgY29tcHJlaGVuc2l2ZSBzZXQgb2YgaGVscGVyIGZ1bmN0aW9ucyBhbmQgY29uc3RhbnRzIGRlc2lnbmVkIHRvIHN0cmVhbWxpbmVcclxuICogYW5kIGVuaGFuY2UgdmFyaW91cyBvcGVyYXRpb25zIHJlcXVpcmVkIGZvciBIaWdoY2hhcnRzIGV4cG9ydCB0YXNrcy5cclxuICovXHJcblxyXG5pbXBvcnQgeyByZWFkRmlsZVN5bmMgfSBmcm9tICdmcyc7XHJcbmltcG9ydCB7IGlzQWJzb2x1dGUsIG5vcm1hbGl6ZSwgcmVzb2x2ZSB9IGZyb20gJ3BhdGgnO1xyXG5pbXBvcnQgeyBmaWxlVVJMVG9QYXRoIH0gZnJvbSAndXJsJztcclxuXHJcbmNvbnN0IE1BWF9CQUNLT0ZGX0FUVEVNUFRTID0gNjtcclxuXHJcbi8vIFRoZSBkaXJlY3RvcnkgcGF0aFxyXG5leHBvcnQgY29uc3QgX19kaXJuYW1lID0gZmlsZVVSTFRvUGF0aChuZXcgVVJMKCcuLi8uJywgaW1wb3J0Lm1ldGEudXJsKSk7XHJcblxyXG4vKipcclxuICogQ2xlYXJzIGFuZCBzdGFuZGFyZGl6ZXMgdGV4dCBieSByZXBsYWNpbmcgbXVsdGlwbGUgY29uc2VjdXRpdmUgd2hpdGVzcGFjZVxyXG4gKiBjaGFyYWN0ZXJzIHdpdGggYSBzaW5nbGUgc3BhY2UgYW5kIHRyaW1taW5nIGFueSBsZWFkaW5nIG9yIHRyYWlsaW5nXHJcbiAqIHdoaXRlc3BhY2UuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBjbGVhclRleHRcclxuICpcclxuICogQHBhcmFtIHtzdHJpbmd9IHRleHQgLSBUaGUgaW5wdXQgdGV4dCB0byBiZSBjbGVhcmVkLlxyXG4gKiBAcGFyYW0ge1JlZ0V4cH0gW3J1bGU9L1xcc1xccysvZ10gLSBUaGUgcmVndWxhciBleHByZXNzaW9uIHJ1bGUgdG8gbWF0Y2hcclxuICogbXVsdGlwbGUgY29uc2VjdXRpdmUgd2hpdGVzcGFjZSBjaGFyYWN0ZXJzLiBUaGUgZGVmYXVsdCB2YWx1ZVxyXG4gKiBpcyB0aGUgJy9cXHNcXHMrL2cnIFJlZ0V4cC5cclxuICogQHBhcmFtIHtzdHJpbmd9IFtyZXBsYWNlcj0nICddIC0gVGhlIHN0cmluZyB1c2VkIHRvIHJlcGxhY2UgbXVsdGlwbGVcclxuICogY29uc2VjdXRpdmUgd2hpdGVzcGFjZSBjaGFyYWN0ZXJzLiBUaGUgZGVmYXVsdCB2YWx1ZSBpcyB0aGUgJyAnIHN0cmluZy5cclxuICpcclxuICogQHJldHVybnMge3N0cmluZ30gVGhlIGNsZWFyZWQgYW5kIHN0YW5kYXJkaXplZCB0ZXh0LlxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIGNsZWFyVGV4dCh0ZXh0LCBydWxlID0gL1xcc1xccysvZywgcmVwbGFjZXIgPSAnICcpIHtcclxuICByZXR1cm4gdGV4dC5yZXBsYWNlQWxsKHJ1bGUsIHJlcGxhY2VyKS50cmltKCk7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBDcmVhdGVzIGEgZGVlcCBjb3B5IG9mIHRoZSBnaXZlbiBvYmplY3Qgb3IgYXJyYXkuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBkZWVwQ29weVxyXG4gKlxyXG4gKiBAcGFyYW0geyhPYmplY3R8QXJyYXkpfSBvYmpBcnIgLSBUaGUgb2JqZWN0IG9yIGFycmF5IHRvIGJlIGRlZXBseSBjb3BpZWQuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHsoT2JqZWN0fEFycmF5KX0gVGhlIGRlZXAgY29weSBvZiB0aGUgcHJvdmlkZWQgb2JqZWN0IG9yIGFycmF5LlxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIGRlZXBDb3B5KG9iakFycikge1xyXG4gIC8vIElmIHRoZSBgb2JqQXJyYCBpcyBudWxsIG9yIG5vdCBvZiB0aGUgYG9iamVjdGAgdHlwZSwgcmV0dXJuIGl0XHJcbiAgaWYgKG9iakFyciA9PT0gbnVsbCB8fCB0eXBlb2Ygb2JqQXJyICE9PSAnb2JqZWN0Jykge1xyXG4gICAgcmV0dXJuIG9iakFycjtcclxuICB9XHJcblxyXG4gIC8vIFByZXBhcmUgZWl0aGVyIGEgbmV3IGFycmF5IG9yIGEgbmV3IG9iamVjdFxyXG4gIGNvbnN0IG9iakFyckNvcHkgPSBBcnJheS5pc0FycmF5KG9iakFycikgPyBbXSA6IHt9O1xyXG5cclxuICAvLyBSZWN1cnNpdmVseSBjb3B5IGVhY2ggcHJvcGVydHlcclxuICBmb3IgKGNvbnN0IGtleSBpbiBvYmpBcnIpIHtcclxuICAgIGlmIChPYmplY3QucHJvdG90eXBlLmhhc093blByb3BlcnR5LmNhbGwob2JqQXJyLCBrZXkpKSB7XHJcbiAgICAgIG9iakFyckNvcHlba2V5XSA9IGRlZXBDb3B5KG9iakFycltrZXldKTtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIC8vIFJldHVybiB0aGUgY29waWVkIG9iamVjdFxyXG4gIHJldHVybiBvYmpBcnJDb3B5O1xyXG59XHJcblxyXG4vKipcclxuICogSW1wbGVtZW50cyBhbiBleHBvbmVudGlhbCBiYWNrb2ZmIHN0cmF0ZWd5IGZvciByZXRyeWluZyBhIGZ1bmN0aW9uIHVudGlsXHJcbiAqIGEgY2VydGFpbiBudW1iZXIgb2YgYXR0ZW1wdHMgYXJlIHJlYWNoZWQuXHJcbiAqXHJcbiAqIEBhc3luY1xyXG4gKiBAZnVuY3Rpb24gZXhwQmFja29mZlxyXG4gKlxyXG4gKiBAcGFyYW0ge0Z1bmN0aW9ufSBmbiAtIFRoZSBmdW5jdGlvbiB0byBiZSByZXRyaWVkLlxyXG4gKiBAcGFyYW0ge251bWJlcn0gW2F0dGVtcHQ9MF0gLSBUaGUgY3VycmVudCBhdHRlbXB0IG51bWJlci4gVGhlIGRlZmF1bHQgdmFsdWVcclxuICogaXMgYDBgLlxyXG4gKiBAcGFyYW0gey4uLnVua25vd259IGFyZ3MgLSBBcmd1bWVudHMgdG8gYmUgcGFzc2VkIHRvIHRoZSBmdW5jdGlvbi5cclxuICpcclxuICogQHJldHVybnMge1Byb21pc2U8dW5rbm93bj59IEEgUHJvbWlzZSB0aGF0IHJlc29sdmVzIHRvIHRoZSByZXN1bHRcclxuICogb2YgdGhlIGZ1bmN0aW9uIGlmIHN1Y2Nlc3NmdWwuXHJcbiAqXHJcbiAqIEB0aHJvd3Mge0Vycm9yfSBUaHJvd3MgYW4gYEVycm9yYCBpZiB0aGUgbWF4aW11bSBudW1iZXIgb2YgYXR0ZW1wdHNcclxuICogaXMgcmVhY2hlZC5cclxuICovXHJcbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBleHBCYWNrb2ZmKGZuLCBhdHRlbXB0ID0gMCwgLi4uYXJncykge1xyXG4gIHRyeSB7XHJcbiAgICAvLyBUcnkgdG8gY2FsbCB0aGUgZnVuY3Rpb25cclxuICAgIHJldHVybiBhd2FpdCBmbiguLi5hcmdzKTtcclxuICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgLy8gQ2FsY3VsYXRlIGRlbGF5IGluIG1zXHJcbiAgICBjb25zdCBkZWxheUluTXMgPSAyICoqIGF0dGVtcHQgKiAxMDAwO1xyXG5cclxuICAgIC8vIElmIHRoZSBhdHRlbXB0IGV4Y2VlZHMgdGhlIG1heGltdW0gYXR0ZW1wdHMgb2YgcmVwZWF0LCB0aHJvdyBhbiBlcnJvclxyXG4gICAgaWYgKCsrYXR0ZW1wdCA+PSBNQVhfQkFDS09GRl9BVFRFTVBUUykge1xyXG4gICAgICB0aHJvdyBlcnJvcjtcclxuICAgIH1cclxuXHJcbiAgICAvLyBXYWl0IGdpdmVuIGFtb3VudCBvZiB0aW1lXHJcbiAgICBhd2FpdCBuZXcgUHJvbWlzZSgocmVzcG9uc2UpID0+IHNldFRpbWVvdXQocmVzcG9uc2UsIGRlbGF5SW5NcykpO1xyXG5cclxuICAgIC8vLyBUTyBETzogQ29ycmVjdFxyXG4gICAgLy8gLy8gSW5mb3JtYXRpb24gYWJvdXQgdGhlIHJlc291cmNlIHRpbWVvdXRcclxuICAgIC8vIGxvZyhcclxuICAgIC8vICAgMyxcclxuICAgIC8vICAgYFt1dGlsc10gV2FpdGVkICR7ZGVsYXlJbk1zfW1zIHVudGlsIG5leHQgY2FsbCBmb3IgdGhlIHJlc291cmNlIG9mIElEOiAke2FyZ3NbMF19LmBcclxuICAgIC8vICk7XHJcblxyXG4gICAgLy8gVHJ5IGFnYWluXHJcbiAgICByZXR1cm4gZXhwQmFja29mZihmbiwgYXR0ZW1wdCwgLi4uYXJncyk7XHJcbiAgfVxyXG59XHJcblxyXG4vKipcclxuICogQWRqdXN0cyB0aGUgY29uc3RydWN0b3IgbmFtZSBieSB0cmFuc2Zvcm1pbmcgYW5kIG5vcm1hbGl6aW5nIGl0IGJhc2VkXHJcbiAqIG9uIGNvbW1vbiBjaGFydCB0eXBlcy5cclxuICpcclxuICogQGZ1bmN0aW9uIGZpeENvbnN0clxyXG4gKlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gY29uc3RyIC0gVGhlIG9yaWdpbmFsIGNvbnN0cnVjdG9yIG5hbWUgdG8gYmUgZml4ZWQuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtzdHJpbmd9IFRoZSBjb3JyZWN0ZWQgY29uc3RydWN0b3IgbmFtZSwgb3IgJ2NoYXJ0JyBpZiB0aGUgaW5wdXRcclxuICogaXMgbm90IHJlY29nbml6ZWQuXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gZml4Q29uc3RyKGNvbnN0cikge1xyXG4gIHRyeSB7XHJcbiAgICAvLyBGaXggdGhlIGNvbnN0cnVjdG9yIGJ5IGxvd2VyaW5nIGNhc2luZ1xyXG4gICAgY29uc3QgZml4ZWRDb25zdHIgPSBgJHtjb25zdHIudG9Mb3dlckNhc2UoKS5yZXBsYWNlKCdjaGFydCcsICcnKX1DaGFydGA7XHJcblxyXG4gICAgLy8gSGFuZGxlIHRoZSBjYXNlIHdoZXJlIHRoZSByZXN1bHQgaXMganVzdCAnQ2hhcnQnXHJcbiAgICBpZiAoZml4ZWRDb25zdHIgPT09ICdDaGFydCcpIHtcclxuICAgICAgZml4ZWRDb25zdHIudG9Mb3dlckNhc2UoKTtcclxuICAgIH1cclxuXHJcbiAgICAvLyBSZXR1cm4gdGhlIGNvcnJlY3RlZCBjb25zdHJ1Y3Rvciwgb3RoZXJ3aXNlIGRlZmF1bHQgdG8gJ2NoYXJ0J1xyXG4gICAgcmV0dXJuIFsnY2hhcnQnLCAnc3RvY2tDaGFydCcsICdtYXBDaGFydCcsICdnYW50dENoYXJ0J10uaW5jbHVkZXMoXHJcbiAgICAgIGZpeGVkQ29uc3RyXHJcbiAgICApXHJcbiAgICAgID8gZml4ZWRDb25zdHJcclxuICAgICAgOiAnY2hhcnQnO1xyXG4gIH0gY2F0Y2gge1xyXG4gICAgLy8gRGVmYXVsdCB0byAnY2hhcnQnIGluIGNhc2Ugb2YgYW55IGVycm9yXHJcbiAgICByZXR1cm4gJ2NoYXJ0JztcclxuICB9XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBGaXhlcyB0aGUgb3V0ZmlsZSBiYXNlZCBvbiBwcm92aWRlZCB0eXBlLlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gZml4T3V0ZmlsZVxyXG4gKlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gdHlwZSAtIFRoZSBvcmlnaW5hbCBleHBvcnQgdHlwZS5cclxuICogQHBhcmFtIHtzdHJpbmd9IG91dGZpbGUgLSBUaGUgZmlsZSBwYXRoIG9yIG5hbWUuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtzdHJpbmd9IFRoZSBjb3JyZWN0ZWQgb3V0ZmlsZS5cclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiBmaXhPdXRmaWxlKHR5cGUsIG91dGZpbGUpIHtcclxuICAvLyBHZXQgdGhlIGZpbGUgbmFtZSBmcm9tIHRoZSBgb3V0ZmlsZWAgb3B0aW9uXHJcbiAgY29uc3QgZmlsZU5hbWUgPSBnZXRBYnNvbHV0ZVBhdGgob3V0ZmlsZSB8fCAnY2hhcnQnKVxyXG4gICAgLnNwbGl0KCcuJylcclxuICAgIC5zaGlmdCgpO1xyXG5cclxuICAvLyBSZXR1cm4gYSBjb3JyZWN0IG91dGZpbGVcclxuICByZXR1cm4gYCR7ZmlsZU5hbWV9LiR7dHlwZX1gO1xyXG59XHJcblxyXG4vKipcclxuICogRml4ZXMgdGhlIGV4cG9ydCB0eXBlIGJhc2VkIG9uIE1JTUUgdHlwZXMgYW5kIGZpbGUgZXh0ZW5zaW9ucy5cclxuICpcclxuICogQGZ1bmN0aW9uIGZpeFR5cGVcclxuICpcclxuICogQHBhcmFtIHtzdHJpbmd9IHR5cGUgLSBUaGUgb3JpZ2luYWwgZXhwb3J0IHR5cGUuXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSBbb3V0ZmlsZT1udWxsXSAtIFRoZSBmaWxlIHBhdGggb3IgbmFtZS4gVGhlIGRlZmF1bHQgdmFsdWVcclxuICogaXMgYG51bGxgLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7c3RyaW5nfSBUaGUgY29ycmVjdGVkIGV4cG9ydCB0eXBlLlxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIGZpeFR5cGUodHlwZSwgb3V0ZmlsZSA9IG51bGwpIHtcclxuICAvLyBNSU1FIHR5cGVzXHJcbiAgY29uc3QgbWltZVR5cGVzID0ge1xyXG4gICAgJ2ltYWdlL3BuZyc6ICdwbmcnLFxyXG4gICAgJ2ltYWdlL2pwZWcnOiAnanBlZycsXHJcbiAgICAnYXBwbGljYXRpb24vcGRmJzogJ3BkZicsXHJcbiAgICAnaW1hZ2Uvc3ZnK3htbCc6ICdzdmcnXHJcbiAgfTtcclxuXHJcbiAgLy8gR2V0IGZvcm1hdHNcclxuICBjb25zdCBmb3JtYXRzID0gT2JqZWN0LnZhbHVlcyhtaW1lVHlwZXMpO1xyXG5cclxuICAvLyBDaGVjayBpZiB0eXBlIGFuZCBvdXRmaWxlJ3MgZXh0ZW5zaW9ucyBhcmUgdGhlIHNhbWVcclxuICBpZiAob3V0ZmlsZSkge1xyXG4gICAgY29uc3Qgb3V0VHlwZSA9IG91dGZpbGUuc3BsaXQoJy4nKS5wb3AoKTtcclxuXHJcbiAgICAvLyBTdXBwb3J0IHRoZSBKUEcgdHlwZVxyXG4gICAgaWYgKG91dFR5cGUgPT09ICdqcGcnKSB7XHJcbiAgICAgIHR5cGUgPSAnanBlZyc7XHJcbiAgICB9IGVsc2UgaWYgKGZvcm1hdHMuaW5jbHVkZXMob3V0VHlwZSkgJiYgdHlwZSAhPT0gb3V0VHlwZSkge1xyXG4gICAgICB0eXBlID0gb3V0VHlwZTtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIC8vIFJldHVybiBhIGNvcnJlY3QgdHlwZVxyXG4gIHJldHVybiBtaW1lVHlwZXNbdHlwZV0gfHwgZm9ybWF0cy5maW5kKCh0KSA9PiB0ID09PSB0eXBlKSB8fCAncG5nJztcclxufVxyXG5cclxuLyoqXHJcbiAqIENoZWNrcyBpZiB0aGUgZ2l2ZW4gcGF0aCBpcyByZWxhdGl2ZSBvciBhYnNvbHV0ZSBhbmQgcmV0dXJucyB0aGUgY29ycmVjdGVkLFxyXG4gKiBhYnNvbHV0ZSBwYXRoLlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gaXNBYnNvbHV0ZVBhdGhcclxuICpcclxuICogQHBhcmFtIHtzdHJpbmd9IHBhdGggLSBUaGUgcGF0aCB0byBiZSBjaGVja2VkIG9uLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7c3RyaW5nfSBUaGUgYWJzb2x1dGUgcGF0aC5cclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiBnZXRBYnNvbHV0ZVBhdGgocGF0aCkge1xyXG4gIHJldHVybiBpc0Fic29sdXRlKHBhdGgpID8gbm9ybWFsaXplKHBhdGgpIDogcmVzb2x2ZShwYXRoKTtcclxufVxyXG5cclxuLyoqXHJcbiAqIENvbnZlcnRzIGlucHV0IGRhdGEgdG8gYSBCYXNlNjQgc3RyaW5nIGJhc2VkIG9uIHRoZSBleHBvcnQgdHlwZS5cclxuICpcclxuICogQGZ1bmN0aW9uIGdldEJhc2U2NFxyXG4gKlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gaW5wdXQgLSBUaGUgaW5wdXQgdG8gYmUgdHJhbnNmb3JtZWQgdG8gQmFzZTY0IGZvcm1hdC5cclxuICogQHBhcmFtIHtzdHJpbmd9IHR5cGUgLSBUaGUgb3JpZ2luYWwgZXhwb3J0IHR5cGUuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtzdHJpbmd9IFRoZSBCYXNlNjQgc3RyaW5nIHJlcHJlc2VudGF0aW9uIG9mIHRoZSBpbnB1dC5cclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiBnZXRCYXNlNjQoaW5wdXQsIHR5cGUpIHtcclxuICAvLyBGb3IgcGRmIGFuZCBzdmcgdHlwZXMgdGhlIGlucHV0IG11c3QgYmUgdHJhbnNmb3JtZWQgdG8gQmFzZTY0IGZyb20gYSBidWZmZXJcclxuICBpZiAodHlwZSA9PT0gJ3BkZicgfHwgdHlwZSA9PSAnc3ZnJykge1xyXG4gICAgcmV0dXJuIEJ1ZmZlci5mcm9tKGlucHV0LCAndXRmOCcpLnRvU3RyaW5nKCdiYXNlNjQnKTtcclxuICB9XHJcblxyXG4gIC8vIEZvciBwbmcgYW5kIGpwZWcgaW5wdXQgaXMgYWxyZWFkeSBhIEJhc2U2NCBzdHJpbmdcclxuICByZXR1cm4gaW5wdXQ7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBSZXR1cm5zIHN0cmluZ2lmaWVkIGRhdGUgd2l0aG91dCB0aGUgR01UIHRleHQgaW5mb3JtYXRpb24uXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBnZXROZXdEYXRlXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gZ2V0TmV3RGF0ZSgpIHtcclxuICAvLyBHZXQgcmlkIG9mIHRoZSBHTVQgdGV4dCBpbmZvcm1hdGlvblxyXG4gIHJldHVybiBuZXcgRGF0ZSgpLnRvU3RyaW5nKCkuc3BsaXQoJygnKVswXS50cmltKCk7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBSZXR1cm5zIHRoZSBzdG9yZWQgdGltZSB2YWx1ZSBpbiBtaWxsaXNlY29uZHMuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBnZXROZXdEYXRlVGltZVxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIGdldE5ld0RhdGVUaW1lKCkge1xyXG4gIHJldHVybiBuZXcgRGF0ZSgpLmdldFRpbWUoKTtcclxufVxyXG5cclxuLyoqXHJcbiAqIENoZWNrcyBpZiB0aGUgZ2l2ZW4gaXRlbSBpcyBhbiBvYmplY3QuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBpc09iamVjdFxyXG4gKlxyXG4gKiBAcGFyYW0ge3Vua25vd259IGl0ZW0gLSBUaGUgaXRlbSB0byBiZSBjaGVja2VkLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7Ym9vbGVhbn0gVHJ1ZSBpZiB0aGUgaXRlbSBpcyBhbiBvYmplY3QsIGZhbHNlIG90aGVyd2lzZS5cclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiBpc09iamVjdChpdGVtKSB7XHJcbiAgcmV0dXJuIE9iamVjdC5wcm90b3R5cGUudG9TdHJpbmcuY2FsbChpdGVtKSA9PT0gJ1tvYmplY3QgT2JqZWN0XSc7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBDaGVja3MgaWYgdGhlIGdpdmVuIG9iamVjdCBpcyBlbXB0eS5cclxuICpcclxuICogQGZ1bmN0aW9uIGlzT2JqZWN0RW1wdHlcclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IGl0ZW0gLSBUaGUgb2JqZWN0IHRvIGJlIGNoZWNrZWQuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtib29sZWFufSBUcnVlIGlmIHRoZSBvYmplY3QgaXMgZW1wdHksIGZhbHNlIG90aGVyd2lzZS5cclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiBpc09iamVjdEVtcHR5KGl0ZW0pIHtcclxuICByZXR1cm4gKFxyXG4gICAgdHlwZW9mIGl0ZW0gPT09ICdvYmplY3QnICYmXHJcbiAgICAhQXJyYXkuaXNBcnJheShpdGVtKSAmJlxyXG4gICAgaXRlbSAhPT0gbnVsbCAmJlxyXG4gICAgT2JqZWN0LmtleXMoaXRlbSkubGVuZ3RoID09PSAwXHJcbiAgKTtcclxufVxyXG5cclxuLyoqXHJcbiAqIENoZWNrcyBpZiBhIHByaXZhdGUgSVAgcmFuZ2UgVVJMIGlzIGZvdW5kIGluIHRoZSBnaXZlbiBzdHJpbmcuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBpc1ByaXZhdGVSYW5nZVVybEZvdW5kXHJcbiAqXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSBpdGVtIC0gVGhlIHN0cmluZyB0byBiZSBjaGVja2VkIGZvciBhIHByaXZhdGUgSVAgcmFuZ2UgVVJMLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7Ym9vbGVhbn0gVHJ1ZSBpZiBhIHByaXZhdGUgSVAgcmFuZ2UgVVJMIGlzIGZvdW5kLCBmYWxzZSBvdGhlcndpc2UuXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gaXNQcml2YXRlUmFuZ2VVcmxGb3VuZChpdGVtKSB7XHJcbiAgY29uc3QgcmVnZXhQYXR0ZXJucyA9IFtcclxuICAgIC94bGluazpocmVmPVwiKD86aHR0cDpcXC9cXC98aHR0cHM6XFwvXFwvKT9sb2NhbGhvc3RcXGIvLFxyXG4gICAgL3hsaW5rOmhyZWY9XCIoPzpodHRwOlxcL1xcL3xodHRwczpcXC9cXC8pPzEwXFwuXFxkezEsM31cXC5cXGR7MSwzfVxcLlxcZHsxLDN9XFxiLyxcclxuICAgIC94bGluazpocmVmPVwiKD86aHR0cDpcXC9cXC98aHR0cHM6XFwvXFwvKT8xMjdcXC5cXGR7MSwzfVxcLlxcZHsxLDN9XFwuXFxkezEsM31cXGIvLFxyXG4gICAgL3hsaW5rOmhyZWY9XCIoPzpodHRwOlxcL1xcL3xodHRwczpcXC9cXC8pPzE3MlxcLigxWzYtOV18MlswLTldfDNbMC0xXSlcXC5cXGR7MSwzfVxcLlxcZHsxLDN9XFxiLyxcclxuICAgIC94bGluazpocmVmPVwiKD86aHR0cDpcXC9cXC98aHR0cHM6XFwvXFwvKT8xOTJcXC4xNjhcXC5cXGR7MSwzfVxcLlxcZHsxLDN9XFxiL1xyXG4gIF07XHJcblxyXG4gIHJldHVybiByZWdleFBhdHRlcm5zLnNvbWUoKHBhdHRlcm4pID0+IHBhdHRlcm4udGVzdChpdGVtKSk7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBVdGlsaXR5IHRvIG1lYXN1cmUgZWxhcHNlZCB0aW1lIHVzaW5nIHRoZSBOb2RlLmpzIGBwcm9jZXNzLmhydGltZSgpYCBtZXRob2QuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBtZWFzdXJlVGltZVxyXG4gKlxyXG4gKiBAcmV0dXJucyB7RnVuY3Rpb259IEEgZnVuY3Rpb24gdG8gY2FsY3VsYXRlIHRoZSBlbGFwc2VkIHRpbWUgaW4gbWlsbGlzZWNvbmRzLlxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIG1lYXN1cmVUaW1lKCkge1xyXG4gIGNvbnN0IHN0YXJ0ID0gcHJvY2Vzcy5ocnRpbWUuYmlnaW50KCk7XHJcbiAgcmV0dXJuICgpID0+IE51bWJlcihwcm9jZXNzLmhydGltZS5iaWdpbnQoKSAtIHN0YXJ0KSAvIDEwMDAwMDA7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBSb3VuZHMgYSBudW1iZXIgdG8gdGhlIHNwZWNpZmllZCBwcmVjaXNpb24uXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiByb3VuZE51bWJlclxyXG4gKlxyXG4gKiBAcGFyYW0ge251bWJlcn0gdmFsdWUgLSBUaGUgbnVtYmVyIHRvIGJlIHJvdW5kZWQuXHJcbiAqIEBwYXJhbSB7bnVtYmVyfSBwcmVjaXNpb24gLSBUaGUgbnVtYmVyIG9mIGRlY2ltYWwgcGxhY2VzIHRvIHJvdW5kIHRvLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7bnVtYmVyfSBUaGUgcm91bmRlZCBudW1iZXIuXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gcm91bmROdW1iZXIodmFsdWUsIHByZWNpc2lvbiA9IDEpIHtcclxuICBjb25zdCBtdWx0aXBsaWVyID0gTWF0aC5wb3coMTAsIHByZWNpc2lvbiB8fCAwKTtcclxuICByZXR1cm4gTWF0aC5yb3VuZCgrdmFsdWUgKiBtdWx0aXBsaWVyKSAvIG11bHRpcGxpZXI7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBDb252ZXJ0cyBhIHZhbHVlIHRvIGEgYm9vbGVhbi5cclxuICpcclxuICogQGZ1bmN0aW9uIHRvQm9vbGVhblxyXG4gKlxyXG4gKiBAcGFyYW0ge3Vua25vd259IGl0ZW0gLSBUaGUgdmFsdWUgdG8gYmUgY29udmVydGVkIHRvIGEgYm9vbGVhbi5cclxuICpcclxuICogQHJldHVybnMge2Jvb2xlYW59IFRoZSBib29sZWFuIHJlcHJlc2VudGF0aW9uIG9mIHRoZSBpbnB1dCB2YWx1ZS5cclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiB0b0Jvb2xlYW4oaXRlbSkge1xyXG4gIHJldHVybiBbJ2ZhbHNlJywgJ3VuZGVmaW5lZCcsICdudWxsJywgJ05hTicsICcwJywgJyddLmluY2x1ZGVzKGl0ZW0pXHJcbiAgICA/IGZhbHNlXHJcbiAgICA6ICEhaXRlbTtcclxufVxyXG5cclxuLyoqXHJcbiAqIFdyYXBzIGN1c3RvbSBjb2RlIHRvIGV4ZWN1dGUgaXQgc2FmZWx5LlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gd3JhcEFyb3VuZFxyXG4gKlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gY3VzdG9tQ29kZSAtIFRoZSBjdXN0b20gY29kZSB0byBiZSB3cmFwcGVkLlxyXG4gKiBAcGFyYW0ge2Jvb2xlYW59IGFsbG93RmlsZVJlc291cmNlcyAtIEZsYWcgdG8gYWxsb3cgbG9hZGluZyBjb2RlIGZyb20gYSBmaWxlLlxyXG4gKiBAcGFyYW0ge2Jvb2xlYW59IFtpc0NhbGxiYWNrPWZhbHNlXSAtIEZsYWcgdGhhdCBpbmRpY2F0ZXMgdGhlIHJldHVybmVkIGNvZGVcclxuICogbXVzdCBiZSBpbiBhIGNhbGxiYWNrIGZvcm1hdC5cclxuICpcclxuICogQHJldHVybnMgeyhzdHJpbmd8bnVsbCl9IFRoZSB3cmFwcGVkIGN1c3RvbSBjb2RlIG9yIG51bGwgaWYgd3JhcHBpbmcgZmFpbHMuXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gd3JhcEFyb3VuZChjdXN0b21Db2RlLCBhbGxvd0ZpbGVSZXNvdXJjZXMsIGlzQ2FsbGJhY2sgPSBmYWxzZSkge1xyXG4gIGlmIChjdXN0b21Db2RlICYmIHR5cGVvZiBjdXN0b21Db2RlID09PSAnc3RyaW5nJykge1xyXG4gICAgY3VzdG9tQ29kZSA9IGN1c3RvbUNvZGUudHJpbSgpO1xyXG5cclxuICAgIGlmIChjdXN0b21Db2RlLmVuZHNXaXRoKCcuanMnKSkge1xyXG4gICAgICAvLyBMb2FkIGEgZmlsZSBpZiB0aGUgZmlsZSByZXNvdXJjZXMgYXJlIGFsbG93ZWRcclxuICAgICAgcmV0dXJuIGFsbG93RmlsZVJlc291cmNlc1xyXG4gICAgICAgID8gd3JhcEFyb3VuZChcclxuICAgICAgICAgICAgcmVhZEZpbGVTeW5jKGdldEFic29sdXRlUGF0aChjdXN0b21Db2RlKSwgJ3V0ZjgnKSxcclxuICAgICAgICAgICAgYWxsb3dGaWxlUmVzb3VyY2VzLFxyXG4gICAgICAgICAgICBpc0NhbGxiYWNrXHJcbiAgICAgICAgICApXHJcbiAgICAgICAgOiBudWxsO1xyXG4gICAgfSBlbHNlIGlmIChcclxuICAgICAgIWlzQ2FsbGJhY2sgJiZcclxuICAgICAgKGN1c3RvbUNvZGUuc3RhcnRzV2l0aCgnZnVuY3Rpb24oKScpIHx8XHJcbiAgICAgICAgY3VzdG9tQ29kZS5zdGFydHNXaXRoKCdmdW5jdGlvbiAoKScpIHx8XHJcbiAgICAgICAgY3VzdG9tQ29kZS5zdGFydHNXaXRoKCcoKT0+JykgfHxcclxuICAgICAgICBjdXN0b21Db2RlLnN0YXJ0c1dpdGgoJygpID0+JykpXHJcbiAgICApIHtcclxuICAgICAgLy8gVHJlYXQgYSBmdW5jdGlvbiBhcyBhIHNlbGYtaW52b2tpbmcgZXhwcmVzc2lvblxyXG4gICAgICByZXR1cm4gYCgke2N1c3RvbUNvZGV9KSgpYDtcclxuICAgIH1cclxuXHJcbiAgICAvLyBPciByZXR1cm4gYXMgYSBzdHJpbmdpZmllZCBjb2RlXHJcbiAgICByZXR1cm4gY3VzdG9tQ29kZS5yZXBsYWNlKC87JC8sICcnKTtcclxuICB9XHJcbn1cclxuXHJcbmV4cG9ydCBkZWZhdWx0IHtcclxuICBfX2Rpcm5hbWUsXHJcbiAgY2xlYXJUZXh0LFxyXG4gIGRlZXBDb3B5LFxyXG4gIGV4cEJhY2tvZmYsXHJcbiAgZml4Q29uc3RyLFxyXG4gIGZpeE91dGZpbGUsXHJcbiAgZml4VHlwZSxcclxuICBnZXRBYnNvbHV0ZVBhdGgsXHJcbiAgZ2V0QmFzZTY0LFxyXG4gIGdldE5ld0RhdGUsXHJcbiAgZ2V0TmV3RGF0ZVRpbWUsXHJcbiAgaXNPYmplY3QsXHJcbiAgaXNPYmplY3RFbXB0eSxcclxuICBpc1ByaXZhdGVSYW5nZVVybEZvdW5kLFxyXG4gIG1lYXN1cmVUaW1lLFxyXG4gIHJvdW5kTnVtYmVyLFxyXG4gIHRvQm9vbGVhbixcclxuICB3cmFwQXJvdW5kXHJcbn07XHJcbiIsIi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXHJcblxyXG5IaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXJcclxuXHJcbkNvcHlyaWdodCAoYykgMjAxNi0yMDI1LCBIaWdoc29mdFxyXG5cclxuTGljZW5jZWQgdW5kZXIgdGhlIE1JVCBsaWNlbmNlLlxyXG5cclxuQWRkaXRpb25hbGx5IGEgdmFsaWQgSGlnaGNoYXJ0cyBsaWNlbnNlIGlzIHJlcXVpcmVkIGZvciB1c2UuXHJcblxyXG5TZWUgTElDRU5TRSBmaWxlIGluIHJvb3QgZm9yIGRldGFpbHMuXHJcblxyXG4qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xyXG5cclxuLyoqXHJcbiAqIEBvdmVydmlldyBBIG1vZHVsZSBmb3IgbWFuYWdpbmcgbG9nZ2luZyBmdW5jdGlvbmFsaXR5IHdpdGggY3VzdG9taXphYmxlXHJcbiAqIGxvZyBsZXZlbHMsIGNvbnNvbGUgYW5kIGZpbGUgbG9nZ2luZyBvcHRpb25zLCBhbmQgZXJyb3IgaGFuZGxpbmcgc3VwcG9ydC5cclxuICogVGhlIG1vZHVsZSBhbHNvIGVuc3VyZXMgdGhhdCBmaWxlLWJhc2VkIGxvZ3MgYXJlIHN0b3JlZCBpbiBhIHN0cnVjdHVyZWRcclxuICogZGlyZWN0b3J5LCBjcmVhdGluZyB0aGUgbmVjZXNzYXJ5IHBhdGhzIGF1dG9tYXRpY2FsbHkgaWYgdGhleSBkbyBub3QgZXhpc3QuXHJcbiAqL1xyXG5cclxuaW1wb3J0IHsgYXBwZW5kRmlsZSwgZXhpc3RzU3luYywgbWtkaXJTeW5jIH0gZnJvbSAnZnMnO1xyXG5pbXBvcnQgeyBqb2luIH0gZnJvbSAncGF0aCc7XHJcblxyXG5pbXBvcnQgeyBnZXRBYnNvbHV0ZVBhdGgsIGdldE5ld0RhdGUgfSBmcm9tICcuL3V0aWxzLmpzJztcclxuXHJcbi8vIFRoZSBhdmFpbGFibGUgY29sb3JzXHJcbmNvbnN0IGNvbG9ycyA9IFsncmVkJywgJ3llbGxvdycsICdibHVlJywgJ2dyYXknLCAnZ3JlZW4nXTtcclxuXHJcbi8vIFRoZSBkZWZhdWx0IGxvZ2dpbmcgY29uZmlnXHJcbmNvbnN0IGxvZ2dpbmcgPSB7XHJcbiAgLy8gRmxhZ3MgZm9yIGxvZ2dpbmcgc3RhdHVzXHJcbiAgdG9Db25zb2xlOiB0cnVlLFxyXG4gIHRvRmlsZTogZmFsc2UsXHJcbiAgcGF0aENyZWF0ZWQ6IGZhbHNlLFxyXG4gIC8vIEZ1bGwgcGF0aCB0byB0aGUgbG9nIGZpbGVcclxuICBwYXRoVG9Mb2c6ICcnLFxyXG4gIC8vIExvZyBsZXZlbHNcclxuICBsZXZlbHNEZXNjOiBbXHJcbiAgICB7XHJcbiAgICAgIHRpdGxlOiAnZXJyb3InLFxyXG4gICAgICBjb2xvcjogY29sb3JzWzBdXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0aXRsZTogJ3dhcm5pbmcnLFxyXG4gICAgICBjb2xvcjogY29sb3JzWzFdXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0aXRsZTogJ25vdGljZScsXHJcbiAgICAgIGNvbG9yOiBjb2xvcnNbMl1cclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHRpdGxlOiAndmVyYm9zZScsXHJcbiAgICAgIGNvbG9yOiBjb2xvcnNbM11cclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHRpdGxlOiAnYmVuY2htYXJrJyxcclxuICAgICAgY29sb3I6IGNvbG9yc1s0XVxyXG4gICAgfVxyXG4gIF1cclxufTtcclxuXHJcbi8qKlxyXG4gKiBMb2dzIGEgbWVzc2FnZSB3aXRoIGEgc3BlY2lmaWVkIGxvZyBsZXZlbC4gQWNjZXB0cyBhIHZhcmlhYmxlIG51bWJlclxyXG4gKiBvZiBhcmd1bWVudHMuIFRoZSBhcmd1bWVudHMgYWZ0ZXIgdGhlIGBsZXZlbGAgYXJlIHBhc3NlZCB0byBgY29uc29sZS5sb2dgXHJcbiAqIGFuZC9vciB1c2VkIHRvIGNvbnN0cnVjdCBhbmQgYXBwZW5kIG1lc3NhZ2VzIHRvIGEgbG9nIGZpbGUuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBsb2dcclxuICpcclxuICogQHBhcmFtIHsuLi51bmtub3dufSBhcmdzIC0gQW4gYXJyYXkgb2YgYXJndW1lbnRzIHdoZXJlIHRoZSBmaXJzdCBpcyB0aGUgbG9nXHJcbiAqIGxldmVsIGFuZCB0aGUgcmVtYWluaW5nIGFyZSBzdHJpbmdzIHVzZWQgdG8gYnVpbGQgdGhlIGxvZyBtZXNzYWdlLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7dm9pZH0gRXhpdHMgdGhlIGZ1bmN0aW9uIGV4ZWN1dGlvbiBpZiBhdHRlbXB0aW5nIHRvIGxvZyBhdCBhIGxldmVsXHJcbiAqIGhpZ2hlciB0aGFuIGFsbG93ZWQuXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gbG9nKC4uLmFyZ3MpIHtcclxuICBjb25zdCBbbmV3TGV2ZWwsIC4uLnRleHRzXSA9IGFyZ3M7XHJcblxyXG4gIC8vIEN1cnJlbnQgbG9nZ2luZyBvcHRpb25zXHJcbiAgY29uc3QgeyBsZXZlbHNEZXNjLCBsZXZlbCB9ID0gbG9nZ2luZztcclxuXHJcbiAgLy8gQ2hlY2sgaWYgdGhlIGxvZyBsZXZlbCBpcyB3aXRoaW4gYSBjb3JyZWN0IHJhbmdlIG9yIGlzIGl0IGEgYmVuY2htYXJrIGxvZ1xyXG4gIGlmIChcclxuICAgIG5ld0xldmVsICE9PSA1ICYmXHJcbiAgICAobmV3TGV2ZWwgPT09IDAgfHwgbmV3TGV2ZWwgPiBsZXZlbCB8fCBsZXZlbCA+IGxldmVsc0Rlc2MubGVuZ3RoKVxyXG4gICkge1xyXG4gICAgcmV0dXJuO1xyXG4gIH1cclxuXHJcbiAgLy8gQ3JlYXRlIGEgbWVzc2FnZSdzIHByZWZpeFxyXG4gIGNvbnN0IHByZWZpeCA9IGAke2dldE5ld0RhdGUoKX0gWyR7bGV2ZWxzRGVzY1tuZXdMZXZlbCAtIDFdLnRpdGxlfV0gLWA7XHJcblxyXG4gIC8vIExvZyB0byBmaWxlXHJcbiAgaWYgKGxvZ2dpbmcudG9GaWxlKSB7XHJcbiAgICBfbG9nVG9GaWxlKHRleHRzLCBwcmVmaXgpO1xyXG4gIH1cclxuXHJcbiAgLy8gTG9nIHRvIGNvbnNvbGVcclxuICBpZiAobG9nZ2luZy50b0NvbnNvbGUpIHtcclxuICAgIGNvbnNvbGUubG9nLmFwcGx5KFxyXG4gICAgICB1bmRlZmluZWQsXHJcbiAgICAgIFtwcmVmaXgudG9TdHJpbmcoKVtsb2dnaW5nLmxldmVsc0Rlc2NbbmV3TGV2ZWwgLSAxXS5jb2xvcl1dLmNvbmNhdCh0ZXh0cylcclxuICAgICk7XHJcbiAgfVxyXG59XHJcblxyXG4vKipcclxuICogTG9ncyBhbiBlcnJvciBtZXNzYWdlIGFsb25nIHdpdGggaXRzIHN0YWNrIHRyYWNlLiBPcHRpb25hbGx5LCBhIGN1c3RvbSBtZXNzYWdlXHJcbiAqIGNhbiBiZSBwcm92aWRlZC5cclxuICpcclxuICogQGZ1bmN0aW9uIGxvZ1dpdGhTdGFja1xyXG4gKlxyXG4gKiBAcGFyYW0ge251bWJlcn0gbmV3TGV2ZWwgLSBUaGUgbG9nIGxldmVsLlxyXG4gKiBAcGFyYW0ge0Vycm9yfSBlcnJvciAtIFRoZSBlcnJvciBvYmplY3QgY29udGFpbmluZyB0aGUgc3RhY2sgdHJhY2UuXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSBjdXN0b21NZXNzYWdlIC0gQW4gb3B0aW9uYWwgY3VzdG9tIG1lc3NhZ2UgdG8gYmUgaW5jbHVkZWRcclxuICogaW4gdGhlIGxvZyBhbG9uZ3NpZGUgdGhlIGVycm9yLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7dm9pZH0gRXhpdHMgdGhlIGZ1bmN0aW9uIGV4ZWN1dGlvbiBpZiBhdHRlbXB0aW5nIHRvIGxvZyBhdCBhIGxldmVsXHJcbiAqIGhpZ2hlciB0aGFuIGFsbG93ZWQuXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gbG9nV2l0aFN0YWNrKG5ld0xldmVsLCBlcnJvciwgY3VzdG9tTWVzc2FnZSkge1xyXG4gIC8vIEdldCB0aGUgbWFpbiBtZXNzYWdlXHJcbiAgY29uc3QgbWFpbk1lc3NhZ2UgPSBjdXN0b21NZXNzYWdlIHx8IChlcnJvciAmJiBlcnJvci5tZXNzYWdlKSB8fCAnJztcclxuXHJcbiAgLy8gQ3VycmVudCBsb2dnaW5nIG9wdGlvbnNcclxuICBjb25zdCB7IGxldmVsLCBsZXZlbHNEZXNjIH0gPSBsb2dnaW5nO1xyXG5cclxuICAvLyBDaGVjayBpZiB0aGUgbG9nIGxldmVsIGlzIHdpdGhpbiBhIGNvcnJlY3QgcmFuZ2VcclxuICBpZiAobmV3TGV2ZWwgPT09IDAgfHwgbmV3TGV2ZWwgPiBsZXZlbCB8fCBsZXZlbCA+IGxldmVsc0Rlc2MubGVuZ3RoKSB7XHJcbiAgICByZXR1cm47XHJcbiAgfVxyXG5cclxuICAvLyBDcmVhdGUgYSBtZXNzYWdlJ3MgcHJlZml4XHJcbiAgY29uc3QgcHJlZml4ID0gYCR7Z2V0TmV3RGF0ZSgpfSBbJHtsZXZlbHNEZXNjW25ld0xldmVsIC0gMV0udGl0bGV9XSAtYDtcclxuXHJcbiAgLy8gQWRkIHRoZSB3aG9sZSBzdGFjayBtZXNzYWdlXHJcbiAgY29uc3Qgc3RhY2tNZXNzYWdlID0gZXJyb3IgJiYgZXJyb3Iuc3RhY2s7XHJcblxyXG4gIC8vIENvbWJpbmUgY3VzdG9tIG1lc3NhZ2Ugb3IgZXJyb3IgbWVzc2FnZSB3aXRoIGVycm9yIHN0YWNrIG1lc3NhZ2UsIGlmIGV4aXN0c1xyXG4gIGNvbnN0IHRleHRzID0gW21haW5NZXNzYWdlXTtcclxuICBpZiAoc3RhY2tNZXNzYWdlKSB7XHJcbiAgICB0ZXh0cy5wdXNoKCdcXG4nLCBzdGFja01lc3NhZ2UpO1xyXG4gIH1cclxuXHJcbiAgLy8gTG9nIHRvIGZpbGVcclxuICBpZiAobG9nZ2luZy50b0ZpbGUpIHtcclxuICAgIF9sb2dUb0ZpbGUodGV4dHMsIHByZWZpeCk7XHJcbiAgfVxyXG5cclxuICAvLyBMb2cgdG8gY29uc29sZVxyXG4gIGlmIChsb2dnaW5nLnRvQ29uc29sZSkge1xyXG4gICAgY29uc29sZS5sb2cuYXBwbHkoXHJcbiAgICAgIHVuZGVmaW5lZCxcclxuICAgICAgW3ByZWZpeC50b1N0cmluZygpW2xvZ2dpbmcubGV2ZWxzRGVzY1tuZXdMZXZlbCAtIDFdLmNvbG9yXV0uY29uY2F0KFtcclxuICAgICAgICB0ZXh0cy5zaGlmdCgpW2NvbG9yc1tuZXdMZXZlbCAtIDFdXSxcclxuICAgICAgICAuLi50ZXh0c1xyXG4gICAgICBdKVxyXG4gICAgKTtcclxuICB9XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBMb2dzIGFuIGVycm9yIG1lc3NhZ2UgcmVsYXRlZCB0byBab2QgdmFsaWRhdGlvbiBpc3N1ZXMuIE9wdGlvbmFsbHksIGEgY3VzdG9tXHJcbiAqIG1lc3NhZ2UgY2FuIGJlIHByb3ZpZGVkLlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gbG9nWm9kSXNzdWVzXHJcbiAqXHJcbiAqIEBwYXJhbSB7bnVtYmVyfSBuZXdMZXZlbCAtIFRoZSBsb2cgbGV2ZWwuXHJcbiAqIEBwYXJhbSB7RXJyb3JbXX0gaXNzdWVzIC0gQW4gYXJyYXkgb2YgWm9kIHZhbGlkYXRpb24gaXNzdWVzLlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gY3VzdG9tTWVzc2FnZSAtIEFuIG9wdGlvbmFsIGN1c3RvbSBtZXNzYWdlIHRvIGJlIGluY2x1ZGVkXHJcbiAqIGluIHRoZSBsb2cgYWxvbmdzaWRlIHRoZSBlcnJvci5cclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiBsb2dab2RJc3N1ZXMobmV3TGV2ZWwsIGlzc3VlcywgY3VzdG9tTWVzc2FnZSkge1xyXG4gIGxvZ1dpdGhTdGFjayhcclxuICAgIG5ld0xldmVsLFxyXG4gICAgbnVsbCxcclxuICAgIFtcclxuICAgICAgYCR7Y3VzdG9tTWVzc2FnZSB8fCAnW3ZhbGlkYXRpb25dIFZhbGlkYXRpb24gZXJyb3InfSAtIHRoZSBmb2xsb3dpbmcgWm9kIGlzc3VlcyBvY2N1cmVkOmAsXHJcbiAgICAgIC4uLihpc3N1ZXMgfHwgW10pLm1hcCgoaXNzdWUpID0+IGAtICR7aXNzdWUubWVzc2FnZX1gKVxyXG4gICAgXS5qb2luKCdcXG4nKVxyXG4gICk7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBJbml0aWFsaXplcyBsb2dnaW5nIHdpdGggdGhlIHNwZWNpZmllZCBsb2dnaW5nIGNvbmZpZ3VyYXRpb24uXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBpbml0TG9nZ2luZ1xyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gbG9nZ2luZ09wdGlvbnMgLSBUaGUgY29uZmlndXJhdGlvbiBvYmplY3QgY29udGFpbmluZ1xyXG4gKiBgbG9nZ2luZ2Agb3B0aW9ucy5cclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiBpbml0TG9nZ2luZyhsb2dnaW5nT3B0aW9ucykge1xyXG4gIC8vIEdldCBvcHRpb25zIGZyb20gdGhlIGBsb2dnaW5nT3B0aW9uc2Agb2JqZWN0XHJcbiAgY29uc3QgeyBsZXZlbCwgZGVzdCwgZmlsZSwgdG9Db25zb2xlLCB0b0ZpbGUgfSA9IGxvZ2dpbmdPcHRpb25zO1xyXG5cclxuICAvLyBSZXNldCBmbGFncyB0byB0aGUgZGVmYXVsdCB2YWx1ZXNcclxuICBsb2dnaW5nLnBhdGhDcmVhdGVkID0gZmFsc2U7XHJcbiAgbG9nZ2luZy5wYXRoVG9Mb2cgPSAnJztcclxuXHJcbiAgLy8gU2V0IHRoZSBsb2dnaW5nIGxldmVsXHJcbiAgc2V0TG9nTGV2ZWwobGV2ZWwpO1xyXG5cclxuICAvLyBTZXQgdGhlIGNvbnNvbGUgbG9nZ2luZ1xyXG4gIGVuYWJsZUNvbnNvbGVMb2dnaW5nKHRvQ29uc29sZSk7XHJcblxyXG4gIC8vIFNldCB0aGUgZmlsZSBsb2dnaW5nXHJcbiAgZW5hYmxlRmlsZUxvZ2dpbmcoZGVzdCwgZmlsZSwgdG9GaWxlKTtcclxufVxyXG5cclxuLyoqXHJcbiAqIFNldHMgdGhlIGxvZyBsZXZlbCB0byB0aGUgc3BlY2lmaWVkIHZhbHVlLiBMb2cgbGV2ZWxzIGFyZSAoYDBgID0gbm8gbG9nZ2luZyxcclxuICogYDFgID0gZXJyb3IsIGAyYCA9IHdhcm5pbmcsIGAzYCA9IG5vdGljZSwgYDRgID0gdmVyYm9zZSwgb3IgYDVgID0gYmVuY2htYXJrKS5cclxuICpcclxuICogQGZ1bmN0aW9uIHNldExvZ0xldmVsXHJcbiAqXHJcbiAqIEBwYXJhbSB7bnVtYmVyfSBsZXZlbCAtIFRoZSBsb2cgbGV2ZWwgdG8gYmUgc2V0LlxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIHNldExvZ0xldmVsKGxldmVsKSB7XHJcbiAgaWYgKFxyXG4gICAgTnVtYmVyLmlzSW50ZWdlcihsZXZlbCkgJiZcclxuICAgIGxldmVsID49IDAgJiZcclxuICAgIGxldmVsIDw9IGxvZ2dpbmcubGV2ZWxzRGVzYy5sZW5ndGhcclxuICApIHtcclxuICAgIC8vIFVwZGF0ZSB0aGUgbW9kdWxlIGxvZ2dpbmcncyBgbGV2ZWxgIG9wdGlvblxyXG4gICAgbG9nZ2luZy5sZXZlbCA9IGxldmVsO1xyXG4gIH1cclxufVxyXG5cclxuLyoqXHJcbiAqIEVuYWJsZXMgY29uc29sZSBsb2dnaW5nLlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gZW5hYmxlQ29uc29sZUxvZ2dpbmdcclxuICpcclxuICogQHBhcmFtIHtib29sZWFufSB0b0NvbnNvbGUgLSBUaGUgZmxhZyBmb3Igc2V0dGluZyB0aGUgbG9nZ2luZyB0byB0aGUgY29uc29sZS5cclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiBlbmFibGVDb25zb2xlTG9nZ2luZyh0b0NvbnNvbGUpIHtcclxuICAvLyBVcGRhdGUgdGhlIG1vZHVsZSBsb2dnaW5nJ3MgYHRvQ29uc29sZWAgb3B0aW9uXHJcbiAgbG9nZ2luZy50b0NvbnNvbGUgPSAhIXRvQ29uc29sZTtcclxufVxyXG5cclxuLyoqXHJcbiAqIEVuYWJsZXMgZmlsZSBsb2dnaW5nIHdpdGggdGhlIHNwZWNpZmllZCBkZXN0aW5hdGlvbiBhbmQgbG9nIGZpbGUgbmFtZS5cclxuICpcclxuICogQGZ1bmN0aW9uIGVuYWJsZUZpbGVMb2dnaW5nXHJcbiAqXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSBkZXN0IC0gVGhlIGRlc3RpbmF0aW9uIHBhdGggd2hlcmUgdGhlIGxvZyBmaWxlIHNob3VsZFxyXG4gKiBiZSBzYXZlZC5cclxuICogQHBhcmFtIHtzdHJpbmd9IGZpbGUgLSBUaGUgbmFtZSBvZiB0aGUgbG9nIGZpbGUuXHJcbiAqIEBwYXJhbSB7Ym9vbGVhbn0gdG9GaWxlIC0gQSBmbGFnIGluZGljYXRpbmcgd2hldGhlciBsb2dnaW5nIHNob3VsZFxyXG4gKiBiZSBkaXJlY3RlZCB0byBhIGZpbGUuXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gZW5hYmxlRmlsZUxvZ2dpbmcoZGVzdCwgZmlsZSwgdG9GaWxlKSB7XHJcbiAgLy8gVXBkYXRlIHRoZSBtb2R1bGUgbG9nZ2luZydzIGB0b0ZpbGVgIG9wdGlvblxyXG4gIGxvZ2dpbmcudG9GaWxlID0gISF0b0ZpbGU7XHJcblxyXG4gIC8vIFNldCB0aGUgYGRlc3RgIGFuZCBgZmlsZWAgb3B0aW9ucyBvbmx5IGlmIHRoZSBmaWxlIGxvZ2dpbmcgaXMgZW5hYmxlZFxyXG4gIGlmIChsb2dnaW5nLnRvRmlsZSkge1xyXG4gICAgbG9nZ2luZy5kZXN0ID0gZGVzdCB8fCAnJztcclxuICAgIGxvZ2dpbmcuZmlsZSA9IGZpbGUgfHwgJyc7XHJcbiAgfVxyXG59XHJcblxyXG4vKipcclxuICogTG9ncyB0aGUgcHJvdmlkZWQgdGV4dHMgdG8gYSBmaWxlLCBpZiBmaWxlIGxvZ2dpbmcgaXMgZW5hYmxlZC4gSXQgY3JlYXRlc1xyXG4gKiB0aGUgbmVjZXNzYXJ5IGRpcmVjdG9yeSBzdHJ1Y3R1cmUgaWYgbm90IGFscmVhZHkgY3JlYXRlZCBhbmQgYXBwZW5kc1xyXG4gKiB0aGUgY29udGVudCwgaW5jbHVkaW5nIGFuIG9wdGlvbmFsIHByZWZpeCwgdG8gdGhlIHNwZWNpZmllZCBsb2cgZmlsZS5cclxuICpcclxuICogQGZ1bmN0aW9uIF9sb2dUb0ZpbGVcclxuICpcclxuICogQHBhcmFtIHtBcnJheS48c3RyaW5nPn0gdGV4dHMgLSBBbiBhcnJheSBvZiB0ZXh0cyB0byBiZSBsb2dnZWQuXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSBwcmVmaXggLSBBbiBvcHRpb25hbCBwcmVmaXggdG8gYmUgYWRkZWQgdG8gZWFjaCBsb2cgZW50cnkuXHJcbiAqL1xyXG5mdW5jdGlvbiBfbG9nVG9GaWxlKHRleHRzLCBwcmVmaXgpIHtcclxuICBpZiAoIWxvZ2dpbmcucGF0aENyZWF0ZWQpIHtcclxuICAgIC8vIENyZWF0ZSBpZiBkb2VzIG5vdCBleGlzdFxyXG4gICAgIWV4aXN0c1N5bmMoZ2V0QWJzb2x1dGVQYXRoKGxvZ2dpbmcuZGVzdCkpICYmXHJcbiAgICAgIG1rZGlyU3luYyhnZXRBYnNvbHV0ZVBhdGgobG9nZ2luZy5kZXN0KSk7XHJcblxyXG4gICAgLy8gQ3JlYXRlIHRoZSBmdWxsIHBhdGhcclxuICAgIGxvZ2dpbmcucGF0aFRvTG9nID0gZ2V0QWJzb2x1dGVQYXRoKGpvaW4obG9nZ2luZy5kZXN0LCBsb2dnaW5nLmZpbGUpKTtcclxuXHJcbiAgICAvLyBXZSBub3cgYXNzdW1lIHRoZSBwYXRoIGlzIGF2YWlsYWJsZSwgZS5nLiBpdCdzIHRoZSByZXNwb25zaWJpbGl0eVxyXG4gICAgLy8gb2YgdGhlIHVzZXIgdG8gY3JlYXRlIHRoZSBwYXRoIHdpdGggdGhlIGNvcnJlY3QgYWNjZXNzIHJpZ2h0cy5cclxuICAgIGxvZ2dpbmcucGF0aENyZWF0ZWQgPSB0cnVlO1xyXG4gIH1cclxuXHJcbiAgLy8gQWRkIHRoZSBjb250ZW50IHRvIGEgZmlsZVxyXG4gIGFwcGVuZEZpbGUoXHJcbiAgICBsb2dnaW5nLnBhdGhUb0xvZyxcclxuICAgIFtwcmVmaXhdLmNvbmNhdCh0ZXh0cykuam9pbignICcpICsgJ1xcbicsXHJcbiAgICAoZXJyb3IpID0+IHtcclxuICAgICAgaWYgKGVycm9yICYmIGxvZ2dpbmcudG9GaWxlICYmIGxvZ2dpbmcucGF0aENyZWF0ZWQpIHtcclxuICAgICAgICBsb2dnaW5nLnRvRmlsZSA9IGZhbHNlO1xyXG4gICAgICAgIGxvZ2dpbmcucGF0aENyZWF0ZWQgPSBmYWxzZTtcclxuICAgICAgICBsb2dXaXRoU3RhY2soMiwgZXJyb3IsIGBbbG9nZ2VyXSBVbmFibGUgdG8gd3JpdGUgdG8gbG9nIGZpbGUuYCk7XHJcbiAgICAgIH1cclxuICAgIH1cclxuICApO1xyXG59XHJcblxyXG5leHBvcnQgZGVmYXVsdCB7XHJcbiAgbG9nLFxyXG4gIGxvZ1dpdGhTdGFjayxcclxuICBsb2dab2RJc3N1ZXMsXHJcbiAgaW5pdExvZ2dpbmcsXHJcbiAgc2V0TG9nTGV2ZWwsXHJcbiAgZW5hYmxlQ29uc29sZUxvZ2dpbmcsXHJcbiAgZW5hYmxlRmlsZUxvZ2dpbmdcclxufTtcclxuIiwiLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcclxuXHJcbkhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlclxyXG5cclxuQ29weXJpZ2h0IChjKSAyMDE2LTIwMjUsIEhpZ2hzb2Z0XHJcblxyXG5MaWNlbmNlZCB1bmRlciB0aGUgTUlUIGxpY2VuY2UuXHJcblxyXG5BZGRpdGlvbmFsbHkgYSB2YWxpZCBIaWdoY2hhcnRzIGxpY2Vuc2UgaXMgcmVxdWlyZWQgZm9yIHVzZS5cclxuXHJcblNlZSBMSUNFTlNFIGZpbGUgaW4gcm9vdCBmb3IgZGV0YWlscy5cclxuXHJcbioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXHJcblxyXG4vKipcclxuICogQG92ZXJ2aWV3IENvbmZpZ3VyYXRpb24gbWFuYWdlbWVudCBtb2R1bGUgZm9yIHRoZSBIaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXIuXHJcbiAqIFByb3ZpZGVzIGRlZmF1bHQgY29uZmlndXJhdGlvbnMgdGhhdCBzdXBwb3J0IGVudmlyb25tZW50IHZhcmlhYmxlcywgQ0xJXHJcbiAqIGFyZ3VtZW50cywgYW5kIGludGVyYWN0aXZlIHByb21wdHMgZm9yIGN1c3RvbWl6YXRpb24gb2Ygb3B0aW9ucyBhbmQgZmVhdHVyZXMuXHJcbiAqIEFkZGl0aW9uYWxseSwgaXQgbWFwcyBsZWdhY3kgb3B0aW9ucyB0byBtb2Rlcm4gc3RydWN0dXJlcywgZ2VuZXJhdGVzIG5lc3RlZFxyXG4gKiBhcmd1bWVudCBtYXBwaW5ncywgYW5kIGRpc3BsYXlzIENMSSB1c2FnZSBpbmZvcm1hdGlvbi5cclxuICovXHJcblxyXG4vKipcclxuICogVGhlIGNvbmZpZ3VyYXRpb24gb2JqZWN0IGNvbnRhaW5pbmcgYWxsIGF2YWlsYWJsZSBvcHRpb25zLCBvcmdhbml6ZWRcclxuICogYnkgc2VjdGlvbnMuXHJcbiAqXHJcbiAqIFRoaXMgb2JqZWN0IGluY2x1ZGVzOlxyXG4gKiAtIERlZmF1bHQgdmFsdWVzIGZvciBlYWNoIG9wdGlvblxyXG4gKiAtIERhdGEgdHlwZXMgZm9yIHZhbGlkYXRpb25cclxuICogLSBOYW1lcyBvZiBjb3JyZXNwb25kaW5nIGVudmlyb25tZW50IHZhcmlhYmxlc1xyXG4gKiAtIERlc2NyaXB0aW9ucyBvZiBlYWNoIHByb3BlcnR5XHJcbiAqIC0gSW5mb3JtYXRpb24gdXNlZCBmb3IgcHJvbXB0cyBpbiBpbnRlcmFjdGl2ZSBjb25maWd1cmF0aW9uXHJcbiAqIC0gW09wdGlvbmFsXSBDb3JyZXNwb25kaW5nIENMSSBhcmd1bWVudCBuYW1lcyBmb3IgQ0xJIHVzYWdlXHJcbiAqIC0gW09wdGlvbmFsXSBMZWdhY3kgbmFtZXMgZnJvbSB0aGUgcHJldmlvdXMgUGhhbnRvbUpTLWJhc2VkIHNlcnZlclxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IGRlZmF1bHRDb25maWcgPSB7XHJcbiAgcHVwcGV0ZWVyOiB7XHJcbiAgICBhcmdzOiB7XHJcbiAgICAgIHZhbHVlOiBbXHJcbiAgICAgICAgJy0tYWxsb3ctcnVubmluZy1pbnNlY3VyZS1jb250ZW50JyxcclxuICAgICAgICAnLS1hc2gtbm8tbnVkZ2VzJyxcclxuICAgICAgICAnLS1hdXRvcGxheS1wb2xpY3k9dXNlci1nZXN0dXJlLXJlcXVpcmVkJyxcclxuICAgICAgICAnLS1ibG9jay1uZXctd2ViLWNvbnRlbnRzJyxcclxuICAgICAgICAnLS1kaXNhYmxlLWFjY2VsZXJhdGVkLTJkLWNhbnZhcycsXHJcbiAgICAgICAgJy0tZGlzYWJsZS1iYWNrZ3JvdW5kLW5ldHdvcmtpbmcnLFxyXG4gICAgICAgICctLWRpc2FibGUtYmFja2dyb3VuZC10aW1lci10aHJvdHRsaW5nJyxcclxuICAgICAgICAnLS1kaXNhYmxlLWJhY2tncm91bmRpbmctb2NjbHVkZWQtd2luZG93cycsXHJcbiAgICAgICAgJy0tZGlzYWJsZS1icmVha3BhZCcsXHJcbiAgICAgICAgJy0tZGlzYWJsZS1jaGVja2VyLWltYWdpbmcnLFxyXG4gICAgICAgICctLWRpc2FibGUtY2xpZW50LXNpZGUtcGhpc2hpbmctZGV0ZWN0aW9uJyxcclxuICAgICAgICAnLS1kaXNhYmxlLWNvbXBvbmVudC1leHRlbnNpb25zLXdpdGgtYmFja2dyb3VuZC1wYWdlcycsXHJcbiAgICAgICAgJy0tZGlzYWJsZS1jb21wb25lbnQtdXBkYXRlJyxcclxuICAgICAgICAnLS1kaXNhYmxlLWRlZmF1bHQtYXBwcycsXHJcbiAgICAgICAgJy0tZGlzYWJsZS1kZXYtc2htLXVzYWdlJyxcclxuICAgICAgICAnLS1kaXNhYmxlLWRvbWFpbi1yZWxpYWJpbGl0eScsXHJcbiAgICAgICAgJy0tZGlzYWJsZS1leHRlbnNpb25zJyxcclxuICAgICAgICAnLS1kaXNhYmxlLWZlYXR1cmVzPUNhbGN1bGF0ZU5hdGl2ZVdpbk9jY2x1c2lvbixJbnRlcmVzdEZlZWRDb250ZW50U3VnZ2VzdGlvbnMsV2ViT1RQJyxcclxuICAgICAgICAnLS1kaXNhYmxlLWhhbmctbW9uaXRvcicsXHJcbiAgICAgICAgJy0tZGlzYWJsZS1pcGMtZmxvb2RpbmctcHJvdGVjdGlvbicsXHJcbiAgICAgICAgJy0tZGlzYWJsZS1sb2dnaW5nJyxcclxuICAgICAgICAnLS1kaXNhYmxlLW5vdGlmaWNhdGlvbnMnLFxyXG4gICAgICAgICctLWRpc2FibGUtb2ZmZXItc3RvcmUtdW5tYXNrZWQtd2FsbGV0LWNhcmRzJyxcclxuICAgICAgICAnLS1kaXNhYmxlLXBvcHVwLWJsb2NraW5nJyxcclxuICAgICAgICAnLS1kaXNhYmxlLXByaW50LXByZXZpZXcnLFxyXG4gICAgICAgICctLWRpc2FibGUtcHJvbXB0LW9uLXJlcG9zdCcsXHJcbiAgICAgICAgJy0tZGlzYWJsZS1yZW5kZXJlci1iYWNrZ3JvdW5kaW5nJyxcclxuICAgICAgICAnLS1kaXNhYmxlLXNlYXJjaC1lbmdpbmUtY2hvaWNlLXNjcmVlbicsXHJcbiAgICAgICAgJy0tZGlzYWJsZS1zZXNzaW9uLWNyYXNoZWQtYnViYmxlJyxcclxuICAgICAgICAnLS1kaXNhYmxlLXNldHVpZC1zYW5kYm94JyxcclxuICAgICAgICAnLS1kaXNhYmxlLXNpdGUtaXNvbGF0aW9uLXRyaWFscycsXHJcbiAgICAgICAgJy0tZGlzYWJsZS1zcGVlY2gtYXBpJyxcclxuICAgICAgICAnLS1kaXNhYmxlLXN5bmMnLFxyXG4gICAgICAgICctLWVuYWJsZS11bnNhZmUtd2ViZ3B1JyxcclxuICAgICAgICAnLS1oaWRlLWNyYXNoLXJlc3RvcmUtYnViYmxlJyxcclxuICAgICAgICAnLS1oaWRlLXNjcm9sbGJhcnMnLFxyXG4gICAgICAgICctLW1ldHJpY3MtcmVjb3JkaW5nLW9ubHknLFxyXG4gICAgICAgICctLW11dGUtYXVkaW8nLFxyXG4gICAgICAgICctLW5vLWRlZmF1bHQtYnJvd3Nlci1jaGVjaycsXHJcbiAgICAgICAgJy0tbm8tZmlyc3QtcnVuJyxcclxuICAgICAgICAnLS1uby1waW5ncycsXHJcbiAgICAgICAgJy0tbm8tc2FuZGJveCcsXHJcbiAgICAgICAgJy0tbm8tc3RhcnR1cC13aW5kb3cnLFxyXG4gICAgICAgICctLW5vLXp5Z290ZScsXHJcbiAgICAgICAgJy0tcGFzc3dvcmQtc3RvcmU9YmFzaWMnLFxyXG4gICAgICAgICctLXByb2Nlc3MtcGVyLXRhYicsXHJcbiAgICAgICAgJy0tdXNlLW1vY2sta2V5Y2hhaW4nXHJcbiAgICAgIF0sXHJcbiAgICAgIHR5cGVzOiBbJ3N0cmluZ1tdJ10sXHJcbiAgICAgIGVudkxpbms6ICdQVVBQRVRFRVJfQVJHUycsXHJcbiAgICAgIGNsaU5hbWU6ICdwdXBwZXRlZXJBcmdzJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdBcnJheSBvZiBQdXBwZXRlZXIgYXJndW1lbnRzJyxcclxuICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgIHR5cGU6ICdsaXN0JyxcclxuICAgICAgICBzZXBhcmF0b3I6ICc7J1xyXG4gICAgICB9XHJcbiAgICB9XHJcbiAgfSxcclxuICBoaWdoY2hhcnRzOiB7XHJcbiAgICB2ZXJzaW9uOiB7XHJcbiAgICAgIHZhbHVlOiAnbGF0ZXN0JyxcclxuICAgICAgdHlwZXM6IFsnc3RyaW5nJ10sXHJcbiAgICAgIGVudkxpbms6ICdISUdIQ0hBUlRTX1ZFUlNJT04nLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ0hpZ2hjaGFydHMgdmVyc2lvbicsXHJcbiAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICB0eXBlOiAndGV4dCdcclxuICAgICAgfVxyXG4gICAgfSxcclxuICAgIGNkblVybDoge1xyXG4gICAgICB2YWx1ZTogJ2h0dHBzOi8vY29kZS5oaWdoY2hhcnRzLmNvbScsXHJcbiAgICAgIHR5cGVzOiBbJ3N0cmluZyddLFxyXG4gICAgICBlbnZMaW5rOiAnSElHSENIQVJUU19DRE5fVVJMJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdDRE4gVVJMIGZvciBIaWdoY2hhcnRzIHNjcmlwdHMnLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ3RleHQnXHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICBmb3JjZUZldGNoOiB7XHJcbiAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgdHlwZXM6IFsnYm9vbGVhbiddLFxyXG4gICAgICBlbnZMaW5rOiAnSElHSENIQVJUU19GT1JDRV9GRVRDSCcsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnRmxhZyB0byByZWZldGNoIHNjcmlwdHMgYWZ0ZXIgZWFjaCBzZXJ2ZXIgcmVydW4nLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ3RvZ2dsZSdcclxuICAgICAgfVxyXG4gICAgfSxcclxuICAgIGNhY2hlUGF0aDoge1xyXG4gICAgICB2YWx1ZTogJy5jYWNoZScsXHJcbiAgICAgIHR5cGVzOiBbJ3N0cmluZyddLFxyXG4gICAgICBlbnZMaW5rOiAnSElHSENIQVJUU19DQUNIRV9QQVRIJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdEaXJlY3RvcnkgcGF0aCBmb3IgY2FjaGVkIEhpZ2hjaGFydHMgc2NyaXB0cycsXHJcbiAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICB0eXBlOiAndGV4dCdcclxuICAgICAgfVxyXG4gICAgfSxcclxuICAgIGNvcmVTY3JpcHRzOiB7XHJcbiAgICAgIHZhbHVlOiBbJ2hpZ2hjaGFydHMnLCAnaGlnaGNoYXJ0cy1tb3JlJywgJ2hpZ2hjaGFydHMtM2QnXSxcclxuICAgICAgdHlwZXM6IFsnc3RyaW5nW10nXSxcclxuICAgICAgZW52TGluazogJ0hJR0hDSEFSVFNfQ09SRV9TQ1JJUFRTJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdIaWdoY2hhcnRzIGNvcmUgc2NyaXB0cyB0byBmZXRjaCcsXHJcbiAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICB0eXBlOiAnbXVsdGlzZWxlY3QnLFxyXG4gICAgICAgIGluc3RydWN0aW9uczogJ1NwYWNlOiBTZWxlY3Qgc3BlY2lmaWMsIEE6IFNlbGVjdCBhbGwsIEVudGVyOiBDb25maXJtJ1xyXG4gICAgICB9XHJcbiAgICB9LFxyXG4gICAgbW9kdWxlU2NyaXB0czoge1xyXG4gICAgICB2YWx1ZTogW1xyXG4gICAgICAgICdzdG9jaycsXHJcbiAgICAgICAgJ21hcCcsXHJcbiAgICAgICAgJ2dhbnR0JyxcclxuICAgICAgICAnZXhwb3J0aW5nJyxcclxuICAgICAgICAncGFyYWxsZWwtY29vcmRpbmF0ZXMnLFxyXG4gICAgICAgICdhY2Nlc3NpYmlsaXR5JyxcclxuICAgICAgICAvLyAnYW5ub3RhdGlvbnMtYWR2YW5jZWQnLFxyXG4gICAgICAgICdib29zdC1jYW52YXMnLFxyXG4gICAgICAgICdib29zdCcsXHJcbiAgICAgICAgJ2RhdGEnLFxyXG4gICAgICAgICdkYXRhLXRvb2xzJyxcclxuICAgICAgICAnZHJhZ2dhYmxlLXBvaW50cycsXHJcbiAgICAgICAgJ3N0YXRpYy1zY2FsZScsXHJcbiAgICAgICAgJ2Jyb2tlbi1heGlzJyxcclxuICAgICAgICAnaGVhdG1hcCcsXHJcbiAgICAgICAgJ3RpbGVtYXAnLFxyXG4gICAgICAgICd0aWxlZHdlYm1hcCcsXHJcbiAgICAgICAgJ3RpbWVsaW5lJyxcclxuICAgICAgICAndHJlZW1hcCcsXHJcbiAgICAgICAgJ3RyZWVncmFwaCcsXHJcbiAgICAgICAgJ2l0ZW0tc2VyaWVzJyxcclxuICAgICAgICAnZHJpbGxkb3duJyxcclxuICAgICAgICAnaGlzdG9ncmFtLWJlbGxjdXJ2ZScsXHJcbiAgICAgICAgJ2J1bGxldCcsXHJcbiAgICAgICAgJ2Z1bm5lbCcsXHJcbiAgICAgICAgJ2Z1bm5lbDNkJyxcclxuICAgICAgICAnZ2VvaGVhdG1hcCcsXHJcbiAgICAgICAgJ3B5cmFtaWQzZCcsXHJcbiAgICAgICAgJ25ldHdvcmtncmFwaCcsXHJcbiAgICAgICAgJ292ZXJsYXBwaW5nLWRhdGFsYWJlbHMnLFxyXG4gICAgICAgICdwYXJldG8nLFxyXG4gICAgICAgICdwYXR0ZXJuLWZpbGwnLFxyXG4gICAgICAgICdwaWN0b3JpYWwnLFxyXG4gICAgICAgICdwcmljZS1pbmRpY2F0b3InLFxyXG4gICAgICAgICdzYW5rZXknLFxyXG4gICAgICAgICdhcmMtZGlhZ3JhbScsXHJcbiAgICAgICAgJ2RlcGVuZGVuY3ktd2hlZWwnLFxyXG4gICAgICAgICdzZXJpZXMtbGFiZWwnLFxyXG4gICAgICAgICdzZXJpZXMtb24tcG9pbnQnLFxyXG4gICAgICAgICdzb2xpZC1nYXVnZScsXHJcbiAgICAgICAgJ3NvbmlmaWNhdGlvbicsXHJcbiAgICAgICAgLy8gJ3N0b2NrLXRvb2xzJyxcclxuICAgICAgICAnc3RyZWFtZ3JhcGgnLFxyXG4gICAgICAgICdzdW5idXJzdCcsXHJcbiAgICAgICAgJ3ZhcmlhYmxlLXBpZScsXHJcbiAgICAgICAgJ3Zhcml3aWRlJyxcclxuICAgICAgICAndmVjdG9yJyxcclxuICAgICAgICAndmVubicsXHJcbiAgICAgICAgJ3dpbmRiYXJiJyxcclxuICAgICAgICAnd29yZGNsb3VkJyxcclxuICAgICAgICAneHJhbmdlJyxcclxuICAgICAgICAnbm8tZGF0YS10by1kaXNwbGF5JyxcclxuICAgICAgICAnZHJhZy1wYW5lcycsXHJcbiAgICAgICAgJ2RlYnVnZ2VyJyxcclxuICAgICAgICAnZHVtYmJlbGwnLFxyXG4gICAgICAgICdsb2xsaXBvcCcsXHJcbiAgICAgICAgJ2N5bGluZGVyJyxcclxuICAgICAgICAnb3JnYW5pemF0aW9uJyxcclxuICAgICAgICAnZG90cGxvdCcsXHJcbiAgICAgICAgJ21hcmtlci1jbHVzdGVycycsXHJcbiAgICAgICAgJ2hvbGxvd2NhbmRsZXN0aWNrJyxcclxuICAgICAgICAnaGVpa2luYXNoaScsXHJcbiAgICAgICAgJ2Zsb3dtYXAnLFxyXG4gICAgICAgICdleHBvcnQtZGF0YScsXHJcbiAgICAgICAgJ25hdmlnYXRvcicsXHJcbiAgICAgICAgJ3RleHRwYXRoJ1xyXG4gICAgICBdLFxyXG4gICAgICB0eXBlczogWydzdHJpbmdbXSddLFxyXG4gICAgICBlbnZMaW5rOiAnSElHSENIQVJUU19NT0RVTEVfU0NSSVBUUycsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnSGlnaGNoYXJ0cyBtb2R1bGUgc2NyaXB0cyB0byBmZXRjaCcsXHJcbiAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICB0eXBlOiAnbXVsdGlzZWxlY3QnLFxyXG4gICAgICAgIGluc3RydWN0aW9uczogJ1NwYWNlOiBTZWxlY3Qgc3BlY2lmaWMsIEE6IFNlbGVjdCBhbGwsIEVudGVyOiBDb25maXJtJ1xyXG4gICAgICB9XHJcbiAgICB9LFxyXG4gICAgaW5kaWNhdG9yU2NyaXB0czoge1xyXG4gICAgICB2YWx1ZTogWydpbmRpY2F0b3JzLWFsbCddLFxyXG4gICAgICB0eXBlczogWydzdHJpbmdbXSddLFxyXG4gICAgICBlbnZMaW5rOiAnSElHSENIQVJUU19JTkRJQ0FUT1JfU0NSSVBUUycsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnSGlnaGNoYXJ0cyBpbmRpY2F0b3Igc2NyaXB0cyB0byBmZXRjaCcsXHJcbiAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICB0eXBlOiAnbXVsdGlzZWxlY3QnLFxyXG4gICAgICAgIGluc3RydWN0aW9uczogJ1NwYWNlOiBTZWxlY3Qgc3BlY2lmaWMsIEE6IFNlbGVjdCBhbGwsIEVudGVyOiBDb25maXJtJ1xyXG4gICAgICB9XHJcbiAgICB9LFxyXG4gICAgY3VzdG9tU2NyaXB0czoge1xyXG4gICAgICB2YWx1ZTogW1xyXG4gICAgICAgICdodHRwczovL2NkbmpzLmNsb3VkZmxhcmUuY29tL2FqYXgvbGlicy9tb21lbnQuanMvMi4zMC4xL21vbWVudC5taW4uanMnLFxyXG4gICAgICAgICdodHRwczovL2NkbmpzLmNsb3VkZmxhcmUuY29tL2FqYXgvbGlicy9tb21lbnQtdGltZXpvbmUvMC41LjQ1L21vbWVudC10aW1lem9uZS13aXRoLWRhdGEubWluLmpzJ1xyXG4gICAgICBdLFxyXG4gICAgICB0eXBlczogWydzdHJpbmdbXSddLFxyXG4gICAgICBlbnZMaW5rOiAnSElHSENIQVJUU19DVVNUT01fU0NSSVBUUycsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnQWRkaXRpb25hbCBjdXN0b20gc2NyaXB0cyBvciBkZXBlbmRlbmNpZXMgdG8gZmV0Y2gnLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ2xpc3QnLFxyXG4gICAgICAgIHNlcGFyYXRvcjogJzsnXHJcbiAgICAgIH1cclxuICAgIH1cclxuICB9LFxyXG4gIGV4cG9ydDoge1xyXG4gICAgaW5maWxlOiB7XHJcbiAgICAgIHZhbHVlOiBudWxsLFxyXG4gICAgICB0eXBlczogWydzdHJpbmcnLCAnbnVsbCddLFxyXG4gICAgICBlbnZMaW5rOiAnRVhQT1JUX0lORklMRScsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdJbnB1dCBmaWxlbmFtZSB3aXRoIHR5cGUsIGZvcm1hdHRlZCBjb3JyZWN0bHkgYXMgSlNPTiBvciBTVkcnLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ3RleHQnXHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICBpbnN0cjoge1xyXG4gICAgICB2YWx1ZTogbnVsbCxcclxuICAgICAgdHlwZXM6IFsnT2JqZWN0JywgJ3N0cmluZycsICdudWxsJ10sXHJcbiAgICAgIGVudkxpbms6ICdFWFBPUlRfSU5TVFInLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnT3ZlcnJpZGVzIHRoZSBgaW5maWxlYCB3aXRoIEpTT04sIHN0cmluZ2lmaWVkIEpTT04sIG9yIFNWRyBpbnB1dCcsXHJcbiAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICB0eXBlOiAndGV4dCdcclxuICAgICAgfVxyXG4gICAgfSxcclxuICAgIG9wdGlvbnM6IHtcclxuICAgICAgdmFsdWU6IG51bGwsXHJcbiAgICAgIHR5cGVzOiBbJ09iamVjdCcsICdzdHJpbmcnLCAnbnVsbCddLFxyXG4gICAgICBlbnZMaW5rOiAnRVhQT1JUX09QVElPTlMnLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ0FsaWFzIGZvciB0aGUgYGluc3RyYCBvcHRpb24nLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ3RleHQnXHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICBzdmc6IHtcclxuICAgICAgdmFsdWU6IG51bGwsXHJcbiAgICAgIHR5cGVzOiBbJ3N0cmluZycsICdudWxsJ10sXHJcbiAgICAgIGVudkxpbms6ICdFWFBPUlRfU1ZHJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdTVkcgc3RyaW5nIHJlcHJlc2VudGF0aW9uIG9mIHRoZSBjaGFydCB0byByZW5kZXInLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ3RleHQnXHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICBiYXRjaDoge1xyXG4gICAgICB2YWx1ZTogbnVsbCxcclxuICAgICAgdHlwZXM6IFsnc3RyaW5nJywgJ251bGwnXSxcclxuICAgICAgZW52TGluazogJ0VYUE9SVF9CQVRDSCcsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdCYXRjaCBqb2Igc3RyaW5nIHdpdGggaW5wdXQvb3V0cHV0IHBhaXJzOiBcImluPW91dDtpbj1vdXQ7Li4uXCInLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ3RleHQnXHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICBvdXRmaWxlOiB7XHJcbiAgICAgIHZhbHVlOiBudWxsLFxyXG4gICAgICB0eXBlczogWydzdHJpbmcnLCAnbnVsbCddLFxyXG4gICAgICBlbnZMaW5rOiAnRVhQT1JUX09VVEZJTEUnLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnT3V0cHV0IGZpbGVuYW1lIHdpdGggdHlwZS4gQ2FuIGJlIGpwZWcsIHBuZywgcGRmLCBvciBzdmcgYW5kIGlnbm9yZXMgYHR5cGVgIG9wdGlvbicsXHJcbiAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICB0eXBlOiAndGV4dCdcclxuICAgICAgfVxyXG4gICAgfSxcclxuICAgIHR5cGU6IHtcclxuICAgICAgdmFsdWU6ICdwbmcnLFxyXG4gICAgICB0eXBlczogWydzdHJpbmcnXSxcclxuICAgICAgZW52TGluazogJ0VYUE9SVF9UWVBFJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdGaWxlIGV4cG9ydCBmb3JtYXQuIENhbiBiZSBqcGVnLCBwbmcsIHBkZiwgb3Igc3ZnJyxcclxuICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgIHR5cGU6ICdzZWxlY3QnLFxyXG4gICAgICAgIGhpbnQ6ICdEZWZhdWx0OiBwbmcnLFxyXG4gICAgICAgIGNob2ljZXM6IFsncG5nJywgJ2pwZWcnLCAncGRmJywgJ3N2ZyddXHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICBjb25zdHI6IHtcclxuICAgICAgdmFsdWU6ICdjaGFydCcsXHJcbiAgICAgIHR5cGVzOiBbJ3N0cmluZyddLFxyXG4gICAgICBlbnZMaW5rOiAnRVhQT1JUX0NPTlNUUicsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdDaGFydCBjb25zdHJ1Y3Rvci4gQ2FuIGJlIGNoYXJ0LCBzdG9ja0NoYXJ0LCBtYXBDaGFydCwgb3IgZ2FudHRDaGFydCcsXHJcbiAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICB0eXBlOiAnc2VsZWN0JyxcclxuICAgICAgICBoaW50OiAnRGVmYXVsdDogY2hhcnQnLFxyXG4gICAgICAgIGNob2ljZXM6IFsnY2hhcnQnLCAnc3RvY2tDaGFydCcsICdtYXBDaGFydCcsICdnYW50dENoYXJ0J11cclxuICAgICAgfVxyXG4gICAgfSxcclxuICAgIGI2NDoge1xyXG4gICAgICB2YWx1ZTogZmFsc2UsXHJcbiAgICAgIHR5cGVzOiBbJ2Jvb2xlYW4nXSxcclxuICAgICAgZW52TGluazogJ0VYUE9SVF9CNjQnLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnV2hldGhlciBvciBub3QgdG8gdGhlIGNoYXJ0IHNob3VsZCBiZSByZWNlaXZlZCBpbiBCYXNlNjQgZm9ybWF0IGluc3RlYWQgb2YgYmluYXJ5JyxcclxuICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgIHR5cGU6ICd0b2dnbGUnXHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICBub0Rvd25sb2FkOiB7XHJcbiAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgdHlwZXM6IFsnYm9vbGVhbiddLFxyXG4gICAgICBlbnZMaW5rOiAnRVhQT1JUX05PX0RPV05MT0FEJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ1doZXRoZXIgb3Igbm90IHRvIGluY2x1ZGUgb3IgZXhjbHVkZSBhdHRhY2htZW50IGhlYWRlcnMgaW4gdGhlIHJlc3BvbnNlJyxcclxuICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgIHR5cGU6ICd0b2dnbGUnXHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICBoZWlnaHQ6IHtcclxuICAgICAgdmFsdWU6IG51bGwsXHJcbiAgICAgIHR5cGVzOiBbJ251bWJlcicsICdudWxsJ10sXHJcbiAgICAgIGVudkxpbms6ICdFWFBPUlRfSEVJR0hUJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdIZWlnaHQgb2YgdGhlIGV4cG9ydGVkIGNoYXJ0LCBvdmVycmlkZXMgY2hhcnQgc2V0dGluZ3MnLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ251bWJlcidcclxuICAgICAgfVxyXG4gICAgfSxcclxuICAgIHdpZHRoOiB7XHJcbiAgICAgIHZhbHVlOiBudWxsLFxyXG4gICAgICB0eXBlczogWydudW1iZXInLCAnbnVsbCddLFxyXG4gICAgICBlbnZMaW5rOiAnRVhQT1JUX1dJRFRIJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdXaWR0aCBvZiB0aGUgZXhwb3J0ZWQgY2hhcnQsIG92ZXJyaWRlcyBjaGFydCBzZXR0aW5ncycsXHJcbiAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICB0eXBlOiAnbnVtYmVyJ1xyXG4gICAgICB9XHJcbiAgICB9LFxyXG4gICAgc2NhbGU6IHtcclxuICAgICAgdmFsdWU6IG51bGwsXHJcbiAgICAgIHR5cGVzOiBbJ251bWJlcicsICdudWxsJ10sXHJcbiAgICAgIGVudkxpbms6ICdFWFBPUlRfU0NBTEUnLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnU2NhbGUgb2YgdGhlIGV4cG9ydGVkIGNoYXJ0LCBvdmVycmlkZXMgY2hhcnQgc2V0dGluZ3MuIFJhbmdlcyBmcm9tIDAuMSB0byA1LjAnLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ251bWJlcidcclxuICAgICAgfVxyXG4gICAgfSxcclxuICAgIGRlZmF1bHRIZWlnaHQ6IHtcclxuICAgICAgdmFsdWU6IDQwMCxcclxuICAgICAgdHlwZXM6IFsnbnVtYmVyJ10sXHJcbiAgICAgIGVudkxpbms6ICdFWFBPUlRfREVGQVVMVF9IRUlHSFQnLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ0RlZmF1bHQgaGVpZ2h0IG9mIHRoZSBleHBvcnRlZCBjaGFydCBpZiBub3Qgc2V0JyxcclxuICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgIHR5cGU6ICdudW1iZXInXHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICBkZWZhdWx0V2lkdGg6IHtcclxuICAgICAgdmFsdWU6IDYwMCxcclxuICAgICAgdHlwZXM6IFsnbnVtYmVyJ10sXHJcbiAgICAgIGVudkxpbms6ICdFWFBPUlRfREVGQVVMVF9XSURUSCcsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnRGVmYXVsdCB3aWR0aCBvZiB0aGUgZXhwb3J0ZWQgY2hhcnQgaWYgbm90IHNldCcsXHJcbiAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICB0eXBlOiAnbnVtYmVyJ1xyXG4gICAgICB9XHJcbiAgICB9LFxyXG4gICAgZGVmYXVsdFNjYWxlOiB7XHJcbiAgICAgIHZhbHVlOiAxLFxyXG4gICAgICB0eXBlczogWydudW1iZXInXSxcclxuICAgICAgZW52TGluazogJ0VYUE9SVF9ERUZBVUxUX1NDQUxFJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ0RlZmF1bHQgc2NhbGUgb2YgdGhlIGV4cG9ydGVkIGNoYXJ0IGlmIG5vdCBzZXQuIFJhbmdlcyBmcm9tIDAuMSB0byA1LjAnLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgICAgbWluOiAwLjEsXHJcbiAgICAgICAgbWF4OiA1XHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICBnbG9iYWxPcHRpb25zOiB7XHJcbiAgICAgIHZhbHVlOiBudWxsLFxyXG4gICAgICB0eXBlczogWydPYmplY3QnLCAnc3RyaW5nJywgJ251bGwnXSxcclxuICAgICAgZW52TGluazogJ0VYUE9SVF9HTE9CQUxfT1BUSU9OUycsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdKU09OLCBzdHJpbmdpZmllZCBKU09OIG9yIGZpbGVuYW1lIHdpdGggZ2xvYmFsIG9wdGlvbnMgZm9yIEhpZ2hjaGFydHMuc2V0T3B0aW9ucycsXHJcbiAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICB0eXBlOiAndGV4dCdcclxuICAgICAgfVxyXG4gICAgfSxcclxuICAgIHRoZW1lT3B0aW9uczoge1xyXG4gICAgICB2YWx1ZTogbnVsbCxcclxuICAgICAgdHlwZXM6IFsnT2JqZWN0JywgJ3N0cmluZycsICdudWxsJ10sXHJcbiAgICAgIGVudkxpbms6ICdFWFBPUlRfVEhFTUVfT1BUSU9OUycsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdKU09OLCBzdHJpbmdpZmllZCBKU09OIG9yIGZpbGVuYW1lIHdpdGggdGhlbWUgb3B0aW9ucyBmb3IgSGlnaGNoYXJ0cy5zZXRPcHRpb25zJyxcclxuICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgIHR5cGU6ICd0ZXh0J1xyXG4gICAgICB9XHJcbiAgICB9LFxyXG4gICAgcmFzdGVyaXphdGlvblRpbWVvdXQ6IHtcclxuICAgICAgdmFsdWU6IDE1MDAsXHJcbiAgICAgIHR5cGVzOiBbJ251bWJlciddLFxyXG4gICAgICBlbnZMaW5rOiAnRVhQT1JUX1JBU1RFUklaQVRJT05fVElNRU9VVCcsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnTWlsbGlzZWNvbmRzIHRvIHdhaXQgZm9yIHdlYnBhZ2UgcmVuZGVyaW5nJyxcclxuICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgIHR5cGU6ICdudW1iZXInXHJcbiAgICAgIH1cclxuICAgIH1cclxuICB9LFxyXG4gIGN1c3RvbUxvZ2ljOiB7XHJcbiAgICBhbGxvd0NvZGVFeGVjdXRpb246IHtcclxuICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICB0eXBlczogWydib29sZWFuJ10sXHJcbiAgICAgIGVudkxpbms6ICdDVVNUT01fTE9HSUNfQUxMT1dfQ09ERV9FWEVDVVRJT04nLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnQWxsb3dzIG9yIGRpc2FsbG93cyBleGVjdXRpb24gb2YgYXJiaXRyYXJ5IGNvZGUgZHVyaW5nIGV4cG9ydGluZycsXHJcbiAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICB0eXBlOiAndG9nZ2xlJ1xyXG4gICAgICB9XHJcbiAgICB9LFxyXG4gICAgYWxsb3dGaWxlUmVzb3VyY2VzOiB7XHJcbiAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgdHlwZXM6IFsnYm9vbGVhbiddLFxyXG4gICAgICBlbnZMaW5rOiAnQ1VTVE9NX0xPR0lDX0FMTE9XX0ZJTEVfUkVTT1VSQ0VTJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ0FsbG93cyBvciBkaXNhbGxvd3MgaW5qZWN0aW9uIG9mIGZpbGVzeXN0ZW0gcmVzb3VyY2VzIChkaXNhYmxlZCBpbiBzZXJ2ZXIgbW9kZSknLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ3RvZ2dsZSdcclxuICAgICAgfVxyXG4gICAgfSxcclxuICAgIGN1c3RvbUNvZGU6IHtcclxuICAgICAgdmFsdWU6IG51bGwsXHJcbiAgICAgIHR5cGVzOiBbJ3N0cmluZycsICdudWxsJ10sXHJcbiAgICAgIGVudkxpbms6ICdDVVNUT01fTE9HSUNfQ1VTVE9NX0NPREUnLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnQ3VzdG9tIGNvZGUgdG8gZXhlY3V0ZSBiZWZvcmUgY2hhcnQgaW5pdGlhbGl6YXRpb24uIENhbiBiZSBhIGZ1bmN0aW9uLCBjb2RlIHdyYXBwZWQgaW4gYSBmdW5jdGlvbiwgb3IgYSAuanMgZmlsZW5hbWUnLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ3RleHQnXHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICBjYWxsYmFjazoge1xyXG4gICAgICB2YWx1ZTogbnVsbCxcclxuICAgICAgdHlwZXM6IFsnc3RyaW5nJywgJ251bGwnXSxcclxuICAgICAgZW52TGluazogJ0NVU1RPTV9MT0dJQ19DQUxMQkFDSycsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdKYXZhU2NyaXB0IGNvZGUgdG8gcnVuIGR1cmluZyBjb25zdHJ1Y3Rpb24uIENhbiBiZSBhIGZ1bmN0aW9uIG9yIGEgLmpzIGZpbGVuYW1lJyxcclxuICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgIHR5cGU6ICd0ZXh0J1xyXG4gICAgICB9XHJcbiAgICB9LFxyXG4gICAgcmVzb3VyY2VzOiB7XHJcbiAgICAgIHZhbHVlOiBudWxsLFxyXG4gICAgICB0eXBlczogWydPYmplY3QnLCAnc3RyaW5nJywgJ251bGwnXSxcclxuICAgICAgZW52TGluazogJ0NVU1RPTV9MT0dJQ19SRVNPVVJDRVMnLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnQWRkaXRpb25hbCByZXNvdXJjZXMgYXMgSlNPTiwgc3RyaW5naWZpZWQgSlNPTiwgb3IgZmlsZW5hbWUsIGNvbnRhaW5pbmcgZmlsZXMsIGpzLCBhbmQgY3NzIHNlY3Rpb25zJyxcclxuICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgIHR5cGU6ICd0ZXh0J1xyXG4gICAgICB9XHJcbiAgICB9LFxyXG4gICAgbG9hZENvbmZpZzoge1xyXG4gICAgICB2YWx1ZTogbnVsbCxcclxuICAgICAgdHlwZXM6IFsnc3RyaW5nJywgJ251bGwnXSxcclxuICAgICAgZW52TGluazogJ0NVU1RPTV9MT0dJQ19MT0FEX0NPTkZJRycsXHJcbiAgICAgIGxlZ2FjeU5hbWU6ICdmcm9tRmlsZScsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnRmlsZSB3aXRoIGEgcHJlLWRlZmluZWQgY29uZmlndXJhdGlvbiB0byB1c2UnLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ3RleHQnXHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICBjcmVhdGVDb25maWc6IHtcclxuICAgICAgdmFsdWU6IG51bGwsXHJcbiAgICAgIHR5cGVzOiBbJ3N0cmluZycsICdudWxsJ10sXHJcbiAgICAgIGVudkxpbms6ICdDVVNUT01fTE9HSUNfQ1JFQVRFX0NPTkZJRycsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdQcm9tcHQtYmFzZWQgb3B0aW9uIHNldHRpbmcsIHNhdmVkIHRvIGEgcHJvdmlkZWQgY29uZmlnIGZpbGUnLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ3RleHQnXHJcbiAgICAgIH1cclxuICAgIH1cclxuICB9LFxyXG4gIHNlcnZlcjoge1xyXG4gICAgZW5hYmxlOiB7XHJcbiAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgdHlwZXM6IFsnYm9vbGVhbiddLFxyXG4gICAgICBlbnZMaW5rOiAnU0VSVkVSX0VOQUJMRScsXHJcbiAgICAgIGNsaU5hbWU6ICdlbmFibGVTZXJ2ZXInLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ1N0YXJ0cyB0aGUgc2VydmVyIHdoZW4gdHJ1ZScsXHJcbiAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICB0eXBlOiAndG9nZ2xlJ1xyXG4gICAgICB9XHJcbiAgICB9LFxyXG4gICAgaG9zdDoge1xyXG4gICAgICB2YWx1ZTogJzAuMC4wLjAnLFxyXG4gICAgICB0eXBlczogWydzdHJpbmcnXSxcclxuICAgICAgZW52TGluazogJ1NFUlZFUl9IT1NUJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdIb3N0bmFtZSBvZiB0aGUgc2VydmVyJyxcclxuICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgIHR5cGU6ICd0ZXh0J1xyXG4gICAgICB9XHJcbiAgICB9LFxyXG4gICAgcG9ydDoge1xyXG4gICAgICB2YWx1ZTogNzgwMSxcclxuICAgICAgdHlwZXM6IFsnbnVtYmVyJ10sXHJcbiAgICAgIGVudkxpbms6ICdTRVJWRVJfUE9SVCcsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnUG9ydCBudW1iZXIgZm9yIHRoZSBzZXJ2ZXInLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ251bWJlcidcclxuICAgICAgfVxyXG4gICAgfSxcclxuICAgIHVwbG9hZExpbWl0OiB7XHJcbiAgICAgIHZhbHVlOiAzLFxyXG4gICAgICB0eXBlczogWydudW1iZXInXSxcclxuICAgICAgZW52TGluazogJ1NFUlZFUl9VUExPQURfTElNSVQnLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ01heGltdW0gcmVxdWVzdCBib2R5IHNpemUgaW4gTUInLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ251bWJlcidcclxuICAgICAgfVxyXG4gICAgfSxcclxuICAgIGJlbmNobWFya2luZzoge1xyXG4gICAgICB2YWx1ZTogZmFsc2UsXHJcbiAgICAgIHR5cGVzOiBbJ2Jvb2xlYW4nXSxcclxuICAgICAgZW52TGluazogJ1NFUlZFUl9CRU5DSE1BUktJTkcnLFxyXG4gICAgICBjbGlOYW1lOiAnc2VydmVyQmVuY2htYXJraW5nJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ0Rpc3BsYXlzIG9yIG5vdCBhY3Rpb24gZHVyYXRpb25zIGluIG1pbGxpc2Vjb25kcyBkdXJpbmcgc2VydmVyIHJlcXVlc3RzJyxcclxuICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgIHR5cGU6ICd0b2dnbGUnXHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICBwcm94eToge1xyXG4gICAgICBob3N0OiB7XHJcbiAgICAgICAgdmFsdWU6IG51bGwsXHJcbiAgICAgICAgdHlwZXM6IFsnc3RyaW5nJywgJ251bGwnXSxcclxuICAgICAgICBlbnZMaW5rOiAnU0VSVkVSX1BST1hZX0hPU1QnLFxyXG4gICAgICAgIGNsaU5hbWU6ICdwcm94eUhvc3QnLFxyXG4gICAgICAgIGRlc2NyaXB0aW9uOiAnSG9zdCBvZiB0aGUgcHJveHkgc2VydmVyLCBpZiBhcHBsaWNhYmxlJyxcclxuICAgICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgICB0eXBlOiAndGV4dCdcclxuICAgICAgICB9XHJcbiAgICAgIH0sXHJcbiAgICAgIHBvcnQ6IHtcclxuICAgICAgICB2YWx1ZTogbnVsbCxcclxuICAgICAgICB0eXBlczogWydudW1iZXInLCAnbnVsbCddLFxyXG4gICAgICAgIGVudkxpbms6ICdTRVJWRVJfUFJPWFlfUE9SVCcsXHJcbiAgICAgICAgY2xpTmFtZTogJ3Byb3h5UG9ydCcsXHJcbiAgICAgICAgZGVzY3JpcHRpb246ICdQb3J0IG9mIHRoZSBwcm94eSBzZXJ2ZXIsIGlmIGFwcGxpY2FibGUnLFxyXG4gICAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICAgIHR5cGU6ICdudW1iZXInXHJcbiAgICAgICAgfVxyXG4gICAgICB9LFxyXG4gICAgICB0aW1lb3V0OiB7XHJcbiAgICAgICAgdmFsdWU6IDUwMDAsXHJcbiAgICAgICAgdHlwZXM6IFsnbnVtYmVyJ10sXHJcbiAgICAgICAgZW52TGluazogJ1NFUlZFUl9QUk9YWV9USU1FT1VUJyxcclxuICAgICAgICBjbGlOYW1lOiAncHJveHlUaW1lb3V0JyxcclxuICAgICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAgICdUaW1lb3V0IGluIG1pbGxpc2Vjb25kcyBmb3IgdGhlIHByb3h5IHNlcnZlciwgaWYgYXBwbGljYWJsZScsXHJcbiAgICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgICAgdHlwZTogJ251bWJlcidcclxuICAgICAgICB9XHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICByYXRlTGltaXRpbmc6IHtcclxuICAgICAgZW5hYmxlOiB7XHJcbiAgICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICAgIHR5cGVzOiBbJ2Jvb2xlYW4nXSxcclxuICAgICAgICBlbnZMaW5rOiAnU0VSVkVSX1JBVEVfTElNSVRJTkdfRU5BQkxFJyxcclxuICAgICAgICBjbGlOYW1lOiAnZW5hYmxlUmF0ZUxpbWl0aW5nJyxcclxuICAgICAgICBkZXNjcmlwdGlvbjogJ0VuYWJsZXMgb3IgZGlzYWJsZXMgcmF0ZSBsaW1pdGluZyBvbiB0aGUgc2VydmVyJyxcclxuICAgICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgICB0eXBlOiAndG9nZ2xlJ1xyXG4gICAgICAgIH1cclxuICAgICAgfSxcclxuICAgICAgbWF4UmVxdWVzdHM6IHtcclxuICAgICAgICB2YWx1ZTogMTAsXHJcbiAgICAgICAgdHlwZXM6IFsnbnVtYmVyJ10sXHJcbiAgICAgICAgZW52TGluazogJ1NFUlZFUl9SQVRFX0xJTUlUSU5HX01BWF9SRVFVRVNUUycsXHJcbiAgICAgICAgbGVnYWN5TmFtZTogJ3JhdGVMaW1pdCcsXHJcbiAgICAgICAgZGVzY3JpcHRpb246ICdNYXhpbXVtIG51bWJlciBvZiByZXF1ZXN0cyBhbGxvd2VkIHBlciBtaW51dGUnLFxyXG4gICAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICAgIHR5cGU6ICdudW1iZXInXHJcbiAgICAgICAgfVxyXG4gICAgICB9LFxyXG4gICAgICB3aW5kb3c6IHtcclxuICAgICAgICB2YWx1ZTogMSxcclxuICAgICAgICB0eXBlczogWydudW1iZXInXSxcclxuICAgICAgICBlbnZMaW5rOiAnU0VSVkVSX1JBVEVfTElNSVRJTkdfV0lORE9XJyxcclxuICAgICAgICBkZXNjcmlwdGlvbjogJ1RpbWUgd2luZG93IGluIG1pbnV0ZXMgZm9yIHJhdGUgbGltaXRpbmcnLFxyXG4gICAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICAgIHR5cGU6ICdudW1iZXInXHJcbiAgICAgICAgfVxyXG4gICAgICB9LFxyXG4gICAgICBkZWxheToge1xyXG4gICAgICAgIHZhbHVlOiAwLFxyXG4gICAgICAgIHR5cGVzOiBbJ251bWJlciddLFxyXG4gICAgICAgIGVudkxpbms6ICdTRVJWRVJfUkFURV9MSU1JVElOR19ERUxBWScsXHJcbiAgICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgICAnRGVsYXkgZHVyYXRpb24gYmV0d2VlbiBzdWNjZXNzaXZlIHJlcXVlc3RzIGJlZm9yZSByZWFjaGluZyB0aGUgbGltaXQnLFxyXG4gICAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICAgIHR5cGU6ICdudW1iZXInXHJcbiAgICAgICAgfVxyXG4gICAgICB9LFxyXG4gICAgICB0cnVzdFByb3h5OiB7XHJcbiAgICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICAgIHR5cGVzOiBbJ2Jvb2xlYW4nXSxcclxuICAgICAgICBlbnZMaW5rOiAnU0VSVkVSX1JBVEVfTElNSVRJTkdfVFJVU1RfUFJPWFknLFxyXG4gICAgICAgIGRlc2NyaXB0aW9uOiAnU2V0IHRvIHRydWUgaWYgdGhlIHNlcnZlciBpcyBiZWhpbmQgYSBsb2FkIGJhbGFuY2VyJyxcclxuICAgICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgICB0eXBlOiAndG9nZ2xlJ1xyXG4gICAgICAgIH1cclxuICAgICAgfSxcclxuICAgICAgc2tpcEtleToge1xyXG4gICAgICAgIHZhbHVlOiBudWxsLFxyXG4gICAgICAgIHR5cGVzOiBbJ3N0cmluZycsICdudWxsJ10sXHJcbiAgICAgICAgZW52TGluazogJ1NFUlZFUl9SQVRFX0xJTUlUSU5HX1NLSVBfS0VZJyxcclxuICAgICAgICBkZXNjcmlwdGlvbjogJ0tleSB0byBieXBhc3MgdGhlIHJhdGUgbGltaXRlciwgdXNlZCB3aXRoIGBza2lwVG9rZW5gJyxcclxuICAgICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgICB0eXBlOiAndGV4dCdcclxuICAgICAgICB9XHJcbiAgICAgIH0sXHJcbiAgICAgIHNraXBUb2tlbjoge1xyXG4gICAgICAgIHZhbHVlOiBudWxsLFxyXG4gICAgICAgIHR5cGVzOiBbJ3N0cmluZycsICdudWxsJ10sXHJcbiAgICAgICAgZW52TGluazogJ1NFUlZFUl9SQVRFX0xJTUlUSU5HX1NLSVBfVE9LRU4nLFxyXG4gICAgICAgIGRlc2NyaXB0aW9uOiAnVG9rZW4gdG8gYnlwYXNzIHRoZSByYXRlIGxpbWl0ZXIsIHVzZWQgd2l0aCBgc2tpcEtleWAnLFxyXG4gICAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICAgIHR5cGU6ICd0ZXh0J1xyXG4gICAgICAgIH1cclxuICAgICAgfVxyXG4gICAgfSxcclxuICAgIHNzbDoge1xyXG4gICAgICBlbmFibGU6IHtcclxuICAgICAgICB2YWx1ZTogZmFsc2UsXHJcbiAgICAgICAgdHlwZXM6IFsnYm9vbGVhbiddLFxyXG4gICAgICAgIGVudkxpbms6ICdTRVJWRVJfU1NMX0VOQUJMRScsXHJcbiAgICAgICAgY2xpTmFtZTogJ2VuYWJsZVNzbCcsXHJcbiAgICAgICAgZGVzY3JpcHRpb246ICdFbmFibGVzIG9yIGRpc2FibGVzIFNTTCBwcm90b2NvbCcsXHJcbiAgICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgICAgdHlwZTogJ3RvZ2dsZSdcclxuICAgICAgICB9XHJcbiAgICAgIH0sXHJcbiAgICAgIGZvcmNlOiB7XHJcbiAgICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICAgIHR5cGVzOiBbJ2Jvb2xlYW4nXSxcclxuICAgICAgICBlbnZMaW5rOiAnU0VSVkVSX1NTTF9GT1JDRScsXHJcbiAgICAgICAgY2xpTmFtZTogJ3NzbEZvcmNlJyxcclxuICAgICAgICBsZWdhY3lOYW1lOiAnc3NsT25seScsXHJcbiAgICAgICAgZGVzY3JpcHRpb246ICdGb3JjZXMgdGhlIHNlcnZlciB0byB1c2UgSFRUUFMgb25seSB3aGVuIHRydWUnLFxyXG4gICAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICAgIHR5cGU6ICd0b2dnbGUnXHJcbiAgICAgICAgfVxyXG4gICAgICB9LFxyXG4gICAgICBwb3J0OiB7XHJcbiAgICAgICAgdmFsdWU6IDQ0MyxcclxuICAgICAgICB0eXBlczogWydudW1iZXInXSxcclxuICAgICAgICBlbnZMaW5rOiAnU0VSVkVSX1NTTF9QT1JUJyxcclxuICAgICAgICBjbGlOYW1lOiAnc3NsUG9ydCcsXHJcbiAgICAgICAgZGVzY3JpcHRpb246ICdQb3J0IGZvciB0aGUgU1NMIHNlcnZlcicsXHJcbiAgICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgICAgdHlwZTogJ251bWJlcidcclxuICAgICAgICB9XHJcbiAgICAgIH0sXHJcbiAgICAgIGNlcnRQYXRoOiB7XHJcbiAgICAgICAgdmFsdWU6IG51bGwsXHJcbiAgICAgICAgdHlwZXM6IFsnc3RyaW5nJywgJ251bGwnXSxcclxuICAgICAgICBlbnZMaW5rOiAnU0VSVkVSX1NTTF9DRVJUX1BBVEgnLFxyXG4gICAgICAgIGNsaU5hbWU6ICdzc2xDZXJ0UGF0aCcsXHJcbiAgICAgICAgbGVnYWN5TmFtZTogJ3NzbFBhdGgnLFxyXG4gICAgICAgIGRlc2NyaXB0aW9uOiAnUGF0aCB0byB0aGUgU1NMIGNlcnRpZmljYXRlL2tleSBmaWxlJyxcclxuICAgICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgICB0eXBlOiAndGV4dCdcclxuICAgICAgICB9XHJcbiAgICAgIH1cclxuICAgIH1cclxuICB9LFxyXG4gIHBvb2w6IHtcclxuICAgIG1pbldvcmtlcnM6IHtcclxuICAgICAgdmFsdWU6IDQsXHJcbiAgICAgIHR5cGVzOiBbJ251bWJlciddLFxyXG4gICAgICBlbnZMaW5rOiAnUE9PTF9NSU5fV09SS0VSUycsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnTWluaW11bSBhbmQgaW5pdGlhbCBudW1iZXIgb2YgcG9vbCB3b3JrZXJzIHRvIHNwYXduJyxcclxuICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgIHR5cGU6ICdudW1iZXInXHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICBtYXhXb3JrZXJzOiB7XHJcbiAgICAgIHZhbHVlOiA4LFxyXG4gICAgICB0eXBlczogWydudW1iZXInXSxcclxuICAgICAgZW52TGluazogJ1BPT0xfTUFYX1dPUktFUlMnLFxyXG4gICAgICBsZWdhY3lOYW1lOiAnd29ya2VycycsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnTWF4aW11bSBudW1iZXIgb2YgcG9vbCB3b3JrZXJzIHRvIHNwYXduJyxcclxuICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgIHR5cGU6ICdudW1iZXInXHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICB3b3JrTGltaXQ6IHtcclxuICAgICAgdmFsdWU6IDQwLFxyXG4gICAgICB0eXBlczogWydudW1iZXInXSxcclxuICAgICAgZW52TGluazogJ1BPT0xfV09SS19MSU1JVCcsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnTnVtYmVyIG9mIHRhc2tzIGEgd29ya2VyIGNhbiBoYW5kbGUgYmVmb3JlIHJlc3RhcnRpbmcnLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ251bWJlcidcclxuICAgICAgfVxyXG4gICAgfSxcclxuICAgIGFjcXVpcmVUaW1lb3V0OiB7XHJcbiAgICAgIHZhbHVlOiA1MDAwLFxyXG4gICAgICB0eXBlczogWydudW1iZXInXSxcclxuICAgICAgZW52TGluazogJ1BPT0xfQUNRVUlSRV9USU1FT1VUJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdUaW1lb3V0IGluIG1pbGxpc2Vjb25kcyBmb3IgYWNxdWlyaW5nIGEgcmVzb3VyY2UnLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ251bWJlcidcclxuICAgICAgfVxyXG4gICAgfSxcclxuICAgIGNyZWF0ZVRpbWVvdXQ6IHtcclxuICAgICAgdmFsdWU6IDUwMDAsXHJcbiAgICAgIHR5cGVzOiBbJ251bWJlciddLFxyXG4gICAgICBlbnZMaW5rOiAnUE9PTF9DUkVBVEVfVElNRU9VVCcsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnVGltZW91dCBpbiBtaWxsaXNlY29uZHMgZm9yIGNyZWF0aW5nIGEgcmVzb3VyY2UnLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ251bWJlcidcclxuICAgICAgfVxyXG4gICAgfSxcclxuICAgIGRlc3Ryb3lUaW1lb3V0OiB7XHJcbiAgICAgIHZhbHVlOiA1MDAwLFxyXG4gICAgICB0eXBlczogWydudW1iZXInXSxcclxuICAgICAgZW52TGluazogJ1BPT0xfREVTVFJPWV9USU1FT1VUJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdUaW1lb3V0IGluIG1pbGxpc2Vjb25kcyBmb3IgZGVzdHJveWluZyBhIHJlc291cmNlJyxcclxuICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgIHR5cGU6ICdudW1iZXInXHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICBpZGxlVGltZW91dDoge1xyXG4gICAgICB2YWx1ZTogMzAwMDAsXHJcbiAgICAgIHR5cGVzOiBbJ251bWJlciddLFxyXG4gICAgICBlbnZMaW5rOiAnUE9PTF9JRExFX1RJTUVPVVQnLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ1RpbWVvdXQgaW4gbWlsbGlzZWNvbmRzIGZvciBkZXN0cm95aW5nIGlkbGUgcmVzb3VyY2VzJyxcclxuICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgIHR5cGU6ICdudW1iZXInXHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICBjcmVhdGVSZXRyeUludGVydmFsOiB7XHJcbiAgICAgIHZhbHVlOiAyMDAsXHJcbiAgICAgIHR5cGVzOiBbJ251bWJlciddLFxyXG4gICAgICBlbnZMaW5rOiAnUE9PTF9DUkVBVEVfUkVUUllfSU5URVJWQUwnLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnSW50ZXJ2YWwgaW4gbWlsbGlzZWNvbmRzIGJlZm9yZSByZXRyeWluZyByZXNvdXJjZSBjcmVhdGlvbiBvbiBmYWlsdXJlJyxcclxuICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgIHR5cGU6ICdudW1iZXInXHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICByZWFwZXJJbnRlcnZhbDoge1xyXG4gICAgICB2YWx1ZTogMTAwMCxcclxuICAgICAgdHlwZXM6IFsnbnVtYmVyJ10sXHJcbiAgICAgIGVudkxpbms6ICdQT09MX1JFQVBFUl9JTlRFUlZBTCcsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdJbnRlcnZhbCBpbiBtaWxsaXNlY29uZHMgdG8gY2hlY2sgYW5kIGRlc3Ryb3kgaWRsZSByZXNvdXJjZXMnLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ251bWJlcidcclxuICAgICAgfVxyXG4gICAgfSxcclxuICAgIGJlbmNobWFya2luZzoge1xyXG4gICAgICB2YWx1ZTogZmFsc2UsXHJcbiAgICAgIHR5cGVzOiBbJ2Jvb2xlYW4nXSxcclxuICAgICAgZW52TGluazogJ1BPT0xfQkVOQ0hNQVJLSU5HJyxcclxuICAgICAgY2xpTmFtZTogJ3Bvb2xCZW5jaG1hcmtpbmcnLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ1Nob3dzIHN0YXRpc3RpY3MgZm9yIHRoZSBwb29sIG9mIHJlc291cmNlcycsXHJcbiAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICB0eXBlOiAndG9nZ2xlJ1xyXG4gICAgICB9XHJcbiAgICB9XHJcbiAgfSxcclxuICBsb2dnaW5nOiB7XHJcbiAgICBsZXZlbDoge1xyXG4gICAgICB2YWx1ZTogNCxcclxuICAgICAgdHlwZXM6IFsnbnVtYmVyJ10sXHJcbiAgICAgIGVudkxpbms6ICdMT0dHSU5HX0xFVkVMJyxcclxuICAgICAgY2xpTmFtZTogJ2xvZ0xldmVsJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdMb2dnaW5nIHZlcmJvc2l0eSBsZXZlbCcsXHJcbiAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgICByb3VuZDogMCxcclxuICAgICAgICBtaW46IDAsXHJcbiAgICAgICAgbWF4OiA1XHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICBmaWxlOiB7XHJcbiAgICAgIHZhbHVlOiAnaGlnaGNoYXJ0cy1leHBvcnQtc2VydmVyLmxvZycsXHJcbiAgICAgIHR5cGVzOiBbJ3N0cmluZyddLFxyXG4gICAgICBlbnZMaW5rOiAnTE9HR0lOR19GSUxFJyxcclxuICAgICAgY2xpTmFtZTogJ2xvZ0ZpbGUnLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnTG9nIGZpbGUgbmFtZS4gUmVxdWlyZXMgYGxvZ1RvRmlsZWAgYW5kIGBsb2dEZXN0YCB0byBiZSBzZXQnLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ3RleHQnXHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICBkZXN0OiB7XHJcbiAgICAgIHZhbHVlOiAnbG9nJyxcclxuICAgICAgdHlwZXM6IFsnc3RyaW5nJ10sXHJcbiAgICAgIGVudkxpbms6ICdMT0dHSU5HX0RFU1QnLFxyXG4gICAgICBjbGlOYW1lOiAnbG9nRGVzdCcsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnUGF0aCB0byBzdG9yZSBsb2cgZmlsZXMuIFJlcXVpcmVzIGBsb2dUb0ZpbGVgIHRvIGJlIHNldCcsXHJcbiAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICB0eXBlOiAndGV4dCdcclxuICAgICAgfVxyXG4gICAgfSxcclxuICAgIHRvQ29uc29sZToge1xyXG4gICAgICB2YWx1ZTogdHJ1ZSxcclxuICAgICAgdHlwZXM6IFsnYm9vbGVhbiddLFxyXG4gICAgICBlbnZMaW5rOiAnTE9HR0lOR19UT19DT05TT0xFJyxcclxuICAgICAgY2xpTmFtZTogJ2xvZ1RvQ29uc29sZScsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnRW5hYmxlcyBvciBkaXNhYmxlcyBjb25zb2xlIGxvZ2dpbmcnLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ3RvZ2dsZSdcclxuICAgICAgfVxyXG4gICAgfSxcclxuICAgIHRvRmlsZToge1xyXG4gICAgICB2YWx1ZTogdHJ1ZSxcclxuICAgICAgdHlwZXM6IFsnYm9vbGVhbiddLFxyXG4gICAgICBlbnZMaW5rOiAnTE9HR0lOR19UT19GSUxFJyxcclxuICAgICAgY2xpTmFtZTogJ2xvZ1RvRmlsZScsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnRW5hYmxlcyBvciBkaXNhYmxlcyBsb2dnaW5nIHRvIGEgZmlsZScsXHJcbiAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICB0eXBlOiAndG9nZ2xlJ1xyXG4gICAgICB9XHJcbiAgICB9XHJcbiAgfSxcclxuICB1aToge1xyXG4gICAgZW5hYmxlOiB7XHJcbiAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgdHlwZXM6IFsnYm9vbGVhbiddLFxyXG4gICAgICBlbnZMaW5rOiAnVUlfRU5BQkxFJyxcclxuICAgICAgY2xpTmFtZTogJ2VuYWJsZVVpJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdFbmFibGVzIG9yIGRpc2FibGVzIHRoZSBVSSBmb3IgdGhlIGV4cG9ydCBzZXJ2ZXInLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ3RvZ2dsZSdcclxuICAgICAgfVxyXG4gICAgfSxcclxuICAgIHJvdXRlOiB7XHJcbiAgICAgIHZhbHVlOiAnLycsXHJcbiAgICAgIHR5cGVzOiBbJ3N0cmluZyddLFxyXG4gICAgICBlbnZMaW5rOiAnVUlfUk9VVEUnLFxyXG4gICAgICBjbGlOYW1lOiAndWlSb3V0ZScsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnVGhlIGVuZHBvaW50IHJvdXRlIGZvciB0aGUgVUknLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ3RleHQnXHJcbiAgICAgIH1cclxuICAgIH1cclxuICB9LFxyXG4gIG90aGVyOiB7XHJcbiAgICBub2RlRW52OiB7XHJcbiAgICAgIHZhbHVlOiAncHJvZHVjdGlvbicsXHJcbiAgICAgIHR5cGVzOiBbJ3N0cmluZyddLFxyXG4gICAgICBlbnZMaW5rOiAnT1RIRVJfTk9ERV9FTlYnLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ1RoZSBOb2RlLmpzIGVudmlyb25tZW50IHR5cGUnLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ3RleHQnXHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICBsaXN0ZW5Ub1Byb2Nlc3NFeGl0czoge1xyXG4gICAgICB2YWx1ZTogdHJ1ZSxcclxuICAgICAgdHlwZXM6IFsnYm9vbGVhbiddLFxyXG4gICAgICBlbnZMaW5rOiAnT1RIRVJfTElTVEVOX1RPX1BST0NFU1NfRVhJVFMnLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ1doZXRoZXIgb3Igbm90IHRvIGF0dGFjaCBwcm9jZXNzLmV4aXQgaGFuZGxlcnMnLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ3RvZ2dsZSdcclxuICAgICAgfVxyXG4gICAgfSxcclxuICAgIG5vTG9nbzoge1xyXG4gICAgICB2YWx1ZTogZmFsc2UsXHJcbiAgICAgIHR5cGVzOiBbJ2Jvb2xlYW4nXSxcclxuICAgICAgZW52TGluazogJ09USEVSX05PX0xPR08nLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ0Rpc3BsYXkgb3Igc2tpcCBwcmludGluZyB0aGUgbG9nbyBvbiBzdGFydHVwJyxcclxuICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgIHR5cGU6ICd0b2dnbGUnXHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICBoYXJkUmVzZXRQYWdlOiB7XHJcbiAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgdHlwZXM6IFsnYm9vbGVhbiddLFxyXG4gICAgICBlbnZMaW5rOiAnT1RIRVJfSEFSRF9SRVNFVF9QQUdFJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdXaGV0aGVyIG9yIG5vdCB0byByZXNldCB0aGUgcGFnZSBjb250ZW50IGVudGlyZWx5JyxcclxuICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgIHR5cGU6ICd0b2dnbGUnXHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICBicm93c2VyU2hlbGxNb2RlOiB7XHJcbiAgICAgIHZhbHVlOiB0cnVlLFxyXG4gICAgICB0eXBlczogWydib29sZWFuJ10sXHJcbiAgICAgIGVudkxpbms6ICdPVEhFUl9CUk9XU0VSX1NIRUxMX01PREUnLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ1doZXRoZXIgb3Igbm90IHRvIHNldCB0aGUgYnJvd3NlciB0byBydW4gaW4gc2hlbGwgbW9kZScsXHJcbiAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICB0eXBlOiAndG9nZ2xlJ1xyXG4gICAgICB9XHJcbiAgICB9LFxyXG4gICAgdmFsaWRhdGlvbjoge1xyXG4gICAgICB2YWx1ZTogdHJ1ZSxcclxuICAgICAgdHlwZXM6IFsnYm9vbGVhbiddLFxyXG4gICAgICBlbnZMaW5rOiAnT1RIRVJfVkFMSURBVElPTicsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnV2hldGhlciBvciBub3QgdG8gZW5hYmxlIHZhbGlkYXRpb24gb2Ygb3B0aW9ucyB0eXBlcycsXHJcbiAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICB0eXBlOiAndG9nZ2xlJ1xyXG4gICAgICB9XHJcbiAgICB9XHJcbiAgfSxcclxuICBkZWJ1Zzoge1xyXG4gICAgZW5hYmxlOiB7XHJcbiAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgdHlwZXM6IFsnYm9vbGVhbiddLFxyXG4gICAgICBlbnZMaW5rOiAnREVCVUdfRU5BQkxFJyxcclxuICAgICAgY2xpTmFtZTogJ2VuYWJsZURlYnVnJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdFbmFibGVzIG9yIGRpc2FibGVzIGRlYnVnIG1vZGUgZm9yIHRoZSB1bmRlcmx5aW5nIGJyb3dzZXInLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ3RvZ2dsZSdcclxuICAgICAgfVxyXG4gICAgfSxcclxuICAgIGhlYWRsZXNzOiB7XHJcbiAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgdHlwZXM6IFsnYm9vbGVhbiddLFxyXG4gICAgICBlbnZMaW5rOiAnREVCVUdfSEVBRExFU1MnLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnV2hldGhlciBvciBub3QgdG8gc2V0IHRoZSBicm93c2VyIHRvIHJ1biBpbiBoZWFkbGVzcyBtb2RlIGR1cmluZyBkZWJ1Z2dpbmcnLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ3RvZ2dsZSdcclxuICAgICAgfVxyXG4gICAgfSxcclxuICAgIGRldnRvb2xzOiB7XHJcbiAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgdHlwZXM6IFsnYm9vbGVhbiddLFxyXG4gICAgICBlbnZMaW5rOiAnREVCVUdfREVWVE9PTFMnLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ0VuYWJsZXMgb3IgZGlzYWJsZXMgRGV2VG9vbHMgaW4gaGVhZGZ1bCBtb2RlJyxcclxuICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgIHR5cGU6ICd0b2dnbGUnXHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICBsaXN0ZW5Ub0NvbnNvbGU6IHtcclxuICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICB0eXBlczogWydib29sZWFuJ10sXHJcbiAgICAgIGVudkxpbms6ICdERUJVR19MSVNURU5fVE9fQ09OU09MRScsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdFbmFibGVzIG9yIGRpc2FibGVzIGxpc3RlbmluZyB0byBjb25zb2xlIG1lc3NhZ2VzIGZyb20gdGhlIGJyb3dzZXInLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ3RvZ2dsZSdcclxuICAgICAgfVxyXG4gICAgfSxcclxuICAgIGR1bXBpbzoge1xyXG4gICAgICB2YWx1ZTogZmFsc2UsXHJcbiAgICAgIHR5cGVzOiBbJ2Jvb2xlYW4nXSxcclxuICAgICAgZW52TGluazogJ0RFQlVHX0RVTVBJTycsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdSZWRpcmVjdHMgb3Igbm90IGJyb3dzZXIgc3Rkb3V0IGFuZCBzdGRlcnIgdG8gcHJvY2Vzcy5zdGRvdXQgYW5kIHByb2Nlc3Muc3RkZXJyJyxcclxuICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgIHR5cGU6ICd0b2dnbGUnXHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICBzbG93TW86IHtcclxuICAgICAgdmFsdWU6IDAsXHJcbiAgICAgIHR5cGVzOiBbJ251bWJlciddLFxyXG4gICAgICBlbnZMaW5rOiAnREVCVUdfU0xPV19NTycsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnRGVsYXlzIFB1cHBldGVlciBvcGVyYXRpb25zIGJ5IHRoZSBzcGVjaWZpZWQgbWlsbGlzZWNvbmRzJyxcclxuICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgIHR5cGU6ICdudW1iZXInXHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICBkZWJ1Z2dpbmdQb3J0OiB7XHJcbiAgICAgIHZhbHVlOiA5MjIyLFxyXG4gICAgICB0eXBlczogWydudW1iZXInXSxcclxuICAgICAgZW52TGluazogJ0RFQlVHX0RFQlVHR0lOR19QT1JUJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdQb3J0IHVzZWQgZm9yIGRlYnVnZ2luZycsXHJcbiAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICB0eXBlOiAnbnVtYmVyJ1xyXG4gICAgICB9XHJcbiAgICB9XHJcbiAgfVxyXG59O1xyXG5cclxuLy8gUHJvcGVydGllcyBuZXN0aW5nIGxldmVsIG9mIGFsbCBvcHRpb25zXHJcbmV4cG9ydCBjb25zdCBuZXN0ZWRQcm9wcyA9IF9jcmVhdGVOZXN0ZWRQcm9wcyhkZWZhdWx0Q29uZmlnKTtcclxuXHJcbi8vIFByb3BlcnRpZXMgbmFtZXMgdGhhdCBzaG91bGQgbm90IGJlIHJlY3Vyc2l2ZWx5IG1lcmdlZFxyXG5leHBvcnQgY29uc3QgYWJzb2x1dGVQcm9wcyA9IF9jcmVhdGVBYnNvbHV0ZVByb3BzKGRlZmF1bHRDb25maWcpO1xyXG5cclxuLyoqXHJcbiAqIFJlY3Vyc2l2ZWx5IGdlbmVyYXRlcyBhIG1hcHBpbmcgb2YgbmVzdGVkIGFyZ3VtZW50IGNoYWlucyBmcm9tIGEgbmVzdGVkXHJcbiAqIGNvbmZpZyBvYmplY3QuIFRoaXMgZnVuY3Rpb24gdHJhdmVyc2VzIGEgbmVzdGVkIG9iamVjdCBhbmQgY3JlYXRlcyBhIG1hcHBpbmdcclxuICogd2hlcmUgZWFjaCBrZXkgaXMgYW4gYXJndW1lbnQgbmFtZSAoZWl0aGVyIGZyb20gYGNsaU5hbWVgLCBgbGVnYWN5TmFtZWAsXHJcbiAqIG9yIHRoZSBvcmlnaW5hbCBrZXkpIGFuZCBlYWNoIHZhbHVlIGlzIGEgc3RyaW5nIHJlcHJlc2VudGluZyB0aGUgY2hhaW5cclxuICogb2YgbmVzdGVkIHByb3BlcnRpZXMgbGVhZGluZyB0byB0aGF0IGFyZ3VtZW50LlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gX2NyZWF0ZU5lc3RlZFByb3BzXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBjb25maWcgLSBUaGUgY29uZmlndXJhdGlvbiBvYmplY3QuXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBbbmVzdGVkUHJvcHM9e31dIC0gVGhlIGFjY3VtdWxhdG9yIG9iamVjdCBmb3Igc3RvcmluZ1xyXG4gKiB0aGUgcmVzdWx0aW5nIGFyZ3VtZW50cyBjaGFpbnMuICBUaGUgZGVmYXVsdCB2YWx1ZSBpcyBhbiBlbXB0eSBvYmplY3QuXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSBbcHJvcENoYWluPScnXSAtIFRoZSBjdXJyZW50IGNoYWluIG9mIG5lc3RlZCBwcm9wZXJ0aWVzLFxyXG4gKiB1c2VkIGludGVybmFsbHkgZHVyaW5nIHJlY3Vyc2lvbi4gIFRoZSBkZWZhdWx0IHZhbHVlIGlzIGFuIGVtcHR5IHN0cmluZy5cclxuICpcclxuICogQHJldHVybnMge09iamVjdH0gQW4gb2JqZWN0IG1hcHBpbmcgYXJndW1lbnQgbmFtZXMgdG8gdGhlaXIgY29ycmVzcG9uZGluZ1xyXG4gKiBuZXN0ZWQgcHJvcGVydHkgY2hhaW5zLlxyXG4gKi9cclxuZnVuY3Rpb24gX2NyZWF0ZU5lc3RlZFByb3BzKGNvbmZpZywgbmVzdGVkUHJvcHMgPSB7fSwgcHJvcENoYWluID0gJycpIHtcclxuICBPYmplY3Qua2V5cyhjb25maWcpLmZvckVhY2goKGtleSkgPT4ge1xyXG4gICAgLy8gR2V0IHRoZSBzcGVjaWZpYyBzZWN0aW9uXHJcbiAgICBjb25zdCBlbnRyeSA9IGNvbmZpZ1trZXldO1xyXG5cclxuICAgIC8vIENoZWNrIGlmIHRoZXJlIGlzIHN0aWxsIG1vcmUgZGVwdGggdG8gdHJhdmVyc2VcclxuICAgIGlmICh0eXBlb2YgZW50cnkudmFsdWUgPT09ICd1bmRlZmluZWQnKSB7XHJcbiAgICAgIC8vIFJlY3Vyc2UgaW50byBkZWVwZXIgbGV2ZWxzIG9mIG5lc3RlZCBhcmd1bWVudHNcclxuICAgICAgX2NyZWF0ZU5lc3RlZFByb3BzKGVudHJ5LCBuZXN0ZWRQcm9wcywgYCR7cHJvcENoYWlufS4ke2tleX1gKTtcclxuICAgIH0gZWxzZSB7XHJcbiAgICAgIC8vIENyZWF0ZSB0aGUgY2hhaW4gb2YgbmVzdGVkIGFyZ3VtZW50c1xyXG4gICAgICBuZXN0ZWRQcm9wc1tlbnRyeS5jbGlOYW1lIHx8IGtleV0gPSBgJHtwcm9wQ2hhaW59LiR7a2V5fWAuc3Vic3RyaW5nKDEpO1xyXG5cclxuICAgICAgLy8gU3VwcG9ydCBmb3IgdGhlIGxlZ2FjeSwgUGhhbnRvbUpTIHByb3BlcnRpZXMgbmFtZXNcclxuICAgICAgaWYgKGVudHJ5LmxlZ2FjeU5hbWUgIT09IHVuZGVmaW5lZCkge1xyXG4gICAgICAgIG5lc3RlZFByb3BzW2VudHJ5LmxlZ2FjeU5hbWVdID0gYCR7cHJvcENoYWlufS4ke2tleX1gLnN1YnN0cmluZygxKTtcclxuICAgICAgfVxyXG4gICAgfVxyXG4gIH0pO1xyXG5cclxuICAvLyBSZXR1cm4gdGhlIG9iamVjdCB3aXRoIG5lc3RlZCBhcmd1bWVudCBjaGFpbnNcclxuICByZXR1cm4gbmVzdGVkUHJvcHM7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBSZWN1cnNpdmVseSBnYXRoZXJzIHRoZSBuYW1lcyBvZiBwcm9wZXJ0aWVzIGZyb20gYSBjb25maWd1cmF0aW9uIG9iamVjdCB0aGF0XHJcbiAqIGNhbiBiZSB0cmVhdGVkIGFzIGFic29sdXRlIHByb3BlcnRpZXMuIFRoZXNlIHByb3BlcnRpZXMgaGF2ZSB2YWx1ZXMgdGhhdFxyXG4gKiBhcmUgb2JqZWN0cyBhbmQgZG8gbm90IGNvbnRhaW4gZnVydGhlciBuZXN0ZWQgZGVwdGggd2hlbiBtZXJnaW5nIGFuIG9iamVjdFxyXG4gKiBjb250YWluaW5nIHRoZXNlIG9wdGlvbnMuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBfY3JlYXRlQWJzb2x1dGVQcm9wc1xyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gY29uZmlnIC0gVGhlIGNvbmZpZ3VyYXRpb24gb2JqZWN0LlxyXG4gKiBAcGFyYW0ge0FycmF5LjxzdHJpbmc+fSBbYWJzb2x1dGVQcm9wcz1bXV0gLSBBbiBhcnJheSB0byBjb2xsZWN0IHRoZSBuYW1lc1xyXG4gKiBvZiBhYnNvbHV0ZSBwcm9wZXJ0aWVzLiBUaGUgZGVmYXVsdCB2YWx1ZSBpcyBhbiBlbXB0eSBhcnJheS5cclxuICpcclxuICogQHJldHVybnMge0FycmF5LjxzdHJpbmc+fSBBbiBhcnJheSBjb250YWluaW5nIHRoZSBuYW1lcyBvZiBhYnNvbHV0ZVxyXG4gKiBwcm9wZXJ0aWVzLlxyXG4gKi9cclxuZnVuY3Rpb24gX2NyZWF0ZUFic29sdXRlUHJvcHMoY29uZmlnLCBhYnNvbHV0ZVByb3BzID0gW10pIHtcclxuICBPYmplY3Qua2V5cyhjb25maWcpLmZvckVhY2goKGtleSkgPT4ge1xyXG4gICAgLy8gR2V0IHRoZSBzcGVjaWZpYyBzZWN0aW9uXHJcbiAgICBjb25zdCBlbnRyeSA9IGNvbmZpZ1trZXldO1xyXG5cclxuICAgIC8vIENoZWNrIGlmIHRoZXJlIGlzIHN0aWxsIG1vcmUgZGVwdGggdG8gdHJhdmVyc2VcclxuICAgIGlmICh0eXBlb2YgZW50cnkudHlwZXMgPT09ICd1bmRlZmluZWQnKSB7XHJcbiAgICAgIC8vIFJlY3Vyc2UgaW50byBkZWVwZXIgbGV2ZWxzXHJcbiAgICAgIF9jcmVhdGVBYnNvbHV0ZVByb3BzKGVudHJ5LCBhYnNvbHV0ZVByb3BzKTtcclxuICAgIH0gZWxzZSB7XHJcbiAgICAgIC8vIElmIHRoZSBvcHRpb24gY2FuIGJlIGFuIG9iamVjdCwgc2F2ZSBpdHMgdHlwZSBpbiB0aGUgYXJyYXlcclxuICAgICAgaWYgKGVudHJ5LnR5cGVzLmluY2x1ZGVzKCdPYmplY3QnKSkge1xyXG4gICAgICAgIGFic29sdXRlUHJvcHMucHVzaChrZXkpO1xyXG4gICAgICB9XHJcbiAgICB9XHJcbiAgfSk7XHJcblxyXG4gIC8vIFJldHVybiB0aGUgYXJyYXkgd2l0aCB0aGUgbmFtZXMgb2YgYWJzb2x1dGUgcHJvcGVydGllc1xyXG4gIHJldHVybiBhYnNvbHV0ZVByb3BzO1xyXG59XHJcblxyXG5leHBvcnQgZGVmYXVsdCB7XHJcbiAgZGVmYXVsdENvbmZpZyxcclxuICBuZXN0ZWRQcm9wcyxcclxuICBhYnNvbHV0ZVByb3BzXHJcbn07XHJcbiIsIi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXHJcblxyXG5IaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXJcclxuXHJcbkNvcHlyaWdodCAoYykgMjAxNi0yMDI1LCBIaWdoc29mdFxyXG5cclxuTGljZW5jZWQgdW5kZXIgdGhlIE1JVCBsaWNlbmNlLlxyXG5cclxuQWRkaXRpb25hbGx5IGEgdmFsaWQgSGlnaGNoYXJ0cyBsaWNlbnNlIGlzIHJlcXVpcmVkIGZvciB1c2UuXHJcblxyXG5TZWUgTElDRU5TRSBmaWxlIGluIHJvb3QgZm9yIGRldGFpbHMuXHJcblxyXG4qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xyXG5cclxuLyoqXHJcbiAqIEBvdmVydmlldyBUaGlzIGZpbGUgaGFuZGxlcyBwYXJzaW5nIGFuZCB2YWxpZGF0aW5nIG9wdGlvbnMgZnJvbSBtdWx0aXBsZVxyXG4gKiBzb3VyY2VzICh0aGUgY29uZmlnIGZpbGUsIGN1c3RvbSBKU09OLCBlbnZpcm9ubWVudCB2YXJpYWJsZXMsIENMSSBhcmd1bWVudHMsXHJcbiAqIGFuZCByZXF1ZXN0IHBheWxvYWQpIHVzaW5nIHRoZSAnem9kJyBsaWJyYXJ5LlxyXG4gKlxyXG4gKiBFbnZpcm9ubWVudCB2YXJpYWJsZXMgYXJlIHBhcnNlZCBhbmQgdmFsaWRhdGVkIG9ubHkgb25jZSBhdCBhcHBsaWNhdGlvblxyXG4gKiBzdGFydHVwLCBhbmQgdGhlIHZhbGlkYXRlZCByZXN1bHRzIGFyZSBleHBvcnRlZCBhcyBgZW52c2AgZm9yIHVzZSB0aHJvdWdob3V0XHJcbiAqIHRoZSBhcHBsaWNhdGlvbi5cclxuICpcclxuICogT3B0aW9ucyBmcm9tIG90aGVyIHNvdXJjZXMsIGhvd2V2ZXIsIGFyZSBwYXJzZWQgYW5kIHZhbGlkYXRlZCBvbiBkZW1hbmQsXHJcbiAqIGVhY2ggdGltZSBhbiBleHBvcnQgaXMgYXR0ZW1wdGVkLlxyXG4gKi9cclxuXHJcbmltcG9ydCBkb3RlbnYgZnJvbSAnZG90ZW52JztcclxuaW1wb3J0IHsgeiB9IGZyb20gJ3pvZCc7XHJcblxyXG5pbXBvcnQgeyBkZWZhdWx0Q29uZmlnIH0gZnJvbSAnLi9zY2hlbWFzL2NvbmZpZy5qcyc7XHJcblxyXG4vLyBMb2FkIHRoZSAuZW52IGludG8gZW52aXJvbm1lbnQgdmFyaWFibGVzXHJcbmRvdGVudi5jb25maWcoKTtcclxuXHJcbi8vIEdldCBzY3JpcHRzIG5hbWVzIG9mIGVhY2ggY2F0ZWdvcnkgZnJvbSB0aGUgZGVmYXVsdCBjb25maWdcclxuY29uc3QgeyBjb3JlU2NyaXB0cywgbW9kdWxlU2NyaXB0cywgaW5kaWNhdG9yU2NyaXB0cyB9ID1cclxuICBkZWZhdWx0Q29uZmlnLmhpZ2hjaGFydHM7XHJcblxyXG4vLyBTZXRzIHRoZSBjdXN0b20gZXJyb3IgbWFwIGdsb2JhbGx5XHJcbnouc2V0RXJyb3JNYXAoX2N1c3RvbUVycm9yTWFwKTtcclxuXHJcbi8qKlxyXG4gKiBPYmplY3QgY29udGFpbmluZyBjdXN0b20gZ2VuZXJhbCB2YWxpZGF0b3JzIGFuZCBwYXJzZXJzIHRvIGF2b2lkIHJlcGV0aXRpb25cclxuICogaW4gc2NoZW1hIG9iamVjdHMuIEFsbCB2YWxpZGF0b3JzIGFwcGx5IHRvIHZhbHVlcyBmcm9tIHZhcmlvdXMgc291cmNlcyxcclxuICogaW5jbHVkaW5nIHRoZSBkZWZhdWx0IGNvbmZpZyBmaWxlLCBhIGN1c3RvbSBKU09OIGZpbGUgbG9hZGVkIHdpdGggdGhlIG9wdGlvblxyXG4gKiBjYWxsZWQgYGxvYWRDb25maWdgLCB0aGUgLmVudiBmaWxlLCBDTEkgYXJndW1lbnRzLCBhbmQgdGhlIHJlcXVlc3QgcGF5bG9hZC5cclxuICogVGhlIGBzdHJpY3RDaGVja2AgZmxhZyBlbmFibGVzIHN0cmljdGVyIHZhbGlkYXRpb24gYW5kIHBhcnNpbmcgcnVsZXMuIFRoaXNcclxuICogZmxhZyBpcyBzZXQgdG8gZmFsc2UgZm9yIHZhbHVlcyB0aGF0IGNvbWUgZnJvbSB0aGUgLmVudiBmaWxlIG9yIENMSSBhcmd1bWVudHNcclxuICogYmVjYXVzZSB0aGV5IGFyZSBwcm92aWRlZCBhcyBzdHJpbmdzIGFuZCBuZWVkIHRvIGJlIHBhcnNlZCBhY2NvcmRpbmdseSBmaXJzdC5cclxuICovXHJcbmNvbnN0IHYgPSB7XHJcbiAgLyoqXHJcbiAgICogVGhlIGBib29sZWFuYCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoIGFuIG9wdGlvbmFsIHN0cmljdGVyXHJcbiAgICogY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhhdDpcclxuICAgKlxyXG4gICAqIC0gV2hlbiBgc3RyaWN0Q2hlY2tgIGlzIHRydWUsIHRoZSBzY2hlbWEgd2lsbCBhY2NlcHQgdmFsdWVzIGFyZSB0cnVlXHJcbiAgICogYW5kIGZhbHNlIGFuZCB0aGUgc2NoZW1hIHdpbGwgdmFsaWRhdGUgYWdhaW5zdCB0aGUgZGVmYXVsdCBib29sZWFuXHJcbiAgICogdmFsaWRhdG9yLlxyXG4gICAqXHJcbiAgICogLSBXaGVuIGBzdHJpY3RDaGVja2AgaXMgZmFsc2UsIHRoZSBzY2hlbWEgd2lsbCBhY2NlcHQgdmFsdWVzIGFyZSB0cnVlLFxyXG4gICAqIGZhbHNlLCBudWxsLCAndHJ1ZScsICcxJywgJ2ZhbHNlJywgJzAnLCAndW5kZWZpbmVkJywgJ251bGwnLCBhbmQgJycuXHJcbiAgICogVGhlIHN0cmluZ3MgJ3VuZGVmaW5lZCcsICdudWxsJywgYW5kICcnIHdpbGwgYmUgdHJhbnNmb3JtZWQgdG8gbnVsbCxcclxuICAgKiB0aGUgc3RyaW5nICd0cnVlJyB3aWxsIGJlIHRyYW5zZm9ybWVkIHRvIHRoZSBib29sZWFuIHZhbHVlIHRydWUsXHJcbiAgICogYW5kICdmYWxzZScgd2lsbCBiZSB0cmFuc2Zvcm1lZCB0byB0aGUgYm9vbGVhbiB2YWx1ZSBmYWxzZS5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiBib29sZWFuXHJcbiAgICpcclxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IHN0cmljdENoZWNrIC0gRGV0ZXJtaW5lcyBpZiBzdHJpY3RlciB2YWxpZGF0aW9uIHNob3VsZFxyXG4gICAqIGJlIGFwcGxpZWQuXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9IEEgWm9kIHNjaGVtYSBvYmplY3QgZm9yIHZhbGlkYXRpbmcgYm9vbGVhbiB2YWx1ZXMuXHJcbiAgICovXHJcbiAgYm9vbGVhbihzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHN0cmljdENoZWNrXHJcbiAgICAgID8gei5ib29sZWFuKClcclxuICAgICAgOiB6XHJcbiAgICAgICAgICAudW5pb24oW1xyXG4gICAgICAgICAgICB6XHJcbiAgICAgICAgICAgICAgLmVudW0oWyd0cnVlJywgJzEnLCAnZmFsc2UnLCAnMCcsICd1bmRlZmluZWQnLCAnbnVsbCcsICcnXSlcclxuICAgICAgICAgICAgICAudHJhbnNmb3JtKCh2YWx1ZSkgPT5cclxuICAgICAgICAgICAgICAgICFbJ3VuZGVmaW5lZCcsICdudWxsJywgJyddLmluY2x1ZGVzKHZhbHVlKVxyXG4gICAgICAgICAgICAgICAgICA/IHZhbHVlID09PSAndHJ1ZScgfHwgdmFsdWUgPT09ICcxJ1xyXG4gICAgICAgICAgICAgICAgICA6IG51bGxcclxuICAgICAgICAgICAgICApLFxyXG4gICAgICAgICAgICB6LmJvb2xlYW4oKVxyXG4gICAgICAgICAgXSlcclxuICAgICAgICAgIC5udWxsYWJsZSgpO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgc3RyaW5nYCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoIGFuIG9wdGlvbmFsIHN0cmljdGVyXHJcbiAgICogY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhhdDpcclxuICAgKlxyXG4gICAqIC0gV2hlbiBgc3RyaWN0Q2hlY2tgIGlzIHRydWUsIHRoZSBzY2hlbWEgd2lsbCBhY2NlcHQgdHJpbW1lZCBzdHJpbmdzIGV4Y2VwdFxyXG4gICAqIHRoZSBmb3JiaWRkZW4gdmFsdWVzOiAnZmFsc2UnLCAndW5kZWZpbmVkJywgJ251bGwnLCBhbmQgJycuXHJcbiAgICpcclxuICAgKiAtIFdoZW4gYHN0cmljdENoZWNrYCBpcyBmYWxzZSwgdGhlIHNjaGVtYSB3aWxsIGFjY2VwdCB0cmltbWVkIHN0cmluZ3NcclxuICAgKiBhbmQgbnVsbC4gVGhlIGZvcmJpZGRlbiB2YWx1ZXM6ICdmYWxzZScsICd1bmRlZmluZWQnLCAnbnVsbCcsIGFuZCAnJyB3aWxsXHJcbiAgICogYmUgdHJhbnNmb3JtZWQgdG8gbnVsbC5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiBzdHJpbmdcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZyBzdHJpbmcgdmFsdWVzLlxyXG4gICAqL1xyXG4gIHN0cmluZyhzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHN0cmljdENoZWNrXHJcbiAgICAgID8gelxyXG4gICAgICAgICAgLnN0cmluZygpXHJcbiAgICAgICAgICAudHJpbSgpXHJcbiAgICAgICAgICAucmVmaW5lKFxyXG4gICAgICAgICAgICAodmFsdWUpID0+ICFbJ2ZhbHNlJywgJ3VuZGVmaW5lZCcsICdudWxsJywgJyddLmluY2x1ZGVzKHZhbHVlKSxcclxuICAgICAgICAgICAge1xyXG4gICAgICAgICAgICAgIHBhcmFtczoge1xyXG4gICAgICAgICAgICAgICAgZXJyb3JNZXNzYWdlOiAnVGhlIHN0cmluZyBjb250YWlucyBhIGZvcmJpZGRlbiB2YWx1ZSdcclxuICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgIH1cclxuICAgICAgICAgIClcclxuICAgICAgOiB6XHJcbiAgICAgICAgICAuc3RyaW5nKClcclxuICAgICAgICAgIC50cmltKClcclxuICAgICAgICAgIC50cmFuc2Zvcm0oKHZhbHVlKSA9PlxyXG4gICAgICAgICAgICAhWydmYWxzZScsICd1bmRlZmluZWQnLCAnbnVsbCcsICcnXS5pbmNsdWRlcyh2YWx1ZSkgPyB2YWx1ZSA6IG51bGxcclxuICAgICAgICAgIClcclxuICAgICAgICAgIC5udWxsYWJsZSgpO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgZW51bWAgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbCBzdHJpY3RlclxyXG4gICAqIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSBzY2hlbWEgd2lsbCB2YWxpZGF0ZSBhZ2FpbnN0IHRoZSBwcm92aWRlZCBgdmFsdWVzYCBhcnJheS5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoYXQ6XHJcbiAgICpcclxuICAgKiAtIFdoZW4gYHN0cmljdENoZWNrYCBpcyB0cnVlLCB0aGUgc2NoZW1hIHdpbGwgdmFsaWRhdGUgYWdhaW5zdCB0aGUgYHZhbHVlc2BcclxuICAgKiBhcnJheSB3aXRoIHRoZSBkZWZhdWx0IGVudW0gdmFsaWRhdG9yLlxyXG4gICAqXHJcbiAgICogLSBXaGVuIGBzdHJpY3RDaGVja2AgaXMgZmFsc2UsIHRoZSBzY2hlbWEgd2lsbCBhY2NlcHQgYWxzbyBudWxsLFxyXG4gICAqICd1bmRlZmluZWQnLCAnbnVsbCcsIGFuZCAnJywgd2hpY2ggd2lsbCBiZSB0cmFuc2Zvcm1lZCB0byBudWxsLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIGVudW1cclxuICAgKlxyXG4gICAqIEBwYXJhbSB7QXJyYXkuPHN0cmluZz59IHZhbHVlcyAtIEFuIGFycmF5IG9mIHZhbGlkIHN0cmluZyB2YWx1ZXNcclxuICAgKiBmb3IgdGhlIGVudW0uXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nIGVudW0gdmFsdWVzLlxyXG4gICAqL1xyXG4gIGVudW0odmFsdWVzLCBzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHN0cmljdENoZWNrXHJcbiAgICAgID8gei5lbnVtKFsuLi52YWx1ZXNdKVxyXG4gICAgICA6IHpcclxuICAgICAgICAgIC5lbnVtKFsuLi52YWx1ZXMsICd1bmRlZmluZWQnLCAnbnVsbCcsICcnXSlcclxuICAgICAgICAgIC50cmFuc2Zvcm0oKHZhbHVlKSA9PlxyXG4gICAgICAgICAgICAhWyd1bmRlZmluZWQnLCAnbnVsbCcsICcnXS5pbmNsdWRlcyh2YWx1ZSkgPyB2YWx1ZSA6IG51bGxcclxuICAgICAgICAgIClcclxuICAgICAgICAgIC5udWxsYWJsZSgpO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgc3RyaW5nQXJyYXlgIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGggYW4gb3B0aW9uYWxcclxuICAgKiBzdHJpY3RlciBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGF0OlxyXG4gICAqXHJcbiAgICogLSBXaGVuIGBzdHJpY3RDaGVja2AgaXMgdHJ1ZSwgdGhlIHNjaGVtYSB3aWxsIGFjY2VwdCBhbiBhcnJheSBvZiB0cmltbWVkXHJcbiAgICogc3RyaW5nIHZhbHVlcyBmaWx0ZXJlZCBieSB0aGUgbG9naWMgcHJvdmlkZWQgdGhyb3VnaCB0aGUgYGZpbHRlckNhbGxiYWNrYC5cclxuICAgKlxyXG4gICAqIC0gV2hlbiBgc3RyaWN0Q2hlY2tgIGlzIGZhbHNlLCB0aGUgc2NoZW1hIHdpbGwgYWNjZXB0IG51bGwgYW5kIHRyaW1tZWRcclxuICAgKiBzdHJpbmcgdmFsdWVzIHdoaWNoIHdpbGwgYmUgc3BsaXR0ZWQgaW50byBhbiBhcnJheSBvZiBzdHJpbmdzIGFuZCBmaWx0ZXJlZFxyXG4gICAqIGZyb20gdGhlICdbJyBhbmQgJ10nIGNoYXJhY3RlcnMgYW5kIGJ5IHRoZSBsb2dpYyBwcm92aWRlZCB0aHJvdWdoXHJcbiAgICogdGhlIGBmaWx0ZXJDYWxsYmFja2AuIElmIHRoZSBhcnJheSBpcyBlbXB0eSwgaXQgd2lsbCBiZSB0cmFuc2Zvcm1lZFxyXG4gICAqIHRvIG51bGwuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gc3RyaW5nQXJyYXlcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7ZnVuY3Rpb259IGZpbHRlckNhbGxiYWNrIC0gVGhlIGZpbHRlciBjYWxsYmFjay5cclxuICAgKiBAcGFyYW0ge3N0cmluZ30gc2VwYXJhdG9yIC0gVGhlIHNlcGFyYXRvciBmb3Igc3BsaXRpbmcgYSBzdHJpbmcuXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nIGFycmF5IG9mIHN0cmluZ1xyXG4gICAqIHZhbHVlcy5cclxuICAgKi9cclxuICBzdHJpbmdBcnJheShmaWx0ZXJDYWxsYmFjaywgc2VwYXJhdG9yLCBzdHJpY3RDaGVjaykge1xyXG4gICAgY29uc3QgYXJyYXlTY2hlbWEgPSB6LnN0cmluZygpLnRyaW0oKS5hcnJheSgpO1xyXG4gICAgY29uc3Qgc3RyaW5nU2NoZW1hID0gelxyXG4gICAgICAuc3RyaW5nKClcclxuICAgICAgLnRyaW0oKVxyXG4gICAgICAudHJhbnNmb3JtKCh2YWx1ZSkgPT4ge1xyXG4gICAgICAgIGlmICh2YWx1ZS5zdGFydHNXaXRoKCdbJykpIHtcclxuICAgICAgICAgIHZhbHVlID0gdmFsdWUuc2xpY2UoMSk7XHJcbiAgICAgICAgfVxyXG4gICAgICAgIGlmICh2YWx1ZS5lbmRzV2l0aCgnXScpKSB7XHJcbiAgICAgICAgICB2YWx1ZSA9IHZhbHVlLnNsaWNlKDAsIC0xKTtcclxuICAgICAgICB9XHJcbiAgICAgICAgcmV0dXJuIHZhbHVlLnNwbGl0KHNlcGFyYXRvcik7XHJcbiAgICAgIH0pO1xyXG5cclxuICAgIGNvbnN0IHRyYW5zZm9ybUNhbGxiYWNrID0gKHZhbHVlKSA9PlxyXG4gICAgICB2YWx1ZS5tYXAoKHZhbHVlKSA9PiB2YWx1ZS50cmltKCkpLmZpbHRlcihmaWx0ZXJDYWxsYmFjayk7XHJcblxyXG4gICAgcmV0dXJuIHN0cmljdENoZWNrXHJcbiAgICAgID8gYXJyYXlTY2hlbWEudHJhbnNmb3JtKHRyYW5zZm9ybUNhbGxiYWNrKVxyXG4gICAgICA6IHpcclxuICAgICAgICAgIC51bmlvbihbc3RyaW5nU2NoZW1hLCBhcnJheVNjaGVtYV0pXHJcbiAgICAgICAgICAudHJhbnNmb3JtKHRyYW5zZm9ybUNhbGxiYWNrKVxyXG4gICAgICAgICAgLnRyYW5zZm9ybSgodmFsdWUpID0+ICh2YWx1ZS5sZW5ndGggPyB2YWx1ZSA6IG51bGwpKVxyXG4gICAgICAgICAgLm51bGxhYmxlKCk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGBwb3NpdGl2ZU51bWAgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbFxyXG4gICAqIHN0cmljdGVyIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoYXQ6XHJcbiAgICpcclxuICAgKiAtIFdoZW4gYHN0cmljdENoZWNrYCBpcyB0cnVlLCB0aGUgc2NoZW1hIHdpbGwgYWNjZXB0IHBvc2l0aXZlIG51bWJlciB2YWx1ZXNcclxuICAgKiBhbmQgdmFsaWRhdGUgYWdhaW5zdCB0aGUgZGVmYXVsdCBwb3NpdGl2ZSBudW1iZXIgdmFsaWRhdG9yLlxyXG4gICAqXHJcbiAgICogLSBXaGVuIGBzdHJpY3RDaGVja2AgaXMgZmFsc2UsIHRoZSBzY2hlbWEgd2lsbCBhY2NlcHQgcG9zaXRpdmUgbnVtYmVyXHJcbiAgICogdmFsdWVzLCBudWxsLCBhbmQgdHJpbW1lZCBzdHJpbmcgdmFsdWVzIHRoYXQgY2FuIGVpdGhlciBiZSAndW5kZWZpbmVkJyxcclxuICAgKiAnbnVsbCcsICcnLCBvciByZXByZXNlbnQgYSBwb3NpdGl2ZSBudW1iZXIuIEl0IHdpbGwgdHJhbnNmb3JtIHRoZSBzdHJpbmdcclxuICAgKiB0byBhIHBvc2l0aXZlIG51bWJlciwgb3IgdG8gbnVsbCBpZiBpdCBpcyAndW5kZWZpbmVkJywgJ251bGwnLCBvciAnJy5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiBwb3NpdGl2ZU51bVxyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nIHBvc2l0aXZlIG51bWJlclxyXG4gICAqIHZhbHVlcy5cclxuICAgKi9cclxuICBwb3NpdGl2ZU51bShzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHN0cmljdENoZWNrXHJcbiAgICAgID8gei5udW1iZXIoKS5wb3NpdGl2ZSgpXHJcbiAgICAgIDogelxyXG4gICAgICAgICAgLnVuaW9uKFtcclxuICAgICAgICAgICAgelxyXG4gICAgICAgICAgICAgIC5zdHJpbmcoKVxyXG4gICAgICAgICAgICAgIC50cmltKClcclxuICAgICAgICAgICAgICAucmVmaW5lKFxyXG4gICAgICAgICAgICAgICAgKHZhbHVlKSA9PlxyXG4gICAgICAgICAgICAgICAgICAoIWlzTmFOKE51bWJlcih2YWx1ZSkpICYmIE51bWJlcih2YWx1ZSkgPiAwKSB8fFxyXG4gICAgICAgICAgICAgICAgICBbJ3VuZGVmaW5lZCcsICdudWxsJywgJyddLmluY2x1ZGVzKHZhbHVlKSxcclxuICAgICAgICAgICAgICAgIHtcclxuICAgICAgICAgICAgICAgICAgcGFyYW1zOiB7XHJcbiAgICAgICAgICAgICAgICAgICAgZXJyb3JNZXNzYWdlOiAnVGhlIHZhbHVlIG11c3QgYmUgbnVtZXJpYyBhbmQgcG9zaXRpdmUnXHJcbiAgICAgICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgICApXHJcbiAgICAgICAgICAgICAgLnRyYW5zZm9ybSgodmFsdWUpID0+XHJcbiAgICAgICAgICAgICAgICAhWyd1bmRlZmluZWQnLCAnbnVsbCcsICcnXS5pbmNsdWRlcyh2YWx1ZSlcclxuICAgICAgICAgICAgICAgICAgPyBOdW1iZXIodmFsdWUpXHJcbiAgICAgICAgICAgICAgICAgIDogbnVsbFxyXG4gICAgICAgICAgICAgICksXHJcbiAgICAgICAgICAgIHoubnVtYmVyKCkucG9zaXRpdmUoKVxyXG4gICAgICAgICAgXSlcclxuICAgICAgICAgIC5udWxsYWJsZSgpO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgbm9uTmVnYXRpdmVOdW1gIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGggYW4gb3B0aW9uYWxcclxuICAgKiBzdHJpY3RlciBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGF0OlxyXG4gICAqXHJcbiAgICogLSBXaGVuIGBzdHJpY3RDaGVja2AgaXMgdHJ1ZSwgdGhlIHNjaGVtYSB3aWxsIGFjY2VwdCBub24tbmVnYXRpdmUgbnVtYmVyXHJcbiAgICogdmFsdWVzIGFuZCB2YWxpZGF0ZSBhZ2FpbnN0IHRoZSBkZWZhdWx0IG5vbi1uZWdhdGl2ZSBudW1iZXIgdmFsaWRhdG9yLlxyXG4gICAqXHJcbiAgICogLSBXaGVuIGBzdHJpY3RDaGVja2AgaXMgZmFsc2UsIHRoZSBzY2hlbWEgd2lsbCBhY2NlcHQgbm9uLW5lZ2F0aXZlIG51bWJlclxyXG4gICAqIHZhbHVlcywgbnVsbCwgYW5kIHRyaW1tZWQgc3RyaW5nIHZhbHVlcyB0aGF0IGNhbiBlaXRoZXIgYmUgJ3VuZGVmaW5lZCcsXHJcbiAgICogJ251bGwnLCAnJywgb3IgcmVwcmVzZW50IGEgbm9uLW5lZ2F0aXZlIG51bWJlci4gSXQgd2lsbCB0cmFuc2Zvcm1cclxuICAgKiB0aGUgc3RyaW5nIHRvIGEgbm9uLW5lZ2F0aXZlIG51bWJlciwgb3IgdG8gbnVsbCBpZiBpdCBpcyAndW5kZWZpbmVkJyxcclxuICAgKiAnbnVsbCcsIG9yICcnLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIG5vbk5lZ2F0aXZlTnVtXHJcbiAgICpcclxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IHN0cmljdENoZWNrIC0gRGV0ZXJtaW5lcyBpZiBzdHJpY3RlciB2YWxpZGF0aW9uIHNob3VsZFxyXG4gICAqIGJlIGFwcGxpZWQuXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9IEEgWm9kIHNjaGVtYSBvYmplY3QgZm9yIHZhbGlkYXRpbmcgbm9uLW5lZ2F0aXZlXHJcbiAgICogbnVtYmVyIHZhbHVlcy5cclxuICAgKi9cclxuICBub25OZWdhdGl2ZU51bShzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHN0cmljdENoZWNrXHJcbiAgICAgID8gei5udW1iZXIoKS5ub25uZWdhdGl2ZSgpXHJcbiAgICAgIDogelxyXG4gICAgICAgICAgLnVuaW9uKFtcclxuICAgICAgICAgICAgelxyXG4gICAgICAgICAgICAgIC5zdHJpbmcoKVxyXG4gICAgICAgICAgICAgIC50cmltKClcclxuICAgICAgICAgICAgICAucmVmaW5lKFxyXG4gICAgICAgICAgICAgICAgKHZhbHVlKSA9PlxyXG4gICAgICAgICAgICAgICAgICAoIWlzTmFOKE51bWJlcih2YWx1ZSkpICYmIE51bWJlcih2YWx1ZSkgPj0gMCkgfHxcclxuICAgICAgICAgICAgICAgICAgWyd1bmRlZmluZWQnLCAnbnVsbCcsICcnXS5pbmNsdWRlcyh2YWx1ZSksXHJcbiAgICAgICAgICAgICAgICB7XHJcbiAgICAgICAgICAgICAgICAgIHBhcmFtczoge1xyXG4gICAgICAgICAgICAgICAgICAgIGVycm9yTWVzc2FnZTogJ1RoZSB2YWx1ZSBtdXN0IGJlIG51bWVyaWMgYW5kIG5vbi1uZWdhdGl2ZSdcclxuICAgICAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICAgIClcclxuICAgICAgICAgICAgICAudHJhbnNmb3JtKCh2YWx1ZSkgPT5cclxuICAgICAgICAgICAgICAgICFbJ3VuZGVmaW5lZCcsICdudWxsJywgJyddLmluY2x1ZGVzKHZhbHVlKVxyXG4gICAgICAgICAgICAgICAgICA/IE51bWJlcih2YWx1ZSlcclxuICAgICAgICAgICAgICAgICAgOiBudWxsXHJcbiAgICAgICAgICAgICAgKSxcclxuICAgICAgICAgICAgei5udW1iZXIoKS5ub25uZWdhdGl2ZSgpXHJcbiAgICAgICAgICBdKVxyXG4gICAgICAgICAgLm51bGxhYmxlKCk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGBzdGFydHNXaXRoYCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoIGFuIG9wdGlvbmFsXHJcbiAgICogc3RyaWN0ZXIgY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHNjaGVtYSB3aWxsIHZhbGlkYXRlIGFnYWluc3QgdGhlIHByb3ZpZGVkIGBwcmVmaXhlc2AgYXJyYXkgdG8gY2hlY2tcclxuICAgKiB3aGV0aGVyIGEgc3RyaW5nIHZhbHVlIHN0YXJ0cyB3aXRoIGFueSBvZiB0aGUgdmFsdWVzIHByb3ZpZGVkXHJcbiAgICogaW4gdGhlIGBwcmVmaXhlc2AgYXJyYXkuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGF0OlxyXG4gICAqXHJcbiAgICogLSBXaGVuIGBzdHJpY3RDaGVja2AgaXMgdHJ1ZSwgdGhlIHNjaGVtYSB3aWxsIGFjY2VwdCB0cmltbWVkIHN0cmluZyB2YWx1ZXNcclxuICAgKiB0aGF0IHN0YXJ0IHdpdGggdmFsdWVzIGZyb20gdGhlIHByZWZpeGVzIGFycmF5LlxyXG4gICAqXHJcbiAgICogLSBXaGVuIGBzdHJpY3RDaGVja2AgaXMgZmFsc2UsIHRoZSBzY2hlbWEgd2lsbCBhY2NlcHQgdHJpbW1lZCBzdHJpbmcgdmFsdWVzXHJcbiAgICogdGhhdCBzdGFydCB3aXRoIHZhbHVlcyBmcm9tIHRoZSBwcmVmaXhlcyBhcnJheSwgbnVsbCwgJ3VuZGVmaW5lZCcsICdudWxsJyxcclxuICAgKiBhbmQgJycgd2hlcmUgdGhlIHNjaGVtYSB3aWxsIHRyYW5zZm9ybSB0aGVtIHRvIG51bGwuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gc3RhcnRzV2l0aFxyXG4gICAqXHJcbiAgICogQHBhcmFtIHtBcnJheS48c3RyaW5nPn0gcHJlZml4ZXMgLSBBbiBhcnJheSBvZiBwcmVmaXhlcyB0byB2YWxpZGF0ZVxyXG4gICAqIHRoZSBzdHJpbmcgYWdhaW5zdC5cclxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IHN0cmljdENoZWNrIC0gRGV0ZXJtaW5lcyBpZiBzdHJpY3RlciB2YWxpZGF0aW9uIHNob3VsZFxyXG4gICAqIGJlIGFwcGxpZWQuXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9IEEgWm9kIHNjaGVtYSBvYmplY3QgZm9yIHZhbGlkYXRpbmcgc3RyaW5ncyB0aGF0XHJcbiAgICogc3RhcnRzIHdpdGggdmFsdWVzLlxyXG4gICAqL1xyXG4gIHN0YXJ0c1dpdGgocHJlZml4ZXMsIHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gc3RyaWN0Q2hlY2tcclxuICAgICAgPyB6XHJcbiAgICAgICAgICAuc3RyaW5nKClcclxuICAgICAgICAgIC50cmltKClcclxuICAgICAgICAgIC5yZWZpbmUoXHJcbiAgICAgICAgICAgICh2YWx1ZSkgPT4gcHJlZml4ZXMuc29tZSgocHJlZml4KSA9PiB2YWx1ZS5zdGFydHNXaXRoKHByZWZpeCkpLFxyXG4gICAgICAgICAgICB7XHJcbiAgICAgICAgICAgICAgcGFyYW1zOiB7XHJcbiAgICAgICAgICAgICAgICBlcnJvck1lc3NhZ2U6IGBUaGUgdmFsdWUgbXVzdCBiZSBhIHN0cmluZyB0aGF0IHN0YXJ0cyB3aXRoICR7cHJlZml4ZXMuam9pbignLCAnKX1gXHJcbiAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICB9XHJcbiAgICAgICAgICApXHJcbiAgICAgIDogelxyXG4gICAgICAgICAgLnN0cmluZygpXHJcbiAgICAgICAgICAudHJpbSgpXHJcbiAgICAgICAgICAucmVmaW5lKFxyXG4gICAgICAgICAgICAodmFsdWUpID0+XHJcbiAgICAgICAgICAgICAgcHJlZml4ZXMuc29tZSgocHJlZml4KSA9PiB2YWx1ZS5zdGFydHNXaXRoKHByZWZpeCkpIHx8XHJcbiAgICAgICAgICAgICAgWyd1bmRlZmluZWQnLCAnbnVsbCcsICcnXS5pbmNsdWRlcyh2YWx1ZSksXHJcbiAgICAgICAgICAgIHtcclxuICAgICAgICAgICAgICBwYXJhbXM6IHtcclxuICAgICAgICAgICAgICAgIGVycm9yTWVzc2FnZTogYFRoZSB2YWx1ZSBtdXN0IGJlIGEgc3RyaW5nIHRoYXQgc3RhcnRzIHdpdGggJHtwcmVmaXhlcy5qb2luKCcsICcpfWBcclxuICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgIH1cclxuICAgICAgICAgIClcclxuICAgICAgICAgIC50cmFuc2Zvcm0oKHZhbHVlKSA9PlxyXG4gICAgICAgICAgICAhWyd1bmRlZmluZWQnLCAnbnVsbCcsICcnXS5pbmNsdWRlcyh2YWx1ZSkgPyB2YWx1ZSA6IG51bGxcclxuICAgICAgICAgIClcclxuICAgICAgICAgIC5udWxsYWJsZSgpO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgY2hhcnRDb25maWdgIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhhdCB0aGUgc2NoZW1hIHdpbGwgYWNjZXB0IG9iamVjdCB2YWx1ZXNcclxuICAgKiBvciB0cmltbWVkIHN0cmluZyB2YWx1ZXMgdGhhdCBjb250YWluICc8c3ZnJyBvciAnPD94bWwnIGVsZW1lbnRzLCBzdGFydFxyXG4gICAqIHdpdGggdGhlICd7JyBhbmQgZW5kIHdpdGggdGhlICd9JywgYW5kIG51bGwuIFRoZSAndW5kZWZpbmVkJywgJ251bGwnLFxyXG4gICAqIGFuZCAnJyB2YWx1ZXMgd2lsbCBiZSB0cmFuc2Zvcm1lZCB0byBudWxsLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIGNoYXJ0Q29uZmlnXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9IEEgWm9kIHNjaGVtYSBvYmplY3QgZm9yIHZhbGlkYXRpbmcgY2hhcnRcclxuICAgKiBjb25maWd1cmF0aW9uIHZhbHVlLlxyXG4gICAqL1xyXG4gIGNoYXJ0Q29uZmlnKCkge1xyXG4gICAgcmV0dXJuIHpcclxuICAgICAgLnVuaW9uKFtcclxuICAgICAgICB6XHJcbiAgICAgICAgICAuc3RyaW5nKClcclxuICAgICAgICAgIC50cmltKClcclxuICAgICAgICAgIC5yZWZpbmUoXHJcbiAgICAgICAgICAgICh2YWx1ZSkgPT5cclxuICAgICAgICAgICAgICAodmFsdWUuc3RhcnRzV2l0aCgneycpICYmIHZhbHVlLmVuZHNXaXRoKCd9JykpIHx8XHJcbiAgICAgICAgICAgICAgWyd1bmRlZmluZWQnLCAnbnVsbCcsICcnXS5pbmNsdWRlcyh2YWx1ZSksXHJcbiAgICAgICAgICAgIHtcclxuICAgICAgICAgICAgICBwYXJhbXM6IHtcclxuICAgICAgICAgICAgICAgIGVycm9yTWVzc2FnZTpcclxuICAgICAgICAgICAgICAgICAgXCJUaGUgdmFsdWUgbXVzdCBiZSBhIHN0cmluZyB0aGF0IHN0YXJ0cyB3aXRoICd7JyBhbmQgZW5kcyB3aXRoICd9J1wiXHJcbiAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICB9XHJcbiAgICAgICAgICApXHJcbiAgICAgICAgICAudHJhbnNmb3JtKCh2YWx1ZSkgPT5cclxuICAgICAgICAgICAgIVsndW5kZWZpbmVkJywgJ251bGwnLCAnJ10uaW5jbHVkZXModmFsdWUpID8gdmFsdWUgOiBudWxsXHJcbiAgICAgICAgICApLFxyXG4gICAgICAgIHoub2JqZWN0KHt9KS5wYXNzdGhyb3VnaCgpXHJcbiAgICAgIF0pXHJcbiAgICAgIC5udWxsYWJsZSgpO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgYWRkaXRpb25hbE9wdGlvbnNgIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhhdCB0aGUgc2NoZW1hIHdpbGwgYWNjZXB0IG9iamVjdCB2YWx1ZXNcclxuICAgKiBvciB0cmltbWVkIHN0cmluZyB2YWx1ZXMgdGhhdCBlbmQgd2l0aCAnLmpzb24nIGFuZCBhcmUgYXQgbGVhc3Qgb25lXHJcbiAgICogY2hhcmFjdGVyIGxvbmcgZXhjbHVkaW5nIHRoZSBleHRlbnNpb24sIHN0YXJ0IHdpdGggdGhlICd7JyBhbmQgZW5kXHJcbiAgICogd2l0aCB0aGUgJ30nLCBhbmQgbnVsbC4gVGhlICd1bmRlZmluZWQnLCAnbnVsbCcsIGFuZCAnJyB2YWx1ZXMgd2lsbFxyXG4gICAqIGJlIHRyYW5zZm9ybWVkIHRvIG51bGwuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gYWRkaXRpb25hbE9wdGlvbnNcclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gIEEgWm9kIHNjaGVtYSBvYmplY3QgZm9yIHZhbGlkYXRpbmcgYWRkaXRpb25hbCBjaGFydFxyXG4gICAqIG9wdGlvbnMgdmFsdWUuXHJcbiAgICovXHJcbiAgYWRkaXRpb25hbE9wdGlvbnMoKSB7XHJcbiAgICByZXR1cm4gelxyXG4gICAgICAudW5pb24oW1xyXG4gICAgICAgIHpcclxuICAgICAgICAgIC5zdHJpbmcoKVxyXG4gICAgICAgICAgLnRyaW0oKVxyXG4gICAgICAgICAgLnJlZmluZShcclxuICAgICAgICAgICAgKHZhbHVlKSA9PlxyXG4gICAgICAgICAgICAgICh2YWx1ZS5sZW5ndGggPj0gNiAmJiB2YWx1ZS5lbmRzV2l0aCgnLmpzb24nKSkgfHxcclxuICAgICAgICAgICAgICAodmFsdWUuc3RhcnRzV2l0aCgneycpICYmIHZhbHVlLmVuZHNXaXRoKCd9JykpIHx8XHJcbiAgICAgICAgICAgICAgWyd1bmRlZmluZWQnLCAnbnVsbCcsICcnXS5pbmNsdWRlcyh2YWx1ZSksXHJcbiAgICAgICAgICAgIHtcclxuICAgICAgICAgICAgICBwYXJhbXM6IHtcclxuICAgICAgICAgICAgICAgIGVycm9yTWVzc2FnZTpcclxuICAgICAgICAgICAgICAgICAgXCJUaGUgdmFsdWUgbXVzdCBiZSBhIHN0cmluZyB0aGF0IGVuZHMgd2l0aCAnLmpzb24nIG9yIHN0YXJ0cyB3aXRoICd7JyBhbmQgZW5kcyB3aXRoICd9J1wiXHJcbiAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICB9XHJcbiAgICAgICAgICApXHJcbiAgICAgICAgICAudHJhbnNmb3JtKCh2YWx1ZSkgPT5cclxuICAgICAgICAgICAgIVsndW5kZWZpbmVkJywgJ251bGwnLCAnJ10uaW5jbHVkZXModmFsdWUpID8gdmFsdWUgOiBudWxsXHJcbiAgICAgICAgICApLFxyXG4gICAgICAgIHoub2JqZWN0KHt9KS5wYXNzdGhyb3VnaCgpXHJcbiAgICAgIF0pXHJcbiAgICAgIC5udWxsYWJsZSgpO1xyXG4gIH1cclxufTtcclxuXHJcbi8qKlxyXG4gKiBPYmplY3QgY29udGFpbmluZyBjdXN0b20gY29uZmlnIHZhbGlkYXRvcnMgYW5kIHBhcnNlcnMgdG8gYXZvaWQgcmVwZXRpdGlvblxyXG4gKiBpbiBzY2hlbWEgb2JqZWN0cy4gQWxsIHZhbGlkYXRvcnMgYXBwbHkgdG8gdmFsdWVzIGZyb20gdmFyaW91cyBzb3VyY2VzLFxyXG4gKiBpbmNsdWRpbmcgdGhlIGRlZmF1bHQgY29uZmlnIGZpbGUsIGEgY3VzdG9tIEpTT04gZmlsZSBsb2FkZWQgd2l0aCB0aGUgb3B0aW9uXHJcbiAqIGNhbGxlZCBgbG9hZENvbmZpZ2AsIHRoZSAuZW52IGZpbGUsIENMSSBhcmd1bWVudHMsIGFuZCB0aGUgcmVxdWVzdCBwYXlsb2FkLlxyXG4gKiBUaGUgYHN0cmljdENoZWNrYCBmbGFnIGVuYWJsZXMgc3RyaWN0ZXIgdmFsaWRhdGlvbiBhbmQgcGFyc2luZyBydWxlcy4gVGhpc1xyXG4gKiBmbGFnIGlzIHNldCB0byBmYWxzZSBmb3IgdmFsdWVzIHRoYXQgY29tZSBmcm9tIHRoZSAuZW52IGZpbGUgb3IgQ0xJIGFyZ3VtZW50c1xyXG4gKiBiZWNhdXNlIHRoZXkgYXJlIHByb3ZpZGVkIGFzIHN0cmluZ3MgYW5kIG5lZWQgdG8gYmUgcGFyc2VkIGFjY29yZGluZ2x5IGZpcnN0LlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IHZhbGlkYXRvcnMgPSB7XHJcbiAgLyoqXHJcbiAgICogVGhlIGBhcmdzYCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoIGFuIG9wdGlvbmFsIHN0cmljdGVyXHJcbiAgICogY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhlIHNhbWUgd29yayBhcyB0aGUgYHN0cmluZ0FycmF5YCB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gYXJnc1xyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nIHRoZSBgYXJnc2BcclxuICAgKiBvcHRpb24uXHJcbiAgICovXHJcbiAgYXJncyhzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHYuc3RyaW5nQXJyYXkoXHJcbiAgICAgICh2YWx1ZSkgPT4gIVsnZmFsc2UnLCAndW5kZWZpbmVkJywgJ251bGwnLCAnJ10uaW5jbHVkZXModmFsdWUpLFxyXG4gICAgICAnOycsXHJcbiAgICAgIHN0cmljdENoZWNrXHJcbiAgICApO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgdmVyc2lvbmAgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbCBzdHJpY3RlclxyXG4gICAqIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoYXQ6XHJcbiAgICpcclxuICAgKiAtIFdoZW4gYHN0cmljdENoZWNrYCBpcyB0cnVlLCB0aGUgc2NoZW1hIHdpbGwgYWNjZXB0IHRyaW1tZWQgc3RyaW5nIHZhbHVlc1xyXG4gICAqIHRoYXQgYXJlIGEgUmVnRXhwLWJhc2VkIHRoYXQgYWxsb3dzIHRvIGJlICdsYXRlc3QnLCBvciBpbiB0aGUgZm9ybWF0IFhYLFxyXG4gICAqIFhYLllZLCBvciBYWC5ZWS5aWiwgd2hlcmUgWFgsIFlZLCBhbmQgWlogYXJlIG51bWVyaWMgZm9yIHRoZSBIaWdoY2hhcnRzXHJcbiAgICogdmVyc2lvbiBvcHRpb24uXHJcbiAgICpcclxuICAgKiAtIFdoZW4gYHN0cmljdENoZWNrYCBpcyBmYWxzZSwgdGhlIHNjaGVtYSB3aWxsIGFjY2VwdCBhbHNvIG51bGwsXHJcbiAgICogJ3VuZGVmaW5lZCcsICdudWxsJywgb3IgJycgYW5kIGluIGFsbCBjYXNlcyB0aGUgc2NoZW1hIHdpbGwgdHJhbnNmb3JtIHRoZW1cclxuICAgKiB0byBudWxsLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIHZlcnNpb25cclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZyB0aGUgYHZlcnNpb25gXHJcbiAgICogb3B0aW9uLlxyXG4gICAqL1xyXG4gIHZlcnNpb24oc3RyaWN0Q2hlY2spIHtcclxuICAgIHJldHVybiBzdHJpY3RDaGVja1xyXG4gICAgICA/IHpcclxuICAgICAgICAgIC5zdHJpbmcoKVxyXG4gICAgICAgICAgLnRyaW0oKVxyXG4gICAgICAgICAgLnJlZmluZSgodmFsdWUpID0+IC9eKGxhdGVzdHxcXGR7MSwyfShcXC5cXGR7MSwyfSl7MCwyfSkkLy50ZXN0KHZhbHVlKSwge1xyXG4gICAgICAgICAgICBwYXJhbXM6IHtcclxuICAgICAgICAgICAgICBlcnJvck1lc3NhZ2U6XHJcbiAgICAgICAgICAgICAgICBcIlRoZSB2YWx1ZSBtdXN0IGJlICdsYXRlc3QnLCBhIG1ham9yIHZlcnNpb24sIG9yIGluIHRoZSBmb3JtIFhYLllZLlpaXCJcclxuICAgICAgICAgICAgfVxyXG4gICAgICAgICAgfSlcclxuICAgICAgOiB6XHJcbiAgICAgICAgICAuc3RyaW5nKClcclxuICAgICAgICAgIC50cmltKClcclxuICAgICAgICAgIC5yZWZpbmUoXHJcbiAgICAgICAgICAgICh2YWx1ZSkgPT5cclxuICAgICAgICAgICAgICAvXihsYXRlc3R8XFxkezEsMn0oXFwuXFxkezEsMn0pezAsMn0pJC8udGVzdCh2YWx1ZSkgfHxcclxuICAgICAgICAgICAgICBbJ3VuZGVmaW5lZCcsICdudWxsJywgJyddLmluY2x1ZGVzKHZhbHVlKSxcclxuICAgICAgICAgICAge1xyXG4gICAgICAgICAgICAgIHBhcmFtczoge1xyXG4gICAgICAgICAgICAgICAgZXJyb3JNZXNzYWdlOlxyXG4gICAgICAgICAgICAgICAgICBcIlRoZSB2YWx1ZSBtdXN0IGJlICdsYXRlc3QnLCBhIG1ham9yIHZlcnNpb24sIG9yIGluIHRoZSBmb3JtIFhYLllZLlpaXCJcclxuICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgIH1cclxuICAgICAgICAgIClcclxuICAgICAgICAgIC50cmFuc2Zvcm0oKHZhbHVlKSA9PlxyXG4gICAgICAgICAgICAhWyd1bmRlZmluZWQnLCAnbnVsbCcsICcnXS5pbmNsdWRlcyh2YWx1ZSkgPyB2YWx1ZSA6IG51bGxcclxuICAgICAgICAgIClcclxuICAgICAgICAgIC5udWxsYWJsZSgpO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgY2RuVXJsYCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoIGFuIG9wdGlvbmFsIHN0cmljdGVyXHJcbiAgICogY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhlIHNhbWUgd29yayBhcyB0aGUgYHN0YXJ0c1dpdGhgIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiBjZG5VcmxcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZyB0aGUgYGNkblVybGBcclxuICAgKiBvcHRpb24uXHJcbiAgICovXHJcbiAgY2RuVXJsKHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gdi5zdGFydHNXaXRoKFsnaHR0cDovLycsICdodHRwczovLyddLCBzdHJpY3RDaGVjayk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGBmb3JjZUZldGNoYCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoIGFuIG9wdGlvbmFsXHJcbiAgICogc3RyaWN0ZXIgY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhlIHNhbWUgd29yayBhcyB0aGUgYGJvb2xlYW5gIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiBmb3JjZUZldGNoXHJcbiAgICpcclxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IHN0cmljdENoZWNrIC0gRGV0ZXJtaW5lcyBpZiBzdHJpY3RlciB2YWxpZGF0aW9uIHNob3VsZFxyXG4gICAqIGJlIGFwcGxpZWQuXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9IEEgWm9kIHNjaGVtYSBvYmplY3QgZm9yIHZhbGlkYXRpbmcgdGhlIGBmb3JjZUZldGNoYFxyXG4gICAqIG9wdGlvbi5cclxuICAgKi9cclxuICBmb3JjZUZldGNoKHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gdi5ib29sZWFuKHN0cmljdENoZWNrKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYGNhY2hlUGF0aGAgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbFxyXG4gICAqIHN0cmljdGVyIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgdGhlIGBzdHJpbmdgIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiBjYWNoZVBhdGhcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZyB0aGUgYGNhY2hlUGF0aGBcclxuICAgKiBvcHRpb24uXHJcbiAgICovXHJcbiAgY2FjaGVQYXRoKHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gdi5zdHJpbmcoc3RyaWN0Q2hlY2spO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgYWRtaW5Ub2tlbmAgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbFxyXG4gICAqIHN0cmljdGVyIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgdGhlIGBzdHJpbmdgIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiBhZG1pblRva2VuXHJcbiAgICpcclxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IHN0cmljdENoZWNrIC0gRGV0ZXJtaW5lcyBpZiBzdHJpY3RlciB2YWxpZGF0aW9uIHNob3VsZFxyXG4gICAqIGJlIGFwcGxpZWQuXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9IEEgWm9kIHNjaGVtYSBvYmplY3QgZm9yIHZhbGlkYXRpbmcgdGhlIGBhZG1pblRva2VuYFxyXG4gICAqIG9wdGlvbi5cclxuICAgKi9cclxuICBhZG1pblRva2VuKHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gdi5zdHJpbmcoc3RyaWN0Q2hlY2spO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgY29yZVNjcmlwdHNgIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGggYW4gb3B0aW9uYWxcclxuICAgKiBzdHJpY3RlciBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGUgc2FtZSB3b3JrIGFzIHRoZSBgc3RyaW5nQXJyYXlgIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiBjb3JlU2NyaXB0c1xyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nIHRoZSBgY29yZVNjcmlwdHNgXHJcbiAgICogb3B0aW9uLlxyXG4gICAqL1xyXG4gIGNvcmVTY3JpcHRzKHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gdi5zdHJpbmdBcnJheShcclxuICAgICAgKHZhbHVlKSA9PiBjb3JlU2NyaXB0cy52YWx1ZS5pbmNsdWRlcyh2YWx1ZSksXHJcbiAgICAgICcsJyxcclxuICAgICAgc3RyaWN0Q2hlY2tcclxuICAgICk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGBtb2R1bGVTY3JpcHRzYCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoIGFuIG9wdGlvbmFsXHJcbiAgICogc3RyaWN0ZXIgY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhlIHNhbWUgd29yayBhcyB0aGUgYHN0cmluZ0FycmF5YCB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gbW9kdWxlU2NyaXB0c1xyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nXHJcbiAgICogdGhlIGBtb2R1bGVTY3JpcHRzYCBvcHRpb24uXHJcbiAgICovXHJcbiAgbW9kdWxlU2NyaXB0cyhzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHYuc3RyaW5nQXJyYXkoXHJcbiAgICAgICh2YWx1ZSkgPT4gbW9kdWxlU2NyaXB0cy52YWx1ZS5pbmNsdWRlcyh2YWx1ZSksXHJcbiAgICAgICcsJyxcclxuICAgICAgc3RyaWN0Q2hlY2tcclxuICAgICk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGBpbmRpY2F0b3JTY3JpcHRzYCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoIGFuIG9wdGlvbmFsXHJcbiAgICogc3RyaWN0ZXIgY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhlIHNhbWUgd29yayBhcyB0aGUgYHN0cmluZ0FycmF5YCB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gaW5kaWNhdG9yU2NyaXB0c1xyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nXHJcbiAgICogdGhlIGBpbmRpY2F0b3JTY3JpcHRzYCBvcHRpb24uXHJcbiAgICovXHJcbiAgaW5kaWNhdG9yU2NyaXB0cyhzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHYuc3RyaW5nQXJyYXkoXHJcbiAgICAgICh2YWx1ZSkgPT4gaW5kaWNhdG9yU2NyaXB0cy52YWx1ZS5pbmNsdWRlcyh2YWx1ZSksXHJcbiAgICAgICcsJyxcclxuICAgICAgc3RyaWN0Q2hlY2tcclxuICAgICk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGBjdXN0b21TY3JpcHRzYCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoIGFuIG9wdGlvbmFsXHJcbiAgICogc3RyaWN0ZXIgY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhlIHNhbWUgd29yayBhcyB0aGUgYHN0cmluZ0FycmF5YCB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gY3VzdG9tU2NyaXB0c1xyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nXHJcbiAgICogdGhlIGBjdXN0b21TY3JpcHRzYCBvcHRpb24uXHJcbiAgICovXHJcbiAgY3VzdG9tU2NyaXB0cyhzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHYuc3RyaW5nQXJyYXkoXHJcbiAgICAgICh2YWx1ZSkgPT4gdmFsdWUuc3RhcnRzV2l0aCgnaHR0cHM6Ly8nKSB8fCB2YWx1ZS5zdGFydHNXaXRoKCdodHRwOi8vJyksXHJcbiAgICAgICcsJyxcclxuICAgICAgc3RyaWN0Q2hlY2tcclxuICAgICk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGBpbmZpbGVgIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGggYW4gb3B0aW9uYWwgc3RyaWN0ZXJcclxuICAgKiBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGF0OlxyXG4gICAqXHJcbiAgICogLSBXaGVuIGBzdHJpY3RDaGVja2AgaXMgdHJ1ZSwgdGhlIHNjaGVtYSB3aWxsIGFjY2VwdCB0cmltbWVkIHN0cmluZyB2YWx1ZXNcclxuICAgKiB0aGF0IGVuZCB3aXRoICcuanNvbicgb3IgJy5zdmcnLCBhcmUgYXQgbGVhc3Qgb25lIGNoYXJhY3RlciBsb25nIGV4Y2x1ZGluZ1xyXG4gICAqIHRoZSBleHRlbnNpb24sIG9yIG51bGwuXHJcbiAgICpcclxuICAgKiAtIFdoZW4gYHN0cmljdENoZWNrYCBpcyBmYWxzZSwgdGhlIHNjaGVtYSB3aWxsIGFjY2VwdCB0cmltbWVkIHN0cmluZyB2YWx1ZXNcclxuICAgKiB0aGF0IGVuZCB3aXRoICcuanNvbicgb3IgJy5zdmcnLCBhcmUgYXQgbGVhc3Qgb25lIGNoYXJhY3RlciBsb25nIGV4Y2x1ZGluZ1xyXG4gICAqIHRoZSBleHRlbnNpb24gYW5kIHdpbGwgYmUgbnVsbCBpZiB0aGUgcHJvdmlkZWQgdmFsdWUgaXMgbnVsbCwgJ3VuZGVmaW5lZCcsXHJcbiAgICogJ251bGwnLCBvciAnJy5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiBpbmZpbGVcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZyB0aGUgYGluZmlsZWBcclxuICAgKiBvcHRpb24uXHJcbiAgICovXHJcbiAgaW5maWxlKHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gc3RyaWN0Q2hlY2tcclxuICAgICAgPyB6XHJcbiAgICAgICAgICAuc3RyaW5nKClcclxuICAgICAgICAgIC50cmltKClcclxuICAgICAgICAgIC5yZWZpbmUoXHJcbiAgICAgICAgICAgICh2YWx1ZSkgPT5cclxuICAgICAgICAgICAgICAodmFsdWUubGVuZ3RoID49IDYgJiYgdmFsdWUuZW5kc1dpdGgoJy5qc29uJykpIHx8XHJcbiAgICAgICAgICAgICAgKHZhbHVlLmxlbmd0aCA+PSA1ICYmIHZhbHVlLmVuZHNXaXRoKCcuc3ZnJykpLFxyXG4gICAgICAgICAgICB7XHJcbiAgICAgICAgICAgICAgcGFyYW1zOiB7XHJcbiAgICAgICAgICAgICAgICBlcnJvck1lc3NhZ2U6XHJcbiAgICAgICAgICAgICAgICAgICdUaGUgdmFsdWUgbXVzdCBiZSBhIHN0cmluZyB0aGF0IGVuZHMgd2l0aCAuanNvbiBvciAuc3ZnJ1xyXG4gICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgfVxyXG4gICAgICAgICAgKVxyXG4gICAgICAgICAgLm51bGxhYmxlKClcclxuICAgICAgOiB6XHJcbiAgICAgICAgICAuc3RyaW5nKClcclxuICAgICAgICAgIC50cmltKClcclxuICAgICAgICAgIC5yZWZpbmUoXHJcbiAgICAgICAgICAgICh2YWx1ZSkgPT5cclxuICAgICAgICAgICAgICAodmFsdWUubGVuZ3RoID49IDYgJiYgdmFsdWUuZW5kc1dpdGgoJy5qc29uJykpIHx8XHJcbiAgICAgICAgICAgICAgKHZhbHVlLmxlbmd0aCA+PSA1ICYmIHZhbHVlLmVuZHNXaXRoKCcuc3ZnJykpIHx8XHJcbiAgICAgICAgICAgICAgWyd1bmRlZmluZWQnLCAnbnVsbCcsICcnXS5pbmNsdWRlcyh2YWx1ZSksXHJcbiAgICAgICAgICAgIHtcclxuICAgICAgICAgICAgICBwYXJhbXM6IHtcclxuICAgICAgICAgICAgICAgIGVycm9yTWVzc2FnZTpcclxuICAgICAgICAgICAgICAgICAgJ1RoZSB2YWx1ZSBtdXN0IGJlIGEgc3RyaW5nIHRoYXQgZW5kcyB3aXRoIC5qc29uIG9yIC5zdmcnXHJcbiAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICB9XHJcbiAgICAgICAgICApXHJcbiAgICAgICAgICAudHJhbnNmb3JtKCh2YWx1ZSkgPT5cclxuICAgICAgICAgICAgIVsndW5kZWZpbmVkJywgJ251bGwnLCAnJ10uaW5jbHVkZXModmFsdWUpID8gdmFsdWUgOiBudWxsXHJcbiAgICAgICAgICApXHJcbiAgICAgICAgICAubnVsbGFibGUoKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYGluc3RyYCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYS5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgdGhlIGBvcHRpb25zYCB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gaW5zdHJcclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZyB0aGUgYGluc3RyYFxyXG4gICAqIG9wdGlvbi5cclxuICAgKi9cclxuICBpbnN0cigpIHtcclxuICAgIHJldHVybiB2LmNoYXJ0Q29uZmlnKCk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGBvcHRpb25zYCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYS5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgdGhlIGBvcHRpb25zYCB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gb3B0aW9uc1xyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nIHRoZSBgb3B0aW9uc2BcclxuICAgKiBvcHRpb24uXHJcbiAgICovXHJcbiAgb3B0aW9ucygpIHtcclxuICAgIHJldHVybiB2LmNoYXJ0Q29uZmlnKCk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGBzdmdgIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhhdCB0aGUgc2NoZW1hIHdpbGwgYWNjZXB0IG9iamVjdCB2YWx1ZXNcclxuICAgKiBvciB0cmltbWVkIHN0cmluZyB2YWx1ZXMgdGhhdCBjb250YWluICc8c3ZnJyBvciAnPD94bWwnIGVsZW1lbnRzIGFuZCBudWxsLlxyXG4gICAqIFRoZSAndW5kZWZpbmVkJywgJ251bGwnLCBhbmQgJycgdmFsdWVzIHdpbGwgYmUgdHJhbnNmb3JtZWQgdG8gbnVsbC5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiBzdmdcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZyB0aGUgYHN2Z2Agb3B0aW9uLlxyXG4gICAqL1xyXG4gIHN2ZygpIHtcclxuICAgIHJldHVybiB6XHJcbiAgICAgIC5zdHJpbmcoKVxyXG4gICAgICAudHJpbSgpXHJcbiAgICAgIC5yZWZpbmUoXHJcbiAgICAgICAgKHZhbHVlKSA9PlxyXG4gICAgICAgICAgdmFsdWUuaW5kZXhPZignPHN2ZycpID49IDAgfHxcclxuICAgICAgICAgIHZhbHVlLmluZGV4T2YoJzw/eG1sJykgPj0gMCB8fFxyXG4gICAgICAgICAgWydmYWxzZScsICd1bmRlZmluZWQnLCAnbnVsbCcsICcnXS5pbmNsdWRlcyh2YWx1ZSksXHJcbiAgICAgICAge1xyXG4gICAgICAgICAgcGFyYW1zOiB7XHJcbiAgICAgICAgICAgIGVycm9yTWVzc2FnZTpcclxuICAgICAgICAgICAgICBcIlRoZSB2YWx1ZSBtdXN0IGJlIGEgc3RyaW5nIHRoYXQgY29udGFpbnMgJzxzdmcnIG9yICc8P3htbCdcIlxyXG4gICAgICAgICAgfVxyXG4gICAgICAgIH1cclxuICAgICAgKVxyXG4gICAgICAudHJhbnNmb3JtKCh2YWx1ZSkgPT5cclxuICAgICAgICAhWydmYWxzZScsICd1bmRlZmluZWQnLCAnbnVsbCcsICcnXS5pbmNsdWRlcyh2YWx1ZSkgPyB2YWx1ZSA6IG51bGxcclxuICAgICAgKVxyXG4gICAgICAubnVsbGFibGUoKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYG91dGZpbGVgIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGggYW4gb3B0aW9uYWwgc3RyaWN0ZXJcclxuICAgKiBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGF0OlxyXG4gICAqXHJcbiAgICogLSBXaGVuIGBzdHJpY3RDaGVja2AgaXMgdHJ1ZSwgdGhlIHNjaGVtYSB3aWxsIGFjY2VwdCB0cmltbWVkIHN0cmluZyB2YWx1ZXNcclxuICAgKiB0aGF0IGVuZCB3aXRoICcuanBlZycsICcuanBnJywgJy5wbmcnLCAnLnBkZicsIG9yICcuc3ZnJywgYXJlIGF0IGxlYXN0IG9uZVxyXG4gICAqIGNoYXJhY3RlciBsb25nIGV4Y2x1ZGluZyB0aGUgZXh0ZW5zaW9uLCBvciBudWxsLlxyXG4gICAqXHJcbiAgICogLSBXaGVuIGBzdHJpY3RDaGVja2AgaXMgZmFsc2UsIHRoZSBzY2hlbWEgd2lsbCBhY2NlcHQgdHJpbW1lZCBzdHJpbmcgdmFsdWVzXHJcbiAgICogdGhhdCBlbmQgd2l0aCAnLmpwZWcnLCAnLmpwZycsICcucG5nJywgJy5wZGYnLCBvciAnLnN2ZycsIGFyZSBhdCBsZWFzdCBvbmVcclxuICAgKiBjaGFyYWN0ZXIgbG9uZyBleGNsdWRpbmcgdGhlIGV4dGVuc2lvbiBhbmQgd2lsbCBiZSBudWxsIGlmIHRoZSBwcm92aWRlZFxyXG4gICAqIHZhbHVlIGlzIG51bGwsICd1bmRlZmluZWQnLCAnbnVsbCcsIG9yICcnLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIG91dGZpbGVcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZyB0aGUgYG91dGZpbGVgXHJcbiAgICogb3B0aW9uLlxyXG4gICAqL1xyXG4gIG91dGZpbGUoc3RyaWN0Q2hlY2spIHtcclxuICAgIHJldHVybiBzdHJpY3RDaGVja1xyXG4gICAgICA/IHpcclxuICAgICAgICAgIC5zdHJpbmcoKVxyXG4gICAgICAgICAgLnRyaW0oKVxyXG4gICAgICAgICAgLnJlZmluZShcclxuICAgICAgICAgICAgKHZhbHVlKSA9PlxyXG4gICAgICAgICAgICAgICh2YWx1ZS5sZW5ndGggPj0gNiAmJiB2YWx1ZS5lbmRzV2l0aCgnLmpwZWcnKSkgfHxcclxuICAgICAgICAgICAgICAodmFsdWUubGVuZ3RoID49IDUgJiZcclxuICAgICAgICAgICAgICAgICh2YWx1ZS5lbmRzV2l0aCgnLmpwZycpIHx8XHJcbiAgICAgICAgICAgICAgICAgIHZhbHVlLmVuZHNXaXRoKCcucG5nJykgfHxcclxuICAgICAgICAgICAgICAgICAgdmFsdWUuZW5kc1dpdGgoJy5wZGYnKSB8fFxyXG4gICAgICAgICAgICAgICAgICB2YWx1ZS5lbmRzV2l0aCgnLnN2ZycpKSksXHJcbiAgICAgICAgICAgIHtcclxuICAgICAgICAgICAgICBwYXJhbXM6IHtcclxuICAgICAgICAgICAgICAgIGVycm9yTWVzc2FnZTpcclxuICAgICAgICAgICAgICAgICAgJ1RoZSB2YWx1ZSBtdXN0IGJlIGEgc3RyaW5nIHRoYXQgZW5kcyB3aXRoIC5qcGVnLCAuanBnLCAucG5nLCAucGRmLCBvciAuc3ZnJ1xyXG4gICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgfVxyXG4gICAgICAgICAgKVxyXG4gICAgICAgICAgLm51bGxhYmxlKClcclxuICAgICAgOiB6XHJcbiAgICAgICAgICAuc3RyaW5nKClcclxuICAgICAgICAgIC50cmltKClcclxuICAgICAgICAgIC5yZWZpbmUoXHJcbiAgICAgICAgICAgICh2YWx1ZSkgPT5cclxuICAgICAgICAgICAgICAodmFsdWUubGVuZ3RoID49IDYgJiYgdmFsdWUuZW5kc1dpdGgoJy5qcGVnJykpIHx8XHJcbiAgICAgICAgICAgICAgKHZhbHVlLmxlbmd0aCA+PSA1ICYmXHJcbiAgICAgICAgICAgICAgICAodmFsdWUuZW5kc1dpdGgoJy5qcGcnKSB8fFxyXG4gICAgICAgICAgICAgICAgICB2YWx1ZS5lbmRzV2l0aCgnLnBuZycpIHx8XHJcbiAgICAgICAgICAgICAgICAgIHZhbHVlLmVuZHNXaXRoKCcucGRmJykgfHxcclxuICAgICAgICAgICAgICAgICAgdmFsdWUuZW5kc1dpdGgoJy5zdmcnKSkpIHx8XHJcbiAgICAgICAgICAgICAgWyd1bmRlZmluZWQnLCAnbnVsbCcsICcnXS5pbmNsdWRlcyh2YWx1ZSksXHJcbiAgICAgICAgICAgIHtcclxuICAgICAgICAgICAgICBwYXJhbXM6IHtcclxuICAgICAgICAgICAgICAgIGVycm9yTWVzc2FnZTpcclxuICAgICAgICAgICAgICAgICAgJ1RoZSB2YWx1ZSBtdXN0IGJlIGEgc3RyaW5nIHRoYXQgZW5kcyB3aXRoIC5qcGVnLCAuanBnLCAucG5nLCAucGRmLCBvciAuc3ZnJ1xyXG4gICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgfVxyXG4gICAgICAgICAgKVxyXG4gICAgICAgICAgLnRyYW5zZm9ybSgodmFsdWUpID0+XHJcbiAgICAgICAgICAgICFbJ3VuZGVmaW5lZCcsICdudWxsJywgJyddLmluY2x1ZGVzKHZhbHVlKSA/IHZhbHVlIDogbnVsbFxyXG4gICAgICAgICAgKVxyXG4gICAgICAgICAgLm51bGxhYmxlKCk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGB0eXBlYCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoIGFuIG9wdGlvbmFsIHN0cmljdGVyXHJcbiAgICogY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhlIHNhbWUgd29yayBhcyB0aGUgYGVudW1gIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiB0eXBlXHJcbiAgICpcclxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IHN0cmljdENoZWNrIC0gRGV0ZXJtaW5lcyBpZiBzdHJpY3RlciB2YWxpZGF0aW9uIHNob3VsZFxyXG4gICAqIGJlIGFwcGxpZWQuXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9IEEgWm9kIHNjaGVtYSBvYmplY3QgZm9yIHZhbGlkYXRpbmcgdGhlIGB0eXBlYFxyXG4gICAqIG9wdGlvbi5cclxuICAgKi9cclxuICB0eXBlKHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gdi5lbnVtKFsnanBlZycsICdqcGcnLCAncG5nJywgJ3BkZicsICdzdmcnXSwgc3RyaWN0Q2hlY2spO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgY29uc3RyYCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoIGFuIG9wdGlvbmFsIHN0cmljdGVyXHJcbiAgICogY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhlIHNhbWUgd29yayBhcyB0aGUgYGVudW1gIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiBjb25zdHJcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZyB0aGUgYGNvbnN0cmBcclxuICAgKiBvcHRpb24uXHJcbiAgICovXHJcbiAgY29uc3RyKHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gdi5lbnVtKFxyXG4gICAgICBbJ2NoYXJ0JywgJ3N0b2NrQ2hhcnQnLCAnbWFwQ2hhcnQnLCAnZ2FudHRDaGFydCddLFxyXG4gICAgICBzdHJpY3RDaGVja1xyXG4gICAgKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYGI2NGAgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbCBzdHJpY3RlclxyXG4gICAqIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgdGhlIGBib29sZWFuYCB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gYjY0XHJcbiAgICpcclxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IHN0cmljdENoZWNrIC0gRGV0ZXJtaW5lcyBpZiBzdHJpY3RlciB2YWxpZGF0aW9uIHNob3VsZFxyXG4gICAqIGJlIGFwcGxpZWQuXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9IEEgWm9kIHNjaGVtYSBvYmplY3QgZm9yIHZhbGlkYXRpbmcgdGhlIGBiNjRgIG9wdGlvbi5cclxuICAgKi9cclxuICBiNjQoc3RyaWN0Q2hlY2spIHtcclxuICAgIHJldHVybiB2LmJvb2xlYW4oc3RyaWN0Q2hlY2spO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgbm9Eb3dubG9hZGAgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbFxyXG4gICAqIHN0cmljdGVyIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgdGhlIGBib29sZWFuYCB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gbm9Eb3dubG9hZFxyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nIHRoZSBgbm9Eb3dubG9hZGBcclxuICAgKiBvcHRpb24uXHJcbiAgICovXHJcbiAgbm9Eb3dubG9hZChzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHYuYm9vbGVhbihzdHJpY3RDaGVjayk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGBkZWZhdWx0SGVpZ2h0YCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoIGFuIG9wdGlvbmFsXHJcbiAgICogc3RyaWN0ZXIgY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhlIHNhbWUgd29yayBhcyB0aGUgYHBvc2l0aXZlTnVtYCB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gZGVmYXVsdEhlaWdodFxyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nXHJcbiAgICogdGhlIGBkZWZhdWx0SGVpZ2h0YCBvcHRpb24uXHJcbiAgICovXHJcbiAgZGVmYXVsdEhlaWdodChzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHYucG9zaXRpdmVOdW0oc3RyaWN0Q2hlY2spO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgZGVmYXVsdFdpZHRoYCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoIGFuIG9wdGlvbmFsXHJcbiAgICogc3RyaWN0ZXIgY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhlIHNhbWUgd29yayBhcyB0aGUgYHBvc2l0aXZlTnVtYCB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gZGVmYXVsdFdpZHRoXHJcbiAgICpcclxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IHN0cmljdENoZWNrIC0gRGV0ZXJtaW5lcyBpZiBzdHJpY3RlciB2YWxpZGF0aW9uIHNob3VsZFxyXG4gICAqIGJlIGFwcGxpZWQuXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9IEEgWm9kIHNjaGVtYSBvYmplY3QgZm9yIHZhbGlkYXRpbmdcclxuICAgKiB0aGUgYGRlZmF1bHRXaWR0aGAgb3B0aW9uLlxyXG4gICAqL1xyXG4gIGRlZmF1bHRXaWR0aChzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHYucG9zaXRpdmVOdW0oc3RyaWN0Q2hlY2spO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgZGVmYXVsdFNjYWxlYCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoIGFuIG9wdGlvbmFsXHJcbiAgICogc3RyaWN0ZXIgY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhhdDpcclxuICAgKlxyXG4gICAqIC0gV2hlbiBgc3RyaWN0Q2hlY2tgIGlzIHRydWUsIHRoZSBzY2hlbWEgd2lsbCBhY2NlcHQgbnVtYmVyIHZhbHVlcyB0aGF0XHJcbiAgICogYXJlIGJldHdlZW4gMC4xIGFuZCA1IChpbmNsdXNpdmUpLlxyXG4gICAqXHJcbiAgICogLSBXaGVuIGBzdHJpY3RDaGVja2AgaXMgZmFsc2UsIHRoZSBzY2hlbWEgd2lsbCBhY2NlcHQgbnVtYmVyIHZhbHVlc1xyXG4gICAqIGFuZCBzdHJpbmdpZmllZCBudW1iZXIgdmFsdWVzIHRoYXQgYXJlIGJldHdlZW4gMC4xIGFuZCA1IChpbmNsdXNpdmUpLCBudWxsLFxyXG4gICAqICd1bmRlZmluZWQnLCAnbnVsbCcsIGFuZCAnJyB3aGljaCB3aWxsIGJlIHRyYW5zZm9ybWVkIHRvIG51bGwuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gZGVmYXVsdFNjYWxlXHJcbiAgICpcclxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IHN0cmljdENoZWNrIC0gRGV0ZXJtaW5lcyBpZiBzdHJpY3RlciB2YWxpZGF0aW9uIHNob3VsZFxyXG4gICAqIGJlIGFwcGxpZWQuXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9IEEgWm9kIHNjaGVtYSBvYmplY3QgZm9yIHZhbGlkYXRpbmdcclxuICAgKiB0aGUgYGRlZmF1bHRTY2FsZWAgb3B0aW9uLlxyXG4gICAqL1xyXG4gIGRlZmF1bHRTY2FsZShzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHN0cmljdENoZWNrXHJcbiAgICAgID8gei5udW1iZXIoKS5ndGUoMC4xKS5sdGUoNSlcclxuICAgICAgOiB6XHJcbiAgICAgICAgICAudW5pb24oW1xyXG4gICAgICAgICAgICB6XHJcbiAgICAgICAgICAgICAgLnN0cmluZygpXHJcbiAgICAgICAgICAgICAgLnRyaW0oKVxyXG4gICAgICAgICAgICAgIC5yZWZpbmUoXHJcbiAgICAgICAgICAgICAgICAodmFsdWUpID0+XHJcbiAgICAgICAgICAgICAgICAgICghaXNOYU4oTnVtYmVyKHZhbHVlKSkgJiZcclxuICAgICAgICAgICAgICAgICAgICB2YWx1ZSAhPT0gdHJ1ZSAmJlxyXG4gICAgICAgICAgICAgICAgICAgICF2YWx1ZS5zdGFydHNXaXRoKCdbJykgJiZcclxuICAgICAgICAgICAgICAgICAgICBOdW1iZXIodmFsdWUpID49IDAuMSAmJlxyXG4gICAgICAgICAgICAgICAgICAgIE51bWJlcih2YWx1ZSkgPD0gNSkgfHxcclxuICAgICAgICAgICAgICAgICAgWyd1bmRlZmluZWQnLCAnbnVsbCcsICcnXS5pbmNsdWRlcyh2YWx1ZSksXHJcbiAgICAgICAgICAgICAgICB7XHJcbiAgICAgICAgICAgICAgICAgIHBhcmFtczoge1xyXG4gICAgICAgICAgICAgICAgICAgIGVycm9yTWVzc2FnZTogJ1RoZSB2YWx1ZSBtdXN0IGJlIHdpdGhpbiBhIDAuMSBhbmQgNS4wIHJhbmdlJ1xyXG4gICAgICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgICAgKVxyXG4gICAgICAgICAgICAgIC50cmFuc2Zvcm0oKHZhbHVlKSA9PlxyXG4gICAgICAgICAgICAgICAgIVsndW5kZWZpbmVkJywgJ251bGwnLCAnJ10uaW5jbHVkZXModmFsdWUpXHJcbiAgICAgICAgICAgICAgICAgID8gTnVtYmVyKHZhbHVlKVxyXG4gICAgICAgICAgICAgICAgICA6IG51bGxcclxuICAgICAgICAgICAgICApLFxyXG4gICAgICAgICAgICB6Lm51bWJlcigpLmd0ZSgwLjEpLmx0ZSg1KVxyXG4gICAgICAgICAgXSlcclxuICAgICAgICAgIC5udWxsYWJsZSgpO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgaGVpZ2h0YCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoIGFuIG9wdGlvbmFsIHN0cmljdGVyXHJcbiAgICogY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhlIHNhbWUgd29yayBhcyBhIG51bGxhYmxlIGBkZWZhdWx0SGVpZ2h0YFxyXG4gICAqIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiBoZWlnaHRcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZyB0aGUgYGhlaWdodGBcclxuICAgKiBvcHRpb24uXHJcbiAgICovXHJcbiAgaGVpZ2h0KHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gdGhpcy5kZWZhdWx0SGVpZ2h0KHN0cmljdENoZWNrKS5udWxsYWJsZSgpO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgd2lkdGhgIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGggYW4gb3B0aW9uYWwgc3RyaWN0ZXJcclxuICAgKiBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGUgc2FtZSB3b3JrIGFzIGEgbnVsbGFibGUgYGRlZmF1bHRXaWR0aGBcclxuICAgKiB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gd2lkdGhcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZyB0aGUgYHdpZHRoYFxyXG4gICAqIG9wdGlvbi5cclxuICAgKi9cclxuICB3aWR0aChzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHRoaXMuZGVmYXVsdFdpZHRoKHN0cmljdENoZWNrKS5udWxsYWJsZSgpO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgc2NhbGVgIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGggYW4gb3B0aW9uYWwgc3RyaWN0ZXJcclxuICAgKiBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGUgc2FtZSB3b3JrIGFzIGEgbnVsbGFibGUgYGRlZmF1bHRTY2FsZWBcclxuICAgKiB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gc2NhbGVcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZyB0aGUgYHNjYWxlYFxyXG4gICAqIG9wdGlvbi5cclxuICAgKi9cclxuICBzY2FsZShzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHRoaXMuZGVmYXVsdFNjYWxlKHN0cmljdENoZWNrKS5udWxsYWJsZSgpO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgZ2xvYmFsT3B0aW9uc2AgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGUgc2FtZSB3b3JrIGFzIHRoZSBgYWRkaXRpb25hbE9wdGlvbnNgXHJcbiAgICogdmFsaWRhdG9yLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIGdsb2JhbE9wdGlvbnNcclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZ1xyXG4gICAqIHRoZSBgZ2xvYmFsT3B0aW9uc2Agb3B0aW9uLlxyXG4gICAqL1xyXG4gIGdsb2JhbE9wdGlvbnMoKSB7XHJcbiAgICByZXR1cm4gdi5hZGRpdGlvbmFsT3B0aW9ucygpO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgdGhlbWVPcHRpb25zYCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYS5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgdGhlIGBhZGRpdGlvbmFsT3B0aW9uc2BcclxuICAgKiB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gdGhlbWVPcHRpb25zXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9IEEgWm9kIHNjaGVtYSBvYmplY3QgZm9yIHZhbGlkYXRpbmdcclxuICAgKiB0aGUgYHRoZW1lT3B0aW9uc2Agb3B0aW9uLlxyXG4gICAqL1xyXG4gIHRoZW1lT3B0aW9ucygpIHtcclxuICAgIHJldHVybiB2LmFkZGl0aW9uYWxPcHRpb25zKCk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGBiYXRjaGAgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbCBzdHJpY3RlclxyXG4gICAqIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgdGhlIGBzdHJpbmdgIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiBiYXRjaFxyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nIHRoZSBgYmF0Y2hgXHJcbiAgICogb3B0aW9uLlxyXG4gICAqL1xyXG4gIGJhdGNoKHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gdi5zdHJpbmcoc3RyaWN0Q2hlY2spO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgcmFzdGVyaXphdGlvblRpbWVvdXRgIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGhcclxuICAgKiBhbiBvcHRpb25hbCBzdHJpY3RlciBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGUgc2FtZSB3b3JrIGFzIHRoZSBgbm9uTmVnYXRpdmVOdW1gXHJcbiAgICogdmFsaWRhdG9yLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIHJhc3Rlcml6YXRpb25UaW1lb3V0XHJcbiAgICpcclxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IHN0cmljdENoZWNrIC0gRGV0ZXJtaW5lcyBpZiBzdHJpY3RlciB2YWxpZGF0aW9uIHNob3VsZFxyXG4gICAqIGJlIGFwcGxpZWQuXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9IEEgWm9kIHNjaGVtYSBvYmplY3QgZm9yIHZhbGlkYXRpbmdcclxuICAgKiB0aGUgYHJhc3Rlcml6YXRpb25UaW1lb3V0YCBvcHRpb24uXHJcbiAgICovXHJcbiAgcmFzdGVyaXphdGlvblRpbWVvdXQoc3RyaWN0Q2hlY2spIHtcclxuICAgIHJldHVybiB2Lm5vbk5lZ2F0aXZlTnVtKHN0cmljdENoZWNrKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYGFsbG93Q29kZUV4ZWN1dGlvbmAgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aFxyXG4gICAqIGFuIG9wdGlvbmFsIHN0cmljdGVyIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgdGhlIGBib29sZWFuYCB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gYWxsb3dDb2RlRXhlY3V0aW9uXHJcbiAgICpcclxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IHN0cmljdENoZWNrIC0gRGV0ZXJtaW5lcyBpZiBzdHJpY3RlciB2YWxpZGF0aW9uIHNob3VsZFxyXG4gICAqIGJlIGFwcGxpZWQuXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9IEEgWm9kIHNjaGVtYSBvYmplY3QgZm9yIHZhbGlkYXRpbmdcclxuICAgKiB0aGUgYGFsbG93Q29kZUV4ZWN1dGlvbmAgb3B0aW9uLlxyXG4gICAqL1xyXG4gIGFsbG93Q29kZUV4ZWN1dGlvbihzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHYuYm9vbGVhbihzdHJpY3RDaGVjayk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGBhbGxvd0ZpbGVSZXNvdXJjZXNgIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGhcclxuICAgKiBhbiBvcHRpb25hbCBzdHJpY3RlciBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGUgc2FtZSB3b3JrIGFzIHRoZSBgYm9vbGVhbmAgdmFsaWRhdG9yLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIGFsbG93RmlsZVJlc291cmNlc1xyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nXHJcbiAgICogdGhlIGBhbGxvd0ZpbGVSZXNvdXJjZXNgIG9wdGlvbi5cclxuICAgKi9cclxuICBhbGxvd0ZpbGVSZXNvdXJjZXMoc3RyaWN0Q2hlY2spIHtcclxuICAgIHJldHVybiB2LmJvb2xlYW4oc3RyaWN0Q2hlY2spO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgY3VzdG9tQ29kZWAgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbFxyXG4gICAqIHN0cmljdGVyIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgdGhlIGBzdHJpbmdgIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiBjdXN0b21Db2RlXHJcbiAgICpcclxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IHN0cmljdENoZWNrIC0gRGV0ZXJtaW5lcyBpZiBzdHJpY3RlciB2YWxpZGF0aW9uIHNob3VsZFxyXG4gICAqIGJlIGFwcGxpZWQuXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9IEEgWm9kIHNjaGVtYSBvYmplY3QgZm9yIHZhbGlkYXRpbmcgdGhlIGBjdXN0b21Db2RlYFxyXG4gICAqIG9wdGlvbi5cclxuICAgKi9cclxuICBjdXN0b21Db2RlKHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gdi5zdHJpbmcoc3RyaWN0Q2hlY2spO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgY2FsbGJhY2tgIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGggYW4gb3B0aW9uYWxcclxuICAgKiBzdHJpY3RlciBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGUgc2FtZSB3b3JrIGFzIHRoZSBgc3RyaW5nYCB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gY2FsbGJhY2tcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZyB0aGUgYGNhbGxiYWNrYFxyXG4gICAqIG9wdGlvbi5cclxuICAgKi9cclxuICBjYWxsYmFjayhzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHYuc3RyaW5nKHN0cmljdENoZWNrKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYHJlc291cmNlc2AgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbFxyXG4gICAqIHN0cmljdGVyIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoYXQ6XHJcbiAgICpcclxuICAgKiAtIFdoZW4gYHN0cmljdENoZWNrYCBpcyB0cnVlLCB0aGUgc2NoZW1hIHdpbGwgYWNjZXB0IGEgcGFydGlhbCBvYmplY3RcclxuICAgKiB3aXRoIGFsbG93ZWQgcHJvcGVydGllcyBganNgLCBgY3NzYCwgYW5kIGBmaWxlc2Agd2hlcmUgZWFjaCBvZiB0aGUgYWxsb3dlZFxyXG4gICAqIHByb3BlcnRpZXMgY2FuIGJlIG51bGwsIHN0cmluZ2lmaWVkIHZlcnNpb24gb2YgdGhlIG9iamVjdCwgc3RyaW5nIHRoYXQgZW5kc1xyXG4gICAqIHdpdGggdGhlICcuanNvbicsIGFuZCBudWxsLlxyXG4gICAqXHJcbiAgICogLSBXaGVuIGBzdHJpY3RDaGVja2AgaXMgZmFsc2UsIHRoZSBzY2hlbWEgd2lsbCBhY2NlcHQgYSBzdHJpbmdpZmllZCB2ZXJzaW9uXHJcbiAgICogb2YgYSBwYXJ0aWFsIG9iamVjdCB3aXRoIGFsbG93ZWQgcHJvcGVydGllcyBganNgLCBgY3NzYCwgYW5kIGBmaWxlc2Agd2hlcmVcclxuICAgKiBlYWNoIG9mIHRoZSBhbGxvd2VkIHByb3BlcnRpZXMgY2FuIGJlIG51bGwsIHN0cmluZyB0aGF0IGVuZHMgd2l0aCB0aGVcclxuICAgKiAnLmpzb24nLCBhbmQgd2lsbCBiZSBudWxsIGlmIHRoZSBwcm92aWRlZCB2YWx1ZSBpcyAndW5kZWZpbmVkJywgJ251bGwnXHJcbiAgICogb3IgJycuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gcmVzb3VyY2VzXHJcbiAgICpcclxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IHN0cmljdENoZWNrIC0gRGV0ZXJtaW5lcyBpZiBzdHJpY3RlciB2YWxpZGF0aW9uIHNob3VsZFxyXG4gICAqIGJlIGFwcGxpZWQuXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9IEEgWm9kIHNjaGVtYSBvYmplY3QgZm9yIHZhbGlkYXRpbmcgdGhlIGByZXNvdXJjZXNgXHJcbiAgICogb3B0aW9uLlxyXG4gICAqL1xyXG4gIHJlc291cmNlcyhzdHJpY3RDaGVjaykge1xyXG4gICAgY29uc3Qgb2JqZWN0U2NoZW1hID0gelxyXG4gICAgICAub2JqZWN0KHtcclxuICAgICAgICBqczogdi5zdHJpbmcoZmFsc2UpLFxyXG4gICAgICAgIGNzczogdi5zdHJpbmcoZmFsc2UpLFxyXG4gICAgICAgIGZpbGVzOiB2XHJcbiAgICAgICAgICAuc3RyaW5nQXJyYXkoXHJcbiAgICAgICAgICAgICh2YWx1ZSkgPT4gIVsndW5kZWZpbmVkJywgJ251bGwnLCAnJ10uaW5jbHVkZXModmFsdWUpLFxyXG4gICAgICAgICAgICAnLCcsXHJcbiAgICAgICAgICAgIHRydWVcclxuICAgICAgICAgIClcclxuICAgICAgICAgIC5udWxsYWJsZSgpXHJcbiAgICAgIH0pXHJcbiAgICAgIC5wYXJ0aWFsKCk7XHJcblxyXG4gICAgY29uc3Qgc3RyaW5nU2NoZW1hMSA9IHpcclxuICAgICAgLnN0cmluZygpXHJcbiAgICAgIC50cmltKClcclxuICAgICAgLnJlZmluZShcclxuICAgICAgICAodmFsdWUpID0+XHJcbiAgICAgICAgICAodmFsdWUuc3RhcnRzV2l0aCgneycpICYmIHZhbHVlLmVuZHNXaXRoKCd9JykpIHx8XHJcbiAgICAgICAgICAodmFsdWUubGVuZ3RoID49IDYgJiYgdmFsdWUuZW5kc1dpdGgoJy5qc29uJykpLFxyXG4gICAgICAgIHtcclxuICAgICAgICAgIHBhcmFtczoge1xyXG4gICAgICAgICAgICBlcnJvck1lc3NhZ2U6XHJcbiAgICAgICAgICAgICAgXCJUaGUgdmFsdWUgbXVzdCBiZSBhIHN0cmluZyB0aGF0IHN0YXJ0cyB3aXRoICd7JyBhbmQgZW5kcyB3aXRoICd9XCJcclxuICAgICAgICAgIH1cclxuICAgICAgICB9XHJcbiAgICAgICk7XHJcblxyXG4gICAgY29uc3Qgc3RyaW5nU2NoZW1hMiA9IHpcclxuICAgICAgLnN0cmluZygpXHJcbiAgICAgIC50cmltKClcclxuICAgICAgLnJlZmluZShcclxuICAgICAgICAodmFsdWUpID0+XHJcbiAgICAgICAgICAodmFsdWUuc3RhcnRzV2l0aCgneycpICYmIHZhbHVlLmVuZHNXaXRoKCd9JykpIHx8XHJcbiAgICAgICAgICAodmFsdWUubGVuZ3RoID49IDYgJiYgdmFsdWUuZW5kc1dpdGgoJy5qc29uJykpIHx8XHJcbiAgICAgICAgICBbJ3VuZGVmaW5lZCcsICdudWxsJywgJyddLmluY2x1ZGVzKHZhbHVlKSxcclxuICAgICAgICB7XHJcbiAgICAgICAgICBwYXJhbXM6IHtcclxuICAgICAgICAgICAgZXJyb3JNZXNzYWdlOiAnVGhlIHZhbHVlIG11c3QgYmUgYSBzdHJpbmcgdGhhdCBlbmRzIHdpdGggLmpzb24nXHJcbiAgICAgICAgICB9XHJcbiAgICAgICAgfVxyXG4gICAgICApXHJcbiAgICAgIC50cmFuc2Zvcm0oKHZhbHVlKSA9PlxyXG4gICAgICAgICFbJ3VuZGVmaW5lZCcsICdudWxsJywgJyddLmluY2x1ZGVzKHZhbHVlKSA/IHZhbHVlIDogbnVsbFxyXG4gICAgICApO1xyXG5cclxuICAgIHJldHVybiBzdHJpY3RDaGVja1xyXG4gICAgICA/IHoudW5pb24oW29iamVjdFNjaGVtYSwgc3RyaW5nU2NoZW1hMV0pLm51bGxhYmxlKClcclxuICAgICAgOiB6LnVuaW9uKFtvYmplY3RTY2hlbWEsIHN0cmluZ1NjaGVtYTJdKS5udWxsYWJsZSgpO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgbG9hZENvbmZpZ2AgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbFxyXG4gICAqIHN0cmljdGVyIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgdGhlIGBzdHJpbmdgIHZhbGlkYXRvci5cclxuICAgKiBBZGRpdGlvbmFsbHksIGl0IG11c3QgYmUgYSBzdHJpbmcgdGhhdCBlbmRzIHdpdGggJy5qc29uJy5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiBsb2FkQ29uZmlnXHJcbiAgICpcclxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IHN0cmljdENoZWNrIC0gRGV0ZXJtaW5lcyBpZiBzdHJpY3RlciB2YWxpZGF0aW9uIHNob3VsZFxyXG4gICAqIGJlIGFwcGxpZWQuXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9IEEgWm9kIHNjaGVtYSBvYmplY3QgZm9yIHZhbGlkYXRpbmcgdGhlIGBsb2FkQ29uZmlnYFxyXG4gICAqIG9wdGlvbi5cclxuICAgKi9cclxuICBsb2FkQ29uZmlnKHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gdlxyXG4gICAgICAuc3RyaW5nKHN0cmljdENoZWNrKVxyXG4gICAgICAucmVmaW5lKFxyXG4gICAgICAgICh2YWx1ZSkgPT5cclxuICAgICAgICAgIHZhbHVlID09PSBudWxsIHx8ICh2YWx1ZS5sZW5ndGggPj0gNiAmJiB2YWx1ZS5lbmRzV2l0aCgnLmpzb24nKSksXHJcbiAgICAgICAge1xyXG4gICAgICAgICAgcGFyYW1zOiB7XHJcbiAgICAgICAgICAgIGVycm9yTWVzc2FnZTogJ1RoZSB2YWx1ZSBtdXN0IGJlIGEgc3RyaW5nIHRoYXQgZW5kcyB3aXRoIC5qc29uJ1xyXG4gICAgICAgICAgfVxyXG4gICAgICAgIH1cclxuICAgICAgKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYGNyZWF0ZUNvbmZpZ2AgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbFxyXG4gICAqIHN0cmljdGVyIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgdGhlIGBsb2FkQ29uZmlnYCB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gY3JlYXRlQ29uZmlnXHJcbiAgICpcclxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IHN0cmljdENoZWNrIC0gRGV0ZXJtaW5lcyBpZiBzdHJpY3RlciB2YWxpZGF0aW9uIHNob3VsZFxyXG4gICAqIGJlIGFwcGxpZWQuXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9IEEgWm9kIHNjaGVtYSBvYmplY3QgZm9yIHZhbGlkYXRpbmdcclxuICAgKiB0aGUgYGNyZWF0ZUNvbmZpZ2Agb3B0aW9uLlxyXG4gICAqL1xyXG4gIGNyZWF0ZUNvbmZpZyhzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHRoaXMubG9hZENvbmZpZyhzdHJpY3RDaGVjayk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGBlbmFibGVTZXJ2ZXJgIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGggYW4gb3B0aW9uYWxcclxuICAgKiBzdHJpY3RlciBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGUgc2FtZSB3b3JrIGFzIHRoZSBgYm9vbGVhbmAgdmFsaWRhdG9yLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIGVuYWJsZVNlcnZlclxyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nXHJcbiAgICogdGhlIGBlbmFibGVTZXJ2ZXJgIG9wdGlvbi5cclxuICAgKi9cclxuICBlbmFibGVTZXJ2ZXIoc3RyaWN0Q2hlY2spIHtcclxuICAgIHJldHVybiB2LmJvb2xlYW4oc3RyaWN0Q2hlY2spO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgaG9zdGAgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbCBzdHJpY3RlclxyXG4gICAqIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgdGhlIGBzdHJpbmdgIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiBob3N0XHJcbiAgICpcclxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IHN0cmljdENoZWNrIC0gRGV0ZXJtaW5lcyBpZiBzdHJpY3RlciB2YWxpZGF0aW9uIHNob3VsZFxyXG4gICAqIGJlIGFwcGxpZWQuXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9IEEgWm9kIHNjaGVtYSBvYmplY3QgZm9yIHZhbGlkYXRpbmcgdGhlIGBob3N0YFxyXG4gICAqIG9wdGlvbi5cclxuICAgKi9cclxuICBob3N0KHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gdi5zdHJpbmcoc3RyaWN0Q2hlY2spO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgcG9ydGAgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbCBzdHJpY3RlclxyXG4gICAqIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgdGhlIGBub25OZWdhdGl2ZU51bWBcclxuICAgKiB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gcG9ydFxyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nIHRoZSBgcG9ydGBcclxuICAgKiBvcHRpb24uXHJcbiAgICovXHJcbiAgcG9ydChzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHYubm9uTmVnYXRpdmVOdW0oc3RyaWN0Q2hlY2spO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgdXBsb2FkTGltaXRgIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGggYW4gb3B0aW9uYWxcclxuICAgKiBzdHJpY3RlciBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGUgc2FtZSB3b3JrIGFzIHRoZSBgcG9zaXRpdmVOdW1gIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiB1cGxvYWRMaW1pdFxyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nIHRoZSBgdXBsb2FkTGltaXRgXHJcbiAgICogb3B0aW9uLlxyXG4gICAqL1xyXG4gIHVwbG9hZExpbWl0KHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gdi5wb3NpdGl2ZU51bShzdHJpY3RDaGVjayk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGBzZXJ2ZXJCZW5jaG1hcmtpbmdgIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGhcclxuICAgKiBhbiBvcHRpb25hbCBzdHJpY3RlciBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGUgc2FtZSB3b3JrIGFzIHRoZSBgYm9vbGVhbmAgdmFsaWRhdG9yLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIHNlcnZlckJlbmNobWFya2luZ1xyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nXHJcbiAgICogdGhlIGBzZXJ2ZXJCZW5jaG1hcmtpbmdgIG9wdGlvbi5cclxuICAgKi9cclxuICBzZXJ2ZXJCZW5jaG1hcmtpbmcoc3RyaWN0Q2hlY2spIHtcclxuICAgIHJldHVybiB2LmJvb2xlYW4oc3RyaWN0Q2hlY2spO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgcHJveHlIb3N0YCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoIGFuIG9wdGlvbmFsXHJcbiAgICogc3RyaWN0ZXIgY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhlIHNhbWUgd29yayBhcyB0aGUgYHN0cmluZ2AgdmFsaWRhdG9yLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIHByb3h5SG9zdFxyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nIHRoZSBgcHJveHlIb3N0YFxyXG4gICAqIG9wdGlvbi5cclxuICAgKi9cclxuICBwcm94eUhvc3Qoc3RyaWN0Q2hlY2spIHtcclxuICAgIHJldHVybiB2LnN0cmluZyhzdHJpY3RDaGVjayk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGBwcm94eVBvcnRgIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGggYW4gb3B0aW9uYWxcclxuICAgKiBzdHJpY3RlciBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGUgc2FtZSB3b3JrIGFzIGEgbnVsbGFibGUgYG5vbk5lZ2F0aXZlTnVtYFxyXG4gICAqIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiBwcm94eVBvcnRcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZyB0aGUgYHByb3h5UG9ydGBcclxuICAgKiBvcHRpb24uXHJcbiAgICovXHJcbiAgcHJveHlQb3J0KHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gdi5ub25OZWdhdGl2ZU51bShzdHJpY3RDaGVjaykubnVsbGFibGUoKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYHByb3h5VGltZW91dGAgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbFxyXG4gICAqIHN0cmljdGVyIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgdGhlIGBub25OZWdhdGl2ZU51bWBcclxuICAgKiB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gcHJveHlUaW1lb3V0XHJcbiAgICpcclxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IHN0cmljdENoZWNrIC0gRGV0ZXJtaW5lcyBpZiBzdHJpY3RlciB2YWxpZGF0aW9uIHNob3VsZFxyXG4gICAqIGJlIGFwcGxpZWQuXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9IEEgWm9kIHNjaGVtYSBvYmplY3QgZm9yIHZhbGlkYXRpbmdcclxuICAgKiB0aGUgYHByb3h5VGltZW91dGAgb3B0aW9uLlxyXG4gICAqL1xyXG4gIHByb3h5VGltZW91dChzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHYubm9uTmVnYXRpdmVOdW0oc3RyaWN0Q2hlY2spO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgZW5hYmxlUmF0ZUxpbWl0aW5nYCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoXHJcbiAgICogYW4gb3B0aW9uYWwgc3RyaWN0ZXIgY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhlIHNhbWUgd29yayBhcyB0aGUgYGJvb2xlYW5gIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiBlbmFibGVSYXRlTGltaXRpbmdcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZ1xyXG4gICAqIHRoZSBgZW5hYmxlUmF0ZUxpbWl0aW5nYCBvcHRpb24uXHJcbiAgICovXHJcbiAgZW5hYmxlUmF0ZUxpbWl0aW5nKHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gdi5ib29sZWFuKHN0cmljdENoZWNrKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYG1heFJlcXVlc3RzYCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoIGFuIG9wdGlvbmFsXHJcbiAgICogc3RyaWN0ZXIgY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhlIHNhbWUgd29yayBhcyB0aGUgYG5vbk5lZ2F0aXZlTnVtYFxyXG4gICAqIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiBtYXhSZXF1ZXN0c1xyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nIHRoZSBgbWF4UmVxdWVzdHNgXHJcbiAgICogb3B0aW9uLlxyXG4gICAqL1xyXG4gIG1heFJlcXVlc3RzKHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gdi5ub25OZWdhdGl2ZU51bShzdHJpY3RDaGVjayk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGB3aW5kb3dgIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGggYW4gb3B0aW9uYWwgc3RyaWN0ZXJcclxuICAgKiBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGUgc2FtZSB3b3JrIGFzIHRoZSBgbm9uTmVnYXRpdmVOdW1gXHJcbiAgICogdmFsaWRhdG9yLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIHdpbmRvd1xyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nIHRoZSBgd2luZG93YFxyXG4gICAqIG9wdGlvbi5cclxuICAgKi9cclxuICB3aW5kb3coc3RyaWN0Q2hlY2spIHtcclxuICAgIHJldHVybiB2Lm5vbk5lZ2F0aXZlTnVtKHN0cmljdENoZWNrKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYGRlbGF5YCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoIGFuIG9wdGlvbmFsIHN0cmljdGVyXHJcbiAgICogY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhlIHNhbWUgd29yayBhcyB0aGUgYG5vbk5lZ2F0aXZlTnVtYFxyXG4gICAqIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiBkZWxheVxyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nIHRoZSBgZGVsYXlgXHJcbiAgICogb3B0aW9uLlxyXG4gICAqL1xyXG4gIGRlbGF5KHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gdi5ub25OZWdhdGl2ZU51bShzdHJpY3RDaGVjayk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGB0cnVzdFByb3h5YCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoIGFuIG9wdGlvbmFsXHJcbiAgICogc3RyaWN0ZXIgY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhlIHNhbWUgd29yayBhcyB0aGUgYGJvb2xlYW5gIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiB0cnVzdFByb3h5XHJcbiAgICpcclxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IHN0cmljdENoZWNrIC0gRGV0ZXJtaW5lcyBpZiBzdHJpY3RlciB2YWxpZGF0aW9uIHNob3VsZFxyXG4gICAqIGJlIGFwcGxpZWQuXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9IEEgWm9kIHNjaGVtYSBvYmplY3QgZm9yIHZhbGlkYXRpbmcgdGhlIGB0cnVzdFByb3h5YFxyXG4gICAqIG9wdGlvbi5cclxuICAgKi9cclxuICB0cnVzdFByb3h5KHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gdi5ib29sZWFuKHN0cmljdENoZWNrKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYHNraXBLZXlgIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGggYW4gb3B0aW9uYWwgc3RyaWN0ZXJcclxuICAgKiBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGUgc2FtZSB3b3JrIGFzIHRoZSBgc3RyaW5nYCB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gc2tpcEtleVxyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nIHRoZSBgc2tpcEtleWBcclxuICAgKiBvcHRpb24uXHJcbiAgICovXHJcbiAgc2tpcEtleShzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHYuc3RyaW5nKHN0cmljdENoZWNrKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYHNraXBUb2tlbmAgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbFxyXG4gICAqIHN0cmljdGVyIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgdGhlIGBzdHJpbmdgIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiBza2lwVG9rZW5cclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZyB0aGUgYHNraXBUb2tlbmBcclxuICAgKiBvcHRpb24uXHJcbiAgICovXHJcbiAgc2tpcFRva2VuKHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gdi5zdHJpbmcoc3RyaWN0Q2hlY2spO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgZW5hYmxlU3NsYCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoIGFuIG9wdGlvbmFsXHJcbiAgICogc3RyaWN0ZXIgY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhlIHNhbWUgd29yayBhcyB0aGUgYGJvb2xlYW5gIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiBlbmFibGVTc2xcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZyB0aGUgYGVuYWJsZVNzbGBcclxuICAgKiBvcHRpb24uXHJcbiAgICovXHJcbiAgZW5hYmxlU3NsKHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gdi5ib29sZWFuKHN0cmljdENoZWNrKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYHNzbEZvcmNlYCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoIGFuIG9wdGlvbmFsXHJcbiAgICogc3RyaWN0ZXIgY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhlIHNhbWUgd29yayBhcyB0aGUgYGJvb2xlYW5gIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiBzc2xGb3JjZVxyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nIHRoZSBgc3NsRm9yY2VgXHJcbiAgICogb3B0aW9uLlxyXG4gICAqL1xyXG4gIHNzbEZvcmNlKHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gdi5ib29sZWFuKHN0cmljdENoZWNrKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYHNzbFBvcnRgIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGggYW4gb3B0aW9uYWwgc3RyaWN0ZXJcclxuICAgKiBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGUgc2FtZSB3b3JrIGFzIHRoZSBgbm9uTmVnYXRpdmVOdW1gXHJcbiAgICogdmFsaWRhdG9yLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIHNzbFBvcnRcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZyB0aGUgYHNzbFBvcnRgXHJcbiAgICogb3B0aW9uLlxyXG4gICAqL1xyXG4gIHNzbFBvcnQoc3RyaWN0Q2hlY2spIHtcclxuICAgIHJldHVybiB2Lm5vbk5lZ2F0aXZlTnVtKHN0cmljdENoZWNrKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYHNzbENlcnRQYXRoYCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoIGFuIG9wdGlvbmFsXHJcbiAgICogc3RyaWN0ZXIgY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhlIHNhbWUgd29yayBhcyB0aGUgYHN0cmluZ2AgdmFsaWRhdG9yLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIHNzbENlcnRQYXRoXHJcbiAgICpcclxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IHN0cmljdENoZWNrIC0gRGV0ZXJtaW5lcyBpZiBzdHJpY3RlciB2YWxpZGF0aW9uIHNob3VsZFxyXG4gICAqIGJlIGFwcGxpZWQuXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9IEEgWm9kIHNjaGVtYSBvYmplY3QgZm9yIHZhbGlkYXRpbmcgdGhlIGBzc2xDZXJ0UGF0aGBcclxuICAgKiBvcHRpb24uXHJcbiAgICovXHJcbiAgc3NsQ2VydFBhdGgoc3RyaWN0Q2hlY2spIHtcclxuICAgIHJldHVybiB2LnN0cmluZyhzdHJpY3RDaGVjayk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGBtaW5Xb3JrZXJzYCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoIGFuIG9wdGlvbmFsXHJcbiAgICogc3RyaWN0ZXIgY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhlIHNhbWUgd29yayBhcyB0aGUgYHBvc2l0aXZlTnVtYCB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gbWluV29ya2Vyc1xyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nIHRoZSBgbWluV29ya2Vyc2BcclxuICAgKiBvcHRpb24uXHJcbiAgICovXHJcbiAgbWluV29ya2VycyhzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHYucG9zaXRpdmVOdW0oc3RyaWN0Q2hlY2spO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgbWF4V29ya2Vyc2AgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbFxyXG4gICAqIHN0cmljdGVyIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgdGhlIGBwb3NpdGl2ZU51bWAgdmFsaWRhdG9yLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIG1heFdvcmtlcnNcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZyB0aGUgYG1heFdvcmtlcnNgXHJcbiAgICogb3B0aW9uLlxyXG4gICAqL1xyXG4gIG1heFdvcmtlcnMoc3RyaWN0Q2hlY2spIHtcclxuICAgIHJldHVybiB2LnBvc2l0aXZlTnVtKHN0cmljdENoZWNrKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYHdvcmtMaW1pdGAgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbFxyXG4gICAqIHN0cmljdGVyIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgdGhlIGBwb3NpdGl2ZU51bWAgdmFsaWRhdG9yLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIHdvcmtMaW1pdFxyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nIHRoZSBgd29ya0xpbWl0YFxyXG4gICAqIG9wdGlvbi5cclxuICAgKi9cclxuICB3b3JrTGltaXQoc3RyaWN0Q2hlY2spIHtcclxuICAgIHJldHVybiB2LnBvc2l0aXZlTnVtKHN0cmljdENoZWNrKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYGFjcXVpcmVUaW1lb3V0YCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoIGFuIG9wdGlvbmFsXHJcbiAgICogc3RyaWN0ZXIgY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhlIHNhbWUgd29yayBhcyB0aGUgYG5vbk5lZ2F0aXZlTnVtYFxyXG4gICAqIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiBhY3F1aXJlVGltZW91dFxyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nXHJcbiAgICogdGhlIGBhY3F1aXJlVGltZW91dGAgb3B0aW9uLlxyXG4gICAqL1xyXG4gIGFjcXVpcmVUaW1lb3V0KHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gdi5ub25OZWdhdGl2ZU51bShzdHJpY3RDaGVjayk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGBjcmVhdGVUaW1lb3V0YCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoIGFuIG9wdGlvbmFsXHJcbiAgICogc3RyaWN0ZXIgY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhlIHNhbWUgd29yayBhcyB0aGUgYG5vbk5lZ2F0aXZlTnVtYFxyXG4gICAqIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiBjcmVhdGVUaW1lb3V0XHJcbiAgICpcclxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IHN0cmljdENoZWNrIC0gRGV0ZXJtaW5lcyBpZiBzdHJpY3RlciB2YWxpZGF0aW9uIHNob3VsZFxyXG4gICAqIGJlIGFwcGxpZWQuXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9IEEgWm9kIHNjaGVtYSBvYmplY3QgZm9yIHZhbGlkYXRpbmdcclxuICAgKiB0aGUgYGNyZWF0ZVRpbWVvdXRgIG9wdGlvbi5cclxuICAgKi9cclxuICBjcmVhdGVUaW1lb3V0KHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gdi5ub25OZWdhdGl2ZU51bShzdHJpY3RDaGVjayk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGBkZXN0cm95VGltZW91dGAgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbFxyXG4gICAqIHN0cmljdGVyIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgdGhlIGBub25OZWdhdGl2ZU51bWBcclxuICAgKiB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gZGVzdHJveVRpbWVvdXRcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZ1xyXG4gICAqIHRoZSBgZGVzdHJveVRpbWVvdXRgIG9wdGlvbi5cclxuICAgKi9cclxuICBkZXN0cm95VGltZW91dChzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHYubm9uTmVnYXRpdmVOdW0oc3RyaWN0Q2hlY2spO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgaWRsZVRpbWVvdXRgIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGggYW4gb3B0aW9uYWxcclxuICAgKiBzdHJpY3RlciBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGUgc2FtZSB3b3JrIGFzIHRoZSBgbm9uTmVnYXRpdmVOdW1gXHJcbiAgICogdmFsaWRhdG9yLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIGlkbGVUaW1lb3V0XHJcbiAgICpcclxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IHN0cmljdENoZWNrIC0gRGV0ZXJtaW5lcyBpZiBzdHJpY3RlciB2YWxpZGF0aW9uIHNob3VsZFxyXG4gICAqIGJlIGFwcGxpZWQuXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9IEEgWm9kIHNjaGVtYSBvYmplY3QgZm9yIHZhbGlkYXRpbmdcclxuICAgKiB0aGUgYGlkbGVUaW1lb3V0YCBvcHRpb24uXHJcbiAgICovXHJcbiAgaWRsZVRpbWVvdXQoc3RyaWN0Q2hlY2spIHtcclxuICAgIHJldHVybiB2Lm5vbk5lZ2F0aXZlTnVtKHN0cmljdENoZWNrKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYGNyZWF0ZVJldHJ5SW50ZXJ2YWxgIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGhcclxuICAgKiBhbiBvcHRpb25hbCBzdHJpY3RlciBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGUgc2FtZSB3b3JrIGFzIHRoZSBgbm9uTmVnYXRpdmVOdW1gXHJcbiAgICogdmFsaWRhdG9yLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIGNyZWF0ZVJldHJ5SW50ZXJ2YWxcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZ1xyXG4gICAqIHRoZSBgY3JlYXRlUmV0cnlJbnRlcnZhbGAgb3B0aW9uLlxyXG4gICAqL1xyXG4gIGNyZWF0ZVJldHJ5SW50ZXJ2YWwoc3RyaWN0Q2hlY2spIHtcclxuICAgIHJldHVybiB2Lm5vbk5lZ2F0aXZlTnVtKHN0cmljdENoZWNrKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYHJlYXBlckludGVydmFsYCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoIGFuIG9wdGlvbmFsXHJcbiAgICogc3RyaWN0ZXIgY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhlIHNhbWUgd29yayBhcyB0aGUgYG5vbk5lZ2F0aXZlTnVtYFxyXG4gICAqIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiByZWFwZXJJbnRlcnZhbFxyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nXHJcbiAgICogdGhlIGByZWFwZXJJbnRlcnZhbGAgb3B0aW9uLlxyXG4gICAqL1xyXG4gIHJlYXBlckludGVydmFsKHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gdi5ub25OZWdhdGl2ZU51bShzdHJpY3RDaGVjayk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGBwb29sQmVuY2htYXJraW5nYCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoIGFuIG9wdGlvbmFsXHJcbiAgICogc3RyaWN0ZXIgY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhlIHNhbWUgd29yayBhcyB0aGUgYGJvb2xlYW5gIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiBwb29sQmVuY2htYXJraW5nXHJcbiAgICpcclxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IHN0cmljdENoZWNrIC0gRGV0ZXJtaW5lcyBpZiBzdHJpY3RlciB2YWxpZGF0aW9uIHNob3VsZFxyXG4gICAqIGJlIGFwcGxpZWQuXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9IEEgWm9kIHNjaGVtYSBvYmplY3QgZm9yIHZhbGlkYXRpbmdcclxuICAgKiB0aGUgYHBvb2xCZW5jaG1hcmtpbmdgIG9wdGlvbi5cclxuICAgKi9cclxuICBwb29sQmVuY2htYXJraW5nKHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gdi5ib29sZWFuKHN0cmljdENoZWNrKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYHJlc291cmNlc0ludGVydmFsYCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoXHJcbiAgICogYW4gb3B0aW9uYWwgc3RyaWN0ZXIgY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhlIHNhbWUgd29yayBhcyB0aGUgYG5vbk5lZ2F0aXZlTnVtYFxyXG4gICAqIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiByZXNvdXJjZXNJbnRlcnZhbFxyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nXHJcbiAgICogdGhlIGByZXNvdXJjZXNJbnRlcnZhbGAgb3B0aW9uLlxyXG4gICAqL1xyXG4gIHJlc291cmNlc0ludGVydmFsKHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gdi5ub25OZWdhdGl2ZU51bShzdHJpY3RDaGVjayk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGBsb2dMZXZlbGAgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbFxyXG4gICAqIHN0cmljdGVyIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoYXQ6XHJcbiAgICpcclxuICAgKiAtIFdoZW4gYHN0cmljdENoZWNrYCBpcyB0cnVlLCB0aGUgc2NoZW1hIHdpbGwgYWNjZXB0IGludGVnZXIgbnVtYmVyIHZhbHVlc1xyXG4gICAqIHRoYXQgYXJlIGJldHdlZW4gMCBhbmQgNSAoaW5jbHVzaXZlKS5cclxuICAgKlxyXG4gICAqIC0gV2hlbiBgc3RyaWN0Q2hlY2tgIGlzIGZhbHNlLCB0aGUgc2NoZW1hIHdpbGwgYWNjZXB0IGludGVnZXIgbnVtYmVyIHZhbHVlc1xyXG4gICAqIGFuZCBzdHJpbmdpZmllZCBpbnRlZ2VyIG51bWJlciB2YWx1ZXMgdGhhdCBhcmUgYmV0d2VlbiAxIGFuZCA1IChpbmNsdXNpdmUpLFxyXG4gICAqIG51bGwsICd1bmRlZmluZWQnLCAnbnVsbCcsIGFuZCAnJyB3aGljaCB3aWxsIGJlIHRyYW5zZm9ybWVkIHRvIG51bGwuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gbG9nTGV2ZWxcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZyB0aGUgYGxvZ0xldmVsYFxyXG4gICAqIG9wdGlvbi5cclxuICAgKi9cclxuICBsb2dMZXZlbChzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHN0cmljdENoZWNrXHJcbiAgICAgID8gei5udW1iZXIoKS5pbnQoKS5ndGUoMCkubHRlKDUpXHJcbiAgICAgIDogelxyXG4gICAgICAgICAgLnVuaW9uKFtcclxuICAgICAgICAgICAgelxyXG4gICAgICAgICAgICAgIC5zdHJpbmcoKVxyXG4gICAgICAgICAgICAgIC50cmltKClcclxuICAgICAgICAgICAgICAucmVmaW5lKFxyXG4gICAgICAgICAgICAgICAgKHZhbHVlKSA9PlxyXG4gICAgICAgICAgICAgICAgICAoIWlzTmFOKE51bWJlcih2YWx1ZSkpICYmXHJcbiAgICAgICAgICAgICAgICAgICAgdmFsdWUgIT09IHRydWUgJiZcclxuICAgICAgICAgICAgICAgICAgICAhdmFsdWUuc3RhcnRzV2l0aCgnWycpICYmXHJcbiAgICAgICAgICAgICAgICAgICAgTnVtYmVyLmlzSW50ZWdlcihOdW1iZXIodmFsdWUpKSAmJlxyXG4gICAgICAgICAgICAgICAgICAgIE51bWJlcih2YWx1ZSkgPj0gMCAmJlxyXG4gICAgICAgICAgICAgICAgICAgIE51bWJlcih2YWx1ZSkgPD0gNSkgfHxcclxuICAgICAgICAgICAgICAgICAgWyd1bmRlZmluZWQnLCAnbnVsbCcsICcnXS5pbmNsdWRlcyh2YWx1ZSksXHJcbiAgICAgICAgICAgICAgICB7XHJcbiAgICAgICAgICAgICAgICAgIHBhcmFtczoge1xyXG4gICAgICAgICAgICAgICAgICAgIGVycm9yTWVzc2FnZTogJ1RoZSB2YWx1ZSBtdXN0IGJlIHdpdGhpbiBhIDAgYW5kIDUgcmFuZ2UnXHJcbiAgICAgICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgICApXHJcbiAgICAgICAgICAgICAgLnRyYW5zZm9ybSgodmFsdWUpID0+XHJcbiAgICAgICAgICAgICAgICAhWyd1bmRlZmluZWQnLCAnbnVsbCcsICcnXS5pbmNsdWRlcyh2YWx1ZSlcclxuICAgICAgICAgICAgICAgICAgPyBOdW1iZXIodmFsdWUpXHJcbiAgICAgICAgICAgICAgICAgIDogbnVsbFxyXG4gICAgICAgICAgICAgICksXHJcbiAgICAgICAgICAgIHoubnVtYmVyKCkuaW50KCkuZ3RlKDApLmx0ZSg1KVxyXG4gICAgICAgICAgXSlcclxuICAgICAgICAgIC5udWxsYWJsZSgpO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgbG9nRmlsZWAgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbCBzdHJpY3RlclxyXG4gICAqIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgdGhlIGBzdHJpbmdgIHZhbGlkYXRvci5cclxuICAgKiBBZGRpdGlvbmFsbHksIGl0IG11c3QgYmUgYSBzdHJpbmcgdGhhdCBlbmRzIHdpdGggJy5sb2cnLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIGxvZ0ZpbGVcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZyB0aGUgYGxvZ0ZpbGVgXHJcbiAgICogb3B0aW9uLlxyXG4gICAqL1xyXG4gIGxvZ0ZpbGUoc3RyaWN0Q2hlY2spIHtcclxuICAgIHJldHVybiB2XHJcbiAgICAgIC5zdHJpbmcoc3RyaWN0Q2hlY2spXHJcbiAgICAgIC5yZWZpbmUoXHJcbiAgICAgICAgKHZhbHVlKSA9PlxyXG4gICAgICAgICAgdmFsdWUgPT09IG51bGwgfHwgKHZhbHVlLmxlbmd0aCA+PSA1ICYmIHZhbHVlLmVuZHNXaXRoKCcubG9nJykpLFxyXG4gICAgICAgIHtcclxuICAgICAgICAgIHBhcmFtczoge1xyXG4gICAgICAgICAgICBlcnJvck1lc3NhZ2U6ICdUaGUgdmFsdWUgbXVzdCBiZSBhIHN0cmluZyB0aGF0IGVuZHMgd2l0aCAubG9nJ1xyXG4gICAgICAgICAgfVxyXG4gICAgICAgIH1cclxuICAgICAgKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYGxvZ0Rlc3RgIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGggYW4gb3B0aW9uYWwgc3RyaWN0ZXJcclxuICAgKiBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGUgc2FtZSB3b3JrIGFzIHRoZSBgc3RyaW5nYCB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gbG9nRGVzdFxyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nIHRoZSBgbG9nRGVzdGBcclxuICAgKiBvcHRpb24uXHJcbiAgICovXHJcbiAgbG9nRGVzdChzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHYuc3RyaW5nKHN0cmljdENoZWNrKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYGxvZ1RvQ29uc29sZWAgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbFxyXG4gICAqIHN0cmljdGVyIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgdGhlIGBib29sZWFuYCB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gbG9nVG9Db25zb2xlXHJcbiAgICpcclxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IHN0cmljdENoZWNrIC0gRGV0ZXJtaW5lcyBpZiBzdHJpY3RlciB2YWxpZGF0aW9uIHNob3VsZFxyXG4gICAqIGJlIGFwcGxpZWQuXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9IEEgWm9kIHNjaGVtYSBvYmplY3QgZm9yIHZhbGlkYXRpbmdcclxuICAgKiB0aGUgYGxvZ1RvQ29uc29sZWAgb3B0aW9uLlxyXG4gICAqL1xyXG4gIGxvZ1RvQ29uc29sZShzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHYuYm9vbGVhbihzdHJpY3RDaGVjayk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGBsb2dUb0ZpbGVgIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGggYW4gb3B0aW9uYWxcclxuICAgKiBzdHJpY3RlciBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGUgc2FtZSB3b3JrIGFzIHRoZSBgYm9vbGVhbmAgdmFsaWRhdG9yLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIGxvZ1RvRmlsZVxyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nIHRoZSBgbG9nVG9GaWxlYFxyXG4gICAqIG9wdGlvbi5cclxuICAgKi9cclxuICBsb2dUb0ZpbGUoc3RyaWN0Q2hlY2spIHtcclxuICAgIHJldHVybiB2LmJvb2xlYW4oc3RyaWN0Q2hlY2spO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgZW5hYmxlVWlgIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGggYW4gb3B0aW9uYWxcclxuICAgKiBzdHJpY3RlciBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGUgc2FtZSB3b3JrIGFzIHRoZSBgYm9vbGVhbmAgdmFsaWRhdG9yLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIGVuYWJsZVVpXHJcbiAgICpcclxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IHN0cmljdENoZWNrIC0gRGV0ZXJtaW5lcyBpZiBzdHJpY3RlciB2YWxpZGF0aW9uIHNob3VsZFxyXG4gICAqIGJlIGFwcGxpZWQuXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9IEEgWm9kIHNjaGVtYSBvYmplY3QgZm9yIHZhbGlkYXRpbmcgdGhlIGBlbmFibGVVaWBcclxuICAgKiBvcHRpb24uXHJcbiAgICovXHJcbiAgZW5hYmxlVWkoc3RyaWN0Q2hlY2spIHtcclxuICAgIHJldHVybiB2LmJvb2xlYW4oc3RyaWN0Q2hlY2spO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgdWlSb3V0ZWAgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbFxyXG4gICAqIHN0cmljdGVyIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgdGhlIGBzdGFydHNXaXRoYCB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gdWlSb3V0ZVxyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nIHRoZSBgdWlSb3V0ZWBcclxuICAgKiBvcHRpb24uXHJcbiAgICovXHJcbiAgdWlSb3V0ZShzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHYuc3RhcnRzV2l0aChbJy8nXSwgc3RyaWN0Q2hlY2spO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgbm9kZUVudmAgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbFxyXG4gICAqIHN0cmljdGVyIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgdGhlIGBlbnVtYCB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gbm9kZUVudlxyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nIHRoZSBgbm9kZUVudmBcclxuICAgKiBvcHRpb24uXHJcbiAgICovXHJcbiAgbm9kZUVudihzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHYuZW51bShbJ2RldmVsb3BtZW50JywgJ3Byb2R1Y3Rpb24nLCAndGVzdCddLCBzdHJpY3RDaGVjayk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGBsaXN0ZW5Ub1Byb2Nlc3NFeGl0c2AgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aFxyXG4gICAqIGFuIG9wdGlvbmFsIHN0cmljdGVyIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgdGhlIGBib29sZWFuYCB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gbGlzdGVuVG9Qcm9jZXNzRXhpdHNcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZ1xyXG4gICAqIHRoZSBgbGlzdGVuVG9Qcm9jZXNzRXhpdHNgIG9wdGlvbi5cclxuICAgKi9cclxuICBsaXN0ZW5Ub1Byb2Nlc3NFeGl0cyhzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHYuYm9vbGVhbihzdHJpY3RDaGVjayk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGBub0xvZ29gIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGggYW4gb3B0aW9uYWxcclxuICAgKiBzdHJpY3RlciBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGUgc2FtZSB3b3JrIGFzIHRoZSBgYm9vbGVhbmAgdmFsaWRhdG9yLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIG5vTG9nb1xyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nIHRoZSBgbm9Mb2dvYFxyXG4gICAqIG9wdGlvbi5cclxuICAgKi9cclxuICBub0xvZ28oc3RyaWN0Q2hlY2spIHtcclxuICAgIHJldHVybiB2LmJvb2xlYW4oc3RyaWN0Q2hlY2spO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgaGFyZFJlc2V0UGFnZWAgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbFxyXG4gICAqIHN0cmljdGVyIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgdGhlIGBib29sZWFuYCB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gaGFyZFJlc2V0UGFnZVxyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nXHJcbiAgICogdGhlIGBoYXJkUmVzZXRQYWdlYCBvcHRpb24uXHJcbiAgICovXHJcbiAgaGFyZFJlc2V0UGFnZShzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHYuYm9vbGVhbihzdHJpY3RDaGVjayk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGBicm93c2VyU2hlbGxNb2RlYCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoIGFuIG9wdGlvbmFsXHJcbiAgICogc3RyaWN0ZXIgY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhlIHNhbWUgd29yayBhcyB0aGUgYGJvb2xlYW5gIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiBicm93c2VyU2hlbGxNb2RlXHJcbiAgICpcclxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IHN0cmljdENoZWNrIC0gRGV0ZXJtaW5lcyBpZiBzdHJpY3RlciB2YWxpZGF0aW9uIHNob3VsZFxyXG4gICAqIGJlIGFwcGxpZWQuXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9IEEgWm9kIHNjaGVtYSBvYmplY3QgZm9yIHZhbGlkYXRpbmdcclxuICAgKiB0aGUgYGJyb3dzZXJTaGVsbE1vZGVgIG9wdGlvbi5cclxuICAgKi9cclxuICBicm93c2VyU2hlbGxNb2RlKHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gdi5ib29sZWFuKHN0cmljdENoZWNrKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYHZhbGlkYXRpb25gIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGggYW4gb3B0aW9uYWxcclxuICAgKiBzdHJpY3RlciBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGUgc2FtZSB3b3JrIGFzIHRoZSBgYm9vbGVhbmAgdmFsaWRhdG9yLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIHZhbGlkYXRpb25cclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZyB0aGUgYHZhbGlkYXRpb25gXHJcbiAgICogb3B0aW9uLlxyXG4gICAqL1xyXG4gIHZhbGlkYXRpb24oc3RyaWN0Q2hlY2spIHtcclxuICAgIHJldHVybiB2LmJvb2xlYW4oc3RyaWN0Q2hlY2spO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgZW5hYmxlRGVidWdgIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGggYW4gb3B0aW9uYWxcclxuICAgKiBzdHJpY3RlciBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGUgc2FtZSB3b3JrIGFzIHRoZSBgYm9vbGVhbmAgdmFsaWRhdG9yLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIGVuYWJsZURlYnVnXHJcbiAgICpcclxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IHN0cmljdENoZWNrIC0gRGV0ZXJtaW5lcyBpZiBzdHJpY3RlciB2YWxpZGF0aW9uIHNob3VsZFxyXG4gICAqIGJlIGFwcGxpZWQuXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9IEEgWm9kIHNjaGVtYSBvYmplY3QgZm9yIHZhbGlkYXRpbmcgdGhlIGBlbmFibGVEZWJ1Z2BcclxuICAgKiBvcHRpb24uXHJcbiAgICovXHJcbiAgZW5hYmxlRGVidWcoc3RyaWN0Q2hlY2spIHtcclxuICAgIHJldHVybiB2LmJvb2xlYW4oc3RyaWN0Q2hlY2spO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgaGVhZGxlc3NgIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGggYW4gb3B0aW9uYWxcclxuICAgKiBzdHJpY3RlciBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGUgc2FtZSB3b3JrIGFzIHRoZSBgYm9vbGVhbmAgdmFsaWRhdG9yLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIGhlYWRsZXNzXHJcbiAgICpcclxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IHN0cmljdENoZWNrIC0gRGV0ZXJtaW5lcyBpZiBzdHJpY3RlciB2YWxpZGF0aW9uIHNob3VsZFxyXG4gICAqIGJlIGFwcGxpZWQuXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9IEEgWm9kIHNjaGVtYSBvYmplY3QgZm9yIHZhbGlkYXRpbmcgdGhlIGBoZWFkbGVzc2BcclxuICAgKiBvcHRpb24uXHJcbiAgICovXHJcbiAgaGVhZGxlc3Moc3RyaWN0Q2hlY2spIHtcclxuICAgIHJldHVybiB2LmJvb2xlYW4oc3RyaWN0Q2hlY2spO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgZGV2dG9vbHNgIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGggYW4gb3B0aW9uYWxcclxuICAgKiBzdHJpY3RlciBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGUgc2FtZSB3b3JrIGFzIHRoZSBgYm9vbGVhbmAgdmFsaWRhdG9yLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIGRldnRvb2xzXHJcbiAgICpcclxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IHN0cmljdENoZWNrIC0gRGV0ZXJtaW5lcyBpZiBzdHJpY3RlciB2YWxpZGF0aW9uIHNob3VsZFxyXG4gICAqIGJlIGFwcGxpZWQuXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9IEEgWm9kIHNjaGVtYSBvYmplY3QgZm9yIHZhbGlkYXRpbmcgdGhlIGBkZXZ0b29sc2BcclxuICAgKiBvcHRpb24uXHJcbiAgICovXHJcbiAgZGV2dG9vbHMoc3RyaWN0Q2hlY2spIHtcclxuICAgIHJldHVybiB2LmJvb2xlYW4oc3RyaWN0Q2hlY2spO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgbGlzdGVuVG9Db25zb2xlYCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoIGFuIG9wdGlvbmFsXHJcbiAgICogc3RyaWN0ZXIgY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhlIHNhbWUgd29yayBhcyB0aGUgYGJvb2xlYW5gIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiBsaXN0ZW5Ub0NvbnNvbGVcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZ1xyXG4gICAqIHRoZSBgbGlzdGVuVG9Db25zb2xlYCBvcHRpb24uXHJcbiAgICovXHJcbiAgbGlzdGVuVG9Db25zb2xlKHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gdi5ib29sZWFuKHN0cmljdENoZWNrKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYGR1bXBpb2AgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbCBzdHJpY3RlclxyXG4gICAqIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgdGhlIGBib29sZWFuYCB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gZHVtcGlvXHJcbiAgICpcclxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IHN0cmljdENoZWNrIC0gRGV0ZXJtaW5lcyBpZiBzdHJpY3RlciB2YWxpZGF0aW9uIHNob3VsZFxyXG4gICAqIGJlIGFwcGxpZWQuXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9IEEgWm9kIHNjaGVtYSBvYmplY3QgZm9yIHZhbGlkYXRpbmcgdGhlIGBkdW1waW9gXHJcbiAgICogb3B0aW9uLlxyXG4gICAqL1xyXG4gIGR1bXBpbyhzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHYuYm9vbGVhbihzdHJpY3RDaGVjayk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGBzbG93TW9gIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGggYW4gb3B0aW9uYWwgc3RyaWN0ZXJcclxuICAgKiBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGUgc2FtZSB3b3JrIGFzIHRoZSBgbm9uTmVnYXRpdmVOdW1gXHJcbiAgICogdmFsaWRhdG9yLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIHNsb3dNb1xyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nIHRoZSBgc2xvd01vYFxyXG4gICAqIG9wdGlvbi5cclxuICAgKi9cclxuICBzbG93TW8oc3RyaWN0Q2hlY2spIHtcclxuICAgIHJldHVybiB2Lm5vbk5lZ2F0aXZlTnVtKHN0cmljdENoZWNrKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYGRlYnVnZ2luZ1BvcnRgIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGggYW4gb3B0aW9uYWxcclxuICAgKiBzdHJpY3RlciBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGUgc2FtZSB3b3JrIGFzIHRoZSBgbm9uTmVnYXRpdmVOdW1gXHJcbiAgICogdmFsaWRhdG9yLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIGRlYnVnZ2luZ1BvcnRcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZ1xyXG4gICAqIHRoZSBgZGVidWdnaW5nUG9ydGAgb3B0aW9uLlxyXG4gICAqL1xyXG4gIGRlYnVnZ2luZ1BvcnQoc3RyaWN0Q2hlY2spIHtcclxuICAgIHJldHVybiB2Lm5vbk5lZ2F0aXZlTnVtKHN0cmljdENoZWNrKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYHJlcXVlc3RJZGAgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbFxyXG4gICAqIHN0cmljdGVyIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgdGhlIGBzdHJpbmdgIHZhbGlkYXRvci5cclxuICAgKiBBZGRpdGlvbmFsbHksIGl0IG11c3QgYmUgYSBzdHJpbmdpZmllZCBVVUlEIG9yIGNhbiBiZSBudWxsLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIHJlcXVlc3RJZFxyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nIHRoZSBgcmVxdWVzdElkYFxyXG4gICAqIG9wdGlvbi5cclxuICAgKi9cclxuICByZXF1ZXN0SWQoKSB7XHJcbiAgICByZXR1cm4gelxyXG4gICAgICAuc3RyaW5nKClcclxuICAgICAgLnV1aWQoeyBtZXNzYWdlOiAnVGhlIHZhbHVlIG11c3QgYmUgYSBzdHJpbmdpZmllZCBVVUlEJyB9KVxyXG4gICAgICAubnVsbGFibGUoKTtcclxuICB9XHJcbn07XHJcblxyXG4vLyBTY2hlbWEgZm9yIHRoZSBwdXBwZXRlZXIgc2VjdGlvbiBvZiBvcHRpb25zXHJcbmNvbnN0IFB1cHBldGVlclNjaGVtYSA9IChzdHJpY3RDaGVjaykgPT5cclxuICB6XHJcbiAgICAub2JqZWN0KHtcclxuICAgICAgYXJnczogdmFsaWRhdG9ycy5hcmdzKHN0cmljdENoZWNrKVxyXG4gICAgfSlcclxuICAgIC5wYXJ0aWFsKCk7XHJcblxyXG4vLyBTY2hlbWEgZm9yIHRoZSBoaWdoY2hhcnRzIHNlY3Rpb24gb2Ygb3B0aW9uc1xyXG5jb25zdCBIaWdoY2hhcnRzU2NoZW1hID0gKHN0cmljdENoZWNrKSA9PlxyXG4gIHpcclxuICAgIC5vYmplY3Qoe1xyXG4gICAgICB2ZXJzaW9uOiB2YWxpZGF0b3JzLnZlcnNpb24oc3RyaWN0Q2hlY2spLFxyXG4gICAgICBjZG5Vcmw6IHZhbGlkYXRvcnMuY2RuVXJsKHN0cmljdENoZWNrKSxcclxuICAgICAgZm9yY2VGZXRjaDogdmFsaWRhdG9ycy5mb3JjZUZldGNoKHN0cmljdENoZWNrKSxcclxuICAgICAgY2FjaGVQYXRoOiB2YWxpZGF0b3JzLmNhY2hlUGF0aChzdHJpY3RDaGVjayksXHJcbiAgICAgIGNvcmVTY3JpcHRzOiB2YWxpZGF0b3JzLmNvcmVTY3JpcHRzKHN0cmljdENoZWNrKSxcclxuICAgICAgbW9kdWxlU2NyaXB0czogdmFsaWRhdG9ycy5tb2R1bGVTY3JpcHRzKHN0cmljdENoZWNrKSxcclxuICAgICAgaW5kaWNhdG9yU2NyaXB0czogdmFsaWRhdG9ycy5pbmRpY2F0b3JTY3JpcHRzKHN0cmljdENoZWNrKSxcclxuICAgICAgY3VzdG9tU2NyaXB0czogdmFsaWRhdG9ycy5jdXN0b21TY3JpcHRzKHN0cmljdENoZWNrKVxyXG4gICAgfSlcclxuICAgIC5wYXJ0aWFsKCk7XHJcblxyXG4vLyBTY2hlbWEgZm9yIHRoZSBleHBvcnQgc2VjdGlvbiBvZiBvcHRpb25zXHJcbmNvbnN0IEV4cG9ydFNjaGVtYSA9IChzdHJpY3RDaGVjaykgPT5cclxuICB6XHJcbiAgICAub2JqZWN0KHtcclxuICAgICAgaW5maWxlOiB2YWxpZGF0b3JzLmluZmlsZShzdHJpY3RDaGVjayksXHJcbiAgICAgIGluc3RyOiB2YWxpZGF0b3JzLmluc3RyKCksXHJcbiAgICAgIG9wdGlvbnM6IHZhbGlkYXRvcnMub3B0aW9ucygpLFxyXG4gICAgICBzdmc6IHZhbGlkYXRvcnMuc3ZnKCksXHJcbiAgICAgIG91dGZpbGU6IHZhbGlkYXRvcnMub3V0ZmlsZShzdHJpY3RDaGVjayksXHJcbiAgICAgIHR5cGU6IHZhbGlkYXRvcnMudHlwZShzdHJpY3RDaGVjayksXHJcbiAgICAgIGNvbnN0cjogdmFsaWRhdG9ycy5jb25zdHIoc3RyaWN0Q2hlY2spLFxyXG4gICAgICBiNjQ6IHZhbGlkYXRvcnMuYjY0KHN0cmljdENoZWNrKSxcclxuICAgICAgbm9Eb3dubG9hZDogdmFsaWRhdG9ycy5ub0Rvd25sb2FkKHN0cmljdENoZWNrKSxcclxuICAgICAgZGVmYXVsdEhlaWdodDogdmFsaWRhdG9ycy5kZWZhdWx0SGVpZ2h0KHN0cmljdENoZWNrKSxcclxuICAgICAgZGVmYXVsdFdpZHRoOiB2YWxpZGF0b3JzLmRlZmF1bHRXaWR0aChzdHJpY3RDaGVjayksXHJcbiAgICAgIGRlZmF1bHRTY2FsZTogdmFsaWRhdG9ycy5kZWZhdWx0U2NhbGUoc3RyaWN0Q2hlY2spLFxyXG4gICAgICBoZWlnaHQ6IHZhbGlkYXRvcnMuaGVpZ2h0KHN0cmljdENoZWNrKSxcclxuICAgICAgd2lkdGg6IHZhbGlkYXRvcnMud2lkdGgoc3RyaWN0Q2hlY2spLFxyXG4gICAgICBzY2FsZTogdmFsaWRhdG9ycy5zY2FsZShzdHJpY3RDaGVjayksXHJcbiAgICAgIGdsb2JhbE9wdGlvbnM6IHZhbGlkYXRvcnMuZ2xvYmFsT3B0aW9ucygpLFxyXG4gICAgICB0aGVtZU9wdGlvbnM6IHZhbGlkYXRvcnMudGhlbWVPcHRpb25zKCksXHJcbiAgICAgIGJhdGNoOiB2YWxpZGF0b3JzLmJhdGNoKGZhbHNlKSxcclxuICAgICAgcmFzdGVyaXphdGlvblRpbWVvdXQ6IHZhbGlkYXRvcnMucmFzdGVyaXphdGlvblRpbWVvdXQoc3RyaWN0Q2hlY2spXHJcbiAgICB9KVxyXG4gICAgLnBhcnRpYWwoKTtcclxuXHJcbi8vIFNjaGVtYSBmb3IgdGhlIGN1c3RvbUxvZ2ljIHNlY3Rpb24gb2Ygb3B0aW9uc1xyXG5jb25zdCBDdXN0b21Mb2dpY1NjaGVtYSA9IChzdHJpY3RDaGVjaykgPT5cclxuICB6XHJcbiAgICAub2JqZWN0KHtcclxuICAgICAgYWxsb3dDb2RlRXhlY3V0aW9uOiB2YWxpZGF0b3JzLmFsbG93Q29kZUV4ZWN1dGlvbihzdHJpY3RDaGVjayksXHJcbiAgICAgIGFsbG93RmlsZVJlc291cmNlczogdmFsaWRhdG9ycy5hbGxvd0ZpbGVSZXNvdXJjZXMoc3RyaWN0Q2hlY2spLFxyXG4gICAgICBjdXN0b21Db2RlOiB2YWxpZGF0b3JzLmN1c3RvbUNvZGUoZmFsc2UpLFxyXG4gICAgICBjYWxsYmFjazogdmFsaWRhdG9ycy5jYWxsYmFjayhmYWxzZSksXHJcbiAgICAgIHJlc291cmNlczogdmFsaWRhdG9ycy5yZXNvdXJjZXMoc3RyaWN0Q2hlY2spLFxyXG4gICAgICBsb2FkQ29uZmlnOiB2YWxpZGF0b3JzLmxvYWRDb25maWcoZmFsc2UpLFxyXG4gICAgICBjcmVhdGVDb25maWc6IHZhbGlkYXRvcnMuY3JlYXRlQ29uZmlnKGZhbHNlKVxyXG4gICAgfSlcclxuICAgIC5wYXJ0aWFsKCk7XHJcblxyXG4vLyBTY2hlbWEgZm9yIHRoZSBzZXJ2ZXIucHJveHkgc2VjdGlvbiBvZiBvcHRpb25zXHJcbmNvbnN0IFByb3h5U2NoZW1hID0gKHN0cmljdENoZWNrKSA9PlxyXG4gIHpcclxuICAgIC5vYmplY3Qoe1xyXG4gICAgICBob3N0OiB2YWxpZGF0b3JzLnByb3h5SG9zdChmYWxzZSksXHJcbiAgICAgIHBvcnQ6IHZhbGlkYXRvcnMucHJveHlQb3J0KHN0cmljdENoZWNrKSxcclxuICAgICAgdGltZW91dDogdmFsaWRhdG9ycy5wcm94eVRpbWVvdXQoc3RyaWN0Q2hlY2spXHJcbiAgICB9KVxyXG4gICAgLnBhcnRpYWwoKTtcclxuXHJcbi8vIFNjaGVtYSBmb3IgdGhlIHNlcnZlci5yYXRlTGltaXRpbmcgc2VjdGlvbiBvZiBvcHRpb25zXHJcbmNvbnN0IFJhdGVMaW1pdGluZ1NjaGVtYSA9IChzdHJpY3RDaGVjaykgPT5cclxuICB6XHJcbiAgICAub2JqZWN0KHtcclxuICAgICAgZW5hYmxlOiB2YWxpZGF0b3JzLmVuYWJsZVJhdGVMaW1pdGluZyhzdHJpY3RDaGVjayksXHJcbiAgICAgIG1heFJlcXVlc3RzOiB2YWxpZGF0b3JzLm1heFJlcXVlc3RzKHN0cmljdENoZWNrKSxcclxuICAgICAgd2luZG93OiB2YWxpZGF0b3JzLndpbmRvdyhzdHJpY3RDaGVjayksXHJcbiAgICAgIGRlbGF5OiB2YWxpZGF0b3JzLmRlbGF5KHN0cmljdENoZWNrKSxcclxuICAgICAgdHJ1c3RQcm94eTogdmFsaWRhdG9ycy50cnVzdFByb3h5KHN0cmljdENoZWNrKSxcclxuICAgICAgc2tpcEtleTogdmFsaWRhdG9ycy5za2lwS2V5KGZhbHNlKSxcclxuICAgICAgc2tpcFRva2VuOiB2YWxpZGF0b3JzLnNraXBUb2tlbihmYWxzZSlcclxuICAgIH0pXHJcbiAgICAucGFydGlhbCgpO1xyXG5cclxuLy8gU2NoZW1hIGZvciB0aGUgc2VydmVyLnNzbCBzZWN0aW9uIG9mIG9wdGlvbnNcclxuY29uc3QgU3NsU2NoZW1hID0gKHN0cmljdENoZWNrKSA9PlxyXG4gIHpcclxuICAgIC5vYmplY3Qoe1xyXG4gICAgICBlbmFibGU6IHZhbGlkYXRvcnMuZW5hYmxlU3NsKHN0cmljdENoZWNrKSxcclxuICAgICAgZm9yY2U6IHZhbGlkYXRvcnMuc3NsRm9yY2Uoc3RyaWN0Q2hlY2spLFxyXG4gICAgICBwb3J0OiB2YWxpZGF0b3JzLnNzbFBvcnQoc3RyaWN0Q2hlY2spLFxyXG4gICAgICBjZXJ0UGF0aDogdmFsaWRhdG9ycy5zc2xDZXJ0UGF0aChmYWxzZSlcclxuICAgIH0pXHJcbiAgICAucGFydGlhbCgpO1xyXG5cclxuLy8gU2NoZW1hIGZvciB0aGUgc2VydmVyIHNlY3Rpb24gb2Ygb3B0aW9uc1xyXG5jb25zdCBTZXJ2ZXJTY2hlbWEgPSAoc3RyaWN0Q2hlY2spID0+XHJcbiAgei5vYmplY3Qoe1xyXG4gICAgZW5hYmxlOiB2YWxpZGF0b3JzLmVuYWJsZVNlcnZlcihzdHJpY3RDaGVjaykub3B0aW9uYWwoKSxcclxuICAgIGhvc3Q6IHZhbGlkYXRvcnMuaG9zdChzdHJpY3RDaGVjaykub3B0aW9uYWwoKSxcclxuICAgIHBvcnQ6IHZhbGlkYXRvcnMucG9ydChzdHJpY3RDaGVjaykub3B0aW9uYWwoKSxcclxuICAgIHVwbG9hZExpbWl0OiB2YWxpZGF0b3JzLnVwbG9hZExpbWl0KHN0cmljdENoZWNrKS5vcHRpb25hbCgpLFxyXG4gICAgYmVuY2htYXJraW5nOiB2YWxpZGF0b3JzLnNlcnZlckJlbmNobWFya2luZyhzdHJpY3RDaGVjaykub3B0aW9uYWwoKSxcclxuICAgIHByb3h5OiBQcm94eVNjaGVtYShzdHJpY3RDaGVjaykub3B0aW9uYWwoKSxcclxuICAgIHJhdGVMaW1pdGluZzogUmF0ZUxpbWl0aW5nU2NoZW1hKHN0cmljdENoZWNrKS5vcHRpb25hbCgpLFxyXG4gICAgc3NsOiBTc2xTY2hlbWEoc3RyaWN0Q2hlY2spLm9wdGlvbmFsKClcclxuICB9KTtcclxuXHJcbi8vIFNjaGVtYSBmb3IgdGhlIHBvb2wgc2VjdGlvbiBvZiBvcHRpb25zXHJcbmNvbnN0IFBvb2xTY2hlbWEgPSAoc3RyaWN0Q2hlY2spID0+XHJcbiAgelxyXG4gICAgLm9iamVjdCh7XHJcbiAgICAgIG1pbldvcmtlcnM6IHZhbGlkYXRvcnMubWluV29ya2VycyhzdHJpY3RDaGVjayksXHJcbiAgICAgIG1heFdvcmtlcnM6IHZhbGlkYXRvcnMubWF4V29ya2VycyhzdHJpY3RDaGVjayksXHJcbiAgICAgIHdvcmtMaW1pdDogdmFsaWRhdG9ycy53b3JrTGltaXQoc3RyaWN0Q2hlY2spLFxyXG4gICAgICBhY3F1aXJlVGltZW91dDogdmFsaWRhdG9ycy5hY3F1aXJlVGltZW91dChzdHJpY3RDaGVjayksXHJcbiAgICAgIGNyZWF0ZVRpbWVvdXQ6IHZhbGlkYXRvcnMuY3JlYXRlVGltZW91dChzdHJpY3RDaGVjayksXHJcbiAgICAgIGRlc3Ryb3lUaW1lb3V0OiB2YWxpZGF0b3JzLmRlc3Ryb3lUaW1lb3V0KHN0cmljdENoZWNrKSxcclxuICAgICAgaWRsZVRpbWVvdXQ6IHZhbGlkYXRvcnMuaWRsZVRpbWVvdXQoc3RyaWN0Q2hlY2spLFxyXG4gICAgICBjcmVhdGVSZXRyeUludGVydmFsOiB2YWxpZGF0b3JzLmNyZWF0ZVJldHJ5SW50ZXJ2YWwoc3RyaWN0Q2hlY2spLFxyXG4gICAgICByZWFwZXJJbnRlcnZhbDogdmFsaWRhdG9ycy5yZWFwZXJJbnRlcnZhbChzdHJpY3RDaGVjayksXHJcbiAgICAgIGJlbmNobWFya2luZzogdmFsaWRhdG9ycy5wb29sQmVuY2htYXJraW5nKHN0cmljdENoZWNrKVxyXG4gICAgfSlcclxuICAgIC5wYXJ0aWFsKCk7XHJcblxyXG4vLyBTY2hlbWEgZm9yIHRoZSBsb2dnaW5nIHNlY3Rpb24gb2Ygb3B0aW9uc1xyXG5jb25zdCBMb2dnaW5nU2NoZW1hID0gKHN0cmljdENoZWNrKSA9PlxyXG4gIHpcclxuICAgIC5vYmplY3Qoe1xyXG4gICAgICBsZXZlbDogdmFsaWRhdG9ycy5sb2dMZXZlbChzdHJpY3RDaGVjayksXHJcbiAgICAgIGZpbGU6IHZhbGlkYXRvcnMubG9nRmlsZShzdHJpY3RDaGVjayksXHJcbiAgICAgIGRlc3Q6IHZhbGlkYXRvcnMubG9nRGVzdChzdHJpY3RDaGVjayksXHJcbiAgICAgIHRvQ29uc29sZTogdmFsaWRhdG9ycy5sb2dUb0NvbnNvbGUoc3RyaWN0Q2hlY2spLFxyXG4gICAgICB0b0ZpbGU6IHZhbGlkYXRvcnMubG9nVG9GaWxlKHN0cmljdENoZWNrKVxyXG4gICAgfSlcclxuICAgIC5wYXJ0aWFsKCk7XHJcblxyXG4vLyBTY2hlbWEgZm9yIHRoZSB1aSBzZWN0aW9uIG9mIG9wdGlvbnNcclxuY29uc3QgVWlTY2hlbWEgPSAoc3RyaWN0Q2hlY2spID0+XHJcbiAgelxyXG4gICAgLm9iamVjdCh7XHJcbiAgICAgIGVuYWJsZTogdmFsaWRhdG9ycy5lbmFibGVVaShzdHJpY3RDaGVjayksXHJcbiAgICAgIHJvdXRlOiB2YWxpZGF0b3JzLnVpUm91dGUoc3RyaWN0Q2hlY2spXHJcbiAgICB9KVxyXG4gICAgLnBhcnRpYWwoKTtcclxuXHJcbi8vIFNjaGVtYSBmb3IgdGhlIG90aGVyIHNlY3Rpb24gb2Ygb3B0aW9uc1xyXG5jb25zdCBPdGhlclNjaGVtYSA9IChzdHJpY3RDaGVjaykgPT5cclxuICB6XHJcbiAgICAub2JqZWN0KHtcclxuICAgICAgbm9kZUVudjogdmFsaWRhdG9ycy5ub2RlRW52KHN0cmljdENoZWNrKSxcclxuICAgICAgbGlzdGVuVG9Qcm9jZXNzRXhpdHM6IHZhbGlkYXRvcnMubGlzdGVuVG9Qcm9jZXNzRXhpdHMoc3RyaWN0Q2hlY2spLFxyXG4gICAgICBub0xvZ286IHZhbGlkYXRvcnMubm9Mb2dvKHN0cmljdENoZWNrKSxcclxuICAgICAgaGFyZFJlc2V0UGFnZTogdmFsaWRhdG9ycy5oYXJkUmVzZXRQYWdlKHN0cmljdENoZWNrKSxcclxuICAgICAgYnJvd3NlclNoZWxsTW9kZTogdmFsaWRhdG9ycy5icm93c2VyU2hlbGxNb2RlKHN0cmljdENoZWNrKSxcclxuICAgICAgdmFsaWRhdGlvbjogdmFsaWRhdG9ycy52YWxpZGF0aW9uKHN0cmljdENoZWNrKVxyXG4gICAgfSlcclxuICAgIC5wYXJ0aWFsKCk7XHJcblxyXG4vLyBTY2hlbWEgZm9yIHRoZSBkZWJ1ZyBzZWN0aW9uIG9mIG9wdGlvbnNcclxuY29uc3QgRGVidWdTY2hlbWEgPSAoc3RyaWN0Q2hlY2spID0+XHJcbiAgelxyXG4gICAgLm9iamVjdCh7XHJcbiAgICAgIGVuYWJsZTogdmFsaWRhdG9ycy5lbmFibGVEZWJ1ZyhzdHJpY3RDaGVjayksXHJcbiAgICAgIGhlYWRsZXNzOiB2YWxpZGF0b3JzLmhlYWRsZXNzKHN0cmljdENoZWNrKSxcclxuICAgICAgZGV2dG9vbHM6IHZhbGlkYXRvcnMuZGV2dG9vbHMoc3RyaWN0Q2hlY2spLFxyXG4gICAgICBsaXN0ZW5Ub0NvbnNvbGU6IHZhbGlkYXRvcnMubGlzdGVuVG9Db25zb2xlKHN0cmljdENoZWNrKSxcclxuICAgICAgZHVtcGlvOiB2YWxpZGF0b3JzLmR1bXBpbyhzdHJpY3RDaGVjayksXHJcbiAgICAgIHNsb3dNbzogdmFsaWRhdG9ycy5zbG93TW8oc3RyaWN0Q2hlY2spLFxyXG4gICAgICBkZWJ1Z2dpbmdQb3J0OiB2YWxpZGF0b3JzLmRlYnVnZ2luZ1BvcnQoc3RyaWN0Q2hlY2spXHJcbiAgICB9KVxyXG4gICAgLnBhcnRpYWwoKTtcclxuXHJcbi8vIFN0cmljdCBzY2hlbWEgZm9yIHRoZSBjb25maWdcclxuZXhwb3J0IGNvbnN0IFN0cmljdENvbmZpZ1NjaGVtYSA9IHoub2JqZWN0KHtcclxuICByZXF1ZXN0SWQ6IHZhbGlkYXRvcnMucmVxdWVzdElkKCksXHJcbiAgcHVwcGV0ZWVyOiBQdXBwZXRlZXJTY2hlbWEodHJ1ZSksXHJcbiAgaGlnaGNoYXJ0czogSGlnaGNoYXJ0c1NjaGVtYSh0cnVlKSxcclxuICBleHBvcnQ6IEV4cG9ydFNjaGVtYSh0cnVlKSxcclxuICBjdXN0b21Mb2dpYzogQ3VzdG9tTG9naWNTY2hlbWEodHJ1ZSksXHJcbiAgc2VydmVyOiBTZXJ2ZXJTY2hlbWEodHJ1ZSksXHJcbiAgcG9vbDogUG9vbFNjaGVtYSh0cnVlKSxcclxuICBsb2dnaW5nOiBMb2dnaW5nU2NoZW1hKHRydWUpLFxyXG4gIHVpOiBVaVNjaGVtYSh0cnVlKSxcclxuICBvdGhlcjogT3RoZXJTY2hlbWEodHJ1ZSksXHJcbiAgZGVidWc6IERlYnVnU2NoZW1hKHRydWUpXHJcbn0pO1xyXG5cclxuLy8gTG9vc2Ugc2NoZW1hIGZvciB0aGUgY29uZmlnXHJcbmV4cG9ydCBjb25zdCBMb29zZUNvbmZpZ1NjaGVtYSA9IHoub2JqZWN0KHtcclxuICByZXF1ZXN0SWQ6IHZhbGlkYXRvcnMucmVxdWVzdElkKCksXHJcbiAgcHVwcGV0ZWVyOiBQdXBwZXRlZXJTY2hlbWEoZmFsc2UpLFxyXG4gIGhpZ2hjaGFydHM6IEhpZ2hjaGFydHNTY2hlbWEoZmFsc2UpLFxyXG4gIGV4cG9ydDogRXhwb3J0U2NoZW1hKGZhbHNlKSxcclxuICBjdXN0b21Mb2dpYzogQ3VzdG9tTG9naWNTY2hlbWEoZmFsc2UpLFxyXG4gIHNlcnZlcjogU2VydmVyU2NoZW1hKGZhbHNlKSxcclxuICBwb29sOiBQb29sU2NoZW1hKGZhbHNlKSxcclxuICBsb2dnaW5nOiBMb2dnaW5nU2NoZW1hKGZhbHNlKSxcclxuICB1aTogVWlTY2hlbWEoZmFsc2UpLFxyXG4gIG90aGVyOiBPdGhlclNjaGVtYShmYWxzZSksXHJcbiAgZGVidWc6IERlYnVnU2NoZW1hKGZhbHNlKVxyXG59KTtcclxuXHJcbi8vIFNjaGVtYSBmb3IgdGhlIGVudmlyb25tZW50IHZhcmlhYmxlcyBjb25maWdcclxuZXhwb3J0IGNvbnN0IEVudlNjaGVtYSA9IHoub2JqZWN0KHtcclxuICAvLyBwdXBwZXRlZXJcclxuICBQVVBQRVRFRVJfQVJHUzogdmFsaWRhdG9ycy5hcmdzKGZhbHNlKSxcclxuXHJcbiAgLy8gaGlnaGNoYXJ0c1xyXG4gIEhJR0hDSEFSVFNfVkVSU0lPTjogdmFsaWRhdG9ycy52ZXJzaW9uKGZhbHNlKSxcclxuICBISUdIQ0hBUlRTX0NETl9VUkw6IHZhbGlkYXRvcnMuY2RuVXJsKGZhbHNlKSxcclxuICBISUdIQ0hBUlRTX0ZPUkNFX0ZFVENIOiB2YWxpZGF0b3JzLmZvcmNlRmV0Y2goZmFsc2UpLFxyXG4gIEhJR0hDSEFSVFNfQ0FDSEVfUEFUSDogdmFsaWRhdG9ycy5jYWNoZVBhdGgoZmFsc2UpLFxyXG4gIEhJR0hDSEFSVFNfQURNSU5fVE9LRU46IHZhbGlkYXRvcnMuYWRtaW5Ub2tlbihmYWxzZSksXHJcbiAgSElHSENIQVJUU19DT1JFX1NDUklQVFM6IHZhbGlkYXRvcnMuY29yZVNjcmlwdHMoZmFsc2UpLFxyXG4gIEhJR0hDSEFSVFNfTU9EVUxFX1NDUklQVFM6IHZhbGlkYXRvcnMubW9kdWxlU2NyaXB0cyhmYWxzZSksXHJcbiAgSElHSENIQVJUU19JTkRJQ0FUT1JfU0NSSVBUUzogdmFsaWRhdG9ycy5pbmRpY2F0b3JTY3JpcHRzKGZhbHNlKSxcclxuICBISUdIQ0hBUlRTX0NVU1RPTV9TQ1JJUFRTOiB2YWxpZGF0b3JzLmN1c3RvbVNjcmlwdHMoZmFsc2UpLFxyXG5cclxuICAvLyBleHBvcnRcclxuICBFWFBPUlRfSU5GSUxFOiB2YWxpZGF0b3JzLmluZmlsZShmYWxzZSksXHJcbiAgRVhQT1JUX0lOU1RSOiB2YWxpZGF0b3JzLmluc3RyKCksXHJcbiAgRVhQT1JUX09QVElPTlM6IHZhbGlkYXRvcnMub3B0aW9ucygpLFxyXG4gIEVYUE9SVF9TVkc6IHZhbGlkYXRvcnMuc3ZnKCksXHJcbiAgRVhQT1JUX0JBVENIOiB2YWxpZGF0b3JzLmJhdGNoKGZhbHNlKSxcclxuICBFWFBPUlRfT1VURklMRTogdmFsaWRhdG9ycy5vdXRmaWxlKGZhbHNlKSxcclxuICBFWFBPUlRfVFlQRTogdmFsaWRhdG9ycy50eXBlKGZhbHNlKSxcclxuICBFWFBPUlRfQ09OU1RSOiB2YWxpZGF0b3JzLmNvbnN0cihmYWxzZSksXHJcbiAgRVhQT1JUX0I2NDogdmFsaWRhdG9ycy5iNjQoZmFsc2UpLFxyXG4gIEVYUE9SVF9OT19ET1dOTE9BRDogdmFsaWRhdG9ycy5ub0Rvd25sb2FkKGZhbHNlKSxcclxuICBFWFBPUlRfSEVJR0hUOiB2YWxpZGF0b3JzLmhlaWdodChmYWxzZSksXHJcbiAgRVhQT1JUX1dJRFRIOiB2YWxpZGF0b3JzLndpZHRoKGZhbHNlKSxcclxuICBFWFBPUlRfU0NBTEU6IHZhbGlkYXRvcnMuc2NhbGUoZmFsc2UpLFxyXG4gIEVYUE9SVF9ERUZBVUxUX0hFSUdIVDogdmFsaWRhdG9ycy5kZWZhdWx0SGVpZ2h0KGZhbHNlKSxcclxuICBFWFBPUlRfREVGQVVMVF9XSURUSDogdmFsaWRhdG9ycy5kZWZhdWx0V2lkdGgoZmFsc2UpLFxyXG4gIEVYUE9SVF9ERUZBVUxUX1NDQUxFOiB2YWxpZGF0b3JzLmRlZmF1bHRTY2FsZShmYWxzZSksXHJcbiAgRVhQT1JUX0dMT0JBTF9PUFRJT05TOiB2YWxpZGF0b3JzLmdsb2JhbE9wdGlvbnMoKSxcclxuICBFWFBPUlRfVEhFTUVfT1BUSU9OUzogdmFsaWRhdG9ycy50aGVtZU9wdGlvbnMoKSxcclxuICBFWFBPUlRfUkFTVEVSSVpBVElPTl9USU1FT1VUOiB2YWxpZGF0b3JzLnJhc3Rlcml6YXRpb25UaW1lb3V0KGZhbHNlKSxcclxuXHJcbiAgLy8gY3VzdG9tXHJcbiAgQ1VTVE9NX0xPR0lDX0FMTE9XX0NPREVfRVhFQ1VUSU9OOiB2YWxpZGF0b3JzLmFsbG93Q29kZUV4ZWN1dGlvbihmYWxzZSksXHJcbiAgQ1VTVE9NX0xPR0lDX0FMTE9XX0ZJTEVfUkVTT1VSQ0VTOiB2YWxpZGF0b3JzLmFsbG93RmlsZVJlc291cmNlcyhmYWxzZSksXHJcbiAgQ1VTVE9NX0xPR0lDX0NVU1RPTV9DT0RFOiB2YWxpZGF0b3JzLmN1c3RvbUNvZGUoZmFsc2UpLFxyXG4gIENVU1RPTV9MT0dJQ19DQUxMQkFDSzogdmFsaWRhdG9ycy5jYWxsYmFjayhmYWxzZSksXHJcbiAgQ1VTVE9NX0xPR0lDX1JFU09VUkNFUzogdmFsaWRhdG9ycy5yZXNvdXJjZXMoZmFsc2UpLFxyXG4gIENVU1RPTV9MT0dJQ19MT0FEX0NPTkZJRzogdmFsaWRhdG9ycy5sb2FkQ29uZmlnKGZhbHNlKSxcclxuICBDVVNUT01fTE9HSUNfQ1JFQVRFX0NPTkZJRzogdmFsaWRhdG9ycy5jcmVhdGVDb25maWcoZmFsc2UpLFxyXG5cclxuICAvLyBzZXJ2ZXJcclxuICBTRVJWRVJfRU5BQkxFOiB2YWxpZGF0b3JzLmVuYWJsZVNlcnZlcihmYWxzZSksXHJcbiAgU0VSVkVSX0hPU1Q6IHZhbGlkYXRvcnMuaG9zdChmYWxzZSksXHJcbiAgU0VSVkVSX1BPUlQ6IHZhbGlkYXRvcnMucG9ydChmYWxzZSksXHJcbiAgU0VSVkVSX1VQTE9BRF9MSU1JVDogdmFsaWRhdG9ycy51cGxvYWRMaW1pdChmYWxzZSksXHJcbiAgU0VSVkVSX0JFTkNITUFSS0lORzogdmFsaWRhdG9ycy5zZXJ2ZXJCZW5jaG1hcmtpbmcoZmFsc2UpLFxyXG5cclxuICAvLyBzZXJ2ZXIgcHJveHlcclxuICBTRVJWRVJfUFJPWFlfSE9TVDogdmFsaWRhdG9ycy5wcm94eUhvc3QoZmFsc2UpLFxyXG4gIFNFUlZFUl9QUk9YWV9QT1JUOiB2YWxpZGF0b3JzLnByb3h5UG9ydChmYWxzZSksXHJcbiAgU0VSVkVSX1BST1hZX1RJTUVPVVQ6IHZhbGlkYXRvcnMucHJveHlUaW1lb3V0KGZhbHNlKSxcclxuXHJcbiAgLy8gc2VydmVyIHJhdGUgbGltaXRpbmdcclxuICBTRVJWRVJfUkFURV9MSU1JVElOR19FTkFCTEU6IHZhbGlkYXRvcnMuZW5hYmxlUmF0ZUxpbWl0aW5nKGZhbHNlKSxcclxuICBTRVJWRVJfUkFURV9MSU1JVElOR19NQVhfUkVRVUVTVFM6IHZhbGlkYXRvcnMubWF4UmVxdWVzdHMoZmFsc2UpLFxyXG4gIFNFUlZFUl9SQVRFX0xJTUlUSU5HX1dJTkRPVzogdmFsaWRhdG9ycy53aW5kb3coZmFsc2UpLFxyXG4gIFNFUlZFUl9SQVRFX0xJTUlUSU5HX0RFTEFZOiB2YWxpZGF0b3JzLmRlbGF5KGZhbHNlKSxcclxuICBTRVJWRVJfUkFURV9MSU1JVElOR19UUlVTVF9QUk9YWTogdmFsaWRhdG9ycy50cnVzdFByb3h5KGZhbHNlKSxcclxuICBTRVJWRVJfUkFURV9MSU1JVElOR19TS0lQX0tFWTogdmFsaWRhdG9ycy5za2lwS2V5KGZhbHNlKSxcclxuICBTRVJWRVJfUkFURV9MSU1JVElOR19TS0lQX1RPS0VOOiB2YWxpZGF0b3JzLnNraXBUb2tlbihmYWxzZSksXHJcblxyXG4gIC8vIHNlcnZlciBzc2xcclxuICBTRVJWRVJfU1NMX0VOQUJMRTogdmFsaWRhdG9ycy5lbmFibGVTc2woZmFsc2UpLFxyXG4gIFNFUlZFUl9TU0xfRk9SQ0U6IHZhbGlkYXRvcnMuc3NsRm9yY2UoZmFsc2UpLFxyXG4gIFNFUlZFUl9TU0xfUE9SVDogdmFsaWRhdG9ycy5zc2xQb3J0KGZhbHNlKSxcclxuICBTRVJWRVJfU1NMX0NFUlRfUEFUSDogdmFsaWRhdG9ycy5zc2xDZXJ0UGF0aChmYWxzZSksXHJcblxyXG4gIC8vIHBvb2xcclxuICBQT09MX01JTl9XT1JLRVJTOiB2YWxpZGF0b3JzLm1pbldvcmtlcnMoZmFsc2UpLFxyXG4gIFBPT0xfTUFYX1dPUktFUlM6IHZhbGlkYXRvcnMubWF4V29ya2VycyhmYWxzZSksXHJcbiAgUE9PTF9XT1JLX0xJTUlUOiB2YWxpZGF0b3JzLndvcmtMaW1pdChmYWxzZSksXHJcbiAgUE9PTF9BQ1FVSVJFX1RJTUVPVVQ6IHZhbGlkYXRvcnMuYWNxdWlyZVRpbWVvdXQoZmFsc2UpLFxyXG4gIFBPT0xfQ1JFQVRFX1RJTUVPVVQ6IHZhbGlkYXRvcnMuY3JlYXRlVGltZW91dChmYWxzZSksXHJcbiAgUE9PTF9ERVNUUk9ZX1RJTUVPVVQ6IHZhbGlkYXRvcnMuZGVzdHJveVRpbWVvdXQoZmFsc2UpLFxyXG4gIFBPT0xfSURMRV9USU1FT1VUOiB2YWxpZGF0b3JzLmlkbGVUaW1lb3V0KGZhbHNlKSxcclxuICBQT09MX0NSRUFURV9SRVRSWV9JTlRFUlZBTDogdmFsaWRhdG9ycy5jcmVhdGVSZXRyeUludGVydmFsKGZhbHNlKSxcclxuICBQT09MX1JFQVBFUl9JTlRFUlZBTDogdmFsaWRhdG9ycy5yZWFwZXJJbnRlcnZhbChmYWxzZSksXHJcbiAgUE9PTF9CRU5DSE1BUktJTkc6IHZhbGlkYXRvcnMucG9vbEJlbmNobWFya2luZyhmYWxzZSksXHJcblxyXG4gIC8vIGxvZ2dpbmdcclxuICBMT0dHSU5HX0xFVkVMOiB2YWxpZGF0b3JzLmxvZ0xldmVsKGZhbHNlKSxcclxuICBMT0dHSU5HX0ZJTEU6IHZhbGlkYXRvcnMubG9nRmlsZShmYWxzZSksXHJcbiAgTE9HR0lOR19ERVNUOiB2YWxpZGF0b3JzLmxvZ0Rlc3QoZmFsc2UpLFxyXG4gIExPR0dJTkdfVE9fQ09OU09MRTogdmFsaWRhdG9ycy5sb2dUb0NvbnNvbGUoZmFsc2UpLFxyXG4gIExPR0dJTkdfVE9fRklMRTogdmFsaWRhdG9ycy5sb2dUb0ZpbGUoZmFsc2UpLFxyXG5cclxuICAvLyB1aVxyXG4gIFVJX0VOQUJMRTogdmFsaWRhdG9ycy5lbmFibGVVaShmYWxzZSksXHJcbiAgVUlfUk9VVEU6IHZhbGlkYXRvcnMudWlSb3V0ZShmYWxzZSksXHJcblxyXG4gIC8vIG90aGVyXHJcbiAgT1RIRVJfTk9ERV9FTlY6IHZhbGlkYXRvcnMubm9kZUVudihmYWxzZSksXHJcbiAgT1RIRVJfTElTVEVOX1RPX1BST0NFU1NfRVhJVFM6IHZhbGlkYXRvcnMubGlzdGVuVG9Qcm9jZXNzRXhpdHMoZmFsc2UpLFxyXG4gIE9USEVSX05PX0xPR086IHZhbGlkYXRvcnMubm9Mb2dvKGZhbHNlKSxcclxuICBPVEhFUl9IQVJEX1JFU0VUX1BBR0U6IHZhbGlkYXRvcnMuaGFyZFJlc2V0UGFnZShmYWxzZSksXHJcbiAgT1RIRVJfQlJPV1NFUl9TSEVMTF9NT0RFOiB2YWxpZGF0b3JzLmJyb3dzZXJTaGVsbE1vZGUoZmFsc2UpLFxyXG4gIE9USEVSX1ZBTElEQVRJT046IHZhbGlkYXRvcnMudmFsaWRhdGlvbihmYWxzZSksXHJcblxyXG4gIC8vIGRlYnVnZ2VyXHJcbiAgREVCVUdfRU5BQkxFOiB2YWxpZGF0b3JzLmVuYWJsZURlYnVnKGZhbHNlKSxcclxuICBERUJVR19IRUFETEVTUzogdmFsaWRhdG9ycy5oZWFkbGVzcyhmYWxzZSksXHJcbiAgREVCVUdfREVWVE9PTFM6IHZhbGlkYXRvcnMuZGV2dG9vbHMoZmFsc2UpLFxyXG4gIERFQlVHX0xJU1RFTl9UT19DT05TT0xFOiB2YWxpZGF0b3JzLmxpc3RlblRvQ29uc29sZShmYWxzZSksXHJcbiAgREVCVUdfRFVNUElPOiB2YWxpZGF0b3JzLmR1bXBpbyhmYWxzZSksXHJcbiAgREVCVUdfU0xPV19NTzogdmFsaWRhdG9ycy5zbG93TW8oZmFsc2UpLFxyXG4gIERFQlVHX0RFQlVHR0lOR19QT1JUOiB2YWxpZGF0b3JzLmRlYnVnZ2luZ1BvcnQoZmFsc2UpXHJcbn0pO1xyXG5cclxuLyoqXHJcbiAqIFZhbGlkYXRlcyB0aGUgZW52aXJvbm1lbnQgdmFyaWFibGVzIG9wdGlvbnMgdXNpbmcgdGhlIEVudlNjaGVtYS5cclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IHByb2Nlc3MuZW52IC0gVGhlIGNvbmZpZ3VyYXRpb24gb3B0aW9ucyBmcm9tIGVudmlyb25tZW50XHJcbiAqIHZhcmlhYmxlcyBmaWxlIHRvIHZhbGlkYXRlLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7T2JqZWN0fSBUaGUgcGFyc2VkIGFuZCB2YWxpZGF0ZWQgZW52aXJvbm1lbnQgdmFyaWFibGVzLlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IGVudnMgPSBFbnZTY2hlbWEucGFydGlhbCgpLnBhcnNlKHByb2Nlc3MuZW52KTtcclxuXHJcbi8qKlxyXG4gKiBWYWxpZGF0ZXMgdGhlIGNvbmZpZ3VyYXRpb24gb3B0aW9ucyB1c2luZyB0aGUgYFN0cmljdENvbmZpZ1NjaGVtYWAuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBzdHJpY3RWYWxpZGF0ZVxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gY29uZmlnT3B0aW9ucyAtIFRoZSBjb25maWd1cmF0aW9uIG9wdGlvbnMgdG8gdmFsaWRhdGUuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtPYmplY3R9IFRoZSBwYXJzZWQgYW5kIHZhbGlkYXRlZCBjb25maWd1cmF0aW9uIG9wdGlvbnMuXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gc3RyaWN0VmFsaWRhdGUoY29uZmlnT3B0aW9ucykge1xyXG4gIHJldHVybiBTdHJpY3RDb25maWdTY2hlbWEucGFydGlhbCgpLnBhcnNlKGNvbmZpZ09wdGlvbnMpO1xyXG59XHJcblxyXG4vKipcclxuICogVmFsaWRhdGVzIHRoZSBjb25maWd1cmF0aW9uIG9wdGlvbnMgdXNpbmcgdGhlIGBMb29zZUNvbmZpZ1NjaGVtYWAuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBsb29zZVZhbGlkYXRlXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBjb25maWdPcHRpb25zIC0gVGhlIGNvbmZpZ3VyYXRpb24gb3B0aW9ucyB0byB2YWxpZGF0ZS5cclxuICpcclxuICogQHJldHVybnMge09iamVjdH0gVGhlIHBhcnNlZCBhbmQgdmFsaWRhdGVkIGNvbmZpZ3VyYXRpb24gb3B0aW9ucy5cclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiBsb29zZVZhbGlkYXRlKGNvbmZpZ09wdGlvbnMpIHtcclxuICByZXR1cm4gTG9vc2VDb25maWdTY2hlbWEucGFydGlhbCgpLnBhcnNlKGNvbmZpZ09wdGlvbnMpO1xyXG59XHJcblxyXG4vKipcclxuICogQ3VzdG9tIGVycm9yIG1hcHBpbmcgZnVuY3Rpb24gZm9yIFpvZCBzY2hlbWEgdmFsaWRhdGlvbi5cclxuICpcclxuICogVGhpcyBmdW5jdGlvbiBjdXN0b21pemVzIHRoZSBlcnJvciBtZXNzYWdlcyBwcm9kdWNlZCBieSBab2Qgc2NoZW1hXHJcbiAqIHZhbGlkYXRpb24sIHByb3ZpZGluZyBtb3JlIHNwZWNpZmljIGFuZCB1c2VyLWZyaWVuZGx5IGZlZWRiYWNrIGJhc2VkIG9uIHRoZVxyXG4gKiBpc3N1ZSB0eXBlIGFuZCBjb250ZXh0LlxyXG4gKlxyXG4gKiBUaGUgZnVuY3Rpb24gbW9kaWZpZXMgdGhlIGVycm9yIG1lc3NhZ2VzIGFzIGZvbGxvd3M6XHJcbiAqXHJcbiAqIC0gRm9yIG1pc3NpbmcgcmVxdWlyZWQgdmFsdWVzICh1bmRlZmluZWQpLCBpdCByZXR1cm5zIGEgbWVzc2FnZSBpbmRpY2F0aW5nXHJcbiAqIHRoYXQgbm8gdmFsdWUgd2FzIHByb3ZpZGVkIGZvciB0aGUgc3BlY2lmaWMgcHJvcGVydHkuXHJcbiAqXHJcbiAqIC0gRm9yIGN1c3RvbSB2YWxpZGF0aW9uIGVycm9ycywgaWYgYSBjdXN0b20gZXJyb3IgbWVzc2FnZSBpcyBwcm92aWRlZCBpbiB0aGVcclxuICogaXNzdWUgcGFyYW1ldGVycywgaXQgaW5jbHVkZXMgdGhpcyBtZXNzYWdlIGFsb25nIHdpdGggdGhlIGludmFsaWQgZGF0YVxyXG4gKiByZWNlaXZlZC5cclxuICpcclxuICogLSBGb3IgYWxsIG90aGVyIGVycm9ycywgaXQgYXBwZW5kcyBwcm9wZXJ0eS1zcGVjaWZpYyBpbmZvcm1hdGlvbiB0byB0aGVcclxuICogZGVmYXVsdCBlcnJvciBtZXNzYWdlIHByb3ZpZGVkIGJ5IFpvZC5cclxuICpcclxuICogQGZ1bmN0aW9uIF9jdXN0b21FcnJvck1hcFxyXG4gKlxyXG4gKiBAcGFyYW0ge3ouWm9kSXNzdWV9IGlzc3VlIC0gVGhlIGlzc3VlIG9iamVjdCByZXByZXNlbnRpbmcgdGhlIHZhbGlkYXRpb25cclxuICogZXJyb3IuXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBjb250ZXh0IC0gVGhlIGNvbnRleHQgb2JqZWN0IHByb3ZpZGluZyBhZGRpdGlvbmFsIGluZm9ybWF0aW9uXHJcbiAqIGFib3V0IHRoZSB2YWxpZGF0aW9uIGVycm9yLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7T2JqZWN0fSBBbiBvYmplY3QgY29udGFpbmluZyB0aGUgY3VzdG9taXplZCBlcnJvciBtZXNzYWdlLlxyXG4gKi9cclxuZnVuY3Rpb24gX2N1c3RvbUVycm9yTWFwKGlzc3VlLCBjb250ZXh0KSB7XHJcbiAgLy8gR2V0IHRoZSBjaGFpbiBvZiBwcm9wZXJ0aWVzIHdoaWNoIGVycm9yIGRpcmVjdGx5IHJlZmVycyB0b1xyXG4gIGNvbnN0IHByb3BlcnR5TmFtZSA9IGlzc3VlLnBhdGguam9pbignLicpO1xyXG5cclxuICAvLyBDcmVhdGUgdGhlIGZpcnN0IHBhcnQgb2YgdGhlIG1lc3NhZ2UgYWJvdXQgdGhlIHByb3BlcnR5IGluZm9ybWF0aW9uXHJcbiAgY29uc3QgcHJvcGVydHlJbmZvID0gYEludmFsaWQgdmFsdWUgZm9yIHRoZSAke3Byb3BlcnR5TmFtZX1gO1xyXG5cclxuICAvLyBNb2RpZmllZCBtZXNzYWdlIGZvciB0aGUgaW52YWxpZCB0eXBlXHJcbiAgaWYgKGlzc3VlLmNvZGUgPT09IHouWm9kSXNzdWVDb2RlLmludmFsaWRfdHlwZSkge1xyXG4gICAgLy8gTW9kaWZpZWQgbWVzc2FnZSBmb3IgdGhlIHJlcXVpcmVkIHZhbHVlc1xyXG4gICAgaWYgKGlzc3VlLnJlY2VpdmVkID09PSB6LlpvZFBhcnNlZFR5cGUudW5kZWZpbmVkKSB7XHJcbiAgICAgIHJldHVybiB7XHJcbiAgICAgICAgbWVzc2FnZTogYCR7cHJvcGVydHlJbmZvfSAtIE5vIHZhbHVlIHdhcyBwcm92aWRlZC5gXHJcbiAgICAgIH07XHJcbiAgICB9XHJcblxyXG4gICAgLy8gTW9kaWZpZWQgbWVzc2FnZSBmb3IgdGhlIHNwZWNpZmljIGludmFsaWQgdHlwZSB3aGVuIHZhbHVlcyBleGlzdFxyXG4gICAgcmV0dXJuIHtcclxuICAgICAgbWVzc2FnZTogYCR7cHJvcGVydHlJbmZvfSAtIEludmFsaWQgdHlwZS4gJHtjb250ZXh0LmRlZmF1bHRFcnJvcn0uYFxyXG4gICAgfTtcclxuICB9XHJcblxyXG4gIC8vIE1vZGlmaWVkIG1lc3NhZ2UgZm9yIHRoZSBjdXN0b20gdmFsaWRhdGlvblxyXG4gIGlmIChpc3N1ZS5jb2RlID09PSB6LlpvZElzc3VlQ29kZS5jdXN0b20pIHtcclxuICAgIC8vIElmIHRoZSBjdXN0b20gbWVzc2FnZSBmb3IgZXJyb3IgZXhpc3QsIGluY2x1ZGUgaXRcclxuICAgIGlmIChpc3N1ZS5wYXJhbXM/LmVycm9yTWVzc2FnZSkge1xyXG4gICAgICByZXR1cm4ge1xyXG4gICAgICAgIG1lc3NhZ2U6IGAke3Byb3BlcnR5SW5mb30gLSAke2lzc3VlLnBhcmFtcz8uZXJyb3JNZXNzYWdlfSwgcmVjZWl2ZWQgJyR7Y29udGV4dC5kYXRhfScuYFxyXG4gICAgICB9O1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgLy8gTW9kaWZpZWQgbWVzc2FnZSBmb3IgdGhlIGludmFsaWQgdW5pb24gZXJyb3JcclxuICBpZiAoaXNzdWUuY29kZSA9PT0gei5ab2RJc3N1ZUNvZGUuaW52YWxpZF91bmlvbikge1xyXG4gICAgLy8gQ3JlYXRlIHRoZSBmaXJzdCBwYXJ0IG9mIHRoZSBtZXNzYWdlIGFib3V0IHRoZSBtdWx0aXBsZSBlcnJvcnNcclxuICAgIGxldCBtZXNzYWdlID0gYE11bHRpcGxlIGVycm9ycyBvY2N1cnJlZCBmb3IgdGhlICR7cHJvcGVydHlOYW1lfTpcXG5gO1xyXG5cclxuICAgIC8vIEN5Y2xlIHRocm91Z2ggYWxsIGVycm9ycyBhbmQgY3JlYXRlIGEgY29ycmVjdCBtZXNzYWdlXHJcbiAgICBpc3N1ZS51bmlvbkVycm9ycy5mb3JFYWNoKCh2YWx1ZSkgPT4ge1xyXG4gICAgICBjb25zdCBpbmRleCA9IHZhbHVlLmlzc3Vlc1swXS5tZXNzYWdlLmluZGV4T2YoJy0nKTtcclxuICAgICAgbWVzc2FnZSArPVxyXG4gICAgICAgIGluZGV4ICE9PSAtMVxyXG4gICAgICAgICAgPyBgJHt2YWx1ZS5pc3N1ZXNbMF0ubWVzc2FnZX1cXG5gLnN1YnN0cmluZyhpbmRleClcclxuICAgICAgICAgIDogYCR7dmFsdWUuaXNzdWVzWzBdLm1lc3NhZ2V9XFxuYDtcclxuICAgIH0pO1xyXG5cclxuICAgIC8vIFJldHVybiB0aGUgZmluYWwgbWVzc2FnZSBmb3IgdGhlIGludmFsaWQgdW5pb24gZXJyb3JcclxuICAgIHJldHVybiB7XHJcbiAgICAgIG1lc3NhZ2VcclxuICAgIH07XHJcbiAgfVxyXG5cclxuICAvLyBSZXR1cm4gdGhlIGRlZmF1bHQgZXJyb3IgbWVzc2FnZSwgZXh0ZW5kZWQgYnkgdGhlIGluZm8gYWJvdXQgdGhlIHByb3BlcnR5XHJcbiAgcmV0dXJuIHtcclxuICAgIG1lc3NhZ2U6IGAke3Byb3BlcnR5SW5mb30gLSAke2NvbnRleHQuZGVmYXVsdEVycm9yfS5gXHJcbiAgfTtcclxufVxyXG5cclxuZXhwb3J0IGRlZmF1bHQge1xyXG4gIHZhbGlkYXRvcnMsXHJcbiAgU3RyaWN0Q29uZmlnU2NoZW1hLFxyXG4gIExvb3NlQ29uZmlnU2NoZW1hLFxyXG4gIEVudlNjaGVtYSxcclxuICBlbnZzLFxyXG4gIHN0cmljdFZhbGlkYXRlLFxyXG4gIGxvb3NlVmFsaWRhdGVcclxufTtcclxuIiwiLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcclxuXHJcbkhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlclxyXG5cclxuQ29weXJpZ2h0IChjKSAyMDE2LTIwMjUsIEhpZ2hzb2Z0XHJcblxyXG5MaWNlbmNlZCB1bmRlciB0aGUgTUlUIGxpY2VuY2UuXHJcblxyXG5BZGRpdGlvbmFsbHkgYSB2YWxpZCBIaWdoY2hhcnRzIGxpY2Vuc2UgaXMgcmVxdWlyZWQgZm9yIHVzZS5cclxuXHJcblNlZSBMSUNFTlNFIGZpbGUgaW4gcm9vdCBmb3IgZGV0YWlscy5cclxuXHJcbioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXHJcblxyXG4vKipcclxuICogQSBjdXN0b20gZXJyb3IgY2xhc3MgZm9yIGhhbmRsaW5nIGV4cG9ydC1yZWxhdGVkIGVycm9ycy4gRXh0ZW5kcyB0aGUgbmF0aXZlXHJcbiAqIGBFcnJvcmAgY2xhc3MgdG8gaW5jbHVkZSBhZGRpdGlvbmFsIHByb3BlcnRpZXMgbGlrZSBzdGF0dXMgY29kZSBhbmQgc3RhY2tcclxuICogdHJhY2UgZGV0YWlscy5cclxuICovXHJcbmNsYXNzIEV4cG9ydEVycm9yIGV4dGVuZHMgRXJyb3Ige1xyXG4gIC8qKlxyXG4gICAqIENyZWF0ZXMgYW4gaW5zdGFuY2Ugb2YgdGhlIGBFeHBvcnRFcnJvcmAuXHJcbiAgICpcclxuICAgKiBAcGFyYW0ge3N0cmluZ30gbWVzc2FnZSAtIFRoZSBlcnJvciBtZXNzYWdlIHRvIGJlIGRpc3BsYXllZC5cclxuICAgKiBAcGFyYW0ge251bWJlcn0gc3RhdHVzQ29kZSAtIE9wdGlvbmFsIEhUVFAgc3RhdHVzIGNvZGUgYXNzb2NpYXRlZFxyXG4gICAqIHdpdGggdGhlIGVycm9yIChlLmcuLCA0MDAsIDUwMCkuXHJcbiAgICovXHJcbiAgY29uc3RydWN0b3IobWVzc2FnZSwgc3RhdHVzQ29kZSkge1xyXG4gICAgc3VwZXIoKTtcclxuXHJcbiAgICB0aGlzLm1lc3NhZ2UgPSBtZXNzYWdlO1xyXG4gICAgdGhpcy5zdGFja01lc3NhZ2UgPSBtZXNzYWdlO1xyXG5cclxuICAgIGlmIChzdGF0dXNDb2RlKSB7XHJcbiAgICAgIHRoaXMuc3RhdHVzQ29kZSA9IHN0YXR1c0NvZGU7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICAvKipcclxuICAgKiBTZXRzIG9yIHVwZGF0ZXMgdGhlIEhUVFAgc3RhdHVzIGNvZGUgZm9yIHRoZSBlcnJvci5cclxuICAgKlxyXG4gICAqIEBwYXJhbSB7bnVtYmVyfSBzdGF0dXNDb2RlIC0gVGhlIEhUVFAgc3RhdHVzIGNvZGUgdG8gYXNzaWduIHRvIHRoZSBlcnJvci5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHtFeHBvcnRFcnJvcn0gVGhlIHVwZGF0ZWQgaW5zdGFuY2Ugb2YgdGhlIGBFeHBvcnRFcnJvcmAgY2xhc3MuXHJcbiAgICovXHJcbiAgc2V0U3RhdHVzKHN0YXR1c0NvZGUpIHtcclxuICAgIHRoaXMuc3RhdHVzQ29kZSA9IHN0YXR1c0NvZGU7XHJcblxyXG4gICAgcmV0dXJuIHRoaXM7XHJcbiAgfVxyXG5cclxuICAvKipcclxuICAgKiBTZXRzIGFkZGl0aW9uYWwgZXJyb3IgZGV0YWlscyBiYXNlZCBvbiBhbiBleGlzdGluZyBlcnJvciBvYmplY3QuXHJcbiAgICpcclxuICAgKiBAcGFyYW0ge0Vycm9yfSBlcnJvciAtIEFuIGVycm9yIG9iamVjdCBjb250YWluaW5nIGRldGFpbHMgdG8gcG9wdWxhdGVcclxuICAgKiB0aGUgYEV4cG9ydEVycm9yYCBpbnN0YW5jZS5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHtFeHBvcnRFcnJvcn0gVGhlIHVwZGF0ZWQgaW5zdGFuY2Ugb2YgdGhlIGBFeHBvcnRFcnJvcmAgY2xhc3MuXHJcbiAgICovXHJcbiAgc2V0RXJyb3IoZXJyb3IpIHtcclxuICAgIHRoaXMuZXJyb3IgPSBlcnJvcjtcclxuXHJcbiAgICBpZiAoZXJyb3IubmFtZSkge1xyXG4gICAgICB0aGlzLm5hbWUgPSBlcnJvci5uYW1lO1xyXG4gICAgfVxyXG5cclxuICAgIGlmIChlcnJvci5zdGF0dXNDb2RlKSB7XHJcbiAgICAgIHRoaXMuc3RhdHVzQ29kZSA9IGVycm9yLnN0YXR1c0NvZGU7XHJcbiAgICB9XHJcblxyXG4gICAgaWYgKGVycm9yLnN0YWNrKSB7XHJcbiAgICAgIHRoaXMuc3RhY2tNZXNzYWdlID0gZXJyb3IubWVzc2FnZTtcclxuICAgICAgdGhpcy5zdGFjayA9IGVycm9yLnN0YWNrO1xyXG4gICAgfVxyXG5cclxuICAgIHJldHVybiB0aGlzO1xyXG4gIH1cclxufVxyXG5cclxuZXhwb3J0IGRlZmF1bHQgRXhwb3J0RXJyb3I7XHJcbiIsIi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXHJcblxyXG5IaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXJcclxuXHJcbkNvcHlyaWdodCAoYykgMjAxNi0yMDI1LCBIaWdoc29mdFxyXG5cclxuTGljZW5jZWQgdW5kZXIgdGhlIE1JVCBsaWNlbmNlLlxyXG5cclxuQWRkaXRpb25hbGx5IGEgdmFsaWQgSGlnaGNoYXJ0cyBsaWNlbnNlIGlzIHJlcXVpcmVkIGZvciB1c2UuXHJcblxyXG5TZWUgTElDRU5TRSBmaWxlIGluIHJvb3QgZm9yIGRldGFpbHMuXHJcblxyXG4qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xyXG5cclxuLyoqXHJcbiAqIEBvdmVydmlldyBNYW5hZ2VzIGNvbmZpZ3VyYXRpb24gZm9yIHRoZSBIaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXIgYnkgbG9hZGluZ1xyXG4gKiBhbmQgbWVyZ2luZyBvcHRpb25zIGZyb20gbXVsdGlwbGUgc291cmNlcywgc3VjaCBhcyBkZWZhdWx0IHNldHRpbmdzLFxyXG4gKiBlbnZpcm9ubWVudCB2YXJpYWJsZXMsIHVzZXItcHJvdmlkZWQgb3B0aW9ucywgYW5kIGNvbW1hbmQtbGluZSBhcmd1bWVudHMuXHJcbiAqIEVuc3VyZXMgdGhlIGdsb2JhbCBvcHRpb25zIGFyZSB1cC10by1kYXRlIHdpdGggdGhlIGhpZ2hlc3QgcHJpb3JpdHkgdmFsdWVzLlxyXG4gKiBQcm92aWRlcyBmdW5jdGlvbnMgZm9yIGFjY2Vzc2luZyBhbmQgdXBkYXRpbmcgY29uZmlndXJhdGlvbi5cclxuICovXHJcblxyXG5pbXBvcnQgeyByZWFkRmlsZVN5bmMgfSBmcm9tICdmcyc7XHJcbmltcG9ydCB7IGpvaW4gfSBmcm9tICdwYXRoJztcclxuXHJcbmltcG9ydCB7IGxvZywgbG9nV2l0aFN0YWNrLCBsb2dab2RJc3N1ZXMgfSBmcm9tICcuL2xvZ2dlci5qcyc7XHJcbmltcG9ydCB7IF9fZGlybmFtZSwgZGVlcENvcHksIGdldEFic29sdXRlUGF0aCwgaXNPYmplY3QgfSBmcm9tICcuL3V0aWxzLmpzJztcclxuaW1wb3J0IHtcclxuICBlbnZzLFxyXG4gIGxvb3NlVmFsaWRhdGUsXHJcbiAgc3RyaWN0VmFsaWRhdGUsXHJcbiAgdmFsaWRhdG9yc1xyXG59IGZyb20gJy4vdmFsaWRhdGlvbi5qcyc7XHJcblxyXG5pbXBvcnQgeyBkZWZhdWx0Q29uZmlnLCBhYnNvbHV0ZVByb3BzLCBuZXN0ZWRQcm9wcyB9IGZyb20gJy4vc2NoZW1hcy9jb25maWcuanMnO1xyXG5cclxuaW1wb3J0IEV4cG9ydEVycm9yIGZyb20gJy4vZXJyb3JzL0V4cG9ydEVycm9yLmpzJztcclxuXHJcbi8vIFNldHMgdGhlIGdsb2JhbCBvcHRpb25zIHdpdGggaW5pdGlhbCB2YWx1ZXMgZnJvbSB0aGUgZGVmYXVsdCBjb25maWdcclxuY29uc3QgZ2xvYmFsT3B0aW9ucyA9IF9pbml0T3B0aW9ucyhkZWZhdWx0Q29uZmlnKTtcclxuXHJcbi8qKlxyXG4gKiBSZXRyaWV2ZXMgYSBjb3B5IG9mIHRoZSBnbG9iYWwgb3B0aW9ucyBvYmplY3Qgb3IgYSByZWZlcmVuY2UgdG8gdGhlIGdsb2JhbFxyXG4gKiBvcHRpb25zIG9iamVjdCwgYmFzZWQgb24gdGhlIGBnZXRDb3B5YCBmbGFnLlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gZ2V0T3B0aW9uc1xyXG4gKlxyXG4gKiBAcGFyYW0ge2Jvb2xlYW59IFtnZXRDb3B5PXRydWVdIC0gU3BlY2lmaWVzIHdoZXRoZXIgdG8gcmV0dXJuIGEgY29waWVkXHJcbiAqIG9iamVjdCBvZiB0aGUgZ2xvYmFsIG9wdGlvbnMgKGB0cnVlYCkgb3IgYSByZWZlcmVuY2UgdG8gdGhlIGdsb2JhbCBvcHRpb25zXHJcbiAqIG9iamVjdCAoYGZhbHNlYCkuIFRoZSBkZWZhdWx0IHZhbHVlIGlzIGBmYWxzZWAuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtPYmplY3R9IEEgY29weSBvZiB0aGUgZ2xvYmFsIG9wdGlvbnMgb2JqZWN0LCBvciBhIHJlZmVyZW5jZVxyXG4gKiB0byB0aGUgZ2xvYmFsIG9wdGlvbnMgb2JqZWN0LlxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIGdldE9wdGlvbnMoZ2V0Q29weSA9IHRydWUpIHtcclxuICByZXR1cm4gZ2V0Q29weSA/IGRlZXBDb3B5KGdsb2JhbE9wdGlvbnMpIDogZ2xvYmFsT3B0aW9ucztcclxufVxyXG5cclxuLyoqXHJcbiAqIFVwZGF0ZXMgYSBjb3B5IG9mIHRoZSBnbG9iYWwgb3B0aW9ucyBvYmplY3Qgb3IgYSByZWZlcmVuY2UgdG8gdGhlIGdsb2JhbFxyXG4gKiBvcHRpb25zIG9iamVjdCwgYmFzZWQgb24gdGhlIGBnZXRDb3B5YCBmbGFnLlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gdXBkYXRlT3B0aW9uc1xyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gbmV3T3B0aW9ucyAtIEFuIG9iamVjdCBjb250YWluaW5nIHRoZSBuZXcgb3B0aW9ucyB0byBiZVxyXG4gKiBtZXJnZWQgaW50byB0aGUgZ2xvYmFsIG9wdGlvbnMuXHJcbiAqIEBwYXJhbSB7Ym9vbGVhbn0gW2dldENvcHk9ZmFsc2VdIC0gRGV0ZXJtaW5lcyB3aGV0aGVyIHRvIG1lcmdlIHRoZSBuZXdcclxuICogb3B0aW9ucyBpbnRvIGEgY29weSBvZiB0aGUgZ2xvYmFsIG9wdGlvbnMgb2JqZWN0IChgdHJ1ZWApIG9yIGRpcmVjdGx5IGludG9cclxuICogdGhlIGdsb2JhbCBvcHRpb25zIG9iamVjdCAoYGZhbHNlYCkuIFRoZSBkZWZhdWx0IHZhbHVlIGlzIGBmYWxzZWAuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtPYmplY3R9IFRoZSB1cGRhdGVkIG9wdGlvbnMgb2JqZWN0LCBlaXRoZXIgdGhlIG1vZGlmaWVkIGdsb2JhbFxyXG4gKiBvcHRpb25zIG9yIGEgbW9kaWZpZWQgY29weSwgYmFzZWQgb24gdGhlIHZhbHVlIG9mIGBnZXRDb3B5YC5cclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiB1cGRhdGVPcHRpb25zKG5ld09wdGlvbnMsIGdldENvcHkgPSBmYWxzZSkge1xyXG4gIC8vIE1lcmdlIG5ldyBvcHRpb25zIHRvIHRoZSBnbG9iYWwgb3B0aW9ucyBvciBpdHMgY29weSBhbmQgcmV0dXJuIHRoZSByZXN1bHRcclxuICByZXR1cm4gX21lcmdlT3B0aW9ucyhnZXRPcHRpb25zKGdldENvcHkpLCBuZXdPcHRpb25zKTtcclxufVxyXG5cclxuLyoqXHJcbiAqIFVwZGF0ZXMgdGhlIGdsb2JhbCBvcHRpb25zIHdpdGggdmFsdWVzIHByb3ZpZGVkIHRocm91Z2ggdGhlIENMSSwga2VlcGluZ1xyXG4gKiB0aGUgcHJpbmNpcGxlIG9mIG9wdGlvbnMgbG9hZCBwcmlvcml0eS4gVGhpcyBmdW5jdGlvbiBhY2NlcHRzIGEgYGNsaUFyZ3NgXHJcbiAqIGFycmF5IGNvbnRhaW5pbmcgYXJndW1lbnRzIGZyb20gdGhlIENMSSwgd2hpY2ggd2lsbCBiZSB2YWxpZGF0ZWQgYW5kIGFwcGxpZWRcclxuICogaWYgcHJvdmlkZWQuXHJcbiAqXHJcbiAqIFRoZSBwcmlvcml0eSBvcmRlciBmb3Igc2V0dGluZyB2YWx1ZXMgaXM6XHJcbiAqXHJcbiAqIDEuIFZhbHVlcyBmcm9tIGEgY3VzdG9tIEpTT04gZmlsZSAobG9hZGVkIGJ5IHRoZSBgLS1sb2FkQ29uZmlnYCBvcHRpb24pLlxyXG4gKiAyLiBWYWx1ZXMgZnJvbSB0aGUgY29tbWFuZCBsaW5lIGludGVyZmFjZSAoQ0xJKS5cclxuICpcclxuICogQGZ1bmN0aW9uIHNldENsaU9wdGlvbnNcclxuICpcclxuICogQHBhcmFtIHtBcnJheS48c3RyaW5nPn0gY2xpQXJncyAtIEFuIGFycmF5IG9mIGNvbW1hbmQgbGluZSBhcmd1bWVudHMgdXNlZFxyXG4gKiBmb3IgYWRkaXRpb25hbCBjb25maWd1cmF0aW9uLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7T2JqZWN0fSBUaGUgdXBkYXRlZCBnbG9iYWwgb3B0aW9ucyBvYmplY3QsIHJlZmxlY3RpbmcgdGhlIG1lcmdlZFxyXG4gKiBjb25maWd1cmF0aW9uIGZyb20gc291cmNlcyBwcm92aWRlZCB0aHJvdWdoIHRoZSBDTEkuXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gc2V0Q2xpT3B0aW9ucyhjbGlBcmdzKSB7XHJcbiAgLy8gT25seSBmb3IgdGhlIENMSSB1c2FnZVxyXG4gIGlmIChjbGlBcmdzICYmIEFycmF5LmlzQXJyYXkoY2xpQXJncykgJiYgY2xpQXJncy5sZW5ndGgpIHtcclxuICAgIHRyeSB7XHJcbiAgICAgIC8vIFZhbGlkYXRlIG9wdGlvbnMgZnJvbSB0aGUgY3VzdG9tIEpTT04gbG9hZGVkIHZpYSB0aGUgYC0tbG9hZENvbmZpZ2BcclxuICAgICAgY29uc3QgY29uZmlnT3B0aW9ucyA9IHN0cmljdFZhbGlkYXRlKF9sb2FkQ29uZmlnRmlsZShjbGlBcmdzKSk7XHJcblxyXG4gICAgICAvLyBVcGRhdGUgZ2xvYmFsIG9wdGlvbnMgd2l0aCB0aGUgdmFsdWVzIGZyb20gdGhlIGBjb25maWdPcHRpb25zYFxyXG4gICAgICB1cGRhdGVPcHRpb25zKGNvbmZpZ09wdGlvbnMpO1xyXG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICAgbG9nWm9kSXNzdWVzKFxyXG4gICAgICAgIDEsXHJcbiAgICAgICAgZXJyb3IuaXNzdWVzLFxyXG4gICAgICAgICdbdmFsaWRhdGlvbl0gQ3VzdG9tIG9wdGlvbnMgZnJvbSB0aGUgYGxvYWRDb25maWdgIG9wdGlvbiB2YWxpZGF0aW9uIGVycm9yJ1xyXG4gICAgICApO1xyXG4gICAgfVxyXG5cclxuICAgIHRyeSB7XHJcbiAgICAgIC8vIFZhbGlkYXRlIG9wdGlvbnMgZnJvbSB0aGUgQ0xJXHJcbiAgICAgIGNvbnN0IGNsaU9wdGlvbnMgPSBsb29zZVZhbGlkYXRlKFxyXG4gICAgICAgIF9wYWlyQXJndW1lbnRWYWx1ZShuZXN0ZWRQcm9wcywgY2xpQXJncylcclxuICAgICAgKTtcclxuXHJcbiAgICAgIC8vIFVwZGF0ZSBnbG9iYWwgb3B0aW9ucyB3aXRoIHRoZSB2YWx1ZXMgZnJvbSB0aGUgYGNsaU9wdGlvbnNgXHJcbiAgICAgIHVwZGF0ZU9wdGlvbnMoY2xpT3B0aW9ucyk7XHJcbiAgICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgICBsb2dab2RJc3N1ZXMoXHJcbiAgICAgICAgMSxcclxuICAgICAgICBlcnJvci5pc3N1ZXMsXHJcbiAgICAgICAgJ1t2YWxpZGF0aW9uXSBDTEkgb3B0aW9ucyB2YWxpZGF0aW9uIGVycm9yJ1xyXG4gICAgICApO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgLy8gUmV0dXJuIHJlZmVyZW5jZSB0byB0aGUgZ2xvYmFsIG9wdGlvbnNcclxuICByZXR1cm4gZ2V0T3B0aW9ucyhmYWxzZSk7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBNYXBzIG9sZC1zdHJ1Y3R1cmVkIGNvbmZpZ3VyYXRpb24gb3B0aW9ucyAoUGhhbnRvbUpTKSB0byBhIG5ldyBmb3JtYXRcclxuICogKFB1cHBldGVlcikuIFRoaXMgZnVuY3Rpb24gY29udmVydHMgZmxhdCwgb2xkLXN0cnVjdHVyZWQgb3B0aW9ucyBpbnRvXHJcbiAqIGEgbmV3LCBuZXN0ZWQgY29uZmlndXJhdGlvbiBmb3JtYXQgYmFzZWQgb24gYSBwcmVkZWZpbmVkIG1hcHBpbmdcclxuICogKGBuZXN0ZWRQcm9wc2ApLiBUaGUgbmV3IGZvcm1hdCBpcyB1c2VkIGZvciBQdXBwZXRlZXIsIHdoaWxlIHRoZSBvbGQgZm9ybWF0XHJcbiAqIHdhcyB1c2VkIGZvciBQaGFudG9tSlMuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBtYXBUb05ld09wdGlvbnNcclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IG9sZE9wdGlvbnMgLSBUaGUgb2xkLCBmbGF0IGNvbmZpZ3VyYXRpb24gb3B0aW9uc1xyXG4gKiB0byBiZSBjb252ZXJ0ZWQuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtPYmplY3R9IEEgbmV3IG9iamVjdCBjb250YWluaW5nIG9wdGlvbnMgc3RydWN0dXJlZCBhY2NvcmRpbmdcclxuICogdG8gdGhlIG1hcHBpbmcgZGVmaW5lZCBpbiBgbmVzdGVkUHJvcHNgIG9yIGFuIGVtcHR5IG9iamVjdCBpZiB0aGUgcHJvdmlkZWRcclxuICogYG9sZE9wdGlvbnNgIGlzIG5vdCBhIGNvcnJlY3Qgb2JqZWN0LlxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIG1hcFRvTmV3T3B0aW9ucyhvbGRPcHRpb25zKSB7XHJcbiAgLy8gQW4gb2JqZWN0IGZvciB0aGUgbmV3IHN0cnVjdHVyZWQgb3B0aW9uc1xyXG4gIGNvbnN0IG5ld09wdGlvbnMgPSB7fTtcclxuXHJcbiAgLy8gQ2hlY2sgaWYgcHJvdmlkZWQgdmFsdWUgaXMgYSBjb3JyZWN0IG9iamVjdFxyXG4gIGlmIChpc09iamVjdChvbGRPcHRpb25zKSkge1xyXG4gICAgLy8gSXRlcmF0ZSBvdmVyIGVhY2gga2V5LXZhbHVlIHBhaXIgaW4gdGhlIG9sZC1zdHJ1Y3R1cmVkIG9wdGlvbnNcclxuICAgIGZvciAoY29uc3QgW2tleSwgdmFsdWVdIG9mIE9iamVjdC5lbnRyaWVzKG9sZE9wdGlvbnMpKSB7XHJcbiAgICAgIC8vIElmIHRoZXJlIGlzIGEgbmVzdGVkIG1hcHBpbmcsIHNwbGl0IGl0IGludG8gYSBwcm9wZXJ0aWVzIGNoYWluXHJcbiAgICAgIGNvbnN0IHByb3BlcnRpZXNDaGFpbiA9IG5lc3RlZFByb3BzW2tleV1cclxuICAgICAgICA/IG5lc3RlZFByb3BzW2tleV0uc3BsaXQoJy4nKVxyXG4gICAgICAgIDogW107XHJcblxyXG4gICAgICAvLyBJZiBpdCBpcyB0aGUgbGFzdCBwcm9wZXJ0eSBpbiB0aGUgY2hhaW4sIGFzc2lnbiB0aGUgdmFsdWUsIG90aGVyd2lzZSxcclxuICAgICAgLy8gY3JlYXRlIG9yIHJldXNlIHRoZSBuZXN0ZWQgb2JqZWN0XHJcbiAgICAgIHByb3BlcnRpZXNDaGFpbi5yZWR1Y2UoXHJcbiAgICAgICAgKG9iaiwgcHJvcCwgaW5kZXgpID0+XHJcbiAgICAgICAgICAob2JqW3Byb3BdID1cclxuICAgICAgICAgICAgcHJvcGVydGllc0NoYWluLmxlbmd0aCAtIDEgPT09IGluZGV4ID8gdmFsdWUgOiBvYmpbcHJvcF0gfHwge30pLFxyXG4gICAgICAgIG5ld09wdGlvbnNcclxuICAgICAgKTtcclxuICAgIH1cclxuICB9IGVsc2Uge1xyXG4gICAgbG9nKFxyXG4gICAgICAyLFxyXG4gICAgICAnW2NvbmZpZ10gTm8gY29ycmVjdCBvYmplY3Qgd2l0aCBvcHRpb25zIHdhcyBwcm92aWRlZC4gUmV0dXJuaW5nIGFuIGVtcHR5IGFycmF5LidcclxuICAgICk7XHJcbiAgfVxyXG5cclxuICAvLyBSZXR1cm4gdGhlIG5ldywgc3RydWN0dXJlZCBvcHRpb25zIG9iamVjdFxyXG4gIHJldHVybiBuZXdPcHRpb25zO1xyXG59XHJcblxyXG4vKipcclxuICogVmFsaWRhdGVzIGEgc3BlY2lmaWVkIG9wdGlvbiB1c2luZyB0aGUgY29ycmVzcG9uZGluZyB2YWxpZGF0b3IgZnJvbSB0aGVcclxuICogY29uZmlndXJhdGlvbiBvYmplY3QuIFJldHVybnMgdGhlIG9yaWdpbmFsIG9wdGlvbiBpZiB0aGUgdmFsaWRhdGlvblxyXG4gKiBpcyBkaXNhYmxlZCBnbG9iYWxseS5cclxuICpcclxuICogQGZ1bmN0aW9uIHZhbGlkYXRlT3B0aW9uXHJcbiAqXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSBuYW1lIC0gVGhlIG5hbWUgb2YgdGhlIG9wdGlvbiB0byB2YWxpZGF0ZS5cclxuICogQHBhcmFtIHthbnl9IGNvbmZpZ09wdGlvbiAtIFRoZSB2YWx1ZSBvZiB0aGUgb3B0aW9uIHRvIHZhbGlkYXRlLlxyXG4gKiBAcGFyYW0ge2Jvb2xlYW59IFtzdHJpY3RDaGVjaz10cnVlXSAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvblxyXG4gKiBzaG91bGQgYmUgYXBwbGllZC4gVGhlIGRlZmF1bHQgdmFsdWUgaXMgYHRydWVgLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7YW55fSBUaGUgcGFyc2VkIGFuZCB2YWxpZGF0ZWQgdmFsdWUgb2YgdGhlIG9wdGlvbi5cclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiB2YWxpZGF0ZU9wdGlvbihuYW1lLCBjb25maWdPcHRpb24sIHN0cmljdENoZWNrID0gdHJ1ZSkge1xyXG4gIC8vIFJldHVybiB0aGUgb3JpZ2luYWwgb3B0aW9uIGlmIHRoZSB2YWxpZGF0aW9uIGlzIGRpc2FibGVkXHJcbiAgaWYgKCFnZXRPcHRpb25zKCkub3RoZXIudmFsaWRhdGlvbikge1xyXG4gICAgcmV0dXJuIGNvbmZpZ09wdGlvbjtcclxuICB9XHJcblxyXG4gIHRyeSB7XHJcbiAgICAvLyBSZXR1cm4gdmFsaWRhdGVkIG9wdGlvblxyXG4gICAgcmV0dXJuIHZhbGlkYXRvcnNbbmFtZV0oc3RyaWN0Q2hlY2spLnBhcnNlKGNvbmZpZ09wdGlvbik7XHJcbiAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgIC8vIExvZyBab2QgaXNzdWVzXHJcbiAgICBsb2dab2RJc3N1ZXMoXHJcbiAgICAgIDEsXHJcbiAgICAgIGVycm9yLmlzc3VlcyxcclxuICAgICAgYFt2YWxpZGF0aW9uXSBUaGUgJHtuYW1lfSBvcHRpb24gdmFsaWRhdGlvbiBlcnJvcmBcclxuICAgICk7XHJcblxyXG4gICAgLy8gVGhyb3cgdmFsaWRhdGlvbiBlcnJvclxyXG4gICAgdGhyb3cgbmV3IEV4cG9ydEVycm9yKFxyXG4gICAgICBgW3ZhbGlkYXRpb25dIFRoZSAke25hbWV9IG9wdGlvbiB2YWxpZGF0aW9uIGVycm9yYCxcclxuICAgICAgNDAwXHJcbiAgICApO1xyXG4gIH1cclxufVxyXG5cclxuLyoqXHJcbiAqIFZhbGlkYXRlcyB0aGUgcHJvdmlkZWQgY29uZmlndXJhdGlvbiBvcHRpb25zIGZvciB0aGUgZXhwb3J0aW5nIHByb2Nlc3MuXHJcbiAqIFJldHVybnMgdGhlIG9yaWdpbmFsIG9wdGlvbiBpZiB0aGUgdmFsaWRhdGlvbiBpcyBkaXNhYmxlZCBnbG9iYWxseS5cclxuICpcclxuICogQGZ1bmN0aW9uIHZhbGlkYXRlT3B0aW9uc1xyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gY29uZmlnT3B0aW9ucyAtIFRoZSBjb25maWd1cmF0aW9uIG9wdGlvbnMgdG8gYmUgdmFsaWRhdGVkLlxyXG4gKiBAcGFyYW0ge2Jvb2xlYW59IFtzdHJpY3RDaGVjaz10cnVlXSAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvblxyXG4gKiBzaG91bGQgYmUgYXBwbGllZC4gVGhlIGRlZmF1bHQgdmFsdWUgaXMgYHRydWVgLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7T2JqZWN0fSBUaGUgcGFyc2VkIGFuZCB2YWxpZGF0ZWQgY29uZmlndXJhdGlvbiBvcHRpb25zIG9iamVjdC5cclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiB2YWxpZGF0ZU9wdGlvbnMoY29uZmlnT3B0aW9ucywgc3RyaWN0Q2hlY2sgPSB0cnVlKSB7XHJcbiAgLy8gUmV0dXJuIHRoZSBvcmlnaW5hbCBjb25maWcgaWYgdGhlIHZhbGlkYXRpb24gaXMgZGlzYWJsZWRcclxuICBpZiAoIWdldE9wdGlvbnMoKS5vdGhlci52YWxpZGF0aW9uKSB7XHJcbiAgICByZXR1cm4gY29uZmlnT3B0aW9ucztcclxuICB9XHJcblxyXG4gIHRyeSB7XHJcbiAgICAvLyBSZXR1cm4gdmFsaWRhdGVkIG9wdGlvbnNcclxuICAgIHJldHVybiBzdHJpY3RDaGVja1xyXG4gICAgICA/IHN0cmljdFZhbGlkYXRlKGNvbmZpZ09wdGlvbnMpXHJcbiAgICAgIDogbG9vc2VWYWxpZGF0ZShjb25maWdPcHRpb25zKTtcclxuICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgLy8gTG9nIFpvZCBpc3N1ZXNcclxuICAgIGxvZ1pvZElzc3VlcygxLCBlcnJvci5pc3N1ZXMsICdbdmFsaWRhdGlvbl0gT3B0aW9ucyB2YWxpZGF0aW9uIGVycm9yJyk7XHJcblxyXG4gICAgLy8gVGhyb3cgdmFsaWRhdGlvbiBlcnJvclxyXG4gICAgdGhyb3cgbmV3IEV4cG9ydEVycm9yKCdbdmFsaWRhdGlvbl0gT3B0aW9ucyB2YWxpZGF0aW9uIGVycm9yJywgNDAwKTtcclxuICB9XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBWYWxpZGF0ZXMsIHBhcnNlcywgYW5kIGNoZWNrcyBpZiB0aGUgcHJvdmlkZWQgY29uZmlnIGlzIGFsbG93ZWQgc2V0XHJcbiAqIG9mIG9wdGlvbnMuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBpc0FsbG93ZWRDb25maWdcclxuICpcclxuICogQHBhcmFtIHt1bmtub3dufSBjb25maWcgLSBUaGUgY29uZmlnIHRvIGJlIHZhbGlkYXRlZCBhbmQgcGFyc2VkIGFzIGEgc2V0XHJcbiAqIG9mIG9wdGlvbnMuIE11c3QgYmUgZWl0aGVyIGFuIG9iamVjdCBvciBhIHN0cmluZy5cclxuICogQHBhcmFtIHtib29sZWFufSBbdG9TdHJpbmc9ZmFsc2VdIC0gV2hldGhlciB0byByZXR1cm4gYSBzdHJpbmdpZmllZCB2ZXJzaW9uXHJcbiAqIG9mIHRoZSBwYXJzZWQgY29uZmlnLiBUaGUgZGVmYXVsdCB2YWx1ZSBpcyBgZmFsc2VgLlxyXG4gKiBAcGFyYW0ge2Jvb2xlYW59IFthbGxvd0Z1bmN0aW9ucz1mYWxzZV0gLSBXaGV0aGVyIHRvIGFsbG93IGZ1bmN0aW9uc1xyXG4gKiBpbiB0aGUgcGFyc2VkIGNvbmZpZy4gSWYgdHJ1ZSwgZnVuY3Rpb25zIGFyZSBwcmVzZXJ2ZWQuIE90aGVyd2lzZSwgd2hlblxyXG4gKiBhIGZ1bmN0aW9uIGlzIGZvdW5kLCBudWxsIGlzIHJldHVybmVkLiBUaGUgZGVmYXVsdCB2YWx1ZSBpcyBgZmFsc2VgLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7KE9iamVjdHxzdHJpbmd8bnVsbCl9IFJldHVybnMgYSBwYXJzZWQgc2V0IG9mIG9wdGlvbnMgb2JqZWN0LFxyXG4gKiBhIHN0cmluZ2lmaWVkIHNldCBvZiBvcHRpb25zIG9iamVjdCBpZiB0aGUgYHRvU3RyaW5nYCBpcyB0cnVlLCBhbmQgbnVsbFxyXG4gKiBpZiB0aGUgY29uZmlnIGlzIG5vdCBhIHZhbGlkIHNldCBvZiBvcHRpb25zIG9yIHBhcnNpbmcgZmFpbHMuXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gaXNBbGxvd2VkQ29uZmlnKFxyXG4gIGNvbmZpZyxcclxuICB0b1N0cmluZyA9IGZhbHNlLFxyXG4gIGFsbG93RnVuY3Rpb25zID0gZmFsc2VcclxuKSB7XHJcbiAgdHJ5IHtcclxuICAgIC8vIEFjY2VwdCBvbmx5IG9iamVjdHMgYW5kIHN0cmluZ3NcclxuICAgIGlmICghaXNPYmplY3QoY29uZmlnKSAmJiB0eXBlb2YgY29uZmlnICE9PSAnc3RyaW5nJykge1xyXG4gICAgICAvLyBSZXR1cm4gbnVsbCBpZiBhbnkgb3RoZXIgdHlwZVxyXG4gICAgICByZXR1cm4gbnVsbDtcclxuICAgIH1cclxuXHJcbiAgICAvLyBHZXQgdGhlIG9iamVjdCByZXByZXNlbnRhdGlvbiBvZiB0aGUgb3JpZ2luYWwgY29uZmlnXHJcbiAgICBjb25zdCBvYmplY3RDb25maWcgPVxyXG4gICAgICB0eXBlb2YgY29uZmlnID09PSAnc3RyaW5nJ1xyXG4gICAgICAgID8gYWxsb3dGdW5jdGlvbnNcclxuICAgICAgICAgID8gZXZhbChgKCR7Y29uZmlnfSlgKVxyXG4gICAgICAgICAgOiBKU09OLnBhcnNlKGNvbmZpZylcclxuICAgICAgICA6IGNvbmZpZztcclxuXHJcbiAgICAvLyBQcmVzZXJ2ZSBvciByZW1vdmUgcG90ZW50aWFsIGZ1bmN0aW9ucyBiYXNlZCBvbiB0aGUgYGFsbG93RnVuY3Rpb25zYCBmbGFnXHJcbiAgICBjb25zdCBzdHJpbmdpZmllZE9wdGlvbnMgPSBfb3B0aW9uc1N0cmluZ2lmeShcclxuICAgICAgb2JqZWN0Q29uZmlnLFxyXG4gICAgICBhbGxvd0Z1bmN0aW9ucyxcclxuICAgICAgZmFsc2VcclxuICAgICk7XHJcblxyXG4gICAgLy8gUGFyc2UgdGhlIGNvbmZpZyB0byBjaGVjayBpZiBpdCBpcyB2YWxpZCBzZXQgb2Ygb3B0aW9uc1xyXG4gICAgY29uc3QgcGFyc2VkT3B0aW9ucyA9IGFsbG93RnVuY3Rpb25zXHJcbiAgICAgID8gSlNPTi5wYXJzZShcclxuICAgICAgICAgIF9vcHRpb25zU3RyaW5naWZ5KG9iamVjdENvbmZpZywgYWxsb3dGdW5jdGlvbnMsIHRydWUpLFxyXG4gICAgICAgICAgKF8sIHZhbHVlKSA9PlxyXG4gICAgICAgICAgICB0eXBlb2YgdmFsdWUgPT09ICdzdHJpbmcnICYmIHZhbHVlLnN0YXJ0c1dpdGgoJ2Z1bmN0aW9uJylcclxuICAgICAgICAgICAgICA/IGV2YWwoYCgke3ZhbHVlfSlgKVxyXG4gICAgICAgICAgICAgIDogdmFsdWVcclxuICAgICAgICApXHJcbiAgICAgIDogSlNPTi5wYXJzZShzdHJpbmdpZmllZE9wdGlvbnMpO1xyXG5cclxuICAgIC8vIFJldHVybiBzdHJpbmdpZmllZCBvciBvYmplY3Qgb3B0aW9ucyBiYXNlZCBvbiB0aGUgYHRvU3RyaW5nYCBmbGFnXHJcbiAgICByZXR1cm4gdG9TdHJpbmcgPyBzdHJpbmdpZmllZE9wdGlvbnMgOiBwYXJzZWRPcHRpb25zO1xyXG4gIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICAvLyBSZXR1cm4gbnVsbCBpZiBwYXJzaW5nIGZhaWxzXHJcbiAgICByZXR1cm4gbnVsbDtcclxuICB9XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBQcmludHMgdGhlIEhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlciBsb2dvLCB2ZXJzaW9uLCBhbmQgbGljZW5zZSBpbmZvcm1hdGlvbi5cclxuICpcclxuICogQGZ1bmN0aW9uIHByaW50TGljZW5zZVxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIHByaW50TGljZW5zZSgpIHtcclxuICAvLyBQcmludCB0aGUgbG9nbyBhbmQgdmVyc2lvbiBpbmZvcm1hdGlvblxyXG4gIHByaW50VmVyc2lvbigpO1xyXG5cclxuICAvLyBQcmludCB0aGUgbGljZW5zZSBpbmZvcm1hdGlvblxyXG4gIGNvbnNvbGUubG9nKFxyXG4gICAgJ1RoaXMgc29mdHdhcmUgcmVxdWlyZXMgYSB2YWxpZCBIaWdoY2hhcnRzIGxpY2Vuc2UgZm9yIGNvbW1lcmNpYWwgdXNlLlxcbidcclxuICAgICAgLnllbGxvdyxcclxuICAgICdcXG5Gb3IgYSBmdWxsIGxpc3Qgb2YgQ0xJIG9wdGlvbnMsIHR5cGU6JyxcclxuICAgICdcXG5oaWdoY2hhcnRzLWV4cG9ydC1zZXJ2ZXIgLS1oZWxwXFxuJy5ncmVlbixcclxuICAgICdcXG5JZiB5b3UgZG8gbm90IGhhdmUgYSBsaWNlbnNlLCBvbmUgY2FuIGJlIG9idGFpbmVkIGhlcmU6JyxcclxuICAgICdcXG5odHRwczovL3Nob3AuaGlnaHNvZnQuY29tL1xcbicuZ3JlZW4sXHJcbiAgICAnXFxuVG8gY3VzdG9taXplIHlvdXIgaW5zdGFsbGF0aW9uLCBwbGVhc2UgcmVmZXIgdG8gdGhlIFJFQURNRSBmaWxlIGF0OicsXHJcbiAgICAnXFxuaHR0cHM6Ly9naXRodWIuY29tL2hpZ2hjaGFydHMvbm9kZS1leHBvcnQtc2VydmVyI3JlYWRtZVxcbicuZ3JlZW5cclxuICApO1xyXG59XHJcblxyXG4vKipcclxuICogUHJpbnRzIHVzYWdlIGluZm9ybWF0aW9uIGZvciBDTEkgYXJndW1lbnRzLCBkaXNwbGF5aW5nIGF2YWlsYWJsZSBvcHRpb25zXHJcbiAqIGFuZCB0aGVpciBkZXNjcmlwdGlvbnMuIEl0IGNhbiBsaXN0IHByb3BlcnRpZXMgcmVjdXJzaXZlbHkgaWYgY2F0ZWdvcmllc1xyXG4gKiBjb250YWluIG5lc3RlZCBvcHRpb25zLlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gcHJpbnRVc2FnZVxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIHByaW50VXNhZ2UoKSB7XHJcbiAgLy8gRGlzcGxheSBSRUFETUUgYW5kIGdlbmVyYWwgdXNhZ2UgaW5mb3JtYXRpb25cclxuICBjb25zb2xlLmxvZyhcclxuICAgICdcXG5Vc2FnZSBvZiBDTEkgYXJndW1lbnRzOicuYm9sZCxcclxuICAgICdcXG4tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLScsXHJcbiAgICBgXFxuRm9yIG1vcmUgZGV0YWlsZWQgaW5mb3JtYXRpb24sIHZpc2l0IHRoZSBSRUFETUUgZmlsZSBhdDogJHsnaHR0cHM6Ly9naXRodWIuY29tL2hpZ2hjaGFydHMvbm9kZS1leHBvcnQtc2VydmVyI3JlYWRtZScuZ3JlZW59LlxcbmBcclxuICApO1xyXG5cclxuICAvLyBJdGVyYXRlIHRocm91Z2ggZWFjaCBjYXRlZ29yeSBpbiB0aGUgYGRlZmF1bHRDb25maWdgIGFuZCBkaXNwbGF5IHVzYWdlIGluZm9cclxuICBPYmplY3Qua2V5cyhkZWZhdWx0Q29uZmlnKS5mb3JFYWNoKChjYXRlZ29yeSkgPT4ge1xyXG4gICAgY29uc29sZS5sb2coYCR7Y2F0ZWdvcnkudG9VcHBlckNhc2UoKX1gLmJvbGQucmVkKTtcclxuICAgIF9jeWNsZUNhdGVnb3JpZXMoZGVmYXVsdENvbmZpZ1tjYXRlZ29yeV0pO1xyXG4gICAgY29uc29sZS5sb2coJycpO1xyXG4gIH0pO1xyXG59XHJcblxyXG4vKipcclxuICogUHJpbnRzIHRoZSBIaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXIgbG9nbyBvciB0ZXh0IHdpdGggdGhlIHZlcnNpb25cclxuICogaW5mb3JtYXRpb24uXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBwcmludFZlcnNpb25cclxuICpcclxuICogQHBhcmFtIHtib29sZWFufSBbbm9Mb2dvPWZhbHNlXSAtIElmIHRydWUsIG9ubHkgcHJpbnRzIHRleHQgd2l0aCB0aGUgdmVyc2lvblxyXG4gKiBpbmZvcm1hdGlvbiwgd2l0aG91dCB0aGUgbG9nby4gVGhlIGRlZmF1bHQgdmFsdWUgaXMgYGZhbHNlYC5cclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiBwcmludFZlcnNpb24obm9Mb2dvID0gZmFsc2UpIHtcclxuICAvLyBHZXQgcGFja2FnZSB2ZXJzaW9uIGVpdGhlciBmcm9tIGAuZW52YCBvciBmcm9tIGBwYWNrYWdlLmpzb25gXHJcbiAgY29uc3QgcGFja2FnZVZlcnNpb24gPSBKU09OLnBhcnNlKFxyXG4gICAgcmVhZEZpbGVTeW5jKGpvaW4oX19kaXJuYW1lLCAncGFja2FnZS5qc29uJyksICd1dGY4JylcclxuICApLnZlcnNpb247XHJcblxyXG4gIC8vIFByaW50IHRleHQgb25seVxyXG4gIGlmIChub0xvZ28pIHtcclxuICAgIGNvbnNvbGUubG9nKGBIaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXIgdiR7cGFja2FnZVZlcnNpb259YCk7XHJcbiAgfSBlbHNlIHtcclxuICAgIC8vIFByaW50IHRoZSBsb2dvXHJcbiAgICBjb25zb2xlLmxvZyhcclxuICAgICAgcmVhZEZpbGVTeW5jKGpvaW4oX19kaXJuYW1lLCAnbXNnJywgJ3N0YXJ0dXAubXNnJyksICd1dGY4JykudG9TdHJpbmcoKVxyXG4gICAgICAgIC5ib2xkLnllbGxvdyxcclxuICAgICAgYHYke3BhY2thZ2VWZXJzaW9ufVxcbmAuYm9sZFxyXG4gICAgKTtcclxuICB9XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBJbml0aWFsaXplcyBhbmQgcmV0dXJucyB0aGUgZ2xvYmFsIG9wdGlvbnMgb2JqZWN0IGJhc2VkIG9uIHRoZSBwcm92aWRlZFxyXG4gKiBjb25maWd1cmF0aW9uLCBzZXR0aW5nIHZhbHVlcyBmcm9tIG5lc3RlZCBwcm9wZXJ0aWVzIHJlY3Vyc2l2ZWx5LlxyXG4gKlxyXG4gKiBUaGUgcHJpb3JpdHkgb3JkZXIgZm9yIHNldHRpbmcgdmFsdWVzIGlzOlxyXG4gKlxyXG4gKiAxLiBWYWx1ZXMgZnJvbSB0aGUgYC4vbGliL3NjaGVtYXMvY29uZmlnLmpzYCBmaWxlIChkZWZhdWx0cykuXHJcbiAqIDIuIFZhbHVlcyBmcm9tIGVudmlyb25tZW50IHZhcmlhYmxlcyAoc3BlY2lmaWVkIGluIHRoZSBgLmVudmAgZmlsZSkuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBfaW5pdE9wdGlvbnNcclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IGNvbmZpZyAtIFRoZSBjb25maWd1cmF0aW9uIG9iamVjdCB1c2VkIGZvciBpbml0aWFsaXppbmdcclxuICogdGhlIGdsb2JhbCBvcHRpb25zLiBJdCBzaG91bGQgaW5jbHVkZSBuZXN0ZWQgcHJvcGVydGllcyB3aXRoIGEgYHZhbHVlYFxyXG4gKiBhbmQgYW4gYGVudkxpbmtgIGZvciBsaW5raW5nIHRvIGVudmlyb25tZW50IHZhcmlhYmxlcy5cclxuICpcclxuICogQHJldHVybnMge09iamVjdH0gVGhlIGluaXRpYWxpemVkIGdsb2JhbCBvcHRpb25zIG9iamVjdCwgcG9wdWxhdGVkIHdpdGhcclxuICogdmFsdWVzIGJhc2VkIG9uIHRoZSBwcm92aWRlZCBjb25maWd1cmF0aW9uIGFuZCB0aGUgZXN0YWJsaXNoZWQgcHJpb3JpdHlcclxuICogb3JkZXIuXHJcbiAqL1xyXG5mdW5jdGlvbiBfaW5pdE9wdGlvbnMoY29uZmlnKSB7XHJcbiAgLy8gSW5pdCB0aGUgb2JqZWN0IGZvciBvcHRpb25zXHJcbiAgY29uc3Qgb3B0aW9ucyA9IHt9O1xyXG5cclxuICAvLyBTdGFydCBpbml0aWFsaXppbmcgdGhlIGBvcHRpb25zYCBvYmplY3QgcmVjdXJzaXZlbHlcclxuICBmb3IgKGNvbnN0IFtuYW1lLCBpdGVtXSBvZiBPYmplY3QuZW50cmllcyhjb25maWcpKSB7XHJcbiAgICBpZiAoT2JqZWN0LnByb3RvdHlwZS5oYXNPd25Qcm9wZXJ0eS5jYWxsKGl0ZW0sICd2YWx1ZScpKSB7XHJcbiAgICAgIC8vIFNldCB0aGUgY29ycmVjdCB2YWx1ZSBiYXNlZCBvbiB0aGUgZXN0YWJsaXNoZWQgcHJpb3JpdHkgb3JkZXJcclxuICAgICAgaWYgKGVudnNbaXRlbS5lbnZMaW5rXSAhPT0gdW5kZWZpbmVkICYmIGVudnNbaXRlbS5lbnZMaW5rXSAhPT0gbnVsbCkge1xyXG4gICAgICAgIC8vIFRoZSBlbnZpcm9ubWVudCB2YXJpYWJsZXMgdmFsdWVcclxuICAgICAgICBvcHRpb25zW25hbWVdID0gZW52c1tpdGVtLmVudkxpbmtdO1xyXG4gICAgICB9IGVsc2Uge1xyXG4gICAgICAgIC8vIFRoZSB2YWx1ZSBmcm9tIHRoZSBjb25maWcgZmlsZVxyXG4gICAgICAgIG9wdGlvbnNbbmFtZV0gPSBpdGVtLnZhbHVlO1xyXG4gICAgICB9XHJcbiAgICB9IGVsc2Uge1xyXG4gICAgICAvLyBDcmVhdGUgYSBzZWN0aW9uIGluIHRoZSBvcHRpb25zXHJcbiAgICAgIG9wdGlvbnNbbmFtZV0gPSBfaW5pdE9wdGlvbnMoaXRlbSk7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICAvLyBSZXR1cm4gdGhlIGNyZWF0ZWQgYG9wdGlvbnNgIG9iamVjdFxyXG4gIHJldHVybiBvcHRpb25zO1xyXG59XHJcblxyXG4vKipcclxuICogTWVyZ2VzIHR3byBzZXRzIG9mIGNvbmZpZ3VyYXRpb24gb3B0aW9ucywgY29uc2lkZXJpbmcgYWJzb2x1dGUgcHJvcGVydGllcy5cclxuICpcclxuICogQGZ1bmN0aW9uIF9tZXJnZU9wdGlvbnNcclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IG9yaWdpbmFsT3B0aW9ucyAtIE9yaWdpbmFsIGNvbmZpZ3VyYXRpb24gb3B0aW9ucy5cclxuICogQHBhcmFtIHtPYmplY3R9IG5ld09wdGlvbnMgLSBOZXcgY29uZmlndXJhdGlvbiBvcHRpb25zIHRvIGJlIG1lcmdlZC5cclxuICpcclxuICogQHJldHVybnMge09iamVjdH0gTWVyZ2VkIGNvbmZpZ3VyYXRpb24gb3B0aW9ucy5cclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiBfbWVyZ2VPcHRpb25zKG9yaWdpbmFsT3B0aW9ucywgbmV3T3B0aW9ucykge1xyXG4gIC8vIENoZWNrIGlmIHRoZSBgb3JpZ2luYWxPcHRpb25zYCBhbmQgYG5ld09wdGlvbnNgIGFyZSBjb3JyZWN0IG9iamVjdHNcclxuICBpZiAoaXNPYmplY3Qob3JpZ2luYWxPcHRpb25zKSAmJiBpc09iamVjdChuZXdPcHRpb25zKSkge1xyXG4gICAgZm9yIChjb25zdCBba2V5LCB2YWx1ZV0gb2YgT2JqZWN0LmVudHJpZXMobmV3T3B0aW9ucykpIHtcclxuICAgICAgb3JpZ2luYWxPcHRpb25zW2tleV0gPVxyXG4gICAgICAgIGlzT2JqZWN0KHZhbHVlKSAmJlxyXG4gICAgICAgICFhYnNvbHV0ZVByb3BzLmluY2x1ZGVzKGtleSkgJiZcclxuICAgICAgICBvcmlnaW5hbE9wdGlvbnNba2V5XSAhPT0gdW5kZWZpbmVkXHJcbiAgICAgICAgICA/IF9tZXJnZU9wdGlvbnMob3JpZ2luYWxPcHRpb25zW2tleV0sIHZhbHVlKVxyXG4gICAgICAgICAgOiB2YWx1ZSAhPT0gdW5kZWZpbmVkXHJcbiAgICAgICAgICAgID8gdmFsdWVcclxuICAgICAgICAgICAgOiBvcmlnaW5hbE9wdGlvbnNba2V5XSB8fCBudWxsO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgLy8gUmV0dXJuIHRoZSBvcmlnaW5hbCAobW9kaWZpZWQgb3Igbm90KSBvcHRpb25zXHJcbiAgcmV0dXJuIG9yaWdpbmFsT3B0aW9ucztcclxufVxyXG5cclxuLyoqXHJcbiAqIENvbnZlcnRzIHRoZSBwcm92aWRlZCBvcHRpb25zIG9iamVjdCB0byBhIEpTT04tZm9ybWF0dGVkIHN0cmluZ1xyXG4gKiB3aXRoIHRoZSBvcHRpb24gdG8gcHJlc2VydmUgZnVuY3Rpb25zLiBJbiBvcmRlciBmb3IgYSBmdW5jdGlvblxyXG4gKiB0byBiZSBwcmVzZXJ2ZWQsIGl0IG5lZWRzIHRvIGZvbGxvdyB0aGUgZm9ybWF0IGBmdW5jdGlvbiAoLi4uKSB7Li4ufWAuXHJcbiAqIFN1Y2ggYSBmdW5jdGlvbiBjYW4gYWxzbyBiZSBzdHJpbmdpZmllZC5cclxuICpcclxuICogQGZ1bmN0aW9uIF9vcHRpb25zU3RyaW5naWZ5XHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBvcHRpb25zIC0gVGhlIG9wdGlvbnMgb2JqZWN0IHRvIGJlIGNvbnZlcnRlZCB0byBhIHN0cmluZy5cclxuICogQHBhcmFtIHtib29sZWFufSBhbGxvd0Z1bmN0aW9ucyAtIElmIHNldCB0byB0cnVlLCBmdW5jdGlvbnMgYXJlIHByZXNlcnZlZFxyXG4gKiBpbiB0aGUgb3V0cHV0LiBPdGhlcndpc2UgYW4gZXJyb3IgaXMgdGhyb3duLlxyXG4gKiBAcGFyYW0ge2Jvb2xlYW59IHN0cmluZ2lmeUZ1bmN0aW9ucyAtIElmIHNldCB0byB0cnVlLCBmdW5jdGlvbnMgYXJlIHNhdmVkXHJcbiAqIGFzIHN0cmluZ3MuIFRoZSBgYWxsb3dGdW5jdGlvbnNgIG11c3QgYmUgc2V0IHRvIHRydWUgYXMgd2VsbCBmb3IgdGhpcyB0byB0YWtlXHJcbiAqIGFuIGVmZmVjdC5cclxuICpcclxuICogQHJldHVybnMge3N0cmluZ30gVGhlIEpTT04tZm9ybWF0dGVkIHN0cmluZyByZXByZXNlbnRpbmcgdGhlIG9wdGlvbnMuXHJcbiAqXHJcbiAqIEB0aHJvd3Mge0Vycm9yfSBUaHJvd3MgYW4gYEVycm9yYCB3aGVuIGZ1bmN0aW9ucyBhcmUgbm90IGFsbG93ZWQgYnV0IGFyZVxyXG4gKiBmb3VuZCBpbiBwcm92aWRlZCBvcHRpb25zIG9iamVjdC5cclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiBfb3B0aW9uc1N0cmluZ2lmeShvcHRpb25zLCBhbGxvd0Z1bmN0aW9ucywgc3RyaW5naWZ5RnVuY3Rpb25zKSB7XHJcbiAgY29uc3QgcmVwbGFjZXJDYWxsYmFjayA9IChfLCB2YWx1ZSkgPT4ge1xyXG4gICAgLy8gVHJpbSBzdHJpbmcgdmFsdWVzXHJcbiAgICBpZiAodHlwZW9mIHZhbHVlID09PSAnc3RyaW5nJykge1xyXG4gICAgICB2YWx1ZSA9IHZhbHVlLnRyaW0oKTtcclxuICAgIH1cclxuXHJcbiAgICAvLyBJZiB2YWx1ZSBpcyBhIGZ1bmN0aW9uIG9yIHN0cmluZ2lmaWVkIGZ1bmN0aW9uXHJcbiAgICBpZiAoXHJcbiAgICAgIHR5cGVvZiB2YWx1ZSA9PT0gJ2Z1bmN0aW9uJyB8fFxyXG4gICAgICAodHlwZW9mIHZhbHVlID09PSAnc3RyaW5nJyAmJlxyXG4gICAgICAgIHZhbHVlLnN0YXJ0c1dpdGgoJ2Z1bmN0aW9uJykgJiZcclxuICAgICAgICB2YWx1ZS5lbmRzV2l0aCgnfScpKVxyXG4gICAgKSB7XHJcbiAgICAgIC8vIElmIGFsbG93RnVuY3Rpb25zIGlzIHNldCB0byB0cnVlLCBwcmVzZXJ2ZSBmdW5jdGlvbnNcclxuICAgICAgaWYgKGFsbG93RnVuY3Rpb25zKSB7XHJcbiAgICAgICAgLy8gQmFzZWQgb24gdGhlIGBzdHJpbmdpZnlGdW5jdGlvbnNgIG9wdGlvbnMsIHNldCBmdW5jdGlvbiB2YWx1ZXNcclxuICAgICAgICByZXR1cm4gc3RyaW5naWZ5RnVuY3Rpb25zXHJcbiAgICAgICAgICA/IC8vIEFzIHN0cmluZ2lmaWVkIGZ1bmN0aW9uc1xyXG4gICAgICAgICAgICBgXCJFWFBfRlVOJHsodmFsdWUgKyAnJykucmVwbGFjZUFsbCgvXFxzKy9nLCAnICcpfUVYUF9GVU5cImBcclxuICAgICAgICAgIDogLy8gQXMgZnVuY3Rpb25zXHJcbiAgICAgICAgICAgIGBFWFBfRlVOJHsodmFsdWUgKyAnJykucmVwbGFjZUFsbCgvXFxzKy9nLCAnICcpfUVYUF9GVU5gO1xyXG4gICAgICB9IGVsc2Uge1xyXG4gICAgICAgIC8vIFRocm93IGFuIGVycm9yIG90aGVyd2lzZVxyXG4gICAgICAgIHRocm93IG5ldyBFcnJvcigpO1xyXG4gICAgICB9XHJcbiAgICB9XHJcblxyXG4gICAgLy8gSW4gYWxsIG90aGVyIGNhc2VzLCBzaW1wbHkgcmV0dXJuIHRoZSB2YWx1ZVxyXG4gICAgcmV0dXJuIHZhbHVlO1xyXG4gIH07XHJcblxyXG4gIC8vIFN0cmluZ2lmeSBvcHRpb25zIGFuZCBpZiByZXF1aXJlZCwgcmVwbGFjZSBzcGVjaWFsIGZ1bmN0aW9ucyBtYXJrc1xyXG4gIHJldHVybiBKU09OLnN0cmluZ2lmeShvcHRpb25zLCByZXBsYWNlckNhbGxiYWNrKS5yZXBsYWNlQWxsKFxyXG4gICAgc3RyaW5naWZ5RnVuY3Rpb25zID8gL1xcXFxcIkVYUF9GVU58RVhQX0ZVTlxcXFxcIi9nIDogL1wiRVhQX0ZVTnxFWFBfRlVOXCIvZyxcclxuICAgICcnXHJcbiAgKTtcclxufVxyXG5cclxuLyoqXHJcbiAqIExvYWRzIGFkZGl0aW9uYWwgY29uZmlndXJhdGlvbiBmcm9tIGEgc3BlY2lmaWVkIGZpbGUgcHJvdmlkZWQgdmlhXHJcbiAqIHRoZSBgLS1sb2FkQ29uZmlnYCBvcHRpb24gaW4gdGhlIGNvbW1hbmQtbGluZSBhcmd1bWVudHMuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBfbG9hZENvbmZpZ0ZpbGVcclxuICpcclxuICogQHBhcmFtIHtBcnJheS48c3RyaW5nPn0gY2xpQXJncyAtIENvbW1hbmQtbGluZSBhcmd1bWVudHMgdG8gc2VhcmNoXHJcbiAqIGZvciB0aGUgYC0tbG9hZENvbmZpZ2Agb3B0aW9uIGFuZCB0aGUgY29ycmVzcG9uZGluZyBmaWxlIHBhdGguXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtPYmplY3R9IFRoZSBhZGRpdGlvbmFsIGNvbmZpZ3VyYXRpb24gbG9hZGVkIGZyb20gdGhlIHNwZWNpZmllZFxyXG4gKiBmaWxlLCBvciBhbiBlbXB0eSBvYmplY3QgaWYgdGhlIGZpbGUgaXMgbm90IGZvdW5kLCBpbnZhbGlkLCBvciBhbiBlcnJvclxyXG4gKiBvY2N1cnMuXHJcbiAqL1xyXG5mdW5jdGlvbiBfbG9hZENvbmZpZ0ZpbGUoY2xpQXJncykge1xyXG4gIC8vIEdldCB0aGUgYWxsb3cgZmxhZ3MgZm9yIHRoZSBjdXN0b20gbG9naWMgY2hlY2tcclxuICBjb25zdCB7IGFsbG93Q29kZUV4ZWN1dGlvbiwgYWxsb3dGaWxlUmVzb3VyY2VzIH0gPSBnZXRPcHRpb25zKCkuY3VzdG9tTG9naWM7XHJcblxyXG4gIC8vIENoZWNrIGlmIHRoZSBgLS1sb2FkQ29uZmlnYCBvcHRpb24gd2FzIHVzZWRcclxuICBjb25zdCBjb25maWdJbmRleCA9IGNsaUFyZ3MuZmluZEluZGV4KFxyXG4gICAgKGFyZykgPT4gYXJnLnJlcGxhY2UoLy0vZywgJycpID09PSAnbG9hZENvbmZpZydcclxuICApO1xyXG5cclxuICAvLyBHZXQgdGhlIGAtLWxvYWRDb25maWdgIG9wdGlvbiB2YWx1ZVxyXG4gIGNvbnN0IGNvbmZpZ0ZpbGVOYW1lID0gY29uZmlnSW5kZXggPiAtMSAmJiBjbGlBcmdzW2NvbmZpZ0luZGV4ICsgMV07XHJcblxyXG4gIC8vIENoZWNrIGlmIHRoZSBgLS1sb2FkQ29uZmlnYCBpcyBwcmVzZW50IGFuZCBoYXMgYSBjb3JyZWN0IHZhbHVlXHJcbiAgaWYgKGNvbmZpZ0ZpbGVOYW1lICYmIGFsbG93RmlsZVJlc291cmNlcykge1xyXG4gICAgdHJ5IHtcclxuICAgICAgLy8gTG9hZCBhbiBvcHRpb25hbCBjdXN0b20gSlNPTiBjb25maWcgZmlsZVxyXG4gICAgICByZXR1cm4gaXNBbGxvd2VkQ29uZmlnKFxyXG4gICAgICAgIHJlYWRGaWxlU3luYyhnZXRBYnNvbHV0ZVBhdGgoY29uZmlnRmlsZU5hbWUpLCAndXRmOCcpLFxyXG4gICAgICAgIGZhbHNlLFxyXG4gICAgICAgIGFsbG93Q29kZUV4ZWN1dGlvblxyXG4gICAgICApO1xyXG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICAgbG9nV2l0aFN0YWNrKFxyXG4gICAgICAgIDIsXHJcbiAgICAgICAgZXJyb3IsXHJcbiAgICAgICAgYFtjb25maWddIFVuYWJsZSB0byBsb2FkIHRoZSBjb25maWd1cmF0aW9uIGZyb20gdGhlICR7Y29uZmlnRmlsZU5hbWV9IGZpbGUuYFxyXG4gICAgICApO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgLy8gTm8gYWRkaXRpb25hbCBvcHRpb25zIHRvIHJldHVyblxyXG4gIHJldHVybiB7fTtcclxufVxyXG5cclxuLyoqXHJcbiAqIFBhcnNlcyBjb21tYW5kLWxpbmUgYXJndW1lbnRzIGFuZCBwYWlycyBlYWNoIGFyZ3VtZW50IHdpdGggaXRzIGNvcnJlc3BvbmRpbmdcclxuICogb3B0aW9uIGluIHRoZSBjb25maWd1cmF0aW9uLiBUaGUgdmFsdWVzIGFyZSBzdHJ1Y3R1cmVkIGludG8gYSBuZXN0ZWQgb3B0aW9uc1xyXG4gKiBvYmplY3QsIGJhc2VkIG9uIHByZWRlZmluZWQgbWFwcGluZ3MuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBfcGFpckFyZ3VtZW50VmFsdWVcclxuICpcclxuICogQHBhcmFtIHtBcnJheS48c3RyaW5nPn0gbmVzdGVkUHJvcHMgLSBBbiBhcnJheSBvZiBuZXN0aW5nIGxldmVsIGZvciBhbGxcclxuICogb3B0aW9ucy5cclxuICogQHBhcmFtIHtBcnJheS48c3RyaW5nPn0gY2xpQXJncyAtIEFuIGFycmF5IG9mIGNvbW1hbmQtbGluZSBhcmd1bWVudHNcclxuICogY29udGFpbmluZyBvcHRpb25zIGFuZCB0aGVpciBhc3NvY2lhdGVkIHZhbHVlcy5cclxuICpcclxuICogQHJldHVybnMge09iamVjdH0gQW4gdXBkYXRlZCBvcHRpb25zIG9iamVjdCB3aGVyZSBlYWNoIG9wdGlvbiBmcm9tXHJcbiAqIHRoZSBjb21tYW5kLWxpbmUgaXMgcGFpcmVkIHdpdGggaXRzIHZhbHVlLCBzdHJ1Y3R1cmVkIGludG8gbmVzdGVkIG9iamVjdHNcclxuICogYXMgZGVmaW5lZC5cclxuICovXHJcbmZ1bmN0aW9uIF9wYWlyQXJndW1lbnRWYWx1ZShuZXN0ZWRQcm9wcywgY2xpQXJncykge1xyXG4gIC8vIEFuIGVtcHR5IG9iamVjdCB0byBjb2xsZWN0IGFuZCBzdHJ1Y3R1cml6ZSBkYXRhIGZyb20gdGhlIGFyZ3NcclxuICBjb25zdCBjbGlPcHRpb25zID0ge307XHJcblxyXG4gIC8vIEN5Y2xlIHRocm91Z2ggYWxsIENMSSBhcmdzIGFuZCBmaWx0ZXIgdGhlbVxyXG4gIGZvciAobGV0IGkgPSAwOyBpIDwgY2xpQXJncy5sZW5ndGg7IGkrKykge1xyXG4gICAgY29uc3Qgb3B0aW9uID0gY2xpQXJnc1tpXS5yZXBsYWNlKC8tL2csICcnKTtcclxuXHJcbiAgICAvLyBGaW5kIHRoZSByaWdodCBwbGFjZSBmb3IgcHJvcGVydHkncyB2YWx1ZVxyXG4gICAgY29uc3QgcHJvcGVydGllc0NoYWluID0gbmVzdGVkUHJvcHNbb3B0aW9uXVxyXG4gICAgICA/IG5lc3RlZFByb3BzW29wdGlvbl0uc3BsaXQoJy4nKVxyXG4gICAgICA6IFtdO1xyXG5cclxuICAgIC8vIENyZWF0ZSBvcHRpb25zIG9iamVjdCB3aXRoIHZhbHVlcyBmcm9tIENMSSBmb3IgbGF0ZXIgcGFyc2luZyBhbmQgbWVyZ2luZ1xyXG4gICAgcHJvcGVydGllc0NoYWluLnJlZHVjZSgob2JqLCBwcm9wLCBpbmRleCkgPT4ge1xyXG4gICAgICBpZiAocHJvcGVydGllc0NoYWluLmxlbmd0aCAtIDEgPT09IGluZGV4KSB7XHJcbiAgICAgICAgY29uc3QgdmFsdWUgPSBjbGlBcmdzWysraV07XHJcbiAgICAgICAgaWYgKCF2YWx1ZSkge1xyXG4gICAgICAgICAgbG9nKFxyXG4gICAgICAgICAgICAyLFxyXG4gICAgICAgICAgICBgW2NvbmZpZ10gTWlzc2luZyB2YWx1ZSBmb3IgdGhlIENMSSAnLS0ke29wdGlvbn0nIGFyZ3VtZW50LiBVc2luZyB0aGUgZGVmYXVsdCB2YWx1ZS5gXHJcbiAgICAgICAgICApO1xyXG4gICAgICAgIH1cclxuICAgICAgICBvYmpbcHJvcF0gPSB2YWx1ZSB8fCBudWxsO1xyXG4gICAgICB9IGVsc2UgaWYgKG9ialtwcm9wXSA9PT0gdW5kZWZpbmVkKSB7XHJcbiAgICAgICAgb2JqW3Byb3BdID0ge307XHJcbiAgICAgIH1cclxuICAgICAgcmV0dXJuIG9ialtwcm9wXTtcclxuICAgIH0sIGNsaU9wdGlvbnMpO1xyXG4gIH1cclxuXHJcbiAgLy8gUmV0dXJuIHBhcnNlZCBDTEkgb3B0aW9uc1xyXG4gIHJldHVybiBjbGlPcHRpb25zO1xyXG59XHJcblxyXG4vKipcclxuICogUmVjdXJzaXZlbHkgdHJhdmVyc2VzIHRoZSBvcHRpb25zIG9iamVjdCB0byBwcmludCB0aGUgdXNhZ2UgaW5mb3JtYXRpb25cclxuICogZm9yIGVhY2ggb3B0aW9uIGNhdGVnb3J5IGFuZCBpbmRpdmlkdWFsIG9wdGlvbi5cclxuICpcclxuICogQGZ1bmN0aW9uIF9jeWNsZUNhdGVnb3JpZXNcclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IG9wdGlvbnMgLSBUaGUgb3B0aW9ucyBvYmplY3QgY29udGFpbmluZyBDTEkgb3B0aW9ucy4gSXQgbWF5XHJcbiAqIGluY2x1ZGUgbmVzdGVkIGNhdGVnb3JpZXMgYW5kIGluZGl2aWR1YWwgb3B0aW9ucy5cclxuICovXHJcbmZ1bmN0aW9uIF9jeWNsZUNhdGVnb3JpZXMob3B0aW9ucykge1xyXG4gIGZvciAoY29uc3QgW25hbWUsIG9wdGlvbl0gb2YgT2JqZWN0LmVudHJpZXMob3B0aW9ucykpIHtcclxuICAgIC8vIElmIHRoZSBjdXJyZW50IGVudHJ5IGlzIGEgY2F0ZWdvcnkgYW5kIG5vdCBhIGxlYWYgb3B0aW9uLCByZWN1cnNlIGludG8gaXRcclxuICAgIGlmICghT2JqZWN0LnByb3RvdHlwZS5oYXNPd25Qcm9wZXJ0eS5jYWxsKG9wdGlvbiwgJ3ZhbHVlJykpIHtcclxuICAgICAgX2N5Y2xlQ2F0ZWdvcmllcyhvcHRpb24pO1xyXG4gICAgfSBlbHNlIHtcclxuICAgICAgLy8gUHJlcGFyZSBkZXNjcmlwdGlvblxyXG4gICAgICBjb25zdCBkZXNjTmFtZSA9IGAgLS0ke29wdGlvbi5jbGlOYW1lIHx8IG5hbWV9YDtcclxuXHJcbiAgICAgIC8vIEdldCB0aGUgdmFsdWVcclxuICAgICAgbGV0IG9wdGlvblZhbHVlID0gb3B0aW9uLnZhbHVlO1xyXG5cclxuICAgICAgLy8gUHJlcGFyZSB2YWx1ZSBmb3Igb3B0aW9uIHRoYXQgaXMgbm90IG51bGwgYW5kIGlzIGFycmF5IG9mIHN0cmluZ3NcclxuICAgICAgaWYgKG9wdGlvblZhbHVlICE9PSBudWxsICYmIG9wdGlvbi50eXBlcy5pbmNsdWRlcygnc3RyaW5nW10nKSkge1xyXG4gICAgICAgIG9wdGlvblZhbHVlID1cclxuICAgICAgICAgICdbJyArIG9wdGlvblZhbHVlLm1hcCgoaXRlbSkgPT4gYCcke2l0ZW19J2ApLmpvaW4oJywgJykgKyAnXSc7XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIC8vIFByZXBhcmUgdmFsdWUgZm9yIG9wdGlvbiB0aGF0IGlzIG5vdCBudWxsIGFuZCBpcyBhIHN0cmluZ1xyXG4gICAgICBpZiAob3B0aW9uVmFsdWUgIT09IG51bGwgJiYgb3B0aW9uLnR5cGVzLmluY2x1ZGVzKCdzdHJpbmcnKSkge1xyXG4gICAgICAgIG9wdGlvblZhbHVlID0gYCcke29wdGlvblZhbHVlfSdgO1xyXG4gICAgICB9XHJcblxyXG4gICAgICAvLyBEaXNwbGF5IGNvcnJlY3RseSBhbGlnbmVkIG1lc3NhZ2VzXHJcbiAgICAgIGNvbnNvbGUubG9nKFxyXG4gICAgICAgIGRlc2NOYW1lLmdyZWVuLFxyXG4gICAgICAgIGAkeygnPCcgKyBvcHRpb24udHlwZXMuam9pbignfCcpICsgJz4nKS55ZWxsb3d9YCxcclxuICAgICAgICBgJHtTdHJpbmcob3B0aW9uVmFsdWUpLmJvbGR9YC5ibHVlLFxyXG4gICAgICAgIGAtICR7b3B0aW9uLmRlc2NyaXB0aW9ufS5gXHJcbiAgICAgICk7XHJcbiAgICB9XHJcbiAgfVxyXG59XHJcblxyXG5leHBvcnQgZGVmYXVsdCB7XHJcbiAgZ2V0T3B0aW9ucyxcclxuICB1cGRhdGVPcHRpb25zLFxyXG4gIHNldENsaU9wdGlvbnMsXHJcbiAgbWFwVG9OZXdPcHRpb25zLFxyXG4gIHZhbGlkYXRlT3B0aW9uLFxyXG4gIHZhbGlkYXRlT3B0aW9ucyxcclxuICBpc0FsbG93ZWRDb25maWcsXHJcbiAgcHJpbnRMaWNlbnNlLFxyXG4gIHByaW50VXNhZ2UsXHJcbiAgcHJpbnRWZXJzaW9uXHJcbn07XHJcbiIsIi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXHJcblxyXG5IaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXJcclxuXHJcbkNvcHlyaWdodCAoYykgMjAxNi0yMDI1LCBIaWdoc29mdFxyXG5cclxuTGljZW5jZWQgdW5kZXIgdGhlIE1JVCBsaWNlbmNlLlxyXG5cclxuQWRkaXRpb25hbGx5IGEgdmFsaWQgSGlnaGNoYXJ0cyBsaWNlbnNlIGlzIHJlcXVpcmVkIGZvciB1c2UuXHJcblxyXG5TZWUgTElDRU5TRSBmaWxlIGluIHJvb3QgZm9yIGRldGFpbHMuXHJcblxyXG4qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xyXG5cclxuLyoqXHJcbiAqIEBvdmVydmlldyBIVFRQIHV0aWxpdHkgbW9kdWxlIGZvciBmZXRjaGluZyBhbmQgcG9zdGluZyBkYXRhLiBTdXBwb3J0cyBib3RoXHJcbiAqIEhUVFAgYW5kIEhUVFBTIHByb3RvY29scywgcHJvdmlkaW5nIG1ldGhvZHMgdG8gbWFrZSBHRVQgYW5kIFBPU1QgcmVxdWVzdHNcclxuICogd2l0aCBjdXN0b21pemFibGUgb3B0aW9ucy4gSW5jbHVkZXMgcHJvdG9jb2wgZGV0ZXJtaW5hdGlvbiBiYXNlZCBvbiBVUkxcclxuICogYW5kIGF1Z21lbnRzIHJlc3BvbnNlIG9iamVjdHMgd2l0aCBhICd0ZXh0JyBwcm9wZXJ0eSBmb3IgZWFzaWVyIGRhdGEgYWNjZXNzLlxyXG4gKi9cclxuXHJcbmltcG9ydCBodHRwIGZyb20gJ2h0dHAnO1xyXG5pbXBvcnQgaHR0cHMgZnJvbSAnaHR0cHMnO1xyXG5cclxuLyoqXHJcbiAqIEZldGNoZXMgZGF0YSBmcm9tIHRoZSBzcGVjaWZpZWQgVVJMIHVzaW5nIGVpdGhlciBIVFRQIG9yIEhUVFBTIHByb3RvY29sLlxyXG4gKlxyXG4gKiBAYXN5bmNcclxuICogQGZ1bmN0aW9uIGZldGNoXHJcbiAqXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSB1cmwgLSBUaGUgVVJMIHRvIGZldGNoIGRhdGEgZnJvbS5cclxuICogQHBhcmFtIHtPYmplY3R9IFtyZXF1ZXN0T3B0aW9ucz17fV0gLSBPcHRpb25zIGZvciB0aGUgSFRUUC9IVFRQUyByZXF1ZXN0LlxyXG4gKiBUaGUgZGVmYXVsdCB2YWx1ZSBpcyBhbiBlbXB0eSBvYmplY3QuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtQcm9taXNlPE9iamVjdD59IEEgUHJvbWlzZSB0aGF0IHJlc29sdmVzIHRvIHRoZSBIVFRQL0hUVFBTIHJlc3BvbnNlXHJcbiAqIG9iamVjdCB3aXRoIGFkZGVkICd0ZXh0JyBwcm9wZXJ0eSBvciByZWplY3Rpbmcgd2l0aCBhbiBlcnJvci5cclxuICovXHJcbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBmZXRjaCh1cmwsIHJlcXVlc3RPcHRpb25zID0ge30pIHtcclxuICByZXR1cm4gbmV3IFByb21pc2UoKHJlc29sdmUsIHJlamVjdCkgPT4ge1xyXG4gICAgX2dldFByb3RvY29sTW9kdWxlKHVybClcclxuICAgICAgLmdldCh1cmwsIHJlcXVlc3RPcHRpb25zLCAocmVzcG9uc2UpID0+IHtcclxuICAgICAgICBsZXQgcmVzcG9uc2VEYXRhID0gJyc7XHJcblxyXG4gICAgICAgIC8vIEEgY2h1bmsgb2YgZGF0YSBoYXMgYmVlbiByZWNlaXZlZFxyXG4gICAgICAgIHJlc3BvbnNlLm9uKCdkYXRhJywgKGNodW5rKSA9PiB7XHJcbiAgICAgICAgICByZXNwb25zZURhdGEgKz0gY2h1bms7XHJcbiAgICAgICAgfSk7XHJcblxyXG4gICAgICAgIC8vIFRoZSB3aG9sZSByZXNwb25zZSBoYXMgYmVlbiByZWNlaXZlZFxyXG4gICAgICAgIHJlc3BvbnNlLm9uKCdlbmQnLCAoKSA9PiB7XHJcbiAgICAgICAgICBpZiAoIXJlc3BvbnNlRGF0YSkge1xyXG4gICAgICAgICAgICByZWplY3QoJ05vdGhpbmcgd2FzIGZldGNoZWQgZnJvbSB0aGUgVVJMLicpO1xyXG4gICAgICAgICAgfVxyXG4gICAgICAgICAgcmVzcG9uc2UudGV4dCA9IHJlc3BvbnNlRGF0YTtcclxuICAgICAgICAgIHJlc29sdmUocmVzcG9uc2UpO1xyXG4gICAgICAgIH0pO1xyXG4gICAgICB9KVxyXG4gICAgICAub24oJ2Vycm9yJywgKGVycm9yKSA9PiB7XHJcbiAgICAgICAgcmVqZWN0KGVycm9yKTtcclxuICAgICAgfSk7XHJcbiAgfSk7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBTZW5kcyBhIFBPU1QgcmVxdWVzdCB0byB0aGUgc3BlY2lmaWVkIFVSTCB3aXRoIHRoZSBwcm92aWRlZCBKU09OIGJvZHkgdXNpbmdcclxuICogZWl0aGVyIEhUVFAgb3IgSFRUUFMgcHJvdG9jb2wuXHJcbiAqXHJcbiAqIEBhc3luY1xyXG4gKiBAZnVuY3Rpb24gcG9zdFxyXG4gKlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gdXJsIC0gVGhlIFVSTCB0byBzZW5kIHRoZSBQT1NUIHJlcXVlc3QgdG8uXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBbYm9keT17fV0gLSBUaGUgSlNPTiBib2R5IHRvIGluY2x1ZGUgaW4gdGhlIFBPU1QgcmVxdWVzdC5cclxuICogVGhlIGRlZmF1bHQgdmFsdWUgaXMgYW4gZW1wdHkgb2JqZWN0LlxyXG4gKiBAcGFyYW0ge09iamVjdH0gW3JlcXVlc3RPcHRpb25zPXt9XSAtIE9wdGlvbnMgZm9yIHRoZSBIVFRQL0hUVFBTIHJlcXVlc3QuXHJcbiAqIFRoZSBkZWZhdWx0IHZhbHVlIGlzIGFuIGVtcHR5IG9iamVjdC5cclxuICpcclxuICogQHJldHVybnMge1Byb21pc2U8T2JqZWN0Pn0gQSBQcm9taXNlIHRoYXQgcmVzb2x2ZXMgdG8gdGhlIEhUVFAvSFRUUFMgcmVzcG9uc2VcclxuICogb2JqZWN0IHdpdGggYWRkZWQgJ3RleHQnIHByb3BlcnR5IG9yIHJlamVjdGluZyB3aXRoIGFuIGVycm9yLlxyXG4gKi9cclxuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIHBvc3QodXJsLCBib2R5ID0ge30sIHJlcXVlc3RPcHRpb25zID0ge30pIHtcclxuICByZXR1cm4gbmV3IFByb21pc2UoKHJlc29sdmUsIHJlamVjdCkgPT4ge1xyXG4gICAgY29uc3QgZGF0YSA9IEpTT04uc3RyaW5naWZ5KGJvZHkpO1xyXG5cclxuICAgIC8vIFNldCBkZWZhdWx0IGhlYWRlcnMgYW5kIG1lcmdlIHdpdGggcmVxdWVzdE9wdGlvbnNcclxuICAgIGNvbnN0IG9wdGlvbnMgPSBPYmplY3QuYXNzaWduKFxyXG4gICAgICB7XHJcbiAgICAgICAgbWV0aG9kOiAnUE9TVCcsXHJcbiAgICAgICAgaGVhZGVyczoge1xyXG4gICAgICAgICAgJ0NvbnRlbnQtVHlwZSc6ICdhcHBsaWNhdGlvbi9qc29uJyxcclxuICAgICAgICAgICdDb250ZW50LUxlbmd0aCc6IGRhdGEubGVuZ3RoXHJcbiAgICAgICAgfVxyXG4gICAgICB9LFxyXG4gICAgICByZXF1ZXN0T3B0aW9uc1xyXG4gICAgKTtcclxuXHJcbiAgICBjb25zdCByZXF1ZXN0ID0gX2dldFByb3RvY29sTW9kdWxlKHVybClcclxuICAgICAgLnJlcXVlc3QodXJsLCBvcHRpb25zLCAocmVzcG9uc2UpID0+IHtcclxuICAgICAgICBsZXQgcmVzcG9uc2VEYXRhID0gJyc7XHJcblxyXG4gICAgICAgIC8vIEEgY2h1bmsgb2YgZGF0YSBoYXMgYmVlbiByZWNlaXZlZFxyXG4gICAgICAgIHJlc3BvbnNlLm9uKCdkYXRhJywgKGNodW5rKSA9PiB7XHJcbiAgICAgICAgICByZXNwb25zZURhdGEgKz0gY2h1bms7XHJcbiAgICAgICAgfSk7XHJcblxyXG4gICAgICAgIC8vIFRoZSB3aG9sZSByZXNwb25zZSBoYXMgYmVlbiByZWNlaXZlZFxyXG4gICAgICAgIHJlc3BvbnNlLm9uKCdlbmQnLCAoKSA9PiB7XHJcbiAgICAgICAgICB0cnkge1xyXG4gICAgICAgICAgICByZXNwb25zZS50ZXh0ID0gcmVzcG9uc2VEYXRhO1xyXG4gICAgICAgICAgICByZXNvbHZlKHJlc3BvbnNlKTtcclxuICAgICAgICAgIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICAgICAgICAgIHJlamVjdChlcnJvcik7XHJcbiAgICAgICAgICB9XHJcbiAgICAgICAgfSk7XHJcbiAgICAgIH0pXHJcbiAgICAgIC5vbignZXJyb3InLCAoZXJyb3IpID0+IHtcclxuICAgICAgICByZWplY3QoZXJyb3IpO1xyXG4gICAgICB9KTtcclxuXHJcbiAgICAvLyBXcml0ZSB0aGUgcmVxdWVzdCBib2R5IGFuZCBlbmQgdGhlIHJlcXVlc3RcclxuICAgIHJlcXVlc3Qud3JpdGUoZGF0YSk7XHJcbiAgICByZXF1ZXN0LmVuZCgpO1xyXG4gIH0pO1xyXG59XHJcblxyXG4vKipcclxuICogUmV0dXJucyB0aGUgSFRUUCBvciBIVFRQUyBwcm90b2NvbCBtb2R1bGUgYmFzZWQgb24gdGhlIHByb3ZpZGVkIFVSTC5cclxuICpcclxuICogQGZ1bmN0aW9uIF9nZXRQcm90b2NvbE1vZHVsZVxyXG4gKlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gdXJsIC0gVGhlIFVSTCB0byBkZXRlcm1pbmUgdGhlIHByb3RvY29sLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7T2JqZWN0fSBUaGUgSFRUUCBvciBIVFRQUyBwcm90b2NvbCBtb2R1bGUgKGh0dHAgb3IgaHR0cHMpLlxyXG4gKi9cclxuZnVuY3Rpb24gX2dldFByb3RvY29sTW9kdWxlKHVybCkge1xyXG4gIHJldHVybiB1cmwuc3RhcnRzV2l0aCgnaHR0cHMnKSA/IGh0dHBzIDogaHR0cDtcclxufVxyXG5cclxuZXhwb3J0IGRlZmF1bHQge1xyXG4gIGZldGNoLFxyXG4gIHBvc3RcclxufTtcclxuIiwiLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcclxuXHJcbkhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlclxyXG5cclxuQ29weXJpZ2h0IChjKSAyMDE2LTIwMjUsIEhpZ2hzb2Z0XHJcblxyXG5MaWNlbmNlZCB1bmRlciB0aGUgTUlUIGxpY2VuY2UuXHJcblxyXG5BZGRpdGlvbmFsbHkgYSB2YWxpZCBIaWdoY2hhcnRzIGxpY2Vuc2UgaXMgcmVxdWlyZWQgZm9yIHVzZS5cclxuXHJcblNlZSBMSUNFTlNFIGZpbGUgaW4gcm9vdCBmb3IgZGV0YWlscy5cclxuXHJcbioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXHJcblxyXG4vKipcclxuICogQG92ZXJ2aWV3IFRoZSBjYWNoZSBtYW5hZ2VyIGlzIHJlc3BvbnNpYmxlIGZvciBoYW5kbGluZyBhbmQgbWFuYWdpbmdcclxuICogdGhlIEhpZ2hjaGFydHMgbGlicmFyeSBhbG9uZyB3aXRoIGl0cyBkZXBlbmRlbmNpZXMuIEl0IGVuc3VyZXMgdGhhdCB0aGVzZVxyXG4gKiByZXNvdXJjZXMgYXJlIHN0b3JlZCBhbmQgcmV0cmlldmVkIGVmZmljaWVudGx5IHRvIG9wdGltaXplIHBlcmZvcm1hbmNlXHJcbiAqIGFuZCByZWR1Y2UgcmVkdW5kYW50IG5ldHdvcmsgcmVxdWVzdHMuIFRoZSBjYWNoZSBpcyBzdG9yZWQgaW4gdGhlIGAuY2FjaGVgXHJcbiAqIGRpcmVjdG9yeSBieSBkZWZhdWx0LCB3aGljaCBzZXJ2ZXMgYXMgYSBkZWRpY2F0ZWQgZm9sZGVyIGZvciBrZWVwaW5nIGNhY2hlZFxyXG4gKiBmaWxlcy5cclxuICovXHJcblxyXG5pbXBvcnQgeyBleGlzdHNTeW5jLCBta2RpclN5bmMsIHJlYWRGaWxlU3luYywgd3JpdGVGaWxlU3luYyB9IGZyb20gJ2ZzJztcclxuaW1wb3J0IHsgam9pbiB9IGZyb20gJ3BhdGgnO1xyXG5cclxuaW1wb3J0IHsgSHR0cHNQcm94eUFnZW50IH0gZnJvbSAnaHR0cHMtcHJveHktYWdlbnQnO1xyXG5cclxuaW1wb3J0IHsgZ2V0T3B0aW9ucywgdXBkYXRlT3B0aW9ucyB9IGZyb20gJy4vY29uZmlnLmpzJztcclxuaW1wb3J0IHsgZmV0Y2ggfSBmcm9tICcuL2ZldGNoLmpzJztcclxuaW1wb3J0IHsgbG9nIH0gZnJvbSAnLi9sb2dnZXIuanMnO1xyXG5pbXBvcnQgeyBnZXRBYnNvbHV0ZVBhdGggfSBmcm9tICcuL3V0aWxzLmpzJztcclxuXHJcbmltcG9ydCBFeHBvcnRFcnJvciBmcm9tICcuL2Vycm9ycy9FeHBvcnRFcnJvci5qcyc7XHJcblxyXG4vLyBUaGUgaW5pdGlhbCBjYWNoZSB0ZW1wbGF0ZVxyXG5jb25zdCBjYWNoZSA9IHtcclxuICBjZG5Vcmw6ICdodHRwczovL2NvZGUuaGlnaGNoYXJ0cy5jb20nLFxyXG4gIGFjdGl2ZU1hbmlmZXN0OiB7fSxcclxuICBzb3VyY2VzOiAnJyxcclxuICBoY1ZlcnNpb246ICcnXHJcbn07XHJcblxyXG4vKipcclxuICogQ2hlY2tzIHRoZSBjYWNoZSBmb3IgSGlnaGNoYXJ0cyBkZXBlbmRlbmNpZXMsIHVwZGF0ZXMgdGhlIGNhY2hlIGlmIG5lZWRlZCxcclxuICogYW5kIGxvYWRzIHRoZSBzb3VyY2VzLlxyXG4gKlxyXG4gKiBAYXN5bmNcclxuICogQGZ1bmN0aW9uIGNoZWNrQW5kVXBkYXRlQ2FjaGVcclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IGhpZ2hjaGFydHNPcHRpb25zIC0gVGhlIGNvbmZpZ3VyYXRpb24gb2JqZWN0IGNvbnRhaW5pbmdcclxuICogYGhpZ2hjaGFydHNgIG9wdGlvbnMuXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBzZXJ2ZXJQcm94eU9wdGlvbnMtIFRoZSBjb25maWd1cmF0aW9uIG9iamVjdCBjb250YWluaW5nXHJcbiAqIGBzZXJ2ZXIucHJveHlgIG9wdGlvbnMuXHJcbiAqL1xyXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gY2hlY2tBbmRVcGRhdGVDYWNoZShcclxuICBoaWdoY2hhcnRzT3B0aW9ucyxcclxuICBzZXJ2ZXJQcm94eU9wdGlvbnNcclxuKSB7XHJcbiAgdHJ5IHtcclxuICAgIGxldCBmZXRjaGVkTW9kdWxlcztcclxuXHJcbiAgICAvLyBHZXQgdGhlIGNhY2hlIHBhdGhcclxuICAgIGNvbnN0IGNhY2hlUGF0aCA9IGdldENhY2hlUGF0aCgpO1xyXG5cclxuICAgIC8vIFByZXBhcmUgcGF0aHMgdG8gbWFuaWZlc3QgYW5kIHNvdXJjZXMgZnJvbSB0aGUgY2FjaGUgZm9sZGVyXHJcbiAgICBjb25zdCBtYW5pZmVzdFBhdGggPSBqb2luKGNhY2hlUGF0aCwgJ21hbmlmZXN0Lmpzb24nKTtcclxuICAgIGNvbnN0IHNvdXJjZVBhdGggPSBqb2luKGNhY2hlUGF0aCwgJ3NvdXJjZXMuanMnKTtcclxuXHJcbiAgICAvLyBDcmVhdGUgdGhlIGNhY2hlIGRlc3RpbmF0aW9uIGlmIGl0IGRvZXNuJ3QgZXhpc3QgYWxyZWFkeVxyXG4gICAgIWV4aXN0c1N5bmMoY2FjaGVQYXRoKSAmJiBta2RpclN5bmMoY2FjaGVQYXRoLCB7IHJlY3Vyc2l2ZTogdHJ1ZSB9KTtcclxuXHJcbiAgICAvLyBGZXRjaCBhbGwgdGhlIHNjcmlwdHMgZWl0aGVyIGlmIHRoZSBgbWFuaWZlc3QuanNvbmAgZG9lcyBub3QgZXhpc3RcclxuICAgIC8vIG9yIGlmIHRoZSBgZm9yY2VGZXRjaGAgb3B0aW9uIGlzIGVuYWJsZWRcclxuICAgIGlmICghZXhpc3RzU3luYyhtYW5pZmVzdFBhdGgpIHx8IGhpZ2hjaGFydHNPcHRpb25zLmZvcmNlRmV0Y2gpIHtcclxuICAgICAgbG9nKDMsICdbY2FjaGVdIEZldGNoaW5nIGFuZCBjYWNoaW5nIEhpZ2hjaGFydHMgZGVwZW5kZW5jaWVzLicpO1xyXG4gICAgICBmZXRjaGVkTW9kdWxlcyA9IGF3YWl0IF91cGRhdGVDYWNoZShcclxuICAgICAgICBoaWdoY2hhcnRzT3B0aW9ucyxcclxuICAgICAgICBzZXJ2ZXJQcm94eU9wdGlvbnMsXHJcbiAgICAgICAgc291cmNlUGF0aFxyXG4gICAgICApO1xyXG4gICAgfSBlbHNlIHtcclxuICAgICAgbGV0IHJlcXVlc3RVcGRhdGUgPSBmYWxzZTtcclxuXHJcbiAgICAgIC8vIFJlYWQgdGhlIG1hbmlmZXN0IEpTT05cclxuICAgICAgY29uc3QgbWFuaWZlc3QgPSBKU09OLnBhcnNlKHJlYWRGaWxlU3luYyhtYW5pZmVzdFBhdGgpLCAndXRmOCcpO1xyXG5cclxuICAgICAgLy8gQ2hlY2sgaWYgdGhlIG1vZHVsZXMgaXMgYW4gYXJyYXksIGlmIHNvLCB3ZSByZXdyaXRlIGl0IHRvIGEgbWFwIHRvIG1ha2VcclxuICAgICAgLy8gaXQgZWFzaWVyIHRvIHJlc29sdmUgbW9kdWxlcy5cclxuICAgICAgaWYgKG1hbmlmZXN0Lm1vZHVsZXMgJiYgQXJyYXkuaXNBcnJheShtYW5pZmVzdC5tb2R1bGVzKSkge1xyXG4gICAgICAgIGNvbnN0IG1vZHVsZU1hcCA9IHt9O1xyXG4gICAgICAgIG1hbmlmZXN0Lm1vZHVsZXMuZm9yRWFjaCgobSkgPT4gKG1vZHVsZU1hcFttXSA9IDEpKTtcclxuICAgICAgICBtYW5pZmVzdC5tb2R1bGVzID0gbW9kdWxlTWFwO1xyXG4gICAgICB9XHJcblxyXG4gICAgICAvLyBHZXQgdGhlIGFjdHVhbCBudW1iZXIgb2Ygc2NyaXB0cyB0byBiZSBmZXRjaGVkXHJcbiAgICAgIGNvbnN0IHsgY29yZVNjcmlwdHMsIG1vZHVsZVNjcmlwdHMsIGluZGljYXRvclNjcmlwdHMgfSA9XHJcbiAgICAgICAgaGlnaGNoYXJ0c09wdGlvbnM7XHJcbiAgICAgIGNvbnN0IG51bWJlck9mTW9kdWxlcyA9XHJcbiAgICAgICAgY29yZVNjcmlwdHMubGVuZ3RoICsgbW9kdWxlU2NyaXB0cy5sZW5ndGggKyBpbmRpY2F0b3JTY3JpcHRzLmxlbmd0aDtcclxuXHJcbiAgICAgIC8vIENvbXBhcmUgdGhlIGxvYWRlZCBoaWdoY2hhcnRzIGNvbmZpZyB3aXRoIHRoZSBjb250ZW50cyBpbiBjYWNoZS5cclxuICAgICAgLy8gSWYgdGhlcmUgYXJlIGNoYW5nZXMsIGZldGNoIHJlcXVlc3RlZCBtb2R1bGVzIGFuZCBwcm9kdWN0cyxcclxuICAgICAgLy8gYW5kIGJha2UgdGhlbSBpbnRvIGEgZ2lhbnQgYmxvYi4gU2F2ZSB0aGUgYmxvYi5cclxuICAgICAgaWYgKG1hbmlmZXN0LnZlcnNpb24gIT09IGhpZ2hjaGFydHNPcHRpb25zLnZlcnNpb24pIHtcclxuICAgICAgICBsb2coXHJcbiAgICAgICAgICAyLFxyXG4gICAgICAgICAgJ1tjYWNoZV0gQSBIaWdoY2hhcnRzIHZlcnNpb24gbWlzbWF0Y2ggaW4gdGhlIGNhY2hlLCBuZWVkIHRvIHJlLWZldGNoLidcclxuICAgICAgICApO1xyXG4gICAgICAgIHJlcXVlc3RVcGRhdGUgPSB0cnVlO1xyXG4gICAgICB9IGVsc2UgaWYgKFxyXG4gICAgICAgIE9iamVjdC5rZXlzKG1hbmlmZXN0Lm1vZHVsZXMgfHwge30pLmxlbmd0aCAhPT0gbnVtYmVyT2ZNb2R1bGVzXHJcbiAgICAgICkge1xyXG4gICAgICAgIGxvZyhcclxuICAgICAgICAgIDIsXHJcbiAgICAgICAgICAnW2NhY2hlXSBUaGUgY2FjaGUgYW5kIHRoZSByZXF1ZXN0ZWQgbW9kdWxlcyBkbyBub3QgbWF0Y2gsIG5lZWQgdG8gcmUtZmV0Y2guJ1xyXG4gICAgICAgICk7XHJcbiAgICAgICAgcmVxdWVzdFVwZGF0ZSA9IHRydWU7XHJcbiAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgLy8gQ2hlY2sgZWFjaCBtb2R1bGUsIGlmIGFueXRoaW5nIGlzIG1pc3NpbmcgcmVmZXRjaCBldmVyeXRoaW5nXHJcbiAgICAgICAgcmVxdWVzdFVwZGF0ZSA9IChtb2R1bGVTY3JpcHRzIHx8IFtdKS5zb21lKChtb2R1bGVOYW1lKSA9PiB7XHJcbiAgICAgICAgICBpZiAoIW1hbmlmZXN0Lm1vZHVsZXNbbW9kdWxlTmFtZV0pIHtcclxuICAgICAgICAgICAgbG9nKFxyXG4gICAgICAgICAgICAgIDIsXHJcbiAgICAgICAgICAgICAgYFtjYWNoZV0gVGhlICR7bW9kdWxlTmFtZX0gaXMgbWlzc2luZyBpbiB0aGUgY2FjaGUsIG5lZWQgdG8gcmUtZmV0Y2guYFxyXG4gICAgICAgICAgICApO1xyXG4gICAgICAgICAgICByZXR1cm4gdHJ1ZTtcclxuICAgICAgICAgIH1cclxuICAgICAgICB9KTtcclxuICAgICAgfVxyXG5cclxuICAgICAgLy8gVXBkYXRlIGNhY2hlIGlmIG5lZWRlZFxyXG4gICAgICBpZiAocmVxdWVzdFVwZGF0ZSkge1xyXG4gICAgICAgIGZldGNoZWRNb2R1bGVzID0gYXdhaXQgX3VwZGF0ZUNhY2hlKFxyXG4gICAgICAgICAgaGlnaGNoYXJ0c09wdGlvbnMsXHJcbiAgICAgICAgICBzZXJ2ZXJQcm94eU9wdGlvbnMsXHJcbiAgICAgICAgICBzb3VyY2VQYXRoXHJcbiAgICAgICAgKTtcclxuICAgICAgfSBlbHNlIHtcclxuICAgICAgICBsb2coMywgJ1tjYWNoZV0gRGVwZW5kZW5jeSBjYWNoZSBpcyB1cCB0byBkYXRlLCBwcm9jZWVkaW5nLicpO1xyXG5cclxuICAgICAgICAvLyBMb2FkIHRoZSBzb3VyY2VzXHJcbiAgICAgICAgY2FjaGUuc291cmNlcyA9IHJlYWRGaWxlU3luYyhzb3VyY2VQYXRoLCAndXRmOCcpO1xyXG5cclxuICAgICAgICAvLyBHZXQgY3VycmVudCBtb2R1bGVzIG1hcFxyXG4gICAgICAgIGZldGNoZWRNb2R1bGVzID0gbWFuaWZlc3QubW9kdWxlcztcclxuXHJcbiAgICAgICAgLy8gRXh0cmFjdCBhbmQgc2F2ZSB2ZXJzaW9uIG9mIGN1cnJlbnRseSB1c2VkIEhpZ2hjaGFydHNcclxuICAgICAgICBjYWNoZS5oY1ZlcnNpb24gPSBleHRyYWN0VmVyc2lvbihjYWNoZS5zb3VyY2VzKTtcclxuICAgICAgfVxyXG4gICAgfVxyXG5cclxuICAgIC8vIEZpbmFsbHksIHNhdmUgdGhlIG5ldyBtYW5pZmVzdCwgd2hpY2ggaXMgYmFzaWNhbGx5IG91ciBjdXJyZW50IGNvbmZpZ1xyXG4gICAgLy8gaW4gYSBzbGlnaHRseSBkaWZmZXJlbnQgZm9ybWF0XHJcbiAgICBhd2FpdCBfc2F2ZUNvbmZpZ1RvTWFuaWZlc3QoaGlnaGNoYXJ0c09wdGlvbnMsIGZldGNoZWRNb2R1bGVzKTtcclxuICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgdGhyb3cgbmV3IEV4cG9ydEVycm9yKFxyXG4gICAgICAnW2NhY2hlXSBDb3VsZCBub3QgY29uZmlndXJlIGNhY2hlIGFuZCBjcmVhdGUgb3IgdXBkYXRlIHRoZSBjb25maWcgbWFuaWZlc3QuJyxcclxuICAgICAgNTAwXHJcbiAgICApLnNldEVycm9yKGVycm9yKTtcclxuICB9XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBHZXRzIHRoZSB2ZXJzaW9uIG9mIEhpZ2hjaGFydHMgZnJvbSB0aGUgY2FjaGUuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBnZXRIaWdoY2hhcnRzVmVyc2lvblxyXG4gKlxyXG4gKiBAcmV0dXJucyB7c3RyaW5nfSBUaGUgY2FjaGVkIEhpZ2hjaGFydHMgdmVyc2lvbi5cclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiBnZXRIaWdoY2hhcnRzVmVyc2lvbigpIHtcclxuICByZXR1cm4gY2FjaGUuaGNWZXJzaW9uO1xyXG59XHJcblxyXG4vKipcclxuICogVXBkYXRlcyB0aGUgSGlnaGNoYXJ0cyB2ZXJzaW9uIGluIHRoZSBhcHBsaWVkIGNvbmZpZ3VyYXRpb24gYW5kIGNoZWNrc1xyXG4gKiB0aGUgY2FjaGUgZm9yIHRoZSBuZXcgdmVyc2lvbi5cclxuICpcclxuICogQGFzeW5jXHJcbiAqIEBmdW5jdGlvbiB1cGRhdGVIaWdoY2hhcnRzVmVyc2lvblxyXG4gKlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gbmV3VmVyc2lvbiAtIFRoZSBuZXcgSGlnaGNoYXJ0cyB2ZXJzaW9uIHRvIGJlIGFwcGxpZWQuXHJcbiAqL1xyXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gdXBkYXRlSGlnaGNoYXJ0c1ZlcnNpb24obmV3VmVyc2lvbikge1xyXG4gIC8vIFVwZGF0ZSB0byB0aGUgbmV3IHZlcnNpb25cclxuICBjb25zdCBvcHRpb25zID0gdXBkYXRlT3B0aW9ucyh7XHJcbiAgICBoaWdoY2hhcnRzOiB7XHJcbiAgICAgIHZlcnNpb246IG5ld1ZlcnNpb25cclxuICAgIH1cclxuICB9KTtcclxuXHJcbiAgLy8gQ2hlY2sgaWYgY2FjaGUgbmVlZHMgdG8gYmUgdXBkYXRlZFxyXG4gIGF3YWl0IGNoZWNrQW5kVXBkYXRlQ2FjaGUob3B0aW9ucy5oaWdoY2hhcnRzLCBvcHRpb25zLnNlcnZlci5wcm94eSk7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBFeHRyYWN0cyBIaWdoY2hhcnRzIHZlcnNpb24gZnJvbSB0aGUgY2FjaGUncyBzb3VyY2VzIHN0cmluZy5cclxuICpcclxuICogQGZ1bmN0aW9uIGV4dHJhY3RWZXJzaW9uXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBjYWNoZVNvdXJjZXMgLSBUaGUgY2FjaGUgc291cmNlcyBvYmplY3QuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtzdHJpbmd9IFRoZSBleHRyYWN0ZWQgSGlnaGNoYXJ0cyB2ZXJzaW9uLlxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIGV4dHJhY3RWZXJzaW9uKGNhY2hlU291cmNlcykge1xyXG4gIHJldHVybiBjYWNoZVNvdXJjZXNcclxuICAgIC5zdWJzdHJpbmcoMCwgY2FjaGVTb3VyY2VzLmluZGV4T2YoJyovJykpXHJcbiAgICAucmVwbGFjZSgnLyonLCAnJylcclxuICAgIC5yZXBsYWNlKCcqLycsICcnKVxyXG4gICAgLnJlcGxhY2UoL1xcbi9nLCAnJylcclxuICAgIC50cmltKCk7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBFeHRyYWN0cyB0aGUgSGlnaGNoYXJ0cyBtb2R1bGUgbmFtZSBiYXNlZCBvbiB0aGUgc2NyaXB0UGF0aC5cclxuICpcclxuICogQGZ1bmN0aW9uIGV4dHJhY3RNb2R1bGVOYW1lXHJcbiAqXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSBzY3JpcHRQYXRoIC0gVGhlIHBhdGggb2YgdGhlIHNjcmlwdCBmcm9tIHdoaWNoIHRoZSBtb2R1bGVcclxuICogbmFtZSB3aWxsIGJlIGV4dHJhY3RlZC5cclxuICpcclxuICogQHJldHVybnMge3N0cmluZ30gVGhlIGV4dHJhY3RlZCBtb2R1bGUgbmFtZS5cclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiBleHRyYWN0TW9kdWxlTmFtZShzY3JpcHRQYXRoKSB7XHJcbiAgcmV0dXJuIHNjcmlwdFBhdGgucmVwbGFjZShcclxuICAgIC8oLiopXFwvfCguKiltb2R1bGVzXFwvfHN0b2NrXFwvKC4qKWluZGljYXRvcnNcXC98bWFwc1xcLyguKiltb2R1bGVzXFwvL2dpLFxyXG4gICAgJydcclxuICApO1xyXG59XHJcblxyXG4vKipcclxuICogUmV0cmlldmVzIHRoZSBjdXJyZW50IGNhY2hlIG9iamVjdC5cclxuICpcclxuICogQGZ1bmN0aW9uIGdldENhY2hlXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtPYmplY3R9IFRoZSBjYWNoZSBvYmplY3QgY29udGFpbmluZyB2YXJpb3VzIGNhY2hlZCBkYXRhLlxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIGdldENhY2hlKCkge1xyXG4gIHJldHVybiBjYWNoZTtcclxufVxyXG5cclxuLyoqXHJcbiAqIEdldHMgdGhlIGNhY2hlIHBhdGggZm9yIEhpZ2hjaGFydHMuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBnZXRDYWNoZVBhdGhcclxuICpcclxuICogQHJldHVybnMge3N0cmluZ30gVGhlIGFic29sdXRlIHBhdGggdG8gdGhlIGNhY2hlIGRpcmVjdG9yeSBmb3IgSGlnaGNoYXJ0cy5cclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiBnZXRDYWNoZVBhdGgoKSB7XHJcbiAgcmV0dXJuIGdldEFic29sdXRlUGF0aChnZXRPcHRpb25zKCkuaGlnaGNoYXJ0cy5jYWNoZVBhdGgsICd1dGY4Jyk7IC8vICM1NjJcclxufVxyXG5cclxuLyoqXHJcbiAqIEZldGNoZXMgYSBzaW5nbGUgc2NyaXB0IGFuZCB1cGRhdGVzIHRoZSBgZmV0Y2hlZE1vZHVsZXNgIGFjY29yZGluZ2x5LlxyXG4gKlxyXG4gKiBAYXN5bmNcclxuICogQGZ1bmN0aW9uIF9mZXRjaEFuZFByb2Nlc3NTY3JpcHRcclxuICpcclxuICogQHBhcmFtIHtzdHJpbmd9IHNjcmlwdCAtIEEgcGF0aCB0byBzY3JpcHQgdG8gZ2V0LlxyXG4gKiBAcGFyYW0ge09iamVjdH0gcmVxdWVzdE9wdGlvbnMgLSBBZGRpdGlvbmFsIG9wdGlvbnMgZm9yIHRoZSBwcm94eSBhZ2VudFxyXG4gKiB0byB1c2UgZm9yIGEgcmVxdWVzdC5cclxuICogQHBhcmFtIHtPYmplY3R9IGZldGNoZWRNb2R1bGVzIC0gQW4gb2JqZWN0IHdoaWNoIHRyYWNrcyB3aGljaCBIaWdoY2hhcnRzXHJcbiAqIG1vZHVsZXMgaGF2ZSBiZWVuIGZldGNoZWQuXHJcbiAqIEBwYXJhbSB7Ym9vbGVhbn0gW3Nob3VsZFRocm93RXJyb3I9ZmFsc2VdIC0gQSBmbGFnIHRvIGluZGljYXRlIGlmIHRoZSBlcnJvclxyXG4gKiBzaG91bGQgYmUgdGhyb3duLiBUaGlzIHNob3VsZCBiZSB1c2VkIG9ubHkgZm9yIHRoZSBjb3JlIHNjcmlwdHMuIFRoZSBkZWZhdWx0XHJcbiAqIHZhbHVlIGlzIGBmYWxzZWAuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtQcm9taXNlPHN0cmluZz59IEEgUHJvbWlzZSB0aGF0IHJlc29sdmVzIHRvIHRoZSB0ZXh0IHJlcHJlc2VudGF0aW9uXHJcbiAqIG9mIHRoZSBmZXRjaGVkIHNjcmlwdC5cclxuICpcclxuICogQHRocm93cyB7RXhwb3J0RXJyb3J9IFRocm93cyBhbiBgRXhwb3J0RXJyb3JgIGlmIHRoZXJlIGlzIGEgcHJvYmxlbVxyXG4gKiB3aXRoIGZldGNoaW5nIHRoZSBzY3JpcHQuXHJcbiAqL1xyXG5hc3luYyBmdW5jdGlvbiBfZmV0Y2hBbmRQcm9jZXNzU2NyaXB0KFxyXG4gIHNjcmlwdCxcclxuICByZXF1ZXN0T3B0aW9ucyxcclxuICBmZXRjaGVkTW9kdWxlcyxcclxuICBzaG91bGRUaHJvd0Vycm9yID0gZmFsc2VcclxuKSB7XHJcbiAgLy8gR2V0IHJpZCBvZiB0aGUgLmpzIGZyb20gdGhlIGN1c3RvbSBzdHJpbmdzXHJcbiAgaWYgKHNjcmlwdC5lbmRzV2l0aCgnLmpzJykpIHtcclxuICAgIHNjcmlwdCA9IHNjcmlwdC5zdWJzdHJpbmcoMCwgc2NyaXB0Lmxlbmd0aCAtIDMpO1xyXG4gIH1cclxuICBsb2coNCwgYFtjYWNoZV0gRmV0Y2hpbmcgc2NyaXB0IC0gJHtzY3JpcHR9LmpzYCk7XHJcblxyXG4gIC8vIEZldGNoIHRoZSBzY3JpcHRcclxuICBjb25zdCByZXNwb25zZSA9IGF3YWl0IGZldGNoKGAke3NjcmlwdH0uanNgLCByZXF1ZXN0T3B0aW9ucyk7XHJcblxyXG4gIC8vIElmIE9LLCByZXR1cm4gaXRzIHRleHQgcmVwcmVzZW50YXRpb25cclxuICBpZiAocmVzcG9uc2Uuc3RhdHVzQ29kZSA9PT0gMjAwICYmIHR5cGVvZiByZXNwb25zZS50ZXh0ID09ICdzdHJpbmcnKSB7XHJcbiAgICBpZiAoZmV0Y2hlZE1vZHVsZXMpIHtcclxuICAgICAgY29uc3QgbW9kdWxlTmFtZSA9IGV4dHJhY3RNb2R1bGVOYW1lKHNjcmlwdCk7XHJcbiAgICAgIGZldGNoZWRNb2R1bGVzW21vZHVsZU5hbWVdID0gMTtcclxuICAgIH1cclxuICAgIHJldHVybiByZXNwb25zZS50ZXh0O1xyXG4gIH1cclxuXHJcbiAgLy8gQmFzZWQgb24gdGhlIGBzaG91bGRUaHJvd0Vycm9yYCBmbGFnLCBkZWNpZGUgaG93IHRvIHNlcnZlIGVycm9yIG1lc3NhZ2VcclxuICBpZiAoc2hvdWxkVGhyb3dFcnJvcikge1xyXG4gICAgdGhyb3cgbmV3IEV4cG9ydEVycm9yKFxyXG4gICAgICBgW2NhY2hlXSBDb3VsZCBub3QgZmV0Y2ggdGhlICR7c2NyaXB0fS5qcy4gVGhlIHNjcmlwdCBtaWdodCBub3QgZXhpc3QgaW4gdGhlIHJlcXVlc3RlZCB2ZXJzaW9uIChzdGF0dXMgY29kZTogJHtyZXNwb25zZS5zdGF0dXNDb2RlfSkuYCxcclxuICAgICAgNDA0XHJcbiAgICApLnNldEVycm9yKHJlc3BvbnNlKTtcclxuICB9IGVsc2Uge1xyXG4gICAgbG9nKFxyXG4gICAgICAyLFxyXG4gICAgICBgW2NhY2hlXSBDb3VsZCBub3QgZmV0Y2ggdGhlICR7c2NyaXB0fS5qcy4gVGhlIHNjcmlwdCBtaWdodCBub3QgZXhpc3QgaW4gdGhlIHJlcXVlc3RlZCB2ZXJzaW9uLmBcclxuICAgICk7XHJcbiAgfVxyXG59XHJcblxyXG4vKipcclxuICogU2F2ZXMgdGhlIHByb3ZpZGVkIGNvbmZpZ3VyYXRpb24gYW5kIGZldGNoZWQgbW9kdWxlcyB0byB0aGUgY2FjaGUgbWFuaWZlc3RcclxuICogZmlsZS5cclxuICpcclxuICogQGFzeW5jXHJcbiAqIEBmdW5jdGlvbiBfc2F2ZUNvbmZpZ1RvTWFuaWZlc3RcclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IGhpZ2hjaGFydHNPcHRpb25zIC0gVGhlIGNvbmZpZ3VyYXRpb24gb2JqZWN0IGNvbnRhaW5pbmdcclxuICogYGhpZ2hjaGFydHNgIG9wdGlvbnMuXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBbZmV0Y2hlZE1vZHVsZXM9e31dIC0gQW4gb2JqZWN0IHdoaWNoIHRyYWNrcyB3aGljaCBIaWdoY2hhcnRzXHJcbiAqIG1vZHVsZXMgaGF2ZSBiZWVuIGZldGNoZWQuIFRoZSBkZWZhdWx0IHZhbHVlIGlzIGFuIGVtcHR5IG9iamVjdC5cclxuICpcclxuICogQHRocm93cyB7RXhwb3J0RXJyb3J9IFRocm93cyBhbiBgRXhwb3J0RXJyb3JgIGlmIGFuIGVycm9yIG9jY3VycyB3aGlsZVxyXG4gKiB3cml0aW5nIHRoZSBjYWNoZSBtYW5pZmVzdC5cclxuICovXHJcbmFzeW5jIGZ1bmN0aW9uIF9zYXZlQ29uZmlnVG9NYW5pZmVzdChoaWdoY2hhcnRzT3B0aW9ucywgZmV0Y2hlZE1vZHVsZXMgPSB7fSkge1xyXG4gIGNvbnN0IG5ld01hbmlmZXN0ID0ge1xyXG4gICAgdmVyc2lvbjogaGlnaGNoYXJ0c09wdGlvbnMudmVyc2lvbixcclxuICAgIG1vZHVsZXM6IGZldGNoZWRNb2R1bGVzXHJcbiAgfTtcclxuXHJcbiAgLy8gVXBkYXRlIGNhY2hlIG9iamVjdCB3aXRoIHRoZSBjdXJyZW50IG1vZHVsZXNcclxuICBjYWNoZS5hY3RpdmVNYW5pZmVzdCA9IG5ld01hbmlmZXN0O1xyXG5cclxuICBsb2coMywgJ1tjYWNoZV0gV3JpdGluZyBhIG5ldyBtYW5pZmVzdC4nKTtcclxuICB0cnkge1xyXG4gICAgd3JpdGVGaWxlU3luYyhcclxuICAgICAgam9pbihnZXRDYWNoZVBhdGgoKSwgJ21hbmlmZXN0Lmpzb24nKSxcclxuICAgICAgSlNPTi5zdHJpbmdpZnkobmV3TWFuaWZlc3QpLFxyXG4gICAgICAndXRmOCdcclxuICAgICk7XHJcbiAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcihcclxuICAgICAgJ1tjYWNoZV0gRXJyb3Igd3JpdGluZyB0aGUgY2FjaGUgbWFuaWZlc3QuJyxcclxuICAgICAgNTAwXHJcbiAgICApLnNldEVycm9yKGVycm9yKTtcclxuICB9XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBGZXRjaGVzIEhpZ2hjaGFydHMgYHNjcmlwdHNgIGFuZCBgY3VzdG9tU2NyaXB0c2AgZnJvbSB0aGUgZ2l2ZW4gQ0ROcy5cclxuICpcclxuICogQGFzeW5jXHJcbiAqIEBmdW5jdGlvbiBfZmV0Y2hTY3JpcHRzXHJcbiAqXHJcbiAqIEBwYXJhbSB7QXJyYXkuPHN0cmluZz59IGNvcmVTY3JpcHRzIC0gSGlnaGNoYXJ0cyBjb3JlIHNjcmlwdHMgdG8gZmV0Y2guXHJcbiAqIEBwYXJhbSB7QXJyYXkuPHN0cmluZz59IG1vZHVsZVNjcmlwdHMgLSBIaWdoY2hhcnRzIG1vZHVsZXMgdG8gZmV0Y2guXHJcbiAqIEBwYXJhbSB7QXJyYXkuPHN0cmluZz59IGN1c3RvbVNjcmlwdHMgLSBDdXN0b20gc2NyaXB0IHBhdGhzIHRvIGZldGNoIChmdWxsXHJcbiAqIFVSTHMpLlxyXG4gKiBAcGFyYW0ge09iamVjdH0gc2VydmVyUHJveHlPcHRpb25zIC0gVGhlIGNvbmZpZ3VyYXRpb24gb2JqZWN0IGNvbnRhaW5pbmdcclxuICogYHNlcnZlci5wcm94eWAgb3B0aW9ucy5cclxuICogQHBhcmFtIHtPYmplY3R9IGZldGNoZWRNb2R1bGVzIC0gQW4gb2JqZWN0IHdoaWNoIHRyYWNrcyB3aGljaCBIaWdoY2hhcnRzXHJcbiAqIG1vZHVsZXMgaGF2ZSBiZWVuIGZldGNoZWQuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtQcm9taXNlPHN0cmluZz59IEEgUHJvbWlzZSB0aGF0IHJlc29sdmVzIHRvIHRoZSBmZXRjaGVkIHNjcmlwdHNcclxuICogY29udGVudCBqb2luZWQuXHJcbiAqXHJcbiAqIEB0aHJvd3Mge0V4cG9ydEVycm9yfSBUaHJvd3MgYW4gYEV4cG9ydEVycm9yYCBpZiBhbiBlcnJvciBvY2N1cnMgd2hpbGVcclxuICogc2V0dGluZyBhbiBIVFRQIEFnZW50IGZvciBwcm94eS5cclxuICovXHJcbmFzeW5jIGZ1bmN0aW9uIF9mZXRjaFNjcmlwdHMoXHJcbiAgY29yZVNjcmlwdHMsXHJcbiAgbW9kdWxlU2NyaXB0cyxcclxuICBjdXN0b21TY3JpcHRzLFxyXG4gIHNlcnZlclByb3h5T3B0aW9ucyxcclxuICBmZXRjaGVkTW9kdWxlc1xyXG4pIHtcclxuICAvLyBDb25maWd1cmUgcHJveHkgaWYgZXhpc3RzXHJcbiAgbGV0IHByb3h5QWdlbnQ7XHJcbiAgY29uc3QgcHJveHlIb3N0ID0gc2VydmVyUHJveHlPcHRpb25zLmhvc3Q7XHJcbiAgY29uc3QgcHJveHlQb3J0ID0gc2VydmVyUHJveHlPcHRpb25zLnBvcnQ7XHJcblxyXG4gIC8vIFRyeSB0byBjcmVhdGUgYSBQcm94eSBBZ2VudFxyXG4gIGlmIChwcm94eUhvc3QgJiYgcHJveHlQb3J0KSB7XHJcbiAgICB0cnkge1xyXG4gICAgICBwcm94eUFnZW50ID0gbmV3IEh0dHBzUHJveHlBZ2VudCh7XHJcbiAgICAgICAgaG9zdDogcHJveHlIb3N0LFxyXG4gICAgICAgIHBvcnQ6IHByb3h5UG9ydFxyXG4gICAgICB9KTtcclxuICAgIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcihcclxuICAgICAgICAnW2NhY2hlXSBDb3VsZCBub3QgY3JlYXRlIGEgUHJveHkgQWdlbnQuJyxcclxuICAgICAgICA1MDBcclxuICAgICAgKS5zZXRFcnJvcihlcnJvcik7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICAvLyBJZiBleGlzdHMsIGFkZCBwcm94eSBhZ2VudCB0byByZXF1ZXN0IG9wdGlvbnNcclxuICBjb25zdCByZXF1ZXN0T3B0aW9ucyA9IHByb3h5QWdlbnRcclxuICAgID8ge1xyXG4gICAgICAgIGFnZW50OiBwcm94eUFnZW50LFxyXG4gICAgICAgIHRpbWVvdXQ6IHNlcnZlclByb3h5T3B0aW9ucy50aW1lb3V0XHJcbiAgICAgIH1cclxuICAgIDoge307XHJcblxyXG4gIGNvbnN0IGFsbEZldGNoUHJvbWlzZXMgPSBbXHJcbiAgICAuLi5jb3JlU2NyaXB0cy5tYXAoKHNjcmlwdCkgPT5cclxuICAgICAgX2ZldGNoQW5kUHJvY2Vzc1NjcmlwdChgJHtzY3JpcHR9YCwgcmVxdWVzdE9wdGlvbnMsIGZldGNoZWRNb2R1bGVzLCB0cnVlKVxyXG4gICAgKSxcclxuICAgIC4uLm1vZHVsZVNjcmlwdHMubWFwKChzY3JpcHQpID0+XHJcbiAgICAgIF9mZXRjaEFuZFByb2Nlc3NTY3JpcHQoYCR7c2NyaXB0fWAsIHJlcXVlc3RPcHRpb25zLCBmZXRjaGVkTW9kdWxlcylcclxuICAgICksXHJcbiAgICAuLi5jdXN0b21TY3JpcHRzLm1hcCgoc2NyaXB0KSA9PlxyXG4gICAgICBfZmV0Y2hBbmRQcm9jZXNzU2NyaXB0KGAke3NjcmlwdH1gLCByZXF1ZXN0T3B0aW9ucylcclxuICAgIClcclxuICBdO1xyXG5cclxuICBjb25zdCBmZXRjaGVkU2NyaXB0cyA9IGF3YWl0IFByb21pc2UuYWxsKGFsbEZldGNoUHJvbWlzZXMpO1xyXG4gIHJldHVybiBmZXRjaGVkU2NyaXB0cy5qb2luKCc7XFxuJyk7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBVcGRhdGVzIHRoZSBsb2NhbCBjYWNoZSB3aXRoIEhpZ2hjaGFydHMgc2NyaXB0cyBhbmQgdGhlaXIgdmVyc2lvbnMuXHJcbiAqXHJcbiAqIEBhc3luY1xyXG4gKiBAZnVuY3Rpb24gX3VwZGF0ZUNhY2hlXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBoaWdoY2hhcnRzT3B0aW9ucyAtIFRoZSBjb25maWd1cmF0aW9uIG9iamVjdCBjb250YWluaW5nXHJcbiAqIGBoaWdoY2hhcnRzYCBvcHRpb25zLlxyXG4gKiBAcGFyYW0ge09iamVjdH0gc2VydmVyUHJveHlPcHRpb25zIC0gVGhlIGNvbmZpZ3VyYXRpb24gb2JqZWN0IGNvbnRhaW5pbmdcclxuICogYHNlcnZlci5wcm94eWAgb3B0aW9ucy5cclxuICogQHBhcmFtIHtzdHJpbmd9IHNvdXJjZVBhdGggLSBUaGUgcGF0aCB0byB0aGUgc291cmNlIGZpbGUgaW4gdGhlIGNhY2hlLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7UHJvbWlzZTxPYmplY3Q+fSBBIFByb21pc2UgdGhhdCByZXNvbHZlcyB0byBhbiBvYmplY3QgcmVwcmVzZW50aW5nXHJcbiAqIHRoZSBmZXRjaGVkIG1vZHVsZXMuXHJcbiAqXHJcbiAqIEB0aHJvd3Mge0V4cG9ydEVycm9yfSBUaHJvd3MgYW4gYEV4cG9ydEVycm9yYCBpZiB0aGVyZSBpcyBhbiBpc3N1ZSB1cGRhdGluZ1xyXG4gKiB0aGUgbG9jYWwgSGlnaGNoYXJ0cyBjYWNoZS5cclxuICovXHJcbmFzeW5jIGZ1bmN0aW9uIF91cGRhdGVDYWNoZShoaWdoY2hhcnRzT3B0aW9ucywgc2VydmVyUHJveHlPcHRpb25zLCBzb3VyY2VQYXRoKSB7XHJcbiAgLy8gR2V0IEhpZ2hjaGFydHMgdmVyc2lvbiBmb3Igc2NyaXB0c1xyXG4gIGNvbnN0IGhjVmVyc2lvbiA9XHJcbiAgICBoaWdoY2hhcnRzT3B0aW9ucy52ZXJzaW9uID09PSAnbGF0ZXN0J1xyXG4gICAgICA/IG51bGxcclxuICAgICAgOiBgJHtoaWdoY2hhcnRzT3B0aW9ucy52ZXJzaW9ufWA7XHJcblxyXG4gIC8vIEdldCB0aGUgQ0ROIHVybCBmb3Igc2NyaXB0c1xyXG4gIGNvbnN0IGNkblVybCA9IGhpZ2hjaGFydHNPcHRpb25zLmNkblVybCB8fCBjYWNoZS5jZG5Vcmw7XHJcblxyXG4gIHRyeSB7XHJcbiAgICBjb25zdCBmZXRjaGVkTW9kdWxlcyA9IHt9O1xyXG5cclxuICAgIGxvZyhcclxuICAgICAgMyxcclxuICAgICAgYFtjYWNoZV0gVXBkYXRpbmcgY2FjaGUgdmVyc2lvbiB0byBIaWdoY2hhcnRzOiAke2hjVmVyc2lvbiB8fCAnbGF0ZXN0J30uYFxyXG4gICAgKTtcclxuXHJcbiAgICBjYWNoZS5zb3VyY2VzID0gYXdhaXQgX2ZldGNoU2NyaXB0cyhcclxuICAgICAgW1xyXG4gICAgICAgIC4uLmhpZ2hjaGFydHNPcHRpb25zLmNvcmVTY3JpcHRzLm1hcCgoYykgPT5cclxuICAgICAgICAgIGhjVmVyc2lvbiA/IGAke2NkblVybH0vJHtoY1ZlcnNpb259LyR7Y31gIDogYCR7Y2RuVXJsfS8ke2N9YFxyXG4gICAgICAgIClcclxuICAgICAgXSxcclxuICAgICAgW1xyXG4gICAgICAgIC4uLmhpZ2hjaGFydHNPcHRpb25zLm1vZHVsZVNjcmlwdHMubWFwKChtKSA9PlxyXG4gICAgICAgICAgbSA9PT0gJ21hcCdcclxuICAgICAgICAgICAgPyBoY1ZlcnNpb25cclxuICAgICAgICAgICAgICA/IGAke2NkblVybH0vbWFwcy8ke2hjVmVyc2lvbn0vbW9kdWxlcy8ke219YFxyXG4gICAgICAgICAgICAgIDogYCR7Y2RuVXJsfS9tYXBzL21vZHVsZXMvJHttfWBcclxuICAgICAgICAgICAgOiBoY1ZlcnNpb25cclxuICAgICAgICAgICAgICA/IGAke2NkblVybH0vJHtoY1ZlcnNpb259L21vZHVsZXMvJHttfWBcclxuICAgICAgICAgICAgICA6IGAke2NkblVybH0vbW9kdWxlcy8ke219YFxyXG4gICAgICAgICksXHJcbiAgICAgICAgLi4uaGlnaGNoYXJ0c09wdGlvbnMuaW5kaWNhdG9yU2NyaXB0cy5tYXAoKGkpID0+XHJcbiAgICAgICAgICBoY1ZlcnNpb25cclxuICAgICAgICAgICAgPyBgJHtjZG5Vcmx9L3N0b2NrLyR7aGNWZXJzaW9ufS9pbmRpY2F0b3JzLyR7aX1gXHJcbiAgICAgICAgICAgIDogYCR7Y2RuVXJsfS9zdG9jay9pbmRpY2F0b3JzLyR7aX1gXHJcbiAgICAgICAgKVxyXG4gICAgICBdLFxyXG4gICAgICBoaWdoY2hhcnRzT3B0aW9ucy5jdXN0b21TY3JpcHRzLFxyXG4gICAgICBzZXJ2ZXJQcm94eU9wdGlvbnMsXHJcbiAgICAgIGZldGNoZWRNb2R1bGVzXHJcbiAgICApO1xyXG5cclxuICAgIC8vIEV4dHJhY3QgYW5kIHNhdmUgdmVyc2lvbiBvZiBjdXJyZW50bHkgdXNlZCBIaWdoY2hhcnRzXHJcbiAgICBjYWNoZS5oY1ZlcnNpb24gPSBleHRyYWN0VmVyc2lvbihjYWNoZS5zb3VyY2VzKTtcclxuXHJcbiAgICAvLyBTYXZlIHRoZSBmZXRjaGVkIG1vZHVsZXMgaW50byBjYWNoZXMnIHNvdXJjZSBKU09OXHJcbiAgICB3cml0ZUZpbGVTeW5jKHNvdXJjZVBhdGgsIGNhY2hlLnNvdXJjZXMpO1xyXG4gICAgcmV0dXJuIGZldGNoZWRNb2R1bGVzO1xyXG4gIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoXHJcbiAgICAgICdbY2FjaGVdIFVuYWJsZSB0byB1cGRhdGUgdGhlIGxvY2FsIEhpZ2hjaGFydHMgY2FjaGUuJyxcclxuICAgICAgNTAwXHJcbiAgICApLnNldEVycm9yKGVycm9yKTtcclxuICB9XHJcbn1cclxuXHJcbmV4cG9ydCBkZWZhdWx0IHtcclxuICBjaGVja0FuZFVwZGF0ZUNhY2hlLFxyXG4gIGdldEhpZ2hjaGFydHNWZXJzaW9uLFxyXG4gIHVwZGF0ZUhpZ2hjaGFydHNWZXJzaW9uLFxyXG4gIGV4dHJhY3RWZXJzaW9uLFxyXG4gIGV4dHJhY3RNb2R1bGVOYW1lLFxyXG4gIGdldENhY2hlLFxyXG4gIGdldENhY2hlUGF0aFxyXG59O1xyXG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxyXG5cclxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXHJcblxyXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNSwgSGlnaHNvZnRcclxuXHJcbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cclxuXHJcbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxyXG5cclxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxyXG5cclxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cclxuXHJcbi8qKlxyXG4gKiBAb3ZlcnZpZXcgUHJvdmlkZXMgbWV0aG9kcyBmb3IgaW5pdGlhbGl6aW5nIEhpZ2hjaGFydHMgd2l0aCBjdXN0b21pemVkXHJcbiAqIGFuaW1hdGlvbiBzZXR0aW5ncyBhbmQgdHJpZ2dlcmluZyB0aGUgY3JlYXRpb24gb2YgSGlnaGNoYXJ0cyBjaGFydHMgd2l0aFxyXG4gKiBleHBvcnQtc3BlY2lmaWMgY29uZmlndXJhdGlvbnMgaW4gdGhlIHBhZ2UgY29udGV4dC4gU3VwcG9ydHMgZHluYW1pYyBvcHRpb25cclxuICogbWVyZ2luZywgY3VzdG9tIGxvZ2ljIGluamVjdGlvbiwgYW5kIGNvbnRyb2wgb3ZlciByZW5kZXJpbmcgYmVoYXZpb3JzLiBVc2VkXHJcbiAqIGJ5IHRoZSBQdXBwZXRlZXIgcGFnZS5cclxuICovXHJcblxyXG4vKiBlc2xpbnQtZGlzYWJsZSBuby11bmRlZiAqL1xyXG5cclxuLyoqXHJcbiAqIFNldHRpbmcgdGhlIGBIaWdoY2hhcnRzLmFuaW1PYmplY3RgIGZ1bmN0aW9uLiBDYWxsZWQgd2hlbiBpbml0aW5nIHRoZSBwYWdlLlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gc2V0dXBIaWdoY2hhcnRzXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gc2V0dXBIaWdoY2hhcnRzKCkge1xyXG4gIEhpZ2hjaGFydHMuYW5pbU9iamVjdCA9IGZ1bmN0aW9uICgpIHtcclxuICAgIHJldHVybiB7IGR1cmF0aW9uOiAwIH07XHJcbiAgfTtcclxufVxyXG5cclxuLyoqXHJcbiAqIENyZWF0ZXMgdGhlIGFjdHVhbCBIaWdoY2hhcnRzIGNoYXJ0IG9uIGEgcGFnZS5cclxuICpcclxuICogQGFzeW5jXHJcbiAqIEBmdW5jdGlvbiBjcmVhdGVDaGFydFxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gZXhwb3J0T3B0aW9ucyAtIFRoZSBjb25maWd1cmF0aW9uIG9iamVjdCBjb250YWluaW5nIGBleHBvcnRgXHJcbiAqIG9wdGlvbnMuXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBjdXN0b21Mb2dpY09wdGlvbnMgLSBUaGUgY29uZmlndXJhdGlvbiBvYmplY3QgY29udGFpbmluZ1xyXG4gKiBgY3VzdG9tTG9naWNgIG9wdGlvbnMuXHJcbiAqXHJcbiAqL1xyXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gY3JlYXRlQ2hhcnQoZXhwb3J0T3B0aW9ucywgY3VzdG9tTG9naWNPcHRpb25zKSB7XHJcbiAgLy8gR2V0IHJlcXVpcmVkIGZ1bmN0aW9uc1xyXG4gIGNvbnN0IHsgZ2V0T3B0aW9ucywgc2V0T3B0aW9ucywgbWVyZ2UsIHdyYXAgfSA9IEhpZ2hjaGFydHM7XHJcblxyXG4gIC8vIENyZWF0ZSBhIHNlcGFyYXRlIG9iamVjdCBmb3IgYSBwb3RlbnRpYWwgYHNldE9wdGlvbnNgIHVzYWdlcyBpbiBvcmRlclxyXG4gIC8vIHRvIHByZXZlbnQgZnJvbSBwb2xsdXRpbmcgb3RoZXIgZXhwb3J0cyB0aGF0IGNhbiBoYXBwZW4gb24gdGhlIHNhbWUgcGFnZVxyXG4gIEhpZ2hjaGFydHMuc2V0T3B0aW9uc09iaiA9IG1lcmdlKGZhbHNlLCB7fSwgZ2V0T3B0aW9ucygpKTtcclxuXHJcbiAgLy8gTk9URTogSXMgdGhpcyB1c2VkIGZvciBhbnl0aGluZyB1c2VmdWw/XHJcbiAgd2luZG93LmlzUmVuZGVyQ29tcGxldGUgPSBmYWxzZTtcclxuICB3cmFwKEhpZ2hjaGFydHMuQ2hhcnQucHJvdG90eXBlLCAnaW5pdCcsIGZ1bmN0aW9uIChwcm9jZWVkLCB1c2VyT3B0aW9ucywgY2IpIHtcclxuICAgIC8vIE92ZXJyaWRlIHRoZSBgdXNlck9wdGlvbnNgIHdpdGggaW1hZ2UgZnJpZW5kbHkgb3B0aW9uc1xyXG4gICAgdXNlck9wdGlvbnMgPSBtZXJnZSh1c2VyT3B0aW9ucywge1xyXG4gICAgICBleHBvcnRpbmc6IHtcclxuICAgICAgICBlbmFibGVkOiBmYWxzZVxyXG4gICAgICB9LFxyXG4gICAgICBwbG90T3B0aW9uczoge1xyXG4gICAgICAgIHNlcmllczoge1xyXG4gICAgICAgICAgbGFiZWw6IHtcclxuICAgICAgICAgICAgZW5hYmxlZDogZmFsc2VcclxuICAgICAgICAgIH1cclxuICAgICAgICB9XHJcbiAgICAgIH0sXHJcbiAgICAgIC8qIEV4cGVjdHMgdG9vbHRpcCBpbiB0aGUgYHVzZXJPcHRpb25zYCB3aGVuIGBmb3JFeHBvcnRgIGlzIHRydWUuXHJcbiAgICAgICAgaHR0cHM6Ly9naXRodWIuY29tL2hpZ2hjaGFydHMvaGlnaGNoYXJ0cy9ibG9iLzNhZDQzMGEzNTNiODA1NmI5ZTc2NGFhNGU1Y2Q2ODI4YWE0NzlkYjIvanMvcGFydHMvQ2hhcnQuanMjTDI0MVxyXG4gICAgICAgICovXHJcbiAgICAgIHRvb2x0aXA6IHt9XHJcbiAgICB9KTtcclxuXHJcbiAgICAodXNlck9wdGlvbnMuc2VyaWVzIHx8IFtdKS5mb3JFYWNoKGZ1bmN0aW9uIChzZXJpZXMpIHtcclxuICAgICAgc2VyaWVzLmFuaW1hdGlvbiA9IGZhbHNlO1xyXG4gICAgfSk7XHJcblxyXG4gICAgLy8gQWRkIGZsYWcgdG8ga25vdyBpZiBjaGFydCByZW5kZXIgaGFzIGJlZW4gY2FsbGVkLlxyXG4gICAgaWYgKCF3aW5kb3cub25IaWdoY2hhcnRzUmVuZGVyKSB7XHJcbiAgICAgIHdpbmRvdy5vbkhpZ2hjaGFydHNSZW5kZXIgPSBIaWdoY2hhcnRzLmFkZEV2ZW50KHRoaXMsICdyZW5kZXInLCAoKSA9PiB7XHJcbiAgICAgICAgd2luZG93LmlzUmVuZGVyQ29tcGxldGUgPSB0cnVlO1xyXG4gICAgICB9KTtcclxuICAgIH1cclxuXHJcbiAgICBwcm9jZWVkLmFwcGx5KHRoaXMsIFt1c2VyT3B0aW9ucywgY2JdKTtcclxuICB9KTtcclxuXHJcbiAgd3JhcChIaWdoY2hhcnRzLlNlcmllcy5wcm90b3R5cGUsICdpbml0JywgZnVuY3Rpb24gKHByb2NlZWQsIGNoYXJ0LCBvcHRpb25zKSB7XHJcbiAgICBwcm9jZWVkLmFwcGx5KHRoaXMsIFtjaGFydCwgb3B0aW9uc10pO1xyXG4gIH0pO1xyXG5cclxuICAvLyBTb21lIG1hbmRhdG9yeSBhZGRpdGlvbmFsIGBjaGFydGAgYW5kIGBleHBvcnRpbmdgIG9wdGlvbnNcclxuICBjb25zdCBhZGRpdGlvbmFsT3B0aW9ucyA9IHtcclxuICAgIGNoYXJ0OiB7XHJcbiAgICAgIC8vIEJ5IGRlZmF1bHQgYW5pbWF0aW9uIGlzIGRpc2FibGVkXHJcbiAgICAgIGFuaW1hdGlvbjogZmFsc2UsXHJcbiAgICAgIC8vIEdldCB0aGUgcmlnaHQgc2l6ZSB2YWx1ZXNcclxuICAgICAgaGVpZ2h0OiBleHBvcnRPcHRpb25zLmhlaWdodCxcclxuICAgICAgd2lkdGg6IGV4cG9ydE9wdGlvbnMud2lkdGhcclxuICAgIH0sXHJcbiAgICBleHBvcnRpbmc6IHtcclxuICAgICAgLy8gTm8gbmVlZCBmb3IgdGhlIGV4cG9ydGluZyBidXR0b25cclxuICAgICAgZW5hYmxlZDogZmFsc2VcclxuICAgIH1cclxuICB9O1xyXG5cclxuICAvLyBHZXQgdGhlIGlucHV0IHRvIGV4cG9ydCBmcm9tIHRoZSBgaW5zdHJgIG9wdGlvblxyXG4gIGNvbnN0IHVzZXJPcHRpb25zID0gbmV3IEZ1bmN0aW9uKGByZXR1cm4gJHtleHBvcnRPcHRpb25zLmluc3RyfWApKCk7XHJcblxyXG4gIC8vIEdldCB0aGUgYHRoZW1lT3B0aW9uc2Agb3B0aW9uXHJcbiAgY29uc3QgdGhlbWVPcHRpb25zID0gbmV3IEZ1bmN0aW9uKGByZXR1cm4gJHtleHBvcnRPcHRpb25zLnRoZW1lT3B0aW9uc31gKSgpO1xyXG5cclxuICAvLyBHZXQgdGhlIGBnbG9iYWxPcHRpb25zYCBvcHRpb25cclxuICBjb25zdCBnbG9iYWxPcHRpb25zID0gbmV3IEZ1bmN0aW9uKGByZXR1cm4gJHtleHBvcnRPcHRpb25zLmdsb2JhbE9wdGlvbnN9YCkoKTtcclxuXHJcbiAgLy8gTWVyZ2UgdGhlIGZvbGxvd2luZyBvcHRpb25zIG9iamVjdHMgdG8gY3JlYXRlIGZpbmFsIG9wdGlvbnNcclxuICBjb25zdCBmaW5hbE9wdGlvbnMgPSBtZXJnZShcclxuICAgIGZhbHNlLFxyXG4gICAgdGhlbWVPcHRpb25zLFxyXG4gICAgdXNlck9wdGlvbnMsXHJcbiAgICAvLyBQbGFjZWQgaXQgaGVyZSBpbnN0ZWFkIGluIHRoZSBpbml0IGJlY2F1c2Ugb2YgdGhlIHNpemUgaXNzdWVzXHJcbiAgICBhZGRpdGlvbmFsT3B0aW9uc1xyXG4gICk7XHJcblxyXG4gIC8vIFByZXBhcmUgdGhlIGBjYWxsYmFja2Agb3B0aW9uXHJcbiAgY29uc3QgZmluYWxDYWxsYmFjayA9IGN1c3RvbUxvZ2ljT3B0aW9ucy5jYWxsYmFja1xyXG4gICAgPyBuZXcgRnVuY3Rpb24oYHJldHVybiAke2N1c3RvbUxvZ2ljT3B0aW9ucy5jYWxsYmFja31gKSgpXHJcbiAgICA6IG51bGw7XHJcblxyXG4gIC8vIFRyaWdnZXIgdGhlIGBjdXN0b21Db2RlYCBvcHRpb25cclxuICBpZiAoY3VzdG9tTG9naWNPcHRpb25zLmN1c3RvbUNvZGUpIHtcclxuICAgIG5ldyBGdW5jdGlvbignb3B0aW9ucycsIGN1c3RvbUxvZ2ljT3B0aW9ucy5jdXN0b21Db2RlKSh1c2VyT3B0aW9ucyk7XHJcbiAgfVxyXG5cclxuICAvLyBTZXQgdGhlIGdsb2JhbCBvcHRpb25zIGlmIGV4aXN0XHJcbiAgaWYgKGdsb2JhbE9wdGlvbnMpIHtcclxuICAgIHNldE9wdGlvbnMoZ2xvYmFsT3B0aW9ucyk7XHJcbiAgfVxyXG5cclxuICAvLyBDYWxsIHRoZSBjaGFydCBjcmVhdGlvblxyXG4gIEhpZ2hjaGFydHNbZXhwb3J0T3B0aW9ucy5jb25zdHJdKCdjb250YWluZXInLCBmaW5hbE9wdGlvbnMsIGZpbmFsQ2FsbGJhY2spO1xyXG5cclxuICAvLyBHZXQgdGhlIGN1cnJlbnQgZ2xvYmFsIG9wdGlvbnNcclxuICBjb25zdCBkZWZhdWx0T3B0aW9ucyA9IGdldE9wdGlvbnMoKTtcclxuXHJcbiAgLy8gQ2xlYXIgaXQganVzdCBpbiBjYXNlIChlLmcuIHRoZSBgc2V0T3B0aW9uc2Agd2FzIHVzZWQgaW4gdGhlIGBjdXN0b21Db2RlYClcclxuICBmb3IgKGNvbnN0IHByb3AgaW4gZGVmYXVsdE9wdGlvbnMpIHtcclxuICAgIGlmICh0eXBlb2YgZGVmYXVsdE9wdGlvbnNbcHJvcF0gIT09ICdmdW5jdGlvbicpIHtcclxuICAgICAgZGVsZXRlIGRlZmF1bHRPcHRpb25zW3Byb3BdO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgLy8gU2V0IHRoZSBkZWZhdWx0IG9wdGlvbnMgYmFja1xyXG4gIHNldE9wdGlvbnMoSGlnaGNoYXJ0cy5zZXRPcHRpb25zT2JqKTtcclxuXHJcbiAgLy8gRW1wdHkgdGhlIGN1c3RvbSBnbG9iYWwgb3B0aW9ucyBvYmplY3RcclxuICBIaWdoY2hhcnRzLnNldE9wdGlvbnNPYmogPSB7fTtcclxufVxyXG5cclxuZXhwb3J0IGRlZmF1bHQge1xyXG4gIHNldHVwSGlnaGNoYXJ0cyxcclxuICBjcmVhdGVDaGFydFxyXG59O1xyXG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxyXG5cclxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXHJcblxyXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNSwgSGlnaHNvZnRcclxuXHJcbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cclxuXHJcbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxyXG5cclxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxyXG5cclxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cclxuXHJcbi8qKlxyXG4gKiBAb3ZlcnZpZXcgVGhpcyBtb2R1bGUgcHJvdmlkZXMgZnVuY3Rpb25zIGZvciBtYW5hZ2luZyBQdXBwZXRlZXIgYnJvd3NlclxyXG4gKiBpbnN0YW5jZSwgY3JlYXRpbmcgYW5kIGNsZWFyaW5nIHBhZ2VzLCBpbmplY3RpbmcgY3VzdG9tIHJlc291cmNlcyxcclxuICogYW5kIHNldHRpbmcgdXAgSGlnaGNoYXJ0cyBmb3Igc2VydmVyLXNpZGUgcmVuZGVyaW5nLiBUaGUgbW9kdWxlIGVuc3VyZXNcclxuICogdGhhdCByZXNvdXJjZXMgYXJlIGNvcnJlY3RseSBtYW5hZ2VkIGFuZCBjYW4gaGFuZGxlIGZhaWx1cmVzIGR1cmluZ1xyXG4gKiBvcGVyYXRpb25zIGxpa2UgbGF1bmNoaW5nIHRoZSBicm93c2VyIG9yIGNyZWF0aW5nIG5ldyBwYWdlcy5cclxuICovXHJcblxyXG5pbXBvcnQgeyByZWFkRmlsZVN5bmMgfSBmcm9tICdmcyc7XHJcbmltcG9ydCB7IGpvaW4gfSBmcm9tICdwYXRoJztcclxuXHJcbmltcG9ydCBwdXBwZXRlZXIgZnJvbSAncHVwcGV0ZWVyJztcclxuXHJcbmltcG9ydCB7IGdldENhY2hlUGF0aCB9IGZyb20gJy4vY2FjaGUuanMnO1xyXG5pbXBvcnQgeyBnZXRPcHRpb25zIH0gZnJvbSAnLi9jb25maWcuanMnO1xyXG5pbXBvcnQgeyBzZXR1cEhpZ2hjaGFydHMgfSBmcm9tICcuL2hpZ2hjaGFydHMuanMnO1xyXG5pbXBvcnQgeyBsb2csIGxvZ1dpdGhTdGFjayB9IGZyb20gJy4vbG9nZ2VyLmpzJztcclxuaW1wb3J0IHsgX19kaXJuYW1lLCBnZXRBYnNvbHV0ZVBhdGggfSBmcm9tICcuL3V0aWxzLmpzJztcclxuXHJcbmltcG9ydCBFeHBvcnRFcnJvciBmcm9tICcuL2Vycm9ycy9FeHBvcnRFcnJvci5qcyc7XHJcblxyXG4vLyBHZXQgdGhlIHRlbXBsYXRlIGZvciBwYWdlc1xyXG5jb25zdCB0ZW1wbGF0ZSA9IHJlYWRGaWxlU3luYyhcclxuICBqb2luKF9fZGlybmFtZSwgJ3RlbXBsYXRlcycsICd0ZW1wbGF0ZS5odG1sJyksXHJcbiAgJ3V0ZjgnXHJcbik7XHJcblxyXG4vLyBUbyBzYXZlIHRoZSBicm93c2VyXHJcbmxldCBicm93c2VyID0gbnVsbDtcclxuXHJcbi8qKlxyXG4gKiBSZXRyaWV2ZXMgdGhlIGV4aXN0aW5nIFB1cHBldGVlciBicm93c2VyIGluc3RhbmNlLlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gZ2V0QnJvd3NlclxyXG4gKlxyXG4gKiBAcmV0dXJucyB7T2JqZWN0fSBUaGUgUHVwcGV0ZWVyIGJyb3dzZXIgaW5zdGFuY2UuXHJcbiAqXHJcbiAqIEB0aHJvd3Mge0V4cG9ydEVycm9yfSBUaHJvd3MgYW4gYEV4cG9ydEVycm9yYCBpZiBubyB2YWxpZCBicm93c2VyXHJcbiAqIGhhcyBiZWVuIGNyZWF0ZWQuXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gZ2V0QnJvd3NlcigpIHtcclxuICBpZiAoIWJyb3dzZXIpIHtcclxuICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcignW2Jyb3dzZXJdIE5vIHZhbGlkIGJyb3dzZXIgaGFzIGJlZW4gY3JlYXRlZC4nLCA1MDApO1xyXG4gIH1cclxuICByZXR1cm4gYnJvd3NlcjtcclxufVxyXG5cclxuLyoqXHJcbiAqIENyZWF0ZXMgYSBQdXBwZXRlZXIgYnJvd3NlciBpbnN0YW5jZSB3aXRoIHRoZSBzcGVjaWZpZWQgYXJndW1lbnRzLlxyXG4gKlxyXG4gKiBAYXN5bmNcclxuICogQGZ1bmN0aW9uIGNyZWF0ZUJyb3dzZXJcclxuICpcclxuICogQHBhcmFtIHtBcnJheS48c3RyaW5nPn0gcHVwcGV0ZWVyQXJncyAtIEFkZGl0aW9uYWwgYXJndW1lbnRzIGZvciBQdXBwZXRlZXJcclxuICogbGF1bmNoLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7UHJvbWlzZTxPYmplY3Q+fSBBIFByb21pc2UgdGhhdCByZXNvbHZlcyB0byB0aGUgY3JlYXRlZCBQdXBwZXRlZXJcclxuICogYnJvd3NlciBpbnN0YW5jZS5cclxuICpcclxuICogQHRocm93cyB7RXhwb3J0RXJyb3J9IFRocm93cyBhbiBgRXhwb3J0RXJyb3JgIGlmIG1heCByZXRyaWVzIHRvIG9wZW5cclxuICogYSBicm93c2VyIGluc3RhbmNlIGFyZSByZWFjaGVkLCBvciBpZiBubyBicm93c2VyIGluc3RhbmNlIGlzIGZvdW5kIGFmdGVyXHJcbiAqIHJldHJpZXMuXHJcbiAqL1xyXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gY3JlYXRlQnJvd3NlcihwdXBwZXRlZXJBcmdzKSB7XHJcbiAgLy8gR2V0IGBkZWJ1Z2AgYW5kIGBvdGhlcmAgb3B0aW9uc1xyXG4gIGNvbnN0IHsgZGVidWcsIG90aGVyIH0gPSBnZXRPcHRpb25zKCk7XHJcblxyXG4gIC8vIEdldCB0aGUgYGRlYnVnYCBvcHRpb25zXHJcbiAgY29uc3QgeyBlbmFibGU6IGVuYWJsZWREZWJ1ZywgLi4uZGVidWdPcHRpb25zIH0gPSBkZWJ1ZztcclxuXHJcbiAgLy8gTGF1bmNoIG9wdGlvbnMgZm9yIHRoZSBicm93c2VyIGluc3RhbmNlXHJcbiAgY29uc3QgbGF1bmNoT3B0aW9ucyA9IHtcclxuICAgIGhlYWRsZXNzOiBvdGhlci5icm93c2VyU2hlbGxNb2RlID8gJ3NoZWxsJyA6IHRydWUsXHJcbiAgICB1c2VyRGF0YURpcjogJ3RtcCcsXHJcbiAgICBhcmdzOiBwdXBwZXRlZXJBcmdzIHx8IFtdLFxyXG4gICAgaGFuZGxlU0lHSU5UOiBmYWxzZSxcclxuICAgIGhhbmRsZVNJR1RFUk06IGZhbHNlLFxyXG4gICAgaGFuZGxlU0lHSFVQOiBmYWxzZSxcclxuICAgIHdhaXRGb3JJbml0aWFsUGFnZTogZmFsc2UsXHJcbiAgICBkZWZhdWx0Vmlld3BvcnQ6IG51bGwsXHJcbiAgICAuLi4oZW5hYmxlZERlYnVnICYmIGRlYnVnT3B0aW9ucylcclxuICB9O1xyXG5cclxuICAvLyBDcmVhdGUgYSBicm93c2VyXHJcbiAgaWYgKCFicm93c2VyKSB7XHJcbiAgICAvLyBBIGNvdW50ZXIgZm9yIHRoZSBicm93c2VyJ3MgbGF1bmNoIHJldHJpZXNcclxuICAgIGxldCB0cnlDb3VudCA9IDA7XHJcblxyXG4gICAgY29uc3Qgb3BlbiA9IGFzeW5jICgpID0+IHtcclxuICAgICAgdHJ5IHtcclxuICAgICAgICBsb2coXHJcbiAgICAgICAgICAzLFxyXG4gICAgICAgICAgYFticm93c2VyXSBBdHRlbXB0aW5nIHRvIGdldCBhIGJyb3dzZXIgaW5zdGFuY2UgKHRyeSAkeysrdHJ5Q291bnR9KS5gXHJcbiAgICAgICAgKTtcclxuXHJcbiAgICAgICAgLy8gTGF1bmNoIHRoZSBicm93c2VyXHJcbiAgICAgICAgYnJvd3NlciA9IGF3YWl0IHB1cHBldGVlci5sYXVuY2gobGF1bmNoT3B0aW9ucyk7XHJcbiAgICAgIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICAgICAgbG9nV2l0aFN0YWNrKFxyXG4gICAgICAgICAgMSxcclxuICAgICAgICAgIGVycm9yLFxyXG4gICAgICAgICAgJ1ticm93c2VyXSBGYWlsZWQgdG8gbGF1bmNoIGEgYnJvd3NlciBpbnN0YW5jZS4nXHJcbiAgICAgICAgKTtcclxuXHJcbiAgICAgICAgLy8gUmV0cnkgdG8gbGF1bmNoIGJyb3dzZXIgdW50aWwgcmVhY2hpbmcgbWF4IGF0dGVtcHRzXHJcbiAgICAgICAgaWYgKHRyeUNvdW50IDwgMjUpIHtcclxuICAgICAgICAgIGxvZygzLCBgW2Jyb3dzZXJdIFJldHJ5IHRvIG9wZW4gYSBicm93c2VyICgke3RyeUNvdW50fSBvdXQgb2YgMjUpLmApO1xyXG5cclxuICAgICAgICAgIC8vIFdhaXQgZm9yIGEgNCBzZWNvbmRzIGJlZm9yZSB0cnlpbmcgYWdhaW5cclxuICAgICAgICAgIGF3YWl0IG5ldyBQcm9taXNlKChyZXNwb25zZSkgPT4gc2V0VGltZW91dChyZXNwb25zZSwgNDAwMCkpO1xyXG4gICAgICAgICAgYXdhaXQgb3BlbigpO1xyXG4gICAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgICB0aHJvdyBlcnJvcjtcclxuICAgICAgICB9XHJcbiAgICAgIH1cclxuICAgIH07XHJcblxyXG4gICAgdHJ5IHtcclxuICAgICAgYXdhaXQgb3BlbigpO1xyXG5cclxuICAgICAgLy8gU2hlbGwgbW9kZSBpbmZvcm1cclxuICAgICAgaWYgKGxhdW5jaE9wdGlvbnMuaGVhZGxlc3MgPT09ICdzaGVsbCcpIHtcclxuICAgICAgICBsb2coMywgYFticm93c2VyXSBMYXVuY2hlZCBicm93c2VyIGluIHNoZWxsIG1vZGUuYCk7XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIC8vIERlYnVnIG1vZGUgaW5mb3JtXHJcbiAgICAgIGlmIChlbmFibGVkRGVidWcpIHtcclxuICAgICAgICBsb2coMywgYFticm93c2VyXSBMYXVuY2hlZCBicm93c2VyIGluIGRlYnVnIG1vZGUuYCk7XHJcbiAgICAgIH1cclxuICAgIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcihcclxuICAgICAgICAnW2Jyb3dzZXJdIE1heGltdW0gcmV0cmllcyB0byBvcGVuIGEgYnJvd3NlciBpbnN0YW5jZSByZWFjaGVkLicsXHJcbiAgICAgICAgNTAwXHJcbiAgICAgICkuc2V0RXJyb3IoZXJyb3IpO1xyXG4gICAgfVxyXG5cclxuICAgIGlmICghYnJvd3Nlcikge1xyXG4gICAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoJ1ticm93c2VyXSBDYW5ub3QgZmluZCBhIGJyb3dzZXIgdG8gb3Blbi4nLCA1MDApO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgLy8gUmV0dXJuIGEgYnJvd3NlciBpbnN0YW5jZVxyXG4gIHJldHVybiBicm93c2VyO1xyXG59XHJcblxyXG4vKipcclxuICogQ2xvc2VzIHRoZSBQdXBwZXRlZXIgYnJvd3NlciBpbnN0YW5jZSBpZiBpdCBpcyBjb25uZWN0ZWQuXHJcbiAqXHJcbiAqIEBhc3luY1xyXG4gKiBAZnVuY3Rpb24gY2xvc2VCcm93c2VyXHJcbiAqL1xyXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gY2xvc2VCcm93c2VyKCkge1xyXG4gIC8vIENsb3NlIHRoZSBicm93c2VyIHdoZW4gY29ubmVjdGVkXHJcbiAgaWYgKGJyb3dzZXIgJiYgYnJvd3Nlci5jb25uZWN0ZWQpIHtcclxuICAgIGF3YWl0IGJyb3dzZXIuY2xvc2UoKTtcclxuICB9XHJcbiAgYnJvd3NlciA9IG51bGw7XHJcbiAgbG9nKDQsICdbYnJvd3Nlcl0gQ2xvc2VkIHRoZSBicm93c2VyLicpO1xyXG59XHJcblxyXG4vKipcclxuICogQ3JlYXRlcyBhIG5ldyBQdXBwZXRlZXIgcGFnZSB3aXRoaW4gYW4gZXhpc3RpbmcgYnJvd3NlciBpbnN0YW5jZS5cclxuICogVGhlIGZ1bmN0aW9uIGNyZWF0ZXMgYSBuZXcgcGFnZSwgZGlzYWJsZXMgY2FjaGluZywgc2V0cyBjb250ZW50IHVzaW5nXHJcbiAqIHRoZSBgX3NldFBhZ2VDb250ZW50KClgLCBhbmQgcmV0dXJucyB0aGUgY3JlYXRlZCBQdXBwZXRlZXIgcGFnZS5cclxuICpcclxuICogQGFzeW5jXHJcbiAqIEBmdW5jdGlvbiBuZXdQYWdlXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBwb29sUmVzb3VyY2UgLSBUaGUgcG9vbCByZXNvdXJjZSB0aGF0IGNvbnRhaW5zIGBpZGAsXHJcbiAqIGB3b3JrQ291bnRgLCBhbmQgYHBhZ2VgLlxyXG4gKlxyXG4gKiBAdGhyb3dzIHtFeHBvcnRFcnJvcn0gVGhyb3dzIGFuIGBFeHBvcnRFcnJvcmAgaWYgbm8gdmFsaWQgYnJvd3NlclxyXG4gKiBoYXMgYmVlbiBjb25uZWN0ZWQgb3IgaWYgYSBwYWdlIGlzIGludmFsaWQgb3IgY2xvc2VkLlxyXG4gKi9cclxuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIG5ld1BhZ2UocG9vbFJlc291cmNlKSB7XHJcbiAgLy8gRXJyb3IgaW4gY2FzZSBvZiBubyBjb25uZWN0ZWQgYnJvd3NlclxyXG4gIGlmICghYnJvd3NlciB8fCAhYnJvd3Nlci5jb25uZWN0ZWQpIHtcclxuICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcihgW2Jyb3dzZXJdIEJyb3dzZXIgaXMgbm90IHlldCBjb25uZWN0ZWQuYCwgNTAwKTtcclxuICB9XHJcblxyXG4gIC8vIENyZWF0ZSBhIHBhZ2VcclxuICBwb29sUmVzb3VyY2UucGFnZSA9IGF3YWl0IGJyb3dzZXIubmV3UGFnZSgpO1xyXG5cclxuICAvLyBEaXNhYmxlIGNhY2hlXHJcbiAgYXdhaXQgcG9vbFJlc291cmNlLnBhZ2Uuc2V0Q2FjaGVFbmFibGVkKGZhbHNlKTtcclxuXHJcbiAgLy8gU2V0IHRoZSBjb250ZW50XHJcbiAgYXdhaXQgX3NldFBhZ2VDb250ZW50KHBvb2xSZXNvdXJjZS5wYWdlKTtcclxuXHJcbiAgLy8gU2V0IHBhZ2UgZXZlbnRzXHJcbiAgX3NldFBhZ2VFdmVudHMocG9vbFJlc291cmNlLnBhZ2UpO1xyXG5cclxuICAvLyBDaGVjayBpZiB0aGUgcGFnZSBpcyBjb3JyZWN0bHkgY3JlYXRlZFxyXG4gIGlmICghcG9vbFJlc291cmNlLnBhZ2UgfHwgcG9vbFJlc291cmNlLnBhZ2UuaXNDbG9zZWQoKSkge1xyXG4gICAgdGhyb3cgbmV3IEV4cG9ydEVycm9yKCdbYnJvd3Nlcl0gVGhlIHBhZ2UgaXMgaW52YWxpZCBvciBjbG9zZWQuJywgNDAwKTtcclxuICB9XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBDbGVhcnMgdGhlIGNvbnRlbnQgb2YgYSBQdXBwZXRlZXIgUGFnZSBiYXNlZCBvbiB0aGUgc3BlY2lmaWVkIG1vZGUuIExvZ3NcclxuICogdGhyb3duIGVycm9yIGlmIGNsZWFyaW5nIG9mIGEgcGFnZSdzIGNvbnRlbnQgZmFpbHMuXHJcbiAqXHJcbiAqIEBhc3luY1xyXG4gKiBAZnVuY3Rpb24gY2xlYXJQYWdlXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBwb29sUmVzb3VyY2UgLSBUaGUgcG9vbCByZXNvdXJjZSB0aGF0IGNvbnRhaW5zIHBhZ2UgYW5kIGlkLlxyXG4gKiBAcGFyYW0ge2Jvb2xlYW59IFtoYXJkUmVzZXQ9ZmFsc2VdIC0gQSBmbGFnIGluZGljYXRpbmcgdGhlIHR5cGUgb2YgY2xlYXJpbmdcclxuICogdG8gYmUgcGVyZm9ybWVkLiBJZiB0cnVlLCBuYXZpZ2F0ZXMgdG8gYGFib3V0OmJsYW5rYCBhbmQgcmVzZXRzIGNvbnRlbnRcclxuICogYW5kIHNjcmlwdHMuIElmIGZhbHNlLCBjbGVhcnMgdGhlIGJvZHkgY29udGVudCBieSBzZXR0aW5nIGEgcHJlZGVmaW5lZCBIVE1MXHJcbiAqIHN0cnVjdHVyZS4gVGhlIGRlZmF1bHQgdmFsdWUgaXMgYGZhbHNlYC5cclxuICpcclxuICogQHJldHVybnMge1Byb21pc2U8Ym9vbGVhbj59IEEgUHJvbWlzZSB0aGF0IHJlc29sdmVzIHRvIHRydWUgd2hlbiBwYWdlXHJcbiAqIGlzIGNvcnJlY3RseSBjbGVhcmVkIGFuZCBmYWxzZSB3aGVuIGl0IGlzIG5vdC5cclxuICovXHJcbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBjbGVhclBhZ2UocG9vbFJlc291cmNlLCBoYXJkUmVzZXQgPSBmYWxzZSkge1xyXG4gIHRyeSB7XHJcbiAgICBpZiAocG9vbFJlc291cmNlLnBhZ2UgJiYgIXBvb2xSZXNvdXJjZS5wYWdlLmlzQ2xvc2VkKCkpIHtcclxuICAgICAgaWYgKGhhcmRSZXNldCkge1xyXG4gICAgICAgIC8vIE5hdmlnYXRlIHRvIGBhYm91dDpibGFua2BcclxuICAgICAgICBhd2FpdCBwb29sUmVzb3VyY2UucGFnZS5nb3RvKCdhYm91dDpibGFuaycsIHtcclxuICAgICAgICAgIHdhaXRVbnRpbDogJ2RvbWNvbnRlbnRsb2FkZWQnXHJcbiAgICAgICAgfSk7XHJcblxyXG4gICAgICAgIC8vIFNldCB0aGUgY29udGVudCBhbmQgYW5kIHNjcmlwdHMgYWdhaW5cclxuICAgICAgICBhd2FpdCBfc2V0UGFnZUNvbnRlbnQocG9vbFJlc291cmNlLnBhZ2UpO1xyXG4gICAgICB9IGVsc2Uge1xyXG4gICAgICAgIC8vIENsZWFyIGJvZHkgY29udGVudFxyXG4gICAgICAgIGF3YWl0IHBvb2xSZXNvdXJjZS5wYWdlLmV2YWx1YXRlKCgpID0+IHtcclxuICAgICAgICAgIGRvY3VtZW50LmJvZHkuaW5uZXJIVE1MID1cclxuICAgICAgICAgICAgJzxkaXYgaWQ9XCJjaGFydC1jb250YWluZXJcIj48ZGl2IGlkPVwiY29udGFpbmVyXCI+PC9kaXY+PC9kaXY+JztcclxuICAgICAgICB9KTtcclxuICAgICAgfVxyXG4gICAgICByZXR1cm4gdHJ1ZTtcclxuICAgIH1cclxuICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgbG9nV2l0aFN0YWNrKFxyXG4gICAgICAyLFxyXG4gICAgICBlcnJvcixcclxuICAgICAgYFtwb29sXSBQb29sIHJlc291cmNlIFske3Bvb2xSZXNvdXJjZS5pZH1dIC0gQ29udGVudCBvZiB0aGUgcGFnZSBjb3VsZCBub3QgYmUgY2xlYXJlZC5gXHJcbiAgICApO1xyXG5cclxuICAgIC8vIFNldCB0aGUgYHdvcmtMaW1pdGAgdG8gZXhjZWVkZWQgaW4gb3JkZXIgdG8gcmVjcmVhdGUgdGhlIHJlc291cmNlXHJcbiAgICBwb29sUmVzb3VyY2Uud29ya0NvdW50ID0gZ2V0T3B0aW9ucygpLnBvb2wud29ya0xpbWl0ICsgMTtcclxuICB9XHJcbiAgcmV0dXJuIGZhbHNlO1xyXG59XHJcblxyXG4vKipcclxuICogQWRkcyBjdXN0b20gSlMgYW5kIENTUyByZXNvdXJjZXMgdG8gYSBQdXBwZXRlZXIgUGFnZSBiYXNlZCBvbiB0aGUgc3BlY2lmaWVkXHJcbiAqIG9wdGlvbnMuXHJcbiAqXHJcbiAqIEBhc3luY1xyXG4gKiBAZnVuY3Rpb24gYWRkUGFnZVJlc291cmNlc1xyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gcGFnZSAtIFRoZSBQdXBwZXRlZXIgcGFnZSBvYmplY3QgdG8gd2hpY2ggcmVzb3VyY2VzIHdpbGxcclxuICogYmUgYWRkZWQuXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBjdXN0b21Mb2dpY09wdGlvbnMgLSBUaGUgY29uZmlndXJhdGlvbiBvYmplY3QgY29udGFpbmluZ1xyXG4gKiBgY3VzdG9tTG9naWNgIG9wdGlvbnMuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtQcm9taXNlPEFycmF5LjxPYmplY3Q+Pn0gQSBQcm9taXNlIHRoYXQgcmVzb2x2ZXMgdG8gYW4gYXJyYXlcclxuICogb2YgaW5qZWN0ZWQgcmVzb3VyY2VzLlxyXG4gKi9cclxuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIGFkZFBhZ2VSZXNvdXJjZXMocGFnZSwgY3VzdG9tTG9naWNPcHRpb25zKSB7XHJcbiAgLy8gSW5qZWN0ZWQgcmVzb3VyY2VzIGFycmF5XHJcbiAgY29uc3QgaW5qZWN0ZWRSZXNvdXJjZXMgPSBbXTtcclxuXHJcbiAgLy8gVXNlIHJlc291cmNlc1xyXG4gIGNvbnN0IHJlc291cmNlcyA9IGN1c3RvbUxvZ2ljT3B0aW9ucy5yZXNvdXJjZXM7XHJcbiAgaWYgKHJlc291cmNlcykge1xyXG4gICAgY29uc3QgaW5qZWN0ZWRKcyA9IFtdO1xyXG5cclxuICAgIC8vIExvYWQgY3VzdG9tIEpTIGNvZGVcclxuICAgIGlmIChyZXNvdXJjZXMuanMpIHtcclxuICAgICAgaW5qZWN0ZWRKcy5wdXNoKHtcclxuICAgICAgICBjb250ZW50OiByZXNvdXJjZXMuanNcclxuICAgICAgfSk7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gTG9hZCBzY3JpcHRzIGZyb20gYWxsIGN1c3RvbSBmaWxlc1xyXG4gICAgaWYgKHJlc291cmNlcy5maWxlcykge1xyXG4gICAgICBmb3IgKGNvbnN0IGZpbGUgb2YgcmVzb3VyY2VzLmZpbGVzKSB7XHJcbiAgICAgICAgY29uc3QgaXNMb2NhbCA9IGZpbGUuc3RhcnRzV2l0aCgnaHR0cCcpID8gZmFsc2UgOiB0cnVlO1xyXG5cclxuICAgICAgICAvLyBBZGQgZWFjaCBjdXN0b20gc2NyaXB0IGZyb20gcmVzb3VyY2VzJyBmaWxlc1xyXG4gICAgICAgIGluamVjdGVkSnMucHVzaChcclxuICAgICAgICAgIGlzTG9jYWxcclxuICAgICAgICAgICAgPyB7XHJcbiAgICAgICAgICAgICAgICBjb250ZW50OiByZWFkRmlsZVN5bmMoZ2V0QWJzb2x1dGVQYXRoKGZpbGUpLCAndXRmOCcpXHJcbiAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICA6IHtcclxuICAgICAgICAgICAgICAgIHVybDogZmlsZVxyXG4gICAgICAgICAgICAgIH1cclxuICAgICAgICApO1xyXG4gICAgICB9XHJcbiAgICB9XHJcblxyXG4gICAgZm9yIChjb25zdCBqc1Jlc291cmNlIG9mIGluamVjdGVkSnMpIHtcclxuICAgICAgdHJ5IHtcclxuICAgICAgICBpbmplY3RlZFJlc291cmNlcy5wdXNoKGF3YWl0IHBhZ2UuYWRkU2NyaXB0VGFnKGpzUmVzb3VyY2UpKTtcclxuICAgICAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICAgICBsb2dXaXRoU3RhY2soMiwgZXJyb3IsIGBbYnJvd3Nlcl0gVGhlIEpTIHJlc291cmNlIGNhbm5vdCBiZSBsb2FkZWQuYCk7XHJcbiAgICAgIH1cclxuICAgIH1cclxuICAgIGluamVjdGVkSnMubGVuZ3RoID0gMDtcclxuXHJcbiAgICAvLyBMb2FkIENTU1xyXG4gICAgY29uc3QgaW5qZWN0ZWRDc3MgPSBbXTtcclxuICAgIGlmIChyZXNvdXJjZXMuY3NzKSB7XHJcbiAgICAgIGxldCBjc3NJbXBvcnRzID0gcmVzb3VyY2VzLmNzcy5tYXRjaCgvQGltcG9ydFxccyooW147XSopOy9nKTtcclxuICAgICAgaWYgKGNzc0ltcG9ydHMpIHtcclxuICAgICAgICAvLyBIYW5kbGUgY3NzIHNlY3Rpb25cclxuICAgICAgICBmb3IgKGxldCBjc3NJbXBvcnRQYXRoIG9mIGNzc0ltcG9ydHMpIHtcclxuICAgICAgICAgIGlmIChjc3NJbXBvcnRQYXRoKSB7XHJcbiAgICAgICAgICAgIGNzc0ltcG9ydFBhdGggPSBjc3NJbXBvcnRQYXRoXHJcbiAgICAgICAgICAgICAgLnJlcGxhY2UoJ3VybCgnLCAnJylcclxuICAgICAgICAgICAgICAucmVwbGFjZSgnQGltcG9ydCcsICcnKVxyXG4gICAgICAgICAgICAgIC5yZXBsYWNlKC9cIi9nLCAnJylcclxuICAgICAgICAgICAgICAucmVwbGFjZSgvJy9nLCAnJylcclxuICAgICAgICAgICAgICAucmVwbGFjZSgvOy8sICcnKVxyXG4gICAgICAgICAgICAgIC5yZXBsYWNlKC9cXCkvZywgJycpXHJcbiAgICAgICAgICAgICAgLnRyaW0oKTtcclxuXHJcbiAgICAgICAgICAgIC8vIEFkZCBlYWNoIGN1c3RvbSBjc3MgZnJvbSByZXNvdXJjZXNcclxuICAgICAgICAgICAgaWYgKGNzc0ltcG9ydFBhdGguc3RhcnRzV2l0aCgnaHR0cCcpKSB7XHJcbiAgICAgICAgICAgICAgaW5qZWN0ZWRDc3MucHVzaCh7XHJcbiAgICAgICAgICAgICAgICB1cmw6IGNzc0ltcG9ydFBhdGhcclxuICAgICAgICAgICAgICB9KTtcclxuICAgICAgICAgICAgfSBlbHNlIGlmIChjdXN0b21Mb2dpY09wdGlvbnMuYWxsb3dGaWxlUmVzb3VyY2VzKSB7XHJcbiAgICAgICAgICAgICAgaW5qZWN0ZWRDc3MucHVzaCh7XHJcbiAgICAgICAgICAgICAgICBwYXRoOiBnZXRBYnNvbHV0ZVBhdGgoY3NzSW1wb3J0UGF0aClcclxuICAgICAgICAgICAgICB9KTtcclxuICAgICAgICAgICAgfVxyXG4gICAgICAgICAgfVxyXG4gICAgICAgIH1cclxuICAgICAgfVxyXG5cclxuICAgICAgLy8gVGhlIHJlc3Qgb2YgdGhlIENTUyBzZWN0aW9uIHdpbGwgYmUgY29udGVudCBieSBub3dcclxuICAgICAgaW5qZWN0ZWRDc3MucHVzaCh7XHJcbiAgICAgICAgY29udGVudDogcmVzb3VyY2VzLmNzcy5yZXBsYWNlKC9AaW1wb3J0XFxzKihbXjtdKik7L2csICcnKSB8fCAnICdcclxuICAgICAgfSk7XHJcblxyXG4gICAgICBmb3IgKGNvbnN0IGNzc1Jlc291cmNlIG9mIGluamVjdGVkQ3NzKSB7XHJcbiAgICAgICAgdHJ5IHtcclxuICAgICAgICAgIGluamVjdGVkUmVzb3VyY2VzLnB1c2goYXdhaXQgcGFnZS5hZGRTdHlsZVRhZyhjc3NSZXNvdXJjZSkpO1xyXG4gICAgICAgIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICAgICAgICBsb2dXaXRoU3RhY2soXHJcbiAgICAgICAgICAgIDIsXHJcbiAgICAgICAgICAgIGVycm9yLFxyXG4gICAgICAgICAgICBgW2Jyb3dzZXJdIFRoZSBDU1MgcmVzb3VyY2UgY2Fubm90IGJlIGxvYWRlZC5gXHJcbiAgICAgICAgICApO1xyXG4gICAgICAgIH1cclxuICAgICAgfVxyXG4gICAgICBpbmplY3RlZENzcy5sZW5ndGggPSAwO1xyXG4gICAgfVxyXG4gIH1cclxuICByZXR1cm4gaW5qZWN0ZWRSZXNvdXJjZXM7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBDbGVhcnMgb3V0IGFsbCBzdGF0ZSBzZXQgb24gdGhlIHBhZ2Ugd2l0aCBgYWRkU2NyaXB0VGFnYCBhbmQgYGFkZFN0eWxlVGFnYC5cclxuICogUmVtb3ZlcyBpbmplY3RlZCByZXNvdXJjZXMgYW5kIHJlc2V0cyBDU1MgYW5kIHNjcmlwdCB0YWdzIG9uIHRoZSBwYWdlLlxyXG4gKiBBZGRpdGlvbmFsbHksIGl0IGRlc3Ryb3lzIHByZXZpb3VzbHkgZXhpc3RpbmcgY2hhcnRzLlxyXG4gKlxyXG4gKiBAYXN5bmNcclxuICogQGZ1bmN0aW9uIGNsZWFyUGFnZVJlc291cmNlc1xyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gcGFnZSAtIFRoZSBQdXBwZXRlZXIgcGFnZSBvYmplY3QgZnJvbSB3aGljaCByZXNvdXJjZXMgd2lsbFxyXG4gKiBiZSBjbGVhcmVkLlxyXG4gKiBAcGFyYW0ge0FycmF5LjxPYmplY3Q+fSBpbmplY3RlZFJlc291cmNlcyAtIEFycmF5IG9mIGluamVjdGVkIHJlc291cmNlc1xyXG4gKiB0byBiZSBjbGVhcmVkLlxyXG4gKi9cclxuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIGNsZWFyUGFnZVJlc291cmNlcyhwYWdlLCBpbmplY3RlZFJlc291cmNlcykge1xyXG4gIHRyeSB7XHJcbiAgICBmb3IgKGNvbnN0IHJlc291cmNlIG9mIGluamVjdGVkUmVzb3VyY2VzKSB7XHJcbiAgICAgIGF3YWl0IHJlc291cmNlLmRpc3Bvc2UoKTtcclxuICAgIH1cclxuXHJcbiAgICAvLyBEZXN0cm95IG9sZCBjaGFydHMgYWZ0ZXIgZXhwb3J0IGlzIGRvbmUgYW5kIHJlc2V0IGFsbCBDU1MgYW5kIHNjcmlwdCB0YWdzXHJcbiAgICBhd2FpdCBwYWdlLmV2YWx1YXRlKCgpID0+IHtcclxuICAgICAgLy8gV2UgYXJlIG5vdCBndWFyYW50ZWVkIHRoYXQgSGlnaGNoYXJ0cyBpcyBsb2FkZWQsIHdoZW4gZG9pbmcgU1ZHIGV4cG9ydHNcclxuICAgICAgaWYgKHR5cGVvZiBIaWdoY2hhcnRzICE9PSAndW5kZWZpbmVkJykge1xyXG4gICAgICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBuby11bmRlZlxyXG4gICAgICAgIGNvbnN0IG9sZENoYXJ0cyA9IEhpZ2hjaGFydHMuY2hhcnRzO1xyXG5cclxuICAgICAgICAvLyBDaGVjayBpbiBhbnkgYWxyZWFkeSBleGlzdGluZyBjaGFydHNcclxuICAgICAgICBpZiAoQXJyYXkuaXNBcnJheShvbGRDaGFydHMpICYmIG9sZENoYXJ0cy5sZW5ndGgpIHtcclxuICAgICAgICAgIC8vIERlc3Ryb3kgb2xkIGNoYXJ0c1xyXG4gICAgICAgICAgZm9yIChjb25zdCBvbGRDaGFydCBvZiBvbGRDaGFydHMpIHtcclxuICAgICAgICAgICAgb2xkQ2hhcnQgJiYgb2xkQ2hhcnQuZGVzdHJveSgpO1xyXG4gICAgICAgICAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgbm8tdW5kZWZcclxuICAgICAgICAgICAgSGlnaGNoYXJ0cy5jaGFydHMuc2hpZnQoKTtcclxuICAgICAgICAgIH1cclxuICAgICAgICB9XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBuby11bmRlZlxyXG4gICAgICBjb25zdCBbLi4uc2NyaXB0c1RvUmVtb3ZlXSA9IGRvY3VtZW50LmdldEVsZW1lbnRzQnlUYWdOYW1lKCdzY3JpcHQnKTtcclxuICAgICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIG5vLXVuZGVmXHJcbiAgICAgIGNvbnN0IFssIC4uLnN0eWxlc1RvUmVtb3ZlXSA9IGRvY3VtZW50LmdldEVsZW1lbnRzQnlUYWdOYW1lKCdzdHlsZScpO1xyXG4gICAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgbm8tdW5kZWZcclxuICAgICAgY29uc3QgWy4uLmxpbmtzVG9SZW1vdmVdID0gZG9jdW1lbnQuZ2V0RWxlbWVudHNCeVRhZ05hbWUoJ2xpbmsnKTtcclxuXHJcbiAgICAgIC8vIFJlbW92ZSB0YWdzXHJcbiAgICAgIGZvciAoY29uc3QgZWxlbWVudCBvZiBbXHJcbiAgICAgICAgLi4uc2NyaXB0c1RvUmVtb3ZlLFxyXG4gICAgICAgIC4uLnN0eWxlc1RvUmVtb3ZlLFxyXG4gICAgICAgIC4uLmxpbmtzVG9SZW1vdmVcclxuICAgICAgXSkge1xyXG4gICAgICAgIGVsZW1lbnQucmVtb3ZlKCk7XHJcbiAgICAgIH1cclxuICAgIH0pO1xyXG4gIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICBsb2dXaXRoU3RhY2soMiwgZXJyb3IsIGBbYnJvd3Nlcl0gQ291bGQgbm90IGNsZWFyIHBhZ2UncyByZXNvdXJjZXMuYCk7XHJcbiAgfVxyXG59XHJcblxyXG4vKipcclxuICogU2V0cyB0aGUgY29udGVudCBmb3IgYSBQdXBwZXRlZXIgUGFnZSB1c2luZyBhIHByZWRlZmluZWQgdGVtcGxhdGVcclxuICogYW5kIGFkZGl0aW9uYWwgc2NyaXB0cy5cclxuICpcclxuICogQGFzeW5jXHJcbiAqIEBmdW5jdGlvbiBfc2V0UGFnZUNvbnRlbnRcclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IHBhZ2UgLSBUaGUgUHVwcGV0ZWVyIHBhZ2Ugb2JqZWN0IHRvIHdoaWNoIHRoZSBjb250ZW50XHJcbiAqIGlzIGJlaW5nIHNldC5cclxuICovXHJcbmFzeW5jIGZ1bmN0aW9uIF9zZXRQYWdlQ29udGVudChwYWdlKSB7XHJcbiAgLy8gU2V0IHRoZSBpbml0aWFsIHBhZ2UgY29udGVudFxyXG4gIGF3YWl0IHBhZ2Uuc2V0Q29udGVudCh0ZW1wbGF0ZSwgeyB3YWl0VW50aWw6ICdkb21jb250ZW50bG9hZGVkJyB9KTtcclxuXHJcbiAgLy8gQWRkIGFsbCByZWdpc3RlcmVkIEhpZ2NoYXJ0cyBzY3JpcHRzLCBxdWl0ZSBkZW1hbmRpbmdcclxuICBhd2FpdCBwYWdlLmFkZFNjcmlwdFRhZyh7IHBhdGg6IGpvaW4oZ2V0Q2FjaGVQYXRoKCksICdzb3VyY2VzLmpzJykgfSk7XHJcblxyXG4gIC8vIFNldCB0aGUgaW5pdGlhbCBgYW5pbU9iamVjdGAgZm9yIEhpZ2hjaGFydHNcclxuICBhd2FpdCBwYWdlLmV2YWx1YXRlKHNldHVwSGlnaGNoYXJ0cyk7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBTZXQgZXZlbnRzIChsaWtlIGBwYWdlZXJyb3JgIGFuZCBgY29uc29sZWApIGZvciBhIFB1cHBldGVlciBQYWdlIGluIG9yZGVyXHJcbiAqIHRvIGNhdGNoIGFuZCBkaXNwbGF5IGVycm9ycyBhbmQgY29uc29sZSBsb2dzIGZyb20gdGhlIHdpbmRvdyBjb250ZXh0LlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gX3NldFBhZ2VFdmVudHNcclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IHBhZ2UgLSBUaGUgUHVwcGV0ZWVyIHBhZ2Ugb2JqZWN0IHRvIHdoaWNoIHRoZSBsaXN0ZW5lcnNcclxuICogYXJlIGJlaW5nIHNldC5cclxuICovXHJcbmZ1bmN0aW9uIF9zZXRQYWdlRXZlbnRzKHBhZ2UpIHtcclxuICAvLyBHZXQgYGRlYnVnYCBvcHRpb25zXHJcbiAgY29uc3QgeyBkZWJ1ZyB9ID0gZ2V0T3B0aW9ucygpO1xyXG5cclxuICAvLyBTZXQgdGhlIGBwYWdlZXJyb3JgIGxpc3RlbmVyXHJcbiAgcGFnZS5vbigncGFnZWVycm9yJywgYXN5bmMgKCkgPT4ge1xyXG4gICAgLy8gSXQgd291bGQgc2VlbSBsaWtlIHRoaXMgbWF5IGZpcmUgYXQgdGhlIHNhbWUgdGltZSBvciBzaG9ydGx5IGJlZm9yZVxyXG4gICAgLy8gYSBwYWdlIGlzIGNsb3NlZC5cclxuICAgIGlmIChwYWdlLmlzQ2xvc2VkKCkpIHtcclxuICAgICAgcmV0dXJuO1xyXG4gICAgfVxyXG4gIH0pO1xyXG5cclxuICAvLyBTZXQgdGhlIGBjb25zb2xlYCBsaXN0ZW5lciwgaWYgbmVlZGVkXHJcbiAgaWYgKGRlYnVnLmVuYWJsZSAmJiBkZWJ1Zy5saXN0ZW5Ub0NvbnNvbGUpIHtcclxuICAgIHBhZ2Uub24oJ2NvbnNvbGUnLCAobWVzc2FnZSkgPT4ge1xyXG4gICAgICBjb25zb2xlLmxvZyhgW2RlYnVnXSAke21lc3NhZ2UudGV4dCgpfWApO1xyXG4gICAgfSk7XHJcbiAgfVxyXG59XHJcblxyXG5leHBvcnQgZGVmYXVsdCB7XHJcbiAgZ2V0QnJvd3NlcixcclxuICBjcmVhdGVCcm93c2VyLFxyXG4gIGNsb3NlQnJvd3NlcixcclxuICBuZXdQYWdlLFxyXG4gIGNsZWFyUGFnZSxcclxuICBhZGRQYWdlUmVzb3VyY2VzLFxyXG4gIGNsZWFyUGFnZVJlc291cmNlc1xyXG59O1xyXG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxyXG5cclxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXHJcblxyXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNSwgSGlnaHNvZnRcclxuXHJcbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cclxuXHJcbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxyXG5cclxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxyXG5cclxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cclxuXHJcbi8qKlxyXG4gKiBUaGUgQ1NTIHRvIGJlIHVzZWQgb24gdGhlIGV4cG9ydGVkIHBhZ2UuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtzdHJpbmd9IFRoZSBDU1MgY29uZmlndXJhdGlvbi5cclxuICovXHJcbmV4cG9ydCBkZWZhdWx0ICgpID0+IGBcclxuXHJcbmh0bWwsIGJvZHkge1xyXG4gIG1hcmdpbjogMDtcclxuICBwYWRkaW5nOiAwO1xyXG4gIGJveC1zaXppbmc6IGJvcmRlci1ib3g7XHJcbn1cclxuXHJcbiN0YWJsZS1kaXYsICNzbGlkZXJzLCAjZGF0YXRhYmxlLCAjY29udHJvbHMsIC5sZC1yb3cge1xyXG4gIGRpc3BsYXk6IG5vbmU7XHJcbiAgaGVpZ2h0OiAwO1xyXG59XHJcblxyXG4jY2hhcnQtY29udGFpbmVyIHtcclxuICBib3gtc2l6aW5nOiBib3JkZXItYm94O1xyXG4gIG1hcmdpbjogMDtcclxuICBvdmVyZmxvdzogYXV0bztcclxuICBmb250LXNpemU6IDA7XHJcbn1cclxuXHJcbiNjaGFydC1jb250YWluZXIgPiBmaWd1cmUsIGRpdiB7XHJcbiAgbWFyZ2luLXRvcDogMCAhaW1wb3J0YW50O1xyXG4gIG1hcmdpbi1ib3R0b206IDAgIWltcG9ydGFudDtcclxufVxyXG5cclxuYDtcclxuIiwiLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcclxuXHJcbkhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlclxyXG5cclxuQ29weXJpZ2h0IChjKSAyMDE2LTIwMjUsIEhpZ2hzb2Z0XHJcblxyXG5MaWNlbmNlZCB1bmRlciB0aGUgTUlUIGxpY2VuY2UuXHJcblxyXG5BZGRpdGlvbmFsbHkgYSB2YWxpZCBIaWdoY2hhcnRzIGxpY2Vuc2UgaXMgcmVxdWlyZWQgZm9yIHVzZS5cclxuXHJcblNlZSBMSUNFTlNFIGZpbGUgaW4gcm9vdCBmb3IgZGV0YWlscy5cclxuXHJcbioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXHJcblxyXG5pbXBvcnQgY3NzVGVtcGxhdGUgZnJvbSAnLi9jc3MuanMnO1xyXG5cclxuLyoqXHJcbiAqIFRoZSBTVkcgdGVtcGxhdGUgdG8gdXNlIHdoZW4gbG9hZGluZyBTVkcgY29udGVudCB0byBiZSBleHBvcnRlZC5cclxuICpcclxuICogQHBhcmFtIHtzdHJpbmd9IHN2ZyAtIFRoZSBTVkcgaW5wdXQgY29udGVudCB0byBiZSBleHBvcnRlZC5cclxuICpcclxuICogQHJldHVybnMge3N0cmluZ30gVGhlIFNWRyB0ZW1wbGF0ZS5cclxuICovXHJcbmV4cG9ydCBkZWZhdWx0IChzdmcpID0+IGBcclxuPCFET0NUWVBFIGh0bWw+XHJcbjxodG1sIGxhbmc9J2VuLVVTJz5cclxuICA8aGVhZD5cclxuICAgIDxtZXRhIGh0dHAtZXF1aXY9XCJDb250ZW50LVR5cGVcIiBjb250ZW50PVwidGV4dC9odG1sOyBjaGFyc2V0PXV0Zi04XCI+XHJcbiAgICA8dGl0bGU+SGlnaGNoYXJ0cyBFeHBvcnQ8L3RpdGxlPlxyXG4gIDwvaGVhZD5cclxuICA8c3R5bGU+XHJcbiAgICAke2Nzc1RlbXBsYXRlKCl9XHJcbiAgPC9zdHlsZT5cclxuICA8Ym9keT5cclxuICAgIDxkaXYgaWQ9XCJjaGFydC1jb250YWluZXJcIj5cclxuICAgICAgJHtzdmd9XHJcbiAgICA8L2Rpdj5cclxuICA8L2JvZHk+XHJcbjwvaHRtbD5cclxuXHJcbmA7XHJcbiIsIi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXHJcblxyXG5IaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXJcclxuXHJcbkNvcHlyaWdodCAoYykgMjAxNi0yMDI1LCBIaWdoc29mdFxyXG5cclxuTGljZW5jZWQgdW5kZXIgdGhlIE1JVCBsaWNlbmNlLlxyXG5cclxuQWRkaXRpb25hbGx5IGEgdmFsaWQgSGlnaGNoYXJ0cyBsaWNlbnNlIGlzIHJlcXVpcmVkIGZvciB1c2UuXHJcblxyXG5TZWUgTElDRU5TRSBmaWxlIGluIHJvb3QgZm9yIGRldGFpbHMuXHJcblxyXG4qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xyXG5cclxuLyoqXHJcbiAqIEBvdmVydmlldyBUaGlzIG1vZHVsZSBoYW5kbGVzIGNoYXJ0IGV4cG9ydCBmdW5jdGlvbmFsaXR5IHVzaW5nIFB1cHBldGVlci5cclxuICogSXQgc3VwcG9ydHMgZXhwb3J0aW5nIGNoYXJ0cyBhcyBTVkcsIFBORywgSlBFRywgYW5kIFBERiBmb3JtYXRzLiBUaGUgbW9kdWxlXHJcbiAqIG1hbmFnZXMgcGFnZSByZXNvdXJjZXMsIHNldHMgdXAgdGhlIGV4cG9ydCBlbnZpcm9ubWVudCwgYW5kIHByb2Nlc3NlcyBjaGFydFxyXG4gKiBjb25maWd1cmF0aW9ucyBvciBTVkcgaW5wdXRzIGZvciByZW5kZXJpbmcuIEV4cG9ydHMgdG8gYSBjaGFydCBmcm9tIGEgcGFnZVxyXG4gKiB1c2luZyBQdXBwZXRlZXIuXHJcbiAqL1xyXG5cclxuaW1wb3J0IHsgYWRkUGFnZVJlc291cmNlcywgY2xlYXJQYWdlUmVzb3VyY2VzIH0gZnJvbSAnLi9icm93c2VyLmpzJztcclxuaW1wb3J0IHsgY3JlYXRlQ2hhcnQgfSBmcm9tICcuL2hpZ2hjaGFydHMuanMnO1xyXG5pbXBvcnQgeyBsb2cgfSBmcm9tICcuL2xvZ2dlci5qcyc7XHJcblxyXG5pbXBvcnQgc3ZnVGVtcGxhdGUgZnJvbSAnLi4vdGVtcGxhdGVzL3N2Z0V4cG9ydC9zdmdFeHBvcnQuanMnO1xyXG5cclxuaW1wb3J0IEV4cG9ydEVycm9yIGZyb20gJy4vZXJyb3JzL0V4cG9ydEVycm9yLmpzJztcclxuXHJcbi8qKlxyXG4gKiBFeHBvcnRzIHRvIGEgY2hhcnQgZnJvbSBhIHBhZ2UgdXNpbmcgUHVwcGV0ZWVyLlxyXG4gKlxyXG4gKiBAYXN5bmNcclxuICogQGZ1bmN0aW9uIHB1cHBldGVlckV4cG9ydFxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gcGFnZSAtIFB1cHBldGVlciBwYWdlIG9iamVjdC5cclxuICogQHBhcmFtIHtPYmplY3R9IGV4cG9ydE9wdGlvbnMgLSBUaGUgY29uZmlndXJhdGlvbiBvYmplY3QgY29udGFpbmluZyBgZXhwb3J0YFxyXG4gKiBvcHRpb25zLlxyXG4gKiBAcGFyYW0ge09iamVjdH0gY3VzdG9tTG9naWNPcHRpb25zIC0gVGhlIGNvbmZpZ3VyYXRpb24gb2JqZWN0IGNvbnRhaW5pbmdcclxuICogYGN1c3RvbUxvZ2ljYCBvcHRpb25zLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7UHJvbWlzZTwoc3RyaW5nfEJ1ZmZlcnxFeHBvcnRFcnJvcik+fSBBIFByb21pc2UgdGhhdCByZXNvbHZlc1xyXG4gKiB0byB0aGUgZXhwb3J0ZWQgZGF0YSBvciByZWplY3Rpbmcgd2l0aCBhbiBgRXhwb3J0RXJyb3JgLlxyXG4gKlxyXG4gKiBAdGhyb3dzIHtFeHBvcnRFcnJvcn0gVGhyb3dzIGFuIGBFeHBvcnRFcnJvcmAgaWYgZXhwb3J0IHRvIGFuIHVuc3VwcG9ydGVkXHJcbiAqIG91dHB1dCBmb3JtYXQgb2NjdXJzLlxyXG4gKi9cclxuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIHB1cHBldGVlckV4cG9ydChwYWdlLCBleHBvcnRPcHRpb25zLCBjdXN0b21Mb2dpY09wdGlvbnMpIHtcclxuICAvLyBJbmplY3RlZCByZXNvdXJjZXMgYXJyYXkgKGFkZGl0aW9uYWwgSlMgYW5kIENTUylcclxuICBjb25zdCBpbmplY3RlZFJlc291cmNlcyA9IFtdO1xyXG5cclxuICB0cnkge1xyXG4gICAgbGV0IGlzU1ZHID0gZmFsc2U7XHJcblxyXG4gICAgLy8gRGVjaWRlIG9uIHRoZSBleHBvcnQgbWV0aG9kXHJcbiAgICBpZiAoZXhwb3J0T3B0aW9ucy5zdmcpIHtcclxuICAgICAgbG9nKDQsICdbZXhwb3J0XSBUcmVhdGluZyBhcyBTVkcgaW5wdXQuJyk7XHJcblxyXG4gICAgICAvLyBJZiB0aGUgYHR5cGVgIGlzIGFsc28gU1ZHLCByZXR1cm4gdGhlIGlucHV0XHJcbiAgICAgIGlmIChleHBvcnRPcHRpb25zLnR5cGUgPT09ICdzdmcnKSB7XHJcbiAgICAgICAgcmV0dXJuIGV4cG9ydE9wdGlvbnMuc3ZnO1xyXG4gICAgICB9XHJcblxyXG4gICAgICAvLyBNYXJrIGFzIFNWRyBleHBvcnQgZm9yIHRoZSBsYXRlciBzaXplIGNvcnJlY3Rpb25zXHJcbiAgICAgIGlzU1ZHID0gdHJ1ZTtcclxuXHJcbiAgICAgIC8vIFNWRyBleHBvcnRcclxuICAgICAgYXdhaXQgcGFnZS5zZXRDb250ZW50KHN2Z1RlbXBsYXRlKGV4cG9ydE9wdGlvbnMuc3ZnKSwge1xyXG4gICAgICAgIHdhaXRVbnRpbDogJ2RvbWNvbnRlbnRsb2FkZWQnXHJcbiAgICAgIH0pO1xyXG4gICAgfSBlbHNlIHtcclxuICAgICAgbG9nKDQsICdbZXhwb3J0XSBUcmVhdGluZyBhcyBKU09OIGNvbmZpZy4nKTtcclxuXHJcbiAgICAgIC8vIE9wdGlvbnMgZXhwb3J0XHJcbiAgICAgIGF3YWl0IHBhZ2UuZXZhbHVhdGUoY3JlYXRlQ2hhcnQsIGV4cG9ydE9wdGlvbnMsIGN1c3RvbUxvZ2ljT3B0aW9ucyk7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gS2VlcHMgdHJhY2sgb2YgYWxsIHJlc291cmNlcyBhZGRlZCBvbiB0aGUgcGFnZSB3aXRoIGFkZFhYWFRhZy4gZXRjXHJcbiAgICAvLyBJdCdzIFZJVEFMIHRoYXQgYWxsIGFkZGVkIHJlc291cmNlcyBlbmRzIHVwIGhlcmUgc28gd2UgY2FuIGNsZWFyIHRoaW5nc1xyXG4gICAgLy8gb3V0IHdoZW4gZG9pbmcgYSBuZXcgZXhwb3J0IGluIHRoZSBzYW1lIHBhZ2UhXHJcbiAgICBpbmplY3RlZFJlc291cmNlcy5wdXNoKFxyXG4gICAgICAuLi4oYXdhaXQgYWRkUGFnZVJlc291cmNlcyhwYWdlLCBjdXN0b21Mb2dpY09wdGlvbnMpKVxyXG4gICAgKTtcclxuXHJcbiAgICAvLyBHZXQgdGhlIHJlYWwgY2hhcnQgc2l6ZSBhbmQgc2V0IHRoZSB6b29tIGFjY29yZGluZ2x5XHJcbiAgICBjb25zdCBzaXplID0gaXNTVkdcclxuICAgICAgPyBhd2FpdCBwYWdlLmV2YWx1YXRlKChzY2FsZSkgPT4ge1xyXG4gICAgICAgICAgY29uc3Qgc3ZnRWxlbWVudCA9IGRvY3VtZW50LnF1ZXJ5U2VsZWN0b3IoXHJcbiAgICAgICAgICAgICcjY2hhcnQtY29udGFpbmVyIHN2ZzpmaXJzdC1vZi10eXBlJ1xyXG4gICAgICAgICAgKTtcclxuXHJcbiAgICAgICAgICAvLyBHZXQgdGhlIHZhbHVlcyBjb3JyZWN0bHkgc2NhbGVkXHJcbiAgICAgICAgICBjb25zdCBjaGFydEhlaWdodCA9IHN2Z0VsZW1lbnQuaGVpZ2h0LmJhc2VWYWwudmFsdWUgKiBzY2FsZTtcclxuICAgICAgICAgIGNvbnN0IGNoYXJ0V2lkdGggPSBzdmdFbGVtZW50LndpZHRoLmJhc2VWYWwudmFsdWUgKiBzY2FsZTtcclxuXHJcbiAgICAgICAgICAvLyBJbiBjYXNlIG9mIFNWRyB0aGUgem9vbSBtdXN0IGJlIHNldCBkaXJlY3RseSBmb3IgYm9keSBhcyBzY2FsZVxyXG4gICAgICAgICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIG5vLXVuZGVmXHJcbiAgICAgICAgICBkb2N1bWVudC5ib2R5LnN0eWxlLnpvb20gPSBzY2FsZTtcclxuXHJcbiAgICAgICAgICAvLyBTZXQgdGhlIG1hcmdpbiB0byAwcHhcclxuICAgICAgICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBuby11bmRlZlxyXG4gICAgICAgICAgZG9jdW1lbnQuYm9keS5zdHlsZS5tYXJnaW4gPSAnMHB4JztcclxuXHJcbiAgICAgICAgICByZXR1cm4ge1xyXG4gICAgICAgICAgICBjaGFydEhlaWdodCxcclxuICAgICAgICAgICAgY2hhcnRXaWR0aFxyXG4gICAgICAgICAgfTtcclxuICAgICAgICB9LCBwYXJzZUZsb2F0KGV4cG9ydE9wdGlvbnMuc2NhbGUpKVxyXG4gICAgICA6IGF3YWl0IHBhZ2UuZXZhbHVhdGUoKCkgPT4ge1xyXG4gICAgICAgICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIG5vLXVuZGVmXHJcbiAgICAgICAgICBjb25zdCB7IGNoYXJ0SGVpZ2h0LCBjaGFydFdpZHRoIH0gPSB3aW5kb3cuSGlnaGNoYXJ0cy5jaGFydHNbMF07XHJcblxyXG4gICAgICAgICAgLy8gTm8gbmVlZCBmb3Igc3VjaCBzY2FsZSBtYW5pcHVsYXRpb24gaW4gY2FzZSBvZiBvdGhlciB0eXBlc1xyXG4gICAgICAgICAgLy8gb2YgZXhwb3J0cy4gUmVzZXQgdGhlIHpvb20gZm9yIG90aGVyIGV4cG9ydHMgdGhhbiB0byBTVkdzXHJcbiAgICAgICAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgbm8tdW5kZWZcclxuICAgICAgICAgIGRvY3VtZW50LmJvZHkuc3R5bGUuem9vbSA9IDE7XHJcblxyXG4gICAgICAgICAgcmV0dXJuIHtcclxuICAgICAgICAgICAgY2hhcnRIZWlnaHQsXHJcbiAgICAgICAgICAgIGNoYXJ0V2lkdGhcclxuICAgICAgICAgIH07XHJcbiAgICAgICAgfSk7XHJcblxyXG4gICAgLy8gR2V0IHRoZSBjbGlwIHJlZ2lvbiBmb3IgdGhlIHBhZ2VcclxuICAgIGNvbnN0IHsgeCwgeSB9ID0gYXdhaXQgX2dldENsaXBSZWdpb24ocGFnZSk7XHJcblxyXG4gICAgLy8gU2V0IGZpbmFsIGBoZWlnaHRgIGZvciB2aWV3cG9ydFxyXG4gICAgY29uc3Qgdmlld3BvcnRIZWlnaHQgPSBNYXRoLmFicyhcclxuICAgICAgTWF0aC5jZWlsKHNpemUuY2hhcnRIZWlnaHQgfHwgZXhwb3J0T3B0aW9ucy5oZWlnaHQpXHJcbiAgICApO1xyXG5cclxuICAgIC8vIFNldCBmaW5hbCBgd2lkdGhgIGZvciB2aWV3cG9ydFxyXG4gICAgY29uc3Qgdmlld3BvcnRXaWR0aCA9IE1hdGguYWJzKFxyXG4gICAgICBNYXRoLmNlaWwoc2l6ZS5jaGFydFdpZHRoIHx8IGV4cG9ydE9wdGlvbnMud2lkdGgpXHJcbiAgICApO1xyXG5cclxuICAgIC8vIFNldCB0aGUgZmluYWwgdmlld3BvcnQgbm93IHRoYXQgd2UgaGF2ZSB0aGUgcmVhbCBoZWlnaHRcclxuICAgIGF3YWl0IHBhZ2Uuc2V0Vmlld3BvcnQoe1xyXG4gICAgICBoZWlnaHQ6IHZpZXdwb3J0SGVpZ2h0LFxyXG4gICAgICB3aWR0aDogdmlld3BvcnRXaWR0aCxcclxuICAgICAgZGV2aWNlU2NhbGVGYWN0b3I6IGlzU1ZHID8gMSA6IHBhcnNlRmxvYXQoZXhwb3J0T3B0aW9ucy5zY2FsZSlcclxuICAgIH0pO1xyXG5cclxuICAgIGxldCByZXN1bHQ7XHJcbiAgICAvLyBSYXN0ZXJpemF0aW9uIHByb2Nlc3NcclxuICAgIHN3aXRjaCAoZXhwb3J0T3B0aW9ucy50eXBlKSB7XHJcbiAgICAgIGNhc2UgJ3N2Zyc6XHJcbiAgICAgICAgcmVzdWx0ID0gYXdhaXQgX2NyZWF0ZVNWRyhwYWdlKTtcclxuICAgICAgICBicmVhaztcclxuICAgICAgY2FzZSAncG5nJzpcclxuICAgICAgY2FzZSAnanBlZyc6XHJcbiAgICAgICAgcmVzdWx0ID0gYXdhaXQgX2NyZWF0ZUltYWdlKFxyXG4gICAgICAgICAgcGFnZSxcclxuICAgICAgICAgIGV4cG9ydE9wdGlvbnMudHlwZSxcclxuICAgICAgICAgIHtcclxuICAgICAgICAgICAgd2lkdGg6IHZpZXdwb3J0V2lkdGgsXHJcbiAgICAgICAgICAgIGhlaWdodDogdmlld3BvcnRIZWlnaHQsXHJcbiAgICAgICAgICAgIHgsXHJcbiAgICAgICAgICAgIHlcclxuICAgICAgICAgIH0sXHJcbiAgICAgICAgICBleHBvcnRPcHRpb25zLnJhc3Rlcml6YXRpb25UaW1lb3V0XHJcbiAgICAgICAgKTtcclxuICAgICAgICBicmVhaztcclxuICAgICAgY2FzZSAncGRmJzpcclxuICAgICAgICByZXN1bHQgPSBhd2FpdCBfY3JlYXRlUERGKFxyXG4gICAgICAgICAgcGFnZSxcclxuICAgICAgICAgIHZpZXdwb3J0SGVpZ2h0LFxyXG4gICAgICAgICAgdmlld3BvcnRXaWR0aCxcclxuICAgICAgICAgIGV4cG9ydE9wdGlvbnMucmFzdGVyaXphdGlvblRpbWVvdXRcclxuICAgICAgICApO1xyXG4gICAgICAgIGJyZWFrO1xyXG4gICAgICBkZWZhdWx0OlxyXG4gICAgICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcihcclxuICAgICAgICAgIGBbZXhwb3J0XSBVbnN1cHBvcnRlZCBvdXRwdXQgZm9ybWF0OiAke2V4cG9ydE9wdGlvbnMudHlwZX0uYCxcclxuICAgICAgICAgIDQwMFxyXG4gICAgICAgICk7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gQ2xlYXIgcHJldmlvdXNseSBpbmplY3RlZCBKUyBhbmQgQ1NTIHJlc291cmNlc1xyXG4gICAgYXdhaXQgY2xlYXJQYWdlUmVzb3VyY2VzKHBhZ2UsIGluamVjdGVkUmVzb3VyY2VzKTtcclxuICAgIHJldHVybiByZXN1bHQ7XHJcbiAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgIGF3YWl0IGNsZWFyUGFnZVJlc291cmNlcyhwYWdlLCBpbmplY3RlZFJlc291cmNlcyk7XHJcbiAgICByZXR1cm4gZXJyb3I7XHJcbiAgfVxyXG59XHJcblxyXG4vKipcclxuICogUmV0cmlldmVzIHRoZSBjbGlwcGluZyByZWdpb24gY29vcmRpbmF0ZXMgb2YgdGhlIHNwZWNpZmllZCBwYWdlIGVsZW1lbnRcclxuICogd2l0aCB0aGUgJ2NoYXJ0LWNvbnRhaW5lcicgaWQuXHJcbiAqXHJcbiAqIEBhc3luY1xyXG4gKiBAZnVuY3Rpb24gX2dldENsaXBSZWdpb25cclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IHBhZ2UgLSBQdXBwZXRlZXIgcGFnZSBvYmplY3QuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtQcm9taXNlPE9iamVjdD59IEEgUHJvbWlzZSB0aGF0IHJlc29sdmVzIHRvIGFuIG9iamVjdCBjb250YWluaW5nXHJcbiAqIGB4YCwgYHlgLCBgd2lkdGhgLCBhbmQgYGhlaWdodGAgcHJvcGVydGllcy5cclxuICovXHJcbmFzeW5jIGZ1bmN0aW9uIF9nZXRDbGlwUmVnaW9uKHBhZ2UpIHtcclxuICByZXR1cm4gcGFnZS4kZXZhbCgnI2NoYXJ0LWNvbnRhaW5lcicsIChlbGVtZW50KSA9PiB7XHJcbiAgICBjb25zdCB7IHgsIHksIHdpZHRoLCBoZWlnaHQgfSA9IGVsZW1lbnQuZ2V0Qm91bmRpbmdDbGllbnRSZWN0KCk7XHJcbiAgICByZXR1cm4ge1xyXG4gICAgICB4LFxyXG4gICAgICB5LFxyXG4gICAgICB3aWR0aCxcclxuICAgICAgaGVpZ2h0OiBNYXRoLnRydW5jKGhlaWdodCA+IDEgPyBoZWlnaHQgOiA1MDApXHJcbiAgICB9O1xyXG4gIH0pO1xyXG59XHJcblxyXG4vKipcclxuICogQ3JlYXRlcyBhbiBTVkcgYnkgZXZhbHVhdGluZyB0aGUgYG91dGVySFRNTGAgb2YgdGhlIGZpcnN0ICdzdmcnIGVsZW1lbnRcclxuICogaW5zaWRlIGFuIGVsZW1lbnQgd2l0aCB0aGUgaWQgJ2NvbnRhaW5lcicuXHJcbiAqXHJcbiAqIEBhc3luY1xyXG4gKiBAZnVuY3Rpb24gX2NyZWF0ZVNWR1xyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gcGFnZSAtIFB1cHBldGVlciBwYWdlIG9iamVjdC5cclxuICpcclxuICogQHJldHVybnMge1Byb21pc2U8c3RyaW5nPn0gQSBQcm9taXNlIHRoYXQgcmVzb2x2ZXMgdG8gdGhlIFNWRyBzdHJpbmcuXHJcbiAqL1xyXG5hc3luYyBmdW5jdGlvbiBfY3JlYXRlU1ZHKHBhZ2UpIHtcclxuICByZXR1cm4gcGFnZS4kZXZhbChcclxuICAgICcjY29udGFpbmVyIHN2ZzpmaXJzdC1vZi10eXBlJyxcclxuICAgIChlbGVtZW50KSA9PiBlbGVtZW50Lm91dGVySFRNTFxyXG4gICk7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBDcmVhdGVzIGFuIGltYWdlIHVzaW5nIFB1cHBldGVlcidzIHBhZ2UgYHNjcmVlbnNob3RgIGZ1bmN0aW9uYWxpdHkgd2l0aFxyXG4gKiBzcGVjaWZpZWQgb3B0aW9ucy5cclxuICpcclxuICogQGFzeW5jXHJcbiAqIEBmdW5jdGlvbiBfY3JlYXRlSW1hZ2VcclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IHBhZ2UgLSBQdXBwZXRlZXIgcGFnZSBvYmplY3QuXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSB0eXBlIC0gSW1hZ2UgdHlwZS5cclxuICogQHBhcmFtIHtPYmplY3R9IGNsaXAgLSBDbGlwcGluZyByZWdpb24gY29vcmRpbmF0ZXMuXHJcbiAqIEBwYXJhbSB7bnVtYmVyfSByYXN0ZXJpemF0aW9uVGltZW91dCAtIFRpbWVvdXQgZm9yIHJhc3Rlcml6YXRpb25cclxuICogaW4gbWlsbGlzZWNvbmRzLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7UHJvbWlzZTxCdWZmZXI+fSBBIFByb21pc2UgdGhhdCByZXNvbHZlcyB0byB0aGUgaW1hZ2UgYnVmZmVyXHJcbiAqIG9yIHJlamVjdGluZyB3aXRoIGFuIGBFeHBvcnRFcnJvcmAgZm9yIHRpbWVvdXQuXHJcbiAqL1xyXG5hc3luYyBmdW5jdGlvbiBfY3JlYXRlSW1hZ2UocGFnZSwgdHlwZSwgY2xpcCwgcmFzdGVyaXphdGlvblRpbWVvdXQpIHtcclxuICByZXR1cm4gUHJvbWlzZS5yYWNlKFtcclxuICAgIHBhZ2Uuc2NyZWVuc2hvdCh7XHJcbiAgICAgIHR5cGUsXHJcbiAgICAgIGNsaXAsXHJcbiAgICAgIGVuY29kaW5nOiAnYmFzZTY0JyxcclxuICAgICAgZnVsbFBhZ2U6IGZhbHNlLFxyXG4gICAgICBvcHRpbWl6ZUZvclNwZWVkOiB0cnVlLFxyXG4gICAgICBjYXB0dXJlQmV5b25kVmlld3BvcnQ6IHRydWUsXHJcbiAgICAgIC4uLih0eXBlICE9PSAncG5nJyA/IHsgcXVhbGl0eTogODAgfSA6IHt9KSxcclxuICAgICAgLy8gQWx3YXlzIHJlbmRlciBvbiBhIHRyYW5zcGFyZW50IHBhZ2UgaWYgdGhlIGV4cGVjdGVkIHR5cGUgZm9ybWF0IGlzIFBOR1xyXG4gICAgICBvbWl0QmFja2dyb3VuZDogdHlwZSA9PSAncG5nJyAvLyAjNDQ3LCAjNDYzXHJcbiAgICB9KSxcclxuICAgIG5ldyBQcm9taXNlKChfcmVzb2x2ZSwgcmVqZWN0KSA9PlxyXG4gICAgICBzZXRUaW1lb3V0KFxyXG4gICAgICAgICgpID0+IHJlamVjdChuZXcgRXhwb3J0RXJyb3IoJ1Jhc3Rlcml6YXRpb24gdGltZW91dCcsIDQwOCkpLFxyXG4gICAgICAgIHJhc3Rlcml6YXRpb25UaW1lb3V0IHx8IDE1MDBcclxuICAgICAgKVxyXG4gICAgKVxyXG4gIF0pO1xyXG59XHJcblxyXG4vKipcclxuICogQ3JlYXRlcyBhIFBERiB1c2luZyBQdXBwZXRlZXIncyBwYWdlIGBwZGZgIGZ1bmN0aW9uYWxpdHkgd2l0aCBzcGVjaWZpZWRcclxuICogb3B0aW9ucy5cclxuICpcclxuICogQGFzeW5jXHJcbiAqIEBmdW5jdGlvbiBfY3JlYXRlUERGXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBwYWdlIC0gUHVwcGV0ZWVyIHBhZ2Ugb2JqZWN0LlxyXG4gKiBAcGFyYW0ge251bWJlcn0gaGVpZ2h0IC0gUERGIGhlaWdodC5cclxuICogQHBhcmFtIHtudW1iZXJ9IHdpZHRoIC0gUERGIHdpZHRoLlxyXG4gKiBAcGFyYW0ge251bWJlcn0gcmFzdGVyaXphdGlvblRpbWVvdXQgLSBUaW1lb3V0IGZvciByYXN0ZXJpemF0aW9uXHJcbiAqIGluIG1pbGxpc2Vjb25kcy5cclxuICpcclxuICogQHJldHVybnMge1Byb21pc2U8QnVmZmVyPn0gQSBQcm9taXNlIHRoYXQgcmVzb2x2ZXMgdG8gdGhlIFBERiBidWZmZXIuXHJcbiAqL1xyXG5hc3luYyBmdW5jdGlvbiBfY3JlYXRlUERGKHBhZ2UsIGhlaWdodCwgd2lkdGgsIHJhc3Rlcml6YXRpb25UaW1lb3V0KSB7XHJcbiAgYXdhaXQgcGFnZS5lbXVsYXRlTWVkaWFUeXBlKCdzY3JlZW4nKTtcclxuICByZXR1cm4gcGFnZS5wZGYoe1xyXG4gICAgLy8gVGhpcyB3aWxsIHJlbW92ZSBhbiBleHRyYSBlbXB0eSBwYWdlIGluIFBERiBleHBvcnRzXHJcbiAgICBoZWlnaHQ6IGhlaWdodCArIDEsXHJcbiAgICB3aWR0aCxcclxuICAgIGVuY29kaW5nOiAnYmFzZTY0JyxcclxuICAgIHRpbWVvdXQ6IHJhc3Rlcml6YXRpb25UaW1lb3V0IHx8IDE1MDBcclxuICB9KTtcclxufVxyXG5cclxuZXhwb3J0IGRlZmF1bHQge1xyXG4gIHB1cHBldGVlckV4cG9ydFxyXG59O1xyXG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxyXG5cclxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXHJcblxyXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNSwgSGlnaHNvZnRcclxuXHJcbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cclxuXHJcbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxyXG5cclxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxyXG5cclxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cclxuXHJcbi8qKlxyXG4gKiBAb3ZlcnZpZXcgVGhpcyBtb2R1bGUgcHJvdmlkZXMgYSB3b3JrZXIgcG9vbCBpbXBsZW1lbnRhdGlvbiBmb3IgbWFuYWdpbmdcclxuICogdGhlIGJyb3dzZXIgaW5zdGFuY2UgYW5kIHBhZ2VzLCBzcGVjaWZpY2FsbHkgZGVzaWduZWQgZm9yIHVzZSB3aXRoXHJcbiAqIHRoZSBIaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXIuIEl0IG9wdGltaXplcyByZXNvdXJjZXMgdXNhZ2UgYW5kIHBlcmZvcm1hbmNlXHJcbiAqIGJ5IG1haW50YWluaW5nIGEgcG9vbCBvZiB3b3JrZXJzIHRoYXQgY2FuIGhhbmRsZSBjb25jdXJyZW50IGV4cG9ydCB0YXNrc1xyXG4gKiB1c2luZyBQdXBwZXRlZXIuXHJcbiAqL1xyXG5cclxuaW1wb3J0IHsgUG9vbCB9IGZyb20gJ3Rhcm4nO1xyXG5pbXBvcnQgeyB2NCBhcyB1dWlkIH0gZnJvbSAndXVpZCc7XHJcblxyXG5pbXBvcnQgeyBjbGVhclBhZ2UsIGNyZWF0ZUJyb3dzZXIsIGNsb3NlQnJvd3NlciwgbmV3UGFnZSB9IGZyb20gJy4vYnJvd3Nlci5qcyc7XHJcbmltcG9ydCB7IHB1cHBldGVlckV4cG9ydCB9IGZyb20gJy4vZXhwb3J0LmpzJztcclxuaW1wb3J0IHsgbG9nLCBsb2dXaXRoU3RhY2sgfSBmcm9tICcuL2xvZ2dlci5qcyc7XHJcbmltcG9ydCB7IGdldE5ld0RhdGVUaW1lLCBtZWFzdXJlVGltZSB9IGZyb20gJy4vdXRpbHMuanMnO1xyXG5cclxuaW1wb3J0IEV4cG9ydEVycm9yIGZyb20gJy4vZXJyb3JzL0V4cG9ydEVycm9yLmpzJztcclxuXHJcbi8vIFRoZSBwb29sIGluc3RhbmNlXHJcbmxldCBwb29sID0gbnVsbDtcclxuXHJcbi8vIFBvb2wgc3RhdGlzdGljc1xyXG5jb25zdCBwb29sU3RhdHMgPSB7XHJcbiAgZXhwb3J0c0F0dGVtcHRlZDogMCxcclxuICBleHBvcnRzUGVyZm9ybWVkOiAwLFxyXG4gIGV4cG9ydHNEcm9wcGVkOiAwLFxyXG4gIGV4cG9ydHNGcm9tU3ZnOiAwLFxyXG4gIGV4cG9ydHNGcm9tT3B0aW9uczogMCxcclxuICBleHBvcnRzRnJvbVN2Z0F0dGVtcHRzOiAwLFxyXG4gIGV4cG9ydHNGcm9tT3B0aW9uc0F0dGVtcHRzOiAwLFxyXG4gIHRpbWVTcGVudDogMCxcclxuICB0aW1lU3BlbnRBdmVyYWdlOiAwXHJcbn07XHJcblxyXG4vKipcclxuICogSW5pdGlhbGl6ZXMgdGhlIGV4cG9ydCBwb29sIHdpdGggdGhlIHByb3ZpZGVkIGNvbmZpZ3VyYXRpb24sIGNyZWF0aW5nXHJcbiAqIGEgYnJvd3NlciBpbnN0YW5jZSBhbmQgc2V0dGluZyB1cCB3b3JrZXIgcmVzb3VyY2VzLlxyXG4gKlxyXG4gKiBAYXN5bmNcclxuICogQGZ1bmN0aW9uIGluaXRQb29sXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBwb29sT3B0aW9ucyAtIFRoZSBjb25maWd1cmF0aW9uIG9iamVjdCBjb250YWluaW5nIGBwb29sYFxyXG4gKiBvcHRpb25zLlxyXG4gKiBAcGFyYW0ge0FycmF5LjxzdHJpbmc+fSBwdXBwZXRlZXJBcmdzIC0gQWRkaXRpb25hbCBhcmd1bWVudHMgZm9yIFB1cHBldGVlclxyXG4gKiBsYXVuY2guXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtQcm9taXNlPHZvaWQ+fSBBIFByb21pc2UgdGhhdCByZXNvbHZlcyB0byBlbmRpbmcgdGhlIGZ1bmN0aW9uXHJcbiAqIGV4ZWN1dGlvbiB3aGVuIGFuIGFscmVhZHkgaW5pdGlhbGl6ZWQgcG9vbCBvZiByZXNvdXJjZXMgaXMgZm91bmQuXHJcbiAqXHJcbiAqIEB0aHJvd3Mge0V4cG9ydEVycm9yfSBUaHJvd3MgYW4gYEV4cG9ydEVycm9yYCBpZiBjb3VsZCBub3QgY3JlYXRlIHRoZSBwb29sXHJcbiAqIG9mIHdvcmtlcnMuXHJcbiAqL1xyXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gaW5pdFBvb2wocG9vbE9wdGlvbnMsIHB1cHBldGVlckFyZ3MpIHtcclxuICAvLyBDcmVhdGUgYSBicm93c2VyIGluc3RhbmNlIHdpdGggdGhlIHB1cHBldGVlciBhcmd1bWVudHNcclxuICBhd2FpdCBjcmVhdGVCcm93c2VyKHB1cHBldGVlckFyZ3MpO1xyXG5cclxuICB0cnkge1xyXG4gICAgbG9nKFxyXG4gICAgICAzLFxyXG4gICAgICBgW3Bvb2xdIEluaXRpYWxpemluZyBwb29sIHdpdGggd29ya2VyczogbWluICR7cG9vbE9wdGlvbnMubWluV29ya2Vyc30sIG1heCAke3Bvb2xPcHRpb25zLm1heFdvcmtlcnN9LmBcclxuICAgICk7XHJcblxyXG4gICAgaWYgKHBvb2wpIHtcclxuICAgICAgbG9nKFxyXG4gICAgICAgIDQsXHJcbiAgICAgICAgJ1twb29sXSBBbHJlYWR5IGluaXRpYWxpemVkLCBwbGVhc2Uga2lsbCBpdCBiZWZvcmUgY3JlYXRpbmcgYSBuZXcgb25lLidcclxuICAgICAgKTtcclxuICAgICAgcmV0dXJuO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIEtlZXAgYW4gZXllIG9uIGEgY29ycmVjdCBtaW4gYW5kIG1heCB3b3JrZXJzIG51bWJlclxyXG4gICAgaWYgKHBvb2xPcHRpb25zLm1pbldvcmtlcnMgPiBwb29sT3B0aW9ucy5tYXhXb3JrZXJzKSB7XHJcbiAgICAgIHBvb2xPcHRpb25zLm1pbldvcmtlcnMgPSBwb29sT3B0aW9ucy5tYXhXb3JrZXJzO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIENyZWF0ZSBhIHBvb2wgYWxvbmcgd2l0aCBhIG1pbmltYWwgbnVtYmVyIG9mIHJlc291cmNlc1xyXG4gICAgcG9vbCA9IG5ldyBQb29sKHtcclxuICAgICAgLy8gR2V0IHRoZSBgY3JlYXRlYCwgYHZhbGlkYXRlYCwgYW5kIGBkZXN0cm95YCBmdW5jdGlvbnNcclxuICAgICAgLi4uX2ZhY3RvcnkocG9vbE9wdGlvbnMpLFxyXG4gICAgICBtaW46IHBvb2xPcHRpb25zLm1pbldvcmtlcnMsXHJcbiAgICAgIG1heDogcG9vbE9wdGlvbnMubWF4V29ya2VycyxcclxuICAgICAgYWNxdWlyZVRpbWVvdXRNaWxsaXM6IHBvb2xPcHRpb25zLmFjcXVpcmVUaW1lb3V0LFxyXG4gICAgICBjcmVhdGVUaW1lb3V0TWlsbGlzOiBwb29sT3B0aW9ucy5jcmVhdGVUaW1lb3V0LFxyXG4gICAgICBkZXN0cm95VGltZW91dE1pbGxpczogcG9vbE9wdGlvbnMuZGVzdHJveVRpbWVvdXQsXHJcbiAgICAgIGlkbGVUaW1lb3V0TWlsbGlzOiBwb29sT3B0aW9ucy5pZGxlVGltZW91dCxcclxuICAgICAgY3JlYXRlUmV0cnlJbnRlcnZhbE1pbGxpczogcG9vbE9wdGlvbnMuY3JlYXRlUmV0cnlJbnRlcnZhbCxcclxuICAgICAgcmVhcEludGVydmFsTWlsbGlzOiBwb29sT3B0aW9ucy5yZWFwZXJJbnRlcnZhbCxcclxuICAgICAgcHJvcGFnYXRlQ3JlYXRlRXJyb3I6IGZhbHNlXHJcbiAgICB9KTtcclxuXHJcbiAgICAvLyBTZXQgZXZlbnRzXHJcbiAgICBwb29sLm9uKCdyZWxlYXNlJywgYXN5bmMgKHJlc291cmNlKSA9PiB7XHJcbiAgICAgIC8vIENsZWFyIHBhZ2VcclxuICAgICAgY29uc3QgY2xlYXJTdGF0dXMgPSBhd2FpdCBjbGVhclBhZ2UocmVzb3VyY2UsIGZhbHNlKTtcclxuICAgICAgbG9nKFxyXG4gICAgICAgIDQsXHJcbiAgICAgICAgYFtwb29sXSBQb29sIHJlc291cmNlIFske3Jlc291cmNlLmlkfV0gLSBSZWxlYXNpbmcgYSB3b3JrZXIuIENsZWFyIHBhZ2Ugc3RhdHVzOiAke2NsZWFyU3RhdHVzfS5gXHJcbiAgICAgICk7XHJcbiAgICB9KTtcclxuXHJcbiAgICBwb29sLm9uKCdkZXN0cm95U3VjY2VzcycsIChfZXZlbnRJZCwgcmVzb3VyY2UpID0+IHtcclxuICAgICAgbG9nKFxyXG4gICAgICAgIDQsXHJcbiAgICAgICAgYFtwb29sXSBQb29sIHJlc291cmNlIFske3Jlc291cmNlLmlkfV0gLSBEZXN0cm95ZWQgYSB3b3JrZXIgc3VjY2Vzc2Z1bGx5LmBcclxuICAgICAgKTtcclxuICAgICAgcmVzb3VyY2UucGFnZSA9IG51bGw7XHJcbiAgICB9KTtcclxuXHJcbiAgICBjb25zdCBpbml0aWFsUmVzb3VyY2VzID0gW107XHJcbiAgICAvLyBDcmVhdGUgYW4gaW5pdGlhbCBudW1iZXIgb2YgcmVzb3VyY2VzXHJcbiAgICBmb3IgKGxldCBpID0gMDsgaSA8IHBvb2xPcHRpb25zLm1pbldvcmtlcnM7IGkrKykge1xyXG4gICAgICB0cnkge1xyXG4gICAgICAgIGNvbnN0IHJlc291cmNlID0gYXdhaXQgcG9vbC5hY3F1aXJlKCkucHJvbWlzZTtcclxuICAgICAgICBpbml0aWFsUmVzb3VyY2VzLnB1c2gocmVzb3VyY2UpO1xyXG4gICAgICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgICAgIGxvZ1dpdGhTdGFjaygyLCBlcnJvciwgJ1twb29sXSBDb3VsZCBub3QgY3JlYXRlIGFuIGluaXRpYWwgcmVzb3VyY2UuJyk7XHJcbiAgICAgIH1cclxuICAgIH1cclxuXHJcbiAgICAvLyBSZWxlYXNlIHRoZSBpbml0aWFsIG51bWJlciBvZiByZXNvdXJjZXMgYmFjayB0byB0aGUgcG9vbFxyXG4gICAgaW5pdGlhbFJlc291cmNlcy5mb3JFYWNoKChyZXNvdXJjZSkgPT4ge1xyXG4gICAgICBwb29sLnJlbGVhc2UocmVzb3VyY2UpO1xyXG4gICAgfSk7XHJcblxyXG4gICAgbG9nKFxyXG4gICAgICAzLFxyXG4gICAgICBgW3Bvb2xdIFRoZSBwb29sIGlzIHJlYWR5JHtpbml0aWFsUmVzb3VyY2VzLmxlbmd0aCA/IGAgd2l0aCAke2luaXRpYWxSZXNvdXJjZXMubGVuZ3RofSBpbml0aWFsIHJlc291cmNlcyB3YWl0aW5nLmAgOiAnLid9YFxyXG4gICAgKTtcclxuICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgdGhyb3cgbmV3IEV4cG9ydEVycm9yKFxyXG4gICAgICAnW3Bvb2xdIENvdWxkIG5vdCBjb25maWd1cmUgYW5kIGNyZWF0ZSB0aGUgcG9vbCBvZiB3b3JrZXJzLicsXHJcbiAgICAgIDUwMFxyXG4gICAgKS5zZXRFcnJvcihlcnJvcik7XHJcbiAgfVxyXG59XHJcblxyXG4vKipcclxuICogVGVybWluYXRlcyBhbGwgd29ya2VycyBpbiB0aGUgcG9vbCwgZGVzdHJveXMgdGhlIHBvb2wsIGFuZCBjbG9zZXMgdGhlIGJyb3dzZXJcclxuICogaW5zdGFuY2UuXHJcbiAqXHJcbiAqIEBhc3luY1xyXG4gKiBAZnVuY3Rpb24ga2lsbFBvb2xcclxuICpcclxuICogQHJldHVybnMge1Byb21pc2U8dm9pZD59IEEgUHJvbWlzZSB0aGF0IHJlc29sdmVzIG9uY2UgYWxsIHdvcmtlcnMgYXJlXHJcbiAqIHRlcm1pbmF0ZWQsIHRoZSBwb29sIGlzIGRlc3Ryb3llZCwgYW5kIHRoZSBicm93c2VyIGlzIHN1Y2Nlc3NmdWxseSBjbG9zZWQuXHJcbiAqL1xyXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24ga2lsbFBvb2woKSB7XHJcbiAgbG9nKDMsICdbcG9vbF0gS2lsbGluZyBwb29sIHdpdGggYWxsIHdvcmtlcnMgYW5kIGNsb3NpbmcgYnJvd3Nlci4nKTtcclxuXHJcbiAgLy8gSWYgc3RpbGwgYWxpdmUsIGRlc3Ryb3kgdGhlIHBvb2wgb2YgcGFnZXMgYmVmb3JlIGNsb3NpbmcgYSBicm93c2VyXHJcbiAgaWYgKHBvb2wpIHtcclxuICAgIC8vIEZyZWUgdXAgbm90IHJlbGVhc2VkIHdvcmtlcnNcclxuICAgIGZvciAoY29uc3Qgd29ya2VyIG9mIHBvb2wudXNlZCkge1xyXG4gICAgICBwb29sLnJlbGVhc2Uod29ya2VyLnJlc291cmNlKTtcclxuICAgIH1cclxuXHJcbiAgICAvLyBEZXN0cm95IHRoZSBwb29sIGlmIGl0IGlzIHN0aWxsIGF2YWlsYWJsZVxyXG4gICAgaWYgKCFwb29sLmRlc3Ryb3llZCkge1xyXG4gICAgICBhd2FpdCBwb29sLmRlc3Ryb3koKTtcclxuICAgICAgbG9nKDQsICdbcG9vbF0gRGVzdHJveWVkIHRoZSBwb29sIG9mIHJlc291cmNlcy4nKTtcclxuICAgIH1cclxuICAgIHBvb2wgPSBudWxsO1xyXG4gIH1cclxuXHJcbiAgLy8gQ2xvc2UgdGhlIGJyb3dzZXIgaW5zdGFuY2VcclxuICBhd2FpdCBjbG9zZUJyb3dzZXIoKTtcclxufVxyXG5cclxuLyoqXHJcbiAqIFByb2Nlc3NlcyB0aGUgZXhwb3J0IHdvcmsgdXNpbmcgYSB3b3JrZXIgZnJvbSB0aGUgcG9vbC4gQWNxdWlyZXMgYSB3b3JrZXJcclxuICogaGFuZGxlIGZyb20gdGhlIHBvb2wsIHBlcmZvcm1zIHRoZSBleHBvcnQgdXNpbmcgcHVwcGV0ZWVyLCBhbmQgcmVsZWFzZXNcclxuICogdGhlIHdvcmtlciBoYW5kbGUgYmFjayB0byB0aGUgcG9vbC5cclxuICpcclxuICogQGFzeW5jXHJcbiAqIEBmdW5jdGlvbiBwb3N0V29ya1xyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gb3B0aW9ucyAtIFRoZSBjb25maWd1cmF0aW9uIG9iamVjdCBjb250YWluaW5nIGNvbXBsZXRlIHNldFxyXG4gKiBvZiBvcHRpb25zLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7UHJvbWlzZTxPYmplY3Q+fSBBIFByb21pc2UgdGhhdCByZXNvbHZlcyB0byB0aGUgZXhwb3J0IHJlc3VsdFxyXG4gKiBhbmQgb3B0aW9ucy5cclxuICpcclxuICogQHRocm93cyB7RXhwb3J0RXJyb3J9IFRocm93cyBhbiBgRXhwb3J0RXJyb3JgIGlmIGFuIGVycm9yIG9jY3VycyBkdXJpbmdcclxuICogdGhlIGV4cG9ydCBwcm9jZXNzLlxyXG4gKi9cclxuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIHBvc3RXb3JrKG9wdGlvbnMpIHtcclxuICBsZXQgd29ya2VySGFuZGxlO1xyXG5cclxuICB0cnkge1xyXG4gICAgbG9nKDQsICdbcG9vbF0gV29yayByZWNlaXZlZCwgc3RhcnRpbmcgdG8gcHJvY2Vzcy4nKTtcclxuXHJcbiAgICAvLyBBbiBleHBvcnQgYXR0ZW1wdCBjb3VudGVkXHJcbiAgICArK3Bvb2xTdGF0cy5leHBvcnRzQXR0ZW1wdGVkO1xyXG5cclxuICAgIC8vIERpc3BsYXkgdGhlIHBvb2wgaW5mb3JtYXRpb24gaWYgbmVlZGVkXHJcbiAgICBpZiAob3B0aW9ucy5wb29sLmJlbmNobWFya2luZykge1xyXG4gICAgICBnZXRQb29sSW5mbygpO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIFRocm93IGFuIGVycm9yIGluIGNhc2Ugb2YgbGFja2luZyB0aGUgcG9vbCBpbnN0YW5jZVxyXG4gICAgaWYgKCFwb29sKSB7XHJcbiAgICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcihcclxuICAgICAgICAnW3Bvb2xdIFdvcmsgcmVjZWl2ZWQsIGJ1dCBwb29sIGhhcyBub3QgYmVlbiBzdGFydGVkLicsXHJcbiAgICAgICAgNTAwXHJcbiAgICAgICk7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gVGhlIGFjcXVpcmUgY291bnRlclxyXG4gICAgY29uc3QgYWNxdWlyZUNvdW50ZXIgPSBtZWFzdXJlVGltZSgpO1xyXG5cclxuICAgIC8vIFRyeSB0byBhY3F1aXJlIHRoZSB3b3JrZXIgYWxvbmcgd2l0aCB0aGUgaWQsIHdvcmtzIGNvdW50IGFuZCBwYWdlXHJcbiAgICB0cnkge1xyXG4gICAgICBsb2coNCwgJ1twb29sXSBBY3F1aXJpbmcgYSB3b3JrZXIgaGFuZGxlLicpO1xyXG5cclxuICAgICAgLy8gQWNxdWlyZSBhIHBvb2wgcmVzb3VyY2VcclxuICAgICAgd29ya2VySGFuZGxlID0gYXdhaXQgcG9vbC5hY3F1aXJlKCkucHJvbWlzZTtcclxuXHJcbiAgICAgIC8vIENoZWNrIHRoZSBwYWdlIGFjcXVpcmUgdGltZVxyXG4gICAgICBpZiAob3B0aW9ucy5zZXJ2ZXIuYmVuY2htYXJraW5nKSB7XHJcbiAgICAgICAgbG9nKFxyXG4gICAgICAgICAgNSxcclxuICAgICAgICAgIGBbYmVuY2htYXJrXSAke29wdGlvbnMucmVxdWVzdElkID8gYFJlcXVlc3QgWyR7b3B0aW9ucy5yZXF1ZXN0SWR9XSAtIGAgOiAnJ31gLFxyXG4gICAgICAgICAgYEFjcXVpcmluZyBhIHdvcmtlciBoYW5kbGUgdG9vayAke2FjcXVpcmVDb3VudGVyKCl9bXMuYFxyXG4gICAgICAgICk7XHJcbiAgICAgIH1cclxuICAgIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcihcclxuICAgICAgICBgW3Bvb2xdICR7XHJcbiAgICAgICAgICBvcHRpb25zLnJlcXVlc3RJZCA/IGBSZXF1ZXN0IFske29wdGlvbnMucmVxdWVzdElkfV0gLSBgIDogJydcclxuICAgICAgICB9RXJyb3IgZW5jb3VudGVyZWQgd2hlbiBhY3F1aXJpbmcgYW4gYXZhaWxhYmxlIGVudHJ5OiAke2FjcXVpcmVDb3VudGVyKCl9bXMuYCxcclxuICAgICAgICA0MDBcclxuICAgICAgKS5zZXRFcnJvcihlcnJvcik7XHJcbiAgICB9XHJcbiAgICBsb2coNCwgJ1twb29sXSBBY3F1aXJlZCBhIHdvcmtlciBoYW5kbGUuJyk7XHJcblxyXG4gICAgaWYgKCF3b3JrZXJIYW5kbGUucGFnZSkge1xyXG4gICAgICAvLyBTZXQgdGhlIGB3b3JrTGltaXRgIHRvIGV4Y2VlZGVkIGluIG9yZGVyIHRvIHJlY3JlYXRlIHRoZSByZXNvdXJjZVxyXG4gICAgICB3b3JrZXJIYW5kbGUud29ya0NvdW50ID0gb3B0aW9ucy5wb29sLndvcmtMaW1pdCArIDE7XHJcbiAgICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcihcclxuICAgICAgICAnW3Bvb2xdIFJlc29sdmVkIHdvcmtlciBwYWdlIGlzIGludmFsaWQ6IHRoZSBwb29sIHNldHVwIGlzIHdvbmt5LicsXHJcbiAgICAgICAgNDAwXHJcbiAgICAgICk7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gU2F2ZSB0aGUgc3RhcnQgdGltZVxyXG4gICAgY29uc3Qgd29ya1N0YXJ0ID0gZ2V0TmV3RGF0ZVRpbWUoKTtcclxuXHJcbiAgICBsb2coXHJcbiAgICAgIDQsXHJcbiAgICAgIGBbcG9vbF0gUG9vbCByZXNvdXJjZSBbJHt3b3JrZXJIYW5kbGUuaWR9XSAtIFN0YXJ0aW5nIHdvcmsgb24gdGhpcyBwb29sIGVudHJ5LmBcclxuICAgICk7XHJcblxyXG4gICAgLy8gU3RhcnQgbWVhc3VyaW5nIGV4cG9ydCB0aW1lXHJcbiAgICBjb25zdCBleHBvcnRDb3VudGVyID0gbWVhc3VyZVRpbWUoKTtcclxuXHJcbiAgICAvLyBQZXJmb3JtIGFuIGV4cG9ydCBvbiBhIHB1cHBldGVlciBsZXZlbFxyXG4gICAgY29uc3QgcmVzdWx0ID0gYXdhaXQgcHVwcGV0ZWVyRXhwb3J0KFxyXG4gICAgICB3b3JrZXJIYW5kbGUucGFnZSxcclxuICAgICAgb3B0aW9ucy5leHBvcnQsXHJcbiAgICAgIG9wdGlvbnMuY3VzdG9tTG9naWNcclxuICAgICk7XHJcblxyXG4gICAgLy8gQ2hlY2sgaWYgaXQncyBhbiBlcnJvclxyXG4gICAgaWYgKHJlc3VsdCBpbnN0YW5jZW9mIEVycm9yKSB7XHJcbiAgICAgIC8vIE5PVEU6XHJcbiAgICAgIC8vIElmIHRoZXJlJ3MgYSByYXN0ZXJpemF0aW9uIHRpbWVvdXQsIHdlIHdhbnQgbmVlZCB0byBmbHVzaCB0aGUgcGFnZS5cclxuICAgICAgLy8gVGhpcyBpcyBiZWNhdXNlIHRoZSBwYWdlIG1heSBiZSBpbiBhIHN0YXRlIHdoZXJlIGl0J3Mgd2FpdGluZyBmb3JcclxuICAgICAgLy8gdGhlIHNjcmVlbnNob3QgdG8gZmluaXNoIGV2ZW4gdGhvdWdoIHRoZSB0aW1lb3V0IGhhcyBvY2N1cmVkLlxyXG4gICAgICAvLyBXaGljaCBvZiBjb3Vyc2UgY2F1c2VzIGEgbG90IG9mIGlzc3VlcyB3aXRoIHRoZSBldmVudCBzeXN0ZW0sXHJcbiAgICAgIC8vIGFuZCBwYWdlIGNvbnNpc3RlbmN5LlxyXG4gICAgICAvL1xyXG4gICAgICAvLyBOT1RFOlxyXG4gICAgICAvLyBPbmx5IHBhZ2Uuc2NyZWVuc2hvdCB3aWxsIHRocm93IHRoaXMsIHRpbWVvdXRzIGZvciBQREYncyBhcmVcclxuICAgICAgLy8gaGFuZGxlZCBieSB0aGUgcGFnZS5wZGYgZnVuY3Rpb24gaXRzZWxmLlxyXG4gICAgICAvL1xyXG4gICAgICAvLyAuLi55ZXMsIHRoaXMgaXMgdWdseS5cclxuICAgICAgaWYgKHJlc3VsdC5tZXNzYWdlID09PSAnUmFzdGVyaXphdGlvbiB0aW1lb3V0Jykge1xyXG4gICAgICAgIC8vIFNldCB0aGUgYHdvcmtMaW1pdGAgdG8gZXhjZWVkZWQgaW4gb3JkZXIgdG8gcmVjcmVhdGUgdGhlIHJlc291cmNlXHJcbiAgICAgICAgd29ya2VySGFuZGxlLndvcmtDb3VudCA9IG9wdGlvbnMucG9vbC53b3JrTGltaXQgKyAxO1xyXG4gICAgICAgIHdvcmtlckhhbmRsZS5wYWdlID0gbnVsbDtcclxuICAgICAgfVxyXG5cclxuICAgICAgaWYgKFxyXG4gICAgICAgIHJlc3VsdC5uYW1lID09PSAnVGltZW91dEVycm9yJyB8fFxyXG4gICAgICAgIHJlc3VsdC5tZXNzYWdlID09PSAnUmFzdGVyaXphdGlvbiB0aW1lb3V0J1xyXG4gICAgICApIHtcclxuICAgICAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoXHJcbiAgICAgICAgICBgW3Bvb2xdICR7XHJcbiAgICAgICAgICAgIG9wdGlvbnMucmVxdWVzdElkID8gYFJlcXVlc3QgWyR7b3B0aW9ucy5yZXF1ZXN0SWR9XSAtIGAgOiAnJ1xyXG4gICAgICAgICAgfVJhc3Rlcml6YXRpb24gdGltZW91dDogeW91ciBjaGFydCBtYXkgYmUgdG9vIGNvbXBsZXggb3IgbGFyZ2UsIGFuZCBmYWlsZWQgdG8gcmVuZGVyIHdpdGhpbiB0aGUgYWxsb3R0ZWQgdGltZS5gXHJcbiAgICAgICAgKS5zZXRFcnJvcihyZXN1bHQpO1xyXG4gICAgICB9IGVsc2Uge1xyXG4gICAgICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcihcclxuICAgICAgICAgIGBbcG9vbF0gJHtcclxuICAgICAgICAgICAgb3B0aW9ucy5yZXF1ZXN0SWQgPyBgUmVxdWVzdCBbJHtvcHRpb25zLnJlcXVlc3RJZH1dIC0gYCA6ICcnXHJcbiAgICAgICAgICB9RXJyb3IgZW5jb3VudGVyZWQgZHVyaW5nIGV4cG9ydDogJHtleHBvcnRDb3VudGVyKCl9bXMuYFxyXG4gICAgICAgICkuc2V0RXJyb3IocmVzdWx0KTtcclxuICAgICAgfVxyXG4gICAgfVxyXG5cclxuICAgIC8vIENoZWNrIHRoZSBQdXBwZXRlZXIgZXhwb3J0IHRpbWVcclxuICAgIGlmIChvcHRpb25zLnNlcnZlci5iZW5jaG1hcmtpbmcpIHtcclxuICAgICAgbG9nKFxyXG4gICAgICAgIDUsXHJcbiAgICAgICAgYFtiZW5jaG1hcmtdICR7b3B0aW9ucy5yZXF1ZXN0SWQgPyBgUmVxdWVzdCBbJHtvcHRpb25zLnJlcXVlc3RJZH1dIC0gYCA6ICcnfWAsXHJcbiAgICAgICAgYEV4cG9ydGluZyBhIGNoYXJ0IHN1Y2Vzc2Z1bGx5IHRvb2sgJHtleHBvcnRDb3VudGVyKCl9bXMuYFxyXG4gICAgICApO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIFJlbGVhc2UgdGhlIHJlc291cmNlIGJhY2sgdG8gdGhlIHBvb2xcclxuICAgIHBvb2wucmVsZWFzZSh3b3JrZXJIYW5kbGUpO1xyXG5cclxuICAgIC8vIFVzZWQgZm9yIHN0YXRpc3RpY3MgaW4gYXZlcmFnZVRpbWUgYW5kIHByb2Nlc3NlZFdvcmtDb3VudCwgd2hpY2hcclxuICAgIC8vIGluIHR1cm4gaXMgdXNlZCBieSB0aGUgL2hlYWx0aCByb3V0ZS5cclxuICAgIGNvbnN0IHdvcmtFbmQgPSBnZXROZXdEYXRlVGltZSgpO1xyXG4gICAgY29uc3QgZXhwb3J0VGltZSA9IHdvcmtFbmQgLSB3b3JrU3RhcnQ7XHJcblxyXG4gICAgcG9vbFN0YXRzLnRpbWVTcGVudCArPSBleHBvcnRUaW1lO1xyXG4gICAgcG9vbFN0YXRzLnRpbWVTcGVudEF2ZXJhZ2UgPVxyXG4gICAgICBwb29sU3RhdHMudGltZVNwZW50IC8gKytwb29sU3RhdHMuZXhwb3J0c1BlcmZvcm1lZDtcclxuXHJcbiAgICBsb2coNCwgYFtwb29sXSBXb3JrIGNvbXBsZXRlZCBpbiAke2V4cG9ydFRpbWV9bXMuYCk7XHJcblxyXG4gICAgLy8gT3RoZXJ3aXNlIHJldHVybiB0aGUgcmVzdWx0XHJcbiAgICByZXR1cm4ge1xyXG4gICAgICByZXN1bHQsXHJcbiAgICAgIG9wdGlvbnNcclxuICAgIH07XHJcbiAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICsrcG9vbFN0YXRzLmV4cG9ydHNEcm9wcGVkO1xyXG5cclxuICAgIGlmICh3b3JrZXJIYW5kbGUpIHtcclxuICAgICAgcG9vbC5yZWxlYXNlKHdvcmtlckhhbmRsZSk7XHJcbiAgICB9XHJcblxyXG4gICAgdGhyb3cgZXJyb3I7XHJcbiAgfVxyXG59XHJcblxyXG4vKipcclxuICogUmV0cmlldmVzIHRoZSBjdXJyZW50IHBvb2wgaW5zdGFuY2UuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBnZXRQb29sXHJcbiAqXHJcbiAqIEByZXR1cm5zIHsoT2JqZWN0fG51bGwpfSBUaGUgY3VycmVudCBwb29sIGluc3RhbmNlIGlmIGluaXRpYWxpemVkLCBvciBudWxsXHJcbiAqIGlmIHRoZSBwb29sIGhhcyBub3QgYmVlbiBjcmVhdGVkLlxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIGdldFBvb2woKSB7XHJcbiAgcmV0dXJuIHBvb2w7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBHZXRzIHRoZSBzdGF0aXN0aWMgb2YgYSBwb29sIGluc3RhY2UgYWJvdXQgZXhwb3J0cy5cclxuICpcclxuICogQGZ1bmN0aW9uIGdldFBvb2xTdGF0c1xyXG4gKlxyXG4gKiBAcmV0dXJucyB7T2JqZWN0fSBUaGUgY3VycmVudCBwb29sIHN0YXRpc3RpY3MuXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gZ2V0UG9vbFN0YXRzKCkge1xyXG4gIHJldHVybiBwb29sU3RhdHM7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBSZXRyaWV2ZXMgcG9vbCBpbmZvcm1hdGlvbiBpbiBKU09OIGZvcm1hdCwgaW5jbHVkaW5nIG1pbmltdW0gYW5kIG1heGltdW1cclxuICogd29ya2VycywgYXZhaWxhYmxlIHdvcmtlcnMsIHdvcmtlcnMgaW4gdXNlLCBhbmQgcGVuZGluZyBhY3F1aXJlIHJlcXVlc3RzLlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gZ2V0UG9vbEluZm9KU09OXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtPYmplY3R9IFBvb2wgaW5mb3JtYXRpb24gaW4gSlNPTiBmb3JtYXQuXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gZ2V0UG9vbEluZm9KU09OKCkge1xyXG4gIHJldHVybiB7XHJcbiAgICBtaW46IHBvb2wubWluLFxyXG4gICAgbWF4OiBwb29sLm1heCxcclxuICAgIHVzZWQ6IHBvb2wubnVtVXNlZCgpLFxyXG4gICAgYXZhaWxhYmxlOiBwb29sLm51bUZyZWUoKSxcclxuICAgIGFsbENyZWF0ZWQ6IHBvb2wubnVtVXNlZCgpICsgcG9vbC5udW1GcmVlKCksXHJcbiAgICBwZW5kaW5nQWNxdWlyZXM6IHBvb2wubnVtUGVuZGluZ0FjcXVpcmVzKCksXHJcbiAgICBwZW5kaW5nQ3JlYXRlczogcG9vbC5udW1QZW5kaW5nQ3JlYXRlcygpLFxyXG4gICAgcGVuZGluZ1ZhbGlkYXRpb25zOiBwb29sLm51bVBlbmRpbmdWYWxpZGF0aW9ucygpLFxyXG4gICAgcGVuZGluZ0Rlc3Ryb3lzOiBwb29sLnBlbmRpbmdEZXN0cm95cy5sZW5ndGgsXHJcbiAgICBhYnNvbHV0ZUFsbDpcclxuICAgICAgcG9vbC5udW1Vc2VkKCkgK1xyXG4gICAgICBwb29sLm51bUZyZWUoKSArXHJcbiAgICAgIHBvb2wubnVtUGVuZGluZ0FjcXVpcmVzKCkgK1xyXG4gICAgICBwb29sLm51bVBlbmRpbmdDcmVhdGVzKCkgK1xyXG4gICAgICBwb29sLm51bVBlbmRpbmdWYWxpZGF0aW9ucygpICtcclxuICAgICAgcG9vbC5wZW5kaW5nRGVzdHJveXMubGVuZ3RoXHJcbiAgfTtcclxufVxyXG5cclxuLyoqXHJcbiAqIExvZ3MgaW5mb3JtYXRpb24gYWJvdXQgdGhlIGN1cnJlbnQgc3RhdGUgb2YgdGhlIHBvb2wsIGluY2x1ZGluZyB0aGUgbWluaW11bVxyXG4gKiBhbmQgbWF4aW11bSB3b3JrZXJzLCBhdmFpbGFibGUgd29ya2Vycywgd29ya2VycyBpbiB1c2UsIGFuZCBwZW5kaW5nIGFjcXVpcmVcclxuICogcmVxdWVzdHMuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBnZXRQb29sSW5mb1xyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIGdldFBvb2xJbmZvKCkge1xyXG4gIGNvbnN0IHtcclxuICAgIG1pbixcclxuICAgIG1heCxcclxuICAgIHVzZWQsXHJcbiAgICBhdmFpbGFibGUsXHJcbiAgICBhbGxDcmVhdGVkLFxyXG4gICAgcGVuZGluZ0FjcXVpcmVzLFxyXG4gICAgcGVuZGluZ0NyZWF0ZXMsXHJcbiAgICBwZW5kaW5nVmFsaWRhdGlvbnMsXHJcbiAgICBwZW5kaW5nRGVzdHJveXMsXHJcbiAgICBhYnNvbHV0ZUFsbFxyXG4gIH0gPSBnZXRQb29sSW5mb0pTT04oKTtcclxuXHJcbiAgbG9nKDUsIGBbcG9vbF0gVGhlIG1pbmltdW0gbnVtYmVyIG9mIHJlc291cmNlcyBhbGxvd2VkIGJ5IHBvb2w6ICR7bWlufS5gKTtcclxuICBsb2coNSwgYFtwb29sXSBUaGUgbWF4aW11bSBudW1iZXIgb2YgcmVzb3VyY2VzIGFsbG93ZWQgYnkgcG9vbDogJHttYXh9LmApO1xyXG4gIGxvZyg1LCBgW3Bvb2xdIFRoZSBudW1iZXIgb2YgdXNlZCByZXNvdXJjZXM6ICR7dXNlZH0uYCk7XHJcbiAgbG9nKDUsIGBbcG9vbF0gVGhlIG51bWJlciBvZiBmcmVlIHJlc291cmNlczogJHthdmFpbGFibGV9LmApO1xyXG4gIGxvZyhcclxuICAgIDUsXHJcbiAgICBgW3Bvb2xdIFRoZSBudW1iZXIgb2YgYWxsIGNyZWF0ZWQgKHVzZWQgYW5kIGZyZWUpIHJlc291cmNlczogJHthbGxDcmVhdGVkfS5gXHJcbiAgKTtcclxuICBsb2coXHJcbiAgICA1LFxyXG4gICAgYFtwb29sXSBUaGUgbnVtYmVyIG9mIHJlc291cmNlcyB3YWl0aW5nIHRvIGJlIGFjcXVpcmVkOiAke3BlbmRpbmdBY3F1aXJlc30uYFxyXG4gICk7XHJcbiAgbG9nKFxyXG4gICAgNSxcclxuICAgIGBbcG9vbF0gVGhlIG51bWJlciBvZiByZXNvdXJjZXMgd2FpdGluZyB0byBiZSBjcmVhdGVkOiAke3BlbmRpbmdDcmVhdGVzfS5gXHJcbiAgKTtcclxuICBsb2coXHJcbiAgICA1LFxyXG4gICAgYFtwb29sXSBUaGUgbnVtYmVyIG9mIHJlc291cmNlcyB3YWl0aW5nIHRvIGJlIHZhbGlkYXRlZDogJHtwZW5kaW5nVmFsaWRhdGlvbnN9LmBcclxuICApO1xyXG4gIGxvZyhcclxuICAgIDUsXHJcbiAgICBgW3Bvb2xdIFRoZSBudW1iZXIgb2YgcmVzb3VyY2VzIHdhaXRpbmcgdG8gYmUgZGVzdHJveWVkOiAke3BlbmRpbmdEZXN0cm95c30uYFxyXG4gICk7XHJcbiAgbG9nKDUsIGBbcG9vbF0gVGhlIG51bWJlciBvZiBhbGwgcmVzb3VyY2VzOiAke2Fic29sdXRlQWxsfS5gKTtcclxufVxyXG5cclxuLyoqXHJcbiAqIEZhY3RvcnkgZnVuY3Rpb24gdGhhdCByZXR1cm5zIGFuIG9iamVjdCB3aXRoIGBjcmVhdGVgLCBgdmFsaWRhdGVgLFxyXG4gKiBhbmQgYGRlc3Ryb3lgIGZ1bmN0aW9ucyBmb3IgdGhlIHBvb2wgaW5zdGFuY2UuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBfZmFjdG9yeVxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gcG9vbE9wdGlvbnMgLSBUaGUgY29uZmlndXJhdGlvbiBvYmplY3QgY29udGFpbmluZyBgcG9vbGBcclxuICogb3B0aW9ucy5cclxuICovXHJcbmZ1bmN0aW9uIF9mYWN0b3J5KHBvb2xPcHRpb25zKSB7XHJcbiAgcmV0dXJuIHtcclxuICAgIC8qKlxyXG4gICAgICogQ3JlYXRlcyBhIG5ldyB3b3JrZXIgcGFnZSBmb3IgdGhlIGV4cG9ydCBwb29sLlxyXG4gICAgICpcclxuICAgICAqIEBhc3luY1xyXG4gICAgICogQGZ1bmN0aW9uIGNyZWF0ZVxyXG4gICAgICpcclxuICAgICAqIEByZXR1cm5zIHtQcm9taXNlPE9iamVjdD59IEEgUHJvbWlzZSB0aGF0IHJlc29sdmVzIHRvIGFuIG9iamVjdFxyXG4gICAgICogY29udGFpbmluZyB0aGUgd29ya2VyIElELCBhIHJlZmVyZW5jZSB0byB0aGUgYnJvd3NlciBwYWdlLCBhbmQgaW5pdGlhbFxyXG4gICAgICogd29yayBjb3VudC5cclxuICAgICAqXHJcbiAgICAgKiBAdGhyb3dzIHtFeHBvcnRFcnJvcn0gVGhyb3dzIGFuIGBFeHBvcnRFcnJvcmAgaWYgdGhlcmUgaXMgYW4gZXJyb3IgZHVyaW5nXHJcbiAgICAgKiB0aGUgY3JlYXRpb24gb2YgdGhlIG5ldyBwYWdlLlxyXG4gICAgICovXHJcbiAgICBjcmVhdGU6IGFzeW5jICgpID0+IHtcclxuICAgICAgLy8gSW5pdCB0aGUgcmVzb3VyY2Ugd2l0aCB1bmlxdWUgaWQgYW5kIHdvcmsgY291bnRcclxuICAgICAgY29uc3QgcG9vbFJlc291cmNlID0ge1xyXG4gICAgICAgIGlkOiB1dWlkKCksXHJcbiAgICAgICAgLy8gVHJ5IHRvIGRpc3RyaWJ1dGUgdGhlIGluaXRpYWwgd29yayBjb3VudFxyXG4gICAgICAgIHdvcmtDb3VudDogTWF0aC5yb3VuZChNYXRoLnJhbmRvbSgpICogKHBvb2xPcHRpb25zLndvcmtMaW1pdCAvIDIpKVxyXG4gICAgICB9O1xyXG5cclxuICAgICAgdHJ5IHtcclxuICAgICAgICAvLyBTdGFydCBtZWFzdXJpbmcgYSBwYWdlIGNyZWF0aW9uIHRpbWVcclxuICAgICAgICBjb25zdCBzdGFydERhdGUgPSBnZXROZXdEYXRlVGltZSgpO1xyXG5cclxuICAgICAgICAvLyBDcmVhdGUgYSBuZXcgcGFnZVxyXG4gICAgICAgIGF3YWl0IG5ld1BhZ2UocG9vbFJlc291cmNlKTtcclxuXHJcbiAgICAgICAgLy8gTWVhc3VyZSB0aGUgdGltZSBvZiBmdWxsIGNyZWF0aW9uIGFuZCBjb25maWd1cmF0aW9uIG9mIGEgcGFnZVxyXG4gICAgICAgIGxvZyhcclxuICAgICAgICAgIDMsXHJcbiAgICAgICAgICBgW3Bvb2xdIFBvb2wgcmVzb3VyY2UgWyR7cG9vbFJlc291cmNlLmlkfV0gLSBTdWNjZXNzZnVsbHkgY3JlYXRlZCBhIHdvcmtlciwgdG9vayAke1xyXG4gICAgICAgICAgICBnZXROZXdEYXRlVGltZSgpIC0gc3RhcnREYXRlXHJcbiAgICAgICAgICB9bXMuYFxyXG4gICAgICAgICk7XHJcblxyXG4gICAgICAgIC8vIFJldHVybiByZWFkeSBwb29sIHJlc291cmNlXHJcbiAgICAgICAgcmV0dXJuIHBvb2xSZXNvdXJjZTtcclxuICAgICAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICAgICBsb2coXHJcbiAgICAgICAgICAzLFxyXG4gICAgICAgICAgYFtwb29sXSBQb29sIHJlc291cmNlIFske3Bvb2xSZXNvdXJjZS5pZH1dIC0gRXJyb3IgZW5jb3VudGVyZWQgd2hlbiBjcmVhdGluZyBhIG5ldyBwYWdlLmBcclxuICAgICAgICApO1xyXG4gICAgICAgIHRocm93IGVycm9yO1xyXG4gICAgICB9XHJcbiAgICB9LFxyXG5cclxuICAgIC8qKlxyXG4gICAgICogVmFsaWRhdGVzIGEgd29ya2VyIHBhZ2UgaW4gdGhlIGV4cG9ydCBwb29sLCBjaGVja2luZyBpZiBpdCBoYXMgZXhjZWVkZWRcclxuICAgICAqIHRoZSB3b3JrIGxpbWl0LlxyXG4gICAgICpcclxuICAgICAqIEBhc3luY1xyXG4gICAgICogQGZ1bmN0aW9uIHZhbGlkYXRlXHJcbiAgICAgKlxyXG4gICAgICogQHBhcmFtIHtPYmplY3R9IHBvb2xSZXNvdXJjZSAtIFRoZSBoYW5kbGUgdG8gdGhlIHdvcmtlciwgY29udGFpbmluZ1xyXG4gICAgICogdGhlIHdvcmtlcidzIElELCBhIHJlZmVyZW5jZSB0byB0aGUgYnJvd3NlciBwYWdlLCBhbmQgd29yayBjb3VudC5cclxuICAgICAqXHJcbiAgICAgKiBAcmV0dXJucyB7UHJvbWlzZTxib29sZWFuPn0gQSBQcm9taXNlIHRoYXQgcmVzb2x2ZXMgdG8gdHJ1ZSBpZiB0aGUgd29ya2VyXHJcbiAgICAgKiBpcyB2YWxpZCBhbmQgd2l0aGluIHRoZSB3b3JrIGxpbWl0OyBvdGhlcndpc2UsIHRvIGZhbHNlLlxyXG4gICAgICovXHJcbiAgICB2YWxpZGF0ZTogYXN5bmMgKHBvb2xSZXNvdXJjZSkgPT4ge1xyXG4gICAgICAvLyBOT1RFOlxyXG4gICAgICAvLyBJbiBjZXJ0YWluIGNhc2VzIGFjcXVpcmluZyB0aHJvd3MgYSBUYXJnZXRDbG9zZUVycm9yLCB3aGljaCBtYXlcclxuICAgICAgLy8gYmUgY2F1c2VkIGJ5IHR3byB0aGluZ3M6XHJcbiAgICAgIC8vIC0gVGhlIHBhZ2UgaXMgY2xvc2VkIGFuZCBhdHRlbXB0ZWQgdG8gYmUgcmV1c2VkLlxyXG4gICAgICAvLyAtIExvc3QgY29udGFjdCB3aXRoIHRoZSBicm93c2VyLlxyXG4gICAgICAvL1xyXG4gICAgICAvLyBXaGF0IHdlJ3JlIHNlZWluZyBpbiBsb2dzIGlzIHRoYXQgc3VjY2Vzc2l2ZSBleHBvcnRzIHR5cGljYWxseVxyXG4gICAgICAvLyBzdWNjZWVkcywgYW5kIHRoZSBzZXJ2ZXIgcmVjb3ZlcnMsIGluZGljYXRpbmcgdGhhdCBpdCdzIGxpa2VseVxyXG4gICAgICAvLyB0aGUgZmlyc3QgY2FzZS4gVGhpcyBpcyBhbiBhdHRlbXB0IGF0IGFsbGlldmF0aW5nIHRoZSBpc3N1ZSBieVxyXG4gICAgICAvLyBzaW1wbHkgbm90IHZhbGlkYXRpbmcgdGhlIHdvcmtlciBpZiB0aGUgcGFnZSBpcyBudWxsIG9yIGNsb3NlZC5cclxuICAgICAgLy9cclxuICAgICAgLy8gVGhlIGFjdHVhbCByZXN1bHQgZnJvbSB3aGVuIHRoaXMgaGFwcGVuZWQsIHdhcyB0aGF0IGEgd29ya2VyIHdvdWxkXHJcbiAgICAgIC8vIGJlIGNvbXBsZXRlbHkgbG9ja2VkLCBzdG9wcGluZyBpdCBmcm9tIGJlaW5nIGFjcXVpcmVkIHVudGlsXHJcbiAgICAgIC8vIGl0cyB3b3JrIGNvdW50IHJlYWNoZWQgdGhlIGxpbWl0LlxyXG5cclxuICAgICAgLy8gQ2hlY2sgaWYgdGhlIGBwYWdlYCBpcyB2YWxpZFxyXG4gICAgICBpZiAoIXBvb2xSZXNvdXJjZS5wYWdlKSB7XHJcbiAgICAgICAgbG9nKFxyXG4gICAgICAgICAgMyxcclxuICAgICAgICAgIGBbcG9vbF0gUG9vbCByZXNvdXJjZSBbJHtwb29sUmVzb3VyY2UuaWR9XSAtIFZhbGlkYXRpb24gZmFpbGVkIChubyB2YWxpZCBwYWdlIGlzIGZvdW5kKS5gXHJcbiAgICAgICAgKTtcclxuICAgICAgICByZXR1cm4gZmFsc2U7XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIC8vIENoZWNrIGlmIHRoZSBgcGFnZWAgaXMgY2xvc2VkXHJcbiAgICAgIGlmIChwb29sUmVzb3VyY2UucGFnZS5pc0Nsb3NlZCgpKSB7XHJcbiAgICAgICAgbG9nKFxyXG4gICAgICAgICAgMyxcclxuICAgICAgICAgIGBbcG9vbF0gUG9vbCByZXNvdXJjZSBbJHtwb29sUmVzb3VyY2UuaWR9XSAtIFZhbGlkYXRpb24gZmFpbGVkIChwYWdlIGlzIGNsb3NlZCBvciBpbnZhbGlkKS5gXHJcbiAgICAgICAgKTtcclxuICAgICAgICByZXR1cm4gZmFsc2U7XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIC8vIENoZWNrIGlmIHRoZSBgbWFpbkZyYW1lYCBpcyBkZXRhY2hlZFxyXG4gICAgICBpZiAocG9vbFJlc291cmNlLnBhZ2UubWFpbkZyYW1lKCkuZGV0YWNoZWQpIHtcclxuICAgICAgICBsb2coXHJcbiAgICAgICAgICAzLFxyXG4gICAgICAgICAgYFtwb29sXSBQb29sIHJlc291cmNlIFske3Bvb2xSZXNvdXJjZS5pZH1dIC0gVmFsaWRhdGlvbiBmYWlsZWQgKHBhZ2UncyBmcmFtZSBpcyBkZXRhY2hlZCkuYFxyXG4gICAgICAgICk7XHJcbiAgICAgICAgcmV0dXJuIGZhbHNlO1xyXG4gICAgICB9XHJcblxyXG4gICAgICAvLyBDaGVjayBpZiB0aGUgYHdvcmtMaW1pdGAgaXMgZXhjZWVkZWRcclxuICAgICAgaWYgKFxyXG4gICAgICAgIHBvb2xPcHRpb25zLndvcmtMaW1pdCAmJlxyXG4gICAgICAgICsrcG9vbFJlc291cmNlLndvcmtDb3VudCA+IHBvb2xPcHRpb25zLndvcmtMaW1pdFxyXG4gICAgICApIHtcclxuICAgICAgICBsb2coXHJcbiAgICAgICAgICAzLFxyXG4gICAgICAgICAgYFtwb29sXSBQb29sIHJlc291cmNlIFske3Bvb2xSZXNvdXJjZS5pZH1dIC0gVmFsaWRhdGlvbiBmYWlsZWQgKGV4Y2VlZGVkIHRoZSAke3Bvb2xPcHRpb25zLndvcmtMaW1pdH0gd29ya3MgcGVyIHJlc291cmNlIGxpbWl0KS5gXHJcbiAgICAgICAgKTtcclxuICAgICAgICByZXR1cm4gZmFsc2U7XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIC8vIFRoZSBgcG9vbFJlc291cmNlYCBpcyB2YWxpZGF0ZWRcclxuICAgICAgcmV0dXJuIHRydWU7XHJcbiAgICB9LFxyXG5cclxuICAgIC8qKlxyXG4gICAgICogRGVzdHJveXMgYSB3b3JrZXIgZW50cnkgaW4gdGhlIGV4cG9ydCBwb29sLCBjbG9zaW5nIGl0cyBhc3NvY2lhdGVkIHBhZ2UuXHJcbiAgICAgKlxyXG4gICAgICogQGFzeW5jXHJcbiAgICAgKiBAZnVuY3Rpb24gZGVzdHJveVxyXG4gICAgICpcclxuICAgICAqIEBwYXJhbSB7T2JqZWN0fSBwb29sUmVzb3VyY2UgLSBUaGUgaGFuZGxlIHRvIHRoZSB3b3JrZXIsIGNvbnRhaW5pbmdcclxuICAgICAqIHRoZSB3b3JrZXIncyBJRCwgYSByZWZlcmVuY2UgdG8gdGhlIGJyb3dzZXIgcGFnZSwgYW5kIHdvcmsgY291bnQuXHJcbiAgICAgKi9cclxuICAgIGRlc3Ryb3k6IGFzeW5jIChwb29sUmVzb3VyY2UpID0+IHtcclxuICAgICAgbG9nKFxyXG4gICAgICAgIDMsXHJcbiAgICAgICAgYFtwb29sXSBQb29sIHJlc291cmNlIFske3Bvb2xSZXNvdXJjZS5pZH1dIC0gRGVzdHJveWluZyBhIHdvcmtlci5gXHJcbiAgICAgICk7XHJcblxyXG4gICAgICBpZiAocG9vbFJlc291cmNlLnBhZ2UgJiYgIXBvb2xSZXNvdXJjZS5wYWdlLmlzQ2xvc2VkKCkpIHtcclxuICAgICAgICB0cnkge1xyXG4gICAgICAgICAgLy8gUmVtb3ZlIGFsbCBhdHRhY2hlZCBldmVudCBsaXN0ZW5lcnMgZnJvbSB0aGUgcmVzb3VyY2VcclxuICAgICAgICAgIHBvb2xSZXNvdXJjZS5wYWdlLnJlbW92ZUFsbExpc3RlbmVycygncGFnZWVycm9yJyk7XHJcbiAgICAgICAgICBwb29sUmVzb3VyY2UucGFnZS5yZW1vdmVBbGxMaXN0ZW5lcnMoJ2NvbnNvbGUnKTtcclxuICAgICAgICAgIHBvb2xSZXNvdXJjZS5wYWdlLnJlbW92ZUFsbExpc3RlbmVycygnZnJhbWVkZXRhY2hlZCcpO1xyXG5cclxuICAgICAgICAgIC8vIFdlIG5lZWQgdG8gd2FpdCBhcm91bmQgZm9yIHRoaXNcclxuICAgICAgICAgIGF3YWl0IHBvb2xSZXNvdXJjZS5wYWdlLmNsb3NlKCk7XHJcbiAgICAgICAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICAgICAgIGxvZyhcclxuICAgICAgICAgICAgMyxcclxuICAgICAgICAgICAgYFtwb29sXSBQb29sIHJlc291cmNlIFske3Bvb2xSZXNvdXJjZS5pZH1dIC0gUGFnZSBjb3VsZCBub3QgYmUgY2xvc2VkIHVwb24gZGVzdHJveWluZy5gXHJcbiAgICAgICAgICApO1xyXG4gICAgICAgICAgdGhyb3cgZXJyb3I7XHJcbiAgICAgICAgfVxyXG4gICAgICB9XHJcbiAgICB9XHJcbiAgfTtcclxufVxyXG5cclxuZXhwb3J0IGRlZmF1bHQge1xyXG4gIGluaXRQb29sLFxyXG4gIGtpbGxQb29sLFxyXG4gIHBvc3RXb3JrLFxyXG4gIGdldFBvb2wsXHJcbiAgZ2V0UG9vbFN0YXRzLFxyXG4gIGdldFBvb2xJbmZvLFxyXG4gIGdldFBvb2xJbmZvSlNPTlxyXG59O1xyXG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxyXG5cclxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXHJcblxyXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNSwgSGlnaHNvZnRcclxuXHJcbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cclxuXHJcbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxyXG5cclxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxyXG5cclxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cclxuXHJcbi8qKlxyXG4gKiBAb3ZlcnZpZXcgVXNlZCB0byBzYW5pdGl6ZSB0aGUgc3RyaW5ncyBjb21pbmcgZnJvbSB0aGUgZXhwb3J0aW5nIG1vZHVsZVxyXG4gKiB0byBwcmV2ZW50IFhTUyBhdHRhY2tzICh3aXRoIHRoZSBET01QdXJpZnkgbGlicmFyeSkuXHJcbiAqL1xyXG5cclxuaW1wb3J0IERPTVB1cmlmeSBmcm9tICdkb21wdXJpZnknO1xyXG5pbXBvcnQgeyBKU0RPTSB9IGZyb20gJ2pzZG9tJztcclxuXHJcbi8qKlxyXG4gKiBTYW5pdGl6ZXMgYSBnaXZlbiBIVE1MIHN0cmluZyBieSByZW1vdmluZyA8c2NyaXB0PiB0YWdzLiBUaGlzIGZ1bmN0aW9uIHVzZXNcclxuICogYSByZWd1bGFyIGV4cHJlc3Npb24gdG8gZmluZCBhbmQgcmVtb3ZlIGFsbCBvY2N1cnJlbmNlcyBvZiA8c2NyaXB0Pjwvc2NyaXB0PlxyXG4gKiB0YWdzIGFuZCBhbnkgY29udGVudCB3aXRoaW4gdGhlbS5cclxuICpcclxuICogQGZ1bmN0aW9uIHNhbml0aXplXHJcbiAqXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSBpbnB1dCAtIFRoZSBIVE1MIHN0cmluZyB0byBiZSBzYW5pdGl6ZWQuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtzdHJpbmd9IFRoZSBzYW5pdGl6ZWQgSFRNTCBzdHJpbmcuXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gc2FuaXRpemUoaW5wdXQpIHtcclxuICAvLyBHZXQgdGhlIHZpcnR1YWwgRE9NXHJcbiAgY29uc3Qgd2luZG93ID0gbmV3IEpTRE9NKCcnKS53aW5kb3c7XHJcblxyXG4gIC8vIENyZWF0ZSBhIHB1cmlmeWluZyBpbnN0YW5jZVxyXG4gIGNvbnN0IHB1cmlmeSA9IERPTVB1cmlmeSh3aW5kb3cpO1xyXG5cclxuICAvLyBSZXR1cm4gc2FuaXRpemVkIGlucHV0XHJcbiAgcmV0dXJuIHB1cmlmeS5zYW5pdGl6ZShpbnB1dCwgeyBBRERfVEFHUzogWydmb3JlaWduT2JqZWN0J10gfSk7XHJcbn1cclxuXHJcbmV4cG9ydCBkZWZhdWx0IHtcclxuICBzYW5pdGl6ZVxyXG59O1xyXG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxyXG5cclxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXHJcblxyXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNSwgSGlnaHNvZnRcclxuXHJcbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cclxuXHJcbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxyXG5cclxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxyXG5cclxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cclxuXHJcbi8qKlxyXG4gKiBAb3ZlcnZpZXcgVGhpcyBtb2R1bGUgcHJvdmlkZXMgZnVuY3Rpb25zIHRvIHByZXBhcmUgZm9yIHRoZSBleHBvcnRpbmcgY2hhcnRzXHJcbiAqIGludG8gdmFyaW91cyBpbWFnZSBvdXRwdXQgZm9ybWF0cyBzdWNoIGFzIEpQRUcsIFBORywgUERGLCBhbmQgU1ZHcy5cclxuICogSXQgc3VwcG9ydHMgc2luZ2xlIGFuZCBiYXRjaCBleHBvcnQgb3BlcmF0aW9ucyBhbmQgYWxsb3dzIGN1c3RvbWl6YXRpb25cclxuICogdGhyb3VnaCBvcHRpb25zIHBhc3NlZCBmcm9tIGNvbmZpZ3VyYXRpb25zIG9yIEFQSXMuXHJcbiAqL1xyXG5cclxuaW1wb3J0IHsgcmVhZEZpbGVTeW5jLCB3cml0ZUZpbGVTeW5jIH0gZnJvbSAnZnMnO1xyXG5cclxuaW1wb3J0IHtcclxuICBpc0FsbG93ZWRDb25maWcsXHJcbiAgdXBkYXRlT3B0aW9ucyxcclxuICB2YWxpZGF0ZU9wdGlvbixcclxuICB2YWxpZGF0ZU9wdGlvbnNcclxufSBmcm9tICcuL2NvbmZpZy5qcyc7XHJcbmltcG9ydCB7IGxvZywgbG9nV2l0aFN0YWNrIH0gZnJvbSAnLi9sb2dnZXIuanMnO1xyXG5pbXBvcnQgeyBnZXRQb29sU3RhdHMsIGtpbGxQb29sLCBwb3N0V29yayB9IGZyb20gJy4vcG9vbC5qcyc7XHJcbmltcG9ydCB7IHNhbml0aXplIH0gZnJvbSAnLi9zYW5pdGl6ZS5qcyc7XHJcbmltcG9ydCB7XHJcbiAgZml4Q29uc3RyLFxyXG4gIGZpeE91dGZpbGUsXHJcbiAgZml4VHlwZSxcclxuICBnZXRBYnNvbHV0ZVBhdGgsXHJcbiAgZ2V0QmFzZTY0LFxyXG4gIGlzT2JqZWN0LFxyXG4gIHJvdW5kTnVtYmVyLFxyXG4gIHdyYXBBcm91bmRcclxufSBmcm9tICcuL3V0aWxzLmpzJztcclxuXHJcbmltcG9ydCBFeHBvcnRFcnJvciBmcm9tICcuL2Vycm9ycy9FeHBvcnRFcnJvci5qcyc7XHJcblxyXG4vLyBUaGUgZ2xvYmFsIGZsYWcgZm9yIHRoZSBjb2RlIGV4ZWN1dGlvbiBwZXJtaXNzaW9uXHJcbmxldCBhbGxvd0NvZGVFeGVjdXRpb24gPSBmYWxzZTtcclxuXHJcbi8qKlxyXG4gKiBTdGFydHMgYSBzaW5nbGUgZXhwb3J0IHByb2Nlc3MgYmFzZWQgb24gdGhlIHNwZWNpZmllZCBvcHRpb25zIGFuZCBzYXZlc1xyXG4gKiB0aGUgcmVzdWx0aW5nIGltYWdlIHRvIHRoZSBwcm92aWRlZCBvdXRwdXQgZmlsZS5cclxuICpcclxuICogQGFzeW5jXHJcbiAqIEBmdW5jdGlvbiBzaW5nbGVFeHBvcnRcclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IG9wdGlvbnMgLSBUaGUgYG9wdGlvbnNgIG9iamVjdCwgd2hpY2ggc2hvdWxkIGluY2x1ZGUgc2V0dGluZ3NcclxuICogZnJvbSB0aGUgYGV4cG9ydGAgYW5kIGBjdXN0b21Mb2dpY2Agc2VjdGlvbnMuIEl0IGNhbiBiZSBhIHBhcnRpYWwgb3IgY29tcGxldGVcclxuICogc2V0IG9mIG9wdGlvbnMgZnJvbSB0aGVzZSBzZWN0aW9ucy4gVGhlIG9iamVjdCBtdXN0IGNvbnRhaW4gYXQgbGVhc3Qgb25lXHJcbiAqIG9mIHRoZSBmb2xsb3dpbmcgYGV4cG9ydGAgcHJvcGVydGllczogYGluZmlsZWAsIGBpbnN0cmAsIGBvcHRpb25zYCwgb3IgYHN2Z2BcclxuICogdG8gZ2VuZXJhdGUgYSB2YWxpZCBpbWFnZS5cclxuICpcclxuICogQHJldHVybnMge1Byb21pc2U8dm9pZD59IEEgUHJvbWlzZSB0aGF0IHJlc29sdmVzIG9uY2UgdGhlIHNpbmdsZSBleHBvcnRcclxuICogcHJvY2VzcyBpcyBjb21wbGV0ZWQuXHJcbiAqXHJcbiAqIEB0aHJvd3Mge0V4cG9ydEVycm9yfSBUaHJvd3MgYW4gYEV4cG9ydEVycm9yYCBpZiBhbiBlcnJvciBvY2N1cnMgZHVyaW5nXHJcbiAqIHRoZSBzaW5nbGUgZXhwb3J0IHByb2Nlc3MuXHJcbiAqL1xyXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gc2luZ2xlRXhwb3J0KG9wdGlvbnMpIHtcclxuICAvLyBDaGVjayBpZiB0aGUgZXhwb3J0IG1ha2VzIHNlbnNlXHJcbiAgaWYgKG9wdGlvbnMgJiYgb3B0aW9ucy5leHBvcnQpIHtcclxuICAgIC8vIFZhbGlkYXRlIHNpbmdsZSBleHBvcnQgb3B0aW9uc1xyXG4gICAgb3B0aW9ucyA9IHZhbGlkYXRlT3B0aW9ucyhvcHRpb25zKTtcclxuXHJcbiAgICAvLyBQZXJmb3JtIGFuIGV4cG9ydFxyXG4gICAgYXdhaXQgc3RhcnRFeHBvcnQoXHJcbiAgICAgIHsgZXhwb3J0OiBvcHRpb25zLmV4cG9ydCwgY3VzdG9tTG9naWM6IG9wdGlvbnMuY3VzdG9tTG9naWMgfSxcclxuICAgICAgYXN5bmMgKGVycm9yLCBkYXRhKSA9PiB7XHJcbiAgICAgICAgLy8gRXhpdCBwcm9jZXNzIHdoZW4gZXJyb3IgZXhpc3RzXHJcbiAgICAgICAgaWYgKGVycm9yKSB7XHJcbiAgICAgICAgICB0aHJvdyBlcnJvcjtcclxuICAgICAgICB9XHJcblxyXG4gICAgICAgIC8vIEdldCB0aGUgYGI2NGAsIGBvdXRmaWxlYCwgYW5kIGB0eXBlYCBmb3IgYSBjaGFydFxyXG4gICAgICAgIGNvbnN0IHsgYjY0LCBvdXRmaWxlLCB0eXBlIH0gPSBkYXRhLm9wdGlvbnMuZXhwb3J0O1xyXG5cclxuICAgICAgICAvLyBTYXZlIHRoZSByZXN1bHRcclxuICAgICAgICB0cnkge1xyXG4gICAgICAgICAgaWYgKGI2NCkge1xyXG4gICAgICAgICAgICAvLyBBcyBhIEJhc2U2NCBzdHJpbmcgdG8gYSB0eHQgZmlsZVxyXG4gICAgICAgICAgICB3cml0ZUZpbGVTeW5jKFxyXG4gICAgICAgICAgICAgIGAke291dGZpbGUuc3BsaXQoJy4nKS5zaGlmdCgpIHx8ICdjaGFydCd9LnR4dGAsXHJcbiAgICAgICAgICAgICAgZ2V0QmFzZTY0KGRhdGEucmVzdWx0LCB0eXBlKVxyXG4gICAgICAgICAgICApO1xyXG4gICAgICAgICAgfSBlbHNlIHtcclxuICAgICAgICAgICAgLy8gQXMgYSBjb3JyZWN0IGltYWdlIGZvcm1hdFxyXG4gICAgICAgICAgICB3cml0ZUZpbGVTeW5jKFxyXG4gICAgICAgICAgICAgIG91dGZpbGUgfHwgYGNoYXJ0LiR7dHlwZX1gLFxyXG4gICAgICAgICAgICAgIHR5cGUgIT09ICdzdmcnID8gQnVmZmVyLmZyb20oZGF0YS5yZXN1bHQsICdiYXNlNjQnKSA6IGRhdGEucmVzdWx0XHJcbiAgICAgICAgICAgICk7XHJcbiAgICAgICAgICB9XHJcbiAgICAgICAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICAgICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcihcclxuICAgICAgICAgICAgJ1tjaGFydF0gRXJyb3Igd2hpbGUgc2F2aW5nIGEgY2hhcnQuJyxcclxuICAgICAgICAgICAgNTAwXHJcbiAgICAgICAgICApLnNldEVycm9yKGVycm9yKTtcclxuICAgICAgICB9XHJcblxyXG4gICAgICAgIC8vIEtpbGwgcG9vbCBhbmQgY2xvc2UgYnJvd3NlciBhZnRlciBmaW5pc2hpbmcgc2luZ2xlIGV4cG9ydFxyXG4gICAgICAgIGF3YWl0IGtpbGxQb29sKCk7XHJcbiAgICAgIH1cclxuICAgICk7XHJcbiAgfSBlbHNlIHtcclxuICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcihcclxuICAgICAgJ1tjaGFydF0gTm8gZXhwZWN0ZWQgYGV4cG9ydGAgb3B0aW9ucyB3ZXJlIGZvdW5kLiBQbGVhc2UgcHJvdmlkZSBvbmUgb2YgdGhlIGZvbGxvd2luZyBvcHRpb25zOiBgaW5maWxlYCwgYGluc3RyYCwgYG9wdGlvbnNgLCBvciBgc3ZnYCB0byBnZW5lcmF0ZSBhIHZhbGlkIGltYWdlLicsXHJcbiAgICAgIDQwMFxyXG4gICAgKTtcclxuICB9XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBTdGFydHMgYSBiYXRjaCBleHBvcnQgcHJvY2VzcyBmb3IgbXVsdGlwbGUgY2hhcnRzIGJhc2VkIG9uIGluZm9ybWF0aW9uXHJcbiAqIHByb3ZpZGVkIGluIHRoZSBgYmF0Y2hgIG9wdGlvbi4gVGhlIGBiYXRjaGAgaXMgYSBzdHJpbmcgaW4gdGhlIGZvbGxvd2luZ1xyXG4gKiBmb3JtYXQ6IFwiaW5maWxlMS5qc29uPW91dGZpbGUxLnBuZztpbmZpbGUyLmpzb249b3V0ZmlsZTIucG5nOy4uLlwiLiBSZXN1bHRzXHJcbiAqIGFyZSBzYXZlZCB0byB0aGUgc3BlY2lmaWVkIG91dHB1dCBmaWxlcy5cclxuICpcclxuICogQGFzeW5jXHJcbiAqIEBmdW5jdGlvbiBiYXRjaEV4cG9ydFxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gb3B0aW9ucyAtIFRoZSBgb3B0aW9uc2Agb2JqZWN0LCB3aGljaCBzaG91bGQgaW5jbHVkZSBzZXR0aW5nc1xyXG4gKiBmcm9tIHRoZSBgZXhwb3J0YCBhbmQgYGN1c3RvbUxvZ2ljYCBzZWN0aW9ucy4gSXQgY2FuIGJlIGEgcGFydGlhbCBvciBjb21wbGV0ZVxyXG4gKiBzZXQgb2Ygb3B0aW9ucyBmcm9tIHRoZXNlIHNlY3Rpb25zLiBJdCBtdXN0IGNvbnRhaW4gdGhlIGBiYXRjaGAgb3B0aW9uIGZyb21cclxuICogdGhlIGBleHBvcnRgIHNlY3Rpb24gdG8gZ2VuZXJhdGUgdmFsaWQgaW1hZ2VzLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7UHJvbWlzZTx2b2lkPn0gQSBQcm9taXNlIHRoYXQgcmVzb2x2ZXMgb25jZSB0aGUgYmF0Y2ggZXhwb3J0XHJcbiAqIHByb2Nlc3NlcyBhcmUgY29tcGxldGVkLlxyXG4gKlxyXG4gKiBAdGhyb3dzIHtFeHBvcnRFcnJvcn0gVGhyb3dzIGFuIGBFeHBvcnRFcnJvcmAgaWYgYW4gZXJyb3Igb2NjdXJzIGR1cmluZ1xyXG4gKiBhbnkgb2YgdGhlIGJhdGNoIGV4cG9ydCBwcm9jZXNzLlxyXG4gKi9cclxuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIGJhdGNoRXhwb3J0KG9wdGlvbnMpIHtcclxuICAvLyBDaGVjayBpZiB0aGUgZXhwb3J0IG1ha2VzIHNlbnNlXHJcbiAgaWYgKG9wdGlvbnMgJiYgb3B0aW9ucy5leHBvcnQgJiYgb3B0aW9ucy5leHBvcnQuYmF0Y2gpIHtcclxuICAgIC8vIFZhbGlkYXRlIGJhdGNoIGV4cG9ydCBvcHRpb25zXHJcbiAgICBvcHRpb25zID0gdmFsaWRhdGVPcHRpb25zKG9wdGlvbnMpO1xyXG5cclxuICAgIC8vIEFuIGFycmF5IGZvciBjb2xsZWN0aW5nIGJhdGNoIGV4cG9ydHNcclxuICAgIGNvbnN0IGJhdGNoRnVuY3Rpb25zID0gW107XHJcblxyXG4gICAgLy8gU3BsaXQgYW5kIHBhaXIgdGhlIGBiYXRjaGAgYXJndW1lbnRzXHJcbiAgICBmb3IgKGxldCBwYWlyIG9mIG9wdGlvbnMuZXhwb3J0LmJhdGNoLnNwbGl0KCc7JykgfHwgW10pIHtcclxuICAgICAgcGFpciA9IHBhaXIuc3BsaXQoJz0nKTtcclxuICAgICAgaWYgKHBhaXIubGVuZ3RoID09PSAyKSB7XHJcbiAgICAgICAgYmF0Y2hGdW5jdGlvbnMucHVzaChcclxuICAgICAgICAgIHN0YXJ0RXhwb3J0KFxyXG4gICAgICAgICAgICB7XHJcbiAgICAgICAgICAgICAgZXhwb3J0OiB7XHJcbiAgICAgICAgICAgICAgICAuLi5vcHRpb25zLmV4cG9ydCxcclxuICAgICAgICAgICAgICAgIGluZmlsZTogcGFpclswXSxcclxuICAgICAgICAgICAgICAgIG91dGZpbGU6IHBhaXJbMV1cclxuICAgICAgICAgICAgICB9LFxyXG4gICAgICAgICAgICAgIGN1c3RvbUxvZ2ljOiBvcHRpb25zLmN1c3RvbUxvZ2ljXHJcbiAgICAgICAgICAgIH0sXHJcbiAgICAgICAgICAgIChlcnJvciwgZGF0YSkgPT4ge1xyXG4gICAgICAgICAgICAgIC8vIEV4aXQgcHJvY2VzcyB3aGVuIGVycm9yIGV4aXN0c1xyXG4gICAgICAgICAgICAgIGlmIChlcnJvcikge1xyXG4gICAgICAgICAgICAgICAgdGhyb3cgZXJyb3I7XHJcbiAgICAgICAgICAgICAgfVxyXG5cclxuICAgICAgICAgICAgICAvLyBHZXQgdGhlIGBiNjRgLCBgb3V0ZmlsZWAsIGFuZCBgdHlwZWAgZm9yIGEgY2hhcnRcclxuICAgICAgICAgICAgICBjb25zdCB7IGI2NCwgb3V0ZmlsZSwgdHlwZSB9ID0gZGF0YS5vcHRpb25zLmV4cG9ydDtcclxuXHJcbiAgICAgICAgICAgICAgLy8gU2F2ZSB0aGUgcmVzdWx0XHJcbiAgICAgICAgICAgICAgdHJ5IHtcclxuICAgICAgICAgICAgICAgIGlmIChiNjQpIHtcclxuICAgICAgICAgICAgICAgICAgLy8gQXMgYSBCYXNlNjQgc3RyaW5nIHRvIGEgdHh0IGZpbGVcclxuICAgICAgICAgICAgICAgICAgd3JpdGVGaWxlU3luYyhcclxuICAgICAgICAgICAgICAgICAgICBgJHtvdXRmaWxlLnNwbGl0KCcuJykuc2hpZnQoKSB8fCAnY2hhcnQnfS50eHRgLFxyXG4gICAgICAgICAgICAgICAgICAgIGdldEJhc2U2NChkYXRhLnJlc3VsdCwgdHlwZSlcclxuICAgICAgICAgICAgICAgICAgKTtcclxuICAgICAgICAgICAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgICAgICAgICAgIC8vIEFzIGEgY29ycmVjdCBpbWFnZSBmb3JtYXRcclxuICAgICAgICAgICAgICAgICAgd3JpdGVGaWxlU3luYyhcclxuICAgICAgICAgICAgICAgICAgICBvdXRmaWxlLFxyXG4gICAgICAgICAgICAgICAgICAgIHR5cGUgIT09ICdzdmcnXHJcbiAgICAgICAgICAgICAgICAgICAgICA/IEJ1ZmZlci5mcm9tKGRhdGEucmVzdWx0LCAnYmFzZTY0JylcclxuICAgICAgICAgICAgICAgICAgICAgIDogZGF0YS5yZXN1bHRcclxuICAgICAgICAgICAgICAgICAgKTtcclxuICAgICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgICAgICAgICAgICAgdGhyb3cgbmV3IEV4cG9ydEVycm9yKFxyXG4gICAgICAgICAgICAgICAgICAnW2NoYXJ0XSBFcnJvciB3aGlsZSBzYXZpbmcgYSBjaGFydC4nLFxyXG4gICAgICAgICAgICAgICAgICA1MDBcclxuICAgICAgICAgICAgICAgICkuc2V0RXJyb3IoZXJyb3IpO1xyXG4gICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgfVxyXG4gICAgICAgICAgKVxyXG4gICAgICAgICk7XHJcbiAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgbG9nKDIsICdbY2hhcnRdIE5vIGNvcnJlY3QgcGFpciBmb3VuZCBmb3IgdGhlIGJhdGNoIGV4cG9ydC4nKTtcclxuICAgICAgfVxyXG4gICAgfVxyXG5cclxuICAgIC8vIEF3YWl0IGFsbCBleHBvcnRzIGFyZSBkb25lXHJcbiAgICBjb25zdCBiYXRjaFJlc3VsdHMgPSBhd2FpdCBQcm9taXNlLmFsbFNldHRsZWQoYmF0Y2hGdW5jdGlvbnMpO1xyXG5cclxuICAgIC8vIEtpbGwgcG9vbCBhbmQgY2xvc2UgYnJvd3NlciBhZnRlciBmaW5pc2hpbmcgYmF0Y2ggZXhwb3J0XHJcbiAgICBhd2FpdCBraWxsUG9vbCgpO1xyXG5cclxuICAgIC8vIExvZyBlcnJvcnMgaWYgZm91bmRcclxuICAgIGJhdGNoUmVzdWx0cy5mb3JFYWNoKChyZXN1bHQsIGluZGV4KSA9PiB7XHJcbiAgICAgIC8vIExvZyB0aGUgZXJyb3Igd2l0aCBzdGFjayBhYm91dCB0aGUgc3BlY2lmaWMgYmF0Y2ggZXhwb3J0XHJcbiAgICAgIGlmIChyZXN1bHQucmVhc29uKSB7XHJcbiAgICAgICAgbG9nV2l0aFN0YWNrKFxyXG4gICAgICAgICAgMSxcclxuICAgICAgICAgIHJlc3VsdC5yZWFzb24sXHJcbiAgICAgICAgICBgW2NoYXJ0XSBCYXRjaCBleHBvcnQgbnVtYmVyICR7aW5kZXggKyAxfSBjb3VsZCBub3QgYmUgY29ycmVjdGx5IGNvbXBsZXRlZC5gXHJcbiAgICAgICAgKTtcclxuICAgICAgfVxyXG4gICAgfSk7XHJcbiAgfSBlbHNlIHtcclxuICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcihcclxuICAgICAgJ1tjaGFydF0gTm8gZXhwZWN0ZWQgYGV4cG9ydGAgb3B0aW9ucyB3ZXJlIGZvdW5kLiBQbGVhc2UgcHJvdmlkZSB0aGUgYGJhdGNoYCBvcHRpb24gdG8gZ2VuZXJhdGUgdmFsaWQgaW1hZ2VzLicsXHJcbiAgICAgIDQwMFxyXG4gICAgKTtcclxuICB9XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBTdGFydHMgYW4gZXhwb3J0IHByb2Nlc3MuIFRoZSBgaW1hZ2VPcHRpb25zYCBwYXJhbWV0ZXIgaXMgYW4gb2JqZWN0IHRoYXRcclxuICogc2hvdWxkIGluY2x1ZGUgc2V0dGluZ3MgZnJvbSB0aGUgYGV4cG9ydGAgYW5kIGBjdXN0b21Mb2dpY2Agc2VjdGlvbnMuIEl0IGNhblxyXG4gKiBiZSBhIHBhcnRpYWwgb3IgY29tcGxldGUgc2V0IG9mIG9wdGlvbnMgZnJvbSB0aGVzZSBzZWN0aW9ucy4gSWYgcGFydGlhbFxyXG4gKiBvcHRpb25zIGFyZSBwcm92aWRlZCwgbWlzc2luZyB2YWx1ZXMgd2lsbCBiZSBtZXJnZWQgd2l0aCB0aGUgY3VycmVudCBnbG9iYWxcclxuICogb3B0aW9ucy5cclxuICpcclxuICogVGhlIGBlbmRDYWxsYmFja2AgZnVuY3Rpb24gaXMgaW52b2tlZCB1cG9uIHRoZSBjb21wbGV0aW9uIG9mIHRoZSBleHBvcnQsXHJcbiAqIGVpdGhlciBzdWNjZXNzZnVsbHkgb3Igd2l0aCBhbiBlcnJvci4gVGhlIGBlcnJvcmAgb2JqZWN0IGlzIHByb3ZpZGVkXHJcbiAqIGFzIHRoZSBmaXJzdCBhcmd1bWVudCwgYW5kIHRoZSBgZGF0YWAgb2JqZWN0IGlzIHRoZSBzZWNvbmQsIGNvbnRhaW5pbmdcclxuICogdGhlIEJhc2U2NCByZXByZXNlbnRhdGlvbiBvZiB0aGUgY2hhcnQgaW4gdGhlIGByZXN1bHRgIHByb3BlcnR5XHJcbiAqIGFuZCB0aGUgY29tcGxldGUgc2V0IG9mIG9wdGlvbnMgaW4gdGhlIGBvcHRpb25zYCBwcm9wZXJ0eS5cclxuICpcclxuICogQGFzeW5jXHJcbiAqIEBmdW5jdGlvbiBzdGFydEV4cG9ydFxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gaW1hZ2VPcHRpb25zIC0gVGhlIGBpbWFnZU9wdGlvbnNgIG9iamVjdCwgd2hpY2ggc2hvdWxkXHJcbiAqIGluY2x1ZGUgc2V0dGluZ3MgZnJvbSB0aGUgYGV4cG9ydGAgYW5kIGBjdXN0b21Mb2dpY2Agc2VjdGlvbnMuIEl0IGNhblxyXG4gKiBiZSBhIHBhcnRpYWwgb3IgY29tcGxldGUgc2V0IG9mIG9wdGlvbnMgZnJvbSB0aGVzZSBzZWN0aW9ucy4gSWYgdGhlIHByb3ZpZGVkXHJcbiAqIG9wdGlvbnMgYXJlIHBhcnRpYWwsIG1pc3NpbmcgdmFsdWVzIHdpbGwgYmUgbWVyZ2VkIHdpdGggdGhlIGN1cnJlbnQgZ2xvYmFsXHJcbiAqIG9wdGlvbnMuXHJcbiAqIEBwYXJhbSB7RnVuY3Rpb259IGVuZENhbGxiYWNrIC0gVGhlIGNhbGxiYWNrIGZ1bmN0aW9uIHRvIGJlIGludm9rZWQgdXBvblxyXG4gKiBmaW5hbGl6aW5nIHRoZSBleHBvcnQgcHJvY2VzcyBvciB1cG9uIGVuY291bnRlcmluZyBhbiBlcnJvci4gVGhlIGZpcnN0XHJcbiAqIGFyZ3VtZW50IGlzIHRoZSBgZXJyb3JgIG9iamVjdCwgYW5kIHRoZSBzZWNvbmQgYXJndW1lbnQgaXMgdGhlIGBkYXRhYCBvYmplY3QsXHJcbiAqIHdoaWNoIGluY2x1ZGVzIHRoZSBCYXNlNjQgcmVwcmVzZW50YXRpb24gb2YgdGhlIGNoYXJ0IGluIHRoZSBgcmVzdWx0YFxyXG4gKiBwcm9wZXJ0eSBhbmQgdGhlIGZ1bGwgc2V0IG9mIG9wdGlvbnMgaW4gdGhlIGBvcHRpb25zYCBwcm9wZXJ0eS5cclxuICpcclxuICogQHJldHVybnMge1Byb21pc2U8dm9pZD59IFRoaXMgZnVuY3Rpb24gZG9lcyBub3QgcmV0dXJuIGEgdmFsdWUgZGlyZWN0bHkuXHJcbiAqIEluc3RlYWQsIGl0IGNvbW11bmljYXRlcyByZXN1bHRzIHZpYSB0aGUgYGVuZENhbGxiYWNrYC5cclxuICpcclxuICogQHRocm93cyB7RXhwb3J0RXJyb3J9IFRocm93cyBhbiBgRXhwb3J0RXJyb3JgIGlmIHRoZXJlIGlzIGEgcHJvYmxlbSB3aXRoXHJcbiAqIHByb2Nlc3NpbmcgaW5wdXQgb2YgYW55IHR5cGUuIFRoZSBlcnJvciBpcyBwYXNzZWQgaW50byB0aGUgYGVuZENhbGxiYWNrYFxyXG4gKiBmdW5jdGlvbiBhbmQgcHJvY2Vzc2VkIHRoZXJlLlxyXG4gKi9cclxuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIHN0YXJ0RXhwb3J0KGltYWdlT3B0aW9ucywgZW5kQ2FsbGJhY2spIHtcclxuICB0cnkge1xyXG4gICAgLy8gQ2hlY2sgaWYgcHJvdmlkZWQgb3B0aW9ucyBhcmUgaW4gYW4gb2JqZWN0XHJcbiAgICBpZiAoIWlzT2JqZWN0KGltYWdlT3B0aW9ucykpIHtcclxuICAgICAgdGhyb3cgbmV3IEV4cG9ydEVycm9yKFxyXG4gICAgICAgICdbY2hhcnRdIEluY29ycmVjdCB2YWx1ZSBvZiB0aGUgcHJvdmlkZWQgYGltYWdlT3B0aW9uc2AuIE5lZWRzIHRvIGJlIGFuIG9iamVjdC4nLFxyXG4gICAgICAgIDQwMFxyXG4gICAgICApO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIE1lcmdlIGFkZGl0aW9uYWwgb3B0aW9ucyB0byB0aGUgY29weSBvZiB0aGUgaW5zdGFuY2Ugb3B0aW9uc1xyXG4gICAgY29uc3Qgb3B0aW9ucyA9IHVwZGF0ZU9wdGlvbnMoXHJcbiAgICAgIHtcclxuICAgICAgICBleHBvcnQ6IGltYWdlT3B0aW9ucy5leHBvcnQsXHJcbiAgICAgICAgY3VzdG9tTG9naWM6IGltYWdlT3B0aW9ucy5jdXN0b21Mb2dpY1xyXG4gICAgICB9LFxyXG4gICAgICB0cnVlXHJcbiAgICApO1xyXG5cclxuICAgIC8vIEdldCB0aGUgYGV4cG9ydGAgb3B0aW9uc1xyXG4gICAgY29uc3QgZXhwb3J0T3B0aW9ucyA9IG9wdGlvbnMuZXhwb3J0O1xyXG5cclxuICAgIC8vIFN0YXJ0aW5nIGV4cG9ydGluZyBwcm9jZXNzIG1lc3NhZ2VcclxuICAgIGxvZyg0LCAnW2NoYXJ0XSBTdGFydGluZyB0aGUgZXhwb3J0aW5nIHByb2Nlc3MuJyk7XHJcblxyXG4gICAgLy8gRXhwb3J0IHVzaW5nIG9wdGlvbnMgZnJvbSB0aGUgZmlsZSBhcyBhbiBpbnB1dFxyXG4gICAgaWYgKGV4cG9ydE9wdGlvbnMuaW5maWxlICE9PSBudWxsKSB7XHJcbiAgICAgIGxvZyg0LCAnW2NoYXJ0XSBBdHRlbXB0aW5nIHRvIGV4cG9ydCBmcm9tIGEgZmlsZSBpbnB1dC4nKTtcclxuXHJcbiAgICAgIGxldCBmaWxlQ29udGVudDtcclxuICAgICAgdHJ5IHtcclxuICAgICAgICAvLyBUcnkgdG8gcmVhZCB0aGUgZmlsZSB0byBnZXQgdGhlIHN0cmluZyByZXByZXNlbnRhdGlvblxyXG4gICAgICAgIGZpbGVDb250ZW50ID0gcmVhZEZpbGVTeW5jKFxyXG4gICAgICAgICAgZ2V0QWJzb2x1dGVQYXRoKGV4cG9ydE9wdGlvbnMuaW5maWxlKSxcclxuICAgICAgICAgICd1dGY4J1xyXG4gICAgICAgICk7XHJcbiAgICAgIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICAgICAgdGhyb3cgbmV3IEV4cG9ydEVycm9yKFxyXG4gICAgICAgICAgJ1tjaGFydF0gRXJyb3IgbG9hZGluZyBjb250ZW50IGZyb20gYSBmaWxlIGlucHV0LicsXHJcbiAgICAgICAgICA0MDBcclxuICAgICAgICApLnNldEVycm9yKGVycm9yKTtcclxuICAgICAgfVxyXG5cclxuICAgICAgLy8gQ2hlY2sgdGhlIGZpbGUncyBleHRlbnNpb25cclxuICAgICAgaWYgKGV4cG9ydE9wdGlvbnMuaW5maWxlLmVuZHNXaXRoKCcuc3ZnJykpIHtcclxuICAgICAgICAvLyBTZXQgdG8gdGhlIGBzdmdgIG9wdGlvblxyXG4gICAgICAgIGV4cG9ydE9wdGlvbnMuc3ZnID0gdmFsaWRhdGVPcHRpb24oJ3N2ZycsIGZpbGVDb250ZW50KTtcclxuICAgICAgfSBlbHNlIGlmIChleHBvcnRPcHRpb25zLmluZmlsZS5lbmRzV2l0aCgnLmpzb24nKSkge1xyXG4gICAgICAgIC8vIFNldCB0byB0aGUgYGluc3RyYCBvcHRpb25cclxuICAgICAgICBleHBvcnRPcHRpb25zLmluc3RyID0gdmFsaWRhdGVPcHRpb24oJ2luc3RyJywgZmlsZUNvbnRlbnQpO1xyXG4gICAgICB9IGVsc2Uge1xyXG4gICAgICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcihcclxuICAgICAgICAgICdbY2hhcnRdIEluY29ycmVjdCB2YWx1ZSBvZiB0aGUgYGluZmlsZWAgb3B0aW9uLicsXHJcbiAgICAgICAgICA0MDBcclxuICAgICAgICApO1xyXG4gICAgICB9XHJcbiAgICB9XHJcblxyXG4gICAgLy8gRXhwb3J0IHVzaW5nIFNWRyBhcyBhbiBpbnB1dFxyXG4gICAgaWYgKGV4cG9ydE9wdGlvbnMuc3ZnICE9PSBudWxsKSB7XHJcbiAgICAgIGxvZyg0LCAnW2NoYXJ0XSBBdHRlbXB0aW5nIHRvIGV4cG9ydCBmcm9tIGFuIFNWRyBpbnB1dC4nKTtcclxuXHJcbiAgICAgIC8vIFNWRyBleHBvcnRzIGF0dGVtcHRzIGNvdW50ZXJcclxuICAgICAgKytnZXRQb29sU3RhdHMoKS5leHBvcnRzRnJvbVN2Z0F0dGVtcHRzO1xyXG5cclxuICAgICAgLy8gRXhwb3J0IGZyb20gYW4gU1ZHIHN0cmluZ1xyXG4gICAgICBjb25zdCByZXN1bHQgPSBhd2FpdCBfZXhwb3J0RnJvbVN2ZyhcclxuICAgICAgICBzYW5pdGl6ZShleHBvcnRPcHRpb25zLnN2ZyksIC8vICMyMDlcclxuICAgICAgICBvcHRpb25zXHJcbiAgICAgICk7XHJcblxyXG4gICAgICAvLyBTVkcgZXhwb3J0cyBjb3VudGVyXHJcbiAgICAgICsrZ2V0UG9vbFN0YXRzKCkuZXhwb3J0c0Zyb21Tdmc7XHJcblxyXG4gICAgICAvLyBQYXNzIFNWRyBleHBvcnQgcmVzdWx0IHRvIHRoZSBlbmQgY2FsbGJhY2tcclxuICAgICAgcmV0dXJuIGVuZENhbGxiYWNrKG51bGwsIHJlc3VsdCk7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gRXhwb3J0IHVzaW5nIG9wdGlvbnMgYXMgYW4gaW5wdXRcclxuICAgIGlmIChleHBvcnRPcHRpb25zLmluc3RyICE9PSBudWxsIHx8IGV4cG9ydE9wdGlvbnMub3B0aW9ucyAhPT0gbnVsbCkge1xyXG4gICAgICBsb2coNCwgJ1tjaGFydF0gQXR0ZW1wdGluZyB0byBleHBvcnQgZnJvbSBvcHRpb25zIGlucHV0LicpO1xyXG5cclxuICAgICAgLy8gT3B0aW9ucyBleHBvcnRzIGF0dGVtcHRzIGNvdW50ZXJcclxuICAgICAgKytnZXRQb29sU3RhdHMoKS5leHBvcnRzRnJvbU9wdGlvbnNBdHRlbXB0cztcclxuXHJcbiAgICAgIC8vIEV4cG9ydCBmcm9tIG9wdGlvbnNcclxuICAgICAgY29uc3QgcmVzdWx0ID0gYXdhaXQgX2V4cG9ydEZyb21PcHRpb25zKFxyXG4gICAgICAgIGV4cG9ydE9wdGlvbnMuaW5zdHIgfHwgZXhwb3J0T3B0aW9ucy5vcHRpb25zLFxyXG4gICAgICAgIG9wdGlvbnNcclxuICAgICAgKTtcclxuXHJcbiAgICAgIC8vIE9wdGlvbnMgZXhwb3J0cyBjb3VudGVyXHJcbiAgICAgICsrZ2V0UG9vbFN0YXRzKCkuZXhwb3J0c0Zyb21PcHRpb25zO1xyXG5cclxuICAgICAgLy8gUGFzcyBvcHRpb25zIGV4cG9ydCByZXN1bHQgdG8gdGhlIGVuZCBjYWxsYmFja1xyXG4gICAgICByZXR1cm4gZW5kQ2FsbGJhY2sobnVsbCwgcmVzdWx0KTtcclxuICAgIH1cclxuXHJcbiAgICAvLyBObyBpbnB1dCBzcGVjaWZpZWQsIHBhc3MgYW4gZXJyb3IgbWVzc2FnZSB0byB0aGUgY2FsbGJhY2tcclxuICAgIHJldHVybiBlbmRDYWxsYmFjayhcclxuICAgICAgbmV3IEV4cG9ydEVycm9yKFxyXG4gICAgICAgIGBbY2hhcnRdIE5vIHZhbGlkIGlucHV0IHNwZWNpZmllZC4gQ2hlY2sgaWYgYXQgbGVhc3Qgb25lIG9mIHRoZSBmb2xsb3dpbmcgcGFyYW1ldGVycyBpcyBjb3JyZWN0bHkgc2V0OiAnaW5maWxlJywgJ2luc3RyJywgJ29wdGlvbnMnLCBvciAnc3ZnJy5gLFxyXG4gICAgICAgIDQwMFxyXG4gICAgICApXHJcbiAgICApO1xyXG4gIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICByZXR1cm4gZW5kQ2FsbGJhY2soZXJyb3IpO1xyXG4gIH1cclxufVxyXG5cclxuLyoqXHJcbiAqIFJldHJpZXZlcyBhbmQgcmV0dXJucyB0aGUgY3VycmVudCBzdGF0dXMgb2YgdGhlIGNvZGUgZXhlY3V0aW9uIHBlcm1pc3Npb24uXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBnZXRBbGxvd0NvZGVFeGVjdXRpb25cclxuICpcclxuICogQHJldHVybnMge2Jvb2xlYW59IFRoZSB2YWx1ZSBvZiB0aGUgZ2xvYmFsIGBhbGxvd0NvZGVFeGVjdXRpb25gIG9wdGlvbi5cclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiBnZXRBbGxvd0NvZGVFeGVjdXRpb24oKSB7XHJcbiAgcmV0dXJuIGFsbG93Q29kZUV4ZWN1dGlvbjtcclxufVxyXG5cclxuLyoqXHJcbiAqIFNldHMgdGhlIGNvZGUgZXhlY3V0aW9uIHBlcm1pc3Npb24gYmFzZWQgb24gdGhlIHByb3ZpZGVkIGJvb2xlYW4gdmFsdWUuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBzZXRBbGxvd0NvZGVFeGVjdXRpb25cclxuICpcclxuICogQHBhcmFtIHtib29sZWFufSB2YWx1ZSAtIFRoZSBib29sZWFuIHZhbHVlIHRvIGJlIGFzc2lnbmVkIHRvIHRoZSBnbG9iYWxcclxuICogYGFsbG93Q29kZUV4ZWN1dGlvbmAgb3B0aW9uLlxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIHNldEFsbG93Q29kZUV4ZWN1dGlvbih2YWx1ZSkge1xyXG4gIGFsbG93Q29kZUV4ZWN1dGlvbiA9IHZhbHVlO1xyXG59XHJcblxyXG4vKipcclxuICogRXhwb3J0cyBmcm9tIGFuIFNWRyBiYXNlZCBpbnB1dCB3aXRoIHRoZSBwcm92aWRlZCBvcHRpb25zLlxyXG4gKlxyXG4gKiBAYXN5bmNcclxuICogQGZ1bmN0aW9uIF9leHBvcnRGcm9tU3ZnXHJcbiAqXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSBpbnB1dFRvRXhwb3J0IC0gVGhlIFNWRyBiYXNlZCBpbnB1dCB0byBiZSBleHBvcnRlZC5cclxuICogQHBhcmFtIHtPYmplY3R9IG9wdGlvbnMgLSBUaGUgY29uZmlndXJhdGlvbiBvYmplY3QgY29udGFpbmluZyBjb21wbGV0ZSBzZXRcclxuICogb2Ygb3B0aW9ucy5cclxuICpcclxuICogQHJldHVybnMge1Byb21pc2U8dW5rbm93bj59IEEgUHJvbWlzZSB0aGF0IHJlc29sdmVzIHRvIGEgcmVzdWx0IG9mIHRoZSBleHBvcnRcclxuICogcHJvY2Vzcy5cclxuICpcclxuICogQHRocm93cyB7RXhwb3J0RXJyb3J9IFRocm93cyBhbiBgRXhwb3J0RXJyb3JgIGlmIHRoZXJlIGlzIG5vdCBhIGNvcnJlY3QgU1ZHXHJcbiAqIGlucHV0LlxyXG4gKi9cclxuYXN5bmMgZnVuY3Rpb24gX2V4cG9ydEZyb21TdmcoaW5wdXRUb0V4cG9ydCwgb3B0aW9ucykge1xyXG4gIC8vIENoZWNrIGlmIGl0IGlzIFNWR1xyXG4gIGlmIChcclxuICAgIHR5cGVvZiBpbnB1dFRvRXhwb3J0ID09PSAnc3RyaW5nJyAmJlxyXG4gICAgKGlucHV0VG9FeHBvcnQuaW5kZXhPZignPHN2ZycpID49IDAgfHwgaW5wdXRUb0V4cG9ydC5pbmRleE9mKCc8P3htbCcpID49IDApXHJcbiAgKSB7XHJcbiAgICBsb2coNCwgJ1tjaGFydF0gUGFyc2luZyBpbnB1dCBhcyBTVkcuJyk7XHJcblxyXG4gICAgLy8gU2V0IHRoZSBleHBvcnQgaW5wdXQgYXMgU1ZHXHJcbiAgICBvcHRpb25zLmV4cG9ydC5zdmcgPSBpbnB1dFRvRXhwb3J0O1xyXG5cclxuICAgIC8vIFJlc2V0IHRoZSByZXN0IG9mIHRoZSBleHBvcnQgaW5wdXQgb3B0aW9uc1xyXG4gICAgb3B0aW9ucy5leHBvcnQuaW5zdHIgPSBudWxsO1xyXG4gICAgb3B0aW9ucy5leHBvcnQub3B0aW9ucyA9IG51bGw7XHJcblxyXG4gICAgLy8gQ2FsbCB0aGUgZnVuY3Rpb24gd2l0aCBhbiBTVkcgc3RyaW5nIGFzIGFuIGV4cG9ydCBpbnB1dFxyXG4gICAgcmV0dXJuIF9wcmVwYXJlRXhwb3J0KG9wdGlvbnMpO1xyXG4gIH0gZWxzZSB7XHJcbiAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoJ1tjaGFydF0gTm90IGEgY29ycmVjdCBTVkcgaW5wdXQuJywgNDAwKTtcclxuICB9XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBFeHBvcnRzIGZyb20gYW4gb3B0aW9ucyBiYXNlZCBpbnB1dCB3aXRoIHRoZSBwcm92aWRlZCBvcHRpb25zLlxyXG4gKlxyXG4gKiBAYXN5bmNcclxuICogQGZ1bmN0aW9uIF9leHBvcnRGcm9tT3B0aW9uc1xyXG4gKlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gaW5wdXRUb0V4cG9ydCAtIFRoZSBvcHRpb25zIGJhc2VkIGlucHV0IHRvIGJlIGV4cG9ydGVkLlxyXG4gKiBAcGFyYW0ge09iamVjdH0gb3B0aW9ucyAtIFRoZSBjb25maWd1cmF0aW9uIG9iamVjdCBjb250YWluaW5nIGNvbXBsZXRlIHNldFxyXG4gKiBvZiBvcHRpb25zLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7UHJvbWlzZTx1bmtub3duPn0gQSBQcm9taXNlIHRoYXQgcmVzb2x2ZXMgdG8gYSByZXN1bHQgb2YgdGhlIGV4cG9ydFxyXG4gKiBwcm9jZXNzLlxyXG4gKlxyXG4gKiBAdGhyb3dzIHtFeHBvcnRFcnJvcn0gVGhyb3dzIGFuIGBFeHBvcnRFcnJvcmAgaWYgdGhlcmUgaXMgbm90IGEgY29ycmVjdFxyXG4gKiBjaGFydCBvcHRpb25zIGlucHV0LlxyXG4gKi9cclxuYXN5bmMgZnVuY3Rpb24gX2V4cG9ydEZyb21PcHRpb25zKGlucHV0VG9FeHBvcnQsIG9wdGlvbnMpIHtcclxuICBsb2coNCwgJ1tjaGFydF0gUGFyc2luZyBpbnB1dCBmcm9tIG9wdGlvbnMuJyk7XHJcblxyXG4gIC8vIFRyeSB0byBjaGVjaywgdmFsaWRhdGUgYW5kIHBhcnNlIHRvIHN0cmluZ2lmaWVkIG9wdGlvbnNcclxuICBjb25zdCBzdHJpbmdpZmllZE9wdGlvbnMgPSBpc0FsbG93ZWRDb25maWcoXHJcbiAgICBpbnB1dFRvRXhwb3J0LFxyXG4gICAgdHJ1ZSxcclxuICAgIG9wdGlvbnMuY3VzdG9tTG9naWMuYWxsb3dDb2RlRXhlY3V0aW9uXHJcbiAgKTtcclxuXHJcbiAgLy8gQ2hlY2sgaWYgYSBjb3JyZWN0IHN0cmluZ2lmaWVkIG9wdGlvbnNcclxuICBpZiAoXHJcbiAgICBzdHJpbmdpZmllZE9wdGlvbnMgPT09IG51bGwgfHxcclxuICAgIHR5cGVvZiBzdHJpbmdpZmllZE9wdGlvbnMgIT09ICdzdHJpbmcnIHx8XHJcbiAgICAhc3RyaW5naWZpZWRPcHRpb25zLnN0YXJ0c1dpdGgoJ3snKSB8fFxyXG4gICAgIXN0cmluZ2lmaWVkT3B0aW9ucy5lbmRzV2l0aCgnfScpXHJcbiAgKSB7XHJcbiAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoXHJcbiAgICAgICdbY2hhcnRdIEludmFsaWQgY29uZmlndXJhdGlvbiBwcm92aWRlZCAtIE9ubHkgb3B0aW9ucyBjb25maWd1cmF0aW9ucyBhbmQgU1ZHIGFyZSBhbGxvd2VkIGZvciB0aGlzIHNlcnZlci4gSWYgdGhpcyBpcyB5b3VyIHNlcnZlciwgSmF2YVNjcmlwdCBjdXN0b20gY29kZSBjYW4gYmUgZW5hYmxlZCBieSBzdGFydGluZyB0aGUgc2VydmVyIHdpdGggdGhlIGBhbGxvd0NvZGVFeGVjdXRpb25gIG9wdGlvbnMgc2V0IHRvIHRydWUuJyxcclxuICAgICAgNDAzXHJcbiAgICApO1xyXG4gIH1cclxuXHJcbiAgLy8gU2V0IHRoZSBleHBvcnQgaW5wdXQgYXMgYSBzdHJpbmdpZmllZCBjaGFydCBvcHRpb25zXHJcbiAgb3B0aW9ucy5leHBvcnQuaW5zdHIgPSBzdHJpbmdpZmllZE9wdGlvbnM7XHJcblxyXG4gIC8vIFJlc2V0IHRoZSByZXN0IG9mIHRoZSBleHBvcnQgaW5wdXQgb3B0aW9uc1xyXG4gIG9wdGlvbnMuZXhwb3J0LnN2ZyA9IG51bGw7XHJcblxyXG4gIC8vIENhbGwgdGhlIGZ1bmN0aW9uIHdpdGggYSBzdHJpbmdpZmllZCBjaGFydCBvcHRpb25zXHJcbiAgcmV0dXJuIF9wcmVwYXJlRXhwb3J0KG9wdGlvbnMpO1xyXG59XHJcblxyXG4vKipcclxuICogRnVuY3Rpb24gZm9yIGZpbmFsaXppbmcgb3B0aW9ucyBhbmQgY29uZmlndXJhdGlvbnMgYmVmb3JlIGV4cG9ydC5cclxuICpcclxuICogQGFzeW5jXHJcbiAqIEBmdW5jdGlvbiBfcHJlcGFyZUV4cG9ydFxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gb3B0aW9ucyAtIFRoZSBjb25maWd1cmF0aW9uIG9iamVjdCBjb250YWluaW5nIGNvbXBsZXRlIHNldFxyXG4gKiBvZiBvcHRpb25zLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7UHJvbWlzZTx1bmtub3duPn0gQSBQcm9taXNlIHRoYXQgcmVzb2x2ZXMgdG8gYSByZXN1bHQgb2YgdGhlIGV4cG9ydFxyXG4gKiBwcm9jZXNzLlxyXG4gKi9cclxuYXN5bmMgZnVuY3Rpb24gX3ByZXBhcmVFeHBvcnQob3B0aW9ucykge1xyXG4gIGNvbnN0IHsgZXhwb3J0OiBleHBvcnRPcHRpb25zLCBjdXN0b21Mb2dpYzogY3VzdG9tTG9naWNPcHRpb25zIH0gPSBvcHRpb25zO1xyXG5cclxuICAvLyBQcmVwYXJlIHRoZSBgdHlwZWAgb3B0aW9uXHJcbiAgZXhwb3J0T3B0aW9ucy50eXBlID0gZml4VHlwZShleHBvcnRPcHRpb25zLnR5cGUsIGV4cG9ydE9wdGlvbnMub3V0ZmlsZSk7XHJcblxyXG4gIC8vIFByZXBhcmUgdGhlIGBvdXRmaWxlYCBvcHRpb25cclxuICBleHBvcnRPcHRpb25zLm91dGZpbGUgPSBmaXhPdXRmaWxlKGV4cG9ydE9wdGlvbnMudHlwZSwgZXhwb3J0T3B0aW9ucy5vdXRmaWxlKTtcclxuXHJcbiAgLy8gUHJlcGFyZSB0aGUgYGNvbnN0cmAgb3B0aW9uXHJcbiAgZXhwb3J0T3B0aW9ucy5jb25zdHIgPSBmaXhDb25zdHIoZXhwb3J0T3B0aW9ucy5jb25zdHIpO1xyXG5cclxuICAvLyBOb3RpZnkgYWJvdXQgdGhlIGN1c3RvbSBsb2dpYyB1c2FnZSBzdGF0dXNcclxuICBsb2coXHJcbiAgICAzLFxyXG4gICAgYFtjaGFydF0gVGhlIGN1c3RvbSBsb2dpYyBpcyAke2N1c3RvbUxvZ2ljT3B0aW9ucy5hbGxvd0NvZGVFeGVjdXRpb24gPyAnYWxsb3dlZCcgOiAnZGlzYWxsb3dlZCd9LmBcclxuICApO1xyXG5cclxuICAvLyBQcmVwYXJlIHRoZSBjdXN0b20gbG9naWMgb3B0aW9ucyAoYGN1c3RvbUNvZGVgLCBgY2FsbGJhY2tgLCBgcmVzb3VyY2VzYClcclxuICBfaGFuZGxlQ3VzdG9tTG9naWMoY3VzdG9tTG9naWNPcHRpb25zLCBjdXN0b21Mb2dpY09wdGlvbnMuYWxsb3dDb2RlRXhlY3V0aW9uKTtcclxuXHJcbiAgLy8gUHJlcGFyZSB0aGUgYGdsb2JhbE9wdGlvbnNgIGFuZCBgdGhlbWVPcHRpb25zYCBvcHRpb25zXHJcbiAgX2hhbmRsZUdsb2JhbEFuZFRoZW1lKFxyXG4gICAgZXhwb3J0T3B0aW9ucyxcclxuICAgIGN1c3RvbUxvZ2ljT3B0aW9ucy5hbGxvd0ZpbGVSZXNvdXJjZXMsXHJcbiAgICBjdXN0b21Mb2dpY09wdGlvbnMuYWxsb3dDb2RlRXhlY3V0aW9uXHJcbiAgKTtcclxuXHJcbiAgLy8gUHJlcGFyZSB0aGUgYGhlaWdodGAsIGB3aWR0aGAsIGFuZCBgc2NhbGVgIG9wdGlvbnNcclxuICBvcHRpb25zLmV4cG9ydCA9IHtcclxuICAgIC4uLmV4cG9ydE9wdGlvbnMsXHJcbiAgICAuLi5fZmluZENoYXJ0U2l6ZShleHBvcnRPcHRpb25zKVxyXG4gIH07XHJcblxyXG4gIC8vIFBvc3QgdGhlIHdvcmsgdG8gdGhlIHBvb2xcclxuICByZXR1cm4gcG9zdFdvcmsob3B0aW9ucyk7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBDYWxjdWxhdGVzIHRoZSBgaGVpZ2h0YCwgYHdpZHRoYCBhbmQgYHNjYWxlYCBmb3IgY2hhcnQgZXhwb3J0cyBiYXNlZFxyXG4gKiBvbiB0aGUgcHJvdmlkZWQgZXhwb3J0IG9wdGlvbnMuXHJcbiAqXHJcbiAqIFRoZSBmdW5jdGlvbiBwcmlvcml0aXplcyB2YWx1ZXMgaW4gdGhlIGZvbGxvd2luZyBvcmRlcjpcclxuICogMS4gVGhlIGBoZWlnaHRgLCBgd2lkdGhgLCBgc2NhbGVgIGZyb20gdGhlIGBleHBvcnRPcHRpb25zYC5cclxuICogMi4gT3B0aW9ucyBmcm9tIHRoZSBjaGFydCBjb25maWd1cmF0aW9uIChmcm9tIGBleHBvcnRpbmdgIGFuZCBgY2hhcnRgKS5cclxuICogMy4gT3B0aW9ucyBmcm9tIHRoZSBnbG9iYWwgb3B0aW9ucyAoZnJvbSBgZXhwb3J0aW5nYCBhbmQgYGNoYXJ0YCkuXHJcbiAqIDQuIE9wdGlvbnMgZnJvbSB0aGUgdGhlbWUgb3B0aW9ucyAoZnJvbSBgZXhwb3J0aW5nYCBhbmQgYGNoYXJ0YCBzZWN0aW9ucykuXHJcbiAqIDUuIEZhbGxiYWNrIGRlZmF1bHQgdmFsdWVzIChgaGVpZ2h0ID0gNDAwYCwgYHdpZHRoID0gNjAwYCwgYHNjYWxlID0gMWApLlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gX2ZpbmRDaGFydFNpemVcclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IGV4cG9ydE9wdGlvbnMgLSBUaGUgY29uZmlndXJhdGlvbiBvYmplY3QgY29udGFpbmluZyBgZXhwb3J0YFxyXG4gKiBvcHRpb25zLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7T2JqZWN0fSBUaGUgb2JqZWN0IGNvbnRhaW5pbmcgY2FsY3VsYXRlZCBgaGVpZ2h0YCwgYHdpZHRoYFxyXG4gKiBhbmQgYHNjYWxlYCB2YWx1ZXMgZm9yIHRoZSBjaGFydCBleHBvcnQuXHJcbiAqL1xyXG5mdW5jdGlvbiBfZmluZENoYXJ0U2l6ZShleHBvcnRPcHRpb25zKSB7XHJcbiAgLy8gQ2hlY2sgdGhlIGBvcHRpb25zYCBhbmQgYGluc3RyYCBmb3IgY2hhcnQgYW5kIGV4cG9ydGluZyBzZWN0aW9uc1xyXG4gIGNvbnN0IHsgY2hhcnQ6IG9wdGlvbnNDaGFydCwgZXhwb3J0aW5nOiBvcHRpb25zRXhwb3J0aW5nIH0gPVxyXG4gICAgZXhwb3J0T3B0aW9ucy5vcHRpb25zIHx8IGlzQWxsb3dlZENvbmZpZyhleHBvcnRPcHRpb25zLmluc3RyKSB8fCBmYWxzZTtcclxuXHJcbiAgLy8gQ2hlY2sgdGhlIGBnbG9iYWxPcHRpb25zYCBmb3IgY2hhcnQgYW5kIGV4cG9ydGluZyBzZWN0aW9uc1xyXG4gIGNvbnN0IHsgY2hhcnQ6IGdsb2JhbE9wdGlvbnNDaGFydCwgZXhwb3J0aW5nOiBnbG9iYWxPcHRpb25zRXhwb3J0aW5nIH0gPVxyXG4gICAgaXNBbGxvd2VkQ29uZmlnKGV4cG9ydE9wdGlvbnMuZ2xvYmFsT3B0aW9ucykgfHwgZmFsc2U7XHJcblxyXG4gIC8vIENoZWNrIHRoZSBgdGhlbWVPcHRpb25zYCBmb3IgY2hhcnQgYW5kIGV4cG9ydGluZyBzZWN0aW9uc1xyXG4gIGNvbnN0IHsgY2hhcnQ6IHRoZW1lT3B0aW9uc0NoYXJ0LCBleHBvcnRpbmc6IHRoZW1lT3B0aW9uc0V4cG9ydGluZyB9ID1cclxuICAgIGlzQWxsb3dlZENvbmZpZyhleHBvcnRPcHRpb25zLnRoZW1lT3B0aW9ucykgfHwgZmFsc2U7XHJcblxyXG4gIC8vIEZpbmQgdGhlIGBzY2FsZWAgdmFsdWU6XHJcbiAgLy8gLSBJdCBjYW5ub3QgYmUgbG93ZXIgdGhhbiAwLjFcclxuICAvLyAtIEl0IGNhbm5vdCBiZSBoaWdoZXIgdGhhbiA1LjBcclxuICAvLyAtIEl0IG11c3QgYmUgcm91bmRlZCB0byAyIGRlY2ltYWwgcGxhY2VzIChlLmcuIDAuMjMyMzQgLT4gMC4yMylcclxuICBjb25zdCBzY2FsZSA9IHJvdW5kTnVtYmVyKFxyXG4gICAgTWF0aC5tYXgoXHJcbiAgICAgIDAuMSxcclxuICAgICAgTWF0aC5taW4oXHJcbiAgICAgICAgZXhwb3J0T3B0aW9ucy5zY2FsZSB8fFxyXG4gICAgICAgICAgb3B0aW9uc0V4cG9ydGluZz8uc2NhbGUgfHxcclxuICAgICAgICAgIGdsb2JhbE9wdGlvbnNFeHBvcnRpbmc/LnNjYWxlIHx8XHJcbiAgICAgICAgICB0aGVtZU9wdGlvbnNFeHBvcnRpbmc/LnNjYWxlIHx8XHJcbiAgICAgICAgICBleHBvcnRPcHRpb25zLmRlZmF1bHRTY2FsZSB8fFxyXG4gICAgICAgICAgMSxcclxuICAgICAgICA1LjBcclxuICAgICAgKVxyXG4gICAgKSxcclxuICAgIDJcclxuICApO1xyXG5cclxuICAvLyBGaW5kIHRoZSBgaGVpZ2h0YCB2YWx1ZVxyXG4gIGNvbnN0IGhlaWdodCA9XHJcbiAgICBleHBvcnRPcHRpb25zLmhlaWdodCB8fFxyXG4gICAgb3B0aW9uc0V4cG9ydGluZz8uc291cmNlSGVpZ2h0IHx8XHJcbiAgICBvcHRpb25zQ2hhcnQ/LmhlaWdodCB8fFxyXG4gICAgZ2xvYmFsT3B0aW9uc0V4cG9ydGluZz8uc291cmNlSGVpZ2h0IHx8XHJcbiAgICBnbG9iYWxPcHRpb25zQ2hhcnQ/LmhlaWdodCB8fFxyXG4gICAgdGhlbWVPcHRpb25zRXhwb3J0aW5nPy5zb3VyY2VIZWlnaHQgfHxcclxuICAgIHRoZW1lT3B0aW9uc0NoYXJ0Py5oZWlnaHQgfHxcclxuICAgIGV4cG9ydE9wdGlvbnMuZGVmYXVsdEhlaWdodCB8fFxyXG4gICAgNDAwO1xyXG5cclxuICAvLyBGaW5kIHRoZSBgd2lkdGhgIHZhbHVlXHJcbiAgY29uc3Qgd2lkdGggPVxyXG4gICAgZXhwb3J0T3B0aW9ucy53aWR0aCB8fFxyXG4gICAgb3B0aW9uc0V4cG9ydGluZz8uc291cmNlV2lkdGggfHxcclxuICAgIG9wdGlvbnNDaGFydD8ud2lkdGggfHxcclxuICAgIGdsb2JhbE9wdGlvbnNFeHBvcnRpbmc/LnNvdXJjZVdpZHRoIHx8XHJcbiAgICBnbG9iYWxPcHRpb25zQ2hhcnQ/LndpZHRoIHx8XHJcbiAgICB0aGVtZU9wdGlvbnNFeHBvcnRpbmc/LnNvdXJjZVdpZHRoIHx8XHJcbiAgICB0aGVtZU9wdGlvbnNDaGFydD8ud2lkdGggfHxcclxuICAgIGV4cG9ydE9wdGlvbnMuZGVmYXVsdFdpZHRoIHx8XHJcbiAgICA2MDA7XHJcblxyXG4gIC8vIEdhdGhlciBgaGVpZ2h0YCwgYHdpZHRoYCBhbmQgYHNjYWxlYCBpbmZvcm1hdGlvbiBpbiBvbmUgb2JqZWN0XHJcbiAgY29uc3Qgc2l6ZSA9IHsgaGVpZ2h0LCB3aWR0aCwgc2NhbGUgfTtcclxuXHJcbiAgLy8gR2V0IHJpZCBvZiBwb3RlbnRpYWwgYHB4YCBhbmQgYCVgXHJcbiAgZm9yIChsZXQgW3BhcmFtLCB2YWx1ZV0gb2YgT2JqZWN0LmVudHJpZXMoc2l6ZSkpIHtcclxuICAgIHNpemVbcGFyYW1dID1cclxuICAgICAgdHlwZW9mIHZhbHVlID09PSAnc3RyaW5nJyA/ICt2YWx1ZS5yZXBsYWNlKC9weHwlL2dpLCAnJykgOiB2YWx1ZTtcclxuICB9XHJcblxyXG4gIC8vIFJldHVybiB0aGUgc2l6ZSBvYmplY3RcclxuICByZXR1cm4gc2l6ZTtcclxufVxyXG5cclxuLyoqXHJcbiAqIEhhbmRsZXMgdGhlIGV4ZWN1dGlvbiBvZiBjdXN0b20gbG9naWMgb3B0aW9ucywgaW5jbHVkaW5nIGxvYWRpbmcgYHJlc291cmNlc2AsXHJcbiAqIGBjdXN0b21Db2RlYCwgYW5kIGBjYWxsYmFja2AuIElmIGNvZGUgZXhlY3V0aW9uIGlzIGFsbG93ZWQsIGl0IHByb2Nlc3Nlc1xyXG4gKiB0aGUgY3VzdG9tIGxvZ2ljIG9wdGlvbnMgYWNjb3JkaW5nbHkuIElmIGNvZGUgZXhlY3V0aW9uIGlzIG5vdCBhbGxvd2VkLFxyXG4gKiBpdCBkaXNhYmxlcyB0aGUgdXNhZ2Ugb2YgcmVzb3VyY2VzLCBjdXN0b20gY29kZSBhbmQgY2FsbGJhY2suXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBfaGFuZGxlQ3VzdG9tTG9naWNcclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IGN1c3RvbUxvZ2ljT3B0aW9ucyAtIFRoZSBjb25maWd1cmF0aW9uIG9iamVjdCBjb250YWluaW5nXHJcbiAqIGBjdXN0b21Mb2dpY2Agb3B0aW9ucy5cclxuICogQHBhcmFtIHtib29sZWFufSBhbGxvd0NvZGVFeGVjdXRpb24gLSBBIGZsYWcgaW5kaWNhdGluZyB3aGV0aGVyIGNvZGVcclxuICogZXhlY3V0aW9uIGlzIGFsbG93ZWQuXHJcbiAqXHJcbiAqIEB0aHJvd3Mge0V4cG9ydEVycm9yfSBUaHJvd3MgYW4gYEV4cG9ydEVycm9yYCBpZiBjb2RlIGV4ZWN1dGlvblxyXG4gKiBpcyBub3QgYWxsb3dlZCBidXQgY3VzdG9tIGxvZ2ljIG9wdGlvbnMgYXJlIHN0aWxsIHByb3ZpZGVkLlxyXG4gKi9cclxuZnVuY3Rpb24gX2hhbmRsZUN1c3RvbUxvZ2ljKGN1c3RvbUxvZ2ljT3B0aW9ucywgYWxsb3dDb2RlRXhlY3V0aW9uKSB7XHJcbiAgLy8gSW4gY2FzZSBvZiBhbGxvd2luZyBjb2RlIGV4ZWN1dGlvblxyXG4gIGlmIChhbGxvd0NvZGVFeGVjdXRpb24pIHtcclxuICAgIC8vIFByb2Nlc3MgdGhlIGByZXNvdXJjZXNgIG9wdGlvblxyXG4gICAgaWYgKHR5cGVvZiBjdXN0b21Mb2dpY09wdGlvbnMucmVzb3VyY2VzID09PSAnc3RyaW5nJykge1xyXG4gICAgICAvLyBDdXN0b20gc3RyaW5naWZpZWQgcmVzb3VyY2VzXHJcbiAgICAgIGN1c3RvbUxvZ2ljT3B0aW9ucy5yZXNvdXJjZXMgPSBfaGFuZGxlUmVzb3VyY2VzKFxyXG4gICAgICAgIGN1c3RvbUxvZ2ljT3B0aW9ucy5yZXNvdXJjZXMsXHJcbiAgICAgICAgY3VzdG9tTG9naWNPcHRpb25zLmFsbG93RmlsZVJlc291cmNlcyxcclxuICAgICAgICB0cnVlXHJcbiAgICAgICk7XHJcbiAgICB9IGVsc2UgaWYgKCFjdXN0b21Mb2dpY09wdGlvbnMucmVzb3VyY2VzKSB7XHJcbiAgICAgIHRyeSB7XHJcbiAgICAgICAgLy8gTG9hZCB0aGUgZGVmYXVsdCBvbmVcclxuICAgICAgICBjdXN0b21Mb2dpY09wdGlvbnMucmVzb3VyY2VzID0gX2hhbmRsZVJlc291cmNlcyhcclxuICAgICAgICAgIHJlYWRGaWxlU3luYyhnZXRBYnNvbHV0ZVBhdGgoJ3Jlc291cmNlcy5qc29uJyksICd1dGY4JyksXHJcbiAgICAgICAgICBjdXN0b21Mb2dpY09wdGlvbnMuYWxsb3dGaWxlUmVzb3VyY2VzLFxyXG4gICAgICAgICAgdHJ1ZVxyXG4gICAgICAgICk7XHJcbiAgICAgIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICAgICAgbG9nKDIsICdbY2hhcnRdIFVuYWJsZSB0byBsb2FkIHRoZSBkZWZhdWx0IGByZXNvdXJjZXMuanNvbmAgZmlsZS4nKTtcclxuICAgICAgfVxyXG4gICAgfVxyXG5cclxuICAgIC8vIFByb2Nlc3MgdGhlIGBjdXN0b21Db2RlYCBvcHRpb25cclxuICAgIHRyeSB7XHJcbiAgICAgIC8vIFRyeSB0byBsb2FkIGN1c3RvbSBjb2RlIGFuZCB3cmFwIGFyb3VuZCBpdCBpbiBhIHNlbGYgaW52b2tpbmcgZnVuY3Rpb25cclxuICAgICAgY3VzdG9tTG9naWNPcHRpb25zLmN1c3RvbUNvZGUgPSB3cmFwQXJvdW5kKFxyXG4gICAgICAgIGN1c3RvbUxvZ2ljT3B0aW9ucy5jdXN0b21Db2RlLFxyXG4gICAgICAgIGN1c3RvbUxvZ2ljT3B0aW9ucy5hbGxvd0ZpbGVSZXNvdXJjZXNcclxuICAgICAgKTtcclxuXHJcbiAgICAgIC8vIFZhbGlkYXRlIHRoZSBvcHRpb25cclxuICAgICAgY3VzdG9tTG9naWNPcHRpb25zLmN1c3RvbUNvZGUgPSB2YWxpZGF0ZU9wdGlvbihcclxuICAgICAgICAnY3VzdG9tQ29kZScsXHJcbiAgICAgICAgY3VzdG9tTG9naWNPcHRpb25zLmN1c3RvbUNvZGVcclxuICAgICAgKTtcclxuICAgIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICAgIGxvZ1dpdGhTdGFjaygyLCBlcnJvciwgJ1tjaGFydF0gVGhlIGBjdXN0b21Db2RlYCBjYW5ub3QgYmUgbG9hZGVkLicpO1xyXG5cclxuICAgICAgLy8gSW4gY2FzZSBvZiBhbiBlcnJvciwgc2V0IHRoZSBvcHRpb24gd2l0aCBudWxsXHJcbiAgICAgIGN1c3RvbUxvZ2ljT3B0aW9ucy5jdXN0b21Db2RlID0gbnVsbDtcclxuICAgIH1cclxuXHJcbiAgICAvLyBQcm9jZXNzIHRoZSBgY2FsbGJhY2tgIG9wdGlvblxyXG4gICAgdHJ5IHtcclxuICAgICAgLy8gVHJ5IHRvIGxvYWQgY2FsbGJhY2sgZnVuY3Rpb25cclxuICAgICAgY3VzdG9tTG9naWNPcHRpb25zLmNhbGxiYWNrID0gd3JhcEFyb3VuZChcclxuICAgICAgICBjdXN0b21Mb2dpY09wdGlvbnMuY2FsbGJhY2ssXHJcbiAgICAgICAgY3VzdG9tTG9naWNPcHRpb25zLmFsbG93RmlsZVJlc291cmNlcyxcclxuICAgICAgICB0cnVlXHJcbiAgICAgICk7XHJcblxyXG4gICAgICAvLyBWYWxpZGF0ZSB0aGUgb3B0aW9uXHJcbiAgICAgIGN1c3RvbUxvZ2ljT3B0aW9ucy5jYWxsYmFjayA9IHZhbGlkYXRlT3B0aW9uKFxyXG4gICAgICAgICdjYWxsYmFjaycsXHJcbiAgICAgICAgY3VzdG9tTG9naWNPcHRpb25zLmNhbGxiYWNrXHJcbiAgICAgICk7XHJcbiAgICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgICBsb2dXaXRoU3RhY2soMiwgZXJyb3IsICdbY2hhcnRdIFRoZSBgY2FsbGJhY2tgIGNhbm5vdCBiZSBsb2FkZWQuJyk7XHJcblxyXG4gICAgICAvLyBJbiBjYXNlIG9mIGFuIGVycm9yLCBzZXQgdGhlIG9wdGlvbiB3aXRoIG51bGxcclxuICAgICAgY3VzdG9tTG9naWNPcHRpb25zLmNhbGxiYWNrID0gbnVsbDtcclxuICAgIH1cclxuXHJcbiAgICAvLyBDaGVjayBpZiB0aGVyZSBpcyB0aGUgYGN1c3RvbUNvZGVgIHByZXNlbnRcclxuICAgIGlmIChbbnVsbCwgdW5kZWZpbmVkXS5pbmNsdWRlcyhjdXN0b21Mb2dpY09wdGlvbnMuY3VzdG9tQ29kZSkpIHtcclxuICAgICAgbG9nKDMsICdbY2hhcnRdIE5vIHZhbHVlIGZvciB0aGUgYGN1c3RvbUNvZGVgIG9wdGlvbiBmb3VuZC4nKTtcclxuICAgIH1cclxuXHJcbiAgICAvLyBDaGVjayBpZiB0aGVyZSBpcyB0aGUgYGNhbGxiYWNrYCBwcmVzZW50XHJcbiAgICBpZiAoW251bGwsIHVuZGVmaW5lZF0uaW5jbHVkZXMoY3VzdG9tTG9naWNPcHRpb25zLmNhbGxiYWNrKSkge1xyXG4gICAgICBsb2coMywgJ1tjaGFydF0gTm8gdmFsdWUgZm9yIHRoZSBgY2FsbGJhY2tgIG9wdGlvbiBmb3VuZC4nKTtcclxuICAgIH1cclxuXHJcbiAgICAvLyBDaGVjayBpZiB0aGVyZSBpcyB0aGUgYHJlc291cmNlc2AgcHJlc2VudFxyXG4gICAgaWYgKFtudWxsLCB1bmRlZmluZWRdLmluY2x1ZGVzKGN1c3RvbUxvZ2ljT3B0aW9ucy5yZXNvdXJjZXMpKSB7XHJcbiAgICAgIGxvZygzLCAnW2NoYXJ0XSBObyB2YWx1ZSBmb3IgdGhlIGByZXNvdXJjZXNgIG9wdGlvbiBmb3VuZC4nKTtcclxuICAgIH1cclxuICB9IGVsc2Uge1xyXG4gICAgLy8gSWYgdGhlIGBhbGxvd0NvZGVFeGVjdXRpb25gIGZsYWcgaXMgc2V0IHRvIGZhbHNlLCB3ZSBzaG91bGQgcmVmdXNlXHJcbiAgICAvLyB0aGUgdXNhZ2Ugb2YgdGhlIGBjYWxsYmFja2AsIGByZXNvdXJjZXNgLCBhbmQgYGN1c3RvbUNvZGVgIG9wdGlvbnMuXHJcbiAgICAvLyBBZGRpdGlvbmFsbHksIHRoZSB3b3JrZXIgd2lsbCByZWZ1c2UgdG8gcnVuIGFyYml0cmFyeSBKYXZhU2NyaXB0LlxyXG4gICAgaWYgKFxyXG4gICAgICBjdXN0b21Mb2dpY09wdGlvbnMuY2FsbGJhY2sgfHxcclxuICAgICAgY3VzdG9tTG9naWNPcHRpb25zLnJlc291cmNlcyB8fFxyXG4gICAgICBjdXN0b21Mb2dpY09wdGlvbnMuY3VzdG9tQ29kZVxyXG4gICAgKSB7XHJcbiAgICAgIC8vIFJlc2V0IGFsbCBjdXN0b20gY29kZSBvcHRpb25zXHJcbiAgICAgIGN1c3RvbUxvZ2ljT3B0aW9ucy5jYWxsYmFjayA9IG51bGw7XHJcbiAgICAgIGN1c3RvbUxvZ2ljT3B0aW9ucy5yZXNvdXJjZXMgPSBudWxsO1xyXG4gICAgICBjdXN0b21Mb2dpY09wdGlvbnMuY3VzdG9tQ29kZSA9IG51bGw7XHJcblxyXG4gICAgICAvLyBTZW5kIGEgbWVzc2FnZSBzYXlpbmcgdGhhdCB0aGUgZXhwb3J0ZXIgZG9lcyBub3Qgc3VwcG9ydCB0aGVzZSBzZXR0aW5nc1xyXG4gICAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoXHJcbiAgICAgICAgYFtjaGFydF0gVGhlICdjYWxsYmFjaycsICdyZXNvdXJjZXMnLCBhbmQgJ2N1c3RvbUNvZGUnIG9wdGlvbnMgaGF2ZSBiZWVuIGRpc2FibGVkIGZvciB0aGlzIHNlcnZlci5gLFxyXG4gICAgICAgIDQwM1xyXG4gICAgICApO1xyXG4gICAgfVxyXG4gIH1cclxufVxyXG5cclxuLyoqXHJcbiAqIEhhbmRsZXMgYW5kIHZhbGlkYXRlcyByZXNvdXJjZXMgZnJvbSB0aGUgYHJlc291cmNlc2Agb3B0aW9uIGZvciBleHBvcnQuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBfaGFuZGxlUmVzb3VyY2VzXHJcbiAqXHJcbiAqIEBwYXJhbSB7KE9iamVjdHxzdHJpbmd8bnVsbCl9IFtyZXNvdXJjZXM9bnVsbF0gLSBUaGUgcmVzb3VyY2VzIHRvIGJlIGhhbmRsZWQuXHJcbiAqIENhbiBiZSBlaXRoZXIgYSBKU09OIG9iamVjdCwgc3RyaW5naWZpZWQgSlNPTiwgYSBwYXRoIHRvIGEgSlNPTiBmaWxlLFxyXG4gKiBvciBudWxsLiBUaGUgZGVmYXVsdCB2YWx1ZSBpcyBgbnVsbGAuXHJcbiAqIEBwYXJhbSB7Ym9vbGVhbn0gYWxsb3dGaWxlUmVzb3VyY2VzIC0gQSBmbGFnIGluZGljYXRpbmcgd2hldGhlciBsb2FkaW5nXHJcbiAqIHJlc291cmNlcyBmcm9tIGZpbGVzIGlzIGFsbG93ZWQuXHJcbiAqIEBwYXJhbSB7Ym9vbGVhbn0gYWxsb3dDb2RlRXhlY3V0aW9uIC0gQSBmbGFnIGluZGljYXRpbmcgd2hldGhlciBjb2RlXHJcbiAqIGV4ZWN1dGlvbiBpcyBhbGxvd2VkLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7KE9iamVjdHxudWxsKX0gVGhlIGhhbmRsZWQgcmVzb3VyY2VzIG9yIG51bGwgaWYgbm8gdmFsaWQgcmVzb3VyY2VzXHJcbiAqIGFyZSBmb3VuZC5cclxuICovXHJcbmZ1bmN0aW9uIF9oYW5kbGVSZXNvdXJjZXMoXHJcbiAgcmVzb3VyY2VzID0gbnVsbCxcclxuICBhbGxvd0ZpbGVSZXNvdXJjZXMsXHJcbiAgYWxsb3dDb2RlRXhlY3V0aW9uXHJcbikge1xyXG4gIC8vIExpc3Qgb2YgYWxsb3dlZCBzZWN0aW9ucyBpbiB0aGUgcmVzb3VyY2VzIEpTT05cclxuICBjb25zdCBhbGxvd2VkUHJvcHMgPSBbJ2pzJywgJ2NzcycsICdmaWxlcyddO1xyXG5cclxuICBsZXQgaGFuZGxlZFJlc291cmNlcyA9IHJlc291cmNlcztcclxuICBsZXQgY29ycmVjdFJlc291cmNlcyA9IGZhbHNlO1xyXG5cclxuICAvLyBUcnkgdG8gbG9hZCByZXNvdXJjZXMgZnJvbSBhIGZpbGVcclxuICBpZiAoYWxsb3dGaWxlUmVzb3VyY2VzICYmIHJlc291cmNlcy5lbmRzV2l0aCgnLmpzb24nKSkge1xyXG4gICAgdHJ5IHtcclxuICAgICAgaGFuZGxlZFJlc291cmNlcyA9IGlzQWxsb3dlZENvbmZpZyhcclxuICAgICAgICByZWFkRmlsZVN5bmMoZ2V0QWJzb2x1dGVQYXRoKHJlc291cmNlcyksICd1dGY4JyksXHJcbiAgICAgICAgZmFsc2UsXHJcbiAgICAgICAgYWxsb3dDb2RlRXhlY3V0aW9uXHJcbiAgICAgICk7XHJcbiAgICB9IGNhdGNoIHtcclxuICAgICAgcmV0dXJuIG51bGw7XHJcbiAgICB9XHJcbiAgfSBlbHNlIHtcclxuICAgIC8vIFRyeSB0byBnZXQgSlNPTlxyXG4gICAgaGFuZGxlZFJlc291cmNlcyA9IGlzQWxsb3dlZENvbmZpZyhyZXNvdXJjZXMsIGZhbHNlLCBhbGxvd0NvZGVFeGVjdXRpb24pO1xyXG5cclxuICAgIC8vIEdldCByaWQgb2YgdGhlIGZpbGVzIHNlY3Rpb25cclxuICAgIGlmIChoYW5kbGVkUmVzb3VyY2VzICYmICFhbGxvd0ZpbGVSZXNvdXJjZXMpIHtcclxuICAgICAgZGVsZXRlIGhhbmRsZWRSZXNvdXJjZXMuZmlsZXM7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICAvLyBGaWx0ZXIgZnJvbSB1bm5lY2Vzc2FyeSBwcm9wZXJ0aWVzXHJcbiAgZm9yIChjb25zdCBwcm9wTmFtZSBpbiBoYW5kbGVkUmVzb3VyY2VzKSB7XHJcbiAgICBpZiAoIWFsbG93ZWRQcm9wcy5pbmNsdWRlcyhwcm9wTmFtZSkpIHtcclxuICAgICAgZGVsZXRlIGhhbmRsZWRSZXNvdXJjZXNbcHJvcE5hbWVdO1xyXG4gICAgfSBlbHNlIGlmICghY29ycmVjdFJlc291cmNlcykge1xyXG4gICAgICBjb3JyZWN0UmVzb3VyY2VzID0gdHJ1ZTtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIC8vIENoZWNrIGlmIGF0IGxlYXN0IG9uZSBvZiBhbGxvd2VkIHByb3BlcnRpZXMgaXMgcHJlc2VudFxyXG4gIGlmICghY29ycmVjdFJlc291cmNlcykge1xyXG4gICAgcmV0dXJuIG51bGw7XHJcbiAgfVxyXG5cclxuICAvLyBIYW5kbGUgZmlsZXMgc2VjdGlvblxyXG4gIGlmIChoYW5kbGVkUmVzb3VyY2VzLmZpbGVzKSB7XHJcbiAgICBoYW5kbGVkUmVzb3VyY2VzLmZpbGVzID0gaGFuZGxlZFJlc291cmNlcy5maWxlcy5tYXAoKGl0ZW0pID0+IGl0ZW0udHJpbSgpKTtcclxuICAgIGlmICghaGFuZGxlZFJlc291cmNlcy5maWxlcyB8fCBoYW5kbGVkUmVzb3VyY2VzLmZpbGVzLmxlbmd0aCA8PSAwKSB7XHJcbiAgICAgIGRlbGV0ZSBoYW5kbGVkUmVzb3VyY2VzLmZpbGVzO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgLy8gVmFsaWRhdGUgb3B0aW9uXHJcbiAgaGFuZGxlZFJlc291cmNlcyA9IHZhbGlkYXRlT3B0aW9uKCdyZXNvdXJjZXMnLCBoYW5kbGVkUmVzb3VyY2VzKTtcclxuXHJcbiAgLy8gUmV0dXJuIHJlc291cmNlc1xyXG4gIHJldHVybiBoYW5kbGVkUmVzb3VyY2VzO1xyXG59XHJcblxyXG4vKipcclxuICogSGFuZGxlcyB0aGUgbG9hZGluZyBhbmQgdmFsaWRhdGlvbiBvZiB0aGUgYGdsb2JhbE9wdGlvbnNgIGFuZCBgdGhlbWVPcHRpb25zYFxyXG4gKiBpbiB0aGUgZXhwb3J0IG9wdGlvbnMuIElmIHRoZSBvcHRpb24gaXMgYSBzdHJpbmcgYW5kIHJlZmVyZW5jZXMgYSBKU09OIGZpbGVcclxuICogKHdoZW4gdGhlIGBhbGxvd0ZpbGVSZXNvdXJjZXNgIGlzIHRydWUpLCBpdCByZWFkcyBhbmQgcGFyc2VzIHRoZSBmaWxlLlxyXG4gKiBPdGhlcndpc2UsIGl0IGF0dGVtcHRzIHRvIHBhcnNlIHRoZSBzdHJpbmcgb3Igb2JqZWN0IGFzIEpTT04uIElmIGFueSBlcnJvcnNcclxuICogb2NjdXIgZHVyaW5nIHRoaXMgcHJvY2VzcywgdGhlIG9wdGlvbiBpcyBzZXQgdG8gbnVsbC4gSWYgdGhlcmUgaXMgYW4gZXJyb3JcclxuICogbG9hZGluZyBvciBwYXJzaW5nIHRoZSBgZ2xvYmFsT3B0aW9uc2Agb3IgYHRoZW1lT3B0aW9uc2AsIHRoZSBlcnJvciBpcyBsb2dnZWRcclxuICogYW5kIHRoZSBvcHRpb24gaXMgc2V0IHRvIG51bGwuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBfaGFuZGxlR2xvYmFsQW5kVGhlbWVcclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IGV4cG9ydE9wdGlvbnMgLSBUaGUgY29uZmlndXJhdGlvbiBvYmplY3QgY29udGFpbmluZyBgZXhwb3J0YFxyXG4gKiBvcHRpb25zLlxyXG4gKiBAcGFyYW0ge2Jvb2xlYW59IGFsbG93RmlsZVJlc291cmNlcyAtIEEgZmxhZyBpbmRpY2F0aW5nIHdoZXRoZXIgbG9hZGluZ1xyXG4gKiByZXNvdXJjZXMgZnJvbSBmaWxlcyBpcyBhbGxvd2VkLlxyXG4gKiBAcGFyYW0ge2Jvb2xlYW59IGFsbG93Q29kZUV4ZWN1dGlvbiAtIEEgZmxhZyBpbmRpY2F0aW5nIHdoZXRoZXIgY29kZVxyXG4gKiBleGVjdXRpb24gaXMgYWxsb3dlZC5cclxuICovXHJcbmZ1bmN0aW9uIF9oYW5kbGVHbG9iYWxBbmRUaGVtZShcclxuICBleHBvcnRPcHRpb25zLFxyXG4gIGFsbG93RmlsZVJlc291cmNlcyxcclxuICBhbGxvd0NvZGVFeGVjdXRpb25cclxuKSB7XHJcbiAgLy8gQ2hlY2sgdGhlIGBnbG9iYWxPcHRpb25zYCBhbmQgYHRoZW1lT3B0aW9uc2Agb3B0aW9uc1xyXG4gIFsnZ2xvYmFsT3B0aW9ucycsICd0aGVtZU9wdGlvbnMnXS5mb3JFYWNoKChvcHRpb25zTmFtZSkgPT4ge1xyXG4gICAgdHJ5IHtcclxuICAgICAgLy8gQ2hlY2sgaWYgdGhlIG9wdGlvbiBleGlzdHNcclxuICAgICAgaWYgKGV4cG9ydE9wdGlvbnNbb3B0aW9uc05hbWVdKSB7XHJcbiAgICAgICAgLy8gQ2hlY2sgaWYgaXQgaXMgYSBzdHJpbmcgYW5kIGEgZmlsZSBuYW1lIHdpdGggdGhlIGAuanNvbmAgZXh0ZW5zaW9uXHJcbiAgICAgICAgaWYgKFxyXG4gICAgICAgICAgYWxsb3dGaWxlUmVzb3VyY2VzICYmXHJcbiAgICAgICAgICB0eXBlb2YgZXhwb3J0T3B0aW9uc1tvcHRpb25zTmFtZV0gPT09ICdzdHJpbmcnICYmXHJcbiAgICAgICAgICBleHBvcnRPcHRpb25zW29wdGlvbnNOYW1lXS5lbmRzV2l0aCgnLmpzb24nKVxyXG4gICAgICAgICkge1xyXG4gICAgICAgICAgLy8gQ2hlY2sgaWYgdGhlIGZpbGUgY29udGVudCBjYW4gYmUgYSBjb25maWcsIGFuZCBzYXZlIGl0IGFzIGEgc3RyaW5nXHJcbiAgICAgICAgICBleHBvcnRPcHRpb25zW29wdGlvbnNOYW1lXSA9IGlzQWxsb3dlZENvbmZpZyhcclxuICAgICAgICAgICAgcmVhZEZpbGVTeW5jKGdldEFic29sdXRlUGF0aChleHBvcnRPcHRpb25zW29wdGlvbnNOYW1lXSksICd1dGY4JyksXHJcbiAgICAgICAgICAgIHRydWUsXHJcbiAgICAgICAgICAgIGFsbG93Q29kZUV4ZWN1dGlvblxyXG4gICAgICAgICAgKTtcclxuICAgICAgICB9IGVsc2Uge1xyXG4gICAgICAgICAgLy8gQ2hlY2sgaWYgdGhlIHZhbHVlIGNhbiBiZSBhIGNvbmZpZywgYW5kIHNhdmUgaXQgYXMgYSBzdHJpbmdcclxuICAgICAgICAgIGV4cG9ydE9wdGlvbnNbb3B0aW9uc05hbWVdID0gaXNBbGxvd2VkQ29uZmlnKFxyXG4gICAgICAgICAgICBleHBvcnRPcHRpb25zW29wdGlvbnNOYW1lXSxcclxuICAgICAgICAgICAgdHJ1ZSxcclxuICAgICAgICAgICAgYWxsb3dDb2RlRXhlY3V0aW9uXHJcbiAgICAgICAgICApO1xyXG4gICAgICAgIH1cclxuXHJcbiAgICAgICAgLy8gVmFsaWRhdGUgdGhlIG9wdGlvblxyXG4gICAgICAgIGV4cG9ydE9wdGlvbnNbb3B0aW9uc05hbWVdID0gdmFsaWRhdGVPcHRpb24oXHJcbiAgICAgICAgICBvcHRpb25zTmFtZSxcclxuICAgICAgICAgIGV4cG9ydE9wdGlvbnNbb3B0aW9uc05hbWVdXHJcbiAgICAgICAgKTtcclxuICAgICAgfVxyXG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICAgbG9nV2l0aFN0YWNrKFxyXG4gICAgICAgIDIsXHJcbiAgICAgICAgZXJyb3IsXHJcbiAgICAgICAgYFtjaGFydF0gVGhlIFxcYCR7b3B0aW9uc05hbWV9XFxgIGNhbm5vdCBiZSBsb2FkZWQuYFxyXG4gICAgICApO1xyXG5cclxuICAgICAgLy8gSW4gY2FzZSBvZiBhbiBlcnJvciwgc2V0IHRoZSBvcHRpb24gd2l0aCBudWxsXHJcbiAgICAgIGV4cG9ydE9wdGlvbnNbb3B0aW9uc05hbWVdID0gbnVsbDtcclxuICAgIH1cclxuICB9KTtcclxuXHJcbiAgLy8gQ2hlY2sgaWYgdGhlcmUgaXMgdGhlIGBnbG9iYWxPcHRpb25zYCBwcmVzZW50XHJcbiAgaWYgKFtudWxsLCB1bmRlZmluZWRdLmluY2x1ZGVzKGV4cG9ydE9wdGlvbnMuZ2xvYmFsT3B0aW9ucykpIHtcclxuICAgIGxvZygzLCAnW2NoYXJ0XSBObyB2YWx1ZSBmb3IgdGhlIGBnbG9iYWxPcHRpb25zYCBvcHRpb24gZm91bmQuJyk7XHJcbiAgfVxyXG5cclxuICAvLyBDaGVjayBpZiB0aGVyZSBpcyB0aGUgYHRoZW1lT3B0aW9uc2AgcHJlc2VudFxyXG4gIGlmIChbbnVsbCwgdW5kZWZpbmVkXS5pbmNsdWRlcyhleHBvcnRPcHRpb25zLnRoZW1lT3B0aW9ucykpIHtcclxuICAgIGxvZygzLCAnW2NoYXJ0XSBObyB2YWx1ZSBmb3IgdGhlIGB0aGVtZU9wdGlvbnNgIG9wdGlvbiBmb3VuZC4nKTtcclxuICB9XHJcbn1cclxuXHJcbmV4cG9ydCBkZWZhdWx0IHtcclxuICBzaW5nbGVFeHBvcnQsXHJcbiAgYmF0Y2hFeHBvcnQsXHJcbiAgc3RhcnRFeHBvcnQsXHJcbiAgZ2V0QWxsb3dDb2RlRXhlY3V0aW9uLFxyXG4gIHNldEFsbG93Q29kZUV4ZWN1dGlvblxyXG59O1xyXG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxyXG5cclxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXHJcblxyXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNSwgSGlnaHNvZnRcclxuXHJcbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cclxuXHJcbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxyXG5cclxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxyXG5cclxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cclxuXHJcbi8qKlxyXG4gKiBAb3ZlcnZpZXcgVGhpcyBtb2R1bGUgcHJvdmlkZXMgdXRpbGl0eSBmdW5jdGlvbnMgZm9yIG1hbmFnaW5nIGludGVydmFsc1xyXG4gKiBhbmQgdGltZW91dHMgaW4gYSBjZW50cmFsaXplZCBtYW5uZXIuIEl0IG1haW50YWlucyBhIHJlZ2lzdHJ5IG9mIGFsbCBhY3RpdmVcclxuICogdGltZXJzIGFuZCBhbGxvd3MgZm9yIHRoZWlyIGVmZmljaWVudCBjbGVhbnVwIHdoZW4gbmVlZGVkLiBUaGlzIGNhbiBiZSB1c2VmdWxcclxuICogaW4gYXBwbGljYXRpb25zIHdoZXJlIHByb3BlciByZXNvdXJjZSBtYW5hZ2VtZW50IGFuZCBjbGVhbiBzaHV0ZG93biBvZiB0aW1lcnNcclxuICogYXJlIGNyaXRpY2FsIHRvIGF2b2lkIG1lbW9yeSBsZWFrcyBvciB1bmludGVuZGVkIGJlaGF2aW9yLlxyXG4gKi9cclxuXHJcbmltcG9ydCB7IGxvZyB9IGZyb20gJy4vbG9nZ2VyLmpzJztcclxuXHJcbi8vIEFycmF5IHRoYXQgY29udGFpbnMgaWRzIG9mIGFsbCBvbmdvaW5nIGludGVydmFscyBhbmQgdGltZW91dHNcclxuY29uc3QgdGltZXJJZHMgPSBbXTtcclxuXHJcbi8qKlxyXG4gKiBBZGRzIGlkIG9mIHRoZSBgc2V0SW50ZXJ2YWxgIG9yIGBzZXRUaW1lb3V0YCBhbmQgdG8gdGhlIGB0aW1lcklkc2AgYXJyYXkuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBhZGRUaW1lclxyXG4gKlxyXG4gKiBAcGFyYW0ge05vZGVKUy5UaW1lb3V0fSBpZCAtIElkIG9mIGFuIGludGVydmFsIG9yIGEgdGltZW91dC5cclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiBhZGRUaW1lcihpZCkge1xyXG4gIHRpbWVySWRzLnB1c2goaWQpO1xyXG59XHJcblxyXG4vKipcclxuICogQ2xlYXJzIGFsbCBvZiBvbmdvaW5nIGludGVydmFscyBhbmQgdGltZW91dHMgYnkgaWRzIGdhdGhlcmVkXHJcbiAqIGluIHRoZSBgdGltZXJJZHNgIGFycmF5LlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gY2xlYXJBbGxUaW1lcnNcclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiBjbGVhckFsbFRpbWVycygpIHtcclxuICBsb2coNCwgYFt0aW1lcl0gQ2xlYXJpbmcgYWxsIHJlZ2lzdGVyZWQgaW50ZXJ2YWxzIGFuZCB0aW1lb3V0cy5gKTtcclxuICBmb3IgKGNvbnN0IGlkIG9mIHRpbWVySWRzKSB7XHJcbiAgICBjbGVhckludGVydmFsKGlkKTtcclxuICAgIGNsZWFyVGltZW91dChpZCk7XHJcbiAgfVxyXG59XHJcblxyXG5leHBvcnQgZGVmYXVsdCB7XHJcbiAgYWRkVGltZXIsXHJcbiAgY2xlYXJBbGxUaW1lcnNcclxufTtcclxuIiwiLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcclxuXHJcbkhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlclxyXG5cclxuQ29weXJpZ2h0IChjKSAyMDE2LTIwMjUsIEhpZ2hzb2Z0XHJcblxyXG5MaWNlbmNlZCB1bmRlciB0aGUgTUlUIGxpY2VuY2UuXHJcblxyXG5BZGRpdGlvbmFsbHkgYSB2YWxpZCBIaWdoY2hhcnRzIGxpY2Vuc2UgaXMgcmVxdWlyZWQgZm9yIHVzZS5cclxuXHJcblNlZSBMSUNFTlNFIGZpbGUgaW4gcm9vdCBmb3IgZGV0YWlscy5cclxuXHJcbioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXHJcblxyXG4vKipcclxuICogQG92ZXJ2aWV3IFByb3ZpZGVzIG1pZGRsZXdhcmUgZnVuY3Rpb25zIGZvciBsb2dnaW5nIGVycm9ycyB3aXRoIHN0YWNrIHRyYWNlc1xyXG4gKiBhbmQgaGFuZGxpbmcgZXJyb3IgcmVzcG9uc2VzIGluIGFuIEV4cHJlc3MgYXBwbGljYXRpb24uXHJcbiAqL1xyXG5cclxuaW1wb3J0IHsgZ2V0T3B0aW9ucyB9IGZyb20gJy4uLy4uL2NvbmZpZy5qcyc7XHJcbmltcG9ydCB7IGxvZ1dpdGhTdGFjayB9IGZyb20gJy4uLy4uL2xvZ2dlci5qcyc7XHJcblxyXG4vKipcclxuICogTWlkZGxld2FyZSBmb3IgbG9nZ2luZyBlcnJvcnMgd2l0aCBzdGFjayB0cmFjZSBhbmQgaGFuZGxpbmcgZXJyb3IgcmVzcG9uc2UuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBsb2dFcnJvck1pZGRsZXdhcmVcclxuICpcclxuICogQHBhcmFtIHtFcnJvcn0gZXJyb3IgLSBUaGUgZXJyb3Igb2JqZWN0LlxyXG4gKiBAcGFyYW0ge0V4cHJlc3MuUmVxdWVzdH0gcmVxdWVzdCAtIFRoZSBFeHByZXNzIHJlcXVlc3Qgb2JqZWN0LlxyXG4gKiBAcGFyYW0ge0V4cHJlc3MuUmVzcG9uc2V9IHJlc3BvbnNlIC0gVGhlIEV4cHJlc3MgcmVzcG9uc2Ugb2JqZWN0LlxyXG4gKiBAcGFyYW0ge0Z1bmN0aW9ufSBuZXh0IC0gVGhlIG5leHQgbWlkZGxld2FyZSBmdW5jdGlvbi5cclxuICpcclxuICogQHJldHVybnMge3VuZGVmaW5lZH0gVGhlIGNhbGwgdG8gdGhlIG5leHQgbWlkZGxld2FyZSBmdW5jdGlvbiB3aXRoXHJcbiAqIHRoZSBwYXNzZWQgZXJyb3IuXHJcbiAqL1xyXG5mdW5jdGlvbiBsb2dFcnJvck1pZGRsZXdhcmUoZXJyb3IsIHJlcXVlc3QsIHJlc3BvbnNlLCBuZXh0KSB7XHJcbiAgLy8gRGlzcGxheSB0aGUgZXJyb3Igd2l0aCBzdGFjayBpbiBhIGNvcnJlY3QgZm9ybWF0XHJcbiAgbG9nV2l0aFN0YWNrKDEsIGVycm9yKTtcclxuXHJcbiAgLy8gRGVsZXRlIHRoZSBzdGFjayBmb3IgdGhlIGVudmlyb25tZW50IG90aGVyIHRoYW4gdGhlIGRldmVsb3BtZW50XHJcbiAgaWYgKGdldE9wdGlvbnMoKS5vdGhlci5ub2RlRW52ICE9PSAnZGV2ZWxvcG1lbnQnKSB7XHJcbiAgICBkZWxldGUgZXJyb3Iuc3RhY2s7XHJcbiAgfVxyXG5cclxuICAvLyBDYWxsIHRoZSBgcmV0dXJuRXJyb3JNaWRkbGV3YXJlYCBtaWRkbGV3YXJlXHJcbiAgcmV0dXJuIG5leHQoZXJyb3IpO1xyXG59XHJcblxyXG4vKipcclxuICogTWlkZGxld2FyZSBmb3IgcmV0dXJuaW5nIGVycm9yIHJlc3BvbnNlLlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gcmV0dXJuRXJyb3JNaWRkbGV3YXJlXHJcbiAqXHJcbiAqIEBwYXJhbSB7RXJyb3J9IGVycm9yIC0gVGhlIGVycm9yIG9iamVjdC5cclxuICogQHBhcmFtIHtFeHByZXNzLlJlcXVlc3R9IHJlcXVlc3QgLSBUaGUgRXhwcmVzcyByZXF1ZXN0IG9iamVjdC5cclxuICogQHBhcmFtIHtFeHByZXNzLlJlc3BvbnNlfSByZXNwb25zZSAtIFRoZSBFeHByZXNzIHJlc3BvbnNlIG9iamVjdC5cclxuICogQHBhcmFtIHtGdW5jdGlvbn0gbmV4dCAtIFRoZSBuZXh0IG1pZGRsZXdhcmUgZnVuY3Rpb24uXHJcbiAqL1xyXG5mdW5jdGlvbiByZXR1cm5FcnJvck1pZGRsZXdhcmUoZXJyb3IsIHJlcXVlc3QsIHJlc3BvbnNlLCBuZXh0KSB7XHJcbiAgLy8gR2F0aGVyIGFsbCByZXF1aWVkIGluZm9ybWF0aW9uIGZvciB0aGUgcmVzcG9uc2VcclxuICBjb25zdCB7IG1lc3NhZ2UsIHN0YWNrIH0gPSBlcnJvcjtcclxuXHJcbiAgLy8gVXNlIHRoZSBlcnJvcidzIHN0YXR1cyBjb2RlIG9yIHRoZSBkZWZhdWx0IDQwMFxyXG4gIGNvbnN0IHN0YXR1c0NvZGUgPSBlcnJvci5zdGF0dXNDb2RlIHx8IDQwMDtcclxuXHJcbiAgLy8gU2V0IGFuZCByZXR1cm4gcmVzcG9uc2VcclxuICByZXNwb25zZS5zdGF0dXMoc3RhdHVzQ29kZSkuanNvbih7IHN0YXR1c0NvZGUsIG1lc3NhZ2UsIHN0YWNrIH0pO1xyXG59XHJcblxyXG4vKipcclxuICogQWRkcyB0aGUgZXJyb3IgbWlkZGxld2FyZXMgdG8gdGhlIHBhc3NlZCBleHByZXNzIGFwcCBpbnN0YW5jZS5cclxuICpcclxuICogQHBhcmFtIHtFeHByZXNzfSBhcHAgLSBUaGUgRXhwcmVzcyBhcHAgaW5zdGFuY2UuXHJcbiAqL1xyXG5leHBvcnQgZGVmYXVsdCBmdW5jdGlvbiBlcnJvck1pZGRsZXdhcmUoYXBwKSB7XHJcbiAgLy8gQWRkIGxvZyBlcnJvciBtaWRkbGV3YXJlXHJcbiAgYXBwLnVzZShsb2dFcnJvck1pZGRsZXdhcmUpO1xyXG5cclxuICAvLyBBZGQgc2V0IHN0YXR1cyBhbmQgcmV0dXJuIGVycm9yIG1pZGRsZXdhcmVcclxuICBhcHAudXNlKHJldHVybkVycm9yTWlkZGxld2FyZSk7XHJcbn1cclxuIiwiLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcclxuXHJcbkhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlclxyXG5cclxuQ29weXJpZ2h0IChjKSAyMDE2LTIwMjUsIEhpZ2hzb2Z0XHJcblxyXG5MaWNlbmNlZCB1bmRlciB0aGUgTUlUIGxpY2VuY2UuXHJcblxyXG5BZGRpdGlvbmFsbHkgYSB2YWxpZCBIaWdoY2hhcnRzIGxpY2Vuc2UgaXMgcmVxdWlyZWQgZm9yIHVzZS5cclxuXHJcblNlZSBMSUNFTlNFIGZpbGUgaW4gcm9vdCBmb3IgZGV0YWlscy5cclxuXHJcbioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXHJcblxyXG4vKipcclxuICogQG92ZXJ2aWV3IFByb3ZpZGVzIG1pZGRsZXdhcmUgZnVuY3Rpb25zIGZvciBjb25maWd1cmluZyBhbmQgZW5hYmxpbmcgcmF0ZVxyXG4gKiBsaW1pdGluZyBpbiBhbiBFeHByZXNzIGFwcGxpY2F0aW9uLlxyXG4gKi9cclxuXHJcbmltcG9ydCByYXRlTGltaXQgZnJvbSAnZXhwcmVzcy1yYXRlLWxpbWl0JztcclxuXHJcbmltcG9ydCB7IGxvZyB9IGZyb20gJy4uLy4uL2xvZ2dlci5qcyc7XHJcblxyXG5pbXBvcnQgRXhwb3J0RXJyb3IgZnJvbSAnLi4vLi4vZXJyb3JzL0V4cG9ydEVycm9yLmpzJztcclxuXHJcbi8qKlxyXG4gKiBNaWRkbGV3YXJlIGZvciBlbmFibGluZyByYXRlIGxpbWl0aW5nIG9uIHRoZSBzcGVjaWZpZWQgRXhwcmVzcyBhcHAuXHJcbiAqXHJcbiAqIEBwYXJhbSB7RXhwcmVzc30gYXBwIC0gVGhlIEV4cHJlc3MgYXBwIGluc3RhbmNlLlxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gcmF0ZUxpbWl0aW5nT3B0aW9ucyAtIFRoZSBjb25maWd1cmF0aW9uIG9iamVjdCBjb250YWluaW5nXHJcbiAqIGByYXRlTGltaXRpbmdgIG9wdGlvbnMuXHJcbiAqXHJcbiAqIEB0aHJvd3Mge0V4cG9ydEVycm9yfSBUaHJvd3MgYW4gYEV4cG9ydEVycm9yYCBpZiBjb3VsZCBub3QgY29uZmlndXJlIGFuZCBzZXRcclxuICogdGhlIHJhdGUgbGltaXRpbmcgb3B0aW9ucy5cclxuICovXHJcbmV4cG9ydCBkZWZhdWx0IGZ1bmN0aW9uIHJhdGVMaW1pdGluZ01pZGRsZXdhcmUoYXBwLCByYXRlTGltaXRpbmdPcHRpb25zKSB7XHJcbiAgdHJ5IHtcclxuICAgIC8vIENoZWNrIGlmIHRoZSByYXRlIGxpbWl0aW5nIGlzIGVuYWJsZWQgYW5kIHRoZSBhcHAgZXhpc3RzXHJcbiAgICBpZiAoYXBwICYmIHJhdGVMaW1pdGluZ09wdGlvbnMuZW5hYmxlKSB7XHJcbiAgICAgIGNvbnN0IG1lc3NhZ2UgPVxyXG4gICAgICAgICdUb28gbWFueSByZXF1ZXN0cywgeW91IGhhdmUgYmVlbiByYXRlIGxpbWl0ZWQuIFBsZWFzZSB0cnkgYWdhaW4gbGF0ZXIuJztcclxuXHJcbiAgICAgIC8vIE9wdGlvbnMgZm9yIHRoZSByYXRlIGxpbWl0ZXJcclxuICAgICAgY29uc3QgcmF0ZU9wdGlvbnMgPSB7XHJcbiAgICAgICAgd2luZG93OiByYXRlTGltaXRpbmdPcHRpb25zLndpbmRvdyB8fCAxLFxyXG4gICAgICAgIG1heFJlcXVlc3RzOiByYXRlTGltaXRpbmdPcHRpb25zLm1heFJlcXVlc3RzIHx8IDMwLFxyXG4gICAgICAgIGRlbGF5OiByYXRlTGltaXRpbmdPcHRpb25zLmRlbGF5IHx8IDAsXHJcbiAgICAgICAgdHJ1c3RQcm94eTogcmF0ZUxpbWl0aW5nT3B0aW9ucy50cnVzdFByb3h5IHx8IGZhbHNlLFxyXG4gICAgICAgIHNraXBLZXk6IHJhdGVMaW1pdGluZ09wdGlvbnMuc2tpcEtleSB8fCBudWxsLFxyXG4gICAgICAgIHNraXBUb2tlbjogcmF0ZUxpbWl0aW5nT3B0aW9ucy5za2lwVG9rZW4gfHwgbnVsbFxyXG4gICAgICB9O1xyXG5cclxuICAgICAgLy8gU2V0IGlmIGJlaGluZCBhIHByb3h5XHJcbiAgICAgIGlmIChyYXRlT3B0aW9ucy50cnVzdFByb3h5KSB7XHJcbiAgICAgICAgYXBwLmVuYWJsZSgndHJ1c3QgcHJveHknKTtcclxuICAgICAgfVxyXG5cclxuICAgICAgLy8gQ3JlYXRlIGEgbGltaXRlclxyXG4gICAgICBjb25zdCBsaW1pdGVyID0gcmF0ZUxpbWl0KHtcclxuICAgICAgICAvLyBUaW1lIGZyYW1lIGZvciB3aGljaCByZXF1ZXN0cyBhcmUgY2hlY2tlZCBhbmQgcmVtZW1iZXJlZFxyXG4gICAgICAgIHdpbmRvd01zOiByYXRlT3B0aW9ucy53aW5kb3cgKiA2MCAqIDEwMDAsXHJcbiAgICAgICAgLy8gTGltaXQgZWFjaCBJUCB0byAxMDAgcmVxdWVzdHMgcGVyIGB3aW5kb3dNc2BcclxuICAgICAgICBsaW1pdDogcmF0ZU9wdGlvbnMubWF4UmVxdWVzdHMsXHJcbiAgICAgICAgLy8gRGlzYWJsZSBkZWxheWluZywgZnVsbCBzcGVlZCB1bnRpbCB0aGUgbWF4IGxpbWl0IGlzIHJlYWNoZWRcclxuICAgICAgICBkZWxheU1zOiByYXRlT3B0aW9ucy5kZWxheSxcclxuICAgICAgICBoYW5kbGVyOiAocmVxdWVzdCwgcmVzcG9uc2UpID0+IHtcclxuICAgICAgICAgIHJlc3BvbnNlLmZvcm1hdCh7XHJcbiAgICAgICAgICAgIGpzb246ICgpID0+IHtcclxuICAgICAgICAgICAgICByZXNwb25zZS5zdGF0dXMoNDI5KS5zZW5kKHsgbWVzc2FnZSB9KTtcclxuICAgICAgICAgICAgfSxcclxuICAgICAgICAgICAgZGVmYXVsdDogKCkgPT4ge1xyXG4gICAgICAgICAgICAgIHJlc3BvbnNlLnN0YXR1cyg0MjkpLnNlbmQobWVzc2FnZSk7XHJcbiAgICAgICAgICAgIH1cclxuICAgICAgICAgIH0pO1xyXG4gICAgICAgIH0sXHJcbiAgICAgICAgc2tpcDogKHJlcXVlc3QpID0+IHtcclxuICAgICAgICAgIC8vIEFsbG93IGJ5cGFzc2luZyB0aGUgbGltaXRlciBpZiBhIHZhbGlkIGtleS90b2tlbiBoYXMgYmVlbiBzZW50XHJcbiAgICAgICAgICBpZiAoXHJcbiAgICAgICAgICAgIHJhdGVPcHRpb25zLnNraXBLZXkgIT09IG51bGwgJiZcclxuICAgICAgICAgICAgcmF0ZU9wdGlvbnMuc2tpcFRva2VuICE9PSBudWxsICYmXHJcbiAgICAgICAgICAgIHJlcXVlc3QucXVlcnkua2V5ID09PSByYXRlT3B0aW9ucy5za2lwS2V5ICYmXHJcbiAgICAgICAgICAgIHJlcXVlc3QucXVlcnkuYWNjZXNzX3Rva2VuID09PSByYXRlT3B0aW9ucy5za2lwVG9rZW5cclxuICAgICAgICAgICkge1xyXG4gICAgICAgICAgICBsb2coNCwgJ1tyYXRlIGxpbWl0aW5nXSBTa2lwcGluZyByYXRlIGxpbWl0ZXIuJyk7XHJcbiAgICAgICAgICAgIHJldHVybiB0cnVlO1xyXG4gICAgICAgICAgfVxyXG4gICAgICAgICAgcmV0dXJuIGZhbHNlO1xyXG4gICAgICAgIH1cclxuICAgICAgfSk7XHJcblxyXG4gICAgICAvLyBVc2UgYSBsaW1pdGVyIGFzIGEgbWlkZGxld2FyZVxyXG4gICAgICBhcHAudXNlKGxpbWl0ZXIpO1xyXG5cclxuICAgICAgbG9nKFxyXG4gICAgICAgIDMsXHJcbiAgICAgICAgYFtyYXRlIGxpbWl0aW5nXSBFbmFibGVkIHJhdGUgbGltaXRpbmcgd2l0aCAke3JhdGVPcHRpb25zLm1heFJlcXVlc3RzfSByZXF1ZXN0cyBwZXIgJHtyYXRlT3B0aW9ucy53aW5kb3d9IG1pbnV0ZSBmb3IgZWFjaCBJUCwgdHJ1c3RpbmcgcHJveHk6ICR7cmF0ZU9wdGlvbnMudHJ1c3RQcm94eX0uYFxyXG4gICAgICApO1xyXG4gICAgfVxyXG4gIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoXHJcbiAgICAgICdbcmF0ZSBsaW1pdGluZ10gQ291bGQgbm90IGNvbmZpZ3VyZSBhbmQgc2V0IHRoZSByYXRlIGxpbWl0aW5nIG9wdGlvbnMuJyxcclxuICAgICAgNTAwXHJcbiAgICApLnNldEVycm9yKGVycm9yKTtcclxuICB9XHJcbn1cclxuIiwiLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcclxuXHJcbkhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlclxyXG5cclxuQ29weXJpZ2h0IChjKSAyMDE2LTIwMjUsIEhpZ2hzb2Z0XHJcblxyXG5MaWNlbmNlZCB1bmRlciB0aGUgTUlUIGxpY2VuY2UuXHJcblxyXG5BZGRpdGlvbmFsbHkgYSB2YWxpZCBIaWdoY2hhcnRzIGxpY2Vuc2UgaXMgcmVxdWlyZWQgZm9yIHVzZS5cclxuXHJcblNlZSBMSUNFTlNFIGZpbGUgaW4gcm9vdCBmb3IgZGV0YWlscy5cclxuXHJcbioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXHJcblxyXG4vKipcclxuICogQG92ZXJ2aWV3IFByb3ZpZGVzIG1pZGRsZXdhcmUgZnVuY3Rpb25zIGZvciB2YWxpZGF0aW5nIGluY29taW5nIEhUVFAgcmVxdWVzdHNcclxuICogaW4gYW4gRXhwcmVzcyBhcHBsaWNhdGlvbi4gVGhpcyBtb2R1bGUgZW5zdXJlcyB0aGF0IHJlcXVlc3RzIGNvbnRhaW5cclxuICogYXBwcm9wcmlhdGUgY29udGVudCB0eXBlcyBhbmQgdmFsaWQgcmVxdWVzdCBib2RpZXMsIGluY2x1ZGluZyBwcm9wZXIgSlNPTlxyXG4gKiBzdHJ1Y3R1cmVzIGFuZCBjaGFydCBkYXRhIGZvciBleHBvcnRzLiBJdCBjaGVja3MgZm9yIHBvdGVudGlhbCBpc3N1ZXMgc3VjaFxyXG4gKiBhcyBtaXNzaW5nIG9yIG1hbGZvcm1lZCBkYXRhLCBwcml2YXRlIHJhbmdlIFVSTHMgaW4gU1ZHIHBheWxvYWRzLCBhbmQgYWxsb3dzXHJcbiAqIGZvciBmbGV4aWJsZSBvcHRpb25zIHZhbGlkYXRpb24uIFRoZSBtaWRkbGV3YXJlIGxvZ3MgZGV0YWlsZWQgaW5mb3JtYXRpb25cclxuICogYW5kIGhhbmRsZXMgZXJyb3JzIHJlbGF0ZWQgdG8gaW5jb3JyZWN0IHBheWxvYWRzLCBjaGFydCBkYXRhLCBhbmQgcHJpdmF0ZSBVUkxcclxuICogdXNhZ2UuXHJcbiAqL1xyXG5cclxuaW1wb3J0IHsgdjQgYXMgdXVpZCB9IGZyb20gJ3V1aWQnO1xyXG5cclxuaW1wb3J0IHsgZ2V0QWxsb3dDb2RlRXhlY3V0aW9uIH0gZnJvbSAnLi4vLi4vY2hhcnQuanMnO1xyXG5pbXBvcnQgeyBpc0FsbG93ZWRDb25maWcsIHZhbGlkYXRlT3B0aW9ucyB9IGZyb20gJy4uLy4uL2NvbmZpZy5qcyc7XHJcbmltcG9ydCB7IGxvZyB9IGZyb20gJy4uLy4uL2xvZ2dlci5qcyc7XHJcbmltcG9ydCB7IGlzT2JqZWN0RW1wdHksIGlzUHJpdmF0ZVJhbmdlVXJsRm91bmQgfSBmcm9tICcuLi8uLi91dGlscy5qcyc7XHJcblxyXG5pbXBvcnQgRXhwb3J0RXJyb3IgZnJvbSAnLi4vLi4vZXJyb3JzL0V4cG9ydEVycm9yLmpzJztcclxuXHJcbi8qKlxyXG4gKiBNaWRkbGV3YXJlIGZvciB2YWxpZGF0aW5nIHRoZSBjb250ZW50LXR5cGUgaGVhZGVyLlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gY29udGVudFR5cGVNaWRkbGV3YXJlXHJcbiAqXHJcbiAqIEBwYXJhbSB7RXhwcmVzcy5SZXF1ZXN0fSByZXF1ZXN0IC0gVGhlIEV4cHJlc3MgcmVxdWVzdCBvYmplY3QuXHJcbiAqIEBwYXJhbSB7RXhwcmVzcy5SZXNwb25zZX0gcmVzcG9uc2UgLSBUaGUgRXhwcmVzcyByZXNwb25zZSBvYmplY3QuXHJcbiAqIEBwYXJhbSB7RnVuY3Rpb259IG5leHQgLSBUaGUgbmV4dCBtaWRkbGV3YXJlIGZ1bmN0aW9uLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7dW5kZWZpbmVkfSBUaGUgY2FsbCB0byB0aGUgbmV4dCBtaWRkbGV3YXJlIGZ1bmN0aW9uLlxyXG4gKlxyXG4gKiBAdGhyb3dzIHtFeHBvcnRFcnJvcn0gVGhyb3dzIGFuIGBFeHBvcnRFcnJvcmAgaWYgdGhlIGNvbnRlbnQtdHlwZVxyXG4gKiBpcyBub3QgY29ycmVjdC5cclxuICovXHJcbmZ1bmN0aW9uIGNvbnRlbnRUeXBlTWlkZGxld2FyZShyZXF1ZXN0LCByZXNwb25zZSwgbmV4dCkge1xyXG4gIHRyeSB7XHJcbiAgICAvLyBHZXQgdGhlIGNvbnRlbnQgdHlwZSBoZWFkZXJcclxuICAgIGNvbnN0IGNvbnRlbnRUeXBlID0gcmVxdWVzdC5oZWFkZXJzWydjb250ZW50LXR5cGUnXSB8fCAnJztcclxuXHJcbiAgICAvLyBBbGxvdyBvbmx5IEpTT04sIFVSTC1lbmNvZGVkIGFuZCBmb3JtIGRhdGEgd2l0aG91dCBmaWxlcyB0eXBlcyBvZiBkYXRhXHJcbiAgICBpZiAoXHJcbiAgICAgICFjb250ZW50VHlwZS5pbmNsdWRlcygnYXBwbGljYXRpb24vanNvbicpICYmXHJcbiAgICAgICFjb250ZW50VHlwZS5pbmNsdWRlcygnYXBwbGljYXRpb24veC13d3ctZm9ybS11cmxlbmNvZGVkJykgJiZcclxuICAgICAgIWNvbnRlbnRUeXBlLmluY2x1ZGVzKCdtdWx0aXBhcnQvZm9ybS1kYXRhJylcclxuICAgICkge1xyXG4gICAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoXHJcbiAgICAgICAgJ1t2YWxpZGF0aW9uXSBDb250ZW50LVR5cGUgbXVzdCBiZSBhcHBsaWNhdGlvbi9qc29uLCBhcHBsaWNhdGlvbi94LXd3dy1mb3JtLXVybGVuY29kZWQsIG9yIG11bHRpcGFydC9mb3JtLWRhdGEuJyxcclxuICAgICAgICA0MTVcclxuICAgICAgKTtcclxuICAgIH1cclxuXHJcbiAgICAvLyBDYWxsIHRoZSBgcmVxdWVzdEJvZHlNaWRkbGV3YXJlYCBtaWRkbGV3YXJlXHJcbiAgICByZXR1cm4gbmV4dCgpO1xyXG4gIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICByZXR1cm4gbmV4dChlcnJvcik7XHJcbiAgfVxyXG59XHJcblxyXG4vKipcclxuICogTWlkZGxld2FyZSBmb3IgdmFsaWRhdGluZyB0aGUgcmVxdWVzdCdzIGJvZHkuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiByZXF1ZXN0Qm9keU1pZGRsZXdhcmVcclxuICpcclxuICogQHBhcmFtIHtFeHByZXNzLlJlcXVlc3R9IHJlcXVlc3QgLSBUaGUgRXhwcmVzcyByZXF1ZXN0IG9iamVjdC5cclxuICogQHBhcmFtIHtFeHByZXNzLlJlc3BvbnNlfSByZXNwb25zZSAtIFRoZSBFeHByZXNzIHJlc3BvbnNlIG9iamVjdC5cclxuICogQHBhcmFtIHtGdW5jdGlvbn0gbmV4dCAtIFRoZSBuZXh0IG1pZGRsZXdhcmUgZnVuY3Rpb24uXHJcbiAqXHJcbiAqIEByZXR1cm5zIHt1bmRlZmluZWR9IFRoZSBjYWxsIHRvIHRoZSBuZXh0IG1pZGRsZXdhcmUgZnVuY3Rpb24uXHJcbiAqXHJcbiAqIEB0aHJvd3Mge0V4cG9ydEVycm9yfSBUaHJvd3MgYW4gYEV4cG9ydEVycm9yYCBpZiB0aGUgYm9keSBpcyBub3QgY29ycmVjdC5cclxuICogQHRocm93cyB7RXhwb3J0RXJyb3J9IFRocm93cyBhbiBgRXhwb3J0RXJyb3JgIGlmIHRoZSBjaGFydCBkYXRhIGZyb20gdGhlIGJvZHlcclxuICogaXMgbm90IGNvcnJlY3QuXHJcbiAqIEB0aHJvd3Mge0V4cG9ydEVycm9yfSBUaHJvd3MgYW4gYEV4cG9ydEVycm9yYCBpbiBjYXNlIG9mIHRoZSBwcml2YXRlIHJhbmdlXHJcbiAqIHVybCBlcnJvci5cclxuICovXHJcbmZ1bmN0aW9uIHJlcXVlc3RCb2R5TWlkZGxld2FyZShyZXF1ZXN0LCByZXNwb25zZSwgbmV4dCkge1xyXG4gIHRyeSB7XHJcbiAgICAvLyBHZXQgdGhlIHJlcXVlc3QgYm9keVxyXG4gICAgY29uc3QgYm9keSA9IHJlcXVlc3QuYm9keTtcclxuXHJcbiAgICAvLyBDcmVhdGUgYSB1bmlxdWUgSUQgZm9yIGEgcmVxdWVzdFxyXG4gICAgY29uc3QgcmVxdWVzdElkID0gdXVpZCgpO1xyXG5cclxuICAgIC8vIFRocm93IGFuIGVycm9yIGlmIHRoZXJlIGlzIG5vIGNvcnJlY3QgYm9keVxyXG4gICAgaWYgKCFib2R5IHx8IGlzT2JqZWN0RW1wdHkoYm9keSkpIHtcclxuICAgICAgbG9nKFxyXG4gICAgICAgIDIsXHJcbiAgICAgICAgYFt2YWxpZGF0aW9uXSBSZXF1ZXN0IFske3JlcXVlc3RJZH1dIC0gVGhlIHJlcXVlc3QgZnJvbSAke1xyXG4gICAgICAgICAgcmVxdWVzdC5oZWFkZXJzWyd4LWZvcndhcmRlZC1mb3InXSB8fCByZXF1ZXN0LmNvbm5lY3Rpb24ucmVtb3RlQWRkcmVzc1xyXG4gICAgICAgIH0gd2FzIGluY29ycmVjdC4gUmVjZWl2ZWQgcGF5bG9hZCBpcyBlbXB0eS5gXHJcbiAgICAgICk7XHJcblxyXG4gICAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoXHJcbiAgICAgICAgYFt2YWxpZGF0aW9uXSBSZXF1ZXN0IFske3JlcXVlc3RJZH1dIC0gVGhlIHJlcXVlc3QgYm9keSBpcyByZXF1aXJlZC4gUGxlYXNlIGVuc3VyZSB0aGF0IHlvdXIgQ29udGVudC1UeXBlIGhlYWRlciBpcyBjb3JyZWN0LiBBY2NlcHRlZCB0eXBlcyBhcmUgJ2FwcGxpY2F0aW9uL2pzb24nIGFuZCAnbXVsdGlwYXJ0L2Zvcm0tZGF0YScuYCxcclxuICAgICAgICA0MDBcclxuICAgICAgKTtcclxuICAgIH1cclxuXHJcbiAgICAvLyBHZXQgdGhlIGBhbGxvd0NvZGVFeGVjdXRpb25gIG9wdGlvbiBmb3IgdGhlIHNlcnZlclxyXG4gICAgY29uc3QgYWxsb3dDb2RlRXhlY3V0aW9uID0gZ2V0QWxsb3dDb2RlRXhlY3V0aW9uKCk7XHJcblxyXG4gICAgLy8gRmluZCBhIGNvcnJlY3QgY2hhcnQgb3B0aW9uc1xyXG4gICAgY29uc3QgaW5zdHIgPSBpc0FsbG93ZWRDb25maWcoXHJcbiAgICAgIC8vIFVzZSBvbmUgb2YgdGhlIGJlbG93XHJcbiAgICAgIGJvZHkuaW5zdHIgfHwgYm9keS5vcHRpb25zIHx8IGJvZHkuaW5maWxlIHx8IGJvZHkuZGF0YSxcclxuICAgICAgLy8gU3RyaW5naWZ5IG9wdGlvbnNcclxuICAgICAgdHJ1ZSxcclxuICAgICAgLy8gQWxsb3cgb3IgZGlzYWxsb3cgZnVuY3Rpb25zXHJcbiAgICAgIGFsbG93Q29kZUV4ZWN1dGlvblxyXG4gICAgKTtcclxuXHJcbiAgICAvLyBUaHJvdyBhbiBlcnJvciBpZiB0aGVyZSBpcyBubyBjb3JyZWN0IGNoYXJ0IGRhdGFcclxuICAgIGlmIChpbnN0ciA9PT0gbnVsbCAmJiAhYm9keS5zdmcpIHtcclxuICAgICAgbG9nKFxyXG4gICAgICAgIDIsXHJcbiAgICAgICAgYFt2YWxpZGF0aW9uXSBSZXF1ZXN0IFske3JlcXVlc3RJZH1dIC0gVGhlIHJlcXVlc3QgZnJvbSAke1xyXG4gICAgICAgICAgcmVxdWVzdC5oZWFkZXJzWyd4LWZvcndhcmRlZC1mb3InXSB8fCByZXF1ZXN0LmNvbm5lY3Rpb24ucmVtb3RlQWRkcmVzc1xyXG4gICAgICAgIH0gd2FzIGluY29ycmVjdC4gUmVjZWl2ZWQgcGF5bG9hZCBpcyBtaXNzaW5nIGNvcnJlY3QgY2hhcnQgZGF0YSBmb3IgZXhwb3J0OiAke0pTT04uc3RyaW5naWZ5KGJvZHkpfS5gXHJcbiAgICAgICk7XHJcblxyXG4gICAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoXHJcbiAgICAgICAgYFJlcXVlc3QgWyR7cmVxdWVzdElkfV0gLSBbdmFsaWRhdGlvbl0gTm8gY29ycmVjdCBjaGFydCBkYXRhIGZvdW5kLiBFbnN1cmUgdGhhdCB5b3UgYXJlIHVzaW5nIGVpdGhlciBhcHBsaWNhdGlvbi9qc29uIG9yIG11bHRpcGFydC9mb3JtLWRhdGEgaGVhZGVycy4gSWYgc2VuZGluZyBKU09OLCBtYWtlIHN1cmUgdGhlIGNoYXJ0IGRhdGEgaXMgaW4gdGhlICdpbmZpbGUnLCAnb3B0aW9ucycsIG9yICdkYXRhJyBhdHRyaWJ1dGUuIElmIHNlbmRpbmcgU1ZHLCBlbnN1cmUgaXQgaXMgaW4gdGhlICdzdmcnIGF0dHJpYnV0ZS5gLFxyXG4gICAgICAgIDQwMFxyXG4gICAgICApO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIFRocm93IGFuIGVycm9yIGlmIHRlc3Qgb2YgeGxpbms6aHJlZiBlbGVtZW50cyBmcm9tIHBheWxvYWQncyBTVkcgZmFpbHNcclxuICAgIGlmIChib2R5LnN2ZyAmJiBpc1ByaXZhdGVSYW5nZVVybEZvdW5kKGJvZHkuc3ZnKSkge1xyXG4gICAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoXHJcbiAgICAgICAgYFJlcXVlc3QgWyR7cmVxdWVzdElkfV0gLSBbdmFsaWRhdGlvbl0gU1ZHIHBvdGVudGlhbGx5IGNvbnRhaW4gYXQgbGVhc3Qgb25lIGZvcmJpZGRlbiBVUkwgaW4gJ3hsaW5rOmhyZWYnIGVsZW1lbnQuIFBsZWFzZSByZXZpZXcgdGhlIFNWRyBjb250ZW50IGFuZCBlbnN1cmUgdGhhdCBhbGwgcmVmZXJlbmNlZCBVUkxzIGNvbXBseSB3aXRoIHNlY3VyaXR5IHBvbGljaWVzLmAsXHJcbiAgICAgICAgNDAwXHJcbiAgICAgICk7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gVmFsaWRhdGUgdGhlIHJlcXVlc3Qgb3B0aW9ucyBhbmQgc3RvcmUgcGFyc2VkIHN0cnVjdHVyZSBpbiB0aGUgcmVxdWVzdFxyXG4gICAgcmVxdWVzdC52YWxpZGF0ZWRPcHRpb25zID0gdmFsaWRhdGVPcHRpb25zKHtcclxuICAgICAgLy8gU2V0IHRoZSBjcmVhdGVkIElEIGFzIGEgYHJlcXVlc3RJZGAgcHJvcGVydHkgaW4gdGhlIG9wdGlvbnNcclxuICAgICAgcmVxdWVzdElkLFxyXG4gICAgICBleHBvcnQ6IHtcclxuICAgICAgICBpbnN0cixcclxuICAgICAgICBzdmc6IGJvZHkuc3ZnLFxyXG4gICAgICAgIG91dGZpbGU6XHJcbiAgICAgICAgICBib2R5Lm91dGZpbGUgfHxcclxuICAgICAgICAgIGAke3JlcXVlc3QucGFyYW1zLmZpbGVuYW1lIHx8ICdjaGFydCd9LiR7Ym9keS50eXBlIHx8ICdwbmcnfWAsXHJcbiAgICAgICAgdHlwZTogYm9keS50eXBlLFxyXG4gICAgICAgIGNvbnN0cjogYm9keS5jb25zdHIsXHJcbiAgICAgICAgYjY0OiBib2R5LmI2NCxcclxuICAgICAgICBub0Rvd25sb2FkOiBib2R5Lm5vRG93bmxvYWQsXHJcbiAgICAgICAgaGVpZ2h0OiBib2R5LmhlaWdodCxcclxuICAgICAgICB3aWR0aDogYm9keS53aWR0aCxcclxuICAgICAgICBzY2FsZTogYm9keS5zY2FsZSxcclxuICAgICAgICBnbG9iYWxPcHRpb25zOiBpc0FsbG93ZWRDb25maWcoXHJcbiAgICAgICAgICBib2R5Lmdsb2JhbE9wdGlvbnMsXHJcbiAgICAgICAgICB0cnVlLFxyXG4gICAgICAgICAgYWxsb3dDb2RlRXhlY3V0aW9uXHJcbiAgICAgICAgKSxcclxuICAgICAgICB0aGVtZU9wdGlvbnM6IGlzQWxsb3dlZENvbmZpZyhcclxuICAgICAgICAgIGJvZHkudGhlbWVPcHRpb25zLFxyXG4gICAgICAgICAgdHJ1ZSxcclxuICAgICAgICAgIGFsbG93Q29kZUV4ZWN1dGlvblxyXG4gICAgICAgIClcclxuICAgICAgfSxcclxuICAgICAgY3VzdG9tTG9naWM6IHtcclxuICAgICAgICBhbGxvd0NvZGVFeGVjdXRpb24sXHJcbiAgICAgICAgYWxsb3dGaWxlUmVzb3VyY2VzOiBmYWxzZSxcclxuICAgICAgICBjdXN0b21Db2RlOiBib2R5LmN1c3RvbUNvZGUsXHJcbiAgICAgICAgY2FsbGJhY2s6IGJvZHkuY2FsbGJhY2ssXHJcbiAgICAgICAgcmVzb3VyY2VzOiBpc0FsbG93ZWRDb25maWcoYm9keS5yZXNvdXJjZXMsIHRydWUsIGFsbG93Q29kZUV4ZWN1dGlvbilcclxuICAgICAgfVxyXG4gICAgfSk7XHJcblxyXG4gICAgLy8gQ2FsbCB0aGUgbmV4dCBtaWRkbGV3YXJlXHJcbiAgICByZXR1cm4gbmV4dCgpO1xyXG4gIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICByZXR1cm4gbmV4dChlcnJvcik7XHJcbiAgfVxyXG59XHJcblxyXG4vKipcclxuICogQWRkcyB0aGUgdmFsaWRhdGlvbiBtaWRkbGV3YXJlcyB0byB0aGUgcGFzc2VkIGV4cHJlc3MgYXBwIGluc3RhbmNlLlxyXG4gKlxyXG4gKiBAcGFyYW0ge0V4cHJlc3N9IGFwcCAtIFRoZSBFeHByZXNzIGFwcCBpbnN0YW5jZS5cclxuICovXHJcbmV4cG9ydCBkZWZhdWx0IGZ1bmN0aW9uIHZhbGlkYXRpb25NaWRkbGV3YXJlKGFwcCkge1xyXG4gIC8vIEFkZCBjb250ZW50IHR5cGUgdmFsaWRhdGlvbiBtaWRkbGV3YXJlXHJcbiAgYXBwLnBvc3QoWycvJywgJy86ZmlsZW5hbWUnXSwgY29udGVudFR5cGVNaWRkbGV3YXJlKTtcclxuXHJcbiAgLy8gQWRkIHJlcXVlc3QgYm9keSByZXF1ZXN0IHZhbGlkYXRpb24gbWlkZGxld2FyZVxyXG4gIGFwcC5wb3N0KFsnLycsICcvOmZpbGVuYW1lJ10sIHJlcXVlc3RCb2R5TWlkZGxld2FyZSk7XHJcbn1cclxuIiwiLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcclxuXHJcbkhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlclxyXG5cclxuQ29weXJpZ2h0IChjKSAyMDE2LTIwMjUsIEhpZ2hzb2Z0XHJcblxyXG5MaWNlbmNlZCB1bmRlciB0aGUgTUlUIGxpY2VuY2UuXHJcblxyXG5BZGRpdGlvbmFsbHkgYSB2YWxpZCBIaWdoY2hhcnRzIGxpY2Vuc2UgaXMgcmVxdWlyZWQgZm9yIHVzZS5cclxuXHJcblNlZSBMSUNFTlNFIGZpbGUgaW4gcm9vdCBmb3IgZGV0YWlscy5cclxuXHJcbioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXHJcblxyXG4vKipcclxuICogQG92ZXJ2aWV3IERlZmluZXMgdGhlIGV4cG9ydCByb3V0ZXMgYW5kIGxvZ2ljIGZvciBoYW5kbGluZyBjaGFydCBleHBvcnRcclxuICogcmVxdWVzdHMgaW4gYW4gRXhwcmVzcyBzZXJ2ZXIuIFRoaXMgbW9kdWxlIHByb2Nlc3NlcyBpbmNvbWluZyByZXF1ZXN0c1xyXG4gKiB0byBleHBvcnQgY2hhcnRzIGluIHZhcmlvdXMgZm9ybWF0cyAoZS5nLiBKUEVHLCBQTkcsIFBERiwgU1ZHKS4gSXQgaW50ZWdyYXRlc1xyXG4gKiB3aXRoIEhpZ2hjaGFydHMnIGNvcmUgZnVuY3Rpb25hbGl0aWVzIGFuZCBzdXBwb3J0cyBib3RoIGltbWVkaWF0ZSBkb3dubG9hZFxyXG4gKiByZXNwb25zZXMgYW5kIEJhc2U2NC1lbmNvZGVkIGNvbnRlbnQgcmV0dXJucy4gVGhlIGNvZGUgYWxzbyBmZWF0dXJlc1xyXG4gKiBiZW5jaG1hcmtpbmcgZm9yIHBlcmZvcm1hbmNlIG1vbml0b3JpbmcuXHJcbiAqL1xyXG5cclxuaW1wb3J0IHsgc3RhcnRFeHBvcnQgfSBmcm9tICcuLi8uLi9jaGFydC5qcyc7XHJcbmltcG9ydCB7IGxvZyB9IGZyb20gJy4uLy4uL2xvZ2dlci5qcyc7XHJcbmltcG9ydCB7IGdldEJhc2U2NCwgbWVhc3VyZVRpbWUgfSBmcm9tICcuLi8uLi91dGlscy5qcyc7XHJcblxyXG5pbXBvcnQgRXhwb3J0RXJyb3IgZnJvbSAnLi4vLi4vZXJyb3JzL0V4cG9ydEVycm9yLmpzJztcclxuXHJcbi8vIFJldmVyc2VkIE1JTUUgdHlwZXNcclxuY29uc3QgcmV2ZXJzZWRNaW1lID0ge1xyXG4gIHBuZzogJ2ltYWdlL3BuZycsXHJcbiAganBlZzogJ2ltYWdlL2pwZWcnLFxyXG4gIGdpZjogJ2ltYWdlL2dpZicsXHJcbiAgcGRmOiAnYXBwbGljYXRpb24vcGRmJyxcclxuICBzdmc6ICdpbWFnZS9zdmcreG1sJ1xyXG59O1xyXG5cclxuLyoqXHJcbiAqIEhhbmRsZXMgdGhlIGV4cG9ydCByZXF1ZXN0cyBmcm9tIHRoZSBjbGllbnQuXHJcbiAqXHJcbiAqIEBhc3luY1xyXG4gKiBAZnVuY3Rpb24gcmVxdWVzdEV4cG9ydFxyXG4gKlxyXG4gKiBAcGFyYW0ge0V4cHJlc3MuUmVxdWVzdH0gcmVxdWVzdCAtIFRoZSBFeHByZXNzIHJlcXVlc3Qgb2JqZWN0LlxyXG4gKiBAcGFyYW0ge0V4cHJlc3MuUmVzcG9uc2V9IHJlc3BvbnNlIC0gVGhlIEV4cHJlc3MgcmVzcG9uc2Ugb2JqZWN0LlxyXG4gKiBAcGFyYW0ge0Z1bmN0aW9ufSBuZXh0IC0gVGhlIG5leHQgbWlkZGxld2FyZSBmdW5jdGlvbi5cclxuICpcclxuICogQHJldHVybnMge1Byb21pc2U8dm9pZD59IEEgUHJvbWlzZSB0aGF0IHJlc29sdmVzIG9uY2UgdGhlIGV4cG9ydCBwcm9jZXNzXHJcbiAqIGlzIGNvbXBsZXRlLlxyXG4gKi9cclxuYXN5bmMgZnVuY3Rpb24gcmVxdWVzdEV4cG9ydChyZXF1ZXN0LCByZXNwb25zZSwgbmV4dCkge1xyXG4gIHRyeSB7XHJcbiAgICAvLyBTdGFydCBjb3VudGluZyB0aW1lIGZvciBhIHJlcXVlc3RcclxuICAgIGNvbnN0IHJlcXVlc3RDb3VudGVyID0gbWVhc3VyZVRpbWUoKTtcclxuXHJcbiAgICAvLyBJbiBjYXNlIHRoZSBjb25uZWN0aW9uIGlzIGNsb3NlZCwgZm9yY2UgdG8gYWJvcnQgZnVydGhlciBhY3Rpb25zXHJcbiAgICBsZXQgY29ubmVjdGlvbkFib3J0ZWQgPSBmYWxzZTtcclxuICAgIHJlcXVlc3Quc29ja2V0Lm9uKCdjbG9zZScsIChoYWRFcnJvcnMpID0+IHtcclxuICAgICAgaWYgKGhhZEVycm9ycykge1xyXG4gICAgICAgIGNvbm5lY3Rpb25BYm9ydGVkID0gdHJ1ZTtcclxuICAgICAgfVxyXG4gICAgfSk7XHJcblxyXG4gICAgLy8gR2V0IHRoZSBvcHRpb25zIHByZXZpb3VzbHkgdmFsaWRhdGVkIGluIHRoZSB2YWxpZGF0aW9uIG1pZGRsZXdhcmVcclxuICAgIGNvbnN0IHJlcXVlc3RPcHRpb25zID0gcmVxdWVzdC52YWxpZGF0ZWRPcHRpb25zO1xyXG5cclxuICAgIC8vIEdldCB0aGUgcmVxdWVzdCBpZFxyXG4gICAgY29uc3QgcmVxdWVzdElkID0gcmVxdWVzdE9wdGlvbnMucmVxdWVzdElkO1xyXG5cclxuICAgIC8vIEluZm8gYWJvdXQgYW4gaW5jb21pbmcgcmVxdWVzdCB3aXRoIGNvcnJlY3QgZGF0YVxyXG4gICAgbG9nKDQsIGBbZXhwb3J0XSBSZXF1ZXN0IFske3JlcXVlc3RJZH1dIC0gR290IGFuIGluY29taW5nIEhUVFAgcmVxdWVzdC5gKTtcclxuXHJcbiAgICAvLyBTdGFydCB0aGUgZXhwb3J0IHByb2Nlc3NcclxuICAgIGF3YWl0IHN0YXJ0RXhwb3J0KHJlcXVlc3RPcHRpb25zLCAoZXJyb3IsIGRhdGEpID0+IHtcclxuICAgICAgLy8gUmVtb3ZlIHRoZSBjbG9zZSBldmVudCBmcm9tIHRoZSBzb2NrZXRcclxuICAgICAgcmVxdWVzdC5zb2NrZXQucmVtb3ZlQWxsTGlzdGVuZXJzKCdjbG9zZScpO1xyXG5cclxuICAgICAgLy8gSWYgdGhlIGNvbm5lY3Rpb24gd2FzIGNsb3NlZCwgZG8gbm90aGluZ1xyXG4gICAgICBpZiAoY29ubmVjdGlvbkFib3J0ZWQpIHtcclxuICAgICAgICBsb2coXHJcbiAgICAgICAgICAzLFxyXG4gICAgICAgICAgYFtleHBvcnRdIFJlcXVlc3QgWyR7cmVxdWVzdElkfV0gLSBUaGUgY2xpZW50IGNsb3NlZCB0aGUgY29ubmVjdGlvbiBiZWZvcmUgdGhlIGNoYXJ0IGZpbmlzaGVkIHByb2Nlc3NpbmcuYFxyXG4gICAgICAgICk7XHJcbiAgICAgICAgcmV0dXJuO1xyXG4gICAgICB9XHJcblxyXG4gICAgICAvLyBJZiBlcnJvciwgbG9nIGl0IGFuZCBzZW5kIGl0IHRvIHRoZSBlcnJvciBtaWRkbGV3YXJlXHJcbiAgICAgIGlmIChlcnJvcikge1xyXG4gICAgICAgIHRocm93IGVycm9yO1xyXG4gICAgICB9XHJcblxyXG4gICAgICAvLyBJZiBkYXRhIGlzIG1pc3NpbmcsIGxvZyB0aGUgbWVzc2FnZSBhbmQgc2VuZCBpdCB0byB0aGUgZXJyb3IgbWlkZGxld2FyZVxyXG4gICAgICBpZiAoIWRhdGEgfHwgIWRhdGEucmVzdWx0KSB7XHJcbiAgICAgICAgbG9nKFxyXG4gICAgICAgICAgMixcclxuICAgICAgICAgIGBbZXhwb3J0XSBSZXF1ZXN0IFske3JlcXVlc3RJZH1dIC0gUmVxdWVzdCBmcm9tICR7XHJcbiAgICAgICAgICAgIHJlcXVlc3QuaGVhZGVyc1sneC1mb3J3YXJkZWQtZm9yJ10gfHxcclxuICAgICAgICAgICAgcmVxdWVzdC5jb25uZWN0aW9uLnJlbW90ZUFkZHJlc3NcclxuICAgICAgICAgIH0gd2FzIGluY29ycmVjdC4gUmVjZWl2ZWQgcmVzdWx0IGlzICR7ZGF0YS5yZXN1bHR9LmBcclxuICAgICAgICApO1xyXG5cclxuICAgICAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoXHJcbiAgICAgICAgICBgW2V4cG9ydF0gUmVxdWVzdCBbJHtyZXF1ZXN0SWR9XSAtIFVuZXhwZWN0ZWQgcmV0dXJuIG9mIHRoZSBleHBvcnQgcmVzdWx0IGZyb20gdGhlIGNoYXJ0IGdlbmVyYXRpb24uIFBsZWFzZSBjaGVjayB5b3VyIHJlcXVlc3QgZGF0YS5gLFxyXG4gICAgICAgICAgNDAwXHJcbiAgICAgICAgKTtcclxuICAgICAgfVxyXG5cclxuICAgICAgLy8gUmV0dXJuIHRoZSByZXN1bHQgaW4gYW4gYXBwcm9wcmlhdGUgZm9ybWF0XHJcbiAgICAgIGlmIChkYXRhLnJlc3VsdCkge1xyXG4gICAgICAgIGxvZyhcclxuICAgICAgICAgIDMsXHJcbiAgICAgICAgICBgW2V4cG9ydF0gUmVxdWVzdCBbJHtyZXF1ZXN0SWR9XSAtIFRoZSB3aG9sZSBleHBvcnRpbmcgcHJvY2VzcyB0b29rICR7cmVxdWVzdENvdW50ZXIoKX1tcy5gXHJcbiAgICAgICAgKTtcclxuXHJcbiAgICAgICAgLy8gR2V0IHRoZSBgdHlwZWAsIGBiNjRgLCBgbm9Eb3dubG9hZGAsIGFuZCBgb3V0ZmlsZWAgZnJvbSBvcHRpb25zXHJcbiAgICAgICAgY29uc3QgeyB0eXBlLCBiNjQsIG5vRG93bmxvYWQsIG91dGZpbGUgfSA9IGRhdGEub3B0aW9ucy5leHBvcnQ7XHJcblxyXG4gICAgICAgIC8vIElmIG9ubHkgQmFzZTY0IGlzIHJlcXVpcmVkLCByZXR1cm4gaXRcclxuICAgICAgICBpZiAoYjY0KSB7XHJcbiAgICAgICAgICByZXR1cm4gcmVzcG9uc2Uuc2VuZChnZXRCYXNlNjQoZGF0YS5yZXN1bHQsIHR5cGUpKTtcclxuICAgICAgICB9XHJcblxyXG4gICAgICAgIC8vIFNldCBjb3JyZWN0IGNvbnRlbnQgdHlwZVxyXG4gICAgICAgIHJlc3BvbnNlLmhlYWRlcignQ29udGVudC1UeXBlJywgcmV2ZXJzZWRNaW1lW3R5cGVdIHx8ICdpbWFnZS9wbmcnKTtcclxuXHJcbiAgICAgICAgLy8gRGVjaWRlIHdoZXRoZXIgdG8gZG93bmxvYWQgb3Igbm90IGNoYXJ0IGZpbGVcclxuICAgICAgICBpZiAoIW5vRG93bmxvYWQpIHtcclxuICAgICAgICAgIHJlc3BvbnNlLmF0dGFjaG1lbnQob3V0ZmlsZSk7XHJcbiAgICAgICAgfVxyXG5cclxuICAgICAgICAvLyBJZiBTVkcsIHJldHVybiBwbGFpbiBjb250ZW50LCBvdGhlcndpc2UgYSBiNjQgc3RyaW5nIGZyb20gYSBidWZmZXJcclxuICAgICAgICByZXR1cm4gdHlwZSA9PT0gJ3N2ZydcclxuICAgICAgICAgID8gcmVzcG9uc2Uuc2VuZChkYXRhLnJlc3VsdClcclxuICAgICAgICAgIDogcmVzcG9uc2Uuc2VuZChCdWZmZXIuZnJvbShkYXRhLnJlc3VsdCwgJ2Jhc2U2NCcpKTtcclxuICAgICAgfVxyXG4gICAgfSk7XHJcbiAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgIHJldHVybiBuZXh0KGVycm9yKTtcclxuICB9XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBBZGRzIHRoZSBgZXhwb3J0YCByb3V0ZXMuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBleHBvcnRSb3V0ZXNcclxuICpcclxuICogQHBhcmFtIHtFeHByZXNzfSBhcHAgLSBUaGUgRXhwcmVzcyBhcHAgaW5zdGFuY2UuXHJcbiAqL1xyXG5leHBvcnQgZGVmYXVsdCBmdW5jdGlvbiBleHBvcnRSb3V0ZXMoYXBwKSB7XHJcbiAgLyoqXHJcbiAgICogQWRkcyB0aGUgUE9TVCAnLycgLSBBIHJvdXRlIGZvciBoYW5kbGluZyBQT1NUIHJlcXVlc3RzIGF0IHRoZSByb290XHJcbiAgICogZW5kcG9pbnQuXHJcbiAgICovXHJcbiAgYXBwLnBvc3QoJy8nLCByZXF1ZXN0RXhwb3J0KTtcclxuXHJcbiAgLyoqXHJcbiAgICogQWRkcyB0aGUgUE9TVCAnLzpmaWxlbmFtZScgLSBBIHJvdXRlIGZvciBoYW5kbGluZyBQT1NUIHJlcXVlc3RzIHdpdGhcclxuICAgKiBhIHNwZWNpZmllZCBmaWxlbmFtZSBwYXJhbWV0ZXIuXHJcbiAgICovXHJcbiAgYXBwLnBvc3QoJy86ZmlsZW5hbWUnLCByZXF1ZXN0RXhwb3J0KTtcclxufVxyXG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxyXG5cclxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXHJcblxyXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNSwgSGlnaHNvZnRcclxuXHJcbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cclxuXHJcbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxyXG5cclxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxyXG5cclxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cclxuXHJcbi8qKlxyXG4gKiBAb3ZlcnZpZXcgRGVmaW5lcyBhbiBFeHByZXNzIHJvdXRlIGZvciBzZXJ2ZXIgaGVhbHRoIG1vbml0b3JpbmcsIGluY2x1ZGluZ1xyXG4gKiB1cHRpbWUsIHN1Y2Nlc3MgcmF0ZXMsIGFuZCBvdGhlciBzZXJ2ZXIgc3RhdGlzdGljcy5cclxuICovXHJcblxyXG5pbXBvcnQgeyByZWFkRmlsZVN5bmMgfSBmcm9tICdmcyc7XHJcbmltcG9ydCB7IGpvaW4gfSBmcm9tICdwYXRoJztcclxuXHJcbmltcG9ydCB7IGdldEhpZ2hjaGFydHNWZXJzaW9uIH0gZnJvbSAnLi4vLi4vY2FjaGUuanMnO1xyXG5pbXBvcnQgeyBsb2cgfSBmcm9tICcuLi8uLi9sb2dnZXIuanMnO1xyXG5pbXBvcnQgeyBnZXRQb29sSW5mb0pTT04sIGdldFBvb2xTdGF0cyB9IGZyb20gJy4uLy4uL3Bvb2wuanMnO1xyXG5pbXBvcnQgeyBhZGRUaW1lciB9IGZyb20gJy4uLy4uL3RpbWVyLmpzJztcclxuaW1wb3J0IHsgX19kaXJuYW1lLCBnZXROZXdEYXRlVGltZSB9IGZyb20gJy4uLy4uL3V0aWxzLmpzJztcclxuXHJcbi8vIFNldCB0aGUgc3RhcnQgZGF0ZSBvZiB0aGUgc2VydmVyXHJcbmNvbnN0IHNlcnZlclN0YXJ0VGltZSA9IG5ldyBEYXRlKCk7XHJcblxyXG4vLyBHZXQgdGhlIGBwYWNrYWdlLmpzb25gIGNvbnRlbnRcclxuY29uc3QgcGFja2FnZUZpbGUgPSBKU09OLnBhcnNlKFxyXG4gIHJlYWRGaWxlU3luYyhqb2luKF9fZGlybmFtZSwgJ3BhY2thZ2UuanNvbicpLCAndXRmOCcpXHJcbik7XHJcblxyXG4vLyBBbiBhcnJheSBmb3Igc3VjY2VzcyByYXRlIHJhdGlvc1xyXG5jb25zdCBzdWNjZXNzUmF0ZXMgPSBbXTtcclxuXHJcbi8vIFJlY29yZCBldmVyeSBtaW51dGVcclxuY29uc3QgcmVjb3JkSW50ZXJ2YWwgPSA2MCAqIDEwMDA7XHJcblxyXG4vLyAzMCBtaW51dGVzXHJcbmNvbnN0IHdpbmRvd1NpemUgPSAzMDtcclxuXHJcbi8qKlxyXG4gKiBDYWxjdWxhdGVzIG1vdmluZyBhdmVyYWdlIGluZGljYXRvciBiYXNlZCBvbiB0aGUgZGF0YSBmcm9tIHRoZSBgc3VjY2Vzc1JhdGVzYFxyXG4gKiBhcnJheS5cclxuICpcclxuICogQGZ1bmN0aW9uIF9jYWxjdWxhdGVNb3ZpbmdBdmVyYWdlXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtudW1iZXJ9IEEgbW92aW5nIGF2ZXJhZ2UgZm9yIHN1Y2Nlc3MgcmF0aW8gb2YgdGhlIHNlcnZlciBleHBvcnRzLlxyXG4gKi9cclxuZnVuY3Rpb24gX2NhbGN1bGF0ZU1vdmluZ0F2ZXJhZ2UoKSB7XHJcbiAgcmV0dXJuIHN1Y2Nlc3NSYXRlcy5yZWR1Y2UoKGEsIGIpID0+IGEgKyBiLCAwKSAvIHN1Y2Nlc3NSYXRlcy5sZW5ndGg7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBTdGFydHMgdGhlIGludGVydmFsIHJlc3BvbnNpYmxlIGZvciBjYWxjdWxhdGluZyBjdXJyZW50IHN1Y2Nlc3MgcmF0ZSByYXRpb1xyXG4gKiBhbmQgY29sbGVjdHMgcmVjb3JkcyB0byB0aGUgYHN1Y2Nlc3NSYXRlc2AgYXJyYXkuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBfc3RhcnRTdWNjZXNzUmF0ZVxyXG4gKlxyXG4gKiBAcmV0dXJucyB7Tm9kZUpTLlRpbWVvdXR9IElkIG9mIGFuIGludGVydmFsLlxyXG4gKi9cclxuZnVuY3Rpb24gX3N0YXJ0U3VjY2Vzc1JhdGUoKSB7XHJcbiAgcmV0dXJuIHNldEludGVydmFsKCgpID0+IHtcclxuICAgIGNvbnN0IHN0YXRzID0gZ2V0UG9vbFN0YXRzKCk7XHJcbiAgICBjb25zdCBzdWNjZXNzUmF0aW8gPVxyXG4gICAgICBzdGF0cy5leHBvcnRzQXR0ZW1wdGVkID09PSAwXHJcbiAgICAgICAgPyAxXHJcbiAgICAgICAgOiAoc3RhdHMuZXhwb3J0c1BlcmZvcm1lZCAvIHN0YXRzLmV4cG9ydHNBdHRlbXB0ZWQpICogMTAwO1xyXG5cclxuICAgIHN1Y2Nlc3NSYXRlcy5wdXNoKHN1Y2Nlc3NSYXRpbyk7XHJcbiAgICBpZiAoc3VjY2Vzc1JhdGVzLmxlbmd0aCA+IHdpbmRvd1NpemUpIHtcclxuICAgICAgc3VjY2Vzc1JhdGVzLnNoaWZ0KCk7XHJcbiAgICB9XHJcbiAgfSwgcmVjb3JkSW50ZXJ2YWwpO1xyXG59XHJcblxyXG4vKipcclxuICogQWRkcyB0aGUgYGhlYWx0aGAgcm91dGVzLlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gaGVhbHRoUm91dGVzXHJcbiAqXHJcbiAqIEBwYXJhbSB7RXhwcmVzc30gYXBwIC0gVGhlIEV4cHJlc3MgYXBwIGluc3RhbmNlLlxyXG4gKi9cclxuZXhwb3J0IGRlZmF1bHQgZnVuY3Rpb24gaGVhbHRoUm91dGVzKGFwcCkge1xyXG4gIC8vIFN0YXJ0IHByb2Nlc3Npbmcgc3VjY2VzcyByYXRlIHJhdGlvIGludGVydmFsIGFuZCBzYXZlIGl0cyBpZCB0byB0aGUgYXJyYXlcclxuICAvLyBmb3IgdGhlIGdyYWNlZnVsIGNsZWFyaW5nIG9uIHNodXRkb3duIHdpdGggaW5qZWN0ZWQgYGFkZFRpbWVyYCBmdW50aW9uXHJcbiAgYWRkVGltZXIoX3N0YXJ0U3VjY2Vzc1JhdGUoKSk7XHJcblxyXG4gIC8qKlxyXG4gICAqIEFkZHMgdGhlIEdFVCAnL2hlYWx0aCcgLSBBIHJvdXRlIGZvciBnZXR0aW5nIHRoZSBiYXNpYyBzdGF0cyBvZiB0aGUgc2VydmVyLlxyXG4gICAqL1xyXG4gIGFwcC5nZXQoJy9oZWFsdGgnLCAocmVxdWVzdCwgcmVzcG9uc2UsIG5leHQpID0+IHtcclxuICAgIHRyeSB7XHJcbiAgICAgIGxvZyg0LCAnW2hlYWx0aF0gUmV0dXJuaW5nIHNlcnZlciBoZWFsdGguJyk7XHJcblxyXG4gICAgICBjb25zdCBzdGF0cyA9IGdldFBvb2xTdGF0cygpO1xyXG4gICAgICBjb25zdCBwZXJpb2QgPSBzdWNjZXNzUmF0ZXMubGVuZ3RoO1xyXG4gICAgICBjb25zdCBtb3ZpbmdBdmVyYWdlID0gX2NhbGN1bGF0ZU1vdmluZ0F2ZXJhZ2UoKTtcclxuXHJcbiAgICAgIC8vIFNlbmQgdGhlIHNlcnZlcidzIHN0YXRpc3RpY3NcclxuICAgICAgcmVzcG9uc2Uuc2VuZCh7XHJcbiAgICAgICAgLy8gU3RhdHVzIGFuZCB0aW1lc1xyXG4gICAgICAgIHN0YXR1czogJ09LJyxcclxuICAgICAgICBib290VGltZTogc2VydmVyU3RhcnRUaW1lLFxyXG4gICAgICAgIHVwdGltZTogYCR7TWF0aC5mbG9vcigoZ2V0TmV3RGF0ZVRpbWUoKSAtIHNlcnZlclN0YXJ0VGltZS5nZXRUaW1lKCkpIC8gMTAwMCAvIDYwKX0gbWludXRlc2AsXHJcblxyXG4gICAgICAgIC8vIFZlcnNpb25zXHJcbiAgICAgICAgc2VydmVyVmVyc2lvbjogcGFja2FnZUZpbGUudmVyc2lvbixcclxuICAgICAgICBoaWdoY2hhcnRzVmVyc2lvbjogZ2V0SGlnaGNoYXJ0c1ZlcnNpb24oKSxcclxuXHJcbiAgICAgICAgLy8gRXhwb3J0c1xyXG4gICAgICAgIGF2ZXJhZ2VFeHBvcnRUaW1lOiBzdGF0cy50aW1lU3BlbnRBdmVyYWdlLFxyXG4gICAgICAgIGF0dGVtcHRlZEV4cG9ydHM6IHN0YXRzLmV4cG9ydHNBdHRlbXB0ZWQsXHJcbiAgICAgICAgcGVyZm9ybWVkRXhwb3J0czogc3RhdHMuZXhwb3J0c1BlcmZvcm1lZCxcclxuICAgICAgICBmYWlsZWRFeHBvcnRzOiBzdGF0cy5leHBvcnRzRHJvcHBlZCxcclxuICAgICAgICBzdWNlc3NSYXRpbzogKHN0YXRzLmV4cG9ydHNQZXJmb3JtZWQgLyBzdGF0cy5leHBvcnRzQXR0ZW1wdGVkKSAqIDEwMCxcclxuXHJcbiAgICAgICAgLy8gUG9vbFxyXG4gICAgICAgIHBvb2w6IGdldFBvb2xJbmZvSlNPTigpLFxyXG5cclxuICAgICAgICAvLyBNb3ZpbmcgYXZlcmFnZVxyXG4gICAgICAgIHBlcmlvZCxcclxuICAgICAgICBtb3ZpbmdBdmVyYWdlLFxyXG4gICAgICAgIG1lc3NhZ2U6XHJcbiAgICAgICAgICBpc05hTihtb3ZpbmdBdmVyYWdlKSB8fCAhc3VjY2Vzc1JhdGVzLmxlbmd0aFxyXG4gICAgICAgICAgICA/ICdUb28gZWFybHkgdG8gcmVwb3J0LiBObyBleHBvcnRzIG1hZGUgeWV0LiBQbGVhc2UgY2hlY2sgYmFjayBzb29uLidcclxuICAgICAgICAgICAgOiBgTGFzdCAke3BlcmlvZH0gbWludXRlcyBoYWQgYSBzdWNjZXNzIHJhdGUgb2YgJHttb3ZpbmdBdmVyYWdlLnRvRml4ZWQoMil9JS5gLFxyXG5cclxuICAgICAgICAvLyBTVkcgYW5kIEpTT04gZXhwb3J0c1xyXG4gICAgICAgIHN2Z0V4cG9ydHM6IHN0YXRzLmV4cG9ydHNGcm9tU3ZnLFxyXG4gICAgICAgIGpzb25FeHBvcnRzOiBzdGF0cy5leHBvcnRzRnJvbU9wdGlvbnMsXHJcbiAgICAgICAgc3ZnRXhwb3J0c0F0dGVtcHRzOiBzdGF0cy5leHBvcnRzRnJvbVN2Z0F0dGVtcHRzLFxyXG4gICAgICAgIGpzb25FeHBvcnRzQXR0ZW1wdHM6IHN0YXRzLmV4cG9ydHNGcm9tT3B0aW9uc0F0dGVtcHRzXHJcbiAgICAgIH0pO1xyXG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICAgcmV0dXJuIG5leHQoZXJyb3IpO1xyXG4gICAgfVxyXG4gIH0pO1xyXG59XHJcbiIsIi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXHJcblxyXG5IaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXJcclxuXHJcbkNvcHlyaWdodCAoYykgMjAxNi0yMDI1LCBIaWdoc29mdFxyXG5cclxuTGljZW5jZWQgdW5kZXIgdGhlIE1JVCBsaWNlbmNlLlxyXG5cclxuQWRkaXRpb25hbGx5IGEgdmFsaWQgSGlnaGNoYXJ0cyBsaWNlbnNlIGlzIHJlcXVpcmVkIGZvciB1c2UuXHJcblxyXG5TZWUgTElDRU5TRSBmaWxlIGluIHJvb3QgZm9yIGRldGFpbHMuXHJcblxyXG4qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xyXG5cclxuLyoqXHJcbiAqIEBvdmVydmlldyBEZWZpbmVzIGFuIEV4cHJlc3Mgcm91dGUgZm9yIHNlcnZpbmcgdGhlIFVJIGZvciB0aGUgZXhwb3J0IHNlcnZlclxyXG4gKiB3aGVuIGVuYWJsZWQuXHJcbiAqL1xyXG5cclxuaW1wb3J0IHsgam9pbiB9IGZyb20gJ3BhdGgnO1xyXG5cclxuaW1wb3J0IHsgZ2V0T3B0aW9ucyB9IGZyb20gJy4uLy4uL2NvbmZpZy5qcyc7XHJcbmltcG9ydCB7IGxvZyB9IGZyb20gJy4uLy4uL2xvZ2dlci5qcyc7XHJcbmltcG9ydCB7IF9fZGlybmFtZSB9IGZyb20gJy4uLy4uL3V0aWxzLmpzJztcclxuXHJcbi8qKlxyXG4gKiBBZGRzIHRoZSBgdWlgIHJvdXRlcy5cclxuICpcclxuICogQGZ1bmN0aW9uIHVpUm91dGVzXHJcbiAqXHJcbiAqIEBwYXJhbSB7RXhwcmVzc30gYXBwIC0gVGhlIEV4cHJlc3MgYXBwIGluc3RhbmNlLlxyXG4gKi9cclxuZXhwb3J0IGRlZmF1bHQgZnVuY3Rpb24gdWlSb3V0ZXMoYXBwKSB7XHJcbiAgLyoqXHJcbiAgICogQWRkcyB0aGUgR0VUICcvJyAtIEEgcm91dGUgZm9yIGEgVUkgd2hlbiBlbmFibGVkIG9uIHRoZSBleHBvcnQgc2VydmVyLlxyXG4gICAqL1xyXG4gIGFwcC5nZXQoZ2V0T3B0aW9ucygpLnVpLnJvdXRlIHx8ICcvJywgKHJlcXVlc3QsIHJlc3BvbnNlLCBuZXh0KSA9PiB7XHJcbiAgICB0cnkge1xyXG4gICAgICBsb2coNCwgJ1t1aV0gUmV0dXJuaW5nIFVJIGZvciB0aGUgZXhwb3J0LicpO1xyXG5cclxuICAgICAgcmVzcG9uc2Uuc2VuZEZpbGUoam9pbihfX2Rpcm5hbWUsICdwdWJsaWMnLCAnaW5kZXguaHRtbCcpLCB7XHJcbiAgICAgICAgYWNjZXB0UmFuZ2VzOiBmYWxzZVxyXG4gICAgICB9KTtcclxuICAgIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICAgIHJldHVybiBuZXh0KGVycm9yKTtcclxuICAgIH1cclxuICB9KTtcclxufVxyXG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxyXG5cclxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXHJcblxyXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNSwgSGlnaHNvZnRcclxuXHJcbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cclxuXHJcbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxyXG5cclxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxyXG5cclxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cclxuXHJcbi8qKlxyXG4gKiBAb3ZlcnZpZXcgRGVmaW5lcyBhbiBFeHByZXNzIHJvdXRlIGZvciB1cGRhdGluZyB0aGUgSGlnaGNoYXJ0cyB2ZXJzaW9uXHJcbiAqIG9uIHRoZSBzZXJ2ZXIsIHdpdGggYXV0aGVudGljYXRpb24gYW5kIHZhbGlkYXRpb24uXHJcbiAqL1xyXG5cclxuaW1wb3J0IHsgZ2V0SGlnaGNoYXJ0c1ZlcnNpb24sIHVwZGF0ZUhpZ2hjaGFydHNWZXJzaW9uIH0gZnJvbSAnLi4vLi4vY2FjaGUuanMnO1xyXG5pbXBvcnQgeyB2YWxpZGF0ZU9wdGlvbiB9IGZyb20gJy4uLy4uL2NvbmZpZy5qcyc7XHJcbmltcG9ydCB7IGxvZyB9IGZyb20gJy4uLy4uL2xvZ2dlci5qcyc7XHJcbmltcG9ydCB7IGVudnMgfSBmcm9tICcuLi8uLi92YWxpZGF0aW9uLmpzJztcclxuXHJcbmltcG9ydCBFeHBvcnRFcnJvciBmcm9tICcuLi8uLi9lcnJvcnMvRXhwb3J0RXJyb3IuanMnO1xyXG5cclxuLyoqXHJcbiAqIEFkZHMgdGhlIGB2ZXJzaW9uX2NoYW5nZWAgcm91dGVzLlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gdmVyc2lvbkNoYW5nZVJvdXRlc1xyXG4gKlxyXG4gKiBAcGFyYW0ge0V4cHJlc3N9IGFwcCAtIFRoZSBFeHByZXNzIGFwcCBpbnN0YW5jZS5cclxuICovXHJcbmV4cG9ydCBkZWZhdWx0IGZ1bmN0aW9uIHZlcnNpb25DaGFuZ2VSb3V0ZXMoYXBwKSB7XHJcbiAgLyoqXHJcbiAgICogQWRkcyB0aGUgUE9TVCAnL3ZlcnNpb25fY2hhbmdlLzpuZXdWZXJzaW9uJyAtIEEgcm91dGUgZm9yIGNoYW5naW5nXHJcbiAgICogdGhlIEhpZ2hjaGFydHMgdmVyc2lvbiBvbiB0aGUgc2VydmVyLlxyXG4gICAqL1xyXG4gIGFwcC5wb3N0KCcvdmVyc2lvbl9jaGFuZ2UvOm5ld1ZlcnNpb24nLCBhc3luYyAocmVxdWVzdCwgcmVzcG9uc2UsIG5leHQpID0+IHtcclxuICAgIHRyeSB7XHJcbiAgICAgIGxvZyg0LCAnW3ZlcnNpb25dIENoYW5naW5nIEhpZ2hjaGFydHMgdmVyc2lvbi4nKTtcclxuXHJcbiAgICAgIC8vIEdldCB0aGUgdG9rZW4gZGlyZWN0bHkgZnJvbSBlbnZzXHJcbiAgICAgIGNvbnN0IGFkbWluVG9rZW4gPSBlbnZzLkhJR0hDSEFSVFNfQURNSU5fVE9LRU47XHJcblxyXG4gICAgICAvLyBDaGVjayB0aGUgZXhpc3RlbmNlIG9mIHRoZSB0b2tlblxyXG4gICAgICBpZiAoIWFkbWluVG9rZW4gfHwgIWFkbWluVG9rZW4ubGVuZ3RoKSB7XHJcbiAgICAgICAgdGhyb3cgbmV3IEV4cG9ydEVycm9yKFxyXG4gICAgICAgICAgJ1t2ZXJzaW9uXSBUaGUgc2VydmVyIGlzIG5vdCBjb25maWd1cmVkIHRvIHBlcmZvcm0gcnVuLXRpbWUgdmVyc2lvbiBjaGFuZ2VzOiBISUdIQ0hBUlRTX0FETUlOX1RPS0VOIGlzIG5vdCBzZXQuJyxcclxuICAgICAgICAgIDQwMVxyXG4gICAgICAgICk7XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIC8vIEdldCB0aGUgdG9rZW4gZnJvbSB0aGUgaGMtYXV0aCBoZWFkZXJcclxuICAgICAgY29uc3QgdG9rZW4gPSByZXF1ZXN0LmdldCgnaGMtYXV0aCcpO1xyXG5cclxuICAgICAgLy8gQ2hlY2sgaWYgdGhlIGhjLWF1dGggaGVhZGVyIGNvbnRhaW4gYSBjb3JyZWN0IHRva2VuXHJcbiAgICAgIGlmICghdG9rZW4gfHwgdG9rZW4gIT09IGFkbWluVG9rZW4pIHtcclxuICAgICAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoXHJcbiAgICAgICAgICAnW3ZlcnNpb25dIEludmFsaWQgb3IgbWlzc2luZyB0b2tlbjogU2V0IHRoZSB0b2tlbiBpbiB0aGUgaGMtYXV0aCBoZWFkZXIuJyxcclxuICAgICAgICAgIDQwMVxyXG4gICAgICAgICk7XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIC8vIENvbXBhcmUgdmVyc2lvbnNcclxuICAgICAgbGV0IG5ld1ZlcnNpb24gPSByZXF1ZXN0LnBhcmFtcy5uZXdWZXJzaW9uO1xyXG5cclxuICAgICAgLy8gVmFsaWRhdGUgdGhlIHZlcnNpb25cclxuICAgICAgdHJ5IHtcclxuICAgICAgICBuZXdWZXJzaW9uID0gdmFsaWRhdGVPcHRpb24oJ3ZlcnNpb24nLCByZXF1ZXN0LnBhcmFtcy5uZXdWZXJzaW9uKTtcclxuICAgICAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoXHJcbiAgICAgICAgICBgW3ZlcnNpb25dIFZlcnNpb24gaXMgaW5jb3JyZWN0OiAke2Vycm9yLm1lc3NhZ2V9YCxcclxuICAgICAgICAgIDQwMFxyXG4gICAgICAgICkuc2V0RXJyb3IoZXJyb3IpO1xyXG4gICAgICB9XHJcblxyXG4gICAgICAvLyBXaGVuIGEgY29ycmVjdCB2YWx1ZSBmb3VuZFxyXG4gICAgICBpZiAobmV3VmVyc2lvbikge1xyXG4gICAgICAgIHRyeSB7XHJcbiAgICAgICAgICAvLyBVcGRhdGUgdmVyc2lvblxyXG4gICAgICAgICAgYXdhaXQgdXBkYXRlSGlnaGNoYXJ0c1ZlcnNpb24obmV3VmVyc2lvbik7XHJcbiAgICAgICAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICAgICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcihcclxuICAgICAgICAgICAgYFt2ZXJzaW9uXSBWZXJzaW9uIGNoYW5nZTogJHtlcnJvci5tZXNzYWdlfWAsXHJcbiAgICAgICAgICAgIDQwMFxyXG4gICAgICAgICAgKS5zZXRFcnJvcihlcnJvcik7XHJcbiAgICAgICAgfVxyXG5cclxuICAgICAgICAvLyBTdWNjZXNzXHJcbiAgICAgICAgcmVzcG9uc2Uuc3RhdHVzKDIwMCkuc2VuZCh7XHJcbiAgICAgICAgICBzdGF0dXNDb2RlOiAyMDAsXHJcbiAgICAgICAgICBoaWdoY2hhcnRzVmVyc2lvbjogZ2V0SGlnaGNoYXJ0c1ZlcnNpb24oKSxcclxuICAgICAgICAgIG1lc3NhZ2U6IGBTdWNjZXNzZnVsbHkgdXBkYXRlZCBIaWdoY2hhcnRzIHRvIHZlcnNpb246ICR7bmV3VmVyc2lvbn0uYFxyXG4gICAgICAgIH0pO1xyXG4gICAgICB9IGVsc2Uge1xyXG4gICAgICAgIC8vIE5vIHZlcnNpb24gc3BlY2lmaWVkXHJcbiAgICAgICAgdGhyb3cgbmV3IEV4cG9ydEVycm9yKCdbdmVyc2lvbl0gTm8gbmV3IHZlcnNpb24gc3VwcGxpZWQuJywgNDAwKTtcclxuICAgICAgfVxyXG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICAgcmV0dXJuIG5leHQoZXJyb3IpO1xyXG4gICAgfVxyXG4gIH0pO1xyXG59XHJcbiIsIi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXHJcblxyXG5IaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXJcclxuXHJcbkNvcHlyaWdodCAoYykgMjAxNi0yMDI1LCBIaWdoc29mdFxyXG5cclxuTGljZW5jZWQgdW5kZXIgdGhlIE1JVCBsaWNlbmNlLlxyXG5cclxuQWRkaXRpb25hbGx5IGEgdmFsaWQgSGlnaGNoYXJ0cyBsaWNlbnNlIGlzIHJlcXVpcmVkIGZvciB1c2UuXHJcblxyXG5TZWUgTElDRU5TRSBmaWxlIGluIHJvb3QgZm9yIGRldGFpbHMuXHJcblxyXG4qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xyXG5cclxuLyoqXHJcbiAqIEBvdmVydmlldyBBIG1vZHVsZSB0aGF0IHNldHMgdXAgYW5kIG1hbmFnZXMgSFRUUCBhbmQgSFRUUFMgc2VydmVyc1xyXG4gKiBmb3IgdGhlIEhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlci4gSXQgaGFuZGxlcyBzZXJ2ZXIgaW5pdGlhbGl6YXRpb24sXHJcbiAqIGNvbmZpZ3VyYXRpb24sIGVycm9yIGhhbmRsaW5nLCBtaWRkbGV3YXJlIHNldHVwLCByb3V0ZSBkZWZpbml0aW9uLCBhbmQgcmF0ZVxyXG4gKiBsaW1pdGluZy4gVGhlIG1vZHVsZSBleHBvcnRzIGZ1bmN0aW9ucyB0byBzdGFydCwgc3RvcCwgYW5kIG1hbmFnZSBzZXJ2ZXJcclxuICogaW5zdGFuY2VzLCBhcyB3ZWxsIGFzIHV0aWxpdHkgZnVuY3Rpb25zIGZvciBkZWZpbmluZyByb3V0ZXMgYW5kIGF0dGFjaGluZ1xyXG4gKiBtaWRkbGV3YXJlcy5cclxuICovXHJcblxyXG5pbXBvcnQgeyByZWFkRmlsZVN5bmMgfSBmcm9tICdmcyc7XHJcbmltcG9ydCB7IGpvaW4gfSBmcm9tICdwYXRoJztcclxuXHJcbmltcG9ydCBjb3JzIGZyb20gJ2NvcnMnO1xyXG5pbXBvcnQgZXhwcmVzcyBmcm9tICdleHByZXNzJztcclxuaW1wb3J0IGh0dHAgZnJvbSAnaHR0cCc7XHJcbmltcG9ydCBodHRwcyBmcm9tICdodHRwcyc7XHJcbmltcG9ydCBtdWx0ZXIgZnJvbSAnbXVsdGVyJztcclxuXHJcbmltcG9ydCB7IHVwZGF0ZU9wdGlvbnMsIHZhbGlkYXRlT3B0aW9ucyB9IGZyb20gJy4uL2NvbmZpZy5qcyc7XHJcbmltcG9ydCB7IGxvZywgbG9nV2l0aFN0YWNrIH0gZnJvbSAnLi4vbG9nZ2VyLmpzJztcclxuaW1wb3J0IHsgX19kaXJuYW1lLCBnZXRBYnNvbHV0ZVBhdGggfSBmcm9tICcuLi91dGlscy5qcyc7XHJcblxyXG5pbXBvcnQgZXJyb3JNaWRkbGV3YXJlIGZyb20gJy4vbWlkZGxld2FyZXMvZXJyb3IuanMnO1xyXG5pbXBvcnQgcmF0ZUxpbWl0aW5nTWlkZGxld2FyZSBmcm9tICcuL21pZGRsZXdhcmVzL3JhdGVMaW1pdGluZy5qcyc7XHJcbmltcG9ydCB2YWxpZGF0aW9uTWlkZGxld2FyZSBmcm9tICcuL21pZGRsZXdhcmVzL3ZhbGlkYXRpb24uanMnO1xyXG5cclxuaW1wb3J0IGV4cG9ydFJvdXRlcyBmcm9tICcuL3JvdXRlcy9leHBvcnQuanMnO1xyXG5pbXBvcnQgaGVhbHRoUm91dGVzIGZyb20gJy4vcm91dGVzL2hlYWx0aC5qcyc7XHJcbmltcG9ydCB1aVJvdXRlcyBmcm9tICcuL3JvdXRlcy91aS5qcyc7XHJcbmltcG9ydCB2ZXJzaW9uQ2hhbmdlUm91dGVzIGZyb20gJy4vcm91dGVzL3ZlcnNpb25DaGFuZ2UuanMnO1xyXG5cclxuaW1wb3J0IEV4cG9ydEVycm9yIGZyb20gJy4uL2Vycm9ycy9FeHBvcnRFcnJvci5qcyc7XHJcblxyXG4vLyBBcnJheSBvZiBhbiBhY3RpdmUgc2VydmVyc1xyXG5jb25zdCBhY3RpdmVTZXJ2ZXJzID0gbmV3IE1hcCgpO1xyXG5cclxuLy8gQ3JlYXRlIGV4cHJlc3MgYXBwXHJcbmNvbnN0IGFwcCA9IGV4cHJlc3MoKTtcclxuXHJcbi8qKlxyXG4gKiBTdGFydHMgYW4gSFRUUCBhbmQvb3IgSFRUUFMgc2VydmVyIGJhc2VkIG9uIHRoZSBwcm92aWRlZCBjb25maWd1cmF0aW9uLlxyXG4gKiBUaGUgYHNlcnZlck9wdGlvbnNgIG9iamVjdCBjb250YWlucyBzZXJ2ZXItcmVsYXRlZCBwcm9wZXJ0aWVzIChyZWZlclxyXG4gKiB0byB0aGUgYHNlcnZlcmAgc2VjdGlvbiBpbiB0aGUgYC4vbGliL3NjaGVtYXMvY29uZmlnLmpzYCBmaWxlIGZvciBkZXRhaWxzKS5cclxuICpcclxuICogQGFzeW5jXHJcbiAqIEBmdW5jdGlvbiBzdGFydFNlcnZlclxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gc2VydmVyT3B0aW9ucyAtIFRoZSBjb25maWd1cmF0aW9uIG9iamVjdCBjb250YWluaW5nIGBzZXJ2ZXJgXHJcbiAqIG9wdGlvbnMuIFRoaXMgb2JqZWN0IG1heSBpbmNsdWRlIGEgcGFydGlhbCBvciBjb21wbGV0ZSBzZXQgb2YgdGhlIGBzZXJ2ZXJgXHJcbiAqIG9wdGlvbnMuIElmIHRoZSBvcHRpb25zIGFyZSBwYXJ0aWFsLCBtaXNzaW5nIHZhbHVlcyB3aWxsIGRlZmF1bHRcclxuICogdG8gdGhlIGN1cnJlbnQgZ2xvYmFsIGNvbmZpZ3VyYXRpb24uXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtQcm9taXNlPHZvaWQ+fSBBIFByb21pc2UgdGhhdCByZXNvbHZlcyB3aGVuIHRoZSBzZXJ2ZXIgaXMgZWl0aGVyXHJcbiAqIG5vdCBlbmFibGVkIG9yIG5vIHZhbGlkIEV4cHJlc3MgYXBwIGlzIGZvdW5kLCBzaWduYWxpbmcgdGhlIGVuZCBvZiB0aGVcclxuICogZnVuY3Rpb24ncyBleGVjdXRpb24uXHJcbiAqXHJcbiAqIEB0aHJvd3Mge0V4cG9ydEVycm9yfSBUaHJvd3MgYW4gYEV4cG9ydEVycm9yYCBpZiB0aGUgc2VydmVyIGNhbm5vdFxyXG4gKiBiZSBjb25maWd1cmVkIGFuZCBzdGFydGVkLlxyXG4gKi9cclxuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIHN0YXJ0U2VydmVyKHNlcnZlck9wdGlvbnMpIHtcclxuICB0cnkge1xyXG4gICAgLy8gVXBkYXRlIHRoZSBpbnN0YW5jZSBvcHRpb25zIG9iamVjdFxyXG4gICAgY29uc3Qgb3B0aW9ucyA9IHVwZGF0ZU9wdGlvbnMoXHJcbiAgICAgIHZhbGlkYXRlT3B0aW9ucyh7XHJcbiAgICAgICAgc2VydmVyOiBzZXJ2ZXJPcHRpb25zXHJcbiAgICAgIH0pXHJcbiAgICApO1xyXG5cclxuICAgIC8vIFVzZSB2YWxpZGF0ZWQgb3B0aW9uc1xyXG4gICAgc2VydmVyT3B0aW9ucyA9IG9wdGlvbnMuc2VydmVyO1xyXG5cclxuICAgIC8vIFN0b3AgaWYgbm90IGVuYWJsZWRcclxuICAgIGlmICghc2VydmVyT3B0aW9ucy5lbmFibGUgfHwgIWFwcCkge1xyXG4gICAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoXHJcbiAgICAgICAgJ1tzZXJ2ZXJdIFNlcnZlciBjYW5ub3QgYmUgc3RhcnRlZCAobm90IGVuYWJsZWQgb3Igbm8gY29ycmVjdCBFeHByZXNzIGFwcCBmb3VuZCkuJyxcclxuICAgICAgICA1MDBcclxuICAgICAgKTtcclxuICAgIH1cclxuXHJcbiAgICAvLyBUb28gYmlnIGxpbWl0cyBsZWFkIHRvIHRpbWVvdXRzIGluIHRoZSBleHBvcnQgcHJvY2VzcyB3aGVuXHJcbiAgICAvLyB0aGUgcmFzdGVyaXphdGlvbiB0aW1lb3V0IGlzIHNldCB0b28gbG93XHJcbiAgICBjb25zdCB1cGxvYWRMaW1pdEJ5dGVzID0gc2VydmVyT3B0aW9ucy51cGxvYWRMaW1pdCAqIDEwMjQgKiAxMDI0O1xyXG5cclxuICAgIC8vIE1lbW9yeSBzdG9yYWdlIGZvciBtdWx0ZXIgcGFja2FnZVxyXG4gICAgY29uc3Qgc3RvcmFnZSA9IG11bHRlci5tZW1vcnlTdG9yYWdlKCk7XHJcblxyXG4gICAgLy8gRW5hYmxlIHBhcnNpbmcgb2YgZm9ybSBkYXRhIChmaWxlcykgd2l0aCBtdWx0ZXIgcGFja2FnZVxyXG4gICAgY29uc3QgdXBsb2FkID0gbXVsdGVyKHtcclxuICAgICAgc3RvcmFnZSxcclxuICAgICAgbGltaXRzOiB7XHJcbiAgICAgICAgZmllbGRTaXplOiB1cGxvYWRMaW1pdEJ5dGVzXHJcbiAgICAgIH1cclxuICAgIH0pO1xyXG5cclxuICAgIC8vIERpc2FibGUgdGhlIFgtUG93ZXJlZC1CeSBoZWFkZXJcclxuICAgIGFwcC5kaXNhYmxlKCd4LXBvd2VyZWQtYnknKTtcclxuXHJcbiAgICAvLyBFbmFibGUgQ09SUyBzdXBwb3J0XHJcbiAgICBhcHAudXNlKFxyXG4gICAgICBjb3JzKHtcclxuICAgICAgICBtZXRob2RzOiBbJ1BPU1QnLCAnR0VUJywgJ09QVElPTlMnXVxyXG4gICAgICB9KVxyXG4gICAgKTtcclxuXHJcbiAgICAvLyBHZXR0aW5nIGEgbG90IG9mIGBSYW5nZU5vdFNhdGlzZmlhYmxlRXJyb3JgIGV4Y2VwdGlvbnMgKGV2ZW4gdGhvdWdoIHRoaXNcclxuICAgIC8vIGlzIGEgZGVwcmVjYXRlZCBvcHRpb25zLCBsZXQncyB0cnkgdG8gc2V0IGl0IHRvIGZhbHNlKVxyXG4gICAgYXBwLnVzZSgocmVxdWVzdCwgcmVzcG9uc2UsIG5leHQpID0+IHtcclxuICAgICAgcmVzcG9uc2Uuc2V0KCdBY2NlcHQtUmFuZ2VzJywgJ25vbmUnKTtcclxuICAgICAgbmV4dCgpO1xyXG4gICAgfSk7XHJcblxyXG4gICAgLy8gRW5hYmxlIGJvZHkgcGFyc2VyIGZvciBKU09OIGRhdGFcclxuICAgIGFwcC51c2UoXHJcbiAgICAgIGV4cHJlc3MuanNvbih7XHJcbiAgICAgICAgbGltaXQ6IHVwbG9hZExpbWl0Qnl0ZXNcclxuICAgICAgfSlcclxuICAgICk7XHJcblxyXG4gICAgLy8gRW5hYmxlIGJvZHkgcGFyc2VyIGZvciBVUkwtZW5jb2RlZCBmb3JtIGRhdGFcclxuICAgIGFwcC51c2UoXHJcbiAgICAgIGV4cHJlc3MudXJsZW5jb2RlZCh7XHJcbiAgICAgICAgZXh0ZW5kZWQ6IHRydWUsXHJcbiAgICAgICAgbGltaXQ6IHVwbG9hZExpbWl0Qnl0ZXNcclxuICAgICAgfSlcclxuICAgICk7XHJcblxyXG4gICAgLy8gVXNlIG9ubHkgbm9uLWZpbGUgbXVsdGlwYXJ0IGZvcm0gZmllbGRzXHJcbiAgICBhcHAudXNlKHVwbG9hZC5ub25lKCkpO1xyXG5cclxuICAgIC8vIFNldCB1cCBzdGF0aWMgZm9sZGVyJ3Mgcm91dGVcclxuICAgIGFwcC51c2UoZXhwcmVzcy5zdGF0aWMoam9pbihfX2Rpcm5hbWUsICdwdWJsaWMnKSkpO1xyXG5cclxuICAgIC8vIExpc3RlbiBIVFRQIHNlcnZlclxyXG4gICAgaWYgKCFzZXJ2ZXJPcHRpb25zLnNzbC5mb3JjZSkge1xyXG4gICAgICAvLyBNYWluIHNlcnZlciBpbnN0YW5jZSAoSFRUUClcclxuICAgICAgY29uc3QgaHR0cFNlcnZlciA9IGh0dHAuY3JlYXRlU2VydmVyKGFwcCk7XHJcblxyXG4gICAgICAvLyBBdHRhY2ggZXJyb3IgaGFuZGxlcnMgYW5kIGxpc3RlbiB0byB0aGUgc2VydmVyXHJcbiAgICAgIF9hdHRhY2hTZXJ2ZXJFcnJvckhhbmRsZXJzKGh0dHBTZXJ2ZXIpO1xyXG5cclxuICAgICAgLy8gTGlzdGVuXHJcbiAgICAgIGh0dHBTZXJ2ZXIubGlzdGVuKHNlcnZlck9wdGlvbnMucG9ydCwgc2VydmVyT3B0aW9ucy5ob3N0LCAoKSA9PiB7XHJcbiAgICAgICAgLy8gU2F2ZSB0aGUgcmVmZXJlbmNlIHRvIEhUVFAgc2VydmVyXHJcbiAgICAgICAgYWN0aXZlU2VydmVycy5zZXQoc2VydmVyT3B0aW9ucy5wb3J0LCBodHRwU2VydmVyKTtcclxuXHJcbiAgICAgICAgbG9nKFxyXG4gICAgICAgICAgMyxcclxuICAgICAgICAgIGBbc2VydmVyXSBTdGFydGVkIEhUVFAgc2VydmVyIG9uICR7c2VydmVyT3B0aW9ucy5ob3N0fToke3NlcnZlck9wdGlvbnMucG9ydH0uYFxyXG4gICAgICAgICk7XHJcbiAgICAgIH0pO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIExpc3RlbiBIVFRQUyBzZXJ2ZXJcclxuICAgIGlmIChzZXJ2ZXJPcHRpb25zLnNzbC5lbmFibGUpIHtcclxuICAgICAgLy8gU2V0IHVwIGFuIFNTTCBzZXJ2ZXIgYWxzb1xyXG4gICAgICBsZXQga2V5LCBjZXJ0O1xyXG5cclxuICAgICAgdHJ5IHtcclxuICAgICAgICAvLyBHZXQgdGhlIFNTTCBrZXlcclxuICAgICAgICBrZXkgPSByZWFkRmlsZVN5bmMoXHJcbiAgICAgICAgICBqb2luKGdldEFic29sdXRlUGF0aChzZXJ2ZXJPcHRpb25zLnNzbC5jZXJ0UGF0aCksICdzZXJ2ZXIua2V5JyksXHJcbiAgICAgICAgICAndXRmOCdcclxuICAgICAgICApO1xyXG5cclxuICAgICAgICAvLyBHZXQgdGhlIFNTTCBjZXJ0aWZpY2F0ZVxyXG4gICAgICAgIGNlcnQgPSByZWFkRmlsZVN5bmMoXHJcbiAgICAgICAgICBqb2luKGdldEFic29sdXRlUGF0aChzZXJ2ZXJPcHRpb25zLnNzbC5jZXJ0UGF0aCksICdzZXJ2ZXIuY3J0JyksXHJcbiAgICAgICAgICAndXRmOCdcclxuICAgICAgICApO1xyXG4gICAgICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgICAgIGxvZyhcclxuICAgICAgICAgIDIsXHJcbiAgICAgICAgICBgW3NlcnZlcl0gVW5hYmxlIHRvIGxvYWQga2V5L2NlcnRpZmljYXRlIGZyb20gdGhlICcke3NlcnZlck9wdGlvbnMuc3NsLmNlcnRQYXRofScgcGF0aC4gQ291bGQgbm90IHJ1biBzZWN1cmVkIGxheWVyIHNlcnZlci5gXHJcbiAgICAgICAgKTtcclxuICAgICAgfVxyXG5cclxuICAgICAgaWYgKGtleSAmJiBjZXJ0KSB7XHJcbiAgICAgICAgLy8gTWFpbiBzZXJ2ZXIgaW5zdGFuY2UgKEhUVFBTKVxyXG4gICAgICAgIGNvbnN0IGh0dHBzU2VydmVyID0gaHR0cHMuY3JlYXRlU2VydmVyKHsga2V5LCBjZXJ0IH0sIGFwcCk7XHJcblxyXG4gICAgICAgIC8vIEF0dGFjaCBlcnJvciBoYW5kbGVycyBhbmQgbGlzdGVuIHRvIHRoZSBzZXJ2ZXJcclxuICAgICAgICBfYXR0YWNoU2VydmVyRXJyb3JIYW5kbGVycyhodHRwc1NlcnZlcik7XHJcblxyXG4gICAgICAgIC8vIExpc3RlblxyXG4gICAgICAgIGh0dHBzU2VydmVyLmxpc3RlbihzZXJ2ZXJPcHRpb25zLnNzbC5wb3J0LCBzZXJ2ZXJPcHRpb25zLmhvc3QsICgpID0+IHtcclxuICAgICAgICAgIC8vIFNhdmUgdGhlIHJlZmVyZW5jZSB0byBIVFRQUyBzZXJ2ZXJcclxuICAgICAgICAgIGFjdGl2ZVNlcnZlcnMuc2V0KHNlcnZlck9wdGlvbnMuc3NsLnBvcnQsIGh0dHBzU2VydmVyKTtcclxuXHJcbiAgICAgICAgICBsb2coXHJcbiAgICAgICAgICAgIDMsXHJcbiAgICAgICAgICAgIGBbc2VydmVyXSBTdGFydGVkIEhUVFBTIHNlcnZlciBvbiAke3NlcnZlck9wdGlvbnMuaG9zdH06JHtzZXJ2ZXJPcHRpb25zLnNzbC5wb3J0fS5gXHJcbiAgICAgICAgICApO1xyXG4gICAgICAgIH0pO1xyXG4gICAgICB9XHJcbiAgICB9XHJcblxyXG4gICAgLy8gU2V0IHVwIHRoZSByYXRlIGxpbWl0ZXJcclxuICAgIHJhdGVMaW1pdGluZ01pZGRsZXdhcmUoYXBwLCBzZXJ2ZXJPcHRpb25zLnJhdGVMaW1pdGluZyk7XHJcblxyXG4gICAgLy8gU2V0IHVwIHRoZSB2YWxpZGF0aW9uIGhhbmRsZXJcclxuICAgIHZhbGlkYXRpb25NaWRkbGV3YXJlKGFwcCk7XHJcblxyXG4gICAgLy8gU2V0IHVwIHJvdXRlc1xyXG4gICAgZXhwb3J0Um91dGVzKGFwcCk7XHJcbiAgICBoZWFsdGhSb3V0ZXMoYXBwKTtcclxuICAgIHVpUm91dGVzKGFwcCk7XHJcbiAgICB2ZXJzaW9uQ2hhbmdlUm91dGVzKGFwcCk7XHJcblxyXG4gICAgLy8gU2V0IHVwIHRoZSBjZW50cmFsaXplZCBlcnJvciBoYW5kbGVyXHJcbiAgICBlcnJvck1pZGRsZXdhcmUoYXBwKTtcclxuICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgdGhyb3cgbmV3IEV4cG9ydEVycm9yKFxyXG4gICAgICAnW3NlcnZlcl0gQ291bGQgbm90IGNvbmZpZ3VyZSBhbmQgc3RhcnQgdGhlIHNlcnZlci4nLFxyXG4gICAgICA1MDBcclxuICAgICkuc2V0RXJyb3IoZXJyb3IpO1xyXG4gIH1cclxufVxyXG5cclxuLyoqXHJcbiAqIENsb3NlcyBhbGwgc2VydmVycyBhc3NvY2lhdGVkIHdpdGggRXhwcmVzcyBhcHAgaW5zdGFuY2UuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBjbG9zZVNlcnZlcnNcclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiBjbG9zZVNlcnZlcnMoKSB7XHJcbiAgLy8gQ2hlY2sgaWYgdGhlcmUgYXJlIHNlcnZlcnMgd29ya2luZ1xyXG4gIGlmIChhY3RpdmVTZXJ2ZXJzLnNpemUgPiAwKSB7XHJcbiAgICBsb2coNCwgYFtzZXJ2ZXJdIENsb3NpbmcgYWxsIHNlcnZlcnMuYCk7XHJcblxyXG4gICAgLy8gQ2xvc2UgZWFjaCBvbmUgb2Ygc2VydmVyc1xyXG4gICAgZm9yIChjb25zdCBbcG9ydCwgc2VydmVyXSBvZiBhY3RpdmVTZXJ2ZXJzKSB7XHJcbiAgICAgIHNlcnZlci5jbG9zZSgoKSA9PiB7XHJcbiAgICAgICAgYWN0aXZlU2VydmVycy5kZWxldGUocG9ydCk7XHJcbiAgICAgICAgbG9nKDQsIGBbc2VydmVyXSBDbG9zZWQgc2VydmVyIG9uIHBvcnQ6ICR7cG9ydH0uYCk7XHJcbiAgICAgIH0pO1xyXG4gICAgfVxyXG4gIH1cclxufVxyXG5cclxuLyoqXHJcbiAqIEdldCBhbGwgc2VydmVycyBhc3NvY2lhdGVkIHdpdGggRXhwcmVzcyBhcHAgaW5zdGFuY2UuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBnZXRTZXJ2ZXJzXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtBcnJheS48T2JqZWN0Pn0gU2VydmVycyBhc3NvY2lhdGVkIHdpdGggRXhwcmVzcyBhcHAgaW5zdGFuY2UuXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gZ2V0U2VydmVycygpIHtcclxuICByZXR1cm4gYWN0aXZlU2VydmVycztcclxufVxyXG5cclxuLyoqXHJcbiAqIEdldCB0aGUgRXhwcmVzcyBpbnN0YW5jZS5cclxuICpcclxuICogQGZ1bmN0aW9uIGdldEV4cHJlc3NcclxuICpcclxuICogQHJldHVybnMge0V4cHJlc3N9IFRoZSBFeHByZXNzIGluc3RhbmNlLlxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIGdldEV4cHJlc3MoKSB7XHJcbiAgcmV0dXJuIGV4cHJlc3M7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBHZXQgdGhlIEV4cHJlc3MgYXBwIGluc3RhbmNlLlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gZ2V0QXBwXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtFeHByZXNzfSBUaGUgRXhwcmVzcyBhcHAgaW5zdGFuY2UuXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gZ2V0QXBwKCkge1xyXG4gIHJldHVybiBhcHA7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBFbmFibGUgcmF0ZSBsaW1pdGluZyBmb3IgdGhlIHNlcnZlci5cclxuICpcclxuICogQGZ1bmN0aW9uIGVuYWJsZVJhdGVMaW1pdGluZ1xyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gcmF0ZUxpbWl0aW5nT3B0aW9ucyAtIFRoZSBjb25maWd1cmF0aW9uIG9iamVjdCBjb250YWluaW5nXHJcbiAqIGByYXRlTGltaXRpbmdgIG9wdGlvbnMuIFRoaXMgb2JqZWN0IG1heSBpbmNsdWRlIGEgcGFydGlhbCBvciBjb21wbGV0ZSBzZXRcclxuICogb2YgdGhlIGByYXRlTGltaXRpbmdgIG9wdGlvbnMuIElmIHRoZSBvcHRpb25zIGFyZSBwYXJ0aWFsLCBtaXNzaW5nIHZhbHVlc1xyXG4gKiB3aWxsIGRlZmF1bHQgdG8gdGhlIGN1cnJlbnQgZ2xvYmFsIGNvbmZpZ3VyYXRpb24uXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gZW5hYmxlUmF0ZUxpbWl0aW5nKHJhdGVMaW1pdGluZ09wdGlvbnMpIHtcclxuICAvLyBVcGRhdGUgdGhlIGluc3RhbmNlIG9wdGlvbnMgb2JqZWN0XHJcbiAgY29uc3Qgb3B0aW9ucyA9IHVwZGF0ZU9wdGlvbnMoXHJcbiAgICB2YWxpZGF0ZU9wdGlvbnMoe1xyXG4gICAgICBzZXJ2ZXI6IHtcclxuICAgICAgICByYXRlTGltaXRpbmc6IHJhdGVMaW1pdGluZ09wdGlvbnNcclxuICAgICAgfVxyXG4gICAgfSlcclxuICApO1xyXG5cclxuICAvLyBTZXQgdGhlIHJhdGUgbGltaXRpbmcgb3B0aW9uc1xyXG4gIHJhdGVMaW1pdGluZ01pZGRsZXdhcmUoYXBwLCBvcHRpb25zLnNlcnZlci5yYXRlTGltaXRpbmdPcHRpb25zKTtcclxufVxyXG5cclxuLyoqXHJcbiAqIEFwcGx5IG1pZGRsZXdhcmUocykgdG8gYSBzcGVjaWZpYyBwYXRoLlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gdXNlXHJcbiAqXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSBwYXRoIC0gVGhlIHBhdGggdG8gd2hpY2ggdGhlIG1pZGRsZXdhcmUocykgc2hvdWxkIGJlIGFwcGxpZWQuXHJcbiAqIEBwYXJhbSB7Li4uRnVuY3Rpb259IG1pZGRsZXdhcmVzIC0gVGhlIG1pZGRsZXdhcmUgZnVuY3Rpb24ocykgdG8gYmUgYXBwbGllZC5cclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiB1c2UocGF0aCwgLi4ubWlkZGxld2FyZXMpIHtcclxuICBhcHAudXNlKHBhdGgsIC4uLm1pZGRsZXdhcmVzKTtcclxufVxyXG5cclxuLyoqXHJcbiAqIFNldCB1cCBhIHJvdXRlIHdpdGggR0VUIG1ldGhvZCBhbmQgYXBwbHkgbWlkZGxld2FyZShzKS5cclxuICpcclxuICogQGZ1bmN0aW9uIGdldFxyXG4gKlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gcGF0aCAtIFRoZSBwYXRoIHRvIHdoaWNoIHRoZSBtaWRkbGV3YXJlKHMpIHNob3VsZCBiZSBhcHBsaWVkLlxyXG4gKiBAcGFyYW0gey4uLkZ1bmN0aW9ufSBtaWRkbGV3YXJlcyAtIFRoZSBtaWRkbGV3YXJlIGZ1bmN0aW9uKHMpIHRvIGJlIGFwcGxpZWQuXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gZ2V0KHBhdGgsIC4uLm1pZGRsZXdhcmVzKSB7XHJcbiAgYXBwLmdldChwYXRoLCAuLi5taWRkbGV3YXJlcyk7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBTZXQgdXAgYSByb3V0ZSB3aXRoIFBPU1QgbWV0aG9kIGFuZCBhcHBseSBtaWRkbGV3YXJlKHMpLlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gcG9zdFxyXG4gKlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gcGF0aCAtIFRoZSBwYXRoIHRvIHdoaWNoIHRoZSBtaWRkbGV3YXJlKHMpIHNob3VsZCBiZSBhcHBsaWVkLlxyXG4gKiBAcGFyYW0gey4uLkZ1bmN0aW9ufSBtaWRkbGV3YXJlcyAtIFRoZSBtaWRkbGV3YXJlIGZ1bmN0aW9uKHMpIHRvIGJlIGFwcGxpZWQuXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gcG9zdChwYXRoLCAuLi5taWRkbGV3YXJlcykge1xyXG4gIGFwcC5wb3N0KHBhdGgsIC4uLm1pZGRsZXdhcmVzKTtcclxufVxyXG5cclxuLyoqXHJcbiAqIEF0dGFjaCBlcnJvciBoYW5kbGVycyB0byB0aGUgc2VydmVyLlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gX2F0dGFjaFNlcnZlckVycm9ySGFuZGxlcnNcclxuICpcclxuICogQHBhcmFtIHsoaHR0cC5TZXJ2ZXJ8aHR0cHMuU2VydmVyKX0gc2VydmVyIC0gVGhlIEhUVFAvSFRUUFMgc2VydmVyIGluc3RhbmNlLlxyXG4gKi9cclxuZnVuY3Rpb24gX2F0dGFjaFNlcnZlckVycm9ySGFuZGxlcnMoc2VydmVyKSB7XHJcbiAgc2VydmVyLm9uKCdjbGllbnRFcnJvcicsIChlcnJvciwgc29ja2V0KSA9PiB7XHJcbiAgICBsb2dXaXRoU3RhY2soXHJcbiAgICAgIDEsXHJcbiAgICAgIGVycm9yLFxyXG4gICAgICBgW3NlcnZlcl0gQ2xpZW50IGVycm9yOiAke2Vycm9yLm1lc3NhZ2V9LCBkZXN0cm95aW5nIHNvY2tldC5gXHJcbiAgICApO1xyXG4gICAgc29ja2V0LmRlc3Ryb3koKTtcclxuICB9KTtcclxuXHJcbiAgc2VydmVyLm9uKCdlcnJvcicsIChlcnJvcikgPT4ge1xyXG4gICAgbG9nV2l0aFN0YWNrKDEsIGVycm9yLCBgW3NlcnZlcl0gU2VydmVyIGVycm9yOiAke2Vycm9yLm1lc3NhZ2V9YCk7XHJcbiAgfSk7XHJcblxyXG4gIHNlcnZlci5vbignY29ubmVjdGlvbicsIChzb2NrZXQpID0+IHtcclxuICAgIHNvY2tldC5vbignZXJyb3InLCAoZXJyb3IpID0+IHtcclxuICAgICAgbG9nV2l0aFN0YWNrKDEsIGVycm9yLCBgW3NlcnZlcl0gU29ja2V0IGVycm9yOiAke2Vycm9yLm1lc3NhZ2V9YCk7XHJcbiAgICB9KTtcclxuICB9KTtcclxufVxyXG5cclxuZXhwb3J0IGRlZmF1bHQge1xyXG4gIHN0YXJ0U2VydmVyLFxyXG4gIGNsb3NlU2VydmVycyxcclxuICBnZXRTZXJ2ZXJzLFxyXG4gIGdldEV4cHJlc3MsXHJcbiAgZ2V0QXBwLFxyXG4gIGVuYWJsZVJhdGVMaW1pdGluZyxcclxuICB1c2UsXHJcbiAgZ2V0LFxyXG4gIHBvc3RcclxufTtcclxuIiwiLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcclxuXHJcbkhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlclxyXG5cclxuQ29weXJpZ2h0IChjKSAyMDE2LTIwMjUsIEhpZ2hzb2Z0XHJcblxyXG5MaWNlbmNlZCB1bmRlciB0aGUgTUlUIGxpY2VuY2UuXHJcblxyXG5BZGRpdGlvbmFsbHkgYSB2YWxpZCBIaWdoY2hhcnRzIGxpY2Vuc2UgaXMgcmVxdWlyZWQgZm9yIHVzZS5cclxuXHJcblNlZSBMSUNFTlNFIGZpbGUgaW4gcm9vdCBmb3IgZGV0YWlscy5cclxuXHJcbioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXHJcblxyXG4vKipcclxuICogQG92ZXJ2aWV3IEhhbmRsZXMgZ3JhY2VmdWwgc2h1dGRvd24gb2YgdGhlIEhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlciwgZW5zdXJpbmdcclxuICogcHJvcGVyIGNsZWFudXAgb2YgcmVzb3VyY2VzIHN1Y2ggYXMgYnJvd3NlciwgcGFnZXMsIHNlcnZlcnMsIGFuZCB0aW1lcnMuXHJcbiAqL1xyXG5cclxuaW1wb3J0IHsga2lsbFBvb2wgfSBmcm9tICcuL3Bvb2wuanMnO1xyXG5pbXBvcnQgeyBjbGVhckFsbFRpbWVycyB9IGZyb20gJy4vdGltZXIuanMnO1xyXG5cclxuaW1wb3J0IHsgY2xvc2VTZXJ2ZXJzIH0gZnJvbSAnLi9zZXJ2ZXIvc2VydmVyLmpzJztcclxuXHJcbi8qKlxyXG4gKiBQZXJmb3JtcyBjbGVhbnVwIG9wZXJhdGlvbnMgdG8gZW5zdXJlIGEgZ3JhY2VmdWwgc2h1dGRvd24gb2YgdGhlIHByb2Nlc3MuXHJcbiAqIFRoaXMgaW5jbHVkZXMgY2xlYXJpbmcgYWxsIHJlZ2lzdGVyZWQgdGltZW91dHMvaW50ZXJ2YWxzLCBjbG9zaW5nIGFjdGl2ZVxyXG4gKiBzZXJ2ZXJzLCB0ZXJtaW5hdGluZyByZXNvdXJjZXMgKHBhZ2VzKSBvZiB0aGUgcG9vbCwgcG9vbCBpdHNlbGYsIGFuZCBjbG9zaW5nXHJcbiAqIHRoZSBicm93c2VyLlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gc2h1dGRvd25DbGVhblVwXHJcbiAqXHJcbiAqIEBwYXJhbSB7bnVtYmVyfSBbZXhpdENvZGU9MF0gLSBUaGUgZXhpdCBjb2RlIHRvIHVzZSB3aXRoIGBwcm9jZXNzLmV4aXQoKWAuXHJcbiAqIFRoZSBkZWZhdWx0IHZhbHVlIGlzIGAwYC5cclxuICovXHJcbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBzaHV0ZG93bkNsZWFuVXAoZXhpdENvZGUgPSAwKSB7XHJcbiAgLy8gQXdhaXQgZnJlZWluZyBhbGwgcmVzb3VyY2VzXHJcbiAgYXdhaXQgUHJvbWlzZS5hbGxTZXR0bGVkKFtcclxuICAgIC8vIENsZWFyIGFsbCBvbmdvaW5nIGludGVydmFsc1xyXG4gICAgY2xlYXJBbGxUaW1lcnMoKSxcclxuXHJcbiAgICAvLyBHZXQgYXZhaWxhYmxlIHNlcnZlciBpbnN0YW5jZXMgKEhUVFAvSFRUUFMpIGFuZCBjbG9zZSB0aGVtXHJcbiAgICBjbG9zZVNlcnZlcnMoKSxcclxuXHJcbiAgICAvLyBDbG9zZSBhbiBhY3RpdmUgcG9vbCBhbG9uZyB3aXRoIGl0cyB3b3JrZXJzIGFuZCB0aGUgYnJvd3NlciBpbnN0YW5jZVxyXG4gICAga2lsbFBvb2woKVxyXG4gIF0pO1xyXG5cclxuICAvLyBFeGl0IHByb2Nlc3Mgd2l0aCBhIGNvcnJlY3QgY29kZVxyXG4gIHByb2Nlc3MuZXhpdChleGl0Q29kZSk7XHJcbn1cclxuXHJcbmV4cG9ydCBkZWZhdWx0IHtcclxuICBzaHV0ZG93bkNsZWFuVXBcclxufTtcclxuIiwiLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcclxuXHJcbkhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlclxyXG5cclxuQ29weXJpZ2h0IChjKSAyMDE2LTIwMjUsIEhpZ2hzb2Z0XHJcblxyXG5MaWNlbmNlZCB1bmRlciB0aGUgTUlUIGxpY2VuY2UuXHJcblxyXG5BZGRpdGlvbmFsbHkgYSB2YWxpZCBIaWdoY2hhcnRzIGxpY2Vuc2UgaXMgcmVxdWlyZWQgZm9yIHVzZS5cclxuXHJcblNlZSBMSUNFTlNFIGZpbGUgaW4gcm9vdCBmb3IgZGV0YWlscy5cclxuXHJcbioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXHJcblxyXG4vKipcclxuICogQG92ZXJ2aWV3IENvcmUgbW9kdWxlIGZvciBpbml0aWFsaXppbmcgYW5kIG1hbmFnaW5nIHRoZSBIaWdoY2hhcnRzIEV4cG9ydFxyXG4gKiBTZXJ2ZXIuIFByb3ZpZGVzIGZ1bmN0aW9uYWxpdGllcyBmb3IgY29uZmlndXJpbmcgZXhwb3J0cywgc2V0dGluZyB1cCBzZXJ2ZXJcclxuICogb3BlcmF0aW9ucywgbG9nZ2luZywgc2NyaXB0cyBjYWNoaW5nLCByZXNvdXJjZSBwb29saW5nLCBhbmQgZ3JhY2VmdWwgcHJvY2Vzc1xyXG4gKiBjbGVhbnVwLlxyXG4gKi9cclxuXHJcbmltcG9ydCAnY29sb3JzJztcclxuXHJcbmltcG9ydCB7IGNoZWNrQW5kVXBkYXRlQ2FjaGUgfSBmcm9tICcuL2NhY2hlLmpzJztcclxuaW1wb3J0IHtcclxuICBzaW5nbGVFeHBvcnQsXHJcbiAgYmF0Y2hFeHBvcnQsXHJcbiAgc3RhcnRFeHBvcnQsXHJcbiAgc2V0QWxsb3dDb2RlRXhlY3V0aW9uXHJcbn0gZnJvbSAnLi9jaGFydC5qcyc7XHJcbmltcG9ydCB7XHJcbiAgZ2V0T3B0aW9ucyxcclxuICB1cGRhdGVPcHRpb25zLFxyXG4gIG1hcFRvTmV3T3B0aW9ucyxcclxuICB2YWxpZGF0ZU9wdGlvbixcclxuICB2YWxpZGF0ZU9wdGlvbnNcclxufSBmcm9tICcuL2NvbmZpZy5qcyc7XHJcbmltcG9ydCB7XHJcbiAgbG9nLFxyXG4gIGxvZ1dpdGhTdGFjayxcclxuICBsb2dab2RJc3N1ZXMsXHJcbiAgaW5pdExvZ2dpbmcsXHJcbiAgZW5hYmxlQ29uc29sZUxvZ2dpbmcsXHJcbiAgZW5hYmxlRmlsZUxvZ2dpbmcsXHJcbiAgc2V0TG9nTGV2ZWxcclxufSBmcm9tICcuL2xvZ2dlci5qcyc7XHJcbmltcG9ydCB7IGluaXRQb29sLCBraWxsUG9vbCB9IGZyb20gJy4vcG9vbC5qcyc7XHJcbmltcG9ydCB7IHNodXRkb3duQ2xlYW5VcCB9IGZyb20gJy4vcmVzb3VyY2VSZWxlYXNlLmpzJztcclxuXHJcbmltcG9ydCBzZXJ2ZXIgZnJvbSAnLi9zZXJ2ZXIvc2VydmVyLmpzJztcclxuXHJcbi8qKlxyXG4gKiBJbml0aWFsaXplcyB0aGUgZXhwb3J0IHByb2Nlc3MuIFRhc2tzIHN1Y2ggYXMgY29uZmlndXJpbmcgbG9nZ2luZywgY2hlY2tpbmdcclxuICogdGhlIGNhY2hlIGFuZCBzb3VyY2VzLCBhbmQgaW5pdGlhbGl6aW5nIHRoZSByZXNvdXJjZSBwb29sIG9jY3VyIGR1cmluZyB0aGlzXHJcbiAqIHN0YWdlLlxyXG4gKlxyXG4gKiBUaGlzIGZ1bmN0aW9uIG11c3QgYmUgY2FsbGVkIGJlZm9yZSBhdHRlbXB0aW5nIHRvIGV4cG9ydCBjaGFydHMgb3Igc2V0XHJcbiAqIHVwIGEgc2VydmVyLlxyXG4gKlxyXG4gKiBAYXN5bmNcclxuICogQGZ1bmN0aW9uIGluaXRFeHBvcnRcclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IGluaXRPcHRpb25zIC0gVGhlIGBpbml0T3B0aW9uc2Agb2JqZWN0LCB3aGljaCBtYXlcclxuICogYmUgYSBwYXJ0aWFsIG9yIGNvbXBsZXRlIHNldCBvZiBvcHRpb25zLiBJZiB0aGUgb3B0aW9ucyBhcmUgcGFydGlhbCwgbWlzc2luZ1xyXG4gKiB2YWx1ZXMgd2lsbCBkZWZhdWx0IHRvIHRoZSBjdXJyZW50IGdsb2JhbCBjb25maWd1cmF0aW9uLlxyXG4gKi9cclxuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIGluaXRFeHBvcnQoaW5pdE9wdGlvbnMpIHtcclxuICAvLyBJbml0LCB2YWxpZGF0ZSBhbmQgdXBkYXRlIHRoZSBvcHRpb25zIG9iamVjdFxyXG4gIGNvbnN0IG9wdGlvbnMgPSB1cGRhdGVPcHRpb25zKHZhbGlkYXRlT3B0aW9ucyhpbml0T3B0aW9ucykpO1xyXG5cclxuICAvLyBTZXQgdGhlIGBhbGxvd0NvZGVFeGVjdXRpb25gIHBlciBleHBvcnQgbW9kdWxlIHNjb3BlXHJcbiAgc2V0QWxsb3dDb2RlRXhlY3V0aW9uKG9wdGlvbnMuY3VzdG9tTG9naWMuYWxsb3dDb2RlRXhlY3V0aW9uKTtcclxuXHJcbiAgLy8gSW5pdCB0aGUgbG9nZ2luZ1xyXG4gIGluaXRMb2dnaW5nKG9wdGlvbnMubG9nZ2luZyk7XHJcblxyXG4gIC8vIEF0dGFjaCBwcm9jZXNzJyBleGl0IGxpc3RlbmVyc1xyXG4gIGlmIChvcHRpb25zLm90aGVyLmxpc3RlblRvUHJvY2Vzc0V4aXRzKSB7XHJcbiAgICBfYXR0YWNoUHJvY2Vzc0V4aXRMaXN0ZW5lcnMoKTtcclxuICB9XHJcblxyXG4gIC8vIENoZWNrIGlmIGNhY2hlIG5lZWRzIHRvIGJlIHVwZGF0ZWRcclxuICBhd2FpdCBjaGVja0FuZFVwZGF0ZUNhY2hlKG9wdGlvbnMuaGlnaGNoYXJ0cywgb3B0aW9ucy5zZXJ2ZXIucHJveHkpO1xyXG5cclxuICAvLyBJbml0IHRoZSBwb29sXHJcbiAgYXdhaXQgaW5pdFBvb2wob3B0aW9ucy5wb29sLCBvcHRpb25zLnB1cHBldGVlci5hcmdzKTtcclxufVxyXG5cclxuLyoqXHJcbiAqIEF0dGFjaGVzIGV4aXQgbGlzdGVuZXJzIHRvIHRoZSBwcm9jZXNzLCBlbnN1cmluZyBwcm9wZXIgY2xlYW51cCBvZiByZXNvdXJjZXNcclxuICogYW5kIHRlcm1pbmF0aW9uIG9uIGV4aXQgc2lnbmFscy4gSGFuZGxlcyAnZXhpdCcsICdTSUdJTlQnLCAnU0lHVEVSTSdcclxuICogYW5kICd1bmNhdWdodEV4Y2VwdGlvbicgZXZlbnRzLlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gX2F0dGFjaFByb2Nlc3NFeGl0TGlzdGVuZXJzXHJcbiAqL1xyXG5mdW5jdGlvbiBfYXR0YWNoUHJvY2Vzc0V4aXRMaXN0ZW5lcnMoKSB7XHJcbiAgbG9nKDMsICdbcHJvY2Vzc10gQXR0YWNoaW5nIGV4aXQgbGlzdGVuZXJzIHRvIHRoZSBwcm9jZXNzLicpO1xyXG5cclxuICAvLyBIYW5kbGVyIGZvciB0aGUgJ2V4aXQnXHJcbiAgcHJvY2Vzcy5vbignZXhpdCcsIChjb2RlKSA9PiB7XHJcbiAgICBsb2coNCwgYFtwcm9jZXNzXSBQcm9jZXNzIGV4aXRlZCB3aXRoIGNvZGUgJHtjb2RlfS5gKTtcclxuICB9KTtcclxuXHJcbiAgLy8gSGFuZGxlciBmb3IgdGhlICdTSUdJTlQnXHJcbiAgcHJvY2Vzcy5vbignU0lHSU5UJywgYXN5bmMgKG5hbWUsIGNvZGUpID0+IHtcclxuICAgIGxvZyg0LCBgW3Byb2Nlc3NdIFRoZSAke25hbWV9IGV2ZW50IHdpdGggY29kZTogJHtjb2RlfS5gKTtcclxuICAgIGF3YWl0IHNodXRkb3duQ2xlYW5VcCgpO1xyXG4gIH0pO1xyXG5cclxuICAvLyBIYW5kbGVyIGZvciB0aGUgJ1NJR1RFUk0nXHJcbiAgcHJvY2Vzcy5vbignU0lHVEVSTScsIGFzeW5jIChuYW1lLCBjb2RlKSA9PiB7XHJcbiAgICBsb2coNCwgYFtwcm9jZXNzXSBUaGUgJHtuYW1lfSBldmVudCB3aXRoIGNvZGU6ICR7Y29kZX0uYCk7XHJcbiAgICBhd2FpdCBzaHV0ZG93bkNsZWFuVXAoKTtcclxuICB9KTtcclxuXHJcbiAgLy8gSGFuZGxlciBmb3IgdGhlICdTSUdIVVAnXHJcbiAgcHJvY2Vzcy5vbignU0lHSFVQJywgYXN5bmMgKG5hbWUsIGNvZGUpID0+IHtcclxuICAgIGxvZyg0LCBgW3Byb2Nlc3NdIFRoZSAke25hbWV9IGV2ZW50IHdpdGggY29kZTogJHtjb2RlfS5gKTtcclxuICAgIGF3YWl0IHNodXRkb3duQ2xlYW5VcCgpO1xyXG4gIH0pO1xyXG5cclxuICAvLyBIYW5kbGVyIGZvciB0aGUgJ3VuY2F1Z2h0RXhjZXB0aW9uJ1xyXG4gIHByb2Nlc3Mub24oJ3VuY2F1Z2h0RXhjZXB0aW9uJywgYXN5bmMgKGVycm9yLCBuYW1lKSA9PiB7XHJcbiAgICBsb2dXaXRoU3RhY2soMSwgZXJyb3IsIGBbcHJvY2Vzc10gVGhlICR7bmFtZX0gZXJyb3IuYCk7XHJcbiAgICBhd2FpdCBzaHV0ZG93bkNsZWFuVXAoMSk7XHJcbiAgfSk7XHJcbn1cclxuXHJcbmV4cG9ydCBkZWZhdWx0IHtcclxuICAvLyBTZXJ2ZXJcclxuICAuLi5zZXJ2ZXIsXHJcblxyXG4gIC8vIE9wdGlvbnNcclxuICBnZXRPcHRpb25zLFxyXG4gIHVwZGF0ZU9wdGlvbnMsXHJcbiAgbWFwVG9OZXdPcHRpb25zLFxyXG5cclxuICAvLyBWYWxpZGF0aW9uXHJcbiAgdmFsaWRhdGVPcHRpb24sXHJcbiAgdmFsaWRhdGVPcHRpb25zLFxyXG5cclxuICAvLyBFeHBvcnRpbmdcclxuICBpbml0RXhwb3J0LFxyXG4gIHNpbmdsZUV4cG9ydCxcclxuICBiYXRjaEV4cG9ydCxcclxuICBzdGFydEV4cG9ydCxcclxuXHJcbiAgLy8gUmVsZWFzZVxyXG4gIGtpbGxQb29sLFxyXG4gIHNodXRkb3duQ2xlYW5VcCxcclxuXHJcbiAgLy8gTG9nc1xyXG4gIGxvZyxcclxuICBsb2dXaXRoU3RhY2ssXHJcbiAgbG9nWm9kSXNzdWVzLFxyXG4gIHNldExvZ0xldmVsOiBmdW5jdGlvbiAobGV2ZWwpIHtcclxuICAgIC8vIFVwZGF0ZSB0aGUgaW5zdGFuY2Ugb3B0aW9ucyBvYmplY3RcclxuICAgIGNvbnN0IG9wdGlvbnMgPSB1cGRhdGVPcHRpb25zKFxyXG4gICAgICB2YWxpZGF0ZU9wdGlvbnMoe1xyXG4gICAgICAgIGxvZ2dpbmc6IHtcclxuICAgICAgICAgIGxldmVsXHJcbiAgICAgICAgfVxyXG4gICAgICB9KVxyXG4gICAgKTtcclxuXHJcbiAgICAvLyBDYWxsIHRoZSBmdW5jdGlvblxyXG4gICAgc2V0TG9nTGV2ZWwob3B0aW9ucy5sb2dnaW5nLmxldmVsKTtcclxuICB9LFxyXG4gIGVuYWJsZUNvbnNvbGVMb2dnaW5nOiBmdW5jdGlvbiAodG9Db25zb2xlKSB7XHJcbiAgICAvLyBVcGRhdGUgdGhlIGluc3RhbmNlIG9wdGlvbnMgb2JqZWN0XHJcbiAgICBjb25zdCBvcHRpb25zID0gdXBkYXRlT3B0aW9ucyhcclxuICAgICAgdmFsaWRhdGVPcHRpb25zKHtcclxuICAgICAgICBsb2dnaW5nOiB7XHJcbiAgICAgICAgICB0b0NvbnNvbGVcclxuICAgICAgICB9XHJcbiAgICAgIH0pXHJcbiAgICApO1xyXG5cclxuICAgIC8vIENhbGwgdGhlIGZ1bmN0aW9uXHJcbiAgICBlbmFibGVDb25zb2xlTG9nZ2luZyhvcHRpb25zLmxvZ2dpbmcudG9Db25zb2xlKTtcclxuICB9LFxyXG4gIGVuYWJsZUZpbGVMb2dnaW5nOiBmdW5jdGlvbiAoZGVzdCwgZmlsZSwgdG9GaWxlKSB7XHJcbiAgICAvLyBVcGRhdGUgdGhlIGluc3RhbmNlIG9wdGlvbnMgb2JqZWN0XHJcbiAgICBjb25zdCBvcHRpb25zID0gdXBkYXRlT3B0aW9ucyhcclxuICAgICAgdmFsaWRhdGVPcHRpb25zKHtcclxuICAgICAgICBsb2dnaW5nOiB7XHJcbiAgICAgICAgICBkZXN0LFxyXG4gICAgICAgICAgZmlsZSxcclxuICAgICAgICAgIHRvRmlsZVxyXG4gICAgICAgIH1cclxuICAgICAgfSlcclxuICAgICk7XHJcblxyXG4gICAgLy8gQ2FsbCB0aGUgZnVuY3Rpb25cclxuICAgIGVuYWJsZUZpbGVMb2dnaW5nKFxyXG4gICAgICBvcHRpb25zLmxvZ2dpbmcuZGVzdCxcclxuICAgICAgb3B0aW9ucy5sb2dnaW5nLmZpbGUsXHJcbiAgICAgIG9wdGlvbnMubG9nZ2luZy50b0ZpbGVcclxuICAgICk7XHJcbiAgfVxyXG59O1xyXG4iXSwibmFtZXMiOlsiX19kaXJuYW1lIiwiZmlsZVVSTFRvUGF0aCIsIlVSTCIsImRvY3VtZW50IiwicmVxdWlyZSIsInBhdGhUb0ZpbGVVUkwiLCJfX2ZpbGVuYW1lIiwiaHJlZiIsIl9kb2N1bWVudEN1cnJlbnRTY3JpcHQiLCJ0YWdOYW1lIiwidG9VcHBlckNhc2UiLCJzcmMiLCJiYXNlVVJJIiwiZGVlcENvcHkiLCJvYmpBcnIiLCJvYmpBcnJDb3B5IiwiQXJyYXkiLCJpc0FycmF5Iiwia2V5IiwiT2JqZWN0IiwicHJvdG90eXBlIiwiaGFzT3duUHJvcGVydHkiLCJjYWxsIiwiZml4Q29uc3RyIiwiY29uc3RyIiwiZml4ZWRDb25zdHIiLCJ0b0xvd2VyQ2FzZSIsInJlcGxhY2UiLCJpbmNsdWRlcyIsImZpeE91dGZpbGUiLCJ0eXBlIiwib3V0ZmlsZSIsImdldEFic29sdXRlUGF0aCIsInNwbGl0Iiwic2hpZnQiLCJmaXhUeXBlIiwibWltZVR5cGVzIiwiZm9ybWF0cyIsInZhbHVlcyIsIm91dFR5cGUiLCJwb3AiLCJmaW5kIiwidCIsInBhdGgiLCJpc0Fic29sdXRlIiwibm9ybWFsaXplIiwicmVzb2x2ZSIsImdldEJhc2U2NCIsImlucHV0IiwiQnVmZmVyIiwiZnJvbSIsInRvU3RyaW5nIiwiZ2V0TmV3RGF0ZSIsIkRhdGUiLCJ0cmltIiwiZ2V0TmV3RGF0ZVRpbWUiLCJnZXRUaW1lIiwiaXNPYmplY3QiLCJpdGVtIiwiaXNPYmplY3RFbXB0eSIsImtleXMiLCJsZW5ndGgiLCJpc1ByaXZhdGVSYW5nZVVybEZvdW5kIiwic29tZSIsInBhdHRlcm4iLCJ0ZXN0IiwibWVhc3VyZVRpbWUiLCJzdGFydCIsInByb2Nlc3MiLCJocnRpbWUiLCJiaWdpbnQiLCJOdW1iZXIiLCJyb3VuZE51bWJlciIsInZhbHVlIiwicHJlY2lzaW9uIiwibXVsdGlwbGllciIsIk1hdGgiLCJwb3ciLCJyb3VuZCIsIndyYXBBcm91bmQiLCJjdXN0b21Db2RlIiwiYWxsb3dGaWxlUmVzb3VyY2VzIiwiaXNDYWxsYmFjayIsImVuZHNXaXRoIiwicmVhZEZpbGVTeW5jIiwic3RhcnRzV2l0aCIsImNvbG9ycyIsImxvZ2dpbmciLCJ0b0NvbnNvbGUiLCJ0b0ZpbGUiLCJwYXRoQ3JlYXRlZCIsInBhdGhUb0xvZyIsImxldmVsc0Rlc2MiLCJ0aXRsZSIsImNvbG9yIiwibG9nIiwiYXJncyIsIm5ld0xldmVsIiwidGV4dHMiLCJsZXZlbCIsInByZWZpeCIsIl9sb2dUb0ZpbGUiLCJjb25zb2xlIiwiYXBwbHkiLCJ1bmRlZmluZWQiLCJjb25jYXQiLCJsb2dXaXRoU3RhY2siLCJlcnJvciIsImN1c3RvbU1lc3NhZ2UiLCJtYWluTWVzc2FnZSIsIm1lc3NhZ2UiLCJzdGFja01lc3NhZ2UiLCJzdGFjayIsInB1c2giLCJsb2dab2RJc3N1ZXMiLCJpc3N1ZXMiLCJtYXAiLCJpc3N1ZSIsImpvaW4iLCJpbml0TG9nZ2luZyIsImxvZ2dpbmdPcHRpb25zIiwiZGVzdCIsImZpbGUiLCJzZXRMb2dMZXZlbCIsImVuYWJsZUNvbnNvbGVMb2dnaW5nIiwiZW5hYmxlRmlsZUxvZ2dpbmciLCJpc0ludGVnZXIiLCJleGlzdHNTeW5jIiwibWtkaXJTeW5jIiwiYXBwZW5kRmlsZSIsImRlZmF1bHRDb25maWciLCJwdXBwZXRlZXIiLCJ0eXBlcyIsImVudkxpbmsiLCJjbGlOYW1lIiwiZGVzY3JpcHRpb24iLCJwcm9tcHRPcHRpb25zIiwic2VwYXJhdG9yIiwiaGlnaGNoYXJ0cyIsInZlcnNpb24iLCJjZG5VcmwiLCJmb3JjZUZldGNoIiwiY2FjaGVQYXRoIiwiY29yZVNjcmlwdHMiLCJpbnN0cnVjdGlvbnMiLCJtb2R1bGVTY3JpcHRzIiwiaW5kaWNhdG9yU2NyaXB0cyIsImN1c3RvbVNjcmlwdHMiLCJleHBvcnQiLCJpbmZpbGUiLCJpbnN0ciIsIm9wdGlvbnMiLCJzdmciLCJiYXRjaCIsImhpbnQiLCJjaG9pY2VzIiwiYjY0Iiwibm9Eb3dubG9hZCIsImhlaWdodCIsIndpZHRoIiwic2NhbGUiLCJkZWZhdWx0SGVpZ2h0IiwiZGVmYXVsdFdpZHRoIiwiZGVmYXVsdFNjYWxlIiwibWluIiwibWF4IiwiZ2xvYmFsT3B0aW9ucyIsInRoZW1lT3B0aW9ucyIsInJhc3Rlcml6YXRpb25UaW1lb3V0IiwiY3VzdG9tTG9naWMiLCJhbGxvd0NvZGVFeGVjdXRpb24iLCJjYWxsYmFjayIsInJlc291cmNlcyIsImxvYWRDb25maWciLCJsZWdhY3lOYW1lIiwiY3JlYXRlQ29uZmlnIiwic2VydmVyIiwiZW5hYmxlIiwiaG9zdCIsInBvcnQiLCJ1cGxvYWRMaW1pdCIsImJlbmNobWFya2luZyIsInByb3h5IiwidGltZW91dCIsInJhdGVMaW1pdGluZyIsIm1heFJlcXVlc3RzIiwid2luZG93IiwiZGVsYXkiLCJ0cnVzdFByb3h5Iiwic2tpcEtleSIsInNraXBUb2tlbiIsInNzbCIsImZvcmNlIiwiY2VydFBhdGgiLCJwb29sIiwibWluV29ya2VycyIsIm1heFdvcmtlcnMiLCJ3b3JrTGltaXQiLCJhY3F1aXJlVGltZW91dCIsImNyZWF0ZVRpbWVvdXQiLCJkZXN0cm95VGltZW91dCIsImlkbGVUaW1lb3V0IiwiY3JlYXRlUmV0cnlJbnRlcnZhbCIsInJlYXBlckludGVydmFsIiwidWkiLCJyb3V0ZSIsIm90aGVyIiwibm9kZUVudiIsImxpc3RlblRvUHJvY2Vzc0V4aXRzIiwibm9Mb2dvIiwiaGFyZFJlc2V0UGFnZSIsImJyb3dzZXJTaGVsbE1vZGUiLCJ2YWxpZGF0aW9uIiwiZGVidWciLCJoZWFkbGVzcyIsImRldnRvb2xzIiwibGlzdGVuVG9Db25zb2xlIiwiZHVtcGlvIiwic2xvd01vIiwiZGVidWdnaW5nUG9ydCIsIm5lc3RlZFByb3BzIiwiX2NyZWF0ZU5lc3RlZFByb3BzIiwiYWJzb2x1dGVQcm9wcyIsIl9jcmVhdGVBYnNvbHV0ZVByb3BzIiwiY29uZmlnIiwicHJvcENoYWluIiwiZm9yRWFjaCIsImVudHJ5Iiwic3Vic3RyaW5nIiwiZG90ZW52IiwieiIsInNldEVycm9yTWFwIiwiX2N1c3RvbUVycm9yTWFwIiwidiIsImJvb2xlYW4iLCJzdHJpY3RDaGVjayIsInVuaW9uIiwiZW51bSIsInRyYW5zZm9ybSIsIm51bGxhYmxlIiwic3RyaW5nIiwicmVmaW5lIiwicGFyYW1zIiwiZXJyb3JNZXNzYWdlIiwic3RyaW5nQXJyYXkiLCJmaWx0ZXJDYWxsYmFjayIsImFycmF5U2NoZW1hIiwiYXJyYXkiLCJzdHJpbmdTY2hlbWEiLCJzbGljZSIsInRyYW5zZm9ybUNhbGxiYWNrIiwiZmlsdGVyIiwicG9zaXRpdmVOdW0iLCJudW1iZXIiLCJwb3NpdGl2ZSIsImlzTmFOIiwibm9uTmVnYXRpdmVOdW0iLCJub25uZWdhdGl2ZSIsInByZWZpeGVzIiwiY2hhcnRDb25maWciLCJvYmplY3QiLCJwYXNzdGhyb3VnaCIsImFkZGl0aW9uYWxPcHRpb25zIiwidmFsaWRhdG9ycyIsImFkbWluVG9rZW4iLCJpbmRleE9mIiwiZ3RlIiwibHRlIiwidGhpcyIsIm9iamVjdFNjaGVtYSIsImpzIiwiY3NzIiwiZmlsZXMiLCJwYXJ0aWFsIiwic3RyaW5nU2NoZW1hMSIsInN0cmluZ1NjaGVtYTIiLCJlbmFibGVTZXJ2ZXIiLCJzZXJ2ZXJCZW5jaG1hcmtpbmciLCJwcm94eUhvc3QiLCJwcm94eVBvcnQiLCJwcm94eVRpbWVvdXQiLCJlbmFibGVSYXRlTGltaXRpbmciLCJlbmFibGVTc2wiLCJzc2xGb3JjZSIsInNzbFBvcnQiLCJzc2xDZXJ0UGF0aCIsInBvb2xCZW5jaG1hcmtpbmciLCJyZXNvdXJjZXNJbnRlcnZhbCIsImxvZ0xldmVsIiwiaW50IiwibG9nRmlsZSIsImxvZ0Rlc3QiLCJsb2dUb0NvbnNvbGUiLCJsb2dUb0ZpbGUiLCJlbmFibGVVaSIsInVpUm91dGUiLCJlbmFibGVEZWJ1ZyIsInJlcXVlc3RJZCIsInV1aWQiLCJQdXBwZXRlZXJTY2hlbWEiLCJIaWdoY2hhcnRzU2NoZW1hIiwiRXhwb3J0U2NoZW1hIiwiQ3VzdG9tTG9naWNTY2hlbWEiLCJQcm94eVNjaGVtYSIsIlJhdGVMaW1pdGluZ1NjaGVtYSIsIlNzbFNjaGVtYSIsIlNlcnZlclNjaGVtYSIsIm9wdGlvbmFsIiwiUG9vbFNjaGVtYSIsIkxvZ2dpbmdTY2hlbWEiLCJVaVNjaGVtYSIsIk90aGVyU2NoZW1hIiwiRGVidWdTY2hlbWEiLCJTdHJpY3RDb25maWdTY2hlbWEiLCJMb29zZUNvbmZpZ1NjaGVtYSIsIkVudlNjaGVtYSIsIlBVUFBFVEVFUl9BUkdTIiwiSElHSENIQVJUU19WRVJTSU9OIiwiSElHSENIQVJUU19DRE5fVVJMIiwiSElHSENIQVJUU19GT1JDRV9GRVRDSCIsIkhJR0hDSEFSVFNfQ0FDSEVfUEFUSCIsIkhJR0hDSEFSVFNfQURNSU5fVE9LRU4iLCJISUdIQ0hBUlRTX0NPUkVfU0NSSVBUUyIsIkhJR0hDSEFSVFNfTU9EVUxFX1NDUklQVFMiLCJISUdIQ0hBUlRTX0lORElDQVRPUl9TQ1JJUFRTIiwiSElHSENIQVJUU19DVVNUT01fU0NSSVBUUyIsIkVYUE9SVF9JTkZJTEUiLCJFWFBPUlRfSU5TVFIiLCJFWFBPUlRfT1BUSU9OUyIsIkVYUE9SVF9TVkciLCJFWFBPUlRfQkFUQ0giLCJFWFBPUlRfT1VURklMRSIsIkVYUE9SVF9UWVBFIiwiRVhQT1JUX0NPTlNUUiIsIkVYUE9SVF9CNjQiLCJFWFBPUlRfTk9fRE9XTkxPQUQiLCJFWFBPUlRfSEVJR0hUIiwiRVhQT1JUX1dJRFRIIiwiRVhQT1JUX1NDQUxFIiwiRVhQT1JUX0RFRkFVTFRfSEVJR0hUIiwiRVhQT1JUX0RFRkFVTFRfV0lEVEgiLCJFWFBPUlRfREVGQVVMVF9TQ0FMRSIsIkVYUE9SVF9HTE9CQUxfT1BUSU9OUyIsIkVYUE9SVF9USEVNRV9PUFRJT05TIiwiRVhQT1JUX1JBU1RFUklaQVRJT05fVElNRU9VVCIsIkNVU1RPTV9MT0dJQ19BTExPV19DT0RFX0VYRUNVVElPTiIsIkNVU1RPTV9MT0dJQ19BTExPV19GSUxFX1JFU09VUkNFUyIsIkNVU1RPTV9MT0dJQ19DVVNUT01fQ09ERSIsIkNVU1RPTV9MT0dJQ19DQUxMQkFDSyIsIkNVU1RPTV9MT0dJQ19SRVNPVVJDRVMiLCJDVVNUT01fTE9HSUNfTE9BRF9DT05GSUciLCJDVVNUT01fTE9HSUNfQ1JFQVRFX0NPTkZJRyIsIlNFUlZFUl9FTkFCTEUiLCJTRVJWRVJfSE9TVCIsIlNFUlZFUl9QT1JUIiwiU0VSVkVSX1VQTE9BRF9MSU1JVCIsIlNFUlZFUl9CRU5DSE1BUktJTkciLCJTRVJWRVJfUFJPWFlfSE9TVCIsIlNFUlZFUl9QUk9YWV9QT1JUIiwiU0VSVkVSX1BST1hZX1RJTUVPVVQiLCJTRVJWRVJfUkFURV9MSU1JVElOR19FTkFCTEUiLCJTRVJWRVJfUkFURV9MSU1JVElOR19NQVhfUkVRVUVTVFMiLCJTRVJWRVJfUkFURV9MSU1JVElOR19XSU5ET1ciLCJTRVJWRVJfUkFURV9MSU1JVElOR19ERUxBWSIsIlNFUlZFUl9SQVRFX0xJTUlUSU5HX1RSVVNUX1BST1hZIiwiU0VSVkVSX1JBVEVfTElNSVRJTkdfU0tJUF9LRVkiLCJTRVJWRVJfUkFURV9MSU1JVElOR19TS0lQX1RPS0VOIiwiU0VSVkVSX1NTTF9FTkFCTEUiLCJTRVJWRVJfU1NMX0ZPUkNFIiwiU0VSVkVSX1NTTF9QT1JUIiwiU0VSVkVSX1NTTF9DRVJUX1BBVEgiLCJQT09MX01JTl9XT1JLRVJTIiwiUE9PTF9NQVhfV09SS0VSUyIsIlBPT0xfV09SS19MSU1JVCIsIlBPT0xfQUNRVUlSRV9USU1FT1VUIiwiUE9PTF9DUkVBVEVfVElNRU9VVCIsIlBPT0xfREVTVFJPWV9USU1FT1VUIiwiUE9PTF9JRExFX1RJTUVPVVQiLCJQT09MX0NSRUFURV9SRVRSWV9JTlRFUlZBTCIsIlBPT0xfUkVBUEVSX0lOVEVSVkFMIiwiUE9PTF9CRU5DSE1BUktJTkciLCJMT0dHSU5HX0xFVkVMIiwiTE9HR0lOR19GSUxFIiwiTE9HR0lOR19ERVNUIiwiTE9HR0lOR19UT19DT05TT0xFIiwiTE9HR0lOR19UT19GSUxFIiwiVUlfRU5BQkxFIiwiVUlfUk9VVEUiLCJPVEhFUl9OT0RFX0VOViIsIk9USEVSX0xJU1RFTl9UT19QUk9DRVNTX0VYSVRTIiwiT1RIRVJfTk9fTE9HTyIsIk9USEVSX0hBUkRfUkVTRVRfUEFHRSIsIk9USEVSX0JST1dTRVJfU0hFTExfTU9ERSIsIk9USEVSX1ZBTElEQVRJT04iLCJERUJVR19FTkFCTEUiLCJERUJVR19IRUFETEVTUyIsIkRFQlVHX0RFVlRPT0xTIiwiREVCVUdfTElTVEVOX1RPX0NPTlNPTEUiLCJERUJVR19EVU1QSU8iLCJERUJVR19TTE9XX01PIiwiREVCVUdfREVCVUdHSU5HX1BPUlQiLCJlbnZzIiwicGFyc2UiLCJlbnYiLCJzdHJpY3RWYWxpZGF0ZSIsImNvbmZpZ09wdGlvbnMiLCJsb29zZVZhbGlkYXRlIiwiY29udGV4dCIsInByb3BlcnR5TmFtZSIsInByb3BlcnR5SW5mbyIsImNvZGUiLCJab2RJc3N1ZUNvZGUiLCJpbnZhbGlkX3R5cGUiLCJyZWNlaXZlZCIsIlpvZFBhcnNlZFR5cGUiLCJkZWZhdWx0RXJyb3IiLCJjdXN0b20iLCJkYXRhIiwiaW52YWxpZF91bmlvbiIsInVuaW9uRXJyb3JzIiwiaW5kZXgiLCJFeHBvcnRFcnJvciIsIkVycm9yIiwiY29uc3RydWN0b3IiLCJzdGF0dXNDb2RlIiwic3VwZXIiLCJzZXRTdGF0dXMiLCJzZXRFcnJvciIsIm5hbWUiLCJfaW5pdE9wdGlvbnMiLCJnZXRPcHRpb25zIiwiZ2V0Q29weSIsInVwZGF0ZU9wdGlvbnMiLCJuZXdPcHRpb25zIiwiX21lcmdlT3B0aW9ucyIsIm1hcFRvTmV3T3B0aW9ucyIsIm9sZE9wdGlvbnMiLCJlbnRyaWVzIiwicHJvcGVydGllc0NoYWluIiwicmVkdWNlIiwib2JqIiwicHJvcCIsInZhbGlkYXRlT3B0aW9uIiwiY29uZmlnT3B0aW9uIiwidmFsaWRhdGVPcHRpb25zIiwiaXNBbGxvd2VkQ29uZmlnIiwiYWxsb3dGdW5jdGlvbnMiLCJvYmplY3RDb25maWciLCJldmFsIiwiSlNPTiIsInN0cmluZ2lmaWVkT3B0aW9ucyIsIl9vcHRpb25zU3RyaW5naWZ5IiwicGFyc2VkT3B0aW9ucyIsIl8iLCJvcmlnaW5hbE9wdGlvbnMiLCJzdHJpbmdpZnlGdW5jdGlvbnMiLCJzdHJpbmdpZnkiLCJyZXBsYWNlQWxsIiwiYXN5bmMiLCJmZXRjaCIsInVybCIsInJlcXVlc3RPcHRpb25zIiwiUHJvbWlzZSIsInJlamVjdCIsIl9nZXRQcm90b2NvbE1vZHVsZSIsImdldCIsInJlc3BvbnNlIiwicmVzcG9uc2VEYXRhIiwib24iLCJjaHVuayIsInRleHQiLCJodHRwcyIsImh0dHAiLCJjYWNoZSIsImFjdGl2ZU1hbmlmZXN0Iiwic291cmNlcyIsImhjVmVyc2lvbiIsImNoZWNrQW5kVXBkYXRlQ2FjaGUiLCJoaWdoY2hhcnRzT3B0aW9ucyIsInNlcnZlclByb3h5T3B0aW9ucyIsImZldGNoZWRNb2R1bGVzIiwiZ2V0Q2FjaGVQYXRoIiwibWFuaWZlc3RQYXRoIiwic291cmNlUGF0aCIsInJlY3Vyc2l2ZSIsIl91cGRhdGVDYWNoZSIsInJlcXVlc3RVcGRhdGUiLCJtYW5pZmVzdCIsIm1vZHVsZXMiLCJtb2R1bGVNYXAiLCJtIiwibnVtYmVyT2ZNb2R1bGVzIiwibW9kdWxlTmFtZSIsImV4dHJhY3RWZXJzaW9uIiwiX3NhdmVDb25maWdUb01hbmlmZXN0IiwiZ2V0SGlnaGNoYXJ0c1ZlcnNpb24iLCJ1cGRhdGVIaWdoY2hhcnRzVmVyc2lvbiIsIm5ld1ZlcnNpb24iLCJjYWNoZVNvdXJjZXMiLCJleHRyYWN0TW9kdWxlTmFtZSIsInNjcmlwdFBhdGgiLCJfZmV0Y2hBbmRQcm9jZXNzU2NyaXB0Iiwic2NyaXB0Iiwic2hvdWxkVGhyb3dFcnJvciIsIm5ld01hbmlmZXN0Iiwid3JpdGVGaWxlU3luYyIsIl9mZXRjaFNjcmlwdHMiLCJwcm94eUFnZW50IiwiSHR0cHNQcm94eUFnZW50IiwiYWdlbnQiLCJhbGxGZXRjaFByb21pc2VzIiwiYWxsIiwiYyIsImkiLCJzZXR1cEhpZ2hjaGFydHMiLCJIaWdoY2hhcnRzIiwiYW5pbU9iamVjdCIsImR1cmF0aW9uIiwiY3JlYXRlQ2hhcnQiLCJleHBvcnRPcHRpb25zIiwiY3VzdG9tTG9naWNPcHRpb25zIiwic2V0T3B0aW9ucyIsIm1lcmdlIiwid3JhcCIsInNldE9wdGlvbnNPYmoiLCJpc1JlbmRlckNvbXBsZXRlIiwiQ2hhcnQiLCJwcm9jZWVkIiwidXNlck9wdGlvbnMiLCJjYiIsImV4cG9ydGluZyIsImVuYWJsZWQiLCJwbG90T3B0aW9ucyIsInNlcmllcyIsImxhYmVsIiwidG9vbHRpcCIsImFuaW1hdGlvbiIsIm9uSGlnaGNoYXJ0c1JlbmRlciIsImFkZEV2ZW50IiwiU2VyaWVzIiwiY2hhcnQiLCJGdW5jdGlvbiIsImZpbmFsT3B0aW9ucyIsImZpbmFsQ2FsbGJhY2siLCJkZWZhdWx0T3B0aW9ucyIsInRlbXBsYXRlIiwiYnJvd3NlciIsImNyZWF0ZUJyb3dzZXIiLCJwdXBwZXRlZXJBcmdzIiwiZW5hYmxlZERlYnVnIiwiZGVidWdPcHRpb25zIiwibGF1bmNoT3B0aW9ucyIsInVzZXJEYXRhRGlyIiwiaGFuZGxlU0lHSU5UIiwiaGFuZGxlU0lHVEVSTSIsImhhbmRsZVNJR0hVUCIsIndhaXRGb3JJbml0aWFsUGFnZSIsImRlZmF1bHRWaWV3cG9ydCIsInRyeUNvdW50Iiwib3BlbiIsImxhdW5jaCIsInNldFRpbWVvdXQiLCJjbG9zZUJyb3dzZXIiLCJjb25uZWN0ZWQiLCJjbG9zZSIsIm5ld1BhZ2UiLCJwb29sUmVzb3VyY2UiLCJwYWdlIiwic2V0Q2FjaGVFbmFibGVkIiwiX3NldFBhZ2VDb250ZW50IiwiX3NldFBhZ2VFdmVudHMiLCJpc0Nsb3NlZCIsImNsZWFyUGFnZSIsImhhcmRSZXNldCIsImdvdG8iLCJ3YWl0VW50aWwiLCJldmFsdWF0ZSIsImJvZHkiLCJpbm5lckhUTUwiLCJpZCIsIndvcmtDb3VudCIsImFkZFBhZ2VSZXNvdXJjZXMiLCJpbmplY3RlZFJlc291cmNlcyIsImluamVjdGVkSnMiLCJjb250ZW50IiwiaXNMb2NhbCIsImpzUmVzb3VyY2UiLCJhZGRTY3JpcHRUYWciLCJpbmplY3RlZENzcyIsImNzc0ltcG9ydHMiLCJtYXRjaCIsImNzc0ltcG9ydFBhdGgiLCJjc3NSZXNvdXJjZSIsImFkZFN0eWxlVGFnIiwiY2xlYXJQYWdlUmVzb3VyY2VzIiwicmVzb3VyY2UiLCJkaXNwb3NlIiwib2xkQ2hhcnRzIiwiY2hhcnRzIiwib2xkQ2hhcnQiLCJkZXN0cm95Iiwic2NyaXB0c1RvUmVtb3ZlIiwiZ2V0RWxlbWVudHNCeVRhZ05hbWUiLCJzdHlsZXNUb1JlbW92ZSIsImxpbmtzVG9SZW1vdmUiLCJlbGVtZW50IiwicmVtb3ZlIiwic2V0Q29udGVudCIsImNzc1RlbXBsYXRlIiwic3ZnVGVtcGxhdGUiLCJwdXBwZXRlZXJFeHBvcnQiLCJpc1NWRyIsInNpemUiLCJzdmdFbGVtZW50IiwicXVlcnlTZWxlY3RvciIsImNoYXJ0SGVpZ2h0IiwiYmFzZVZhbCIsImNoYXJ0V2lkdGgiLCJzdHlsZSIsInpvb20iLCJtYXJnaW4iLCJwYXJzZUZsb2F0IiwieCIsInkiLCJfZ2V0Q2xpcFJlZ2lvbiIsInZpZXdwb3J0SGVpZ2h0IiwiYWJzIiwiY2VpbCIsInZpZXdwb3J0V2lkdGgiLCJyZXN1bHQiLCJzZXRWaWV3cG9ydCIsImRldmljZVNjYWxlRmFjdG9yIiwiX2NyZWF0ZVNWRyIsIl9jcmVhdGVJbWFnZSIsIl9jcmVhdGVQREYiLCIkZXZhbCIsImdldEJvdW5kaW5nQ2xpZW50UmVjdCIsInRydW5jIiwib3V0ZXJIVE1MIiwiY2xpcCIsInJhY2UiLCJzY3JlZW5zaG90IiwiZW5jb2RpbmciLCJmdWxsUGFnZSIsIm9wdGltaXplRm9yU3BlZWQiLCJjYXB0dXJlQmV5b25kVmlld3BvcnQiLCJxdWFsaXR5Iiwib21pdEJhY2tncm91bmQiLCJfcmVzb2x2ZSIsImVtdWxhdGVNZWRpYVR5cGUiLCJwZGYiLCJwb29sU3RhdHMiLCJleHBvcnRzQXR0ZW1wdGVkIiwiZXhwb3J0c1BlcmZvcm1lZCIsImV4cG9ydHNEcm9wcGVkIiwiZXhwb3J0c0Zyb21TdmciLCJleHBvcnRzRnJvbU9wdGlvbnMiLCJleHBvcnRzRnJvbVN2Z0F0dGVtcHRzIiwiZXhwb3J0c0Zyb21PcHRpb25zQXR0ZW1wdHMiLCJ0aW1lU3BlbnQiLCJ0aW1lU3BlbnRBdmVyYWdlIiwiaW5pdFBvb2wiLCJwb29sT3B0aW9ucyIsIlBvb2wiLCJfZmFjdG9yeSIsImFjcXVpcmVUaW1lb3V0TWlsbGlzIiwiY3JlYXRlVGltZW91dE1pbGxpcyIsImRlc3Ryb3lUaW1lb3V0TWlsbGlzIiwiaWRsZVRpbWVvdXRNaWxsaXMiLCJjcmVhdGVSZXRyeUludGVydmFsTWlsbGlzIiwicmVhcEludGVydmFsTWlsbGlzIiwicHJvcGFnYXRlQ3JlYXRlRXJyb3IiLCJjbGVhclN0YXR1cyIsIl9ldmVudElkIiwiaW5pdGlhbFJlc291cmNlcyIsImFjcXVpcmUiLCJwcm9taXNlIiwicmVsZWFzZSIsImtpbGxQb29sIiwid29ya2VyIiwidXNlZCIsImRlc3Ryb3llZCIsInBvc3RXb3JrIiwid29ya2VySGFuZGxlIiwiZ2V0UG9vbEluZm8iLCJhY3F1aXJlQ291bnRlciIsIndvcmtTdGFydCIsImV4cG9ydENvdW50ZXIiLCJleHBvcnRUaW1lIiwiZ2V0UG9vbFN0YXRzIiwiZ2V0UG9vbEluZm9KU09OIiwibnVtVXNlZCIsImF2YWlsYWJsZSIsIm51bUZyZWUiLCJhbGxDcmVhdGVkIiwicGVuZGluZ0FjcXVpcmVzIiwibnVtUGVuZGluZ0FjcXVpcmVzIiwicGVuZGluZ0NyZWF0ZXMiLCJudW1QZW5kaW5nQ3JlYXRlcyIsInBlbmRpbmdWYWxpZGF0aW9ucyIsIm51bVBlbmRpbmdWYWxpZGF0aW9ucyIsInBlbmRpbmdEZXN0cm95cyIsImFic29sdXRlQWxsIiwiY3JlYXRlIiwicmFuZG9tIiwic3RhcnREYXRlIiwidmFsaWRhdGUiLCJtYWluRnJhbWUiLCJkZXRhY2hlZCIsInJlbW92ZUFsbExpc3RlbmVycyIsInNhbml0aXplIiwiSlNET00iLCJET01QdXJpZnkiLCJBRERfVEFHUyIsInNpbmdsZUV4cG9ydCIsInN0YXJ0RXhwb3J0IiwiYmF0Y2hFeHBvcnQiLCJiYXRjaEZ1bmN0aW9ucyIsInBhaXIiLCJiYXRjaFJlc3VsdHMiLCJhbGxTZXR0bGVkIiwicmVhc29uIiwiaW1hZ2VPcHRpb25zIiwiZW5kQ2FsbGJhY2siLCJmaWxlQ29udGVudCIsIl9leHBvcnRGcm9tU3ZnIiwiX2V4cG9ydEZyb21PcHRpb25zIiwiZ2V0QWxsb3dDb2RlRXhlY3V0aW9uIiwic2V0QWxsb3dDb2RlRXhlY3V0aW9uIiwiaW5wdXRUb0V4cG9ydCIsIl9wcmVwYXJlRXhwb3J0IiwiX2hhbmRsZUN1c3RvbUxvZ2ljIiwiX2hhbmRsZUdsb2JhbEFuZFRoZW1lIiwiX2ZpbmRDaGFydFNpemUiLCJvcHRpb25zQ2hhcnQiLCJvcHRpb25zRXhwb3J0aW5nIiwiZ2xvYmFsT3B0aW9uc0NoYXJ0IiwiZ2xvYmFsT3B0aW9uc0V4cG9ydGluZyIsInRoZW1lT3B0aW9uc0NoYXJ0IiwidGhlbWVPcHRpb25zRXhwb3J0aW5nIiwic291cmNlSGVpZ2h0Iiwic291cmNlV2lkdGgiLCJwYXJhbSIsIl9oYW5kbGVSZXNvdXJjZXMiLCJhbGxvd2VkUHJvcHMiLCJoYW5kbGVkUmVzb3VyY2VzIiwiY29ycmVjdFJlc291cmNlcyIsInByb3BOYW1lIiwib3B0aW9uc05hbWUiLCJ0aW1lcklkcyIsImFkZFRpbWVyIiwiY2xlYXJBbGxUaW1lcnMiLCJjbGVhckludGVydmFsIiwiY2xlYXJUaW1lb3V0IiwibG9nRXJyb3JNaWRkbGV3YXJlIiwicmVxdWVzdCIsIm5leHQiLCJyZXR1cm5FcnJvck1pZGRsZXdhcmUiLCJzdGF0dXMiLCJqc29uIiwiZXJyb3JNaWRkbGV3YXJlIiwiYXBwIiwidXNlIiwicmF0ZUxpbWl0aW5nTWlkZGxld2FyZSIsInJhdGVMaW1pdGluZ09wdGlvbnMiLCJyYXRlT3B0aW9ucyIsImxpbWl0ZXIiLCJyYXRlTGltaXQiLCJ3aW5kb3dNcyIsImxpbWl0IiwiZGVsYXlNcyIsImhhbmRsZXIiLCJmb3JtYXQiLCJzZW5kIiwiZGVmYXVsdCIsInNraXAiLCJxdWVyeSIsImFjY2Vzc190b2tlbiIsImNvbnRlbnRUeXBlTWlkZGxld2FyZSIsImNvbnRlbnRUeXBlIiwiaGVhZGVycyIsInJlcXVlc3RCb2R5TWlkZGxld2FyZSIsImNvbm5lY3Rpb24iLCJyZW1vdGVBZGRyZXNzIiwidmFsaWRhdGVkT3B0aW9ucyIsImZpbGVuYW1lIiwidmFsaWRhdGlvbk1pZGRsZXdhcmUiLCJwb3N0IiwicmV2ZXJzZWRNaW1lIiwicG5nIiwianBlZyIsImdpZiIsInJlcXVlc3RFeHBvcnQiLCJyZXF1ZXN0Q291bnRlciIsImNvbm5lY3Rpb25BYm9ydGVkIiwic29ja2V0IiwiaGFkRXJyb3JzIiwiaGVhZGVyIiwiYXR0YWNobWVudCIsImV4cG9ydFJvdXRlcyIsInNlcnZlclN0YXJ0VGltZSIsInBhY2thZ2VGaWxlIiwic3VjY2Vzc1JhdGVzIiwicmVjb3JkSW50ZXJ2YWwiLCJ3aW5kb3dTaXplIiwiX2NhbGN1bGF0ZU1vdmluZ0F2ZXJhZ2UiLCJhIiwiYiIsIl9zdGFydFN1Y2Nlc3NSYXRlIiwic2V0SW50ZXJ2YWwiLCJzdGF0cyIsInN1Y2Nlc3NSYXRpbyIsImhlYWx0aFJvdXRlcyIsInBlcmlvZCIsIm1vdmluZ0F2ZXJhZ2UiLCJib290VGltZSIsInVwdGltZSIsImZsb29yIiwic2VydmVyVmVyc2lvbiIsImhpZ2hjaGFydHNWZXJzaW9uIiwiYXZlcmFnZUV4cG9ydFRpbWUiLCJhdHRlbXB0ZWRFeHBvcnRzIiwicGVyZm9ybWVkRXhwb3J0cyIsImZhaWxlZEV4cG9ydHMiLCJzdWNlc3NSYXRpbyIsInRvRml4ZWQiLCJzdmdFeHBvcnRzIiwianNvbkV4cG9ydHMiLCJzdmdFeHBvcnRzQXR0ZW1wdHMiLCJqc29uRXhwb3J0c0F0dGVtcHRzIiwidWlSb3V0ZXMiLCJzZW5kRmlsZSIsImFjY2VwdFJhbmdlcyIsInZlcnNpb25DaGFuZ2VSb3V0ZXMiLCJ0b2tlbiIsImFjdGl2ZVNlcnZlcnMiLCJNYXAiLCJleHByZXNzIiwic3RhcnRTZXJ2ZXIiLCJzZXJ2ZXJPcHRpb25zIiwidXBsb2FkTGltaXRCeXRlcyIsInN0b3JhZ2UiLCJtdWx0ZXIiLCJtZW1vcnlTdG9yYWdlIiwidXBsb2FkIiwibGltaXRzIiwiZmllbGRTaXplIiwiZGlzYWJsZSIsImNvcnMiLCJtZXRob2RzIiwic2V0IiwidXJsZW5jb2RlZCIsImV4dGVuZGVkIiwibm9uZSIsInN0YXRpYyIsImh0dHBTZXJ2ZXIiLCJjcmVhdGVTZXJ2ZXIiLCJfYXR0YWNoU2VydmVyRXJyb3JIYW5kbGVycyIsImxpc3RlbiIsImNlcnQiLCJodHRwc1NlcnZlciIsImNsb3NlU2VydmVycyIsImRlbGV0ZSIsImdldFNlcnZlcnMiLCJnZXRFeHByZXNzIiwiZ2V0QXBwIiwibWlkZGxld2FyZXMiLCJzaHV0ZG93bkNsZWFuVXAiLCJleGl0Q29kZSIsImV4aXQiLCJpbml0RXhwb3J0IiwiaW5pdE9wdGlvbnMiLCJfYXR0YWNoUHJvY2Vzc0V4aXRMaXN0ZW5lcnMiXSwibWFwcGluZ3MiOiJ3bEJBMkJPLE1BQU1BLFlBQVlDLElBQWFBLGNBQUMsSUFBSUMsSUFBSSxPQUFRLG9CQUFBQyxTQUFBQyxRQUFBLE9BQUFDLGNBQUFDLFlBQUFDLEtBQUFDLHdCQUFBLFdBQUFBLHVCQUFBQyxRQUFBQyxlQUFBRix1QkFBQUcsS0FBQSxJQUFBVCxJQUFBLFlBQUFDLFNBQUFTLFNBQUFMLE9BK0JoRCxTQUFTTSxTQUFTQyxHQUV2QixHQUFlLE9BQVhBLEdBQXFDLGlCQUFYQSxFQUM1QixPQUFPQSxFQUlULE1BQU1DLEVBQWFDLE1BQU1DLFFBQVFILEdBQVUsR0FBSyxHQUdoRCxJQUFLLE1BQU1JLEtBQU9KLEVBQ1pLLE9BQU9DLFVBQVVDLGVBQWVDLEtBQUtSLEVBQVFJLEtBQy9DSCxFQUFXRyxHQUFPTCxTQUFTQyxFQUFPSSxLQUt0QyxPQUFPSCxDQUNULENBMkRPLFNBQVNRLFVBQVVDLEdBQ3hCLElBRUUsTUFBTUMsRUFBYyxHQUFHRCxFQUFPRSxjQUFjQyxRQUFRLFFBQVMsV0FRN0QsTUFMb0IsVUFBaEJGLEdBQ0ZBLEVBQVlDLGNBSVAsQ0FBQyxRQUFTLGFBQWMsV0FBWSxjQUFjRSxTQUN2REgsR0FFRUEsRUFDQSxPQUNSLENBQUksTUFFQSxNQUFPLE9BQ1IsQ0FDSCxDQVlPLFNBQVNJLFdBQVdDLEVBQU1DLEdBTy9C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 +"use strict";Object.defineProperty(exports,"__esModule",{value:!0}),require("colors");var fs=require("fs"),path=require("path"),httpsProxyAgent=require("https-proxy-agent"),url=require("url"),dotenv=require("dotenv"),zod=require("zod"),http=require("http"),https=require("https"),tarn=require("tarn"),uuid=require("uuid"),puppeteer=require("puppeteer"),DOMPurify=require("dompurify"),jsdom=require("jsdom"),cors=require("cors"),express=require("express"),multer=require("multer"),rateLimit=require("express-rate-limit"),_documentCurrentScript="undefined"!=typeof document?document.currentScript:null;const __dirname$1=url.fileURLToPath(new URL("../.","undefined"==typeof document?require("url").pathToFileURL(__filename).href:_documentCurrentScript&&"SCRIPT"===_documentCurrentScript.tagName.toUpperCase()&&_documentCurrentScript.src||new URL("index.cjs",document.baseURI).href));function deepCopy(e){if(null===e||"object"!=typeof e)return e;const t=Array.isArray(e)?[]:{};for(const o in e)Object.prototype.hasOwnProperty.call(e,o)&&(t[o]=deepCopy(e[o]));return t}function fixConstr(e){try{const t=`${e.toLowerCase().replace("chart","")}Chart`;return"Chart"===t&&t.toLowerCase(),["chart","stockChart","mapChart","ganttChart"].includes(t)?t:"chart"}catch{return"chart"}}function fixOutfile(e,t){return`${getAbsolutePath(t||"chart").split(".").shift()}.${e}`}function fixType(e,t=null){const o={"image/png":"png","image/jpeg":"jpeg","application/pdf":"pdf","image/svg+xml":"svg"},r=Object.values(o);if(t){const o=t.split(".").pop();"jpg"===o?e="jpeg":r.includes(o)&&e!==o&&(e=o)}return o[e]||r.find((t=>t===e))||"png"}function getAbsolutePath(e){return path.isAbsolute(e)?path.normalize(e):path.resolve(e)}function getBase64(e,t){return"pdf"===t||"svg"==t?Buffer.from(e,"utf8").toString("base64"):e}function getNewDate(){return(new Date).toString().split("(")[0].trim()}function getNewDateTime(){return(new Date).getTime()}function isObject(e){return"[object Object]"===Object.prototype.toString.call(e)}function isObjectEmpty(e){return"object"==typeof e&&!Array.isArray(e)&&null!==e&&0===Object.keys(e).length}function isPrivateRangeUrlFound(e){return[/xlink:href="(?:http:\/\/|https:\/\/)?localhost\b/,/xlink:href="(?:http:\/\/|https:\/\/)?10\.\d{1,3}\.\d{1,3}\.\d{1,3}\b/,/xlink:href="(?:http:\/\/|https:\/\/)?127\.\d{1,3}\.\d{1,3}\.\d{1,3}\b/,/xlink:href="(?:http:\/\/|https:\/\/)?172\.(1[6-9]|2[0-9]|3[0-1])\.\d{1,3}\.\d{1,3}\b/,/xlink:href="(?:http:\/\/|https:\/\/)?192\.168\.\d{1,3}\.\d{1,3}\b/].some((t=>t.test(e)))}function measureTime(){const e=process.hrtime.bigint();return()=>Number(process.hrtime.bigint()-e)/1e6}function roundNumber(e,t=1){const o=Math.pow(10,t||0);return Math.round(+e*o)/o}function wrapAround(e,t,o=!1){if(e&&"string"==typeof e)return(e=e.trim()).endsWith(".js")?t?wrapAround(fs.readFileSync(getAbsolutePath(e),"utf8"),t,o):null:!o&&(e.startsWith("function()")||e.startsWith("function ()")||e.startsWith("()=>")||e.startsWith("() =>"))?`(${e})()`:e.replace(/;$/,"")}const colors=["red","yellow","blue","gray","green"],logging={toConsole:!0,toFile:!1,pathCreated:!1,pathToLog:"",levelsDesc:[{title:"error",color:colors[0]},{title:"warning",color:colors[1]},{title:"notice",color:colors[2]},{title:"verbose",color:colors[3]},{title:"benchmark",color:colors[4]}]};function log(...e){const[t,...o]=e,{levelsDesc:r,level:n}=logging;if(5!==t&&(0===t||t>n||n>r.length))return;const i=`${getNewDate()} [${r[t-1].title}] -`;logging.toFile&&_logToFile(o,i),logging.toConsole&&console.log.apply(void 0,[i.toString()[logging.levelsDesc[t-1].color]].concat(o))}function logWithStack(e,t,o){const r=o||t&&t.message||"",{level:n,levelsDesc:i}=logging;if(0===e||e>n||n>i.length)return;const s=`${getNewDate()} [${i[e-1].title}] -`,a=t&&t.stack,l=[r];a&&l.push("\n",a),logging.toFile&&_logToFile(l,s),logging.toConsole&&console.log.apply(void 0,[s.toString()[logging.levelsDesc[e-1].color]].concat([l.shift()[colors[e-1]],...l]))}function logZodIssues(e,t,o){logWithStack(e,null,[`${o||"[validation] Validation error"} - the following Zod issues occured:`,...(t||[]).map((e=>`- ${e.message}`))].join("\n"))}function initLogging(e){const{level:t,dest:o,file:r,toConsole:n,toFile:i}=e;logging.pathCreated=!1,logging.pathToLog="",setLogLevel(t),enableConsoleLogging(n),enableFileLogging(o,r,i)}function setLogLevel(e){Number.isInteger(e)&&e>=0&&e<=logging.levelsDesc.length&&(logging.level=e)}function enableConsoleLogging(e){logging.toConsole=!!e}function enableFileLogging(e,t,o){logging.toFile=!!o,logging.toFile&&(logging.dest=e||"",logging.file=t||"")}function _logToFile(e,t){logging.pathCreated||(!fs.existsSync(getAbsolutePath(logging.dest))&&fs.mkdirSync(getAbsolutePath(logging.dest)),logging.pathToLog=getAbsolutePath(path.join(logging.dest,logging.file)),logging.pathCreated=!0),fs.appendFile(logging.pathToLog,[t].concat(e).join(" ")+"\n",(e=>{e&&logging.toFile&&logging.pathCreated&&(logging.toFile=!1,logging.pathCreated=!1,logWithStack(2,e,"[logger] Unable to write to log file."))}))}const defaultConfig={puppeteer:{args:{value:["--allow-running-insecure-content","--ash-no-nudges","--autoplay-policy=user-gesture-required","--block-new-web-contents","--disable-accelerated-2d-canvas","--disable-background-networking","--disable-background-timer-throttling","--disable-backgrounding-occluded-windows","--disable-breakpad","--disable-checker-imaging","--disable-client-side-phishing-detection","--disable-component-extensions-with-background-pages","--disable-component-update","--disable-default-apps","--disable-dev-shm-usage","--disable-domain-reliability","--disable-extensions","--disable-features=CalculateNativeWinOcclusion,InterestFeedContentSuggestions,WebOTP","--disable-hang-monitor","--disable-ipc-flooding-protection","--disable-logging","--disable-notifications","--disable-offer-store-unmasked-wallet-cards","--disable-popup-blocking","--disable-print-preview","--disable-prompt-on-repost","--disable-renderer-backgrounding","--disable-search-engine-choice-screen","--disable-session-crashed-bubble","--disable-setuid-sandbox","--disable-site-isolation-trials","--disable-speech-api","--disable-sync","--enable-unsafe-webgpu","--hide-crash-restore-bubble","--hide-scrollbars","--metrics-recording-only","--mute-audio","--no-default-browser-check","--no-first-run","--no-pings","--no-sandbox","--no-startup-window","--no-zygote","--password-store=basic","--process-per-tab","--use-mock-keychain"],types:["string[]"],envLink:"PUPPETEER_ARGS",cliName:"puppeteerArgs",description:"Array of Puppeteer arguments",promptOptions:{type:"list",separator:";"}}},highcharts:{version:{value:"latest",types:["string"],envLink:"HIGHCHARTS_VERSION",description:"Highcharts version",promptOptions:{type:"text"}},cdnUrl:{value:"https://code.highcharts.com",types:["string"],envLink:"HIGHCHARTS_CDN_URL",description:"CDN URL for Highcharts scripts",promptOptions:{type:"text"}},forceFetch:{value:!1,types:["boolean"],envLink:"HIGHCHARTS_FORCE_FETCH",description:"Flag to refetch scripts after each server rerun",promptOptions:{type:"toggle"}},cachePath:{value:".cache",types:["string"],envLink:"HIGHCHARTS_CACHE_PATH",description:"Directory path for cached Highcharts scripts",promptOptions:{type:"text"}},coreScripts:{value:["highcharts","highcharts-more","highcharts-3d"],types:["string[]"],envLink:"HIGHCHARTS_CORE_SCRIPTS",description:"Highcharts core scripts to fetch",promptOptions:{type:"multiselect",instructions:"Space: Select specific, A: Select all, Enter: Confirm"}},moduleScripts:{value:["stock","map","gantt","exporting","parallel-coordinates","accessibility","boost-canvas","boost","data","data-tools","draggable-points","static-scale","broken-axis","heatmap","tilemap","tiledwebmap","timeline","treemap","treegraph","item-series","drilldown","histogram-bellcurve","bullet","funnel","funnel3d","geoheatmap","pyramid3d","networkgraph","overlapping-datalabels","pareto","pattern-fill","pictorial","price-indicator","sankey","arc-diagram","dependency-wheel","series-label","series-on-point","solid-gauge","sonification","streamgraph","sunburst","variable-pie","variwide","vector","venn","windbarb","wordcloud","xrange","no-data-to-display","drag-panes","debugger","dumbbell","lollipop","cylinder","organization","dotplot","marker-clusters","hollowcandlestick","heikinashi","flowmap","export-data","navigator","textpath"],types:["string[]"],envLink:"HIGHCHARTS_MODULE_SCRIPTS",description:"Highcharts module scripts to fetch",promptOptions:{type:"multiselect",instructions:"Space: Select specific, A: Select all, Enter: Confirm"}},indicatorScripts:{value:["indicators-all"],types:["string[]"],envLink:"HIGHCHARTS_INDICATOR_SCRIPTS",description:"Highcharts indicator scripts to fetch",promptOptions:{type:"multiselect",instructions:"Space: Select specific, A: Select all, Enter: Confirm"}},customScripts:{value:["https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.30.1/moment.min.js","https://cdnjs.cloudflare.com/ajax/libs/moment-timezone/0.5.45/moment-timezone-with-data.min.js"],types:["string[]"],envLink:"HIGHCHARTS_CUSTOM_SCRIPTS",description:"Additional custom scripts or dependencies to fetch",promptOptions:{type:"list",separator:";"}}},export:{infile:{value:null,types:["string","null"],envLink:"EXPORT_INFILE",description:"Input filename with type, formatted correctly as JSON or SVG",promptOptions:{type:"text"}},instr:{value:null,types:["Object","string","null"],envLink:"EXPORT_INSTR",description:"Overrides the `infile` with JSON, stringified JSON, or SVG input",promptOptions:{type:"text"}},options:{value:null,types:["Object","string","null"],envLink:"EXPORT_OPTIONS",description:"Alias for the `instr` option",promptOptions:{type:"text"}},svg:{value:null,types:["string","null"],envLink:"EXPORT_SVG",description:"SVG string representation of the chart to render",promptOptions:{type:"text"}},batch:{value:null,types:["string","null"],envLink:"EXPORT_BATCH",description:'Batch job string with input/output pairs: "in=out;in=out;..."',promptOptions:{type:"text"}},outfile:{value:null,types:["string","null"],envLink:"EXPORT_OUTFILE",description:"Output filename with type. Can be jpeg, png, pdf, or svg and ignores `type` option",promptOptions:{type:"text"}},type:{value:"png",types:["string"],envLink:"EXPORT_TYPE",description:"File export format. Can be jpeg, png, pdf, or svg",promptOptions:{type:"select",hint:"Default: png",choices:["png","jpeg","pdf","svg"]}},constr:{value:"chart",types:["string"],envLink:"EXPORT_CONSTR",description:"Chart constructor. Can be chart, stockChart, mapChart, or ganttChart",promptOptions:{type:"select",hint:"Default: chart",choices:["chart","stockChart","mapChart","ganttChart"]}},b64:{value:!1,types:["boolean"],envLink:"EXPORT_B64",description:"Whether or not to the chart should be received in Base64 format instead of binary",promptOptions:{type:"toggle"}},noDownload:{value:!1,types:["boolean"],envLink:"EXPORT_NO_DOWNLOAD",description:"Whether or not to include or exclude attachment headers in the response",promptOptions:{type:"toggle"}},height:{value:null,types:["number","null"],envLink:"EXPORT_HEIGHT",description:"Height of the exported chart, overrides chart settings",promptOptions:{type:"number"}},width:{value:null,types:["number","null"],envLink:"EXPORT_WIDTH",description:"Width of the exported chart, overrides chart settings",promptOptions:{type:"number"}},scale:{value:null,types:["number","null"],envLink:"EXPORT_SCALE",description:"Scale of the exported chart, overrides chart settings. Ranges from 0.1 to 5.0",promptOptions:{type:"number"}},defaultHeight:{value:400,types:["number"],envLink:"EXPORT_DEFAULT_HEIGHT",description:"Default height of the exported chart if not set",promptOptions:{type:"number"}},defaultWidth:{value:600,types:["number"],envLink:"EXPORT_DEFAULT_WIDTH",description:"Default width of the exported chart if not set",promptOptions:{type:"number"}},defaultScale:{value:1,types:["number"],envLink:"EXPORT_DEFAULT_SCALE",description:"Default scale of the exported chart if not set. Ranges from 0.1 to 5.0",promptOptions:{type:"number",min:.1,max:5}},globalOptions:{value:null,types:["Object","string","null"],envLink:"EXPORT_GLOBAL_OPTIONS",description:"JSON, stringified JSON or filename with global options for Highcharts.setOptions",promptOptions:{type:"text"}},themeOptions:{value:null,types:["Object","string","null"],envLink:"EXPORT_THEME_OPTIONS",description:"JSON, stringified JSON or filename with theme options for Highcharts.setOptions",promptOptions:{type:"text"}},rasterizationTimeout:{value:1500,types:["number"],envLink:"EXPORT_RASTERIZATION_TIMEOUT",description:"Milliseconds to wait for webpage rendering",promptOptions:{type:"number"}}},customLogic:{allowCodeExecution:{value:!1,types:["boolean"],envLink:"CUSTOM_LOGIC_ALLOW_CODE_EXECUTION",description:"Allows or disallows execution of arbitrary code during exporting",promptOptions:{type:"toggle"}},allowFileResources:{value:!1,types:["boolean"],envLink:"CUSTOM_LOGIC_ALLOW_FILE_RESOURCES",description:"Allows or disallows injection of filesystem resources (disabled in server mode)",promptOptions:{type:"toggle"}},customCode:{value:null,types:["string","null"],envLink:"CUSTOM_LOGIC_CUSTOM_CODE",description:"Custom code to execute before chart initialization. Can be a function, code wrapped in a function, or a .js filename",promptOptions:{type:"text"}},callback:{value:null,types:["string","null"],envLink:"CUSTOM_LOGIC_CALLBACK",description:"JavaScript code to run during construction. Can be a function or a .js filename",promptOptions:{type:"text"}},resources:{value:null,types:["Object","string","null"],envLink:"CUSTOM_LOGIC_RESOURCES",description:"Additional resources as JSON, stringified JSON, or filename, containing files, js, and css sections",promptOptions:{type:"text"}},loadConfig:{value:null,types:["string","null"],envLink:"CUSTOM_LOGIC_LOAD_CONFIG",legacyName:"fromFile",description:"File with a pre-defined configuration to use",promptOptions:{type:"text"}},createConfig:{value:null,types:["string","null"],envLink:"CUSTOM_LOGIC_CREATE_CONFIG",description:"Prompt-based option setting, saved to a provided config file",promptOptions:{type:"text"}}},server:{enable:{value:!1,types:["boolean"],envLink:"SERVER_ENABLE",cliName:"enableServer",description:"Starts the server when true",promptOptions:{type:"toggle"}},host:{value:"0.0.0.0",types:["string"],envLink:"SERVER_HOST",description:"Hostname of the server",promptOptions:{type:"text"}},port:{value:7801,types:["number"],envLink:"SERVER_PORT",description:"Port number for the server",promptOptions:{type:"number"}},uploadLimit:{value:3,types:["number"],envLink:"SERVER_UPLOAD_LIMIT",description:"Maximum request body size in MB",promptOptions:{type:"number"}},benchmarking:{value:!1,types:["boolean"],envLink:"SERVER_BENCHMARKING",cliName:"serverBenchmarking",description:"Displays or not action durations in milliseconds during server requests",promptOptions:{type:"toggle"}},proxy:{host:{value:null,types:["string","null"],envLink:"SERVER_PROXY_HOST",cliName:"proxyHost",description:"Host of the proxy server, if applicable",promptOptions:{type:"text"}},port:{value:null,types:["number","null"],envLink:"SERVER_PROXY_PORT",cliName:"proxyPort",description:"Port of the proxy server, if applicable",promptOptions:{type:"number"}},timeout:{value:5e3,types:["number"],envLink:"SERVER_PROXY_TIMEOUT",cliName:"proxyTimeout",description:"Timeout in milliseconds for the proxy server, if applicable",promptOptions:{type:"number"}}},rateLimiting:{enable:{value:!1,types:["boolean"],envLink:"SERVER_RATE_LIMITING_ENABLE",cliName:"enableRateLimiting",description:"Enables or disables rate limiting on the server",promptOptions:{type:"toggle"}},maxRequests:{value:10,types:["number"],envLink:"SERVER_RATE_LIMITING_MAX_REQUESTS",legacyName:"rateLimit",description:"Maximum number of requests allowed per minute",promptOptions:{type:"number"}},window:{value:1,types:["number"],envLink:"SERVER_RATE_LIMITING_WINDOW",description:"Time window in minutes for rate limiting",promptOptions:{type:"number"}},delay:{value:0,types:["number"],envLink:"SERVER_RATE_LIMITING_DELAY",description:"Delay duration between successive requests before reaching the limit",promptOptions:{type:"number"}},trustProxy:{value:!1,types:["boolean"],envLink:"SERVER_RATE_LIMITING_TRUST_PROXY",description:"Set to true if the server is behind a load balancer",promptOptions:{type:"toggle"}},skipKey:{value:null,types:["string","null"],envLink:"SERVER_RATE_LIMITING_SKIP_KEY",description:"Key to bypass the rate limiter, used with `skipToken`",promptOptions:{type:"text"}},skipToken:{value:null,types:["string","null"],envLink:"SERVER_RATE_LIMITING_SKIP_TOKEN",description:"Token to bypass the rate limiter, used with `skipKey`",promptOptions:{type:"text"}}},ssl:{enable:{value:!1,types:["boolean"],envLink:"SERVER_SSL_ENABLE",cliName:"enableSsl",description:"Enables or disables SSL protocol",promptOptions:{type:"toggle"}},force:{value:!1,types:["boolean"],envLink:"SERVER_SSL_FORCE",cliName:"sslForce",legacyName:"sslOnly",description:"Forces the server to use HTTPS only when true",promptOptions:{type:"toggle"}},port:{value:443,types:["number"],envLink:"SERVER_SSL_PORT",cliName:"sslPort",description:"Port for the SSL server",promptOptions:{type:"number"}},certPath:{value:null,types:["string","null"],envLink:"SERVER_SSL_CERT_PATH",cliName:"sslCertPath",legacyName:"sslPath",description:"Path to the SSL certificate/key file",promptOptions:{type:"text"}}}},pool:{minWorkers:{value:4,types:["number"],envLink:"POOL_MIN_WORKERS",description:"Minimum and initial number of pool workers to spawn",promptOptions:{type:"number"}},maxWorkers:{value:8,types:["number"],envLink:"POOL_MAX_WORKERS",legacyName:"workers",description:"Maximum number of pool workers to spawn",promptOptions:{type:"number"}},workLimit:{value:40,types:["number"],envLink:"POOL_WORK_LIMIT",description:"Number of tasks a worker can handle before restarting",promptOptions:{type:"number"}},acquireTimeout:{value:5e3,types:["number"],envLink:"POOL_ACQUIRE_TIMEOUT",description:"Timeout in milliseconds for acquiring a resource",promptOptions:{type:"number"}},createTimeout:{value:5e3,types:["number"],envLink:"POOL_CREATE_TIMEOUT",description:"Timeout in milliseconds for creating a resource",promptOptions:{type:"number"}},destroyTimeout:{value:5e3,types:["number"],envLink:"POOL_DESTROY_TIMEOUT",description:"Timeout in milliseconds for destroying a resource",promptOptions:{type:"number"}},idleTimeout:{value:3e4,types:["number"],envLink:"POOL_IDLE_TIMEOUT",description:"Timeout in milliseconds for destroying idle resources",promptOptions:{type:"number"}},createRetryInterval:{value:200,types:["number"],envLink:"POOL_CREATE_RETRY_INTERVAL",description:"Interval in milliseconds before retrying resource creation on failure",promptOptions:{type:"number"}},reaperInterval:{value:1e3,types:["number"],envLink:"POOL_REAPER_INTERVAL",description:"Interval in milliseconds to check and destroy idle resources",promptOptions:{type:"number"}},benchmarking:{value:!1,types:["boolean"],envLink:"POOL_BENCHMARKING",cliName:"poolBenchmarking",description:"Shows statistics for the pool of resources",promptOptions:{type:"toggle"}}},logging:{level:{value:4,types:["number"],envLink:"LOGGING_LEVEL",cliName:"logLevel",description:"Logging verbosity level",promptOptions:{type:"number",round:0,min:0,max:5}},file:{value:"highcharts-export-server.log",types:["string"],envLink:"LOGGING_FILE",cliName:"logFile",description:"Log file name. Requires `logToFile` and `logDest` to be set",promptOptions:{type:"text"}},dest:{value:"log",types:["string"],envLink:"LOGGING_DEST",cliName:"logDest",description:"Path to store log files. Requires `logToFile` to be set",promptOptions:{type:"text"}},toConsole:{value:!0,types:["boolean"],envLink:"LOGGING_TO_CONSOLE",cliName:"logToConsole",description:"Enables or disables console logging",promptOptions:{type:"toggle"}},toFile:{value:!0,types:["boolean"],envLink:"LOGGING_TO_FILE",cliName:"logToFile",description:"Enables or disables logging to a file",promptOptions:{type:"toggle"}}},ui:{enable:{value:!1,types:["boolean"],envLink:"UI_ENABLE",cliName:"enableUi",description:"Enables or disables the UI for the export server",promptOptions:{type:"toggle"}},route:{value:"/",types:["string"],envLink:"UI_ROUTE",cliName:"uiRoute",description:"The endpoint route for the UI",promptOptions:{type:"text"}}},other:{nodeEnv:{value:"production",types:["string"],envLink:"OTHER_NODE_ENV",description:"The Node.js environment type",promptOptions:{type:"text"}},listenToProcessExits:{value:!0,types:["boolean"],envLink:"OTHER_LISTEN_TO_PROCESS_EXITS",description:"Whether or not to attach process.exit handlers",promptOptions:{type:"toggle"}},noLogo:{value:!1,types:["boolean"],envLink:"OTHER_NO_LOGO",description:"Display or skip printing the logo on startup",promptOptions:{type:"toggle"}},hardResetPage:{value:!1,types:["boolean"],envLink:"OTHER_HARD_RESET_PAGE",description:"Whether or not to reset the page content entirely",promptOptions:{type:"toggle"}},browserShellMode:{value:!0,types:["boolean"],envLink:"OTHER_BROWSER_SHELL_MODE",description:"Whether or not to set the browser to run in shell mode",promptOptions:{type:"toggle"}},validation:{value:!0,types:["boolean"],envLink:"OTHER_VALIDATION",description:"Whether or not to enable validation of options types",promptOptions:{type:"toggle"}}},debug:{enable:{value:!1,types:["boolean"],envLink:"DEBUG_ENABLE",cliName:"enableDebug",description:"Enables or disables debug mode for the underlying browser",promptOptions:{type:"toggle"}},headless:{value:!1,types:["boolean"],envLink:"DEBUG_HEADLESS",description:"Whether or not to set the browser to run in headless mode during debugging",promptOptions:{type:"toggle"}},devtools:{value:!1,types:["boolean"],envLink:"DEBUG_DEVTOOLS",description:"Enables or disables DevTools in headful mode",promptOptions:{type:"toggle"}},listenToConsole:{value:!1,types:["boolean"],envLink:"DEBUG_LISTEN_TO_CONSOLE",description:"Enables or disables listening to console messages from the browser",promptOptions:{type:"toggle"}},dumpio:{value:!1,types:["boolean"],envLink:"DEBUG_DUMPIO",description:"Redirects or not browser stdout and stderr to process.stdout and process.stderr",promptOptions:{type:"toggle"}},slowMo:{value:0,types:["number"],envLink:"DEBUG_SLOW_MO",description:"Delays Puppeteer operations by the specified milliseconds",promptOptions:{type:"number"}},debuggingPort:{value:9222,types:["number"],envLink:"DEBUG_DEBUGGING_PORT",description:"Port used for debugging",promptOptions:{type:"number"}}}},nestedProps=_createNestedProps(defaultConfig),absoluteProps=_createAbsoluteProps(defaultConfig);function _createNestedProps(e,t={},o=""){return Object.keys(e).forEach((r=>{const n=e[r];void 0===n.value?_createNestedProps(n,t,`${o}.${r}`):(t[n.cliName||r]=`${o}.${r}`.substring(1),void 0!==n.legacyName&&(t[n.legacyName]=`${o}.${r}`.substring(1)))})),t}function _createAbsoluteProps(e,t=[]){return Object.keys(e).forEach((o=>{const r=e[o];void 0===r.types?_createAbsoluteProps(r,t):r.types.includes("Object")&&t.push(o)})),t}dotenv.config();const{coreScripts:coreScripts,moduleScripts:moduleScripts,indicatorScripts:indicatorScripts}=defaultConfig.highcharts;zod.z.setErrorMap(_customErrorMap);const v={boolean:e=>e?zod.z.boolean():zod.z.union([zod.z.enum(["true","1","false","0","undefined","null",""]).transform((e=>["undefined","null",""].includes(e)?null:"true"===e||"1"===e)),zod.z.boolean()]).nullable(),string:e=>e?zod.z.string().trim().refine((e=>!["false","undefined","null",""].includes(e)),{params:{errorMessage:"The string contains a forbidden value"}}):zod.z.string().trim().transform((e=>["false","undefined","null",""].includes(e)?null:e)).nullable(),enum:(e,t)=>t?zod.z.enum([...e]):zod.z.enum([...e,"undefined","null",""]).transform((e=>["undefined","null",""].includes(e)?null:e)).nullable(),stringArray(e,t,o){const r=zod.z.string().trim().array(),n=zod.z.string().trim().transform((e=>(e.startsWith("[")&&(e=e.slice(1)),e.endsWith("]")&&(e=e.slice(0,-1)),e.split(t)))),i=t=>t.map((e=>e.trim())).filter(e);return o?r.transform(i):zod.z.union([n,r]).transform(i).transform((e=>e.length?e:null)).nullable()},positiveNum:e=>e?zod.z.number().positive():zod.z.union([zod.z.string().trim().refine((e=>!isNaN(Number(e))&&Number(e)>0||["undefined","null",""].includes(e)),{params:{errorMessage:"The value must be numeric and positive"}}).transform((e=>["undefined","null",""].includes(e)?null:Number(e))),zod.z.number().positive()]).nullable(),nonNegativeNum:e=>e?zod.z.number().nonnegative():zod.z.union([zod.z.string().trim().refine((e=>!isNaN(Number(e))&&Number(e)>=0||["undefined","null",""].includes(e)),{params:{errorMessage:"The value must be numeric and non-negative"}}).transform((e=>["undefined","null",""].includes(e)?null:Number(e))),zod.z.number().nonnegative()]).nullable(),startsWith:(e,t)=>t?zod.z.string().trim().refine((t=>e.some((e=>t.startsWith(e)))),{params:{errorMessage:`The value must be a string that starts with ${e.join(", ")}`}}):zod.z.string().trim().refine((t=>e.some((e=>t.startsWith(e)))||["undefined","null",""].includes(t)),{params:{errorMessage:`The value must be a string that starts with ${e.join(", ")}`}}).transform((e=>["undefined","null",""].includes(e)?null:e)).nullable(),chartConfig:()=>zod.z.union([zod.z.string().trim().refine((e=>e.startsWith("{")&&e.endsWith("}")||["undefined","null",""].includes(e)),{params:{errorMessage:"The value must be a string that starts with '{' and ends with '}'"}}).transform((e=>["undefined","null",""].includes(e)?null:e)),zod.z.object({}).passthrough()]).nullable(),additionalOptions:()=>zod.z.union([zod.z.string().trim().refine((e=>e.length>=6&&e.endsWith(".json")||e.startsWith("{")&&e.endsWith("}")||["undefined","null",""].includes(e)),{params:{errorMessage:"The value must be a string that ends with '.json' or starts with '{' and ends with '}'"}}).transform((e=>["undefined","null",""].includes(e)?null:e)),zod.z.object({}).passthrough()]).nullable()},validators={args:e=>v.stringArray((e=>!["false","undefined","null",""].includes(e)),";",e),version:e=>e?zod.z.string().trim().refine((e=>/^(latest|\d{1,2}(\.\d{1,2}){0,2})$/.test(e)),{params:{errorMessage:"The value must be 'latest', a major version, or in the form XX.YY.ZZ"}}):zod.z.string().trim().refine((e=>/^(latest|\d{1,2}(\.\d{1,2}){0,2})$/.test(e)||["undefined","null",""].includes(e)),{params:{errorMessage:"The value must be 'latest', a major version, or in the form XX.YY.ZZ"}}).transform((e=>["undefined","null",""].includes(e)?null:e)).nullable(),cdnUrl:e=>v.startsWith(["http://","https://"],e),forceFetch:e=>v.boolean(e),cachePath:e=>v.string(e),adminToken:e=>v.string(e),coreScripts:e=>v.stringArray((e=>coreScripts.value.includes(e)),",",e),moduleScripts:e=>v.stringArray((e=>moduleScripts.value.includes(e)),",",e),indicatorScripts:e=>v.stringArray((e=>indicatorScripts.value.includes(e)),",",e),customScripts:e=>v.stringArray((e=>e.startsWith("https://")||e.startsWith("http://")),",",e),infile:e=>e?zod.z.string().trim().refine((e=>e.length>=6&&e.endsWith(".json")||e.length>=5&&e.endsWith(".svg")),{params:{errorMessage:"The value must be a string that ends with .json or .svg"}}).nullable():zod.z.string().trim().refine((e=>e.length>=6&&e.endsWith(".json")||e.length>=5&&e.endsWith(".svg")||["undefined","null",""].includes(e)),{params:{errorMessage:"The value must be a string that ends with .json or .svg"}}).transform((e=>["undefined","null",""].includes(e)?null:e)).nullable(),instr:()=>v.chartConfig(),options:()=>v.chartConfig(),svg:()=>zod.z.string().trim().refine((e=>e.indexOf("=0||e.indexOf("=0||["false","undefined","null",""].includes(e)),{params:{errorMessage:"The value must be a string that contains '["false","undefined","null",""].includes(e)?null:e)).nullable(),outfile:e=>e?zod.z.string().trim().refine((e=>e.length>=6&&e.endsWith(".jpeg")||e.length>=5&&(e.endsWith(".jpg")||e.endsWith(".png")||e.endsWith(".pdf")||e.endsWith(".svg"))),{params:{errorMessage:"The value must be a string that ends with .jpeg, .jpg, .png, .pdf, or .svg"}}).nullable():zod.z.string().trim().refine((e=>e.length>=6&&e.endsWith(".jpeg")||e.length>=5&&(e.endsWith(".jpg")||e.endsWith(".png")||e.endsWith(".pdf")||e.endsWith(".svg"))||["undefined","null",""].includes(e)),{params:{errorMessage:"The value must be a string that ends with .jpeg, .jpg, .png, .pdf, or .svg"}}).transform((e=>["undefined","null",""].includes(e)?null:e)).nullable(),type:e=>v.enum(["jpeg","jpg","png","pdf","svg"],e),constr:e=>v.enum(["chart","stockChart","mapChart","ganttChart"],e),b64:e=>v.boolean(e),noDownload:e=>v.boolean(e),defaultHeight:e=>v.positiveNum(e),defaultWidth:e=>v.positiveNum(e),defaultScale:e=>e?zod.z.number().gte(.1).lte(5):zod.z.union([zod.z.string().trim().refine((e=>!isNaN(Number(e))&&!0!==e&&!e.startsWith("[")&&Number(e)>=.1&&Number(e)<=5||["undefined","null",""].includes(e)),{params:{errorMessage:"The value must be within a 0.1 and 5.0 range"}}).transform((e=>["undefined","null",""].includes(e)?null:Number(e))),zod.z.number().gte(.1).lte(5)]).nullable(),height(e){return this.defaultHeight(e).nullable()},width(e){return this.defaultWidth(e).nullable()},scale(e){return this.defaultScale(e).nullable()},globalOptions:()=>v.additionalOptions(),themeOptions:()=>v.additionalOptions(),batch:e=>v.string(e),rasterizationTimeout:e=>v.nonNegativeNum(e),allowCodeExecution:e=>v.boolean(e),allowFileResources:e=>v.boolean(e),customCode:e=>v.string(e),callback:e=>v.string(e),resources(e){const t=zod.z.object({js:v.string(!1),css:v.string(!1),files:v.stringArray((e=>!["undefined","null",""].includes(e)),",",!0).nullable()}).partial(),o=zod.z.string().trim().refine((e=>e.startsWith("{")&&e.endsWith("}")||e.length>=6&&e.endsWith(".json")),{params:{errorMessage:"The value must be a string that starts with '{' and ends with '}"}}),r=zod.z.string().trim().refine((e=>e.startsWith("{")&&e.endsWith("}")||e.length>=6&&e.endsWith(".json")||["undefined","null",""].includes(e)),{params:{errorMessage:"The value must be a string that ends with .json"}}).transform((e=>["undefined","null",""].includes(e)?null:e));return e?zod.z.union([t,o]).nullable():zod.z.union([t,r]).nullable()},loadConfig:e=>v.string(e).refine((e=>null===e||e.length>=6&&e.endsWith(".json")),{params:{errorMessage:"The value must be a string that ends with .json"}}),createConfig(e){return this.loadConfig(e)},enableServer:e=>v.boolean(e),host:e=>v.string(e),port:e=>v.nonNegativeNum(e),uploadLimit:e=>v.positiveNum(e),serverBenchmarking:e=>v.boolean(e),proxyHost:e=>v.string(e),proxyPort:e=>v.nonNegativeNum(e).nullable(),proxyTimeout:e=>v.nonNegativeNum(e),enableRateLimiting:e=>v.boolean(e),maxRequests:e=>v.nonNegativeNum(e),window:e=>v.nonNegativeNum(e),delay:e=>v.nonNegativeNum(e),trustProxy:e=>v.boolean(e),skipKey:e=>v.string(e),skipToken:e=>v.string(e),enableSsl:e=>v.boolean(e),sslForce:e=>v.boolean(e),sslPort:e=>v.nonNegativeNum(e),sslCertPath:e=>v.string(e),minWorkers:e=>v.positiveNum(e),maxWorkers:e=>v.positiveNum(e),workLimit:e=>v.positiveNum(e),acquireTimeout:e=>v.nonNegativeNum(e),createTimeout:e=>v.nonNegativeNum(e),destroyTimeout:e=>v.nonNegativeNum(e),idleTimeout:e=>v.nonNegativeNum(e),createRetryInterval:e=>v.nonNegativeNum(e),reaperInterval:e=>v.nonNegativeNum(e),poolBenchmarking:e=>v.boolean(e),resourcesInterval:e=>v.nonNegativeNum(e),logLevel:e=>e?zod.z.number().int().gte(0).lte(5):zod.z.union([zod.z.string().trim().refine((e=>!isNaN(Number(e))&&!0!==e&&!e.startsWith("[")&&Number.isInteger(Number(e))&&Number(e)>=0&&Number(e)<=5||["undefined","null",""].includes(e)),{params:{errorMessage:"The value must be within a 0 and 5 range"}}).transform((e=>["undefined","null",""].includes(e)?null:Number(e))),zod.z.number().int().gte(0).lte(5)]).nullable(),logFile:e=>v.string(e).refine((e=>null===e||e.length>=5&&e.endsWith(".log")),{params:{errorMessage:"The value must be a string that ends with .log"}}),logDest:e=>v.string(e),logToConsole:e=>v.boolean(e),logToFile:e=>v.boolean(e),enableUi:e=>v.boolean(e),uiRoute:e=>v.startsWith(["/"],e),nodeEnv:e=>v.enum(["development","production","test"],e),listenToProcessExits:e=>v.boolean(e),noLogo:e=>v.boolean(e),hardResetPage:e=>v.boolean(e),browserShellMode:e=>v.boolean(e),validation:e=>v.boolean(e),enableDebug:e=>v.boolean(e),headless:e=>v.boolean(e),devtools:e=>v.boolean(e),listenToConsole:e=>v.boolean(e),dumpio:e=>v.boolean(e),slowMo:e=>v.nonNegativeNum(e),debuggingPort:e=>v.nonNegativeNum(e),requestId:()=>zod.z.string().uuid({message:"The value must be a stringified UUID"}).nullable()},PuppeteerSchema=e=>zod.z.object({args:validators.args(e)}).partial(),HighchartsSchema=e=>zod.z.object({version:validators.version(e),cdnUrl:validators.cdnUrl(e),forceFetch:validators.forceFetch(e),cachePath:validators.cachePath(e),coreScripts:validators.coreScripts(e),moduleScripts:validators.moduleScripts(e),indicatorScripts:validators.indicatorScripts(e),customScripts:validators.customScripts(e)}).partial(),ExportSchema=e=>zod.z.object({infile:validators.infile(e),instr:validators.instr(),options:validators.options(),svg:validators.svg(),outfile:validators.outfile(e),type:validators.type(e),constr:validators.constr(e),b64:validators.b64(e),noDownload:validators.noDownload(e),defaultHeight:validators.defaultHeight(e),defaultWidth:validators.defaultWidth(e),defaultScale:validators.defaultScale(e),height:validators.height(e),width:validators.width(e),scale:validators.scale(e),globalOptions:validators.globalOptions(),themeOptions:validators.themeOptions(),batch:validators.batch(!1),rasterizationTimeout:validators.rasterizationTimeout(e)}).partial(),CustomLogicSchema=e=>zod.z.object({allowCodeExecution:validators.allowCodeExecution(e),allowFileResources:validators.allowFileResources(e),customCode:validators.customCode(!1),callback:validators.callback(!1),resources:validators.resources(e),loadConfig:validators.loadConfig(!1),createConfig:validators.createConfig(!1)}).partial(),ProxySchema=e=>zod.z.object({host:validators.proxyHost(!1),port:validators.proxyPort(e),timeout:validators.proxyTimeout(e)}).partial(),RateLimitingSchema=e=>zod.z.object({enable:validators.enableRateLimiting(e),maxRequests:validators.maxRequests(e),window:validators.window(e),delay:validators.delay(e),trustProxy:validators.trustProxy(e),skipKey:validators.skipKey(!1),skipToken:validators.skipToken(!1)}).partial(),SslSchema=e=>zod.z.object({enable:validators.enableSsl(e),force:validators.sslForce(e),port:validators.sslPort(e),certPath:validators.sslCertPath(!1)}).partial(),ServerSchema=e=>zod.z.object({enable:validators.enableServer(e).optional(),host:validators.host(e).optional(),port:validators.port(e).optional(),uploadLimit:validators.uploadLimit(e).optional(),benchmarking:validators.serverBenchmarking(e).optional(),proxy:ProxySchema(e).optional(),rateLimiting:RateLimitingSchema(e).optional(),ssl:SslSchema(e).optional()}),PoolSchema=e=>zod.z.object({minWorkers:validators.minWorkers(e),maxWorkers:validators.maxWorkers(e),workLimit:validators.workLimit(e),acquireTimeout:validators.acquireTimeout(e),createTimeout:validators.createTimeout(e),destroyTimeout:validators.destroyTimeout(e),idleTimeout:validators.idleTimeout(e),createRetryInterval:validators.createRetryInterval(e),reaperInterval:validators.reaperInterval(e),benchmarking:validators.poolBenchmarking(e)}).partial(),LoggingSchema=e=>zod.z.object({level:validators.logLevel(e),file:validators.logFile(e),dest:validators.logDest(e),toConsole:validators.logToConsole(e),toFile:validators.logToFile(e)}).partial(),UiSchema=e=>zod.z.object({enable:validators.enableUi(e),route:validators.uiRoute(e)}).partial(),OtherSchema=e=>zod.z.object({nodeEnv:validators.nodeEnv(e),listenToProcessExits:validators.listenToProcessExits(e),noLogo:validators.noLogo(e),hardResetPage:validators.hardResetPage(e),browserShellMode:validators.browserShellMode(e),validation:validators.validation(e)}).partial(),DebugSchema=e=>zod.z.object({enable:validators.enableDebug(e),headless:validators.headless(e),devtools:validators.devtools(e),listenToConsole:validators.listenToConsole(e),dumpio:validators.dumpio(e),slowMo:validators.slowMo(e),debuggingPort:validators.debuggingPort(e)}).partial(),StrictConfigSchema=zod.z.object({requestId:validators.requestId(),puppeteer:PuppeteerSchema(!0),highcharts:HighchartsSchema(!0),export:ExportSchema(!0),customLogic:CustomLogicSchema(!0),server:ServerSchema(!0),pool:PoolSchema(!0),logging:LoggingSchema(!0),ui:UiSchema(!0),other:OtherSchema(!0),debug:DebugSchema(!0)}),LooseConfigSchema=zod.z.object({requestId:validators.requestId(),puppeteer:PuppeteerSchema(!1),highcharts:HighchartsSchema(!1),export:ExportSchema(!1),customLogic:CustomLogicSchema(!1),server:ServerSchema(!1),pool:PoolSchema(!1),logging:LoggingSchema(!1),ui:UiSchema(!1),other:OtherSchema(!1),debug:DebugSchema(!1)}),EnvSchema=zod.z.object({PUPPETEER_ARGS:validators.args(!1),HIGHCHARTS_VERSION:validators.version(!1),HIGHCHARTS_CDN_URL:validators.cdnUrl(!1),HIGHCHARTS_FORCE_FETCH:validators.forceFetch(!1),HIGHCHARTS_CACHE_PATH:validators.cachePath(!1),HIGHCHARTS_ADMIN_TOKEN:validators.adminToken(!1),HIGHCHARTS_CORE_SCRIPTS:validators.coreScripts(!1),HIGHCHARTS_MODULE_SCRIPTS:validators.moduleScripts(!1),HIGHCHARTS_INDICATOR_SCRIPTS:validators.indicatorScripts(!1),HIGHCHARTS_CUSTOM_SCRIPTS:validators.customScripts(!1),EXPORT_INFILE:validators.infile(!1),EXPORT_INSTR:validators.instr(),EXPORT_OPTIONS:validators.options(),EXPORT_SVG:validators.svg(),EXPORT_BATCH:validators.batch(!1),EXPORT_OUTFILE:validators.outfile(!1),EXPORT_TYPE:validators.type(!1),EXPORT_CONSTR:validators.constr(!1),EXPORT_B64:validators.b64(!1),EXPORT_NO_DOWNLOAD:validators.noDownload(!1),EXPORT_HEIGHT:validators.height(!1),EXPORT_WIDTH:validators.width(!1),EXPORT_SCALE:validators.scale(!1),EXPORT_DEFAULT_HEIGHT:validators.defaultHeight(!1),EXPORT_DEFAULT_WIDTH:validators.defaultWidth(!1),EXPORT_DEFAULT_SCALE:validators.defaultScale(!1),EXPORT_GLOBAL_OPTIONS:validators.globalOptions(),EXPORT_THEME_OPTIONS:validators.themeOptions(),EXPORT_RASTERIZATION_TIMEOUT:validators.rasterizationTimeout(!1),CUSTOM_LOGIC_ALLOW_CODE_EXECUTION:validators.allowCodeExecution(!1),CUSTOM_LOGIC_ALLOW_FILE_RESOURCES:validators.allowFileResources(!1),CUSTOM_LOGIC_CUSTOM_CODE:validators.customCode(!1),CUSTOM_LOGIC_CALLBACK:validators.callback(!1),CUSTOM_LOGIC_RESOURCES:validators.resources(!1),CUSTOM_LOGIC_LOAD_CONFIG:validators.loadConfig(!1),CUSTOM_LOGIC_CREATE_CONFIG:validators.createConfig(!1),SERVER_ENABLE:validators.enableServer(!1),SERVER_HOST:validators.host(!1),SERVER_PORT:validators.port(!1),SERVER_UPLOAD_LIMIT:validators.uploadLimit(!1),SERVER_BENCHMARKING:validators.serverBenchmarking(!1),SERVER_PROXY_HOST:validators.proxyHost(!1),SERVER_PROXY_PORT:validators.proxyPort(!1),SERVER_PROXY_TIMEOUT:validators.proxyTimeout(!1),SERVER_RATE_LIMITING_ENABLE:validators.enableRateLimiting(!1),SERVER_RATE_LIMITING_MAX_REQUESTS:validators.maxRequests(!1),SERVER_RATE_LIMITING_WINDOW:validators.window(!1),SERVER_RATE_LIMITING_DELAY:validators.delay(!1),SERVER_RATE_LIMITING_TRUST_PROXY:validators.trustProxy(!1),SERVER_RATE_LIMITING_SKIP_KEY:validators.skipKey(!1),SERVER_RATE_LIMITING_SKIP_TOKEN:validators.skipToken(!1),SERVER_SSL_ENABLE:validators.enableSsl(!1),SERVER_SSL_FORCE:validators.sslForce(!1),SERVER_SSL_PORT:validators.sslPort(!1),SERVER_SSL_CERT_PATH:validators.sslCertPath(!1),POOL_MIN_WORKERS:validators.minWorkers(!1),POOL_MAX_WORKERS:validators.maxWorkers(!1),POOL_WORK_LIMIT:validators.workLimit(!1),POOL_ACQUIRE_TIMEOUT:validators.acquireTimeout(!1),POOL_CREATE_TIMEOUT:validators.createTimeout(!1),POOL_DESTROY_TIMEOUT:validators.destroyTimeout(!1),POOL_IDLE_TIMEOUT:validators.idleTimeout(!1),POOL_CREATE_RETRY_INTERVAL:validators.createRetryInterval(!1),POOL_REAPER_INTERVAL:validators.reaperInterval(!1),POOL_BENCHMARKING:validators.poolBenchmarking(!1),LOGGING_LEVEL:validators.logLevel(!1),LOGGING_FILE:validators.logFile(!1),LOGGING_DEST:validators.logDest(!1),LOGGING_TO_CONSOLE:validators.logToConsole(!1),LOGGING_TO_FILE:validators.logToFile(!1),UI_ENABLE:validators.enableUi(!1),UI_ROUTE:validators.uiRoute(!1),OTHER_NODE_ENV:validators.nodeEnv(!1),OTHER_LISTEN_TO_PROCESS_EXITS:validators.listenToProcessExits(!1),OTHER_NO_LOGO:validators.noLogo(!1),OTHER_HARD_RESET_PAGE:validators.hardResetPage(!1),OTHER_BROWSER_SHELL_MODE:validators.browserShellMode(!1),OTHER_VALIDATION:validators.validation(!1),DEBUG_ENABLE:validators.enableDebug(!1),DEBUG_HEADLESS:validators.headless(!1),DEBUG_DEVTOOLS:validators.devtools(!1),DEBUG_LISTEN_TO_CONSOLE:validators.listenToConsole(!1),DEBUG_DUMPIO:validators.dumpio(!1),DEBUG_SLOW_MO:validators.slowMo(!1),DEBUG_DEBUGGING_PORT:validators.debuggingPort(!1)}),envs=EnvSchema.partial().parse(process.env);function strictValidate(e){return StrictConfigSchema.partial().parse(e)}function looseValidate(e){return LooseConfigSchema.partial().parse(e)}function _customErrorMap(e,t){const o=e.path.join("."),r=`Invalid value for the ${o}`;if(e.code===zod.z.ZodIssueCode.invalid_type)return e.received===zod.z.ZodParsedType.undefined?{message:`${r} - No value was provided.`}:{message:`${r} - Invalid type. ${t.defaultError}.`};if(e.code===zod.z.ZodIssueCode.custom&&e.params?.errorMessage)return{message:`${r} - ${e.params?.errorMessage}, received '${t.data}'.`};if(e.code===zod.z.ZodIssueCode.invalid_union){let t=`Multiple errors occurred for the ${o}:\n`;return e.unionErrors.forEach((e=>{const o=e.issues[0].message.indexOf("-");t+=-1!==o?`${e.issues[0].message}\n`.substring(o):`${e.issues[0].message}\n`})),{message:t}}return{message:`${r} - ${t.defaultError}.`}}class ExportError extends Error{constructor(e,t){super(),this.message=e,this.stackMessage=e,t&&(this.statusCode=t)}setStatus(e){return this.statusCode=e,this}setError(e){return this.error=e,e.name&&(this.name=e.name),e.statusCode&&(this.statusCode=e.statusCode),e.stack&&(this.stackMessage=e.message,this.stack=e.stack),this}}const globalOptions=_initOptions(defaultConfig);function getOptions(e=!0){return e?deepCopy(globalOptions):globalOptions}function updateOptions(e,t=!1,o=!0){return _mergeOptions(getOptions(t),validateOptions(e,o))}function mapToNewOptions(e){const t={};if(isObject(e))for(const[o,r]of Object.entries(e)){const e=nestedProps[o]?nestedProps[o].split("."):[];e.reduce(((t,o,n)=>t[o]=e.length-1===n?r:t[o]||{}),t)}else log(2,"[config] No correct object with options was provided. Returning an empty array.");return t}function validateOption(e,t,o=!0){if(!getOptions().other.validation)return t;try{return validators[e](o).parse(t)}catch(t){throw logZodIssues(1,t.issues,`[validation] The ${e} option validation error`),new ExportError(`[validation] The ${e} option validation error`,400)}}function validateOptions(e,t=!0){if(!getOptions().other.validation)return e;try{return t?strictValidate(e):looseValidate(e)}catch(e){throw logZodIssues(1,e.issues,"[validation] Options validation error"),new ExportError("[validation] Options validation error",400)}}function isAllowedConfig(config,toString=!1,allowFunctions=!1){try{if(!isObject(config)&&"string"!=typeof config)return null;const objectConfig="string"==typeof config?allowFunctions?eval(`(${config})`):JSON.parse(config):config,stringifiedOptions=_optionsStringify(objectConfig,allowFunctions,!1),parsedOptions=allowFunctions?JSON.parse(_optionsStringify(objectConfig,allowFunctions,!0),((_,value)=>"string"==typeof value&&value.startsWith("function")?eval(`(${value})`):value)):JSON.parse(stringifiedOptions);return toString?stringifiedOptions:parsedOptions}catch(e){return null}}function _initOptions(e){const t={};for(const[o,r]of Object.entries(e))Object.prototype.hasOwnProperty.call(r,"value")?void 0!==envs[r.envLink]&&null!==envs[r.envLink]?t[o]=envs[r.envLink]:t[o]=r.value:t[o]=_initOptions(r);return t}function _mergeOptions(e,t){if(isObject(e)&&isObject(t))for(const[o,r]of Object.entries(t))e[o]=isObject(r)&&!absoluteProps.includes(o)&&void 0!==e[o]?_mergeOptions(e[o],r):void 0!==r?r:e[o]||null;return e}function _optionsStringify(e,t,o){return JSON.stringify(e,((e,r)=>{if("string"==typeof r&&(r=r.trim()),"function"==typeof r||"string"==typeof r&&r.startsWith("function")&&r.endsWith("}")){if(t)return o?`"EXP_FUN${(r+"").replaceAll(/\s+/g," ")}EXP_FUN"`:`EXP_FUN${(r+"").replaceAll(/\s+/g," ")}EXP_FUN`;throw new Error}return r})).replaceAll(o?/\\"EXP_FUN|EXP_FUN\\"/g:/"EXP_FUN|EXP_FUN"/g,"")}async function fetch(e,t={}){return new Promise(((o,r)=>{_getProtocolModule(e).get(e,t,(e=>{let t="";e.on("data",(e=>{t+=e})),e.on("end",(()=>{t||r("Nothing was fetched from the URL."),e.text=t,o(e)}))})).on("error",(e=>{r(e)}))}))}function _getProtocolModule(e){return e.startsWith("https")?https:http}const cache={cdnUrl:"https://code.highcharts.com",activeManifest:{},sources:"",hcVersion:""};async function checkAndUpdateCache(e,t){try{let o;const r=getCachePath(),n=path.join(r,"manifest.json"),i=path.join(r,"sources.js");if(!fs.existsSync(r)&&fs.mkdirSync(r,{recursive:!0}),!fs.existsSync(n)||e.forceFetch)log(3,"[cache] Fetching and caching Highcharts dependencies."),o=await _updateCache(e,t,i);else{let r=!1;const s=JSON.parse(fs.readFileSync(n),"utf8");if(s.modules&&Array.isArray(s.modules)){const e={};s.modules.forEach((t=>e[t]=1)),s.modules=e}const{coreScripts:a,moduleScripts:l,indicatorScripts:c}=e,p=a.length+l.length+c.length;s.version!==e.version?(log(2,"[cache] A Highcharts version mismatch in the cache, need to re-fetch."),r=!0):Object.keys(s.modules||{}).length!==p?(log(2,"[cache] The cache and the requested modules do not match, need to re-fetch."),r=!0):r=(l||[]).some((e=>{if(!s.modules[e])return log(2,`[cache] The ${e} is missing in the cache, need to re-fetch.`),!0})),r?o=await _updateCache(e,t,i):(log(3,"[cache] Dependency cache is up to date, proceeding."),cache.sources=fs.readFileSync(i,"utf8"),o=s.modules,cache.hcVersion=extractVersion(cache.sources))}await _saveConfigToManifest(e,o)}catch(e){throw new ExportError("[cache] Could not configure cache and create or update the config manifest.",500).setError(e)}}function getHighchartsVersion(){return cache.hcVersion}async function updateHighchartsVersion(e){const t=updateOptions({highcharts:{version:e}});await checkAndUpdateCache(t.highcharts,t.server.proxy)}function extractVersion(e){return e.substring(0,e.indexOf("*/")).replace("/*","").replace("*/","").replace(/\n/g,"").trim()}function extractModuleName(e){return e.replace(/(.*)\/|(.*)modules\/|stock\/(.*)indicators\/|maps\/(.*)modules\//gi,"")}function getCachePath(){return getAbsolutePath(getOptions().highcharts.cachePath)}async function _fetchAndProcessScript(e,t,o,r=!1){e.endsWith(".js")&&(e=e.substring(0,e.length-3)),log(4,`[cache] Fetching script - ${e}.js`);const n=await fetch(`${e}.js`,t);if(200===n.statusCode&&"string"==typeof n.text){if(o){o[extractModuleName(e)]=1}return n.text}if(r)throw new ExportError(`[cache] Could not fetch the ${e}.js. The script might not exist in the requested version (status code: ${n.statusCode}).`,404).setError(n);log(2,`[cache] Could not fetch the ${e}.js. The script might not exist in the requested version.`)}async function _saveConfigToManifest(e,t={}){const o={version:e.version,modules:t};cache.activeManifest=o,log(3,"[cache] Writing a new manifest.");try{fs.writeFileSync(path.join(getCachePath(),"manifest.json"),JSON.stringify(o),"utf8")}catch(e){throw new ExportError("[cache] Error writing the cache manifest.",500).setError(e)}}async function _fetchScripts(e,t,o,r,n){let i;const s=r.host,a=r.port;if(s&&a)try{i=new httpsProxyAgent.HttpsProxyAgent({host:s,port:a})}catch(e){throw new ExportError("[cache] Could not create a Proxy Agent.",500).setError(e)}const l=i?{agent:i,timeout:r.timeout}:{},c=[...e.map((e=>_fetchAndProcessScript(`${e}`,l,n,!0))),...t.map((e=>_fetchAndProcessScript(`${e}`,l,n))),...o.map((e=>_fetchAndProcessScript(`${e}`,l)))];return(await Promise.all(c)).join(";\n")}async function _updateCache(e,t,o){const r="latest"===e.version?null:`${e.version}`,n=e.cdnUrl||cache.cdnUrl;try{const i={};return log(3,`[cache] Updating cache version to Highcharts: ${r||"latest"}.`),cache.sources=await _fetchScripts([...e.coreScripts.map((e=>r?`${n}/${r}/${e}`:`${n}/${e}`))],[...e.moduleScripts.map((e=>"map"===e?r?`${n}/maps/${r}/modules/${e}`:`${n}/maps/modules/${e}`:r?`${n}/${r}/modules/${e}`:`${n}/modules/${e}`)),...e.indicatorScripts.map((e=>r?`${n}/stock/${r}/indicators/${e}`:`${n}/stock/indicators/${e}`))],e.customScripts,t,i),cache.hcVersion=extractVersion(cache.sources),fs.writeFileSync(o,cache.sources),i}catch(e){throw new ExportError("[cache] Unable to update the local Highcharts cache.",500).setError(e)}}function setupHighcharts(){Highcharts.animObject=function(){return{duration:0}}}async function createChart(e,t){const{getOptions:o,setOptions:r,merge:n,wrap:i}=Highcharts;Highcharts.setOptionsObj=n(!1,{},o()),window.isRenderComplete=!1,i(Highcharts.Chart.prototype,"init",(function(e,t,o){((t=n(t,{exporting:{enabled:!1},plotOptions:{series:{label:{enabled:!1}}},tooltip:{}})).series||[]).forEach((function(e){e.animation=!1})),window.onHighchartsRender||(window.onHighchartsRender=Highcharts.addEvent(this,"render",(()=>{window.isRenderComplete=!0}))),e.apply(this,[t,o])})),i(Highcharts.Series.prototype,"init",(function(e,t,o){e.apply(this,[t,o])}));const s={chart:{animation:!1,height:e.height,width:e.width},exporting:{enabled:!1}},a=new Function(`return ${e.instr}`)(),l=new Function(`return ${e.themeOptions}`)(),c=new Function(`return ${e.globalOptions}`)(),p=n(!1,l,a,s),u=t.callback?new Function(`return ${t.callback}`)():null;t.customCode&&new Function("options",t.customCode)(a),c&&r(c),Highcharts[e.constr]("container",p,u);const d=o();for(const e in d)"function"!=typeof d[e]&&delete d[e];r(Highcharts.setOptionsObj),Highcharts.setOptionsObj={}}const template=fs.readFileSync(path.join(__dirname$1,"templates","template.html"),"utf8");let browser=null;async function createBrowser(e){const{debug:t,other:o}=getOptions(),{enable:r,...n}=t,i={headless:!o.browserShellMode||"shell",userDataDir:"tmp",args:e||[],handleSIGINT:!1,handleSIGTERM:!1,handleSIGHUP:!1,waitForInitialPage:!1,defaultViewport:null,...r&&n};if(!browser){let e=0;const t=async()=>{try{log(3,`[browser] Attempting to get a browser instance (try ${++e}).`),browser=await puppeteer.launch(i)}catch(o){if(logWithStack(1,o,"[browser] Failed to launch a browser instance."),!(e<25))throw o;log(3,`[browser] Retry to open a browser (${e} out of 25).`),await new Promise((e=>setTimeout(e,4e3))),await t()}};try{await t(),"shell"===i.headless&&log(3,"[browser] Launched browser in shell mode."),r&&log(3,"[browser] Launched browser in debug mode.")}catch(e){throw new ExportError("[browser] Maximum retries to open a browser instance reached.",500).setError(e)}if(!browser)throw new ExportError("[browser] Cannot find a browser to open.",500)}return browser}async function closeBrowser(){browser&&browser.connected&&await browser.close(),browser=null,log(4,"[browser] Closed the browser.")}async function newPage(e){if(!browser||!browser.connected)throw new ExportError("[browser] Browser is not yet connected.",500);if(e.page=await browser.newPage(),await e.page.setCacheEnabled(!1),await _setPageContent(e.page),_setPageEvents(e.page),!e.page||e.page.isClosed())throw new ExportError("[browser] The page is invalid or closed.",400)}async function clearPage(e,t=!1){try{if(e.page&&!e.page.isClosed())return t?(await e.page.goto("about:blank",{waitUntil:"domcontentloaded"}),await _setPageContent(e.page)):await e.page.evaluate((()=>{document.body.innerHTML='
'})),!0}catch(t){logWithStack(2,t,`[pool] Pool resource [${e.id}] - Content of the page could not be cleared.`),e.workCount=getOptions().pool.workLimit+1}return!1}async function addPageResources(e,t){const o=[],r=t.resources;if(r){const n=[];if(r.js&&n.push({content:r.js}),r.files)for(const e of r.files){const t=!e.startsWith("http");n.push(t?{content:fs.readFileSync(getAbsolutePath(e),"utf8")}:{url:e})}for(const t of n)try{o.push(await e.addScriptTag(t))}catch(e){logWithStack(2,e,"[browser] The JS resource cannot be loaded.")}n.length=0;const i=[];if(r.css){let n=r.css.match(/@import\s*([^;]*);/g);if(n)for(let e of n)e&&(e=e.replace("url(","").replace("@import","").replace(/"/g,"").replace(/'/g,"").replace(/;/,"").replace(/\)/g,"").trim(),e.startsWith("http")?i.push({url:e}):t.allowFileResources&&i.push({path:getAbsolutePath(e)}));i.push({content:r.css.replace(/@import\s*([^;]*);/g,"")||" "});for(const t of i)try{o.push(await e.addStyleTag(t))}catch(e){logWithStack(2,e,"[browser] The CSS resource cannot be loaded.")}i.length=0}}return o}async function clearPageResources(e,t){try{for(const e of t)await e.dispose();await e.evaluate((()=>{if("undefined"!=typeof Highcharts){const e=Highcharts.charts;if(Array.isArray(e)&&e.length)for(const t of e)t&&t.destroy(),Highcharts.charts.shift()}const[...e]=document.getElementsByTagName("script"),[,...t]=document.getElementsByTagName("style"),[...o]=document.getElementsByTagName("link");for(const r of[...e,...t,...o])r.remove()}))}catch(e){logWithStack(2,e,"[browser] Could not clear page's resources.")}}async function _setPageContent(e){await e.setContent(template,{waitUntil:"domcontentloaded"}),await e.addScriptTag({path:path.join(getCachePath(),"sources.js")}),await e.evaluate(setupHighcharts)}function _setPageEvents(e){const{debug:t}=getOptions();e.on("pageerror",(async()=>{e.isClosed()})),t.enable&&t.listenToConsole&&e.on("console",(e=>{console.log(`[debug] ${e.text()}`)}))}var cssTemplate=()=>"\n\nhtml, body {\n margin: 0;\n padding: 0;\n box-sizing: border-box;\n}\n\n#table-div, #sliders, #datatable, #controls, .ld-row {\n display: none;\n height: 0;\n}\n\n#chart-container {\n box-sizing: border-box;\n margin: 0;\n overflow: auto;\n font-size: 0;\n}\n\n#chart-container > figure, div {\n margin-top: 0 !important;\n margin-bottom: 0 !important;\n}\n\n",svgTemplate=e=>`\n\n\n \n \n Highcharts Export\n \n \n \n
\n ${e}\n
\n \n\n\n`;async function puppeteerExport(e,t,o){const r=[];try{let n=!1;if(t.svg){if(log(4,"[export] Treating as SVG input."),"svg"===t.type)return t.svg;n=!0,await e.setContent(svgTemplate(t.svg),{waitUntil:"domcontentloaded"})}else log(4,"[export] Treating as JSON config."),await e.evaluate(createChart,t,o);r.push(...await addPageResources(e,o));const i=n?await e.evaluate((e=>{const t=document.querySelector("#chart-container svg:first-of-type"),o=t.height.baseVal.value*e,r=t.width.baseVal.value*e;return document.body.style.zoom=e,document.body.style.margin="0px",{chartHeight:o,chartWidth:r}}),parseFloat(t.scale)):await e.evaluate((()=>{const{chartHeight:e,chartWidth:t}=window.Highcharts.charts[0];return document.body.style.zoom=1,{chartHeight:e,chartWidth:t}})),{x:s,y:a}=await _getClipRegion(e),l=Math.abs(Math.ceil(i.chartHeight||t.height)),c=Math.abs(Math.ceil(i.chartWidth||t.width));let p;switch(await e.setViewport({height:l,width:c,deviceScaleFactor:n?1:parseFloat(t.scale)}),t.type){case"svg":p=await _createSVG(e);break;case"png":case"jpeg":p=await _createImage(e,t.type,{width:c,height:l,x:s,y:a},t.rasterizationTimeout);break;case"pdf":p=await _createPDF(e,l,c,t.rasterizationTimeout);break;default:throw new ExportError(`[export] Unsupported output format: ${t.type}.`,400)}return await clearPageResources(e,r),p}catch(t){return await clearPageResources(e,r),t}}async function _getClipRegion(e){return e.$eval("#chart-container",(e=>{const{x:t,y:o,width:r,height:n}=e.getBoundingClientRect();return{x:t,y:o,width:r,height:Math.trunc(n>1?n:500)}}))}async function _createSVG(e){return e.$eval("#container svg:first-of-type",(e=>e.outerHTML))}async function _createImage(e,t,o,r){return Promise.race([e.screenshot({type:t,clip:o,encoding:"base64",fullPage:!1,optimizeForSpeed:!0,captureBeyondViewport:!0,..."png"!==t?{quality:80}:{},omitBackground:"png"==t}),new Promise(((e,t)=>setTimeout((()=>t(new ExportError("Rasterization timeout",408))),r||1500)))])}async function _createPDF(e,t,o,r){return await e.emulateMediaType("screen"),e.pdf({height:t+1,width:o,encoding:"base64",timeout:r||1500})}let pool=null;const poolStats={exportsAttempted:0,exportsPerformed:0,exportsDropped:0,exportsFromSvg:0,exportsFromOptions:0,exportsFromSvgAttempts:0,exportsFromOptionsAttempts:0,timeSpent:0,timeSpentAverage:0};async function initPool(e,t){await createBrowser(t);try{if(log(3,`[pool] Initializing pool with workers: min ${e.minWorkers}, max ${e.maxWorkers}.`),pool)return void log(4,"[pool] Already initialized, please kill it before creating a new one.");e.minWorkers>e.maxWorkers&&(e.minWorkers=e.maxWorkers),pool=new tarn.Pool({..._factory(e),min:e.minWorkers,max:e.maxWorkers,acquireTimeoutMillis:e.acquireTimeout,createTimeoutMillis:e.createTimeout,destroyTimeoutMillis:e.destroyTimeout,idleTimeoutMillis:e.idleTimeout,createRetryIntervalMillis:e.createRetryInterval,reapIntervalMillis:e.reaperInterval,propagateCreateError:!1}),pool.on("release",(async e=>{const t=await clearPage(e,!1);log(4,`[pool] Pool resource [${e.id}] - Releasing a worker. Clear page status: ${t}.`)})),pool.on("destroySuccess",((e,t)=>{log(4,`[pool] Pool resource [${t.id}] - Destroyed a worker successfully.`),t.page=null}));const t=[];for(let o=0;o{pool.release(e)})),log(3,"[pool] The pool is ready"+(t.length?` with ${t.length} initial resources waiting.`:"."))}catch(e){throw new ExportError("[pool] Could not configure and create the pool of workers.",500).setError(e)}}async function killPool(){if(log(3,"[pool] Killing pool with all workers and closing browser."),pool){for(const e of pool.used)pool.release(e.resource);pool.destroyed||(await pool.destroy(),log(4,"[pool] Destroyed the pool of resources.")),pool=null}await closeBrowser()}async function postWork(e){let t;try{if(log(4,"[pool] Work received, starting to process."),++poolStats.exportsAttempted,e.pool.benchmarking&&getPoolInfo(),!pool)throw new ExportError("[pool] Work received, but pool has not been started.",500);const o=measureTime();try{log(4,"[pool] Acquiring a worker handle."),t=await pool.acquire().promise,e.server.benchmarking&&log(5,"[benchmark] "+(e.requestId?`Request [${e.requestId}] - `:""),`Acquiring a worker handle took ${o()}ms.`)}catch(t){throw new ExportError(`[pool] ${e.requestId?`Request [${e.requestId}] - `:""}Error encountered when acquiring an available entry: ${o()}ms.`,400).setError(t)}if(log(4,"[pool] Acquired a worker handle."),!t.page)throw t.workCount=e.pool.workLimit+1,new ExportError("[pool] Resolved worker page is invalid: the pool setup is wonky.",400);const r=getNewDateTime();log(4,`[pool] Pool resource [${t.id}] - Starting work on this pool entry.`);const n=measureTime(),i=await puppeteerExport(t.page,e.export,e.customLogic);if(i instanceof Error)throw"Rasterization timeout"===i.message&&(t.workCount=e.pool.workLimit+1,t.page=null),"TimeoutError"===i.name||"Rasterization timeout"===i.message?new ExportError(`[pool] ${e.requestId?`Request [${e.requestId}] - `:""}Rasterization timeout: your chart may be too complex or large, and failed to render within the allotted time.`).setError(i):new ExportError(`[pool] ${e.requestId?`Request [${e.requestId}] - `:""}Error encountered during export: ${n()}ms.`).setError(i);e.server.benchmarking&&log(5,"[benchmark] "+(e.requestId?`Request [${e.requestId}] - `:""),`Exporting a chart sucessfully took ${n()}ms.`),pool.release(t);const s=getNewDateTime()-r;return poolStats.timeSpent+=s,poolStats.timeSpentAverage=poolStats.timeSpent/++poolStats.exportsPerformed,log(4,`[pool] Work completed in ${s}ms.`),{result:i,options:e}}catch(e){throw++poolStats.exportsDropped,t&&pool.release(t),e}}function getPoolStats(){return poolStats}function getPoolInfoJSON(){return{min:pool.min,max:pool.max,used:pool.numUsed(),available:pool.numFree(),allCreated:pool.numUsed()+pool.numFree(),pendingAcquires:pool.numPendingAcquires(),pendingCreates:pool.numPendingCreates(),pendingValidations:pool.numPendingValidations(),pendingDestroys:pool.pendingDestroys.length,absoluteAll:pool.numUsed()+pool.numFree()+pool.numPendingAcquires()+pool.numPendingCreates()+pool.numPendingValidations()+pool.pendingDestroys.length}}function getPoolInfo(){const{min:e,max:t,used:o,available:r,allCreated:n,pendingAcquires:i,pendingCreates:s,pendingValidations:a,pendingDestroys:l,absoluteAll:c}=getPoolInfoJSON();log(5,`[pool] The minimum number of resources allowed by pool: ${e}.`),log(5,`[pool] The maximum number of resources allowed by pool: ${t}.`),log(5,`[pool] The number of used resources: ${o}.`),log(5,`[pool] The number of free resources: ${r}.`),log(5,`[pool] The number of all created (used and free) resources: ${n}.`),log(5,`[pool] The number of resources waiting to be acquired: ${i}.`),log(5,`[pool] The number of resources waiting to be created: ${s}.`),log(5,`[pool] The number of resources waiting to be validated: ${a}.`),log(5,`[pool] The number of resources waiting to be destroyed: ${l}.`),log(5,`[pool] The number of all resources: ${c}.`)}function _factory(e){return{create:async()=>{const t={id:uuid.v4(),workCount:Math.round(Math.random()*(e.workLimit/2))};try{const e=getNewDateTime();return await newPage(t),log(3,`[pool] Pool resource [${t.id}] - Successfully created a worker, took ${getNewDateTime()-e}ms.`),t}catch(e){throw log(3,`[pool] Pool resource [${t.id}] - Error encountered when creating a new page.`),e}},validate:async t=>t.page?t.page.isClosed()?(log(3,`[pool] Pool resource [${t.id}] - Validation failed (page is closed or invalid).`),!1):t.page.mainFrame().detached?(log(3,`[pool] Pool resource [${t.id}] - Validation failed (page's frame is detached).`),!1):!(e.workLimit&&++t.workCount>e.workLimit)||(log(3,`[pool] Pool resource [${t.id}] - Validation failed (exceeded the ${e.workLimit} works per resource limit).`),!1):(log(3,`[pool] Pool resource [${t.id}] - Validation failed (no valid page is found).`),!1),destroy:async e=>{if(log(3,`[pool] Pool resource [${e.id}] - Destroying a worker.`),e.page&&!e.page.isClosed())try{e.page.removeAllListeners("pageerror"),e.page.removeAllListeners("console"),e.page.removeAllListeners("framedetached"),await e.page.close()}catch(t){throw log(3,`[pool] Pool resource [${e.id}] - Page could not be closed upon destroying.`),t}}}}function sanitize(e){const t=new jsdom.JSDOM("").window;return DOMPurify(t).sanitize(e,{ADD_TAGS:["foreignObject"]})}let allowCodeExecution=!1;async function singleExport(e){if(!e||!e.export)throw new ExportError("[chart] No expected `export` options were found. Please provide one of the following options: `infile`, `instr`, `options`, or `svg` to generate a valid image.",400);await startExport({export:e.export,customLogic:e.customLogic},(async(e,t)=>{if(e)throw e;const{b64:o,outfile:r,type:n}=t.options.export;try{o?fs.writeFileSync(`${r.split(".").shift()||"chart"}.txt`,getBase64(t.result,n)):fs.writeFileSync(r||`chart.${n}`,"svg"!==n?Buffer.from(t.result,"base64"):t.result)}catch(e){throw new ExportError("[chart] Error while saving a chart.",500).setError(e)}await killPool()}))}async function batchExport(e){if(!(e&&e.export&&e.export.batch))throw new ExportError("[chart] No expected `export` options were found. Please provide the `batch` option to generate valid images.",400);{const t=[];for(let o of e.export.batch.split(";")||[])o=o.split("="),2===o.length?t.push(startExport({export:{...e.export,infile:o[0],outfile:o[1]},customLogic:e.customLogic},((e,t)=>{if(e)throw e;const{b64:o,outfile:r,type:n}=t.options.export;try{o?fs.writeFileSync(`${r.split(".").shift()||"chart"}.txt`,getBase64(t.result,n)):fs.writeFileSync(r,"svg"!==n?Buffer.from(t.result,"base64"):t.result)}catch(e){throw new ExportError("[chart] Error while saving a chart.",500).setError(e)}}))):log(2,"[chart] No correct pair found for the batch export.");const o=await Promise.allSettled(t);await killPool(),o.forEach(((e,t)=>{e.reason&&logWithStack(1,e.reason,`[chart] Batch export number ${t+1} could not be correctly completed.`)}))}}async function startExport(e,t){try{if(!isObject(e))throw new ExportError("[chart] Incorrect value of the provided `imageOptions`. Needs to be an object.",400);const o=updateOptions({export:e.export,customLogic:e.customLogic},!0),r=o.export;if(log(4,"[chart] Starting the exporting process."),null!==r.infile){let e;log(4,"[chart] Attempting to export from a file input.");try{e=fs.readFileSync(getAbsolutePath(r.infile),"utf8")}catch(e){throw new ExportError("[chart] Error loading content from a file input.",400).setError(e)}if(r.infile.endsWith(".svg"))r.svg=validateOption("svg",e);else{if(!r.infile.endsWith(".json"))throw new ExportError("[chart] Incorrect value of the `infile` option.",400);r.instr=validateOption("instr",e)}}if(null!==r.svg){log(4,"[chart] Attempting to export from an SVG input."),++getPoolStats().exportsFromSvgAttempts;const e=await _exportFromSvg(sanitize(r.svg),o);return++getPoolStats().exportsFromSvg,t(null,e)}if(null!==r.instr||null!==r.options){log(4,"[chart] Attempting to export from options input."),++getPoolStats().exportsFromOptionsAttempts;const e=await _exportFromOptions(r.instr||r.options,o);return++getPoolStats().exportsFromOptions,t(null,e)}return t(new ExportError("[chart] No valid input specified. Check if at least one of the following parameters is correctly set: 'infile', 'instr', 'options', or 'svg'.",400))}catch(e){return t(e)}}function getAllowCodeExecution(){return allowCodeExecution}function setAllowCodeExecution(e){allowCodeExecution=e}async function _exportFromSvg(e,t){if("string"==typeof e&&(e.indexOf("=0||e.indexOf("=0))return log(4,"[chart] Parsing input as SVG."),t.export.svg=e,t.export.instr=null,t.export.options=null,_prepareExport(t);throw new ExportError("[chart] Not a correct SVG input.",400)}async function _exportFromOptions(e,t){log(4,"[chart] Parsing input from options.");const o=isAllowedConfig(e,!0,t.customLogic.allowCodeExecution);if(null===o||"string"!=typeof o||!o.startsWith("{")||!o.endsWith("}"))throw new ExportError("[chart] Invalid configuration provided - Only options configurations and SVG are allowed for this server. If this is your server, JavaScript custom code can be enabled by starting the server with the `allowCodeExecution` options set to true.",403);return t.export.instr=o,t.export.svg=null,_prepareExport(t)}async function _prepareExport(e){const{export:t,customLogic:o}=e;return t.type=fixType(t.type,t.outfile),t.outfile=fixOutfile(t.type,t.outfile),t.constr=fixConstr(t.constr),log(3,`[chart] The custom logic is ${o.allowCodeExecution?"allowed":"disallowed"}.`),_handleCustomLogic(o,o.allowCodeExecution),_handleGlobalAndTheme(t,o.allowFileResources,o.allowCodeExecution),e.export={...t,..._findChartSize(t)},postWork(e)}function _findChartSize(e){const{chart:t,exporting:o}=e.options||isAllowedConfig(e.instr)||!1,{chart:r,exporting:n}=isAllowedConfig(e.globalOptions)||!1,{chart:i,exporting:s}=isAllowedConfig(e.themeOptions)||!1,a=roundNumber(Math.max(.1,Math.min(e.scale||o?.scale||n?.scale||s?.scale||e.defaultScale||1,5)),2),l={height:e.height||o?.sourceHeight||t?.height||n?.sourceHeight||r?.height||s?.sourceHeight||i?.height||e.defaultHeight||400,width:e.width||o?.sourceWidth||t?.width||n?.sourceWidth||r?.width||s?.sourceWidth||i?.width||e.defaultWidth||600,scale:a};for(let[e,t]of Object.entries(l))l[e]="string"==typeof t?+t.replace(/px|%/gi,""):t;return l}function _handleCustomLogic(e,t){if(t){if("string"==typeof e.resources)e.resources=_handleResources(e.resources,e.allowFileResources,!0);else if(!e.resources)try{e.resources=_handleResources(fs.readFileSync(getAbsolutePath("resources.json"),"utf8"),e.allowFileResources,!0)}catch(e){log(2,"[chart] Unable to load the default `resources.json` file.")}try{e.customCode=wrapAround(e.customCode,e.allowFileResources),e.customCode=validateOption("customCode",e.customCode)}catch(t){logWithStack(2,t,"[chart] The `customCode` cannot be loaded."),e.customCode=null}try{e.callback=wrapAround(e.callback,e.allowFileResources,!0),e.callback=validateOption("callback",e.callback)}catch(t){logWithStack(2,t,"[chart] The `callback` cannot be loaded."),e.callback=null}[null,void 0].includes(e.customCode)&&log(3,"[chart] No value for the `customCode` option found."),[null,void 0].includes(e.callback)&&log(3,"[chart] No value for the `callback` option found."),[null,void 0].includes(e.resources)&&log(3,"[chart] No value for the `resources` option found.")}else if(e.callback||e.resources||e.customCode)throw e.callback=null,e.resources=null,e.customCode=null,new ExportError("[chart] The 'callback', 'resources', and 'customCode' options have been disabled for this server.",403)}function _handleResources(e=null,t,o){const r=["js","css","files"];let n=e,i=!1;if(t&&e.endsWith(".json"))try{n=isAllowedConfig(fs.readFileSync(getAbsolutePath(e),"utf8"),!1,o)}catch{return null}else n=isAllowedConfig(e,!1,o),n&&!t&&delete n.files;for(const e in n)r.includes(e)?i||(i=!0):delete n[e];return i?(n.files&&(n.files=n.files.map((e=>e.trim())),(!n.files||n.files.length<=0)&&delete n.files),n=validateOption("resources",n),n):null}function _handleGlobalAndTheme(e,t,o){["globalOptions","themeOptions"].forEach((r=>{try{e[r]&&(t&&"string"==typeof e[r]&&e[r].endsWith(".json")?e[r]=isAllowedConfig(fs.readFileSync(getAbsolutePath(e[r]),"utf8"),!0,o):e[r]=isAllowedConfig(e[r],!0,o),e[r]=validateOption(r,e[r]))}catch(t){logWithStack(2,t,`[chart] The \`${r}\` cannot be loaded.`),e[r]=null}})),[null,void 0].includes(e.globalOptions)&&log(3,"[chart] No value for the `globalOptions` option found."),[null,void 0].includes(e.themeOptions)&&log(3,"[chart] No value for the `themeOptions` option found.")}const timerIds=[];function addTimer(e){timerIds.push(e)}function clearAllTimers(){log(4,"[timer] Clearing all registered intervals and timeouts.");for(const e of timerIds)clearInterval(e),clearTimeout(e)}function logErrorMiddleware(e,t,o,r){return logWithStack(1,e),"development"!==getOptions().other.nodeEnv&&delete e.stack,r(e)}function returnErrorMiddleware(e,t,o,r){const{message:n,stack:i}=e,s=e.statusCode||400;o.status(s).json({statusCode:s,message:n,stack:i})}function errorMiddleware(e){e.use(logErrorMiddleware),e.use(returnErrorMiddleware)}function rateLimitingMiddleware(e,t){try{if(e&&t.enable){const o="Too many requests, you have been rate limited. Please try again later.",r={window:t.window||1,maxRequests:t.maxRequests||30,delay:t.delay||0,trustProxy:t.trustProxy||!1,skipKey:t.skipKey||null,skipToken:t.skipToken||null};r.trustProxy&&e.enable("trust proxy");const n=rateLimit({windowMs:60*r.window*1e3,limit:r.maxRequests,delayMs:r.delay,handler:(e,t)=>{t.format({json:()=>{t.status(429).send({message:o})},default:()=>{t.status(429).send(o)}})},skip:e=>null!==r.skipKey&&null!==r.skipToken&&e.query.key===r.skipKey&&e.query.access_token===r.skipToken&&(log(4,"[rate limiting] Skipping rate limiter."),!0)});e.use(n),log(3,`[rate limiting] Enabled rate limiting with ${r.maxRequests} requests per ${r.window} minute for each IP, trusting proxy: ${r.trustProxy}.`)}}catch(e){throw new ExportError("[rate limiting] Could not configure and set the rate limiting options.",500).setError(e)}}function contentTypeMiddleware(e,t,o){try{const t=e.headers["content-type"]||"";if(!t.includes("application/json")&&!t.includes("application/x-www-form-urlencoded")&&!t.includes("multipart/form-data"))throw new ExportError("[validation] Content-Type must be application/json, application/x-www-form-urlencoded, or multipart/form-data.",415);return o()}catch(e){return o(e)}}function requestBodyMiddleware(e,t,o){try{const t=e.body,r=uuid.v4();if(!t||isObjectEmpty(t))throw log(2,`[validation] Request [${r}] - The request from ${e.headers["x-forwarded-for"]||e.connection.remoteAddress} was incorrect. Received payload is empty.`),new ExportError(`[validation] Request [${r}] - The request body is required. Please ensure that your Content-Type header is correct. Accepted types are 'application/json' and 'multipart/form-data'.`,400);const n=getAllowCodeExecution(),i=isAllowedConfig(t.instr||t.options||t.infile||t.data,!0,n);if(null===i&&!t.svg)throw log(2,`[validation] Request [${r}] - The request from ${e.headers["x-forwarded-for"]||e.connection.remoteAddress} was incorrect. Received payload is missing correct chart data for export: ${JSON.stringify(t)}.`),new ExportError(`Request [${r}] - [validation] No correct chart data found. Ensure that you are using either application/json or multipart/form-data headers. If sending JSON, make sure the chart data is in the 'infile', 'options', or 'data' attribute. If sending SVG, ensure it is in the 'svg' attribute.`,400);if(t.svg&&isPrivateRangeUrlFound(t.svg))throw new ExportError(`Request [${r}] - [validation] SVG potentially contain at least one forbidden URL in 'xlink:href' element. Please review the SVG content and ensure that all referenced URLs comply with security policies.`,400);return e.validatedOptions={requestId:r,export:{instr:i,svg:t.svg,outfile:t.outfile||`${e.params.filename||"chart"}.${t.type||"png"}`,type:t.type,constr:t.constr,b64:t.b64,noDownload:t.noDownload,height:t.height,width:t.width,scale:t.scale,globalOptions:isAllowedConfig(t.globalOptions,!0,n),themeOptions:isAllowedConfig(t.themeOptions,!0,n)},customLogic:{allowCodeExecution:n,allowFileResources:!1,customCode:t.customCode,callback:t.callback,resources:isAllowedConfig(t.resources,!0,n)}},o()}catch(e){return o(e)}}function validationMiddleware(e){e.post(["/","/:filename"],contentTypeMiddleware),e.post(["/","/:filename"],requestBodyMiddleware)}const reversedMime={png:"image/png",jpeg:"image/jpeg",gif:"image/gif",pdf:"application/pdf",svg:"image/svg+xml"};async function requestExport(e,t,o){try{const o=measureTime();let r=!1;e.socket.on("close",(e=>{e&&(r=!0)}));const n=e.validatedOptions,i=n.requestId;log(4,`[export] Request [${i}] - Got an incoming HTTP request.`),await startExport(n,((n,s)=>{if(e.socket.removeAllListeners("close"),r)log(3,`[export] Request [${i}] - The client closed the connection before the chart finished processing.`);else{if(n)throw n;if(!s||!s.result)throw log(2,`[export] Request [${i}] - Request from ${e.headers["x-forwarded-for"]||e.connection.remoteAddress} was incorrect. Received result is ${s.result}.`),new ExportError(`[export] Request [${i}] - Unexpected return of the export result from the chart generation. Please check your request data.`,400);if(s.result){log(3,`[export] Request [${i}] - The whole exporting process took ${o()}ms.`);const{type:e,b64:r,noDownload:n,outfile:a}=s.options.export;return r?t.send(getBase64(s.result,e)):(t.header("Content-Type",reversedMime[e]||"image/png"),n||t.attachment(a),"svg"===e?t.send(s.result):t.send(Buffer.from(s.result,"base64")))}}}))}catch(e){return o(e)}}function exportRoutes(e){e.post("/",requestExport),e.post("/:filename",requestExport)}const serverStartTime=new Date,packageFile=JSON.parse(fs.readFileSync(path.join(__dirname$1,"package.json"),"utf8")),successRates=[],recordInterval=6e4,windowSize=30;function _calculateMovingAverage(){return successRates.reduce(((e,t)=>e+t),0)/successRates.length}function _startSuccessRate(){return setInterval((()=>{const e=getPoolStats(),t=0===e.exportsAttempted?1:e.exportsPerformed/e.exportsAttempted*100;successRates.push(t),successRates.length>windowSize&&successRates.shift()}),recordInterval)}function healthRoutes(e){addTimer(_startSuccessRate()),e.get("/health",((e,t,o)=>{try{log(4,"[health] Returning server health.");const e=getPoolStats(),o=successRates.length,r=_calculateMovingAverage();t.send({status:"OK",bootTime:serverStartTime,uptime:`${Math.floor((getNewDateTime()-serverStartTime.getTime())/1e3/60)} minutes`,serverVersion:packageFile.version,highchartsVersion:getHighchartsVersion(),averageExportTime:e.timeSpentAverage,attemptedExports:e.exportsAttempted,performedExports:e.exportsPerformed,failedExports:e.exportsDropped,sucessRatio:e.exportsPerformed/e.exportsAttempted*100,pool:getPoolInfoJSON(),period:o,movingAverage:r,message:isNaN(r)||!successRates.length?"Too early to report. No exports made yet. Please check back soon.":`Last ${o} minutes had a success rate of ${r.toFixed(2)}%.`,svgExports:e.exportsFromSvg,jsonExports:e.exportsFromOptions,svgExportsAttempts:e.exportsFromSvgAttempts,jsonExportsAttempts:e.exportsFromOptionsAttempts})}catch(e){return o(e)}}))}function uiRoutes(e){e.get(getOptions().ui.route||"/",((e,t,o)=>{try{log(4,"[ui] Returning UI for the export."),t.sendFile(path.join(__dirname$1,"public","index.html"),{acceptRanges:!1})}catch(e){return o(e)}}))}function versionChangeRoutes(e){e.post("/version_change/:newVersion",(async(e,t,o)=>{try{log(4,"[version] Changing Highcharts version.");const o=envs.HIGHCHARTS_ADMIN_TOKEN;if(!o||!o.length)throw new ExportError("[version] The server is not configured to perform run-time version changes: HIGHCHARTS_ADMIN_TOKEN is not set.",401);const r=e.get("hc-auth");if(!r||r!==o)throw new ExportError("[version] Invalid or missing token: Set the token in the hc-auth header.",401);const n=e.params.newVersion;if(!n)throw new ExportError("[version] No new version supplied.",400);try{await updateHighchartsVersion(n)}catch(e){throw new ExportError(`[version] Version change: ${e.message}`,400).setError(e)}t.status(200).send({statusCode:200,highchartsVersion:getHighchartsVersion(),message:`Successfully updated Highcharts to version: ${n}.`})}catch(e){return o(e)}}))}const activeServers=new Map,app=express();async function startServer(e){try{const t=updateOptions({server:e});if(!(e=t.server).enable||!app)throw new ExportError("[server] Server cannot be started (not enabled or no correct Express app found).",500);const o=1024*e.uploadLimit*1024,r=multer.memoryStorage(),n=multer({storage:r,limits:{fieldSize:o}});if(app.disable("x-powered-by"),app.use(cors({methods:["POST","GET","OPTIONS"]})),app.use(((e,t,o)=>{t.set("Accept-Ranges","none"),o()})),app.use(express.json({limit:o})),app.use(express.urlencoded({extended:!0,limit:o})),app.use(n.none()),app.use(express.static(path.join(__dirname$1,"public"))),!e.ssl.force){const t=http.createServer(app);_attachServerErrorHandlers(t),t.listen(e.port,e.host,(()=>{activeServers.set(e.port,t),log(3,`[server] Started HTTP server on ${e.host}:${e.port}.`)}))}if(e.ssl.enable){let t,o;try{t=fs.readFileSync(path.join(getAbsolutePath(e.ssl.certPath),"server.key"),"utf8"),o=fs.readFileSync(path.join(getAbsolutePath(e.ssl.certPath),"server.crt"),"utf8")}catch(t){log(2,`[server] Unable to load key/certificate from the '${e.ssl.certPath}' path. Could not run secured layer server.`)}if(t&&o){const r=https.createServer({key:t,cert:o},app);_attachServerErrorHandlers(r),r.listen(e.ssl.port,e.host,(()=>{activeServers.set(e.ssl.port,r),log(3,`[server] Started HTTPS server on ${e.host}:${e.ssl.port}.`)}))}}rateLimitingMiddleware(app,e.rateLimiting),validationMiddleware(app),exportRoutes(app),healthRoutes(app),uiRoutes(app),versionChangeRoutes(app),errorMiddleware(app)}catch(e){throw new ExportError("[server] Could not configure and start the server.",500).setError(e)}}function closeServers(){if(activeServers.size>0){log(4,"[server] Closing all servers.");for(const[e,t]of activeServers)t.close((()=>{activeServers.delete(e),log(4,`[server] Closed server on port: ${e}.`)}))}}function getServers(){return activeServers}function getExpress(){return express}function getApp(){return app}function enableRateLimiting(e){const t=updateOptions({server:{rateLimiting:e}});rateLimitingMiddleware(app,t.server.rateLimitingOptions)}function use(e,...t){app.use(e,...t)}function get(e,...t){app.get(e,...t)}function post(e,...t){app.post(e,...t)}function _attachServerErrorHandlers(e){e.on("clientError",((e,t)=>{logWithStack(1,e,`[server] Client error: ${e.message}, destroying socket.`),t.destroy()})),e.on("error",(e=>{logWithStack(1,e,`[server] Server error: ${e.message}`)})),e.on("connection",(e=>{e.on("error",(e=>{logWithStack(1,e,`[server] Socket error: ${e.message}`)}))}))}var server={startServer:startServer,closeServers:closeServers,getServers:getServers,getExpress:getExpress,getApp:getApp,enableRateLimiting:enableRateLimiting,use:use,get:get,post:post};async function shutdownCleanUp(e=0){await Promise.allSettled([clearAllTimers(),closeServers(),killPool()]),process.exit(e)}async function initExport(e){const t=updateOptions(e);setAllowCodeExecution(t.customLogic.allowCodeExecution),initLogging(t.logging),t.other.listenToProcessExits&&_attachProcessExitListeners(),await checkAndUpdateCache(t.highcharts,t.server.proxy),await initPool(t.pool,t.puppeteer.args)}function _attachProcessExitListeners(){log(3,"[process] Attaching exit listeners to the process."),process.on("exit",(e=>{log(4,`[process] Process exited with code ${e}.`)})),process.on("SIGINT",(async(e,t)=>{log(4,`[process] The ${e} event with code: ${t}.`),await shutdownCleanUp()})),process.on("SIGTERM",(async(e,t)=>{log(4,`[process] The ${e} event with code: ${t}.`),await shutdownCleanUp()})),process.on("SIGHUP",(async(e,t)=>{log(4,`[process] The ${e} event with code: ${t}.`),await shutdownCleanUp()})),process.on("uncaughtException",(async(e,t)=>{logWithStack(1,e,`[process] The ${t} error.`),await shutdownCleanUp(1)}))}var index={...server,getOptions:getOptions,updateOptions:updateOptions,mapToNewOptions:mapToNewOptions,validateOption:validateOption,validateOptions:validateOptions,initExport:initExport,singleExport:singleExport,batchExport:batchExport,startExport:startExport,killPool:killPool,shutdownCleanUp:shutdownCleanUp,log:log,logWithStack:logWithStack,logZodIssues:logZodIssues,setLogLevel:function(e){setLogLevel(updateOptions({logging:{level:e}}).logging.level)},enableConsoleLogging:function(e){enableConsoleLogging(updateOptions({logging:{toConsole:e}}).logging.toConsole)},enableFileLogging:function(e,t,o){const r=updateOptions({logging:{dest:e,file:t,toFile:o}});enableFileLogging(r.logging.dest,r.logging.file,r.logging.toFile)}};exports.default=index,exports.initExport=initExport; +//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguY2pzIiwic291cmNlcyI6WyIuLi9saWIvdXRpbHMuanMiLCIuLi9saWIvbG9nZ2VyLmpzIiwiLi4vbGliL3NjaGVtYXMvY29uZmlnLmpzIiwiLi4vbGliL3ZhbGlkYXRpb24uanMiLCIuLi9saWIvZXJyb3JzL0V4cG9ydEVycm9yLmpzIiwiLi4vbGliL2NvbmZpZy5qcyIsIi4uL2xpYi9mZXRjaC5qcyIsIi4uL2xpYi9jYWNoZS5qcyIsIi4uL2xpYi9oaWdoY2hhcnRzLmpzIiwiLi4vbGliL2Jyb3dzZXIuanMiLCIuLi90ZW1wbGF0ZXMvc3ZnRXhwb3J0L2Nzcy5qcyIsIi4uL3RlbXBsYXRlcy9zdmdFeHBvcnQvc3ZnRXhwb3J0LmpzIiwiLi4vbGliL2V4cG9ydC5qcyIsIi4uL2xpYi9wb29sLmpzIiwiLi4vbGliL3Nhbml0aXplLmpzIiwiLi4vbGliL2NoYXJ0LmpzIiwiLi4vbGliL3RpbWVyLmpzIiwiLi4vbGliL3NlcnZlci9taWRkbGV3YXJlcy9lcnJvci5qcyIsIi4uL2xpYi9zZXJ2ZXIvbWlkZGxld2FyZXMvcmF0ZUxpbWl0aW5nLmpzIiwiLi4vbGliL3NlcnZlci9taWRkbGV3YXJlcy92YWxpZGF0aW9uLmpzIiwiLi4vbGliL3NlcnZlci9yb3V0ZXMvZXhwb3J0LmpzIiwiLi4vbGliL3NlcnZlci9yb3V0ZXMvaGVhbHRoLmpzIiwiLi4vbGliL3NlcnZlci9yb3V0ZXMvdWkuanMiLCIuLi9saWIvc2VydmVyL3JvdXRlcy92ZXJzaW9uQ2hhbmdlLmpzIiwiLi4vbGliL3NlcnZlci9zZXJ2ZXIuanMiLCIuLi9saWIvcmVzb3VyY2VSZWxlYXNlLmpzIiwiLi4vbGliL2luZGV4LmpzIl0sInNvdXJjZXNDb250ZW50IjpbIi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXHJcblxyXG5IaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXJcclxuXHJcbkNvcHlyaWdodCAoYykgMjAxNi0yMDI1LCBIaWdoc29mdFxyXG5cclxuTGljZW5jZWQgdW5kZXIgdGhlIE1JVCBsaWNlbmNlLlxyXG5cclxuQWRkaXRpb25hbGx5IGEgdmFsaWQgSGlnaGNoYXJ0cyBsaWNlbnNlIGlzIHJlcXVpcmVkIGZvciB1c2UuXHJcblxyXG5TZWUgTElDRU5TRSBmaWxlIGluIHJvb3QgZm9yIGRldGFpbHMuXHJcblxyXG4qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xyXG5cclxuLyoqXHJcbiAqIEBvdmVydmlldyBUaGUgSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyIHV0aWxpdHkgbW9kdWxlIHByb3ZpZGVzXHJcbiAqIGEgY29tcHJlaGVuc2l2ZSBzZXQgb2YgaGVscGVyIGZ1bmN0aW9ucyBhbmQgY29uc3RhbnRzIGRlc2lnbmVkIHRvIHN0cmVhbWxpbmVcclxuICogYW5kIGVuaGFuY2UgdmFyaW91cyBvcGVyYXRpb25zIHJlcXVpcmVkIGZvciBIaWdoY2hhcnRzIGV4cG9ydCB0YXNrcy5cclxuICovXHJcblxyXG5pbXBvcnQgeyByZWFkRmlsZVN5bmMgfSBmcm9tICdmcyc7XHJcbmltcG9ydCB7IGlzQWJzb2x1dGUsIG5vcm1hbGl6ZSwgcmVzb2x2ZSB9IGZyb20gJ3BhdGgnO1xyXG5pbXBvcnQgeyBmaWxlVVJMVG9QYXRoIH0gZnJvbSAndXJsJztcclxuXHJcbmNvbnN0IE1BWF9CQUNLT0ZGX0FUVEVNUFRTID0gNjtcclxuXHJcbi8vIFRoZSBkaXJlY3RvcnkgcGF0aFxyXG5leHBvcnQgY29uc3QgX19kaXJuYW1lID0gZmlsZVVSTFRvUGF0aChuZXcgVVJMKCcuLi8uJywgaW1wb3J0Lm1ldGEudXJsKSk7XHJcblxyXG4vKipcclxuICogQ2xlYXJzIGFuZCBzdGFuZGFyZGl6ZXMgdGV4dCBieSByZXBsYWNpbmcgbXVsdGlwbGUgY29uc2VjdXRpdmUgd2hpdGVzcGFjZVxyXG4gKiBjaGFyYWN0ZXJzIHdpdGggYSBzaW5nbGUgc3BhY2UgYW5kIHRyaW1taW5nIGFueSBsZWFkaW5nIG9yIHRyYWlsaW5nXHJcbiAqIHdoaXRlc3BhY2UuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBjbGVhclRleHRcclxuICpcclxuICogQHBhcmFtIHtzdHJpbmd9IHRleHQgLSBUaGUgaW5wdXQgdGV4dCB0byBiZSBjbGVhcmVkLlxyXG4gKiBAcGFyYW0ge1JlZ0V4cH0gW3J1bGU9L1xcc1xccysvZ10gLSBUaGUgcmVndWxhciBleHByZXNzaW9uIHJ1bGUgdG8gbWF0Y2hcclxuICogbXVsdGlwbGUgY29uc2VjdXRpdmUgd2hpdGVzcGFjZSBjaGFyYWN0ZXJzLiBUaGUgZGVmYXVsdCB2YWx1ZVxyXG4gKiBpcyB0aGUgJy9cXHNcXHMrL2cnIFJlZ0V4cC5cclxuICogQHBhcmFtIHtzdHJpbmd9IFtyZXBsYWNlcj0nICddIC0gVGhlIHN0cmluZyB1c2VkIHRvIHJlcGxhY2UgbXVsdGlwbGVcclxuICogY29uc2VjdXRpdmUgd2hpdGVzcGFjZSBjaGFyYWN0ZXJzLiBUaGUgZGVmYXVsdCB2YWx1ZSBpcyB0aGUgJyAnIHN0cmluZy5cclxuICpcclxuICogQHJldHVybnMge3N0cmluZ30gVGhlIGNsZWFyZWQgYW5kIHN0YW5kYXJkaXplZCB0ZXh0LlxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIGNsZWFyVGV4dCh0ZXh0LCBydWxlID0gL1xcc1xccysvZywgcmVwbGFjZXIgPSAnICcpIHtcclxuICByZXR1cm4gdGV4dC5yZXBsYWNlQWxsKHJ1bGUsIHJlcGxhY2VyKS50cmltKCk7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBDcmVhdGVzIGEgZGVlcCBjb3B5IG9mIHRoZSBnaXZlbiBvYmplY3Qgb3IgYXJyYXkuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBkZWVwQ29weVxyXG4gKlxyXG4gKiBAcGFyYW0geyhPYmplY3R8QXJyYXkpfSBvYmpBcnIgLSBUaGUgb2JqZWN0IG9yIGFycmF5IHRvIGJlIGRlZXBseSBjb3BpZWQuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHsoT2JqZWN0fEFycmF5KX0gVGhlIGRlZXAgY29weSBvZiB0aGUgcHJvdmlkZWQgb2JqZWN0IG9yIGFycmF5LlxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIGRlZXBDb3B5KG9iakFycikge1xyXG4gIC8vIElmIHRoZSBgb2JqQXJyYCBpcyBudWxsIG9yIG5vdCBvZiB0aGUgYG9iamVjdGAgdHlwZSwgcmV0dXJuIGl0XHJcbiAgaWYgKG9iakFyciA9PT0gbnVsbCB8fCB0eXBlb2Ygb2JqQXJyICE9PSAnb2JqZWN0Jykge1xyXG4gICAgcmV0dXJuIG9iakFycjtcclxuICB9XHJcblxyXG4gIC8vIFByZXBhcmUgZWl0aGVyIGEgbmV3IGFycmF5IG9yIGEgbmV3IG9iamVjdFxyXG4gIGNvbnN0IG9iakFyckNvcHkgPSBBcnJheS5pc0FycmF5KG9iakFycikgPyBbXSA6IHt9O1xyXG5cclxuICAvLyBSZWN1cnNpdmVseSBjb3B5IGVhY2ggcHJvcGVydHlcclxuICBmb3IgKGNvbnN0IGtleSBpbiBvYmpBcnIpIHtcclxuICAgIGlmIChPYmplY3QucHJvdG90eXBlLmhhc093blByb3BlcnR5LmNhbGwob2JqQXJyLCBrZXkpKSB7XHJcbiAgICAgIG9iakFyckNvcHlba2V5XSA9IGRlZXBDb3B5KG9iakFycltrZXldKTtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIC8vIFJldHVybiB0aGUgY29waWVkIG9iamVjdFxyXG4gIHJldHVybiBvYmpBcnJDb3B5O1xyXG59XHJcblxyXG4vKipcclxuICogSW1wbGVtZW50cyBhbiBleHBvbmVudGlhbCBiYWNrb2ZmIHN0cmF0ZWd5IGZvciByZXRyeWluZyBhIGZ1bmN0aW9uIHVudGlsXHJcbiAqIGEgY2VydGFpbiBudW1iZXIgb2YgYXR0ZW1wdHMgYXJlIHJlYWNoZWQuXHJcbiAqXHJcbiAqIEBhc3luY1xyXG4gKiBAZnVuY3Rpb24gZXhwQmFja29mZlxyXG4gKlxyXG4gKiBAcGFyYW0ge0Z1bmN0aW9ufSBmbiAtIFRoZSBmdW5jdGlvbiB0byBiZSByZXRyaWVkLlxyXG4gKiBAcGFyYW0ge251bWJlcn0gW2F0dGVtcHQ9MF0gLSBUaGUgY3VycmVudCBhdHRlbXB0IG51bWJlci4gVGhlIGRlZmF1bHQgdmFsdWVcclxuICogaXMgYDBgLlxyXG4gKiBAcGFyYW0gey4uLnVua25vd259IGFyZ3MgLSBBcmd1bWVudHMgdG8gYmUgcGFzc2VkIHRvIHRoZSBmdW5jdGlvbi5cclxuICpcclxuICogQHJldHVybnMge1Byb21pc2U8dW5rbm93bj59IEEgUHJvbWlzZSB0aGF0IHJlc29sdmVzIHRvIHRoZSByZXN1bHRcclxuICogb2YgdGhlIGZ1bmN0aW9uIGlmIHN1Y2Nlc3NmdWwuXHJcbiAqXHJcbiAqIEB0aHJvd3Mge0Vycm9yfSBUaHJvd3MgYW4gYEVycm9yYCBpZiB0aGUgbWF4aW11bSBudW1iZXIgb2YgYXR0ZW1wdHNcclxuICogaXMgcmVhY2hlZC5cclxuICovXHJcbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBleHBCYWNrb2ZmKGZuLCBhdHRlbXB0ID0gMCwgLi4uYXJncykge1xyXG4gIHRyeSB7XHJcbiAgICAvLyBUcnkgdG8gY2FsbCB0aGUgZnVuY3Rpb25cclxuICAgIHJldHVybiBhd2FpdCBmbiguLi5hcmdzKTtcclxuICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgLy8gQ2FsY3VsYXRlIGRlbGF5IGluIG1zXHJcbiAgICBjb25zdCBkZWxheUluTXMgPSAyICoqIGF0dGVtcHQgKiAxMDAwO1xyXG5cclxuICAgIC8vIElmIHRoZSBhdHRlbXB0IGV4Y2VlZHMgdGhlIG1heGltdW0gYXR0ZW1wdHMgb2YgcmVwZWF0LCB0aHJvdyBhbiBlcnJvclxyXG4gICAgaWYgKCsrYXR0ZW1wdCA+PSBNQVhfQkFDS09GRl9BVFRFTVBUUykge1xyXG4gICAgICB0aHJvdyBlcnJvcjtcclxuICAgIH1cclxuXHJcbiAgICAvLyBXYWl0IGdpdmVuIGFtb3VudCBvZiB0aW1lXHJcbiAgICBhd2FpdCBuZXcgUHJvbWlzZSgocmVzcG9uc2UpID0+IHNldFRpbWVvdXQocmVzcG9uc2UsIGRlbGF5SW5NcykpO1xyXG5cclxuICAgIC8vLyBUTyBETzogQ29ycmVjdFxyXG4gICAgLy8gLy8gSW5mb3JtYXRpb24gYWJvdXQgdGhlIHJlc291cmNlIHRpbWVvdXRcclxuICAgIC8vIGxvZyhcclxuICAgIC8vICAgMyxcclxuICAgIC8vICAgYFt1dGlsc10gV2FpdGVkICR7ZGVsYXlJbk1zfW1zIHVudGlsIG5leHQgY2FsbCBmb3IgdGhlIHJlc291cmNlIG9mIElEOiAke2FyZ3NbMF19LmBcclxuICAgIC8vICk7XHJcblxyXG4gICAgLy8gVHJ5IGFnYWluXHJcbiAgICByZXR1cm4gZXhwQmFja29mZihmbiwgYXR0ZW1wdCwgLi4uYXJncyk7XHJcbiAgfVxyXG59XHJcblxyXG4vKipcclxuICogQWRqdXN0cyB0aGUgY29uc3RydWN0b3IgbmFtZSBieSB0cmFuc2Zvcm1pbmcgYW5kIG5vcm1hbGl6aW5nIGl0IGJhc2VkXHJcbiAqIG9uIGNvbW1vbiBjaGFydCB0eXBlcy5cclxuICpcclxuICogQGZ1bmN0aW9uIGZpeENvbnN0clxyXG4gKlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gY29uc3RyIC0gVGhlIG9yaWdpbmFsIGNvbnN0cnVjdG9yIG5hbWUgdG8gYmUgZml4ZWQuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtzdHJpbmd9IFRoZSBjb3JyZWN0ZWQgY29uc3RydWN0b3IgbmFtZSwgb3IgJ2NoYXJ0JyBpZiB0aGUgaW5wdXRcclxuICogaXMgbm90IHJlY29nbml6ZWQuXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gZml4Q29uc3RyKGNvbnN0cikge1xyXG4gIHRyeSB7XHJcbiAgICAvLyBGaXggdGhlIGNvbnN0cnVjdG9yIGJ5IGxvd2VyaW5nIGNhc2luZ1xyXG4gICAgY29uc3QgZml4ZWRDb25zdHIgPSBgJHtjb25zdHIudG9Mb3dlckNhc2UoKS5yZXBsYWNlKCdjaGFydCcsICcnKX1DaGFydGA7XHJcblxyXG4gICAgLy8gSGFuZGxlIHRoZSBjYXNlIHdoZXJlIHRoZSByZXN1bHQgaXMganVzdCAnQ2hhcnQnXHJcbiAgICBpZiAoZml4ZWRDb25zdHIgPT09ICdDaGFydCcpIHtcclxuICAgICAgZml4ZWRDb25zdHIudG9Mb3dlckNhc2UoKTtcclxuICAgIH1cclxuXHJcbiAgICAvLyBSZXR1cm4gdGhlIGNvcnJlY3RlZCBjb25zdHJ1Y3Rvciwgb3RoZXJ3aXNlIGRlZmF1bHQgdG8gJ2NoYXJ0J1xyXG4gICAgcmV0dXJuIFsnY2hhcnQnLCAnc3RvY2tDaGFydCcsICdtYXBDaGFydCcsICdnYW50dENoYXJ0J10uaW5jbHVkZXMoXHJcbiAgICAgIGZpeGVkQ29uc3RyXHJcbiAgICApXHJcbiAgICAgID8gZml4ZWRDb25zdHJcclxuICAgICAgOiAnY2hhcnQnO1xyXG4gIH0gY2F0Y2gge1xyXG4gICAgLy8gRGVmYXVsdCB0byAnY2hhcnQnIGluIGNhc2Ugb2YgYW55IGVycm9yXHJcbiAgICByZXR1cm4gJ2NoYXJ0JztcclxuICB9XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBGaXhlcyB0aGUgb3V0ZmlsZSBiYXNlZCBvbiBwcm92aWRlZCB0eXBlLlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gZml4T3V0ZmlsZVxyXG4gKlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gdHlwZSAtIFRoZSBvcmlnaW5hbCBleHBvcnQgdHlwZS5cclxuICogQHBhcmFtIHtzdHJpbmd9IG91dGZpbGUgLSBUaGUgZmlsZSBwYXRoIG9yIG5hbWUuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtzdHJpbmd9IFRoZSBjb3JyZWN0ZWQgb3V0ZmlsZS5cclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiBmaXhPdXRmaWxlKHR5cGUsIG91dGZpbGUpIHtcclxuICAvLyBHZXQgdGhlIGZpbGUgbmFtZSBmcm9tIHRoZSBgb3V0ZmlsZWAgb3B0aW9uXHJcbiAgY29uc3QgZmlsZU5hbWUgPSBnZXRBYnNvbHV0ZVBhdGgob3V0ZmlsZSB8fCAnY2hhcnQnKVxyXG4gICAgLnNwbGl0KCcuJylcclxuICAgIC5zaGlmdCgpO1xyXG5cclxuICAvLyBSZXR1cm4gYSBjb3JyZWN0IG91dGZpbGVcclxuICByZXR1cm4gYCR7ZmlsZU5hbWV9LiR7dHlwZX1gO1xyXG59XHJcblxyXG4vKipcclxuICogRml4ZXMgdGhlIGV4cG9ydCB0eXBlIGJhc2VkIG9uIE1JTUUgdHlwZXMgYW5kIGZpbGUgZXh0ZW5zaW9ucy5cclxuICpcclxuICogQGZ1bmN0aW9uIGZpeFR5cGVcclxuICpcclxuICogQHBhcmFtIHtzdHJpbmd9IHR5cGUgLSBUaGUgb3JpZ2luYWwgZXhwb3J0IHR5cGUuXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSBbb3V0ZmlsZT1udWxsXSAtIFRoZSBmaWxlIHBhdGggb3IgbmFtZS4gVGhlIGRlZmF1bHQgdmFsdWVcclxuICogaXMgYG51bGxgLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7c3RyaW5nfSBUaGUgY29ycmVjdGVkIGV4cG9ydCB0eXBlLlxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIGZpeFR5cGUodHlwZSwgb3V0ZmlsZSA9IG51bGwpIHtcclxuICAvLyBNSU1FIHR5cGVzXHJcbiAgY29uc3QgbWltZVR5cGVzID0ge1xyXG4gICAgJ2ltYWdlL3BuZyc6ICdwbmcnLFxyXG4gICAgJ2ltYWdlL2pwZWcnOiAnanBlZycsXHJcbiAgICAnYXBwbGljYXRpb24vcGRmJzogJ3BkZicsXHJcbiAgICAnaW1hZ2Uvc3ZnK3htbCc6ICdzdmcnXHJcbiAgfTtcclxuXHJcbiAgLy8gR2V0IGZvcm1hdHNcclxuICBjb25zdCBmb3JtYXRzID0gT2JqZWN0LnZhbHVlcyhtaW1lVHlwZXMpO1xyXG5cclxuICAvLyBDaGVjayBpZiB0eXBlIGFuZCBvdXRmaWxlJ3MgZXh0ZW5zaW9ucyBhcmUgdGhlIHNhbWVcclxuICBpZiAob3V0ZmlsZSkge1xyXG4gICAgY29uc3Qgb3V0VHlwZSA9IG91dGZpbGUuc3BsaXQoJy4nKS5wb3AoKTtcclxuXHJcbiAgICAvLyBTdXBwb3J0IHRoZSBKUEcgdHlwZVxyXG4gICAgaWYgKG91dFR5cGUgPT09ICdqcGcnKSB7XHJcbiAgICAgIHR5cGUgPSAnanBlZyc7XHJcbiAgICB9IGVsc2UgaWYgKGZvcm1hdHMuaW5jbHVkZXMob3V0VHlwZSkgJiYgdHlwZSAhPT0gb3V0VHlwZSkge1xyXG4gICAgICB0eXBlID0gb3V0VHlwZTtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIC8vIFJldHVybiBhIGNvcnJlY3QgdHlwZVxyXG4gIHJldHVybiBtaW1lVHlwZXNbdHlwZV0gfHwgZm9ybWF0cy5maW5kKCh0KSA9PiB0ID09PSB0eXBlKSB8fCAncG5nJztcclxufVxyXG5cclxuLyoqXHJcbiAqIENoZWNrcyBpZiB0aGUgZ2l2ZW4gcGF0aCBpcyByZWxhdGl2ZSBvciBhYnNvbHV0ZSBhbmQgcmV0dXJucyB0aGUgY29ycmVjdGVkLFxyXG4gKiBhYnNvbHV0ZSBwYXRoLlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gaXNBYnNvbHV0ZVBhdGhcclxuICpcclxuICogQHBhcmFtIHtzdHJpbmd9IHBhdGggLSBUaGUgcGF0aCB0byBiZSBjaGVja2VkIG9uLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7c3RyaW5nfSBUaGUgYWJzb2x1dGUgcGF0aC5cclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiBnZXRBYnNvbHV0ZVBhdGgocGF0aCkge1xyXG4gIHJldHVybiBpc0Fic29sdXRlKHBhdGgpID8gbm9ybWFsaXplKHBhdGgpIDogcmVzb2x2ZShwYXRoKTtcclxufVxyXG5cclxuLyoqXHJcbiAqIENvbnZlcnRzIGlucHV0IGRhdGEgdG8gYSBCYXNlNjQgc3RyaW5nIGJhc2VkIG9uIHRoZSBleHBvcnQgdHlwZS5cclxuICpcclxuICogQGZ1bmN0aW9uIGdldEJhc2U2NFxyXG4gKlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gaW5wdXQgLSBUaGUgaW5wdXQgdG8gYmUgdHJhbnNmb3JtZWQgdG8gQmFzZTY0IGZvcm1hdC5cclxuICogQHBhcmFtIHtzdHJpbmd9IHR5cGUgLSBUaGUgb3JpZ2luYWwgZXhwb3J0IHR5cGUuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtzdHJpbmd9IFRoZSBCYXNlNjQgc3RyaW5nIHJlcHJlc2VudGF0aW9uIG9mIHRoZSBpbnB1dC5cclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiBnZXRCYXNlNjQoaW5wdXQsIHR5cGUpIHtcclxuICAvLyBGb3IgcGRmIGFuZCBzdmcgdHlwZXMgdGhlIGlucHV0IG11c3QgYmUgdHJhbnNmb3JtZWQgdG8gQmFzZTY0IGZyb20gYSBidWZmZXJcclxuICBpZiAodHlwZSA9PT0gJ3BkZicgfHwgdHlwZSA9PSAnc3ZnJykge1xyXG4gICAgcmV0dXJuIEJ1ZmZlci5mcm9tKGlucHV0LCAndXRmOCcpLnRvU3RyaW5nKCdiYXNlNjQnKTtcclxuICB9XHJcblxyXG4gIC8vIEZvciBwbmcgYW5kIGpwZWcgaW5wdXQgaXMgYWxyZWFkeSBhIEJhc2U2NCBzdHJpbmdcclxuICByZXR1cm4gaW5wdXQ7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBSZXR1cm5zIHN0cmluZ2lmaWVkIGRhdGUgd2l0aG91dCB0aGUgR01UIHRleHQgaW5mb3JtYXRpb24uXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBnZXROZXdEYXRlXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gZ2V0TmV3RGF0ZSgpIHtcclxuICAvLyBHZXQgcmlkIG9mIHRoZSBHTVQgdGV4dCBpbmZvcm1hdGlvblxyXG4gIHJldHVybiBuZXcgRGF0ZSgpLnRvU3RyaW5nKCkuc3BsaXQoJygnKVswXS50cmltKCk7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBSZXR1cm5zIHRoZSBzdG9yZWQgdGltZSB2YWx1ZSBpbiBtaWxsaXNlY29uZHMuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBnZXROZXdEYXRlVGltZVxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIGdldE5ld0RhdGVUaW1lKCkge1xyXG4gIHJldHVybiBuZXcgRGF0ZSgpLmdldFRpbWUoKTtcclxufVxyXG5cclxuLyoqXHJcbiAqIENoZWNrcyBpZiB0aGUgZ2l2ZW4gaXRlbSBpcyBhbiBvYmplY3QuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBpc09iamVjdFxyXG4gKlxyXG4gKiBAcGFyYW0ge3Vua25vd259IGl0ZW0gLSBUaGUgaXRlbSB0byBiZSBjaGVja2VkLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7Ym9vbGVhbn0gVHJ1ZSBpZiB0aGUgaXRlbSBpcyBhbiBvYmplY3QsIGZhbHNlIG90aGVyd2lzZS5cclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiBpc09iamVjdChpdGVtKSB7XHJcbiAgcmV0dXJuIE9iamVjdC5wcm90b3R5cGUudG9TdHJpbmcuY2FsbChpdGVtKSA9PT0gJ1tvYmplY3QgT2JqZWN0XSc7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBDaGVja3MgaWYgdGhlIGdpdmVuIG9iamVjdCBpcyBlbXB0eS5cclxuICpcclxuICogQGZ1bmN0aW9uIGlzT2JqZWN0RW1wdHlcclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IGl0ZW0gLSBUaGUgb2JqZWN0IHRvIGJlIGNoZWNrZWQuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtib29sZWFufSBUcnVlIGlmIHRoZSBvYmplY3QgaXMgZW1wdHksIGZhbHNlIG90aGVyd2lzZS5cclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiBpc09iamVjdEVtcHR5KGl0ZW0pIHtcclxuICByZXR1cm4gKFxyXG4gICAgdHlwZW9mIGl0ZW0gPT09ICdvYmplY3QnICYmXHJcbiAgICAhQXJyYXkuaXNBcnJheShpdGVtKSAmJlxyXG4gICAgaXRlbSAhPT0gbnVsbCAmJlxyXG4gICAgT2JqZWN0LmtleXMoaXRlbSkubGVuZ3RoID09PSAwXHJcbiAgKTtcclxufVxyXG5cclxuLyoqXHJcbiAqIENoZWNrcyBpZiBhIHByaXZhdGUgSVAgcmFuZ2UgVVJMIGlzIGZvdW5kIGluIHRoZSBnaXZlbiBzdHJpbmcuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBpc1ByaXZhdGVSYW5nZVVybEZvdW5kXHJcbiAqXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSBpdGVtIC0gVGhlIHN0cmluZyB0byBiZSBjaGVja2VkIGZvciBhIHByaXZhdGUgSVAgcmFuZ2UgVVJMLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7Ym9vbGVhbn0gVHJ1ZSBpZiBhIHByaXZhdGUgSVAgcmFuZ2UgVVJMIGlzIGZvdW5kLCBmYWxzZSBvdGhlcndpc2UuXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gaXNQcml2YXRlUmFuZ2VVcmxGb3VuZChpdGVtKSB7XHJcbiAgY29uc3QgcmVnZXhQYXR0ZXJucyA9IFtcclxuICAgIC94bGluazpocmVmPVwiKD86aHR0cDpcXC9cXC98aHR0cHM6XFwvXFwvKT9sb2NhbGhvc3RcXGIvLFxyXG4gICAgL3hsaW5rOmhyZWY9XCIoPzpodHRwOlxcL1xcL3xodHRwczpcXC9cXC8pPzEwXFwuXFxkezEsM31cXC5cXGR7MSwzfVxcLlxcZHsxLDN9XFxiLyxcclxuICAgIC94bGluazpocmVmPVwiKD86aHR0cDpcXC9cXC98aHR0cHM6XFwvXFwvKT8xMjdcXC5cXGR7MSwzfVxcLlxcZHsxLDN9XFwuXFxkezEsM31cXGIvLFxyXG4gICAgL3hsaW5rOmhyZWY9XCIoPzpodHRwOlxcL1xcL3xodHRwczpcXC9cXC8pPzE3MlxcLigxWzYtOV18MlswLTldfDNbMC0xXSlcXC5cXGR7MSwzfVxcLlxcZHsxLDN9XFxiLyxcclxuICAgIC94bGluazpocmVmPVwiKD86aHR0cDpcXC9cXC98aHR0cHM6XFwvXFwvKT8xOTJcXC4xNjhcXC5cXGR7MSwzfVxcLlxcZHsxLDN9XFxiL1xyXG4gIF07XHJcblxyXG4gIHJldHVybiByZWdleFBhdHRlcm5zLnNvbWUoKHBhdHRlcm4pID0+IHBhdHRlcm4udGVzdChpdGVtKSk7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBVdGlsaXR5IHRvIG1lYXN1cmUgZWxhcHNlZCB0aW1lIHVzaW5nIHRoZSBOb2RlLmpzIGBwcm9jZXNzLmhydGltZSgpYCBtZXRob2QuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBtZWFzdXJlVGltZVxyXG4gKlxyXG4gKiBAcmV0dXJucyB7RnVuY3Rpb259IEEgZnVuY3Rpb24gdG8gY2FsY3VsYXRlIHRoZSBlbGFwc2VkIHRpbWUgaW4gbWlsbGlzZWNvbmRzLlxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIG1lYXN1cmVUaW1lKCkge1xyXG4gIGNvbnN0IHN0YXJ0ID0gcHJvY2Vzcy5ocnRpbWUuYmlnaW50KCk7XHJcbiAgcmV0dXJuICgpID0+IE51bWJlcihwcm9jZXNzLmhydGltZS5iaWdpbnQoKSAtIHN0YXJ0KSAvIDEwMDAwMDA7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBSb3VuZHMgYSBudW1iZXIgdG8gdGhlIHNwZWNpZmllZCBwcmVjaXNpb24uXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiByb3VuZE51bWJlclxyXG4gKlxyXG4gKiBAcGFyYW0ge251bWJlcn0gdmFsdWUgLSBUaGUgbnVtYmVyIHRvIGJlIHJvdW5kZWQuXHJcbiAqIEBwYXJhbSB7bnVtYmVyfSBwcmVjaXNpb24gLSBUaGUgbnVtYmVyIG9mIGRlY2ltYWwgcGxhY2VzIHRvIHJvdW5kIHRvLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7bnVtYmVyfSBUaGUgcm91bmRlZCBudW1iZXIuXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gcm91bmROdW1iZXIodmFsdWUsIHByZWNpc2lvbiA9IDEpIHtcclxuICBjb25zdCBtdWx0aXBsaWVyID0gTWF0aC5wb3coMTAsIHByZWNpc2lvbiB8fCAwKTtcclxuICByZXR1cm4gTWF0aC5yb3VuZCgrdmFsdWUgKiBtdWx0aXBsaWVyKSAvIG11bHRpcGxpZXI7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBDb252ZXJ0cyBhIHZhbHVlIHRvIGEgYm9vbGVhbi5cclxuICpcclxuICogQGZ1bmN0aW9uIHRvQm9vbGVhblxyXG4gKlxyXG4gKiBAcGFyYW0ge3Vua25vd259IGl0ZW0gLSBUaGUgdmFsdWUgdG8gYmUgY29udmVydGVkIHRvIGEgYm9vbGVhbi5cclxuICpcclxuICogQHJldHVybnMge2Jvb2xlYW59IFRoZSBib29sZWFuIHJlcHJlc2VudGF0aW9uIG9mIHRoZSBpbnB1dCB2YWx1ZS5cclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiB0b0Jvb2xlYW4oaXRlbSkge1xyXG4gIHJldHVybiBbJ2ZhbHNlJywgJ3VuZGVmaW5lZCcsICdudWxsJywgJ05hTicsICcwJywgJyddLmluY2x1ZGVzKGl0ZW0pXHJcbiAgICA/IGZhbHNlXHJcbiAgICA6ICEhaXRlbTtcclxufVxyXG5cclxuLyoqXHJcbiAqIFdyYXBzIGN1c3RvbSBjb2RlIHRvIGV4ZWN1dGUgaXQgc2FmZWx5LlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gd3JhcEFyb3VuZFxyXG4gKlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gY3VzdG9tQ29kZSAtIFRoZSBjdXN0b20gY29kZSB0byBiZSB3cmFwcGVkLlxyXG4gKiBAcGFyYW0ge2Jvb2xlYW59IGFsbG93RmlsZVJlc291cmNlcyAtIEZsYWcgdG8gYWxsb3cgbG9hZGluZyBjb2RlIGZyb20gYSBmaWxlLlxyXG4gKiBAcGFyYW0ge2Jvb2xlYW59IFtpc0NhbGxiYWNrPWZhbHNlXSAtIEZsYWcgdGhhdCBpbmRpY2F0ZXMgdGhlIHJldHVybmVkIGNvZGVcclxuICogbXVzdCBiZSBpbiBhIGNhbGxiYWNrIGZvcm1hdC5cclxuICpcclxuICogQHJldHVybnMgeyhzdHJpbmd8bnVsbCl9IFRoZSB3cmFwcGVkIGN1c3RvbSBjb2RlIG9yIG51bGwgaWYgd3JhcHBpbmcgZmFpbHMuXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gd3JhcEFyb3VuZChjdXN0b21Db2RlLCBhbGxvd0ZpbGVSZXNvdXJjZXMsIGlzQ2FsbGJhY2sgPSBmYWxzZSkge1xyXG4gIGlmIChjdXN0b21Db2RlICYmIHR5cGVvZiBjdXN0b21Db2RlID09PSAnc3RyaW5nJykge1xyXG4gICAgY3VzdG9tQ29kZSA9IGN1c3RvbUNvZGUudHJpbSgpO1xyXG5cclxuICAgIGlmIChjdXN0b21Db2RlLmVuZHNXaXRoKCcuanMnKSkge1xyXG4gICAgICAvLyBMb2FkIGEgZmlsZSBpZiB0aGUgZmlsZSByZXNvdXJjZXMgYXJlIGFsbG93ZWRcclxuICAgICAgcmV0dXJuIGFsbG93RmlsZVJlc291cmNlc1xyXG4gICAgICAgID8gd3JhcEFyb3VuZChcclxuICAgICAgICAgICAgcmVhZEZpbGVTeW5jKGdldEFic29sdXRlUGF0aChjdXN0b21Db2RlKSwgJ3V0ZjgnKSxcclxuICAgICAgICAgICAgYWxsb3dGaWxlUmVzb3VyY2VzLFxyXG4gICAgICAgICAgICBpc0NhbGxiYWNrXHJcbiAgICAgICAgICApXHJcbiAgICAgICAgOiBudWxsO1xyXG4gICAgfSBlbHNlIGlmIChcclxuICAgICAgIWlzQ2FsbGJhY2sgJiZcclxuICAgICAgKGN1c3RvbUNvZGUuc3RhcnRzV2l0aCgnZnVuY3Rpb24oKScpIHx8XHJcbiAgICAgICAgY3VzdG9tQ29kZS5zdGFydHNXaXRoKCdmdW5jdGlvbiAoKScpIHx8XHJcbiAgICAgICAgY3VzdG9tQ29kZS5zdGFydHNXaXRoKCcoKT0+JykgfHxcclxuICAgICAgICBjdXN0b21Db2RlLnN0YXJ0c1dpdGgoJygpID0+JykpXHJcbiAgICApIHtcclxuICAgICAgLy8gVHJlYXQgYSBmdW5jdGlvbiBhcyBhIHNlbGYtaW52b2tpbmcgZXhwcmVzc2lvblxyXG4gICAgICByZXR1cm4gYCgke2N1c3RvbUNvZGV9KSgpYDtcclxuICAgIH1cclxuXHJcbiAgICAvLyBPciByZXR1cm4gYXMgYSBzdHJpbmdpZmllZCBjb2RlXHJcbiAgICByZXR1cm4gY3VzdG9tQ29kZS5yZXBsYWNlKC87JC8sICcnKTtcclxuICB9XHJcbn1cclxuXHJcbmV4cG9ydCBkZWZhdWx0IHtcclxuICBfX2Rpcm5hbWUsXHJcbiAgY2xlYXJUZXh0LFxyXG4gIGRlZXBDb3B5LFxyXG4gIGV4cEJhY2tvZmYsXHJcbiAgZml4Q29uc3RyLFxyXG4gIGZpeE91dGZpbGUsXHJcbiAgZml4VHlwZSxcclxuICBnZXRBYnNvbHV0ZVBhdGgsXHJcbiAgZ2V0QmFzZTY0LFxyXG4gIGdldE5ld0RhdGUsXHJcbiAgZ2V0TmV3RGF0ZVRpbWUsXHJcbiAgaXNPYmplY3QsXHJcbiAgaXNPYmplY3RFbXB0eSxcclxuICBpc1ByaXZhdGVSYW5nZVVybEZvdW5kLFxyXG4gIG1lYXN1cmVUaW1lLFxyXG4gIHJvdW5kTnVtYmVyLFxyXG4gIHRvQm9vbGVhbixcclxuICB3cmFwQXJvdW5kXHJcbn07XHJcbiIsIi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXHJcblxyXG5IaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXJcclxuXHJcbkNvcHlyaWdodCAoYykgMjAxNi0yMDI1LCBIaWdoc29mdFxyXG5cclxuTGljZW5jZWQgdW5kZXIgdGhlIE1JVCBsaWNlbmNlLlxyXG5cclxuQWRkaXRpb25hbGx5IGEgdmFsaWQgSGlnaGNoYXJ0cyBsaWNlbnNlIGlzIHJlcXVpcmVkIGZvciB1c2UuXHJcblxyXG5TZWUgTElDRU5TRSBmaWxlIGluIHJvb3QgZm9yIGRldGFpbHMuXHJcblxyXG4qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xyXG5cclxuLyoqXHJcbiAqIEBvdmVydmlldyBBIG1vZHVsZSBmb3IgbWFuYWdpbmcgbG9nZ2luZyBmdW5jdGlvbmFsaXR5IHdpdGggY3VzdG9taXphYmxlXHJcbiAqIGxvZyBsZXZlbHMsIGNvbnNvbGUgYW5kIGZpbGUgbG9nZ2luZyBvcHRpb25zLCBhbmQgZXJyb3IgaGFuZGxpbmcgc3VwcG9ydC5cclxuICogVGhlIG1vZHVsZSBhbHNvIGVuc3VyZXMgdGhhdCBmaWxlLWJhc2VkIGxvZ3MgYXJlIHN0b3JlZCBpbiBhIHN0cnVjdHVyZWRcclxuICogZGlyZWN0b3J5LCBjcmVhdGluZyB0aGUgbmVjZXNzYXJ5IHBhdGhzIGF1dG9tYXRpY2FsbHkgaWYgdGhleSBkbyBub3QgZXhpc3QuXHJcbiAqL1xyXG5cclxuaW1wb3J0IHsgYXBwZW5kRmlsZSwgZXhpc3RzU3luYywgbWtkaXJTeW5jIH0gZnJvbSAnZnMnO1xyXG5pbXBvcnQgeyBqb2luIH0gZnJvbSAncGF0aCc7XHJcblxyXG5pbXBvcnQgeyBnZXRBYnNvbHV0ZVBhdGgsIGdldE5ld0RhdGUgfSBmcm9tICcuL3V0aWxzLmpzJztcclxuXHJcbi8vIFRoZSBhdmFpbGFibGUgY29sb3JzXHJcbmNvbnN0IGNvbG9ycyA9IFsncmVkJywgJ3llbGxvdycsICdibHVlJywgJ2dyYXknLCAnZ3JlZW4nXTtcclxuXHJcbi8vIFRoZSBkZWZhdWx0IGxvZ2dpbmcgY29uZmlnXHJcbmNvbnN0IGxvZ2dpbmcgPSB7XHJcbiAgLy8gRmxhZ3MgZm9yIGxvZ2dpbmcgc3RhdHVzXHJcbiAgdG9Db25zb2xlOiB0cnVlLFxyXG4gIHRvRmlsZTogZmFsc2UsXHJcbiAgcGF0aENyZWF0ZWQ6IGZhbHNlLFxyXG4gIC8vIEZ1bGwgcGF0aCB0byB0aGUgbG9nIGZpbGVcclxuICBwYXRoVG9Mb2c6ICcnLFxyXG4gIC8vIExvZyBsZXZlbHNcclxuICBsZXZlbHNEZXNjOiBbXHJcbiAgICB7XHJcbiAgICAgIHRpdGxlOiAnZXJyb3InLFxyXG4gICAgICBjb2xvcjogY29sb3JzWzBdXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0aXRsZTogJ3dhcm5pbmcnLFxyXG4gICAgICBjb2xvcjogY29sb3JzWzFdXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0aXRsZTogJ25vdGljZScsXHJcbiAgICAgIGNvbG9yOiBjb2xvcnNbMl1cclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHRpdGxlOiAndmVyYm9zZScsXHJcbiAgICAgIGNvbG9yOiBjb2xvcnNbM11cclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHRpdGxlOiAnYmVuY2htYXJrJyxcclxuICAgICAgY29sb3I6IGNvbG9yc1s0XVxyXG4gICAgfVxyXG4gIF1cclxufTtcclxuXHJcbi8qKlxyXG4gKiBMb2dzIGEgbWVzc2FnZSB3aXRoIGEgc3BlY2lmaWVkIGxvZyBsZXZlbC4gQWNjZXB0cyBhIHZhcmlhYmxlIG51bWJlclxyXG4gKiBvZiBhcmd1bWVudHMuIFRoZSBhcmd1bWVudHMgYWZ0ZXIgdGhlIGBsZXZlbGAgYXJlIHBhc3NlZCB0byBgY29uc29sZS5sb2dgXHJcbiAqIGFuZC9vciB1c2VkIHRvIGNvbnN0cnVjdCBhbmQgYXBwZW5kIG1lc3NhZ2VzIHRvIGEgbG9nIGZpbGUuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBsb2dcclxuICpcclxuICogQHBhcmFtIHsuLi51bmtub3dufSBhcmdzIC0gQW4gYXJyYXkgb2YgYXJndW1lbnRzIHdoZXJlIHRoZSBmaXJzdCBpcyB0aGUgbG9nXHJcbiAqIGxldmVsIGFuZCB0aGUgcmVtYWluaW5nIGFyZSBzdHJpbmdzIHVzZWQgdG8gYnVpbGQgdGhlIGxvZyBtZXNzYWdlLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7dm9pZH0gRXhpdHMgdGhlIGZ1bmN0aW9uIGV4ZWN1dGlvbiBpZiBhdHRlbXB0aW5nIHRvIGxvZyBhdCBhIGxldmVsXHJcbiAqIGhpZ2hlciB0aGFuIGFsbG93ZWQuXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gbG9nKC4uLmFyZ3MpIHtcclxuICBjb25zdCBbbmV3TGV2ZWwsIC4uLnRleHRzXSA9IGFyZ3M7XHJcblxyXG4gIC8vIEN1cnJlbnQgbG9nZ2luZyBvcHRpb25zXHJcbiAgY29uc3QgeyBsZXZlbHNEZXNjLCBsZXZlbCB9ID0gbG9nZ2luZztcclxuXHJcbiAgLy8gQ2hlY2sgaWYgdGhlIGxvZyBsZXZlbCBpcyB3aXRoaW4gYSBjb3JyZWN0IHJhbmdlIG9yIGlzIGl0IGEgYmVuY2htYXJrIGxvZ1xyXG4gIGlmIChcclxuICAgIG5ld0xldmVsICE9PSA1ICYmXHJcbiAgICAobmV3TGV2ZWwgPT09IDAgfHwgbmV3TGV2ZWwgPiBsZXZlbCB8fCBsZXZlbCA+IGxldmVsc0Rlc2MubGVuZ3RoKVxyXG4gICkge1xyXG4gICAgcmV0dXJuO1xyXG4gIH1cclxuXHJcbiAgLy8gQ3JlYXRlIGEgbWVzc2FnZSdzIHByZWZpeFxyXG4gIGNvbnN0IHByZWZpeCA9IGAke2dldE5ld0RhdGUoKX0gWyR7bGV2ZWxzRGVzY1tuZXdMZXZlbCAtIDFdLnRpdGxlfV0gLWA7XHJcblxyXG4gIC8vIExvZyB0byBmaWxlXHJcbiAgaWYgKGxvZ2dpbmcudG9GaWxlKSB7XHJcbiAgICBfbG9nVG9GaWxlKHRleHRzLCBwcmVmaXgpO1xyXG4gIH1cclxuXHJcbiAgLy8gTG9nIHRvIGNvbnNvbGVcclxuICBpZiAobG9nZ2luZy50b0NvbnNvbGUpIHtcclxuICAgIGNvbnNvbGUubG9nLmFwcGx5KFxyXG4gICAgICB1bmRlZmluZWQsXHJcbiAgICAgIFtwcmVmaXgudG9TdHJpbmcoKVtsb2dnaW5nLmxldmVsc0Rlc2NbbmV3TGV2ZWwgLSAxXS5jb2xvcl1dLmNvbmNhdCh0ZXh0cylcclxuICAgICk7XHJcbiAgfVxyXG59XHJcblxyXG4vKipcclxuICogTG9ncyBhbiBlcnJvciBtZXNzYWdlIGFsb25nIHdpdGggaXRzIHN0YWNrIHRyYWNlLiBPcHRpb25hbGx5LCBhIGN1c3RvbSBtZXNzYWdlXHJcbiAqIGNhbiBiZSBwcm92aWRlZC5cclxuICpcclxuICogQGZ1bmN0aW9uIGxvZ1dpdGhTdGFja1xyXG4gKlxyXG4gKiBAcGFyYW0ge251bWJlcn0gbmV3TGV2ZWwgLSBUaGUgbG9nIGxldmVsLlxyXG4gKiBAcGFyYW0ge0Vycm9yfSBlcnJvciAtIFRoZSBlcnJvciBvYmplY3QgY29udGFpbmluZyB0aGUgc3RhY2sgdHJhY2UuXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSBjdXN0b21NZXNzYWdlIC0gQW4gb3B0aW9uYWwgY3VzdG9tIG1lc3NhZ2UgdG8gYmUgaW5jbHVkZWRcclxuICogaW4gdGhlIGxvZyBhbG9uZ3NpZGUgdGhlIGVycm9yLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7dm9pZH0gRXhpdHMgdGhlIGZ1bmN0aW9uIGV4ZWN1dGlvbiBpZiBhdHRlbXB0aW5nIHRvIGxvZyBhdCBhIGxldmVsXHJcbiAqIGhpZ2hlciB0aGFuIGFsbG93ZWQuXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gbG9nV2l0aFN0YWNrKG5ld0xldmVsLCBlcnJvciwgY3VzdG9tTWVzc2FnZSkge1xyXG4gIC8vIEdldCB0aGUgbWFpbiBtZXNzYWdlXHJcbiAgY29uc3QgbWFpbk1lc3NhZ2UgPSBjdXN0b21NZXNzYWdlIHx8IChlcnJvciAmJiBlcnJvci5tZXNzYWdlKSB8fCAnJztcclxuXHJcbiAgLy8gQ3VycmVudCBsb2dnaW5nIG9wdGlvbnNcclxuICBjb25zdCB7IGxldmVsLCBsZXZlbHNEZXNjIH0gPSBsb2dnaW5nO1xyXG5cclxuICAvLyBDaGVjayBpZiB0aGUgbG9nIGxldmVsIGlzIHdpdGhpbiBhIGNvcnJlY3QgcmFuZ2VcclxuICBpZiAobmV3TGV2ZWwgPT09IDAgfHwgbmV3TGV2ZWwgPiBsZXZlbCB8fCBsZXZlbCA+IGxldmVsc0Rlc2MubGVuZ3RoKSB7XHJcbiAgICByZXR1cm47XHJcbiAgfVxyXG5cclxuICAvLyBDcmVhdGUgYSBtZXNzYWdlJ3MgcHJlZml4XHJcbiAgY29uc3QgcHJlZml4ID0gYCR7Z2V0TmV3RGF0ZSgpfSBbJHtsZXZlbHNEZXNjW25ld0xldmVsIC0gMV0udGl0bGV9XSAtYDtcclxuXHJcbiAgLy8gQWRkIHRoZSB3aG9sZSBzdGFjayBtZXNzYWdlXHJcbiAgY29uc3Qgc3RhY2tNZXNzYWdlID0gZXJyb3IgJiYgZXJyb3Iuc3RhY2s7XHJcblxyXG4gIC8vIENvbWJpbmUgY3VzdG9tIG1lc3NhZ2Ugb3IgZXJyb3IgbWVzc2FnZSB3aXRoIGVycm9yIHN0YWNrIG1lc3NhZ2UsIGlmIGV4aXN0c1xyXG4gIGNvbnN0IHRleHRzID0gW21haW5NZXNzYWdlXTtcclxuICBpZiAoc3RhY2tNZXNzYWdlKSB7XHJcbiAgICB0ZXh0cy5wdXNoKCdcXG4nLCBzdGFja01lc3NhZ2UpO1xyXG4gIH1cclxuXHJcbiAgLy8gTG9nIHRvIGZpbGVcclxuICBpZiAobG9nZ2luZy50b0ZpbGUpIHtcclxuICAgIF9sb2dUb0ZpbGUodGV4dHMsIHByZWZpeCk7XHJcbiAgfVxyXG5cclxuICAvLyBMb2cgdG8gY29uc29sZVxyXG4gIGlmIChsb2dnaW5nLnRvQ29uc29sZSkge1xyXG4gICAgY29uc29sZS5sb2cuYXBwbHkoXHJcbiAgICAgIHVuZGVmaW5lZCxcclxuICAgICAgW3ByZWZpeC50b1N0cmluZygpW2xvZ2dpbmcubGV2ZWxzRGVzY1tuZXdMZXZlbCAtIDFdLmNvbG9yXV0uY29uY2F0KFtcclxuICAgICAgICB0ZXh0cy5zaGlmdCgpW2NvbG9yc1tuZXdMZXZlbCAtIDFdXSxcclxuICAgICAgICAuLi50ZXh0c1xyXG4gICAgICBdKVxyXG4gICAgKTtcclxuICB9XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBMb2dzIGFuIGVycm9yIG1lc3NhZ2UgcmVsYXRlZCB0byBab2QgdmFsaWRhdGlvbiBpc3N1ZXMuIE9wdGlvbmFsbHksIGEgY3VzdG9tXHJcbiAqIG1lc3NhZ2UgY2FuIGJlIHByb3ZpZGVkLlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gbG9nWm9kSXNzdWVzXHJcbiAqXHJcbiAqIEBwYXJhbSB7bnVtYmVyfSBuZXdMZXZlbCAtIFRoZSBsb2cgbGV2ZWwuXHJcbiAqIEBwYXJhbSB7RXJyb3JbXX0gaXNzdWVzIC0gQW4gYXJyYXkgb2YgWm9kIHZhbGlkYXRpb24gaXNzdWVzLlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gY3VzdG9tTWVzc2FnZSAtIEFuIG9wdGlvbmFsIGN1c3RvbSBtZXNzYWdlIHRvIGJlIGluY2x1ZGVkXHJcbiAqIGluIHRoZSBsb2cgYWxvbmdzaWRlIHRoZSBlcnJvci5cclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiBsb2dab2RJc3N1ZXMobmV3TGV2ZWwsIGlzc3VlcywgY3VzdG9tTWVzc2FnZSkge1xyXG4gIGxvZ1dpdGhTdGFjayhcclxuICAgIG5ld0xldmVsLFxyXG4gICAgbnVsbCxcclxuICAgIFtcclxuICAgICAgYCR7Y3VzdG9tTWVzc2FnZSB8fCAnW3ZhbGlkYXRpb25dIFZhbGlkYXRpb24gZXJyb3InfSAtIHRoZSBmb2xsb3dpbmcgWm9kIGlzc3VlcyBvY2N1cmVkOmAsXHJcbiAgICAgIC4uLihpc3N1ZXMgfHwgW10pLm1hcCgoaXNzdWUpID0+IGAtICR7aXNzdWUubWVzc2FnZX1gKVxyXG4gICAgXS5qb2luKCdcXG4nKVxyXG4gICk7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBJbml0aWFsaXplcyBsb2dnaW5nIHdpdGggdGhlIHNwZWNpZmllZCBsb2dnaW5nIGNvbmZpZ3VyYXRpb24uXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBpbml0TG9nZ2luZ1xyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gbG9nZ2luZ09wdGlvbnMgLSBUaGUgY29uZmlndXJhdGlvbiBvYmplY3QgY29udGFpbmluZ1xyXG4gKiBgbG9nZ2luZ2Agb3B0aW9ucy5cclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiBpbml0TG9nZ2luZyhsb2dnaW5nT3B0aW9ucykge1xyXG4gIC8vIEdldCBvcHRpb25zIGZyb20gdGhlIGBsb2dnaW5nT3B0aW9uc2Agb2JqZWN0XHJcbiAgY29uc3QgeyBsZXZlbCwgZGVzdCwgZmlsZSwgdG9Db25zb2xlLCB0b0ZpbGUgfSA9IGxvZ2dpbmdPcHRpb25zO1xyXG5cclxuICAvLyBSZXNldCBmbGFncyB0byB0aGUgZGVmYXVsdCB2YWx1ZXNcclxuICBsb2dnaW5nLnBhdGhDcmVhdGVkID0gZmFsc2U7XHJcbiAgbG9nZ2luZy5wYXRoVG9Mb2cgPSAnJztcclxuXHJcbiAgLy8gU2V0IHRoZSBsb2dnaW5nIGxldmVsXHJcbiAgc2V0TG9nTGV2ZWwobGV2ZWwpO1xyXG5cclxuICAvLyBTZXQgdGhlIGNvbnNvbGUgbG9nZ2luZ1xyXG4gIGVuYWJsZUNvbnNvbGVMb2dnaW5nKHRvQ29uc29sZSk7XHJcblxyXG4gIC8vIFNldCB0aGUgZmlsZSBsb2dnaW5nXHJcbiAgZW5hYmxlRmlsZUxvZ2dpbmcoZGVzdCwgZmlsZSwgdG9GaWxlKTtcclxufVxyXG5cclxuLyoqXHJcbiAqIFNldHMgdGhlIGxvZyBsZXZlbCB0byB0aGUgc3BlY2lmaWVkIHZhbHVlLiBMb2cgbGV2ZWxzIGFyZSAoYDBgID0gbm8gbG9nZ2luZyxcclxuICogYDFgID0gZXJyb3IsIGAyYCA9IHdhcm5pbmcsIGAzYCA9IG5vdGljZSwgYDRgID0gdmVyYm9zZSwgb3IgYDVgID0gYmVuY2htYXJrKS5cclxuICpcclxuICogQGZ1bmN0aW9uIHNldExvZ0xldmVsXHJcbiAqXHJcbiAqIEBwYXJhbSB7bnVtYmVyfSBsZXZlbCAtIFRoZSBsb2cgbGV2ZWwgdG8gYmUgc2V0LlxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIHNldExvZ0xldmVsKGxldmVsKSB7XHJcbiAgaWYgKFxyXG4gICAgTnVtYmVyLmlzSW50ZWdlcihsZXZlbCkgJiZcclxuICAgIGxldmVsID49IDAgJiZcclxuICAgIGxldmVsIDw9IGxvZ2dpbmcubGV2ZWxzRGVzYy5sZW5ndGhcclxuICApIHtcclxuICAgIC8vIFVwZGF0ZSB0aGUgbW9kdWxlIGxvZ2dpbmcncyBgbGV2ZWxgIG9wdGlvblxyXG4gICAgbG9nZ2luZy5sZXZlbCA9IGxldmVsO1xyXG4gIH1cclxufVxyXG5cclxuLyoqXHJcbiAqIEVuYWJsZXMgY29uc29sZSBsb2dnaW5nLlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gZW5hYmxlQ29uc29sZUxvZ2dpbmdcclxuICpcclxuICogQHBhcmFtIHtib29sZWFufSB0b0NvbnNvbGUgLSBUaGUgZmxhZyBmb3Igc2V0dGluZyB0aGUgbG9nZ2luZyB0byB0aGUgY29uc29sZS5cclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiBlbmFibGVDb25zb2xlTG9nZ2luZyh0b0NvbnNvbGUpIHtcclxuICAvLyBVcGRhdGUgdGhlIG1vZHVsZSBsb2dnaW5nJ3MgYHRvQ29uc29sZWAgb3B0aW9uXHJcbiAgbG9nZ2luZy50b0NvbnNvbGUgPSAhIXRvQ29uc29sZTtcclxufVxyXG5cclxuLyoqXHJcbiAqIEVuYWJsZXMgZmlsZSBsb2dnaW5nIHdpdGggdGhlIHNwZWNpZmllZCBkZXN0aW5hdGlvbiBhbmQgbG9nIGZpbGUgbmFtZS5cclxuICpcclxuICogQGZ1bmN0aW9uIGVuYWJsZUZpbGVMb2dnaW5nXHJcbiAqXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSBkZXN0IC0gVGhlIGRlc3RpbmF0aW9uIHBhdGggd2hlcmUgdGhlIGxvZyBmaWxlIHNob3VsZFxyXG4gKiBiZSBzYXZlZC5cclxuICogQHBhcmFtIHtzdHJpbmd9IGZpbGUgLSBUaGUgbmFtZSBvZiB0aGUgbG9nIGZpbGUuXHJcbiAqIEBwYXJhbSB7Ym9vbGVhbn0gdG9GaWxlIC0gQSBmbGFnIGluZGljYXRpbmcgd2hldGhlciBsb2dnaW5nIHNob3VsZFxyXG4gKiBiZSBkaXJlY3RlZCB0byBhIGZpbGUuXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gZW5hYmxlRmlsZUxvZ2dpbmcoZGVzdCwgZmlsZSwgdG9GaWxlKSB7XHJcbiAgLy8gVXBkYXRlIHRoZSBtb2R1bGUgbG9nZ2luZydzIGB0b0ZpbGVgIG9wdGlvblxyXG4gIGxvZ2dpbmcudG9GaWxlID0gISF0b0ZpbGU7XHJcblxyXG4gIC8vIFNldCB0aGUgYGRlc3RgIGFuZCBgZmlsZWAgb3B0aW9ucyBvbmx5IGlmIHRoZSBmaWxlIGxvZ2dpbmcgaXMgZW5hYmxlZFxyXG4gIGlmIChsb2dnaW5nLnRvRmlsZSkge1xyXG4gICAgbG9nZ2luZy5kZXN0ID0gZGVzdCB8fCAnJztcclxuICAgIGxvZ2dpbmcuZmlsZSA9IGZpbGUgfHwgJyc7XHJcbiAgfVxyXG59XHJcblxyXG4vKipcclxuICogTG9ncyB0aGUgcHJvdmlkZWQgdGV4dHMgdG8gYSBmaWxlLCBpZiBmaWxlIGxvZ2dpbmcgaXMgZW5hYmxlZC4gSXQgY3JlYXRlc1xyXG4gKiB0aGUgbmVjZXNzYXJ5IGRpcmVjdG9yeSBzdHJ1Y3R1cmUgaWYgbm90IGFscmVhZHkgY3JlYXRlZCBhbmQgYXBwZW5kc1xyXG4gKiB0aGUgY29udGVudCwgaW5jbHVkaW5nIGFuIG9wdGlvbmFsIHByZWZpeCwgdG8gdGhlIHNwZWNpZmllZCBsb2cgZmlsZS5cclxuICpcclxuICogQGZ1bmN0aW9uIF9sb2dUb0ZpbGVcclxuICpcclxuICogQHBhcmFtIHtBcnJheS48c3RyaW5nPn0gdGV4dHMgLSBBbiBhcnJheSBvZiB0ZXh0cyB0byBiZSBsb2dnZWQuXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSBwcmVmaXggLSBBbiBvcHRpb25hbCBwcmVmaXggdG8gYmUgYWRkZWQgdG8gZWFjaCBsb2cgZW50cnkuXHJcbiAqL1xyXG5mdW5jdGlvbiBfbG9nVG9GaWxlKHRleHRzLCBwcmVmaXgpIHtcclxuICBpZiAoIWxvZ2dpbmcucGF0aENyZWF0ZWQpIHtcclxuICAgIC8vIENyZWF0ZSBpZiBkb2VzIG5vdCBleGlzdFxyXG4gICAgIWV4aXN0c1N5bmMoZ2V0QWJzb2x1dGVQYXRoKGxvZ2dpbmcuZGVzdCkpICYmXHJcbiAgICAgIG1rZGlyU3luYyhnZXRBYnNvbHV0ZVBhdGgobG9nZ2luZy5kZXN0KSk7XHJcblxyXG4gICAgLy8gQ3JlYXRlIHRoZSBmdWxsIHBhdGhcclxuICAgIGxvZ2dpbmcucGF0aFRvTG9nID0gZ2V0QWJzb2x1dGVQYXRoKGpvaW4obG9nZ2luZy5kZXN0LCBsb2dnaW5nLmZpbGUpKTtcclxuXHJcbiAgICAvLyBXZSBub3cgYXNzdW1lIHRoZSBwYXRoIGlzIGF2YWlsYWJsZSwgZS5nLiBpdCdzIHRoZSByZXNwb25zaWJpbGl0eVxyXG4gICAgLy8gb2YgdGhlIHVzZXIgdG8gY3JlYXRlIHRoZSBwYXRoIHdpdGggdGhlIGNvcnJlY3QgYWNjZXNzIHJpZ2h0cy5cclxuICAgIGxvZ2dpbmcucGF0aENyZWF0ZWQgPSB0cnVlO1xyXG4gIH1cclxuXHJcbiAgLy8gQWRkIHRoZSBjb250ZW50IHRvIGEgZmlsZVxyXG4gIGFwcGVuZEZpbGUoXHJcbiAgICBsb2dnaW5nLnBhdGhUb0xvZyxcclxuICAgIFtwcmVmaXhdLmNvbmNhdCh0ZXh0cykuam9pbignICcpICsgJ1xcbicsXHJcbiAgICAoZXJyb3IpID0+IHtcclxuICAgICAgaWYgKGVycm9yICYmIGxvZ2dpbmcudG9GaWxlICYmIGxvZ2dpbmcucGF0aENyZWF0ZWQpIHtcclxuICAgICAgICBsb2dnaW5nLnRvRmlsZSA9IGZhbHNlO1xyXG4gICAgICAgIGxvZ2dpbmcucGF0aENyZWF0ZWQgPSBmYWxzZTtcclxuICAgICAgICBsb2dXaXRoU3RhY2soMiwgZXJyb3IsIGBbbG9nZ2VyXSBVbmFibGUgdG8gd3JpdGUgdG8gbG9nIGZpbGUuYCk7XHJcbiAgICAgIH1cclxuICAgIH1cclxuICApO1xyXG59XHJcblxyXG5leHBvcnQgZGVmYXVsdCB7XHJcbiAgbG9nLFxyXG4gIGxvZ1dpdGhTdGFjayxcclxuICBsb2dab2RJc3N1ZXMsXHJcbiAgaW5pdExvZ2dpbmcsXHJcbiAgc2V0TG9nTGV2ZWwsXHJcbiAgZW5hYmxlQ29uc29sZUxvZ2dpbmcsXHJcbiAgZW5hYmxlRmlsZUxvZ2dpbmdcclxufTtcclxuIiwiLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcclxuXHJcbkhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlclxyXG5cclxuQ29weXJpZ2h0IChjKSAyMDE2LTIwMjUsIEhpZ2hzb2Z0XHJcblxyXG5MaWNlbmNlZCB1bmRlciB0aGUgTUlUIGxpY2VuY2UuXHJcblxyXG5BZGRpdGlvbmFsbHkgYSB2YWxpZCBIaWdoY2hhcnRzIGxpY2Vuc2UgaXMgcmVxdWlyZWQgZm9yIHVzZS5cclxuXHJcblNlZSBMSUNFTlNFIGZpbGUgaW4gcm9vdCBmb3IgZGV0YWlscy5cclxuXHJcbioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXHJcblxyXG4vKipcclxuICogQG92ZXJ2aWV3IENvbmZpZ3VyYXRpb24gbWFuYWdlbWVudCBtb2R1bGUgZm9yIHRoZSBIaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXIuXHJcbiAqIFByb3ZpZGVzIGRlZmF1bHQgY29uZmlndXJhdGlvbnMgdGhhdCBzdXBwb3J0IGVudmlyb25tZW50IHZhcmlhYmxlcywgQ0xJXHJcbiAqIGFyZ3VtZW50cywgYW5kIGludGVyYWN0aXZlIHByb21wdHMgZm9yIGN1c3RvbWl6YXRpb24gb2Ygb3B0aW9ucyBhbmQgZmVhdHVyZXMuXHJcbiAqIEFkZGl0aW9uYWxseSwgaXQgbWFwcyBsZWdhY3kgb3B0aW9ucyB0byBtb2Rlcm4gc3RydWN0dXJlcywgZ2VuZXJhdGVzIG5lc3RlZFxyXG4gKiBhcmd1bWVudCBtYXBwaW5ncywgYW5kIGRpc3BsYXlzIENMSSB1c2FnZSBpbmZvcm1hdGlvbi5cclxuICovXHJcblxyXG4vKipcclxuICogVGhlIGNvbmZpZ3VyYXRpb24gb2JqZWN0IGNvbnRhaW5pbmcgYWxsIGF2YWlsYWJsZSBvcHRpb25zLCBvcmdhbml6ZWRcclxuICogYnkgc2VjdGlvbnMuXHJcbiAqXHJcbiAqIFRoaXMgb2JqZWN0IGluY2x1ZGVzOlxyXG4gKiAtIERlZmF1bHQgdmFsdWVzIGZvciBlYWNoIG9wdGlvblxyXG4gKiAtIERhdGEgdHlwZXMgZm9yIHZhbGlkYXRpb25cclxuICogLSBOYW1lcyBvZiBjb3JyZXNwb25kaW5nIGVudmlyb25tZW50IHZhcmlhYmxlc1xyXG4gKiAtIERlc2NyaXB0aW9ucyBvZiBlYWNoIHByb3BlcnR5XHJcbiAqIC0gSW5mb3JtYXRpb24gdXNlZCBmb3IgcHJvbXB0cyBpbiBpbnRlcmFjdGl2ZSBjb25maWd1cmF0aW9uXHJcbiAqIC0gW09wdGlvbmFsXSBDb3JyZXNwb25kaW5nIENMSSBhcmd1bWVudCBuYW1lcyBmb3IgQ0xJIHVzYWdlXHJcbiAqIC0gW09wdGlvbmFsXSBMZWdhY3kgbmFtZXMgZnJvbSB0aGUgcHJldmlvdXMgUGhhbnRvbUpTLWJhc2VkIHNlcnZlclxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IGRlZmF1bHRDb25maWcgPSB7XHJcbiAgcHVwcGV0ZWVyOiB7XHJcbiAgICBhcmdzOiB7XHJcbiAgICAgIHZhbHVlOiBbXHJcbiAgICAgICAgJy0tYWxsb3ctcnVubmluZy1pbnNlY3VyZS1jb250ZW50JyxcclxuICAgICAgICAnLS1hc2gtbm8tbnVkZ2VzJyxcclxuICAgICAgICAnLS1hdXRvcGxheS1wb2xpY3k9dXNlci1nZXN0dXJlLXJlcXVpcmVkJyxcclxuICAgICAgICAnLS1ibG9jay1uZXctd2ViLWNvbnRlbnRzJyxcclxuICAgICAgICAnLS1kaXNhYmxlLWFjY2VsZXJhdGVkLTJkLWNhbnZhcycsXHJcbiAgICAgICAgJy0tZGlzYWJsZS1iYWNrZ3JvdW5kLW5ldHdvcmtpbmcnLFxyXG4gICAgICAgICctLWRpc2FibGUtYmFja2dyb3VuZC10aW1lci10aHJvdHRsaW5nJyxcclxuICAgICAgICAnLS1kaXNhYmxlLWJhY2tncm91bmRpbmctb2NjbHVkZWQtd2luZG93cycsXHJcbiAgICAgICAgJy0tZGlzYWJsZS1icmVha3BhZCcsXHJcbiAgICAgICAgJy0tZGlzYWJsZS1jaGVja2VyLWltYWdpbmcnLFxyXG4gICAgICAgICctLWRpc2FibGUtY2xpZW50LXNpZGUtcGhpc2hpbmctZGV0ZWN0aW9uJyxcclxuICAgICAgICAnLS1kaXNhYmxlLWNvbXBvbmVudC1leHRlbnNpb25zLXdpdGgtYmFja2dyb3VuZC1wYWdlcycsXHJcbiAgICAgICAgJy0tZGlzYWJsZS1jb21wb25lbnQtdXBkYXRlJyxcclxuICAgICAgICAnLS1kaXNhYmxlLWRlZmF1bHQtYXBwcycsXHJcbiAgICAgICAgJy0tZGlzYWJsZS1kZXYtc2htLXVzYWdlJyxcclxuICAgICAgICAnLS1kaXNhYmxlLWRvbWFpbi1yZWxpYWJpbGl0eScsXHJcbiAgICAgICAgJy0tZGlzYWJsZS1leHRlbnNpb25zJyxcclxuICAgICAgICAnLS1kaXNhYmxlLWZlYXR1cmVzPUNhbGN1bGF0ZU5hdGl2ZVdpbk9jY2x1c2lvbixJbnRlcmVzdEZlZWRDb250ZW50U3VnZ2VzdGlvbnMsV2ViT1RQJyxcclxuICAgICAgICAnLS1kaXNhYmxlLWhhbmctbW9uaXRvcicsXHJcbiAgICAgICAgJy0tZGlzYWJsZS1pcGMtZmxvb2RpbmctcHJvdGVjdGlvbicsXHJcbiAgICAgICAgJy0tZGlzYWJsZS1sb2dnaW5nJyxcclxuICAgICAgICAnLS1kaXNhYmxlLW5vdGlmaWNhdGlvbnMnLFxyXG4gICAgICAgICctLWRpc2FibGUtb2ZmZXItc3RvcmUtdW5tYXNrZWQtd2FsbGV0LWNhcmRzJyxcclxuICAgICAgICAnLS1kaXNhYmxlLXBvcHVwLWJsb2NraW5nJyxcclxuICAgICAgICAnLS1kaXNhYmxlLXByaW50LXByZXZpZXcnLFxyXG4gICAgICAgICctLWRpc2FibGUtcHJvbXB0LW9uLXJlcG9zdCcsXHJcbiAgICAgICAgJy0tZGlzYWJsZS1yZW5kZXJlci1iYWNrZ3JvdW5kaW5nJyxcclxuICAgICAgICAnLS1kaXNhYmxlLXNlYXJjaC1lbmdpbmUtY2hvaWNlLXNjcmVlbicsXHJcbiAgICAgICAgJy0tZGlzYWJsZS1zZXNzaW9uLWNyYXNoZWQtYnViYmxlJyxcclxuICAgICAgICAnLS1kaXNhYmxlLXNldHVpZC1zYW5kYm94JyxcclxuICAgICAgICAnLS1kaXNhYmxlLXNpdGUtaXNvbGF0aW9uLXRyaWFscycsXHJcbiAgICAgICAgJy0tZGlzYWJsZS1zcGVlY2gtYXBpJyxcclxuICAgICAgICAnLS1kaXNhYmxlLXN5bmMnLFxyXG4gICAgICAgICctLWVuYWJsZS11bnNhZmUtd2ViZ3B1JyxcclxuICAgICAgICAnLS1oaWRlLWNyYXNoLXJlc3RvcmUtYnViYmxlJyxcclxuICAgICAgICAnLS1oaWRlLXNjcm9sbGJhcnMnLFxyXG4gICAgICAgICctLW1ldHJpY3MtcmVjb3JkaW5nLW9ubHknLFxyXG4gICAgICAgICctLW11dGUtYXVkaW8nLFxyXG4gICAgICAgICctLW5vLWRlZmF1bHQtYnJvd3Nlci1jaGVjaycsXHJcbiAgICAgICAgJy0tbm8tZmlyc3QtcnVuJyxcclxuICAgICAgICAnLS1uby1waW5ncycsXHJcbiAgICAgICAgJy0tbm8tc2FuZGJveCcsXHJcbiAgICAgICAgJy0tbm8tc3RhcnR1cC13aW5kb3cnLFxyXG4gICAgICAgICctLW5vLXp5Z290ZScsXHJcbiAgICAgICAgJy0tcGFzc3dvcmQtc3RvcmU9YmFzaWMnLFxyXG4gICAgICAgICctLXByb2Nlc3MtcGVyLXRhYicsXHJcbiAgICAgICAgJy0tdXNlLW1vY2sta2V5Y2hhaW4nXHJcbiAgICAgIF0sXHJcbiAgICAgIHR5cGVzOiBbJ3N0cmluZ1tdJ10sXHJcbiAgICAgIGVudkxpbms6ICdQVVBQRVRFRVJfQVJHUycsXHJcbiAgICAgIGNsaU5hbWU6ICdwdXBwZXRlZXJBcmdzJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdBcnJheSBvZiBQdXBwZXRlZXIgYXJndW1lbnRzJyxcclxuICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgIHR5cGU6ICdsaXN0JyxcclxuICAgICAgICBzZXBhcmF0b3I6ICc7J1xyXG4gICAgICB9XHJcbiAgICB9XHJcbiAgfSxcclxuICBoaWdoY2hhcnRzOiB7XHJcbiAgICB2ZXJzaW9uOiB7XHJcbiAgICAgIHZhbHVlOiAnbGF0ZXN0JyxcclxuICAgICAgdHlwZXM6IFsnc3RyaW5nJ10sXHJcbiAgICAgIGVudkxpbms6ICdISUdIQ0hBUlRTX1ZFUlNJT04nLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ0hpZ2hjaGFydHMgdmVyc2lvbicsXHJcbiAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICB0eXBlOiAndGV4dCdcclxuICAgICAgfVxyXG4gICAgfSxcclxuICAgIGNkblVybDoge1xyXG4gICAgICB2YWx1ZTogJ2h0dHBzOi8vY29kZS5oaWdoY2hhcnRzLmNvbScsXHJcbiAgICAgIHR5cGVzOiBbJ3N0cmluZyddLFxyXG4gICAgICBlbnZMaW5rOiAnSElHSENIQVJUU19DRE5fVVJMJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdDRE4gVVJMIGZvciBIaWdoY2hhcnRzIHNjcmlwdHMnLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ3RleHQnXHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICBmb3JjZUZldGNoOiB7XHJcbiAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgdHlwZXM6IFsnYm9vbGVhbiddLFxyXG4gICAgICBlbnZMaW5rOiAnSElHSENIQVJUU19GT1JDRV9GRVRDSCcsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnRmxhZyB0byByZWZldGNoIHNjcmlwdHMgYWZ0ZXIgZWFjaCBzZXJ2ZXIgcmVydW4nLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ3RvZ2dsZSdcclxuICAgICAgfVxyXG4gICAgfSxcclxuICAgIGNhY2hlUGF0aDoge1xyXG4gICAgICB2YWx1ZTogJy5jYWNoZScsXHJcbiAgICAgIHR5cGVzOiBbJ3N0cmluZyddLFxyXG4gICAgICBlbnZMaW5rOiAnSElHSENIQVJUU19DQUNIRV9QQVRIJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdEaXJlY3RvcnkgcGF0aCBmb3IgY2FjaGVkIEhpZ2hjaGFydHMgc2NyaXB0cycsXHJcbiAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICB0eXBlOiAndGV4dCdcclxuICAgICAgfVxyXG4gICAgfSxcclxuICAgIGNvcmVTY3JpcHRzOiB7XHJcbiAgICAgIHZhbHVlOiBbJ2hpZ2hjaGFydHMnLCAnaGlnaGNoYXJ0cy1tb3JlJywgJ2hpZ2hjaGFydHMtM2QnXSxcclxuICAgICAgdHlwZXM6IFsnc3RyaW5nW10nXSxcclxuICAgICAgZW52TGluazogJ0hJR0hDSEFSVFNfQ09SRV9TQ1JJUFRTJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdIaWdoY2hhcnRzIGNvcmUgc2NyaXB0cyB0byBmZXRjaCcsXHJcbiAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICB0eXBlOiAnbXVsdGlzZWxlY3QnLFxyXG4gICAgICAgIGluc3RydWN0aW9uczogJ1NwYWNlOiBTZWxlY3Qgc3BlY2lmaWMsIEE6IFNlbGVjdCBhbGwsIEVudGVyOiBDb25maXJtJ1xyXG4gICAgICB9XHJcbiAgICB9LFxyXG4gICAgbW9kdWxlU2NyaXB0czoge1xyXG4gICAgICB2YWx1ZTogW1xyXG4gICAgICAgICdzdG9jaycsXHJcbiAgICAgICAgJ21hcCcsXHJcbiAgICAgICAgJ2dhbnR0JyxcclxuICAgICAgICAnZXhwb3J0aW5nJyxcclxuICAgICAgICAncGFyYWxsZWwtY29vcmRpbmF0ZXMnLFxyXG4gICAgICAgICdhY2Nlc3NpYmlsaXR5JyxcclxuICAgICAgICAvLyAnYW5ub3RhdGlvbnMtYWR2YW5jZWQnLFxyXG4gICAgICAgICdib29zdC1jYW52YXMnLFxyXG4gICAgICAgICdib29zdCcsXHJcbiAgICAgICAgJ2RhdGEnLFxyXG4gICAgICAgICdkYXRhLXRvb2xzJyxcclxuICAgICAgICAnZHJhZ2dhYmxlLXBvaW50cycsXHJcbiAgICAgICAgJ3N0YXRpYy1zY2FsZScsXHJcbiAgICAgICAgJ2Jyb2tlbi1heGlzJyxcclxuICAgICAgICAnaGVhdG1hcCcsXHJcbiAgICAgICAgJ3RpbGVtYXAnLFxyXG4gICAgICAgICd0aWxlZHdlYm1hcCcsXHJcbiAgICAgICAgJ3RpbWVsaW5lJyxcclxuICAgICAgICAndHJlZW1hcCcsXHJcbiAgICAgICAgJ3RyZWVncmFwaCcsXHJcbiAgICAgICAgJ2l0ZW0tc2VyaWVzJyxcclxuICAgICAgICAnZHJpbGxkb3duJyxcclxuICAgICAgICAnaGlzdG9ncmFtLWJlbGxjdXJ2ZScsXHJcbiAgICAgICAgJ2J1bGxldCcsXHJcbiAgICAgICAgJ2Z1bm5lbCcsXHJcbiAgICAgICAgJ2Z1bm5lbDNkJyxcclxuICAgICAgICAnZ2VvaGVhdG1hcCcsXHJcbiAgICAgICAgJ3B5cmFtaWQzZCcsXHJcbiAgICAgICAgJ25ldHdvcmtncmFwaCcsXHJcbiAgICAgICAgJ292ZXJsYXBwaW5nLWRhdGFsYWJlbHMnLFxyXG4gICAgICAgICdwYXJldG8nLFxyXG4gICAgICAgICdwYXR0ZXJuLWZpbGwnLFxyXG4gICAgICAgICdwaWN0b3JpYWwnLFxyXG4gICAgICAgICdwcmljZS1pbmRpY2F0b3InLFxyXG4gICAgICAgICdzYW5rZXknLFxyXG4gICAgICAgICdhcmMtZGlhZ3JhbScsXHJcbiAgICAgICAgJ2RlcGVuZGVuY3ktd2hlZWwnLFxyXG4gICAgICAgICdzZXJpZXMtbGFiZWwnLFxyXG4gICAgICAgICdzZXJpZXMtb24tcG9pbnQnLFxyXG4gICAgICAgICdzb2xpZC1nYXVnZScsXHJcbiAgICAgICAgJ3NvbmlmaWNhdGlvbicsXHJcbiAgICAgICAgLy8gJ3N0b2NrLXRvb2xzJyxcclxuICAgICAgICAnc3RyZWFtZ3JhcGgnLFxyXG4gICAgICAgICdzdW5idXJzdCcsXHJcbiAgICAgICAgJ3ZhcmlhYmxlLXBpZScsXHJcbiAgICAgICAgJ3Zhcml3aWRlJyxcclxuICAgICAgICAndmVjdG9yJyxcclxuICAgICAgICAndmVubicsXHJcbiAgICAgICAgJ3dpbmRiYXJiJyxcclxuICAgICAgICAnd29yZGNsb3VkJyxcclxuICAgICAgICAneHJhbmdlJyxcclxuICAgICAgICAnbm8tZGF0YS10by1kaXNwbGF5JyxcclxuICAgICAgICAnZHJhZy1wYW5lcycsXHJcbiAgICAgICAgJ2RlYnVnZ2VyJyxcclxuICAgICAgICAnZHVtYmJlbGwnLFxyXG4gICAgICAgICdsb2xsaXBvcCcsXHJcbiAgICAgICAgJ2N5bGluZGVyJyxcclxuICAgICAgICAnb3JnYW5pemF0aW9uJyxcclxuICAgICAgICAnZG90cGxvdCcsXHJcbiAgICAgICAgJ21hcmtlci1jbHVzdGVycycsXHJcbiAgICAgICAgJ2hvbGxvd2NhbmRsZXN0aWNrJyxcclxuICAgICAgICAnaGVpa2luYXNoaScsXHJcbiAgICAgICAgJ2Zsb3dtYXAnLFxyXG4gICAgICAgICdleHBvcnQtZGF0YScsXHJcbiAgICAgICAgJ25hdmlnYXRvcicsXHJcbiAgICAgICAgJ3RleHRwYXRoJ1xyXG4gICAgICBdLFxyXG4gICAgICB0eXBlczogWydzdHJpbmdbXSddLFxyXG4gICAgICBlbnZMaW5rOiAnSElHSENIQVJUU19NT0RVTEVfU0NSSVBUUycsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnSGlnaGNoYXJ0cyBtb2R1bGUgc2NyaXB0cyB0byBmZXRjaCcsXHJcbiAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICB0eXBlOiAnbXVsdGlzZWxlY3QnLFxyXG4gICAgICAgIGluc3RydWN0aW9uczogJ1NwYWNlOiBTZWxlY3Qgc3BlY2lmaWMsIEE6IFNlbGVjdCBhbGwsIEVudGVyOiBDb25maXJtJ1xyXG4gICAgICB9XHJcbiAgICB9LFxyXG4gICAgaW5kaWNhdG9yU2NyaXB0czoge1xyXG4gICAgICB2YWx1ZTogWydpbmRpY2F0b3JzLWFsbCddLFxyXG4gICAgICB0eXBlczogWydzdHJpbmdbXSddLFxyXG4gICAgICBlbnZMaW5rOiAnSElHSENIQVJUU19JTkRJQ0FUT1JfU0NSSVBUUycsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnSGlnaGNoYXJ0cyBpbmRpY2F0b3Igc2NyaXB0cyB0byBmZXRjaCcsXHJcbiAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICB0eXBlOiAnbXVsdGlzZWxlY3QnLFxyXG4gICAgICAgIGluc3RydWN0aW9uczogJ1NwYWNlOiBTZWxlY3Qgc3BlY2lmaWMsIEE6IFNlbGVjdCBhbGwsIEVudGVyOiBDb25maXJtJ1xyXG4gICAgICB9XHJcbiAgICB9LFxyXG4gICAgY3VzdG9tU2NyaXB0czoge1xyXG4gICAgICB2YWx1ZTogW1xyXG4gICAgICAgICdodHRwczovL2NkbmpzLmNsb3VkZmxhcmUuY29tL2FqYXgvbGlicy9tb21lbnQuanMvMi4zMC4xL21vbWVudC5taW4uanMnLFxyXG4gICAgICAgICdodHRwczovL2NkbmpzLmNsb3VkZmxhcmUuY29tL2FqYXgvbGlicy9tb21lbnQtdGltZXpvbmUvMC41LjQ1L21vbWVudC10aW1lem9uZS13aXRoLWRhdGEubWluLmpzJ1xyXG4gICAgICBdLFxyXG4gICAgICB0eXBlczogWydzdHJpbmdbXSddLFxyXG4gICAgICBlbnZMaW5rOiAnSElHSENIQVJUU19DVVNUT01fU0NSSVBUUycsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnQWRkaXRpb25hbCBjdXN0b20gc2NyaXB0cyBvciBkZXBlbmRlbmNpZXMgdG8gZmV0Y2gnLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ2xpc3QnLFxyXG4gICAgICAgIHNlcGFyYXRvcjogJzsnXHJcbiAgICAgIH1cclxuICAgIH1cclxuICB9LFxyXG4gIGV4cG9ydDoge1xyXG4gICAgaW5maWxlOiB7XHJcbiAgICAgIHZhbHVlOiBudWxsLFxyXG4gICAgICB0eXBlczogWydzdHJpbmcnLCAnbnVsbCddLFxyXG4gICAgICBlbnZMaW5rOiAnRVhQT1JUX0lORklMRScsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdJbnB1dCBmaWxlbmFtZSB3aXRoIHR5cGUsIGZvcm1hdHRlZCBjb3JyZWN0bHkgYXMgSlNPTiBvciBTVkcnLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ3RleHQnXHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICBpbnN0cjoge1xyXG4gICAgICB2YWx1ZTogbnVsbCxcclxuICAgICAgdHlwZXM6IFsnT2JqZWN0JywgJ3N0cmluZycsICdudWxsJ10sXHJcbiAgICAgIGVudkxpbms6ICdFWFBPUlRfSU5TVFInLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnT3ZlcnJpZGVzIHRoZSBgaW5maWxlYCB3aXRoIEpTT04sIHN0cmluZ2lmaWVkIEpTT04sIG9yIFNWRyBpbnB1dCcsXHJcbiAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICB0eXBlOiAndGV4dCdcclxuICAgICAgfVxyXG4gICAgfSxcclxuICAgIG9wdGlvbnM6IHtcclxuICAgICAgdmFsdWU6IG51bGwsXHJcbiAgICAgIHR5cGVzOiBbJ09iamVjdCcsICdzdHJpbmcnLCAnbnVsbCddLFxyXG4gICAgICBlbnZMaW5rOiAnRVhQT1JUX09QVElPTlMnLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ0FsaWFzIGZvciB0aGUgYGluc3RyYCBvcHRpb24nLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ3RleHQnXHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICBzdmc6IHtcclxuICAgICAgdmFsdWU6IG51bGwsXHJcbiAgICAgIHR5cGVzOiBbJ3N0cmluZycsICdudWxsJ10sXHJcbiAgICAgIGVudkxpbms6ICdFWFBPUlRfU1ZHJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdTVkcgc3RyaW5nIHJlcHJlc2VudGF0aW9uIG9mIHRoZSBjaGFydCB0byByZW5kZXInLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ3RleHQnXHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICBiYXRjaDoge1xyXG4gICAgICB2YWx1ZTogbnVsbCxcclxuICAgICAgdHlwZXM6IFsnc3RyaW5nJywgJ251bGwnXSxcclxuICAgICAgZW52TGluazogJ0VYUE9SVF9CQVRDSCcsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdCYXRjaCBqb2Igc3RyaW5nIHdpdGggaW5wdXQvb3V0cHV0IHBhaXJzOiBcImluPW91dDtpbj1vdXQ7Li4uXCInLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ3RleHQnXHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICBvdXRmaWxlOiB7XHJcbiAgICAgIHZhbHVlOiBudWxsLFxyXG4gICAgICB0eXBlczogWydzdHJpbmcnLCAnbnVsbCddLFxyXG4gICAgICBlbnZMaW5rOiAnRVhQT1JUX09VVEZJTEUnLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnT3V0cHV0IGZpbGVuYW1lIHdpdGggdHlwZS4gQ2FuIGJlIGpwZWcsIHBuZywgcGRmLCBvciBzdmcgYW5kIGlnbm9yZXMgYHR5cGVgIG9wdGlvbicsXHJcbiAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICB0eXBlOiAndGV4dCdcclxuICAgICAgfVxyXG4gICAgfSxcclxuICAgIHR5cGU6IHtcclxuICAgICAgdmFsdWU6ICdwbmcnLFxyXG4gICAgICB0eXBlczogWydzdHJpbmcnXSxcclxuICAgICAgZW52TGluazogJ0VYUE9SVF9UWVBFJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdGaWxlIGV4cG9ydCBmb3JtYXQuIENhbiBiZSBqcGVnLCBwbmcsIHBkZiwgb3Igc3ZnJyxcclxuICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgIHR5cGU6ICdzZWxlY3QnLFxyXG4gICAgICAgIGhpbnQ6ICdEZWZhdWx0OiBwbmcnLFxyXG4gICAgICAgIGNob2ljZXM6IFsncG5nJywgJ2pwZWcnLCAncGRmJywgJ3N2ZyddXHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICBjb25zdHI6IHtcclxuICAgICAgdmFsdWU6ICdjaGFydCcsXHJcbiAgICAgIHR5cGVzOiBbJ3N0cmluZyddLFxyXG4gICAgICBlbnZMaW5rOiAnRVhQT1JUX0NPTlNUUicsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdDaGFydCBjb25zdHJ1Y3Rvci4gQ2FuIGJlIGNoYXJ0LCBzdG9ja0NoYXJ0LCBtYXBDaGFydCwgb3IgZ2FudHRDaGFydCcsXHJcbiAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICB0eXBlOiAnc2VsZWN0JyxcclxuICAgICAgICBoaW50OiAnRGVmYXVsdDogY2hhcnQnLFxyXG4gICAgICAgIGNob2ljZXM6IFsnY2hhcnQnLCAnc3RvY2tDaGFydCcsICdtYXBDaGFydCcsICdnYW50dENoYXJ0J11cclxuICAgICAgfVxyXG4gICAgfSxcclxuICAgIGI2NDoge1xyXG4gICAgICB2YWx1ZTogZmFsc2UsXHJcbiAgICAgIHR5cGVzOiBbJ2Jvb2xlYW4nXSxcclxuICAgICAgZW52TGluazogJ0VYUE9SVF9CNjQnLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnV2hldGhlciBvciBub3QgdG8gdGhlIGNoYXJ0IHNob3VsZCBiZSByZWNlaXZlZCBpbiBCYXNlNjQgZm9ybWF0IGluc3RlYWQgb2YgYmluYXJ5JyxcclxuICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgIHR5cGU6ICd0b2dnbGUnXHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICBub0Rvd25sb2FkOiB7XHJcbiAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgdHlwZXM6IFsnYm9vbGVhbiddLFxyXG4gICAgICBlbnZMaW5rOiAnRVhQT1JUX05PX0RPV05MT0FEJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ1doZXRoZXIgb3Igbm90IHRvIGluY2x1ZGUgb3IgZXhjbHVkZSBhdHRhY2htZW50IGhlYWRlcnMgaW4gdGhlIHJlc3BvbnNlJyxcclxuICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgIHR5cGU6ICd0b2dnbGUnXHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICBoZWlnaHQ6IHtcclxuICAgICAgdmFsdWU6IG51bGwsXHJcbiAgICAgIHR5cGVzOiBbJ251bWJlcicsICdudWxsJ10sXHJcbiAgICAgIGVudkxpbms6ICdFWFBPUlRfSEVJR0hUJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdIZWlnaHQgb2YgdGhlIGV4cG9ydGVkIGNoYXJ0LCBvdmVycmlkZXMgY2hhcnQgc2V0dGluZ3MnLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ251bWJlcidcclxuICAgICAgfVxyXG4gICAgfSxcclxuICAgIHdpZHRoOiB7XHJcbiAgICAgIHZhbHVlOiBudWxsLFxyXG4gICAgICB0eXBlczogWydudW1iZXInLCAnbnVsbCddLFxyXG4gICAgICBlbnZMaW5rOiAnRVhQT1JUX1dJRFRIJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdXaWR0aCBvZiB0aGUgZXhwb3J0ZWQgY2hhcnQsIG92ZXJyaWRlcyBjaGFydCBzZXR0aW5ncycsXHJcbiAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICB0eXBlOiAnbnVtYmVyJ1xyXG4gICAgICB9XHJcbiAgICB9LFxyXG4gICAgc2NhbGU6IHtcclxuICAgICAgdmFsdWU6IG51bGwsXHJcbiAgICAgIHR5cGVzOiBbJ251bWJlcicsICdudWxsJ10sXHJcbiAgICAgIGVudkxpbms6ICdFWFBPUlRfU0NBTEUnLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnU2NhbGUgb2YgdGhlIGV4cG9ydGVkIGNoYXJ0LCBvdmVycmlkZXMgY2hhcnQgc2V0dGluZ3MuIFJhbmdlcyBmcm9tIDAuMSB0byA1LjAnLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ251bWJlcidcclxuICAgICAgfVxyXG4gICAgfSxcclxuICAgIGRlZmF1bHRIZWlnaHQ6IHtcclxuICAgICAgdmFsdWU6IDQwMCxcclxuICAgICAgdHlwZXM6IFsnbnVtYmVyJ10sXHJcbiAgICAgIGVudkxpbms6ICdFWFBPUlRfREVGQVVMVF9IRUlHSFQnLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ0RlZmF1bHQgaGVpZ2h0IG9mIHRoZSBleHBvcnRlZCBjaGFydCBpZiBub3Qgc2V0JyxcclxuICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgIHR5cGU6ICdudW1iZXInXHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICBkZWZhdWx0V2lkdGg6IHtcclxuICAgICAgdmFsdWU6IDYwMCxcclxuICAgICAgdHlwZXM6IFsnbnVtYmVyJ10sXHJcbiAgICAgIGVudkxpbms6ICdFWFBPUlRfREVGQVVMVF9XSURUSCcsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnRGVmYXVsdCB3aWR0aCBvZiB0aGUgZXhwb3J0ZWQgY2hhcnQgaWYgbm90IHNldCcsXHJcbiAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICB0eXBlOiAnbnVtYmVyJ1xyXG4gICAgICB9XHJcbiAgICB9LFxyXG4gICAgZGVmYXVsdFNjYWxlOiB7XHJcbiAgICAgIHZhbHVlOiAxLFxyXG4gICAgICB0eXBlczogWydudW1iZXInXSxcclxuICAgICAgZW52TGluazogJ0VYUE9SVF9ERUZBVUxUX1NDQUxFJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ0RlZmF1bHQgc2NhbGUgb2YgdGhlIGV4cG9ydGVkIGNoYXJ0IGlmIG5vdCBzZXQuIFJhbmdlcyBmcm9tIDAuMSB0byA1LjAnLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgICAgbWluOiAwLjEsXHJcbiAgICAgICAgbWF4OiA1XHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICBnbG9iYWxPcHRpb25zOiB7XHJcbiAgICAgIHZhbHVlOiBudWxsLFxyXG4gICAgICB0eXBlczogWydPYmplY3QnLCAnc3RyaW5nJywgJ251bGwnXSxcclxuICAgICAgZW52TGluazogJ0VYUE9SVF9HTE9CQUxfT1BUSU9OUycsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdKU09OLCBzdHJpbmdpZmllZCBKU09OIG9yIGZpbGVuYW1lIHdpdGggZ2xvYmFsIG9wdGlvbnMgZm9yIEhpZ2hjaGFydHMuc2V0T3B0aW9ucycsXHJcbiAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICB0eXBlOiAndGV4dCdcclxuICAgICAgfVxyXG4gICAgfSxcclxuICAgIHRoZW1lT3B0aW9uczoge1xyXG4gICAgICB2YWx1ZTogbnVsbCxcclxuICAgICAgdHlwZXM6IFsnT2JqZWN0JywgJ3N0cmluZycsICdudWxsJ10sXHJcbiAgICAgIGVudkxpbms6ICdFWFBPUlRfVEhFTUVfT1BUSU9OUycsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdKU09OLCBzdHJpbmdpZmllZCBKU09OIG9yIGZpbGVuYW1lIHdpdGggdGhlbWUgb3B0aW9ucyBmb3IgSGlnaGNoYXJ0cy5zZXRPcHRpb25zJyxcclxuICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgIHR5cGU6ICd0ZXh0J1xyXG4gICAgICB9XHJcbiAgICB9LFxyXG4gICAgcmFzdGVyaXphdGlvblRpbWVvdXQ6IHtcclxuICAgICAgdmFsdWU6IDE1MDAsXHJcbiAgICAgIHR5cGVzOiBbJ251bWJlciddLFxyXG4gICAgICBlbnZMaW5rOiAnRVhQT1JUX1JBU1RFUklaQVRJT05fVElNRU9VVCcsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnTWlsbGlzZWNvbmRzIHRvIHdhaXQgZm9yIHdlYnBhZ2UgcmVuZGVyaW5nJyxcclxuICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgIHR5cGU6ICdudW1iZXInXHJcbiAgICAgIH1cclxuICAgIH1cclxuICB9LFxyXG4gIGN1c3RvbUxvZ2ljOiB7XHJcbiAgICBhbGxvd0NvZGVFeGVjdXRpb246IHtcclxuICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICB0eXBlczogWydib29sZWFuJ10sXHJcbiAgICAgIGVudkxpbms6ICdDVVNUT01fTE9HSUNfQUxMT1dfQ09ERV9FWEVDVVRJT04nLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnQWxsb3dzIG9yIGRpc2FsbG93cyBleGVjdXRpb24gb2YgYXJiaXRyYXJ5IGNvZGUgZHVyaW5nIGV4cG9ydGluZycsXHJcbiAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICB0eXBlOiAndG9nZ2xlJ1xyXG4gICAgICB9XHJcbiAgICB9LFxyXG4gICAgYWxsb3dGaWxlUmVzb3VyY2VzOiB7XHJcbiAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgdHlwZXM6IFsnYm9vbGVhbiddLFxyXG4gICAgICBlbnZMaW5rOiAnQ1VTVE9NX0xPR0lDX0FMTE9XX0ZJTEVfUkVTT1VSQ0VTJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ0FsbG93cyBvciBkaXNhbGxvd3MgaW5qZWN0aW9uIG9mIGZpbGVzeXN0ZW0gcmVzb3VyY2VzIChkaXNhYmxlZCBpbiBzZXJ2ZXIgbW9kZSknLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ3RvZ2dsZSdcclxuICAgICAgfVxyXG4gICAgfSxcclxuICAgIGN1c3RvbUNvZGU6IHtcclxuICAgICAgdmFsdWU6IG51bGwsXHJcbiAgICAgIHR5cGVzOiBbJ3N0cmluZycsICdudWxsJ10sXHJcbiAgICAgIGVudkxpbms6ICdDVVNUT01fTE9HSUNfQ1VTVE9NX0NPREUnLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnQ3VzdG9tIGNvZGUgdG8gZXhlY3V0ZSBiZWZvcmUgY2hhcnQgaW5pdGlhbGl6YXRpb24uIENhbiBiZSBhIGZ1bmN0aW9uLCBjb2RlIHdyYXBwZWQgaW4gYSBmdW5jdGlvbiwgb3IgYSAuanMgZmlsZW5hbWUnLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ3RleHQnXHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICBjYWxsYmFjazoge1xyXG4gICAgICB2YWx1ZTogbnVsbCxcclxuICAgICAgdHlwZXM6IFsnc3RyaW5nJywgJ251bGwnXSxcclxuICAgICAgZW52TGluazogJ0NVU1RPTV9MT0dJQ19DQUxMQkFDSycsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdKYXZhU2NyaXB0IGNvZGUgdG8gcnVuIGR1cmluZyBjb25zdHJ1Y3Rpb24uIENhbiBiZSBhIGZ1bmN0aW9uIG9yIGEgLmpzIGZpbGVuYW1lJyxcclxuICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgIHR5cGU6ICd0ZXh0J1xyXG4gICAgICB9XHJcbiAgICB9LFxyXG4gICAgcmVzb3VyY2VzOiB7XHJcbiAgICAgIHZhbHVlOiBudWxsLFxyXG4gICAgICB0eXBlczogWydPYmplY3QnLCAnc3RyaW5nJywgJ251bGwnXSxcclxuICAgICAgZW52TGluazogJ0NVU1RPTV9MT0dJQ19SRVNPVVJDRVMnLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnQWRkaXRpb25hbCByZXNvdXJjZXMgYXMgSlNPTiwgc3RyaW5naWZpZWQgSlNPTiwgb3IgZmlsZW5hbWUsIGNvbnRhaW5pbmcgZmlsZXMsIGpzLCBhbmQgY3NzIHNlY3Rpb25zJyxcclxuICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgIHR5cGU6ICd0ZXh0J1xyXG4gICAgICB9XHJcbiAgICB9LFxyXG4gICAgbG9hZENvbmZpZzoge1xyXG4gICAgICB2YWx1ZTogbnVsbCxcclxuICAgICAgdHlwZXM6IFsnc3RyaW5nJywgJ251bGwnXSxcclxuICAgICAgZW52TGluazogJ0NVU1RPTV9MT0dJQ19MT0FEX0NPTkZJRycsXHJcbiAgICAgIGxlZ2FjeU5hbWU6ICdmcm9tRmlsZScsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnRmlsZSB3aXRoIGEgcHJlLWRlZmluZWQgY29uZmlndXJhdGlvbiB0byB1c2UnLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ3RleHQnXHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICBjcmVhdGVDb25maWc6IHtcclxuICAgICAgdmFsdWU6IG51bGwsXHJcbiAgICAgIHR5cGVzOiBbJ3N0cmluZycsICdudWxsJ10sXHJcbiAgICAgIGVudkxpbms6ICdDVVNUT01fTE9HSUNfQ1JFQVRFX0NPTkZJRycsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdQcm9tcHQtYmFzZWQgb3B0aW9uIHNldHRpbmcsIHNhdmVkIHRvIGEgcHJvdmlkZWQgY29uZmlnIGZpbGUnLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ3RleHQnXHJcbiAgICAgIH1cclxuICAgIH1cclxuICB9LFxyXG4gIHNlcnZlcjoge1xyXG4gICAgZW5hYmxlOiB7XHJcbiAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgdHlwZXM6IFsnYm9vbGVhbiddLFxyXG4gICAgICBlbnZMaW5rOiAnU0VSVkVSX0VOQUJMRScsXHJcbiAgICAgIGNsaU5hbWU6ICdlbmFibGVTZXJ2ZXInLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ1N0YXJ0cyB0aGUgc2VydmVyIHdoZW4gdHJ1ZScsXHJcbiAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICB0eXBlOiAndG9nZ2xlJ1xyXG4gICAgICB9XHJcbiAgICB9LFxyXG4gICAgaG9zdDoge1xyXG4gICAgICB2YWx1ZTogJzAuMC4wLjAnLFxyXG4gICAgICB0eXBlczogWydzdHJpbmcnXSxcclxuICAgICAgZW52TGluazogJ1NFUlZFUl9IT1NUJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdIb3N0bmFtZSBvZiB0aGUgc2VydmVyJyxcclxuICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgIHR5cGU6ICd0ZXh0J1xyXG4gICAgICB9XHJcbiAgICB9LFxyXG4gICAgcG9ydDoge1xyXG4gICAgICB2YWx1ZTogNzgwMSxcclxuICAgICAgdHlwZXM6IFsnbnVtYmVyJ10sXHJcbiAgICAgIGVudkxpbms6ICdTRVJWRVJfUE9SVCcsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnUG9ydCBudW1iZXIgZm9yIHRoZSBzZXJ2ZXInLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ251bWJlcidcclxuICAgICAgfVxyXG4gICAgfSxcclxuICAgIHVwbG9hZExpbWl0OiB7XHJcbiAgICAgIHZhbHVlOiAzLFxyXG4gICAgICB0eXBlczogWydudW1iZXInXSxcclxuICAgICAgZW52TGluazogJ1NFUlZFUl9VUExPQURfTElNSVQnLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ01heGltdW0gcmVxdWVzdCBib2R5IHNpemUgaW4gTUInLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ251bWJlcidcclxuICAgICAgfVxyXG4gICAgfSxcclxuICAgIGJlbmNobWFya2luZzoge1xyXG4gICAgICB2YWx1ZTogZmFsc2UsXHJcbiAgICAgIHR5cGVzOiBbJ2Jvb2xlYW4nXSxcclxuICAgICAgZW52TGluazogJ1NFUlZFUl9CRU5DSE1BUktJTkcnLFxyXG4gICAgICBjbGlOYW1lOiAnc2VydmVyQmVuY2htYXJraW5nJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ0Rpc3BsYXlzIG9yIG5vdCBhY3Rpb24gZHVyYXRpb25zIGluIG1pbGxpc2Vjb25kcyBkdXJpbmcgc2VydmVyIHJlcXVlc3RzJyxcclxuICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgIHR5cGU6ICd0b2dnbGUnXHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICBwcm94eToge1xyXG4gICAgICBob3N0OiB7XHJcbiAgICAgICAgdmFsdWU6IG51bGwsXHJcbiAgICAgICAgdHlwZXM6IFsnc3RyaW5nJywgJ251bGwnXSxcclxuICAgICAgICBlbnZMaW5rOiAnU0VSVkVSX1BST1hZX0hPU1QnLFxyXG4gICAgICAgIGNsaU5hbWU6ICdwcm94eUhvc3QnLFxyXG4gICAgICAgIGRlc2NyaXB0aW9uOiAnSG9zdCBvZiB0aGUgcHJveHkgc2VydmVyLCBpZiBhcHBsaWNhYmxlJyxcclxuICAgICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgICB0eXBlOiAndGV4dCdcclxuICAgICAgICB9XHJcbiAgICAgIH0sXHJcbiAgICAgIHBvcnQ6IHtcclxuICAgICAgICB2YWx1ZTogbnVsbCxcclxuICAgICAgICB0eXBlczogWydudW1iZXInLCAnbnVsbCddLFxyXG4gICAgICAgIGVudkxpbms6ICdTRVJWRVJfUFJPWFlfUE9SVCcsXHJcbiAgICAgICAgY2xpTmFtZTogJ3Byb3h5UG9ydCcsXHJcbiAgICAgICAgZGVzY3JpcHRpb246ICdQb3J0IG9mIHRoZSBwcm94eSBzZXJ2ZXIsIGlmIGFwcGxpY2FibGUnLFxyXG4gICAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICAgIHR5cGU6ICdudW1iZXInXHJcbiAgICAgICAgfVxyXG4gICAgICB9LFxyXG4gICAgICB0aW1lb3V0OiB7XHJcbiAgICAgICAgdmFsdWU6IDUwMDAsXHJcbiAgICAgICAgdHlwZXM6IFsnbnVtYmVyJ10sXHJcbiAgICAgICAgZW52TGluazogJ1NFUlZFUl9QUk9YWV9USU1FT1VUJyxcclxuICAgICAgICBjbGlOYW1lOiAncHJveHlUaW1lb3V0JyxcclxuICAgICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAgICdUaW1lb3V0IGluIG1pbGxpc2Vjb25kcyBmb3IgdGhlIHByb3h5IHNlcnZlciwgaWYgYXBwbGljYWJsZScsXHJcbiAgICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgICAgdHlwZTogJ251bWJlcidcclxuICAgICAgICB9XHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICByYXRlTGltaXRpbmc6IHtcclxuICAgICAgZW5hYmxlOiB7XHJcbiAgICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICAgIHR5cGVzOiBbJ2Jvb2xlYW4nXSxcclxuICAgICAgICBlbnZMaW5rOiAnU0VSVkVSX1JBVEVfTElNSVRJTkdfRU5BQkxFJyxcclxuICAgICAgICBjbGlOYW1lOiAnZW5hYmxlUmF0ZUxpbWl0aW5nJyxcclxuICAgICAgICBkZXNjcmlwdGlvbjogJ0VuYWJsZXMgb3IgZGlzYWJsZXMgcmF0ZSBsaW1pdGluZyBvbiB0aGUgc2VydmVyJyxcclxuICAgICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgICB0eXBlOiAndG9nZ2xlJ1xyXG4gICAgICAgIH1cclxuICAgICAgfSxcclxuICAgICAgbWF4UmVxdWVzdHM6IHtcclxuICAgICAgICB2YWx1ZTogMTAsXHJcbiAgICAgICAgdHlwZXM6IFsnbnVtYmVyJ10sXHJcbiAgICAgICAgZW52TGluazogJ1NFUlZFUl9SQVRFX0xJTUlUSU5HX01BWF9SRVFVRVNUUycsXHJcbiAgICAgICAgbGVnYWN5TmFtZTogJ3JhdGVMaW1pdCcsXHJcbiAgICAgICAgZGVzY3JpcHRpb246ICdNYXhpbXVtIG51bWJlciBvZiByZXF1ZXN0cyBhbGxvd2VkIHBlciBtaW51dGUnLFxyXG4gICAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICAgIHR5cGU6ICdudW1iZXInXHJcbiAgICAgICAgfVxyXG4gICAgICB9LFxyXG4gICAgICB3aW5kb3c6IHtcclxuICAgICAgICB2YWx1ZTogMSxcclxuICAgICAgICB0eXBlczogWydudW1iZXInXSxcclxuICAgICAgICBlbnZMaW5rOiAnU0VSVkVSX1JBVEVfTElNSVRJTkdfV0lORE9XJyxcclxuICAgICAgICBkZXNjcmlwdGlvbjogJ1RpbWUgd2luZG93IGluIG1pbnV0ZXMgZm9yIHJhdGUgbGltaXRpbmcnLFxyXG4gICAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICAgIHR5cGU6ICdudW1iZXInXHJcbiAgICAgICAgfVxyXG4gICAgICB9LFxyXG4gICAgICBkZWxheToge1xyXG4gICAgICAgIHZhbHVlOiAwLFxyXG4gICAgICAgIHR5cGVzOiBbJ251bWJlciddLFxyXG4gICAgICAgIGVudkxpbms6ICdTRVJWRVJfUkFURV9MSU1JVElOR19ERUxBWScsXHJcbiAgICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgICAnRGVsYXkgZHVyYXRpb24gYmV0d2VlbiBzdWNjZXNzaXZlIHJlcXVlc3RzIGJlZm9yZSByZWFjaGluZyB0aGUgbGltaXQnLFxyXG4gICAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICAgIHR5cGU6ICdudW1iZXInXHJcbiAgICAgICAgfVxyXG4gICAgICB9LFxyXG4gICAgICB0cnVzdFByb3h5OiB7XHJcbiAgICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICAgIHR5cGVzOiBbJ2Jvb2xlYW4nXSxcclxuICAgICAgICBlbnZMaW5rOiAnU0VSVkVSX1JBVEVfTElNSVRJTkdfVFJVU1RfUFJPWFknLFxyXG4gICAgICAgIGRlc2NyaXB0aW9uOiAnU2V0IHRvIHRydWUgaWYgdGhlIHNlcnZlciBpcyBiZWhpbmQgYSBsb2FkIGJhbGFuY2VyJyxcclxuICAgICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgICB0eXBlOiAndG9nZ2xlJ1xyXG4gICAgICAgIH1cclxuICAgICAgfSxcclxuICAgICAgc2tpcEtleToge1xyXG4gICAgICAgIHZhbHVlOiBudWxsLFxyXG4gICAgICAgIHR5cGVzOiBbJ3N0cmluZycsICdudWxsJ10sXHJcbiAgICAgICAgZW52TGluazogJ1NFUlZFUl9SQVRFX0xJTUlUSU5HX1NLSVBfS0VZJyxcclxuICAgICAgICBkZXNjcmlwdGlvbjogJ0tleSB0byBieXBhc3MgdGhlIHJhdGUgbGltaXRlciwgdXNlZCB3aXRoIGBza2lwVG9rZW5gJyxcclxuICAgICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgICB0eXBlOiAndGV4dCdcclxuICAgICAgICB9XHJcbiAgICAgIH0sXHJcbiAgICAgIHNraXBUb2tlbjoge1xyXG4gICAgICAgIHZhbHVlOiBudWxsLFxyXG4gICAgICAgIHR5cGVzOiBbJ3N0cmluZycsICdudWxsJ10sXHJcbiAgICAgICAgZW52TGluazogJ1NFUlZFUl9SQVRFX0xJTUlUSU5HX1NLSVBfVE9LRU4nLFxyXG4gICAgICAgIGRlc2NyaXB0aW9uOiAnVG9rZW4gdG8gYnlwYXNzIHRoZSByYXRlIGxpbWl0ZXIsIHVzZWQgd2l0aCBgc2tpcEtleWAnLFxyXG4gICAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICAgIHR5cGU6ICd0ZXh0J1xyXG4gICAgICAgIH1cclxuICAgICAgfVxyXG4gICAgfSxcclxuICAgIHNzbDoge1xyXG4gICAgICBlbmFibGU6IHtcclxuICAgICAgICB2YWx1ZTogZmFsc2UsXHJcbiAgICAgICAgdHlwZXM6IFsnYm9vbGVhbiddLFxyXG4gICAgICAgIGVudkxpbms6ICdTRVJWRVJfU1NMX0VOQUJMRScsXHJcbiAgICAgICAgY2xpTmFtZTogJ2VuYWJsZVNzbCcsXHJcbiAgICAgICAgZGVzY3JpcHRpb246ICdFbmFibGVzIG9yIGRpc2FibGVzIFNTTCBwcm90b2NvbCcsXHJcbiAgICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgICAgdHlwZTogJ3RvZ2dsZSdcclxuICAgICAgICB9XHJcbiAgICAgIH0sXHJcbiAgICAgIGZvcmNlOiB7XHJcbiAgICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICAgIHR5cGVzOiBbJ2Jvb2xlYW4nXSxcclxuICAgICAgICBlbnZMaW5rOiAnU0VSVkVSX1NTTF9GT1JDRScsXHJcbiAgICAgICAgY2xpTmFtZTogJ3NzbEZvcmNlJyxcclxuICAgICAgICBsZWdhY3lOYW1lOiAnc3NsT25seScsXHJcbiAgICAgICAgZGVzY3JpcHRpb246ICdGb3JjZXMgdGhlIHNlcnZlciB0byB1c2UgSFRUUFMgb25seSB3aGVuIHRydWUnLFxyXG4gICAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICAgIHR5cGU6ICd0b2dnbGUnXHJcbiAgICAgICAgfVxyXG4gICAgICB9LFxyXG4gICAgICBwb3J0OiB7XHJcbiAgICAgICAgdmFsdWU6IDQ0MyxcclxuICAgICAgICB0eXBlczogWydudW1iZXInXSxcclxuICAgICAgICBlbnZMaW5rOiAnU0VSVkVSX1NTTF9QT1JUJyxcclxuICAgICAgICBjbGlOYW1lOiAnc3NsUG9ydCcsXHJcbiAgICAgICAgZGVzY3JpcHRpb246ICdQb3J0IGZvciB0aGUgU1NMIHNlcnZlcicsXHJcbiAgICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgICAgdHlwZTogJ251bWJlcidcclxuICAgICAgICB9XHJcbiAgICAgIH0sXHJcbiAgICAgIGNlcnRQYXRoOiB7XHJcbiAgICAgICAgdmFsdWU6IG51bGwsXHJcbiAgICAgICAgdHlwZXM6IFsnc3RyaW5nJywgJ251bGwnXSxcclxuICAgICAgICBlbnZMaW5rOiAnU0VSVkVSX1NTTF9DRVJUX1BBVEgnLFxyXG4gICAgICAgIGNsaU5hbWU6ICdzc2xDZXJ0UGF0aCcsXHJcbiAgICAgICAgbGVnYWN5TmFtZTogJ3NzbFBhdGgnLFxyXG4gICAgICAgIGRlc2NyaXB0aW9uOiAnUGF0aCB0byB0aGUgU1NMIGNlcnRpZmljYXRlL2tleSBmaWxlJyxcclxuICAgICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgICB0eXBlOiAndGV4dCdcclxuICAgICAgICB9XHJcbiAgICAgIH1cclxuICAgIH1cclxuICB9LFxyXG4gIHBvb2w6IHtcclxuICAgIG1pbldvcmtlcnM6IHtcclxuICAgICAgdmFsdWU6IDQsXHJcbiAgICAgIHR5cGVzOiBbJ251bWJlciddLFxyXG4gICAgICBlbnZMaW5rOiAnUE9PTF9NSU5fV09SS0VSUycsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnTWluaW11bSBhbmQgaW5pdGlhbCBudW1iZXIgb2YgcG9vbCB3b3JrZXJzIHRvIHNwYXduJyxcclxuICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgIHR5cGU6ICdudW1iZXInXHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICBtYXhXb3JrZXJzOiB7XHJcbiAgICAgIHZhbHVlOiA4LFxyXG4gICAgICB0eXBlczogWydudW1iZXInXSxcclxuICAgICAgZW52TGluazogJ1BPT0xfTUFYX1dPUktFUlMnLFxyXG4gICAgICBsZWdhY3lOYW1lOiAnd29ya2VycycsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnTWF4aW11bSBudW1iZXIgb2YgcG9vbCB3b3JrZXJzIHRvIHNwYXduJyxcclxuICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgIHR5cGU6ICdudW1iZXInXHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICB3b3JrTGltaXQ6IHtcclxuICAgICAgdmFsdWU6IDQwLFxyXG4gICAgICB0eXBlczogWydudW1iZXInXSxcclxuICAgICAgZW52TGluazogJ1BPT0xfV09SS19MSU1JVCcsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnTnVtYmVyIG9mIHRhc2tzIGEgd29ya2VyIGNhbiBoYW5kbGUgYmVmb3JlIHJlc3RhcnRpbmcnLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ251bWJlcidcclxuICAgICAgfVxyXG4gICAgfSxcclxuICAgIGFjcXVpcmVUaW1lb3V0OiB7XHJcbiAgICAgIHZhbHVlOiA1MDAwLFxyXG4gICAgICB0eXBlczogWydudW1iZXInXSxcclxuICAgICAgZW52TGluazogJ1BPT0xfQUNRVUlSRV9USU1FT1VUJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdUaW1lb3V0IGluIG1pbGxpc2Vjb25kcyBmb3IgYWNxdWlyaW5nIGEgcmVzb3VyY2UnLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ251bWJlcidcclxuICAgICAgfVxyXG4gICAgfSxcclxuICAgIGNyZWF0ZVRpbWVvdXQ6IHtcclxuICAgICAgdmFsdWU6IDUwMDAsXHJcbiAgICAgIHR5cGVzOiBbJ251bWJlciddLFxyXG4gICAgICBlbnZMaW5rOiAnUE9PTF9DUkVBVEVfVElNRU9VVCcsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnVGltZW91dCBpbiBtaWxsaXNlY29uZHMgZm9yIGNyZWF0aW5nIGEgcmVzb3VyY2UnLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ251bWJlcidcclxuICAgICAgfVxyXG4gICAgfSxcclxuICAgIGRlc3Ryb3lUaW1lb3V0OiB7XHJcbiAgICAgIHZhbHVlOiA1MDAwLFxyXG4gICAgICB0eXBlczogWydudW1iZXInXSxcclxuICAgICAgZW52TGluazogJ1BPT0xfREVTVFJPWV9USU1FT1VUJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdUaW1lb3V0IGluIG1pbGxpc2Vjb25kcyBmb3IgZGVzdHJveWluZyBhIHJlc291cmNlJyxcclxuICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgIHR5cGU6ICdudW1iZXInXHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICBpZGxlVGltZW91dDoge1xyXG4gICAgICB2YWx1ZTogMzAwMDAsXHJcbiAgICAgIHR5cGVzOiBbJ251bWJlciddLFxyXG4gICAgICBlbnZMaW5rOiAnUE9PTF9JRExFX1RJTUVPVVQnLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ1RpbWVvdXQgaW4gbWlsbGlzZWNvbmRzIGZvciBkZXN0cm95aW5nIGlkbGUgcmVzb3VyY2VzJyxcclxuICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgIHR5cGU6ICdudW1iZXInXHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICBjcmVhdGVSZXRyeUludGVydmFsOiB7XHJcbiAgICAgIHZhbHVlOiAyMDAsXHJcbiAgICAgIHR5cGVzOiBbJ251bWJlciddLFxyXG4gICAgICBlbnZMaW5rOiAnUE9PTF9DUkVBVEVfUkVUUllfSU5URVJWQUwnLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnSW50ZXJ2YWwgaW4gbWlsbGlzZWNvbmRzIGJlZm9yZSByZXRyeWluZyByZXNvdXJjZSBjcmVhdGlvbiBvbiBmYWlsdXJlJyxcclxuICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgIHR5cGU6ICdudW1iZXInXHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICByZWFwZXJJbnRlcnZhbDoge1xyXG4gICAgICB2YWx1ZTogMTAwMCxcclxuICAgICAgdHlwZXM6IFsnbnVtYmVyJ10sXHJcbiAgICAgIGVudkxpbms6ICdQT09MX1JFQVBFUl9JTlRFUlZBTCcsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdJbnRlcnZhbCBpbiBtaWxsaXNlY29uZHMgdG8gY2hlY2sgYW5kIGRlc3Ryb3kgaWRsZSByZXNvdXJjZXMnLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ251bWJlcidcclxuICAgICAgfVxyXG4gICAgfSxcclxuICAgIGJlbmNobWFya2luZzoge1xyXG4gICAgICB2YWx1ZTogZmFsc2UsXHJcbiAgICAgIHR5cGVzOiBbJ2Jvb2xlYW4nXSxcclxuICAgICAgZW52TGluazogJ1BPT0xfQkVOQ0hNQVJLSU5HJyxcclxuICAgICAgY2xpTmFtZTogJ3Bvb2xCZW5jaG1hcmtpbmcnLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ1Nob3dzIHN0YXRpc3RpY3MgZm9yIHRoZSBwb29sIG9mIHJlc291cmNlcycsXHJcbiAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICB0eXBlOiAndG9nZ2xlJ1xyXG4gICAgICB9XHJcbiAgICB9XHJcbiAgfSxcclxuICBsb2dnaW5nOiB7XHJcbiAgICBsZXZlbDoge1xyXG4gICAgICB2YWx1ZTogNCxcclxuICAgICAgdHlwZXM6IFsnbnVtYmVyJ10sXHJcbiAgICAgIGVudkxpbms6ICdMT0dHSU5HX0xFVkVMJyxcclxuICAgICAgY2xpTmFtZTogJ2xvZ0xldmVsJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdMb2dnaW5nIHZlcmJvc2l0eSBsZXZlbCcsXHJcbiAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgICByb3VuZDogMCxcclxuICAgICAgICBtaW46IDAsXHJcbiAgICAgICAgbWF4OiA1XHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICBmaWxlOiB7XHJcbiAgICAgIHZhbHVlOiAnaGlnaGNoYXJ0cy1leHBvcnQtc2VydmVyLmxvZycsXHJcbiAgICAgIHR5cGVzOiBbJ3N0cmluZyddLFxyXG4gICAgICBlbnZMaW5rOiAnTE9HR0lOR19GSUxFJyxcclxuICAgICAgY2xpTmFtZTogJ2xvZ0ZpbGUnLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnTG9nIGZpbGUgbmFtZS4gUmVxdWlyZXMgYGxvZ1RvRmlsZWAgYW5kIGBsb2dEZXN0YCB0byBiZSBzZXQnLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ3RleHQnXHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICBkZXN0OiB7XHJcbiAgICAgIHZhbHVlOiAnbG9nJyxcclxuICAgICAgdHlwZXM6IFsnc3RyaW5nJ10sXHJcbiAgICAgIGVudkxpbms6ICdMT0dHSU5HX0RFU1QnLFxyXG4gICAgICBjbGlOYW1lOiAnbG9nRGVzdCcsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnUGF0aCB0byBzdG9yZSBsb2cgZmlsZXMuIFJlcXVpcmVzIGBsb2dUb0ZpbGVgIHRvIGJlIHNldCcsXHJcbiAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICB0eXBlOiAndGV4dCdcclxuICAgICAgfVxyXG4gICAgfSxcclxuICAgIHRvQ29uc29sZToge1xyXG4gICAgICB2YWx1ZTogdHJ1ZSxcclxuICAgICAgdHlwZXM6IFsnYm9vbGVhbiddLFxyXG4gICAgICBlbnZMaW5rOiAnTE9HR0lOR19UT19DT05TT0xFJyxcclxuICAgICAgY2xpTmFtZTogJ2xvZ1RvQ29uc29sZScsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnRW5hYmxlcyBvciBkaXNhYmxlcyBjb25zb2xlIGxvZ2dpbmcnLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ3RvZ2dsZSdcclxuICAgICAgfVxyXG4gICAgfSxcclxuICAgIHRvRmlsZToge1xyXG4gICAgICB2YWx1ZTogdHJ1ZSxcclxuICAgICAgdHlwZXM6IFsnYm9vbGVhbiddLFxyXG4gICAgICBlbnZMaW5rOiAnTE9HR0lOR19UT19GSUxFJyxcclxuICAgICAgY2xpTmFtZTogJ2xvZ1RvRmlsZScsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnRW5hYmxlcyBvciBkaXNhYmxlcyBsb2dnaW5nIHRvIGEgZmlsZScsXHJcbiAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICB0eXBlOiAndG9nZ2xlJ1xyXG4gICAgICB9XHJcbiAgICB9XHJcbiAgfSxcclxuICB1aToge1xyXG4gICAgZW5hYmxlOiB7XHJcbiAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgdHlwZXM6IFsnYm9vbGVhbiddLFxyXG4gICAgICBlbnZMaW5rOiAnVUlfRU5BQkxFJyxcclxuICAgICAgY2xpTmFtZTogJ2VuYWJsZVVpJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdFbmFibGVzIG9yIGRpc2FibGVzIHRoZSBVSSBmb3IgdGhlIGV4cG9ydCBzZXJ2ZXInLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ3RvZ2dsZSdcclxuICAgICAgfVxyXG4gICAgfSxcclxuICAgIHJvdXRlOiB7XHJcbiAgICAgIHZhbHVlOiAnLycsXHJcbiAgICAgIHR5cGVzOiBbJ3N0cmluZyddLFxyXG4gICAgICBlbnZMaW5rOiAnVUlfUk9VVEUnLFxyXG4gICAgICBjbGlOYW1lOiAndWlSb3V0ZScsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnVGhlIGVuZHBvaW50IHJvdXRlIGZvciB0aGUgVUknLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ3RleHQnXHJcbiAgICAgIH1cclxuICAgIH1cclxuICB9LFxyXG4gIG90aGVyOiB7XHJcbiAgICBub2RlRW52OiB7XHJcbiAgICAgIHZhbHVlOiAncHJvZHVjdGlvbicsXHJcbiAgICAgIHR5cGVzOiBbJ3N0cmluZyddLFxyXG4gICAgICBlbnZMaW5rOiAnT1RIRVJfTk9ERV9FTlYnLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ1RoZSBOb2RlLmpzIGVudmlyb25tZW50IHR5cGUnLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ3RleHQnXHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICBsaXN0ZW5Ub1Byb2Nlc3NFeGl0czoge1xyXG4gICAgICB2YWx1ZTogdHJ1ZSxcclxuICAgICAgdHlwZXM6IFsnYm9vbGVhbiddLFxyXG4gICAgICBlbnZMaW5rOiAnT1RIRVJfTElTVEVOX1RPX1BST0NFU1NfRVhJVFMnLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ1doZXRoZXIgb3Igbm90IHRvIGF0dGFjaCBwcm9jZXNzLmV4aXQgaGFuZGxlcnMnLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ3RvZ2dsZSdcclxuICAgICAgfVxyXG4gICAgfSxcclxuICAgIG5vTG9nbzoge1xyXG4gICAgICB2YWx1ZTogZmFsc2UsXHJcbiAgICAgIHR5cGVzOiBbJ2Jvb2xlYW4nXSxcclxuICAgICAgZW52TGluazogJ09USEVSX05PX0xPR08nLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ0Rpc3BsYXkgb3Igc2tpcCBwcmludGluZyB0aGUgbG9nbyBvbiBzdGFydHVwJyxcclxuICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgIHR5cGU6ICd0b2dnbGUnXHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICBoYXJkUmVzZXRQYWdlOiB7XHJcbiAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgdHlwZXM6IFsnYm9vbGVhbiddLFxyXG4gICAgICBlbnZMaW5rOiAnT1RIRVJfSEFSRF9SRVNFVF9QQUdFJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdXaGV0aGVyIG9yIG5vdCB0byByZXNldCB0aGUgcGFnZSBjb250ZW50IGVudGlyZWx5JyxcclxuICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgIHR5cGU6ICd0b2dnbGUnXHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICBicm93c2VyU2hlbGxNb2RlOiB7XHJcbiAgICAgIHZhbHVlOiB0cnVlLFxyXG4gICAgICB0eXBlczogWydib29sZWFuJ10sXHJcbiAgICAgIGVudkxpbms6ICdPVEhFUl9CUk9XU0VSX1NIRUxMX01PREUnLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ1doZXRoZXIgb3Igbm90IHRvIHNldCB0aGUgYnJvd3NlciB0byBydW4gaW4gc2hlbGwgbW9kZScsXHJcbiAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICB0eXBlOiAndG9nZ2xlJ1xyXG4gICAgICB9XHJcbiAgICB9LFxyXG4gICAgdmFsaWRhdGlvbjoge1xyXG4gICAgICB2YWx1ZTogdHJ1ZSxcclxuICAgICAgdHlwZXM6IFsnYm9vbGVhbiddLFxyXG4gICAgICBlbnZMaW5rOiAnT1RIRVJfVkFMSURBVElPTicsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnV2hldGhlciBvciBub3QgdG8gZW5hYmxlIHZhbGlkYXRpb24gb2Ygb3B0aW9ucyB0eXBlcycsXHJcbiAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICB0eXBlOiAndG9nZ2xlJ1xyXG4gICAgICB9XHJcbiAgICB9XHJcbiAgfSxcclxuICBkZWJ1Zzoge1xyXG4gICAgZW5hYmxlOiB7XHJcbiAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgdHlwZXM6IFsnYm9vbGVhbiddLFxyXG4gICAgICBlbnZMaW5rOiAnREVCVUdfRU5BQkxFJyxcclxuICAgICAgY2xpTmFtZTogJ2VuYWJsZURlYnVnJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdFbmFibGVzIG9yIGRpc2FibGVzIGRlYnVnIG1vZGUgZm9yIHRoZSB1bmRlcmx5aW5nIGJyb3dzZXInLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ3RvZ2dsZSdcclxuICAgICAgfVxyXG4gICAgfSxcclxuICAgIGhlYWRsZXNzOiB7XHJcbiAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgdHlwZXM6IFsnYm9vbGVhbiddLFxyXG4gICAgICBlbnZMaW5rOiAnREVCVUdfSEVBRExFU1MnLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnV2hldGhlciBvciBub3QgdG8gc2V0IHRoZSBicm93c2VyIHRvIHJ1biBpbiBoZWFkbGVzcyBtb2RlIGR1cmluZyBkZWJ1Z2dpbmcnLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ3RvZ2dsZSdcclxuICAgICAgfVxyXG4gICAgfSxcclxuICAgIGRldnRvb2xzOiB7XHJcbiAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgdHlwZXM6IFsnYm9vbGVhbiddLFxyXG4gICAgICBlbnZMaW5rOiAnREVCVUdfREVWVE9PTFMnLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ0VuYWJsZXMgb3IgZGlzYWJsZXMgRGV2VG9vbHMgaW4gaGVhZGZ1bCBtb2RlJyxcclxuICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgIHR5cGU6ICd0b2dnbGUnXHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICBsaXN0ZW5Ub0NvbnNvbGU6IHtcclxuICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICB0eXBlczogWydib29sZWFuJ10sXHJcbiAgICAgIGVudkxpbms6ICdERUJVR19MSVNURU5fVE9fQ09OU09MRScsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdFbmFibGVzIG9yIGRpc2FibGVzIGxpc3RlbmluZyB0byBjb25zb2xlIG1lc3NhZ2VzIGZyb20gdGhlIGJyb3dzZXInLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ3RvZ2dsZSdcclxuICAgICAgfVxyXG4gICAgfSxcclxuICAgIGR1bXBpbzoge1xyXG4gICAgICB2YWx1ZTogZmFsc2UsXHJcbiAgICAgIHR5cGVzOiBbJ2Jvb2xlYW4nXSxcclxuICAgICAgZW52TGluazogJ0RFQlVHX0RVTVBJTycsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdSZWRpcmVjdHMgb3Igbm90IGJyb3dzZXIgc3Rkb3V0IGFuZCBzdGRlcnIgdG8gcHJvY2Vzcy5zdGRvdXQgYW5kIHByb2Nlc3Muc3RkZXJyJyxcclxuICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgIHR5cGU6ICd0b2dnbGUnXHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICBzbG93TW86IHtcclxuICAgICAgdmFsdWU6IDAsXHJcbiAgICAgIHR5cGVzOiBbJ251bWJlciddLFxyXG4gICAgICBlbnZMaW5rOiAnREVCVUdfU0xPV19NTycsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnRGVsYXlzIFB1cHBldGVlciBvcGVyYXRpb25zIGJ5IHRoZSBzcGVjaWZpZWQgbWlsbGlzZWNvbmRzJyxcclxuICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgIHR5cGU6ICdudW1iZXInXHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICBkZWJ1Z2dpbmdQb3J0OiB7XHJcbiAgICAgIHZhbHVlOiA5MjIyLFxyXG4gICAgICB0eXBlczogWydudW1iZXInXSxcclxuICAgICAgZW52TGluazogJ0RFQlVHX0RFQlVHR0lOR19QT1JUJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdQb3J0IHVzZWQgZm9yIGRlYnVnZ2luZycsXHJcbiAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICB0eXBlOiAnbnVtYmVyJ1xyXG4gICAgICB9XHJcbiAgICB9XHJcbiAgfVxyXG59O1xyXG5cclxuLy8gUHJvcGVydGllcyBuZXN0aW5nIGxldmVsIG9mIGFsbCBvcHRpb25zXHJcbmV4cG9ydCBjb25zdCBuZXN0ZWRQcm9wcyA9IF9jcmVhdGVOZXN0ZWRQcm9wcyhkZWZhdWx0Q29uZmlnKTtcclxuXHJcbi8vIFByb3BlcnRpZXMgbmFtZXMgdGhhdCBzaG91bGQgbm90IGJlIHJlY3Vyc2l2ZWx5IG1lcmdlZFxyXG5leHBvcnQgY29uc3QgYWJzb2x1dGVQcm9wcyA9IF9jcmVhdGVBYnNvbHV0ZVByb3BzKGRlZmF1bHRDb25maWcpO1xyXG5cclxuLyoqXHJcbiAqIFJlY3Vyc2l2ZWx5IGdlbmVyYXRlcyBhIG1hcHBpbmcgb2YgbmVzdGVkIGFyZ3VtZW50IGNoYWlucyBmcm9tIGEgbmVzdGVkXHJcbiAqIGNvbmZpZyBvYmplY3QuIFRoaXMgZnVuY3Rpb24gdHJhdmVyc2VzIGEgbmVzdGVkIG9iamVjdCBhbmQgY3JlYXRlcyBhIG1hcHBpbmdcclxuICogd2hlcmUgZWFjaCBrZXkgaXMgYW4gYXJndW1lbnQgbmFtZSAoZWl0aGVyIGZyb20gYGNsaU5hbWVgLCBgbGVnYWN5TmFtZWAsXHJcbiAqIG9yIHRoZSBvcmlnaW5hbCBrZXkpIGFuZCBlYWNoIHZhbHVlIGlzIGEgc3RyaW5nIHJlcHJlc2VudGluZyB0aGUgY2hhaW5cclxuICogb2YgbmVzdGVkIHByb3BlcnRpZXMgbGVhZGluZyB0byB0aGF0IGFyZ3VtZW50LlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gX2NyZWF0ZU5lc3RlZFByb3BzXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBjb25maWcgLSBUaGUgY29uZmlndXJhdGlvbiBvYmplY3QuXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBbbmVzdGVkUHJvcHM9e31dIC0gVGhlIGFjY3VtdWxhdG9yIG9iamVjdCBmb3Igc3RvcmluZ1xyXG4gKiB0aGUgcmVzdWx0aW5nIGFyZ3VtZW50cyBjaGFpbnMuICBUaGUgZGVmYXVsdCB2YWx1ZSBpcyBhbiBlbXB0eSBvYmplY3QuXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSBbcHJvcENoYWluPScnXSAtIFRoZSBjdXJyZW50IGNoYWluIG9mIG5lc3RlZCBwcm9wZXJ0aWVzLFxyXG4gKiB1c2VkIGludGVybmFsbHkgZHVyaW5nIHJlY3Vyc2lvbi4gIFRoZSBkZWZhdWx0IHZhbHVlIGlzIGFuIGVtcHR5IHN0cmluZy5cclxuICpcclxuICogQHJldHVybnMge09iamVjdH0gQW4gb2JqZWN0IG1hcHBpbmcgYXJndW1lbnQgbmFtZXMgdG8gdGhlaXIgY29ycmVzcG9uZGluZ1xyXG4gKiBuZXN0ZWQgcHJvcGVydHkgY2hhaW5zLlxyXG4gKi9cclxuZnVuY3Rpb24gX2NyZWF0ZU5lc3RlZFByb3BzKGNvbmZpZywgbmVzdGVkUHJvcHMgPSB7fSwgcHJvcENoYWluID0gJycpIHtcclxuICBPYmplY3Qua2V5cyhjb25maWcpLmZvckVhY2goKGtleSkgPT4ge1xyXG4gICAgLy8gR2V0IHRoZSBzcGVjaWZpYyBzZWN0aW9uXHJcbiAgICBjb25zdCBlbnRyeSA9IGNvbmZpZ1trZXldO1xyXG5cclxuICAgIC8vIENoZWNrIGlmIHRoZXJlIGlzIHN0aWxsIG1vcmUgZGVwdGggdG8gdHJhdmVyc2VcclxuICAgIGlmICh0eXBlb2YgZW50cnkudmFsdWUgPT09ICd1bmRlZmluZWQnKSB7XHJcbiAgICAgIC8vIFJlY3Vyc2UgaW50byBkZWVwZXIgbGV2ZWxzIG9mIG5lc3RlZCBhcmd1bWVudHNcclxuICAgICAgX2NyZWF0ZU5lc3RlZFByb3BzKGVudHJ5LCBuZXN0ZWRQcm9wcywgYCR7cHJvcENoYWlufS4ke2tleX1gKTtcclxuICAgIH0gZWxzZSB7XHJcbiAgICAgIC8vIENyZWF0ZSB0aGUgY2hhaW4gb2YgbmVzdGVkIGFyZ3VtZW50c1xyXG4gICAgICBuZXN0ZWRQcm9wc1tlbnRyeS5jbGlOYW1lIHx8IGtleV0gPSBgJHtwcm9wQ2hhaW59LiR7a2V5fWAuc3Vic3RyaW5nKDEpO1xyXG5cclxuICAgICAgLy8gU3VwcG9ydCBmb3IgdGhlIGxlZ2FjeSwgUGhhbnRvbUpTIHByb3BlcnRpZXMgbmFtZXNcclxuICAgICAgaWYgKGVudHJ5LmxlZ2FjeU5hbWUgIT09IHVuZGVmaW5lZCkge1xyXG4gICAgICAgIG5lc3RlZFByb3BzW2VudHJ5LmxlZ2FjeU5hbWVdID0gYCR7cHJvcENoYWlufS4ke2tleX1gLnN1YnN0cmluZygxKTtcclxuICAgICAgfVxyXG4gICAgfVxyXG4gIH0pO1xyXG5cclxuICAvLyBSZXR1cm4gdGhlIG9iamVjdCB3aXRoIG5lc3RlZCBhcmd1bWVudCBjaGFpbnNcclxuICByZXR1cm4gbmVzdGVkUHJvcHM7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBSZWN1cnNpdmVseSBnYXRoZXJzIHRoZSBuYW1lcyBvZiBwcm9wZXJ0aWVzIGZyb20gYSBjb25maWd1cmF0aW9uIG9iamVjdCB0aGF0XHJcbiAqIGNhbiBiZSB0cmVhdGVkIGFzIGFic29sdXRlIHByb3BlcnRpZXMuIFRoZXNlIHByb3BlcnRpZXMgaGF2ZSB2YWx1ZXMgdGhhdFxyXG4gKiBhcmUgb2JqZWN0cyBhbmQgZG8gbm90IGNvbnRhaW4gZnVydGhlciBuZXN0ZWQgZGVwdGggd2hlbiBtZXJnaW5nIGFuIG9iamVjdFxyXG4gKiBjb250YWluaW5nIHRoZXNlIG9wdGlvbnMuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBfY3JlYXRlQWJzb2x1dGVQcm9wc1xyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gY29uZmlnIC0gVGhlIGNvbmZpZ3VyYXRpb24gb2JqZWN0LlxyXG4gKiBAcGFyYW0ge0FycmF5LjxzdHJpbmc+fSBbYWJzb2x1dGVQcm9wcz1bXV0gLSBBbiBhcnJheSB0byBjb2xsZWN0IHRoZSBuYW1lc1xyXG4gKiBvZiBhYnNvbHV0ZSBwcm9wZXJ0aWVzLiBUaGUgZGVmYXVsdCB2YWx1ZSBpcyBhbiBlbXB0eSBhcnJheS5cclxuICpcclxuICogQHJldHVybnMge0FycmF5LjxzdHJpbmc+fSBBbiBhcnJheSBjb250YWluaW5nIHRoZSBuYW1lcyBvZiBhYnNvbHV0ZVxyXG4gKiBwcm9wZXJ0aWVzLlxyXG4gKi9cclxuZnVuY3Rpb24gX2NyZWF0ZUFic29sdXRlUHJvcHMoY29uZmlnLCBhYnNvbHV0ZVByb3BzID0gW10pIHtcclxuICBPYmplY3Qua2V5cyhjb25maWcpLmZvckVhY2goKGtleSkgPT4ge1xyXG4gICAgLy8gR2V0IHRoZSBzcGVjaWZpYyBzZWN0aW9uXHJcbiAgICBjb25zdCBlbnRyeSA9IGNvbmZpZ1trZXldO1xyXG5cclxuICAgIC8vIENoZWNrIGlmIHRoZXJlIGlzIHN0aWxsIG1vcmUgZGVwdGggdG8gdHJhdmVyc2VcclxuICAgIGlmICh0eXBlb2YgZW50cnkudHlwZXMgPT09ICd1bmRlZmluZWQnKSB7XHJcbiAgICAgIC8vIFJlY3Vyc2UgaW50byBkZWVwZXIgbGV2ZWxzXHJcbiAgICAgIF9jcmVhdGVBYnNvbHV0ZVByb3BzKGVudHJ5LCBhYnNvbHV0ZVByb3BzKTtcclxuICAgIH0gZWxzZSB7XHJcbiAgICAgIC8vIElmIHRoZSBvcHRpb24gY2FuIGJlIGFuIG9iamVjdCwgc2F2ZSBpdHMgdHlwZSBpbiB0aGUgYXJyYXlcclxuICAgICAgaWYgKGVudHJ5LnR5cGVzLmluY2x1ZGVzKCdPYmplY3QnKSkge1xyXG4gICAgICAgIGFic29sdXRlUHJvcHMucHVzaChrZXkpO1xyXG4gICAgICB9XHJcbiAgICB9XHJcbiAgfSk7XHJcblxyXG4gIC8vIFJldHVybiB0aGUgYXJyYXkgd2l0aCB0aGUgbmFtZXMgb2YgYWJzb2x1dGUgcHJvcGVydGllc1xyXG4gIHJldHVybiBhYnNvbHV0ZVByb3BzO1xyXG59XHJcblxyXG5leHBvcnQgZGVmYXVsdCB7XHJcbiAgZGVmYXVsdENvbmZpZyxcclxuICBuZXN0ZWRQcm9wcyxcclxuICBhYnNvbHV0ZVByb3BzXHJcbn07XHJcbiIsIi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXHJcblxyXG5IaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXJcclxuXHJcbkNvcHlyaWdodCAoYykgMjAxNi0yMDI1LCBIaWdoc29mdFxyXG5cclxuTGljZW5jZWQgdW5kZXIgdGhlIE1JVCBsaWNlbmNlLlxyXG5cclxuQWRkaXRpb25hbGx5IGEgdmFsaWQgSGlnaGNoYXJ0cyBsaWNlbnNlIGlzIHJlcXVpcmVkIGZvciB1c2UuXHJcblxyXG5TZWUgTElDRU5TRSBmaWxlIGluIHJvb3QgZm9yIGRldGFpbHMuXHJcblxyXG4qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xyXG5cclxuLyoqXHJcbiAqIEBvdmVydmlldyBUaGlzIGZpbGUgaGFuZGxlcyBwYXJzaW5nIGFuZCB2YWxpZGF0aW5nIG9wdGlvbnMgZnJvbSBtdWx0aXBsZVxyXG4gKiBzb3VyY2VzICh0aGUgY29uZmlnIGZpbGUsIGN1c3RvbSBKU09OLCBlbnZpcm9ubWVudCB2YXJpYWJsZXMsIENMSSBhcmd1bWVudHMsXHJcbiAqIGFuZCByZXF1ZXN0IHBheWxvYWQpIHVzaW5nIHRoZSAnem9kJyBsaWJyYXJ5LlxyXG4gKlxyXG4gKiBFbnZpcm9ubWVudCB2YXJpYWJsZXMgYXJlIHBhcnNlZCBhbmQgdmFsaWRhdGVkIG9ubHkgb25jZSBhdCBhcHBsaWNhdGlvblxyXG4gKiBzdGFydHVwLCBhbmQgdGhlIHZhbGlkYXRlZCByZXN1bHRzIGFyZSBleHBvcnRlZCBhcyBgZW52c2AgZm9yIHVzZSB0aHJvdWdob3V0XHJcbiAqIHRoZSBhcHBsaWNhdGlvbi5cclxuICpcclxuICogT3B0aW9ucyBmcm9tIG90aGVyIHNvdXJjZXMsIGhvd2V2ZXIsIGFyZSBwYXJzZWQgYW5kIHZhbGlkYXRlZCBvbiBkZW1hbmQsXHJcbiAqIGVhY2ggdGltZSBhbiBleHBvcnQgaXMgYXR0ZW1wdGVkLlxyXG4gKi9cclxuXHJcbmltcG9ydCBkb3RlbnYgZnJvbSAnZG90ZW52JztcclxuaW1wb3J0IHsgeiB9IGZyb20gJ3pvZCc7XHJcblxyXG5pbXBvcnQgeyBkZWZhdWx0Q29uZmlnIH0gZnJvbSAnLi9zY2hlbWFzL2NvbmZpZy5qcyc7XHJcblxyXG4vLyBMb2FkIHRoZSAuZW52IGludG8gZW52aXJvbm1lbnQgdmFyaWFibGVzXHJcbmRvdGVudi5jb25maWcoKTtcclxuXHJcbi8vIEdldCBzY3JpcHRzIG5hbWVzIG9mIGVhY2ggY2F0ZWdvcnkgZnJvbSB0aGUgZGVmYXVsdCBjb25maWdcclxuY29uc3QgeyBjb3JlU2NyaXB0cywgbW9kdWxlU2NyaXB0cywgaW5kaWNhdG9yU2NyaXB0cyB9ID1cclxuICBkZWZhdWx0Q29uZmlnLmhpZ2hjaGFydHM7XHJcblxyXG4vLyBTZXRzIHRoZSBjdXN0b20gZXJyb3IgbWFwIGdsb2JhbGx5XHJcbnouc2V0RXJyb3JNYXAoX2N1c3RvbUVycm9yTWFwKTtcclxuXHJcbi8qKlxyXG4gKiBPYmplY3QgY29udGFpbmluZyBjdXN0b20gZ2VuZXJhbCB2YWxpZGF0b3JzIGFuZCBwYXJzZXJzIHRvIGF2b2lkIHJlcGV0aXRpb25cclxuICogaW4gc2NoZW1hIG9iamVjdHMuIEFsbCB2YWxpZGF0b3JzIGFwcGx5IHRvIHZhbHVlcyBmcm9tIHZhcmlvdXMgc291cmNlcyxcclxuICogaW5jbHVkaW5nIHRoZSBkZWZhdWx0IGNvbmZpZyBmaWxlLCBhIGN1c3RvbSBKU09OIGZpbGUgbG9hZGVkIHdpdGggdGhlIG9wdGlvblxyXG4gKiBjYWxsZWQgYGxvYWRDb25maWdgLCB0aGUgLmVudiBmaWxlLCBDTEkgYXJndW1lbnRzLCBhbmQgdGhlIHJlcXVlc3QgcGF5bG9hZC5cclxuICogVGhlIGBzdHJpY3RDaGVja2AgZmxhZyBlbmFibGVzIHN0cmljdGVyIHZhbGlkYXRpb24gYW5kIHBhcnNpbmcgcnVsZXMuIFRoaXNcclxuICogZmxhZyBpcyBzZXQgdG8gZmFsc2UgZm9yIHZhbHVlcyB0aGF0IGNvbWUgZnJvbSB0aGUgLmVudiBmaWxlIG9yIENMSSBhcmd1bWVudHNcclxuICogYmVjYXVzZSB0aGV5IGFyZSBwcm92aWRlZCBhcyBzdHJpbmdzIGFuZCBuZWVkIHRvIGJlIHBhcnNlZCBhY2NvcmRpbmdseSBmaXJzdC5cclxuICovXHJcbmNvbnN0IHYgPSB7XHJcbiAgLyoqXHJcbiAgICogVGhlIGBib29sZWFuYCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoIGFuIG9wdGlvbmFsIHN0cmljdGVyXHJcbiAgICogY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhhdDpcclxuICAgKlxyXG4gICAqIC0gV2hlbiBgc3RyaWN0Q2hlY2tgIGlzIHRydWUsIHRoZSBzY2hlbWEgd2lsbCBhY2NlcHQgdmFsdWVzIGFyZSB0cnVlXHJcbiAgICogYW5kIGZhbHNlIGFuZCB0aGUgc2NoZW1hIHdpbGwgdmFsaWRhdGUgYWdhaW5zdCB0aGUgZGVmYXVsdCBib29sZWFuXHJcbiAgICogdmFsaWRhdG9yLlxyXG4gICAqXHJcbiAgICogLSBXaGVuIGBzdHJpY3RDaGVja2AgaXMgZmFsc2UsIHRoZSBzY2hlbWEgd2lsbCBhY2NlcHQgdmFsdWVzIGFyZSB0cnVlLFxyXG4gICAqIGZhbHNlLCBudWxsLCAndHJ1ZScsICcxJywgJ2ZhbHNlJywgJzAnLCAndW5kZWZpbmVkJywgJ251bGwnLCBhbmQgJycuXHJcbiAgICogVGhlIHN0cmluZ3MgJ3VuZGVmaW5lZCcsICdudWxsJywgYW5kICcnIHdpbGwgYmUgdHJhbnNmb3JtZWQgdG8gbnVsbCxcclxuICAgKiB0aGUgc3RyaW5nICd0cnVlJyB3aWxsIGJlIHRyYW5zZm9ybWVkIHRvIHRoZSBib29sZWFuIHZhbHVlIHRydWUsXHJcbiAgICogYW5kICdmYWxzZScgd2lsbCBiZSB0cmFuc2Zvcm1lZCB0byB0aGUgYm9vbGVhbiB2YWx1ZSBmYWxzZS5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiBib29sZWFuXHJcbiAgICpcclxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IHN0cmljdENoZWNrIC0gRGV0ZXJtaW5lcyBpZiBzdHJpY3RlciB2YWxpZGF0aW9uIHNob3VsZFxyXG4gICAqIGJlIGFwcGxpZWQuXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9IEEgWm9kIHNjaGVtYSBvYmplY3QgZm9yIHZhbGlkYXRpbmcgYm9vbGVhbiB2YWx1ZXMuXHJcbiAgICovXHJcbiAgYm9vbGVhbihzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHN0cmljdENoZWNrXHJcbiAgICAgID8gei5ib29sZWFuKClcclxuICAgICAgOiB6XHJcbiAgICAgICAgICAudW5pb24oW1xyXG4gICAgICAgICAgICB6XHJcbiAgICAgICAgICAgICAgLmVudW0oWyd0cnVlJywgJzEnLCAnZmFsc2UnLCAnMCcsICd1bmRlZmluZWQnLCAnbnVsbCcsICcnXSlcclxuICAgICAgICAgICAgICAudHJhbnNmb3JtKCh2YWx1ZSkgPT5cclxuICAgICAgICAgICAgICAgICFbJ3VuZGVmaW5lZCcsICdudWxsJywgJyddLmluY2x1ZGVzKHZhbHVlKVxyXG4gICAgICAgICAgICAgICAgICA/IHZhbHVlID09PSAndHJ1ZScgfHwgdmFsdWUgPT09ICcxJ1xyXG4gICAgICAgICAgICAgICAgICA6IG51bGxcclxuICAgICAgICAgICAgICApLFxyXG4gICAgICAgICAgICB6LmJvb2xlYW4oKVxyXG4gICAgICAgICAgXSlcclxuICAgICAgICAgIC5udWxsYWJsZSgpO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgc3RyaW5nYCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoIGFuIG9wdGlvbmFsIHN0cmljdGVyXHJcbiAgICogY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhhdDpcclxuICAgKlxyXG4gICAqIC0gV2hlbiBgc3RyaWN0Q2hlY2tgIGlzIHRydWUsIHRoZSBzY2hlbWEgd2lsbCBhY2NlcHQgdHJpbW1lZCBzdHJpbmdzIGV4Y2VwdFxyXG4gICAqIHRoZSBmb3JiaWRkZW4gdmFsdWVzOiAnZmFsc2UnLCAndW5kZWZpbmVkJywgJ251bGwnLCBhbmQgJycuXHJcbiAgICpcclxuICAgKiAtIFdoZW4gYHN0cmljdENoZWNrYCBpcyBmYWxzZSwgdGhlIHNjaGVtYSB3aWxsIGFjY2VwdCB0cmltbWVkIHN0cmluZ3NcclxuICAgKiBhbmQgbnVsbC4gVGhlIGZvcmJpZGRlbiB2YWx1ZXM6ICdmYWxzZScsICd1bmRlZmluZWQnLCAnbnVsbCcsIGFuZCAnJyB3aWxsXHJcbiAgICogYmUgdHJhbnNmb3JtZWQgdG8gbnVsbC5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiBzdHJpbmdcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZyBzdHJpbmcgdmFsdWVzLlxyXG4gICAqL1xyXG4gIHN0cmluZyhzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHN0cmljdENoZWNrXHJcbiAgICAgID8gelxyXG4gICAgICAgICAgLnN0cmluZygpXHJcbiAgICAgICAgICAudHJpbSgpXHJcbiAgICAgICAgICAucmVmaW5lKFxyXG4gICAgICAgICAgICAodmFsdWUpID0+ICFbJ2ZhbHNlJywgJ3VuZGVmaW5lZCcsICdudWxsJywgJyddLmluY2x1ZGVzKHZhbHVlKSxcclxuICAgICAgICAgICAge1xyXG4gICAgICAgICAgICAgIHBhcmFtczoge1xyXG4gICAgICAgICAgICAgICAgZXJyb3JNZXNzYWdlOiAnVGhlIHN0cmluZyBjb250YWlucyBhIGZvcmJpZGRlbiB2YWx1ZSdcclxuICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgIH1cclxuICAgICAgICAgIClcclxuICAgICAgOiB6XHJcbiAgICAgICAgICAuc3RyaW5nKClcclxuICAgICAgICAgIC50cmltKClcclxuICAgICAgICAgIC50cmFuc2Zvcm0oKHZhbHVlKSA9PlxyXG4gICAgICAgICAgICAhWydmYWxzZScsICd1bmRlZmluZWQnLCAnbnVsbCcsICcnXS5pbmNsdWRlcyh2YWx1ZSkgPyB2YWx1ZSA6IG51bGxcclxuICAgICAgICAgIClcclxuICAgICAgICAgIC5udWxsYWJsZSgpO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgZW51bWAgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbCBzdHJpY3RlclxyXG4gICAqIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSBzY2hlbWEgd2lsbCB2YWxpZGF0ZSBhZ2FpbnN0IHRoZSBwcm92aWRlZCBgdmFsdWVzYCBhcnJheS5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoYXQ6XHJcbiAgICpcclxuICAgKiAtIFdoZW4gYHN0cmljdENoZWNrYCBpcyB0cnVlLCB0aGUgc2NoZW1hIHdpbGwgdmFsaWRhdGUgYWdhaW5zdCB0aGUgYHZhbHVlc2BcclxuICAgKiBhcnJheSB3aXRoIHRoZSBkZWZhdWx0IGVudW0gdmFsaWRhdG9yLlxyXG4gICAqXHJcbiAgICogLSBXaGVuIGBzdHJpY3RDaGVja2AgaXMgZmFsc2UsIHRoZSBzY2hlbWEgd2lsbCBhY2NlcHQgYWxzbyBudWxsLFxyXG4gICAqICd1bmRlZmluZWQnLCAnbnVsbCcsIGFuZCAnJywgd2hpY2ggd2lsbCBiZSB0cmFuc2Zvcm1lZCB0byBudWxsLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIGVudW1cclxuICAgKlxyXG4gICAqIEBwYXJhbSB7QXJyYXkuPHN0cmluZz59IHZhbHVlcyAtIEFuIGFycmF5IG9mIHZhbGlkIHN0cmluZyB2YWx1ZXNcclxuICAgKiBmb3IgdGhlIGVudW0uXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nIGVudW0gdmFsdWVzLlxyXG4gICAqL1xyXG4gIGVudW0odmFsdWVzLCBzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHN0cmljdENoZWNrXHJcbiAgICAgID8gei5lbnVtKFsuLi52YWx1ZXNdKVxyXG4gICAgICA6IHpcclxuICAgICAgICAgIC5lbnVtKFsuLi52YWx1ZXMsICd1bmRlZmluZWQnLCAnbnVsbCcsICcnXSlcclxuICAgICAgICAgIC50cmFuc2Zvcm0oKHZhbHVlKSA9PlxyXG4gICAgICAgICAgICAhWyd1bmRlZmluZWQnLCAnbnVsbCcsICcnXS5pbmNsdWRlcyh2YWx1ZSkgPyB2YWx1ZSA6IG51bGxcclxuICAgICAgICAgIClcclxuICAgICAgICAgIC5udWxsYWJsZSgpO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgc3RyaW5nQXJyYXlgIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGggYW4gb3B0aW9uYWxcclxuICAgKiBzdHJpY3RlciBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGF0OlxyXG4gICAqXHJcbiAgICogLSBXaGVuIGBzdHJpY3RDaGVja2AgaXMgdHJ1ZSwgdGhlIHNjaGVtYSB3aWxsIGFjY2VwdCBhbiBhcnJheSBvZiB0cmltbWVkXHJcbiAgICogc3RyaW5nIHZhbHVlcyBmaWx0ZXJlZCBieSB0aGUgbG9naWMgcHJvdmlkZWQgdGhyb3VnaCB0aGUgYGZpbHRlckNhbGxiYWNrYC5cclxuICAgKlxyXG4gICAqIC0gV2hlbiBgc3RyaWN0Q2hlY2tgIGlzIGZhbHNlLCB0aGUgc2NoZW1hIHdpbGwgYWNjZXB0IG51bGwgYW5kIHRyaW1tZWRcclxuICAgKiBzdHJpbmcgdmFsdWVzIHdoaWNoIHdpbGwgYmUgc3BsaXR0ZWQgaW50byBhbiBhcnJheSBvZiBzdHJpbmdzIGFuZCBmaWx0ZXJlZFxyXG4gICAqIGZyb20gdGhlICdbJyBhbmQgJ10nIGNoYXJhY3RlcnMgYW5kIGJ5IHRoZSBsb2dpYyBwcm92aWRlZCB0aHJvdWdoXHJcbiAgICogdGhlIGBmaWx0ZXJDYWxsYmFja2AuIElmIHRoZSBhcnJheSBpcyBlbXB0eSwgaXQgd2lsbCBiZSB0cmFuc2Zvcm1lZFxyXG4gICAqIHRvIG51bGwuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gc3RyaW5nQXJyYXlcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7ZnVuY3Rpb259IGZpbHRlckNhbGxiYWNrIC0gVGhlIGZpbHRlciBjYWxsYmFjay5cclxuICAgKiBAcGFyYW0ge3N0cmluZ30gc2VwYXJhdG9yIC0gVGhlIHNlcGFyYXRvciBmb3Igc3BsaXRpbmcgYSBzdHJpbmcuXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nIGFycmF5IG9mIHN0cmluZ1xyXG4gICAqIHZhbHVlcy5cclxuICAgKi9cclxuICBzdHJpbmdBcnJheShmaWx0ZXJDYWxsYmFjaywgc2VwYXJhdG9yLCBzdHJpY3RDaGVjaykge1xyXG4gICAgY29uc3QgYXJyYXlTY2hlbWEgPSB6LnN0cmluZygpLnRyaW0oKS5hcnJheSgpO1xyXG4gICAgY29uc3Qgc3RyaW5nU2NoZW1hID0gelxyXG4gICAgICAuc3RyaW5nKClcclxuICAgICAgLnRyaW0oKVxyXG4gICAgICAudHJhbnNmb3JtKCh2YWx1ZSkgPT4ge1xyXG4gICAgICAgIGlmICh2YWx1ZS5zdGFydHNXaXRoKCdbJykpIHtcclxuICAgICAgICAgIHZhbHVlID0gdmFsdWUuc2xpY2UoMSk7XHJcbiAgICAgICAgfVxyXG4gICAgICAgIGlmICh2YWx1ZS5lbmRzV2l0aCgnXScpKSB7XHJcbiAgICAgICAgICB2YWx1ZSA9IHZhbHVlLnNsaWNlKDAsIC0xKTtcclxuICAgICAgICB9XHJcbiAgICAgICAgcmV0dXJuIHZhbHVlLnNwbGl0KHNlcGFyYXRvcik7XHJcbiAgICAgIH0pO1xyXG5cclxuICAgIGNvbnN0IHRyYW5zZm9ybUNhbGxiYWNrID0gKHZhbHVlKSA9PlxyXG4gICAgICB2YWx1ZS5tYXAoKHZhbHVlKSA9PiB2YWx1ZS50cmltKCkpLmZpbHRlcihmaWx0ZXJDYWxsYmFjayk7XHJcblxyXG4gICAgcmV0dXJuIHN0cmljdENoZWNrXHJcbiAgICAgID8gYXJyYXlTY2hlbWEudHJhbnNmb3JtKHRyYW5zZm9ybUNhbGxiYWNrKVxyXG4gICAgICA6IHpcclxuICAgICAgICAgIC51bmlvbihbc3RyaW5nU2NoZW1hLCBhcnJheVNjaGVtYV0pXHJcbiAgICAgICAgICAudHJhbnNmb3JtKHRyYW5zZm9ybUNhbGxiYWNrKVxyXG4gICAgICAgICAgLnRyYW5zZm9ybSgodmFsdWUpID0+ICh2YWx1ZS5sZW5ndGggPyB2YWx1ZSA6IG51bGwpKVxyXG4gICAgICAgICAgLm51bGxhYmxlKCk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGBwb3NpdGl2ZU51bWAgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbFxyXG4gICAqIHN0cmljdGVyIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoYXQ6XHJcbiAgICpcclxuICAgKiAtIFdoZW4gYHN0cmljdENoZWNrYCBpcyB0cnVlLCB0aGUgc2NoZW1hIHdpbGwgYWNjZXB0IHBvc2l0aXZlIG51bWJlciB2YWx1ZXNcclxuICAgKiBhbmQgdmFsaWRhdGUgYWdhaW5zdCB0aGUgZGVmYXVsdCBwb3NpdGl2ZSBudW1iZXIgdmFsaWRhdG9yLlxyXG4gICAqXHJcbiAgICogLSBXaGVuIGBzdHJpY3RDaGVja2AgaXMgZmFsc2UsIHRoZSBzY2hlbWEgd2lsbCBhY2NlcHQgcG9zaXRpdmUgbnVtYmVyXHJcbiAgICogdmFsdWVzLCBudWxsLCBhbmQgdHJpbW1lZCBzdHJpbmcgdmFsdWVzIHRoYXQgY2FuIGVpdGhlciBiZSAndW5kZWZpbmVkJyxcclxuICAgKiAnbnVsbCcsICcnLCBvciByZXByZXNlbnQgYSBwb3NpdGl2ZSBudW1iZXIuIEl0IHdpbGwgdHJhbnNmb3JtIHRoZSBzdHJpbmdcclxuICAgKiB0byBhIHBvc2l0aXZlIG51bWJlciwgb3IgdG8gbnVsbCBpZiBpdCBpcyAndW5kZWZpbmVkJywgJ251bGwnLCBvciAnJy5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiBwb3NpdGl2ZU51bVxyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nIHBvc2l0aXZlIG51bWJlclxyXG4gICAqIHZhbHVlcy5cclxuICAgKi9cclxuICBwb3NpdGl2ZU51bShzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHN0cmljdENoZWNrXHJcbiAgICAgID8gei5udW1iZXIoKS5wb3NpdGl2ZSgpXHJcbiAgICAgIDogelxyXG4gICAgICAgICAgLnVuaW9uKFtcclxuICAgICAgICAgICAgelxyXG4gICAgICAgICAgICAgIC5zdHJpbmcoKVxyXG4gICAgICAgICAgICAgIC50cmltKClcclxuICAgICAgICAgICAgICAucmVmaW5lKFxyXG4gICAgICAgICAgICAgICAgKHZhbHVlKSA9PlxyXG4gICAgICAgICAgICAgICAgICAoIWlzTmFOKE51bWJlcih2YWx1ZSkpICYmIE51bWJlcih2YWx1ZSkgPiAwKSB8fFxyXG4gICAgICAgICAgICAgICAgICBbJ3VuZGVmaW5lZCcsICdudWxsJywgJyddLmluY2x1ZGVzKHZhbHVlKSxcclxuICAgICAgICAgICAgICAgIHtcclxuICAgICAgICAgICAgICAgICAgcGFyYW1zOiB7XHJcbiAgICAgICAgICAgICAgICAgICAgZXJyb3JNZXNzYWdlOiAnVGhlIHZhbHVlIG11c3QgYmUgbnVtZXJpYyBhbmQgcG9zaXRpdmUnXHJcbiAgICAgICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgICApXHJcbiAgICAgICAgICAgICAgLnRyYW5zZm9ybSgodmFsdWUpID0+XHJcbiAgICAgICAgICAgICAgICAhWyd1bmRlZmluZWQnLCAnbnVsbCcsICcnXS5pbmNsdWRlcyh2YWx1ZSlcclxuICAgICAgICAgICAgICAgICAgPyBOdW1iZXIodmFsdWUpXHJcbiAgICAgICAgICAgICAgICAgIDogbnVsbFxyXG4gICAgICAgICAgICAgICksXHJcbiAgICAgICAgICAgIHoubnVtYmVyKCkucG9zaXRpdmUoKVxyXG4gICAgICAgICAgXSlcclxuICAgICAgICAgIC5udWxsYWJsZSgpO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgbm9uTmVnYXRpdmVOdW1gIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGggYW4gb3B0aW9uYWxcclxuICAgKiBzdHJpY3RlciBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGF0OlxyXG4gICAqXHJcbiAgICogLSBXaGVuIGBzdHJpY3RDaGVja2AgaXMgdHJ1ZSwgdGhlIHNjaGVtYSB3aWxsIGFjY2VwdCBub24tbmVnYXRpdmUgbnVtYmVyXHJcbiAgICogdmFsdWVzIGFuZCB2YWxpZGF0ZSBhZ2FpbnN0IHRoZSBkZWZhdWx0IG5vbi1uZWdhdGl2ZSBudW1iZXIgdmFsaWRhdG9yLlxyXG4gICAqXHJcbiAgICogLSBXaGVuIGBzdHJpY3RDaGVja2AgaXMgZmFsc2UsIHRoZSBzY2hlbWEgd2lsbCBhY2NlcHQgbm9uLW5lZ2F0aXZlIG51bWJlclxyXG4gICAqIHZhbHVlcywgbnVsbCwgYW5kIHRyaW1tZWQgc3RyaW5nIHZhbHVlcyB0aGF0IGNhbiBlaXRoZXIgYmUgJ3VuZGVmaW5lZCcsXHJcbiAgICogJ251bGwnLCAnJywgb3IgcmVwcmVzZW50IGEgbm9uLW5lZ2F0aXZlIG51bWJlci4gSXQgd2lsbCB0cmFuc2Zvcm1cclxuICAgKiB0aGUgc3RyaW5nIHRvIGEgbm9uLW5lZ2F0aXZlIG51bWJlciwgb3IgdG8gbnVsbCBpZiBpdCBpcyAndW5kZWZpbmVkJyxcclxuICAgKiAnbnVsbCcsIG9yICcnLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIG5vbk5lZ2F0aXZlTnVtXHJcbiAgICpcclxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IHN0cmljdENoZWNrIC0gRGV0ZXJtaW5lcyBpZiBzdHJpY3RlciB2YWxpZGF0aW9uIHNob3VsZFxyXG4gICAqIGJlIGFwcGxpZWQuXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9IEEgWm9kIHNjaGVtYSBvYmplY3QgZm9yIHZhbGlkYXRpbmcgbm9uLW5lZ2F0aXZlXHJcbiAgICogbnVtYmVyIHZhbHVlcy5cclxuICAgKi9cclxuICBub25OZWdhdGl2ZU51bShzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHN0cmljdENoZWNrXHJcbiAgICAgID8gei5udW1iZXIoKS5ub25uZWdhdGl2ZSgpXHJcbiAgICAgIDogelxyXG4gICAgICAgICAgLnVuaW9uKFtcclxuICAgICAgICAgICAgelxyXG4gICAgICAgICAgICAgIC5zdHJpbmcoKVxyXG4gICAgICAgICAgICAgIC50cmltKClcclxuICAgICAgICAgICAgICAucmVmaW5lKFxyXG4gICAgICAgICAgICAgICAgKHZhbHVlKSA9PlxyXG4gICAgICAgICAgICAgICAgICAoIWlzTmFOKE51bWJlcih2YWx1ZSkpICYmIE51bWJlcih2YWx1ZSkgPj0gMCkgfHxcclxuICAgICAgICAgICAgICAgICAgWyd1bmRlZmluZWQnLCAnbnVsbCcsICcnXS5pbmNsdWRlcyh2YWx1ZSksXHJcbiAgICAgICAgICAgICAgICB7XHJcbiAgICAgICAgICAgICAgICAgIHBhcmFtczoge1xyXG4gICAgICAgICAgICAgICAgICAgIGVycm9yTWVzc2FnZTogJ1RoZSB2YWx1ZSBtdXN0IGJlIG51bWVyaWMgYW5kIG5vbi1uZWdhdGl2ZSdcclxuICAgICAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICAgIClcclxuICAgICAgICAgICAgICAudHJhbnNmb3JtKCh2YWx1ZSkgPT5cclxuICAgICAgICAgICAgICAgICFbJ3VuZGVmaW5lZCcsICdudWxsJywgJyddLmluY2x1ZGVzKHZhbHVlKVxyXG4gICAgICAgICAgICAgICAgICA/IE51bWJlcih2YWx1ZSlcclxuICAgICAgICAgICAgICAgICAgOiBudWxsXHJcbiAgICAgICAgICAgICAgKSxcclxuICAgICAgICAgICAgei5udW1iZXIoKS5ub25uZWdhdGl2ZSgpXHJcbiAgICAgICAgICBdKVxyXG4gICAgICAgICAgLm51bGxhYmxlKCk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGBzdGFydHNXaXRoYCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoIGFuIG9wdGlvbmFsXHJcbiAgICogc3RyaWN0ZXIgY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHNjaGVtYSB3aWxsIHZhbGlkYXRlIGFnYWluc3QgdGhlIHByb3ZpZGVkIGBwcmVmaXhlc2AgYXJyYXkgdG8gY2hlY2tcclxuICAgKiB3aGV0aGVyIGEgc3RyaW5nIHZhbHVlIHN0YXJ0cyB3aXRoIGFueSBvZiB0aGUgdmFsdWVzIHByb3ZpZGVkXHJcbiAgICogaW4gdGhlIGBwcmVmaXhlc2AgYXJyYXkuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGF0OlxyXG4gICAqXHJcbiAgICogLSBXaGVuIGBzdHJpY3RDaGVja2AgaXMgdHJ1ZSwgdGhlIHNjaGVtYSB3aWxsIGFjY2VwdCB0cmltbWVkIHN0cmluZyB2YWx1ZXNcclxuICAgKiB0aGF0IHN0YXJ0IHdpdGggdmFsdWVzIGZyb20gdGhlIHByZWZpeGVzIGFycmF5LlxyXG4gICAqXHJcbiAgICogLSBXaGVuIGBzdHJpY3RDaGVja2AgaXMgZmFsc2UsIHRoZSBzY2hlbWEgd2lsbCBhY2NlcHQgdHJpbW1lZCBzdHJpbmcgdmFsdWVzXHJcbiAgICogdGhhdCBzdGFydCB3aXRoIHZhbHVlcyBmcm9tIHRoZSBwcmVmaXhlcyBhcnJheSwgbnVsbCwgJ3VuZGVmaW5lZCcsICdudWxsJyxcclxuICAgKiBhbmQgJycgd2hlcmUgdGhlIHNjaGVtYSB3aWxsIHRyYW5zZm9ybSB0aGVtIHRvIG51bGwuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gc3RhcnRzV2l0aFxyXG4gICAqXHJcbiAgICogQHBhcmFtIHtBcnJheS48c3RyaW5nPn0gcHJlZml4ZXMgLSBBbiBhcnJheSBvZiBwcmVmaXhlcyB0byB2YWxpZGF0ZVxyXG4gICAqIHRoZSBzdHJpbmcgYWdhaW5zdC5cclxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IHN0cmljdENoZWNrIC0gRGV0ZXJtaW5lcyBpZiBzdHJpY3RlciB2YWxpZGF0aW9uIHNob3VsZFxyXG4gICAqIGJlIGFwcGxpZWQuXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9IEEgWm9kIHNjaGVtYSBvYmplY3QgZm9yIHZhbGlkYXRpbmcgc3RyaW5ncyB0aGF0XHJcbiAgICogc3RhcnRzIHdpdGggdmFsdWVzLlxyXG4gICAqL1xyXG4gIHN0YXJ0c1dpdGgocHJlZml4ZXMsIHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gc3RyaWN0Q2hlY2tcclxuICAgICAgPyB6XHJcbiAgICAgICAgICAuc3RyaW5nKClcclxuICAgICAgICAgIC50cmltKClcclxuICAgICAgICAgIC5yZWZpbmUoXHJcbiAgICAgICAgICAgICh2YWx1ZSkgPT4gcHJlZml4ZXMuc29tZSgocHJlZml4KSA9PiB2YWx1ZS5zdGFydHNXaXRoKHByZWZpeCkpLFxyXG4gICAgICAgICAgICB7XHJcbiAgICAgICAgICAgICAgcGFyYW1zOiB7XHJcbiAgICAgICAgICAgICAgICBlcnJvck1lc3NhZ2U6IGBUaGUgdmFsdWUgbXVzdCBiZSBhIHN0cmluZyB0aGF0IHN0YXJ0cyB3aXRoICR7cHJlZml4ZXMuam9pbignLCAnKX1gXHJcbiAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICB9XHJcbiAgICAgICAgICApXHJcbiAgICAgIDogelxyXG4gICAgICAgICAgLnN0cmluZygpXHJcbiAgICAgICAgICAudHJpbSgpXHJcbiAgICAgICAgICAucmVmaW5lKFxyXG4gICAgICAgICAgICAodmFsdWUpID0+XHJcbiAgICAgICAgICAgICAgcHJlZml4ZXMuc29tZSgocHJlZml4KSA9PiB2YWx1ZS5zdGFydHNXaXRoKHByZWZpeCkpIHx8XHJcbiAgICAgICAgICAgICAgWyd1bmRlZmluZWQnLCAnbnVsbCcsICcnXS5pbmNsdWRlcyh2YWx1ZSksXHJcbiAgICAgICAgICAgIHtcclxuICAgICAgICAgICAgICBwYXJhbXM6IHtcclxuICAgICAgICAgICAgICAgIGVycm9yTWVzc2FnZTogYFRoZSB2YWx1ZSBtdXN0IGJlIGEgc3RyaW5nIHRoYXQgc3RhcnRzIHdpdGggJHtwcmVmaXhlcy5qb2luKCcsICcpfWBcclxuICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgIH1cclxuICAgICAgICAgIClcclxuICAgICAgICAgIC50cmFuc2Zvcm0oKHZhbHVlKSA9PlxyXG4gICAgICAgICAgICAhWyd1bmRlZmluZWQnLCAnbnVsbCcsICcnXS5pbmNsdWRlcyh2YWx1ZSkgPyB2YWx1ZSA6IG51bGxcclxuICAgICAgICAgIClcclxuICAgICAgICAgIC5udWxsYWJsZSgpO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgY2hhcnRDb25maWdgIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhhdCB0aGUgc2NoZW1hIHdpbGwgYWNjZXB0IG9iamVjdCB2YWx1ZXNcclxuICAgKiBvciB0cmltbWVkIHN0cmluZyB2YWx1ZXMgdGhhdCBjb250YWluICc8c3ZnJyBvciAnPD94bWwnIGVsZW1lbnRzLCBzdGFydFxyXG4gICAqIHdpdGggdGhlICd7JyBhbmQgZW5kIHdpdGggdGhlICd9JywgYW5kIG51bGwuIFRoZSAndW5kZWZpbmVkJywgJ251bGwnLFxyXG4gICAqIGFuZCAnJyB2YWx1ZXMgd2lsbCBiZSB0cmFuc2Zvcm1lZCB0byBudWxsLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIGNoYXJ0Q29uZmlnXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9IEEgWm9kIHNjaGVtYSBvYmplY3QgZm9yIHZhbGlkYXRpbmcgY2hhcnRcclxuICAgKiBjb25maWd1cmF0aW9uIHZhbHVlLlxyXG4gICAqL1xyXG4gIGNoYXJ0Q29uZmlnKCkge1xyXG4gICAgcmV0dXJuIHpcclxuICAgICAgLnVuaW9uKFtcclxuICAgICAgICB6XHJcbiAgICAgICAgICAuc3RyaW5nKClcclxuICAgICAgICAgIC50cmltKClcclxuICAgICAgICAgIC5yZWZpbmUoXHJcbiAgICAgICAgICAgICh2YWx1ZSkgPT5cclxuICAgICAgICAgICAgICAodmFsdWUuc3RhcnRzV2l0aCgneycpICYmIHZhbHVlLmVuZHNXaXRoKCd9JykpIHx8XHJcbiAgICAgICAgICAgICAgWyd1bmRlZmluZWQnLCAnbnVsbCcsICcnXS5pbmNsdWRlcyh2YWx1ZSksXHJcbiAgICAgICAgICAgIHtcclxuICAgICAgICAgICAgICBwYXJhbXM6IHtcclxuICAgICAgICAgICAgICAgIGVycm9yTWVzc2FnZTpcclxuICAgICAgICAgICAgICAgICAgXCJUaGUgdmFsdWUgbXVzdCBiZSBhIHN0cmluZyB0aGF0IHN0YXJ0cyB3aXRoICd7JyBhbmQgZW5kcyB3aXRoICd9J1wiXHJcbiAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICB9XHJcbiAgICAgICAgICApXHJcbiAgICAgICAgICAudHJhbnNmb3JtKCh2YWx1ZSkgPT5cclxuICAgICAgICAgICAgIVsndW5kZWZpbmVkJywgJ251bGwnLCAnJ10uaW5jbHVkZXModmFsdWUpID8gdmFsdWUgOiBudWxsXHJcbiAgICAgICAgICApLFxyXG4gICAgICAgIHoub2JqZWN0KHt9KS5wYXNzdGhyb3VnaCgpXHJcbiAgICAgIF0pXHJcbiAgICAgIC5udWxsYWJsZSgpO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgYWRkaXRpb25hbE9wdGlvbnNgIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhhdCB0aGUgc2NoZW1hIHdpbGwgYWNjZXB0IG9iamVjdCB2YWx1ZXNcclxuICAgKiBvciB0cmltbWVkIHN0cmluZyB2YWx1ZXMgdGhhdCBlbmQgd2l0aCAnLmpzb24nIGFuZCBhcmUgYXQgbGVhc3Qgb25lXHJcbiAgICogY2hhcmFjdGVyIGxvbmcgZXhjbHVkaW5nIHRoZSBleHRlbnNpb24sIHN0YXJ0IHdpdGggdGhlICd7JyBhbmQgZW5kXHJcbiAgICogd2l0aCB0aGUgJ30nLCBhbmQgbnVsbC4gVGhlICd1bmRlZmluZWQnLCAnbnVsbCcsIGFuZCAnJyB2YWx1ZXMgd2lsbFxyXG4gICAqIGJlIHRyYW5zZm9ybWVkIHRvIG51bGwuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gYWRkaXRpb25hbE9wdGlvbnNcclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gIEEgWm9kIHNjaGVtYSBvYmplY3QgZm9yIHZhbGlkYXRpbmcgYWRkaXRpb25hbCBjaGFydFxyXG4gICAqIG9wdGlvbnMgdmFsdWUuXHJcbiAgICovXHJcbiAgYWRkaXRpb25hbE9wdGlvbnMoKSB7XHJcbiAgICByZXR1cm4gelxyXG4gICAgICAudW5pb24oW1xyXG4gICAgICAgIHpcclxuICAgICAgICAgIC5zdHJpbmcoKVxyXG4gICAgICAgICAgLnRyaW0oKVxyXG4gICAgICAgICAgLnJlZmluZShcclxuICAgICAgICAgICAgKHZhbHVlKSA9PlxyXG4gICAgICAgICAgICAgICh2YWx1ZS5sZW5ndGggPj0gNiAmJiB2YWx1ZS5lbmRzV2l0aCgnLmpzb24nKSkgfHxcclxuICAgICAgICAgICAgICAodmFsdWUuc3RhcnRzV2l0aCgneycpICYmIHZhbHVlLmVuZHNXaXRoKCd9JykpIHx8XHJcbiAgICAgICAgICAgICAgWyd1bmRlZmluZWQnLCAnbnVsbCcsICcnXS5pbmNsdWRlcyh2YWx1ZSksXHJcbiAgICAgICAgICAgIHtcclxuICAgICAgICAgICAgICBwYXJhbXM6IHtcclxuICAgICAgICAgICAgICAgIGVycm9yTWVzc2FnZTpcclxuICAgICAgICAgICAgICAgICAgXCJUaGUgdmFsdWUgbXVzdCBiZSBhIHN0cmluZyB0aGF0IGVuZHMgd2l0aCAnLmpzb24nIG9yIHN0YXJ0cyB3aXRoICd7JyBhbmQgZW5kcyB3aXRoICd9J1wiXHJcbiAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICB9XHJcbiAgICAgICAgICApXHJcbiAgICAgICAgICAudHJhbnNmb3JtKCh2YWx1ZSkgPT5cclxuICAgICAgICAgICAgIVsndW5kZWZpbmVkJywgJ251bGwnLCAnJ10uaW5jbHVkZXModmFsdWUpID8gdmFsdWUgOiBudWxsXHJcbiAgICAgICAgICApLFxyXG4gICAgICAgIHoub2JqZWN0KHt9KS5wYXNzdGhyb3VnaCgpXHJcbiAgICAgIF0pXHJcbiAgICAgIC5udWxsYWJsZSgpO1xyXG4gIH1cclxufTtcclxuXHJcbi8qKlxyXG4gKiBPYmplY3QgY29udGFpbmluZyBjdXN0b20gY29uZmlnIHZhbGlkYXRvcnMgYW5kIHBhcnNlcnMgdG8gYXZvaWQgcmVwZXRpdGlvblxyXG4gKiBpbiBzY2hlbWEgb2JqZWN0cy4gQWxsIHZhbGlkYXRvcnMgYXBwbHkgdG8gdmFsdWVzIGZyb20gdmFyaW91cyBzb3VyY2VzLFxyXG4gKiBpbmNsdWRpbmcgdGhlIGRlZmF1bHQgY29uZmlnIGZpbGUsIGEgY3VzdG9tIEpTT04gZmlsZSBsb2FkZWQgd2l0aCB0aGUgb3B0aW9uXHJcbiAqIGNhbGxlZCBgbG9hZENvbmZpZ2AsIHRoZSAuZW52IGZpbGUsIENMSSBhcmd1bWVudHMsIGFuZCB0aGUgcmVxdWVzdCBwYXlsb2FkLlxyXG4gKiBUaGUgYHN0cmljdENoZWNrYCBmbGFnIGVuYWJsZXMgc3RyaWN0ZXIgdmFsaWRhdGlvbiBhbmQgcGFyc2luZyBydWxlcy4gVGhpc1xyXG4gKiBmbGFnIGlzIHNldCB0byBmYWxzZSBmb3IgdmFsdWVzIHRoYXQgY29tZSBmcm9tIHRoZSAuZW52IGZpbGUgb3IgQ0xJIGFyZ3VtZW50c1xyXG4gKiBiZWNhdXNlIHRoZXkgYXJlIHByb3ZpZGVkIGFzIHN0cmluZ3MgYW5kIG5lZWQgdG8gYmUgcGFyc2VkIGFjY29yZGluZ2x5IGZpcnN0LlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IHZhbGlkYXRvcnMgPSB7XHJcbiAgLyoqXHJcbiAgICogVGhlIGBhcmdzYCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoIGFuIG9wdGlvbmFsIHN0cmljdGVyXHJcbiAgICogY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhlIHNhbWUgd29yayBhcyB0aGUgYHN0cmluZ0FycmF5YCB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gYXJnc1xyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nIHRoZSBgYXJnc2BcclxuICAgKiBvcHRpb24uXHJcbiAgICovXHJcbiAgYXJncyhzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHYuc3RyaW5nQXJyYXkoXHJcbiAgICAgICh2YWx1ZSkgPT4gIVsnZmFsc2UnLCAndW5kZWZpbmVkJywgJ251bGwnLCAnJ10uaW5jbHVkZXModmFsdWUpLFxyXG4gICAgICAnOycsXHJcbiAgICAgIHN0cmljdENoZWNrXHJcbiAgICApO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgdmVyc2lvbmAgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbCBzdHJpY3RlclxyXG4gICAqIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoYXQ6XHJcbiAgICpcclxuICAgKiAtIFdoZW4gYHN0cmljdENoZWNrYCBpcyB0cnVlLCB0aGUgc2NoZW1hIHdpbGwgYWNjZXB0IHRyaW1tZWQgc3RyaW5nIHZhbHVlc1xyXG4gICAqIHRoYXQgYXJlIGEgUmVnRXhwLWJhc2VkIHRoYXQgYWxsb3dzIHRvIGJlICdsYXRlc3QnLCBvciBpbiB0aGUgZm9ybWF0IFhYLFxyXG4gICAqIFhYLllZLCBvciBYWC5ZWS5aWiwgd2hlcmUgWFgsIFlZLCBhbmQgWlogYXJlIG51bWVyaWMgZm9yIHRoZSBIaWdoY2hhcnRzXHJcbiAgICogdmVyc2lvbiBvcHRpb24uXHJcbiAgICpcclxuICAgKiAtIFdoZW4gYHN0cmljdENoZWNrYCBpcyBmYWxzZSwgdGhlIHNjaGVtYSB3aWxsIGFjY2VwdCBhbHNvIG51bGwsXHJcbiAgICogJ3VuZGVmaW5lZCcsICdudWxsJywgb3IgJycgYW5kIGluIGFsbCBjYXNlcyB0aGUgc2NoZW1hIHdpbGwgdHJhbnNmb3JtIHRoZW1cclxuICAgKiB0byBudWxsLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIHZlcnNpb25cclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZyB0aGUgYHZlcnNpb25gXHJcbiAgICogb3B0aW9uLlxyXG4gICAqL1xyXG4gIHZlcnNpb24oc3RyaWN0Q2hlY2spIHtcclxuICAgIHJldHVybiBzdHJpY3RDaGVja1xyXG4gICAgICA/IHpcclxuICAgICAgICAgIC5zdHJpbmcoKVxyXG4gICAgICAgICAgLnRyaW0oKVxyXG4gICAgICAgICAgLnJlZmluZSgodmFsdWUpID0+IC9eKGxhdGVzdHxcXGR7MSwyfShcXC5cXGR7MSwyfSl7MCwyfSkkLy50ZXN0KHZhbHVlKSwge1xyXG4gICAgICAgICAgICBwYXJhbXM6IHtcclxuICAgICAgICAgICAgICBlcnJvck1lc3NhZ2U6XHJcbiAgICAgICAgICAgICAgICBcIlRoZSB2YWx1ZSBtdXN0IGJlICdsYXRlc3QnLCBhIG1ham9yIHZlcnNpb24sIG9yIGluIHRoZSBmb3JtIFhYLllZLlpaXCJcclxuICAgICAgICAgICAgfVxyXG4gICAgICAgICAgfSlcclxuICAgICAgOiB6XHJcbiAgICAgICAgICAuc3RyaW5nKClcclxuICAgICAgICAgIC50cmltKClcclxuICAgICAgICAgIC5yZWZpbmUoXHJcbiAgICAgICAgICAgICh2YWx1ZSkgPT5cclxuICAgICAgICAgICAgICAvXihsYXRlc3R8XFxkezEsMn0oXFwuXFxkezEsMn0pezAsMn0pJC8udGVzdCh2YWx1ZSkgfHxcclxuICAgICAgICAgICAgICBbJ3VuZGVmaW5lZCcsICdudWxsJywgJyddLmluY2x1ZGVzKHZhbHVlKSxcclxuICAgICAgICAgICAge1xyXG4gICAgICAgICAgICAgIHBhcmFtczoge1xyXG4gICAgICAgICAgICAgICAgZXJyb3JNZXNzYWdlOlxyXG4gICAgICAgICAgICAgICAgICBcIlRoZSB2YWx1ZSBtdXN0IGJlICdsYXRlc3QnLCBhIG1ham9yIHZlcnNpb24sIG9yIGluIHRoZSBmb3JtIFhYLllZLlpaXCJcclxuICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgIH1cclxuICAgICAgICAgIClcclxuICAgICAgICAgIC50cmFuc2Zvcm0oKHZhbHVlKSA9PlxyXG4gICAgICAgICAgICAhWyd1bmRlZmluZWQnLCAnbnVsbCcsICcnXS5pbmNsdWRlcyh2YWx1ZSkgPyB2YWx1ZSA6IG51bGxcclxuICAgICAgICAgIClcclxuICAgICAgICAgIC5udWxsYWJsZSgpO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgY2RuVXJsYCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoIGFuIG9wdGlvbmFsIHN0cmljdGVyXHJcbiAgICogY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhlIHNhbWUgd29yayBhcyB0aGUgYHN0YXJ0c1dpdGhgIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiBjZG5VcmxcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZyB0aGUgYGNkblVybGBcclxuICAgKiBvcHRpb24uXHJcbiAgICovXHJcbiAgY2RuVXJsKHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gdi5zdGFydHNXaXRoKFsnaHR0cDovLycsICdodHRwczovLyddLCBzdHJpY3RDaGVjayk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGBmb3JjZUZldGNoYCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoIGFuIG9wdGlvbmFsXHJcbiAgICogc3RyaWN0ZXIgY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhlIHNhbWUgd29yayBhcyB0aGUgYGJvb2xlYW5gIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiBmb3JjZUZldGNoXHJcbiAgICpcclxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IHN0cmljdENoZWNrIC0gRGV0ZXJtaW5lcyBpZiBzdHJpY3RlciB2YWxpZGF0aW9uIHNob3VsZFxyXG4gICAqIGJlIGFwcGxpZWQuXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9IEEgWm9kIHNjaGVtYSBvYmplY3QgZm9yIHZhbGlkYXRpbmcgdGhlIGBmb3JjZUZldGNoYFxyXG4gICAqIG9wdGlvbi5cclxuICAgKi9cclxuICBmb3JjZUZldGNoKHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gdi5ib29sZWFuKHN0cmljdENoZWNrKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYGNhY2hlUGF0aGAgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbFxyXG4gICAqIHN0cmljdGVyIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgdGhlIGBzdHJpbmdgIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiBjYWNoZVBhdGhcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZyB0aGUgYGNhY2hlUGF0aGBcclxuICAgKiBvcHRpb24uXHJcbiAgICovXHJcbiAgY2FjaGVQYXRoKHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gdi5zdHJpbmcoc3RyaWN0Q2hlY2spO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgYWRtaW5Ub2tlbmAgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbFxyXG4gICAqIHN0cmljdGVyIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgdGhlIGBzdHJpbmdgIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiBhZG1pblRva2VuXHJcbiAgICpcclxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IHN0cmljdENoZWNrIC0gRGV0ZXJtaW5lcyBpZiBzdHJpY3RlciB2YWxpZGF0aW9uIHNob3VsZFxyXG4gICAqIGJlIGFwcGxpZWQuXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9IEEgWm9kIHNjaGVtYSBvYmplY3QgZm9yIHZhbGlkYXRpbmcgdGhlIGBhZG1pblRva2VuYFxyXG4gICAqIG9wdGlvbi5cclxuICAgKi9cclxuICBhZG1pblRva2VuKHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gdi5zdHJpbmcoc3RyaWN0Q2hlY2spO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgY29yZVNjcmlwdHNgIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGggYW4gb3B0aW9uYWxcclxuICAgKiBzdHJpY3RlciBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGUgc2FtZSB3b3JrIGFzIHRoZSBgc3RyaW5nQXJyYXlgIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiBjb3JlU2NyaXB0c1xyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nIHRoZSBgY29yZVNjcmlwdHNgXHJcbiAgICogb3B0aW9uLlxyXG4gICAqL1xyXG4gIGNvcmVTY3JpcHRzKHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gdi5zdHJpbmdBcnJheShcclxuICAgICAgKHZhbHVlKSA9PiBjb3JlU2NyaXB0cy52YWx1ZS5pbmNsdWRlcyh2YWx1ZSksXHJcbiAgICAgICcsJyxcclxuICAgICAgc3RyaWN0Q2hlY2tcclxuICAgICk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGBtb2R1bGVTY3JpcHRzYCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoIGFuIG9wdGlvbmFsXHJcbiAgICogc3RyaWN0ZXIgY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhlIHNhbWUgd29yayBhcyB0aGUgYHN0cmluZ0FycmF5YCB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gbW9kdWxlU2NyaXB0c1xyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nXHJcbiAgICogdGhlIGBtb2R1bGVTY3JpcHRzYCBvcHRpb24uXHJcbiAgICovXHJcbiAgbW9kdWxlU2NyaXB0cyhzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHYuc3RyaW5nQXJyYXkoXHJcbiAgICAgICh2YWx1ZSkgPT4gbW9kdWxlU2NyaXB0cy52YWx1ZS5pbmNsdWRlcyh2YWx1ZSksXHJcbiAgICAgICcsJyxcclxuICAgICAgc3RyaWN0Q2hlY2tcclxuICAgICk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGBpbmRpY2F0b3JTY3JpcHRzYCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoIGFuIG9wdGlvbmFsXHJcbiAgICogc3RyaWN0ZXIgY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhlIHNhbWUgd29yayBhcyB0aGUgYHN0cmluZ0FycmF5YCB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gaW5kaWNhdG9yU2NyaXB0c1xyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nXHJcbiAgICogdGhlIGBpbmRpY2F0b3JTY3JpcHRzYCBvcHRpb24uXHJcbiAgICovXHJcbiAgaW5kaWNhdG9yU2NyaXB0cyhzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHYuc3RyaW5nQXJyYXkoXHJcbiAgICAgICh2YWx1ZSkgPT4gaW5kaWNhdG9yU2NyaXB0cy52YWx1ZS5pbmNsdWRlcyh2YWx1ZSksXHJcbiAgICAgICcsJyxcclxuICAgICAgc3RyaWN0Q2hlY2tcclxuICAgICk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGBjdXN0b21TY3JpcHRzYCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoIGFuIG9wdGlvbmFsXHJcbiAgICogc3RyaWN0ZXIgY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhlIHNhbWUgd29yayBhcyB0aGUgYHN0cmluZ0FycmF5YCB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gY3VzdG9tU2NyaXB0c1xyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nXHJcbiAgICogdGhlIGBjdXN0b21TY3JpcHRzYCBvcHRpb24uXHJcbiAgICovXHJcbiAgY3VzdG9tU2NyaXB0cyhzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHYuc3RyaW5nQXJyYXkoXHJcbiAgICAgICh2YWx1ZSkgPT4gdmFsdWUuc3RhcnRzV2l0aCgnaHR0cHM6Ly8nKSB8fCB2YWx1ZS5zdGFydHNXaXRoKCdodHRwOi8vJyksXHJcbiAgICAgICcsJyxcclxuICAgICAgc3RyaWN0Q2hlY2tcclxuICAgICk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGBpbmZpbGVgIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGggYW4gb3B0aW9uYWwgc3RyaWN0ZXJcclxuICAgKiBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGF0OlxyXG4gICAqXHJcbiAgICogLSBXaGVuIGBzdHJpY3RDaGVja2AgaXMgdHJ1ZSwgdGhlIHNjaGVtYSB3aWxsIGFjY2VwdCB0cmltbWVkIHN0cmluZyB2YWx1ZXNcclxuICAgKiB0aGF0IGVuZCB3aXRoICcuanNvbicgb3IgJy5zdmcnLCBhcmUgYXQgbGVhc3Qgb25lIGNoYXJhY3RlciBsb25nIGV4Y2x1ZGluZ1xyXG4gICAqIHRoZSBleHRlbnNpb24sIG9yIG51bGwuXHJcbiAgICpcclxuICAgKiAtIFdoZW4gYHN0cmljdENoZWNrYCBpcyBmYWxzZSwgdGhlIHNjaGVtYSB3aWxsIGFjY2VwdCB0cmltbWVkIHN0cmluZyB2YWx1ZXNcclxuICAgKiB0aGF0IGVuZCB3aXRoICcuanNvbicgb3IgJy5zdmcnLCBhcmUgYXQgbGVhc3Qgb25lIGNoYXJhY3RlciBsb25nIGV4Y2x1ZGluZ1xyXG4gICAqIHRoZSBleHRlbnNpb24gYW5kIHdpbGwgYmUgbnVsbCBpZiB0aGUgcHJvdmlkZWQgdmFsdWUgaXMgbnVsbCwgJ3VuZGVmaW5lZCcsXHJcbiAgICogJ251bGwnLCBvciAnJy5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiBpbmZpbGVcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZyB0aGUgYGluZmlsZWBcclxuICAgKiBvcHRpb24uXHJcbiAgICovXHJcbiAgaW5maWxlKHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gc3RyaWN0Q2hlY2tcclxuICAgICAgPyB6XHJcbiAgICAgICAgICAuc3RyaW5nKClcclxuICAgICAgICAgIC50cmltKClcclxuICAgICAgICAgIC5yZWZpbmUoXHJcbiAgICAgICAgICAgICh2YWx1ZSkgPT5cclxuICAgICAgICAgICAgICAodmFsdWUubGVuZ3RoID49IDYgJiYgdmFsdWUuZW5kc1dpdGgoJy5qc29uJykpIHx8XHJcbiAgICAgICAgICAgICAgKHZhbHVlLmxlbmd0aCA+PSA1ICYmIHZhbHVlLmVuZHNXaXRoKCcuc3ZnJykpLFxyXG4gICAgICAgICAgICB7XHJcbiAgICAgICAgICAgICAgcGFyYW1zOiB7XHJcbiAgICAgICAgICAgICAgICBlcnJvck1lc3NhZ2U6XHJcbiAgICAgICAgICAgICAgICAgICdUaGUgdmFsdWUgbXVzdCBiZSBhIHN0cmluZyB0aGF0IGVuZHMgd2l0aCAuanNvbiBvciAuc3ZnJ1xyXG4gICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgfVxyXG4gICAgICAgICAgKVxyXG4gICAgICAgICAgLm51bGxhYmxlKClcclxuICAgICAgOiB6XHJcbiAgICAgICAgICAuc3RyaW5nKClcclxuICAgICAgICAgIC50cmltKClcclxuICAgICAgICAgIC5yZWZpbmUoXHJcbiAgICAgICAgICAgICh2YWx1ZSkgPT5cclxuICAgICAgICAgICAgICAodmFsdWUubGVuZ3RoID49IDYgJiYgdmFsdWUuZW5kc1dpdGgoJy5qc29uJykpIHx8XHJcbiAgICAgICAgICAgICAgKHZhbHVlLmxlbmd0aCA+PSA1ICYmIHZhbHVlLmVuZHNXaXRoKCcuc3ZnJykpIHx8XHJcbiAgICAgICAgICAgICAgWyd1bmRlZmluZWQnLCAnbnVsbCcsICcnXS5pbmNsdWRlcyh2YWx1ZSksXHJcbiAgICAgICAgICAgIHtcclxuICAgICAgICAgICAgICBwYXJhbXM6IHtcclxuICAgICAgICAgICAgICAgIGVycm9yTWVzc2FnZTpcclxuICAgICAgICAgICAgICAgICAgJ1RoZSB2YWx1ZSBtdXN0IGJlIGEgc3RyaW5nIHRoYXQgZW5kcyB3aXRoIC5qc29uIG9yIC5zdmcnXHJcbiAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICB9XHJcbiAgICAgICAgICApXHJcbiAgICAgICAgICAudHJhbnNmb3JtKCh2YWx1ZSkgPT5cclxuICAgICAgICAgICAgIVsndW5kZWZpbmVkJywgJ251bGwnLCAnJ10uaW5jbHVkZXModmFsdWUpID8gdmFsdWUgOiBudWxsXHJcbiAgICAgICAgICApXHJcbiAgICAgICAgICAubnVsbGFibGUoKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYGluc3RyYCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYS5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgdGhlIGBvcHRpb25zYCB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gaW5zdHJcclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZyB0aGUgYGluc3RyYFxyXG4gICAqIG9wdGlvbi5cclxuICAgKi9cclxuICBpbnN0cigpIHtcclxuICAgIHJldHVybiB2LmNoYXJ0Q29uZmlnKCk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGBvcHRpb25zYCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYS5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgdGhlIGBvcHRpb25zYCB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gb3B0aW9uc1xyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nIHRoZSBgb3B0aW9uc2BcclxuICAgKiBvcHRpb24uXHJcbiAgICovXHJcbiAgb3B0aW9ucygpIHtcclxuICAgIHJldHVybiB2LmNoYXJ0Q29uZmlnKCk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGBzdmdgIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhhdCB0aGUgc2NoZW1hIHdpbGwgYWNjZXB0IG9iamVjdCB2YWx1ZXNcclxuICAgKiBvciB0cmltbWVkIHN0cmluZyB2YWx1ZXMgdGhhdCBjb250YWluICc8c3ZnJyBvciAnPD94bWwnIGVsZW1lbnRzIGFuZCBudWxsLlxyXG4gICAqIFRoZSAndW5kZWZpbmVkJywgJ251bGwnLCBhbmQgJycgdmFsdWVzIHdpbGwgYmUgdHJhbnNmb3JtZWQgdG8gbnVsbC5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiBzdmdcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZyB0aGUgYHN2Z2Agb3B0aW9uLlxyXG4gICAqL1xyXG4gIHN2ZygpIHtcclxuICAgIHJldHVybiB6XHJcbiAgICAgIC5zdHJpbmcoKVxyXG4gICAgICAudHJpbSgpXHJcbiAgICAgIC5yZWZpbmUoXHJcbiAgICAgICAgKHZhbHVlKSA9PlxyXG4gICAgICAgICAgdmFsdWUuaW5kZXhPZignPHN2ZycpID49IDAgfHxcclxuICAgICAgICAgIHZhbHVlLmluZGV4T2YoJzw/eG1sJykgPj0gMCB8fFxyXG4gICAgICAgICAgWydmYWxzZScsICd1bmRlZmluZWQnLCAnbnVsbCcsICcnXS5pbmNsdWRlcyh2YWx1ZSksXHJcbiAgICAgICAge1xyXG4gICAgICAgICAgcGFyYW1zOiB7XHJcbiAgICAgICAgICAgIGVycm9yTWVzc2FnZTpcclxuICAgICAgICAgICAgICBcIlRoZSB2YWx1ZSBtdXN0IGJlIGEgc3RyaW5nIHRoYXQgY29udGFpbnMgJzxzdmcnIG9yICc8P3htbCdcIlxyXG4gICAgICAgICAgfVxyXG4gICAgICAgIH1cclxuICAgICAgKVxyXG4gICAgICAudHJhbnNmb3JtKCh2YWx1ZSkgPT5cclxuICAgICAgICAhWydmYWxzZScsICd1bmRlZmluZWQnLCAnbnVsbCcsICcnXS5pbmNsdWRlcyh2YWx1ZSkgPyB2YWx1ZSA6IG51bGxcclxuICAgICAgKVxyXG4gICAgICAubnVsbGFibGUoKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYG91dGZpbGVgIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGggYW4gb3B0aW9uYWwgc3RyaWN0ZXJcclxuICAgKiBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGF0OlxyXG4gICAqXHJcbiAgICogLSBXaGVuIGBzdHJpY3RDaGVja2AgaXMgdHJ1ZSwgdGhlIHNjaGVtYSB3aWxsIGFjY2VwdCB0cmltbWVkIHN0cmluZyB2YWx1ZXNcclxuICAgKiB0aGF0IGVuZCB3aXRoICcuanBlZycsICcuanBnJywgJy5wbmcnLCAnLnBkZicsIG9yICcuc3ZnJywgYXJlIGF0IGxlYXN0IG9uZVxyXG4gICAqIGNoYXJhY3RlciBsb25nIGV4Y2x1ZGluZyB0aGUgZXh0ZW5zaW9uLCBvciBudWxsLlxyXG4gICAqXHJcbiAgICogLSBXaGVuIGBzdHJpY3RDaGVja2AgaXMgZmFsc2UsIHRoZSBzY2hlbWEgd2lsbCBhY2NlcHQgdHJpbW1lZCBzdHJpbmcgdmFsdWVzXHJcbiAgICogdGhhdCBlbmQgd2l0aCAnLmpwZWcnLCAnLmpwZycsICcucG5nJywgJy5wZGYnLCBvciAnLnN2ZycsIGFyZSBhdCBsZWFzdCBvbmVcclxuICAgKiBjaGFyYWN0ZXIgbG9uZyBleGNsdWRpbmcgdGhlIGV4dGVuc2lvbiBhbmQgd2lsbCBiZSBudWxsIGlmIHRoZSBwcm92aWRlZFxyXG4gICAqIHZhbHVlIGlzIG51bGwsICd1bmRlZmluZWQnLCAnbnVsbCcsIG9yICcnLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIG91dGZpbGVcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZyB0aGUgYG91dGZpbGVgXHJcbiAgICogb3B0aW9uLlxyXG4gICAqL1xyXG4gIG91dGZpbGUoc3RyaWN0Q2hlY2spIHtcclxuICAgIHJldHVybiBzdHJpY3RDaGVja1xyXG4gICAgICA/IHpcclxuICAgICAgICAgIC5zdHJpbmcoKVxyXG4gICAgICAgICAgLnRyaW0oKVxyXG4gICAgICAgICAgLnJlZmluZShcclxuICAgICAgICAgICAgKHZhbHVlKSA9PlxyXG4gICAgICAgICAgICAgICh2YWx1ZS5sZW5ndGggPj0gNiAmJiB2YWx1ZS5lbmRzV2l0aCgnLmpwZWcnKSkgfHxcclxuICAgICAgICAgICAgICAodmFsdWUubGVuZ3RoID49IDUgJiZcclxuICAgICAgICAgICAgICAgICh2YWx1ZS5lbmRzV2l0aCgnLmpwZycpIHx8XHJcbiAgICAgICAgICAgICAgICAgIHZhbHVlLmVuZHNXaXRoKCcucG5nJykgfHxcclxuICAgICAgICAgICAgICAgICAgdmFsdWUuZW5kc1dpdGgoJy5wZGYnKSB8fFxyXG4gICAgICAgICAgICAgICAgICB2YWx1ZS5lbmRzV2l0aCgnLnN2ZycpKSksXHJcbiAgICAgICAgICAgIHtcclxuICAgICAgICAgICAgICBwYXJhbXM6IHtcclxuICAgICAgICAgICAgICAgIGVycm9yTWVzc2FnZTpcclxuICAgICAgICAgICAgICAgICAgJ1RoZSB2YWx1ZSBtdXN0IGJlIGEgc3RyaW5nIHRoYXQgZW5kcyB3aXRoIC5qcGVnLCAuanBnLCAucG5nLCAucGRmLCBvciAuc3ZnJ1xyXG4gICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgfVxyXG4gICAgICAgICAgKVxyXG4gICAgICAgICAgLm51bGxhYmxlKClcclxuICAgICAgOiB6XHJcbiAgICAgICAgICAuc3RyaW5nKClcclxuICAgICAgICAgIC50cmltKClcclxuICAgICAgICAgIC5yZWZpbmUoXHJcbiAgICAgICAgICAgICh2YWx1ZSkgPT5cclxuICAgICAgICAgICAgICAodmFsdWUubGVuZ3RoID49IDYgJiYgdmFsdWUuZW5kc1dpdGgoJy5qcGVnJykpIHx8XHJcbiAgICAgICAgICAgICAgKHZhbHVlLmxlbmd0aCA+PSA1ICYmXHJcbiAgICAgICAgICAgICAgICAodmFsdWUuZW5kc1dpdGgoJy5qcGcnKSB8fFxyXG4gICAgICAgICAgICAgICAgICB2YWx1ZS5lbmRzV2l0aCgnLnBuZycpIHx8XHJcbiAgICAgICAgICAgICAgICAgIHZhbHVlLmVuZHNXaXRoKCcucGRmJykgfHxcclxuICAgICAgICAgICAgICAgICAgdmFsdWUuZW5kc1dpdGgoJy5zdmcnKSkpIHx8XHJcbiAgICAgICAgICAgICAgWyd1bmRlZmluZWQnLCAnbnVsbCcsICcnXS5pbmNsdWRlcyh2YWx1ZSksXHJcbiAgICAgICAgICAgIHtcclxuICAgICAgICAgICAgICBwYXJhbXM6IHtcclxuICAgICAgICAgICAgICAgIGVycm9yTWVzc2FnZTpcclxuICAgICAgICAgICAgICAgICAgJ1RoZSB2YWx1ZSBtdXN0IGJlIGEgc3RyaW5nIHRoYXQgZW5kcyB3aXRoIC5qcGVnLCAuanBnLCAucG5nLCAucGRmLCBvciAuc3ZnJ1xyXG4gICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgfVxyXG4gICAgICAgICAgKVxyXG4gICAgICAgICAgLnRyYW5zZm9ybSgodmFsdWUpID0+XHJcbiAgICAgICAgICAgICFbJ3VuZGVmaW5lZCcsICdudWxsJywgJyddLmluY2x1ZGVzKHZhbHVlKSA/IHZhbHVlIDogbnVsbFxyXG4gICAgICAgICAgKVxyXG4gICAgICAgICAgLm51bGxhYmxlKCk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGB0eXBlYCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoIGFuIG9wdGlvbmFsIHN0cmljdGVyXHJcbiAgICogY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhlIHNhbWUgd29yayBhcyB0aGUgYGVudW1gIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiB0eXBlXHJcbiAgICpcclxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IHN0cmljdENoZWNrIC0gRGV0ZXJtaW5lcyBpZiBzdHJpY3RlciB2YWxpZGF0aW9uIHNob3VsZFxyXG4gICAqIGJlIGFwcGxpZWQuXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9IEEgWm9kIHNjaGVtYSBvYmplY3QgZm9yIHZhbGlkYXRpbmcgdGhlIGB0eXBlYFxyXG4gICAqIG9wdGlvbi5cclxuICAgKi9cclxuICB0eXBlKHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gdi5lbnVtKFsnanBlZycsICdqcGcnLCAncG5nJywgJ3BkZicsICdzdmcnXSwgc3RyaWN0Q2hlY2spO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgY29uc3RyYCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoIGFuIG9wdGlvbmFsIHN0cmljdGVyXHJcbiAgICogY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhlIHNhbWUgd29yayBhcyB0aGUgYGVudW1gIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiBjb25zdHJcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZyB0aGUgYGNvbnN0cmBcclxuICAgKiBvcHRpb24uXHJcbiAgICovXHJcbiAgY29uc3RyKHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gdi5lbnVtKFxyXG4gICAgICBbJ2NoYXJ0JywgJ3N0b2NrQ2hhcnQnLCAnbWFwQ2hhcnQnLCAnZ2FudHRDaGFydCddLFxyXG4gICAgICBzdHJpY3RDaGVja1xyXG4gICAgKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYGI2NGAgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbCBzdHJpY3RlclxyXG4gICAqIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgdGhlIGBib29sZWFuYCB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gYjY0XHJcbiAgICpcclxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IHN0cmljdENoZWNrIC0gRGV0ZXJtaW5lcyBpZiBzdHJpY3RlciB2YWxpZGF0aW9uIHNob3VsZFxyXG4gICAqIGJlIGFwcGxpZWQuXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9IEEgWm9kIHNjaGVtYSBvYmplY3QgZm9yIHZhbGlkYXRpbmcgdGhlIGBiNjRgIG9wdGlvbi5cclxuICAgKi9cclxuICBiNjQoc3RyaWN0Q2hlY2spIHtcclxuICAgIHJldHVybiB2LmJvb2xlYW4oc3RyaWN0Q2hlY2spO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgbm9Eb3dubG9hZGAgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbFxyXG4gICAqIHN0cmljdGVyIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgdGhlIGBib29sZWFuYCB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gbm9Eb3dubG9hZFxyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nIHRoZSBgbm9Eb3dubG9hZGBcclxuICAgKiBvcHRpb24uXHJcbiAgICovXHJcbiAgbm9Eb3dubG9hZChzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHYuYm9vbGVhbihzdHJpY3RDaGVjayk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGBkZWZhdWx0SGVpZ2h0YCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoIGFuIG9wdGlvbmFsXHJcbiAgICogc3RyaWN0ZXIgY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhlIHNhbWUgd29yayBhcyB0aGUgYHBvc2l0aXZlTnVtYCB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gZGVmYXVsdEhlaWdodFxyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nXHJcbiAgICogdGhlIGBkZWZhdWx0SGVpZ2h0YCBvcHRpb24uXHJcbiAgICovXHJcbiAgZGVmYXVsdEhlaWdodChzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHYucG9zaXRpdmVOdW0oc3RyaWN0Q2hlY2spO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgZGVmYXVsdFdpZHRoYCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoIGFuIG9wdGlvbmFsXHJcbiAgICogc3RyaWN0ZXIgY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhlIHNhbWUgd29yayBhcyB0aGUgYHBvc2l0aXZlTnVtYCB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gZGVmYXVsdFdpZHRoXHJcbiAgICpcclxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IHN0cmljdENoZWNrIC0gRGV0ZXJtaW5lcyBpZiBzdHJpY3RlciB2YWxpZGF0aW9uIHNob3VsZFxyXG4gICAqIGJlIGFwcGxpZWQuXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9IEEgWm9kIHNjaGVtYSBvYmplY3QgZm9yIHZhbGlkYXRpbmdcclxuICAgKiB0aGUgYGRlZmF1bHRXaWR0aGAgb3B0aW9uLlxyXG4gICAqL1xyXG4gIGRlZmF1bHRXaWR0aChzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHYucG9zaXRpdmVOdW0oc3RyaWN0Q2hlY2spO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgZGVmYXVsdFNjYWxlYCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoIGFuIG9wdGlvbmFsXHJcbiAgICogc3RyaWN0ZXIgY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhhdDpcclxuICAgKlxyXG4gICAqIC0gV2hlbiBgc3RyaWN0Q2hlY2tgIGlzIHRydWUsIHRoZSBzY2hlbWEgd2lsbCBhY2NlcHQgbnVtYmVyIHZhbHVlcyB0aGF0XHJcbiAgICogYXJlIGJldHdlZW4gMC4xIGFuZCA1IChpbmNsdXNpdmUpLlxyXG4gICAqXHJcbiAgICogLSBXaGVuIGBzdHJpY3RDaGVja2AgaXMgZmFsc2UsIHRoZSBzY2hlbWEgd2lsbCBhY2NlcHQgbnVtYmVyIHZhbHVlc1xyXG4gICAqIGFuZCBzdHJpbmdpZmllZCBudW1iZXIgdmFsdWVzIHRoYXQgYXJlIGJldHdlZW4gMC4xIGFuZCA1IChpbmNsdXNpdmUpLCBudWxsLFxyXG4gICAqICd1bmRlZmluZWQnLCAnbnVsbCcsIGFuZCAnJyB3aGljaCB3aWxsIGJlIHRyYW5zZm9ybWVkIHRvIG51bGwuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gZGVmYXVsdFNjYWxlXHJcbiAgICpcclxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IHN0cmljdENoZWNrIC0gRGV0ZXJtaW5lcyBpZiBzdHJpY3RlciB2YWxpZGF0aW9uIHNob3VsZFxyXG4gICAqIGJlIGFwcGxpZWQuXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9IEEgWm9kIHNjaGVtYSBvYmplY3QgZm9yIHZhbGlkYXRpbmdcclxuICAgKiB0aGUgYGRlZmF1bHRTY2FsZWAgb3B0aW9uLlxyXG4gICAqL1xyXG4gIGRlZmF1bHRTY2FsZShzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHN0cmljdENoZWNrXHJcbiAgICAgID8gei5udW1iZXIoKS5ndGUoMC4xKS5sdGUoNSlcclxuICAgICAgOiB6XHJcbiAgICAgICAgICAudW5pb24oW1xyXG4gICAgICAgICAgICB6XHJcbiAgICAgICAgICAgICAgLnN0cmluZygpXHJcbiAgICAgICAgICAgICAgLnRyaW0oKVxyXG4gICAgICAgICAgICAgIC5yZWZpbmUoXHJcbiAgICAgICAgICAgICAgICAodmFsdWUpID0+XHJcbiAgICAgICAgICAgICAgICAgICghaXNOYU4oTnVtYmVyKHZhbHVlKSkgJiZcclxuICAgICAgICAgICAgICAgICAgICB2YWx1ZSAhPT0gdHJ1ZSAmJlxyXG4gICAgICAgICAgICAgICAgICAgICF2YWx1ZS5zdGFydHNXaXRoKCdbJykgJiZcclxuICAgICAgICAgICAgICAgICAgICBOdW1iZXIodmFsdWUpID49IDAuMSAmJlxyXG4gICAgICAgICAgICAgICAgICAgIE51bWJlcih2YWx1ZSkgPD0gNSkgfHxcclxuICAgICAgICAgICAgICAgICAgWyd1bmRlZmluZWQnLCAnbnVsbCcsICcnXS5pbmNsdWRlcyh2YWx1ZSksXHJcbiAgICAgICAgICAgICAgICB7XHJcbiAgICAgICAgICAgICAgICAgIHBhcmFtczoge1xyXG4gICAgICAgICAgICAgICAgICAgIGVycm9yTWVzc2FnZTogJ1RoZSB2YWx1ZSBtdXN0IGJlIHdpdGhpbiBhIDAuMSBhbmQgNS4wIHJhbmdlJ1xyXG4gICAgICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgICAgKVxyXG4gICAgICAgICAgICAgIC50cmFuc2Zvcm0oKHZhbHVlKSA9PlxyXG4gICAgICAgICAgICAgICAgIVsndW5kZWZpbmVkJywgJ251bGwnLCAnJ10uaW5jbHVkZXModmFsdWUpXHJcbiAgICAgICAgICAgICAgICAgID8gTnVtYmVyKHZhbHVlKVxyXG4gICAgICAgICAgICAgICAgICA6IG51bGxcclxuICAgICAgICAgICAgICApLFxyXG4gICAgICAgICAgICB6Lm51bWJlcigpLmd0ZSgwLjEpLmx0ZSg1KVxyXG4gICAgICAgICAgXSlcclxuICAgICAgICAgIC5udWxsYWJsZSgpO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgaGVpZ2h0YCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoIGFuIG9wdGlvbmFsIHN0cmljdGVyXHJcbiAgICogY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhlIHNhbWUgd29yayBhcyBhIG51bGxhYmxlIGBkZWZhdWx0SGVpZ2h0YFxyXG4gICAqIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiBoZWlnaHRcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZyB0aGUgYGhlaWdodGBcclxuICAgKiBvcHRpb24uXHJcbiAgICovXHJcbiAgaGVpZ2h0KHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gdGhpcy5kZWZhdWx0SGVpZ2h0KHN0cmljdENoZWNrKS5udWxsYWJsZSgpO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgd2lkdGhgIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGggYW4gb3B0aW9uYWwgc3RyaWN0ZXJcclxuICAgKiBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGUgc2FtZSB3b3JrIGFzIGEgbnVsbGFibGUgYGRlZmF1bHRXaWR0aGBcclxuICAgKiB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gd2lkdGhcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZyB0aGUgYHdpZHRoYFxyXG4gICAqIG9wdGlvbi5cclxuICAgKi9cclxuICB3aWR0aChzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHRoaXMuZGVmYXVsdFdpZHRoKHN0cmljdENoZWNrKS5udWxsYWJsZSgpO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgc2NhbGVgIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGggYW4gb3B0aW9uYWwgc3RyaWN0ZXJcclxuICAgKiBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGUgc2FtZSB3b3JrIGFzIGEgbnVsbGFibGUgYGRlZmF1bHRTY2FsZWBcclxuICAgKiB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gc2NhbGVcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZyB0aGUgYHNjYWxlYFxyXG4gICAqIG9wdGlvbi5cclxuICAgKi9cclxuICBzY2FsZShzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHRoaXMuZGVmYXVsdFNjYWxlKHN0cmljdENoZWNrKS5udWxsYWJsZSgpO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgZ2xvYmFsT3B0aW9uc2AgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGUgc2FtZSB3b3JrIGFzIHRoZSBgYWRkaXRpb25hbE9wdGlvbnNgXHJcbiAgICogdmFsaWRhdG9yLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIGdsb2JhbE9wdGlvbnNcclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZ1xyXG4gICAqIHRoZSBgZ2xvYmFsT3B0aW9uc2Agb3B0aW9uLlxyXG4gICAqL1xyXG4gIGdsb2JhbE9wdGlvbnMoKSB7XHJcbiAgICByZXR1cm4gdi5hZGRpdGlvbmFsT3B0aW9ucygpO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgdGhlbWVPcHRpb25zYCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYS5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgdGhlIGBhZGRpdGlvbmFsT3B0aW9uc2BcclxuICAgKiB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gdGhlbWVPcHRpb25zXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9IEEgWm9kIHNjaGVtYSBvYmplY3QgZm9yIHZhbGlkYXRpbmdcclxuICAgKiB0aGUgYHRoZW1lT3B0aW9uc2Agb3B0aW9uLlxyXG4gICAqL1xyXG4gIHRoZW1lT3B0aW9ucygpIHtcclxuICAgIHJldHVybiB2LmFkZGl0aW9uYWxPcHRpb25zKCk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGBiYXRjaGAgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbCBzdHJpY3RlclxyXG4gICAqIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgdGhlIGBzdHJpbmdgIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiBiYXRjaFxyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nIHRoZSBgYmF0Y2hgXHJcbiAgICogb3B0aW9uLlxyXG4gICAqL1xyXG4gIGJhdGNoKHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gdi5zdHJpbmcoc3RyaWN0Q2hlY2spO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgcmFzdGVyaXphdGlvblRpbWVvdXRgIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGhcclxuICAgKiBhbiBvcHRpb25hbCBzdHJpY3RlciBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGUgc2FtZSB3b3JrIGFzIHRoZSBgbm9uTmVnYXRpdmVOdW1gXHJcbiAgICogdmFsaWRhdG9yLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIHJhc3Rlcml6YXRpb25UaW1lb3V0XHJcbiAgICpcclxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IHN0cmljdENoZWNrIC0gRGV0ZXJtaW5lcyBpZiBzdHJpY3RlciB2YWxpZGF0aW9uIHNob3VsZFxyXG4gICAqIGJlIGFwcGxpZWQuXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9IEEgWm9kIHNjaGVtYSBvYmplY3QgZm9yIHZhbGlkYXRpbmdcclxuICAgKiB0aGUgYHJhc3Rlcml6YXRpb25UaW1lb3V0YCBvcHRpb24uXHJcbiAgICovXHJcbiAgcmFzdGVyaXphdGlvblRpbWVvdXQoc3RyaWN0Q2hlY2spIHtcclxuICAgIHJldHVybiB2Lm5vbk5lZ2F0aXZlTnVtKHN0cmljdENoZWNrKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYGFsbG93Q29kZUV4ZWN1dGlvbmAgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aFxyXG4gICAqIGFuIG9wdGlvbmFsIHN0cmljdGVyIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgdGhlIGBib29sZWFuYCB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gYWxsb3dDb2RlRXhlY3V0aW9uXHJcbiAgICpcclxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IHN0cmljdENoZWNrIC0gRGV0ZXJtaW5lcyBpZiBzdHJpY3RlciB2YWxpZGF0aW9uIHNob3VsZFxyXG4gICAqIGJlIGFwcGxpZWQuXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9IEEgWm9kIHNjaGVtYSBvYmplY3QgZm9yIHZhbGlkYXRpbmdcclxuICAgKiB0aGUgYGFsbG93Q29kZUV4ZWN1dGlvbmAgb3B0aW9uLlxyXG4gICAqL1xyXG4gIGFsbG93Q29kZUV4ZWN1dGlvbihzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHYuYm9vbGVhbihzdHJpY3RDaGVjayk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGBhbGxvd0ZpbGVSZXNvdXJjZXNgIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGhcclxuICAgKiBhbiBvcHRpb25hbCBzdHJpY3RlciBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGUgc2FtZSB3b3JrIGFzIHRoZSBgYm9vbGVhbmAgdmFsaWRhdG9yLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIGFsbG93RmlsZVJlc291cmNlc1xyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nXHJcbiAgICogdGhlIGBhbGxvd0ZpbGVSZXNvdXJjZXNgIG9wdGlvbi5cclxuICAgKi9cclxuICBhbGxvd0ZpbGVSZXNvdXJjZXMoc3RyaWN0Q2hlY2spIHtcclxuICAgIHJldHVybiB2LmJvb2xlYW4oc3RyaWN0Q2hlY2spO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgY3VzdG9tQ29kZWAgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbFxyXG4gICAqIHN0cmljdGVyIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgdGhlIGBzdHJpbmdgIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiBjdXN0b21Db2RlXHJcbiAgICpcclxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IHN0cmljdENoZWNrIC0gRGV0ZXJtaW5lcyBpZiBzdHJpY3RlciB2YWxpZGF0aW9uIHNob3VsZFxyXG4gICAqIGJlIGFwcGxpZWQuXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9IEEgWm9kIHNjaGVtYSBvYmplY3QgZm9yIHZhbGlkYXRpbmcgdGhlIGBjdXN0b21Db2RlYFxyXG4gICAqIG9wdGlvbi5cclxuICAgKi9cclxuICBjdXN0b21Db2RlKHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gdi5zdHJpbmcoc3RyaWN0Q2hlY2spO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgY2FsbGJhY2tgIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGggYW4gb3B0aW9uYWxcclxuICAgKiBzdHJpY3RlciBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGUgc2FtZSB3b3JrIGFzIHRoZSBgc3RyaW5nYCB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gY2FsbGJhY2tcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZyB0aGUgYGNhbGxiYWNrYFxyXG4gICAqIG9wdGlvbi5cclxuICAgKi9cclxuICBjYWxsYmFjayhzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHYuc3RyaW5nKHN0cmljdENoZWNrKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYHJlc291cmNlc2AgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbFxyXG4gICAqIHN0cmljdGVyIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoYXQ6XHJcbiAgICpcclxuICAgKiAtIFdoZW4gYHN0cmljdENoZWNrYCBpcyB0cnVlLCB0aGUgc2NoZW1hIHdpbGwgYWNjZXB0IGEgcGFydGlhbCBvYmplY3RcclxuICAgKiB3aXRoIGFsbG93ZWQgcHJvcGVydGllcyBganNgLCBgY3NzYCwgYW5kIGBmaWxlc2Agd2hlcmUgZWFjaCBvZiB0aGUgYWxsb3dlZFxyXG4gICAqIHByb3BlcnRpZXMgY2FuIGJlIG51bGwsIHN0cmluZ2lmaWVkIHZlcnNpb24gb2YgdGhlIG9iamVjdCwgc3RyaW5nIHRoYXQgZW5kc1xyXG4gICAqIHdpdGggdGhlICcuanNvbicsIGFuZCBudWxsLlxyXG4gICAqXHJcbiAgICogLSBXaGVuIGBzdHJpY3RDaGVja2AgaXMgZmFsc2UsIHRoZSBzY2hlbWEgd2lsbCBhY2NlcHQgYSBzdHJpbmdpZmllZCB2ZXJzaW9uXHJcbiAgICogb2YgYSBwYXJ0aWFsIG9iamVjdCB3aXRoIGFsbG93ZWQgcHJvcGVydGllcyBganNgLCBgY3NzYCwgYW5kIGBmaWxlc2Agd2hlcmVcclxuICAgKiBlYWNoIG9mIHRoZSBhbGxvd2VkIHByb3BlcnRpZXMgY2FuIGJlIG51bGwsIHN0cmluZyB0aGF0IGVuZHMgd2l0aCB0aGVcclxuICAgKiAnLmpzb24nLCBhbmQgd2lsbCBiZSBudWxsIGlmIHRoZSBwcm92aWRlZCB2YWx1ZSBpcyAndW5kZWZpbmVkJywgJ251bGwnXHJcbiAgICogb3IgJycuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gcmVzb3VyY2VzXHJcbiAgICpcclxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IHN0cmljdENoZWNrIC0gRGV0ZXJtaW5lcyBpZiBzdHJpY3RlciB2YWxpZGF0aW9uIHNob3VsZFxyXG4gICAqIGJlIGFwcGxpZWQuXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9IEEgWm9kIHNjaGVtYSBvYmplY3QgZm9yIHZhbGlkYXRpbmcgdGhlIGByZXNvdXJjZXNgXHJcbiAgICogb3B0aW9uLlxyXG4gICAqL1xyXG4gIHJlc291cmNlcyhzdHJpY3RDaGVjaykge1xyXG4gICAgY29uc3Qgb2JqZWN0U2NoZW1hID0gelxyXG4gICAgICAub2JqZWN0KHtcclxuICAgICAgICBqczogdi5zdHJpbmcoZmFsc2UpLFxyXG4gICAgICAgIGNzczogdi5zdHJpbmcoZmFsc2UpLFxyXG4gICAgICAgIGZpbGVzOiB2XHJcbiAgICAgICAgICAuc3RyaW5nQXJyYXkoXHJcbiAgICAgICAgICAgICh2YWx1ZSkgPT4gIVsndW5kZWZpbmVkJywgJ251bGwnLCAnJ10uaW5jbHVkZXModmFsdWUpLFxyXG4gICAgICAgICAgICAnLCcsXHJcbiAgICAgICAgICAgIHRydWVcclxuICAgICAgICAgIClcclxuICAgICAgICAgIC5udWxsYWJsZSgpXHJcbiAgICAgIH0pXHJcbiAgICAgIC5wYXJ0aWFsKCk7XHJcblxyXG4gICAgY29uc3Qgc3RyaW5nU2NoZW1hMSA9IHpcclxuICAgICAgLnN0cmluZygpXHJcbiAgICAgIC50cmltKClcclxuICAgICAgLnJlZmluZShcclxuICAgICAgICAodmFsdWUpID0+XHJcbiAgICAgICAgICAodmFsdWUuc3RhcnRzV2l0aCgneycpICYmIHZhbHVlLmVuZHNXaXRoKCd9JykpIHx8XHJcbiAgICAgICAgICAodmFsdWUubGVuZ3RoID49IDYgJiYgdmFsdWUuZW5kc1dpdGgoJy5qc29uJykpLFxyXG4gICAgICAgIHtcclxuICAgICAgICAgIHBhcmFtczoge1xyXG4gICAgICAgICAgICBlcnJvck1lc3NhZ2U6XHJcbiAgICAgICAgICAgICAgXCJUaGUgdmFsdWUgbXVzdCBiZSBhIHN0cmluZyB0aGF0IHN0YXJ0cyB3aXRoICd7JyBhbmQgZW5kcyB3aXRoICd9XCJcclxuICAgICAgICAgIH1cclxuICAgICAgICB9XHJcbiAgICAgICk7XHJcblxyXG4gICAgY29uc3Qgc3RyaW5nU2NoZW1hMiA9IHpcclxuICAgICAgLnN0cmluZygpXHJcbiAgICAgIC50cmltKClcclxuICAgICAgLnJlZmluZShcclxuICAgICAgICAodmFsdWUpID0+XHJcbiAgICAgICAgICAodmFsdWUuc3RhcnRzV2l0aCgneycpICYmIHZhbHVlLmVuZHNXaXRoKCd9JykpIHx8XHJcbiAgICAgICAgICAodmFsdWUubGVuZ3RoID49IDYgJiYgdmFsdWUuZW5kc1dpdGgoJy5qc29uJykpIHx8XHJcbiAgICAgICAgICBbJ3VuZGVmaW5lZCcsICdudWxsJywgJyddLmluY2x1ZGVzKHZhbHVlKSxcclxuICAgICAgICB7XHJcbiAgICAgICAgICBwYXJhbXM6IHtcclxuICAgICAgICAgICAgZXJyb3JNZXNzYWdlOiAnVGhlIHZhbHVlIG11c3QgYmUgYSBzdHJpbmcgdGhhdCBlbmRzIHdpdGggLmpzb24nXHJcbiAgICAgICAgICB9XHJcbiAgICAgICAgfVxyXG4gICAgICApXHJcbiAgICAgIC50cmFuc2Zvcm0oKHZhbHVlKSA9PlxyXG4gICAgICAgICFbJ3VuZGVmaW5lZCcsICdudWxsJywgJyddLmluY2x1ZGVzKHZhbHVlKSA/IHZhbHVlIDogbnVsbFxyXG4gICAgICApO1xyXG5cclxuICAgIHJldHVybiBzdHJpY3RDaGVja1xyXG4gICAgICA/IHoudW5pb24oW29iamVjdFNjaGVtYSwgc3RyaW5nU2NoZW1hMV0pLm51bGxhYmxlKClcclxuICAgICAgOiB6LnVuaW9uKFtvYmplY3RTY2hlbWEsIHN0cmluZ1NjaGVtYTJdKS5udWxsYWJsZSgpO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgbG9hZENvbmZpZ2AgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbFxyXG4gICAqIHN0cmljdGVyIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgdGhlIGBzdHJpbmdgIHZhbGlkYXRvci5cclxuICAgKiBBZGRpdGlvbmFsbHksIGl0IG11c3QgYmUgYSBzdHJpbmcgdGhhdCBlbmRzIHdpdGggJy5qc29uJy5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiBsb2FkQ29uZmlnXHJcbiAgICpcclxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IHN0cmljdENoZWNrIC0gRGV0ZXJtaW5lcyBpZiBzdHJpY3RlciB2YWxpZGF0aW9uIHNob3VsZFxyXG4gICAqIGJlIGFwcGxpZWQuXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9IEEgWm9kIHNjaGVtYSBvYmplY3QgZm9yIHZhbGlkYXRpbmcgdGhlIGBsb2FkQ29uZmlnYFxyXG4gICAqIG9wdGlvbi5cclxuICAgKi9cclxuICBsb2FkQ29uZmlnKHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gdlxyXG4gICAgICAuc3RyaW5nKHN0cmljdENoZWNrKVxyXG4gICAgICAucmVmaW5lKFxyXG4gICAgICAgICh2YWx1ZSkgPT5cclxuICAgICAgICAgIHZhbHVlID09PSBudWxsIHx8ICh2YWx1ZS5sZW5ndGggPj0gNiAmJiB2YWx1ZS5lbmRzV2l0aCgnLmpzb24nKSksXHJcbiAgICAgICAge1xyXG4gICAgICAgICAgcGFyYW1zOiB7XHJcbiAgICAgICAgICAgIGVycm9yTWVzc2FnZTogJ1RoZSB2YWx1ZSBtdXN0IGJlIGEgc3RyaW5nIHRoYXQgZW5kcyB3aXRoIC5qc29uJ1xyXG4gICAgICAgICAgfVxyXG4gICAgICAgIH1cclxuICAgICAgKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYGNyZWF0ZUNvbmZpZ2AgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbFxyXG4gICAqIHN0cmljdGVyIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgdGhlIGBsb2FkQ29uZmlnYCB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gY3JlYXRlQ29uZmlnXHJcbiAgICpcclxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IHN0cmljdENoZWNrIC0gRGV0ZXJtaW5lcyBpZiBzdHJpY3RlciB2YWxpZGF0aW9uIHNob3VsZFxyXG4gICAqIGJlIGFwcGxpZWQuXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9IEEgWm9kIHNjaGVtYSBvYmplY3QgZm9yIHZhbGlkYXRpbmdcclxuICAgKiB0aGUgYGNyZWF0ZUNvbmZpZ2Agb3B0aW9uLlxyXG4gICAqL1xyXG4gIGNyZWF0ZUNvbmZpZyhzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHRoaXMubG9hZENvbmZpZyhzdHJpY3RDaGVjayk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGBlbmFibGVTZXJ2ZXJgIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGggYW4gb3B0aW9uYWxcclxuICAgKiBzdHJpY3RlciBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGUgc2FtZSB3b3JrIGFzIHRoZSBgYm9vbGVhbmAgdmFsaWRhdG9yLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIGVuYWJsZVNlcnZlclxyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nXHJcbiAgICogdGhlIGBlbmFibGVTZXJ2ZXJgIG9wdGlvbi5cclxuICAgKi9cclxuICBlbmFibGVTZXJ2ZXIoc3RyaWN0Q2hlY2spIHtcclxuICAgIHJldHVybiB2LmJvb2xlYW4oc3RyaWN0Q2hlY2spO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgaG9zdGAgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbCBzdHJpY3RlclxyXG4gICAqIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgdGhlIGBzdHJpbmdgIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiBob3N0XHJcbiAgICpcclxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IHN0cmljdENoZWNrIC0gRGV0ZXJtaW5lcyBpZiBzdHJpY3RlciB2YWxpZGF0aW9uIHNob3VsZFxyXG4gICAqIGJlIGFwcGxpZWQuXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9IEEgWm9kIHNjaGVtYSBvYmplY3QgZm9yIHZhbGlkYXRpbmcgdGhlIGBob3N0YFxyXG4gICAqIG9wdGlvbi5cclxuICAgKi9cclxuICBob3N0KHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gdi5zdHJpbmcoc3RyaWN0Q2hlY2spO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgcG9ydGAgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbCBzdHJpY3RlclxyXG4gICAqIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgdGhlIGBub25OZWdhdGl2ZU51bWBcclxuICAgKiB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gcG9ydFxyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nIHRoZSBgcG9ydGBcclxuICAgKiBvcHRpb24uXHJcbiAgICovXHJcbiAgcG9ydChzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHYubm9uTmVnYXRpdmVOdW0oc3RyaWN0Q2hlY2spO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgdXBsb2FkTGltaXRgIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGggYW4gb3B0aW9uYWxcclxuICAgKiBzdHJpY3RlciBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGUgc2FtZSB3b3JrIGFzIHRoZSBgcG9zaXRpdmVOdW1gIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiB1cGxvYWRMaW1pdFxyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nIHRoZSBgdXBsb2FkTGltaXRgXHJcbiAgICogb3B0aW9uLlxyXG4gICAqL1xyXG4gIHVwbG9hZExpbWl0KHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gdi5wb3NpdGl2ZU51bShzdHJpY3RDaGVjayk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGBzZXJ2ZXJCZW5jaG1hcmtpbmdgIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGhcclxuICAgKiBhbiBvcHRpb25hbCBzdHJpY3RlciBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGUgc2FtZSB3b3JrIGFzIHRoZSBgYm9vbGVhbmAgdmFsaWRhdG9yLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIHNlcnZlckJlbmNobWFya2luZ1xyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nXHJcbiAgICogdGhlIGBzZXJ2ZXJCZW5jaG1hcmtpbmdgIG9wdGlvbi5cclxuICAgKi9cclxuICBzZXJ2ZXJCZW5jaG1hcmtpbmcoc3RyaWN0Q2hlY2spIHtcclxuICAgIHJldHVybiB2LmJvb2xlYW4oc3RyaWN0Q2hlY2spO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgcHJveHlIb3N0YCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoIGFuIG9wdGlvbmFsXHJcbiAgICogc3RyaWN0ZXIgY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhlIHNhbWUgd29yayBhcyB0aGUgYHN0cmluZ2AgdmFsaWRhdG9yLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIHByb3h5SG9zdFxyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nIHRoZSBgcHJveHlIb3N0YFxyXG4gICAqIG9wdGlvbi5cclxuICAgKi9cclxuICBwcm94eUhvc3Qoc3RyaWN0Q2hlY2spIHtcclxuICAgIHJldHVybiB2LnN0cmluZyhzdHJpY3RDaGVjayk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGBwcm94eVBvcnRgIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGggYW4gb3B0aW9uYWxcclxuICAgKiBzdHJpY3RlciBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGUgc2FtZSB3b3JrIGFzIGEgbnVsbGFibGUgYG5vbk5lZ2F0aXZlTnVtYFxyXG4gICAqIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiBwcm94eVBvcnRcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZyB0aGUgYHByb3h5UG9ydGBcclxuICAgKiBvcHRpb24uXHJcbiAgICovXHJcbiAgcHJveHlQb3J0KHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gdi5ub25OZWdhdGl2ZU51bShzdHJpY3RDaGVjaykubnVsbGFibGUoKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYHByb3h5VGltZW91dGAgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbFxyXG4gICAqIHN0cmljdGVyIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgdGhlIGBub25OZWdhdGl2ZU51bWBcclxuICAgKiB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gcHJveHlUaW1lb3V0XHJcbiAgICpcclxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IHN0cmljdENoZWNrIC0gRGV0ZXJtaW5lcyBpZiBzdHJpY3RlciB2YWxpZGF0aW9uIHNob3VsZFxyXG4gICAqIGJlIGFwcGxpZWQuXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9IEEgWm9kIHNjaGVtYSBvYmplY3QgZm9yIHZhbGlkYXRpbmdcclxuICAgKiB0aGUgYHByb3h5VGltZW91dGAgb3B0aW9uLlxyXG4gICAqL1xyXG4gIHByb3h5VGltZW91dChzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHYubm9uTmVnYXRpdmVOdW0oc3RyaWN0Q2hlY2spO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgZW5hYmxlUmF0ZUxpbWl0aW5nYCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoXHJcbiAgICogYW4gb3B0aW9uYWwgc3RyaWN0ZXIgY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhlIHNhbWUgd29yayBhcyB0aGUgYGJvb2xlYW5gIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiBlbmFibGVSYXRlTGltaXRpbmdcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZ1xyXG4gICAqIHRoZSBgZW5hYmxlUmF0ZUxpbWl0aW5nYCBvcHRpb24uXHJcbiAgICovXHJcbiAgZW5hYmxlUmF0ZUxpbWl0aW5nKHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gdi5ib29sZWFuKHN0cmljdENoZWNrKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYG1heFJlcXVlc3RzYCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoIGFuIG9wdGlvbmFsXHJcbiAgICogc3RyaWN0ZXIgY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhlIHNhbWUgd29yayBhcyB0aGUgYG5vbk5lZ2F0aXZlTnVtYFxyXG4gICAqIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiBtYXhSZXF1ZXN0c1xyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nIHRoZSBgbWF4UmVxdWVzdHNgXHJcbiAgICogb3B0aW9uLlxyXG4gICAqL1xyXG4gIG1heFJlcXVlc3RzKHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gdi5ub25OZWdhdGl2ZU51bShzdHJpY3RDaGVjayk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGB3aW5kb3dgIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGggYW4gb3B0aW9uYWwgc3RyaWN0ZXJcclxuICAgKiBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGUgc2FtZSB3b3JrIGFzIHRoZSBgbm9uTmVnYXRpdmVOdW1gXHJcbiAgICogdmFsaWRhdG9yLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIHdpbmRvd1xyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nIHRoZSBgd2luZG93YFxyXG4gICAqIG9wdGlvbi5cclxuICAgKi9cclxuICB3aW5kb3coc3RyaWN0Q2hlY2spIHtcclxuICAgIHJldHVybiB2Lm5vbk5lZ2F0aXZlTnVtKHN0cmljdENoZWNrKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYGRlbGF5YCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoIGFuIG9wdGlvbmFsIHN0cmljdGVyXHJcbiAgICogY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhlIHNhbWUgd29yayBhcyB0aGUgYG5vbk5lZ2F0aXZlTnVtYFxyXG4gICAqIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiBkZWxheVxyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nIHRoZSBgZGVsYXlgXHJcbiAgICogb3B0aW9uLlxyXG4gICAqL1xyXG4gIGRlbGF5KHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gdi5ub25OZWdhdGl2ZU51bShzdHJpY3RDaGVjayk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGB0cnVzdFByb3h5YCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoIGFuIG9wdGlvbmFsXHJcbiAgICogc3RyaWN0ZXIgY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhlIHNhbWUgd29yayBhcyB0aGUgYGJvb2xlYW5gIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiB0cnVzdFByb3h5XHJcbiAgICpcclxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IHN0cmljdENoZWNrIC0gRGV0ZXJtaW5lcyBpZiBzdHJpY3RlciB2YWxpZGF0aW9uIHNob3VsZFxyXG4gICAqIGJlIGFwcGxpZWQuXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9IEEgWm9kIHNjaGVtYSBvYmplY3QgZm9yIHZhbGlkYXRpbmcgdGhlIGB0cnVzdFByb3h5YFxyXG4gICAqIG9wdGlvbi5cclxuICAgKi9cclxuICB0cnVzdFByb3h5KHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gdi5ib29sZWFuKHN0cmljdENoZWNrKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYHNraXBLZXlgIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGggYW4gb3B0aW9uYWwgc3RyaWN0ZXJcclxuICAgKiBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGUgc2FtZSB3b3JrIGFzIHRoZSBgc3RyaW5nYCB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gc2tpcEtleVxyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nIHRoZSBgc2tpcEtleWBcclxuICAgKiBvcHRpb24uXHJcbiAgICovXHJcbiAgc2tpcEtleShzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHYuc3RyaW5nKHN0cmljdENoZWNrKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYHNraXBUb2tlbmAgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbFxyXG4gICAqIHN0cmljdGVyIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgdGhlIGBzdHJpbmdgIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiBza2lwVG9rZW5cclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZyB0aGUgYHNraXBUb2tlbmBcclxuICAgKiBvcHRpb24uXHJcbiAgICovXHJcbiAgc2tpcFRva2VuKHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gdi5zdHJpbmcoc3RyaWN0Q2hlY2spO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgZW5hYmxlU3NsYCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoIGFuIG9wdGlvbmFsXHJcbiAgICogc3RyaWN0ZXIgY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhlIHNhbWUgd29yayBhcyB0aGUgYGJvb2xlYW5gIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiBlbmFibGVTc2xcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZyB0aGUgYGVuYWJsZVNzbGBcclxuICAgKiBvcHRpb24uXHJcbiAgICovXHJcbiAgZW5hYmxlU3NsKHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gdi5ib29sZWFuKHN0cmljdENoZWNrKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYHNzbEZvcmNlYCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoIGFuIG9wdGlvbmFsXHJcbiAgICogc3RyaWN0ZXIgY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhlIHNhbWUgd29yayBhcyB0aGUgYGJvb2xlYW5gIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiBzc2xGb3JjZVxyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nIHRoZSBgc3NsRm9yY2VgXHJcbiAgICogb3B0aW9uLlxyXG4gICAqL1xyXG4gIHNzbEZvcmNlKHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gdi5ib29sZWFuKHN0cmljdENoZWNrKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYHNzbFBvcnRgIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGggYW4gb3B0aW9uYWwgc3RyaWN0ZXJcclxuICAgKiBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGUgc2FtZSB3b3JrIGFzIHRoZSBgbm9uTmVnYXRpdmVOdW1gXHJcbiAgICogdmFsaWRhdG9yLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIHNzbFBvcnRcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZyB0aGUgYHNzbFBvcnRgXHJcbiAgICogb3B0aW9uLlxyXG4gICAqL1xyXG4gIHNzbFBvcnQoc3RyaWN0Q2hlY2spIHtcclxuICAgIHJldHVybiB2Lm5vbk5lZ2F0aXZlTnVtKHN0cmljdENoZWNrKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYHNzbENlcnRQYXRoYCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoIGFuIG9wdGlvbmFsXHJcbiAgICogc3RyaWN0ZXIgY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhlIHNhbWUgd29yayBhcyB0aGUgYHN0cmluZ2AgdmFsaWRhdG9yLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIHNzbENlcnRQYXRoXHJcbiAgICpcclxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IHN0cmljdENoZWNrIC0gRGV0ZXJtaW5lcyBpZiBzdHJpY3RlciB2YWxpZGF0aW9uIHNob3VsZFxyXG4gICAqIGJlIGFwcGxpZWQuXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9IEEgWm9kIHNjaGVtYSBvYmplY3QgZm9yIHZhbGlkYXRpbmcgdGhlIGBzc2xDZXJ0UGF0aGBcclxuICAgKiBvcHRpb24uXHJcbiAgICovXHJcbiAgc3NsQ2VydFBhdGgoc3RyaWN0Q2hlY2spIHtcclxuICAgIHJldHVybiB2LnN0cmluZyhzdHJpY3RDaGVjayk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGBtaW5Xb3JrZXJzYCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoIGFuIG9wdGlvbmFsXHJcbiAgICogc3RyaWN0ZXIgY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhlIHNhbWUgd29yayBhcyB0aGUgYHBvc2l0aXZlTnVtYCB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gbWluV29ya2Vyc1xyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nIHRoZSBgbWluV29ya2Vyc2BcclxuICAgKiBvcHRpb24uXHJcbiAgICovXHJcbiAgbWluV29ya2VycyhzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHYucG9zaXRpdmVOdW0oc3RyaWN0Q2hlY2spO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgbWF4V29ya2Vyc2AgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbFxyXG4gICAqIHN0cmljdGVyIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgdGhlIGBwb3NpdGl2ZU51bWAgdmFsaWRhdG9yLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIG1heFdvcmtlcnNcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZyB0aGUgYG1heFdvcmtlcnNgXHJcbiAgICogb3B0aW9uLlxyXG4gICAqL1xyXG4gIG1heFdvcmtlcnMoc3RyaWN0Q2hlY2spIHtcclxuICAgIHJldHVybiB2LnBvc2l0aXZlTnVtKHN0cmljdENoZWNrKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYHdvcmtMaW1pdGAgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbFxyXG4gICAqIHN0cmljdGVyIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgdGhlIGBwb3NpdGl2ZU51bWAgdmFsaWRhdG9yLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIHdvcmtMaW1pdFxyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nIHRoZSBgd29ya0xpbWl0YFxyXG4gICAqIG9wdGlvbi5cclxuICAgKi9cclxuICB3b3JrTGltaXQoc3RyaWN0Q2hlY2spIHtcclxuICAgIHJldHVybiB2LnBvc2l0aXZlTnVtKHN0cmljdENoZWNrKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYGFjcXVpcmVUaW1lb3V0YCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoIGFuIG9wdGlvbmFsXHJcbiAgICogc3RyaWN0ZXIgY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhlIHNhbWUgd29yayBhcyB0aGUgYG5vbk5lZ2F0aXZlTnVtYFxyXG4gICAqIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiBhY3F1aXJlVGltZW91dFxyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nXHJcbiAgICogdGhlIGBhY3F1aXJlVGltZW91dGAgb3B0aW9uLlxyXG4gICAqL1xyXG4gIGFjcXVpcmVUaW1lb3V0KHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gdi5ub25OZWdhdGl2ZU51bShzdHJpY3RDaGVjayk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGBjcmVhdGVUaW1lb3V0YCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoIGFuIG9wdGlvbmFsXHJcbiAgICogc3RyaWN0ZXIgY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhlIHNhbWUgd29yayBhcyB0aGUgYG5vbk5lZ2F0aXZlTnVtYFxyXG4gICAqIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiBjcmVhdGVUaW1lb3V0XHJcbiAgICpcclxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IHN0cmljdENoZWNrIC0gRGV0ZXJtaW5lcyBpZiBzdHJpY3RlciB2YWxpZGF0aW9uIHNob3VsZFxyXG4gICAqIGJlIGFwcGxpZWQuXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9IEEgWm9kIHNjaGVtYSBvYmplY3QgZm9yIHZhbGlkYXRpbmdcclxuICAgKiB0aGUgYGNyZWF0ZVRpbWVvdXRgIG9wdGlvbi5cclxuICAgKi9cclxuICBjcmVhdGVUaW1lb3V0KHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gdi5ub25OZWdhdGl2ZU51bShzdHJpY3RDaGVjayk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGBkZXN0cm95VGltZW91dGAgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbFxyXG4gICAqIHN0cmljdGVyIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgdGhlIGBub25OZWdhdGl2ZU51bWBcclxuICAgKiB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gZGVzdHJveVRpbWVvdXRcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZ1xyXG4gICAqIHRoZSBgZGVzdHJveVRpbWVvdXRgIG9wdGlvbi5cclxuICAgKi9cclxuICBkZXN0cm95VGltZW91dChzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHYubm9uTmVnYXRpdmVOdW0oc3RyaWN0Q2hlY2spO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgaWRsZVRpbWVvdXRgIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGggYW4gb3B0aW9uYWxcclxuICAgKiBzdHJpY3RlciBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGUgc2FtZSB3b3JrIGFzIHRoZSBgbm9uTmVnYXRpdmVOdW1gXHJcbiAgICogdmFsaWRhdG9yLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIGlkbGVUaW1lb3V0XHJcbiAgICpcclxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IHN0cmljdENoZWNrIC0gRGV0ZXJtaW5lcyBpZiBzdHJpY3RlciB2YWxpZGF0aW9uIHNob3VsZFxyXG4gICAqIGJlIGFwcGxpZWQuXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9IEEgWm9kIHNjaGVtYSBvYmplY3QgZm9yIHZhbGlkYXRpbmdcclxuICAgKiB0aGUgYGlkbGVUaW1lb3V0YCBvcHRpb24uXHJcbiAgICovXHJcbiAgaWRsZVRpbWVvdXQoc3RyaWN0Q2hlY2spIHtcclxuICAgIHJldHVybiB2Lm5vbk5lZ2F0aXZlTnVtKHN0cmljdENoZWNrKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYGNyZWF0ZVJldHJ5SW50ZXJ2YWxgIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGhcclxuICAgKiBhbiBvcHRpb25hbCBzdHJpY3RlciBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGUgc2FtZSB3b3JrIGFzIHRoZSBgbm9uTmVnYXRpdmVOdW1gXHJcbiAgICogdmFsaWRhdG9yLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIGNyZWF0ZVJldHJ5SW50ZXJ2YWxcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZ1xyXG4gICAqIHRoZSBgY3JlYXRlUmV0cnlJbnRlcnZhbGAgb3B0aW9uLlxyXG4gICAqL1xyXG4gIGNyZWF0ZVJldHJ5SW50ZXJ2YWwoc3RyaWN0Q2hlY2spIHtcclxuICAgIHJldHVybiB2Lm5vbk5lZ2F0aXZlTnVtKHN0cmljdENoZWNrKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYHJlYXBlckludGVydmFsYCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoIGFuIG9wdGlvbmFsXHJcbiAgICogc3RyaWN0ZXIgY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhlIHNhbWUgd29yayBhcyB0aGUgYG5vbk5lZ2F0aXZlTnVtYFxyXG4gICAqIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiByZWFwZXJJbnRlcnZhbFxyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nXHJcbiAgICogdGhlIGByZWFwZXJJbnRlcnZhbGAgb3B0aW9uLlxyXG4gICAqL1xyXG4gIHJlYXBlckludGVydmFsKHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gdi5ub25OZWdhdGl2ZU51bShzdHJpY3RDaGVjayk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGBwb29sQmVuY2htYXJraW5nYCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoIGFuIG9wdGlvbmFsXHJcbiAgICogc3RyaWN0ZXIgY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhlIHNhbWUgd29yayBhcyB0aGUgYGJvb2xlYW5gIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiBwb29sQmVuY2htYXJraW5nXHJcbiAgICpcclxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IHN0cmljdENoZWNrIC0gRGV0ZXJtaW5lcyBpZiBzdHJpY3RlciB2YWxpZGF0aW9uIHNob3VsZFxyXG4gICAqIGJlIGFwcGxpZWQuXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9IEEgWm9kIHNjaGVtYSBvYmplY3QgZm9yIHZhbGlkYXRpbmdcclxuICAgKiB0aGUgYHBvb2xCZW5jaG1hcmtpbmdgIG9wdGlvbi5cclxuICAgKi9cclxuICBwb29sQmVuY2htYXJraW5nKHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gdi5ib29sZWFuKHN0cmljdENoZWNrKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYHJlc291cmNlc0ludGVydmFsYCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoXHJcbiAgICogYW4gb3B0aW9uYWwgc3RyaWN0ZXIgY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhlIHNhbWUgd29yayBhcyB0aGUgYG5vbk5lZ2F0aXZlTnVtYFxyXG4gICAqIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiByZXNvdXJjZXNJbnRlcnZhbFxyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nXHJcbiAgICogdGhlIGByZXNvdXJjZXNJbnRlcnZhbGAgb3B0aW9uLlxyXG4gICAqL1xyXG4gIHJlc291cmNlc0ludGVydmFsKHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gdi5ub25OZWdhdGl2ZU51bShzdHJpY3RDaGVjayk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGBsb2dMZXZlbGAgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbFxyXG4gICAqIHN0cmljdGVyIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoYXQ6XHJcbiAgICpcclxuICAgKiAtIFdoZW4gYHN0cmljdENoZWNrYCBpcyB0cnVlLCB0aGUgc2NoZW1hIHdpbGwgYWNjZXB0IGludGVnZXIgbnVtYmVyIHZhbHVlc1xyXG4gICAqIHRoYXQgYXJlIGJldHdlZW4gMCBhbmQgNSAoaW5jbHVzaXZlKS5cclxuICAgKlxyXG4gICAqIC0gV2hlbiBgc3RyaWN0Q2hlY2tgIGlzIGZhbHNlLCB0aGUgc2NoZW1hIHdpbGwgYWNjZXB0IGludGVnZXIgbnVtYmVyIHZhbHVlc1xyXG4gICAqIGFuZCBzdHJpbmdpZmllZCBpbnRlZ2VyIG51bWJlciB2YWx1ZXMgdGhhdCBhcmUgYmV0d2VlbiAxIGFuZCA1IChpbmNsdXNpdmUpLFxyXG4gICAqIG51bGwsICd1bmRlZmluZWQnLCAnbnVsbCcsIGFuZCAnJyB3aGljaCB3aWxsIGJlIHRyYW5zZm9ybWVkIHRvIG51bGwuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gbG9nTGV2ZWxcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZyB0aGUgYGxvZ0xldmVsYFxyXG4gICAqIG9wdGlvbi5cclxuICAgKi9cclxuICBsb2dMZXZlbChzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHN0cmljdENoZWNrXHJcbiAgICAgID8gei5udW1iZXIoKS5pbnQoKS5ndGUoMCkubHRlKDUpXHJcbiAgICAgIDogelxyXG4gICAgICAgICAgLnVuaW9uKFtcclxuICAgICAgICAgICAgelxyXG4gICAgICAgICAgICAgIC5zdHJpbmcoKVxyXG4gICAgICAgICAgICAgIC50cmltKClcclxuICAgICAgICAgICAgICAucmVmaW5lKFxyXG4gICAgICAgICAgICAgICAgKHZhbHVlKSA9PlxyXG4gICAgICAgICAgICAgICAgICAoIWlzTmFOKE51bWJlcih2YWx1ZSkpICYmXHJcbiAgICAgICAgICAgICAgICAgICAgdmFsdWUgIT09IHRydWUgJiZcclxuICAgICAgICAgICAgICAgICAgICAhdmFsdWUuc3RhcnRzV2l0aCgnWycpICYmXHJcbiAgICAgICAgICAgICAgICAgICAgTnVtYmVyLmlzSW50ZWdlcihOdW1iZXIodmFsdWUpKSAmJlxyXG4gICAgICAgICAgICAgICAgICAgIE51bWJlcih2YWx1ZSkgPj0gMCAmJlxyXG4gICAgICAgICAgICAgICAgICAgIE51bWJlcih2YWx1ZSkgPD0gNSkgfHxcclxuICAgICAgICAgICAgICAgICAgWyd1bmRlZmluZWQnLCAnbnVsbCcsICcnXS5pbmNsdWRlcyh2YWx1ZSksXHJcbiAgICAgICAgICAgICAgICB7XHJcbiAgICAgICAgICAgICAgICAgIHBhcmFtczoge1xyXG4gICAgICAgICAgICAgICAgICAgIGVycm9yTWVzc2FnZTogJ1RoZSB2YWx1ZSBtdXN0IGJlIHdpdGhpbiBhIDAgYW5kIDUgcmFuZ2UnXHJcbiAgICAgICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgICApXHJcbiAgICAgICAgICAgICAgLnRyYW5zZm9ybSgodmFsdWUpID0+XHJcbiAgICAgICAgICAgICAgICAhWyd1bmRlZmluZWQnLCAnbnVsbCcsICcnXS5pbmNsdWRlcyh2YWx1ZSlcclxuICAgICAgICAgICAgICAgICAgPyBOdW1iZXIodmFsdWUpXHJcbiAgICAgICAgICAgICAgICAgIDogbnVsbFxyXG4gICAgICAgICAgICAgICksXHJcbiAgICAgICAgICAgIHoubnVtYmVyKCkuaW50KCkuZ3RlKDApLmx0ZSg1KVxyXG4gICAgICAgICAgXSlcclxuICAgICAgICAgIC5udWxsYWJsZSgpO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgbG9nRmlsZWAgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbCBzdHJpY3RlclxyXG4gICAqIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgdGhlIGBzdHJpbmdgIHZhbGlkYXRvci5cclxuICAgKiBBZGRpdGlvbmFsbHksIGl0IG11c3QgYmUgYSBzdHJpbmcgdGhhdCBlbmRzIHdpdGggJy5sb2cnLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIGxvZ0ZpbGVcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZyB0aGUgYGxvZ0ZpbGVgXHJcbiAgICogb3B0aW9uLlxyXG4gICAqL1xyXG4gIGxvZ0ZpbGUoc3RyaWN0Q2hlY2spIHtcclxuICAgIHJldHVybiB2XHJcbiAgICAgIC5zdHJpbmcoc3RyaWN0Q2hlY2spXHJcbiAgICAgIC5yZWZpbmUoXHJcbiAgICAgICAgKHZhbHVlKSA9PlxyXG4gICAgICAgICAgdmFsdWUgPT09IG51bGwgfHwgKHZhbHVlLmxlbmd0aCA+PSA1ICYmIHZhbHVlLmVuZHNXaXRoKCcubG9nJykpLFxyXG4gICAgICAgIHtcclxuICAgICAgICAgIHBhcmFtczoge1xyXG4gICAgICAgICAgICBlcnJvck1lc3NhZ2U6ICdUaGUgdmFsdWUgbXVzdCBiZSBhIHN0cmluZyB0aGF0IGVuZHMgd2l0aCAubG9nJ1xyXG4gICAgICAgICAgfVxyXG4gICAgICAgIH1cclxuICAgICAgKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYGxvZ0Rlc3RgIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGggYW4gb3B0aW9uYWwgc3RyaWN0ZXJcclxuICAgKiBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGUgc2FtZSB3b3JrIGFzIHRoZSBgc3RyaW5nYCB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gbG9nRGVzdFxyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nIHRoZSBgbG9nRGVzdGBcclxuICAgKiBvcHRpb24uXHJcbiAgICovXHJcbiAgbG9nRGVzdChzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHYuc3RyaW5nKHN0cmljdENoZWNrKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYGxvZ1RvQ29uc29sZWAgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbFxyXG4gICAqIHN0cmljdGVyIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgdGhlIGBib29sZWFuYCB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gbG9nVG9Db25zb2xlXHJcbiAgICpcclxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IHN0cmljdENoZWNrIC0gRGV0ZXJtaW5lcyBpZiBzdHJpY3RlciB2YWxpZGF0aW9uIHNob3VsZFxyXG4gICAqIGJlIGFwcGxpZWQuXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9IEEgWm9kIHNjaGVtYSBvYmplY3QgZm9yIHZhbGlkYXRpbmdcclxuICAgKiB0aGUgYGxvZ1RvQ29uc29sZWAgb3B0aW9uLlxyXG4gICAqL1xyXG4gIGxvZ1RvQ29uc29sZShzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHYuYm9vbGVhbihzdHJpY3RDaGVjayk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGBsb2dUb0ZpbGVgIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGggYW4gb3B0aW9uYWxcclxuICAgKiBzdHJpY3RlciBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGUgc2FtZSB3b3JrIGFzIHRoZSBgYm9vbGVhbmAgdmFsaWRhdG9yLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIGxvZ1RvRmlsZVxyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nIHRoZSBgbG9nVG9GaWxlYFxyXG4gICAqIG9wdGlvbi5cclxuICAgKi9cclxuICBsb2dUb0ZpbGUoc3RyaWN0Q2hlY2spIHtcclxuICAgIHJldHVybiB2LmJvb2xlYW4oc3RyaWN0Q2hlY2spO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgZW5hYmxlVWlgIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGggYW4gb3B0aW9uYWxcclxuICAgKiBzdHJpY3RlciBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGUgc2FtZSB3b3JrIGFzIHRoZSBgYm9vbGVhbmAgdmFsaWRhdG9yLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIGVuYWJsZVVpXHJcbiAgICpcclxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IHN0cmljdENoZWNrIC0gRGV0ZXJtaW5lcyBpZiBzdHJpY3RlciB2YWxpZGF0aW9uIHNob3VsZFxyXG4gICAqIGJlIGFwcGxpZWQuXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9IEEgWm9kIHNjaGVtYSBvYmplY3QgZm9yIHZhbGlkYXRpbmcgdGhlIGBlbmFibGVVaWBcclxuICAgKiBvcHRpb24uXHJcbiAgICovXHJcbiAgZW5hYmxlVWkoc3RyaWN0Q2hlY2spIHtcclxuICAgIHJldHVybiB2LmJvb2xlYW4oc3RyaWN0Q2hlY2spO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgdWlSb3V0ZWAgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbFxyXG4gICAqIHN0cmljdGVyIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgdGhlIGBzdGFydHNXaXRoYCB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gdWlSb3V0ZVxyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nIHRoZSBgdWlSb3V0ZWBcclxuICAgKiBvcHRpb24uXHJcbiAgICovXHJcbiAgdWlSb3V0ZShzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHYuc3RhcnRzV2l0aChbJy8nXSwgc3RyaWN0Q2hlY2spO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgbm9kZUVudmAgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbFxyXG4gICAqIHN0cmljdGVyIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgdGhlIGBlbnVtYCB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gbm9kZUVudlxyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nIHRoZSBgbm9kZUVudmBcclxuICAgKiBvcHRpb24uXHJcbiAgICovXHJcbiAgbm9kZUVudihzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHYuZW51bShbJ2RldmVsb3BtZW50JywgJ3Byb2R1Y3Rpb24nLCAndGVzdCddLCBzdHJpY3RDaGVjayk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGBsaXN0ZW5Ub1Byb2Nlc3NFeGl0c2AgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aFxyXG4gICAqIGFuIG9wdGlvbmFsIHN0cmljdGVyIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgdGhlIGBib29sZWFuYCB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gbGlzdGVuVG9Qcm9jZXNzRXhpdHNcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZ1xyXG4gICAqIHRoZSBgbGlzdGVuVG9Qcm9jZXNzRXhpdHNgIG9wdGlvbi5cclxuICAgKi9cclxuICBsaXN0ZW5Ub1Byb2Nlc3NFeGl0cyhzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHYuYm9vbGVhbihzdHJpY3RDaGVjayk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGBub0xvZ29gIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGggYW4gb3B0aW9uYWxcclxuICAgKiBzdHJpY3RlciBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGUgc2FtZSB3b3JrIGFzIHRoZSBgYm9vbGVhbmAgdmFsaWRhdG9yLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIG5vTG9nb1xyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nIHRoZSBgbm9Mb2dvYFxyXG4gICAqIG9wdGlvbi5cclxuICAgKi9cclxuICBub0xvZ28oc3RyaWN0Q2hlY2spIHtcclxuICAgIHJldHVybiB2LmJvb2xlYW4oc3RyaWN0Q2hlY2spO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgaGFyZFJlc2V0UGFnZWAgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbFxyXG4gICAqIHN0cmljdGVyIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgdGhlIGBib29sZWFuYCB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gaGFyZFJlc2V0UGFnZVxyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nXHJcbiAgICogdGhlIGBoYXJkUmVzZXRQYWdlYCBvcHRpb24uXHJcbiAgICovXHJcbiAgaGFyZFJlc2V0UGFnZShzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHYuYm9vbGVhbihzdHJpY3RDaGVjayk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGBicm93c2VyU2hlbGxNb2RlYCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoIGFuIG9wdGlvbmFsXHJcbiAgICogc3RyaWN0ZXIgY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhlIHNhbWUgd29yayBhcyB0aGUgYGJvb2xlYW5gIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiBicm93c2VyU2hlbGxNb2RlXHJcbiAgICpcclxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IHN0cmljdENoZWNrIC0gRGV0ZXJtaW5lcyBpZiBzdHJpY3RlciB2YWxpZGF0aW9uIHNob3VsZFxyXG4gICAqIGJlIGFwcGxpZWQuXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9IEEgWm9kIHNjaGVtYSBvYmplY3QgZm9yIHZhbGlkYXRpbmdcclxuICAgKiB0aGUgYGJyb3dzZXJTaGVsbE1vZGVgIG9wdGlvbi5cclxuICAgKi9cclxuICBicm93c2VyU2hlbGxNb2RlKHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gdi5ib29sZWFuKHN0cmljdENoZWNrKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYHZhbGlkYXRpb25gIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGggYW4gb3B0aW9uYWxcclxuICAgKiBzdHJpY3RlciBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGUgc2FtZSB3b3JrIGFzIHRoZSBgYm9vbGVhbmAgdmFsaWRhdG9yLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIHZhbGlkYXRpb25cclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZyB0aGUgYHZhbGlkYXRpb25gXHJcbiAgICogb3B0aW9uLlxyXG4gICAqL1xyXG4gIHZhbGlkYXRpb24oc3RyaWN0Q2hlY2spIHtcclxuICAgIHJldHVybiB2LmJvb2xlYW4oc3RyaWN0Q2hlY2spO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgZW5hYmxlRGVidWdgIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGggYW4gb3B0aW9uYWxcclxuICAgKiBzdHJpY3RlciBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGUgc2FtZSB3b3JrIGFzIHRoZSBgYm9vbGVhbmAgdmFsaWRhdG9yLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIGVuYWJsZURlYnVnXHJcbiAgICpcclxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IHN0cmljdENoZWNrIC0gRGV0ZXJtaW5lcyBpZiBzdHJpY3RlciB2YWxpZGF0aW9uIHNob3VsZFxyXG4gICAqIGJlIGFwcGxpZWQuXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9IEEgWm9kIHNjaGVtYSBvYmplY3QgZm9yIHZhbGlkYXRpbmcgdGhlIGBlbmFibGVEZWJ1Z2BcclxuICAgKiBvcHRpb24uXHJcbiAgICovXHJcbiAgZW5hYmxlRGVidWcoc3RyaWN0Q2hlY2spIHtcclxuICAgIHJldHVybiB2LmJvb2xlYW4oc3RyaWN0Q2hlY2spO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgaGVhZGxlc3NgIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGggYW4gb3B0aW9uYWxcclxuICAgKiBzdHJpY3RlciBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGUgc2FtZSB3b3JrIGFzIHRoZSBgYm9vbGVhbmAgdmFsaWRhdG9yLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIGhlYWRsZXNzXHJcbiAgICpcclxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IHN0cmljdENoZWNrIC0gRGV0ZXJtaW5lcyBpZiBzdHJpY3RlciB2YWxpZGF0aW9uIHNob3VsZFxyXG4gICAqIGJlIGFwcGxpZWQuXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9IEEgWm9kIHNjaGVtYSBvYmplY3QgZm9yIHZhbGlkYXRpbmcgdGhlIGBoZWFkbGVzc2BcclxuICAgKiBvcHRpb24uXHJcbiAgICovXHJcbiAgaGVhZGxlc3Moc3RyaWN0Q2hlY2spIHtcclxuICAgIHJldHVybiB2LmJvb2xlYW4oc3RyaWN0Q2hlY2spO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgZGV2dG9vbHNgIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGggYW4gb3B0aW9uYWxcclxuICAgKiBzdHJpY3RlciBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGUgc2FtZSB3b3JrIGFzIHRoZSBgYm9vbGVhbmAgdmFsaWRhdG9yLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIGRldnRvb2xzXHJcbiAgICpcclxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IHN0cmljdENoZWNrIC0gRGV0ZXJtaW5lcyBpZiBzdHJpY3RlciB2YWxpZGF0aW9uIHNob3VsZFxyXG4gICAqIGJlIGFwcGxpZWQuXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9IEEgWm9kIHNjaGVtYSBvYmplY3QgZm9yIHZhbGlkYXRpbmcgdGhlIGBkZXZ0b29sc2BcclxuICAgKiBvcHRpb24uXHJcbiAgICovXHJcbiAgZGV2dG9vbHMoc3RyaWN0Q2hlY2spIHtcclxuICAgIHJldHVybiB2LmJvb2xlYW4oc3RyaWN0Q2hlY2spO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgbGlzdGVuVG9Db25zb2xlYCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoIGFuIG9wdGlvbmFsXHJcbiAgICogc3RyaWN0ZXIgY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhlIHNhbWUgd29yayBhcyB0aGUgYGJvb2xlYW5gIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiBsaXN0ZW5Ub0NvbnNvbGVcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZ1xyXG4gICAqIHRoZSBgbGlzdGVuVG9Db25zb2xlYCBvcHRpb24uXHJcbiAgICovXHJcbiAgbGlzdGVuVG9Db25zb2xlKHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gdi5ib29sZWFuKHN0cmljdENoZWNrKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYGR1bXBpb2AgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbCBzdHJpY3RlclxyXG4gICAqIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgdGhlIGBib29sZWFuYCB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gZHVtcGlvXHJcbiAgICpcclxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IHN0cmljdENoZWNrIC0gRGV0ZXJtaW5lcyBpZiBzdHJpY3RlciB2YWxpZGF0aW9uIHNob3VsZFxyXG4gICAqIGJlIGFwcGxpZWQuXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9IEEgWm9kIHNjaGVtYSBvYmplY3QgZm9yIHZhbGlkYXRpbmcgdGhlIGBkdW1waW9gXHJcbiAgICogb3B0aW9uLlxyXG4gICAqL1xyXG4gIGR1bXBpbyhzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHYuYm9vbGVhbihzdHJpY3RDaGVjayk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGBzbG93TW9gIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGggYW4gb3B0aW9uYWwgc3RyaWN0ZXJcclxuICAgKiBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGUgc2FtZSB3b3JrIGFzIHRoZSBgbm9uTmVnYXRpdmVOdW1gXHJcbiAgICogdmFsaWRhdG9yLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIHNsb3dNb1xyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nIHRoZSBgc2xvd01vYFxyXG4gICAqIG9wdGlvbi5cclxuICAgKi9cclxuICBzbG93TW8oc3RyaWN0Q2hlY2spIHtcclxuICAgIHJldHVybiB2Lm5vbk5lZ2F0aXZlTnVtKHN0cmljdENoZWNrKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYGRlYnVnZ2luZ1BvcnRgIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGggYW4gb3B0aW9uYWxcclxuICAgKiBzdHJpY3RlciBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGUgc2FtZSB3b3JrIGFzIHRoZSBgbm9uTmVnYXRpdmVOdW1gXHJcbiAgICogdmFsaWRhdG9yLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIGRlYnVnZ2luZ1BvcnRcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZ1xyXG4gICAqIHRoZSBgZGVidWdnaW5nUG9ydGAgb3B0aW9uLlxyXG4gICAqL1xyXG4gIGRlYnVnZ2luZ1BvcnQoc3RyaWN0Q2hlY2spIHtcclxuICAgIHJldHVybiB2Lm5vbk5lZ2F0aXZlTnVtKHN0cmljdENoZWNrKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYHJlcXVlc3RJZGAgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbFxyXG4gICAqIHN0cmljdGVyIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgdGhlIGBzdHJpbmdgIHZhbGlkYXRvci5cclxuICAgKiBBZGRpdGlvbmFsbHksIGl0IG11c3QgYmUgYSBzdHJpbmdpZmllZCBVVUlEIG9yIGNhbiBiZSBudWxsLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIHJlcXVlc3RJZFxyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nIHRoZSBgcmVxdWVzdElkYFxyXG4gICAqIG9wdGlvbi5cclxuICAgKi9cclxuICByZXF1ZXN0SWQoKSB7XHJcbiAgICByZXR1cm4gelxyXG4gICAgICAuc3RyaW5nKClcclxuICAgICAgLnV1aWQoeyBtZXNzYWdlOiAnVGhlIHZhbHVlIG11c3QgYmUgYSBzdHJpbmdpZmllZCBVVUlEJyB9KVxyXG4gICAgICAubnVsbGFibGUoKTtcclxuICB9XHJcbn07XHJcblxyXG4vLyBTY2hlbWEgZm9yIHRoZSBwdXBwZXRlZXIgc2VjdGlvbiBvZiBvcHRpb25zXHJcbmNvbnN0IFB1cHBldGVlclNjaGVtYSA9IChzdHJpY3RDaGVjaykgPT5cclxuICB6XHJcbiAgICAub2JqZWN0KHtcclxuICAgICAgYXJnczogdmFsaWRhdG9ycy5hcmdzKHN0cmljdENoZWNrKVxyXG4gICAgfSlcclxuICAgIC5wYXJ0aWFsKCk7XHJcblxyXG4vLyBTY2hlbWEgZm9yIHRoZSBoaWdoY2hhcnRzIHNlY3Rpb24gb2Ygb3B0aW9uc1xyXG5jb25zdCBIaWdoY2hhcnRzU2NoZW1hID0gKHN0cmljdENoZWNrKSA9PlxyXG4gIHpcclxuICAgIC5vYmplY3Qoe1xyXG4gICAgICB2ZXJzaW9uOiB2YWxpZGF0b3JzLnZlcnNpb24oc3RyaWN0Q2hlY2spLFxyXG4gICAgICBjZG5Vcmw6IHZhbGlkYXRvcnMuY2RuVXJsKHN0cmljdENoZWNrKSxcclxuICAgICAgZm9yY2VGZXRjaDogdmFsaWRhdG9ycy5mb3JjZUZldGNoKHN0cmljdENoZWNrKSxcclxuICAgICAgY2FjaGVQYXRoOiB2YWxpZGF0b3JzLmNhY2hlUGF0aChzdHJpY3RDaGVjayksXHJcbiAgICAgIGNvcmVTY3JpcHRzOiB2YWxpZGF0b3JzLmNvcmVTY3JpcHRzKHN0cmljdENoZWNrKSxcclxuICAgICAgbW9kdWxlU2NyaXB0czogdmFsaWRhdG9ycy5tb2R1bGVTY3JpcHRzKHN0cmljdENoZWNrKSxcclxuICAgICAgaW5kaWNhdG9yU2NyaXB0czogdmFsaWRhdG9ycy5pbmRpY2F0b3JTY3JpcHRzKHN0cmljdENoZWNrKSxcclxuICAgICAgY3VzdG9tU2NyaXB0czogdmFsaWRhdG9ycy5jdXN0b21TY3JpcHRzKHN0cmljdENoZWNrKVxyXG4gICAgfSlcclxuICAgIC5wYXJ0aWFsKCk7XHJcblxyXG4vLyBTY2hlbWEgZm9yIHRoZSBleHBvcnQgc2VjdGlvbiBvZiBvcHRpb25zXHJcbmNvbnN0IEV4cG9ydFNjaGVtYSA9IChzdHJpY3RDaGVjaykgPT5cclxuICB6XHJcbiAgICAub2JqZWN0KHtcclxuICAgICAgaW5maWxlOiB2YWxpZGF0b3JzLmluZmlsZShzdHJpY3RDaGVjayksXHJcbiAgICAgIGluc3RyOiB2YWxpZGF0b3JzLmluc3RyKCksXHJcbiAgICAgIG9wdGlvbnM6IHZhbGlkYXRvcnMub3B0aW9ucygpLFxyXG4gICAgICBzdmc6IHZhbGlkYXRvcnMuc3ZnKCksXHJcbiAgICAgIG91dGZpbGU6IHZhbGlkYXRvcnMub3V0ZmlsZShzdHJpY3RDaGVjayksXHJcbiAgICAgIHR5cGU6IHZhbGlkYXRvcnMudHlwZShzdHJpY3RDaGVjayksXHJcbiAgICAgIGNvbnN0cjogdmFsaWRhdG9ycy5jb25zdHIoc3RyaWN0Q2hlY2spLFxyXG4gICAgICBiNjQ6IHZhbGlkYXRvcnMuYjY0KHN0cmljdENoZWNrKSxcclxuICAgICAgbm9Eb3dubG9hZDogdmFsaWRhdG9ycy5ub0Rvd25sb2FkKHN0cmljdENoZWNrKSxcclxuICAgICAgZGVmYXVsdEhlaWdodDogdmFsaWRhdG9ycy5kZWZhdWx0SGVpZ2h0KHN0cmljdENoZWNrKSxcclxuICAgICAgZGVmYXVsdFdpZHRoOiB2YWxpZGF0b3JzLmRlZmF1bHRXaWR0aChzdHJpY3RDaGVjayksXHJcbiAgICAgIGRlZmF1bHRTY2FsZTogdmFsaWRhdG9ycy5kZWZhdWx0U2NhbGUoc3RyaWN0Q2hlY2spLFxyXG4gICAgICBoZWlnaHQ6IHZhbGlkYXRvcnMuaGVpZ2h0KHN0cmljdENoZWNrKSxcclxuICAgICAgd2lkdGg6IHZhbGlkYXRvcnMud2lkdGgoc3RyaWN0Q2hlY2spLFxyXG4gICAgICBzY2FsZTogdmFsaWRhdG9ycy5zY2FsZShzdHJpY3RDaGVjayksXHJcbiAgICAgIGdsb2JhbE9wdGlvbnM6IHZhbGlkYXRvcnMuZ2xvYmFsT3B0aW9ucygpLFxyXG4gICAgICB0aGVtZU9wdGlvbnM6IHZhbGlkYXRvcnMudGhlbWVPcHRpb25zKCksXHJcbiAgICAgIGJhdGNoOiB2YWxpZGF0b3JzLmJhdGNoKGZhbHNlKSxcclxuICAgICAgcmFzdGVyaXphdGlvblRpbWVvdXQ6IHZhbGlkYXRvcnMucmFzdGVyaXphdGlvblRpbWVvdXQoc3RyaWN0Q2hlY2spXHJcbiAgICB9KVxyXG4gICAgLnBhcnRpYWwoKTtcclxuXHJcbi8vIFNjaGVtYSBmb3IgdGhlIGN1c3RvbUxvZ2ljIHNlY3Rpb24gb2Ygb3B0aW9uc1xyXG5jb25zdCBDdXN0b21Mb2dpY1NjaGVtYSA9IChzdHJpY3RDaGVjaykgPT5cclxuICB6XHJcbiAgICAub2JqZWN0KHtcclxuICAgICAgYWxsb3dDb2RlRXhlY3V0aW9uOiB2YWxpZGF0b3JzLmFsbG93Q29kZUV4ZWN1dGlvbihzdHJpY3RDaGVjayksXHJcbiAgICAgIGFsbG93RmlsZVJlc291cmNlczogdmFsaWRhdG9ycy5hbGxvd0ZpbGVSZXNvdXJjZXMoc3RyaWN0Q2hlY2spLFxyXG4gICAgICBjdXN0b21Db2RlOiB2YWxpZGF0b3JzLmN1c3RvbUNvZGUoZmFsc2UpLFxyXG4gICAgICBjYWxsYmFjazogdmFsaWRhdG9ycy5jYWxsYmFjayhmYWxzZSksXHJcbiAgICAgIHJlc291cmNlczogdmFsaWRhdG9ycy5yZXNvdXJjZXMoc3RyaWN0Q2hlY2spLFxyXG4gICAgICBsb2FkQ29uZmlnOiB2YWxpZGF0b3JzLmxvYWRDb25maWcoZmFsc2UpLFxyXG4gICAgICBjcmVhdGVDb25maWc6IHZhbGlkYXRvcnMuY3JlYXRlQ29uZmlnKGZhbHNlKVxyXG4gICAgfSlcclxuICAgIC5wYXJ0aWFsKCk7XHJcblxyXG4vLyBTY2hlbWEgZm9yIHRoZSBzZXJ2ZXIucHJveHkgc2VjdGlvbiBvZiBvcHRpb25zXHJcbmNvbnN0IFByb3h5U2NoZW1hID0gKHN0cmljdENoZWNrKSA9PlxyXG4gIHpcclxuICAgIC5vYmplY3Qoe1xyXG4gICAgICBob3N0OiB2YWxpZGF0b3JzLnByb3h5SG9zdChmYWxzZSksXHJcbiAgICAgIHBvcnQ6IHZhbGlkYXRvcnMucHJveHlQb3J0KHN0cmljdENoZWNrKSxcclxuICAgICAgdGltZW91dDogdmFsaWRhdG9ycy5wcm94eVRpbWVvdXQoc3RyaWN0Q2hlY2spXHJcbiAgICB9KVxyXG4gICAgLnBhcnRpYWwoKTtcclxuXHJcbi8vIFNjaGVtYSBmb3IgdGhlIHNlcnZlci5yYXRlTGltaXRpbmcgc2VjdGlvbiBvZiBvcHRpb25zXHJcbmNvbnN0IFJhdGVMaW1pdGluZ1NjaGVtYSA9IChzdHJpY3RDaGVjaykgPT5cclxuICB6XHJcbiAgICAub2JqZWN0KHtcclxuICAgICAgZW5hYmxlOiB2YWxpZGF0b3JzLmVuYWJsZVJhdGVMaW1pdGluZyhzdHJpY3RDaGVjayksXHJcbiAgICAgIG1heFJlcXVlc3RzOiB2YWxpZGF0b3JzLm1heFJlcXVlc3RzKHN0cmljdENoZWNrKSxcclxuICAgICAgd2luZG93OiB2YWxpZGF0b3JzLndpbmRvdyhzdHJpY3RDaGVjayksXHJcbiAgICAgIGRlbGF5OiB2YWxpZGF0b3JzLmRlbGF5KHN0cmljdENoZWNrKSxcclxuICAgICAgdHJ1c3RQcm94eTogdmFsaWRhdG9ycy50cnVzdFByb3h5KHN0cmljdENoZWNrKSxcclxuICAgICAgc2tpcEtleTogdmFsaWRhdG9ycy5za2lwS2V5KGZhbHNlKSxcclxuICAgICAgc2tpcFRva2VuOiB2YWxpZGF0b3JzLnNraXBUb2tlbihmYWxzZSlcclxuICAgIH0pXHJcbiAgICAucGFydGlhbCgpO1xyXG5cclxuLy8gU2NoZW1hIGZvciB0aGUgc2VydmVyLnNzbCBzZWN0aW9uIG9mIG9wdGlvbnNcclxuY29uc3QgU3NsU2NoZW1hID0gKHN0cmljdENoZWNrKSA9PlxyXG4gIHpcclxuICAgIC5vYmplY3Qoe1xyXG4gICAgICBlbmFibGU6IHZhbGlkYXRvcnMuZW5hYmxlU3NsKHN0cmljdENoZWNrKSxcclxuICAgICAgZm9yY2U6IHZhbGlkYXRvcnMuc3NsRm9yY2Uoc3RyaWN0Q2hlY2spLFxyXG4gICAgICBwb3J0OiB2YWxpZGF0b3JzLnNzbFBvcnQoc3RyaWN0Q2hlY2spLFxyXG4gICAgICBjZXJ0UGF0aDogdmFsaWRhdG9ycy5zc2xDZXJ0UGF0aChmYWxzZSlcclxuICAgIH0pXHJcbiAgICAucGFydGlhbCgpO1xyXG5cclxuLy8gU2NoZW1hIGZvciB0aGUgc2VydmVyIHNlY3Rpb24gb2Ygb3B0aW9uc1xyXG5jb25zdCBTZXJ2ZXJTY2hlbWEgPSAoc3RyaWN0Q2hlY2spID0+XHJcbiAgei5vYmplY3Qoe1xyXG4gICAgZW5hYmxlOiB2YWxpZGF0b3JzLmVuYWJsZVNlcnZlcihzdHJpY3RDaGVjaykub3B0aW9uYWwoKSxcclxuICAgIGhvc3Q6IHZhbGlkYXRvcnMuaG9zdChzdHJpY3RDaGVjaykub3B0aW9uYWwoKSxcclxuICAgIHBvcnQ6IHZhbGlkYXRvcnMucG9ydChzdHJpY3RDaGVjaykub3B0aW9uYWwoKSxcclxuICAgIHVwbG9hZExpbWl0OiB2YWxpZGF0b3JzLnVwbG9hZExpbWl0KHN0cmljdENoZWNrKS5vcHRpb25hbCgpLFxyXG4gICAgYmVuY2htYXJraW5nOiB2YWxpZGF0b3JzLnNlcnZlckJlbmNobWFya2luZyhzdHJpY3RDaGVjaykub3B0aW9uYWwoKSxcclxuICAgIHByb3h5OiBQcm94eVNjaGVtYShzdHJpY3RDaGVjaykub3B0aW9uYWwoKSxcclxuICAgIHJhdGVMaW1pdGluZzogUmF0ZUxpbWl0aW5nU2NoZW1hKHN0cmljdENoZWNrKS5vcHRpb25hbCgpLFxyXG4gICAgc3NsOiBTc2xTY2hlbWEoc3RyaWN0Q2hlY2spLm9wdGlvbmFsKClcclxuICB9KTtcclxuXHJcbi8vIFNjaGVtYSBmb3IgdGhlIHBvb2wgc2VjdGlvbiBvZiBvcHRpb25zXHJcbmNvbnN0IFBvb2xTY2hlbWEgPSAoc3RyaWN0Q2hlY2spID0+XHJcbiAgelxyXG4gICAgLm9iamVjdCh7XHJcbiAgICAgIG1pbldvcmtlcnM6IHZhbGlkYXRvcnMubWluV29ya2VycyhzdHJpY3RDaGVjayksXHJcbiAgICAgIG1heFdvcmtlcnM6IHZhbGlkYXRvcnMubWF4V29ya2VycyhzdHJpY3RDaGVjayksXHJcbiAgICAgIHdvcmtMaW1pdDogdmFsaWRhdG9ycy53b3JrTGltaXQoc3RyaWN0Q2hlY2spLFxyXG4gICAgICBhY3F1aXJlVGltZW91dDogdmFsaWRhdG9ycy5hY3F1aXJlVGltZW91dChzdHJpY3RDaGVjayksXHJcbiAgICAgIGNyZWF0ZVRpbWVvdXQ6IHZhbGlkYXRvcnMuY3JlYXRlVGltZW91dChzdHJpY3RDaGVjayksXHJcbiAgICAgIGRlc3Ryb3lUaW1lb3V0OiB2YWxpZGF0b3JzLmRlc3Ryb3lUaW1lb3V0KHN0cmljdENoZWNrKSxcclxuICAgICAgaWRsZVRpbWVvdXQ6IHZhbGlkYXRvcnMuaWRsZVRpbWVvdXQoc3RyaWN0Q2hlY2spLFxyXG4gICAgICBjcmVhdGVSZXRyeUludGVydmFsOiB2YWxpZGF0b3JzLmNyZWF0ZVJldHJ5SW50ZXJ2YWwoc3RyaWN0Q2hlY2spLFxyXG4gICAgICByZWFwZXJJbnRlcnZhbDogdmFsaWRhdG9ycy5yZWFwZXJJbnRlcnZhbChzdHJpY3RDaGVjayksXHJcbiAgICAgIGJlbmNobWFya2luZzogdmFsaWRhdG9ycy5wb29sQmVuY2htYXJraW5nKHN0cmljdENoZWNrKVxyXG4gICAgfSlcclxuICAgIC5wYXJ0aWFsKCk7XHJcblxyXG4vLyBTY2hlbWEgZm9yIHRoZSBsb2dnaW5nIHNlY3Rpb24gb2Ygb3B0aW9uc1xyXG5jb25zdCBMb2dnaW5nU2NoZW1hID0gKHN0cmljdENoZWNrKSA9PlxyXG4gIHpcclxuICAgIC5vYmplY3Qoe1xyXG4gICAgICBsZXZlbDogdmFsaWRhdG9ycy5sb2dMZXZlbChzdHJpY3RDaGVjayksXHJcbiAgICAgIGZpbGU6IHZhbGlkYXRvcnMubG9nRmlsZShzdHJpY3RDaGVjayksXHJcbiAgICAgIGRlc3Q6IHZhbGlkYXRvcnMubG9nRGVzdChzdHJpY3RDaGVjayksXHJcbiAgICAgIHRvQ29uc29sZTogdmFsaWRhdG9ycy5sb2dUb0NvbnNvbGUoc3RyaWN0Q2hlY2spLFxyXG4gICAgICB0b0ZpbGU6IHZhbGlkYXRvcnMubG9nVG9GaWxlKHN0cmljdENoZWNrKVxyXG4gICAgfSlcclxuICAgIC5wYXJ0aWFsKCk7XHJcblxyXG4vLyBTY2hlbWEgZm9yIHRoZSB1aSBzZWN0aW9uIG9mIG9wdGlvbnNcclxuY29uc3QgVWlTY2hlbWEgPSAoc3RyaWN0Q2hlY2spID0+XHJcbiAgelxyXG4gICAgLm9iamVjdCh7XHJcbiAgICAgIGVuYWJsZTogdmFsaWRhdG9ycy5lbmFibGVVaShzdHJpY3RDaGVjayksXHJcbiAgICAgIHJvdXRlOiB2YWxpZGF0b3JzLnVpUm91dGUoc3RyaWN0Q2hlY2spXHJcbiAgICB9KVxyXG4gICAgLnBhcnRpYWwoKTtcclxuXHJcbi8vIFNjaGVtYSBmb3IgdGhlIG90aGVyIHNlY3Rpb24gb2Ygb3B0aW9uc1xyXG5jb25zdCBPdGhlclNjaGVtYSA9IChzdHJpY3RDaGVjaykgPT5cclxuICB6XHJcbiAgICAub2JqZWN0KHtcclxuICAgICAgbm9kZUVudjogdmFsaWRhdG9ycy5ub2RlRW52KHN0cmljdENoZWNrKSxcclxuICAgICAgbGlzdGVuVG9Qcm9jZXNzRXhpdHM6IHZhbGlkYXRvcnMubGlzdGVuVG9Qcm9jZXNzRXhpdHMoc3RyaWN0Q2hlY2spLFxyXG4gICAgICBub0xvZ286IHZhbGlkYXRvcnMubm9Mb2dvKHN0cmljdENoZWNrKSxcclxuICAgICAgaGFyZFJlc2V0UGFnZTogdmFsaWRhdG9ycy5oYXJkUmVzZXRQYWdlKHN0cmljdENoZWNrKSxcclxuICAgICAgYnJvd3NlclNoZWxsTW9kZTogdmFsaWRhdG9ycy5icm93c2VyU2hlbGxNb2RlKHN0cmljdENoZWNrKSxcclxuICAgICAgdmFsaWRhdGlvbjogdmFsaWRhdG9ycy52YWxpZGF0aW9uKHN0cmljdENoZWNrKVxyXG4gICAgfSlcclxuICAgIC5wYXJ0aWFsKCk7XHJcblxyXG4vLyBTY2hlbWEgZm9yIHRoZSBkZWJ1ZyBzZWN0aW9uIG9mIG9wdGlvbnNcclxuY29uc3QgRGVidWdTY2hlbWEgPSAoc3RyaWN0Q2hlY2spID0+XHJcbiAgelxyXG4gICAgLm9iamVjdCh7XHJcbiAgICAgIGVuYWJsZTogdmFsaWRhdG9ycy5lbmFibGVEZWJ1ZyhzdHJpY3RDaGVjayksXHJcbiAgICAgIGhlYWRsZXNzOiB2YWxpZGF0b3JzLmhlYWRsZXNzKHN0cmljdENoZWNrKSxcclxuICAgICAgZGV2dG9vbHM6IHZhbGlkYXRvcnMuZGV2dG9vbHMoc3RyaWN0Q2hlY2spLFxyXG4gICAgICBsaXN0ZW5Ub0NvbnNvbGU6IHZhbGlkYXRvcnMubGlzdGVuVG9Db25zb2xlKHN0cmljdENoZWNrKSxcclxuICAgICAgZHVtcGlvOiB2YWxpZGF0b3JzLmR1bXBpbyhzdHJpY3RDaGVjayksXHJcbiAgICAgIHNsb3dNbzogdmFsaWRhdG9ycy5zbG93TW8oc3RyaWN0Q2hlY2spLFxyXG4gICAgICBkZWJ1Z2dpbmdQb3J0OiB2YWxpZGF0b3JzLmRlYnVnZ2luZ1BvcnQoc3RyaWN0Q2hlY2spXHJcbiAgICB9KVxyXG4gICAgLnBhcnRpYWwoKTtcclxuXHJcbi8vIFN0cmljdCBzY2hlbWEgZm9yIHRoZSBjb25maWdcclxuZXhwb3J0IGNvbnN0IFN0cmljdENvbmZpZ1NjaGVtYSA9IHoub2JqZWN0KHtcclxuICByZXF1ZXN0SWQ6IHZhbGlkYXRvcnMucmVxdWVzdElkKCksXHJcbiAgcHVwcGV0ZWVyOiBQdXBwZXRlZXJTY2hlbWEodHJ1ZSksXHJcbiAgaGlnaGNoYXJ0czogSGlnaGNoYXJ0c1NjaGVtYSh0cnVlKSxcclxuICBleHBvcnQ6IEV4cG9ydFNjaGVtYSh0cnVlKSxcclxuICBjdXN0b21Mb2dpYzogQ3VzdG9tTG9naWNTY2hlbWEodHJ1ZSksXHJcbiAgc2VydmVyOiBTZXJ2ZXJTY2hlbWEodHJ1ZSksXHJcbiAgcG9vbDogUG9vbFNjaGVtYSh0cnVlKSxcclxuICBsb2dnaW5nOiBMb2dnaW5nU2NoZW1hKHRydWUpLFxyXG4gIHVpOiBVaVNjaGVtYSh0cnVlKSxcclxuICBvdGhlcjogT3RoZXJTY2hlbWEodHJ1ZSksXHJcbiAgZGVidWc6IERlYnVnU2NoZW1hKHRydWUpXHJcbn0pO1xyXG5cclxuLy8gTG9vc2Ugc2NoZW1hIGZvciB0aGUgY29uZmlnXHJcbmV4cG9ydCBjb25zdCBMb29zZUNvbmZpZ1NjaGVtYSA9IHoub2JqZWN0KHtcclxuICByZXF1ZXN0SWQ6IHZhbGlkYXRvcnMucmVxdWVzdElkKCksXHJcbiAgcHVwcGV0ZWVyOiBQdXBwZXRlZXJTY2hlbWEoZmFsc2UpLFxyXG4gIGhpZ2hjaGFydHM6IEhpZ2hjaGFydHNTY2hlbWEoZmFsc2UpLFxyXG4gIGV4cG9ydDogRXhwb3J0U2NoZW1hKGZhbHNlKSxcclxuICBjdXN0b21Mb2dpYzogQ3VzdG9tTG9naWNTY2hlbWEoZmFsc2UpLFxyXG4gIHNlcnZlcjogU2VydmVyU2NoZW1hKGZhbHNlKSxcclxuICBwb29sOiBQb29sU2NoZW1hKGZhbHNlKSxcclxuICBsb2dnaW5nOiBMb2dnaW5nU2NoZW1hKGZhbHNlKSxcclxuICB1aTogVWlTY2hlbWEoZmFsc2UpLFxyXG4gIG90aGVyOiBPdGhlclNjaGVtYShmYWxzZSksXHJcbiAgZGVidWc6IERlYnVnU2NoZW1hKGZhbHNlKVxyXG59KTtcclxuXHJcbi8vIFNjaGVtYSBmb3IgdGhlIGVudmlyb25tZW50IHZhcmlhYmxlcyBjb25maWdcclxuZXhwb3J0IGNvbnN0IEVudlNjaGVtYSA9IHoub2JqZWN0KHtcclxuICAvLyBwdXBwZXRlZXJcclxuICBQVVBQRVRFRVJfQVJHUzogdmFsaWRhdG9ycy5hcmdzKGZhbHNlKSxcclxuXHJcbiAgLy8gaGlnaGNoYXJ0c1xyXG4gIEhJR0hDSEFSVFNfVkVSU0lPTjogdmFsaWRhdG9ycy52ZXJzaW9uKGZhbHNlKSxcclxuICBISUdIQ0hBUlRTX0NETl9VUkw6IHZhbGlkYXRvcnMuY2RuVXJsKGZhbHNlKSxcclxuICBISUdIQ0hBUlRTX0ZPUkNFX0ZFVENIOiB2YWxpZGF0b3JzLmZvcmNlRmV0Y2goZmFsc2UpLFxyXG4gIEhJR0hDSEFSVFNfQ0FDSEVfUEFUSDogdmFsaWRhdG9ycy5jYWNoZVBhdGgoZmFsc2UpLFxyXG4gIEhJR0hDSEFSVFNfQURNSU5fVE9LRU46IHZhbGlkYXRvcnMuYWRtaW5Ub2tlbihmYWxzZSksXHJcbiAgSElHSENIQVJUU19DT1JFX1NDUklQVFM6IHZhbGlkYXRvcnMuY29yZVNjcmlwdHMoZmFsc2UpLFxyXG4gIEhJR0hDSEFSVFNfTU9EVUxFX1NDUklQVFM6IHZhbGlkYXRvcnMubW9kdWxlU2NyaXB0cyhmYWxzZSksXHJcbiAgSElHSENIQVJUU19JTkRJQ0FUT1JfU0NSSVBUUzogdmFsaWRhdG9ycy5pbmRpY2F0b3JTY3JpcHRzKGZhbHNlKSxcclxuICBISUdIQ0hBUlRTX0NVU1RPTV9TQ1JJUFRTOiB2YWxpZGF0b3JzLmN1c3RvbVNjcmlwdHMoZmFsc2UpLFxyXG5cclxuICAvLyBleHBvcnRcclxuICBFWFBPUlRfSU5GSUxFOiB2YWxpZGF0b3JzLmluZmlsZShmYWxzZSksXHJcbiAgRVhQT1JUX0lOU1RSOiB2YWxpZGF0b3JzLmluc3RyKCksXHJcbiAgRVhQT1JUX09QVElPTlM6IHZhbGlkYXRvcnMub3B0aW9ucygpLFxyXG4gIEVYUE9SVF9TVkc6IHZhbGlkYXRvcnMuc3ZnKCksXHJcbiAgRVhQT1JUX0JBVENIOiB2YWxpZGF0b3JzLmJhdGNoKGZhbHNlKSxcclxuICBFWFBPUlRfT1VURklMRTogdmFsaWRhdG9ycy5vdXRmaWxlKGZhbHNlKSxcclxuICBFWFBPUlRfVFlQRTogdmFsaWRhdG9ycy50eXBlKGZhbHNlKSxcclxuICBFWFBPUlRfQ09OU1RSOiB2YWxpZGF0b3JzLmNvbnN0cihmYWxzZSksXHJcbiAgRVhQT1JUX0I2NDogdmFsaWRhdG9ycy5iNjQoZmFsc2UpLFxyXG4gIEVYUE9SVF9OT19ET1dOTE9BRDogdmFsaWRhdG9ycy5ub0Rvd25sb2FkKGZhbHNlKSxcclxuICBFWFBPUlRfSEVJR0hUOiB2YWxpZGF0b3JzLmhlaWdodChmYWxzZSksXHJcbiAgRVhQT1JUX1dJRFRIOiB2YWxpZGF0b3JzLndpZHRoKGZhbHNlKSxcclxuICBFWFBPUlRfU0NBTEU6IHZhbGlkYXRvcnMuc2NhbGUoZmFsc2UpLFxyXG4gIEVYUE9SVF9ERUZBVUxUX0hFSUdIVDogdmFsaWRhdG9ycy5kZWZhdWx0SGVpZ2h0KGZhbHNlKSxcclxuICBFWFBPUlRfREVGQVVMVF9XSURUSDogdmFsaWRhdG9ycy5kZWZhdWx0V2lkdGgoZmFsc2UpLFxyXG4gIEVYUE9SVF9ERUZBVUxUX1NDQUxFOiB2YWxpZGF0b3JzLmRlZmF1bHRTY2FsZShmYWxzZSksXHJcbiAgRVhQT1JUX0dMT0JBTF9PUFRJT05TOiB2YWxpZGF0b3JzLmdsb2JhbE9wdGlvbnMoKSxcclxuICBFWFBPUlRfVEhFTUVfT1BUSU9OUzogdmFsaWRhdG9ycy50aGVtZU9wdGlvbnMoKSxcclxuICBFWFBPUlRfUkFTVEVSSVpBVElPTl9USU1FT1VUOiB2YWxpZGF0b3JzLnJhc3Rlcml6YXRpb25UaW1lb3V0KGZhbHNlKSxcclxuXHJcbiAgLy8gY3VzdG9tXHJcbiAgQ1VTVE9NX0xPR0lDX0FMTE9XX0NPREVfRVhFQ1VUSU9OOiB2YWxpZGF0b3JzLmFsbG93Q29kZUV4ZWN1dGlvbihmYWxzZSksXHJcbiAgQ1VTVE9NX0xPR0lDX0FMTE9XX0ZJTEVfUkVTT1VSQ0VTOiB2YWxpZGF0b3JzLmFsbG93RmlsZVJlc291cmNlcyhmYWxzZSksXHJcbiAgQ1VTVE9NX0xPR0lDX0NVU1RPTV9DT0RFOiB2YWxpZGF0b3JzLmN1c3RvbUNvZGUoZmFsc2UpLFxyXG4gIENVU1RPTV9MT0dJQ19DQUxMQkFDSzogdmFsaWRhdG9ycy5jYWxsYmFjayhmYWxzZSksXHJcbiAgQ1VTVE9NX0xPR0lDX1JFU09VUkNFUzogdmFsaWRhdG9ycy5yZXNvdXJjZXMoZmFsc2UpLFxyXG4gIENVU1RPTV9MT0dJQ19MT0FEX0NPTkZJRzogdmFsaWRhdG9ycy5sb2FkQ29uZmlnKGZhbHNlKSxcclxuICBDVVNUT01fTE9HSUNfQ1JFQVRFX0NPTkZJRzogdmFsaWRhdG9ycy5jcmVhdGVDb25maWcoZmFsc2UpLFxyXG5cclxuICAvLyBzZXJ2ZXJcclxuICBTRVJWRVJfRU5BQkxFOiB2YWxpZGF0b3JzLmVuYWJsZVNlcnZlcihmYWxzZSksXHJcbiAgU0VSVkVSX0hPU1Q6IHZhbGlkYXRvcnMuaG9zdChmYWxzZSksXHJcbiAgU0VSVkVSX1BPUlQ6IHZhbGlkYXRvcnMucG9ydChmYWxzZSksXHJcbiAgU0VSVkVSX1VQTE9BRF9MSU1JVDogdmFsaWRhdG9ycy51cGxvYWRMaW1pdChmYWxzZSksXHJcbiAgU0VSVkVSX0JFTkNITUFSS0lORzogdmFsaWRhdG9ycy5zZXJ2ZXJCZW5jaG1hcmtpbmcoZmFsc2UpLFxyXG5cclxuICAvLyBzZXJ2ZXIgcHJveHlcclxuICBTRVJWRVJfUFJPWFlfSE9TVDogdmFsaWRhdG9ycy5wcm94eUhvc3QoZmFsc2UpLFxyXG4gIFNFUlZFUl9QUk9YWV9QT1JUOiB2YWxpZGF0b3JzLnByb3h5UG9ydChmYWxzZSksXHJcbiAgU0VSVkVSX1BST1hZX1RJTUVPVVQ6IHZhbGlkYXRvcnMucHJveHlUaW1lb3V0KGZhbHNlKSxcclxuXHJcbiAgLy8gc2VydmVyIHJhdGUgbGltaXRpbmdcclxuICBTRVJWRVJfUkFURV9MSU1JVElOR19FTkFCTEU6IHZhbGlkYXRvcnMuZW5hYmxlUmF0ZUxpbWl0aW5nKGZhbHNlKSxcclxuICBTRVJWRVJfUkFURV9MSU1JVElOR19NQVhfUkVRVUVTVFM6IHZhbGlkYXRvcnMubWF4UmVxdWVzdHMoZmFsc2UpLFxyXG4gIFNFUlZFUl9SQVRFX0xJTUlUSU5HX1dJTkRPVzogdmFsaWRhdG9ycy53aW5kb3coZmFsc2UpLFxyXG4gIFNFUlZFUl9SQVRFX0xJTUlUSU5HX0RFTEFZOiB2YWxpZGF0b3JzLmRlbGF5KGZhbHNlKSxcclxuICBTRVJWRVJfUkFURV9MSU1JVElOR19UUlVTVF9QUk9YWTogdmFsaWRhdG9ycy50cnVzdFByb3h5KGZhbHNlKSxcclxuICBTRVJWRVJfUkFURV9MSU1JVElOR19TS0lQX0tFWTogdmFsaWRhdG9ycy5za2lwS2V5KGZhbHNlKSxcclxuICBTRVJWRVJfUkFURV9MSU1JVElOR19TS0lQX1RPS0VOOiB2YWxpZGF0b3JzLnNraXBUb2tlbihmYWxzZSksXHJcblxyXG4gIC8vIHNlcnZlciBzc2xcclxuICBTRVJWRVJfU1NMX0VOQUJMRTogdmFsaWRhdG9ycy5lbmFibGVTc2woZmFsc2UpLFxyXG4gIFNFUlZFUl9TU0xfRk9SQ0U6IHZhbGlkYXRvcnMuc3NsRm9yY2UoZmFsc2UpLFxyXG4gIFNFUlZFUl9TU0xfUE9SVDogdmFsaWRhdG9ycy5zc2xQb3J0KGZhbHNlKSxcclxuICBTRVJWRVJfU1NMX0NFUlRfUEFUSDogdmFsaWRhdG9ycy5zc2xDZXJ0UGF0aChmYWxzZSksXHJcblxyXG4gIC8vIHBvb2xcclxuICBQT09MX01JTl9XT1JLRVJTOiB2YWxpZGF0b3JzLm1pbldvcmtlcnMoZmFsc2UpLFxyXG4gIFBPT0xfTUFYX1dPUktFUlM6IHZhbGlkYXRvcnMubWF4V29ya2VycyhmYWxzZSksXHJcbiAgUE9PTF9XT1JLX0xJTUlUOiB2YWxpZGF0b3JzLndvcmtMaW1pdChmYWxzZSksXHJcbiAgUE9PTF9BQ1FVSVJFX1RJTUVPVVQ6IHZhbGlkYXRvcnMuYWNxdWlyZVRpbWVvdXQoZmFsc2UpLFxyXG4gIFBPT0xfQ1JFQVRFX1RJTUVPVVQ6IHZhbGlkYXRvcnMuY3JlYXRlVGltZW91dChmYWxzZSksXHJcbiAgUE9PTF9ERVNUUk9ZX1RJTUVPVVQ6IHZhbGlkYXRvcnMuZGVzdHJveVRpbWVvdXQoZmFsc2UpLFxyXG4gIFBPT0xfSURMRV9USU1FT1VUOiB2YWxpZGF0b3JzLmlkbGVUaW1lb3V0KGZhbHNlKSxcclxuICBQT09MX0NSRUFURV9SRVRSWV9JTlRFUlZBTDogdmFsaWRhdG9ycy5jcmVhdGVSZXRyeUludGVydmFsKGZhbHNlKSxcclxuICBQT09MX1JFQVBFUl9JTlRFUlZBTDogdmFsaWRhdG9ycy5yZWFwZXJJbnRlcnZhbChmYWxzZSksXHJcbiAgUE9PTF9CRU5DSE1BUktJTkc6IHZhbGlkYXRvcnMucG9vbEJlbmNobWFya2luZyhmYWxzZSksXHJcblxyXG4gIC8vIGxvZ2dpbmdcclxuICBMT0dHSU5HX0xFVkVMOiB2YWxpZGF0b3JzLmxvZ0xldmVsKGZhbHNlKSxcclxuICBMT0dHSU5HX0ZJTEU6IHZhbGlkYXRvcnMubG9nRmlsZShmYWxzZSksXHJcbiAgTE9HR0lOR19ERVNUOiB2YWxpZGF0b3JzLmxvZ0Rlc3QoZmFsc2UpLFxyXG4gIExPR0dJTkdfVE9fQ09OU09MRTogdmFsaWRhdG9ycy5sb2dUb0NvbnNvbGUoZmFsc2UpLFxyXG4gIExPR0dJTkdfVE9fRklMRTogdmFsaWRhdG9ycy5sb2dUb0ZpbGUoZmFsc2UpLFxyXG5cclxuICAvLyB1aVxyXG4gIFVJX0VOQUJMRTogdmFsaWRhdG9ycy5lbmFibGVVaShmYWxzZSksXHJcbiAgVUlfUk9VVEU6IHZhbGlkYXRvcnMudWlSb3V0ZShmYWxzZSksXHJcblxyXG4gIC8vIG90aGVyXHJcbiAgT1RIRVJfTk9ERV9FTlY6IHZhbGlkYXRvcnMubm9kZUVudihmYWxzZSksXHJcbiAgT1RIRVJfTElTVEVOX1RPX1BST0NFU1NfRVhJVFM6IHZhbGlkYXRvcnMubGlzdGVuVG9Qcm9jZXNzRXhpdHMoZmFsc2UpLFxyXG4gIE9USEVSX05PX0xPR086IHZhbGlkYXRvcnMubm9Mb2dvKGZhbHNlKSxcclxuICBPVEhFUl9IQVJEX1JFU0VUX1BBR0U6IHZhbGlkYXRvcnMuaGFyZFJlc2V0UGFnZShmYWxzZSksXHJcbiAgT1RIRVJfQlJPV1NFUl9TSEVMTF9NT0RFOiB2YWxpZGF0b3JzLmJyb3dzZXJTaGVsbE1vZGUoZmFsc2UpLFxyXG4gIE9USEVSX1ZBTElEQVRJT046IHZhbGlkYXRvcnMudmFsaWRhdGlvbihmYWxzZSksXHJcblxyXG4gIC8vIGRlYnVnZ2VyXHJcbiAgREVCVUdfRU5BQkxFOiB2YWxpZGF0b3JzLmVuYWJsZURlYnVnKGZhbHNlKSxcclxuICBERUJVR19IRUFETEVTUzogdmFsaWRhdG9ycy5oZWFkbGVzcyhmYWxzZSksXHJcbiAgREVCVUdfREVWVE9PTFM6IHZhbGlkYXRvcnMuZGV2dG9vbHMoZmFsc2UpLFxyXG4gIERFQlVHX0xJU1RFTl9UT19DT05TT0xFOiB2YWxpZGF0b3JzLmxpc3RlblRvQ29uc29sZShmYWxzZSksXHJcbiAgREVCVUdfRFVNUElPOiB2YWxpZGF0b3JzLmR1bXBpbyhmYWxzZSksXHJcbiAgREVCVUdfU0xPV19NTzogdmFsaWRhdG9ycy5zbG93TW8oZmFsc2UpLFxyXG4gIERFQlVHX0RFQlVHR0lOR19QT1JUOiB2YWxpZGF0b3JzLmRlYnVnZ2luZ1BvcnQoZmFsc2UpXHJcbn0pO1xyXG5cclxuLyoqXHJcbiAqIFZhbGlkYXRlcyB0aGUgZW52aXJvbm1lbnQgdmFyaWFibGVzIG9wdGlvbnMgdXNpbmcgdGhlIEVudlNjaGVtYS5cclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IHByb2Nlc3MuZW52IC0gVGhlIGNvbmZpZ3VyYXRpb24gb3B0aW9ucyBmcm9tIGVudmlyb25tZW50XHJcbiAqIHZhcmlhYmxlcyBmaWxlIHRvIHZhbGlkYXRlLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7T2JqZWN0fSBUaGUgcGFyc2VkIGFuZCB2YWxpZGF0ZWQgZW52aXJvbm1lbnQgdmFyaWFibGVzLlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IGVudnMgPSBFbnZTY2hlbWEucGFydGlhbCgpLnBhcnNlKHByb2Nlc3MuZW52KTtcclxuXHJcbi8qKlxyXG4gKiBWYWxpZGF0ZXMgdGhlIGNvbmZpZ3VyYXRpb24gb3B0aW9ucyB1c2luZyB0aGUgYFN0cmljdENvbmZpZ1NjaGVtYWAuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBzdHJpY3RWYWxpZGF0ZVxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gY29uZmlnT3B0aW9ucyAtIFRoZSBjb25maWd1cmF0aW9uIG9wdGlvbnMgdG8gdmFsaWRhdGUuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtPYmplY3R9IFRoZSBwYXJzZWQgYW5kIHZhbGlkYXRlZCBjb25maWd1cmF0aW9uIG9wdGlvbnMuXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gc3RyaWN0VmFsaWRhdGUoY29uZmlnT3B0aW9ucykge1xyXG4gIHJldHVybiBTdHJpY3RDb25maWdTY2hlbWEucGFydGlhbCgpLnBhcnNlKGNvbmZpZ09wdGlvbnMpO1xyXG59XHJcblxyXG4vKipcclxuICogVmFsaWRhdGVzIHRoZSBjb25maWd1cmF0aW9uIG9wdGlvbnMgdXNpbmcgdGhlIGBMb29zZUNvbmZpZ1NjaGVtYWAuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBsb29zZVZhbGlkYXRlXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBjb25maWdPcHRpb25zIC0gVGhlIGNvbmZpZ3VyYXRpb24gb3B0aW9ucyB0byB2YWxpZGF0ZS5cclxuICpcclxuICogQHJldHVybnMge09iamVjdH0gVGhlIHBhcnNlZCBhbmQgdmFsaWRhdGVkIGNvbmZpZ3VyYXRpb24gb3B0aW9ucy5cclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiBsb29zZVZhbGlkYXRlKGNvbmZpZ09wdGlvbnMpIHtcclxuICByZXR1cm4gTG9vc2VDb25maWdTY2hlbWEucGFydGlhbCgpLnBhcnNlKGNvbmZpZ09wdGlvbnMpO1xyXG59XHJcblxyXG4vKipcclxuICogQ3VzdG9tIGVycm9yIG1hcHBpbmcgZnVuY3Rpb24gZm9yIFpvZCBzY2hlbWEgdmFsaWRhdGlvbi5cclxuICpcclxuICogVGhpcyBmdW5jdGlvbiBjdXN0b21pemVzIHRoZSBlcnJvciBtZXNzYWdlcyBwcm9kdWNlZCBieSBab2Qgc2NoZW1hXHJcbiAqIHZhbGlkYXRpb24sIHByb3ZpZGluZyBtb3JlIHNwZWNpZmljIGFuZCB1c2VyLWZyaWVuZGx5IGZlZWRiYWNrIGJhc2VkIG9uIHRoZVxyXG4gKiBpc3N1ZSB0eXBlIGFuZCBjb250ZXh0LlxyXG4gKlxyXG4gKiBUaGUgZnVuY3Rpb24gbW9kaWZpZXMgdGhlIGVycm9yIG1lc3NhZ2VzIGFzIGZvbGxvd3M6XHJcbiAqXHJcbiAqIC0gRm9yIG1pc3NpbmcgcmVxdWlyZWQgdmFsdWVzICh1bmRlZmluZWQpLCBpdCByZXR1cm5zIGEgbWVzc2FnZSBpbmRpY2F0aW5nXHJcbiAqIHRoYXQgbm8gdmFsdWUgd2FzIHByb3ZpZGVkIGZvciB0aGUgc3BlY2lmaWMgcHJvcGVydHkuXHJcbiAqXHJcbiAqIC0gRm9yIGN1c3RvbSB2YWxpZGF0aW9uIGVycm9ycywgaWYgYSBjdXN0b20gZXJyb3IgbWVzc2FnZSBpcyBwcm92aWRlZCBpbiB0aGVcclxuICogaXNzdWUgcGFyYW1ldGVycywgaXQgaW5jbHVkZXMgdGhpcyBtZXNzYWdlIGFsb25nIHdpdGggdGhlIGludmFsaWQgZGF0YVxyXG4gKiByZWNlaXZlZC5cclxuICpcclxuICogLSBGb3IgYWxsIG90aGVyIGVycm9ycywgaXQgYXBwZW5kcyBwcm9wZXJ0eS1zcGVjaWZpYyBpbmZvcm1hdGlvbiB0byB0aGVcclxuICogZGVmYXVsdCBlcnJvciBtZXNzYWdlIHByb3ZpZGVkIGJ5IFpvZC5cclxuICpcclxuICogQGZ1bmN0aW9uIF9jdXN0b21FcnJvck1hcFxyXG4gKlxyXG4gKiBAcGFyYW0ge3ouWm9kSXNzdWV9IGlzc3VlIC0gVGhlIGlzc3VlIG9iamVjdCByZXByZXNlbnRpbmcgdGhlIHZhbGlkYXRpb25cclxuICogZXJyb3IuXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBjb250ZXh0IC0gVGhlIGNvbnRleHQgb2JqZWN0IHByb3ZpZGluZyBhZGRpdGlvbmFsIGluZm9ybWF0aW9uXHJcbiAqIGFib3V0IHRoZSB2YWxpZGF0aW9uIGVycm9yLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7T2JqZWN0fSBBbiBvYmplY3QgY29udGFpbmluZyB0aGUgY3VzdG9taXplZCBlcnJvciBtZXNzYWdlLlxyXG4gKi9cclxuZnVuY3Rpb24gX2N1c3RvbUVycm9yTWFwKGlzc3VlLCBjb250ZXh0KSB7XHJcbiAgLy8gR2V0IHRoZSBjaGFpbiBvZiBwcm9wZXJ0aWVzIHdoaWNoIGVycm9yIGRpcmVjdGx5IHJlZmVycyB0b1xyXG4gIGNvbnN0IHByb3BlcnR5TmFtZSA9IGlzc3VlLnBhdGguam9pbignLicpO1xyXG5cclxuICAvLyBDcmVhdGUgdGhlIGZpcnN0IHBhcnQgb2YgdGhlIG1lc3NhZ2UgYWJvdXQgdGhlIHByb3BlcnR5IGluZm9ybWF0aW9uXHJcbiAgY29uc3QgcHJvcGVydHlJbmZvID0gYEludmFsaWQgdmFsdWUgZm9yIHRoZSAke3Byb3BlcnR5TmFtZX1gO1xyXG5cclxuICAvLyBNb2RpZmllZCBtZXNzYWdlIGZvciB0aGUgaW52YWxpZCB0eXBlXHJcbiAgaWYgKGlzc3VlLmNvZGUgPT09IHouWm9kSXNzdWVDb2RlLmludmFsaWRfdHlwZSkge1xyXG4gICAgLy8gTW9kaWZpZWQgbWVzc2FnZSBmb3IgdGhlIHJlcXVpcmVkIHZhbHVlc1xyXG4gICAgaWYgKGlzc3VlLnJlY2VpdmVkID09PSB6LlpvZFBhcnNlZFR5cGUudW5kZWZpbmVkKSB7XHJcbiAgICAgIHJldHVybiB7XHJcbiAgICAgICAgbWVzc2FnZTogYCR7cHJvcGVydHlJbmZvfSAtIE5vIHZhbHVlIHdhcyBwcm92aWRlZC5gXHJcbiAgICAgIH07XHJcbiAgICB9XHJcblxyXG4gICAgLy8gTW9kaWZpZWQgbWVzc2FnZSBmb3IgdGhlIHNwZWNpZmljIGludmFsaWQgdHlwZSB3aGVuIHZhbHVlcyBleGlzdFxyXG4gICAgcmV0dXJuIHtcclxuICAgICAgbWVzc2FnZTogYCR7cHJvcGVydHlJbmZvfSAtIEludmFsaWQgdHlwZS4gJHtjb250ZXh0LmRlZmF1bHRFcnJvcn0uYFxyXG4gICAgfTtcclxuICB9XHJcblxyXG4gIC8vIE1vZGlmaWVkIG1lc3NhZ2UgZm9yIHRoZSBjdXN0b20gdmFsaWRhdGlvblxyXG4gIGlmIChpc3N1ZS5jb2RlID09PSB6LlpvZElzc3VlQ29kZS5jdXN0b20pIHtcclxuICAgIC8vIElmIHRoZSBjdXN0b20gbWVzc2FnZSBmb3IgZXJyb3IgZXhpc3QsIGluY2x1ZGUgaXRcclxuICAgIGlmIChpc3N1ZS5wYXJhbXM/LmVycm9yTWVzc2FnZSkge1xyXG4gICAgICByZXR1cm4ge1xyXG4gICAgICAgIG1lc3NhZ2U6IGAke3Byb3BlcnR5SW5mb30gLSAke2lzc3VlLnBhcmFtcz8uZXJyb3JNZXNzYWdlfSwgcmVjZWl2ZWQgJyR7Y29udGV4dC5kYXRhfScuYFxyXG4gICAgICB9O1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgLy8gTW9kaWZpZWQgbWVzc2FnZSBmb3IgdGhlIGludmFsaWQgdW5pb24gZXJyb3JcclxuICBpZiAoaXNzdWUuY29kZSA9PT0gei5ab2RJc3N1ZUNvZGUuaW52YWxpZF91bmlvbikge1xyXG4gICAgLy8gQ3JlYXRlIHRoZSBmaXJzdCBwYXJ0IG9mIHRoZSBtZXNzYWdlIGFib3V0IHRoZSBtdWx0aXBsZSBlcnJvcnNcclxuICAgIGxldCBtZXNzYWdlID0gYE11bHRpcGxlIGVycm9ycyBvY2N1cnJlZCBmb3IgdGhlICR7cHJvcGVydHlOYW1lfTpcXG5gO1xyXG5cclxuICAgIC8vIEN5Y2xlIHRocm91Z2ggYWxsIGVycm9ycyBhbmQgY3JlYXRlIGEgY29ycmVjdCBtZXNzYWdlXHJcbiAgICBpc3N1ZS51bmlvbkVycm9ycy5mb3JFYWNoKCh2YWx1ZSkgPT4ge1xyXG4gICAgICBjb25zdCBpbmRleCA9IHZhbHVlLmlzc3Vlc1swXS5tZXNzYWdlLmluZGV4T2YoJy0nKTtcclxuICAgICAgbWVzc2FnZSArPVxyXG4gICAgICAgIGluZGV4ICE9PSAtMVxyXG4gICAgICAgICAgPyBgJHt2YWx1ZS5pc3N1ZXNbMF0ubWVzc2FnZX1cXG5gLnN1YnN0cmluZyhpbmRleClcclxuICAgICAgICAgIDogYCR7dmFsdWUuaXNzdWVzWzBdLm1lc3NhZ2V9XFxuYDtcclxuICAgIH0pO1xyXG5cclxuICAgIC8vIFJldHVybiB0aGUgZmluYWwgbWVzc2FnZSBmb3IgdGhlIGludmFsaWQgdW5pb24gZXJyb3JcclxuICAgIHJldHVybiB7XHJcbiAgICAgIG1lc3NhZ2VcclxuICAgIH07XHJcbiAgfVxyXG5cclxuICAvLyBSZXR1cm4gdGhlIGRlZmF1bHQgZXJyb3IgbWVzc2FnZSwgZXh0ZW5kZWQgYnkgdGhlIGluZm8gYWJvdXQgdGhlIHByb3BlcnR5XHJcbiAgcmV0dXJuIHtcclxuICAgIG1lc3NhZ2U6IGAke3Byb3BlcnR5SW5mb30gLSAke2NvbnRleHQuZGVmYXVsdEVycm9yfS5gXHJcbiAgfTtcclxufVxyXG5cclxuZXhwb3J0IGRlZmF1bHQge1xyXG4gIHZhbGlkYXRvcnMsXHJcbiAgU3RyaWN0Q29uZmlnU2NoZW1hLFxyXG4gIExvb3NlQ29uZmlnU2NoZW1hLFxyXG4gIEVudlNjaGVtYSxcclxuICBlbnZzLFxyXG4gIHN0cmljdFZhbGlkYXRlLFxyXG4gIGxvb3NlVmFsaWRhdGVcclxufTtcclxuIiwiLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcclxuXHJcbkhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlclxyXG5cclxuQ29weXJpZ2h0IChjKSAyMDE2LTIwMjUsIEhpZ2hzb2Z0XHJcblxyXG5MaWNlbmNlZCB1bmRlciB0aGUgTUlUIGxpY2VuY2UuXHJcblxyXG5BZGRpdGlvbmFsbHkgYSB2YWxpZCBIaWdoY2hhcnRzIGxpY2Vuc2UgaXMgcmVxdWlyZWQgZm9yIHVzZS5cclxuXHJcblNlZSBMSUNFTlNFIGZpbGUgaW4gcm9vdCBmb3IgZGV0YWlscy5cclxuXHJcbioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXHJcblxyXG4vKipcclxuICogQSBjdXN0b20gZXJyb3IgY2xhc3MgZm9yIGhhbmRsaW5nIGV4cG9ydC1yZWxhdGVkIGVycm9ycy4gRXh0ZW5kcyB0aGUgbmF0aXZlXHJcbiAqIGBFcnJvcmAgY2xhc3MgdG8gaW5jbHVkZSBhZGRpdGlvbmFsIHByb3BlcnRpZXMgbGlrZSBzdGF0dXMgY29kZSBhbmQgc3RhY2tcclxuICogdHJhY2UgZGV0YWlscy5cclxuICovXHJcbmNsYXNzIEV4cG9ydEVycm9yIGV4dGVuZHMgRXJyb3Ige1xyXG4gIC8qKlxyXG4gICAqIENyZWF0ZXMgYW4gaW5zdGFuY2Ugb2YgdGhlIGBFeHBvcnRFcnJvcmAuXHJcbiAgICpcclxuICAgKiBAcGFyYW0ge3N0cmluZ30gbWVzc2FnZSAtIFRoZSBlcnJvciBtZXNzYWdlIHRvIGJlIGRpc3BsYXllZC5cclxuICAgKiBAcGFyYW0ge251bWJlcn0gc3RhdHVzQ29kZSAtIE9wdGlvbmFsIEhUVFAgc3RhdHVzIGNvZGUgYXNzb2NpYXRlZFxyXG4gICAqIHdpdGggdGhlIGVycm9yIChlLmcuLCA0MDAsIDUwMCkuXHJcbiAgICovXHJcbiAgY29uc3RydWN0b3IobWVzc2FnZSwgc3RhdHVzQ29kZSkge1xyXG4gICAgc3VwZXIoKTtcclxuXHJcbiAgICB0aGlzLm1lc3NhZ2UgPSBtZXNzYWdlO1xyXG4gICAgdGhpcy5zdGFja01lc3NhZ2UgPSBtZXNzYWdlO1xyXG5cclxuICAgIGlmIChzdGF0dXNDb2RlKSB7XHJcbiAgICAgIHRoaXMuc3RhdHVzQ29kZSA9IHN0YXR1c0NvZGU7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICAvKipcclxuICAgKiBTZXRzIG9yIHVwZGF0ZXMgdGhlIEhUVFAgc3RhdHVzIGNvZGUgZm9yIHRoZSBlcnJvci5cclxuICAgKlxyXG4gICAqIEBwYXJhbSB7bnVtYmVyfSBzdGF0dXNDb2RlIC0gVGhlIEhUVFAgc3RhdHVzIGNvZGUgdG8gYXNzaWduIHRvIHRoZSBlcnJvci5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHtFeHBvcnRFcnJvcn0gVGhlIHVwZGF0ZWQgaW5zdGFuY2Ugb2YgdGhlIGBFeHBvcnRFcnJvcmAgY2xhc3MuXHJcbiAgICovXHJcbiAgc2V0U3RhdHVzKHN0YXR1c0NvZGUpIHtcclxuICAgIHRoaXMuc3RhdHVzQ29kZSA9IHN0YXR1c0NvZGU7XHJcblxyXG4gICAgcmV0dXJuIHRoaXM7XHJcbiAgfVxyXG5cclxuICAvKipcclxuICAgKiBTZXRzIGFkZGl0aW9uYWwgZXJyb3IgZGV0YWlscyBiYXNlZCBvbiBhbiBleGlzdGluZyBlcnJvciBvYmplY3QuXHJcbiAgICpcclxuICAgKiBAcGFyYW0ge0Vycm9yfSBlcnJvciAtIEFuIGVycm9yIG9iamVjdCBjb250YWluaW5nIGRldGFpbHMgdG8gcG9wdWxhdGVcclxuICAgKiB0aGUgYEV4cG9ydEVycm9yYCBpbnN0YW5jZS5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHtFeHBvcnRFcnJvcn0gVGhlIHVwZGF0ZWQgaW5zdGFuY2Ugb2YgdGhlIGBFeHBvcnRFcnJvcmAgY2xhc3MuXHJcbiAgICovXHJcbiAgc2V0RXJyb3IoZXJyb3IpIHtcclxuICAgIHRoaXMuZXJyb3IgPSBlcnJvcjtcclxuXHJcbiAgICBpZiAoZXJyb3IubmFtZSkge1xyXG4gICAgICB0aGlzLm5hbWUgPSBlcnJvci5uYW1lO1xyXG4gICAgfVxyXG5cclxuICAgIGlmIChlcnJvci5zdGF0dXNDb2RlKSB7XHJcbiAgICAgIHRoaXMuc3RhdHVzQ29kZSA9IGVycm9yLnN0YXR1c0NvZGU7XHJcbiAgICB9XHJcblxyXG4gICAgaWYgKGVycm9yLnN0YWNrKSB7XHJcbiAgICAgIHRoaXMuc3RhY2tNZXNzYWdlID0gZXJyb3IubWVzc2FnZTtcclxuICAgICAgdGhpcy5zdGFjayA9IGVycm9yLnN0YWNrO1xyXG4gICAgfVxyXG5cclxuICAgIHJldHVybiB0aGlzO1xyXG4gIH1cclxufVxyXG5cclxuZXhwb3J0IGRlZmF1bHQgRXhwb3J0RXJyb3I7XHJcbiIsIi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXHJcblxyXG5IaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXJcclxuXHJcbkNvcHlyaWdodCAoYykgMjAxNi0yMDI1LCBIaWdoc29mdFxyXG5cclxuTGljZW5jZWQgdW5kZXIgdGhlIE1JVCBsaWNlbmNlLlxyXG5cclxuQWRkaXRpb25hbGx5IGEgdmFsaWQgSGlnaGNoYXJ0cyBsaWNlbnNlIGlzIHJlcXVpcmVkIGZvciB1c2UuXHJcblxyXG5TZWUgTElDRU5TRSBmaWxlIGluIHJvb3QgZm9yIGRldGFpbHMuXHJcblxyXG4qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xyXG5cclxuLyoqXHJcbiAqIEBvdmVydmlldyBNYW5hZ2VzIGNvbmZpZ3VyYXRpb24gZm9yIHRoZSBIaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXIgYnkgbG9hZGluZ1xyXG4gKiBhbmQgbWVyZ2luZyBvcHRpb25zIGZyb20gbXVsdGlwbGUgc291cmNlcywgc3VjaCBhcyBkZWZhdWx0IHNldHRpbmdzLFxyXG4gKiBlbnZpcm9ubWVudCB2YXJpYWJsZXMsIHVzZXItcHJvdmlkZWQgb3B0aW9ucywgYW5kIGNvbW1hbmQtbGluZSBhcmd1bWVudHMuXHJcbiAqIEVuc3VyZXMgdGhlIGdsb2JhbCBvcHRpb25zIGFyZSB1cC10by1kYXRlIHdpdGggdGhlIGhpZ2hlc3QgcHJpb3JpdHkgdmFsdWVzLlxyXG4gKiBQcm92aWRlcyBmdW5jdGlvbnMgZm9yIGFjY2Vzc2luZyBhbmQgdXBkYXRpbmcgY29uZmlndXJhdGlvbi5cclxuICovXHJcblxyXG5pbXBvcnQgeyByZWFkRmlsZVN5bmMgfSBmcm9tICdmcyc7XHJcbmltcG9ydCB7IGpvaW4gfSBmcm9tICdwYXRoJztcclxuXHJcbmltcG9ydCB7IGxvZywgbG9nV2l0aFN0YWNrLCBsb2dab2RJc3N1ZXMgfSBmcm9tICcuL2xvZ2dlci5qcyc7XHJcbmltcG9ydCB7IF9fZGlybmFtZSwgZGVlcENvcHksIGdldEFic29sdXRlUGF0aCwgaXNPYmplY3QgfSBmcm9tICcuL3V0aWxzLmpzJztcclxuaW1wb3J0IHtcclxuICBlbnZzLFxyXG4gIGxvb3NlVmFsaWRhdGUsXHJcbiAgc3RyaWN0VmFsaWRhdGUsXHJcbiAgdmFsaWRhdG9yc1xyXG59IGZyb20gJy4vdmFsaWRhdGlvbi5qcyc7XHJcblxyXG5pbXBvcnQgeyBkZWZhdWx0Q29uZmlnLCBhYnNvbHV0ZVByb3BzLCBuZXN0ZWRQcm9wcyB9IGZyb20gJy4vc2NoZW1hcy9jb25maWcuanMnO1xyXG5cclxuaW1wb3J0IEV4cG9ydEVycm9yIGZyb20gJy4vZXJyb3JzL0V4cG9ydEVycm9yLmpzJztcclxuXHJcbi8vIFNldHMgdGhlIGdsb2JhbCBvcHRpb25zIHdpdGggaW5pdGlhbCB2YWx1ZXMgZnJvbSB0aGUgZGVmYXVsdCBjb25maWdcclxuY29uc3QgZ2xvYmFsT3B0aW9ucyA9IF9pbml0T3B0aW9ucyhkZWZhdWx0Q29uZmlnKTtcclxuXHJcbi8qKlxyXG4gKiBSZXRyaWV2ZXMgYSBjb3B5IG9mIHRoZSBnbG9iYWwgb3B0aW9ucyBvYmplY3Qgb3IgYSByZWZlcmVuY2UgdG8gdGhlIGdsb2JhbFxyXG4gKiBvcHRpb25zIG9iamVjdCwgYmFzZWQgb24gdGhlIGBnZXRDb3B5YCBmbGFnLlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gZ2V0T3B0aW9uc1xyXG4gKlxyXG4gKiBAcGFyYW0ge2Jvb2xlYW59IFtnZXRDb3B5PXRydWVdIC0gU3BlY2lmaWVzIHdoZXRoZXIgdG8gcmV0dXJuIGEgY29waWVkXHJcbiAqIG9iamVjdCBvZiB0aGUgZ2xvYmFsIG9wdGlvbnMgKGB0cnVlYCkgb3IgYSByZWZlcmVuY2UgdG8gdGhlIGdsb2JhbCBvcHRpb25zXHJcbiAqIG9iamVjdCAoYGZhbHNlYCkuIFRoZSBkZWZhdWx0IHZhbHVlIGlzIGBmYWxzZWAuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtPYmplY3R9IEEgY29weSBvZiB0aGUgZ2xvYmFsIG9wdGlvbnMgb2JqZWN0LCBvciBhIHJlZmVyZW5jZVxyXG4gKiB0byB0aGUgZ2xvYmFsIG9wdGlvbnMgb2JqZWN0LlxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIGdldE9wdGlvbnMoZ2V0Q29weSA9IHRydWUpIHtcclxuICByZXR1cm4gZ2V0Q29weSA/IGRlZXBDb3B5KGdsb2JhbE9wdGlvbnMpIDogZ2xvYmFsT3B0aW9ucztcclxufVxyXG5cclxuLyoqXHJcbiAqIFVwZGF0ZXMgZWl0aGVyIGEgY29weSBvZiB0aGUgZ2xvYmFsIG9wdGlvbnMgb2JqZWN0IG9yIGEgcmVmZXJlbmNlXHJcbiAqIHRvIHRoZSBnbG9iYWwgb3B0aW9ucyBvYmplY3QsIGRlcGVuZGluZyBvbiB0aGUgZ2V0Q29weSBmbGFnLCB1c2luZ1xyXG4gKiB0aGUgcHJvdmlkZWQgbmV3T3B0aW9ucywgd2hpY2ggbWF5IG9yIG1heSBub3QgYmUgdmFsaWRhdGVkLlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gdXBkYXRlT3B0aW9uc1xyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gbmV3T3B0aW9ucyAtIEFuIG9iamVjdCBjb250YWluaW5nIHRoZSBuZXcgb3B0aW9ucyB0byBiZVxyXG4gKiBtZXJnZWQgaW50byB0aGUgZ2xvYmFsIG9wdGlvbnMuXHJcbiAqIEBwYXJhbSB7Ym9vbGVhbn0gW2dldENvcHk9ZmFsc2VdIC0gRGV0ZXJtaW5lcyB3aGV0aGVyIHRvIG1lcmdlIHRoZSBuZXdcclxuICogb3B0aW9ucyBpbnRvIGEgY29weSBvZiB0aGUgZ2xvYmFsIG9wdGlvbnMgb2JqZWN0IChgdHJ1ZWApIG9yIGRpcmVjdGx5IGludG9cclxuICogdGhlIGdsb2JhbCBvcHRpb25zIG9iamVjdCAoYGZhbHNlYCkuIFRoZSBkZWZhdWx0IHZhbHVlIGlzIGBmYWxzZWAuXHJcbiAqIEBwYXJhbSB7Ym9vbGVhbn0gW3N0cmljdENoZWNrPXRydWVdIC0gRGV0ZXJtaW5lcyBpZiBzdHJpY3RlciB2YWxpZGF0aW9uXHJcbiAqIHNob3VsZCBiZSBhcHBsaWVkLiBUaGUgZGVmYXVsdCB2YWx1ZSBpcyBgdHJ1ZWAuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtPYmplY3R9IFRoZSB1cGRhdGVkIG9wdGlvbnMgb2JqZWN0LCBlaXRoZXIgdGhlIG1vZGlmaWVkIGdsb2JhbFxyXG4gKiBvcHRpb25zIG9yIGEgbW9kaWZpZWQgY29weSwgYmFzZWQgb24gdGhlIHZhbHVlIG9mIGBnZXRDb3B5YC5cclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiB1cGRhdGVPcHRpb25zKG5ld09wdGlvbnMsIGdldENvcHkgPSBmYWxzZSwgc3RyaWN0Q2hlY2sgPSB0cnVlKSB7XHJcbiAgLy8gTWVyZ2UgbmV3IG9wdGlvbnMgdG8gdGhlIGdsb2JhbCBvcHRpb25zIG9yIGl0cyBjb3B5IGFuZCByZXR1cm4gdGhlIHJlc3VsdFxyXG4gIHJldHVybiBfbWVyZ2VPcHRpb25zKFxyXG4gICAgLy8gRmlyc3QsIGdldCB0aGUgb3B0aW9uc1xyXG4gICAgZ2V0T3B0aW9ucyhnZXRDb3B5KSxcclxuICAgIC8vIE5leHQsIHZhbGlkYXRlIHRoZSBuZXcgb3B0aW9uc1xyXG4gICAgdmFsaWRhdGVPcHRpb25zKG5ld09wdGlvbnMsIHN0cmljdENoZWNrKVxyXG4gICk7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBVcGRhdGVzIHRoZSBnbG9iYWwgb3B0aW9ucyB3aXRoIHZhbHVlcyBwcm92aWRlZCB0aHJvdWdoIHRoZSBDTEksIGtlZXBpbmdcclxuICogdGhlIHByaW5jaXBsZSBvZiBvcHRpb25zIGxvYWQgcHJpb3JpdHkuIFRoaXMgZnVuY3Rpb24gYWNjZXB0cyBhIGBjbGlBcmdzYFxyXG4gKiBhcnJheSBjb250YWluaW5nIGFyZ3VtZW50cyBmcm9tIHRoZSBDTEksIHdoaWNoIHdpbGwgYmUgdmFsaWRhdGVkIGFuZCBhcHBsaWVkXHJcbiAqIGlmIHByb3ZpZGVkLlxyXG4gKlxyXG4gKiBUaGUgcHJpb3JpdHkgb3JkZXIgZm9yIHNldHRpbmcgdmFsdWVzIGlzOlxyXG4gKlxyXG4gKiAxLiBWYWx1ZXMgZnJvbSBhIGN1c3RvbSBKU09OIGZpbGUgKGxvYWRlZCBieSB0aGUgYC0tbG9hZENvbmZpZ2Agb3B0aW9uKS5cclxuICogMi4gVmFsdWVzIGZyb20gdGhlIGNvbW1hbmQgbGluZSBpbnRlcmZhY2UgKENMSSkuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBzZXRDbGlPcHRpb25zXHJcbiAqXHJcbiAqIEBwYXJhbSB7QXJyYXkuPHN0cmluZz59IGNsaUFyZ3MgLSBBbiBhcnJheSBvZiBjb21tYW5kIGxpbmUgYXJndW1lbnRzIHVzZWRcclxuICogZm9yIGFkZGl0aW9uYWwgY29uZmlndXJhdGlvbi5cclxuICpcclxuICogQHJldHVybnMge09iamVjdH0gVGhlIHVwZGF0ZWQgZ2xvYmFsIG9wdGlvbnMgb2JqZWN0LCByZWZsZWN0aW5nIHRoZSBtZXJnZWRcclxuICogY29uZmlndXJhdGlvbiBmcm9tIHNvdXJjZXMgcHJvdmlkZWQgdGhyb3VnaCB0aGUgQ0xJLlxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIHNldENsaU9wdGlvbnMoY2xpQXJncykge1xyXG4gIC8vIE9ubHkgZm9yIHRoZSBDTEkgdXNhZ2VcclxuICBpZiAoY2xpQXJncyAmJiBBcnJheS5pc0FycmF5KGNsaUFyZ3MpICYmIGNsaUFyZ3MubGVuZ3RoKSB7XHJcbiAgICB0cnkge1xyXG4gICAgICAvLyBHZXQgb3B0aW9ucyBmcm9tIHRoZSBjdXN0b20gSlNPTiBsb2FkZWQgdmlhIHRoZSBgLS1sb2FkQ29uZmlnYFxyXG4gICAgICBjb25zdCBjb25maWdPcHRpb25zID0gX2xvYWRDb25maWdGaWxlKGNsaUFyZ3MpO1xyXG5cclxuICAgICAgLy8gVXBkYXRlIGdsb2JhbCBvcHRpb25zIHdpdGggdmFsaWRhdGVkIHZhbHVlcyBmcm9tIHRoZSBgY29uZmlnT3B0aW9uc2BcclxuICAgICAgdXBkYXRlT3B0aW9ucyhjb25maWdPcHRpb25zKTtcclxuICAgIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICAgIGxvZygyLCAnW3ZhbGlkYXRpb25dIE5vIG9wdGlvbnMgYWRkZWQgZnJvbSB0aGUgYC0tbG9hZENvbmZpZ2Agb3B0aW9uLicpO1xyXG4gICAgfVxyXG5cclxuICAgIHRyeSB7XHJcbiAgICAgIC8vIEdldCBvcHRpb25zIGZyb20gdGhlIENMSVxyXG4gICAgICBjb25zdCBjbGlPcHRpb25zID0gX3BhaXJBcmd1bWVudFZhbHVlKG5lc3RlZFByb3BzLCBjbGlBcmdzKTtcclxuXHJcbiAgICAgIC8vIFVwZGF0ZSBnbG9iYWwgb3B0aW9ucyB3aXRoIHZhbGlkYXRlZCB2YWx1ZXMgZnJvbSB0aGUgYGNsaU9wdGlvbnNgXHJcbiAgICAgIHVwZGF0ZU9wdGlvbnMoY2xpT3B0aW9ucywgZmFsc2UsIGZhbHNlKTtcclxuICAgIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICAgIGxvZygyLCAnW3ZhbGlkYXRpb25dIE5vIG9wdGlvbnMgYWRkZWQgZnJvbSB0aGUgQ0xJIGFyZ3VtZW50cy4nKTtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIC8vIFJldHVybiByZWZlcmVuY2UgdG8gdGhlIGdsb2JhbCBvcHRpb25zXHJcbiAgcmV0dXJuIGdldE9wdGlvbnMoZmFsc2UpO1xyXG59XHJcblxyXG4vKipcclxuICogTWFwcyBvbGQtc3RydWN0dXJlZCBjb25maWd1cmF0aW9uIG9wdGlvbnMgKFBoYW50b21KUykgdG8gYSBuZXcgZm9ybWF0XHJcbiAqIChQdXBwZXRlZXIpLiBUaGlzIGZ1bmN0aW9uIGNvbnZlcnRzIGZsYXQsIG9sZC1zdHJ1Y3R1cmVkIG9wdGlvbnMgaW50b1xyXG4gKiBhIG5ldywgbmVzdGVkIGNvbmZpZ3VyYXRpb24gZm9ybWF0IGJhc2VkIG9uIGEgcHJlZGVmaW5lZCBtYXBwaW5nXHJcbiAqIChgbmVzdGVkUHJvcHNgKS4gVGhlIG5ldyBmb3JtYXQgaXMgdXNlZCBmb3IgUHVwcGV0ZWVyLCB3aGlsZSB0aGUgb2xkIGZvcm1hdFxyXG4gKiB3YXMgdXNlZCBmb3IgUGhhbnRvbUpTLlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gbWFwVG9OZXdPcHRpb25zXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBvbGRPcHRpb25zIC0gVGhlIG9sZCwgZmxhdCBjb25maWd1cmF0aW9uIG9wdGlvbnNcclxuICogdG8gYmUgY29udmVydGVkLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7T2JqZWN0fSBBIG5ldyBvYmplY3QgY29udGFpbmluZyBvcHRpb25zIHN0cnVjdHVyZWQgYWNjb3JkaW5nXHJcbiAqIHRvIHRoZSBtYXBwaW5nIGRlZmluZWQgaW4gYG5lc3RlZFByb3BzYCBvciBhbiBlbXB0eSBvYmplY3QgaWYgdGhlIHByb3ZpZGVkXHJcbiAqIGBvbGRPcHRpb25zYCBpcyBub3QgYSBjb3JyZWN0IG9iamVjdC5cclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiBtYXBUb05ld09wdGlvbnMob2xkT3B0aW9ucykge1xyXG4gIC8vIEFuIG9iamVjdCBmb3IgdGhlIG5ldyBzdHJ1Y3R1cmVkIG9wdGlvbnNcclxuICBjb25zdCBuZXdPcHRpb25zID0ge307XHJcblxyXG4gIC8vIENoZWNrIGlmIHByb3ZpZGVkIHZhbHVlIGlzIGEgY29ycmVjdCBvYmplY3RcclxuICBpZiAoaXNPYmplY3Qob2xkT3B0aW9ucykpIHtcclxuICAgIC8vIEl0ZXJhdGUgb3ZlciBlYWNoIGtleS12YWx1ZSBwYWlyIGluIHRoZSBvbGQtc3RydWN0dXJlZCBvcHRpb25zXHJcbiAgICBmb3IgKGNvbnN0IFtrZXksIHZhbHVlXSBvZiBPYmplY3QuZW50cmllcyhvbGRPcHRpb25zKSkge1xyXG4gICAgICAvLyBJZiB0aGVyZSBpcyBhIG5lc3RlZCBtYXBwaW5nLCBzcGxpdCBpdCBpbnRvIGEgcHJvcGVydGllcyBjaGFpblxyXG4gICAgICBjb25zdCBwcm9wZXJ0aWVzQ2hhaW4gPSBuZXN0ZWRQcm9wc1trZXldXHJcbiAgICAgICAgPyBuZXN0ZWRQcm9wc1trZXldLnNwbGl0KCcuJylcclxuICAgICAgICA6IFtdO1xyXG5cclxuICAgICAgLy8gSWYgaXQgaXMgdGhlIGxhc3QgcHJvcGVydHkgaW4gdGhlIGNoYWluLCBhc3NpZ24gdGhlIHZhbHVlLCBvdGhlcndpc2UsXHJcbiAgICAgIC8vIGNyZWF0ZSBvciByZXVzZSB0aGUgbmVzdGVkIG9iamVjdFxyXG4gICAgICBwcm9wZXJ0aWVzQ2hhaW4ucmVkdWNlKFxyXG4gICAgICAgIChvYmosIHByb3AsIGluZGV4KSA9PlxyXG4gICAgICAgICAgKG9ialtwcm9wXSA9XHJcbiAgICAgICAgICAgIHByb3BlcnRpZXNDaGFpbi5sZW5ndGggLSAxID09PSBpbmRleCA/IHZhbHVlIDogb2JqW3Byb3BdIHx8IHt9KSxcclxuICAgICAgICBuZXdPcHRpb25zXHJcbiAgICAgICk7XHJcbiAgICB9XHJcbiAgfSBlbHNlIHtcclxuICAgIGxvZyhcclxuICAgICAgMixcclxuICAgICAgJ1tjb25maWddIE5vIGNvcnJlY3Qgb2JqZWN0IHdpdGggb3B0aW9ucyB3YXMgcHJvdmlkZWQuIFJldHVybmluZyBhbiBlbXB0eSBhcnJheS4nXHJcbiAgICApO1xyXG4gIH1cclxuXHJcbiAgLy8gUmV0dXJuIHRoZSBuZXcsIHN0cnVjdHVyZWQgb3B0aW9ucyBvYmplY3RcclxuICByZXR1cm4gbmV3T3B0aW9ucztcclxufVxyXG5cclxuLyoqXHJcbiAqIFZhbGlkYXRlcyBhIHNwZWNpZmllZCBvcHRpb24gdXNpbmcgdGhlIGNvcnJlc3BvbmRpbmcgdmFsaWRhdG9yIGZyb20gdGhlXHJcbiAqIGNvbmZpZ3VyYXRpb24gb2JqZWN0LiBSZXR1cm5zIHRoZSBvcmlnaW5hbCBvcHRpb24gaWYgdGhlIHZhbGlkYXRpb25cclxuICogaXMgZGlzYWJsZWQgZ2xvYmFsbHkuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiB2YWxpZGF0ZU9wdGlvblxyXG4gKlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gbmFtZSAtIFRoZSBuYW1lIG9mIHRoZSBvcHRpb24gdG8gdmFsaWRhdGUuXHJcbiAqIEBwYXJhbSB7YW55fSBjb25maWdPcHRpb24gLSBUaGUgdmFsdWUgb2YgdGhlIG9wdGlvbiB0byB2YWxpZGF0ZS5cclxuICogQHBhcmFtIHtib29sZWFufSBbc3RyaWN0Q2hlY2s9dHJ1ZV0gLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb25cclxuICogc2hvdWxkIGJlIGFwcGxpZWQuIFRoZSBkZWZhdWx0IHZhbHVlIGlzIGB0cnVlYC5cclxuICpcclxuICogQHJldHVybnMge2FueX0gVGhlIHBhcnNlZCBhbmQgdmFsaWRhdGVkIHZhbHVlIG9mIHRoZSBvcHRpb24uXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gdmFsaWRhdGVPcHRpb24obmFtZSwgY29uZmlnT3B0aW9uLCBzdHJpY3RDaGVjayA9IHRydWUpIHtcclxuICAvLyBSZXR1cm4gdGhlIG9yaWdpbmFsIG9wdGlvbiBpZiB0aGUgdmFsaWRhdGlvbiBpcyBkaXNhYmxlZFxyXG4gIGlmICghZ2V0T3B0aW9ucygpLm90aGVyLnZhbGlkYXRpb24pIHtcclxuICAgIHJldHVybiBjb25maWdPcHRpb247XHJcbiAgfVxyXG5cclxuICB0cnkge1xyXG4gICAgLy8gUmV0dXJuIHZhbGlkYXRlZCBvcHRpb25cclxuICAgIHJldHVybiB2YWxpZGF0b3JzW25hbWVdKHN0cmljdENoZWNrKS5wYXJzZShjb25maWdPcHRpb24pO1xyXG4gIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICAvLyBMb2cgWm9kIGlzc3Vlc1xyXG4gICAgbG9nWm9kSXNzdWVzKFxyXG4gICAgICAxLFxyXG4gICAgICBlcnJvci5pc3N1ZXMsXHJcbiAgICAgIGBbdmFsaWRhdGlvbl0gVGhlICR7bmFtZX0gb3B0aW9uIHZhbGlkYXRpb24gZXJyb3JgXHJcbiAgICApO1xyXG5cclxuICAgIC8vIFRocm93IHZhbGlkYXRpb24gZXJyb3JcclxuICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcihcclxuICAgICAgYFt2YWxpZGF0aW9uXSBUaGUgJHtuYW1lfSBvcHRpb24gdmFsaWRhdGlvbiBlcnJvcmAsXHJcbiAgICAgIDQwMFxyXG4gICAgKTtcclxuICB9XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBWYWxpZGF0ZXMgdGhlIHByb3ZpZGVkIGNvbmZpZ3VyYXRpb24gb3B0aW9ucyBmb3IgdGhlIGV4cG9ydGluZyBwcm9jZXNzLlxyXG4gKiBSZXR1cm5zIHRoZSBvcmlnaW5hbCBvcHRpb24gaWYgdGhlIHZhbGlkYXRpb24gaXMgZGlzYWJsZWQgZ2xvYmFsbHkuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiB2YWxpZGF0ZU9wdGlvbnNcclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IGNvbmZpZ09wdGlvbnMgLSBUaGUgY29uZmlndXJhdGlvbiBvcHRpb25zIHRvIGJlIHZhbGlkYXRlZC5cclxuICogQHBhcmFtIHtib29sZWFufSBbc3RyaWN0Q2hlY2s9dHJ1ZV0gLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb25cclxuICogc2hvdWxkIGJlIGFwcGxpZWQuIFRoZSBkZWZhdWx0IHZhbHVlIGlzIGB0cnVlYC5cclxuICpcclxuICogQHJldHVybnMge09iamVjdH0gVGhlIHBhcnNlZCBhbmQgdmFsaWRhdGVkIGNvbmZpZ3VyYXRpb24gb3B0aW9ucyBvYmplY3QuXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gdmFsaWRhdGVPcHRpb25zKGNvbmZpZ09wdGlvbnMsIHN0cmljdENoZWNrID0gdHJ1ZSkge1xyXG4gIC8vIFJldHVybiB0aGUgb3JpZ2luYWwgY29uZmlnIGlmIHRoZSB2YWxpZGF0aW9uIGlzIGRpc2FibGVkXHJcbiAgaWYgKCFnZXRPcHRpb25zKCkub3RoZXIudmFsaWRhdGlvbikge1xyXG4gICAgcmV0dXJuIGNvbmZpZ09wdGlvbnM7XHJcbiAgfVxyXG5cclxuICB0cnkge1xyXG4gICAgLy8gUmV0dXJuIHZhbGlkYXRlZCBvcHRpb25zXHJcbiAgICByZXR1cm4gc3RyaWN0Q2hlY2tcclxuICAgICAgPyBzdHJpY3RWYWxpZGF0ZShjb25maWdPcHRpb25zKVxyXG4gICAgICA6IGxvb3NlVmFsaWRhdGUoY29uZmlnT3B0aW9ucyk7XHJcbiAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgIC8vIExvZyBab2QgaXNzdWVzXHJcbiAgICBsb2dab2RJc3N1ZXMoMSwgZXJyb3IuaXNzdWVzLCAnW3ZhbGlkYXRpb25dIE9wdGlvbnMgdmFsaWRhdGlvbiBlcnJvcicpO1xyXG5cclxuICAgIC8vIFRocm93IHZhbGlkYXRpb24gZXJyb3JcclxuICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcignW3ZhbGlkYXRpb25dIE9wdGlvbnMgdmFsaWRhdGlvbiBlcnJvcicsIDQwMCk7XHJcbiAgfVxyXG59XHJcblxyXG4vKipcclxuICogVmFsaWRhdGVzLCBwYXJzZXMsIGFuZCBjaGVja3MgaWYgdGhlIHByb3ZpZGVkIGNvbmZpZyBpcyBhbGxvd2VkIHNldFxyXG4gKiBvZiBvcHRpb25zLlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gaXNBbGxvd2VkQ29uZmlnXHJcbiAqXHJcbiAqIEBwYXJhbSB7dW5rbm93bn0gY29uZmlnIC0gVGhlIGNvbmZpZyB0byBiZSB2YWxpZGF0ZWQgYW5kIHBhcnNlZCBhcyBhIHNldFxyXG4gKiBvZiBvcHRpb25zLiBNdXN0IGJlIGVpdGhlciBhbiBvYmplY3Qgb3IgYSBzdHJpbmcuXHJcbiAqIEBwYXJhbSB7Ym9vbGVhbn0gW3RvU3RyaW5nPWZhbHNlXSAtIFdoZXRoZXIgdG8gcmV0dXJuIGEgc3RyaW5naWZpZWQgdmVyc2lvblxyXG4gKiBvZiB0aGUgcGFyc2VkIGNvbmZpZy4gVGhlIGRlZmF1bHQgdmFsdWUgaXMgYGZhbHNlYC5cclxuICogQHBhcmFtIHtib29sZWFufSBbYWxsb3dGdW5jdGlvbnM9ZmFsc2VdIC0gV2hldGhlciB0byBhbGxvdyBmdW5jdGlvbnNcclxuICogaW4gdGhlIHBhcnNlZCBjb25maWcuIElmIHRydWUsIGZ1bmN0aW9ucyBhcmUgcHJlc2VydmVkLiBPdGhlcndpc2UsIHdoZW5cclxuICogYSBmdW5jdGlvbiBpcyBmb3VuZCwgbnVsbCBpcyByZXR1cm5lZC4gVGhlIGRlZmF1bHQgdmFsdWUgaXMgYGZhbHNlYC5cclxuICpcclxuICogQHJldHVybnMgeyhPYmplY3R8c3RyaW5nfG51bGwpfSBSZXR1cm5zIGEgcGFyc2VkIHNldCBvZiBvcHRpb25zIG9iamVjdCxcclxuICogYSBzdHJpbmdpZmllZCBzZXQgb2Ygb3B0aW9ucyBvYmplY3QgaWYgdGhlIGB0b1N0cmluZ2AgaXMgdHJ1ZSwgYW5kIG51bGxcclxuICogaWYgdGhlIGNvbmZpZyBpcyBub3QgYSB2YWxpZCBzZXQgb2Ygb3B0aW9ucyBvciBwYXJzaW5nIGZhaWxzLlxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIGlzQWxsb3dlZENvbmZpZyhcclxuICBjb25maWcsXHJcbiAgdG9TdHJpbmcgPSBmYWxzZSxcclxuICBhbGxvd0Z1bmN0aW9ucyA9IGZhbHNlXHJcbikge1xyXG4gIHRyeSB7XHJcbiAgICAvLyBBY2NlcHQgb25seSBvYmplY3RzIGFuZCBzdHJpbmdzXHJcbiAgICBpZiAoIWlzT2JqZWN0KGNvbmZpZykgJiYgdHlwZW9mIGNvbmZpZyAhPT0gJ3N0cmluZycpIHtcclxuICAgICAgLy8gUmV0dXJuIG51bGwgaWYgYW55IG90aGVyIHR5cGVcclxuICAgICAgcmV0dXJuIG51bGw7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gR2V0IHRoZSBvYmplY3QgcmVwcmVzZW50YXRpb24gb2YgdGhlIG9yaWdpbmFsIGNvbmZpZ1xyXG4gICAgY29uc3Qgb2JqZWN0Q29uZmlnID1cclxuICAgICAgdHlwZW9mIGNvbmZpZyA9PT0gJ3N0cmluZydcclxuICAgICAgICA/IGFsbG93RnVuY3Rpb25zXHJcbiAgICAgICAgICA/IGV2YWwoYCgke2NvbmZpZ30pYClcclxuICAgICAgICAgIDogSlNPTi5wYXJzZShjb25maWcpXHJcbiAgICAgICAgOiBjb25maWc7XHJcblxyXG4gICAgLy8gUHJlc2VydmUgb3IgcmVtb3ZlIHBvdGVudGlhbCBmdW5jdGlvbnMgYmFzZWQgb24gdGhlIGBhbGxvd0Z1bmN0aW9uc2AgZmxhZ1xyXG4gICAgY29uc3Qgc3RyaW5naWZpZWRPcHRpb25zID0gX29wdGlvbnNTdHJpbmdpZnkoXHJcbiAgICAgIG9iamVjdENvbmZpZyxcclxuICAgICAgYWxsb3dGdW5jdGlvbnMsXHJcbiAgICAgIGZhbHNlXHJcbiAgICApO1xyXG5cclxuICAgIC8vIFBhcnNlIHRoZSBjb25maWcgdG8gY2hlY2sgaWYgaXQgaXMgdmFsaWQgc2V0IG9mIG9wdGlvbnNcclxuICAgIGNvbnN0IHBhcnNlZE9wdGlvbnMgPSBhbGxvd0Z1bmN0aW9uc1xyXG4gICAgICA/IEpTT04ucGFyc2UoXHJcbiAgICAgICAgICBfb3B0aW9uc1N0cmluZ2lmeShvYmplY3RDb25maWcsIGFsbG93RnVuY3Rpb25zLCB0cnVlKSxcclxuICAgICAgICAgIChfLCB2YWx1ZSkgPT5cclxuICAgICAgICAgICAgdHlwZW9mIHZhbHVlID09PSAnc3RyaW5nJyAmJiB2YWx1ZS5zdGFydHNXaXRoKCdmdW5jdGlvbicpXHJcbiAgICAgICAgICAgICAgPyBldmFsKGAoJHt2YWx1ZX0pYClcclxuICAgICAgICAgICAgICA6IHZhbHVlXHJcbiAgICAgICAgKVxyXG4gICAgICA6IEpTT04ucGFyc2Uoc3RyaW5naWZpZWRPcHRpb25zKTtcclxuXHJcbiAgICAvLyBSZXR1cm4gc3RyaW5naWZpZWQgb3Igb2JqZWN0IG9wdGlvbnMgYmFzZWQgb24gdGhlIGB0b1N0cmluZ2AgZmxhZ1xyXG4gICAgcmV0dXJuIHRvU3RyaW5nID8gc3RyaW5naWZpZWRPcHRpb25zIDogcGFyc2VkT3B0aW9ucztcclxuICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgLy8gUmV0dXJuIG51bGwgaWYgcGFyc2luZyBmYWlsc1xyXG4gICAgcmV0dXJuIG51bGw7XHJcbiAgfVxyXG59XHJcblxyXG4vKipcclxuICogUHJpbnRzIHRoZSBIaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXIgbG9nbywgdmVyc2lvbiwgYW5kIGxpY2Vuc2UgaW5mb3JtYXRpb24uXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBwcmludExpY2Vuc2VcclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiBwcmludExpY2Vuc2UoKSB7XHJcbiAgLy8gUHJpbnQgdGhlIGxvZ28gYW5kIHZlcnNpb24gaW5mb3JtYXRpb25cclxuICBwcmludFZlcnNpb24oKTtcclxuXHJcbiAgLy8gUHJpbnQgdGhlIGxpY2Vuc2UgaW5mb3JtYXRpb25cclxuICBjb25zb2xlLmxvZyhcclxuICAgICdUaGlzIHNvZnR3YXJlIHJlcXVpcmVzIGEgdmFsaWQgSGlnaGNoYXJ0cyBsaWNlbnNlIGZvciBjb21tZXJjaWFsIHVzZS5cXG4nXHJcbiAgICAgIC55ZWxsb3csXHJcbiAgICAnXFxuRm9yIGEgZnVsbCBsaXN0IG9mIENMSSBvcHRpb25zLCB0eXBlOicsXHJcbiAgICAnXFxuaGlnaGNoYXJ0cy1leHBvcnQtc2VydmVyIC0taGVscFxcbicuZ3JlZW4sXHJcbiAgICAnXFxuSWYgeW91IGRvIG5vdCBoYXZlIGEgbGljZW5zZSwgb25lIGNhbiBiZSBvYnRhaW5lZCBoZXJlOicsXHJcbiAgICAnXFxuaHR0cHM6Ly9zaG9wLmhpZ2hzb2Z0LmNvbS9cXG4nLmdyZWVuLFxyXG4gICAgJ1xcblRvIGN1c3RvbWl6ZSB5b3VyIGluc3RhbGxhdGlvbiwgcGxlYXNlIHJlZmVyIHRvIHRoZSBSRUFETUUgZmlsZSBhdDonLFxyXG4gICAgJ1xcbmh0dHBzOi8vZ2l0aHViLmNvbS9oaWdoY2hhcnRzL25vZGUtZXhwb3J0LXNlcnZlciNyZWFkbWVcXG4nLmdyZWVuXHJcbiAgKTtcclxufVxyXG5cclxuLyoqXHJcbiAqIFByaW50cyB1c2FnZSBpbmZvcm1hdGlvbiBmb3IgQ0xJIGFyZ3VtZW50cywgZGlzcGxheWluZyBhdmFpbGFibGUgb3B0aW9uc1xyXG4gKiBhbmQgdGhlaXIgZGVzY3JpcHRpb25zLiBJdCBjYW4gbGlzdCBwcm9wZXJ0aWVzIHJlY3Vyc2l2ZWx5IGlmIGNhdGVnb3JpZXNcclxuICogY29udGFpbiBuZXN0ZWQgb3B0aW9ucy5cclxuICpcclxuICogQGZ1bmN0aW9uIHByaW50VXNhZ2VcclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiBwcmludFVzYWdlKCkge1xyXG4gIC8vIERpc3BsYXkgUkVBRE1FIGFuZCBnZW5lcmFsIHVzYWdlIGluZm9ybWF0aW9uXHJcbiAgY29uc29sZS5sb2coXHJcbiAgICAnXFxuVXNhZ2Ugb2YgQ0xJIGFyZ3VtZW50czonLmJvbGQsXHJcbiAgICAnXFxuLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0nLFxyXG4gICAgYFxcbkZvciBtb3JlIGRldGFpbGVkIGluZm9ybWF0aW9uLCB2aXNpdCB0aGUgUkVBRE1FIGZpbGUgYXQ6ICR7J2h0dHBzOi8vZ2l0aHViLmNvbS9oaWdoY2hhcnRzL25vZGUtZXhwb3J0LXNlcnZlciNyZWFkbWUnLmdyZWVufS5cXG5gXHJcbiAgKTtcclxuXHJcbiAgLy8gSXRlcmF0ZSB0aHJvdWdoIGVhY2ggY2F0ZWdvcnkgaW4gdGhlIGBkZWZhdWx0Q29uZmlnYCBhbmQgZGlzcGxheSB1c2FnZSBpbmZvXHJcbiAgT2JqZWN0LmtleXMoZGVmYXVsdENvbmZpZykuZm9yRWFjaCgoY2F0ZWdvcnkpID0+IHtcclxuICAgIGNvbnNvbGUubG9nKGAke2NhdGVnb3J5LnRvVXBwZXJDYXNlKCl9YC5ib2xkLnJlZCk7XHJcbiAgICBfY3ljbGVDYXRlZ29yaWVzKGRlZmF1bHRDb25maWdbY2F0ZWdvcnldKTtcclxuICAgIGNvbnNvbGUubG9nKCcnKTtcclxuICB9KTtcclxufVxyXG5cclxuLyoqXHJcbiAqIFByaW50cyB0aGUgSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyIGxvZ28gb3IgdGV4dCB3aXRoIHRoZSB2ZXJzaW9uXHJcbiAqIGluZm9ybWF0aW9uLlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gcHJpbnRWZXJzaW9uXHJcbiAqXHJcbiAqIEBwYXJhbSB7Ym9vbGVhbn0gW25vTG9nbz1mYWxzZV0gLSBJZiB0cnVlLCBvbmx5IHByaW50cyB0ZXh0IHdpdGggdGhlIHZlcnNpb25cclxuICogaW5mb3JtYXRpb24sIHdpdGhvdXQgdGhlIGxvZ28uIFRoZSBkZWZhdWx0IHZhbHVlIGlzIGBmYWxzZWAuXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gcHJpbnRWZXJzaW9uKG5vTG9nbyA9IGZhbHNlKSB7XHJcbiAgLy8gR2V0IHBhY2thZ2UgdmVyc2lvbiBlaXRoZXIgZnJvbSBgLmVudmAgb3IgZnJvbSBgcGFja2FnZS5qc29uYFxyXG4gIGNvbnN0IHBhY2thZ2VWZXJzaW9uID0gSlNPTi5wYXJzZShcclxuICAgIHJlYWRGaWxlU3luYyhqb2luKF9fZGlybmFtZSwgJ3BhY2thZ2UuanNvbicpLCAndXRmOCcpXHJcbiAgKS52ZXJzaW9uO1xyXG5cclxuICAvLyBQcmludCB0ZXh0IG9ubHlcclxuICBpZiAobm9Mb2dvKSB7XHJcbiAgICBjb25zb2xlLmxvZyhgSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyIHYke3BhY2thZ2VWZXJzaW9ufWApO1xyXG4gIH0gZWxzZSB7XHJcbiAgICAvLyBQcmludCB0aGUgbG9nb1xyXG4gICAgY29uc29sZS5sb2coXHJcbiAgICAgIHJlYWRGaWxlU3luYyhqb2luKF9fZGlybmFtZSwgJ21zZycsICdzdGFydHVwLm1zZycpLCAndXRmOCcpLnRvU3RyaW5nKClcclxuICAgICAgICAuYm9sZC55ZWxsb3csXHJcbiAgICAgIGB2JHtwYWNrYWdlVmVyc2lvbn1cXG5gLmJvbGRcclxuICAgICk7XHJcbiAgfVxyXG59XHJcblxyXG4vKipcclxuICogSW5pdGlhbGl6ZXMgYW5kIHJldHVybnMgdGhlIGdsb2JhbCBvcHRpb25zIG9iamVjdCBiYXNlZCBvbiB0aGUgcHJvdmlkZWRcclxuICogY29uZmlndXJhdGlvbiwgc2V0dGluZyB2YWx1ZXMgZnJvbSBuZXN0ZWQgcHJvcGVydGllcyByZWN1cnNpdmVseS5cclxuICpcclxuICogVGhlIHByaW9yaXR5IG9yZGVyIGZvciBzZXR0aW5nIHZhbHVlcyBpczpcclxuICpcclxuICogMS4gVmFsdWVzIGZyb20gdGhlIGAuL2xpYi9zY2hlbWFzL2NvbmZpZy5qc2AgZmlsZSAoZGVmYXVsdHMpLlxyXG4gKiAyLiBWYWx1ZXMgZnJvbSBlbnZpcm9ubWVudCB2YXJpYWJsZXMgKHNwZWNpZmllZCBpbiB0aGUgYC5lbnZgIGZpbGUpLlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gX2luaXRPcHRpb25zXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBjb25maWcgLSBUaGUgY29uZmlndXJhdGlvbiBvYmplY3QgdXNlZCBmb3IgaW5pdGlhbGl6aW5nXHJcbiAqIHRoZSBnbG9iYWwgb3B0aW9ucy4gSXQgc2hvdWxkIGluY2x1ZGUgbmVzdGVkIHByb3BlcnRpZXMgd2l0aCBhIGB2YWx1ZWBcclxuICogYW5kIGFuIGBlbnZMaW5rYCBmb3IgbGlua2luZyB0byBlbnZpcm9ubWVudCB2YXJpYWJsZXMuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtPYmplY3R9IFRoZSBpbml0aWFsaXplZCBnbG9iYWwgb3B0aW9ucyBvYmplY3QsIHBvcHVsYXRlZCB3aXRoXHJcbiAqIHZhbHVlcyBiYXNlZCBvbiB0aGUgcHJvdmlkZWQgY29uZmlndXJhdGlvbiBhbmQgdGhlIGVzdGFibGlzaGVkIHByaW9yaXR5XHJcbiAqIG9yZGVyLlxyXG4gKi9cclxuZnVuY3Rpb24gX2luaXRPcHRpb25zKGNvbmZpZykge1xyXG4gIC8vIEluaXQgdGhlIG9iamVjdCBmb3Igb3B0aW9uc1xyXG4gIGNvbnN0IG9wdGlvbnMgPSB7fTtcclxuXHJcbiAgLy8gU3RhcnQgaW5pdGlhbGl6aW5nIHRoZSBgb3B0aW9uc2Agb2JqZWN0IHJlY3Vyc2l2ZWx5XHJcbiAgZm9yIChjb25zdCBbbmFtZSwgaXRlbV0gb2YgT2JqZWN0LmVudHJpZXMoY29uZmlnKSkge1xyXG4gICAgaWYgKE9iamVjdC5wcm90b3R5cGUuaGFzT3duUHJvcGVydHkuY2FsbChpdGVtLCAndmFsdWUnKSkge1xyXG4gICAgICAvLyBTZXQgdGhlIGNvcnJlY3QgdmFsdWUgYmFzZWQgb24gdGhlIGVzdGFibGlzaGVkIHByaW9yaXR5IG9yZGVyXHJcbiAgICAgIGlmIChlbnZzW2l0ZW0uZW52TGlua10gIT09IHVuZGVmaW5lZCAmJiBlbnZzW2l0ZW0uZW52TGlua10gIT09IG51bGwpIHtcclxuICAgICAgICAvLyBUaGUgZW52aXJvbm1lbnQgdmFyaWFibGVzIHZhbHVlXHJcbiAgICAgICAgb3B0aW9uc1tuYW1lXSA9IGVudnNbaXRlbS5lbnZMaW5rXTtcclxuICAgICAgfSBlbHNlIHtcclxuICAgICAgICAvLyBUaGUgdmFsdWUgZnJvbSB0aGUgY29uZmlnIGZpbGVcclxuICAgICAgICBvcHRpb25zW25hbWVdID0gaXRlbS52YWx1ZTtcclxuICAgICAgfVxyXG4gICAgfSBlbHNlIHtcclxuICAgICAgLy8gQ3JlYXRlIGEgc2VjdGlvbiBpbiB0aGUgb3B0aW9uc1xyXG4gICAgICBvcHRpb25zW25hbWVdID0gX2luaXRPcHRpb25zKGl0ZW0pO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgLy8gUmV0dXJuIHRoZSBjcmVhdGVkIGBvcHRpb25zYCBvYmplY3RcclxuICByZXR1cm4gb3B0aW9ucztcclxufVxyXG5cclxuLyoqXHJcbiAqIE1lcmdlcyB0d28gc2V0cyBvZiBjb25maWd1cmF0aW9uIG9wdGlvbnMsIGNvbnNpZGVyaW5nIGFic29sdXRlIHByb3BlcnRpZXMuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBfbWVyZ2VPcHRpb25zXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBvcmlnaW5hbE9wdGlvbnMgLSBPcmlnaW5hbCBjb25maWd1cmF0aW9uIG9wdGlvbnMuXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBuZXdPcHRpb25zIC0gTmV3IGNvbmZpZ3VyYXRpb24gb3B0aW9ucyB0byBiZSBtZXJnZWQuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtPYmplY3R9IE1lcmdlZCBjb25maWd1cmF0aW9uIG9wdGlvbnMuXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gX21lcmdlT3B0aW9ucyhvcmlnaW5hbE9wdGlvbnMsIG5ld09wdGlvbnMpIHtcclxuICAvLyBDaGVjayBpZiB0aGUgYG9yaWdpbmFsT3B0aW9uc2AgYW5kIGBuZXdPcHRpb25zYCBhcmUgY29ycmVjdCBvYmplY3RzXHJcbiAgaWYgKGlzT2JqZWN0KG9yaWdpbmFsT3B0aW9ucykgJiYgaXNPYmplY3QobmV3T3B0aW9ucykpIHtcclxuICAgIGZvciAoY29uc3QgW2tleSwgdmFsdWVdIG9mIE9iamVjdC5lbnRyaWVzKG5ld09wdGlvbnMpKSB7XHJcbiAgICAgIG9yaWdpbmFsT3B0aW9uc1trZXldID1cclxuICAgICAgICBpc09iamVjdCh2YWx1ZSkgJiZcclxuICAgICAgICAhYWJzb2x1dGVQcm9wcy5pbmNsdWRlcyhrZXkpICYmXHJcbiAgICAgICAgb3JpZ2luYWxPcHRpb25zW2tleV0gIT09IHVuZGVmaW5lZFxyXG4gICAgICAgICAgPyBfbWVyZ2VPcHRpb25zKG9yaWdpbmFsT3B0aW9uc1trZXldLCB2YWx1ZSlcclxuICAgICAgICAgIDogdmFsdWUgIT09IHVuZGVmaW5lZFxyXG4gICAgICAgICAgICA/IHZhbHVlXHJcbiAgICAgICAgICAgIDogb3JpZ2luYWxPcHRpb25zW2tleV0gfHwgbnVsbDtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIC8vIFJldHVybiB0aGUgb3JpZ2luYWwgKG1vZGlmaWVkIG9yIG5vdCkgb3B0aW9uc1xyXG4gIHJldHVybiBvcmlnaW5hbE9wdGlvbnM7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBDb252ZXJ0cyB0aGUgcHJvdmlkZWQgb3B0aW9ucyBvYmplY3QgdG8gYSBKU09OLWZvcm1hdHRlZCBzdHJpbmdcclxuICogd2l0aCB0aGUgb3B0aW9uIHRvIHByZXNlcnZlIGZ1bmN0aW9ucy4gSW4gb3JkZXIgZm9yIGEgZnVuY3Rpb25cclxuICogdG8gYmUgcHJlc2VydmVkLCBpdCBuZWVkcyB0byBmb2xsb3cgdGhlIGZvcm1hdCBgZnVuY3Rpb24gKC4uLikgey4uLn1gLlxyXG4gKiBTdWNoIGEgZnVuY3Rpb24gY2FuIGFsc28gYmUgc3RyaW5naWZpZWQuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBfb3B0aW9uc1N0cmluZ2lmeVxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gb3B0aW9ucyAtIFRoZSBvcHRpb25zIG9iamVjdCB0byBiZSBjb252ZXJ0ZWQgdG8gYSBzdHJpbmcuXHJcbiAqIEBwYXJhbSB7Ym9vbGVhbn0gYWxsb3dGdW5jdGlvbnMgLSBJZiBzZXQgdG8gdHJ1ZSwgZnVuY3Rpb25zIGFyZSBwcmVzZXJ2ZWRcclxuICogaW4gdGhlIG91dHB1dC4gT3RoZXJ3aXNlIGFuIGVycm9yIGlzIHRocm93bi5cclxuICogQHBhcmFtIHtib29sZWFufSBzdHJpbmdpZnlGdW5jdGlvbnMgLSBJZiBzZXQgdG8gdHJ1ZSwgZnVuY3Rpb25zIGFyZSBzYXZlZFxyXG4gKiBhcyBzdHJpbmdzLiBUaGUgYGFsbG93RnVuY3Rpb25zYCBtdXN0IGJlIHNldCB0byB0cnVlIGFzIHdlbGwgZm9yIHRoaXMgdG8gdGFrZVxyXG4gKiBhbiBlZmZlY3QuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtzdHJpbmd9IFRoZSBKU09OLWZvcm1hdHRlZCBzdHJpbmcgcmVwcmVzZW50aW5nIHRoZSBvcHRpb25zLlxyXG4gKlxyXG4gKiBAdGhyb3dzIHtFcnJvcn0gVGhyb3dzIGFuIGBFcnJvcmAgd2hlbiBmdW5jdGlvbnMgYXJlIG5vdCBhbGxvd2VkIGJ1dCBhcmVcclxuICogZm91bmQgaW4gcHJvdmlkZWQgb3B0aW9ucyBvYmplY3QuXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gX29wdGlvbnNTdHJpbmdpZnkob3B0aW9ucywgYWxsb3dGdW5jdGlvbnMsIHN0cmluZ2lmeUZ1bmN0aW9ucykge1xyXG4gIGNvbnN0IHJlcGxhY2VyQ2FsbGJhY2sgPSAoXywgdmFsdWUpID0+IHtcclxuICAgIC8vIFRyaW0gc3RyaW5nIHZhbHVlc1xyXG4gICAgaWYgKHR5cGVvZiB2YWx1ZSA9PT0gJ3N0cmluZycpIHtcclxuICAgICAgdmFsdWUgPSB2YWx1ZS50cmltKCk7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gSWYgdmFsdWUgaXMgYSBmdW5jdGlvbiBvciBzdHJpbmdpZmllZCBmdW5jdGlvblxyXG4gICAgaWYgKFxyXG4gICAgICB0eXBlb2YgdmFsdWUgPT09ICdmdW5jdGlvbicgfHxcclxuICAgICAgKHR5cGVvZiB2YWx1ZSA9PT0gJ3N0cmluZycgJiZcclxuICAgICAgICB2YWx1ZS5zdGFydHNXaXRoKCdmdW5jdGlvbicpICYmXHJcbiAgICAgICAgdmFsdWUuZW5kc1dpdGgoJ30nKSlcclxuICAgICkge1xyXG4gICAgICAvLyBJZiBhbGxvd0Z1bmN0aW9ucyBpcyBzZXQgdG8gdHJ1ZSwgcHJlc2VydmUgZnVuY3Rpb25zXHJcbiAgICAgIGlmIChhbGxvd0Z1bmN0aW9ucykge1xyXG4gICAgICAgIC8vIEJhc2VkIG9uIHRoZSBgc3RyaW5naWZ5RnVuY3Rpb25zYCBvcHRpb25zLCBzZXQgZnVuY3Rpb24gdmFsdWVzXHJcbiAgICAgICAgcmV0dXJuIHN0cmluZ2lmeUZ1bmN0aW9uc1xyXG4gICAgICAgICAgPyAvLyBBcyBzdHJpbmdpZmllZCBmdW5jdGlvbnNcclxuICAgICAgICAgICAgYFwiRVhQX0ZVTiR7KHZhbHVlICsgJycpLnJlcGxhY2VBbGwoL1xccysvZywgJyAnKX1FWFBfRlVOXCJgXHJcbiAgICAgICAgICA6IC8vIEFzIGZ1bmN0aW9uc1xyXG4gICAgICAgICAgICBgRVhQX0ZVTiR7KHZhbHVlICsgJycpLnJlcGxhY2VBbGwoL1xccysvZywgJyAnKX1FWFBfRlVOYDtcclxuICAgICAgfSBlbHNlIHtcclxuICAgICAgICAvLyBUaHJvdyBhbiBlcnJvciBvdGhlcndpc2VcclxuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoKTtcclxuICAgICAgfVxyXG4gICAgfVxyXG5cclxuICAgIC8vIEluIGFsbCBvdGhlciBjYXNlcywgc2ltcGx5IHJldHVybiB0aGUgdmFsdWVcclxuICAgIHJldHVybiB2YWx1ZTtcclxuICB9O1xyXG5cclxuICAvLyBTdHJpbmdpZnkgb3B0aW9ucyBhbmQgaWYgcmVxdWlyZWQsIHJlcGxhY2Ugc3BlY2lhbCBmdW5jdGlvbnMgbWFya3NcclxuICByZXR1cm4gSlNPTi5zdHJpbmdpZnkob3B0aW9ucywgcmVwbGFjZXJDYWxsYmFjaykucmVwbGFjZUFsbChcclxuICAgIHN0cmluZ2lmeUZ1bmN0aW9ucyA/IC9cXFxcXCJFWFBfRlVOfEVYUF9GVU5cXFxcXCIvZyA6IC9cIkVYUF9GVU58RVhQX0ZVTlwiL2csXHJcbiAgICAnJ1xyXG4gICk7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBMb2FkcyBhZGRpdGlvbmFsIGNvbmZpZ3VyYXRpb24gZnJvbSBhIHNwZWNpZmllZCBmaWxlIHByb3ZpZGVkIHZpYVxyXG4gKiB0aGUgYC0tbG9hZENvbmZpZ2Agb3B0aW9uIGluIHRoZSBjb21tYW5kLWxpbmUgYXJndW1lbnRzLlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gX2xvYWRDb25maWdGaWxlXHJcbiAqXHJcbiAqIEBwYXJhbSB7QXJyYXkuPHN0cmluZz59IGNsaUFyZ3MgLSBDb21tYW5kLWxpbmUgYXJndW1lbnRzIHRvIHNlYXJjaFxyXG4gKiBmb3IgdGhlIGAtLWxvYWRDb25maWdgIG9wdGlvbiBhbmQgdGhlIGNvcnJlc3BvbmRpbmcgZmlsZSBwYXRoLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7T2JqZWN0fSBUaGUgYWRkaXRpb25hbCBjb25maWd1cmF0aW9uIGxvYWRlZCBmcm9tIHRoZSBzcGVjaWZpZWRcclxuICogZmlsZSwgb3IgYW4gZW1wdHkgb2JqZWN0IGlmIHRoZSBmaWxlIGlzIG5vdCBmb3VuZCwgaW52YWxpZCwgb3IgYW4gZXJyb3JcclxuICogb2NjdXJzLlxyXG4gKi9cclxuZnVuY3Rpb24gX2xvYWRDb25maWdGaWxlKGNsaUFyZ3MpIHtcclxuICAvLyBHZXQgdGhlIGFsbG93IGZsYWdzIGZvciB0aGUgY3VzdG9tIGxvZ2ljIGNoZWNrXHJcbiAgY29uc3QgeyBhbGxvd0NvZGVFeGVjdXRpb24sIGFsbG93RmlsZVJlc291cmNlcyB9ID0gZ2V0T3B0aW9ucygpLmN1c3RvbUxvZ2ljO1xyXG5cclxuICAvLyBDaGVjayBpZiB0aGUgYC0tbG9hZENvbmZpZ2Agb3B0aW9uIHdhcyB1c2VkXHJcbiAgY29uc3QgY29uZmlnSW5kZXggPSBjbGlBcmdzLmZpbmRJbmRleChcclxuICAgIChhcmcpID0+IGFyZy5yZXBsYWNlKC8tL2csICcnKSA9PT0gJ2xvYWRDb25maWcnXHJcbiAgKTtcclxuXHJcbiAgLy8gR2V0IHRoZSBgLS1sb2FkQ29uZmlnYCBvcHRpb24gdmFsdWVcclxuICBjb25zdCBjb25maWdGaWxlTmFtZSA9IGNvbmZpZ0luZGV4ID4gLTEgJiYgY2xpQXJnc1tjb25maWdJbmRleCArIDFdO1xyXG5cclxuICAvLyBDaGVjayBpZiB0aGUgYC0tbG9hZENvbmZpZ2AgaXMgcHJlc2VudCBhbmQgaGFzIGEgY29ycmVjdCB2YWx1ZVxyXG4gIGlmIChjb25maWdGaWxlTmFtZSAmJiBhbGxvd0ZpbGVSZXNvdXJjZXMpIHtcclxuICAgIHRyeSB7XHJcbiAgICAgIC8vIExvYWQgYW4gb3B0aW9uYWwgY3VzdG9tIEpTT04gY29uZmlnIGZpbGVcclxuICAgICAgcmV0dXJuIGlzQWxsb3dlZENvbmZpZyhcclxuICAgICAgICByZWFkRmlsZVN5bmMoZ2V0QWJzb2x1dGVQYXRoKGNvbmZpZ0ZpbGVOYW1lKSwgJ3V0ZjgnKSxcclxuICAgICAgICBmYWxzZSxcclxuICAgICAgICBhbGxvd0NvZGVFeGVjdXRpb25cclxuICAgICAgKTtcclxuICAgIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICAgIGxvZ1dpdGhTdGFjayhcclxuICAgICAgICAyLFxyXG4gICAgICAgIGVycm9yLFxyXG4gICAgICAgIGBbY29uZmlnXSBVbmFibGUgdG8gbG9hZCB0aGUgY29uZmlndXJhdGlvbiBmcm9tIHRoZSAke2NvbmZpZ0ZpbGVOYW1lfSBmaWxlLmBcclxuICAgICAgKTtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIC8vIE5vIGFkZGl0aW9uYWwgb3B0aW9ucyB0byByZXR1cm5cclxuICByZXR1cm4ge307XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBQYXJzZXMgY29tbWFuZC1saW5lIGFyZ3VtZW50cyBhbmQgcGFpcnMgZWFjaCBhcmd1bWVudCB3aXRoIGl0cyBjb3JyZXNwb25kaW5nXHJcbiAqIG9wdGlvbiBpbiB0aGUgY29uZmlndXJhdGlvbi4gVGhlIHZhbHVlcyBhcmUgc3RydWN0dXJlZCBpbnRvIGEgbmVzdGVkIG9wdGlvbnNcclxuICogb2JqZWN0LCBiYXNlZCBvbiBwcmVkZWZpbmVkIG1hcHBpbmdzLlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gX3BhaXJBcmd1bWVudFZhbHVlXHJcbiAqXHJcbiAqIEBwYXJhbSB7QXJyYXkuPHN0cmluZz59IG5lc3RlZFByb3BzIC0gQW4gYXJyYXkgb2YgbmVzdGluZyBsZXZlbCBmb3IgYWxsXHJcbiAqIG9wdGlvbnMuXHJcbiAqIEBwYXJhbSB7QXJyYXkuPHN0cmluZz59IGNsaUFyZ3MgLSBBbiBhcnJheSBvZiBjb21tYW5kLWxpbmUgYXJndW1lbnRzXHJcbiAqIGNvbnRhaW5pbmcgb3B0aW9ucyBhbmQgdGhlaXIgYXNzb2NpYXRlZCB2YWx1ZXMuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtPYmplY3R9IEFuIHVwZGF0ZWQgb3B0aW9ucyBvYmplY3Qgd2hlcmUgZWFjaCBvcHRpb24gZnJvbVxyXG4gKiB0aGUgY29tbWFuZC1saW5lIGlzIHBhaXJlZCB3aXRoIGl0cyB2YWx1ZSwgc3RydWN0dXJlZCBpbnRvIG5lc3RlZCBvYmplY3RzXHJcbiAqIGFzIGRlZmluZWQuXHJcbiAqL1xyXG5mdW5jdGlvbiBfcGFpckFyZ3VtZW50VmFsdWUobmVzdGVkUHJvcHMsIGNsaUFyZ3MpIHtcclxuICAvLyBBbiBlbXB0eSBvYmplY3QgdG8gY29sbGVjdCBhbmQgc3RydWN0dXJpemUgZGF0YSBmcm9tIHRoZSBhcmdzXHJcbiAgY29uc3QgY2xpT3B0aW9ucyA9IHt9O1xyXG5cclxuICAvLyBDeWNsZSB0aHJvdWdoIGFsbCBDTEkgYXJncyBhbmQgZmlsdGVyIHRoZW1cclxuICBmb3IgKGxldCBpID0gMDsgaSA8IGNsaUFyZ3MubGVuZ3RoOyBpKyspIHtcclxuICAgIGNvbnN0IG9wdGlvbiA9IGNsaUFyZ3NbaV0ucmVwbGFjZSgvLS9nLCAnJyk7XHJcblxyXG4gICAgLy8gRmluZCB0aGUgcmlnaHQgcGxhY2UgZm9yIHByb3BlcnR5J3MgdmFsdWVcclxuICAgIGNvbnN0IHByb3BlcnRpZXNDaGFpbiA9IG5lc3RlZFByb3BzW29wdGlvbl1cclxuICAgICAgPyBuZXN0ZWRQcm9wc1tvcHRpb25dLnNwbGl0KCcuJylcclxuICAgICAgOiBbXTtcclxuXHJcbiAgICAvLyBDcmVhdGUgb3B0aW9ucyBvYmplY3Qgd2l0aCB2YWx1ZXMgZnJvbSBDTEkgZm9yIGxhdGVyIHBhcnNpbmcgYW5kIG1lcmdpbmdcclxuICAgIHByb3BlcnRpZXNDaGFpbi5yZWR1Y2UoKG9iaiwgcHJvcCwgaW5kZXgpID0+IHtcclxuICAgICAgaWYgKHByb3BlcnRpZXNDaGFpbi5sZW5ndGggLSAxID09PSBpbmRleCkge1xyXG4gICAgICAgIGNvbnN0IHZhbHVlID0gY2xpQXJnc1srK2ldO1xyXG4gICAgICAgIGlmICghdmFsdWUpIHtcclxuICAgICAgICAgIGxvZyhcclxuICAgICAgICAgICAgMixcclxuICAgICAgICAgICAgYFtjb25maWddIE1pc3NpbmcgdmFsdWUgZm9yIHRoZSBDTEkgJy0tJHtvcHRpb259JyBhcmd1bWVudC4gVXNpbmcgdGhlIGRlZmF1bHQgdmFsdWUuYFxyXG4gICAgICAgICAgKTtcclxuICAgICAgICB9XHJcbiAgICAgICAgb2JqW3Byb3BdID0gdmFsdWUgfHwgbnVsbDtcclxuICAgICAgfSBlbHNlIGlmIChvYmpbcHJvcF0gPT09IHVuZGVmaW5lZCkge1xyXG4gICAgICAgIG9ialtwcm9wXSA9IHt9O1xyXG4gICAgICB9XHJcbiAgICAgIHJldHVybiBvYmpbcHJvcF07XHJcbiAgICB9LCBjbGlPcHRpb25zKTtcclxuICB9XHJcblxyXG4gIC8vIFJldHVybiBwYXJzZWQgQ0xJIG9wdGlvbnNcclxuICByZXR1cm4gY2xpT3B0aW9ucztcclxufVxyXG5cclxuLyoqXHJcbiAqIFJlY3Vyc2l2ZWx5IHRyYXZlcnNlcyB0aGUgb3B0aW9ucyBvYmplY3QgdG8gcHJpbnQgdGhlIHVzYWdlIGluZm9ybWF0aW9uXHJcbiAqIGZvciBlYWNoIG9wdGlvbiBjYXRlZ29yeSBhbmQgaW5kaXZpZHVhbCBvcHRpb24uXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBfY3ljbGVDYXRlZ29yaWVzXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBvcHRpb25zIC0gVGhlIG9wdGlvbnMgb2JqZWN0IGNvbnRhaW5pbmcgQ0xJIG9wdGlvbnMuIEl0IG1heVxyXG4gKiBpbmNsdWRlIG5lc3RlZCBjYXRlZ29yaWVzIGFuZCBpbmRpdmlkdWFsIG9wdGlvbnMuXHJcbiAqL1xyXG5mdW5jdGlvbiBfY3ljbGVDYXRlZ29yaWVzKG9wdGlvbnMpIHtcclxuICBmb3IgKGNvbnN0IFtuYW1lLCBvcHRpb25dIG9mIE9iamVjdC5lbnRyaWVzKG9wdGlvbnMpKSB7XHJcbiAgICAvLyBJZiB0aGUgY3VycmVudCBlbnRyeSBpcyBhIGNhdGVnb3J5IGFuZCBub3QgYSBsZWFmIG9wdGlvbiwgcmVjdXJzZSBpbnRvIGl0XHJcbiAgICBpZiAoIU9iamVjdC5wcm90b3R5cGUuaGFzT3duUHJvcGVydHkuY2FsbChvcHRpb24sICd2YWx1ZScpKSB7XHJcbiAgICAgIF9jeWNsZUNhdGVnb3JpZXMob3B0aW9uKTtcclxuICAgIH0gZWxzZSB7XHJcbiAgICAgIC8vIFByZXBhcmUgZGVzY3JpcHRpb25cclxuICAgICAgY29uc3QgZGVzY05hbWUgPSBgIC0tJHtvcHRpb24uY2xpTmFtZSB8fCBuYW1lfWA7XHJcblxyXG4gICAgICAvLyBHZXQgdGhlIHZhbHVlXHJcbiAgICAgIGxldCBvcHRpb25WYWx1ZSA9IG9wdGlvbi52YWx1ZTtcclxuXHJcbiAgICAgIC8vIFByZXBhcmUgdmFsdWUgZm9yIG9wdGlvbiB0aGF0IGlzIG5vdCBudWxsIGFuZCBpcyBhcnJheSBvZiBzdHJpbmdzXHJcbiAgICAgIGlmIChvcHRpb25WYWx1ZSAhPT0gbnVsbCAmJiBvcHRpb24udHlwZXMuaW5jbHVkZXMoJ3N0cmluZ1tdJykpIHtcclxuICAgICAgICBvcHRpb25WYWx1ZSA9XHJcbiAgICAgICAgICAnWycgKyBvcHRpb25WYWx1ZS5tYXAoKGl0ZW0pID0+IGAnJHtpdGVtfSdgKS5qb2luKCcsICcpICsgJ10nO1xyXG4gICAgICB9XHJcblxyXG4gICAgICAvLyBQcmVwYXJlIHZhbHVlIGZvciBvcHRpb24gdGhhdCBpcyBub3QgbnVsbCBhbmQgaXMgYSBzdHJpbmdcclxuICAgICAgaWYgKG9wdGlvblZhbHVlICE9PSBudWxsICYmIG9wdGlvbi50eXBlcy5pbmNsdWRlcygnc3RyaW5nJykpIHtcclxuICAgICAgICBvcHRpb25WYWx1ZSA9IGAnJHtvcHRpb25WYWx1ZX0nYDtcclxuICAgICAgfVxyXG5cclxuICAgICAgLy8gRGlzcGxheSBjb3JyZWN0bHkgYWxpZ25lZCBtZXNzYWdlc1xyXG4gICAgICBjb25zb2xlLmxvZyhcclxuICAgICAgICBkZXNjTmFtZS5ncmVlbixcclxuICAgICAgICBgJHsoJzwnICsgb3B0aW9uLnR5cGVzLmpvaW4oJ3wnKSArICc+JykueWVsbG93fWAsXHJcbiAgICAgICAgYCR7U3RyaW5nKG9wdGlvblZhbHVlKS5ib2xkfWAuYmx1ZSxcclxuICAgICAgICBgLSAke29wdGlvbi5kZXNjcmlwdGlvbn0uYFxyXG4gICAgICApO1xyXG4gICAgfVxyXG4gIH1cclxufVxyXG5cclxuZXhwb3J0IGRlZmF1bHQge1xyXG4gIGdldE9wdGlvbnMsXHJcbiAgdXBkYXRlT3B0aW9ucyxcclxuICBzZXRDbGlPcHRpb25zLFxyXG4gIG1hcFRvTmV3T3B0aW9ucyxcclxuICB2YWxpZGF0ZU9wdGlvbixcclxuICB2YWxpZGF0ZU9wdGlvbnMsXHJcbiAgaXNBbGxvd2VkQ29uZmlnLFxyXG4gIHByaW50TGljZW5zZSxcclxuICBwcmludFVzYWdlLFxyXG4gIHByaW50VmVyc2lvblxyXG59O1xyXG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxyXG5cclxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXHJcblxyXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNSwgSGlnaHNvZnRcclxuXHJcbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cclxuXHJcbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxyXG5cclxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxyXG5cclxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cclxuXHJcbi8qKlxyXG4gKiBAb3ZlcnZpZXcgSFRUUCB1dGlsaXR5IG1vZHVsZSBmb3IgZmV0Y2hpbmcgYW5kIHBvc3RpbmcgZGF0YS4gU3VwcG9ydHMgYm90aFxyXG4gKiBIVFRQIGFuZCBIVFRQUyBwcm90b2NvbHMsIHByb3ZpZGluZyBtZXRob2RzIHRvIG1ha2UgR0VUIGFuZCBQT1NUIHJlcXVlc3RzXHJcbiAqIHdpdGggY3VzdG9taXphYmxlIG9wdGlvbnMuIEluY2x1ZGVzIHByb3RvY29sIGRldGVybWluYXRpb24gYmFzZWQgb24gVVJMXHJcbiAqIGFuZCBhdWdtZW50cyByZXNwb25zZSBvYmplY3RzIHdpdGggYSAndGV4dCcgcHJvcGVydHkgZm9yIGVhc2llciBkYXRhIGFjY2Vzcy5cclxuICovXHJcblxyXG5pbXBvcnQgaHR0cCBmcm9tICdodHRwJztcclxuaW1wb3J0IGh0dHBzIGZyb20gJ2h0dHBzJztcclxuXHJcbi8qKlxyXG4gKiBGZXRjaGVzIGRhdGEgZnJvbSB0aGUgc3BlY2lmaWVkIFVSTCB1c2luZyBlaXRoZXIgSFRUUCBvciBIVFRQUyBwcm90b2NvbC5cclxuICpcclxuICogQGFzeW5jXHJcbiAqIEBmdW5jdGlvbiBmZXRjaFxyXG4gKlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gdXJsIC0gVGhlIFVSTCB0byBmZXRjaCBkYXRhIGZyb20uXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBbcmVxdWVzdE9wdGlvbnM9e31dIC0gT3B0aW9ucyBmb3IgdGhlIEhUVFAvSFRUUFMgcmVxdWVzdC5cclxuICogVGhlIGRlZmF1bHQgdmFsdWUgaXMgYW4gZW1wdHkgb2JqZWN0LlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7UHJvbWlzZTxPYmplY3Q+fSBBIFByb21pc2UgdGhhdCByZXNvbHZlcyB0byB0aGUgSFRUUC9IVFRQUyByZXNwb25zZVxyXG4gKiBvYmplY3Qgd2l0aCBhZGRlZCAndGV4dCcgcHJvcGVydHkgb3IgcmVqZWN0aW5nIHdpdGggYW4gZXJyb3IuXHJcbiAqL1xyXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gZmV0Y2godXJsLCByZXF1ZXN0T3B0aW9ucyA9IHt9KSB7XHJcbiAgcmV0dXJuIG5ldyBQcm9taXNlKChyZXNvbHZlLCByZWplY3QpID0+IHtcclxuICAgIF9nZXRQcm90b2NvbE1vZHVsZSh1cmwpXHJcbiAgICAgIC5nZXQodXJsLCByZXF1ZXN0T3B0aW9ucywgKHJlc3BvbnNlKSA9PiB7XHJcbiAgICAgICAgbGV0IHJlc3BvbnNlRGF0YSA9ICcnO1xyXG5cclxuICAgICAgICAvLyBBIGNodW5rIG9mIGRhdGEgaGFzIGJlZW4gcmVjZWl2ZWRcclxuICAgICAgICByZXNwb25zZS5vbignZGF0YScsIChjaHVuaykgPT4ge1xyXG4gICAgICAgICAgcmVzcG9uc2VEYXRhICs9IGNodW5rO1xyXG4gICAgICAgIH0pO1xyXG5cclxuICAgICAgICAvLyBUaGUgd2hvbGUgcmVzcG9uc2UgaGFzIGJlZW4gcmVjZWl2ZWRcclxuICAgICAgICByZXNwb25zZS5vbignZW5kJywgKCkgPT4ge1xyXG4gICAgICAgICAgaWYgKCFyZXNwb25zZURhdGEpIHtcclxuICAgICAgICAgICAgcmVqZWN0KCdOb3RoaW5nIHdhcyBmZXRjaGVkIGZyb20gdGhlIFVSTC4nKTtcclxuICAgICAgICAgIH1cclxuICAgICAgICAgIHJlc3BvbnNlLnRleHQgPSByZXNwb25zZURhdGE7XHJcbiAgICAgICAgICByZXNvbHZlKHJlc3BvbnNlKTtcclxuICAgICAgICB9KTtcclxuICAgICAgfSlcclxuICAgICAgLm9uKCdlcnJvcicsIChlcnJvcikgPT4ge1xyXG4gICAgICAgIHJlamVjdChlcnJvcik7XHJcbiAgICAgIH0pO1xyXG4gIH0pO1xyXG59XHJcblxyXG4vKipcclxuICogU2VuZHMgYSBQT1NUIHJlcXVlc3QgdG8gdGhlIHNwZWNpZmllZCBVUkwgd2l0aCB0aGUgcHJvdmlkZWQgSlNPTiBib2R5IHVzaW5nXHJcbiAqIGVpdGhlciBIVFRQIG9yIEhUVFBTIHByb3RvY29sLlxyXG4gKlxyXG4gKiBAYXN5bmNcclxuICogQGZ1bmN0aW9uIHBvc3RcclxuICpcclxuICogQHBhcmFtIHtzdHJpbmd9IHVybCAtIFRoZSBVUkwgdG8gc2VuZCB0aGUgUE9TVCByZXF1ZXN0IHRvLlxyXG4gKiBAcGFyYW0ge09iamVjdH0gW2JvZHk9e31dIC0gVGhlIEpTT04gYm9keSB0byBpbmNsdWRlIGluIHRoZSBQT1NUIHJlcXVlc3QuXHJcbiAqIFRoZSBkZWZhdWx0IHZhbHVlIGlzIGFuIGVtcHR5IG9iamVjdC5cclxuICogQHBhcmFtIHtPYmplY3R9IFtyZXF1ZXN0T3B0aW9ucz17fV0gLSBPcHRpb25zIGZvciB0aGUgSFRUUC9IVFRQUyByZXF1ZXN0LlxyXG4gKiBUaGUgZGVmYXVsdCB2YWx1ZSBpcyBhbiBlbXB0eSBvYmplY3QuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtQcm9taXNlPE9iamVjdD59IEEgUHJvbWlzZSB0aGF0IHJlc29sdmVzIHRvIHRoZSBIVFRQL0hUVFBTIHJlc3BvbnNlXHJcbiAqIG9iamVjdCB3aXRoIGFkZGVkICd0ZXh0JyBwcm9wZXJ0eSBvciByZWplY3Rpbmcgd2l0aCBhbiBlcnJvci5cclxuICovXHJcbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBwb3N0KHVybCwgYm9keSA9IHt9LCByZXF1ZXN0T3B0aW9ucyA9IHt9KSB7XHJcbiAgcmV0dXJuIG5ldyBQcm9taXNlKChyZXNvbHZlLCByZWplY3QpID0+IHtcclxuICAgIGNvbnN0IGRhdGEgPSBKU09OLnN0cmluZ2lmeShib2R5KTtcclxuXHJcbiAgICAvLyBTZXQgZGVmYXVsdCBoZWFkZXJzIGFuZCBtZXJnZSB3aXRoIHJlcXVlc3RPcHRpb25zXHJcbiAgICBjb25zdCBvcHRpb25zID0gT2JqZWN0LmFzc2lnbihcclxuICAgICAge1xyXG4gICAgICAgIG1ldGhvZDogJ1BPU1QnLFxyXG4gICAgICAgIGhlYWRlcnM6IHtcclxuICAgICAgICAgICdDb250ZW50LVR5cGUnOiAnYXBwbGljYXRpb24vanNvbicsXHJcbiAgICAgICAgICAnQ29udGVudC1MZW5ndGgnOiBkYXRhLmxlbmd0aFxyXG4gICAgICAgIH1cclxuICAgICAgfSxcclxuICAgICAgcmVxdWVzdE9wdGlvbnNcclxuICAgICk7XHJcblxyXG4gICAgY29uc3QgcmVxdWVzdCA9IF9nZXRQcm90b2NvbE1vZHVsZSh1cmwpXHJcbiAgICAgIC5yZXF1ZXN0KHVybCwgb3B0aW9ucywgKHJlc3BvbnNlKSA9PiB7XHJcbiAgICAgICAgbGV0IHJlc3BvbnNlRGF0YSA9ICcnO1xyXG5cclxuICAgICAgICAvLyBBIGNodW5rIG9mIGRhdGEgaGFzIGJlZW4gcmVjZWl2ZWRcclxuICAgICAgICByZXNwb25zZS5vbignZGF0YScsIChjaHVuaykgPT4ge1xyXG4gICAgICAgICAgcmVzcG9uc2VEYXRhICs9IGNodW5rO1xyXG4gICAgICAgIH0pO1xyXG5cclxuICAgICAgICAvLyBUaGUgd2hvbGUgcmVzcG9uc2UgaGFzIGJlZW4gcmVjZWl2ZWRcclxuICAgICAgICByZXNwb25zZS5vbignZW5kJywgKCkgPT4ge1xyXG4gICAgICAgICAgdHJ5IHtcclxuICAgICAgICAgICAgcmVzcG9uc2UudGV4dCA9IHJlc3BvbnNlRGF0YTtcclxuICAgICAgICAgICAgcmVzb2x2ZShyZXNwb25zZSk7XHJcbiAgICAgICAgICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgICAgICAgICByZWplY3QoZXJyb3IpO1xyXG4gICAgICAgICAgfVxyXG4gICAgICAgIH0pO1xyXG4gICAgICB9KVxyXG4gICAgICAub24oJ2Vycm9yJywgKGVycm9yKSA9PiB7XHJcbiAgICAgICAgcmVqZWN0KGVycm9yKTtcclxuICAgICAgfSk7XHJcblxyXG4gICAgLy8gV3JpdGUgdGhlIHJlcXVlc3QgYm9keSBhbmQgZW5kIHRoZSByZXF1ZXN0XHJcbiAgICByZXF1ZXN0LndyaXRlKGRhdGEpO1xyXG4gICAgcmVxdWVzdC5lbmQoKTtcclxuICB9KTtcclxufVxyXG5cclxuLyoqXHJcbiAqIFJldHVybnMgdGhlIEhUVFAgb3IgSFRUUFMgcHJvdG9jb2wgbW9kdWxlIGJhc2VkIG9uIHRoZSBwcm92aWRlZCBVUkwuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBfZ2V0UHJvdG9jb2xNb2R1bGVcclxuICpcclxuICogQHBhcmFtIHtzdHJpbmd9IHVybCAtIFRoZSBVUkwgdG8gZGV0ZXJtaW5lIHRoZSBwcm90b2NvbC5cclxuICpcclxuICogQHJldHVybnMge09iamVjdH0gVGhlIEhUVFAgb3IgSFRUUFMgcHJvdG9jb2wgbW9kdWxlIChodHRwIG9yIGh0dHBzKS5cclxuICovXHJcbmZ1bmN0aW9uIF9nZXRQcm90b2NvbE1vZHVsZSh1cmwpIHtcclxuICByZXR1cm4gdXJsLnN0YXJ0c1dpdGgoJ2h0dHBzJykgPyBodHRwcyA6IGh0dHA7XHJcbn1cclxuXHJcbmV4cG9ydCBkZWZhdWx0IHtcclxuICBmZXRjaCxcclxuICBwb3N0XHJcbn07XHJcbiIsIi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXHJcblxyXG5IaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXJcclxuXHJcbkNvcHlyaWdodCAoYykgMjAxNi0yMDI1LCBIaWdoc29mdFxyXG5cclxuTGljZW5jZWQgdW5kZXIgdGhlIE1JVCBsaWNlbmNlLlxyXG5cclxuQWRkaXRpb25hbGx5IGEgdmFsaWQgSGlnaGNoYXJ0cyBsaWNlbnNlIGlzIHJlcXVpcmVkIGZvciB1c2UuXHJcblxyXG5TZWUgTElDRU5TRSBmaWxlIGluIHJvb3QgZm9yIGRldGFpbHMuXHJcblxyXG4qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xyXG5cclxuLyoqXHJcbiAqIEBvdmVydmlldyBUaGUgY2FjaGUgbWFuYWdlciBpcyByZXNwb25zaWJsZSBmb3IgaGFuZGxpbmcgYW5kIG1hbmFnaW5nXHJcbiAqIHRoZSBIaWdoY2hhcnRzIGxpYnJhcnkgYWxvbmcgd2l0aCBpdHMgZGVwZW5kZW5jaWVzLiBJdCBlbnN1cmVzIHRoYXQgdGhlc2VcclxuICogcmVzb3VyY2VzIGFyZSBzdG9yZWQgYW5kIHJldHJpZXZlZCBlZmZpY2llbnRseSB0byBvcHRpbWl6ZSBwZXJmb3JtYW5jZVxyXG4gKiBhbmQgcmVkdWNlIHJlZHVuZGFudCBuZXR3b3JrIHJlcXVlc3RzLiBUaGUgY2FjaGUgaXMgc3RvcmVkIGluIHRoZSBgLmNhY2hlYFxyXG4gKiBkaXJlY3RvcnkgYnkgZGVmYXVsdCwgd2hpY2ggc2VydmVzIGFzIGEgZGVkaWNhdGVkIGZvbGRlciBmb3Iga2VlcGluZyBjYWNoZWRcclxuICogZmlsZXMuXHJcbiAqL1xyXG5cclxuaW1wb3J0IHsgZXhpc3RzU3luYywgbWtkaXJTeW5jLCByZWFkRmlsZVN5bmMsIHdyaXRlRmlsZVN5bmMgfSBmcm9tICdmcyc7XHJcbmltcG9ydCB7IGpvaW4gfSBmcm9tICdwYXRoJztcclxuXHJcbmltcG9ydCB7IEh0dHBzUHJveHlBZ2VudCB9IGZyb20gJ2h0dHBzLXByb3h5LWFnZW50JztcclxuXHJcbmltcG9ydCB7IGdldE9wdGlvbnMsIHVwZGF0ZU9wdGlvbnMgfSBmcm9tICcuL2NvbmZpZy5qcyc7XHJcbmltcG9ydCB7IGZldGNoIH0gZnJvbSAnLi9mZXRjaC5qcyc7XHJcbmltcG9ydCB7IGxvZyB9IGZyb20gJy4vbG9nZ2VyLmpzJztcclxuaW1wb3J0IHsgZ2V0QWJzb2x1dGVQYXRoIH0gZnJvbSAnLi91dGlscy5qcyc7XHJcblxyXG5pbXBvcnQgRXhwb3J0RXJyb3IgZnJvbSAnLi9lcnJvcnMvRXhwb3J0RXJyb3IuanMnO1xyXG5cclxuLy8gVGhlIGluaXRpYWwgY2FjaGUgdGVtcGxhdGVcclxuY29uc3QgY2FjaGUgPSB7XHJcbiAgY2RuVXJsOiAnaHR0cHM6Ly9jb2RlLmhpZ2hjaGFydHMuY29tJyxcclxuICBhY3RpdmVNYW5pZmVzdDoge30sXHJcbiAgc291cmNlczogJycsXHJcbiAgaGNWZXJzaW9uOiAnJ1xyXG59O1xyXG5cclxuLyoqXHJcbiAqIENoZWNrcyB0aGUgY2FjaGUgZm9yIEhpZ2hjaGFydHMgZGVwZW5kZW5jaWVzLCB1cGRhdGVzIHRoZSBjYWNoZSBpZiBuZWVkZWQsXHJcbiAqIGFuZCBsb2FkcyB0aGUgc291cmNlcy5cclxuICpcclxuICogQGFzeW5jXHJcbiAqIEBmdW5jdGlvbiBjaGVja0FuZFVwZGF0ZUNhY2hlXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBoaWdoY2hhcnRzT3B0aW9ucyAtIFRoZSBjb25maWd1cmF0aW9uIG9iamVjdCBjb250YWluaW5nXHJcbiAqIGBoaWdoY2hhcnRzYCBvcHRpb25zLlxyXG4gKiBAcGFyYW0ge09iamVjdH0gc2VydmVyUHJveHlPcHRpb25zLSBUaGUgY29uZmlndXJhdGlvbiBvYmplY3QgY29udGFpbmluZ1xyXG4gKiBgc2VydmVyLnByb3h5YCBvcHRpb25zLlxyXG4gKi9cclxuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIGNoZWNrQW5kVXBkYXRlQ2FjaGUoXHJcbiAgaGlnaGNoYXJ0c09wdGlvbnMsXHJcbiAgc2VydmVyUHJveHlPcHRpb25zXHJcbikge1xyXG4gIHRyeSB7XHJcbiAgICBsZXQgZmV0Y2hlZE1vZHVsZXM7XHJcblxyXG4gICAgLy8gR2V0IHRoZSBjYWNoZSBwYXRoXHJcbiAgICBjb25zdCBjYWNoZVBhdGggPSBnZXRDYWNoZVBhdGgoKTtcclxuXHJcbiAgICAvLyBQcmVwYXJlIHBhdGhzIHRvIG1hbmlmZXN0IGFuZCBzb3VyY2VzIGZyb20gdGhlIGNhY2hlIGZvbGRlclxyXG4gICAgY29uc3QgbWFuaWZlc3RQYXRoID0gam9pbihjYWNoZVBhdGgsICdtYW5pZmVzdC5qc29uJyk7XHJcbiAgICBjb25zdCBzb3VyY2VQYXRoID0gam9pbihjYWNoZVBhdGgsICdzb3VyY2VzLmpzJyk7XHJcblxyXG4gICAgLy8gQ3JlYXRlIHRoZSBjYWNoZSBkZXN0aW5hdGlvbiBpZiBpdCBkb2Vzbid0IGV4aXN0IGFscmVhZHlcclxuICAgICFleGlzdHNTeW5jKGNhY2hlUGF0aCkgJiYgbWtkaXJTeW5jKGNhY2hlUGF0aCwgeyByZWN1cnNpdmU6IHRydWUgfSk7XHJcblxyXG4gICAgLy8gRmV0Y2ggYWxsIHRoZSBzY3JpcHRzIGVpdGhlciBpZiB0aGUgYG1hbmlmZXN0Lmpzb25gIGRvZXMgbm90IGV4aXN0XHJcbiAgICAvLyBvciBpZiB0aGUgYGZvcmNlRmV0Y2hgIG9wdGlvbiBpcyBlbmFibGVkXHJcbiAgICBpZiAoIWV4aXN0c1N5bmMobWFuaWZlc3RQYXRoKSB8fCBoaWdoY2hhcnRzT3B0aW9ucy5mb3JjZUZldGNoKSB7XHJcbiAgICAgIGxvZygzLCAnW2NhY2hlXSBGZXRjaGluZyBhbmQgY2FjaGluZyBIaWdoY2hhcnRzIGRlcGVuZGVuY2llcy4nKTtcclxuICAgICAgZmV0Y2hlZE1vZHVsZXMgPSBhd2FpdCBfdXBkYXRlQ2FjaGUoXHJcbiAgICAgICAgaGlnaGNoYXJ0c09wdGlvbnMsXHJcbiAgICAgICAgc2VydmVyUHJveHlPcHRpb25zLFxyXG4gICAgICAgIHNvdXJjZVBhdGhcclxuICAgICAgKTtcclxuICAgIH0gZWxzZSB7XHJcbiAgICAgIGxldCByZXF1ZXN0VXBkYXRlID0gZmFsc2U7XHJcblxyXG4gICAgICAvLyBSZWFkIHRoZSBtYW5pZmVzdCBKU09OXHJcbiAgICAgIGNvbnN0IG1hbmlmZXN0ID0gSlNPTi5wYXJzZShyZWFkRmlsZVN5bmMobWFuaWZlc3RQYXRoKSwgJ3V0ZjgnKTtcclxuXHJcbiAgICAgIC8vIENoZWNrIGlmIHRoZSBtb2R1bGVzIGlzIGFuIGFycmF5LCBpZiBzbywgd2UgcmV3cml0ZSBpdCB0byBhIG1hcCB0byBtYWtlXHJcbiAgICAgIC8vIGl0IGVhc2llciB0byByZXNvbHZlIG1vZHVsZXMuXHJcbiAgICAgIGlmIChtYW5pZmVzdC5tb2R1bGVzICYmIEFycmF5LmlzQXJyYXkobWFuaWZlc3QubW9kdWxlcykpIHtcclxuICAgICAgICBjb25zdCBtb2R1bGVNYXAgPSB7fTtcclxuICAgICAgICBtYW5pZmVzdC5tb2R1bGVzLmZvckVhY2goKG0pID0+IChtb2R1bGVNYXBbbV0gPSAxKSk7XHJcbiAgICAgICAgbWFuaWZlc3QubW9kdWxlcyA9IG1vZHVsZU1hcDtcclxuICAgICAgfVxyXG5cclxuICAgICAgLy8gR2V0IHRoZSBhY3R1YWwgbnVtYmVyIG9mIHNjcmlwdHMgdG8gYmUgZmV0Y2hlZFxyXG4gICAgICBjb25zdCB7IGNvcmVTY3JpcHRzLCBtb2R1bGVTY3JpcHRzLCBpbmRpY2F0b3JTY3JpcHRzIH0gPVxyXG4gICAgICAgIGhpZ2hjaGFydHNPcHRpb25zO1xyXG4gICAgICBjb25zdCBudW1iZXJPZk1vZHVsZXMgPVxyXG4gICAgICAgIGNvcmVTY3JpcHRzLmxlbmd0aCArIG1vZHVsZVNjcmlwdHMubGVuZ3RoICsgaW5kaWNhdG9yU2NyaXB0cy5sZW5ndGg7XHJcblxyXG4gICAgICAvLyBDb21wYXJlIHRoZSBsb2FkZWQgaGlnaGNoYXJ0cyBjb25maWcgd2l0aCB0aGUgY29udGVudHMgaW4gY2FjaGUuXHJcbiAgICAgIC8vIElmIHRoZXJlIGFyZSBjaGFuZ2VzLCBmZXRjaCByZXF1ZXN0ZWQgbW9kdWxlcyBhbmQgcHJvZHVjdHMsXHJcbiAgICAgIC8vIGFuZCBiYWtlIHRoZW0gaW50byBhIGdpYW50IGJsb2IuIFNhdmUgdGhlIGJsb2IuXHJcbiAgICAgIGlmIChtYW5pZmVzdC52ZXJzaW9uICE9PSBoaWdoY2hhcnRzT3B0aW9ucy52ZXJzaW9uKSB7XHJcbiAgICAgICAgbG9nKFxyXG4gICAgICAgICAgMixcclxuICAgICAgICAgICdbY2FjaGVdIEEgSGlnaGNoYXJ0cyB2ZXJzaW9uIG1pc21hdGNoIGluIHRoZSBjYWNoZSwgbmVlZCB0byByZS1mZXRjaC4nXHJcbiAgICAgICAgKTtcclxuICAgICAgICByZXF1ZXN0VXBkYXRlID0gdHJ1ZTtcclxuICAgICAgfSBlbHNlIGlmIChcclxuICAgICAgICBPYmplY3Qua2V5cyhtYW5pZmVzdC5tb2R1bGVzIHx8IHt9KS5sZW5ndGggIT09IG51bWJlck9mTW9kdWxlc1xyXG4gICAgICApIHtcclxuICAgICAgICBsb2coXHJcbiAgICAgICAgICAyLFxyXG4gICAgICAgICAgJ1tjYWNoZV0gVGhlIGNhY2hlIGFuZCB0aGUgcmVxdWVzdGVkIG1vZHVsZXMgZG8gbm90IG1hdGNoLCBuZWVkIHRvIHJlLWZldGNoLidcclxuICAgICAgICApO1xyXG4gICAgICAgIHJlcXVlc3RVcGRhdGUgPSB0cnVlO1xyXG4gICAgICB9IGVsc2Uge1xyXG4gICAgICAgIC8vIENoZWNrIGVhY2ggbW9kdWxlLCBpZiBhbnl0aGluZyBpcyBtaXNzaW5nIHJlZmV0Y2ggZXZlcnl0aGluZ1xyXG4gICAgICAgIHJlcXVlc3RVcGRhdGUgPSAobW9kdWxlU2NyaXB0cyB8fCBbXSkuc29tZSgobW9kdWxlTmFtZSkgPT4ge1xyXG4gICAgICAgICAgaWYgKCFtYW5pZmVzdC5tb2R1bGVzW21vZHVsZU5hbWVdKSB7XHJcbiAgICAgICAgICAgIGxvZyhcclxuICAgICAgICAgICAgICAyLFxyXG4gICAgICAgICAgICAgIGBbY2FjaGVdIFRoZSAke21vZHVsZU5hbWV9IGlzIG1pc3NpbmcgaW4gdGhlIGNhY2hlLCBuZWVkIHRvIHJlLWZldGNoLmBcclxuICAgICAgICAgICAgKTtcclxuICAgICAgICAgICAgcmV0dXJuIHRydWU7XHJcbiAgICAgICAgICB9XHJcbiAgICAgICAgfSk7XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIC8vIFVwZGF0ZSBjYWNoZSBpZiBuZWVkZWRcclxuICAgICAgaWYgKHJlcXVlc3RVcGRhdGUpIHtcclxuICAgICAgICBmZXRjaGVkTW9kdWxlcyA9IGF3YWl0IF91cGRhdGVDYWNoZShcclxuICAgICAgICAgIGhpZ2hjaGFydHNPcHRpb25zLFxyXG4gICAgICAgICAgc2VydmVyUHJveHlPcHRpb25zLFxyXG4gICAgICAgICAgc291cmNlUGF0aFxyXG4gICAgICAgICk7XHJcbiAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgbG9nKDMsICdbY2FjaGVdIERlcGVuZGVuY3kgY2FjaGUgaXMgdXAgdG8gZGF0ZSwgcHJvY2VlZGluZy4nKTtcclxuXHJcbiAgICAgICAgLy8gTG9hZCB0aGUgc291cmNlc1xyXG4gICAgICAgIGNhY2hlLnNvdXJjZXMgPSByZWFkRmlsZVN5bmMoc291cmNlUGF0aCwgJ3V0ZjgnKTtcclxuXHJcbiAgICAgICAgLy8gR2V0IGN1cnJlbnQgbW9kdWxlcyBtYXBcclxuICAgICAgICBmZXRjaGVkTW9kdWxlcyA9IG1hbmlmZXN0Lm1vZHVsZXM7XHJcblxyXG4gICAgICAgIC8vIEV4dHJhY3QgYW5kIHNhdmUgdmVyc2lvbiBvZiBjdXJyZW50bHkgdXNlZCBIaWdoY2hhcnRzXHJcbiAgICAgICAgY2FjaGUuaGNWZXJzaW9uID0gZXh0cmFjdFZlcnNpb24oY2FjaGUuc291cmNlcyk7XHJcbiAgICAgIH1cclxuICAgIH1cclxuXHJcbiAgICAvLyBGaW5hbGx5LCBzYXZlIHRoZSBuZXcgbWFuaWZlc3QsIHdoaWNoIGlzIGJhc2ljYWxseSBvdXIgY3VycmVudCBjb25maWdcclxuICAgIC8vIGluIGEgc2xpZ2h0bHkgZGlmZmVyZW50IGZvcm1hdFxyXG4gICAgYXdhaXQgX3NhdmVDb25maWdUb01hbmlmZXN0KGhpZ2hjaGFydHNPcHRpb25zLCBmZXRjaGVkTW9kdWxlcyk7XHJcbiAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcihcclxuICAgICAgJ1tjYWNoZV0gQ291bGQgbm90IGNvbmZpZ3VyZSBjYWNoZSBhbmQgY3JlYXRlIG9yIHVwZGF0ZSB0aGUgY29uZmlnIG1hbmlmZXN0LicsXHJcbiAgICAgIDUwMFxyXG4gICAgKS5zZXRFcnJvcihlcnJvcik7XHJcbiAgfVxyXG59XHJcblxyXG4vKipcclxuICogR2V0cyB0aGUgdmVyc2lvbiBvZiBIaWdoY2hhcnRzIGZyb20gdGhlIGNhY2hlLlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gZ2V0SGlnaGNoYXJ0c1ZlcnNpb25cclxuICpcclxuICogQHJldHVybnMge3N0cmluZ30gVGhlIGNhY2hlZCBIaWdoY2hhcnRzIHZlcnNpb24uXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gZ2V0SGlnaGNoYXJ0c1ZlcnNpb24oKSB7XHJcbiAgcmV0dXJuIGNhY2hlLmhjVmVyc2lvbjtcclxufVxyXG5cclxuLyoqXHJcbiAqIFVwZGF0ZXMgdGhlIEhpZ2hjaGFydHMgdmVyc2lvbiBpbiB0aGUgYXBwbGllZCBjb25maWd1cmF0aW9uIGFuZCBjaGVja3NcclxuICogdGhlIGNhY2hlIGZvciB0aGUgbmV3IHZlcnNpb24uXHJcbiAqXHJcbiAqIEBhc3luY1xyXG4gKiBAZnVuY3Rpb24gdXBkYXRlSGlnaGNoYXJ0c1ZlcnNpb25cclxuICpcclxuICogQHBhcmFtIHtzdHJpbmd9IG5ld1ZlcnNpb24gLSBUaGUgbmV3IEhpZ2hjaGFydHMgdmVyc2lvbiB0byBiZSBhcHBsaWVkLlxyXG4gKi9cclxuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIHVwZGF0ZUhpZ2hjaGFydHNWZXJzaW9uKG5ld1ZlcnNpb24pIHtcclxuICAvLyBVcGRhdGUgdG8gdGhlIG5ldyB2ZXJzaW9uXHJcbiAgY29uc3Qgb3B0aW9ucyA9IHVwZGF0ZU9wdGlvbnMoe1xyXG4gICAgaGlnaGNoYXJ0czoge1xyXG4gICAgICB2ZXJzaW9uOiBuZXdWZXJzaW9uXHJcbiAgICB9XHJcbiAgfSk7XHJcblxyXG4gIC8vIENoZWNrIGlmIGNhY2hlIG5lZWRzIHRvIGJlIHVwZGF0ZWRcclxuICBhd2FpdCBjaGVja0FuZFVwZGF0ZUNhY2hlKG9wdGlvbnMuaGlnaGNoYXJ0cywgb3B0aW9ucy5zZXJ2ZXIucHJveHkpO1xyXG59XHJcblxyXG4vKipcclxuICogRXh0cmFjdHMgSGlnaGNoYXJ0cyB2ZXJzaW9uIGZyb20gdGhlIGNhY2hlJ3Mgc291cmNlcyBzdHJpbmcuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBleHRyYWN0VmVyc2lvblxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gY2FjaGVTb3VyY2VzIC0gVGhlIGNhY2hlIHNvdXJjZXMgb2JqZWN0LlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7c3RyaW5nfSBUaGUgZXh0cmFjdGVkIEhpZ2hjaGFydHMgdmVyc2lvbi5cclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiBleHRyYWN0VmVyc2lvbihjYWNoZVNvdXJjZXMpIHtcclxuICByZXR1cm4gY2FjaGVTb3VyY2VzXHJcbiAgICAuc3Vic3RyaW5nKDAsIGNhY2hlU291cmNlcy5pbmRleE9mKCcqLycpKVxyXG4gICAgLnJlcGxhY2UoJy8qJywgJycpXHJcbiAgICAucmVwbGFjZSgnKi8nLCAnJylcclxuICAgIC5yZXBsYWNlKC9cXG4vZywgJycpXHJcbiAgICAudHJpbSgpO1xyXG59XHJcblxyXG4vKipcclxuICogRXh0cmFjdHMgdGhlIEhpZ2hjaGFydHMgbW9kdWxlIG5hbWUgYmFzZWQgb24gdGhlIHNjcmlwdFBhdGguXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBleHRyYWN0TW9kdWxlTmFtZVxyXG4gKlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gc2NyaXB0UGF0aCAtIFRoZSBwYXRoIG9mIHRoZSBzY3JpcHQgZnJvbSB3aGljaCB0aGUgbW9kdWxlXHJcbiAqIG5hbWUgd2lsbCBiZSBleHRyYWN0ZWQuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtzdHJpbmd9IFRoZSBleHRyYWN0ZWQgbW9kdWxlIG5hbWUuXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gZXh0cmFjdE1vZHVsZU5hbWUoc2NyaXB0UGF0aCkge1xyXG4gIHJldHVybiBzY3JpcHRQYXRoLnJlcGxhY2UoXHJcbiAgICAvKC4qKVxcL3woLiopbW9kdWxlc1xcL3xzdG9ja1xcLyguKilpbmRpY2F0b3JzXFwvfG1hcHNcXC8oLiopbW9kdWxlc1xcLy9naSxcclxuICAgICcnXHJcbiAgKTtcclxufVxyXG5cclxuLyoqXHJcbiAqIFJldHJpZXZlcyB0aGUgY3VycmVudCBjYWNoZSBvYmplY3QuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBnZXRDYWNoZVxyXG4gKlxyXG4gKiBAcmV0dXJucyB7T2JqZWN0fSBUaGUgY2FjaGUgb2JqZWN0IGNvbnRhaW5pbmcgdmFyaW91cyBjYWNoZWQgZGF0YS5cclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiBnZXRDYWNoZSgpIHtcclxuICByZXR1cm4gY2FjaGU7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBHZXRzIHRoZSBjYWNoZSBwYXRoIGZvciBIaWdoY2hhcnRzLlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gZ2V0Q2FjaGVQYXRoXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtzdHJpbmd9IFRoZSBhYnNvbHV0ZSBwYXRoIHRvIHRoZSBjYWNoZSBkaXJlY3RvcnkgZm9yIEhpZ2hjaGFydHMuXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gZ2V0Q2FjaGVQYXRoKCkge1xyXG4gIHJldHVybiBnZXRBYnNvbHV0ZVBhdGgoZ2V0T3B0aW9ucygpLmhpZ2hjaGFydHMuY2FjaGVQYXRoLCAndXRmOCcpOyAvLyAjNTYyXHJcbn1cclxuXHJcbi8qKlxyXG4gKiBGZXRjaGVzIGEgc2luZ2xlIHNjcmlwdCBhbmQgdXBkYXRlcyB0aGUgYGZldGNoZWRNb2R1bGVzYCBhY2NvcmRpbmdseS5cclxuICpcclxuICogQGFzeW5jXHJcbiAqIEBmdW5jdGlvbiBfZmV0Y2hBbmRQcm9jZXNzU2NyaXB0XHJcbiAqXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSBzY3JpcHQgLSBBIHBhdGggdG8gc2NyaXB0IHRvIGdldC5cclxuICogQHBhcmFtIHtPYmplY3R9IHJlcXVlc3RPcHRpb25zIC0gQWRkaXRpb25hbCBvcHRpb25zIGZvciB0aGUgcHJveHkgYWdlbnRcclxuICogdG8gdXNlIGZvciBhIHJlcXVlc3QuXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBmZXRjaGVkTW9kdWxlcyAtIEFuIG9iamVjdCB3aGljaCB0cmFja3Mgd2hpY2ggSGlnaGNoYXJ0c1xyXG4gKiBtb2R1bGVzIGhhdmUgYmVlbiBmZXRjaGVkLlxyXG4gKiBAcGFyYW0ge2Jvb2xlYW59IFtzaG91bGRUaHJvd0Vycm9yPWZhbHNlXSAtIEEgZmxhZyB0byBpbmRpY2F0ZSBpZiB0aGUgZXJyb3JcclxuICogc2hvdWxkIGJlIHRocm93bi4gVGhpcyBzaG91bGQgYmUgdXNlZCBvbmx5IGZvciB0aGUgY29yZSBzY3JpcHRzLiBUaGUgZGVmYXVsdFxyXG4gKiB2YWx1ZSBpcyBgZmFsc2VgLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7UHJvbWlzZTxzdHJpbmc+fSBBIFByb21pc2UgdGhhdCByZXNvbHZlcyB0byB0aGUgdGV4dCByZXByZXNlbnRhdGlvblxyXG4gKiBvZiB0aGUgZmV0Y2hlZCBzY3JpcHQuXHJcbiAqXHJcbiAqIEB0aHJvd3Mge0V4cG9ydEVycm9yfSBUaHJvd3MgYW4gYEV4cG9ydEVycm9yYCBpZiB0aGVyZSBpcyBhIHByb2JsZW1cclxuICogd2l0aCBmZXRjaGluZyB0aGUgc2NyaXB0LlxyXG4gKi9cclxuYXN5bmMgZnVuY3Rpb24gX2ZldGNoQW5kUHJvY2Vzc1NjcmlwdChcclxuICBzY3JpcHQsXHJcbiAgcmVxdWVzdE9wdGlvbnMsXHJcbiAgZmV0Y2hlZE1vZHVsZXMsXHJcbiAgc2hvdWxkVGhyb3dFcnJvciA9IGZhbHNlXHJcbikge1xyXG4gIC8vIEdldCByaWQgb2YgdGhlIC5qcyBmcm9tIHRoZSBjdXN0b20gc3RyaW5nc1xyXG4gIGlmIChzY3JpcHQuZW5kc1dpdGgoJy5qcycpKSB7XHJcbiAgICBzY3JpcHQgPSBzY3JpcHQuc3Vic3RyaW5nKDAsIHNjcmlwdC5sZW5ndGggLSAzKTtcclxuICB9XHJcbiAgbG9nKDQsIGBbY2FjaGVdIEZldGNoaW5nIHNjcmlwdCAtICR7c2NyaXB0fS5qc2ApO1xyXG5cclxuICAvLyBGZXRjaCB0aGUgc2NyaXB0XHJcbiAgY29uc3QgcmVzcG9uc2UgPSBhd2FpdCBmZXRjaChgJHtzY3JpcHR9LmpzYCwgcmVxdWVzdE9wdGlvbnMpO1xyXG5cclxuICAvLyBJZiBPSywgcmV0dXJuIGl0cyB0ZXh0IHJlcHJlc2VudGF0aW9uXHJcbiAgaWYgKHJlc3BvbnNlLnN0YXR1c0NvZGUgPT09IDIwMCAmJiB0eXBlb2YgcmVzcG9uc2UudGV4dCA9PSAnc3RyaW5nJykge1xyXG4gICAgaWYgKGZldGNoZWRNb2R1bGVzKSB7XHJcbiAgICAgIGNvbnN0IG1vZHVsZU5hbWUgPSBleHRyYWN0TW9kdWxlTmFtZShzY3JpcHQpO1xyXG4gICAgICBmZXRjaGVkTW9kdWxlc1ttb2R1bGVOYW1lXSA9IDE7XHJcbiAgICB9XHJcbiAgICByZXR1cm4gcmVzcG9uc2UudGV4dDtcclxuICB9XHJcblxyXG4gIC8vIEJhc2VkIG9uIHRoZSBgc2hvdWxkVGhyb3dFcnJvcmAgZmxhZywgZGVjaWRlIGhvdyB0byBzZXJ2ZSBlcnJvciBtZXNzYWdlXHJcbiAgaWYgKHNob3VsZFRocm93RXJyb3IpIHtcclxuICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcihcclxuICAgICAgYFtjYWNoZV0gQ291bGQgbm90IGZldGNoIHRoZSAke3NjcmlwdH0uanMuIFRoZSBzY3JpcHQgbWlnaHQgbm90IGV4aXN0IGluIHRoZSByZXF1ZXN0ZWQgdmVyc2lvbiAoc3RhdHVzIGNvZGU6ICR7cmVzcG9uc2Uuc3RhdHVzQ29kZX0pLmAsXHJcbiAgICAgIDQwNFxyXG4gICAgKS5zZXRFcnJvcihyZXNwb25zZSk7XHJcbiAgfSBlbHNlIHtcclxuICAgIGxvZyhcclxuICAgICAgMixcclxuICAgICAgYFtjYWNoZV0gQ291bGQgbm90IGZldGNoIHRoZSAke3NjcmlwdH0uanMuIFRoZSBzY3JpcHQgbWlnaHQgbm90IGV4aXN0IGluIHRoZSByZXF1ZXN0ZWQgdmVyc2lvbi5gXHJcbiAgICApO1xyXG4gIH1cclxufVxyXG5cclxuLyoqXHJcbiAqIFNhdmVzIHRoZSBwcm92aWRlZCBjb25maWd1cmF0aW9uIGFuZCBmZXRjaGVkIG1vZHVsZXMgdG8gdGhlIGNhY2hlIG1hbmlmZXN0XHJcbiAqIGZpbGUuXHJcbiAqXHJcbiAqIEBhc3luY1xyXG4gKiBAZnVuY3Rpb24gX3NhdmVDb25maWdUb01hbmlmZXN0XHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBoaWdoY2hhcnRzT3B0aW9ucyAtIFRoZSBjb25maWd1cmF0aW9uIG9iamVjdCBjb250YWluaW5nXHJcbiAqIGBoaWdoY2hhcnRzYCBvcHRpb25zLlxyXG4gKiBAcGFyYW0ge09iamVjdH0gW2ZldGNoZWRNb2R1bGVzPXt9XSAtIEFuIG9iamVjdCB3aGljaCB0cmFja3Mgd2hpY2ggSGlnaGNoYXJ0c1xyXG4gKiBtb2R1bGVzIGhhdmUgYmVlbiBmZXRjaGVkLiBUaGUgZGVmYXVsdCB2YWx1ZSBpcyBhbiBlbXB0eSBvYmplY3QuXHJcbiAqXHJcbiAqIEB0aHJvd3Mge0V4cG9ydEVycm9yfSBUaHJvd3MgYW4gYEV4cG9ydEVycm9yYCBpZiBhbiBlcnJvciBvY2N1cnMgd2hpbGVcclxuICogd3JpdGluZyB0aGUgY2FjaGUgbWFuaWZlc3QuXHJcbiAqL1xyXG5hc3luYyBmdW5jdGlvbiBfc2F2ZUNvbmZpZ1RvTWFuaWZlc3QoaGlnaGNoYXJ0c09wdGlvbnMsIGZldGNoZWRNb2R1bGVzID0ge30pIHtcclxuICBjb25zdCBuZXdNYW5pZmVzdCA9IHtcclxuICAgIHZlcnNpb246IGhpZ2hjaGFydHNPcHRpb25zLnZlcnNpb24sXHJcbiAgICBtb2R1bGVzOiBmZXRjaGVkTW9kdWxlc1xyXG4gIH07XHJcblxyXG4gIC8vIFVwZGF0ZSBjYWNoZSBvYmplY3Qgd2l0aCB0aGUgY3VycmVudCBtb2R1bGVzXHJcbiAgY2FjaGUuYWN0aXZlTWFuaWZlc3QgPSBuZXdNYW5pZmVzdDtcclxuXHJcbiAgbG9nKDMsICdbY2FjaGVdIFdyaXRpbmcgYSBuZXcgbWFuaWZlc3QuJyk7XHJcbiAgdHJ5IHtcclxuICAgIHdyaXRlRmlsZVN5bmMoXHJcbiAgICAgIGpvaW4oZ2V0Q2FjaGVQYXRoKCksICdtYW5pZmVzdC5qc29uJyksXHJcbiAgICAgIEpTT04uc3RyaW5naWZ5KG5ld01hbmlmZXN0KSxcclxuICAgICAgJ3V0ZjgnXHJcbiAgICApO1xyXG4gIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoXHJcbiAgICAgICdbY2FjaGVdIEVycm9yIHdyaXRpbmcgdGhlIGNhY2hlIG1hbmlmZXN0LicsXHJcbiAgICAgIDUwMFxyXG4gICAgKS5zZXRFcnJvcihlcnJvcik7XHJcbiAgfVxyXG59XHJcblxyXG4vKipcclxuICogRmV0Y2hlcyBIaWdoY2hhcnRzIGBzY3JpcHRzYCBhbmQgYGN1c3RvbVNjcmlwdHNgIGZyb20gdGhlIGdpdmVuIENETnMuXHJcbiAqXHJcbiAqIEBhc3luY1xyXG4gKiBAZnVuY3Rpb24gX2ZldGNoU2NyaXB0c1xyXG4gKlxyXG4gKiBAcGFyYW0ge0FycmF5LjxzdHJpbmc+fSBjb3JlU2NyaXB0cyAtIEhpZ2hjaGFydHMgY29yZSBzY3JpcHRzIHRvIGZldGNoLlxyXG4gKiBAcGFyYW0ge0FycmF5LjxzdHJpbmc+fSBtb2R1bGVTY3JpcHRzIC0gSGlnaGNoYXJ0cyBtb2R1bGVzIHRvIGZldGNoLlxyXG4gKiBAcGFyYW0ge0FycmF5LjxzdHJpbmc+fSBjdXN0b21TY3JpcHRzIC0gQ3VzdG9tIHNjcmlwdCBwYXRocyB0byBmZXRjaCAoZnVsbFxyXG4gKiBVUkxzKS5cclxuICogQHBhcmFtIHtPYmplY3R9IHNlcnZlclByb3h5T3B0aW9ucyAtIFRoZSBjb25maWd1cmF0aW9uIG9iamVjdCBjb250YWluaW5nXHJcbiAqIGBzZXJ2ZXIucHJveHlgIG9wdGlvbnMuXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBmZXRjaGVkTW9kdWxlcyAtIEFuIG9iamVjdCB3aGljaCB0cmFja3Mgd2hpY2ggSGlnaGNoYXJ0c1xyXG4gKiBtb2R1bGVzIGhhdmUgYmVlbiBmZXRjaGVkLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7UHJvbWlzZTxzdHJpbmc+fSBBIFByb21pc2UgdGhhdCByZXNvbHZlcyB0byB0aGUgZmV0Y2hlZCBzY3JpcHRzXHJcbiAqIGNvbnRlbnQgam9pbmVkLlxyXG4gKlxyXG4gKiBAdGhyb3dzIHtFeHBvcnRFcnJvcn0gVGhyb3dzIGFuIGBFeHBvcnRFcnJvcmAgaWYgYW4gZXJyb3Igb2NjdXJzIHdoaWxlXHJcbiAqIHNldHRpbmcgYW4gSFRUUCBBZ2VudCBmb3IgcHJveHkuXHJcbiAqL1xyXG5hc3luYyBmdW5jdGlvbiBfZmV0Y2hTY3JpcHRzKFxyXG4gIGNvcmVTY3JpcHRzLFxyXG4gIG1vZHVsZVNjcmlwdHMsXHJcbiAgY3VzdG9tU2NyaXB0cyxcclxuICBzZXJ2ZXJQcm94eU9wdGlvbnMsXHJcbiAgZmV0Y2hlZE1vZHVsZXNcclxuKSB7XHJcbiAgLy8gQ29uZmlndXJlIHByb3h5IGlmIGV4aXN0c1xyXG4gIGxldCBwcm94eUFnZW50O1xyXG4gIGNvbnN0IHByb3h5SG9zdCA9IHNlcnZlclByb3h5T3B0aW9ucy5ob3N0O1xyXG4gIGNvbnN0IHByb3h5UG9ydCA9IHNlcnZlclByb3h5T3B0aW9ucy5wb3J0O1xyXG5cclxuICAvLyBUcnkgdG8gY3JlYXRlIGEgUHJveHkgQWdlbnRcclxuICBpZiAocHJveHlIb3N0ICYmIHByb3h5UG9ydCkge1xyXG4gICAgdHJ5IHtcclxuICAgICAgcHJveHlBZ2VudCA9IG5ldyBIdHRwc1Byb3h5QWdlbnQoe1xyXG4gICAgICAgIGhvc3Q6IHByb3h5SG9zdCxcclxuICAgICAgICBwb3J0OiBwcm94eVBvcnRcclxuICAgICAgfSk7XHJcbiAgICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoXHJcbiAgICAgICAgJ1tjYWNoZV0gQ291bGQgbm90IGNyZWF0ZSBhIFByb3h5IEFnZW50LicsXHJcbiAgICAgICAgNTAwXHJcbiAgICAgICkuc2V0RXJyb3IoZXJyb3IpO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgLy8gSWYgZXhpc3RzLCBhZGQgcHJveHkgYWdlbnQgdG8gcmVxdWVzdCBvcHRpb25zXHJcbiAgY29uc3QgcmVxdWVzdE9wdGlvbnMgPSBwcm94eUFnZW50XHJcbiAgICA/IHtcclxuICAgICAgICBhZ2VudDogcHJveHlBZ2VudCxcclxuICAgICAgICB0aW1lb3V0OiBzZXJ2ZXJQcm94eU9wdGlvbnMudGltZW91dFxyXG4gICAgICB9XHJcbiAgICA6IHt9O1xyXG5cclxuICBjb25zdCBhbGxGZXRjaFByb21pc2VzID0gW1xyXG4gICAgLi4uY29yZVNjcmlwdHMubWFwKChzY3JpcHQpID0+XHJcbiAgICAgIF9mZXRjaEFuZFByb2Nlc3NTY3JpcHQoYCR7c2NyaXB0fWAsIHJlcXVlc3RPcHRpb25zLCBmZXRjaGVkTW9kdWxlcywgdHJ1ZSlcclxuICAgICksXHJcbiAgICAuLi5tb2R1bGVTY3JpcHRzLm1hcCgoc2NyaXB0KSA9PlxyXG4gICAgICBfZmV0Y2hBbmRQcm9jZXNzU2NyaXB0KGAke3NjcmlwdH1gLCByZXF1ZXN0T3B0aW9ucywgZmV0Y2hlZE1vZHVsZXMpXHJcbiAgICApLFxyXG4gICAgLi4uY3VzdG9tU2NyaXB0cy5tYXAoKHNjcmlwdCkgPT5cclxuICAgICAgX2ZldGNoQW5kUHJvY2Vzc1NjcmlwdChgJHtzY3JpcHR9YCwgcmVxdWVzdE9wdGlvbnMpXHJcbiAgICApXHJcbiAgXTtcclxuXHJcbiAgY29uc3QgZmV0Y2hlZFNjcmlwdHMgPSBhd2FpdCBQcm9taXNlLmFsbChhbGxGZXRjaFByb21pc2VzKTtcclxuICByZXR1cm4gZmV0Y2hlZFNjcmlwdHMuam9pbignO1xcbicpO1xyXG59XHJcblxyXG4vKipcclxuICogVXBkYXRlcyB0aGUgbG9jYWwgY2FjaGUgd2l0aCBIaWdoY2hhcnRzIHNjcmlwdHMgYW5kIHRoZWlyIHZlcnNpb25zLlxyXG4gKlxyXG4gKiBAYXN5bmNcclxuICogQGZ1bmN0aW9uIF91cGRhdGVDYWNoZVxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gaGlnaGNoYXJ0c09wdGlvbnMgLSBUaGUgY29uZmlndXJhdGlvbiBvYmplY3QgY29udGFpbmluZ1xyXG4gKiBgaGlnaGNoYXJ0c2Agb3B0aW9ucy5cclxuICogQHBhcmFtIHtPYmplY3R9IHNlcnZlclByb3h5T3B0aW9ucyAtIFRoZSBjb25maWd1cmF0aW9uIG9iamVjdCBjb250YWluaW5nXHJcbiAqIGBzZXJ2ZXIucHJveHlgIG9wdGlvbnMuXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSBzb3VyY2VQYXRoIC0gVGhlIHBhdGggdG8gdGhlIHNvdXJjZSBmaWxlIGluIHRoZSBjYWNoZS5cclxuICpcclxuICogQHJldHVybnMge1Byb21pc2U8T2JqZWN0Pn0gQSBQcm9taXNlIHRoYXQgcmVzb2x2ZXMgdG8gYW4gb2JqZWN0IHJlcHJlc2VudGluZ1xyXG4gKiB0aGUgZmV0Y2hlZCBtb2R1bGVzLlxyXG4gKlxyXG4gKiBAdGhyb3dzIHtFeHBvcnRFcnJvcn0gVGhyb3dzIGFuIGBFeHBvcnRFcnJvcmAgaWYgdGhlcmUgaXMgYW4gaXNzdWUgdXBkYXRpbmdcclxuICogdGhlIGxvY2FsIEhpZ2hjaGFydHMgY2FjaGUuXHJcbiAqL1xyXG5hc3luYyBmdW5jdGlvbiBfdXBkYXRlQ2FjaGUoaGlnaGNoYXJ0c09wdGlvbnMsIHNlcnZlclByb3h5T3B0aW9ucywgc291cmNlUGF0aCkge1xyXG4gIC8vIEdldCBIaWdoY2hhcnRzIHZlcnNpb24gZm9yIHNjcmlwdHNcclxuICBjb25zdCBoY1ZlcnNpb24gPVxyXG4gICAgaGlnaGNoYXJ0c09wdGlvbnMudmVyc2lvbiA9PT0gJ2xhdGVzdCdcclxuICAgICAgPyBudWxsXHJcbiAgICAgIDogYCR7aGlnaGNoYXJ0c09wdGlvbnMudmVyc2lvbn1gO1xyXG5cclxuICAvLyBHZXQgdGhlIENETiB1cmwgZm9yIHNjcmlwdHNcclxuICBjb25zdCBjZG5VcmwgPSBoaWdoY2hhcnRzT3B0aW9ucy5jZG5VcmwgfHwgY2FjaGUuY2RuVXJsO1xyXG5cclxuICB0cnkge1xyXG4gICAgY29uc3QgZmV0Y2hlZE1vZHVsZXMgPSB7fTtcclxuXHJcbiAgICBsb2coXHJcbiAgICAgIDMsXHJcbiAgICAgIGBbY2FjaGVdIFVwZGF0aW5nIGNhY2hlIHZlcnNpb24gdG8gSGlnaGNoYXJ0czogJHtoY1ZlcnNpb24gfHwgJ2xhdGVzdCd9LmBcclxuICAgICk7XHJcblxyXG4gICAgY2FjaGUuc291cmNlcyA9IGF3YWl0IF9mZXRjaFNjcmlwdHMoXHJcbiAgICAgIFtcclxuICAgICAgICAuLi5oaWdoY2hhcnRzT3B0aW9ucy5jb3JlU2NyaXB0cy5tYXAoKGMpID0+XHJcbiAgICAgICAgICBoY1ZlcnNpb24gPyBgJHtjZG5Vcmx9LyR7aGNWZXJzaW9ufS8ke2N9YCA6IGAke2NkblVybH0vJHtjfWBcclxuICAgICAgICApXHJcbiAgICAgIF0sXHJcbiAgICAgIFtcclxuICAgICAgICAuLi5oaWdoY2hhcnRzT3B0aW9ucy5tb2R1bGVTY3JpcHRzLm1hcCgobSkgPT5cclxuICAgICAgICAgIG0gPT09ICdtYXAnXHJcbiAgICAgICAgICAgID8gaGNWZXJzaW9uXHJcbiAgICAgICAgICAgICAgPyBgJHtjZG5Vcmx9L21hcHMvJHtoY1ZlcnNpb259L21vZHVsZXMvJHttfWBcclxuICAgICAgICAgICAgICA6IGAke2NkblVybH0vbWFwcy9tb2R1bGVzLyR7bX1gXHJcbiAgICAgICAgICAgIDogaGNWZXJzaW9uXHJcbiAgICAgICAgICAgICAgPyBgJHtjZG5Vcmx9LyR7aGNWZXJzaW9ufS9tb2R1bGVzLyR7bX1gXHJcbiAgICAgICAgICAgICAgOiBgJHtjZG5Vcmx9L21vZHVsZXMvJHttfWBcclxuICAgICAgICApLFxyXG4gICAgICAgIC4uLmhpZ2hjaGFydHNPcHRpb25zLmluZGljYXRvclNjcmlwdHMubWFwKChpKSA9PlxyXG4gICAgICAgICAgaGNWZXJzaW9uXHJcbiAgICAgICAgICAgID8gYCR7Y2RuVXJsfS9zdG9jay8ke2hjVmVyc2lvbn0vaW5kaWNhdG9ycy8ke2l9YFxyXG4gICAgICAgICAgICA6IGAke2NkblVybH0vc3RvY2svaW5kaWNhdG9ycy8ke2l9YFxyXG4gICAgICAgIClcclxuICAgICAgXSxcclxuICAgICAgaGlnaGNoYXJ0c09wdGlvbnMuY3VzdG9tU2NyaXB0cyxcclxuICAgICAgc2VydmVyUHJveHlPcHRpb25zLFxyXG4gICAgICBmZXRjaGVkTW9kdWxlc1xyXG4gICAgKTtcclxuXHJcbiAgICAvLyBFeHRyYWN0IGFuZCBzYXZlIHZlcnNpb24gb2YgY3VycmVudGx5IHVzZWQgSGlnaGNoYXJ0c1xyXG4gICAgY2FjaGUuaGNWZXJzaW9uID0gZXh0cmFjdFZlcnNpb24oY2FjaGUuc291cmNlcyk7XHJcblxyXG4gICAgLy8gU2F2ZSB0aGUgZmV0Y2hlZCBtb2R1bGVzIGludG8gY2FjaGVzJyBzb3VyY2UgSlNPTlxyXG4gICAgd3JpdGVGaWxlU3luYyhzb3VyY2VQYXRoLCBjYWNoZS5zb3VyY2VzKTtcclxuICAgIHJldHVybiBmZXRjaGVkTW9kdWxlcztcclxuICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgdGhyb3cgbmV3IEV4cG9ydEVycm9yKFxyXG4gICAgICAnW2NhY2hlXSBVbmFibGUgdG8gdXBkYXRlIHRoZSBsb2NhbCBIaWdoY2hhcnRzIGNhY2hlLicsXHJcbiAgICAgIDUwMFxyXG4gICAgKS5zZXRFcnJvcihlcnJvcik7XHJcbiAgfVxyXG59XHJcblxyXG5leHBvcnQgZGVmYXVsdCB7XHJcbiAgY2hlY2tBbmRVcGRhdGVDYWNoZSxcclxuICBnZXRIaWdoY2hhcnRzVmVyc2lvbixcclxuICB1cGRhdGVIaWdoY2hhcnRzVmVyc2lvbixcclxuICBleHRyYWN0VmVyc2lvbixcclxuICBleHRyYWN0TW9kdWxlTmFtZSxcclxuICBnZXRDYWNoZSxcclxuICBnZXRDYWNoZVBhdGhcclxufTtcclxuIiwiLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcclxuXHJcbkhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlclxyXG5cclxuQ29weXJpZ2h0IChjKSAyMDE2LTIwMjUsIEhpZ2hzb2Z0XHJcblxyXG5MaWNlbmNlZCB1bmRlciB0aGUgTUlUIGxpY2VuY2UuXHJcblxyXG5BZGRpdGlvbmFsbHkgYSB2YWxpZCBIaWdoY2hhcnRzIGxpY2Vuc2UgaXMgcmVxdWlyZWQgZm9yIHVzZS5cclxuXHJcblNlZSBMSUNFTlNFIGZpbGUgaW4gcm9vdCBmb3IgZGV0YWlscy5cclxuXHJcbioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXHJcblxyXG4vKipcclxuICogQG92ZXJ2aWV3IFByb3ZpZGVzIG1ldGhvZHMgZm9yIGluaXRpYWxpemluZyBIaWdoY2hhcnRzIHdpdGggY3VzdG9taXplZFxyXG4gKiBhbmltYXRpb24gc2V0dGluZ3MgYW5kIHRyaWdnZXJpbmcgdGhlIGNyZWF0aW9uIG9mIEhpZ2hjaGFydHMgY2hhcnRzIHdpdGhcclxuICogZXhwb3J0LXNwZWNpZmljIGNvbmZpZ3VyYXRpb25zIGluIHRoZSBwYWdlIGNvbnRleHQuIFN1cHBvcnRzIGR5bmFtaWMgb3B0aW9uXHJcbiAqIG1lcmdpbmcsIGN1c3RvbSBsb2dpYyBpbmplY3Rpb24sIGFuZCBjb250cm9sIG92ZXIgcmVuZGVyaW5nIGJlaGF2aW9ycy4gVXNlZFxyXG4gKiBieSB0aGUgUHVwcGV0ZWVyIHBhZ2UuXHJcbiAqL1xyXG5cclxuLyogZXNsaW50LWRpc2FibGUgbm8tdW5kZWYgKi9cclxuXHJcbi8qKlxyXG4gKiBTZXR0aW5nIHRoZSBgSGlnaGNoYXJ0cy5hbmltT2JqZWN0YCBmdW5jdGlvbi4gQ2FsbGVkIHdoZW4gaW5pdGluZyB0aGUgcGFnZS5cclxuICpcclxuICogQGZ1bmN0aW9uIHNldHVwSGlnaGNoYXJ0c1xyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIHNldHVwSGlnaGNoYXJ0cygpIHtcclxuICBIaWdoY2hhcnRzLmFuaW1PYmplY3QgPSBmdW5jdGlvbiAoKSB7XHJcbiAgICByZXR1cm4geyBkdXJhdGlvbjogMCB9O1xyXG4gIH07XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBDcmVhdGVzIHRoZSBhY3R1YWwgSGlnaGNoYXJ0cyBjaGFydCBvbiBhIHBhZ2UuXHJcbiAqXHJcbiAqIEBhc3luY1xyXG4gKiBAZnVuY3Rpb24gY3JlYXRlQ2hhcnRcclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IGV4cG9ydE9wdGlvbnMgLSBUaGUgY29uZmlndXJhdGlvbiBvYmplY3QgY29udGFpbmluZyBgZXhwb3J0YFxyXG4gKiBvcHRpb25zLlxyXG4gKiBAcGFyYW0ge09iamVjdH0gY3VzdG9tTG9naWNPcHRpb25zIC0gVGhlIGNvbmZpZ3VyYXRpb24gb2JqZWN0IGNvbnRhaW5pbmdcclxuICogYGN1c3RvbUxvZ2ljYCBvcHRpb25zLlxyXG4gKlxyXG4gKi9cclxuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIGNyZWF0ZUNoYXJ0KGV4cG9ydE9wdGlvbnMsIGN1c3RvbUxvZ2ljT3B0aW9ucykge1xyXG4gIC8vIEdldCByZXF1aXJlZCBmdW5jdGlvbnNcclxuICBjb25zdCB7IGdldE9wdGlvbnMsIHNldE9wdGlvbnMsIG1lcmdlLCB3cmFwIH0gPSBIaWdoY2hhcnRzO1xyXG5cclxuICAvLyBDcmVhdGUgYSBzZXBhcmF0ZSBvYmplY3QgZm9yIGEgcG90ZW50aWFsIGBzZXRPcHRpb25zYCB1c2FnZXMgaW4gb3JkZXJcclxuICAvLyB0byBwcmV2ZW50IGZyb20gcG9sbHV0aW5nIG90aGVyIGV4cG9ydHMgdGhhdCBjYW4gaGFwcGVuIG9uIHRoZSBzYW1lIHBhZ2VcclxuICBIaWdoY2hhcnRzLnNldE9wdGlvbnNPYmogPSBtZXJnZShmYWxzZSwge30sIGdldE9wdGlvbnMoKSk7XHJcblxyXG4gIC8vIE5PVEU6IElzIHRoaXMgdXNlZCBmb3IgYW55dGhpbmcgdXNlZnVsP1xyXG4gIHdpbmRvdy5pc1JlbmRlckNvbXBsZXRlID0gZmFsc2U7XHJcbiAgd3JhcChIaWdoY2hhcnRzLkNoYXJ0LnByb3RvdHlwZSwgJ2luaXQnLCBmdW5jdGlvbiAocHJvY2VlZCwgdXNlck9wdGlvbnMsIGNiKSB7XHJcbiAgICAvLyBPdmVycmlkZSB0aGUgYHVzZXJPcHRpb25zYCB3aXRoIGltYWdlIGZyaWVuZGx5IG9wdGlvbnNcclxuICAgIHVzZXJPcHRpb25zID0gbWVyZ2UodXNlck9wdGlvbnMsIHtcclxuICAgICAgZXhwb3J0aW5nOiB7XHJcbiAgICAgICAgZW5hYmxlZDogZmFsc2VcclxuICAgICAgfSxcclxuICAgICAgcGxvdE9wdGlvbnM6IHtcclxuICAgICAgICBzZXJpZXM6IHtcclxuICAgICAgICAgIGxhYmVsOiB7XHJcbiAgICAgICAgICAgIGVuYWJsZWQ6IGZhbHNlXHJcbiAgICAgICAgICB9XHJcbiAgICAgICAgfVxyXG4gICAgICB9LFxyXG4gICAgICAvKiBFeHBlY3RzIHRvb2x0aXAgaW4gdGhlIGB1c2VyT3B0aW9uc2Agd2hlbiBgZm9yRXhwb3J0YCBpcyB0cnVlLlxyXG4gICAgICAgIGh0dHBzOi8vZ2l0aHViLmNvbS9oaWdoY2hhcnRzL2hpZ2hjaGFydHMvYmxvYi8zYWQ0MzBhMzUzYjgwNTZiOWU3NjRhYTRlNWNkNjgyOGFhNDc5ZGIyL2pzL3BhcnRzL0NoYXJ0LmpzI0wyNDFcclxuICAgICAgICAqL1xyXG4gICAgICB0b29sdGlwOiB7fVxyXG4gICAgfSk7XHJcblxyXG4gICAgKHVzZXJPcHRpb25zLnNlcmllcyB8fCBbXSkuZm9yRWFjaChmdW5jdGlvbiAoc2VyaWVzKSB7XHJcbiAgICAgIHNlcmllcy5hbmltYXRpb24gPSBmYWxzZTtcclxuICAgIH0pO1xyXG5cclxuICAgIC8vIEFkZCBmbGFnIHRvIGtub3cgaWYgY2hhcnQgcmVuZGVyIGhhcyBiZWVuIGNhbGxlZC5cclxuICAgIGlmICghd2luZG93Lm9uSGlnaGNoYXJ0c1JlbmRlcikge1xyXG4gICAgICB3aW5kb3cub25IaWdoY2hhcnRzUmVuZGVyID0gSGlnaGNoYXJ0cy5hZGRFdmVudCh0aGlzLCAncmVuZGVyJywgKCkgPT4ge1xyXG4gICAgICAgIHdpbmRvdy5pc1JlbmRlckNvbXBsZXRlID0gdHJ1ZTtcclxuICAgICAgfSk7XHJcbiAgICB9XHJcblxyXG4gICAgcHJvY2VlZC5hcHBseSh0aGlzLCBbdXNlck9wdGlvbnMsIGNiXSk7XHJcbiAgfSk7XHJcblxyXG4gIHdyYXAoSGlnaGNoYXJ0cy5TZXJpZXMucHJvdG90eXBlLCAnaW5pdCcsIGZ1bmN0aW9uIChwcm9jZWVkLCBjaGFydCwgb3B0aW9ucykge1xyXG4gICAgcHJvY2VlZC5hcHBseSh0aGlzLCBbY2hhcnQsIG9wdGlvbnNdKTtcclxuICB9KTtcclxuXHJcbiAgLy8gU29tZSBtYW5kYXRvcnkgYWRkaXRpb25hbCBgY2hhcnRgIGFuZCBgZXhwb3J0aW5nYCBvcHRpb25zXHJcbiAgY29uc3QgYWRkaXRpb25hbE9wdGlvbnMgPSB7XHJcbiAgICBjaGFydDoge1xyXG4gICAgICAvLyBCeSBkZWZhdWx0IGFuaW1hdGlvbiBpcyBkaXNhYmxlZFxyXG4gICAgICBhbmltYXRpb246IGZhbHNlLFxyXG4gICAgICAvLyBHZXQgdGhlIHJpZ2h0IHNpemUgdmFsdWVzXHJcbiAgICAgIGhlaWdodDogZXhwb3J0T3B0aW9ucy5oZWlnaHQsXHJcbiAgICAgIHdpZHRoOiBleHBvcnRPcHRpb25zLndpZHRoXHJcbiAgICB9LFxyXG4gICAgZXhwb3J0aW5nOiB7XHJcbiAgICAgIC8vIE5vIG5lZWQgZm9yIHRoZSBleHBvcnRpbmcgYnV0dG9uXHJcbiAgICAgIGVuYWJsZWQ6IGZhbHNlXHJcbiAgICB9XHJcbiAgfTtcclxuXHJcbiAgLy8gR2V0IHRoZSBpbnB1dCB0byBleHBvcnQgZnJvbSB0aGUgYGluc3RyYCBvcHRpb25cclxuICBjb25zdCB1c2VyT3B0aW9ucyA9IG5ldyBGdW5jdGlvbihgcmV0dXJuICR7ZXhwb3J0T3B0aW9ucy5pbnN0cn1gKSgpO1xyXG5cclxuICAvLyBHZXQgdGhlIGB0aGVtZU9wdGlvbnNgIG9wdGlvblxyXG4gIGNvbnN0IHRoZW1lT3B0aW9ucyA9IG5ldyBGdW5jdGlvbihgcmV0dXJuICR7ZXhwb3J0T3B0aW9ucy50aGVtZU9wdGlvbnN9YCkoKTtcclxuXHJcbiAgLy8gR2V0IHRoZSBgZ2xvYmFsT3B0aW9uc2Agb3B0aW9uXHJcbiAgY29uc3QgZ2xvYmFsT3B0aW9ucyA9IG5ldyBGdW5jdGlvbihgcmV0dXJuICR7ZXhwb3J0T3B0aW9ucy5nbG9iYWxPcHRpb25zfWApKCk7XHJcblxyXG4gIC8vIE1lcmdlIHRoZSBmb2xsb3dpbmcgb3B0aW9ucyBvYmplY3RzIHRvIGNyZWF0ZSBmaW5hbCBvcHRpb25zXHJcbiAgY29uc3QgZmluYWxPcHRpb25zID0gbWVyZ2UoXHJcbiAgICBmYWxzZSxcclxuICAgIHRoZW1lT3B0aW9ucyxcclxuICAgIHVzZXJPcHRpb25zLFxyXG4gICAgLy8gUGxhY2VkIGl0IGhlcmUgaW5zdGVhZCBpbiB0aGUgaW5pdCBiZWNhdXNlIG9mIHRoZSBzaXplIGlzc3Vlc1xyXG4gICAgYWRkaXRpb25hbE9wdGlvbnNcclxuICApO1xyXG5cclxuICAvLyBQcmVwYXJlIHRoZSBgY2FsbGJhY2tgIG9wdGlvblxyXG4gIGNvbnN0IGZpbmFsQ2FsbGJhY2sgPSBjdXN0b21Mb2dpY09wdGlvbnMuY2FsbGJhY2tcclxuICAgID8gbmV3IEZ1bmN0aW9uKGByZXR1cm4gJHtjdXN0b21Mb2dpY09wdGlvbnMuY2FsbGJhY2t9YCkoKVxyXG4gICAgOiBudWxsO1xyXG5cclxuICAvLyBUcmlnZ2VyIHRoZSBgY3VzdG9tQ29kZWAgb3B0aW9uXHJcbiAgaWYgKGN1c3RvbUxvZ2ljT3B0aW9ucy5jdXN0b21Db2RlKSB7XHJcbiAgICBuZXcgRnVuY3Rpb24oJ29wdGlvbnMnLCBjdXN0b21Mb2dpY09wdGlvbnMuY3VzdG9tQ29kZSkodXNlck9wdGlvbnMpO1xyXG4gIH1cclxuXHJcbiAgLy8gU2V0IHRoZSBnbG9iYWwgb3B0aW9ucyBpZiBleGlzdFxyXG4gIGlmIChnbG9iYWxPcHRpb25zKSB7XHJcbiAgICBzZXRPcHRpb25zKGdsb2JhbE9wdGlvbnMpO1xyXG4gIH1cclxuXHJcbiAgLy8gQ2FsbCB0aGUgY2hhcnQgY3JlYXRpb25cclxuICBIaWdoY2hhcnRzW2V4cG9ydE9wdGlvbnMuY29uc3RyXSgnY29udGFpbmVyJywgZmluYWxPcHRpb25zLCBmaW5hbENhbGxiYWNrKTtcclxuXHJcbiAgLy8gR2V0IHRoZSBjdXJyZW50IGdsb2JhbCBvcHRpb25zXHJcbiAgY29uc3QgZGVmYXVsdE9wdGlvbnMgPSBnZXRPcHRpb25zKCk7XHJcblxyXG4gIC8vIENsZWFyIGl0IGp1c3QgaW4gY2FzZSAoZS5nLiB0aGUgYHNldE9wdGlvbnNgIHdhcyB1c2VkIGluIHRoZSBgY3VzdG9tQ29kZWApXHJcbiAgZm9yIChjb25zdCBwcm9wIGluIGRlZmF1bHRPcHRpb25zKSB7XHJcbiAgICBpZiAodHlwZW9mIGRlZmF1bHRPcHRpb25zW3Byb3BdICE9PSAnZnVuY3Rpb24nKSB7XHJcbiAgICAgIGRlbGV0ZSBkZWZhdWx0T3B0aW9uc1twcm9wXTtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIC8vIFNldCB0aGUgZGVmYXVsdCBvcHRpb25zIGJhY2tcclxuICBzZXRPcHRpb25zKEhpZ2hjaGFydHMuc2V0T3B0aW9uc09iaik7XHJcblxyXG4gIC8vIEVtcHR5IHRoZSBjdXN0b20gZ2xvYmFsIG9wdGlvbnMgb2JqZWN0XHJcbiAgSGlnaGNoYXJ0cy5zZXRPcHRpb25zT2JqID0ge307XHJcbn1cclxuXHJcbmV4cG9ydCBkZWZhdWx0IHtcclxuICBzZXR1cEhpZ2hjaGFydHMsXHJcbiAgY3JlYXRlQ2hhcnRcclxufTtcclxuIiwiLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcclxuXHJcbkhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlclxyXG5cclxuQ29weXJpZ2h0IChjKSAyMDE2LTIwMjUsIEhpZ2hzb2Z0XHJcblxyXG5MaWNlbmNlZCB1bmRlciB0aGUgTUlUIGxpY2VuY2UuXHJcblxyXG5BZGRpdGlvbmFsbHkgYSB2YWxpZCBIaWdoY2hhcnRzIGxpY2Vuc2UgaXMgcmVxdWlyZWQgZm9yIHVzZS5cclxuXHJcblNlZSBMSUNFTlNFIGZpbGUgaW4gcm9vdCBmb3IgZGV0YWlscy5cclxuXHJcbioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXHJcblxyXG4vKipcclxuICogQG92ZXJ2aWV3IFRoaXMgbW9kdWxlIHByb3ZpZGVzIGZ1bmN0aW9ucyBmb3IgbWFuYWdpbmcgUHVwcGV0ZWVyIGJyb3dzZXJcclxuICogaW5zdGFuY2UsIGNyZWF0aW5nIGFuZCBjbGVhcmluZyBwYWdlcywgaW5qZWN0aW5nIGN1c3RvbSByZXNvdXJjZXMsXHJcbiAqIGFuZCBzZXR0aW5nIHVwIEhpZ2hjaGFydHMgZm9yIHNlcnZlci1zaWRlIHJlbmRlcmluZy4gVGhlIG1vZHVsZSBlbnN1cmVzXHJcbiAqIHRoYXQgcmVzb3VyY2VzIGFyZSBjb3JyZWN0bHkgbWFuYWdlZCBhbmQgY2FuIGhhbmRsZSBmYWlsdXJlcyBkdXJpbmdcclxuICogb3BlcmF0aW9ucyBsaWtlIGxhdW5jaGluZyB0aGUgYnJvd3NlciBvciBjcmVhdGluZyBuZXcgcGFnZXMuXHJcbiAqL1xyXG5cclxuaW1wb3J0IHsgcmVhZEZpbGVTeW5jIH0gZnJvbSAnZnMnO1xyXG5pbXBvcnQgeyBqb2luIH0gZnJvbSAncGF0aCc7XHJcblxyXG5pbXBvcnQgcHVwcGV0ZWVyIGZyb20gJ3B1cHBldGVlcic7XHJcblxyXG5pbXBvcnQgeyBnZXRDYWNoZVBhdGggfSBmcm9tICcuL2NhY2hlLmpzJztcclxuaW1wb3J0IHsgZ2V0T3B0aW9ucyB9IGZyb20gJy4vY29uZmlnLmpzJztcclxuaW1wb3J0IHsgc2V0dXBIaWdoY2hhcnRzIH0gZnJvbSAnLi9oaWdoY2hhcnRzLmpzJztcclxuaW1wb3J0IHsgbG9nLCBsb2dXaXRoU3RhY2sgfSBmcm9tICcuL2xvZ2dlci5qcyc7XHJcbmltcG9ydCB7IF9fZGlybmFtZSwgZ2V0QWJzb2x1dGVQYXRoIH0gZnJvbSAnLi91dGlscy5qcyc7XHJcblxyXG5pbXBvcnQgRXhwb3J0RXJyb3IgZnJvbSAnLi9lcnJvcnMvRXhwb3J0RXJyb3IuanMnO1xyXG5cclxuLy8gR2V0IHRoZSB0ZW1wbGF0ZSBmb3IgcGFnZXNcclxuY29uc3QgdGVtcGxhdGUgPSByZWFkRmlsZVN5bmMoXHJcbiAgam9pbihfX2Rpcm5hbWUsICd0ZW1wbGF0ZXMnLCAndGVtcGxhdGUuaHRtbCcpLFxyXG4gICd1dGY4J1xyXG4pO1xyXG5cclxuLy8gVG8gc2F2ZSB0aGUgYnJvd3NlclxyXG5sZXQgYnJvd3NlciA9IG51bGw7XHJcblxyXG4vKipcclxuICogUmV0cmlldmVzIHRoZSBleGlzdGluZyBQdXBwZXRlZXIgYnJvd3NlciBpbnN0YW5jZS5cclxuICpcclxuICogQGZ1bmN0aW9uIGdldEJyb3dzZXJcclxuICpcclxuICogQHJldHVybnMge09iamVjdH0gVGhlIFB1cHBldGVlciBicm93c2VyIGluc3RhbmNlLlxyXG4gKlxyXG4gKiBAdGhyb3dzIHtFeHBvcnRFcnJvcn0gVGhyb3dzIGFuIGBFeHBvcnRFcnJvcmAgaWYgbm8gdmFsaWQgYnJvd3NlclxyXG4gKiBoYXMgYmVlbiBjcmVhdGVkLlxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIGdldEJyb3dzZXIoKSB7XHJcbiAgaWYgKCFicm93c2VyKSB7XHJcbiAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoJ1ticm93c2VyXSBObyB2YWxpZCBicm93c2VyIGhhcyBiZWVuIGNyZWF0ZWQuJywgNTAwKTtcclxuICB9XHJcbiAgcmV0dXJuIGJyb3dzZXI7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBDcmVhdGVzIGEgUHVwcGV0ZWVyIGJyb3dzZXIgaW5zdGFuY2Ugd2l0aCB0aGUgc3BlY2lmaWVkIGFyZ3VtZW50cy5cclxuICpcclxuICogQGFzeW5jXHJcbiAqIEBmdW5jdGlvbiBjcmVhdGVCcm93c2VyXHJcbiAqXHJcbiAqIEBwYXJhbSB7QXJyYXkuPHN0cmluZz59IHB1cHBldGVlckFyZ3MgLSBBZGRpdGlvbmFsIGFyZ3VtZW50cyBmb3IgUHVwcGV0ZWVyXHJcbiAqIGxhdW5jaC5cclxuICpcclxuICogQHJldHVybnMge1Byb21pc2U8T2JqZWN0Pn0gQSBQcm9taXNlIHRoYXQgcmVzb2x2ZXMgdG8gdGhlIGNyZWF0ZWQgUHVwcGV0ZWVyXHJcbiAqIGJyb3dzZXIgaW5zdGFuY2UuXHJcbiAqXHJcbiAqIEB0aHJvd3Mge0V4cG9ydEVycm9yfSBUaHJvd3MgYW4gYEV4cG9ydEVycm9yYCBpZiBtYXggcmV0cmllcyB0byBvcGVuXHJcbiAqIGEgYnJvd3NlciBpbnN0YW5jZSBhcmUgcmVhY2hlZCwgb3IgaWYgbm8gYnJvd3NlciBpbnN0YW5jZSBpcyBmb3VuZCBhZnRlclxyXG4gKiByZXRyaWVzLlxyXG4gKi9cclxuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIGNyZWF0ZUJyb3dzZXIocHVwcGV0ZWVyQXJncykge1xyXG4gIC8vIEdldCBgZGVidWdgIGFuZCBgb3RoZXJgIG9wdGlvbnNcclxuICBjb25zdCB7IGRlYnVnLCBvdGhlciB9ID0gZ2V0T3B0aW9ucygpO1xyXG5cclxuICAvLyBHZXQgdGhlIGBkZWJ1Z2Agb3B0aW9uc1xyXG4gIGNvbnN0IHsgZW5hYmxlOiBlbmFibGVkRGVidWcsIC4uLmRlYnVnT3B0aW9ucyB9ID0gZGVidWc7XHJcblxyXG4gIC8vIExhdW5jaCBvcHRpb25zIGZvciB0aGUgYnJvd3NlciBpbnN0YW5jZVxyXG4gIGNvbnN0IGxhdW5jaE9wdGlvbnMgPSB7XHJcbiAgICBoZWFkbGVzczogb3RoZXIuYnJvd3NlclNoZWxsTW9kZSA/ICdzaGVsbCcgOiB0cnVlLFxyXG4gICAgdXNlckRhdGFEaXI6ICd0bXAnLFxyXG4gICAgYXJnczogcHVwcGV0ZWVyQXJncyB8fCBbXSxcclxuICAgIGhhbmRsZVNJR0lOVDogZmFsc2UsXHJcbiAgICBoYW5kbGVTSUdURVJNOiBmYWxzZSxcclxuICAgIGhhbmRsZVNJR0hVUDogZmFsc2UsXHJcbiAgICB3YWl0Rm9ySW5pdGlhbFBhZ2U6IGZhbHNlLFxyXG4gICAgZGVmYXVsdFZpZXdwb3J0OiBudWxsLFxyXG4gICAgLi4uKGVuYWJsZWREZWJ1ZyAmJiBkZWJ1Z09wdGlvbnMpXHJcbiAgfTtcclxuXHJcbiAgLy8gQ3JlYXRlIGEgYnJvd3NlclxyXG4gIGlmICghYnJvd3Nlcikge1xyXG4gICAgLy8gQSBjb3VudGVyIGZvciB0aGUgYnJvd3NlcidzIGxhdW5jaCByZXRyaWVzXHJcbiAgICBsZXQgdHJ5Q291bnQgPSAwO1xyXG5cclxuICAgIGNvbnN0IG9wZW4gPSBhc3luYyAoKSA9PiB7XHJcbiAgICAgIHRyeSB7XHJcbiAgICAgICAgbG9nKFxyXG4gICAgICAgICAgMyxcclxuICAgICAgICAgIGBbYnJvd3Nlcl0gQXR0ZW1wdGluZyB0byBnZXQgYSBicm93c2VyIGluc3RhbmNlICh0cnkgJHsrK3RyeUNvdW50fSkuYFxyXG4gICAgICAgICk7XHJcblxyXG4gICAgICAgIC8vIExhdW5jaCB0aGUgYnJvd3NlclxyXG4gICAgICAgIGJyb3dzZXIgPSBhd2FpdCBwdXBwZXRlZXIubGF1bmNoKGxhdW5jaE9wdGlvbnMpO1xyXG4gICAgICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgICAgIGxvZ1dpdGhTdGFjayhcclxuICAgICAgICAgIDEsXHJcbiAgICAgICAgICBlcnJvcixcclxuICAgICAgICAgICdbYnJvd3Nlcl0gRmFpbGVkIHRvIGxhdW5jaCBhIGJyb3dzZXIgaW5zdGFuY2UuJ1xyXG4gICAgICAgICk7XHJcblxyXG4gICAgICAgIC8vIFJldHJ5IHRvIGxhdW5jaCBicm93c2VyIHVudGlsIHJlYWNoaW5nIG1heCBhdHRlbXB0c1xyXG4gICAgICAgIGlmICh0cnlDb3VudCA8IDI1KSB7XHJcbiAgICAgICAgICBsb2coMywgYFticm93c2VyXSBSZXRyeSB0byBvcGVuIGEgYnJvd3NlciAoJHt0cnlDb3VudH0gb3V0IG9mIDI1KS5gKTtcclxuXHJcbiAgICAgICAgICAvLyBXYWl0IGZvciBhIDQgc2Vjb25kcyBiZWZvcmUgdHJ5aW5nIGFnYWluXHJcbiAgICAgICAgICBhd2FpdCBuZXcgUHJvbWlzZSgocmVzcG9uc2UpID0+IHNldFRpbWVvdXQocmVzcG9uc2UsIDQwMDApKTtcclxuICAgICAgICAgIGF3YWl0IG9wZW4oKTtcclxuICAgICAgICB9IGVsc2Uge1xyXG4gICAgICAgICAgdGhyb3cgZXJyb3I7XHJcbiAgICAgICAgfVxyXG4gICAgICB9XHJcbiAgICB9O1xyXG5cclxuICAgIHRyeSB7XHJcbiAgICAgIGF3YWl0IG9wZW4oKTtcclxuXHJcbiAgICAgIC8vIFNoZWxsIG1vZGUgaW5mb3JtXHJcbiAgICAgIGlmIChsYXVuY2hPcHRpb25zLmhlYWRsZXNzID09PSAnc2hlbGwnKSB7XHJcbiAgICAgICAgbG9nKDMsIGBbYnJvd3Nlcl0gTGF1bmNoZWQgYnJvd3NlciBpbiBzaGVsbCBtb2RlLmApO1xyXG4gICAgICB9XHJcblxyXG4gICAgICAvLyBEZWJ1ZyBtb2RlIGluZm9ybVxyXG4gICAgICBpZiAoZW5hYmxlZERlYnVnKSB7XHJcbiAgICAgICAgbG9nKDMsIGBbYnJvd3Nlcl0gTGF1bmNoZWQgYnJvd3NlciBpbiBkZWJ1ZyBtb2RlLmApO1xyXG4gICAgICB9XHJcbiAgICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoXHJcbiAgICAgICAgJ1ticm93c2VyXSBNYXhpbXVtIHJldHJpZXMgdG8gb3BlbiBhIGJyb3dzZXIgaW5zdGFuY2UgcmVhY2hlZC4nLFxyXG4gICAgICAgIDUwMFxyXG4gICAgICApLnNldEVycm9yKGVycm9yKTtcclxuICAgIH1cclxuXHJcbiAgICBpZiAoIWJyb3dzZXIpIHtcclxuICAgICAgdGhyb3cgbmV3IEV4cG9ydEVycm9yKCdbYnJvd3Nlcl0gQ2Fubm90IGZpbmQgYSBicm93c2VyIHRvIG9wZW4uJywgNTAwKTtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIC8vIFJldHVybiBhIGJyb3dzZXIgaW5zdGFuY2VcclxuICByZXR1cm4gYnJvd3NlcjtcclxufVxyXG5cclxuLyoqXHJcbiAqIENsb3NlcyB0aGUgUHVwcGV0ZWVyIGJyb3dzZXIgaW5zdGFuY2UgaWYgaXQgaXMgY29ubmVjdGVkLlxyXG4gKlxyXG4gKiBAYXN5bmNcclxuICogQGZ1bmN0aW9uIGNsb3NlQnJvd3NlclxyXG4gKi9cclxuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIGNsb3NlQnJvd3NlcigpIHtcclxuICAvLyBDbG9zZSB0aGUgYnJvd3NlciB3aGVuIGNvbm5lY3RlZFxyXG4gIGlmIChicm93c2VyICYmIGJyb3dzZXIuY29ubmVjdGVkKSB7XHJcbiAgICBhd2FpdCBicm93c2VyLmNsb3NlKCk7XHJcbiAgfVxyXG4gIGJyb3dzZXIgPSBudWxsO1xyXG4gIGxvZyg0LCAnW2Jyb3dzZXJdIENsb3NlZCB0aGUgYnJvd3Nlci4nKTtcclxufVxyXG5cclxuLyoqXHJcbiAqIENyZWF0ZXMgYSBuZXcgUHVwcGV0ZWVyIHBhZ2Ugd2l0aGluIGFuIGV4aXN0aW5nIGJyb3dzZXIgaW5zdGFuY2UuXHJcbiAqIFRoZSBmdW5jdGlvbiBjcmVhdGVzIGEgbmV3IHBhZ2UsIGRpc2FibGVzIGNhY2hpbmcsIHNldHMgY29udGVudCB1c2luZ1xyXG4gKiB0aGUgYF9zZXRQYWdlQ29udGVudCgpYCwgYW5kIHJldHVybnMgdGhlIGNyZWF0ZWQgUHVwcGV0ZWVyIHBhZ2UuXHJcbiAqXHJcbiAqIEBhc3luY1xyXG4gKiBAZnVuY3Rpb24gbmV3UGFnZVxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gcG9vbFJlc291cmNlIC0gVGhlIHBvb2wgcmVzb3VyY2UgdGhhdCBjb250YWlucyBgaWRgLFxyXG4gKiBgd29ya0NvdW50YCwgYW5kIGBwYWdlYC5cclxuICpcclxuICogQHRocm93cyB7RXhwb3J0RXJyb3J9IFRocm93cyBhbiBgRXhwb3J0RXJyb3JgIGlmIG5vIHZhbGlkIGJyb3dzZXJcclxuICogaGFzIGJlZW4gY29ubmVjdGVkIG9yIGlmIGEgcGFnZSBpcyBpbnZhbGlkIG9yIGNsb3NlZC5cclxuICovXHJcbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBuZXdQYWdlKHBvb2xSZXNvdXJjZSkge1xyXG4gIC8vIEVycm9yIGluIGNhc2Ugb2Ygbm8gY29ubmVjdGVkIGJyb3dzZXJcclxuICBpZiAoIWJyb3dzZXIgfHwgIWJyb3dzZXIuY29ubmVjdGVkKSB7XHJcbiAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoYFticm93c2VyXSBCcm93c2VyIGlzIG5vdCB5ZXQgY29ubmVjdGVkLmAsIDUwMCk7XHJcbiAgfVxyXG5cclxuICAvLyBDcmVhdGUgYSBwYWdlXHJcbiAgcG9vbFJlc291cmNlLnBhZ2UgPSBhd2FpdCBicm93c2VyLm5ld1BhZ2UoKTtcclxuXHJcbiAgLy8gRGlzYWJsZSBjYWNoZVxyXG4gIGF3YWl0IHBvb2xSZXNvdXJjZS5wYWdlLnNldENhY2hlRW5hYmxlZChmYWxzZSk7XHJcblxyXG4gIC8vIFNldCB0aGUgY29udGVudFxyXG4gIGF3YWl0IF9zZXRQYWdlQ29udGVudChwb29sUmVzb3VyY2UucGFnZSk7XHJcblxyXG4gIC8vIFNldCBwYWdlIGV2ZW50c1xyXG4gIF9zZXRQYWdlRXZlbnRzKHBvb2xSZXNvdXJjZS5wYWdlKTtcclxuXHJcbiAgLy8gQ2hlY2sgaWYgdGhlIHBhZ2UgaXMgY29ycmVjdGx5IGNyZWF0ZWRcclxuICBpZiAoIXBvb2xSZXNvdXJjZS5wYWdlIHx8IHBvb2xSZXNvdXJjZS5wYWdlLmlzQ2xvc2VkKCkpIHtcclxuICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcignW2Jyb3dzZXJdIFRoZSBwYWdlIGlzIGludmFsaWQgb3IgY2xvc2VkLicsIDQwMCk7XHJcbiAgfVxyXG59XHJcblxyXG4vKipcclxuICogQ2xlYXJzIHRoZSBjb250ZW50IG9mIGEgUHVwcGV0ZWVyIFBhZ2UgYmFzZWQgb24gdGhlIHNwZWNpZmllZCBtb2RlLiBMb2dzXHJcbiAqIHRocm93biBlcnJvciBpZiBjbGVhcmluZyBvZiBhIHBhZ2UncyBjb250ZW50IGZhaWxzLlxyXG4gKlxyXG4gKiBAYXN5bmNcclxuICogQGZ1bmN0aW9uIGNsZWFyUGFnZVxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gcG9vbFJlc291cmNlIC0gVGhlIHBvb2wgcmVzb3VyY2UgdGhhdCBjb250YWlucyBwYWdlIGFuZCBpZC5cclxuICogQHBhcmFtIHtib29sZWFufSBbaGFyZFJlc2V0PWZhbHNlXSAtIEEgZmxhZyBpbmRpY2F0aW5nIHRoZSB0eXBlIG9mIGNsZWFyaW5nXHJcbiAqIHRvIGJlIHBlcmZvcm1lZC4gSWYgdHJ1ZSwgbmF2aWdhdGVzIHRvIGBhYm91dDpibGFua2AgYW5kIHJlc2V0cyBjb250ZW50XHJcbiAqIGFuZCBzY3JpcHRzLiBJZiBmYWxzZSwgY2xlYXJzIHRoZSBib2R5IGNvbnRlbnQgYnkgc2V0dGluZyBhIHByZWRlZmluZWQgSFRNTFxyXG4gKiBzdHJ1Y3R1cmUuIFRoZSBkZWZhdWx0IHZhbHVlIGlzIGBmYWxzZWAuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtQcm9taXNlPGJvb2xlYW4+fSBBIFByb21pc2UgdGhhdCByZXNvbHZlcyB0byB0cnVlIHdoZW4gcGFnZVxyXG4gKiBpcyBjb3JyZWN0bHkgY2xlYXJlZCBhbmQgZmFsc2Ugd2hlbiBpdCBpcyBub3QuXHJcbiAqL1xyXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gY2xlYXJQYWdlKHBvb2xSZXNvdXJjZSwgaGFyZFJlc2V0ID0gZmFsc2UpIHtcclxuICB0cnkge1xyXG4gICAgaWYgKHBvb2xSZXNvdXJjZS5wYWdlICYmICFwb29sUmVzb3VyY2UucGFnZS5pc0Nsb3NlZCgpKSB7XHJcbiAgICAgIGlmIChoYXJkUmVzZXQpIHtcclxuICAgICAgICAvLyBOYXZpZ2F0ZSB0byBgYWJvdXQ6YmxhbmtgXHJcbiAgICAgICAgYXdhaXQgcG9vbFJlc291cmNlLnBhZ2UuZ290bygnYWJvdXQ6YmxhbmsnLCB7XHJcbiAgICAgICAgICB3YWl0VW50aWw6ICdkb21jb250ZW50bG9hZGVkJ1xyXG4gICAgICAgIH0pO1xyXG5cclxuICAgICAgICAvLyBTZXQgdGhlIGNvbnRlbnQgYW5kIGFuZCBzY3JpcHRzIGFnYWluXHJcbiAgICAgICAgYXdhaXQgX3NldFBhZ2VDb250ZW50KHBvb2xSZXNvdXJjZS5wYWdlKTtcclxuICAgICAgfSBlbHNlIHtcclxuICAgICAgICAvLyBDbGVhciBib2R5IGNvbnRlbnRcclxuICAgICAgICBhd2FpdCBwb29sUmVzb3VyY2UucGFnZS5ldmFsdWF0ZSgoKSA9PiB7XHJcbiAgICAgICAgICBkb2N1bWVudC5ib2R5LmlubmVySFRNTCA9XHJcbiAgICAgICAgICAgICc8ZGl2IGlkPVwiY2hhcnQtY29udGFpbmVyXCI+PGRpdiBpZD1cImNvbnRhaW5lclwiPjwvZGl2PjwvZGl2Pic7XHJcbiAgICAgICAgfSk7XHJcbiAgICAgIH1cclxuICAgICAgcmV0dXJuIHRydWU7XHJcbiAgICB9XHJcbiAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgIGxvZ1dpdGhTdGFjayhcclxuICAgICAgMixcclxuICAgICAgZXJyb3IsXHJcbiAgICAgIGBbcG9vbF0gUG9vbCByZXNvdXJjZSBbJHtwb29sUmVzb3VyY2UuaWR9XSAtIENvbnRlbnQgb2YgdGhlIHBhZ2UgY291bGQgbm90IGJlIGNsZWFyZWQuYFxyXG4gICAgKTtcclxuXHJcbiAgICAvLyBTZXQgdGhlIGB3b3JrTGltaXRgIHRvIGV4Y2VlZGVkIGluIG9yZGVyIHRvIHJlY3JlYXRlIHRoZSByZXNvdXJjZVxyXG4gICAgcG9vbFJlc291cmNlLndvcmtDb3VudCA9IGdldE9wdGlvbnMoKS5wb29sLndvcmtMaW1pdCArIDE7XHJcbiAgfVxyXG4gIHJldHVybiBmYWxzZTtcclxufVxyXG5cclxuLyoqXHJcbiAqIEFkZHMgY3VzdG9tIEpTIGFuZCBDU1MgcmVzb3VyY2VzIHRvIGEgUHVwcGV0ZWVyIFBhZ2UgYmFzZWQgb24gdGhlIHNwZWNpZmllZFxyXG4gKiBvcHRpb25zLlxyXG4gKlxyXG4gKiBAYXN5bmNcclxuICogQGZ1bmN0aW9uIGFkZFBhZ2VSZXNvdXJjZXNcclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IHBhZ2UgLSBUaGUgUHVwcGV0ZWVyIHBhZ2Ugb2JqZWN0IHRvIHdoaWNoIHJlc291cmNlcyB3aWxsXHJcbiAqIGJlIGFkZGVkLlxyXG4gKiBAcGFyYW0ge09iamVjdH0gY3VzdG9tTG9naWNPcHRpb25zIC0gVGhlIGNvbmZpZ3VyYXRpb24gb2JqZWN0IGNvbnRhaW5pbmdcclxuICogYGN1c3RvbUxvZ2ljYCBvcHRpb25zLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7UHJvbWlzZTxBcnJheS48T2JqZWN0Pj59IEEgUHJvbWlzZSB0aGF0IHJlc29sdmVzIHRvIGFuIGFycmF5XHJcbiAqIG9mIGluamVjdGVkIHJlc291cmNlcy5cclxuICovXHJcbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBhZGRQYWdlUmVzb3VyY2VzKHBhZ2UsIGN1c3RvbUxvZ2ljT3B0aW9ucykge1xyXG4gIC8vIEluamVjdGVkIHJlc291cmNlcyBhcnJheVxyXG4gIGNvbnN0IGluamVjdGVkUmVzb3VyY2VzID0gW107XHJcblxyXG4gIC8vIFVzZSByZXNvdXJjZXNcclxuICBjb25zdCByZXNvdXJjZXMgPSBjdXN0b21Mb2dpY09wdGlvbnMucmVzb3VyY2VzO1xyXG4gIGlmIChyZXNvdXJjZXMpIHtcclxuICAgIGNvbnN0IGluamVjdGVkSnMgPSBbXTtcclxuXHJcbiAgICAvLyBMb2FkIGN1c3RvbSBKUyBjb2RlXHJcbiAgICBpZiAocmVzb3VyY2VzLmpzKSB7XHJcbiAgICAgIGluamVjdGVkSnMucHVzaCh7XHJcbiAgICAgICAgY29udGVudDogcmVzb3VyY2VzLmpzXHJcbiAgICAgIH0pO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIExvYWQgc2NyaXB0cyBmcm9tIGFsbCBjdXN0b20gZmlsZXNcclxuICAgIGlmIChyZXNvdXJjZXMuZmlsZXMpIHtcclxuICAgICAgZm9yIChjb25zdCBmaWxlIG9mIHJlc291cmNlcy5maWxlcykge1xyXG4gICAgICAgIGNvbnN0IGlzTG9jYWwgPSBmaWxlLnN0YXJ0c1dpdGgoJ2h0dHAnKSA/IGZhbHNlIDogdHJ1ZTtcclxuXHJcbiAgICAgICAgLy8gQWRkIGVhY2ggY3VzdG9tIHNjcmlwdCBmcm9tIHJlc291cmNlcycgZmlsZXNcclxuICAgICAgICBpbmplY3RlZEpzLnB1c2goXHJcbiAgICAgICAgICBpc0xvY2FsXHJcbiAgICAgICAgICAgID8ge1xyXG4gICAgICAgICAgICAgICAgY29udGVudDogcmVhZEZpbGVTeW5jKGdldEFic29sdXRlUGF0aChmaWxlKSwgJ3V0ZjgnKVxyXG4gICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgOiB7XHJcbiAgICAgICAgICAgICAgICB1cmw6IGZpbGVcclxuICAgICAgICAgICAgICB9XHJcbiAgICAgICAgKTtcclxuICAgICAgfVxyXG4gICAgfVxyXG5cclxuICAgIGZvciAoY29uc3QganNSZXNvdXJjZSBvZiBpbmplY3RlZEpzKSB7XHJcbiAgICAgIHRyeSB7XHJcbiAgICAgICAgaW5qZWN0ZWRSZXNvdXJjZXMucHVzaChhd2FpdCBwYWdlLmFkZFNjcmlwdFRhZyhqc1Jlc291cmNlKSk7XHJcbiAgICAgIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICAgICAgbG9nV2l0aFN0YWNrKDIsIGVycm9yLCBgW2Jyb3dzZXJdIFRoZSBKUyByZXNvdXJjZSBjYW5ub3QgYmUgbG9hZGVkLmApO1xyXG4gICAgICB9XHJcbiAgICB9XHJcbiAgICBpbmplY3RlZEpzLmxlbmd0aCA9IDA7XHJcblxyXG4gICAgLy8gTG9hZCBDU1NcclxuICAgIGNvbnN0IGluamVjdGVkQ3NzID0gW107XHJcbiAgICBpZiAocmVzb3VyY2VzLmNzcykge1xyXG4gICAgICBsZXQgY3NzSW1wb3J0cyA9IHJlc291cmNlcy5jc3MubWF0Y2goL0BpbXBvcnRcXHMqKFteO10qKTsvZyk7XHJcbiAgICAgIGlmIChjc3NJbXBvcnRzKSB7XHJcbiAgICAgICAgLy8gSGFuZGxlIGNzcyBzZWN0aW9uXHJcbiAgICAgICAgZm9yIChsZXQgY3NzSW1wb3J0UGF0aCBvZiBjc3NJbXBvcnRzKSB7XHJcbiAgICAgICAgICBpZiAoY3NzSW1wb3J0UGF0aCkge1xyXG4gICAgICAgICAgICBjc3NJbXBvcnRQYXRoID0gY3NzSW1wb3J0UGF0aFxyXG4gICAgICAgICAgICAgIC5yZXBsYWNlKCd1cmwoJywgJycpXHJcbiAgICAgICAgICAgICAgLnJlcGxhY2UoJ0BpbXBvcnQnLCAnJylcclxuICAgICAgICAgICAgICAucmVwbGFjZSgvXCIvZywgJycpXHJcbiAgICAgICAgICAgICAgLnJlcGxhY2UoLycvZywgJycpXHJcbiAgICAgICAgICAgICAgLnJlcGxhY2UoLzsvLCAnJylcclxuICAgICAgICAgICAgICAucmVwbGFjZSgvXFwpL2csICcnKVxyXG4gICAgICAgICAgICAgIC50cmltKCk7XHJcblxyXG4gICAgICAgICAgICAvLyBBZGQgZWFjaCBjdXN0b20gY3NzIGZyb20gcmVzb3VyY2VzXHJcbiAgICAgICAgICAgIGlmIChjc3NJbXBvcnRQYXRoLnN0YXJ0c1dpdGgoJ2h0dHAnKSkge1xyXG4gICAgICAgICAgICAgIGluamVjdGVkQ3NzLnB1c2goe1xyXG4gICAgICAgICAgICAgICAgdXJsOiBjc3NJbXBvcnRQYXRoXHJcbiAgICAgICAgICAgICAgfSk7XHJcbiAgICAgICAgICAgIH0gZWxzZSBpZiAoY3VzdG9tTG9naWNPcHRpb25zLmFsbG93RmlsZVJlc291cmNlcykge1xyXG4gICAgICAgICAgICAgIGluamVjdGVkQ3NzLnB1c2goe1xyXG4gICAgICAgICAgICAgICAgcGF0aDogZ2V0QWJzb2x1dGVQYXRoKGNzc0ltcG9ydFBhdGgpXHJcbiAgICAgICAgICAgICAgfSk7XHJcbiAgICAgICAgICAgIH1cclxuICAgICAgICAgIH1cclxuICAgICAgICB9XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIC8vIFRoZSByZXN0IG9mIHRoZSBDU1Mgc2VjdGlvbiB3aWxsIGJlIGNvbnRlbnQgYnkgbm93XHJcbiAgICAgIGluamVjdGVkQ3NzLnB1c2goe1xyXG4gICAgICAgIGNvbnRlbnQ6IHJlc291cmNlcy5jc3MucmVwbGFjZSgvQGltcG9ydFxccyooW147XSopOy9nLCAnJykgfHwgJyAnXHJcbiAgICAgIH0pO1xyXG5cclxuICAgICAgZm9yIChjb25zdCBjc3NSZXNvdXJjZSBvZiBpbmplY3RlZENzcykge1xyXG4gICAgICAgIHRyeSB7XHJcbiAgICAgICAgICBpbmplY3RlZFJlc291cmNlcy5wdXNoKGF3YWl0IHBhZ2UuYWRkU3R5bGVUYWcoY3NzUmVzb3VyY2UpKTtcclxuICAgICAgICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgICAgICAgbG9nV2l0aFN0YWNrKFxyXG4gICAgICAgICAgICAyLFxyXG4gICAgICAgICAgICBlcnJvcixcclxuICAgICAgICAgICAgYFticm93c2VyXSBUaGUgQ1NTIHJlc291cmNlIGNhbm5vdCBiZSBsb2FkZWQuYFxyXG4gICAgICAgICAgKTtcclxuICAgICAgICB9XHJcbiAgICAgIH1cclxuICAgICAgaW5qZWN0ZWRDc3MubGVuZ3RoID0gMDtcclxuICAgIH1cclxuICB9XHJcbiAgcmV0dXJuIGluamVjdGVkUmVzb3VyY2VzO1xyXG59XHJcblxyXG4vKipcclxuICogQ2xlYXJzIG91dCBhbGwgc3RhdGUgc2V0IG9uIHRoZSBwYWdlIHdpdGggYGFkZFNjcmlwdFRhZ2AgYW5kIGBhZGRTdHlsZVRhZ2AuXHJcbiAqIFJlbW92ZXMgaW5qZWN0ZWQgcmVzb3VyY2VzIGFuZCByZXNldHMgQ1NTIGFuZCBzY3JpcHQgdGFncyBvbiB0aGUgcGFnZS5cclxuICogQWRkaXRpb25hbGx5LCBpdCBkZXN0cm95cyBwcmV2aW91c2x5IGV4aXN0aW5nIGNoYXJ0cy5cclxuICpcclxuICogQGFzeW5jXHJcbiAqIEBmdW5jdGlvbiBjbGVhclBhZ2VSZXNvdXJjZXNcclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IHBhZ2UgLSBUaGUgUHVwcGV0ZWVyIHBhZ2Ugb2JqZWN0IGZyb20gd2hpY2ggcmVzb3VyY2VzIHdpbGxcclxuICogYmUgY2xlYXJlZC5cclxuICogQHBhcmFtIHtBcnJheS48T2JqZWN0Pn0gaW5qZWN0ZWRSZXNvdXJjZXMgLSBBcnJheSBvZiBpbmplY3RlZCByZXNvdXJjZXNcclxuICogdG8gYmUgY2xlYXJlZC5cclxuICovXHJcbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBjbGVhclBhZ2VSZXNvdXJjZXMocGFnZSwgaW5qZWN0ZWRSZXNvdXJjZXMpIHtcclxuICB0cnkge1xyXG4gICAgZm9yIChjb25zdCByZXNvdXJjZSBvZiBpbmplY3RlZFJlc291cmNlcykge1xyXG4gICAgICBhd2FpdCByZXNvdXJjZS5kaXNwb3NlKCk7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gRGVzdHJveSBvbGQgY2hhcnRzIGFmdGVyIGV4cG9ydCBpcyBkb25lIGFuZCByZXNldCBhbGwgQ1NTIGFuZCBzY3JpcHQgdGFnc1xyXG4gICAgYXdhaXQgcGFnZS5ldmFsdWF0ZSgoKSA9PiB7XHJcbiAgICAgIC8vIFdlIGFyZSBub3QgZ3VhcmFudGVlZCB0aGF0IEhpZ2hjaGFydHMgaXMgbG9hZGVkLCB3aGVuIGRvaW5nIFNWRyBleHBvcnRzXHJcbiAgICAgIGlmICh0eXBlb2YgSGlnaGNoYXJ0cyAhPT0gJ3VuZGVmaW5lZCcpIHtcclxuICAgICAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgbm8tdW5kZWZcclxuICAgICAgICBjb25zdCBvbGRDaGFydHMgPSBIaWdoY2hhcnRzLmNoYXJ0cztcclxuXHJcbiAgICAgICAgLy8gQ2hlY2sgaW4gYW55IGFscmVhZHkgZXhpc3RpbmcgY2hhcnRzXHJcbiAgICAgICAgaWYgKEFycmF5LmlzQXJyYXkob2xkQ2hhcnRzKSAmJiBvbGRDaGFydHMubGVuZ3RoKSB7XHJcbiAgICAgICAgICAvLyBEZXN0cm95IG9sZCBjaGFydHNcclxuICAgICAgICAgIGZvciAoY29uc3Qgb2xkQ2hhcnQgb2Ygb2xkQ2hhcnRzKSB7XHJcbiAgICAgICAgICAgIG9sZENoYXJ0ICYmIG9sZENoYXJ0LmRlc3Ryb3koKTtcclxuICAgICAgICAgICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIG5vLXVuZGVmXHJcbiAgICAgICAgICAgIEhpZ2hjaGFydHMuY2hhcnRzLnNoaWZ0KCk7XHJcbiAgICAgICAgICB9XHJcbiAgICAgICAgfVxyXG4gICAgICB9XHJcblxyXG4gICAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgbm8tdW5kZWZcclxuICAgICAgY29uc3QgWy4uLnNjcmlwdHNUb1JlbW92ZV0gPSBkb2N1bWVudC5nZXRFbGVtZW50c0J5VGFnTmFtZSgnc2NyaXB0Jyk7XHJcbiAgICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBuby11bmRlZlxyXG4gICAgICBjb25zdCBbLCAuLi5zdHlsZXNUb1JlbW92ZV0gPSBkb2N1bWVudC5nZXRFbGVtZW50c0J5VGFnTmFtZSgnc3R5bGUnKTtcclxuICAgICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIG5vLXVuZGVmXHJcbiAgICAgIGNvbnN0IFsuLi5saW5rc1RvUmVtb3ZlXSA9IGRvY3VtZW50LmdldEVsZW1lbnRzQnlUYWdOYW1lKCdsaW5rJyk7XHJcblxyXG4gICAgICAvLyBSZW1vdmUgdGFnc1xyXG4gICAgICBmb3IgKGNvbnN0IGVsZW1lbnQgb2YgW1xyXG4gICAgICAgIC4uLnNjcmlwdHNUb1JlbW92ZSxcclxuICAgICAgICAuLi5zdHlsZXNUb1JlbW92ZSxcclxuICAgICAgICAuLi5saW5rc1RvUmVtb3ZlXHJcbiAgICAgIF0pIHtcclxuICAgICAgICBlbGVtZW50LnJlbW92ZSgpO1xyXG4gICAgICB9XHJcbiAgICB9KTtcclxuICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgbG9nV2l0aFN0YWNrKDIsIGVycm9yLCBgW2Jyb3dzZXJdIENvdWxkIG5vdCBjbGVhciBwYWdlJ3MgcmVzb3VyY2VzLmApO1xyXG4gIH1cclxufVxyXG5cclxuLyoqXHJcbiAqIFNldHMgdGhlIGNvbnRlbnQgZm9yIGEgUHVwcGV0ZWVyIFBhZ2UgdXNpbmcgYSBwcmVkZWZpbmVkIHRlbXBsYXRlXHJcbiAqIGFuZCBhZGRpdGlvbmFsIHNjcmlwdHMuXHJcbiAqXHJcbiAqIEBhc3luY1xyXG4gKiBAZnVuY3Rpb24gX3NldFBhZ2VDb250ZW50XHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBwYWdlIC0gVGhlIFB1cHBldGVlciBwYWdlIG9iamVjdCB0byB3aGljaCB0aGUgY29udGVudFxyXG4gKiBpcyBiZWluZyBzZXQuXHJcbiAqL1xyXG5hc3luYyBmdW5jdGlvbiBfc2V0UGFnZUNvbnRlbnQocGFnZSkge1xyXG4gIC8vIFNldCB0aGUgaW5pdGlhbCBwYWdlIGNvbnRlbnRcclxuICBhd2FpdCBwYWdlLnNldENvbnRlbnQodGVtcGxhdGUsIHsgd2FpdFVudGlsOiAnZG9tY29udGVudGxvYWRlZCcgfSk7XHJcblxyXG4gIC8vIEFkZCBhbGwgcmVnaXN0ZXJlZCBIaWdjaGFydHMgc2NyaXB0cywgcXVpdGUgZGVtYW5kaW5nXHJcbiAgYXdhaXQgcGFnZS5hZGRTY3JpcHRUYWcoeyBwYXRoOiBqb2luKGdldENhY2hlUGF0aCgpLCAnc291cmNlcy5qcycpIH0pO1xyXG5cclxuICAvLyBTZXQgdGhlIGluaXRpYWwgYGFuaW1PYmplY3RgIGZvciBIaWdoY2hhcnRzXHJcbiAgYXdhaXQgcGFnZS5ldmFsdWF0ZShzZXR1cEhpZ2hjaGFydHMpO1xyXG59XHJcblxyXG4vKipcclxuICogU2V0IGV2ZW50cyAobGlrZSBgcGFnZWVycm9yYCBhbmQgYGNvbnNvbGVgKSBmb3IgYSBQdXBwZXRlZXIgUGFnZSBpbiBvcmRlclxyXG4gKiB0byBjYXRjaCBhbmQgZGlzcGxheSBlcnJvcnMgYW5kIGNvbnNvbGUgbG9ncyBmcm9tIHRoZSB3aW5kb3cgY29udGV4dC5cclxuICpcclxuICogQGZ1bmN0aW9uIF9zZXRQYWdlRXZlbnRzXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBwYWdlIC0gVGhlIFB1cHBldGVlciBwYWdlIG9iamVjdCB0byB3aGljaCB0aGUgbGlzdGVuZXJzXHJcbiAqIGFyZSBiZWluZyBzZXQuXHJcbiAqL1xyXG5mdW5jdGlvbiBfc2V0UGFnZUV2ZW50cyhwYWdlKSB7XHJcbiAgLy8gR2V0IGBkZWJ1Z2Agb3B0aW9uc1xyXG4gIGNvbnN0IHsgZGVidWcgfSA9IGdldE9wdGlvbnMoKTtcclxuXHJcbiAgLy8gU2V0IHRoZSBgcGFnZWVycm9yYCBsaXN0ZW5lclxyXG4gIHBhZ2Uub24oJ3BhZ2VlcnJvcicsIGFzeW5jICgpID0+IHtcclxuICAgIC8vIEl0IHdvdWxkIHNlZW0gbGlrZSB0aGlzIG1heSBmaXJlIGF0IHRoZSBzYW1lIHRpbWUgb3Igc2hvcnRseSBiZWZvcmVcclxuICAgIC8vIGEgcGFnZSBpcyBjbG9zZWQuXHJcbiAgICBpZiAocGFnZS5pc0Nsb3NlZCgpKSB7XHJcbiAgICAgIHJldHVybjtcclxuICAgIH1cclxuICB9KTtcclxuXHJcbiAgLy8gU2V0IHRoZSBgY29uc29sZWAgbGlzdGVuZXIsIGlmIG5lZWRlZFxyXG4gIGlmIChkZWJ1Zy5lbmFibGUgJiYgZGVidWcubGlzdGVuVG9Db25zb2xlKSB7XHJcbiAgICBwYWdlLm9uKCdjb25zb2xlJywgKG1lc3NhZ2UpID0+IHtcclxuICAgICAgY29uc29sZS5sb2coYFtkZWJ1Z10gJHttZXNzYWdlLnRleHQoKX1gKTtcclxuICAgIH0pO1xyXG4gIH1cclxufVxyXG5cclxuZXhwb3J0IGRlZmF1bHQge1xyXG4gIGdldEJyb3dzZXIsXHJcbiAgY3JlYXRlQnJvd3NlcixcclxuICBjbG9zZUJyb3dzZXIsXHJcbiAgbmV3UGFnZSxcclxuICBjbGVhclBhZ2UsXHJcbiAgYWRkUGFnZVJlc291cmNlcyxcclxuICBjbGVhclBhZ2VSZXNvdXJjZXNcclxufTtcclxuIiwiLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcclxuXHJcbkhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlclxyXG5cclxuQ29weXJpZ2h0IChjKSAyMDE2LTIwMjUsIEhpZ2hzb2Z0XHJcblxyXG5MaWNlbmNlZCB1bmRlciB0aGUgTUlUIGxpY2VuY2UuXHJcblxyXG5BZGRpdGlvbmFsbHkgYSB2YWxpZCBIaWdoY2hhcnRzIGxpY2Vuc2UgaXMgcmVxdWlyZWQgZm9yIHVzZS5cclxuXHJcblNlZSBMSUNFTlNFIGZpbGUgaW4gcm9vdCBmb3IgZGV0YWlscy5cclxuXHJcbioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXHJcblxyXG4vKipcclxuICogVGhlIENTUyB0byBiZSB1c2VkIG9uIHRoZSBleHBvcnRlZCBwYWdlLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7c3RyaW5nfSBUaGUgQ1NTIGNvbmZpZ3VyYXRpb24uXHJcbiAqL1xyXG5leHBvcnQgZGVmYXVsdCAoKSA9PiBgXHJcblxyXG5odG1sLCBib2R5IHtcclxuICBtYXJnaW46IDA7XHJcbiAgcGFkZGluZzogMDtcclxuICBib3gtc2l6aW5nOiBib3JkZXItYm94O1xyXG59XHJcblxyXG4jdGFibGUtZGl2LCAjc2xpZGVycywgI2RhdGF0YWJsZSwgI2NvbnRyb2xzLCAubGQtcm93IHtcclxuICBkaXNwbGF5OiBub25lO1xyXG4gIGhlaWdodDogMDtcclxufVxyXG5cclxuI2NoYXJ0LWNvbnRhaW5lciB7XHJcbiAgYm94LXNpemluZzogYm9yZGVyLWJveDtcclxuICBtYXJnaW46IDA7XHJcbiAgb3ZlcmZsb3c6IGF1dG87XHJcbiAgZm9udC1zaXplOiAwO1xyXG59XHJcblxyXG4jY2hhcnQtY29udGFpbmVyID4gZmlndXJlLCBkaXYge1xyXG4gIG1hcmdpbi10b3A6IDAgIWltcG9ydGFudDtcclxuICBtYXJnaW4tYm90dG9tOiAwICFpbXBvcnRhbnQ7XHJcbn1cclxuXHJcbmA7XHJcbiIsIi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXHJcblxyXG5IaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXJcclxuXHJcbkNvcHlyaWdodCAoYykgMjAxNi0yMDI1LCBIaWdoc29mdFxyXG5cclxuTGljZW5jZWQgdW5kZXIgdGhlIE1JVCBsaWNlbmNlLlxyXG5cclxuQWRkaXRpb25hbGx5IGEgdmFsaWQgSGlnaGNoYXJ0cyBsaWNlbnNlIGlzIHJlcXVpcmVkIGZvciB1c2UuXHJcblxyXG5TZWUgTElDRU5TRSBmaWxlIGluIHJvb3QgZm9yIGRldGFpbHMuXHJcblxyXG4qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xyXG5cclxuaW1wb3J0IGNzc1RlbXBsYXRlIGZyb20gJy4vY3NzLmpzJztcclxuXHJcbi8qKlxyXG4gKiBUaGUgU1ZHIHRlbXBsYXRlIHRvIHVzZSB3aGVuIGxvYWRpbmcgU1ZHIGNvbnRlbnQgdG8gYmUgZXhwb3J0ZWQuXHJcbiAqXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSBzdmcgLSBUaGUgU1ZHIGlucHV0IGNvbnRlbnQgdG8gYmUgZXhwb3J0ZWQuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtzdHJpbmd9IFRoZSBTVkcgdGVtcGxhdGUuXHJcbiAqL1xyXG5leHBvcnQgZGVmYXVsdCAoc3ZnKSA9PiBgXHJcbjwhRE9DVFlQRSBodG1sPlxyXG48aHRtbCBsYW5nPSdlbi1VUyc+XHJcbiAgPGhlYWQ+XHJcbiAgICA8bWV0YSBodHRwLWVxdWl2PVwiQ29udGVudC1UeXBlXCIgY29udGVudD1cInRleHQvaHRtbDsgY2hhcnNldD11dGYtOFwiPlxyXG4gICAgPHRpdGxlPkhpZ2hjaGFydHMgRXhwb3J0PC90aXRsZT5cclxuICA8L2hlYWQ+XHJcbiAgPHN0eWxlPlxyXG4gICAgJHtjc3NUZW1wbGF0ZSgpfVxyXG4gIDwvc3R5bGU+XHJcbiAgPGJvZHk+XHJcbiAgICA8ZGl2IGlkPVwiY2hhcnQtY29udGFpbmVyXCI+XHJcbiAgICAgICR7c3ZnfVxyXG4gICAgPC9kaXY+XHJcbiAgPC9ib2R5PlxyXG48L2h0bWw+XHJcblxyXG5gO1xyXG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxyXG5cclxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXHJcblxyXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNSwgSGlnaHNvZnRcclxuXHJcbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cclxuXHJcbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxyXG5cclxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxyXG5cclxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cclxuXHJcbi8qKlxyXG4gKiBAb3ZlcnZpZXcgVGhpcyBtb2R1bGUgaGFuZGxlcyBjaGFydCBleHBvcnQgZnVuY3Rpb25hbGl0eSB1c2luZyBQdXBwZXRlZXIuXHJcbiAqIEl0IHN1cHBvcnRzIGV4cG9ydGluZyBjaGFydHMgYXMgU1ZHLCBQTkcsIEpQRUcsIGFuZCBQREYgZm9ybWF0cy4gVGhlIG1vZHVsZVxyXG4gKiBtYW5hZ2VzIHBhZ2UgcmVzb3VyY2VzLCBzZXRzIHVwIHRoZSBleHBvcnQgZW52aXJvbm1lbnQsIGFuZCBwcm9jZXNzZXMgY2hhcnRcclxuICogY29uZmlndXJhdGlvbnMgb3IgU1ZHIGlucHV0cyBmb3IgcmVuZGVyaW5nLiBFeHBvcnRzIHRvIGEgY2hhcnQgZnJvbSBhIHBhZ2VcclxuICogdXNpbmcgUHVwcGV0ZWVyLlxyXG4gKi9cclxuXHJcbmltcG9ydCB7IGFkZFBhZ2VSZXNvdXJjZXMsIGNsZWFyUGFnZVJlc291cmNlcyB9IGZyb20gJy4vYnJvd3Nlci5qcyc7XHJcbmltcG9ydCB7IGNyZWF0ZUNoYXJ0IH0gZnJvbSAnLi9oaWdoY2hhcnRzLmpzJztcclxuaW1wb3J0IHsgbG9nIH0gZnJvbSAnLi9sb2dnZXIuanMnO1xyXG5cclxuaW1wb3J0IHN2Z1RlbXBsYXRlIGZyb20gJy4uL3RlbXBsYXRlcy9zdmdFeHBvcnQvc3ZnRXhwb3J0LmpzJztcclxuXHJcbmltcG9ydCBFeHBvcnRFcnJvciBmcm9tICcuL2Vycm9ycy9FeHBvcnRFcnJvci5qcyc7XHJcblxyXG4vKipcclxuICogRXhwb3J0cyB0byBhIGNoYXJ0IGZyb20gYSBwYWdlIHVzaW5nIFB1cHBldGVlci5cclxuICpcclxuICogQGFzeW5jXHJcbiAqIEBmdW5jdGlvbiBwdXBwZXRlZXJFeHBvcnRcclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IHBhZ2UgLSBQdXBwZXRlZXIgcGFnZSBvYmplY3QuXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBleHBvcnRPcHRpb25zIC0gVGhlIGNvbmZpZ3VyYXRpb24gb2JqZWN0IGNvbnRhaW5pbmcgYGV4cG9ydGBcclxuICogb3B0aW9ucy5cclxuICogQHBhcmFtIHtPYmplY3R9IGN1c3RvbUxvZ2ljT3B0aW9ucyAtIFRoZSBjb25maWd1cmF0aW9uIG9iamVjdCBjb250YWluaW5nXHJcbiAqIGBjdXN0b21Mb2dpY2Agb3B0aW9ucy5cclxuICpcclxuICogQHJldHVybnMge1Byb21pc2U8KHN0cmluZ3xCdWZmZXJ8RXhwb3J0RXJyb3IpPn0gQSBQcm9taXNlIHRoYXQgcmVzb2x2ZXNcclxuICogdG8gdGhlIGV4cG9ydGVkIGRhdGEgb3IgcmVqZWN0aW5nIHdpdGggYW4gYEV4cG9ydEVycm9yYC5cclxuICpcclxuICogQHRocm93cyB7RXhwb3J0RXJyb3J9IFRocm93cyBhbiBgRXhwb3J0RXJyb3JgIGlmIGV4cG9ydCB0byBhbiB1bnN1cHBvcnRlZFxyXG4gKiBvdXRwdXQgZm9ybWF0IG9jY3Vycy5cclxuICovXHJcbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBwdXBwZXRlZXJFeHBvcnQocGFnZSwgZXhwb3J0T3B0aW9ucywgY3VzdG9tTG9naWNPcHRpb25zKSB7XHJcbiAgLy8gSW5qZWN0ZWQgcmVzb3VyY2VzIGFycmF5IChhZGRpdGlvbmFsIEpTIGFuZCBDU1MpXHJcbiAgY29uc3QgaW5qZWN0ZWRSZXNvdXJjZXMgPSBbXTtcclxuXHJcbiAgdHJ5IHtcclxuICAgIGxldCBpc1NWRyA9IGZhbHNlO1xyXG5cclxuICAgIC8vIERlY2lkZSBvbiB0aGUgZXhwb3J0IG1ldGhvZFxyXG4gICAgaWYgKGV4cG9ydE9wdGlvbnMuc3ZnKSB7XHJcbiAgICAgIGxvZyg0LCAnW2V4cG9ydF0gVHJlYXRpbmcgYXMgU1ZHIGlucHV0LicpO1xyXG5cclxuICAgICAgLy8gSWYgdGhlIGB0eXBlYCBpcyBhbHNvIFNWRywgcmV0dXJuIHRoZSBpbnB1dFxyXG4gICAgICBpZiAoZXhwb3J0T3B0aW9ucy50eXBlID09PSAnc3ZnJykge1xyXG4gICAgICAgIHJldHVybiBleHBvcnRPcHRpb25zLnN2ZztcclxuICAgICAgfVxyXG5cclxuICAgICAgLy8gTWFyayBhcyBTVkcgZXhwb3J0IGZvciB0aGUgbGF0ZXIgc2l6ZSBjb3JyZWN0aW9uc1xyXG4gICAgICBpc1NWRyA9IHRydWU7XHJcblxyXG4gICAgICAvLyBTVkcgZXhwb3J0XHJcbiAgICAgIGF3YWl0IHBhZ2Uuc2V0Q29udGVudChzdmdUZW1wbGF0ZShleHBvcnRPcHRpb25zLnN2ZyksIHtcclxuICAgICAgICB3YWl0VW50aWw6ICdkb21jb250ZW50bG9hZGVkJ1xyXG4gICAgICB9KTtcclxuICAgIH0gZWxzZSB7XHJcbiAgICAgIGxvZyg0LCAnW2V4cG9ydF0gVHJlYXRpbmcgYXMgSlNPTiBjb25maWcuJyk7XHJcblxyXG4gICAgICAvLyBPcHRpb25zIGV4cG9ydFxyXG4gICAgICBhd2FpdCBwYWdlLmV2YWx1YXRlKGNyZWF0ZUNoYXJ0LCBleHBvcnRPcHRpb25zLCBjdXN0b21Mb2dpY09wdGlvbnMpO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIEtlZXBzIHRyYWNrIG9mIGFsbCByZXNvdXJjZXMgYWRkZWQgb24gdGhlIHBhZ2Ugd2l0aCBhZGRYWFhUYWcuIGV0Y1xyXG4gICAgLy8gSXQncyBWSVRBTCB0aGF0IGFsbCBhZGRlZCByZXNvdXJjZXMgZW5kcyB1cCBoZXJlIHNvIHdlIGNhbiBjbGVhciB0aGluZ3NcclxuICAgIC8vIG91dCB3aGVuIGRvaW5nIGEgbmV3IGV4cG9ydCBpbiB0aGUgc2FtZSBwYWdlIVxyXG4gICAgaW5qZWN0ZWRSZXNvdXJjZXMucHVzaChcclxuICAgICAgLi4uKGF3YWl0IGFkZFBhZ2VSZXNvdXJjZXMocGFnZSwgY3VzdG9tTG9naWNPcHRpb25zKSlcclxuICAgICk7XHJcblxyXG4gICAgLy8gR2V0IHRoZSByZWFsIGNoYXJ0IHNpemUgYW5kIHNldCB0aGUgem9vbSBhY2NvcmRpbmdseVxyXG4gICAgY29uc3Qgc2l6ZSA9IGlzU1ZHXHJcbiAgICAgID8gYXdhaXQgcGFnZS5ldmFsdWF0ZSgoc2NhbGUpID0+IHtcclxuICAgICAgICAgIGNvbnN0IHN2Z0VsZW1lbnQgPSBkb2N1bWVudC5xdWVyeVNlbGVjdG9yKFxyXG4gICAgICAgICAgICAnI2NoYXJ0LWNvbnRhaW5lciBzdmc6Zmlyc3Qtb2YtdHlwZSdcclxuICAgICAgICAgICk7XHJcblxyXG4gICAgICAgICAgLy8gR2V0IHRoZSB2YWx1ZXMgY29ycmVjdGx5IHNjYWxlZFxyXG4gICAgICAgICAgY29uc3QgY2hhcnRIZWlnaHQgPSBzdmdFbGVtZW50LmhlaWdodC5iYXNlVmFsLnZhbHVlICogc2NhbGU7XHJcbiAgICAgICAgICBjb25zdCBjaGFydFdpZHRoID0gc3ZnRWxlbWVudC53aWR0aC5iYXNlVmFsLnZhbHVlICogc2NhbGU7XHJcblxyXG4gICAgICAgICAgLy8gSW4gY2FzZSBvZiBTVkcgdGhlIHpvb20gbXVzdCBiZSBzZXQgZGlyZWN0bHkgZm9yIGJvZHkgYXMgc2NhbGVcclxuICAgICAgICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBuby11bmRlZlxyXG4gICAgICAgICAgZG9jdW1lbnQuYm9keS5zdHlsZS56b29tID0gc2NhbGU7XHJcblxyXG4gICAgICAgICAgLy8gU2V0IHRoZSBtYXJnaW4gdG8gMHB4XHJcbiAgICAgICAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgbm8tdW5kZWZcclxuICAgICAgICAgIGRvY3VtZW50LmJvZHkuc3R5bGUubWFyZ2luID0gJzBweCc7XHJcblxyXG4gICAgICAgICAgcmV0dXJuIHtcclxuICAgICAgICAgICAgY2hhcnRIZWlnaHQsXHJcbiAgICAgICAgICAgIGNoYXJ0V2lkdGhcclxuICAgICAgICAgIH07XHJcbiAgICAgICAgfSwgcGFyc2VGbG9hdChleHBvcnRPcHRpb25zLnNjYWxlKSlcclxuICAgICAgOiBhd2FpdCBwYWdlLmV2YWx1YXRlKCgpID0+IHtcclxuICAgICAgICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBuby11bmRlZlxyXG4gICAgICAgICAgY29uc3QgeyBjaGFydEhlaWdodCwgY2hhcnRXaWR0aCB9ID0gd2luZG93LkhpZ2hjaGFydHMuY2hhcnRzWzBdO1xyXG5cclxuICAgICAgICAgIC8vIE5vIG5lZWQgZm9yIHN1Y2ggc2NhbGUgbWFuaXB1bGF0aW9uIGluIGNhc2Ugb2Ygb3RoZXIgdHlwZXNcclxuICAgICAgICAgIC8vIG9mIGV4cG9ydHMuIFJlc2V0IHRoZSB6b29tIGZvciBvdGhlciBleHBvcnRzIHRoYW4gdG8gU1ZHc1xyXG4gICAgICAgICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIG5vLXVuZGVmXHJcbiAgICAgICAgICBkb2N1bWVudC5ib2R5LnN0eWxlLnpvb20gPSAxO1xyXG5cclxuICAgICAgICAgIHJldHVybiB7XHJcbiAgICAgICAgICAgIGNoYXJ0SGVpZ2h0LFxyXG4gICAgICAgICAgICBjaGFydFdpZHRoXHJcbiAgICAgICAgICB9O1xyXG4gICAgICAgIH0pO1xyXG5cclxuICAgIC8vIEdldCB0aGUgY2xpcCByZWdpb24gZm9yIHRoZSBwYWdlXHJcbiAgICBjb25zdCB7IHgsIHkgfSA9IGF3YWl0IF9nZXRDbGlwUmVnaW9uKHBhZ2UpO1xyXG5cclxuICAgIC8vIFNldCBmaW5hbCBgaGVpZ2h0YCBmb3Igdmlld3BvcnRcclxuICAgIGNvbnN0IHZpZXdwb3J0SGVpZ2h0ID0gTWF0aC5hYnMoXHJcbiAgICAgIE1hdGguY2VpbChzaXplLmNoYXJ0SGVpZ2h0IHx8IGV4cG9ydE9wdGlvbnMuaGVpZ2h0KVxyXG4gICAgKTtcclxuXHJcbiAgICAvLyBTZXQgZmluYWwgYHdpZHRoYCBmb3Igdmlld3BvcnRcclxuICAgIGNvbnN0IHZpZXdwb3J0V2lkdGggPSBNYXRoLmFicyhcclxuICAgICAgTWF0aC5jZWlsKHNpemUuY2hhcnRXaWR0aCB8fCBleHBvcnRPcHRpb25zLndpZHRoKVxyXG4gICAgKTtcclxuXHJcbiAgICAvLyBTZXQgdGhlIGZpbmFsIHZpZXdwb3J0IG5vdyB0aGF0IHdlIGhhdmUgdGhlIHJlYWwgaGVpZ2h0XHJcbiAgICBhd2FpdCBwYWdlLnNldFZpZXdwb3J0KHtcclxuICAgICAgaGVpZ2h0OiB2aWV3cG9ydEhlaWdodCxcclxuICAgICAgd2lkdGg6IHZpZXdwb3J0V2lkdGgsXHJcbiAgICAgIGRldmljZVNjYWxlRmFjdG9yOiBpc1NWRyA/IDEgOiBwYXJzZUZsb2F0KGV4cG9ydE9wdGlvbnMuc2NhbGUpXHJcbiAgICB9KTtcclxuXHJcbiAgICBsZXQgcmVzdWx0O1xyXG4gICAgLy8gUmFzdGVyaXphdGlvbiBwcm9jZXNzXHJcbiAgICBzd2l0Y2ggKGV4cG9ydE9wdGlvbnMudHlwZSkge1xyXG4gICAgICBjYXNlICdzdmcnOlxyXG4gICAgICAgIHJlc3VsdCA9IGF3YWl0IF9jcmVhdGVTVkcocGFnZSk7XHJcbiAgICAgICAgYnJlYWs7XHJcbiAgICAgIGNhc2UgJ3BuZyc6XHJcbiAgICAgIGNhc2UgJ2pwZWcnOlxyXG4gICAgICAgIHJlc3VsdCA9IGF3YWl0IF9jcmVhdGVJbWFnZShcclxuICAgICAgICAgIHBhZ2UsXHJcbiAgICAgICAgICBleHBvcnRPcHRpb25zLnR5cGUsXHJcbiAgICAgICAgICB7XHJcbiAgICAgICAgICAgIHdpZHRoOiB2aWV3cG9ydFdpZHRoLFxyXG4gICAgICAgICAgICBoZWlnaHQ6IHZpZXdwb3J0SGVpZ2h0LFxyXG4gICAgICAgICAgICB4LFxyXG4gICAgICAgICAgICB5XHJcbiAgICAgICAgICB9LFxyXG4gICAgICAgICAgZXhwb3J0T3B0aW9ucy5yYXN0ZXJpemF0aW9uVGltZW91dFxyXG4gICAgICAgICk7XHJcbiAgICAgICAgYnJlYWs7XHJcbiAgICAgIGNhc2UgJ3BkZic6XHJcbiAgICAgICAgcmVzdWx0ID0gYXdhaXQgX2NyZWF0ZVBERihcclxuICAgICAgICAgIHBhZ2UsXHJcbiAgICAgICAgICB2aWV3cG9ydEhlaWdodCxcclxuICAgICAgICAgIHZpZXdwb3J0V2lkdGgsXHJcbiAgICAgICAgICBleHBvcnRPcHRpb25zLnJhc3Rlcml6YXRpb25UaW1lb3V0XHJcbiAgICAgICAgKTtcclxuICAgICAgICBicmVhaztcclxuICAgICAgZGVmYXVsdDpcclxuICAgICAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoXHJcbiAgICAgICAgICBgW2V4cG9ydF0gVW5zdXBwb3J0ZWQgb3V0cHV0IGZvcm1hdDogJHtleHBvcnRPcHRpb25zLnR5cGV9LmAsXHJcbiAgICAgICAgICA0MDBcclxuICAgICAgICApO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIENsZWFyIHByZXZpb3VzbHkgaW5qZWN0ZWQgSlMgYW5kIENTUyByZXNvdXJjZXNcclxuICAgIGF3YWl0IGNsZWFyUGFnZVJlc291cmNlcyhwYWdlLCBpbmplY3RlZFJlc291cmNlcyk7XHJcbiAgICByZXR1cm4gcmVzdWx0O1xyXG4gIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICBhd2FpdCBjbGVhclBhZ2VSZXNvdXJjZXMocGFnZSwgaW5qZWN0ZWRSZXNvdXJjZXMpO1xyXG4gICAgcmV0dXJuIGVycm9yO1xyXG4gIH1cclxufVxyXG5cclxuLyoqXHJcbiAqIFJldHJpZXZlcyB0aGUgY2xpcHBpbmcgcmVnaW9uIGNvb3JkaW5hdGVzIG9mIHRoZSBzcGVjaWZpZWQgcGFnZSBlbGVtZW50XHJcbiAqIHdpdGggdGhlICdjaGFydC1jb250YWluZXInIGlkLlxyXG4gKlxyXG4gKiBAYXN5bmNcclxuICogQGZ1bmN0aW9uIF9nZXRDbGlwUmVnaW9uXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBwYWdlIC0gUHVwcGV0ZWVyIHBhZ2Ugb2JqZWN0LlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7UHJvbWlzZTxPYmplY3Q+fSBBIFByb21pc2UgdGhhdCByZXNvbHZlcyB0byBhbiBvYmplY3QgY29udGFpbmluZ1xyXG4gKiBgeGAsIGB5YCwgYHdpZHRoYCwgYW5kIGBoZWlnaHRgIHByb3BlcnRpZXMuXHJcbiAqL1xyXG5hc3luYyBmdW5jdGlvbiBfZ2V0Q2xpcFJlZ2lvbihwYWdlKSB7XHJcbiAgcmV0dXJuIHBhZ2UuJGV2YWwoJyNjaGFydC1jb250YWluZXInLCAoZWxlbWVudCkgPT4ge1xyXG4gICAgY29uc3QgeyB4LCB5LCB3aWR0aCwgaGVpZ2h0IH0gPSBlbGVtZW50LmdldEJvdW5kaW5nQ2xpZW50UmVjdCgpO1xyXG4gICAgcmV0dXJuIHtcclxuICAgICAgeCxcclxuICAgICAgeSxcclxuICAgICAgd2lkdGgsXHJcbiAgICAgIGhlaWdodDogTWF0aC50cnVuYyhoZWlnaHQgPiAxID8gaGVpZ2h0IDogNTAwKVxyXG4gICAgfTtcclxuICB9KTtcclxufVxyXG5cclxuLyoqXHJcbiAqIENyZWF0ZXMgYW4gU1ZHIGJ5IGV2YWx1YXRpbmcgdGhlIGBvdXRlckhUTUxgIG9mIHRoZSBmaXJzdCAnc3ZnJyBlbGVtZW50XHJcbiAqIGluc2lkZSBhbiBlbGVtZW50IHdpdGggdGhlIGlkICdjb250YWluZXInLlxyXG4gKlxyXG4gKiBAYXN5bmNcclxuICogQGZ1bmN0aW9uIF9jcmVhdGVTVkdcclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IHBhZ2UgLSBQdXBwZXRlZXIgcGFnZSBvYmplY3QuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtQcm9taXNlPHN0cmluZz59IEEgUHJvbWlzZSB0aGF0IHJlc29sdmVzIHRvIHRoZSBTVkcgc3RyaW5nLlxyXG4gKi9cclxuYXN5bmMgZnVuY3Rpb24gX2NyZWF0ZVNWRyhwYWdlKSB7XHJcbiAgcmV0dXJuIHBhZ2UuJGV2YWwoXHJcbiAgICAnI2NvbnRhaW5lciBzdmc6Zmlyc3Qtb2YtdHlwZScsXHJcbiAgICAoZWxlbWVudCkgPT4gZWxlbWVudC5vdXRlckhUTUxcclxuICApO1xyXG59XHJcblxyXG4vKipcclxuICogQ3JlYXRlcyBhbiBpbWFnZSB1c2luZyBQdXBwZXRlZXIncyBwYWdlIGBzY3JlZW5zaG90YCBmdW5jdGlvbmFsaXR5IHdpdGhcclxuICogc3BlY2lmaWVkIG9wdGlvbnMuXHJcbiAqXHJcbiAqIEBhc3luY1xyXG4gKiBAZnVuY3Rpb24gX2NyZWF0ZUltYWdlXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBwYWdlIC0gUHVwcGV0ZWVyIHBhZ2Ugb2JqZWN0LlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gdHlwZSAtIEltYWdlIHR5cGUuXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBjbGlwIC0gQ2xpcHBpbmcgcmVnaW9uIGNvb3JkaW5hdGVzLlxyXG4gKiBAcGFyYW0ge251bWJlcn0gcmFzdGVyaXphdGlvblRpbWVvdXQgLSBUaW1lb3V0IGZvciByYXN0ZXJpemF0aW9uXHJcbiAqIGluIG1pbGxpc2Vjb25kcy5cclxuICpcclxuICogQHJldHVybnMge1Byb21pc2U8QnVmZmVyPn0gQSBQcm9taXNlIHRoYXQgcmVzb2x2ZXMgdG8gdGhlIGltYWdlIGJ1ZmZlclxyXG4gKiBvciByZWplY3Rpbmcgd2l0aCBhbiBgRXhwb3J0RXJyb3JgIGZvciB0aW1lb3V0LlxyXG4gKi9cclxuYXN5bmMgZnVuY3Rpb24gX2NyZWF0ZUltYWdlKHBhZ2UsIHR5cGUsIGNsaXAsIHJhc3Rlcml6YXRpb25UaW1lb3V0KSB7XHJcbiAgcmV0dXJuIFByb21pc2UucmFjZShbXHJcbiAgICBwYWdlLnNjcmVlbnNob3Qoe1xyXG4gICAgICB0eXBlLFxyXG4gICAgICBjbGlwLFxyXG4gICAgICBlbmNvZGluZzogJ2Jhc2U2NCcsXHJcbiAgICAgIGZ1bGxQYWdlOiBmYWxzZSxcclxuICAgICAgb3B0aW1pemVGb3JTcGVlZDogdHJ1ZSxcclxuICAgICAgY2FwdHVyZUJleW9uZFZpZXdwb3J0OiB0cnVlLFxyXG4gICAgICAuLi4odHlwZSAhPT0gJ3BuZycgPyB7IHF1YWxpdHk6IDgwIH0gOiB7fSksXHJcbiAgICAgIC8vIEFsd2F5cyByZW5kZXIgb24gYSB0cmFuc3BhcmVudCBwYWdlIGlmIHRoZSBleHBlY3RlZCB0eXBlIGZvcm1hdCBpcyBQTkdcclxuICAgICAgb21pdEJhY2tncm91bmQ6IHR5cGUgPT0gJ3BuZycgLy8gIzQ0NywgIzQ2M1xyXG4gICAgfSksXHJcbiAgICBuZXcgUHJvbWlzZSgoX3Jlc29sdmUsIHJlamVjdCkgPT5cclxuICAgICAgc2V0VGltZW91dChcclxuICAgICAgICAoKSA9PiByZWplY3QobmV3IEV4cG9ydEVycm9yKCdSYXN0ZXJpemF0aW9uIHRpbWVvdXQnLCA0MDgpKSxcclxuICAgICAgICByYXN0ZXJpemF0aW9uVGltZW91dCB8fCAxNTAwXHJcbiAgICAgIClcclxuICAgIClcclxuICBdKTtcclxufVxyXG5cclxuLyoqXHJcbiAqIENyZWF0ZXMgYSBQREYgdXNpbmcgUHVwcGV0ZWVyJ3MgcGFnZSBgcGRmYCBmdW5jdGlvbmFsaXR5IHdpdGggc3BlY2lmaWVkXHJcbiAqIG9wdGlvbnMuXHJcbiAqXHJcbiAqIEBhc3luY1xyXG4gKiBAZnVuY3Rpb24gX2NyZWF0ZVBERlxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gcGFnZSAtIFB1cHBldGVlciBwYWdlIG9iamVjdC5cclxuICogQHBhcmFtIHtudW1iZXJ9IGhlaWdodCAtIFBERiBoZWlnaHQuXHJcbiAqIEBwYXJhbSB7bnVtYmVyfSB3aWR0aCAtIFBERiB3aWR0aC5cclxuICogQHBhcmFtIHtudW1iZXJ9IHJhc3Rlcml6YXRpb25UaW1lb3V0IC0gVGltZW91dCBmb3IgcmFzdGVyaXphdGlvblxyXG4gKiBpbiBtaWxsaXNlY29uZHMuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtQcm9taXNlPEJ1ZmZlcj59IEEgUHJvbWlzZSB0aGF0IHJlc29sdmVzIHRvIHRoZSBQREYgYnVmZmVyLlxyXG4gKi9cclxuYXN5bmMgZnVuY3Rpb24gX2NyZWF0ZVBERihwYWdlLCBoZWlnaHQsIHdpZHRoLCByYXN0ZXJpemF0aW9uVGltZW91dCkge1xyXG4gIGF3YWl0IHBhZ2UuZW11bGF0ZU1lZGlhVHlwZSgnc2NyZWVuJyk7XHJcbiAgcmV0dXJuIHBhZ2UucGRmKHtcclxuICAgIC8vIFRoaXMgd2lsbCByZW1vdmUgYW4gZXh0cmEgZW1wdHkgcGFnZSBpbiBQREYgZXhwb3J0c1xyXG4gICAgaGVpZ2h0OiBoZWlnaHQgKyAxLFxyXG4gICAgd2lkdGgsXHJcbiAgICBlbmNvZGluZzogJ2Jhc2U2NCcsXHJcbiAgICB0aW1lb3V0OiByYXN0ZXJpemF0aW9uVGltZW91dCB8fCAxNTAwXHJcbiAgfSk7XHJcbn1cclxuXHJcbmV4cG9ydCBkZWZhdWx0IHtcclxuICBwdXBwZXRlZXJFeHBvcnRcclxufTtcclxuIiwiLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcclxuXHJcbkhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlclxyXG5cclxuQ29weXJpZ2h0IChjKSAyMDE2LTIwMjUsIEhpZ2hzb2Z0XHJcblxyXG5MaWNlbmNlZCB1bmRlciB0aGUgTUlUIGxpY2VuY2UuXHJcblxyXG5BZGRpdGlvbmFsbHkgYSB2YWxpZCBIaWdoY2hhcnRzIGxpY2Vuc2UgaXMgcmVxdWlyZWQgZm9yIHVzZS5cclxuXHJcblNlZSBMSUNFTlNFIGZpbGUgaW4gcm9vdCBmb3IgZGV0YWlscy5cclxuXHJcbioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXHJcblxyXG4vKipcclxuICogQG92ZXJ2aWV3IFRoaXMgbW9kdWxlIHByb3ZpZGVzIGEgd29ya2VyIHBvb2wgaW1wbGVtZW50YXRpb24gZm9yIG1hbmFnaW5nXHJcbiAqIHRoZSBicm93c2VyIGluc3RhbmNlIGFuZCBwYWdlcywgc3BlY2lmaWNhbGx5IGRlc2lnbmVkIGZvciB1c2Ugd2l0aFxyXG4gKiB0aGUgSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyLiBJdCBvcHRpbWl6ZXMgcmVzb3VyY2VzIHVzYWdlIGFuZCBwZXJmb3JtYW5jZVxyXG4gKiBieSBtYWludGFpbmluZyBhIHBvb2wgb2Ygd29ya2VycyB0aGF0IGNhbiBoYW5kbGUgY29uY3VycmVudCBleHBvcnQgdGFza3NcclxuICogdXNpbmcgUHVwcGV0ZWVyLlxyXG4gKi9cclxuXHJcbmltcG9ydCB7IFBvb2wgfSBmcm9tICd0YXJuJztcclxuaW1wb3J0IHsgdjQgYXMgdXVpZCB9IGZyb20gJ3V1aWQnO1xyXG5cclxuaW1wb3J0IHsgY2xlYXJQYWdlLCBjcmVhdGVCcm93c2VyLCBjbG9zZUJyb3dzZXIsIG5ld1BhZ2UgfSBmcm9tICcuL2Jyb3dzZXIuanMnO1xyXG5pbXBvcnQgeyBwdXBwZXRlZXJFeHBvcnQgfSBmcm9tICcuL2V4cG9ydC5qcyc7XHJcbmltcG9ydCB7IGxvZywgbG9nV2l0aFN0YWNrIH0gZnJvbSAnLi9sb2dnZXIuanMnO1xyXG5pbXBvcnQgeyBnZXROZXdEYXRlVGltZSwgbWVhc3VyZVRpbWUgfSBmcm9tICcuL3V0aWxzLmpzJztcclxuXHJcbmltcG9ydCBFeHBvcnRFcnJvciBmcm9tICcuL2Vycm9ycy9FeHBvcnRFcnJvci5qcyc7XHJcblxyXG4vLyBUaGUgcG9vbCBpbnN0YW5jZVxyXG5sZXQgcG9vbCA9IG51bGw7XHJcblxyXG4vLyBQb29sIHN0YXRpc3RpY3NcclxuY29uc3QgcG9vbFN0YXRzID0ge1xyXG4gIGV4cG9ydHNBdHRlbXB0ZWQ6IDAsXHJcbiAgZXhwb3J0c1BlcmZvcm1lZDogMCxcclxuICBleHBvcnRzRHJvcHBlZDogMCxcclxuICBleHBvcnRzRnJvbVN2ZzogMCxcclxuICBleHBvcnRzRnJvbU9wdGlvbnM6IDAsXHJcbiAgZXhwb3J0c0Zyb21TdmdBdHRlbXB0czogMCxcclxuICBleHBvcnRzRnJvbU9wdGlvbnNBdHRlbXB0czogMCxcclxuICB0aW1lU3BlbnQ6IDAsXHJcbiAgdGltZVNwZW50QXZlcmFnZTogMFxyXG59O1xyXG5cclxuLyoqXHJcbiAqIEluaXRpYWxpemVzIHRoZSBleHBvcnQgcG9vbCB3aXRoIHRoZSBwcm92aWRlZCBjb25maWd1cmF0aW9uLCBjcmVhdGluZ1xyXG4gKiBhIGJyb3dzZXIgaW5zdGFuY2UgYW5kIHNldHRpbmcgdXAgd29ya2VyIHJlc291cmNlcy5cclxuICpcclxuICogQGFzeW5jXHJcbiAqIEBmdW5jdGlvbiBpbml0UG9vbFxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gcG9vbE9wdGlvbnMgLSBUaGUgY29uZmlndXJhdGlvbiBvYmplY3QgY29udGFpbmluZyBgcG9vbGBcclxuICogb3B0aW9ucy5cclxuICogQHBhcmFtIHtBcnJheS48c3RyaW5nPn0gcHVwcGV0ZWVyQXJncyAtIEFkZGl0aW9uYWwgYXJndW1lbnRzIGZvciBQdXBwZXRlZXJcclxuICogbGF1bmNoLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7UHJvbWlzZTx2b2lkPn0gQSBQcm9taXNlIHRoYXQgcmVzb2x2ZXMgdG8gZW5kaW5nIHRoZSBmdW5jdGlvblxyXG4gKiBleGVjdXRpb24gd2hlbiBhbiBhbHJlYWR5IGluaXRpYWxpemVkIHBvb2wgb2YgcmVzb3VyY2VzIGlzIGZvdW5kLlxyXG4gKlxyXG4gKiBAdGhyb3dzIHtFeHBvcnRFcnJvcn0gVGhyb3dzIGFuIGBFeHBvcnRFcnJvcmAgaWYgY291bGQgbm90IGNyZWF0ZSB0aGUgcG9vbFxyXG4gKiBvZiB3b3JrZXJzLlxyXG4gKi9cclxuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIGluaXRQb29sKHBvb2xPcHRpb25zLCBwdXBwZXRlZXJBcmdzKSB7XHJcbiAgLy8gQ3JlYXRlIGEgYnJvd3NlciBpbnN0YW5jZSB3aXRoIHRoZSBwdXBwZXRlZXIgYXJndW1lbnRzXHJcbiAgYXdhaXQgY3JlYXRlQnJvd3NlcihwdXBwZXRlZXJBcmdzKTtcclxuXHJcbiAgdHJ5IHtcclxuICAgIGxvZyhcclxuICAgICAgMyxcclxuICAgICAgYFtwb29sXSBJbml0aWFsaXppbmcgcG9vbCB3aXRoIHdvcmtlcnM6IG1pbiAke3Bvb2xPcHRpb25zLm1pbldvcmtlcnN9LCBtYXggJHtwb29sT3B0aW9ucy5tYXhXb3JrZXJzfS5gXHJcbiAgICApO1xyXG5cclxuICAgIGlmIChwb29sKSB7XHJcbiAgICAgIGxvZyhcclxuICAgICAgICA0LFxyXG4gICAgICAgICdbcG9vbF0gQWxyZWFkeSBpbml0aWFsaXplZCwgcGxlYXNlIGtpbGwgaXQgYmVmb3JlIGNyZWF0aW5nIGEgbmV3IG9uZS4nXHJcbiAgICAgICk7XHJcbiAgICAgIHJldHVybjtcclxuICAgIH1cclxuXHJcbiAgICAvLyBLZWVwIGFuIGV5ZSBvbiBhIGNvcnJlY3QgbWluIGFuZCBtYXggd29ya2VycyBudW1iZXJcclxuICAgIGlmIChwb29sT3B0aW9ucy5taW5Xb3JrZXJzID4gcG9vbE9wdGlvbnMubWF4V29ya2Vycykge1xyXG4gICAgICBwb29sT3B0aW9ucy5taW5Xb3JrZXJzID0gcG9vbE9wdGlvbnMubWF4V29ya2VycztcclxuICAgIH1cclxuXHJcbiAgICAvLyBDcmVhdGUgYSBwb29sIGFsb25nIHdpdGggYSBtaW5pbWFsIG51bWJlciBvZiByZXNvdXJjZXNcclxuICAgIHBvb2wgPSBuZXcgUG9vbCh7XHJcbiAgICAgIC8vIEdldCB0aGUgYGNyZWF0ZWAsIGB2YWxpZGF0ZWAsIGFuZCBgZGVzdHJveWAgZnVuY3Rpb25zXHJcbiAgICAgIC4uLl9mYWN0b3J5KHBvb2xPcHRpb25zKSxcclxuICAgICAgbWluOiBwb29sT3B0aW9ucy5taW5Xb3JrZXJzLFxyXG4gICAgICBtYXg6IHBvb2xPcHRpb25zLm1heFdvcmtlcnMsXHJcbiAgICAgIGFjcXVpcmVUaW1lb3V0TWlsbGlzOiBwb29sT3B0aW9ucy5hY3F1aXJlVGltZW91dCxcclxuICAgICAgY3JlYXRlVGltZW91dE1pbGxpczogcG9vbE9wdGlvbnMuY3JlYXRlVGltZW91dCxcclxuICAgICAgZGVzdHJveVRpbWVvdXRNaWxsaXM6IHBvb2xPcHRpb25zLmRlc3Ryb3lUaW1lb3V0LFxyXG4gICAgICBpZGxlVGltZW91dE1pbGxpczogcG9vbE9wdGlvbnMuaWRsZVRpbWVvdXQsXHJcbiAgICAgIGNyZWF0ZVJldHJ5SW50ZXJ2YWxNaWxsaXM6IHBvb2xPcHRpb25zLmNyZWF0ZVJldHJ5SW50ZXJ2YWwsXHJcbiAgICAgIHJlYXBJbnRlcnZhbE1pbGxpczogcG9vbE9wdGlvbnMucmVhcGVySW50ZXJ2YWwsXHJcbiAgICAgIHByb3BhZ2F0ZUNyZWF0ZUVycm9yOiBmYWxzZVxyXG4gICAgfSk7XHJcblxyXG4gICAgLy8gU2V0IGV2ZW50c1xyXG4gICAgcG9vbC5vbigncmVsZWFzZScsIGFzeW5jIChyZXNvdXJjZSkgPT4ge1xyXG4gICAgICAvLyBDbGVhciBwYWdlXHJcbiAgICAgIGNvbnN0IGNsZWFyU3RhdHVzID0gYXdhaXQgY2xlYXJQYWdlKHJlc291cmNlLCBmYWxzZSk7XHJcbiAgICAgIGxvZyhcclxuICAgICAgICA0LFxyXG4gICAgICAgIGBbcG9vbF0gUG9vbCByZXNvdXJjZSBbJHtyZXNvdXJjZS5pZH1dIC0gUmVsZWFzaW5nIGEgd29ya2VyLiBDbGVhciBwYWdlIHN0YXR1czogJHtjbGVhclN0YXR1c30uYFxyXG4gICAgICApO1xyXG4gICAgfSk7XHJcblxyXG4gICAgcG9vbC5vbignZGVzdHJveVN1Y2Nlc3MnLCAoX2V2ZW50SWQsIHJlc291cmNlKSA9PiB7XHJcbiAgICAgIGxvZyhcclxuICAgICAgICA0LFxyXG4gICAgICAgIGBbcG9vbF0gUG9vbCByZXNvdXJjZSBbJHtyZXNvdXJjZS5pZH1dIC0gRGVzdHJveWVkIGEgd29ya2VyIHN1Y2Nlc3NmdWxseS5gXHJcbiAgICAgICk7XHJcbiAgICAgIHJlc291cmNlLnBhZ2UgPSBudWxsO1xyXG4gICAgfSk7XHJcblxyXG4gICAgY29uc3QgaW5pdGlhbFJlc291cmNlcyA9IFtdO1xyXG4gICAgLy8gQ3JlYXRlIGFuIGluaXRpYWwgbnVtYmVyIG9mIHJlc291cmNlc1xyXG4gICAgZm9yIChsZXQgaSA9IDA7IGkgPCBwb29sT3B0aW9ucy5taW5Xb3JrZXJzOyBpKyspIHtcclxuICAgICAgdHJ5IHtcclxuICAgICAgICBjb25zdCByZXNvdXJjZSA9IGF3YWl0IHBvb2wuYWNxdWlyZSgpLnByb21pc2U7XHJcbiAgICAgICAgaW5pdGlhbFJlc291cmNlcy5wdXNoKHJlc291cmNlKTtcclxuICAgICAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICAgICBsb2dXaXRoU3RhY2soMiwgZXJyb3IsICdbcG9vbF0gQ291bGQgbm90IGNyZWF0ZSBhbiBpbml0aWFsIHJlc291cmNlLicpO1xyXG4gICAgICB9XHJcbiAgICB9XHJcblxyXG4gICAgLy8gUmVsZWFzZSB0aGUgaW5pdGlhbCBudW1iZXIgb2YgcmVzb3VyY2VzIGJhY2sgdG8gdGhlIHBvb2xcclxuICAgIGluaXRpYWxSZXNvdXJjZXMuZm9yRWFjaCgocmVzb3VyY2UpID0+IHtcclxuICAgICAgcG9vbC5yZWxlYXNlKHJlc291cmNlKTtcclxuICAgIH0pO1xyXG5cclxuICAgIGxvZyhcclxuICAgICAgMyxcclxuICAgICAgYFtwb29sXSBUaGUgcG9vbCBpcyByZWFkeSR7aW5pdGlhbFJlc291cmNlcy5sZW5ndGggPyBgIHdpdGggJHtpbml0aWFsUmVzb3VyY2VzLmxlbmd0aH0gaW5pdGlhbCByZXNvdXJjZXMgd2FpdGluZy5gIDogJy4nfWBcclxuICAgICk7XHJcbiAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcihcclxuICAgICAgJ1twb29sXSBDb3VsZCBub3QgY29uZmlndXJlIGFuZCBjcmVhdGUgdGhlIHBvb2wgb2Ygd29ya2Vycy4nLFxyXG4gICAgICA1MDBcclxuICAgICkuc2V0RXJyb3IoZXJyb3IpO1xyXG4gIH1cclxufVxyXG5cclxuLyoqXHJcbiAqIFRlcm1pbmF0ZXMgYWxsIHdvcmtlcnMgaW4gdGhlIHBvb2wsIGRlc3Ryb3lzIHRoZSBwb29sLCBhbmQgY2xvc2VzIHRoZSBicm93c2VyXHJcbiAqIGluc3RhbmNlLlxyXG4gKlxyXG4gKiBAYXN5bmNcclxuICogQGZ1bmN0aW9uIGtpbGxQb29sXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtQcm9taXNlPHZvaWQ+fSBBIFByb21pc2UgdGhhdCByZXNvbHZlcyBvbmNlIGFsbCB3b3JrZXJzIGFyZVxyXG4gKiB0ZXJtaW5hdGVkLCB0aGUgcG9vbCBpcyBkZXN0cm95ZWQsIGFuZCB0aGUgYnJvd3NlciBpcyBzdWNjZXNzZnVsbHkgY2xvc2VkLlxyXG4gKi9cclxuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIGtpbGxQb29sKCkge1xyXG4gIGxvZygzLCAnW3Bvb2xdIEtpbGxpbmcgcG9vbCB3aXRoIGFsbCB3b3JrZXJzIGFuZCBjbG9zaW5nIGJyb3dzZXIuJyk7XHJcblxyXG4gIC8vIElmIHN0aWxsIGFsaXZlLCBkZXN0cm95IHRoZSBwb29sIG9mIHBhZ2VzIGJlZm9yZSBjbG9zaW5nIGEgYnJvd3NlclxyXG4gIGlmIChwb29sKSB7XHJcbiAgICAvLyBGcmVlIHVwIG5vdCByZWxlYXNlZCB3b3JrZXJzXHJcbiAgICBmb3IgKGNvbnN0IHdvcmtlciBvZiBwb29sLnVzZWQpIHtcclxuICAgICAgcG9vbC5yZWxlYXNlKHdvcmtlci5yZXNvdXJjZSk7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gRGVzdHJveSB0aGUgcG9vbCBpZiBpdCBpcyBzdGlsbCBhdmFpbGFibGVcclxuICAgIGlmICghcG9vbC5kZXN0cm95ZWQpIHtcclxuICAgICAgYXdhaXQgcG9vbC5kZXN0cm95KCk7XHJcbiAgICAgIGxvZyg0LCAnW3Bvb2xdIERlc3Ryb3llZCB0aGUgcG9vbCBvZiByZXNvdXJjZXMuJyk7XHJcbiAgICB9XHJcbiAgICBwb29sID0gbnVsbDtcclxuICB9XHJcblxyXG4gIC8vIENsb3NlIHRoZSBicm93c2VyIGluc3RhbmNlXHJcbiAgYXdhaXQgY2xvc2VCcm93c2VyKCk7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBQcm9jZXNzZXMgdGhlIGV4cG9ydCB3b3JrIHVzaW5nIGEgd29ya2VyIGZyb20gdGhlIHBvb2wuIEFjcXVpcmVzIGEgd29ya2VyXHJcbiAqIGhhbmRsZSBmcm9tIHRoZSBwb29sLCBwZXJmb3JtcyB0aGUgZXhwb3J0IHVzaW5nIHB1cHBldGVlciwgYW5kIHJlbGVhc2VzXHJcbiAqIHRoZSB3b3JrZXIgaGFuZGxlIGJhY2sgdG8gdGhlIHBvb2wuXHJcbiAqXHJcbiAqIEBhc3luY1xyXG4gKiBAZnVuY3Rpb24gcG9zdFdvcmtcclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IG9wdGlvbnMgLSBUaGUgY29uZmlndXJhdGlvbiBvYmplY3QgY29udGFpbmluZyBjb21wbGV0ZSBzZXRcclxuICogb2Ygb3B0aW9ucy5cclxuICpcclxuICogQHJldHVybnMge1Byb21pc2U8T2JqZWN0Pn0gQSBQcm9taXNlIHRoYXQgcmVzb2x2ZXMgdG8gdGhlIGV4cG9ydCByZXN1bHRcclxuICogYW5kIG9wdGlvbnMuXHJcbiAqXHJcbiAqIEB0aHJvd3Mge0V4cG9ydEVycm9yfSBUaHJvd3MgYW4gYEV4cG9ydEVycm9yYCBpZiBhbiBlcnJvciBvY2N1cnMgZHVyaW5nXHJcbiAqIHRoZSBleHBvcnQgcHJvY2Vzcy5cclxuICovXHJcbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBwb3N0V29yayhvcHRpb25zKSB7XHJcbiAgbGV0IHdvcmtlckhhbmRsZTtcclxuXHJcbiAgdHJ5IHtcclxuICAgIGxvZyg0LCAnW3Bvb2xdIFdvcmsgcmVjZWl2ZWQsIHN0YXJ0aW5nIHRvIHByb2Nlc3MuJyk7XHJcblxyXG4gICAgLy8gQW4gZXhwb3J0IGF0dGVtcHQgY291bnRlZFxyXG4gICAgKytwb29sU3RhdHMuZXhwb3J0c0F0dGVtcHRlZDtcclxuXHJcbiAgICAvLyBEaXNwbGF5IHRoZSBwb29sIGluZm9ybWF0aW9uIGlmIG5lZWRlZFxyXG4gICAgaWYgKG9wdGlvbnMucG9vbC5iZW5jaG1hcmtpbmcpIHtcclxuICAgICAgZ2V0UG9vbEluZm8oKTtcclxuICAgIH1cclxuXHJcbiAgICAvLyBUaHJvdyBhbiBlcnJvciBpbiBjYXNlIG9mIGxhY2tpbmcgdGhlIHBvb2wgaW5zdGFuY2VcclxuICAgIGlmICghcG9vbCkge1xyXG4gICAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoXHJcbiAgICAgICAgJ1twb29sXSBXb3JrIHJlY2VpdmVkLCBidXQgcG9vbCBoYXMgbm90IGJlZW4gc3RhcnRlZC4nLFxyXG4gICAgICAgIDUwMFxyXG4gICAgICApO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIFRoZSBhY3F1aXJlIGNvdW50ZXJcclxuICAgIGNvbnN0IGFjcXVpcmVDb3VudGVyID0gbWVhc3VyZVRpbWUoKTtcclxuXHJcbiAgICAvLyBUcnkgdG8gYWNxdWlyZSB0aGUgd29ya2VyIGFsb25nIHdpdGggdGhlIGlkLCB3b3JrcyBjb3VudCBhbmQgcGFnZVxyXG4gICAgdHJ5IHtcclxuICAgICAgbG9nKDQsICdbcG9vbF0gQWNxdWlyaW5nIGEgd29ya2VyIGhhbmRsZS4nKTtcclxuXHJcbiAgICAgIC8vIEFjcXVpcmUgYSBwb29sIHJlc291cmNlXHJcbiAgICAgIHdvcmtlckhhbmRsZSA9IGF3YWl0IHBvb2wuYWNxdWlyZSgpLnByb21pc2U7XHJcblxyXG4gICAgICAvLyBDaGVjayB0aGUgcGFnZSBhY3F1aXJlIHRpbWVcclxuICAgICAgaWYgKG9wdGlvbnMuc2VydmVyLmJlbmNobWFya2luZykge1xyXG4gICAgICAgIGxvZyhcclxuICAgICAgICAgIDUsXHJcbiAgICAgICAgICBgW2JlbmNobWFya10gJHtvcHRpb25zLnJlcXVlc3RJZCA/IGBSZXF1ZXN0IFske29wdGlvbnMucmVxdWVzdElkfV0gLSBgIDogJyd9YCxcclxuICAgICAgICAgIGBBY3F1aXJpbmcgYSB3b3JrZXIgaGFuZGxlIHRvb2sgJHthY3F1aXJlQ291bnRlcigpfW1zLmBcclxuICAgICAgICApO1xyXG4gICAgICB9XHJcbiAgICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoXHJcbiAgICAgICAgYFtwb29sXSAke1xyXG4gICAgICAgICAgb3B0aW9ucy5yZXF1ZXN0SWQgPyBgUmVxdWVzdCBbJHtvcHRpb25zLnJlcXVlc3RJZH1dIC0gYCA6ICcnXHJcbiAgICAgICAgfUVycm9yIGVuY291bnRlcmVkIHdoZW4gYWNxdWlyaW5nIGFuIGF2YWlsYWJsZSBlbnRyeTogJHthY3F1aXJlQ291bnRlcigpfW1zLmAsXHJcbiAgICAgICAgNDAwXHJcbiAgICAgICkuc2V0RXJyb3IoZXJyb3IpO1xyXG4gICAgfVxyXG4gICAgbG9nKDQsICdbcG9vbF0gQWNxdWlyZWQgYSB3b3JrZXIgaGFuZGxlLicpO1xyXG5cclxuICAgIGlmICghd29ya2VySGFuZGxlLnBhZ2UpIHtcclxuICAgICAgLy8gU2V0IHRoZSBgd29ya0xpbWl0YCB0byBleGNlZWRlZCBpbiBvcmRlciB0byByZWNyZWF0ZSB0aGUgcmVzb3VyY2VcclxuICAgICAgd29ya2VySGFuZGxlLndvcmtDb3VudCA9IG9wdGlvbnMucG9vbC53b3JrTGltaXQgKyAxO1xyXG4gICAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoXHJcbiAgICAgICAgJ1twb29sXSBSZXNvbHZlZCB3b3JrZXIgcGFnZSBpcyBpbnZhbGlkOiB0aGUgcG9vbCBzZXR1cCBpcyB3b25reS4nLFxyXG4gICAgICAgIDQwMFxyXG4gICAgICApO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIFNhdmUgdGhlIHN0YXJ0IHRpbWVcclxuICAgIGNvbnN0IHdvcmtTdGFydCA9IGdldE5ld0RhdGVUaW1lKCk7XHJcblxyXG4gICAgbG9nKFxyXG4gICAgICA0LFxyXG4gICAgICBgW3Bvb2xdIFBvb2wgcmVzb3VyY2UgWyR7d29ya2VySGFuZGxlLmlkfV0gLSBTdGFydGluZyB3b3JrIG9uIHRoaXMgcG9vbCBlbnRyeS5gXHJcbiAgICApO1xyXG5cclxuICAgIC8vIFN0YXJ0IG1lYXN1cmluZyBleHBvcnQgdGltZVxyXG4gICAgY29uc3QgZXhwb3J0Q291bnRlciA9IG1lYXN1cmVUaW1lKCk7XHJcblxyXG4gICAgLy8gUGVyZm9ybSBhbiBleHBvcnQgb24gYSBwdXBwZXRlZXIgbGV2ZWxcclxuICAgIGNvbnN0IHJlc3VsdCA9IGF3YWl0IHB1cHBldGVlckV4cG9ydChcclxuICAgICAgd29ya2VySGFuZGxlLnBhZ2UsXHJcbiAgICAgIG9wdGlvbnMuZXhwb3J0LFxyXG4gICAgICBvcHRpb25zLmN1c3RvbUxvZ2ljXHJcbiAgICApO1xyXG5cclxuICAgIC8vIENoZWNrIGlmIGl0J3MgYW4gZXJyb3JcclxuICAgIGlmIChyZXN1bHQgaW5zdGFuY2VvZiBFcnJvcikge1xyXG4gICAgICAvLyBOT1RFOlxyXG4gICAgICAvLyBJZiB0aGVyZSdzIGEgcmFzdGVyaXphdGlvbiB0aW1lb3V0LCB3ZSB3YW50IG5lZWQgdG8gZmx1c2ggdGhlIHBhZ2UuXHJcbiAgICAgIC8vIFRoaXMgaXMgYmVjYXVzZSB0aGUgcGFnZSBtYXkgYmUgaW4gYSBzdGF0ZSB3aGVyZSBpdCdzIHdhaXRpbmcgZm9yXHJcbiAgICAgIC8vIHRoZSBzY3JlZW5zaG90IHRvIGZpbmlzaCBldmVuIHRob3VnaCB0aGUgdGltZW91dCBoYXMgb2NjdXJlZC5cclxuICAgICAgLy8gV2hpY2ggb2YgY291cnNlIGNhdXNlcyBhIGxvdCBvZiBpc3N1ZXMgd2l0aCB0aGUgZXZlbnQgc3lzdGVtLFxyXG4gICAgICAvLyBhbmQgcGFnZSBjb25zaXN0ZW5jeS5cclxuICAgICAgLy9cclxuICAgICAgLy8gTk9URTpcclxuICAgICAgLy8gT25seSBwYWdlLnNjcmVlbnNob3Qgd2lsbCB0aHJvdyB0aGlzLCB0aW1lb3V0cyBmb3IgUERGJ3MgYXJlXHJcbiAgICAgIC8vIGhhbmRsZWQgYnkgdGhlIHBhZ2UucGRmIGZ1bmN0aW9uIGl0c2VsZi5cclxuICAgICAgLy9cclxuICAgICAgLy8gLi4ueWVzLCB0aGlzIGlzIHVnbHkuXHJcbiAgICAgIGlmIChyZXN1bHQubWVzc2FnZSA9PT0gJ1Jhc3Rlcml6YXRpb24gdGltZW91dCcpIHtcclxuICAgICAgICAvLyBTZXQgdGhlIGB3b3JrTGltaXRgIHRvIGV4Y2VlZGVkIGluIG9yZGVyIHRvIHJlY3JlYXRlIHRoZSByZXNvdXJjZVxyXG4gICAgICAgIHdvcmtlckhhbmRsZS53b3JrQ291bnQgPSBvcHRpb25zLnBvb2wud29ya0xpbWl0ICsgMTtcclxuICAgICAgICB3b3JrZXJIYW5kbGUucGFnZSA9IG51bGw7XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIGlmIChcclxuICAgICAgICByZXN1bHQubmFtZSA9PT0gJ1RpbWVvdXRFcnJvcicgfHxcclxuICAgICAgICByZXN1bHQubWVzc2FnZSA9PT0gJ1Jhc3Rlcml6YXRpb24gdGltZW91dCdcclxuICAgICAgKSB7XHJcbiAgICAgICAgdGhyb3cgbmV3IEV4cG9ydEVycm9yKFxyXG4gICAgICAgICAgYFtwb29sXSAke1xyXG4gICAgICAgICAgICBvcHRpb25zLnJlcXVlc3RJZCA/IGBSZXF1ZXN0IFske29wdGlvbnMucmVxdWVzdElkfV0gLSBgIDogJydcclxuICAgICAgICAgIH1SYXN0ZXJpemF0aW9uIHRpbWVvdXQ6IHlvdXIgY2hhcnQgbWF5IGJlIHRvbyBjb21wbGV4IG9yIGxhcmdlLCBhbmQgZmFpbGVkIHRvIHJlbmRlciB3aXRoaW4gdGhlIGFsbG90dGVkIHRpbWUuYFxyXG4gICAgICAgICkuc2V0RXJyb3IocmVzdWx0KTtcclxuICAgICAgfSBlbHNlIHtcclxuICAgICAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoXHJcbiAgICAgICAgICBgW3Bvb2xdICR7XHJcbiAgICAgICAgICAgIG9wdGlvbnMucmVxdWVzdElkID8gYFJlcXVlc3QgWyR7b3B0aW9ucy5yZXF1ZXN0SWR9XSAtIGAgOiAnJ1xyXG4gICAgICAgICAgfUVycm9yIGVuY291bnRlcmVkIGR1cmluZyBleHBvcnQ6ICR7ZXhwb3J0Q291bnRlcigpfW1zLmBcclxuICAgICAgICApLnNldEVycm9yKHJlc3VsdCk7XHJcbiAgICAgIH1cclxuICAgIH1cclxuXHJcbiAgICAvLyBDaGVjayB0aGUgUHVwcGV0ZWVyIGV4cG9ydCB0aW1lXHJcbiAgICBpZiAob3B0aW9ucy5zZXJ2ZXIuYmVuY2htYXJraW5nKSB7XHJcbiAgICAgIGxvZyhcclxuICAgICAgICA1LFxyXG4gICAgICAgIGBbYmVuY2htYXJrXSAke29wdGlvbnMucmVxdWVzdElkID8gYFJlcXVlc3QgWyR7b3B0aW9ucy5yZXF1ZXN0SWR9XSAtIGAgOiAnJ31gLFxyXG4gICAgICAgIGBFeHBvcnRpbmcgYSBjaGFydCBzdWNlc3NmdWxseSB0b29rICR7ZXhwb3J0Q291bnRlcigpfW1zLmBcclxuICAgICAgKTtcclxuICAgIH1cclxuXHJcbiAgICAvLyBSZWxlYXNlIHRoZSByZXNvdXJjZSBiYWNrIHRvIHRoZSBwb29sXHJcbiAgICBwb29sLnJlbGVhc2Uod29ya2VySGFuZGxlKTtcclxuXHJcbiAgICAvLyBVc2VkIGZvciBzdGF0aXN0aWNzIGluIGF2ZXJhZ2VUaW1lIGFuZCBwcm9jZXNzZWRXb3JrQ291bnQsIHdoaWNoXHJcbiAgICAvLyBpbiB0dXJuIGlzIHVzZWQgYnkgdGhlIC9oZWFsdGggcm91dGUuXHJcbiAgICBjb25zdCB3b3JrRW5kID0gZ2V0TmV3RGF0ZVRpbWUoKTtcclxuICAgIGNvbnN0IGV4cG9ydFRpbWUgPSB3b3JrRW5kIC0gd29ya1N0YXJ0O1xyXG5cclxuICAgIHBvb2xTdGF0cy50aW1lU3BlbnQgKz0gZXhwb3J0VGltZTtcclxuICAgIHBvb2xTdGF0cy50aW1lU3BlbnRBdmVyYWdlID1cclxuICAgICAgcG9vbFN0YXRzLnRpbWVTcGVudCAvICsrcG9vbFN0YXRzLmV4cG9ydHNQZXJmb3JtZWQ7XHJcblxyXG4gICAgbG9nKDQsIGBbcG9vbF0gV29yayBjb21wbGV0ZWQgaW4gJHtleHBvcnRUaW1lfW1zLmApO1xyXG5cclxuICAgIC8vIE90aGVyd2lzZSByZXR1cm4gdGhlIHJlc3VsdFxyXG4gICAgcmV0dXJuIHtcclxuICAgICAgcmVzdWx0LFxyXG4gICAgICBvcHRpb25zXHJcbiAgICB9O1xyXG4gIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICArK3Bvb2xTdGF0cy5leHBvcnRzRHJvcHBlZDtcclxuXHJcbiAgICBpZiAod29ya2VySGFuZGxlKSB7XHJcbiAgICAgIHBvb2wucmVsZWFzZSh3b3JrZXJIYW5kbGUpO1xyXG4gICAgfVxyXG5cclxuICAgIHRocm93IGVycm9yO1xyXG4gIH1cclxufVxyXG5cclxuLyoqXHJcbiAqIFJldHJpZXZlcyB0aGUgY3VycmVudCBwb29sIGluc3RhbmNlLlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gZ2V0UG9vbFxyXG4gKlxyXG4gKiBAcmV0dXJucyB7KE9iamVjdHxudWxsKX0gVGhlIGN1cnJlbnQgcG9vbCBpbnN0YW5jZSBpZiBpbml0aWFsaXplZCwgb3IgbnVsbFxyXG4gKiBpZiB0aGUgcG9vbCBoYXMgbm90IGJlZW4gY3JlYXRlZC5cclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiBnZXRQb29sKCkge1xyXG4gIHJldHVybiBwb29sO1xyXG59XHJcblxyXG4vKipcclxuICogR2V0cyB0aGUgc3RhdGlzdGljIG9mIGEgcG9vbCBpbnN0YWNlIGFib3V0IGV4cG9ydHMuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBnZXRQb29sU3RhdHNcclxuICpcclxuICogQHJldHVybnMge09iamVjdH0gVGhlIGN1cnJlbnQgcG9vbCBzdGF0aXN0aWNzLlxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIGdldFBvb2xTdGF0cygpIHtcclxuICByZXR1cm4gcG9vbFN0YXRzO1xyXG59XHJcblxyXG4vKipcclxuICogUmV0cmlldmVzIHBvb2wgaW5mb3JtYXRpb24gaW4gSlNPTiBmb3JtYXQsIGluY2x1ZGluZyBtaW5pbXVtIGFuZCBtYXhpbXVtXHJcbiAqIHdvcmtlcnMsIGF2YWlsYWJsZSB3b3JrZXJzLCB3b3JrZXJzIGluIHVzZSwgYW5kIHBlbmRpbmcgYWNxdWlyZSByZXF1ZXN0cy5cclxuICpcclxuICogQGZ1bmN0aW9uIGdldFBvb2xJbmZvSlNPTlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7T2JqZWN0fSBQb29sIGluZm9ybWF0aW9uIGluIEpTT04gZm9ybWF0LlxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIGdldFBvb2xJbmZvSlNPTigpIHtcclxuICByZXR1cm4ge1xyXG4gICAgbWluOiBwb29sLm1pbixcclxuICAgIG1heDogcG9vbC5tYXgsXHJcbiAgICB1c2VkOiBwb29sLm51bVVzZWQoKSxcclxuICAgIGF2YWlsYWJsZTogcG9vbC5udW1GcmVlKCksXHJcbiAgICBhbGxDcmVhdGVkOiBwb29sLm51bVVzZWQoKSArIHBvb2wubnVtRnJlZSgpLFxyXG4gICAgcGVuZGluZ0FjcXVpcmVzOiBwb29sLm51bVBlbmRpbmdBY3F1aXJlcygpLFxyXG4gICAgcGVuZGluZ0NyZWF0ZXM6IHBvb2wubnVtUGVuZGluZ0NyZWF0ZXMoKSxcclxuICAgIHBlbmRpbmdWYWxpZGF0aW9uczogcG9vbC5udW1QZW5kaW5nVmFsaWRhdGlvbnMoKSxcclxuICAgIHBlbmRpbmdEZXN0cm95czogcG9vbC5wZW5kaW5nRGVzdHJveXMubGVuZ3RoLFxyXG4gICAgYWJzb2x1dGVBbGw6XHJcbiAgICAgIHBvb2wubnVtVXNlZCgpICtcclxuICAgICAgcG9vbC5udW1GcmVlKCkgK1xyXG4gICAgICBwb29sLm51bVBlbmRpbmdBY3F1aXJlcygpICtcclxuICAgICAgcG9vbC5udW1QZW5kaW5nQ3JlYXRlcygpICtcclxuICAgICAgcG9vbC5udW1QZW5kaW5nVmFsaWRhdGlvbnMoKSArXHJcbiAgICAgIHBvb2wucGVuZGluZ0Rlc3Ryb3lzLmxlbmd0aFxyXG4gIH07XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBMb2dzIGluZm9ybWF0aW9uIGFib3V0IHRoZSBjdXJyZW50IHN0YXRlIG9mIHRoZSBwb29sLCBpbmNsdWRpbmcgdGhlIG1pbmltdW1cclxuICogYW5kIG1heGltdW0gd29ya2VycywgYXZhaWxhYmxlIHdvcmtlcnMsIHdvcmtlcnMgaW4gdXNlLCBhbmQgcGVuZGluZyBhY3F1aXJlXHJcbiAqIHJlcXVlc3RzLlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gZ2V0UG9vbEluZm9cclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiBnZXRQb29sSW5mbygpIHtcclxuICBjb25zdCB7XHJcbiAgICBtaW4sXHJcbiAgICBtYXgsXHJcbiAgICB1c2VkLFxyXG4gICAgYXZhaWxhYmxlLFxyXG4gICAgYWxsQ3JlYXRlZCxcclxuICAgIHBlbmRpbmdBY3F1aXJlcyxcclxuICAgIHBlbmRpbmdDcmVhdGVzLFxyXG4gICAgcGVuZGluZ1ZhbGlkYXRpb25zLFxyXG4gICAgcGVuZGluZ0Rlc3Ryb3lzLFxyXG4gICAgYWJzb2x1dGVBbGxcclxuICB9ID0gZ2V0UG9vbEluZm9KU09OKCk7XHJcblxyXG4gIGxvZyg1LCBgW3Bvb2xdIFRoZSBtaW5pbXVtIG51bWJlciBvZiByZXNvdXJjZXMgYWxsb3dlZCBieSBwb29sOiAke21pbn0uYCk7XHJcbiAgbG9nKDUsIGBbcG9vbF0gVGhlIG1heGltdW0gbnVtYmVyIG9mIHJlc291cmNlcyBhbGxvd2VkIGJ5IHBvb2w6ICR7bWF4fS5gKTtcclxuICBsb2coNSwgYFtwb29sXSBUaGUgbnVtYmVyIG9mIHVzZWQgcmVzb3VyY2VzOiAke3VzZWR9LmApO1xyXG4gIGxvZyg1LCBgW3Bvb2xdIFRoZSBudW1iZXIgb2YgZnJlZSByZXNvdXJjZXM6ICR7YXZhaWxhYmxlfS5gKTtcclxuICBsb2coXHJcbiAgICA1LFxyXG4gICAgYFtwb29sXSBUaGUgbnVtYmVyIG9mIGFsbCBjcmVhdGVkICh1c2VkIGFuZCBmcmVlKSByZXNvdXJjZXM6ICR7YWxsQ3JlYXRlZH0uYFxyXG4gICk7XHJcbiAgbG9nKFxyXG4gICAgNSxcclxuICAgIGBbcG9vbF0gVGhlIG51bWJlciBvZiByZXNvdXJjZXMgd2FpdGluZyB0byBiZSBhY3F1aXJlZDogJHtwZW5kaW5nQWNxdWlyZXN9LmBcclxuICApO1xyXG4gIGxvZyhcclxuICAgIDUsXHJcbiAgICBgW3Bvb2xdIFRoZSBudW1iZXIgb2YgcmVzb3VyY2VzIHdhaXRpbmcgdG8gYmUgY3JlYXRlZDogJHtwZW5kaW5nQ3JlYXRlc30uYFxyXG4gICk7XHJcbiAgbG9nKFxyXG4gICAgNSxcclxuICAgIGBbcG9vbF0gVGhlIG51bWJlciBvZiByZXNvdXJjZXMgd2FpdGluZyB0byBiZSB2YWxpZGF0ZWQ6ICR7cGVuZGluZ1ZhbGlkYXRpb25zfS5gXHJcbiAgKTtcclxuICBsb2coXHJcbiAgICA1LFxyXG4gICAgYFtwb29sXSBUaGUgbnVtYmVyIG9mIHJlc291cmNlcyB3YWl0aW5nIHRvIGJlIGRlc3Ryb3llZDogJHtwZW5kaW5nRGVzdHJveXN9LmBcclxuICApO1xyXG4gIGxvZyg1LCBgW3Bvb2xdIFRoZSBudW1iZXIgb2YgYWxsIHJlc291cmNlczogJHthYnNvbHV0ZUFsbH0uYCk7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBGYWN0b3J5IGZ1bmN0aW9uIHRoYXQgcmV0dXJucyBhbiBvYmplY3Qgd2l0aCBgY3JlYXRlYCwgYHZhbGlkYXRlYCxcclxuICogYW5kIGBkZXN0cm95YCBmdW5jdGlvbnMgZm9yIHRoZSBwb29sIGluc3RhbmNlLlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gX2ZhY3RvcnlcclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IHBvb2xPcHRpb25zIC0gVGhlIGNvbmZpZ3VyYXRpb24gb2JqZWN0IGNvbnRhaW5pbmcgYHBvb2xgXHJcbiAqIG9wdGlvbnMuXHJcbiAqL1xyXG5mdW5jdGlvbiBfZmFjdG9yeShwb29sT3B0aW9ucykge1xyXG4gIHJldHVybiB7XHJcbiAgICAvKipcclxuICAgICAqIENyZWF0ZXMgYSBuZXcgd29ya2VyIHBhZ2UgZm9yIHRoZSBleHBvcnQgcG9vbC5cclxuICAgICAqXHJcbiAgICAgKiBAYXN5bmNcclxuICAgICAqIEBmdW5jdGlvbiBjcmVhdGVcclxuICAgICAqXHJcbiAgICAgKiBAcmV0dXJucyB7UHJvbWlzZTxPYmplY3Q+fSBBIFByb21pc2UgdGhhdCByZXNvbHZlcyB0byBhbiBvYmplY3RcclxuICAgICAqIGNvbnRhaW5pbmcgdGhlIHdvcmtlciBJRCwgYSByZWZlcmVuY2UgdG8gdGhlIGJyb3dzZXIgcGFnZSwgYW5kIGluaXRpYWxcclxuICAgICAqIHdvcmsgY291bnQuXHJcbiAgICAgKlxyXG4gICAgICogQHRocm93cyB7RXhwb3J0RXJyb3J9IFRocm93cyBhbiBgRXhwb3J0RXJyb3JgIGlmIHRoZXJlIGlzIGFuIGVycm9yIGR1cmluZ1xyXG4gICAgICogdGhlIGNyZWF0aW9uIG9mIHRoZSBuZXcgcGFnZS5cclxuICAgICAqL1xyXG4gICAgY3JlYXRlOiBhc3luYyAoKSA9PiB7XHJcbiAgICAgIC8vIEluaXQgdGhlIHJlc291cmNlIHdpdGggdW5pcXVlIGlkIGFuZCB3b3JrIGNvdW50XHJcbiAgICAgIGNvbnN0IHBvb2xSZXNvdXJjZSA9IHtcclxuICAgICAgICBpZDogdXVpZCgpLFxyXG4gICAgICAgIC8vIFRyeSB0byBkaXN0cmlidXRlIHRoZSBpbml0aWFsIHdvcmsgY291bnRcclxuICAgICAgICB3b3JrQ291bnQ6IE1hdGgucm91bmQoTWF0aC5yYW5kb20oKSAqIChwb29sT3B0aW9ucy53b3JrTGltaXQgLyAyKSlcclxuICAgICAgfTtcclxuXHJcbiAgICAgIHRyeSB7XHJcbiAgICAgICAgLy8gU3RhcnQgbWVhc3VyaW5nIGEgcGFnZSBjcmVhdGlvbiB0aW1lXHJcbiAgICAgICAgY29uc3Qgc3RhcnREYXRlID0gZ2V0TmV3RGF0ZVRpbWUoKTtcclxuXHJcbiAgICAgICAgLy8gQ3JlYXRlIGEgbmV3IHBhZ2VcclxuICAgICAgICBhd2FpdCBuZXdQYWdlKHBvb2xSZXNvdXJjZSk7XHJcblxyXG4gICAgICAgIC8vIE1lYXN1cmUgdGhlIHRpbWUgb2YgZnVsbCBjcmVhdGlvbiBhbmQgY29uZmlndXJhdGlvbiBvZiBhIHBhZ2VcclxuICAgICAgICBsb2coXHJcbiAgICAgICAgICAzLFxyXG4gICAgICAgICAgYFtwb29sXSBQb29sIHJlc291cmNlIFske3Bvb2xSZXNvdXJjZS5pZH1dIC0gU3VjY2Vzc2Z1bGx5IGNyZWF0ZWQgYSB3b3JrZXIsIHRvb2sgJHtcclxuICAgICAgICAgICAgZ2V0TmV3RGF0ZVRpbWUoKSAtIHN0YXJ0RGF0ZVxyXG4gICAgICAgICAgfW1zLmBcclxuICAgICAgICApO1xyXG5cclxuICAgICAgICAvLyBSZXR1cm4gcmVhZHkgcG9vbCByZXNvdXJjZVxyXG4gICAgICAgIHJldHVybiBwb29sUmVzb3VyY2U7XHJcbiAgICAgIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICAgICAgbG9nKFxyXG4gICAgICAgICAgMyxcclxuICAgICAgICAgIGBbcG9vbF0gUG9vbCByZXNvdXJjZSBbJHtwb29sUmVzb3VyY2UuaWR9XSAtIEVycm9yIGVuY291bnRlcmVkIHdoZW4gY3JlYXRpbmcgYSBuZXcgcGFnZS5gXHJcbiAgICAgICAgKTtcclxuICAgICAgICB0aHJvdyBlcnJvcjtcclxuICAgICAgfVxyXG4gICAgfSxcclxuXHJcbiAgICAvKipcclxuICAgICAqIFZhbGlkYXRlcyBhIHdvcmtlciBwYWdlIGluIHRoZSBleHBvcnQgcG9vbCwgY2hlY2tpbmcgaWYgaXQgaGFzIGV4Y2VlZGVkXHJcbiAgICAgKiB0aGUgd29yayBsaW1pdC5cclxuICAgICAqXHJcbiAgICAgKiBAYXN5bmNcclxuICAgICAqIEBmdW5jdGlvbiB2YWxpZGF0ZVxyXG4gICAgICpcclxuICAgICAqIEBwYXJhbSB7T2JqZWN0fSBwb29sUmVzb3VyY2UgLSBUaGUgaGFuZGxlIHRvIHRoZSB3b3JrZXIsIGNvbnRhaW5pbmdcclxuICAgICAqIHRoZSB3b3JrZXIncyBJRCwgYSByZWZlcmVuY2UgdG8gdGhlIGJyb3dzZXIgcGFnZSwgYW5kIHdvcmsgY291bnQuXHJcbiAgICAgKlxyXG4gICAgICogQHJldHVybnMge1Byb21pc2U8Ym9vbGVhbj59IEEgUHJvbWlzZSB0aGF0IHJlc29sdmVzIHRvIHRydWUgaWYgdGhlIHdvcmtlclxyXG4gICAgICogaXMgdmFsaWQgYW5kIHdpdGhpbiB0aGUgd29yayBsaW1pdDsgb3RoZXJ3aXNlLCB0byBmYWxzZS5cclxuICAgICAqL1xyXG4gICAgdmFsaWRhdGU6IGFzeW5jIChwb29sUmVzb3VyY2UpID0+IHtcclxuICAgICAgLy8gTk9URTpcclxuICAgICAgLy8gSW4gY2VydGFpbiBjYXNlcyBhY3F1aXJpbmcgdGhyb3dzIGEgVGFyZ2V0Q2xvc2VFcnJvciwgd2hpY2ggbWF5XHJcbiAgICAgIC8vIGJlIGNhdXNlZCBieSB0d28gdGhpbmdzOlxyXG4gICAgICAvLyAtIFRoZSBwYWdlIGlzIGNsb3NlZCBhbmQgYXR0ZW1wdGVkIHRvIGJlIHJldXNlZC5cclxuICAgICAgLy8gLSBMb3N0IGNvbnRhY3Qgd2l0aCB0aGUgYnJvd3Nlci5cclxuICAgICAgLy9cclxuICAgICAgLy8gV2hhdCB3ZSdyZSBzZWVpbmcgaW4gbG9ncyBpcyB0aGF0IHN1Y2Nlc3NpdmUgZXhwb3J0cyB0eXBpY2FsbHlcclxuICAgICAgLy8gc3VjY2VlZHMsIGFuZCB0aGUgc2VydmVyIHJlY292ZXJzLCBpbmRpY2F0aW5nIHRoYXQgaXQncyBsaWtlbHlcclxuICAgICAgLy8gdGhlIGZpcnN0IGNhc2UuIFRoaXMgaXMgYW4gYXR0ZW1wdCBhdCBhbGxpZXZhdGluZyB0aGUgaXNzdWUgYnlcclxuICAgICAgLy8gc2ltcGx5IG5vdCB2YWxpZGF0aW5nIHRoZSB3b3JrZXIgaWYgdGhlIHBhZ2UgaXMgbnVsbCBvciBjbG9zZWQuXHJcbiAgICAgIC8vXHJcbiAgICAgIC8vIFRoZSBhY3R1YWwgcmVzdWx0IGZyb20gd2hlbiB0aGlzIGhhcHBlbmVkLCB3YXMgdGhhdCBhIHdvcmtlciB3b3VsZFxyXG4gICAgICAvLyBiZSBjb21wbGV0ZWx5IGxvY2tlZCwgc3RvcHBpbmcgaXQgZnJvbSBiZWluZyBhY3F1aXJlZCB1bnRpbFxyXG4gICAgICAvLyBpdHMgd29yayBjb3VudCByZWFjaGVkIHRoZSBsaW1pdC5cclxuXHJcbiAgICAgIC8vIENoZWNrIGlmIHRoZSBgcGFnZWAgaXMgdmFsaWRcclxuICAgICAgaWYgKCFwb29sUmVzb3VyY2UucGFnZSkge1xyXG4gICAgICAgIGxvZyhcclxuICAgICAgICAgIDMsXHJcbiAgICAgICAgICBgW3Bvb2xdIFBvb2wgcmVzb3VyY2UgWyR7cG9vbFJlc291cmNlLmlkfV0gLSBWYWxpZGF0aW9uIGZhaWxlZCAobm8gdmFsaWQgcGFnZSBpcyBmb3VuZCkuYFxyXG4gICAgICAgICk7XHJcbiAgICAgICAgcmV0dXJuIGZhbHNlO1xyXG4gICAgICB9XHJcblxyXG4gICAgICAvLyBDaGVjayBpZiB0aGUgYHBhZ2VgIGlzIGNsb3NlZFxyXG4gICAgICBpZiAocG9vbFJlc291cmNlLnBhZ2UuaXNDbG9zZWQoKSkge1xyXG4gICAgICAgIGxvZyhcclxuICAgICAgICAgIDMsXHJcbiAgICAgICAgICBgW3Bvb2xdIFBvb2wgcmVzb3VyY2UgWyR7cG9vbFJlc291cmNlLmlkfV0gLSBWYWxpZGF0aW9uIGZhaWxlZCAocGFnZSBpcyBjbG9zZWQgb3IgaW52YWxpZCkuYFxyXG4gICAgICAgICk7XHJcbiAgICAgICAgcmV0dXJuIGZhbHNlO1xyXG4gICAgICB9XHJcblxyXG4gICAgICAvLyBDaGVjayBpZiB0aGUgYG1haW5GcmFtZWAgaXMgZGV0YWNoZWRcclxuICAgICAgaWYgKHBvb2xSZXNvdXJjZS5wYWdlLm1haW5GcmFtZSgpLmRldGFjaGVkKSB7XHJcbiAgICAgICAgbG9nKFxyXG4gICAgICAgICAgMyxcclxuICAgICAgICAgIGBbcG9vbF0gUG9vbCByZXNvdXJjZSBbJHtwb29sUmVzb3VyY2UuaWR9XSAtIFZhbGlkYXRpb24gZmFpbGVkIChwYWdlJ3MgZnJhbWUgaXMgZGV0YWNoZWQpLmBcclxuICAgICAgICApO1xyXG4gICAgICAgIHJldHVybiBmYWxzZTtcclxuICAgICAgfVxyXG5cclxuICAgICAgLy8gQ2hlY2sgaWYgdGhlIGB3b3JrTGltaXRgIGlzIGV4Y2VlZGVkXHJcbiAgICAgIGlmIChcclxuICAgICAgICBwb29sT3B0aW9ucy53b3JrTGltaXQgJiZcclxuICAgICAgICArK3Bvb2xSZXNvdXJjZS53b3JrQ291bnQgPiBwb29sT3B0aW9ucy53b3JrTGltaXRcclxuICAgICAgKSB7XHJcbiAgICAgICAgbG9nKFxyXG4gICAgICAgICAgMyxcclxuICAgICAgICAgIGBbcG9vbF0gUG9vbCByZXNvdXJjZSBbJHtwb29sUmVzb3VyY2UuaWR9XSAtIFZhbGlkYXRpb24gZmFpbGVkIChleGNlZWRlZCB0aGUgJHtwb29sT3B0aW9ucy53b3JrTGltaXR9IHdvcmtzIHBlciByZXNvdXJjZSBsaW1pdCkuYFxyXG4gICAgICAgICk7XHJcbiAgICAgICAgcmV0dXJuIGZhbHNlO1xyXG4gICAgICB9XHJcblxyXG4gICAgICAvLyBUaGUgYHBvb2xSZXNvdXJjZWAgaXMgdmFsaWRhdGVkXHJcbiAgICAgIHJldHVybiB0cnVlO1xyXG4gICAgfSxcclxuXHJcbiAgICAvKipcclxuICAgICAqIERlc3Ryb3lzIGEgd29ya2VyIGVudHJ5IGluIHRoZSBleHBvcnQgcG9vbCwgY2xvc2luZyBpdHMgYXNzb2NpYXRlZCBwYWdlLlxyXG4gICAgICpcclxuICAgICAqIEBhc3luY1xyXG4gICAgICogQGZ1bmN0aW9uIGRlc3Ryb3lcclxuICAgICAqXHJcbiAgICAgKiBAcGFyYW0ge09iamVjdH0gcG9vbFJlc291cmNlIC0gVGhlIGhhbmRsZSB0byB0aGUgd29ya2VyLCBjb250YWluaW5nXHJcbiAgICAgKiB0aGUgd29ya2VyJ3MgSUQsIGEgcmVmZXJlbmNlIHRvIHRoZSBicm93c2VyIHBhZ2UsIGFuZCB3b3JrIGNvdW50LlxyXG4gICAgICovXHJcbiAgICBkZXN0cm95OiBhc3luYyAocG9vbFJlc291cmNlKSA9PiB7XHJcbiAgICAgIGxvZyhcclxuICAgICAgICAzLFxyXG4gICAgICAgIGBbcG9vbF0gUG9vbCByZXNvdXJjZSBbJHtwb29sUmVzb3VyY2UuaWR9XSAtIERlc3Ryb3lpbmcgYSB3b3JrZXIuYFxyXG4gICAgICApO1xyXG5cclxuICAgICAgaWYgKHBvb2xSZXNvdXJjZS5wYWdlICYmICFwb29sUmVzb3VyY2UucGFnZS5pc0Nsb3NlZCgpKSB7XHJcbiAgICAgICAgdHJ5IHtcclxuICAgICAgICAgIC8vIFJlbW92ZSBhbGwgYXR0YWNoZWQgZXZlbnQgbGlzdGVuZXJzIGZyb20gdGhlIHJlc291cmNlXHJcbiAgICAgICAgICBwb29sUmVzb3VyY2UucGFnZS5yZW1vdmVBbGxMaXN0ZW5lcnMoJ3BhZ2VlcnJvcicpO1xyXG4gICAgICAgICAgcG9vbFJlc291cmNlLnBhZ2UucmVtb3ZlQWxsTGlzdGVuZXJzKCdjb25zb2xlJyk7XHJcbiAgICAgICAgICBwb29sUmVzb3VyY2UucGFnZS5yZW1vdmVBbGxMaXN0ZW5lcnMoJ2ZyYW1lZGV0YWNoZWQnKTtcclxuXHJcbiAgICAgICAgICAvLyBXZSBuZWVkIHRvIHdhaXQgYXJvdW5kIGZvciB0aGlzXHJcbiAgICAgICAgICBhd2FpdCBwb29sUmVzb3VyY2UucGFnZS5jbG9zZSgpO1xyXG4gICAgICAgIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICAgICAgICBsb2coXHJcbiAgICAgICAgICAgIDMsXHJcbiAgICAgICAgICAgIGBbcG9vbF0gUG9vbCByZXNvdXJjZSBbJHtwb29sUmVzb3VyY2UuaWR9XSAtIFBhZ2UgY291bGQgbm90IGJlIGNsb3NlZCB1cG9uIGRlc3Ryb3lpbmcuYFxyXG4gICAgICAgICAgKTtcclxuICAgICAgICAgIHRocm93IGVycm9yO1xyXG4gICAgICAgIH1cclxuICAgICAgfVxyXG4gICAgfVxyXG4gIH07XHJcbn1cclxuXHJcbmV4cG9ydCBkZWZhdWx0IHtcclxuICBpbml0UG9vbCxcclxuICBraWxsUG9vbCxcclxuICBwb3N0V29yayxcclxuICBnZXRQb29sLFxyXG4gIGdldFBvb2xTdGF0cyxcclxuICBnZXRQb29sSW5mbyxcclxuICBnZXRQb29sSW5mb0pTT05cclxufTtcclxuIiwiLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcclxuXHJcbkhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlclxyXG5cclxuQ29weXJpZ2h0IChjKSAyMDE2LTIwMjUsIEhpZ2hzb2Z0XHJcblxyXG5MaWNlbmNlZCB1bmRlciB0aGUgTUlUIGxpY2VuY2UuXHJcblxyXG5BZGRpdGlvbmFsbHkgYSB2YWxpZCBIaWdoY2hhcnRzIGxpY2Vuc2UgaXMgcmVxdWlyZWQgZm9yIHVzZS5cclxuXHJcblNlZSBMSUNFTlNFIGZpbGUgaW4gcm9vdCBmb3IgZGV0YWlscy5cclxuXHJcbioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXHJcblxyXG4vKipcclxuICogQG92ZXJ2aWV3IFVzZWQgdG8gc2FuaXRpemUgdGhlIHN0cmluZ3MgY29taW5nIGZyb20gdGhlIGV4cG9ydGluZyBtb2R1bGVcclxuICogdG8gcHJldmVudCBYU1MgYXR0YWNrcyAod2l0aCB0aGUgRE9NUHVyaWZ5IGxpYnJhcnkpLlxyXG4gKi9cclxuXHJcbmltcG9ydCBET01QdXJpZnkgZnJvbSAnZG9tcHVyaWZ5JztcclxuaW1wb3J0IHsgSlNET00gfSBmcm9tICdqc2RvbSc7XHJcblxyXG4vKipcclxuICogU2FuaXRpemVzIGEgZ2l2ZW4gSFRNTCBzdHJpbmcgYnkgcmVtb3ZpbmcgPHNjcmlwdD4gdGFncy4gVGhpcyBmdW5jdGlvbiB1c2VzXHJcbiAqIGEgcmVndWxhciBleHByZXNzaW9uIHRvIGZpbmQgYW5kIHJlbW92ZSBhbGwgb2NjdXJyZW5jZXMgb2YgPHNjcmlwdD48L3NjcmlwdD5cclxuICogdGFncyBhbmQgYW55IGNvbnRlbnQgd2l0aGluIHRoZW0uXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBzYW5pdGl6ZVxyXG4gKlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gaW5wdXQgLSBUaGUgSFRNTCBzdHJpbmcgdG8gYmUgc2FuaXRpemVkLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7c3RyaW5nfSBUaGUgc2FuaXRpemVkIEhUTUwgc3RyaW5nLlxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIHNhbml0aXplKGlucHV0KSB7XHJcbiAgLy8gR2V0IHRoZSB2aXJ0dWFsIERPTVxyXG4gIGNvbnN0IHdpbmRvdyA9IG5ldyBKU0RPTSgnJykud2luZG93O1xyXG5cclxuICAvLyBDcmVhdGUgYSBwdXJpZnlpbmcgaW5zdGFuY2VcclxuICBjb25zdCBwdXJpZnkgPSBET01QdXJpZnkod2luZG93KTtcclxuXHJcbiAgLy8gUmV0dXJuIHNhbml0aXplZCBpbnB1dFxyXG4gIHJldHVybiBwdXJpZnkuc2FuaXRpemUoaW5wdXQsIHsgQUREX1RBR1M6IFsnZm9yZWlnbk9iamVjdCddIH0pO1xyXG59XHJcblxyXG5leHBvcnQgZGVmYXVsdCB7XHJcbiAgc2FuaXRpemVcclxufTtcclxuIiwiLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcclxuXHJcbkhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlclxyXG5cclxuQ29weXJpZ2h0IChjKSAyMDE2LTIwMjUsIEhpZ2hzb2Z0XHJcblxyXG5MaWNlbmNlZCB1bmRlciB0aGUgTUlUIGxpY2VuY2UuXHJcblxyXG5BZGRpdGlvbmFsbHkgYSB2YWxpZCBIaWdoY2hhcnRzIGxpY2Vuc2UgaXMgcmVxdWlyZWQgZm9yIHVzZS5cclxuXHJcblNlZSBMSUNFTlNFIGZpbGUgaW4gcm9vdCBmb3IgZGV0YWlscy5cclxuXHJcbioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXHJcblxyXG4vKipcclxuICogQG92ZXJ2aWV3IFRoaXMgbW9kdWxlIHByb3ZpZGVzIGZ1bmN0aW9ucyB0byBwcmVwYXJlIGZvciB0aGUgZXhwb3J0aW5nIGNoYXJ0c1xyXG4gKiBpbnRvIHZhcmlvdXMgaW1hZ2Ugb3V0cHV0IGZvcm1hdHMgc3VjaCBhcyBKUEVHLCBQTkcsIFBERiwgYW5kIFNWR3MuXHJcbiAqIEl0IHN1cHBvcnRzIHNpbmdsZSBhbmQgYmF0Y2ggZXhwb3J0IG9wZXJhdGlvbnMgYW5kIGFsbG93cyBjdXN0b21pemF0aW9uXHJcbiAqIHRocm91Z2ggb3B0aW9ucyBwYXNzZWQgZnJvbSBjb25maWd1cmF0aW9ucyBvciBBUElzLlxyXG4gKi9cclxuXHJcbmltcG9ydCB7IHJlYWRGaWxlU3luYywgd3JpdGVGaWxlU3luYyB9IGZyb20gJ2ZzJztcclxuXHJcbmltcG9ydCB7IGlzQWxsb3dlZENvbmZpZywgdXBkYXRlT3B0aW9ucywgdmFsaWRhdGVPcHRpb24gfSBmcm9tICcuL2NvbmZpZy5qcyc7XHJcbmltcG9ydCB7IGxvZywgbG9nV2l0aFN0YWNrIH0gZnJvbSAnLi9sb2dnZXIuanMnO1xyXG5pbXBvcnQgeyBnZXRQb29sU3RhdHMsIGtpbGxQb29sLCBwb3N0V29yayB9IGZyb20gJy4vcG9vbC5qcyc7XHJcbmltcG9ydCB7IHNhbml0aXplIH0gZnJvbSAnLi9zYW5pdGl6ZS5qcyc7XHJcbmltcG9ydCB7XHJcbiAgZml4Q29uc3RyLFxyXG4gIGZpeE91dGZpbGUsXHJcbiAgZml4VHlwZSxcclxuICBnZXRBYnNvbHV0ZVBhdGgsXHJcbiAgZ2V0QmFzZTY0LFxyXG4gIGlzT2JqZWN0LFxyXG4gIHJvdW5kTnVtYmVyLFxyXG4gIHdyYXBBcm91bmRcclxufSBmcm9tICcuL3V0aWxzLmpzJztcclxuXHJcbmltcG9ydCBFeHBvcnRFcnJvciBmcm9tICcuL2Vycm9ycy9FeHBvcnRFcnJvci5qcyc7XHJcblxyXG4vLyBUaGUgZ2xvYmFsIGZsYWcgZm9yIHRoZSBjb2RlIGV4ZWN1dGlvbiBwZXJtaXNzaW9uXHJcbmxldCBhbGxvd0NvZGVFeGVjdXRpb24gPSBmYWxzZTtcclxuXHJcbi8qKlxyXG4gKiBTdGFydHMgYSBzaW5nbGUgZXhwb3J0IHByb2Nlc3MgYmFzZWQgb24gdGhlIHNwZWNpZmllZCBvcHRpb25zIGFuZCBzYXZlc1xyXG4gKiB0aGUgcmVzdWx0aW5nIGltYWdlIHRvIHRoZSBwcm92aWRlZCBvdXRwdXQgZmlsZS5cclxuICpcclxuICogQGFzeW5jXHJcbiAqIEBmdW5jdGlvbiBzaW5nbGVFeHBvcnRcclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IG9wdGlvbnMgLSBUaGUgYG9wdGlvbnNgIG9iamVjdCwgd2hpY2ggc2hvdWxkIGluY2x1ZGUgc2V0dGluZ3NcclxuICogZnJvbSB0aGUgYGV4cG9ydGAgYW5kIGBjdXN0b21Mb2dpY2Agc2VjdGlvbnMuIEl0IGNhbiBiZSBhIHBhcnRpYWwgb3IgY29tcGxldGVcclxuICogc2V0IG9mIG9wdGlvbnMgZnJvbSB0aGVzZSBzZWN0aW9ucy4gVGhlIG9iamVjdCBtdXN0IGNvbnRhaW4gYXQgbGVhc3Qgb25lXHJcbiAqIG9mIHRoZSBmb2xsb3dpbmcgYGV4cG9ydGAgcHJvcGVydGllczogYGluZmlsZWAsIGBpbnN0cmAsIGBvcHRpb25zYCwgb3IgYHN2Z2BcclxuICogdG8gZ2VuZXJhdGUgYSB2YWxpZCBpbWFnZS5cclxuICpcclxuICogQHJldHVybnMge1Byb21pc2U8dm9pZD59IEEgUHJvbWlzZSB0aGF0IHJlc29sdmVzIG9uY2UgdGhlIHNpbmdsZSBleHBvcnRcclxuICogcHJvY2VzcyBpcyBjb21wbGV0ZWQuXHJcbiAqXHJcbiAqIEB0aHJvd3Mge0V4cG9ydEVycm9yfSBUaHJvd3MgYW4gYEV4cG9ydEVycm9yYCBpZiBhbiBlcnJvciBvY2N1cnMgZHVyaW5nXHJcbiAqIHRoZSBzaW5nbGUgZXhwb3J0IHByb2Nlc3MuXHJcbiAqL1xyXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gc2luZ2xlRXhwb3J0KG9wdGlvbnMpIHtcclxuICAvLyBDaGVjayBpZiB0aGUgZXhwb3J0IG1ha2VzIHNlbnNlXHJcbiAgaWYgKG9wdGlvbnMgJiYgb3B0aW9ucy5leHBvcnQpIHtcclxuICAgIC8vIFBlcmZvcm0gYW4gZXhwb3J0XHJcbiAgICBhd2FpdCBzdGFydEV4cG9ydChcclxuICAgICAgeyBleHBvcnQ6IG9wdGlvbnMuZXhwb3J0LCBjdXN0b21Mb2dpYzogb3B0aW9ucy5jdXN0b21Mb2dpYyB9LFxyXG4gICAgICBhc3luYyAoZXJyb3IsIGRhdGEpID0+IHtcclxuICAgICAgICAvLyBFeGl0IHByb2Nlc3Mgd2hlbiBlcnJvciBleGlzdHNcclxuICAgICAgICBpZiAoZXJyb3IpIHtcclxuICAgICAgICAgIHRocm93IGVycm9yO1xyXG4gICAgICAgIH1cclxuXHJcbiAgICAgICAgLy8gR2V0IHRoZSBgYjY0YCwgYG91dGZpbGVgLCBhbmQgYHR5cGVgIGZvciBhIGNoYXJ0XHJcbiAgICAgICAgY29uc3QgeyBiNjQsIG91dGZpbGUsIHR5cGUgfSA9IGRhdGEub3B0aW9ucy5leHBvcnQ7XHJcblxyXG4gICAgICAgIC8vIFNhdmUgdGhlIHJlc3VsdFxyXG4gICAgICAgIHRyeSB7XHJcbiAgICAgICAgICBpZiAoYjY0KSB7XHJcbiAgICAgICAgICAgIC8vIEFzIGEgQmFzZTY0IHN0cmluZyB0byBhIHR4dCBmaWxlXHJcbiAgICAgICAgICAgIHdyaXRlRmlsZVN5bmMoXHJcbiAgICAgICAgICAgICAgYCR7b3V0ZmlsZS5zcGxpdCgnLicpLnNoaWZ0KCkgfHwgJ2NoYXJ0J30udHh0YCxcclxuICAgICAgICAgICAgICBnZXRCYXNlNjQoZGF0YS5yZXN1bHQsIHR5cGUpXHJcbiAgICAgICAgICAgICk7XHJcbiAgICAgICAgICB9IGVsc2Uge1xyXG4gICAgICAgICAgICAvLyBBcyBhIGNvcnJlY3QgaW1hZ2UgZm9ybWF0XHJcbiAgICAgICAgICAgIHdyaXRlRmlsZVN5bmMoXHJcbiAgICAgICAgICAgICAgb3V0ZmlsZSB8fCBgY2hhcnQuJHt0eXBlfWAsXHJcbiAgICAgICAgICAgICAgdHlwZSAhPT0gJ3N2ZycgPyBCdWZmZXIuZnJvbShkYXRhLnJlc3VsdCwgJ2Jhc2U2NCcpIDogZGF0YS5yZXN1bHRcclxuICAgICAgICAgICAgKTtcclxuICAgICAgICAgIH1cclxuICAgICAgICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgICAgICAgdGhyb3cgbmV3IEV4cG9ydEVycm9yKFxyXG4gICAgICAgICAgICAnW2NoYXJ0XSBFcnJvciB3aGlsZSBzYXZpbmcgYSBjaGFydC4nLFxyXG4gICAgICAgICAgICA1MDBcclxuICAgICAgICAgICkuc2V0RXJyb3IoZXJyb3IpO1xyXG4gICAgICAgIH1cclxuXHJcbiAgICAgICAgLy8gS2lsbCBwb29sIGFuZCBjbG9zZSBicm93c2VyIGFmdGVyIGZpbmlzaGluZyBzaW5nbGUgZXhwb3J0XHJcbiAgICAgICAgYXdhaXQga2lsbFBvb2woKTtcclxuICAgICAgfVxyXG4gICAgKTtcclxuICB9IGVsc2Uge1xyXG4gICAgdGhyb3cgbmV3IEV4cG9ydEVycm9yKFxyXG4gICAgICAnW2NoYXJ0XSBObyBleHBlY3RlZCBgZXhwb3J0YCBvcHRpb25zIHdlcmUgZm91bmQuIFBsZWFzZSBwcm92aWRlIG9uZSBvZiB0aGUgZm9sbG93aW5nIG9wdGlvbnM6IGBpbmZpbGVgLCBgaW5zdHJgLCBgb3B0aW9uc2AsIG9yIGBzdmdgIHRvIGdlbmVyYXRlIGEgdmFsaWQgaW1hZ2UuJyxcclxuICAgICAgNDAwXHJcbiAgICApO1xyXG4gIH1cclxufVxyXG5cclxuLyoqXHJcbiAqIFN0YXJ0cyBhIGJhdGNoIGV4cG9ydCBwcm9jZXNzIGZvciBtdWx0aXBsZSBjaGFydHMgYmFzZWQgb24gaW5mb3JtYXRpb25cclxuICogcHJvdmlkZWQgaW4gdGhlIGBiYXRjaGAgb3B0aW9uLiBUaGUgYGJhdGNoYCBpcyBhIHN0cmluZyBpbiB0aGUgZm9sbG93aW5nXHJcbiAqIGZvcm1hdDogXCJpbmZpbGUxLmpzb249b3V0ZmlsZTEucG5nO2luZmlsZTIuanNvbj1vdXRmaWxlMi5wbmc7Li4uXCIuIFJlc3VsdHNcclxuICogYXJlIHNhdmVkIHRvIHRoZSBzcGVjaWZpZWQgb3V0cHV0IGZpbGVzLlxyXG4gKlxyXG4gKiBAYXN5bmNcclxuICogQGZ1bmN0aW9uIGJhdGNoRXhwb3J0XHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBvcHRpb25zIC0gVGhlIGBvcHRpb25zYCBvYmplY3QsIHdoaWNoIHNob3VsZCBpbmNsdWRlIHNldHRpbmdzXHJcbiAqIGZyb20gdGhlIGBleHBvcnRgIGFuZCBgY3VzdG9tTG9naWNgIHNlY3Rpb25zLiBJdCBjYW4gYmUgYSBwYXJ0aWFsIG9yIGNvbXBsZXRlXHJcbiAqIHNldCBvZiBvcHRpb25zIGZyb20gdGhlc2Ugc2VjdGlvbnMuIEl0IG11c3QgY29udGFpbiB0aGUgYGJhdGNoYCBvcHRpb24gZnJvbVxyXG4gKiB0aGUgYGV4cG9ydGAgc2VjdGlvbiB0byBnZW5lcmF0ZSB2YWxpZCBpbWFnZXMuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtQcm9taXNlPHZvaWQ+fSBBIFByb21pc2UgdGhhdCByZXNvbHZlcyBvbmNlIHRoZSBiYXRjaCBleHBvcnRcclxuICogcHJvY2Vzc2VzIGFyZSBjb21wbGV0ZWQuXHJcbiAqXHJcbiAqIEB0aHJvd3Mge0V4cG9ydEVycm9yfSBUaHJvd3MgYW4gYEV4cG9ydEVycm9yYCBpZiBhbiBlcnJvciBvY2N1cnMgZHVyaW5nXHJcbiAqIGFueSBvZiB0aGUgYmF0Y2ggZXhwb3J0IHByb2Nlc3MuXHJcbiAqL1xyXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gYmF0Y2hFeHBvcnQob3B0aW9ucykge1xyXG4gIC8vIENoZWNrIGlmIHRoZSBleHBvcnQgbWFrZXMgc2Vuc2VcclxuICBpZiAob3B0aW9ucyAmJiBvcHRpb25zLmV4cG9ydCAmJiBvcHRpb25zLmV4cG9ydC5iYXRjaCkge1xyXG4gICAgLy8gQW4gYXJyYXkgZm9yIGNvbGxlY3RpbmcgYmF0Y2ggZXhwb3J0c1xyXG4gICAgY29uc3QgYmF0Y2hGdW5jdGlvbnMgPSBbXTtcclxuXHJcbiAgICAvLyBTcGxpdCBhbmQgcGFpciB0aGUgYGJhdGNoYCBhcmd1bWVudHNcclxuICAgIGZvciAobGV0IHBhaXIgb2Ygb3B0aW9ucy5leHBvcnQuYmF0Y2guc3BsaXQoJzsnKSB8fCBbXSkge1xyXG4gICAgICBwYWlyID0gcGFpci5zcGxpdCgnPScpO1xyXG4gICAgICBpZiAocGFpci5sZW5ndGggPT09IDIpIHtcclxuICAgICAgICBiYXRjaEZ1bmN0aW9ucy5wdXNoKFxyXG4gICAgICAgICAgc3RhcnRFeHBvcnQoXHJcbiAgICAgICAgICAgIHtcclxuICAgICAgICAgICAgICBleHBvcnQ6IHtcclxuICAgICAgICAgICAgICAgIC4uLm9wdGlvbnMuZXhwb3J0LFxyXG4gICAgICAgICAgICAgICAgaW5maWxlOiBwYWlyWzBdLFxyXG4gICAgICAgICAgICAgICAgb3V0ZmlsZTogcGFpclsxXVxyXG4gICAgICAgICAgICAgIH0sXHJcbiAgICAgICAgICAgICAgY3VzdG9tTG9naWM6IG9wdGlvbnMuY3VzdG9tTG9naWNcclxuICAgICAgICAgICAgfSxcclxuICAgICAgICAgICAgKGVycm9yLCBkYXRhKSA9PiB7XHJcbiAgICAgICAgICAgICAgLy8gRXhpdCBwcm9jZXNzIHdoZW4gZXJyb3IgZXhpc3RzXHJcbiAgICAgICAgICAgICAgaWYgKGVycm9yKSB7XHJcbiAgICAgICAgICAgICAgICB0aHJvdyBlcnJvcjtcclxuICAgICAgICAgICAgICB9XHJcblxyXG4gICAgICAgICAgICAgIC8vIEdldCB0aGUgYGI2NGAsIGBvdXRmaWxlYCwgYW5kIGB0eXBlYCBmb3IgYSBjaGFydFxyXG4gICAgICAgICAgICAgIGNvbnN0IHsgYjY0LCBvdXRmaWxlLCB0eXBlIH0gPSBkYXRhLm9wdGlvbnMuZXhwb3J0O1xyXG5cclxuICAgICAgICAgICAgICAvLyBTYXZlIHRoZSByZXN1bHRcclxuICAgICAgICAgICAgICB0cnkge1xyXG4gICAgICAgICAgICAgICAgaWYgKGI2NCkge1xyXG4gICAgICAgICAgICAgICAgICAvLyBBcyBhIEJhc2U2NCBzdHJpbmcgdG8gYSB0eHQgZmlsZVxyXG4gICAgICAgICAgICAgICAgICB3cml0ZUZpbGVTeW5jKFxyXG4gICAgICAgICAgICAgICAgICAgIGAke291dGZpbGUuc3BsaXQoJy4nKS5zaGlmdCgpIHx8ICdjaGFydCd9LnR4dGAsXHJcbiAgICAgICAgICAgICAgICAgICAgZ2V0QmFzZTY0KGRhdGEucmVzdWx0LCB0eXBlKVxyXG4gICAgICAgICAgICAgICAgICApO1xyXG4gICAgICAgICAgICAgICAgfSBlbHNlIHtcclxuICAgICAgICAgICAgICAgICAgLy8gQXMgYSBjb3JyZWN0IGltYWdlIGZvcm1hdFxyXG4gICAgICAgICAgICAgICAgICB3cml0ZUZpbGVTeW5jKFxyXG4gICAgICAgICAgICAgICAgICAgIG91dGZpbGUsXHJcbiAgICAgICAgICAgICAgICAgICAgdHlwZSAhPT0gJ3N2ZydcclxuICAgICAgICAgICAgICAgICAgICAgID8gQnVmZmVyLmZyb20oZGF0YS5yZXN1bHQsICdiYXNlNjQnKVxyXG4gICAgICAgICAgICAgICAgICAgICAgOiBkYXRhLnJlc3VsdFxyXG4gICAgICAgICAgICAgICAgICApO1xyXG4gICAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICAgIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICAgICAgICAgICAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoXHJcbiAgICAgICAgICAgICAgICAgICdbY2hhcnRdIEVycm9yIHdoaWxlIHNhdmluZyBhIGNoYXJ0LicsXHJcbiAgICAgICAgICAgICAgICAgIDUwMFxyXG4gICAgICAgICAgICAgICAgKS5zZXRFcnJvcihlcnJvcik7XHJcbiAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICB9XHJcbiAgICAgICAgICApXHJcbiAgICAgICAgKTtcclxuICAgICAgfSBlbHNlIHtcclxuICAgICAgICBsb2coMiwgJ1tjaGFydF0gTm8gY29ycmVjdCBwYWlyIGZvdW5kIGZvciB0aGUgYmF0Y2ggZXhwb3J0LicpO1xyXG4gICAgICB9XHJcbiAgICB9XHJcblxyXG4gICAgLy8gQXdhaXQgYWxsIGV4cG9ydHMgYXJlIGRvbmVcclxuICAgIGNvbnN0IGJhdGNoUmVzdWx0cyA9IGF3YWl0IFByb21pc2UuYWxsU2V0dGxlZChiYXRjaEZ1bmN0aW9ucyk7XHJcblxyXG4gICAgLy8gS2lsbCBwb29sIGFuZCBjbG9zZSBicm93c2VyIGFmdGVyIGZpbmlzaGluZyBiYXRjaCBleHBvcnRcclxuICAgIGF3YWl0IGtpbGxQb29sKCk7XHJcblxyXG4gICAgLy8gTG9nIGVycm9ycyBpZiBmb3VuZFxyXG4gICAgYmF0Y2hSZXN1bHRzLmZvckVhY2goKHJlc3VsdCwgaW5kZXgpID0+IHtcclxuICAgICAgLy8gTG9nIHRoZSBlcnJvciB3aXRoIHN0YWNrIGFib3V0IHRoZSBzcGVjaWZpYyBiYXRjaCBleHBvcnRcclxuICAgICAgaWYgKHJlc3VsdC5yZWFzb24pIHtcclxuICAgICAgICBsb2dXaXRoU3RhY2soXHJcbiAgICAgICAgICAxLFxyXG4gICAgICAgICAgcmVzdWx0LnJlYXNvbixcclxuICAgICAgICAgIGBbY2hhcnRdIEJhdGNoIGV4cG9ydCBudW1iZXIgJHtpbmRleCArIDF9IGNvdWxkIG5vdCBiZSBjb3JyZWN0bHkgY29tcGxldGVkLmBcclxuICAgICAgICApO1xyXG4gICAgICB9XHJcbiAgICB9KTtcclxuICB9IGVsc2Uge1xyXG4gICAgdGhyb3cgbmV3IEV4cG9ydEVycm9yKFxyXG4gICAgICAnW2NoYXJ0XSBObyBleHBlY3RlZCBgZXhwb3J0YCBvcHRpb25zIHdlcmUgZm91bmQuIFBsZWFzZSBwcm92aWRlIHRoZSBgYmF0Y2hgIG9wdGlvbiB0byBnZW5lcmF0ZSB2YWxpZCBpbWFnZXMuJyxcclxuICAgICAgNDAwXHJcbiAgICApO1xyXG4gIH1cclxufVxyXG5cclxuLyoqXHJcbiAqIFN0YXJ0cyBhbiBleHBvcnQgcHJvY2Vzcy4gVGhlIGBpbWFnZU9wdGlvbnNgIHBhcmFtZXRlciBpcyBhbiBvYmplY3QgdGhhdFxyXG4gKiBzaG91bGQgaW5jbHVkZSBzZXR0aW5ncyBmcm9tIHRoZSBgZXhwb3J0YCBhbmQgYGN1c3RvbUxvZ2ljYCBzZWN0aW9ucy4gSXQgY2FuXHJcbiAqIGJlIGEgcGFydGlhbCBvciBjb21wbGV0ZSBzZXQgb2Ygb3B0aW9ucyBmcm9tIHRoZXNlIHNlY3Rpb25zLiBJZiBwYXJ0aWFsXHJcbiAqIG9wdGlvbnMgYXJlIHByb3ZpZGVkLCBtaXNzaW5nIHZhbHVlcyB3aWxsIGJlIG1lcmdlZCB3aXRoIHRoZSBjdXJyZW50IGdsb2JhbFxyXG4gKiBvcHRpb25zLlxyXG4gKlxyXG4gKiBUaGUgYGVuZENhbGxiYWNrYCBmdW5jdGlvbiBpcyBpbnZva2VkIHVwb24gdGhlIGNvbXBsZXRpb24gb2YgdGhlIGV4cG9ydCxcclxuICogZWl0aGVyIHN1Y2Nlc3NmdWxseSBvciB3aXRoIGFuIGVycm9yLiBUaGUgYGVycm9yYCBvYmplY3QgaXMgcHJvdmlkZWRcclxuICogYXMgdGhlIGZpcnN0IGFyZ3VtZW50LCBhbmQgdGhlIGBkYXRhYCBvYmplY3QgaXMgdGhlIHNlY29uZCwgY29udGFpbmluZ1xyXG4gKiB0aGUgQmFzZTY0IHJlcHJlc2VudGF0aW9uIG9mIHRoZSBjaGFydCBpbiB0aGUgYHJlc3VsdGAgcHJvcGVydHlcclxuICogYW5kIHRoZSBjb21wbGV0ZSBzZXQgb2Ygb3B0aW9ucyBpbiB0aGUgYG9wdGlvbnNgIHByb3BlcnR5LlxyXG4gKlxyXG4gKiBAYXN5bmNcclxuICogQGZ1bmN0aW9uIHN0YXJ0RXhwb3J0XHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBpbWFnZU9wdGlvbnMgLSBUaGUgYGltYWdlT3B0aW9uc2Agb2JqZWN0LCB3aGljaCBzaG91bGRcclxuICogaW5jbHVkZSBzZXR0aW5ncyBmcm9tIHRoZSBgZXhwb3J0YCBhbmQgYGN1c3RvbUxvZ2ljYCBzZWN0aW9ucy4gSXQgY2FuXHJcbiAqIGJlIGEgcGFydGlhbCBvciBjb21wbGV0ZSBzZXQgb2Ygb3B0aW9ucyBmcm9tIHRoZXNlIHNlY3Rpb25zLiBJZiB0aGUgcHJvdmlkZWRcclxuICogb3B0aW9ucyBhcmUgcGFydGlhbCwgbWlzc2luZyB2YWx1ZXMgd2lsbCBiZSBtZXJnZWQgd2l0aCB0aGUgY3VycmVudCBnbG9iYWxcclxuICogb3B0aW9ucy5cclxuICogQHBhcmFtIHtGdW5jdGlvbn0gZW5kQ2FsbGJhY2sgLSBUaGUgY2FsbGJhY2sgZnVuY3Rpb24gdG8gYmUgaW52b2tlZCB1cG9uXHJcbiAqIGZpbmFsaXppbmcgdGhlIGV4cG9ydCBwcm9jZXNzIG9yIHVwb24gZW5jb3VudGVyaW5nIGFuIGVycm9yLiBUaGUgZmlyc3RcclxuICogYXJndW1lbnQgaXMgdGhlIGBlcnJvcmAgb2JqZWN0LCBhbmQgdGhlIHNlY29uZCBhcmd1bWVudCBpcyB0aGUgYGRhdGFgIG9iamVjdCxcclxuICogd2hpY2ggaW5jbHVkZXMgdGhlIEJhc2U2NCByZXByZXNlbnRhdGlvbiBvZiB0aGUgY2hhcnQgaW4gdGhlIGByZXN1bHRgXHJcbiAqIHByb3BlcnR5IGFuZCB0aGUgZnVsbCBzZXQgb2Ygb3B0aW9ucyBpbiB0aGUgYG9wdGlvbnNgIHByb3BlcnR5LlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7UHJvbWlzZTx2b2lkPn0gVGhpcyBmdW5jdGlvbiBkb2VzIG5vdCByZXR1cm4gYSB2YWx1ZSBkaXJlY3RseS5cclxuICogSW5zdGVhZCwgaXQgY29tbXVuaWNhdGVzIHJlc3VsdHMgdmlhIHRoZSBgZW5kQ2FsbGJhY2tgLlxyXG4gKlxyXG4gKiBAdGhyb3dzIHtFeHBvcnRFcnJvcn0gVGhyb3dzIGFuIGBFeHBvcnRFcnJvcmAgaWYgdGhlcmUgaXMgYSBwcm9ibGVtIHdpdGhcclxuICogcHJvY2Vzc2luZyBpbnB1dCBvZiBhbnkgdHlwZS4gVGhlIGVycm9yIGlzIHBhc3NlZCBpbnRvIHRoZSBgZW5kQ2FsbGJhY2tgXHJcbiAqIGZ1bmN0aW9uIGFuZCBwcm9jZXNzZWQgdGhlcmUuXHJcbiAqL1xyXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gc3RhcnRFeHBvcnQoaW1hZ2VPcHRpb25zLCBlbmRDYWxsYmFjaykge1xyXG4gIHRyeSB7XHJcbiAgICAvLyBDaGVjayBpZiBwcm92aWRlZCBvcHRpb25zIGFyZSBpbiBhbiBvYmplY3RcclxuICAgIGlmICghaXNPYmplY3QoaW1hZ2VPcHRpb25zKSkge1xyXG4gICAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoXHJcbiAgICAgICAgJ1tjaGFydF0gSW5jb3JyZWN0IHZhbHVlIG9mIHRoZSBwcm92aWRlZCBgaW1hZ2VPcHRpb25zYC4gTmVlZHMgdG8gYmUgYW4gb2JqZWN0LicsXHJcbiAgICAgICAgNDAwXHJcbiAgICAgICk7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gTWVyZ2UgYWRkaXRpb25hbCBvcHRpb25zIHRvIHRoZSBjb3B5IG9mIHRoZSBpbnN0YW5jZSBvcHRpb25zXHJcbiAgICBjb25zdCBvcHRpb25zID0gdXBkYXRlT3B0aW9ucyhcclxuICAgICAge1xyXG4gICAgICAgIGV4cG9ydDogaW1hZ2VPcHRpb25zLmV4cG9ydCxcclxuICAgICAgICBjdXN0b21Mb2dpYzogaW1hZ2VPcHRpb25zLmN1c3RvbUxvZ2ljXHJcbiAgICAgIH0sXHJcbiAgICAgIHRydWVcclxuICAgICk7XHJcblxyXG4gICAgLy8gR2V0IHRoZSBgZXhwb3J0YCBvcHRpb25zXHJcbiAgICBjb25zdCBleHBvcnRPcHRpb25zID0gb3B0aW9ucy5leHBvcnQ7XHJcblxyXG4gICAgLy8gU3RhcnRpbmcgZXhwb3J0aW5nIHByb2Nlc3MgbWVzc2FnZVxyXG4gICAgbG9nKDQsICdbY2hhcnRdIFN0YXJ0aW5nIHRoZSBleHBvcnRpbmcgcHJvY2Vzcy4nKTtcclxuXHJcbiAgICAvLyBFeHBvcnQgdXNpbmcgb3B0aW9ucyBmcm9tIHRoZSBmaWxlIGFzIGFuIGlucHV0XHJcbiAgICBpZiAoZXhwb3J0T3B0aW9ucy5pbmZpbGUgIT09IG51bGwpIHtcclxuICAgICAgbG9nKDQsICdbY2hhcnRdIEF0dGVtcHRpbmcgdG8gZXhwb3J0IGZyb20gYSBmaWxlIGlucHV0LicpO1xyXG5cclxuICAgICAgbGV0IGZpbGVDb250ZW50O1xyXG4gICAgICB0cnkge1xyXG4gICAgICAgIC8vIFRyeSB0byByZWFkIHRoZSBmaWxlIHRvIGdldCB0aGUgc3RyaW5nIHJlcHJlc2VudGF0aW9uXHJcbiAgICAgICAgZmlsZUNvbnRlbnQgPSByZWFkRmlsZVN5bmMoXHJcbiAgICAgICAgICBnZXRBYnNvbHV0ZVBhdGgoZXhwb3J0T3B0aW9ucy5pbmZpbGUpLFxyXG4gICAgICAgICAgJ3V0ZjgnXHJcbiAgICAgICAgKTtcclxuICAgICAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoXHJcbiAgICAgICAgICAnW2NoYXJ0XSBFcnJvciBsb2FkaW5nIGNvbnRlbnQgZnJvbSBhIGZpbGUgaW5wdXQuJyxcclxuICAgICAgICAgIDQwMFxyXG4gICAgICAgICkuc2V0RXJyb3IoZXJyb3IpO1xyXG4gICAgICB9XHJcblxyXG4gICAgICAvLyBDaGVjayB0aGUgZmlsZSdzIGV4dGVuc2lvblxyXG4gICAgICBpZiAoZXhwb3J0T3B0aW9ucy5pbmZpbGUuZW5kc1dpdGgoJy5zdmcnKSkge1xyXG4gICAgICAgIC8vIFNldCB0byB0aGUgYHN2Z2Agb3B0aW9uXHJcbiAgICAgICAgZXhwb3J0T3B0aW9ucy5zdmcgPSB2YWxpZGF0ZU9wdGlvbignc3ZnJywgZmlsZUNvbnRlbnQpO1xyXG4gICAgICB9IGVsc2UgaWYgKGV4cG9ydE9wdGlvbnMuaW5maWxlLmVuZHNXaXRoKCcuanNvbicpKSB7XHJcbiAgICAgICAgLy8gU2V0IHRvIHRoZSBgaW5zdHJgIG9wdGlvblxyXG4gICAgICAgIGV4cG9ydE9wdGlvbnMuaW5zdHIgPSB2YWxpZGF0ZU9wdGlvbignaW5zdHInLCBmaWxlQ29udGVudCk7XHJcbiAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgdGhyb3cgbmV3IEV4cG9ydEVycm9yKFxyXG4gICAgICAgICAgJ1tjaGFydF0gSW5jb3JyZWN0IHZhbHVlIG9mIHRoZSBgaW5maWxlYCBvcHRpb24uJyxcclxuICAgICAgICAgIDQwMFxyXG4gICAgICAgICk7XHJcbiAgICAgIH1cclxuICAgIH1cclxuXHJcbiAgICAvLyBFeHBvcnQgdXNpbmcgU1ZHIGFzIGFuIGlucHV0XHJcbiAgICBpZiAoZXhwb3J0T3B0aW9ucy5zdmcgIT09IG51bGwpIHtcclxuICAgICAgbG9nKDQsICdbY2hhcnRdIEF0dGVtcHRpbmcgdG8gZXhwb3J0IGZyb20gYW4gU1ZHIGlucHV0LicpO1xyXG5cclxuICAgICAgLy8gU1ZHIGV4cG9ydHMgYXR0ZW1wdHMgY291bnRlclxyXG4gICAgICArK2dldFBvb2xTdGF0cygpLmV4cG9ydHNGcm9tU3ZnQXR0ZW1wdHM7XHJcblxyXG4gICAgICAvLyBFeHBvcnQgZnJvbSBhbiBTVkcgc3RyaW5nXHJcbiAgICAgIGNvbnN0IHJlc3VsdCA9IGF3YWl0IF9leHBvcnRGcm9tU3ZnKFxyXG4gICAgICAgIHNhbml0aXplKGV4cG9ydE9wdGlvbnMuc3ZnKSwgLy8gIzIwOVxyXG4gICAgICAgIG9wdGlvbnNcclxuICAgICAgKTtcclxuXHJcbiAgICAgIC8vIFNWRyBleHBvcnRzIGNvdW50ZXJcclxuICAgICAgKytnZXRQb29sU3RhdHMoKS5leHBvcnRzRnJvbVN2ZztcclxuXHJcbiAgICAgIC8vIFBhc3MgU1ZHIGV4cG9ydCByZXN1bHQgdG8gdGhlIGVuZCBjYWxsYmFja1xyXG4gICAgICByZXR1cm4gZW5kQ2FsbGJhY2sobnVsbCwgcmVzdWx0KTtcclxuICAgIH1cclxuXHJcbiAgICAvLyBFeHBvcnQgdXNpbmcgb3B0aW9ucyBhcyBhbiBpbnB1dFxyXG4gICAgaWYgKGV4cG9ydE9wdGlvbnMuaW5zdHIgIT09IG51bGwgfHwgZXhwb3J0T3B0aW9ucy5vcHRpb25zICE9PSBudWxsKSB7XHJcbiAgICAgIGxvZyg0LCAnW2NoYXJ0XSBBdHRlbXB0aW5nIHRvIGV4cG9ydCBmcm9tIG9wdGlvbnMgaW5wdXQuJyk7XHJcblxyXG4gICAgICAvLyBPcHRpb25zIGV4cG9ydHMgYXR0ZW1wdHMgY291bnRlclxyXG4gICAgICArK2dldFBvb2xTdGF0cygpLmV4cG9ydHNGcm9tT3B0aW9uc0F0dGVtcHRzO1xyXG5cclxuICAgICAgLy8gRXhwb3J0IGZyb20gb3B0aW9uc1xyXG4gICAgICBjb25zdCByZXN1bHQgPSBhd2FpdCBfZXhwb3J0RnJvbU9wdGlvbnMoXHJcbiAgICAgICAgZXhwb3J0T3B0aW9ucy5pbnN0ciB8fCBleHBvcnRPcHRpb25zLm9wdGlvbnMsXHJcbiAgICAgICAgb3B0aW9uc1xyXG4gICAgICApO1xyXG5cclxuICAgICAgLy8gT3B0aW9ucyBleHBvcnRzIGNvdW50ZXJcclxuICAgICAgKytnZXRQb29sU3RhdHMoKS5leHBvcnRzRnJvbU9wdGlvbnM7XHJcblxyXG4gICAgICAvLyBQYXNzIG9wdGlvbnMgZXhwb3J0IHJlc3VsdCB0byB0aGUgZW5kIGNhbGxiYWNrXHJcbiAgICAgIHJldHVybiBlbmRDYWxsYmFjayhudWxsLCByZXN1bHQpO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIE5vIGlucHV0IHNwZWNpZmllZCwgcGFzcyBhbiBlcnJvciBtZXNzYWdlIHRvIHRoZSBjYWxsYmFja1xyXG4gICAgcmV0dXJuIGVuZENhbGxiYWNrKFxyXG4gICAgICBuZXcgRXhwb3J0RXJyb3IoXHJcbiAgICAgICAgYFtjaGFydF0gTm8gdmFsaWQgaW5wdXQgc3BlY2lmaWVkLiBDaGVjayBpZiBhdCBsZWFzdCBvbmUgb2YgdGhlIGZvbGxvd2luZyBwYXJhbWV0ZXJzIGlzIGNvcnJlY3RseSBzZXQ6ICdpbmZpbGUnLCAnaW5zdHInLCAnb3B0aW9ucycsIG9yICdzdmcnLmAsXHJcbiAgICAgICAgNDAwXHJcbiAgICAgIClcclxuICAgICk7XHJcbiAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgIHJldHVybiBlbmRDYWxsYmFjayhlcnJvcik7XHJcbiAgfVxyXG59XHJcblxyXG4vKipcclxuICogUmV0cmlldmVzIGFuZCByZXR1cm5zIHRoZSBjdXJyZW50IHN0YXR1cyBvZiB0aGUgY29kZSBleGVjdXRpb24gcGVybWlzc2lvbi5cclxuICpcclxuICogQGZ1bmN0aW9uIGdldEFsbG93Q29kZUV4ZWN1dGlvblxyXG4gKlxyXG4gKiBAcmV0dXJucyB7Ym9vbGVhbn0gVGhlIHZhbHVlIG9mIHRoZSBnbG9iYWwgYGFsbG93Q29kZUV4ZWN1dGlvbmAgb3B0aW9uLlxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIGdldEFsbG93Q29kZUV4ZWN1dGlvbigpIHtcclxuICByZXR1cm4gYWxsb3dDb2RlRXhlY3V0aW9uO1xyXG59XHJcblxyXG4vKipcclxuICogU2V0cyB0aGUgY29kZSBleGVjdXRpb24gcGVybWlzc2lvbiBiYXNlZCBvbiB0aGUgcHJvdmlkZWQgYm9vbGVhbiB2YWx1ZS5cclxuICpcclxuICogQGZ1bmN0aW9uIHNldEFsbG93Q29kZUV4ZWN1dGlvblxyXG4gKlxyXG4gKiBAcGFyYW0ge2Jvb2xlYW59IHZhbHVlIC0gVGhlIGJvb2xlYW4gdmFsdWUgdG8gYmUgYXNzaWduZWQgdG8gdGhlIGdsb2JhbFxyXG4gKiBgYWxsb3dDb2RlRXhlY3V0aW9uYCBvcHRpb24uXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gc2V0QWxsb3dDb2RlRXhlY3V0aW9uKHZhbHVlKSB7XHJcbiAgYWxsb3dDb2RlRXhlY3V0aW9uID0gdmFsdWU7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBFeHBvcnRzIGZyb20gYW4gU1ZHIGJhc2VkIGlucHV0IHdpdGggdGhlIHByb3ZpZGVkIG9wdGlvbnMuXHJcbiAqXHJcbiAqIEBhc3luY1xyXG4gKiBAZnVuY3Rpb24gX2V4cG9ydEZyb21TdmdcclxuICpcclxuICogQHBhcmFtIHtzdHJpbmd9IGlucHV0VG9FeHBvcnQgLSBUaGUgU1ZHIGJhc2VkIGlucHV0IHRvIGJlIGV4cG9ydGVkLlxyXG4gKiBAcGFyYW0ge09iamVjdH0gb3B0aW9ucyAtIFRoZSBjb25maWd1cmF0aW9uIG9iamVjdCBjb250YWluaW5nIGNvbXBsZXRlIHNldFxyXG4gKiBvZiBvcHRpb25zLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7UHJvbWlzZTx1bmtub3duPn0gQSBQcm9taXNlIHRoYXQgcmVzb2x2ZXMgdG8gYSByZXN1bHQgb2YgdGhlIGV4cG9ydFxyXG4gKiBwcm9jZXNzLlxyXG4gKlxyXG4gKiBAdGhyb3dzIHtFeHBvcnRFcnJvcn0gVGhyb3dzIGFuIGBFeHBvcnRFcnJvcmAgaWYgdGhlcmUgaXMgbm90IGEgY29ycmVjdCBTVkdcclxuICogaW5wdXQuXHJcbiAqL1xyXG5hc3luYyBmdW5jdGlvbiBfZXhwb3J0RnJvbVN2ZyhpbnB1dFRvRXhwb3J0LCBvcHRpb25zKSB7XHJcbiAgLy8gQ2hlY2sgaWYgaXQgaXMgU1ZHXHJcbiAgaWYgKFxyXG4gICAgdHlwZW9mIGlucHV0VG9FeHBvcnQgPT09ICdzdHJpbmcnICYmXHJcbiAgICAoaW5wdXRUb0V4cG9ydC5pbmRleE9mKCc8c3ZnJykgPj0gMCB8fCBpbnB1dFRvRXhwb3J0LmluZGV4T2YoJzw/eG1sJykgPj0gMClcclxuICApIHtcclxuICAgIGxvZyg0LCAnW2NoYXJ0XSBQYXJzaW5nIGlucHV0IGFzIFNWRy4nKTtcclxuXHJcbiAgICAvLyBTZXQgdGhlIGV4cG9ydCBpbnB1dCBhcyBTVkdcclxuICAgIG9wdGlvbnMuZXhwb3J0LnN2ZyA9IGlucHV0VG9FeHBvcnQ7XHJcblxyXG4gICAgLy8gUmVzZXQgdGhlIHJlc3Qgb2YgdGhlIGV4cG9ydCBpbnB1dCBvcHRpb25zXHJcbiAgICBvcHRpb25zLmV4cG9ydC5pbnN0ciA9IG51bGw7XHJcbiAgICBvcHRpb25zLmV4cG9ydC5vcHRpb25zID0gbnVsbDtcclxuXHJcbiAgICAvLyBDYWxsIHRoZSBmdW5jdGlvbiB3aXRoIGFuIFNWRyBzdHJpbmcgYXMgYW4gZXhwb3J0IGlucHV0XHJcbiAgICByZXR1cm4gX3ByZXBhcmVFeHBvcnQob3B0aW9ucyk7XHJcbiAgfSBlbHNlIHtcclxuICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcignW2NoYXJ0XSBOb3QgYSBjb3JyZWN0IFNWRyBpbnB1dC4nLCA0MDApO1xyXG4gIH1cclxufVxyXG5cclxuLyoqXHJcbiAqIEV4cG9ydHMgZnJvbSBhbiBvcHRpb25zIGJhc2VkIGlucHV0IHdpdGggdGhlIHByb3ZpZGVkIG9wdGlvbnMuXHJcbiAqXHJcbiAqIEBhc3luY1xyXG4gKiBAZnVuY3Rpb24gX2V4cG9ydEZyb21PcHRpb25zXHJcbiAqXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSBpbnB1dFRvRXhwb3J0IC0gVGhlIG9wdGlvbnMgYmFzZWQgaW5wdXQgdG8gYmUgZXhwb3J0ZWQuXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBvcHRpb25zIC0gVGhlIGNvbmZpZ3VyYXRpb24gb2JqZWN0IGNvbnRhaW5pbmcgY29tcGxldGUgc2V0XHJcbiAqIG9mIG9wdGlvbnMuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtQcm9taXNlPHVua25vd24+fSBBIFByb21pc2UgdGhhdCByZXNvbHZlcyB0byBhIHJlc3VsdCBvZiB0aGUgZXhwb3J0XHJcbiAqIHByb2Nlc3MuXHJcbiAqXHJcbiAqIEB0aHJvd3Mge0V4cG9ydEVycm9yfSBUaHJvd3MgYW4gYEV4cG9ydEVycm9yYCBpZiB0aGVyZSBpcyBub3QgYSBjb3JyZWN0XHJcbiAqIGNoYXJ0IG9wdGlvbnMgaW5wdXQuXHJcbiAqL1xyXG5hc3luYyBmdW5jdGlvbiBfZXhwb3J0RnJvbU9wdGlvbnMoaW5wdXRUb0V4cG9ydCwgb3B0aW9ucykge1xyXG4gIGxvZyg0LCAnW2NoYXJ0XSBQYXJzaW5nIGlucHV0IGZyb20gb3B0aW9ucy4nKTtcclxuXHJcbiAgLy8gVHJ5IHRvIGNoZWNrLCB2YWxpZGF0ZSBhbmQgcGFyc2UgdG8gc3RyaW5naWZpZWQgb3B0aW9uc1xyXG4gIGNvbnN0IHN0cmluZ2lmaWVkT3B0aW9ucyA9IGlzQWxsb3dlZENvbmZpZyhcclxuICAgIGlucHV0VG9FeHBvcnQsXHJcbiAgICB0cnVlLFxyXG4gICAgb3B0aW9ucy5jdXN0b21Mb2dpYy5hbGxvd0NvZGVFeGVjdXRpb25cclxuICApO1xyXG5cclxuICAvLyBDaGVjayBpZiBhIGNvcnJlY3Qgc3RyaW5naWZpZWQgb3B0aW9uc1xyXG4gIGlmIChcclxuICAgIHN0cmluZ2lmaWVkT3B0aW9ucyA9PT0gbnVsbCB8fFxyXG4gICAgdHlwZW9mIHN0cmluZ2lmaWVkT3B0aW9ucyAhPT0gJ3N0cmluZycgfHxcclxuICAgICFzdHJpbmdpZmllZE9wdGlvbnMuc3RhcnRzV2l0aCgneycpIHx8XHJcbiAgICAhc3RyaW5naWZpZWRPcHRpb25zLmVuZHNXaXRoKCd9JylcclxuICApIHtcclxuICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcihcclxuICAgICAgJ1tjaGFydF0gSW52YWxpZCBjb25maWd1cmF0aW9uIHByb3ZpZGVkIC0gT25seSBvcHRpb25zIGNvbmZpZ3VyYXRpb25zIGFuZCBTVkcgYXJlIGFsbG93ZWQgZm9yIHRoaXMgc2VydmVyLiBJZiB0aGlzIGlzIHlvdXIgc2VydmVyLCBKYXZhU2NyaXB0IGN1c3RvbSBjb2RlIGNhbiBiZSBlbmFibGVkIGJ5IHN0YXJ0aW5nIHRoZSBzZXJ2ZXIgd2l0aCB0aGUgYGFsbG93Q29kZUV4ZWN1dGlvbmAgb3B0aW9ucyBzZXQgdG8gdHJ1ZS4nLFxyXG4gICAgICA0MDNcclxuICAgICk7XHJcbiAgfVxyXG5cclxuICAvLyBTZXQgdGhlIGV4cG9ydCBpbnB1dCBhcyBhIHN0cmluZ2lmaWVkIGNoYXJ0IG9wdGlvbnNcclxuICBvcHRpb25zLmV4cG9ydC5pbnN0ciA9IHN0cmluZ2lmaWVkT3B0aW9ucztcclxuXHJcbiAgLy8gUmVzZXQgdGhlIHJlc3Qgb2YgdGhlIGV4cG9ydCBpbnB1dCBvcHRpb25zXHJcbiAgb3B0aW9ucy5leHBvcnQuc3ZnID0gbnVsbDtcclxuXHJcbiAgLy8gQ2FsbCB0aGUgZnVuY3Rpb24gd2l0aCBhIHN0cmluZ2lmaWVkIGNoYXJ0IG9wdGlvbnNcclxuICByZXR1cm4gX3ByZXBhcmVFeHBvcnQob3B0aW9ucyk7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBGdW5jdGlvbiBmb3IgZmluYWxpemluZyBvcHRpb25zIGFuZCBjb25maWd1cmF0aW9ucyBiZWZvcmUgZXhwb3J0LlxyXG4gKlxyXG4gKiBAYXN5bmNcclxuICogQGZ1bmN0aW9uIF9wcmVwYXJlRXhwb3J0XHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBvcHRpb25zIC0gVGhlIGNvbmZpZ3VyYXRpb24gb2JqZWN0IGNvbnRhaW5pbmcgY29tcGxldGUgc2V0XHJcbiAqIG9mIG9wdGlvbnMuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtQcm9taXNlPHVua25vd24+fSBBIFByb21pc2UgdGhhdCByZXNvbHZlcyB0byBhIHJlc3VsdCBvZiB0aGUgZXhwb3J0XHJcbiAqIHByb2Nlc3MuXHJcbiAqL1xyXG5hc3luYyBmdW5jdGlvbiBfcHJlcGFyZUV4cG9ydChvcHRpb25zKSB7XHJcbiAgY29uc3QgeyBleHBvcnQ6IGV4cG9ydE9wdGlvbnMsIGN1c3RvbUxvZ2ljOiBjdXN0b21Mb2dpY09wdGlvbnMgfSA9IG9wdGlvbnM7XHJcblxyXG4gIC8vIFByZXBhcmUgdGhlIGB0eXBlYCBvcHRpb25cclxuICBleHBvcnRPcHRpb25zLnR5cGUgPSBmaXhUeXBlKGV4cG9ydE9wdGlvbnMudHlwZSwgZXhwb3J0T3B0aW9ucy5vdXRmaWxlKTtcclxuXHJcbiAgLy8gUHJlcGFyZSB0aGUgYG91dGZpbGVgIG9wdGlvblxyXG4gIGV4cG9ydE9wdGlvbnMub3V0ZmlsZSA9IGZpeE91dGZpbGUoZXhwb3J0T3B0aW9ucy50eXBlLCBleHBvcnRPcHRpb25zLm91dGZpbGUpO1xyXG5cclxuICAvLyBQcmVwYXJlIHRoZSBgY29uc3RyYCBvcHRpb25cclxuICBleHBvcnRPcHRpb25zLmNvbnN0ciA9IGZpeENvbnN0cihleHBvcnRPcHRpb25zLmNvbnN0cik7XHJcblxyXG4gIC8vIE5vdGlmeSBhYm91dCB0aGUgY3VzdG9tIGxvZ2ljIHVzYWdlIHN0YXR1c1xyXG4gIGxvZyhcclxuICAgIDMsXHJcbiAgICBgW2NoYXJ0XSBUaGUgY3VzdG9tIGxvZ2ljIGlzICR7Y3VzdG9tTG9naWNPcHRpb25zLmFsbG93Q29kZUV4ZWN1dGlvbiA/ICdhbGxvd2VkJyA6ICdkaXNhbGxvd2VkJ30uYFxyXG4gICk7XHJcblxyXG4gIC8vIFByZXBhcmUgdGhlIGN1c3RvbSBsb2dpYyBvcHRpb25zIChgY3VzdG9tQ29kZWAsIGBjYWxsYmFja2AsIGByZXNvdXJjZXNgKVxyXG4gIF9oYW5kbGVDdXN0b21Mb2dpYyhjdXN0b21Mb2dpY09wdGlvbnMsIGN1c3RvbUxvZ2ljT3B0aW9ucy5hbGxvd0NvZGVFeGVjdXRpb24pO1xyXG5cclxuICAvLyBQcmVwYXJlIHRoZSBgZ2xvYmFsT3B0aW9uc2AgYW5kIGB0aGVtZU9wdGlvbnNgIG9wdGlvbnNcclxuICBfaGFuZGxlR2xvYmFsQW5kVGhlbWUoXHJcbiAgICBleHBvcnRPcHRpb25zLFxyXG4gICAgY3VzdG9tTG9naWNPcHRpb25zLmFsbG93RmlsZVJlc291cmNlcyxcclxuICAgIGN1c3RvbUxvZ2ljT3B0aW9ucy5hbGxvd0NvZGVFeGVjdXRpb25cclxuICApO1xyXG5cclxuICAvLyBQcmVwYXJlIHRoZSBgaGVpZ2h0YCwgYHdpZHRoYCwgYW5kIGBzY2FsZWAgb3B0aW9uc1xyXG4gIG9wdGlvbnMuZXhwb3J0ID0ge1xyXG4gICAgLi4uZXhwb3J0T3B0aW9ucyxcclxuICAgIC4uLl9maW5kQ2hhcnRTaXplKGV4cG9ydE9wdGlvbnMpXHJcbiAgfTtcclxuXHJcbiAgLy8gUG9zdCB0aGUgd29yayB0byB0aGUgcG9vbFxyXG4gIHJldHVybiBwb3N0V29yayhvcHRpb25zKTtcclxufVxyXG5cclxuLyoqXHJcbiAqIENhbGN1bGF0ZXMgdGhlIGBoZWlnaHRgLCBgd2lkdGhgIGFuZCBgc2NhbGVgIGZvciBjaGFydCBleHBvcnRzIGJhc2VkXHJcbiAqIG9uIHRoZSBwcm92aWRlZCBleHBvcnQgb3B0aW9ucy5cclxuICpcclxuICogVGhlIGZ1bmN0aW9uIHByaW9yaXRpemVzIHZhbHVlcyBpbiB0aGUgZm9sbG93aW5nIG9yZGVyOlxyXG4gKiAxLiBUaGUgYGhlaWdodGAsIGB3aWR0aGAsIGBzY2FsZWAgZnJvbSB0aGUgYGV4cG9ydE9wdGlvbnNgLlxyXG4gKiAyLiBPcHRpb25zIGZyb20gdGhlIGNoYXJ0IGNvbmZpZ3VyYXRpb24gKGZyb20gYGV4cG9ydGluZ2AgYW5kIGBjaGFydGApLlxyXG4gKiAzLiBPcHRpb25zIGZyb20gdGhlIGdsb2JhbCBvcHRpb25zIChmcm9tIGBleHBvcnRpbmdgIGFuZCBgY2hhcnRgKS5cclxuICogNC4gT3B0aW9ucyBmcm9tIHRoZSB0aGVtZSBvcHRpb25zIChmcm9tIGBleHBvcnRpbmdgIGFuZCBgY2hhcnRgIHNlY3Rpb25zKS5cclxuICogNS4gRmFsbGJhY2sgZGVmYXVsdCB2YWx1ZXMgKGBoZWlnaHQgPSA0MDBgLCBgd2lkdGggPSA2MDBgLCBgc2NhbGUgPSAxYCkuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBfZmluZENoYXJ0U2l6ZVxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gZXhwb3J0T3B0aW9ucyAtIFRoZSBjb25maWd1cmF0aW9uIG9iamVjdCBjb250YWluaW5nIGBleHBvcnRgXHJcbiAqIG9wdGlvbnMuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtPYmplY3R9IFRoZSBvYmplY3QgY29udGFpbmluZyBjYWxjdWxhdGVkIGBoZWlnaHRgLCBgd2lkdGhgXHJcbiAqIGFuZCBgc2NhbGVgIHZhbHVlcyBmb3IgdGhlIGNoYXJ0IGV4cG9ydC5cclxuICovXHJcbmZ1bmN0aW9uIF9maW5kQ2hhcnRTaXplKGV4cG9ydE9wdGlvbnMpIHtcclxuICAvLyBDaGVjayB0aGUgYG9wdGlvbnNgIGFuZCBgaW5zdHJgIGZvciBjaGFydCBhbmQgZXhwb3J0aW5nIHNlY3Rpb25zXHJcbiAgY29uc3QgeyBjaGFydDogb3B0aW9uc0NoYXJ0LCBleHBvcnRpbmc6IG9wdGlvbnNFeHBvcnRpbmcgfSA9XHJcbiAgICBleHBvcnRPcHRpb25zLm9wdGlvbnMgfHwgaXNBbGxvd2VkQ29uZmlnKGV4cG9ydE9wdGlvbnMuaW5zdHIpIHx8IGZhbHNlO1xyXG5cclxuICAvLyBDaGVjayB0aGUgYGdsb2JhbE9wdGlvbnNgIGZvciBjaGFydCBhbmQgZXhwb3J0aW5nIHNlY3Rpb25zXHJcbiAgY29uc3QgeyBjaGFydDogZ2xvYmFsT3B0aW9uc0NoYXJ0LCBleHBvcnRpbmc6IGdsb2JhbE9wdGlvbnNFeHBvcnRpbmcgfSA9XHJcbiAgICBpc0FsbG93ZWRDb25maWcoZXhwb3J0T3B0aW9ucy5nbG9iYWxPcHRpb25zKSB8fCBmYWxzZTtcclxuXHJcbiAgLy8gQ2hlY2sgdGhlIGB0aGVtZU9wdGlvbnNgIGZvciBjaGFydCBhbmQgZXhwb3J0aW5nIHNlY3Rpb25zXHJcbiAgY29uc3QgeyBjaGFydDogdGhlbWVPcHRpb25zQ2hhcnQsIGV4cG9ydGluZzogdGhlbWVPcHRpb25zRXhwb3J0aW5nIH0gPVxyXG4gICAgaXNBbGxvd2VkQ29uZmlnKGV4cG9ydE9wdGlvbnMudGhlbWVPcHRpb25zKSB8fCBmYWxzZTtcclxuXHJcbiAgLy8gRmluZCB0aGUgYHNjYWxlYCB2YWx1ZTpcclxuICAvLyAtIEl0IGNhbm5vdCBiZSBsb3dlciB0aGFuIDAuMVxyXG4gIC8vIC0gSXQgY2Fubm90IGJlIGhpZ2hlciB0aGFuIDUuMFxyXG4gIC8vIC0gSXQgbXVzdCBiZSByb3VuZGVkIHRvIDIgZGVjaW1hbCBwbGFjZXMgKGUuZy4gMC4yMzIzNCAtPiAwLjIzKVxyXG4gIGNvbnN0IHNjYWxlID0gcm91bmROdW1iZXIoXHJcbiAgICBNYXRoLm1heChcclxuICAgICAgMC4xLFxyXG4gICAgICBNYXRoLm1pbihcclxuICAgICAgICBleHBvcnRPcHRpb25zLnNjYWxlIHx8XHJcbiAgICAgICAgICBvcHRpb25zRXhwb3J0aW5nPy5zY2FsZSB8fFxyXG4gICAgICAgICAgZ2xvYmFsT3B0aW9uc0V4cG9ydGluZz8uc2NhbGUgfHxcclxuICAgICAgICAgIHRoZW1lT3B0aW9uc0V4cG9ydGluZz8uc2NhbGUgfHxcclxuICAgICAgICAgIGV4cG9ydE9wdGlvbnMuZGVmYXVsdFNjYWxlIHx8XHJcbiAgICAgICAgICAxLFxyXG4gICAgICAgIDUuMFxyXG4gICAgICApXHJcbiAgICApLFxyXG4gICAgMlxyXG4gICk7XHJcblxyXG4gIC8vIEZpbmQgdGhlIGBoZWlnaHRgIHZhbHVlXHJcbiAgY29uc3QgaGVpZ2h0ID1cclxuICAgIGV4cG9ydE9wdGlvbnMuaGVpZ2h0IHx8XHJcbiAgICBvcHRpb25zRXhwb3J0aW5nPy5zb3VyY2VIZWlnaHQgfHxcclxuICAgIG9wdGlvbnNDaGFydD8uaGVpZ2h0IHx8XHJcbiAgICBnbG9iYWxPcHRpb25zRXhwb3J0aW5nPy5zb3VyY2VIZWlnaHQgfHxcclxuICAgIGdsb2JhbE9wdGlvbnNDaGFydD8uaGVpZ2h0IHx8XHJcbiAgICB0aGVtZU9wdGlvbnNFeHBvcnRpbmc/LnNvdXJjZUhlaWdodCB8fFxyXG4gICAgdGhlbWVPcHRpb25zQ2hhcnQ/LmhlaWdodCB8fFxyXG4gICAgZXhwb3J0T3B0aW9ucy5kZWZhdWx0SGVpZ2h0IHx8XHJcbiAgICA0MDA7XHJcblxyXG4gIC8vIEZpbmQgdGhlIGB3aWR0aGAgdmFsdWVcclxuICBjb25zdCB3aWR0aCA9XHJcbiAgICBleHBvcnRPcHRpb25zLndpZHRoIHx8XHJcbiAgICBvcHRpb25zRXhwb3J0aW5nPy5zb3VyY2VXaWR0aCB8fFxyXG4gICAgb3B0aW9uc0NoYXJ0Py53aWR0aCB8fFxyXG4gICAgZ2xvYmFsT3B0aW9uc0V4cG9ydGluZz8uc291cmNlV2lkdGggfHxcclxuICAgIGdsb2JhbE9wdGlvbnNDaGFydD8ud2lkdGggfHxcclxuICAgIHRoZW1lT3B0aW9uc0V4cG9ydGluZz8uc291cmNlV2lkdGggfHxcclxuICAgIHRoZW1lT3B0aW9uc0NoYXJ0Py53aWR0aCB8fFxyXG4gICAgZXhwb3J0T3B0aW9ucy5kZWZhdWx0V2lkdGggfHxcclxuICAgIDYwMDtcclxuXHJcbiAgLy8gR2F0aGVyIGBoZWlnaHRgLCBgd2lkdGhgIGFuZCBgc2NhbGVgIGluZm9ybWF0aW9uIGluIG9uZSBvYmplY3RcclxuICBjb25zdCBzaXplID0geyBoZWlnaHQsIHdpZHRoLCBzY2FsZSB9O1xyXG5cclxuICAvLyBHZXQgcmlkIG9mIHBvdGVudGlhbCBgcHhgIGFuZCBgJWBcclxuICBmb3IgKGxldCBbcGFyYW0sIHZhbHVlXSBvZiBPYmplY3QuZW50cmllcyhzaXplKSkge1xyXG4gICAgc2l6ZVtwYXJhbV0gPVxyXG4gICAgICB0eXBlb2YgdmFsdWUgPT09ICdzdHJpbmcnID8gK3ZhbHVlLnJlcGxhY2UoL3B4fCUvZ2ksICcnKSA6IHZhbHVlO1xyXG4gIH1cclxuXHJcbiAgLy8gUmV0dXJuIHRoZSBzaXplIG9iamVjdFxyXG4gIHJldHVybiBzaXplO1xyXG59XHJcblxyXG4vKipcclxuICogSGFuZGxlcyB0aGUgZXhlY3V0aW9uIG9mIGN1c3RvbSBsb2dpYyBvcHRpb25zLCBpbmNsdWRpbmcgbG9hZGluZyBgcmVzb3VyY2VzYCxcclxuICogYGN1c3RvbUNvZGVgLCBhbmQgYGNhbGxiYWNrYC4gSWYgY29kZSBleGVjdXRpb24gaXMgYWxsb3dlZCwgaXQgcHJvY2Vzc2VzXHJcbiAqIHRoZSBjdXN0b20gbG9naWMgb3B0aW9ucyBhY2NvcmRpbmdseS4gSWYgY29kZSBleGVjdXRpb24gaXMgbm90IGFsbG93ZWQsXHJcbiAqIGl0IGRpc2FibGVzIHRoZSB1c2FnZSBvZiByZXNvdXJjZXMsIGN1c3RvbSBjb2RlIGFuZCBjYWxsYmFjay5cclxuICpcclxuICogQGZ1bmN0aW9uIF9oYW5kbGVDdXN0b21Mb2dpY1xyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gY3VzdG9tTG9naWNPcHRpb25zIC0gVGhlIGNvbmZpZ3VyYXRpb24gb2JqZWN0IGNvbnRhaW5pbmdcclxuICogYGN1c3RvbUxvZ2ljYCBvcHRpb25zLlxyXG4gKiBAcGFyYW0ge2Jvb2xlYW59IGFsbG93Q29kZUV4ZWN1dGlvbiAtIEEgZmxhZyBpbmRpY2F0aW5nIHdoZXRoZXIgY29kZVxyXG4gKiBleGVjdXRpb24gaXMgYWxsb3dlZC5cclxuICpcclxuICogQHRocm93cyB7RXhwb3J0RXJyb3J9IFRocm93cyBhbiBgRXhwb3J0RXJyb3JgIGlmIGNvZGUgZXhlY3V0aW9uXHJcbiAqIGlzIG5vdCBhbGxvd2VkIGJ1dCBjdXN0b20gbG9naWMgb3B0aW9ucyBhcmUgc3RpbGwgcHJvdmlkZWQuXHJcbiAqL1xyXG5mdW5jdGlvbiBfaGFuZGxlQ3VzdG9tTG9naWMoY3VzdG9tTG9naWNPcHRpb25zLCBhbGxvd0NvZGVFeGVjdXRpb24pIHtcclxuICAvLyBJbiBjYXNlIG9mIGFsbG93aW5nIGNvZGUgZXhlY3V0aW9uXHJcbiAgaWYgKGFsbG93Q29kZUV4ZWN1dGlvbikge1xyXG4gICAgLy8gUHJvY2VzcyB0aGUgYHJlc291cmNlc2Agb3B0aW9uXHJcbiAgICBpZiAodHlwZW9mIGN1c3RvbUxvZ2ljT3B0aW9ucy5yZXNvdXJjZXMgPT09ICdzdHJpbmcnKSB7XHJcbiAgICAgIC8vIEN1c3RvbSBzdHJpbmdpZmllZCByZXNvdXJjZXNcclxuICAgICAgY3VzdG9tTG9naWNPcHRpb25zLnJlc291cmNlcyA9IF9oYW5kbGVSZXNvdXJjZXMoXHJcbiAgICAgICAgY3VzdG9tTG9naWNPcHRpb25zLnJlc291cmNlcyxcclxuICAgICAgICBjdXN0b21Mb2dpY09wdGlvbnMuYWxsb3dGaWxlUmVzb3VyY2VzLFxyXG4gICAgICAgIHRydWVcclxuICAgICAgKTtcclxuICAgIH0gZWxzZSBpZiAoIWN1c3RvbUxvZ2ljT3B0aW9ucy5yZXNvdXJjZXMpIHtcclxuICAgICAgdHJ5IHtcclxuICAgICAgICAvLyBMb2FkIHRoZSBkZWZhdWx0IG9uZVxyXG4gICAgICAgIGN1c3RvbUxvZ2ljT3B0aW9ucy5yZXNvdXJjZXMgPSBfaGFuZGxlUmVzb3VyY2VzKFxyXG4gICAgICAgICAgcmVhZEZpbGVTeW5jKGdldEFic29sdXRlUGF0aCgncmVzb3VyY2VzLmpzb24nKSwgJ3V0ZjgnKSxcclxuICAgICAgICAgIGN1c3RvbUxvZ2ljT3B0aW9ucy5hbGxvd0ZpbGVSZXNvdXJjZXMsXHJcbiAgICAgICAgICB0cnVlXHJcbiAgICAgICAgKTtcclxuICAgICAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICAgICBsb2coMiwgJ1tjaGFydF0gVW5hYmxlIHRvIGxvYWQgdGhlIGRlZmF1bHQgYHJlc291cmNlcy5qc29uYCBmaWxlLicpO1xyXG4gICAgICB9XHJcbiAgICB9XHJcblxyXG4gICAgLy8gUHJvY2VzcyB0aGUgYGN1c3RvbUNvZGVgIG9wdGlvblxyXG4gICAgdHJ5IHtcclxuICAgICAgLy8gVHJ5IHRvIGxvYWQgY3VzdG9tIGNvZGUgYW5kIHdyYXAgYXJvdW5kIGl0IGluIGEgc2VsZiBpbnZva2luZyBmdW5jdGlvblxyXG4gICAgICBjdXN0b21Mb2dpY09wdGlvbnMuY3VzdG9tQ29kZSA9IHdyYXBBcm91bmQoXHJcbiAgICAgICAgY3VzdG9tTG9naWNPcHRpb25zLmN1c3RvbUNvZGUsXHJcbiAgICAgICAgY3VzdG9tTG9naWNPcHRpb25zLmFsbG93RmlsZVJlc291cmNlc1xyXG4gICAgICApO1xyXG5cclxuICAgICAgLy8gVmFsaWRhdGUgdGhlIG9wdGlvblxyXG4gICAgICBjdXN0b21Mb2dpY09wdGlvbnMuY3VzdG9tQ29kZSA9IHZhbGlkYXRlT3B0aW9uKFxyXG4gICAgICAgICdjdXN0b21Db2RlJyxcclxuICAgICAgICBjdXN0b21Mb2dpY09wdGlvbnMuY3VzdG9tQ29kZVxyXG4gICAgICApO1xyXG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICAgbG9nV2l0aFN0YWNrKDIsIGVycm9yLCAnW2NoYXJ0XSBUaGUgYGN1c3RvbUNvZGVgIGNhbm5vdCBiZSBsb2FkZWQuJyk7XHJcblxyXG4gICAgICAvLyBJbiBjYXNlIG9mIGFuIGVycm9yLCBzZXQgdGhlIG9wdGlvbiB3aXRoIG51bGxcclxuICAgICAgY3VzdG9tTG9naWNPcHRpb25zLmN1c3RvbUNvZGUgPSBudWxsO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIFByb2Nlc3MgdGhlIGBjYWxsYmFja2Agb3B0aW9uXHJcbiAgICB0cnkge1xyXG4gICAgICAvLyBUcnkgdG8gbG9hZCBjYWxsYmFjayBmdW5jdGlvblxyXG4gICAgICBjdXN0b21Mb2dpY09wdGlvbnMuY2FsbGJhY2sgPSB3cmFwQXJvdW5kKFxyXG4gICAgICAgIGN1c3RvbUxvZ2ljT3B0aW9ucy5jYWxsYmFjayxcclxuICAgICAgICBjdXN0b21Mb2dpY09wdGlvbnMuYWxsb3dGaWxlUmVzb3VyY2VzLFxyXG4gICAgICAgIHRydWVcclxuICAgICAgKTtcclxuXHJcbiAgICAgIC8vIFZhbGlkYXRlIHRoZSBvcHRpb25cclxuICAgICAgY3VzdG9tTG9naWNPcHRpb25zLmNhbGxiYWNrID0gdmFsaWRhdGVPcHRpb24oXHJcbiAgICAgICAgJ2NhbGxiYWNrJyxcclxuICAgICAgICBjdXN0b21Mb2dpY09wdGlvbnMuY2FsbGJhY2tcclxuICAgICAgKTtcclxuICAgIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICAgIGxvZ1dpdGhTdGFjaygyLCBlcnJvciwgJ1tjaGFydF0gVGhlIGBjYWxsYmFja2AgY2Fubm90IGJlIGxvYWRlZC4nKTtcclxuXHJcbiAgICAgIC8vIEluIGNhc2Ugb2YgYW4gZXJyb3IsIHNldCB0aGUgb3B0aW9uIHdpdGggbnVsbFxyXG4gICAgICBjdXN0b21Mb2dpY09wdGlvbnMuY2FsbGJhY2sgPSBudWxsO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIENoZWNrIGlmIHRoZXJlIGlzIHRoZSBgY3VzdG9tQ29kZWAgcHJlc2VudFxyXG4gICAgaWYgKFtudWxsLCB1bmRlZmluZWRdLmluY2x1ZGVzKGN1c3RvbUxvZ2ljT3B0aW9ucy5jdXN0b21Db2RlKSkge1xyXG4gICAgICBsb2coMywgJ1tjaGFydF0gTm8gdmFsdWUgZm9yIHRoZSBgY3VzdG9tQ29kZWAgb3B0aW9uIGZvdW5kLicpO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIENoZWNrIGlmIHRoZXJlIGlzIHRoZSBgY2FsbGJhY2tgIHByZXNlbnRcclxuICAgIGlmIChbbnVsbCwgdW5kZWZpbmVkXS5pbmNsdWRlcyhjdXN0b21Mb2dpY09wdGlvbnMuY2FsbGJhY2spKSB7XHJcbiAgICAgIGxvZygzLCAnW2NoYXJ0XSBObyB2YWx1ZSBmb3IgdGhlIGBjYWxsYmFja2Agb3B0aW9uIGZvdW5kLicpO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIENoZWNrIGlmIHRoZXJlIGlzIHRoZSBgcmVzb3VyY2VzYCBwcmVzZW50XHJcbiAgICBpZiAoW251bGwsIHVuZGVmaW5lZF0uaW5jbHVkZXMoY3VzdG9tTG9naWNPcHRpb25zLnJlc291cmNlcykpIHtcclxuICAgICAgbG9nKDMsICdbY2hhcnRdIE5vIHZhbHVlIGZvciB0aGUgYHJlc291cmNlc2Agb3B0aW9uIGZvdW5kLicpO1xyXG4gICAgfVxyXG4gIH0gZWxzZSB7XHJcbiAgICAvLyBJZiB0aGUgYGFsbG93Q29kZUV4ZWN1dGlvbmAgZmxhZyBpcyBzZXQgdG8gZmFsc2UsIHdlIHNob3VsZCByZWZ1c2VcclxuICAgIC8vIHRoZSB1c2FnZSBvZiB0aGUgYGNhbGxiYWNrYCwgYHJlc291cmNlc2AsIGFuZCBgY3VzdG9tQ29kZWAgb3B0aW9ucy5cclxuICAgIC8vIEFkZGl0aW9uYWxseSwgdGhlIHdvcmtlciB3aWxsIHJlZnVzZSB0byBydW4gYXJiaXRyYXJ5IEphdmFTY3JpcHQuXHJcbiAgICBpZiAoXHJcbiAgICAgIGN1c3RvbUxvZ2ljT3B0aW9ucy5jYWxsYmFjayB8fFxyXG4gICAgICBjdXN0b21Mb2dpY09wdGlvbnMucmVzb3VyY2VzIHx8XHJcbiAgICAgIGN1c3RvbUxvZ2ljT3B0aW9ucy5jdXN0b21Db2RlXHJcbiAgICApIHtcclxuICAgICAgLy8gUmVzZXQgYWxsIGN1c3RvbSBjb2RlIG9wdGlvbnNcclxuICAgICAgY3VzdG9tTG9naWNPcHRpb25zLmNhbGxiYWNrID0gbnVsbDtcclxuICAgICAgY3VzdG9tTG9naWNPcHRpb25zLnJlc291cmNlcyA9IG51bGw7XHJcbiAgICAgIGN1c3RvbUxvZ2ljT3B0aW9ucy5jdXN0b21Db2RlID0gbnVsbDtcclxuXHJcbiAgICAgIC8vIFNlbmQgYSBtZXNzYWdlIHNheWluZyB0aGF0IHRoZSBleHBvcnRlciBkb2VzIG5vdCBzdXBwb3J0IHRoZXNlIHNldHRpbmdzXHJcbiAgICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcihcclxuICAgICAgICBgW2NoYXJ0XSBUaGUgJ2NhbGxiYWNrJywgJ3Jlc291cmNlcycsIGFuZCAnY3VzdG9tQ29kZScgb3B0aW9ucyBoYXZlIGJlZW4gZGlzYWJsZWQgZm9yIHRoaXMgc2VydmVyLmAsXHJcbiAgICAgICAgNDAzXHJcbiAgICAgICk7XHJcbiAgICB9XHJcbiAgfVxyXG59XHJcblxyXG4vKipcclxuICogSGFuZGxlcyBhbmQgdmFsaWRhdGVzIHJlc291cmNlcyBmcm9tIHRoZSBgcmVzb3VyY2VzYCBvcHRpb24gZm9yIGV4cG9ydC5cclxuICpcclxuICogQGZ1bmN0aW9uIF9oYW5kbGVSZXNvdXJjZXNcclxuICpcclxuICogQHBhcmFtIHsoT2JqZWN0fHN0cmluZ3xudWxsKX0gW3Jlc291cmNlcz1udWxsXSAtIFRoZSByZXNvdXJjZXMgdG8gYmUgaGFuZGxlZC5cclxuICogQ2FuIGJlIGVpdGhlciBhIEpTT04gb2JqZWN0LCBzdHJpbmdpZmllZCBKU09OLCBhIHBhdGggdG8gYSBKU09OIGZpbGUsXHJcbiAqIG9yIG51bGwuIFRoZSBkZWZhdWx0IHZhbHVlIGlzIGBudWxsYC5cclxuICogQHBhcmFtIHtib29sZWFufSBhbGxvd0ZpbGVSZXNvdXJjZXMgLSBBIGZsYWcgaW5kaWNhdGluZyB3aGV0aGVyIGxvYWRpbmdcclxuICogcmVzb3VyY2VzIGZyb20gZmlsZXMgaXMgYWxsb3dlZC5cclxuICogQHBhcmFtIHtib29sZWFufSBhbGxvd0NvZGVFeGVjdXRpb24gLSBBIGZsYWcgaW5kaWNhdGluZyB3aGV0aGVyIGNvZGVcclxuICogZXhlY3V0aW9uIGlzIGFsbG93ZWQuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHsoT2JqZWN0fG51bGwpfSBUaGUgaGFuZGxlZCByZXNvdXJjZXMgb3IgbnVsbCBpZiBubyB2YWxpZCByZXNvdXJjZXNcclxuICogYXJlIGZvdW5kLlxyXG4gKi9cclxuZnVuY3Rpb24gX2hhbmRsZVJlc291cmNlcyhcclxuICByZXNvdXJjZXMgPSBudWxsLFxyXG4gIGFsbG93RmlsZVJlc291cmNlcyxcclxuICBhbGxvd0NvZGVFeGVjdXRpb25cclxuKSB7XHJcbiAgLy8gTGlzdCBvZiBhbGxvd2VkIHNlY3Rpb25zIGluIHRoZSByZXNvdXJjZXMgSlNPTlxyXG4gIGNvbnN0IGFsbG93ZWRQcm9wcyA9IFsnanMnLCAnY3NzJywgJ2ZpbGVzJ107XHJcblxyXG4gIGxldCBoYW5kbGVkUmVzb3VyY2VzID0gcmVzb3VyY2VzO1xyXG4gIGxldCBjb3JyZWN0UmVzb3VyY2VzID0gZmFsc2U7XHJcblxyXG4gIC8vIFRyeSB0byBsb2FkIHJlc291cmNlcyBmcm9tIGEgZmlsZVxyXG4gIGlmIChhbGxvd0ZpbGVSZXNvdXJjZXMgJiYgcmVzb3VyY2VzLmVuZHNXaXRoKCcuanNvbicpKSB7XHJcbiAgICB0cnkge1xyXG4gICAgICBoYW5kbGVkUmVzb3VyY2VzID0gaXNBbGxvd2VkQ29uZmlnKFxyXG4gICAgICAgIHJlYWRGaWxlU3luYyhnZXRBYnNvbHV0ZVBhdGgocmVzb3VyY2VzKSwgJ3V0ZjgnKSxcclxuICAgICAgICBmYWxzZSxcclxuICAgICAgICBhbGxvd0NvZGVFeGVjdXRpb25cclxuICAgICAgKTtcclxuICAgIH0gY2F0Y2gge1xyXG4gICAgICByZXR1cm4gbnVsbDtcclxuICAgIH1cclxuICB9IGVsc2Uge1xyXG4gICAgLy8gVHJ5IHRvIGdldCBKU09OXHJcbiAgICBoYW5kbGVkUmVzb3VyY2VzID0gaXNBbGxvd2VkQ29uZmlnKHJlc291cmNlcywgZmFsc2UsIGFsbG93Q29kZUV4ZWN1dGlvbik7XHJcblxyXG4gICAgLy8gR2V0IHJpZCBvZiB0aGUgZmlsZXMgc2VjdGlvblxyXG4gICAgaWYgKGhhbmRsZWRSZXNvdXJjZXMgJiYgIWFsbG93RmlsZVJlc291cmNlcykge1xyXG4gICAgICBkZWxldGUgaGFuZGxlZFJlc291cmNlcy5maWxlcztcclxuICAgIH1cclxuICB9XHJcblxyXG4gIC8vIEZpbHRlciBmcm9tIHVubmVjZXNzYXJ5IHByb3BlcnRpZXNcclxuICBmb3IgKGNvbnN0IHByb3BOYW1lIGluIGhhbmRsZWRSZXNvdXJjZXMpIHtcclxuICAgIGlmICghYWxsb3dlZFByb3BzLmluY2x1ZGVzKHByb3BOYW1lKSkge1xyXG4gICAgICBkZWxldGUgaGFuZGxlZFJlc291cmNlc1twcm9wTmFtZV07XHJcbiAgICB9IGVsc2UgaWYgKCFjb3JyZWN0UmVzb3VyY2VzKSB7XHJcbiAgICAgIGNvcnJlY3RSZXNvdXJjZXMgPSB0cnVlO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgLy8gQ2hlY2sgaWYgYXQgbGVhc3Qgb25lIG9mIGFsbG93ZWQgcHJvcGVydGllcyBpcyBwcmVzZW50XHJcbiAgaWYgKCFjb3JyZWN0UmVzb3VyY2VzKSB7XHJcbiAgICByZXR1cm4gbnVsbDtcclxuICB9XHJcblxyXG4gIC8vIEhhbmRsZSBmaWxlcyBzZWN0aW9uXHJcbiAgaWYgKGhhbmRsZWRSZXNvdXJjZXMuZmlsZXMpIHtcclxuICAgIGhhbmRsZWRSZXNvdXJjZXMuZmlsZXMgPSBoYW5kbGVkUmVzb3VyY2VzLmZpbGVzLm1hcCgoaXRlbSkgPT4gaXRlbS50cmltKCkpO1xyXG4gICAgaWYgKCFoYW5kbGVkUmVzb3VyY2VzLmZpbGVzIHx8IGhhbmRsZWRSZXNvdXJjZXMuZmlsZXMubGVuZ3RoIDw9IDApIHtcclxuICAgICAgZGVsZXRlIGhhbmRsZWRSZXNvdXJjZXMuZmlsZXM7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICAvLyBWYWxpZGF0ZSBvcHRpb25cclxuICBoYW5kbGVkUmVzb3VyY2VzID0gdmFsaWRhdGVPcHRpb24oJ3Jlc291cmNlcycsIGhhbmRsZWRSZXNvdXJjZXMpO1xyXG5cclxuICAvLyBSZXR1cm4gcmVzb3VyY2VzXHJcbiAgcmV0dXJuIGhhbmRsZWRSZXNvdXJjZXM7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBIYW5kbGVzIHRoZSBsb2FkaW5nIGFuZCB2YWxpZGF0aW9uIG9mIHRoZSBgZ2xvYmFsT3B0aW9uc2AgYW5kIGB0aGVtZU9wdGlvbnNgXHJcbiAqIGluIHRoZSBleHBvcnQgb3B0aW9ucy4gSWYgdGhlIG9wdGlvbiBpcyBhIHN0cmluZyBhbmQgcmVmZXJlbmNlcyBhIEpTT04gZmlsZVxyXG4gKiAod2hlbiB0aGUgYGFsbG93RmlsZVJlc291cmNlc2AgaXMgdHJ1ZSksIGl0IHJlYWRzIGFuZCBwYXJzZXMgdGhlIGZpbGUuXHJcbiAqIE90aGVyd2lzZSwgaXQgYXR0ZW1wdHMgdG8gcGFyc2UgdGhlIHN0cmluZyBvciBvYmplY3QgYXMgSlNPTi4gSWYgYW55IGVycm9yc1xyXG4gKiBvY2N1ciBkdXJpbmcgdGhpcyBwcm9jZXNzLCB0aGUgb3B0aW9uIGlzIHNldCB0byBudWxsLiBJZiB0aGVyZSBpcyBhbiBlcnJvclxyXG4gKiBsb2FkaW5nIG9yIHBhcnNpbmcgdGhlIGBnbG9iYWxPcHRpb25zYCBvciBgdGhlbWVPcHRpb25zYCwgdGhlIGVycm9yIGlzIGxvZ2dlZFxyXG4gKiBhbmQgdGhlIG9wdGlvbiBpcyBzZXQgdG8gbnVsbC5cclxuICpcclxuICogQGZ1bmN0aW9uIF9oYW5kbGVHbG9iYWxBbmRUaGVtZVxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gZXhwb3J0T3B0aW9ucyAtIFRoZSBjb25maWd1cmF0aW9uIG9iamVjdCBjb250YWluaW5nIGBleHBvcnRgXHJcbiAqIG9wdGlvbnMuXHJcbiAqIEBwYXJhbSB7Ym9vbGVhbn0gYWxsb3dGaWxlUmVzb3VyY2VzIC0gQSBmbGFnIGluZGljYXRpbmcgd2hldGhlciBsb2FkaW5nXHJcbiAqIHJlc291cmNlcyBmcm9tIGZpbGVzIGlzIGFsbG93ZWQuXHJcbiAqIEBwYXJhbSB7Ym9vbGVhbn0gYWxsb3dDb2RlRXhlY3V0aW9uIC0gQSBmbGFnIGluZGljYXRpbmcgd2hldGhlciBjb2RlXHJcbiAqIGV4ZWN1dGlvbiBpcyBhbGxvd2VkLlxyXG4gKi9cclxuZnVuY3Rpb24gX2hhbmRsZUdsb2JhbEFuZFRoZW1lKFxyXG4gIGV4cG9ydE9wdGlvbnMsXHJcbiAgYWxsb3dGaWxlUmVzb3VyY2VzLFxyXG4gIGFsbG93Q29kZUV4ZWN1dGlvblxyXG4pIHtcclxuICAvLyBDaGVjayB0aGUgYGdsb2JhbE9wdGlvbnNgIGFuZCBgdGhlbWVPcHRpb25zYCBvcHRpb25zXHJcbiAgWydnbG9iYWxPcHRpb25zJywgJ3RoZW1lT3B0aW9ucyddLmZvckVhY2goKG9wdGlvbnNOYW1lKSA9PiB7XHJcbiAgICB0cnkge1xyXG4gICAgICAvLyBDaGVjayBpZiB0aGUgb3B0aW9uIGV4aXN0c1xyXG4gICAgICBpZiAoZXhwb3J0T3B0aW9uc1tvcHRpb25zTmFtZV0pIHtcclxuICAgICAgICAvLyBDaGVjayBpZiBpdCBpcyBhIHN0cmluZyBhbmQgYSBmaWxlIG5hbWUgd2l0aCB0aGUgYC5qc29uYCBleHRlbnNpb25cclxuICAgICAgICBpZiAoXHJcbiAgICAgICAgICBhbGxvd0ZpbGVSZXNvdXJjZXMgJiZcclxuICAgICAgICAgIHR5cGVvZiBleHBvcnRPcHRpb25zW29wdGlvbnNOYW1lXSA9PT0gJ3N0cmluZycgJiZcclxuICAgICAgICAgIGV4cG9ydE9wdGlvbnNbb3B0aW9uc05hbWVdLmVuZHNXaXRoKCcuanNvbicpXHJcbiAgICAgICAgKSB7XHJcbiAgICAgICAgICAvLyBDaGVjayBpZiB0aGUgZmlsZSBjb250ZW50IGNhbiBiZSBhIGNvbmZpZywgYW5kIHNhdmUgaXQgYXMgYSBzdHJpbmdcclxuICAgICAgICAgIGV4cG9ydE9wdGlvbnNbb3B0aW9uc05hbWVdID0gaXNBbGxvd2VkQ29uZmlnKFxyXG4gICAgICAgICAgICByZWFkRmlsZVN5bmMoZ2V0QWJzb2x1dGVQYXRoKGV4cG9ydE9wdGlvbnNbb3B0aW9uc05hbWVdKSwgJ3V0ZjgnKSxcclxuICAgICAgICAgICAgdHJ1ZSxcclxuICAgICAgICAgICAgYWxsb3dDb2RlRXhlY3V0aW9uXHJcbiAgICAgICAgICApO1xyXG4gICAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgICAvLyBDaGVjayBpZiB0aGUgdmFsdWUgY2FuIGJlIGEgY29uZmlnLCBhbmQgc2F2ZSBpdCBhcyBhIHN0cmluZ1xyXG4gICAgICAgICAgZXhwb3J0T3B0aW9uc1tvcHRpb25zTmFtZV0gPSBpc0FsbG93ZWRDb25maWcoXHJcbiAgICAgICAgICAgIGV4cG9ydE9wdGlvbnNbb3B0aW9uc05hbWVdLFxyXG4gICAgICAgICAgICB0cnVlLFxyXG4gICAgICAgICAgICBhbGxvd0NvZGVFeGVjdXRpb25cclxuICAgICAgICAgICk7XHJcbiAgICAgICAgfVxyXG5cclxuICAgICAgICAvLyBWYWxpZGF0ZSB0aGUgb3B0aW9uXHJcbiAgICAgICAgZXhwb3J0T3B0aW9uc1tvcHRpb25zTmFtZV0gPSB2YWxpZGF0ZU9wdGlvbihcclxuICAgICAgICAgIG9wdGlvbnNOYW1lLFxyXG4gICAgICAgICAgZXhwb3J0T3B0aW9uc1tvcHRpb25zTmFtZV1cclxuICAgICAgICApO1xyXG4gICAgICB9XHJcbiAgICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgICBsb2dXaXRoU3RhY2soXHJcbiAgICAgICAgMixcclxuICAgICAgICBlcnJvcixcclxuICAgICAgICBgW2NoYXJ0XSBUaGUgXFxgJHtvcHRpb25zTmFtZX1cXGAgY2Fubm90IGJlIGxvYWRlZC5gXHJcbiAgICAgICk7XHJcblxyXG4gICAgICAvLyBJbiBjYXNlIG9mIGFuIGVycm9yLCBzZXQgdGhlIG9wdGlvbiB3aXRoIG51bGxcclxuICAgICAgZXhwb3J0T3B0aW9uc1tvcHRpb25zTmFtZV0gPSBudWxsO1xyXG4gICAgfVxyXG4gIH0pO1xyXG5cclxuICAvLyBDaGVjayBpZiB0aGVyZSBpcyB0aGUgYGdsb2JhbE9wdGlvbnNgIHByZXNlbnRcclxuICBpZiAoW251bGwsIHVuZGVmaW5lZF0uaW5jbHVkZXMoZXhwb3J0T3B0aW9ucy5nbG9iYWxPcHRpb25zKSkge1xyXG4gICAgbG9nKDMsICdbY2hhcnRdIE5vIHZhbHVlIGZvciB0aGUgYGdsb2JhbE9wdGlvbnNgIG9wdGlvbiBmb3VuZC4nKTtcclxuICB9XHJcblxyXG4gIC8vIENoZWNrIGlmIHRoZXJlIGlzIHRoZSBgdGhlbWVPcHRpb25zYCBwcmVzZW50XHJcbiAgaWYgKFtudWxsLCB1bmRlZmluZWRdLmluY2x1ZGVzKGV4cG9ydE9wdGlvbnMudGhlbWVPcHRpb25zKSkge1xyXG4gICAgbG9nKDMsICdbY2hhcnRdIE5vIHZhbHVlIGZvciB0aGUgYHRoZW1lT3B0aW9uc2Agb3B0aW9uIGZvdW5kLicpO1xyXG4gIH1cclxufVxyXG5cclxuZXhwb3J0IGRlZmF1bHQge1xyXG4gIHNpbmdsZUV4cG9ydCxcclxuICBiYXRjaEV4cG9ydCxcclxuICBzdGFydEV4cG9ydCxcclxuICBnZXRBbGxvd0NvZGVFeGVjdXRpb24sXHJcbiAgc2V0QWxsb3dDb2RlRXhlY3V0aW9uXHJcbn07XHJcbiIsIi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXHJcblxyXG5IaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXJcclxuXHJcbkNvcHlyaWdodCAoYykgMjAxNi0yMDI1LCBIaWdoc29mdFxyXG5cclxuTGljZW5jZWQgdW5kZXIgdGhlIE1JVCBsaWNlbmNlLlxyXG5cclxuQWRkaXRpb25hbGx5IGEgdmFsaWQgSGlnaGNoYXJ0cyBsaWNlbnNlIGlzIHJlcXVpcmVkIGZvciB1c2UuXHJcblxyXG5TZWUgTElDRU5TRSBmaWxlIGluIHJvb3QgZm9yIGRldGFpbHMuXHJcblxyXG4qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xyXG5cclxuLyoqXHJcbiAqIEBvdmVydmlldyBUaGlzIG1vZHVsZSBwcm92aWRlcyB1dGlsaXR5IGZ1bmN0aW9ucyBmb3IgbWFuYWdpbmcgaW50ZXJ2YWxzXHJcbiAqIGFuZCB0aW1lb3V0cyBpbiBhIGNlbnRyYWxpemVkIG1hbm5lci4gSXQgbWFpbnRhaW5zIGEgcmVnaXN0cnkgb2YgYWxsIGFjdGl2ZVxyXG4gKiB0aW1lcnMgYW5kIGFsbG93cyBmb3IgdGhlaXIgZWZmaWNpZW50IGNsZWFudXAgd2hlbiBuZWVkZWQuIFRoaXMgY2FuIGJlIHVzZWZ1bFxyXG4gKiBpbiBhcHBsaWNhdGlvbnMgd2hlcmUgcHJvcGVyIHJlc291cmNlIG1hbmFnZW1lbnQgYW5kIGNsZWFuIHNodXRkb3duIG9mIHRpbWVyc1xyXG4gKiBhcmUgY3JpdGljYWwgdG8gYXZvaWQgbWVtb3J5IGxlYWtzIG9yIHVuaW50ZW5kZWQgYmVoYXZpb3IuXHJcbiAqL1xyXG5cclxuaW1wb3J0IHsgbG9nIH0gZnJvbSAnLi9sb2dnZXIuanMnO1xyXG5cclxuLy8gQXJyYXkgdGhhdCBjb250YWlucyBpZHMgb2YgYWxsIG9uZ29pbmcgaW50ZXJ2YWxzIGFuZCB0aW1lb3V0c1xyXG5jb25zdCB0aW1lcklkcyA9IFtdO1xyXG5cclxuLyoqXHJcbiAqIEFkZHMgaWQgb2YgdGhlIGBzZXRJbnRlcnZhbGAgb3IgYHNldFRpbWVvdXRgIGFuZCB0byB0aGUgYHRpbWVySWRzYCBhcnJheS5cclxuICpcclxuICogQGZ1bmN0aW9uIGFkZFRpbWVyXHJcbiAqXHJcbiAqIEBwYXJhbSB7Tm9kZUpTLlRpbWVvdXR9IGlkIC0gSWQgb2YgYW4gaW50ZXJ2YWwgb3IgYSB0aW1lb3V0LlxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIGFkZFRpbWVyKGlkKSB7XHJcbiAgdGltZXJJZHMucHVzaChpZCk7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBDbGVhcnMgYWxsIG9mIG9uZ29pbmcgaW50ZXJ2YWxzIGFuZCB0aW1lb3V0cyBieSBpZHMgZ2F0aGVyZWRcclxuICogaW4gdGhlIGB0aW1lcklkc2AgYXJyYXkuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBjbGVhckFsbFRpbWVyc1xyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIGNsZWFyQWxsVGltZXJzKCkge1xyXG4gIGxvZyg0LCBgW3RpbWVyXSBDbGVhcmluZyBhbGwgcmVnaXN0ZXJlZCBpbnRlcnZhbHMgYW5kIHRpbWVvdXRzLmApO1xyXG4gIGZvciAoY29uc3QgaWQgb2YgdGltZXJJZHMpIHtcclxuICAgIGNsZWFySW50ZXJ2YWwoaWQpO1xyXG4gICAgY2xlYXJUaW1lb3V0KGlkKTtcclxuICB9XHJcbn1cclxuXHJcbmV4cG9ydCBkZWZhdWx0IHtcclxuICBhZGRUaW1lcixcclxuICBjbGVhckFsbFRpbWVyc1xyXG59O1xyXG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxyXG5cclxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXHJcblxyXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNSwgSGlnaHNvZnRcclxuXHJcbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cclxuXHJcbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxyXG5cclxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxyXG5cclxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cclxuXHJcbi8qKlxyXG4gKiBAb3ZlcnZpZXcgUHJvdmlkZXMgbWlkZGxld2FyZSBmdW5jdGlvbnMgZm9yIGxvZ2dpbmcgZXJyb3JzIHdpdGggc3RhY2sgdHJhY2VzXHJcbiAqIGFuZCBoYW5kbGluZyBlcnJvciByZXNwb25zZXMgaW4gYW4gRXhwcmVzcyBhcHBsaWNhdGlvbi5cclxuICovXHJcblxyXG5pbXBvcnQgeyBnZXRPcHRpb25zIH0gZnJvbSAnLi4vLi4vY29uZmlnLmpzJztcclxuaW1wb3J0IHsgbG9nV2l0aFN0YWNrIH0gZnJvbSAnLi4vLi4vbG9nZ2VyLmpzJztcclxuXHJcbi8qKlxyXG4gKiBNaWRkbGV3YXJlIGZvciBsb2dnaW5nIGVycm9ycyB3aXRoIHN0YWNrIHRyYWNlIGFuZCBoYW5kbGluZyBlcnJvciByZXNwb25zZS5cclxuICpcclxuICogQGZ1bmN0aW9uIGxvZ0Vycm9yTWlkZGxld2FyZVxyXG4gKlxyXG4gKiBAcGFyYW0ge0Vycm9yfSBlcnJvciAtIFRoZSBlcnJvciBvYmplY3QuXHJcbiAqIEBwYXJhbSB7RXhwcmVzcy5SZXF1ZXN0fSByZXF1ZXN0IC0gVGhlIEV4cHJlc3MgcmVxdWVzdCBvYmplY3QuXHJcbiAqIEBwYXJhbSB7RXhwcmVzcy5SZXNwb25zZX0gcmVzcG9uc2UgLSBUaGUgRXhwcmVzcyByZXNwb25zZSBvYmplY3QuXHJcbiAqIEBwYXJhbSB7RnVuY3Rpb259IG5leHQgLSBUaGUgbmV4dCBtaWRkbGV3YXJlIGZ1bmN0aW9uLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7dW5kZWZpbmVkfSBUaGUgY2FsbCB0byB0aGUgbmV4dCBtaWRkbGV3YXJlIGZ1bmN0aW9uIHdpdGhcclxuICogdGhlIHBhc3NlZCBlcnJvci5cclxuICovXHJcbmZ1bmN0aW9uIGxvZ0Vycm9yTWlkZGxld2FyZShlcnJvciwgcmVxdWVzdCwgcmVzcG9uc2UsIG5leHQpIHtcclxuICAvLyBEaXNwbGF5IHRoZSBlcnJvciB3aXRoIHN0YWNrIGluIGEgY29ycmVjdCBmb3JtYXRcclxuICBsb2dXaXRoU3RhY2soMSwgZXJyb3IpO1xyXG5cclxuICAvLyBEZWxldGUgdGhlIHN0YWNrIGZvciB0aGUgZW52aXJvbm1lbnQgb3RoZXIgdGhhbiB0aGUgZGV2ZWxvcG1lbnRcclxuICBpZiAoZ2V0T3B0aW9ucygpLm90aGVyLm5vZGVFbnYgIT09ICdkZXZlbG9wbWVudCcpIHtcclxuICAgIGRlbGV0ZSBlcnJvci5zdGFjaztcclxuICB9XHJcblxyXG4gIC8vIENhbGwgdGhlIGByZXR1cm5FcnJvck1pZGRsZXdhcmVgIG1pZGRsZXdhcmVcclxuICByZXR1cm4gbmV4dChlcnJvcik7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBNaWRkbGV3YXJlIGZvciByZXR1cm5pbmcgZXJyb3IgcmVzcG9uc2UuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiByZXR1cm5FcnJvck1pZGRsZXdhcmVcclxuICpcclxuICogQHBhcmFtIHtFcnJvcn0gZXJyb3IgLSBUaGUgZXJyb3Igb2JqZWN0LlxyXG4gKiBAcGFyYW0ge0V4cHJlc3MuUmVxdWVzdH0gcmVxdWVzdCAtIFRoZSBFeHByZXNzIHJlcXVlc3Qgb2JqZWN0LlxyXG4gKiBAcGFyYW0ge0V4cHJlc3MuUmVzcG9uc2V9IHJlc3BvbnNlIC0gVGhlIEV4cHJlc3MgcmVzcG9uc2Ugb2JqZWN0LlxyXG4gKiBAcGFyYW0ge0Z1bmN0aW9ufSBuZXh0IC0gVGhlIG5leHQgbWlkZGxld2FyZSBmdW5jdGlvbi5cclxuICovXHJcbmZ1bmN0aW9uIHJldHVybkVycm9yTWlkZGxld2FyZShlcnJvciwgcmVxdWVzdCwgcmVzcG9uc2UsIG5leHQpIHtcclxuICAvLyBHYXRoZXIgYWxsIHJlcXVpZWQgaW5mb3JtYXRpb24gZm9yIHRoZSByZXNwb25zZVxyXG4gIGNvbnN0IHsgbWVzc2FnZSwgc3RhY2sgfSA9IGVycm9yO1xyXG5cclxuICAvLyBVc2UgdGhlIGVycm9yJ3Mgc3RhdHVzIGNvZGUgb3IgdGhlIGRlZmF1bHQgNDAwXHJcbiAgY29uc3Qgc3RhdHVzQ29kZSA9IGVycm9yLnN0YXR1c0NvZGUgfHwgNDAwO1xyXG5cclxuICAvLyBTZXQgYW5kIHJldHVybiByZXNwb25zZVxyXG4gIHJlc3BvbnNlLnN0YXR1cyhzdGF0dXNDb2RlKS5qc29uKHsgc3RhdHVzQ29kZSwgbWVzc2FnZSwgc3RhY2sgfSk7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBBZGRzIHRoZSBlcnJvciBtaWRkbGV3YXJlcyB0byB0aGUgcGFzc2VkIGV4cHJlc3MgYXBwIGluc3RhbmNlLlxyXG4gKlxyXG4gKiBAcGFyYW0ge0V4cHJlc3N9IGFwcCAtIFRoZSBFeHByZXNzIGFwcCBpbnN0YW5jZS5cclxuICovXHJcbmV4cG9ydCBkZWZhdWx0IGZ1bmN0aW9uIGVycm9yTWlkZGxld2FyZShhcHApIHtcclxuICAvLyBBZGQgbG9nIGVycm9yIG1pZGRsZXdhcmVcclxuICBhcHAudXNlKGxvZ0Vycm9yTWlkZGxld2FyZSk7XHJcblxyXG4gIC8vIEFkZCBzZXQgc3RhdHVzIGFuZCByZXR1cm4gZXJyb3IgbWlkZGxld2FyZVxyXG4gIGFwcC51c2UocmV0dXJuRXJyb3JNaWRkbGV3YXJlKTtcclxufVxyXG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxyXG5cclxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXHJcblxyXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNSwgSGlnaHNvZnRcclxuXHJcbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cclxuXHJcbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxyXG5cclxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxyXG5cclxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cclxuXHJcbi8qKlxyXG4gKiBAb3ZlcnZpZXcgUHJvdmlkZXMgbWlkZGxld2FyZSBmdW5jdGlvbnMgZm9yIGNvbmZpZ3VyaW5nIGFuZCBlbmFibGluZyByYXRlXHJcbiAqIGxpbWl0aW5nIGluIGFuIEV4cHJlc3MgYXBwbGljYXRpb24uXHJcbiAqL1xyXG5cclxuaW1wb3J0IHJhdGVMaW1pdCBmcm9tICdleHByZXNzLXJhdGUtbGltaXQnO1xyXG5cclxuaW1wb3J0IHsgbG9nIH0gZnJvbSAnLi4vLi4vbG9nZ2VyLmpzJztcclxuXHJcbmltcG9ydCBFeHBvcnRFcnJvciBmcm9tICcuLi8uLi9lcnJvcnMvRXhwb3J0RXJyb3IuanMnO1xyXG5cclxuLyoqXHJcbiAqIE1pZGRsZXdhcmUgZm9yIGVuYWJsaW5nIHJhdGUgbGltaXRpbmcgb24gdGhlIHNwZWNpZmllZCBFeHByZXNzIGFwcC5cclxuICpcclxuICogQHBhcmFtIHtFeHByZXNzfSBhcHAgLSBUaGUgRXhwcmVzcyBhcHAgaW5zdGFuY2UuXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSByYXRlTGltaXRpbmdPcHRpb25zIC0gVGhlIGNvbmZpZ3VyYXRpb24gb2JqZWN0IGNvbnRhaW5pbmdcclxuICogYHJhdGVMaW1pdGluZ2Agb3B0aW9ucy5cclxuICpcclxuICogQHRocm93cyB7RXhwb3J0RXJyb3J9IFRocm93cyBhbiBgRXhwb3J0RXJyb3JgIGlmIGNvdWxkIG5vdCBjb25maWd1cmUgYW5kIHNldFxyXG4gKiB0aGUgcmF0ZSBsaW1pdGluZyBvcHRpb25zLlxyXG4gKi9cclxuZXhwb3J0IGRlZmF1bHQgZnVuY3Rpb24gcmF0ZUxpbWl0aW5nTWlkZGxld2FyZShhcHAsIHJhdGVMaW1pdGluZ09wdGlvbnMpIHtcclxuICB0cnkge1xyXG4gICAgLy8gQ2hlY2sgaWYgdGhlIHJhdGUgbGltaXRpbmcgaXMgZW5hYmxlZCBhbmQgdGhlIGFwcCBleGlzdHNcclxuICAgIGlmIChhcHAgJiYgcmF0ZUxpbWl0aW5nT3B0aW9ucy5lbmFibGUpIHtcclxuICAgICAgY29uc3QgbWVzc2FnZSA9XHJcbiAgICAgICAgJ1RvbyBtYW55IHJlcXVlc3RzLCB5b3UgaGF2ZSBiZWVuIHJhdGUgbGltaXRlZC4gUGxlYXNlIHRyeSBhZ2FpbiBsYXRlci4nO1xyXG5cclxuICAgICAgLy8gT3B0aW9ucyBmb3IgdGhlIHJhdGUgbGltaXRlclxyXG4gICAgICBjb25zdCByYXRlT3B0aW9ucyA9IHtcclxuICAgICAgICB3aW5kb3c6IHJhdGVMaW1pdGluZ09wdGlvbnMud2luZG93IHx8IDEsXHJcbiAgICAgICAgbWF4UmVxdWVzdHM6IHJhdGVMaW1pdGluZ09wdGlvbnMubWF4UmVxdWVzdHMgfHwgMzAsXHJcbiAgICAgICAgZGVsYXk6IHJhdGVMaW1pdGluZ09wdGlvbnMuZGVsYXkgfHwgMCxcclxuICAgICAgICB0cnVzdFByb3h5OiByYXRlTGltaXRpbmdPcHRpb25zLnRydXN0UHJveHkgfHwgZmFsc2UsXHJcbiAgICAgICAgc2tpcEtleTogcmF0ZUxpbWl0aW5nT3B0aW9ucy5za2lwS2V5IHx8IG51bGwsXHJcbiAgICAgICAgc2tpcFRva2VuOiByYXRlTGltaXRpbmdPcHRpb25zLnNraXBUb2tlbiB8fCBudWxsXHJcbiAgICAgIH07XHJcblxyXG4gICAgICAvLyBTZXQgaWYgYmVoaW5kIGEgcHJveHlcclxuICAgICAgaWYgKHJhdGVPcHRpb25zLnRydXN0UHJveHkpIHtcclxuICAgICAgICBhcHAuZW5hYmxlKCd0cnVzdCBwcm94eScpO1xyXG4gICAgICB9XHJcblxyXG4gICAgICAvLyBDcmVhdGUgYSBsaW1pdGVyXHJcbiAgICAgIGNvbnN0IGxpbWl0ZXIgPSByYXRlTGltaXQoe1xyXG4gICAgICAgIC8vIFRpbWUgZnJhbWUgZm9yIHdoaWNoIHJlcXVlc3RzIGFyZSBjaGVja2VkIGFuZCByZW1lbWJlcmVkXHJcbiAgICAgICAgd2luZG93TXM6IHJhdGVPcHRpb25zLndpbmRvdyAqIDYwICogMTAwMCxcclxuICAgICAgICAvLyBMaW1pdCBlYWNoIElQIHRvIDEwMCByZXF1ZXN0cyBwZXIgYHdpbmRvd01zYFxyXG4gICAgICAgIGxpbWl0OiByYXRlT3B0aW9ucy5tYXhSZXF1ZXN0cyxcclxuICAgICAgICAvLyBEaXNhYmxlIGRlbGF5aW5nLCBmdWxsIHNwZWVkIHVudGlsIHRoZSBtYXggbGltaXQgaXMgcmVhY2hlZFxyXG4gICAgICAgIGRlbGF5TXM6IHJhdGVPcHRpb25zLmRlbGF5LFxyXG4gICAgICAgIGhhbmRsZXI6IChyZXF1ZXN0LCByZXNwb25zZSkgPT4ge1xyXG4gICAgICAgICAgcmVzcG9uc2UuZm9ybWF0KHtcclxuICAgICAgICAgICAganNvbjogKCkgPT4ge1xyXG4gICAgICAgICAgICAgIHJlc3BvbnNlLnN0YXR1cyg0MjkpLnNlbmQoeyBtZXNzYWdlIH0pO1xyXG4gICAgICAgICAgICB9LFxyXG4gICAgICAgICAgICBkZWZhdWx0OiAoKSA9PiB7XHJcbiAgICAgICAgICAgICAgcmVzcG9uc2Uuc3RhdHVzKDQyOSkuc2VuZChtZXNzYWdlKTtcclxuICAgICAgICAgICAgfVxyXG4gICAgICAgICAgfSk7XHJcbiAgICAgICAgfSxcclxuICAgICAgICBza2lwOiAocmVxdWVzdCkgPT4ge1xyXG4gICAgICAgICAgLy8gQWxsb3cgYnlwYXNzaW5nIHRoZSBsaW1pdGVyIGlmIGEgdmFsaWQga2V5L3Rva2VuIGhhcyBiZWVuIHNlbnRcclxuICAgICAgICAgIGlmIChcclxuICAgICAgICAgICAgcmF0ZU9wdGlvbnMuc2tpcEtleSAhPT0gbnVsbCAmJlxyXG4gICAgICAgICAgICByYXRlT3B0aW9ucy5za2lwVG9rZW4gIT09IG51bGwgJiZcclxuICAgICAgICAgICAgcmVxdWVzdC5xdWVyeS5rZXkgPT09IHJhdGVPcHRpb25zLnNraXBLZXkgJiZcclxuICAgICAgICAgICAgcmVxdWVzdC5xdWVyeS5hY2Nlc3NfdG9rZW4gPT09IHJhdGVPcHRpb25zLnNraXBUb2tlblxyXG4gICAgICAgICAgKSB7XHJcbiAgICAgICAgICAgIGxvZyg0LCAnW3JhdGUgbGltaXRpbmddIFNraXBwaW5nIHJhdGUgbGltaXRlci4nKTtcclxuICAgICAgICAgICAgcmV0dXJuIHRydWU7XHJcbiAgICAgICAgICB9XHJcbiAgICAgICAgICByZXR1cm4gZmFsc2U7XHJcbiAgICAgICAgfVxyXG4gICAgICB9KTtcclxuXHJcbiAgICAgIC8vIFVzZSBhIGxpbWl0ZXIgYXMgYSBtaWRkbGV3YXJlXHJcbiAgICAgIGFwcC51c2UobGltaXRlcik7XHJcblxyXG4gICAgICBsb2coXHJcbiAgICAgICAgMyxcclxuICAgICAgICBgW3JhdGUgbGltaXRpbmddIEVuYWJsZWQgcmF0ZSBsaW1pdGluZyB3aXRoICR7cmF0ZU9wdGlvbnMubWF4UmVxdWVzdHN9IHJlcXVlc3RzIHBlciAke3JhdGVPcHRpb25zLndpbmRvd30gbWludXRlIGZvciBlYWNoIElQLCB0cnVzdGluZyBwcm94eTogJHtyYXRlT3B0aW9ucy50cnVzdFByb3h5fS5gXHJcbiAgICAgICk7XHJcbiAgICB9XHJcbiAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcihcclxuICAgICAgJ1tyYXRlIGxpbWl0aW5nXSBDb3VsZCBub3QgY29uZmlndXJlIGFuZCBzZXQgdGhlIHJhdGUgbGltaXRpbmcgb3B0aW9ucy4nLFxyXG4gICAgICA1MDBcclxuICAgICkuc2V0RXJyb3IoZXJyb3IpO1xyXG4gIH1cclxufVxyXG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxyXG5cclxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXHJcblxyXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNSwgSGlnaHNvZnRcclxuXHJcbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cclxuXHJcbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxyXG5cclxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxyXG5cclxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cclxuXHJcbi8qKlxyXG4gKiBAb3ZlcnZpZXcgUHJvdmlkZXMgbWlkZGxld2FyZSBmdW5jdGlvbnMgZm9yIHZhbGlkYXRpbmcgaW5jb21pbmcgSFRUUCByZXF1ZXN0c1xyXG4gKiBpbiBhbiBFeHByZXNzIGFwcGxpY2F0aW9uLiBUaGlzIG1vZHVsZSBlbnN1cmVzIHRoYXQgcmVxdWVzdHMgY29udGFpblxyXG4gKiBhcHByb3ByaWF0ZSBjb250ZW50IHR5cGVzIGFuZCB2YWxpZCByZXF1ZXN0IGJvZGllcywgaW5jbHVkaW5nIHByb3BlciBKU09OXHJcbiAqIHN0cnVjdHVyZXMgYW5kIGNoYXJ0IGRhdGEgZm9yIGV4cG9ydHMuIEl0IGNoZWNrcyBmb3IgcG90ZW50aWFsIGlzc3VlcyBzdWNoXHJcbiAqIGFzIG1pc3Npbmcgb3IgbWFsZm9ybWVkIGRhdGEsIHByaXZhdGUgcmFuZ2UgVVJMcyBpbiBTVkcgcGF5bG9hZHMsIGFuZCBhbGxvd3NcclxuICogZm9yIGZsZXhpYmxlIG9wdGlvbnMgdmFsaWRhdGlvbi4gVGhlIG1pZGRsZXdhcmUgbG9ncyBkZXRhaWxlZCBpbmZvcm1hdGlvblxyXG4gKiBhbmQgaGFuZGxlcyBlcnJvcnMgcmVsYXRlZCB0byBpbmNvcnJlY3QgcGF5bG9hZHMsIGNoYXJ0IGRhdGEsIGFuZCBwcml2YXRlIFVSTFxyXG4gKiB1c2FnZS5cclxuICovXHJcblxyXG5pbXBvcnQgeyB2NCBhcyB1dWlkIH0gZnJvbSAndXVpZCc7XHJcblxyXG5pbXBvcnQgeyBnZXRBbGxvd0NvZGVFeGVjdXRpb24gfSBmcm9tICcuLi8uLi9jaGFydC5qcyc7XHJcbmltcG9ydCB7IGlzQWxsb3dlZENvbmZpZyB9IGZyb20gJy4uLy4uL2NvbmZpZy5qcyc7XHJcbmltcG9ydCB7IGxvZyB9IGZyb20gJy4uLy4uL2xvZ2dlci5qcyc7XHJcbmltcG9ydCB7IGlzT2JqZWN0RW1wdHksIGlzUHJpdmF0ZVJhbmdlVXJsRm91bmQgfSBmcm9tICcuLi8uLi91dGlscy5qcyc7XHJcblxyXG5pbXBvcnQgRXhwb3J0RXJyb3IgZnJvbSAnLi4vLi4vZXJyb3JzL0V4cG9ydEVycm9yLmpzJztcclxuXHJcbi8qKlxyXG4gKiBNaWRkbGV3YXJlIGZvciB2YWxpZGF0aW5nIHRoZSBjb250ZW50LXR5cGUgaGVhZGVyLlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gY29udGVudFR5cGVNaWRkbGV3YXJlXHJcbiAqXHJcbiAqIEBwYXJhbSB7RXhwcmVzcy5SZXF1ZXN0fSByZXF1ZXN0IC0gVGhlIEV4cHJlc3MgcmVxdWVzdCBvYmplY3QuXHJcbiAqIEBwYXJhbSB7RXhwcmVzcy5SZXNwb25zZX0gcmVzcG9uc2UgLSBUaGUgRXhwcmVzcyByZXNwb25zZSBvYmplY3QuXHJcbiAqIEBwYXJhbSB7RnVuY3Rpb259IG5leHQgLSBUaGUgbmV4dCBtaWRkbGV3YXJlIGZ1bmN0aW9uLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7dW5kZWZpbmVkfSBUaGUgY2FsbCB0byB0aGUgbmV4dCBtaWRkbGV3YXJlIGZ1bmN0aW9uLlxyXG4gKlxyXG4gKiBAdGhyb3dzIHtFeHBvcnRFcnJvcn0gVGhyb3dzIGFuIGBFeHBvcnRFcnJvcmAgaWYgdGhlIGNvbnRlbnQtdHlwZVxyXG4gKiBpcyBub3QgY29ycmVjdC5cclxuICovXHJcbmZ1bmN0aW9uIGNvbnRlbnRUeXBlTWlkZGxld2FyZShyZXF1ZXN0LCByZXNwb25zZSwgbmV4dCkge1xyXG4gIHRyeSB7XHJcbiAgICAvLyBHZXQgdGhlIGNvbnRlbnQgdHlwZSBoZWFkZXJcclxuICAgIGNvbnN0IGNvbnRlbnRUeXBlID0gcmVxdWVzdC5oZWFkZXJzWydjb250ZW50LXR5cGUnXSB8fCAnJztcclxuXHJcbiAgICAvLyBBbGxvdyBvbmx5IEpTT04sIFVSTC1lbmNvZGVkIGFuZCBmb3JtIGRhdGEgd2l0aG91dCBmaWxlcyB0eXBlcyBvZiBkYXRhXHJcbiAgICBpZiAoXHJcbiAgICAgICFjb250ZW50VHlwZS5pbmNsdWRlcygnYXBwbGljYXRpb24vanNvbicpICYmXHJcbiAgICAgICFjb250ZW50VHlwZS5pbmNsdWRlcygnYXBwbGljYXRpb24veC13d3ctZm9ybS11cmxlbmNvZGVkJykgJiZcclxuICAgICAgIWNvbnRlbnRUeXBlLmluY2x1ZGVzKCdtdWx0aXBhcnQvZm9ybS1kYXRhJylcclxuICAgICkge1xyXG4gICAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoXHJcbiAgICAgICAgJ1t2YWxpZGF0aW9uXSBDb250ZW50LVR5cGUgbXVzdCBiZSBhcHBsaWNhdGlvbi9qc29uLCBhcHBsaWNhdGlvbi94LXd3dy1mb3JtLXVybGVuY29kZWQsIG9yIG11bHRpcGFydC9mb3JtLWRhdGEuJyxcclxuICAgICAgICA0MTVcclxuICAgICAgKTtcclxuICAgIH1cclxuXHJcbiAgICAvLyBDYWxsIHRoZSBgcmVxdWVzdEJvZHlNaWRkbGV3YXJlYCBtaWRkbGV3YXJlXHJcbiAgICByZXR1cm4gbmV4dCgpO1xyXG4gIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICByZXR1cm4gbmV4dChlcnJvcik7XHJcbiAgfVxyXG59XHJcblxyXG4vKipcclxuICogTWlkZGxld2FyZSBmb3IgdmFsaWRhdGluZyB0aGUgcmVxdWVzdCdzIGJvZHkuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiByZXF1ZXN0Qm9keU1pZGRsZXdhcmVcclxuICpcclxuICogQHBhcmFtIHtFeHByZXNzLlJlcXVlc3R9IHJlcXVlc3QgLSBUaGUgRXhwcmVzcyByZXF1ZXN0IG9iamVjdC5cclxuICogQHBhcmFtIHtFeHByZXNzLlJlc3BvbnNlfSByZXNwb25zZSAtIFRoZSBFeHByZXNzIHJlc3BvbnNlIG9iamVjdC5cclxuICogQHBhcmFtIHtGdW5jdGlvbn0gbmV4dCAtIFRoZSBuZXh0IG1pZGRsZXdhcmUgZnVuY3Rpb24uXHJcbiAqXHJcbiAqIEByZXR1cm5zIHt1bmRlZmluZWR9IFRoZSBjYWxsIHRvIHRoZSBuZXh0IG1pZGRsZXdhcmUgZnVuY3Rpb24uXHJcbiAqXHJcbiAqIEB0aHJvd3Mge0V4cG9ydEVycm9yfSBUaHJvd3MgYW4gYEV4cG9ydEVycm9yYCBpZiB0aGUgYm9keSBpcyBub3QgY29ycmVjdC5cclxuICogQHRocm93cyB7RXhwb3J0RXJyb3J9IFRocm93cyBhbiBgRXhwb3J0RXJyb3JgIGlmIHRoZSBjaGFydCBkYXRhIGZyb20gdGhlIGJvZHlcclxuICogaXMgbm90IGNvcnJlY3QuXHJcbiAqIEB0aHJvd3Mge0V4cG9ydEVycm9yfSBUaHJvd3MgYW4gYEV4cG9ydEVycm9yYCBpbiBjYXNlIG9mIHRoZSBwcml2YXRlIHJhbmdlXHJcbiAqIHVybCBlcnJvci5cclxuICovXHJcbmZ1bmN0aW9uIHJlcXVlc3RCb2R5TWlkZGxld2FyZShyZXF1ZXN0LCByZXNwb25zZSwgbmV4dCkge1xyXG4gIHRyeSB7XHJcbiAgICAvLyBHZXQgdGhlIHJlcXVlc3QgYm9keVxyXG4gICAgY29uc3QgYm9keSA9IHJlcXVlc3QuYm9keTtcclxuXHJcbiAgICAvLyBDcmVhdGUgYSB1bmlxdWUgSUQgZm9yIGEgcmVxdWVzdFxyXG4gICAgY29uc3QgcmVxdWVzdElkID0gdXVpZCgpO1xyXG5cclxuICAgIC8vIFRocm93IGFuIGVycm9yIGlmIHRoZXJlIGlzIG5vIGNvcnJlY3QgYm9keVxyXG4gICAgaWYgKCFib2R5IHx8IGlzT2JqZWN0RW1wdHkoYm9keSkpIHtcclxuICAgICAgbG9nKFxyXG4gICAgICAgIDIsXHJcbiAgICAgICAgYFt2YWxpZGF0aW9uXSBSZXF1ZXN0IFske3JlcXVlc3RJZH1dIC0gVGhlIHJlcXVlc3QgZnJvbSAke1xyXG4gICAgICAgICAgcmVxdWVzdC5oZWFkZXJzWyd4LWZvcndhcmRlZC1mb3InXSB8fCByZXF1ZXN0LmNvbm5lY3Rpb24ucmVtb3RlQWRkcmVzc1xyXG4gICAgICAgIH0gd2FzIGluY29ycmVjdC4gUmVjZWl2ZWQgcGF5bG9hZCBpcyBlbXB0eS5gXHJcbiAgICAgICk7XHJcblxyXG4gICAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoXHJcbiAgICAgICAgYFt2YWxpZGF0aW9uXSBSZXF1ZXN0IFske3JlcXVlc3RJZH1dIC0gVGhlIHJlcXVlc3QgYm9keSBpcyByZXF1aXJlZC4gUGxlYXNlIGVuc3VyZSB0aGF0IHlvdXIgQ29udGVudC1UeXBlIGhlYWRlciBpcyBjb3JyZWN0LiBBY2NlcHRlZCB0eXBlcyBhcmUgJ2FwcGxpY2F0aW9uL2pzb24nIGFuZCAnbXVsdGlwYXJ0L2Zvcm0tZGF0YScuYCxcclxuICAgICAgICA0MDBcclxuICAgICAgKTtcclxuICAgIH1cclxuXHJcbiAgICAvLyBHZXQgdGhlIGBhbGxvd0NvZGVFeGVjdXRpb25gIG9wdGlvbiBmb3IgdGhlIHNlcnZlclxyXG4gICAgY29uc3QgYWxsb3dDb2RlRXhlY3V0aW9uID0gZ2V0QWxsb3dDb2RlRXhlY3V0aW9uKCk7XHJcblxyXG4gICAgLy8gRmluZCBhIGNvcnJlY3QgY2hhcnQgb3B0aW9uc1xyXG4gICAgY29uc3QgaW5zdHIgPSBpc0FsbG93ZWRDb25maWcoXHJcbiAgICAgIC8vIFVzZSBvbmUgb2YgdGhlIGJlbG93XHJcbiAgICAgIGJvZHkuaW5zdHIgfHwgYm9keS5vcHRpb25zIHx8IGJvZHkuaW5maWxlIHx8IGJvZHkuZGF0YSxcclxuICAgICAgLy8gU3RyaW5naWZ5IG9wdGlvbnNcclxuICAgICAgdHJ1ZSxcclxuICAgICAgLy8gQWxsb3cgb3IgZGlzYWxsb3cgZnVuY3Rpb25zXHJcbiAgICAgIGFsbG93Q29kZUV4ZWN1dGlvblxyXG4gICAgKTtcclxuXHJcbiAgICAvLyBUaHJvdyBhbiBlcnJvciBpZiB0aGVyZSBpcyBubyBjb3JyZWN0IGNoYXJ0IGRhdGFcclxuICAgIGlmIChpbnN0ciA9PT0gbnVsbCAmJiAhYm9keS5zdmcpIHtcclxuICAgICAgbG9nKFxyXG4gICAgICAgIDIsXHJcbiAgICAgICAgYFt2YWxpZGF0aW9uXSBSZXF1ZXN0IFske3JlcXVlc3RJZH1dIC0gVGhlIHJlcXVlc3QgZnJvbSAke1xyXG4gICAgICAgICAgcmVxdWVzdC5oZWFkZXJzWyd4LWZvcndhcmRlZC1mb3InXSB8fCByZXF1ZXN0LmNvbm5lY3Rpb24ucmVtb3RlQWRkcmVzc1xyXG4gICAgICAgIH0gd2FzIGluY29ycmVjdC4gUmVjZWl2ZWQgcGF5bG9hZCBpcyBtaXNzaW5nIGNvcnJlY3QgY2hhcnQgZGF0YSBmb3IgZXhwb3J0OiAke0pTT04uc3RyaW5naWZ5KGJvZHkpfS5gXHJcbiAgICAgICk7XHJcblxyXG4gICAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoXHJcbiAgICAgICAgYFJlcXVlc3QgWyR7cmVxdWVzdElkfV0gLSBbdmFsaWRhdGlvbl0gTm8gY29ycmVjdCBjaGFydCBkYXRhIGZvdW5kLiBFbnN1cmUgdGhhdCB5b3UgYXJlIHVzaW5nIGVpdGhlciBhcHBsaWNhdGlvbi9qc29uIG9yIG11bHRpcGFydC9mb3JtLWRhdGEgaGVhZGVycy4gSWYgc2VuZGluZyBKU09OLCBtYWtlIHN1cmUgdGhlIGNoYXJ0IGRhdGEgaXMgaW4gdGhlICdpbmZpbGUnLCAnb3B0aW9ucycsIG9yICdkYXRhJyBhdHRyaWJ1dGUuIElmIHNlbmRpbmcgU1ZHLCBlbnN1cmUgaXQgaXMgaW4gdGhlICdzdmcnIGF0dHJpYnV0ZS5gLFxyXG4gICAgICAgIDQwMFxyXG4gICAgICApO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIFRocm93IGFuIGVycm9yIGlmIHRlc3Qgb2YgeGxpbms6aHJlZiBlbGVtZW50cyBmcm9tIHBheWxvYWQncyBTVkcgZmFpbHNcclxuICAgIGlmIChib2R5LnN2ZyAmJiBpc1ByaXZhdGVSYW5nZVVybEZvdW5kKGJvZHkuc3ZnKSkge1xyXG4gICAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoXHJcbiAgICAgICAgYFJlcXVlc3QgWyR7cmVxdWVzdElkfV0gLSBbdmFsaWRhdGlvbl0gU1ZHIHBvdGVudGlhbGx5IGNvbnRhaW4gYXQgbGVhc3Qgb25lIGZvcmJpZGRlbiBVUkwgaW4gJ3hsaW5rOmhyZWYnIGVsZW1lbnQuIFBsZWFzZSByZXZpZXcgdGhlIFNWRyBjb250ZW50IGFuZCBlbnN1cmUgdGhhdCBhbGwgcmVmZXJlbmNlZCBVUkxzIGNvbXBseSB3aXRoIHNlY3VyaXR5IHBvbGljaWVzLmAsXHJcbiAgICAgICAgNDAwXHJcbiAgICAgICk7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gR2V0IGFuZCBwcmUtdmFsaWRhdGUgdGhlIG9wdGlvbnMgYW5kIHN0b3JlIHRoZW0gaW4gdGhlIHJlcXVlc3RcclxuICAgIHJlcXVlc3QudmFsaWRhdGVkT3B0aW9ucyA9IHtcclxuICAgICAgLy8gU2V0IHRoZSBjcmVhdGVkIElEIGFzIGEgYHJlcXVlc3RJZGAgcHJvcGVydHkgaW4gdGhlIG9wdGlvbnNcclxuICAgICAgcmVxdWVzdElkLFxyXG4gICAgICBleHBvcnQ6IHtcclxuICAgICAgICBpbnN0cixcclxuICAgICAgICBzdmc6IGJvZHkuc3ZnLFxyXG4gICAgICAgIG91dGZpbGU6XHJcbiAgICAgICAgICBib2R5Lm91dGZpbGUgfHxcclxuICAgICAgICAgIGAke3JlcXVlc3QucGFyYW1zLmZpbGVuYW1lIHx8ICdjaGFydCd9LiR7Ym9keS50eXBlIHx8ICdwbmcnfWAsXHJcbiAgICAgICAgdHlwZTogYm9keS50eXBlLFxyXG4gICAgICAgIGNvbnN0cjogYm9keS5jb25zdHIsXHJcbiAgICAgICAgYjY0OiBib2R5LmI2NCxcclxuICAgICAgICBub0Rvd25sb2FkOiBib2R5Lm5vRG93bmxvYWQsXHJcbiAgICAgICAgaGVpZ2h0OiBib2R5LmhlaWdodCxcclxuICAgICAgICB3aWR0aDogYm9keS53aWR0aCxcclxuICAgICAgICBzY2FsZTogYm9keS5zY2FsZSxcclxuICAgICAgICBnbG9iYWxPcHRpb25zOiBpc0FsbG93ZWRDb25maWcoXHJcbiAgICAgICAgICBib2R5Lmdsb2JhbE9wdGlvbnMsXHJcbiAgICAgICAgICB0cnVlLFxyXG4gICAgICAgICAgYWxsb3dDb2RlRXhlY3V0aW9uXHJcbiAgICAgICAgKSxcclxuICAgICAgICB0aGVtZU9wdGlvbnM6IGlzQWxsb3dlZENvbmZpZyhcclxuICAgICAgICAgIGJvZHkudGhlbWVPcHRpb25zLFxyXG4gICAgICAgICAgdHJ1ZSxcclxuICAgICAgICAgIGFsbG93Q29kZUV4ZWN1dGlvblxyXG4gICAgICAgIClcclxuICAgICAgfSxcclxuICAgICAgY3VzdG9tTG9naWM6IHtcclxuICAgICAgICBhbGxvd0NvZGVFeGVjdXRpb24sXHJcbiAgICAgICAgYWxsb3dGaWxlUmVzb3VyY2VzOiBmYWxzZSxcclxuICAgICAgICBjdXN0b21Db2RlOiBib2R5LmN1c3RvbUNvZGUsXHJcbiAgICAgICAgY2FsbGJhY2s6IGJvZHkuY2FsbGJhY2ssXHJcbiAgICAgICAgcmVzb3VyY2VzOiBpc0FsbG93ZWRDb25maWcoYm9keS5yZXNvdXJjZXMsIHRydWUsIGFsbG93Q29kZUV4ZWN1dGlvbilcclxuICAgICAgfVxyXG4gICAgfTtcclxuXHJcbiAgICAvLyBDYWxsIHRoZSBuZXh0IG1pZGRsZXdhcmVcclxuICAgIHJldHVybiBuZXh0KCk7XHJcbiAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgIHJldHVybiBuZXh0KGVycm9yKTtcclxuICB9XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBBZGRzIHRoZSB2YWxpZGF0aW9uIG1pZGRsZXdhcmVzIHRvIHRoZSBwYXNzZWQgZXhwcmVzcyBhcHAgaW5zdGFuY2UuXHJcbiAqXHJcbiAqIEBwYXJhbSB7RXhwcmVzc30gYXBwIC0gVGhlIEV4cHJlc3MgYXBwIGluc3RhbmNlLlxyXG4gKi9cclxuZXhwb3J0IGRlZmF1bHQgZnVuY3Rpb24gdmFsaWRhdGlvbk1pZGRsZXdhcmUoYXBwKSB7XHJcbiAgLy8gQWRkIGNvbnRlbnQgdHlwZSB2YWxpZGF0aW9uIG1pZGRsZXdhcmVcclxuICBhcHAucG9zdChbJy8nLCAnLzpmaWxlbmFtZSddLCBjb250ZW50VHlwZU1pZGRsZXdhcmUpO1xyXG5cclxuICAvLyBBZGQgcmVxdWVzdCBib2R5IHJlcXVlc3QgdmFsaWRhdGlvbiBtaWRkbGV3YXJlXHJcbiAgYXBwLnBvc3QoWycvJywgJy86ZmlsZW5hbWUnXSwgcmVxdWVzdEJvZHlNaWRkbGV3YXJlKTtcclxufVxyXG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxyXG5cclxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXHJcblxyXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNSwgSGlnaHNvZnRcclxuXHJcbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cclxuXHJcbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxyXG5cclxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxyXG5cclxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cclxuXHJcbi8qKlxyXG4gKiBAb3ZlcnZpZXcgRGVmaW5lcyB0aGUgZXhwb3J0IHJvdXRlcyBhbmQgbG9naWMgZm9yIGhhbmRsaW5nIGNoYXJ0IGV4cG9ydFxyXG4gKiByZXF1ZXN0cyBpbiBhbiBFeHByZXNzIHNlcnZlci4gVGhpcyBtb2R1bGUgcHJvY2Vzc2VzIGluY29taW5nIHJlcXVlc3RzXHJcbiAqIHRvIGV4cG9ydCBjaGFydHMgaW4gdmFyaW91cyBmb3JtYXRzIChlLmcuIEpQRUcsIFBORywgUERGLCBTVkcpLiBJdCBpbnRlZ3JhdGVzXHJcbiAqIHdpdGggSGlnaGNoYXJ0cycgY29yZSBmdW5jdGlvbmFsaXRpZXMgYW5kIHN1cHBvcnRzIGJvdGggaW1tZWRpYXRlIGRvd25sb2FkXHJcbiAqIHJlc3BvbnNlcyBhbmQgQmFzZTY0LWVuY29kZWQgY29udGVudCByZXR1cm5zLiBUaGUgY29kZSBhbHNvIGZlYXR1cmVzXHJcbiAqIGJlbmNobWFya2luZyBmb3IgcGVyZm9ybWFuY2UgbW9uaXRvcmluZy5cclxuICovXHJcblxyXG5pbXBvcnQgeyBzdGFydEV4cG9ydCB9IGZyb20gJy4uLy4uL2NoYXJ0LmpzJztcclxuaW1wb3J0IHsgbG9nIH0gZnJvbSAnLi4vLi4vbG9nZ2VyLmpzJztcclxuaW1wb3J0IHsgZ2V0QmFzZTY0LCBtZWFzdXJlVGltZSB9IGZyb20gJy4uLy4uL3V0aWxzLmpzJztcclxuXHJcbmltcG9ydCBFeHBvcnRFcnJvciBmcm9tICcuLi8uLi9lcnJvcnMvRXhwb3J0RXJyb3IuanMnO1xyXG5cclxuLy8gUmV2ZXJzZWQgTUlNRSB0eXBlc1xyXG5jb25zdCByZXZlcnNlZE1pbWUgPSB7XHJcbiAgcG5nOiAnaW1hZ2UvcG5nJyxcclxuICBqcGVnOiAnaW1hZ2UvanBlZycsXHJcbiAgZ2lmOiAnaW1hZ2UvZ2lmJyxcclxuICBwZGY6ICdhcHBsaWNhdGlvbi9wZGYnLFxyXG4gIHN2ZzogJ2ltYWdlL3N2Zyt4bWwnXHJcbn07XHJcblxyXG4vKipcclxuICogSGFuZGxlcyB0aGUgZXhwb3J0IHJlcXVlc3RzIGZyb20gdGhlIGNsaWVudC5cclxuICpcclxuICogQGFzeW5jXHJcbiAqIEBmdW5jdGlvbiByZXF1ZXN0RXhwb3J0XHJcbiAqXHJcbiAqIEBwYXJhbSB7RXhwcmVzcy5SZXF1ZXN0fSByZXF1ZXN0IC0gVGhlIEV4cHJlc3MgcmVxdWVzdCBvYmplY3QuXHJcbiAqIEBwYXJhbSB7RXhwcmVzcy5SZXNwb25zZX0gcmVzcG9uc2UgLSBUaGUgRXhwcmVzcyByZXNwb25zZSBvYmplY3QuXHJcbiAqIEBwYXJhbSB7RnVuY3Rpb259IG5leHQgLSBUaGUgbmV4dCBtaWRkbGV3YXJlIGZ1bmN0aW9uLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7UHJvbWlzZTx2b2lkPn0gQSBQcm9taXNlIHRoYXQgcmVzb2x2ZXMgb25jZSB0aGUgZXhwb3J0IHByb2Nlc3NcclxuICogaXMgY29tcGxldGUuXHJcbiAqL1xyXG5hc3luYyBmdW5jdGlvbiByZXF1ZXN0RXhwb3J0KHJlcXVlc3QsIHJlc3BvbnNlLCBuZXh0KSB7XHJcbiAgdHJ5IHtcclxuICAgIC8vIFN0YXJ0IGNvdW50aW5nIHRpbWUgZm9yIGEgcmVxdWVzdFxyXG4gICAgY29uc3QgcmVxdWVzdENvdW50ZXIgPSBtZWFzdXJlVGltZSgpO1xyXG5cclxuICAgIC8vIEluIGNhc2UgdGhlIGNvbm5lY3Rpb24gaXMgY2xvc2VkLCBmb3JjZSB0byBhYm9ydCBmdXJ0aGVyIGFjdGlvbnNcclxuICAgIGxldCBjb25uZWN0aW9uQWJvcnRlZCA9IGZhbHNlO1xyXG4gICAgcmVxdWVzdC5zb2NrZXQub24oJ2Nsb3NlJywgKGhhZEVycm9ycykgPT4ge1xyXG4gICAgICBpZiAoaGFkRXJyb3JzKSB7XHJcbiAgICAgICAgY29ubmVjdGlvbkFib3J0ZWQgPSB0cnVlO1xyXG4gICAgICB9XHJcbiAgICB9KTtcclxuXHJcbiAgICAvLyBHZXQgdGhlIG9wdGlvbnMgcHJldmlvdXNseSB2YWxpZGF0ZWQgaW4gdGhlIHZhbGlkYXRpb24gbWlkZGxld2FyZVxyXG4gICAgY29uc3QgcmVxdWVzdE9wdGlvbnMgPSByZXF1ZXN0LnZhbGlkYXRlZE9wdGlvbnM7XHJcblxyXG4gICAgLy8gR2V0IHRoZSByZXF1ZXN0IGlkXHJcbiAgICBjb25zdCByZXF1ZXN0SWQgPSByZXF1ZXN0T3B0aW9ucy5yZXF1ZXN0SWQ7XHJcblxyXG4gICAgLy8gSW5mbyBhYm91dCBhbiBpbmNvbWluZyByZXF1ZXN0IHdpdGggY29ycmVjdCBkYXRhXHJcbiAgICBsb2coNCwgYFtleHBvcnRdIFJlcXVlc3QgWyR7cmVxdWVzdElkfV0gLSBHb3QgYW4gaW5jb21pbmcgSFRUUCByZXF1ZXN0LmApO1xyXG5cclxuICAgIC8vIFN0YXJ0IHRoZSBleHBvcnQgcHJvY2Vzc1xyXG4gICAgYXdhaXQgc3RhcnRFeHBvcnQocmVxdWVzdE9wdGlvbnMsIChlcnJvciwgZGF0YSkgPT4ge1xyXG4gICAgICAvLyBSZW1vdmUgdGhlIGNsb3NlIGV2ZW50IGZyb20gdGhlIHNvY2tldFxyXG4gICAgICByZXF1ZXN0LnNvY2tldC5yZW1vdmVBbGxMaXN0ZW5lcnMoJ2Nsb3NlJyk7XHJcblxyXG4gICAgICAvLyBJZiB0aGUgY29ubmVjdGlvbiB3YXMgY2xvc2VkLCBkbyBub3RoaW5nXHJcbiAgICAgIGlmIChjb25uZWN0aW9uQWJvcnRlZCkge1xyXG4gICAgICAgIGxvZyhcclxuICAgICAgICAgIDMsXHJcbiAgICAgICAgICBgW2V4cG9ydF0gUmVxdWVzdCBbJHtyZXF1ZXN0SWR9XSAtIFRoZSBjbGllbnQgY2xvc2VkIHRoZSBjb25uZWN0aW9uIGJlZm9yZSB0aGUgY2hhcnQgZmluaXNoZWQgcHJvY2Vzc2luZy5gXHJcbiAgICAgICAgKTtcclxuICAgICAgICByZXR1cm47XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIC8vIElmIGVycm9yLCBsb2cgaXQgYW5kIHNlbmQgaXQgdG8gdGhlIGVycm9yIG1pZGRsZXdhcmVcclxuICAgICAgaWYgKGVycm9yKSB7XHJcbiAgICAgICAgdGhyb3cgZXJyb3I7XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIC8vIElmIGRhdGEgaXMgbWlzc2luZywgbG9nIHRoZSBtZXNzYWdlIGFuZCBzZW5kIGl0IHRvIHRoZSBlcnJvciBtaWRkbGV3YXJlXHJcbiAgICAgIGlmICghZGF0YSB8fCAhZGF0YS5yZXN1bHQpIHtcclxuICAgICAgICBsb2coXHJcbiAgICAgICAgICAyLFxyXG4gICAgICAgICAgYFtleHBvcnRdIFJlcXVlc3QgWyR7cmVxdWVzdElkfV0gLSBSZXF1ZXN0IGZyb20gJHtcclxuICAgICAgICAgICAgcmVxdWVzdC5oZWFkZXJzWyd4LWZvcndhcmRlZC1mb3InXSB8fFxyXG4gICAgICAgICAgICByZXF1ZXN0LmNvbm5lY3Rpb24ucmVtb3RlQWRkcmVzc1xyXG4gICAgICAgICAgfSB3YXMgaW5jb3JyZWN0LiBSZWNlaXZlZCByZXN1bHQgaXMgJHtkYXRhLnJlc3VsdH0uYFxyXG4gICAgICAgICk7XHJcblxyXG4gICAgICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcihcclxuICAgICAgICAgIGBbZXhwb3J0XSBSZXF1ZXN0IFske3JlcXVlc3RJZH1dIC0gVW5leHBlY3RlZCByZXR1cm4gb2YgdGhlIGV4cG9ydCByZXN1bHQgZnJvbSB0aGUgY2hhcnQgZ2VuZXJhdGlvbi4gUGxlYXNlIGNoZWNrIHlvdXIgcmVxdWVzdCBkYXRhLmAsXHJcbiAgICAgICAgICA0MDBcclxuICAgICAgICApO1xyXG4gICAgICB9XHJcblxyXG4gICAgICAvLyBSZXR1cm4gdGhlIHJlc3VsdCBpbiBhbiBhcHByb3ByaWF0ZSBmb3JtYXRcclxuICAgICAgaWYgKGRhdGEucmVzdWx0KSB7XHJcbiAgICAgICAgbG9nKFxyXG4gICAgICAgICAgMyxcclxuICAgICAgICAgIGBbZXhwb3J0XSBSZXF1ZXN0IFske3JlcXVlc3RJZH1dIC0gVGhlIHdob2xlIGV4cG9ydGluZyBwcm9jZXNzIHRvb2sgJHtyZXF1ZXN0Q291bnRlcigpfW1zLmBcclxuICAgICAgICApO1xyXG5cclxuICAgICAgICAvLyBHZXQgdGhlIGB0eXBlYCwgYGI2NGAsIGBub0Rvd25sb2FkYCwgYW5kIGBvdXRmaWxlYCBmcm9tIG9wdGlvbnNcclxuICAgICAgICBjb25zdCB7IHR5cGUsIGI2NCwgbm9Eb3dubG9hZCwgb3V0ZmlsZSB9ID0gZGF0YS5vcHRpb25zLmV4cG9ydDtcclxuXHJcbiAgICAgICAgLy8gSWYgb25seSBCYXNlNjQgaXMgcmVxdWlyZWQsIHJldHVybiBpdFxyXG4gICAgICAgIGlmIChiNjQpIHtcclxuICAgICAgICAgIHJldHVybiByZXNwb25zZS5zZW5kKGdldEJhc2U2NChkYXRhLnJlc3VsdCwgdHlwZSkpO1xyXG4gICAgICAgIH1cclxuXHJcbiAgICAgICAgLy8gU2V0IGNvcnJlY3QgY29udGVudCB0eXBlXHJcbiAgICAgICAgcmVzcG9uc2UuaGVhZGVyKCdDb250ZW50LVR5cGUnLCByZXZlcnNlZE1pbWVbdHlwZV0gfHwgJ2ltYWdlL3BuZycpO1xyXG5cclxuICAgICAgICAvLyBEZWNpZGUgd2hldGhlciB0byBkb3dubG9hZCBvciBub3QgY2hhcnQgZmlsZVxyXG4gICAgICAgIGlmICghbm9Eb3dubG9hZCkge1xyXG4gICAgICAgICAgcmVzcG9uc2UuYXR0YWNobWVudChvdXRmaWxlKTtcclxuICAgICAgICB9XHJcblxyXG4gICAgICAgIC8vIElmIFNWRywgcmV0dXJuIHBsYWluIGNvbnRlbnQsIG90aGVyd2lzZSBhIGI2NCBzdHJpbmcgZnJvbSBhIGJ1ZmZlclxyXG4gICAgICAgIHJldHVybiB0eXBlID09PSAnc3ZnJ1xyXG4gICAgICAgICAgPyByZXNwb25zZS5zZW5kKGRhdGEucmVzdWx0KVxyXG4gICAgICAgICAgOiByZXNwb25zZS5zZW5kKEJ1ZmZlci5mcm9tKGRhdGEucmVzdWx0LCAnYmFzZTY0JykpO1xyXG4gICAgICB9XHJcbiAgICB9KTtcclxuICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgcmV0dXJuIG5leHQoZXJyb3IpO1xyXG4gIH1cclxufVxyXG5cclxuLyoqXHJcbiAqIEFkZHMgdGhlIGBleHBvcnRgIHJvdXRlcy5cclxuICpcclxuICogQGZ1bmN0aW9uIGV4cG9ydFJvdXRlc1xyXG4gKlxyXG4gKiBAcGFyYW0ge0V4cHJlc3N9IGFwcCAtIFRoZSBFeHByZXNzIGFwcCBpbnN0YW5jZS5cclxuICovXHJcbmV4cG9ydCBkZWZhdWx0IGZ1bmN0aW9uIGV4cG9ydFJvdXRlcyhhcHApIHtcclxuICAvKipcclxuICAgKiBBZGRzIHRoZSBQT1NUICcvJyAtIEEgcm91dGUgZm9yIGhhbmRsaW5nIFBPU1QgcmVxdWVzdHMgYXQgdGhlIHJvb3RcclxuICAgKiBlbmRwb2ludC5cclxuICAgKi9cclxuICBhcHAucG9zdCgnLycsIHJlcXVlc3RFeHBvcnQpO1xyXG5cclxuICAvKipcclxuICAgKiBBZGRzIHRoZSBQT1NUICcvOmZpbGVuYW1lJyAtIEEgcm91dGUgZm9yIGhhbmRsaW5nIFBPU1QgcmVxdWVzdHMgd2l0aFxyXG4gICAqIGEgc3BlY2lmaWVkIGZpbGVuYW1lIHBhcmFtZXRlci5cclxuICAgKi9cclxuICBhcHAucG9zdCgnLzpmaWxlbmFtZScsIHJlcXVlc3RFeHBvcnQpO1xyXG59XHJcbiIsIi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXHJcblxyXG5IaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXJcclxuXHJcbkNvcHlyaWdodCAoYykgMjAxNi0yMDI1LCBIaWdoc29mdFxyXG5cclxuTGljZW5jZWQgdW5kZXIgdGhlIE1JVCBsaWNlbmNlLlxyXG5cclxuQWRkaXRpb25hbGx5IGEgdmFsaWQgSGlnaGNoYXJ0cyBsaWNlbnNlIGlzIHJlcXVpcmVkIGZvciB1c2UuXHJcblxyXG5TZWUgTElDRU5TRSBmaWxlIGluIHJvb3QgZm9yIGRldGFpbHMuXHJcblxyXG4qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xyXG5cclxuLyoqXHJcbiAqIEBvdmVydmlldyBEZWZpbmVzIGFuIEV4cHJlc3Mgcm91dGUgZm9yIHNlcnZlciBoZWFsdGggbW9uaXRvcmluZywgaW5jbHVkaW5nXHJcbiAqIHVwdGltZSwgc3VjY2VzcyByYXRlcywgYW5kIG90aGVyIHNlcnZlciBzdGF0aXN0aWNzLlxyXG4gKi9cclxuXHJcbmltcG9ydCB7IHJlYWRGaWxlU3luYyB9IGZyb20gJ2ZzJztcclxuaW1wb3J0IHsgam9pbiB9IGZyb20gJ3BhdGgnO1xyXG5cclxuaW1wb3J0IHsgZ2V0SGlnaGNoYXJ0c1ZlcnNpb24gfSBmcm9tICcuLi8uLi9jYWNoZS5qcyc7XHJcbmltcG9ydCB7IGxvZyB9IGZyb20gJy4uLy4uL2xvZ2dlci5qcyc7XHJcbmltcG9ydCB7IGdldFBvb2xJbmZvSlNPTiwgZ2V0UG9vbFN0YXRzIH0gZnJvbSAnLi4vLi4vcG9vbC5qcyc7XHJcbmltcG9ydCB7IGFkZFRpbWVyIH0gZnJvbSAnLi4vLi4vdGltZXIuanMnO1xyXG5pbXBvcnQgeyBfX2Rpcm5hbWUsIGdldE5ld0RhdGVUaW1lIH0gZnJvbSAnLi4vLi4vdXRpbHMuanMnO1xyXG5cclxuLy8gU2V0IHRoZSBzdGFydCBkYXRlIG9mIHRoZSBzZXJ2ZXJcclxuY29uc3Qgc2VydmVyU3RhcnRUaW1lID0gbmV3IERhdGUoKTtcclxuXHJcbi8vIEdldCB0aGUgYHBhY2thZ2UuanNvbmAgY29udGVudFxyXG5jb25zdCBwYWNrYWdlRmlsZSA9IEpTT04ucGFyc2UoXHJcbiAgcmVhZEZpbGVTeW5jKGpvaW4oX19kaXJuYW1lLCAncGFja2FnZS5qc29uJyksICd1dGY4JylcclxuKTtcclxuXHJcbi8vIEFuIGFycmF5IGZvciBzdWNjZXNzIHJhdGUgcmF0aW9zXHJcbmNvbnN0IHN1Y2Nlc3NSYXRlcyA9IFtdO1xyXG5cclxuLy8gUmVjb3JkIGV2ZXJ5IG1pbnV0ZVxyXG5jb25zdCByZWNvcmRJbnRlcnZhbCA9IDYwICogMTAwMDtcclxuXHJcbi8vIDMwIG1pbnV0ZXNcclxuY29uc3Qgd2luZG93U2l6ZSA9IDMwO1xyXG5cclxuLyoqXHJcbiAqIENhbGN1bGF0ZXMgbW92aW5nIGF2ZXJhZ2UgaW5kaWNhdG9yIGJhc2VkIG9uIHRoZSBkYXRhIGZyb20gdGhlIGBzdWNjZXNzUmF0ZXNgXHJcbiAqIGFycmF5LlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gX2NhbGN1bGF0ZU1vdmluZ0F2ZXJhZ2VcclxuICpcclxuICogQHJldHVybnMge251bWJlcn0gQSBtb3ZpbmcgYXZlcmFnZSBmb3Igc3VjY2VzcyByYXRpbyBvZiB0aGUgc2VydmVyIGV4cG9ydHMuXHJcbiAqL1xyXG5mdW5jdGlvbiBfY2FsY3VsYXRlTW92aW5nQXZlcmFnZSgpIHtcclxuICByZXR1cm4gc3VjY2Vzc1JhdGVzLnJlZHVjZSgoYSwgYikgPT4gYSArIGIsIDApIC8gc3VjY2Vzc1JhdGVzLmxlbmd0aDtcclxufVxyXG5cclxuLyoqXHJcbiAqIFN0YXJ0cyB0aGUgaW50ZXJ2YWwgcmVzcG9uc2libGUgZm9yIGNhbGN1bGF0aW5nIGN1cnJlbnQgc3VjY2VzcyByYXRlIHJhdGlvXHJcbiAqIGFuZCBjb2xsZWN0cyByZWNvcmRzIHRvIHRoZSBgc3VjY2Vzc1JhdGVzYCBhcnJheS5cclxuICpcclxuICogQGZ1bmN0aW9uIF9zdGFydFN1Y2Nlc3NSYXRlXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtOb2RlSlMuVGltZW91dH0gSWQgb2YgYW4gaW50ZXJ2YWwuXHJcbiAqL1xyXG5mdW5jdGlvbiBfc3RhcnRTdWNjZXNzUmF0ZSgpIHtcclxuICByZXR1cm4gc2V0SW50ZXJ2YWwoKCkgPT4ge1xyXG4gICAgY29uc3Qgc3RhdHMgPSBnZXRQb29sU3RhdHMoKTtcclxuICAgIGNvbnN0IHN1Y2Nlc3NSYXRpbyA9XHJcbiAgICAgIHN0YXRzLmV4cG9ydHNBdHRlbXB0ZWQgPT09IDBcclxuICAgICAgICA/IDFcclxuICAgICAgICA6IChzdGF0cy5leHBvcnRzUGVyZm9ybWVkIC8gc3RhdHMuZXhwb3J0c0F0dGVtcHRlZCkgKiAxMDA7XHJcblxyXG4gICAgc3VjY2Vzc1JhdGVzLnB1c2goc3VjY2Vzc1JhdGlvKTtcclxuICAgIGlmIChzdWNjZXNzUmF0ZXMubGVuZ3RoID4gd2luZG93U2l6ZSkge1xyXG4gICAgICBzdWNjZXNzUmF0ZXMuc2hpZnQoKTtcclxuICAgIH1cclxuICB9LCByZWNvcmRJbnRlcnZhbCk7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBBZGRzIHRoZSBgaGVhbHRoYCByb3V0ZXMuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBoZWFsdGhSb3V0ZXNcclxuICpcclxuICogQHBhcmFtIHtFeHByZXNzfSBhcHAgLSBUaGUgRXhwcmVzcyBhcHAgaW5zdGFuY2UuXHJcbiAqL1xyXG5leHBvcnQgZGVmYXVsdCBmdW5jdGlvbiBoZWFsdGhSb3V0ZXMoYXBwKSB7XHJcbiAgLy8gU3RhcnQgcHJvY2Vzc2luZyBzdWNjZXNzIHJhdGUgcmF0aW8gaW50ZXJ2YWwgYW5kIHNhdmUgaXRzIGlkIHRvIHRoZSBhcnJheVxyXG4gIC8vIGZvciB0aGUgZ3JhY2VmdWwgY2xlYXJpbmcgb24gc2h1dGRvd24gd2l0aCBpbmplY3RlZCBgYWRkVGltZXJgIGZ1bnRpb25cclxuICBhZGRUaW1lcihfc3RhcnRTdWNjZXNzUmF0ZSgpKTtcclxuXHJcbiAgLyoqXHJcbiAgICogQWRkcyB0aGUgR0VUICcvaGVhbHRoJyAtIEEgcm91dGUgZm9yIGdldHRpbmcgdGhlIGJhc2ljIHN0YXRzIG9mIHRoZSBzZXJ2ZXIuXHJcbiAgICovXHJcbiAgYXBwLmdldCgnL2hlYWx0aCcsIChyZXF1ZXN0LCByZXNwb25zZSwgbmV4dCkgPT4ge1xyXG4gICAgdHJ5IHtcclxuICAgICAgbG9nKDQsICdbaGVhbHRoXSBSZXR1cm5pbmcgc2VydmVyIGhlYWx0aC4nKTtcclxuXHJcbiAgICAgIGNvbnN0IHN0YXRzID0gZ2V0UG9vbFN0YXRzKCk7XHJcbiAgICAgIGNvbnN0IHBlcmlvZCA9IHN1Y2Nlc3NSYXRlcy5sZW5ndGg7XHJcbiAgICAgIGNvbnN0IG1vdmluZ0F2ZXJhZ2UgPSBfY2FsY3VsYXRlTW92aW5nQXZlcmFnZSgpO1xyXG5cclxuICAgICAgLy8gU2VuZCB0aGUgc2VydmVyJ3Mgc3RhdGlzdGljc1xyXG4gICAgICByZXNwb25zZS5zZW5kKHtcclxuICAgICAgICAvLyBTdGF0dXMgYW5kIHRpbWVzXHJcbiAgICAgICAgc3RhdHVzOiAnT0snLFxyXG4gICAgICAgIGJvb3RUaW1lOiBzZXJ2ZXJTdGFydFRpbWUsXHJcbiAgICAgICAgdXB0aW1lOiBgJHtNYXRoLmZsb29yKChnZXROZXdEYXRlVGltZSgpIC0gc2VydmVyU3RhcnRUaW1lLmdldFRpbWUoKSkgLyAxMDAwIC8gNjApfSBtaW51dGVzYCxcclxuXHJcbiAgICAgICAgLy8gVmVyc2lvbnNcclxuICAgICAgICBzZXJ2ZXJWZXJzaW9uOiBwYWNrYWdlRmlsZS52ZXJzaW9uLFxyXG4gICAgICAgIGhpZ2hjaGFydHNWZXJzaW9uOiBnZXRIaWdoY2hhcnRzVmVyc2lvbigpLFxyXG5cclxuICAgICAgICAvLyBFeHBvcnRzXHJcbiAgICAgICAgYXZlcmFnZUV4cG9ydFRpbWU6IHN0YXRzLnRpbWVTcGVudEF2ZXJhZ2UsXHJcbiAgICAgICAgYXR0ZW1wdGVkRXhwb3J0czogc3RhdHMuZXhwb3J0c0F0dGVtcHRlZCxcclxuICAgICAgICBwZXJmb3JtZWRFeHBvcnRzOiBzdGF0cy5leHBvcnRzUGVyZm9ybWVkLFxyXG4gICAgICAgIGZhaWxlZEV4cG9ydHM6IHN0YXRzLmV4cG9ydHNEcm9wcGVkLFxyXG4gICAgICAgIHN1Y2Vzc1JhdGlvOiAoc3RhdHMuZXhwb3J0c1BlcmZvcm1lZCAvIHN0YXRzLmV4cG9ydHNBdHRlbXB0ZWQpICogMTAwLFxyXG5cclxuICAgICAgICAvLyBQb29sXHJcbiAgICAgICAgcG9vbDogZ2V0UG9vbEluZm9KU09OKCksXHJcblxyXG4gICAgICAgIC8vIE1vdmluZyBhdmVyYWdlXHJcbiAgICAgICAgcGVyaW9kLFxyXG4gICAgICAgIG1vdmluZ0F2ZXJhZ2UsXHJcbiAgICAgICAgbWVzc2FnZTpcclxuICAgICAgICAgIGlzTmFOKG1vdmluZ0F2ZXJhZ2UpIHx8ICFzdWNjZXNzUmF0ZXMubGVuZ3RoXHJcbiAgICAgICAgICAgID8gJ1RvbyBlYXJseSB0byByZXBvcnQuIE5vIGV4cG9ydHMgbWFkZSB5ZXQuIFBsZWFzZSBjaGVjayBiYWNrIHNvb24uJ1xyXG4gICAgICAgICAgICA6IGBMYXN0ICR7cGVyaW9kfSBtaW51dGVzIGhhZCBhIHN1Y2Nlc3MgcmF0ZSBvZiAke21vdmluZ0F2ZXJhZ2UudG9GaXhlZCgyKX0lLmAsXHJcblxyXG4gICAgICAgIC8vIFNWRyBhbmQgSlNPTiBleHBvcnRzXHJcbiAgICAgICAgc3ZnRXhwb3J0czogc3RhdHMuZXhwb3J0c0Zyb21TdmcsXHJcbiAgICAgICAganNvbkV4cG9ydHM6IHN0YXRzLmV4cG9ydHNGcm9tT3B0aW9ucyxcclxuICAgICAgICBzdmdFeHBvcnRzQXR0ZW1wdHM6IHN0YXRzLmV4cG9ydHNGcm9tU3ZnQXR0ZW1wdHMsXHJcbiAgICAgICAganNvbkV4cG9ydHNBdHRlbXB0czogc3RhdHMuZXhwb3J0c0Zyb21PcHRpb25zQXR0ZW1wdHNcclxuICAgICAgfSk7XHJcbiAgICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgICByZXR1cm4gbmV4dChlcnJvcik7XHJcbiAgICB9XHJcbiAgfSk7XHJcbn1cclxuIiwiLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcclxuXHJcbkhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlclxyXG5cclxuQ29weXJpZ2h0IChjKSAyMDE2LTIwMjUsIEhpZ2hzb2Z0XHJcblxyXG5MaWNlbmNlZCB1bmRlciB0aGUgTUlUIGxpY2VuY2UuXHJcblxyXG5BZGRpdGlvbmFsbHkgYSB2YWxpZCBIaWdoY2hhcnRzIGxpY2Vuc2UgaXMgcmVxdWlyZWQgZm9yIHVzZS5cclxuXHJcblNlZSBMSUNFTlNFIGZpbGUgaW4gcm9vdCBmb3IgZGV0YWlscy5cclxuXHJcbioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXHJcblxyXG4vKipcclxuICogQG92ZXJ2aWV3IERlZmluZXMgYW4gRXhwcmVzcyByb3V0ZSBmb3Igc2VydmluZyB0aGUgVUkgZm9yIHRoZSBleHBvcnQgc2VydmVyXHJcbiAqIHdoZW4gZW5hYmxlZC5cclxuICovXHJcblxyXG5pbXBvcnQgeyBqb2luIH0gZnJvbSAncGF0aCc7XHJcblxyXG5pbXBvcnQgeyBnZXRPcHRpb25zIH0gZnJvbSAnLi4vLi4vY29uZmlnLmpzJztcclxuaW1wb3J0IHsgbG9nIH0gZnJvbSAnLi4vLi4vbG9nZ2VyLmpzJztcclxuaW1wb3J0IHsgX19kaXJuYW1lIH0gZnJvbSAnLi4vLi4vdXRpbHMuanMnO1xyXG5cclxuLyoqXHJcbiAqIEFkZHMgdGhlIGB1aWAgcm91dGVzLlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gdWlSb3V0ZXNcclxuICpcclxuICogQHBhcmFtIHtFeHByZXNzfSBhcHAgLSBUaGUgRXhwcmVzcyBhcHAgaW5zdGFuY2UuXHJcbiAqL1xyXG5leHBvcnQgZGVmYXVsdCBmdW5jdGlvbiB1aVJvdXRlcyhhcHApIHtcclxuICAvKipcclxuICAgKiBBZGRzIHRoZSBHRVQgJy8nIC0gQSByb3V0ZSBmb3IgYSBVSSB3aGVuIGVuYWJsZWQgb24gdGhlIGV4cG9ydCBzZXJ2ZXIuXHJcbiAgICovXHJcbiAgYXBwLmdldChnZXRPcHRpb25zKCkudWkucm91dGUgfHwgJy8nLCAocmVxdWVzdCwgcmVzcG9uc2UsIG5leHQpID0+IHtcclxuICAgIHRyeSB7XHJcbiAgICAgIGxvZyg0LCAnW3VpXSBSZXR1cm5pbmcgVUkgZm9yIHRoZSBleHBvcnQuJyk7XHJcblxyXG4gICAgICByZXNwb25zZS5zZW5kRmlsZShqb2luKF9fZGlybmFtZSwgJ3B1YmxpYycsICdpbmRleC5odG1sJyksIHtcclxuICAgICAgICBhY2NlcHRSYW5nZXM6IGZhbHNlXHJcbiAgICAgIH0pO1xyXG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICAgcmV0dXJuIG5leHQoZXJyb3IpO1xyXG4gICAgfVxyXG4gIH0pO1xyXG59XHJcbiIsIi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXHJcblxyXG5IaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXJcclxuXHJcbkNvcHlyaWdodCAoYykgMjAxNi0yMDI1LCBIaWdoc29mdFxyXG5cclxuTGljZW5jZWQgdW5kZXIgdGhlIE1JVCBsaWNlbmNlLlxyXG5cclxuQWRkaXRpb25hbGx5IGEgdmFsaWQgSGlnaGNoYXJ0cyBsaWNlbnNlIGlzIHJlcXVpcmVkIGZvciB1c2UuXHJcblxyXG5TZWUgTElDRU5TRSBmaWxlIGluIHJvb3QgZm9yIGRldGFpbHMuXHJcblxyXG4qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xyXG5cclxuLyoqXHJcbiAqIEBvdmVydmlldyBEZWZpbmVzIGFuIEV4cHJlc3Mgcm91dGUgZm9yIHVwZGF0aW5nIHRoZSBIaWdoY2hhcnRzIHZlcnNpb25cclxuICogb24gdGhlIHNlcnZlciwgd2l0aCBhdXRoZW50aWNhdGlvbiBhbmQgdmFsaWRhdGlvbi5cclxuICovXHJcblxyXG5pbXBvcnQgeyBnZXRIaWdoY2hhcnRzVmVyc2lvbiwgdXBkYXRlSGlnaGNoYXJ0c1ZlcnNpb24gfSBmcm9tICcuLi8uLi9jYWNoZS5qcyc7XHJcbmltcG9ydCB7IGxvZyB9IGZyb20gJy4uLy4uL2xvZ2dlci5qcyc7XHJcbmltcG9ydCB7IGVudnMgfSBmcm9tICcuLi8uLi92YWxpZGF0aW9uLmpzJztcclxuXHJcbmltcG9ydCBFeHBvcnRFcnJvciBmcm9tICcuLi8uLi9lcnJvcnMvRXhwb3J0RXJyb3IuanMnO1xyXG5cclxuLyoqXHJcbiAqIEFkZHMgdGhlIGB2ZXJzaW9uX2NoYW5nZWAgcm91dGVzLlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gdmVyc2lvbkNoYW5nZVJvdXRlc1xyXG4gKlxyXG4gKiBAcGFyYW0ge0V4cHJlc3N9IGFwcCAtIFRoZSBFeHByZXNzIGFwcCBpbnN0YW5jZS5cclxuICovXHJcbmV4cG9ydCBkZWZhdWx0IGZ1bmN0aW9uIHZlcnNpb25DaGFuZ2VSb3V0ZXMoYXBwKSB7XHJcbiAgLyoqXHJcbiAgICogQWRkcyB0aGUgUE9TVCAnL3ZlcnNpb25fY2hhbmdlLzpuZXdWZXJzaW9uJyAtIEEgcm91dGUgZm9yIGNoYW5naW5nXHJcbiAgICogdGhlIEhpZ2hjaGFydHMgdmVyc2lvbiBvbiB0aGUgc2VydmVyLlxyXG4gICAqL1xyXG4gIGFwcC5wb3N0KCcvdmVyc2lvbl9jaGFuZ2UvOm5ld1ZlcnNpb24nLCBhc3luYyAocmVxdWVzdCwgcmVzcG9uc2UsIG5leHQpID0+IHtcclxuICAgIHRyeSB7XHJcbiAgICAgIGxvZyg0LCAnW3ZlcnNpb25dIENoYW5naW5nIEhpZ2hjaGFydHMgdmVyc2lvbi4nKTtcclxuXHJcbiAgICAgIC8vIEdldCB0aGUgdG9rZW4gZGlyZWN0bHkgZnJvbSBlbnZzXHJcbiAgICAgIGNvbnN0IGFkbWluVG9rZW4gPSBlbnZzLkhJR0hDSEFSVFNfQURNSU5fVE9LRU47XHJcblxyXG4gICAgICAvLyBDaGVjayB0aGUgZXhpc3RlbmNlIG9mIHRoZSB0b2tlblxyXG4gICAgICBpZiAoIWFkbWluVG9rZW4gfHwgIWFkbWluVG9rZW4ubGVuZ3RoKSB7XHJcbiAgICAgICAgdGhyb3cgbmV3IEV4cG9ydEVycm9yKFxyXG4gICAgICAgICAgJ1t2ZXJzaW9uXSBUaGUgc2VydmVyIGlzIG5vdCBjb25maWd1cmVkIHRvIHBlcmZvcm0gcnVuLXRpbWUgdmVyc2lvbiBjaGFuZ2VzOiBISUdIQ0hBUlRTX0FETUlOX1RPS0VOIGlzIG5vdCBzZXQuJyxcclxuICAgICAgICAgIDQwMVxyXG4gICAgICAgICk7XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIC8vIEdldCB0aGUgdG9rZW4gZnJvbSB0aGUgaGMtYXV0aCBoZWFkZXJcclxuICAgICAgY29uc3QgdG9rZW4gPSByZXF1ZXN0LmdldCgnaGMtYXV0aCcpO1xyXG5cclxuICAgICAgLy8gQ2hlY2sgaWYgdGhlIGhjLWF1dGggaGVhZGVyIGNvbnRhaW4gYSBjb3JyZWN0IHRva2VuXHJcbiAgICAgIGlmICghdG9rZW4gfHwgdG9rZW4gIT09IGFkbWluVG9rZW4pIHtcclxuICAgICAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoXHJcbiAgICAgICAgICAnW3ZlcnNpb25dIEludmFsaWQgb3IgbWlzc2luZyB0b2tlbjogU2V0IHRoZSB0b2tlbiBpbiB0aGUgaGMtYXV0aCBoZWFkZXIuJyxcclxuICAgICAgICAgIDQwMVxyXG4gICAgICAgICk7XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIC8vIENvbXBhcmUgdmVyc2lvbnNcclxuICAgICAgY29uc3QgbmV3VmVyc2lvbiA9IHJlcXVlc3QucGFyYW1zLm5ld1ZlcnNpb247XHJcblxyXG4gICAgICAvLyBXaGVuIGEgY29ycmVjdCB2YWx1ZSBmb3VuZFxyXG4gICAgICBpZiAobmV3VmVyc2lvbikge1xyXG4gICAgICAgIHRyeSB7XHJcbiAgICAgICAgICAvLyBVcGRhdGUgdmVyc2lvblxyXG4gICAgICAgICAgYXdhaXQgdXBkYXRlSGlnaGNoYXJ0c1ZlcnNpb24obmV3VmVyc2lvbik7XHJcbiAgICAgICAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICAgICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcihcclxuICAgICAgICAgICAgYFt2ZXJzaW9uXSBWZXJzaW9uIGNoYW5nZTogJHtlcnJvci5tZXNzYWdlfWAsXHJcbiAgICAgICAgICAgIDQwMFxyXG4gICAgICAgICAgKS5zZXRFcnJvcihlcnJvcik7XHJcbiAgICAgICAgfVxyXG5cclxuICAgICAgICAvLyBTdWNjZXNzXHJcbiAgICAgICAgcmVzcG9uc2Uuc3RhdHVzKDIwMCkuc2VuZCh7XHJcbiAgICAgICAgICBzdGF0dXNDb2RlOiAyMDAsXHJcbiAgICAgICAgICBoaWdoY2hhcnRzVmVyc2lvbjogZ2V0SGlnaGNoYXJ0c1ZlcnNpb24oKSxcclxuICAgICAgICAgIG1lc3NhZ2U6IGBTdWNjZXNzZnVsbHkgdXBkYXRlZCBIaWdoY2hhcnRzIHRvIHZlcnNpb246ICR7bmV3VmVyc2lvbn0uYFxyXG4gICAgICAgIH0pO1xyXG4gICAgICB9IGVsc2Uge1xyXG4gICAgICAgIC8vIE5vIHZlcnNpb24gc3BlY2lmaWVkXHJcbiAgICAgICAgdGhyb3cgbmV3IEV4cG9ydEVycm9yKCdbdmVyc2lvbl0gTm8gbmV3IHZlcnNpb24gc3VwcGxpZWQuJywgNDAwKTtcclxuICAgICAgfVxyXG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICAgcmV0dXJuIG5leHQoZXJyb3IpO1xyXG4gICAgfVxyXG4gIH0pO1xyXG59XHJcbiIsIi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXHJcblxyXG5IaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXJcclxuXHJcbkNvcHlyaWdodCAoYykgMjAxNi0yMDI1LCBIaWdoc29mdFxyXG5cclxuTGljZW5jZWQgdW5kZXIgdGhlIE1JVCBsaWNlbmNlLlxyXG5cclxuQWRkaXRpb25hbGx5IGEgdmFsaWQgSGlnaGNoYXJ0cyBsaWNlbnNlIGlzIHJlcXVpcmVkIGZvciB1c2UuXHJcblxyXG5TZWUgTElDRU5TRSBmaWxlIGluIHJvb3QgZm9yIGRldGFpbHMuXHJcblxyXG4qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xyXG5cclxuLyoqXHJcbiAqIEBvdmVydmlldyBBIG1vZHVsZSB0aGF0IHNldHMgdXAgYW5kIG1hbmFnZXMgSFRUUCBhbmQgSFRUUFMgc2VydmVyc1xyXG4gKiBmb3IgdGhlIEhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlci4gSXQgaGFuZGxlcyBzZXJ2ZXIgaW5pdGlhbGl6YXRpb24sXHJcbiAqIGNvbmZpZ3VyYXRpb24sIGVycm9yIGhhbmRsaW5nLCBtaWRkbGV3YXJlIHNldHVwLCByb3V0ZSBkZWZpbml0aW9uLCBhbmQgcmF0ZVxyXG4gKiBsaW1pdGluZy4gVGhlIG1vZHVsZSBleHBvcnRzIGZ1bmN0aW9ucyB0byBzdGFydCwgc3RvcCwgYW5kIG1hbmFnZSBzZXJ2ZXJcclxuICogaW5zdGFuY2VzLCBhcyB3ZWxsIGFzIHV0aWxpdHkgZnVuY3Rpb25zIGZvciBkZWZpbmluZyByb3V0ZXMgYW5kIGF0dGFjaGluZ1xyXG4gKiBtaWRkbGV3YXJlcy5cclxuICovXHJcblxyXG5pbXBvcnQgeyByZWFkRmlsZVN5bmMgfSBmcm9tICdmcyc7XHJcbmltcG9ydCB7IGpvaW4gfSBmcm9tICdwYXRoJztcclxuXHJcbmltcG9ydCBjb3JzIGZyb20gJ2NvcnMnO1xyXG5pbXBvcnQgZXhwcmVzcyBmcm9tICdleHByZXNzJztcclxuaW1wb3J0IGh0dHAgZnJvbSAnaHR0cCc7XHJcbmltcG9ydCBodHRwcyBmcm9tICdodHRwcyc7XHJcbmltcG9ydCBtdWx0ZXIgZnJvbSAnbXVsdGVyJztcclxuXHJcbmltcG9ydCB7IHVwZGF0ZU9wdGlvbnMgfSBmcm9tICcuLi9jb25maWcuanMnO1xyXG5pbXBvcnQgeyBsb2csIGxvZ1dpdGhTdGFjayB9IGZyb20gJy4uL2xvZ2dlci5qcyc7XHJcbmltcG9ydCB7IF9fZGlybmFtZSwgZ2V0QWJzb2x1dGVQYXRoIH0gZnJvbSAnLi4vdXRpbHMuanMnO1xyXG5cclxuaW1wb3J0IGVycm9yTWlkZGxld2FyZSBmcm9tICcuL21pZGRsZXdhcmVzL2Vycm9yLmpzJztcclxuaW1wb3J0IHJhdGVMaW1pdGluZ01pZGRsZXdhcmUgZnJvbSAnLi9taWRkbGV3YXJlcy9yYXRlTGltaXRpbmcuanMnO1xyXG5pbXBvcnQgdmFsaWRhdGlvbk1pZGRsZXdhcmUgZnJvbSAnLi9taWRkbGV3YXJlcy92YWxpZGF0aW9uLmpzJztcclxuXHJcbmltcG9ydCBleHBvcnRSb3V0ZXMgZnJvbSAnLi9yb3V0ZXMvZXhwb3J0LmpzJztcclxuaW1wb3J0IGhlYWx0aFJvdXRlcyBmcm9tICcuL3JvdXRlcy9oZWFsdGguanMnO1xyXG5pbXBvcnQgdWlSb3V0ZXMgZnJvbSAnLi9yb3V0ZXMvdWkuanMnO1xyXG5pbXBvcnQgdmVyc2lvbkNoYW5nZVJvdXRlcyBmcm9tICcuL3JvdXRlcy92ZXJzaW9uQ2hhbmdlLmpzJztcclxuXHJcbmltcG9ydCBFeHBvcnRFcnJvciBmcm9tICcuLi9lcnJvcnMvRXhwb3J0RXJyb3IuanMnO1xyXG5cclxuLy8gQXJyYXkgb2YgYW4gYWN0aXZlIHNlcnZlcnNcclxuY29uc3QgYWN0aXZlU2VydmVycyA9IG5ldyBNYXAoKTtcclxuXHJcbi8vIENyZWF0ZSBleHByZXNzIGFwcFxyXG5jb25zdCBhcHAgPSBleHByZXNzKCk7XHJcblxyXG4vKipcclxuICogU3RhcnRzIGFuIEhUVFAgYW5kL29yIEhUVFBTIHNlcnZlciBiYXNlZCBvbiB0aGUgcHJvdmlkZWQgY29uZmlndXJhdGlvbi5cclxuICogVGhlIGBzZXJ2ZXJPcHRpb25zYCBvYmplY3QgY29udGFpbnMgc2VydmVyLXJlbGF0ZWQgcHJvcGVydGllcyAocmVmZXJcclxuICogdG8gdGhlIGBzZXJ2ZXJgIHNlY3Rpb24gaW4gdGhlIGAuL2xpYi9zY2hlbWFzL2NvbmZpZy5qc2AgZmlsZSBmb3IgZGV0YWlscykuXHJcbiAqXHJcbiAqIEBhc3luY1xyXG4gKiBAZnVuY3Rpb24gc3RhcnRTZXJ2ZXJcclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IHNlcnZlck9wdGlvbnMgLSBUaGUgY29uZmlndXJhdGlvbiBvYmplY3QgY29udGFpbmluZyBgc2VydmVyYFxyXG4gKiBvcHRpb25zLiBUaGlzIG9iamVjdCBtYXkgaW5jbHVkZSBhIHBhcnRpYWwgb3IgY29tcGxldGUgc2V0IG9mIHRoZSBgc2VydmVyYFxyXG4gKiBvcHRpb25zLiBJZiB0aGUgb3B0aW9ucyBhcmUgcGFydGlhbCwgbWlzc2luZyB2YWx1ZXMgd2lsbCBkZWZhdWx0XHJcbiAqIHRvIHRoZSBjdXJyZW50IGdsb2JhbCBjb25maWd1cmF0aW9uLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7UHJvbWlzZTx2b2lkPn0gQSBQcm9taXNlIHRoYXQgcmVzb2x2ZXMgd2hlbiB0aGUgc2VydmVyIGlzIGVpdGhlclxyXG4gKiBub3QgZW5hYmxlZCBvciBubyB2YWxpZCBFeHByZXNzIGFwcCBpcyBmb3VuZCwgc2lnbmFsaW5nIHRoZSBlbmQgb2YgdGhlXHJcbiAqIGZ1bmN0aW9uJ3MgZXhlY3V0aW9uLlxyXG4gKlxyXG4gKiBAdGhyb3dzIHtFeHBvcnRFcnJvcn0gVGhyb3dzIGFuIGBFeHBvcnRFcnJvcmAgaWYgdGhlIHNlcnZlciBjYW5ub3RcclxuICogYmUgY29uZmlndXJlZCBhbmQgc3RhcnRlZC5cclxuICovXHJcbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBzdGFydFNlcnZlcihzZXJ2ZXJPcHRpb25zKSB7XHJcbiAgdHJ5IHtcclxuICAgIC8vIFVwZGF0ZSB0aGUgaW5zdGFuY2Ugb3B0aW9ucyBvYmplY3RcclxuICAgIGNvbnN0IG9wdGlvbnMgPSB1cGRhdGVPcHRpb25zKHtcclxuICAgICAgc2VydmVyOiBzZXJ2ZXJPcHRpb25zXHJcbiAgICB9KTtcclxuXHJcbiAgICAvLyBVc2UgdmFsaWRhdGVkIG9wdGlvbnNcclxuICAgIHNlcnZlck9wdGlvbnMgPSBvcHRpb25zLnNlcnZlcjtcclxuXHJcbiAgICAvLyBTdG9wIGlmIG5vdCBlbmFibGVkXHJcbiAgICBpZiAoIXNlcnZlck9wdGlvbnMuZW5hYmxlIHx8ICFhcHApIHtcclxuICAgICAgdGhyb3cgbmV3IEV4cG9ydEVycm9yKFxyXG4gICAgICAgICdbc2VydmVyXSBTZXJ2ZXIgY2Fubm90IGJlIHN0YXJ0ZWQgKG5vdCBlbmFibGVkIG9yIG5vIGNvcnJlY3QgRXhwcmVzcyBhcHAgZm91bmQpLicsXHJcbiAgICAgICAgNTAwXHJcbiAgICAgICk7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gVG9vIGJpZyBsaW1pdHMgbGVhZCB0byB0aW1lb3V0cyBpbiB0aGUgZXhwb3J0IHByb2Nlc3Mgd2hlblxyXG4gICAgLy8gdGhlIHJhc3Rlcml6YXRpb24gdGltZW91dCBpcyBzZXQgdG9vIGxvd1xyXG4gICAgY29uc3QgdXBsb2FkTGltaXRCeXRlcyA9IHNlcnZlck9wdGlvbnMudXBsb2FkTGltaXQgKiAxMDI0ICogMTAyNDtcclxuXHJcbiAgICAvLyBNZW1vcnkgc3RvcmFnZSBmb3IgbXVsdGVyIHBhY2thZ2VcclxuICAgIGNvbnN0IHN0b3JhZ2UgPSBtdWx0ZXIubWVtb3J5U3RvcmFnZSgpO1xyXG5cclxuICAgIC8vIEVuYWJsZSBwYXJzaW5nIG9mIGZvcm0gZGF0YSAoZmlsZXMpIHdpdGggbXVsdGVyIHBhY2thZ2VcclxuICAgIGNvbnN0IHVwbG9hZCA9IG11bHRlcih7XHJcbiAgICAgIHN0b3JhZ2UsXHJcbiAgICAgIGxpbWl0czoge1xyXG4gICAgICAgIGZpZWxkU2l6ZTogdXBsb2FkTGltaXRCeXRlc1xyXG4gICAgICB9XHJcbiAgICB9KTtcclxuXHJcbiAgICAvLyBEaXNhYmxlIHRoZSBYLVBvd2VyZWQtQnkgaGVhZGVyXHJcbiAgICBhcHAuZGlzYWJsZSgneC1wb3dlcmVkLWJ5Jyk7XHJcblxyXG4gICAgLy8gRW5hYmxlIENPUlMgc3VwcG9ydFxyXG4gICAgYXBwLnVzZShcclxuICAgICAgY29ycyh7XHJcbiAgICAgICAgbWV0aG9kczogWydQT1NUJywgJ0dFVCcsICdPUFRJT05TJ11cclxuICAgICAgfSlcclxuICAgICk7XHJcblxyXG4gICAgLy8gR2V0dGluZyBhIGxvdCBvZiBgUmFuZ2VOb3RTYXRpc2ZpYWJsZUVycm9yYCBleGNlcHRpb25zIChldmVuIHRob3VnaCB0aGlzXHJcbiAgICAvLyBpcyBhIGRlcHJlY2F0ZWQgb3B0aW9ucywgbGV0J3MgdHJ5IHRvIHNldCBpdCB0byBmYWxzZSlcclxuICAgIGFwcC51c2UoKHJlcXVlc3QsIHJlc3BvbnNlLCBuZXh0KSA9PiB7XHJcbiAgICAgIHJlc3BvbnNlLnNldCgnQWNjZXB0LVJhbmdlcycsICdub25lJyk7XHJcbiAgICAgIG5leHQoKTtcclxuICAgIH0pO1xyXG5cclxuICAgIC8vIEVuYWJsZSBib2R5IHBhcnNlciBmb3IgSlNPTiBkYXRhXHJcbiAgICBhcHAudXNlKFxyXG4gICAgICBleHByZXNzLmpzb24oe1xyXG4gICAgICAgIGxpbWl0OiB1cGxvYWRMaW1pdEJ5dGVzXHJcbiAgICAgIH0pXHJcbiAgICApO1xyXG5cclxuICAgIC8vIEVuYWJsZSBib2R5IHBhcnNlciBmb3IgVVJMLWVuY29kZWQgZm9ybSBkYXRhXHJcbiAgICBhcHAudXNlKFxyXG4gICAgICBleHByZXNzLnVybGVuY29kZWQoe1xyXG4gICAgICAgIGV4dGVuZGVkOiB0cnVlLFxyXG4gICAgICAgIGxpbWl0OiB1cGxvYWRMaW1pdEJ5dGVzXHJcbiAgICAgIH0pXHJcbiAgICApO1xyXG5cclxuICAgIC8vIFVzZSBvbmx5IG5vbi1maWxlIG11bHRpcGFydCBmb3JtIGZpZWxkc1xyXG4gICAgYXBwLnVzZSh1cGxvYWQubm9uZSgpKTtcclxuXHJcbiAgICAvLyBTZXQgdXAgc3RhdGljIGZvbGRlcidzIHJvdXRlXHJcbiAgICBhcHAudXNlKGV4cHJlc3Muc3RhdGljKGpvaW4oX19kaXJuYW1lLCAncHVibGljJykpKTtcclxuXHJcbiAgICAvLyBMaXN0ZW4gSFRUUCBzZXJ2ZXJcclxuICAgIGlmICghc2VydmVyT3B0aW9ucy5zc2wuZm9yY2UpIHtcclxuICAgICAgLy8gTWFpbiBzZXJ2ZXIgaW5zdGFuY2UgKEhUVFApXHJcbiAgICAgIGNvbnN0IGh0dHBTZXJ2ZXIgPSBodHRwLmNyZWF0ZVNlcnZlcihhcHApO1xyXG5cclxuICAgICAgLy8gQXR0YWNoIGVycm9yIGhhbmRsZXJzIGFuZCBsaXN0ZW4gdG8gdGhlIHNlcnZlclxyXG4gICAgICBfYXR0YWNoU2VydmVyRXJyb3JIYW5kbGVycyhodHRwU2VydmVyKTtcclxuXHJcbiAgICAgIC8vIExpc3RlblxyXG4gICAgICBodHRwU2VydmVyLmxpc3RlbihzZXJ2ZXJPcHRpb25zLnBvcnQsIHNlcnZlck9wdGlvbnMuaG9zdCwgKCkgPT4ge1xyXG4gICAgICAgIC8vIFNhdmUgdGhlIHJlZmVyZW5jZSB0byBIVFRQIHNlcnZlclxyXG4gICAgICAgIGFjdGl2ZVNlcnZlcnMuc2V0KHNlcnZlck9wdGlvbnMucG9ydCwgaHR0cFNlcnZlcik7XHJcblxyXG4gICAgICAgIGxvZyhcclxuICAgICAgICAgIDMsXHJcbiAgICAgICAgICBgW3NlcnZlcl0gU3RhcnRlZCBIVFRQIHNlcnZlciBvbiAke3NlcnZlck9wdGlvbnMuaG9zdH06JHtzZXJ2ZXJPcHRpb25zLnBvcnR9LmBcclxuICAgICAgICApO1xyXG4gICAgICB9KTtcclxuICAgIH1cclxuXHJcbiAgICAvLyBMaXN0ZW4gSFRUUFMgc2VydmVyXHJcbiAgICBpZiAoc2VydmVyT3B0aW9ucy5zc2wuZW5hYmxlKSB7XHJcbiAgICAgIC8vIFNldCB1cCBhbiBTU0wgc2VydmVyIGFsc29cclxuICAgICAgbGV0IGtleSwgY2VydDtcclxuXHJcbiAgICAgIHRyeSB7XHJcbiAgICAgICAgLy8gR2V0IHRoZSBTU0wga2V5XHJcbiAgICAgICAga2V5ID0gcmVhZEZpbGVTeW5jKFxyXG4gICAgICAgICAgam9pbihnZXRBYnNvbHV0ZVBhdGgoc2VydmVyT3B0aW9ucy5zc2wuY2VydFBhdGgpLCAnc2VydmVyLmtleScpLFxyXG4gICAgICAgICAgJ3V0ZjgnXHJcbiAgICAgICAgKTtcclxuXHJcbiAgICAgICAgLy8gR2V0IHRoZSBTU0wgY2VydGlmaWNhdGVcclxuICAgICAgICBjZXJ0ID0gcmVhZEZpbGVTeW5jKFxyXG4gICAgICAgICAgam9pbihnZXRBYnNvbHV0ZVBhdGgoc2VydmVyT3B0aW9ucy5zc2wuY2VydFBhdGgpLCAnc2VydmVyLmNydCcpLFxyXG4gICAgICAgICAgJ3V0ZjgnXHJcbiAgICAgICAgKTtcclxuICAgICAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICAgICBsb2coXHJcbiAgICAgICAgICAyLFxyXG4gICAgICAgICAgYFtzZXJ2ZXJdIFVuYWJsZSB0byBsb2FkIGtleS9jZXJ0aWZpY2F0ZSBmcm9tIHRoZSAnJHtzZXJ2ZXJPcHRpb25zLnNzbC5jZXJ0UGF0aH0nIHBhdGguIENvdWxkIG5vdCBydW4gc2VjdXJlZCBsYXllciBzZXJ2ZXIuYFxyXG4gICAgICAgICk7XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIGlmIChrZXkgJiYgY2VydCkge1xyXG4gICAgICAgIC8vIE1haW4gc2VydmVyIGluc3RhbmNlIChIVFRQUylcclxuICAgICAgICBjb25zdCBodHRwc1NlcnZlciA9IGh0dHBzLmNyZWF0ZVNlcnZlcih7IGtleSwgY2VydCB9LCBhcHApO1xyXG5cclxuICAgICAgICAvLyBBdHRhY2ggZXJyb3IgaGFuZGxlcnMgYW5kIGxpc3RlbiB0byB0aGUgc2VydmVyXHJcbiAgICAgICAgX2F0dGFjaFNlcnZlckVycm9ySGFuZGxlcnMoaHR0cHNTZXJ2ZXIpO1xyXG5cclxuICAgICAgICAvLyBMaXN0ZW5cclxuICAgICAgICBodHRwc1NlcnZlci5saXN0ZW4oc2VydmVyT3B0aW9ucy5zc2wucG9ydCwgc2VydmVyT3B0aW9ucy5ob3N0LCAoKSA9PiB7XHJcbiAgICAgICAgICAvLyBTYXZlIHRoZSByZWZlcmVuY2UgdG8gSFRUUFMgc2VydmVyXHJcbiAgICAgICAgICBhY3RpdmVTZXJ2ZXJzLnNldChzZXJ2ZXJPcHRpb25zLnNzbC5wb3J0LCBodHRwc1NlcnZlcik7XHJcblxyXG4gICAgICAgICAgbG9nKFxyXG4gICAgICAgICAgICAzLFxyXG4gICAgICAgICAgICBgW3NlcnZlcl0gU3RhcnRlZCBIVFRQUyBzZXJ2ZXIgb24gJHtzZXJ2ZXJPcHRpb25zLmhvc3R9OiR7c2VydmVyT3B0aW9ucy5zc2wucG9ydH0uYFxyXG4gICAgICAgICAgKTtcclxuICAgICAgICB9KTtcclxuICAgICAgfVxyXG4gICAgfVxyXG5cclxuICAgIC8vIFNldCB1cCB0aGUgcmF0ZSBsaW1pdGVyXHJcbiAgICByYXRlTGltaXRpbmdNaWRkbGV3YXJlKGFwcCwgc2VydmVyT3B0aW9ucy5yYXRlTGltaXRpbmcpO1xyXG5cclxuICAgIC8vIFNldCB1cCB0aGUgdmFsaWRhdGlvbiBoYW5kbGVyXHJcbiAgICB2YWxpZGF0aW9uTWlkZGxld2FyZShhcHApO1xyXG5cclxuICAgIC8vIFNldCB1cCByb3V0ZXNcclxuICAgIGV4cG9ydFJvdXRlcyhhcHApO1xyXG4gICAgaGVhbHRoUm91dGVzKGFwcCk7XHJcbiAgICB1aVJvdXRlcyhhcHApO1xyXG4gICAgdmVyc2lvbkNoYW5nZVJvdXRlcyhhcHApO1xyXG5cclxuICAgIC8vIFNldCB1cCB0aGUgY2VudHJhbGl6ZWQgZXJyb3IgaGFuZGxlclxyXG4gICAgZXJyb3JNaWRkbGV3YXJlKGFwcCk7XHJcbiAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcihcclxuICAgICAgJ1tzZXJ2ZXJdIENvdWxkIG5vdCBjb25maWd1cmUgYW5kIHN0YXJ0IHRoZSBzZXJ2ZXIuJyxcclxuICAgICAgNTAwXHJcbiAgICApLnNldEVycm9yKGVycm9yKTtcclxuICB9XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBDbG9zZXMgYWxsIHNlcnZlcnMgYXNzb2NpYXRlZCB3aXRoIEV4cHJlc3MgYXBwIGluc3RhbmNlLlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gY2xvc2VTZXJ2ZXJzXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gY2xvc2VTZXJ2ZXJzKCkge1xyXG4gIC8vIENoZWNrIGlmIHRoZXJlIGFyZSBzZXJ2ZXJzIHdvcmtpbmdcclxuICBpZiAoYWN0aXZlU2VydmVycy5zaXplID4gMCkge1xyXG4gICAgbG9nKDQsIGBbc2VydmVyXSBDbG9zaW5nIGFsbCBzZXJ2ZXJzLmApO1xyXG5cclxuICAgIC8vIENsb3NlIGVhY2ggb25lIG9mIHNlcnZlcnNcclxuICAgIGZvciAoY29uc3QgW3BvcnQsIHNlcnZlcl0gb2YgYWN0aXZlU2VydmVycykge1xyXG4gICAgICBzZXJ2ZXIuY2xvc2UoKCkgPT4ge1xyXG4gICAgICAgIGFjdGl2ZVNlcnZlcnMuZGVsZXRlKHBvcnQpO1xyXG4gICAgICAgIGxvZyg0LCBgW3NlcnZlcl0gQ2xvc2VkIHNlcnZlciBvbiBwb3J0OiAke3BvcnR9LmApO1xyXG4gICAgICB9KTtcclxuICAgIH1cclxuICB9XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBHZXQgYWxsIHNlcnZlcnMgYXNzb2NpYXRlZCB3aXRoIEV4cHJlc3MgYXBwIGluc3RhbmNlLlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gZ2V0U2VydmVyc1xyXG4gKlxyXG4gKiBAcmV0dXJucyB7QXJyYXkuPE9iamVjdD59IFNlcnZlcnMgYXNzb2NpYXRlZCB3aXRoIEV4cHJlc3MgYXBwIGluc3RhbmNlLlxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIGdldFNlcnZlcnMoKSB7XHJcbiAgcmV0dXJuIGFjdGl2ZVNlcnZlcnM7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBHZXQgdGhlIEV4cHJlc3MgaW5zdGFuY2UuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBnZXRFeHByZXNzXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtFeHByZXNzfSBUaGUgRXhwcmVzcyBpbnN0YW5jZS5cclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiBnZXRFeHByZXNzKCkge1xyXG4gIHJldHVybiBleHByZXNzO1xyXG59XHJcblxyXG4vKipcclxuICogR2V0IHRoZSBFeHByZXNzIGFwcCBpbnN0YW5jZS5cclxuICpcclxuICogQGZ1bmN0aW9uIGdldEFwcFxyXG4gKlxyXG4gKiBAcmV0dXJucyB7RXhwcmVzc30gVGhlIEV4cHJlc3MgYXBwIGluc3RhbmNlLlxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIGdldEFwcCgpIHtcclxuICByZXR1cm4gYXBwO1xyXG59XHJcblxyXG4vKipcclxuICogRW5hYmxlIHJhdGUgbGltaXRpbmcgZm9yIHRoZSBzZXJ2ZXIuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBlbmFibGVSYXRlTGltaXRpbmdcclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IHJhdGVMaW1pdGluZ09wdGlvbnMgLSBUaGUgY29uZmlndXJhdGlvbiBvYmplY3QgY29udGFpbmluZ1xyXG4gKiBgcmF0ZUxpbWl0aW5nYCBvcHRpb25zLiBUaGlzIG9iamVjdCBtYXkgaW5jbHVkZSBhIHBhcnRpYWwgb3IgY29tcGxldGUgc2V0XHJcbiAqIG9mIHRoZSBgcmF0ZUxpbWl0aW5nYCBvcHRpb25zLiBJZiB0aGUgb3B0aW9ucyBhcmUgcGFydGlhbCwgbWlzc2luZyB2YWx1ZXNcclxuICogd2lsbCBkZWZhdWx0IHRvIHRoZSBjdXJyZW50IGdsb2JhbCBjb25maWd1cmF0aW9uLlxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIGVuYWJsZVJhdGVMaW1pdGluZyhyYXRlTGltaXRpbmdPcHRpb25zKSB7XHJcbiAgLy8gVXBkYXRlIHRoZSBpbnN0YW5jZSBvcHRpb25zIG9iamVjdFxyXG4gIGNvbnN0IG9wdGlvbnMgPSB1cGRhdGVPcHRpb25zKHtcclxuICAgIHNlcnZlcjoge1xyXG4gICAgICByYXRlTGltaXRpbmc6IHJhdGVMaW1pdGluZ09wdGlvbnNcclxuICAgIH1cclxuICB9KTtcclxuXHJcbiAgLy8gU2V0IHRoZSByYXRlIGxpbWl0aW5nIG9wdGlvbnNcclxuICByYXRlTGltaXRpbmdNaWRkbGV3YXJlKGFwcCwgb3B0aW9ucy5zZXJ2ZXIucmF0ZUxpbWl0aW5nT3B0aW9ucyk7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBBcHBseSBtaWRkbGV3YXJlKHMpIHRvIGEgc3BlY2lmaWMgcGF0aC5cclxuICpcclxuICogQGZ1bmN0aW9uIHVzZVxyXG4gKlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gcGF0aCAtIFRoZSBwYXRoIHRvIHdoaWNoIHRoZSBtaWRkbGV3YXJlKHMpIHNob3VsZCBiZSBhcHBsaWVkLlxyXG4gKiBAcGFyYW0gey4uLkZ1bmN0aW9ufSBtaWRkbGV3YXJlcyAtIFRoZSBtaWRkbGV3YXJlIGZ1bmN0aW9uKHMpIHRvIGJlIGFwcGxpZWQuXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gdXNlKHBhdGgsIC4uLm1pZGRsZXdhcmVzKSB7XHJcbiAgYXBwLnVzZShwYXRoLCAuLi5taWRkbGV3YXJlcyk7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBTZXQgdXAgYSByb3V0ZSB3aXRoIEdFVCBtZXRob2QgYW5kIGFwcGx5IG1pZGRsZXdhcmUocykuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBnZXRcclxuICpcclxuICogQHBhcmFtIHtzdHJpbmd9IHBhdGggLSBUaGUgcGF0aCB0byB3aGljaCB0aGUgbWlkZGxld2FyZShzKSBzaG91bGQgYmUgYXBwbGllZC5cclxuICogQHBhcmFtIHsuLi5GdW5jdGlvbn0gbWlkZGxld2FyZXMgLSBUaGUgbWlkZGxld2FyZSBmdW5jdGlvbihzKSB0byBiZSBhcHBsaWVkLlxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIGdldChwYXRoLCAuLi5taWRkbGV3YXJlcykge1xyXG4gIGFwcC5nZXQocGF0aCwgLi4ubWlkZGxld2FyZXMpO1xyXG59XHJcblxyXG4vKipcclxuICogU2V0IHVwIGEgcm91dGUgd2l0aCBQT1NUIG1ldGhvZCBhbmQgYXBwbHkgbWlkZGxld2FyZShzKS5cclxuICpcclxuICogQGZ1bmN0aW9uIHBvc3RcclxuICpcclxuICogQHBhcmFtIHtzdHJpbmd9IHBhdGggLSBUaGUgcGF0aCB0byB3aGljaCB0aGUgbWlkZGxld2FyZShzKSBzaG91bGQgYmUgYXBwbGllZC5cclxuICogQHBhcmFtIHsuLi5GdW5jdGlvbn0gbWlkZGxld2FyZXMgLSBUaGUgbWlkZGxld2FyZSBmdW5jdGlvbihzKSB0byBiZSBhcHBsaWVkLlxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIHBvc3QocGF0aCwgLi4ubWlkZGxld2FyZXMpIHtcclxuICBhcHAucG9zdChwYXRoLCAuLi5taWRkbGV3YXJlcyk7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBBdHRhY2ggZXJyb3IgaGFuZGxlcnMgdG8gdGhlIHNlcnZlci5cclxuICpcclxuICogQGZ1bmN0aW9uIF9hdHRhY2hTZXJ2ZXJFcnJvckhhbmRsZXJzXHJcbiAqXHJcbiAqIEBwYXJhbSB7KGh0dHAuU2VydmVyfGh0dHBzLlNlcnZlcil9IHNlcnZlciAtIFRoZSBIVFRQL0hUVFBTIHNlcnZlciBpbnN0YW5jZS5cclxuICovXHJcbmZ1bmN0aW9uIF9hdHRhY2hTZXJ2ZXJFcnJvckhhbmRsZXJzKHNlcnZlcikge1xyXG4gIHNlcnZlci5vbignY2xpZW50RXJyb3InLCAoZXJyb3IsIHNvY2tldCkgPT4ge1xyXG4gICAgbG9nV2l0aFN0YWNrKFxyXG4gICAgICAxLFxyXG4gICAgICBlcnJvcixcclxuICAgICAgYFtzZXJ2ZXJdIENsaWVudCBlcnJvcjogJHtlcnJvci5tZXNzYWdlfSwgZGVzdHJveWluZyBzb2NrZXQuYFxyXG4gICAgKTtcclxuICAgIHNvY2tldC5kZXN0cm95KCk7XHJcbiAgfSk7XHJcblxyXG4gIHNlcnZlci5vbignZXJyb3InLCAoZXJyb3IpID0+IHtcclxuICAgIGxvZ1dpdGhTdGFjaygxLCBlcnJvciwgYFtzZXJ2ZXJdIFNlcnZlciBlcnJvcjogJHtlcnJvci5tZXNzYWdlfWApO1xyXG4gIH0pO1xyXG5cclxuICBzZXJ2ZXIub24oJ2Nvbm5lY3Rpb24nLCAoc29ja2V0KSA9PiB7XHJcbiAgICBzb2NrZXQub24oJ2Vycm9yJywgKGVycm9yKSA9PiB7XHJcbiAgICAgIGxvZ1dpdGhTdGFjaygxLCBlcnJvciwgYFtzZXJ2ZXJdIFNvY2tldCBlcnJvcjogJHtlcnJvci5tZXNzYWdlfWApO1xyXG4gICAgfSk7XHJcbiAgfSk7XHJcbn1cclxuXHJcbmV4cG9ydCBkZWZhdWx0IHtcclxuICBzdGFydFNlcnZlcixcclxuICBjbG9zZVNlcnZlcnMsXHJcbiAgZ2V0U2VydmVycyxcclxuICBnZXRFeHByZXNzLFxyXG4gIGdldEFwcCxcclxuICBlbmFibGVSYXRlTGltaXRpbmcsXHJcbiAgdXNlLFxyXG4gIGdldCxcclxuICBwb3N0XHJcbn07XHJcbiIsIi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXHJcblxyXG5IaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXJcclxuXHJcbkNvcHlyaWdodCAoYykgMjAxNi0yMDI1LCBIaWdoc29mdFxyXG5cclxuTGljZW5jZWQgdW5kZXIgdGhlIE1JVCBsaWNlbmNlLlxyXG5cclxuQWRkaXRpb25hbGx5IGEgdmFsaWQgSGlnaGNoYXJ0cyBsaWNlbnNlIGlzIHJlcXVpcmVkIGZvciB1c2UuXHJcblxyXG5TZWUgTElDRU5TRSBmaWxlIGluIHJvb3QgZm9yIGRldGFpbHMuXHJcblxyXG4qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xyXG5cclxuLyoqXHJcbiAqIEBvdmVydmlldyBIYW5kbGVzIGdyYWNlZnVsIHNodXRkb3duIG9mIHRoZSBIaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXIsIGVuc3VyaW5nXHJcbiAqIHByb3BlciBjbGVhbnVwIG9mIHJlc291cmNlcyBzdWNoIGFzIGJyb3dzZXIsIHBhZ2VzLCBzZXJ2ZXJzLCBhbmQgdGltZXJzLlxyXG4gKi9cclxuXHJcbmltcG9ydCB7IGtpbGxQb29sIH0gZnJvbSAnLi9wb29sLmpzJztcclxuaW1wb3J0IHsgY2xlYXJBbGxUaW1lcnMgfSBmcm9tICcuL3RpbWVyLmpzJztcclxuXHJcbmltcG9ydCB7IGNsb3NlU2VydmVycyB9IGZyb20gJy4vc2VydmVyL3NlcnZlci5qcyc7XHJcblxyXG4vKipcclxuICogUGVyZm9ybXMgY2xlYW51cCBvcGVyYXRpb25zIHRvIGVuc3VyZSBhIGdyYWNlZnVsIHNodXRkb3duIG9mIHRoZSBwcm9jZXNzLlxyXG4gKiBUaGlzIGluY2x1ZGVzIGNsZWFyaW5nIGFsbCByZWdpc3RlcmVkIHRpbWVvdXRzL2ludGVydmFscywgY2xvc2luZyBhY3RpdmVcclxuICogc2VydmVycywgdGVybWluYXRpbmcgcmVzb3VyY2VzIChwYWdlcykgb2YgdGhlIHBvb2wsIHBvb2wgaXRzZWxmLCBhbmQgY2xvc2luZ1xyXG4gKiB0aGUgYnJvd3Nlci5cclxuICpcclxuICogQGZ1bmN0aW9uIHNodXRkb3duQ2xlYW5VcFxyXG4gKlxyXG4gKiBAcGFyYW0ge251bWJlcn0gW2V4aXRDb2RlPTBdIC0gVGhlIGV4aXQgY29kZSB0byB1c2Ugd2l0aCBgcHJvY2Vzcy5leGl0KClgLlxyXG4gKiBUaGUgZGVmYXVsdCB2YWx1ZSBpcyBgMGAuXHJcbiAqL1xyXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gc2h1dGRvd25DbGVhblVwKGV4aXRDb2RlID0gMCkge1xyXG4gIC8vIEF3YWl0IGZyZWVpbmcgYWxsIHJlc291cmNlc1xyXG4gIGF3YWl0IFByb21pc2UuYWxsU2V0dGxlZChbXHJcbiAgICAvLyBDbGVhciBhbGwgb25nb2luZyBpbnRlcnZhbHNcclxuICAgIGNsZWFyQWxsVGltZXJzKCksXHJcblxyXG4gICAgLy8gR2V0IGF2YWlsYWJsZSBzZXJ2ZXIgaW5zdGFuY2VzIChIVFRQL0hUVFBTKSBhbmQgY2xvc2UgdGhlbVxyXG4gICAgY2xvc2VTZXJ2ZXJzKCksXHJcblxyXG4gICAgLy8gQ2xvc2UgYW4gYWN0aXZlIHBvb2wgYWxvbmcgd2l0aCBpdHMgd29ya2VycyBhbmQgdGhlIGJyb3dzZXIgaW5zdGFuY2VcclxuICAgIGtpbGxQb29sKClcclxuICBdKTtcclxuXHJcbiAgLy8gRXhpdCBwcm9jZXNzIHdpdGggYSBjb3JyZWN0IGNvZGVcclxuICBwcm9jZXNzLmV4aXQoZXhpdENvZGUpO1xyXG59XHJcblxyXG5leHBvcnQgZGVmYXVsdCB7XHJcbiAgc2h1dGRvd25DbGVhblVwXHJcbn07XHJcbiIsIi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXHJcblxyXG5IaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXJcclxuXHJcbkNvcHlyaWdodCAoYykgMjAxNi0yMDI1LCBIaWdoc29mdFxyXG5cclxuTGljZW5jZWQgdW5kZXIgdGhlIE1JVCBsaWNlbmNlLlxyXG5cclxuQWRkaXRpb25hbGx5IGEgdmFsaWQgSGlnaGNoYXJ0cyBsaWNlbnNlIGlzIHJlcXVpcmVkIGZvciB1c2UuXHJcblxyXG5TZWUgTElDRU5TRSBmaWxlIGluIHJvb3QgZm9yIGRldGFpbHMuXHJcblxyXG4qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xyXG5cclxuLyoqXHJcbiAqIEBvdmVydmlldyBDb3JlIG1vZHVsZSBmb3IgaW5pdGlhbGl6aW5nIGFuZCBtYW5hZ2luZyB0aGUgSGlnaGNoYXJ0cyBFeHBvcnRcclxuICogU2VydmVyLiBQcm92aWRlcyBmdW5jdGlvbmFsaXRpZXMgZm9yIGNvbmZpZ3VyaW5nIGV4cG9ydHMsIHNldHRpbmcgdXAgc2VydmVyXHJcbiAqIG9wZXJhdGlvbnMsIGxvZ2dpbmcsIHNjcmlwdHMgY2FjaGluZywgcmVzb3VyY2UgcG9vbGluZywgYW5kIGdyYWNlZnVsIHByb2Nlc3NcclxuICogY2xlYW51cC5cclxuICovXHJcblxyXG5pbXBvcnQgJ2NvbG9ycyc7XHJcblxyXG5pbXBvcnQgeyBjaGVja0FuZFVwZGF0ZUNhY2hlIH0gZnJvbSAnLi9jYWNoZS5qcyc7XHJcbmltcG9ydCB7XHJcbiAgc2luZ2xlRXhwb3J0LFxyXG4gIGJhdGNoRXhwb3J0LFxyXG4gIHN0YXJ0RXhwb3J0LFxyXG4gIHNldEFsbG93Q29kZUV4ZWN1dGlvblxyXG59IGZyb20gJy4vY2hhcnQuanMnO1xyXG5pbXBvcnQge1xyXG4gIGdldE9wdGlvbnMsXHJcbiAgdXBkYXRlT3B0aW9ucyxcclxuICBtYXBUb05ld09wdGlvbnMsXHJcbiAgdmFsaWRhdGVPcHRpb24sXHJcbiAgdmFsaWRhdGVPcHRpb25zXHJcbn0gZnJvbSAnLi9jb25maWcuanMnO1xyXG5pbXBvcnQge1xyXG4gIGxvZyxcclxuICBsb2dXaXRoU3RhY2ssXHJcbiAgbG9nWm9kSXNzdWVzLFxyXG4gIGluaXRMb2dnaW5nLFxyXG4gIGVuYWJsZUNvbnNvbGVMb2dnaW5nLFxyXG4gIGVuYWJsZUZpbGVMb2dnaW5nLFxyXG4gIHNldExvZ0xldmVsXHJcbn0gZnJvbSAnLi9sb2dnZXIuanMnO1xyXG5pbXBvcnQgeyBpbml0UG9vbCwga2lsbFBvb2wgfSBmcm9tICcuL3Bvb2wuanMnO1xyXG5pbXBvcnQgeyBzaHV0ZG93bkNsZWFuVXAgfSBmcm9tICcuL3Jlc291cmNlUmVsZWFzZS5qcyc7XHJcblxyXG5pbXBvcnQgc2VydmVyIGZyb20gJy4vc2VydmVyL3NlcnZlci5qcyc7XHJcblxyXG4vKipcclxuICogSW5pdGlhbGl6ZXMgdGhlIGV4cG9ydCBwcm9jZXNzLiBUYXNrcyBzdWNoIGFzIGNvbmZpZ3VyaW5nIGxvZ2dpbmcsIGNoZWNraW5nXHJcbiAqIHRoZSBjYWNoZSBhbmQgc291cmNlcywgYW5kIGluaXRpYWxpemluZyB0aGUgcmVzb3VyY2UgcG9vbCBvY2N1ciBkdXJpbmcgdGhpc1xyXG4gKiBzdGFnZS5cclxuICpcclxuICogVGhpcyBmdW5jdGlvbiBtdXN0IGJlIGNhbGxlZCBiZWZvcmUgYXR0ZW1wdGluZyB0byBleHBvcnQgY2hhcnRzIG9yIHNldFxyXG4gKiB1cCBhIHNlcnZlci5cclxuICpcclxuICogQGFzeW5jXHJcbiAqIEBmdW5jdGlvbiBpbml0RXhwb3J0XHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBpbml0T3B0aW9ucyAtIFRoZSBgaW5pdE9wdGlvbnNgIG9iamVjdCwgd2hpY2ggbWF5XHJcbiAqIGJlIGEgcGFydGlhbCBvciBjb21wbGV0ZSBzZXQgb2Ygb3B0aW9ucy4gSWYgdGhlIG9wdGlvbnMgYXJlIHBhcnRpYWwsIG1pc3NpbmdcclxuICogdmFsdWVzIHdpbGwgZGVmYXVsdCB0byB0aGUgY3VycmVudCBnbG9iYWwgY29uZmlndXJhdGlvbi5cclxuICovXHJcbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBpbml0RXhwb3J0KGluaXRPcHRpb25zKSB7XHJcbiAgLy8gSW5pdCwgdmFsaWRhdGUgYW5kIHVwZGF0ZSB0aGUgb3B0aW9ucyBvYmplY3RcclxuICBjb25zdCBvcHRpb25zID0gdXBkYXRlT3B0aW9ucyhpbml0T3B0aW9ucyk7XHJcblxyXG4gIC8vIFNldCB0aGUgYGFsbG93Q29kZUV4ZWN1dGlvbmAgcGVyIGV4cG9ydCBtb2R1bGUgc2NvcGVcclxuICBzZXRBbGxvd0NvZGVFeGVjdXRpb24ob3B0aW9ucy5jdXN0b21Mb2dpYy5hbGxvd0NvZGVFeGVjdXRpb24pO1xyXG5cclxuICAvLyBJbml0IHRoZSBsb2dnaW5nXHJcbiAgaW5pdExvZ2dpbmcob3B0aW9ucy5sb2dnaW5nKTtcclxuXHJcbiAgLy8gQXR0YWNoIHByb2Nlc3MnIGV4aXQgbGlzdGVuZXJzXHJcbiAgaWYgKG9wdGlvbnMub3RoZXIubGlzdGVuVG9Qcm9jZXNzRXhpdHMpIHtcclxuICAgIF9hdHRhY2hQcm9jZXNzRXhpdExpc3RlbmVycygpO1xyXG4gIH1cclxuXHJcbiAgLy8gQ2hlY2sgaWYgY2FjaGUgbmVlZHMgdG8gYmUgdXBkYXRlZFxyXG4gIGF3YWl0IGNoZWNrQW5kVXBkYXRlQ2FjaGUob3B0aW9ucy5oaWdoY2hhcnRzLCBvcHRpb25zLnNlcnZlci5wcm94eSk7XHJcblxyXG4gIC8vIEluaXQgdGhlIHBvb2xcclxuICBhd2FpdCBpbml0UG9vbChvcHRpb25zLnBvb2wsIG9wdGlvbnMucHVwcGV0ZWVyLmFyZ3MpO1xyXG59XHJcblxyXG4vKipcclxuICogQXR0YWNoZXMgZXhpdCBsaXN0ZW5lcnMgdG8gdGhlIHByb2Nlc3MsIGVuc3VyaW5nIHByb3BlciBjbGVhbnVwIG9mIHJlc291cmNlc1xyXG4gKiBhbmQgdGVybWluYXRpb24gb24gZXhpdCBzaWduYWxzLiBIYW5kbGVzICdleGl0JywgJ1NJR0lOVCcsICdTSUdURVJNJ1xyXG4gKiBhbmQgJ3VuY2F1Z2h0RXhjZXB0aW9uJyBldmVudHMuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBfYXR0YWNoUHJvY2Vzc0V4aXRMaXN0ZW5lcnNcclxuICovXHJcbmZ1bmN0aW9uIF9hdHRhY2hQcm9jZXNzRXhpdExpc3RlbmVycygpIHtcclxuICBsb2coMywgJ1twcm9jZXNzXSBBdHRhY2hpbmcgZXhpdCBsaXN0ZW5lcnMgdG8gdGhlIHByb2Nlc3MuJyk7XHJcblxyXG4gIC8vIEhhbmRsZXIgZm9yIHRoZSAnZXhpdCdcclxuICBwcm9jZXNzLm9uKCdleGl0JywgKGNvZGUpID0+IHtcclxuICAgIGxvZyg0LCBgW3Byb2Nlc3NdIFByb2Nlc3MgZXhpdGVkIHdpdGggY29kZSAke2NvZGV9LmApO1xyXG4gIH0pO1xyXG5cclxuICAvLyBIYW5kbGVyIGZvciB0aGUgJ1NJR0lOVCdcclxuICBwcm9jZXNzLm9uKCdTSUdJTlQnLCBhc3luYyAobmFtZSwgY29kZSkgPT4ge1xyXG4gICAgbG9nKDQsIGBbcHJvY2Vzc10gVGhlICR7bmFtZX0gZXZlbnQgd2l0aCBjb2RlOiAke2NvZGV9LmApO1xyXG4gICAgYXdhaXQgc2h1dGRvd25DbGVhblVwKCk7XHJcbiAgfSk7XHJcblxyXG4gIC8vIEhhbmRsZXIgZm9yIHRoZSAnU0lHVEVSTSdcclxuICBwcm9jZXNzLm9uKCdTSUdURVJNJywgYXN5bmMgKG5hbWUsIGNvZGUpID0+IHtcclxuICAgIGxvZyg0LCBgW3Byb2Nlc3NdIFRoZSAke25hbWV9IGV2ZW50IHdpdGggY29kZTogJHtjb2RlfS5gKTtcclxuICAgIGF3YWl0IHNodXRkb3duQ2xlYW5VcCgpO1xyXG4gIH0pO1xyXG5cclxuICAvLyBIYW5kbGVyIGZvciB0aGUgJ1NJR0hVUCdcclxuICBwcm9jZXNzLm9uKCdTSUdIVVAnLCBhc3luYyAobmFtZSwgY29kZSkgPT4ge1xyXG4gICAgbG9nKDQsIGBbcHJvY2Vzc10gVGhlICR7bmFtZX0gZXZlbnQgd2l0aCBjb2RlOiAke2NvZGV9LmApO1xyXG4gICAgYXdhaXQgc2h1dGRvd25DbGVhblVwKCk7XHJcbiAgfSk7XHJcblxyXG4gIC8vIEhhbmRsZXIgZm9yIHRoZSAndW5jYXVnaHRFeGNlcHRpb24nXHJcbiAgcHJvY2Vzcy5vbigndW5jYXVnaHRFeGNlcHRpb24nLCBhc3luYyAoZXJyb3IsIG5hbWUpID0+IHtcclxuICAgIGxvZ1dpdGhTdGFjaygxLCBlcnJvciwgYFtwcm9jZXNzXSBUaGUgJHtuYW1lfSBlcnJvci5gKTtcclxuICAgIGF3YWl0IHNodXRkb3duQ2xlYW5VcCgxKTtcclxuICB9KTtcclxufVxyXG5cclxuZXhwb3J0IGRlZmF1bHQge1xyXG4gIC8vIFNlcnZlclxyXG4gIC4uLnNlcnZlcixcclxuXHJcbiAgLy8gT3B0aW9uc1xyXG4gIGdldE9wdGlvbnMsXHJcbiAgdXBkYXRlT3B0aW9ucyxcclxuICBtYXBUb05ld09wdGlvbnMsXHJcblxyXG4gIC8vIFZhbGlkYXRpb25cclxuICB2YWxpZGF0ZU9wdGlvbixcclxuICB2YWxpZGF0ZU9wdGlvbnMsXHJcblxyXG4gIC8vIEV4cG9ydGluZ1xyXG4gIGluaXRFeHBvcnQsXHJcbiAgc2luZ2xlRXhwb3J0LFxyXG4gIGJhdGNoRXhwb3J0LFxyXG4gIHN0YXJ0RXhwb3J0LFxyXG5cclxuICAvLyBSZWxlYXNlXHJcbiAga2lsbFBvb2wsXHJcbiAgc2h1dGRvd25DbGVhblVwLFxyXG5cclxuICAvLyBMb2dzXHJcbiAgbG9nLFxyXG4gIGxvZ1dpdGhTdGFjayxcclxuICBsb2dab2RJc3N1ZXMsXHJcbiAgc2V0TG9nTGV2ZWw6IGZ1bmN0aW9uIChsZXZlbCkge1xyXG4gICAgLy8gVXBkYXRlIHRoZSBpbnN0YW5jZSBvcHRpb25zIG9iamVjdFxyXG4gICAgY29uc3Qgb3B0aW9ucyA9IHVwZGF0ZU9wdGlvbnMoe1xyXG4gICAgICBsb2dnaW5nOiB7XHJcbiAgICAgICAgbGV2ZWxcclxuICAgICAgfVxyXG4gICAgfSk7XHJcblxyXG4gICAgLy8gQ2FsbCB0aGUgZnVuY3Rpb25cclxuICAgIHNldExvZ0xldmVsKG9wdGlvbnMubG9nZ2luZy5sZXZlbCk7XHJcbiAgfSxcclxuICBlbmFibGVDb25zb2xlTG9nZ2luZzogZnVuY3Rpb24gKHRvQ29uc29sZSkge1xyXG4gICAgLy8gVXBkYXRlIHRoZSBpbnN0YW5jZSBvcHRpb25zIG9iamVjdFxyXG4gICAgY29uc3Qgb3B0aW9ucyA9IHVwZGF0ZU9wdGlvbnMoe1xyXG4gICAgICBsb2dnaW5nOiB7XHJcbiAgICAgICAgdG9Db25zb2xlXHJcbiAgICAgIH1cclxuICAgIH0pO1xyXG5cclxuICAgIC8vIENhbGwgdGhlIGZ1bmN0aW9uXHJcbiAgICBlbmFibGVDb25zb2xlTG9nZ2luZyhvcHRpb25zLmxvZ2dpbmcudG9Db25zb2xlKTtcclxuICB9LFxyXG4gIGVuYWJsZUZpbGVMb2dnaW5nOiBmdW5jdGlvbiAoZGVzdCwgZmlsZSwgdG9GaWxlKSB7XHJcbiAgICAvLyBVcGRhdGUgdGhlIGluc3RhbmNlIG9wdGlvbnMgb2JqZWN0XHJcbiAgICBjb25zdCBvcHRpb25zID0gdXBkYXRlT3B0aW9ucyh7XHJcbiAgICAgIGxvZ2dpbmc6IHtcclxuICAgICAgICBkZXN0LFxyXG4gICAgICAgIGZpbGUsXHJcbiAgICAgICAgdG9GaWxlXHJcbiAgICAgIH1cclxuICAgIH0pO1xyXG5cclxuICAgIC8vIENhbGwgdGhlIGZ1bmN0aW9uXHJcbiAgICBlbmFibGVGaWxlTG9nZ2luZyhcclxuICAgICAgb3B0aW9ucy5sb2dnaW5nLmRlc3QsXHJcbiAgICAgIG9wdGlvbnMubG9nZ2luZy5maWxlLFxyXG4gICAgICBvcHRpb25zLmxvZ2dpbmcudG9GaWxlXHJcbiAgICApO1xyXG4gIH1cclxufTtcclxuIl0sIm5hbWVzIjpbIl9fZGlybmFtZSIsImZpbGVVUkxUb1BhdGgiLCJVUkwiLCJkb2N1bWVudCIsInJlcXVpcmUiLCJwYXRoVG9GaWxlVVJMIiwiX19maWxlbmFtZSIsImhyZWYiLCJfZG9jdW1lbnRDdXJyZW50U2NyaXB0IiwidGFnTmFtZSIsInRvVXBwZXJDYXNlIiwic3JjIiwiYmFzZVVSSSIsImRlZXBDb3B5Iiwib2JqQXJyIiwib2JqQXJyQ29weSIsIkFycmF5IiwiaXNBcnJheSIsImtleSIsIk9iamVjdCIsInByb3RvdHlwZSIsImhhc093blByb3BlcnR5IiwiY2FsbCIsImZpeENvbnN0ciIsImNvbnN0ciIsImZpeGVkQ29uc3RyIiwidG9Mb3dlckNhc2UiLCJyZXBsYWNlIiwiaW5jbHVkZXMiLCJmaXhPdXRmaWxlIiwidHlwZSIsIm91dGZpbGUiLCJnZXRBYnNvbHV0ZVBhdGgiLCJzcGxpdCIsInNoaWZ0IiwiZml4VHlwZSIsIm1pbWVUeXBlcyIsImZvcm1hdHMiLCJ2YWx1ZXMiLCJvdXRUeXBlIiwicG9wIiwiZmluZCIsInQiLCJwYXRoIiwiaXNBYnNvbHV0ZSIsIm5vcm1hbGl6ZSIsInJlc29sdmUiLCJnZXRCYXNlNjQiLCJpbnB1dCIsIkJ1ZmZlciIsImZyb20iLCJ0b1N0cmluZyIsImdldE5ld0RhdGUiLCJEYXRlIiwidHJpbSIsImdldE5ld0RhdGVUaW1lIiwiZ2V0VGltZSIsImlzT2JqZWN0IiwiaXRlbSIsImlzT2JqZWN0RW1wdHkiLCJrZXlzIiwibGVuZ3RoIiwiaXNQcml2YXRlUmFuZ2VVcmxGb3VuZCIsInNvbWUiLCJwYXR0ZXJuIiwidGVzdCIsIm1lYXN1cmVUaW1lIiwic3RhcnQiLCJwcm9jZXNzIiwiaHJ0aW1lIiwiYmlnaW50IiwiTnVtYmVyIiwicm91bmROdW1iZXIiLCJ2YWx1ZSIsInByZWNpc2lvbiIsIm11bHRpcGxpZXIiLCJNYXRoIiwicG93Iiwicm91bmQiLCJ3cmFwQXJvdW5kIiwiY3VzdG9tQ29kZSIsImFsbG93RmlsZVJlc291cmNlcyIsImlzQ2FsbGJhY2siLCJlbmRzV2l0aCIsInJlYWRGaWxlU3luYyIsInN0YXJ0c1dpdGgiLCJjb2xvcnMiLCJsb2dnaW5nIiwidG9Db25zb2xlIiwidG9GaWxlIiwicGF0aENyZWF0ZWQiLCJwYXRoVG9Mb2ciLCJsZXZlbHNEZXNjIiwidGl0bGUiLCJjb2xvciIsImxvZyIsImFyZ3MiLCJuZXdMZXZlbCIsInRleHRzIiwibGV2ZWwiLCJwcmVmaXgiLCJfbG9nVG9GaWxlIiwiY29uc29sZSIsImFwcGx5IiwidW5kZWZpbmVkIiwiY29uY2F0IiwibG9nV2l0aFN0YWNrIiwiZXJyb3IiLCJjdXN0b21NZXNzYWdlIiwibWFpbk1lc3NhZ2UiLCJtZXNzYWdlIiwic3RhY2tNZXNzYWdlIiwic3RhY2siLCJwdXNoIiwibG9nWm9kSXNzdWVzIiwiaXNzdWVzIiwibWFwIiwiaXNzdWUiLCJqb2luIiwiaW5pdExvZ2dpbmciLCJsb2dnaW5nT3B0aW9ucyIsImRlc3QiLCJmaWxlIiwic2V0TG9nTGV2ZWwiLCJlbmFibGVDb25zb2xlTG9nZ2luZyIsImVuYWJsZUZpbGVMb2dnaW5nIiwiaXNJbnRlZ2VyIiwiZXhpc3RzU3luYyIsIm1rZGlyU3luYyIsImFwcGVuZEZpbGUiLCJkZWZhdWx0Q29uZmlnIiwicHVwcGV0ZWVyIiwidHlwZXMiLCJlbnZMaW5rIiwiY2xpTmFtZSIsImRlc2NyaXB0aW9uIiwicHJvbXB0T3B0aW9ucyIsInNlcGFyYXRvciIsImhpZ2hjaGFydHMiLCJ2ZXJzaW9uIiwiY2RuVXJsIiwiZm9yY2VGZXRjaCIsImNhY2hlUGF0aCIsImNvcmVTY3JpcHRzIiwiaW5zdHJ1Y3Rpb25zIiwibW9kdWxlU2NyaXB0cyIsImluZGljYXRvclNjcmlwdHMiLCJjdXN0b21TY3JpcHRzIiwiZXhwb3J0IiwiaW5maWxlIiwiaW5zdHIiLCJvcHRpb25zIiwic3ZnIiwiYmF0Y2giLCJoaW50IiwiY2hvaWNlcyIsImI2NCIsIm5vRG93bmxvYWQiLCJoZWlnaHQiLCJ3aWR0aCIsInNjYWxlIiwiZGVmYXVsdEhlaWdodCIsImRlZmF1bHRXaWR0aCIsImRlZmF1bHRTY2FsZSIsIm1pbiIsIm1heCIsImdsb2JhbE9wdGlvbnMiLCJ0aGVtZU9wdGlvbnMiLCJyYXN0ZXJpemF0aW9uVGltZW91dCIsImN1c3RvbUxvZ2ljIiwiYWxsb3dDb2RlRXhlY3V0aW9uIiwiY2FsbGJhY2siLCJyZXNvdXJjZXMiLCJsb2FkQ29uZmlnIiwibGVnYWN5TmFtZSIsImNyZWF0ZUNvbmZpZyIsInNlcnZlciIsImVuYWJsZSIsImhvc3QiLCJwb3J0IiwidXBsb2FkTGltaXQiLCJiZW5jaG1hcmtpbmciLCJwcm94eSIsInRpbWVvdXQiLCJyYXRlTGltaXRpbmciLCJtYXhSZXF1ZXN0cyIsIndpbmRvdyIsImRlbGF5IiwidHJ1c3RQcm94eSIsInNraXBLZXkiLCJza2lwVG9rZW4iLCJzc2wiLCJmb3JjZSIsImNlcnRQYXRoIiwicG9vbCIsIm1pbldvcmtlcnMiLCJtYXhXb3JrZXJzIiwid29ya0xpbWl0IiwiYWNxdWlyZVRpbWVvdXQiLCJjcmVhdGVUaW1lb3V0IiwiZGVzdHJveVRpbWVvdXQiLCJpZGxlVGltZW91dCIsImNyZWF0ZVJldHJ5SW50ZXJ2YWwiLCJyZWFwZXJJbnRlcnZhbCIsInVpIiwicm91dGUiLCJvdGhlciIsIm5vZGVFbnYiLCJsaXN0ZW5Ub1Byb2Nlc3NFeGl0cyIsIm5vTG9nbyIsImhhcmRSZXNldFBhZ2UiLCJicm93c2VyU2hlbGxNb2RlIiwidmFsaWRhdGlvbiIsImRlYnVnIiwiaGVhZGxlc3MiLCJkZXZ0b29scyIsImxpc3RlblRvQ29uc29sZSIsImR1bXBpbyIsInNsb3dNbyIsImRlYnVnZ2luZ1BvcnQiLCJuZXN0ZWRQcm9wcyIsIl9jcmVhdGVOZXN0ZWRQcm9wcyIsImFic29sdXRlUHJvcHMiLCJfY3JlYXRlQWJzb2x1dGVQcm9wcyIsImNvbmZpZyIsInByb3BDaGFpbiIsImZvckVhY2giLCJlbnRyeSIsInN1YnN0cmluZyIsImRvdGVudiIsInoiLCJzZXRFcnJvck1hcCIsIl9jdXN0b21FcnJvck1hcCIsInYiLCJib29sZWFuIiwic3RyaWN0Q2hlY2siLCJ1bmlvbiIsImVudW0iLCJ0cmFuc2Zvcm0iLCJudWxsYWJsZSIsInN0cmluZyIsInJlZmluZSIsInBhcmFtcyIsImVycm9yTWVzc2FnZSIsInN0cmluZ0FycmF5IiwiZmlsdGVyQ2FsbGJhY2siLCJhcnJheVNjaGVtYSIsImFycmF5Iiwic3RyaW5nU2NoZW1hIiwic2xpY2UiLCJ0cmFuc2Zvcm1DYWxsYmFjayIsImZpbHRlciIsInBvc2l0aXZlTnVtIiwibnVtYmVyIiwicG9zaXRpdmUiLCJpc05hTiIsIm5vbk5lZ2F0aXZlTnVtIiwibm9ubmVnYXRpdmUiLCJwcmVmaXhlcyIsImNoYXJ0Q29uZmlnIiwib2JqZWN0IiwicGFzc3Rocm91Z2giLCJhZGRpdGlvbmFsT3B0aW9ucyIsInZhbGlkYXRvcnMiLCJhZG1pblRva2VuIiwiaW5kZXhPZiIsImd0ZSIsImx0ZSIsInRoaXMiLCJvYmplY3RTY2hlbWEiLCJqcyIsImNzcyIsImZpbGVzIiwicGFydGlhbCIsInN0cmluZ1NjaGVtYTEiLCJzdHJpbmdTY2hlbWEyIiwiZW5hYmxlU2VydmVyIiwic2VydmVyQmVuY2htYXJraW5nIiwicHJveHlIb3N0IiwicHJveHlQb3J0IiwicHJveHlUaW1lb3V0IiwiZW5hYmxlUmF0ZUxpbWl0aW5nIiwiZW5hYmxlU3NsIiwic3NsRm9yY2UiLCJzc2xQb3J0Iiwic3NsQ2VydFBhdGgiLCJwb29sQmVuY2htYXJraW5nIiwicmVzb3VyY2VzSW50ZXJ2YWwiLCJsb2dMZXZlbCIsImludCIsImxvZ0ZpbGUiLCJsb2dEZXN0IiwibG9nVG9Db25zb2xlIiwibG9nVG9GaWxlIiwiZW5hYmxlVWkiLCJ1aVJvdXRlIiwiZW5hYmxlRGVidWciLCJyZXF1ZXN0SWQiLCJ1dWlkIiwiUHVwcGV0ZWVyU2NoZW1hIiwiSGlnaGNoYXJ0c1NjaGVtYSIsIkV4cG9ydFNjaGVtYSIsIkN1c3RvbUxvZ2ljU2NoZW1hIiwiUHJveHlTY2hlbWEiLCJSYXRlTGltaXRpbmdTY2hlbWEiLCJTc2xTY2hlbWEiLCJTZXJ2ZXJTY2hlbWEiLCJvcHRpb25hbCIsIlBvb2xTY2hlbWEiLCJMb2dnaW5nU2NoZW1hIiwiVWlTY2hlbWEiLCJPdGhlclNjaGVtYSIsIkRlYnVnU2NoZW1hIiwiU3RyaWN0Q29uZmlnU2NoZW1hIiwiTG9vc2VDb25maWdTY2hlbWEiLCJFbnZTY2hlbWEiLCJQVVBQRVRFRVJfQVJHUyIsIkhJR0hDSEFSVFNfVkVSU0lPTiIsIkhJR0hDSEFSVFNfQ0ROX1VSTCIsIkhJR0hDSEFSVFNfRk9SQ0VfRkVUQ0giLCJISUdIQ0hBUlRTX0NBQ0hFX1BBVEgiLCJISUdIQ0hBUlRTX0FETUlOX1RPS0VOIiwiSElHSENIQVJUU19DT1JFX1NDUklQVFMiLCJISUdIQ0hBUlRTX01PRFVMRV9TQ1JJUFRTIiwiSElHSENIQVJUU19JTkRJQ0FUT1JfU0NSSVBUUyIsIkhJR0hDSEFSVFNfQ1VTVE9NX1NDUklQVFMiLCJFWFBPUlRfSU5GSUxFIiwiRVhQT1JUX0lOU1RSIiwiRVhQT1JUX09QVElPTlMiLCJFWFBPUlRfU1ZHIiwiRVhQT1JUX0JBVENIIiwiRVhQT1JUX09VVEZJTEUiLCJFWFBPUlRfVFlQRSIsIkVYUE9SVF9DT05TVFIiLCJFWFBPUlRfQjY0IiwiRVhQT1JUX05PX0RPV05MT0FEIiwiRVhQT1JUX0hFSUdIVCIsIkVYUE9SVF9XSURUSCIsIkVYUE9SVF9TQ0FMRSIsIkVYUE9SVF9ERUZBVUxUX0hFSUdIVCIsIkVYUE9SVF9ERUZBVUxUX1dJRFRIIiwiRVhQT1JUX0RFRkFVTFRfU0NBTEUiLCJFWFBPUlRfR0xPQkFMX09QVElPTlMiLCJFWFBPUlRfVEhFTUVfT1BUSU9OUyIsIkVYUE9SVF9SQVNURVJJWkFUSU9OX1RJTUVPVVQiLCJDVVNUT01fTE9HSUNfQUxMT1dfQ09ERV9FWEVDVVRJT04iLCJDVVNUT01fTE9HSUNfQUxMT1dfRklMRV9SRVNPVVJDRVMiLCJDVVNUT01fTE9HSUNfQ1VTVE9NX0NPREUiLCJDVVNUT01fTE9HSUNfQ0FMTEJBQ0siLCJDVVNUT01fTE9HSUNfUkVTT1VSQ0VTIiwiQ1VTVE9NX0xPR0lDX0xPQURfQ09ORklHIiwiQ1VTVE9NX0xPR0lDX0NSRUFURV9DT05GSUciLCJTRVJWRVJfRU5BQkxFIiwiU0VSVkVSX0hPU1QiLCJTRVJWRVJfUE9SVCIsIlNFUlZFUl9VUExPQURfTElNSVQiLCJTRVJWRVJfQkVOQ0hNQVJLSU5HIiwiU0VSVkVSX1BST1hZX0hPU1QiLCJTRVJWRVJfUFJPWFlfUE9SVCIsIlNFUlZFUl9QUk9YWV9USU1FT1VUIiwiU0VSVkVSX1JBVEVfTElNSVRJTkdfRU5BQkxFIiwiU0VSVkVSX1JBVEVfTElNSVRJTkdfTUFYX1JFUVVFU1RTIiwiU0VSVkVSX1JBVEVfTElNSVRJTkdfV0lORE9XIiwiU0VSVkVSX1JBVEVfTElNSVRJTkdfREVMQVkiLCJTRVJWRVJfUkFURV9MSU1JVElOR19UUlVTVF9QUk9YWSIsIlNFUlZFUl9SQVRFX0xJTUlUSU5HX1NLSVBfS0VZIiwiU0VSVkVSX1JBVEVfTElNSVRJTkdfU0tJUF9UT0tFTiIsIlNFUlZFUl9TU0xfRU5BQkxFIiwiU0VSVkVSX1NTTF9GT1JDRSIsIlNFUlZFUl9TU0xfUE9SVCIsIlNFUlZFUl9TU0xfQ0VSVF9QQVRIIiwiUE9PTF9NSU5fV09SS0VSUyIsIlBPT0xfTUFYX1dPUktFUlMiLCJQT09MX1dPUktfTElNSVQiLCJQT09MX0FDUVVJUkVfVElNRU9VVCIsIlBPT0xfQ1JFQVRFX1RJTUVPVVQiLCJQT09MX0RFU1RST1lfVElNRU9VVCIsIlBPT0xfSURMRV9USU1FT1VUIiwiUE9PTF9DUkVBVEVfUkVUUllfSU5URVJWQUwiLCJQT09MX1JFQVBFUl9JTlRFUlZBTCIsIlBPT0xfQkVOQ0hNQVJLSU5HIiwiTE9HR0lOR19MRVZFTCIsIkxPR0dJTkdfRklMRSIsIkxPR0dJTkdfREVTVCIsIkxPR0dJTkdfVE9fQ09OU09MRSIsIkxPR0dJTkdfVE9fRklMRSIsIlVJX0VOQUJMRSIsIlVJX1JPVVRFIiwiT1RIRVJfTk9ERV9FTlYiLCJPVEhFUl9MSVNURU5fVE9fUFJPQ0VTU19FWElUUyIsIk9USEVSX05PX0xPR08iLCJPVEhFUl9IQVJEX1JFU0VUX1BBR0UiLCJPVEhFUl9CUk9XU0VSX1NIRUxMX01PREUiLCJPVEhFUl9WQUxJREFUSU9OIiwiREVCVUdfRU5BQkxFIiwiREVCVUdfSEVBRExFU1MiLCJERUJVR19ERVZUT09MUyIsIkRFQlVHX0xJU1RFTl9UT19DT05TT0xFIiwiREVCVUdfRFVNUElPIiwiREVCVUdfU0xPV19NTyIsIkRFQlVHX0RFQlVHR0lOR19QT1JUIiwiZW52cyIsInBhcnNlIiwiZW52Iiwic3RyaWN0VmFsaWRhdGUiLCJjb25maWdPcHRpb25zIiwibG9vc2VWYWxpZGF0ZSIsImNvbnRleHQiLCJwcm9wZXJ0eU5hbWUiLCJwcm9wZXJ0eUluZm8iLCJjb2RlIiwiWm9kSXNzdWVDb2RlIiwiaW52YWxpZF90eXBlIiwicmVjZWl2ZWQiLCJab2RQYXJzZWRUeXBlIiwiZGVmYXVsdEVycm9yIiwiY3VzdG9tIiwiZGF0YSIsImludmFsaWRfdW5pb24iLCJ1bmlvbkVycm9ycyIsImluZGV4IiwiRXhwb3J0RXJyb3IiLCJFcnJvciIsImNvbnN0cnVjdG9yIiwic3RhdHVzQ29kZSIsInN1cGVyIiwic2V0U3RhdHVzIiwic2V0RXJyb3IiLCJuYW1lIiwiX2luaXRPcHRpb25zIiwiZ2V0T3B0aW9ucyIsImdldENvcHkiLCJ1cGRhdGVPcHRpb25zIiwibmV3T3B0aW9ucyIsIl9tZXJnZU9wdGlvbnMiLCJ2YWxpZGF0ZU9wdGlvbnMiLCJtYXBUb05ld09wdGlvbnMiLCJvbGRPcHRpb25zIiwiZW50cmllcyIsInByb3BlcnRpZXNDaGFpbiIsInJlZHVjZSIsIm9iaiIsInByb3AiLCJ2YWxpZGF0ZU9wdGlvbiIsImNvbmZpZ09wdGlvbiIsImlzQWxsb3dlZENvbmZpZyIsImFsbG93RnVuY3Rpb25zIiwib2JqZWN0Q29uZmlnIiwiZXZhbCIsIkpTT04iLCJzdHJpbmdpZmllZE9wdGlvbnMiLCJfb3B0aW9uc1N0cmluZ2lmeSIsInBhcnNlZE9wdGlvbnMiLCJfIiwib3JpZ2luYWxPcHRpb25zIiwic3RyaW5naWZ5RnVuY3Rpb25zIiwic3RyaW5naWZ5IiwicmVwbGFjZUFsbCIsImFzeW5jIiwiZmV0Y2giLCJ1cmwiLCJyZXF1ZXN0T3B0aW9ucyIsIlByb21pc2UiLCJyZWplY3QiLCJfZ2V0UHJvdG9jb2xNb2R1bGUiLCJnZXQiLCJyZXNwb25zZSIsInJlc3BvbnNlRGF0YSIsIm9uIiwiY2h1bmsiLCJ0ZXh0IiwiaHR0cHMiLCJodHRwIiwiY2FjaGUiLCJhY3RpdmVNYW5pZmVzdCIsInNvdXJjZXMiLCJoY1ZlcnNpb24iLCJjaGVja0FuZFVwZGF0ZUNhY2hlIiwiaGlnaGNoYXJ0c09wdGlvbnMiLCJzZXJ2ZXJQcm94eU9wdGlvbnMiLCJmZXRjaGVkTW9kdWxlcyIsImdldENhY2hlUGF0aCIsIm1hbmlmZXN0UGF0aCIsInNvdXJjZVBhdGgiLCJyZWN1cnNpdmUiLCJfdXBkYXRlQ2FjaGUiLCJyZXF1ZXN0VXBkYXRlIiwibWFuaWZlc3QiLCJtb2R1bGVzIiwibW9kdWxlTWFwIiwibSIsIm51bWJlck9mTW9kdWxlcyIsIm1vZHVsZU5hbWUiLCJleHRyYWN0VmVyc2lvbiIsIl9zYXZlQ29uZmlnVG9NYW5pZmVzdCIsImdldEhpZ2hjaGFydHNWZXJzaW9uIiwidXBkYXRlSGlnaGNoYXJ0c1ZlcnNpb24iLCJuZXdWZXJzaW9uIiwiY2FjaGVTb3VyY2VzIiwiZXh0cmFjdE1vZHVsZU5hbWUiLCJzY3JpcHRQYXRoIiwiX2ZldGNoQW5kUHJvY2Vzc1NjcmlwdCIsInNjcmlwdCIsInNob3VsZFRocm93RXJyb3IiLCJuZXdNYW5pZmVzdCIsIndyaXRlRmlsZVN5bmMiLCJfZmV0Y2hTY3JpcHRzIiwicHJveHlBZ2VudCIsIkh0dHBzUHJveHlBZ2VudCIsImFnZW50IiwiYWxsRmV0Y2hQcm9taXNlcyIsImFsbCIsImMiLCJpIiwic2V0dXBIaWdoY2hhcnRzIiwiSGlnaGNoYXJ0cyIsImFuaW1PYmplY3QiLCJkdXJhdGlvbiIsImNyZWF0ZUNoYXJ0IiwiZXhwb3J0T3B0aW9ucyIsImN1c3RvbUxvZ2ljT3B0aW9ucyIsInNldE9wdGlvbnMiLCJtZXJnZSIsIndyYXAiLCJzZXRPcHRpb25zT2JqIiwiaXNSZW5kZXJDb21wbGV0ZSIsIkNoYXJ0IiwicHJvY2VlZCIsInVzZXJPcHRpb25zIiwiY2IiLCJleHBvcnRpbmciLCJlbmFibGVkIiwicGxvdE9wdGlvbnMiLCJzZXJpZXMiLCJsYWJlbCIsInRvb2x0aXAiLCJhbmltYXRpb24iLCJvbkhpZ2hjaGFydHNSZW5kZXIiLCJhZGRFdmVudCIsIlNlcmllcyIsImNoYXJ0IiwiRnVuY3Rpb24iLCJmaW5hbE9wdGlvbnMiLCJmaW5hbENhbGxiYWNrIiwiZGVmYXVsdE9wdGlvbnMiLCJ0ZW1wbGF0ZSIsImJyb3dzZXIiLCJjcmVhdGVCcm93c2VyIiwicHVwcGV0ZWVyQXJncyIsImVuYWJsZWREZWJ1ZyIsImRlYnVnT3B0aW9ucyIsImxhdW5jaE9wdGlvbnMiLCJ1c2VyRGF0YURpciIsImhhbmRsZVNJR0lOVCIsImhhbmRsZVNJR1RFUk0iLCJoYW5kbGVTSUdIVVAiLCJ3YWl0Rm9ySW5pdGlhbFBhZ2UiLCJkZWZhdWx0Vmlld3BvcnQiLCJ0cnlDb3VudCIsIm9wZW4iLCJsYXVuY2giLCJzZXRUaW1lb3V0IiwiY2xvc2VCcm93c2VyIiwiY29ubmVjdGVkIiwiY2xvc2UiLCJuZXdQYWdlIiwicG9vbFJlc291cmNlIiwicGFnZSIsInNldENhY2hlRW5hYmxlZCIsIl9zZXRQYWdlQ29udGVudCIsIl9zZXRQYWdlRXZlbnRzIiwiaXNDbG9zZWQiLCJjbGVhclBhZ2UiLCJoYXJkUmVzZXQiLCJnb3RvIiwid2FpdFVudGlsIiwiZXZhbHVhdGUiLCJib2R5IiwiaW5uZXJIVE1MIiwiaWQiLCJ3b3JrQ291bnQiLCJhZGRQYWdlUmVzb3VyY2VzIiwiaW5qZWN0ZWRSZXNvdXJjZXMiLCJpbmplY3RlZEpzIiwiY29udGVudCIsImlzTG9jYWwiLCJqc1Jlc291cmNlIiwiYWRkU2NyaXB0VGFnIiwiaW5qZWN0ZWRDc3MiLCJjc3NJbXBvcnRzIiwibWF0Y2giLCJjc3NJbXBvcnRQYXRoIiwiY3NzUmVzb3VyY2UiLCJhZGRTdHlsZVRhZyIsImNsZWFyUGFnZVJlc291cmNlcyIsInJlc291cmNlIiwiZGlzcG9zZSIsIm9sZENoYXJ0cyIsImNoYXJ0cyIsIm9sZENoYXJ0IiwiZGVzdHJveSIsInNjcmlwdHNUb1JlbW92ZSIsImdldEVsZW1lbnRzQnlUYWdOYW1lIiwic3R5bGVzVG9SZW1vdmUiLCJsaW5rc1RvUmVtb3ZlIiwiZWxlbWVudCIsInJlbW92ZSIsInNldENvbnRlbnQiLCJjc3NUZW1wbGF0ZSIsInN2Z1RlbXBsYXRlIiwicHVwcGV0ZWVyRXhwb3J0IiwiaXNTVkciLCJzaXplIiwic3ZnRWxlbWVudCIsInF1ZXJ5U2VsZWN0b3IiLCJjaGFydEhlaWdodCIsImJhc2VWYWwiLCJjaGFydFdpZHRoIiwic3R5bGUiLCJ6b29tIiwibWFyZ2luIiwicGFyc2VGbG9hdCIsIngiLCJ5IiwiX2dldENsaXBSZWdpb24iLCJ2aWV3cG9ydEhlaWdodCIsImFicyIsImNlaWwiLCJ2aWV3cG9ydFdpZHRoIiwicmVzdWx0Iiwic2V0Vmlld3BvcnQiLCJkZXZpY2VTY2FsZUZhY3RvciIsIl9jcmVhdGVTVkciLCJfY3JlYXRlSW1hZ2UiLCJfY3JlYXRlUERGIiwiJGV2YWwiLCJnZXRCb3VuZGluZ0NsaWVudFJlY3QiLCJ0cnVuYyIsIm91dGVySFRNTCIsImNsaXAiLCJyYWNlIiwic2NyZWVuc2hvdCIsImVuY29kaW5nIiwiZnVsbFBhZ2UiLCJvcHRpbWl6ZUZvclNwZWVkIiwiY2FwdHVyZUJleW9uZFZpZXdwb3J0IiwicXVhbGl0eSIsIm9taXRCYWNrZ3JvdW5kIiwiX3Jlc29sdmUiLCJlbXVsYXRlTWVkaWFUeXBlIiwicGRmIiwicG9vbFN0YXRzIiwiZXhwb3J0c0F0dGVtcHRlZCIsImV4cG9ydHNQZXJmb3JtZWQiLCJleHBvcnRzRHJvcHBlZCIsImV4cG9ydHNGcm9tU3ZnIiwiZXhwb3J0c0Zyb21PcHRpb25zIiwiZXhwb3J0c0Zyb21TdmdBdHRlbXB0cyIsImV4cG9ydHNGcm9tT3B0aW9uc0F0dGVtcHRzIiwidGltZVNwZW50IiwidGltZVNwZW50QXZlcmFnZSIsImluaXRQb29sIiwicG9vbE9wdGlvbnMiLCJQb29sIiwiX2ZhY3RvcnkiLCJhY3F1aXJlVGltZW91dE1pbGxpcyIsImNyZWF0ZVRpbWVvdXRNaWxsaXMiLCJkZXN0cm95VGltZW91dE1pbGxpcyIsImlkbGVUaW1lb3V0TWlsbGlzIiwiY3JlYXRlUmV0cnlJbnRlcnZhbE1pbGxpcyIsInJlYXBJbnRlcnZhbE1pbGxpcyIsInByb3BhZ2F0ZUNyZWF0ZUVycm9yIiwiY2xlYXJTdGF0dXMiLCJfZXZlbnRJZCIsImluaXRpYWxSZXNvdXJjZXMiLCJhY3F1aXJlIiwicHJvbWlzZSIsInJlbGVhc2UiLCJraWxsUG9vbCIsIndvcmtlciIsInVzZWQiLCJkZXN0cm95ZWQiLCJwb3N0V29yayIsIndvcmtlckhhbmRsZSIsImdldFBvb2xJbmZvIiwiYWNxdWlyZUNvdW50ZXIiLCJ3b3JrU3RhcnQiLCJleHBvcnRDb3VudGVyIiwiZXhwb3J0VGltZSIsImdldFBvb2xTdGF0cyIsImdldFBvb2xJbmZvSlNPTiIsIm51bVVzZWQiLCJhdmFpbGFibGUiLCJudW1GcmVlIiwiYWxsQ3JlYXRlZCIsInBlbmRpbmdBY3F1aXJlcyIsIm51bVBlbmRpbmdBY3F1aXJlcyIsInBlbmRpbmdDcmVhdGVzIiwibnVtUGVuZGluZ0NyZWF0ZXMiLCJwZW5kaW5nVmFsaWRhdGlvbnMiLCJudW1QZW5kaW5nVmFsaWRhdGlvbnMiLCJwZW5kaW5nRGVzdHJveXMiLCJhYnNvbHV0ZUFsbCIsImNyZWF0ZSIsInJhbmRvbSIsInN0YXJ0RGF0ZSIsInZhbGlkYXRlIiwibWFpbkZyYW1lIiwiZGV0YWNoZWQiLCJyZW1vdmVBbGxMaXN0ZW5lcnMiLCJzYW5pdGl6ZSIsIkpTRE9NIiwiRE9NUHVyaWZ5IiwiQUREX1RBR1MiLCJzaW5nbGVFeHBvcnQiLCJzdGFydEV4cG9ydCIsImJhdGNoRXhwb3J0IiwiYmF0Y2hGdW5jdGlvbnMiLCJwYWlyIiwiYmF0Y2hSZXN1bHRzIiwiYWxsU2V0dGxlZCIsInJlYXNvbiIsImltYWdlT3B0aW9ucyIsImVuZENhbGxiYWNrIiwiZmlsZUNvbnRlbnQiLCJfZXhwb3J0RnJvbVN2ZyIsIl9leHBvcnRGcm9tT3B0aW9ucyIsImdldEFsbG93Q29kZUV4ZWN1dGlvbiIsInNldEFsbG93Q29kZUV4ZWN1dGlvbiIsImlucHV0VG9FeHBvcnQiLCJfcHJlcGFyZUV4cG9ydCIsIl9oYW5kbGVDdXN0b21Mb2dpYyIsIl9oYW5kbGVHbG9iYWxBbmRUaGVtZSIsIl9maW5kQ2hhcnRTaXplIiwib3B0aW9uc0NoYXJ0Iiwib3B0aW9uc0V4cG9ydGluZyIsImdsb2JhbE9wdGlvbnNDaGFydCIsImdsb2JhbE9wdGlvbnNFeHBvcnRpbmciLCJ0aGVtZU9wdGlvbnNDaGFydCIsInRoZW1lT3B0aW9uc0V4cG9ydGluZyIsInNvdXJjZUhlaWdodCIsInNvdXJjZVdpZHRoIiwicGFyYW0iLCJfaGFuZGxlUmVzb3VyY2VzIiwiYWxsb3dlZFByb3BzIiwiaGFuZGxlZFJlc291cmNlcyIsImNvcnJlY3RSZXNvdXJjZXMiLCJwcm9wTmFtZSIsIm9wdGlvbnNOYW1lIiwidGltZXJJZHMiLCJhZGRUaW1lciIsImNsZWFyQWxsVGltZXJzIiwiY2xlYXJJbnRlcnZhbCIsImNsZWFyVGltZW91dCIsImxvZ0Vycm9yTWlkZGxld2FyZSIsInJlcXVlc3QiLCJuZXh0IiwicmV0dXJuRXJyb3JNaWRkbGV3YXJlIiwic3RhdHVzIiwianNvbiIsImVycm9yTWlkZGxld2FyZSIsImFwcCIsInVzZSIsInJhdGVMaW1pdGluZ01pZGRsZXdhcmUiLCJyYXRlTGltaXRpbmdPcHRpb25zIiwicmF0ZU9wdGlvbnMiLCJsaW1pdGVyIiwicmF0ZUxpbWl0Iiwid2luZG93TXMiLCJsaW1pdCIsImRlbGF5TXMiLCJoYW5kbGVyIiwiZm9ybWF0Iiwic2VuZCIsImRlZmF1bHQiLCJza2lwIiwicXVlcnkiLCJhY2Nlc3NfdG9rZW4iLCJjb250ZW50VHlwZU1pZGRsZXdhcmUiLCJjb250ZW50VHlwZSIsImhlYWRlcnMiLCJyZXF1ZXN0Qm9keU1pZGRsZXdhcmUiLCJjb25uZWN0aW9uIiwicmVtb3RlQWRkcmVzcyIsInZhbGlkYXRlZE9wdGlvbnMiLCJmaWxlbmFtZSIsInZhbGlkYXRpb25NaWRkbGV3YXJlIiwicG9zdCIsInJldmVyc2VkTWltZSIsInBuZyIsImpwZWciLCJnaWYiLCJyZXF1ZXN0RXhwb3J0IiwicmVxdWVzdENvdW50ZXIiLCJjb25uZWN0aW9uQWJvcnRlZCIsInNvY2tldCIsImhhZEVycm9ycyIsImhlYWRlciIsImF0dGFjaG1lbnQiLCJleHBvcnRSb3V0ZXMiLCJzZXJ2ZXJTdGFydFRpbWUiLCJwYWNrYWdlRmlsZSIsInN1Y2Nlc3NSYXRlcyIsInJlY29yZEludGVydmFsIiwid2luZG93U2l6ZSIsIl9jYWxjdWxhdGVNb3ZpbmdBdmVyYWdlIiwiYSIsImIiLCJfc3RhcnRTdWNjZXNzUmF0ZSIsInNldEludGVydmFsIiwic3RhdHMiLCJzdWNjZXNzUmF0aW8iLCJoZWFsdGhSb3V0ZXMiLCJwZXJpb2QiLCJtb3ZpbmdBdmVyYWdlIiwiYm9vdFRpbWUiLCJ1cHRpbWUiLCJmbG9vciIsInNlcnZlclZlcnNpb24iLCJoaWdoY2hhcnRzVmVyc2lvbiIsImF2ZXJhZ2VFeHBvcnRUaW1lIiwiYXR0ZW1wdGVkRXhwb3J0cyIsInBlcmZvcm1lZEV4cG9ydHMiLCJmYWlsZWRFeHBvcnRzIiwic3VjZXNzUmF0aW8iLCJ0b0ZpeGVkIiwic3ZnRXhwb3J0cyIsImpzb25FeHBvcnRzIiwic3ZnRXhwb3J0c0F0dGVtcHRzIiwianNvbkV4cG9ydHNBdHRlbXB0cyIsInVpUm91dGVzIiwic2VuZEZpbGUiLCJhY2NlcHRSYW5nZXMiLCJ2ZXJzaW9uQ2hhbmdlUm91dGVzIiwidG9rZW4iLCJhY3RpdmVTZXJ2ZXJzIiwiTWFwIiwiZXhwcmVzcyIsInN0YXJ0U2VydmVyIiwic2VydmVyT3B0aW9ucyIsInVwbG9hZExpbWl0Qnl0ZXMiLCJzdG9yYWdlIiwibXVsdGVyIiwibWVtb3J5U3RvcmFnZSIsInVwbG9hZCIsImxpbWl0cyIsImZpZWxkU2l6ZSIsImRpc2FibGUiLCJjb3JzIiwibWV0aG9kcyIsInNldCIsInVybGVuY29kZWQiLCJleHRlbmRlZCIsIm5vbmUiLCJzdGF0aWMiLCJodHRwU2VydmVyIiwiY3JlYXRlU2VydmVyIiwiX2F0dGFjaFNlcnZlckVycm9ySGFuZGxlcnMiLCJsaXN0ZW4iLCJjZXJ0IiwiaHR0cHNTZXJ2ZXIiLCJjbG9zZVNlcnZlcnMiLCJkZWxldGUiLCJnZXRTZXJ2ZXJzIiwiZ2V0RXhwcmVzcyIsImdldEFwcCIsIm1pZGRsZXdhcmVzIiwic2h1dGRvd25DbGVhblVwIiwiZXhpdENvZGUiLCJleGl0IiwiaW5pdEV4cG9ydCIsImluaXRPcHRpb25zIiwiX2F0dGFjaFByb2Nlc3NFeGl0TGlzdGVuZXJzIl0sIm1hcHBpbmdzIjoid2xCQTJCTyxNQUFNQSxZQUFZQyxJQUFhQSxjQUFDLElBQUlDLElBQUksT0FBUSxvQkFBQUMsU0FBQUMsUUFBQSxPQUFBQyxjQUFBQyxZQUFBQyxLQUFBQyx3QkFBQSxXQUFBQSx1QkFBQUMsUUFBQUMsZUFBQUYsdUJBQUFHLEtBQUEsSUFBQVQsSUFBQSxZQUFBQyxTQUFBUyxTQUFBTCxPQStCaEQsU0FBU00sU0FBU0MsR0FFdkIsR0FBZSxPQUFYQSxHQUFxQyxpQkFBWEEsRUFDNUIsT0FBT0EsRUFJVCxNQUFNQyxFQUFhQyxNQUFNQyxRQUFRSCxHQUFVLEdBQUssR0FHaEQsSUFBSyxNQUFNSSxLQUFPSixFQUNaSyxPQUFPQyxVQUFVQyxlQUFlQyxLQUFLUixFQUFRSSxLQUMvQ0gsRUFBV0csR0FBT0wsU0FBU0MsRUFBT0ksS0FL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 diff --git a/dist/index.esm.js b/dist/index.esm.js index 4b5b4558..8a23a2f7 100644 --- a/dist/index.esm.js +++ b/dist/index.esm.js @@ -1,2 +1,2 @@ -import"colors";import{readFileSync,existsSync,mkdirSync,appendFile,writeFileSync}from"fs";import{isAbsolute,normalize,resolve,join}from"path";import{HttpsProxyAgent}from"https-proxy-agent";import{fileURLToPath}from"url";import dotenv from"dotenv";import{z}from"zod";import http from"http";import https from"https";import{Pool}from"tarn";import{v4}from"uuid";import puppeteer from"puppeteer";import DOMPurify from"dompurify";import{JSDOM}from"jsdom";import cors from"cors";import express from"express";import multer from"multer";import rateLimit from"express-rate-limit";const __dirname=fileURLToPath(new URL("../.",import.meta.url));function deepCopy(e){if(null===e||"object"!=typeof e)return e;const t=Array.isArray(e)?[]:{};for(const o in e)Object.prototype.hasOwnProperty.call(e,o)&&(t[o]=deepCopy(e[o]));return t}function fixConstr(e){try{const t=`${e.toLowerCase().replace("chart","")}Chart`;return"Chart"===t&&t.toLowerCase(),["chart","stockChart","mapChart","ganttChart"].includes(t)?t:"chart"}catch{return"chart"}}function fixOutfile(e,t){return`${getAbsolutePath(t||"chart").split(".").shift()}.${e}`}function fixType(e,t=null){const o={"image/png":"png","image/jpeg":"jpeg","application/pdf":"pdf","image/svg+xml":"svg"},r=Object.values(o);if(t){const o=t.split(".").pop();"jpg"===o?e="jpeg":r.includes(o)&&e!==o&&(e=o)}return o[e]||r.find((t=>t===e))||"png"}function getAbsolutePath(e){return isAbsolute(e)?normalize(e):resolve(e)}function getBase64(e,t){return"pdf"===t||"svg"==t?Buffer.from(e,"utf8").toString("base64"):e}function getNewDate(){return(new Date).toString().split("(")[0].trim()}function getNewDateTime(){return(new Date).getTime()}function isObject(e){return"[object Object]"===Object.prototype.toString.call(e)}function isObjectEmpty(e){return"object"==typeof e&&!Array.isArray(e)&&null!==e&&0===Object.keys(e).length}function isPrivateRangeUrlFound(e){return[/xlink:href="(?:http:\/\/|https:\/\/)?localhost\b/,/xlink:href="(?:http:\/\/|https:\/\/)?10\.\d{1,3}\.\d{1,3}\.\d{1,3}\b/,/xlink:href="(?:http:\/\/|https:\/\/)?127\.\d{1,3}\.\d{1,3}\.\d{1,3}\b/,/xlink:href="(?:http:\/\/|https:\/\/)?172\.(1[6-9]|2[0-9]|3[0-1])\.\d{1,3}\.\d{1,3}\b/,/xlink:href="(?:http:\/\/|https:\/\/)?192\.168\.\d{1,3}\.\d{1,3}\b/].some((t=>t.test(e)))}function measureTime(){const e=process.hrtime.bigint();return()=>Number(process.hrtime.bigint()-e)/1e6}function roundNumber(e,t=1){const o=Math.pow(10,t||0);return Math.round(+e*o)/o}function wrapAround(e,t,o=!1){if(e&&"string"==typeof e)return(e=e.trim()).endsWith(".js")?t?wrapAround(readFileSync(getAbsolutePath(e),"utf8"),t,o):null:!o&&(e.startsWith("function()")||e.startsWith("function ()")||e.startsWith("()=>")||e.startsWith("() =>"))?`(${e})()`:e.replace(/;$/,"")}const colors=["red","yellow","blue","gray","green"],logging={toConsole:!0,toFile:!1,pathCreated:!1,pathToLog:"",levelsDesc:[{title:"error",color:colors[0]},{title:"warning",color:colors[1]},{title:"notice",color:colors[2]},{title:"verbose",color:colors[3]},{title:"benchmark",color:colors[4]}]};function log(...e){const[t,...o]=e,{levelsDesc:r,level:i}=logging;if(5!==t&&(0===t||t>i||i>r.length))return;const n=`${getNewDate()} [${r[t-1].title}] -`;logging.toFile&&_logToFile(o,n),logging.toConsole&&console.log.apply(void 0,[n.toString()[logging.levelsDesc[t-1].color]].concat(o))}function logWithStack(e,t,o){const r=o||t&&t.message||"",{level:i,levelsDesc:n}=logging;if(0===e||e>i||i>n.length)return;const s=`${getNewDate()} [${n[e-1].title}] -`,a=t&&t.stack,l=[r];a&&l.push("\n",a),logging.toFile&&_logToFile(l,s),logging.toConsole&&console.log.apply(void 0,[s.toString()[logging.levelsDesc[e-1].color]].concat([l.shift()[colors[e-1]],...l]))}function logZodIssues(e,t,o){logWithStack(e,null,[`${o||"[validation] Validation error"} - the following Zod issues occured:`,...(t||[]).map((e=>`- ${e.message}`))].join("\n"))}function initLogging(e){const{level:t,dest:o,file:r,toConsole:i,toFile:n}=e;logging.pathCreated=!1,logging.pathToLog="",setLogLevel(t),enableConsoleLogging(i),enableFileLogging(o,r,n)}function setLogLevel(e){Number.isInteger(e)&&e>=0&&e<=logging.levelsDesc.length&&(logging.level=e)}function enableConsoleLogging(e){logging.toConsole=!!e}function enableFileLogging(e,t,o){logging.toFile=!!o,logging.toFile&&(logging.dest=e||"",logging.file=t||"")}function _logToFile(e,t){logging.pathCreated||(!existsSync(getAbsolutePath(logging.dest))&&mkdirSync(getAbsolutePath(logging.dest)),logging.pathToLog=getAbsolutePath(join(logging.dest,logging.file)),logging.pathCreated=!0),appendFile(logging.pathToLog,[t].concat(e).join(" ")+"\n",(e=>{e&&logging.toFile&&logging.pathCreated&&(logging.toFile=!1,logging.pathCreated=!1,logWithStack(2,e,"[logger] Unable to write to log file."))}))}const defaultConfig={puppeteer:{args:{value:["--allow-running-insecure-content","--ash-no-nudges","--autoplay-policy=user-gesture-required","--block-new-web-contents","--disable-accelerated-2d-canvas","--disable-background-networking","--disable-background-timer-throttling","--disable-backgrounding-occluded-windows","--disable-breakpad","--disable-checker-imaging","--disable-client-side-phishing-detection","--disable-component-extensions-with-background-pages","--disable-component-update","--disable-default-apps","--disable-dev-shm-usage","--disable-domain-reliability","--disable-extensions","--disable-features=CalculateNativeWinOcclusion,InterestFeedContentSuggestions,WebOTP","--disable-hang-monitor","--disable-ipc-flooding-protection","--disable-logging","--disable-notifications","--disable-offer-store-unmasked-wallet-cards","--disable-popup-blocking","--disable-print-preview","--disable-prompt-on-repost","--disable-renderer-backgrounding","--disable-search-engine-choice-screen","--disable-session-crashed-bubble","--disable-setuid-sandbox","--disable-site-isolation-trials","--disable-speech-api","--disable-sync","--enable-unsafe-webgpu","--hide-crash-restore-bubble","--hide-scrollbars","--metrics-recording-only","--mute-audio","--no-default-browser-check","--no-first-run","--no-pings","--no-sandbox","--no-startup-window","--no-zygote","--password-store=basic","--process-per-tab","--use-mock-keychain"],types:["string[]"],envLink:"PUPPETEER_ARGS",cliName:"puppeteerArgs",description:"Array of Puppeteer arguments",promptOptions:{type:"list",separator:";"}}},highcharts:{version:{value:"latest",types:["string"],envLink:"HIGHCHARTS_VERSION",description:"Highcharts version",promptOptions:{type:"text"}},cdnUrl:{value:"https://code.highcharts.com",types:["string"],envLink:"HIGHCHARTS_CDN_URL",description:"CDN URL for Highcharts scripts",promptOptions:{type:"text"}},forceFetch:{value:!1,types:["boolean"],envLink:"HIGHCHARTS_FORCE_FETCH",description:"Flag to refetch scripts after each server rerun",promptOptions:{type:"toggle"}},cachePath:{value:".cache",types:["string"],envLink:"HIGHCHARTS_CACHE_PATH",description:"Directory path for cached Highcharts scripts",promptOptions:{type:"text"}},coreScripts:{value:["highcharts","highcharts-more","highcharts-3d"],types:["string[]"],envLink:"HIGHCHARTS_CORE_SCRIPTS",description:"Highcharts core scripts to fetch",promptOptions:{type:"multiselect",instructions:"Space: Select specific, A: Select all, Enter: Confirm"}},moduleScripts:{value:["stock","map","gantt","exporting","parallel-coordinates","accessibility","boost-canvas","boost","data","data-tools","draggable-points","static-scale","broken-axis","heatmap","tilemap","tiledwebmap","timeline","treemap","treegraph","item-series","drilldown","histogram-bellcurve","bullet","funnel","funnel3d","geoheatmap","pyramid3d","networkgraph","overlapping-datalabels","pareto","pattern-fill","pictorial","price-indicator","sankey","arc-diagram","dependency-wheel","series-label","series-on-point","solid-gauge","sonification","streamgraph","sunburst","variable-pie","variwide","vector","venn","windbarb","wordcloud","xrange","no-data-to-display","drag-panes","debugger","dumbbell","lollipop","cylinder","organization","dotplot","marker-clusters","hollowcandlestick","heikinashi","flowmap","export-data","navigator","textpath"],types:["string[]"],envLink:"HIGHCHARTS_MODULE_SCRIPTS",description:"Highcharts module scripts to fetch",promptOptions:{type:"multiselect",instructions:"Space: Select specific, A: Select all, Enter: Confirm"}},indicatorScripts:{value:["indicators-all"],types:["string[]"],envLink:"HIGHCHARTS_INDICATOR_SCRIPTS",description:"Highcharts indicator scripts to fetch",promptOptions:{type:"multiselect",instructions:"Space: Select specific, A: Select all, Enter: Confirm"}},customScripts:{value:["https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.30.1/moment.min.js","https://cdnjs.cloudflare.com/ajax/libs/moment-timezone/0.5.45/moment-timezone-with-data.min.js"],types:["string[]"],envLink:"HIGHCHARTS_CUSTOM_SCRIPTS",description:"Additional custom scripts or dependencies to fetch",promptOptions:{type:"list",separator:";"}}},export:{infile:{value:null,types:["string","null"],envLink:"EXPORT_INFILE",description:"Input filename with type, formatted correctly as JSON or SVG",promptOptions:{type:"text"}},instr:{value:null,types:["Object","string","null"],envLink:"EXPORT_INSTR",description:"Overrides the `infile` with JSON, stringified JSON, or SVG input",promptOptions:{type:"text"}},options:{value:null,types:["Object","string","null"],envLink:"EXPORT_OPTIONS",description:"Alias for the `instr` option",promptOptions:{type:"text"}},svg:{value:null,types:["string","null"],envLink:"EXPORT_SVG",description:"SVG string representation of the chart to render",promptOptions:{type:"text"}},batch:{value:null,types:["string","null"],envLink:"EXPORT_BATCH",description:'Batch job string with input/output pairs: "in=out;in=out;..."',promptOptions:{type:"text"}},outfile:{value:null,types:["string","null"],envLink:"EXPORT_OUTFILE",description:"Output filename with type. Can be jpeg, png, pdf, or svg and ignores `type` option",promptOptions:{type:"text"}},type:{value:"png",types:["string"],envLink:"EXPORT_TYPE",description:"File export format. Can be jpeg, png, pdf, or svg",promptOptions:{type:"select",hint:"Default: png",choices:["png","jpeg","pdf","svg"]}},constr:{value:"chart",types:["string"],envLink:"EXPORT_CONSTR",description:"Chart constructor. Can be chart, stockChart, mapChart, or ganttChart",promptOptions:{type:"select",hint:"Default: chart",choices:["chart","stockChart","mapChart","ganttChart"]}},b64:{value:!1,types:["boolean"],envLink:"EXPORT_B64",description:"Whether or not to the chart should be received in Base64 format instead of binary",promptOptions:{type:"toggle"}},noDownload:{value:!1,types:["boolean"],envLink:"EXPORT_NO_DOWNLOAD",description:"Whether or not to include or exclude attachment headers in the response",promptOptions:{type:"toggle"}},height:{value:null,types:["number","null"],envLink:"EXPORT_HEIGHT",description:"Height of the exported chart, overrides chart settings",promptOptions:{type:"number"}},width:{value:null,types:["number","null"],envLink:"EXPORT_WIDTH",description:"Width of the exported chart, overrides chart settings",promptOptions:{type:"number"}},scale:{value:null,types:["number","null"],envLink:"EXPORT_SCALE",description:"Scale of the exported chart, overrides chart settings. Ranges from 0.1 to 5.0",promptOptions:{type:"number"}},defaultHeight:{value:400,types:["number"],envLink:"EXPORT_DEFAULT_HEIGHT",description:"Default height of the exported chart if not set",promptOptions:{type:"number"}},defaultWidth:{value:600,types:["number"],envLink:"EXPORT_DEFAULT_WIDTH",description:"Default width of the exported chart if not set",promptOptions:{type:"number"}},defaultScale:{value:1,types:["number"],envLink:"EXPORT_DEFAULT_SCALE",description:"Default scale of the exported chart if not set. Ranges from 0.1 to 5.0",promptOptions:{type:"number",min:.1,max:5}},globalOptions:{value:null,types:["Object","string","null"],envLink:"EXPORT_GLOBAL_OPTIONS",description:"JSON, stringified JSON or filename with global options for Highcharts.setOptions",promptOptions:{type:"text"}},themeOptions:{value:null,types:["Object","string","null"],envLink:"EXPORT_THEME_OPTIONS",description:"JSON, stringified JSON or filename with theme options for Highcharts.setOptions",promptOptions:{type:"text"}},rasterizationTimeout:{value:1500,types:["number"],envLink:"EXPORT_RASTERIZATION_TIMEOUT",description:"Milliseconds to wait for webpage rendering",promptOptions:{type:"number"}}},customLogic:{allowCodeExecution:{value:!1,types:["boolean"],envLink:"CUSTOM_LOGIC_ALLOW_CODE_EXECUTION",description:"Allows or disallows execution of arbitrary code during exporting",promptOptions:{type:"toggle"}},allowFileResources:{value:!1,types:["boolean"],envLink:"CUSTOM_LOGIC_ALLOW_FILE_RESOURCES",description:"Allows or disallows injection of filesystem resources (disabled in server mode)",promptOptions:{type:"toggle"}},customCode:{value:null,types:["string","null"],envLink:"CUSTOM_LOGIC_CUSTOM_CODE",description:"Custom code to execute before chart initialization. Can be a function, code wrapped in a function, or a .js filename",promptOptions:{type:"text"}},callback:{value:null,types:["string","null"],envLink:"CUSTOM_LOGIC_CALLBACK",description:"JavaScript code to run during construction. Can be a function or a .js filename",promptOptions:{type:"text"}},resources:{value:null,types:["Object","string","null"],envLink:"CUSTOM_LOGIC_RESOURCES",description:"Additional resources as JSON, stringified JSON, or filename, containing files, js, and css sections",promptOptions:{type:"text"}},loadConfig:{value:null,types:["string","null"],envLink:"CUSTOM_LOGIC_LOAD_CONFIG",legacyName:"fromFile",description:"File with a pre-defined configuration to use",promptOptions:{type:"text"}},createConfig:{value:null,types:["string","null"],envLink:"CUSTOM_LOGIC_CREATE_CONFIG",description:"Prompt-based option setting, saved to a provided config file",promptOptions:{type:"text"}}},server:{enable:{value:!1,types:["boolean"],envLink:"SERVER_ENABLE",cliName:"enableServer",description:"Starts the server when true",promptOptions:{type:"toggle"}},host:{value:"0.0.0.0",types:["string"],envLink:"SERVER_HOST",description:"Hostname of the server",promptOptions:{type:"text"}},port:{value:7801,types:["number"],envLink:"SERVER_PORT",description:"Port number for the server",promptOptions:{type:"number"}},uploadLimit:{value:3,types:["number"],envLink:"SERVER_UPLOAD_LIMIT",description:"Maximum request body size in MB",promptOptions:{type:"number"}},benchmarking:{value:!1,types:["boolean"],envLink:"SERVER_BENCHMARKING",cliName:"serverBenchmarking",description:"Displays or not action durations in milliseconds during server requests",promptOptions:{type:"toggle"}},proxy:{host:{value:null,types:["string","null"],envLink:"SERVER_PROXY_HOST",cliName:"proxyHost",description:"Host of the proxy server, if applicable",promptOptions:{type:"text"}},port:{value:null,types:["number","null"],envLink:"SERVER_PROXY_PORT",cliName:"proxyPort",description:"Port of the proxy server, if applicable",promptOptions:{type:"number"}},timeout:{value:5e3,types:["number"],envLink:"SERVER_PROXY_TIMEOUT",cliName:"proxyTimeout",description:"Timeout in milliseconds for the proxy server, if applicable",promptOptions:{type:"number"}}},rateLimiting:{enable:{value:!1,types:["boolean"],envLink:"SERVER_RATE_LIMITING_ENABLE",cliName:"enableRateLimiting",description:"Enables or disables rate limiting on the server",promptOptions:{type:"toggle"}},maxRequests:{value:10,types:["number"],envLink:"SERVER_RATE_LIMITING_MAX_REQUESTS",legacyName:"rateLimit",description:"Maximum number of requests allowed per minute",promptOptions:{type:"number"}},window:{value:1,types:["number"],envLink:"SERVER_RATE_LIMITING_WINDOW",description:"Time window in minutes for rate limiting",promptOptions:{type:"number"}},delay:{value:0,types:["number"],envLink:"SERVER_RATE_LIMITING_DELAY",description:"Delay duration between successive requests before reaching the limit",promptOptions:{type:"number"}},trustProxy:{value:!1,types:["boolean"],envLink:"SERVER_RATE_LIMITING_TRUST_PROXY",description:"Set to true if the server is behind a load balancer",promptOptions:{type:"toggle"}},skipKey:{value:null,types:["string","null"],envLink:"SERVER_RATE_LIMITING_SKIP_KEY",description:"Key to bypass the rate limiter, used with `skipToken`",promptOptions:{type:"text"}},skipToken:{value:null,types:["string","null"],envLink:"SERVER_RATE_LIMITING_SKIP_TOKEN",description:"Token to bypass the rate limiter, used with `skipKey`",promptOptions:{type:"text"}}},ssl:{enable:{value:!1,types:["boolean"],envLink:"SERVER_SSL_ENABLE",cliName:"enableSsl",description:"Enables or disables SSL protocol",promptOptions:{type:"toggle"}},force:{value:!1,types:["boolean"],envLink:"SERVER_SSL_FORCE",cliName:"sslForce",legacyName:"sslOnly",description:"Forces the server to use HTTPS only when true",promptOptions:{type:"toggle"}},port:{value:443,types:["number"],envLink:"SERVER_SSL_PORT",cliName:"sslPort",description:"Port for the SSL server",promptOptions:{type:"number"}},certPath:{value:null,types:["string","null"],envLink:"SERVER_SSL_CERT_PATH",cliName:"sslCertPath",legacyName:"sslPath",description:"Path to the SSL certificate/key file",promptOptions:{type:"text"}}}},pool:{minWorkers:{value:4,types:["number"],envLink:"POOL_MIN_WORKERS",description:"Minimum and initial number of pool workers to spawn",promptOptions:{type:"number"}},maxWorkers:{value:8,types:["number"],envLink:"POOL_MAX_WORKERS",legacyName:"workers",description:"Maximum number of pool workers to spawn",promptOptions:{type:"number"}},workLimit:{value:40,types:["number"],envLink:"POOL_WORK_LIMIT",description:"Number of tasks a worker can handle before restarting",promptOptions:{type:"number"}},acquireTimeout:{value:5e3,types:["number"],envLink:"POOL_ACQUIRE_TIMEOUT",description:"Timeout in milliseconds for acquiring a resource",promptOptions:{type:"number"}},createTimeout:{value:5e3,types:["number"],envLink:"POOL_CREATE_TIMEOUT",description:"Timeout in milliseconds for creating a resource",promptOptions:{type:"number"}},destroyTimeout:{value:5e3,types:["number"],envLink:"POOL_DESTROY_TIMEOUT",description:"Timeout in milliseconds for destroying a resource",promptOptions:{type:"number"}},idleTimeout:{value:3e4,types:["number"],envLink:"POOL_IDLE_TIMEOUT",description:"Timeout in milliseconds for destroying idle resources",promptOptions:{type:"number"}},createRetryInterval:{value:200,types:["number"],envLink:"POOL_CREATE_RETRY_INTERVAL",description:"Interval in milliseconds before retrying resource creation on failure",promptOptions:{type:"number"}},reaperInterval:{value:1e3,types:["number"],envLink:"POOL_REAPER_INTERVAL",description:"Interval in milliseconds to check and destroy idle resources",promptOptions:{type:"number"}},benchmarking:{value:!1,types:["boolean"],envLink:"POOL_BENCHMARKING",cliName:"poolBenchmarking",description:"Shows statistics for the pool of resources",promptOptions:{type:"toggle"}}},logging:{level:{value:4,types:["number"],envLink:"LOGGING_LEVEL",cliName:"logLevel",description:"Logging verbosity level",promptOptions:{type:"number",round:0,min:0,max:5}},file:{value:"highcharts-export-server.log",types:["string"],envLink:"LOGGING_FILE",cliName:"logFile",description:"Log file name. Requires `logToFile` and `logDest` to be set",promptOptions:{type:"text"}},dest:{value:"log",types:["string"],envLink:"LOGGING_DEST",cliName:"logDest",description:"Path to store log files. Requires `logToFile` to be set",promptOptions:{type:"text"}},toConsole:{value:!0,types:["boolean"],envLink:"LOGGING_TO_CONSOLE",cliName:"logToConsole",description:"Enables or disables console logging",promptOptions:{type:"toggle"}},toFile:{value:!0,types:["boolean"],envLink:"LOGGING_TO_FILE",cliName:"logToFile",description:"Enables or disables logging to a file",promptOptions:{type:"toggle"}}},ui:{enable:{value:!1,types:["boolean"],envLink:"UI_ENABLE",cliName:"enableUi",description:"Enables or disables the UI for the export server",promptOptions:{type:"toggle"}},route:{value:"/",types:["string"],envLink:"UI_ROUTE",cliName:"uiRoute",description:"The endpoint route for the UI",promptOptions:{type:"text"}}},other:{nodeEnv:{value:"production",types:["string"],envLink:"OTHER_NODE_ENV",description:"The Node.js environment type",promptOptions:{type:"text"}},listenToProcessExits:{value:!0,types:["boolean"],envLink:"OTHER_LISTEN_TO_PROCESS_EXITS",description:"Whether or not to attach process.exit handlers",promptOptions:{type:"toggle"}},noLogo:{value:!1,types:["boolean"],envLink:"OTHER_NO_LOGO",description:"Display or skip printing the logo on startup",promptOptions:{type:"toggle"}},hardResetPage:{value:!1,types:["boolean"],envLink:"OTHER_HARD_RESET_PAGE",description:"Whether or not to reset the page content entirely",promptOptions:{type:"toggle"}},browserShellMode:{value:!0,types:["boolean"],envLink:"OTHER_BROWSER_SHELL_MODE",description:"Whether or not to set the browser to run in shell mode",promptOptions:{type:"toggle"}},validation:{value:!0,types:["boolean"],envLink:"OTHER_VALIDATION",description:"Whether or not to enable validation of options types",promptOptions:{type:"toggle"}}},debug:{enable:{value:!1,types:["boolean"],envLink:"DEBUG_ENABLE",cliName:"enableDebug",description:"Enables or disables debug mode for the underlying browser",promptOptions:{type:"toggle"}},headless:{value:!1,types:["boolean"],envLink:"DEBUG_HEADLESS",description:"Whether or not to set the browser to run in headless mode during debugging",promptOptions:{type:"toggle"}},devtools:{value:!1,types:["boolean"],envLink:"DEBUG_DEVTOOLS",description:"Enables or disables DevTools in headful mode",promptOptions:{type:"toggle"}},listenToConsole:{value:!1,types:["boolean"],envLink:"DEBUG_LISTEN_TO_CONSOLE",description:"Enables or disables listening to console messages from the browser",promptOptions:{type:"toggle"}},dumpio:{value:!1,types:["boolean"],envLink:"DEBUG_DUMPIO",description:"Redirects or not browser stdout and stderr to process.stdout and process.stderr",promptOptions:{type:"toggle"}},slowMo:{value:0,types:["number"],envLink:"DEBUG_SLOW_MO",description:"Delays Puppeteer operations by the specified milliseconds",promptOptions:{type:"number"}},debuggingPort:{value:9222,types:["number"],envLink:"DEBUG_DEBUGGING_PORT",description:"Port used for debugging",promptOptions:{type:"number"}}}},nestedProps=_createNestedProps(defaultConfig),absoluteProps=_createAbsoluteProps(defaultConfig);function _createNestedProps(e,t={},o=""){return Object.keys(e).forEach((r=>{const i=e[r];void 0===i.value?_createNestedProps(i,t,`${o}.${r}`):(t[i.cliName||r]=`${o}.${r}`.substring(1),void 0!==i.legacyName&&(t[i.legacyName]=`${o}.${r}`.substring(1)))})),t}function _createAbsoluteProps(e,t=[]){return Object.keys(e).forEach((o=>{const r=e[o];void 0===r.types?_createAbsoluteProps(r,t):r.types.includes("Object")&&t.push(o)})),t}dotenv.config();const{coreScripts:coreScripts,moduleScripts:moduleScripts,indicatorScripts:indicatorScripts}=defaultConfig.highcharts;z.setErrorMap(_customErrorMap);const v={boolean:e=>e?z.boolean():z.union([z.enum(["true","1","false","0","undefined","null",""]).transform((e=>["undefined","null",""].includes(e)?null:"true"===e||"1"===e)),z.boolean()]).nullable(),string:e=>e?z.string().trim().refine((e=>!["false","undefined","null",""].includes(e)),{params:{errorMessage:"The string contains a forbidden value"}}):z.string().trim().transform((e=>["false","undefined","null",""].includes(e)?null:e)).nullable(),enum:(e,t)=>t?z.enum([...e]):z.enum([...e,"undefined","null",""]).transform((e=>["undefined","null",""].includes(e)?null:e)).nullable(),stringArray(e,t,o){const r=z.string().trim().array(),i=z.string().trim().transform((e=>(e.startsWith("[")&&(e=e.slice(1)),e.endsWith("]")&&(e=e.slice(0,-1)),e.split(t)))),n=t=>t.map((e=>e.trim())).filter(e);return o?r.transform(n):z.union([i,r]).transform(n).transform((e=>e.length?e:null)).nullable()},positiveNum:e=>e?z.number().positive():z.union([z.string().trim().refine((e=>!isNaN(Number(e))&&Number(e)>0||["undefined","null",""].includes(e)),{params:{errorMessage:"The value must be numeric and positive"}}).transform((e=>["undefined","null",""].includes(e)?null:Number(e))),z.number().positive()]).nullable(),nonNegativeNum:e=>e?z.number().nonnegative():z.union([z.string().trim().refine((e=>!isNaN(Number(e))&&Number(e)>=0||["undefined","null",""].includes(e)),{params:{errorMessage:"The value must be numeric and non-negative"}}).transform((e=>["undefined","null",""].includes(e)?null:Number(e))),z.number().nonnegative()]).nullable(),startsWith:(e,t)=>t?z.string().trim().refine((t=>e.some((e=>t.startsWith(e)))),{params:{errorMessage:`The value must be a string that starts with ${e.join(", ")}`}}):z.string().trim().refine((t=>e.some((e=>t.startsWith(e)))||["undefined","null",""].includes(t)),{params:{errorMessage:`The value must be a string that starts with ${e.join(", ")}`}}).transform((e=>["undefined","null",""].includes(e)?null:e)).nullable(),chartConfig:()=>z.union([z.string().trim().refine((e=>e.startsWith("{")&&e.endsWith("}")||["undefined","null",""].includes(e)),{params:{errorMessage:"The value must be a string that starts with '{' and ends with '}'"}}).transform((e=>["undefined","null",""].includes(e)?null:e)),z.object({}).passthrough()]).nullable(),additionalOptions:()=>z.union([z.string().trim().refine((e=>e.length>=6&&e.endsWith(".json")||e.startsWith("{")&&e.endsWith("}")||["undefined","null",""].includes(e)),{params:{errorMessage:"The value must be a string that ends with '.json' or starts with '{' and ends with '}'"}}).transform((e=>["undefined","null",""].includes(e)?null:e)),z.object({}).passthrough()]).nullable()},validators={args:e=>v.stringArray((e=>!["false","undefined","null",""].includes(e)),";",e),version:e=>e?z.string().trim().refine((e=>/^(latest|\d{1,2}(\.\d{1,2}){0,2})$/.test(e)),{params:{errorMessage:"The value must be 'latest', a major version, or in the form XX.YY.ZZ"}}):z.string().trim().refine((e=>/^(latest|\d{1,2}(\.\d{1,2}){0,2})$/.test(e)||["undefined","null",""].includes(e)),{params:{errorMessage:"The value must be 'latest', a major version, or in the form XX.YY.ZZ"}}).transform((e=>["undefined","null",""].includes(e)?null:e)).nullable(),cdnUrl:e=>v.startsWith(["http://","https://"],e),forceFetch:e=>v.boolean(e),cachePath:e=>v.string(e),adminToken:e=>v.string(e),coreScripts:e=>v.stringArray((e=>coreScripts.value.includes(e)),",",e),moduleScripts:e=>v.stringArray((e=>moduleScripts.value.includes(e)),",",e),indicatorScripts:e=>v.stringArray((e=>indicatorScripts.value.includes(e)),",",e),customScripts:e=>v.stringArray((e=>e.startsWith("https://")||e.startsWith("http://")),",",e),infile:e=>e?z.string().trim().refine((e=>e.length>=6&&e.endsWith(".json")||e.length>=5&&e.endsWith(".svg")),{params:{errorMessage:"The value must be a string that ends with .json or .svg"}}).nullable():z.string().trim().refine((e=>e.length>=6&&e.endsWith(".json")||e.length>=5&&e.endsWith(".svg")||["undefined","null",""].includes(e)),{params:{errorMessage:"The value must be a string that ends with .json or .svg"}}).transform((e=>["undefined","null",""].includes(e)?null:e)).nullable(),instr:()=>v.chartConfig(),options:()=>v.chartConfig(),svg:()=>z.string().trim().refine((e=>e.indexOf("=0||e.indexOf("=0||["false","undefined","null",""].includes(e)),{params:{errorMessage:"The value must be a string that contains '["false","undefined","null",""].includes(e)?null:e)).nullable(),outfile:e=>e?z.string().trim().refine((e=>e.length>=6&&e.endsWith(".jpeg")||e.length>=5&&(e.endsWith(".jpg")||e.endsWith(".png")||e.endsWith(".pdf")||e.endsWith(".svg"))),{params:{errorMessage:"The value must be a string that ends with .jpeg, .jpg, .png, .pdf, or .svg"}}).nullable():z.string().trim().refine((e=>e.length>=6&&e.endsWith(".jpeg")||e.length>=5&&(e.endsWith(".jpg")||e.endsWith(".png")||e.endsWith(".pdf")||e.endsWith(".svg"))||["undefined","null",""].includes(e)),{params:{errorMessage:"The value must be a string that ends with .jpeg, .jpg, .png, .pdf, or .svg"}}).transform((e=>["undefined","null",""].includes(e)?null:e)).nullable(),type:e=>v.enum(["jpeg","jpg","png","pdf","svg"],e),constr:e=>v.enum(["chart","stockChart","mapChart","ganttChart"],e),b64:e=>v.boolean(e),noDownload:e=>v.boolean(e),defaultHeight:e=>v.positiveNum(e),defaultWidth:e=>v.positiveNum(e),defaultScale:e=>e?z.number().gte(.1).lte(5):z.union([z.string().trim().refine((e=>!isNaN(Number(e))&&!0!==e&&!e.startsWith("[")&&Number(e)>=.1&&Number(e)<=5||["undefined","null",""].includes(e)),{params:{errorMessage:"The value must be within a 0.1 and 5.0 range"}}).transform((e=>["undefined","null",""].includes(e)?null:Number(e))),z.number().gte(.1).lte(5)]).nullable(),height(e){return this.defaultHeight(e).nullable()},width(e){return this.defaultWidth(e).nullable()},scale(e){return this.defaultScale(e).nullable()},globalOptions:()=>v.additionalOptions(),themeOptions:()=>v.additionalOptions(),batch:e=>v.string(e),rasterizationTimeout:e=>v.nonNegativeNum(e),allowCodeExecution:e=>v.boolean(e),allowFileResources:e=>v.boolean(e),customCode:e=>v.string(e),callback:e=>v.string(e),resources(e){const t=z.object({js:v.string(!1),css:v.string(!1),files:v.stringArray((e=>!["undefined","null",""].includes(e)),",",!0).nullable()}).partial(),o=z.string().trim().refine((e=>e.startsWith("{")&&e.endsWith("}")||e.length>=6&&e.endsWith(".json")),{params:{errorMessage:"The value must be a string that starts with '{' and ends with '}"}}),r=z.string().trim().refine((e=>e.startsWith("{")&&e.endsWith("}")||e.length>=6&&e.endsWith(".json")||["undefined","null",""].includes(e)),{params:{errorMessage:"The value must be a string that ends with .json"}}).transform((e=>["undefined","null",""].includes(e)?null:e));return e?z.union([t,o]).nullable():z.union([t,r]).nullable()},loadConfig:e=>v.string(e).refine((e=>null===e||e.length>=6&&e.endsWith(".json")),{params:{errorMessage:"The value must be a string that ends with .json"}}),createConfig(e){return this.loadConfig(e)},enableServer:e=>v.boolean(e),host:e=>v.string(e),port:e=>v.nonNegativeNum(e),uploadLimit:e=>v.positiveNum(e),serverBenchmarking:e=>v.boolean(e),proxyHost:e=>v.string(e),proxyPort:e=>v.nonNegativeNum(e).nullable(),proxyTimeout:e=>v.nonNegativeNum(e),enableRateLimiting:e=>v.boolean(e),maxRequests:e=>v.nonNegativeNum(e),window:e=>v.nonNegativeNum(e),delay:e=>v.nonNegativeNum(e),trustProxy:e=>v.boolean(e),skipKey:e=>v.string(e),skipToken:e=>v.string(e),enableSsl:e=>v.boolean(e),sslForce:e=>v.boolean(e),sslPort:e=>v.nonNegativeNum(e),sslCertPath:e=>v.string(e),minWorkers:e=>v.positiveNum(e),maxWorkers:e=>v.positiveNum(e),workLimit:e=>v.positiveNum(e),acquireTimeout:e=>v.nonNegativeNum(e),createTimeout:e=>v.nonNegativeNum(e),destroyTimeout:e=>v.nonNegativeNum(e),idleTimeout:e=>v.nonNegativeNum(e),createRetryInterval:e=>v.nonNegativeNum(e),reaperInterval:e=>v.nonNegativeNum(e),poolBenchmarking:e=>v.boolean(e),resourcesInterval:e=>v.nonNegativeNum(e),logLevel:e=>e?z.number().int().gte(0).lte(5):z.union([z.string().trim().refine((e=>!isNaN(Number(e))&&!0!==e&&!e.startsWith("[")&&Number.isInteger(Number(e))&&Number(e)>=0&&Number(e)<=5||["undefined","null",""].includes(e)),{params:{errorMessage:"The value must be within a 0 and 5 range"}}).transform((e=>["undefined","null",""].includes(e)?null:Number(e))),z.number().int().gte(0).lte(5)]).nullable(),logFile:e=>v.string(e).refine((e=>null===e||e.length>=5&&e.endsWith(".log")),{params:{errorMessage:"The value must be a string that ends with .log"}}),logDest:e=>v.string(e),logToConsole:e=>v.boolean(e),logToFile:e=>v.boolean(e),enableUi:e=>v.boolean(e),uiRoute:e=>v.startsWith(["/"],e),nodeEnv:e=>v.enum(["development","production","test"],e),listenToProcessExits:e=>v.boolean(e),noLogo:e=>v.boolean(e),hardResetPage:e=>v.boolean(e),browserShellMode:e=>v.boolean(e),validation:e=>v.boolean(e),enableDebug:e=>v.boolean(e),headless:e=>v.boolean(e),devtools:e=>v.boolean(e),listenToConsole:e=>v.boolean(e),dumpio:e=>v.boolean(e),slowMo:e=>v.nonNegativeNum(e),debuggingPort:e=>v.nonNegativeNum(e),requestId:()=>z.string().uuid({message:"The value must be a stringified UUID"}).nullable()},PuppeteerSchema=e=>z.object({args:validators.args(e)}).partial(),HighchartsSchema=e=>z.object({version:validators.version(e),cdnUrl:validators.cdnUrl(e),forceFetch:validators.forceFetch(e),cachePath:validators.cachePath(e),coreScripts:validators.coreScripts(e),moduleScripts:validators.moduleScripts(e),indicatorScripts:validators.indicatorScripts(e),customScripts:validators.customScripts(e)}).partial(),ExportSchema=e=>z.object({infile:validators.infile(e),instr:validators.instr(),options:validators.options(),svg:validators.svg(),outfile:validators.outfile(e),type:validators.type(e),constr:validators.constr(e),b64:validators.b64(e),noDownload:validators.noDownload(e),defaultHeight:validators.defaultHeight(e),defaultWidth:validators.defaultWidth(e),defaultScale:validators.defaultScale(e),height:validators.height(e),width:validators.width(e),scale:validators.scale(e),globalOptions:validators.globalOptions(),themeOptions:validators.themeOptions(),batch:validators.batch(!1),rasterizationTimeout:validators.rasterizationTimeout(e)}).partial(),CustomLogicSchema=e=>z.object({allowCodeExecution:validators.allowCodeExecution(e),allowFileResources:validators.allowFileResources(e),customCode:validators.customCode(!1),callback:validators.callback(!1),resources:validators.resources(e),loadConfig:validators.loadConfig(!1),createConfig:validators.createConfig(!1)}).partial(),ProxySchema=e=>z.object({host:validators.proxyHost(!1),port:validators.proxyPort(e),timeout:validators.proxyTimeout(e)}).partial(),RateLimitingSchema=e=>z.object({enable:validators.enableRateLimiting(e),maxRequests:validators.maxRequests(e),window:validators.window(e),delay:validators.delay(e),trustProxy:validators.trustProxy(e),skipKey:validators.skipKey(!1),skipToken:validators.skipToken(!1)}).partial(),SslSchema=e=>z.object({enable:validators.enableSsl(e),force:validators.sslForce(e),port:validators.sslPort(e),certPath:validators.sslCertPath(!1)}).partial(),ServerSchema=e=>z.object({enable:validators.enableServer(e).optional(),host:validators.host(e).optional(),port:validators.port(e).optional(),uploadLimit:validators.uploadLimit(e).optional(),benchmarking:validators.serverBenchmarking(e).optional(),proxy:ProxySchema(e).optional(),rateLimiting:RateLimitingSchema(e).optional(),ssl:SslSchema(e).optional()}),PoolSchema=e=>z.object({minWorkers:validators.minWorkers(e),maxWorkers:validators.maxWorkers(e),workLimit:validators.workLimit(e),acquireTimeout:validators.acquireTimeout(e),createTimeout:validators.createTimeout(e),destroyTimeout:validators.destroyTimeout(e),idleTimeout:validators.idleTimeout(e),createRetryInterval:validators.createRetryInterval(e),reaperInterval:validators.reaperInterval(e),benchmarking:validators.poolBenchmarking(e)}).partial(),LoggingSchema=e=>z.object({level:validators.logLevel(e),file:validators.logFile(e),dest:validators.logDest(e),toConsole:validators.logToConsole(e),toFile:validators.logToFile(e)}).partial(),UiSchema=e=>z.object({enable:validators.enableUi(e),route:validators.uiRoute(e)}).partial(),OtherSchema=e=>z.object({nodeEnv:validators.nodeEnv(e),listenToProcessExits:validators.listenToProcessExits(e),noLogo:validators.noLogo(e),hardResetPage:validators.hardResetPage(e),browserShellMode:validators.browserShellMode(e),validation:validators.validation(e)}).partial(),DebugSchema=e=>z.object({enable:validators.enableDebug(e),headless:validators.headless(e),devtools:validators.devtools(e),listenToConsole:validators.listenToConsole(e),dumpio:validators.dumpio(e),slowMo:validators.slowMo(e),debuggingPort:validators.debuggingPort(e)}).partial(),StrictConfigSchema=z.object({requestId:validators.requestId(),puppeteer:PuppeteerSchema(!0),highcharts:HighchartsSchema(!0),export:ExportSchema(!0),customLogic:CustomLogicSchema(!0),server:ServerSchema(!0),pool:PoolSchema(!0),logging:LoggingSchema(!0),ui:UiSchema(!0),other:OtherSchema(!0),debug:DebugSchema(!0)}),LooseConfigSchema=z.object({requestId:validators.requestId(),puppeteer:PuppeteerSchema(!1),highcharts:HighchartsSchema(!1),export:ExportSchema(!1),customLogic:CustomLogicSchema(!1),server:ServerSchema(!1),pool:PoolSchema(!1),logging:LoggingSchema(!1),ui:UiSchema(!1),other:OtherSchema(!1),debug:DebugSchema(!1)}),EnvSchema=z.object({PUPPETEER_ARGS:validators.args(!1),HIGHCHARTS_VERSION:validators.version(!1),HIGHCHARTS_CDN_URL:validators.cdnUrl(!1),HIGHCHARTS_FORCE_FETCH:validators.forceFetch(!1),HIGHCHARTS_CACHE_PATH:validators.cachePath(!1),HIGHCHARTS_ADMIN_TOKEN:validators.adminToken(!1),HIGHCHARTS_CORE_SCRIPTS:validators.coreScripts(!1),HIGHCHARTS_MODULE_SCRIPTS:validators.moduleScripts(!1),HIGHCHARTS_INDICATOR_SCRIPTS:validators.indicatorScripts(!1),HIGHCHARTS_CUSTOM_SCRIPTS:validators.customScripts(!1),EXPORT_INFILE:validators.infile(!1),EXPORT_INSTR:validators.instr(),EXPORT_OPTIONS:validators.options(),EXPORT_SVG:validators.svg(),EXPORT_BATCH:validators.batch(!1),EXPORT_OUTFILE:validators.outfile(!1),EXPORT_TYPE:validators.type(!1),EXPORT_CONSTR:validators.constr(!1),EXPORT_B64:validators.b64(!1),EXPORT_NO_DOWNLOAD:validators.noDownload(!1),EXPORT_HEIGHT:validators.height(!1),EXPORT_WIDTH:validators.width(!1),EXPORT_SCALE:validators.scale(!1),EXPORT_DEFAULT_HEIGHT:validators.defaultHeight(!1),EXPORT_DEFAULT_WIDTH:validators.defaultWidth(!1),EXPORT_DEFAULT_SCALE:validators.defaultScale(!1),EXPORT_GLOBAL_OPTIONS:validators.globalOptions(),EXPORT_THEME_OPTIONS:validators.themeOptions(),EXPORT_RASTERIZATION_TIMEOUT:validators.rasterizationTimeout(!1),CUSTOM_LOGIC_ALLOW_CODE_EXECUTION:validators.allowCodeExecution(!1),CUSTOM_LOGIC_ALLOW_FILE_RESOURCES:validators.allowFileResources(!1),CUSTOM_LOGIC_CUSTOM_CODE:validators.customCode(!1),CUSTOM_LOGIC_CALLBACK:validators.callback(!1),CUSTOM_LOGIC_RESOURCES:validators.resources(!1),CUSTOM_LOGIC_LOAD_CONFIG:validators.loadConfig(!1),CUSTOM_LOGIC_CREATE_CONFIG:validators.createConfig(!1),SERVER_ENABLE:validators.enableServer(!1),SERVER_HOST:validators.host(!1),SERVER_PORT:validators.port(!1),SERVER_UPLOAD_LIMIT:validators.uploadLimit(!1),SERVER_BENCHMARKING:validators.serverBenchmarking(!1),SERVER_PROXY_HOST:validators.proxyHost(!1),SERVER_PROXY_PORT:validators.proxyPort(!1),SERVER_PROXY_TIMEOUT:validators.proxyTimeout(!1),SERVER_RATE_LIMITING_ENABLE:validators.enableRateLimiting(!1),SERVER_RATE_LIMITING_MAX_REQUESTS:validators.maxRequests(!1),SERVER_RATE_LIMITING_WINDOW:validators.window(!1),SERVER_RATE_LIMITING_DELAY:validators.delay(!1),SERVER_RATE_LIMITING_TRUST_PROXY:validators.trustProxy(!1),SERVER_RATE_LIMITING_SKIP_KEY:validators.skipKey(!1),SERVER_RATE_LIMITING_SKIP_TOKEN:validators.skipToken(!1),SERVER_SSL_ENABLE:validators.enableSsl(!1),SERVER_SSL_FORCE:validators.sslForce(!1),SERVER_SSL_PORT:validators.sslPort(!1),SERVER_SSL_CERT_PATH:validators.sslCertPath(!1),POOL_MIN_WORKERS:validators.minWorkers(!1),POOL_MAX_WORKERS:validators.maxWorkers(!1),POOL_WORK_LIMIT:validators.workLimit(!1),POOL_ACQUIRE_TIMEOUT:validators.acquireTimeout(!1),POOL_CREATE_TIMEOUT:validators.createTimeout(!1),POOL_DESTROY_TIMEOUT:validators.destroyTimeout(!1),POOL_IDLE_TIMEOUT:validators.idleTimeout(!1),POOL_CREATE_RETRY_INTERVAL:validators.createRetryInterval(!1),POOL_REAPER_INTERVAL:validators.reaperInterval(!1),POOL_BENCHMARKING:validators.poolBenchmarking(!1),LOGGING_LEVEL:validators.logLevel(!1),LOGGING_FILE:validators.logFile(!1),LOGGING_DEST:validators.logDest(!1),LOGGING_TO_CONSOLE:validators.logToConsole(!1),LOGGING_TO_FILE:validators.logToFile(!1),UI_ENABLE:validators.enableUi(!1),UI_ROUTE:validators.uiRoute(!1),OTHER_NODE_ENV:validators.nodeEnv(!1),OTHER_LISTEN_TO_PROCESS_EXITS:validators.listenToProcessExits(!1),OTHER_NO_LOGO:validators.noLogo(!1),OTHER_HARD_RESET_PAGE:validators.hardResetPage(!1),OTHER_BROWSER_SHELL_MODE:validators.browserShellMode(!1),OTHER_VALIDATION:validators.validation(!1),DEBUG_ENABLE:validators.enableDebug(!1),DEBUG_HEADLESS:validators.headless(!1),DEBUG_DEVTOOLS:validators.devtools(!1),DEBUG_LISTEN_TO_CONSOLE:validators.listenToConsole(!1),DEBUG_DUMPIO:validators.dumpio(!1),DEBUG_SLOW_MO:validators.slowMo(!1),DEBUG_DEBUGGING_PORT:validators.debuggingPort(!1)}),envs=EnvSchema.partial().parse(process.env);function strictValidate(e){return StrictConfigSchema.partial().parse(e)}function looseValidate(e){return LooseConfigSchema.partial().parse(e)}function _customErrorMap(e,t){const o=e.path.join("."),r=`Invalid value for the ${o}`;if(e.code===z.ZodIssueCode.invalid_type)return e.received===z.ZodParsedType.undefined?{message:`${r} - No value was provided.`}:{message:`${r} - Invalid type. ${t.defaultError}.`};if(e.code===z.ZodIssueCode.custom&&e.params?.errorMessage)return{message:`${r} - ${e.params?.errorMessage}, received '${t.data}'.`};if(e.code===z.ZodIssueCode.invalid_union){let t=`Multiple errors occurred for the ${o}:\n`;return e.unionErrors.forEach((e=>{const o=e.issues[0].message.indexOf("-");t+=-1!==o?`${e.issues[0].message}\n`.substring(o):`${e.issues[0].message}\n`})),{message:t}}return{message:`${r} - ${t.defaultError}.`}}class ExportError extends Error{constructor(e,t){super(),this.message=e,this.stackMessage=e,t&&(this.statusCode=t)}setStatus(e){return this.statusCode=e,this}setError(e){return this.error=e,e.name&&(this.name=e.name),e.statusCode&&(this.statusCode=e.statusCode),e.stack&&(this.stackMessage=e.message,this.stack=e.stack),this}}const globalOptions=_initOptions(defaultConfig);function getOptions(e=!0){return e?deepCopy(globalOptions):globalOptions}function updateOptions(e,t=!1){return _mergeOptions(getOptions(t),e)}function mapToNewOptions(e){const t={};if(isObject(e))for(const[o,r]of Object.entries(e)){const e=nestedProps[o]?nestedProps[o].split("."):[];e.reduce(((t,o,i)=>t[o]=e.length-1===i?r:t[o]||{}),t)}else log(2,"[config] No correct object with options was provided. Returning an empty array.");return t}function validateOption(e,t,o=!0){if(!getOptions().other.validation)return t;try{return validators[e](o).parse(t)}catch(t){throw logZodIssues(1,t.issues,`[validation] The ${e} option validation error`),new ExportError(`[validation] The ${e} option validation error`,400)}}function validateOptions(e,t=!0){if(!getOptions().other.validation)return e;try{return t?strictValidate(e):looseValidate(e)}catch(e){throw logZodIssues(1,e.issues,"[validation] Options validation error"),new ExportError("[validation] Options validation error",400)}}function isAllowedConfig(config,toString=!1,allowFunctions=!1){try{if(!isObject(config)&&"string"!=typeof config)return null;const objectConfig="string"==typeof config?allowFunctions?eval(`(${config})`):JSON.parse(config):config,stringifiedOptions=_optionsStringify(objectConfig,allowFunctions,!1),parsedOptions=allowFunctions?JSON.parse(_optionsStringify(objectConfig,allowFunctions,!0),((_,value)=>"string"==typeof value&&value.startsWith("function")?eval(`(${value})`):value)):JSON.parse(stringifiedOptions);return toString?stringifiedOptions:parsedOptions}catch(e){return null}}function _initOptions(e){const t={};for(const[o,r]of Object.entries(e))Object.prototype.hasOwnProperty.call(r,"value")?void 0!==envs[r.envLink]&&null!==envs[r.envLink]?t[o]=envs[r.envLink]:t[o]=r.value:t[o]=_initOptions(r);return t}function _mergeOptions(e,t){if(isObject(e)&&isObject(t))for(const[o,r]of Object.entries(t))e[o]=isObject(r)&&!absoluteProps.includes(o)&&void 0!==e[o]?_mergeOptions(e[o],r):void 0!==r?r:e[o]||null;return e}function _optionsStringify(e,t,o){return JSON.stringify(e,((e,r)=>{if("string"==typeof r&&(r=r.trim()),"function"==typeof r||"string"==typeof r&&r.startsWith("function")&&r.endsWith("}")){if(t)return o?`"EXP_FUN${(r+"").replaceAll(/\s+/g," ")}EXP_FUN"`:`EXP_FUN${(r+"").replaceAll(/\s+/g," ")}EXP_FUN`;throw new Error}return r})).replaceAll(o?/\\"EXP_FUN|EXP_FUN\\"/g:/"EXP_FUN|EXP_FUN"/g,"")}async function fetch(e,t={}){return new Promise(((o,r)=>{_getProtocolModule(e).get(e,t,(e=>{let t="";e.on("data",(e=>{t+=e})),e.on("end",(()=>{t||r("Nothing was fetched from the URL."),e.text=t,o(e)}))})).on("error",(e=>{r(e)}))}))}function _getProtocolModule(e){return e.startsWith("https")?https:http}const cache={cdnUrl:"https://code.highcharts.com",activeManifest:{},sources:"",hcVersion:""};async function checkAndUpdateCache(e,t){try{let o;const r=getCachePath(),i=join(r,"manifest.json"),n=join(r,"sources.js");if(!existsSync(r)&&mkdirSync(r,{recursive:!0}),!existsSync(i)||e.forceFetch)log(3,"[cache] Fetching and caching Highcharts dependencies."),o=await _updateCache(e,t,n);else{let r=!1;const s=JSON.parse(readFileSync(i),"utf8");if(s.modules&&Array.isArray(s.modules)){const e={};s.modules.forEach((t=>e[t]=1)),s.modules=e}const{coreScripts:a,moduleScripts:l,indicatorScripts:c}=e,p=a.length+l.length+c.length;s.version!==e.version?(log(2,"[cache] A Highcharts version mismatch in the cache, need to re-fetch."),r=!0):Object.keys(s.modules||{}).length!==p?(log(2,"[cache] The cache and the requested modules do not match, need to re-fetch."),r=!0):r=(l||[]).some((e=>{if(!s.modules[e])return log(2,`[cache] The ${e} is missing in the cache, need to re-fetch.`),!0})),r?o=await _updateCache(e,t,n):(log(3,"[cache] Dependency cache is up to date, proceeding."),cache.sources=readFileSync(n,"utf8"),o=s.modules,cache.hcVersion=extractVersion(cache.sources))}await _saveConfigToManifest(e,o)}catch(e){throw new ExportError("[cache] Could not configure cache and create or update the config manifest.",500).setError(e)}}function getHighchartsVersion(){return cache.hcVersion}async function updateHighchartsVersion(e){const t=updateOptions({highcharts:{version:e}});await checkAndUpdateCache(t.highcharts,t.server.proxy)}function extractVersion(e){return e.substring(0,e.indexOf("*/")).replace("/*","").replace("*/","").replace(/\n/g,"").trim()}function extractModuleName(e){return e.replace(/(.*)\/|(.*)modules\/|stock\/(.*)indicators\/|maps\/(.*)modules\//gi,"")}function getCachePath(){return getAbsolutePath(getOptions().highcharts.cachePath)}async function _fetchAndProcessScript(e,t,o,r=!1){e.endsWith(".js")&&(e=e.substring(0,e.length-3)),log(4,`[cache] Fetching script - ${e}.js`);const i=await fetch(`${e}.js`,t);if(200===i.statusCode&&"string"==typeof i.text){if(o){o[extractModuleName(e)]=1}return i.text}if(r)throw new ExportError(`[cache] Could not fetch the ${e}.js. The script might not exist in the requested version (status code: ${i.statusCode}).`,404).setError(i);log(2,`[cache] Could not fetch the ${e}.js. The script might not exist in the requested version.`)}async function _saveConfigToManifest(e,t={}){const o={version:e.version,modules:t};cache.activeManifest=o,log(3,"[cache] Writing a new manifest.");try{writeFileSync(join(getCachePath(),"manifest.json"),JSON.stringify(o),"utf8")}catch(e){throw new ExportError("[cache] Error writing the cache manifest.",500).setError(e)}}async function _fetchScripts(e,t,o,r,i){let n;const s=r.host,a=r.port;if(s&&a)try{n=new HttpsProxyAgent({host:s,port:a})}catch(e){throw new ExportError("[cache] Could not create a Proxy Agent.",500).setError(e)}const l=n?{agent:n,timeout:r.timeout}:{},c=[...e.map((e=>_fetchAndProcessScript(`${e}`,l,i,!0))),...t.map((e=>_fetchAndProcessScript(`${e}`,l,i))),...o.map((e=>_fetchAndProcessScript(`${e}`,l)))];return(await Promise.all(c)).join(";\n")}async function _updateCache(e,t,o){const r="latest"===e.version?null:`${e.version}`,i=e.cdnUrl||cache.cdnUrl;try{const n={};return log(3,`[cache] Updating cache version to Highcharts: ${r||"latest"}.`),cache.sources=await _fetchScripts([...e.coreScripts.map((e=>r?`${i}/${r}/${e}`:`${i}/${e}`))],[...e.moduleScripts.map((e=>"map"===e?r?`${i}/maps/${r}/modules/${e}`:`${i}/maps/modules/${e}`:r?`${i}/${r}/modules/${e}`:`${i}/modules/${e}`)),...e.indicatorScripts.map((e=>r?`${i}/stock/${r}/indicators/${e}`:`${i}/stock/indicators/${e}`))],e.customScripts,t,n),cache.hcVersion=extractVersion(cache.sources),writeFileSync(o,cache.sources),n}catch(e){throw new ExportError("[cache] Unable to update the local Highcharts cache.",500).setError(e)}}function setupHighcharts(){Highcharts.animObject=function(){return{duration:0}}}async function createChart(e,t){const{getOptions:o,setOptions:r,merge:i,wrap:n}=Highcharts;Highcharts.setOptionsObj=i(!1,{},o()),window.isRenderComplete=!1,n(Highcharts.Chart.prototype,"init",(function(e,t,o){((t=i(t,{exporting:{enabled:!1},plotOptions:{series:{label:{enabled:!1}}},tooltip:{}})).series||[]).forEach((function(e){e.animation=!1})),window.onHighchartsRender||(window.onHighchartsRender=Highcharts.addEvent(this,"render",(()=>{window.isRenderComplete=!0}))),e.apply(this,[t,o])})),n(Highcharts.Series.prototype,"init",(function(e,t,o){e.apply(this,[t,o])}));const s={chart:{animation:!1,height:e.height,width:e.width},exporting:{enabled:!1}},a=new Function(`return ${e.instr}`)(),l=new Function(`return ${e.themeOptions}`)(),c=new Function(`return ${e.globalOptions}`)(),p=i(!1,l,a,s),u=t.callback?new Function(`return ${t.callback}`)():null;t.customCode&&new Function("options",t.customCode)(a),c&&r(c),Highcharts[e.constr]("container",p,u);const d=o();for(const e in d)"function"!=typeof d[e]&&delete d[e];r(Highcharts.setOptionsObj),Highcharts.setOptionsObj={}}const template=readFileSync(join(__dirname,"templates","template.html"),"utf8");let browser=null;async function createBrowser(e){const{debug:t,other:o}=getOptions(),{enable:r,...i}=t,n={headless:!o.browserShellMode||"shell",userDataDir:"tmp",args:e||[],handleSIGINT:!1,handleSIGTERM:!1,handleSIGHUP:!1,waitForInitialPage:!1,defaultViewport:null,...r&&i};if(!browser){let e=0;const t=async()=>{try{log(3,`[browser] Attempting to get a browser instance (try ${++e}).`),browser=await puppeteer.launch(n)}catch(o){if(logWithStack(1,o,"[browser] Failed to launch a browser instance."),!(e<25))throw o;log(3,`[browser] Retry to open a browser (${e} out of 25).`),await new Promise((e=>setTimeout(e,4e3))),await t()}};try{await t(),"shell"===n.headless&&log(3,"[browser] Launched browser in shell mode."),r&&log(3,"[browser] Launched browser in debug mode.")}catch(e){throw new ExportError("[browser] Maximum retries to open a browser instance reached.",500).setError(e)}if(!browser)throw new ExportError("[browser] Cannot find a browser to open.",500)}return browser}async function closeBrowser(){browser&&browser.connected&&await browser.close(),browser=null,log(4,"[browser] Closed the browser.")}async function newPage(e){if(!browser||!browser.connected)throw new ExportError("[browser] Browser is not yet connected.",500);if(e.page=await browser.newPage(),await e.page.setCacheEnabled(!1),await _setPageContent(e.page),_setPageEvents(e.page),!e.page||e.page.isClosed())throw new ExportError("[browser] The page is invalid or closed.",400)}async function clearPage(e,t=!1){try{if(e.page&&!e.page.isClosed())return t?(await e.page.goto("about:blank",{waitUntil:"domcontentloaded"}),await _setPageContent(e.page)):await e.page.evaluate((()=>{document.body.innerHTML='
'})),!0}catch(t){logWithStack(2,t,`[pool] Pool resource [${e.id}] - Content of the page could not be cleared.`),e.workCount=getOptions().pool.workLimit+1}return!1}async function addPageResources(e,t){const o=[],r=t.resources;if(r){const i=[];if(r.js&&i.push({content:r.js}),r.files)for(const e of r.files){const t=!e.startsWith("http");i.push(t?{content:readFileSync(getAbsolutePath(e),"utf8")}:{url:e})}for(const t of i)try{o.push(await e.addScriptTag(t))}catch(e){logWithStack(2,e,"[browser] The JS resource cannot be loaded.")}i.length=0;const n=[];if(r.css){let i=r.css.match(/@import\s*([^;]*);/g);if(i)for(let e of i)e&&(e=e.replace("url(","").replace("@import","").replace(/"/g,"").replace(/'/g,"").replace(/;/,"").replace(/\)/g,"").trim(),e.startsWith("http")?n.push({url:e}):t.allowFileResources&&n.push({path:getAbsolutePath(e)}));n.push({content:r.css.replace(/@import\s*([^;]*);/g,"")||" "});for(const t of n)try{o.push(await e.addStyleTag(t))}catch(e){logWithStack(2,e,"[browser] The CSS resource cannot be loaded.")}n.length=0}}return o}async function clearPageResources(e,t){try{for(const e of t)await e.dispose();await e.evaluate((()=>{if("undefined"!=typeof Highcharts){const e=Highcharts.charts;if(Array.isArray(e)&&e.length)for(const t of e)t&&t.destroy(),Highcharts.charts.shift()}const[...e]=document.getElementsByTagName("script"),[,...t]=document.getElementsByTagName("style"),[...o]=document.getElementsByTagName("link");for(const r of[...e,...t,...o])r.remove()}))}catch(e){logWithStack(2,e,"[browser] Could not clear page's resources.")}}async function _setPageContent(e){await e.setContent(template,{waitUntil:"domcontentloaded"}),await e.addScriptTag({path:join(getCachePath(),"sources.js")}),await e.evaluate(setupHighcharts)}function _setPageEvents(e){const{debug:t}=getOptions();e.on("pageerror",(async()=>{e.isClosed()})),t.enable&&t.listenToConsole&&e.on("console",(e=>{console.log(`[debug] ${e.text()}`)}))}var cssTemplate=()=>"\n\nhtml, body {\n margin: 0;\n padding: 0;\n box-sizing: border-box;\n}\n\n#table-div, #sliders, #datatable, #controls, .ld-row {\n display: none;\n height: 0;\n}\n\n#chart-container {\n box-sizing: border-box;\n margin: 0;\n overflow: auto;\n font-size: 0;\n}\n\n#chart-container > figure, div {\n margin-top: 0 !important;\n margin-bottom: 0 !important;\n}\n\n",svgTemplate=e=>`\n\n\n \n \n Highcharts Export\n \n \n \n
\n ${e}\n
\n \n\n\n`;async function puppeteerExport(e,t,o){const r=[];try{let i=!1;if(t.svg){if(log(4,"[export] Treating as SVG input."),"svg"===t.type)return t.svg;i=!0,await e.setContent(svgTemplate(t.svg),{waitUntil:"domcontentloaded"})}else log(4,"[export] Treating as JSON config."),await e.evaluate(createChart,t,o);r.push(...await addPageResources(e,o));const n=i?await e.evaluate((e=>{const t=document.querySelector("#chart-container svg:first-of-type"),o=t.height.baseVal.value*e,r=t.width.baseVal.value*e;return document.body.style.zoom=e,document.body.style.margin="0px",{chartHeight:o,chartWidth:r}}),parseFloat(t.scale)):await e.evaluate((()=>{const{chartHeight:e,chartWidth:t}=window.Highcharts.charts[0];return document.body.style.zoom=1,{chartHeight:e,chartWidth:t}})),{x:s,y:a}=await _getClipRegion(e),l=Math.abs(Math.ceil(n.chartHeight||t.height)),c=Math.abs(Math.ceil(n.chartWidth||t.width));let p;switch(await e.setViewport({height:l,width:c,deviceScaleFactor:i?1:parseFloat(t.scale)}),t.type){case"svg":p=await _createSVG(e);break;case"png":case"jpeg":p=await _createImage(e,t.type,{width:c,height:l,x:s,y:a},t.rasterizationTimeout);break;case"pdf":p=await _createPDF(e,l,c,t.rasterizationTimeout);break;default:throw new ExportError(`[export] Unsupported output format: ${t.type}.`,400)}return await clearPageResources(e,r),p}catch(t){return await clearPageResources(e,r),t}}async function _getClipRegion(e){return e.$eval("#chart-container",(e=>{const{x:t,y:o,width:r,height:i}=e.getBoundingClientRect();return{x:t,y:o,width:r,height:Math.trunc(i>1?i:500)}}))}async function _createSVG(e){return e.$eval("#container svg:first-of-type",(e=>e.outerHTML))}async function _createImage(e,t,o,r){return Promise.race([e.screenshot({type:t,clip:o,encoding:"base64",fullPage:!1,optimizeForSpeed:!0,captureBeyondViewport:!0,..."png"!==t?{quality:80}:{},omitBackground:"png"==t}),new Promise(((e,t)=>setTimeout((()=>t(new ExportError("Rasterization timeout",408))),r||1500)))])}async function _createPDF(e,t,o,r){return await e.emulateMediaType("screen"),e.pdf({height:t+1,width:o,encoding:"base64",timeout:r||1500})}let pool=null;const poolStats={exportsAttempted:0,exportsPerformed:0,exportsDropped:0,exportsFromSvg:0,exportsFromOptions:0,exportsFromSvgAttempts:0,exportsFromOptionsAttempts:0,timeSpent:0,timeSpentAverage:0};async function initPool(e,t){await createBrowser(t);try{if(log(3,`[pool] Initializing pool with workers: min ${e.minWorkers}, max ${e.maxWorkers}.`),pool)return void log(4,"[pool] Already initialized, please kill it before creating a new one.");e.minWorkers>e.maxWorkers&&(e.minWorkers=e.maxWorkers),pool=new Pool({..._factory(e),min:e.minWorkers,max:e.maxWorkers,acquireTimeoutMillis:e.acquireTimeout,createTimeoutMillis:e.createTimeout,destroyTimeoutMillis:e.destroyTimeout,idleTimeoutMillis:e.idleTimeout,createRetryIntervalMillis:e.createRetryInterval,reapIntervalMillis:e.reaperInterval,propagateCreateError:!1}),pool.on("release",(async e=>{const t=await clearPage(e,!1);log(4,`[pool] Pool resource [${e.id}] - Releasing a worker. Clear page status: ${t}.`)})),pool.on("destroySuccess",((e,t)=>{log(4,`[pool] Pool resource [${t.id}] - Destroyed a worker successfully.`),t.page=null}));const t=[];for(let o=0;o{pool.release(e)})),log(3,"[pool] The pool is ready"+(t.length?` with ${t.length} initial resources waiting.`:"."))}catch(e){throw new ExportError("[pool] Could not configure and create the pool of workers.",500).setError(e)}}async function killPool(){if(log(3,"[pool] Killing pool with all workers and closing browser."),pool){for(const e of pool.used)pool.release(e.resource);pool.destroyed||(await pool.destroy(),log(4,"[pool] Destroyed the pool of resources.")),pool=null}await closeBrowser()}async function postWork(e){let t;try{if(log(4,"[pool] Work received, starting to process."),++poolStats.exportsAttempted,e.pool.benchmarking&&getPoolInfo(),!pool)throw new ExportError("[pool] Work received, but pool has not been started.",500);const o=measureTime();try{log(4,"[pool] Acquiring a worker handle."),t=await pool.acquire().promise,e.server.benchmarking&&log(5,"[benchmark] "+(e.requestId?`Request [${e.requestId}] - `:""),`Acquiring a worker handle took ${o()}ms.`)}catch(t){throw new ExportError(`[pool] ${e.requestId?`Request [${e.requestId}] - `:""}Error encountered when acquiring an available entry: ${o()}ms.`,400).setError(t)}if(log(4,"[pool] Acquired a worker handle."),!t.page)throw t.workCount=e.pool.workLimit+1,new ExportError("[pool] Resolved worker page is invalid: the pool setup is wonky.",400);const r=getNewDateTime();log(4,`[pool] Pool resource [${t.id}] - Starting work on this pool entry.`);const i=measureTime(),n=await puppeteerExport(t.page,e.export,e.customLogic);if(n instanceof Error)throw"Rasterization timeout"===n.message&&(t.workCount=e.pool.workLimit+1,t.page=null),"TimeoutError"===n.name||"Rasterization timeout"===n.message?new ExportError(`[pool] ${e.requestId?`Request [${e.requestId}] - `:""}Rasterization timeout: your chart may be too complex or large, and failed to render within the allotted time.`).setError(n):new ExportError(`[pool] ${e.requestId?`Request [${e.requestId}] - `:""}Error encountered during export: ${i()}ms.`).setError(n);e.server.benchmarking&&log(5,"[benchmark] "+(e.requestId?`Request [${e.requestId}] - `:""),`Exporting a chart sucessfully took ${i()}ms.`),pool.release(t);const s=getNewDateTime()-r;return poolStats.timeSpent+=s,poolStats.timeSpentAverage=poolStats.timeSpent/++poolStats.exportsPerformed,log(4,`[pool] Work completed in ${s}ms.`),{result:n,options:e}}catch(e){throw++poolStats.exportsDropped,t&&pool.release(t),e}}function getPoolStats(){return poolStats}function getPoolInfoJSON(){return{min:pool.min,max:pool.max,used:pool.numUsed(),available:pool.numFree(),allCreated:pool.numUsed()+pool.numFree(),pendingAcquires:pool.numPendingAcquires(),pendingCreates:pool.numPendingCreates(),pendingValidations:pool.numPendingValidations(),pendingDestroys:pool.pendingDestroys.length,absoluteAll:pool.numUsed()+pool.numFree()+pool.numPendingAcquires()+pool.numPendingCreates()+pool.numPendingValidations()+pool.pendingDestroys.length}}function getPoolInfo(){const{min:e,max:t,used:o,available:r,allCreated:i,pendingAcquires:n,pendingCreates:s,pendingValidations:a,pendingDestroys:l,absoluteAll:c}=getPoolInfoJSON();log(5,`[pool] The minimum number of resources allowed by pool: ${e}.`),log(5,`[pool] The maximum number of resources allowed by pool: ${t}.`),log(5,`[pool] The number of used resources: ${o}.`),log(5,`[pool] The number of free resources: ${r}.`),log(5,`[pool] The number of all created (used and free) resources: ${i}.`),log(5,`[pool] The number of resources waiting to be acquired: ${n}.`),log(5,`[pool] The number of resources waiting to be created: ${s}.`),log(5,`[pool] The number of resources waiting to be validated: ${a}.`),log(5,`[pool] The number of resources waiting to be destroyed: ${l}.`),log(5,`[pool] The number of all resources: ${c}.`)}function _factory(e){return{create:async()=>{const t={id:v4(),workCount:Math.round(Math.random()*(e.workLimit/2))};try{const e=getNewDateTime();return await newPage(t),log(3,`[pool] Pool resource [${t.id}] - Successfully created a worker, took ${getNewDateTime()-e}ms.`),t}catch(e){throw log(3,`[pool] Pool resource [${t.id}] - Error encountered when creating a new page.`),e}},validate:async t=>t.page?t.page.isClosed()?(log(3,`[pool] Pool resource [${t.id}] - Validation failed (page is closed or invalid).`),!1):t.page.mainFrame().detached?(log(3,`[pool] Pool resource [${t.id}] - Validation failed (page's frame is detached).`),!1):!(e.workLimit&&++t.workCount>e.workLimit)||(log(3,`[pool] Pool resource [${t.id}] - Validation failed (exceeded the ${e.workLimit} works per resource limit).`),!1):(log(3,`[pool] Pool resource [${t.id}] - Validation failed (no valid page is found).`),!1),destroy:async e=>{if(log(3,`[pool] Pool resource [${e.id}] - Destroying a worker.`),e.page&&!e.page.isClosed())try{e.page.removeAllListeners("pageerror"),e.page.removeAllListeners("console"),e.page.removeAllListeners("framedetached"),await e.page.close()}catch(t){throw log(3,`[pool] Pool resource [${e.id}] - Page could not be closed upon destroying.`),t}}}}function sanitize(e){const t=new JSDOM("").window;return DOMPurify(t).sanitize(e,{ADD_TAGS:["foreignObject"]})}let allowCodeExecution=!1;async function singleExport(e){if(!e||!e.export)throw new ExportError("[chart] No expected `export` options were found. Please provide one of the following options: `infile`, `instr`, `options`, or `svg` to generate a valid image.",400);e=validateOptions(e),await startExport({export:e.export,customLogic:e.customLogic},(async(e,t)=>{if(e)throw e;const{b64:o,outfile:r,type:i}=t.options.export;try{o?writeFileSync(`${r.split(".").shift()||"chart"}.txt`,getBase64(t.result,i)):writeFileSync(r||`chart.${i}`,"svg"!==i?Buffer.from(t.result,"base64"):t.result)}catch(e){throw new ExportError("[chart] Error while saving a chart.",500).setError(e)}await killPool()}))}async function batchExport(e){if(!(e&&e.export&&e.export.batch))throw new ExportError("[chart] No expected `export` options were found. Please provide the `batch` option to generate valid images.",400);{e=validateOptions(e);const t=[];for(let o of e.export.batch.split(";")||[])o=o.split("="),2===o.length?t.push(startExport({export:{...e.export,infile:o[0],outfile:o[1]},customLogic:e.customLogic},((e,t)=>{if(e)throw e;const{b64:o,outfile:r,type:i}=t.options.export;try{o?writeFileSync(`${r.split(".").shift()||"chart"}.txt`,getBase64(t.result,i)):writeFileSync(r,"svg"!==i?Buffer.from(t.result,"base64"):t.result)}catch(e){throw new ExportError("[chart] Error while saving a chart.",500).setError(e)}}))):log(2,"[chart] No correct pair found for the batch export.");const o=await Promise.allSettled(t);await killPool(),o.forEach(((e,t)=>{e.reason&&logWithStack(1,e.reason,`[chart] Batch export number ${t+1} could not be correctly completed.`)}))}}async function startExport(e,t){try{if(!isObject(e))throw new ExportError("[chart] Incorrect value of the provided `imageOptions`. Needs to be an object.",400);const o=updateOptions({export:e.export,customLogic:e.customLogic},!0),r=o.export;if(log(4,"[chart] Starting the exporting process."),null!==r.infile){let e;log(4,"[chart] Attempting to export from a file input.");try{e=readFileSync(getAbsolutePath(r.infile),"utf8")}catch(e){throw new ExportError("[chart] Error loading content from a file input.",400).setError(e)}if(r.infile.endsWith(".svg"))r.svg=validateOption("svg",e);else{if(!r.infile.endsWith(".json"))throw new ExportError("[chart] Incorrect value of the `infile` option.",400);r.instr=validateOption("instr",e)}}if(null!==r.svg){log(4,"[chart] Attempting to export from an SVG input."),++getPoolStats().exportsFromSvgAttempts;const e=await _exportFromSvg(sanitize(r.svg),o);return++getPoolStats().exportsFromSvg,t(null,e)}if(null!==r.instr||null!==r.options){log(4,"[chart] Attempting to export from options input."),++getPoolStats().exportsFromOptionsAttempts;const e=await _exportFromOptions(r.instr||r.options,o);return++getPoolStats().exportsFromOptions,t(null,e)}return t(new ExportError("[chart] No valid input specified. Check if at least one of the following parameters is correctly set: 'infile', 'instr', 'options', or 'svg'.",400))}catch(e){return t(e)}}function getAllowCodeExecution(){return allowCodeExecution}function setAllowCodeExecution(e){allowCodeExecution=e}async function _exportFromSvg(e,t){if("string"==typeof e&&(e.indexOf("=0||e.indexOf("=0))return log(4,"[chart] Parsing input as SVG."),t.export.svg=e,t.export.instr=null,t.export.options=null,_prepareExport(t);throw new ExportError("[chart] Not a correct SVG input.",400)}async function _exportFromOptions(e,t){log(4,"[chart] Parsing input from options.");const o=isAllowedConfig(e,!0,t.customLogic.allowCodeExecution);if(null===o||"string"!=typeof o||!o.startsWith("{")||!o.endsWith("}"))throw new ExportError("[chart] Invalid configuration provided - Only options configurations and SVG are allowed for this server. If this is your server, JavaScript custom code can be enabled by starting the server with the `allowCodeExecution` options set to true.",403);return t.export.instr=o,t.export.svg=null,_prepareExport(t)}async function _prepareExport(e){const{export:t,customLogic:o}=e;return t.type=fixType(t.type,t.outfile),t.outfile=fixOutfile(t.type,t.outfile),t.constr=fixConstr(t.constr),log(3,`[chart] The custom logic is ${o.allowCodeExecution?"allowed":"disallowed"}.`),_handleCustomLogic(o,o.allowCodeExecution),_handleGlobalAndTheme(t,o.allowFileResources,o.allowCodeExecution),e.export={...t,..._findChartSize(t)},postWork(e)}function _findChartSize(e){const{chart:t,exporting:o}=e.options||isAllowedConfig(e.instr)||!1,{chart:r,exporting:i}=isAllowedConfig(e.globalOptions)||!1,{chart:n,exporting:s}=isAllowedConfig(e.themeOptions)||!1,a=roundNumber(Math.max(.1,Math.min(e.scale||o?.scale||i?.scale||s?.scale||e.defaultScale||1,5)),2),l={height:e.height||o?.sourceHeight||t?.height||i?.sourceHeight||r?.height||s?.sourceHeight||n?.height||e.defaultHeight||400,width:e.width||o?.sourceWidth||t?.width||i?.sourceWidth||r?.width||s?.sourceWidth||n?.width||e.defaultWidth||600,scale:a};for(let[e,t]of Object.entries(l))l[e]="string"==typeof t?+t.replace(/px|%/gi,""):t;return l}function _handleCustomLogic(e,t){if(t){if("string"==typeof e.resources)e.resources=_handleResources(e.resources,e.allowFileResources,!0);else if(!e.resources)try{e.resources=_handleResources(readFileSync(getAbsolutePath("resources.json"),"utf8"),e.allowFileResources,!0)}catch(e){log(2,"[chart] Unable to load the default `resources.json` file.")}try{e.customCode=wrapAround(e.customCode,e.allowFileResources),e.customCode=validateOption("customCode",e.customCode)}catch(t){logWithStack(2,t,"[chart] The `customCode` cannot be loaded."),e.customCode=null}try{e.callback=wrapAround(e.callback,e.allowFileResources,!0),e.callback=validateOption("callback",e.callback)}catch(t){logWithStack(2,t,"[chart] The `callback` cannot be loaded."),e.callback=null}[null,void 0].includes(e.customCode)&&log(3,"[chart] No value for the `customCode` option found."),[null,void 0].includes(e.callback)&&log(3,"[chart] No value for the `callback` option found."),[null,void 0].includes(e.resources)&&log(3,"[chart] No value for the `resources` option found.")}else if(e.callback||e.resources||e.customCode)throw e.callback=null,e.resources=null,e.customCode=null,new ExportError("[chart] The 'callback', 'resources', and 'customCode' options have been disabled for this server.",403)}function _handleResources(e=null,t,o){const r=["js","css","files"];let i=e,n=!1;if(t&&e.endsWith(".json"))try{i=isAllowedConfig(readFileSync(getAbsolutePath(e),"utf8"),!1,o)}catch{return null}else i=isAllowedConfig(e,!1,o),i&&!t&&delete i.files;for(const e in i)r.includes(e)?n||(n=!0):delete i[e];return n?(i.files&&(i.files=i.files.map((e=>e.trim())),(!i.files||i.files.length<=0)&&delete i.files),i=validateOption("resources",i),i):null}function _handleGlobalAndTheme(e,t,o){["globalOptions","themeOptions"].forEach((r=>{try{e[r]&&(t&&"string"==typeof e[r]&&e[r].endsWith(".json")?e[r]=isAllowedConfig(readFileSync(getAbsolutePath(e[r]),"utf8"),!0,o):e[r]=isAllowedConfig(e[r],!0,o),e[r]=validateOption(r,e[r]))}catch(t){logWithStack(2,t,`[chart] The \`${r}\` cannot be loaded.`),e[r]=null}})),[null,void 0].includes(e.globalOptions)&&log(3,"[chart] No value for the `globalOptions` option found."),[null,void 0].includes(e.themeOptions)&&log(3,"[chart] No value for the `themeOptions` option found.")}const timerIds=[];function addTimer(e){timerIds.push(e)}function clearAllTimers(){log(4,"[timer] Clearing all registered intervals and timeouts.");for(const e of timerIds)clearInterval(e),clearTimeout(e)}function logErrorMiddleware(e,t,o,r){return logWithStack(1,e),"development"!==getOptions().other.nodeEnv&&delete e.stack,r(e)}function returnErrorMiddleware(e,t,o,r){const{message:i,stack:n}=e,s=e.statusCode||400;o.status(s).json({statusCode:s,message:i,stack:n})}function errorMiddleware(e){e.use(logErrorMiddleware),e.use(returnErrorMiddleware)}function rateLimitingMiddleware(e,t){try{if(e&&t.enable){const o="Too many requests, you have been rate limited. Please try again later.",r={window:t.window||1,maxRequests:t.maxRequests||30,delay:t.delay||0,trustProxy:t.trustProxy||!1,skipKey:t.skipKey||null,skipToken:t.skipToken||null};r.trustProxy&&e.enable("trust proxy");const i=rateLimit({windowMs:60*r.window*1e3,limit:r.maxRequests,delayMs:r.delay,handler:(e,t)=>{t.format({json:()=>{t.status(429).send({message:o})},default:()=>{t.status(429).send(o)}})},skip:e=>null!==r.skipKey&&null!==r.skipToken&&e.query.key===r.skipKey&&e.query.access_token===r.skipToken&&(log(4,"[rate limiting] Skipping rate limiter."),!0)});e.use(i),log(3,`[rate limiting] Enabled rate limiting with ${r.maxRequests} requests per ${r.window} minute for each IP, trusting proxy: ${r.trustProxy}.`)}}catch(e){throw new ExportError("[rate limiting] Could not configure and set the rate limiting options.",500).setError(e)}}function contentTypeMiddleware(e,t,o){try{const t=e.headers["content-type"]||"";if(!t.includes("application/json")&&!t.includes("application/x-www-form-urlencoded")&&!t.includes("multipart/form-data"))throw new ExportError("[validation] Content-Type must be application/json, application/x-www-form-urlencoded, or multipart/form-data.",415);return o()}catch(e){return o(e)}}function requestBodyMiddleware(e,t,o){try{const t=e.body,r=v4();if(!t||isObjectEmpty(t))throw log(2,`[validation] Request [${r}] - The request from ${e.headers["x-forwarded-for"]||e.connection.remoteAddress} was incorrect. Received payload is empty.`),new ExportError(`[validation] Request [${r}] - The request body is required. Please ensure that your Content-Type header is correct. Accepted types are 'application/json' and 'multipart/form-data'.`,400);const i=getAllowCodeExecution(),n=isAllowedConfig(t.instr||t.options||t.infile||t.data,!0,i);if(null===n&&!t.svg)throw log(2,`[validation] Request [${r}] - The request from ${e.headers["x-forwarded-for"]||e.connection.remoteAddress} was incorrect. Received payload is missing correct chart data for export: ${JSON.stringify(t)}.`),new ExportError(`Request [${r}] - [validation] No correct chart data found. Ensure that you are using either application/json or multipart/form-data headers. If sending JSON, make sure the chart data is in the 'infile', 'options', or 'data' attribute. If sending SVG, ensure it is in the 'svg' attribute.`,400);if(t.svg&&isPrivateRangeUrlFound(t.svg))throw new ExportError(`Request [${r}] - [validation] SVG potentially contain at least one forbidden URL in 'xlink:href' element. Please review the SVG content and ensure that all referenced URLs comply with security policies.`,400);return e.validatedOptions=validateOptions({requestId:r,export:{instr:n,svg:t.svg,outfile:t.outfile||`${e.params.filename||"chart"}.${t.type||"png"}`,type:t.type,constr:t.constr,b64:t.b64,noDownload:t.noDownload,height:t.height,width:t.width,scale:t.scale,globalOptions:isAllowedConfig(t.globalOptions,!0,i),themeOptions:isAllowedConfig(t.themeOptions,!0,i)},customLogic:{allowCodeExecution:i,allowFileResources:!1,customCode:t.customCode,callback:t.callback,resources:isAllowedConfig(t.resources,!0,i)}}),o()}catch(e){return o(e)}}function validationMiddleware(e){e.post(["/","/:filename"],contentTypeMiddleware),e.post(["/","/:filename"],requestBodyMiddleware)}const reversedMime={png:"image/png",jpeg:"image/jpeg",gif:"image/gif",pdf:"application/pdf",svg:"image/svg+xml"};async function requestExport(e,t,o){try{const o=measureTime();let r=!1;e.socket.on("close",(e=>{e&&(r=!0)}));const i=e.validatedOptions,n=i.requestId;log(4,`[export] Request [${n}] - Got an incoming HTTP request.`),await startExport(i,((i,s)=>{if(e.socket.removeAllListeners("close"),r)log(3,`[export] Request [${n}] - The client closed the connection before the chart finished processing.`);else{if(i)throw i;if(!s||!s.result)throw log(2,`[export] Request [${n}] - Request from ${e.headers["x-forwarded-for"]||e.connection.remoteAddress} was incorrect. Received result is ${s.result}.`),new ExportError(`[export] Request [${n}] - Unexpected return of the export result from the chart generation. Please check your request data.`,400);if(s.result){log(3,`[export] Request [${n}] - The whole exporting process took ${o()}ms.`);const{type:e,b64:r,noDownload:i,outfile:a}=s.options.export;return r?t.send(getBase64(s.result,e)):(t.header("Content-Type",reversedMime[e]||"image/png"),i||t.attachment(a),"svg"===e?t.send(s.result):t.send(Buffer.from(s.result,"base64")))}}}))}catch(e){return o(e)}}function exportRoutes(e){e.post("/",requestExport),e.post("/:filename",requestExport)}const serverStartTime=new Date,packageFile=JSON.parse(readFileSync(join(__dirname,"package.json"),"utf8")),successRates=[],recordInterval=6e4,windowSize=30;function _calculateMovingAverage(){return successRates.reduce(((e,t)=>e+t),0)/successRates.length}function _startSuccessRate(){return setInterval((()=>{const e=getPoolStats(),t=0===e.exportsAttempted?1:e.exportsPerformed/e.exportsAttempted*100;successRates.push(t),successRates.length>windowSize&&successRates.shift()}),recordInterval)}function healthRoutes(e){addTimer(_startSuccessRate()),e.get("/health",((e,t,o)=>{try{log(4,"[health] Returning server health.");const e=getPoolStats(),o=successRates.length,r=_calculateMovingAverage();t.send({status:"OK",bootTime:serverStartTime,uptime:`${Math.floor((getNewDateTime()-serverStartTime.getTime())/1e3/60)} minutes`,serverVersion:packageFile.version,highchartsVersion:getHighchartsVersion(),averageExportTime:e.timeSpentAverage,attemptedExports:e.exportsAttempted,performedExports:e.exportsPerformed,failedExports:e.exportsDropped,sucessRatio:e.exportsPerformed/e.exportsAttempted*100,pool:getPoolInfoJSON(),period:o,movingAverage:r,message:isNaN(r)||!successRates.length?"Too early to report. No exports made yet. Please check back soon.":`Last ${o} minutes had a success rate of ${r.toFixed(2)}%.`,svgExports:e.exportsFromSvg,jsonExports:e.exportsFromOptions,svgExportsAttempts:e.exportsFromSvgAttempts,jsonExportsAttempts:e.exportsFromOptionsAttempts})}catch(e){return o(e)}}))}function uiRoutes(e){e.get(getOptions().ui.route||"/",((e,t,o)=>{try{log(4,"[ui] Returning UI for the export."),t.sendFile(join(__dirname,"public","index.html"),{acceptRanges:!1})}catch(e){return o(e)}}))}function versionChangeRoutes(e){e.post("/version_change/:newVersion",(async(e,t,o)=>{try{log(4,"[version] Changing Highcharts version.");const o=envs.HIGHCHARTS_ADMIN_TOKEN;if(!o||!o.length)throw new ExportError("[version] The server is not configured to perform run-time version changes: HIGHCHARTS_ADMIN_TOKEN is not set.",401);const r=e.get("hc-auth");if(!r||r!==o)throw new ExportError("[version] Invalid or missing token: Set the token in the hc-auth header.",401);let i=e.params.newVersion;try{i=validateOption("version",e.params.newVersion)}catch(e){throw new ExportError(`[version] Version is incorrect: ${e.message}`,400).setError(e)}if(!i)throw new ExportError("[version] No new version supplied.",400);try{await updateHighchartsVersion(i)}catch(e){throw new ExportError(`[version] Version change: ${e.message}`,400).setError(e)}t.status(200).send({statusCode:200,highchartsVersion:getHighchartsVersion(),message:`Successfully updated Highcharts to version: ${i}.`})}catch(e){return o(e)}}))}const activeServers=new Map,app=express();async function startServer(e){try{const t=updateOptions(validateOptions({server:e}));if(!(e=t.server).enable||!app)throw new ExportError("[server] Server cannot be started (not enabled or no correct Express app found).",500);const o=1024*e.uploadLimit*1024,r=multer.memoryStorage(),i=multer({storage:r,limits:{fieldSize:o}});if(app.disable("x-powered-by"),app.use(cors({methods:["POST","GET","OPTIONS"]})),app.use(((e,t,o)=>{t.set("Accept-Ranges","none"),o()})),app.use(express.json({limit:o})),app.use(express.urlencoded({extended:!0,limit:o})),app.use(i.none()),app.use(express.static(join(__dirname,"public"))),!e.ssl.force){const t=http.createServer(app);_attachServerErrorHandlers(t),t.listen(e.port,e.host,(()=>{activeServers.set(e.port,t),log(3,`[server] Started HTTP server on ${e.host}:${e.port}.`)}))}if(e.ssl.enable){let t,o;try{t=readFileSync(join(getAbsolutePath(e.ssl.certPath),"server.key"),"utf8"),o=readFileSync(join(getAbsolutePath(e.ssl.certPath),"server.crt"),"utf8")}catch(t){log(2,`[server] Unable to load key/certificate from the '${e.ssl.certPath}' path. Could not run secured layer server.`)}if(t&&o){const r=https.createServer({key:t,cert:o},app);_attachServerErrorHandlers(r),r.listen(e.ssl.port,e.host,(()=>{activeServers.set(e.ssl.port,r),log(3,`[server] Started HTTPS server on ${e.host}:${e.ssl.port}.`)}))}}rateLimitingMiddleware(app,e.rateLimiting),validationMiddleware(app),exportRoutes(app),healthRoutes(app),uiRoutes(app),versionChangeRoutes(app),errorMiddleware(app)}catch(e){throw new ExportError("[server] Could not configure and start the server.",500).setError(e)}}function closeServers(){if(activeServers.size>0){log(4,"[server] Closing all servers.");for(const[e,t]of activeServers)t.close((()=>{activeServers.delete(e),log(4,`[server] Closed server on port: ${e}.`)}))}}function getServers(){return activeServers}function getExpress(){return express}function getApp(){return app}function enableRateLimiting(e){const t=updateOptions(validateOptions({server:{rateLimiting:e}}));rateLimitingMiddleware(app,t.server.rateLimitingOptions)}function use(e,...t){app.use(e,...t)}function get(e,...t){app.get(e,...t)}function post(e,...t){app.post(e,...t)}function _attachServerErrorHandlers(e){e.on("clientError",((e,t)=>{logWithStack(1,e,`[server] Client error: ${e.message}, destroying socket.`),t.destroy()})),e.on("error",(e=>{logWithStack(1,e,`[server] Server error: ${e.message}`)})),e.on("connection",(e=>{e.on("error",(e=>{logWithStack(1,e,`[server] Socket error: ${e.message}`)}))}))}var server={startServer:startServer,closeServers:closeServers,getServers:getServers,getExpress:getExpress,getApp:getApp,enableRateLimiting:enableRateLimiting,use:use,get:get,post:post};async function shutdownCleanUp(e=0){await Promise.allSettled([clearAllTimers(),closeServers(),killPool()]),process.exit(e)}async function initExport(e){const t=updateOptions(validateOptions(e));setAllowCodeExecution(t.customLogic.allowCodeExecution),initLogging(t.logging),t.other.listenToProcessExits&&_attachProcessExitListeners(),await checkAndUpdateCache(t.highcharts,t.server.proxy),await initPool(t.pool,t.puppeteer.args)}function _attachProcessExitListeners(){log(3,"[process] Attaching exit listeners to the process."),process.on("exit",(e=>{log(4,`[process] Process exited with code ${e}.`)})),process.on("SIGINT",(async(e,t)=>{log(4,`[process] The ${e} event with code: ${t}.`),await shutdownCleanUp()})),process.on("SIGTERM",(async(e,t)=>{log(4,`[process] The ${e} event with code: ${t}.`),await shutdownCleanUp()})),process.on("SIGHUP",(async(e,t)=>{log(4,`[process] The ${e} event with code: ${t}.`),await shutdownCleanUp()})),process.on("uncaughtException",(async(e,t)=>{logWithStack(1,e,`[process] The ${t} error.`),await shutdownCleanUp(1)}))}var index={...server,getOptions:getOptions,updateOptions:updateOptions,mapToNewOptions:mapToNewOptions,validateOption:validateOption,validateOptions:validateOptions,initExport:initExport,singleExport:singleExport,batchExport:batchExport,startExport:startExport,killPool:killPool,shutdownCleanUp:shutdownCleanUp,log:log,logWithStack:logWithStack,logZodIssues:logZodIssues,setLogLevel:function(e){setLogLevel(updateOptions(validateOptions({logging:{level:e}})).logging.level)},enableConsoleLogging:function(e){enableConsoleLogging(updateOptions(validateOptions({logging:{toConsole:e}})).logging.toConsole)},enableFileLogging:function(e,t,o){const r=updateOptions(validateOptions({logging:{dest:e,file:t,toFile:o}}));enableFileLogging(r.logging.dest,r.logging.file,r.logging.toFile)}};export{index as default,initExport}; +import"colors";import{readFileSync,existsSync,mkdirSync,appendFile,writeFileSync}from"fs";import{isAbsolute,normalize,resolve,join}from"path";import{HttpsProxyAgent}from"https-proxy-agent";import{fileURLToPath}from"url";import dotenv from"dotenv";import{z}from"zod";import http from"http";import https from"https";import{Pool}from"tarn";import{v4}from"uuid";import puppeteer from"puppeteer";import DOMPurify from"dompurify";import{JSDOM}from"jsdom";import cors from"cors";import express from"express";import multer from"multer";import rateLimit from"express-rate-limit";const __dirname=fileURLToPath(new URL("../.",import.meta.url));function deepCopy(e){if(null===e||"object"!=typeof e)return e;const t=Array.isArray(e)?[]:{};for(const o in e)Object.prototype.hasOwnProperty.call(e,o)&&(t[o]=deepCopy(e[o]));return t}function fixConstr(e){try{const t=`${e.toLowerCase().replace("chart","")}Chart`;return"Chart"===t&&t.toLowerCase(),["chart","stockChart","mapChart","ganttChart"].includes(t)?t:"chart"}catch{return"chart"}}function fixOutfile(e,t){return`${getAbsolutePath(t||"chart").split(".").shift()}.${e}`}function fixType(e,t=null){const o={"image/png":"png","image/jpeg":"jpeg","application/pdf":"pdf","image/svg+xml":"svg"},r=Object.values(o);if(t){const o=t.split(".").pop();"jpg"===o?e="jpeg":r.includes(o)&&e!==o&&(e=o)}return o[e]||r.find((t=>t===e))||"png"}function getAbsolutePath(e){return isAbsolute(e)?normalize(e):resolve(e)}function getBase64(e,t){return"pdf"===t||"svg"==t?Buffer.from(e,"utf8").toString("base64"):e}function getNewDate(){return(new Date).toString().split("(")[0].trim()}function getNewDateTime(){return(new Date).getTime()}function isObject(e){return"[object Object]"===Object.prototype.toString.call(e)}function isObjectEmpty(e){return"object"==typeof e&&!Array.isArray(e)&&null!==e&&0===Object.keys(e).length}function isPrivateRangeUrlFound(e){return[/xlink:href="(?:http:\/\/|https:\/\/)?localhost\b/,/xlink:href="(?:http:\/\/|https:\/\/)?10\.\d{1,3}\.\d{1,3}\.\d{1,3}\b/,/xlink:href="(?:http:\/\/|https:\/\/)?127\.\d{1,3}\.\d{1,3}\.\d{1,3}\b/,/xlink:href="(?:http:\/\/|https:\/\/)?172\.(1[6-9]|2[0-9]|3[0-1])\.\d{1,3}\.\d{1,3}\b/,/xlink:href="(?:http:\/\/|https:\/\/)?192\.168\.\d{1,3}\.\d{1,3}\b/].some((t=>t.test(e)))}function measureTime(){const e=process.hrtime.bigint();return()=>Number(process.hrtime.bigint()-e)/1e6}function roundNumber(e,t=1){const o=Math.pow(10,t||0);return Math.round(+e*o)/o}function wrapAround(e,t,o=!1){if(e&&"string"==typeof e)return(e=e.trim()).endsWith(".js")?t?wrapAround(readFileSync(getAbsolutePath(e),"utf8"),t,o):null:!o&&(e.startsWith("function()")||e.startsWith("function ()")||e.startsWith("()=>")||e.startsWith("() =>"))?`(${e})()`:e.replace(/;$/,"")}const colors=["red","yellow","blue","gray","green"],logging={toConsole:!0,toFile:!1,pathCreated:!1,pathToLog:"",levelsDesc:[{title:"error",color:colors[0]},{title:"warning",color:colors[1]},{title:"notice",color:colors[2]},{title:"verbose",color:colors[3]},{title:"benchmark",color:colors[4]}]};function log(...e){const[t,...o]=e,{levelsDesc:r,level:i}=logging;if(5!==t&&(0===t||t>i||i>r.length))return;const n=`${getNewDate()} [${r[t-1].title}] -`;logging.toFile&&_logToFile(o,n),logging.toConsole&&console.log.apply(void 0,[n.toString()[logging.levelsDesc[t-1].color]].concat(o))}function logWithStack(e,t,o){const r=o||t&&t.message||"",{level:i,levelsDesc:n}=logging;if(0===e||e>i||i>n.length)return;const s=`${getNewDate()} [${n[e-1].title}] -`,a=t&&t.stack,l=[r];a&&l.push("\n",a),logging.toFile&&_logToFile(l,s),logging.toConsole&&console.log.apply(void 0,[s.toString()[logging.levelsDesc[e-1].color]].concat([l.shift()[colors[e-1]],...l]))}function logZodIssues(e,t,o){logWithStack(e,null,[`${o||"[validation] Validation error"} - the following Zod issues occured:`,...(t||[]).map((e=>`- ${e.message}`))].join("\n"))}function initLogging(e){const{level:t,dest:o,file:r,toConsole:i,toFile:n}=e;logging.pathCreated=!1,logging.pathToLog="",setLogLevel(t),enableConsoleLogging(i),enableFileLogging(o,r,n)}function setLogLevel(e){Number.isInteger(e)&&e>=0&&e<=logging.levelsDesc.length&&(logging.level=e)}function enableConsoleLogging(e){logging.toConsole=!!e}function enableFileLogging(e,t,o){logging.toFile=!!o,logging.toFile&&(logging.dest=e||"",logging.file=t||"")}function _logToFile(e,t){logging.pathCreated||(!existsSync(getAbsolutePath(logging.dest))&&mkdirSync(getAbsolutePath(logging.dest)),logging.pathToLog=getAbsolutePath(join(logging.dest,logging.file)),logging.pathCreated=!0),appendFile(logging.pathToLog,[t].concat(e).join(" ")+"\n",(e=>{e&&logging.toFile&&logging.pathCreated&&(logging.toFile=!1,logging.pathCreated=!1,logWithStack(2,e,"[logger] Unable to write to log file."))}))}const defaultConfig={puppeteer:{args:{value:["--allow-running-insecure-content","--ash-no-nudges","--autoplay-policy=user-gesture-required","--block-new-web-contents","--disable-accelerated-2d-canvas","--disable-background-networking","--disable-background-timer-throttling","--disable-backgrounding-occluded-windows","--disable-breakpad","--disable-checker-imaging","--disable-client-side-phishing-detection","--disable-component-extensions-with-background-pages","--disable-component-update","--disable-default-apps","--disable-dev-shm-usage","--disable-domain-reliability","--disable-extensions","--disable-features=CalculateNativeWinOcclusion,InterestFeedContentSuggestions,WebOTP","--disable-hang-monitor","--disable-ipc-flooding-protection","--disable-logging","--disable-notifications","--disable-offer-store-unmasked-wallet-cards","--disable-popup-blocking","--disable-print-preview","--disable-prompt-on-repost","--disable-renderer-backgrounding","--disable-search-engine-choice-screen","--disable-session-crashed-bubble","--disable-setuid-sandbox","--disable-site-isolation-trials","--disable-speech-api","--disable-sync","--enable-unsafe-webgpu","--hide-crash-restore-bubble","--hide-scrollbars","--metrics-recording-only","--mute-audio","--no-default-browser-check","--no-first-run","--no-pings","--no-sandbox","--no-startup-window","--no-zygote","--password-store=basic","--process-per-tab","--use-mock-keychain"],types:["string[]"],envLink:"PUPPETEER_ARGS",cliName:"puppeteerArgs",description:"Array of Puppeteer arguments",promptOptions:{type:"list",separator:";"}}},highcharts:{version:{value:"latest",types:["string"],envLink:"HIGHCHARTS_VERSION",description:"Highcharts version",promptOptions:{type:"text"}},cdnUrl:{value:"https://code.highcharts.com",types:["string"],envLink:"HIGHCHARTS_CDN_URL",description:"CDN URL for Highcharts scripts",promptOptions:{type:"text"}},forceFetch:{value:!1,types:["boolean"],envLink:"HIGHCHARTS_FORCE_FETCH",description:"Flag to refetch scripts after each server rerun",promptOptions:{type:"toggle"}},cachePath:{value:".cache",types:["string"],envLink:"HIGHCHARTS_CACHE_PATH",description:"Directory path for cached Highcharts scripts",promptOptions:{type:"text"}},coreScripts:{value:["highcharts","highcharts-more","highcharts-3d"],types:["string[]"],envLink:"HIGHCHARTS_CORE_SCRIPTS",description:"Highcharts core scripts to fetch",promptOptions:{type:"multiselect",instructions:"Space: Select specific, A: Select all, Enter: Confirm"}},moduleScripts:{value:["stock","map","gantt","exporting","parallel-coordinates","accessibility","boost-canvas","boost","data","data-tools","draggable-points","static-scale","broken-axis","heatmap","tilemap","tiledwebmap","timeline","treemap","treegraph","item-series","drilldown","histogram-bellcurve","bullet","funnel","funnel3d","geoheatmap","pyramid3d","networkgraph","overlapping-datalabels","pareto","pattern-fill","pictorial","price-indicator","sankey","arc-diagram","dependency-wheel","series-label","series-on-point","solid-gauge","sonification","streamgraph","sunburst","variable-pie","variwide","vector","venn","windbarb","wordcloud","xrange","no-data-to-display","drag-panes","debugger","dumbbell","lollipop","cylinder","organization","dotplot","marker-clusters","hollowcandlestick","heikinashi","flowmap","export-data","navigator","textpath"],types:["string[]"],envLink:"HIGHCHARTS_MODULE_SCRIPTS",description:"Highcharts module scripts to fetch",promptOptions:{type:"multiselect",instructions:"Space: Select specific, A: Select all, Enter: Confirm"}},indicatorScripts:{value:["indicators-all"],types:["string[]"],envLink:"HIGHCHARTS_INDICATOR_SCRIPTS",description:"Highcharts indicator scripts to fetch",promptOptions:{type:"multiselect",instructions:"Space: Select specific, A: Select all, Enter: Confirm"}},customScripts:{value:["https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.30.1/moment.min.js","https://cdnjs.cloudflare.com/ajax/libs/moment-timezone/0.5.45/moment-timezone-with-data.min.js"],types:["string[]"],envLink:"HIGHCHARTS_CUSTOM_SCRIPTS",description:"Additional custom scripts or dependencies to fetch",promptOptions:{type:"list",separator:";"}}},export:{infile:{value:null,types:["string","null"],envLink:"EXPORT_INFILE",description:"Input filename with type, formatted correctly as JSON or SVG",promptOptions:{type:"text"}},instr:{value:null,types:["Object","string","null"],envLink:"EXPORT_INSTR",description:"Overrides the `infile` with JSON, stringified JSON, or SVG input",promptOptions:{type:"text"}},options:{value:null,types:["Object","string","null"],envLink:"EXPORT_OPTIONS",description:"Alias for the `instr` option",promptOptions:{type:"text"}},svg:{value:null,types:["string","null"],envLink:"EXPORT_SVG",description:"SVG string representation of the chart to render",promptOptions:{type:"text"}},batch:{value:null,types:["string","null"],envLink:"EXPORT_BATCH",description:'Batch job string with input/output pairs: "in=out;in=out;..."',promptOptions:{type:"text"}},outfile:{value:null,types:["string","null"],envLink:"EXPORT_OUTFILE",description:"Output filename with type. Can be jpeg, png, pdf, or svg and ignores `type` option",promptOptions:{type:"text"}},type:{value:"png",types:["string"],envLink:"EXPORT_TYPE",description:"File export format. Can be jpeg, png, pdf, or svg",promptOptions:{type:"select",hint:"Default: png",choices:["png","jpeg","pdf","svg"]}},constr:{value:"chart",types:["string"],envLink:"EXPORT_CONSTR",description:"Chart constructor. Can be chart, stockChart, mapChart, or ganttChart",promptOptions:{type:"select",hint:"Default: chart",choices:["chart","stockChart","mapChart","ganttChart"]}},b64:{value:!1,types:["boolean"],envLink:"EXPORT_B64",description:"Whether or not to the chart should be received in Base64 format instead of binary",promptOptions:{type:"toggle"}},noDownload:{value:!1,types:["boolean"],envLink:"EXPORT_NO_DOWNLOAD",description:"Whether or not to include or exclude attachment headers in the response",promptOptions:{type:"toggle"}},height:{value:null,types:["number","null"],envLink:"EXPORT_HEIGHT",description:"Height of the exported chart, overrides chart settings",promptOptions:{type:"number"}},width:{value:null,types:["number","null"],envLink:"EXPORT_WIDTH",description:"Width of the exported chart, overrides chart settings",promptOptions:{type:"number"}},scale:{value:null,types:["number","null"],envLink:"EXPORT_SCALE",description:"Scale of the exported chart, overrides chart settings. Ranges from 0.1 to 5.0",promptOptions:{type:"number"}},defaultHeight:{value:400,types:["number"],envLink:"EXPORT_DEFAULT_HEIGHT",description:"Default height of the exported chart if not set",promptOptions:{type:"number"}},defaultWidth:{value:600,types:["number"],envLink:"EXPORT_DEFAULT_WIDTH",description:"Default width of the exported chart if not set",promptOptions:{type:"number"}},defaultScale:{value:1,types:["number"],envLink:"EXPORT_DEFAULT_SCALE",description:"Default scale of the exported chart if not set. Ranges from 0.1 to 5.0",promptOptions:{type:"number",min:.1,max:5}},globalOptions:{value:null,types:["Object","string","null"],envLink:"EXPORT_GLOBAL_OPTIONS",description:"JSON, stringified JSON or filename with global options for Highcharts.setOptions",promptOptions:{type:"text"}},themeOptions:{value:null,types:["Object","string","null"],envLink:"EXPORT_THEME_OPTIONS",description:"JSON, stringified JSON or filename with theme options for Highcharts.setOptions",promptOptions:{type:"text"}},rasterizationTimeout:{value:1500,types:["number"],envLink:"EXPORT_RASTERIZATION_TIMEOUT",description:"Milliseconds to wait for webpage rendering",promptOptions:{type:"number"}}},customLogic:{allowCodeExecution:{value:!1,types:["boolean"],envLink:"CUSTOM_LOGIC_ALLOW_CODE_EXECUTION",description:"Allows or disallows execution of arbitrary code during exporting",promptOptions:{type:"toggle"}},allowFileResources:{value:!1,types:["boolean"],envLink:"CUSTOM_LOGIC_ALLOW_FILE_RESOURCES",description:"Allows or disallows injection of filesystem resources (disabled in server mode)",promptOptions:{type:"toggle"}},customCode:{value:null,types:["string","null"],envLink:"CUSTOM_LOGIC_CUSTOM_CODE",description:"Custom code to execute before chart initialization. Can be a function, code wrapped in a function, or a .js filename",promptOptions:{type:"text"}},callback:{value:null,types:["string","null"],envLink:"CUSTOM_LOGIC_CALLBACK",description:"JavaScript code to run during construction. Can be a function or a .js filename",promptOptions:{type:"text"}},resources:{value:null,types:["Object","string","null"],envLink:"CUSTOM_LOGIC_RESOURCES",description:"Additional resources as JSON, stringified JSON, or filename, containing files, js, and css sections",promptOptions:{type:"text"}},loadConfig:{value:null,types:["string","null"],envLink:"CUSTOM_LOGIC_LOAD_CONFIG",legacyName:"fromFile",description:"File with a pre-defined configuration to use",promptOptions:{type:"text"}},createConfig:{value:null,types:["string","null"],envLink:"CUSTOM_LOGIC_CREATE_CONFIG",description:"Prompt-based option setting, saved to a provided config file",promptOptions:{type:"text"}}},server:{enable:{value:!1,types:["boolean"],envLink:"SERVER_ENABLE",cliName:"enableServer",description:"Starts the server when true",promptOptions:{type:"toggle"}},host:{value:"0.0.0.0",types:["string"],envLink:"SERVER_HOST",description:"Hostname of the server",promptOptions:{type:"text"}},port:{value:7801,types:["number"],envLink:"SERVER_PORT",description:"Port number for the server",promptOptions:{type:"number"}},uploadLimit:{value:3,types:["number"],envLink:"SERVER_UPLOAD_LIMIT",description:"Maximum request body size in MB",promptOptions:{type:"number"}},benchmarking:{value:!1,types:["boolean"],envLink:"SERVER_BENCHMARKING",cliName:"serverBenchmarking",description:"Displays or not action durations in milliseconds during server requests",promptOptions:{type:"toggle"}},proxy:{host:{value:null,types:["string","null"],envLink:"SERVER_PROXY_HOST",cliName:"proxyHost",description:"Host of the proxy server, if applicable",promptOptions:{type:"text"}},port:{value:null,types:["number","null"],envLink:"SERVER_PROXY_PORT",cliName:"proxyPort",description:"Port of the proxy server, if applicable",promptOptions:{type:"number"}},timeout:{value:5e3,types:["number"],envLink:"SERVER_PROXY_TIMEOUT",cliName:"proxyTimeout",description:"Timeout in milliseconds for the proxy server, if applicable",promptOptions:{type:"number"}}},rateLimiting:{enable:{value:!1,types:["boolean"],envLink:"SERVER_RATE_LIMITING_ENABLE",cliName:"enableRateLimiting",description:"Enables or disables rate limiting on the server",promptOptions:{type:"toggle"}},maxRequests:{value:10,types:["number"],envLink:"SERVER_RATE_LIMITING_MAX_REQUESTS",legacyName:"rateLimit",description:"Maximum number of requests allowed per minute",promptOptions:{type:"number"}},window:{value:1,types:["number"],envLink:"SERVER_RATE_LIMITING_WINDOW",description:"Time window in minutes for rate limiting",promptOptions:{type:"number"}},delay:{value:0,types:["number"],envLink:"SERVER_RATE_LIMITING_DELAY",description:"Delay duration between successive requests before reaching the limit",promptOptions:{type:"number"}},trustProxy:{value:!1,types:["boolean"],envLink:"SERVER_RATE_LIMITING_TRUST_PROXY",description:"Set to true if the server is behind a load balancer",promptOptions:{type:"toggle"}},skipKey:{value:null,types:["string","null"],envLink:"SERVER_RATE_LIMITING_SKIP_KEY",description:"Key to bypass the rate limiter, used with `skipToken`",promptOptions:{type:"text"}},skipToken:{value:null,types:["string","null"],envLink:"SERVER_RATE_LIMITING_SKIP_TOKEN",description:"Token to bypass the rate limiter, used with `skipKey`",promptOptions:{type:"text"}}},ssl:{enable:{value:!1,types:["boolean"],envLink:"SERVER_SSL_ENABLE",cliName:"enableSsl",description:"Enables or disables SSL protocol",promptOptions:{type:"toggle"}},force:{value:!1,types:["boolean"],envLink:"SERVER_SSL_FORCE",cliName:"sslForce",legacyName:"sslOnly",description:"Forces the server to use HTTPS only when true",promptOptions:{type:"toggle"}},port:{value:443,types:["number"],envLink:"SERVER_SSL_PORT",cliName:"sslPort",description:"Port for the SSL server",promptOptions:{type:"number"}},certPath:{value:null,types:["string","null"],envLink:"SERVER_SSL_CERT_PATH",cliName:"sslCertPath",legacyName:"sslPath",description:"Path to the SSL certificate/key file",promptOptions:{type:"text"}}}},pool:{minWorkers:{value:4,types:["number"],envLink:"POOL_MIN_WORKERS",description:"Minimum and initial number of pool workers to spawn",promptOptions:{type:"number"}},maxWorkers:{value:8,types:["number"],envLink:"POOL_MAX_WORKERS",legacyName:"workers",description:"Maximum number of pool workers to spawn",promptOptions:{type:"number"}},workLimit:{value:40,types:["number"],envLink:"POOL_WORK_LIMIT",description:"Number of tasks a worker can handle before restarting",promptOptions:{type:"number"}},acquireTimeout:{value:5e3,types:["number"],envLink:"POOL_ACQUIRE_TIMEOUT",description:"Timeout in milliseconds for acquiring a resource",promptOptions:{type:"number"}},createTimeout:{value:5e3,types:["number"],envLink:"POOL_CREATE_TIMEOUT",description:"Timeout in milliseconds for creating a resource",promptOptions:{type:"number"}},destroyTimeout:{value:5e3,types:["number"],envLink:"POOL_DESTROY_TIMEOUT",description:"Timeout in milliseconds for destroying a resource",promptOptions:{type:"number"}},idleTimeout:{value:3e4,types:["number"],envLink:"POOL_IDLE_TIMEOUT",description:"Timeout in milliseconds for destroying idle resources",promptOptions:{type:"number"}},createRetryInterval:{value:200,types:["number"],envLink:"POOL_CREATE_RETRY_INTERVAL",description:"Interval in milliseconds before retrying resource creation on failure",promptOptions:{type:"number"}},reaperInterval:{value:1e3,types:["number"],envLink:"POOL_REAPER_INTERVAL",description:"Interval in milliseconds to check and destroy idle resources",promptOptions:{type:"number"}},benchmarking:{value:!1,types:["boolean"],envLink:"POOL_BENCHMARKING",cliName:"poolBenchmarking",description:"Shows statistics for the pool of resources",promptOptions:{type:"toggle"}}},logging:{level:{value:4,types:["number"],envLink:"LOGGING_LEVEL",cliName:"logLevel",description:"Logging verbosity level",promptOptions:{type:"number",round:0,min:0,max:5}},file:{value:"highcharts-export-server.log",types:["string"],envLink:"LOGGING_FILE",cliName:"logFile",description:"Log file name. Requires `logToFile` and `logDest` to be set",promptOptions:{type:"text"}},dest:{value:"log",types:["string"],envLink:"LOGGING_DEST",cliName:"logDest",description:"Path to store log files. Requires `logToFile` to be set",promptOptions:{type:"text"}},toConsole:{value:!0,types:["boolean"],envLink:"LOGGING_TO_CONSOLE",cliName:"logToConsole",description:"Enables or disables console logging",promptOptions:{type:"toggle"}},toFile:{value:!0,types:["boolean"],envLink:"LOGGING_TO_FILE",cliName:"logToFile",description:"Enables or disables logging to a file",promptOptions:{type:"toggle"}}},ui:{enable:{value:!1,types:["boolean"],envLink:"UI_ENABLE",cliName:"enableUi",description:"Enables or disables the UI for the export server",promptOptions:{type:"toggle"}},route:{value:"/",types:["string"],envLink:"UI_ROUTE",cliName:"uiRoute",description:"The endpoint route for the UI",promptOptions:{type:"text"}}},other:{nodeEnv:{value:"production",types:["string"],envLink:"OTHER_NODE_ENV",description:"The Node.js environment type",promptOptions:{type:"text"}},listenToProcessExits:{value:!0,types:["boolean"],envLink:"OTHER_LISTEN_TO_PROCESS_EXITS",description:"Whether or not to attach process.exit handlers",promptOptions:{type:"toggle"}},noLogo:{value:!1,types:["boolean"],envLink:"OTHER_NO_LOGO",description:"Display or skip printing the logo on startup",promptOptions:{type:"toggle"}},hardResetPage:{value:!1,types:["boolean"],envLink:"OTHER_HARD_RESET_PAGE",description:"Whether or not to reset the page content entirely",promptOptions:{type:"toggle"}},browserShellMode:{value:!0,types:["boolean"],envLink:"OTHER_BROWSER_SHELL_MODE",description:"Whether or not to set the browser to run in shell mode",promptOptions:{type:"toggle"}},validation:{value:!0,types:["boolean"],envLink:"OTHER_VALIDATION",description:"Whether or not to enable validation of options types",promptOptions:{type:"toggle"}}},debug:{enable:{value:!1,types:["boolean"],envLink:"DEBUG_ENABLE",cliName:"enableDebug",description:"Enables or disables debug mode for the underlying browser",promptOptions:{type:"toggle"}},headless:{value:!1,types:["boolean"],envLink:"DEBUG_HEADLESS",description:"Whether or not to set the browser to run in headless mode during debugging",promptOptions:{type:"toggle"}},devtools:{value:!1,types:["boolean"],envLink:"DEBUG_DEVTOOLS",description:"Enables or disables DevTools in headful mode",promptOptions:{type:"toggle"}},listenToConsole:{value:!1,types:["boolean"],envLink:"DEBUG_LISTEN_TO_CONSOLE",description:"Enables or disables listening to console messages from the browser",promptOptions:{type:"toggle"}},dumpio:{value:!1,types:["boolean"],envLink:"DEBUG_DUMPIO",description:"Redirects or not browser stdout and stderr to process.stdout and process.stderr",promptOptions:{type:"toggle"}},slowMo:{value:0,types:["number"],envLink:"DEBUG_SLOW_MO",description:"Delays Puppeteer operations by the specified milliseconds",promptOptions:{type:"number"}},debuggingPort:{value:9222,types:["number"],envLink:"DEBUG_DEBUGGING_PORT",description:"Port used for debugging",promptOptions:{type:"number"}}}},nestedProps=_createNestedProps(defaultConfig),absoluteProps=_createAbsoluteProps(defaultConfig);function _createNestedProps(e,t={},o=""){return Object.keys(e).forEach((r=>{const i=e[r];void 0===i.value?_createNestedProps(i,t,`${o}.${r}`):(t[i.cliName||r]=`${o}.${r}`.substring(1),void 0!==i.legacyName&&(t[i.legacyName]=`${o}.${r}`.substring(1)))})),t}function _createAbsoluteProps(e,t=[]){return Object.keys(e).forEach((o=>{const r=e[o];void 0===r.types?_createAbsoluteProps(r,t):r.types.includes("Object")&&t.push(o)})),t}dotenv.config();const{coreScripts:coreScripts,moduleScripts:moduleScripts,indicatorScripts:indicatorScripts}=defaultConfig.highcharts;z.setErrorMap(_customErrorMap);const v={boolean:e=>e?z.boolean():z.union([z.enum(["true","1","false","0","undefined","null",""]).transform((e=>["undefined","null",""].includes(e)?null:"true"===e||"1"===e)),z.boolean()]).nullable(),string:e=>e?z.string().trim().refine((e=>!["false","undefined","null",""].includes(e)),{params:{errorMessage:"The string contains a forbidden value"}}):z.string().trim().transform((e=>["false","undefined","null",""].includes(e)?null:e)).nullable(),enum:(e,t)=>t?z.enum([...e]):z.enum([...e,"undefined","null",""]).transform((e=>["undefined","null",""].includes(e)?null:e)).nullable(),stringArray(e,t,o){const r=z.string().trim().array(),i=z.string().trim().transform((e=>(e.startsWith("[")&&(e=e.slice(1)),e.endsWith("]")&&(e=e.slice(0,-1)),e.split(t)))),n=t=>t.map((e=>e.trim())).filter(e);return o?r.transform(n):z.union([i,r]).transform(n).transform((e=>e.length?e:null)).nullable()},positiveNum:e=>e?z.number().positive():z.union([z.string().trim().refine((e=>!isNaN(Number(e))&&Number(e)>0||["undefined","null",""].includes(e)),{params:{errorMessage:"The value must be numeric and positive"}}).transform((e=>["undefined","null",""].includes(e)?null:Number(e))),z.number().positive()]).nullable(),nonNegativeNum:e=>e?z.number().nonnegative():z.union([z.string().trim().refine((e=>!isNaN(Number(e))&&Number(e)>=0||["undefined","null",""].includes(e)),{params:{errorMessage:"The value must be numeric and non-negative"}}).transform((e=>["undefined","null",""].includes(e)?null:Number(e))),z.number().nonnegative()]).nullable(),startsWith:(e,t)=>t?z.string().trim().refine((t=>e.some((e=>t.startsWith(e)))),{params:{errorMessage:`The value must be a string that starts with ${e.join(", ")}`}}):z.string().trim().refine((t=>e.some((e=>t.startsWith(e)))||["undefined","null",""].includes(t)),{params:{errorMessage:`The value must be a string that starts with ${e.join(", ")}`}}).transform((e=>["undefined","null",""].includes(e)?null:e)).nullable(),chartConfig:()=>z.union([z.string().trim().refine((e=>e.startsWith("{")&&e.endsWith("}")||["undefined","null",""].includes(e)),{params:{errorMessage:"The value must be a string that starts with '{' and ends with '}'"}}).transform((e=>["undefined","null",""].includes(e)?null:e)),z.object({}).passthrough()]).nullable(),additionalOptions:()=>z.union([z.string().trim().refine((e=>e.length>=6&&e.endsWith(".json")||e.startsWith("{")&&e.endsWith("}")||["undefined","null",""].includes(e)),{params:{errorMessage:"The value must be a string that ends with '.json' or starts with '{' and ends with '}'"}}).transform((e=>["undefined","null",""].includes(e)?null:e)),z.object({}).passthrough()]).nullable()},validators={args:e=>v.stringArray((e=>!["false","undefined","null",""].includes(e)),";",e),version:e=>e?z.string().trim().refine((e=>/^(latest|\d{1,2}(\.\d{1,2}){0,2})$/.test(e)),{params:{errorMessage:"The value must be 'latest', a major version, or in the form XX.YY.ZZ"}}):z.string().trim().refine((e=>/^(latest|\d{1,2}(\.\d{1,2}){0,2})$/.test(e)||["undefined","null",""].includes(e)),{params:{errorMessage:"The value must be 'latest', a major version, or in the form XX.YY.ZZ"}}).transform((e=>["undefined","null",""].includes(e)?null:e)).nullable(),cdnUrl:e=>v.startsWith(["http://","https://"],e),forceFetch:e=>v.boolean(e),cachePath:e=>v.string(e),adminToken:e=>v.string(e),coreScripts:e=>v.stringArray((e=>coreScripts.value.includes(e)),",",e),moduleScripts:e=>v.stringArray((e=>moduleScripts.value.includes(e)),",",e),indicatorScripts:e=>v.stringArray((e=>indicatorScripts.value.includes(e)),",",e),customScripts:e=>v.stringArray((e=>e.startsWith("https://")||e.startsWith("http://")),",",e),infile:e=>e?z.string().trim().refine((e=>e.length>=6&&e.endsWith(".json")||e.length>=5&&e.endsWith(".svg")),{params:{errorMessage:"The value must be a string that ends with .json or .svg"}}).nullable():z.string().trim().refine((e=>e.length>=6&&e.endsWith(".json")||e.length>=5&&e.endsWith(".svg")||["undefined","null",""].includes(e)),{params:{errorMessage:"The value must be a string that ends with .json or .svg"}}).transform((e=>["undefined","null",""].includes(e)?null:e)).nullable(),instr:()=>v.chartConfig(),options:()=>v.chartConfig(),svg:()=>z.string().trim().refine((e=>e.indexOf("=0||e.indexOf("=0||["false","undefined","null",""].includes(e)),{params:{errorMessage:"The value must be a string that contains '["false","undefined","null",""].includes(e)?null:e)).nullable(),outfile:e=>e?z.string().trim().refine((e=>e.length>=6&&e.endsWith(".jpeg")||e.length>=5&&(e.endsWith(".jpg")||e.endsWith(".png")||e.endsWith(".pdf")||e.endsWith(".svg"))),{params:{errorMessage:"The value must be a string that ends with .jpeg, .jpg, .png, .pdf, or .svg"}}).nullable():z.string().trim().refine((e=>e.length>=6&&e.endsWith(".jpeg")||e.length>=5&&(e.endsWith(".jpg")||e.endsWith(".png")||e.endsWith(".pdf")||e.endsWith(".svg"))||["undefined","null",""].includes(e)),{params:{errorMessage:"The value must be a string that ends with .jpeg, .jpg, .png, .pdf, or .svg"}}).transform((e=>["undefined","null",""].includes(e)?null:e)).nullable(),type:e=>v.enum(["jpeg","jpg","png","pdf","svg"],e),constr:e=>v.enum(["chart","stockChart","mapChart","ganttChart"],e),b64:e=>v.boolean(e),noDownload:e=>v.boolean(e),defaultHeight:e=>v.positiveNum(e),defaultWidth:e=>v.positiveNum(e),defaultScale:e=>e?z.number().gte(.1).lte(5):z.union([z.string().trim().refine((e=>!isNaN(Number(e))&&!0!==e&&!e.startsWith("[")&&Number(e)>=.1&&Number(e)<=5||["undefined","null",""].includes(e)),{params:{errorMessage:"The value must be within a 0.1 and 5.0 range"}}).transform((e=>["undefined","null",""].includes(e)?null:Number(e))),z.number().gte(.1).lte(5)]).nullable(),height(e){return this.defaultHeight(e).nullable()},width(e){return this.defaultWidth(e).nullable()},scale(e){return this.defaultScale(e).nullable()},globalOptions:()=>v.additionalOptions(),themeOptions:()=>v.additionalOptions(),batch:e=>v.string(e),rasterizationTimeout:e=>v.nonNegativeNum(e),allowCodeExecution:e=>v.boolean(e),allowFileResources:e=>v.boolean(e),customCode:e=>v.string(e),callback:e=>v.string(e),resources(e){const t=z.object({js:v.string(!1),css:v.string(!1),files:v.stringArray((e=>!["undefined","null",""].includes(e)),",",!0).nullable()}).partial(),o=z.string().trim().refine((e=>e.startsWith("{")&&e.endsWith("}")||e.length>=6&&e.endsWith(".json")),{params:{errorMessage:"The value must be a string that starts with '{' and ends with '}"}}),r=z.string().trim().refine((e=>e.startsWith("{")&&e.endsWith("}")||e.length>=6&&e.endsWith(".json")||["undefined","null",""].includes(e)),{params:{errorMessage:"The value must be a string that ends with .json"}}).transform((e=>["undefined","null",""].includes(e)?null:e));return e?z.union([t,o]).nullable():z.union([t,r]).nullable()},loadConfig:e=>v.string(e).refine((e=>null===e||e.length>=6&&e.endsWith(".json")),{params:{errorMessage:"The value must be a string that ends with .json"}}),createConfig(e){return this.loadConfig(e)},enableServer:e=>v.boolean(e),host:e=>v.string(e),port:e=>v.nonNegativeNum(e),uploadLimit:e=>v.positiveNum(e),serverBenchmarking:e=>v.boolean(e),proxyHost:e=>v.string(e),proxyPort:e=>v.nonNegativeNum(e).nullable(),proxyTimeout:e=>v.nonNegativeNum(e),enableRateLimiting:e=>v.boolean(e),maxRequests:e=>v.nonNegativeNum(e),window:e=>v.nonNegativeNum(e),delay:e=>v.nonNegativeNum(e),trustProxy:e=>v.boolean(e),skipKey:e=>v.string(e),skipToken:e=>v.string(e),enableSsl:e=>v.boolean(e),sslForce:e=>v.boolean(e),sslPort:e=>v.nonNegativeNum(e),sslCertPath:e=>v.string(e),minWorkers:e=>v.positiveNum(e),maxWorkers:e=>v.positiveNum(e),workLimit:e=>v.positiveNum(e),acquireTimeout:e=>v.nonNegativeNum(e),createTimeout:e=>v.nonNegativeNum(e),destroyTimeout:e=>v.nonNegativeNum(e),idleTimeout:e=>v.nonNegativeNum(e),createRetryInterval:e=>v.nonNegativeNum(e),reaperInterval:e=>v.nonNegativeNum(e),poolBenchmarking:e=>v.boolean(e),resourcesInterval:e=>v.nonNegativeNum(e),logLevel:e=>e?z.number().int().gte(0).lte(5):z.union([z.string().trim().refine((e=>!isNaN(Number(e))&&!0!==e&&!e.startsWith("[")&&Number.isInteger(Number(e))&&Number(e)>=0&&Number(e)<=5||["undefined","null",""].includes(e)),{params:{errorMessage:"The value must be within a 0 and 5 range"}}).transform((e=>["undefined","null",""].includes(e)?null:Number(e))),z.number().int().gte(0).lte(5)]).nullable(),logFile:e=>v.string(e).refine((e=>null===e||e.length>=5&&e.endsWith(".log")),{params:{errorMessage:"The value must be a string that ends with .log"}}),logDest:e=>v.string(e),logToConsole:e=>v.boolean(e),logToFile:e=>v.boolean(e),enableUi:e=>v.boolean(e),uiRoute:e=>v.startsWith(["/"],e),nodeEnv:e=>v.enum(["development","production","test"],e),listenToProcessExits:e=>v.boolean(e),noLogo:e=>v.boolean(e),hardResetPage:e=>v.boolean(e),browserShellMode:e=>v.boolean(e),validation:e=>v.boolean(e),enableDebug:e=>v.boolean(e),headless:e=>v.boolean(e),devtools:e=>v.boolean(e),listenToConsole:e=>v.boolean(e),dumpio:e=>v.boolean(e),slowMo:e=>v.nonNegativeNum(e),debuggingPort:e=>v.nonNegativeNum(e),requestId:()=>z.string().uuid({message:"The value must be a stringified UUID"}).nullable()},PuppeteerSchema=e=>z.object({args:validators.args(e)}).partial(),HighchartsSchema=e=>z.object({version:validators.version(e),cdnUrl:validators.cdnUrl(e),forceFetch:validators.forceFetch(e),cachePath:validators.cachePath(e),coreScripts:validators.coreScripts(e),moduleScripts:validators.moduleScripts(e),indicatorScripts:validators.indicatorScripts(e),customScripts:validators.customScripts(e)}).partial(),ExportSchema=e=>z.object({infile:validators.infile(e),instr:validators.instr(),options:validators.options(),svg:validators.svg(),outfile:validators.outfile(e),type:validators.type(e),constr:validators.constr(e),b64:validators.b64(e),noDownload:validators.noDownload(e),defaultHeight:validators.defaultHeight(e),defaultWidth:validators.defaultWidth(e),defaultScale:validators.defaultScale(e),height:validators.height(e),width:validators.width(e),scale:validators.scale(e),globalOptions:validators.globalOptions(),themeOptions:validators.themeOptions(),batch:validators.batch(!1),rasterizationTimeout:validators.rasterizationTimeout(e)}).partial(),CustomLogicSchema=e=>z.object({allowCodeExecution:validators.allowCodeExecution(e),allowFileResources:validators.allowFileResources(e),customCode:validators.customCode(!1),callback:validators.callback(!1),resources:validators.resources(e),loadConfig:validators.loadConfig(!1),createConfig:validators.createConfig(!1)}).partial(),ProxySchema=e=>z.object({host:validators.proxyHost(!1),port:validators.proxyPort(e),timeout:validators.proxyTimeout(e)}).partial(),RateLimitingSchema=e=>z.object({enable:validators.enableRateLimiting(e),maxRequests:validators.maxRequests(e),window:validators.window(e),delay:validators.delay(e),trustProxy:validators.trustProxy(e),skipKey:validators.skipKey(!1),skipToken:validators.skipToken(!1)}).partial(),SslSchema=e=>z.object({enable:validators.enableSsl(e),force:validators.sslForce(e),port:validators.sslPort(e),certPath:validators.sslCertPath(!1)}).partial(),ServerSchema=e=>z.object({enable:validators.enableServer(e).optional(),host:validators.host(e).optional(),port:validators.port(e).optional(),uploadLimit:validators.uploadLimit(e).optional(),benchmarking:validators.serverBenchmarking(e).optional(),proxy:ProxySchema(e).optional(),rateLimiting:RateLimitingSchema(e).optional(),ssl:SslSchema(e).optional()}),PoolSchema=e=>z.object({minWorkers:validators.minWorkers(e),maxWorkers:validators.maxWorkers(e),workLimit:validators.workLimit(e),acquireTimeout:validators.acquireTimeout(e),createTimeout:validators.createTimeout(e),destroyTimeout:validators.destroyTimeout(e),idleTimeout:validators.idleTimeout(e),createRetryInterval:validators.createRetryInterval(e),reaperInterval:validators.reaperInterval(e),benchmarking:validators.poolBenchmarking(e)}).partial(),LoggingSchema=e=>z.object({level:validators.logLevel(e),file:validators.logFile(e),dest:validators.logDest(e),toConsole:validators.logToConsole(e),toFile:validators.logToFile(e)}).partial(),UiSchema=e=>z.object({enable:validators.enableUi(e),route:validators.uiRoute(e)}).partial(),OtherSchema=e=>z.object({nodeEnv:validators.nodeEnv(e),listenToProcessExits:validators.listenToProcessExits(e),noLogo:validators.noLogo(e),hardResetPage:validators.hardResetPage(e),browserShellMode:validators.browserShellMode(e),validation:validators.validation(e)}).partial(),DebugSchema=e=>z.object({enable:validators.enableDebug(e),headless:validators.headless(e),devtools:validators.devtools(e),listenToConsole:validators.listenToConsole(e),dumpio:validators.dumpio(e),slowMo:validators.slowMo(e),debuggingPort:validators.debuggingPort(e)}).partial(),StrictConfigSchema=z.object({requestId:validators.requestId(),puppeteer:PuppeteerSchema(!0),highcharts:HighchartsSchema(!0),export:ExportSchema(!0),customLogic:CustomLogicSchema(!0),server:ServerSchema(!0),pool:PoolSchema(!0),logging:LoggingSchema(!0),ui:UiSchema(!0),other:OtherSchema(!0),debug:DebugSchema(!0)}),LooseConfigSchema=z.object({requestId:validators.requestId(),puppeteer:PuppeteerSchema(!1),highcharts:HighchartsSchema(!1),export:ExportSchema(!1),customLogic:CustomLogicSchema(!1),server:ServerSchema(!1),pool:PoolSchema(!1),logging:LoggingSchema(!1),ui:UiSchema(!1),other:OtherSchema(!1),debug:DebugSchema(!1)}),EnvSchema=z.object({PUPPETEER_ARGS:validators.args(!1),HIGHCHARTS_VERSION:validators.version(!1),HIGHCHARTS_CDN_URL:validators.cdnUrl(!1),HIGHCHARTS_FORCE_FETCH:validators.forceFetch(!1),HIGHCHARTS_CACHE_PATH:validators.cachePath(!1),HIGHCHARTS_ADMIN_TOKEN:validators.adminToken(!1),HIGHCHARTS_CORE_SCRIPTS:validators.coreScripts(!1),HIGHCHARTS_MODULE_SCRIPTS:validators.moduleScripts(!1),HIGHCHARTS_INDICATOR_SCRIPTS:validators.indicatorScripts(!1),HIGHCHARTS_CUSTOM_SCRIPTS:validators.customScripts(!1),EXPORT_INFILE:validators.infile(!1),EXPORT_INSTR:validators.instr(),EXPORT_OPTIONS:validators.options(),EXPORT_SVG:validators.svg(),EXPORT_BATCH:validators.batch(!1),EXPORT_OUTFILE:validators.outfile(!1),EXPORT_TYPE:validators.type(!1),EXPORT_CONSTR:validators.constr(!1),EXPORT_B64:validators.b64(!1),EXPORT_NO_DOWNLOAD:validators.noDownload(!1),EXPORT_HEIGHT:validators.height(!1),EXPORT_WIDTH:validators.width(!1),EXPORT_SCALE:validators.scale(!1),EXPORT_DEFAULT_HEIGHT:validators.defaultHeight(!1),EXPORT_DEFAULT_WIDTH:validators.defaultWidth(!1),EXPORT_DEFAULT_SCALE:validators.defaultScale(!1),EXPORT_GLOBAL_OPTIONS:validators.globalOptions(),EXPORT_THEME_OPTIONS:validators.themeOptions(),EXPORT_RASTERIZATION_TIMEOUT:validators.rasterizationTimeout(!1),CUSTOM_LOGIC_ALLOW_CODE_EXECUTION:validators.allowCodeExecution(!1),CUSTOM_LOGIC_ALLOW_FILE_RESOURCES:validators.allowFileResources(!1),CUSTOM_LOGIC_CUSTOM_CODE:validators.customCode(!1),CUSTOM_LOGIC_CALLBACK:validators.callback(!1),CUSTOM_LOGIC_RESOURCES:validators.resources(!1),CUSTOM_LOGIC_LOAD_CONFIG:validators.loadConfig(!1),CUSTOM_LOGIC_CREATE_CONFIG:validators.createConfig(!1),SERVER_ENABLE:validators.enableServer(!1),SERVER_HOST:validators.host(!1),SERVER_PORT:validators.port(!1),SERVER_UPLOAD_LIMIT:validators.uploadLimit(!1),SERVER_BENCHMARKING:validators.serverBenchmarking(!1),SERVER_PROXY_HOST:validators.proxyHost(!1),SERVER_PROXY_PORT:validators.proxyPort(!1),SERVER_PROXY_TIMEOUT:validators.proxyTimeout(!1),SERVER_RATE_LIMITING_ENABLE:validators.enableRateLimiting(!1),SERVER_RATE_LIMITING_MAX_REQUESTS:validators.maxRequests(!1),SERVER_RATE_LIMITING_WINDOW:validators.window(!1),SERVER_RATE_LIMITING_DELAY:validators.delay(!1),SERVER_RATE_LIMITING_TRUST_PROXY:validators.trustProxy(!1),SERVER_RATE_LIMITING_SKIP_KEY:validators.skipKey(!1),SERVER_RATE_LIMITING_SKIP_TOKEN:validators.skipToken(!1),SERVER_SSL_ENABLE:validators.enableSsl(!1),SERVER_SSL_FORCE:validators.sslForce(!1),SERVER_SSL_PORT:validators.sslPort(!1),SERVER_SSL_CERT_PATH:validators.sslCertPath(!1),POOL_MIN_WORKERS:validators.minWorkers(!1),POOL_MAX_WORKERS:validators.maxWorkers(!1),POOL_WORK_LIMIT:validators.workLimit(!1),POOL_ACQUIRE_TIMEOUT:validators.acquireTimeout(!1),POOL_CREATE_TIMEOUT:validators.createTimeout(!1),POOL_DESTROY_TIMEOUT:validators.destroyTimeout(!1),POOL_IDLE_TIMEOUT:validators.idleTimeout(!1),POOL_CREATE_RETRY_INTERVAL:validators.createRetryInterval(!1),POOL_REAPER_INTERVAL:validators.reaperInterval(!1),POOL_BENCHMARKING:validators.poolBenchmarking(!1),LOGGING_LEVEL:validators.logLevel(!1),LOGGING_FILE:validators.logFile(!1),LOGGING_DEST:validators.logDest(!1),LOGGING_TO_CONSOLE:validators.logToConsole(!1),LOGGING_TO_FILE:validators.logToFile(!1),UI_ENABLE:validators.enableUi(!1),UI_ROUTE:validators.uiRoute(!1),OTHER_NODE_ENV:validators.nodeEnv(!1),OTHER_LISTEN_TO_PROCESS_EXITS:validators.listenToProcessExits(!1),OTHER_NO_LOGO:validators.noLogo(!1),OTHER_HARD_RESET_PAGE:validators.hardResetPage(!1),OTHER_BROWSER_SHELL_MODE:validators.browserShellMode(!1),OTHER_VALIDATION:validators.validation(!1),DEBUG_ENABLE:validators.enableDebug(!1),DEBUG_HEADLESS:validators.headless(!1),DEBUG_DEVTOOLS:validators.devtools(!1),DEBUG_LISTEN_TO_CONSOLE:validators.listenToConsole(!1),DEBUG_DUMPIO:validators.dumpio(!1),DEBUG_SLOW_MO:validators.slowMo(!1),DEBUG_DEBUGGING_PORT:validators.debuggingPort(!1)}),envs=EnvSchema.partial().parse(process.env);function strictValidate(e){return StrictConfigSchema.partial().parse(e)}function looseValidate(e){return LooseConfigSchema.partial().parse(e)}function _customErrorMap(e,t){const o=e.path.join("."),r=`Invalid value for the ${o}`;if(e.code===z.ZodIssueCode.invalid_type)return e.received===z.ZodParsedType.undefined?{message:`${r} - No value was provided.`}:{message:`${r} - Invalid type. ${t.defaultError}.`};if(e.code===z.ZodIssueCode.custom&&e.params?.errorMessage)return{message:`${r} - ${e.params?.errorMessage}, received '${t.data}'.`};if(e.code===z.ZodIssueCode.invalid_union){let t=`Multiple errors occurred for the ${o}:\n`;return e.unionErrors.forEach((e=>{const o=e.issues[0].message.indexOf("-");t+=-1!==o?`${e.issues[0].message}\n`.substring(o):`${e.issues[0].message}\n`})),{message:t}}return{message:`${r} - ${t.defaultError}.`}}class ExportError extends Error{constructor(e,t){super(),this.message=e,this.stackMessage=e,t&&(this.statusCode=t)}setStatus(e){return this.statusCode=e,this}setError(e){return this.error=e,e.name&&(this.name=e.name),e.statusCode&&(this.statusCode=e.statusCode),e.stack&&(this.stackMessage=e.message,this.stack=e.stack),this}}const globalOptions=_initOptions(defaultConfig);function getOptions(e=!0){return e?deepCopy(globalOptions):globalOptions}function updateOptions(e,t=!1,o=!0){return _mergeOptions(getOptions(t),validateOptions(e,o))}function mapToNewOptions(e){const t={};if(isObject(e))for(const[o,r]of Object.entries(e)){const e=nestedProps[o]?nestedProps[o].split("."):[];e.reduce(((t,o,i)=>t[o]=e.length-1===i?r:t[o]||{}),t)}else log(2,"[config] No correct object with options was provided. Returning an empty array.");return t}function validateOption(e,t,o=!0){if(!getOptions().other.validation)return t;try{return validators[e](o).parse(t)}catch(t){throw logZodIssues(1,t.issues,`[validation] The ${e} option validation error`),new ExportError(`[validation] The ${e} option validation error`,400)}}function validateOptions(e,t=!0){if(!getOptions().other.validation)return e;try{return t?strictValidate(e):looseValidate(e)}catch(e){throw logZodIssues(1,e.issues,"[validation] Options validation error"),new ExportError("[validation] Options validation error",400)}}function isAllowedConfig(config,toString=!1,allowFunctions=!1){try{if(!isObject(config)&&"string"!=typeof config)return null;const objectConfig="string"==typeof config?allowFunctions?eval(`(${config})`):JSON.parse(config):config,stringifiedOptions=_optionsStringify(objectConfig,allowFunctions,!1),parsedOptions=allowFunctions?JSON.parse(_optionsStringify(objectConfig,allowFunctions,!0),((_,value)=>"string"==typeof value&&value.startsWith("function")?eval(`(${value})`):value)):JSON.parse(stringifiedOptions);return toString?stringifiedOptions:parsedOptions}catch(e){return null}}function _initOptions(e){const t={};for(const[o,r]of Object.entries(e))Object.prototype.hasOwnProperty.call(r,"value")?void 0!==envs[r.envLink]&&null!==envs[r.envLink]?t[o]=envs[r.envLink]:t[o]=r.value:t[o]=_initOptions(r);return t}function _mergeOptions(e,t){if(isObject(e)&&isObject(t))for(const[o,r]of Object.entries(t))e[o]=isObject(r)&&!absoluteProps.includes(o)&&void 0!==e[o]?_mergeOptions(e[o],r):void 0!==r?r:e[o]||null;return e}function _optionsStringify(e,t,o){return JSON.stringify(e,((e,r)=>{if("string"==typeof r&&(r=r.trim()),"function"==typeof r||"string"==typeof r&&r.startsWith("function")&&r.endsWith("}")){if(t)return o?`"EXP_FUN${(r+"").replaceAll(/\s+/g," ")}EXP_FUN"`:`EXP_FUN${(r+"").replaceAll(/\s+/g," ")}EXP_FUN`;throw new Error}return r})).replaceAll(o?/\\"EXP_FUN|EXP_FUN\\"/g:/"EXP_FUN|EXP_FUN"/g,"")}async function fetch(e,t={}){return new Promise(((o,r)=>{_getProtocolModule(e).get(e,t,(e=>{let t="";e.on("data",(e=>{t+=e})),e.on("end",(()=>{t||r("Nothing was fetched from the URL."),e.text=t,o(e)}))})).on("error",(e=>{r(e)}))}))}function _getProtocolModule(e){return e.startsWith("https")?https:http}const cache={cdnUrl:"https://code.highcharts.com",activeManifest:{},sources:"",hcVersion:""};async function checkAndUpdateCache(e,t){try{let o;const r=getCachePath(),i=join(r,"manifest.json"),n=join(r,"sources.js");if(!existsSync(r)&&mkdirSync(r,{recursive:!0}),!existsSync(i)||e.forceFetch)log(3,"[cache] Fetching and caching Highcharts dependencies."),o=await _updateCache(e,t,n);else{let r=!1;const s=JSON.parse(readFileSync(i),"utf8");if(s.modules&&Array.isArray(s.modules)){const e={};s.modules.forEach((t=>e[t]=1)),s.modules=e}const{coreScripts:a,moduleScripts:l,indicatorScripts:c}=e,p=a.length+l.length+c.length;s.version!==e.version?(log(2,"[cache] A Highcharts version mismatch in the cache, need to re-fetch."),r=!0):Object.keys(s.modules||{}).length!==p?(log(2,"[cache] The cache and the requested modules do not match, need to re-fetch."),r=!0):r=(l||[]).some((e=>{if(!s.modules[e])return log(2,`[cache] The ${e} is missing in the cache, need to re-fetch.`),!0})),r?o=await _updateCache(e,t,n):(log(3,"[cache] Dependency cache is up to date, proceeding."),cache.sources=readFileSync(n,"utf8"),o=s.modules,cache.hcVersion=extractVersion(cache.sources))}await _saveConfigToManifest(e,o)}catch(e){throw new ExportError("[cache] Could not configure cache and create or update the config manifest.",500).setError(e)}}function getHighchartsVersion(){return cache.hcVersion}async function updateHighchartsVersion(e){const t=updateOptions({highcharts:{version:e}});await checkAndUpdateCache(t.highcharts,t.server.proxy)}function extractVersion(e){return e.substring(0,e.indexOf("*/")).replace("/*","").replace("*/","").replace(/\n/g,"").trim()}function extractModuleName(e){return e.replace(/(.*)\/|(.*)modules\/|stock\/(.*)indicators\/|maps\/(.*)modules\//gi,"")}function getCachePath(){return getAbsolutePath(getOptions().highcharts.cachePath)}async function _fetchAndProcessScript(e,t,o,r=!1){e.endsWith(".js")&&(e=e.substring(0,e.length-3)),log(4,`[cache] Fetching script - ${e}.js`);const i=await fetch(`${e}.js`,t);if(200===i.statusCode&&"string"==typeof i.text){if(o){o[extractModuleName(e)]=1}return i.text}if(r)throw new ExportError(`[cache] Could not fetch the ${e}.js. The script might not exist in the requested version (status code: ${i.statusCode}).`,404).setError(i);log(2,`[cache] Could not fetch the ${e}.js. The script might not exist in the requested version.`)}async function _saveConfigToManifest(e,t={}){const o={version:e.version,modules:t};cache.activeManifest=o,log(3,"[cache] Writing a new manifest.");try{writeFileSync(join(getCachePath(),"manifest.json"),JSON.stringify(o),"utf8")}catch(e){throw new ExportError("[cache] Error writing the cache manifest.",500).setError(e)}}async function _fetchScripts(e,t,o,r,i){let n;const s=r.host,a=r.port;if(s&&a)try{n=new HttpsProxyAgent({host:s,port:a})}catch(e){throw new ExportError("[cache] Could not create a Proxy Agent.",500).setError(e)}const l=n?{agent:n,timeout:r.timeout}:{},c=[...e.map((e=>_fetchAndProcessScript(`${e}`,l,i,!0))),...t.map((e=>_fetchAndProcessScript(`${e}`,l,i))),...o.map((e=>_fetchAndProcessScript(`${e}`,l)))];return(await Promise.all(c)).join(";\n")}async function _updateCache(e,t,o){const r="latest"===e.version?null:`${e.version}`,i=e.cdnUrl||cache.cdnUrl;try{const n={};return log(3,`[cache] Updating cache version to Highcharts: ${r||"latest"}.`),cache.sources=await _fetchScripts([...e.coreScripts.map((e=>r?`${i}/${r}/${e}`:`${i}/${e}`))],[...e.moduleScripts.map((e=>"map"===e?r?`${i}/maps/${r}/modules/${e}`:`${i}/maps/modules/${e}`:r?`${i}/${r}/modules/${e}`:`${i}/modules/${e}`)),...e.indicatorScripts.map((e=>r?`${i}/stock/${r}/indicators/${e}`:`${i}/stock/indicators/${e}`))],e.customScripts,t,n),cache.hcVersion=extractVersion(cache.sources),writeFileSync(o,cache.sources),n}catch(e){throw new ExportError("[cache] Unable to update the local Highcharts cache.",500).setError(e)}}function setupHighcharts(){Highcharts.animObject=function(){return{duration:0}}}async function createChart(e,t){const{getOptions:o,setOptions:r,merge:i,wrap:n}=Highcharts;Highcharts.setOptionsObj=i(!1,{},o()),window.isRenderComplete=!1,n(Highcharts.Chart.prototype,"init",(function(e,t,o){((t=i(t,{exporting:{enabled:!1},plotOptions:{series:{label:{enabled:!1}}},tooltip:{}})).series||[]).forEach((function(e){e.animation=!1})),window.onHighchartsRender||(window.onHighchartsRender=Highcharts.addEvent(this,"render",(()=>{window.isRenderComplete=!0}))),e.apply(this,[t,o])})),n(Highcharts.Series.prototype,"init",(function(e,t,o){e.apply(this,[t,o])}));const s={chart:{animation:!1,height:e.height,width:e.width},exporting:{enabled:!1}},a=new Function(`return ${e.instr}`)(),l=new Function(`return ${e.themeOptions}`)(),c=new Function(`return ${e.globalOptions}`)(),p=i(!1,l,a,s),u=t.callback?new Function(`return ${t.callback}`)():null;t.customCode&&new Function("options",t.customCode)(a),c&&r(c),Highcharts[e.constr]("container",p,u);const d=o();for(const e in d)"function"!=typeof d[e]&&delete d[e];r(Highcharts.setOptionsObj),Highcharts.setOptionsObj={}}const template=readFileSync(join(__dirname,"templates","template.html"),"utf8");let browser=null;async function createBrowser(e){const{debug:t,other:o}=getOptions(),{enable:r,...i}=t,n={headless:!o.browserShellMode||"shell",userDataDir:"tmp",args:e||[],handleSIGINT:!1,handleSIGTERM:!1,handleSIGHUP:!1,waitForInitialPage:!1,defaultViewport:null,...r&&i};if(!browser){let e=0;const t=async()=>{try{log(3,`[browser] Attempting to get a browser instance (try ${++e}).`),browser=await puppeteer.launch(n)}catch(o){if(logWithStack(1,o,"[browser] Failed to launch a browser instance."),!(e<25))throw o;log(3,`[browser] Retry to open a browser (${e} out of 25).`),await new Promise((e=>setTimeout(e,4e3))),await t()}};try{await t(),"shell"===n.headless&&log(3,"[browser] Launched browser in shell mode."),r&&log(3,"[browser] Launched browser in debug mode.")}catch(e){throw new ExportError("[browser] Maximum retries to open a browser instance reached.",500).setError(e)}if(!browser)throw new ExportError("[browser] Cannot find a browser to open.",500)}return browser}async function closeBrowser(){browser&&browser.connected&&await browser.close(),browser=null,log(4,"[browser] Closed the browser.")}async function newPage(e){if(!browser||!browser.connected)throw new ExportError("[browser] Browser is not yet connected.",500);if(e.page=await browser.newPage(),await e.page.setCacheEnabled(!1),await _setPageContent(e.page),_setPageEvents(e.page),!e.page||e.page.isClosed())throw new ExportError("[browser] The page is invalid or closed.",400)}async function clearPage(e,t=!1){try{if(e.page&&!e.page.isClosed())return t?(await e.page.goto("about:blank",{waitUntil:"domcontentloaded"}),await _setPageContent(e.page)):await e.page.evaluate((()=>{document.body.innerHTML='
'})),!0}catch(t){logWithStack(2,t,`[pool] Pool resource [${e.id}] - Content of the page could not be cleared.`),e.workCount=getOptions().pool.workLimit+1}return!1}async function addPageResources(e,t){const o=[],r=t.resources;if(r){const i=[];if(r.js&&i.push({content:r.js}),r.files)for(const e of r.files){const t=!e.startsWith("http");i.push(t?{content:readFileSync(getAbsolutePath(e),"utf8")}:{url:e})}for(const t of i)try{o.push(await e.addScriptTag(t))}catch(e){logWithStack(2,e,"[browser] The JS resource cannot be loaded.")}i.length=0;const n=[];if(r.css){let i=r.css.match(/@import\s*([^;]*);/g);if(i)for(let e of i)e&&(e=e.replace("url(","").replace("@import","").replace(/"/g,"").replace(/'/g,"").replace(/;/,"").replace(/\)/g,"").trim(),e.startsWith("http")?n.push({url:e}):t.allowFileResources&&n.push({path:getAbsolutePath(e)}));n.push({content:r.css.replace(/@import\s*([^;]*);/g,"")||" "});for(const t of n)try{o.push(await e.addStyleTag(t))}catch(e){logWithStack(2,e,"[browser] The CSS resource cannot be loaded.")}n.length=0}}return o}async function clearPageResources(e,t){try{for(const e of t)await e.dispose();await e.evaluate((()=>{if("undefined"!=typeof Highcharts){const e=Highcharts.charts;if(Array.isArray(e)&&e.length)for(const t of e)t&&t.destroy(),Highcharts.charts.shift()}const[...e]=document.getElementsByTagName("script"),[,...t]=document.getElementsByTagName("style"),[...o]=document.getElementsByTagName("link");for(const r of[...e,...t,...o])r.remove()}))}catch(e){logWithStack(2,e,"[browser] Could not clear page's resources.")}}async function _setPageContent(e){await e.setContent(template,{waitUntil:"domcontentloaded"}),await e.addScriptTag({path:join(getCachePath(),"sources.js")}),await e.evaluate(setupHighcharts)}function _setPageEvents(e){const{debug:t}=getOptions();e.on("pageerror",(async()=>{e.isClosed()})),t.enable&&t.listenToConsole&&e.on("console",(e=>{console.log(`[debug] ${e.text()}`)}))}var cssTemplate=()=>"\n\nhtml, body {\n margin: 0;\n padding: 0;\n box-sizing: border-box;\n}\n\n#table-div, #sliders, #datatable, #controls, .ld-row {\n display: none;\n height: 0;\n}\n\n#chart-container {\n box-sizing: border-box;\n margin: 0;\n overflow: auto;\n font-size: 0;\n}\n\n#chart-container > figure, div {\n margin-top: 0 !important;\n margin-bottom: 0 !important;\n}\n\n",svgTemplate=e=>`\n\n\n \n \n Highcharts Export\n \n \n \n
\n ${e}\n
\n \n\n\n`;async function puppeteerExport(e,t,o){const r=[];try{let i=!1;if(t.svg){if(log(4,"[export] Treating as SVG input."),"svg"===t.type)return t.svg;i=!0,await e.setContent(svgTemplate(t.svg),{waitUntil:"domcontentloaded"})}else log(4,"[export] Treating as JSON config."),await e.evaluate(createChart,t,o);r.push(...await addPageResources(e,o));const n=i?await e.evaluate((e=>{const t=document.querySelector("#chart-container svg:first-of-type"),o=t.height.baseVal.value*e,r=t.width.baseVal.value*e;return document.body.style.zoom=e,document.body.style.margin="0px",{chartHeight:o,chartWidth:r}}),parseFloat(t.scale)):await e.evaluate((()=>{const{chartHeight:e,chartWidth:t}=window.Highcharts.charts[0];return document.body.style.zoom=1,{chartHeight:e,chartWidth:t}})),{x:s,y:a}=await _getClipRegion(e),l=Math.abs(Math.ceil(n.chartHeight||t.height)),c=Math.abs(Math.ceil(n.chartWidth||t.width));let p;switch(await e.setViewport({height:l,width:c,deviceScaleFactor:i?1:parseFloat(t.scale)}),t.type){case"svg":p=await _createSVG(e);break;case"png":case"jpeg":p=await _createImage(e,t.type,{width:c,height:l,x:s,y:a},t.rasterizationTimeout);break;case"pdf":p=await _createPDF(e,l,c,t.rasterizationTimeout);break;default:throw new ExportError(`[export] Unsupported output format: ${t.type}.`,400)}return await clearPageResources(e,r),p}catch(t){return await clearPageResources(e,r),t}}async function _getClipRegion(e){return e.$eval("#chart-container",(e=>{const{x:t,y:o,width:r,height:i}=e.getBoundingClientRect();return{x:t,y:o,width:r,height:Math.trunc(i>1?i:500)}}))}async function _createSVG(e){return e.$eval("#container svg:first-of-type",(e=>e.outerHTML))}async function _createImage(e,t,o,r){return Promise.race([e.screenshot({type:t,clip:o,encoding:"base64",fullPage:!1,optimizeForSpeed:!0,captureBeyondViewport:!0,..."png"!==t?{quality:80}:{},omitBackground:"png"==t}),new Promise(((e,t)=>setTimeout((()=>t(new ExportError("Rasterization timeout",408))),r||1500)))])}async function _createPDF(e,t,o,r){return await e.emulateMediaType("screen"),e.pdf({height:t+1,width:o,encoding:"base64",timeout:r||1500})}let pool=null;const poolStats={exportsAttempted:0,exportsPerformed:0,exportsDropped:0,exportsFromSvg:0,exportsFromOptions:0,exportsFromSvgAttempts:0,exportsFromOptionsAttempts:0,timeSpent:0,timeSpentAverage:0};async function initPool(e,t){await createBrowser(t);try{if(log(3,`[pool] Initializing pool with workers: min ${e.minWorkers}, max ${e.maxWorkers}.`),pool)return void log(4,"[pool] Already initialized, please kill it before creating a new one.");e.minWorkers>e.maxWorkers&&(e.minWorkers=e.maxWorkers),pool=new Pool({..._factory(e),min:e.minWorkers,max:e.maxWorkers,acquireTimeoutMillis:e.acquireTimeout,createTimeoutMillis:e.createTimeout,destroyTimeoutMillis:e.destroyTimeout,idleTimeoutMillis:e.idleTimeout,createRetryIntervalMillis:e.createRetryInterval,reapIntervalMillis:e.reaperInterval,propagateCreateError:!1}),pool.on("release",(async e=>{const t=await clearPage(e,!1);log(4,`[pool] Pool resource [${e.id}] - Releasing a worker. Clear page status: ${t}.`)})),pool.on("destroySuccess",((e,t)=>{log(4,`[pool] Pool resource [${t.id}] - Destroyed a worker successfully.`),t.page=null}));const t=[];for(let o=0;o{pool.release(e)})),log(3,"[pool] The pool is ready"+(t.length?` with ${t.length} initial resources waiting.`:"."))}catch(e){throw new ExportError("[pool] Could not configure and create the pool of workers.",500).setError(e)}}async function killPool(){if(log(3,"[pool] Killing pool with all workers and closing browser."),pool){for(const e of pool.used)pool.release(e.resource);pool.destroyed||(await pool.destroy(),log(4,"[pool] Destroyed the pool of resources.")),pool=null}await closeBrowser()}async function postWork(e){let t;try{if(log(4,"[pool] Work received, starting to process."),++poolStats.exportsAttempted,e.pool.benchmarking&&getPoolInfo(),!pool)throw new ExportError("[pool] Work received, but pool has not been started.",500);const o=measureTime();try{log(4,"[pool] Acquiring a worker handle."),t=await pool.acquire().promise,e.server.benchmarking&&log(5,"[benchmark] "+(e.requestId?`Request [${e.requestId}] - `:""),`Acquiring a worker handle took ${o()}ms.`)}catch(t){throw new ExportError(`[pool] ${e.requestId?`Request [${e.requestId}] - `:""}Error encountered when acquiring an available entry: ${o()}ms.`,400).setError(t)}if(log(4,"[pool] Acquired a worker handle."),!t.page)throw t.workCount=e.pool.workLimit+1,new ExportError("[pool] Resolved worker page is invalid: the pool setup is wonky.",400);const r=getNewDateTime();log(4,`[pool] Pool resource [${t.id}] - Starting work on this pool entry.`);const i=measureTime(),n=await puppeteerExport(t.page,e.export,e.customLogic);if(n instanceof Error)throw"Rasterization timeout"===n.message&&(t.workCount=e.pool.workLimit+1,t.page=null),"TimeoutError"===n.name||"Rasterization timeout"===n.message?new ExportError(`[pool] ${e.requestId?`Request [${e.requestId}] - `:""}Rasterization timeout: your chart may be too complex or large, and failed to render within the allotted time.`).setError(n):new ExportError(`[pool] ${e.requestId?`Request [${e.requestId}] - `:""}Error encountered during export: ${i()}ms.`).setError(n);e.server.benchmarking&&log(5,"[benchmark] "+(e.requestId?`Request [${e.requestId}] - `:""),`Exporting a chart sucessfully took ${i()}ms.`),pool.release(t);const s=getNewDateTime()-r;return poolStats.timeSpent+=s,poolStats.timeSpentAverage=poolStats.timeSpent/++poolStats.exportsPerformed,log(4,`[pool] Work completed in ${s}ms.`),{result:n,options:e}}catch(e){throw++poolStats.exportsDropped,t&&pool.release(t),e}}function getPoolStats(){return poolStats}function getPoolInfoJSON(){return{min:pool.min,max:pool.max,used:pool.numUsed(),available:pool.numFree(),allCreated:pool.numUsed()+pool.numFree(),pendingAcquires:pool.numPendingAcquires(),pendingCreates:pool.numPendingCreates(),pendingValidations:pool.numPendingValidations(),pendingDestroys:pool.pendingDestroys.length,absoluteAll:pool.numUsed()+pool.numFree()+pool.numPendingAcquires()+pool.numPendingCreates()+pool.numPendingValidations()+pool.pendingDestroys.length}}function getPoolInfo(){const{min:e,max:t,used:o,available:r,allCreated:i,pendingAcquires:n,pendingCreates:s,pendingValidations:a,pendingDestroys:l,absoluteAll:c}=getPoolInfoJSON();log(5,`[pool] The minimum number of resources allowed by pool: ${e}.`),log(5,`[pool] The maximum number of resources allowed by pool: ${t}.`),log(5,`[pool] The number of used resources: ${o}.`),log(5,`[pool] The number of free resources: ${r}.`),log(5,`[pool] The number of all created (used and free) resources: ${i}.`),log(5,`[pool] The number of resources waiting to be acquired: ${n}.`),log(5,`[pool] The number of resources waiting to be created: ${s}.`),log(5,`[pool] The number of resources waiting to be validated: ${a}.`),log(5,`[pool] The number of resources waiting to be destroyed: ${l}.`),log(5,`[pool] The number of all resources: ${c}.`)}function _factory(e){return{create:async()=>{const t={id:v4(),workCount:Math.round(Math.random()*(e.workLimit/2))};try{const e=getNewDateTime();return await newPage(t),log(3,`[pool] Pool resource [${t.id}] - Successfully created a worker, took ${getNewDateTime()-e}ms.`),t}catch(e){throw log(3,`[pool] Pool resource [${t.id}] - Error encountered when creating a new page.`),e}},validate:async t=>t.page?t.page.isClosed()?(log(3,`[pool] Pool resource [${t.id}] - Validation failed (page is closed or invalid).`),!1):t.page.mainFrame().detached?(log(3,`[pool] Pool resource [${t.id}] - Validation failed (page's frame is detached).`),!1):!(e.workLimit&&++t.workCount>e.workLimit)||(log(3,`[pool] Pool resource [${t.id}] - Validation failed (exceeded the ${e.workLimit} works per resource limit).`),!1):(log(3,`[pool] Pool resource [${t.id}] - Validation failed (no valid page is found).`),!1),destroy:async e=>{if(log(3,`[pool] Pool resource [${e.id}] - Destroying a worker.`),e.page&&!e.page.isClosed())try{e.page.removeAllListeners("pageerror"),e.page.removeAllListeners("console"),e.page.removeAllListeners("framedetached"),await e.page.close()}catch(t){throw log(3,`[pool] Pool resource [${e.id}] - Page could not be closed upon destroying.`),t}}}}function sanitize(e){const t=new JSDOM("").window;return DOMPurify(t).sanitize(e,{ADD_TAGS:["foreignObject"]})}let allowCodeExecution=!1;async function singleExport(e){if(!e||!e.export)throw new ExportError("[chart] No expected `export` options were found. Please provide one of the following options: `infile`, `instr`, `options`, or `svg` to generate a valid image.",400);await startExport({export:e.export,customLogic:e.customLogic},(async(e,t)=>{if(e)throw e;const{b64:o,outfile:r,type:i}=t.options.export;try{o?writeFileSync(`${r.split(".").shift()||"chart"}.txt`,getBase64(t.result,i)):writeFileSync(r||`chart.${i}`,"svg"!==i?Buffer.from(t.result,"base64"):t.result)}catch(e){throw new ExportError("[chart] Error while saving a chart.",500).setError(e)}await killPool()}))}async function batchExport(e){if(!(e&&e.export&&e.export.batch))throw new ExportError("[chart] No expected `export` options were found. Please provide the `batch` option to generate valid images.",400);{const t=[];for(let o of e.export.batch.split(";")||[])o=o.split("="),2===o.length?t.push(startExport({export:{...e.export,infile:o[0],outfile:o[1]},customLogic:e.customLogic},((e,t)=>{if(e)throw e;const{b64:o,outfile:r,type:i}=t.options.export;try{o?writeFileSync(`${r.split(".").shift()||"chart"}.txt`,getBase64(t.result,i)):writeFileSync(r,"svg"!==i?Buffer.from(t.result,"base64"):t.result)}catch(e){throw new ExportError("[chart] Error while saving a chart.",500).setError(e)}}))):log(2,"[chart] No correct pair found for the batch export.");const o=await Promise.allSettled(t);await killPool(),o.forEach(((e,t)=>{e.reason&&logWithStack(1,e.reason,`[chart] Batch export number ${t+1} could not be correctly completed.`)}))}}async function startExport(e,t){try{if(!isObject(e))throw new ExportError("[chart] Incorrect value of the provided `imageOptions`. Needs to be an object.",400);const o=updateOptions({export:e.export,customLogic:e.customLogic},!0),r=o.export;if(log(4,"[chart] Starting the exporting process."),null!==r.infile){let e;log(4,"[chart] Attempting to export from a file input.");try{e=readFileSync(getAbsolutePath(r.infile),"utf8")}catch(e){throw new ExportError("[chart] Error loading content from a file input.",400).setError(e)}if(r.infile.endsWith(".svg"))r.svg=validateOption("svg",e);else{if(!r.infile.endsWith(".json"))throw new ExportError("[chart] Incorrect value of the `infile` option.",400);r.instr=validateOption("instr",e)}}if(null!==r.svg){log(4,"[chart] Attempting to export from an SVG input."),++getPoolStats().exportsFromSvgAttempts;const e=await _exportFromSvg(sanitize(r.svg),o);return++getPoolStats().exportsFromSvg,t(null,e)}if(null!==r.instr||null!==r.options){log(4,"[chart] Attempting to export from options input."),++getPoolStats().exportsFromOptionsAttempts;const e=await _exportFromOptions(r.instr||r.options,o);return++getPoolStats().exportsFromOptions,t(null,e)}return t(new ExportError("[chart] No valid input specified. Check if at least one of the following parameters is correctly set: 'infile', 'instr', 'options', or 'svg'.",400))}catch(e){return t(e)}}function getAllowCodeExecution(){return allowCodeExecution}function setAllowCodeExecution(e){allowCodeExecution=e}async function _exportFromSvg(e,t){if("string"==typeof e&&(e.indexOf("=0||e.indexOf("=0))return log(4,"[chart] Parsing input as SVG."),t.export.svg=e,t.export.instr=null,t.export.options=null,_prepareExport(t);throw new ExportError("[chart] Not a correct SVG input.",400)}async function _exportFromOptions(e,t){log(4,"[chart] Parsing input from options.");const o=isAllowedConfig(e,!0,t.customLogic.allowCodeExecution);if(null===o||"string"!=typeof o||!o.startsWith("{")||!o.endsWith("}"))throw new ExportError("[chart] Invalid configuration provided - Only options configurations and SVG are allowed for this server. If this is your server, JavaScript custom code can be enabled by starting the server with the `allowCodeExecution` options set to true.",403);return t.export.instr=o,t.export.svg=null,_prepareExport(t)}async function _prepareExport(e){const{export:t,customLogic:o}=e;return t.type=fixType(t.type,t.outfile),t.outfile=fixOutfile(t.type,t.outfile),t.constr=fixConstr(t.constr),log(3,`[chart] The custom logic is ${o.allowCodeExecution?"allowed":"disallowed"}.`),_handleCustomLogic(o,o.allowCodeExecution),_handleGlobalAndTheme(t,o.allowFileResources,o.allowCodeExecution),e.export={...t,..._findChartSize(t)},postWork(e)}function _findChartSize(e){const{chart:t,exporting:o}=e.options||isAllowedConfig(e.instr)||!1,{chart:r,exporting:i}=isAllowedConfig(e.globalOptions)||!1,{chart:n,exporting:s}=isAllowedConfig(e.themeOptions)||!1,a=roundNumber(Math.max(.1,Math.min(e.scale||o?.scale||i?.scale||s?.scale||e.defaultScale||1,5)),2),l={height:e.height||o?.sourceHeight||t?.height||i?.sourceHeight||r?.height||s?.sourceHeight||n?.height||e.defaultHeight||400,width:e.width||o?.sourceWidth||t?.width||i?.sourceWidth||r?.width||s?.sourceWidth||n?.width||e.defaultWidth||600,scale:a};for(let[e,t]of Object.entries(l))l[e]="string"==typeof t?+t.replace(/px|%/gi,""):t;return l}function _handleCustomLogic(e,t){if(t){if("string"==typeof e.resources)e.resources=_handleResources(e.resources,e.allowFileResources,!0);else if(!e.resources)try{e.resources=_handleResources(readFileSync(getAbsolutePath("resources.json"),"utf8"),e.allowFileResources,!0)}catch(e){log(2,"[chart] Unable to load the default `resources.json` file.")}try{e.customCode=wrapAround(e.customCode,e.allowFileResources),e.customCode=validateOption("customCode",e.customCode)}catch(t){logWithStack(2,t,"[chart] The `customCode` cannot be loaded."),e.customCode=null}try{e.callback=wrapAround(e.callback,e.allowFileResources,!0),e.callback=validateOption("callback",e.callback)}catch(t){logWithStack(2,t,"[chart] The `callback` cannot be loaded."),e.callback=null}[null,void 0].includes(e.customCode)&&log(3,"[chart] No value for the `customCode` option found."),[null,void 0].includes(e.callback)&&log(3,"[chart] No value for the `callback` option found."),[null,void 0].includes(e.resources)&&log(3,"[chart] No value for the `resources` option found.")}else if(e.callback||e.resources||e.customCode)throw e.callback=null,e.resources=null,e.customCode=null,new ExportError("[chart] The 'callback', 'resources', and 'customCode' options have been disabled for this server.",403)}function _handleResources(e=null,t,o){const r=["js","css","files"];let i=e,n=!1;if(t&&e.endsWith(".json"))try{i=isAllowedConfig(readFileSync(getAbsolutePath(e),"utf8"),!1,o)}catch{return null}else i=isAllowedConfig(e,!1,o),i&&!t&&delete i.files;for(const e in i)r.includes(e)?n||(n=!0):delete i[e];return n?(i.files&&(i.files=i.files.map((e=>e.trim())),(!i.files||i.files.length<=0)&&delete i.files),i=validateOption("resources",i),i):null}function _handleGlobalAndTheme(e,t,o){["globalOptions","themeOptions"].forEach((r=>{try{e[r]&&(t&&"string"==typeof e[r]&&e[r].endsWith(".json")?e[r]=isAllowedConfig(readFileSync(getAbsolutePath(e[r]),"utf8"),!0,o):e[r]=isAllowedConfig(e[r],!0,o),e[r]=validateOption(r,e[r]))}catch(t){logWithStack(2,t,`[chart] The \`${r}\` cannot be loaded.`),e[r]=null}})),[null,void 0].includes(e.globalOptions)&&log(3,"[chart] No value for the `globalOptions` option found."),[null,void 0].includes(e.themeOptions)&&log(3,"[chart] No value for the `themeOptions` option found.")}const timerIds=[];function addTimer(e){timerIds.push(e)}function clearAllTimers(){log(4,"[timer] Clearing all registered intervals and timeouts.");for(const e of timerIds)clearInterval(e),clearTimeout(e)}function logErrorMiddleware(e,t,o,r){return logWithStack(1,e),"development"!==getOptions().other.nodeEnv&&delete e.stack,r(e)}function returnErrorMiddleware(e,t,o,r){const{message:i,stack:n}=e,s=e.statusCode||400;o.status(s).json({statusCode:s,message:i,stack:n})}function errorMiddleware(e){e.use(logErrorMiddleware),e.use(returnErrorMiddleware)}function rateLimitingMiddleware(e,t){try{if(e&&t.enable){const o="Too many requests, you have been rate limited. Please try again later.",r={window:t.window||1,maxRequests:t.maxRequests||30,delay:t.delay||0,trustProxy:t.trustProxy||!1,skipKey:t.skipKey||null,skipToken:t.skipToken||null};r.trustProxy&&e.enable("trust proxy");const i=rateLimit({windowMs:60*r.window*1e3,limit:r.maxRequests,delayMs:r.delay,handler:(e,t)=>{t.format({json:()=>{t.status(429).send({message:o})},default:()=>{t.status(429).send(o)}})},skip:e=>null!==r.skipKey&&null!==r.skipToken&&e.query.key===r.skipKey&&e.query.access_token===r.skipToken&&(log(4,"[rate limiting] Skipping rate limiter."),!0)});e.use(i),log(3,`[rate limiting] Enabled rate limiting with ${r.maxRequests} requests per ${r.window} minute for each IP, trusting proxy: ${r.trustProxy}.`)}}catch(e){throw new ExportError("[rate limiting] Could not configure and set the rate limiting options.",500).setError(e)}}function contentTypeMiddleware(e,t,o){try{const t=e.headers["content-type"]||"";if(!t.includes("application/json")&&!t.includes("application/x-www-form-urlencoded")&&!t.includes("multipart/form-data"))throw new ExportError("[validation] Content-Type must be application/json, application/x-www-form-urlencoded, or multipart/form-data.",415);return o()}catch(e){return o(e)}}function requestBodyMiddleware(e,t,o){try{const t=e.body,r=v4();if(!t||isObjectEmpty(t))throw log(2,`[validation] Request [${r}] - The request from ${e.headers["x-forwarded-for"]||e.connection.remoteAddress} was incorrect. Received payload is empty.`),new ExportError(`[validation] Request [${r}] - The request body is required. Please ensure that your Content-Type header is correct. Accepted types are 'application/json' and 'multipart/form-data'.`,400);const i=getAllowCodeExecution(),n=isAllowedConfig(t.instr||t.options||t.infile||t.data,!0,i);if(null===n&&!t.svg)throw log(2,`[validation] Request [${r}] - The request from ${e.headers["x-forwarded-for"]||e.connection.remoteAddress} was incorrect. Received payload is missing correct chart data for export: ${JSON.stringify(t)}.`),new ExportError(`Request [${r}] - [validation] No correct chart data found. Ensure that you are using either application/json or multipart/form-data headers. If sending JSON, make sure the chart data is in the 'infile', 'options', or 'data' attribute. If sending SVG, ensure it is in the 'svg' attribute.`,400);if(t.svg&&isPrivateRangeUrlFound(t.svg))throw new ExportError(`Request [${r}] - [validation] SVG potentially contain at least one forbidden URL in 'xlink:href' element. Please review the SVG content and ensure that all referenced URLs comply with security policies.`,400);return e.validatedOptions={requestId:r,export:{instr:n,svg:t.svg,outfile:t.outfile||`${e.params.filename||"chart"}.${t.type||"png"}`,type:t.type,constr:t.constr,b64:t.b64,noDownload:t.noDownload,height:t.height,width:t.width,scale:t.scale,globalOptions:isAllowedConfig(t.globalOptions,!0,i),themeOptions:isAllowedConfig(t.themeOptions,!0,i)},customLogic:{allowCodeExecution:i,allowFileResources:!1,customCode:t.customCode,callback:t.callback,resources:isAllowedConfig(t.resources,!0,i)}},o()}catch(e){return o(e)}}function validationMiddleware(e){e.post(["/","/:filename"],contentTypeMiddleware),e.post(["/","/:filename"],requestBodyMiddleware)}const reversedMime={png:"image/png",jpeg:"image/jpeg",gif:"image/gif",pdf:"application/pdf",svg:"image/svg+xml"};async function requestExport(e,t,o){try{const o=measureTime();let r=!1;e.socket.on("close",(e=>{e&&(r=!0)}));const i=e.validatedOptions,n=i.requestId;log(4,`[export] Request [${n}] - Got an incoming HTTP request.`),await startExport(i,((i,s)=>{if(e.socket.removeAllListeners("close"),r)log(3,`[export] Request [${n}] - The client closed the connection before the chart finished processing.`);else{if(i)throw i;if(!s||!s.result)throw log(2,`[export] Request [${n}] - Request from ${e.headers["x-forwarded-for"]||e.connection.remoteAddress} was incorrect. Received result is ${s.result}.`),new ExportError(`[export] Request [${n}] - Unexpected return of the export result from the chart generation. Please check your request data.`,400);if(s.result){log(3,`[export] Request [${n}] - The whole exporting process took ${o()}ms.`);const{type:e,b64:r,noDownload:i,outfile:a}=s.options.export;return r?t.send(getBase64(s.result,e)):(t.header("Content-Type",reversedMime[e]||"image/png"),i||t.attachment(a),"svg"===e?t.send(s.result):t.send(Buffer.from(s.result,"base64")))}}}))}catch(e){return o(e)}}function exportRoutes(e){e.post("/",requestExport),e.post("/:filename",requestExport)}const serverStartTime=new Date,packageFile=JSON.parse(readFileSync(join(__dirname,"package.json"),"utf8")),successRates=[],recordInterval=6e4,windowSize=30;function _calculateMovingAverage(){return successRates.reduce(((e,t)=>e+t),0)/successRates.length}function _startSuccessRate(){return setInterval((()=>{const e=getPoolStats(),t=0===e.exportsAttempted?1:e.exportsPerformed/e.exportsAttempted*100;successRates.push(t),successRates.length>windowSize&&successRates.shift()}),recordInterval)}function healthRoutes(e){addTimer(_startSuccessRate()),e.get("/health",((e,t,o)=>{try{log(4,"[health] Returning server health.");const e=getPoolStats(),o=successRates.length,r=_calculateMovingAverage();t.send({status:"OK",bootTime:serverStartTime,uptime:`${Math.floor((getNewDateTime()-serverStartTime.getTime())/1e3/60)} minutes`,serverVersion:packageFile.version,highchartsVersion:getHighchartsVersion(),averageExportTime:e.timeSpentAverage,attemptedExports:e.exportsAttempted,performedExports:e.exportsPerformed,failedExports:e.exportsDropped,sucessRatio:e.exportsPerformed/e.exportsAttempted*100,pool:getPoolInfoJSON(),period:o,movingAverage:r,message:isNaN(r)||!successRates.length?"Too early to report. No exports made yet. Please check back soon.":`Last ${o} minutes had a success rate of ${r.toFixed(2)}%.`,svgExports:e.exportsFromSvg,jsonExports:e.exportsFromOptions,svgExportsAttempts:e.exportsFromSvgAttempts,jsonExportsAttempts:e.exportsFromOptionsAttempts})}catch(e){return o(e)}}))}function uiRoutes(e){e.get(getOptions().ui.route||"/",((e,t,o)=>{try{log(4,"[ui] Returning UI for the export."),t.sendFile(join(__dirname,"public","index.html"),{acceptRanges:!1})}catch(e){return o(e)}}))}function versionChangeRoutes(e){e.post("/version_change/:newVersion",(async(e,t,o)=>{try{log(4,"[version] Changing Highcharts version.");const o=envs.HIGHCHARTS_ADMIN_TOKEN;if(!o||!o.length)throw new ExportError("[version] The server is not configured to perform run-time version changes: HIGHCHARTS_ADMIN_TOKEN is not set.",401);const r=e.get("hc-auth");if(!r||r!==o)throw new ExportError("[version] Invalid or missing token: Set the token in the hc-auth header.",401);const i=e.params.newVersion;if(!i)throw new ExportError("[version] No new version supplied.",400);try{await updateHighchartsVersion(i)}catch(e){throw new ExportError(`[version] Version change: ${e.message}`,400).setError(e)}t.status(200).send({statusCode:200,highchartsVersion:getHighchartsVersion(),message:`Successfully updated Highcharts to version: ${i}.`})}catch(e){return o(e)}}))}const activeServers=new Map,app=express();async function startServer(e){try{const t=updateOptions({server:e});if(!(e=t.server).enable||!app)throw new ExportError("[server] Server cannot be started (not enabled or no correct Express app found).",500);const o=1024*e.uploadLimit*1024,r=multer.memoryStorage(),i=multer({storage:r,limits:{fieldSize:o}});if(app.disable("x-powered-by"),app.use(cors({methods:["POST","GET","OPTIONS"]})),app.use(((e,t,o)=>{t.set("Accept-Ranges","none"),o()})),app.use(express.json({limit:o})),app.use(express.urlencoded({extended:!0,limit:o})),app.use(i.none()),app.use(express.static(join(__dirname,"public"))),!e.ssl.force){const t=http.createServer(app);_attachServerErrorHandlers(t),t.listen(e.port,e.host,(()=>{activeServers.set(e.port,t),log(3,`[server] Started HTTP server on ${e.host}:${e.port}.`)}))}if(e.ssl.enable){let t,o;try{t=readFileSync(join(getAbsolutePath(e.ssl.certPath),"server.key"),"utf8"),o=readFileSync(join(getAbsolutePath(e.ssl.certPath),"server.crt"),"utf8")}catch(t){log(2,`[server] Unable to load key/certificate from the '${e.ssl.certPath}' path. Could not run secured layer server.`)}if(t&&o){const r=https.createServer({key:t,cert:o},app);_attachServerErrorHandlers(r),r.listen(e.ssl.port,e.host,(()=>{activeServers.set(e.ssl.port,r),log(3,`[server] Started HTTPS server on ${e.host}:${e.ssl.port}.`)}))}}rateLimitingMiddleware(app,e.rateLimiting),validationMiddleware(app),exportRoutes(app),healthRoutes(app),uiRoutes(app),versionChangeRoutes(app),errorMiddleware(app)}catch(e){throw new ExportError("[server] Could not configure and start the server.",500).setError(e)}}function closeServers(){if(activeServers.size>0){log(4,"[server] Closing all servers.");for(const[e,t]of activeServers)t.close((()=>{activeServers.delete(e),log(4,`[server] Closed server on port: ${e}.`)}))}}function getServers(){return activeServers}function getExpress(){return express}function getApp(){return app}function enableRateLimiting(e){const t=updateOptions({server:{rateLimiting:e}});rateLimitingMiddleware(app,t.server.rateLimitingOptions)}function use(e,...t){app.use(e,...t)}function get(e,...t){app.get(e,...t)}function post(e,...t){app.post(e,...t)}function _attachServerErrorHandlers(e){e.on("clientError",((e,t)=>{logWithStack(1,e,`[server] Client error: ${e.message}, destroying socket.`),t.destroy()})),e.on("error",(e=>{logWithStack(1,e,`[server] Server error: ${e.message}`)})),e.on("connection",(e=>{e.on("error",(e=>{logWithStack(1,e,`[server] Socket error: ${e.message}`)}))}))}var server={startServer:startServer,closeServers:closeServers,getServers:getServers,getExpress:getExpress,getApp:getApp,enableRateLimiting:enableRateLimiting,use:use,get:get,post:post};async function shutdownCleanUp(e=0){await Promise.allSettled([clearAllTimers(),closeServers(),killPool()]),process.exit(e)}async function initExport(e){const t=updateOptions(e);setAllowCodeExecution(t.customLogic.allowCodeExecution),initLogging(t.logging),t.other.listenToProcessExits&&_attachProcessExitListeners(),await checkAndUpdateCache(t.highcharts,t.server.proxy),await initPool(t.pool,t.puppeteer.args)}function _attachProcessExitListeners(){log(3,"[process] Attaching exit listeners to the process."),process.on("exit",(e=>{log(4,`[process] Process exited with code ${e}.`)})),process.on("SIGINT",(async(e,t)=>{log(4,`[process] The ${e} event with code: ${t}.`),await shutdownCleanUp()})),process.on("SIGTERM",(async(e,t)=>{log(4,`[process] The ${e} event with code: ${t}.`),await shutdownCleanUp()})),process.on("SIGHUP",(async(e,t)=>{log(4,`[process] The ${e} event with code: ${t}.`),await shutdownCleanUp()})),process.on("uncaughtException",(async(e,t)=>{logWithStack(1,e,`[process] The ${t} error.`),await shutdownCleanUp(1)}))}var index={...server,getOptions:getOptions,updateOptions:updateOptions,mapToNewOptions:mapToNewOptions,validateOption:validateOption,validateOptions:validateOptions,initExport:initExport,singleExport:singleExport,batchExport:batchExport,startExport:startExport,killPool:killPool,shutdownCleanUp:shutdownCleanUp,log:log,logWithStack:logWithStack,logZodIssues:logZodIssues,setLogLevel:function(e){setLogLevel(updateOptions({logging:{level:e}}).logging.level)},enableConsoleLogging:function(e){enableConsoleLogging(updateOptions({logging:{toConsole:e}}).logging.toConsole)},enableFileLogging:function(e,t,o){const r=updateOptions({logging:{dest:e,file:t,toFile:o}});enableFileLogging(r.logging.dest,r.logging.file,r.logging.toFile)}};export{index as default,initExport}; //# sourceMappingURL=index.esm.js.map diff --git a/dist/index.esm.js.map b/dist/index.esm.js.map index e26d85c7..4eb4c3b2 100644 --- a/dist/index.esm.js.map +++ b/dist/index.esm.js.map @@ -1 +1 @@ -{"version":3,"file":"index.esm.js","sources":["../lib/utils.js","../lib/logger.js","../lib/schemas/config.js","../lib/validation.js","../lib/errors/ExportError.js","../lib/config.js","../lib/fetch.js","../lib/cache.js","../lib/highcharts.js","../lib/browser.js","../templates/svgExport/css.js","../templates/svgExport/svgExport.js","../lib/export.js","../lib/pool.js","../lib/sanitize.js","../lib/chart.js","../lib/timer.js","../lib/server/middlewares/error.js","../lib/server/middlewares/rateLimiting.js","../lib/server/middlewares/validation.js","../lib/server/routes/export.js","../lib/server/routes/health.js","../lib/server/routes/ui.js","../lib/server/routes/versionChange.js","../lib/server/server.js","../lib/resourceRelease.js","../lib/index.js"],"sourcesContent":["/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * @overview The Highcharts Export Server utility module provides\r\n * a comprehensive set of helper functions and constants designed to streamline\r\n * and enhance various operations required for Highcharts export tasks.\r\n */\r\n\r\nimport { readFileSync } from 'fs';\r\nimport { isAbsolute, normalize, resolve } from 'path';\r\nimport { fileURLToPath } from 'url';\r\n\r\nconst MAX_BACKOFF_ATTEMPTS = 6;\r\n\r\n// The directory path\r\nexport const __dirname = fileURLToPath(new URL('../.', import.meta.url));\r\n\r\n/**\r\n * Clears and standardizes text by replacing multiple consecutive whitespace\r\n * characters with a single space and trimming any leading or trailing\r\n * whitespace.\r\n *\r\n * @function clearText\r\n *\r\n * @param {string} text - The input text to be cleared.\r\n * @param {RegExp} [rule=/\\s\\s+/g] - The regular expression rule to match\r\n * multiple consecutive whitespace characters. The default value\r\n * is the '/\\s\\s+/g' RegExp.\r\n * @param {string} [replacer=' '] - The string used to replace multiple\r\n * consecutive whitespace characters. The default value is the ' ' string.\r\n *\r\n * @returns {string} The cleared and standardized text.\r\n */\r\nexport function clearText(text, rule = /\\s\\s+/g, replacer = ' ') {\r\n return text.replaceAll(rule, replacer).trim();\r\n}\r\n\r\n/**\r\n * Creates a deep copy of the given object or array.\r\n *\r\n * @function deepCopy\r\n *\r\n * @param {(Object|Array)} objArr - The object or array to be deeply copied.\r\n *\r\n * @returns {(Object|Array)} The deep copy of the provided object or array.\r\n */\r\nexport function deepCopy(objArr) {\r\n // If the `objArr` is null or not of the `object` type, return it\r\n if (objArr === null || typeof objArr !== 'object') {\r\n return objArr;\r\n }\r\n\r\n // Prepare either a new array or a new object\r\n const objArrCopy = Array.isArray(objArr) ? [] : {};\r\n\r\n // Recursively copy each property\r\n for (const key in objArr) {\r\n if (Object.prototype.hasOwnProperty.call(objArr, key)) {\r\n objArrCopy[key] = deepCopy(objArr[key]);\r\n }\r\n }\r\n\r\n // Return the copied object\r\n return objArrCopy;\r\n}\r\n\r\n/**\r\n * Implements an exponential backoff strategy for retrying a function until\r\n * a certain number of attempts are reached.\r\n *\r\n * @async\r\n * @function expBackoff\r\n *\r\n * @param {Function} fn - The function to be retried.\r\n * @param {number} [attempt=0] - The current attempt number. The default value\r\n * is `0`.\r\n * @param {...unknown} args - Arguments to be passed to the function.\r\n *\r\n * @returns {Promise} A Promise that resolves to the result\r\n * of the function if successful.\r\n *\r\n * @throws {Error} Throws an `Error` if the maximum number of attempts\r\n * is reached.\r\n */\r\nexport async function expBackoff(fn, attempt = 0, ...args) {\r\n try {\r\n // Try to call the function\r\n return await fn(...args);\r\n } catch (error) {\r\n // Calculate delay in ms\r\n const delayInMs = 2 ** attempt * 1000;\r\n\r\n // If the attempt exceeds the maximum attempts of repeat, throw an error\r\n if (++attempt >= MAX_BACKOFF_ATTEMPTS) {\r\n throw error;\r\n }\r\n\r\n // Wait given amount of time\r\n await new Promise((response) => setTimeout(response, delayInMs));\r\n\r\n /// TO DO: Correct\r\n // // Information about the resource timeout\r\n // log(\r\n // 3,\r\n // `[utils] Waited ${delayInMs}ms until next call for the resource of ID: ${args[0]}.`\r\n // );\r\n\r\n // Try again\r\n return expBackoff(fn, attempt, ...args);\r\n }\r\n}\r\n\r\n/**\r\n * Adjusts the constructor name by transforming and normalizing it based\r\n * on common chart types.\r\n *\r\n * @function fixConstr\r\n *\r\n * @param {string} constr - The original constructor name to be fixed.\r\n *\r\n * @returns {string} The corrected constructor name, or 'chart' if the input\r\n * is not recognized.\r\n */\r\nexport function fixConstr(constr) {\r\n try {\r\n // Fix the constructor by lowering casing\r\n const fixedConstr = `${constr.toLowerCase().replace('chart', '')}Chart`;\r\n\r\n // Handle the case where the result is just 'Chart'\r\n if (fixedConstr === 'Chart') {\r\n fixedConstr.toLowerCase();\r\n }\r\n\r\n // Return the corrected constructor, otherwise default to 'chart'\r\n return ['chart', 'stockChart', 'mapChart', 'ganttChart'].includes(\r\n fixedConstr\r\n )\r\n ? fixedConstr\r\n : 'chart';\r\n } catch {\r\n // Default to 'chart' in case of any error\r\n return 'chart';\r\n }\r\n}\r\n\r\n/**\r\n * Fixes the outfile based on provided type.\r\n *\r\n * @function fixOutfile\r\n *\r\n * @param {string} type - The original export type.\r\n * @param {string} outfile - The file path or name.\r\n *\r\n * @returns {string} The corrected outfile.\r\n */\r\nexport function fixOutfile(type, outfile) {\r\n // Get the file name from the `outfile` option\r\n const fileName = getAbsolutePath(outfile || 'chart')\r\n .split('.')\r\n .shift();\r\n\r\n // Return a correct outfile\r\n return `${fileName}.${type}`;\r\n}\r\n\r\n/**\r\n * Fixes the export type based on MIME types and file extensions.\r\n *\r\n * @function fixType\r\n *\r\n * @param {string} type - The original export type.\r\n * @param {string} [outfile=null] - The file path or name. The default value\r\n * is `null`.\r\n *\r\n * @returns {string} The corrected export type.\r\n */\r\nexport function fixType(type, outfile = null) {\r\n // MIME types\r\n const mimeTypes = {\r\n 'image/png': 'png',\r\n 'image/jpeg': 'jpeg',\r\n 'application/pdf': 'pdf',\r\n 'image/svg+xml': 'svg'\r\n };\r\n\r\n // Get formats\r\n const formats = Object.values(mimeTypes);\r\n\r\n // Check if type and outfile's extensions are the same\r\n if (outfile) {\r\n const outType = outfile.split('.').pop();\r\n\r\n // Support the JPG type\r\n if (outType === 'jpg') {\r\n type = 'jpeg';\r\n } else if (formats.includes(outType) && type !== outType) {\r\n type = outType;\r\n }\r\n }\r\n\r\n // Return a correct type\r\n return mimeTypes[type] || formats.find((t) => t === type) || 'png';\r\n}\r\n\r\n/**\r\n * Checks if the given path is relative or absolute and returns the corrected,\r\n * absolute path.\r\n *\r\n * @function isAbsolutePath\r\n *\r\n * @param {string} path - The path to be checked on.\r\n *\r\n * @returns {string} The absolute path.\r\n */\r\nexport function getAbsolutePath(path) {\r\n return isAbsolute(path) ? normalize(path) : resolve(path);\r\n}\r\n\r\n/**\r\n * Converts input data to a Base64 string based on the export type.\r\n *\r\n * @function getBase64\r\n *\r\n * @param {string} input - The input to be transformed to Base64 format.\r\n * @param {string} type - The original export type.\r\n *\r\n * @returns {string} The Base64 string representation of the input.\r\n */\r\nexport function getBase64(input, type) {\r\n // For pdf and svg types the input must be transformed to Base64 from a buffer\r\n if (type === 'pdf' || type == 'svg') {\r\n return Buffer.from(input, 'utf8').toString('base64');\r\n }\r\n\r\n // For png and jpeg input is already a Base64 string\r\n return input;\r\n}\r\n\r\n/**\r\n * Returns stringified date without the GMT text information.\r\n *\r\n * @function getNewDate\r\n */\r\nexport function getNewDate() {\r\n // Get rid of the GMT text information\r\n return new Date().toString().split('(')[0].trim();\r\n}\r\n\r\n/**\r\n * Returns the stored time value in milliseconds.\r\n *\r\n * @function getNewDateTime\r\n */\r\nexport function getNewDateTime() {\r\n return new Date().getTime();\r\n}\r\n\r\n/**\r\n * Checks if the given item is an object.\r\n *\r\n * @function isObject\r\n *\r\n * @param {unknown} item - The item to be checked.\r\n *\r\n * @returns {boolean} True if the item is an object, false otherwise.\r\n */\r\nexport function isObject(item) {\r\n return Object.prototype.toString.call(item) === '[object Object]';\r\n}\r\n\r\n/**\r\n * Checks if the given object is empty.\r\n *\r\n * @function isObjectEmpty\r\n *\r\n * @param {Object} item - The object to be checked.\r\n *\r\n * @returns {boolean} True if the object is empty, false otherwise.\r\n */\r\nexport function isObjectEmpty(item) {\r\n return (\r\n typeof item === 'object' &&\r\n !Array.isArray(item) &&\r\n item !== null &&\r\n Object.keys(item).length === 0\r\n );\r\n}\r\n\r\n/**\r\n * Checks if a private IP range URL is found in the given string.\r\n *\r\n * @function isPrivateRangeUrlFound\r\n *\r\n * @param {string} item - The string to be checked for a private IP range URL.\r\n *\r\n * @returns {boolean} True if a private IP range URL is found, false otherwise.\r\n */\r\nexport function isPrivateRangeUrlFound(item) {\r\n const regexPatterns = [\r\n /xlink:href=\"(?:http:\\/\\/|https:\\/\\/)?localhost\\b/,\r\n /xlink:href=\"(?:http:\\/\\/|https:\\/\\/)?10\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\b/,\r\n /xlink:href=\"(?:http:\\/\\/|https:\\/\\/)?127\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\b/,\r\n /xlink:href=\"(?:http:\\/\\/|https:\\/\\/)?172\\.(1[6-9]|2[0-9]|3[0-1])\\.\\d{1,3}\\.\\d{1,3}\\b/,\r\n /xlink:href=\"(?:http:\\/\\/|https:\\/\\/)?192\\.168\\.\\d{1,3}\\.\\d{1,3}\\b/\r\n ];\r\n\r\n return regexPatterns.some((pattern) => pattern.test(item));\r\n}\r\n\r\n/**\r\n * Utility to measure elapsed time using the Node.js `process.hrtime()` method.\r\n *\r\n * @function measureTime\r\n *\r\n * @returns {Function} A function to calculate the elapsed time in milliseconds.\r\n */\r\nexport function measureTime() {\r\n const start = process.hrtime.bigint();\r\n return () => Number(process.hrtime.bigint() - start) / 1000000;\r\n}\r\n\r\n/**\r\n * Rounds a number to the specified precision.\r\n *\r\n * @function roundNumber\r\n *\r\n * @param {number} value - The number to be rounded.\r\n * @param {number} precision - The number of decimal places to round to.\r\n *\r\n * @returns {number} The rounded number.\r\n */\r\nexport function roundNumber(value, precision = 1) {\r\n const multiplier = Math.pow(10, precision || 0);\r\n return Math.round(+value * multiplier) / multiplier;\r\n}\r\n\r\n/**\r\n * Converts a value to a boolean.\r\n *\r\n * @function toBoolean\r\n *\r\n * @param {unknown} item - The value to be converted to a boolean.\r\n *\r\n * @returns {boolean} The boolean representation of the input value.\r\n */\r\nexport function toBoolean(item) {\r\n return ['false', 'undefined', 'null', 'NaN', '0', ''].includes(item)\r\n ? false\r\n : !!item;\r\n}\r\n\r\n/**\r\n * Wraps custom code to execute it safely.\r\n *\r\n * @function wrapAround\r\n *\r\n * @param {string} customCode - The custom code to be wrapped.\r\n * @param {boolean} allowFileResources - Flag to allow loading code from a file.\r\n * @param {boolean} [isCallback=false] - Flag that indicates the returned code\r\n * must be in a callback format.\r\n *\r\n * @returns {(string|null)} The wrapped custom code or null if wrapping fails.\r\n */\r\nexport function wrapAround(customCode, allowFileResources, isCallback = false) {\r\n if (customCode && typeof customCode === 'string') {\r\n customCode = customCode.trim();\r\n\r\n if (customCode.endsWith('.js')) {\r\n // Load a file if the file resources are allowed\r\n return allowFileResources\r\n ? wrapAround(\r\n readFileSync(getAbsolutePath(customCode), 'utf8'),\r\n allowFileResources,\r\n isCallback\r\n )\r\n : null;\r\n } else if (\r\n !isCallback &&\r\n (customCode.startsWith('function()') ||\r\n customCode.startsWith('function ()') ||\r\n customCode.startsWith('()=>') ||\r\n customCode.startsWith('() =>'))\r\n ) {\r\n // Treat a function as a self-invoking expression\r\n return `(${customCode})()`;\r\n }\r\n\r\n // Or return as a stringified code\r\n return customCode.replace(/;$/, '');\r\n }\r\n}\r\n\r\nexport default {\r\n __dirname,\r\n clearText,\r\n deepCopy,\r\n expBackoff,\r\n fixConstr,\r\n fixOutfile,\r\n fixType,\r\n getAbsolutePath,\r\n getBase64,\r\n getNewDate,\r\n getNewDateTime,\r\n isObject,\r\n isObjectEmpty,\r\n isPrivateRangeUrlFound,\r\n measureTime,\r\n roundNumber,\r\n toBoolean,\r\n wrapAround\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * @overview A module for managing logging functionality with customizable\r\n * log levels, console and file logging options, and error handling support.\r\n * The module also ensures that file-based logs are stored in a structured\r\n * directory, creating the necessary paths automatically if they do not exist.\r\n */\r\n\r\nimport { appendFile, existsSync, mkdirSync } from 'fs';\r\nimport { join } from 'path';\r\n\r\nimport { getAbsolutePath, getNewDate } from './utils.js';\r\n\r\n// The available colors\r\nconst colors = ['red', 'yellow', 'blue', 'gray', 'green'];\r\n\r\n// The default logging config\r\nconst logging = {\r\n // Flags for logging status\r\n toConsole: true,\r\n toFile: false,\r\n pathCreated: false,\r\n // Full path to the log file\r\n pathToLog: '',\r\n // Log levels\r\n levelsDesc: [\r\n {\r\n title: 'error',\r\n color: colors[0]\r\n },\r\n {\r\n title: 'warning',\r\n color: colors[1]\r\n },\r\n {\r\n title: 'notice',\r\n color: colors[2]\r\n },\r\n {\r\n title: 'verbose',\r\n color: colors[3]\r\n },\r\n {\r\n title: 'benchmark',\r\n color: colors[4]\r\n }\r\n ]\r\n};\r\n\r\n/**\r\n * Logs a message with a specified log level. Accepts a variable number\r\n * of arguments. The arguments after the `level` are passed to `console.log`\r\n * and/or used to construct and append messages to a log file.\r\n *\r\n * @function log\r\n *\r\n * @param {...unknown} args - An array of arguments where the first is the log\r\n * level and the remaining are strings used to build the log message.\r\n *\r\n * @returns {void} Exits the function execution if attempting to log at a level\r\n * higher than allowed.\r\n */\r\nexport function log(...args) {\r\n const [newLevel, ...texts] = args;\r\n\r\n // Current logging options\r\n const { levelsDesc, level } = logging;\r\n\r\n // Check if the log level is within a correct range or is it a benchmark log\r\n if (\r\n newLevel !== 5 &&\r\n (newLevel === 0 || newLevel > level || level > levelsDesc.length)\r\n ) {\r\n return;\r\n }\r\n\r\n // Create a message's prefix\r\n const prefix = `${getNewDate()} [${levelsDesc[newLevel - 1].title}] -`;\r\n\r\n // Log to file\r\n if (logging.toFile) {\r\n _logToFile(texts, prefix);\r\n }\r\n\r\n // Log to console\r\n if (logging.toConsole) {\r\n console.log.apply(\r\n undefined,\r\n [prefix.toString()[logging.levelsDesc[newLevel - 1].color]].concat(texts)\r\n );\r\n }\r\n}\r\n\r\n/**\r\n * Logs an error message along with its stack trace. Optionally, a custom message\r\n * can be provided.\r\n *\r\n * @function logWithStack\r\n *\r\n * @param {number} newLevel - The log level.\r\n * @param {Error} error - The error object containing the stack trace.\r\n * @param {string} customMessage - An optional custom message to be included\r\n * in the log alongside the error.\r\n *\r\n * @returns {void} Exits the function execution if attempting to log at a level\r\n * higher than allowed.\r\n */\r\nexport function logWithStack(newLevel, error, customMessage) {\r\n // Get the main message\r\n const mainMessage = customMessage || (error && error.message) || '';\r\n\r\n // Current logging options\r\n const { level, levelsDesc } = logging;\r\n\r\n // Check if the log level is within a correct range\r\n if (newLevel === 0 || newLevel > level || level > levelsDesc.length) {\r\n return;\r\n }\r\n\r\n // Create a message's prefix\r\n const prefix = `${getNewDate()} [${levelsDesc[newLevel - 1].title}] -`;\r\n\r\n // Add the whole stack message\r\n const stackMessage = error && error.stack;\r\n\r\n // Combine custom message or error message with error stack message, if exists\r\n const texts = [mainMessage];\r\n if (stackMessage) {\r\n texts.push('\\n', stackMessage);\r\n }\r\n\r\n // Log to file\r\n if (logging.toFile) {\r\n _logToFile(texts, prefix);\r\n }\r\n\r\n // Log to console\r\n if (logging.toConsole) {\r\n console.log.apply(\r\n undefined,\r\n [prefix.toString()[logging.levelsDesc[newLevel - 1].color]].concat([\r\n texts.shift()[colors[newLevel - 1]],\r\n ...texts\r\n ])\r\n );\r\n }\r\n}\r\n\r\n/**\r\n * Logs an error message related to Zod validation issues. Optionally, a custom\r\n * message can be provided.\r\n *\r\n * @function logZodIssues\r\n *\r\n * @param {number} newLevel - The log level.\r\n * @param {Error[]} issues - An array of Zod validation issues.\r\n * @param {string} customMessage - An optional custom message to be included\r\n * in the log alongside the error.\r\n */\r\nexport function logZodIssues(newLevel, issues, customMessage) {\r\n logWithStack(\r\n newLevel,\r\n null,\r\n [\r\n `${customMessage || '[validation] Validation error'} - the following Zod issues occured:`,\r\n ...(issues || []).map((issue) => `- ${issue.message}`)\r\n ].join('\\n')\r\n );\r\n}\r\n\r\n/**\r\n * Initializes logging with the specified logging configuration.\r\n *\r\n * @function initLogging\r\n *\r\n * @param {Object} loggingOptions - The configuration object containing\r\n * `logging` options.\r\n */\r\nexport function initLogging(loggingOptions) {\r\n // Get options from the `loggingOptions` object\r\n const { level, dest, file, toConsole, toFile } = loggingOptions;\r\n\r\n // Reset flags to the default values\r\n logging.pathCreated = false;\r\n logging.pathToLog = '';\r\n\r\n // Set the logging level\r\n setLogLevel(level);\r\n\r\n // Set the console logging\r\n enableConsoleLogging(toConsole);\r\n\r\n // Set the file logging\r\n enableFileLogging(dest, file, toFile);\r\n}\r\n\r\n/**\r\n * Sets the log level to the specified value. Log levels are (`0` = no logging,\r\n * `1` = error, `2` = warning, `3` = notice, `4` = verbose, or `5` = benchmark).\r\n *\r\n * @function setLogLevel\r\n *\r\n * @param {number} level - The log level to be set.\r\n */\r\nexport function setLogLevel(level) {\r\n if (\r\n Number.isInteger(level) &&\r\n level >= 0 &&\r\n level <= logging.levelsDesc.length\r\n ) {\r\n // Update the module logging's `level` option\r\n logging.level = level;\r\n }\r\n}\r\n\r\n/**\r\n * Enables console logging.\r\n *\r\n * @function enableConsoleLogging\r\n *\r\n * @param {boolean} toConsole - The flag for setting the logging to the console.\r\n */\r\nexport function enableConsoleLogging(toConsole) {\r\n // Update the module logging's `toConsole` option\r\n logging.toConsole = !!toConsole;\r\n}\r\n\r\n/**\r\n * Enables file logging with the specified destination and log file name.\r\n *\r\n * @function enableFileLogging\r\n *\r\n * @param {string} dest - The destination path where the log file should\r\n * be saved.\r\n * @param {string} file - The name of the log file.\r\n * @param {boolean} toFile - A flag indicating whether logging should\r\n * be directed to a file.\r\n */\r\nexport function enableFileLogging(dest, file, toFile) {\r\n // Update the module logging's `toFile` option\r\n logging.toFile = !!toFile;\r\n\r\n // Set the `dest` and `file` options only if the file logging is enabled\r\n if (logging.toFile) {\r\n logging.dest = dest || '';\r\n logging.file = file || '';\r\n }\r\n}\r\n\r\n/**\r\n * Logs the provided texts to a file, if file logging is enabled. It creates\r\n * the necessary directory structure if not already created and appends\r\n * the content, including an optional prefix, to the specified log file.\r\n *\r\n * @function _logToFile\r\n *\r\n * @param {Array.} texts - An array of texts to be logged.\r\n * @param {string} prefix - An optional prefix to be added to each log entry.\r\n */\r\nfunction _logToFile(texts, prefix) {\r\n if (!logging.pathCreated) {\r\n // Create if does not exist\r\n !existsSync(getAbsolutePath(logging.dest)) &&\r\n mkdirSync(getAbsolutePath(logging.dest));\r\n\r\n // Create the full path\r\n logging.pathToLog = getAbsolutePath(join(logging.dest, logging.file));\r\n\r\n // We now assume the path is available, e.g. it's the responsibility\r\n // of the user to create the path with the correct access rights.\r\n logging.pathCreated = true;\r\n }\r\n\r\n // Add the content to a file\r\n appendFile(\r\n logging.pathToLog,\r\n [prefix].concat(texts).join(' ') + '\\n',\r\n (error) => {\r\n if (error && logging.toFile && logging.pathCreated) {\r\n logging.toFile = false;\r\n logging.pathCreated = false;\r\n logWithStack(2, error, `[logger] Unable to write to log file.`);\r\n }\r\n }\r\n );\r\n}\r\n\r\nexport default {\r\n log,\r\n logWithStack,\r\n logZodIssues,\r\n initLogging,\r\n setLogLevel,\r\n enableConsoleLogging,\r\n enableFileLogging\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * @overview Configuration management module for the Highcharts Export Server.\r\n * Provides default configurations that support environment variables, CLI\r\n * arguments, and interactive prompts for customization of options and features.\r\n * Additionally, it maps legacy options to modern structures, generates nested\r\n * argument mappings, and displays CLI usage information.\r\n */\r\n\r\n/**\r\n * The configuration object containing all available options, organized\r\n * by sections.\r\n *\r\n * This object includes:\r\n * - Default values for each option\r\n * - Data types for validation\r\n * - Names of corresponding environment variables\r\n * - Descriptions of each property\r\n * - Information used for prompts in interactive configuration\r\n * - [Optional] Corresponding CLI argument names for CLI usage\r\n * - [Optional] Legacy names from the previous PhantomJS-based server\r\n */\r\nexport const defaultConfig = {\r\n puppeteer: {\r\n args: {\r\n value: [\r\n '--allow-running-insecure-content',\r\n '--ash-no-nudges',\r\n '--autoplay-policy=user-gesture-required',\r\n '--block-new-web-contents',\r\n '--disable-accelerated-2d-canvas',\r\n '--disable-background-networking',\r\n '--disable-background-timer-throttling',\r\n '--disable-backgrounding-occluded-windows',\r\n '--disable-breakpad',\r\n '--disable-checker-imaging',\r\n '--disable-client-side-phishing-detection',\r\n '--disable-component-extensions-with-background-pages',\r\n '--disable-component-update',\r\n '--disable-default-apps',\r\n '--disable-dev-shm-usage',\r\n '--disable-domain-reliability',\r\n '--disable-extensions',\r\n '--disable-features=CalculateNativeWinOcclusion,InterestFeedContentSuggestions,WebOTP',\r\n '--disable-hang-monitor',\r\n '--disable-ipc-flooding-protection',\r\n '--disable-logging',\r\n '--disable-notifications',\r\n '--disable-offer-store-unmasked-wallet-cards',\r\n '--disable-popup-blocking',\r\n '--disable-print-preview',\r\n '--disable-prompt-on-repost',\r\n '--disable-renderer-backgrounding',\r\n '--disable-search-engine-choice-screen',\r\n '--disable-session-crashed-bubble',\r\n '--disable-setuid-sandbox',\r\n '--disable-site-isolation-trials',\r\n '--disable-speech-api',\r\n '--disable-sync',\r\n '--enable-unsafe-webgpu',\r\n '--hide-crash-restore-bubble',\r\n '--hide-scrollbars',\r\n '--metrics-recording-only',\r\n '--mute-audio',\r\n '--no-default-browser-check',\r\n '--no-first-run',\r\n '--no-pings',\r\n '--no-sandbox',\r\n '--no-startup-window',\r\n '--no-zygote',\r\n '--password-store=basic',\r\n '--process-per-tab',\r\n '--use-mock-keychain'\r\n ],\r\n types: ['string[]'],\r\n envLink: 'PUPPETEER_ARGS',\r\n cliName: 'puppeteerArgs',\r\n description: 'Array of Puppeteer arguments',\r\n promptOptions: {\r\n type: 'list',\r\n separator: ';'\r\n }\r\n }\r\n },\r\n highcharts: {\r\n version: {\r\n value: 'latest',\r\n types: ['string'],\r\n envLink: 'HIGHCHARTS_VERSION',\r\n description: 'Highcharts version',\r\n promptOptions: {\r\n type: 'text'\r\n }\r\n },\r\n cdnUrl: {\r\n value: 'https://code.highcharts.com',\r\n types: ['string'],\r\n envLink: 'HIGHCHARTS_CDN_URL',\r\n description: 'CDN URL for Highcharts scripts',\r\n promptOptions: {\r\n type: 'text'\r\n }\r\n },\r\n forceFetch: {\r\n value: false,\r\n types: ['boolean'],\r\n envLink: 'HIGHCHARTS_FORCE_FETCH',\r\n description: 'Flag to refetch scripts after each server rerun',\r\n promptOptions: {\r\n type: 'toggle'\r\n }\r\n },\r\n cachePath: {\r\n value: '.cache',\r\n types: ['string'],\r\n envLink: 'HIGHCHARTS_CACHE_PATH',\r\n description: 'Directory path for cached Highcharts scripts',\r\n promptOptions: {\r\n type: 'text'\r\n }\r\n },\r\n coreScripts: {\r\n value: ['highcharts', 'highcharts-more', 'highcharts-3d'],\r\n types: ['string[]'],\r\n envLink: 'HIGHCHARTS_CORE_SCRIPTS',\r\n description: 'Highcharts core scripts to fetch',\r\n promptOptions: {\r\n type: 'multiselect',\r\n instructions: 'Space: Select specific, A: Select all, Enter: Confirm'\r\n }\r\n },\r\n moduleScripts: {\r\n value: [\r\n 'stock',\r\n 'map',\r\n 'gantt',\r\n 'exporting',\r\n 'parallel-coordinates',\r\n 'accessibility',\r\n // 'annotations-advanced',\r\n 'boost-canvas',\r\n 'boost',\r\n 'data',\r\n 'data-tools',\r\n 'draggable-points',\r\n 'static-scale',\r\n 'broken-axis',\r\n 'heatmap',\r\n 'tilemap',\r\n 'tiledwebmap',\r\n 'timeline',\r\n 'treemap',\r\n 'treegraph',\r\n 'item-series',\r\n 'drilldown',\r\n 'histogram-bellcurve',\r\n 'bullet',\r\n 'funnel',\r\n 'funnel3d',\r\n 'geoheatmap',\r\n 'pyramid3d',\r\n 'networkgraph',\r\n 'overlapping-datalabels',\r\n 'pareto',\r\n 'pattern-fill',\r\n 'pictorial',\r\n 'price-indicator',\r\n 'sankey',\r\n 'arc-diagram',\r\n 'dependency-wheel',\r\n 'series-label',\r\n 'series-on-point',\r\n 'solid-gauge',\r\n 'sonification',\r\n // 'stock-tools',\r\n 'streamgraph',\r\n 'sunburst',\r\n 'variable-pie',\r\n 'variwide',\r\n 'vector',\r\n 'venn',\r\n 'windbarb',\r\n 'wordcloud',\r\n 'xrange',\r\n 'no-data-to-display',\r\n 'drag-panes',\r\n 'debugger',\r\n 'dumbbell',\r\n 'lollipop',\r\n 'cylinder',\r\n 'organization',\r\n 'dotplot',\r\n 'marker-clusters',\r\n 'hollowcandlestick',\r\n 'heikinashi',\r\n 'flowmap',\r\n 'export-data',\r\n 'navigator',\r\n 'textpath'\r\n ],\r\n types: ['string[]'],\r\n envLink: 'HIGHCHARTS_MODULE_SCRIPTS',\r\n description: 'Highcharts module scripts to fetch',\r\n promptOptions: {\r\n type: 'multiselect',\r\n instructions: 'Space: Select specific, A: Select all, Enter: Confirm'\r\n }\r\n },\r\n indicatorScripts: {\r\n value: ['indicators-all'],\r\n types: ['string[]'],\r\n envLink: 'HIGHCHARTS_INDICATOR_SCRIPTS',\r\n description: 'Highcharts indicator scripts to fetch',\r\n promptOptions: {\r\n type: 'multiselect',\r\n instructions: 'Space: Select specific, A: Select all, Enter: Confirm'\r\n }\r\n },\r\n customScripts: {\r\n value: [\r\n 'https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.30.1/moment.min.js',\r\n 'https://cdnjs.cloudflare.com/ajax/libs/moment-timezone/0.5.45/moment-timezone-with-data.min.js'\r\n ],\r\n types: ['string[]'],\r\n envLink: 'HIGHCHARTS_CUSTOM_SCRIPTS',\r\n description: 'Additional custom scripts or dependencies to fetch',\r\n promptOptions: {\r\n type: 'list',\r\n separator: ';'\r\n }\r\n }\r\n },\r\n export: {\r\n infile: {\r\n value: null,\r\n types: ['string', 'null'],\r\n envLink: 'EXPORT_INFILE',\r\n description:\r\n 'Input filename with type, formatted correctly as JSON or SVG',\r\n promptOptions: {\r\n type: 'text'\r\n }\r\n },\r\n instr: {\r\n value: null,\r\n types: ['Object', 'string', 'null'],\r\n envLink: 'EXPORT_INSTR',\r\n description:\r\n 'Overrides the `infile` with JSON, stringified JSON, or SVG input',\r\n promptOptions: {\r\n type: 'text'\r\n }\r\n },\r\n options: {\r\n value: null,\r\n types: ['Object', 'string', 'null'],\r\n envLink: 'EXPORT_OPTIONS',\r\n description: 'Alias for the `instr` option',\r\n promptOptions: {\r\n type: 'text'\r\n }\r\n },\r\n svg: {\r\n value: null,\r\n types: ['string', 'null'],\r\n envLink: 'EXPORT_SVG',\r\n description: 'SVG string representation of the chart to render',\r\n promptOptions: {\r\n type: 'text'\r\n }\r\n },\r\n batch: {\r\n value: null,\r\n types: ['string', 'null'],\r\n envLink: 'EXPORT_BATCH',\r\n description:\r\n 'Batch job string with input/output pairs: \"in=out;in=out;...\"',\r\n promptOptions: {\r\n type: 'text'\r\n }\r\n },\r\n outfile: {\r\n value: null,\r\n types: ['string', 'null'],\r\n envLink: 'EXPORT_OUTFILE',\r\n description:\r\n 'Output filename with type. Can be jpeg, png, pdf, or svg and ignores `type` option',\r\n promptOptions: {\r\n type: 'text'\r\n }\r\n },\r\n type: {\r\n value: 'png',\r\n types: ['string'],\r\n envLink: 'EXPORT_TYPE',\r\n description: 'File export format. Can be jpeg, png, pdf, or svg',\r\n promptOptions: {\r\n type: 'select',\r\n hint: 'Default: png',\r\n choices: ['png', 'jpeg', 'pdf', 'svg']\r\n }\r\n },\r\n constr: {\r\n value: 'chart',\r\n types: ['string'],\r\n envLink: 'EXPORT_CONSTR',\r\n description:\r\n 'Chart constructor. Can be chart, stockChart, mapChart, or ganttChart',\r\n promptOptions: {\r\n type: 'select',\r\n hint: 'Default: chart',\r\n choices: ['chart', 'stockChart', 'mapChart', 'ganttChart']\r\n }\r\n },\r\n b64: {\r\n value: false,\r\n types: ['boolean'],\r\n envLink: 'EXPORT_B64',\r\n description:\r\n 'Whether or not to the chart should be received in Base64 format instead of binary',\r\n promptOptions: {\r\n type: 'toggle'\r\n }\r\n },\r\n noDownload: {\r\n value: false,\r\n types: ['boolean'],\r\n envLink: 'EXPORT_NO_DOWNLOAD',\r\n description:\r\n 'Whether or not to include or exclude attachment headers in the response',\r\n promptOptions: {\r\n type: 'toggle'\r\n }\r\n },\r\n height: {\r\n value: null,\r\n types: ['number', 'null'],\r\n envLink: 'EXPORT_HEIGHT',\r\n description: 'Height of the exported chart, overrides chart settings',\r\n promptOptions: {\r\n type: 'number'\r\n }\r\n },\r\n width: {\r\n value: null,\r\n types: ['number', 'null'],\r\n envLink: 'EXPORT_WIDTH',\r\n description: 'Width of the exported chart, overrides chart settings',\r\n promptOptions: {\r\n type: 'number'\r\n }\r\n },\r\n scale: {\r\n value: null,\r\n types: ['number', 'null'],\r\n envLink: 'EXPORT_SCALE',\r\n description:\r\n 'Scale of the exported chart, overrides chart settings. Ranges from 0.1 to 5.0',\r\n promptOptions: {\r\n type: 'number'\r\n }\r\n },\r\n defaultHeight: {\r\n value: 400,\r\n types: ['number'],\r\n envLink: 'EXPORT_DEFAULT_HEIGHT',\r\n description: 'Default height of the exported chart if not set',\r\n promptOptions: {\r\n type: 'number'\r\n }\r\n },\r\n defaultWidth: {\r\n value: 600,\r\n types: ['number'],\r\n envLink: 'EXPORT_DEFAULT_WIDTH',\r\n description: 'Default width of the exported chart if not set',\r\n promptOptions: {\r\n type: 'number'\r\n }\r\n },\r\n defaultScale: {\r\n value: 1,\r\n types: ['number'],\r\n envLink: 'EXPORT_DEFAULT_SCALE',\r\n description:\r\n 'Default scale of the exported chart if not set. Ranges from 0.1 to 5.0',\r\n promptOptions: {\r\n type: 'number',\r\n min: 0.1,\r\n max: 5\r\n }\r\n },\r\n globalOptions: {\r\n value: null,\r\n types: ['Object', 'string', 'null'],\r\n envLink: 'EXPORT_GLOBAL_OPTIONS',\r\n description:\r\n 'JSON, stringified JSON or filename with global options for Highcharts.setOptions',\r\n promptOptions: {\r\n type: 'text'\r\n }\r\n },\r\n themeOptions: {\r\n value: null,\r\n types: ['Object', 'string', 'null'],\r\n envLink: 'EXPORT_THEME_OPTIONS',\r\n description:\r\n 'JSON, stringified JSON or filename with theme options for Highcharts.setOptions',\r\n promptOptions: {\r\n type: 'text'\r\n }\r\n },\r\n rasterizationTimeout: {\r\n value: 1500,\r\n types: ['number'],\r\n envLink: 'EXPORT_RASTERIZATION_TIMEOUT',\r\n description: 'Milliseconds to wait for webpage rendering',\r\n promptOptions: {\r\n type: 'number'\r\n }\r\n }\r\n },\r\n customLogic: {\r\n allowCodeExecution: {\r\n value: false,\r\n types: ['boolean'],\r\n envLink: 'CUSTOM_LOGIC_ALLOW_CODE_EXECUTION',\r\n description:\r\n 'Allows or disallows execution of arbitrary code during exporting',\r\n promptOptions: {\r\n type: 'toggle'\r\n }\r\n },\r\n allowFileResources: {\r\n value: false,\r\n types: ['boolean'],\r\n envLink: 'CUSTOM_LOGIC_ALLOW_FILE_RESOURCES',\r\n description:\r\n 'Allows or disallows injection of filesystem resources (disabled in server mode)',\r\n promptOptions: {\r\n type: 'toggle'\r\n }\r\n },\r\n customCode: {\r\n value: null,\r\n types: ['string', 'null'],\r\n envLink: 'CUSTOM_LOGIC_CUSTOM_CODE',\r\n description:\r\n 'Custom code to execute before chart initialization. Can be a function, code wrapped in a function, or a .js filename',\r\n promptOptions: {\r\n type: 'text'\r\n }\r\n },\r\n callback: {\r\n value: null,\r\n types: ['string', 'null'],\r\n envLink: 'CUSTOM_LOGIC_CALLBACK',\r\n description:\r\n 'JavaScript code to run during construction. Can be a function or a .js filename',\r\n promptOptions: {\r\n type: 'text'\r\n }\r\n },\r\n resources: {\r\n value: null,\r\n types: ['Object', 'string', 'null'],\r\n envLink: 'CUSTOM_LOGIC_RESOURCES',\r\n description:\r\n 'Additional resources as JSON, stringified JSON, or filename, containing files, js, and css sections',\r\n promptOptions: {\r\n type: 'text'\r\n }\r\n },\r\n loadConfig: {\r\n value: null,\r\n types: ['string', 'null'],\r\n envLink: 'CUSTOM_LOGIC_LOAD_CONFIG',\r\n legacyName: 'fromFile',\r\n description: 'File with a pre-defined configuration to use',\r\n promptOptions: {\r\n type: 'text'\r\n }\r\n },\r\n createConfig: {\r\n value: null,\r\n types: ['string', 'null'],\r\n envLink: 'CUSTOM_LOGIC_CREATE_CONFIG',\r\n description:\r\n 'Prompt-based option setting, saved to a provided config file',\r\n promptOptions: {\r\n type: 'text'\r\n }\r\n }\r\n },\r\n server: {\r\n enable: {\r\n value: false,\r\n types: ['boolean'],\r\n envLink: 'SERVER_ENABLE',\r\n cliName: 'enableServer',\r\n description: 'Starts the server when true',\r\n promptOptions: {\r\n type: 'toggle'\r\n }\r\n },\r\n host: {\r\n value: '0.0.0.0',\r\n types: ['string'],\r\n envLink: 'SERVER_HOST',\r\n description: 'Hostname of the server',\r\n promptOptions: {\r\n type: 'text'\r\n }\r\n },\r\n port: {\r\n value: 7801,\r\n types: ['number'],\r\n envLink: 'SERVER_PORT',\r\n description: 'Port number for the server',\r\n promptOptions: {\r\n type: 'number'\r\n }\r\n },\r\n uploadLimit: {\r\n value: 3,\r\n types: ['number'],\r\n envLink: 'SERVER_UPLOAD_LIMIT',\r\n description: 'Maximum request body size in MB',\r\n promptOptions: {\r\n type: 'number'\r\n }\r\n },\r\n benchmarking: {\r\n value: false,\r\n types: ['boolean'],\r\n envLink: 'SERVER_BENCHMARKING',\r\n cliName: 'serverBenchmarking',\r\n description:\r\n 'Displays or not action durations in milliseconds during server requests',\r\n promptOptions: {\r\n type: 'toggle'\r\n }\r\n },\r\n proxy: {\r\n host: {\r\n value: null,\r\n types: ['string', 'null'],\r\n envLink: 'SERVER_PROXY_HOST',\r\n cliName: 'proxyHost',\r\n description: 'Host of the proxy server, if applicable',\r\n promptOptions: {\r\n type: 'text'\r\n }\r\n },\r\n port: {\r\n value: null,\r\n types: ['number', 'null'],\r\n envLink: 'SERVER_PROXY_PORT',\r\n cliName: 'proxyPort',\r\n description: 'Port of the proxy server, if applicable',\r\n promptOptions: {\r\n type: 'number'\r\n }\r\n },\r\n timeout: {\r\n value: 5000,\r\n types: ['number'],\r\n envLink: 'SERVER_PROXY_TIMEOUT',\r\n cliName: 'proxyTimeout',\r\n description:\r\n 'Timeout in milliseconds for the proxy server, if applicable',\r\n promptOptions: {\r\n type: 'number'\r\n }\r\n }\r\n },\r\n rateLimiting: {\r\n enable: {\r\n value: false,\r\n types: ['boolean'],\r\n envLink: 'SERVER_RATE_LIMITING_ENABLE',\r\n cliName: 'enableRateLimiting',\r\n description: 'Enables or disables rate limiting on the server',\r\n promptOptions: {\r\n type: 'toggle'\r\n }\r\n },\r\n maxRequests: {\r\n value: 10,\r\n types: ['number'],\r\n envLink: 'SERVER_RATE_LIMITING_MAX_REQUESTS',\r\n legacyName: 'rateLimit',\r\n description: 'Maximum number of requests allowed per minute',\r\n promptOptions: {\r\n type: 'number'\r\n }\r\n },\r\n window: {\r\n value: 1,\r\n types: ['number'],\r\n envLink: 'SERVER_RATE_LIMITING_WINDOW',\r\n description: 'Time window in minutes for rate limiting',\r\n promptOptions: {\r\n type: 'number'\r\n }\r\n },\r\n delay: {\r\n value: 0,\r\n types: ['number'],\r\n envLink: 'SERVER_RATE_LIMITING_DELAY',\r\n description:\r\n 'Delay duration between successive requests before reaching the limit',\r\n promptOptions: {\r\n type: 'number'\r\n }\r\n },\r\n trustProxy: {\r\n value: false,\r\n types: ['boolean'],\r\n envLink: 'SERVER_RATE_LIMITING_TRUST_PROXY',\r\n description: 'Set to true if the server is behind a load balancer',\r\n promptOptions: {\r\n type: 'toggle'\r\n }\r\n },\r\n skipKey: {\r\n value: null,\r\n types: ['string', 'null'],\r\n envLink: 'SERVER_RATE_LIMITING_SKIP_KEY',\r\n description: 'Key to bypass the rate limiter, used with `skipToken`',\r\n promptOptions: {\r\n type: 'text'\r\n }\r\n },\r\n skipToken: {\r\n value: null,\r\n types: ['string', 'null'],\r\n envLink: 'SERVER_RATE_LIMITING_SKIP_TOKEN',\r\n description: 'Token to bypass the rate limiter, used with `skipKey`',\r\n promptOptions: {\r\n type: 'text'\r\n }\r\n }\r\n },\r\n ssl: {\r\n enable: {\r\n value: false,\r\n types: ['boolean'],\r\n envLink: 'SERVER_SSL_ENABLE',\r\n cliName: 'enableSsl',\r\n description: 'Enables or disables SSL protocol',\r\n promptOptions: {\r\n type: 'toggle'\r\n }\r\n },\r\n force: {\r\n value: false,\r\n types: ['boolean'],\r\n envLink: 'SERVER_SSL_FORCE',\r\n cliName: 'sslForce',\r\n legacyName: 'sslOnly',\r\n description: 'Forces the server to use HTTPS only when true',\r\n promptOptions: {\r\n type: 'toggle'\r\n }\r\n },\r\n port: {\r\n value: 443,\r\n types: ['number'],\r\n envLink: 'SERVER_SSL_PORT',\r\n cliName: 'sslPort',\r\n description: 'Port for the SSL server',\r\n promptOptions: {\r\n type: 'number'\r\n }\r\n },\r\n certPath: {\r\n value: null,\r\n types: ['string', 'null'],\r\n envLink: 'SERVER_SSL_CERT_PATH',\r\n cliName: 'sslCertPath',\r\n legacyName: 'sslPath',\r\n description: 'Path to the SSL certificate/key file',\r\n promptOptions: {\r\n type: 'text'\r\n }\r\n }\r\n }\r\n },\r\n pool: {\r\n minWorkers: {\r\n value: 4,\r\n types: ['number'],\r\n envLink: 'POOL_MIN_WORKERS',\r\n description: 'Minimum and initial number of pool workers to spawn',\r\n promptOptions: {\r\n type: 'number'\r\n }\r\n },\r\n maxWorkers: {\r\n value: 8,\r\n types: ['number'],\r\n envLink: 'POOL_MAX_WORKERS',\r\n legacyName: 'workers',\r\n description: 'Maximum number of pool workers to spawn',\r\n promptOptions: {\r\n type: 'number'\r\n }\r\n },\r\n workLimit: {\r\n value: 40,\r\n types: ['number'],\r\n envLink: 'POOL_WORK_LIMIT',\r\n description: 'Number of tasks a worker can handle before restarting',\r\n promptOptions: {\r\n type: 'number'\r\n }\r\n },\r\n acquireTimeout: {\r\n value: 5000,\r\n types: ['number'],\r\n envLink: 'POOL_ACQUIRE_TIMEOUT',\r\n description: 'Timeout in milliseconds for acquiring a resource',\r\n promptOptions: {\r\n type: 'number'\r\n }\r\n },\r\n createTimeout: {\r\n value: 5000,\r\n types: ['number'],\r\n envLink: 'POOL_CREATE_TIMEOUT',\r\n description: 'Timeout in milliseconds for creating a resource',\r\n promptOptions: {\r\n type: 'number'\r\n }\r\n },\r\n destroyTimeout: {\r\n value: 5000,\r\n types: ['number'],\r\n envLink: 'POOL_DESTROY_TIMEOUT',\r\n description: 'Timeout in milliseconds for destroying a resource',\r\n promptOptions: {\r\n type: 'number'\r\n }\r\n },\r\n idleTimeout: {\r\n value: 30000,\r\n types: ['number'],\r\n envLink: 'POOL_IDLE_TIMEOUT',\r\n description: 'Timeout in milliseconds for destroying idle resources',\r\n promptOptions: {\r\n type: 'number'\r\n }\r\n },\r\n createRetryInterval: {\r\n value: 200,\r\n types: ['number'],\r\n envLink: 'POOL_CREATE_RETRY_INTERVAL',\r\n description:\r\n 'Interval in milliseconds before retrying resource creation on failure',\r\n promptOptions: {\r\n type: 'number'\r\n }\r\n },\r\n reaperInterval: {\r\n value: 1000,\r\n types: ['number'],\r\n envLink: 'POOL_REAPER_INTERVAL',\r\n description:\r\n 'Interval in milliseconds to check and destroy idle resources',\r\n promptOptions: {\r\n type: 'number'\r\n }\r\n },\r\n benchmarking: {\r\n value: false,\r\n types: ['boolean'],\r\n envLink: 'POOL_BENCHMARKING',\r\n cliName: 'poolBenchmarking',\r\n description: 'Shows statistics for the pool of resources',\r\n promptOptions: {\r\n type: 'toggle'\r\n }\r\n }\r\n },\r\n logging: {\r\n level: {\r\n value: 4,\r\n types: ['number'],\r\n envLink: 'LOGGING_LEVEL',\r\n cliName: 'logLevel',\r\n description: 'Logging verbosity level',\r\n promptOptions: {\r\n type: 'number',\r\n round: 0,\r\n min: 0,\r\n max: 5\r\n }\r\n },\r\n file: {\r\n value: 'highcharts-export-server.log',\r\n types: ['string'],\r\n envLink: 'LOGGING_FILE',\r\n cliName: 'logFile',\r\n description:\r\n 'Log file name. Requires `logToFile` and `logDest` to be set',\r\n promptOptions: {\r\n type: 'text'\r\n }\r\n },\r\n dest: {\r\n value: 'log',\r\n types: ['string'],\r\n envLink: 'LOGGING_DEST',\r\n cliName: 'logDest',\r\n description: 'Path to store log files. Requires `logToFile` to be set',\r\n promptOptions: {\r\n type: 'text'\r\n }\r\n },\r\n toConsole: {\r\n value: true,\r\n types: ['boolean'],\r\n envLink: 'LOGGING_TO_CONSOLE',\r\n cliName: 'logToConsole',\r\n description: 'Enables or disables console logging',\r\n promptOptions: {\r\n type: 'toggle'\r\n }\r\n },\r\n toFile: {\r\n value: true,\r\n types: ['boolean'],\r\n envLink: 'LOGGING_TO_FILE',\r\n cliName: 'logToFile',\r\n description: 'Enables or disables logging to a file',\r\n promptOptions: {\r\n type: 'toggle'\r\n }\r\n }\r\n },\r\n ui: {\r\n enable: {\r\n value: false,\r\n types: ['boolean'],\r\n envLink: 'UI_ENABLE',\r\n cliName: 'enableUi',\r\n description: 'Enables or disables the UI for the export server',\r\n promptOptions: {\r\n type: 'toggle'\r\n }\r\n },\r\n route: {\r\n value: '/',\r\n types: ['string'],\r\n envLink: 'UI_ROUTE',\r\n cliName: 'uiRoute',\r\n description: 'The endpoint route for the UI',\r\n promptOptions: {\r\n type: 'text'\r\n }\r\n }\r\n },\r\n other: {\r\n nodeEnv: {\r\n value: 'production',\r\n types: ['string'],\r\n envLink: 'OTHER_NODE_ENV',\r\n description: 'The Node.js environment type',\r\n promptOptions: {\r\n type: 'text'\r\n }\r\n },\r\n listenToProcessExits: {\r\n value: true,\r\n types: ['boolean'],\r\n envLink: 'OTHER_LISTEN_TO_PROCESS_EXITS',\r\n description: 'Whether or not to attach process.exit handlers',\r\n promptOptions: {\r\n type: 'toggle'\r\n }\r\n },\r\n noLogo: {\r\n value: false,\r\n types: ['boolean'],\r\n envLink: 'OTHER_NO_LOGO',\r\n description: 'Display or skip printing the logo on startup',\r\n promptOptions: {\r\n type: 'toggle'\r\n }\r\n },\r\n hardResetPage: {\r\n value: false,\r\n types: ['boolean'],\r\n envLink: 'OTHER_HARD_RESET_PAGE',\r\n description: 'Whether or not to reset the page content entirely',\r\n promptOptions: {\r\n type: 'toggle'\r\n }\r\n },\r\n browserShellMode: {\r\n value: true,\r\n types: ['boolean'],\r\n envLink: 'OTHER_BROWSER_SHELL_MODE',\r\n description: 'Whether or not to set the browser to run in shell mode',\r\n promptOptions: {\r\n type: 'toggle'\r\n }\r\n },\r\n validation: {\r\n value: true,\r\n types: ['boolean'],\r\n envLink: 'OTHER_VALIDATION',\r\n description: 'Whether or not to enable validation of options types',\r\n promptOptions: {\r\n type: 'toggle'\r\n }\r\n }\r\n },\r\n debug: {\r\n enable: {\r\n value: false,\r\n types: ['boolean'],\r\n envLink: 'DEBUG_ENABLE',\r\n cliName: 'enableDebug',\r\n description: 'Enables or disables debug mode for the underlying browser',\r\n promptOptions: {\r\n type: 'toggle'\r\n }\r\n },\r\n headless: {\r\n value: false,\r\n types: ['boolean'],\r\n envLink: 'DEBUG_HEADLESS',\r\n description:\r\n 'Whether or not to set the browser to run in headless mode during debugging',\r\n promptOptions: {\r\n type: 'toggle'\r\n }\r\n },\r\n devtools: {\r\n value: false,\r\n types: ['boolean'],\r\n envLink: 'DEBUG_DEVTOOLS',\r\n description: 'Enables or disables DevTools in headful mode',\r\n promptOptions: {\r\n type: 'toggle'\r\n }\r\n },\r\n listenToConsole: {\r\n value: false,\r\n types: ['boolean'],\r\n envLink: 'DEBUG_LISTEN_TO_CONSOLE',\r\n description:\r\n 'Enables or disables listening to console messages from the browser',\r\n promptOptions: {\r\n type: 'toggle'\r\n }\r\n },\r\n dumpio: {\r\n value: false,\r\n types: ['boolean'],\r\n envLink: 'DEBUG_DUMPIO',\r\n description:\r\n 'Redirects or not browser stdout and stderr to process.stdout and process.stderr',\r\n promptOptions: {\r\n type: 'toggle'\r\n }\r\n },\r\n slowMo: {\r\n value: 0,\r\n types: ['number'],\r\n envLink: 'DEBUG_SLOW_MO',\r\n description: 'Delays Puppeteer operations by the specified milliseconds',\r\n promptOptions: {\r\n type: 'number'\r\n }\r\n },\r\n debuggingPort: {\r\n value: 9222,\r\n types: ['number'],\r\n envLink: 'DEBUG_DEBUGGING_PORT',\r\n description: 'Port used for debugging',\r\n promptOptions: {\r\n type: 'number'\r\n }\r\n }\r\n }\r\n};\r\n\r\n// Properties nesting level of all options\r\nexport const nestedProps = _createNestedProps(defaultConfig);\r\n\r\n// Properties names that should not be recursively merged\r\nexport const absoluteProps = _createAbsoluteProps(defaultConfig);\r\n\r\n/**\r\n * Recursively generates a mapping of nested argument chains from a nested\r\n * config object. This function traverses a nested object and creates a mapping\r\n * where each key is an argument name (either from `cliName`, `legacyName`,\r\n * or the original key) and each value is a string representing the chain\r\n * of nested properties leading to that argument.\r\n *\r\n * @function _createNestedProps\r\n *\r\n * @param {Object} config - The configuration object.\r\n * @param {Object} [nestedProps={}] - The accumulator object for storing\r\n * the resulting arguments chains. The default value is an empty object.\r\n * @param {string} [propChain=''] - The current chain of nested properties,\r\n * used internally during recursion. The default value is an empty string.\r\n *\r\n * @returns {Object} An object mapping argument names to their corresponding\r\n * nested property chains.\r\n */\r\nfunction _createNestedProps(config, nestedProps = {}, propChain = '') {\r\n Object.keys(config).forEach((key) => {\r\n // Get the specific section\r\n const entry = config[key];\r\n\r\n // Check if there is still more depth to traverse\r\n if (typeof entry.value === 'undefined') {\r\n // Recurse into deeper levels of nested arguments\r\n _createNestedProps(entry, nestedProps, `${propChain}.${key}`);\r\n } else {\r\n // Create the chain of nested arguments\r\n nestedProps[entry.cliName || key] = `${propChain}.${key}`.substring(1);\r\n\r\n // Support for the legacy, PhantomJS properties names\r\n if (entry.legacyName !== undefined) {\r\n nestedProps[entry.legacyName] = `${propChain}.${key}`.substring(1);\r\n }\r\n }\r\n });\r\n\r\n // Return the object with nested argument chains\r\n return nestedProps;\r\n}\r\n\r\n/**\r\n * Recursively gathers the names of properties from a configuration object that\r\n * can be treated as absolute properties. These properties have values that\r\n * are objects and do not contain further nested depth when merging an object\r\n * containing these options.\r\n *\r\n * @function _createAbsoluteProps\r\n *\r\n * @param {Object} config - The configuration object.\r\n * @param {Array.} [absoluteProps=[]] - An array to collect the names\r\n * of absolute properties. The default value is an empty array.\r\n *\r\n * @returns {Array.} An array containing the names of absolute\r\n * properties.\r\n */\r\nfunction _createAbsoluteProps(config, absoluteProps = []) {\r\n Object.keys(config).forEach((key) => {\r\n // Get the specific section\r\n const entry = config[key];\r\n\r\n // Check if there is still more depth to traverse\r\n if (typeof entry.types === 'undefined') {\r\n // Recurse into deeper levels\r\n _createAbsoluteProps(entry, absoluteProps);\r\n } else {\r\n // If the option can be an object, save its type in the array\r\n if (entry.types.includes('Object')) {\r\n absoluteProps.push(key);\r\n }\r\n }\r\n });\r\n\r\n // Return the array with the names of absolute properties\r\n return absoluteProps;\r\n}\r\n\r\nexport default {\r\n defaultConfig,\r\n nestedProps,\r\n absoluteProps\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * @overview This file handles parsing and validating options from multiple\r\n * sources (the config file, custom JSON, environment variables, CLI arguments,\r\n * and request payload) using the 'zod' library.\r\n *\r\n * Environment variables are parsed and validated only once at application\r\n * startup, and the validated results are exported as `envs` for use throughout\r\n * the application.\r\n *\r\n * Options from other sources, however, are parsed and validated on demand,\r\n * each time an export is attempted.\r\n */\r\n\r\nimport dotenv from 'dotenv';\r\nimport { z } from 'zod';\r\n\r\nimport { defaultConfig } from './schemas/config.js';\r\n\r\n// Load the .env into environment variables\r\ndotenv.config();\r\n\r\n// Get scripts names of each category from the default config\r\nconst { coreScripts, moduleScripts, indicatorScripts } =\r\n defaultConfig.highcharts;\r\n\r\n// Sets the custom error map globally\r\nz.setErrorMap(_customErrorMap);\r\n\r\n/**\r\n * Object containing custom general validators and parsers to avoid repetition\r\n * in schema objects. All validators apply to values from various sources,\r\n * including the default config file, a custom JSON file loaded with the option\r\n * called `loadConfig`, the .env file, CLI arguments, and the request payload.\r\n * The `strictCheck` flag enables stricter validation and parsing rules. This\r\n * flag is set to false for values that come from the .env file or CLI arguments\r\n * because they are provided as strings and need to be parsed accordingly first.\r\n */\r\nconst v = {\r\n /**\r\n * The `boolean` validator that returns a Zod schema with an optional stricter\r\n * check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures that:\r\n *\r\n * - When `strictCheck` is true, the schema will accept values are true\r\n * and false and the schema will validate against the default boolean\r\n * validator.\r\n *\r\n * - When `strictCheck` is false, the schema will accept values are true,\r\n * false, null, 'true', '1', 'false', '0', 'undefined', 'null', and ''.\r\n * The strings 'undefined', 'null', and '' will be transformed to null,\r\n * the string 'true' will be transformed to the boolean value true,\r\n * and 'false' will be transformed to the boolean value false.\r\n *\r\n * @function boolean\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating boolean values.\r\n */\r\n boolean(strictCheck) {\r\n return strictCheck\r\n ? z.boolean()\r\n : z\r\n .union([\r\n z\r\n .enum(['true', '1', 'false', '0', 'undefined', 'null', ''])\r\n .transform((value) =>\r\n !['undefined', 'null', ''].includes(value)\r\n ? value === 'true' || value === '1'\r\n : null\r\n ),\r\n z.boolean()\r\n ])\r\n .nullable();\r\n },\r\n\r\n /**\r\n * The `string` validator that returns a Zod schema with an optional stricter\r\n * check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures that:\r\n *\r\n * - When `strictCheck` is true, the schema will accept trimmed strings except\r\n * the forbidden values: 'false', 'undefined', 'null', and ''.\r\n *\r\n * - When `strictCheck` is false, the schema will accept trimmed strings\r\n * and null. The forbidden values: 'false', 'undefined', 'null', and '' will\r\n * be transformed to null.\r\n *\r\n * @function string\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating string values.\r\n */\r\n string(strictCheck) {\r\n return strictCheck\r\n ? z\r\n .string()\r\n .trim()\r\n .refine(\r\n (value) => !['false', 'undefined', 'null', ''].includes(value),\r\n {\r\n params: {\r\n errorMessage: 'The string contains a forbidden value'\r\n }\r\n }\r\n )\r\n : z\r\n .string()\r\n .trim()\r\n .transform((value) =>\r\n !['false', 'undefined', 'null', ''].includes(value) ? value : null\r\n )\r\n .nullable();\r\n },\r\n\r\n /**\r\n * The `enum` validator that returns a Zod schema with an optional stricter\r\n * check based on the `strictCheck` parameter.\r\n *\r\n * The schema will validate against the provided `values` array.\r\n *\r\n * The validation schema ensures that:\r\n *\r\n * - When `strictCheck` is true, the schema will validate against the `values`\r\n * array with the default enum validator.\r\n *\r\n * - When `strictCheck` is false, the schema will accept also null,\r\n * 'undefined', 'null', and '', which will be transformed to null.\r\n *\r\n * @function enum\r\n *\r\n * @param {Array.} values - An array of valid string values\r\n * for the enum.\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating enum values.\r\n */\r\n enum(values, strictCheck) {\r\n return strictCheck\r\n ? z.enum([...values])\r\n : z\r\n .enum([...values, 'undefined', 'null', ''])\r\n .transform((value) =>\r\n !['undefined', 'null', ''].includes(value) ? value : null\r\n )\r\n .nullable();\r\n },\r\n\r\n /**\r\n * The `stringArray` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures that:\r\n *\r\n * - When `strictCheck` is true, the schema will accept an array of trimmed\r\n * string values filtered by the logic provided through the `filterCallback`.\r\n *\r\n * - When `strictCheck` is false, the schema will accept null and trimmed\r\n * string values which will be splitted into an array of strings and filtered\r\n * from the '[' and ']' characters and by the logic provided through\r\n * the `filterCallback`. If the array is empty, it will be transformed\r\n * to null.\r\n *\r\n * @function stringArray\r\n *\r\n * @param {function} filterCallback - The filter callback.\r\n * @param {string} separator - The separator for spliting a string.\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating array of string\r\n * values.\r\n */\r\n stringArray(filterCallback, separator, strictCheck) {\r\n const arraySchema = z.string().trim().array();\r\n const stringSchema = z\r\n .string()\r\n .trim()\r\n .transform((value) => {\r\n if (value.startsWith('[')) {\r\n value = value.slice(1);\r\n }\r\n if (value.endsWith(']')) {\r\n value = value.slice(0, -1);\r\n }\r\n return value.split(separator);\r\n });\r\n\r\n const transformCallback = (value) =>\r\n value.map((value) => value.trim()).filter(filterCallback);\r\n\r\n return strictCheck\r\n ? arraySchema.transform(transformCallback)\r\n : z\r\n .union([stringSchema, arraySchema])\r\n .transform(transformCallback)\r\n .transform((value) => (value.length ? value : null))\r\n .nullable();\r\n },\r\n\r\n /**\r\n * The `positiveNum` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures that:\r\n *\r\n * - When `strictCheck` is true, the schema will accept positive number values\r\n * and validate against the default positive number validator.\r\n *\r\n * - When `strictCheck` is false, the schema will accept positive number\r\n * values, null, and trimmed string values that can either be 'undefined',\r\n * 'null', '', or represent a positive number. It will transform the string\r\n * to a positive number, or to null if it is 'undefined', 'null', or ''.\r\n *\r\n * @function positiveNum\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating positive number\r\n * values.\r\n */\r\n positiveNum(strictCheck) {\r\n return strictCheck\r\n ? z.number().positive()\r\n : z\r\n .union([\r\n z\r\n .string()\r\n .trim()\r\n .refine(\r\n (value) =>\r\n (!isNaN(Number(value)) && Number(value) > 0) ||\r\n ['undefined', 'null', ''].includes(value),\r\n {\r\n params: {\r\n errorMessage: 'The value must be numeric and positive'\r\n }\r\n }\r\n )\r\n .transform((value) =>\r\n !['undefined', 'null', ''].includes(value)\r\n ? Number(value)\r\n : null\r\n ),\r\n z.number().positive()\r\n ])\r\n .nullable();\r\n },\r\n\r\n /**\r\n * The `nonNegativeNum` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures that:\r\n *\r\n * - When `strictCheck` is true, the schema will accept non-negative number\r\n * values and validate against the default non-negative number validator.\r\n *\r\n * - When `strictCheck` is false, the schema will accept non-negative number\r\n * values, null, and trimmed string values that can either be 'undefined',\r\n * 'null', '', or represent a non-negative number. It will transform\r\n * the string to a non-negative number, or to null if it is 'undefined',\r\n * 'null', or ''.\r\n *\r\n * @function nonNegativeNum\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating non-negative\r\n * number values.\r\n */\r\n nonNegativeNum(strictCheck) {\r\n return strictCheck\r\n ? z.number().nonnegative()\r\n : z\r\n .union([\r\n z\r\n .string()\r\n .trim()\r\n .refine(\r\n (value) =>\r\n (!isNaN(Number(value)) && Number(value) >= 0) ||\r\n ['undefined', 'null', ''].includes(value),\r\n {\r\n params: {\r\n errorMessage: 'The value must be numeric and non-negative'\r\n }\r\n }\r\n )\r\n .transform((value) =>\r\n !['undefined', 'null', ''].includes(value)\r\n ? Number(value)\r\n : null\r\n ),\r\n z.number().nonnegative()\r\n ])\r\n .nullable();\r\n },\r\n\r\n /**\r\n * The `startsWith` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The schema will validate against the provided `prefixes` array to check\r\n * whether a string value starts with any of the values provided\r\n * in the `prefixes` array.\r\n *\r\n * The validation schema ensures that:\r\n *\r\n * - When `strictCheck` is true, the schema will accept trimmed string values\r\n * that start with values from the prefixes array.\r\n *\r\n * - When `strictCheck` is false, the schema will accept trimmed string values\r\n * that start with values from the prefixes array, null, 'undefined', 'null',\r\n * and '' where the schema will transform them to null.\r\n *\r\n * @function startsWith\r\n *\r\n * @param {Array.} prefixes - An array of prefixes to validate\r\n * the string against.\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating strings that\r\n * starts with values.\r\n */\r\n startsWith(prefixes, strictCheck) {\r\n return strictCheck\r\n ? z\r\n .string()\r\n .trim()\r\n .refine(\r\n (value) => prefixes.some((prefix) => value.startsWith(prefix)),\r\n {\r\n params: {\r\n errorMessage: `The value must be a string that starts with ${prefixes.join(', ')}`\r\n }\r\n }\r\n )\r\n : z\r\n .string()\r\n .trim()\r\n .refine(\r\n (value) =>\r\n prefixes.some((prefix) => value.startsWith(prefix)) ||\r\n ['undefined', 'null', ''].includes(value),\r\n {\r\n params: {\r\n errorMessage: `The value must be a string that starts with ${prefixes.join(', ')}`\r\n }\r\n }\r\n )\r\n .transform((value) =>\r\n !['undefined', 'null', ''].includes(value) ? value : null\r\n )\r\n .nullable();\r\n },\r\n\r\n /**\r\n * The `chartConfig` validator that returns a Zod schema.\r\n *\r\n * The validation schema ensures that the schema will accept object values\r\n * or trimmed string values that contain '\r\n (value.startsWith('{') && value.endsWith('}')) ||\r\n ['undefined', 'null', ''].includes(value),\r\n {\r\n params: {\r\n errorMessage:\r\n \"The value must be a string that starts with '{' and ends with '}'\"\r\n }\r\n }\r\n )\r\n .transform((value) =>\r\n !['undefined', 'null', ''].includes(value) ? value : null\r\n ),\r\n z.object({}).passthrough()\r\n ])\r\n .nullable();\r\n },\r\n\r\n /**\r\n * The `additionalOptions` validator that returns a Zod schema.\r\n *\r\n * The validation schema ensures that the schema will accept object values\r\n * or trimmed string values that end with '.json' and are at least one\r\n * character long excluding the extension, start with the '{' and end\r\n * with the '}', and null. The 'undefined', 'null', and '' values will\r\n * be transformed to null.\r\n *\r\n * @function additionalOptions\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating additional chart\r\n * options value.\r\n */\r\n additionalOptions() {\r\n return z\r\n .union([\r\n z\r\n .string()\r\n .trim()\r\n .refine(\r\n (value) =>\r\n (value.length >= 6 && value.endsWith('.json')) ||\r\n (value.startsWith('{') && value.endsWith('}')) ||\r\n ['undefined', 'null', ''].includes(value),\r\n {\r\n params: {\r\n errorMessage:\r\n \"The value must be a string that ends with '.json' or starts with '{' and ends with '}'\"\r\n }\r\n }\r\n )\r\n .transform((value) =>\r\n !['undefined', 'null', ''].includes(value) ? value : null\r\n ),\r\n z.object({}).passthrough()\r\n ])\r\n .nullable();\r\n }\r\n};\r\n\r\n/**\r\n * Object containing custom config validators and parsers to avoid repetition\r\n * in schema objects. All validators apply to values from various sources,\r\n * including the default config file, a custom JSON file loaded with the option\r\n * called `loadConfig`, the .env file, CLI arguments, and the request payload.\r\n * The `strictCheck` flag enables stricter validation and parsing rules. This\r\n * flag is set to false for values that come from the .env file or CLI arguments\r\n * because they are provided as strings and need to be parsed accordingly first.\r\n */\r\nexport const validators = {\r\n /**\r\n * The `args` validator that returns a Zod schema with an optional stricter\r\n * check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `stringArray` validator.\r\n *\r\n * @function args\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `args`\r\n * option.\r\n */\r\n args(strictCheck) {\r\n return v.stringArray(\r\n (value) => !['false', 'undefined', 'null', ''].includes(value),\r\n ';',\r\n strictCheck\r\n );\r\n },\r\n\r\n /**\r\n * The `version` validator that returns a Zod schema with an optional stricter\r\n * check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures that:\r\n *\r\n * - When `strictCheck` is true, the schema will accept trimmed string values\r\n * that are a RegExp-based that allows to be 'latest', or in the format XX,\r\n * XX.YY, or XX.YY.ZZ, where XX, YY, and ZZ are numeric for the Highcharts\r\n * version option.\r\n *\r\n * - When `strictCheck` is false, the schema will accept also null,\r\n * 'undefined', 'null', or '' and in all cases the schema will transform them\r\n * to null.\r\n *\r\n * @function version\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `version`\r\n * option.\r\n */\r\n version(strictCheck) {\r\n return strictCheck\r\n ? z\r\n .string()\r\n .trim()\r\n .refine((value) => /^(latest|\\d{1,2}(\\.\\d{1,2}){0,2})$/.test(value), {\r\n params: {\r\n errorMessage:\r\n \"The value must be 'latest', a major version, or in the form XX.YY.ZZ\"\r\n }\r\n })\r\n : z\r\n .string()\r\n .trim()\r\n .refine(\r\n (value) =>\r\n /^(latest|\\d{1,2}(\\.\\d{1,2}){0,2})$/.test(value) ||\r\n ['undefined', 'null', ''].includes(value),\r\n {\r\n params: {\r\n errorMessage:\r\n \"The value must be 'latest', a major version, or in the form XX.YY.ZZ\"\r\n }\r\n }\r\n )\r\n .transform((value) =>\r\n !['undefined', 'null', ''].includes(value) ? value : null\r\n )\r\n .nullable();\r\n },\r\n\r\n /**\r\n * The `cdnUrl` validator that returns a Zod schema with an optional stricter\r\n * check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `startsWith` validator.\r\n *\r\n * @function cdnUrl\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `cdnUrl`\r\n * option.\r\n */\r\n cdnUrl(strictCheck) {\r\n return v.startsWith(['http://', 'https://'], strictCheck);\r\n },\r\n\r\n /**\r\n * The `forceFetch` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `boolean` validator.\r\n *\r\n * @function forceFetch\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `forceFetch`\r\n * option.\r\n */\r\n forceFetch(strictCheck) {\r\n return v.boolean(strictCheck);\r\n },\r\n\r\n /**\r\n * The `cachePath` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `string` validator.\r\n *\r\n * @function cachePath\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `cachePath`\r\n * option.\r\n */\r\n cachePath(strictCheck) {\r\n return v.string(strictCheck);\r\n },\r\n\r\n /**\r\n * The `adminToken` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `string` validator.\r\n *\r\n * @function adminToken\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `adminToken`\r\n * option.\r\n */\r\n adminToken(strictCheck) {\r\n return v.string(strictCheck);\r\n },\r\n\r\n /**\r\n * The `coreScripts` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `stringArray` validator.\r\n *\r\n * @function coreScripts\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `coreScripts`\r\n * option.\r\n */\r\n coreScripts(strictCheck) {\r\n return v.stringArray(\r\n (value) => coreScripts.value.includes(value),\r\n ',',\r\n strictCheck\r\n );\r\n },\r\n\r\n /**\r\n * The `moduleScripts` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `stringArray` validator.\r\n *\r\n * @function moduleScripts\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating\r\n * the `moduleScripts` option.\r\n */\r\n moduleScripts(strictCheck) {\r\n return v.stringArray(\r\n (value) => moduleScripts.value.includes(value),\r\n ',',\r\n strictCheck\r\n );\r\n },\r\n\r\n /**\r\n * The `indicatorScripts` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `stringArray` validator.\r\n *\r\n * @function indicatorScripts\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating\r\n * the `indicatorScripts` option.\r\n */\r\n indicatorScripts(strictCheck) {\r\n return v.stringArray(\r\n (value) => indicatorScripts.value.includes(value),\r\n ',',\r\n strictCheck\r\n );\r\n },\r\n\r\n /**\r\n * The `customScripts` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `stringArray` validator.\r\n *\r\n * @function customScripts\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating\r\n * the `customScripts` option.\r\n */\r\n customScripts(strictCheck) {\r\n return v.stringArray(\r\n (value) => value.startsWith('https://') || value.startsWith('http://'),\r\n ',',\r\n strictCheck\r\n );\r\n },\r\n\r\n /**\r\n * The `infile` validator that returns a Zod schema with an optional stricter\r\n * check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures that:\r\n *\r\n * - When `strictCheck` is true, the schema will accept trimmed string values\r\n * that end with '.json' or '.svg', are at least one character long excluding\r\n * the extension, or null.\r\n *\r\n * - When `strictCheck` is false, the schema will accept trimmed string values\r\n * that end with '.json' or '.svg', are at least one character long excluding\r\n * the extension and will be null if the provided value is null, 'undefined',\r\n * 'null', or ''.\r\n *\r\n * @function infile\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `infile`\r\n * option.\r\n */\r\n infile(strictCheck) {\r\n return strictCheck\r\n ? z\r\n .string()\r\n .trim()\r\n .refine(\r\n (value) =>\r\n (value.length >= 6 && value.endsWith('.json')) ||\r\n (value.length >= 5 && value.endsWith('.svg')),\r\n {\r\n params: {\r\n errorMessage:\r\n 'The value must be a string that ends with .json or .svg'\r\n }\r\n }\r\n )\r\n .nullable()\r\n : z\r\n .string()\r\n .trim()\r\n .refine(\r\n (value) =>\r\n (value.length >= 6 && value.endsWith('.json')) ||\r\n (value.length >= 5 && value.endsWith('.svg')) ||\r\n ['undefined', 'null', ''].includes(value),\r\n {\r\n params: {\r\n errorMessage:\r\n 'The value must be a string that ends with .json or .svg'\r\n }\r\n }\r\n )\r\n .transform((value) =>\r\n !['undefined', 'null', ''].includes(value) ? value : null\r\n )\r\n .nullable();\r\n },\r\n\r\n /**\r\n * The `instr` validator that returns a Zod schema.\r\n *\r\n * The validation schema ensures the same work as the `options` validator.\r\n *\r\n * @function instr\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `instr`\r\n * option.\r\n */\r\n instr() {\r\n return v.chartConfig();\r\n },\r\n\r\n /**\r\n * The `options` validator that returns a Zod schema.\r\n *\r\n * The validation schema ensures the same work as the `options` validator.\r\n *\r\n * @function options\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `options`\r\n * option.\r\n */\r\n options() {\r\n return v.chartConfig();\r\n },\r\n\r\n /**\r\n * The `svg` validator that returns a Zod schema.\r\n *\r\n * The validation schema ensures that the schema will accept object values\r\n * or trimmed string values that contain '\r\n value.indexOf('= 0 ||\r\n value.indexOf('= 0 ||\r\n ['false', 'undefined', 'null', ''].includes(value),\r\n {\r\n params: {\r\n errorMessage:\r\n \"The value must be a string that contains '\r\n !['false', 'undefined', 'null', ''].includes(value) ? value : null\r\n )\r\n .nullable();\r\n },\r\n\r\n /**\r\n * The `outfile` validator that returns a Zod schema with an optional stricter\r\n * check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures that:\r\n *\r\n * - When `strictCheck` is true, the schema will accept trimmed string values\r\n * that end with '.jpeg', '.jpg', '.png', '.pdf', or '.svg', are at least one\r\n * character long excluding the extension, or null.\r\n *\r\n * - When `strictCheck` is false, the schema will accept trimmed string values\r\n * that end with '.jpeg', '.jpg', '.png', '.pdf', or '.svg', are at least one\r\n * character long excluding the extension and will be null if the provided\r\n * value is null, 'undefined', 'null', or ''.\r\n *\r\n * @function outfile\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `outfile`\r\n * option.\r\n */\r\n outfile(strictCheck) {\r\n return strictCheck\r\n ? z\r\n .string()\r\n .trim()\r\n .refine(\r\n (value) =>\r\n (value.length >= 6 && value.endsWith('.jpeg')) ||\r\n (value.length >= 5 &&\r\n (value.endsWith('.jpg') ||\r\n value.endsWith('.png') ||\r\n value.endsWith('.pdf') ||\r\n value.endsWith('.svg'))),\r\n {\r\n params: {\r\n errorMessage:\r\n 'The value must be a string that ends with .jpeg, .jpg, .png, .pdf, or .svg'\r\n }\r\n }\r\n )\r\n .nullable()\r\n : z\r\n .string()\r\n .trim()\r\n .refine(\r\n (value) =>\r\n (value.length >= 6 && value.endsWith('.jpeg')) ||\r\n (value.length >= 5 &&\r\n (value.endsWith('.jpg') ||\r\n value.endsWith('.png') ||\r\n value.endsWith('.pdf') ||\r\n value.endsWith('.svg'))) ||\r\n ['undefined', 'null', ''].includes(value),\r\n {\r\n params: {\r\n errorMessage:\r\n 'The value must be a string that ends with .jpeg, .jpg, .png, .pdf, or .svg'\r\n }\r\n }\r\n )\r\n .transform((value) =>\r\n !['undefined', 'null', ''].includes(value) ? value : null\r\n )\r\n .nullable();\r\n },\r\n\r\n /**\r\n * The `type` validator that returns a Zod schema with an optional stricter\r\n * check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `enum` validator.\r\n *\r\n * @function type\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `type`\r\n * option.\r\n */\r\n type(strictCheck) {\r\n return v.enum(['jpeg', 'jpg', 'png', 'pdf', 'svg'], strictCheck);\r\n },\r\n\r\n /**\r\n * The `constr` validator that returns a Zod schema with an optional stricter\r\n * check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `enum` validator.\r\n *\r\n * @function constr\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `constr`\r\n * option.\r\n */\r\n constr(strictCheck) {\r\n return v.enum(\r\n ['chart', 'stockChart', 'mapChart', 'ganttChart'],\r\n strictCheck\r\n );\r\n },\r\n\r\n /**\r\n * The `b64` validator that returns a Zod schema with an optional stricter\r\n * check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `boolean` validator.\r\n *\r\n * @function b64\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `b64` option.\r\n */\r\n b64(strictCheck) {\r\n return v.boolean(strictCheck);\r\n },\r\n\r\n /**\r\n * The `noDownload` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `boolean` validator.\r\n *\r\n * @function noDownload\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `noDownload`\r\n * option.\r\n */\r\n noDownload(strictCheck) {\r\n return v.boolean(strictCheck);\r\n },\r\n\r\n /**\r\n * The `defaultHeight` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `positiveNum` validator.\r\n *\r\n * @function defaultHeight\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating\r\n * the `defaultHeight` option.\r\n */\r\n defaultHeight(strictCheck) {\r\n return v.positiveNum(strictCheck);\r\n },\r\n\r\n /**\r\n * The `defaultWidth` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `positiveNum` validator.\r\n *\r\n * @function defaultWidth\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating\r\n * the `defaultWidth` option.\r\n */\r\n defaultWidth(strictCheck) {\r\n return v.positiveNum(strictCheck);\r\n },\r\n\r\n /**\r\n * The `defaultScale` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures that:\r\n *\r\n * - When `strictCheck` is true, the schema will accept number values that\r\n * are between 0.1 and 5 (inclusive).\r\n *\r\n * - When `strictCheck` is false, the schema will accept number values\r\n * and stringified number values that are between 0.1 and 5 (inclusive), null,\r\n * 'undefined', 'null', and '' which will be transformed to null.\r\n *\r\n * @function defaultScale\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating\r\n * the `defaultScale` option.\r\n */\r\n defaultScale(strictCheck) {\r\n return strictCheck\r\n ? z.number().gte(0.1).lte(5)\r\n : z\r\n .union([\r\n z\r\n .string()\r\n .trim()\r\n .refine(\r\n (value) =>\r\n (!isNaN(Number(value)) &&\r\n value !== true &&\r\n !value.startsWith('[') &&\r\n Number(value) >= 0.1 &&\r\n Number(value) <= 5) ||\r\n ['undefined', 'null', ''].includes(value),\r\n {\r\n params: {\r\n errorMessage: 'The value must be within a 0.1 and 5.0 range'\r\n }\r\n }\r\n )\r\n .transform((value) =>\r\n !['undefined', 'null', ''].includes(value)\r\n ? Number(value)\r\n : null\r\n ),\r\n z.number().gte(0.1).lte(5)\r\n ])\r\n .nullable();\r\n },\r\n\r\n /**\r\n * The `height` validator that returns a Zod schema with an optional stricter\r\n * check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as a nullable `defaultHeight`\r\n * validator.\r\n *\r\n * @function height\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `height`\r\n * option.\r\n */\r\n height(strictCheck) {\r\n return this.defaultHeight(strictCheck).nullable();\r\n },\r\n\r\n /**\r\n * The `width` validator that returns a Zod schema with an optional stricter\r\n * check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as a nullable `defaultWidth`\r\n * validator.\r\n *\r\n * @function width\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `width`\r\n * option.\r\n */\r\n width(strictCheck) {\r\n return this.defaultWidth(strictCheck).nullable();\r\n },\r\n\r\n /**\r\n * The `scale` validator that returns a Zod schema with an optional stricter\r\n * check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as a nullable `defaultScale`\r\n * validator.\r\n *\r\n * @function scale\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `scale`\r\n * option.\r\n */\r\n scale(strictCheck) {\r\n return this.defaultScale(strictCheck).nullable();\r\n },\r\n\r\n /**\r\n * The `globalOptions` validator that returns a Zod schema.\r\n *\r\n * The validation schema ensures the same work as the `additionalOptions`\r\n * validator.\r\n *\r\n * @function globalOptions\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating\r\n * the `globalOptions` option.\r\n */\r\n globalOptions() {\r\n return v.additionalOptions();\r\n },\r\n\r\n /**\r\n * The `themeOptions` validator that returns a Zod schema.\r\n *\r\n * The validation schema ensures the same work as the `additionalOptions`\r\n * validator.\r\n *\r\n * @function themeOptions\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating\r\n * the `themeOptions` option.\r\n */\r\n themeOptions() {\r\n return v.additionalOptions();\r\n },\r\n\r\n /**\r\n * The `batch` validator that returns a Zod schema with an optional stricter\r\n * check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `string` validator.\r\n *\r\n * @function batch\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `batch`\r\n * option.\r\n */\r\n batch(strictCheck) {\r\n return v.string(strictCheck);\r\n },\r\n\r\n /**\r\n * The `rasterizationTimeout` validator that returns a Zod schema with\r\n * an optional stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `nonNegativeNum`\r\n * validator.\r\n *\r\n * @function rasterizationTimeout\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating\r\n * the `rasterizationTimeout` option.\r\n */\r\n rasterizationTimeout(strictCheck) {\r\n return v.nonNegativeNum(strictCheck);\r\n },\r\n\r\n /**\r\n * The `allowCodeExecution` validator that returns a Zod schema with\r\n * an optional stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `boolean` validator.\r\n *\r\n * @function allowCodeExecution\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating\r\n * the `allowCodeExecution` option.\r\n */\r\n allowCodeExecution(strictCheck) {\r\n return v.boolean(strictCheck);\r\n },\r\n\r\n /**\r\n * The `allowFileResources` validator that returns a Zod schema with\r\n * an optional stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `boolean` validator.\r\n *\r\n * @function allowFileResources\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating\r\n * the `allowFileResources` option.\r\n */\r\n allowFileResources(strictCheck) {\r\n return v.boolean(strictCheck);\r\n },\r\n\r\n /**\r\n * The `customCode` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `string` validator.\r\n *\r\n * @function customCode\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `customCode`\r\n * option.\r\n */\r\n customCode(strictCheck) {\r\n return v.string(strictCheck);\r\n },\r\n\r\n /**\r\n * The `callback` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `string` validator.\r\n *\r\n * @function callback\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `callback`\r\n * option.\r\n */\r\n callback(strictCheck) {\r\n return v.string(strictCheck);\r\n },\r\n\r\n /**\r\n * The `resources` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures that:\r\n *\r\n * - When `strictCheck` is true, the schema will accept a partial object\r\n * with allowed properties `js`, `css`, and `files` where each of the allowed\r\n * properties can be null, stringified version of the object, string that ends\r\n * with the '.json', and null.\r\n *\r\n * - When `strictCheck` is false, the schema will accept a stringified version\r\n * of a partial object with allowed properties `js`, `css`, and `files` where\r\n * each of the allowed properties can be null, string that ends with the\r\n * '.json', and will be null if the provided value is 'undefined', 'null'\r\n * or ''.\r\n *\r\n * @function resources\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `resources`\r\n * option.\r\n */\r\n resources(strictCheck) {\r\n const objectSchema = z\r\n .object({\r\n js: v.string(false),\r\n css: v.string(false),\r\n files: v\r\n .stringArray(\r\n (value) => !['undefined', 'null', ''].includes(value),\r\n ',',\r\n true\r\n )\r\n .nullable()\r\n })\r\n .partial();\r\n\r\n const stringSchema1 = z\r\n .string()\r\n .trim()\r\n .refine(\r\n (value) =>\r\n (value.startsWith('{') && value.endsWith('}')) ||\r\n (value.length >= 6 && value.endsWith('.json')),\r\n {\r\n params: {\r\n errorMessage:\r\n \"The value must be a string that starts with '{' and ends with '}\"\r\n }\r\n }\r\n );\r\n\r\n const stringSchema2 = z\r\n .string()\r\n .trim()\r\n .refine(\r\n (value) =>\r\n (value.startsWith('{') && value.endsWith('}')) ||\r\n (value.length >= 6 && value.endsWith('.json')) ||\r\n ['undefined', 'null', ''].includes(value),\r\n {\r\n params: {\r\n errorMessage: 'The value must be a string that ends with .json'\r\n }\r\n }\r\n )\r\n .transform((value) =>\r\n !['undefined', 'null', ''].includes(value) ? value : null\r\n );\r\n\r\n return strictCheck\r\n ? z.union([objectSchema, stringSchema1]).nullable()\r\n : z.union([objectSchema, stringSchema2]).nullable();\r\n },\r\n\r\n /**\r\n * The `loadConfig` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `string` validator.\r\n * Additionally, it must be a string that ends with '.json'.\r\n *\r\n * @function loadConfig\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `loadConfig`\r\n * option.\r\n */\r\n loadConfig(strictCheck) {\r\n return v\r\n .string(strictCheck)\r\n .refine(\r\n (value) =>\r\n value === null || (value.length >= 6 && value.endsWith('.json')),\r\n {\r\n params: {\r\n errorMessage: 'The value must be a string that ends with .json'\r\n }\r\n }\r\n );\r\n },\r\n\r\n /**\r\n * The `createConfig` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `loadConfig` validator.\r\n *\r\n * @function createConfig\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating\r\n * the `createConfig` option.\r\n */\r\n createConfig(strictCheck) {\r\n return this.loadConfig(strictCheck);\r\n },\r\n\r\n /**\r\n * The `enableServer` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `boolean` validator.\r\n *\r\n * @function enableServer\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating\r\n * the `enableServer` option.\r\n */\r\n enableServer(strictCheck) {\r\n return v.boolean(strictCheck);\r\n },\r\n\r\n /**\r\n * The `host` validator that returns a Zod schema with an optional stricter\r\n * check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `string` validator.\r\n *\r\n * @function host\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `host`\r\n * option.\r\n */\r\n host(strictCheck) {\r\n return v.string(strictCheck);\r\n },\r\n\r\n /**\r\n * The `port` validator that returns a Zod schema with an optional stricter\r\n * check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `nonNegativeNum`\r\n * validator.\r\n *\r\n * @function port\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `port`\r\n * option.\r\n */\r\n port(strictCheck) {\r\n return v.nonNegativeNum(strictCheck);\r\n },\r\n\r\n /**\r\n * The `uploadLimit` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `positiveNum` validator.\r\n *\r\n * @function uploadLimit\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `uploadLimit`\r\n * option.\r\n */\r\n uploadLimit(strictCheck) {\r\n return v.positiveNum(strictCheck);\r\n },\r\n\r\n /**\r\n * The `serverBenchmarking` validator that returns a Zod schema with\r\n * an optional stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `boolean` validator.\r\n *\r\n * @function serverBenchmarking\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating\r\n * the `serverBenchmarking` option.\r\n */\r\n serverBenchmarking(strictCheck) {\r\n return v.boolean(strictCheck);\r\n },\r\n\r\n /**\r\n * The `proxyHost` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `string` validator.\r\n *\r\n * @function proxyHost\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `proxyHost`\r\n * option.\r\n */\r\n proxyHost(strictCheck) {\r\n return v.string(strictCheck);\r\n },\r\n\r\n /**\r\n * The `proxyPort` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as a nullable `nonNegativeNum`\r\n * validator.\r\n *\r\n * @function proxyPort\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `proxyPort`\r\n * option.\r\n */\r\n proxyPort(strictCheck) {\r\n return v.nonNegativeNum(strictCheck).nullable();\r\n },\r\n\r\n /**\r\n * The `proxyTimeout` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `nonNegativeNum`\r\n * validator.\r\n *\r\n * @function proxyTimeout\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating\r\n * the `proxyTimeout` option.\r\n */\r\n proxyTimeout(strictCheck) {\r\n return v.nonNegativeNum(strictCheck);\r\n },\r\n\r\n /**\r\n * The `enableRateLimiting` validator that returns a Zod schema with\r\n * an optional stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `boolean` validator.\r\n *\r\n * @function enableRateLimiting\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating\r\n * the `enableRateLimiting` option.\r\n */\r\n enableRateLimiting(strictCheck) {\r\n return v.boolean(strictCheck);\r\n },\r\n\r\n /**\r\n * The `maxRequests` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `nonNegativeNum`\r\n * validator.\r\n *\r\n * @function maxRequests\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `maxRequests`\r\n * option.\r\n */\r\n maxRequests(strictCheck) {\r\n return v.nonNegativeNum(strictCheck);\r\n },\r\n\r\n /**\r\n * The `window` validator that returns a Zod schema with an optional stricter\r\n * check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `nonNegativeNum`\r\n * validator.\r\n *\r\n * @function window\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `window`\r\n * option.\r\n */\r\n window(strictCheck) {\r\n return v.nonNegativeNum(strictCheck);\r\n },\r\n\r\n /**\r\n * The `delay` validator that returns a Zod schema with an optional stricter\r\n * check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `nonNegativeNum`\r\n * validator.\r\n *\r\n * @function delay\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `delay`\r\n * option.\r\n */\r\n delay(strictCheck) {\r\n return v.nonNegativeNum(strictCheck);\r\n },\r\n\r\n /**\r\n * The `trustProxy` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `boolean` validator.\r\n *\r\n * @function trustProxy\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `trustProxy`\r\n * option.\r\n */\r\n trustProxy(strictCheck) {\r\n return v.boolean(strictCheck);\r\n },\r\n\r\n /**\r\n * The `skipKey` validator that returns a Zod schema with an optional stricter\r\n * check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `string` validator.\r\n *\r\n * @function skipKey\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `skipKey`\r\n * option.\r\n */\r\n skipKey(strictCheck) {\r\n return v.string(strictCheck);\r\n },\r\n\r\n /**\r\n * The `skipToken` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `string` validator.\r\n *\r\n * @function skipToken\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `skipToken`\r\n * option.\r\n */\r\n skipToken(strictCheck) {\r\n return v.string(strictCheck);\r\n },\r\n\r\n /**\r\n * The `enableSsl` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `boolean` validator.\r\n *\r\n * @function enableSsl\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `enableSsl`\r\n * option.\r\n */\r\n enableSsl(strictCheck) {\r\n return v.boolean(strictCheck);\r\n },\r\n\r\n /**\r\n * The `sslForce` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `boolean` validator.\r\n *\r\n * @function sslForce\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `sslForce`\r\n * option.\r\n */\r\n sslForce(strictCheck) {\r\n return v.boolean(strictCheck);\r\n },\r\n\r\n /**\r\n * The `sslPort` validator that returns a Zod schema with an optional stricter\r\n * check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `nonNegativeNum`\r\n * validator.\r\n *\r\n * @function sslPort\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `sslPort`\r\n * option.\r\n */\r\n sslPort(strictCheck) {\r\n return v.nonNegativeNum(strictCheck);\r\n },\r\n\r\n /**\r\n * The `sslCertPath` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `string` validator.\r\n *\r\n * @function sslCertPath\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `sslCertPath`\r\n * option.\r\n */\r\n sslCertPath(strictCheck) {\r\n return v.string(strictCheck);\r\n },\r\n\r\n /**\r\n * The `minWorkers` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `positiveNum` validator.\r\n *\r\n * @function minWorkers\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `minWorkers`\r\n * option.\r\n */\r\n minWorkers(strictCheck) {\r\n return v.positiveNum(strictCheck);\r\n },\r\n\r\n /**\r\n * The `maxWorkers` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `positiveNum` validator.\r\n *\r\n * @function maxWorkers\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `maxWorkers`\r\n * option.\r\n */\r\n maxWorkers(strictCheck) {\r\n return v.positiveNum(strictCheck);\r\n },\r\n\r\n /**\r\n * The `workLimit` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `positiveNum` validator.\r\n *\r\n * @function workLimit\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `workLimit`\r\n * option.\r\n */\r\n workLimit(strictCheck) {\r\n return v.positiveNum(strictCheck);\r\n },\r\n\r\n /**\r\n * The `acquireTimeout` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `nonNegativeNum`\r\n * validator.\r\n *\r\n * @function acquireTimeout\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating\r\n * the `acquireTimeout` option.\r\n */\r\n acquireTimeout(strictCheck) {\r\n return v.nonNegativeNum(strictCheck);\r\n },\r\n\r\n /**\r\n * The `createTimeout` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `nonNegativeNum`\r\n * validator.\r\n *\r\n * @function createTimeout\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating\r\n * the `createTimeout` option.\r\n */\r\n createTimeout(strictCheck) {\r\n return v.nonNegativeNum(strictCheck);\r\n },\r\n\r\n /**\r\n * The `destroyTimeout` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `nonNegativeNum`\r\n * validator.\r\n *\r\n * @function destroyTimeout\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating\r\n * the `destroyTimeout` option.\r\n */\r\n destroyTimeout(strictCheck) {\r\n return v.nonNegativeNum(strictCheck);\r\n },\r\n\r\n /**\r\n * The `idleTimeout` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `nonNegativeNum`\r\n * validator.\r\n *\r\n * @function idleTimeout\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating\r\n * the `idleTimeout` option.\r\n */\r\n idleTimeout(strictCheck) {\r\n return v.nonNegativeNum(strictCheck);\r\n },\r\n\r\n /**\r\n * The `createRetryInterval` validator that returns a Zod schema with\r\n * an optional stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `nonNegativeNum`\r\n * validator.\r\n *\r\n * @function createRetryInterval\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating\r\n * the `createRetryInterval` option.\r\n */\r\n createRetryInterval(strictCheck) {\r\n return v.nonNegativeNum(strictCheck);\r\n },\r\n\r\n /**\r\n * The `reaperInterval` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `nonNegativeNum`\r\n * validator.\r\n *\r\n * @function reaperInterval\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating\r\n * the `reaperInterval` option.\r\n */\r\n reaperInterval(strictCheck) {\r\n return v.nonNegativeNum(strictCheck);\r\n },\r\n\r\n /**\r\n * The `poolBenchmarking` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `boolean` validator.\r\n *\r\n * @function poolBenchmarking\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating\r\n * the `poolBenchmarking` option.\r\n */\r\n poolBenchmarking(strictCheck) {\r\n return v.boolean(strictCheck);\r\n },\r\n\r\n /**\r\n * The `resourcesInterval` validator that returns a Zod schema with\r\n * an optional stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `nonNegativeNum`\r\n * validator.\r\n *\r\n * @function resourcesInterval\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating\r\n * the `resourcesInterval` option.\r\n */\r\n resourcesInterval(strictCheck) {\r\n return v.nonNegativeNum(strictCheck);\r\n },\r\n\r\n /**\r\n * The `logLevel` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures that:\r\n *\r\n * - When `strictCheck` is true, the schema will accept integer number values\r\n * that are between 0 and 5 (inclusive).\r\n *\r\n * - When `strictCheck` is false, the schema will accept integer number values\r\n * and stringified integer number values that are between 1 and 5 (inclusive),\r\n * null, 'undefined', 'null', and '' which will be transformed to null.\r\n *\r\n * @function logLevel\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `logLevel`\r\n * option.\r\n */\r\n logLevel(strictCheck) {\r\n return strictCheck\r\n ? z.number().int().gte(0).lte(5)\r\n : z\r\n .union([\r\n z\r\n .string()\r\n .trim()\r\n .refine(\r\n (value) =>\r\n (!isNaN(Number(value)) &&\r\n value !== true &&\r\n !value.startsWith('[') &&\r\n Number.isInteger(Number(value)) &&\r\n Number(value) >= 0 &&\r\n Number(value) <= 5) ||\r\n ['undefined', 'null', ''].includes(value),\r\n {\r\n params: {\r\n errorMessage: 'The value must be within a 0 and 5 range'\r\n }\r\n }\r\n )\r\n .transform((value) =>\r\n !['undefined', 'null', ''].includes(value)\r\n ? Number(value)\r\n : null\r\n ),\r\n z.number().int().gte(0).lte(5)\r\n ])\r\n .nullable();\r\n },\r\n\r\n /**\r\n * The `logFile` validator that returns a Zod schema with an optional stricter\r\n * check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `string` validator.\r\n * Additionally, it must be a string that ends with '.log'.\r\n *\r\n * @function logFile\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `logFile`\r\n * option.\r\n */\r\n logFile(strictCheck) {\r\n return v\r\n .string(strictCheck)\r\n .refine(\r\n (value) =>\r\n value === null || (value.length >= 5 && value.endsWith('.log')),\r\n {\r\n params: {\r\n errorMessage: 'The value must be a string that ends with .log'\r\n }\r\n }\r\n );\r\n },\r\n\r\n /**\r\n * The `logDest` validator that returns a Zod schema with an optional stricter\r\n * check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `string` validator.\r\n *\r\n * @function logDest\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `logDest`\r\n * option.\r\n */\r\n logDest(strictCheck) {\r\n return v.string(strictCheck);\r\n },\r\n\r\n /**\r\n * The `logToConsole` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `boolean` validator.\r\n *\r\n * @function logToConsole\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating\r\n * the `logToConsole` option.\r\n */\r\n logToConsole(strictCheck) {\r\n return v.boolean(strictCheck);\r\n },\r\n\r\n /**\r\n * The `logToFile` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `boolean` validator.\r\n *\r\n * @function logToFile\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `logToFile`\r\n * option.\r\n */\r\n logToFile(strictCheck) {\r\n return v.boolean(strictCheck);\r\n },\r\n\r\n /**\r\n * The `enableUi` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `boolean` validator.\r\n *\r\n * @function enableUi\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `enableUi`\r\n * option.\r\n */\r\n enableUi(strictCheck) {\r\n return v.boolean(strictCheck);\r\n },\r\n\r\n /**\r\n * The `uiRoute` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `startsWith` validator.\r\n *\r\n * @function uiRoute\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `uiRoute`\r\n * option.\r\n */\r\n uiRoute(strictCheck) {\r\n return v.startsWith(['/'], strictCheck);\r\n },\r\n\r\n /**\r\n * The `nodeEnv` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `enum` validator.\r\n *\r\n * @function nodeEnv\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `nodeEnv`\r\n * option.\r\n */\r\n nodeEnv(strictCheck) {\r\n return v.enum(['development', 'production', 'test'], strictCheck);\r\n },\r\n\r\n /**\r\n * The `listenToProcessExits` validator that returns a Zod schema with\r\n * an optional stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `boolean` validator.\r\n *\r\n * @function listenToProcessExits\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating\r\n * the `listenToProcessExits` option.\r\n */\r\n listenToProcessExits(strictCheck) {\r\n return v.boolean(strictCheck);\r\n },\r\n\r\n /**\r\n * The `noLogo` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `boolean` validator.\r\n *\r\n * @function noLogo\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `noLogo`\r\n * option.\r\n */\r\n noLogo(strictCheck) {\r\n return v.boolean(strictCheck);\r\n },\r\n\r\n /**\r\n * The `hardResetPage` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `boolean` validator.\r\n *\r\n * @function hardResetPage\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating\r\n * the `hardResetPage` option.\r\n */\r\n hardResetPage(strictCheck) {\r\n return v.boolean(strictCheck);\r\n },\r\n\r\n /**\r\n * The `browserShellMode` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `boolean` validator.\r\n *\r\n * @function browserShellMode\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating\r\n * the `browserShellMode` option.\r\n */\r\n browserShellMode(strictCheck) {\r\n return v.boolean(strictCheck);\r\n },\r\n\r\n /**\r\n * The `validation` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `boolean` validator.\r\n *\r\n * @function validation\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `validation`\r\n * option.\r\n */\r\n validation(strictCheck) {\r\n return v.boolean(strictCheck);\r\n },\r\n\r\n /**\r\n * The `enableDebug` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `boolean` validator.\r\n *\r\n * @function enableDebug\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `enableDebug`\r\n * option.\r\n */\r\n enableDebug(strictCheck) {\r\n return v.boolean(strictCheck);\r\n },\r\n\r\n /**\r\n * The `headless` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `boolean` validator.\r\n *\r\n * @function headless\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `headless`\r\n * option.\r\n */\r\n headless(strictCheck) {\r\n return v.boolean(strictCheck);\r\n },\r\n\r\n /**\r\n * The `devtools` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `boolean` validator.\r\n *\r\n * @function devtools\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `devtools`\r\n * option.\r\n */\r\n devtools(strictCheck) {\r\n return v.boolean(strictCheck);\r\n },\r\n\r\n /**\r\n * The `listenToConsole` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `boolean` validator.\r\n *\r\n * @function listenToConsole\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating\r\n * the `listenToConsole` option.\r\n */\r\n listenToConsole(strictCheck) {\r\n return v.boolean(strictCheck);\r\n },\r\n\r\n /**\r\n * The `dumpio` validator that returns a Zod schema with an optional stricter\r\n * check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `boolean` validator.\r\n *\r\n * @function dumpio\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `dumpio`\r\n * option.\r\n */\r\n dumpio(strictCheck) {\r\n return v.boolean(strictCheck);\r\n },\r\n\r\n /**\r\n * The `slowMo` validator that returns a Zod schema with an optional stricter\r\n * check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `nonNegativeNum`\r\n * validator.\r\n *\r\n * @function slowMo\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `slowMo`\r\n * option.\r\n */\r\n slowMo(strictCheck) {\r\n return v.nonNegativeNum(strictCheck);\r\n },\r\n\r\n /**\r\n * The `debuggingPort` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `nonNegativeNum`\r\n * validator.\r\n *\r\n * @function debuggingPort\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating\r\n * the `debuggingPort` option.\r\n */\r\n debuggingPort(strictCheck) {\r\n return v.nonNegativeNum(strictCheck);\r\n },\r\n\r\n /**\r\n * The `requestId` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `string` validator.\r\n * Additionally, it must be a stringified UUID or can be null.\r\n *\r\n * @function requestId\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `requestId`\r\n * option.\r\n */\r\n requestId() {\r\n return z\r\n .string()\r\n .uuid({ message: 'The value must be a stringified UUID' })\r\n .nullable();\r\n }\r\n};\r\n\r\n// Schema for the puppeteer section of options\r\nconst PuppeteerSchema = (strictCheck) =>\r\n z\r\n .object({\r\n args: validators.args(strictCheck)\r\n })\r\n .partial();\r\n\r\n// Schema for the highcharts section of options\r\nconst HighchartsSchema = (strictCheck) =>\r\n z\r\n .object({\r\n version: validators.version(strictCheck),\r\n cdnUrl: validators.cdnUrl(strictCheck),\r\n forceFetch: validators.forceFetch(strictCheck),\r\n cachePath: validators.cachePath(strictCheck),\r\n coreScripts: validators.coreScripts(strictCheck),\r\n moduleScripts: validators.moduleScripts(strictCheck),\r\n indicatorScripts: validators.indicatorScripts(strictCheck),\r\n customScripts: validators.customScripts(strictCheck)\r\n })\r\n .partial();\r\n\r\n// Schema for the export section of options\r\nconst ExportSchema = (strictCheck) =>\r\n z\r\n .object({\r\n infile: validators.infile(strictCheck),\r\n instr: validators.instr(),\r\n options: validators.options(),\r\n svg: validators.svg(),\r\n outfile: validators.outfile(strictCheck),\r\n type: validators.type(strictCheck),\r\n constr: validators.constr(strictCheck),\r\n b64: validators.b64(strictCheck),\r\n noDownload: validators.noDownload(strictCheck),\r\n defaultHeight: validators.defaultHeight(strictCheck),\r\n defaultWidth: validators.defaultWidth(strictCheck),\r\n defaultScale: validators.defaultScale(strictCheck),\r\n height: validators.height(strictCheck),\r\n width: validators.width(strictCheck),\r\n scale: validators.scale(strictCheck),\r\n globalOptions: validators.globalOptions(),\r\n themeOptions: validators.themeOptions(),\r\n batch: validators.batch(false),\r\n rasterizationTimeout: validators.rasterizationTimeout(strictCheck)\r\n })\r\n .partial();\r\n\r\n// Schema for the customLogic section of options\r\nconst CustomLogicSchema = (strictCheck) =>\r\n z\r\n .object({\r\n allowCodeExecution: validators.allowCodeExecution(strictCheck),\r\n allowFileResources: validators.allowFileResources(strictCheck),\r\n customCode: validators.customCode(false),\r\n callback: validators.callback(false),\r\n resources: validators.resources(strictCheck),\r\n loadConfig: validators.loadConfig(false),\r\n createConfig: validators.createConfig(false)\r\n })\r\n .partial();\r\n\r\n// Schema for the server.proxy section of options\r\nconst ProxySchema = (strictCheck) =>\r\n z\r\n .object({\r\n host: validators.proxyHost(false),\r\n port: validators.proxyPort(strictCheck),\r\n timeout: validators.proxyTimeout(strictCheck)\r\n })\r\n .partial();\r\n\r\n// Schema for the server.rateLimiting section of options\r\nconst RateLimitingSchema = (strictCheck) =>\r\n z\r\n .object({\r\n enable: validators.enableRateLimiting(strictCheck),\r\n maxRequests: validators.maxRequests(strictCheck),\r\n window: validators.window(strictCheck),\r\n delay: validators.delay(strictCheck),\r\n trustProxy: validators.trustProxy(strictCheck),\r\n skipKey: validators.skipKey(false),\r\n skipToken: validators.skipToken(false)\r\n })\r\n .partial();\r\n\r\n// Schema for the server.ssl section of options\r\nconst SslSchema = (strictCheck) =>\r\n z\r\n .object({\r\n enable: validators.enableSsl(strictCheck),\r\n force: validators.sslForce(strictCheck),\r\n port: validators.sslPort(strictCheck),\r\n certPath: validators.sslCertPath(false)\r\n })\r\n .partial();\r\n\r\n// Schema for the server section of options\r\nconst ServerSchema = (strictCheck) =>\r\n z.object({\r\n enable: validators.enableServer(strictCheck).optional(),\r\n host: validators.host(strictCheck).optional(),\r\n port: validators.port(strictCheck).optional(),\r\n uploadLimit: validators.uploadLimit(strictCheck).optional(),\r\n benchmarking: validators.serverBenchmarking(strictCheck).optional(),\r\n proxy: ProxySchema(strictCheck).optional(),\r\n rateLimiting: RateLimitingSchema(strictCheck).optional(),\r\n ssl: SslSchema(strictCheck).optional()\r\n });\r\n\r\n// Schema for the pool section of options\r\nconst PoolSchema = (strictCheck) =>\r\n z\r\n .object({\r\n minWorkers: validators.minWorkers(strictCheck),\r\n maxWorkers: validators.maxWorkers(strictCheck),\r\n workLimit: validators.workLimit(strictCheck),\r\n acquireTimeout: validators.acquireTimeout(strictCheck),\r\n createTimeout: validators.createTimeout(strictCheck),\r\n destroyTimeout: validators.destroyTimeout(strictCheck),\r\n idleTimeout: validators.idleTimeout(strictCheck),\r\n createRetryInterval: validators.createRetryInterval(strictCheck),\r\n reaperInterval: validators.reaperInterval(strictCheck),\r\n benchmarking: validators.poolBenchmarking(strictCheck)\r\n })\r\n .partial();\r\n\r\n// Schema for the logging section of options\r\nconst LoggingSchema = (strictCheck) =>\r\n z\r\n .object({\r\n level: validators.logLevel(strictCheck),\r\n file: validators.logFile(strictCheck),\r\n dest: validators.logDest(strictCheck),\r\n toConsole: validators.logToConsole(strictCheck),\r\n toFile: validators.logToFile(strictCheck)\r\n })\r\n .partial();\r\n\r\n// Schema for the ui section of options\r\nconst UiSchema = (strictCheck) =>\r\n z\r\n .object({\r\n enable: validators.enableUi(strictCheck),\r\n route: validators.uiRoute(strictCheck)\r\n })\r\n .partial();\r\n\r\n// Schema for the other section of options\r\nconst OtherSchema = (strictCheck) =>\r\n z\r\n .object({\r\n nodeEnv: validators.nodeEnv(strictCheck),\r\n listenToProcessExits: validators.listenToProcessExits(strictCheck),\r\n noLogo: validators.noLogo(strictCheck),\r\n hardResetPage: validators.hardResetPage(strictCheck),\r\n browserShellMode: validators.browserShellMode(strictCheck),\r\n validation: validators.validation(strictCheck)\r\n })\r\n .partial();\r\n\r\n// Schema for the debug section of options\r\nconst DebugSchema = (strictCheck) =>\r\n z\r\n .object({\r\n enable: validators.enableDebug(strictCheck),\r\n headless: validators.headless(strictCheck),\r\n devtools: validators.devtools(strictCheck),\r\n listenToConsole: validators.listenToConsole(strictCheck),\r\n dumpio: validators.dumpio(strictCheck),\r\n slowMo: validators.slowMo(strictCheck),\r\n debuggingPort: validators.debuggingPort(strictCheck)\r\n })\r\n .partial();\r\n\r\n// Strict schema for the config\r\nexport const StrictConfigSchema = z.object({\r\n requestId: validators.requestId(),\r\n puppeteer: PuppeteerSchema(true),\r\n highcharts: HighchartsSchema(true),\r\n export: ExportSchema(true),\r\n customLogic: CustomLogicSchema(true),\r\n server: ServerSchema(true),\r\n pool: PoolSchema(true),\r\n logging: LoggingSchema(true),\r\n ui: UiSchema(true),\r\n other: OtherSchema(true),\r\n debug: DebugSchema(true)\r\n});\r\n\r\n// Loose schema for the config\r\nexport const LooseConfigSchema = z.object({\r\n requestId: validators.requestId(),\r\n puppeteer: PuppeteerSchema(false),\r\n highcharts: HighchartsSchema(false),\r\n export: ExportSchema(false),\r\n customLogic: CustomLogicSchema(false),\r\n server: ServerSchema(false),\r\n pool: PoolSchema(false),\r\n logging: LoggingSchema(false),\r\n ui: UiSchema(false),\r\n other: OtherSchema(false),\r\n debug: DebugSchema(false)\r\n});\r\n\r\n// Schema for the environment variables config\r\nexport const EnvSchema = z.object({\r\n // puppeteer\r\n PUPPETEER_ARGS: validators.args(false),\r\n\r\n // highcharts\r\n HIGHCHARTS_VERSION: validators.version(false),\r\n HIGHCHARTS_CDN_URL: validators.cdnUrl(false),\r\n HIGHCHARTS_FORCE_FETCH: validators.forceFetch(false),\r\n HIGHCHARTS_CACHE_PATH: validators.cachePath(false),\r\n HIGHCHARTS_ADMIN_TOKEN: validators.adminToken(false),\r\n HIGHCHARTS_CORE_SCRIPTS: validators.coreScripts(false),\r\n HIGHCHARTS_MODULE_SCRIPTS: validators.moduleScripts(false),\r\n HIGHCHARTS_INDICATOR_SCRIPTS: validators.indicatorScripts(false),\r\n HIGHCHARTS_CUSTOM_SCRIPTS: validators.customScripts(false),\r\n\r\n // export\r\n EXPORT_INFILE: validators.infile(false),\r\n EXPORT_INSTR: validators.instr(),\r\n EXPORT_OPTIONS: validators.options(),\r\n EXPORT_SVG: validators.svg(),\r\n EXPORT_BATCH: validators.batch(false),\r\n EXPORT_OUTFILE: validators.outfile(false),\r\n EXPORT_TYPE: validators.type(false),\r\n EXPORT_CONSTR: validators.constr(false),\r\n EXPORT_B64: validators.b64(false),\r\n EXPORT_NO_DOWNLOAD: validators.noDownload(false),\r\n EXPORT_HEIGHT: validators.height(false),\r\n EXPORT_WIDTH: validators.width(false),\r\n EXPORT_SCALE: validators.scale(false),\r\n EXPORT_DEFAULT_HEIGHT: validators.defaultHeight(false),\r\n EXPORT_DEFAULT_WIDTH: validators.defaultWidth(false),\r\n EXPORT_DEFAULT_SCALE: validators.defaultScale(false),\r\n EXPORT_GLOBAL_OPTIONS: validators.globalOptions(),\r\n EXPORT_THEME_OPTIONS: validators.themeOptions(),\r\n EXPORT_RASTERIZATION_TIMEOUT: validators.rasterizationTimeout(false),\r\n\r\n // custom\r\n CUSTOM_LOGIC_ALLOW_CODE_EXECUTION: validators.allowCodeExecution(false),\r\n CUSTOM_LOGIC_ALLOW_FILE_RESOURCES: validators.allowFileResources(false),\r\n CUSTOM_LOGIC_CUSTOM_CODE: validators.customCode(false),\r\n CUSTOM_LOGIC_CALLBACK: validators.callback(false),\r\n CUSTOM_LOGIC_RESOURCES: validators.resources(false),\r\n CUSTOM_LOGIC_LOAD_CONFIG: validators.loadConfig(false),\r\n CUSTOM_LOGIC_CREATE_CONFIG: validators.createConfig(false),\r\n\r\n // server\r\n SERVER_ENABLE: validators.enableServer(false),\r\n SERVER_HOST: validators.host(false),\r\n SERVER_PORT: validators.port(false),\r\n SERVER_UPLOAD_LIMIT: validators.uploadLimit(false),\r\n SERVER_BENCHMARKING: validators.serverBenchmarking(false),\r\n\r\n // server proxy\r\n SERVER_PROXY_HOST: validators.proxyHost(false),\r\n SERVER_PROXY_PORT: validators.proxyPort(false),\r\n SERVER_PROXY_TIMEOUT: validators.proxyTimeout(false),\r\n\r\n // server rate limiting\r\n SERVER_RATE_LIMITING_ENABLE: validators.enableRateLimiting(false),\r\n SERVER_RATE_LIMITING_MAX_REQUESTS: validators.maxRequests(false),\r\n SERVER_RATE_LIMITING_WINDOW: validators.window(false),\r\n SERVER_RATE_LIMITING_DELAY: validators.delay(false),\r\n SERVER_RATE_LIMITING_TRUST_PROXY: validators.trustProxy(false),\r\n SERVER_RATE_LIMITING_SKIP_KEY: validators.skipKey(false),\r\n SERVER_RATE_LIMITING_SKIP_TOKEN: validators.skipToken(false),\r\n\r\n // server ssl\r\n SERVER_SSL_ENABLE: validators.enableSsl(false),\r\n SERVER_SSL_FORCE: validators.sslForce(false),\r\n SERVER_SSL_PORT: validators.sslPort(false),\r\n SERVER_SSL_CERT_PATH: validators.sslCertPath(false),\r\n\r\n // pool\r\n POOL_MIN_WORKERS: validators.minWorkers(false),\r\n POOL_MAX_WORKERS: validators.maxWorkers(false),\r\n POOL_WORK_LIMIT: validators.workLimit(false),\r\n POOL_ACQUIRE_TIMEOUT: validators.acquireTimeout(false),\r\n POOL_CREATE_TIMEOUT: validators.createTimeout(false),\r\n POOL_DESTROY_TIMEOUT: validators.destroyTimeout(false),\r\n POOL_IDLE_TIMEOUT: validators.idleTimeout(false),\r\n POOL_CREATE_RETRY_INTERVAL: validators.createRetryInterval(false),\r\n POOL_REAPER_INTERVAL: validators.reaperInterval(false),\r\n POOL_BENCHMARKING: validators.poolBenchmarking(false),\r\n\r\n // logging\r\n LOGGING_LEVEL: validators.logLevel(false),\r\n LOGGING_FILE: validators.logFile(false),\r\n LOGGING_DEST: validators.logDest(false),\r\n LOGGING_TO_CONSOLE: validators.logToConsole(false),\r\n LOGGING_TO_FILE: validators.logToFile(false),\r\n\r\n // ui\r\n UI_ENABLE: validators.enableUi(false),\r\n UI_ROUTE: validators.uiRoute(false),\r\n\r\n // other\r\n OTHER_NODE_ENV: validators.nodeEnv(false),\r\n OTHER_LISTEN_TO_PROCESS_EXITS: validators.listenToProcessExits(false),\r\n OTHER_NO_LOGO: validators.noLogo(false),\r\n OTHER_HARD_RESET_PAGE: validators.hardResetPage(false),\r\n OTHER_BROWSER_SHELL_MODE: validators.browserShellMode(false),\r\n OTHER_VALIDATION: validators.validation(false),\r\n\r\n // debugger\r\n DEBUG_ENABLE: validators.enableDebug(false),\r\n DEBUG_HEADLESS: validators.headless(false),\r\n DEBUG_DEVTOOLS: validators.devtools(false),\r\n DEBUG_LISTEN_TO_CONSOLE: validators.listenToConsole(false),\r\n DEBUG_DUMPIO: validators.dumpio(false),\r\n DEBUG_SLOW_MO: validators.slowMo(false),\r\n DEBUG_DEBUGGING_PORT: validators.debuggingPort(false)\r\n});\r\n\r\n/**\r\n * Validates the environment variables options using the EnvSchema.\r\n *\r\n * @param {Object} process.env - The configuration options from environment\r\n * variables file to validate.\r\n *\r\n * @returns {Object} The parsed and validated environment variables.\r\n */\r\nexport const envs = EnvSchema.partial().parse(process.env);\r\n\r\n/**\r\n * Validates the configuration options using the `StrictConfigSchema`.\r\n *\r\n * @function strictValidate\r\n *\r\n * @param {Object} configOptions - The configuration options to validate.\r\n *\r\n * @returns {Object} The parsed and validated configuration options.\r\n */\r\nexport function strictValidate(configOptions) {\r\n return StrictConfigSchema.partial().parse(configOptions);\r\n}\r\n\r\n/**\r\n * Validates the configuration options using the `LooseConfigSchema`.\r\n *\r\n * @function looseValidate\r\n *\r\n * @param {Object} configOptions - The configuration options to validate.\r\n *\r\n * @returns {Object} The parsed and validated configuration options.\r\n */\r\nexport function looseValidate(configOptions) {\r\n return LooseConfigSchema.partial().parse(configOptions);\r\n}\r\n\r\n/**\r\n * Custom error mapping function for Zod schema validation.\r\n *\r\n * This function customizes the error messages produced by Zod schema\r\n * validation, providing more specific and user-friendly feedback based on the\r\n * issue type and context.\r\n *\r\n * The function modifies the error messages as follows:\r\n *\r\n * - For missing required values (undefined), it returns a message indicating\r\n * that no value was provided for the specific property.\r\n *\r\n * - For custom validation errors, if a custom error message is provided in the\r\n * issue parameters, it includes this message along with the invalid data\r\n * received.\r\n *\r\n * - For all other errors, it appends property-specific information to the\r\n * default error message provided by Zod.\r\n *\r\n * @function _customErrorMap\r\n *\r\n * @param {z.ZodIssue} issue - The issue object representing the validation\r\n * error.\r\n * @param {Object} context - The context object providing additional information\r\n * about the validation error.\r\n *\r\n * @returns {Object} An object containing the customized error message.\r\n */\r\nfunction _customErrorMap(issue, context) {\r\n // Get the chain of properties which error directly refers to\r\n const propertyName = issue.path.join('.');\r\n\r\n // Create the first part of the message about the property information\r\n const propertyInfo = `Invalid value for the ${propertyName}`;\r\n\r\n // Modified message for the invalid type\r\n if (issue.code === z.ZodIssueCode.invalid_type) {\r\n // Modified message for the required values\r\n if (issue.received === z.ZodParsedType.undefined) {\r\n return {\r\n message: `${propertyInfo} - No value was provided.`\r\n };\r\n }\r\n\r\n // Modified message for the specific invalid type when values exist\r\n return {\r\n message: `${propertyInfo} - Invalid type. ${context.defaultError}.`\r\n };\r\n }\r\n\r\n // Modified message for the custom validation\r\n if (issue.code === z.ZodIssueCode.custom) {\r\n // If the custom message for error exist, include it\r\n if (issue.params?.errorMessage) {\r\n return {\r\n message: `${propertyInfo} - ${issue.params?.errorMessage}, received '${context.data}'.`\r\n };\r\n }\r\n }\r\n\r\n // Modified message for the invalid union error\r\n if (issue.code === z.ZodIssueCode.invalid_union) {\r\n // Create the first part of the message about the multiple errors\r\n let message = `Multiple errors occurred for the ${propertyName}:\\n`;\r\n\r\n // Cycle through all errors and create a correct message\r\n issue.unionErrors.forEach((value) => {\r\n const index = value.issues[0].message.indexOf('-');\r\n message +=\r\n index !== -1\r\n ? `${value.issues[0].message}\\n`.substring(index)\r\n : `${value.issues[0].message}\\n`;\r\n });\r\n\r\n // Return the final message for the invalid union error\r\n return {\r\n message\r\n };\r\n }\r\n\r\n // Return the default error message, extended by the info about the property\r\n return {\r\n message: `${propertyInfo} - ${context.defaultError}.`\r\n };\r\n}\r\n\r\nexport default {\r\n validators,\r\n StrictConfigSchema,\r\n LooseConfigSchema,\r\n EnvSchema,\r\n envs,\r\n strictValidate,\r\n looseValidate\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * A custom error class for handling export-related errors. Extends the native\r\n * `Error` class to include additional properties like status code and stack\r\n * trace details.\r\n */\r\nclass ExportError extends Error {\r\n /**\r\n * Creates an instance of the `ExportError`.\r\n *\r\n * @param {string} message - The error message to be displayed.\r\n * @param {number} statusCode - Optional HTTP status code associated\r\n * with the error (e.g., 400, 500).\r\n */\r\n constructor(message, statusCode) {\r\n super();\r\n\r\n this.message = message;\r\n this.stackMessage = message;\r\n\r\n if (statusCode) {\r\n this.statusCode = statusCode;\r\n }\r\n }\r\n\r\n /**\r\n * Sets or updates the HTTP status code for the error.\r\n *\r\n * @param {number} statusCode - The HTTP status code to assign to the error.\r\n *\r\n * @returns {ExportError} The updated instance of the `ExportError` class.\r\n */\r\n setStatus(statusCode) {\r\n this.statusCode = statusCode;\r\n\r\n return this;\r\n }\r\n\r\n /**\r\n * Sets additional error details based on an existing error object.\r\n *\r\n * @param {Error} error - An error object containing details to populate\r\n * the `ExportError` instance.\r\n *\r\n * @returns {ExportError} The updated instance of the `ExportError` class.\r\n */\r\n setError(error) {\r\n this.error = error;\r\n\r\n if (error.name) {\r\n this.name = error.name;\r\n }\r\n\r\n if (error.statusCode) {\r\n this.statusCode = error.statusCode;\r\n }\r\n\r\n if (error.stack) {\r\n this.stackMessage = error.message;\r\n this.stack = error.stack;\r\n }\r\n\r\n return this;\r\n }\r\n}\r\n\r\nexport default ExportError;\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * @overview Manages configuration for the Highcharts Export Server by loading\r\n * and merging options from multiple sources, such as default settings,\r\n * environment variables, user-provided options, and command-line arguments.\r\n * Ensures the global options are up-to-date with the highest priority values.\r\n * Provides functions for accessing and updating configuration.\r\n */\r\n\r\nimport { readFileSync } from 'fs';\r\nimport { join } from 'path';\r\n\r\nimport { log, logWithStack, logZodIssues } from './logger.js';\r\nimport { __dirname, deepCopy, getAbsolutePath, isObject } from './utils.js';\r\nimport {\r\n envs,\r\n looseValidate,\r\n strictValidate,\r\n validators\r\n} from './validation.js';\r\n\r\nimport { defaultConfig, absoluteProps, nestedProps } from './schemas/config.js';\r\n\r\nimport ExportError from './errors/ExportError.js';\r\n\r\n// Sets the global options with initial values from the default config\r\nconst globalOptions = _initOptions(defaultConfig);\r\n\r\n/**\r\n * Retrieves a copy of the global options object or a reference to the global\r\n * options object, based on the `getCopy` flag.\r\n *\r\n * @function getOptions\r\n *\r\n * @param {boolean} [getCopy=true] - Specifies whether to return a copied\r\n * object of the global options (`true`) or a reference to the global options\r\n * object (`false`). The default value is `false`.\r\n *\r\n * @returns {Object} A copy of the global options object, or a reference\r\n * to the global options object.\r\n */\r\nexport function getOptions(getCopy = true) {\r\n return getCopy ? deepCopy(globalOptions) : globalOptions;\r\n}\r\n\r\n/**\r\n * Updates a copy of the global options object or a reference to the global\r\n * options object, based on the `getCopy` flag.\r\n *\r\n * @function updateOptions\r\n *\r\n * @param {Object} newOptions - An object containing the new options to be\r\n * merged into the global options.\r\n * @param {boolean} [getCopy=false] - Determines whether to merge the new\r\n * options into a copy of the global options object (`true`) or directly into\r\n * the global options object (`false`). The default value is `false`.\r\n *\r\n * @returns {Object} The updated options object, either the modified global\r\n * options or a modified copy, based on the value of `getCopy`.\r\n */\r\nexport function updateOptions(newOptions, getCopy = false) {\r\n // Merge new options to the global options or its copy and return the result\r\n return _mergeOptions(getOptions(getCopy), newOptions);\r\n}\r\n\r\n/**\r\n * Updates the global options with values provided through the CLI, keeping\r\n * the principle of options load priority. This function accepts a `cliArgs`\r\n * array containing arguments from the CLI, which will be validated and applied\r\n * if provided.\r\n *\r\n * The priority order for setting values is:\r\n *\r\n * 1. Values from a custom JSON file (loaded by the `--loadConfig` option).\r\n * 2. Values from the command line interface (CLI).\r\n *\r\n * @function setCliOptions\r\n *\r\n * @param {Array.} cliArgs - An array of command line arguments used\r\n * for additional configuration.\r\n *\r\n * @returns {Object} The updated global options object, reflecting the merged\r\n * configuration from sources provided through the CLI.\r\n */\r\nexport function setCliOptions(cliArgs) {\r\n // Only for the CLI usage\r\n if (cliArgs && Array.isArray(cliArgs) && cliArgs.length) {\r\n try {\r\n // Validate options from the custom JSON loaded via the `--loadConfig`\r\n const configOptions = strictValidate(_loadConfigFile(cliArgs));\r\n\r\n // Update global options with the values from the `configOptions`\r\n updateOptions(configOptions);\r\n } catch (error) {\r\n logZodIssues(\r\n 1,\r\n error.issues,\r\n '[validation] Custom options from the `loadConfig` option validation error'\r\n );\r\n }\r\n\r\n try {\r\n // Validate options from the CLI\r\n const cliOptions = looseValidate(\r\n _pairArgumentValue(nestedProps, cliArgs)\r\n );\r\n\r\n // Update global options with the values from the `cliOptions`\r\n updateOptions(cliOptions);\r\n } catch (error) {\r\n logZodIssues(\r\n 1,\r\n error.issues,\r\n '[validation] CLI options validation error'\r\n );\r\n }\r\n }\r\n\r\n // Return reference to the global options\r\n return getOptions(false);\r\n}\r\n\r\n/**\r\n * Maps old-structured configuration options (PhantomJS) to a new format\r\n * (Puppeteer). This function converts flat, old-structured options into\r\n * a new, nested configuration format based on a predefined mapping\r\n * (`nestedProps`). The new format is used for Puppeteer, while the old format\r\n * was used for PhantomJS.\r\n *\r\n * @function mapToNewOptions\r\n *\r\n * @param {Object} oldOptions - The old, flat configuration options\r\n * to be converted.\r\n *\r\n * @returns {Object} A new object containing options structured according\r\n * to the mapping defined in `nestedProps` or an empty object if the provided\r\n * `oldOptions` is not a correct object.\r\n */\r\nexport function mapToNewOptions(oldOptions) {\r\n // An object for the new structured options\r\n const newOptions = {};\r\n\r\n // Check if provided value is a correct object\r\n if (isObject(oldOptions)) {\r\n // Iterate over each key-value pair in the old-structured options\r\n for (const [key, value] of Object.entries(oldOptions)) {\r\n // If there is a nested mapping, split it into a properties chain\r\n const propertiesChain = nestedProps[key]\r\n ? nestedProps[key].split('.')\r\n : [];\r\n\r\n // If it is the last property in the chain, assign the value, otherwise,\r\n // create or reuse the nested object\r\n propertiesChain.reduce(\r\n (obj, prop, index) =>\r\n (obj[prop] =\r\n propertiesChain.length - 1 === index ? value : obj[prop] || {}),\r\n newOptions\r\n );\r\n }\r\n } else {\r\n log(\r\n 2,\r\n '[config] No correct object with options was provided. Returning an empty array.'\r\n );\r\n }\r\n\r\n // Return the new, structured options object\r\n return newOptions;\r\n}\r\n\r\n/**\r\n * Validates a specified option using the corresponding validator from the\r\n * configuration object. Returns the original option if the validation\r\n * is disabled globally.\r\n *\r\n * @function validateOption\r\n *\r\n * @param {string} name - The name of the option to validate.\r\n * @param {any} configOption - The value of the option to validate.\r\n * @param {boolean} [strictCheck=true] - Determines if stricter validation\r\n * should be applied. The default value is `true`.\r\n *\r\n * @returns {any} The parsed and validated value of the option.\r\n */\r\nexport function validateOption(name, configOption, strictCheck = true) {\r\n // Return the original option if the validation is disabled\r\n if (!getOptions().other.validation) {\r\n return configOption;\r\n }\r\n\r\n try {\r\n // Return validated option\r\n return validators[name](strictCheck).parse(configOption);\r\n } catch (error) {\r\n // Log Zod issues\r\n logZodIssues(\r\n 1,\r\n error.issues,\r\n `[validation] The ${name} option validation error`\r\n );\r\n\r\n // Throw validation error\r\n throw new ExportError(\r\n `[validation] The ${name} option validation error`,\r\n 400\r\n );\r\n }\r\n}\r\n\r\n/**\r\n * Validates the provided configuration options for the exporting process.\r\n * Returns the original option if the validation is disabled globally.\r\n *\r\n * @function validateOptions\r\n *\r\n * @param {Object} configOptions - The configuration options to be validated.\r\n * @param {boolean} [strictCheck=true] - Determines if stricter validation\r\n * should be applied. The default value is `true`.\r\n *\r\n * @returns {Object} The parsed and validated configuration options object.\r\n */\r\nexport function validateOptions(configOptions, strictCheck = true) {\r\n // Return the original config if the validation is disabled\r\n if (!getOptions().other.validation) {\r\n return configOptions;\r\n }\r\n\r\n try {\r\n // Return validated options\r\n return strictCheck\r\n ? strictValidate(configOptions)\r\n : looseValidate(configOptions);\r\n } catch (error) {\r\n // Log Zod issues\r\n logZodIssues(1, error.issues, '[validation] Options validation error');\r\n\r\n // Throw validation error\r\n throw new ExportError('[validation] Options validation error', 400);\r\n }\r\n}\r\n\r\n/**\r\n * Validates, parses, and checks if the provided config is allowed set\r\n * of options.\r\n *\r\n * @function isAllowedConfig\r\n *\r\n * @param {unknown} config - The config to be validated and parsed as a set\r\n * of options. Must be either an object or a string.\r\n * @param {boolean} [toString=false] - Whether to return a stringified version\r\n * of the parsed config. The default value is `false`.\r\n * @param {boolean} [allowFunctions=false] - Whether to allow functions\r\n * in the parsed config. If true, functions are preserved. Otherwise, when\r\n * a function is found, null is returned. The default value is `false`.\r\n *\r\n * @returns {(Object|string|null)} Returns a parsed set of options object,\r\n * a stringified set of options object if the `toString` is true, and null\r\n * if the config is not a valid set of options or parsing fails.\r\n */\r\nexport function isAllowedConfig(\r\n config,\r\n toString = false,\r\n allowFunctions = false\r\n) {\r\n try {\r\n // Accept only objects and strings\r\n if (!isObject(config) && typeof config !== 'string') {\r\n // Return null if any other type\r\n return null;\r\n }\r\n\r\n // Get the object representation of the original config\r\n const objectConfig =\r\n typeof config === 'string'\r\n ? allowFunctions\r\n ? eval(`(${config})`)\r\n : JSON.parse(config)\r\n : config;\r\n\r\n // Preserve or remove potential functions based on the `allowFunctions` flag\r\n const stringifiedOptions = _optionsStringify(\r\n objectConfig,\r\n allowFunctions,\r\n false\r\n );\r\n\r\n // Parse the config to check if it is valid set of options\r\n const parsedOptions = allowFunctions\r\n ? JSON.parse(\r\n _optionsStringify(objectConfig, allowFunctions, true),\r\n (_, value) =>\r\n typeof value === 'string' && value.startsWith('function')\r\n ? eval(`(${value})`)\r\n : value\r\n )\r\n : JSON.parse(stringifiedOptions);\r\n\r\n // Return stringified or object options based on the `toString` flag\r\n return toString ? stringifiedOptions : parsedOptions;\r\n } catch (error) {\r\n // Return null if parsing fails\r\n return null;\r\n }\r\n}\r\n\r\n/**\r\n * Prints the Highcharts Export Server logo, version, and license information.\r\n *\r\n * @function printLicense\r\n */\r\nexport function printLicense() {\r\n // Print the logo and version information\r\n printVersion();\r\n\r\n // Print the license information\r\n console.log(\r\n 'This software requires a valid Highcharts license for commercial use.\\n'\r\n .yellow,\r\n '\\nFor a full list of CLI options, type:',\r\n '\\nhighcharts-export-server --help\\n'.green,\r\n '\\nIf you do not have a license, one can be obtained here:',\r\n '\\nhttps://shop.highsoft.com/\\n'.green,\r\n '\\nTo customize your installation, please refer to the README file at:',\r\n '\\nhttps://github.com/highcharts/node-export-server#readme\\n'.green\r\n );\r\n}\r\n\r\n/**\r\n * Prints usage information for CLI arguments, displaying available options\r\n * and their descriptions. It can list properties recursively if categories\r\n * contain nested options.\r\n *\r\n * @function printUsage\r\n */\r\nexport function printUsage() {\r\n // Display README and general usage information\r\n console.log(\r\n '\\nUsage of CLI arguments:'.bold,\r\n '\\n-----------------------',\r\n `\\nFor more detailed information, visit the README file at: ${'https://github.com/highcharts/node-export-server#readme'.green}.\\n`\r\n );\r\n\r\n // Iterate through each category in the `defaultConfig` and display usage info\r\n Object.keys(defaultConfig).forEach((category) => {\r\n console.log(`${category.toUpperCase()}`.bold.red);\r\n _cycleCategories(defaultConfig[category]);\r\n console.log('');\r\n });\r\n}\r\n\r\n/**\r\n * Prints the Highcharts Export Server logo or text with the version\r\n * information.\r\n *\r\n * @function printVersion\r\n *\r\n * @param {boolean} [noLogo=false] - If true, only prints text with the version\r\n * information, without the logo. The default value is `false`.\r\n */\r\nexport function printVersion(noLogo = false) {\r\n // Get package version either from `.env` or from `package.json`\r\n const packageVersion = JSON.parse(\r\n readFileSync(join(__dirname, 'package.json'), 'utf8')\r\n ).version;\r\n\r\n // Print text only\r\n if (noLogo) {\r\n console.log(`Highcharts Export Server v${packageVersion}`);\r\n } else {\r\n // Print the logo\r\n console.log(\r\n readFileSync(join(__dirname, 'msg', 'startup.msg'), 'utf8').toString()\r\n .bold.yellow,\r\n `v${packageVersion}\\n`.bold\r\n );\r\n }\r\n}\r\n\r\n/**\r\n * Initializes and returns the global options object based on the provided\r\n * configuration, setting values from nested properties recursively.\r\n *\r\n * The priority order for setting values is:\r\n *\r\n * 1. Values from the `./lib/schemas/config.js` file (defaults).\r\n * 2. Values from environment variables (specified in the `.env` file).\r\n *\r\n * @function _initOptions\r\n *\r\n * @param {Object} config - The configuration object used for initializing\r\n * the global options. It should include nested properties with a `value`\r\n * and an `envLink` for linking to environment variables.\r\n *\r\n * @returns {Object} The initialized global options object, populated with\r\n * values based on the provided configuration and the established priority\r\n * order.\r\n */\r\nfunction _initOptions(config) {\r\n // Init the object for options\r\n const options = {};\r\n\r\n // Start initializing the `options` object recursively\r\n for (const [name, item] of Object.entries(config)) {\r\n if (Object.prototype.hasOwnProperty.call(item, 'value')) {\r\n // Set the correct value based on the established priority order\r\n if (envs[item.envLink] !== undefined && envs[item.envLink] !== null) {\r\n // The environment variables value\r\n options[name] = envs[item.envLink];\r\n } else {\r\n // The value from the config file\r\n options[name] = item.value;\r\n }\r\n } else {\r\n // Create a section in the options\r\n options[name] = _initOptions(item);\r\n }\r\n }\r\n\r\n // Return the created `options` object\r\n return options;\r\n}\r\n\r\n/**\r\n * Merges two sets of configuration options, considering absolute properties.\r\n *\r\n * @function _mergeOptions\r\n *\r\n * @param {Object} originalOptions - Original configuration options.\r\n * @param {Object} newOptions - New configuration options to be merged.\r\n *\r\n * @returns {Object} Merged configuration options.\r\n */\r\nexport function _mergeOptions(originalOptions, newOptions) {\r\n // Check if the `originalOptions` and `newOptions` are correct objects\r\n if (isObject(originalOptions) && isObject(newOptions)) {\r\n for (const [key, value] of Object.entries(newOptions)) {\r\n originalOptions[key] =\r\n isObject(value) &&\r\n !absoluteProps.includes(key) &&\r\n originalOptions[key] !== undefined\r\n ? _mergeOptions(originalOptions[key], value)\r\n : value !== undefined\r\n ? value\r\n : originalOptions[key] || null;\r\n }\r\n }\r\n\r\n // Return the original (modified or not) options\r\n return originalOptions;\r\n}\r\n\r\n/**\r\n * Converts the provided options object to a JSON-formatted string\r\n * with the option to preserve functions. In order for a function\r\n * to be preserved, it needs to follow the format `function (...) {...}`.\r\n * Such a function can also be stringified.\r\n *\r\n * @function _optionsStringify\r\n *\r\n * @param {Object} options - The options object to be converted to a string.\r\n * @param {boolean} allowFunctions - If set to true, functions are preserved\r\n * in the output. Otherwise an error is thrown.\r\n * @param {boolean} stringifyFunctions - If set to true, functions are saved\r\n * as strings. The `allowFunctions` must be set to true as well for this to take\r\n * an effect.\r\n *\r\n * @returns {string} The JSON-formatted string representing the options.\r\n *\r\n * @throws {Error} Throws an `Error` when functions are not allowed but are\r\n * found in provided options object.\r\n */\r\nexport function _optionsStringify(options, allowFunctions, stringifyFunctions) {\r\n const replacerCallback = (_, value) => {\r\n // Trim string values\r\n if (typeof value === 'string') {\r\n value = value.trim();\r\n }\r\n\r\n // If value is a function or stringified function\r\n if (\r\n typeof value === 'function' ||\r\n (typeof value === 'string' &&\r\n value.startsWith('function') &&\r\n value.endsWith('}'))\r\n ) {\r\n // If allowFunctions is set to true, preserve functions\r\n if (allowFunctions) {\r\n // Based on the `stringifyFunctions` options, set function values\r\n return stringifyFunctions\r\n ? // As stringified functions\r\n `\"EXP_FUN${(value + '').replaceAll(/\\s+/g, ' ')}EXP_FUN\"`\r\n : // As functions\r\n `EXP_FUN${(value + '').replaceAll(/\\s+/g, ' ')}EXP_FUN`;\r\n } else {\r\n // Throw an error otherwise\r\n throw new Error();\r\n }\r\n }\r\n\r\n // In all other cases, simply return the value\r\n return value;\r\n };\r\n\r\n // Stringify options and if required, replace special functions marks\r\n return JSON.stringify(options, replacerCallback).replaceAll(\r\n stringifyFunctions ? /\\\\\"EXP_FUN|EXP_FUN\\\\\"/g : /\"EXP_FUN|EXP_FUN\"/g,\r\n ''\r\n );\r\n}\r\n\r\n/**\r\n * Loads additional configuration from a specified file provided via\r\n * the `--loadConfig` option in the command-line arguments.\r\n *\r\n * @function _loadConfigFile\r\n *\r\n * @param {Array.} cliArgs - Command-line arguments to search\r\n * for the `--loadConfig` option and the corresponding file path.\r\n *\r\n * @returns {Object} The additional configuration loaded from the specified\r\n * file, or an empty object if the file is not found, invalid, or an error\r\n * occurs.\r\n */\r\nfunction _loadConfigFile(cliArgs) {\r\n // Get the allow flags for the custom logic check\r\n const { allowCodeExecution, allowFileResources } = getOptions().customLogic;\r\n\r\n // Check if the `--loadConfig` option was used\r\n const configIndex = cliArgs.findIndex(\r\n (arg) => arg.replace(/-/g, '') === 'loadConfig'\r\n );\r\n\r\n // Get the `--loadConfig` option value\r\n const configFileName = configIndex > -1 && cliArgs[configIndex + 1];\r\n\r\n // Check if the `--loadConfig` is present and has a correct value\r\n if (configFileName && allowFileResources) {\r\n try {\r\n // Load an optional custom JSON config file\r\n return isAllowedConfig(\r\n readFileSync(getAbsolutePath(configFileName), 'utf8'),\r\n false,\r\n allowCodeExecution\r\n );\r\n } catch (error) {\r\n logWithStack(\r\n 2,\r\n error,\r\n `[config] Unable to load the configuration from the ${configFileName} file.`\r\n );\r\n }\r\n }\r\n\r\n // No additional options to return\r\n return {};\r\n}\r\n\r\n/**\r\n * Parses command-line arguments and pairs each argument with its corresponding\r\n * option in the configuration. The values are structured into a nested options\r\n * object, based on predefined mappings.\r\n *\r\n * @function _pairArgumentValue\r\n *\r\n * @param {Array.} nestedProps - An array of nesting level for all\r\n * options.\r\n * @param {Array.} cliArgs - An array of command-line arguments\r\n * containing options and their associated values.\r\n *\r\n * @returns {Object} An updated options object where each option from\r\n * the command-line is paired with its value, structured into nested objects\r\n * as defined.\r\n */\r\nfunction _pairArgumentValue(nestedProps, cliArgs) {\r\n // An empty object to collect and structurize data from the args\r\n const cliOptions = {};\r\n\r\n // Cycle through all CLI args and filter them\r\n for (let i = 0; i < cliArgs.length; i++) {\r\n const option = cliArgs[i].replace(/-/g, '');\r\n\r\n // Find the right place for property's value\r\n const propertiesChain = nestedProps[option]\r\n ? nestedProps[option].split('.')\r\n : [];\r\n\r\n // Create options object with values from CLI for later parsing and merging\r\n propertiesChain.reduce((obj, prop, index) => {\r\n if (propertiesChain.length - 1 === index) {\r\n const value = cliArgs[++i];\r\n if (!value) {\r\n log(\r\n 2,\r\n `[config] Missing value for the CLI '--${option}' argument. Using the default value.`\r\n );\r\n }\r\n obj[prop] = value || null;\r\n } else if (obj[prop] === undefined) {\r\n obj[prop] = {};\r\n }\r\n return obj[prop];\r\n }, cliOptions);\r\n }\r\n\r\n // Return parsed CLI options\r\n return cliOptions;\r\n}\r\n\r\n/**\r\n * Recursively traverses the options object to print the usage information\r\n * for each option category and individual option.\r\n *\r\n * @function _cycleCategories\r\n *\r\n * @param {Object} options - The options object containing CLI options. It may\r\n * include nested categories and individual options.\r\n */\r\nfunction _cycleCategories(options) {\r\n for (const [name, option] of Object.entries(options)) {\r\n // If the current entry is a category and not a leaf option, recurse into it\r\n if (!Object.prototype.hasOwnProperty.call(option, 'value')) {\r\n _cycleCategories(option);\r\n } else {\r\n // Prepare description\r\n const descName = ` --${option.cliName || name}`;\r\n\r\n // Get the value\r\n let optionValue = option.value;\r\n\r\n // Prepare value for option that is not null and is array of strings\r\n if (optionValue !== null && option.types.includes('string[]')) {\r\n optionValue =\r\n '[' + optionValue.map((item) => `'${item}'`).join(', ') + ']';\r\n }\r\n\r\n // Prepare value for option that is not null and is a string\r\n if (optionValue !== null && option.types.includes('string')) {\r\n optionValue = `'${optionValue}'`;\r\n }\r\n\r\n // Display correctly aligned messages\r\n console.log(\r\n descName.green,\r\n `${('<' + option.types.join('|') + '>').yellow}`,\r\n `${String(optionValue).bold}`.blue,\r\n `- ${option.description}.`\r\n );\r\n }\r\n }\r\n}\r\n\r\nexport default {\r\n getOptions,\r\n updateOptions,\r\n setCliOptions,\r\n mapToNewOptions,\r\n validateOption,\r\n validateOptions,\r\n isAllowedConfig,\r\n printLicense,\r\n printUsage,\r\n printVersion\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * @overview HTTP utility module for fetching and posting data. Supports both\r\n * HTTP and HTTPS protocols, providing methods to make GET and POST requests\r\n * with customizable options. Includes protocol determination based on URL\r\n * and augments response objects with a 'text' property for easier data access.\r\n */\r\n\r\nimport http from 'http';\r\nimport https from 'https';\r\n\r\n/**\r\n * Fetches data from the specified URL using either HTTP or HTTPS protocol.\r\n *\r\n * @async\r\n * @function fetch\r\n *\r\n * @param {string} url - The URL to fetch data from.\r\n * @param {Object} [requestOptions={}] - Options for the HTTP/HTTPS request.\r\n * The default value is an empty object.\r\n *\r\n * @returns {Promise} A Promise that resolves to the HTTP/HTTPS response\r\n * object with added 'text' property or rejecting with an error.\r\n */\r\nexport async function fetch(url, requestOptions = {}) {\r\n return new Promise((resolve, reject) => {\r\n _getProtocolModule(url)\r\n .get(url, requestOptions, (response) => {\r\n let responseData = '';\r\n\r\n // A chunk of data has been received\r\n response.on('data', (chunk) => {\r\n responseData += chunk;\r\n });\r\n\r\n // The whole response has been received\r\n response.on('end', () => {\r\n if (!responseData) {\r\n reject('Nothing was fetched from the URL.');\r\n }\r\n response.text = responseData;\r\n resolve(response);\r\n });\r\n })\r\n .on('error', (error) => {\r\n reject(error);\r\n });\r\n });\r\n}\r\n\r\n/**\r\n * Sends a POST request to the specified URL with the provided JSON body using\r\n * either HTTP or HTTPS protocol.\r\n *\r\n * @async\r\n * @function post\r\n *\r\n * @param {string} url - The URL to send the POST request to.\r\n * @param {Object} [body={}] - The JSON body to include in the POST request.\r\n * The default value is an empty object.\r\n * @param {Object} [requestOptions={}] - Options for the HTTP/HTTPS request.\r\n * The default value is an empty object.\r\n *\r\n * @returns {Promise} A Promise that resolves to the HTTP/HTTPS response\r\n * object with added 'text' property or rejecting with an error.\r\n */\r\nexport async function post(url, body = {}, requestOptions = {}) {\r\n return new Promise((resolve, reject) => {\r\n const data = JSON.stringify(body);\r\n\r\n // Set default headers and merge with requestOptions\r\n const options = Object.assign(\r\n {\r\n method: 'POST',\r\n headers: {\r\n 'Content-Type': 'application/json',\r\n 'Content-Length': data.length\r\n }\r\n },\r\n requestOptions\r\n );\r\n\r\n const request = _getProtocolModule(url)\r\n .request(url, options, (response) => {\r\n let responseData = '';\r\n\r\n // A chunk of data has been received\r\n response.on('data', (chunk) => {\r\n responseData += chunk;\r\n });\r\n\r\n // The whole response has been received\r\n response.on('end', () => {\r\n try {\r\n response.text = responseData;\r\n resolve(response);\r\n } catch (error) {\r\n reject(error);\r\n }\r\n });\r\n })\r\n .on('error', (error) => {\r\n reject(error);\r\n });\r\n\r\n // Write the request body and end the request\r\n request.write(data);\r\n request.end();\r\n });\r\n}\r\n\r\n/**\r\n * Returns the HTTP or HTTPS protocol module based on the provided URL.\r\n *\r\n * @function _getProtocolModule\r\n *\r\n * @param {string} url - The URL to determine the protocol.\r\n *\r\n * @returns {Object} The HTTP or HTTPS protocol module (http or https).\r\n */\r\nfunction _getProtocolModule(url) {\r\n return url.startsWith('https') ? https : http;\r\n}\r\n\r\nexport default {\r\n fetch,\r\n post\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * @overview The cache manager is responsible for handling and managing\r\n * the Highcharts library along with its dependencies. It ensures that these\r\n * resources are stored and retrieved efficiently to optimize performance\r\n * and reduce redundant network requests. The cache is stored in the `.cache`\r\n * directory by default, which serves as a dedicated folder for keeping cached\r\n * files.\r\n */\r\n\r\nimport { existsSync, mkdirSync, readFileSync, writeFileSync } from 'fs';\r\nimport { join } from 'path';\r\n\r\nimport { HttpsProxyAgent } from 'https-proxy-agent';\r\n\r\nimport { getOptions, updateOptions } from './config.js';\r\nimport { fetch } from './fetch.js';\r\nimport { log } from './logger.js';\r\nimport { getAbsolutePath } from './utils.js';\r\n\r\nimport ExportError from './errors/ExportError.js';\r\n\r\n// The initial cache template\r\nconst cache = {\r\n cdnUrl: 'https://code.highcharts.com',\r\n activeManifest: {},\r\n sources: '',\r\n hcVersion: ''\r\n};\r\n\r\n/**\r\n * Checks the cache for Highcharts dependencies, updates the cache if needed,\r\n * and loads the sources.\r\n *\r\n * @async\r\n * @function checkAndUpdateCache\r\n *\r\n * @param {Object} highchartsOptions - The configuration object containing\r\n * `highcharts` options.\r\n * @param {Object} serverProxyOptions- The configuration object containing\r\n * `server.proxy` options.\r\n */\r\nexport async function checkAndUpdateCache(\r\n highchartsOptions,\r\n serverProxyOptions\r\n) {\r\n try {\r\n let fetchedModules;\r\n\r\n // Get the cache path\r\n const cachePath = getCachePath();\r\n\r\n // Prepare paths to manifest and sources from the cache folder\r\n const manifestPath = join(cachePath, 'manifest.json');\r\n const sourcePath = join(cachePath, 'sources.js');\r\n\r\n // Create the cache destination if it doesn't exist already\r\n !existsSync(cachePath) && mkdirSync(cachePath, { recursive: true });\r\n\r\n // Fetch all the scripts either if the `manifest.json` does not exist\r\n // or if the `forceFetch` option is enabled\r\n if (!existsSync(manifestPath) || highchartsOptions.forceFetch) {\r\n log(3, '[cache] Fetching and caching Highcharts dependencies.');\r\n fetchedModules = await _updateCache(\r\n highchartsOptions,\r\n serverProxyOptions,\r\n sourcePath\r\n );\r\n } else {\r\n let requestUpdate = false;\r\n\r\n // Read the manifest JSON\r\n const manifest = JSON.parse(readFileSync(manifestPath), 'utf8');\r\n\r\n // Check if the modules is an array, if so, we rewrite it to a map to make\r\n // it easier to resolve modules.\r\n if (manifest.modules && Array.isArray(manifest.modules)) {\r\n const moduleMap = {};\r\n manifest.modules.forEach((m) => (moduleMap[m] = 1));\r\n manifest.modules = moduleMap;\r\n }\r\n\r\n // Get the actual number of scripts to be fetched\r\n const { coreScripts, moduleScripts, indicatorScripts } =\r\n highchartsOptions;\r\n const numberOfModules =\r\n coreScripts.length + moduleScripts.length + indicatorScripts.length;\r\n\r\n // Compare the loaded highcharts config with the contents in cache.\r\n // If there are changes, fetch requested modules and products,\r\n // and bake them into a giant blob. Save the blob.\r\n if (manifest.version !== highchartsOptions.version) {\r\n log(\r\n 2,\r\n '[cache] A Highcharts version mismatch in the cache, need to re-fetch.'\r\n );\r\n requestUpdate = true;\r\n } else if (\r\n Object.keys(manifest.modules || {}).length !== numberOfModules\r\n ) {\r\n log(\r\n 2,\r\n '[cache] The cache and the requested modules do not match, need to re-fetch.'\r\n );\r\n requestUpdate = true;\r\n } else {\r\n // Check each module, if anything is missing refetch everything\r\n requestUpdate = (moduleScripts || []).some((moduleName) => {\r\n if (!manifest.modules[moduleName]) {\r\n log(\r\n 2,\r\n `[cache] The ${moduleName} is missing in the cache, need to re-fetch.`\r\n );\r\n return true;\r\n }\r\n });\r\n }\r\n\r\n // Update cache if needed\r\n if (requestUpdate) {\r\n fetchedModules = await _updateCache(\r\n highchartsOptions,\r\n serverProxyOptions,\r\n sourcePath\r\n );\r\n } else {\r\n log(3, '[cache] Dependency cache is up to date, proceeding.');\r\n\r\n // Load the sources\r\n cache.sources = readFileSync(sourcePath, 'utf8');\r\n\r\n // Get current modules map\r\n fetchedModules = manifest.modules;\r\n\r\n // Extract and save version of currently used Highcharts\r\n cache.hcVersion = extractVersion(cache.sources);\r\n }\r\n }\r\n\r\n // Finally, save the new manifest, which is basically our current config\r\n // in a slightly different format\r\n await _saveConfigToManifest(highchartsOptions, fetchedModules);\r\n } catch (error) {\r\n throw new ExportError(\r\n '[cache] Could not configure cache and create or update the config manifest.',\r\n 500\r\n ).setError(error);\r\n }\r\n}\r\n\r\n/**\r\n * Gets the version of Highcharts from the cache.\r\n *\r\n * @function getHighchartsVersion\r\n *\r\n * @returns {string} The cached Highcharts version.\r\n */\r\nexport function getHighchartsVersion() {\r\n return cache.hcVersion;\r\n}\r\n\r\n/**\r\n * Updates the Highcharts version in the applied configuration and checks\r\n * the cache for the new version.\r\n *\r\n * @async\r\n * @function updateHighchartsVersion\r\n *\r\n * @param {string} newVersion - The new Highcharts version to be applied.\r\n */\r\nexport async function updateHighchartsVersion(newVersion) {\r\n // Update to the new version\r\n const options = updateOptions({\r\n highcharts: {\r\n version: newVersion\r\n }\r\n });\r\n\r\n // Check if cache needs to be updated\r\n await checkAndUpdateCache(options.highcharts, options.server.proxy);\r\n}\r\n\r\n/**\r\n * Extracts Highcharts version from the cache's sources string.\r\n *\r\n * @function extractVersion\r\n *\r\n * @param {Object} cacheSources - The cache sources object.\r\n *\r\n * @returns {string} The extracted Highcharts version.\r\n */\r\nexport function extractVersion(cacheSources) {\r\n return cacheSources\r\n .substring(0, cacheSources.indexOf('*/'))\r\n .replace('/*', '')\r\n .replace('*/', '')\r\n .replace(/\\n/g, '')\r\n .trim();\r\n}\r\n\r\n/**\r\n * Extracts the Highcharts module name based on the scriptPath.\r\n *\r\n * @function extractModuleName\r\n *\r\n * @param {string} scriptPath - The path of the script from which the module\r\n * name will be extracted.\r\n *\r\n * @returns {string} The extracted module name.\r\n */\r\nexport function extractModuleName(scriptPath) {\r\n return scriptPath.replace(\r\n /(.*)\\/|(.*)modules\\/|stock\\/(.*)indicators\\/|maps\\/(.*)modules\\//gi,\r\n ''\r\n );\r\n}\r\n\r\n/**\r\n * Retrieves the current cache object.\r\n *\r\n * @function getCache\r\n *\r\n * @returns {Object} The cache object containing various cached data.\r\n */\r\nexport function getCache() {\r\n return cache;\r\n}\r\n\r\n/**\r\n * Gets the cache path for Highcharts.\r\n *\r\n * @function getCachePath\r\n *\r\n * @returns {string} The absolute path to the cache directory for Highcharts.\r\n */\r\nexport function getCachePath() {\r\n return getAbsolutePath(getOptions().highcharts.cachePath, 'utf8'); // #562\r\n}\r\n\r\n/**\r\n * Fetches a single script and updates the `fetchedModules` accordingly.\r\n *\r\n * @async\r\n * @function _fetchAndProcessScript\r\n *\r\n * @param {string} script - A path to script to get.\r\n * @param {Object} requestOptions - Additional options for the proxy agent\r\n * to use for a request.\r\n * @param {Object} fetchedModules - An object which tracks which Highcharts\r\n * modules have been fetched.\r\n * @param {boolean} [shouldThrowError=false] - A flag to indicate if the error\r\n * should be thrown. This should be used only for the core scripts. The default\r\n * value is `false`.\r\n *\r\n * @returns {Promise} A Promise that resolves to the text representation\r\n * of the fetched script.\r\n *\r\n * @throws {ExportError} Throws an `ExportError` if there is a problem\r\n * with fetching the script.\r\n */\r\nasync function _fetchAndProcessScript(\r\n script,\r\n requestOptions,\r\n fetchedModules,\r\n shouldThrowError = false\r\n) {\r\n // Get rid of the .js from the custom strings\r\n if (script.endsWith('.js')) {\r\n script = script.substring(0, script.length - 3);\r\n }\r\n log(4, `[cache] Fetching script - ${script}.js`);\r\n\r\n // Fetch the script\r\n const response = await fetch(`${script}.js`, requestOptions);\r\n\r\n // If OK, return its text representation\r\n if (response.statusCode === 200 && typeof response.text == 'string') {\r\n if (fetchedModules) {\r\n const moduleName = extractModuleName(script);\r\n fetchedModules[moduleName] = 1;\r\n }\r\n return response.text;\r\n }\r\n\r\n // Based on the `shouldThrowError` flag, decide how to serve error message\r\n if (shouldThrowError) {\r\n throw new ExportError(\r\n `[cache] Could not fetch the ${script}.js. The script might not exist in the requested version (status code: ${response.statusCode}).`,\r\n 404\r\n ).setError(response);\r\n } else {\r\n log(\r\n 2,\r\n `[cache] Could not fetch the ${script}.js. The script might not exist in the requested version.`\r\n );\r\n }\r\n}\r\n\r\n/**\r\n * Saves the provided configuration and fetched modules to the cache manifest\r\n * file.\r\n *\r\n * @async\r\n * @function _saveConfigToManifest\r\n *\r\n * @param {Object} highchartsOptions - The configuration object containing\r\n * `highcharts` options.\r\n * @param {Object} [fetchedModules={}] - An object which tracks which Highcharts\r\n * modules have been fetched. The default value is an empty object.\r\n *\r\n * @throws {ExportError} Throws an `ExportError` if an error occurs while\r\n * writing the cache manifest.\r\n */\r\nasync function _saveConfigToManifest(highchartsOptions, fetchedModules = {}) {\r\n const newManifest = {\r\n version: highchartsOptions.version,\r\n modules: fetchedModules\r\n };\r\n\r\n // Update cache object with the current modules\r\n cache.activeManifest = newManifest;\r\n\r\n log(3, '[cache] Writing a new manifest.');\r\n try {\r\n writeFileSync(\r\n join(getCachePath(), 'manifest.json'),\r\n JSON.stringify(newManifest),\r\n 'utf8'\r\n );\r\n } catch (error) {\r\n throw new ExportError(\r\n '[cache] Error writing the cache manifest.',\r\n 500\r\n ).setError(error);\r\n }\r\n}\r\n\r\n/**\r\n * Fetches Highcharts `scripts` and `customScripts` from the given CDNs.\r\n *\r\n * @async\r\n * @function _fetchScripts\r\n *\r\n * @param {Array.} coreScripts - Highcharts core scripts to fetch.\r\n * @param {Array.} moduleScripts - Highcharts modules to fetch.\r\n * @param {Array.} customScripts - Custom script paths to fetch (full\r\n * URLs).\r\n * @param {Object} serverProxyOptions - The configuration object containing\r\n * `server.proxy` options.\r\n * @param {Object} fetchedModules - An object which tracks which Highcharts\r\n * modules have been fetched.\r\n *\r\n * @returns {Promise} A Promise that resolves to the fetched scripts\r\n * content joined.\r\n *\r\n * @throws {ExportError} Throws an `ExportError` if an error occurs while\r\n * setting an HTTP Agent for proxy.\r\n */\r\nasync function _fetchScripts(\r\n coreScripts,\r\n moduleScripts,\r\n customScripts,\r\n serverProxyOptions,\r\n fetchedModules\r\n) {\r\n // Configure proxy if exists\r\n let proxyAgent;\r\n const proxyHost = serverProxyOptions.host;\r\n const proxyPort = serverProxyOptions.port;\r\n\r\n // Try to create a Proxy Agent\r\n if (proxyHost && proxyPort) {\r\n try {\r\n proxyAgent = new HttpsProxyAgent({\r\n host: proxyHost,\r\n port: proxyPort\r\n });\r\n } catch (error) {\r\n throw new ExportError(\r\n '[cache] Could not create a Proxy Agent.',\r\n 500\r\n ).setError(error);\r\n }\r\n }\r\n\r\n // If exists, add proxy agent to request options\r\n const requestOptions = proxyAgent\r\n ? {\r\n agent: proxyAgent,\r\n timeout: serverProxyOptions.timeout\r\n }\r\n : {};\r\n\r\n const allFetchPromises = [\r\n ...coreScripts.map((script) =>\r\n _fetchAndProcessScript(`${script}`, requestOptions, fetchedModules, true)\r\n ),\r\n ...moduleScripts.map((script) =>\r\n _fetchAndProcessScript(`${script}`, requestOptions, fetchedModules)\r\n ),\r\n ...customScripts.map((script) =>\r\n _fetchAndProcessScript(`${script}`, requestOptions)\r\n )\r\n ];\r\n\r\n const fetchedScripts = await Promise.all(allFetchPromises);\r\n return fetchedScripts.join(';\\n');\r\n}\r\n\r\n/**\r\n * Updates the local cache with Highcharts scripts and their versions.\r\n *\r\n * @async\r\n * @function _updateCache\r\n *\r\n * @param {Object} highchartsOptions - The configuration object containing\r\n * `highcharts` options.\r\n * @param {Object} serverProxyOptions - The configuration object containing\r\n * `server.proxy` options.\r\n * @param {string} sourcePath - The path to the source file in the cache.\r\n *\r\n * @returns {Promise} A Promise that resolves to an object representing\r\n * the fetched modules.\r\n *\r\n * @throws {ExportError} Throws an `ExportError` if there is an issue updating\r\n * the local Highcharts cache.\r\n */\r\nasync function _updateCache(highchartsOptions, serverProxyOptions, sourcePath) {\r\n // Get Highcharts version for scripts\r\n const hcVersion =\r\n highchartsOptions.version === 'latest'\r\n ? null\r\n : `${highchartsOptions.version}`;\r\n\r\n // Get the CDN url for scripts\r\n const cdnUrl = highchartsOptions.cdnUrl || cache.cdnUrl;\r\n\r\n try {\r\n const fetchedModules = {};\r\n\r\n log(\r\n 3,\r\n `[cache] Updating cache version to Highcharts: ${hcVersion || 'latest'}.`\r\n );\r\n\r\n cache.sources = await _fetchScripts(\r\n [\r\n ...highchartsOptions.coreScripts.map((c) =>\r\n hcVersion ? `${cdnUrl}/${hcVersion}/${c}` : `${cdnUrl}/${c}`\r\n )\r\n ],\r\n [\r\n ...highchartsOptions.moduleScripts.map((m) =>\r\n m === 'map'\r\n ? hcVersion\r\n ? `${cdnUrl}/maps/${hcVersion}/modules/${m}`\r\n : `${cdnUrl}/maps/modules/${m}`\r\n : hcVersion\r\n ? `${cdnUrl}/${hcVersion}/modules/${m}`\r\n : `${cdnUrl}/modules/${m}`\r\n ),\r\n ...highchartsOptions.indicatorScripts.map((i) =>\r\n hcVersion\r\n ? `${cdnUrl}/stock/${hcVersion}/indicators/${i}`\r\n : `${cdnUrl}/stock/indicators/${i}`\r\n )\r\n ],\r\n highchartsOptions.customScripts,\r\n serverProxyOptions,\r\n fetchedModules\r\n );\r\n\r\n // Extract and save version of currently used Highcharts\r\n cache.hcVersion = extractVersion(cache.sources);\r\n\r\n // Save the fetched modules into caches' source JSON\r\n writeFileSync(sourcePath, cache.sources);\r\n return fetchedModules;\r\n } catch (error) {\r\n throw new ExportError(\r\n '[cache] Unable to update the local Highcharts cache.',\r\n 500\r\n ).setError(error);\r\n }\r\n}\r\n\r\nexport default {\r\n checkAndUpdateCache,\r\n getHighchartsVersion,\r\n updateHighchartsVersion,\r\n extractVersion,\r\n extractModuleName,\r\n getCache,\r\n getCachePath\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * @overview Provides methods for initializing Highcharts with customized\r\n * animation settings and triggering the creation of Highcharts charts with\r\n * export-specific configurations in the page context. Supports dynamic option\r\n * merging, custom logic injection, and control over rendering behaviors. Used\r\n * by the Puppeteer page.\r\n */\r\n\r\n/* eslint-disable no-undef */\r\n\r\n/**\r\n * Setting the `Highcharts.animObject` function. Called when initing the page.\r\n *\r\n * @function setupHighcharts\r\n */\r\nexport function setupHighcharts() {\r\n Highcharts.animObject = function () {\r\n return { duration: 0 };\r\n };\r\n}\r\n\r\n/**\r\n * Creates the actual Highcharts chart on a page.\r\n *\r\n * @async\r\n * @function createChart\r\n *\r\n * @param {Object} exportOptions - The configuration object containing `export`\r\n * options.\r\n * @param {Object} customLogicOptions - The configuration object containing\r\n * `customLogic` options.\r\n *\r\n */\r\nexport async function createChart(exportOptions, customLogicOptions) {\r\n // Get required functions\r\n const { getOptions, setOptions, merge, wrap } = Highcharts;\r\n\r\n // Create a separate object for a potential `setOptions` usages in order\r\n // to prevent from polluting other exports that can happen on the same page\r\n Highcharts.setOptionsObj = merge(false, {}, getOptions());\r\n\r\n // NOTE: Is this used for anything useful?\r\n window.isRenderComplete = false;\r\n wrap(Highcharts.Chart.prototype, 'init', function (proceed, userOptions, cb) {\r\n // Override the `userOptions` with image friendly options\r\n userOptions = merge(userOptions, {\r\n exporting: {\r\n enabled: false\r\n },\r\n plotOptions: {\r\n series: {\r\n label: {\r\n enabled: false\r\n }\r\n }\r\n },\r\n /* Expects tooltip in the `userOptions` when `forExport` is true.\r\n https://github.com/highcharts/highcharts/blob/3ad430a353b8056b9e764aa4e5cd6828aa479db2/js/parts/Chart.js#L241\r\n */\r\n tooltip: {}\r\n });\r\n\r\n (userOptions.series || []).forEach(function (series) {\r\n series.animation = false;\r\n });\r\n\r\n // Add flag to know if chart render has been called.\r\n if (!window.onHighchartsRender) {\r\n window.onHighchartsRender = Highcharts.addEvent(this, 'render', () => {\r\n window.isRenderComplete = true;\r\n });\r\n }\r\n\r\n proceed.apply(this, [userOptions, cb]);\r\n });\r\n\r\n wrap(Highcharts.Series.prototype, 'init', function (proceed, chart, options) {\r\n proceed.apply(this, [chart, options]);\r\n });\r\n\r\n // Some mandatory additional `chart` and `exporting` options\r\n const additionalOptions = {\r\n chart: {\r\n // By default animation is disabled\r\n animation: false,\r\n // Get the right size values\r\n height: exportOptions.height,\r\n width: exportOptions.width\r\n },\r\n exporting: {\r\n // No need for the exporting button\r\n enabled: false\r\n }\r\n };\r\n\r\n // Get the input to export from the `instr` option\r\n const userOptions = new Function(`return ${exportOptions.instr}`)();\r\n\r\n // Get the `themeOptions` option\r\n const themeOptions = new Function(`return ${exportOptions.themeOptions}`)();\r\n\r\n // Get the `globalOptions` option\r\n const globalOptions = new Function(`return ${exportOptions.globalOptions}`)();\r\n\r\n // Merge the following options objects to create final options\r\n const finalOptions = merge(\r\n false,\r\n themeOptions,\r\n userOptions,\r\n // Placed it here instead in the init because of the size issues\r\n additionalOptions\r\n );\r\n\r\n // Prepare the `callback` option\r\n const finalCallback = customLogicOptions.callback\r\n ? new Function(`return ${customLogicOptions.callback}`)()\r\n : null;\r\n\r\n // Trigger the `customCode` option\r\n if (customLogicOptions.customCode) {\r\n new Function('options', customLogicOptions.customCode)(userOptions);\r\n }\r\n\r\n // Set the global options if exist\r\n if (globalOptions) {\r\n setOptions(globalOptions);\r\n }\r\n\r\n // Call the chart creation\r\n Highcharts[exportOptions.constr]('container', finalOptions, finalCallback);\r\n\r\n // Get the current global options\r\n const defaultOptions = getOptions();\r\n\r\n // Clear it just in case (e.g. the `setOptions` was used in the `customCode`)\r\n for (const prop in defaultOptions) {\r\n if (typeof defaultOptions[prop] !== 'function') {\r\n delete defaultOptions[prop];\r\n }\r\n }\r\n\r\n // Set the default options back\r\n setOptions(Highcharts.setOptionsObj);\r\n\r\n // Empty the custom global options object\r\n Highcharts.setOptionsObj = {};\r\n}\r\n\r\nexport default {\r\n setupHighcharts,\r\n createChart\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * @overview This module provides functions for managing Puppeteer browser\r\n * instance, creating and clearing pages, injecting custom resources,\r\n * and setting up Highcharts for server-side rendering. The module ensures\r\n * that resources are correctly managed and can handle failures during\r\n * operations like launching the browser or creating new pages.\r\n */\r\n\r\nimport { readFileSync } from 'fs';\r\nimport { join } from 'path';\r\n\r\nimport puppeteer from 'puppeteer';\r\n\r\nimport { getCachePath } from './cache.js';\r\nimport { getOptions } from './config.js';\r\nimport { setupHighcharts } from './highcharts.js';\r\nimport { log, logWithStack } from './logger.js';\r\nimport { __dirname, getAbsolutePath } from './utils.js';\r\n\r\nimport ExportError from './errors/ExportError.js';\r\n\r\n// Get the template for pages\r\nconst template = readFileSync(\r\n join(__dirname, 'templates', 'template.html'),\r\n 'utf8'\r\n);\r\n\r\n// To save the browser\r\nlet browser = null;\r\n\r\n/**\r\n * Retrieves the existing Puppeteer browser instance.\r\n *\r\n * @function getBrowser\r\n *\r\n * @returns {Object} The Puppeteer browser instance.\r\n *\r\n * @throws {ExportError} Throws an `ExportError` if no valid browser\r\n * has been created.\r\n */\r\nexport function getBrowser() {\r\n if (!browser) {\r\n throw new ExportError('[browser] No valid browser has been created.', 500);\r\n }\r\n return browser;\r\n}\r\n\r\n/**\r\n * Creates a Puppeteer browser instance with the specified arguments.\r\n *\r\n * @async\r\n * @function createBrowser\r\n *\r\n * @param {Array.} puppeteerArgs - Additional arguments for Puppeteer\r\n * launch.\r\n *\r\n * @returns {Promise} A Promise that resolves to the created Puppeteer\r\n * browser instance.\r\n *\r\n * @throws {ExportError} Throws an `ExportError` if max retries to open\r\n * a browser instance are reached, or if no browser instance is found after\r\n * retries.\r\n */\r\nexport async function createBrowser(puppeteerArgs) {\r\n // Get `debug` and `other` options\r\n const { debug, other } = getOptions();\r\n\r\n // Get the `debug` options\r\n const { enable: enabledDebug, ...debugOptions } = debug;\r\n\r\n // Launch options for the browser instance\r\n const launchOptions = {\r\n headless: other.browserShellMode ? 'shell' : true,\r\n userDataDir: 'tmp',\r\n args: puppeteerArgs || [],\r\n handleSIGINT: false,\r\n handleSIGTERM: false,\r\n handleSIGHUP: false,\r\n waitForInitialPage: false,\r\n defaultViewport: null,\r\n ...(enabledDebug && debugOptions)\r\n };\r\n\r\n // Create a browser\r\n if (!browser) {\r\n // A counter for the browser's launch retries\r\n let tryCount = 0;\r\n\r\n const open = async () => {\r\n try {\r\n log(\r\n 3,\r\n `[browser] Attempting to get a browser instance (try ${++tryCount}).`\r\n );\r\n\r\n // Launch the browser\r\n browser = await puppeteer.launch(launchOptions);\r\n } catch (error) {\r\n logWithStack(\r\n 1,\r\n error,\r\n '[browser] Failed to launch a browser instance.'\r\n );\r\n\r\n // Retry to launch browser until reaching max attempts\r\n if (tryCount < 25) {\r\n log(3, `[browser] Retry to open a browser (${tryCount} out of 25).`);\r\n\r\n // Wait for a 4 seconds before trying again\r\n await new Promise((response) => setTimeout(response, 4000));\r\n await open();\r\n } else {\r\n throw error;\r\n }\r\n }\r\n };\r\n\r\n try {\r\n await open();\r\n\r\n // Shell mode inform\r\n if (launchOptions.headless === 'shell') {\r\n log(3, `[browser] Launched browser in shell mode.`);\r\n }\r\n\r\n // Debug mode inform\r\n if (enabledDebug) {\r\n log(3, `[browser] Launched browser in debug mode.`);\r\n }\r\n } catch (error) {\r\n throw new ExportError(\r\n '[browser] Maximum retries to open a browser instance reached.',\r\n 500\r\n ).setError(error);\r\n }\r\n\r\n if (!browser) {\r\n throw new ExportError('[browser] Cannot find a browser to open.', 500);\r\n }\r\n }\r\n\r\n // Return a browser instance\r\n return browser;\r\n}\r\n\r\n/**\r\n * Closes the Puppeteer browser instance if it is connected.\r\n *\r\n * @async\r\n * @function closeBrowser\r\n */\r\nexport async function closeBrowser() {\r\n // Close the browser when connected\r\n if (browser && browser.connected) {\r\n await browser.close();\r\n }\r\n browser = null;\r\n log(4, '[browser] Closed the browser.');\r\n}\r\n\r\n/**\r\n * Creates a new Puppeteer page within an existing browser instance.\r\n * The function creates a new page, disables caching, sets content using\r\n * the `_setPageContent()`, and returns the created Puppeteer page.\r\n *\r\n * @async\r\n * @function newPage\r\n *\r\n * @param {Object} poolResource - The pool resource that contains `id`,\r\n * `workCount`, and `page`.\r\n *\r\n * @throws {ExportError} Throws an `ExportError` if no valid browser\r\n * has been connected or if a page is invalid or closed.\r\n */\r\nexport async function newPage(poolResource) {\r\n // Error in case of no connected browser\r\n if (!browser || !browser.connected) {\r\n throw new ExportError(`[browser] Browser is not yet connected.`, 500);\r\n }\r\n\r\n // Create a page\r\n poolResource.page = await browser.newPage();\r\n\r\n // Disable cache\r\n await poolResource.page.setCacheEnabled(false);\r\n\r\n // Set the content\r\n await _setPageContent(poolResource.page);\r\n\r\n // Set page events\r\n _setPageEvents(poolResource.page);\r\n\r\n // Check if the page is correctly created\r\n if (!poolResource.page || poolResource.page.isClosed()) {\r\n throw new ExportError('[browser] The page is invalid or closed.', 400);\r\n }\r\n}\r\n\r\n/**\r\n * Clears the content of a Puppeteer Page based on the specified mode. Logs\r\n * thrown error if clearing of a page's content fails.\r\n *\r\n * @async\r\n * @function clearPage\r\n *\r\n * @param {Object} poolResource - The pool resource that contains page and id.\r\n * @param {boolean} [hardReset=false] - A flag indicating the type of clearing\r\n * to be performed. If true, navigates to `about:blank` and resets content\r\n * and scripts. If false, clears the body content by setting a predefined HTML\r\n * structure. The default value is `false`.\r\n *\r\n * @returns {Promise} A Promise that resolves to true when page\r\n * is correctly cleared and false when it is not.\r\n */\r\nexport async function clearPage(poolResource, hardReset = false) {\r\n try {\r\n if (poolResource.page && !poolResource.page.isClosed()) {\r\n if (hardReset) {\r\n // Navigate to `about:blank`\r\n await poolResource.page.goto('about:blank', {\r\n waitUntil: 'domcontentloaded'\r\n });\r\n\r\n // Set the content and and scripts again\r\n await _setPageContent(poolResource.page);\r\n } else {\r\n // Clear body content\r\n await poolResource.page.evaluate(() => {\r\n document.body.innerHTML =\r\n '
';\r\n });\r\n }\r\n return true;\r\n }\r\n } catch (error) {\r\n logWithStack(\r\n 2,\r\n error,\r\n `[pool] Pool resource [${poolResource.id}] - Content of the page could not be cleared.`\r\n );\r\n\r\n // Set the `workLimit` to exceeded in order to recreate the resource\r\n poolResource.workCount = getOptions().pool.workLimit + 1;\r\n }\r\n return false;\r\n}\r\n\r\n/**\r\n * Adds custom JS and CSS resources to a Puppeteer Page based on the specified\r\n * options.\r\n *\r\n * @async\r\n * @function addPageResources\r\n *\r\n * @param {Object} page - The Puppeteer page object to which resources will\r\n * be added.\r\n * @param {Object} customLogicOptions - The configuration object containing\r\n * `customLogic` options.\r\n *\r\n * @returns {Promise>} A Promise that resolves to an array\r\n * of injected resources.\r\n */\r\nexport async function addPageResources(page, customLogicOptions) {\r\n // Injected resources array\r\n const injectedResources = [];\r\n\r\n // Use resources\r\n const resources = customLogicOptions.resources;\r\n if (resources) {\r\n const injectedJs = [];\r\n\r\n // Load custom JS code\r\n if (resources.js) {\r\n injectedJs.push({\r\n content: resources.js\r\n });\r\n }\r\n\r\n // Load scripts from all custom files\r\n if (resources.files) {\r\n for (const file of resources.files) {\r\n const isLocal = file.startsWith('http') ? false : true;\r\n\r\n // Add each custom script from resources' files\r\n injectedJs.push(\r\n isLocal\r\n ? {\r\n content: readFileSync(getAbsolutePath(file), 'utf8')\r\n }\r\n : {\r\n url: file\r\n }\r\n );\r\n }\r\n }\r\n\r\n for (const jsResource of injectedJs) {\r\n try {\r\n injectedResources.push(await page.addScriptTag(jsResource));\r\n } catch (error) {\r\n logWithStack(2, error, `[browser] The JS resource cannot be loaded.`);\r\n }\r\n }\r\n injectedJs.length = 0;\r\n\r\n // Load CSS\r\n const injectedCss = [];\r\n if (resources.css) {\r\n let cssImports = resources.css.match(/@import\\s*([^;]*);/g);\r\n if (cssImports) {\r\n // Handle css section\r\n for (let cssImportPath of cssImports) {\r\n if (cssImportPath) {\r\n cssImportPath = cssImportPath\r\n .replace('url(', '')\r\n .replace('@import', '')\r\n .replace(/\"/g, '')\r\n .replace(/'/g, '')\r\n .replace(/;/, '')\r\n .replace(/\\)/g, '')\r\n .trim();\r\n\r\n // Add each custom css from resources\r\n if (cssImportPath.startsWith('http')) {\r\n injectedCss.push({\r\n url: cssImportPath\r\n });\r\n } else if (customLogicOptions.allowFileResources) {\r\n injectedCss.push({\r\n path: getAbsolutePath(cssImportPath)\r\n });\r\n }\r\n }\r\n }\r\n }\r\n\r\n // The rest of the CSS section will be content by now\r\n injectedCss.push({\r\n content: resources.css.replace(/@import\\s*([^;]*);/g, '') || ' '\r\n });\r\n\r\n for (const cssResource of injectedCss) {\r\n try {\r\n injectedResources.push(await page.addStyleTag(cssResource));\r\n } catch (error) {\r\n logWithStack(\r\n 2,\r\n error,\r\n `[browser] The CSS resource cannot be loaded.`\r\n );\r\n }\r\n }\r\n injectedCss.length = 0;\r\n }\r\n }\r\n return injectedResources;\r\n}\r\n\r\n/**\r\n * Clears out all state set on the page with `addScriptTag` and `addStyleTag`.\r\n * Removes injected resources and resets CSS and script tags on the page.\r\n * Additionally, it destroys previously existing charts.\r\n *\r\n * @async\r\n * @function clearPageResources\r\n *\r\n * @param {Object} page - The Puppeteer page object from which resources will\r\n * be cleared.\r\n * @param {Array.} injectedResources - Array of injected resources\r\n * to be cleared.\r\n */\r\nexport async function clearPageResources(page, injectedResources) {\r\n try {\r\n for (const resource of injectedResources) {\r\n await resource.dispose();\r\n }\r\n\r\n // Destroy old charts after export is done and reset all CSS and script tags\r\n await page.evaluate(() => {\r\n // We are not guaranteed that Highcharts is loaded, when doing SVG exports\r\n if (typeof Highcharts !== 'undefined') {\r\n // eslint-disable-next-line no-undef\r\n const oldCharts = Highcharts.charts;\r\n\r\n // Check in any already existing charts\r\n if (Array.isArray(oldCharts) && oldCharts.length) {\r\n // Destroy old charts\r\n for (const oldChart of oldCharts) {\r\n oldChart && oldChart.destroy();\r\n // eslint-disable-next-line no-undef\r\n Highcharts.charts.shift();\r\n }\r\n }\r\n }\r\n\r\n // eslint-disable-next-line no-undef\r\n const [...scriptsToRemove] = document.getElementsByTagName('script');\r\n // eslint-disable-next-line no-undef\r\n const [, ...stylesToRemove] = document.getElementsByTagName('style');\r\n // eslint-disable-next-line no-undef\r\n const [...linksToRemove] = document.getElementsByTagName('link');\r\n\r\n // Remove tags\r\n for (const element of [\r\n ...scriptsToRemove,\r\n ...stylesToRemove,\r\n ...linksToRemove\r\n ]) {\r\n element.remove();\r\n }\r\n });\r\n } catch (error) {\r\n logWithStack(2, error, `[browser] Could not clear page's resources.`);\r\n }\r\n}\r\n\r\n/**\r\n * Sets the content for a Puppeteer Page using a predefined template\r\n * and additional scripts.\r\n *\r\n * @async\r\n * @function _setPageContent\r\n *\r\n * @param {Object} page - The Puppeteer page object to which the content\r\n * is being set.\r\n */\r\nasync function _setPageContent(page) {\r\n // Set the initial page content\r\n await page.setContent(template, { waitUntil: 'domcontentloaded' });\r\n\r\n // Add all registered Higcharts scripts, quite demanding\r\n await page.addScriptTag({ path: join(getCachePath(), 'sources.js') });\r\n\r\n // Set the initial `animObject` for Highcharts\r\n await page.evaluate(setupHighcharts);\r\n}\r\n\r\n/**\r\n * Set events (like `pageerror` and `console`) for a Puppeteer Page in order\r\n * to catch and display errors and console logs from the window context.\r\n *\r\n * @function _setPageEvents\r\n *\r\n * @param {Object} page - The Puppeteer page object to which the listeners\r\n * are being set.\r\n */\r\nfunction _setPageEvents(page) {\r\n // Get `debug` options\r\n const { debug } = getOptions();\r\n\r\n // Set the `pageerror` listener\r\n page.on('pageerror', async () => {\r\n // It would seem like this may fire at the same time or shortly before\r\n // a page is closed.\r\n if (page.isClosed()) {\r\n return;\r\n }\r\n });\r\n\r\n // Set the `console` listener, if needed\r\n if (debug.enable && debug.listenToConsole) {\r\n page.on('console', (message) => {\r\n console.log(`[debug] ${message.text()}`);\r\n });\r\n }\r\n}\r\n\r\nexport default {\r\n getBrowser,\r\n createBrowser,\r\n closeBrowser,\r\n newPage,\r\n clearPage,\r\n addPageResources,\r\n clearPageResources\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * The CSS to be used on the exported page.\r\n *\r\n * @returns {string} The CSS configuration.\r\n */\r\nexport default () => `\r\n\r\nhtml, body {\r\n margin: 0;\r\n padding: 0;\r\n box-sizing: border-box;\r\n}\r\n\r\n#table-div, #sliders, #datatable, #controls, .ld-row {\r\n display: none;\r\n height: 0;\r\n}\r\n\r\n#chart-container {\r\n box-sizing: border-box;\r\n margin: 0;\r\n overflow: auto;\r\n font-size: 0;\r\n}\r\n\r\n#chart-container > figure, div {\r\n margin-top: 0 !important;\r\n margin-bottom: 0 !important;\r\n}\r\n\r\n`;\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\nimport cssTemplate from './css.js';\r\n\r\n/**\r\n * The SVG template to use when loading SVG content to be exported.\r\n *\r\n * @param {string} svg - The SVG input content to be exported.\r\n *\r\n * @returns {string} The SVG template.\r\n */\r\nexport default (svg) => `\r\n\r\n\r\n \r\n \r\n Highcharts Export\r\n \r\n \r\n \r\n
\r\n ${svg}\r\n
\r\n \r\n\r\n\r\n`;\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * @overview This module handles chart export functionality using Puppeteer.\r\n * It supports exporting charts as SVG, PNG, JPEG, and PDF formats. The module\r\n * manages page resources, sets up the export environment, and processes chart\r\n * configurations or SVG inputs for rendering. Exports to a chart from a page\r\n * using Puppeteer.\r\n */\r\n\r\nimport { addPageResources, clearPageResources } from './browser.js';\r\nimport { createChart } from './highcharts.js';\r\nimport { log } from './logger.js';\r\n\r\nimport svgTemplate from '../templates/svgExport/svgExport.js';\r\n\r\nimport ExportError from './errors/ExportError.js';\r\n\r\n/**\r\n * Exports to a chart from a page using Puppeteer.\r\n *\r\n * @async\r\n * @function puppeteerExport\r\n *\r\n * @param {Object} page - Puppeteer page object.\r\n * @param {Object} exportOptions - The configuration object containing `export`\r\n * options.\r\n * @param {Object} customLogicOptions - The configuration object containing\r\n * `customLogic` options.\r\n *\r\n * @returns {Promise<(string|Buffer|ExportError)>} A Promise that resolves\r\n * to the exported data or rejecting with an `ExportError`.\r\n *\r\n * @throws {ExportError} Throws an `ExportError` if export to an unsupported\r\n * output format occurs.\r\n */\r\nexport async function puppeteerExport(page, exportOptions, customLogicOptions) {\r\n // Injected resources array (additional JS and CSS)\r\n const injectedResources = [];\r\n\r\n try {\r\n let isSVG = false;\r\n\r\n // Decide on the export method\r\n if (exportOptions.svg) {\r\n log(4, '[export] Treating as SVG input.');\r\n\r\n // If the `type` is also SVG, return the input\r\n if (exportOptions.type === 'svg') {\r\n return exportOptions.svg;\r\n }\r\n\r\n // Mark as SVG export for the later size corrections\r\n isSVG = true;\r\n\r\n // SVG export\r\n await page.setContent(svgTemplate(exportOptions.svg), {\r\n waitUntil: 'domcontentloaded'\r\n });\r\n } else {\r\n log(4, '[export] Treating as JSON config.');\r\n\r\n // Options export\r\n await page.evaluate(createChart, exportOptions, customLogicOptions);\r\n }\r\n\r\n // Keeps track of all resources added on the page with addXXXTag. etc\r\n // It's VITAL that all added resources ends up here so we can clear things\r\n // out when doing a new export in the same page!\r\n injectedResources.push(\r\n ...(await addPageResources(page, customLogicOptions))\r\n );\r\n\r\n // Get the real chart size and set the zoom accordingly\r\n const size = isSVG\r\n ? await page.evaluate((scale) => {\r\n const svgElement = document.querySelector(\r\n '#chart-container svg:first-of-type'\r\n );\r\n\r\n // Get the values correctly scaled\r\n const chartHeight = svgElement.height.baseVal.value * scale;\r\n const chartWidth = svgElement.width.baseVal.value * scale;\r\n\r\n // In case of SVG the zoom must be set directly for body as scale\r\n // eslint-disable-next-line no-undef\r\n document.body.style.zoom = scale;\r\n\r\n // Set the margin to 0px\r\n // eslint-disable-next-line no-undef\r\n document.body.style.margin = '0px';\r\n\r\n return {\r\n chartHeight,\r\n chartWidth\r\n };\r\n }, parseFloat(exportOptions.scale))\r\n : await page.evaluate(() => {\r\n // eslint-disable-next-line no-undef\r\n const { chartHeight, chartWidth } = window.Highcharts.charts[0];\r\n\r\n // No need for such scale manipulation in case of other types\r\n // of exports. Reset the zoom for other exports than to SVGs\r\n // eslint-disable-next-line no-undef\r\n document.body.style.zoom = 1;\r\n\r\n return {\r\n chartHeight,\r\n chartWidth\r\n };\r\n });\r\n\r\n // Get the clip region for the page\r\n const { x, y } = await _getClipRegion(page);\r\n\r\n // Set final `height` for viewport\r\n const viewportHeight = Math.abs(\r\n Math.ceil(size.chartHeight || exportOptions.height)\r\n );\r\n\r\n // Set final `width` for viewport\r\n const viewportWidth = Math.abs(\r\n Math.ceil(size.chartWidth || exportOptions.width)\r\n );\r\n\r\n // Set the final viewport now that we have the real height\r\n await page.setViewport({\r\n height: viewportHeight,\r\n width: viewportWidth,\r\n deviceScaleFactor: isSVG ? 1 : parseFloat(exportOptions.scale)\r\n });\r\n\r\n let result;\r\n // Rasterization process\r\n switch (exportOptions.type) {\r\n case 'svg':\r\n result = await _createSVG(page);\r\n break;\r\n case 'png':\r\n case 'jpeg':\r\n result = await _createImage(\r\n page,\r\n exportOptions.type,\r\n {\r\n width: viewportWidth,\r\n height: viewportHeight,\r\n x,\r\n y\r\n },\r\n exportOptions.rasterizationTimeout\r\n );\r\n break;\r\n case 'pdf':\r\n result = await _createPDF(\r\n page,\r\n viewportHeight,\r\n viewportWidth,\r\n exportOptions.rasterizationTimeout\r\n );\r\n break;\r\n default:\r\n throw new ExportError(\r\n `[export] Unsupported output format: ${exportOptions.type}.`,\r\n 400\r\n );\r\n }\r\n\r\n // Clear previously injected JS and CSS resources\r\n await clearPageResources(page, injectedResources);\r\n return result;\r\n } catch (error) {\r\n await clearPageResources(page, injectedResources);\r\n return error;\r\n }\r\n}\r\n\r\n/**\r\n * Retrieves the clipping region coordinates of the specified page element\r\n * with the 'chart-container' id.\r\n *\r\n * @async\r\n * @function _getClipRegion\r\n *\r\n * @param {Object} page - Puppeteer page object.\r\n *\r\n * @returns {Promise} A Promise that resolves to an object containing\r\n * `x`, `y`, `width`, and `height` properties.\r\n */\r\nasync function _getClipRegion(page) {\r\n return page.$eval('#chart-container', (element) => {\r\n const { x, y, width, height } = element.getBoundingClientRect();\r\n return {\r\n x,\r\n y,\r\n width,\r\n height: Math.trunc(height > 1 ? height : 500)\r\n };\r\n });\r\n}\r\n\r\n/**\r\n * Creates an SVG by evaluating the `outerHTML` of the first 'svg' element\r\n * inside an element with the id 'container'.\r\n *\r\n * @async\r\n * @function _createSVG\r\n *\r\n * @param {Object} page - Puppeteer page object.\r\n *\r\n * @returns {Promise} A Promise that resolves to the SVG string.\r\n */\r\nasync function _createSVG(page) {\r\n return page.$eval(\r\n '#container svg:first-of-type',\r\n (element) => element.outerHTML\r\n );\r\n}\r\n\r\n/**\r\n * Creates an image using Puppeteer's page `screenshot` functionality with\r\n * specified options.\r\n *\r\n * @async\r\n * @function _createImage\r\n *\r\n * @param {Object} page - Puppeteer page object.\r\n * @param {string} type - Image type.\r\n * @param {Object} clip - Clipping region coordinates.\r\n * @param {number} rasterizationTimeout - Timeout for rasterization\r\n * in milliseconds.\r\n *\r\n * @returns {Promise} A Promise that resolves to the image buffer\r\n * or rejecting with an `ExportError` for timeout.\r\n */\r\nasync function _createImage(page, type, clip, rasterizationTimeout) {\r\n return Promise.race([\r\n page.screenshot({\r\n type,\r\n clip,\r\n encoding: 'base64',\r\n fullPage: false,\r\n optimizeForSpeed: true,\r\n captureBeyondViewport: true,\r\n ...(type !== 'png' ? { quality: 80 } : {}),\r\n // Always render on a transparent page if the expected type format is PNG\r\n omitBackground: type == 'png' // #447, #463\r\n }),\r\n new Promise((_resolve, reject) =>\r\n setTimeout(\r\n () => reject(new ExportError('Rasterization timeout', 408)),\r\n rasterizationTimeout || 1500\r\n )\r\n )\r\n ]);\r\n}\r\n\r\n/**\r\n * Creates a PDF using Puppeteer's page `pdf` functionality with specified\r\n * options.\r\n *\r\n * @async\r\n * @function _createPDF\r\n *\r\n * @param {Object} page - Puppeteer page object.\r\n * @param {number} height - PDF height.\r\n * @param {number} width - PDF width.\r\n * @param {number} rasterizationTimeout - Timeout for rasterization\r\n * in milliseconds.\r\n *\r\n * @returns {Promise} A Promise that resolves to the PDF buffer.\r\n */\r\nasync function _createPDF(page, height, width, rasterizationTimeout) {\r\n await page.emulateMediaType('screen');\r\n return page.pdf({\r\n // This will remove an extra empty page in PDF exports\r\n height: height + 1,\r\n width,\r\n encoding: 'base64',\r\n timeout: rasterizationTimeout || 1500\r\n });\r\n}\r\n\r\nexport default {\r\n puppeteerExport\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * @overview This module provides a worker pool implementation for managing\r\n * the browser instance and pages, specifically designed for use with\r\n * the Highcharts Export Server. It optimizes resources usage and performance\r\n * by maintaining a pool of workers that can handle concurrent export tasks\r\n * using Puppeteer.\r\n */\r\n\r\nimport { Pool } from 'tarn';\r\nimport { v4 as uuid } from 'uuid';\r\n\r\nimport { clearPage, createBrowser, closeBrowser, newPage } from './browser.js';\r\nimport { puppeteerExport } from './export.js';\r\nimport { log, logWithStack } from './logger.js';\r\nimport { getNewDateTime, measureTime } from './utils.js';\r\n\r\nimport ExportError from './errors/ExportError.js';\r\n\r\n// The pool instance\r\nlet pool = null;\r\n\r\n// Pool statistics\r\nconst poolStats = {\r\n exportsAttempted: 0,\r\n exportsPerformed: 0,\r\n exportsDropped: 0,\r\n exportsFromSvg: 0,\r\n exportsFromOptions: 0,\r\n exportsFromSvgAttempts: 0,\r\n exportsFromOptionsAttempts: 0,\r\n timeSpent: 0,\r\n timeSpentAverage: 0\r\n};\r\n\r\n/**\r\n * Initializes the export pool with the provided configuration, creating\r\n * a browser instance and setting up worker resources.\r\n *\r\n * @async\r\n * @function initPool\r\n *\r\n * @param {Object} poolOptions - The configuration object containing `pool`\r\n * options.\r\n * @param {Array.} puppeteerArgs - Additional arguments for Puppeteer\r\n * launch.\r\n *\r\n * @returns {Promise} A Promise that resolves to ending the function\r\n * execution when an already initialized pool of resources is found.\r\n *\r\n * @throws {ExportError} Throws an `ExportError` if could not create the pool\r\n * of workers.\r\n */\r\nexport async function initPool(poolOptions, puppeteerArgs) {\r\n // Create a browser instance with the puppeteer arguments\r\n await createBrowser(puppeteerArgs);\r\n\r\n try {\r\n log(\r\n 3,\r\n `[pool] Initializing pool with workers: min ${poolOptions.minWorkers}, max ${poolOptions.maxWorkers}.`\r\n );\r\n\r\n if (pool) {\r\n log(\r\n 4,\r\n '[pool] Already initialized, please kill it before creating a new one.'\r\n );\r\n return;\r\n }\r\n\r\n // Keep an eye on a correct min and max workers number\r\n if (poolOptions.minWorkers > poolOptions.maxWorkers) {\r\n poolOptions.minWorkers = poolOptions.maxWorkers;\r\n }\r\n\r\n // Create a pool along with a minimal number of resources\r\n pool = new Pool({\r\n // Get the `create`, `validate`, and `destroy` functions\r\n ..._factory(poolOptions),\r\n min: poolOptions.minWorkers,\r\n max: poolOptions.maxWorkers,\r\n acquireTimeoutMillis: poolOptions.acquireTimeout,\r\n createTimeoutMillis: poolOptions.createTimeout,\r\n destroyTimeoutMillis: poolOptions.destroyTimeout,\r\n idleTimeoutMillis: poolOptions.idleTimeout,\r\n createRetryIntervalMillis: poolOptions.createRetryInterval,\r\n reapIntervalMillis: poolOptions.reaperInterval,\r\n propagateCreateError: false\r\n });\r\n\r\n // Set events\r\n pool.on('release', async (resource) => {\r\n // Clear page\r\n const clearStatus = await clearPage(resource, false);\r\n log(\r\n 4,\r\n `[pool] Pool resource [${resource.id}] - Releasing a worker. Clear page status: ${clearStatus}.`\r\n );\r\n });\r\n\r\n pool.on('destroySuccess', (_eventId, resource) => {\r\n log(\r\n 4,\r\n `[pool] Pool resource [${resource.id}] - Destroyed a worker successfully.`\r\n );\r\n resource.page = null;\r\n });\r\n\r\n const initialResources = [];\r\n // Create an initial number of resources\r\n for (let i = 0; i < poolOptions.minWorkers; i++) {\r\n try {\r\n const resource = await pool.acquire().promise;\r\n initialResources.push(resource);\r\n } catch (error) {\r\n logWithStack(2, error, '[pool] Could not create an initial resource.');\r\n }\r\n }\r\n\r\n // Release the initial number of resources back to the pool\r\n initialResources.forEach((resource) => {\r\n pool.release(resource);\r\n });\r\n\r\n log(\r\n 3,\r\n `[pool] The pool is ready${initialResources.length ? ` with ${initialResources.length} initial resources waiting.` : '.'}`\r\n );\r\n } catch (error) {\r\n throw new ExportError(\r\n '[pool] Could not configure and create the pool of workers.',\r\n 500\r\n ).setError(error);\r\n }\r\n}\r\n\r\n/**\r\n * Terminates all workers in the pool, destroys the pool, and closes the browser\r\n * instance.\r\n *\r\n * @async\r\n * @function killPool\r\n *\r\n * @returns {Promise} A Promise that resolves once all workers are\r\n * terminated, the pool is destroyed, and the browser is successfully closed.\r\n */\r\nexport async function killPool() {\r\n log(3, '[pool] Killing pool with all workers and closing browser.');\r\n\r\n // If still alive, destroy the pool of pages before closing a browser\r\n if (pool) {\r\n // Free up not released workers\r\n for (const worker of pool.used) {\r\n pool.release(worker.resource);\r\n }\r\n\r\n // Destroy the pool if it is still available\r\n if (!pool.destroyed) {\r\n await pool.destroy();\r\n log(4, '[pool] Destroyed the pool of resources.');\r\n }\r\n pool = null;\r\n }\r\n\r\n // Close the browser instance\r\n await closeBrowser();\r\n}\r\n\r\n/**\r\n * Processes the export work using a worker from the pool. Acquires a worker\r\n * handle from the pool, performs the export using puppeteer, and releases\r\n * the worker handle back to the pool.\r\n *\r\n * @async\r\n * @function postWork\r\n *\r\n * @param {Object} options - The configuration object containing complete set\r\n * of options.\r\n *\r\n * @returns {Promise} A Promise that resolves to the export result\r\n * and options.\r\n *\r\n * @throws {ExportError} Throws an `ExportError` if an error occurs during\r\n * the export process.\r\n */\r\nexport async function postWork(options) {\r\n let workerHandle;\r\n\r\n try {\r\n log(4, '[pool] Work received, starting to process.');\r\n\r\n // An export attempt counted\r\n ++poolStats.exportsAttempted;\r\n\r\n // Display the pool information if needed\r\n if (options.pool.benchmarking) {\r\n getPoolInfo();\r\n }\r\n\r\n // Throw an error in case of lacking the pool instance\r\n if (!pool) {\r\n throw new ExportError(\r\n '[pool] Work received, but pool has not been started.',\r\n 500\r\n );\r\n }\r\n\r\n // The acquire counter\r\n const acquireCounter = measureTime();\r\n\r\n // Try to acquire the worker along with the id, works count and page\r\n try {\r\n log(4, '[pool] Acquiring a worker handle.');\r\n\r\n // Acquire a pool resource\r\n workerHandle = await pool.acquire().promise;\r\n\r\n // Check the page acquire time\r\n if (options.server.benchmarking) {\r\n log(\r\n 5,\r\n `[benchmark] ${options.requestId ? `Request [${options.requestId}] - ` : ''}`,\r\n `Acquiring a worker handle took ${acquireCounter()}ms.`\r\n );\r\n }\r\n } catch (error) {\r\n throw new ExportError(\r\n `[pool] ${\r\n options.requestId ? `Request [${options.requestId}] - ` : ''\r\n }Error encountered when acquiring an available entry: ${acquireCounter()}ms.`,\r\n 400\r\n ).setError(error);\r\n }\r\n log(4, '[pool] Acquired a worker handle.');\r\n\r\n if (!workerHandle.page) {\r\n // Set the `workLimit` to exceeded in order to recreate the resource\r\n workerHandle.workCount = options.pool.workLimit + 1;\r\n throw new ExportError(\r\n '[pool] Resolved worker page is invalid: the pool setup is wonky.',\r\n 400\r\n );\r\n }\r\n\r\n // Save the start time\r\n const workStart = getNewDateTime();\r\n\r\n log(\r\n 4,\r\n `[pool] Pool resource [${workerHandle.id}] - Starting work on this pool entry.`\r\n );\r\n\r\n // Start measuring export time\r\n const exportCounter = measureTime();\r\n\r\n // Perform an export on a puppeteer level\r\n const result = await puppeteerExport(\r\n workerHandle.page,\r\n options.export,\r\n options.customLogic\r\n );\r\n\r\n // Check if it's an error\r\n if (result instanceof Error) {\r\n // NOTE:\r\n // If there's a rasterization timeout, we want need to flush the page.\r\n // This is because the page may be in a state where it's waiting for\r\n // the screenshot to finish even though the timeout has occured.\r\n // Which of course causes a lot of issues with the event system,\r\n // and page consistency.\r\n //\r\n // NOTE:\r\n // Only page.screenshot will throw this, timeouts for PDF's are\r\n // handled by the page.pdf function itself.\r\n //\r\n // ...yes, this is ugly.\r\n if (result.message === 'Rasterization timeout') {\r\n // Set the `workLimit` to exceeded in order to recreate the resource\r\n workerHandle.workCount = options.pool.workLimit + 1;\r\n workerHandle.page = null;\r\n }\r\n\r\n if (\r\n result.name === 'TimeoutError' ||\r\n result.message === 'Rasterization timeout'\r\n ) {\r\n throw new ExportError(\r\n `[pool] ${\r\n options.requestId ? `Request [${options.requestId}] - ` : ''\r\n }Rasterization timeout: your chart may be too complex or large, and failed to render within the allotted time.`\r\n ).setError(result);\r\n } else {\r\n throw new ExportError(\r\n `[pool] ${\r\n options.requestId ? `Request [${options.requestId}] - ` : ''\r\n }Error encountered during export: ${exportCounter()}ms.`\r\n ).setError(result);\r\n }\r\n }\r\n\r\n // Check the Puppeteer export time\r\n if (options.server.benchmarking) {\r\n log(\r\n 5,\r\n `[benchmark] ${options.requestId ? `Request [${options.requestId}] - ` : ''}`,\r\n `Exporting a chart sucessfully took ${exportCounter()}ms.`\r\n );\r\n }\r\n\r\n // Release the resource back to the pool\r\n pool.release(workerHandle);\r\n\r\n // Used for statistics in averageTime and processedWorkCount, which\r\n // in turn is used by the /health route.\r\n const workEnd = getNewDateTime();\r\n const exportTime = workEnd - workStart;\r\n\r\n poolStats.timeSpent += exportTime;\r\n poolStats.timeSpentAverage =\r\n poolStats.timeSpent / ++poolStats.exportsPerformed;\r\n\r\n log(4, `[pool] Work completed in ${exportTime}ms.`);\r\n\r\n // Otherwise return the result\r\n return {\r\n result,\r\n options\r\n };\r\n } catch (error) {\r\n ++poolStats.exportsDropped;\r\n\r\n if (workerHandle) {\r\n pool.release(workerHandle);\r\n }\r\n\r\n throw error;\r\n }\r\n}\r\n\r\n/**\r\n * Retrieves the current pool instance.\r\n *\r\n * @function getPool\r\n *\r\n * @returns {(Object|null)} The current pool instance if initialized, or null\r\n * if the pool has not been created.\r\n */\r\nexport function getPool() {\r\n return pool;\r\n}\r\n\r\n/**\r\n * Gets the statistic of a pool instace about exports.\r\n *\r\n * @function getPoolStats\r\n *\r\n * @returns {Object} The current pool statistics.\r\n */\r\nexport function getPoolStats() {\r\n return poolStats;\r\n}\r\n\r\n/**\r\n * Retrieves pool information in JSON format, including minimum and maximum\r\n * workers, available workers, workers in use, and pending acquire requests.\r\n *\r\n * @function getPoolInfoJSON\r\n *\r\n * @returns {Object} Pool information in JSON format.\r\n */\r\nexport function getPoolInfoJSON() {\r\n return {\r\n min: pool.min,\r\n max: pool.max,\r\n used: pool.numUsed(),\r\n available: pool.numFree(),\r\n allCreated: pool.numUsed() + pool.numFree(),\r\n pendingAcquires: pool.numPendingAcquires(),\r\n pendingCreates: pool.numPendingCreates(),\r\n pendingValidations: pool.numPendingValidations(),\r\n pendingDestroys: pool.pendingDestroys.length,\r\n absoluteAll:\r\n pool.numUsed() +\r\n pool.numFree() +\r\n pool.numPendingAcquires() +\r\n pool.numPendingCreates() +\r\n pool.numPendingValidations() +\r\n pool.pendingDestroys.length\r\n };\r\n}\r\n\r\n/**\r\n * Logs information about the current state of the pool, including the minimum\r\n * and maximum workers, available workers, workers in use, and pending acquire\r\n * requests.\r\n *\r\n * @function getPoolInfo\r\n */\r\nexport function getPoolInfo() {\r\n const {\r\n min,\r\n max,\r\n used,\r\n available,\r\n allCreated,\r\n pendingAcquires,\r\n pendingCreates,\r\n pendingValidations,\r\n pendingDestroys,\r\n absoluteAll\r\n } = getPoolInfoJSON();\r\n\r\n log(5, `[pool] The minimum number of resources allowed by pool: ${min}.`);\r\n log(5, `[pool] The maximum number of resources allowed by pool: ${max}.`);\r\n log(5, `[pool] The number of used resources: ${used}.`);\r\n log(5, `[pool] The number of free resources: ${available}.`);\r\n log(\r\n 5,\r\n `[pool] The number of all created (used and free) resources: ${allCreated}.`\r\n );\r\n log(\r\n 5,\r\n `[pool] The number of resources waiting to be acquired: ${pendingAcquires}.`\r\n );\r\n log(\r\n 5,\r\n `[pool] The number of resources waiting to be created: ${pendingCreates}.`\r\n );\r\n log(\r\n 5,\r\n `[pool] The number of resources waiting to be validated: ${pendingValidations}.`\r\n );\r\n log(\r\n 5,\r\n `[pool] The number of resources waiting to be destroyed: ${pendingDestroys}.`\r\n );\r\n log(5, `[pool] The number of all resources: ${absoluteAll}.`);\r\n}\r\n\r\n/**\r\n * Factory function that returns an object with `create`, `validate`,\r\n * and `destroy` functions for the pool instance.\r\n *\r\n * @function _factory\r\n *\r\n * @param {Object} poolOptions - The configuration object containing `pool`\r\n * options.\r\n */\r\nfunction _factory(poolOptions) {\r\n return {\r\n /**\r\n * Creates a new worker page for the export pool.\r\n *\r\n * @async\r\n * @function create\r\n *\r\n * @returns {Promise} A Promise that resolves to an object\r\n * containing the worker ID, a reference to the browser page, and initial\r\n * work count.\r\n *\r\n * @throws {ExportError} Throws an `ExportError` if there is an error during\r\n * the creation of the new page.\r\n */\r\n create: async () => {\r\n // Init the resource with unique id and work count\r\n const poolResource = {\r\n id: uuid(),\r\n // Try to distribute the initial work count\r\n workCount: Math.round(Math.random() * (poolOptions.workLimit / 2))\r\n };\r\n\r\n try {\r\n // Start measuring a page creation time\r\n const startDate = getNewDateTime();\r\n\r\n // Create a new page\r\n await newPage(poolResource);\r\n\r\n // Measure the time of full creation and configuration of a page\r\n log(\r\n 3,\r\n `[pool] Pool resource [${poolResource.id}] - Successfully created a worker, took ${\r\n getNewDateTime() - startDate\r\n }ms.`\r\n );\r\n\r\n // Return ready pool resource\r\n return poolResource;\r\n } catch (error) {\r\n log(\r\n 3,\r\n `[pool] Pool resource [${poolResource.id}] - Error encountered when creating a new page.`\r\n );\r\n throw error;\r\n }\r\n },\r\n\r\n /**\r\n * Validates a worker page in the export pool, checking if it has exceeded\r\n * the work limit.\r\n *\r\n * @async\r\n * @function validate\r\n *\r\n * @param {Object} poolResource - The handle to the worker, containing\r\n * the worker's ID, a reference to the browser page, and work count.\r\n *\r\n * @returns {Promise} A Promise that resolves to true if the worker\r\n * is valid and within the work limit; otherwise, to false.\r\n */\r\n validate: async (poolResource) => {\r\n // NOTE:\r\n // In certain cases acquiring throws a TargetCloseError, which may\r\n // be caused by two things:\r\n // - The page is closed and attempted to be reused.\r\n // - Lost contact with the browser.\r\n //\r\n // What we're seeing in logs is that successive exports typically\r\n // succeeds, and the server recovers, indicating that it's likely\r\n // the first case. This is an attempt at allievating the issue by\r\n // simply not validating the worker if the page is null or closed.\r\n //\r\n // The actual result from when this happened, was that a worker would\r\n // be completely locked, stopping it from being acquired until\r\n // its work count reached the limit.\r\n\r\n // Check if the `page` is valid\r\n if (!poolResource.page) {\r\n log(\r\n 3,\r\n `[pool] Pool resource [${poolResource.id}] - Validation failed (no valid page is found).`\r\n );\r\n return false;\r\n }\r\n\r\n // Check if the `page` is closed\r\n if (poolResource.page.isClosed()) {\r\n log(\r\n 3,\r\n `[pool] Pool resource [${poolResource.id}] - Validation failed (page is closed or invalid).`\r\n );\r\n return false;\r\n }\r\n\r\n // Check if the `mainFrame` is detached\r\n if (poolResource.page.mainFrame().detached) {\r\n log(\r\n 3,\r\n `[pool] Pool resource [${poolResource.id}] - Validation failed (page's frame is detached).`\r\n );\r\n return false;\r\n }\r\n\r\n // Check if the `workLimit` is exceeded\r\n if (\r\n poolOptions.workLimit &&\r\n ++poolResource.workCount > poolOptions.workLimit\r\n ) {\r\n log(\r\n 3,\r\n `[pool] Pool resource [${poolResource.id}] - Validation failed (exceeded the ${poolOptions.workLimit} works per resource limit).`\r\n );\r\n return false;\r\n }\r\n\r\n // The `poolResource` is validated\r\n return true;\r\n },\r\n\r\n /**\r\n * Destroys a worker entry in the export pool, closing its associated page.\r\n *\r\n * @async\r\n * @function destroy\r\n *\r\n * @param {Object} poolResource - The handle to the worker, containing\r\n * the worker's ID, a reference to the browser page, and work count.\r\n */\r\n destroy: async (poolResource) => {\r\n log(\r\n 3,\r\n `[pool] Pool resource [${poolResource.id}] - Destroying a worker.`\r\n );\r\n\r\n if (poolResource.page && !poolResource.page.isClosed()) {\r\n try {\r\n // Remove all attached event listeners from the resource\r\n poolResource.page.removeAllListeners('pageerror');\r\n poolResource.page.removeAllListeners('console');\r\n poolResource.page.removeAllListeners('framedetached');\r\n\r\n // We need to wait around for this\r\n await poolResource.page.close();\r\n } catch (error) {\r\n log(\r\n 3,\r\n `[pool] Pool resource [${poolResource.id}] - Page could not be closed upon destroying.`\r\n );\r\n throw error;\r\n }\r\n }\r\n }\r\n };\r\n}\r\n\r\nexport default {\r\n initPool,\r\n killPool,\r\n postWork,\r\n getPool,\r\n getPoolStats,\r\n getPoolInfo,\r\n getPoolInfoJSON\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * @overview Used to sanitize the strings coming from the exporting module\r\n * to prevent XSS attacks (with the DOMPurify library).\r\n */\r\n\r\nimport DOMPurify from 'dompurify';\r\nimport { JSDOM } from 'jsdom';\r\n\r\n/**\r\n * Sanitizes a given HTML string by removing \r\n * tags and any content within them.\r\n *\r\n * @function sanitize\r\n *\r\n * @param {string} input - The HTML string to be sanitized.\r\n *\r\n * @returns {string} The sanitized HTML string.\r\n */\r\nexport function sanitize(input) {\r\n // Get the virtual DOM\r\n const window = new JSDOM('').window;\r\n\r\n // Create a purifying instance\r\n const purify = DOMPurify(window);\r\n\r\n // Return sanitized input\r\n return purify.sanitize(input, { ADD_TAGS: ['foreignObject'] });\r\n}\r\n\r\nexport default {\r\n sanitize\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * @overview This module provides functions to prepare for the exporting charts\r\n * into various image output formats such as JPEG, PNG, PDF, and SVGs.\r\n * It supports single and batch export operations and allows customization\r\n * through options passed from configurations or APIs.\r\n */\r\n\r\nimport { readFileSync, writeFileSync } from 'fs';\r\n\r\nimport {\r\n isAllowedConfig,\r\n updateOptions,\r\n validateOption,\r\n validateOptions\r\n} from './config.js';\r\nimport { log, logWithStack } from './logger.js';\r\nimport { getPoolStats, killPool, postWork } from './pool.js';\r\nimport { sanitize } from './sanitize.js';\r\nimport {\r\n fixConstr,\r\n fixOutfile,\r\n fixType,\r\n getAbsolutePath,\r\n getBase64,\r\n isObject,\r\n roundNumber,\r\n wrapAround\r\n} from './utils.js';\r\n\r\nimport ExportError from './errors/ExportError.js';\r\n\r\n// The global flag for the code execution permission\r\nlet allowCodeExecution = false;\r\n\r\n/**\r\n * Starts a single export process based on the specified options and saves\r\n * the resulting image to the provided output file.\r\n *\r\n * @async\r\n * @function singleExport\r\n *\r\n * @param {Object} options - The `options` object, which should include settings\r\n * from the `export` and `customLogic` sections. It can be a partial or complete\r\n * set of options from these sections. The object must contain at least one\r\n * of the following `export` properties: `infile`, `instr`, `options`, or `svg`\r\n * to generate a valid image.\r\n *\r\n * @returns {Promise} A Promise that resolves once the single export\r\n * process is completed.\r\n *\r\n * @throws {ExportError} Throws an `ExportError` if an error occurs during\r\n * the single export process.\r\n */\r\nexport async function singleExport(options) {\r\n // Check if the export makes sense\r\n if (options && options.export) {\r\n // Validate single export options\r\n options = validateOptions(options);\r\n\r\n // Perform an export\r\n await startExport(\r\n { export: options.export, customLogic: options.customLogic },\r\n async (error, data) => {\r\n // Exit process when error exists\r\n if (error) {\r\n throw error;\r\n }\r\n\r\n // Get the `b64`, `outfile`, and `type` for a chart\r\n const { b64, outfile, type } = data.options.export;\r\n\r\n // Save the result\r\n try {\r\n if (b64) {\r\n // As a Base64 string to a txt file\r\n writeFileSync(\r\n `${outfile.split('.').shift() || 'chart'}.txt`,\r\n getBase64(data.result, type)\r\n );\r\n } else {\r\n // As a correct image format\r\n writeFileSync(\r\n outfile || `chart.${type}`,\r\n type !== 'svg' ? Buffer.from(data.result, 'base64') : data.result\r\n );\r\n }\r\n } catch (error) {\r\n throw new ExportError(\r\n '[chart] Error while saving a chart.',\r\n 500\r\n ).setError(error);\r\n }\r\n\r\n // Kill pool and close browser after finishing single export\r\n await killPool();\r\n }\r\n );\r\n } else {\r\n throw new ExportError(\r\n '[chart] No expected `export` options were found. Please provide one of the following options: `infile`, `instr`, `options`, or `svg` to generate a valid image.',\r\n 400\r\n );\r\n }\r\n}\r\n\r\n/**\r\n * Starts a batch export process for multiple charts based on information\r\n * provided in the `batch` option. The `batch` is a string in the following\r\n * format: \"infile1.json=outfile1.png;infile2.json=outfile2.png;...\". Results\r\n * are saved to the specified output files.\r\n *\r\n * @async\r\n * @function batchExport\r\n *\r\n * @param {Object} options - The `options` object, which should include settings\r\n * from the `export` and `customLogic` sections. It can be a partial or complete\r\n * set of options from these sections. It must contain the `batch` option from\r\n * the `export` section to generate valid images.\r\n *\r\n * @returns {Promise} A Promise that resolves once the batch export\r\n * processes are completed.\r\n *\r\n * @throws {ExportError} Throws an `ExportError` if an error occurs during\r\n * any of the batch export process.\r\n */\r\nexport async function batchExport(options) {\r\n // Check if the export makes sense\r\n if (options && options.export && options.export.batch) {\r\n // Validate batch export options\r\n options = validateOptions(options);\r\n\r\n // An array for collecting batch exports\r\n const batchFunctions = [];\r\n\r\n // Split and pair the `batch` arguments\r\n for (let pair of options.export.batch.split(';') || []) {\r\n pair = pair.split('=');\r\n if (pair.length === 2) {\r\n batchFunctions.push(\r\n startExport(\r\n {\r\n export: {\r\n ...options.export,\r\n infile: pair[0],\r\n outfile: pair[1]\r\n },\r\n customLogic: options.customLogic\r\n },\r\n (error, data) => {\r\n // Exit process when error exists\r\n if (error) {\r\n throw error;\r\n }\r\n\r\n // Get the `b64`, `outfile`, and `type` for a chart\r\n const { b64, outfile, type } = data.options.export;\r\n\r\n // Save the result\r\n try {\r\n if (b64) {\r\n // As a Base64 string to a txt file\r\n writeFileSync(\r\n `${outfile.split('.').shift() || 'chart'}.txt`,\r\n getBase64(data.result, type)\r\n );\r\n } else {\r\n // As a correct image format\r\n writeFileSync(\r\n outfile,\r\n type !== 'svg'\r\n ? Buffer.from(data.result, 'base64')\r\n : data.result\r\n );\r\n }\r\n } catch (error) {\r\n throw new ExportError(\r\n '[chart] Error while saving a chart.',\r\n 500\r\n ).setError(error);\r\n }\r\n }\r\n )\r\n );\r\n } else {\r\n log(2, '[chart] No correct pair found for the batch export.');\r\n }\r\n }\r\n\r\n // Await all exports are done\r\n const batchResults = await Promise.allSettled(batchFunctions);\r\n\r\n // Kill pool and close browser after finishing batch export\r\n await killPool();\r\n\r\n // Log errors if found\r\n batchResults.forEach((result, index) => {\r\n // Log the error with stack about the specific batch export\r\n if (result.reason) {\r\n logWithStack(\r\n 1,\r\n result.reason,\r\n `[chart] Batch export number ${index + 1} could not be correctly completed.`\r\n );\r\n }\r\n });\r\n } else {\r\n throw new ExportError(\r\n '[chart] No expected `export` options were found. Please provide the `batch` option to generate valid images.',\r\n 400\r\n );\r\n }\r\n}\r\n\r\n/**\r\n * Starts an export process. The `imageOptions` parameter is an object that\r\n * should include settings from the `export` and `customLogic` sections. It can\r\n * be a partial or complete set of options from these sections. If partial\r\n * options are provided, missing values will be merged with the current global\r\n * options.\r\n *\r\n * The `endCallback` function is invoked upon the completion of the export,\r\n * either successfully or with an error. The `error` object is provided\r\n * as the first argument, and the `data` object is the second, containing\r\n * the Base64 representation of the chart in the `result` property\r\n * and the complete set of options in the `options` property.\r\n *\r\n * @async\r\n * @function startExport\r\n *\r\n * @param {Object} imageOptions - The `imageOptions` object, which should\r\n * include settings from the `export` and `customLogic` sections. It can\r\n * be a partial or complete set of options from these sections. If the provided\r\n * options are partial, missing values will be merged with the current global\r\n * options.\r\n * @param {Function} endCallback - The callback function to be invoked upon\r\n * finalizing the export process or upon encountering an error. The first\r\n * argument is the `error` object, and the second argument is the `data` object,\r\n * which includes the Base64 representation of the chart in the `result`\r\n * property and the full set of options in the `options` property.\r\n *\r\n * @returns {Promise} This function does not return a value directly.\r\n * Instead, it communicates results via the `endCallback`.\r\n *\r\n * @throws {ExportError} Throws an `ExportError` if there is a problem with\r\n * processing input of any type. The error is passed into the `endCallback`\r\n * function and processed there.\r\n */\r\nexport async function startExport(imageOptions, endCallback) {\r\n try {\r\n // Check if provided options are in an object\r\n if (!isObject(imageOptions)) {\r\n throw new ExportError(\r\n '[chart] Incorrect value of the provided `imageOptions`. Needs to be an object.',\r\n 400\r\n );\r\n }\r\n\r\n // Merge additional options to the copy of the instance options\r\n const options = updateOptions(\r\n {\r\n export: imageOptions.export,\r\n customLogic: imageOptions.customLogic\r\n },\r\n true\r\n );\r\n\r\n // Get the `export` options\r\n const exportOptions = options.export;\r\n\r\n // Starting exporting process message\r\n log(4, '[chart] Starting the exporting process.');\r\n\r\n // Export using options from the file as an input\r\n if (exportOptions.infile !== null) {\r\n log(4, '[chart] Attempting to export from a file input.');\r\n\r\n let fileContent;\r\n try {\r\n // Try to read the file to get the string representation\r\n fileContent = readFileSync(\r\n getAbsolutePath(exportOptions.infile),\r\n 'utf8'\r\n );\r\n } catch (error) {\r\n throw new ExportError(\r\n '[chart] Error loading content from a file input.',\r\n 400\r\n ).setError(error);\r\n }\r\n\r\n // Check the file's extension\r\n if (exportOptions.infile.endsWith('.svg')) {\r\n // Set to the `svg` option\r\n exportOptions.svg = validateOption('svg', fileContent);\r\n } else if (exportOptions.infile.endsWith('.json')) {\r\n // Set to the `instr` option\r\n exportOptions.instr = validateOption('instr', fileContent);\r\n } else {\r\n throw new ExportError(\r\n '[chart] Incorrect value of the `infile` option.',\r\n 400\r\n );\r\n }\r\n }\r\n\r\n // Export using SVG as an input\r\n if (exportOptions.svg !== null) {\r\n log(4, '[chart] Attempting to export from an SVG input.');\r\n\r\n // SVG exports attempts counter\r\n ++getPoolStats().exportsFromSvgAttempts;\r\n\r\n // Export from an SVG string\r\n const result = await _exportFromSvg(\r\n sanitize(exportOptions.svg), // #209\r\n options\r\n );\r\n\r\n // SVG exports counter\r\n ++getPoolStats().exportsFromSvg;\r\n\r\n // Pass SVG export result to the end callback\r\n return endCallback(null, result);\r\n }\r\n\r\n // Export using options as an input\r\n if (exportOptions.instr !== null || exportOptions.options !== null) {\r\n log(4, '[chart] Attempting to export from options input.');\r\n\r\n // Options exports attempts counter\r\n ++getPoolStats().exportsFromOptionsAttempts;\r\n\r\n // Export from options\r\n const result = await _exportFromOptions(\r\n exportOptions.instr || exportOptions.options,\r\n options\r\n );\r\n\r\n // Options exports counter\r\n ++getPoolStats().exportsFromOptions;\r\n\r\n // Pass options export result to the end callback\r\n return endCallback(null, result);\r\n }\r\n\r\n // No input specified, pass an error message to the callback\r\n return endCallback(\r\n new ExportError(\r\n `[chart] No valid input specified. Check if at least one of the following parameters is correctly set: 'infile', 'instr', 'options', or 'svg'.`,\r\n 400\r\n )\r\n );\r\n } catch (error) {\r\n return endCallback(error);\r\n }\r\n}\r\n\r\n/**\r\n * Retrieves and returns the current status of the code execution permission.\r\n *\r\n * @function getAllowCodeExecution\r\n *\r\n * @returns {boolean} The value of the global `allowCodeExecution` option.\r\n */\r\nexport function getAllowCodeExecution() {\r\n return allowCodeExecution;\r\n}\r\n\r\n/**\r\n * Sets the code execution permission based on the provided boolean value.\r\n *\r\n * @function setAllowCodeExecution\r\n *\r\n * @param {boolean} value - The boolean value to be assigned to the global\r\n * `allowCodeExecution` option.\r\n */\r\nexport function setAllowCodeExecution(value) {\r\n allowCodeExecution = value;\r\n}\r\n\r\n/**\r\n * Exports from an SVG based input with the provided options.\r\n *\r\n * @async\r\n * @function _exportFromSvg\r\n *\r\n * @param {string} inputToExport - The SVG based input to be exported.\r\n * @param {Object} options - The configuration object containing complete set\r\n * of options.\r\n *\r\n * @returns {Promise} A Promise that resolves to a result of the export\r\n * process.\r\n *\r\n * @throws {ExportError} Throws an `ExportError` if there is not a correct SVG\r\n * input.\r\n */\r\nasync function _exportFromSvg(inputToExport, options) {\r\n // Check if it is SVG\r\n if (\r\n typeof inputToExport === 'string' &&\r\n (inputToExport.indexOf('= 0 || inputToExport.indexOf('= 0)\r\n ) {\r\n log(4, '[chart] Parsing input as SVG.');\r\n\r\n // Set the export input as SVG\r\n options.export.svg = inputToExport;\r\n\r\n // Reset the rest of the export input options\r\n options.export.instr = null;\r\n options.export.options = null;\r\n\r\n // Call the function with an SVG string as an export input\r\n return _prepareExport(options);\r\n } else {\r\n throw new ExportError('[chart] Not a correct SVG input.', 400);\r\n }\r\n}\r\n\r\n/**\r\n * Exports from an options based input with the provided options.\r\n *\r\n * @async\r\n * @function _exportFromOptions\r\n *\r\n * @param {string} inputToExport - The options based input to be exported.\r\n * @param {Object} options - The configuration object containing complete set\r\n * of options.\r\n *\r\n * @returns {Promise} A Promise that resolves to a result of the export\r\n * process.\r\n *\r\n * @throws {ExportError} Throws an `ExportError` if there is not a correct\r\n * chart options input.\r\n */\r\nasync function _exportFromOptions(inputToExport, options) {\r\n log(4, '[chart] Parsing input from options.');\r\n\r\n // Try to check, validate and parse to stringified options\r\n const stringifiedOptions = isAllowedConfig(\r\n inputToExport,\r\n true,\r\n options.customLogic.allowCodeExecution\r\n );\r\n\r\n // Check if a correct stringified options\r\n if (\r\n stringifiedOptions === null ||\r\n typeof stringifiedOptions !== 'string' ||\r\n !stringifiedOptions.startsWith('{') ||\r\n !stringifiedOptions.endsWith('}')\r\n ) {\r\n throw new ExportError(\r\n '[chart] Invalid configuration provided - Only options configurations and SVG are allowed for this server. If this is your server, JavaScript custom code can be enabled by starting the server with the `allowCodeExecution` options set to true.',\r\n 403\r\n );\r\n }\r\n\r\n // Set the export input as a stringified chart options\r\n options.export.instr = stringifiedOptions;\r\n\r\n // Reset the rest of the export input options\r\n options.export.svg = null;\r\n\r\n // Call the function with a stringified chart options\r\n return _prepareExport(options);\r\n}\r\n\r\n/**\r\n * Function for finalizing options and configurations before export.\r\n *\r\n * @async\r\n * @function _prepareExport\r\n *\r\n * @param {Object} options - The configuration object containing complete set\r\n * of options.\r\n *\r\n * @returns {Promise} A Promise that resolves to a result of the export\r\n * process.\r\n */\r\nasync function _prepareExport(options) {\r\n const { export: exportOptions, customLogic: customLogicOptions } = options;\r\n\r\n // Prepare the `type` option\r\n exportOptions.type = fixType(exportOptions.type, exportOptions.outfile);\r\n\r\n // Prepare the `outfile` option\r\n exportOptions.outfile = fixOutfile(exportOptions.type, exportOptions.outfile);\r\n\r\n // Prepare the `constr` option\r\n exportOptions.constr = fixConstr(exportOptions.constr);\r\n\r\n // Notify about the custom logic usage status\r\n log(\r\n 3,\r\n `[chart] The custom logic is ${customLogicOptions.allowCodeExecution ? 'allowed' : 'disallowed'}.`\r\n );\r\n\r\n // Prepare the custom logic options (`customCode`, `callback`, `resources`)\r\n _handleCustomLogic(customLogicOptions, customLogicOptions.allowCodeExecution);\r\n\r\n // Prepare the `globalOptions` and `themeOptions` options\r\n _handleGlobalAndTheme(\r\n exportOptions,\r\n customLogicOptions.allowFileResources,\r\n customLogicOptions.allowCodeExecution\r\n );\r\n\r\n // Prepare the `height`, `width`, and `scale` options\r\n options.export = {\r\n ...exportOptions,\r\n ..._findChartSize(exportOptions)\r\n };\r\n\r\n // Post the work to the pool\r\n return postWork(options);\r\n}\r\n\r\n/**\r\n * Calculates the `height`, `width` and `scale` for chart exports based\r\n * on the provided export options.\r\n *\r\n * The function prioritizes values in the following order:\r\n * 1. The `height`, `width`, `scale` from the `exportOptions`.\r\n * 2. Options from the chart configuration (from `exporting` and `chart`).\r\n * 3. Options from the global options (from `exporting` and `chart`).\r\n * 4. Options from the theme options (from `exporting` and `chart` sections).\r\n * 5. Fallback default values (`height = 400`, `width = 600`, `scale = 1`).\r\n *\r\n * @function _findChartSize\r\n *\r\n * @param {Object} exportOptions - The configuration object containing `export`\r\n * options.\r\n *\r\n * @returns {Object} The object containing calculated `height`, `width`\r\n * and `scale` values for the chart export.\r\n */\r\nfunction _findChartSize(exportOptions) {\r\n // Check the `options` and `instr` for chart and exporting sections\r\n const { chart: optionsChart, exporting: optionsExporting } =\r\n exportOptions.options || isAllowedConfig(exportOptions.instr) || false;\r\n\r\n // Check the `globalOptions` for chart and exporting sections\r\n const { chart: globalOptionsChart, exporting: globalOptionsExporting } =\r\n isAllowedConfig(exportOptions.globalOptions) || false;\r\n\r\n // Check the `themeOptions` for chart and exporting sections\r\n const { chart: themeOptionsChart, exporting: themeOptionsExporting } =\r\n isAllowedConfig(exportOptions.themeOptions) || false;\r\n\r\n // Find the `scale` value:\r\n // - It cannot be lower than 0.1\r\n // - It cannot be higher than 5.0\r\n // - It must be rounded to 2 decimal places (e.g. 0.23234 -> 0.23)\r\n const scale = roundNumber(\r\n Math.max(\r\n 0.1,\r\n Math.min(\r\n exportOptions.scale ||\r\n optionsExporting?.scale ||\r\n globalOptionsExporting?.scale ||\r\n themeOptionsExporting?.scale ||\r\n exportOptions.defaultScale ||\r\n 1,\r\n 5.0\r\n )\r\n ),\r\n 2\r\n );\r\n\r\n // Find the `height` value\r\n const height =\r\n exportOptions.height ||\r\n optionsExporting?.sourceHeight ||\r\n optionsChart?.height ||\r\n globalOptionsExporting?.sourceHeight ||\r\n globalOptionsChart?.height ||\r\n themeOptionsExporting?.sourceHeight ||\r\n themeOptionsChart?.height ||\r\n exportOptions.defaultHeight ||\r\n 400;\r\n\r\n // Find the `width` value\r\n const width =\r\n exportOptions.width ||\r\n optionsExporting?.sourceWidth ||\r\n optionsChart?.width ||\r\n globalOptionsExporting?.sourceWidth ||\r\n globalOptionsChart?.width ||\r\n themeOptionsExporting?.sourceWidth ||\r\n themeOptionsChart?.width ||\r\n exportOptions.defaultWidth ||\r\n 600;\r\n\r\n // Gather `height`, `width` and `scale` information in one object\r\n const size = { height, width, scale };\r\n\r\n // Get rid of potential `px` and `%`\r\n for (let [param, value] of Object.entries(size)) {\r\n size[param] =\r\n typeof value === 'string' ? +value.replace(/px|%/gi, '') : value;\r\n }\r\n\r\n // Return the size object\r\n return size;\r\n}\r\n\r\n/**\r\n * Handles the execution of custom logic options, including loading `resources`,\r\n * `customCode`, and `callback`. If code execution is allowed, it processes\r\n * the custom logic options accordingly. If code execution is not allowed,\r\n * it disables the usage of resources, custom code and callback.\r\n *\r\n * @function _handleCustomLogic\r\n *\r\n * @param {Object} customLogicOptions - The configuration object containing\r\n * `customLogic` options.\r\n * @param {boolean} allowCodeExecution - A flag indicating whether code\r\n * execution is allowed.\r\n *\r\n * @throws {ExportError} Throws an `ExportError` if code execution\r\n * is not allowed but custom logic options are still provided.\r\n */\r\nfunction _handleCustomLogic(customLogicOptions, allowCodeExecution) {\r\n // In case of allowing code execution\r\n if (allowCodeExecution) {\r\n // Process the `resources` option\r\n if (typeof customLogicOptions.resources === 'string') {\r\n // Custom stringified resources\r\n customLogicOptions.resources = _handleResources(\r\n customLogicOptions.resources,\r\n customLogicOptions.allowFileResources,\r\n true\r\n );\r\n } else if (!customLogicOptions.resources) {\r\n try {\r\n // Load the default one\r\n customLogicOptions.resources = _handleResources(\r\n readFileSync(getAbsolutePath('resources.json'), 'utf8'),\r\n customLogicOptions.allowFileResources,\r\n true\r\n );\r\n } catch (error) {\r\n log(2, '[chart] Unable to load the default `resources.json` file.');\r\n }\r\n }\r\n\r\n // Process the `customCode` option\r\n try {\r\n // Try to load custom code and wrap around it in a self invoking function\r\n customLogicOptions.customCode = wrapAround(\r\n customLogicOptions.customCode,\r\n customLogicOptions.allowFileResources\r\n );\r\n\r\n // Validate the option\r\n customLogicOptions.customCode = validateOption(\r\n 'customCode',\r\n customLogicOptions.customCode\r\n );\r\n } catch (error) {\r\n logWithStack(2, error, '[chart] The `customCode` cannot be loaded.');\r\n\r\n // In case of an error, set the option with null\r\n customLogicOptions.customCode = null;\r\n }\r\n\r\n // Process the `callback` option\r\n try {\r\n // Try to load callback function\r\n customLogicOptions.callback = wrapAround(\r\n customLogicOptions.callback,\r\n customLogicOptions.allowFileResources,\r\n true\r\n );\r\n\r\n // Validate the option\r\n customLogicOptions.callback = validateOption(\r\n 'callback',\r\n customLogicOptions.callback\r\n );\r\n } catch (error) {\r\n logWithStack(2, error, '[chart] The `callback` cannot be loaded.');\r\n\r\n // In case of an error, set the option with null\r\n customLogicOptions.callback = null;\r\n }\r\n\r\n // Check if there is the `customCode` present\r\n if ([null, undefined].includes(customLogicOptions.customCode)) {\r\n log(3, '[chart] No value for the `customCode` option found.');\r\n }\r\n\r\n // Check if there is the `callback` present\r\n if ([null, undefined].includes(customLogicOptions.callback)) {\r\n log(3, '[chart] No value for the `callback` option found.');\r\n }\r\n\r\n // Check if there is the `resources` present\r\n if ([null, undefined].includes(customLogicOptions.resources)) {\r\n log(3, '[chart] No value for the `resources` option found.');\r\n }\r\n } else {\r\n // If the `allowCodeExecution` flag is set to false, we should refuse\r\n // the usage of the `callback`, `resources`, and `customCode` options.\r\n // Additionally, the worker will refuse to run arbitrary JavaScript.\r\n if (\r\n customLogicOptions.callback ||\r\n customLogicOptions.resources ||\r\n customLogicOptions.customCode\r\n ) {\r\n // Reset all custom code options\r\n customLogicOptions.callback = null;\r\n customLogicOptions.resources = null;\r\n customLogicOptions.customCode = null;\r\n\r\n // Send a message saying that the exporter does not support these settings\r\n throw new ExportError(\r\n `[chart] The 'callback', 'resources', and 'customCode' options have been disabled for this server.`,\r\n 403\r\n );\r\n }\r\n }\r\n}\r\n\r\n/**\r\n * Handles and validates resources from the `resources` option for export.\r\n *\r\n * @function _handleResources\r\n *\r\n * @param {(Object|string|null)} [resources=null] - The resources to be handled.\r\n * Can be either a JSON object, stringified JSON, a path to a JSON file,\r\n * or null. The default value is `null`.\r\n * @param {boolean} allowFileResources - A flag indicating whether loading\r\n * resources from files is allowed.\r\n * @param {boolean} allowCodeExecution - A flag indicating whether code\r\n * execution is allowed.\r\n *\r\n * @returns {(Object|null)} The handled resources or null if no valid resources\r\n * are found.\r\n */\r\nfunction _handleResources(\r\n resources = null,\r\n allowFileResources,\r\n allowCodeExecution\r\n) {\r\n // List of allowed sections in the resources JSON\r\n const allowedProps = ['js', 'css', 'files'];\r\n\r\n let handledResources = resources;\r\n let correctResources = false;\r\n\r\n // Try to load resources from a file\r\n if (allowFileResources && resources.endsWith('.json')) {\r\n try {\r\n handledResources = isAllowedConfig(\r\n readFileSync(getAbsolutePath(resources), 'utf8'),\r\n false,\r\n allowCodeExecution\r\n );\r\n } catch {\r\n return null;\r\n }\r\n } else {\r\n // Try to get JSON\r\n handledResources = isAllowedConfig(resources, false, allowCodeExecution);\r\n\r\n // Get rid of the files section\r\n if (handledResources && !allowFileResources) {\r\n delete handledResources.files;\r\n }\r\n }\r\n\r\n // Filter from unnecessary properties\r\n for (const propName in handledResources) {\r\n if (!allowedProps.includes(propName)) {\r\n delete handledResources[propName];\r\n } else if (!correctResources) {\r\n correctResources = true;\r\n }\r\n }\r\n\r\n // Check if at least one of allowed properties is present\r\n if (!correctResources) {\r\n return null;\r\n }\r\n\r\n // Handle files section\r\n if (handledResources.files) {\r\n handledResources.files = handledResources.files.map((item) => item.trim());\r\n if (!handledResources.files || handledResources.files.length <= 0) {\r\n delete handledResources.files;\r\n }\r\n }\r\n\r\n // Validate option\r\n handledResources = validateOption('resources', handledResources);\r\n\r\n // Return resources\r\n return handledResources;\r\n}\r\n\r\n/**\r\n * Handles the loading and validation of the `globalOptions` and `themeOptions`\r\n * in the export options. If the option is a string and references a JSON file\r\n * (when the `allowFileResources` is true), it reads and parses the file.\r\n * Otherwise, it attempts to parse the string or object as JSON. If any errors\r\n * occur during this process, the option is set to null. If there is an error\r\n * loading or parsing the `globalOptions` or `themeOptions`, the error is logged\r\n * and the option is set to null.\r\n *\r\n * @function _handleGlobalAndTheme\r\n *\r\n * @param {Object} exportOptions - The configuration object containing `export`\r\n * options.\r\n * @param {boolean} allowFileResources - A flag indicating whether loading\r\n * resources from files is allowed.\r\n * @param {boolean} allowCodeExecution - A flag indicating whether code\r\n * execution is allowed.\r\n */\r\nfunction _handleGlobalAndTheme(\r\n exportOptions,\r\n allowFileResources,\r\n allowCodeExecution\r\n) {\r\n // Check the `globalOptions` and `themeOptions` options\r\n ['globalOptions', 'themeOptions'].forEach((optionsName) => {\r\n try {\r\n // Check if the option exists\r\n if (exportOptions[optionsName]) {\r\n // Check if it is a string and a file name with the `.json` extension\r\n if (\r\n allowFileResources &&\r\n typeof exportOptions[optionsName] === 'string' &&\r\n exportOptions[optionsName].endsWith('.json')\r\n ) {\r\n // Check if the file content can be a config, and save it as a string\r\n exportOptions[optionsName] = isAllowedConfig(\r\n readFileSync(getAbsolutePath(exportOptions[optionsName]), 'utf8'),\r\n true,\r\n allowCodeExecution\r\n );\r\n } else {\r\n // Check if the value can be a config, and save it as a string\r\n exportOptions[optionsName] = isAllowedConfig(\r\n exportOptions[optionsName],\r\n true,\r\n allowCodeExecution\r\n );\r\n }\r\n\r\n // Validate the option\r\n exportOptions[optionsName] = validateOption(\r\n optionsName,\r\n exportOptions[optionsName]\r\n );\r\n }\r\n } catch (error) {\r\n logWithStack(\r\n 2,\r\n error,\r\n `[chart] The \\`${optionsName}\\` cannot be loaded.`\r\n );\r\n\r\n // In case of an error, set the option with null\r\n exportOptions[optionsName] = null;\r\n }\r\n });\r\n\r\n // Check if there is the `globalOptions` present\r\n if ([null, undefined].includes(exportOptions.globalOptions)) {\r\n log(3, '[chart] No value for the `globalOptions` option found.');\r\n }\r\n\r\n // Check if there is the `themeOptions` present\r\n if ([null, undefined].includes(exportOptions.themeOptions)) {\r\n log(3, '[chart] No value for the `themeOptions` option found.');\r\n }\r\n}\r\n\r\nexport default {\r\n singleExport,\r\n batchExport,\r\n startExport,\r\n getAllowCodeExecution,\r\n setAllowCodeExecution\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * @overview This module provides utility functions for managing intervals\r\n * and timeouts in a centralized manner. It maintains a registry of all active\r\n * timers and allows for their efficient cleanup when needed. This can be useful\r\n * in applications where proper resource management and clean shutdown of timers\r\n * are critical to avoid memory leaks or unintended behavior.\r\n */\r\n\r\nimport { log } from './logger.js';\r\n\r\n// Array that contains ids of all ongoing intervals and timeouts\r\nconst timerIds = [];\r\n\r\n/**\r\n * Adds id of the `setInterval` or `setTimeout` and to the `timerIds` array.\r\n *\r\n * @function addTimer\r\n *\r\n * @param {NodeJS.Timeout} id - Id of an interval or a timeout.\r\n */\r\nexport function addTimer(id) {\r\n timerIds.push(id);\r\n}\r\n\r\n/**\r\n * Clears all of ongoing intervals and timeouts by ids gathered\r\n * in the `timerIds` array.\r\n *\r\n * @function clearAllTimers\r\n */\r\nexport function clearAllTimers() {\r\n log(4, `[timer] Clearing all registered intervals and timeouts.`);\r\n for (const id of timerIds) {\r\n clearInterval(id);\r\n clearTimeout(id);\r\n }\r\n}\r\n\r\nexport default {\r\n addTimer,\r\n clearAllTimers\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * @overview Provides middleware functions for logging errors with stack traces\r\n * and handling error responses in an Express application.\r\n */\r\n\r\nimport { getOptions } from '../../config.js';\r\nimport { logWithStack } from '../../logger.js';\r\n\r\n/**\r\n * Middleware for logging errors with stack trace and handling error response.\r\n *\r\n * @function logErrorMiddleware\r\n *\r\n * @param {Error} error - The error object.\r\n * @param {Express.Request} request - The Express request object.\r\n * @param {Express.Response} response - The Express response object.\r\n * @param {Function} next - The next middleware function.\r\n *\r\n * @returns {undefined} The call to the next middleware function with\r\n * the passed error.\r\n */\r\nfunction logErrorMiddleware(error, request, response, next) {\r\n // Display the error with stack in a correct format\r\n logWithStack(1, error);\r\n\r\n // Delete the stack for the environment other than the development\r\n if (getOptions().other.nodeEnv !== 'development') {\r\n delete error.stack;\r\n }\r\n\r\n // Call the `returnErrorMiddleware` middleware\r\n return next(error);\r\n}\r\n\r\n/**\r\n * Middleware for returning error response.\r\n *\r\n * @function returnErrorMiddleware\r\n *\r\n * @param {Error} error - The error object.\r\n * @param {Express.Request} request - The Express request object.\r\n * @param {Express.Response} response - The Express response object.\r\n * @param {Function} next - The next middleware function.\r\n */\r\nfunction returnErrorMiddleware(error, request, response, next) {\r\n // Gather all requied information for the response\r\n const { message, stack } = error;\r\n\r\n // Use the error's status code or the default 400\r\n const statusCode = error.statusCode || 400;\r\n\r\n // Set and return response\r\n response.status(statusCode).json({ statusCode, message, stack });\r\n}\r\n\r\n/**\r\n * Adds the error middlewares to the passed express app instance.\r\n *\r\n * @param {Express} app - The Express app instance.\r\n */\r\nexport default function errorMiddleware(app) {\r\n // Add log error middleware\r\n app.use(logErrorMiddleware);\r\n\r\n // Add set status and return error middleware\r\n app.use(returnErrorMiddleware);\r\n}\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * @overview Provides middleware functions for configuring and enabling rate\r\n * limiting in an Express application.\r\n */\r\n\r\nimport rateLimit from 'express-rate-limit';\r\n\r\nimport { log } from '../../logger.js';\r\n\r\nimport ExportError from '../../errors/ExportError.js';\r\n\r\n/**\r\n * Middleware for enabling rate limiting on the specified Express app.\r\n *\r\n * @param {Express} app - The Express app instance.\r\n *\r\n * @param {Object} rateLimitingOptions - The configuration object containing\r\n * `rateLimiting` options.\r\n *\r\n * @throws {ExportError} Throws an `ExportError` if could not configure and set\r\n * the rate limiting options.\r\n */\r\nexport default function rateLimitingMiddleware(app, rateLimitingOptions) {\r\n try {\r\n // Check if the rate limiting is enabled and the app exists\r\n if (app && rateLimitingOptions.enable) {\r\n const message =\r\n 'Too many requests, you have been rate limited. Please try again later.';\r\n\r\n // Options for the rate limiter\r\n const rateOptions = {\r\n window: rateLimitingOptions.window || 1,\r\n maxRequests: rateLimitingOptions.maxRequests || 30,\r\n delay: rateLimitingOptions.delay || 0,\r\n trustProxy: rateLimitingOptions.trustProxy || false,\r\n skipKey: rateLimitingOptions.skipKey || null,\r\n skipToken: rateLimitingOptions.skipToken || null\r\n };\r\n\r\n // Set if behind a proxy\r\n if (rateOptions.trustProxy) {\r\n app.enable('trust proxy');\r\n }\r\n\r\n // Create a limiter\r\n const limiter = rateLimit({\r\n // Time frame for which requests are checked and remembered\r\n windowMs: rateOptions.window * 60 * 1000,\r\n // Limit each IP to 100 requests per `windowMs`\r\n limit: rateOptions.maxRequests,\r\n // Disable delaying, full speed until the max limit is reached\r\n delayMs: rateOptions.delay,\r\n handler: (request, response) => {\r\n response.format({\r\n json: () => {\r\n response.status(429).send({ message });\r\n },\r\n default: () => {\r\n response.status(429).send(message);\r\n }\r\n });\r\n },\r\n skip: (request) => {\r\n // Allow bypassing the limiter if a valid key/token has been sent\r\n if (\r\n rateOptions.skipKey !== null &&\r\n rateOptions.skipToken !== null &&\r\n request.query.key === rateOptions.skipKey &&\r\n request.query.access_token === rateOptions.skipToken\r\n ) {\r\n log(4, '[rate limiting] Skipping rate limiter.');\r\n return true;\r\n }\r\n return false;\r\n }\r\n });\r\n\r\n // Use a limiter as a middleware\r\n app.use(limiter);\r\n\r\n log(\r\n 3,\r\n `[rate limiting] Enabled rate limiting with ${rateOptions.maxRequests} requests per ${rateOptions.window} minute for each IP, trusting proxy: ${rateOptions.trustProxy}.`\r\n );\r\n }\r\n } catch (error) {\r\n throw new ExportError(\r\n '[rate limiting] Could not configure and set the rate limiting options.',\r\n 500\r\n ).setError(error);\r\n }\r\n}\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * @overview Provides middleware functions for validating incoming HTTP requests\r\n * in an Express application. This module ensures that requests contain\r\n * appropriate content types and valid request bodies, including proper JSON\r\n * structures and chart data for exports. It checks for potential issues such\r\n * as missing or malformed data, private range URLs in SVG payloads, and allows\r\n * for flexible options validation. The middleware logs detailed information\r\n * and handles errors related to incorrect payloads, chart data, and private URL\r\n * usage.\r\n */\r\n\r\nimport { v4 as uuid } from 'uuid';\r\n\r\nimport { getAllowCodeExecution } from '../../chart.js';\r\nimport { isAllowedConfig, validateOptions } from '../../config.js';\r\nimport { log } from '../../logger.js';\r\nimport { isObjectEmpty, isPrivateRangeUrlFound } from '../../utils.js';\r\n\r\nimport ExportError from '../../errors/ExportError.js';\r\n\r\n/**\r\n * Middleware for validating the content-type header.\r\n *\r\n * @function contentTypeMiddleware\r\n *\r\n * @param {Express.Request} request - The Express request object.\r\n * @param {Express.Response} response - The Express response object.\r\n * @param {Function} next - The next middleware function.\r\n *\r\n * @returns {undefined} The call to the next middleware function.\r\n *\r\n * @throws {ExportError} Throws an `ExportError` if the content-type\r\n * is not correct.\r\n */\r\nfunction contentTypeMiddleware(request, response, next) {\r\n try {\r\n // Get the content type header\r\n const contentType = request.headers['content-type'] || '';\r\n\r\n // Allow only JSON, URL-encoded and form data without files types of data\r\n if (\r\n !contentType.includes('application/json') &&\r\n !contentType.includes('application/x-www-form-urlencoded') &&\r\n !contentType.includes('multipart/form-data')\r\n ) {\r\n throw new ExportError(\r\n '[validation] Content-Type must be application/json, application/x-www-form-urlencoded, or multipart/form-data.',\r\n 415\r\n );\r\n }\r\n\r\n // Call the `requestBodyMiddleware` middleware\r\n return next();\r\n } catch (error) {\r\n return next(error);\r\n }\r\n}\r\n\r\n/**\r\n * Middleware for validating the request's body.\r\n *\r\n * @function requestBodyMiddleware\r\n *\r\n * @param {Express.Request} request - The Express request object.\r\n * @param {Express.Response} response - The Express response object.\r\n * @param {Function} next - The next middleware function.\r\n *\r\n * @returns {undefined} The call to the next middleware function.\r\n *\r\n * @throws {ExportError} Throws an `ExportError` if the body is not correct.\r\n * @throws {ExportError} Throws an `ExportError` if the chart data from the body\r\n * is not correct.\r\n * @throws {ExportError} Throws an `ExportError` in case of the private range\r\n * url error.\r\n */\r\nfunction requestBodyMiddleware(request, response, next) {\r\n try {\r\n // Get the request body\r\n const body = request.body;\r\n\r\n // Create a unique ID for a request\r\n const requestId = uuid();\r\n\r\n // Throw an error if there is no correct body\r\n if (!body || isObjectEmpty(body)) {\r\n log(\r\n 2,\r\n `[validation] Request [${requestId}] - The request from ${\r\n request.headers['x-forwarded-for'] || request.connection.remoteAddress\r\n } was incorrect. Received payload is empty.`\r\n );\r\n\r\n throw new ExportError(\r\n `[validation] Request [${requestId}] - The request body is required. Please ensure that your Content-Type header is correct. Accepted types are 'application/json' and 'multipart/form-data'.`,\r\n 400\r\n );\r\n }\r\n\r\n // Get the `allowCodeExecution` option for the server\r\n const allowCodeExecution = getAllowCodeExecution();\r\n\r\n // Find a correct chart options\r\n const instr = isAllowedConfig(\r\n // Use one of the below\r\n body.instr || body.options || body.infile || body.data,\r\n // Stringify options\r\n true,\r\n // Allow or disallow functions\r\n allowCodeExecution\r\n );\r\n\r\n // Throw an error if there is no correct chart data\r\n if (instr === null && !body.svg) {\r\n log(\r\n 2,\r\n `[validation] Request [${requestId}] - The request from ${\r\n request.headers['x-forwarded-for'] || request.connection.remoteAddress\r\n } was incorrect. Received payload is missing correct chart data for export: ${JSON.stringify(body)}.`\r\n );\r\n\r\n throw new ExportError(\r\n `Request [${requestId}] - [validation] No correct chart data found. Ensure that you are using either application/json or multipart/form-data headers. If sending JSON, make sure the chart data is in the 'infile', 'options', or 'data' attribute. If sending SVG, ensure it is in the 'svg' attribute.`,\r\n 400\r\n );\r\n }\r\n\r\n // Throw an error if test of xlink:href elements from payload's SVG fails\r\n if (body.svg && isPrivateRangeUrlFound(body.svg)) {\r\n throw new ExportError(\r\n `Request [${requestId}] - [validation] SVG potentially contain at least one forbidden URL in 'xlink:href' element. Please review the SVG content and ensure that all referenced URLs comply with security policies.`,\r\n 400\r\n );\r\n }\r\n\r\n // Validate the request options and store parsed structure in the request\r\n request.validatedOptions = validateOptions({\r\n // Set the created ID as a `requestId` property in the options\r\n requestId,\r\n export: {\r\n instr,\r\n svg: body.svg,\r\n outfile:\r\n body.outfile ||\r\n `${request.params.filename || 'chart'}.${body.type || 'png'}`,\r\n type: body.type,\r\n constr: body.constr,\r\n b64: body.b64,\r\n noDownload: body.noDownload,\r\n height: body.height,\r\n width: body.width,\r\n scale: body.scale,\r\n globalOptions: isAllowedConfig(\r\n body.globalOptions,\r\n true,\r\n allowCodeExecution\r\n ),\r\n themeOptions: isAllowedConfig(\r\n body.themeOptions,\r\n true,\r\n allowCodeExecution\r\n )\r\n },\r\n customLogic: {\r\n allowCodeExecution,\r\n allowFileResources: false,\r\n customCode: body.customCode,\r\n callback: body.callback,\r\n resources: isAllowedConfig(body.resources, true, allowCodeExecution)\r\n }\r\n });\r\n\r\n // Call the next middleware\r\n return next();\r\n } catch (error) {\r\n return next(error);\r\n }\r\n}\r\n\r\n/**\r\n * Adds the validation middlewares to the passed express app instance.\r\n *\r\n * @param {Express} app - The Express app instance.\r\n */\r\nexport default function validationMiddleware(app) {\r\n // Add content type validation middleware\r\n app.post(['/', '/:filename'], contentTypeMiddleware);\r\n\r\n // Add request body request validation middleware\r\n app.post(['/', '/:filename'], requestBodyMiddleware);\r\n}\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * @overview Defines the export routes and logic for handling chart export\r\n * requests in an Express server. This module processes incoming requests\r\n * to export charts in various formats (e.g. JPEG, PNG, PDF, SVG). It integrates\r\n * with Highcharts' core functionalities and supports both immediate download\r\n * responses and Base64-encoded content returns. The code also features\r\n * benchmarking for performance monitoring.\r\n */\r\n\r\nimport { startExport } from '../../chart.js';\r\nimport { log } from '../../logger.js';\r\nimport { getBase64, measureTime } from '../../utils.js';\r\n\r\nimport ExportError from '../../errors/ExportError.js';\r\n\r\n// Reversed MIME types\r\nconst reversedMime = {\r\n png: 'image/png',\r\n jpeg: 'image/jpeg',\r\n gif: 'image/gif',\r\n pdf: 'application/pdf',\r\n svg: 'image/svg+xml'\r\n};\r\n\r\n/**\r\n * Handles the export requests from the client.\r\n *\r\n * @async\r\n * @function requestExport\r\n *\r\n * @param {Express.Request} request - The Express request object.\r\n * @param {Express.Response} response - The Express response object.\r\n * @param {Function} next - The next middleware function.\r\n *\r\n * @returns {Promise} A Promise that resolves once the export process\r\n * is complete.\r\n */\r\nasync function requestExport(request, response, next) {\r\n try {\r\n // Start counting time for a request\r\n const requestCounter = measureTime();\r\n\r\n // In case the connection is closed, force to abort further actions\r\n let connectionAborted = false;\r\n request.socket.on('close', (hadErrors) => {\r\n if (hadErrors) {\r\n connectionAborted = true;\r\n }\r\n });\r\n\r\n // Get the options previously validated in the validation middleware\r\n const requestOptions = request.validatedOptions;\r\n\r\n // Get the request id\r\n const requestId = requestOptions.requestId;\r\n\r\n // Info about an incoming request with correct data\r\n log(4, `[export] Request [${requestId}] - Got an incoming HTTP request.`);\r\n\r\n // Start the export process\r\n await startExport(requestOptions, (error, data) => {\r\n // Remove the close event from the socket\r\n request.socket.removeAllListeners('close');\r\n\r\n // If the connection was closed, do nothing\r\n if (connectionAborted) {\r\n log(\r\n 3,\r\n `[export] Request [${requestId}] - The client closed the connection before the chart finished processing.`\r\n );\r\n return;\r\n }\r\n\r\n // If error, log it and send it to the error middleware\r\n if (error) {\r\n throw error;\r\n }\r\n\r\n // If data is missing, log the message and send it to the error middleware\r\n if (!data || !data.result) {\r\n log(\r\n 2,\r\n `[export] Request [${requestId}] - Request from ${\r\n request.headers['x-forwarded-for'] ||\r\n request.connection.remoteAddress\r\n } was incorrect. Received result is ${data.result}.`\r\n );\r\n\r\n throw new ExportError(\r\n `[export] Request [${requestId}] - Unexpected return of the export result from the chart generation. Please check your request data.`,\r\n 400\r\n );\r\n }\r\n\r\n // Return the result in an appropriate format\r\n if (data.result) {\r\n log(\r\n 3,\r\n `[export] Request [${requestId}] - The whole exporting process took ${requestCounter()}ms.`\r\n );\r\n\r\n // Get the `type`, `b64`, `noDownload`, and `outfile` from options\r\n const { type, b64, noDownload, outfile } = data.options.export;\r\n\r\n // If only Base64 is required, return it\r\n if (b64) {\r\n return response.send(getBase64(data.result, type));\r\n }\r\n\r\n // Set correct content type\r\n response.header('Content-Type', reversedMime[type] || 'image/png');\r\n\r\n // Decide whether to download or not chart file\r\n if (!noDownload) {\r\n response.attachment(outfile);\r\n }\r\n\r\n // If SVG, return plain content, otherwise a b64 string from a buffer\r\n return type === 'svg'\r\n ? response.send(data.result)\r\n : response.send(Buffer.from(data.result, 'base64'));\r\n }\r\n });\r\n } catch (error) {\r\n return next(error);\r\n }\r\n}\r\n\r\n/**\r\n * Adds the `export` routes.\r\n *\r\n * @function exportRoutes\r\n *\r\n * @param {Express} app - The Express app instance.\r\n */\r\nexport default function exportRoutes(app) {\r\n /**\r\n * Adds the POST '/' - A route for handling POST requests at the root\r\n * endpoint.\r\n */\r\n app.post('/', requestExport);\r\n\r\n /**\r\n * Adds the POST '/:filename' - A route for handling POST requests with\r\n * a specified filename parameter.\r\n */\r\n app.post('/:filename', requestExport);\r\n}\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * @overview Defines an Express route for server health monitoring, including\r\n * uptime, success rates, and other server statistics.\r\n */\r\n\r\nimport { readFileSync } from 'fs';\r\nimport { join } from 'path';\r\n\r\nimport { getHighchartsVersion } from '../../cache.js';\r\nimport { log } from '../../logger.js';\r\nimport { getPoolInfoJSON, getPoolStats } from '../../pool.js';\r\nimport { addTimer } from '../../timer.js';\r\nimport { __dirname, getNewDateTime } from '../../utils.js';\r\n\r\n// Set the start date of the server\r\nconst serverStartTime = new Date();\r\n\r\n// Get the `package.json` content\r\nconst packageFile = JSON.parse(\r\n readFileSync(join(__dirname, 'package.json'), 'utf8')\r\n);\r\n\r\n// An array for success rate ratios\r\nconst successRates = [];\r\n\r\n// Record every minute\r\nconst recordInterval = 60 * 1000;\r\n\r\n// 30 minutes\r\nconst windowSize = 30;\r\n\r\n/**\r\n * Calculates moving average indicator based on the data from the `successRates`\r\n * array.\r\n *\r\n * @function _calculateMovingAverage\r\n *\r\n * @returns {number} A moving average for success ratio of the server exports.\r\n */\r\nfunction _calculateMovingAverage() {\r\n return successRates.reduce((a, b) => a + b, 0) / successRates.length;\r\n}\r\n\r\n/**\r\n * Starts the interval responsible for calculating current success rate ratio\r\n * and collects records to the `successRates` array.\r\n *\r\n * @function _startSuccessRate\r\n *\r\n * @returns {NodeJS.Timeout} Id of an interval.\r\n */\r\nfunction _startSuccessRate() {\r\n return setInterval(() => {\r\n const stats = getPoolStats();\r\n const successRatio =\r\n stats.exportsAttempted === 0\r\n ? 1\r\n : (stats.exportsPerformed / stats.exportsAttempted) * 100;\r\n\r\n successRates.push(successRatio);\r\n if (successRates.length > windowSize) {\r\n successRates.shift();\r\n }\r\n }, recordInterval);\r\n}\r\n\r\n/**\r\n * Adds the `health` routes.\r\n *\r\n * @function healthRoutes\r\n *\r\n * @param {Express} app - The Express app instance.\r\n */\r\nexport default function healthRoutes(app) {\r\n // Start processing success rate ratio interval and save its id to the array\r\n // for the graceful clearing on shutdown with injected `addTimer` funtion\r\n addTimer(_startSuccessRate());\r\n\r\n /**\r\n * Adds the GET '/health' - A route for getting the basic stats of the server.\r\n */\r\n app.get('/health', (request, response, next) => {\r\n try {\r\n log(4, '[health] Returning server health.');\r\n\r\n const stats = getPoolStats();\r\n const period = successRates.length;\r\n const movingAverage = _calculateMovingAverage();\r\n\r\n // Send the server's statistics\r\n response.send({\r\n // Status and times\r\n status: 'OK',\r\n bootTime: serverStartTime,\r\n uptime: `${Math.floor((getNewDateTime() - serverStartTime.getTime()) / 1000 / 60)} minutes`,\r\n\r\n // Versions\r\n serverVersion: packageFile.version,\r\n highchartsVersion: getHighchartsVersion(),\r\n\r\n // Exports\r\n averageExportTime: stats.timeSpentAverage,\r\n attemptedExports: stats.exportsAttempted,\r\n performedExports: stats.exportsPerformed,\r\n failedExports: stats.exportsDropped,\r\n sucessRatio: (stats.exportsPerformed / stats.exportsAttempted) * 100,\r\n\r\n // Pool\r\n pool: getPoolInfoJSON(),\r\n\r\n // Moving average\r\n period,\r\n movingAverage,\r\n message:\r\n isNaN(movingAverage) || !successRates.length\r\n ? 'Too early to report. No exports made yet. Please check back soon.'\r\n : `Last ${period} minutes had a success rate of ${movingAverage.toFixed(2)}%.`,\r\n\r\n // SVG and JSON exports\r\n svgExports: stats.exportsFromSvg,\r\n jsonExports: stats.exportsFromOptions,\r\n svgExportsAttempts: stats.exportsFromSvgAttempts,\r\n jsonExportsAttempts: stats.exportsFromOptionsAttempts\r\n });\r\n } catch (error) {\r\n return next(error);\r\n }\r\n });\r\n}\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * @overview Defines an Express route for serving the UI for the export server\r\n * when enabled.\r\n */\r\n\r\nimport { join } from 'path';\r\n\r\nimport { getOptions } from '../../config.js';\r\nimport { log } from '../../logger.js';\r\nimport { __dirname } from '../../utils.js';\r\n\r\n/**\r\n * Adds the `ui` routes.\r\n *\r\n * @function uiRoutes\r\n *\r\n * @param {Express} app - The Express app instance.\r\n */\r\nexport default function uiRoutes(app) {\r\n /**\r\n * Adds the GET '/' - A route for a UI when enabled on the export server.\r\n */\r\n app.get(getOptions().ui.route || '/', (request, response, next) => {\r\n try {\r\n log(4, '[ui] Returning UI for the export.');\r\n\r\n response.sendFile(join(__dirname, 'public', 'index.html'), {\r\n acceptRanges: false\r\n });\r\n } catch (error) {\r\n return next(error);\r\n }\r\n });\r\n}\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * @overview Defines an Express route for updating the Highcharts version\r\n * on the server, with authentication and validation.\r\n */\r\n\r\nimport { getHighchartsVersion, updateHighchartsVersion } from '../../cache.js';\r\nimport { validateOption } from '../../config.js';\r\nimport { log } from '../../logger.js';\r\nimport { envs } from '../../validation.js';\r\n\r\nimport ExportError from '../../errors/ExportError.js';\r\n\r\n/**\r\n * Adds the `version_change` routes.\r\n *\r\n * @function versionChangeRoutes\r\n *\r\n * @param {Express} app - The Express app instance.\r\n */\r\nexport default function versionChangeRoutes(app) {\r\n /**\r\n * Adds the POST '/version_change/:newVersion' - A route for changing\r\n * the Highcharts version on the server.\r\n */\r\n app.post('/version_change/:newVersion', async (request, response, next) => {\r\n try {\r\n log(4, '[version] Changing Highcharts version.');\r\n\r\n // Get the token directly from envs\r\n const adminToken = envs.HIGHCHARTS_ADMIN_TOKEN;\r\n\r\n // Check the existence of the token\r\n if (!adminToken || !adminToken.length) {\r\n throw new ExportError(\r\n '[version] The server is not configured to perform run-time version changes: HIGHCHARTS_ADMIN_TOKEN is not set.',\r\n 401\r\n );\r\n }\r\n\r\n // Get the token from the hc-auth header\r\n const token = request.get('hc-auth');\r\n\r\n // Check if the hc-auth header contain a correct token\r\n if (!token || token !== adminToken) {\r\n throw new ExportError(\r\n '[version] Invalid or missing token: Set the token in the hc-auth header.',\r\n 401\r\n );\r\n }\r\n\r\n // Compare versions\r\n let newVersion = request.params.newVersion;\r\n\r\n // Validate the version\r\n try {\r\n newVersion = validateOption('version', request.params.newVersion);\r\n } catch (error) {\r\n throw new ExportError(\r\n `[version] Version is incorrect: ${error.message}`,\r\n 400\r\n ).setError(error);\r\n }\r\n\r\n // When a correct value found\r\n if (newVersion) {\r\n try {\r\n // Update version\r\n await updateHighchartsVersion(newVersion);\r\n } catch (error) {\r\n throw new ExportError(\r\n `[version] Version change: ${error.message}`,\r\n 400\r\n ).setError(error);\r\n }\r\n\r\n // Success\r\n response.status(200).send({\r\n statusCode: 200,\r\n highchartsVersion: getHighchartsVersion(),\r\n message: `Successfully updated Highcharts to version: ${newVersion}.`\r\n });\r\n } else {\r\n // No version specified\r\n throw new ExportError('[version] No new version supplied.', 400);\r\n }\r\n } catch (error) {\r\n return next(error);\r\n }\r\n });\r\n}\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * @overview A module that sets up and manages HTTP and HTTPS servers\r\n * for the Highcharts Export Server. It handles server initialization,\r\n * configuration, error handling, middleware setup, route definition, and rate\r\n * limiting. The module exports functions to start, stop, and manage server\r\n * instances, as well as utility functions for defining routes and attaching\r\n * middlewares.\r\n */\r\n\r\nimport { readFileSync } from 'fs';\r\nimport { join } from 'path';\r\n\r\nimport cors from 'cors';\r\nimport express from 'express';\r\nimport http from 'http';\r\nimport https from 'https';\r\nimport multer from 'multer';\r\n\r\nimport { updateOptions, validateOptions } from '../config.js';\r\nimport { log, logWithStack } from '../logger.js';\r\nimport { __dirname, getAbsolutePath } from '../utils.js';\r\n\r\nimport errorMiddleware from './middlewares/error.js';\r\nimport rateLimitingMiddleware from './middlewares/rateLimiting.js';\r\nimport validationMiddleware from './middlewares/validation.js';\r\n\r\nimport exportRoutes from './routes/export.js';\r\nimport healthRoutes from './routes/health.js';\r\nimport uiRoutes from './routes/ui.js';\r\nimport versionChangeRoutes from './routes/versionChange.js';\r\n\r\nimport ExportError from '../errors/ExportError.js';\r\n\r\n// Array of an active servers\r\nconst activeServers = new Map();\r\n\r\n// Create express app\r\nconst app = express();\r\n\r\n/**\r\n * Starts an HTTP and/or HTTPS server based on the provided configuration.\r\n * The `serverOptions` object contains server-related properties (refer\r\n * to the `server` section in the `./lib/schemas/config.js` file for details).\r\n *\r\n * @async\r\n * @function startServer\r\n *\r\n * @param {Object} serverOptions - The configuration object containing `server`\r\n * options. This object may include a partial or complete set of the `server`\r\n * options. If the options are partial, missing values will default\r\n * to the current global configuration.\r\n *\r\n * @returns {Promise} A Promise that resolves when the server is either\r\n * not enabled or no valid Express app is found, signaling the end of the\r\n * function's execution.\r\n *\r\n * @throws {ExportError} Throws an `ExportError` if the server cannot\r\n * be configured and started.\r\n */\r\nexport async function startServer(serverOptions) {\r\n try {\r\n // Update the instance options object\r\n const options = updateOptions(\r\n validateOptions({\r\n server: serverOptions\r\n })\r\n );\r\n\r\n // Use validated options\r\n serverOptions = options.server;\r\n\r\n // Stop if not enabled\r\n if (!serverOptions.enable || !app) {\r\n throw new ExportError(\r\n '[server] Server cannot be started (not enabled or no correct Express app found).',\r\n 500\r\n );\r\n }\r\n\r\n // Too big limits lead to timeouts in the export process when\r\n // the rasterization timeout is set too low\r\n const uploadLimitBytes = serverOptions.uploadLimit * 1024 * 1024;\r\n\r\n // Memory storage for multer package\r\n const storage = multer.memoryStorage();\r\n\r\n // Enable parsing of form data (files) with multer package\r\n const upload = multer({\r\n storage,\r\n limits: {\r\n fieldSize: uploadLimitBytes\r\n }\r\n });\r\n\r\n // Disable the X-Powered-By header\r\n app.disable('x-powered-by');\r\n\r\n // Enable CORS support\r\n app.use(\r\n cors({\r\n methods: ['POST', 'GET', 'OPTIONS']\r\n })\r\n );\r\n\r\n // Getting a lot of `RangeNotSatisfiableError` exceptions (even though this\r\n // is a deprecated options, let's try to set it to false)\r\n app.use((request, response, next) => {\r\n response.set('Accept-Ranges', 'none');\r\n next();\r\n });\r\n\r\n // Enable body parser for JSON data\r\n app.use(\r\n express.json({\r\n limit: uploadLimitBytes\r\n })\r\n );\r\n\r\n // Enable body parser for URL-encoded form data\r\n app.use(\r\n express.urlencoded({\r\n extended: true,\r\n limit: uploadLimitBytes\r\n })\r\n );\r\n\r\n // Use only non-file multipart form fields\r\n app.use(upload.none());\r\n\r\n // Set up static folder's route\r\n app.use(express.static(join(__dirname, 'public')));\r\n\r\n // Listen HTTP server\r\n if (!serverOptions.ssl.force) {\r\n // Main server instance (HTTP)\r\n const httpServer = http.createServer(app);\r\n\r\n // Attach error handlers and listen to the server\r\n _attachServerErrorHandlers(httpServer);\r\n\r\n // Listen\r\n httpServer.listen(serverOptions.port, serverOptions.host, () => {\r\n // Save the reference to HTTP server\r\n activeServers.set(serverOptions.port, httpServer);\r\n\r\n log(\r\n 3,\r\n `[server] Started HTTP server on ${serverOptions.host}:${serverOptions.port}.`\r\n );\r\n });\r\n }\r\n\r\n // Listen HTTPS server\r\n if (serverOptions.ssl.enable) {\r\n // Set up an SSL server also\r\n let key, cert;\r\n\r\n try {\r\n // Get the SSL key\r\n key = readFileSync(\r\n join(getAbsolutePath(serverOptions.ssl.certPath), 'server.key'),\r\n 'utf8'\r\n );\r\n\r\n // Get the SSL certificate\r\n cert = readFileSync(\r\n join(getAbsolutePath(serverOptions.ssl.certPath), 'server.crt'),\r\n 'utf8'\r\n );\r\n } catch (error) {\r\n log(\r\n 2,\r\n `[server] Unable to load key/certificate from the '${serverOptions.ssl.certPath}' path. Could not run secured layer server.`\r\n );\r\n }\r\n\r\n if (key && cert) {\r\n // Main server instance (HTTPS)\r\n const httpsServer = https.createServer({ key, cert }, app);\r\n\r\n // Attach error handlers and listen to the server\r\n _attachServerErrorHandlers(httpsServer);\r\n\r\n // Listen\r\n httpsServer.listen(serverOptions.ssl.port, serverOptions.host, () => {\r\n // Save the reference to HTTPS server\r\n activeServers.set(serverOptions.ssl.port, httpsServer);\r\n\r\n log(\r\n 3,\r\n `[server] Started HTTPS server on ${serverOptions.host}:${serverOptions.ssl.port}.`\r\n );\r\n });\r\n }\r\n }\r\n\r\n // Set up the rate limiter\r\n rateLimitingMiddleware(app, serverOptions.rateLimiting);\r\n\r\n // Set up the validation handler\r\n validationMiddleware(app);\r\n\r\n // Set up routes\r\n exportRoutes(app);\r\n healthRoutes(app);\r\n uiRoutes(app);\r\n versionChangeRoutes(app);\r\n\r\n // Set up the centralized error handler\r\n errorMiddleware(app);\r\n } catch (error) {\r\n throw new ExportError(\r\n '[server] Could not configure and start the server.',\r\n 500\r\n ).setError(error);\r\n }\r\n}\r\n\r\n/**\r\n * Closes all servers associated with Express app instance.\r\n *\r\n * @function closeServers\r\n */\r\nexport function closeServers() {\r\n // Check if there are servers working\r\n if (activeServers.size > 0) {\r\n log(4, `[server] Closing all servers.`);\r\n\r\n // Close each one of servers\r\n for (const [port, server] of activeServers) {\r\n server.close(() => {\r\n activeServers.delete(port);\r\n log(4, `[server] Closed server on port: ${port}.`);\r\n });\r\n }\r\n }\r\n}\r\n\r\n/**\r\n * Get all servers associated with Express app instance.\r\n *\r\n * @function getServers\r\n *\r\n * @returns {Array.} Servers associated with Express app instance.\r\n */\r\nexport function getServers() {\r\n return activeServers;\r\n}\r\n\r\n/**\r\n * Get the Express instance.\r\n *\r\n * @function getExpress\r\n *\r\n * @returns {Express} The Express instance.\r\n */\r\nexport function getExpress() {\r\n return express;\r\n}\r\n\r\n/**\r\n * Get the Express app instance.\r\n *\r\n * @function getApp\r\n *\r\n * @returns {Express} The Express app instance.\r\n */\r\nexport function getApp() {\r\n return app;\r\n}\r\n\r\n/**\r\n * Enable rate limiting for the server.\r\n *\r\n * @function enableRateLimiting\r\n *\r\n * @param {Object} rateLimitingOptions - The configuration object containing\r\n * `rateLimiting` options. This object may include a partial or complete set\r\n * of the `rateLimiting` options. If the options are partial, missing values\r\n * will default to the current global configuration.\r\n */\r\nexport function enableRateLimiting(rateLimitingOptions) {\r\n // Update the instance options object\r\n const options = updateOptions(\r\n validateOptions({\r\n server: {\r\n rateLimiting: rateLimitingOptions\r\n }\r\n })\r\n );\r\n\r\n // Set the rate limiting options\r\n rateLimitingMiddleware(app, options.server.rateLimitingOptions);\r\n}\r\n\r\n/**\r\n * Apply middleware(s) to a specific path.\r\n *\r\n * @function use\r\n *\r\n * @param {string} path - The path to which the middleware(s) should be applied.\r\n * @param {...Function} middlewares - The middleware function(s) to be applied.\r\n */\r\nexport function use(path, ...middlewares) {\r\n app.use(path, ...middlewares);\r\n}\r\n\r\n/**\r\n * Set up a route with GET method and apply middleware(s).\r\n *\r\n * @function get\r\n *\r\n * @param {string} path - The path to which the middleware(s) should be applied.\r\n * @param {...Function} middlewares - The middleware function(s) to be applied.\r\n */\r\nexport function get(path, ...middlewares) {\r\n app.get(path, ...middlewares);\r\n}\r\n\r\n/**\r\n * Set up a route with POST method and apply middleware(s).\r\n *\r\n * @function post\r\n *\r\n * @param {string} path - The path to which the middleware(s) should be applied.\r\n * @param {...Function} middlewares - The middleware function(s) to be applied.\r\n */\r\nexport function post(path, ...middlewares) {\r\n app.post(path, ...middlewares);\r\n}\r\n\r\n/**\r\n * Attach error handlers to the server.\r\n *\r\n * @function _attachServerErrorHandlers\r\n *\r\n * @param {(http.Server|https.Server)} server - The HTTP/HTTPS server instance.\r\n */\r\nfunction _attachServerErrorHandlers(server) {\r\n server.on('clientError', (error, socket) => {\r\n logWithStack(\r\n 1,\r\n error,\r\n `[server] Client error: ${error.message}, destroying socket.`\r\n );\r\n socket.destroy();\r\n });\r\n\r\n server.on('error', (error) => {\r\n logWithStack(1, error, `[server] Server error: ${error.message}`);\r\n });\r\n\r\n server.on('connection', (socket) => {\r\n socket.on('error', (error) => {\r\n logWithStack(1, error, `[server] Socket error: ${error.message}`);\r\n });\r\n });\r\n}\r\n\r\nexport default {\r\n startServer,\r\n closeServers,\r\n getServers,\r\n getExpress,\r\n getApp,\r\n enableRateLimiting,\r\n use,\r\n get,\r\n post\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * @overview Handles graceful shutdown of the Highcharts Export Server, ensuring\r\n * proper cleanup of resources such as browser, pages, servers, and timers.\r\n */\r\n\r\nimport { killPool } from './pool.js';\r\nimport { clearAllTimers } from './timer.js';\r\n\r\nimport { closeServers } from './server/server.js';\r\n\r\n/**\r\n * Performs cleanup operations to ensure a graceful shutdown of the process.\r\n * This includes clearing all registered timeouts/intervals, closing active\r\n * servers, terminating resources (pages) of the pool, pool itself, and closing\r\n * the browser.\r\n *\r\n * @function shutdownCleanUp\r\n *\r\n * @param {number} [exitCode=0] - The exit code to use with `process.exit()`.\r\n * The default value is `0`.\r\n */\r\nexport async function shutdownCleanUp(exitCode = 0) {\r\n // Await freeing all resources\r\n await Promise.allSettled([\r\n // Clear all ongoing intervals\r\n clearAllTimers(),\r\n\r\n // Get available server instances (HTTP/HTTPS) and close them\r\n closeServers(),\r\n\r\n // Close an active pool along with its workers and the browser instance\r\n killPool()\r\n ]);\r\n\r\n // Exit process with a correct code\r\n process.exit(exitCode);\r\n}\r\n\r\nexport default {\r\n shutdownCleanUp\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * @overview Core module for initializing and managing the Highcharts Export\r\n * Server. Provides functionalities for configuring exports, setting up server\r\n * operations, logging, scripts caching, resource pooling, and graceful process\r\n * cleanup.\r\n */\r\n\r\nimport 'colors';\r\n\r\nimport { checkAndUpdateCache } from './cache.js';\r\nimport {\r\n singleExport,\r\n batchExport,\r\n startExport,\r\n setAllowCodeExecution\r\n} from './chart.js';\r\nimport {\r\n getOptions,\r\n updateOptions,\r\n mapToNewOptions,\r\n validateOption,\r\n validateOptions\r\n} from './config.js';\r\nimport {\r\n log,\r\n logWithStack,\r\n logZodIssues,\r\n initLogging,\r\n enableConsoleLogging,\r\n enableFileLogging,\r\n setLogLevel\r\n} from './logger.js';\r\nimport { initPool, killPool } from './pool.js';\r\nimport { shutdownCleanUp } from './resourceRelease.js';\r\n\r\nimport server from './server/server.js';\r\n\r\n/**\r\n * Initializes the export process. Tasks such as configuring logging, checking\r\n * the cache and sources, and initializing the resource pool occur during this\r\n * stage.\r\n *\r\n * This function must be called before attempting to export charts or set\r\n * up a server.\r\n *\r\n * @async\r\n * @function initExport\r\n *\r\n * @param {Object} initOptions - The `initOptions` object, which may\r\n * be a partial or complete set of options. If the options are partial, missing\r\n * values will default to the current global configuration.\r\n */\r\nexport async function initExport(initOptions) {\r\n // Init, validate and update the options object\r\n const options = updateOptions(validateOptions(initOptions));\r\n\r\n // Set the `allowCodeExecution` per export module scope\r\n setAllowCodeExecution(options.customLogic.allowCodeExecution);\r\n\r\n // Init the logging\r\n initLogging(options.logging);\r\n\r\n // Attach process' exit listeners\r\n if (options.other.listenToProcessExits) {\r\n _attachProcessExitListeners();\r\n }\r\n\r\n // Check if cache needs to be updated\r\n await checkAndUpdateCache(options.highcharts, options.server.proxy);\r\n\r\n // Init the pool\r\n await initPool(options.pool, options.puppeteer.args);\r\n}\r\n\r\n/**\r\n * Attaches exit listeners to the process, ensuring proper cleanup of resources\r\n * and termination on exit signals. Handles 'exit', 'SIGINT', 'SIGTERM'\r\n * and 'uncaughtException' events.\r\n *\r\n * @function _attachProcessExitListeners\r\n */\r\nfunction _attachProcessExitListeners() {\r\n log(3, '[process] Attaching exit listeners to the process.');\r\n\r\n // Handler for the 'exit'\r\n process.on('exit', (code) => {\r\n log(4, `[process] Process exited with code ${code}.`);\r\n });\r\n\r\n // Handler for the 'SIGINT'\r\n process.on('SIGINT', async (name, code) => {\r\n log(4, `[process] The ${name} event with code: ${code}.`);\r\n await shutdownCleanUp();\r\n });\r\n\r\n // Handler for the 'SIGTERM'\r\n process.on('SIGTERM', async (name, code) => {\r\n log(4, `[process] The ${name} event with code: ${code}.`);\r\n await shutdownCleanUp();\r\n });\r\n\r\n // Handler for the 'SIGHUP'\r\n process.on('SIGHUP', async (name, code) => {\r\n log(4, `[process] The ${name} event with code: ${code}.`);\r\n await shutdownCleanUp();\r\n });\r\n\r\n // Handler for the 'uncaughtException'\r\n process.on('uncaughtException', async (error, name) => {\r\n logWithStack(1, error, `[process] The ${name} error.`);\r\n await shutdownCleanUp(1);\r\n });\r\n}\r\n\r\nexport default {\r\n // Server\r\n ...server,\r\n\r\n // Options\r\n getOptions,\r\n updateOptions,\r\n mapToNewOptions,\r\n\r\n // Validation\r\n validateOption,\r\n validateOptions,\r\n\r\n // Exporting\r\n initExport,\r\n singleExport,\r\n batchExport,\r\n startExport,\r\n\r\n // Release\r\n killPool,\r\n shutdownCleanUp,\r\n\r\n // Logs\r\n log,\r\n logWithStack,\r\n logZodIssues,\r\n setLogLevel: function (level) {\r\n // Update the instance options object\r\n const options = updateOptions(\r\n validateOptions({\r\n logging: {\r\n level\r\n }\r\n })\r\n );\r\n\r\n // Call the function\r\n setLogLevel(options.logging.level);\r\n },\r\n enableConsoleLogging: function (toConsole) {\r\n // Update the instance options object\r\n const options = updateOptions(\r\n validateOptions({\r\n logging: {\r\n toConsole\r\n }\r\n })\r\n );\r\n\r\n // Call the function\r\n enableConsoleLogging(options.logging.toConsole);\r\n },\r\n enableFileLogging: function (dest, file, toFile) {\r\n // Update the instance options object\r\n const options = updateOptions(\r\n validateOptions({\r\n logging: {\r\n dest,\r\n file,\r\n toFile\r\n }\r\n })\r\n );\r\n\r\n // Call the function\r\n enableFileLogging(\r\n options.logging.dest,\r\n options.logging.file,\r\n options.logging.toFile\r\n );\r\n }\r\n};\r\n"],"names":["__dirname","fileURLToPath","URL","url","deepCopy","objArr","objArrCopy","Array","isArray","key","Object","prototype","hasOwnProperty","call","fixConstr","constr","fixedConstr","toLowerCase","replace","includes","fixOutfile","type","outfile","getAbsolutePath","split","shift","fixType","mimeTypes","formats","values","outType","pop","find","t","path","isAbsolute","normalize","resolve","getBase64","input","Buffer","from","toString","getNewDate","Date","trim","getNewDateTime","getTime","isObject","item","isObjectEmpty","keys","length","isPrivateRangeUrlFound","some","pattern","test","measureTime","start","process","hrtime","bigint","Number","roundNumber","value","precision","multiplier","Math","pow","round","wrapAround","customCode","allowFileResources","isCallback","endsWith","readFileSync","startsWith","colors","logging","toConsole","toFile","pathCreated","pathToLog","levelsDesc","title","color","log","args","newLevel","texts","level","prefix","_logToFile","console","apply","undefined","concat","logWithStack","error","customMessage","mainMessage","message","stackMessage","stack","push","logZodIssues","issues","map","issue","join","initLogging","loggingOptions","dest","file","setLogLevel","enableConsoleLogging","enableFileLogging","isInteger","existsSync","mkdirSync","appendFile","defaultConfig","puppeteer","types","envLink","cliName","description","promptOptions","separator","highcharts","version","cdnUrl","forceFetch","cachePath","coreScripts","instructions","moduleScripts","indicatorScripts","customScripts","export","infile","instr","options","svg","batch","hint","choices","b64","noDownload","height","width","scale","defaultHeight","defaultWidth","defaultScale","min","max","globalOptions","themeOptions","rasterizationTimeout","customLogic","allowCodeExecution","callback","resources","loadConfig","legacyName","createConfig","server","enable","host","port","uploadLimit","benchmarking","proxy","timeout","rateLimiting","maxRequests","window","delay","trustProxy","skipKey","skipToken","ssl","force","certPath","pool","minWorkers","maxWorkers","workLimit","acquireTimeout","createTimeout","destroyTimeout","idleTimeout","createRetryInterval","reaperInterval","ui","route","other","nodeEnv","listenToProcessExits","noLogo","hardResetPage","browserShellMode","validation","debug","headless","devtools","listenToConsole","dumpio","slowMo","debuggingPort","nestedProps","_createNestedProps","absoluteProps","_createAbsoluteProps","config","propChain","forEach","entry","substring","dotenv","z","setErrorMap","_customErrorMap","v","boolean","strictCheck","union","enum","transform","nullable","string","refine","params","errorMessage","stringArray","filterCallback","arraySchema","array","stringSchema","slice","transformCallback","filter","positiveNum","number","positive","isNaN","nonNegativeNum","nonnegative","prefixes","chartConfig","object","passthrough","additionalOptions","validators","adminToken","indexOf","gte","lte","this","objectSchema","js","css","files","partial","stringSchema1","stringSchema2","enableServer","serverBenchmarking","proxyHost","proxyPort","proxyTimeout","enableRateLimiting","enableSsl","sslForce","sslPort","sslCertPath","poolBenchmarking","resourcesInterval","logLevel","int","logFile","logDest","logToConsole","logToFile","enableUi","uiRoute","enableDebug","requestId","uuid","PuppeteerSchema","HighchartsSchema","ExportSchema","CustomLogicSchema","ProxySchema","RateLimitingSchema","SslSchema","ServerSchema","optional","PoolSchema","LoggingSchema","UiSchema","OtherSchema","DebugSchema","StrictConfigSchema","LooseConfigSchema","EnvSchema","PUPPETEER_ARGS","HIGHCHARTS_VERSION","HIGHCHARTS_CDN_URL","HIGHCHARTS_FORCE_FETCH","HIGHCHARTS_CACHE_PATH","HIGHCHARTS_ADMIN_TOKEN","HIGHCHARTS_CORE_SCRIPTS","HIGHCHARTS_MODULE_SCRIPTS","HIGHCHARTS_INDICATOR_SCRIPTS","HIGHCHARTS_CUSTOM_SCRIPTS","EXPORT_INFILE","EXPORT_INSTR","EXPORT_OPTIONS","EXPORT_SVG","EXPORT_BATCH","EXPORT_OUTFILE","EXPORT_TYPE","EXPORT_CONSTR","EXPORT_B64","EXPORT_NO_DOWNLOAD","EXPORT_HEIGHT","EXPORT_WIDTH","EXPORT_SCALE","EXPORT_DEFAULT_HEIGHT","EXPORT_DEFAULT_WIDTH","EXPORT_DEFAULT_SCALE","EXPORT_GLOBAL_OPTIONS","EXPORT_THEME_OPTIONS","EXPORT_RASTERIZATION_TIMEOUT","CUSTOM_LOGIC_ALLOW_CODE_EXECUTION","CUSTOM_LOGIC_ALLOW_FILE_RESOURCES","CUSTOM_LOGIC_CUSTOM_CODE","CUSTOM_LOGIC_CALLBACK","CUSTOM_LOGIC_RESOURCES","CUSTOM_LOGIC_LOAD_CONFIG","CUSTOM_LOGIC_CREATE_CONFIG","SERVER_ENABLE","SERVER_HOST","SERVER_PORT","SERVER_UPLOAD_LIMIT","SERVER_BENCHMARKING","SERVER_PROXY_HOST","SERVER_PROXY_PORT","SERVER_PROXY_TIMEOUT","SERVER_RATE_LIMITING_ENABLE","SERVER_RATE_LIMITING_MAX_REQUESTS","SERVER_RATE_LIMITING_WINDOW","SERVER_RATE_LIMITING_DELAY","SERVER_RATE_LIMITING_TRUST_PROXY","SERVER_RATE_LIMITING_SKIP_KEY","SERVER_RATE_LIMITING_SKIP_TOKEN","SERVER_SSL_ENABLE","SERVER_SSL_FORCE","SERVER_SSL_PORT","SERVER_SSL_CERT_PATH","POOL_MIN_WORKERS","POOL_MAX_WORKERS","POOL_WORK_LIMIT","POOL_ACQUIRE_TIMEOUT","POOL_CREATE_TIMEOUT","POOL_DESTROY_TIMEOUT","POOL_IDLE_TIMEOUT","POOL_CREATE_RETRY_INTERVAL","POOL_REAPER_INTERVAL","POOL_BENCHMARKING","LOGGING_LEVEL","LOGGING_FILE","LOGGING_DEST","LOGGING_TO_CONSOLE","LOGGING_TO_FILE","UI_ENABLE","UI_ROUTE","OTHER_NODE_ENV","OTHER_LISTEN_TO_PROCESS_EXITS","OTHER_NO_LOGO","OTHER_HARD_RESET_PAGE","OTHER_BROWSER_SHELL_MODE","OTHER_VALIDATION","DEBUG_ENABLE","DEBUG_HEADLESS","DEBUG_DEVTOOLS","DEBUG_LISTEN_TO_CONSOLE","DEBUG_DUMPIO","DEBUG_SLOW_MO","DEBUG_DEBUGGING_PORT","envs","parse","env","strictValidate","configOptions","looseValidate","context","propertyName","propertyInfo","code","ZodIssueCode","invalid_type","received","ZodParsedType","defaultError","custom","data","invalid_union","unionErrors","index","ExportError","Error","constructor","statusCode","super","setStatus","setError","name","_initOptions","getOptions","getCopy","updateOptions","newOptions","_mergeOptions","mapToNewOptions","oldOptions","entries","propertiesChain","reduce","obj","prop","validateOption","configOption","validateOptions","isAllowedConfig","allowFunctions","objectConfig","eval","JSON","stringifiedOptions","_optionsStringify","parsedOptions","_","originalOptions","stringifyFunctions","stringify","replaceAll","async","fetch","requestOptions","Promise","reject","_getProtocolModule","get","response","responseData","on","chunk","text","https","http","cache","activeManifest","sources","hcVersion","checkAndUpdateCache","highchartsOptions","serverProxyOptions","fetchedModules","getCachePath","manifestPath","sourcePath","recursive","_updateCache","requestUpdate","manifest","modules","moduleMap","m","numberOfModules","moduleName","extractVersion","_saveConfigToManifest","getHighchartsVersion","updateHighchartsVersion","newVersion","cacheSources","extractModuleName","scriptPath","_fetchAndProcessScript","script","shouldThrowError","newManifest","writeFileSync","_fetchScripts","proxyAgent","HttpsProxyAgent","agent","allFetchPromises","all","c","i","setupHighcharts","Highcharts","animObject","duration","createChart","exportOptions","customLogicOptions","setOptions","merge","wrap","setOptionsObj","isRenderComplete","Chart","proceed","userOptions","cb","exporting","enabled","plotOptions","series","label","tooltip","animation","onHighchartsRender","addEvent","Series","chart","Function","finalOptions","finalCallback","defaultOptions","template","browser","createBrowser","puppeteerArgs","enabledDebug","debugOptions","launchOptions","userDataDir","handleSIGINT","handleSIGTERM","handleSIGHUP","waitForInitialPage","defaultViewport","tryCount","open","launch","setTimeout","closeBrowser","connected","close","newPage","poolResource","page","setCacheEnabled","_setPageContent","_setPageEvents","isClosed","clearPage","hardReset","goto","waitUntil","evaluate","document","body","innerHTML","id","workCount","addPageResources","injectedResources","injectedJs","content","isLocal","jsResource","addScriptTag","injectedCss","cssImports","match","cssImportPath","cssResource","addStyleTag","clearPageResources","resource","dispose","oldCharts","charts","oldChart","destroy","scriptsToRemove","getElementsByTagName","stylesToRemove","linksToRemove","element","remove","setContent","cssTemplate","svgTemplate","puppeteerExport","isSVG","size","svgElement","querySelector","chartHeight","baseVal","chartWidth","style","zoom","margin","parseFloat","x","y","_getClipRegion","viewportHeight","abs","ceil","viewportWidth","result","setViewport","deviceScaleFactor","_createSVG","_createImage","_createPDF","$eval","getBoundingClientRect","trunc","outerHTML","clip","race","screenshot","encoding","fullPage","optimizeForSpeed","captureBeyondViewport","quality","omitBackground","_resolve","emulateMediaType","pdf","poolStats","exportsAttempted","exportsPerformed","exportsDropped","exportsFromSvg","exportsFromOptions","exportsFromSvgAttempts","exportsFromOptionsAttempts","timeSpent","timeSpentAverage","initPool","poolOptions","Pool","_factory","acquireTimeoutMillis","createTimeoutMillis","destroyTimeoutMillis","idleTimeoutMillis","createRetryIntervalMillis","reapIntervalMillis","propagateCreateError","clearStatus","_eventId","initialResources","acquire","promise","release","killPool","worker","used","destroyed","postWork","workerHandle","getPoolInfo","acquireCounter","workStart","exportCounter","exportTime","getPoolStats","getPoolInfoJSON","numUsed","available","numFree","allCreated","pendingAcquires","numPendingAcquires","pendingCreates","numPendingCreates","pendingValidations","numPendingValidations","pendingDestroys","absoluteAll","create","random","startDate","validate","mainFrame","detached","removeAllListeners","sanitize","JSDOM","DOMPurify","ADD_TAGS","singleExport","startExport","batchExport","batchFunctions","pair","batchResults","allSettled","reason","imageOptions","endCallback","fileContent","_exportFromSvg","_exportFromOptions","getAllowCodeExecution","setAllowCodeExecution","inputToExport","_prepareExport","_handleCustomLogic","_handleGlobalAndTheme","_findChartSize","optionsChart","optionsExporting","globalOptionsChart","globalOptionsExporting","themeOptionsChart","themeOptionsExporting","sourceHeight","sourceWidth","param","_handleResources","allowedProps","handledResources","correctResources","propName","optionsName","timerIds","addTimer","clearAllTimers","clearInterval","clearTimeout","logErrorMiddleware","request","next","returnErrorMiddleware","status","json","errorMiddleware","app","use","rateLimitingMiddleware","rateLimitingOptions","rateOptions","limiter","rateLimit","windowMs","limit","delayMs","handler","format","send","default","skip","query","access_token","contentTypeMiddleware","contentType","headers","requestBodyMiddleware","connection","remoteAddress","validatedOptions","filename","validationMiddleware","post","reversedMime","png","jpeg","gif","requestExport","requestCounter","connectionAborted","socket","hadErrors","header","attachment","exportRoutes","serverStartTime","packageFile","successRates","recordInterval","windowSize","_calculateMovingAverage","a","b","_startSuccessRate","setInterval","stats","successRatio","healthRoutes","period","movingAverage","bootTime","uptime","floor","serverVersion","highchartsVersion","averageExportTime","attemptedExports","performedExports","failedExports","sucessRatio","toFixed","svgExports","jsonExports","svgExportsAttempts","jsonExportsAttempts","uiRoutes","sendFile","acceptRanges","versionChangeRoutes","token","activeServers","Map","express","startServer","serverOptions","uploadLimitBytes","storage","multer","memoryStorage","upload","limits","fieldSize","disable","cors","methods","set","urlencoded","extended","none","static","httpServer","createServer","_attachServerErrorHandlers","listen","cert","httpsServer","closeServers","delete","getServers","getExpress","getApp","middlewares","shutdownCleanUp","exitCode","exit","initExport","initOptions","_attachProcessExitListeners"],"mappings":"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QACA,OACA,aACA,mBACA,eACA,cACA,UACA,UACA,cACA,WACA,UACA,YACA,cACA,YACA,sBACA,SACA,SACA,WACA,aACA,YACA,eACA,yBACA,SACA,eACA,YACA,kBACA,SACA,cACA,mBACA,eACA,kBACA,cACA,eAEA,cACA,WACA,eACA,WACA,SACA,OACA,WACA,YACA,SACA,qBACA,aACA,WACA,WACA,WACA,WACA,eACA,UACA,kBACA,oBACA,aACA,UACA,cACA,YACA,YAEF2D,MAAO,CAAC,YACRC,QAAS,4BACTE,YAAa,qCACbC,cAAe,CACb1G,KAAM,cACNkH,aAAc,0DAGlBE,iBAAkB,CAChBzE,MAAO,CAAC,kBACR2D,MAAO,CAAC,YACRC,QAAS,+BACTE,YAAa,wCACbC,cAAe,CACb1G,KAAM,cACNkH,aAAc,0DAGlBG,cAAe,CACb1E,MAAO,CACL,wEACA,kGAEF2D,MAAO,CAAC,YACRC,QAAS,4BACTE,YAAa,qDACbC,cAAe,CACb1G,KAAM,OACN2G,UAAW,OAIjBW,OAAQ,CACNC,OAAQ,CACN5E,MAAO,KACP2D,MAAO,CAAC,SAAU,QAClBC,QAAS,gBACTE,YACE,+DACFC,cAAe,CACb1G,KAAM,SAGVwH,MAAO,CACL7E,MAAO,KACP2D,MAAO,CAAC,SAAU,SAAU,QAC5BC,QAAS,eACTE,YACE,mEACFC,cAAe,CACb1G,KAAM,SAGVyH,QAAS,CACP9E,MAAO,KACP2D,MAAO,CAAC,SAAU,SAAU,QAC5BC,QAAS,iBACTE,YAAa,+BACbC,cAAe,CACb1G,KAAM,SAGV0H,IAAK,CACH/E,MAAO,KACP2D,MAAO,CAAC,SAAU,QAClBC,QAAS,aACTE,YAAa,mDACbC,cAAe,CACb1G,KAAM,SAGV2H,MAAO,CACLhF,MAAO,KACP2D,MAAO,CAAC,SAAU,QAClBC,QAAS,eACTE,YACE,gEACFC,cAAe,CACb1G,KAAM,SAGVC,QAAS,CACP0C,MAAO,KACP2D,MAAO,CAAC,SAAU,QAClBC,QAAS,iBACTE,YACE,qFACFC,cAAe,CACb1G,KAAM,SAGVA,KAAM,CACJ2C,MAAO,MACP2D,M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"} \ No newline at end of file +{"version":3,"file":"index.esm.js","sources":["../lib/utils.js","../lib/logger.js","../lib/schemas/config.js","../lib/validation.js","../lib/errors/ExportError.js","../lib/config.js","../lib/fetch.js","../lib/cache.js","../lib/highcharts.js","../lib/browser.js","../templates/svgExport/css.js","../templates/svgExport/svgExport.js","../lib/export.js","../lib/pool.js","../lib/sanitize.js","../lib/chart.js","../lib/timer.js","../lib/server/middlewares/error.js","../lib/server/middlewares/rateLimiting.js","../lib/server/middlewares/validation.js","../lib/server/routes/export.js","../lib/server/routes/health.js","../lib/server/routes/ui.js","../lib/server/routes/versionChange.js","../lib/server/server.js","../lib/resourceRelease.js","../lib/index.js"],"sourcesContent":["/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * @overview The Highcharts Export Server utility module provides\r\n * a comprehensive set of helper functions and constants designed to streamline\r\n * and enhance various operations required for Highcharts export tasks.\r\n */\r\n\r\nimport { readFileSync } from 'fs';\r\nimport { isAbsolute, normalize, resolve } from 'path';\r\nimport { fileURLToPath } from 'url';\r\n\r\nconst MAX_BACKOFF_ATTEMPTS = 6;\r\n\r\n// The directory path\r\nexport const __dirname = fileURLToPath(new URL('../.', import.meta.url));\r\n\r\n/**\r\n * Clears and standardizes text by replacing multiple consecutive whitespace\r\n * characters with a single space and trimming any leading or trailing\r\n * whitespace.\r\n *\r\n * @function clearText\r\n *\r\n * @param {string} text - The input text to be cleared.\r\n * @param {RegExp} [rule=/\\s\\s+/g] - The regular expression rule to match\r\n * multiple consecutive whitespace characters. The default value\r\n * is the '/\\s\\s+/g' RegExp.\r\n * @param {string} [replacer=' '] - The string used to replace multiple\r\n * consecutive whitespace characters. The default value is the ' ' string.\r\n *\r\n * @returns {string} The cleared and standardized text.\r\n */\r\nexport function clearText(text, rule = /\\s\\s+/g, replacer = ' ') {\r\n return text.replaceAll(rule, replacer).trim();\r\n}\r\n\r\n/**\r\n * Creates a deep copy of the given object or array.\r\n *\r\n * @function deepCopy\r\n *\r\n * @param {(Object|Array)} objArr - The object or array to be deeply copied.\r\n *\r\n * @returns {(Object|Array)} The deep copy of the provided object or array.\r\n */\r\nexport function deepCopy(objArr) {\r\n // If the `objArr` is null or not of the `object` type, return it\r\n if (objArr === null || typeof objArr !== 'object') {\r\n return objArr;\r\n }\r\n\r\n // Prepare either a new array or a new object\r\n const objArrCopy = Array.isArray(objArr) ? [] : {};\r\n\r\n // Recursively copy each property\r\n for (const key in objArr) {\r\n if (Object.prototype.hasOwnProperty.call(objArr, key)) {\r\n objArrCopy[key] = deepCopy(objArr[key]);\r\n }\r\n }\r\n\r\n // Return the copied object\r\n return objArrCopy;\r\n}\r\n\r\n/**\r\n * Implements an exponential backoff strategy for retrying a function until\r\n * a certain number of attempts are reached.\r\n *\r\n * @async\r\n * @function expBackoff\r\n *\r\n * @param {Function} fn - The function to be retried.\r\n * @param {number} [attempt=0] - The current attempt number. The default value\r\n * is `0`.\r\n * @param {...unknown} args - Arguments to be passed to the function.\r\n *\r\n * @returns {Promise} A Promise that resolves to the result\r\n * of the function if successful.\r\n *\r\n * @throws {Error} Throws an `Error` if the maximum number of attempts\r\n * is reached.\r\n */\r\nexport async function expBackoff(fn, attempt = 0, ...args) {\r\n try {\r\n // Try to call the function\r\n return await fn(...args);\r\n } catch (error) {\r\n // Calculate delay in ms\r\n const delayInMs = 2 ** attempt * 1000;\r\n\r\n // If the attempt exceeds the maximum attempts of repeat, throw an error\r\n if (++attempt >= MAX_BACKOFF_ATTEMPTS) {\r\n throw error;\r\n }\r\n\r\n // Wait given amount of time\r\n await new Promise((response) => setTimeout(response, delayInMs));\r\n\r\n /// TO DO: Correct\r\n // // Information about the resource timeout\r\n // log(\r\n // 3,\r\n // `[utils] Waited ${delayInMs}ms until next call for the resource of ID: ${args[0]}.`\r\n // );\r\n\r\n // Try again\r\n return expBackoff(fn, attempt, ...args);\r\n }\r\n}\r\n\r\n/**\r\n * Adjusts the constructor name by transforming and normalizing it based\r\n * on common chart types.\r\n *\r\n * @function fixConstr\r\n *\r\n * @param {string} constr - The original constructor name to be fixed.\r\n *\r\n * @returns {string} The corrected constructor name, or 'chart' if the input\r\n * is not recognized.\r\n */\r\nexport function fixConstr(constr) {\r\n try {\r\n // Fix the constructor by lowering casing\r\n const fixedConstr = `${constr.toLowerCase().replace('chart', '')}Chart`;\r\n\r\n // Handle the case where the result is just 'Chart'\r\n if (fixedConstr === 'Chart') {\r\n fixedConstr.toLowerCase();\r\n }\r\n\r\n // Return the corrected constructor, otherwise default to 'chart'\r\n return ['chart', 'stockChart', 'mapChart', 'ganttChart'].includes(\r\n fixedConstr\r\n )\r\n ? fixedConstr\r\n : 'chart';\r\n } catch {\r\n // Default to 'chart' in case of any error\r\n return 'chart';\r\n }\r\n}\r\n\r\n/**\r\n * Fixes the outfile based on provided type.\r\n *\r\n * @function fixOutfile\r\n *\r\n * @param {string} type - The original export type.\r\n * @param {string} outfile - The file path or name.\r\n *\r\n * @returns {string} The corrected outfile.\r\n */\r\nexport function fixOutfile(type, outfile) {\r\n // Get the file name from the `outfile` option\r\n const fileName = getAbsolutePath(outfile || 'chart')\r\n .split('.')\r\n .shift();\r\n\r\n // Return a correct outfile\r\n return `${fileName}.${type}`;\r\n}\r\n\r\n/**\r\n * Fixes the export type based on MIME types and file extensions.\r\n *\r\n * @function fixType\r\n *\r\n * @param {string} type - The original export type.\r\n * @param {string} [outfile=null] - The file path or name. The default value\r\n * is `null`.\r\n *\r\n * @returns {string} The corrected export type.\r\n */\r\nexport function fixType(type, outfile = null) {\r\n // MIME types\r\n const mimeTypes = {\r\n 'image/png': 'png',\r\n 'image/jpeg': 'jpeg',\r\n 'application/pdf': 'pdf',\r\n 'image/svg+xml': 'svg'\r\n };\r\n\r\n // Get formats\r\n const formats = Object.values(mimeTypes);\r\n\r\n // Check if type and outfile's extensions are the same\r\n if (outfile) {\r\n const outType = outfile.split('.').pop();\r\n\r\n // Support the JPG type\r\n if (outType === 'jpg') {\r\n type = 'jpeg';\r\n } else if (formats.includes(outType) && type !== outType) {\r\n type = outType;\r\n }\r\n }\r\n\r\n // Return a correct type\r\n return mimeTypes[type] || formats.find((t) => t === type) || 'png';\r\n}\r\n\r\n/**\r\n * Checks if the given path is relative or absolute and returns the corrected,\r\n * absolute path.\r\n *\r\n * @function isAbsolutePath\r\n *\r\n * @param {string} path - The path to be checked on.\r\n *\r\n * @returns {string} The absolute path.\r\n */\r\nexport function getAbsolutePath(path) {\r\n return isAbsolute(path) ? normalize(path) : resolve(path);\r\n}\r\n\r\n/**\r\n * Converts input data to a Base64 string based on the export type.\r\n *\r\n * @function getBase64\r\n *\r\n * @param {string} input - The input to be transformed to Base64 format.\r\n * @param {string} type - The original export type.\r\n *\r\n * @returns {string} The Base64 string representation of the input.\r\n */\r\nexport function getBase64(input, type) {\r\n // For pdf and svg types the input must be transformed to Base64 from a buffer\r\n if (type === 'pdf' || type == 'svg') {\r\n return Buffer.from(input, 'utf8').toString('base64');\r\n }\r\n\r\n // For png and jpeg input is already a Base64 string\r\n return input;\r\n}\r\n\r\n/**\r\n * Returns stringified date without the GMT text information.\r\n *\r\n * @function getNewDate\r\n */\r\nexport function getNewDate() {\r\n // Get rid of the GMT text information\r\n return new Date().toString().split('(')[0].trim();\r\n}\r\n\r\n/**\r\n * Returns the stored time value in milliseconds.\r\n *\r\n * @function getNewDateTime\r\n */\r\nexport function getNewDateTime() {\r\n return new Date().getTime();\r\n}\r\n\r\n/**\r\n * Checks if the given item is an object.\r\n *\r\n * @function isObject\r\n *\r\n * @param {unknown} item - The item to be checked.\r\n *\r\n * @returns {boolean} True if the item is an object, false otherwise.\r\n */\r\nexport function isObject(item) {\r\n return Object.prototype.toString.call(item) === '[object Object]';\r\n}\r\n\r\n/**\r\n * Checks if the given object is empty.\r\n *\r\n * @function isObjectEmpty\r\n *\r\n * @param {Object} item - The object to be checked.\r\n *\r\n * @returns {boolean} True if the object is empty, false otherwise.\r\n */\r\nexport function isObjectEmpty(item) {\r\n return (\r\n typeof item === 'object' &&\r\n !Array.isArray(item) &&\r\n item !== null &&\r\n Object.keys(item).length === 0\r\n );\r\n}\r\n\r\n/**\r\n * Checks if a private IP range URL is found in the given string.\r\n *\r\n * @function isPrivateRangeUrlFound\r\n *\r\n * @param {string} item - The string to be checked for a private IP range URL.\r\n *\r\n * @returns {boolean} True if a private IP range URL is found, false otherwise.\r\n */\r\nexport function isPrivateRangeUrlFound(item) {\r\n const regexPatterns = [\r\n /xlink:href=\"(?:http:\\/\\/|https:\\/\\/)?localhost\\b/,\r\n /xlink:href=\"(?:http:\\/\\/|https:\\/\\/)?10\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\b/,\r\n /xlink:href=\"(?:http:\\/\\/|https:\\/\\/)?127\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\b/,\r\n /xlink:href=\"(?:http:\\/\\/|https:\\/\\/)?172\\.(1[6-9]|2[0-9]|3[0-1])\\.\\d{1,3}\\.\\d{1,3}\\b/,\r\n /xlink:href=\"(?:http:\\/\\/|https:\\/\\/)?192\\.168\\.\\d{1,3}\\.\\d{1,3}\\b/\r\n ];\r\n\r\n return regexPatterns.some((pattern) => pattern.test(item));\r\n}\r\n\r\n/**\r\n * Utility to measure elapsed time using the Node.js `process.hrtime()` method.\r\n *\r\n * @function measureTime\r\n *\r\n * @returns {Function} A function to calculate the elapsed time in milliseconds.\r\n */\r\nexport function measureTime() {\r\n const start = process.hrtime.bigint();\r\n return () => Number(process.hrtime.bigint() - start) / 1000000;\r\n}\r\n\r\n/**\r\n * Rounds a number to the specified precision.\r\n *\r\n * @function roundNumber\r\n *\r\n * @param {number} value - The number to be rounded.\r\n * @param {number} precision - The number of decimal places to round to.\r\n *\r\n * @returns {number} The rounded number.\r\n */\r\nexport function roundNumber(value, precision = 1) {\r\n const multiplier = Math.pow(10, precision || 0);\r\n return Math.round(+value * multiplier) / multiplier;\r\n}\r\n\r\n/**\r\n * Converts a value to a boolean.\r\n *\r\n * @function toBoolean\r\n *\r\n * @param {unknown} item - The value to be converted to a boolean.\r\n *\r\n * @returns {boolean} The boolean representation of the input value.\r\n */\r\nexport function toBoolean(item) {\r\n return ['false', 'undefined', 'null', 'NaN', '0', ''].includes(item)\r\n ? false\r\n : !!item;\r\n}\r\n\r\n/**\r\n * Wraps custom code to execute it safely.\r\n *\r\n * @function wrapAround\r\n *\r\n * @param {string} customCode - The custom code to be wrapped.\r\n * @param {boolean} allowFileResources - Flag to allow loading code from a file.\r\n * @param {boolean} [isCallback=false] - Flag that indicates the returned code\r\n * must be in a callback format.\r\n *\r\n * @returns {(string|null)} The wrapped custom code or null if wrapping fails.\r\n */\r\nexport function wrapAround(customCode, allowFileResources, isCallback = false) {\r\n if (customCode && typeof customCode === 'string') {\r\n customCode = customCode.trim();\r\n\r\n if (customCode.endsWith('.js')) {\r\n // Load a file if the file resources are allowed\r\n return allowFileResources\r\n ? wrapAround(\r\n readFileSync(getAbsolutePath(customCode), 'utf8'),\r\n allowFileResources,\r\n isCallback\r\n )\r\n : null;\r\n } else if (\r\n !isCallback &&\r\n (customCode.startsWith('function()') ||\r\n customCode.startsWith('function ()') ||\r\n customCode.startsWith('()=>') ||\r\n customCode.startsWith('() =>'))\r\n ) {\r\n // Treat a function as a self-invoking expression\r\n return `(${customCode})()`;\r\n }\r\n\r\n // Or return as a stringified code\r\n return customCode.replace(/;$/, '');\r\n }\r\n}\r\n\r\nexport default {\r\n __dirname,\r\n clearText,\r\n deepCopy,\r\n expBackoff,\r\n fixConstr,\r\n fixOutfile,\r\n fixType,\r\n getAbsolutePath,\r\n getBase64,\r\n getNewDate,\r\n getNewDateTime,\r\n isObject,\r\n isObjectEmpty,\r\n isPrivateRangeUrlFound,\r\n measureTime,\r\n roundNumber,\r\n toBoolean,\r\n wrapAround\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * @overview A module for managing logging functionality with customizable\r\n * log levels, console and file logging options, and error handling support.\r\n * The module also ensures that file-based logs are stored in a structured\r\n * directory, creating the necessary paths automatically if they do not exist.\r\n */\r\n\r\nimport { appendFile, existsSync, mkdirSync } from 'fs';\r\nimport { join } from 'path';\r\n\r\nimport { getAbsolutePath, getNewDate } from './utils.js';\r\n\r\n// The available colors\r\nconst colors = ['red', 'yellow', 'blue', 'gray', 'green'];\r\n\r\n// The default logging config\r\nconst logging = {\r\n // Flags for logging status\r\n toConsole: true,\r\n toFile: false,\r\n pathCreated: false,\r\n // Full path to the log file\r\n pathToLog: '',\r\n // Log levels\r\n levelsDesc: [\r\n {\r\n title: 'error',\r\n color: colors[0]\r\n },\r\n {\r\n title: 'warning',\r\n color: colors[1]\r\n },\r\n {\r\n title: 'notice',\r\n color: colors[2]\r\n },\r\n {\r\n title: 'verbose',\r\n color: colors[3]\r\n },\r\n {\r\n title: 'benchmark',\r\n color: colors[4]\r\n }\r\n ]\r\n};\r\n\r\n/**\r\n * Logs a message with a specified log level. Accepts a variable number\r\n * of arguments. The arguments after the `level` are passed to `console.log`\r\n * and/or used to construct and append messages to a log file.\r\n *\r\n * @function log\r\n *\r\n * @param {...unknown} args - An array of arguments where the first is the log\r\n * level and the remaining are strings used to build the log message.\r\n *\r\n * @returns {void} Exits the function execution if attempting to log at a level\r\n * higher than allowed.\r\n */\r\nexport function log(...args) {\r\n const [newLevel, ...texts] = args;\r\n\r\n // Current logging options\r\n const { levelsDesc, level } = logging;\r\n\r\n // Check if the log level is within a correct range or is it a benchmark log\r\n if (\r\n newLevel !== 5 &&\r\n (newLevel === 0 || newLevel > level || level > levelsDesc.length)\r\n ) {\r\n return;\r\n }\r\n\r\n // Create a message's prefix\r\n const prefix = `${getNewDate()} [${levelsDesc[newLevel - 1].title}] -`;\r\n\r\n // Log to file\r\n if (logging.toFile) {\r\n _logToFile(texts, prefix);\r\n }\r\n\r\n // Log to console\r\n if (logging.toConsole) {\r\n console.log.apply(\r\n undefined,\r\n [prefix.toString()[logging.levelsDesc[newLevel - 1].color]].concat(texts)\r\n );\r\n }\r\n}\r\n\r\n/**\r\n * Logs an error message along with its stack trace. Optionally, a custom message\r\n * can be provided.\r\n *\r\n * @function logWithStack\r\n *\r\n * @param {number} newLevel - The log level.\r\n * @param {Error} error - The error object containing the stack trace.\r\n * @param {string} customMessage - An optional custom message to be included\r\n * in the log alongside the error.\r\n *\r\n * @returns {void} Exits the function execution if attempting to log at a level\r\n * higher than allowed.\r\n */\r\nexport function logWithStack(newLevel, error, customMessage) {\r\n // Get the main message\r\n const mainMessage = customMessage || (error && error.message) || '';\r\n\r\n // Current logging options\r\n const { level, levelsDesc } = logging;\r\n\r\n // Check if the log level is within a correct range\r\n if (newLevel === 0 || newLevel > level || level > levelsDesc.length) {\r\n return;\r\n }\r\n\r\n // Create a message's prefix\r\n const prefix = `${getNewDate()} [${levelsDesc[newLevel - 1].title}] -`;\r\n\r\n // Add the whole stack message\r\n const stackMessage = error && error.stack;\r\n\r\n // Combine custom message or error message with error stack message, if exists\r\n const texts = [mainMessage];\r\n if (stackMessage) {\r\n texts.push('\\n', stackMessage);\r\n }\r\n\r\n // Log to file\r\n if (logging.toFile) {\r\n _logToFile(texts, prefix);\r\n }\r\n\r\n // Log to console\r\n if (logging.toConsole) {\r\n console.log.apply(\r\n undefined,\r\n [prefix.toString()[logging.levelsDesc[newLevel - 1].color]].concat([\r\n texts.shift()[colors[newLevel - 1]],\r\n ...texts\r\n ])\r\n );\r\n }\r\n}\r\n\r\n/**\r\n * Logs an error message related to Zod validation issues. Optionally, a custom\r\n * message can be provided.\r\n *\r\n * @function logZodIssues\r\n *\r\n * @param {number} newLevel - The log level.\r\n * @param {Error[]} issues - An array of Zod validation issues.\r\n * @param {string} customMessage - An optional custom message to be included\r\n * in the log alongside the error.\r\n */\r\nexport function logZodIssues(newLevel, issues, customMessage) {\r\n logWithStack(\r\n newLevel,\r\n null,\r\n [\r\n `${customMessage || '[validation] Validation error'} - the following Zod issues occured:`,\r\n ...(issues || []).map((issue) => `- ${issue.message}`)\r\n ].join('\\n')\r\n );\r\n}\r\n\r\n/**\r\n * Initializes logging with the specified logging configuration.\r\n *\r\n * @function initLogging\r\n *\r\n * @param {Object} loggingOptions - The configuration object containing\r\n * `logging` options.\r\n */\r\nexport function initLogging(loggingOptions) {\r\n // Get options from the `loggingOptions` object\r\n const { level, dest, file, toConsole, toFile } = loggingOptions;\r\n\r\n // Reset flags to the default values\r\n logging.pathCreated = false;\r\n logging.pathToLog = '';\r\n\r\n // Set the logging level\r\n setLogLevel(level);\r\n\r\n // Set the console logging\r\n enableConsoleLogging(toConsole);\r\n\r\n // Set the file logging\r\n enableFileLogging(dest, file, toFile);\r\n}\r\n\r\n/**\r\n * Sets the log level to the specified value. Log levels are (`0` = no logging,\r\n * `1` = error, `2` = warning, `3` = notice, `4` = verbose, or `5` = benchmark).\r\n *\r\n * @function setLogLevel\r\n *\r\n * @param {number} level - The log level to be set.\r\n */\r\nexport function setLogLevel(level) {\r\n if (\r\n Number.isInteger(level) &&\r\n level >= 0 &&\r\n level <= logging.levelsDesc.length\r\n ) {\r\n // Update the module logging's `level` option\r\n logging.level = level;\r\n }\r\n}\r\n\r\n/**\r\n * Enables console logging.\r\n *\r\n * @function enableConsoleLogging\r\n *\r\n * @param {boolean} toConsole - The flag for setting the logging to the console.\r\n */\r\nexport function enableConsoleLogging(toConsole) {\r\n // Update the module logging's `toConsole` option\r\n logging.toConsole = !!toConsole;\r\n}\r\n\r\n/**\r\n * Enables file logging with the specified destination and log file name.\r\n *\r\n * @function enableFileLogging\r\n *\r\n * @param {string} dest - The destination path where the log file should\r\n * be saved.\r\n * @param {string} file - The name of the log file.\r\n * @param {boolean} toFile - A flag indicating whether logging should\r\n * be directed to a file.\r\n */\r\nexport function enableFileLogging(dest, file, toFile) {\r\n // Update the module logging's `toFile` option\r\n logging.toFile = !!toFile;\r\n\r\n // Set the `dest` and `file` options only if the file logging is enabled\r\n if (logging.toFile) {\r\n logging.dest = dest || '';\r\n logging.file = file || '';\r\n }\r\n}\r\n\r\n/**\r\n * Logs the provided texts to a file, if file logging is enabled. It creates\r\n * the necessary directory structure if not already created and appends\r\n * the content, including an optional prefix, to the specified log file.\r\n *\r\n * @function _logToFile\r\n *\r\n * @param {Array.} texts - An array of texts to be logged.\r\n * @param {string} prefix - An optional prefix to be added to each log entry.\r\n */\r\nfunction _logToFile(texts, prefix) {\r\n if (!logging.pathCreated) {\r\n // Create if does not exist\r\n !existsSync(getAbsolutePath(logging.dest)) &&\r\n mkdirSync(getAbsolutePath(logging.dest));\r\n\r\n // Create the full path\r\n logging.pathToLog = getAbsolutePath(join(logging.dest, logging.file));\r\n\r\n // We now assume the path is available, e.g. it's the responsibility\r\n // of the user to create the path with the correct access rights.\r\n logging.pathCreated = true;\r\n }\r\n\r\n // Add the content to a file\r\n appendFile(\r\n logging.pathToLog,\r\n [prefix].concat(texts).join(' ') + '\\n',\r\n (error) => {\r\n if (error && logging.toFile && logging.pathCreated) {\r\n logging.toFile = false;\r\n logging.pathCreated = false;\r\n logWithStack(2, error, `[logger] Unable to write to log file.`);\r\n }\r\n }\r\n );\r\n}\r\n\r\nexport default {\r\n log,\r\n logWithStack,\r\n logZodIssues,\r\n initLogging,\r\n setLogLevel,\r\n enableConsoleLogging,\r\n enableFileLogging\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * @overview Configuration management module for the Highcharts Export Server.\r\n * Provides default configurations that support environment variables, CLI\r\n * arguments, and interactive prompts for customization of options and features.\r\n * Additionally, it maps legacy options to modern structures, generates nested\r\n * argument mappings, and displays CLI usage information.\r\n */\r\n\r\n/**\r\n * The configuration object containing all available options, organized\r\n * by sections.\r\n *\r\n * This object includes:\r\n * - Default values for each option\r\n * - Data types for validation\r\n * - Names of corresponding environment variables\r\n * - Descriptions of each property\r\n * - Information used for prompts in interactive configuration\r\n * - [Optional] Corresponding CLI argument names for CLI usage\r\n * - [Optional] Legacy names from the previous PhantomJS-based server\r\n */\r\nexport const defaultConfig = {\r\n puppeteer: {\r\n args: {\r\n value: [\r\n '--allow-running-insecure-content',\r\n '--ash-no-nudges',\r\n '--autoplay-policy=user-gesture-required',\r\n '--block-new-web-contents',\r\n '--disable-accelerated-2d-canvas',\r\n '--disable-background-networking',\r\n '--disable-background-timer-throttling',\r\n '--disable-backgrounding-occluded-windows',\r\n '--disable-breakpad',\r\n '--disable-checker-imaging',\r\n '--disable-client-side-phishing-detection',\r\n '--disable-component-extensions-with-background-pages',\r\n '--disable-component-update',\r\n '--disable-default-apps',\r\n '--disable-dev-shm-usage',\r\n '--disable-domain-reliability',\r\n '--disable-extensions',\r\n '--disable-features=CalculateNativeWinOcclusion,InterestFeedContentSuggestions,WebOTP',\r\n '--disable-hang-monitor',\r\n '--disable-ipc-flooding-protection',\r\n '--disable-logging',\r\n '--disable-notifications',\r\n '--disable-offer-store-unmasked-wallet-cards',\r\n '--disable-popup-blocking',\r\n '--disable-print-preview',\r\n '--disable-prompt-on-repost',\r\n '--disable-renderer-backgrounding',\r\n '--disable-search-engine-choice-screen',\r\n '--disable-session-crashed-bubble',\r\n '--disable-setuid-sandbox',\r\n '--disable-site-isolation-trials',\r\n '--disable-speech-api',\r\n '--disable-sync',\r\n '--enable-unsafe-webgpu',\r\n '--hide-crash-restore-bubble',\r\n '--hide-scrollbars',\r\n '--metrics-recording-only',\r\n '--mute-audio',\r\n '--no-default-browser-check',\r\n '--no-first-run',\r\n '--no-pings',\r\n '--no-sandbox',\r\n '--no-startup-window',\r\n '--no-zygote',\r\n '--password-store=basic',\r\n '--process-per-tab',\r\n '--use-mock-keychain'\r\n ],\r\n types: ['string[]'],\r\n envLink: 'PUPPETEER_ARGS',\r\n cliName: 'puppeteerArgs',\r\n description: 'Array of Puppeteer arguments',\r\n promptOptions: {\r\n type: 'list',\r\n separator: ';'\r\n }\r\n }\r\n },\r\n highcharts: {\r\n version: {\r\n value: 'latest',\r\n types: ['string'],\r\n envLink: 'HIGHCHARTS_VERSION',\r\n description: 'Highcharts version',\r\n promptOptions: {\r\n type: 'text'\r\n }\r\n },\r\n cdnUrl: {\r\n value: 'https://code.highcharts.com',\r\n types: ['string'],\r\n envLink: 'HIGHCHARTS_CDN_URL',\r\n description: 'CDN URL for Highcharts scripts',\r\n promptOptions: {\r\n type: 'text'\r\n }\r\n },\r\n forceFetch: {\r\n value: false,\r\n types: ['boolean'],\r\n envLink: 'HIGHCHARTS_FORCE_FETCH',\r\n description: 'Flag to refetch scripts after each server rerun',\r\n promptOptions: {\r\n type: 'toggle'\r\n }\r\n },\r\n cachePath: {\r\n value: '.cache',\r\n types: ['string'],\r\n envLink: 'HIGHCHARTS_CACHE_PATH',\r\n description: 'Directory path for cached Highcharts scripts',\r\n promptOptions: {\r\n type: 'text'\r\n }\r\n },\r\n coreScripts: {\r\n value: ['highcharts', 'highcharts-more', 'highcharts-3d'],\r\n types: ['string[]'],\r\n envLink: 'HIGHCHARTS_CORE_SCRIPTS',\r\n description: 'Highcharts core scripts to fetch',\r\n promptOptions: {\r\n type: 'multiselect',\r\n instructions: 'Space: Select specific, A: Select all, Enter: Confirm'\r\n }\r\n },\r\n moduleScripts: {\r\n value: [\r\n 'stock',\r\n 'map',\r\n 'gantt',\r\n 'exporting',\r\n 'parallel-coordinates',\r\n 'accessibility',\r\n // 'annotations-advanced',\r\n 'boost-canvas',\r\n 'boost',\r\n 'data',\r\n 'data-tools',\r\n 'draggable-points',\r\n 'static-scale',\r\n 'broken-axis',\r\n 'heatmap',\r\n 'tilemap',\r\n 'tiledwebmap',\r\n 'timeline',\r\n 'treemap',\r\n 'treegraph',\r\n 'item-series',\r\n 'drilldown',\r\n 'histogram-bellcurve',\r\n 'bullet',\r\n 'funnel',\r\n 'funnel3d',\r\n 'geoheatmap',\r\n 'pyramid3d',\r\n 'networkgraph',\r\n 'overlapping-datalabels',\r\n 'pareto',\r\n 'pattern-fill',\r\n 'pictorial',\r\n 'price-indicator',\r\n 'sankey',\r\n 'arc-diagram',\r\n 'dependency-wheel',\r\n 'series-label',\r\n 'series-on-point',\r\n 'solid-gauge',\r\n 'sonification',\r\n // 'stock-tools',\r\n 'streamgraph',\r\n 'sunburst',\r\n 'variable-pie',\r\n 'variwide',\r\n 'vector',\r\n 'venn',\r\n 'windbarb',\r\n 'wordcloud',\r\n 'xrange',\r\n 'no-data-to-display',\r\n 'drag-panes',\r\n 'debugger',\r\n 'dumbbell',\r\n 'lollipop',\r\n 'cylinder',\r\n 'organization',\r\n 'dotplot',\r\n 'marker-clusters',\r\n 'hollowcandlestick',\r\n 'heikinashi',\r\n 'flowmap',\r\n 'export-data',\r\n 'navigator',\r\n 'textpath'\r\n ],\r\n types: ['string[]'],\r\n envLink: 'HIGHCHARTS_MODULE_SCRIPTS',\r\n description: 'Highcharts module scripts to fetch',\r\n promptOptions: {\r\n type: 'multiselect',\r\n instructions: 'Space: Select specific, A: Select all, Enter: Confirm'\r\n }\r\n },\r\n indicatorScripts: {\r\n value: ['indicators-all'],\r\n types: ['string[]'],\r\n envLink: 'HIGHCHARTS_INDICATOR_SCRIPTS',\r\n description: 'Highcharts indicator scripts to fetch',\r\n promptOptions: {\r\n type: 'multiselect',\r\n instructions: 'Space: Select specific, A: Select all, Enter: Confirm'\r\n }\r\n },\r\n customScripts: {\r\n value: [\r\n 'https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.30.1/moment.min.js',\r\n 'https://cdnjs.cloudflare.com/ajax/libs/moment-timezone/0.5.45/moment-timezone-with-data.min.js'\r\n ],\r\n types: ['string[]'],\r\n envLink: 'HIGHCHARTS_CUSTOM_SCRIPTS',\r\n description: 'Additional custom scripts or dependencies to fetch',\r\n promptOptions: {\r\n type: 'list',\r\n separator: ';'\r\n }\r\n }\r\n },\r\n export: {\r\n infile: {\r\n value: null,\r\n types: ['string', 'null'],\r\n envLink: 'EXPORT_INFILE',\r\n description:\r\n 'Input filename with type, formatted correctly as JSON or SVG',\r\n promptOptions: {\r\n type: 'text'\r\n }\r\n },\r\n instr: {\r\n value: null,\r\n types: ['Object', 'string', 'null'],\r\n envLink: 'EXPORT_INSTR',\r\n description:\r\n 'Overrides the `infile` with JSON, stringified JSON, or SVG input',\r\n promptOptions: {\r\n type: 'text'\r\n }\r\n },\r\n options: {\r\n value: null,\r\n types: ['Object', 'string', 'null'],\r\n envLink: 'EXPORT_OPTIONS',\r\n description: 'Alias for the `instr` option',\r\n promptOptions: {\r\n type: 'text'\r\n }\r\n },\r\n svg: {\r\n value: null,\r\n types: ['string', 'null'],\r\n envLink: 'EXPORT_SVG',\r\n description: 'SVG string representation of the chart to render',\r\n promptOptions: {\r\n type: 'text'\r\n }\r\n },\r\n batch: {\r\n value: null,\r\n types: ['string', 'null'],\r\n envLink: 'EXPORT_BATCH',\r\n description:\r\n 'Batch job string with input/output pairs: \"in=out;in=out;...\"',\r\n promptOptions: {\r\n type: 'text'\r\n }\r\n },\r\n outfile: {\r\n value: null,\r\n types: ['string', 'null'],\r\n envLink: 'EXPORT_OUTFILE',\r\n description:\r\n 'Output filename with type. Can be jpeg, png, pdf, or svg and ignores `type` option',\r\n promptOptions: {\r\n type: 'text'\r\n }\r\n },\r\n type: {\r\n value: 'png',\r\n types: ['string'],\r\n envLink: 'EXPORT_TYPE',\r\n description: 'File export format. Can be jpeg, png, pdf, or svg',\r\n promptOptions: {\r\n type: 'select',\r\n hint: 'Default: png',\r\n choices: ['png', 'jpeg', 'pdf', 'svg']\r\n }\r\n },\r\n constr: {\r\n value: 'chart',\r\n types: ['string'],\r\n envLink: 'EXPORT_CONSTR',\r\n description:\r\n 'Chart constructor. Can be chart, stockChart, mapChart, or ganttChart',\r\n promptOptions: {\r\n type: 'select',\r\n hint: 'Default: chart',\r\n choices: ['chart', 'stockChart', 'mapChart', 'ganttChart']\r\n }\r\n },\r\n b64: {\r\n value: false,\r\n types: ['boolean'],\r\n envLink: 'EXPORT_B64',\r\n description:\r\n 'Whether or not to the chart should be received in Base64 format instead of binary',\r\n promptOptions: {\r\n type: 'toggle'\r\n }\r\n },\r\n noDownload: {\r\n value: false,\r\n types: ['boolean'],\r\n envLink: 'EXPORT_NO_DOWNLOAD',\r\n description:\r\n 'Whether or not to include or exclude attachment headers in the response',\r\n promptOptions: {\r\n type: 'toggle'\r\n }\r\n },\r\n height: {\r\n value: null,\r\n types: ['number', 'null'],\r\n envLink: 'EXPORT_HEIGHT',\r\n description: 'Height of the exported chart, overrides chart settings',\r\n promptOptions: {\r\n type: 'number'\r\n }\r\n },\r\n width: {\r\n value: null,\r\n types: ['number', 'null'],\r\n envLink: 'EXPORT_WIDTH',\r\n description: 'Width of the exported chart, overrides chart settings',\r\n promptOptions: {\r\n type: 'number'\r\n }\r\n },\r\n scale: {\r\n value: null,\r\n types: ['number', 'null'],\r\n envLink: 'EXPORT_SCALE',\r\n description:\r\n 'Scale of the exported chart, overrides chart settings. Ranges from 0.1 to 5.0',\r\n promptOptions: {\r\n type: 'number'\r\n }\r\n },\r\n defaultHeight: {\r\n value: 400,\r\n types: ['number'],\r\n envLink: 'EXPORT_DEFAULT_HEIGHT',\r\n description: 'Default height of the exported chart if not set',\r\n promptOptions: {\r\n type: 'number'\r\n }\r\n },\r\n defaultWidth: {\r\n value: 600,\r\n types: ['number'],\r\n envLink: 'EXPORT_DEFAULT_WIDTH',\r\n description: 'Default width of the exported chart if not set',\r\n promptOptions: {\r\n type: 'number'\r\n }\r\n },\r\n defaultScale: {\r\n value: 1,\r\n types: ['number'],\r\n envLink: 'EXPORT_DEFAULT_SCALE',\r\n description:\r\n 'Default scale of the exported chart if not set. Ranges from 0.1 to 5.0',\r\n promptOptions: {\r\n type: 'number',\r\n min: 0.1,\r\n max: 5\r\n }\r\n },\r\n globalOptions: {\r\n value: null,\r\n types: ['Object', 'string', 'null'],\r\n envLink: 'EXPORT_GLOBAL_OPTIONS',\r\n description:\r\n 'JSON, stringified JSON or filename with global options for Highcharts.setOptions',\r\n promptOptions: {\r\n type: 'text'\r\n }\r\n },\r\n themeOptions: {\r\n value: null,\r\n types: ['Object', 'string', 'null'],\r\n envLink: 'EXPORT_THEME_OPTIONS',\r\n description:\r\n 'JSON, stringified JSON or filename with theme options for Highcharts.setOptions',\r\n promptOptions: {\r\n type: 'text'\r\n }\r\n },\r\n rasterizationTimeout: {\r\n value: 1500,\r\n types: ['number'],\r\n envLink: 'EXPORT_RASTERIZATION_TIMEOUT',\r\n description: 'Milliseconds to wait for webpage rendering',\r\n promptOptions: {\r\n type: 'number'\r\n }\r\n }\r\n },\r\n customLogic: {\r\n allowCodeExecution: {\r\n value: false,\r\n types: ['boolean'],\r\n envLink: 'CUSTOM_LOGIC_ALLOW_CODE_EXECUTION',\r\n description:\r\n 'Allows or disallows execution of arbitrary code during exporting',\r\n promptOptions: {\r\n type: 'toggle'\r\n }\r\n },\r\n allowFileResources: {\r\n value: false,\r\n types: ['boolean'],\r\n envLink: 'CUSTOM_LOGIC_ALLOW_FILE_RESOURCES',\r\n description:\r\n 'Allows or disallows injection of filesystem resources (disabled in server mode)',\r\n promptOptions: {\r\n type: 'toggle'\r\n }\r\n },\r\n customCode: {\r\n value: null,\r\n types: ['string', 'null'],\r\n envLink: 'CUSTOM_LOGIC_CUSTOM_CODE',\r\n description:\r\n 'Custom code to execute before chart initialization. Can be a function, code wrapped in a function, or a .js filename',\r\n promptOptions: {\r\n type: 'text'\r\n }\r\n },\r\n callback: {\r\n value: null,\r\n types: ['string', 'null'],\r\n envLink: 'CUSTOM_LOGIC_CALLBACK',\r\n description:\r\n 'JavaScript code to run during construction. Can be a function or a .js filename',\r\n promptOptions: {\r\n type: 'text'\r\n }\r\n },\r\n resources: {\r\n value: null,\r\n types: ['Object', 'string', 'null'],\r\n envLink: 'CUSTOM_LOGIC_RESOURCES',\r\n description:\r\n 'Additional resources as JSON, stringified JSON, or filename, containing files, js, and css sections',\r\n promptOptions: {\r\n type: 'text'\r\n }\r\n },\r\n loadConfig: {\r\n value: null,\r\n types: ['string', 'null'],\r\n envLink: 'CUSTOM_LOGIC_LOAD_CONFIG',\r\n legacyName: 'fromFile',\r\n description: 'File with a pre-defined configuration to use',\r\n promptOptions: {\r\n type: 'text'\r\n }\r\n },\r\n createConfig: {\r\n value: null,\r\n types: ['string', 'null'],\r\n envLink: 'CUSTOM_LOGIC_CREATE_CONFIG',\r\n description:\r\n 'Prompt-based option setting, saved to a provided config file',\r\n promptOptions: {\r\n type: 'text'\r\n }\r\n }\r\n },\r\n server: {\r\n enable: {\r\n value: false,\r\n types: ['boolean'],\r\n envLink: 'SERVER_ENABLE',\r\n cliName: 'enableServer',\r\n description: 'Starts the server when true',\r\n promptOptions: {\r\n type: 'toggle'\r\n }\r\n },\r\n host: {\r\n value: '0.0.0.0',\r\n types: ['string'],\r\n envLink: 'SERVER_HOST',\r\n description: 'Hostname of the server',\r\n promptOptions: {\r\n type: 'text'\r\n }\r\n },\r\n port: {\r\n value: 7801,\r\n types: ['number'],\r\n envLink: 'SERVER_PORT',\r\n description: 'Port number for the server',\r\n promptOptions: {\r\n type: 'number'\r\n }\r\n },\r\n uploadLimit: {\r\n value: 3,\r\n types: ['number'],\r\n envLink: 'SERVER_UPLOAD_LIMIT',\r\n description: 'Maximum request body size in MB',\r\n promptOptions: {\r\n type: 'number'\r\n }\r\n },\r\n benchmarking: {\r\n value: false,\r\n types: ['boolean'],\r\n envLink: 'SERVER_BENCHMARKING',\r\n cliName: 'serverBenchmarking',\r\n description:\r\n 'Displays or not action durations in milliseconds during server requests',\r\n promptOptions: {\r\n type: 'toggle'\r\n }\r\n },\r\n proxy: {\r\n host: {\r\n value: null,\r\n types: ['string', 'null'],\r\n envLink: 'SERVER_PROXY_HOST',\r\n cliName: 'proxyHost',\r\n description: 'Host of the proxy server, if applicable',\r\n promptOptions: {\r\n type: 'text'\r\n }\r\n },\r\n port: {\r\n value: null,\r\n types: ['number', 'null'],\r\n envLink: 'SERVER_PROXY_PORT',\r\n cliName: 'proxyPort',\r\n description: 'Port of the proxy server, if applicable',\r\n promptOptions: {\r\n type: 'number'\r\n }\r\n },\r\n timeout: {\r\n value: 5000,\r\n types: ['number'],\r\n envLink: 'SERVER_PROXY_TIMEOUT',\r\n cliName: 'proxyTimeout',\r\n description:\r\n 'Timeout in milliseconds for the proxy server, if applicable',\r\n promptOptions: {\r\n type: 'number'\r\n }\r\n }\r\n },\r\n rateLimiting: {\r\n enable: {\r\n value: false,\r\n types: ['boolean'],\r\n envLink: 'SERVER_RATE_LIMITING_ENABLE',\r\n cliName: 'enableRateLimiting',\r\n description: 'Enables or disables rate limiting on the server',\r\n promptOptions: {\r\n type: 'toggle'\r\n }\r\n },\r\n maxRequests: {\r\n value: 10,\r\n types: ['number'],\r\n envLink: 'SERVER_RATE_LIMITING_MAX_REQUESTS',\r\n legacyName: 'rateLimit',\r\n description: 'Maximum number of requests allowed per minute',\r\n promptOptions: {\r\n type: 'number'\r\n }\r\n },\r\n window: {\r\n value: 1,\r\n types: ['number'],\r\n envLink: 'SERVER_RATE_LIMITING_WINDOW',\r\n description: 'Time window in minutes for rate limiting',\r\n promptOptions: {\r\n type: 'number'\r\n }\r\n },\r\n delay: {\r\n value: 0,\r\n types: ['number'],\r\n envLink: 'SERVER_RATE_LIMITING_DELAY',\r\n description:\r\n 'Delay duration between successive requests before reaching the limit',\r\n promptOptions: {\r\n type: 'number'\r\n }\r\n },\r\n trustProxy: {\r\n value: false,\r\n types: ['boolean'],\r\n envLink: 'SERVER_RATE_LIMITING_TRUST_PROXY',\r\n description: 'Set to true if the server is behind a load balancer',\r\n promptOptions: {\r\n type: 'toggle'\r\n }\r\n },\r\n skipKey: {\r\n value: null,\r\n types: ['string', 'null'],\r\n envLink: 'SERVER_RATE_LIMITING_SKIP_KEY',\r\n description: 'Key to bypass the rate limiter, used with `skipToken`',\r\n promptOptions: {\r\n type: 'text'\r\n }\r\n },\r\n skipToken: {\r\n value: null,\r\n types: ['string', 'null'],\r\n envLink: 'SERVER_RATE_LIMITING_SKIP_TOKEN',\r\n description: 'Token to bypass the rate limiter, used with `skipKey`',\r\n promptOptions: {\r\n type: 'text'\r\n }\r\n }\r\n },\r\n ssl: {\r\n enable: {\r\n value: false,\r\n types: ['boolean'],\r\n envLink: 'SERVER_SSL_ENABLE',\r\n cliName: 'enableSsl',\r\n description: 'Enables or disables SSL protocol',\r\n promptOptions: {\r\n type: 'toggle'\r\n }\r\n },\r\n force: {\r\n value: false,\r\n types: ['boolean'],\r\n envLink: 'SERVER_SSL_FORCE',\r\n cliName: 'sslForce',\r\n legacyName: 'sslOnly',\r\n description: 'Forces the server to use HTTPS only when true',\r\n promptOptions: {\r\n type: 'toggle'\r\n }\r\n },\r\n port: {\r\n value: 443,\r\n types: ['number'],\r\n envLink: 'SERVER_SSL_PORT',\r\n cliName: 'sslPort',\r\n description: 'Port for the SSL server',\r\n promptOptions: {\r\n type: 'number'\r\n }\r\n },\r\n certPath: {\r\n value: null,\r\n types: ['string', 'null'],\r\n envLink: 'SERVER_SSL_CERT_PATH',\r\n cliName: 'sslCertPath',\r\n legacyName: 'sslPath',\r\n description: 'Path to the SSL certificate/key file',\r\n promptOptions: {\r\n type: 'text'\r\n }\r\n }\r\n }\r\n },\r\n pool: {\r\n minWorkers: {\r\n value: 4,\r\n types: ['number'],\r\n envLink: 'POOL_MIN_WORKERS',\r\n description: 'Minimum and initial number of pool workers to spawn',\r\n promptOptions: {\r\n type: 'number'\r\n }\r\n },\r\n maxWorkers: {\r\n value: 8,\r\n types: ['number'],\r\n envLink: 'POOL_MAX_WORKERS',\r\n legacyName: 'workers',\r\n description: 'Maximum number of pool workers to spawn',\r\n promptOptions: {\r\n type: 'number'\r\n }\r\n },\r\n workLimit: {\r\n value: 40,\r\n types: ['number'],\r\n envLink: 'POOL_WORK_LIMIT',\r\n description: 'Number of tasks a worker can handle before restarting',\r\n promptOptions: {\r\n type: 'number'\r\n }\r\n },\r\n acquireTimeout: {\r\n value: 5000,\r\n types: ['number'],\r\n envLink: 'POOL_ACQUIRE_TIMEOUT',\r\n description: 'Timeout in milliseconds for acquiring a resource',\r\n promptOptions: {\r\n type: 'number'\r\n }\r\n },\r\n createTimeout: {\r\n value: 5000,\r\n types: ['number'],\r\n envLink: 'POOL_CREATE_TIMEOUT',\r\n description: 'Timeout in milliseconds for creating a resource',\r\n promptOptions: {\r\n type: 'number'\r\n }\r\n },\r\n destroyTimeout: {\r\n value: 5000,\r\n types: ['number'],\r\n envLink: 'POOL_DESTROY_TIMEOUT',\r\n description: 'Timeout in milliseconds for destroying a resource',\r\n promptOptions: {\r\n type: 'number'\r\n }\r\n },\r\n idleTimeout: {\r\n value: 30000,\r\n types: ['number'],\r\n envLink: 'POOL_IDLE_TIMEOUT',\r\n description: 'Timeout in milliseconds for destroying idle resources',\r\n promptOptions: {\r\n type: 'number'\r\n }\r\n },\r\n createRetryInterval: {\r\n value: 200,\r\n types: ['number'],\r\n envLink: 'POOL_CREATE_RETRY_INTERVAL',\r\n description:\r\n 'Interval in milliseconds before retrying resource creation on failure',\r\n promptOptions: {\r\n type: 'number'\r\n }\r\n },\r\n reaperInterval: {\r\n value: 1000,\r\n types: ['number'],\r\n envLink: 'POOL_REAPER_INTERVAL',\r\n description:\r\n 'Interval in milliseconds to check and destroy idle resources',\r\n promptOptions: {\r\n type: 'number'\r\n }\r\n },\r\n benchmarking: {\r\n value: false,\r\n types: ['boolean'],\r\n envLink: 'POOL_BENCHMARKING',\r\n cliName: 'poolBenchmarking',\r\n description: 'Shows statistics for the pool of resources',\r\n promptOptions: {\r\n type: 'toggle'\r\n }\r\n }\r\n },\r\n logging: {\r\n level: {\r\n value: 4,\r\n types: ['number'],\r\n envLink: 'LOGGING_LEVEL',\r\n cliName: 'logLevel',\r\n description: 'Logging verbosity level',\r\n promptOptions: {\r\n type: 'number',\r\n round: 0,\r\n min: 0,\r\n max: 5\r\n }\r\n },\r\n file: {\r\n value: 'highcharts-export-server.log',\r\n types: ['string'],\r\n envLink: 'LOGGING_FILE',\r\n cliName: 'logFile',\r\n description:\r\n 'Log file name. Requires `logToFile` and `logDest` to be set',\r\n promptOptions: {\r\n type: 'text'\r\n }\r\n },\r\n dest: {\r\n value: 'log',\r\n types: ['string'],\r\n envLink: 'LOGGING_DEST',\r\n cliName: 'logDest',\r\n description: 'Path to store log files. Requires `logToFile` to be set',\r\n promptOptions: {\r\n type: 'text'\r\n }\r\n },\r\n toConsole: {\r\n value: true,\r\n types: ['boolean'],\r\n envLink: 'LOGGING_TO_CONSOLE',\r\n cliName: 'logToConsole',\r\n description: 'Enables or disables console logging',\r\n promptOptions: {\r\n type: 'toggle'\r\n }\r\n },\r\n toFile: {\r\n value: true,\r\n types: ['boolean'],\r\n envLink: 'LOGGING_TO_FILE',\r\n cliName: 'logToFile',\r\n description: 'Enables or disables logging to a file',\r\n promptOptions: {\r\n type: 'toggle'\r\n }\r\n }\r\n },\r\n ui: {\r\n enable: {\r\n value: false,\r\n types: ['boolean'],\r\n envLink: 'UI_ENABLE',\r\n cliName: 'enableUi',\r\n description: 'Enables or disables the UI for the export server',\r\n promptOptions: {\r\n type: 'toggle'\r\n }\r\n },\r\n route: {\r\n value: '/',\r\n types: ['string'],\r\n envLink: 'UI_ROUTE',\r\n cliName: 'uiRoute',\r\n description: 'The endpoint route for the UI',\r\n promptOptions: {\r\n type: 'text'\r\n }\r\n }\r\n },\r\n other: {\r\n nodeEnv: {\r\n value: 'production',\r\n types: ['string'],\r\n envLink: 'OTHER_NODE_ENV',\r\n description: 'The Node.js environment type',\r\n promptOptions: {\r\n type: 'text'\r\n }\r\n },\r\n listenToProcessExits: {\r\n value: true,\r\n types: ['boolean'],\r\n envLink: 'OTHER_LISTEN_TO_PROCESS_EXITS',\r\n description: 'Whether or not to attach process.exit handlers',\r\n promptOptions: {\r\n type: 'toggle'\r\n }\r\n },\r\n noLogo: {\r\n value: false,\r\n types: ['boolean'],\r\n envLink: 'OTHER_NO_LOGO',\r\n description: 'Display or skip printing the logo on startup',\r\n promptOptions: {\r\n type: 'toggle'\r\n }\r\n },\r\n hardResetPage: {\r\n value: false,\r\n types: ['boolean'],\r\n envLink: 'OTHER_HARD_RESET_PAGE',\r\n description: 'Whether or not to reset the page content entirely',\r\n promptOptions: {\r\n type: 'toggle'\r\n }\r\n },\r\n browserShellMode: {\r\n value: true,\r\n types: ['boolean'],\r\n envLink: 'OTHER_BROWSER_SHELL_MODE',\r\n description: 'Whether or not to set the browser to run in shell mode',\r\n promptOptions: {\r\n type: 'toggle'\r\n }\r\n },\r\n validation: {\r\n value: true,\r\n types: ['boolean'],\r\n envLink: 'OTHER_VALIDATION',\r\n description: 'Whether or not to enable validation of options types',\r\n promptOptions: {\r\n type: 'toggle'\r\n }\r\n }\r\n },\r\n debug: {\r\n enable: {\r\n value: false,\r\n types: ['boolean'],\r\n envLink: 'DEBUG_ENABLE',\r\n cliName: 'enableDebug',\r\n description: 'Enables or disables debug mode for the underlying browser',\r\n promptOptions: {\r\n type: 'toggle'\r\n }\r\n },\r\n headless: {\r\n value: false,\r\n types: ['boolean'],\r\n envLink: 'DEBUG_HEADLESS',\r\n description:\r\n 'Whether or not to set the browser to run in headless mode during debugging',\r\n promptOptions: {\r\n type: 'toggle'\r\n }\r\n },\r\n devtools: {\r\n value: false,\r\n types: ['boolean'],\r\n envLink: 'DEBUG_DEVTOOLS',\r\n description: 'Enables or disables DevTools in headful mode',\r\n promptOptions: {\r\n type: 'toggle'\r\n }\r\n },\r\n listenToConsole: {\r\n value: false,\r\n types: ['boolean'],\r\n envLink: 'DEBUG_LISTEN_TO_CONSOLE',\r\n description:\r\n 'Enables or disables listening to console messages from the browser',\r\n promptOptions: {\r\n type: 'toggle'\r\n }\r\n },\r\n dumpio: {\r\n value: false,\r\n types: ['boolean'],\r\n envLink: 'DEBUG_DUMPIO',\r\n description:\r\n 'Redirects or not browser stdout and stderr to process.stdout and process.stderr',\r\n promptOptions: {\r\n type: 'toggle'\r\n }\r\n },\r\n slowMo: {\r\n value: 0,\r\n types: ['number'],\r\n envLink: 'DEBUG_SLOW_MO',\r\n description: 'Delays Puppeteer operations by the specified milliseconds',\r\n promptOptions: {\r\n type: 'number'\r\n }\r\n },\r\n debuggingPort: {\r\n value: 9222,\r\n types: ['number'],\r\n envLink: 'DEBUG_DEBUGGING_PORT',\r\n description: 'Port used for debugging',\r\n promptOptions: {\r\n type: 'number'\r\n }\r\n }\r\n }\r\n};\r\n\r\n// Properties nesting level of all options\r\nexport const nestedProps = _createNestedProps(defaultConfig);\r\n\r\n// Properties names that should not be recursively merged\r\nexport const absoluteProps = _createAbsoluteProps(defaultConfig);\r\n\r\n/**\r\n * Recursively generates a mapping of nested argument chains from a nested\r\n * config object. This function traverses a nested object and creates a mapping\r\n * where each key is an argument name (either from `cliName`, `legacyName`,\r\n * or the original key) and each value is a string representing the chain\r\n * of nested properties leading to that argument.\r\n *\r\n * @function _createNestedProps\r\n *\r\n * @param {Object} config - The configuration object.\r\n * @param {Object} [nestedProps={}] - The accumulator object for storing\r\n * the resulting arguments chains. The default value is an empty object.\r\n * @param {string} [propChain=''] - The current chain of nested properties,\r\n * used internally during recursion. The default value is an empty string.\r\n *\r\n * @returns {Object} An object mapping argument names to their corresponding\r\n * nested property chains.\r\n */\r\nfunction _createNestedProps(config, nestedProps = {}, propChain = '') {\r\n Object.keys(config).forEach((key) => {\r\n // Get the specific section\r\n const entry = config[key];\r\n\r\n // Check if there is still more depth to traverse\r\n if (typeof entry.value === 'undefined') {\r\n // Recurse into deeper levels of nested arguments\r\n _createNestedProps(entry, nestedProps, `${propChain}.${key}`);\r\n } else {\r\n // Create the chain of nested arguments\r\n nestedProps[entry.cliName || key] = `${propChain}.${key}`.substring(1);\r\n\r\n // Support for the legacy, PhantomJS properties names\r\n if (entry.legacyName !== undefined) {\r\n nestedProps[entry.legacyName] = `${propChain}.${key}`.substring(1);\r\n }\r\n }\r\n });\r\n\r\n // Return the object with nested argument chains\r\n return nestedProps;\r\n}\r\n\r\n/**\r\n * Recursively gathers the names of properties from a configuration object that\r\n * can be treated as absolute properties. These properties have values that\r\n * are objects and do not contain further nested depth when merging an object\r\n * containing these options.\r\n *\r\n * @function _createAbsoluteProps\r\n *\r\n * @param {Object} config - The configuration object.\r\n * @param {Array.} [absoluteProps=[]] - An array to collect the names\r\n * of absolute properties. The default value is an empty array.\r\n *\r\n * @returns {Array.} An array containing the names of absolute\r\n * properties.\r\n */\r\nfunction _createAbsoluteProps(config, absoluteProps = []) {\r\n Object.keys(config).forEach((key) => {\r\n // Get the specific section\r\n const entry = config[key];\r\n\r\n // Check if there is still more depth to traverse\r\n if (typeof entry.types === 'undefined') {\r\n // Recurse into deeper levels\r\n _createAbsoluteProps(entry, absoluteProps);\r\n } else {\r\n // If the option can be an object, save its type in the array\r\n if (entry.types.includes('Object')) {\r\n absoluteProps.push(key);\r\n }\r\n }\r\n });\r\n\r\n // Return the array with the names of absolute properties\r\n return absoluteProps;\r\n}\r\n\r\nexport default {\r\n defaultConfig,\r\n nestedProps,\r\n absoluteProps\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * @overview This file handles parsing and validating options from multiple\r\n * sources (the config file, custom JSON, environment variables, CLI arguments,\r\n * and request payload) using the 'zod' library.\r\n *\r\n * Environment variables are parsed and validated only once at application\r\n * startup, and the validated results are exported as `envs` for use throughout\r\n * the application.\r\n *\r\n * Options from other sources, however, are parsed and validated on demand,\r\n * each time an export is attempted.\r\n */\r\n\r\nimport dotenv from 'dotenv';\r\nimport { z } from 'zod';\r\n\r\nimport { defaultConfig } from './schemas/config.js';\r\n\r\n// Load the .env into environment variables\r\ndotenv.config();\r\n\r\n// Get scripts names of each category from the default config\r\nconst { coreScripts, moduleScripts, indicatorScripts } =\r\n defaultConfig.highcharts;\r\n\r\n// Sets the custom error map globally\r\nz.setErrorMap(_customErrorMap);\r\n\r\n/**\r\n * Object containing custom general validators and parsers to avoid repetition\r\n * in schema objects. All validators apply to values from various sources,\r\n * including the default config file, a custom JSON file loaded with the option\r\n * called `loadConfig`, the .env file, CLI arguments, and the request payload.\r\n * The `strictCheck` flag enables stricter validation and parsing rules. This\r\n * flag is set to false for values that come from the .env file or CLI arguments\r\n * because they are provided as strings and need to be parsed accordingly first.\r\n */\r\nconst v = {\r\n /**\r\n * The `boolean` validator that returns a Zod schema with an optional stricter\r\n * check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures that:\r\n *\r\n * - When `strictCheck` is true, the schema will accept values are true\r\n * and false and the schema will validate against the default boolean\r\n * validator.\r\n *\r\n * - When `strictCheck` is false, the schema will accept values are true,\r\n * false, null, 'true', '1', 'false', '0', 'undefined', 'null', and ''.\r\n * The strings 'undefined', 'null', and '' will be transformed to null,\r\n * the string 'true' will be transformed to the boolean value true,\r\n * and 'false' will be transformed to the boolean value false.\r\n *\r\n * @function boolean\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating boolean values.\r\n */\r\n boolean(strictCheck) {\r\n return strictCheck\r\n ? z.boolean()\r\n : z\r\n .union([\r\n z\r\n .enum(['true', '1', 'false', '0', 'undefined', 'null', ''])\r\n .transform((value) =>\r\n !['undefined', 'null', ''].includes(value)\r\n ? value === 'true' || value === '1'\r\n : null\r\n ),\r\n z.boolean()\r\n ])\r\n .nullable();\r\n },\r\n\r\n /**\r\n * The `string` validator that returns a Zod schema with an optional stricter\r\n * check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures that:\r\n *\r\n * - When `strictCheck` is true, the schema will accept trimmed strings except\r\n * the forbidden values: 'false', 'undefined', 'null', and ''.\r\n *\r\n * - When `strictCheck` is false, the schema will accept trimmed strings\r\n * and null. The forbidden values: 'false', 'undefined', 'null', and '' will\r\n * be transformed to null.\r\n *\r\n * @function string\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating string values.\r\n */\r\n string(strictCheck) {\r\n return strictCheck\r\n ? z\r\n .string()\r\n .trim()\r\n .refine(\r\n (value) => !['false', 'undefined', 'null', ''].includes(value),\r\n {\r\n params: {\r\n errorMessage: 'The string contains a forbidden value'\r\n }\r\n }\r\n )\r\n : z\r\n .string()\r\n .trim()\r\n .transform((value) =>\r\n !['false', 'undefined', 'null', ''].includes(value) ? value : null\r\n )\r\n .nullable();\r\n },\r\n\r\n /**\r\n * The `enum` validator that returns a Zod schema with an optional stricter\r\n * check based on the `strictCheck` parameter.\r\n *\r\n * The schema will validate against the provided `values` array.\r\n *\r\n * The validation schema ensures that:\r\n *\r\n * - When `strictCheck` is true, the schema will validate against the `values`\r\n * array with the default enum validator.\r\n *\r\n * - When `strictCheck` is false, the schema will accept also null,\r\n * 'undefined', 'null', and '', which will be transformed to null.\r\n *\r\n * @function enum\r\n *\r\n * @param {Array.} values - An array of valid string values\r\n * for the enum.\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating enum values.\r\n */\r\n enum(values, strictCheck) {\r\n return strictCheck\r\n ? z.enum([...values])\r\n : z\r\n .enum([...values, 'undefined', 'null', ''])\r\n .transform((value) =>\r\n !['undefined', 'null', ''].includes(value) ? value : null\r\n )\r\n .nullable();\r\n },\r\n\r\n /**\r\n * The `stringArray` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures that:\r\n *\r\n * - When `strictCheck` is true, the schema will accept an array of trimmed\r\n * string values filtered by the logic provided through the `filterCallback`.\r\n *\r\n * - When `strictCheck` is false, the schema will accept null and trimmed\r\n * string values which will be splitted into an array of strings and filtered\r\n * from the '[' and ']' characters and by the logic provided through\r\n * the `filterCallback`. If the array is empty, it will be transformed\r\n * to null.\r\n *\r\n * @function stringArray\r\n *\r\n * @param {function} filterCallback - The filter callback.\r\n * @param {string} separator - The separator for spliting a string.\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating array of string\r\n * values.\r\n */\r\n stringArray(filterCallback, separator, strictCheck) {\r\n const arraySchema = z.string().trim().array();\r\n const stringSchema = z\r\n .string()\r\n .trim()\r\n .transform((value) => {\r\n if (value.startsWith('[')) {\r\n value = value.slice(1);\r\n }\r\n if (value.endsWith(']')) {\r\n value = value.slice(0, -1);\r\n }\r\n return value.split(separator);\r\n });\r\n\r\n const transformCallback = (value) =>\r\n value.map((value) => value.trim()).filter(filterCallback);\r\n\r\n return strictCheck\r\n ? arraySchema.transform(transformCallback)\r\n : z\r\n .union([stringSchema, arraySchema])\r\n .transform(transformCallback)\r\n .transform((value) => (value.length ? value : null))\r\n .nullable();\r\n },\r\n\r\n /**\r\n * The `positiveNum` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures that:\r\n *\r\n * - When `strictCheck` is true, the schema will accept positive number values\r\n * and validate against the default positive number validator.\r\n *\r\n * - When `strictCheck` is false, the schema will accept positive number\r\n * values, null, and trimmed string values that can either be 'undefined',\r\n * 'null', '', or represent a positive number. It will transform the string\r\n * to a positive number, or to null if it is 'undefined', 'null', or ''.\r\n *\r\n * @function positiveNum\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating positive number\r\n * values.\r\n */\r\n positiveNum(strictCheck) {\r\n return strictCheck\r\n ? z.number().positive()\r\n : z\r\n .union([\r\n z\r\n .string()\r\n .trim()\r\n .refine(\r\n (value) =>\r\n (!isNaN(Number(value)) && Number(value) > 0) ||\r\n ['undefined', 'null', ''].includes(value),\r\n {\r\n params: {\r\n errorMessage: 'The value must be numeric and positive'\r\n }\r\n }\r\n )\r\n .transform((value) =>\r\n !['undefined', 'null', ''].includes(value)\r\n ? Number(value)\r\n : null\r\n ),\r\n z.number().positive()\r\n ])\r\n .nullable();\r\n },\r\n\r\n /**\r\n * The `nonNegativeNum` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures that:\r\n *\r\n * - When `strictCheck` is true, the schema will accept non-negative number\r\n * values and validate against the default non-negative number validator.\r\n *\r\n * - When `strictCheck` is false, the schema will accept non-negative number\r\n * values, null, and trimmed string values that can either be 'undefined',\r\n * 'null', '', or represent a non-negative number. It will transform\r\n * the string to a non-negative number, or to null if it is 'undefined',\r\n * 'null', or ''.\r\n *\r\n * @function nonNegativeNum\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating non-negative\r\n * number values.\r\n */\r\n nonNegativeNum(strictCheck) {\r\n return strictCheck\r\n ? z.number().nonnegative()\r\n : z\r\n .union([\r\n z\r\n .string()\r\n .trim()\r\n .refine(\r\n (value) =>\r\n (!isNaN(Number(value)) && Number(value) >= 0) ||\r\n ['undefined', 'null', ''].includes(value),\r\n {\r\n params: {\r\n errorMessage: 'The value must be numeric and non-negative'\r\n }\r\n }\r\n )\r\n .transform((value) =>\r\n !['undefined', 'null', ''].includes(value)\r\n ? Number(value)\r\n : null\r\n ),\r\n z.number().nonnegative()\r\n ])\r\n .nullable();\r\n },\r\n\r\n /**\r\n * The `startsWith` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The schema will validate against the provided `prefixes` array to check\r\n * whether a string value starts with any of the values provided\r\n * in the `prefixes` array.\r\n *\r\n * The validation schema ensures that:\r\n *\r\n * - When `strictCheck` is true, the schema will accept trimmed string values\r\n * that start with values from the prefixes array.\r\n *\r\n * - When `strictCheck` is false, the schema will accept trimmed string values\r\n * that start with values from the prefixes array, null, 'undefined', 'null',\r\n * and '' where the schema will transform them to null.\r\n *\r\n * @function startsWith\r\n *\r\n * @param {Array.} prefixes - An array of prefixes to validate\r\n * the string against.\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating strings that\r\n * starts with values.\r\n */\r\n startsWith(prefixes, strictCheck) {\r\n return strictCheck\r\n ? z\r\n .string()\r\n .trim()\r\n .refine(\r\n (value) => prefixes.some((prefix) => value.startsWith(prefix)),\r\n {\r\n params: {\r\n errorMessage: `The value must be a string that starts with ${prefixes.join(', ')}`\r\n }\r\n }\r\n )\r\n : z\r\n .string()\r\n .trim()\r\n .refine(\r\n (value) =>\r\n prefixes.some((prefix) => value.startsWith(prefix)) ||\r\n ['undefined', 'null', ''].includes(value),\r\n {\r\n params: {\r\n errorMessage: `The value must be a string that starts with ${prefixes.join(', ')}`\r\n }\r\n }\r\n )\r\n .transform((value) =>\r\n !['undefined', 'null', ''].includes(value) ? value : null\r\n )\r\n .nullable();\r\n },\r\n\r\n /**\r\n * The `chartConfig` validator that returns a Zod schema.\r\n *\r\n * The validation schema ensures that the schema will accept object values\r\n * or trimmed string values that contain '\r\n (value.startsWith('{') && value.endsWith('}')) ||\r\n ['undefined', 'null', ''].includes(value),\r\n {\r\n params: {\r\n errorMessage:\r\n \"The value must be a string that starts with '{' and ends with '}'\"\r\n }\r\n }\r\n )\r\n .transform((value) =>\r\n !['undefined', 'null', ''].includes(value) ? value : null\r\n ),\r\n z.object({}).passthrough()\r\n ])\r\n .nullable();\r\n },\r\n\r\n /**\r\n * The `additionalOptions` validator that returns a Zod schema.\r\n *\r\n * The validation schema ensures that the schema will accept object values\r\n * or trimmed string values that end with '.json' and are at least one\r\n * character long excluding the extension, start with the '{' and end\r\n * with the '}', and null. The 'undefined', 'null', and '' values will\r\n * be transformed to null.\r\n *\r\n * @function additionalOptions\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating additional chart\r\n * options value.\r\n */\r\n additionalOptions() {\r\n return z\r\n .union([\r\n z\r\n .string()\r\n .trim()\r\n .refine(\r\n (value) =>\r\n (value.length >= 6 && value.endsWith('.json')) ||\r\n (value.startsWith('{') && value.endsWith('}')) ||\r\n ['undefined', 'null', ''].includes(value),\r\n {\r\n params: {\r\n errorMessage:\r\n \"The value must be a string that ends with '.json' or starts with '{' and ends with '}'\"\r\n }\r\n }\r\n )\r\n .transform((value) =>\r\n !['undefined', 'null', ''].includes(value) ? value : null\r\n ),\r\n z.object({}).passthrough()\r\n ])\r\n .nullable();\r\n }\r\n};\r\n\r\n/**\r\n * Object containing custom config validators and parsers to avoid repetition\r\n * in schema objects. All validators apply to values from various sources,\r\n * including the default config file, a custom JSON file loaded with the option\r\n * called `loadConfig`, the .env file, CLI arguments, and the request payload.\r\n * The `strictCheck` flag enables stricter validation and parsing rules. This\r\n * flag is set to false for values that come from the .env file or CLI arguments\r\n * because they are provided as strings and need to be parsed accordingly first.\r\n */\r\nexport const validators = {\r\n /**\r\n * The `args` validator that returns a Zod schema with an optional stricter\r\n * check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `stringArray` validator.\r\n *\r\n * @function args\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `args`\r\n * option.\r\n */\r\n args(strictCheck) {\r\n return v.stringArray(\r\n (value) => !['false', 'undefined', 'null', ''].includes(value),\r\n ';',\r\n strictCheck\r\n );\r\n },\r\n\r\n /**\r\n * The `version` validator that returns a Zod schema with an optional stricter\r\n * check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures that:\r\n *\r\n * - When `strictCheck` is true, the schema will accept trimmed string values\r\n * that are a RegExp-based that allows to be 'latest', or in the format XX,\r\n * XX.YY, or XX.YY.ZZ, where XX, YY, and ZZ are numeric for the Highcharts\r\n * version option.\r\n *\r\n * - When `strictCheck` is false, the schema will accept also null,\r\n * 'undefined', 'null', or '' and in all cases the schema will transform them\r\n * to null.\r\n *\r\n * @function version\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `version`\r\n * option.\r\n */\r\n version(strictCheck) {\r\n return strictCheck\r\n ? z\r\n .string()\r\n .trim()\r\n .refine((value) => /^(latest|\\d{1,2}(\\.\\d{1,2}){0,2})$/.test(value), {\r\n params: {\r\n errorMessage:\r\n \"The value must be 'latest', a major version, or in the form XX.YY.ZZ\"\r\n }\r\n })\r\n : z\r\n .string()\r\n .trim()\r\n .refine(\r\n (value) =>\r\n /^(latest|\\d{1,2}(\\.\\d{1,2}){0,2})$/.test(value) ||\r\n ['undefined', 'null', ''].includes(value),\r\n {\r\n params: {\r\n errorMessage:\r\n \"The value must be 'latest', a major version, or in the form XX.YY.ZZ\"\r\n }\r\n }\r\n )\r\n .transform((value) =>\r\n !['undefined', 'null', ''].includes(value) ? value : null\r\n )\r\n .nullable();\r\n },\r\n\r\n /**\r\n * The `cdnUrl` validator that returns a Zod schema with an optional stricter\r\n * check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `startsWith` validator.\r\n *\r\n * @function cdnUrl\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `cdnUrl`\r\n * option.\r\n */\r\n cdnUrl(strictCheck) {\r\n return v.startsWith(['http://', 'https://'], strictCheck);\r\n },\r\n\r\n /**\r\n * The `forceFetch` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `boolean` validator.\r\n *\r\n * @function forceFetch\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `forceFetch`\r\n * option.\r\n */\r\n forceFetch(strictCheck) {\r\n return v.boolean(strictCheck);\r\n },\r\n\r\n /**\r\n * The `cachePath` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `string` validator.\r\n *\r\n * @function cachePath\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `cachePath`\r\n * option.\r\n */\r\n cachePath(strictCheck) {\r\n return v.string(strictCheck);\r\n },\r\n\r\n /**\r\n * The `adminToken` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `string` validator.\r\n *\r\n * @function adminToken\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `adminToken`\r\n * option.\r\n */\r\n adminToken(strictCheck) {\r\n return v.string(strictCheck);\r\n },\r\n\r\n /**\r\n * The `coreScripts` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `stringArray` validator.\r\n *\r\n * @function coreScripts\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `coreScripts`\r\n * option.\r\n */\r\n coreScripts(strictCheck) {\r\n return v.stringArray(\r\n (value) => coreScripts.value.includes(value),\r\n ',',\r\n strictCheck\r\n );\r\n },\r\n\r\n /**\r\n * The `moduleScripts` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `stringArray` validator.\r\n *\r\n * @function moduleScripts\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating\r\n * the `moduleScripts` option.\r\n */\r\n moduleScripts(strictCheck) {\r\n return v.stringArray(\r\n (value) => moduleScripts.value.includes(value),\r\n ',',\r\n strictCheck\r\n );\r\n },\r\n\r\n /**\r\n * The `indicatorScripts` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `stringArray` validator.\r\n *\r\n * @function indicatorScripts\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating\r\n * the `indicatorScripts` option.\r\n */\r\n indicatorScripts(strictCheck) {\r\n return v.stringArray(\r\n (value) => indicatorScripts.value.includes(value),\r\n ',',\r\n strictCheck\r\n );\r\n },\r\n\r\n /**\r\n * The `customScripts` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `stringArray` validator.\r\n *\r\n * @function customScripts\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating\r\n * the `customScripts` option.\r\n */\r\n customScripts(strictCheck) {\r\n return v.stringArray(\r\n (value) => value.startsWith('https://') || value.startsWith('http://'),\r\n ',',\r\n strictCheck\r\n );\r\n },\r\n\r\n /**\r\n * The `infile` validator that returns a Zod schema with an optional stricter\r\n * check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures that:\r\n *\r\n * - When `strictCheck` is true, the schema will accept trimmed string values\r\n * that end with '.json' or '.svg', are at least one character long excluding\r\n * the extension, or null.\r\n *\r\n * - When `strictCheck` is false, the schema will accept trimmed string values\r\n * that end with '.json' or '.svg', are at least one character long excluding\r\n * the extension and will be null if the provided value is null, 'undefined',\r\n * 'null', or ''.\r\n *\r\n * @function infile\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `infile`\r\n * option.\r\n */\r\n infile(strictCheck) {\r\n return strictCheck\r\n ? z\r\n .string()\r\n .trim()\r\n .refine(\r\n (value) =>\r\n (value.length >= 6 && value.endsWith('.json')) ||\r\n (value.length >= 5 && value.endsWith('.svg')),\r\n {\r\n params: {\r\n errorMessage:\r\n 'The value must be a string that ends with .json or .svg'\r\n }\r\n }\r\n )\r\n .nullable()\r\n : z\r\n .string()\r\n .trim()\r\n .refine(\r\n (value) =>\r\n (value.length >= 6 && value.endsWith('.json')) ||\r\n (value.length >= 5 && value.endsWith('.svg')) ||\r\n ['undefined', 'null', ''].includes(value),\r\n {\r\n params: {\r\n errorMessage:\r\n 'The value must be a string that ends with .json or .svg'\r\n }\r\n }\r\n )\r\n .transform((value) =>\r\n !['undefined', 'null', ''].includes(value) ? value : null\r\n )\r\n .nullable();\r\n },\r\n\r\n /**\r\n * The `instr` validator that returns a Zod schema.\r\n *\r\n * The validation schema ensures the same work as the `options` validator.\r\n *\r\n * @function instr\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `instr`\r\n * option.\r\n */\r\n instr() {\r\n return v.chartConfig();\r\n },\r\n\r\n /**\r\n * The `options` validator that returns a Zod schema.\r\n *\r\n * The validation schema ensures the same work as the `options` validator.\r\n *\r\n * @function options\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `options`\r\n * option.\r\n */\r\n options() {\r\n return v.chartConfig();\r\n },\r\n\r\n /**\r\n * The `svg` validator that returns a Zod schema.\r\n *\r\n * The validation schema ensures that the schema will accept object values\r\n * or trimmed string values that contain '\r\n value.indexOf('= 0 ||\r\n value.indexOf('= 0 ||\r\n ['false', 'undefined', 'null', ''].includes(value),\r\n {\r\n params: {\r\n errorMessage:\r\n \"The value must be a string that contains '\r\n !['false', 'undefined', 'null', ''].includes(value) ? value : null\r\n )\r\n .nullable();\r\n },\r\n\r\n /**\r\n * The `outfile` validator that returns a Zod schema with an optional stricter\r\n * check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures that:\r\n *\r\n * - When `strictCheck` is true, the schema will accept trimmed string values\r\n * that end with '.jpeg', '.jpg', '.png', '.pdf', or '.svg', are at least one\r\n * character long excluding the extension, or null.\r\n *\r\n * - When `strictCheck` is false, the schema will accept trimmed string values\r\n * that end with '.jpeg', '.jpg', '.png', '.pdf', or '.svg', are at least one\r\n * character long excluding the extension and will be null if the provided\r\n * value is null, 'undefined', 'null', or ''.\r\n *\r\n * @function outfile\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `outfile`\r\n * option.\r\n */\r\n outfile(strictCheck) {\r\n return strictCheck\r\n ? z\r\n .string()\r\n .trim()\r\n .refine(\r\n (value) =>\r\n (value.length >= 6 && value.endsWith('.jpeg')) ||\r\n (value.length >= 5 &&\r\n (value.endsWith('.jpg') ||\r\n value.endsWith('.png') ||\r\n value.endsWith('.pdf') ||\r\n value.endsWith('.svg'))),\r\n {\r\n params: {\r\n errorMessage:\r\n 'The value must be a string that ends with .jpeg, .jpg, .png, .pdf, or .svg'\r\n }\r\n }\r\n )\r\n .nullable()\r\n : z\r\n .string()\r\n .trim()\r\n .refine(\r\n (value) =>\r\n (value.length >= 6 && value.endsWith('.jpeg')) ||\r\n (value.length >= 5 &&\r\n (value.endsWith('.jpg') ||\r\n value.endsWith('.png') ||\r\n value.endsWith('.pdf') ||\r\n value.endsWith('.svg'))) ||\r\n ['undefined', 'null', ''].includes(value),\r\n {\r\n params: {\r\n errorMessage:\r\n 'The value must be a string that ends with .jpeg, .jpg, .png, .pdf, or .svg'\r\n }\r\n }\r\n )\r\n .transform((value) =>\r\n !['undefined', 'null', ''].includes(value) ? value : null\r\n )\r\n .nullable();\r\n },\r\n\r\n /**\r\n * The `type` validator that returns a Zod schema with an optional stricter\r\n * check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `enum` validator.\r\n *\r\n * @function type\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `type`\r\n * option.\r\n */\r\n type(strictCheck) {\r\n return v.enum(['jpeg', 'jpg', 'png', 'pdf', 'svg'], strictCheck);\r\n },\r\n\r\n /**\r\n * The `constr` validator that returns a Zod schema with an optional stricter\r\n * check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `enum` validator.\r\n *\r\n * @function constr\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `constr`\r\n * option.\r\n */\r\n constr(strictCheck) {\r\n return v.enum(\r\n ['chart', 'stockChart', 'mapChart', 'ganttChart'],\r\n strictCheck\r\n );\r\n },\r\n\r\n /**\r\n * The `b64` validator that returns a Zod schema with an optional stricter\r\n * check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `boolean` validator.\r\n *\r\n * @function b64\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `b64` option.\r\n */\r\n b64(strictCheck) {\r\n return v.boolean(strictCheck);\r\n },\r\n\r\n /**\r\n * The `noDownload` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `boolean` validator.\r\n *\r\n * @function noDownload\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `noDownload`\r\n * option.\r\n */\r\n noDownload(strictCheck) {\r\n return v.boolean(strictCheck);\r\n },\r\n\r\n /**\r\n * The `defaultHeight` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `positiveNum` validator.\r\n *\r\n * @function defaultHeight\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating\r\n * the `defaultHeight` option.\r\n */\r\n defaultHeight(strictCheck) {\r\n return v.positiveNum(strictCheck);\r\n },\r\n\r\n /**\r\n * The `defaultWidth` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `positiveNum` validator.\r\n *\r\n * @function defaultWidth\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating\r\n * the `defaultWidth` option.\r\n */\r\n defaultWidth(strictCheck) {\r\n return v.positiveNum(strictCheck);\r\n },\r\n\r\n /**\r\n * The `defaultScale` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures that:\r\n *\r\n * - When `strictCheck` is true, the schema will accept number values that\r\n * are between 0.1 and 5 (inclusive).\r\n *\r\n * - When `strictCheck` is false, the schema will accept number values\r\n * and stringified number values that are between 0.1 and 5 (inclusive), null,\r\n * 'undefined', 'null', and '' which will be transformed to null.\r\n *\r\n * @function defaultScale\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating\r\n * the `defaultScale` option.\r\n */\r\n defaultScale(strictCheck) {\r\n return strictCheck\r\n ? z.number().gte(0.1).lte(5)\r\n : z\r\n .union([\r\n z\r\n .string()\r\n .trim()\r\n .refine(\r\n (value) =>\r\n (!isNaN(Number(value)) &&\r\n value !== true &&\r\n !value.startsWith('[') &&\r\n Number(value) >= 0.1 &&\r\n Number(value) <= 5) ||\r\n ['undefined', 'null', ''].includes(value),\r\n {\r\n params: {\r\n errorMessage: 'The value must be within a 0.1 and 5.0 range'\r\n }\r\n }\r\n )\r\n .transform((value) =>\r\n !['undefined', 'null', ''].includes(value)\r\n ? Number(value)\r\n : null\r\n ),\r\n z.number().gte(0.1).lte(5)\r\n ])\r\n .nullable();\r\n },\r\n\r\n /**\r\n * The `height` validator that returns a Zod schema with an optional stricter\r\n * check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as a nullable `defaultHeight`\r\n * validator.\r\n *\r\n * @function height\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `height`\r\n * option.\r\n */\r\n height(strictCheck) {\r\n return this.defaultHeight(strictCheck).nullable();\r\n },\r\n\r\n /**\r\n * The `width` validator that returns a Zod schema with an optional stricter\r\n * check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as a nullable `defaultWidth`\r\n * validator.\r\n *\r\n * @function width\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `width`\r\n * option.\r\n */\r\n width(strictCheck) {\r\n return this.defaultWidth(strictCheck).nullable();\r\n },\r\n\r\n /**\r\n * The `scale` validator that returns a Zod schema with an optional stricter\r\n * check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as a nullable `defaultScale`\r\n * validator.\r\n *\r\n * @function scale\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `scale`\r\n * option.\r\n */\r\n scale(strictCheck) {\r\n return this.defaultScale(strictCheck).nullable();\r\n },\r\n\r\n /**\r\n * The `globalOptions` validator that returns a Zod schema.\r\n *\r\n * The validation schema ensures the same work as the `additionalOptions`\r\n * validator.\r\n *\r\n * @function globalOptions\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating\r\n * the `globalOptions` option.\r\n */\r\n globalOptions() {\r\n return v.additionalOptions();\r\n },\r\n\r\n /**\r\n * The `themeOptions` validator that returns a Zod schema.\r\n *\r\n * The validation schema ensures the same work as the `additionalOptions`\r\n * validator.\r\n *\r\n * @function themeOptions\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating\r\n * the `themeOptions` option.\r\n */\r\n themeOptions() {\r\n return v.additionalOptions();\r\n },\r\n\r\n /**\r\n * The `batch` validator that returns a Zod schema with an optional stricter\r\n * check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `string` validator.\r\n *\r\n * @function batch\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `batch`\r\n * option.\r\n */\r\n batch(strictCheck) {\r\n return v.string(strictCheck);\r\n },\r\n\r\n /**\r\n * The `rasterizationTimeout` validator that returns a Zod schema with\r\n * an optional stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `nonNegativeNum`\r\n * validator.\r\n *\r\n * @function rasterizationTimeout\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating\r\n * the `rasterizationTimeout` option.\r\n */\r\n rasterizationTimeout(strictCheck) {\r\n return v.nonNegativeNum(strictCheck);\r\n },\r\n\r\n /**\r\n * The `allowCodeExecution` validator that returns a Zod schema with\r\n * an optional stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `boolean` validator.\r\n *\r\n * @function allowCodeExecution\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating\r\n * the `allowCodeExecution` option.\r\n */\r\n allowCodeExecution(strictCheck) {\r\n return v.boolean(strictCheck);\r\n },\r\n\r\n /**\r\n * The `allowFileResources` validator that returns a Zod schema with\r\n * an optional stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `boolean` validator.\r\n *\r\n * @function allowFileResources\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating\r\n * the `allowFileResources` option.\r\n */\r\n allowFileResources(strictCheck) {\r\n return v.boolean(strictCheck);\r\n },\r\n\r\n /**\r\n * The `customCode` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `string` validator.\r\n *\r\n * @function customCode\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `customCode`\r\n * option.\r\n */\r\n customCode(strictCheck) {\r\n return v.string(strictCheck);\r\n },\r\n\r\n /**\r\n * The `callback` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `string` validator.\r\n *\r\n * @function callback\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `callback`\r\n * option.\r\n */\r\n callback(strictCheck) {\r\n return v.string(strictCheck);\r\n },\r\n\r\n /**\r\n * The `resources` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures that:\r\n *\r\n * - When `strictCheck` is true, the schema will accept a partial object\r\n * with allowed properties `js`, `css`, and `files` where each of the allowed\r\n * properties can be null, stringified version of the object, string that ends\r\n * with the '.json', and null.\r\n *\r\n * - When `strictCheck` is false, the schema will accept a stringified version\r\n * of a partial object with allowed properties `js`, `css`, and `files` where\r\n * each of the allowed properties can be null, string that ends with the\r\n * '.json', and will be null if the provided value is 'undefined', 'null'\r\n * or ''.\r\n *\r\n * @function resources\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `resources`\r\n * option.\r\n */\r\n resources(strictCheck) {\r\n const objectSchema = z\r\n .object({\r\n js: v.string(false),\r\n css: v.string(false),\r\n files: v\r\n .stringArray(\r\n (value) => !['undefined', 'null', ''].includes(value),\r\n ',',\r\n true\r\n )\r\n .nullable()\r\n })\r\n .partial();\r\n\r\n const stringSchema1 = z\r\n .string()\r\n .trim()\r\n .refine(\r\n (value) =>\r\n (value.startsWith('{') && value.endsWith('}')) ||\r\n (value.length >= 6 && value.endsWith('.json')),\r\n {\r\n params: {\r\n errorMessage:\r\n \"The value must be a string that starts with '{' and ends with '}\"\r\n }\r\n }\r\n );\r\n\r\n const stringSchema2 = z\r\n .string()\r\n .trim()\r\n .refine(\r\n (value) =>\r\n (value.startsWith('{') && value.endsWith('}')) ||\r\n (value.length >= 6 && value.endsWith('.json')) ||\r\n ['undefined', 'null', ''].includes(value),\r\n {\r\n params: {\r\n errorMessage: 'The value must be a string that ends with .json'\r\n }\r\n }\r\n )\r\n .transform((value) =>\r\n !['undefined', 'null', ''].includes(value) ? value : null\r\n );\r\n\r\n return strictCheck\r\n ? z.union([objectSchema, stringSchema1]).nullable()\r\n : z.union([objectSchema, stringSchema2]).nullable();\r\n },\r\n\r\n /**\r\n * The `loadConfig` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `string` validator.\r\n * Additionally, it must be a string that ends with '.json'.\r\n *\r\n * @function loadConfig\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `loadConfig`\r\n * option.\r\n */\r\n loadConfig(strictCheck) {\r\n return v\r\n .string(strictCheck)\r\n .refine(\r\n (value) =>\r\n value === null || (value.length >= 6 && value.endsWith('.json')),\r\n {\r\n params: {\r\n errorMessage: 'The value must be a string that ends with .json'\r\n }\r\n }\r\n );\r\n },\r\n\r\n /**\r\n * The `createConfig` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `loadConfig` validator.\r\n *\r\n * @function createConfig\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating\r\n * the `createConfig` option.\r\n */\r\n createConfig(strictCheck) {\r\n return this.loadConfig(strictCheck);\r\n },\r\n\r\n /**\r\n * The `enableServer` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `boolean` validator.\r\n *\r\n * @function enableServer\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating\r\n * the `enableServer` option.\r\n */\r\n enableServer(strictCheck) {\r\n return v.boolean(strictCheck);\r\n },\r\n\r\n /**\r\n * The `host` validator that returns a Zod schema with an optional stricter\r\n * check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `string` validator.\r\n *\r\n * @function host\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `host`\r\n * option.\r\n */\r\n host(strictCheck) {\r\n return v.string(strictCheck);\r\n },\r\n\r\n /**\r\n * The `port` validator that returns a Zod schema with an optional stricter\r\n * check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `nonNegativeNum`\r\n * validator.\r\n *\r\n * @function port\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `port`\r\n * option.\r\n */\r\n port(strictCheck) {\r\n return v.nonNegativeNum(strictCheck);\r\n },\r\n\r\n /**\r\n * The `uploadLimit` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `positiveNum` validator.\r\n *\r\n * @function uploadLimit\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `uploadLimit`\r\n * option.\r\n */\r\n uploadLimit(strictCheck) {\r\n return v.positiveNum(strictCheck);\r\n },\r\n\r\n /**\r\n * The `serverBenchmarking` validator that returns a Zod schema with\r\n * an optional stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `boolean` validator.\r\n *\r\n * @function serverBenchmarking\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating\r\n * the `serverBenchmarking` option.\r\n */\r\n serverBenchmarking(strictCheck) {\r\n return v.boolean(strictCheck);\r\n },\r\n\r\n /**\r\n * The `proxyHost` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `string` validator.\r\n *\r\n * @function proxyHost\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `proxyHost`\r\n * option.\r\n */\r\n proxyHost(strictCheck) {\r\n return v.string(strictCheck);\r\n },\r\n\r\n /**\r\n * The `proxyPort` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as a nullable `nonNegativeNum`\r\n * validator.\r\n *\r\n * @function proxyPort\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `proxyPort`\r\n * option.\r\n */\r\n proxyPort(strictCheck) {\r\n return v.nonNegativeNum(strictCheck).nullable();\r\n },\r\n\r\n /**\r\n * The `proxyTimeout` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `nonNegativeNum`\r\n * validator.\r\n *\r\n * @function proxyTimeout\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating\r\n * the `proxyTimeout` option.\r\n */\r\n proxyTimeout(strictCheck) {\r\n return v.nonNegativeNum(strictCheck);\r\n },\r\n\r\n /**\r\n * The `enableRateLimiting` validator that returns a Zod schema with\r\n * an optional stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `boolean` validator.\r\n *\r\n * @function enableRateLimiting\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating\r\n * the `enableRateLimiting` option.\r\n */\r\n enableRateLimiting(strictCheck) {\r\n return v.boolean(strictCheck);\r\n },\r\n\r\n /**\r\n * The `maxRequests` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `nonNegativeNum`\r\n * validator.\r\n *\r\n * @function maxRequests\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `maxRequests`\r\n * option.\r\n */\r\n maxRequests(strictCheck) {\r\n return v.nonNegativeNum(strictCheck);\r\n },\r\n\r\n /**\r\n * The `window` validator that returns a Zod schema with an optional stricter\r\n * check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `nonNegativeNum`\r\n * validator.\r\n *\r\n * @function window\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `window`\r\n * option.\r\n */\r\n window(strictCheck) {\r\n return v.nonNegativeNum(strictCheck);\r\n },\r\n\r\n /**\r\n * The `delay` validator that returns a Zod schema with an optional stricter\r\n * check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `nonNegativeNum`\r\n * validator.\r\n *\r\n * @function delay\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `delay`\r\n * option.\r\n */\r\n delay(strictCheck) {\r\n return v.nonNegativeNum(strictCheck);\r\n },\r\n\r\n /**\r\n * The `trustProxy` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `boolean` validator.\r\n *\r\n * @function trustProxy\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `trustProxy`\r\n * option.\r\n */\r\n trustProxy(strictCheck) {\r\n return v.boolean(strictCheck);\r\n },\r\n\r\n /**\r\n * The `skipKey` validator that returns a Zod schema with an optional stricter\r\n * check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `string` validator.\r\n *\r\n * @function skipKey\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `skipKey`\r\n * option.\r\n */\r\n skipKey(strictCheck) {\r\n return v.string(strictCheck);\r\n },\r\n\r\n /**\r\n * The `skipToken` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `string` validator.\r\n *\r\n * @function skipToken\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `skipToken`\r\n * option.\r\n */\r\n skipToken(strictCheck) {\r\n return v.string(strictCheck);\r\n },\r\n\r\n /**\r\n * The `enableSsl` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `boolean` validator.\r\n *\r\n * @function enableSsl\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `enableSsl`\r\n * option.\r\n */\r\n enableSsl(strictCheck) {\r\n return v.boolean(strictCheck);\r\n },\r\n\r\n /**\r\n * The `sslForce` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `boolean` validator.\r\n *\r\n * @function sslForce\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `sslForce`\r\n * option.\r\n */\r\n sslForce(strictCheck) {\r\n return v.boolean(strictCheck);\r\n },\r\n\r\n /**\r\n * The `sslPort` validator that returns a Zod schema with an optional stricter\r\n * check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `nonNegativeNum`\r\n * validator.\r\n *\r\n * @function sslPort\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `sslPort`\r\n * option.\r\n */\r\n sslPort(strictCheck) {\r\n return v.nonNegativeNum(strictCheck);\r\n },\r\n\r\n /**\r\n * The `sslCertPath` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `string` validator.\r\n *\r\n * @function sslCertPath\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `sslCertPath`\r\n * option.\r\n */\r\n sslCertPath(strictCheck) {\r\n return v.string(strictCheck);\r\n },\r\n\r\n /**\r\n * The `minWorkers` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `positiveNum` validator.\r\n *\r\n * @function minWorkers\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `minWorkers`\r\n * option.\r\n */\r\n minWorkers(strictCheck) {\r\n return v.positiveNum(strictCheck);\r\n },\r\n\r\n /**\r\n * The `maxWorkers` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `positiveNum` validator.\r\n *\r\n * @function maxWorkers\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `maxWorkers`\r\n * option.\r\n */\r\n maxWorkers(strictCheck) {\r\n return v.positiveNum(strictCheck);\r\n },\r\n\r\n /**\r\n * The `workLimit` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `positiveNum` validator.\r\n *\r\n * @function workLimit\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `workLimit`\r\n * option.\r\n */\r\n workLimit(strictCheck) {\r\n return v.positiveNum(strictCheck);\r\n },\r\n\r\n /**\r\n * The `acquireTimeout` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `nonNegativeNum`\r\n * validator.\r\n *\r\n * @function acquireTimeout\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating\r\n * the `acquireTimeout` option.\r\n */\r\n acquireTimeout(strictCheck) {\r\n return v.nonNegativeNum(strictCheck);\r\n },\r\n\r\n /**\r\n * The `createTimeout` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `nonNegativeNum`\r\n * validator.\r\n *\r\n * @function createTimeout\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating\r\n * the `createTimeout` option.\r\n */\r\n createTimeout(strictCheck) {\r\n return v.nonNegativeNum(strictCheck);\r\n },\r\n\r\n /**\r\n * The `destroyTimeout` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `nonNegativeNum`\r\n * validator.\r\n *\r\n * @function destroyTimeout\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating\r\n * the `destroyTimeout` option.\r\n */\r\n destroyTimeout(strictCheck) {\r\n return v.nonNegativeNum(strictCheck);\r\n },\r\n\r\n /**\r\n * The `idleTimeout` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `nonNegativeNum`\r\n * validator.\r\n *\r\n * @function idleTimeout\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating\r\n * the `idleTimeout` option.\r\n */\r\n idleTimeout(strictCheck) {\r\n return v.nonNegativeNum(strictCheck);\r\n },\r\n\r\n /**\r\n * The `createRetryInterval` validator that returns a Zod schema with\r\n * an optional stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `nonNegativeNum`\r\n * validator.\r\n *\r\n * @function createRetryInterval\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating\r\n * the `createRetryInterval` option.\r\n */\r\n createRetryInterval(strictCheck) {\r\n return v.nonNegativeNum(strictCheck);\r\n },\r\n\r\n /**\r\n * The `reaperInterval` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `nonNegativeNum`\r\n * validator.\r\n *\r\n * @function reaperInterval\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating\r\n * the `reaperInterval` option.\r\n */\r\n reaperInterval(strictCheck) {\r\n return v.nonNegativeNum(strictCheck);\r\n },\r\n\r\n /**\r\n * The `poolBenchmarking` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `boolean` validator.\r\n *\r\n * @function poolBenchmarking\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating\r\n * the `poolBenchmarking` option.\r\n */\r\n poolBenchmarking(strictCheck) {\r\n return v.boolean(strictCheck);\r\n },\r\n\r\n /**\r\n * The `resourcesInterval` validator that returns a Zod schema with\r\n * an optional stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `nonNegativeNum`\r\n * validator.\r\n *\r\n * @function resourcesInterval\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating\r\n * the `resourcesInterval` option.\r\n */\r\n resourcesInterval(strictCheck) {\r\n return v.nonNegativeNum(strictCheck);\r\n },\r\n\r\n /**\r\n * The `logLevel` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures that:\r\n *\r\n * - When `strictCheck` is true, the schema will accept integer number values\r\n * that are between 0 and 5 (inclusive).\r\n *\r\n * - When `strictCheck` is false, the schema will accept integer number values\r\n * and stringified integer number values that are between 1 and 5 (inclusive),\r\n * null, 'undefined', 'null', and '' which will be transformed to null.\r\n *\r\n * @function logLevel\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `logLevel`\r\n * option.\r\n */\r\n logLevel(strictCheck) {\r\n return strictCheck\r\n ? z.number().int().gte(0).lte(5)\r\n : z\r\n .union([\r\n z\r\n .string()\r\n .trim()\r\n .refine(\r\n (value) =>\r\n (!isNaN(Number(value)) &&\r\n value !== true &&\r\n !value.startsWith('[') &&\r\n Number.isInteger(Number(value)) &&\r\n Number(value) >= 0 &&\r\n Number(value) <= 5) ||\r\n ['undefined', 'null', ''].includes(value),\r\n {\r\n params: {\r\n errorMessage: 'The value must be within a 0 and 5 range'\r\n }\r\n }\r\n )\r\n .transform((value) =>\r\n !['undefined', 'null', ''].includes(value)\r\n ? Number(value)\r\n : null\r\n ),\r\n z.number().int().gte(0).lte(5)\r\n ])\r\n .nullable();\r\n },\r\n\r\n /**\r\n * The `logFile` validator that returns a Zod schema with an optional stricter\r\n * check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `string` validator.\r\n * Additionally, it must be a string that ends with '.log'.\r\n *\r\n * @function logFile\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `logFile`\r\n * option.\r\n */\r\n logFile(strictCheck) {\r\n return v\r\n .string(strictCheck)\r\n .refine(\r\n (value) =>\r\n value === null || (value.length >= 5 && value.endsWith('.log')),\r\n {\r\n params: {\r\n errorMessage: 'The value must be a string that ends with .log'\r\n }\r\n }\r\n );\r\n },\r\n\r\n /**\r\n * The `logDest` validator that returns a Zod schema with an optional stricter\r\n * check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `string` validator.\r\n *\r\n * @function logDest\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `logDest`\r\n * option.\r\n */\r\n logDest(strictCheck) {\r\n return v.string(strictCheck);\r\n },\r\n\r\n /**\r\n * The `logToConsole` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `boolean` validator.\r\n *\r\n * @function logToConsole\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating\r\n * the `logToConsole` option.\r\n */\r\n logToConsole(strictCheck) {\r\n return v.boolean(strictCheck);\r\n },\r\n\r\n /**\r\n * The `logToFile` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `boolean` validator.\r\n *\r\n * @function logToFile\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `logToFile`\r\n * option.\r\n */\r\n logToFile(strictCheck) {\r\n return v.boolean(strictCheck);\r\n },\r\n\r\n /**\r\n * The `enableUi` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `boolean` validator.\r\n *\r\n * @function enableUi\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `enableUi`\r\n * option.\r\n */\r\n enableUi(strictCheck) {\r\n return v.boolean(strictCheck);\r\n },\r\n\r\n /**\r\n * The `uiRoute` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `startsWith` validator.\r\n *\r\n * @function uiRoute\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `uiRoute`\r\n * option.\r\n */\r\n uiRoute(strictCheck) {\r\n return v.startsWith(['/'], strictCheck);\r\n },\r\n\r\n /**\r\n * The `nodeEnv` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `enum` validator.\r\n *\r\n * @function nodeEnv\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `nodeEnv`\r\n * option.\r\n */\r\n nodeEnv(strictCheck) {\r\n return v.enum(['development', 'production', 'test'], strictCheck);\r\n },\r\n\r\n /**\r\n * The `listenToProcessExits` validator that returns a Zod schema with\r\n * an optional stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `boolean` validator.\r\n *\r\n * @function listenToProcessExits\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating\r\n * the `listenToProcessExits` option.\r\n */\r\n listenToProcessExits(strictCheck) {\r\n return v.boolean(strictCheck);\r\n },\r\n\r\n /**\r\n * The `noLogo` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `boolean` validator.\r\n *\r\n * @function noLogo\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `noLogo`\r\n * option.\r\n */\r\n noLogo(strictCheck) {\r\n return v.boolean(strictCheck);\r\n },\r\n\r\n /**\r\n * The `hardResetPage` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `boolean` validator.\r\n *\r\n * @function hardResetPage\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating\r\n * the `hardResetPage` option.\r\n */\r\n hardResetPage(strictCheck) {\r\n return v.boolean(strictCheck);\r\n },\r\n\r\n /**\r\n * The `browserShellMode` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `boolean` validator.\r\n *\r\n * @function browserShellMode\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating\r\n * the `browserShellMode` option.\r\n */\r\n browserShellMode(strictCheck) {\r\n return v.boolean(strictCheck);\r\n },\r\n\r\n /**\r\n * The `validation` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `boolean` validator.\r\n *\r\n * @function validation\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `validation`\r\n * option.\r\n */\r\n validation(strictCheck) {\r\n return v.boolean(strictCheck);\r\n },\r\n\r\n /**\r\n * The `enableDebug` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `boolean` validator.\r\n *\r\n * @function enableDebug\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `enableDebug`\r\n * option.\r\n */\r\n enableDebug(strictCheck) {\r\n return v.boolean(strictCheck);\r\n },\r\n\r\n /**\r\n * The `headless` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `boolean` validator.\r\n *\r\n * @function headless\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `headless`\r\n * option.\r\n */\r\n headless(strictCheck) {\r\n return v.boolean(strictCheck);\r\n },\r\n\r\n /**\r\n * The `devtools` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `boolean` validator.\r\n *\r\n * @function devtools\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `devtools`\r\n * option.\r\n */\r\n devtools(strictCheck) {\r\n return v.boolean(strictCheck);\r\n },\r\n\r\n /**\r\n * The `listenToConsole` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `boolean` validator.\r\n *\r\n * @function listenToConsole\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating\r\n * the `listenToConsole` option.\r\n */\r\n listenToConsole(strictCheck) {\r\n return v.boolean(strictCheck);\r\n },\r\n\r\n /**\r\n * The `dumpio` validator that returns a Zod schema with an optional stricter\r\n * check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `boolean` validator.\r\n *\r\n * @function dumpio\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `dumpio`\r\n * option.\r\n */\r\n dumpio(strictCheck) {\r\n return v.boolean(strictCheck);\r\n },\r\n\r\n /**\r\n * The `slowMo` validator that returns a Zod schema with an optional stricter\r\n * check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `nonNegativeNum`\r\n * validator.\r\n *\r\n * @function slowMo\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `slowMo`\r\n * option.\r\n */\r\n slowMo(strictCheck) {\r\n return v.nonNegativeNum(strictCheck);\r\n },\r\n\r\n /**\r\n * The `debuggingPort` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `nonNegativeNum`\r\n * validator.\r\n *\r\n * @function debuggingPort\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating\r\n * the `debuggingPort` option.\r\n */\r\n debuggingPort(strictCheck) {\r\n return v.nonNegativeNum(strictCheck);\r\n },\r\n\r\n /**\r\n * The `requestId` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `string` validator.\r\n * Additionally, it must be a stringified UUID or can be null.\r\n *\r\n * @function requestId\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `requestId`\r\n * option.\r\n */\r\n requestId() {\r\n return z\r\n .string()\r\n .uuid({ message: 'The value must be a stringified UUID' })\r\n .nullable();\r\n }\r\n};\r\n\r\n// Schema for the puppeteer section of options\r\nconst PuppeteerSchema = (strictCheck) =>\r\n z\r\n .object({\r\n args: validators.args(strictCheck)\r\n })\r\n .partial();\r\n\r\n// Schema for the highcharts section of options\r\nconst HighchartsSchema = (strictCheck) =>\r\n z\r\n .object({\r\n version: validators.version(strictCheck),\r\n cdnUrl: validators.cdnUrl(strictCheck),\r\n forceFetch: validators.forceFetch(strictCheck),\r\n cachePath: validators.cachePath(strictCheck),\r\n coreScripts: validators.coreScripts(strictCheck),\r\n moduleScripts: validators.moduleScripts(strictCheck),\r\n indicatorScripts: validators.indicatorScripts(strictCheck),\r\n customScripts: validators.customScripts(strictCheck)\r\n })\r\n .partial();\r\n\r\n// Schema for the export section of options\r\nconst ExportSchema = (strictCheck) =>\r\n z\r\n .object({\r\n infile: validators.infile(strictCheck),\r\n instr: validators.instr(),\r\n options: validators.options(),\r\n svg: validators.svg(),\r\n outfile: validators.outfile(strictCheck),\r\n type: validators.type(strictCheck),\r\n constr: validators.constr(strictCheck),\r\n b64: validators.b64(strictCheck),\r\n noDownload: validators.noDownload(strictCheck),\r\n defaultHeight: validators.defaultHeight(strictCheck),\r\n defaultWidth: validators.defaultWidth(strictCheck),\r\n defaultScale: validators.defaultScale(strictCheck),\r\n height: validators.height(strictCheck),\r\n width: validators.width(strictCheck),\r\n scale: validators.scale(strictCheck),\r\n globalOptions: validators.globalOptions(),\r\n themeOptions: validators.themeOptions(),\r\n batch: validators.batch(false),\r\n rasterizationTimeout: validators.rasterizationTimeout(strictCheck)\r\n })\r\n .partial();\r\n\r\n// Schema for the customLogic section of options\r\nconst CustomLogicSchema = (strictCheck) =>\r\n z\r\n .object({\r\n allowCodeExecution: validators.allowCodeExecution(strictCheck),\r\n allowFileResources: validators.allowFileResources(strictCheck),\r\n customCode: validators.customCode(false),\r\n callback: validators.callback(false),\r\n resources: validators.resources(strictCheck),\r\n loadConfig: validators.loadConfig(false),\r\n createConfig: validators.createConfig(false)\r\n })\r\n .partial();\r\n\r\n// Schema for the server.proxy section of options\r\nconst ProxySchema = (strictCheck) =>\r\n z\r\n .object({\r\n host: validators.proxyHost(false),\r\n port: validators.proxyPort(strictCheck),\r\n timeout: validators.proxyTimeout(strictCheck)\r\n })\r\n .partial();\r\n\r\n// Schema for the server.rateLimiting section of options\r\nconst RateLimitingSchema = (strictCheck) =>\r\n z\r\n .object({\r\n enable: validators.enableRateLimiting(strictCheck),\r\n maxRequests: validators.maxRequests(strictCheck),\r\n window: validators.window(strictCheck),\r\n delay: validators.delay(strictCheck),\r\n trustProxy: validators.trustProxy(strictCheck),\r\n skipKey: validators.skipKey(false),\r\n skipToken: validators.skipToken(false)\r\n })\r\n .partial();\r\n\r\n// Schema for the server.ssl section of options\r\nconst SslSchema = (strictCheck) =>\r\n z\r\n .object({\r\n enable: validators.enableSsl(strictCheck),\r\n force: validators.sslForce(strictCheck),\r\n port: validators.sslPort(strictCheck),\r\n certPath: validators.sslCertPath(false)\r\n })\r\n .partial();\r\n\r\n// Schema for the server section of options\r\nconst ServerSchema = (strictCheck) =>\r\n z.object({\r\n enable: validators.enableServer(strictCheck).optional(),\r\n host: validators.host(strictCheck).optional(),\r\n port: validators.port(strictCheck).optional(),\r\n uploadLimit: validators.uploadLimit(strictCheck).optional(),\r\n benchmarking: validators.serverBenchmarking(strictCheck).optional(),\r\n proxy: ProxySchema(strictCheck).optional(),\r\n rateLimiting: RateLimitingSchema(strictCheck).optional(),\r\n ssl: SslSchema(strictCheck).optional()\r\n });\r\n\r\n// Schema for the pool section of options\r\nconst PoolSchema = (strictCheck) =>\r\n z\r\n .object({\r\n minWorkers: validators.minWorkers(strictCheck),\r\n maxWorkers: validators.maxWorkers(strictCheck),\r\n workLimit: validators.workLimit(strictCheck),\r\n acquireTimeout: validators.acquireTimeout(strictCheck),\r\n createTimeout: validators.createTimeout(strictCheck),\r\n destroyTimeout: validators.destroyTimeout(strictCheck),\r\n idleTimeout: validators.idleTimeout(strictCheck),\r\n createRetryInterval: validators.createRetryInterval(strictCheck),\r\n reaperInterval: validators.reaperInterval(strictCheck),\r\n benchmarking: validators.poolBenchmarking(strictCheck)\r\n })\r\n .partial();\r\n\r\n// Schema for the logging section of options\r\nconst LoggingSchema = (strictCheck) =>\r\n z\r\n .object({\r\n level: validators.logLevel(strictCheck),\r\n file: validators.logFile(strictCheck),\r\n dest: validators.logDest(strictCheck),\r\n toConsole: validators.logToConsole(strictCheck),\r\n toFile: validators.logToFile(strictCheck)\r\n })\r\n .partial();\r\n\r\n// Schema for the ui section of options\r\nconst UiSchema = (strictCheck) =>\r\n z\r\n .object({\r\n enable: validators.enableUi(strictCheck),\r\n route: validators.uiRoute(strictCheck)\r\n })\r\n .partial();\r\n\r\n// Schema for the other section of options\r\nconst OtherSchema = (strictCheck) =>\r\n z\r\n .object({\r\n nodeEnv: validators.nodeEnv(strictCheck),\r\n listenToProcessExits: validators.listenToProcessExits(strictCheck),\r\n noLogo: validators.noLogo(strictCheck),\r\n hardResetPage: validators.hardResetPage(strictCheck),\r\n browserShellMode: validators.browserShellMode(strictCheck),\r\n validation: validators.validation(strictCheck)\r\n })\r\n .partial();\r\n\r\n// Schema for the debug section of options\r\nconst DebugSchema = (strictCheck) =>\r\n z\r\n .object({\r\n enable: validators.enableDebug(strictCheck),\r\n headless: validators.headless(strictCheck),\r\n devtools: validators.devtools(strictCheck),\r\n listenToConsole: validators.listenToConsole(strictCheck),\r\n dumpio: validators.dumpio(strictCheck),\r\n slowMo: validators.slowMo(strictCheck),\r\n debuggingPort: validators.debuggingPort(strictCheck)\r\n })\r\n .partial();\r\n\r\n// Strict schema for the config\r\nexport const StrictConfigSchema = z.object({\r\n requestId: validators.requestId(),\r\n puppeteer: PuppeteerSchema(true),\r\n highcharts: HighchartsSchema(true),\r\n export: ExportSchema(true),\r\n customLogic: CustomLogicSchema(true),\r\n server: ServerSchema(true),\r\n pool: PoolSchema(true),\r\n logging: LoggingSchema(true),\r\n ui: UiSchema(true),\r\n other: OtherSchema(true),\r\n debug: DebugSchema(true)\r\n});\r\n\r\n// Loose schema for the config\r\nexport const LooseConfigSchema = z.object({\r\n requestId: validators.requestId(),\r\n puppeteer: PuppeteerSchema(false),\r\n highcharts: HighchartsSchema(false),\r\n export: ExportSchema(false),\r\n customLogic: CustomLogicSchema(false),\r\n server: ServerSchema(false),\r\n pool: PoolSchema(false),\r\n logging: LoggingSchema(false),\r\n ui: UiSchema(false),\r\n other: OtherSchema(false),\r\n debug: DebugSchema(false)\r\n});\r\n\r\n// Schema for the environment variables config\r\nexport const EnvSchema = z.object({\r\n // puppeteer\r\n PUPPETEER_ARGS: validators.args(false),\r\n\r\n // highcharts\r\n HIGHCHARTS_VERSION: validators.version(false),\r\n HIGHCHARTS_CDN_URL: validators.cdnUrl(false),\r\n HIGHCHARTS_FORCE_FETCH: validators.forceFetch(false),\r\n HIGHCHARTS_CACHE_PATH: validators.cachePath(false),\r\n HIGHCHARTS_ADMIN_TOKEN: validators.adminToken(false),\r\n HIGHCHARTS_CORE_SCRIPTS: validators.coreScripts(false),\r\n HIGHCHARTS_MODULE_SCRIPTS: validators.moduleScripts(false),\r\n HIGHCHARTS_INDICATOR_SCRIPTS: validators.indicatorScripts(false),\r\n HIGHCHARTS_CUSTOM_SCRIPTS: validators.customScripts(false),\r\n\r\n // export\r\n EXPORT_INFILE: validators.infile(false),\r\n EXPORT_INSTR: validators.instr(),\r\n EXPORT_OPTIONS: validators.options(),\r\n EXPORT_SVG: validators.svg(),\r\n EXPORT_BATCH: validators.batch(false),\r\n EXPORT_OUTFILE: validators.outfile(false),\r\n EXPORT_TYPE: validators.type(false),\r\n EXPORT_CONSTR: validators.constr(false),\r\n EXPORT_B64: validators.b64(false),\r\n EXPORT_NO_DOWNLOAD: validators.noDownload(false),\r\n EXPORT_HEIGHT: validators.height(false),\r\n EXPORT_WIDTH: validators.width(false),\r\n EXPORT_SCALE: validators.scale(false),\r\n EXPORT_DEFAULT_HEIGHT: validators.defaultHeight(false),\r\n EXPORT_DEFAULT_WIDTH: validators.defaultWidth(false),\r\n EXPORT_DEFAULT_SCALE: validators.defaultScale(false),\r\n EXPORT_GLOBAL_OPTIONS: validators.globalOptions(),\r\n EXPORT_THEME_OPTIONS: validators.themeOptions(),\r\n EXPORT_RASTERIZATION_TIMEOUT: validators.rasterizationTimeout(false),\r\n\r\n // custom\r\n CUSTOM_LOGIC_ALLOW_CODE_EXECUTION: validators.allowCodeExecution(false),\r\n CUSTOM_LOGIC_ALLOW_FILE_RESOURCES: validators.allowFileResources(false),\r\n CUSTOM_LOGIC_CUSTOM_CODE: validators.customCode(false),\r\n CUSTOM_LOGIC_CALLBACK: validators.callback(false),\r\n CUSTOM_LOGIC_RESOURCES: validators.resources(false),\r\n CUSTOM_LOGIC_LOAD_CONFIG: validators.loadConfig(false),\r\n CUSTOM_LOGIC_CREATE_CONFIG: validators.createConfig(false),\r\n\r\n // server\r\n SERVER_ENABLE: validators.enableServer(false),\r\n SERVER_HOST: validators.host(false),\r\n SERVER_PORT: validators.port(false),\r\n SERVER_UPLOAD_LIMIT: validators.uploadLimit(false),\r\n SERVER_BENCHMARKING: validators.serverBenchmarking(false),\r\n\r\n // server proxy\r\n SERVER_PROXY_HOST: validators.proxyHost(false),\r\n SERVER_PROXY_PORT: validators.proxyPort(false),\r\n SERVER_PROXY_TIMEOUT: validators.proxyTimeout(false),\r\n\r\n // server rate limiting\r\n SERVER_RATE_LIMITING_ENABLE: validators.enableRateLimiting(false),\r\n SERVER_RATE_LIMITING_MAX_REQUESTS: validators.maxRequests(false),\r\n SERVER_RATE_LIMITING_WINDOW: validators.window(false),\r\n SERVER_RATE_LIMITING_DELAY: validators.delay(false),\r\n SERVER_RATE_LIMITING_TRUST_PROXY: validators.trustProxy(false),\r\n SERVER_RATE_LIMITING_SKIP_KEY: validators.skipKey(false),\r\n SERVER_RATE_LIMITING_SKIP_TOKEN: validators.skipToken(false),\r\n\r\n // server ssl\r\n SERVER_SSL_ENABLE: validators.enableSsl(false),\r\n SERVER_SSL_FORCE: validators.sslForce(false),\r\n SERVER_SSL_PORT: validators.sslPort(false),\r\n SERVER_SSL_CERT_PATH: validators.sslCertPath(false),\r\n\r\n // pool\r\n POOL_MIN_WORKERS: validators.minWorkers(false),\r\n POOL_MAX_WORKERS: validators.maxWorkers(false),\r\n POOL_WORK_LIMIT: validators.workLimit(false),\r\n POOL_ACQUIRE_TIMEOUT: validators.acquireTimeout(false),\r\n POOL_CREATE_TIMEOUT: validators.createTimeout(false),\r\n POOL_DESTROY_TIMEOUT: validators.destroyTimeout(false),\r\n POOL_IDLE_TIMEOUT: validators.idleTimeout(false),\r\n POOL_CREATE_RETRY_INTERVAL: validators.createRetryInterval(false),\r\n POOL_REAPER_INTERVAL: validators.reaperInterval(false),\r\n POOL_BENCHMARKING: validators.poolBenchmarking(false),\r\n\r\n // logging\r\n LOGGING_LEVEL: validators.logLevel(false),\r\n LOGGING_FILE: validators.logFile(false),\r\n LOGGING_DEST: validators.logDest(false),\r\n LOGGING_TO_CONSOLE: validators.logToConsole(false),\r\n LOGGING_TO_FILE: validators.logToFile(false),\r\n\r\n // ui\r\n UI_ENABLE: validators.enableUi(false),\r\n UI_ROUTE: validators.uiRoute(false),\r\n\r\n // other\r\n OTHER_NODE_ENV: validators.nodeEnv(false),\r\n OTHER_LISTEN_TO_PROCESS_EXITS: validators.listenToProcessExits(false),\r\n OTHER_NO_LOGO: validators.noLogo(false),\r\n OTHER_HARD_RESET_PAGE: validators.hardResetPage(false),\r\n OTHER_BROWSER_SHELL_MODE: validators.browserShellMode(false),\r\n OTHER_VALIDATION: validators.validation(false),\r\n\r\n // debugger\r\n DEBUG_ENABLE: validators.enableDebug(false),\r\n DEBUG_HEADLESS: validators.headless(false),\r\n DEBUG_DEVTOOLS: validators.devtools(false),\r\n DEBUG_LISTEN_TO_CONSOLE: validators.listenToConsole(false),\r\n DEBUG_DUMPIO: validators.dumpio(false),\r\n DEBUG_SLOW_MO: validators.slowMo(false),\r\n DEBUG_DEBUGGING_PORT: validators.debuggingPort(false)\r\n});\r\n\r\n/**\r\n * Validates the environment variables options using the EnvSchema.\r\n *\r\n * @param {Object} process.env - The configuration options from environment\r\n * variables file to validate.\r\n *\r\n * @returns {Object} The parsed and validated environment variables.\r\n */\r\nexport const envs = EnvSchema.partial().parse(process.env);\r\n\r\n/**\r\n * Validates the configuration options using the `StrictConfigSchema`.\r\n *\r\n * @function strictValidate\r\n *\r\n * @param {Object} configOptions - The configuration options to validate.\r\n *\r\n * @returns {Object} The parsed and validated configuration options.\r\n */\r\nexport function strictValidate(configOptions) {\r\n return StrictConfigSchema.partial().parse(configOptions);\r\n}\r\n\r\n/**\r\n * Validates the configuration options using the `LooseConfigSchema`.\r\n *\r\n * @function looseValidate\r\n *\r\n * @param {Object} configOptions - The configuration options to validate.\r\n *\r\n * @returns {Object} The parsed and validated configuration options.\r\n */\r\nexport function looseValidate(configOptions) {\r\n return LooseConfigSchema.partial().parse(configOptions);\r\n}\r\n\r\n/**\r\n * Custom error mapping function for Zod schema validation.\r\n *\r\n * This function customizes the error messages produced by Zod schema\r\n * validation, providing more specific and user-friendly feedback based on the\r\n * issue type and context.\r\n *\r\n * The function modifies the error messages as follows:\r\n *\r\n * - For missing required values (undefined), it returns a message indicating\r\n * that no value was provided for the specific property.\r\n *\r\n * - For custom validation errors, if a custom error message is provided in the\r\n * issue parameters, it includes this message along with the invalid data\r\n * received.\r\n *\r\n * - For all other errors, it appends property-specific information to the\r\n * default error message provided by Zod.\r\n *\r\n * @function _customErrorMap\r\n *\r\n * @param {z.ZodIssue} issue - The issue object representing the validation\r\n * error.\r\n * @param {Object} context - The context object providing additional information\r\n * about the validation error.\r\n *\r\n * @returns {Object} An object containing the customized error message.\r\n */\r\nfunction _customErrorMap(issue, context) {\r\n // Get the chain of properties which error directly refers to\r\n const propertyName = issue.path.join('.');\r\n\r\n // Create the first part of the message about the property information\r\n const propertyInfo = `Invalid value for the ${propertyName}`;\r\n\r\n // Modified message for the invalid type\r\n if (issue.code === z.ZodIssueCode.invalid_type) {\r\n // Modified message for the required values\r\n if (issue.received === z.ZodParsedType.undefined) {\r\n return {\r\n message: `${propertyInfo} - No value was provided.`\r\n };\r\n }\r\n\r\n // Modified message for the specific invalid type when values exist\r\n return {\r\n message: `${propertyInfo} - Invalid type. ${context.defaultError}.`\r\n };\r\n }\r\n\r\n // Modified message for the custom validation\r\n if (issue.code === z.ZodIssueCode.custom) {\r\n // If the custom message for error exist, include it\r\n if (issue.params?.errorMessage) {\r\n return {\r\n message: `${propertyInfo} - ${issue.params?.errorMessage}, received '${context.data}'.`\r\n };\r\n }\r\n }\r\n\r\n // Modified message for the invalid union error\r\n if (issue.code === z.ZodIssueCode.invalid_union) {\r\n // Create the first part of the message about the multiple errors\r\n let message = `Multiple errors occurred for the ${propertyName}:\\n`;\r\n\r\n // Cycle through all errors and create a correct message\r\n issue.unionErrors.forEach((value) => {\r\n const index = value.issues[0].message.indexOf('-');\r\n message +=\r\n index !== -1\r\n ? `${value.issues[0].message}\\n`.substring(index)\r\n : `${value.issues[0].message}\\n`;\r\n });\r\n\r\n // Return the final message for the invalid union error\r\n return {\r\n message\r\n };\r\n }\r\n\r\n // Return the default error message, extended by the info about the property\r\n return {\r\n message: `${propertyInfo} - ${context.defaultError}.`\r\n };\r\n}\r\n\r\nexport default {\r\n validators,\r\n StrictConfigSchema,\r\n LooseConfigSchema,\r\n EnvSchema,\r\n envs,\r\n strictValidate,\r\n looseValidate\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * A custom error class for handling export-related errors. Extends the native\r\n * `Error` class to include additional properties like status code and stack\r\n * trace details.\r\n */\r\nclass ExportError extends Error {\r\n /**\r\n * Creates an instance of the `ExportError`.\r\n *\r\n * @param {string} message - The error message to be displayed.\r\n * @param {number} statusCode - Optional HTTP status code associated\r\n * with the error (e.g., 400, 500).\r\n */\r\n constructor(message, statusCode) {\r\n super();\r\n\r\n this.message = message;\r\n this.stackMessage = message;\r\n\r\n if (statusCode) {\r\n this.statusCode = statusCode;\r\n }\r\n }\r\n\r\n /**\r\n * Sets or updates the HTTP status code for the error.\r\n *\r\n * @param {number} statusCode - The HTTP status code to assign to the error.\r\n *\r\n * @returns {ExportError} The updated instance of the `ExportError` class.\r\n */\r\n setStatus(statusCode) {\r\n this.statusCode = statusCode;\r\n\r\n return this;\r\n }\r\n\r\n /**\r\n * Sets additional error details based on an existing error object.\r\n *\r\n * @param {Error} error - An error object containing details to populate\r\n * the `ExportError` instance.\r\n *\r\n * @returns {ExportError} The updated instance of the `ExportError` class.\r\n */\r\n setError(error) {\r\n this.error = error;\r\n\r\n if (error.name) {\r\n this.name = error.name;\r\n }\r\n\r\n if (error.statusCode) {\r\n this.statusCode = error.statusCode;\r\n }\r\n\r\n if (error.stack) {\r\n this.stackMessage = error.message;\r\n this.stack = error.stack;\r\n }\r\n\r\n return this;\r\n }\r\n}\r\n\r\nexport default ExportError;\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * @overview Manages configuration for the Highcharts Export Server by loading\r\n * and merging options from multiple sources, such as default settings,\r\n * environment variables, user-provided options, and command-line arguments.\r\n * Ensures the global options are up-to-date with the highest priority values.\r\n * Provides functions for accessing and updating configuration.\r\n */\r\n\r\nimport { readFileSync } from 'fs';\r\nimport { join } from 'path';\r\n\r\nimport { log, logWithStack, logZodIssues } from './logger.js';\r\nimport { __dirname, deepCopy, getAbsolutePath, isObject } from './utils.js';\r\nimport {\r\n envs,\r\n looseValidate,\r\n strictValidate,\r\n validators\r\n} from './validation.js';\r\n\r\nimport { defaultConfig, absoluteProps, nestedProps } from './schemas/config.js';\r\n\r\nimport ExportError from './errors/ExportError.js';\r\n\r\n// Sets the global options with initial values from the default config\r\nconst globalOptions = _initOptions(defaultConfig);\r\n\r\n/**\r\n * Retrieves a copy of the global options object or a reference to the global\r\n * options object, based on the `getCopy` flag.\r\n *\r\n * @function getOptions\r\n *\r\n * @param {boolean} [getCopy=true] - Specifies whether to return a copied\r\n * object of the global options (`true`) or a reference to the global options\r\n * object (`false`). The default value is `false`.\r\n *\r\n * @returns {Object} A copy of the global options object, or a reference\r\n * to the global options object.\r\n */\r\nexport function getOptions(getCopy = true) {\r\n return getCopy ? deepCopy(globalOptions) : globalOptions;\r\n}\r\n\r\n/**\r\n * Updates either a copy of the global options object or a reference\r\n * to the global options object, depending on the getCopy flag, using\r\n * the provided newOptions, which may or may not be validated.\r\n *\r\n * @function updateOptions\r\n *\r\n * @param {Object} newOptions - An object containing the new options to be\r\n * merged into the global options.\r\n * @param {boolean} [getCopy=false] - Determines whether to merge the new\r\n * options into a copy of the global options object (`true`) or directly into\r\n * the global options object (`false`). The default value is `false`.\r\n * @param {boolean} [strictCheck=true] - Determines if stricter validation\r\n * should be applied. The default value is `true`.\r\n *\r\n * @returns {Object} The updated options object, either the modified global\r\n * options or a modified copy, based on the value of `getCopy`.\r\n */\r\nexport function updateOptions(newOptions, getCopy = false, strictCheck = true) {\r\n // Merge new options to the global options or its copy and return the result\r\n return _mergeOptions(\r\n // First, get the options\r\n getOptions(getCopy),\r\n // Next, validate the new options\r\n validateOptions(newOptions, strictCheck)\r\n );\r\n}\r\n\r\n/**\r\n * Updates the global options with values provided through the CLI, keeping\r\n * the principle of options load priority. This function accepts a `cliArgs`\r\n * array containing arguments from the CLI, which will be validated and applied\r\n * if provided.\r\n *\r\n * The priority order for setting values is:\r\n *\r\n * 1. Values from a custom JSON file (loaded by the `--loadConfig` option).\r\n * 2. Values from the command line interface (CLI).\r\n *\r\n * @function setCliOptions\r\n *\r\n * @param {Array.} cliArgs - An array of command line arguments used\r\n * for additional configuration.\r\n *\r\n * @returns {Object} The updated global options object, reflecting the merged\r\n * configuration from sources provided through the CLI.\r\n */\r\nexport function setCliOptions(cliArgs) {\r\n // Only for the CLI usage\r\n if (cliArgs && Array.isArray(cliArgs) && cliArgs.length) {\r\n try {\r\n // Get options from the custom JSON loaded via the `--loadConfig`\r\n const configOptions = _loadConfigFile(cliArgs);\r\n\r\n // Update global options with validated values from the `configOptions`\r\n updateOptions(configOptions);\r\n } catch (error) {\r\n log(2, '[validation] No options added from the `--loadConfig` option.');\r\n }\r\n\r\n try {\r\n // Get options from the CLI\r\n const cliOptions = _pairArgumentValue(nestedProps, cliArgs);\r\n\r\n // Update global options with validated values from the `cliOptions`\r\n updateOptions(cliOptions, false, false);\r\n } catch (error) {\r\n log(2, '[validation] No options added from the CLI arguments.');\r\n }\r\n }\r\n\r\n // Return reference to the global options\r\n return getOptions(false);\r\n}\r\n\r\n/**\r\n * Maps old-structured configuration options (PhantomJS) to a new format\r\n * (Puppeteer). This function converts flat, old-structured options into\r\n * a new, nested configuration format based on a predefined mapping\r\n * (`nestedProps`). The new format is used for Puppeteer, while the old format\r\n * was used for PhantomJS.\r\n *\r\n * @function mapToNewOptions\r\n *\r\n * @param {Object} oldOptions - The old, flat configuration options\r\n * to be converted.\r\n *\r\n * @returns {Object} A new object containing options structured according\r\n * to the mapping defined in `nestedProps` or an empty object if the provided\r\n * `oldOptions` is not a correct object.\r\n */\r\nexport function mapToNewOptions(oldOptions) {\r\n // An object for the new structured options\r\n const newOptions = {};\r\n\r\n // Check if provided value is a correct object\r\n if (isObject(oldOptions)) {\r\n // Iterate over each key-value pair in the old-structured options\r\n for (const [key, value] of Object.entries(oldOptions)) {\r\n // If there is a nested mapping, split it into a properties chain\r\n const propertiesChain = nestedProps[key]\r\n ? nestedProps[key].split('.')\r\n : [];\r\n\r\n // If it is the last property in the chain, assign the value, otherwise,\r\n // create or reuse the nested object\r\n propertiesChain.reduce(\r\n (obj, prop, index) =>\r\n (obj[prop] =\r\n propertiesChain.length - 1 === index ? value : obj[prop] || {}),\r\n newOptions\r\n );\r\n }\r\n } else {\r\n log(\r\n 2,\r\n '[config] No correct object with options was provided. Returning an empty array.'\r\n );\r\n }\r\n\r\n // Return the new, structured options object\r\n return newOptions;\r\n}\r\n\r\n/**\r\n * Validates a specified option using the corresponding validator from the\r\n * configuration object. Returns the original option if the validation\r\n * is disabled globally.\r\n *\r\n * @function validateOption\r\n *\r\n * @param {string} name - The name of the option to validate.\r\n * @param {any} configOption - The value of the option to validate.\r\n * @param {boolean} [strictCheck=true] - Determines if stricter validation\r\n * should be applied. The default value is `true`.\r\n *\r\n * @returns {any} The parsed and validated value of the option.\r\n */\r\nexport function validateOption(name, configOption, strictCheck = true) {\r\n // Return the original option if the validation is disabled\r\n if (!getOptions().other.validation) {\r\n return configOption;\r\n }\r\n\r\n try {\r\n // Return validated option\r\n return validators[name](strictCheck).parse(configOption);\r\n } catch (error) {\r\n // Log Zod issues\r\n logZodIssues(\r\n 1,\r\n error.issues,\r\n `[validation] The ${name} option validation error`\r\n );\r\n\r\n // Throw validation error\r\n throw new ExportError(\r\n `[validation] The ${name} option validation error`,\r\n 400\r\n );\r\n }\r\n}\r\n\r\n/**\r\n * Validates the provided configuration options for the exporting process.\r\n * Returns the original option if the validation is disabled globally.\r\n *\r\n * @function validateOptions\r\n *\r\n * @param {Object} configOptions - The configuration options to be validated.\r\n * @param {boolean} [strictCheck=true] - Determines if stricter validation\r\n * should be applied. The default value is `true`.\r\n *\r\n * @returns {Object} The parsed and validated configuration options object.\r\n */\r\nexport function validateOptions(configOptions, strictCheck = true) {\r\n // Return the original config if the validation is disabled\r\n if (!getOptions().other.validation) {\r\n return configOptions;\r\n }\r\n\r\n try {\r\n // Return validated options\r\n return strictCheck\r\n ? strictValidate(configOptions)\r\n : looseValidate(configOptions);\r\n } catch (error) {\r\n // Log Zod issues\r\n logZodIssues(1, error.issues, '[validation] Options validation error');\r\n\r\n // Throw validation error\r\n throw new ExportError('[validation] Options validation error', 400);\r\n }\r\n}\r\n\r\n/**\r\n * Validates, parses, and checks if the provided config is allowed set\r\n * of options.\r\n *\r\n * @function isAllowedConfig\r\n *\r\n * @param {unknown} config - The config to be validated and parsed as a set\r\n * of options. Must be either an object or a string.\r\n * @param {boolean} [toString=false] - Whether to return a stringified version\r\n * of the parsed config. The default value is `false`.\r\n * @param {boolean} [allowFunctions=false] - Whether to allow functions\r\n * in the parsed config. If true, functions are preserved. Otherwise, when\r\n * a function is found, null is returned. The default value is `false`.\r\n *\r\n * @returns {(Object|string|null)} Returns a parsed set of options object,\r\n * a stringified set of options object if the `toString` is true, and null\r\n * if the config is not a valid set of options or parsing fails.\r\n */\r\nexport function isAllowedConfig(\r\n config,\r\n toString = false,\r\n allowFunctions = false\r\n) {\r\n try {\r\n // Accept only objects and strings\r\n if (!isObject(config) && typeof config !== 'string') {\r\n // Return null if any other type\r\n return null;\r\n }\r\n\r\n // Get the object representation of the original config\r\n const objectConfig =\r\n typeof config === 'string'\r\n ? allowFunctions\r\n ? eval(`(${config})`)\r\n : JSON.parse(config)\r\n : config;\r\n\r\n // Preserve or remove potential functions based on the `allowFunctions` flag\r\n const stringifiedOptions = _optionsStringify(\r\n objectConfig,\r\n allowFunctions,\r\n false\r\n );\r\n\r\n // Parse the config to check if it is valid set of options\r\n const parsedOptions = allowFunctions\r\n ? JSON.parse(\r\n _optionsStringify(objectConfig, allowFunctions, true),\r\n (_, value) =>\r\n typeof value === 'string' && value.startsWith('function')\r\n ? eval(`(${value})`)\r\n : value\r\n )\r\n : JSON.parse(stringifiedOptions);\r\n\r\n // Return stringified or object options based on the `toString` flag\r\n return toString ? stringifiedOptions : parsedOptions;\r\n } catch (error) {\r\n // Return null if parsing fails\r\n return null;\r\n }\r\n}\r\n\r\n/**\r\n * Prints the Highcharts Export Server logo, version, and license information.\r\n *\r\n * @function printLicense\r\n */\r\nexport function printLicense() {\r\n // Print the logo and version information\r\n printVersion();\r\n\r\n // Print the license information\r\n console.log(\r\n 'This software requires a valid Highcharts license for commercial use.\\n'\r\n .yellow,\r\n '\\nFor a full list of CLI options, type:',\r\n '\\nhighcharts-export-server --help\\n'.green,\r\n '\\nIf you do not have a license, one can be obtained here:',\r\n '\\nhttps://shop.highsoft.com/\\n'.green,\r\n '\\nTo customize your installation, please refer to the README file at:',\r\n '\\nhttps://github.com/highcharts/node-export-server#readme\\n'.green\r\n );\r\n}\r\n\r\n/**\r\n * Prints usage information for CLI arguments, displaying available options\r\n * and their descriptions. It can list properties recursively if categories\r\n * contain nested options.\r\n *\r\n * @function printUsage\r\n */\r\nexport function printUsage() {\r\n // Display README and general usage information\r\n console.log(\r\n '\\nUsage of CLI arguments:'.bold,\r\n '\\n-----------------------',\r\n `\\nFor more detailed information, visit the README file at: ${'https://github.com/highcharts/node-export-server#readme'.green}.\\n`\r\n );\r\n\r\n // Iterate through each category in the `defaultConfig` and display usage info\r\n Object.keys(defaultConfig).forEach((category) => {\r\n console.log(`${category.toUpperCase()}`.bold.red);\r\n _cycleCategories(defaultConfig[category]);\r\n console.log('');\r\n });\r\n}\r\n\r\n/**\r\n * Prints the Highcharts Export Server logo or text with the version\r\n * information.\r\n *\r\n * @function printVersion\r\n *\r\n * @param {boolean} [noLogo=false] - If true, only prints text with the version\r\n * information, without the logo. The default value is `false`.\r\n */\r\nexport function printVersion(noLogo = false) {\r\n // Get package version either from `.env` or from `package.json`\r\n const packageVersion = JSON.parse(\r\n readFileSync(join(__dirname, 'package.json'), 'utf8')\r\n ).version;\r\n\r\n // Print text only\r\n if (noLogo) {\r\n console.log(`Highcharts Export Server v${packageVersion}`);\r\n } else {\r\n // Print the logo\r\n console.log(\r\n readFileSync(join(__dirname, 'msg', 'startup.msg'), 'utf8').toString()\r\n .bold.yellow,\r\n `v${packageVersion}\\n`.bold\r\n );\r\n }\r\n}\r\n\r\n/**\r\n * Initializes and returns the global options object based on the provided\r\n * configuration, setting values from nested properties recursively.\r\n *\r\n * The priority order for setting values is:\r\n *\r\n * 1. Values from the `./lib/schemas/config.js` file (defaults).\r\n * 2. Values from environment variables (specified in the `.env` file).\r\n *\r\n * @function _initOptions\r\n *\r\n * @param {Object} config - The configuration object used for initializing\r\n * the global options. It should include nested properties with a `value`\r\n * and an `envLink` for linking to environment variables.\r\n *\r\n * @returns {Object} The initialized global options object, populated with\r\n * values based on the provided configuration and the established priority\r\n * order.\r\n */\r\nfunction _initOptions(config) {\r\n // Init the object for options\r\n const options = {};\r\n\r\n // Start initializing the `options` object recursively\r\n for (const [name, item] of Object.entries(config)) {\r\n if (Object.prototype.hasOwnProperty.call(item, 'value')) {\r\n // Set the correct value based on the established priority order\r\n if (envs[item.envLink] !== undefined && envs[item.envLink] !== null) {\r\n // The environment variables value\r\n options[name] = envs[item.envLink];\r\n } else {\r\n // The value from the config file\r\n options[name] = item.value;\r\n }\r\n } else {\r\n // Create a section in the options\r\n options[name] = _initOptions(item);\r\n }\r\n }\r\n\r\n // Return the created `options` object\r\n return options;\r\n}\r\n\r\n/**\r\n * Merges two sets of configuration options, considering absolute properties.\r\n *\r\n * @function _mergeOptions\r\n *\r\n * @param {Object} originalOptions - Original configuration options.\r\n * @param {Object} newOptions - New configuration options to be merged.\r\n *\r\n * @returns {Object} Merged configuration options.\r\n */\r\nexport function _mergeOptions(originalOptions, newOptions) {\r\n // Check if the `originalOptions` and `newOptions` are correct objects\r\n if (isObject(originalOptions) && isObject(newOptions)) {\r\n for (const [key, value] of Object.entries(newOptions)) {\r\n originalOptions[key] =\r\n isObject(value) &&\r\n !absoluteProps.includes(key) &&\r\n originalOptions[key] !== undefined\r\n ? _mergeOptions(originalOptions[key], value)\r\n : value !== undefined\r\n ? value\r\n : originalOptions[key] || null;\r\n }\r\n }\r\n\r\n // Return the original (modified or not) options\r\n return originalOptions;\r\n}\r\n\r\n/**\r\n * Converts the provided options object to a JSON-formatted string\r\n * with the option to preserve functions. In order for a function\r\n * to be preserved, it needs to follow the format `function (...) {...}`.\r\n * Such a function can also be stringified.\r\n *\r\n * @function _optionsStringify\r\n *\r\n * @param {Object} options - The options object to be converted to a string.\r\n * @param {boolean} allowFunctions - If set to true, functions are preserved\r\n * in the output. Otherwise an error is thrown.\r\n * @param {boolean} stringifyFunctions - If set to true, functions are saved\r\n * as strings. The `allowFunctions` must be set to true as well for this to take\r\n * an effect.\r\n *\r\n * @returns {string} The JSON-formatted string representing the options.\r\n *\r\n * @throws {Error} Throws an `Error` when functions are not allowed but are\r\n * found in provided options object.\r\n */\r\nexport function _optionsStringify(options, allowFunctions, stringifyFunctions) {\r\n const replacerCallback = (_, value) => {\r\n // Trim string values\r\n if (typeof value === 'string') {\r\n value = value.trim();\r\n }\r\n\r\n // If value is a function or stringified function\r\n if (\r\n typeof value === 'function' ||\r\n (typeof value === 'string' &&\r\n value.startsWith('function') &&\r\n value.endsWith('}'))\r\n ) {\r\n // If allowFunctions is set to true, preserve functions\r\n if (allowFunctions) {\r\n // Based on the `stringifyFunctions` options, set function values\r\n return stringifyFunctions\r\n ? // As stringified functions\r\n `\"EXP_FUN${(value + '').replaceAll(/\\s+/g, ' ')}EXP_FUN\"`\r\n : // As functions\r\n `EXP_FUN${(value + '').replaceAll(/\\s+/g, ' ')}EXP_FUN`;\r\n } else {\r\n // Throw an error otherwise\r\n throw new Error();\r\n }\r\n }\r\n\r\n // In all other cases, simply return the value\r\n return value;\r\n };\r\n\r\n // Stringify options and if required, replace special functions marks\r\n return JSON.stringify(options, replacerCallback).replaceAll(\r\n stringifyFunctions ? /\\\\\"EXP_FUN|EXP_FUN\\\\\"/g : /\"EXP_FUN|EXP_FUN\"/g,\r\n ''\r\n );\r\n}\r\n\r\n/**\r\n * Loads additional configuration from a specified file provided via\r\n * the `--loadConfig` option in the command-line arguments.\r\n *\r\n * @function _loadConfigFile\r\n *\r\n * @param {Array.} cliArgs - Command-line arguments to search\r\n * for the `--loadConfig` option and the corresponding file path.\r\n *\r\n * @returns {Object} The additional configuration loaded from the specified\r\n * file, or an empty object if the file is not found, invalid, or an error\r\n * occurs.\r\n */\r\nfunction _loadConfigFile(cliArgs) {\r\n // Get the allow flags for the custom logic check\r\n const { allowCodeExecution, allowFileResources } = getOptions().customLogic;\r\n\r\n // Check if the `--loadConfig` option was used\r\n const configIndex = cliArgs.findIndex(\r\n (arg) => arg.replace(/-/g, '') === 'loadConfig'\r\n );\r\n\r\n // Get the `--loadConfig` option value\r\n const configFileName = configIndex > -1 && cliArgs[configIndex + 1];\r\n\r\n // Check if the `--loadConfig` is present and has a correct value\r\n if (configFileName && allowFileResources) {\r\n try {\r\n // Load an optional custom JSON config file\r\n return isAllowedConfig(\r\n readFileSync(getAbsolutePath(configFileName), 'utf8'),\r\n false,\r\n allowCodeExecution\r\n );\r\n } catch (error) {\r\n logWithStack(\r\n 2,\r\n error,\r\n `[config] Unable to load the configuration from the ${configFileName} file.`\r\n );\r\n }\r\n }\r\n\r\n // No additional options to return\r\n return {};\r\n}\r\n\r\n/**\r\n * Parses command-line arguments and pairs each argument with its corresponding\r\n * option in the configuration. The values are structured into a nested options\r\n * object, based on predefined mappings.\r\n *\r\n * @function _pairArgumentValue\r\n *\r\n * @param {Array.} nestedProps - An array of nesting level for all\r\n * options.\r\n * @param {Array.} cliArgs - An array of command-line arguments\r\n * containing options and their associated values.\r\n *\r\n * @returns {Object} An updated options object where each option from\r\n * the command-line is paired with its value, structured into nested objects\r\n * as defined.\r\n */\r\nfunction _pairArgumentValue(nestedProps, cliArgs) {\r\n // An empty object to collect and structurize data from the args\r\n const cliOptions = {};\r\n\r\n // Cycle through all CLI args and filter them\r\n for (let i = 0; i < cliArgs.length; i++) {\r\n const option = cliArgs[i].replace(/-/g, '');\r\n\r\n // Find the right place for property's value\r\n const propertiesChain = nestedProps[option]\r\n ? nestedProps[option].split('.')\r\n : [];\r\n\r\n // Create options object with values from CLI for later parsing and merging\r\n propertiesChain.reduce((obj, prop, index) => {\r\n if (propertiesChain.length - 1 === index) {\r\n const value = cliArgs[++i];\r\n if (!value) {\r\n log(\r\n 2,\r\n `[config] Missing value for the CLI '--${option}' argument. Using the default value.`\r\n );\r\n }\r\n obj[prop] = value || null;\r\n } else if (obj[prop] === undefined) {\r\n obj[prop] = {};\r\n }\r\n return obj[prop];\r\n }, cliOptions);\r\n }\r\n\r\n // Return parsed CLI options\r\n return cliOptions;\r\n}\r\n\r\n/**\r\n * Recursively traverses the options object to print the usage information\r\n * for each option category and individual option.\r\n *\r\n * @function _cycleCategories\r\n *\r\n * @param {Object} options - The options object containing CLI options. It may\r\n * include nested categories and individual options.\r\n */\r\nfunction _cycleCategories(options) {\r\n for (const [name, option] of Object.entries(options)) {\r\n // If the current entry is a category and not a leaf option, recurse into it\r\n if (!Object.prototype.hasOwnProperty.call(option, 'value')) {\r\n _cycleCategories(option);\r\n } else {\r\n // Prepare description\r\n const descName = ` --${option.cliName || name}`;\r\n\r\n // Get the value\r\n let optionValue = option.value;\r\n\r\n // Prepare value for option that is not null and is array of strings\r\n if (optionValue !== null && option.types.includes('string[]')) {\r\n optionValue =\r\n '[' + optionValue.map((item) => `'${item}'`).join(', ') + ']';\r\n }\r\n\r\n // Prepare value for option that is not null and is a string\r\n if (optionValue !== null && option.types.includes('string')) {\r\n optionValue = `'${optionValue}'`;\r\n }\r\n\r\n // Display correctly aligned messages\r\n console.log(\r\n descName.green,\r\n `${('<' + option.types.join('|') + '>').yellow}`,\r\n `${String(optionValue).bold}`.blue,\r\n `- ${option.description}.`\r\n );\r\n }\r\n }\r\n}\r\n\r\nexport default {\r\n getOptions,\r\n updateOptions,\r\n setCliOptions,\r\n mapToNewOptions,\r\n validateOption,\r\n validateOptions,\r\n isAllowedConfig,\r\n printLicense,\r\n printUsage,\r\n printVersion\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * @overview HTTP utility module for fetching and posting data. Supports both\r\n * HTTP and HTTPS protocols, providing methods to make GET and POST requests\r\n * with customizable options. Includes protocol determination based on URL\r\n * and augments response objects with a 'text' property for easier data access.\r\n */\r\n\r\nimport http from 'http';\r\nimport https from 'https';\r\n\r\n/**\r\n * Fetches data from the specified URL using either HTTP or HTTPS protocol.\r\n *\r\n * @async\r\n * @function fetch\r\n *\r\n * @param {string} url - The URL to fetch data from.\r\n * @param {Object} [requestOptions={}] - Options for the HTTP/HTTPS request.\r\n * The default value is an empty object.\r\n *\r\n * @returns {Promise} A Promise that resolves to the HTTP/HTTPS response\r\n * object with added 'text' property or rejecting with an error.\r\n */\r\nexport async function fetch(url, requestOptions = {}) {\r\n return new Promise((resolve, reject) => {\r\n _getProtocolModule(url)\r\n .get(url, requestOptions, (response) => {\r\n let responseData = '';\r\n\r\n // A chunk of data has been received\r\n response.on('data', (chunk) => {\r\n responseData += chunk;\r\n });\r\n\r\n // The whole response has been received\r\n response.on('end', () => {\r\n if (!responseData) {\r\n reject('Nothing was fetched from the URL.');\r\n }\r\n response.text = responseData;\r\n resolve(response);\r\n });\r\n })\r\n .on('error', (error) => {\r\n reject(error);\r\n });\r\n });\r\n}\r\n\r\n/**\r\n * Sends a POST request to the specified URL with the provided JSON body using\r\n * either HTTP or HTTPS protocol.\r\n *\r\n * @async\r\n * @function post\r\n *\r\n * @param {string} url - The URL to send the POST request to.\r\n * @param {Object} [body={}] - The JSON body to include in the POST request.\r\n * The default value is an empty object.\r\n * @param {Object} [requestOptions={}] - Options for the HTTP/HTTPS request.\r\n * The default value is an empty object.\r\n *\r\n * @returns {Promise} A Promise that resolves to the HTTP/HTTPS response\r\n * object with added 'text' property or rejecting with an error.\r\n */\r\nexport async function post(url, body = {}, requestOptions = {}) {\r\n return new Promise((resolve, reject) => {\r\n const data = JSON.stringify(body);\r\n\r\n // Set default headers and merge with requestOptions\r\n const options = Object.assign(\r\n {\r\n method: 'POST',\r\n headers: {\r\n 'Content-Type': 'application/json',\r\n 'Content-Length': data.length\r\n }\r\n },\r\n requestOptions\r\n );\r\n\r\n const request = _getProtocolModule(url)\r\n .request(url, options, (response) => {\r\n let responseData = '';\r\n\r\n // A chunk of data has been received\r\n response.on('data', (chunk) => {\r\n responseData += chunk;\r\n });\r\n\r\n // The whole response has been received\r\n response.on('end', () => {\r\n try {\r\n response.text = responseData;\r\n resolve(response);\r\n } catch (error) {\r\n reject(error);\r\n }\r\n });\r\n })\r\n .on('error', (error) => {\r\n reject(error);\r\n });\r\n\r\n // Write the request body and end the request\r\n request.write(data);\r\n request.end();\r\n });\r\n}\r\n\r\n/**\r\n * Returns the HTTP or HTTPS protocol module based on the provided URL.\r\n *\r\n * @function _getProtocolModule\r\n *\r\n * @param {string} url - The URL to determine the protocol.\r\n *\r\n * @returns {Object} The HTTP or HTTPS protocol module (http or https).\r\n */\r\nfunction _getProtocolModule(url) {\r\n return url.startsWith('https') ? https : http;\r\n}\r\n\r\nexport default {\r\n fetch,\r\n post\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * @overview The cache manager is responsible for handling and managing\r\n * the Highcharts library along with its dependencies. It ensures that these\r\n * resources are stored and retrieved efficiently to optimize performance\r\n * and reduce redundant network requests. The cache is stored in the `.cache`\r\n * directory by default, which serves as a dedicated folder for keeping cached\r\n * files.\r\n */\r\n\r\nimport { existsSync, mkdirSync, readFileSync, writeFileSync } from 'fs';\r\nimport { join } from 'path';\r\n\r\nimport { HttpsProxyAgent } from 'https-proxy-agent';\r\n\r\nimport { getOptions, updateOptions } from './config.js';\r\nimport { fetch } from './fetch.js';\r\nimport { log } from './logger.js';\r\nimport { getAbsolutePath } from './utils.js';\r\n\r\nimport ExportError from './errors/ExportError.js';\r\n\r\n// The initial cache template\r\nconst cache = {\r\n cdnUrl: 'https://code.highcharts.com',\r\n activeManifest: {},\r\n sources: '',\r\n hcVersion: ''\r\n};\r\n\r\n/**\r\n * Checks the cache for Highcharts dependencies, updates the cache if needed,\r\n * and loads the sources.\r\n *\r\n * @async\r\n * @function checkAndUpdateCache\r\n *\r\n * @param {Object} highchartsOptions - The configuration object containing\r\n * `highcharts` options.\r\n * @param {Object} serverProxyOptions- The configuration object containing\r\n * `server.proxy` options.\r\n */\r\nexport async function checkAndUpdateCache(\r\n highchartsOptions,\r\n serverProxyOptions\r\n) {\r\n try {\r\n let fetchedModules;\r\n\r\n // Get the cache path\r\n const cachePath = getCachePath();\r\n\r\n // Prepare paths to manifest and sources from the cache folder\r\n const manifestPath = join(cachePath, 'manifest.json');\r\n const sourcePath = join(cachePath, 'sources.js');\r\n\r\n // Create the cache destination if it doesn't exist already\r\n !existsSync(cachePath) && mkdirSync(cachePath, { recursive: true });\r\n\r\n // Fetch all the scripts either if the `manifest.json` does not exist\r\n // or if the `forceFetch` option is enabled\r\n if (!existsSync(manifestPath) || highchartsOptions.forceFetch) {\r\n log(3, '[cache] Fetching and caching Highcharts dependencies.');\r\n fetchedModules = await _updateCache(\r\n highchartsOptions,\r\n serverProxyOptions,\r\n sourcePath\r\n );\r\n } else {\r\n let requestUpdate = false;\r\n\r\n // Read the manifest JSON\r\n const manifest = JSON.parse(readFileSync(manifestPath), 'utf8');\r\n\r\n // Check if the modules is an array, if so, we rewrite it to a map to make\r\n // it easier to resolve modules.\r\n if (manifest.modules && Array.isArray(manifest.modules)) {\r\n const moduleMap = {};\r\n manifest.modules.forEach((m) => (moduleMap[m] = 1));\r\n manifest.modules = moduleMap;\r\n }\r\n\r\n // Get the actual number of scripts to be fetched\r\n const { coreScripts, moduleScripts, indicatorScripts } =\r\n highchartsOptions;\r\n const numberOfModules =\r\n coreScripts.length + moduleScripts.length + indicatorScripts.length;\r\n\r\n // Compare the loaded highcharts config with the contents in cache.\r\n // If there are changes, fetch requested modules and products,\r\n // and bake them into a giant blob. Save the blob.\r\n if (manifest.version !== highchartsOptions.version) {\r\n log(\r\n 2,\r\n '[cache] A Highcharts version mismatch in the cache, need to re-fetch.'\r\n );\r\n requestUpdate = true;\r\n } else if (\r\n Object.keys(manifest.modules || {}).length !== numberOfModules\r\n ) {\r\n log(\r\n 2,\r\n '[cache] The cache and the requested modules do not match, need to re-fetch.'\r\n );\r\n requestUpdate = true;\r\n } else {\r\n // Check each module, if anything is missing refetch everything\r\n requestUpdate = (moduleScripts || []).some((moduleName) => {\r\n if (!manifest.modules[moduleName]) {\r\n log(\r\n 2,\r\n `[cache] The ${moduleName} is missing in the cache, need to re-fetch.`\r\n );\r\n return true;\r\n }\r\n });\r\n }\r\n\r\n // Update cache if needed\r\n if (requestUpdate) {\r\n fetchedModules = await _updateCache(\r\n highchartsOptions,\r\n serverProxyOptions,\r\n sourcePath\r\n );\r\n } else {\r\n log(3, '[cache] Dependency cache is up to date, proceeding.');\r\n\r\n // Load the sources\r\n cache.sources = readFileSync(sourcePath, 'utf8');\r\n\r\n // Get current modules map\r\n fetchedModules = manifest.modules;\r\n\r\n // Extract and save version of currently used Highcharts\r\n cache.hcVersion = extractVersion(cache.sources);\r\n }\r\n }\r\n\r\n // Finally, save the new manifest, which is basically our current config\r\n // in a slightly different format\r\n await _saveConfigToManifest(highchartsOptions, fetchedModules);\r\n } catch (error) {\r\n throw new ExportError(\r\n '[cache] Could not configure cache and create or update the config manifest.',\r\n 500\r\n ).setError(error);\r\n }\r\n}\r\n\r\n/**\r\n * Gets the version of Highcharts from the cache.\r\n *\r\n * @function getHighchartsVersion\r\n *\r\n * @returns {string} The cached Highcharts version.\r\n */\r\nexport function getHighchartsVersion() {\r\n return cache.hcVersion;\r\n}\r\n\r\n/**\r\n * Updates the Highcharts version in the applied configuration and checks\r\n * the cache for the new version.\r\n *\r\n * @async\r\n * @function updateHighchartsVersion\r\n *\r\n * @param {string} newVersion - The new Highcharts version to be applied.\r\n */\r\nexport async function updateHighchartsVersion(newVersion) {\r\n // Update to the new version\r\n const options = updateOptions({\r\n highcharts: {\r\n version: newVersion\r\n }\r\n });\r\n\r\n // Check if cache needs to be updated\r\n await checkAndUpdateCache(options.highcharts, options.server.proxy);\r\n}\r\n\r\n/**\r\n * Extracts Highcharts version from the cache's sources string.\r\n *\r\n * @function extractVersion\r\n *\r\n * @param {Object} cacheSources - The cache sources object.\r\n *\r\n * @returns {string} The extracted Highcharts version.\r\n */\r\nexport function extractVersion(cacheSources) {\r\n return cacheSources\r\n .substring(0, cacheSources.indexOf('*/'))\r\n .replace('/*', '')\r\n .replace('*/', '')\r\n .replace(/\\n/g, '')\r\n .trim();\r\n}\r\n\r\n/**\r\n * Extracts the Highcharts module name based on the scriptPath.\r\n *\r\n * @function extractModuleName\r\n *\r\n * @param {string} scriptPath - The path of the script from which the module\r\n * name will be extracted.\r\n *\r\n * @returns {string} The extracted module name.\r\n */\r\nexport function extractModuleName(scriptPath) {\r\n return scriptPath.replace(\r\n /(.*)\\/|(.*)modules\\/|stock\\/(.*)indicators\\/|maps\\/(.*)modules\\//gi,\r\n ''\r\n );\r\n}\r\n\r\n/**\r\n * Retrieves the current cache object.\r\n *\r\n * @function getCache\r\n *\r\n * @returns {Object} The cache object containing various cached data.\r\n */\r\nexport function getCache() {\r\n return cache;\r\n}\r\n\r\n/**\r\n * Gets the cache path for Highcharts.\r\n *\r\n * @function getCachePath\r\n *\r\n * @returns {string} The absolute path to the cache directory for Highcharts.\r\n */\r\nexport function getCachePath() {\r\n return getAbsolutePath(getOptions().highcharts.cachePath, 'utf8'); // #562\r\n}\r\n\r\n/**\r\n * Fetches a single script and updates the `fetchedModules` accordingly.\r\n *\r\n * @async\r\n * @function _fetchAndProcessScript\r\n *\r\n * @param {string} script - A path to script to get.\r\n * @param {Object} requestOptions - Additional options for the proxy agent\r\n * to use for a request.\r\n * @param {Object} fetchedModules - An object which tracks which Highcharts\r\n * modules have been fetched.\r\n * @param {boolean} [shouldThrowError=false] - A flag to indicate if the error\r\n * should be thrown. This should be used only for the core scripts. The default\r\n * value is `false`.\r\n *\r\n * @returns {Promise} A Promise that resolves to the text representation\r\n * of the fetched script.\r\n *\r\n * @throws {ExportError} Throws an `ExportError` if there is a problem\r\n * with fetching the script.\r\n */\r\nasync function _fetchAndProcessScript(\r\n script,\r\n requestOptions,\r\n fetchedModules,\r\n shouldThrowError = false\r\n) {\r\n // Get rid of the .js from the custom strings\r\n if (script.endsWith('.js')) {\r\n script = script.substring(0, script.length - 3);\r\n }\r\n log(4, `[cache] Fetching script - ${script}.js`);\r\n\r\n // Fetch the script\r\n const response = await fetch(`${script}.js`, requestOptions);\r\n\r\n // If OK, return its text representation\r\n if (response.statusCode === 200 && typeof response.text == 'string') {\r\n if (fetchedModules) {\r\n const moduleName = extractModuleName(script);\r\n fetchedModules[moduleName] = 1;\r\n }\r\n return response.text;\r\n }\r\n\r\n // Based on the `shouldThrowError` flag, decide how to serve error message\r\n if (shouldThrowError) {\r\n throw new ExportError(\r\n `[cache] Could not fetch the ${script}.js. The script might not exist in the requested version (status code: ${response.statusCode}).`,\r\n 404\r\n ).setError(response);\r\n } else {\r\n log(\r\n 2,\r\n `[cache] Could not fetch the ${script}.js. The script might not exist in the requested version.`\r\n );\r\n }\r\n}\r\n\r\n/**\r\n * Saves the provided configuration and fetched modules to the cache manifest\r\n * file.\r\n *\r\n * @async\r\n * @function _saveConfigToManifest\r\n *\r\n * @param {Object} highchartsOptions - The configuration object containing\r\n * `highcharts` options.\r\n * @param {Object} [fetchedModules={}] - An object which tracks which Highcharts\r\n * modules have been fetched. The default value is an empty object.\r\n *\r\n * @throws {ExportError} Throws an `ExportError` if an error occurs while\r\n * writing the cache manifest.\r\n */\r\nasync function _saveConfigToManifest(highchartsOptions, fetchedModules = {}) {\r\n const newManifest = {\r\n version: highchartsOptions.version,\r\n modules: fetchedModules\r\n };\r\n\r\n // Update cache object with the current modules\r\n cache.activeManifest = newManifest;\r\n\r\n log(3, '[cache] Writing a new manifest.');\r\n try {\r\n writeFileSync(\r\n join(getCachePath(), 'manifest.json'),\r\n JSON.stringify(newManifest),\r\n 'utf8'\r\n );\r\n } catch (error) {\r\n throw new ExportError(\r\n '[cache] Error writing the cache manifest.',\r\n 500\r\n ).setError(error);\r\n }\r\n}\r\n\r\n/**\r\n * Fetches Highcharts `scripts` and `customScripts` from the given CDNs.\r\n *\r\n * @async\r\n * @function _fetchScripts\r\n *\r\n * @param {Array.} coreScripts - Highcharts core scripts to fetch.\r\n * @param {Array.} moduleScripts - Highcharts modules to fetch.\r\n * @param {Array.} customScripts - Custom script paths to fetch (full\r\n * URLs).\r\n * @param {Object} serverProxyOptions - The configuration object containing\r\n * `server.proxy` options.\r\n * @param {Object} fetchedModules - An object which tracks which Highcharts\r\n * modules have been fetched.\r\n *\r\n * @returns {Promise} A Promise that resolves to the fetched scripts\r\n * content joined.\r\n *\r\n * @throws {ExportError} Throws an `ExportError` if an error occurs while\r\n * setting an HTTP Agent for proxy.\r\n */\r\nasync function _fetchScripts(\r\n coreScripts,\r\n moduleScripts,\r\n customScripts,\r\n serverProxyOptions,\r\n fetchedModules\r\n) {\r\n // Configure proxy if exists\r\n let proxyAgent;\r\n const proxyHost = serverProxyOptions.host;\r\n const proxyPort = serverProxyOptions.port;\r\n\r\n // Try to create a Proxy Agent\r\n if (proxyHost && proxyPort) {\r\n try {\r\n proxyAgent = new HttpsProxyAgent({\r\n host: proxyHost,\r\n port: proxyPort\r\n });\r\n } catch (error) {\r\n throw new ExportError(\r\n '[cache] Could not create a Proxy Agent.',\r\n 500\r\n ).setError(error);\r\n }\r\n }\r\n\r\n // If exists, add proxy agent to request options\r\n const requestOptions = proxyAgent\r\n ? {\r\n agent: proxyAgent,\r\n timeout: serverProxyOptions.timeout\r\n }\r\n : {};\r\n\r\n const allFetchPromises = [\r\n ...coreScripts.map((script) =>\r\n _fetchAndProcessScript(`${script}`, requestOptions, fetchedModules, true)\r\n ),\r\n ...moduleScripts.map((script) =>\r\n _fetchAndProcessScript(`${script}`, requestOptions, fetchedModules)\r\n ),\r\n ...customScripts.map((script) =>\r\n _fetchAndProcessScript(`${script}`, requestOptions)\r\n )\r\n ];\r\n\r\n const fetchedScripts = await Promise.all(allFetchPromises);\r\n return fetchedScripts.join(';\\n');\r\n}\r\n\r\n/**\r\n * Updates the local cache with Highcharts scripts and their versions.\r\n *\r\n * @async\r\n * @function _updateCache\r\n *\r\n * @param {Object} highchartsOptions - The configuration object containing\r\n * `highcharts` options.\r\n * @param {Object} serverProxyOptions - The configuration object containing\r\n * `server.proxy` options.\r\n * @param {string} sourcePath - The path to the source file in the cache.\r\n *\r\n * @returns {Promise} A Promise that resolves to an object representing\r\n * the fetched modules.\r\n *\r\n * @throws {ExportError} Throws an `ExportError` if there is an issue updating\r\n * the local Highcharts cache.\r\n */\r\nasync function _updateCache(highchartsOptions, serverProxyOptions, sourcePath) {\r\n // Get Highcharts version for scripts\r\n const hcVersion =\r\n highchartsOptions.version === 'latest'\r\n ? null\r\n : `${highchartsOptions.version}`;\r\n\r\n // Get the CDN url for scripts\r\n const cdnUrl = highchartsOptions.cdnUrl || cache.cdnUrl;\r\n\r\n try {\r\n const fetchedModules = {};\r\n\r\n log(\r\n 3,\r\n `[cache] Updating cache version to Highcharts: ${hcVersion || 'latest'}.`\r\n );\r\n\r\n cache.sources = await _fetchScripts(\r\n [\r\n ...highchartsOptions.coreScripts.map((c) =>\r\n hcVersion ? `${cdnUrl}/${hcVersion}/${c}` : `${cdnUrl}/${c}`\r\n )\r\n ],\r\n [\r\n ...highchartsOptions.moduleScripts.map((m) =>\r\n m === 'map'\r\n ? hcVersion\r\n ? `${cdnUrl}/maps/${hcVersion}/modules/${m}`\r\n : `${cdnUrl}/maps/modules/${m}`\r\n : hcVersion\r\n ? `${cdnUrl}/${hcVersion}/modules/${m}`\r\n : `${cdnUrl}/modules/${m}`\r\n ),\r\n ...highchartsOptions.indicatorScripts.map((i) =>\r\n hcVersion\r\n ? `${cdnUrl}/stock/${hcVersion}/indicators/${i}`\r\n : `${cdnUrl}/stock/indicators/${i}`\r\n )\r\n ],\r\n highchartsOptions.customScripts,\r\n serverProxyOptions,\r\n fetchedModules\r\n );\r\n\r\n // Extract and save version of currently used Highcharts\r\n cache.hcVersion = extractVersion(cache.sources);\r\n\r\n // Save the fetched modules into caches' source JSON\r\n writeFileSync(sourcePath, cache.sources);\r\n return fetchedModules;\r\n } catch (error) {\r\n throw new ExportError(\r\n '[cache] Unable to update the local Highcharts cache.',\r\n 500\r\n ).setError(error);\r\n }\r\n}\r\n\r\nexport default {\r\n checkAndUpdateCache,\r\n getHighchartsVersion,\r\n updateHighchartsVersion,\r\n extractVersion,\r\n extractModuleName,\r\n getCache,\r\n getCachePath\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * @overview Provides methods for initializing Highcharts with customized\r\n * animation settings and triggering the creation of Highcharts charts with\r\n * export-specific configurations in the page context. Supports dynamic option\r\n * merging, custom logic injection, and control over rendering behaviors. Used\r\n * by the Puppeteer page.\r\n */\r\n\r\n/* eslint-disable no-undef */\r\n\r\n/**\r\n * Setting the `Highcharts.animObject` function. Called when initing the page.\r\n *\r\n * @function setupHighcharts\r\n */\r\nexport function setupHighcharts() {\r\n Highcharts.animObject = function () {\r\n return { duration: 0 };\r\n };\r\n}\r\n\r\n/**\r\n * Creates the actual Highcharts chart on a page.\r\n *\r\n * @async\r\n * @function createChart\r\n *\r\n * @param {Object} exportOptions - The configuration object containing `export`\r\n * options.\r\n * @param {Object} customLogicOptions - The configuration object containing\r\n * `customLogic` options.\r\n *\r\n */\r\nexport async function createChart(exportOptions, customLogicOptions) {\r\n // Get required functions\r\n const { getOptions, setOptions, merge, wrap } = Highcharts;\r\n\r\n // Create a separate object for a potential `setOptions` usages in order\r\n // to prevent from polluting other exports that can happen on the same page\r\n Highcharts.setOptionsObj = merge(false, {}, getOptions());\r\n\r\n // NOTE: Is this used for anything useful?\r\n window.isRenderComplete = false;\r\n wrap(Highcharts.Chart.prototype, 'init', function (proceed, userOptions, cb) {\r\n // Override the `userOptions` with image friendly options\r\n userOptions = merge(userOptions, {\r\n exporting: {\r\n enabled: false\r\n },\r\n plotOptions: {\r\n series: {\r\n label: {\r\n enabled: false\r\n }\r\n }\r\n },\r\n /* Expects tooltip in the `userOptions` when `forExport` is true.\r\n https://github.com/highcharts/highcharts/blob/3ad430a353b8056b9e764aa4e5cd6828aa479db2/js/parts/Chart.js#L241\r\n */\r\n tooltip: {}\r\n });\r\n\r\n (userOptions.series || []).forEach(function (series) {\r\n series.animation = false;\r\n });\r\n\r\n // Add flag to know if chart render has been called.\r\n if (!window.onHighchartsRender) {\r\n window.onHighchartsRender = Highcharts.addEvent(this, 'render', () => {\r\n window.isRenderComplete = true;\r\n });\r\n }\r\n\r\n proceed.apply(this, [userOptions, cb]);\r\n });\r\n\r\n wrap(Highcharts.Series.prototype, 'init', function (proceed, chart, options) {\r\n proceed.apply(this, [chart, options]);\r\n });\r\n\r\n // Some mandatory additional `chart` and `exporting` options\r\n const additionalOptions = {\r\n chart: {\r\n // By default animation is disabled\r\n animation: false,\r\n // Get the right size values\r\n height: exportOptions.height,\r\n width: exportOptions.width\r\n },\r\n exporting: {\r\n // No need for the exporting button\r\n enabled: false\r\n }\r\n };\r\n\r\n // Get the input to export from the `instr` option\r\n const userOptions = new Function(`return ${exportOptions.instr}`)();\r\n\r\n // Get the `themeOptions` option\r\n const themeOptions = new Function(`return ${exportOptions.themeOptions}`)();\r\n\r\n // Get the `globalOptions` option\r\n const globalOptions = new Function(`return ${exportOptions.globalOptions}`)();\r\n\r\n // Merge the following options objects to create final options\r\n const finalOptions = merge(\r\n false,\r\n themeOptions,\r\n userOptions,\r\n // Placed it here instead in the init because of the size issues\r\n additionalOptions\r\n );\r\n\r\n // Prepare the `callback` option\r\n const finalCallback = customLogicOptions.callback\r\n ? new Function(`return ${customLogicOptions.callback}`)()\r\n : null;\r\n\r\n // Trigger the `customCode` option\r\n if (customLogicOptions.customCode) {\r\n new Function('options', customLogicOptions.customCode)(userOptions);\r\n }\r\n\r\n // Set the global options if exist\r\n if (globalOptions) {\r\n setOptions(globalOptions);\r\n }\r\n\r\n // Call the chart creation\r\n Highcharts[exportOptions.constr]('container', finalOptions, finalCallback);\r\n\r\n // Get the current global options\r\n const defaultOptions = getOptions();\r\n\r\n // Clear it just in case (e.g. the `setOptions` was used in the `customCode`)\r\n for (const prop in defaultOptions) {\r\n if (typeof defaultOptions[prop] !== 'function') {\r\n delete defaultOptions[prop];\r\n }\r\n }\r\n\r\n // Set the default options back\r\n setOptions(Highcharts.setOptionsObj);\r\n\r\n // Empty the custom global options object\r\n Highcharts.setOptionsObj = {};\r\n}\r\n\r\nexport default {\r\n setupHighcharts,\r\n createChart\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * @overview This module provides functions for managing Puppeteer browser\r\n * instance, creating and clearing pages, injecting custom resources,\r\n * and setting up Highcharts for server-side rendering. The module ensures\r\n * that resources are correctly managed and can handle failures during\r\n * operations like launching the browser or creating new pages.\r\n */\r\n\r\nimport { readFileSync } from 'fs';\r\nimport { join } from 'path';\r\n\r\nimport puppeteer from 'puppeteer';\r\n\r\nimport { getCachePath } from './cache.js';\r\nimport { getOptions } from './config.js';\r\nimport { setupHighcharts } from './highcharts.js';\r\nimport { log, logWithStack } from './logger.js';\r\nimport { __dirname, getAbsolutePath } from './utils.js';\r\n\r\nimport ExportError from './errors/ExportError.js';\r\n\r\n// Get the template for pages\r\nconst template = readFileSync(\r\n join(__dirname, 'templates', 'template.html'),\r\n 'utf8'\r\n);\r\n\r\n// To save the browser\r\nlet browser = null;\r\n\r\n/**\r\n * Retrieves the existing Puppeteer browser instance.\r\n *\r\n * @function getBrowser\r\n *\r\n * @returns {Object} The Puppeteer browser instance.\r\n *\r\n * @throws {ExportError} Throws an `ExportError` if no valid browser\r\n * has been created.\r\n */\r\nexport function getBrowser() {\r\n if (!browser) {\r\n throw new ExportError('[browser] No valid browser has been created.', 500);\r\n }\r\n return browser;\r\n}\r\n\r\n/**\r\n * Creates a Puppeteer browser instance with the specified arguments.\r\n *\r\n * @async\r\n * @function createBrowser\r\n *\r\n * @param {Array.} puppeteerArgs - Additional arguments for Puppeteer\r\n * launch.\r\n *\r\n * @returns {Promise} A Promise that resolves to the created Puppeteer\r\n * browser instance.\r\n *\r\n * @throws {ExportError} Throws an `ExportError` if max retries to open\r\n * a browser instance are reached, or if no browser instance is found after\r\n * retries.\r\n */\r\nexport async function createBrowser(puppeteerArgs) {\r\n // Get `debug` and `other` options\r\n const { debug, other } = getOptions();\r\n\r\n // Get the `debug` options\r\n const { enable: enabledDebug, ...debugOptions } = debug;\r\n\r\n // Launch options for the browser instance\r\n const launchOptions = {\r\n headless: other.browserShellMode ? 'shell' : true,\r\n userDataDir: 'tmp',\r\n args: puppeteerArgs || [],\r\n handleSIGINT: false,\r\n handleSIGTERM: false,\r\n handleSIGHUP: false,\r\n waitForInitialPage: false,\r\n defaultViewport: null,\r\n ...(enabledDebug && debugOptions)\r\n };\r\n\r\n // Create a browser\r\n if (!browser) {\r\n // A counter for the browser's launch retries\r\n let tryCount = 0;\r\n\r\n const open = async () => {\r\n try {\r\n log(\r\n 3,\r\n `[browser] Attempting to get a browser instance (try ${++tryCount}).`\r\n );\r\n\r\n // Launch the browser\r\n browser = await puppeteer.launch(launchOptions);\r\n } catch (error) {\r\n logWithStack(\r\n 1,\r\n error,\r\n '[browser] Failed to launch a browser instance.'\r\n );\r\n\r\n // Retry to launch browser until reaching max attempts\r\n if (tryCount < 25) {\r\n log(3, `[browser] Retry to open a browser (${tryCount} out of 25).`);\r\n\r\n // Wait for a 4 seconds before trying again\r\n await new Promise((response) => setTimeout(response, 4000));\r\n await open();\r\n } else {\r\n throw error;\r\n }\r\n }\r\n };\r\n\r\n try {\r\n await open();\r\n\r\n // Shell mode inform\r\n if (launchOptions.headless === 'shell') {\r\n log(3, `[browser] Launched browser in shell mode.`);\r\n }\r\n\r\n // Debug mode inform\r\n if (enabledDebug) {\r\n log(3, `[browser] Launched browser in debug mode.`);\r\n }\r\n } catch (error) {\r\n throw new ExportError(\r\n '[browser] Maximum retries to open a browser instance reached.',\r\n 500\r\n ).setError(error);\r\n }\r\n\r\n if (!browser) {\r\n throw new ExportError('[browser] Cannot find a browser to open.', 500);\r\n }\r\n }\r\n\r\n // Return a browser instance\r\n return browser;\r\n}\r\n\r\n/**\r\n * Closes the Puppeteer browser instance if it is connected.\r\n *\r\n * @async\r\n * @function closeBrowser\r\n */\r\nexport async function closeBrowser() {\r\n // Close the browser when connected\r\n if (browser && browser.connected) {\r\n await browser.close();\r\n }\r\n browser = null;\r\n log(4, '[browser] Closed the browser.');\r\n}\r\n\r\n/**\r\n * Creates a new Puppeteer page within an existing browser instance.\r\n * The function creates a new page, disables caching, sets content using\r\n * the `_setPageContent()`, and returns the created Puppeteer page.\r\n *\r\n * @async\r\n * @function newPage\r\n *\r\n * @param {Object} poolResource - The pool resource that contains `id`,\r\n * `workCount`, and `page`.\r\n *\r\n * @throws {ExportError} Throws an `ExportError` if no valid browser\r\n * has been connected or if a page is invalid or closed.\r\n */\r\nexport async function newPage(poolResource) {\r\n // Error in case of no connected browser\r\n if (!browser || !browser.connected) {\r\n throw new ExportError(`[browser] Browser is not yet connected.`, 500);\r\n }\r\n\r\n // Create a page\r\n poolResource.page = await browser.newPage();\r\n\r\n // Disable cache\r\n await poolResource.page.setCacheEnabled(false);\r\n\r\n // Set the content\r\n await _setPageContent(poolResource.page);\r\n\r\n // Set page events\r\n _setPageEvents(poolResource.page);\r\n\r\n // Check if the page is correctly created\r\n if (!poolResource.page || poolResource.page.isClosed()) {\r\n throw new ExportError('[browser] The page is invalid or closed.', 400);\r\n }\r\n}\r\n\r\n/**\r\n * Clears the content of a Puppeteer Page based on the specified mode. Logs\r\n * thrown error if clearing of a page's content fails.\r\n *\r\n * @async\r\n * @function clearPage\r\n *\r\n * @param {Object} poolResource - The pool resource that contains page and id.\r\n * @param {boolean} [hardReset=false] - A flag indicating the type of clearing\r\n * to be performed. If true, navigates to `about:blank` and resets content\r\n * and scripts. If false, clears the body content by setting a predefined HTML\r\n * structure. The default value is `false`.\r\n *\r\n * @returns {Promise} A Promise that resolves to true when page\r\n * is correctly cleared and false when it is not.\r\n */\r\nexport async function clearPage(poolResource, hardReset = false) {\r\n try {\r\n if (poolResource.page && !poolResource.page.isClosed()) {\r\n if (hardReset) {\r\n // Navigate to `about:blank`\r\n await poolResource.page.goto('about:blank', {\r\n waitUntil: 'domcontentloaded'\r\n });\r\n\r\n // Set the content and and scripts again\r\n await _setPageContent(poolResource.page);\r\n } else {\r\n // Clear body content\r\n await poolResource.page.evaluate(() => {\r\n document.body.innerHTML =\r\n '
';\r\n });\r\n }\r\n return true;\r\n }\r\n } catch (error) {\r\n logWithStack(\r\n 2,\r\n error,\r\n `[pool] Pool resource [${poolResource.id}] - Content of the page could not be cleared.`\r\n );\r\n\r\n // Set the `workLimit` to exceeded in order to recreate the resource\r\n poolResource.workCount = getOptions().pool.workLimit + 1;\r\n }\r\n return false;\r\n}\r\n\r\n/**\r\n * Adds custom JS and CSS resources to a Puppeteer Page based on the specified\r\n * options.\r\n *\r\n * @async\r\n * @function addPageResources\r\n *\r\n * @param {Object} page - The Puppeteer page object to which resources will\r\n * be added.\r\n * @param {Object} customLogicOptions - The configuration object containing\r\n * `customLogic` options.\r\n *\r\n * @returns {Promise>} A Promise that resolves to an array\r\n * of injected resources.\r\n */\r\nexport async function addPageResources(page, customLogicOptions) {\r\n // Injected resources array\r\n const injectedResources = [];\r\n\r\n // Use resources\r\n const resources = customLogicOptions.resources;\r\n if (resources) {\r\n const injectedJs = [];\r\n\r\n // Load custom JS code\r\n if (resources.js) {\r\n injectedJs.push({\r\n content: resources.js\r\n });\r\n }\r\n\r\n // Load scripts from all custom files\r\n if (resources.files) {\r\n for (const file of resources.files) {\r\n const isLocal = file.startsWith('http') ? false : true;\r\n\r\n // Add each custom script from resources' files\r\n injectedJs.push(\r\n isLocal\r\n ? {\r\n content: readFileSync(getAbsolutePath(file), 'utf8')\r\n }\r\n : {\r\n url: file\r\n }\r\n );\r\n }\r\n }\r\n\r\n for (const jsResource of injectedJs) {\r\n try {\r\n injectedResources.push(await page.addScriptTag(jsResource));\r\n } catch (error) {\r\n logWithStack(2, error, `[browser] The JS resource cannot be loaded.`);\r\n }\r\n }\r\n injectedJs.length = 0;\r\n\r\n // Load CSS\r\n const injectedCss = [];\r\n if (resources.css) {\r\n let cssImports = resources.css.match(/@import\\s*([^;]*);/g);\r\n if (cssImports) {\r\n // Handle css section\r\n for (let cssImportPath of cssImports) {\r\n if (cssImportPath) {\r\n cssImportPath = cssImportPath\r\n .replace('url(', '')\r\n .replace('@import', '')\r\n .replace(/\"/g, '')\r\n .replace(/'/g, '')\r\n .replace(/;/, '')\r\n .replace(/\\)/g, '')\r\n .trim();\r\n\r\n // Add each custom css from resources\r\n if (cssImportPath.startsWith('http')) {\r\n injectedCss.push({\r\n url: cssImportPath\r\n });\r\n } else if (customLogicOptions.allowFileResources) {\r\n injectedCss.push({\r\n path: getAbsolutePath(cssImportPath)\r\n });\r\n }\r\n }\r\n }\r\n }\r\n\r\n // The rest of the CSS section will be content by now\r\n injectedCss.push({\r\n content: resources.css.replace(/@import\\s*([^;]*);/g, '') || ' '\r\n });\r\n\r\n for (const cssResource of injectedCss) {\r\n try {\r\n injectedResources.push(await page.addStyleTag(cssResource));\r\n } catch (error) {\r\n logWithStack(\r\n 2,\r\n error,\r\n `[browser] The CSS resource cannot be loaded.`\r\n );\r\n }\r\n }\r\n injectedCss.length = 0;\r\n }\r\n }\r\n return injectedResources;\r\n}\r\n\r\n/**\r\n * Clears out all state set on the page with `addScriptTag` and `addStyleTag`.\r\n * Removes injected resources and resets CSS and script tags on the page.\r\n * Additionally, it destroys previously existing charts.\r\n *\r\n * @async\r\n * @function clearPageResources\r\n *\r\n * @param {Object} page - The Puppeteer page object from which resources will\r\n * be cleared.\r\n * @param {Array.} injectedResources - Array of injected resources\r\n * to be cleared.\r\n */\r\nexport async function clearPageResources(page, injectedResources) {\r\n try {\r\n for (const resource of injectedResources) {\r\n await resource.dispose();\r\n }\r\n\r\n // Destroy old charts after export is done and reset all CSS and script tags\r\n await page.evaluate(() => {\r\n // We are not guaranteed that Highcharts is loaded, when doing SVG exports\r\n if (typeof Highcharts !== 'undefined') {\r\n // eslint-disable-next-line no-undef\r\n const oldCharts = Highcharts.charts;\r\n\r\n // Check in any already existing charts\r\n if (Array.isArray(oldCharts) && oldCharts.length) {\r\n // Destroy old charts\r\n for (const oldChart of oldCharts) {\r\n oldChart && oldChart.destroy();\r\n // eslint-disable-next-line no-undef\r\n Highcharts.charts.shift();\r\n }\r\n }\r\n }\r\n\r\n // eslint-disable-next-line no-undef\r\n const [...scriptsToRemove] = document.getElementsByTagName('script');\r\n // eslint-disable-next-line no-undef\r\n const [, ...stylesToRemove] = document.getElementsByTagName('style');\r\n // eslint-disable-next-line no-undef\r\n const [...linksToRemove] = document.getElementsByTagName('link');\r\n\r\n // Remove tags\r\n for (const element of [\r\n ...scriptsToRemove,\r\n ...stylesToRemove,\r\n ...linksToRemove\r\n ]) {\r\n element.remove();\r\n }\r\n });\r\n } catch (error) {\r\n logWithStack(2, error, `[browser] Could not clear page's resources.`);\r\n }\r\n}\r\n\r\n/**\r\n * Sets the content for a Puppeteer Page using a predefined template\r\n * and additional scripts.\r\n *\r\n * @async\r\n * @function _setPageContent\r\n *\r\n * @param {Object} page - The Puppeteer page object to which the content\r\n * is being set.\r\n */\r\nasync function _setPageContent(page) {\r\n // Set the initial page content\r\n await page.setContent(template, { waitUntil: 'domcontentloaded' });\r\n\r\n // Add all registered Higcharts scripts, quite demanding\r\n await page.addScriptTag({ path: join(getCachePath(), 'sources.js') });\r\n\r\n // Set the initial `animObject` for Highcharts\r\n await page.evaluate(setupHighcharts);\r\n}\r\n\r\n/**\r\n * Set events (like `pageerror` and `console`) for a Puppeteer Page in order\r\n * to catch and display errors and console logs from the window context.\r\n *\r\n * @function _setPageEvents\r\n *\r\n * @param {Object} page - The Puppeteer page object to which the listeners\r\n * are being set.\r\n */\r\nfunction _setPageEvents(page) {\r\n // Get `debug` options\r\n const { debug } = getOptions();\r\n\r\n // Set the `pageerror` listener\r\n page.on('pageerror', async () => {\r\n // It would seem like this may fire at the same time or shortly before\r\n // a page is closed.\r\n if (page.isClosed()) {\r\n return;\r\n }\r\n });\r\n\r\n // Set the `console` listener, if needed\r\n if (debug.enable && debug.listenToConsole) {\r\n page.on('console', (message) => {\r\n console.log(`[debug] ${message.text()}`);\r\n });\r\n }\r\n}\r\n\r\nexport default {\r\n getBrowser,\r\n createBrowser,\r\n closeBrowser,\r\n newPage,\r\n clearPage,\r\n addPageResources,\r\n clearPageResources\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * The CSS to be used on the exported page.\r\n *\r\n * @returns {string} The CSS configuration.\r\n */\r\nexport default () => `\r\n\r\nhtml, body {\r\n margin: 0;\r\n padding: 0;\r\n box-sizing: border-box;\r\n}\r\n\r\n#table-div, #sliders, #datatable, #controls, .ld-row {\r\n display: none;\r\n height: 0;\r\n}\r\n\r\n#chart-container {\r\n box-sizing: border-box;\r\n margin: 0;\r\n overflow: auto;\r\n font-size: 0;\r\n}\r\n\r\n#chart-container > figure, div {\r\n margin-top: 0 !important;\r\n margin-bottom: 0 !important;\r\n}\r\n\r\n`;\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\nimport cssTemplate from './css.js';\r\n\r\n/**\r\n * The SVG template to use when loading SVG content to be exported.\r\n *\r\n * @param {string} svg - The SVG input content to be exported.\r\n *\r\n * @returns {string} The SVG template.\r\n */\r\nexport default (svg) => `\r\n\r\n\r\n \r\n \r\n Highcharts Export\r\n \r\n \r\n \r\n
\r\n ${svg}\r\n
\r\n \r\n\r\n\r\n`;\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * @overview This module handles chart export functionality using Puppeteer.\r\n * It supports exporting charts as SVG, PNG, JPEG, and PDF formats. The module\r\n * manages page resources, sets up the export environment, and processes chart\r\n * configurations or SVG inputs for rendering. Exports to a chart from a page\r\n * using Puppeteer.\r\n */\r\n\r\nimport { addPageResources, clearPageResources } from './browser.js';\r\nimport { createChart } from './highcharts.js';\r\nimport { log } from './logger.js';\r\n\r\nimport svgTemplate from '../templates/svgExport/svgExport.js';\r\n\r\nimport ExportError from './errors/ExportError.js';\r\n\r\n/**\r\n * Exports to a chart from a page using Puppeteer.\r\n *\r\n * @async\r\n * @function puppeteerExport\r\n *\r\n * @param {Object} page - Puppeteer page object.\r\n * @param {Object} exportOptions - The configuration object containing `export`\r\n * options.\r\n * @param {Object} customLogicOptions - The configuration object containing\r\n * `customLogic` options.\r\n *\r\n * @returns {Promise<(string|Buffer|ExportError)>} A Promise that resolves\r\n * to the exported data or rejecting with an `ExportError`.\r\n *\r\n * @throws {ExportError} Throws an `ExportError` if export to an unsupported\r\n * output format occurs.\r\n */\r\nexport async function puppeteerExport(page, exportOptions, customLogicOptions) {\r\n // Injected resources array (additional JS and CSS)\r\n const injectedResources = [];\r\n\r\n try {\r\n let isSVG = false;\r\n\r\n // Decide on the export method\r\n if (exportOptions.svg) {\r\n log(4, '[export] Treating as SVG input.');\r\n\r\n // If the `type` is also SVG, return the input\r\n if (exportOptions.type === 'svg') {\r\n return exportOptions.svg;\r\n }\r\n\r\n // Mark as SVG export for the later size corrections\r\n isSVG = true;\r\n\r\n // SVG export\r\n await page.setContent(svgTemplate(exportOptions.svg), {\r\n waitUntil: 'domcontentloaded'\r\n });\r\n } else {\r\n log(4, '[export] Treating as JSON config.');\r\n\r\n // Options export\r\n await page.evaluate(createChart, exportOptions, customLogicOptions);\r\n }\r\n\r\n // Keeps track of all resources added on the page with addXXXTag. etc\r\n // It's VITAL that all added resources ends up here so we can clear things\r\n // out when doing a new export in the same page!\r\n injectedResources.push(\r\n ...(await addPageResources(page, customLogicOptions))\r\n );\r\n\r\n // Get the real chart size and set the zoom accordingly\r\n const size = isSVG\r\n ? await page.evaluate((scale) => {\r\n const svgElement = document.querySelector(\r\n '#chart-container svg:first-of-type'\r\n );\r\n\r\n // Get the values correctly scaled\r\n const chartHeight = svgElement.height.baseVal.value * scale;\r\n const chartWidth = svgElement.width.baseVal.value * scale;\r\n\r\n // In case of SVG the zoom must be set directly for body as scale\r\n // eslint-disable-next-line no-undef\r\n document.body.style.zoom = scale;\r\n\r\n // Set the margin to 0px\r\n // eslint-disable-next-line no-undef\r\n document.body.style.margin = '0px';\r\n\r\n return {\r\n chartHeight,\r\n chartWidth\r\n };\r\n }, parseFloat(exportOptions.scale))\r\n : await page.evaluate(() => {\r\n // eslint-disable-next-line no-undef\r\n const { chartHeight, chartWidth } = window.Highcharts.charts[0];\r\n\r\n // No need for such scale manipulation in case of other types\r\n // of exports. Reset the zoom for other exports than to SVGs\r\n // eslint-disable-next-line no-undef\r\n document.body.style.zoom = 1;\r\n\r\n return {\r\n chartHeight,\r\n chartWidth\r\n };\r\n });\r\n\r\n // Get the clip region for the page\r\n const { x, y } = await _getClipRegion(page);\r\n\r\n // Set final `height` for viewport\r\n const viewportHeight = Math.abs(\r\n Math.ceil(size.chartHeight || exportOptions.height)\r\n );\r\n\r\n // Set final `width` for viewport\r\n const viewportWidth = Math.abs(\r\n Math.ceil(size.chartWidth || exportOptions.width)\r\n );\r\n\r\n // Set the final viewport now that we have the real height\r\n await page.setViewport({\r\n height: viewportHeight,\r\n width: viewportWidth,\r\n deviceScaleFactor: isSVG ? 1 : parseFloat(exportOptions.scale)\r\n });\r\n\r\n let result;\r\n // Rasterization process\r\n switch (exportOptions.type) {\r\n case 'svg':\r\n result = await _createSVG(page);\r\n break;\r\n case 'png':\r\n case 'jpeg':\r\n result = await _createImage(\r\n page,\r\n exportOptions.type,\r\n {\r\n width: viewportWidth,\r\n height: viewportHeight,\r\n x,\r\n y\r\n },\r\n exportOptions.rasterizationTimeout\r\n );\r\n break;\r\n case 'pdf':\r\n result = await _createPDF(\r\n page,\r\n viewportHeight,\r\n viewportWidth,\r\n exportOptions.rasterizationTimeout\r\n );\r\n break;\r\n default:\r\n throw new ExportError(\r\n `[export] Unsupported output format: ${exportOptions.type}.`,\r\n 400\r\n );\r\n }\r\n\r\n // Clear previously injected JS and CSS resources\r\n await clearPageResources(page, injectedResources);\r\n return result;\r\n } catch (error) {\r\n await clearPageResources(page, injectedResources);\r\n return error;\r\n }\r\n}\r\n\r\n/**\r\n * Retrieves the clipping region coordinates of the specified page element\r\n * with the 'chart-container' id.\r\n *\r\n * @async\r\n * @function _getClipRegion\r\n *\r\n * @param {Object} page - Puppeteer page object.\r\n *\r\n * @returns {Promise} A Promise that resolves to an object containing\r\n * `x`, `y`, `width`, and `height` properties.\r\n */\r\nasync function _getClipRegion(page) {\r\n return page.$eval('#chart-container', (element) => {\r\n const { x, y, width, height } = element.getBoundingClientRect();\r\n return {\r\n x,\r\n y,\r\n width,\r\n height: Math.trunc(height > 1 ? height : 500)\r\n };\r\n });\r\n}\r\n\r\n/**\r\n * Creates an SVG by evaluating the `outerHTML` of the first 'svg' element\r\n * inside an element with the id 'container'.\r\n *\r\n * @async\r\n * @function _createSVG\r\n *\r\n * @param {Object} page - Puppeteer page object.\r\n *\r\n * @returns {Promise} A Promise that resolves to the SVG string.\r\n */\r\nasync function _createSVG(page) {\r\n return page.$eval(\r\n '#container svg:first-of-type',\r\n (element) => element.outerHTML\r\n );\r\n}\r\n\r\n/**\r\n * Creates an image using Puppeteer's page `screenshot` functionality with\r\n * specified options.\r\n *\r\n * @async\r\n * @function _createImage\r\n *\r\n * @param {Object} page - Puppeteer page object.\r\n * @param {string} type - Image type.\r\n * @param {Object} clip - Clipping region coordinates.\r\n * @param {number} rasterizationTimeout - Timeout for rasterization\r\n * in milliseconds.\r\n *\r\n * @returns {Promise} A Promise that resolves to the image buffer\r\n * or rejecting with an `ExportError` for timeout.\r\n */\r\nasync function _createImage(page, type, clip, rasterizationTimeout) {\r\n return Promise.race([\r\n page.screenshot({\r\n type,\r\n clip,\r\n encoding: 'base64',\r\n fullPage: false,\r\n optimizeForSpeed: true,\r\n captureBeyondViewport: true,\r\n ...(type !== 'png' ? { quality: 80 } : {}),\r\n // Always render on a transparent page if the expected type format is PNG\r\n omitBackground: type == 'png' // #447, #463\r\n }),\r\n new Promise((_resolve, reject) =>\r\n setTimeout(\r\n () => reject(new ExportError('Rasterization timeout', 408)),\r\n rasterizationTimeout || 1500\r\n )\r\n )\r\n ]);\r\n}\r\n\r\n/**\r\n * Creates a PDF using Puppeteer's page `pdf` functionality with specified\r\n * options.\r\n *\r\n * @async\r\n * @function _createPDF\r\n *\r\n * @param {Object} page - Puppeteer page object.\r\n * @param {number} height - PDF height.\r\n * @param {number} width - PDF width.\r\n * @param {number} rasterizationTimeout - Timeout for rasterization\r\n * in milliseconds.\r\n *\r\n * @returns {Promise} A Promise that resolves to the PDF buffer.\r\n */\r\nasync function _createPDF(page, height, width, rasterizationTimeout) {\r\n await page.emulateMediaType('screen');\r\n return page.pdf({\r\n // This will remove an extra empty page in PDF exports\r\n height: height + 1,\r\n width,\r\n encoding: 'base64',\r\n timeout: rasterizationTimeout || 1500\r\n });\r\n}\r\n\r\nexport default {\r\n puppeteerExport\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * @overview This module provides a worker pool implementation for managing\r\n * the browser instance and pages, specifically designed for use with\r\n * the Highcharts Export Server. It optimizes resources usage and performance\r\n * by maintaining a pool of workers that can handle concurrent export tasks\r\n * using Puppeteer.\r\n */\r\n\r\nimport { Pool } from 'tarn';\r\nimport { v4 as uuid } from 'uuid';\r\n\r\nimport { clearPage, createBrowser, closeBrowser, newPage } from './browser.js';\r\nimport { puppeteerExport } from './export.js';\r\nimport { log, logWithStack } from './logger.js';\r\nimport { getNewDateTime, measureTime } from './utils.js';\r\n\r\nimport ExportError from './errors/ExportError.js';\r\n\r\n// The pool instance\r\nlet pool = null;\r\n\r\n// Pool statistics\r\nconst poolStats = {\r\n exportsAttempted: 0,\r\n exportsPerformed: 0,\r\n exportsDropped: 0,\r\n exportsFromSvg: 0,\r\n exportsFromOptions: 0,\r\n exportsFromSvgAttempts: 0,\r\n exportsFromOptionsAttempts: 0,\r\n timeSpent: 0,\r\n timeSpentAverage: 0\r\n};\r\n\r\n/**\r\n * Initializes the export pool with the provided configuration, creating\r\n * a browser instance and setting up worker resources.\r\n *\r\n * @async\r\n * @function initPool\r\n *\r\n * @param {Object} poolOptions - The configuration object containing `pool`\r\n * options.\r\n * @param {Array.} puppeteerArgs - Additional arguments for Puppeteer\r\n * launch.\r\n *\r\n * @returns {Promise} A Promise that resolves to ending the function\r\n * execution when an already initialized pool of resources is found.\r\n *\r\n * @throws {ExportError} Throws an `ExportError` if could not create the pool\r\n * of workers.\r\n */\r\nexport async function initPool(poolOptions, puppeteerArgs) {\r\n // Create a browser instance with the puppeteer arguments\r\n await createBrowser(puppeteerArgs);\r\n\r\n try {\r\n log(\r\n 3,\r\n `[pool] Initializing pool with workers: min ${poolOptions.minWorkers}, max ${poolOptions.maxWorkers}.`\r\n );\r\n\r\n if (pool) {\r\n log(\r\n 4,\r\n '[pool] Already initialized, please kill it before creating a new one.'\r\n );\r\n return;\r\n }\r\n\r\n // Keep an eye on a correct min and max workers number\r\n if (poolOptions.minWorkers > poolOptions.maxWorkers) {\r\n poolOptions.minWorkers = poolOptions.maxWorkers;\r\n }\r\n\r\n // Create a pool along with a minimal number of resources\r\n pool = new Pool({\r\n // Get the `create`, `validate`, and `destroy` functions\r\n ..._factory(poolOptions),\r\n min: poolOptions.minWorkers,\r\n max: poolOptions.maxWorkers,\r\n acquireTimeoutMillis: poolOptions.acquireTimeout,\r\n createTimeoutMillis: poolOptions.createTimeout,\r\n destroyTimeoutMillis: poolOptions.destroyTimeout,\r\n idleTimeoutMillis: poolOptions.idleTimeout,\r\n createRetryIntervalMillis: poolOptions.createRetryInterval,\r\n reapIntervalMillis: poolOptions.reaperInterval,\r\n propagateCreateError: false\r\n });\r\n\r\n // Set events\r\n pool.on('release', async (resource) => {\r\n // Clear page\r\n const clearStatus = await clearPage(resource, false);\r\n log(\r\n 4,\r\n `[pool] Pool resource [${resource.id}] - Releasing a worker. Clear page status: ${clearStatus}.`\r\n );\r\n });\r\n\r\n pool.on('destroySuccess', (_eventId, resource) => {\r\n log(\r\n 4,\r\n `[pool] Pool resource [${resource.id}] - Destroyed a worker successfully.`\r\n );\r\n resource.page = null;\r\n });\r\n\r\n const initialResources = [];\r\n // Create an initial number of resources\r\n for (let i = 0; i < poolOptions.minWorkers; i++) {\r\n try {\r\n const resource = await pool.acquire().promise;\r\n initialResources.push(resource);\r\n } catch (error) {\r\n logWithStack(2, error, '[pool] Could not create an initial resource.');\r\n }\r\n }\r\n\r\n // Release the initial number of resources back to the pool\r\n initialResources.forEach((resource) => {\r\n pool.release(resource);\r\n });\r\n\r\n log(\r\n 3,\r\n `[pool] The pool is ready${initialResources.length ? ` with ${initialResources.length} initial resources waiting.` : '.'}`\r\n );\r\n } catch (error) {\r\n throw new ExportError(\r\n '[pool] Could not configure and create the pool of workers.',\r\n 500\r\n ).setError(error);\r\n }\r\n}\r\n\r\n/**\r\n * Terminates all workers in the pool, destroys the pool, and closes the browser\r\n * instance.\r\n *\r\n * @async\r\n * @function killPool\r\n *\r\n * @returns {Promise} A Promise that resolves once all workers are\r\n * terminated, the pool is destroyed, and the browser is successfully closed.\r\n */\r\nexport async function killPool() {\r\n log(3, '[pool] Killing pool with all workers and closing browser.');\r\n\r\n // If still alive, destroy the pool of pages before closing a browser\r\n if (pool) {\r\n // Free up not released workers\r\n for (const worker of pool.used) {\r\n pool.release(worker.resource);\r\n }\r\n\r\n // Destroy the pool if it is still available\r\n if (!pool.destroyed) {\r\n await pool.destroy();\r\n log(4, '[pool] Destroyed the pool of resources.');\r\n }\r\n pool = null;\r\n }\r\n\r\n // Close the browser instance\r\n await closeBrowser();\r\n}\r\n\r\n/**\r\n * Processes the export work using a worker from the pool. Acquires a worker\r\n * handle from the pool, performs the export using puppeteer, and releases\r\n * the worker handle back to the pool.\r\n *\r\n * @async\r\n * @function postWork\r\n *\r\n * @param {Object} options - The configuration object containing complete set\r\n * of options.\r\n *\r\n * @returns {Promise} A Promise that resolves to the export result\r\n * and options.\r\n *\r\n * @throws {ExportError} Throws an `ExportError` if an error occurs during\r\n * the export process.\r\n */\r\nexport async function postWork(options) {\r\n let workerHandle;\r\n\r\n try {\r\n log(4, '[pool] Work received, starting to process.');\r\n\r\n // An export attempt counted\r\n ++poolStats.exportsAttempted;\r\n\r\n // Display the pool information if needed\r\n if (options.pool.benchmarking) {\r\n getPoolInfo();\r\n }\r\n\r\n // Throw an error in case of lacking the pool instance\r\n if (!pool) {\r\n throw new ExportError(\r\n '[pool] Work received, but pool has not been started.',\r\n 500\r\n );\r\n }\r\n\r\n // The acquire counter\r\n const acquireCounter = measureTime();\r\n\r\n // Try to acquire the worker along with the id, works count and page\r\n try {\r\n log(4, '[pool] Acquiring a worker handle.');\r\n\r\n // Acquire a pool resource\r\n workerHandle = await pool.acquire().promise;\r\n\r\n // Check the page acquire time\r\n if (options.server.benchmarking) {\r\n log(\r\n 5,\r\n `[benchmark] ${options.requestId ? `Request [${options.requestId}] - ` : ''}`,\r\n `Acquiring a worker handle took ${acquireCounter()}ms.`\r\n );\r\n }\r\n } catch (error) {\r\n throw new ExportError(\r\n `[pool] ${\r\n options.requestId ? `Request [${options.requestId}] - ` : ''\r\n }Error encountered when acquiring an available entry: ${acquireCounter()}ms.`,\r\n 400\r\n ).setError(error);\r\n }\r\n log(4, '[pool] Acquired a worker handle.');\r\n\r\n if (!workerHandle.page) {\r\n // Set the `workLimit` to exceeded in order to recreate the resource\r\n workerHandle.workCount = options.pool.workLimit + 1;\r\n throw new ExportError(\r\n '[pool] Resolved worker page is invalid: the pool setup is wonky.',\r\n 400\r\n );\r\n }\r\n\r\n // Save the start time\r\n const workStart = getNewDateTime();\r\n\r\n log(\r\n 4,\r\n `[pool] Pool resource [${workerHandle.id}] - Starting work on this pool entry.`\r\n );\r\n\r\n // Start measuring export time\r\n const exportCounter = measureTime();\r\n\r\n // Perform an export on a puppeteer level\r\n const result = await puppeteerExport(\r\n workerHandle.page,\r\n options.export,\r\n options.customLogic\r\n );\r\n\r\n // Check if it's an error\r\n if (result instanceof Error) {\r\n // NOTE:\r\n // If there's a rasterization timeout, we want need to flush the page.\r\n // This is because the page may be in a state where it's waiting for\r\n // the screenshot to finish even though the timeout has occured.\r\n // Which of course causes a lot of issues with the event system,\r\n // and page consistency.\r\n //\r\n // NOTE:\r\n // Only page.screenshot will throw this, timeouts for PDF's are\r\n // handled by the page.pdf function itself.\r\n //\r\n // ...yes, this is ugly.\r\n if (result.message === 'Rasterization timeout') {\r\n // Set the `workLimit` to exceeded in order to recreate the resource\r\n workerHandle.workCount = options.pool.workLimit + 1;\r\n workerHandle.page = null;\r\n }\r\n\r\n if (\r\n result.name === 'TimeoutError' ||\r\n result.message === 'Rasterization timeout'\r\n ) {\r\n throw new ExportError(\r\n `[pool] ${\r\n options.requestId ? `Request [${options.requestId}] - ` : ''\r\n }Rasterization timeout: your chart may be too complex or large, and failed to render within the allotted time.`\r\n ).setError(result);\r\n } else {\r\n throw new ExportError(\r\n `[pool] ${\r\n options.requestId ? `Request [${options.requestId}] - ` : ''\r\n }Error encountered during export: ${exportCounter()}ms.`\r\n ).setError(result);\r\n }\r\n }\r\n\r\n // Check the Puppeteer export time\r\n if (options.server.benchmarking) {\r\n log(\r\n 5,\r\n `[benchmark] ${options.requestId ? `Request [${options.requestId}] - ` : ''}`,\r\n `Exporting a chart sucessfully took ${exportCounter()}ms.`\r\n );\r\n }\r\n\r\n // Release the resource back to the pool\r\n pool.release(workerHandle);\r\n\r\n // Used for statistics in averageTime and processedWorkCount, which\r\n // in turn is used by the /health route.\r\n const workEnd = getNewDateTime();\r\n const exportTime = workEnd - workStart;\r\n\r\n poolStats.timeSpent += exportTime;\r\n poolStats.timeSpentAverage =\r\n poolStats.timeSpent / ++poolStats.exportsPerformed;\r\n\r\n log(4, `[pool] Work completed in ${exportTime}ms.`);\r\n\r\n // Otherwise return the result\r\n return {\r\n result,\r\n options\r\n };\r\n } catch (error) {\r\n ++poolStats.exportsDropped;\r\n\r\n if (workerHandle) {\r\n pool.release(workerHandle);\r\n }\r\n\r\n throw error;\r\n }\r\n}\r\n\r\n/**\r\n * Retrieves the current pool instance.\r\n *\r\n * @function getPool\r\n *\r\n * @returns {(Object|null)} The current pool instance if initialized, or null\r\n * if the pool has not been created.\r\n */\r\nexport function getPool() {\r\n return pool;\r\n}\r\n\r\n/**\r\n * Gets the statistic of a pool instace about exports.\r\n *\r\n * @function getPoolStats\r\n *\r\n * @returns {Object} The current pool statistics.\r\n */\r\nexport function getPoolStats() {\r\n return poolStats;\r\n}\r\n\r\n/**\r\n * Retrieves pool information in JSON format, including minimum and maximum\r\n * workers, available workers, workers in use, and pending acquire requests.\r\n *\r\n * @function getPoolInfoJSON\r\n *\r\n * @returns {Object} Pool information in JSON format.\r\n */\r\nexport function getPoolInfoJSON() {\r\n return {\r\n min: pool.min,\r\n max: pool.max,\r\n used: pool.numUsed(),\r\n available: pool.numFree(),\r\n allCreated: pool.numUsed() + pool.numFree(),\r\n pendingAcquires: pool.numPendingAcquires(),\r\n pendingCreates: pool.numPendingCreates(),\r\n pendingValidations: pool.numPendingValidations(),\r\n pendingDestroys: pool.pendingDestroys.length,\r\n absoluteAll:\r\n pool.numUsed() +\r\n pool.numFree() +\r\n pool.numPendingAcquires() +\r\n pool.numPendingCreates() +\r\n pool.numPendingValidations() +\r\n pool.pendingDestroys.length\r\n };\r\n}\r\n\r\n/**\r\n * Logs information about the current state of the pool, including the minimum\r\n * and maximum workers, available workers, workers in use, and pending acquire\r\n * requests.\r\n *\r\n * @function getPoolInfo\r\n */\r\nexport function getPoolInfo() {\r\n const {\r\n min,\r\n max,\r\n used,\r\n available,\r\n allCreated,\r\n pendingAcquires,\r\n pendingCreates,\r\n pendingValidations,\r\n pendingDestroys,\r\n absoluteAll\r\n } = getPoolInfoJSON();\r\n\r\n log(5, `[pool] The minimum number of resources allowed by pool: ${min}.`);\r\n log(5, `[pool] The maximum number of resources allowed by pool: ${max}.`);\r\n log(5, `[pool] The number of used resources: ${used}.`);\r\n log(5, `[pool] The number of free resources: ${available}.`);\r\n log(\r\n 5,\r\n `[pool] The number of all created (used and free) resources: ${allCreated}.`\r\n );\r\n log(\r\n 5,\r\n `[pool] The number of resources waiting to be acquired: ${pendingAcquires}.`\r\n );\r\n log(\r\n 5,\r\n `[pool] The number of resources waiting to be created: ${pendingCreates}.`\r\n );\r\n log(\r\n 5,\r\n `[pool] The number of resources waiting to be validated: ${pendingValidations}.`\r\n );\r\n log(\r\n 5,\r\n `[pool] The number of resources waiting to be destroyed: ${pendingDestroys}.`\r\n );\r\n log(5, `[pool] The number of all resources: ${absoluteAll}.`);\r\n}\r\n\r\n/**\r\n * Factory function that returns an object with `create`, `validate`,\r\n * and `destroy` functions for the pool instance.\r\n *\r\n * @function _factory\r\n *\r\n * @param {Object} poolOptions - The configuration object containing `pool`\r\n * options.\r\n */\r\nfunction _factory(poolOptions) {\r\n return {\r\n /**\r\n * Creates a new worker page for the export pool.\r\n *\r\n * @async\r\n * @function create\r\n *\r\n * @returns {Promise} A Promise that resolves to an object\r\n * containing the worker ID, a reference to the browser page, and initial\r\n * work count.\r\n *\r\n * @throws {ExportError} Throws an `ExportError` if there is an error during\r\n * the creation of the new page.\r\n */\r\n create: async () => {\r\n // Init the resource with unique id and work count\r\n const poolResource = {\r\n id: uuid(),\r\n // Try to distribute the initial work count\r\n workCount: Math.round(Math.random() * (poolOptions.workLimit / 2))\r\n };\r\n\r\n try {\r\n // Start measuring a page creation time\r\n const startDate = getNewDateTime();\r\n\r\n // Create a new page\r\n await newPage(poolResource);\r\n\r\n // Measure the time of full creation and configuration of a page\r\n log(\r\n 3,\r\n `[pool] Pool resource [${poolResource.id}] - Successfully created a worker, took ${\r\n getNewDateTime() - startDate\r\n }ms.`\r\n );\r\n\r\n // Return ready pool resource\r\n return poolResource;\r\n } catch (error) {\r\n log(\r\n 3,\r\n `[pool] Pool resource [${poolResource.id}] - Error encountered when creating a new page.`\r\n );\r\n throw error;\r\n }\r\n },\r\n\r\n /**\r\n * Validates a worker page in the export pool, checking if it has exceeded\r\n * the work limit.\r\n *\r\n * @async\r\n * @function validate\r\n *\r\n * @param {Object} poolResource - The handle to the worker, containing\r\n * the worker's ID, a reference to the browser page, and work count.\r\n *\r\n * @returns {Promise} A Promise that resolves to true if the worker\r\n * is valid and within the work limit; otherwise, to false.\r\n */\r\n validate: async (poolResource) => {\r\n // NOTE:\r\n // In certain cases acquiring throws a TargetCloseError, which may\r\n // be caused by two things:\r\n // - The page is closed and attempted to be reused.\r\n // - Lost contact with the browser.\r\n //\r\n // What we're seeing in logs is that successive exports typically\r\n // succeeds, and the server recovers, indicating that it's likely\r\n // the first case. This is an attempt at allievating the issue by\r\n // simply not validating the worker if the page is null or closed.\r\n //\r\n // The actual result from when this happened, was that a worker would\r\n // be completely locked, stopping it from being acquired until\r\n // its work count reached the limit.\r\n\r\n // Check if the `page` is valid\r\n if (!poolResource.page) {\r\n log(\r\n 3,\r\n `[pool] Pool resource [${poolResource.id}] - Validation failed (no valid page is found).`\r\n );\r\n return false;\r\n }\r\n\r\n // Check if the `page` is closed\r\n if (poolResource.page.isClosed()) {\r\n log(\r\n 3,\r\n `[pool] Pool resource [${poolResource.id}] - Validation failed (page is closed or invalid).`\r\n );\r\n return false;\r\n }\r\n\r\n // Check if the `mainFrame` is detached\r\n if (poolResource.page.mainFrame().detached) {\r\n log(\r\n 3,\r\n `[pool] Pool resource [${poolResource.id}] - Validation failed (page's frame is detached).`\r\n );\r\n return false;\r\n }\r\n\r\n // Check if the `workLimit` is exceeded\r\n if (\r\n poolOptions.workLimit &&\r\n ++poolResource.workCount > poolOptions.workLimit\r\n ) {\r\n log(\r\n 3,\r\n `[pool] Pool resource [${poolResource.id}] - Validation failed (exceeded the ${poolOptions.workLimit} works per resource limit).`\r\n );\r\n return false;\r\n }\r\n\r\n // The `poolResource` is validated\r\n return true;\r\n },\r\n\r\n /**\r\n * Destroys a worker entry in the export pool, closing its associated page.\r\n *\r\n * @async\r\n * @function destroy\r\n *\r\n * @param {Object} poolResource - The handle to the worker, containing\r\n * the worker's ID, a reference to the browser page, and work count.\r\n */\r\n destroy: async (poolResource) => {\r\n log(\r\n 3,\r\n `[pool] Pool resource [${poolResource.id}] - Destroying a worker.`\r\n );\r\n\r\n if (poolResource.page && !poolResource.page.isClosed()) {\r\n try {\r\n // Remove all attached event listeners from the resource\r\n poolResource.page.removeAllListeners('pageerror');\r\n poolResource.page.removeAllListeners('console');\r\n poolResource.page.removeAllListeners('framedetached');\r\n\r\n // We need to wait around for this\r\n await poolResource.page.close();\r\n } catch (error) {\r\n log(\r\n 3,\r\n `[pool] Pool resource [${poolResource.id}] - Page could not be closed upon destroying.`\r\n );\r\n throw error;\r\n }\r\n }\r\n }\r\n };\r\n}\r\n\r\nexport default {\r\n initPool,\r\n killPool,\r\n postWork,\r\n getPool,\r\n getPoolStats,\r\n getPoolInfo,\r\n getPoolInfoJSON\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * @overview Used to sanitize the strings coming from the exporting module\r\n * to prevent XSS attacks (with the DOMPurify library).\r\n */\r\n\r\nimport DOMPurify from 'dompurify';\r\nimport { JSDOM } from 'jsdom';\r\n\r\n/**\r\n * Sanitizes a given HTML string by removing \r\n * tags and any content within them.\r\n *\r\n * @function sanitize\r\n *\r\n * @param {string} input - The HTML string to be sanitized.\r\n *\r\n * @returns {string} The sanitized HTML string.\r\n */\r\nexport function sanitize(input) {\r\n // Get the virtual DOM\r\n const window = new JSDOM('').window;\r\n\r\n // Create a purifying instance\r\n const purify = DOMPurify(window);\r\n\r\n // Return sanitized input\r\n return purify.sanitize(input, { ADD_TAGS: ['foreignObject'] });\r\n}\r\n\r\nexport default {\r\n sanitize\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * @overview This module provides functions to prepare for the exporting charts\r\n * into various image output formats such as JPEG, PNG, PDF, and SVGs.\r\n * It supports single and batch export operations and allows customization\r\n * through options passed from configurations or APIs.\r\n */\r\n\r\nimport { readFileSync, writeFileSync } from 'fs';\r\n\r\nimport { isAllowedConfig, updateOptions, validateOption } from './config.js';\r\nimport { log, logWithStack } from './logger.js';\r\nimport { getPoolStats, killPool, postWork } from './pool.js';\r\nimport { sanitize } from './sanitize.js';\r\nimport {\r\n fixConstr,\r\n fixOutfile,\r\n fixType,\r\n getAbsolutePath,\r\n getBase64,\r\n isObject,\r\n roundNumber,\r\n wrapAround\r\n} from './utils.js';\r\n\r\nimport ExportError from './errors/ExportError.js';\r\n\r\n// The global flag for the code execution permission\r\nlet allowCodeExecution = false;\r\n\r\n/**\r\n * Starts a single export process based on the specified options and saves\r\n * the resulting image to the provided output file.\r\n *\r\n * @async\r\n * @function singleExport\r\n *\r\n * @param {Object} options - The `options` object, which should include settings\r\n * from the `export` and `customLogic` sections. It can be a partial or complete\r\n * set of options from these sections. The object must contain at least one\r\n * of the following `export` properties: `infile`, `instr`, `options`, or `svg`\r\n * to generate a valid image.\r\n *\r\n * @returns {Promise} A Promise that resolves once the single export\r\n * process is completed.\r\n *\r\n * @throws {ExportError} Throws an `ExportError` if an error occurs during\r\n * the single export process.\r\n */\r\nexport async function singleExport(options) {\r\n // Check if the export makes sense\r\n if (options && options.export) {\r\n // Perform an export\r\n await startExport(\r\n { export: options.export, customLogic: options.customLogic },\r\n async (error, data) => {\r\n // Exit process when error exists\r\n if (error) {\r\n throw error;\r\n }\r\n\r\n // Get the `b64`, `outfile`, and `type` for a chart\r\n const { b64, outfile, type } = data.options.export;\r\n\r\n // Save the result\r\n try {\r\n if (b64) {\r\n // As a Base64 string to a txt file\r\n writeFileSync(\r\n `${outfile.split('.').shift() || 'chart'}.txt`,\r\n getBase64(data.result, type)\r\n );\r\n } else {\r\n // As a correct image format\r\n writeFileSync(\r\n outfile || `chart.${type}`,\r\n type !== 'svg' ? Buffer.from(data.result, 'base64') : data.result\r\n );\r\n }\r\n } catch (error) {\r\n throw new ExportError(\r\n '[chart] Error while saving a chart.',\r\n 500\r\n ).setError(error);\r\n }\r\n\r\n // Kill pool and close browser after finishing single export\r\n await killPool();\r\n }\r\n );\r\n } else {\r\n throw new ExportError(\r\n '[chart] No expected `export` options were found. Please provide one of the following options: `infile`, `instr`, `options`, or `svg` to generate a valid image.',\r\n 400\r\n );\r\n }\r\n}\r\n\r\n/**\r\n * Starts a batch export process for multiple charts based on information\r\n * provided in the `batch` option. The `batch` is a string in the following\r\n * format: \"infile1.json=outfile1.png;infile2.json=outfile2.png;...\". Results\r\n * are saved to the specified output files.\r\n *\r\n * @async\r\n * @function batchExport\r\n *\r\n * @param {Object} options - The `options` object, which should include settings\r\n * from the `export` and `customLogic` sections. It can be a partial or complete\r\n * set of options from these sections. It must contain the `batch` option from\r\n * the `export` section to generate valid images.\r\n *\r\n * @returns {Promise} A Promise that resolves once the batch export\r\n * processes are completed.\r\n *\r\n * @throws {ExportError} Throws an `ExportError` if an error occurs during\r\n * any of the batch export process.\r\n */\r\nexport async function batchExport(options) {\r\n // Check if the export makes sense\r\n if (options && options.export && options.export.batch) {\r\n // An array for collecting batch exports\r\n const batchFunctions = [];\r\n\r\n // Split and pair the `batch` arguments\r\n for (let pair of options.export.batch.split(';') || []) {\r\n pair = pair.split('=');\r\n if (pair.length === 2) {\r\n batchFunctions.push(\r\n startExport(\r\n {\r\n export: {\r\n ...options.export,\r\n infile: pair[0],\r\n outfile: pair[1]\r\n },\r\n customLogic: options.customLogic\r\n },\r\n (error, data) => {\r\n // Exit process when error exists\r\n if (error) {\r\n throw error;\r\n }\r\n\r\n // Get the `b64`, `outfile`, and `type` for a chart\r\n const { b64, outfile, type } = data.options.export;\r\n\r\n // Save the result\r\n try {\r\n if (b64) {\r\n // As a Base64 string to a txt file\r\n writeFileSync(\r\n `${outfile.split('.').shift() || 'chart'}.txt`,\r\n getBase64(data.result, type)\r\n );\r\n } else {\r\n // As a correct image format\r\n writeFileSync(\r\n outfile,\r\n type !== 'svg'\r\n ? Buffer.from(data.result, 'base64')\r\n : data.result\r\n );\r\n }\r\n } catch (error) {\r\n throw new ExportError(\r\n '[chart] Error while saving a chart.',\r\n 500\r\n ).setError(error);\r\n }\r\n }\r\n )\r\n );\r\n } else {\r\n log(2, '[chart] No correct pair found for the batch export.');\r\n }\r\n }\r\n\r\n // Await all exports are done\r\n const batchResults = await Promise.allSettled(batchFunctions);\r\n\r\n // Kill pool and close browser after finishing batch export\r\n await killPool();\r\n\r\n // Log errors if found\r\n batchResults.forEach((result, index) => {\r\n // Log the error with stack about the specific batch export\r\n if (result.reason) {\r\n logWithStack(\r\n 1,\r\n result.reason,\r\n `[chart] Batch export number ${index + 1} could not be correctly completed.`\r\n );\r\n }\r\n });\r\n } else {\r\n throw new ExportError(\r\n '[chart] No expected `export` options were found. Please provide the `batch` option to generate valid images.',\r\n 400\r\n );\r\n }\r\n}\r\n\r\n/**\r\n * Starts an export process. The `imageOptions` parameter is an object that\r\n * should include settings from the `export` and `customLogic` sections. It can\r\n * be a partial or complete set of options from these sections. If partial\r\n * options are provided, missing values will be merged with the current global\r\n * options.\r\n *\r\n * The `endCallback` function is invoked upon the completion of the export,\r\n * either successfully or with an error. The `error` object is provided\r\n * as the first argument, and the `data` object is the second, containing\r\n * the Base64 representation of the chart in the `result` property\r\n * and the complete set of options in the `options` property.\r\n *\r\n * @async\r\n * @function startExport\r\n *\r\n * @param {Object} imageOptions - The `imageOptions` object, which should\r\n * include settings from the `export` and `customLogic` sections. It can\r\n * be a partial or complete set of options from these sections. If the provided\r\n * options are partial, missing values will be merged with the current global\r\n * options.\r\n * @param {Function} endCallback - The callback function to be invoked upon\r\n * finalizing the export process or upon encountering an error. The first\r\n * argument is the `error` object, and the second argument is the `data` object,\r\n * which includes the Base64 representation of the chart in the `result`\r\n * property and the full set of options in the `options` property.\r\n *\r\n * @returns {Promise} This function does not return a value directly.\r\n * Instead, it communicates results via the `endCallback`.\r\n *\r\n * @throws {ExportError} Throws an `ExportError` if there is a problem with\r\n * processing input of any type. The error is passed into the `endCallback`\r\n * function and processed there.\r\n */\r\nexport async function startExport(imageOptions, endCallback) {\r\n try {\r\n // Check if provided options are in an object\r\n if (!isObject(imageOptions)) {\r\n throw new ExportError(\r\n '[chart] Incorrect value of the provided `imageOptions`. Needs to be an object.',\r\n 400\r\n );\r\n }\r\n\r\n // Merge additional options to the copy of the instance options\r\n const options = updateOptions(\r\n {\r\n export: imageOptions.export,\r\n customLogic: imageOptions.customLogic\r\n },\r\n true\r\n );\r\n\r\n // Get the `export` options\r\n const exportOptions = options.export;\r\n\r\n // Starting exporting process message\r\n log(4, '[chart] Starting the exporting process.');\r\n\r\n // Export using options from the file as an input\r\n if (exportOptions.infile !== null) {\r\n log(4, '[chart] Attempting to export from a file input.');\r\n\r\n let fileContent;\r\n try {\r\n // Try to read the file to get the string representation\r\n fileContent = readFileSync(\r\n getAbsolutePath(exportOptions.infile),\r\n 'utf8'\r\n );\r\n } catch (error) {\r\n throw new ExportError(\r\n '[chart] Error loading content from a file input.',\r\n 400\r\n ).setError(error);\r\n }\r\n\r\n // Check the file's extension\r\n if (exportOptions.infile.endsWith('.svg')) {\r\n // Set to the `svg` option\r\n exportOptions.svg = validateOption('svg', fileContent);\r\n } else if (exportOptions.infile.endsWith('.json')) {\r\n // Set to the `instr` option\r\n exportOptions.instr = validateOption('instr', fileContent);\r\n } else {\r\n throw new ExportError(\r\n '[chart] Incorrect value of the `infile` option.',\r\n 400\r\n );\r\n }\r\n }\r\n\r\n // Export using SVG as an input\r\n if (exportOptions.svg !== null) {\r\n log(4, '[chart] Attempting to export from an SVG input.');\r\n\r\n // SVG exports attempts counter\r\n ++getPoolStats().exportsFromSvgAttempts;\r\n\r\n // Export from an SVG string\r\n const result = await _exportFromSvg(\r\n sanitize(exportOptions.svg), // #209\r\n options\r\n );\r\n\r\n // SVG exports counter\r\n ++getPoolStats().exportsFromSvg;\r\n\r\n // Pass SVG export result to the end callback\r\n return endCallback(null, result);\r\n }\r\n\r\n // Export using options as an input\r\n if (exportOptions.instr !== null || exportOptions.options !== null) {\r\n log(4, '[chart] Attempting to export from options input.');\r\n\r\n // Options exports attempts counter\r\n ++getPoolStats().exportsFromOptionsAttempts;\r\n\r\n // Export from options\r\n const result = await _exportFromOptions(\r\n exportOptions.instr || exportOptions.options,\r\n options\r\n );\r\n\r\n // Options exports counter\r\n ++getPoolStats().exportsFromOptions;\r\n\r\n // Pass options export result to the end callback\r\n return endCallback(null, result);\r\n }\r\n\r\n // No input specified, pass an error message to the callback\r\n return endCallback(\r\n new ExportError(\r\n `[chart] No valid input specified. Check if at least one of the following parameters is correctly set: 'infile', 'instr', 'options', or 'svg'.`,\r\n 400\r\n )\r\n );\r\n } catch (error) {\r\n return endCallback(error);\r\n }\r\n}\r\n\r\n/**\r\n * Retrieves and returns the current status of the code execution permission.\r\n *\r\n * @function getAllowCodeExecution\r\n *\r\n * @returns {boolean} The value of the global `allowCodeExecution` option.\r\n */\r\nexport function getAllowCodeExecution() {\r\n return allowCodeExecution;\r\n}\r\n\r\n/**\r\n * Sets the code execution permission based on the provided boolean value.\r\n *\r\n * @function setAllowCodeExecution\r\n *\r\n * @param {boolean} value - The boolean value to be assigned to the global\r\n * `allowCodeExecution` option.\r\n */\r\nexport function setAllowCodeExecution(value) {\r\n allowCodeExecution = value;\r\n}\r\n\r\n/**\r\n * Exports from an SVG based input with the provided options.\r\n *\r\n * @async\r\n * @function _exportFromSvg\r\n *\r\n * @param {string} inputToExport - The SVG based input to be exported.\r\n * @param {Object} options - The configuration object containing complete set\r\n * of options.\r\n *\r\n * @returns {Promise} A Promise that resolves to a result of the export\r\n * process.\r\n *\r\n * @throws {ExportError} Throws an `ExportError` if there is not a correct SVG\r\n * input.\r\n */\r\nasync function _exportFromSvg(inputToExport, options) {\r\n // Check if it is SVG\r\n if (\r\n typeof inputToExport === 'string' &&\r\n (inputToExport.indexOf('= 0 || inputToExport.indexOf('= 0)\r\n ) {\r\n log(4, '[chart] Parsing input as SVG.');\r\n\r\n // Set the export input as SVG\r\n options.export.svg = inputToExport;\r\n\r\n // Reset the rest of the export input options\r\n options.export.instr = null;\r\n options.export.options = null;\r\n\r\n // Call the function with an SVG string as an export input\r\n return _prepareExport(options);\r\n } else {\r\n throw new ExportError('[chart] Not a correct SVG input.', 400);\r\n }\r\n}\r\n\r\n/**\r\n * Exports from an options based input with the provided options.\r\n *\r\n * @async\r\n * @function _exportFromOptions\r\n *\r\n * @param {string} inputToExport - The options based input to be exported.\r\n * @param {Object} options - The configuration object containing complete set\r\n * of options.\r\n *\r\n * @returns {Promise} A Promise that resolves to a result of the export\r\n * process.\r\n *\r\n * @throws {ExportError} Throws an `ExportError` if there is not a correct\r\n * chart options input.\r\n */\r\nasync function _exportFromOptions(inputToExport, options) {\r\n log(4, '[chart] Parsing input from options.');\r\n\r\n // Try to check, validate and parse to stringified options\r\n const stringifiedOptions = isAllowedConfig(\r\n inputToExport,\r\n true,\r\n options.customLogic.allowCodeExecution\r\n );\r\n\r\n // Check if a correct stringified options\r\n if (\r\n stringifiedOptions === null ||\r\n typeof stringifiedOptions !== 'string' ||\r\n !stringifiedOptions.startsWith('{') ||\r\n !stringifiedOptions.endsWith('}')\r\n ) {\r\n throw new ExportError(\r\n '[chart] Invalid configuration provided - Only options configurations and SVG are allowed for this server. If this is your server, JavaScript custom code can be enabled by starting the server with the `allowCodeExecution` options set to true.',\r\n 403\r\n );\r\n }\r\n\r\n // Set the export input as a stringified chart options\r\n options.export.instr = stringifiedOptions;\r\n\r\n // Reset the rest of the export input options\r\n options.export.svg = null;\r\n\r\n // Call the function with a stringified chart options\r\n return _prepareExport(options);\r\n}\r\n\r\n/**\r\n * Function for finalizing options and configurations before export.\r\n *\r\n * @async\r\n * @function _prepareExport\r\n *\r\n * @param {Object} options - The configuration object containing complete set\r\n * of options.\r\n *\r\n * @returns {Promise} A Promise that resolves to a result of the export\r\n * process.\r\n */\r\nasync function _prepareExport(options) {\r\n const { export: exportOptions, customLogic: customLogicOptions } = options;\r\n\r\n // Prepare the `type` option\r\n exportOptions.type = fixType(exportOptions.type, exportOptions.outfile);\r\n\r\n // Prepare the `outfile` option\r\n exportOptions.outfile = fixOutfile(exportOptions.type, exportOptions.outfile);\r\n\r\n // Prepare the `constr` option\r\n exportOptions.constr = fixConstr(exportOptions.constr);\r\n\r\n // Notify about the custom logic usage status\r\n log(\r\n 3,\r\n `[chart] The custom logic is ${customLogicOptions.allowCodeExecution ? 'allowed' : 'disallowed'}.`\r\n );\r\n\r\n // Prepare the custom logic options (`customCode`, `callback`, `resources`)\r\n _handleCustomLogic(customLogicOptions, customLogicOptions.allowCodeExecution);\r\n\r\n // Prepare the `globalOptions` and `themeOptions` options\r\n _handleGlobalAndTheme(\r\n exportOptions,\r\n customLogicOptions.allowFileResources,\r\n customLogicOptions.allowCodeExecution\r\n );\r\n\r\n // Prepare the `height`, `width`, and `scale` options\r\n options.export = {\r\n ...exportOptions,\r\n ..._findChartSize(exportOptions)\r\n };\r\n\r\n // Post the work to the pool\r\n return postWork(options);\r\n}\r\n\r\n/**\r\n * Calculates the `height`, `width` and `scale` for chart exports based\r\n * on the provided export options.\r\n *\r\n * The function prioritizes values in the following order:\r\n * 1. The `height`, `width`, `scale` from the `exportOptions`.\r\n * 2. Options from the chart configuration (from `exporting` and `chart`).\r\n * 3. Options from the global options (from `exporting` and `chart`).\r\n * 4. Options from the theme options (from `exporting` and `chart` sections).\r\n * 5. Fallback default values (`height = 400`, `width = 600`, `scale = 1`).\r\n *\r\n * @function _findChartSize\r\n *\r\n * @param {Object} exportOptions - The configuration object containing `export`\r\n * options.\r\n *\r\n * @returns {Object} The object containing calculated `height`, `width`\r\n * and `scale` values for the chart export.\r\n */\r\nfunction _findChartSize(exportOptions) {\r\n // Check the `options` and `instr` for chart and exporting sections\r\n const { chart: optionsChart, exporting: optionsExporting } =\r\n exportOptions.options || isAllowedConfig(exportOptions.instr) || false;\r\n\r\n // Check the `globalOptions` for chart and exporting sections\r\n const { chart: globalOptionsChart, exporting: globalOptionsExporting } =\r\n isAllowedConfig(exportOptions.globalOptions) || false;\r\n\r\n // Check the `themeOptions` for chart and exporting sections\r\n const { chart: themeOptionsChart, exporting: themeOptionsExporting } =\r\n isAllowedConfig(exportOptions.themeOptions) || false;\r\n\r\n // Find the `scale` value:\r\n // - It cannot be lower than 0.1\r\n // - It cannot be higher than 5.0\r\n // - It must be rounded to 2 decimal places (e.g. 0.23234 -> 0.23)\r\n const scale = roundNumber(\r\n Math.max(\r\n 0.1,\r\n Math.min(\r\n exportOptions.scale ||\r\n optionsExporting?.scale ||\r\n globalOptionsExporting?.scale ||\r\n themeOptionsExporting?.scale ||\r\n exportOptions.defaultScale ||\r\n 1,\r\n 5.0\r\n )\r\n ),\r\n 2\r\n );\r\n\r\n // Find the `height` value\r\n const height =\r\n exportOptions.height ||\r\n optionsExporting?.sourceHeight ||\r\n optionsChart?.height ||\r\n globalOptionsExporting?.sourceHeight ||\r\n globalOptionsChart?.height ||\r\n themeOptionsExporting?.sourceHeight ||\r\n themeOptionsChart?.height ||\r\n exportOptions.defaultHeight ||\r\n 400;\r\n\r\n // Find the `width` value\r\n const width =\r\n exportOptions.width ||\r\n optionsExporting?.sourceWidth ||\r\n optionsChart?.width ||\r\n globalOptionsExporting?.sourceWidth ||\r\n globalOptionsChart?.width ||\r\n themeOptionsExporting?.sourceWidth ||\r\n themeOptionsChart?.width ||\r\n exportOptions.defaultWidth ||\r\n 600;\r\n\r\n // Gather `height`, `width` and `scale` information in one object\r\n const size = { height, width, scale };\r\n\r\n // Get rid of potential `px` and `%`\r\n for (let [param, value] of Object.entries(size)) {\r\n size[param] =\r\n typeof value === 'string' ? +value.replace(/px|%/gi, '') : value;\r\n }\r\n\r\n // Return the size object\r\n return size;\r\n}\r\n\r\n/**\r\n * Handles the execution of custom logic options, including loading `resources`,\r\n * `customCode`, and `callback`. If code execution is allowed, it processes\r\n * the custom logic options accordingly. If code execution is not allowed,\r\n * it disables the usage of resources, custom code and callback.\r\n *\r\n * @function _handleCustomLogic\r\n *\r\n * @param {Object} customLogicOptions - The configuration object containing\r\n * `customLogic` options.\r\n * @param {boolean} allowCodeExecution - A flag indicating whether code\r\n * execution is allowed.\r\n *\r\n * @throws {ExportError} Throws an `ExportError` if code execution\r\n * is not allowed but custom logic options are still provided.\r\n */\r\nfunction _handleCustomLogic(customLogicOptions, allowCodeExecution) {\r\n // In case of allowing code execution\r\n if (allowCodeExecution) {\r\n // Process the `resources` option\r\n if (typeof customLogicOptions.resources === 'string') {\r\n // Custom stringified resources\r\n customLogicOptions.resources = _handleResources(\r\n customLogicOptions.resources,\r\n customLogicOptions.allowFileResources,\r\n true\r\n );\r\n } else if (!customLogicOptions.resources) {\r\n try {\r\n // Load the default one\r\n customLogicOptions.resources = _handleResources(\r\n readFileSync(getAbsolutePath('resources.json'), 'utf8'),\r\n customLogicOptions.allowFileResources,\r\n true\r\n );\r\n } catch (error) {\r\n log(2, '[chart] Unable to load the default `resources.json` file.');\r\n }\r\n }\r\n\r\n // Process the `customCode` option\r\n try {\r\n // Try to load custom code and wrap around it in a self invoking function\r\n customLogicOptions.customCode = wrapAround(\r\n customLogicOptions.customCode,\r\n customLogicOptions.allowFileResources\r\n );\r\n\r\n // Validate the option\r\n customLogicOptions.customCode = validateOption(\r\n 'customCode',\r\n customLogicOptions.customCode\r\n );\r\n } catch (error) {\r\n logWithStack(2, error, '[chart] The `customCode` cannot be loaded.');\r\n\r\n // In case of an error, set the option with null\r\n customLogicOptions.customCode = null;\r\n }\r\n\r\n // Process the `callback` option\r\n try {\r\n // Try to load callback function\r\n customLogicOptions.callback = wrapAround(\r\n customLogicOptions.callback,\r\n customLogicOptions.allowFileResources,\r\n true\r\n );\r\n\r\n // Validate the option\r\n customLogicOptions.callback = validateOption(\r\n 'callback',\r\n customLogicOptions.callback\r\n );\r\n } catch (error) {\r\n logWithStack(2, error, '[chart] The `callback` cannot be loaded.');\r\n\r\n // In case of an error, set the option with null\r\n customLogicOptions.callback = null;\r\n }\r\n\r\n // Check if there is the `customCode` present\r\n if ([null, undefined].includes(customLogicOptions.customCode)) {\r\n log(3, '[chart] No value for the `customCode` option found.');\r\n }\r\n\r\n // Check if there is the `callback` present\r\n if ([null, undefined].includes(customLogicOptions.callback)) {\r\n log(3, '[chart] No value for the `callback` option found.');\r\n }\r\n\r\n // Check if there is the `resources` present\r\n if ([null, undefined].includes(customLogicOptions.resources)) {\r\n log(3, '[chart] No value for the `resources` option found.');\r\n }\r\n } else {\r\n // If the `allowCodeExecution` flag is set to false, we should refuse\r\n // the usage of the `callback`, `resources`, and `customCode` options.\r\n // Additionally, the worker will refuse to run arbitrary JavaScript.\r\n if (\r\n customLogicOptions.callback ||\r\n customLogicOptions.resources ||\r\n customLogicOptions.customCode\r\n ) {\r\n // Reset all custom code options\r\n customLogicOptions.callback = null;\r\n customLogicOptions.resources = null;\r\n customLogicOptions.customCode = null;\r\n\r\n // Send a message saying that the exporter does not support these settings\r\n throw new ExportError(\r\n `[chart] The 'callback', 'resources', and 'customCode' options have been disabled for this server.`,\r\n 403\r\n );\r\n }\r\n }\r\n}\r\n\r\n/**\r\n * Handles and validates resources from the `resources` option for export.\r\n *\r\n * @function _handleResources\r\n *\r\n * @param {(Object|string|null)} [resources=null] - The resources to be handled.\r\n * Can be either a JSON object, stringified JSON, a path to a JSON file,\r\n * or null. The default value is `null`.\r\n * @param {boolean} allowFileResources - A flag indicating whether loading\r\n * resources from files is allowed.\r\n * @param {boolean} allowCodeExecution - A flag indicating whether code\r\n * execution is allowed.\r\n *\r\n * @returns {(Object|null)} The handled resources or null if no valid resources\r\n * are found.\r\n */\r\nfunction _handleResources(\r\n resources = null,\r\n allowFileResources,\r\n allowCodeExecution\r\n) {\r\n // List of allowed sections in the resources JSON\r\n const allowedProps = ['js', 'css', 'files'];\r\n\r\n let handledResources = resources;\r\n let correctResources = false;\r\n\r\n // Try to load resources from a file\r\n if (allowFileResources && resources.endsWith('.json')) {\r\n try {\r\n handledResources = isAllowedConfig(\r\n readFileSync(getAbsolutePath(resources), 'utf8'),\r\n false,\r\n allowCodeExecution\r\n );\r\n } catch {\r\n return null;\r\n }\r\n } else {\r\n // Try to get JSON\r\n handledResources = isAllowedConfig(resources, false, allowCodeExecution);\r\n\r\n // Get rid of the files section\r\n if (handledResources && !allowFileResources) {\r\n delete handledResources.files;\r\n }\r\n }\r\n\r\n // Filter from unnecessary properties\r\n for (const propName in handledResources) {\r\n if (!allowedProps.includes(propName)) {\r\n delete handledResources[propName];\r\n } else if (!correctResources) {\r\n correctResources = true;\r\n }\r\n }\r\n\r\n // Check if at least one of allowed properties is present\r\n if (!correctResources) {\r\n return null;\r\n }\r\n\r\n // Handle files section\r\n if (handledResources.files) {\r\n handledResources.files = handledResources.files.map((item) => item.trim());\r\n if (!handledResources.files || handledResources.files.length <= 0) {\r\n delete handledResources.files;\r\n }\r\n }\r\n\r\n // Validate option\r\n handledResources = validateOption('resources', handledResources);\r\n\r\n // Return resources\r\n return handledResources;\r\n}\r\n\r\n/**\r\n * Handles the loading and validation of the `globalOptions` and `themeOptions`\r\n * in the export options. If the option is a string and references a JSON file\r\n * (when the `allowFileResources` is true), it reads and parses the file.\r\n * Otherwise, it attempts to parse the string or object as JSON. If any errors\r\n * occur during this process, the option is set to null. If there is an error\r\n * loading or parsing the `globalOptions` or `themeOptions`, the error is logged\r\n * and the option is set to null.\r\n *\r\n * @function _handleGlobalAndTheme\r\n *\r\n * @param {Object} exportOptions - The configuration object containing `export`\r\n * options.\r\n * @param {boolean} allowFileResources - A flag indicating whether loading\r\n * resources from files is allowed.\r\n * @param {boolean} allowCodeExecution - A flag indicating whether code\r\n * execution is allowed.\r\n */\r\nfunction _handleGlobalAndTheme(\r\n exportOptions,\r\n allowFileResources,\r\n allowCodeExecution\r\n) {\r\n // Check the `globalOptions` and `themeOptions` options\r\n ['globalOptions', 'themeOptions'].forEach((optionsName) => {\r\n try {\r\n // Check if the option exists\r\n if (exportOptions[optionsName]) {\r\n // Check if it is a string and a file name with the `.json` extension\r\n if (\r\n allowFileResources &&\r\n typeof exportOptions[optionsName] === 'string' &&\r\n exportOptions[optionsName].endsWith('.json')\r\n ) {\r\n // Check if the file content can be a config, and save it as a string\r\n exportOptions[optionsName] = isAllowedConfig(\r\n readFileSync(getAbsolutePath(exportOptions[optionsName]), 'utf8'),\r\n true,\r\n allowCodeExecution\r\n );\r\n } else {\r\n // Check if the value can be a config, and save it as a string\r\n exportOptions[optionsName] = isAllowedConfig(\r\n exportOptions[optionsName],\r\n true,\r\n allowCodeExecution\r\n );\r\n }\r\n\r\n // Validate the option\r\n exportOptions[optionsName] = validateOption(\r\n optionsName,\r\n exportOptions[optionsName]\r\n );\r\n }\r\n } catch (error) {\r\n logWithStack(\r\n 2,\r\n error,\r\n `[chart] The \\`${optionsName}\\` cannot be loaded.`\r\n );\r\n\r\n // In case of an error, set the option with null\r\n exportOptions[optionsName] = null;\r\n }\r\n });\r\n\r\n // Check if there is the `globalOptions` present\r\n if ([null, undefined].includes(exportOptions.globalOptions)) {\r\n log(3, '[chart] No value for the `globalOptions` option found.');\r\n }\r\n\r\n // Check if there is the `themeOptions` present\r\n if ([null, undefined].includes(exportOptions.themeOptions)) {\r\n log(3, '[chart] No value for the `themeOptions` option found.');\r\n }\r\n}\r\n\r\nexport default {\r\n singleExport,\r\n batchExport,\r\n startExport,\r\n getAllowCodeExecution,\r\n setAllowCodeExecution\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * @overview This module provides utility functions for managing intervals\r\n * and timeouts in a centralized manner. It maintains a registry of all active\r\n * timers and allows for their efficient cleanup when needed. This can be useful\r\n * in applications where proper resource management and clean shutdown of timers\r\n * are critical to avoid memory leaks or unintended behavior.\r\n */\r\n\r\nimport { log } from './logger.js';\r\n\r\n// Array that contains ids of all ongoing intervals and timeouts\r\nconst timerIds = [];\r\n\r\n/**\r\n * Adds id of the `setInterval` or `setTimeout` and to the `timerIds` array.\r\n *\r\n * @function addTimer\r\n *\r\n * @param {NodeJS.Timeout} id - Id of an interval or a timeout.\r\n */\r\nexport function addTimer(id) {\r\n timerIds.push(id);\r\n}\r\n\r\n/**\r\n * Clears all of ongoing intervals and timeouts by ids gathered\r\n * in the `timerIds` array.\r\n *\r\n * @function clearAllTimers\r\n */\r\nexport function clearAllTimers() {\r\n log(4, `[timer] Clearing all registered intervals and timeouts.`);\r\n for (const id of timerIds) {\r\n clearInterval(id);\r\n clearTimeout(id);\r\n }\r\n}\r\n\r\nexport default {\r\n addTimer,\r\n clearAllTimers\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * @overview Provides middleware functions for logging errors with stack traces\r\n * and handling error responses in an Express application.\r\n */\r\n\r\nimport { getOptions } from '../../config.js';\r\nimport { logWithStack } from '../../logger.js';\r\n\r\n/**\r\n * Middleware for logging errors with stack trace and handling error response.\r\n *\r\n * @function logErrorMiddleware\r\n *\r\n * @param {Error} error - The error object.\r\n * @param {Express.Request} request - The Express request object.\r\n * @param {Express.Response} response - The Express response object.\r\n * @param {Function} next - The next middleware function.\r\n *\r\n * @returns {undefined} The call to the next middleware function with\r\n * the passed error.\r\n */\r\nfunction logErrorMiddleware(error, request, response, next) {\r\n // Display the error with stack in a correct format\r\n logWithStack(1, error);\r\n\r\n // Delete the stack for the environment other than the development\r\n if (getOptions().other.nodeEnv !== 'development') {\r\n delete error.stack;\r\n }\r\n\r\n // Call the `returnErrorMiddleware` middleware\r\n return next(error);\r\n}\r\n\r\n/**\r\n * Middleware for returning error response.\r\n *\r\n * @function returnErrorMiddleware\r\n *\r\n * @param {Error} error - The error object.\r\n * @param {Express.Request} request - The Express request object.\r\n * @param {Express.Response} response - The Express response object.\r\n * @param {Function} next - The next middleware function.\r\n */\r\nfunction returnErrorMiddleware(error, request, response, next) {\r\n // Gather all requied information for the response\r\n const { message, stack } = error;\r\n\r\n // Use the error's status code or the default 400\r\n const statusCode = error.statusCode || 400;\r\n\r\n // Set and return response\r\n response.status(statusCode).json({ statusCode, message, stack });\r\n}\r\n\r\n/**\r\n * Adds the error middlewares to the passed express app instance.\r\n *\r\n * @param {Express} app - The Express app instance.\r\n */\r\nexport default function errorMiddleware(app) {\r\n // Add log error middleware\r\n app.use(logErrorMiddleware);\r\n\r\n // Add set status and return error middleware\r\n app.use(returnErrorMiddleware);\r\n}\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * @overview Provides middleware functions for configuring and enabling rate\r\n * limiting in an Express application.\r\n */\r\n\r\nimport rateLimit from 'express-rate-limit';\r\n\r\nimport { log } from '../../logger.js';\r\n\r\nimport ExportError from '../../errors/ExportError.js';\r\n\r\n/**\r\n * Middleware for enabling rate limiting on the specified Express app.\r\n *\r\n * @param {Express} app - The Express app instance.\r\n *\r\n * @param {Object} rateLimitingOptions - The configuration object containing\r\n * `rateLimiting` options.\r\n *\r\n * @throws {ExportError} Throws an `ExportError` if could not configure and set\r\n * the rate limiting options.\r\n */\r\nexport default function rateLimitingMiddleware(app, rateLimitingOptions) {\r\n try {\r\n // Check if the rate limiting is enabled and the app exists\r\n if (app && rateLimitingOptions.enable) {\r\n const message =\r\n 'Too many requests, you have been rate limited. Please try again later.';\r\n\r\n // Options for the rate limiter\r\n const rateOptions = {\r\n window: rateLimitingOptions.window || 1,\r\n maxRequests: rateLimitingOptions.maxRequests || 30,\r\n delay: rateLimitingOptions.delay || 0,\r\n trustProxy: rateLimitingOptions.trustProxy || false,\r\n skipKey: rateLimitingOptions.skipKey || null,\r\n skipToken: rateLimitingOptions.skipToken || null\r\n };\r\n\r\n // Set if behind a proxy\r\n if (rateOptions.trustProxy) {\r\n app.enable('trust proxy');\r\n }\r\n\r\n // Create a limiter\r\n const limiter = rateLimit({\r\n // Time frame for which requests are checked and remembered\r\n windowMs: rateOptions.window * 60 * 1000,\r\n // Limit each IP to 100 requests per `windowMs`\r\n limit: rateOptions.maxRequests,\r\n // Disable delaying, full speed until the max limit is reached\r\n delayMs: rateOptions.delay,\r\n handler: (request, response) => {\r\n response.format({\r\n json: () => {\r\n response.status(429).send({ message });\r\n },\r\n default: () => {\r\n response.status(429).send(message);\r\n }\r\n });\r\n },\r\n skip: (request) => {\r\n // Allow bypassing the limiter if a valid key/token has been sent\r\n if (\r\n rateOptions.skipKey !== null &&\r\n rateOptions.skipToken !== null &&\r\n request.query.key === rateOptions.skipKey &&\r\n request.query.access_token === rateOptions.skipToken\r\n ) {\r\n log(4, '[rate limiting] Skipping rate limiter.');\r\n return true;\r\n }\r\n return false;\r\n }\r\n });\r\n\r\n // Use a limiter as a middleware\r\n app.use(limiter);\r\n\r\n log(\r\n 3,\r\n `[rate limiting] Enabled rate limiting with ${rateOptions.maxRequests} requests per ${rateOptions.window} minute for each IP, trusting proxy: ${rateOptions.trustProxy}.`\r\n );\r\n }\r\n } catch (error) {\r\n throw new ExportError(\r\n '[rate limiting] Could not configure and set the rate limiting options.',\r\n 500\r\n ).setError(error);\r\n }\r\n}\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * @overview Provides middleware functions for validating incoming HTTP requests\r\n * in an Express application. This module ensures that requests contain\r\n * appropriate content types and valid request bodies, including proper JSON\r\n * structures and chart data for exports. It checks for potential issues such\r\n * as missing or malformed data, private range URLs in SVG payloads, and allows\r\n * for flexible options validation. The middleware logs detailed information\r\n * and handles errors related to incorrect payloads, chart data, and private URL\r\n * usage.\r\n */\r\n\r\nimport { v4 as uuid } from 'uuid';\r\n\r\nimport { getAllowCodeExecution } from '../../chart.js';\r\nimport { isAllowedConfig } from '../../config.js';\r\nimport { log } from '../../logger.js';\r\nimport { isObjectEmpty, isPrivateRangeUrlFound } from '../../utils.js';\r\n\r\nimport ExportError from '../../errors/ExportError.js';\r\n\r\n/**\r\n * Middleware for validating the content-type header.\r\n *\r\n * @function contentTypeMiddleware\r\n *\r\n * @param {Express.Request} request - The Express request object.\r\n * @param {Express.Response} response - The Express response object.\r\n * @param {Function} next - The next middleware function.\r\n *\r\n * @returns {undefined} The call to the next middleware function.\r\n *\r\n * @throws {ExportError} Throws an `ExportError` if the content-type\r\n * is not correct.\r\n */\r\nfunction contentTypeMiddleware(request, response, next) {\r\n try {\r\n // Get the content type header\r\n const contentType = request.headers['content-type'] || '';\r\n\r\n // Allow only JSON, URL-encoded and form data without files types of data\r\n if (\r\n !contentType.includes('application/json') &&\r\n !contentType.includes('application/x-www-form-urlencoded') &&\r\n !contentType.includes('multipart/form-data')\r\n ) {\r\n throw new ExportError(\r\n '[validation] Content-Type must be application/json, application/x-www-form-urlencoded, or multipart/form-data.',\r\n 415\r\n );\r\n }\r\n\r\n // Call the `requestBodyMiddleware` middleware\r\n return next();\r\n } catch (error) {\r\n return next(error);\r\n }\r\n}\r\n\r\n/**\r\n * Middleware for validating the request's body.\r\n *\r\n * @function requestBodyMiddleware\r\n *\r\n * @param {Express.Request} request - The Express request object.\r\n * @param {Express.Response} response - The Express response object.\r\n * @param {Function} next - The next middleware function.\r\n *\r\n * @returns {undefined} The call to the next middleware function.\r\n *\r\n * @throws {ExportError} Throws an `ExportError` if the body is not correct.\r\n * @throws {ExportError} Throws an `ExportError` if the chart data from the body\r\n * is not correct.\r\n * @throws {ExportError} Throws an `ExportError` in case of the private range\r\n * url error.\r\n */\r\nfunction requestBodyMiddleware(request, response, next) {\r\n try {\r\n // Get the request body\r\n const body = request.body;\r\n\r\n // Create a unique ID for a request\r\n const requestId = uuid();\r\n\r\n // Throw an error if there is no correct body\r\n if (!body || isObjectEmpty(body)) {\r\n log(\r\n 2,\r\n `[validation] Request [${requestId}] - The request from ${\r\n request.headers['x-forwarded-for'] || request.connection.remoteAddress\r\n } was incorrect. Received payload is empty.`\r\n );\r\n\r\n throw new ExportError(\r\n `[validation] Request [${requestId}] - The request body is required. Please ensure that your Content-Type header is correct. Accepted types are 'application/json' and 'multipart/form-data'.`,\r\n 400\r\n );\r\n }\r\n\r\n // Get the `allowCodeExecution` option for the server\r\n const allowCodeExecution = getAllowCodeExecution();\r\n\r\n // Find a correct chart options\r\n const instr = isAllowedConfig(\r\n // Use one of the below\r\n body.instr || body.options || body.infile || body.data,\r\n // Stringify options\r\n true,\r\n // Allow or disallow functions\r\n allowCodeExecution\r\n );\r\n\r\n // Throw an error if there is no correct chart data\r\n if (instr === null && !body.svg) {\r\n log(\r\n 2,\r\n `[validation] Request [${requestId}] - The request from ${\r\n request.headers['x-forwarded-for'] || request.connection.remoteAddress\r\n } was incorrect. Received payload is missing correct chart data for export: ${JSON.stringify(body)}.`\r\n );\r\n\r\n throw new ExportError(\r\n `Request [${requestId}] - [validation] No correct chart data found. Ensure that you are using either application/json or multipart/form-data headers. If sending JSON, make sure the chart data is in the 'infile', 'options', or 'data' attribute. If sending SVG, ensure it is in the 'svg' attribute.`,\r\n 400\r\n );\r\n }\r\n\r\n // Throw an error if test of xlink:href elements from payload's SVG fails\r\n if (body.svg && isPrivateRangeUrlFound(body.svg)) {\r\n throw new ExportError(\r\n `Request [${requestId}] - [validation] SVG potentially contain at least one forbidden URL in 'xlink:href' element. Please review the SVG content and ensure that all referenced URLs comply with security policies.`,\r\n 400\r\n );\r\n }\r\n\r\n // Get and pre-validate the options and store them in the request\r\n request.validatedOptions = {\r\n // Set the created ID as a `requestId` property in the options\r\n requestId,\r\n export: {\r\n instr,\r\n svg: body.svg,\r\n outfile:\r\n body.outfile ||\r\n `${request.params.filename || 'chart'}.${body.type || 'png'}`,\r\n type: body.type,\r\n constr: body.constr,\r\n b64: body.b64,\r\n noDownload: body.noDownload,\r\n height: body.height,\r\n width: body.width,\r\n scale: body.scale,\r\n globalOptions: isAllowedConfig(\r\n body.globalOptions,\r\n true,\r\n allowCodeExecution\r\n ),\r\n themeOptions: isAllowedConfig(\r\n body.themeOptions,\r\n true,\r\n allowCodeExecution\r\n )\r\n },\r\n customLogic: {\r\n allowCodeExecution,\r\n allowFileResources: false,\r\n customCode: body.customCode,\r\n callback: body.callback,\r\n resources: isAllowedConfig(body.resources, true, allowCodeExecution)\r\n }\r\n };\r\n\r\n // Call the next middleware\r\n return next();\r\n } catch (error) {\r\n return next(error);\r\n }\r\n}\r\n\r\n/**\r\n * Adds the validation middlewares to the passed express app instance.\r\n *\r\n * @param {Express} app - The Express app instance.\r\n */\r\nexport default function validationMiddleware(app) {\r\n // Add content type validation middleware\r\n app.post(['/', '/:filename'], contentTypeMiddleware);\r\n\r\n // Add request body request validation middleware\r\n app.post(['/', '/:filename'], requestBodyMiddleware);\r\n}\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * @overview Defines the export routes and logic for handling chart export\r\n * requests in an Express server. This module processes incoming requests\r\n * to export charts in various formats (e.g. JPEG, PNG, PDF, SVG). It integrates\r\n * with Highcharts' core functionalities and supports both immediate download\r\n * responses and Base64-encoded content returns. The code also features\r\n * benchmarking for performance monitoring.\r\n */\r\n\r\nimport { startExport } from '../../chart.js';\r\nimport { log } from '../../logger.js';\r\nimport { getBase64, measureTime } from '../../utils.js';\r\n\r\nimport ExportError from '../../errors/ExportError.js';\r\n\r\n// Reversed MIME types\r\nconst reversedMime = {\r\n png: 'image/png',\r\n jpeg: 'image/jpeg',\r\n gif: 'image/gif',\r\n pdf: 'application/pdf',\r\n svg: 'image/svg+xml'\r\n};\r\n\r\n/**\r\n * Handles the export requests from the client.\r\n *\r\n * @async\r\n * @function requestExport\r\n *\r\n * @param {Express.Request} request - The Express request object.\r\n * @param {Express.Response} response - The Express response object.\r\n * @param {Function} next - The next middleware function.\r\n *\r\n * @returns {Promise} A Promise that resolves once the export process\r\n * is complete.\r\n */\r\nasync function requestExport(request, response, next) {\r\n try {\r\n // Start counting time for a request\r\n const requestCounter = measureTime();\r\n\r\n // In case the connection is closed, force to abort further actions\r\n let connectionAborted = false;\r\n request.socket.on('close', (hadErrors) => {\r\n if (hadErrors) {\r\n connectionAborted = true;\r\n }\r\n });\r\n\r\n // Get the options previously validated in the validation middleware\r\n const requestOptions = request.validatedOptions;\r\n\r\n // Get the request id\r\n const requestId = requestOptions.requestId;\r\n\r\n // Info about an incoming request with correct data\r\n log(4, `[export] Request [${requestId}] - Got an incoming HTTP request.`);\r\n\r\n // Start the export process\r\n await startExport(requestOptions, (error, data) => {\r\n // Remove the close event from the socket\r\n request.socket.removeAllListeners('close');\r\n\r\n // If the connection was closed, do nothing\r\n if (connectionAborted) {\r\n log(\r\n 3,\r\n `[export] Request [${requestId}] - The client closed the connection before the chart finished processing.`\r\n );\r\n return;\r\n }\r\n\r\n // If error, log it and send it to the error middleware\r\n if (error) {\r\n throw error;\r\n }\r\n\r\n // If data is missing, log the message and send it to the error middleware\r\n if (!data || !data.result) {\r\n log(\r\n 2,\r\n `[export] Request [${requestId}] - Request from ${\r\n request.headers['x-forwarded-for'] ||\r\n request.connection.remoteAddress\r\n } was incorrect. Received result is ${data.result}.`\r\n );\r\n\r\n throw new ExportError(\r\n `[export] Request [${requestId}] - Unexpected return of the export result from the chart generation. Please check your request data.`,\r\n 400\r\n );\r\n }\r\n\r\n // Return the result in an appropriate format\r\n if (data.result) {\r\n log(\r\n 3,\r\n `[export] Request [${requestId}] - The whole exporting process took ${requestCounter()}ms.`\r\n );\r\n\r\n // Get the `type`, `b64`, `noDownload`, and `outfile` from options\r\n const { type, b64, noDownload, outfile } = data.options.export;\r\n\r\n // If only Base64 is required, return it\r\n if (b64) {\r\n return response.send(getBase64(data.result, type));\r\n }\r\n\r\n // Set correct content type\r\n response.header('Content-Type', reversedMime[type] || 'image/png');\r\n\r\n // Decide whether to download or not chart file\r\n if (!noDownload) {\r\n response.attachment(outfile);\r\n }\r\n\r\n // If SVG, return plain content, otherwise a b64 string from a buffer\r\n return type === 'svg'\r\n ? response.send(data.result)\r\n : response.send(Buffer.from(data.result, 'base64'));\r\n }\r\n });\r\n } catch (error) {\r\n return next(error);\r\n }\r\n}\r\n\r\n/**\r\n * Adds the `export` routes.\r\n *\r\n * @function exportRoutes\r\n *\r\n * @param {Express} app - The Express app instance.\r\n */\r\nexport default function exportRoutes(app) {\r\n /**\r\n * Adds the POST '/' - A route for handling POST requests at the root\r\n * endpoint.\r\n */\r\n app.post('/', requestExport);\r\n\r\n /**\r\n * Adds the POST '/:filename' - A route for handling POST requests with\r\n * a specified filename parameter.\r\n */\r\n app.post('/:filename', requestExport);\r\n}\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * @overview Defines an Express route for server health monitoring, including\r\n * uptime, success rates, and other server statistics.\r\n */\r\n\r\nimport { readFileSync } from 'fs';\r\nimport { join } from 'path';\r\n\r\nimport { getHighchartsVersion } from '../../cache.js';\r\nimport { log } from '../../logger.js';\r\nimport { getPoolInfoJSON, getPoolStats } from '../../pool.js';\r\nimport { addTimer } from '../../timer.js';\r\nimport { __dirname, getNewDateTime } from '../../utils.js';\r\n\r\n// Set the start date of the server\r\nconst serverStartTime = new Date();\r\n\r\n// Get the `package.json` content\r\nconst packageFile = JSON.parse(\r\n readFileSync(join(__dirname, 'package.json'), 'utf8')\r\n);\r\n\r\n// An array for success rate ratios\r\nconst successRates = [];\r\n\r\n// Record every minute\r\nconst recordInterval = 60 * 1000;\r\n\r\n// 30 minutes\r\nconst windowSize = 30;\r\n\r\n/**\r\n * Calculates moving average indicator based on the data from the `successRates`\r\n * array.\r\n *\r\n * @function _calculateMovingAverage\r\n *\r\n * @returns {number} A moving average for success ratio of the server exports.\r\n */\r\nfunction _calculateMovingAverage() {\r\n return successRates.reduce((a, b) => a + b, 0) / successRates.length;\r\n}\r\n\r\n/**\r\n * Starts the interval responsible for calculating current success rate ratio\r\n * and collects records to the `successRates` array.\r\n *\r\n * @function _startSuccessRate\r\n *\r\n * @returns {NodeJS.Timeout} Id of an interval.\r\n */\r\nfunction _startSuccessRate() {\r\n return setInterval(() => {\r\n const stats = getPoolStats();\r\n const successRatio =\r\n stats.exportsAttempted === 0\r\n ? 1\r\n : (stats.exportsPerformed / stats.exportsAttempted) * 100;\r\n\r\n successRates.push(successRatio);\r\n if (successRates.length > windowSize) {\r\n successRates.shift();\r\n }\r\n }, recordInterval);\r\n}\r\n\r\n/**\r\n * Adds the `health` routes.\r\n *\r\n * @function healthRoutes\r\n *\r\n * @param {Express} app - The Express app instance.\r\n */\r\nexport default function healthRoutes(app) {\r\n // Start processing success rate ratio interval and save its id to the array\r\n // for the graceful clearing on shutdown with injected `addTimer` funtion\r\n addTimer(_startSuccessRate());\r\n\r\n /**\r\n * Adds the GET '/health' - A route for getting the basic stats of the server.\r\n */\r\n app.get('/health', (request, response, next) => {\r\n try {\r\n log(4, '[health] Returning server health.');\r\n\r\n const stats = getPoolStats();\r\n const period = successRates.length;\r\n const movingAverage = _calculateMovingAverage();\r\n\r\n // Send the server's statistics\r\n response.send({\r\n // Status and times\r\n status: 'OK',\r\n bootTime: serverStartTime,\r\n uptime: `${Math.floor((getNewDateTime() - serverStartTime.getTime()) / 1000 / 60)} minutes`,\r\n\r\n // Versions\r\n serverVersion: packageFile.version,\r\n highchartsVersion: getHighchartsVersion(),\r\n\r\n // Exports\r\n averageExportTime: stats.timeSpentAverage,\r\n attemptedExports: stats.exportsAttempted,\r\n performedExports: stats.exportsPerformed,\r\n failedExports: stats.exportsDropped,\r\n sucessRatio: (stats.exportsPerformed / stats.exportsAttempted) * 100,\r\n\r\n // Pool\r\n pool: getPoolInfoJSON(),\r\n\r\n // Moving average\r\n period,\r\n movingAverage,\r\n message:\r\n isNaN(movingAverage) || !successRates.length\r\n ? 'Too early to report. No exports made yet. Please check back soon.'\r\n : `Last ${period} minutes had a success rate of ${movingAverage.toFixed(2)}%.`,\r\n\r\n // SVG and JSON exports\r\n svgExports: stats.exportsFromSvg,\r\n jsonExports: stats.exportsFromOptions,\r\n svgExportsAttempts: stats.exportsFromSvgAttempts,\r\n jsonExportsAttempts: stats.exportsFromOptionsAttempts\r\n });\r\n } catch (error) {\r\n return next(error);\r\n }\r\n });\r\n}\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * @overview Defines an Express route for serving the UI for the export server\r\n * when enabled.\r\n */\r\n\r\nimport { join } from 'path';\r\n\r\nimport { getOptions } from '../../config.js';\r\nimport { log } from '../../logger.js';\r\nimport { __dirname } from '../../utils.js';\r\n\r\n/**\r\n * Adds the `ui` routes.\r\n *\r\n * @function uiRoutes\r\n *\r\n * @param {Express} app - The Express app instance.\r\n */\r\nexport default function uiRoutes(app) {\r\n /**\r\n * Adds the GET '/' - A route for a UI when enabled on the export server.\r\n */\r\n app.get(getOptions().ui.route || '/', (request, response, next) => {\r\n try {\r\n log(4, '[ui] Returning UI for the export.');\r\n\r\n response.sendFile(join(__dirname, 'public', 'index.html'), {\r\n acceptRanges: false\r\n });\r\n } catch (error) {\r\n return next(error);\r\n }\r\n });\r\n}\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * @overview Defines an Express route for updating the Highcharts version\r\n * on the server, with authentication and validation.\r\n */\r\n\r\nimport { getHighchartsVersion, updateHighchartsVersion } from '../../cache.js';\r\nimport { log } from '../../logger.js';\r\nimport { envs } from '../../validation.js';\r\n\r\nimport ExportError from '../../errors/ExportError.js';\r\n\r\n/**\r\n * Adds the `version_change` routes.\r\n *\r\n * @function versionChangeRoutes\r\n *\r\n * @param {Express} app - The Express app instance.\r\n */\r\nexport default function versionChangeRoutes(app) {\r\n /**\r\n * Adds the POST '/version_change/:newVersion' - A route for changing\r\n * the Highcharts version on the server.\r\n */\r\n app.post('/version_change/:newVersion', async (request, response, next) => {\r\n try {\r\n log(4, '[version] Changing Highcharts version.');\r\n\r\n // Get the token directly from envs\r\n const adminToken = envs.HIGHCHARTS_ADMIN_TOKEN;\r\n\r\n // Check the existence of the token\r\n if (!adminToken || !adminToken.length) {\r\n throw new ExportError(\r\n '[version] The server is not configured to perform run-time version changes: HIGHCHARTS_ADMIN_TOKEN is not set.',\r\n 401\r\n );\r\n }\r\n\r\n // Get the token from the hc-auth header\r\n const token = request.get('hc-auth');\r\n\r\n // Check if the hc-auth header contain a correct token\r\n if (!token || token !== adminToken) {\r\n throw new ExportError(\r\n '[version] Invalid or missing token: Set the token in the hc-auth header.',\r\n 401\r\n );\r\n }\r\n\r\n // Compare versions\r\n const newVersion = request.params.newVersion;\r\n\r\n // When a correct value found\r\n if (newVersion) {\r\n try {\r\n // Update version\r\n await updateHighchartsVersion(newVersion);\r\n } catch (error) {\r\n throw new ExportError(\r\n `[version] Version change: ${error.message}`,\r\n 400\r\n ).setError(error);\r\n }\r\n\r\n // Success\r\n response.status(200).send({\r\n statusCode: 200,\r\n highchartsVersion: getHighchartsVersion(),\r\n message: `Successfully updated Highcharts to version: ${newVersion}.`\r\n });\r\n } else {\r\n // No version specified\r\n throw new ExportError('[version] No new version supplied.', 400);\r\n }\r\n } catch (error) {\r\n return next(error);\r\n }\r\n });\r\n}\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * @overview A module that sets up and manages HTTP and HTTPS servers\r\n * for the Highcharts Export Server. It handles server initialization,\r\n * configuration, error handling, middleware setup, route definition, and rate\r\n * limiting. The module exports functions to start, stop, and manage server\r\n * instances, as well as utility functions for defining routes and attaching\r\n * middlewares.\r\n */\r\n\r\nimport { readFileSync } from 'fs';\r\nimport { join } from 'path';\r\n\r\nimport cors from 'cors';\r\nimport express from 'express';\r\nimport http from 'http';\r\nimport https from 'https';\r\nimport multer from 'multer';\r\n\r\nimport { updateOptions } from '../config.js';\r\nimport { log, logWithStack } from '../logger.js';\r\nimport { __dirname, getAbsolutePath } from '../utils.js';\r\n\r\nimport errorMiddleware from './middlewares/error.js';\r\nimport rateLimitingMiddleware from './middlewares/rateLimiting.js';\r\nimport validationMiddleware from './middlewares/validation.js';\r\n\r\nimport exportRoutes from './routes/export.js';\r\nimport healthRoutes from './routes/health.js';\r\nimport uiRoutes from './routes/ui.js';\r\nimport versionChangeRoutes from './routes/versionChange.js';\r\n\r\nimport ExportError from '../errors/ExportError.js';\r\n\r\n// Array of an active servers\r\nconst activeServers = new Map();\r\n\r\n// Create express app\r\nconst app = express();\r\n\r\n/**\r\n * Starts an HTTP and/or HTTPS server based on the provided configuration.\r\n * The `serverOptions` object contains server-related properties (refer\r\n * to the `server` section in the `./lib/schemas/config.js` file for details).\r\n *\r\n * @async\r\n * @function startServer\r\n *\r\n * @param {Object} serverOptions - The configuration object containing `server`\r\n * options. This object may include a partial or complete set of the `server`\r\n * options. If the options are partial, missing values will default\r\n * to the current global configuration.\r\n *\r\n * @returns {Promise} A Promise that resolves when the server is either\r\n * not enabled or no valid Express app is found, signaling the end of the\r\n * function's execution.\r\n *\r\n * @throws {ExportError} Throws an `ExportError` if the server cannot\r\n * be configured and started.\r\n */\r\nexport async function startServer(serverOptions) {\r\n try {\r\n // Update the instance options object\r\n const options = updateOptions({\r\n server: serverOptions\r\n });\r\n\r\n // Use validated options\r\n serverOptions = options.server;\r\n\r\n // Stop if not enabled\r\n if (!serverOptions.enable || !app) {\r\n throw new ExportError(\r\n '[server] Server cannot be started (not enabled or no correct Express app found).',\r\n 500\r\n );\r\n }\r\n\r\n // Too big limits lead to timeouts in the export process when\r\n // the rasterization timeout is set too low\r\n const uploadLimitBytes = serverOptions.uploadLimit * 1024 * 1024;\r\n\r\n // Memory storage for multer package\r\n const storage = multer.memoryStorage();\r\n\r\n // Enable parsing of form data (files) with multer package\r\n const upload = multer({\r\n storage,\r\n limits: {\r\n fieldSize: uploadLimitBytes\r\n }\r\n });\r\n\r\n // Disable the X-Powered-By header\r\n app.disable('x-powered-by');\r\n\r\n // Enable CORS support\r\n app.use(\r\n cors({\r\n methods: ['POST', 'GET', 'OPTIONS']\r\n })\r\n );\r\n\r\n // Getting a lot of `RangeNotSatisfiableError` exceptions (even though this\r\n // is a deprecated options, let's try to set it to false)\r\n app.use((request, response, next) => {\r\n response.set('Accept-Ranges', 'none');\r\n next();\r\n });\r\n\r\n // Enable body parser for JSON data\r\n app.use(\r\n express.json({\r\n limit: uploadLimitBytes\r\n })\r\n );\r\n\r\n // Enable body parser for URL-encoded form data\r\n app.use(\r\n express.urlencoded({\r\n extended: true,\r\n limit: uploadLimitBytes\r\n })\r\n );\r\n\r\n // Use only non-file multipart form fields\r\n app.use(upload.none());\r\n\r\n // Set up static folder's route\r\n app.use(express.static(join(__dirname, 'public')));\r\n\r\n // Listen HTTP server\r\n if (!serverOptions.ssl.force) {\r\n // Main server instance (HTTP)\r\n const httpServer = http.createServer(app);\r\n\r\n // Attach error handlers and listen to the server\r\n _attachServerErrorHandlers(httpServer);\r\n\r\n // Listen\r\n httpServer.listen(serverOptions.port, serverOptions.host, () => {\r\n // Save the reference to HTTP server\r\n activeServers.set(serverOptions.port, httpServer);\r\n\r\n log(\r\n 3,\r\n `[server] Started HTTP server on ${serverOptions.host}:${serverOptions.port}.`\r\n );\r\n });\r\n }\r\n\r\n // Listen HTTPS server\r\n if (serverOptions.ssl.enable) {\r\n // Set up an SSL server also\r\n let key, cert;\r\n\r\n try {\r\n // Get the SSL key\r\n key = readFileSync(\r\n join(getAbsolutePath(serverOptions.ssl.certPath), 'server.key'),\r\n 'utf8'\r\n );\r\n\r\n // Get the SSL certificate\r\n cert = readFileSync(\r\n join(getAbsolutePath(serverOptions.ssl.certPath), 'server.crt'),\r\n 'utf8'\r\n );\r\n } catch (error) {\r\n log(\r\n 2,\r\n `[server] Unable to load key/certificate from the '${serverOptions.ssl.certPath}' path. Could not run secured layer server.`\r\n );\r\n }\r\n\r\n if (key && cert) {\r\n // Main server instance (HTTPS)\r\n const httpsServer = https.createServer({ key, cert }, app);\r\n\r\n // Attach error handlers and listen to the server\r\n _attachServerErrorHandlers(httpsServer);\r\n\r\n // Listen\r\n httpsServer.listen(serverOptions.ssl.port, serverOptions.host, () => {\r\n // Save the reference to HTTPS server\r\n activeServers.set(serverOptions.ssl.port, httpsServer);\r\n\r\n log(\r\n 3,\r\n `[server] Started HTTPS server on ${serverOptions.host}:${serverOptions.ssl.port}.`\r\n );\r\n });\r\n }\r\n }\r\n\r\n // Set up the rate limiter\r\n rateLimitingMiddleware(app, serverOptions.rateLimiting);\r\n\r\n // Set up the validation handler\r\n validationMiddleware(app);\r\n\r\n // Set up routes\r\n exportRoutes(app);\r\n healthRoutes(app);\r\n uiRoutes(app);\r\n versionChangeRoutes(app);\r\n\r\n // Set up the centralized error handler\r\n errorMiddleware(app);\r\n } catch (error) {\r\n throw new ExportError(\r\n '[server] Could not configure and start the server.',\r\n 500\r\n ).setError(error);\r\n }\r\n}\r\n\r\n/**\r\n * Closes all servers associated with Express app instance.\r\n *\r\n * @function closeServers\r\n */\r\nexport function closeServers() {\r\n // Check if there are servers working\r\n if (activeServers.size > 0) {\r\n log(4, `[server] Closing all servers.`);\r\n\r\n // Close each one of servers\r\n for (const [port, server] of activeServers) {\r\n server.close(() => {\r\n activeServers.delete(port);\r\n log(4, `[server] Closed server on port: ${port}.`);\r\n });\r\n }\r\n }\r\n}\r\n\r\n/**\r\n * Get all servers associated with Express app instance.\r\n *\r\n * @function getServers\r\n *\r\n * @returns {Array.} Servers associated with Express app instance.\r\n */\r\nexport function getServers() {\r\n return activeServers;\r\n}\r\n\r\n/**\r\n * Get the Express instance.\r\n *\r\n * @function getExpress\r\n *\r\n * @returns {Express} The Express instance.\r\n */\r\nexport function getExpress() {\r\n return express;\r\n}\r\n\r\n/**\r\n * Get the Express app instance.\r\n *\r\n * @function getApp\r\n *\r\n * @returns {Express} The Express app instance.\r\n */\r\nexport function getApp() {\r\n return app;\r\n}\r\n\r\n/**\r\n * Enable rate limiting for the server.\r\n *\r\n * @function enableRateLimiting\r\n *\r\n * @param {Object} rateLimitingOptions - The configuration object containing\r\n * `rateLimiting` options. This object may include a partial or complete set\r\n * of the `rateLimiting` options. If the options are partial, missing values\r\n * will default to the current global configuration.\r\n */\r\nexport function enableRateLimiting(rateLimitingOptions) {\r\n // Update the instance options object\r\n const options = updateOptions({\r\n server: {\r\n rateLimiting: rateLimitingOptions\r\n }\r\n });\r\n\r\n // Set the rate limiting options\r\n rateLimitingMiddleware(app, options.server.rateLimitingOptions);\r\n}\r\n\r\n/**\r\n * Apply middleware(s) to a specific path.\r\n *\r\n * @function use\r\n *\r\n * @param {string} path - The path to which the middleware(s) should be applied.\r\n * @param {...Function} middlewares - The middleware function(s) to be applied.\r\n */\r\nexport function use(path, ...middlewares) {\r\n app.use(path, ...middlewares);\r\n}\r\n\r\n/**\r\n * Set up a route with GET method and apply middleware(s).\r\n *\r\n * @function get\r\n *\r\n * @param {string} path - The path to which the middleware(s) should be applied.\r\n * @param {...Function} middlewares - The middleware function(s) to be applied.\r\n */\r\nexport function get(path, ...middlewares) {\r\n app.get(path, ...middlewares);\r\n}\r\n\r\n/**\r\n * Set up a route with POST method and apply middleware(s).\r\n *\r\n * @function post\r\n *\r\n * @param {string} path - The path to which the middleware(s) should be applied.\r\n * @param {...Function} middlewares - The middleware function(s) to be applied.\r\n */\r\nexport function post(path, ...middlewares) {\r\n app.post(path, ...middlewares);\r\n}\r\n\r\n/**\r\n * Attach error handlers to the server.\r\n *\r\n * @function _attachServerErrorHandlers\r\n *\r\n * @param {(http.Server|https.Server)} server - The HTTP/HTTPS server instance.\r\n */\r\nfunction _attachServerErrorHandlers(server) {\r\n server.on('clientError', (error, socket) => {\r\n logWithStack(\r\n 1,\r\n error,\r\n `[server] Client error: ${error.message}, destroying socket.`\r\n );\r\n socket.destroy();\r\n });\r\n\r\n server.on('error', (error) => {\r\n logWithStack(1, error, `[server] Server error: ${error.message}`);\r\n });\r\n\r\n server.on('connection', (socket) => {\r\n socket.on('error', (error) => {\r\n logWithStack(1, error, `[server] Socket error: ${error.message}`);\r\n });\r\n });\r\n}\r\n\r\nexport default {\r\n startServer,\r\n closeServers,\r\n getServers,\r\n getExpress,\r\n getApp,\r\n enableRateLimiting,\r\n use,\r\n get,\r\n post\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * @overview Handles graceful shutdown of the Highcharts Export Server, ensuring\r\n * proper cleanup of resources such as browser, pages, servers, and timers.\r\n */\r\n\r\nimport { killPool } from './pool.js';\r\nimport { clearAllTimers } from './timer.js';\r\n\r\nimport { closeServers } from './server/server.js';\r\n\r\n/**\r\n * Performs cleanup operations to ensure a graceful shutdown of the process.\r\n * This includes clearing all registered timeouts/intervals, closing active\r\n * servers, terminating resources (pages) of the pool, pool itself, and closing\r\n * the browser.\r\n *\r\n * @function shutdownCleanUp\r\n *\r\n * @param {number} [exitCode=0] - The exit code to use with `process.exit()`.\r\n * The default value is `0`.\r\n */\r\nexport async function shutdownCleanUp(exitCode = 0) {\r\n // Await freeing all resources\r\n await Promise.allSettled([\r\n // Clear all ongoing intervals\r\n clearAllTimers(),\r\n\r\n // Get available server instances (HTTP/HTTPS) and close them\r\n closeServers(),\r\n\r\n // Close an active pool along with its workers and the browser instance\r\n killPool()\r\n ]);\r\n\r\n // Exit process with a correct code\r\n process.exit(exitCode);\r\n}\r\n\r\nexport default {\r\n shutdownCleanUp\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * @overview Core module for initializing and managing the Highcharts Export\r\n * Server. Provides functionalities for configuring exports, setting up server\r\n * operations, logging, scripts caching, resource pooling, and graceful process\r\n * cleanup.\r\n */\r\n\r\nimport 'colors';\r\n\r\nimport { checkAndUpdateCache } from './cache.js';\r\nimport {\r\n singleExport,\r\n batchExport,\r\n startExport,\r\n setAllowCodeExecution\r\n} from './chart.js';\r\nimport {\r\n getOptions,\r\n updateOptions,\r\n mapToNewOptions,\r\n validateOption,\r\n validateOptions\r\n} from './config.js';\r\nimport {\r\n log,\r\n logWithStack,\r\n logZodIssues,\r\n initLogging,\r\n enableConsoleLogging,\r\n enableFileLogging,\r\n setLogLevel\r\n} from './logger.js';\r\nimport { initPool, killPool } from './pool.js';\r\nimport { shutdownCleanUp } from './resourceRelease.js';\r\n\r\nimport server from './server/server.js';\r\n\r\n/**\r\n * Initializes the export process. Tasks such as configuring logging, checking\r\n * the cache and sources, and initializing the resource pool occur during this\r\n * stage.\r\n *\r\n * This function must be called before attempting to export charts or set\r\n * up a server.\r\n *\r\n * @async\r\n * @function initExport\r\n *\r\n * @param {Object} initOptions - The `initOptions` object, which may\r\n * be a partial or complete set of options. If the options are partial, missing\r\n * values will default to the current global configuration.\r\n */\r\nexport async function initExport(initOptions) {\r\n // Init, validate and update the options object\r\n const options = updateOptions(initOptions);\r\n\r\n // Set the `allowCodeExecution` per export module scope\r\n setAllowCodeExecution(options.customLogic.allowCodeExecution);\r\n\r\n // Init the logging\r\n initLogging(options.logging);\r\n\r\n // Attach process' exit listeners\r\n if (options.other.listenToProcessExits) {\r\n _attachProcessExitListeners();\r\n }\r\n\r\n // Check if cache needs to be updated\r\n await checkAndUpdateCache(options.highcharts, options.server.proxy);\r\n\r\n // Init the pool\r\n await initPool(options.pool, options.puppeteer.args);\r\n}\r\n\r\n/**\r\n * Attaches exit listeners to the process, ensuring proper cleanup of resources\r\n * and termination on exit signals. Handles 'exit', 'SIGINT', 'SIGTERM'\r\n * and 'uncaughtException' events.\r\n *\r\n * @function _attachProcessExitListeners\r\n */\r\nfunction _attachProcessExitListeners() {\r\n log(3, '[process] Attaching exit listeners to the process.');\r\n\r\n // Handler for the 'exit'\r\n process.on('exit', (code) => {\r\n log(4, `[process] Process exited with code ${code}.`);\r\n });\r\n\r\n // Handler for the 'SIGINT'\r\n process.on('SIGINT', async (name, code) => {\r\n log(4, `[process] The ${name} event with code: ${code}.`);\r\n await shutdownCleanUp();\r\n });\r\n\r\n // Handler for the 'SIGTERM'\r\n process.on('SIGTERM', async (name, code) => {\r\n log(4, `[process] The ${name} event with code: ${code}.`);\r\n await shutdownCleanUp();\r\n });\r\n\r\n // Handler for the 'SIGHUP'\r\n process.on('SIGHUP', async (name, code) => {\r\n log(4, `[process] The ${name} event with code: ${code}.`);\r\n await shutdownCleanUp();\r\n });\r\n\r\n // Handler for the 'uncaughtException'\r\n process.on('uncaughtException', async (error, name) => {\r\n logWithStack(1, error, `[process] The ${name} error.`);\r\n await shutdownCleanUp(1);\r\n });\r\n}\r\n\r\nexport default {\r\n // Server\r\n ...server,\r\n\r\n // Options\r\n getOptions,\r\n updateOptions,\r\n mapToNewOptions,\r\n\r\n // Validation\r\n validateOption,\r\n validateOptions,\r\n\r\n // Exporting\r\n initExport,\r\n singleExport,\r\n batchExport,\r\n startExport,\r\n\r\n // Release\r\n killPool,\r\n shutdownCleanUp,\r\n\r\n // Logs\r\n log,\r\n logWithStack,\r\n logZodIssues,\r\n setLogLevel: function (level) {\r\n // Update the instance options object\r\n const options = updateOptions({\r\n logging: {\r\n level\r\n }\r\n });\r\n\r\n // Call the function\r\n setLogLevel(options.logging.level);\r\n },\r\n enableConsoleLogging: function (toConsole) {\r\n // Update the instance options object\r\n const options = updateOptions({\r\n logging: {\r\n toConsole\r\n }\r\n });\r\n\r\n // Call the function\r\n enableConsoleLogging(options.logging.toConsole);\r\n },\r\n enableFileLogging: function (dest, file, toFile) {\r\n // Update the instance options object\r\n const options = updateOptions({\r\n logging: {\r\n dest,\r\n file,\r\n toFile\r\n }\r\n });\r\n\r\n // Call the function\r\n enableFileLogging(\r\n options.logging.dest,\r\n options.logging.file,\r\n options.logging.toFile\r\n );\r\n }\r\n};\r\n"],"names":["__dirname","fileURLToPath","URL","url","deepCopy","objArr","objArrCopy","Array","isArray","key","Object","prototype","hasOwnProperty","call","fixConstr","constr","fixedConstr","toLowerCase","replace","includes","fixOutfile","type","outfile","getAbsolutePath","split","shift","fixType","mimeTypes","formats","values","outType","pop","find","t","path","isAbsolute","normalize","resolve","getBase64","input","Buffer","from","toString","getNewDate","Date","trim","getNewDateTime","getTime","isObject","item","isObjectEmpty","keys","length","isPrivateRangeUrlFound","some","pattern","test","measureTime","start","process","hrtime","bigint","Number","roundNumber","value","precision","multiplier","Math","pow","round","wrapAround","customCode","allowFileResources","isCallback","endsWith","readFileSync","startsWith","colors","logging","toConsole","toFile","pathCreated","pathToLog","levelsDesc","title","color","log","args","newLevel","texts","level","prefix","_logToFile","console","apply","undefined","concat","logWithStack","error","customMessage","mainMessage","message","stackMessage","stack","push","logZodIssues","issues","map","issue","join","initLogging","loggingOptions","dest","file","setLogLevel","enableConsoleLogging","enableFileLogging","isInteger","existsSync","mkdirSync","appendFile","defaultConfig","puppeteer","types","envLink","cliName","description","promptOptions","separator","highcharts","version","cdnUrl","forceFetch","cachePath","coreScripts","instructions","moduleScripts","indicatorScripts","customScripts","export","infile","instr","options","svg","batch","hint","choices","b64","noDownload","height","width","scale","defaultHeight","defaultWidth","defaultScale","min","max","globalOptions","themeOptions","rasterizationTimeout","customLogic","allowCodeExecution","callback","resources","loadConfig","legacyName","createConfig","server","enable","host","port","uploadLimit","benchmarking","proxy","timeout","rateLimiting","maxRequests","window","delay","trustProxy","skipKey","skipToken","ssl","force","certPath","pool","minWorkers","maxWorkers","workLimit","acquireTimeout","createTimeout","destroyTimeout","idleTimeout","createRetryInterval","reaperInterval","ui","route","other","nodeEnv","listenToProcessExits","noLogo","hardResetPage","browserShellMode","validation","debug","headless","devtools","listenToConsole","dumpio","slowMo","debuggingPort","nestedProps","_createNestedProps","absoluteProps","_createAbsoluteProps","config","propChain","forEach","entry","substring","dotenv","z","setErrorMap","_customErrorMap","v","boolean","strictCheck","union","enum","transform","nullable","string","refine","params","errorMessage","stringArray","filterCallback","arraySchema","array","stringSchema","slice","transformCallback","filter","positiveNum","number","positive","isNaN","nonNegativeNum","nonnegative","prefixes","chartConfig","object","passthrough","additionalOptions","validators","adminToken","indexOf","gte","lte","this","objectSchema","js","css","files","partial","stringSchema1","stringSchema2","enableServer","serverBenchmarking","proxyHost","proxyPort","proxyTimeout","enableRateLimiting","enableSsl","sslForce","sslPort","sslCertPath","poolBenchmarking","resourcesInterval","logLevel","int","logFile","logDest","logToConsole","logToFile","enableUi","uiRoute","enableDebug","requestId","uuid","PuppeteerSchema","HighchartsSchema","ExportSchema","CustomLogicSchema","ProxySchema","RateLimitingSchema","SslSchema","ServerSchema","optional","PoolSchema","LoggingSchema","UiSchema","OtherSchema","DebugSchema","StrictConfigSchema","LooseConfigSchema","EnvSchema","PUPPETEER_ARGS","HIGHCHARTS_VERSION","HIGHCHARTS_CDN_URL","HIGHCHARTS_FORCE_FETCH","HIGHCHARTS_CACHE_PATH","HIGHCHARTS_ADMIN_TOKEN","HIGHCHARTS_CORE_SCRIPTS","HIGHCHARTS_MODULE_SCRIPTS","HIGHCHARTS_INDICATOR_SCRIPTS","HIGHCHARTS_CUSTOM_SCRIPTS","EXPORT_INFILE","EXPORT_INSTR","EXPORT_OPTIONS","EXPORT_SVG","EXPORT_BATCH","EXPORT_OUTFILE","EXPORT_TYPE","EXPORT_CONSTR","EXPORT_B64","EXPORT_NO_DOWNLOAD","EXPORT_HEIGHT","EXPORT_WIDTH","EXPORT_SCALE","EXPORT_DEFAULT_HEIGHT","EXPORT_DEFAULT_WIDTH","EXPORT_DEFAULT_SCALE","EXPORT_GLOBAL_OPTIONS","EXPORT_THEME_OPTIONS","EXPORT_RASTERIZATION_TIMEOUT","CUSTOM_LOGIC_ALLOW_CODE_EXECUTION","CUSTOM_LOGIC_ALLOW_FILE_RESOURCES","CUSTOM_LOGIC_CUSTOM_CODE","CUSTOM_LOGIC_CALLBACK","CUSTOM_LOGIC_RESOURCES","CUSTOM_LOGIC_LOAD_CONFIG","CUSTOM_LOGIC_CREATE_CONFIG","SERVER_ENABLE","SERVER_HOST","SERVER_PORT","SERVER_UPLOAD_LIMIT","SERVER_BENCHMARKING","SERVER_PROXY_HOST","SERVER_PROXY_PORT","SERVER_PROXY_TIMEOUT","SERVER_RATE_LIMITING_ENABLE","SERVER_RATE_LIMITING_MAX_REQUESTS","SERVER_RATE_LIMITING_WINDOW","SERVER_RATE_LIMITING_DELAY","SERVER_RATE_LIMITING_TRUST_PROXY","SERVER_RATE_LIMITING_SKIP_KEY","SERVER_RATE_LIMITING_SKIP_TOKEN","SERVER_SSL_ENABLE","SERVER_SSL_FORCE","SERVER_SSL_PORT","SERVER_SSL_CERT_PATH","POOL_MIN_WORKERS","POOL_MAX_WORKERS","POOL_WORK_LIMIT","POOL_ACQUIRE_TIMEOUT","POOL_CREATE_TIMEOUT","POOL_DESTROY_TIMEOUT","POOL_IDLE_TIMEOUT","POOL_CREATE_RETRY_INTERVAL","POOL_REAPER_INTERVAL","POOL_BENCHMARKING","LOGGING_LEVEL","LOGGING_FILE","LOGGING_DEST","LOGGING_TO_CONSOLE","LOGGING_TO_FILE","UI_ENABLE","UI_ROUTE","OTHER_NODE_ENV","OTHER_LISTEN_TO_PROCESS_EXITS","OTHER_NO_LOGO","OTHER_HARD_RESET_PAGE","OTHER_BROWSER_SHELL_MODE","OTHER_VALIDATION","DEBUG_ENABLE","DEBUG_HEADLESS","DEBUG_DEVTOOLS","DEBUG_LISTEN_TO_CONSOLE","DEBUG_DUMPIO","DEBUG_SLOW_MO","DEBUG_DEBUGGING_PORT","envs","parse","env","strictValidate","configOptions","looseValidate","context","propertyName","propertyInfo","code","ZodIssueCode","invalid_type","received","ZodParsedType","defaultError","custom","data","invalid_union","unionErrors","index","ExportError","Error","constructor","statusCode","super","setStatus","setError","name","_initOptions","getOptions","getCopy","updateOptions","newOptions","_mergeOptions","validateOptions","mapToNewOptions","oldOptions","entries","propertiesChain","reduce","obj","prop","validateOption","configOption","isAllowedConfig","allowFunctions","objectConfig","eval","JSON","stringifiedOptions","_optionsStringify","parsedOptions","_","originalOptions","stringifyFunctions","stringify","replaceAll","async","fetch","requestOptions","Promise","reject","_getProtocolModule","get","response","responseData","on","chunk","text","https","http","cache","activeManifest","sources","hcVersion","checkAndUpdateCache","highchartsOptions","serverProxyOptions","fetchedModules","getCachePath","manifestPath","sourcePath","recursive","_updateCache","requestUpdate","manifest","modules","moduleMap","m","numberOfModules","moduleName","extractVersion","_saveConfigToManifest","getHighchartsVersion","updateHighchartsVersion","newVersion","cacheSources","extractModuleName","scriptPath","_fetchAndProcessScript","script","shouldThrowError","newManifest","writeFileSync","_fetchScripts","proxyAgent","HttpsProxyAgent","agent","allFetchPromises","all","c","i","setupHighcharts","Highcharts","animObject","duration","createChart","exportOptions","customLogicOptions","setOptions","merge","wrap","setOptionsObj","isRenderComplete","Chart","proceed","userOptions","cb","exporting","enabled","plotOptions","series","label","tooltip","animation","onHighchartsRender","addEvent","Series","chart","Function","finalOptions","finalCallback","defaultOptions","template","browser","createBrowser","puppeteerArgs","enabledDebug","debugOptions","launchOptions","userDataDir","handleSIGINT","handleSIGTERM","handleSIGHUP","waitForInitialPage","defaultViewport","tryCount","open","launch","setTimeout","closeBrowser","connected","close","newPage","poolResource","page","setCacheEnabled","_setPageContent","_setPageEvents","isClosed","clearPage","hardReset","goto","waitUntil","evaluate","document","body","innerHTML","id","workCount","addPageResources","injectedResources","injectedJs","content","isLocal","jsResource","addScriptTag","injectedCss","cssImports","match","cssImportPath","cssResource","addStyleTag","clearPageResources","resource","dispose","oldCharts","charts","oldChart","destroy","scriptsToRemove","getElementsByTagName","stylesToRemove","linksToRemove","element","remove","setContent","cssTemplate","svgTemplate","puppeteerExport","isSVG","size","svgElement","querySelector","chartHeight","baseVal","chartWidth","style","zoom","margin","parseFloat","x","y","_getClipRegion","viewportHeight","abs","ceil","viewportWidth","result","setViewport","deviceScaleFactor","_createSVG","_createImage","_createPDF","$eval","getBoundingClientRect","trunc","outerHTML","clip","race","screenshot","encoding","fullPage","optimizeForSpeed","captureBeyondViewport","quality","omitBackground","_resolve","emulateMediaType","pdf","poolStats","exportsAttempted","exportsPerformed","exportsDropped","exportsFromSvg","exportsFromOptions","exportsFromSvgAttempts","exportsFromOptionsAttempts","timeSpent","timeSpentAverage","initPool","poolOptions","Pool","_factory","acquireTimeoutMillis","createTimeoutMillis","destroyTimeoutMillis","idleTimeoutMillis","createRetryIntervalMillis","reapIntervalMillis","propagateCreateError","clearStatus","_eventId","initialResources","acquire","promise","release","killPool","worker","used","destroyed","postWork","workerHandle","getPoolInfo","acquireCounter","workStart","exportCounter","exportTime","getPoolStats","getPoolInfoJSON","numUsed","available","numFree","allCreated","pendingAcquires","numPendingAcquires","pendingCreates","numPendingCreates","pendingValidations","numPendingValidations","pendingDestroys","absoluteAll","create","random","startDate","validate","mainFrame","detached","removeAllListeners","sanitize","JSDOM","DOMPurify","ADD_TAGS","singleExport","startExport","batchExport","batchFunctions","pair","batchResults","allSettled","reason","imageOptions","endCallback","fileContent","_exportFromSvg","_exportFromOptions","getAllowCodeExecution","setAllowCodeExecution","inputToExport","_prepareExport","_handleCustomLogic","_handleGlobalAndTheme","_findChartSize","optionsChart","optionsExporting","globalOptionsChart","globalOptionsExporting","themeOptionsChart","themeOptionsExporting","sourceHeight","sourceWidth","param","_handleResources","allowedProps","handledResources","correctResources","propName","optionsName","timerIds","addTimer","clearAllTimers","clearInterval","clearTimeout","logErrorMiddleware","request","next","returnErrorMiddleware","status","json","errorMiddleware","app","use","rateLimitingMiddleware","rateLimitingOptions","rateOptions","limiter","rateLimit","windowMs","limit","delayMs","handler","format","send","default","skip","query","access_token","contentTypeMiddleware","contentType","headers","requestBodyMiddleware","connection","remoteAddress","validatedOptions","filename","validationMiddleware","post","reversedMime","png","jpeg","gif","requestExport","requestCounter","connectionAborted","socket","hadErrors","header","attachment","exportRoutes","serverStartTime","packageFile","successRates","recordInterval","windowSize","_calculateMovingAverage","a","b","_startSuccessRate","setInterval","stats","successRatio","healthRoutes","period","movingAverage","bootTime","uptime","floor","serverVersion","highchartsVersion","averageExportTime","attemptedExports","performedExports","failedExports","sucessRatio","toFixed","svgExports","jsonExports","svgExportsAttempts","jsonExportsAttempts","uiRoutes","sendFile","acceptRanges","versionChangeRoutes","token","activeServers","Map","express","startServer","serverOptions","uploadLimitBytes","storage","multer","memoryStorage","upload","limits","fieldSize","disable","cors","methods","set","urlencoded","extended","none","static","httpServer","createServer","_attachServerErrorHandlers","listen","cert","httpsServer","closeServers","delete","getServers","getExpress","getApp","middlewares","shutdownCleanUp","exitCode","exit","initExport","initOptions","_attachProcessExitListeners"],"mappings":"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QACA,OACA,aACA,mBACA,eACA,cACA,UACA,UACA,cACA,WACA,UACA,YACA,cACA,YACA,sBACA,SACA,SACA,WACA,aACA,YACA,eACA,yBACA,SACA,eACA,YACA,kBACA,SACA,cACA,mBACA,eACA,kBACA,cACA,eAEA,cACA,WACA,eACA,WACA,SACA,OACA,WACA,YACA,SACA,qBACA,aACA,WACA,WACA,WACA,WACA,eACA,UACA,kBACA,oBACA,aACA,UACA,cACA,YACA,YAEF2D,MAAO,CAAC,YACRC,QAAS,4BACTE,YAAa,qCACbC,cAAe,CACb1G,KAAM,cACNkH,aAAc,0DAGlBE,iBAAkB,CAChBzE,MAAO,CAAC,kBACR2D,MAAO,CAAC,YACRC,QAAS,+BACTE,YAAa,wCACbC,cAAe,CACb1G,KAAM,cACNkH,aAAc,0DAGlBG,cAAe,CACb1E,MAAO,CACL,wEACA,kGAEF2D,MAAO,CAAC,YACRC,QAAS,4BACTE,YAAa,qDACbC,cAAe,CACb1G,KAAM,OACN2G,UAAW,OAIjBW,OAAQ,CACNC,OAAQ,CACN5E,MAAO,KACP2D,MAAO,CAAC,SAAU,QAClBC,QAAS,gBACTE,YACE,+DACFC,cAAe,CACb1G,KAAM,SAGVwH,MAAO,CACL7E,MAAO,KACP2D,MAAO,CAAC,SAAU,SAAU,QAC5BC,QAAS,eACTE,YACE,mEACFC,cAAe,CACb1G,KAAM,SAGVyH,QAAS,CACP9E,MAAO,KACP2D,MAAO,CAAC,SAAU,SAAU,QAC5BC,QAAS,iBACTE,YAAa,+BACbC,cAAe,CACb1G,KAAM,SAGV0H,IAAK,CACH/E,MAAO,KACP2D,MAAO,CAAC,SAAU,QAClBC,QAAS,aACTE,YAAa,mDACbC,cAAe,CACb1G,KAAM,SAGV2H,MAAO,CACLhF,MAAO,KACP2D,MAAO,CAAC,SAAU,QAClBC,QAAS,eACTE,YACE,gEACFC,cAAe,CACb1G,KAAM,SAGVC,QAAS,CACP0C,MAAO,KACP2D,MAAO,CAAC,SAAU,QAClBC,QAAS,iBACTE,YACE,qFACFC,cAAe,CACb1G,KAAM,SAGVA,KAAM,CACJ2C,MAAO,MACP2D,M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"} \ No newline at end of file diff --git a/lib/chart.js b/lib/chart.js index 46fe52b5..c9849c09 100644 --- a/lib/chart.js +++ b/lib/chart.js @@ -21,12 +21,7 @@ See LICENSE file in root for details. import { readFileSync, writeFileSync } from 'fs'; -import { - isAllowedConfig, - updateOptions, - validateOption, - validateOptions -} from './config.js'; +import { isAllowedConfig, updateOptions, validateOption } from './config.js'; import { log, logWithStack } from './logger.js'; import { getPoolStats, killPool, postWork } from './pool.js'; import { sanitize } from './sanitize.js'; @@ -68,9 +63,6 @@ let allowCodeExecution = false; export async function singleExport(options) { // Check if the export makes sense if (options && options.export) { - // Validate single export options - options = validateOptions(options); - // Perform an export await startExport( { export: options.export, customLogic: options.customLogic }, @@ -140,9 +132,6 @@ export async function singleExport(options) { export async function batchExport(options) { // Check if the export makes sense if (options && options.export && options.export.batch) { - // Validate batch export options - options = validateOptions(options); - // An array for collecting batch exports const batchFunctions = []; diff --git a/lib/config.js b/lib/config.js index e3613cad..cc0ea7e7 100644 --- a/lib/config.js +++ b/lib/config.js @@ -57,8 +57,9 @@ export function getOptions(getCopy = true) { } /** - * Updates a copy of the global options object or a reference to the global - * options object, based on the `getCopy` flag. + * Updates either a copy of the global options object or a reference + * to the global options object, depending on the getCopy flag, using + * the provided newOptions, which may or may not be validated. * * @function updateOptions * @@ -67,13 +68,20 @@ export function getOptions(getCopy = true) { * @param {boolean} [getCopy=false] - Determines whether to merge the new * options into a copy of the global options object (`true`) or directly into * the global options object (`false`). The default value is `false`. + * @param {boolean} [strictCheck=true] - Determines if stricter validation + * should be applied. The default value is `true`. * * @returns {Object} The updated options object, either the modified global * options or a modified copy, based on the value of `getCopy`. */ -export function updateOptions(newOptions, getCopy = false) { +export function updateOptions(newOptions, getCopy = false, strictCheck = true) { // Merge new options to the global options or its copy and return the result - return _mergeOptions(getOptions(getCopy), newOptions); + return _mergeOptions( + // First, get the options + getOptions(getCopy), + // Next, validate the new options + validateOptions(newOptions, strictCheck) + ); } /** @@ -99,33 +107,23 @@ export function setCliOptions(cliArgs) { // Only for the CLI usage if (cliArgs && Array.isArray(cliArgs) && cliArgs.length) { try { - // Validate options from the custom JSON loaded via the `--loadConfig` - const configOptions = strictValidate(_loadConfigFile(cliArgs)); + // Get options from the custom JSON loaded via the `--loadConfig` + const configOptions = _loadConfigFile(cliArgs); - // Update global options with the values from the `configOptions` + // Update global options with validated values from the `configOptions` updateOptions(configOptions); } catch (error) { - logZodIssues( - 1, - error.issues, - '[validation] Custom options from the `loadConfig` option validation error' - ); + log(2, '[validation] No options added from the `--loadConfig` option.'); } try { - // Validate options from the CLI - const cliOptions = looseValidate( - _pairArgumentValue(nestedProps, cliArgs) - ); + // Get options from the CLI + const cliOptions = _pairArgumentValue(nestedProps, cliArgs); - // Update global options with the values from the `cliOptions` - updateOptions(cliOptions); + // Update global options with validated values from the `cliOptions` + updateOptions(cliOptions, false, false); } catch (error) { - logZodIssues( - 1, - error.issues, - '[validation] CLI options validation error' - ); + log(2, '[validation] No options added from the CLI arguments.'); } } diff --git a/lib/index.js b/lib/index.js index 3cea1550..d59ccd8d 100644 --- a/lib/index.js +++ b/lib/index.js @@ -66,7 +66,7 @@ import server from './server/server.js'; */ export async function initExport(initOptions) { // Init, validate and update the options object - const options = updateOptions(validateOptions(initOptions)); + const options = updateOptions(initOptions); // Set the `allowCodeExecution` per export module scope setAllowCodeExecution(options.customLogic.allowCodeExecution); @@ -155,41 +155,35 @@ export default { logZodIssues, setLogLevel: function (level) { // Update the instance options object - const options = updateOptions( - validateOptions({ - logging: { - level - } - }) - ); + const options = updateOptions({ + logging: { + level + } + }); // Call the function setLogLevel(options.logging.level); }, enableConsoleLogging: function (toConsole) { // Update the instance options object - const options = updateOptions( - validateOptions({ - logging: { - toConsole - } - }) - ); + const options = updateOptions({ + logging: { + toConsole + } + }); // Call the function enableConsoleLogging(options.logging.toConsole); }, enableFileLogging: function (dest, file, toFile) { // Update the instance options object - const options = updateOptions( - validateOptions({ - logging: { - dest, - file, - toFile - } - }) - ); + const options = updateOptions({ + logging: { + dest, + file, + toFile + } + }); // Call the function enableFileLogging( diff --git a/lib/server/middlewares/validation.js b/lib/server/middlewares/validation.js index 551d1337..c451e9de 100644 --- a/lib/server/middlewares/validation.js +++ b/lib/server/middlewares/validation.js @@ -26,7 +26,7 @@ See LICENSE file in root for details. import { v4 as uuid } from 'uuid'; import { getAllowCodeExecution } from '../../chart.js'; -import { isAllowedConfig, validateOptions } from '../../config.js'; +import { isAllowedConfig } from '../../config.js'; import { log } from '../../logger.js'; import { isObjectEmpty, isPrivateRangeUrlFound } from '../../utils.js'; @@ -146,8 +146,8 @@ function requestBodyMiddleware(request, response, next) { ); } - // Validate the request options and store parsed structure in the request - request.validatedOptions = validateOptions({ + // Get and pre-validate the options and store them in the request + request.validatedOptions = { // Set the created ID as a `requestId` property in the options requestId, export: { @@ -181,7 +181,7 @@ function requestBodyMiddleware(request, response, next) { callback: body.callback, resources: isAllowedConfig(body.resources, true, allowCodeExecution) } - }); + }; // Call the next middleware return next(); diff --git a/lib/server/routes/versionChange.js b/lib/server/routes/versionChange.js index d5db30f9..16f3adc5 100644 --- a/lib/server/routes/versionChange.js +++ b/lib/server/routes/versionChange.js @@ -18,7 +18,6 @@ See LICENSE file in root for details. */ import { getHighchartsVersion, updateHighchartsVersion } from '../../cache.js'; -import { validateOption } from '../../config.js'; import { log } from '../../logger.js'; import { envs } from '../../validation.js'; @@ -63,17 +62,7 @@ export default function versionChangeRoutes(app) { } // Compare versions - let newVersion = request.params.newVersion; - - // Validate the version - try { - newVersion = validateOption('version', request.params.newVersion); - } catch (error) { - throw new ExportError( - `[version] Version is incorrect: ${error.message}`, - 400 - ).setError(error); - } + const newVersion = request.params.newVersion; // When a correct value found if (newVersion) { diff --git a/lib/server/server.js b/lib/server/server.js index 36f0a486..3a07e0b4 100644 --- a/lib/server/server.js +++ b/lib/server/server.js @@ -30,7 +30,7 @@ import http from 'http'; import https from 'https'; import multer from 'multer'; -import { updateOptions, validateOptions } from '../config.js'; +import { updateOptions } from '../config.js'; import { log, logWithStack } from '../logger.js'; import { __dirname, getAbsolutePath } from '../utils.js'; @@ -74,11 +74,9 @@ const app = express(); export async function startServer(serverOptions) { try { // Update the instance options object - const options = updateOptions( - validateOptions({ - server: serverOptions - }) - ); + const options = updateOptions({ + server: serverOptions + }); // Use validated options serverOptions = options.server; @@ -295,13 +293,11 @@ export function getApp() { */ export function enableRateLimiting(rateLimitingOptions) { // Update the instance options object - const options = updateOptions( - validateOptions({ - server: { - rateLimiting: rateLimitingOptions - } - }) - ); + const options = updateOptions({ + server: { + rateLimiting: rateLimitingOptions + } + }); // Set the rate limiting options rateLimitingMiddleware(app, options.server.rateLimitingOptions); From c22eeba5eed974fe57438e56a1c74e3e2c1331f7 Mon Sep 17 00:00:00 2001 From: PaulDalek Date: Mon, 3 Feb 2025 01:45:11 +0100 Subject: [PATCH 17/19] Small validation correction after merge. --- README.md | 4 ++-- dist/index.cjs | 4 ++-- dist/index.esm.js | 2 +- dist/index.esm.js.map | 2 +- lib/chart.js | 9 ++++++--- lib/index.js | 7 ++++--- lib/server/server.js | 11 ++++++----- 7 files changed, 22 insertions(+), 17 deletions(-) diff --git a/README.md b/README.md index 5f0fa2d7..cbe764db 100644 --- a/README.md +++ b/README.md @@ -723,9 +723,9 @@ This package supports both CommonJS and ES modules. **highcharts-export-server module** -- `async function startServer(serverOptions)`: Starts an HTTP and/or HTTPS server based on the provided configuration. The `serverOptions` object contains server-related properties (refer to the `server` section in the `./lib/schemas/config.js` file for details). +- `async function startServer(serverOptions = {})`: Starts an HTTP and/or HTTPS server based on the provided configuration. The `serverOptions` object contains server-related properties (refer to the `server` section in the `./lib/schemas/config.js` file for details). - - `@param {Object} serverOptions` - The configuration object containing `server` options. This object may include a partial or complete set of the `server` options. If the options are partial, missing values will default to the current global configuration. + - `@param {Object} [serverOptions={}]` - The configuration object containing `server` options. This object may include a partial or complete set of the `server` options. If the options are partial, missing values will default to the current global configuration. The default value is an empty object. - `@returns {Promise}` A Promise that resolves when the server is either not enabled or no valid Express app is found, signaling the end of the function's execution. diff --git a/dist/index.cjs b/dist/index.cjs index 38c96478..5ca5bb1c 100644 --- a/dist/index.cjs +++ b/dist/index.cjs @@ -1,2 +1,2 @@ -"use strict";Object.defineProperty(exports,"__esModule",{value:!0}),require("colors");var fs=require("fs"),path=require("path"),httpsProxyAgent=require("https-proxy-agent"),url=require("url"),dotenv=require("dotenv"),zod=require("zod"),http=require("http"),https=require("https"),tarn=require("tarn"),uuid=require("uuid"),puppeteer=require("puppeteer"),DOMPurify=require("dompurify"),jsdom=require("jsdom"),cors=require("cors"),express=require("express"),multer=require("multer"),rateLimit=require("express-rate-limit"),_documentCurrentScript="undefined"!=typeof document?document.currentScript:null;const __dirname$1=url.fileURLToPath(new URL("../.","undefined"==typeof document?require("url").pathToFileURL(__filename).href:_documentCurrentScript&&"SCRIPT"===_documentCurrentScript.tagName.toUpperCase()&&_documentCurrentScript.src||new URL("index.cjs",document.baseURI).href));function deepCopy(e){if(null===e||"object"!=typeof e)return e;const t=Array.isArray(e)?[]:{};for(const o in e)Object.prototype.hasOwnProperty.call(e,o)&&(t[o]=deepCopy(e[o]));return t}function getAbsolutePath(e){return path.isAbsolute(e)?path.normalize(e):path.resolve(e)}function getBase64(e,t){return"pdf"===t||"svg"==t?Buffer.from(e,"utf8").toString("base64"):e}function getNewDate(){return(new Date).toString().split("(")[0].trim()}function getNewDateTime(){return(new Date).getTime()}function isObject(e){return"[object Object]"===Object.prototype.toString.call(e)}function isObjectEmpty(e){return"object"==typeof e&&!Array.isArray(e)&&null!==e&&0===Object.keys(e).length}function isPrivateRangeUrlFound(e){return[/xlink:href="(?:http:\/\/|https:\/\/)?localhost\b/,/xlink:href="(?:http:\/\/|https:\/\/)?10\.\d{1,3}\.\d{1,3}\.\d{1,3}\b/,/xlink:href="(?:http:\/\/|https:\/\/)?127\.\d{1,3}\.\d{1,3}\.\d{1,3}\b/,/xlink:href="(?:http:\/\/|https:\/\/)?172\.(1[6-9]|2[0-9]|3[0-1])\.\d{1,3}\.\d{1,3}\b/,/xlink:href="(?:http:\/\/|https:\/\/)?192\.168\.\d{1,3}\.\d{1,3}\b/].some((t=>t.test(e)))}function measureTime(){const e=process.hrtime.bigint();return()=>Number(process.hrtime.bigint()-e)/1e6}function roundNumber(e,t=1){const o=Math.pow(10,t||0);return Math.round(+e*o)/o}const colors=["red","yellow","blue","gray","green"],logging={toConsole:!0,toFile:!1,pathCreated:!1,pathToLog:"",levelsDesc:[{title:"error",color:colors[0]},{title:"warning",color:colors[1]},{title:"notice",color:colors[2]},{title:"verbose",color:colors[3]},{title:"benchmark",color:colors[4]}]};function log(...e){const[t,...o]=e,{levelsDesc:r,level:n}=logging;if(5!==t&&(0===t||t>n||n>r.length))return;const i=`${getNewDate()} [${r[t-1].title}] -`;logging.toFile&&_logToFile(o,i),logging.toConsole&&console.log.apply(void 0,[i.toString()[logging.levelsDesc[t-1].color]].concat(o))}function logWithStack(e,t,o){const r=o||t&&t.message||"",{level:n,levelsDesc:i}=logging;if(0===e||e>n||n>i.length)return;const s=`${getNewDate()} [${i[e-1].title}] -`,a=t&&t.stack,l=[r];a&&l.push("\n",a),logging.toFile&&_logToFile(l,s),logging.toConsole&&console.log.apply(void 0,[s.toString()[logging.levelsDesc[e-1].color]].concat([l.shift()[colors[e-1]],...l]))}function logZodIssues(e,t,o){logWithStack(e,null,[`${o||"[validation] Validation error"} - the following Zod issues occured:`,...(t||[]).map((e=>`- ${e.message}`))].join("\n"))}function initLogging(e){const{level:t,dest:o,file:r,toConsole:n,toFile:i}=e;logging.pathCreated=!1,logging.pathToLog="",setLogLevel(t),enableConsoleLogging(n),enableFileLogging(o,r,i)}function setLogLevel(e){Number.isInteger(e)&&e>=0&&e<=logging.levelsDesc.length&&(logging.level=e)}function enableConsoleLogging(e){logging.toConsole=!!e}function enableFileLogging(e,t,o){logging.toFile=!!o,logging.toFile&&(logging.dest=e||"log",logging.file=t||"highcharts-export-server.log")}function _logToFile(e,t){logging.pathCreated||(!fs.existsSync(getAbsolutePath(logging.dest))&&fs.mkdirSync(getAbsolutePath(logging.dest)),logging.pathToLog=getAbsolutePath(path.join(logging.dest,logging.file)),logging.pathCreated=!0),fs.appendFile(logging.pathToLog,[t].concat(e).join(" ")+"\n",(e=>{e&&logging.toFile&&logging.pathCreated&&(logging.toFile=!1,logging.pathCreated=!1,logWithStack(2,e,"[logger] Unable to write to log file."))}))}const defaultConfig={puppeteer:{args:{value:["--allow-running-insecure-content","--ash-no-nudges","--autoplay-policy=user-gesture-required","--block-new-web-contents","--disable-accelerated-2d-canvas","--disable-background-networking","--disable-background-timer-throttling","--disable-backgrounding-occluded-windows","--disable-breakpad","--disable-checker-imaging","--disable-client-side-phishing-detection","--disable-component-extensions-with-background-pages","--disable-component-update","--disable-default-apps","--disable-dev-shm-usage","--disable-domain-reliability","--disable-extensions","--disable-features=CalculateNativeWinOcclusion,InterestFeedContentSuggestions,WebOTP","--disable-hang-monitor","--disable-ipc-flooding-protection","--disable-logging","--disable-notifications","--disable-offer-store-unmasked-wallet-cards","--disable-popup-blocking","--disable-print-preview","--disable-prompt-on-repost","--disable-renderer-backgrounding","--disable-search-engine-choice-screen","--disable-session-crashed-bubble","--disable-setuid-sandbox","--disable-site-isolation-trials","--disable-speech-api","--disable-sync","--enable-unsafe-webgpu","--hide-crash-restore-bubble","--hide-scrollbars","--metrics-recording-only","--mute-audio","--no-default-browser-check","--no-first-run","--no-pings","--no-sandbox","--no-startup-window","--no-zygote","--password-store=basic","--process-per-tab","--use-mock-keychain"],types:["string[]"],envLink:"PUPPETEER_ARGS",cliName:"puppeteerArgs",description:"Array of Puppeteer arguments",promptOptions:{type:"list",separator:";"}}},highcharts:{version:{value:"latest",types:["string"],envLink:"HIGHCHARTS_VERSION",description:"Highcharts version",promptOptions:{type:"text"}},cdnUrl:{value:"https://code.highcharts.com",types:["string"],envLink:"HIGHCHARTS_CDN_URL",description:"CDN URL for Highcharts scripts",promptOptions:{type:"text"}},forceFetch:{value:!1,types:["boolean"],envLink:"HIGHCHARTS_FORCE_FETCH",description:"Flag to refetch scripts after each server rerun",promptOptions:{type:"toggle"}},cachePath:{value:".cache",types:["string"],envLink:"HIGHCHARTS_CACHE_PATH",description:"Directory path for cached Highcharts scripts",promptOptions:{type:"text"}},coreScripts:{value:["highcharts","highcharts-more","highcharts-3d"],types:["string[]"],envLink:"HIGHCHARTS_CORE_SCRIPTS",description:"Highcharts core scripts to fetch",promptOptions:{type:"multiselect",instructions:"Space: Select specific, A: Select all, Enter: Confirm"}},moduleScripts:{value:["stock","map","gantt","exporting","parallel-coordinates","accessibility","boost-canvas","boost","data","data-tools","draggable-points","static-scale","broken-axis","heatmap","tilemap","tiledwebmap","timeline","treemap","treegraph","item-series","drilldown","histogram-bellcurve","bullet","funnel","funnel3d","geoheatmap","pyramid3d","networkgraph","overlapping-datalabels","pareto","pattern-fill","pictorial","price-indicator","sankey","arc-diagram","dependency-wheel","series-label","series-on-point","solid-gauge","sonification","streamgraph","sunburst","variable-pie","variwide","vector","venn","windbarb","wordcloud","xrange","no-data-to-display","drag-panes","debugger","dumbbell","lollipop","cylinder","organization","dotplot","marker-clusters","hollowcandlestick","heikinashi","flowmap","export-data","navigator","textpath"],types:["string[]"],envLink:"HIGHCHARTS_MODULE_SCRIPTS",description:"Highcharts module scripts to fetch",promptOptions:{type:"multiselect",instructions:"Space: Select specific, A: Select all, Enter: Confirm"}},indicatorScripts:{value:["indicators-all"],types:["string[]"],envLink:"HIGHCHARTS_INDICATOR_SCRIPTS",description:"Highcharts indicator scripts to fetch",promptOptions:{type:"multiselect",instructions:"Space: Select specific, A: Select all, Enter: Confirm"}},customScripts:{value:["https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.30.1/moment.min.js","https://cdnjs.cloudflare.com/ajax/libs/moment-timezone/0.5.45/moment-timezone-with-data.min.js"],types:["string[]"],envLink:"HIGHCHARTS_CUSTOM_SCRIPTS",description:"Additional custom scripts or dependencies to fetch",promptOptions:{type:"list",separator:";"}}},export:{infile:{value:null,types:["string","null"],envLink:"EXPORT_INFILE",description:"Input filename with type, formatted correctly as JSON or SVG",promptOptions:{type:"text"}},instr:{value:null,types:["Object","string","null"],envLink:"EXPORT_INSTR",description:"Overrides the `infile` with JSON, stringified JSON, or SVG input",promptOptions:{type:"text"}},options:{value:null,types:["Object","string","null"],envLink:"EXPORT_OPTIONS",description:"Alias for the `instr` option",promptOptions:{type:"text"}},svg:{value:null,types:["string","null"],envLink:"EXPORT_SVG",description:"SVG string representation of the chart to render",promptOptions:{type:"text"}},batch:{value:null,types:["string","null"],envLink:"EXPORT_BATCH",description:'Batch job string with input/output pairs: "in=out;in=out;..."',promptOptions:{type:"text"}},outfile:{value:null,types:["string","null"],envLink:"EXPORT_OUTFILE",description:"Output filename with type. Can be jpeg, png, pdf, or svg and ignores `type` option",promptOptions:{type:"text"}},type:{value:"png",types:["string"],envLink:"EXPORT_TYPE",description:"File export format. Can be jpeg, png, pdf, or svg",promptOptions:{type:"select",hint:"Default: png",choices:["png","jpeg","pdf","svg"]}},constr:{value:"chart",types:["string"],envLink:"EXPORT_CONSTR",description:"Chart constructor. Can be chart, stockChart, mapChart, or ganttChart",promptOptions:{type:"select",hint:"Default: chart",choices:["chart","stockChart","mapChart","ganttChart"]}},b64:{value:!1,types:["boolean"],envLink:"EXPORT_B64",description:"Whether or not to the chart should be received in Base64 format instead of binary",promptOptions:{type:"toggle"}},noDownload:{value:!1,types:["boolean"],envLink:"EXPORT_NO_DOWNLOAD",description:"Whether or not to include or exclude attachment headers in the response",promptOptions:{type:"toggle"}},height:{value:null,types:["number","null"],envLink:"EXPORT_HEIGHT",description:"Height of the exported chart, overrides chart settings",promptOptions:{type:"number"}},width:{value:null,types:["number","null"],envLink:"EXPORT_WIDTH",description:"Width of the exported chart, overrides chart settings",promptOptions:{type:"number"}},scale:{value:null,types:["number","null"],envLink:"EXPORT_SCALE",description:"Scale of the exported chart, overrides chart settings. Ranges from 0.1 to 5.0",promptOptions:{type:"number"}},defaultHeight:{value:400,types:["number"],envLink:"EXPORT_DEFAULT_HEIGHT",description:"Default height of the exported chart if not set",promptOptions:{type:"number"}},defaultWidth:{value:600,types:["number"],envLink:"EXPORT_DEFAULT_WIDTH",description:"Default width of the exported chart if not set",promptOptions:{type:"number"}},defaultScale:{value:1,types:["number"],envLink:"EXPORT_DEFAULT_SCALE",description:"Default scale of the exported chart if not set. Ranges from 0.1 to 5.0",promptOptions:{type:"number",min:.1,max:5}},globalOptions:{value:null,types:["Object","string","null"],envLink:"EXPORT_GLOBAL_OPTIONS",description:"JSON, stringified JSON or filename with global options for Highcharts.setOptions",promptOptions:{type:"text"}},themeOptions:{value:null,types:["Object","string","null"],envLink:"EXPORT_THEME_OPTIONS",description:"JSON, stringified JSON or filename with theme options for Highcharts.setOptions",promptOptions:{type:"text"}},rasterizationTimeout:{value:1500,types:["number"],envLink:"EXPORT_RASTERIZATION_TIMEOUT",description:"Milliseconds to wait for webpage rendering",promptOptions:{type:"number"}}},customLogic:{allowCodeExecution:{value:!1,types:["boolean"],envLink:"CUSTOM_LOGIC_ALLOW_CODE_EXECUTION",description:"Allows or disallows execution of arbitrary code during exporting",promptOptions:{type:"toggle"}},allowFileResources:{value:!1,types:["boolean"],envLink:"CUSTOM_LOGIC_ALLOW_FILE_RESOURCES",description:"Allows or disallows injection of filesystem resources (disabled in server mode)",promptOptions:{type:"toggle"}},customCode:{value:null,types:["string","null"],envLink:"CUSTOM_LOGIC_CUSTOM_CODE",description:"Custom code to execute before chart initialization. Can be a function, code wrapped in a function, or a .js filename",promptOptions:{type:"text"}},callback:{value:null,types:["string","null"],envLink:"CUSTOM_LOGIC_CALLBACK",description:"JavaScript code to run during construction. Can be a function or a .js filename",promptOptions:{type:"text"}},resources:{value:null,types:["Object","string","null"],envLink:"CUSTOM_LOGIC_RESOURCES",description:"Additional resources as JSON, stringified JSON, or filename, containing files, js, and css sections",promptOptions:{type:"text"}},loadConfig:{value:null,types:["string","null"],envLink:"CUSTOM_LOGIC_LOAD_CONFIG",legacyName:"fromFile",description:"File with a pre-defined configuration to use",promptOptions:{type:"text"}},createConfig:{value:null,types:["string","null"],envLink:"CUSTOM_LOGIC_CREATE_CONFIG",description:"Prompt-based option setting, saved to a provided config file",promptOptions:{type:"text"}}},server:{enable:{value:!1,types:["boolean"],envLink:"SERVER_ENABLE",cliName:"enableServer",description:"Starts the server when true",promptOptions:{type:"toggle"}},host:{value:"0.0.0.0",types:["string"],envLink:"SERVER_HOST",description:"Hostname of the server",promptOptions:{type:"text"}},port:{value:7801,types:["number"],envLink:"SERVER_PORT",description:"Port number for the server",promptOptions:{type:"number"}},uploadLimit:{value:3,types:["number"],envLink:"SERVER_UPLOAD_LIMIT",description:"Maximum request body size in MB",promptOptions:{type:"number"}},benchmarking:{value:!1,types:["boolean"],envLink:"SERVER_BENCHMARKING",cliName:"serverBenchmarking",description:"Displays or not action durations in milliseconds during server requests",promptOptions:{type:"toggle"}},proxy:{host:{value:null,types:["string","null"],envLink:"SERVER_PROXY_HOST",cliName:"proxyHost",description:"Host of the proxy server, if applicable",promptOptions:{type:"text"}},port:{value:null,types:["number","null"],envLink:"SERVER_PROXY_PORT",cliName:"proxyPort",description:"Port of the proxy server, if applicable",promptOptions:{type:"number"}},timeout:{value:5e3,types:["number"],envLink:"SERVER_PROXY_TIMEOUT",cliName:"proxyTimeout",description:"Timeout in milliseconds for the proxy server, if applicable",promptOptions:{type:"number"}}},rateLimiting:{enable:{value:!1,types:["boolean"],envLink:"SERVER_RATE_LIMITING_ENABLE",cliName:"enableRateLimiting",description:"Enables or disables rate limiting on the server",promptOptions:{type:"toggle"}},maxRequests:{value:10,types:["number"],envLink:"SERVER_RATE_LIMITING_MAX_REQUESTS",legacyName:"rateLimit",description:"Maximum number of requests allowed per minute",promptOptions:{type:"number"}},window:{value:1,types:["number"],envLink:"SERVER_RATE_LIMITING_WINDOW",description:"Time window in minutes for rate limiting",promptOptions:{type:"number"}},delay:{value:0,types:["number"],envLink:"SERVER_RATE_LIMITING_DELAY",description:"Delay duration between successive requests before reaching the limit",promptOptions:{type:"number"}},trustProxy:{value:!1,types:["boolean"],envLink:"SERVER_RATE_LIMITING_TRUST_PROXY",description:"Set to true if the server is behind a load balancer",promptOptions:{type:"toggle"}},skipKey:{value:null,types:["string","null"],envLink:"SERVER_RATE_LIMITING_SKIP_KEY",description:"Key to bypass the rate limiter, used with `skipToken`",promptOptions:{type:"text"}},skipToken:{value:null,types:["string","null"],envLink:"SERVER_RATE_LIMITING_SKIP_TOKEN",description:"Token to bypass the rate limiter, used with `skipKey`",promptOptions:{type:"text"}}},ssl:{enable:{value:!1,types:["boolean"],envLink:"SERVER_SSL_ENABLE",cliName:"enableSsl",description:"Enables or disables SSL protocol",promptOptions:{type:"toggle"}},force:{value:!1,types:["boolean"],envLink:"SERVER_SSL_FORCE",cliName:"sslForce",legacyName:"sslOnly",description:"Forces the server to use HTTPS only when true",promptOptions:{type:"toggle"}},port:{value:443,types:["number"],envLink:"SERVER_SSL_PORT",cliName:"sslPort",description:"Port for the SSL server",promptOptions:{type:"number"}},certPath:{value:null,types:["string","null"],envLink:"SERVER_SSL_CERT_PATH",cliName:"sslCertPath",legacyName:"sslPath",description:"Path to the SSL certificate/key file",promptOptions:{type:"text"}}}},pool:{minWorkers:{value:4,types:["number"],envLink:"POOL_MIN_WORKERS",description:"Minimum and initial number of pool workers to spawn",promptOptions:{type:"number"}},maxWorkers:{value:8,types:["number"],envLink:"POOL_MAX_WORKERS",legacyName:"workers",description:"Maximum number of pool workers to spawn",promptOptions:{type:"number"}},workLimit:{value:40,types:["number"],envLink:"POOL_WORK_LIMIT",description:"Number of tasks a worker can handle before restarting",promptOptions:{type:"number"}},acquireTimeout:{value:5e3,types:["number"],envLink:"POOL_ACQUIRE_TIMEOUT",description:"Timeout in milliseconds for acquiring a resource",promptOptions:{type:"number"}},createTimeout:{value:5e3,types:["number"],envLink:"POOL_CREATE_TIMEOUT",description:"Timeout in milliseconds for creating a resource",promptOptions:{type:"number"}},destroyTimeout:{value:5e3,types:["number"],envLink:"POOL_DESTROY_TIMEOUT",description:"Timeout in milliseconds for destroying a resource",promptOptions:{type:"number"}},idleTimeout:{value:3e4,types:["number"],envLink:"POOL_IDLE_TIMEOUT",description:"Timeout in milliseconds for destroying idle resources",promptOptions:{type:"number"}},createRetryInterval:{value:200,types:["number"],envLink:"POOL_CREATE_RETRY_INTERVAL",description:"Interval in milliseconds before retrying resource creation on failure",promptOptions:{type:"number"}},reaperInterval:{value:1e3,types:["number"],envLink:"POOL_REAPER_INTERVAL",description:"Interval in milliseconds to check and destroy idle resources",promptOptions:{type:"number"}},benchmarking:{value:!1,types:["boolean"],envLink:"POOL_BENCHMARKING",cliName:"poolBenchmarking",description:"Shows statistics for the pool of resources",promptOptions:{type:"toggle"}}},logging:{level:{value:4,types:["number"],envLink:"LOGGING_LEVEL",cliName:"logLevel",description:"Logging verbosity level",promptOptions:{type:"number",round:0,min:0,max:5}},file:{value:"highcharts-export-server.log",types:["string"],envLink:"LOGGING_FILE",cliName:"logFile",description:"Log file name. Requires `logToFile` and `logDest` to be set",promptOptions:{type:"text"}},dest:{value:"log",types:["string"],envLink:"LOGGING_DEST",cliName:"logDest",description:"Path to store log files. Requires `logToFile` to be set",promptOptions:{type:"text"}},toConsole:{value:!0,types:["boolean"],envLink:"LOGGING_TO_CONSOLE",cliName:"logToConsole",description:"Enables or disables console logging",promptOptions:{type:"toggle"}},toFile:{value:!0,types:["boolean"],envLink:"LOGGING_TO_FILE",cliName:"logToFile",description:"Enables or disables logging to a file",promptOptions:{type:"toggle"}}},ui:{enable:{value:!1,types:["boolean"],envLink:"UI_ENABLE",cliName:"enableUi",description:"Enables or disables the UI for the export server",promptOptions:{type:"toggle"}},route:{value:"/",types:["string"],envLink:"UI_ROUTE",cliName:"uiRoute",description:"The endpoint route for the UI",promptOptions:{type:"text"}}},other:{nodeEnv:{value:"production",types:["string"],envLink:"OTHER_NODE_ENV",description:"The Node.js environment type",promptOptions:{type:"text"}},listenToProcessExits:{value:!0,types:["boolean"],envLink:"OTHER_LISTEN_TO_PROCESS_EXITS",description:"Whether or not to attach process.exit handlers",promptOptions:{type:"toggle"}},noLogo:{value:!1,types:["boolean"],envLink:"OTHER_NO_LOGO",description:"Display or skip printing the logo on startup",promptOptions:{type:"toggle"}},hardResetPage:{value:!1,types:["boolean"],envLink:"OTHER_HARD_RESET_PAGE",description:"Whether or not to reset the page content entirely",promptOptions:{type:"toggle"}},browserShellMode:{value:!0,types:["boolean"],envLink:"OTHER_BROWSER_SHELL_MODE",description:"Whether or not to set the browser to run in shell mode",promptOptions:{type:"toggle"}},validation:{value:!0,types:["boolean"],envLink:"OTHER_VALIDATION",description:"Whether or not to enable validation of options types",promptOptions:{type:"toggle"}}},debug:{enable:{value:!1,types:["boolean"],envLink:"DEBUG_ENABLE",cliName:"enableDebug",description:"Enables or disables debug mode for the underlying browser",promptOptions:{type:"toggle"}},headless:{value:!1,types:["boolean"],envLink:"DEBUG_HEADLESS",description:"Whether or not to set the browser to run in headless mode during debugging",promptOptions:{type:"toggle"}},devtools:{value:!1,types:["boolean"],envLink:"DEBUG_DEVTOOLS",description:"Enables or disables DevTools in headful mode",promptOptions:{type:"toggle"}},listenToConsole:{value:!1,types:["boolean"],envLink:"DEBUG_LISTEN_TO_CONSOLE",description:"Enables or disables listening to console messages from the browser",promptOptions:{type:"toggle"}},dumpio:{value:!1,types:["boolean"],envLink:"DEBUG_DUMPIO",description:"Redirects or not browser stdout and stderr to process.stdout and process.stderr",promptOptions:{type:"toggle"}},slowMo:{value:0,types:["number"],envLink:"DEBUG_SLOW_MO",description:"Delays Puppeteer operations by the specified milliseconds",promptOptions:{type:"number"}},debuggingPort:{value:9222,types:["number"],envLink:"DEBUG_DEBUGGING_PORT",description:"Port used for debugging",promptOptions:{type:"number"}}}};dotenv.config();const{coreScripts:coreScripts,moduleScripts:moduleScripts,indicatorScripts:indicatorScripts}=defaultConfig.highcharts;zod.z.setErrorMap(_customErrorMap);const v={boolean:e=>e?zod.z.boolean():zod.z.union([zod.z.enum(["true","1","false","0","undefined","null",""]).transform((e=>["undefined","null",""].includes(e)?null:"true"===e||"1"===e)),zod.z.boolean()]).nullable(),string:e=>e?zod.z.string().trim().refine((e=>!["false","undefined","null",""].includes(e)),{params:{errorMessage:"The string contains a forbidden value"}}):zod.z.string().trim().transform((e=>["false","undefined","null",""].includes(e)?null:e)).nullable(),enum:(e,t)=>t?zod.z.enum([...e]):zod.z.enum([...e,"undefined","null",""]).transform((e=>["undefined","null",""].includes(e)?null:e)).nullable(),stringArray(e,t,o){const r=zod.z.string().trim().array(),n=zod.z.string().trim().transform((e=>(e.startsWith("[")&&(e=e.slice(1)),e.endsWith("]")&&(e=e.slice(0,-1)),e.split(t)))),i=t=>t.map((e=>e.trim())).filter(e);return o?r.transform(i):zod.z.union([n,r]).transform(i).transform((e=>e.length?e:null)).nullable()},positiveNum:e=>e?zod.z.number().positive():zod.z.union([zod.z.string().trim().refine((e=>!isNaN(Number(e))&&Number(e)>0||["undefined","null",""].includes(e)),{params:{errorMessage:"The value must be numeric and positive"}}).transform((e=>["undefined","null",""].includes(e)?null:Number(e))),zod.z.number().positive()]).nullable(),nonNegativeNum:e=>e?zod.z.number().nonnegative():zod.z.union([zod.z.string().trim().refine((e=>!isNaN(Number(e))&&Number(e)>=0||["undefined","null",""].includes(e)),{params:{errorMessage:"The value must be numeric and non-negative"}}).transform((e=>["undefined","null",""].includes(e)?null:Number(e))),zod.z.number().nonnegative()]).nullable(),startsWith:(e,t)=>t?zod.z.string().trim().refine((t=>e.some((e=>t.startsWith(e)))),{params:{errorMessage:`The value must be a string that starts with ${e.join(", ")}`}}):zod.z.string().trim().refine((t=>e.some((e=>t.startsWith(e)))||["undefined","null",""].includes(t)),{params:{errorMessage:`The value must be a string that starts with ${e.join(", ")}`}}).transform((e=>["undefined","null",""].includes(e)?null:e)).nullable(),chartConfig:()=>zod.z.union([zod.z.string().trim().refine((e=>e.startsWith("{")&&e.endsWith("}")||["undefined","null",""].includes(e)),{params:{errorMessage:"The value must be a string that starts with '{' and ends with '}'"}}).transform((e=>["undefined","null",""].includes(e)?null:e)),zod.z.object({}).passthrough()]).nullable(),additionalOptions:()=>zod.z.union([zod.z.string().trim().refine((e=>e.length>=6&&e.endsWith(".json")||e.startsWith("{")&&e.endsWith("}")||["undefined","null",""].includes(e)),{params:{errorMessage:"The value must be a string that ends with '.json' or starts with '{' and ends with '}'"}}).transform((e=>["undefined","null",""].includes(e)?null:e)),zod.z.object({}).passthrough()]).nullable()},validators={args:e=>v.stringArray((e=>!["false","undefined","null",""].includes(e)),";",e),version:e=>e?zod.z.string().trim().refine((e=>/^(latest|\d{1,2}(\.\d{1,2}){0,2})$/.test(e)),{params:{errorMessage:"The value must be 'latest', a major version, or in the form XX.YY.ZZ"}}):zod.z.string().trim().refine((e=>/^(latest|\d{1,2}(\.\d{1,2}){0,2})$/.test(e)||["undefined","null",""].includes(e)),{params:{errorMessage:"The value must be 'latest', a major version, or in the form XX.YY.ZZ"}}).transform((e=>["undefined","null",""].includes(e)?null:e)).nullable(),cdnUrl:e=>v.startsWith(["http://","https://"],e),forceFetch:e=>v.boolean(e),cachePath:e=>v.string(e),adminToken:e=>v.string(e),coreScripts:e=>v.stringArray((e=>coreScripts.value.includes(e)),",",e),moduleScripts:e=>v.stringArray((e=>moduleScripts.value.includes(e)),",",e),indicatorScripts:e=>v.stringArray((e=>indicatorScripts.value.includes(e)),",",e),customScripts:e=>v.stringArray((e=>e.startsWith("https://")||e.startsWith("http://")),",",e),infile:e=>e?zod.z.string().trim().refine((e=>e.length>=6&&e.endsWith(".json")||e.length>=5&&e.endsWith(".svg")),{params:{errorMessage:"The value must be a string that ends with .json or .svg"}}).nullable():zod.z.string().trim().refine((e=>e.length>=6&&e.endsWith(".json")||e.length>=5&&e.endsWith(".svg")||["undefined","null",""].includes(e)),{params:{errorMessage:"The value must be a string that ends with .json or .svg"}}).transform((e=>["undefined","null",""].includes(e)?null:e)).nullable(),instr:()=>v.chartConfig(),options:()=>v.chartConfig(),svg:()=>zod.z.string().trim().refine((e=>e.indexOf("=0||e.indexOf("=0||["false","undefined","null",""].includes(e)),{params:{errorMessage:"The value must be a string that contains '["false","undefined","null",""].includes(e)?null:e)).nullable(),outfile:e=>e?zod.z.string().trim().refine((e=>e.length>=6&&e.endsWith(".jpeg")||e.length>=5&&(e.endsWith(".jpg")||e.endsWith(".png")||e.endsWith(".pdf")||e.endsWith(".svg"))),{params:{errorMessage:"The value must be a string that ends with .jpeg, .jpg, .png, .pdf, or .svg"}}).nullable():zod.z.string().trim().refine((e=>e.length>=6&&e.endsWith(".jpeg")||e.length>=5&&(e.endsWith(".jpg")||e.endsWith(".png")||e.endsWith(".pdf")||e.endsWith(".svg"))||["undefined","null",""].includes(e)),{params:{errorMessage:"The value must be a string that ends with .jpeg, .jpg, .png, .pdf, or .svg"}}).transform((e=>["undefined","null",""].includes(e)?null:e)).nullable(),type:e=>v.enum(["jpeg","jpg","png","pdf","svg"],e),constr:e=>v.enum(["chart","stockChart","mapChart","ganttChart"],e),b64:e=>v.boolean(e),noDownload:e=>v.boolean(e),defaultHeight:e=>v.positiveNum(e),defaultWidth:e=>v.positiveNum(e),defaultScale:e=>e?zod.z.number().gte(.1).lte(5):zod.z.union([zod.z.string().trim().refine((e=>!isNaN(Number(e))&&!0!==e&&!e.startsWith("[")&&Number(e)>=.1&&Number(e)<=5||["undefined","null",""].includes(e)),{params:{errorMessage:"The value must be within a 0.1 and 5.0 range"}}).transform((e=>["undefined","null",""].includes(e)?null:Number(e))),zod.z.number().gte(.1).lte(5)]).nullable(),height(e){return this.defaultHeight(e).nullable()},width(e){return this.defaultWidth(e).nullable()},scale(e){return this.defaultScale(e).nullable()},globalOptions:()=>v.additionalOptions(),themeOptions:()=>v.additionalOptions(),batch:e=>v.string(e),rasterizationTimeout:e=>v.nonNegativeNum(e),allowCodeExecution:e=>v.boolean(e),allowFileResources:e=>v.boolean(e),customCode:e=>v.string(e),callback:e=>v.string(e),resources(e){const t=zod.z.object({js:v.string(!1),css:v.string(!1),files:v.stringArray((e=>!["undefined","null",""].includes(e)),",",!0).nullable()}).partial(),o=zod.z.string().trim().refine((e=>e.startsWith("{")&&e.endsWith("}")||e.length>=6&&e.endsWith(".json")),{params:{errorMessage:"The value must be a string that starts with '{' and ends with '}"}}),r=zod.z.string().trim().refine((e=>e.startsWith("{")&&e.endsWith("}")||e.length>=6&&e.endsWith(".json")||["undefined","null",""].includes(e)),{params:{errorMessage:"The value must be a string that ends with .json"}}).transform((e=>["undefined","null",""].includes(e)?null:e));return e?zod.z.union([t,o]).nullable():zod.z.union([t,r]).nullable()},loadConfig:e=>v.string(e).refine((e=>null===e||e.length>=6&&e.endsWith(".json")),{params:{errorMessage:"The value must be a string that ends with .json"}}),createConfig(e){return this.loadConfig(e)},enableServer:e=>v.boolean(e),host:e=>v.string(e),port:e=>v.nonNegativeNum(e),uploadLimit:e=>v.positiveNum(e),serverBenchmarking:e=>v.boolean(e),proxyHost:e=>v.string(e),proxyPort:e=>v.nonNegativeNum(e).nullable(),proxyTimeout:e=>v.nonNegativeNum(e),enableRateLimiting:e=>v.boolean(e),maxRequests:e=>v.nonNegativeNum(e),window:e=>v.nonNegativeNum(e),delay:e=>v.nonNegativeNum(e),trustProxy:e=>v.boolean(e),skipKey:e=>v.string(e),skipToken:e=>v.string(e),enableSsl:e=>v.boolean(e),sslForce:e=>v.boolean(e),sslPort:e=>v.nonNegativeNum(e),sslCertPath:e=>v.string(e),minWorkers:e=>v.positiveNum(e),maxWorkers:e=>v.positiveNum(e),workLimit:e=>v.positiveNum(e),acquireTimeout:e=>v.nonNegativeNum(e),createTimeout:e=>v.nonNegativeNum(e),destroyTimeout:e=>v.nonNegativeNum(e),idleTimeout:e=>v.nonNegativeNum(e),createRetryInterval:e=>v.nonNegativeNum(e),reaperInterval:e=>v.nonNegativeNum(e),poolBenchmarking:e=>v.boolean(e),resourcesInterval:e=>v.nonNegativeNum(e),logLevel:e=>e?zod.z.number().int().gte(0).lte(5):zod.z.union([zod.z.string().trim().refine((e=>!isNaN(Number(e))&&!0!==e&&!e.startsWith("[")&&Number.isInteger(Number(e))&&Number(e)>=0&&Number(e)<=5||["undefined","null",""].includes(e)),{params:{errorMessage:"The value must be within a 0 and 5 range"}}).transform((e=>["undefined","null",""].includes(e)?null:Number(e))),zod.z.number().int().gte(0).lte(5)]).nullable(),logFile:e=>v.string(e).refine((e=>null===e||e.length>=5&&e.endsWith(".log")),{params:{errorMessage:"The value must be a string that ends with .log"}}),logDest:e=>v.string(e),logToConsole:e=>v.boolean(e),logToFile:e=>v.boolean(e),enableUi:e=>v.boolean(e),uiRoute:e=>v.startsWith(["/"],e),nodeEnv:e=>v.enum(["development","production","test"],e),listenToProcessExits:e=>v.boolean(e),noLogo:e=>v.boolean(e),hardResetPage:e=>v.boolean(e),browserShellMode:e=>v.boolean(e),validation:e=>v.boolean(e),enableDebug:e=>v.boolean(e),headless:e=>v.boolean(e),devtools:e=>v.boolean(e),listenToConsole:e=>v.boolean(e),dumpio:e=>v.boolean(e),slowMo:e=>v.nonNegativeNum(e),debuggingPort:e=>v.nonNegativeNum(e),requestId:()=>zod.z.string().uuid({message:"The value must be a stringified UUID"}).nullable()},PuppeteerSchema=e=>zod.z.object({args:validators.args(e)}).partial(),HighchartsSchema=e=>zod.z.object({version:validators.version(e),cdnUrl:validators.cdnUrl(e),forceFetch:validators.forceFetch(e),cachePath:validators.cachePath(e),coreScripts:validators.coreScripts(e),moduleScripts:validators.moduleScripts(e),indicatorScripts:validators.indicatorScripts(e),customScripts:validators.customScripts(e)}).partial(),ExportSchema=e=>zod.z.object({infile:validators.infile(e),instr:validators.instr(),options:validators.options(),svg:validators.svg(),outfile:validators.outfile(e),type:validators.type(e),constr:validators.constr(e),b64:validators.b64(e),noDownload:validators.noDownload(e),defaultHeight:validators.defaultHeight(e),defaultWidth:validators.defaultWidth(e),defaultScale:validators.defaultScale(e),height:validators.height(e),width:validators.width(e),scale:validators.scale(e),globalOptions:validators.globalOptions(),themeOptions:validators.themeOptions(),batch:validators.batch(!1),rasterizationTimeout:validators.rasterizationTimeout(e)}).partial(),CustomLogicSchema=e=>zod.z.object({allowCodeExecution:validators.allowCodeExecution(e),allowFileResources:validators.allowFileResources(e),customCode:validators.customCode(!1),callback:validators.callback(!1),resources:validators.resources(e),loadConfig:validators.loadConfig(!1),createConfig:validators.createConfig(!1)}).partial(),ProxySchema=e=>zod.z.object({host:validators.proxyHost(!1),port:validators.proxyPort(e),timeout:validators.proxyTimeout(e)}).partial(),RateLimitingSchema=e=>zod.z.object({enable:validators.enableRateLimiting(e),maxRequests:validators.maxRequests(e),window:validators.window(e),delay:validators.delay(e),trustProxy:validators.trustProxy(e),skipKey:validators.skipKey(!1),skipToken:validators.skipToken(!1)}).partial(),SslSchema=e=>zod.z.object({enable:validators.enableSsl(e),force:validators.sslForce(e),port:validators.sslPort(e),certPath:validators.sslCertPath(!1)}).partial(),ServerSchema=e=>zod.z.object({enable:validators.enableServer(e).optional(),host:validators.host(e).optional(),port:validators.port(e).optional(),uploadLimit:validators.uploadLimit(e).optional(),benchmarking:validators.serverBenchmarking(e).optional(),proxy:ProxySchema(e).optional(),rateLimiting:RateLimitingSchema(e).optional(),ssl:SslSchema(e).optional()}),PoolSchema=e=>zod.z.object({minWorkers:validators.minWorkers(e),maxWorkers:validators.maxWorkers(e),workLimit:validators.workLimit(e),acquireTimeout:validators.acquireTimeout(e),createTimeout:validators.createTimeout(e),destroyTimeout:validators.destroyTimeout(e),idleTimeout:validators.idleTimeout(e),createRetryInterval:validators.createRetryInterval(e),reaperInterval:validators.reaperInterval(e),benchmarking:validators.poolBenchmarking(e)}).partial(),LoggingSchema=e=>zod.z.object({level:validators.logLevel(e),file:validators.logFile(e),dest:validators.logDest(e),toConsole:validators.logToConsole(e),toFile:validators.logToFile(e)}).partial(),UiSchema=e=>zod.z.object({enable:validators.enableUi(e),route:validators.uiRoute(e)}).partial(),OtherSchema=e=>zod.z.object({nodeEnv:validators.nodeEnv(e),listenToProcessExits:validators.listenToProcessExits(e),noLogo:validators.noLogo(e),hardResetPage:validators.hardResetPage(e),browserShellMode:validators.browserShellMode(e),validation:validators.validation(e)}).partial(),DebugSchema=e=>zod.z.object({enable:validators.enableDebug(e),headless:validators.headless(e),devtools:validators.devtools(e),listenToConsole:validators.listenToConsole(e),dumpio:validators.dumpio(e),slowMo:validators.slowMo(e),debuggingPort:validators.debuggingPort(e)}).partial(),StrictConfigSchema=zod.z.object({requestId:validators.requestId(),puppeteer:PuppeteerSchema(!0),highcharts:HighchartsSchema(!0),export:ExportSchema(!0),customLogic:CustomLogicSchema(!0),server:ServerSchema(!0),pool:PoolSchema(!0),logging:LoggingSchema(!0),ui:UiSchema(!0),other:OtherSchema(!0),debug:DebugSchema(!0)}),LooseConfigSchema=zod.z.object({requestId:validators.requestId(),puppeteer:PuppeteerSchema(!1),highcharts:HighchartsSchema(!1),export:ExportSchema(!1),customLogic:CustomLogicSchema(!1),server:ServerSchema(!1),pool:PoolSchema(!1),logging:LoggingSchema(!1),ui:UiSchema(!1),other:OtherSchema(!1),debug:DebugSchema(!1)}),EnvSchema=zod.z.object({PUPPETEER_ARGS:validators.args(!1),HIGHCHARTS_VERSION:validators.version(!1),HIGHCHARTS_CDN_URL:validators.cdnUrl(!1),HIGHCHARTS_FORCE_FETCH:validators.forceFetch(!1),HIGHCHARTS_CACHE_PATH:validators.cachePath(!1),HIGHCHARTS_ADMIN_TOKEN:validators.adminToken(!1),HIGHCHARTS_CORE_SCRIPTS:validators.coreScripts(!1),HIGHCHARTS_MODULE_SCRIPTS:validators.moduleScripts(!1),HIGHCHARTS_INDICATOR_SCRIPTS:validators.indicatorScripts(!1),HIGHCHARTS_CUSTOM_SCRIPTS:validators.customScripts(!1),EXPORT_INFILE:validators.infile(!1),EXPORT_INSTR:validators.instr(),EXPORT_OPTIONS:validators.options(),EXPORT_SVG:validators.svg(),EXPORT_BATCH:validators.batch(!1),EXPORT_OUTFILE:validators.outfile(!1),EXPORT_TYPE:validators.type(!1),EXPORT_CONSTR:validators.constr(!1),EXPORT_B64:validators.b64(!1),EXPORT_NO_DOWNLOAD:validators.noDownload(!1),EXPORT_HEIGHT:validators.height(!1),EXPORT_WIDTH:validators.width(!1),EXPORT_SCALE:validators.scale(!1),EXPORT_DEFAULT_HEIGHT:validators.defaultHeight(!1),EXPORT_DEFAULT_WIDTH:validators.defaultWidth(!1),EXPORT_DEFAULT_SCALE:validators.defaultScale(!1),EXPORT_GLOBAL_OPTIONS:validators.globalOptions(),EXPORT_THEME_OPTIONS:validators.themeOptions(),EXPORT_RASTERIZATION_TIMEOUT:validators.rasterizationTimeout(!1),CUSTOM_LOGIC_ALLOW_CODE_EXECUTION:validators.allowCodeExecution(!1),CUSTOM_LOGIC_ALLOW_FILE_RESOURCES:validators.allowFileResources(!1),CUSTOM_LOGIC_CUSTOM_CODE:validators.customCode(!1),CUSTOM_LOGIC_CALLBACK:validators.callback(!1),CUSTOM_LOGIC_RESOURCES:validators.resources(!1),CUSTOM_LOGIC_LOAD_CONFIG:validators.loadConfig(!1),CUSTOM_LOGIC_CREATE_CONFIG:validators.createConfig(!1),SERVER_ENABLE:validators.enableServer(!1),SERVER_HOST:validators.host(!1),SERVER_PORT:validators.port(!1),SERVER_UPLOAD_LIMIT:validators.uploadLimit(!1),SERVER_BENCHMARKING:validators.serverBenchmarking(!1),SERVER_PROXY_HOST:validators.proxyHost(!1),SERVER_PROXY_PORT:validators.proxyPort(!1),SERVER_PROXY_TIMEOUT:validators.proxyTimeout(!1),SERVER_RATE_LIMITING_ENABLE:validators.enableRateLimiting(!1),SERVER_RATE_LIMITING_MAX_REQUESTS:validators.maxRequests(!1),SERVER_RATE_LIMITING_WINDOW:validators.window(!1),SERVER_RATE_LIMITING_DELAY:validators.delay(!1),SERVER_RATE_LIMITING_TRUST_PROXY:validators.trustProxy(!1),SERVER_RATE_LIMITING_SKIP_KEY:validators.skipKey(!1),SERVER_RATE_LIMITING_SKIP_TOKEN:validators.skipToken(!1),SERVER_SSL_ENABLE:validators.enableSsl(!1),SERVER_SSL_FORCE:validators.sslForce(!1),SERVER_SSL_PORT:validators.sslPort(!1),SERVER_SSL_CERT_PATH:validators.sslCertPath(!1),POOL_MIN_WORKERS:validators.minWorkers(!1),POOL_MAX_WORKERS:validators.maxWorkers(!1),POOL_WORK_LIMIT:validators.workLimit(!1),POOL_ACQUIRE_TIMEOUT:validators.acquireTimeout(!1),POOL_CREATE_TIMEOUT:validators.createTimeout(!1),POOL_DESTROY_TIMEOUT:validators.destroyTimeout(!1),POOL_IDLE_TIMEOUT:validators.idleTimeout(!1),POOL_CREATE_RETRY_INTERVAL:validators.createRetryInterval(!1),POOL_REAPER_INTERVAL:validators.reaperInterval(!1),POOL_BENCHMARKING:validators.poolBenchmarking(!1),LOGGING_LEVEL:validators.logLevel(!1),LOGGING_FILE:validators.logFile(!1),LOGGING_DEST:validators.logDest(!1),LOGGING_TO_CONSOLE:validators.logToConsole(!1),LOGGING_TO_FILE:validators.logToFile(!1),UI_ENABLE:validators.enableUi(!1),UI_ROUTE:validators.uiRoute(!1),OTHER_NODE_ENV:validators.nodeEnv(!1),OTHER_LISTEN_TO_PROCESS_EXITS:validators.listenToProcessExits(!1),OTHER_NO_LOGO:validators.noLogo(!1),OTHER_HARD_RESET_PAGE:validators.hardResetPage(!1),OTHER_BROWSER_SHELL_MODE:validators.browserShellMode(!1),OTHER_VALIDATION:validators.validation(!1),DEBUG_ENABLE:validators.enableDebug(!1),DEBUG_HEADLESS:validators.headless(!1),DEBUG_DEVTOOLS:validators.devtools(!1),DEBUG_LISTEN_TO_CONSOLE:validators.listenToConsole(!1),DEBUG_DUMPIO:validators.dumpio(!1),DEBUG_SLOW_MO:validators.slowMo(!1),DEBUG_DEBUGGING_PORT:validators.debuggingPort(!1)}),envs=EnvSchema.partial().parse(process.env);function strictValidate(e){return StrictConfigSchema.partial().parse(e)}function looseValidate(e){return LooseConfigSchema.partial().parse(e)}function _customErrorMap(e,t){const o=e.path.join("."),r=`Invalid value for the ${o}`;if(e.code===zod.z.ZodIssueCode.invalid_type)return e.received===zod.z.ZodParsedType.undefined?{message:`${r} - No value was provided.`}:{message:`${r} - Invalid type. ${t.defaultError}.`};if(e.code===zod.z.ZodIssueCode.custom&&e.params?.errorMessage)return{message:`${r} - ${e.params?.errorMessage}, received '${t.data}'.`};if(e.code===zod.z.ZodIssueCode.invalid_union){let t=`Multiple errors occurred for the ${o}:\n`;return e.unionErrors.forEach((e=>{const o=e.issues[0].message.indexOf("-");t+=-1!==o?`${e.issues[0].message}\n`.substring(o):`${e.issues[0].message}\n`})),{message:t}}return{message:`${r} - ${t.defaultError}.`}}class ExportError extends Error{constructor(e,t){super(),this.message=e,this.stackMessage=e,t&&(this.statusCode=t)}setError(e){return this.error=e,e.name&&(this.name=e.name),e.statusCode&&(this.statusCode=e.statusCode),e.stack&&(this.stackMessage=e.message,this.stack=e.stack),this}}const globalOptions=_initOptions(defaultConfig),nestedProps=_createNestedProps(defaultConfig),absoluteProps=_createAbsoluteProps(defaultConfig);function getOptions(e=!0){return e?deepCopy(globalOptions):globalOptions}function updateOptions(e,t=!1,o=!0){return _mergeOptions(getOptions(t),validateOptions(e,o))}function mapToNewOptions(e){const t={};if(isObject(e))for(const[o,r]of Object.entries(e)){const e=nestedProps[o]?nestedProps[o].split("."):[];e.reduce(((t,o,n)=>t[o]=e.length-1===n?r:t[o]||{}),t)}else log(2,"[config] No correct object with options was provided. Returning an empty object.");return t}function validateOption(e,t,o=!0){if(!getOptions().other.validation)return t;try{return validators[e](o).parse(t)}catch(t){throw logZodIssues(1,t.issues,`[validation] The ${e} option validation error`),new ExportError(`[validation] The ${e} option validation error`,400)}}function validateOptions(e,t=!0){if(!getOptions().other.validation)return e;try{return t?strictValidate(e):looseValidate(e)}catch(e){throw logZodIssues(1,e.issues,"[validation] Options validation error"),new ExportError("[validation] Options validation error",400)}}function isAllowedConfig(config,toString=!1,allowFunctions=!1){try{if(!isObject(config)&&"string"!=typeof config)return null;const objectConfig="string"==typeof config?allowFunctions?eval(`(${config})`):JSON.parse(config):config,stringifiedOptions=_optionsStringify(objectConfig,allowFunctions,!1),parsedOptions=allowFunctions?JSON.parse(_optionsStringify(objectConfig,allowFunctions,!0),((_,value)=>"string"==typeof value&&value.startsWith("function")?eval(`(${value})`):value)):JSON.parse(stringifiedOptions);return toString?stringifiedOptions:parsedOptions}catch(e){return null}}function _initOptions(e){const t={};for(const[o,r]of Object.entries(e))Object.prototype.hasOwnProperty.call(r,"value")?void 0!==envs[r.envLink]&&null!==envs[r.envLink]?t[o]=envs[r.envLink]:t[o]=r.value:t[o]=_initOptions(r);return t}function _mergeOptions(e,t){if(isObject(e)&&isObject(t))for(const[o,r]of Object.entries(t))e[o]=isObject(r)&&!absoluteProps.includes(o)&&void 0!==e[o]?_mergeOptions(e[o],r):void 0!==r?r:e[o]||null;return e}function _optionsStringify(e,t,o){return JSON.stringify(e,((e,r)=>{if("string"==typeof r&&(r=r.trim()),"function"==typeof r||"string"==typeof r&&r.startsWith("function")&&r.endsWith("}")){if(t)return o?`"EXP_FUN${(r+"").replaceAll(/\s+/g," ")}EXP_FUN"`:`EXP_FUN${(r+"").replaceAll(/\s+/g," ")}EXP_FUN`;throw new Error}return r})).replaceAll(o?/\\"EXP_FUN|EXP_FUN\\"/g:/"EXP_FUN|EXP_FUN"/g,"")}function _createNestedProps(e,t={},o=""){return Object.keys(e).forEach((r=>{const n=e[r];void 0===n.value?_createNestedProps(n,t,`${o}.${r}`):(t[n.cliName||r]=`${o}.${r}`.substring(1),void 0!==n.legacyName&&(t[n.legacyName]=`${o}.${r}`.substring(1)))})),t}function _createAbsoluteProps(e,t=[]){return Object.keys(e).forEach((o=>{const r=e[o];void 0===r.types?_createAbsoluteProps(r,t):r.types.includes("Object")&&t.push(o)})),t}async function get$1(e,t={}){return new Promise(((o,r)=>{_getProtocolModule(e).get(e,t,(e=>{let t="";e.on("data",(e=>{t+=e})),e.on("end",(()=>{t||r("Nothing was fetched from the URL."),e.text=t,o(e)}))})).on("error",(e=>{r(e)}))}))}function _getProtocolModule(e){return e.startsWith("https")?https:http}const cache={cdnUrl:"https://code.highcharts.com",activeManifest:{},sources:"",hcVersion:""};async function checkCache(e,t){try{let o;const r=getCachePath(),n=path.join(r,"manifest.json"),i=path.join(r,"sources.js");if(!fs.existsSync(r)&&fs.mkdirSync(r,{recursive:!0}),!fs.existsSync(n)||e.forceFetch)log(3,"[cache] Fetching and caching Highcharts dependencies."),o=await _updateCache(e,t,i);else{let r=!1;const s=JSON.parse(fs.readFileSync(n),"utf8");if(s.modules&&Array.isArray(s.modules)){const e={};s.modules.forEach((t=>e[t]=1)),s.modules=e}const{coreScripts:a,moduleScripts:l,indicatorScripts:c}=e,p=a.length+l.length+c.length;s.version!==e.version?(log(2,"[cache] A Highcharts version mismatch in the cache, need to re-fetch."),r=!0):Object.keys(s.modules||{}).length!==p?(log(2,"[cache] The cache and the requested modules do not match, need to re-fetch."),r=!0):r=(l||[]).some((e=>{if(!s.modules[e])return log(2,`[cache] The ${e} is missing in the cache, need to re-fetch.`),!0})),r?o=await _updateCache(e,t,i):(log(3,"[cache] Dependency cache is up to date, proceeding."),cache.sources=fs.readFileSync(i,"utf8"),o=s.modules,cache.hcVersion=_extractHcVersion(cache.sources))}await _saveConfigToManifest(e.version,o)}catch(e){throw new ExportError("[cache] Could not configure cache and create or update the config manifest.",500).setError(e)}}function getHcVersion(){return cache.hcVersion}async function updateHcVersion(e){const t=updateOptions({highcharts:{version:e}});await checkCache(t.highcharts,t.server.proxy)}function getCachePath(){return getAbsolutePath(getOptions().highcharts.cachePath)}async function _saveConfigToManifest(e,t={}){cache.activeManifest={version:e,modules:t},log(3,"[cache] Writing a new manifest.");try{fs.writeFileSync(path.join(getCachePath(),"manifest.json"),JSON.stringify(cache.activeManifest),"utf8")}catch(e){throw new ExportError("[cache] Error writing the cache manifest.",500).setError(e)}}async function _updateCache(e,t,o){try{const r="latest"===e.version?null:`${e.version}`;log(3,`[cache] Updating cache version to Highcharts: ${r||"latest"}.`);const n=e.cdnUrl||cache.cdnUrl,i=_configureRequest(t),s={};return cache.sources=(await Promise.all([...e.coreScripts.map((e=>_fetchScript(r?`${n}/${r}/${e}`:`${n}/${e}`,i,s,!0))),...e.moduleScripts.map((e=>_fetchScript("map"===e?r?`${n}/maps/${r}/modules/${e}`:`${n}/maps/modules/${e}`:r?`${n}/${r}/modules/${e}`:`${n}/modules/${e}`,i,s))),...e.indicatorScripts.map((e=>_fetchScript(r?`${n}/stock/${r}/indicators/${e}`:`${n}/stock/indicators/${e}`,i,s))),...e.customScripts.map((e=>_fetchScript(`${e}`,i)))])).join(";\n"),cache.hcVersion=_extractHcVersion(cache.sources),fs.writeFileSync(o,cache.sources),s}catch(e){throw new ExportError("[cache] Unable to update the local Highcharts cache.",500).setError(e)}}async function _fetchScript(e,t,o,r=!1){e.endsWith(".js")&&(e=e.substring(0,e.length-3)),log(4,`[cache] Fetching script - ${e}.js`);const n=await get$1(`${e}.js`,t);if(200===n.statusCode&&"string"==typeof n.text){if(o){o[_extractModuleName(e)]=1}return n.text}if(r)throw new ExportError(`[cache] Could not fetch the ${e}.js. The script might not exist in the requested version (status code: ${n.statusCode}).`,404).setError(n);log(2,`[cache] Could not fetch the ${e}.js. The script might not exist in the requested version.`)}function _configureRequest(e){const t=e.host,o=e.port;if(t&&o)try{return{agent:new httpsProxyAgent.HttpsProxyAgent({host:t,port:o}),timeout:e.timeout}}catch(e){throw new ExportError("[cache] Could not create a Proxy Agent.",500).setError(e)}return{}}function _extractHcVersion(e){return e.substring(0,e.indexOf("*/")).replace("/*","").replace("*/","").replace(/\n/g,"").trim()}function _extractModuleName(e){return e.replace(/(.*)\/|(.*)modules\/|stock\/(.*)indicators\/|maps\/(.*)modules\//gi,"")}function setupHighcharts(){Highcharts.animObject=function(){return{duration:0}}}async function createChart(e,t){const{getOptions:o,setOptions:r,merge:n,wrap:i}=Highcharts;Highcharts.setOptionsObj=n(!1,{},o()),window.isRenderComplete=!1,i(Highcharts.Chart.prototype,"init",(function(e,t,o){((t=n(t,{exporting:{enabled:!1},plotOptions:{series:{label:{enabled:!1}}},tooltip:{}})).series||[]).forEach((function(e){e.animation=!1})),window.onHighchartsRender||(window.onHighchartsRender=Highcharts.addEvent(this,"render",(()=>{window.isRenderComplete=!0}))),e.apply(this,[t,o])})),i(Highcharts.Series.prototype,"init",(function(e,t,o){e.apply(this,[t,o])}));const s={chart:{animation:!1,height:e.height,width:e.width},exporting:{enabled:!1}},a=new Function(`return ${e.instr}`)(),l=new Function(`return ${e.themeOptions}`)(),c=n(!1,l,a,s),p=t.callback?new Function(`return ${t.callback}`)():null;t.customCode&&new Function("options",t.customCode)(a);const u=new Function(`return ${e.globalOptions}`)();u&&r(u),Highcharts[e.constr]("container",c,p);const d=Array.from(document.querySelectorAll(".highcharts-container image"));await Promise.race([Promise.all(d.map((e=>e.complete&&0!==e.naturalHeight?Promise.resolve():new Promise((t=>e.addEventListener("load",t,{once:!0})))))),new Promise((e=>setTimeout(e,2e3)))]);const g=o();for(const e in g)"function"!=typeof g[e]&&delete g[e];r(Highcharts.setOptionsObj),Highcharts.setOptionsObj={}}const pageTemplate=fs.readFileSync(path.join(__dirname$1,"templates","template.html"),"utf8");let browser=null;async function createBrowser(e){const{debug:t,other:o}=getOptions(),{enable:r,...n}=t,i={headless:!o.browserShellMode||"shell",userDataDir:"tmp",args:e||[],handleSIGINT:!1,handleSIGTERM:!1,handleSIGHUP:!1,waitForInitialPage:!1,defaultViewport:null,...r&&n};if(!browser){let e=0;const t=async()=>{try{log(3,`[browser] Attempting to launch and get a browser instance (try ${++e}).`),browser=await puppeteer.launch(i)}catch(o){if(logWithStack(1,o,"[browser] Failed to launch a browser instance."),!(e<25))throw o;log(3,`[browser] Retry to open a browser (${e} out of 25).`),await new Promise((e=>setTimeout(e,4e3))),await t()}};try{await t(),"shell"===i.headless&&log(3,"[browser] Launched browser in shell mode."),r&&log(3,"[browser] Launched browser in debug mode.")}catch(e){throw new ExportError("[browser] Maximum retries to open a browser instance reached.",500).setError(e)}if(!browser)throw new ExportError("[browser] Cannot find a browser to open.",500)}return browser}async function closeBrowser(){browser&&browser.connected&&await browser.close(),browser=null,log(4,"[browser] Closed the browser.")}async function newPage(e){if(!browser||!browser.connected)throw new ExportError("[browser] Browser is not yet connected.",500);if(e.page=await browser.newPage(),await e.page.setCacheEnabled(!1),await _setPageContent(e.page),_setPageEvents(e.page),!e.page||e.page.isClosed())throw new ExportError("[browser] The page is invalid or closed.",400)}async function clearPage(e,t=!1){try{if(e.page&&!e.page.isClosed())return t?(await e.page.goto("about:blank",{waitUntil:"domcontentloaded"}),await _setPageContent(e.page)):await e.page.evaluate((()=>{document.body.innerHTML='
'})),!0}catch(t){logWithStack(2,t,`[pool] Pool resource [${e.id}] - Content of the page could not be cleared.`),e.workCount=getOptions().pool.workLimit+1}return!1}async function addPageResources(e,t){const o=[],r=t.resources;if(r){const n=[];if(r.js&&n.push({content:r.js}),r.files)for(const e of r.files){const t=!e.startsWith("http");n.push(t?{content:fs.readFileSync(getAbsolutePath(e),"utf8")}:{url:e})}for(const t of n)try{o.push(await e.addScriptTag(t))}catch(e){logWithStack(2,e,"[browser] The JS resource cannot be loaded.")}n.length=0;const i=[];if(r.css){const n=r.css.match(/@import\s*([^;]*);/g);if(n)for(let e of n)e&&(e=e.replace("url(","").replace("@import","").replace(/"/g,"").replace(/'/g,"").replace(/;/,"").replace(/\)/g,"").trim(),e.startsWith("http")?i.push({url:e}):t.allowFileResources&&i.push({path:getAbsolutePath(e)}));i.push({content:r.css.replace(/@import\s*([^;]*);/g,"")||" "});for(const t of i)try{o.push(await e.addStyleTag(t))}catch(e){logWithStack(2,e,"[browser] The CSS resource cannot be loaded.")}i.length=0}}return o}async function clearPageResources(e,t){try{for(const e of t)await e.dispose();await e.evaluate((()=>{if("undefined"!=typeof Highcharts){const e=Highcharts.charts;if(Array.isArray(e)&&e.length)for(const t of e)t&&t.destroy(),Highcharts.charts.shift()}const[...e]=document.getElementsByTagName("script"),[,...t]=document.getElementsByTagName("style"),[...o]=document.getElementsByTagName("link");for(const r of[...e,...t,...o])r.remove()}))}catch(e){logWithStack(2,e,"[browser] Could not clear page's resources.")}}async function _setPageContent(e){await e.setContent(pageTemplate,{waitUntil:"domcontentloaded"}),await e.addScriptTag({path:path.join(getCachePath(),"sources.js")}),await e.evaluate(setupHighcharts)}function _setPageEvents(e){const{debug:t}=getOptions();e.on("pageerror",(async()=>{e.isClosed()})),t.enable&&t.listenToConsole&&e.on("console",(e=>{console.log(`[debug] ${e.text()}`)}))}var cssTemplate=()=>"\n\nhtml, body {\n margin: 0;\n padding: 0;\n box-sizing: border-box;\n}\n\n#table-div, #sliders, #datatable, #controls, .ld-row {\n display: none;\n height: 0;\n}\n\n#chart-container {\n box-sizing: border-box;\n margin: 0;\n overflow: auto;\n font-size: 0;\n}\n\n#chart-container > figure, div {\n margin-top: 0 !important;\n margin-bottom: 0 !important;\n}\n\n",svgTemplate=e=>`\n\n\n \n \n Highcharts Export\n \n \n \n
\n ${e}\n
\n \n\n\n`;async function puppeteerExport(e,t,o){const r=[];try{let n=!1;if(t.svg){if(log(4,"[export] Treating as SVG input."),"svg"===t.type)return t.svg;n=!0,await e.setContent(svgTemplate(t.svg),{waitUntil:"domcontentloaded"})}else log(4,"[export] Treating as JSON config."),await e.evaluate(createChart,t,o);r.push(...await addPageResources(e,o));const i=await _getChartSize(e,n,t.scale),{x:s,y:a}=await _getClipRegion(e),l=Math.abs(Math.ceil(i.chartHeight||t.height)),c=Math.abs(Math.ceil(i.chartWidth||t.width));let p;switch(await e.setViewport({height:l,width:c,deviceScaleFactor:n?1:parseFloat(t.scale)}),t.type){case"svg":p=await _createSVG(e);break;case"png":case"jpeg":p=await _createImage(e,t.type,{width:c,height:l,x:s,y:a},t.rasterizationTimeout);break;case"pdf":p=await _createPDF(e,l,c,t.rasterizationTimeout);break;default:throw new ExportError(`[export] Unsupported output format: ${t.type}.`,400)}return await clearPageResources(e,r),p}catch(t){return await clearPageResources(e,r),t}}async function _getClipRegion(e){return e.$eval("#chart-container",(e=>{const{x:t,y:o,width:r,height:n}=e.getBoundingClientRect();return{x:t,y:o,width:r,height:Math.trunc(n>1?n:500)}}))}async function _getChartSize(e,t,o){return t?await e.evaluate((e=>{const t=document.querySelector("#chart-container svg:first-of-type"),o=t.height.baseVal.value*e,r=t.width.baseVal.value*e;return document.body.style.zoom=e,document.body.style.margin="0px",{chartHeight:o,chartWidth:r}}),parseFloat(o)):await e.evaluate((()=>{const{chartHeight:e,chartWidth:t}=window.Highcharts.charts[0];return document.body.style.zoom=1,{chartHeight:e,chartWidth:t}}))}async function _createSVG(e){return e.$eval("#container svg:first-of-type",(e=>e.outerHTML))}async function _createImage(e,t,o,r){return Promise.race([e.screenshot({type:t,clip:o,encoding:"base64",fullPage:!1,optimizeForSpeed:!0,captureBeyondViewport:!0,..."png"!==t?{quality:80}:{},omitBackground:"png"==t}),new Promise(((e,t)=>setTimeout((()=>t(new ExportError("Rasterization timeout",408))),r||1500)))])}async function _createPDF(e,t,o,r){return await e.emulateMediaType("screen"),e.pdf({height:t+1,width:o,encoding:"base64",timeout:r||1500})}let pool=null;const poolStats={exportsAttempted:0,exportsPerformed:0,exportsDropped:0,exportsFromSvg:0,exportsFromOptions:0,exportsFromSvgAttempts:0,exportsFromOptionsAttempts:0,timeSpent:0,timeSpentAverage:0};async function initPool(e,t){await createBrowser(t);try{if(log(3,`[pool] Initializing pool with workers: min ${e.minWorkers}, max ${e.maxWorkers}.`),pool)return void log(4,"[pool] Already initialized, please kill it before creating a new one.");e.minWorkers>e.maxWorkers&&(e.minWorkers=e.maxWorkers),pool=new tarn.Pool({..._factory(e),min:e.minWorkers,max:e.maxWorkers,acquireTimeoutMillis:e.acquireTimeout,createTimeoutMillis:e.createTimeout,destroyTimeoutMillis:e.destroyTimeout,idleTimeoutMillis:e.idleTimeout,createRetryIntervalMillis:e.createRetryInterval,reapIntervalMillis:e.reaperInterval,propagateCreateError:!1}),pool.on("release",(async e=>{const t=await clearPage(e,!1);log(4,`[pool] Pool resource [${e.id}] - Releasing a worker. Clear page status: ${t}.`)})),pool.on("destroySuccess",((e,t)=>{log(4,`[pool] Pool resource [${t.id}] - Destroyed a worker successfully.`),t.page=null}));const t=[];for(let o=0;o{pool.release(e)})),log(3,"[pool] The pool is ready"+(t.length?` with ${t.length} initial resources waiting.`:"."))}catch(e){throw new ExportError("[pool] Could not configure and create the pool of workers.",500).setError(e)}}async function killPool(){if(log(3,"[pool] Killing pool with all workers and closing browser."),pool){for(const e of pool.used)pool.release(e.resource);pool.destroyed||(await pool.destroy(),log(4,"[pool] Destroyed the pool of resources.")),pool=null}await closeBrowser()}async function postWork(e){let t;try{if(log(4,"[pool] Work received, starting to process."),++poolStats.exportsAttempted,e.pool.benchmarking&&_getPoolInfo(),!pool)throw new ExportError("[pool] Work received, but pool has not been started.",500);const o=measureTime();try{log(4,"[pool] Acquiring a worker handle."),t=await pool.acquire().promise,e.server.benchmarking&&log(5,"[benchmark] "+(e.requestId?`Request [${e.requestId}] - `:""),`Acquiring a worker handle took ${o()}ms.`)}catch(t){throw new ExportError(`[pool] ${e.requestId?`Request [${e.requestId}] - `:""}Error encountered when acquiring an available entry: ${o()}ms.`,400).setError(t)}if(log(4,"[pool] Acquired a worker handle."),!t.page)throw t.workCount=e.pool.workLimit+1,new ExportError("[pool] Resolved worker page is invalid: the pool setup is wonky.",400);log(4,`[pool] Pool resource [${t.id}] - Starting work on this pool entry.`);const r=measureTime(),n=await puppeteerExport(t.page,e.export,e.customLogic);if(n instanceof Error)throw"Rasterization timeout"===n.message&&(t.workCount=e.pool.workLimit+1,t.page=null),"TimeoutError"===n.name||"Rasterization timeout"===n.message?new ExportError(`[pool] ${e.requestId?`Request [${e.requestId}] - `:""}Rasterization timeout: your chart may be too complex or large, and failed to render within the allotted time.`).setError(n):new ExportError(`[pool] ${e.requestId?`Request [${e.requestId}] - `:""}Error encountered during export: ${r()}ms.`).setError(n);return e.server.benchmarking&&log(5,"[benchmark] "+(e.requestId?`Request [${e.requestId}] - `:""),`Exporting a chart sucessfully took ${r()}ms.`),pool.release(t),poolStats.timeSpent+=r(),poolStats.timeSpentAverage=poolStats.timeSpent/++poolStats.exportsPerformed,log(4,`[pool] Work completed in ${r()}ms.`),{result:n,options:e}}catch(e){throw++poolStats.exportsDropped,t&&pool.release(t),e}}function getPoolStats(){return poolStats}function getPoolInfoJSON(){return{min:pool.min,max:pool.max,used:pool.numUsed(),available:pool.numFree(),allCreated:pool.numUsed()+pool.numFree(),pendingAcquires:pool.numPendingAcquires(),pendingCreates:pool.numPendingCreates(),pendingValidations:pool.numPendingValidations(),pendingDestroys:pool.pendingDestroys.length,absoluteAll:pool.numUsed()+pool.numFree()+pool.numPendingAcquires()+pool.numPendingCreates()+pool.numPendingValidations()+pool.pendingDestroys.length}}function _getPoolInfo(){const{min:e,max:t,used:o,available:r,allCreated:n,pendingAcquires:i,pendingCreates:s,pendingValidations:a,pendingDestroys:l,absoluteAll:c}=getPoolInfoJSON();log(5,`[pool] The minimum number of resources allowed by pool: ${e}.`),log(5,`[pool] The maximum number of resources allowed by pool: ${t}.`),log(5,`[pool] The number of used resources: ${o}.`),log(5,`[pool] The number of free resources: ${r}.`),log(5,`[pool] The number of all created (used and free) resources: ${n}.`),log(5,`[pool] The number of resources waiting to be acquired: ${i}.`),log(5,`[pool] The number of resources waiting to be created: ${s}.`),log(5,`[pool] The number of resources waiting to be validated: ${a}.`),log(5,`[pool] The number of resources waiting to be destroyed: ${l}.`),log(5,`[pool] The number of all resources: ${c}.`)}function _factory(e){return{create:async()=>{const t={id:uuid.v4(),workCount:Math.round(Math.random()*(e.workLimit/2))};try{const e=getNewDateTime();return await newPage(t),log(3,`[pool] Pool resource [${t.id}] - Successfully created a worker, took ${getNewDateTime()-e}ms.`),t}catch(e){throw log(3,`[pool] Pool resource [${t.id}] - Error encountered when creating a new page.`),e}},validate:async t=>t.page?t.page.isClosed()?(log(3,`[pool] Pool resource [${t.id}] - Validation failed (page is closed or invalid).`),!1):t.page.mainFrame().detached?(log(3,`[pool] Pool resource [${t.id}] - Validation failed (page's frame is detached).`),!1):!(e.workLimit&&++t.workCount>e.workLimit)||(log(3,`[pool] Pool resource [${t.id}] - Validation failed (exceeded the ${e.workLimit} works per resource limit).`),!1):(log(3,`[pool] Pool resource [${t.id}] - Validation failed (no valid page is found).`),!1),destroy:async e=>{if(log(3,`[pool] Pool resource [${e.id}] - Destroying a worker.`),e.page&&!e.page.isClosed())try{e.page.removeAllListeners("pageerror"),e.page.removeAllListeners("console"),e.page.removeAllListeners("framedetached"),await e.page.close()}catch(t){throw log(3,`[pool] Pool resource [${e.id}] - Page could not be closed upon destroying.`),t}}}}function sanitize(e){const t=new jsdom.JSDOM("").window;return DOMPurify(t).sanitize(e,{ADD_TAGS:["foreignObject"]})}let allowCodeExecution=!1;async function singleExport(e){if(!e||!e.export)throw new ExportError("[chart] No expected `export` options were found. Please provide one of the following options: `infile`, `instr`, `options`, or `svg` to generate a valid image.",400);await startExport({export:e.export,customLogic:e.customLogic},(async(e,t)=>{if(e)throw e;const{b64:o,outfile:r,type:n}=t.options.export;try{o?fs.writeFileSync(`${r.split(".").shift()||"chart"}.txt`,getBase64(t.result,n)):fs.writeFileSync(r||`chart.${n}`,"svg"!==n?Buffer.from(t.result,"base64"):t.result)}catch(e){throw new ExportError("[chart] Error while saving a chart.",500).setError(e)}await killPool()}))}async function batchExport(e){if(!(e&&e.export&&e.export.batch))throw new ExportError("[chart] No expected `export` options were found. Please provide the `batch` option to generate valid images.",400);{const t=[];for(let o of e.export.batch.split(";")||[])o=o.split("="),2===o.length?t.push(startExport({export:{...e.export,infile:o[0],outfile:o[1]},customLogic:e.customLogic},((e,t)=>{if(e)throw e;const{b64:o,outfile:r,type:n}=t.options.export;try{o?fs.writeFileSync(`${r.split(".").shift()||"chart"}.txt`,getBase64(t.result,n)):fs.writeFileSync(r,"svg"!==n?Buffer.from(t.result,"base64"):t.result)}catch(e){throw new ExportError("[chart] Error while saving a chart.",500).setError(e)}}))):log(2,"[chart] No correct pair found for the batch export.");const o=await Promise.allSettled(t);await killPool(),o.forEach(((e,t)=>{e.reason&&logWithStack(1,e.reason,`[chart] Batch export number ${t+1} could not be correctly completed.`)}))}}async function startExport(e,t){try{if(!isObject(e))throw new ExportError("[chart] Incorrect value of the provided `imageOptions`. Needs to be an object.",400);const o=updateOptions({export:e.export,customLogic:e.customLogic},!0),r=o.export;if(log(4,"[chart] Starting the exporting process."),null!==r.infile){let e;log(4,"[chart] Attempting to export from a file input.");try{e=fs.readFileSync(getAbsolutePath(r.infile),"utf8")}catch(e){throw new ExportError("[chart] Error loading content from a file input.",400).setError(e)}if(r.infile.endsWith(".svg"))r.svg=validateOption("svg",e);else{if(!r.infile.endsWith(".json"))throw new ExportError("[chart] Incorrect value of the `infile` option.",400);r.instr=validateOption("instr",e)}}if(null!==r.svg){log(4,"[chart] Attempting to export from an SVG input."),++getPoolStats().exportsFromSvgAttempts;const e=await _exportFromSvg(sanitize(r.svg),o);return++getPoolStats().exportsFromSvg,t(null,e)}if(null!==r.instr||null!==r.options){log(4,"[chart] Attempting to export from options input."),++getPoolStats().exportsFromOptionsAttempts;const e=await _exportFromOptions(r.instr||r.options,o);return++getPoolStats().exportsFromOptions,t(null,e)}return t(new ExportError("[chart] No valid input specified. Check if at least one of the following parameters is correctly set: 'infile', 'instr', 'options', or 'svg'.",400))}catch(e){return t(e)}}function getAllowCodeExecution(){return allowCodeExecution}function setAllowCodeExecution(e){allowCodeExecution=e}async function _exportFromSvg(e,t){if("string"==typeof e&&(e.indexOf("=0||e.indexOf("=0))return log(4,"[chart] Parsing input as SVG."),t.export.svg=e,t.export.options=null,t.export.instr=null,_prepareExport(t);throw new ExportError("[chart] Not a correct SVG input.",400)}async function _exportFromOptions(e,t){log(4,"[chart] Parsing input from options.");const o=isAllowedConfig(e,!0,t.customLogic.allowCodeExecution);if(null===o||"string"!=typeof o||!o.startsWith("{")||!o.endsWith("}"))throw new ExportError("[chart] Invalid configuration provided - Only options configurations and SVG are allowed for this server. If this is your server, JavaScript custom code can be enabled by starting the server with the `allowCodeExecution` options set to true.",403);return t.export.instr=o,t.export.options=null,t.export.svg=null,_prepareExport(t)}async function _prepareExport(e){const{export:t,customLogic:o}=e;return t.constr=_fixConstr(t.constr),t.type=_fixType(t.type,t.outfile),t.outfile=_fixOutfile(t.type,t.outfile),log(3,`[chart] The custom logic is ${o.allowCodeExecution?"allowed":"disallowed"}.`),_handleCustomLogic(o),_handleGlobalAndTheme(t,o),_handleSize(t),_checkDataSize({export:t,customLogic:o}),postWork(e)}function _fixConstr(e){try{const t=`${e.toLowerCase().replace("chart","")}Chart`;return"Chart"===t&&t.toLowerCase(),["chart","stockChart","mapChart","ganttChart"].includes(t)?t:"chart"}catch{return"chart"}}function _fixOutfile(e,t){return`${getAbsolutePath(t||"chart").split(".").shift()}.${e||"png"}`}function _fixType(e,t=null){const o={"image/png":"png","image/jpeg":"jpeg","application/pdf":"pdf","image/svg+xml":"svg"},r=Object.values(o);if(t){const o=t.split(".").pop();"jpg"===o?e="jpeg":r.includes(o)&&e!==o&&(e=o)}return o[e]||r.find((t=>t===e))||"png"}function _handleSize(e){const{chart:t,exporting:o}=isAllowedConfig(e.instr)||!1,{chart:r,exporting:n}=isAllowedConfig(e.globalOptions)||!1,{chart:i,exporting:s}=isAllowedConfig(e.themeOptions)||!1,a=e.height||o?.sourceHeight||t?.height||n?.sourceHeight||r?.height||s?.sourceHeight||i?.height||e.defaultHeight||400,l=e.width||o?.sourceWidth||t?.width||n?.sourceWidth||r?.width||s?.sourceWidth||i?.width||e.defaultWidth||600,c=roundNumber(Math.max(.1,Math.min(e.scale||o?.scale||n?.scale||s?.scale||e.defaultScale||1,5)),2);e.height=a,e.width=l,e.scale=c;for(let t of["height","width","scale"])"string"==typeof e[t]&&(e[t]=+e[t].replace(/px|%/gi,""))}function _handleCustomLogic(e){if(e.allowCodeExecution){try{e.resources=_handleResources(e.resources,e.allowFileResources,!0)}catch(t){log(2,"[chart] The `resources` cannot be loaded."),e.resources=null}try{e.customCode=_handleCustomCode(e.customCode,e.allowFileResources),e.customCode=validateOption("customCode",e.customCode)}catch(t){logWithStack(2,t,"[chart] The `customCode` cannot be loaded."),e.customCode=null}try{e.callback=_handleCustomCode(e.callback,e.allowFileResources,!0),e.callback=validateOption("callback",e.callback)}catch(t){logWithStack(2,t,"[chart] The `callback` cannot be loaded."),e.callback=null}[null,void 0].includes(e.customCode)&&log(3,"[chart] No value for the `customCode` option found."),[null,void 0].includes(e.callback)&&log(3,"[chart] No value for the `callback` option found."),[null,void 0].includes(e.resources)&&log(3,"[chart] No value for the `resources` option found.")}else if(e.callback||e.resources||e.customCode)throw e.callback=null,e.resources=null,e.customCode=null,new ExportError("[chart] The 'callback', 'resources', and 'customCode' options have been disabled for this server.",403)}function _handleResources(e=null,t,o){let r=e;r||(e="resources.json");const n=["js","css","files"];let i=!1;t&&"string"==typeof e&&e.endsWith(".json")?r=isAllowedConfig(fs.readFileSync(getAbsolutePath(e),"utf8"),!1,o):(r=isAllowedConfig(e,!1,o),r&&!t&&delete r.files);for(const e in r)n.includes(e)?i||(i=!0):delete r[e];return i?(r.files&&(r.files=r.files.map((e=>e.trim())),(!r.files||r.files.length<=0)&&delete r.files),r=validateOption("resources",r),r):null}function _handleCustomCode(e,t,o=!1){if(e&&"string"==typeof e)return(e=e.trim()).endsWith(".js")?t?_handleCustomCode(fs.readFileSync(getAbsolutePath(e),"utf8"),t,o):null:!o&&(e.startsWith("function()")||e.startsWith("function ()")||e.startsWith("()=>")||e.startsWith("() =>"))?`(${e})()`:e.replace(/;$/,"")}function _handleGlobalAndTheme(e,t){const{allowFileResources:o,allowCodeExecution:r}=t;["globalOptions","themeOptions"].forEach((t=>{try{e[t]&&(o&&"string"==typeof e[t]&&e[t].endsWith(".json")?e[t]=isAllowedConfig(fs.readFileSync(getAbsolutePath(e[t]),"utf8"),!0,r):e[t]=isAllowedConfig(e[t],!0,r),e[t]=validateOption(t,e[t]))}catch(o){logWithStack(2,o,`[chart] The \`${t}\` cannot be loaded.`),e[t]=null}})),[null,void 0].includes(e.globalOptions)&&log(3,"[chart] No value for the `globalOptions` option found."),[null,void 0].includes(e.themeOptions)&&log(3,"[chart] No value for the `themeOptions` option found.")}function _checkDataSize(e){const t=Buffer.byteLength(JSON.stringify(e),"utf-8");if(log(3,`[chart] The current total size of the data for the export process is around ${(t/1048576).toFixed(2)}MB.`),t>=104857600)throw new ExportError("[chart] The data for the export process exceeds 100MB limit.")}const timerIds=[];function addTimer(e){timerIds.push(e)}function clearAllTimers(){log(4,"[timer] Clearing all registered intervals and timeouts.");for(const e of timerIds)clearInterval(e),clearTimeout(e)}function logErrorMiddleware(e,t,o,r){return logWithStack(1,e),"development"!==getOptions().other.nodeEnv&&delete e.stack,r(e)}function returnErrorMiddleware(e,t,o,r){const{message:n,stack:i}=e,s=e.statusCode||400;o.status(s).json({statusCode:s,message:n,stack:i})}function errorMiddleware(e){e.use(logErrorMiddleware),e.use(returnErrorMiddleware)}function rateLimitingMiddleware(e,t){try{if(e&&t.enable){const o="Too many requests, you have been rate limited. Please try again later.",r={window:t.window||1,maxRequests:t.maxRequests||30,delay:t.delay||0,trustProxy:t.trustProxy||!1,skipKey:t.skipKey||null,skipToken:t.skipToken||null};r.trustProxy&&e.enable("trust proxy");const n=rateLimit({windowMs:60*r.window*1e3,limit:r.maxRequests,delayMs:r.delay,handler:(e,t)=>{t.format({json:()=>{t.status(429).send({message:o})},default:()=>{t.status(429).send(o)}})},skip:e=>null!==r.skipKey&&null!==r.skipToken&&e.query.key===r.skipKey&&e.query.access_token===r.skipToken&&(log(4,"[rate limiting] Skipping rate limiter."),!0)});e.use(n),log(3,`[rate limiting] Enabled rate limiting with ${r.maxRequests} requests per ${r.window} minute for each IP, trusting proxy: ${r.trustProxy}.`)}}catch(e){throw new ExportError("[rate limiting] Could not configure and set the rate limiting options.",500).setError(e)}}function contentTypeMiddleware(e,t,o){try{const t=e.headers["content-type"]||"";if(!t.includes("application/json")&&!t.includes("application/x-www-form-urlencoded")&&!t.includes("multipart/form-data"))throw new ExportError("[validation] Content-Type must be application/json, application/x-www-form-urlencoded, or multipart/form-data.",415);return o()}catch(e){return o(e)}}function requestBodyMiddleware(e,t,o){try{const t=e.body,r=uuid.v4();if(!t||isObjectEmpty(t))throw log(2,`[validation] Request [${r}] - The request from ${e.headers["x-forwarded-for"]||e.connection.remoteAddress} was incorrect. Received payload is empty.`),new ExportError(`[validation] Request [${r}] - The request body is required. Please ensure that your Content-Type header is correct. Accepted types are 'application/json' and 'multipart/form-data'.`,400);const n=getAllowCodeExecution(),i=isAllowedConfig(t.instr||t.options||t.infile||t.data,!0,n);if(null===i&&!t.svg)throw log(2,`[validation] Request [${r}] - The request from ${e.headers["x-forwarded-for"]||e.connection.remoteAddress} was incorrect. Received payload is missing correct chart data for export: ${JSON.stringify(t)}.`),new ExportError(`[validation] Request [${r}] - No correct chart data found. Ensure that you are using either application/json or multipart/form-data headers. If sending JSON, make sure the chart data is in the 'infile', 'options', or 'data' attribute. If sending SVG, ensure it is in the 'svg' attribute.`,400);if(t.svg&&isPrivateRangeUrlFound(t.svg))throw new ExportError(`[validation] Request [${r}] - SVG potentially contain at least one forbidden URL in 'xlink:href' element. Please review the SVG content and ensure that all referenced URLs comply with security policies.`,400);return e.validatedOptions={requestId:r,export:{instr:i,svg:t.svg,outfile:t.outfile||`${e.params.filename||"chart"}.${t.type||"png"}`,type:t.type,constr:t.constr,b64:t.b64,noDownload:t.noDownload,height:t.height,width:t.width,scale:t.scale,globalOptions:isAllowedConfig(t.globalOptions,!0,n),themeOptions:isAllowedConfig(t.themeOptions,!0,n)},customLogic:{allowCodeExecution:n,allowFileResources:!1,customCode:t.customCode,callback:t.callback,resources:isAllowedConfig(t.resources,!0,n)}},o()}catch(e){return o(e)}}function validationMiddleware(e){e.post(["/","/:filename"],contentTypeMiddleware),e.post(["/","/:filename"],requestBodyMiddleware)}const reversedMime={png:"image/png",jpeg:"image/jpeg",gif:"image/gif",pdf:"application/pdf",svg:"image/svg+xml"};async function requestExport(e,t,o){try{const o=measureTime();let r=!1;e.socket.on("close",(e=>{e&&(r=!0)}));const n=e.validatedOptions,i=n.requestId;log(4,`[export] Request [${i}] - Got an incoming HTTP request.`),await startExport(n,((n,s)=>{if(e.socket.removeAllListeners("close"),r)log(3,`[export] Request [${i}] - The client closed the connection before the chart finished processing.`);else{if(n)throw n;if(!s||!s.result)throw log(2,`[export] Request [${i}] - Request from ${e.headers["x-forwarded-for"]||e.connection.remoteAddress} was incorrect. Received result is ${s.result}.`),new ExportError(`[export] Request [${i}] - Unexpected return of the export result from the chart generation. Please check your request data.`,400);if(s.result){log(3,`[export] Request [${i}] - The whole exporting process took ${o()}ms.`);const{type:e,b64:r,noDownload:n,outfile:a}=s.options.export;return r?t.send(getBase64(s.result,e)):(t.header("Content-Type",reversedMime[e]||"image/png"),n||t.attachment(a),"svg"===e?t.send(s.result):t.send(Buffer.from(s.result,"base64")))}}}))}catch(e){return o(e)}}function exportRoutes(e){e.post("/",requestExport),e.post("/:filename",requestExport)}const serverStartTime=new Date,packageFile=JSON.parse(fs.readFileSync(path.join(__dirname$1,"package.json"),"utf8")),successRates=[],recordInterval=6e4,windowSize=30;function _calculateMovingAverage(){return successRates.reduce(((e,t)=>e+t),0)/successRates.length}function _startSuccessRate(){return setInterval((()=>{const e=getPoolStats(),t=0===e.exportsAttempted?1:e.exportsPerformed/e.exportsAttempted*100;successRates.push(t),successRates.length>windowSize&&successRates.shift()}),recordInterval)}function healthRoutes(e){addTimer(_startSuccessRate()),e.get("/health",((e,t,o)=>{try{log(4,"[health] Returning server health.");const e=getPoolStats(),o=successRates.length,r=_calculateMovingAverage();t.send({status:"OK",bootTime:serverStartTime,uptime:`${Math.floor((getNewDateTime()-serverStartTime.getTime())/1e3/60)} minutes`,serverVersion:packageFile.version,highchartsVersion:getHcVersion(),averageExportTime:e.timeSpentAverage,attemptedExports:e.exportsAttempted,performedExports:e.exportsPerformed,failedExports:e.exportsDropped,sucessRatio:e.exportsPerformed/e.exportsAttempted*100,pool:getPoolInfoJSON(),period:o,movingAverage:r,message:isNaN(r)||!successRates.length?"Too early to report. No exports made yet. Please check back soon.":`Last ${o} minutes had a success rate of ${r.toFixed(2)}%.`,svgExports:e.exportsFromSvg,jsonExports:e.exportsFromOptions,svgExportsAttempts:e.exportsFromSvgAttempts,jsonExportsAttempts:e.exportsFromOptionsAttempts})}catch(e){return o(e)}}))}function uiRoutes(e){getOptions().ui.enable&&e.get(getOptions().ui.route||"/",((e,t,o)=>{try{log(4,"[ui] Returning UI for the export."),t.sendFile(path.join(__dirname$1,"public","index.html"),{acceptRanges:!1})}catch(e){return o(e)}}))}function versionChangeRoutes(e){e.post("/version_change/:newVersion",(async(e,t,o)=>{try{log(4,"[version] Changing Highcharts version.");const o=envs.HIGHCHARTS_ADMIN_TOKEN;if(!o||!o.length)throw new ExportError("[version] The server is not configured to perform run-time version changes: `HIGHCHARTS_ADMIN_TOKEN` is not set.",401);const r=e.get("hc-auth");if(!r||r!==o)throw new ExportError("[version] Invalid or missing token: Set the token in the hc-auth header.",401);const n=e.params.newVersion;if(!n)throw new ExportError("[version] No new version supplied.",400);try{await updateHcVersion(n)}catch(e){throw new ExportError(`[version] Version change: ${e.message}`,400).setError(e)}t.status(200).send({statusCode:200,highchartsVersion:getHcVersion(),message:`Successfully updated Highcharts to version: ${n}.`})}catch(e){return o(e)}}))}const activeServers=new Map,app=express();async function startServer(e){try{const t=updateOptions({server:e});if(!(e=t.server).enable||!app)throw new ExportError("[server] Server cannot be started (not enabled or no correct Express app found).",500);const o=1024*e.uploadLimit*1024,r=multer.memoryStorage(),n=multer({storage:r,limits:{fieldSize:o}});if(app.disable("x-powered-by"),app.use(cors({methods:["POST","GET","OPTIONS"]})),app.use(((e,t,o)=>{t.set("Accept-Ranges","none"),o()})),app.use(express.json({limit:o})),app.use(express.urlencoded({extended:!0,limit:o})),app.use(n.none()),app.use(express.static(path.join(__dirname$1,"public"))),!e.ssl.force){const t=http.createServer(app);_attachServerErrorHandlers(t),t.listen(e.port,e.host,(()=>{activeServers.set(e.port,t),log(3,`[server] Started HTTP server on ${e.host}:${e.port}.`)}))}if(e.ssl.enable){let t,o;try{t=fs.readFileSync(path.join(getAbsolutePath(e.ssl.certPath),"server.key"),"utf8"),o=fs.readFileSync(path.join(getAbsolutePath(e.ssl.certPath),"server.crt"),"utf8")}catch(t){log(2,`[server] Unable to load key/certificate from the '${e.ssl.certPath}' path. Could not run secured layer server.`)}if(t&&o){const r=https.createServer({key:t,cert:o},app);_attachServerErrorHandlers(r),r.listen(e.ssl.port,e.host,(()=>{activeServers.set(e.ssl.port,r),log(3,`[server] Started HTTPS server on ${e.host}:${e.ssl.port}.`)}))}}rateLimitingMiddleware(app,e.rateLimiting),validationMiddleware(app),exportRoutes(app),healthRoutes(app),uiRoutes(app),versionChangeRoutes(app),errorMiddleware(app)}catch(e){throw new ExportError("[server] Could not configure and start the server.",500).setError(e)}}function closeServers(){if(activeServers.size>0){log(4,"[server] Closing all servers.");for(const[e,t]of activeServers)t.close((()=>{activeServers.delete(e),log(4,`[server] Closed server on port: ${e}.`)}))}}function getServers(){return activeServers}function getExpress(){return express}function getApp(){return app}function enableRateLimiting(e){const t=updateOptions({server:{rateLimiting:e}});rateLimitingMiddleware(app,t.server.rateLimitingOptions)}function use(e,...t){app.use(e,...t)}function get(e,...t){app.get(e,...t)}function post(e,...t){app.post(e,...t)}function _attachServerErrorHandlers(e){e.on("clientError",((e,t)=>{logWithStack(1,e,`[server] Client error: ${e.message}, destroying socket.`),t.destroy()})),e.on("error",(e=>{logWithStack(1,e,`[server] Server error: ${e.message}`)})),e.on("connection",(e=>{e.on("error",(e=>{logWithStack(1,e,`[server] Socket error: ${e.message}`)}))}))}var server={startServer:startServer,closeServers:closeServers,getServers:getServers,getExpress:getExpress,getApp:getApp,enableRateLimiting:enableRateLimiting,use:use,get:get,post:post};async function shutdownCleanUp(e=0){await Promise.allSettled([clearAllTimers(),closeServers(),killPool()]),process.exit(e)}async function initExport(e){const t=updateOptions(e);setAllowCodeExecution(t.customLogic.allowCodeExecution),initLogging(t.logging),t.other.listenToProcessExits&&_attachProcessExitListeners(),await checkCache(t.highcharts,t.server.proxy),await initPool(t.pool,t.puppeteer.args)}function _attachProcessExitListeners(){log(3,"[process] Attaching exit listeners to the process."),process.on("exit",(e=>{log(4,`[process] Process exited with code: ${e}.`)})),process.on("SIGINT",(async(e,t)=>{log(4,`[process] The ${e} event with code: ${t}.`),await shutdownCleanUp()})),process.on("SIGTERM",(async(e,t)=>{log(4,`[process] The ${e} event with code: ${t}.`),await shutdownCleanUp()})),process.on("SIGHUP",(async(e,t)=>{log(4,`[process] The ${e} event with code: ${t}.`),await shutdownCleanUp()})),process.on("uncaughtException",(async(e,t)=>{logWithStack(1,e,`[process] The ${t} error.`),await shutdownCleanUp(1)}))}var index={...server,getOptions:getOptions,updateOptions:updateOptions,mapToNewOptions:mapToNewOptions,validateOption:validateOption,validateOptions:validateOptions,initExport:initExport,singleExport:singleExport,batchExport:batchExport,startExport:startExport,killPool:killPool,shutdownCleanUp:shutdownCleanUp,log:log,logWithStack:logWithStack,logZodIssues:logZodIssues,setLogLevel:function(e){setLogLevel(updateOptions({logging:{level:e}}).logging.level)},enableConsoleLogging:function(e){enableConsoleLogging(updateOptions({logging:{toConsole:e}}).logging.toConsole)},enableFileLogging:function(e,t,o){const r=updateOptions({logging:{dest:e,file:t,toFile:o}});enableFileLogging(r.logging.dest,r.logging.file,r.logging.toFile)}};exports.default=index,exports.initExport=initExport; -//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguY2pzIiwic291cmNlcyI6WyIuLi9saWIvdXRpbHMuanMiLCIuLi9saWIvbG9nZ2VyLmpzIiwiLi4vbGliL3NjaGVtYXMvY29uZmlnLmpzIiwiLi4vbGliL3ZhbGlkYXRpb24uanMiLCIuLi9saWIvZXJyb3JzL0V4cG9ydEVycm9yLmpzIiwiLi4vbGliL2NvbmZpZy5qcyIsIi4uL2xpYi9mZXRjaC5qcyIsIi4uL2xpYi9jYWNoZS5qcyIsIi4uL2xpYi9oaWdoY2hhcnRzLmpzIiwiLi4vbGliL2Jyb3dzZXIuanMiLCIuLi90ZW1wbGF0ZXMvc3ZnRXhwb3J0L2Nzcy5qcyIsIi4uL3RlbXBsYXRlcy9zdmdFeHBvcnQvc3ZnRXhwb3J0LmpzIiwiLi4vbGliL2V4cG9ydC5qcyIsIi4uL2xpYi9wb29sLmpzIiwiLi4vbGliL3Nhbml0aXplLmpzIiwiLi4vbGliL2NoYXJ0LmpzIiwiLi4vbGliL3RpbWVyLmpzIiwiLi4vbGliL3NlcnZlci9taWRkbGV3YXJlcy9lcnJvci5qcyIsIi4uL2xpYi9zZXJ2ZXIvbWlkZGxld2FyZXMvcmF0ZUxpbWl0aW5nLmpzIiwiLi4vbGliL3NlcnZlci9taWRkbGV3YXJlcy92YWxpZGF0aW9uLmpzIiwiLi4vbGliL3NlcnZlci9yb3V0ZXMvZXhwb3J0LmpzIiwiLi4vbGliL3NlcnZlci9yb3V0ZXMvaGVhbHRoLmpzIiwiLi4vbGliL3NlcnZlci9yb3V0ZXMvdWkuanMiLCIuLi9saWIvc2VydmVyL3JvdXRlcy92ZXJzaW9uQ2hhbmdlLmpzIiwiLi4vbGliL3NlcnZlci9zZXJ2ZXIuanMiLCIuLi9saWIvcmVzb3VyY2VSZWxlYXNlLmpzIiwiLi4vbGliL2luZGV4LmpzIl0sInNvdXJjZXNDb250ZW50IjpbIi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXHJcblxyXG5IaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXJcclxuXHJcbkNvcHlyaWdodCAoYykgMjAxNi0yMDI1LCBIaWdoc29mdFxyXG5cclxuTGljZW5jZWQgdW5kZXIgdGhlIE1JVCBsaWNlbmNlLlxyXG5cclxuQWRkaXRpb25hbGx5IGEgdmFsaWQgSGlnaGNoYXJ0cyBsaWNlbnNlIGlzIHJlcXVpcmVkIGZvciB1c2UuXHJcblxyXG5TZWUgTElDRU5TRSBmaWxlIGluIHJvb3QgZm9yIGRldGFpbHMuXHJcblxyXG4qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xyXG5cclxuLyoqXHJcbiAqIEBvdmVydmlldyBUaGUgSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyIHV0aWxpdHkgbW9kdWxlIHByb3ZpZGVzXHJcbiAqIGEgY29tcHJlaGVuc2l2ZSBzZXQgb2YgaGVscGVyIGZ1bmN0aW9ucyBhbmQgY29uc3RhbnRzIGRlc2lnbmVkIHRvIHN0cmVhbWxpbmVcclxuICogYW5kIGVuaGFuY2UgdmFyaW91cyBvcGVyYXRpb25zIHJlcXVpcmVkIGZvciBIaWdoY2hhcnRzIGV4cG9ydCB0YXNrcy5cclxuICovXHJcblxyXG5pbXBvcnQgeyBpc0Fic29sdXRlLCBub3JtYWxpemUsIHJlc29sdmUgfSBmcm9tICdwYXRoJztcclxuaW1wb3J0IHsgZmlsZVVSTFRvUGF0aCB9IGZyb20gJ3VybCc7XHJcblxyXG5jb25zdCBNQVhfQkFDS09GRl9BVFRFTVBUUyA9IDY7XHJcblxyXG4vLyBUaGUgZGlyZWN0b3J5IHBhdGhcclxuZXhwb3J0IGNvbnN0IF9fZGlybmFtZSA9IGZpbGVVUkxUb1BhdGgobmV3IFVSTCgnLi4vLicsIGltcG9ydC5tZXRhLnVybCkpO1xyXG5cclxuLyoqXHJcbiAqIENsZWFycyBhbmQgc3RhbmRhcmRpemVzIHRleHQgYnkgcmVwbGFjaW5nIG11bHRpcGxlIGNvbnNlY3V0aXZlIHdoaXRlc3BhY2VcclxuICogY2hhcmFjdGVycyB3aXRoIGEgc2luZ2xlIHNwYWNlIGFuZCB0cmltbWluZyBhbnkgbGVhZGluZyBvciB0cmFpbGluZ1xyXG4gKiB3aGl0ZXNwYWNlLlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gY2xlYXJUZXh0XHJcbiAqXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSB0ZXh0IC0gVGhlIGlucHV0IHRleHQgdG8gYmUgY2xlYXJlZC5cclxuICogQHBhcmFtIHtSZWdFeHB9IFtydWxlPS9cXHNcXHMrL2ddIC0gVGhlIHJlZ3VsYXIgZXhwcmVzc2lvbiBydWxlIHRvIG1hdGNoXHJcbiAqIG11bHRpcGxlIGNvbnNlY3V0aXZlIHdoaXRlc3BhY2UgY2hhcmFjdGVycy4gVGhlIGRlZmF1bHQgdmFsdWVcclxuICogaXMgdGhlICcvXFxzXFxzKy9nJyBSZWdFeHAuXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSBbcmVwbGFjZXI9JyAnXSAtIFRoZSBzdHJpbmcgdXNlZCB0byByZXBsYWNlIG11bHRpcGxlXHJcbiAqIGNvbnNlY3V0aXZlIHdoaXRlc3BhY2UgY2hhcmFjdGVycy4gVGhlIGRlZmF1bHQgdmFsdWUgaXMgdGhlICcgJyBzdHJpbmcuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtzdHJpbmd9IFRoZSBjbGVhcmVkIGFuZCBzdGFuZGFyZGl6ZWQgdGV4dC5cclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiBjbGVhclRleHQodGV4dCwgcnVsZSA9IC9cXHNcXHMrL2csIHJlcGxhY2VyID0gJyAnKSB7XHJcbiAgcmV0dXJuIHRleHQucmVwbGFjZUFsbChydWxlLCByZXBsYWNlcikudHJpbSgpO1xyXG59XHJcblxyXG4vKipcclxuICogQ3JlYXRlcyBhIGRlZXAgY29weSBvZiB0aGUgZ2l2ZW4gb2JqZWN0IG9yIGFycmF5LlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gZGVlcENvcHlcclxuICpcclxuICogQHBhcmFtIHsoT2JqZWN0fEFycmF5KX0gb2JqQXJyIC0gVGhlIG9iamVjdCBvciBhcnJheSB0byBiZSBkZWVwbHkgY29waWVkLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7KE9iamVjdHxBcnJheSl9IFRoZSBkZWVwIGNvcHkgb2YgdGhlIHByb3ZpZGVkIG9iamVjdCBvciBhcnJheS5cclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiBkZWVwQ29weShvYmpBcnIpIHtcclxuICAvLyBJZiB0aGUgYG9iakFycmAgaXMgbnVsbCBvciBub3Qgb2YgdGhlIGBvYmplY3RgIHR5cGUsIHJldHVybiBpdFxyXG4gIGlmIChvYmpBcnIgPT09IG51bGwgfHwgdHlwZW9mIG9iakFyciAhPT0gJ29iamVjdCcpIHtcclxuICAgIHJldHVybiBvYmpBcnI7XHJcbiAgfVxyXG5cclxuICAvLyBQcmVwYXJlIGVpdGhlciBhIG5ldyBhcnJheSBvciBhIG5ldyBvYmplY3RcclxuICBjb25zdCBvYmpBcnJDb3B5ID0gQXJyYXkuaXNBcnJheShvYmpBcnIpID8gW10gOiB7fTtcclxuXHJcbiAgLy8gUmVjdXJzaXZlbHkgY29weSBlYWNoIHByb3BlcnR5XHJcbiAgZm9yIChjb25zdCBrZXkgaW4gb2JqQXJyKSB7XHJcbiAgICBpZiAoT2JqZWN0LnByb3RvdHlwZS5oYXNPd25Qcm9wZXJ0eS5jYWxsKG9iakFyciwga2V5KSkge1xyXG4gICAgICBvYmpBcnJDb3B5W2tleV0gPSBkZWVwQ29weShvYmpBcnJba2V5XSk7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICAvLyBSZXR1cm4gdGhlIGNvcGllZCBvYmplY3RcclxuICByZXR1cm4gb2JqQXJyQ29weTtcclxufVxyXG5cclxuLyoqXHJcbiAqIEltcGxlbWVudHMgYW4gZXhwb25lbnRpYWwgYmFja29mZiBzdHJhdGVneSBmb3IgcmV0cnlpbmcgYSBmdW5jdGlvbiB1bnRpbFxyXG4gKiBhIGNlcnRhaW4gbnVtYmVyIG9mIGF0dGVtcHRzIGFyZSByZWFjaGVkLlxyXG4gKlxyXG4gKiBAYXN5bmNcclxuICogQGZ1bmN0aW9uIGV4cEJhY2tvZmZcclxuICpcclxuICogQHBhcmFtIHtGdW5jdGlvbn0gZm4gLSBUaGUgZnVuY3Rpb24gdG8gYmUgcmV0cmllZC5cclxuICogQHBhcmFtIHtudW1iZXJ9IFthdHRlbXB0PTBdIC0gVGhlIGN1cnJlbnQgYXR0ZW1wdCBudW1iZXIuIFRoZSBkZWZhdWx0IHZhbHVlXHJcbiAqIGlzIGAwYC5cclxuICogQHBhcmFtIHsuLi51bmtub3dufSBhcmdzIC0gQXJndW1lbnRzIHRvIGJlIHBhc3NlZCB0byB0aGUgZnVuY3Rpb24uXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtQcm9taXNlPHVua25vd24+fSBBIFByb21pc2UgdGhhdCByZXNvbHZlcyB0byB0aGUgcmVzdWx0XHJcbiAqIG9mIHRoZSBmdW5jdGlvbiBpZiBzdWNjZXNzZnVsLlxyXG4gKlxyXG4gKiBAdGhyb3dzIHtFcnJvcn0gVGhyb3dzIGFuIGBFcnJvcmAgaWYgdGhlIG1heGltdW0gbnVtYmVyIG9mIGF0dGVtcHRzXHJcbiAqIGlzIHJlYWNoZWQuXHJcbiAqL1xyXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gZXhwQmFja29mZihmbiwgYXR0ZW1wdCA9IDAsIC4uLmFyZ3MpIHtcclxuICB0cnkge1xyXG4gICAgLy8gVHJ5IHRvIGNhbGwgdGhlIGZ1bmN0aW9uXHJcbiAgICByZXR1cm4gYXdhaXQgZm4oLi4uYXJncyk7XHJcbiAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgIC8vIENhbGN1bGF0ZSBkZWxheSBpbiBtc1xyXG4gICAgY29uc3QgZGVsYXlJbk1zID0gMiAqKiBhdHRlbXB0ICogMTAwMDtcclxuXHJcbiAgICAvLyBJZiB0aGUgYXR0ZW1wdCBleGNlZWRzIHRoZSBtYXhpbXVtIGF0dGVtcHRzIG9mIHJlcGVhdCwgdGhyb3cgYW4gZXJyb3JcclxuICAgIGlmICgrK2F0dGVtcHQgPj0gTUFYX0JBQ0tPRkZfQVRURU1QVFMpIHtcclxuICAgICAgdGhyb3cgZXJyb3I7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gV2FpdCBnaXZlbiBhbW91bnQgb2YgdGltZVxyXG4gICAgYXdhaXQgbmV3IFByb21pc2UoKHJlc3BvbnNlKSA9PiBzZXRUaW1lb3V0KHJlc3BvbnNlLCBkZWxheUluTXMpKTtcclxuXHJcbiAgICAvLy8gVE8gRE86IENvcnJlY3RcclxuICAgIC8vIC8vIEluZm9ybWF0aW9uIGFib3V0IHRoZSByZXNvdXJjZSB0aW1lb3V0XHJcbiAgICAvLyBsb2coXHJcbiAgICAvLyAgIDMsXHJcbiAgICAvLyAgIGBbdXRpbHNdIFdhaXRlZCAke2RlbGF5SW5Nc31tcyB1bnRpbCBuZXh0IGNhbGwgZm9yIHRoZSByZXNvdXJjZSBvZiBJRDogJHthcmdzWzBdfS5gXHJcbiAgICAvLyApO1xyXG5cclxuICAgIC8vIFRyeSBhZ2FpblxyXG4gICAgcmV0dXJuIGV4cEJhY2tvZmYoZm4sIGF0dGVtcHQsIC4uLmFyZ3MpO1xyXG4gIH1cclxufVxyXG5cclxuLyoqXHJcbiAqIENoZWNrcyBpZiB0aGUgZ2l2ZW4gcGF0aCBpcyByZWxhdGl2ZSBvciBhYnNvbHV0ZSBhbmQgcmV0dXJucyB0aGUgY29ycmVjdGVkLFxyXG4gKiBhYnNvbHV0ZSBwYXRoLlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gZ2V0QWJzb2x1dGVQYXRoXHJcbiAqXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSBwYXRoIC0gVGhlIHBhdGggdG8gYmUgY2hlY2tlZCBvbi5cclxuICpcclxuICogQHJldHVybnMge3N0cmluZ30gVGhlIGFic29sdXRlIHBhdGguXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gZ2V0QWJzb2x1dGVQYXRoKHBhdGgpIHtcclxuICByZXR1cm4gaXNBYnNvbHV0ZShwYXRoKSA/IG5vcm1hbGl6ZShwYXRoKSA6IHJlc29sdmUocGF0aCk7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBDb252ZXJ0cyBpbnB1dCBkYXRhIHRvIGEgQmFzZTY0IHN0cmluZyBiYXNlZCBvbiB0aGUgZXhwb3J0IHR5cGUuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBnZXRCYXNlNjRcclxuICpcclxuICogQHBhcmFtIHtzdHJpbmd9IGlucHV0IC0gVGhlIGlucHV0IHRvIGJlIHRyYW5zZm9ybWVkIHRvIEJhc2U2NCBmb3JtYXQuXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSB0eXBlIC0gVGhlIG9yaWdpbmFsIGV4cG9ydCB0eXBlLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7c3RyaW5nfSBUaGUgQmFzZTY0IHN0cmluZyByZXByZXNlbnRhdGlvbiBvZiB0aGUgaW5wdXQuXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gZ2V0QmFzZTY0KGlucHV0LCB0eXBlKSB7XHJcbiAgLy8gRm9yIHBkZiBhbmQgc3ZnIHR5cGVzIHRoZSBpbnB1dCBtdXN0IGJlIHRyYW5zZm9ybWVkIHRvIEJhc2U2NCBmcm9tIGEgYnVmZmVyXHJcbiAgaWYgKHR5cGUgPT09ICdwZGYnIHx8IHR5cGUgPT0gJ3N2ZycpIHtcclxuICAgIHJldHVybiBCdWZmZXIuZnJvbShpbnB1dCwgJ3V0ZjgnKS50b1N0cmluZygnYmFzZTY0Jyk7XHJcbiAgfVxyXG5cclxuICAvLyBGb3IgcG5nIGFuZCBqcGVnIGlucHV0IGlzIGFscmVhZHkgYSBCYXNlNjQgc3RyaW5nXHJcbiAgcmV0dXJuIGlucHV0O1xyXG59XHJcblxyXG4vKipcclxuICogUmV0dXJucyBzdHJpbmdpZmllZCBkYXRlIHdpdGhvdXQgdGhlIEdNVCB0ZXh0IGluZm9ybWF0aW9uLlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gZ2V0TmV3RGF0ZVxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIGdldE5ld0RhdGUoKSB7XHJcbiAgLy8gR2V0IHJpZCBvZiB0aGUgR01UIHRleHQgaW5mb3JtYXRpb25cclxuICByZXR1cm4gbmV3IERhdGUoKS50b1N0cmluZygpLnNwbGl0KCcoJylbMF0udHJpbSgpO1xyXG59XHJcblxyXG4vKipcclxuICogUmV0dXJucyB0aGUgc3RvcmVkIHRpbWUgdmFsdWUgaW4gbWlsbGlzZWNvbmRzLlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gZ2V0TmV3RGF0ZVRpbWVcclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiBnZXROZXdEYXRlVGltZSgpIHtcclxuICByZXR1cm4gbmV3IERhdGUoKS5nZXRUaW1lKCk7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBDaGVja3MgaWYgdGhlIGdpdmVuIGl0ZW0gaXMgYW4gb2JqZWN0LlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gaXNPYmplY3RcclxuICpcclxuICogQHBhcmFtIHt1bmtub3dufSBpdGVtIC0gVGhlIGl0ZW0gdG8gYmUgY2hlY2tlZC5cclxuICpcclxuICogQHJldHVybnMge2Jvb2xlYW59IFJldHVybnMgYHRydWVgIGlmIHRoZSBpdGVtIGlzIGFuIG9iamVjdCwgYGZhbHNlYFxyXG4gKiBvdGhlcndpc2UuXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gaXNPYmplY3QoaXRlbSkge1xyXG4gIHJldHVybiBPYmplY3QucHJvdG90eXBlLnRvU3RyaW5nLmNhbGwoaXRlbSkgPT09ICdbb2JqZWN0IE9iamVjdF0nO1xyXG59XHJcblxyXG4vKipcclxuICogQ2hlY2tzIGlmIHRoZSBnaXZlbiBvYmplY3QgaXMgZW1wdHkuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBpc09iamVjdEVtcHR5XHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBpdGVtIC0gVGhlIG9iamVjdCB0byBiZSBjaGVja2VkLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7Ym9vbGVhbn0gUmV0dXJucyBgdHJ1ZWAgaWYgdGhlIGl0ZW0gaXMgYW4gZW1wdHkgb2JqZWN0LCBgZmFsc2VgXHJcbiAqIG90aGVyd2lzZS5cclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiBpc09iamVjdEVtcHR5KGl0ZW0pIHtcclxuICByZXR1cm4gKFxyXG4gICAgdHlwZW9mIGl0ZW0gPT09ICdvYmplY3QnICYmXHJcbiAgICAhQXJyYXkuaXNBcnJheShpdGVtKSAmJlxyXG4gICAgaXRlbSAhPT0gbnVsbCAmJlxyXG4gICAgT2JqZWN0LmtleXMoaXRlbSkubGVuZ3RoID09PSAwXHJcbiAgKTtcclxufVxyXG5cclxuLyoqXHJcbiAqIENoZWNrcyBpZiBhIHByaXZhdGUgSVAgcmFuZ2UgVVJMIGlzIGZvdW5kIGluIHRoZSBnaXZlbiBzdHJpbmcuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBpc1ByaXZhdGVSYW5nZVVybEZvdW5kXHJcbiAqXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSBpdGVtIC0gVGhlIHN0cmluZyB0byBiZSBjaGVja2VkIGZvciBhIHByaXZhdGUgSVAgcmFuZ2UgVVJMLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7Ym9vbGVhbn0gUmV0dXJucyBgdHJ1ZWAgaWYgYSBwcml2YXRlIElQIHJhbmdlIFVSTCBpcyBmb3VuZCwgYGZhbHNlYFxyXG4gKiBvdGhlcndpc2UuXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gaXNQcml2YXRlUmFuZ2VVcmxGb3VuZChpdGVtKSB7XHJcbiAgY29uc3QgcmVnZXhQYXR0ZXJucyA9IFtcclxuICAgIC94bGluazpocmVmPVwiKD86aHR0cDpcXC9cXC98aHR0cHM6XFwvXFwvKT9sb2NhbGhvc3RcXGIvLFxyXG4gICAgL3hsaW5rOmhyZWY9XCIoPzpodHRwOlxcL1xcL3xodHRwczpcXC9cXC8pPzEwXFwuXFxkezEsM31cXC5cXGR7MSwzfVxcLlxcZHsxLDN9XFxiLyxcclxuICAgIC94bGluazpocmVmPVwiKD86aHR0cDpcXC9cXC98aHR0cHM6XFwvXFwvKT8xMjdcXC5cXGR7MSwzfVxcLlxcZHsxLDN9XFwuXFxkezEsM31cXGIvLFxyXG4gICAgL3hsaW5rOmhyZWY9XCIoPzpodHRwOlxcL1xcL3xodHRwczpcXC9cXC8pPzE3MlxcLigxWzYtOV18MlswLTldfDNbMC0xXSlcXC5cXGR7MSwzfVxcLlxcZHsxLDN9XFxiLyxcclxuICAgIC94bGluazpocmVmPVwiKD86aHR0cDpcXC9cXC98aHR0cHM6XFwvXFwvKT8xOTJcXC4xNjhcXC5cXGR7MSwzfVxcLlxcZHsxLDN9XFxiL1xyXG4gIF07XHJcblxyXG4gIHJldHVybiByZWdleFBhdHRlcm5zLnNvbWUoKHBhdHRlcm4pID0+IHBhdHRlcm4udGVzdChpdGVtKSk7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBVdGlsaXR5IHRvIG1lYXN1cmUgZWxhcHNlZCB0aW1lIHVzaW5nIHRoZSBOb2RlLmpzIGBwcm9jZXNzLmhydGltZSgpYCBtZXRob2QuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBtZWFzdXJlVGltZVxyXG4gKlxyXG4gKiBAcmV0dXJucyB7RnVuY3Rpb259IEEgZnVuY3Rpb24gdG8gY2FsY3VsYXRlIHRoZSBlbGFwc2VkIHRpbWUgaW4gbWlsbGlzZWNvbmRzLlxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIG1lYXN1cmVUaW1lKCkge1xyXG4gIGNvbnN0IHN0YXJ0ID0gcHJvY2Vzcy5ocnRpbWUuYmlnaW50KCk7XHJcbiAgcmV0dXJuICgpID0+IE51bWJlcihwcm9jZXNzLmhydGltZS5iaWdpbnQoKSAtIHN0YXJ0KSAvIDEwMDAwMDA7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBSb3VuZHMgYSBudW1iZXIgdG8gdGhlIHNwZWNpZmllZCBwcmVjaXNpb24uXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiByb3VuZE51bWJlclxyXG4gKlxyXG4gKiBAcGFyYW0ge251bWJlcn0gdmFsdWUgLSBUaGUgbnVtYmVyIHRvIGJlIHJvdW5kZWQuXHJcbiAqIEBwYXJhbSB7bnVtYmVyfSBwcmVjaXNpb24gLSBUaGUgbnVtYmVyIG9mIGRlY2ltYWwgcGxhY2VzIHRvIHJvdW5kIHRvLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7bnVtYmVyfSBUaGUgcm91bmRlZCBudW1iZXIuXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gcm91bmROdW1iZXIodmFsdWUsIHByZWNpc2lvbiA9IDEpIHtcclxuICBjb25zdCBtdWx0aXBsaWVyID0gTWF0aC5wb3coMTAsIHByZWNpc2lvbiB8fCAwKTtcclxuICByZXR1cm4gTWF0aC5yb3VuZCgrdmFsdWUgKiBtdWx0aXBsaWVyKSAvIG11bHRpcGxpZXI7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBDb252ZXJ0cyBhIHZhbHVlIHRvIGEgYm9vbGVhbi5cclxuICpcclxuICogQGZ1bmN0aW9uIHRvQm9vbGVhblxyXG4gKlxyXG4gKiBAcGFyYW0ge3Vua25vd259IGl0ZW0gLSBUaGUgdmFsdWUgdG8gYmUgY29udmVydGVkIHRvIGEgYm9vbGVhbi5cclxuICpcclxuICogQHJldHVybnMge2Jvb2xlYW59IFRoZSBib29sZWFuIHJlcHJlc2VudGF0aW9uIG9mIHRoZSBpbnB1dCB2YWx1ZS5cclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiB0b0Jvb2xlYW4oaXRlbSkge1xyXG4gIHJldHVybiBbJ2ZhbHNlJywgJ3VuZGVmaW5lZCcsICdudWxsJywgJ05hTicsICcwJywgJyddLmluY2x1ZGVzKGl0ZW0pXHJcbiAgICA/IGZhbHNlXHJcbiAgICA6ICEhaXRlbTtcclxufVxyXG5cclxuZXhwb3J0IGRlZmF1bHQge1xyXG4gIF9fZGlybmFtZSxcclxuICBjbGVhclRleHQsXHJcbiAgZGVlcENvcHksXHJcbiAgZXhwQmFja29mZixcclxuICBnZXRBYnNvbHV0ZVBhdGgsXHJcbiAgZ2V0QmFzZTY0LFxyXG4gIGdldE5ld0RhdGUsXHJcbiAgZ2V0TmV3RGF0ZVRpbWUsXHJcbiAgaXNPYmplY3QsXHJcbiAgaXNPYmplY3RFbXB0eSxcclxuICBpc1ByaXZhdGVSYW5nZVVybEZvdW5kLFxyXG4gIG1lYXN1cmVUaW1lLFxyXG4gIHJvdW5kTnVtYmVyLFxyXG4gIHRvQm9vbGVhblxyXG59O1xyXG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxyXG5cclxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXHJcblxyXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNSwgSGlnaHNvZnRcclxuXHJcbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cclxuXHJcbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxyXG5cclxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxyXG5cclxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cclxuXHJcbi8qKlxyXG4gKiBAb3ZlcnZpZXcgQSBtb2R1bGUgZm9yIG1hbmFnaW5nIGxvZ2dpbmcgZnVuY3Rpb25hbGl0eSB3aXRoIGN1c3RvbWl6YWJsZVxyXG4gKiBsb2cgbGV2ZWxzLCBjb25zb2xlIGFuZCBmaWxlIGxvZ2dpbmcgb3B0aW9ucywgYW5kIGVycm9yIGhhbmRsaW5nIHN1cHBvcnQuXHJcbiAqIFRoZSBtb2R1bGUgYWxzbyBlbnN1cmVzIHRoYXQgZmlsZS1iYXNlZCBsb2dzIGFyZSBzdG9yZWQgaW4gYSBzdHJ1Y3R1cmVkXHJcbiAqIGRpcmVjdG9yeSwgY3JlYXRpbmcgdGhlIG5lY2Vzc2FyeSBwYXRocyBhdXRvbWF0aWNhbGx5IGlmIHRoZXkgZG8gbm90IGV4aXN0LlxyXG4gKi9cclxuXHJcbmltcG9ydCB7IGFwcGVuZEZpbGUsIGV4aXN0c1N5bmMsIG1rZGlyU3luYyB9IGZyb20gJ2ZzJztcclxuaW1wb3J0IHsgam9pbiB9IGZyb20gJ3BhdGgnO1xyXG5cclxuaW1wb3J0IHsgZ2V0QWJzb2x1dGVQYXRoLCBnZXROZXdEYXRlIH0gZnJvbSAnLi91dGlscy5qcyc7XHJcblxyXG4vLyBUaGUgYXZhaWxhYmxlIGNvbG9yc1xyXG5jb25zdCBjb2xvcnMgPSBbJ3JlZCcsICd5ZWxsb3cnLCAnYmx1ZScsICdncmF5JywgJ2dyZWVuJ107XHJcblxyXG4vLyBUaGUgZGVmYXVsdCBsb2dnaW5nIGNvbmZpZ1xyXG5jb25zdCBsb2dnaW5nID0ge1xyXG4gIC8vIEZsYWdzIGZvciBsb2dnaW5nIHN0YXR1c1xyXG4gIHRvQ29uc29sZTogdHJ1ZSxcclxuICB0b0ZpbGU6IGZhbHNlLFxyXG4gIHBhdGhDcmVhdGVkOiBmYWxzZSxcclxuICAvLyBGdWxsIHBhdGggdG8gdGhlIGxvZyBmaWxlXHJcbiAgcGF0aFRvTG9nOiAnJyxcclxuICAvLyBMb2cgbGV2ZWxzXHJcbiAgbGV2ZWxzRGVzYzogW1xyXG4gICAge1xyXG4gICAgICB0aXRsZTogJ2Vycm9yJyxcclxuICAgICAgY29sb3I6IGNvbG9yc1swXVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdGl0bGU6ICd3YXJuaW5nJyxcclxuICAgICAgY29sb3I6IGNvbG9yc1sxXVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdGl0bGU6ICdub3RpY2UnLFxyXG4gICAgICBjb2xvcjogY29sb3JzWzJdXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0aXRsZTogJ3ZlcmJvc2UnLFxyXG4gICAgICBjb2xvcjogY29sb3JzWzNdXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0aXRsZTogJ2JlbmNobWFyaycsXHJcbiAgICAgIGNvbG9yOiBjb2xvcnNbNF1cclxuICAgIH1cclxuICBdXHJcbn07XHJcblxyXG4vKipcclxuICogTG9ncyBhIG1lc3NhZ2Ugd2l0aCBhIHNwZWNpZmllZCBsb2cgbGV2ZWwuIEFjY2VwdHMgYSB2YXJpYWJsZSBudW1iZXJcclxuICogb2YgYXJndW1lbnRzLiBUaGUgYXJndW1lbnRzIGFmdGVyIHRoZSBgbGV2ZWxgIGFyZSBwYXNzZWQgdG8gYGNvbnNvbGUubG9nYFxyXG4gKiBhbmQvb3IgdXNlZCB0byBjb25zdHJ1Y3QgYW5kIGFwcGVuZCBtZXNzYWdlcyB0byBhIGxvZyBmaWxlLlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gbG9nXHJcbiAqXHJcbiAqIEBwYXJhbSB7Li4udW5rbm93bn0gYXJncyAtIEFuIGFycmF5IG9mIGFyZ3VtZW50cyB3aGVyZSB0aGUgZmlyc3QgaXMgdGhlIGxvZ1xyXG4gKiBsZXZlbCBhbmQgdGhlIHJlbWFpbmluZyBhcmUgc3RyaW5ncyB1c2VkIHRvIGJ1aWxkIHRoZSBsb2cgbWVzc2FnZS5cclxuICpcclxuICogQHJldHVybnMge3ZvaWR9IEV4aXRzIHRoZSBmdW5jdGlvbiBleGVjdXRpb24gaWYgYXR0ZW1wdGluZyB0byBsb2cgYXQgYSBsZXZlbFxyXG4gKiBoaWdoZXIgdGhhbiBhbGxvd2VkLlxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIGxvZyguLi5hcmdzKSB7XHJcbiAgY29uc3QgW25ld0xldmVsLCAuLi50ZXh0c10gPSBhcmdzO1xyXG5cclxuICAvLyBDdXJyZW50IGxvZ2dpbmcgb3B0aW9uc1xyXG4gIGNvbnN0IHsgbGV2ZWxzRGVzYywgbGV2ZWwgfSA9IGxvZ2dpbmc7XHJcblxyXG4gIC8vIENoZWNrIGlmIHRoZSBsb2cgbGV2ZWwgaXMgd2l0aGluIGEgY29ycmVjdCByYW5nZSBvciBpcyBpdCBhIGJlbmNobWFyayBsb2dcclxuICBpZiAoXHJcbiAgICBuZXdMZXZlbCAhPT0gNSAmJlxyXG4gICAgKG5ld0xldmVsID09PSAwIHx8IG5ld0xldmVsID4gbGV2ZWwgfHwgbGV2ZWwgPiBsZXZlbHNEZXNjLmxlbmd0aClcclxuICApIHtcclxuICAgIHJldHVybjtcclxuICB9XHJcblxyXG4gIC8vIENyZWF0ZSBhIG1lc3NhZ2UncyBwcmVmaXhcclxuICBjb25zdCBwcmVmaXggPSBgJHtnZXROZXdEYXRlKCl9IFske2xldmVsc0Rlc2NbbmV3TGV2ZWwgLSAxXS50aXRsZX1dIC1gO1xyXG5cclxuICAvLyBMb2cgdG8gZmlsZVxyXG4gIGlmIChsb2dnaW5nLnRvRmlsZSkge1xyXG4gICAgX2xvZ1RvRmlsZSh0ZXh0cywgcHJlZml4KTtcclxuICB9XHJcblxyXG4gIC8vIExvZyB0byBjb25zb2xlXHJcbiAgaWYgKGxvZ2dpbmcudG9Db25zb2xlKSB7XHJcbiAgICBjb25zb2xlLmxvZy5hcHBseShcclxuICAgICAgdW5kZWZpbmVkLFxyXG4gICAgICBbcHJlZml4LnRvU3RyaW5nKClbbG9nZ2luZy5sZXZlbHNEZXNjW25ld0xldmVsIC0gMV0uY29sb3JdXS5jb25jYXQodGV4dHMpXHJcbiAgICApO1xyXG4gIH1cclxufVxyXG5cclxuLyoqXHJcbiAqIExvZ3MgYW4gZXJyb3IgbWVzc2FnZSBhbG9uZyB3aXRoIGl0cyBzdGFjayB0cmFjZS4gT3B0aW9uYWxseSwgYSBjdXN0b21cclxuICogbWVzc2FnZSBjYW4gYmUgcHJvdmlkZWQuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBsb2dXaXRoU3RhY2tcclxuICpcclxuICogQHBhcmFtIHtudW1iZXJ9IG5ld0xldmVsIC0gVGhlIGxvZyBsZXZlbC5cclxuICogQHBhcmFtIHtFcnJvcn0gZXJyb3IgLSBUaGUgZXJyb3Igb2JqZWN0IGNvbnRhaW5pbmcgdGhlIHN0YWNrIHRyYWNlLlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gY3VzdG9tTWVzc2FnZSAtIEFuIG9wdGlvbmFsIGN1c3RvbSBtZXNzYWdlIHRvIGJlIGluY2x1ZGVkXHJcbiAqIGluIHRoZSBsb2cgYWxvbmdzaWRlIHRoZSBlcnJvci5cclxuICpcclxuICogQHJldHVybnMge3ZvaWR9IEV4aXRzIHRoZSBmdW5jdGlvbiBleGVjdXRpb24gaWYgYXR0ZW1wdGluZyB0byBsb2cgYXQgYSBsZXZlbFxyXG4gKiBoaWdoZXIgdGhhbiBhbGxvd2VkLlxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIGxvZ1dpdGhTdGFjayhuZXdMZXZlbCwgZXJyb3IsIGN1c3RvbU1lc3NhZ2UpIHtcclxuICAvLyBHZXQgdGhlIG1haW4gbWVzc2FnZVxyXG4gIGNvbnN0IG1haW5NZXNzYWdlID0gY3VzdG9tTWVzc2FnZSB8fCAoZXJyb3IgJiYgZXJyb3IubWVzc2FnZSkgfHwgJyc7XHJcblxyXG4gIC8vIEN1cnJlbnQgbG9nZ2luZyBvcHRpb25zXHJcbiAgY29uc3QgeyBsZXZlbCwgbGV2ZWxzRGVzYyB9ID0gbG9nZ2luZztcclxuXHJcbiAgLy8gQ2hlY2sgaWYgdGhlIGxvZyBsZXZlbCBpcyB3aXRoaW4gYSBjb3JyZWN0IHJhbmdlXHJcbiAgaWYgKG5ld0xldmVsID09PSAwIHx8IG5ld0xldmVsID4gbGV2ZWwgfHwgbGV2ZWwgPiBsZXZlbHNEZXNjLmxlbmd0aCkge1xyXG4gICAgcmV0dXJuO1xyXG4gIH1cclxuXHJcbiAgLy8gQ3JlYXRlIGEgbWVzc2FnZSdzIHByZWZpeFxyXG4gIGNvbnN0IHByZWZpeCA9IGAke2dldE5ld0RhdGUoKX0gWyR7bGV2ZWxzRGVzY1tuZXdMZXZlbCAtIDFdLnRpdGxlfV0gLWA7XHJcblxyXG4gIC8vIEFkZCB0aGUgd2hvbGUgc3RhY2sgbWVzc2FnZVxyXG4gIGNvbnN0IHN0YWNrTWVzc2FnZSA9IGVycm9yICYmIGVycm9yLnN0YWNrO1xyXG5cclxuICAvLyBDb21iaW5lIGN1c3RvbSBtZXNzYWdlIG9yIGVycm9yIG1lc3NhZ2Ugd2l0aCBlcnJvciBzdGFjayBtZXNzYWdlLCBpZiBleGlzdHNcclxuICBjb25zdCB0ZXh0cyA9IFttYWluTWVzc2FnZV07XHJcbiAgaWYgKHN0YWNrTWVzc2FnZSkge1xyXG4gICAgdGV4dHMucHVzaCgnXFxuJywgc3RhY2tNZXNzYWdlKTtcclxuICB9XHJcblxyXG4gIC8vIExvZyB0byBmaWxlXHJcbiAgaWYgKGxvZ2dpbmcudG9GaWxlKSB7XHJcbiAgICBfbG9nVG9GaWxlKHRleHRzLCBwcmVmaXgpO1xyXG4gIH1cclxuXHJcbiAgLy8gTG9nIHRvIGNvbnNvbGVcclxuICBpZiAobG9nZ2luZy50b0NvbnNvbGUpIHtcclxuICAgIGNvbnNvbGUubG9nLmFwcGx5KFxyXG4gICAgICB1bmRlZmluZWQsXHJcbiAgICAgIFtwcmVmaXgudG9TdHJpbmcoKVtsb2dnaW5nLmxldmVsc0Rlc2NbbmV3TGV2ZWwgLSAxXS5jb2xvcl1dLmNvbmNhdChbXHJcbiAgICAgICAgdGV4dHMuc2hpZnQoKVtjb2xvcnNbbmV3TGV2ZWwgLSAxXV0sXHJcbiAgICAgICAgLi4udGV4dHNcclxuICAgICAgXSlcclxuICAgICk7XHJcbiAgfVxyXG59XHJcblxyXG4vKipcclxuICogTG9ncyBhbiBlcnJvciBtZXNzYWdlIHJlbGF0ZWQgdG8gWm9kIHZhbGlkYXRpb24gaXNzdWVzLiBPcHRpb25hbGx5LCBhIGN1c3RvbVxyXG4gKiBtZXNzYWdlIGNhbiBiZSBwcm92aWRlZC5cclxuICpcclxuICogQGZ1bmN0aW9uIGxvZ1pvZElzc3Vlc1xyXG4gKlxyXG4gKiBAcGFyYW0ge251bWJlcn0gbmV3TGV2ZWwgLSBUaGUgbG9nIGxldmVsLlxyXG4gKiBAcGFyYW0ge0Vycm9yW119IGlzc3VlcyAtIEFuIGFycmF5IG9mIFpvZCB2YWxpZGF0aW9uIGlzc3Vlcy5cclxuICogQHBhcmFtIHtzdHJpbmd9IGN1c3RvbU1lc3NhZ2UgLSBBbiBvcHRpb25hbCBjdXN0b20gbWVzc2FnZSB0byBiZSBpbmNsdWRlZFxyXG4gKiBpbiB0aGUgbG9nIGFsb25nc2lkZSB0aGUgZXJyb3IuXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gbG9nWm9kSXNzdWVzKG5ld0xldmVsLCBpc3N1ZXMsIGN1c3RvbU1lc3NhZ2UpIHtcclxuICBsb2dXaXRoU3RhY2soXHJcbiAgICBuZXdMZXZlbCxcclxuICAgIG51bGwsXHJcbiAgICBbXHJcbiAgICAgIGAke2N1c3RvbU1lc3NhZ2UgfHwgJ1t2YWxpZGF0aW9uXSBWYWxpZGF0aW9uIGVycm9yJ30gLSB0aGUgZm9sbG93aW5nIFpvZCBpc3N1ZXMgb2NjdXJlZDpgLFxyXG4gICAgICAuLi4oaXNzdWVzIHx8IFtdKS5tYXAoKGlzc3VlKSA9PiBgLSAke2lzc3VlLm1lc3NhZ2V9YClcclxuICAgIF0uam9pbignXFxuJylcclxuICApO1xyXG59XHJcblxyXG4vKipcclxuICogSW5pdGlhbGl6ZXMgbG9nZ2luZyB3aXRoIHRoZSBzcGVjaWZpZWQgbG9nZ2luZyBjb25maWd1cmF0aW9uLlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gaW5pdExvZ2dpbmdcclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IGxvZ2dpbmdPcHRpb25zIC0gVGhlIGNvbmZpZ3VyYXRpb24gb2JqZWN0IGNvbnRhaW5pbmdcclxuICogYGxvZ2dpbmdgIG9wdGlvbnMuXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gaW5pdExvZ2dpbmcobG9nZ2luZ09wdGlvbnMpIHtcclxuICAvLyBHZXQgb3B0aW9ucyBmcm9tIHRoZSBgbG9nZ2luZ09wdGlvbnNgIG9iamVjdFxyXG4gIGNvbnN0IHsgbGV2ZWwsIGRlc3QsIGZpbGUsIHRvQ29uc29sZSwgdG9GaWxlIH0gPSBsb2dnaW5nT3B0aW9ucztcclxuXHJcbiAgLy8gUmVzZXQgZmxhZ3MgdG8gdGhlIGRlZmF1bHQgdmFsdWVzXHJcbiAgbG9nZ2luZy5wYXRoQ3JlYXRlZCA9IGZhbHNlO1xyXG4gIGxvZ2dpbmcucGF0aFRvTG9nID0gJyc7XHJcblxyXG4gIC8vIFNldCB0aGUgbG9nZ2luZyBsZXZlbFxyXG4gIHNldExvZ0xldmVsKGxldmVsKTtcclxuXHJcbiAgLy8gU2V0IHRoZSBjb25zb2xlIGxvZ2dpbmdcclxuICBlbmFibGVDb25zb2xlTG9nZ2luZyh0b0NvbnNvbGUpO1xyXG5cclxuICAvLyBTZXQgdGhlIGZpbGUgbG9nZ2luZ1xyXG4gIGVuYWJsZUZpbGVMb2dnaW5nKGRlc3QsIGZpbGUsIHRvRmlsZSk7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBTZXRzIHRoZSBsb2cgbGV2ZWwgdG8gdGhlIHNwZWNpZmllZCB2YWx1ZS4gTG9nIGxldmVscyBhcmUgKGAwYCA9IG5vIGxvZ2dpbmcsXHJcbiAqIGAxYCA9IGVycm9yLCBgMmAgPSB3YXJuaW5nLCBgM2AgPSBub3RpY2UsIGA0YCA9IHZlcmJvc2UsIG9yIGA1YCA9IGJlbmNobWFyaykuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBzZXRMb2dMZXZlbFxyXG4gKlxyXG4gKiBAcGFyYW0ge251bWJlcn0gbGV2ZWwgLSBUaGUgbG9nIGxldmVsIHRvIGJlIHNldC5cclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiBzZXRMb2dMZXZlbChsZXZlbCkge1xyXG4gIGlmIChcclxuICAgIE51bWJlci5pc0ludGVnZXIobGV2ZWwpICYmXHJcbiAgICBsZXZlbCA+PSAwICYmXHJcbiAgICBsZXZlbCA8PSBsb2dnaW5nLmxldmVsc0Rlc2MubGVuZ3RoXHJcbiAgKSB7XHJcbiAgICAvLyBVcGRhdGUgdGhlIG1vZHVsZSBsb2dnaW5nJ3MgYGxldmVsYCBvcHRpb25cclxuICAgIGxvZ2dpbmcubGV2ZWwgPSBsZXZlbDtcclxuICB9XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBFbmFibGVzIGNvbnNvbGUgbG9nZ2luZy5cclxuICpcclxuICogQGZ1bmN0aW9uIGVuYWJsZUNvbnNvbGVMb2dnaW5nXHJcbiAqXHJcbiAqIEBwYXJhbSB7Ym9vbGVhbn0gdG9Db25zb2xlIC0gVGhlIGZsYWcgZm9yIHNldHRpbmcgdGhlIGxvZ2dpbmcgdG8gdGhlIGNvbnNvbGUuXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gZW5hYmxlQ29uc29sZUxvZ2dpbmcodG9Db25zb2xlKSB7XHJcbiAgLy8gVXBkYXRlIHRoZSBtb2R1bGUgbG9nZ2luZydzIGB0b0NvbnNvbGVgIG9wdGlvblxyXG4gIGxvZ2dpbmcudG9Db25zb2xlID0gISF0b0NvbnNvbGU7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBFbmFibGVzIGZpbGUgbG9nZ2luZyB3aXRoIHRoZSBzcGVjaWZpZWQgZGVzdGluYXRpb24gYW5kIGxvZyBmaWxlIG5hbWUuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBlbmFibGVGaWxlTG9nZ2luZ1xyXG4gKlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gZGVzdCAtIFRoZSBkZXN0aW5hdGlvbiBwYXRoIHdoZXJlIHRoZSBsb2cgZmlsZSBzaG91bGRcclxuICogYmUgc2F2ZWQuXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSBmaWxlIC0gVGhlIG5hbWUgb2YgdGhlIGxvZyBmaWxlLlxyXG4gKiBAcGFyYW0ge2Jvb2xlYW59IHRvRmlsZSAtIEEgZmxhZyBpbmRpY2F0aW5nIHdoZXRoZXIgbG9nZ2luZyBzaG91bGRcclxuICogYmUgZGlyZWN0ZWQgdG8gYSBmaWxlLlxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIGVuYWJsZUZpbGVMb2dnaW5nKGRlc3QsIGZpbGUsIHRvRmlsZSkge1xyXG4gIC8vIFVwZGF0ZSB0aGUgbW9kdWxlIGxvZ2dpbmcncyBgdG9GaWxlYCBvcHRpb25cclxuICBsb2dnaW5nLnRvRmlsZSA9ICEhdG9GaWxlO1xyXG5cclxuICAvLyBTZXQgdGhlIGBkZXN0YCBhbmQgYGZpbGVgIG9wdGlvbnMgb25seSBpZiB0aGUgZmlsZSBsb2dnaW5nIGlzIGVuYWJsZWRcclxuICBpZiAobG9nZ2luZy50b0ZpbGUpIHtcclxuICAgIGxvZ2dpbmcuZGVzdCA9IGRlc3QgfHwgJ2xvZyc7XHJcbiAgICBsb2dnaW5nLmZpbGUgPSBmaWxlIHx8ICdoaWdoY2hhcnRzLWV4cG9ydC1zZXJ2ZXIubG9nJztcclxuICB9XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBMb2dzIHRoZSBwcm92aWRlZCB0ZXh0cyB0byBhIGZpbGUsIGlmIGZpbGUgbG9nZ2luZyBpcyBlbmFibGVkLiBJdCBjcmVhdGVzXHJcbiAqIHRoZSBuZWNlc3NhcnkgZGlyZWN0b3J5IHN0cnVjdHVyZSBpZiBub3QgYWxyZWFkeSBjcmVhdGVkIGFuZCBhcHBlbmRzXHJcbiAqIHRoZSBjb250ZW50LCBpbmNsdWRpbmcgYW4gb3B0aW9uYWwgcHJlZml4LCB0byB0aGUgc3BlY2lmaWVkIGxvZyBmaWxlLlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gX2xvZ1RvRmlsZVxyXG4gKlxyXG4gKiBAcGFyYW0ge0FycmF5PHN0cmluZz59IHRleHRzIC0gQW4gYXJyYXkgb2YgdGV4dHMgdG8gYmUgbG9nZ2VkLlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gcHJlZml4IC0gQW4gb3B0aW9uYWwgcHJlZml4IHRvIGJlIGFkZGVkIHRvIGVhY2ggbG9nIGVudHJ5LlxyXG4gKi9cclxuZnVuY3Rpb24gX2xvZ1RvRmlsZSh0ZXh0cywgcHJlZml4KSB7XHJcbiAgaWYgKCFsb2dnaW5nLnBhdGhDcmVhdGVkKSB7XHJcbiAgICAvLyBDcmVhdGUgaWYgZG9lcyBub3QgZXhpc3RcclxuICAgICFleGlzdHNTeW5jKGdldEFic29sdXRlUGF0aChsb2dnaW5nLmRlc3QpKSAmJlxyXG4gICAgICBta2RpclN5bmMoZ2V0QWJzb2x1dGVQYXRoKGxvZ2dpbmcuZGVzdCkpO1xyXG5cclxuICAgIC8vIENyZWF0ZSB0aGUgZnVsbCBwYXRoXHJcbiAgICBsb2dnaW5nLnBhdGhUb0xvZyA9IGdldEFic29sdXRlUGF0aChqb2luKGxvZ2dpbmcuZGVzdCwgbG9nZ2luZy5maWxlKSk7XHJcblxyXG4gICAgLy8gV2Ugbm93IGFzc3VtZSB0aGUgcGF0aCBpcyBhdmFpbGFibGUsIGUuZy4gaXQncyB0aGUgcmVzcG9uc2liaWxpdHlcclxuICAgIC8vIG9mIHRoZSB1c2VyIHRvIGNyZWF0ZSB0aGUgcGF0aCB3aXRoIHRoZSBjb3JyZWN0IGFjY2VzcyByaWdodHMuXHJcbiAgICBsb2dnaW5nLnBhdGhDcmVhdGVkID0gdHJ1ZTtcclxuICB9XHJcblxyXG4gIC8vIEFkZCB0aGUgY29udGVudCB0byBhIGZpbGVcclxuICBhcHBlbmRGaWxlKFxyXG4gICAgbG9nZ2luZy5wYXRoVG9Mb2csXHJcbiAgICBbcHJlZml4XS5jb25jYXQodGV4dHMpLmpvaW4oJyAnKSArICdcXG4nLFxyXG4gICAgKGVycm9yKSA9PiB7XHJcbiAgICAgIGlmIChlcnJvciAmJiBsb2dnaW5nLnRvRmlsZSAmJiBsb2dnaW5nLnBhdGhDcmVhdGVkKSB7XHJcbiAgICAgICAgbG9nZ2luZy50b0ZpbGUgPSBmYWxzZTtcclxuICAgICAgICBsb2dnaW5nLnBhdGhDcmVhdGVkID0gZmFsc2U7XHJcbiAgICAgICAgbG9nV2l0aFN0YWNrKDIsIGVycm9yLCBgW2xvZ2dlcl0gVW5hYmxlIHRvIHdyaXRlIHRvIGxvZyBmaWxlLmApO1xyXG4gICAgICB9XHJcbiAgICB9XHJcbiAgKTtcclxufVxyXG5cclxuZXhwb3J0IGRlZmF1bHQge1xyXG4gIGxvZyxcclxuICBsb2dXaXRoU3RhY2ssXHJcbiAgbG9nWm9kSXNzdWVzLFxyXG4gIGluaXRMb2dnaW5nLFxyXG4gIHNldExvZ0xldmVsLFxyXG4gIGVuYWJsZUNvbnNvbGVMb2dnaW5nLFxyXG4gIGVuYWJsZUZpbGVMb2dnaW5nXHJcbn07XHJcbiIsIi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXHJcblxyXG5IaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXJcclxuXHJcbkNvcHlyaWdodCAoYykgMjAxNi0yMDI1LCBIaWdoc29mdFxyXG5cclxuTGljZW5jZWQgdW5kZXIgdGhlIE1JVCBsaWNlbmNlLlxyXG5cclxuQWRkaXRpb25hbGx5IGEgdmFsaWQgSGlnaGNoYXJ0cyBsaWNlbnNlIGlzIHJlcXVpcmVkIGZvciB1c2UuXHJcblxyXG5TZWUgTElDRU5TRSBmaWxlIGluIHJvb3QgZm9yIGRldGFpbHMuXHJcblxyXG4qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xyXG5cclxuLyoqXHJcbiAqIEBvdmVydmlldyBDb25maWd1cmF0aW9uIG1hbmFnZW1lbnQgbW9kdWxlIGZvciB0aGUgSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyLlxyXG4gKiBJdCBwcm92aWRlcyBhIGRlZmF1bHQgY29uZmlndXJhdGlvbiBvYmplY3Qgd2l0aCBwcmVkZWZpbmVkIGRlZmF1bHQgdmFsdWVzLFxyXG4gKiBkZXNjcmlwdGlvbnMsIGFuZCBjaGFyYWN0ZXJpc3RpY3MgZm9yIGVhY2ggb3B0aW9uIHVzZWQgaW4gdGhlIEV4cG9ydCBTZXJ2ZXIuXHJcbiAqL1xyXG5cclxuLyoqXHJcbiAqIFRoZSBkZWZhdWx0IGNvbmZpZ3VyYXRpb24gb2JqZWN0IGNvbnRhaW5pbmcgYWxsIGF2YWlsYWJsZSBvcHRpb25zLCBvcmdhbml6ZWRcclxuICogYnkgc2VjdGlvbnMuXHJcbiAqXHJcbiAqIFRoaXMgb2JqZWN0IGluY2x1ZGVzOlxyXG4gKiAtIERlZmF1bHQgdmFsdWVzIGZvciBlYWNoIG9wdGlvbi5cclxuICogLSBEYXRhIHR5cGVzIGZvciB2YWxpZGF0aW9uLlxyXG4gKiAtIE5hbWVzIG9mIGNvcnJlc3BvbmRpbmcgZW52aXJvbm1lbnQgdmFyaWFibGVzLlxyXG4gKiAtIERlc2NyaXB0aW9ucyBvZiBlYWNoIHByb3BlcnR5LlxyXG4gKiAtIEluZm9ybWF0aW9uIHVzZWQgZm9yIHByb21wdHMgaW4gaW50ZXJhY3RpdmUgY29uZmlndXJhdGlvbi5cclxuICogLSBbT3B0aW9uYWxdIENvcnJlc3BvbmRpbmcgQ0xJIGFyZ3VtZW50IG5hbWVzIGZvciBDTEkgdXNhZ2UuXHJcbiAqIC0gW09wdGlvbmFsXSBMZWdhY3kgbmFtZXMgZnJvbSB0aGUgcHJldmlvdXMgUGhhbnRvbUpTLWJhc2VkIHNlcnZlci5cclxuICovXHJcbmNvbnN0IGRlZmF1bHRDb25maWcgPSB7XHJcbiAgcHVwcGV0ZWVyOiB7XHJcbiAgICBhcmdzOiB7XHJcbiAgICAgIHZhbHVlOiBbXHJcbiAgICAgICAgJy0tYWxsb3ctcnVubmluZy1pbnNlY3VyZS1jb250ZW50JyxcclxuICAgICAgICAnLS1hc2gtbm8tbnVkZ2VzJyxcclxuICAgICAgICAnLS1hdXRvcGxheS1wb2xpY3k9dXNlci1nZXN0dXJlLXJlcXVpcmVkJyxcclxuICAgICAgICAnLS1ibG9jay1uZXctd2ViLWNvbnRlbnRzJyxcclxuICAgICAgICAnLS1kaXNhYmxlLWFjY2VsZXJhdGVkLTJkLWNhbnZhcycsXHJcbiAgICAgICAgJy0tZGlzYWJsZS1iYWNrZ3JvdW5kLW5ldHdvcmtpbmcnLFxyXG4gICAgICAgICctLWRpc2FibGUtYmFja2dyb3VuZC10aW1lci10aHJvdHRsaW5nJyxcclxuICAgICAgICAnLS1kaXNhYmxlLWJhY2tncm91bmRpbmctb2NjbHVkZWQtd2luZG93cycsXHJcbiAgICAgICAgJy0tZGlzYWJsZS1icmVha3BhZCcsXHJcbiAgICAgICAgJy0tZGlzYWJsZS1jaGVja2VyLWltYWdpbmcnLFxyXG4gICAgICAgICctLWRpc2FibGUtY2xpZW50LXNpZGUtcGhpc2hpbmctZGV0ZWN0aW9uJyxcclxuICAgICAgICAnLS1kaXNhYmxlLWNvbXBvbmVudC1leHRlbnNpb25zLXdpdGgtYmFja2dyb3VuZC1wYWdlcycsXHJcbiAgICAgICAgJy0tZGlzYWJsZS1jb21wb25lbnQtdXBkYXRlJyxcclxuICAgICAgICAnLS1kaXNhYmxlLWRlZmF1bHQtYXBwcycsXHJcbiAgICAgICAgJy0tZGlzYWJsZS1kZXYtc2htLXVzYWdlJyxcclxuICAgICAgICAnLS1kaXNhYmxlLWRvbWFpbi1yZWxpYWJpbGl0eScsXHJcbiAgICAgICAgJy0tZGlzYWJsZS1leHRlbnNpb25zJyxcclxuICAgICAgICAnLS1kaXNhYmxlLWZlYXR1cmVzPUNhbGN1bGF0ZU5hdGl2ZVdpbk9jY2x1c2lvbixJbnRlcmVzdEZlZWRDb250ZW50U3VnZ2VzdGlvbnMsV2ViT1RQJyxcclxuICAgICAgICAnLS1kaXNhYmxlLWhhbmctbW9uaXRvcicsXHJcbiAgICAgICAgJy0tZGlzYWJsZS1pcGMtZmxvb2RpbmctcHJvdGVjdGlvbicsXHJcbiAgICAgICAgJy0tZGlzYWJsZS1sb2dnaW5nJyxcclxuICAgICAgICAnLS1kaXNhYmxlLW5vdGlmaWNhdGlvbnMnLFxyXG4gICAgICAgICctLWRpc2FibGUtb2ZmZXItc3RvcmUtdW5tYXNrZWQtd2FsbGV0LWNhcmRzJyxcclxuICAgICAgICAnLS1kaXNhYmxlLXBvcHVwLWJsb2NraW5nJyxcclxuICAgICAgICAnLS1kaXNhYmxlLXByaW50LXByZXZpZXcnLFxyXG4gICAgICAgICctLWRpc2FibGUtcHJvbXB0LW9uLXJlcG9zdCcsXHJcbiAgICAgICAgJy0tZGlzYWJsZS1yZW5kZXJlci1iYWNrZ3JvdW5kaW5nJyxcclxuICAgICAgICAnLS1kaXNhYmxlLXNlYXJjaC1lbmdpbmUtY2hvaWNlLXNjcmVlbicsXHJcbiAgICAgICAgJy0tZGlzYWJsZS1zZXNzaW9uLWNyYXNoZWQtYnViYmxlJyxcclxuICAgICAgICAnLS1kaXNhYmxlLXNldHVpZC1zYW5kYm94JyxcclxuICAgICAgICAnLS1kaXNhYmxlLXNpdGUtaXNvbGF0aW9uLXRyaWFscycsXHJcbiAgICAgICAgJy0tZGlzYWJsZS1zcGVlY2gtYXBpJyxcclxuICAgICAgICAnLS1kaXNhYmxlLXN5bmMnLFxyXG4gICAgICAgICctLWVuYWJsZS11bnNhZmUtd2ViZ3B1JyxcclxuICAgICAgICAnLS1oaWRlLWNyYXNoLXJlc3RvcmUtYnViYmxlJyxcclxuICAgICAgICAnLS1oaWRlLXNjcm9sbGJhcnMnLFxyXG4gICAgICAgICctLW1ldHJpY3MtcmVjb3JkaW5nLW9ubHknLFxyXG4gICAgICAgICctLW11dGUtYXVkaW8nLFxyXG4gICAgICAgICctLW5vLWRlZmF1bHQtYnJvd3Nlci1jaGVjaycsXHJcbiAgICAgICAgJy0tbm8tZmlyc3QtcnVuJyxcclxuICAgICAgICAnLS1uby1waW5ncycsXHJcbiAgICAgICAgJy0tbm8tc2FuZGJveCcsXHJcbiAgICAgICAgJy0tbm8tc3RhcnR1cC13aW5kb3cnLFxyXG4gICAgICAgICctLW5vLXp5Z290ZScsXHJcbiAgICAgICAgJy0tcGFzc3dvcmQtc3RvcmU9YmFzaWMnLFxyXG4gICAgICAgICctLXByb2Nlc3MtcGVyLXRhYicsXHJcbiAgICAgICAgJy0tdXNlLW1vY2sta2V5Y2hhaW4nXHJcbiAgICAgIF0sXHJcbiAgICAgIHR5cGVzOiBbJ3N0cmluZ1tdJ10sXHJcbiAgICAgIGVudkxpbms6ICdQVVBQRVRFRVJfQVJHUycsXHJcbiAgICAgIGNsaU5hbWU6ICdwdXBwZXRlZXJBcmdzJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdBcnJheSBvZiBQdXBwZXRlZXIgYXJndW1lbnRzJyxcclxuICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgIHR5cGU6ICdsaXN0JyxcclxuICAgICAgICBzZXBhcmF0b3I6ICc7J1xyXG4gICAgICB9XHJcbiAgICB9XHJcbiAgfSxcclxuICBoaWdoY2hhcnRzOiB7XHJcbiAgICB2ZXJzaW9uOiB7XHJcbiAgICAgIHZhbHVlOiAnbGF0ZXN0JyxcclxuICAgICAgdHlwZXM6IFsnc3RyaW5nJ10sXHJcbiAgICAgIGVudkxpbms6ICdISUdIQ0hBUlRTX1ZFUlNJT04nLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ0hpZ2hjaGFydHMgdmVyc2lvbicsXHJcbiAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICB0eXBlOiAndGV4dCdcclxuICAgICAgfVxyXG4gICAgfSxcclxuICAgIGNkblVybDoge1xyXG4gICAgICB2YWx1ZTogJ2h0dHBzOi8vY29kZS5oaWdoY2hhcnRzLmNvbScsXHJcbiAgICAgIHR5cGVzOiBbJ3N0cmluZyddLFxyXG4gICAgICBlbnZMaW5rOiAnSElHSENIQVJUU19DRE5fVVJMJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdDRE4gVVJMIGZvciBIaWdoY2hhcnRzIHNjcmlwdHMnLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ3RleHQnXHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICBmb3JjZUZldGNoOiB7XHJcbiAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgdHlwZXM6IFsnYm9vbGVhbiddLFxyXG4gICAgICBlbnZMaW5rOiAnSElHSENIQVJUU19GT1JDRV9GRVRDSCcsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnRmxhZyB0byByZWZldGNoIHNjcmlwdHMgYWZ0ZXIgZWFjaCBzZXJ2ZXIgcmVydW4nLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ3RvZ2dsZSdcclxuICAgICAgfVxyXG4gICAgfSxcclxuICAgIGNhY2hlUGF0aDoge1xyXG4gICAgICB2YWx1ZTogJy5jYWNoZScsXHJcbiAgICAgIHR5cGVzOiBbJ3N0cmluZyddLFxyXG4gICAgICBlbnZMaW5rOiAnSElHSENIQVJUU19DQUNIRV9QQVRIJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdEaXJlY3RvcnkgcGF0aCBmb3IgY2FjaGVkIEhpZ2hjaGFydHMgc2NyaXB0cycsXHJcbiAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICB0eXBlOiAndGV4dCdcclxuICAgICAgfVxyXG4gICAgfSxcclxuICAgIGNvcmVTY3JpcHRzOiB7XHJcbiAgICAgIHZhbHVlOiBbJ2hpZ2hjaGFydHMnLCAnaGlnaGNoYXJ0cy1tb3JlJywgJ2hpZ2hjaGFydHMtM2QnXSxcclxuICAgICAgdHlwZXM6IFsnc3RyaW5nW10nXSxcclxuICAgICAgZW52TGluazogJ0hJR0hDSEFSVFNfQ09SRV9TQ1JJUFRTJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdIaWdoY2hhcnRzIGNvcmUgc2NyaXB0cyB0byBmZXRjaCcsXHJcbiAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICB0eXBlOiAnbXVsdGlzZWxlY3QnLFxyXG4gICAgICAgIGluc3RydWN0aW9uczogJ1NwYWNlOiBTZWxlY3Qgc3BlY2lmaWMsIEE6IFNlbGVjdCBhbGwsIEVudGVyOiBDb25maXJtJ1xyXG4gICAgICB9XHJcbiAgICB9LFxyXG4gICAgbW9kdWxlU2NyaXB0czoge1xyXG4gICAgICB2YWx1ZTogW1xyXG4gICAgICAgICdzdG9jaycsXHJcbiAgICAgICAgJ21hcCcsXHJcbiAgICAgICAgJ2dhbnR0JyxcclxuICAgICAgICAnZXhwb3J0aW5nJyxcclxuICAgICAgICAncGFyYWxsZWwtY29vcmRpbmF0ZXMnLFxyXG4gICAgICAgICdhY2Nlc3NpYmlsaXR5JyxcclxuICAgICAgICAvLyAnYW5ub3RhdGlvbnMtYWR2YW5jZWQnLFxyXG4gICAgICAgICdib29zdC1jYW52YXMnLFxyXG4gICAgICAgICdib29zdCcsXHJcbiAgICAgICAgJ2RhdGEnLFxyXG4gICAgICAgICdkYXRhLXRvb2xzJyxcclxuICAgICAgICAnZHJhZ2dhYmxlLXBvaW50cycsXHJcbiAgICAgICAgJ3N0YXRpYy1zY2FsZScsXHJcbiAgICAgICAgJ2Jyb2tlbi1heGlzJyxcclxuICAgICAgICAnaGVhdG1hcCcsXHJcbiAgICAgICAgJ3RpbGVtYXAnLFxyXG4gICAgICAgICd0aWxlZHdlYm1hcCcsXHJcbiAgICAgICAgJ3RpbWVsaW5lJyxcclxuICAgICAgICAndHJlZW1hcCcsXHJcbiAgICAgICAgJ3RyZWVncmFwaCcsXHJcbiAgICAgICAgJ2l0ZW0tc2VyaWVzJyxcclxuICAgICAgICAnZHJpbGxkb3duJyxcclxuICAgICAgICAnaGlzdG9ncmFtLWJlbGxjdXJ2ZScsXHJcbiAgICAgICAgJ2J1bGxldCcsXHJcbiAgICAgICAgJ2Z1bm5lbCcsXHJcbiAgICAgICAgJ2Z1bm5lbDNkJyxcclxuICAgICAgICAnZ2VvaGVhdG1hcCcsXHJcbiAgICAgICAgJ3B5cmFtaWQzZCcsXHJcbiAgICAgICAgJ25ldHdvcmtncmFwaCcsXHJcbiAgICAgICAgJ292ZXJsYXBwaW5nLWRhdGFsYWJlbHMnLFxyXG4gICAgICAgICdwYXJldG8nLFxyXG4gICAgICAgICdwYXR0ZXJuLWZpbGwnLFxyXG4gICAgICAgICdwaWN0b3JpYWwnLFxyXG4gICAgICAgICdwcmljZS1pbmRpY2F0b3InLFxyXG4gICAgICAgICdzYW5rZXknLFxyXG4gICAgICAgICdhcmMtZGlhZ3JhbScsXHJcbiAgICAgICAgJ2RlcGVuZGVuY3ktd2hlZWwnLFxyXG4gICAgICAgICdzZXJpZXMtbGFiZWwnLFxyXG4gICAgICAgICdzZXJpZXMtb24tcG9pbnQnLFxyXG4gICAgICAgICdzb2xpZC1nYXVnZScsXHJcbiAgICAgICAgJ3NvbmlmaWNhdGlvbicsXHJcbiAgICAgICAgLy8gJ3N0b2NrLXRvb2xzJyxcclxuICAgICAgICAnc3RyZWFtZ3JhcGgnLFxyXG4gICAgICAgICdzdW5idXJzdCcsXHJcbiAgICAgICAgJ3ZhcmlhYmxlLXBpZScsXHJcbiAgICAgICAgJ3Zhcml3aWRlJyxcclxuICAgICAgICAndmVjdG9yJyxcclxuICAgICAgICAndmVubicsXHJcbiAgICAgICAgJ3dpbmRiYXJiJyxcclxuICAgICAgICAnd29yZGNsb3VkJyxcclxuICAgICAgICAneHJhbmdlJyxcclxuICAgICAgICAnbm8tZGF0YS10by1kaXNwbGF5JyxcclxuICAgICAgICAnZHJhZy1wYW5lcycsXHJcbiAgICAgICAgJ2RlYnVnZ2VyJyxcclxuICAgICAgICAnZHVtYmJlbGwnLFxyXG4gICAgICAgICdsb2xsaXBvcCcsXHJcbiAgICAgICAgJ2N5bGluZGVyJyxcclxuICAgICAgICAnb3JnYW5pemF0aW9uJyxcclxuICAgICAgICAnZG90cGxvdCcsXHJcbiAgICAgICAgJ21hcmtlci1jbHVzdGVycycsXHJcbiAgICAgICAgJ2hvbGxvd2NhbmRsZXN0aWNrJyxcclxuICAgICAgICAnaGVpa2luYXNoaScsXHJcbiAgICAgICAgJ2Zsb3dtYXAnLFxyXG4gICAgICAgICdleHBvcnQtZGF0YScsXHJcbiAgICAgICAgJ25hdmlnYXRvcicsXHJcbiAgICAgICAgJ3RleHRwYXRoJ1xyXG4gICAgICBdLFxyXG4gICAgICB0eXBlczogWydzdHJpbmdbXSddLFxyXG4gICAgICBlbnZMaW5rOiAnSElHSENIQVJUU19NT0RVTEVfU0NSSVBUUycsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnSGlnaGNoYXJ0cyBtb2R1bGUgc2NyaXB0cyB0byBmZXRjaCcsXHJcbiAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICB0eXBlOiAnbXVsdGlzZWxlY3QnLFxyXG4gICAgICAgIGluc3RydWN0aW9uczogJ1NwYWNlOiBTZWxlY3Qgc3BlY2lmaWMsIEE6IFNlbGVjdCBhbGwsIEVudGVyOiBDb25maXJtJ1xyXG4gICAgICB9XHJcbiAgICB9LFxyXG4gICAgaW5kaWNhdG9yU2NyaXB0czoge1xyXG4gICAgICB2YWx1ZTogWydpbmRpY2F0b3JzLWFsbCddLFxyXG4gICAgICB0eXBlczogWydzdHJpbmdbXSddLFxyXG4gICAgICBlbnZMaW5rOiAnSElHSENIQVJUU19JTkRJQ0FUT1JfU0NSSVBUUycsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnSGlnaGNoYXJ0cyBpbmRpY2F0b3Igc2NyaXB0cyB0byBmZXRjaCcsXHJcbiAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICB0eXBlOiAnbXVsdGlzZWxlY3QnLFxyXG4gICAgICAgIGluc3RydWN0aW9uczogJ1NwYWNlOiBTZWxlY3Qgc3BlY2lmaWMsIEE6IFNlbGVjdCBhbGwsIEVudGVyOiBDb25maXJtJ1xyXG4gICAgICB9XHJcbiAgICB9LFxyXG4gICAgY3VzdG9tU2NyaXB0czoge1xyXG4gICAgICB2YWx1ZTogW1xyXG4gICAgICAgICdodHRwczovL2NkbmpzLmNsb3VkZmxhcmUuY29tL2FqYXgvbGlicy9tb21lbnQuanMvMi4zMC4xL21vbWVudC5taW4uanMnLFxyXG4gICAgICAgICdodHRwczovL2NkbmpzLmNsb3VkZmxhcmUuY29tL2FqYXgvbGlicy9tb21lbnQtdGltZXpvbmUvMC41LjQ1L21vbWVudC10aW1lem9uZS13aXRoLWRhdGEubWluLmpzJ1xyXG4gICAgICBdLFxyXG4gICAgICB0eXBlczogWydzdHJpbmdbXSddLFxyXG4gICAgICBlbnZMaW5rOiAnSElHSENIQVJUU19DVVNUT01fU0NSSVBUUycsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnQWRkaXRpb25hbCBjdXN0b20gc2NyaXB0cyBvciBkZXBlbmRlbmNpZXMgdG8gZmV0Y2gnLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ2xpc3QnLFxyXG4gICAgICAgIHNlcGFyYXRvcjogJzsnXHJcbiAgICAgIH1cclxuICAgIH1cclxuICB9LFxyXG4gIGV4cG9ydDoge1xyXG4gICAgaW5maWxlOiB7XHJcbiAgICAgIHZhbHVlOiBudWxsLFxyXG4gICAgICB0eXBlczogWydzdHJpbmcnLCAnbnVsbCddLFxyXG4gICAgICBlbnZMaW5rOiAnRVhQT1JUX0lORklMRScsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdJbnB1dCBmaWxlbmFtZSB3aXRoIHR5cGUsIGZvcm1hdHRlZCBjb3JyZWN0bHkgYXMgSlNPTiBvciBTVkcnLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ3RleHQnXHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICBpbnN0cjoge1xyXG4gICAgICB2YWx1ZTogbnVsbCxcclxuICAgICAgdHlwZXM6IFsnT2JqZWN0JywgJ3N0cmluZycsICdudWxsJ10sXHJcbiAgICAgIGVudkxpbms6ICdFWFBPUlRfSU5TVFInLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnT3ZlcnJpZGVzIHRoZSBgaW5maWxlYCB3aXRoIEpTT04sIHN0cmluZ2lmaWVkIEpTT04sIG9yIFNWRyBpbnB1dCcsXHJcbiAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICB0eXBlOiAndGV4dCdcclxuICAgICAgfVxyXG4gICAgfSxcclxuICAgIG9wdGlvbnM6IHtcclxuICAgICAgdmFsdWU6IG51bGwsXHJcbiAgICAgIHR5cGVzOiBbJ09iamVjdCcsICdzdHJpbmcnLCAnbnVsbCddLFxyXG4gICAgICBlbnZMaW5rOiAnRVhQT1JUX09QVElPTlMnLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ0FsaWFzIGZvciB0aGUgYGluc3RyYCBvcHRpb24nLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ3RleHQnXHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICBzdmc6IHtcclxuICAgICAgdmFsdWU6IG51bGwsXHJcbiAgICAgIHR5cGVzOiBbJ3N0cmluZycsICdudWxsJ10sXHJcbiAgICAgIGVudkxpbms6ICdFWFBPUlRfU1ZHJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdTVkcgc3RyaW5nIHJlcHJlc2VudGF0aW9uIG9mIHRoZSBjaGFydCB0byByZW5kZXInLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ3RleHQnXHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICBiYXRjaDoge1xyXG4gICAgICB2YWx1ZTogbnVsbCxcclxuICAgICAgdHlwZXM6IFsnc3RyaW5nJywgJ251bGwnXSxcclxuICAgICAgZW52TGluazogJ0VYUE9SVF9CQVRDSCcsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdCYXRjaCBqb2Igc3RyaW5nIHdpdGggaW5wdXQvb3V0cHV0IHBhaXJzOiBcImluPW91dDtpbj1vdXQ7Li4uXCInLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ3RleHQnXHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICBvdXRmaWxlOiB7XHJcbiAgICAgIHZhbHVlOiBudWxsLFxyXG4gICAgICB0eXBlczogWydzdHJpbmcnLCAnbnVsbCddLFxyXG4gICAgICBlbnZMaW5rOiAnRVhQT1JUX09VVEZJTEUnLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnT3V0cHV0IGZpbGVuYW1lIHdpdGggdHlwZS4gQ2FuIGJlIGpwZWcsIHBuZywgcGRmLCBvciBzdmcgYW5kIGlnbm9yZXMgYHR5cGVgIG9wdGlvbicsXHJcbiAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICB0eXBlOiAndGV4dCdcclxuICAgICAgfVxyXG4gICAgfSxcclxuICAgIHR5cGU6IHtcclxuICAgICAgdmFsdWU6ICdwbmcnLFxyXG4gICAgICB0eXBlczogWydzdHJpbmcnXSxcclxuICAgICAgZW52TGluazogJ0VYUE9SVF9UWVBFJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdGaWxlIGV4cG9ydCBmb3JtYXQuIENhbiBiZSBqcGVnLCBwbmcsIHBkZiwgb3Igc3ZnJyxcclxuICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgIHR5cGU6ICdzZWxlY3QnLFxyXG4gICAgICAgIGhpbnQ6ICdEZWZhdWx0OiBwbmcnLFxyXG4gICAgICAgIGNob2ljZXM6IFsncG5nJywgJ2pwZWcnLCAncGRmJywgJ3N2ZyddXHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICBjb25zdHI6IHtcclxuICAgICAgdmFsdWU6ICdjaGFydCcsXHJcbiAgICAgIHR5cGVzOiBbJ3N0cmluZyddLFxyXG4gICAgICBlbnZMaW5rOiAnRVhQT1JUX0NPTlNUUicsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdDaGFydCBjb25zdHJ1Y3Rvci4gQ2FuIGJlIGNoYXJ0LCBzdG9ja0NoYXJ0LCBtYXBDaGFydCwgb3IgZ2FudHRDaGFydCcsXHJcbiAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICB0eXBlOiAnc2VsZWN0JyxcclxuICAgICAgICBoaW50OiAnRGVmYXVsdDogY2hhcnQnLFxyXG4gICAgICAgIGNob2ljZXM6IFsnY2hhcnQnLCAnc3RvY2tDaGFydCcsICdtYXBDaGFydCcsICdnYW50dENoYXJ0J11cclxuICAgICAgfVxyXG4gICAgfSxcclxuICAgIGI2NDoge1xyXG4gICAgICB2YWx1ZTogZmFsc2UsXHJcbiAgICAgIHR5cGVzOiBbJ2Jvb2xlYW4nXSxcclxuICAgICAgZW52TGluazogJ0VYUE9SVF9CNjQnLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnV2hldGhlciBvciBub3QgdG8gdGhlIGNoYXJ0IHNob3VsZCBiZSByZWNlaXZlZCBpbiBCYXNlNjQgZm9ybWF0IGluc3RlYWQgb2YgYmluYXJ5JyxcclxuICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgIHR5cGU6ICd0b2dnbGUnXHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICBub0Rvd25sb2FkOiB7XHJcbiAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgdHlwZXM6IFsnYm9vbGVhbiddLFxyXG4gICAgICBlbnZMaW5rOiAnRVhQT1JUX05PX0RPV05MT0FEJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ1doZXRoZXIgb3Igbm90IHRvIGluY2x1ZGUgb3IgZXhjbHVkZSBhdHRhY2htZW50IGhlYWRlcnMgaW4gdGhlIHJlc3BvbnNlJyxcclxuICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgIHR5cGU6ICd0b2dnbGUnXHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICBoZWlnaHQ6IHtcclxuICAgICAgdmFsdWU6IG51bGwsXHJcbiAgICAgIHR5cGVzOiBbJ251bWJlcicsICdudWxsJ10sXHJcbiAgICAgIGVudkxpbms6ICdFWFBPUlRfSEVJR0hUJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdIZWlnaHQgb2YgdGhlIGV4cG9ydGVkIGNoYXJ0LCBvdmVycmlkZXMgY2hhcnQgc2V0dGluZ3MnLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ251bWJlcidcclxuICAgICAgfVxyXG4gICAgfSxcclxuICAgIHdpZHRoOiB7XHJcbiAgICAgIHZhbHVlOiBudWxsLFxyXG4gICAgICB0eXBlczogWydudW1iZXInLCAnbnVsbCddLFxyXG4gICAgICBlbnZMaW5rOiAnRVhQT1JUX1dJRFRIJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdXaWR0aCBvZiB0aGUgZXhwb3J0ZWQgY2hhcnQsIG92ZXJyaWRlcyBjaGFydCBzZXR0aW5ncycsXHJcbiAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICB0eXBlOiAnbnVtYmVyJ1xyXG4gICAgICB9XHJcbiAgICB9LFxyXG4gICAgc2NhbGU6IHtcclxuICAgICAgdmFsdWU6IG51bGwsXHJcbiAgICAgIHR5cGVzOiBbJ251bWJlcicsICdudWxsJ10sXHJcbiAgICAgIGVudkxpbms6ICdFWFBPUlRfU0NBTEUnLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnU2NhbGUgb2YgdGhlIGV4cG9ydGVkIGNoYXJ0LCBvdmVycmlkZXMgY2hhcnQgc2V0dGluZ3MuIFJhbmdlcyBmcm9tIDAuMSB0byA1LjAnLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ251bWJlcidcclxuICAgICAgfVxyXG4gICAgfSxcclxuICAgIGRlZmF1bHRIZWlnaHQ6IHtcclxuICAgICAgdmFsdWU6IDQwMCxcclxuICAgICAgdHlwZXM6IFsnbnVtYmVyJ10sXHJcbiAgICAgIGVudkxpbms6ICdFWFBPUlRfREVGQVVMVF9IRUlHSFQnLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ0RlZmF1bHQgaGVpZ2h0IG9mIHRoZSBleHBvcnRlZCBjaGFydCBpZiBub3Qgc2V0JyxcclxuICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgIHR5cGU6ICdudW1iZXInXHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICBkZWZhdWx0V2lkdGg6IHtcclxuICAgICAgdmFsdWU6IDYwMCxcclxuICAgICAgdHlwZXM6IFsnbnVtYmVyJ10sXHJcbiAgICAgIGVudkxpbms6ICdFWFBPUlRfREVGQVVMVF9XSURUSCcsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnRGVmYXVsdCB3aWR0aCBvZiB0aGUgZXhwb3J0ZWQgY2hhcnQgaWYgbm90IHNldCcsXHJcbiAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICB0eXBlOiAnbnVtYmVyJ1xyXG4gICAgICB9XHJcbiAgICB9LFxyXG4gICAgZGVmYXVsdFNjYWxlOiB7XHJcbiAgICAgIHZhbHVlOiAxLFxyXG4gICAgICB0eXBlczogWydudW1iZXInXSxcclxuICAgICAgZW52TGluazogJ0VYUE9SVF9ERUZBVUxUX1NDQUxFJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ0RlZmF1bHQgc2NhbGUgb2YgdGhlIGV4cG9ydGVkIGNoYXJ0IGlmIG5vdCBzZXQuIFJhbmdlcyBmcm9tIDAuMSB0byA1LjAnLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgICAgbWluOiAwLjEsXHJcbiAgICAgICAgbWF4OiA1XHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICBnbG9iYWxPcHRpb25zOiB7XHJcbiAgICAgIHZhbHVlOiBudWxsLFxyXG4gICAgICB0eXBlczogWydPYmplY3QnLCAnc3RyaW5nJywgJ251bGwnXSxcclxuICAgICAgZW52TGluazogJ0VYUE9SVF9HTE9CQUxfT1BUSU9OUycsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdKU09OLCBzdHJpbmdpZmllZCBKU09OIG9yIGZpbGVuYW1lIHdpdGggZ2xvYmFsIG9wdGlvbnMgZm9yIEhpZ2hjaGFydHMuc2V0T3B0aW9ucycsXHJcbiAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICB0eXBlOiAndGV4dCdcclxuICAgICAgfVxyXG4gICAgfSxcclxuICAgIHRoZW1lT3B0aW9uczoge1xyXG4gICAgICB2YWx1ZTogbnVsbCxcclxuICAgICAgdHlwZXM6IFsnT2JqZWN0JywgJ3N0cmluZycsICdudWxsJ10sXHJcbiAgICAgIGVudkxpbms6ICdFWFBPUlRfVEhFTUVfT1BUSU9OUycsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdKU09OLCBzdHJpbmdpZmllZCBKU09OIG9yIGZpbGVuYW1lIHdpdGggdGhlbWUgb3B0aW9ucyBmb3IgSGlnaGNoYXJ0cy5zZXRPcHRpb25zJyxcclxuICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgIHR5cGU6ICd0ZXh0J1xyXG4gICAgICB9XHJcbiAgICB9LFxyXG4gICAgcmFzdGVyaXphdGlvblRpbWVvdXQ6IHtcclxuICAgICAgdmFsdWU6IDE1MDAsXHJcbiAgICAgIHR5cGVzOiBbJ251bWJlciddLFxyXG4gICAgICBlbnZMaW5rOiAnRVhQT1JUX1JBU1RFUklaQVRJT05fVElNRU9VVCcsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnTWlsbGlzZWNvbmRzIHRvIHdhaXQgZm9yIHdlYnBhZ2UgcmVuZGVyaW5nJyxcclxuICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgIHR5cGU6ICdudW1iZXInXHJcbiAgICAgIH1cclxuICAgIH1cclxuICB9LFxyXG4gIGN1c3RvbUxvZ2ljOiB7XHJcbiAgICBhbGxvd0NvZGVFeGVjdXRpb246IHtcclxuICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICB0eXBlczogWydib29sZWFuJ10sXHJcbiAgICAgIGVudkxpbms6ICdDVVNUT01fTE9HSUNfQUxMT1dfQ09ERV9FWEVDVVRJT04nLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnQWxsb3dzIG9yIGRpc2FsbG93cyBleGVjdXRpb24gb2YgYXJiaXRyYXJ5IGNvZGUgZHVyaW5nIGV4cG9ydGluZycsXHJcbiAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICB0eXBlOiAndG9nZ2xlJ1xyXG4gICAgICB9XHJcbiAgICB9LFxyXG4gICAgYWxsb3dGaWxlUmVzb3VyY2VzOiB7XHJcbiAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgdHlwZXM6IFsnYm9vbGVhbiddLFxyXG4gICAgICBlbnZMaW5rOiAnQ1VTVE9NX0xPR0lDX0FMTE9XX0ZJTEVfUkVTT1VSQ0VTJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ0FsbG93cyBvciBkaXNhbGxvd3MgaW5qZWN0aW9uIG9mIGZpbGVzeXN0ZW0gcmVzb3VyY2VzIChkaXNhYmxlZCBpbiBzZXJ2ZXIgbW9kZSknLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ3RvZ2dsZSdcclxuICAgICAgfVxyXG4gICAgfSxcclxuICAgIGN1c3RvbUNvZGU6IHtcclxuICAgICAgdmFsdWU6IG51bGwsXHJcbiAgICAgIHR5cGVzOiBbJ3N0cmluZycsICdudWxsJ10sXHJcbiAgICAgIGVudkxpbms6ICdDVVNUT01fTE9HSUNfQ1VTVE9NX0NPREUnLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnQ3VzdG9tIGNvZGUgdG8gZXhlY3V0ZSBiZWZvcmUgY2hhcnQgaW5pdGlhbGl6YXRpb24uIENhbiBiZSBhIGZ1bmN0aW9uLCBjb2RlIHdyYXBwZWQgaW4gYSBmdW5jdGlvbiwgb3IgYSAuanMgZmlsZW5hbWUnLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ3RleHQnXHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICBjYWxsYmFjazoge1xyXG4gICAgICB2YWx1ZTogbnVsbCxcclxuICAgICAgdHlwZXM6IFsnc3RyaW5nJywgJ251bGwnXSxcclxuICAgICAgZW52TGluazogJ0NVU1RPTV9MT0dJQ19DQUxMQkFDSycsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdKYXZhU2NyaXB0IGNvZGUgdG8gcnVuIGR1cmluZyBjb25zdHJ1Y3Rpb24uIENhbiBiZSBhIGZ1bmN0aW9uIG9yIGEgLmpzIGZpbGVuYW1lJyxcclxuICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgIHR5cGU6ICd0ZXh0J1xyXG4gICAgICB9XHJcbiAgICB9LFxyXG4gICAgcmVzb3VyY2VzOiB7XHJcbiAgICAgIHZhbHVlOiBudWxsLFxyXG4gICAgICB0eXBlczogWydPYmplY3QnLCAnc3RyaW5nJywgJ251bGwnXSxcclxuICAgICAgZW52TGluazogJ0NVU1RPTV9MT0dJQ19SRVNPVVJDRVMnLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnQWRkaXRpb25hbCByZXNvdXJjZXMgYXMgSlNPTiwgc3RyaW5naWZpZWQgSlNPTiwgb3IgZmlsZW5hbWUsIGNvbnRhaW5pbmcgZmlsZXMsIGpzLCBhbmQgY3NzIHNlY3Rpb25zJyxcclxuICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgIHR5cGU6ICd0ZXh0J1xyXG4gICAgICB9XHJcbiAgICB9LFxyXG4gICAgbG9hZENvbmZpZzoge1xyXG4gICAgICB2YWx1ZTogbnVsbCxcclxuICAgICAgdHlwZXM6IFsnc3RyaW5nJywgJ251bGwnXSxcclxuICAgICAgZW52TGluazogJ0NVU1RPTV9MT0dJQ19MT0FEX0NPTkZJRycsXHJcbiAgICAgIGxlZ2FjeU5hbWU6ICdmcm9tRmlsZScsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnRmlsZSB3aXRoIGEgcHJlLWRlZmluZWQgY29uZmlndXJhdGlvbiB0byB1c2UnLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ3RleHQnXHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICBjcmVhdGVDb25maWc6IHtcclxuICAgICAgdmFsdWU6IG51bGwsXHJcbiAgICAgIHR5cGVzOiBbJ3N0cmluZycsICdudWxsJ10sXHJcbiAgICAgIGVudkxpbms6ICdDVVNUT01fTE9HSUNfQ1JFQVRFX0NPTkZJRycsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdQcm9tcHQtYmFzZWQgb3B0aW9uIHNldHRpbmcsIHNhdmVkIHRvIGEgcHJvdmlkZWQgY29uZmlnIGZpbGUnLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ3RleHQnXHJcbiAgICAgIH1cclxuICAgIH1cclxuICB9LFxyXG4gIHNlcnZlcjoge1xyXG4gICAgZW5hYmxlOiB7XHJcbiAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgdHlwZXM6IFsnYm9vbGVhbiddLFxyXG4gICAgICBlbnZMaW5rOiAnU0VSVkVSX0VOQUJMRScsXHJcbiAgICAgIGNsaU5hbWU6ICdlbmFibGVTZXJ2ZXInLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ1N0YXJ0cyB0aGUgc2VydmVyIHdoZW4gdHJ1ZScsXHJcbiAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICB0eXBlOiAndG9nZ2xlJ1xyXG4gICAgICB9XHJcbiAgICB9LFxyXG4gICAgaG9zdDoge1xyXG4gICAgICB2YWx1ZTogJzAuMC4wLjAnLFxyXG4gICAgICB0eXBlczogWydzdHJpbmcnXSxcclxuICAgICAgZW52TGluazogJ1NFUlZFUl9IT1NUJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdIb3N0bmFtZSBvZiB0aGUgc2VydmVyJyxcclxuICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgIHR5cGU6ICd0ZXh0J1xyXG4gICAgICB9XHJcbiAgICB9LFxyXG4gICAgcG9ydDoge1xyXG4gICAgICB2YWx1ZTogNzgwMSxcclxuICAgICAgdHlwZXM6IFsnbnVtYmVyJ10sXHJcbiAgICAgIGVudkxpbms6ICdTRVJWRVJfUE9SVCcsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnUG9ydCBudW1iZXIgZm9yIHRoZSBzZXJ2ZXInLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ251bWJlcidcclxuICAgICAgfVxyXG4gICAgfSxcclxuICAgIHVwbG9hZExpbWl0OiB7XHJcbiAgICAgIHZhbHVlOiAzLFxyXG4gICAgICB0eXBlczogWydudW1iZXInXSxcclxuICAgICAgZW52TGluazogJ1NFUlZFUl9VUExPQURfTElNSVQnLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ01heGltdW0gcmVxdWVzdCBib2R5IHNpemUgaW4gTUInLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ251bWJlcidcclxuICAgICAgfVxyXG4gICAgfSxcclxuICAgIGJlbmNobWFya2luZzoge1xyXG4gICAgICB2YWx1ZTogZmFsc2UsXHJcbiAgICAgIHR5cGVzOiBbJ2Jvb2xlYW4nXSxcclxuICAgICAgZW52TGluazogJ1NFUlZFUl9CRU5DSE1BUktJTkcnLFxyXG4gICAgICBjbGlOYW1lOiAnc2VydmVyQmVuY2htYXJraW5nJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ0Rpc3BsYXlzIG9yIG5vdCBhY3Rpb24gZHVyYXRpb25zIGluIG1pbGxpc2Vjb25kcyBkdXJpbmcgc2VydmVyIHJlcXVlc3RzJyxcclxuICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgIHR5cGU6ICd0b2dnbGUnXHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICBwcm94eToge1xyXG4gICAgICBob3N0OiB7XHJcbiAgICAgICAgdmFsdWU6IG51bGwsXHJcbiAgICAgICAgdHlwZXM6IFsnc3RyaW5nJywgJ251bGwnXSxcclxuICAgICAgICBlbnZMaW5rOiAnU0VSVkVSX1BST1hZX0hPU1QnLFxyXG4gICAgICAgIGNsaU5hbWU6ICdwcm94eUhvc3QnLFxyXG4gICAgICAgIGRlc2NyaXB0aW9uOiAnSG9zdCBvZiB0aGUgcHJveHkgc2VydmVyLCBpZiBhcHBsaWNhYmxlJyxcclxuICAgICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgICB0eXBlOiAndGV4dCdcclxuICAgICAgICB9XHJcbiAgICAgIH0sXHJcbiAgICAgIHBvcnQ6IHtcclxuICAgICAgICB2YWx1ZTogbnVsbCxcclxuICAgICAgICB0eXBlczogWydudW1iZXInLCAnbnVsbCddLFxyXG4gICAgICAgIGVudkxpbms6ICdTRVJWRVJfUFJPWFlfUE9SVCcsXHJcbiAgICAgICAgY2xpTmFtZTogJ3Byb3h5UG9ydCcsXHJcbiAgICAgICAgZGVzY3JpcHRpb246ICdQb3J0IG9mIHRoZSBwcm94eSBzZXJ2ZXIsIGlmIGFwcGxpY2FibGUnLFxyXG4gICAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICAgIHR5cGU6ICdudW1iZXInXHJcbiAgICAgICAgfVxyXG4gICAgICB9LFxyXG4gICAgICB0aW1lb3V0OiB7XHJcbiAgICAgICAgdmFsdWU6IDUwMDAsXHJcbiAgICAgICAgdHlwZXM6IFsnbnVtYmVyJ10sXHJcbiAgICAgICAgZW52TGluazogJ1NFUlZFUl9QUk9YWV9USU1FT1VUJyxcclxuICAgICAgICBjbGlOYW1lOiAncHJveHlUaW1lb3V0JyxcclxuICAgICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAgICdUaW1lb3V0IGluIG1pbGxpc2Vjb25kcyBmb3IgdGhlIHByb3h5IHNlcnZlciwgaWYgYXBwbGljYWJsZScsXHJcbiAgICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgICAgdHlwZTogJ251bWJlcidcclxuICAgICAgICB9XHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICByYXRlTGltaXRpbmc6IHtcclxuICAgICAgZW5hYmxlOiB7XHJcbiAgICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICAgIHR5cGVzOiBbJ2Jvb2xlYW4nXSxcclxuICAgICAgICBlbnZMaW5rOiAnU0VSVkVSX1JBVEVfTElNSVRJTkdfRU5BQkxFJyxcclxuICAgICAgICBjbGlOYW1lOiAnZW5hYmxlUmF0ZUxpbWl0aW5nJyxcclxuICAgICAgICBkZXNjcmlwdGlvbjogJ0VuYWJsZXMgb3IgZGlzYWJsZXMgcmF0ZSBsaW1pdGluZyBvbiB0aGUgc2VydmVyJyxcclxuICAgICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgICB0eXBlOiAndG9nZ2xlJ1xyXG4gICAgICAgIH1cclxuICAgICAgfSxcclxuICAgICAgbWF4UmVxdWVzdHM6IHtcclxuICAgICAgICB2YWx1ZTogMTAsXHJcbiAgICAgICAgdHlwZXM6IFsnbnVtYmVyJ10sXHJcbiAgICAgICAgZW52TGluazogJ1NFUlZFUl9SQVRFX0xJTUlUSU5HX01BWF9SRVFVRVNUUycsXHJcbiAgICAgICAgbGVnYWN5TmFtZTogJ3JhdGVMaW1pdCcsXHJcbiAgICAgICAgZGVzY3JpcHRpb246ICdNYXhpbXVtIG51bWJlciBvZiByZXF1ZXN0cyBhbGxvd2VkIHBlciBtaW51dGUnLFxyXG4gICAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICAgIHR5cGU6ICdudW1iZXInXHJcbiAgICAgICAgfVxyXG4gICAgICB9LFxyXG4gICAgICB3aW5kb3c6IHtcclxuICAgICAgICB2YWx1ZTogMSxcclxuICAgICAgICB0eXBlczogWydudW1iZXInXSxcclxuICAgICAgICBlbnZMaW5rOiAnU0VSVkVSX1JBVEVfTElNSVRJTkdfV0lORE9XJyxcclxuICAgICAgICBkZXNjcmlwdGlvbjogJ1RpbWUgd2luZG93IGluIG1pbnV0ZXMgZm9yIHJhdGUgbGltaXRpbmcnLFxyXG4gICAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICAgIHR5cGU6ICdudW1iZXInXHJcbiAgICAgICAgfVxyXG4gICAgICB9LFxyXG4gICAgICBkZWxheToge1xyXG4gICAgICAgIHZhbHVlOiAwLFxyXG4gICAgICAgIHR5cGVzOiBbJ251bWJlciddLFxyXG4gICAgICAgIGVudkxpbms6ICdTRVJWRVJfUkFURV9MSU1JVElOR19ERUxBWScsXHJcbiAgICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgICAnRGVsYXkgZHVyYXRpb24gYmV0d2VlbiBzdWNjZXNzaXZlIHJlcXVlc3RzIGJlZm9yZSByZWFjaGluZyB0aGUgbGltaXQnLFxyXG4gICAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICAgIHR5cGU6ICdudW1iZXInXHJcbiAgICAgICAgfVxyXG4gICAgICB9LFxyXG4gICAgICB0cnVzdFByb3h5OiB7XHJcbiAgICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICAgIHR5cGVzOiBbJ2Jvb2xlYW4nXSxcclxuICAgICAgICBlbnZMaW5rOiAnU0VSVkVSX1JBVEVfTElNSVRJTkdfVFJVU1RfUFJPWFknLFxyXG4gICAgICAgIGRlc2NyaXB0aW9uOiAnU2V0IHRvIHRydWUgaWYgdGhlIHNlcnZlciBpcyBiZWhpbmQgYSBsb2FkIGJhbGFuY2VyJyxcclxuICAgICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgICB0eXBlOiAndG9nZ2xlJ1xyXG4gICAgICAgIH1cclxuICAgICAgfSxcclxuICAgICAgc2tpcEtleToge1xyXG4gICAgICAgIHZhbHVlOiBudWxsLFxyXG4gICAgICAgIHR5cGVzOiBbJ3N0cmluZycsICdudWxsJ10sXHJcbiAgICAgICAgZW52TGluazogJ1NFUlZFUl9SQVRFX0xJTUlUSU5HX1NLSVBfS0VZJyxcclxuICAgICAgICBkZXNjcmlwdGlvbjogJ0tleSB0byBieXBhc3MgdGhlIHJhdGUgbGltaXRlciwgdXNlZCB3aXRoIGBza2lwVG9rZW5gJyxcclxuICAgICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgICB0eXBlOiAndGV4dCdcclxuICAgICAgICB9XHJcbiAgICAgIH0sXHJcbiAgICAgIHNraXBUb2tlbjoge1xyXG4gICAgICAgIHZhbHVlOiBudWxsLFxyXG4gICAgICAgIHR5cGVzOiBbJ3N0cmluZycsICdudWxsJ10sXHJcbiAgICAgICAgZW52TGluazogJ1NFUlZFUl9SQVRFX0xJTUlUSU5HX1NLSVBfVE9LRU4nLFxyXG4gICAgICAgIGRlc2NyaXB0aW9uOiAnVG9rZW4gdG8gYnlwYXNzIHRoZSByYXRlIGxpbWl0ZXIsIHVzZWQgd2l0aCBgc2tpcEtleWAnLFxyXG4gICAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICAgIHR5cGU6ICd0ZXh0J1xyXG4gICAgICAgIH1cclxuICAgICAgfVxyXG4gICAgfSxcclxuICAgIHNzbDoge1xyXG4gICAgICBlbmFibGU6IHtcclxuICAgICAgICB2YWx1ZTogZmFsc2UsXHJcbiAgICAgICAgdHlwZXM6IFsnYm9vbGVhbiddLFxyXG4gICAgICAgIGVudkxpbms6ICdTRVJWRVJfU1NMX0VOQUJMRScsXHJcbiAgICAgICAgY2xpTmFtZTogJ2VuYWJsZVNzbCcsXHJcbiAgICAgICAgZGVzY3JpcHRpb246ICdFbmFibGVzIG9yIGRpc2FibGVzIFNTTCBwcm90b2NvbCcsXHJcbiAgICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgICAgdHlwZTogJ3RvZ2dsZSdcclxuICAgICAgICB9XHJcbiAgICAgIH0sXHJcbiAgICAgIGZvcmNlOiB7XHJcbiAgICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICAgIHR5cGVzOiBbJ2Jvb2xlYW4nXSxcclxuICAgICAgICBlbnZMaW5rOiAnU0VSVkVSX1NTTF9GT1JDRScsXHJcbiAgICAgICAgY2xpTmFtZTogJ3NzbEZvcmNlJyxcclxuICAgICAgICBsZWdhY3lOYW1lOiAnc3NsT25seScsXHJcbiAgICAgICAgZGVzY3JpcHRpb246ICdGb3JjZXMgdGhlIHNlcnZlciB0byB1c2UgSFRUUFMgb25seSB3aGVuIHRydWUnLFxyXG4gICAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICAgIHR5cGU6ICd0b2dnbGUnXHJcbiAgICAgICAgfVxyXG4gICAgICB9LFxyXG4gICAgICBwb3J0OiB7XHJcbiAgICAgICAgdmFsdWU6IDQ0MyxcclxuICAgICAgICB0eXBlczogWydudW1iZXInXSxcclxuICAgICAgICBlbnZMaW5rOiAnU0VSVkVSX1NTTF9QT1JUJyxcclxuICAgICAgICBjbGlOYW1lOiAnc3NsUG9ydCcsXHJcbiAgICAgICAgZGVzY3JpcHRpb246ICdQb3J0IGZvciB0aGUgU1NMIHNlcnZlcicsXHJcbiAgICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgICAgdHlwZTogJ251bWJlcidcclxuICAgICAgICB9XHJcbiAgICAgIH0sXHJcbiAgICAgIGNlcnRQYXRoOiB7XHJcbiAgICAgICAgdmFsdWU6IG51bGwsXHJcbiAgICAgICAgdHlwZXM6IFsnc3RyaW5nJywgJ251bGwnXSxcclxuICAgICAgICBlbnZMaW5rOiAnU0VSVkVSX1NTTF9DRVJUX1BBVEgnLFxyXG4gICAgICAgIGNsaU5hbWU6ICdzc2xDZXJ0UGF0aCcsXHJcbiAgICAgICAgbGVnYWN5TmFtZTogJ3NzbFBhdGgnLFxyXG4gICAgICAgIGRlc2NyaXB0aW9uOiAnUGF0aCB0byB0aGUgU1NMIGNlcnRpZmljYXRlL2tleSBmaWxlJyxcclxuICAgICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgICB0eXBlOiAndGV4dCdcclxuICAgICAgICB9XHJcbiAgICAgIH1cclxuICAgIH1cclxuICB9LFxyXG4gIHBvb2w6IHtcclxuICAgIG1pbldvcmtlcnM6IHtcclxuICAgICAgdmFsdWU6IDQsXHJcbiAgICAgIHR5cGVzOiBbJ251bWJlciddLFxyXG4gICAgICBlbnZMaW5rOiAnUE9PTF9NSU5fV09SS0VSUycsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnTWluaW11bSBhbmQgaW5pdGlhbCBudW1iZXIgb2YgcG9vbCB3b3JrZXJzIHRvIHNwYXduJyxcclxuICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgIHR5cGU6ICdudW1iZXInXHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICBtYXhXb3JrZXJzOiB7XHJcbiAgICAgIHZhbHVlOiA4LFxyXG4gICAgICB0eXBlczogWydudW1iZXInXSxcclxuICAgICAgZW52TGluazogJ1BPT0xfTUFYX1dPUktFUlMnLFxyXG4gICAgICBsZWdhY3lOYW1lOiAnd29ya2VycycsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnTWF4aW11bSBudW1iZXIgb2YgcG9vbCB3b3JrZXJzIHRvIHNwYXduJyxcclxuICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgIHR5cGU6ICdudW1iZXInXHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICB3b3JrTGltaXQ6IHtcclxuICAgICAgdmFsdWU6IDQwLFxyXG4gICAgICB0eXBlczogWydudW1iZXInXSxcclxuICAgICAgZW52TGluazogJ1BPT0xfV09SS19MSU1JVCcsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnTnVtYmVyIG9mIHRhc2tzIGEgd29ya2VyIGNhbiBoYW5kbGUgYmVmb3JlIHJlc3RhcnRpbmcnLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ251bWJlcidcclxuICAgICAgfVxyXG4gICAgfSxcclxuICAgIGFjcXVpcmVUaW1lb3V0OiB7XHJcbiAgICAgIHZhbHVlOiA1MDAwLFxyXG4gICAgICB0eXBlczogWydudW1iZXInXSxcclxuICAgICAgZW52TGluazogJ1BPT0xfQUNRVUlSRV9USU1FT1VUJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdUaW1lb3V0IGluIG1pbGxpc2Vjb25kcyBmb3IgYWNxdWlyaW5nIGEgcmVzb3VyY2UnLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ251bWJlcidcclxuICAgICAgfVxyXG4gICAgfSxcclxuICAgIGNyZWF0ZVRpbWVvdXQ6IHtcclxuICAgICAgdmFsdWU6IDUwMDAsXHJcbiAgICAgIHR5cGVzOiBbJ251bWJlciddLFxyXG4gICAgICBlbnZMaW5rOiAnUE9PTF9DUkVBVEVfVElNRU9VVCcsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnVGltZW91dCBpbiBtaWxsaXNlY29uZHMgZm9yIGNyZWF0aW5nIGEgcmVzb3VyY2UnLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ251bWJlcidcclxuICAgICAgfVxyXG4gICAgfSxcclxuICAgIGRlc3Ryb3lUaW1lb3V0OiB7XHJcbiAgICAgIHZhbHVlOiA1MDAwLFxyXG4gICAgICB0eXBlczogWydudW1iZXInXSxcclxuICAgICAgZW52TGluazogJ1BPT0xfREVTVFJPWV9USU1FT1VUJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdUaW1lb3V0IGluIG1pbGxpc2Vjb25kcyBmb3IgZGVzdHJveWluZyBhIHJlc291cmNlJyxcclxuICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgIHR5cGU6ICdudW1iZXInXHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICBpZGxlVGltZW91dDoge1xyXG4gICAgICB2YWx1ZTogMzAwMDAsXHJcbiAgICAgIHR5cGVzOiBbJ251bWJlciddLFxyXG4gICAgICBlbnZMaW5rOiAnUE9PTF9JRExFX1RJTUVPVVQnLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ1RpbWVvdXQgaW4gbWlsbGlzZWNvbmRzIGZvciBkZXN0cm95aW5nIGlkbGUgcmVzb3VyY2VzJyxcclxuICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgIHR5cGU6ICdudW1iZXInXHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICBjcmVhdGVSZXRyeUludGVydmFsOiB7XHJcbiAgICAgIHZhbHVlOiAyMDAsXHJcbiAgICAgIHR5cGVzOiBbJ251bWJlciddLFxyXG4gICAgICBlbnZMaW5rOiAnUE9PTF9DUkVBVEVfUkVUUllfSU5URVJWQUwnLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnSW50ZXJ2YWwgaW4gbWlsbGlzZWNvbmRzIGJlZm9yZSByZXRyeWluZyByZXNvdXJjZSBjcmVhdGlvbiBvbiBmYWlsdXJlJyxcclxuICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgIHR5cGU6ICdudW1iZXInXHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICByZWFwZXJJbnRlcnZhbDoge1xyXG4gICAgICB2YWx1ZTogMTAwMCxcclxuICAgICAgdHlwZXM6IFsnbnVtYmVyJ10sXHJcbiAgICAgIGVudkxpbms6ICdQT09MX1JFQVBFUl9JTlRFUlZBTCcsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdJbnRlcnZhbCBpbiBtaWxsaXNlY29uZHMgdG8gY2hlY2sgYW5kIGRlc3Ryb3kgaWRsZSByZXNvdXJjZXMnLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ251bWJlcidcclxuICAgICAgfVxyXG4gICAgfSxcclxuICAgIGJlbmNobWFya2luZzoge1xyXG4gICAgICB2YWx1ZTogZmFsc2UsXHJcbiAgICAgIHR5cGVzOiBbJ2Jvb2xlYW4nXSxcclxuICAgICAgZW52TGluazogJ1BPT0xfQkVOQ0hNQVJLSU5HJyxcclxuICAgICAgY2xpTmFtZTogJ3Bvb2xCZW5jaG1hcmtpbmcnLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ1Nob3dzIHN0YXRpc3RpY3MgZm9yIHRoZSBwb29sIG9mIHJlc291cmNlcycsXHJcbiAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICB0eXBlOiAndG9nZ2xlJ1xyXG4gICAgICB9XHJcbiAgICB9XHJcbiAgfSxcclxuICBsb2dnaW5nOiB7XHJcbiAgICBsZXZlbDoge1xyXG4gICAgICB2YWx1ZTogNCxcclxuICAgICAgdHlwZXM6IFsnbnVtYmVyJ10sXHJcbiAgICAgIGVudkxpbms6ICdMT0dHSU5HX0xFVkVMJyxcclxuICAgICAgY2xpTmFtZTogJ2xvZ0xldmVsJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdMb2dnaW5nIHZlcmJvc2l0eSBsZXZlbCcsXHJcbiAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgICByb3VuZDogMCxcclxuICAgICAgICBtaW46IDAsXHJcbiAgICAgICAgbWF4OiA1XHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICBmaWxlOiB7XHJcbiAgICAgIHZhbHVlOiAnaGlnaGNoYXJ0cy1leHBvcnQtc2VydmVyLmxvZycsXHJcbiAgICAgIHR5cGVzOiBbJ3N0cmluZyddLFxyXG4gICAgICBlbnZMaW5rOiAnTE9HR0lOR19GSUxFJyxcclxuICAgICAgY2xpTmFtZTogJ2xvZ0ZpbGUnLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnTG9nIGZpbGUgbmFtZS4gUmVxdWlyZXMgYGxvZ1RvRmlsZWAgYW5kIGBsb2dEZXN0YCB0byBiZSBzZXQnLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ3RleHQnXHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICBkZXN0OiB7XHJcbiAgICAgIHZhbHVlOiAnbG9nJyxcclxuICAgICAgdHlwZXM6IFsnc3RyaW5nJ10sXHJcbiAgICAgIGVudkxpbms6ICdMT0dHSU5HX0RFU1QnLFxyXG4gICAgICBjbGlOYW1lOiAnbG9nRGVzdCcsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnUGF0aCB0byBzdG9yZSBsb2cgZmlsZXMuIFJlcXVpcmVzIGBsb2dUb0ZpbGVgIHRvIGJlIHNldCcsXHJcbiAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICB0eXBlOiAndGV4dCdcclxuICAgICAgfVxyXG4gICAgfSxcclxuICAgIHRvQ29uc29sZToge1xyXG4gICAgICB2YWx1ZTogdHJ1ZSxcclxuICAgICAgdHlwZXM6IFsnYm9vbGVhbiddLFxyXG4gICAgICBlbnZMaW5rOiAnTE9HR0lOR19UT19DT05TT0xFJyxcclxuICAgICAgY2xpTmFtZTogJ2xvZ1RvQ29uc29sZScsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnRW5hYmxlcyBvciBkaXNhYmxlcyBjb25zb2xlIGxvZ2dpbmcnLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ3RvZ2dsZSdcclxuICAgICAgfVxyXG4gICAgfSxcclxuICAgIHRvRmlsZToge1xyXG4gICAgICB2YWx1ZTogdHJ1ZSxcclxuICAgICAgdHlwZXM6IFsnYm9vbGVhbiddLFxyXG4gICAgICBlbnZMaW5rOiAnTE9HR0lOR19UT19GSUxFJyxcclxuICAgICAgY2xpTmFtZTogJ2xvZ1RvRmlsZScsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnRW5hYmxlcyBvciBkaXNhYmxlcyBsb2dnaW5nIHRvIGEgZmlsZScsXHJcbiAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICB0eXBlOiAndG9nZ2xlJ1xyXG4gICAgICB9XHJcbiAgICB9XHJcbiAgfSxcclxuICB1aToge1xyXG4gICAgZW5hYmxlOiB7XHJcbiAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgdHlwZXM6IFsnYm9vbGVhbiddLFxyXG4gICAgICBlbnZMaW5rOiAnVUlfRU5BQkxFJyxcclxuICAgICAgY2xpTmFtZTogJ2VuYWJsZVVpJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdFbmFibGVzIG9yIGRpc2FibGVzIHRoZSBVSSBmb3IgdGhlIGV4cG9ydCBzZXJ2ZXInLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ3RvZ2dsZSdcclxuICAgICAgfVxyXG4gICAgfSxcclxuICAgIHJvdXRlOiB7XHJcbiAgICAgIHZhbHVlOiAnLycsXHJcbiAgICAgIHR5cGVzOiBbJ3N0cmluZyddLFxyXG4gICAgICBlbnZMaW5rOiAnVUlfUk9VVEUnLFxyXG4gICAgICBjbGlOYW1lOiAndWlSb3V0ZScsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnVGhlIGVuZHBvaW50IHJvdXRlIGZvciB0aGUgVUknLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ3RleHQnXHJcbiAgICAgIH1cclxuICAgIH1cclxuICB9LFxyXG4gIG90aGVyOiB7XHJcbiAgICBub2RlRW52OiB7XHJcbiAgICAgIHZhbHVlOiAncHJvZHVjdGlvbicsXHJcbiAgICAgIHR5cGVzOiBbJ3N0cmluZyddLFxyXG4gICAgICBlbnZMaW5rOiAnT1RIRVJfTk9ERV9FTlYnLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ1RoZSBOb2RlLmpzIGVudmlyb25tZW50IHR5cGUnLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ3RleHQnXHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICBsaXN0ZW5Ub1Byb2Nlc3NFeGl0czoge1xyXG4gICAgICB2YWx1ZTogdHJ1ZSxcclxuICAgICAgdHlwZXM6IFsnYm9vbGVhbiddLFxyXG4gICAgICBlbnZMaW5rOiAnT1RIRVJfTElTVEVOX1RPX1BST0NFU1NfRVhJVFMnLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ1doZXRoZXIgb3Igbm90IHRvIGF0dGFjaCBwcm9jZXNzLmV4aXQgaGFuZGxlcnMnLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ3RvZ2dsZSdcclxuICAgICAgfVxyXG4gICAgfSxcclxuICAgIG5vTG9nbzoge1xyXG4gICAgICB2YWx1ZTogZmFsc2UsXHJcbiAgICAgIHR5cGVzOiBbJ2Jvb2xlYW4nXSxcclxuICAgICAgZW52TGluazogJ09USEVSX05PX0xPR08nLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ0Rpc3BsYXkgb3Igc2tpcCBwcmludGluZyB0aGUgbG9nbyBvbiBzdGFydHVwJyxcclxuICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgIHR5cGU6ICd0b2dnbGUnXHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICBoYXJkUmVzZXRQYWdlOiB7XHJcbiAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgdHlwZXM6IFsnYm9vbGVhbiddLFxyXG4gICAgICBlbnZMaW5rOiAnT1RIRVJfSEFSRF9SRVNFVF9QQUdFJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdXaGV0aGVyIG9yIG5vdCB0byByZXNldCB0aGUgcGFnZSBjb250ZW50IGVudGlyZWx5JyxcclxuICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgIHR5cGU6ICd0b2dnbGUnXHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICBicm93c2VyU2hlbGxNb2RlOiB7XHJcbiAgICAgIHZhbHVlOiB0cnVlLFxyXG4gICAgICB0eXBlczogWydib29sZWFuJ10sXHJcbiAgICAgIGVudkxpbms6ICdPVEhFUl9CUk9XU0VSX1NIRUxMX01PREUnLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ1doZXRoZXIgb3Igbm90IHRvIHNldCB0aGUgYnJvd3NlciB0byBydW4gaW4gc2hlbGwgbW9kZScsXHJcbiAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICB0eXBlOiAndG9nZ2xlJ1xyXG4gICAgICB9XHJcbiAgICB9LFxyXG4gICAgdmFsaWRhdGlvbjoge1xyXG4gICAgICB2YWx1ZTogdHJ1ZSxcclxuICAgICAgdHlwZXM6IFsnYm9vbGVhbiddLFxyXG4gICAgICBlbnZMaW5rOiAnT1RIRVJfVkFMSURBVElPTicsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnV2hldGhlciBvciBub3QgdG8gZW5hYmxlIHZhbGlkYXRpb24gb2Ygb3B0aW9ucyB0eXBlcycsXHJcbiAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICB0eXBlOiAndG9nZ2xlJ1xyXG4gICAgICB9XHJcbiAgICB9XHJcbiAgfSxcclxuICBkZWJ1Zzoge1xyXG4gICAgZW5hYmxlOiB7XHJcbiAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgdHlwZXM6IFsnYm9vbGVhbiddLFxyXG4gICAgICBlbnZMaW5rOiAnREVCVUdfRU5BQkxFJyxcclxuICAgICAgY2xpTmFtZTogJ2VuYWJsZURlYnVnJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdFbmFibGVzIG9yIGRpc2FibGVzIGRlYnVnIG1vZGUgZm9yIHRoZSB1bmRlcmx5aW5nIGJyb3dzZXInLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ3RvZ2dsZSdcclxuICAgICAgfVxyXG4gICAgfSxcclxuICAgIGhlYWRsZXNzOiB7XHJcbiAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgdHlwZXM6IFsnYm9vbGVhbiddLFxyXG4gICAgICBlbnZMaW5rOiAnREVCVUdfSEVBRExFU1MnLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnV2hldGhlciBvciBub3QgdG8gc2V0IHRoZSBicm93c2VyIHRvIHJ1biBpbiBoZWFkbGVzcyBtb2RlIGR1cmluZyBkZWJ1Z2dpbmcnLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ3RvZ2dsZSdcclxuICAgICAgfVxyXG4gICAgfSxcclxuICAgIGRldnRvb2xzOiB7XHJcbiAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgdHlwZXM6IFsnYm9vbGVhbiddLFxyXG4gICAgICBlbnZMaW5rOiAnREVCVUdfREVWVE9PTFMnLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ0VuYWJsZXMgb3IgZGlzYWJsZXMgRGV2VG9vbHMgaW4gaGVhZGZ1bCBtb2RlJyxcclxuICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgIHR5cGU6ICd0b2dnbGUnXHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICBsaXN0ZW5Ub0NvbnNvbGU6IHtcclxuICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICB0eXBlczogWydib29sZWFuJ10sXHJcbiAgICAgIGVudkxpbms6ICdERUJVR19MSVNURU5fVE9fQ09OU09MRScsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdFbmFibGVzIG9yIGRpc2FibGVzIGxpc3RlbmluZyB0byBjb25zb2xlIG1lc3NhZ2VzIGZyb20gdGhlIGJyb3dzZXInLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ3RvZ2dsZSdcclxuICAgICAgfVxyXG4gICAgfSxcclxuICAgIGR1bXBpbzoge1xyXG4gICAgICB2YWx1ZTogZmFsc2UsXHJcbiAgICAgIHR5cGVzOiBbJ2Jvb2xlYW4nXSxcclxuICAgICAgZW52TGluazogJ0RFQlVHX0RVTVBJTycsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdSZWRpcmVjdHMgb3Igbm90IGJyb3dzZXIgc3Rkb3V0IGFuZCBzdGRlcnIgdG8gcHJvY2Vzcy5zdGRvdXQgYW5kIHByb2Nlc3Muc3RkZXJyJyxcclxuICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgIHR5cGU6ICd0b2dnbGUnXHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICBzbG93TW86IHtcclxuICAgICAgdmFsdWU6IDAsXHJcbiAgICAgIHR5cGVzOiBbJ251bWJlciddLFxyXG4gICAgICBlbnZMaW5rOiAnREVCVUdfU0xPV19NTycsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnRGVsYXlzIFB1cHBldGVlciBvcGVyYXRpb25zIGJ5IHRoZSBzcGVjaWZpZWQgbWlsbGlzZWNvbmRzJyxcclxuICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgIHR5cGU6ICdudW1iZXInXHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICBkZWJ1Z2dpbmdQb3J0OiB7XHJcbiAgICAgIHZhbHVlOiA5MjIyLFxyXG4gICAgICB0eXBlczogWydudW1iZXInXSxcclxuICAgICAgZW52TGluazogJ0RFQlVHX0RFQlVHR0lOR19QT1JUJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdQb3J0IHVzZWQgZm9yIGRlYnVnZ2luZycsXHJcbiAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICB0eXBlOiAnbnVtYmVyJ1xyXG4gICAgICB9XHJcbiAgICB9XHJcbiAgfVxyXG59O1xyXG5cclxuZXhwb3J0IGRlZmF1bHQgZGVmYXVsdENvbmZpZztcclxuIiwiLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcclxuXHJcbkhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlclxyXG5cclxuQ29weXJpZ2h0IChjKSAyMDE2LTIwMjUsIEhpZ2hzb2Z0XHJcblxyXG5MaWNlbmNlZCB1bmRlciB0aGUgTUlUIGxpY2VuY2UuXHJcblxyXG5BZGRpdGlvbmFsbHkgYSB2YWxpZCBIaWdoY2hhcnRzIGxpY2Vuc2UgaXMgcmVxdWlyZWQgZm9yIHVzZS5cclxuXHJcblNlZSBMSUNFTlNFIGZpbGUgaW4gcm9vdCBmb3IgZGV0YWlscy5cclxuXHJcbioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXHJcblxyXG4vKipcclxuICogQG92ZXJ2aWV3IFRoaXMgZmlsZSBoYW5kbGVzIHBhcnNpbmcgYW5kIHZhbGlkYXRpbmcgb3B0aW9ucyBmcm9tIG11bHRpcGxlXHJcbiAqIHNvdXJjZXMgKHRoZSBjb25maWcgZmlsZSwgY3VzdG9tIEpTT04sIGVudmlyb25tZW50IHZhcmlhYmxlcywgQ0xJIGFyZ3VtZW50cyxcclxuICogYW5kIHJlcXVlc3QgcGF5bG9hZCkgdXNpbmcgdGhlICd6b2QnIGxpYnJhcnkuXHJcbiAqXHJcbiAqIEVudmlyb25tZW50IHZhcmlhYmxlcyBhcmUgcGFyc2VkIGFuZCB2YWxpZGF0ZWQgb25seSBvbmNlIGF0IGFwcGxpY2F0aW9uXHJcbiAqIHN0YXJ0dXAsIGFuZCB0aGUgdmFsaWRhdGVkIHJlc3VsdHMgYXJlIGV4cG9ydGVkIGFzIGBlbnZzYCBmb3IgdXNlIHRocm91Z2hvdXRcclxuICogdGhlIGFwcGxpY2F0aW9uLlxyXG4gKlxyXG4gKiBPcHRpb25zIGZyb20gb3RoZXIgc291cmNlcywgaG93ZXZlciwgYXJlIHBhcnNlZCBhbmQgdmFsaWRhdGVkIG9uIGRlbWFuZCxcclxuICogZWFjaCB0aW1lIGFuIGV4cG9ydCBpcyBhdHRlbXB0ZWQuXHJcbiAqL1xyXG5cclxuaW1wb3J0IGRvdGVudiBmcm9tICdkb3RlbnYnO1xyXG5pbXBvcnQgeyB6IH0gZnJvbSAnem9kJztcclxuXHJcbmltcG9ydCBkZWZhdWx0Q29uZmlnIGZyb20gJy4vc2NoZW1hcy9jb25maWcuanMnO1xyXG5cclxuLy8gTG9hZCB0aGUgLmVudiBpbnRvIGVudmlyb25tZW50IHZhcmlhYmxlc1xyXG5kb3RlbnYuY29uZmlnKCk7XHJcblxyXG4vLyBHZXQgc2NyaXB0cyBuYW1lcyBvZiBlYWNoIGNhdGVnb3J5IGZyb20gdGhlIGRlZmF1bHQgY29uZmlnXHJcbmNvbnN0IHsgY29yZVNjcmlwdHMsIG1vZHVsZVNjcmlwdHMsIGluZGljYXRvclNjcmlwdHMgfSA9XHJcbiAgZGVmYXVsdENvbmZpZy5oaWdoY2hhcnRzO1xyXG5cclxuLy8gU2V0cyB0aGUgY3VzdG9tIGVycm9yIG1hcCBnbG9iYWxseVxyXG56LnNldEVycm9yTWFwKF9jdXN0b21FcnJvck1hcCk7XHJcblxyXG4vKipcclxuICogT2JqZWN0IGNvbnRhaW5pbmcgY3VzdG9tIGdlbmVyYWwgdmFsaWRhdG9ycyBhbmQgcGFyc2VycyB0byBhdm9pZCByZXBldGl0aW9uXHJcbiAqIGluIHNjaGVtYSBvYmplY3RzLiBBbGwgdmFsaWRhdG9ycyBhcHBseSB0byB2YWx1ZXMgZnJvbSB2YXJpb3VzIHNvdXJjZXMsXHJcbiAqIGluY2x1ZGluZyB0aGUgZGVmYXVsdCBjb25maWcgZmlsZSwgYSBjdXN0b20gSlNPTiBmaWxlIGxvYWRlZCB3aXRoIHRoZSBvcHRpb25cclxuICogY2FsbGVkIGBsb2FkQ29uZmlnYCwgdGhlIC5lbnYgZmlsZSwgQ0xJIGFyZ3VtZW50cywgYW5kIHRoZSByZXF1ZXN0IHBheWxvYWQuXHJcbiAqIFRoZSBgc3RyaWN0Q2hlY2tgIGZsYWcgZW5hYmxlcyBzdHJpY3RlciB2YWxpZGF0aW9uIGFuZCBwYXJzaW5nIHJ1bGVzLiBUaGlzXHJcbiAqIGZsYWcgaXMgc2V0IHRvIGZhbHNlIGZvciB2YWx1ZXMgdGhhdCBjb21lIGZyb20gdGhlIC5lbnYgZmlsZSBvciBDTEkgYXJndW1lbnRzXHJcbiAqIGJlY2F1c2UgdGhleSBhcmUgcHJvdmlkZWQgYXMgc3RyaW5ncyBhbmQgbmVlZCB0byBiZSBwYXJzZWQgYWNjb3JkaW5nbHkgZmlyc3QuXHJcbiAqL1xyXG5jb25zdCB2ID0ge1xyXG4gIC8qKlxyXG4gICAqIFRoZSBgYm9vbGVhbmAgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbCBzdHJpY3RlclxyXG4gICAqIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoYXQ6XHJcbiAgICpcclxuICAgKiAtIFdoZW4gYHN0cmljdENoZWNrYCBpcyB0cnVlLCB0aGUgc2NoZW1hIHdpbGwgYWNjZXB0IHZhbHVlcyBhcmUgdHJ1ZVxyXG4gICAqIGFuZCBmYWxzZSBhbmQgdGhlIHNjaGVtYSB3aWxsIHZhbGlkYXRlIGFnYWluc3QgdGhlIGRlZmF1bHQgYm9vbGVhblxyXG4gICAqIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIC0gV2hlbiBgc3RyaWN0Q2hlY2tgIGlzIGZhbHNlLCB0aGUgc2NoZW1hIHdpbGwgYWNjZXB0IHZhbHVlcyBhcmUgdHJ1ZSxcclxuICAgKiBmYWxzZSwgbnVsbCwgJ3RydWUnLCAnMScsICdmYWxzZScsICcwJywgJ3VuZGVmaW5lZCcsICdudWxsJywgYW5kICcnLlxyXG4gICAqIFRoZSBzdHJpbmdzICd1bmRlZmluZWQnLCAnbnVsbCcsIGFuZCAnJyB3aWxsIGJlIHRyYW5zZm9ybWVkIHRvIG51bGwsXHJcbiAgICogdGhlIHN0cmluZyAndHJ1ZScgd2lsbCBiZSB0cmFuc2Zvcm1lZCB0byB0aGUgYm9vbGVhbiB2YWx1ZSB0cnVlLFxyXG4gICAqIGFuZCAnZmFsc2UnIHdpbGwgYmUgdHJhbnNmb3JtZWQgdG8gdGhlIGJvb2xlYW4gdmFsdWUgZmFsc2UuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gYm9vbGVhblxyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nIGJvb2xlYW4gdmFsdWVzLlxyXG4gICAqL1xyXG4gIGJvb2xlYW4oc3RyaWN0Q2hlY2spIHtcclxuICAgIHJldHVybiBzdHJpY3RDaGVja1xyXG4gICAgICA/IHouYm9vbGVhbigpXHJcbiAgICAgIDogelxyXG4gICAgICAgICAgLnVuaW9uKFtcclxuICAgICAgICAgICAgelxyXG4gICAgICAgICAgICAgIC5lbnVtKFsndHJ1ZScsICcxJywgJ2ZhbHNlJywgJzAnLCAndW5kZWZpbmVkJywgJ251bGwnLCAnJ10pXHJcbiAgICAgICAgICAgICAgLnRyYW5zZm9ybSgodmFsdWUpID0+XHJcbiAgICAgICAgICAgICAgICAhWyd1bmRlZmluZWQnLCAnbnVsbCcsICcnXS5pbmNsdWRlcyh2YWx1ZSlcclxuICAgICAgICAgICAgICAgICAgPyB2YWx1ZSA9PT0gJ3RydWUnIHx8IHZhbHVlID09PSAnMSdcclxuICAgICAgICAgICAgICAgICAgOiBudWxsXHJcbiAgICAgICAgICAgICAgKSxcclxuICAgICAgICAgICAgei5ib29sZWFuKClcclxuICAgICAgICAgIF0pXHJcbiAgICAgICAgICAubnVsbGFibGUoKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYHN0cmluZ2AgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbCBzdHJpY3RlclxyXG4gICAqIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoYXQ6XHJcbiAgICpcclxuICAgKiAtIFdoZW4gYHN0cmljdENoZWNrYCBpcyB0cnVlLCB0aGUgc2NoZW1hIHdpbGwgYWNjZXB0IHRyaW1tZWQgc3RyaW5ncyBleGNlcHRcclxuICAgKiB0aGUgZm9yYmlkZGVuIHZhbHVlczogJ2ZhbHNlJywgJ3VuZGVmaW5lZCcsICdudWxsJywgYW5kICcnLlxyXG4gICAqXHJcbiAgICogLSBXaGVuIGBzdHJpY3RDaGVja2AgaXMgZmFsc2UsIHRoZSBzY2hlbWEgd2lsbCBhY2NlcHQgdHJpbW1lZCBzdHJpbmdzXHJcbiAgICogYW5kIG51bGwuIFRoZSBmb3JiaWRkZW4gdmFsdWVzOiAnZmFsc2UnLCAndW5kZWZpbmVkJywgJ251bGwnLCBhbmQgJycgd2lsbFxyXG4gICAqIGJlIHRyYW5zZm9ybWVkIHRvIG51bGwuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gc3RyaW5nXHJcbiAgICpcclxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IHN0cmljdENoZWNrIC0gRGV0ZXJtaW5lcyBpZiBzdHJpY3RlciB2YWxpZGF0aW9uIHNob3VsZFxyXG4gICAqIGJlIGFwcGxpZWQuXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9IEEgWm9kIHNjaGVtYSBvYmplY3QgZm9yIHZhbGlkYXRpbmcgc3RyaW5nIHZhbHVlcy5cclxuICAgKi9cclxuICBzdHJpbmcoc3RyaWN0Q2hlY2spIHtcclxuICAgIHJldHVybiBzdHJpY3RDaGVja1xyXG4gICAgICA/IHpcclxuICAgICAgICAgIC5zdHJpbmcoKVxyXG4gICAgICAgICAgLnRyaW0oKVxyXG4gICAgICAgICAgLnJlZmluZShcclxuICAgICAgICAgICAgKHZhbHVlKSA9PiAhWydmYWxzZScsICd1bmRlZmluZWQnLCAnbnVsbCcsICcnXS5pbmNsdWRlcyh2YWx1ZSksXHJcbiAgICAgICAgICAgIHtcclxuICAgICAgICAgICAgICBwYXJhbXM6IHtcclxuICAgICAgICAgICAgICAgIGVycm9yTWVzc2FnZTogJ1RoZSBzdHJpbmcgY29udGFpbnMgYSBmb3JiaWRkZW4gdmFsdWUnXHJcbiAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICB9XHJcbiAgICAgICAgICApXHJcbiAgICAgIDogelxyXG4gICAgICAgICAgLnN0cmluZygpXHJcbiAgICAgICAgICAudHJpbSgpXHJcbiAgICAgICAgICAudHJhbnNmb3JtKCh2YWx1ZSkgPT5cclxuICAgICAgICAgICAgIVsnZmFsc2UnLCAndW5kZWZpbmVkJywgJ251bGwnLCAnJ10uaW5jbHVkZXModmFsdWUpID8gdmFsdWUgOiBudWxsXHJcbiAgICAgICAgICApXHJcbiAgICAgICAgICAubnVsbGFibGUoKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYGVudW1gIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGggYW4gb3B0aW9uYWwgc3RyaWN0ZXJcclxuICAgKiBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgc2NoZW1hIHdpbGwgdmFsaWRhdGUgYWdhaW5zdCB0aGUgcHJvdmlkZWQgYHZhbHVlc2AgYXJyYXkuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGF0OlxyXG4gICAqXHJcbiAgICogLSBXaGVuIGBzdHJpY3RDaGVja2AgaXMgdHJ1ZSwgdGhlIHNjaGVtYSB3aWxsIHZhbGlkYXRlIGFnYWluc3QgdGhlIGB2YWx1ZXNgXHJcbiAgICogYXJyYXkgd2l0aCB0aGUgZGVmYXVsdCBlbnVtIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIC0gV2hlbiBgc3RyaWN0Q2hlY2tgIGlzIGZhbHNlLCB0aGUgc2NoZW1hIHdpbGwgYWNjZXB0IGFsc28gbnVsbCxcclxuICAgKiAndW5kZWZpbmVkJywgJ251bGwnLCBhbmQgJycsIHdoaWNoIHdpbGwgYmUgdHJhbnNmb3JtZWQgdG8gbnVsbC5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiBlbnVtXHJcbiAgICpcclxuICAgKiBAcGFyYW0ge0FycmF5LjxzdHJpbmc+fSB2YWx1ZXMgLSBBbiBhcnJheSBvZiB2YWxpZCBzdHJpbmcgdmFsdWVzXHJcbiAgICogZm9yIHRoZSBlbnVtLlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZyBlbnVtIHZhbHVlcy5cclxuICAgKi9cclxuICBlbnVtKHZhbHVlcywgc3RyaWN0Q2hlY2spIHtcclxuICAgIHJldHVybiBzdHJpY3RDaGVja1xyXG4gICAgICA/IHouZW51bShbLi4udmFsdWVzXSlcclxuICAgICAgOiB6XHJcbiAgICAgICAgICAuZW51bShbLi4udmFsdWVzLCAndW5kZWZpbmVkJywgJ251bGwnLCAnJ10pXHJcbiAgICAgICAgICAudHJhbnNmb3JtKCh2YWx1ZSkgPT5cclxuICAgICAgICAgICAgIVsndW5kZWZpbmVkJywgJ251bGwnLCAnJ10uaW5jbHVkZXModmFsdWUpID8gdmFsdWUgOiBudWxsXHJcbiAgICAgICAgICApXHJcbiAgICAgICAgICAubnVsbGFibGUoKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYHN0cmluZ0FycmF5YCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoIGFuIG9wdGlvbmFsXHJcbiAgICogc3RyaWN0ZXIgY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhhdDpcclxuICAgKlxyXG4gICAqIC0gV2hlbiBgc3RyaWN0Q2hlY2tgIGlzIHRydWUsIHRoZSBzY2hlbWEgd2lsbCBhY2NlcHQgYW4gYXJyYXkgb2YgdHJpbW1lZFxyXG4gICAqIHN0cmluZyB2YWx1ZXMgZmlsdGVyZWQgYnkgdGhlIGxvZ2ljIHByb3ZpZGVkIHRocm91Z2ggdGhlIGBmaWx0ZXJDYWxsYmFja2AuXHJcbiAgICpcclxuICAgKiAtIFdoZW4gYHN0cmljdENoZWNrYCBpcyBmYWxzZSwgdGhlIHNjaGVtYSB3aWxsIGFjY2VwdCBudWxsIGFuZCB0cmltbWVkXHJcbiAgICogc3RyaW5nIHZhbHVlcyB3aGljaCB3aWxsIGJlIHNwbGl0dGVkIGludG8gYW4gYXJyYXkgb2Ygc3RyaW5ncyBhbmQgZmlsdGVyZWRcclxuICAgKiBmcm9tIHRoZSAnWycgYW5kICddJyBjaGFyYWN0ZXJzIGFuZCBieSB0aGUgbG9naWMgcHJvdmlkZWQgdGhyb3VnaFxyXG4gICAqIHRoZSBgZmlsdGVyQ2FsbGJhY2tgLiBJZiB0aGUgYXJyYXkgaXMgZW1wdHksIGl0IHdpbGwgYmUgdHJhbnNmb3JtZWRcclxuICAgKiB0byBudWxsLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIHN0cmluZ0FycmF5XHJcbiAgICpcclxuICAgKiBAcGFyYW0ge2Z1bmN0aW9ufSBmaWx0ZXJDYWxsYmFjayAtIFRoZSBmaWx0ZXIgY2FsbGJhY2suXHJcbiAgICogQHBhcmFtIHtzdHJpbmd9IHNlcGFyYXRvciAtIFRoZSBzZXBhcmF0b3IgZm9yIHNwbGl0aW5nIGEgc3RyaW5nLlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZyBhcnJheSBvZiBzdHJpbmdcclxuICAgKiB2YWx1ZXMuXHJcbiAgICovXHJcbiAgc3RyaW5nQXJyYXkoZmlsdGVyQ2FsbGJhY2ssIHNlcGFyYXRvciwgc3RyaWN0Q2hlY2spIHtcclxuICAgIGNvbnN0IGFycmF5U2NoZW1hID0gei5zdHJpbmcoKS50cmltKCkuYXJyYXkoKTtcclxuICAgIGNvbnN0IHN0cmluZ1NjaGVtYSA9IHpcclxuICAgICAgLnN0cmluZygpXHJcbiAgICAgIC50cmltKClcclxuICAgICAgLnRyYW5zZm9ybSgodmFsdWUpID0+IHtcclxuICAgICAgICBpZiAodmFsdWUuc3RhcnRzV2l0aCgnWycpKSB7XHJcbiAgICAgICAgICB2YWx1ZSA9IHZhbHVlLnNsaWNlKDEpO1xyXG4gICAgICAgIH1cclxuICAgICAgICBpZiAodmFsdWUuZW5kc1dpdGgoJ10nKSkge1xyXG4gICAgICAgICAgdmFsdWUgPSB2YWx1ZS5zbGljZSgwLCAtMSk7XHJcbiAgICAgICAgfVxyXG4gICAgICAgIHJldHVybiB2YWx1ZS5zcGxpdChzZXBhcmF0b3IpO1xyXG4gICAgICB9KTtcclxuXHJcbiAgICBjb25zdCB0cmFuc2Zvcm1DYWxsYmFjayA9ICh2YWx1ZSkgPT5cclxuICAgICAgdmFsdWUubWFwKCh2YWx1ZSkgPT4gdmFsdWUudHJpbSgpKS5maWx0ZXIoZmlsdGVyQ2FsbGJhY2spO1xyXG5cclxuICAgIHJldHVybiBzdHJpY3RDaGVja1xyXG4gICAgICA/IGFycmF5U2NoZW1hLnRyYW5zZm9ybSh0cmFuc2Zvcm1DYWxsYmFjaylcclxuICAgICAgOiB6XHJcbiAgICAgICAgICAudW5pb24oW3N0cmluZ1NjaGVtYSwgYXJyYXlTY2hlbWFdKVxyXG4gICAgICAgICAgLnRyYW5zZm9ybSh0cmFuc2Zvcm1DYWxsYmFjaylcclxuICAgICAgICAgIC50cmFuc2Zvcm0oKHZhbHVlKSA9PiAodmFsdWUubGVuZ3RoID8gdmFsdWUgOiBudWxsKSlcclxuICAgICAgICAgIC5udWxsYWJsZSgpO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgcG9zaXRpdmVOdW1gIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGggYW4gb3B0aW9uYWxcclxuICAgKiBzdHJpY3RlciBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGF0OlxyXG4gICAqXHJcbiAgICogLSBXaGVuIGBzdHJpY3RDaGVja2AgaXMgdHJ1ZSwgdGhlIHNjaGVtYSB3aWxsIGFjY2VwdCBwb3NpdGl2ZSBudW1iZXIgdmFsdWVzXHJcbiAgICogYW5kIHZhbGlkYXRlIGFnYWluc3QgdGhlIGRlZmF1bHQgcG9zaXRpdmUgbnVtYmVyIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIC0gV2hlbiBgc3RyaWN0Q2hlY2tgIGlzIGZhbHNlLCB0aGUgc2NoZW1hIHdpbGwgYWNjZXB0IHBvc2l0aXZlIG51bWJlclxyXG4gICAqIHZhbHVlcywgbnVsbCwgYW5kIHRyaW1tZWQgc3RyaW5nIHZhbHVlcyB0aGF0IGNhbiBlaXRoZXIgYmUgJ3VuZGVmaW5lZCcsXHJcbiAgICogJ251bGwnLCAnJywgb3IgcmVwcmVzZW50IGEgcG9zaXRpdmUgbnVtYmVyLiBJdCB3aWxsIHRyYW5zZm9ybSB0aGUgc3RyaW5nXHJcbiAgICogdG8gYSBwb3NpdGl2ZSBudW1iZXIsIG9yIHRvIG51bGwgaWYgaXQgaXMgJ3VuZGVmaW5lZCcsICdudWxsJywgb3IgJycuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gcG9zaXRpdmVOdW1cclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZyBwb3NpdGl2ZSBudW1iZXJcclxuICAgKiB2YWx1ZXMuXHJcbiAgICovXHJcbiAgcG9zaXRpdmVOdW0oc3RyaWN0Q2hlY2spIHtcclxuICAgIHJldHVybiBzdHJpY3RDaGVja1xyXG4gICAgICA/IHoubnVtYmVyKCkucG9zaXRpdmUoKVxyXG4gICAgICA6IHpcclxuICAgICAgICAgIC51bmlvbihbXHJcbiAgICAgICAgICAgIHpcclxuICAgICAgICAgICAgICAuc3RyaW5nKClcclxuICAgICAgICAgICAgICAudHJpbSgpXHJcbiAgICAgICAgICAgICAgLnJlZmluZShcclxuICAgICAgICAgICAgICAgICh2YWx1ZSkgPT5cclxuICAgICAgICAgICAgICAgICAgKCFpc05hTihOdW1iZXIodmFsdWUpKSAmJiBOdW1iZXIodmFsdWUpID4gMCkgfHxcclxuICAgICAgICAgICAgICAgICAgWyd1bmRlZmluZWQnLCAnbnVsbCcsICcnXS5pbmNsdWRlcyh2YWx1ZSksXHJcbiAgICAgICAgICAgICAgICB7XHJcbiAgICAgICAgICAgICAgICAgIHBhcmFtczoge1xyXG4gICAgICAgICAgICAgICAgICAgIGVycm9yTWVzc2FnZTogJ1RoZSB2YWx1ZSBtdXN0IGJlIG51bWVyaWMgYW5kIHBvc2l0aXZlJ1xyXG4gICAgICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgICAgKVxyXG4gICAgICAgICAgICAgIC50cmFuc2Zvcm0oKHZhbHVlKSA9PlxyXG4gICAgICAgICAgICAgICAgIVsndW5kZWZpbmVkJywgJ251bGwnLCAnJ10uaW5jbHVkZXModmFsdWUpXHJcbiAgICAgICAgICAgICAgICAgID8gTnVtYmVyKHZhbHVlKVxyXG4gICAgICAgICAgICAgICAgICA6IG51bGxcclxuICAgICAgICAgICAgICApLFxyXG4gICAgICAgICAgICB6Lm51bWJlcigpLnBvc2l0aXZlKClcclxuICAgICAgICAgIF0pXHJcbiAgICAgICAgICAubnVsbGFibGUoKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYG5vbk5lZ2F0aXZlTnVtYCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoIGFuIG9wdGlvbmFsXHJcbiAgICogc3RyaWN0ZXIgY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhhdDpcclxuICAgKlxyXG4gICAqIC0gV2hlbiBgc3RyaWN0Q2hlY2tgIGlzIHRydWUsIHRoZSBzY2hlbWEgd2lsbCBhY2NlcHQgbm9uLW5lZ2F0aXZlIG51bWJlclxyXG4gICAqIHZhbHVlcyBhbmQgdmFsaWRhdGUgYWdhaW5zdCB0aGUgZGVmYXVsdCBub24tbmVnYXRpdmUgbnVtYmVyIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIC0gV2hlbiBgc3RyaWN0Q2hlY2tgIGlzIGZhbHNlLCB0aGUgc2NoZW1hIHdpbGwgYWNjZXB0IG5vbi1uZWdhdGl2ZSBudW1iZXJcclxuICAgKiB2YWx1ZXMsIG51bGwsIGFuZCB0cmltbWVkIHN0cmluZyB2YWx1ZXMgdGhhdCBjYW4gZWl0aGVyIGJlICd1bmRlZmluZWQnLFxyXG4gICAqICdudWxsJywgJycsIG9yIHJlcHJlc2VudCBhIG5vbi1uZWdhdGl2ZSBudW1iZXIuIEl0IHdpbGwgdHJhbnNmb3JtXHJcbiAgICogdGhlIHN0cmluZyB0byBhIG5vbi1uZWdhdGl2ZSBudW1iZXIsIG9yIHRvIG51bGwgaWYgaXQgaXMgJ3VuZGVmaW5lZCcsXHJcbiAgICogJ251bGwnLCBvciAnJy5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiBub25OZWdhdGl2ZU51bVxyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nIG5vbi1uZWdhdGl2ZVxyXG4gICAqIG51bWJlciB2YWx1ZXMuXHJcbiAgICovXHJcbiAgbm9uTmVnYXRpdmVOdW0oc3RyaWN0Q2hlY2spIHtcclxuICAgIHJldHVybiBzdHJpY3RDaGVja1xyXG4gICAgICA/IHoubnVtYmVyKCkubm9ubmVnYXRpdmUoKVxyXG4gICAgICA6IHpcclxuICAgICAgICAgIC51bmlvbihbXHJcbiAgICAgICAgICAgIHpcclxuICAgICAgICAgICAgICAuc3RyaW5nKClcclxuICAgICAgICAgICAgICAudHJpbSgpXHJcbiAgICAgICAgICAgICAgLnJlZmluZShcclxuICAgICAgICAgICAgICAgICh2YWx1ZSkgPT5cclxuICAgICAgICAgICAgICAgICAgKCFpc05hTihOdW1iZXIodmFsdWUpKSAmJiBOdW1iZXIodmFsdWUpID49IDApIHx8XHJcbiAgICAgICAgICAgICAgICAgIFsndW5kZWZpbmVkJywgJ251bGwnLCAnJ10uaW5jbHVkZXModmFsdWUpLFxyXG4gICAgICAgICAgICAgICAge1xyXG4gICAgICAgICAgICAgICAgICBwYXJhbXM6IHtcclxuICAgICAgICAgICAgICAgICAgICBlcnJvck1lc3NhZ2U6ICdUaGUgdmFsdWUgbXVzdCBiZSBudW1lcmljIGFuZCBub24tbmVnYXRpdmUnXHJcbiAgICAgICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgICApXHJcbiAgICAgICAgICAgICAgLnRyYW5zZm9ybSgodmFsdWUpID0+XHJcbiAgICAgICAgICAgICAgICAhWyd1bmRlZmluZWQnLCAnbnVsbCcsICcnXS5pbmNsdWRlcyh2YWx1ZSlcclxuICAgICAgICAgICAgICAgICAgPyBOdW1iZXIodmFsdWUpXHJcbiAgICAgICAgICAgICAgICAgIDogbnVsbFxyXG4gICAgICAgICAgICAgICksXHJcbiAgICAgICAgICAgIHoubnVtYmVyKCkubm9ubmVnYXRpdmUoKVxyXG4gICAgICAgICAgXSlcclxuICAgICAgICAgIC5udWxsYWJsZSgpO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgc3RhcnRzV2l0aGAgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbFxyXG4gICAqIHN0cmljdGVyIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSBzY2hlbWEgd2lsbCB2YWxpZGF0ZSBhZ2FpbnN0IHRoZSBwcm92aWRlZCBgcHJlZml4ZXNgIGFycmF5IHRvIGNoZWNrXHJcbiAgICogd2hldGhlciBhIHN0cmluZyB2YWx1ZSBzdGFydHMgd2l0aCBhbnkgb2YgdGhlIHZhbHVlcyBwcm92aWRlZFxyXG4gICAqIGluIHRoZSBgcHJlZml4ZXNgIGFycmF5LlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhhdDpcclxuICAgKlxyXG4gICAqIC0gV2hlbiBgc3RyaWN0Q2hlY2tgIGlzIHRydWUsIHRoZSBzY2hlbWEgd2lsbCBhY2NlcHQgdHJpbW1lZCBzdHJpbmcgdmFsdWVzXHJcbiAgICogdGhhdCBzdGFydCB3aXRoIHZhbHVlcyBmcm9tIHRoZSBwcmVmaXhlcyBhcnJheS5cclxuICAgKlxyXG4gICAqIC0gV2hlbiBgc3RyaWN0Q2hlY2tgIGlzIGZhbHNlLCB0aGUgc2NoZW1hIHdpbGwgYWNjZXB0IHRyaW1tZWQgc3RyaW5nIHZhbHVlc1xyXG4gICAqIHRoYXQgc3RhcnQgd2l0aCB2YWx1ZXMgZnJvbSB0aGUgcHJlZml4ZXMgYXJyYXksIG51bGwsICd1bmRlZmluZWQnLCAnbnVsbCcsXHJcbiAgICogYW5kICcnIHdoZXJlIHRoZSBzY2hlbWEgd2lsbCB0cmFuc2Zvcm0gdGhlbSB0byBudWxsLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIHN0YXJ0c1dpdGhcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7QXJyYXkuPHN0cmluZz59IHByZWZpeGVzIC0gQW4gYXJyYXkgb2YgcHJlZml4ZXMgdG8gdmFsaWRhdGVcclxuICAgKiB0aGUgc3RyaW5nIGFnYWluc3QuXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nIHN0cmluZ3MgdGhhdFxyXG4gICAqIHN0YXJ0cyB3aXRoIHZhbHVlcy5cclxuICAgKi9cclxuICBzdGFydHNXaXRoKHByZWZpeGVzLCBzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHN0cmljdENoZWNrXHJcbiAgICAgID8gelxyXG4gICAgICAgICAgLnN0cmluZygpXHJcbiAgICAgICAgICAudHJpbSgpXHJcbiAgICAgICAgICAucmVmaW5lKFxyXG4gICAgICAgICAgICAodmFsdWUpID0+IHByZWZpeGVzLnNvbWUoKHByZWZpeCkgPT4gdmFsdWUuc3RhcnRzV2l0aChwcmVmaXgpKSxcclxuICAgICAgICAgICAge1xyXG4gICAgICAgICAgICAgIHBhcmFtczoge1xyXG4gICAgICAgICAgICAgICAgZXJyb3JNZXNzYWdlOiBgVGhlIHZhbHVlIG11c3QgYmUgYSBzdHJpbmcgdGhhdCBzdGFydHMgd2l0aCAke3ByZWZpeGVzLmpvaW4oJywgJyl9YFxyXG4gICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgfVxyXG4gICAgICAgICAgKVxyXG4gICAgICA6IHpcclxuICAgICAgICAgIC5zdHJpbmcoKVxyXG4gICAgICAgICAgLnRyaW0oKVxyXG4gICAgICAgICAgLnJlZmluZShcclxuICAgICAgICAgICAgKHZhbHVlKSA9PlxyXG4gICAgICAgICAgICAgIHByZWZpeGVzLnNvbWUoKHByZWZpeCkgPT4gdmFsdWUuc3RhcnRzV2l0aChwcmVmaXgpKSB8fFxyXG4gICAgICAgICAgICAgIFsndW5kZWZpbmVkJywgJ251bGwnLCAnJ10uaW5jbHVkZXModmFsdWUpLFxyXG4gICAgICAgICAgICB7XHJcbiAgICAgICAgICAgICAgcGFyYW1zOiB7XHJcbiAgICAgICAgICAgICAgICBlcnJvck1lc3NhZ2U6IGBUaGUgdmFsdWUgbXVzdCBiZSBhIHN0cmluZyB0aGF0IHN0YXJ0cyB3aXRoICR7cHJlZml4ZXMuam9pbignLCAnKX1gXHJcbiAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICB9XHJcbiAgICAgICAgICApXHJcbiAgICAgICAgICAudHJhbnNmb3JtKCh2YWx1ZSkgPT5cclxuICAgICAgICAgICAgIVsndW5kZWZpbmVkJywgJ251bGwnLCAnJ10uaW5jbHVkZXModmFsdWUpID8gdmFsdWUgOiBudWxsXHJcbiAgICAgICAgICApXHJcbiAgICAgICAgICAubnVsbGFibGUoKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYGNoYXJ0Q29uZmlnYCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYS5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoYXQgdGhlIHNjaGVtYSB3aWxsIGFjY2VwdCBvYmplY3QgdmFsdWVzXHJcbiAgICogb3IgdHJpbW1lZCBzdHJpbmcgdmFsdWVzIHRoYXQgY29udGFpbiAnPHN2Zycgb3IgJzw/eG1sJyBlbGVtZW50cywgc3RhcnRcclxuICAgKiB3aXRoIHRoZSAneycgYW5kIGVuZCB3aXRoIHRoZSAnfScsIGFuZCBudWxsLiBUaGUgJ3VuZGVmaW5lZCcsICdudWxsJyxcclxuICAgKiBhbmQgJycgdmFsdWVzIHdpbGwgYmUgdHJhbnNmb3JtZWQgdG8gbnVsbC5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiBjaGFydENvbmZpZ1xyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nIGNoYXJ0XHJcbiAgICogY29uZmlndXJhdGlvbiB2YWx1ZS5cclxuICAgKi9cclxuICBjaGFydENvbmZpZygpIHtcclxuICAgIHJldHVybiB6XHJcbiAgICAgIC51bmlvbihbXHJcbiAgICAgICAgelxyXG4gICAgICAgICAgLnN0cmluZygpXHJcbiAgICAgICAgICAudHJpbSgpXHJcbiAgICAgICAgICAucmVmaW5lKFxyXG4gICAgICAgICAgICAodmFsdWUpID0+XHJcbiAgICAgICAgICAgICAgKHZhbHVlLnN0YXJ0c1dpdGgoJ3snKSAmJiB2YWx1ZS5lbmRzV2l0aCgnfScpKSB8fFxyXG4gICAgICAgICAgICAgIFsndW5kZWZpbmVkJywgJ251bGwnLCAnJ10uaW5jbHVkZXModmFsdWUpLFxyXG4gICAgICAgICAgICB7XHJcbiAgICAgICAgICAgICAgcGFyYW1zOiB7XHJcbiAgICAgICAgICAgICAgICBlcnJvck1lc3NhZ2U6XHJcbiAgICAgICAgICAgICAgICAgIFwiVGhlIHZhbHVlIG11c3QgYmUgYSBzdHJpbmcgdGhhdCBzdGFydHMgd2l0aCAneycgYW5kIGVuZHMgd2l0aCAnfSdcIlxyXG4gICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgfVxyXG4gICAgICAgICAgKVxyXG4gICAgICAgICAgLnRyYW5zZm9ybSgodmFsdWUpID0+XHJcbiAgICAgICAgICAgICFbJ3VuZGVmaW5lZCcsICdudWxsJywgJyddLmluY2x1ZGVzKHZhbHVlKSA/IHZhbHVlIDogbnVsbFxyXG4gICAgICAgICAgKSxcclxuICAgICAgICB6Lm9iamVjdCh7fSkucGFzc3Rocm91Z2goKVxyXG4gICAgICBdKVxyXG4gICAgICAubnVsbGFibGUoKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYGFkZGl0aW9uYWxPcHRpb25zYCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYS5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoYXQgdGhlIHNjaGVtYSB3aWxsIGFjY2VwdCBvYmplY3QgdmFsdWVzXHJcbiAgICogb3IgdHJpbW1lZCBzdHJpbmcgdmFsdWVzIHRoYXQgZW5kIHdpdGggJy5qc29uJyBhbmQgYXJlIGF0IGxlYXN0IG9uZVxyXG4gICAqIGNoYXJhY3RlciBsb25nIGV4Y2x1ZGluZyB0aGUgZXh0ZW5zaW9uLCBzdGFydCB3aXRoIHRoZSAneycgYW5kIGVuZFxyXG4gICAqIHdpdGggdGhlICd9JywgYW5kIG51bGwuIFRoZSAndW5kZWZpbmVkJywgJ251bGwnLCBhbmQgJycgdmFsdWVzIHdpbGxcclxuICAgKiBiZSB0cmFuc2Zvcm1lZCB0byBudWxsLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIGFkZGl0aW9uYWxPcHRpb25zXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9ICBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nIGFkZGl0aW9uYWwgY2hhcnRcclxuICAgKiBvcHRpb25zIHZhbHVlLlxyXG4gICAqL1xyXG4gIGFkZGl0aW9uYWxPcHRpb25zKCkge1xyXG4gICAgcmV0dXJuIHpcclxuICAgICAgLnVuaW9uKFtcclxuICAgICAgICB6XHJcbiAgICAgICAgICAuc3RyaW5nKClcclxuICAgICAgICAgIC50cmltKClcclxuICAgICAgICAgIC5yZWZpbmUoXHJcbiAgICAgICAgICAgICh2YWx1ZSkgPT5cclxuICAgICAgICAgICAgICAodmFsdWUubGVuZ3RoID49IDYgJiYgdmFsdWUuZW5kc1dpdGgoJy5qc29uJykpIHx8XHJcbiAgICAgICAgICAgICAgKHZhbHVlLnN0YXJ0c1dpdGgoJ3snKSAmJiB2YWx1ZS5lbmRzV2l0aCgnfScpKSB8fFxyXG4gICAgICAgICAgICAgIFsndW5kZWZpbmVkJywgJ251bGwnLCAnJ10uaW5jbHVkZXModmFsdWUpLFxyXG4gICAgICAgICAgICB7XHJcbiAgICAgICAgICAgICAgcGFyYW1zOiB7XHJcbiAgICAgICAgICAgICAgICBlcnJvck1lc3NhZ2U6XHJcbiAgICAgICAgICAgICAgICAgIFwiVGhlIHZhbHVlIG11c3QgYmUgYSBzdHJpbmcgdGhhdCBlbmRzIHdpdGggJy5qc29uJyBvciBzdGFydHMgd2l0aCAneycgYW5kIGVuZHMgd2l0aCAnfSdcIlxyXG4gICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgfVxyXG4gICAgICAgICAgKVxyXG4gICAgICAgICAgLnRyYW5zZm9ybSgodmFsdWUpID0+XHJcbiAgICAgICAgICAgICFbJ3VuZGVmaW5lZCcsICdudWxsJywgJyddLmluY2x1ZGVzKHZhbHVlKSA/IHZhbHVlIDogbnVsbFxyXG4gICAgICAgICAgKSxcclxuICAgICAgICB6Lm9iamVjdCh7fSkucGFzc3Rocm91Z2goKVxyXG4gICAgICBdKVxyXG4gICAgICAubnVsbGFibGUoKTtcclxuICB9XHJcbn07XHJcblxyXG4vKipcclxuICogT2JqZWN0IGNvbnRhaW5pbmcgY3VzdG9tIGNvbmZpZyB2YWxpZGF0b3JzIGFuZCBwYXJzZXJzIHRvIGF2b2lkIHJlcGV0aXRpb25cclxuICogaW4gc2NoZW1hIG9iamVjdHMuIEFsbCB2YWxpZGF0b3JzIGFwcGx5IHRvIHZhbHVlcyBmcm9tIHZhcmlvdXMgc291cmNlcyxcclxuICogaW5jbHVkaW5nIHRoZSBkZWZhdWx0IGNvbmZpZyBmaWxlLCBhIGN1c3RvbSBKU09OIGZpbGUgbG9hZGVkIHdpdGggdGhlIG9wdGlvblxyXG4gKiBjYWxsZWQgYGxvYWRDb25maWdgLCB0aGUgLmVudiBmaWxlLCBDTEkgYXJndW1lbnRzLCBhbmQgdGhlIHJlcXVlc3QgcGF5bG9hZC5cclxuICogVGhlIGBzdHJpY3RDaGVja2AgZmxhZyBlbmFibGVzIHN0cmljdGVyIHZhbGlkYXRpb24gYW5kIHBhcnNpbmcgcnVsZXMuIFRoaXNcclxuICogZmxhZyBpcyBzZXQgdG8gZmFsc2UgZm9yIHZhbHVlcyB0aGF0IGNvbWUgZnJvbSB0aGUgLmVudiBmaWxlIG9yIENMSSBhcmd1bWVudHNcclxuICogYmVjYXVzZSB0aGV5IGFyZSBwcm92aWRlZCBhcyBzdHJpbmdzIGFuZCBuZWVkIHRvIGJlIHBhcnNlZCBhY2NvcmRpbmdseSBmaXJzdC5cclxuICovXHJcbmV4cG9ydCBjb25zdCB2YWxpZGF0b3JzID0ge1xyXG4gIC8qKlxyXG4gICAqIFRoZSBgYXJnc2AgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbCBzdHJpY3RlclxyXG4gICAqIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgdGhlIGBzdHJpbmdBcnJheWAgdmFsaWRhdG9yLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIGFyZ3NcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZyB0aGUgYGFyZ3NgXHJcbiAgICogb3B0aW9uLlxyXG4gICAqL1xyXG4gIGFyZ3Moc3RyaWN0Q2hlY2spIHtcclxuICAgIHJldHVybiB2LnN0cmluZ0FycmF5KFxyXG4gICAgICAodmFsdWUpID0+ICFbJ2ZhbHNlJywgJ3VuZGVmaW5lZCcsICdudWxsJywgJyddLmluY2x1ZGVzKHZhbHVlKSxcclxuICAgICAgJzsnLFxyXG4gICAgICBzdHJpY3RDaGVja1xyXG4gICAgKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYHZlcnNpb25gIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGggYW4gb3B0aW9uYWwgc3RyaWN0ZXJcclxuICAgKiBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGF0OlxyXG4gICAqXHJcbiAgICogLSBXaGVuIGBzdHJpY3RDaGVja2AgaXMgdHJ1ZSwgdGhlIHNjaGVtYSB3aWxsIGFjY2VwdCB0cmltbWVkIHN0cmluZyB2YWx1ZXNcclxuICAgKiB0aGF0IGFyZSBhIFJlZ0V4cC1iYXNlZCB0aGF0IGFsbG93cyB0byBiZSAnbGF0ZXN0Jywgb3IgaW4gdGhlIGZvcm1hdCBYWCxcclxuICAgKiBYWC5ZWSwgb3IgWFguWVkuWlosIHdoZXJlIFhYLCBZWSwgYW5kIFpaIGFyZSBudW1lcmljIGZvciB0aGUgSGlnaGNoYXJ0c1xyXG4gICAqIHZlcnNpb24gb3B0aW9uLlxyXG4gICAqXHJcbiAgICogLSBXaGVuIGBzdHJpY3RDaGVja2AgaXMgZmFsc2UsIHRoZSBzY2hlbWEgd2lsbCBhY2NlcHQgYWxzbyBudWxsLFxyXG4gICAqICd1bmRlZmluZWQnLCAnbnVsbCcsIG9yICcnIGFuZCBpbiBhbGwgY2FzZXMgdGhlIHNjaGVtYSB3aWxsIHRyYW5zZm9ybSB0aGVtXHJcbiAgICogdG8gbnVsbC5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiB2ZXJzaW9uXHJcbiAgICpcclxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IHN0cmljdENoZWNrIC0gRGV0ZXJtaW5lcyBpZiBzdHJpY3RlciB2YWxpZGF0aW9uIHNob3VsZFxyXG4gICAqIGJlIGFwcGxpZWQuXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9IEEgWm9kIHNjaGVtYSBvYmplY3QgZm9yIHZhbGlkYXRpbmcgdGhlIGB2ZXJzaW9uYFxyXG4gICAqIG9wdGlvbi5cclxuICAgKi9cclxuICB2ZXJzaW9uKHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gc3RyaWN0Q2hlY2tcclxuICAgICAgPyB6XHJcbiAgICAgICAgICAuc3RyaW5nKClcclxuICAgICAgICAgIC50cmltKClcclxuICAgICAgICAgIC5yZWZpbmUoKHZhbHVlKSA9PiAvXihsYXRlc3R8XFxkezEsMn0oXFwuXFxkezEsMn0pezAsMn0pJC8udGVzdCh2YWx1ZSksIHtcclxuICAgICAgICAgICAgcGFyYW1zOiB7XHJcbiAgICAgICAgICAgICAgZXJyb3JNZXNzYWdlOlxyXG4gICAgICAgICAgICAgICAgXCJUaGUgdmFsdWUgbXVzdCBiZSAnbGF0ZXN0JywgYSBtYWpvciB2ZXJzaW9uLCBvciBpbiB0aGUgZm9ybSBYWC5ZWS5aWlwiXHJcbiAgICAgICAgICAgIH1cclxuICAgICAgICAgIH0pXHJcbiAgICAgIDogelxyXG4gICAgICAgICAgLnN0cmluZygpXHJcbiAgICAgICAgICAudHJpbSgpXHJcbiAgICAgICAgICAucmVmaW5lKFxyXG4gICAgICAgICAgICAodmFsdWUpID0+XHJcbiAgICAgICAgICAgICAgL14obGF0ZXN0fFxcZHsxLDJ9KFxcLlxcZHsxLDJ9KXswLDJ9KSQvLnRlc3QodmFsdWUpIHx8XHJcbiAgICAgICAgICAgICAgWyd1bmRlZmluZWQnLCAnbnVsbCcsICcnXS5pbmNsdWRlcyh2YWx1ZSksXHJcbiAgICAgICAgICAgIHtcclxuICAgICAgICAgICAgICBwYXJhbXM6IHtcclxuICAgICAgICAgICAgICAgIGVycm9yTWVzc2FnZTpcclxuICAgICAgICAgICAgICAgICAgXCJUaGUgdmFsdWUgbXVzdCBiZSAnbGF0ZXN0JywgYSBtYWpvciB2ZXJzaW9uLCBvciBpbiB0aGUgZm9ybSBYWC5ZWS5aWlwiXHJcbiAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICB9XHJcbiAgICAgICAgICApXHJcbiAgICAgICAgICAudHJhbnNmb3JtKCh2YWx1ZSkgPT5cclxuICAgICAgICAgICAgIVsndW5kZWZpbmVkJywgJ251bGwnLCAnJ10uaW5jbHVkZXModmFsdWUpID8gdmFsdWUgOiBudWxsXHJcbiAgICAgICAgICApXHJcbiAgICAgICAgICAubnVsbGFibGUoKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYGNkblVybGAgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbCBzdHJpY3RlclxyXG4gICAqIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgdGhlIGBzdGFydHNXaXRoYCB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gY2RuVXJsXHJcbiAgICpcclxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IHN0cmljdENoZWNrIC0gRGV0ZXJtaW5lcyBpZiBzdHJpY3RlciB2YWxpZGF0aW9uIHNob3VsZFxyXG4gICAqIGJlIGFwcGxpZWQuXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9IEEgWm9kIHNjaGVtYSBvYmplY3QgZm9yIHZhbGlkYXRpbmcgdGhlIGBjZG5VcmxgXHJcbiAgICogb3B0aW9uLlxyXG4gICAqL1xyXG4gIGNkblVybChzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHYuc3RhcnRzV2l0aChbJ2h0dHA6Ly8nLCAnaHR0cHM6Ly8nXSwgc3RyaWN0Q2hlY2spO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgZm9yY2VGZXRjaGAgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbFxyXG4gICAqIHN0cmljdGVyIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgdGhlIGBib29sZWFuYCB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gZm9yY2VGZXRjaFxyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nIHRoZSBgZm9yY2VGZXRjaGBcclxuICAgKiBvcHRpb24uXHJcbiAgICovXHJcbiAgZm9yY2VGZXRjaChzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHYuYm9vbGVhbihzdHJpY3RDaGVjayk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGBjYWNoZVBhdGhgIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGggYW4gb3B0aW9uYWxcclxuICAgKiBzdHJpY3RlciBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGUgc2FtZSB3b3JrIGFzIHRoZSBgc3RyaW5nYCB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gY2FjaGVQYXRoXHJcbiAgICpcclxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IHN0cmljdENoZWNrIC0gRGV0ZXJtaW5lcyBpZiBzdHJpY3RlciB2YWxpZGF0aW9uIHNob3VsZFxyXG4gICAqIGJlIGFwcGxpZWQuXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9IEEgWm9kIHNjaGVtYSBvYmplY3QgZm9yIHZhbGlkYXRpbmcgdGhlIGBjYWNoZVBhdGhgXHJcbiAgICogb3B0aW9uLlxyXG4gICAqL1xyXG4gIGNhY2hlUGF0aChzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHYuc3RyaW5nKHN0cmljdENoZWNrKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYGFkbWluVG9rZW5gIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGggYW4gb3B0aW9uYWxcclxuICAgKiBzdHJpY3RlciBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGUgc2FtZSB3b3JrIGFzIHRoZSBgc3RyaW5nYCB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gYWRtaW5Ub2tlblxyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nIHRoZSBgYWRtaW5Ub2tlbmBcclxuICAgKiBvcHRpb24uXHJcbiAgICovXHJcbiAgYWRtaW5Ub2tlbihzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHYuc3RyaW5nKHN0cmljdENoZWNrKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYGNvcmVTY3JpcHRzYCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoIGFuIG9wdGlvbmFsXHJcbiAgICogc3RyaWN0ZXIgY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhlIHNhbWUgd29yayBhcyB0aGUgYHN0cmluZ0FycmF5YCB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gY29yZVNjcmlwdHNcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZyB0aGUgYGNvcmVTY3JpcHRzYFxyXG4gICAqIG9wdGlvbi5cclxuICAgKi9cclxuICBjb3JlU2NyaXB0cyhzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHYuc3RyaW5nQXJyYXkoXHJcbiAgICAgICh2YWx1ZSkgPT4gY29yZVNjcmlwdHMudmFsdWUuaW5jbHVkZXModmFsdWUpLFxyXG4gICAgICAnLCcsXHJcbiAgICAgIHN0cmljdENoZWNrXHJcbiAgICApO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgbW9kdWxlU2NyaXB0c2AgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbFxyXG4gICAqIHN0cmljdGVyIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgdGhlIGBzdHJpbmdBcnJheWAgdmFsaWRhdG9yLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIG1vZHVsZVNjcmlwdHNcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZ1xyXG4gICAqIHRoZSBgbW9kdWxlU2NyaXB0c2Agb3B0aW9uLlxyXG4gICAqL1xyXG4gIG1vZHVsZVNjcmlwdHMoc3RyaWN0Q2hlY2spIHtcclxuICAgIHJldHVybiB2LnN0cmluZ0FycmF5KFxyXG4gICAgICAodmFsdWUpID0+IG1vZHVsZVNjcmlwdHMudmFsdWUuaW5jbHVkZXModmFsdWUpLFxyXG4gICAgICAnLCcsXHJcbiAgICAgIHN0cmljdENoZWNrXHJcbiAgICApO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgaW5kaWNhdG9yU2NyaXB0c2AgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbFxyXG4gICAqIHN0cmljdGVyIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgdGhlIGBzdHJpbmdBcnJheWAgdmFsaWRhdG9yLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIGluZGljYXRvclNjcmlwdHNcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZ1xyXG4gICAqIHRoZSBgaW5kaWNhdG9yU2NyaXB0c2Agb3B0aW9uLlxyXG4gICAqL1xyXG4gIGluZGljYXRvclNjcmlwdHMoc3RyaWN0Q2hlY2spIHtcclxuICAgIHJldHVybiB2LnN0cmluZ0FycmF5KFxyXG4gICAgICAodmFsdWUpID0+IGluZGljYXRvclNjcmlwdHMudmFsdWUuaW5jbHVkZXModmFsdWUpLFxyXG4gICAgICAnLCcsXHJcbiAgICAgIHN0cmljdENoZWNrXHJcbiAgICApO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgY3VzdG9tU2NyaXB0c2AgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbFxyXG4gICAqIHN0cmljdGVyIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgdGhlIGBzdHJpbmdBcnJheWAgdmFsaWRhdG9yLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIGN1c3RvbVNjcmlwdHNcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZ1xyXG4gICAqIHRoZSBgY3VzdG9tU2NyaXB0c2Agb3B0aW9uLlxyXG4gICAqL1xyXG4gIGN1c3RvbVNjcmlwdHMoc3RyaWN0Q2hlY2spIHtcclxuICAgIHJldHVybiB2LnN0cmluZ0FycmF5KFxyXG4gICAgICAodmFsdWUpID0+IHZhbHVlLnN0YXJ0c1dpdGgoJ2h0dHBzOi8vJykgfHwgdmFsdWUuc3RhcnRzV2l0aCgnaHR0cDovLycpLFxyXG4gICAgICAnLCcsXHJcbiAgICAgIHN0cmljdENoZWNrXHJcbiAgICApO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgaW5maWxlYCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoIGFuIG9wdGlvbmFsIHN0cmljdGVyXHJcbiAgICogY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhhdDpcclxuICAgKlxyXG4gICAqIC0gV2hlbiBgc3RyaWN0Q2hlY2tgIGlzIHRydWUsIHRoZSBzY2hlbWEgd2lsbCBhY2NlcHQgdHJpbW1lZCBzdHJpbmcgdmFsdWVzXHJcbiAgICogdGhhdCBlbmQgd2l0aCAnLmpzb24nIG9yICcuc3ZnJywgYXJlIGF0IGxlYXN0IG9uZSBjaGFyYWN0ZXIgbG9uZyBleGNsdWRpbmdcclxuICAgKiB0aGUgZXh0ZW5zaW9uLCBvciBudWxsLlxyXG4gICAqXHJcbiAgICogLSBXaGVuIGBzdHJpY3RDaGVja2AgaXMgZmFsc2UsIHRoZSBzY2hlbWEgd2lsbCBhY2NlcHQgdHJpbW1lZCBzdHJpbmcgdmFsdWVzXHJcbiAgICogdGhhdCBlbmQgd2l0aCAnLmpzb24nIG9yICcuc3ZnJywgYXJlIGF0IGxlYXN0IG9uZSBjaGFyYWN0ZXIgbG9uZyBleGNsdWRpbmdcclxuICAgKiB0aGUgZXh0ZW5zaW9uIGFuZCB3aWxsIGJlIG51bGwgaWYgdGhlIHByb3ZpZGVkIHZhbHVlIGlzIG51bGwsICd1bmRlZmluZWQnLFxyXG4gICAqICdudWxsJywgb3IgJycuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gaW5maWxlXHJcbiAgICpcclxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IHN0cmljdENoZWNrIC0gRGV0ZXJtaW5lcyBpZiBzdHJpY3RlciB2YWxpZGF0aW9uIHNob3VsZFxyXG4gICAqIGJlIGFwcGxpZWQuXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9IEEgWm9kIHNjaGVtYSBvYmplY3QgZm9yIHZhbGlkYXRpbmcgdGhlIGBpbmZpbGVgXHJcbiAgICogb3B0aW9uLlxyXG4gICAqL1xyXG4gIGluZmlsZShzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHN0cmljdENoZWNrXHJcbiAgICAgID8gelxyXG4gICAgICAgICAgLnN0cmluZygpXHJcbiAgICAgICAgICAudHJpbSgpXHJcbiAgICAgICAgICAucmVmaW5lKFxyXG4gICAgICAgICAgICAodmFsdWUpID0+XHJcbiAgICAgICAgICAgICAgKHZhbHVlLmxlbmd0aCA+PSA2ICYmIHZhbHVlLmVuZHNXaXRoKCcuanNvbicpKSB8fFxyXG4gICAgICAgICAgICAgICh2YWx1ZS5sZW5ndGggPj0gNSAmJiB2YWx1ZS5lbmRzV2l0aCgnLnN2ZycpKSxcclxuICAgICAgICAgICAge1xyXG4gICAgICAgICAgICAgIHBhcmFtczoge1xyXG4gICAgICAgICAgICAgICAgZXJyb3JNZXNzYWdlOlxyXG4gICAgICAgICAgICAgICAgICAnVGhlIHZhbHVlIG11c3QgYmUgYSBzdHJpbmcgdGhhdCBlbmRzIHdpdGggLmpzb24gb3IgLnN2ZydcclxuICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgIH1cclxuICAgICAgICAgIClcclxuICAgICAgICAgIC5udWxsYWJsZSgpXHJcbiAgICAgIDogelxyXG4gICAgICAgICAgLnN0cmluZygpXHJcbiAgICAgICAgICAudHJpbSgpXHJcbiAgICAgICAgICAucmVmaW5lKFxyXG4gICAgICAgICAgICAodmFsdWUpID0+XHJcbiAgICAgICAgICAgICAgKHZhbHVlLmxlbmd0aCA+PSA2ICYmIHZhbHVlLmVuZHNXaXRoKCcuanNvbicpKSB8fFxyXG4gICAgICAgICAgICAgICh2YWx1ZS5sZW5ndGggPj0gNSAmJiB2YWx1ZS5lbmRzV2l0aCgnLnN2ZycpKSB8fFxyXG4gICAgICAgICAgICAgIFsndW5kZWZpbmVkJywgJ251bGwnLCAnJ10uaW5jbHVkZXModmFsdWUpLFxyXG4gICAgICAgICAgICB7XHJcbiAgICAgICAgICAgICAgcGFyYW1zOiB7XHJcbiAgICAgICAgICAgICAgICBlcnJvck1lc3NhZ2U6XHJcbiAgICAgICAgICAgICAgICAgICdUaGUgdmFsdWUgbXVzdCBiZSBhIHN0cmluZyB0aGF0IGVuZHMgd2l0aCAuanNvbiBvciAuc3ZnJ1xyXG4gICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgfVxyXG4gICAgICAgICAgKVxyXG4gICAgICAgICAgLnRyYW5zZm9ybSgodmFsdWUpID0+XHJcbiAgICAgICAgICAgICFbJ3VuZGVmaW5lZCcsICdudWxsJywgJyddLmluY2x1ZGVzKHZhbHVlKSA/IHZhbHVlIDogbnVsbFxyXG4gICAgICAgICAgKVxyXG4gICAgICAgICAgLm51bGxhYmxlKCk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGBpbnN0cmAgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGUgc2FtZSB3b3JrIGFzIHRoZSBgb3B0aW9uc2AgdmFsaWRhdG9yLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIGluc3RyXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9IEEgWm9kIHNjaGVtYSBvYmplY3QgZm9yIHZhbGlkYXRpbmcgdGhlIGBpbnN0cmBcclxuICAgKiBvcHRpb24uXHJcbiAgICovXHJcbiAgaW5zdHIoKSB7XHJcbiAgICByZXR1cm4gdi5jaGFydENvbmZpZygpO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgb3B0aW9uc2AgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGUgc2FtZSB3b3JrIGFzIHRoZSBgb3B0aW9uc2AgdmFsaWRhdG9yLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIG9wdGlvbnNcclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZyB0aGUgYG9wdGlvbnNgXHJcbiAgICogb3B0aW9uLlxyXG4gICAqL1xyXG4gIG9wdGlvbnMoKSB7XHJcbiAgICByZXR1cm4gdi5jaGFydENvbmZpZygpO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgc3ZnYCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYS5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoYXQgdGhlIHNjaGVtYSB3aWxsIGFjY2VwdCBvYmplY3QgdmFsdWVzXHJcbiAgICogb3IgdHJpbW1lZCBzdHJpbmcgdmFsdWVzIHRoYXQgY29udGFpbiAnPHN2Zycgb3IgJzw/eG1sJyBlbGVtZW50cyBhbmQgbnVsbC5cclxuICAgKiBUaGUgJ3VuZGVmaW5lZCcsICdudWxsJywgYW5kICcnIHZhbHVlcyB3aWxsIGJlIHRyYW5zZm9ybWVkIHRvIG51bGwuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gc3ZnXHJcbiAgICpcclxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IHN0cmljdENoZWNrIC0gRGV0ZXJtaW5lcyBpZiBzdHJpY3RlciB2YWxpZGF0aW9uIHNob3VsZFxyXG4gICAqIGJlIGFwcGxpZWQuXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9IEEgWm9kIHNjaGVtYSBvYmplY3QgZm9yIHZhbGlkYXRpbmcgdGhlIGBzdmdgIG9wdGlvbi5cclxuICAgKi9cclxuICBzdmcoKSB7XHJcbiAgICByZXR1cm4gelxyXG4gICAgICAuc3RyaW5nKClcclxuICAgICAgLnRyaW0oKVxyXG4gICAgICAucmVmaW5lKFxyXG4gICAgICAgICh2YWx1ZSkgPT5cclxuICAgICAgICAgIHZhbHVlLmluZGV4T2YoJzxzdmcnKSA+PSAwIHx8XHJcbiAgICAgICAgICB2YWx1ZS5pbmRleE9mKCc8P3htbCcpID49IDAgfHxcclxuICAgICAgICAgIFsnZmFsc2UnLCAndW5kZWZpbmVkJywgJ251bGwnLCAnJ10uaW5jbHVkZXModmFsdWUpLFxyXG4gICAgICAgIHtcclxuICAgICAgICAgIHBhcmFtczoge1xyXG4gICAgICAgICAgICBlcnJvck1lc3NhZ2U6XHJcbiAgICAgICAgICAgICAgXCJUaGUgdmFsdWUgbXVzdCBiZSBhIHN0cmluZyB0aGF0IGNvbnRhaW5zICc8c3ZnJyBvciAnPD94bWwnXCJcclxuICAgICAgICAgIH1cclxuICAgICAgICB9XHJcbiAgICAgIClcclxuICAgICAgLnRyYW5zZm9ybSgodmFsdWUpID0+XHJcbiAgICAgICAgIVsnZmFsc2UnLCAndW5kZWZpbmVkJywgJ251bGwnLCAnJ10uaW5jbHVkZXModmFsdWUpID8gdmFsdWUgOiBudWxsXHJcbiAgICAgIClcclxuICAgICAgLm51bGxhYmxlKCk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGBvdXRmaWxlYCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoIGFuIG9wdGlvbmFsIHN0cmljdGVyXHJcbiAgICogY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhhdDpcclxuICAgKlxyXG4gICAqIC0gV2hlbiBgc3RyaWN0Q2hlY2tgIGlzIHRydWUsIHRoZSBzY2hlbWEgd2lsbCBhY2NlcHQgdHJpbW1lZCBzdHJpbmcgdmFsdWVzXHJcbiAgICogdGhhdCBlbmQgd2l0aCAnLmpwZWcnLCAnLmpwZycsICcucG5nJywgJy5wZGYnLCBvciAnLnN2ZycsIGFyZSBhdCBsZWFzdCBvbmVcclxuICAgKiBjaGFyYWN0ZXIgbG9uZyBleGNsdWRpbmcgdGhlIGV4dGVuc2lvbiwgb3IgbnVsbC5cclxuICAgKlxyXG4gICAqIC0gV2hlbiBgc3RyaWN0Q2hlY2tgIGlzIGZhbHNlLCB0aGUgc2NoZW1hIHdpbGwgYWNjZXB0IHRyaW1tZWQgc3RyaW5nIHZhbHVlc1xyXG4gICAqIHRoYXQgZW5kIHdpdGggJy5qcGVnJywgJy5qcGcnLCAnLnBuZycsICcucGRmJywgb3IgJy5zdmcnLCBhcmUgYXQgbGVhc3Qgb25lXHJcbiAgICogY2hhcmFjdGVyIGxvbmcgZXhjbHVkaW5nIHRoZSBleHRlbnNpb24gYW5kIHdpbGwgYmUgbnVsbCBpZiB0aGUgcHJvdmlkZWRcclxuICAgKiB2YWx1ZSBpcyBudWxsLCAndW5kZWZpbmVkJywgJ251bGwnLCBvciAnJy5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiBvdXRmaWxlXHJcbiAgICpcclxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IHN0cmljdENoZWNrIC0gRGV0ZXJtaW5lcyBpZiBzdHJpY3RlciB2YWxpZGF0aW9uIHNob3VsZFxyXG4gICAqIGJlIGFwcGxpZWQuXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9IEEgWm9kIHNjaGVtYSBvYmplY3QgZm9yIHZhbGlkYXRpbmcgdGhlIGBvdXRmaWxlYFxyXG4gICAqIG9wdGlvbi5cclxuICAgKi9cclxuICBvdXRmaWxlKHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gc3RyaWN0Q2hlY2tcclxuICAgICAgPyB6XHJcbiAgICAgICAgICAuc3RyaW5nKClcclxuICAgICAgICAgIC50cmltKClcclxuICAgICAgICAgIC5yZWZpbmUoXHJcbiAgICAgICAgICAgICh2YWx1ZSkgPT5cclxuICAgICAgICAgICAgICAodmFsdWUubGVuZ3RoID49IDYgJiYgdmFsdWUuZW5kc1dpdGgoJy5qcGVnJykpIHx8XHJcbiAgICAgICAgICAgICAgKHZhbHVlLmxlbmd0aCA+PSA1ICYmXHJcbiAgICAgICAgICAgICAgICAodmFsdWUuZW5kc1dpdGgoJy5qcGcnKSB8fFxyXG4gICAgICAgICAgICAgICAgICB2YWx1ZS5lbmRzV2l0aCgnLnBuZycpIHx8XHJcbiAgICAgICAgICAgICAgICAgIHZhbHVlLmVuZHNXaXRoKCcucGRmJykgfHxcclxuICAgICAgICAgICAgICAgICAgdmFsdWUuZW5kc1dpdGgoJy5zdmcnKSkpLFxyXG4gICAgICAgICAgICB7XHJcbiAgICAgICAgICAgICAgcGFyYW1zOiB7XHJcbiAgICAgICAgICAgICAgICBlcnJvck1lc3NhZ2U6XHJcbiAgICAgICAgICAgICAgICAgICdUaGUgdmFsdWUgbXVzdCBiZSBhIHN0cmluZyB0aGF0IGVuZHMgd2l0aCAuanBlZywgLmpwZywgLnBuZywgLnBkZiwgb3IgLnN2ZydcclxuICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgIH1cclxuICAgICAgICAgIClcclxuICAgICAgICAgIC5udWxsYWJsZSgpXHJcbiAgICAgIDogelxyXG4gICAgICAgICAgLnN0cmluZygpXHJcbiAgICAgICAgICAudHJpbSgpXHJcbiAgICAgICAgICAucmVmaW5lKFxyXG4gICAgICAgICAgICAodmFsdWUpID0+XHJcbiAgICAgICAgICAgICAgKHZhbHVlLmxlbmd0aCA+PSA2ICYmIHZhbHVlLmVuZHNXaXRoKCcuanBlZycpKSB8fFxyXG4gICAgICAgICAgICAgICh2YWx1ZS5sZW5ndGggPj0gNSAmJlxyXG4gICAgICAgICAgICAgICAgKHZhbHVlLmVuZHNXaXRoKCcuanBnJykgfHxcclxuICAgICAgICAgICAgICAgICAgdmFsdWUuZW5kc1dpdGgoJy5wbmcnKSB8fFxyXG4gICAgICAgICAgICAgICAgICB2YWx1ZS5lbmRzV2l0aCgnLnBkZicpIHx8XHJcbiAgICAgICAgICAgICAgICAgIHZhbHVlLmVuZHNXaXRoKCcuc3ZnJykpKSB8fFxyXG4gICAgICAgICAgICAgIFsndW5kZWZpbmVkJywgJ251bGwnLCAnJ10uaW5jbHVkZXModmFsdWUpLFxyXG4gICAgICAgICAgICB7XHJcbiAgICAgICAgICAgICAgcGFyYW1zOiB7XHJcbiAgICAgICAgICAgICAgICBlcnJvck1lc3NhZ2U6XHJcbiAgICAgICAgICAgICAgICAgICdUaGUgdmFsdWUgbXVzdCBiZSBhIHN0cmluZyB0aGF0IGVuZHMgd2l0aCAuanBlZywgLmpwZywgLnBuZywgLnBkZiwgb3IgLnN2ZydcclxuICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgIH1cclxuICAgICAgICAgIClcclxuICAgICAgICAgIC50cmFuc2Zvcm0oKHZhbHVlKSA9PlxyXG4gICAgICAgICAgICAhWyd1bmRlZmluZWQnLCAnbnVsbCcsICcnXS5pbmNsdWRlcyh2YWx1ZSkgPyB2YWx1ZSA6IG51bGxcclxuICAgICAgICAgIClcclxuICAgICAgICAgIC5udWxsYWJsZSgpO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgdHlwZWAgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbCBzdHJpY3RlclxyXG4gICAqIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgdGhlIGBlbnVtYCB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gdHlwZVxyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nIHRoZSBgdHlwZWBcclxuICAgKiBvcHRpb24uXHJcbiAgICovXHJcbiAgdHlwZShzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHYuZW51bShbJ2pwZWcnLCAnanBnJywgJ3BuZycsICdwZGYnLCAnc3ZnJ10sIHN0cmljdENoZWNrKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYGNvbnN0cmAgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbCBzdHJpY3RlclxyXG4gICAqIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgdGhlIGBlbnVtYCB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gY29uc3RyXHJcbiAgICpcclxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IHN0cmljdENoZWNrIC0gRGV0ZXJtaW5lcyBpZiBzdHJpY3RlciB2YWxpZGF0aW9uIHNob3VsZFxyXG4gICAqIGJlIGFwcGxpZWQuXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9IEEgWm9kIHNjaGVtYSBvYmplY3QgZm9yIHZhbGlkYXRpbmcgdGhlIGBjb25zdHJgXHJcbiAgICogb3B0aW9uLlxyXG4gICAqL1xyXG4gIGNvbnN0cihzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHYuZW51bShcclxuICAgICAgWydjaGFydCcsICdzdG9ja0NoYXJ0JywgJ21hcENoYXJ0JywgJ2dhbnR0Q2hhcnQnXSxcclxuICAgICAgc3RyaWN0Q2hlY2tcclxuICAgICk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGBiNjRgIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGggYW4gb3B0aW9uYWwgc3RyaWN0ZXJcclxuICAgKiBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGUgc2FtZSB3b3JrIGFzIHRoZSBgYm9vbGVhbmAgdmFsaWRhdG9yLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIGI2NFxyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nIHRoZSBgYjY0YCBvcHRpb24uXHJcbiAgICovXHJcbiAgYjY0KHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gdi5ib29sZWFuKHN0cmljdENoZWNrKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYG5vRG93bmxvYWRgIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGggYW4gb3B0aW9uYWxcclxuICAgKiBzdHJpY3RlciBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGUgc2FtZSB3b3JrIGFzIHRoZSBgYm9vbGVhbmAgdmFsaWRhdG9yLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIG5vRG93bmxvYWRcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZyB0aGUgYG5vRG93bmxvYWRgXHJcbiAgICogb3B0aW9uLlxyXG4gICAqL1xyXG4gIG5vRG93bmxvYWQoc3RyaWN0Q2hlY2spIHtcclxuICAgIHJldHVybiB2LmJvb2xlYW4oc3RyaWN0Q2hlY2spO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgZGVmYXVsdEhlaWdodGAgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbFxyXG4gICAqIHN0cmljdGVyIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgdGhlIGBwb3NpdGl2ZU51bWAgdmFsaWRhdG9yLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIGRlZmF1bHRIZWlnaHRcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZ1xyXG4gICAqIHRoZSBgZGVmYXVsdEhlaWdodGAgb3B0aW9uLlxyXG4gICAqL1xyXG4gIGRlZmF1bHRIZWlnaHQoc3RyaWN0Q2hlY2spIHtcclxuICAgIHJldHVybiB2LnBvc2l0aXZlTnVtKHN0cmljdENoZWNrKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYGRlZmF1bHRXaWR0aGAgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbFxyXG4gICAqIHN0cmljdGVyIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgdGhlIGBwb3NpdGl2ZU51bWAgdmFsaWRhdG9yLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIGRlZmF1bHRXaWR0aFxyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nXHJcbiAgICogdGhlIGBkZWZhdWx0V2lkdGhgIG9wdGlvbi5cclxuICAgKi9cclxuICBkZWZhdWx0V2lkdGgoc3RyaWN0Q2hlY2spIHtcclxuICAgIHJldHVybiB2LnBvc2l0aXZlTnVtKHN0cmljdENoZWNrKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYGRlZmF1bHRTY2FsZWAgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbFxyXG4gICAqIHN0cmljdGVyIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoYXQ6XHJcbiAgICpcclxuICAgKiAtIFdoZW4gYHN0cmljdENoZWNrYCBpcyB0cnVlLCB0aGUgc2NoZW1hIHdpbGwgYWNjZXB0IG51bWJlciB2YWx1ZXMgdGhhdFxyXG4gICAqIGFyZSBiZXR3ZWVuIDAuMSBhbmQgNSAoaW5jbHVzaXZlKS5cclxuICAgKlxyXG4gICAqIC0gV2hlbiBgc3RyaWN0Q2hlY2tgIGlzIGZhbHNlLCB0aGUgc2NoZW1hIHdpbGwgYWNjZXB0IG51bWJlciB2YWx1ZXNcclxuICAgKiBhbmQgc3RyaW5naWZpZWQgbnVtYmVyIHZhbHVlcyB0aGF0IGFyZSBiZXR3ZWVuIDAuMSBhbmQgNSAoaW5jbHVzaXZlKSwgbnVsbCxcclxuICAgKiAndW5kZWZpbmVkJywgJ251bGwnLCBhbmQgJycgd2hpY2ggd2lsbCBiZSB0cmFuc2Zvcm1lZCB0byBudWxsLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIGRlZmF1bHRTY2FsZVxyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nXHJcbiAgICogdGhlIGBkZWZhdWx0U2NhbGVgIG9wdGlvbi5cclxuICAgKi9cclxuICBkZWZhdWx0U2NhbGUoc3RyaWN0Q2hlY2spIHtcclxuICAgIHJldHVybiBzdHJpY3RDaGVja1xyXG4gICAgICA/IHoubnVtYmVyKCkuZ3RlKDAuMSkubHRlKDUpXHJcbiAgICAgIDogelxyXG4gICAgICAgICAgLnVuaW9uKFtcclxuICAgICAgICAgICAgelxyXG4gICAgICAgICAgICAgIC5zdHJpbmcoKVxyXG4gICAgICAgICAgICAgIC50cmltKClcclxuICAgICAgICAgICAgICAucmVmaW5lKFxyXG4gICAgICAgICAgICAgICAgKHZhbHVlKSA9PlxyXG4gICAgICAgICAgICAgICAgICAoIWlzTmFOKE51bWJlcih2YWx1ZSkpICYmXHJcbiAgICAgICAgICAgICAgICAgICAgdmFsdWUgIT09IHRydWUgJiZcclxuICAgICAgICAgICAgICAgICAgICAhdmFsdWUuc3RhcnRzV2l0aCgnWycpICYmXHJcbiAgICAgICAgICAgICAgICAgICAgTnVtYmVyKHZhbHVlKSA+PSAwLjEgJiZcclxuICAgICAgICAgICAgICAgICAgICBOdW1iZXIodmFsdWUpIDw9IDUpIHx8XHJcbiAgICAgICAgICAgICAgICAgIFsndW5kZWZpbmVkJywgJ251bGwnLCAnJ10uaW5jbHVkZXModmFsdWUpLFxyXG4gICAgICAgICAgICAgICAge1xyXG4gICAgICAgICAgICAgICAgICBwYXJhbXM6IHtcclxuICAgICAgICAgICAgICAgICAgICBlcnJvck1lc3NhZ2U6ICdUaGUgdmFsdWUgbXVzdCBiZSB3aXRoaW4gYSAwLjEgYW5kIDUuMCByYW5nZSdcclxuICAgICAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICAgIClcclxuICAgICAgICAgICAgICAudHJhbnNmb3JtKCh2YWx1ZSkgPT5cclxuICAgICAgICAgICAgICAgICFbJ3VuZGVmaW5lZCcsICdudWxsJywgJyddLmluY2x1ZGVzKHZhbHVlKVxyXG4gICAgICAgICAgICAgICAgICA/IE51bWJlcih2YWx1ZSlcclxuICAgICAgICAgICAgICAgICAgOiBudWxsXHJcbiAgICAgICAgICAgICAgKSxcclxuICAgICAgICAgICAgei5udW1iZXIoKS5ndGUoMC4xKS5sdGUoNSlcclxuICAgICAgICAgIF0pXHJcbiAgICAgICAgICAubnVsbGFibGUoKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYGhlaWdodGAgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbCBzdHJpY3RlclxyXG4gICAqIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgYSBudWxsYWJsZSBgZGVmYXVsdEhlaWdodGBcclxuICAgKiB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gaGVpZ2h0XHJcbiAgICpcclxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IHN0cmljdENoZWNrIC0gRGV0ZXJtaW5lcyBpZiBzdHJpY3RlciB2YWxpZGF0aW9uIHNob3VsZFxyXG4gICAqIGJlIGFwcGxpZWQuXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9IEEgWm9kIHNjaGVtYSBvYmplY3QgZm9yIHZhbGlkYXRpbmcgdGhlIGBoZWlnaHRgXHJcbiAgICogb3B0aW9uLlxyXG4gICAqL1xyXG4gIGhlaWdodChzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHRoaXMuZGVmYXVsdEhlaWdodChzdHJpY3RDaGVjaykubnVsbGFibGUoKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYHdpZHRoYCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoIGFuIG9wdGlvbmFsIHN0cmljdGVyXHJcbiAgICogY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhlIHNhbWUgd29yayBhcyBhIG51bGxhYmxlIGBkZWZhdWx0V2lkdGhgXHJcbiAgICogdmFsaWRhdG9yLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIHdpZHRoXHJcbiAgICpcclxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IHN0cmljdENoZWNrIC0gRGV0ZXJtaW5lcyBpZiBzdHJpY3RlciB2YWxpZGF0aW9uIHNob3VsZFxyXG4gICAqIGJlIGFwcGxpZWQuXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9IEEgWm9kIHNjaGVtYSBvYmplY3QgZm9yIHZhbGlkYXRpbmcgdGhlIGB3aWR0aGBcclxuICAgKiBvcHRpb24uXHJcbiAgICovXHJcbiAgd2lkdGgoc3RyaWN0Q2hlY2spIHtcclxuICAgIHJldHVybiB0aGlzLmRlZmF1bHRXaWR0aChzdHJpY3RDaGVjaykubnVsbGFibGUoKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYHNjYWxlYCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoIGFuIG9wdGlvbmFsIHN0cmljdGVyXHJcbiAgICogY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhlIHNhbWUgd29yayBhcyBhIG51bGxhYmxlIGBkZWZhdWx0U2NhbGVgXHJcbiAgICogdmFsaWRhdG9yLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIHNjYWxlXHJcbiAgICpcclxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IHN0cmljdENoZWNrIC0gRGV0ZXJtaW5lcyBpZiBzdHJpY3RlciB2YWxpZGF0aW9uIHNob3VsZFxyXG4gICAqIGJlIGFwcGxpZWQuXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9IEEgWm9kIHNjaGVtYSBvYmplY3QgZm9yIHZhbGlkYXRpbmcgdGhlIGBzY2FsZWBcclxuICAgKiBvcHRpb24uXHJcbiAgICovXHJcbiAgc2NhbGUoc3RyaWN0Q2hlY2spIHtcclxuICAgIHJldHVybiB0aGlzLmRlZmF1bHRTY2FsZShzdHJpY3RDaGVjaykubnVsbGFibGUoKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYGdsb2JhbE9wdGlvbnNgIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhlIHNhbWUgd29yayBhcyB0aGUgYGFkZGl0aW9uYWxPcHRpb25zYFxyXG4gICAqIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiBnbG9iYWxPcHRpb25zXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9IEEgWm9kIHNjaGVtYSBvYmplY3QgZm9yIHZhbGlkYXRpbmdcclxuICAgKiB0aGUgYGdsb2JhbE9wdGlvbnNgIG9wdGlvbi5cclxuICAgKi9cclxuICBnbG9iYWxPcHRpb25zKCkge1xyXG4gICAgcmV0dXJuIHYuYWRkaXRpb25hbE9wdGlvbnMoKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYHRoZW1lT3B0aW9uc2AgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGUgc2FtZSB3b3JrIGFzIHRoZSBgYWRkaXRpb25hbE9wdGlvbnNgXHJcbiAgICogdmFsaWRhdG9yLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIHRoZW1lT3B0aW9uc1xyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nXHJcbiAgICogdGhlIGB0aGVtZU9wdGlvbnNgIG9wdGlvbi5cclxuICAgKi9cclxuICB0aGVtZU9wdGlvbnMoKSB7XHJcbiAgICByZXR1cm4gdi5hZGRpdGlvbmFsT3B0aW9ucygpO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgYmF0Y2hgIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGggYW4gb3B0aW9uYWwgc3RyaWN0ZXJcclxuICAgKiBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGUgc2FtZSB3b3JrIGFzIHRoZSBgc3RyaW5nYCB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gYmF0Y2hcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZyB0aGUgYGJhdGNoYFxyXG4gICAqIG9wdGlvbi5cclxuICAgKi9cclxuICBiYXRjaChzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHYuc3RyaW5nKHN0cmljdENoZWNrKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYHJhc3Rlcml6YXRpb25UaW1lb3V0YCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoXHJcbiAgICogYW4gb3B0aW9uYWwgc3RyaWN0ZXIgY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhlIHNhbWUgd29yayBhcyB0aGUgYG5vbk5lZ2F0aXZlTnVtYFxyXG4gICAqIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiByYXN0ZXJpemF0aW9uVGltZW91dFxyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nXHJcbiAgICogdGhlIGByYXN0ZXJpemF0aW9uVGltZW91dGAgb3B0aW9uLlxyXG4gICAqL1xyXG4gIHJhc3Rlcml6YXRpb25UaW1lb3V0KHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gdi5ub25OZWdhdGl2ZU51bShzdHJpY3RDaGVjayk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGBhbGxvd0NvZGVFeGVjdXRpb25gIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGhcclxuICAgKiBhbiBvcHRpb25hbCBzdHJpY3RlciBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGUgc2FtZSB3b3JrIGFzIHRoZSBgYm9vbGVhbmAgdmFsaWRhdG9yLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIGFsbG93Q29kZUV4ZWN1dGlvblxyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nXHJcbiAgICogdGhlIGBhbGxvd0NvZGVFeGVjdXRpb25gIG9wdGlvbi5cclxuICAgKi9cclxuICBhbGxvd0NvZGVFeGVjdXRpb24oc3RyaWN0Q2hlY2spIHtcclxuICAgIHJldHVybiB2LmJvb2xlYW4oc3RyaWN0Q2hlY2spO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgYWxsb3dGaWxlUmVzb3VyY2VzYCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoXHJcbiAgICogYW4gb3B0aW9uYWwgc3RyaWN0ZXIgY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhlIHNhbWUgd29yayBhcyB0aGUgYGJvb2xlYW5gIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiBhbGxvd0ZpbGVSZXNvdXJjZXNcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZ1xyXG4gICAqIHRoZSBgYWxsb3dGaWxlUmVzb3VyY2VzYCBvcHRpb24uXHJcbiAgICovXHJcbiAgYWxsb3dGaWxlUmVzb3VyY2VzKHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gdi5ib29sZWFuKHN0cmljdENoZWNrKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYGN1c3RvbUNvZGVgIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGggYW4gb3B0aW9uYWxcclxuICAgKiBzdHJpY3RlciBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGUgc2FtZSB3b3JrIGFzIHRoZSBgc3RyaW5nYCB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gY3VzdG9tQ29kZVxyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nIHRoZSBgY3VzdG9tQ29kZWBcclxuICAgKiBvcHRpb24uXHJcbiAgICovXHJcbiAgY3VzdG9tQ29kZShzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHYuc3RyaW5nKHN0cmljdENoZWNrKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYGNhbGxiYWNrYCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoIGFuIG9wdGlvbmFsXHJcbiAgICogc3RyaWN0ZXIgY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhlIHNhbWUgd29yayBhcyB0aGUgYHN0cmluZ2AgdmFsaWRhdG9yLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIGNhbGxiYWNrXHJcbiAgICpcclxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IHN0cmljdENoZWNrIC0gRGV0ZXJtaW5lcyBpZiBzdHJpY3RlciB2YWxpZGF0aW9uIHNob3VsZFxyXG4gICAqIGJlIGFwcGxpZWQuXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9IEEgWm9kIHNjaGVtYSBvYmplY3QgZm9yIHZhbGlkYXRpbmcgdGhlIGBjYWxsYmFja2BcclxuICAgKiBvcHRpb24uXHJcbiAgICovXHJcbiAgY2FsbGJhY2soc3RyaWN0Q2hlY2spIHtcclxuICAgIHJldHVybiB2LnN0cmluZyhzdHJpY3RDaGVjayk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGByZXNvdXJjZXNgIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGggYW4gb3B0aW9uYWxcclxuICAgKiBzdHJpY3RlciBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGF0OlxyXG4gICAqXHJcbiAgICogLSBXaGVuIGBzdHJpY3RDaGVja2AgaXMgdHJ1ZSwgdGhlIHNjaGVtYSB3aWxsIGFjY2VwdCBhIHBhcnRpYWwgb2JqZWN0XHJcbiAgICogd2l0aCBhbGxvd2VkIHByb3BlcnRpZXMgYGpzYCwgYGNzc2AsIGFuZCBgZmlsZXNgIHdoZXJlIGVhY2ggb2YgdGhlIGFsbG93ZWRcclxuICAgKiBwcm9wZXJ0aWVzIGNhbiBiZSBudWxsLCBzdHJpbmdpZmllZCB2ZXJzaW9uIG9mIHRoZSBvYmplY3QsIHN0cmluZyB0aGF0IGVuZHNcclxuICAgKiB3aXRoIHRoZSAnLmpzb24nLCBhbmQgbnVsbC5cclxuICAgKlxyXG4gICAqIC0gV2hlbiBgc3RyaWN0Q2hlY2tgIGlzIGZhbHNlLCB0aGUgc2NoZW1hIHdpbGwgYWNjZXB0IGEgc3RyaW5naWZpZWQgdmVyc2lvblxyXG4gICAqIG9mIGEgcGFydGlhbCBvYmplY3Qgd2l0aCBhbGxvd2VkIHByb3BlcnRpZXMgYGpzYCwgYGNzc2AsIGFuZCBgZmlsZXNgIHdoZXJlXHJcbiAgICogZWFjaCBvZiB0aGUgYWxsb3dlZCBwcm9wZXJ0aWVzIGNhbiBiZSBudWxsLCBzdHJpbmcgdGhhdCBlbmRzIHdpdGggdGhlXHJcbiAgICogJy5qc29uJywgYW5kIHdpbGwgYmUgbnVsbCBpZiB0aGUgcHJvdmlkZWQgdmFsdWUgaXMgJ3VuZGVmaW5lZCcsICdudWxsJ1xyXG4gICAqIG9yICcnLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIHJlc291cmNlc1xyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nIHRoZSBgcmVzb3VyY2VzYFxyXG4gICAqIG9wdGlvbi5cclxuICAgKi9cclxuICByZXNvdXJjZXMoc3RyaWN0Q2hlY2spIHtcclxuICAgIGNvbnN0IG9iamVjdFNjaGVtYSA9IHpcclxuICAgICAgLm9iamVjdCh7XHJcbiAgICAgICAganM6IHYuc3RyaW5nKGZhbHNlKSxcclxuICAgICAgICBjc3M6IHYuc3RyaW5nKGZhbHNlKSxcclxuICAgICAgICBmaWxlczogdlxyXG4gICAgICAgICAgLnN0cmluZ0FycmF5KFxyXG4gICAgICAgICAgICAodmFsdWUpID0+ICFbJ3VuZGVmaW5lZCcsICdudWxsJywgJyddLmluY2x1ZGVzKHZhbHVlKSxcclxuICAgICAgICAgICAgJywnLFxyXG4gICAgICAgICAgICB0cnVlXHJcbiAgICAgICAgICApXHJcbiAgICAgICAgICAubnVsbGFibGUoKVxyXG4gICAgICB9KVxyXG4gICAgICAucGFydGlhbCgpO1xyXG5cclxuICAgIGNvbnN0IHN0cmluZ1NjaGVtYTEgPSB6XHJcbiAgICAgIC5zdHJpbmcoKVxyXG4gICAgICAudHJpbSgpXHJcbiAgICAgIC5yZWZpbmUoXHJcbiAgICAgICAgKHZhbHVlKSA9PlxyXG4gICAgICAgICAgKHZhbHVlLnN0YXJ0c1dpdGgoJ3snKSAmJiB2YWx1ZS5lbmRzV2l0aCgnfScpKSB8fFxyXG4gICAgICAgICAgKHZhbHVlLmxlbmd0aCA+PSA2ICYmIHZhbHVlLmVuZHNXaXRoKCcuanNvbicpKSxcclxuICAgICAgICB7XHJcbiAgICAgICAgICBwYXJhbXM6IHtcclxuICAgICAgICAgICAgZXJyb3JNZXNzYWdlOlxyXG4gICAgICAgICAgICAgIFwiVGhlIHZhbHVlIG11c3QgYmUgYSBzdHJpbmcgdGhhdCBzdGFydHMgd2l0aCAneycgYW5kIGVuZHMgd2l0aCAnfVwiXHJcbiAgICAgICAgICB9XHJcbiAgICAgICAgfVxyXG4gICAgICApO1xyXG5cclxuICAgIGNvbnN0IHN0cmluZ1NjaGVtYTIgPSB6XHJcbiAgICAgIC5zdHJpbmcoKVxyXG4gICAgICAudHJpbSgpXHJcbiAgICAgIC5yZWZpbmUoXHJcbiAgICAgICAgKHZhbHVlKSA9PlxyXG4gICAgICAgICAgKHZhbHVlLnN0YXJ0c1dpdGgoJ3snKSAmJiB2YWx1ZS5lbmRzV2l0aCgnfScpKSB8fFxyXG4gICAgICAgICAgKHZhbHVlLmxlbmd0aCA+PSA2ICYmIHZhbHVlLmVuZHNXaXRoKCcuanNvbicpKSB8fFxyXG4gICAgICAgICAgWyd1bmRlZmluZWQnLCAnbnVsbCcsICcnXS5pbmNsdWRlcyh2YWx1ZSksXHJcbiAgICAgICAge1xyXG4gICAgICAgICAgcGFyYW1zOiB7XHJcbiAgICAgICAgICAgIGVycm9yTWVzc2FnZTogJ1RoZSB2YWx1ZSBtdXN0IGJlIGEgc3RyaW5nIHRoYXQgZW5kcyB3aXRoIC5qc29uJ1xyXG4gICAgICAgICAgfVxyXG4gICAgICAgIH1cclxuICAgICAgKVxyXG4gICAgICAudHJhbnNmb3JtKCh2YWx1ZSkgPT5cclxuICAgICAgICAhWyd1bmRlZmluZWQnLCAnbnVsbCcsICcnXS5pbmNsdWRlcyh2YWx1ZSkgPyB2YWx1ZSA6IG51bGxcclxuICAgICAgKTtcclxuXHJcbiAgICByZXR1cm4gc3RyaWN0Q2hlY2tcclxuICAgICAgPyB6LnVuaW9uKFtvYmplY3RTY2hlbWEsIHN0cmluZ1NjaGVtYTFdKS5udWxsYWJsZSgpXHJcbiAgICAgIDogei51bmlvbihbb2JqZWN0U2NoZW1hLCBzdHJpbmdTY2hlbWEyXSkubnVsbGFibGUoKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYGxvYWRDb25maWdgIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGggYW4gb3B0aW9uYWxcclxuICAgKiBzdHJpY3RlciBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGUgc2FtZSB3b3JrIGFzIHRoZSBgc3RyaW5nYCB2YWxpZGF0b3IuXHJcbiAgICogQWRkaXRpb25hbGx5LCBpdCBtdXN0IGJlIGEgc3RyaW5nIHRoYXQgZW5kcyB3aXRoICcuanNvbicuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gbG9hZENvbmZpZ1xyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nIHRoZSBgbG9hZENvbmZpZ2BcclxuICAgKiBvcHRpb24uXHJcbiAgICovXHJcbiAgbG9hZENvbmZpZyhzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHZcclxuICAgICAgLnN0cmluZyhzdHJpY3RDaGVjaylcclxuICAgICAgLnJlZmluZShcclxuICAgICAgICAodmFsdWUpID0+XHJcbiAgICAgICAgICB2YWx1ZSA9PT0gbnVsbCB8fCAodmFsdWUubGVuZ3RoID49IDYgJiYgdmFsdWUuZW5kc1dpdGgoJy5qc29uJykpLFxyXG4gICAgICAgIHtcclxuICAgICAgICAgIHBhcmFtczoge1xyXG4gICAgICAgICAgICBlcnJvck1lc3NhZ2U6ICdUaGUgdmFsdWUgbXVzdCBiZSBhIHN0cmluZyB0aGF0IGVuZHMgd2l0aCAuanNvbidcclxuICAgICAgICAgIH1cclxuICAgICAgICB9XHJcbiAgICAgICk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGBjcmVhdGVDb25maWdgIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGggYW4gb3B0aW9uYWxcclxuICAgKiBzdHJpY3RlciBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGUgc2FtZSB3b3JrIGFzIHRoZSBgbG9hZENvbmZpZ2AgdmFsaWRhdG9yLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIGNyZWF0ZUNvbmZpZ1xyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nXHJcbiAgICogdGhlIGBjcmVhdGVDb25maWdgIG9wdGlvbi5cclxuICAgKi9cclxuICBjcmVhdGVDb25maWcoc3RyaWN0Q2hlY2spIHtcclxuICAgIHJldHVybiB0aGlzLmxvYWRDb25maWcoc3RyaWN0Q2hlY2spO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgZW5hYmxlU2VydmVyYCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoIGFuIG9wdGlvbmFsXHJcbiAgICogc3RyaWN0ZXIgY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhlIHNhbWUgd29yayBhcyB0aGUgYGJvb2xlYW5gIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiBlbmFibGVTZXJ2ZXJcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZ1xyXG4gICAqIHRoZSBgZW5hYmxlU2VydmVyYCBvcHRpb24uXHJcbiAgICovXHJcbiAgZW5hYmxlU2VydmVyKHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gdi5ib29sZWFuKHN0cmljdENoZWNrKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYGhvc3RgIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGggYW4gb3B0aW9uYWwgc3RyaWN0ZXJcclxuICAgKiBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGUgc2FtZSB3b3JrIGFzIHRoZSBgc3RyaW5nYCB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gaG9zdFxyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nIHRoZSBgaG9zdGBcclxuICAgKiBvcHRpb24uXHJcbiAgICovXHJcbiAgaG9zdChzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHYuc3RyaW5nKHN0cmljdENoZWNrKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYHBvcnRgIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGggYW4gb3B0aW9uYWwgc3RyaWN0ZXJcclxuICAgKiBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGUgc2FtZSB3b3JrIGFzIHRoZSBgbm9uTmVnYXRpdmVOdW1gXHJcbiAgICogdmFsaWRhdG9yLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIHBvcnRcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZyB0aGUgYHBvcnRgXHJcbiAgICogb3B0aW9uLlxyXG4gICAqL1xyXG4gIHBvcnQoc3RyaWN0Q2hlY2spIHtcclxuICAgIHJldHVybiB2Lm5vbk5lZ2F0aXZlTnVtKHN0cmljdENoZWNrKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYHVwbG9hZExpbWl0YCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoIGFuIG9wdGlvbmFsXHJcbiAgICogc3RyaWN0ZXIgY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhlIHNhbWUgd29yayBhcyB0aGUgYHBvc2l0aXZlTnVtYCB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gdXBsb2FkTGltaXRcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZyB0aGUgYHVwbG9hZExpbWl0YFxyXG4gICAqIG9wdGlvbi5cclxuICAgKi9cclxuICB1cGxvYWRMaW1pdChzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHYucG9zaXRpdmVOdW0oc3RyaWN0Q2hlY2spO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgc2VydmVyQmVuY2htYXJraW5nYCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoXHJcbiAgICogYW4gb3B0aW9uYWwgc3RyaWN0ZXIgY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhlIHNhbWUgd29yayBhcyB0aGUgYGJvb2xlYW5gIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiBzZXJ2ZXJCZW5jaG1hcmtpbmdcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZ1xyXG4gICAqIHRoZSBgc2VydmVyQmVuY2htYXJraW5nYCBvcHRpb24uXHJcbiAgICovXHJcbiAgc2VydmVyQmVuY2htYXJraW5nKHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gdi5ib29sZWFuKHN0cmljdENoZWNrKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYHByb3h5SG9zdGAgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbFxyXG4gICAqIHN0cmljdGVyIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgdGhlIGBzdHJpbmdgIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiBwcm94eUhvc3RcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZyB0aGUgYHByb3h5SG9zdGBcclxuICAgKiBvcHRpb24uXHJcbiAgICovXHJcbiAgcHJveHlIb3N0KHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gdi5zdHJpbmcoc3RyaWN0Q2hlY2spO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgcHJveHlQb3J0YCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoIGFuIG9wdGlvbmFsXHJcbiAgICogc3RyaWN0ZXIgY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhlIHNhbWUgd29yayBhcyBhIG51bGxhYmxlIGBub25OZWdhdGl2ZU51bWBcclxuICAgKiB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gcHJveHlQb3J0XHJcbiAgICpcclxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IHN0cmljdENoZWNrIC0gRGV0ZXJtaW5lcyBpZiBzdHJpY3RlciB2YWxpZGF0aW9uIHNob3VsZFxyXG4gICAqIGJlIGFwcGxpZWQuXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9IEEgWm9kIHNjaGVtYSBvYmplY3QgZm9yIHZhbGlkYXRpbmcgdGhlIGBwcm94eVBvcnRgXHJcbiAgICogb3B0aW9uLlxyXG4gICAqL1xyXG4gIHByb3h5UG9ydChzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHYubm9uTmVnYXRpdmVOdW0oc3RyaWN0Q2hlY2spLm51bGxhYmxlKCk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGBwcm94eVRpbWVvdXRgIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGggYW4gb3B0aW9uYWxcclxuICAgKiBzdHJpY3RlciBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGUgc2FtZSB3b3JrIGFzIHRoZSBgbm9uTmVnYXRpdmVOdW1gXHJcbiAgICogdmFsaWRhdG9yLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIHByb3h5VGltZW91dFxyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nXHJcbiAgICogdGhlIGBwcm94eVRpbWVvdXRgIG9wdGlvbi5cclxuICAgKi9cclxuICBwcm94eVRpbWVvdXQoc3RyaWN0Q2hlY2spIHtcclxuICAgIHJldHVybiB2Lm5vbk5lZ2F0aXZlTnVtKHN0cmljdENoZWNrKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYGVuYWJsZVJhdGVMaW1pdGluZ2AgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aFxyXG4gICAqIGFuIG9wdGlvbmFsIHN0cmljdGVyIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgdGhlIGBib29sZWFuYCB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gZW5hYmxlUmF0ZUxpbWl0aW5nXHJcbiAgICpcclxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IHN0cmljdENoZWNrIC0gRGV0ZXJtaW5lcyBpZiBzdHJpY3RlciB2YWxpZGF0aW9uIHNob3VsZFxyXG4gICAqIGJlIGFwcGxpZWQuXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9IEEgWm9kIHNjaGVtYSBvYmplY3QgZm9yIHZhbGlkYXRpbmdcclxuICAgKiB0aGUgYGVuYWJsZVJhdGVMaW1pdGluZ2Agb3B0aW9uLlxyXG4gICAqL1xyXG4gIGVuYWJsZVJhdGVMaW1pdGluZyhzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHYuYm9vbGVhbihzdHJpY3RDaGVjayk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGBtYXhSZXF1ZXN0c2AgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbFxyXG4gICAqIHN0cmljdGVyIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgdGhlIGBub25OZWdhdGl2ZU51bWBcclxuICAgKiB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gbWF4UmVxdWVzdHNcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZyB0aGUgYG1heFJlcXVlc3RzYFxyXG4gICAqIG9wdGlvbi5cclxuICAgKi9cclxuICBtYXhSZXF1ZXN0cyhzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHYubm9uTmVnYXRpdmVOdW0oc3RyaWN0Q2hlY2spO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgd2luZG93YCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoIGFuIG9wdGlvbmFsIHN0cmljdGVyXHJcbiAgICogY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhlIHNhbWUgd29yayBhcyB0aGUgYG5vbk5lZ2F0aXZlTnVtYFxyXG4gICAqIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiB3aW5kb3dcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZyB0aGUgYHdpbmRvd2BcclxuICAgKiBvcHRpb24uXHJcbiAgICovXHJcbiAgd2luZG93KHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gdi5ub25OZWdhdGl2ZU51bShzdHJpY3RDaGVjayk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGBkZWxheWAgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbCBzdHJpY3RlclxyXG4gICAqIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgdGhlIGBub25OZWdhdGl2ZU51bWBcclxuICAgKiB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gZGVsYXlcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZyB0aGUgYGRlbGF5YFxyXG4gICAqIG9wdGlvbi5cclxuICAgKi9cclxuICBkZWxheShzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHYubm9uTmVnYXRpdmVOdW0oc3RyaWN0Q2hlY2spO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgdHJ1c3RQcm94eWAgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbFxyXG4gICAqIHN0cmljdGVyIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgdGhlIGBib29sZWFuYCB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gdHJ1c3RQcm94eVxyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nIHRoZSBgdHJ1c3RQcm94eWBcclxuICAgKiBvcHRpb24uXHJcbiAgICovXHJcbiAgdHJ1c3RQcm94eShzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHYuYm9vbGVhbihzdHJpY3RDaGVjayk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGBza2lwS2V5YCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoIGFuIG9wdGlvbmFsIHN0cmljdGVyXHJcbiAgICogY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhlIHNhbWUgd29yayBhcyB0aGUgYHN0cmluZ2AgdmFsaWRhdG9yLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIHNraXBLZXlcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZyB0aGUgYHNraXBLZXlgXHJcbiAgICogb3B0aW9uLlxyXG4gICAqL1xyXG4gIHNraXBLZXkoc3RyaWN0Q2hlY2spIHtcclxuICAgIHJldHVybiB2LnN0cmluZyhzdHJpY3RDaGVjayk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGBza2lwVG9rZW5gIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGggYW4gb3B0aW9uYWxcclxuICAgKiBzdHJpY3RlciBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGUgc2FtZSB3b3JrIGFzIHRoZSBgc3RyaW5nYCB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gc2tpcFRva2VuXHJcbiAgICpcclxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IHN0cmljdENoZWNrIC0gRGV0ZXJtaW5lcyBpZiBzdHJpY3RlciB2YWxpZGF0aW9uIHNob3VsZFxyXG4gICAqIGJlIGFwcGxpZWQuXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9IEEgWm9kIHNjaGVtYSBvYmplY3QgZm9yIHZhbGlkYXRpbmcgdGhlIGBza2lwVG9rZW5gXHJcbiAgICogb3B0aW9uLlxyXG4gICAqL1xyXG4gIHNraXBUb2tlbihzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHYuc3RyaW5nKHN0cmljdENoZWNrKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYGVuYWJsZVNzbGAgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbFxyXG4gICAqIHN0cmljdGVyIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgdGhlIGBib29sZWFuYCB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gZW5hYmxlU3NsXHJcbiAgICpcclxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IHN0cmljdENoZWNrIC0gRGV0ZXJtaW5lcyBpZiBzdHJpY3RlciB2YWxpZGF0aW9uIHNob3VsZFxyXG4gICAqIGJlIGFwcGxpZWQuXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9IEEgWm9kIHNjaGVtYSBvYmplY3QgZm9yIHZhbGlkYXRpbmcgdGhlIGBlbmFibGVTc2xgXHJcbiAgICogb3B0aW9uLlxyXG4gICAqL1xyXG4gIGVuYWJsZVNzbChzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHYuYm9vbGVhbihzdHJpY3RDaGVjayk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGBzc2xGb3JjZWAgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbFxyXG4gICAqIHN0cmljdGVyIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgdGhlIGBib29sZWFuYCB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gc3NsRm9yY2VcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZyB0aGUgYHNzbEZvcmNlYFxyXG4gICAqIG9wdGlvbi5cclxuICAgKi9cclxuICBzc2xGb3JjZShzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHYuYm9vbGVhbihzdHJpY3RDaGVjayk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGBzc2xQb3J0YCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoIGFuIG9wdGlvbmFsIHN0cmljdGVyXHJcbiAgICogY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhlIHNhbWUgd29yayBhcyB0aGUgYG5vbk5lZ2F0aXZlTnVtYFxyXG4gICAqIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiBzc2xQb3J0XHJcbiAgICpcclxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IHN0cmljdENoZWNrIC0gRGV0ZXJtaW5lcyBpZiBzdHJpY3RlciB2YWxpZGF0aW9uIHNob3VsZFxyXG4gICAqIGJlIGFwcGxpZWQuXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9IEEgWm9kIHNjaGVtYSBvYmplY3QgZm9yIHZhbGlkYXRpbmcgdGhlIGBzc2xQb3J0YFxyXG4gICAqIG9wdGlvbi5cclxuICAgKi9cclxuICBzc2xQb3J0KHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gdi5ub25OZWdhdGl2ZU51bShzdHJpY3RDaGVjayk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGBzc2xDZXJ0UGF0aGAgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbFxyXG4gICAqIHN0cmljdGVyIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgdGhlIGBzdHJpbmdgIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiBzc2xDZXJ0UGF0aFxyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nIHRoZSBgc3NsQ2VydFBhdGhgXHJcbiAgICogb3B0aW9uLlxyXG4gICAqL1xyXG4gIHNzbENlcnRQYXRoKHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gdi5zdHJpbmcoc3RyaWN0Q2hlY2spO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgbWluV29ya2Vyc2AgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbFxyXG4gICAqIHN0cmljdGVyIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgdGhlIGBwb3NpdGl2ZU51bWAgdmFsaWRhdG9yLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIG1pbldvcmtlcnNcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZyB0aGUgYG1pbldvcmtlcnNgXHJcbiAgICogb3B0aW9uLlxyXG4gICAqL1xyXG4gIG1pbldvcmtlcnMoc3RyaWN0Q2hlY2spIHtcclxuICAgIHJldHVybiB2LnBvc2l0aXZlTnVtKHN0cmljdENoZWNrKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYG1heFdvcmtlcnNgIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGggYW4gb3B0aW9uYWxcclxuICAgKiBzdHJpY3RlciBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGUgc2FtZSB3b3JrIGFzIHRoZSBgcG9zaXRpdmVOdW1gIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiBtYXhXb3JrZXJzXHJcbiAgICpcclxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IHN0cmljdENoZWNrIC0gRGV0ZXJtaW5lcyBpZiBzdHJpY3RlciB2YWxpZGF0aW9uIHNob3VsZFxyXG4gICAqIGJlIGFwcGxpZWQuXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9IEEgWm9kIHNjaGVtYSBvYmplY3QgZm9yIHZhbGlkYXRpbmcgdGhlIGBtYXhXb3JrZXJzYFxyXG4gICAqIG9wdGlvbi5cclxuICAgKi9cclxuICBtYXhXb3JrZXJzKHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gdi5wb3NpdGl2ZU51bShzdHJpY3RDaGVjayk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGB3b3JrTGltaXRgIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGggYW4gb3B0aW9uYWxcclxuICAgKiBzdHJpY3RlciBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGUgc2FtZSB3b3JrIGFzIHRoZSBgcG9zaXRpdmVOdW1gIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiB3b3JrTGltaXRcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZyB0aGUgYHdvcmtMaW1pdGBcclxuICAgKiBvcHRpb24uXHJcbiAgICovXHJcbiAgd29ya0xpbWl0KHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gdi5wb3NpdGl2ZU51bShzdHJpY3RDaGVjayk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGBhY3F1aXJlVGltZW91dGAgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbFxyXG4gICAqIHN0cmljdGVyIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgdGhlIGBub25OZWdhdGl2ZU51bWBcclxuICAgKiB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gYWNxdWlyZVRpbWVvdXRcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZ1xyXG4gICAqIHRoZSBgYWNxdWlyZVRpbWVvdXRgIG9wdGlvbi5cclxuICAgKi9cclxuICBhY3F1aXJlVGltZW91dChzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHYubm9uTmVnYXRpdmVOdW0oc3RyaWN0Q2hlY2spO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgY3JlYXRlVGltZW91dGAgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbFxyXG4gICAqIHN0cmljdGVyIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgdGhlIGBub25OZWdhdGl2ZU51bWBcclxuICAgKiB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gY3JlYXRlVGltZW91dFxyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nXHJcbiAgICogdGhlIGBjcmVhdGVUaW1lb3V0YCBvcHRpb24uXHJcbiAgICovXHJcbiAgY3JlYXRlVGltZW91dChzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHYubm9uTmVnYXRpdmVOdW0oc3RyaWN0Q2hlY2spO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgZGVzdHJveVRpbWVvdXRgIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGggYW4gb3B0aW9uYWxcclxuICAgKiBzdHJpY3RlciBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGUgc2FtZSB3b3JrIGFzIHRoZSBgbm9uTmVnYXRpdmVOdW1gXHJcbiAgICogdmFsaWRhdG9yLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIGRlc3Ryb3lUaW1lb3V0XHJcbiAgICpcclxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IHN0cmljdENoZWNrIC0gRGV0ZXJtaW5lcyBpZiBzdHJpY3RlciB2YWxpZGF0aW9uIHNob3VsZFxyXG4gICAqIGJlIGFwcGxpZWQuXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9IEEgWm9kIHNjaGVtYSBvYmplY3QgZm9yIHZhbGlkYXRpbmdcclxuICAgKiB0aGUgYGRlc3Ryb3lUaW1lb3V0YCBvcHRpb24uXHJcbiAgICovXHJcbiAgZGVzdHJveVRpbWVvdXQoc3RyaWN0Q2hlY2spIHtcclxuICAgIHJldHVybiB2Lm5vbk5lZ2F0aXZlTnVtKHN0cmljdENoZWNrKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYGlkbGVUaW1lb3V0YCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoIGFuIG9wdGlvbmFsXHJcbiAgICogc3RyaWN0ZXIgY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhlIHNhbWUgd29yayBhcyB0aGUgYG5vbk5lZ2F0aXZlTnVtYFxyXG4gICAqIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiBpZGxlVGltZW91dFxyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nXHJcbiAgICogdGhlIGBpZGxlVGltZW91dGAgb3B0aW9uLlxyXG4gICAqL1xyXG4gIGlkbGVUaW1lb3V0KHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gdi5ub25OZWdhdGl2ZU51bShzdHJpY3RDaGVjayk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGBjcmVhdGVSZXRyeUludGVydmFsYCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoXHJcbiAgICogYW4gb3B0aW9uYWwgc3RyaWN0ZXIgY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhlIHNhbWUgd29yayBhcyB0aGUgYG5vbk5lZ2F0aXZlTnVtYFxyXG4gICAqIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiBjcmVhdGVSZXRyeUludGVydmFsXHJcbiAgICpcclxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IHN0cmljdENoZWNrIC0gRGV0ZXJtaW5lcyBpZiBzdHJpY3RlciB2YWxpZGF0aW9uIHNob3VsZFxyXG4gICAqIGJlIGFwcGxpZWQuXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9IEEgWm9kIHNjaGVtYSBvYmplY3QgZm9yIHZhbGlkYXRpbmdcclxuICAgKiB0aGUgYGNyZWF0ZVJldHJ5SW50ZXJ2YWxgIG9wdGlvbi5cclxuICAgKi9cclxuICBjcmVhdGVSZXRyeUludGVydmFsKHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gdi5ub25OZWdhdGl2ZU51bShzdHJpY3RDaGVjayk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGByZWFwZXJJbnRlcnZhbGAgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbFxyXG4gICAqIHN0cmljdGVyIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgdGhlIGBub25OZWdhdGl2ZU51bWBcclxuICAgKiB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gcmVhcGVySW50ZXJ2YWxcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZ1xyXG4gICAqIHRoZSBgcmVhcGVySW50ZXJ2YWxgIG9wdGlvbi5cclxuICAgKi9cclxuICByZWFwZXJJbnRlcnZhbChzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHYubm9uTmVnYXRpdmVOdW0oc3RyaWN0Q2hlY2spO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgcG9vbEJlbmNobWFya2luZ2AgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbFxyXG4gICAqIHN0cmljdGVyIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgdGhlIGBib29sZWFuYCB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gcG9vbEJlbmNobWFya2luZ1xyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nXHJcbiAgICogdGhlIGBwb29sQmVuY2htYXJraW5nYCBvcHRpb24uXHJcbiAgICovXHJcbiAgcG9vbEJlbmNobWFya2luZyhzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHYuYm9vbGVhbihzdHJpY3RDaGVjayk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGByZXNvdXJjZXNJbnRlcnZhbGAgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aFxyXG4gICAqIGFuIG9wdGlvbmFsIHN0cmljdGVyIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgdGhlIGBub25OZWdhdGl2ZU51bWBcclxuICAgKiB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gcmVzb3VyY2VzSW50ZXJ2YWxcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZ1xyXG4gICAqIHRoZSBgcmVzb3VyY2VzSW50ZXJ2YWxgIG9wdGlvbi5cclxuICAgKi9cclxuICByZXNvdXJjZXNJbnRlcnZhbChzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHYubm9uTmVnYXRpdmVOdW0oc3RyaWN0Q2hlY2spO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgbG9nTGV2ZWxgIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGggYW4gb3B0aW9uYWxcclxuICAgKiBzdHJpY3RlciBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGF0OlxyXG4gICAqXHJcbiAgICogLSBXaGVuIGBzdHJpY3RDaGVja2AgaXMgdHJ1ZSwgdGhlIHNjaGVtYSB3aWxsIGFjY2VwdCBpbnRlZ2VyIG51bWJlciB2YWx1ZXNcclxuICAgKiB0aGF0IGFyZSBiZXR3ZWVuIDAgYW5kIDUgKGluY2x1c2l2ZSkuXHJcbiAgICpcclxuICAgKiAtIFdoZW4gYHN0cmljdENoZWNrYCBpcyBmYWxzZSwgdGhlIHNjaGVtYSB3aWxsIGFjY2VwdCBpbnRlZ2VyIG51bWJlciB2YWx1ZXNcclxuICAgKiBhbmQgc3RyaW5naWZpZWQgaW50ZWdlciBudW1iZXIgdmFsdWVzIHRoYXQgYXJlIGJldHdlZW4gMSBhbmQgNSAoaW5jbHVzaXZlKSxcclxuICAgKiBudWxsLCAndW5kZWZpbmVkJywgJ251bGwnLCBhbmQgJycgd2hpY2ggd2lsbCBiZSB0cmFuc2Zvcm1lZCB0byBudWxsLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIGxvZ0xldmVsXHJcbiAgICpcclxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IHN0cmljdENoZWNrIC0gRGV0ZXJtaW5lcyBpZiBzdHJpY3RlciB2YWxpZGF0aW9uIHNob3VsZFxyXG4gICAqIGJlIGFwcGxpZWQuXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9IEEgWm9kIHNjaGVtYSBvYmplY3QgZm9yIHZhbGlkYXRpbmcgdGhlIGBsb2dMZXZlbGBcclxuICAgKiBvcHRpb24uXHJcbiAgICovXHJcbiAgbG9nTGV2ZWwoc3RyaWN0Q2hlY2spIHtcclxuICAgIHJldHVybiBzdHJpY3RDaGVja1xyXG4gICAgICA/IHoubnVtYmVyKCkuaW50KCkuZ3RlKDApLmx0ZSg1KVxyXG4gICAgICA6IHpcclxuICAgICAgICAgIC51bmlvbihbXHJcbiAgICAgICAgICAgIHpcclxuICAgICAgICAgICAgICAuc3RyaW5nKClcclxuICAgICAgICAgICAgICAudHJpbSgpXHJcbiAgICAgICAgICAgICAgLnJlZmluZShcclxuICAgICAgICAgICAgICAgICh2YWx1ZSkgPT5cclxuICAgICAgICAgICAgICAgICAgKCFpc05hTihOdW1iZXIodmFsdWUpKSAmJlxyXG4gICAgICAgICAgICAgICAgICAgIHZhbHVlICE9PSB0cnVlICYmXHJcbiAgICAgICAgICAgICAgICAgICAgIXZhbHVlLnN0YXJ0c1dpdGgoJ1snKSAmJlxyXG4gICAgICAgICAgICAgICAgICAgIE51bWJlci5pc0ludGVnZXIoTnVtYmVyKHZhbHVlKSkgJiZcclxuICAgICAgICAgICAgICAgICAgICBOdW1iZXIodmFsdWUpID49IDAgJiZcclxuICAgICAgICAgICAgICAgICAgICBOdW1iZXIodmFsdWUpIDw9IDUpIHx8XHJcbiAgICAgICAgICAgICAgICAgIFsndW5kZWZpbmVkJywgJ251bGwnLCAnJ10uaW5jbHVkZXModmFsdWUpLFxyXG4gICAgICAgICAgICAgICAge1xyXG4gICAgICAgICAgICAgICAgICBwYXJhbXM6IHtcclxuICAgICAgICAgICAgICAgICAgICBlcnJvck1lc3NhZ2U6ICdUaGUgdmFsdWUgbXVzdCBiZSB3aXRoaW4gYSAwIGFuZCA1IHJhbmdlJ1xyXG4gICAgICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgICAgKVxyXG4gICAgICAgICAgICAgIC50cmFuc2Zvcm0oKHZhbHVlKSA9PlxyXG4gICAgICAgICAgICAgICAgIVsndW5kZWZpbmVkJywgJ251bGwnLCAnJ10uaW5jbHVkZXModmFsdWUpXHJcbiAgICAgICAgICAgICAgICAgID8gTnVtYmVyKHZhbHVlKVxyXG4gICAgICAgICAgICAgICAgICA6IG51bGxcclxuICAgICAgICAgICAgICApLFxyXG4gICAgICAgICAgICB6Lm51bWJlcigpLmludCgpLmd0ZSgwKS5sdGUoNSlcclxuICAgICAgICAgIF0pXHJcbiAgICAgICAgICAubnVsbGFibGUoKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYGxvZ0ZpbGVgIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGggYW4gb3B0aW9uYWwgc3RyaWN0ZXJcclxuICAgKiBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGUgc2FtZSB3b3JrIGFzIHRoZSBgc3RyaW5nYCB2YWxpZGF0b3IuXHJcbiAgICogQWRkaXRpb25hbGx5LCBpdCBtdXN0IGJlIGEgc3RyaW5nIHRoYXQgZW5kcyB3aXRoICcubG9nJy5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiBsb2dGaWxlXHJcbiAgICpcclxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IHN0cmljdENoZWNrIC0gRGV0ZXJtaW5lcyBpZiBzdHJpY3RlciB2YWxpZGF0aW9uIHNob3VsZFxyXG4gICAqIGJlIGFwcGxpZWQuXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9IEEgWm9kIHNjaGVtYSBvYmplY3QgZm9yIHZhbGlkYXRpbmcgdGhlIGBsb2dGaWxlYFxyXG4gICAqIG9wdGlvbi5cclxuICAgKi9cclxuICBsb2dGaWxlKHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gdlxyXG4gICAgICAuc3RyaW5nKHN0cmljdENoZWNrKVxyXG4gICAgICAucmVmaW5lKFxyXG4gICAgICAgICh2YWx1ZSkgPT5cclxuICAgICAgICAgIHZhbHVlID09PSBudWxsIHx8ICh2YWx1ZS5sZW5ndGggPj0gNSAmJiB2YWx1ZS5lbmRzV2l0aCgnLmxvZycpKSxcclxuICAgICAgICB7XHJcbiAgICAgICAgICBwYXJhbXM6IHtcclxuICAgICAgICAgICAgZXJyb3JNZXNzYWdlOiAnVGhlIHZhbHVlIG11c3QgYmUgYSBzdHJpbmcgdGhhdCBlbmRzIHdpdGggLmxvZydcclxuICAgICAgICAgIH1cclxuICAgICAgICB9XHJcbiAgICAgICk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGBsb2dEZXN0YCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoIGFuIG9wdGlvbmFsIHN0cmljdGVyXHJcbiAgICogY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhlIHNhbWUgd29yayBhcyB0aGUgYHN0cmluZ2AgdmFsaWRhdG9yLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIGxvZ0Rlc3RcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZyB0aGUgYGxvZ0Rlc3RgXHJcbiAgICogb3B0aW9uLlxyXG4gICAqL1xyXG4gIGxvZ0Rlc3Qoc3RyaWN0Q2hlY2spIHtcclxuICAgIHJldHVybiB2LnN0cmluZyhzdHJpY3RDaGVjayk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGBsb2dUb0NvbnNvbGVgIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGggYW4gb3B0aW9uYWxcclxuICAgKiBzdHJpY3RlciBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGUgc2FtZSB3b3JrIGFzIHRoZSBgYm9vbGVhbmAgdmFsaWRhdG9yLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIGxvZ1RvQ29uc29sZVxyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nXHJcbiAgICogdGhlIGBsb2dUb0NvbnNvbGVgIG9wdGlvbi5cclxuICAgKi9cclxuICBsb2dUb0NvbnNvbGUoc3RyaWN0Q2hlY2spIHtcclxuICAgIHJldHVybiB2LmJvb2xlYW4oc3RyaWN0Q2hlY2spO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgbG9nVG9GaWxlYCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoIGFuIG9wdGlvbmFsXHJcbiAgICogc3RyaWN0ZXIgY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhlIHNhbWUgd29yayBhcyB0aGUgYGJvb2xlYW5gIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiBsb2dUb0ZpbGVcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZyB0aGUgYGxvZ1RvRmlsZWBcclxuICAgKiBvcHRpb24uXHJcbiAgICovXHJcbiAgbG9nVG9GaWxlKHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gdi5ib29sZWFuKHN0cmljdENoZWNrKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYGVuYWJsZVVpYCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoIGFuIG9wdGlvbmFsXHJcbiAgICogc3RyaWN0ZXIgY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhlIHNhbWUgd29yayBhcyB0aGUgYGJvb2xlYW5gIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiBlbmFibGVVaVxyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nIHRoZSBgZW5hYmxlVWlgXHJcbiAgICogb3B0aW9uLlxyXG4gICAqL1xyXG4gIGVuYWJsZVVpKHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gdi5ib29sZWFuKHN0cmljdENoZWNrKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYHVpUm91dGVgIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGggYW4gb3B0aW9uYWxcclxuICAgKiBzdHJpY3RlciBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGUgc2FtZSB3b3JrIGFzIHRoZSBgc3RhcnRzV2l0aGAgdmFsaWRhdG9yLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIHVpUm91dGVcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZyB0aGUgYHVpUm91dGVgXHJcbiAgICogb3B0aW9uLlxyXG4gICAqL1xyXG4gIHVpUm91dGUoc3RyaWN0Q2hlY2spIHtcclxuICAgIHJldHVybiB2LnN0YXJ0c1dpdGgoWycvJ10sIHN0cmljdENoZWNrKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYG5vZGVFbnZgIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGggYW4gb3B0aW9uYWxcclxuICAgKiBzdHJpY3RlciBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGUgc2FtZSB3b3JrIGFzIHRoZSBgZW51bWAgdmFsaWRhdG9yLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIG5vZGVFbnZcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZyB0aGUgYG5vZGVFbnZgXHJcbiAgICogb3B0aW9uLlxyXG4gICAqL1xyXG4gIG5vZGVFbnYoc3RyaWN0Q2hlY2spIHtcclxuICAgIHJldHVybiB2LmVudW0oWydkZXZlbG9wbWVudCcsICdwcm9kdWN0aW9uJywgJ3Rlc3QnXSwgc3RyaWN0Q2hlY2spO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgbGlzdGVuVG9Qcm9jZXNzRXhpdHNgIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGhcclxuICAgKiBhbiBvcHRpb25hbCBzdHJpY3RlciBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGUgc2FtZSB3b3JrIGFzIHRoZSBgYm9vbGVhbmAgdmFsaWRhdG9yLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIGxpc3RlblRvUHJvY2Vzc0V4aXRzXHJcbiAgICpcclxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IHN0cmljdENoZWNrIC0gRGV0ZXJtaW5lcyBpZiBzdHJpY3RlciB2YWxpZGF0aW9uIHNob3VsZFxyXG4gICAqIGJlIGFwcGxpZWQuXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9IEEgWm9kIHNjaGVtYSBvYmplY3QgZm9yIHZhbGlkYXRpbmdcclxuICAgKiB0aGUgYGxpc3RlblRvUHJvY2Vzc0V4aXRzYCBvcHRpb24uXHJcbiAgICovXHJcbiAgbGlzdGVuVG9Qcm9jZXNzRXhpdHMoc3RyaWN0Q2hlY2spIHtcclxuICAgIHJldHVybiB2LmJvb2xlYW4oc3RyaWN0Q2hlY2spO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgbm9Mb2dvYCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoIGFuIG9wdGlvbmFsXHJcbiAgICogc3RyaWN0ZXIgY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhlIHNhbWUgd29yayBhcyB0aGUgYGJvb2xlYW5gIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiBub0xvZ29cclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZyB0aGUgYG5vTG9nb2BcclxuICAgKiBvcHRpb24uXHJcbiAgICovXHJcbiAgbm9Mb2dvKHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gdi5ib29sZWFuKHN0cmljdENoZWNrKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYGhhcmRSZXNldFBhZ2VgIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGggYW4gb3B0aW9uYWxcclxuICAgKiBzdHJpY3RlciBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGUgc2FtZSB3b3JrIGFzIHRoZSBgYm9vbGVhbmAgdmFsaWRhdG9yLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIGhhcmRSZXNldFBhZ2VcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZ1xyXG4gICAqIHRoZSBgaGFyZFJlc2V0UGFnZWAgb3B0aW9uLlxyXG4gICAqL1xyXG4gIGhhcmRSZXNldFBhZ2Uoc3RyaWN0Q2hlY2spIHtcclxuICAgIHJldHVybiB2LmJvb2xlYW4oc3RyaWN0Q2hlY2spO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgYnJvd3NlclNoZWxsTW9kZWAgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbFxyXG4gICAqIHN0cmljdGVyIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgdGhlIGBib29sZWFuYCB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gYnJvd3NlclNoZWxsTW9kZVxyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nXHJcbiAgICogdGhlIGBicm93c2VyU2hlbGxNb2RlYCBvcHRpb24uXHJcbiAgICovXHJcbiAgYnJvd3NlclNoZWxsTW9kZShzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHYuYm9vbGVhbihzdHJpY3RDaGVjayk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGB2YWxpZGF0aW9uYCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoIGFuIG9wdGlvbmFsXHJcbiAgICogc3RyaWN0ZXIgY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhlIHNhbWUgd29yayBhcyB0aGUgYGJvb2xlYW5gIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiB2YWxpZGF0aW9uXHJcbiAgICpcclxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IHN0cmljdENoZWNrIC0gRGV0ZXJtaW5lcyBpZiBzdHJpY3RlciB2YWxpZGF0aW9uIHNob3VsZFxyXG4gICAqIGJlIGFwcGxpZWQuXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9IEEgWm9kIHNjaGVtYSBvYmplY3QgZm9yIHZhbGlkYXRpbmcgdGhlIGB2YWxpZGF0aW9uYFxyXG4gICAqIG9wdGlvbi5cclxuICAgKi9cclxuICB2YWxpZGF0aW9uKHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gdi5ib29sZWFuKHN0cmljdENoZWNrKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYGVuYWJsZURlYnVnYCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoIGFuIG9wdGlvbmFsXHJcbiAgICogc3RyaWN0ZXIgY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhlIHNhbWUgd29yayBhcyB0aGUgYGJvb2xlYW5gIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiBlbmFibGVEZWJ1Z1xyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nIHRoZSBgZW5hYmxlRGVidWdgXHJcbiAgICogb3B0aW9uLlxyXG4gICAqL1xyXG4gIGVuYWJsZURlYnVnKHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gdi5ib29sZWFuKHN0cmljdENoZWNrKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYGhlYWRsZXNzYCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoIGFuIG9wdGlvbmFsXHJcbiAgICogc3RyaWN0ZXIgY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhlIHNhbWUgd29yayBhcyB0aGUgYGJvb2xlYW5gIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiBoZWFkbGVzc1xyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nIHRoZSBgaGVhZGxlc3NgXHJcbiAgICogb3B0aW9uLlxyXG4gICAqL1xyXG4gIGhlYWRsZXNzKHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gdi5ib29sZWFuKHN0cmljdENoZWNrKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYGRldnRvb2xzYCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoIGFuIG9wdGlvbmFsXHJcbiAgICogc3RyaWN0ZXIgY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhlIHNhbWUgd29yayBhcyB0aGUgYGJvb2xlYW5gIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiBkZXZ0b29sc1xyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nIHRoZSBgZGV2dG9vbHNgXHJcbiAgICogb3B0aW9uLlxyXG4gICAqL1xyXG4gIGRldnRvb2xzKHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gdi5ib29sZWFuKHN0cmljdENoZWNrKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYGxpc3RlblRvQ29uc29sZWAgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbFxyXG4gICAqIHN0cmljdGVyIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgdGhlIGBib29sZWFuYCB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gbGlzdGVuVG9Db25zb2xlXHJcbiAgICpcclxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IHN0cmljdENoZWNrIC0gRGV0ZXJtaW5lcyBpZiBzdHJpY3RlciB2YWxpZGF0aW9uIHNob3VsZFxyXG4gICAqIGJlIGFwcGxpZWQuXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9IEEgWm9kIHNjaGVtYSBvYmplY3QgZm9yIHZhbGlkYXRpbmdcclxuICAgKiB0aGUgYGxpc3RlblRvQ29uc29sZWAgb3B0aW9uLlxyXG4gICAqL1xyXG4gIGxpc3RlblRvQ29uc29sZShzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHYuYm9vbGVhbihzdHJpY3RDaGVjayk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGBkdW1waW9gIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGggYW4gb3B0aW9uYWwgc3RyaWN0ZXJcclxuICAgKiBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGUgc2FtZSB3b3JrIGFzIHRoZSBgYm9vbGVhbmAgdmFsaWRhdG9yLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIGR1bXBpb1xyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nIHRoZSBgZHVtcGlvYFxyXG4gICAqIG9wdGlvbi5cclxuICAgKi9cclxuICBkdW1waW8oc3RyaWN0Q2hlY2spIHtcclxuICAgIHJldHVybiB2LmJvb2xlYW4oc3RyaWN0Q2hlY2spO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgc2xvd01vYCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoIGFuIG9wdGlvbmFsIHN0cmljdGVyXHJcbiAgICogY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhlIHNhbWUgd29yayBhcyB0aGUgYG5vbk5lZ2F0aXZlTnVtYFxyXG4gICAqIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiBzbG93TW9cclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZyB0aGUgYHNsb3dNb2BcclxuICAgKiBvcHRpb24uXHJcbiAgICovXHJcbiAgc2xvd01vKHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gdi5ub25OZWdhdGl2ZU51bShzdHJpY3RDaGVjayk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGBkZWJ1Z2dpbmdQb3J0YCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoIGFuIG9wdGlvbmFsXHJcbiAgICogc3RyaWN0ZXIgY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhlIHNhbWUgd29yayBhcyB0aGUgYG5vbk5lZ2F0aXZlTnVtYFxyXG4gICAqIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiBkZWJ1Z2dpbmdQb3J0XHJcbiAgICpcclxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IHN0cmljdENoZWNrIC0gRGV0ZXJtaW5lcyBpZiBzdHJpY3RlciB2YWxpZGF0aW9uIHNob3VsZFxyXG4gICAqIGJlIGFwcGxpZWQuXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9IEEgWm9kIHNjaGVtYSBvYmplY3QgZm9yIHZhbGlkYXRpbmdcclxuICAgKiB0aGUgYGRlYnVnZ2luZ1BvcnRgIG9wdGlvbi5cclxuICAgKi9cclxuICBkZWJ1Z2dpbmdQb3J0KHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gdi5ub25OZWdhdGl2ZU51bShzdHJpY3RDaGVjayk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGByZXF1ZXN0SWRgIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGggYW4gb3B0aW9uYWxcclxuICAgKiBzdHJpY3RlciBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGUgc2FtZSB3b3JrIGFzIHRoZSBgc3RyaW5nYCB2YWxpZGF0b3IuXHJcbiAgICogQWRkaXRpb25hbGx5LCBpdCBtdXN0IGJlIGEgc3RyaW5naWZpZWQgVVVJRCBvciBjYW4gYmUgbnVsbC5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiByZXF1ZXN0SWRcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZyB0aGUgYHJlcXVlc3RJZGBcclxuICAgKiBvcHRpb24uXHJcbiAgICovXHJcbiAgcmVxdWVzdElkKCkge1xyXG4gICAgcmV0dXJuIHpcclxuICAgICAgLnN0cmluZygpXHJcbiAgICAgIC51dWlkKHsgbWVzc2FnZTogJ1RoZSB2YWx1ZSBtdXN0IGJlIGEgc3RyaW5naWZpZWQgVVVJRCcgfSlcclxuICAgICAgLm51bGxhYmxlKCk7XHJcbiAgfVxyXG59O1xyXG5cclxuLy8gU2NoZW1hIGZvciB0aGUgcHVwcGV0ZWVyIHNlY3Rpb24gb2Ygb3B0aW9uc1xyXG5jb25zdCBQdXBwZXRlZXJTY2hlbWEgPSAoc3RyaWN0Q2hlY2spID0+XHJcbiAgelxyXG4gICAgLm9iamVjdCh7XHJcbiAgICAgIGFyZ3M6IHZhbGlkYXRvcnMuYXJncyhzdHJpY3RDaGVjaylcclxuICAgIH0pXHJcbiAgICAucGFydGlhbCgpO1xyXG5cclxuLy8gU2NoZW1hIGZvciB0aGUgaGlnaGNoYXJ0cyBzZWN0aW9uIG9mIG9wdGlvbnNcclxuY29uc3QgSGlnaGNoYXJ0c1NjaGVtYSA9IChzdHJpY3RDaGVjaykgPT5cclxuICB6XHJcbiAgICAub2JqZWN0KHtcclxuICAgICAgdmVyc2lvbjogdmFsaWRhdG9ycy52ZXJzaW9uKHN0cmljdENoZWNrKSxcclxuICAgICAgY2RuVXJsOiB2YWxpZGF0b3JzLmNkblVybChzdHJpY3RDaGVjayksXHJcbiAgICAgIGZvcmNlRmV0Y2g6IHZhbGlkYXRvcnMuZm9yY2VGZXRjaChzdHJpY3RDaGVjayksXHJcbiAgICAgIGNhY2hlUGF0aDogdmFsaWRhdG9ycy5jYWNoZVBhdGgoc3RyaWN0Q2hlY2spLFxyXG4gICAgICBjb3JlU2NyaXB0czogdmFsaWRhdG9ycy5jb3JlU2NyaXB0cyhzdHJpY3RDaGVjayksXHJcbiAgICAgIG1vZHVsZVNjcmlwdHM6IHZhbGlkYXRvcnMubW9kdWxlU2NyaXB0cyhzdHJpY3RDaGVjayksXHJcbiAgICAgIGluZGljYXRvclNjcmlwdHM6IHZhbGlkYXRvcnMuaW5kaWNhdG9yU2NyaXB0cyhzdHJpY3RDaGVjayksXHJcbiAgICAgIGN1c3RvbVNjcmlwdHM6IHZhbGlkYXRvcnMuY3VzdG9tU2NyaXB0cyhzdHJpY3RDaGVjaylcclxuICAgIH0pXHJcbiAgICAucGFydGlhbCgpO1xyXG5cclxuLy8gU2NoZW1hIGZvciB0aGUgZXhwb3J0IHNlY3Rpb24gb2Ygb3B0aW9uc1xyXG5jb25zdCBFeHBvcnRTY2hlbWEgPSAoc3RyaWN0Q2hlY2spID0+XHJcbiAgelxyXG4gICAgLm9iamVjdCh7XHJcbiAgICAgIGluZmlsZTogdmFsaWRhdG9ycy5pbmZpbGUoc3RyaWN0Q2hlY2spLFxyXG4gICAgICBpbnN0cjogdmFsaWRhdG9ycy5pbnN0cigpLFxyXG4gICAgICBvcHRpb25zOiB2YWxpZGF0b3JzLm9wdGlvbnMoKSxcclxuICAgICAgc3ZnOiB2YWxpZGF0b3JzLnN2ZygpLFxyXG4gICAgICBvdXRmaWxlOiB2YWxpZGF0b3JzLm91dGZpbGUoc3RyaWN0Q2hlY2spLFxyXG4gICAgICB0eXBlOiB2YWxpZGF0b3JzLnR5cGUoc3RyaWN0Q2hlY2spLFxyXG4gICAgICBjb25zdHI6IHZhbGlkYXRvcnMuY29uc3RyKHN0cmljdENoZWNrKSxcclxuICAgICAgYjY0OiB2YWxpZGF0b3JzLmI2NChzdHJpY3RDaGVjayksXHJcbiAgICAgIG5vRG93bmxvYWQ6IHZhbGlkYXRvcnMubm9Eb3dubG9hZChzdHJpY3RDaGVjayksXHJcbiAgICAgIGRlZmF1bHRIZWlnaHQ6IHZhbGlkYXRvcnMuZGVmYXVsdEhlaWdodChzdHJpY3RDaGVjayksXHJcbiAgICAgIGRlZmF1bHRXaWR0aDogdmFsaWRhdG9ycy5kZWZhdWx0V2lkdGgoc3RyaWN0Q2hlY2spLFxyXG4gICAgICBkZWZhdWx0U2NhbGU6IHZhbGlkYXRvcnMuZGVmYXVsdFNjYWxlKHN0cmljdENoZWNrKSxcclxuICAgICAgaGVpZ2h0OiB2YWxpZGF0b3JzLmhlaWdodChzdHJpY3RDaGVjayksXHJcbiAgICAgIHdpZHRoOiB2YWxpZGF0b3JzLndpZHRoKHN0cmljdENoZWNrKSxcclxuICAgICAgc2NhbGU6IHZhbGlkYXRvcnMuc2NhbGUoc3RyaWN0Q2hlY2spLFxyXG4gICAgICBnbG9iYWxPcHRpb25zOiB2YWxpZGF0b3JzLmdsb2JhbE9wdGlvbnMoKSxcclxuICAgICAgdGhlbWVPcHRpb25zOiB2YWxpZGF0b3JzLnRoZW1lT3B0aW9ucygpLFxyXG4gICAgICBiYXRjaDogdmFsaWRhdG9ycy5iYXRjaChmYWxzZSksXHJcbiAgICAgIHJhc3Rlcml6YXRpb25UaW1lb3V0OiB2YWxpZGF0b3JzLnJhc3Rlcml6YXRpb25UaW1lb3V0KHN0cmljdENoZWNrKVxyXG4gICAgfSlcclxuICAgIC5wYXJ0aWFsKCk7XHJcblxyXG4vLyBTY2hlbWEgZm9yIHRoZSBjdXN0b21Mb2dpYyBzZWN0aW9uIG9mIG9wdGlvbnNcclxuY29uc3QgQ3VzdG9tTG9naWNTY2hlbWEgPSAoc3RyaWN0Q2hlY2spID0+XHJcbiAgelxyXG4gICAgLm9iamVjdCh7XHJcbiAgICAgIGFsbG93Q29kZUV4ZWN1dGlvbjogdmFsaWRhdG9ycy5hbGxvd0NvZGVFeGVjdXRpb24oc3RyaWN0Q2hlY2spLFxyXG4gICAgICBhbGxvd0ZpbGVSZXNvdXJjZXM6IHZhbGlkYXRvcnMuYWxsb3dGaWxlUmVzb3VyY2VzKHN0cmljdENoZWNrKSxcclxuICAgICAgY3VzdG9tQ29kZTogdmFsaWRhdG9ycy5jdXN0b21Db2RlKGZhbHNlKSxcclxuICAgICAgY2FsbGJhY2s6IHZhbGlkYXRvcnMuY2FsbGJhY2soZmFsc2UpLFxyXG4gICAgICByZXNvdXJjZXM6IHZhbGlkYXRvcnMucmVzb3VyY2VzKHN0cmljdENoZWNrKSxcclxuICAgICAgbG9hZENvbmZpZzogdmFsaWRhdG9ycy5sb2FkQ29uZmlnKGZhbHNlKSxcclxuICAgICAgY3JlYXRlQ29uZmlnOiB2YWxpZGF0b3JzLmNyZWF0ZUNvbmZpZyhmYWxzZSlcclxuICAgIH0pXHJcbiAgICAucGFydGlhbCgpO1xyXG5cclxuLy8gU2NoZW1hIGZvciB0aGUgc2VydmVyLnByb3h5IHNlY3Rpb24gb2Ygb3B0aW9uc1xyXG5jb25zdCBQcm94eVNjaGVtYSA9IChzdHJpY3RDaGVjaykgPT5cclxuICB6XHJcbiAgICAub2JqZWN0KHtcclxuICAgICAgaG9zdDogdmFsaWRhdG9ycy5wcm94eUhvc3QoZmFsc2UpLFxyXG4gICAgICBwb3J0OiB2YWxpZGF0b3JzLnByb3h5UG9ydChzdHJpY3RDaGVjayksXHJcbiAgICAgIHRpbWVvdXQ6IHZhbGlkYXRvcnMucHJveHlUaW1lb3V0KHN0cmljdENoZWNrKVxyXG4gICAgfSlcclxuICAgIC5wYXJ0aWFsKCk7XHJcblxyXG4vLyBTY2hlbWEgZm9yIHRoZSBzZXJ2ZXIucmF0ZUxpbWl0aW5nIHNlY3Rpb24gb2Ygb3B0aW9uc1xyXG5jb25zdCBSYXRlTGltaXRpbmdTY2hlbWEgPSAoc3RyaWN0Q2hlY2spID0+XHJcbiAgelxyXG4gICAgLm9iamVjdCh7XHJcbiAgICAgIGVuYWJsZTogdmFsaWRhdG9ycy5lbmFibGVSYXRlTGltaXRpbmcoc3RyaWN0Q2hlY2spLFxyXG4gICAgICBtYXhSZXF1ZXN0czogdmFsaWRhdG9ycy5tYXhSZXF1ZXN0cyhzdHJpY3RDaGVjayksXHJcbiAgICAgIHdpbmRvdzogdmFsaWRhdG9ycy53aW5kb3coc3RyaWN0Q2hlY2spLFxyXG4gICAgICBkZWxheTogdmFsaWRhdG9ycy5kZWxheShzdHJpY3RDaGVjayksXHJcbiAgICAgIHRydXN0UHJveHk6IHZhbGlkYXRvcnMudHJ1c3RQcm94eShzdHJpY3RDaGVjayksXHJcbiAgICAgIHNraXBLZXk6IHZhbGlkYXRvcnMuc2tpcEtleShmYWxzZSksXHJcbiAgICAgIHNraXBUb2tlbjogdmFsaWRhdG9ycy5za2lwVG9rZW4oZmFsc2UpXHJcbiAgICB9KVxyXG4gICAgLnBhcnRpYWwoKTtcclxuXHJcbi8vIFNjaGVtYSBmb3IgdGhlIHNlcnZlci5zc2wgc2VjdGlvbiBvZiBvcHRpb25zXHJcbmNvbnN0IFNzbFNjaGVtYSA9IChzdHJpY3RDaGVjaykgPT5cclxuICB6XHJcbiAgICAub2JqZWN0KHtcclxuICAgICAgZW5hYmxlOiB2YWxpZGF0b3JzLmVuYWJsZVNzbChzdHJpY3RDaGVjayksXHJcbiAgICAgIGZvcmNlOiB2YWxpZGF0b3JzLnNzbEZvcmNlKHN0cmljdENoZWNrKSxcclxuICAgICAgcG9ydDogdmFsaWRhdG9ycy5zc2xQb3J0KHN0cmljdENoZWNrKSxcclxuICAgICAgY2VydFBhdGg6IHZhbGlkYXRvcnMuc3NsQ2VydFBhdGgoZmFsc2UpXHJcbiAgICB9KVxyXG4gICAgLnBhcnRpYWwoKTtcclxuXHJcbi8vIFNjaGVtYSBmb3IgdGhlIHNlcnZlciBzZWN0aW9uIG9mIG9wdGlvbnNcclxuY29uc3QgU2VydmVyU2NoZW1hID0gKHN0cmljdENoZWNrKSA9PlxyXG4gIHoub2JqZWN0KHtcclxuICAgIGVuYWJsZTogdmFsaWRhdG9ycy5lbmFibGVTZXJ2ZXIoc3RyaWN0Q2hlY2spLm9wdGlvbmFsKCksXHJcbiAgICBob3N0OiB2YWxpZGF0b3JzLmhvc3Qoc3RyaWN0Q2hlY2spLm9wdGlvbmFsKCksXHJcbiAgICBwb3J0OiB2YWxpZGF0b3JzLnBvcnQoc3RyaWN0Q2hlY2spLm9wdGlvbmFsKCksXHJcbiAgICB1cGxvYWRMaW1pdDogdmFsaWRhdG9ycy51cGxvYWRMaW1pdChzdHJpY3RDaGVjaykub3B0aW9uYWwoKSxcclxuICAgIGJlbmNobWFya2luZzogdmFsaWRhdG9ycy5zZXJ2ZXJCZW5jaG1hcmtpbmcoc3RyaWN0Q2hlY2spLm9wdGlvbmFsKCksXHJcbiAgICBwcm94eTogUHJveHlTY2hlbWEoc3RyaWN0Q2hlY2spLm9wdGlvbmFsKCksXHJcbiAgICByYXRlTGltaXRpbmc6IFJhdGVMaW1pdGluZ1NjaGVtYShzdHJpY3RDaGVjaykub3B0aW9uYWwoKSxcclxuICAgIHNzbDogU3NsU2NoZW1hKHN0cmljdENoZWNrKS5vcHRpb25hbCgpXHJcbiAgfSk7XHJcblxyXG4vLyBTY2hlbWEgZm9yIHRoZSBwb29sIHNlY3Rpb24gb2Ygb3B0aW9uc1xyXG5jb25zdCBQb29sU2NoZW1hID0gKHN0cmljdENoZWNrKSA9PlxyXG4gIHpcclxuICAgIC5vYmplY3Qoe1xyXG4gICAgICBtaW5Xb3JrZXJzOiB2YWxpZGF0b3JzLm1pbldvcmtlcnMoc3RyaWN0Q2hlY2spLFxyXG4gICAgICBtYXhXb3JrZXJzOiB2YWxpZGF0b3JzLm1heFdvcmtlcnMoc3RyaWN0Q2hlY2spLFxyXG4gICAgICB3b3JrTGltaXQ6IHZhbGlkYXRvcnMud29ya0xpbWl0KHN0cmljdENoZWNrKSxcclxuICAgICAgYWNxdWlyZVRpbWVvdXQ6IHZhbGlkYXRvcnMuYWNxdWlyZVRpbWVvdXQoc3RyaWN0Q2hlY2spLFxyXG4gICAgICBjcmVhdGVUaW1lb3V0OiB2YWxpZGF0b3JzLmNyZWF0ZVRpbWVvdXQoc3RyaWN0Q2hlY2spLFxyXG4gICAgICBkZXN0cm95VGltZW91dDogdmFsaWRhdG9ycy5kZXN0cm95VGltZW91dChzdHJpY3RDaGVjayksXHJcbiAgICAgIGlkbGVUaW1lb3V0OiB2YWxpZGF0b3JzLmlkbGVUaW1lb3V0KHN0cmljdENoZWNrKSxcclxuICAgICAgY3JlYXRlUmV0cnlJbnRlcnZhbDogdmFsaWRhdG9ycy5jcmVhdGVSZXRyeUludGVydmFsKHN0cmljdENoZWNrKSxcclxuICAgICAgcmVhcGVySW50ZXJ2YWw6IHZhbGlkYXRvcnMucmVhcGVySW50ZXJ2YWwoc3RyaWN0Q2hlY2spLFxyXG4gICAgICBiZW5jaG1hcmtpbmc6IHZhbGlkYXRvcnMucG9vbEJlbmNobWFya2luZyhzdHJpY3RDaGVjaylcclxuICAgIH0pXHJcbiAgICAucGFydGlhbCgpO1xyXG5cclxuLy8gU2NoZW1hIGZvciB0aGUgbG9nZ2luZyBzZWN0aW9uIG9mIG9wdGlvbnNcclxuY29uc3QgTG9nZ2luZ1NjaGVtYSA9IChzdHJpY3RDaGVjaykgPT5cclxuICB6XHJcbiAgICAub2JqZWN0KHtcclxuICAgICAgbGV2ZWw6IHZhbGlkYXRvcnMubG9nTGV2ZWwoc3RyaWN0Q2hlY2spLFxyXG4gICAgICBmaWxlOiB2YWxpZGF0b3JzLmxvZ0ZpbGUoc3RyaWN0Q2hlY2spLFxyXG4gICAgICBkZXN0OiB2YWxpZGF0b3JzLmxvZ0Rlc3Qoc3RyaWN0Q2hlY2spLFxyXG4gICAgICB0b0NvbnNvbGU6IHZhbGlkYXRvcnMubG9nVG9Db25zb2xlKHN0cmljdENoZWNrKSxcclxuICAgICAgdG9GaWxlOiB2YWxpZGF0b3JzLmxvZ1RvRmlsZShzdHJpY3RDaGVjaylcclxuICAgIH0pXHJcbiAgICAucGFydGlhbCgpO1xyXG5cclxuLy8gU2NoZW1hIGZvciB0aGUgdWkgc2VjdGlvbiBvZiBvcHRpb25zXHJcbmNvbnN0IFVpU2NoZW1hID0gKHN0cmljdENoZWNrKSA9PlxyXG4gIHpcclxuICAgIC5vYmplY3Qoe1xyXG4gICAgICBlbmFibGU6IHZhbGlkYXRvcnMuZW5hYmxlVWkoc3RyaWN0Q2hlY2spLFxyXG4gICAgICByb3V0ZTogdmFsaWRhdG9ycy51aVJvdXRlKHN0cmljdENoZWNrKVxyXG4gICAgfSlcclxuICAgIC5wYXJ0aWFsKCk7XHJcblxyXG4vLyBTY2hlbWEgZm9yIHRoZSBvdGhlciBzZWN0aW9uIG9mIG9wdGlvbnNcclxuY29uc3QgT3RoZXJTY2hlbWEgPSAoc3RyaWN0Q2hlY2spID0+XHJcbiAgelxyXG4gICAgLm9iamVjdCh7XHJcbiAgICAgIG5vZGVFbnY6IHZhbGlkYXRvcnMubm9kZUVudihzdHJpY3RDaGVjayksXHJcbiAgICAgIGxpc3RlblRvUHJvY2Vzc0V4aXRzOiB2YWxpZGF0b3JzLmxpc3RlblRvUHJvY2Vzc0V4aXRzKHN0cmljdENoZWNrKSxcclxuICAgICAgbm9Mb2dvOiB2YWxpZGF0b3JzLm5vTG9nbyhzdHJpY3RDaGVjayksXHJcbiAgICAgIGhhcmRSZXNldFBhZ2U6IHZhbGlkYXRvcnMuaGFyZFJlc2V0UGFnZShzdHJpY3RDaGVjayksXHJcbiAgICAgIGJyb3dzZXJTaGVsbE1vZGU6IHZhbGlkYXRvcnMuYnJvd3NlclNoZWxsTW9kZShzdHJpY3RDaGVjayksXHJcbiAgICAgIHZhbGlkYXRpb246IHZhbGlkYXRvcnMudmFsaWRhdGlvbihzdHJpY3RDaGVjaylcclxuICAgIH0pXHJcbiAgICAucGFydGlhbCgpO1xyXG5cclxuLy8gU2NoZW1hIGZvciB0aGUgZGVidWcgc2VjdGlvbiBvZiBvcHRpb25zXHJcbmNvbnN0IERlYnVnU2NoZW1hID0gKHN0cmljdENoZWNrKSA9PlxyXG4gIHpcclxuICAgIC5vYmplY3Qoe1xyXG4gICAgICBlbmFibGU6IHZhbGlkYXRvcnMuZW5hYmxlRGVidWcoc3RyaWN0Q2hlY2spLFxyXG4gICAgICBoZWFkbGVzczogdmFsaWRhdG9ycy5oZWFkbGVzcyhzdHJpY3RDaGVjayksXHJcbiAgICAgIGRldnRvb2xzOiB2YWxpZGF0b3JzLmRldnRvb2xzKHN0cmljdENoZWNrKSxcclxuICAgICAgbGlzdGVuVG9Db25zb2xlOiB2YWxpZGF0b3JzLmxpc3RlblRvQ29uc29sZShzdHJpY3RDaGVjayksXHJcbiAgICAgIGR1bXBpbzogdmFsaWRhdG9ycy5kdW1waW8oc3RyaWN0Q2hlY2spLFxyXG4gICAgICBzbG93TW86IHZhbGlkYXRvcnMuc2xvd01vKHN0cmljdENoZWNrKSxcclxuICAgICAgZGVidWdnaW5nUG9ydDogdmFsaWRhdG9ycy5kZWJ1Z2dpbmdQb3J0KHN0cmljdENoZWNrKVxyXG4gICAgfSlcclxuICAgIC5wYXJ0aWFsKCk7XHJcblxyXG4vLyBTdHJpY3Qgc2NoZW1hIGZvciB0aGUgY29uZmlnXHJcbmV4cG9ydCBjb25zdCBTdHJpY3RDb25maWdTY2hlbWEgPSB6Lm9iamVjdCh7XHJcbiAgcmVxdWVzdElkOiB2YWxpZGF0b3JzLnJlcXVlc3RJZCgpLFxyXG4gIHB1cHBldGVlcjogUHVwcGV0ZWVyU2NoZW1hKHRydWUpLFxyXG4gIGhpZ2hjaGFydHM6IEhpZ2hjaGFydHNTY2hlbWEodHJ1ZSksXHJcbiAgZXhwb3J0OiBFeHBvcnRTY2hlbWEodHJ1ZSksXHJcbiAgY3VzdG9tTG9naWM6IEN1c3RvbUxvZ2ljU2NoZW1hKHRydWUpLFxyXG4gIHNlcnZlcjogU2VydmVyU2NoZW1hKHRydWUpLFxyXG4gIHBvb2w6IFBvb2xTY2hlbWEodHJ1ZSksXHJcbiAgbG9nZ2luZzogTG9nZ2luZ1NjaGVtYSh0cnVlKSxcclxuICB1aTogVWlTY2hlbWEodHJ1ZSksXHJcbiAgb3RoZXI6IE90aGVyU2NoZW1hKHRydWUpLFxyXG4gIGRlYnVnOiBEZWJ1Z1NjaGVtYSh0cnVlKVxyXG59KTtcclxuXHJcbi8vIExvb3NlIHNjaGVtYSBmb3IgdGhlIGNvbmZpZ1xyXG5leHBvcnQgY29uc3QgTG9vc2VDb25maWdTY2hlbWEgPSB6Lm9iamVjdCh7XHJcbiAgcmVxdWVzdElkOiB2YWxpZGF0b3JzLnJlcXVlc3RJZCgpLFxyXG4gIHB1cHBldGVlcjogUHVwcGV0ZWVyU2NoZW1hKGZhbHNlKSxcclxuICBoaWdoY2hhcnRzOiBIaWdoY2hhcnRzU2NoZW1hKGZhbHNlKSxcclxuICBleHBvcnQ6IEV4cG9ydFNjaGVtYShmYWxzZSksXHJcbiAgY3VzdG9tTG9naWM6IEN1c3RvbUxvZ2ljU2NoZW1hKGZhbHNlKSxcclxuICBzZXJ2ZXI6IFNlcnZlclNjaGVtYShmYWxzZSksXHJcbiAgcG9vbDogUG9vbFNjaGVtYShmYWxzZSksXHJcbiAgbG9nZ2luZzogTG9nZ2luZ1NjaGVtYShmYWxzZSksXHJcbiAgdWk6IFVpU2NoZW1hKGZhbHNlKSxcclxuICBvdGhlcjogT3RoZXJTY2hlbWEoZmFsc2UpLFxyXG4gIGRlYnVnOiBEZWJ1Z1NjaGVtYShmYWxzZSlcclxufSk7XHJcblxyXG4vLyBTY2hlbWEgZm9yIHRoZSBlbnZpcm9ubWVudCB2YXJpYWJsZXMgY29uZmlnXHJcbmV4cG9ydCBjb25zdCBFbnZTY2hlbWEgPSB6Lm9iamVjdCh7XHJcbiAgLy8gcHVwcGV0ZWVyXHJcbiAgUFVQUEVURUVSX0FSR1M6IHZhbGlkYXRvcnMuYXJncyhmYWxzZSksXHJcblxyXG4gIC8vIGhpZ2hjaGFydHNcclxuICBISUdIQ0hBUlRTX1ZFUlNJT046IHZhbGlkYXRvcnMudmVyc2lvbihmYWxzZSksXHJcbiAgSElHSENIQVJUU19DRE5fVVJMOiB2YWxpZGF0b3JzLmNkblVybChmYWxzZSksXHJcbiAgSElHSENIQVJUU19GT1JDRV9GRVRDSDogdmFsaWRhdG9ycy5mb3JjZUZldGNoKGZhbHNlKSxcclxuICBISUdIQ0hBUlRTX0NBQ0hFX1BBVEg6IHZhbGlkYXRvcnMuY2FjaGVQYXRoKGZhbHNlKSxcclxuICBISUdIQ0hBUlRTX0FETUlOX1RPS0VOOiB2YWxpZGF0b3JzLmFkbWluVG9rZW4oZmFsc2UpLFxyXG4gIEhJR0hDSEFSVFNfQ09SRV9TQ1JJUFRTOiB2YWxpZGF0b3JzLmNvcmVTY3JpcHRzKGZhbHNlKSxcclxuICBISUdIQ0hBUlRTX01PRFVMRV9TQ1JJUFRTOiB2YWxpZGF0b3JzLm1vZHVsZVNjcmlwdHMoZmFsc2UpLFxyXG4gIEhJR0hDSEFSVFNfSU5ESUNBVE9SX1NDUklQVFM6IHZhbGlkYXRvcnMuaW5kaWNhdG9yU2NyaXB0cyhmYWxzZSksXHJcbiAgSElHSENIQVJUU19DVVNUT01fU0NSSVBUUzogdmFsaWRhdG9ycy5jdXN0b21TY3JpcHRzKGZhbHNlKSxcclxuXHJcbiAgLy8gZXhwb3J0XHJcbiAgRVhQT1JUX0lORklMRTogdmFsaWRhdG9ycy5pbmZpbGUoZmFsc2UpLFxyXG4gIEVYUE9SVF9JTlNUUjogdmFsaWRhdG9ycy5pbnN0cigpLFxyXG4gIEVYUE9SVF9PUFRJT05TOiB2YWxpZGF0b3JzLm9wdGlvbnMoKSxcclxuICBFWFBPUlRfU1ZHOiB2YWxpZGF0b3JzLnN2ZygpLFxyXG4gIEVYUE9SVF9CQVRDSDogdmFsaWRhdG9ycy5iYXRjaChmYWxzZSksXHJcbiAgRVhQT1JUX09VVEZJTEU6IHZhbGlkYXRvcnMub3V0ZmlsZShmYWxzZSksXHJcbiAgRVhQT1JUX1RZUEU6IHZhbGlkYXRvcnMudHlwZShmYWxzZSksXHJcbiAgRVhQT1JUX0NPTlNUUjogdmFsaWRhdG9ycy5jb25zdHIoZmFsc2UpLFxyXG4gIEVYUE9SVF9CNjQ6IHZhbGlkYXRvcnMuYjY0KGZhbHNlKSxcclxuICBFWFBPUlRfTk9fRE9XTkxPQUQ6IHZhbGlkYXRvcnMubm9Eb3dubG9hZChmYWxzZSksXHJcbiAgRVhQT1JUX0hFSUdIVDogdmFsaWRhdG9ycy5oZWlnaHQoZmFsc2UpLFxyXG4gIEVYUE9SVF9XSURUSDogdmFsaWRhdG9ycy53aWR0aChmYWxzZSksXHJcbiAgRVhQT1JUX1NDQUxFOiB2YWxpZGF0b3JzLnNjYWxlKGZhbHNlKSxcclxuICBFWFBPUlRfREVGQVVMVF9IRUlHSFQ6IHZhbGlkYXRvcnMuZGVmYXVsdEhlaWdodChmYWxzZSksXHJcbiAgRVhQT1JUX0RFRkFVTFRfV0lEVEg6IHZhbGlkYXRvcnMuZGVmYXVsdFdpZHRoKGZhbHNlKSxcclxuICBFWFBPUlRfREVGQVVMVF9TQ0FMRTogdmFsaWRhdG9ycy5kZWZhdWx0U2NhbGUoZmFsc2UpLFxyXG4gIEVYUE9SVF9HTE9CQUxfT1BUSU9OUzogdmFsaWRhdG9ycy5nbG9iYWxPcHRpb25zKCksXHJcbiAgRVhQT1JUX1RIRU1FX09QVElPTlM6IHZhbGlkYXRvcnMudGhlbWVPcHRpb25zKCksXHJcbiAgRVhQT1JUX1JBU1RFUklaQVRJT05fVElNRU9VVDogdmFsaWRhdG9ycy5yYXN0ZXJpemF0aW9uVGltZW91dChmYWxzZSksXHJcblxyXG4gIC8vIGN1c3RvbVxyXG4gIENVU1RPTV9MT0dJQ19BTExPV19DT0RFX0VYRUNVVElPTjogdmFsaWRhdG9ycy5hbGxvd0NvZGVFeGVjdXRpb24oZmFsc2UpLFxyXG4gIENVU1RPTV9MT0dJQ19BTExPV19GSUxFX1JFU09VUkNFUzogdmFsaWRhdG9ycy5hbGxvd0ZpbGVSZXNvdXJjZXMoZmFsc2UpLFxyXG4gIENVU1RPTV9MT0dJQ19DVVNUT01fQ09ERTogdmFsaWRhdG9ycy5jdXN0b21Db2RlKGZhbHNlKSxcclxuICBDVVNUT01fTE9HSUNfQ0FMTEJBQ0s6IHZhbGlkYXRvcnMuY2FsbGJhY2soZmFsc2UpLFxyXG4gIENVU1RPTV9MT0dJQ19SRVNPVVJDRVM6IHZhbGlkYXRvcnMucmVzb3VyY2VzKGZhbHNlKSxcclxuICBDVVNUT01fTE9HSUNfTE9BRF9DT05GSUc6IHZhbGlkYXRvcnMubG9hZENvbmZpZyhmYWxzZSksXHJcbiAgQ1VTVE9NX0xPR0lDX0NSRUFURV9DT05GSUc6IHZhbGlkYXRvcnMuY3JlYXRlQ29uZmlnKGZhbHNlKSxcclxuXHJcbiAgLy8gc2VydmVyXHJcbiAgU0VSVkVSX0VOQUJMRTogdmFsaWRhdG9ycy5lbmFibGVTZXJ2ZXIoZmFsc2UpLFxyXG4gIFNFUlZFUl9IT1NUOiB2YWxpZGF0b3JzLmhvc3QoZmFsc2UpLFxyXG4gIFNFUlZFUl9QT1JUOiB2YWxpZGF0b3JzLnBvcnQoZmFsc2UpLFxyXG4gIFNFUlZFUl9VUExPQURfTElNSVQ6IHZhbGlkYXRvcnMudXBsb2FkTGltaXQoZmFsc2UpLFxyXG4gIFNFUlZFUl9CRU5DSE1BUktJTkc6IHZhbGlkYXRvcnMuc2VydmVyQmVuY2htYXJraW5nKGZhbHNlKSxcclxuXHJcbiAgLy8gc2VydmVyIHByb3h5XHJcbiAgU0VSVkVSX1BST1hZX0hPU1Q6IHZhbGlkYXRvcnMucHJveHlIb3N0KGZhbHNlKSxcclxuICBTRVJWRVJfUFJPWFlfUE9SVDogdmFsaWRhdG9ycy5wcm94eVBvcnQoZmFsc2UpLFxyXG4gIFNFUlZFUl9QUk9YWV9USU1FT1VUOiB2YWxpZGF0b3JzLnByb3h5VGltZW91dChmYWxzZSksXHJcblxyXG4gIC8vIHNlcnZlciByYXRlIGxpbWl0aW5nXHJcbiAgU0VSVkVSX1JBVEVfTElNSVRJTkdfRU5BQkxFOiB2YWxpZGF0b3JzLmVuYWJsZVJhdGVMaW1pdGluZyhmYWxzZSksXHJcbiAgU0VSVkVSX1JBVEVfTElNSVRJTkdfTUFYX1JFUVVFU1RTOiB2YWxpZGF0b3JzLm1heFJlcXVlc3RzKGZhbHNlKSxcclxuICBTRVJWRVJfUkFURV9MSU1JVElOR19XSU5ET1c6IHZhbGlkYXRvcnMud2luZG93KGZhbHNlKSxcclxuICBTRVJWRVJfUkFURV9MSU1JVElOR19ERUxBWTogdmFsaWRhdG9ycy5kZWxheShmYWxzZSksXHJcbiAgU0VSVkVSX1JBVEVfTElNSVRJTkdfVFJVU1RfUFJPWFk6IHZhbGlkYXRvcnMudHJ1c3RQcm94eShmYWxzZSksXHJcbiAgU0VSVkVSX1JBVEVfTElNSVRJTkdfU0tJUF9LRVk6IHZhbGlkYXRvcnMuc2tpcEtleShmYWxzZSksXHJcbiAgU0VSVkVSX1JBVEVfTElNSVRJTkdfU0tJUF9UT0tFTjogdmFsaWRhdG9ycy5za2lwVG9rZW4oZmFsc2UpLFxyXG5cclxuICAvLyBzZXJ2ZXIgc3NsXHJcbiAgU0VSVkVSX1NTTF9FTkFCTEU6IHZhbGlkYXRvcnMuZW5hYmxlU3NsKGZhbHNlKSxcclxuICBTRVJWRVJfU1NMX0ZPUkNFOiB2YWxpZGF0b3JzLnNzbEZvcmNlKGZhbHNlKSxcclxuICBTRVJWRVJfU1NMX1BPUlQ6IHZhbGlkYXRvcnMuc3NsUG9ydChmYWxzZSksXHJcbiAgU0VSVkVSX1NTTF9DRVJUX1BBVEg6IHZhbGlkYXRvcnMuc3NsQ2VydFBhdGgoZmFsc2UpLFxyXG5cclxuICAvLyBwb29sXHJcbiAgUE9PTF9NSU5fV09SS0VSUzogdmFsaWRhdG9ycy5taW5Xb3JrZXJzKGZhbHNlKSxcclxuICBQT09MX01BWF9XT1JLRVJTOiB2YWxpZGF0b3JzLm1heFdvcmtlcnMoZmFsc2UpLFxyXG4gIFBPT0xfV09SS19MSU1JVDogdmFsaWRhdG9ycy53b3JrTGltaXQoZmFsc2UpLFxyXG4gIFBPT0xfQUNRVUlSRV9USU1FT1VUOiB2YWxpZGF0b3JzLmFjcXVpcmVUaW1lb3V0KGZhbHNlKSxcclxuICBQT09MX0NSRUFURV9USU1FT1VUOiB2YWxpZGF0b3JzLmNyZWF0ZVRpbWVvdXQoZmFsc2UpLFxyXG4gIFBPT0xfREVTVFJPWV9USU1FT1VUOiB2YWxpZGF0b3JzLmRlc3Ryb3lUaW1lb3V0KGZhbHNlKSxcclxuICBQT09MX0lETEVfVElNRU9VVDogdmFsaWRhdG9ycy5pZGxlVGltZW91dChmYWxzZSksXHJcbiAgUE9PTF9DUkVBVEVfUkVUUllfSU5URVJWQUw6IHZhbGlkYXRvcnMuY3JlYXRlUmV0cnlJbnRlcnZhbChmYWxzZSksXHJcbiAgUE9PTF9SRUFQRVJfSU5URVJWQUw6IHZhbGlkYXRvcnMucmVhcGVySW50ZXJ2YWwoZmFsc2UpLFxyXG4gIFBPT0xfQkVOQ0hNQVJLSU5HOiB2YWxpZGF0b3JzLnBvb2xCZW5jaG1hcmtpbmcoZmFsc2UpLFxyXG5cclxuICAvLyBsb2dnaW5nXHJcbiAgTE9HR0lOR19MRVZFTDogdmFsaWRhdG9ycy5sb2dMZXZlbChmYWxzZSksXHJcbiAgTE9HR0lOR19GSUxFOiB2YWxpZGF0b3JzLmxvZ0ZpbGUoZmFsc2UpLFxyXG4gIExPR0dJTkdfREVTVDogdmFsaWRhdG9ycy5sb2dEZXN0KGZhbHNlKSxcclxuICBMT0dHSU5HX1RPX0NPTlNPTEU6IHZhbGlkYXRvcnMubG9nVG9Db25zb2xlKGZhbHNlKSxcclxuICBMT0dHSU5HX1RPX0ZJTEU6IHZhbGlkYXRvcnMubG9nVG9GaWxlKGZhbHNlKSxcclxuXHJcbiAgLy8gdWlcclxuICBVSV9FTkFCTEU6IHZhbGlkYXRvcnMuZW5hYmxlVWkoZmFsc2UpLFxyXG4gIFVJX1JPVVRFOiB2YWxpZGF0b3JzLnVpUm91dGUoZmFsc2UpLFxyXG5cclxuICAvLyBvdGhlclxyXG4gIE9USEVSX05PREVfRU5WOiB2YWxpZGF0b3JzLm5vZGVFbnYoZmFsc2UpLFxyXG4gIE9USEVSX0xJU1RFTl9UT19QUk9DRVNTX0VYSVRTOiB2YWxpZGF0b3JzLmxpc3RlblRvUHJvY2Vzc0V4aXRzKGZhbHNlKSxcclxuICBPVEhFUl9OT19MT0dPOiB2YWxpZGF0b3JzLm5vTG9nbyhmYWxzZSksXHJcbiAgT1RIRVJfSEFSRF9SRVNFVF9QQUdFOiB2YWxpZGF0b3JzLmhhcmRSZXNldFBhZ2UoZmFsc2UpLFxyXG4gIE9USEVSX0JST1dTRVJfU0hFTExfTU9ERTogdmFsaWRhdG9ycy5icm93c2VyU2hlbGxNb2RlKGZhbHNlKSxcclxuICBPVEhFUl9WQUxJREFUSU9OOiB2YWxpZGF0b3JzLnZhbGlkYXRpb24oZmFsc2UpLFxyXG5cclxuICAvLyBkZWJ1Z2dlclxyXG4gIERFQlVHX0VOQUJMRTogdmFsaWRhdG9ycy5lbmFibGVEZWJ1ZyhmYWxzZSksXHJcbiAgREVCVUdfSEVBRExFU1M6IHZhbGlkYXRvcnMuaGVhZGxlc3MoZmFsc2UpLFxyXG4gIERFQlVHX0RFVlRPT0xTOiB2YWxpZGF0b3JzLmRldnRvb2xzKGZhbHNlKSxcclxuICBERUJVR19MSVNURU5fVE9fQ09OU09MRTogdmFsaWRhdG9ycy5saXN0ZW5Ub0NvbnNvbGUoZmFsc2UpLFxyXG4gIERFQlVHX0RVTVBJTzogdmFsaWRhdG9ycy5kdW1waW8oZmFsc2UpLFxyXG4gIERFQlVHX1NMT1dfTU86IHZhbGlkYXRvcnMuc2xvd01vKGZhbHNlKSxcclxuICBERUJVR19ERUJVR0dJTkdfUE9SVDogdmFsaWRhdG9ycy5kZWJ1Z2dpbmdQb3J0KGZhbHNlKVxyXG59KTtcclxuXHJcbi8qKlxyXG4gKiBWYWxpZGF0ZXMgdGhlIGVudmlyb25tZW50IHZhcmlhYmxlcyBvcHRpb25zIHVzaW5nIHRoZSBFbnZTY2hlbWEuXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBwcm9jZXNzLmVudiAtIFRoZSBjb25maWd1cmF0aW9uIG9wdGlvbnMgZnJvbSBlbnZpcm9ubWVudFxyXG4gKiB2YXJpYWJsZXMgZmlsZSB0byB2YWxpZGF0ZS5cclxuICpcclxuICogQHJldHVybnMge09iamVjdH0gVGhlIHBhcnNlZCBhbmQgdmFsaWRhdGVkIGVudmlyb25tZW50IHZhcmlhYmxlcy5cclxuICovXHJcbmV4cG9ydCBjb25zdCBlbnZzID0gRW52U2NoZW1hLnBhcnRpYWwoKS5wYXJzZShwcm9jZXNzLmVudik7XHJcblxyXG4vKipcclxuICogVmFsaWRhdGVzIHRoZSBjb25maWd1cmF0aW9uIG9wdGlvbnMgdXNpbmcgdGhlIGBTdHJpY3RDb25maWdTY2hlbWFgLlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gc3RyaWN0VmFsaWRhdGVcclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IGNvbmZpZ09wdGlvbnMgLSBUaGUgY29uZmlndXJhdGlvbiBvcHRpb25zIHRvIHZhbGlkYXRlLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7T2JqZWN0fSBUaGUgcGFyc2VkIGFuZCB2YWxpZGF0ZWQgY29uZmlndXJhdGlvbiBvcHRpb25zLlxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIHN0cmljdFZhbGlkYXRlKGNvbmZpZ09wdGlvbnMpIHtcclxuICByZXR1cm4gU3RyaWN0Q29uZmlnU2NoZW1hLnBhcnRpYWwoKS5wYXJzZShjb25maWdPcHRpb25zKTtcclxufVxyXG5cclxuLyoqXHJcbiAqIFZhbGlkYXRlcyB0aGUgY29uZmlndXJhdGlvbiBvcHRpb25zIHVzaW5nIHRoZSBgTG9vc2VDb25maWdTY2hlbWFgLlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gbG9vc2VWYWxpZGF0ZVxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gY29uZmlnT3B0aW9ucyAtIFRoZSBjb25maWd1cmF0aW9uIG9wdGlvbnMgdG8gdmFsaWRhdGUuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtPYmplY3R9IFRoZSBwYXJzZWQgYW5kIHZhbGlkYXRlZCBjb25maWd1cmF0aW9uIG9wdGlvbnMuXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gbG9vc2VWYWxpZGF0ZShjb25maWdPcHRpb25zKSB7XHJcbiAgcmV0dXJuIExvb3NlQ29uZmlnU2NoZW1hLnBhcnRpYWwoKS5wYXJzZShjb25maWdPcHRpb25zKTtcclxufVxyXG5cclxuLyoqXHJcbiAqIEN1c3RvbSBlcnJvciBtYXBwaW5nIGZ1bmN0aW9uIGZvciBab2Qgc2NoZW1hIHZhbGlkYXRpb24uXHJcbiAqXHJcbiAqIFRoaXMgZnVuY3Rpb24gY3VzdG9taXplcyB0aGUgZXJyb3IgbWVzc2FnZXMgcHJvZHVjZWQgYnkgWm9kIHNjaGVtYVxyXG4gKiB2YWxpZGF0aW9uLCBwcm92aWRpbmcgbW9yZSBzcGVjaWZpYyBhbmQgdXNlci1mcmllbmRseSBmZWVkYmFjayBiYXNlZCBvbiB0aGVcclxuICogaXNzdWUgdHlwZSBhbmQgY29udGV4dC5cclxuICpcclxuICogVGhlIGZ1bmN0aW9uIG1vZGlmaWVzIHRoZSBlcnJvciBtZXNzYWdlcyBhcyBmb2xsb3dzOlxyXG4gKlxyXG4gKiAtIEZvciBtaXNzaW5nIHJlcXVpcmVkIHZhbHVlcyAodW5kZWZpbmVkKSwgaXQgcmV0dXJucyBhIG1lc3NhZ2UgaW5kaWNhdGluZ1xyXG4gKiB0aGF0IG5vIHZhbHVlIHdhcyBwcm92aWRlZCBmb3IgdGhlIHNwZWNpZmljIHByb3BlcnR5LlxyXG4gKlxyXG4gKiAtIEZvciBjdXN0b20gdmFsaWRhdGlvbiBlcnJvcnMsIGlmIGEgY3VzdG9tIGVycm9yIG1lc3NhZ2UgaXMgcHJvdmlkZWQgaW4gdGhlXHJcbiAqIGlzc3VlIHBhcmFtZXRlcnMsIGl0IGluY2x1ZGVzIHRoaXMgbWVzc2FnZSBhbG9uZyB3aXRoIHRoZSBpbnZhbGlkIGRhdGFcclxuICogcmVjZWl2ZWQuXHJcbiAqXHJcbiAqIC0gRm9yIGFsbCBvdGhlciBlcnJvcnMsIGl0IGFwcGVuZHMgcHJvcGVydHktc3BlY2lmaWMgaW5mb3JtYXRpb24gdG8gdGhlXHJcbiAqIGRlZmF1bHQgZXJyb3IgbWVzc2FnZSBwcm92aWRlZCBieSBab2QuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBfY3VzdG9tRXJyb3JNYXBcclxuICpcclxuICogQHBhcmFtIHt6LlpvZElzc3VlfSBpc3N1ZSAtIFRoZSBpc3N1ZSBvYmplY3QgcmVwcmVzZW50aW5nIHRoZSB2YWxpZGF0aW9uXHJcbiAqIGVycm9yLlxyXG4gKiBAcGFyYW0ge09iamVjdH0gY29udGV4dCAtIFRoZSBjb250ZXh0IG9iamVjdCBwcm92aWRpbmcgYWRkaXRpb25hbCBpbmZvcm1hdGlvblxyXG4gKiBhYm91dCB0aGUgdmFsaWRhdGlvbiBlcnJvci5cclxuICpcclxuICogQHJldHVybnMge09iamVjdH0gQW4gb2JqZWN0IGNvbnRhaW5pbmcgdGhlIGN1c3RvbWl6ZWQgZXJyb3IgbWVzc2FnZS5cclxuICovXHJcbmZ1bmN0aW9uIF9jdXN0b21FcnJvck1hcChpc3N1ZSwgY29udGV4dCkge1xyXG4gIC8vIEdldCB0aGUgY2hhaW4gb2YgcHJvcGVydGllcyB3aGljaCBlcnJvciBkaXJlY3RseSByZWZlcnMgdG9cclxuICBjb25zdCBwcm9wZXJ0eU5hbWUgPSBpc3N1ZS5wYXRoLmpvaW4oJy4nKTtcclxuXHJcbiAgLy8gQ3JlYXRlIHRoZSBmaXJzdCBwYXJ0IG9mIHRoZSBtZXNzYWdlIGFib3V0IHRoZSBwcm9wZXJ0eSBpbmZvcm1hdGlvblxyXG4gIGNvbnN0IHByb3BlcnR5SW5mbyA9IGBJbnZhbGlkIHZhbHVlIGZvciB0aGUgJHtwcm9wZXJ0eU5hbWV9YDtcclxuXHJcbiAgLy8gTW9kaWZpZWQgbWVzc2FnZSBmb3IgdGhlIGludmFsaWQgdHlwZVxyXG4gIGlmIChpc3N1ZS5jb2RlID09PSB6LlpvZElzc3VlQ29kZS5pbnZhbGlkX3R5cGUpIHtcclxuICAgIC8vIE1vZGlmaWVkIG1lc3NhZ2UgZm9yIHRoZSByZXF1aXJlZCB2YWx1ZXNcclxuICAgIGlmIChpc3N1ZS5yZWNlaXZlZCA9PT0gei5ab2RQYXJzZWRUeXBlLnVuZGVmaW5lZCkge1xyXG4gICAgICByZXR1cm4ge1xyXG4gICAgICAgIG1lc3NhZ2U6IGAke3Byb3BlcnR5SW5mb30gLSBObyB2YWx1ZSB3YXMgcHJvdmlkZWQuYFxyXG4gICAgICB9O1xyXG4gICAgfVxyXG5cclxuICAgIC8vIE1vZGlmaWVkIG1lc3NhZ2UgZm9yIHRoZSBzcGVjaWZpYyBpbnZhbGlkIHR5cGUgd2hlbiB2YWx1ZXMgZXhpc3RcclxuICAgIHJldHVybiB7XHJcbiAgICAgIG1lc3NhZ2U6IGAke3Byb3BlcnR5SW5mb30gLSBJbnZhbGlkIHR5cGUuICR7Y29udGV4dC5kZWZhdWx0RXJyb3J9LmBcclxuICAgIH07XHJcbiAgfVxyXG5cclxuICAvLyBNb2RpZmllZCBtZXNzYWdlIGZvciB0aGUgY3VzdG9tIHZhbGlkYXRpb25cclxuICBpZiAoaXNzdWUuY29kZSA9PT0gei5ab2RJc3N1ZUNvZGUuY3VzdG9tKSB7XHJcbiAgICAvLyBJZiB0aGUgY3VzdG9tIG1lc3NhZ2UgZm9yIGVycm9yIGV4aXN0LCBpbmNsdWRlIGl0XHJcbiAgICBpZiAoaXNzdWUucGFyYW1zPy5lcnJvck1lc3NhZ2UpIHtcclxuICAgICAgcmV0dXJuIHtcclxuICAgICAgICBtZXNzYWdlOiBgJHtwcm9wZXJ0eUluZm99IC0gJHtpc3N1ZS5wYXJhbXM/LmVycm9yTWVzc2FnZX0sIHJlY2VpdmVkICcke2NvbnRleHQuZGF0YX0nLmBcclxuICAgICAgfTtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIC8vIE1vZGlmaWVkIG1lc3NhZ2UgZm9yIHRoZSBpbnZhbGlkIHVuaW9uIGVycm9yXHJcbiAgaWYgKGlzc3VlLmNvZGUgPT09IHouWm9kSXNzdWVDb2RlLmludmFsaWRfdW5pb24pIHtcclxuICAgIC8vIENyZWF0ZSB0aGUgZmlyc3QgcGFydCBvZiB0aGUgbWVzc2FnZSBhYm91dCB0aGUgbXVsdGlwbGUgZXJyb3JzXHJcbiAgICBsZXQgbWVzc2FnZSA9IGBNdWx0aXBsZSBlcnJvcnMgb2NjdXJyZWQgZm9yIHRoZSAke3Byb3BlcnR5TmFtZX06XFxuYDtcclxuXHJcbiAgICAvLyBDeWNsZSB0aHJvdWdoIGFsbCBlcnJvcnMgYW5kIGNyZWF0ZSBhIGNvcnJlY3QgbWVzc2FnZVxyXG4gICAgaXNzdWUudW5pb25FcnJvcnMuZm9yRWFjaCgodmFsdWUpID0+IHtcclxuICAgICAgY29uc3QgaW5kZXggPSB2YWx1ZS5pc3N1ZXNbMF0ubWVzc2FnZS5pbmRleE9mKCctJyk7XHJcbiAgICAgIG1lc3NhZ2UgKz1cclxuICAgICAgICBpbmRleCAhPT0gLTFcclxuICAgICAgICAgID8gYCR7dmFsdWUuaXNzdWVzWzBdLm1lc3NhZ2V9XFxuYC5zdWJzdHJpbmcoaW5kZXgpXHJcbiAgICAgICAgICA6IGAke3ZhbHVlLmlzc3Vlc1swXS5tZXNzYWdlfVxcbmA7XHJcbiAgICB9KTtcclxuXHJcbiAgICAvLyBSZXR1cm4gdGhlIGZpbmFsIG1lc3NhZ2UgZm9yIHRoZSBpbnZhbGlkIHVuaW9uIGVycm9yXHJcbiAgICByZXR1cm4ge1xyXG4gICAgICBtZXNzYWdlXHJcbiAgICB9O1xyXG4gIH1cclxuXHJcbiAgLy8gUmV0dXJuIHRoZSBkZWZhdWx0IGVycm9yIG1lc3NhZ2UsIGV4dGVuZGVkIGJ5IHRoZSBpbmZvIGFib3V0IHRoZSBwcm9wZXJ0eVxyXG4gIHJldHVybiB7XHJcbiAgICBtZXNzYWdlOiBgJHtwcm9wZXJ0eUluZm99IC0gJHtjb250ZXh0LmRlZmF1bHRFcnJvcn0uYFxyXG4gIH07XHJcbn1cclxuXHJcbmV4cG9ydCBkZWZhdWx0IHtcclxuICB2YWxpZGF0b3JzLFxyXG4gIFN0cmljdENvbmZpZ1NjaGVtYSxcclxuICBMb29zZUNvbmZpZ1NjaGVtYSxcclxuICBFbnZTY2hlbWEsXHJcbiAgZW52cyxcclxuICBzdHJpY3RWYWxpZGF0ZSxcclxuICBsb29zZVZhbGlkYXRlXHJcbn07XHJcbiIsIi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXHJcblxyXG5IaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXJcclxuXHJcbkNvcHlyaWdodCAoYykgMjAxNi0yMDI1LCBIaWdoc29mdFxyXG5cclxuTGljZW5jZWQgdW5kZXIgdGhlIE1JVCBsaWNlbmNlLlxyXG5cclxuQWRkaXRpb25hbGx5IGEgdmFsaWQgSGlnaGNoYXJ0cyBsaWNlbnNlIGlzIHJlcXVpcmVkIGZvciB1c2UuXHJcblxyXG5TZWUgTElDRU5TRSBmaWxlIGluIHJvb3QgZm9yIGRldGFpbHMuXHJcblxyXG4qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xyXG5cclxuLyoqXHJcbiAqIEEgY3VzdG9tIGVycm9yIGNsYXNzIGZvciBoYW5kbGluZyBleHBvcnQtcmVsYXRlZCBlcnJvcnMuIEV4dGVuZHMgdGhlIG5hdGl2ZVxyXG4gKiBgRXJyb3JgIGNsYXNzIHRvIGluY2x1ZGUgYWRkaXRpb25hbCBwcm9wZXJ0aWVzIGxpa2Ugc3RhdHVzIGNvZGUgYW5kIHN0YWNrXHJcbiAqIHRyYWNlIGRldGFpbHMuXHJcbiAqL1xyXG5jbGFzcyBFeHBvcnRFcnJvciBleHRlbmRzIEVycm9yIHtcclxuICAvKipcclxuICAgKiBDcmVhdGVzIGFuIGluc3RhbmNlIG9mIHRoZSBgRXhwb3J0RXJyb3JgLlxyXG4gICAqXHJcbiAgICogQHBhcmFtIHtzdHJpbmd9IG1lc3NhZ2UgLSBUaGUgZXJyb3IgbWVzc2FnZSB0byBiZSBkaXNwbGF5ZWQuXHJcbiAgICogQHBhcmFtIHtudW1iZXJ9IHN0YXR1c0NvZGUgLSBPcHRpb25hbCBIVFRQIHN0YXR1cyBjb2RlIGFzc29jaWF0ZWRcclxuICAgKiB3aXRoIHRoZSBlcnJvciAoZS5nLiwgNDAwLCA1MDApLlxyXG4gICAqL1xyXG4gIGNvbnN0cnVjdG9yKG1lc3NhZ2UsIHN0YXR1c0NvZGUpIHtcclxuICAgIHN1cGVyKCk7XHJcblxyXG4gICAgLy8gU2V0IHRoZSBgbWVzc2FnZWAgYW5kIGBzdGFja01lc3NhZ2VgIHdpdGggcHJvdmlkZWQgbWVzc2FnZVxyXG4gICAgdGhpcy5tZXNzYWdlID0gbWVzc2FnZTtcclxuICAgIHRoaXMuc3RhY2tNZXNzYWdlID0gbWVzc2FnZTtcclxuXHJcbiAgICAvLyBTZXQgdGhlIGBzdGF0dXNDb2RlYCBpZiBwcm92aWRlZFxyXG4gICAgaWYgKHN0YXR1c0NvZGUpIHtcclxuICAgICAgdGhpcy5zdGF0dXNDb2RlID0gc3RhdHVzQ29kZTtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIC8qKlxyXG4gICAqIFNldHMgYWRkaXRpb25hbCBlcnJvciBkZXRhaWxzIGJhc2VkIG9uIGFuIGV4aXN0aW5nIGVycm9yIG9iamVjdC5cclxuICAgKlxyXG4gICAqIEBwYXJhbSB7RXJyb3J9IGVycm9yIC0gQW4gZXJyb3Igb2JqZWN0IGNvbnRhaW5pbmcgZGV0YWlscyB0byBwb3B1bGF0ZVxyXG4gICAqIHRoZSBgRXhwb3J0RXJyb3JgIGluc3RhbmNlLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge0V4cG9ydEVycm9yfSBUaGUgdXBkYXRlZCBpbnN0YW5jZSBvZiB0aGUgYEV4cG9ydEVycm9yYCBjbGFzcy5cclxuICAgKi9cclxuICBzZXRFcnJvcihlcnJvcikge1xyXG4gICAgLy8gU2F2ZSB0aGUgcHJvdmlkZWQgZXJyb3JcclxuICAgIHRoaXMuZXJyb3IgPSBlcnJvcjtcclxuXHJcbiAgICAvLyBTZXQgdGhlIGVycm9yJ3MgbmFtZSBpZiBwcmVzZW50XHJcbiAgICBpZiAoZXJyb3IubmFtZSkge1xyXG4gICAgICB0aGlzLm5hbWUgPSBlcnJvci5uYW1lO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIFNldCB0aGUgZXJyb3IncyBzdGF0dXMgY29kZSBpZiBwcmVzZW50XHJcbiAgICBpZiAoZXJyb3Iuc3RhdHVzQ29kZSkge1xyXG4gICAgICB0aGlzLnN0YXR1c0NvZGUgPSBlcnJvci5zdGF0dXNDb2RlO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIFNldCB0aGUgZXJyb3IncyBzdGFjayBhbmQgc3RhY2sncyBtZXNzYWdlIGlmIHByZXNlbnRcclxuICAgIGlmIChlcnJvci5zdGFjaykge1xyXG4gICAgICB0aGlzLnN0YWNrTWVzc2FnZSA9IGVycm9yLm1lc3NhZ2U7XHJcbiAgICAgIHRoaXMuc3RhY2sgPSBlcnJvci5zdGFjaztcclxuICAgIH1cclxuXHJcbiAgICAvLyBSZXR1cm4gdXBkYXRlZCBgRXhwb3J0RXJyb3JgIGluc3RhbmNlXHJcbiAgICByZXR1cm4gdGhpcztcclxuICB9XHJcbn1cclxuXHJcbmV4cG9ydCBkZWZhdWx0IEV4cG9ydEVycm9yO1xyXG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxyXG5cclxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXHJcblxyXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNSwgSGlnaHNvZnRcclxuXHJcbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cclxuXHJcbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxyXG5cclxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxyXG5cclxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cclxuXHJcbi8qKlxyXG4gKiBAb3ZlcnZpZXcgVGhpcyBtb2R1bGUgbWFuYWdlcyBjb25maWd1cmF0aW9uIGZvciB0aGUgSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXHJcbiAqIGJ5IGxvYWRpbmcgYW5kIG1lcmdpbmcgb3B0aW9ucyBmcm9tIG11bHRpcGxlIHNvdXJjZXMsIHN1Y2ggYXMgdGhlIGRlZmF1bHRcclxuICogc2V0dGluZ3MsIGVudmlyb25tZW50IHZhcmlhYmxlcywgdXNlci1wcm92aWRlZCBvcHRpb25zLCBhbmQgY29tbWFuZC1saW5lXHJcbiAqIGFyZ3VtZW50cy4gRW5zdXJlcyB0aGUgZ2xvYmFsIG9wdGlvbnMgYXJlIHVwLXRvLWRhdGUgd2l0aCB0aGUgaGlnaGVzdFxyXG4gKiBwcmlvcml0eSB2YWx1ZXMuIFByb3ZpZGVzIGZ1bmN0aW9ucyBmb3IgYWNjZXNzaW5nIGFuZCB1cGRhdGluZyBjb25maWd1cmF0aW9uLlxyXG4gKi9cclxuXHJcbmltcG9ydCB7IHJlYWRGaWxlU3luYyB9IGZyb20gJ2ZzJztcclxuXHJcbmltcG9ydCB7IGxvZywgbG9nV2l0aFN0YWNrLCBsb2dab2RJc3N1ZXMgfSBmcm9tICcuL2xvZ2dlci5qcyc7XHJcbmltcG9ydCB7IGRlZXBDb3B5LCBnZXRBYnNvbHV0ZVBhdGgsIGlzT2JqZWN0IH0gZnJvbSAnLi91dGlscy5qcyc7XHJcbmltcG9ydCB7XHJcbiAgZW52cyxcclxuICBsb29zZVZhbGlkYXRlLFxyXG4gIHN0cmljdFZhbGlkYXRlLFxyXG4gIHZhbGlkYXRvcnNcclxufSBmcm9tICcuL3ZhbGlkYXRpb24uanMnO1xyXG5cclxuaW1wb3J0IGRlZmF1bHRDb25maWcgZnJvbSAnLi9zY2hlbWFzL2NvbmZpZy5qcyc7XHJcblxyXG5pbXBvcnQgRXhwb3J0RXJyb3IgZnJvbSAnLi9lcnJvcnMvRXhwb3J0RXJyb3IuanMnO1xyXG5cclxuLy8gU2V0cyB0aGUgZ2xvYmFsIG9wdGlvbnMgd2l0aCBpbml0aWFsIHZhbHVlcyBmcm9tIHRoZSBkZWZhdWx0IGNvbmZpZ1xyXG5jb25zdCBnbG9iYWxPcHRpb25zID0gX2luaXRPcHRpb25zKGRlZmF1bHRDb25maWcpO1xyXG5cclxuLy8gUHJvcGVydGllcyBuZXN0aW5nIGxldmVsIG9mIGFsbCBvcHRpb25zXHJcbmNvbnN0IG5lc3RlZFByb3BzID0gX2NyZWF0ZU5lc3RlZFByb3BzKGRlZmF1bHRDb25maWcpO1xyXG5cclxuLy8gUHJvcGVydGllcyBuYW1lcyB0aGF0IHNob3VsZCBub3QgYmUgcmVjdXJzaXZlbHkgbWVyZ2VkXHJcbmNvbnN0IGFic29sdXRlUHJvcHMgPSBfY3JlYXRlQWJzb2x1dGVQcm9wcyhkZWZhdWx0Q29uZmlnKTtcclxuXHJcbi8qKlxyXG4gKiBSZXRyaWV2ZXMgYSBjb3B5IG9mIHRoZSBnbG9iYWwgb3B0aW9ucyBvYmplY3Qgb3IgYW4gb3JpZ2luYWwgZ2xvYmFsIG9wdGlvbnNcclxuICogb2JqZWN0LCBiYXNlZCBvbiB0aGUgYGdldENvcHlgIGZsYWcuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBnZXRPcHRpb25zXHJcbiAqXHJcbiAqIEBwYXJhbSB7Ym9vbGVhbn0gW2dldENvcHk9dHJ1ZV0gLSBTcGVjaWZpZXMgd2hldGhlciB0byByZXR1cm4gYSBjb3BpZWRcclxuICogb2JqZWN0IG9mIHRoZSBnbG9iYWwgb3B0aW9ucyAoYHRydWVgKSBvciBhIHJlZmVyZW5jZSB0byB0aGUgZ2xvYmFsIG9wdGlvbnNcclxuICogb2JqZWN0IChgZmFsc2VgKS4gVGhlIGRlZmF1bHQgdmFsdWUgaXMgYHRydWVgLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7T2JqZWN0fSBBIGNvcHkgb2YgdGhlIGdsb2JhbCBvcHRpb25zIG9iamVjdCwgb3IgYSByZWZlcmVuY2VcclxuICogdG8gdGhlIGdsb2JhbCBvcHRpb25zIG9iamVjdC5cclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiBnZXRPcHRpb25zKGdldENvcHkgPSB0cnVlKSB7XHJcbiAgLy8gUmV0dXJuIGEgY29weSBvciBhbiBvcmlnaW5hbCBnbG9iYWwgb3B0aW9ucyBvYmplY3RcclxuICByZXR1cm4gZ2V0Q29weSA/IGRlZXBDb3B5KGdsb2JhbE9wdGlvbnMpIDogZ2xvYmFsT3B0aW9ucztcclxufVxyXG5cclxuLyoqXHJcbiAqIFVwZGF0ZXMgYW5kIHJldHVybnMgdGhlIGdsb2JhbCBvcHRpb25zIG9iamVjdCBvciBhIGNvcHkgb2YgdGhlIGdsb2JhbCBvcHRpb25zXHJcbiAqIG9iamVjdCwgYmFzZWQgb24gdGhlIGBnZXRDb3B5YCBmbGFnLiBUaGUgYG5ld09wdGlvbnNgIG9iamVjdCBjYW4gYmVcclxuICogc3RyaWN0bHkgdmFsaWRhdGVkIGRlcGVuZGluZyBvbiB0aGUgYHN0cmljdENoZWNrYCBmbGFnLlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gdXBkYXRlT3B0aW9uc1xyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gbmV3T3B0aW9ucyAtIEFuIG9iamVjdCBjb250YWluaW5nIHRoZSBuZXcgb3B0aW9ucyB0byBiZVxyXG4gKiBtZXJnZWQgaW50byB0aGUgZ2xvYmFsIG9wdGlvbnMuXHJcbiAqIEBwYXJhbSB7Ym9vbGVhbn0gW2dldENvcHk9ZmFsc2VdIC0gRGV0ZXJtaW5lcyB3aGV0aGVyIHRvIG1lcmdlIHRoZSBuZXdcclxuICogb3B0aW9ucyBpbnRvIGEgY29weSBvZiB0aGUgZ2xvYmFsIG9wdGlvbnMgb2JqZWN0IChgdHJ1ZWApIG9yIGRpcmVjdGx5IGludG9cclxuICogdGhlIGdsb2JhbCBvcHRpb25zIG9iamVjdCAoYGZhbHNlYCkuIFRoZSBkZWZhdWx0IHZhbHVlIGlzIGBmYWxzZWAuXHJcbiAqIEBwYXJhbSB7Ym9vbGVhbn0gW3N0cmljdENoZWNrPXRydWVdIC0gRGV0ZXJtaW5lcyBpZiBzdHJpY3RlciB2YWxpZGF0aW9uXHJcbiAqIHNob3VsZCBiZSBhcHBsaWVkLiBUaGUgZGVmYXVsdCB2YWx1ZSBpcyBgdHJ1ZWAuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtPYmplY3R9IFRoZSB1cGRhdGVkIG9wdGlvbnMgb2JqZWN0LCBlaXRoZXIgdGhlIG1vZGlmaWVkIGdsb2JhbFxyXG4gKiBvcHRpb25zIG9yIGEgbW9kaWZpZWQgY29weSwgYmFzZWQgb24gdGhlIHZhbHVlIG9mIGBnZXRDb3B5YC5cclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiB1cGRhdGVPcHRpb25zKG5ld09wdGlvbnMsIGdldENvcHkgPSBmYWxzZSwgc3RyaWN0Q2hlY2sgPSB0cnVlKSB7XHJcbiAgLy8gTWVyZ2UgbmV3IG9wdGlvbnMgdG8gdGhlIGdsb2JhbCBvcHRpb25zIG9yIGl0cyBjb3B5IGFuZCByZXR1cm4gdGhlIHJlc3VsdFxyXG4gIHJldHVybiBfbWVyZ2VPcHRpb25zKFxyXG4gICAgLy8gRmlyc3QsIGdldCB0aGUgb3B0aW9uc1xyXG4gICAgZ2V0T3B0aW9ucyhnZXRDb3B5KSxcclxuICAgIC8vIE5leHQsIHZhbGlkYXRlIHRoZSBuZXcgb3B0aW9uc1xyXG4gICAgdmFsaWRhdGVPcHRpb25zKG5ld09wdGlvbnMsIHN0cmljdENoZWNrKVxyXG4gICk7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBVcGRhdGVzIGFuZCByZXR1cm5zIHRoZSBnbG9iYWwgb3B0aW9ucyBvYmplY3Qgd2l0aCB2YWx1ZXMgcHJvdmlkZWQgdGhyb3VnaFxyXG4gKiB0aGUgQ0xJLCBrZWVwaW5nIHRoZSBwcmluY2lwbGUgb2Ygb3B0aW9ucyBsb2FkIHByaW9yaXR5LiBUaGUgZnVuY3Rpb24gYWNjZXB0c1xyXG4gKiBhIGBjbGlBcmdzYCBhcnJheSBjb250YWluaW5nIGFyZ3VtZW50cyBmcm9tIHRoZSBDTEksIHdoaWNoIHdpbGwgYmUgdmFsaWRhdGVkXHJcbiAqIGFuZCBhcHBsaWVkIGlmIHByb3ZpZGVkLlxyXG4gKlxyXG4gKiBUaGUgZnVuY3Rpb24gcHJpb3JpdGl6ZXMgdmFsdWVzIGluIHRoZSBmb2xsb3dpbmcgb3JkZXI6XHJcbiAqXHJcbiAqIDEuIFZhbHVlcyBmcm9tIHRoZSBjb21tYW5kIGxpbmUgaW50ZXJmYWNlIChDTEkpLlxyXG4gKiAyLiBWYWx1ZXMgZnJvbSBhIGN1c3RvbSBKU09OIGZpbGUgKGxvYWRlZCBieSB0aGUgYC0tbG9hZENvbmZpZ2Agb3B0aW9uKS5cclxuICpcclxuICogQGZ1bmN0aW9uIHNldENsaU9wdGlvbnNcclxuICpcclxuICogQHBhcmFtIHtBcnJheTxzdHJpbmc+fSBjbGlBcmdzIC0gQW4gYXJyYXkgb2YgY29tbWFuZCBsaW5lIGFyZ3VtZW50cyB1c2VkXHJcbiAqIGZvciBhZGRpdGlvbmFsIGNvbmZpZ3VyYXRpb24uXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtPYmplY3R9IFRoZSB1cGRhdGVkIGdsb2JhbCBvcHRpb25zIG9iamVjdCwgcmVmbGVjdGluZyB0aGUgbWVyZ2VkXHJcbiAqIGNvbmZpZ3VyYXRpb24gZnJvbSBzb3VyY2VzIHByb3ZpZGVkIHRocm91Z2ggdGhlIENMSS5cclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiBzZXRDbGlPcHRpb25zKGNsaUFyZ3MpIHtcclxuICAvLyBPbmx5IGZvciB0aGUgQ0xJIHVzYWdlXHJcbiAgaWYgKGNsaUFyZ3MgJiYgQXJyYXkuaXNBcnJheShjbGlBcmdzKSAmJiBjbGlBcmdzLmxlbmd0aCkge1xyXG4gICAgdHJ5IHtcclxuICAgICAgLy8gR2V0IG9wdGlvbnMgZnJvbSB0aGUgY3VzdG9tIEpTT04gbG9hZGVkIHZpYSB0aGUgYC0tbG9hZENvbmZpZ2BcclxuICAgICAgY29uc3QgY29uZmlnT3B0aW9ucyA9IF9sb2FkQ29uZmlnRmlsZShjbGlBcmdzKTtcclxuXHJcbiAgICAgIC8vIFVwZGF0ZSBnbG9iYWwgb3B0aW9ucyB3aXRoIHZhbGlkYXRlZCB2YWx1ZXMgZnJvbSB0aGUgYGNvbmZpZ09wdGlvbnNgXHJcbiAgICAgIHVwZGF0ZU9wdGlvbnMoY29uZmlnT3B0aW9ucyk7XHJcbiAgICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgICBsb2coMiwgJ1t2YWxpZGF0aW9uXSBObyBvcHRpb25zIGFkZGVkIGZyb20gdGhlIGAtLWxvYWRDb25maWdgIG9wdGlvbi4nKTtcclxuICAgIH1cclxuXHJcbiAgICB0cnkge1xyXG4gICAgICAvLyBHZXQgb3B0aW9ucyBmcm9tIHRoZSBDTElcclxuICAgICAgY29uc3QgY2xpT3B0aW9ucyA9IF9wYWlyQXJndW1lbnRWYWx1ZShjbGlBcmdzKTtcclxuXHJcbiAgICAgIC8vIFVwZGF0ZSBnbG9iYWwgb3B0aW9ucyB3aXRoIHZhbGlkYXRlZCB2YWx1ZXMgZnJvbSB0aGUgYGNsaU9wdGlvbnNgXHJcbiAgICAgIHVwZGF0ZU9wdGlvbnMoY2xpT3B0aW9ucywgZmFsc2UsIGZhbHNlKTtcclxuICAgIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICAgIGxvZygyLCAnW3ZhbGlkYXRpb25dIE5vIG9wdGlvbnMgYWRkZWQgZnJvbSB0aGUgQ0xJIGFyZ3VtZW50cy4nKTtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIC8vIFJldHVybiByZWZlcmVuY2UgdG8gdGhlIGdsb2JhbCBvcHRpb25zXHJcbiAgcmV0dXJuIGdldE9wdGlvbnMoZmFsc2UpO1xyXG59XHJcblxyXG4vKipcclxuICogTWFwcyBvbGQtc3RydWN0dXJlZCBjb25maWd1cmF0aW9uIG9wdGlvbnMgKFBoYW50b21KUy1iYXNlZCkgdG8gYSBuZXcgZm9ybWF0XHJcbiAqIChQdXBwZXRlZXItYmFzZWQpLiBUaGlzIGZ1bmN0aW9uIGNvbnZlcnRzIGZsYXQsIG9sZC1zdHJ1Y3R1cmVkIG9wdGlvbnMgaW50b1xyXG4gKiBhIG5ldywgbmVzdGVkIGNvbmZpZ3VyYXRpb24gZm9ybWF0IGJhc2VkIG9uIGEgcHJlZGVmaW5lZCBtYXBwaW5nIHByb3ZpZGVkXHJcbiAqIGluIHRoZSBgbmVzdGVkUHJvcHNgIG9iamVjdC4gVGhlIG5ldyBmb3JtYXQgaXMgdXNlZCBmb3IgUHVwcGV0ZWVyLCB3aGlsZVxyXG4gKiB0aGUgb2xkIGZvcm1hdCB3YXMgdXNlZCBmb3IgUGhhbnRvbUpTLlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gbWFwVG9OZXdPcHRpb25zXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBvbGRPcHRpb25zIC0gVGhlIG9sZCwgZmxhdCBjb25maWd1cmF0aW9uIG9wdGlvbnNcclxuICogdG8gYmUgY29udmVydGVkLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7T2JqZWN0fSBBIG5ldyBvYmplY3QgY29udGFpbmluZyBvcHRpb25zIHN0cnVjdHVyZWQgYWNjb3JkaW5nXHJcbiAqIHRvIHRoZSBtYXBwaW5nIGRlZmluZWQgaW4gdGhlIGBuZXN0ZWRQcm9wc2Agb2JqZWN0IG9yIGFuIGVtcHR5IG9iamVjdFxyXG4gKiBpZiB0aGUgcHJvdmlkZWQgYG9sZE9wdGlvbnNgIGlzIG5vdCBhIGNvcnJlY3Qgb2JqZWN0LlxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIG1hcFRvTmV3T3B0aW9ucyhvbGRPcHRpb25zKSB7XHJcbiAgLy8gQW4gb2JqZWN0IGZvciB0aGUgbmV3IHN0cnVjdHVyZWQgb3B0aW9uc1xyXG4gIGNvbnN0IG5ld09wdGlvbnMgPSB7fTtcclxuXHJcbiAgLy8gQ2hlY2sgaWYgcHJvdmlkZWQgdmFsdWUgaXMgYSBjb3JyZWN0IG9iamVjdFxyXG4gIGlmIChpc09iamVjdChvbGRPcHRpb25zKSkge1xyXG4gICAgLy8gSXRlcmF0ZSBvdmVyIGVhY2gga2V5LXZhbHVlIHBhaXIgaW4gdGhlIG9sZC1zdHJ1Y3R1cmVkIG9wdGlvbnNcclxuICAgIGZvciAoY29uc3QgW2tleSwgdmFsdWVdIG9mIE9iamVjdC5lbnRyaWVzKG9sZE9wdGlvbnMpKSB7XHJcbiAgICAgIC8vIElmIHRoZXJlIGlzIGEgbmVzdGVkIG1hcHBpbmcsIHNwbGl0IGl0IGludG8gYSBwcm9wZXJ0aWVzIGNoYWluXHJcbiAgICAgIGNvbnN0IHByb3BlcnRpZXNDaGFpbiA9IG5lc3RlZFByb3BzW2tleV1cclxuICAgICAgICA/IG5lc3RlZFByb3BzW2tleV0uc3BsaXQoJy4nKVxyXG4gICAgICAgIDogW107XHJcblxyXG4gICAgICAvLyBJZiBpdCBpcyB0aGUgbGFzdCBwcm9wZXJ0eSBpbiB0aGUgY2hhaW4sIGFzc2lnbiB0aGUgdmFsdWUsIG90aGVyd2lzZSxcclxuICAgICAgLy8gY3JlYXRlIG9yIHJldXNlIHRoZSBuZXN0ZWQgb2JqZWN0XHJcbiAgICAgIHByb3BlcnRpZXNDaGFpbi5yZWR1Y2UoXHJcbiAgICAgICAgKG9iaiwgcHJvcCwgaW5kZXgpID0+XHJcbiAgICAgICAgICAob2JqW3Byb3BdID1cclxuICAgICAgICAgICAgcHJvcGVydGllc0NoYWluLmxlbmd0aCAtIDEgPT09IGluZGV4ID8gdmFsdWUgOiBvYmpbcHJvcF0gfHwge30pLFxyXG4gICAgICAgIG5ld09wdGlvbnNcclxuICAgICAgKTtcclxuICAgIH1cclxuICB9IGVsc2Uge1xyXG4gICAgbG9nKFxyXG4gICAgICAyLFxyXG4gICAgICAnW2NvbmZpZ10gTm8gY29ycmVjdCBvYmplY3Qgd2l0aCBvcHRpb25zIHdhcyBwcm92aWRlZC4gUmV0dXJuaW5nIGFuIGVtcHR5IG9iamVjdC4nXHJcbiAgICApO1xyXG4gIH1cclxuXHJcbiAgLy8gUmV0dXJuIHRoZSBuZXcsIHN0cnVjdHVyZWQgb3B0aW9ucyBvYmplY3RcclxuICByZXR1cm4gbmV3T3B0aW9ucztcclxufVxyXG5cclxuLyoqXHJcbiAqIFZhbGlkYXRlcyBhIHNwZWNpZmllZCBvcHRpb24gdXNpbmcgdGhlIGNvcnJlc3BvbmRpbmcgdmFsaWRhdG9yIGZyb20gdGhlXHJcbiAqIGNvbmZpZ3VyYXRpb24gb2JqZWN0LiBSZXR1cm5zIHRoZSBvcmlnaW5hbCBvcHRpb24gaWYgdGhlIHZhbGlkYXRpb25cclxuICogaXMgZGlzYWJsZWQgZ2xvYmFsbHkuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiB2YWxpZGF0ZU9wdGlvblxyXG4gKlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gbmFtZSAtIFRoZSBuYW1lIG9mIHRoZSBvcHRpb24gdG8gdmFsaWRhdGUuXHJcbiAqIEBwYXJhbSB7YW55fSBjb25maWdPcHRpb24gLSBUaGUgdmFsdWUgb2YgdGhlIG9wdGlvbiB0byB2YWxpZGF0ZS5cclxuICogQHBhcmFtIHtib29sZWFufSBbc3RyaWN0Q2hlY2s9dHJ1ZV0gLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb25cclxuICogc2hvdWxkIGJlIGFwcGxpZWQuIFRoZSBkZWZhdWx0IHZhbHVlIGlzIGB0cnVlYC5cclxuICpcclxuICogQHJldHVybnMge2FueX0gVGhlIHBhcnNlZCBhbmQgdmFsaWRhdGVkIHZhbHVlIG9mIHRoZSBvcHRpb24uXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gdmFsaWRhdGVPcHRpb24obmFtZSwgY29uZmlnT3B0aW9uLCBzdHJpY3RDaGVjayA9IHRydWUpIHtcclxuICAvLyBSZXR1cm4gdGhlIG9yaWdpbmFsIG9wdGlvbiBpZiB0aGUgdmFsaWRhdGlvbiBpcyBkaXNhYmxlZFxyXG4gIGlmICghZ2V0T3B0aW9ucygpLm90aGVyLnZhbGlkYXRpb24pIHtcclxuICAgIHJldHVybiBjb25maWdPcHRpb247XHJcbiAgfVxyXG5cclxuICB0cnkge1xyXG4gICAgLy8gUmV0dXJuIHZhbGlkYXRlZCBvcHRpb25cclxuICAgIHJldHVybiB2YWxpZGF0b3JzW25hbWVdKHN0cmljdENoZWNrKS5wYXJzZShjb25maWdPcHRpb24pO1xyXG4gIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICAvLyBMb2cgWm9kIGlzc3Vlc1xyXG4gICAgbG9nWm9kSXNzdWVzKFxyXG4gICAgICAxLFxyXG4gICAgICBlcnJvci5pc3N1ZXMsXHJcbiAgICAgIGBbdmFsaWRhdGlvbl0gVGhlICR7bmFtZX0gb3B0aW9uIHZhbGlkYXRpb24gZXJyb3JgXHJcbiAgICApO1xyXG5cclxuICAgIC8vIFRocm93IHZhbGlkYXRpb24gZXJyb3JcclxuICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcihcclxuICAgICAgYFt2YWxpZGF0aW9uXSBUaGUgJHtuYW1lfSBvcHRpb24gdmFsaWRhdGlvbiBlcnJvcmAsXHJcbiAgICAgIDQwMFxyXG4gICAgKTtcclxuICB9XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBWYWxpZGF0ZXMgdGhlIHByb3ZpZGVkIGNvbmZpZ3VyYXRpb24gb3B0aW9ucyBmb3IgdGhlIGV4cG9ydGluZyBwcm9jZXNzLlxyXG4gKiBSZXR1cm5zIHRoZSBvcmlnaW5hbCBvcHRpb24gaWYgdGhlIHZhbGlkYXRpb24gaXMgZGlzYWJsZWQgZ2xvYmFsbHkuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiB2YWxpZGF0ZU9wdGlvbnNcclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IGNvbmZpZ09wdGlvbnMgLSBUaGUgY29uZmlndXJhdGlvbiBvcHRpb25zIHRvIGJlIHZhbGlkYXRlZC5cclxuICogQHBhcmFtIHtib29sZWFufSBbc3RyaWN0Q2hlY2s9dHJ1ZV0gLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb25cclxuICogc2hvdWxkIGJlIGFwcGxpZWQuIFRoZSBkZWZhdWx0IHZhbHVlIGlzIGB0cnVlYC5cclxuICpcclxuICogQHJldHVybnMge09iamVjdH0gVGhlIHBhcnNlZCBhbmQgdmFsaWRhdGVkIGNvbmZpZ3VyYXRpb24gb3B0aW9ucyBvYmplY3QuXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gdmFsaWRhdGVPcHRpb25zKGNvbmZpZ09wdGlvbnMsIHN0cmljdENoZWNrID0gdHJ1ZSkge1xyXG4gIC8vIFJldHVybiB0aGUgb3JpZ2luYWwgY29uZmlnIGlmIHRoZSB2YWxpZGF0aW9uIGlzIGRpc2FibGVkXHJcbiAgaWYgKCFnZXRPcHRpb25zKCkub3RoZXIudmFsaWRhdGlvbikge1xyXG4gICAgcmV0dXJuIGNvbmZpZ09wdGlvbnM7XHJcbiAgfVxyXG5cclxuICB0cnkge1xyXG4gICAgLy8gUmV0dXJuIHZhbGlkYXRlZCBvcHRpb25zXHJcbiAgICByZXR1cm4gc3RyaWN0Q2hlY2tcclxuICAgICAgPyBzdHJpY3RWYWxpZGF0ZShjb25maWdPcHRpb25zKVxyXG4gICAgICA6IGxvb3NlVmFsaWRhdGUoY29uZmlnT3B0aW9ucyk7XHJcbiAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgIC8vIExvZyBab2QgaXNzdWVzXHJcbiAgICBsb2dab2RJc3N1ZXMoMSwgZXJyb3IuaXNzdWVzLCAnW3ZhbGlkYXRpb25dIE9wdGlvbnMgdmFsaWRhdGlvbiBlcnJvcicpO1xyXG5cclxuICAgIC8vIFRocm93IHZhbGlkYXRpb24gZXJyb3JcclxuICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcignW3ZhbGlkYXRpb25dIE9wdGlvbnMgdmFsaWRhdGlvbiBlcnJvcicsIDQwMCk7XHJcbiAgfVxyXG59XHJcblxyXG4vKipcclxuICogVmFsaWRhdGVzLCBwYXJzZXMsIGFuZCBjaGVja3MgaWYgdGhlIHByb3ZpZGVkIGNvbmZpZyBpcyBhbGxvd2VkIHNldFxyXG4gKiBvZiBvcHRpb25zLlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gaXNBbGxvd2VkQ29uZmlnXHJcbiAqXHJcbiAqIEBwYXJhbSB7dW5rbm93bn0gY29uZmlnIC0gVGhlIGNvbmZpZyB0byBiZSB2YWxpZGF0ZWQgYW5kIHBhcnNlZCBhcyBhIHNldFxyXG4gKiBvZiBvcHRpb25zLiBNdXN0IGJlIGVpdGhlciBhbiBvYmplY3Qgb3IgYSBzdHJpbmcuXHJcbiAqIEBwYXJhbSB7Ym9vbGVhbn0gW3RvU3RyaW5nPWZhbHNlXSAtIFdoZXRoZXIgdG8gcmV0dXJuIGEgc3RyaW5naWZpZWQgdmVyc2lvblxyXG4gKiBvZiB0aGUgcGFyc2VkIGNvbmZpZy4gVGhlIGRlZmF1bHQgdmFsdWUgaXMgYGZhbHNlYC5cclxuICogQHBhcmFtIHtib29sZWFufSBbYWxsb3dGdW5jdGlvbnM9ZmFsc2VdIC0gV2hldGhlciB0byBhbGxvdyBmdW5jdGlvbnNcclxuICogaW4gdGhlIHBhcnNlZCBjb25maWcuIElmIGB0cnVlYCwgZnVuY3Rpb25zIGFyZSBwcmVzZXJ2ZWQuIE90aGVyd2lzZSwgd2hlblxyXG4gKiBhIGZ1bmN0aW9uIGlzIGZvdW5kLCBgbnVsbGAgaXMgcmV0dXJuZWQuIFRoZSBkZWZhdWx0IHZhbHVlIGlzIGBmYWxzZWAuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHsoT2JqZWN0fHN0cmluZ3xudWxsKX0gUmV0dXJucyBhIHBhcnNlZCBzZXQgb2Ygb3B0aW9ucyBvYmplY3QsXHJcbiAqIGEgc3RyaW5naWZpZWQgc2V0IG9mIG9wdGlvbnMgb2JqZWN0IGlmIHRoZSBgdG9TdHJpbmdgIGlzIGB0cnVlYCwgYW5kIGBudWxsYFxyXG4gKiBpZiB0aGUgY29uZmlnIGlzIG5vdCBhIHZhbGlkIHNldCBvZiBvcHRpb25zIG9yIHBhcnNpbmcgZmFpbHMuXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gaXNBbGxvd2VkQ29uZmlnKFxyXG4gIGNvbmZpZyxcclxuICB0b1N0cmluZyA9IGZhbHNlLFxyXG4gIGFsbG93RnVuY3Rpb25zID0gZmFsc2VcclxuKSB7XHJcbiAgdHJ5IHtcclxuICAgIC8vIEFjY2VwdCBvbmx5IG9iamVjdHMgYW5kIHN0cmluZ3NcclxuICAgIGlmICghaXNPYmplY3QoY29uZmlnKSAmJiB0eXBlb2YgY29uZmlnICE9PSAnc3RyaW5nJykge1xyXG4gICAgICAvLyBSZXR1cm4gYG51bGxgIGlmIGFueSBvdGhlciB0eXBlXHJcbiAgICAgIHJldHVybiBudWxsO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIEdldCB0aGUgb2JqZWN0IHJlcHJlc2VudGF0aW9uIG9mIHRoZSBvcmlnaW5hbCBjb25maWdcclxuICAgIGNvbnN0IG9iamVjdENvbmZpZyA9XHJcbiAgICAgIHR5cGVvZiBjb25maWcgPT09ICdzdHJpbmcnXHJcbiAgICAgICAgPyBhbGxvd0Z1bmN0aW9uc1xyXG4gICAgICAgICAgPyBldmFsKGAoJHtjb25maWd9KWApXHJcbiAgICAgICAgICA6IEpTT04ucGFyc2UoY29uZmlnKVxyXG4gICAgICAgIDogY29uZmlnO1xyXG5cclxuICAgIC8vIFByZXNlcnZlIG9yIHJlbW92ZSBwb3RlbnRpYWwgZnVuY3Rpb25zIGJhc2VkIG9uIHRoZSBgYWxsb3dGdW5jdGlvbnNgIGZsYWdcclxuICAgIGNvbnN0IHN0cmluZ2lmaWVkT3B0aW9ucyA9IF9vcHRpb25zU3RyaW5naWZ5KFxyXG4gICAgICBvYmplY3RDb25maWcsXHJcbiAgICAgIGFsbG93RnVuY3Rpb25zLFxyXG4gICAgICBmYWxzZVxyXG4gICAgKTtcclxuXHJcbiAgICAvLyBQYXJzZSB0aGUgY29uZmlnIHRvIGNoZWNrIGlmIGl0IGlzIHZhbGlkIHNldCBvZiBvcHRpb25zXHJcbiAgICBjb25zdCBwYXJzZWRPcHRpb25zID0gYWxsb3dGdW5jdGlvbnNcclxuICAgICAgPyBKU09OLnBhcnNlKFxyXG4gICAgICAgICAgX29wdGlvbnNTdHJpbmdpZnkob2JqZWN0Q29uZmlnLCBhbGxvd0Z1bmN0aW9ucywgdHJ1ZSksXHJcbiAgICAgICAgICAoXywgdmFsdWUpID0+XHJcbiAgICAgICAgICAgIHR5cGVvZiB2YWx1ZSA9PT0gJ3N0cmluZycgJiYgdmFsdWUuc3RhcnRzV2l0aCgnZnVuY3Rpb24nKVxyXG4gICAgICAgICAgICAgID8gZXZhbChgKCR7dmFsdWV9KWApXHJcbiAgICAgICAgICAgICAgOiB2YWx1ZVxyXG4gICAgICAgIClcclxuICAgICAgOiBKU09OLnBhcnNlKHN0cmluZ2lmaWVkT3B0aW9ucyk7XHJcblxyXG4gICAgLy8gUmV0dXJuIHN0cmluZ2lmaWVkIG9yIG9iamVjdCBvcHRpb25zIGJhc2VkIG9uIHRoZSBgdG9TdHJpbmdgIGZsYWdcclxuICAgIHJldHVybiB0b1N0cmluZyA/IHN0cmluZ2lmaWVkT3B0aW9ucyA6IHBhcnNlZE9wdGlvbnM7XHJcbiAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgIC8vIFJldHVybiBgbnVsbGAgaWYgcGFyc2luZyBmYWlsc1xyXG4gICAgcmV0dXJuIG51bGw7XHJcbiAgfVxyXG59XHJcblxyXG4vKipcclxuICogSW5pdGlhbGl6ZXMgYW5kIHJldHVybnMgdGhlIGdsb2JhbCBvcHRpb25zIG9iamVjdCBiYXNlZCBvbiB0aGUgcHJvdmlkZWRcclxuICogY29uZmlndXJhdGlvbiwgc2V0dGluZyB2YWx1ZXMgZnJvbSBuZXN0ZWQgcHJvcGVydGllcyByZWN1cnNpdmVseS5cclxuICpcclxuICogVGhlIGZ1bmN0aW9uIHByaW9yaXRpemVzIHZhbHVlcyBpbiB0aGUgZm9sbG93aW5nIG9yZGVyOlxyXG4gKlxyXG4gKiAxLiBWYWx1ZXMgZnJvbSBlbnZpcm9ubWVudCB2YXJpYWJsZXMgKHNwZWNpZmllZCBpbiB0aGUgYC5lbnZgIGZpbGUpLlxyXG4gKiAyLiBWYWx1ZXMgZnJvbSB0aGUgYC4vbGliL3NjaGVtYXMvY29uZmlnLmpzYCBmaWxlIChkZWZhdWx0cykuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBfaW5pdE9wdGlvbnNcclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IGNvbmZpZyAtIFRoZSBjb25maWd1cmF0aW9uIG9iamVjdCB1c2VkIGZvciBpbml0aWFsaXppbmdcclxuICogdGhlIGdsb2JhbCBvcHRpb25zLiBJdCBzaG91bGQgaW5jbHVkZSBuZXN0ZWQgcHJvcGVydGllcyB3aXRoIGEgYHZhbHVlYFxyXG4gKiBhbmQgYW4gYGVudkxpbmtgIGZvciBsaW5raW5nIHRvIGVudmlyb25tZW50IHZhcmlhYmxlcy5cclxuICpcclxuICogQHJldHVybnMge09iamVjdH0gVGhlIGluaXRpYWxpemVkIGdsb2JhbCBvcHRpb25zIG9iamVjdCwgcG9wdWxhdGVkIHdpdGhcclxuICogdmFsdWVzIGJhc2VkIG9uIHRoZSBwcm92aWRlZCBjb25maWd1cmF0aW9uIGFuZCB0aGUgZXN0YWJsaXNoZWQgcHJpb3JpdHlcclxuICogb3JkZXIuXHJcbiAqL1xyXG5mdW5jdGlvbiBfaW5pdE9wdGlvbnMoY29uZmlnKSB7XHJcbiAgLy8gSW5pdCB0aGUgb2JqZWN0IGZvciBvcHRpb25zXHJcbiAgY29uc3Qgb3B0aW9ucyA9IHt9O1xyXG5cclxuICAvLyBTdGFydCBpbml0aWFsaXppbmcgdGhlIGBvcHRpb25zYCBvYmplY3QgcmVjdXJzaXZlbHlcclxuICBmb3IgKGNvbnN0IFtuYW1lLCBpdGVtXSBvZiBPYmplY3QuZW50cmllcyhjb25maWcpKSB7XHJcbiAgICBpZiAoT2JqZWN0LnByb3RvdHlwZS5oYXNPd25Qcm9wZXJ0eS5jYWxsKGl0ZW0sICd2YWx1ZScpKSB7XHJcbiAgICAgIC8vIFNldCB0aGUgY29ycmVjdCB2YWx1ZSBiYXNlZCBvbiB0aGUgZXN0YWJsaXNoZWQgcHJpb3JpdHkgb3JkZXJcclxuICAgICAgaWYgKGVudnNbaXRlbS5lbnZMaW5rXSAhPT0gdW5kZWZpbmVkICYmIGVudnNbaXRlbS5lbnZMaW5rXSAhPT0gbnVsbCkge1xyXG4gICAgICAgIC8vIFRoZSBlbnZpcm9ubWVudCB2YXJpYWJsZXMgdmFsdWVcclxuICAgICAgICBvcHRpb25zW25hbWVdID0gZW52c1tpdGVtLmVudkxpbmtdO1xyXG4gICAgICB9IGVsc2Uge1xyXG4gICAgICAgIC8vIFRoZSB2YWx1ZSBmcm9tIHRoZSBjb25maWcgZmlsZVxyXG4gICAgICAgIG9wdGlvbnNbbmFtZV0gPSBpdGVtLnZhbHVlO1xyXG4gICAgICB9XHJcbiAgICB9IGVsc2Uge1xyXG4gICAgICAvLyBDcmVhdGUgYSBjYXRlZ29yeSBvZiBvcHRpb25zIGluIHRoZSBgb3B0aW9uc2Agb2JqZWN0XHJcbiAgICAgIG9wdGlvbnNbbmFtZV0gPSBfaW5pdE9wdGlvbnMoaXRlbSk7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICAvLyBSZXR1cm4gdGhlIGNyZWF0ZWQgYG9wdGlvbnNgIG9iamVjdFxyXG4gIHJldHVybiBvcHRpb25zO1xyXG59XHJcblxyXG4vKipcclxuICogUmVjdXJzaXZlbHkgbWVyZ2VzIHR3byBzZXRzIG9mIGNvbmZpZ3VyYXRpb24gb3B0aW9ucywgdGFraW5nIGludG8gYWNjb3VudFxyXG4gKiBwcm9wZXJ0aWVzIHNwZWNpZmllZCBpbiB0aGUgYGFic29sdXRlUHJvcHNgIGFycmF5IHRoYXQgcmVxdWlyZSBhYnNvbHV0ZVxyXG4gKiBtZXJnaW5nLiBUaGUgYG9yaWdpbmFsT3B0aW9uc2Agb2JqZWN0IHdpbGwgYmUgZXh0ZW5kZWQgd2l0aCBvcHRpb25zIGZyb21cclxuICogdGhlIGBuZXdPcHRpb25zYCBvYmplY3QuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBfbWVyZ2VPcHRpb25zXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBvcmlnaW5hbE9wdGlvbnMgLSBUaGUgb3JpZ2luYWwgY29uZmlndXJhdGlvbiBvcHRpb25zIG9iamVjdFxyXG4gKiB0byBiZSBleHRlbmRlZC5cclxuICogQHBhcmFtIHtPYmplY3R9IG5ld09wdGlvbnMgLSBUaGUgbmV3IGNvbmZpZ3VyYXRpb24gb3B0aW9ucyBvYmplY3QgdG8gbWVyZ2UuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtPYmplY3R9IFRoZSBleHRlbmRlZCBgb3JpZ2luYWxPcHRpb25zYCBvYmplY3QuXHJcbiAqL1xyXG5mdW5jdGlvbiBfbWVyZ2VPcHRpb25zKG9yaWdpbmFsT3B0aW9ucywgbmV3T3B0aW9ucykge1xyXG4gIC8vIENoZWNrIGlmIHRoZSBgb3JpZ2luYWxPcHRpb25zYCBhbmQgYG5ld09wdGlvbnNgIGFyZSBjb3JyZWN0IG9iamVjdHNcclxuICBpZiAoaXNPYmplY3Qob3JpZ2luYWxPcHRpb25zKSAmJiBpc09iamVjdChuZXdPcHRpb25zKSkge1xyXG4gICAgZm9yIChjb25zdCBba2V5LCB2YWx1ZV0gb2YgT2JqZWN0LmVudHJpZXMobmV3T3B0aW9ucykpIHtcclxuICAgICAgb3JpZ2luYWxPcHRpb25zW2tleV0gPVxyXG4gICAgICAgIGlzT2JqZWN0KHZhbHVlKSAmJlxyXG4gICAgICAgICFhYnNvbHV0ZVByb3BzLmluY2x1ZGVzKGtleSkgJiZcclxuICAgICAgICBvcmlnaW5hbE9wdGlvbnNba2V5XSAhPT0gdW5kZWZpbmVkXHJcbiAgICAgICAgICA/IF9tZXJnZU9wdGlvbnMob3JpZ2luYWxPcHRpb25zW2tleV0sIHZhbHVlKVxyXG4gICAgICAgICAgOiB2YWx1ZSAhPT0gdW5kZWZpbmVkXHJcbiAgICAgICAgICAgID8gdmFsdWVcclxuICAgICAgICAgICAgOiBvcmlnaW5hbE9wdGlvbnNba2V5XSB8fCBudWxsO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgLy8gUmV0dXJuIHRoZSBvcmlnaW5hbCAobW9kaWZpZWQgb3Igbm90KSBvcHRpb25zXHJcbiAgcmV0dXJuIG9yaWdpbmFsT3B0aW9ucztcclxufVxyXG5cclxuLyoqXHJcbiAqIENvbnZlcnRzIHRoZSBwcm92aWRlZCBvcHRpb25zIG9iamVjdCB0byBhIEpTT04gc3RyaW5nIHdpdGggdGhlIG9wdGlvblxyXG4gKiB0byBwcmVzZXJ2ZSBmdW5jdGlvbnMuIEluIG9yZGVyIGZvciBhIGZ1bmN0aW9uIHRvIGJlIHByZXNlcnZlZCwgaXQgbmVlZHNcclxuICogdG8gZm9sbG93IHRoZSBmb3JtYXQgYGZ1bmN0aW9uICguLi4pIHsuLi59YC4gU3VjaCBhIGZ1bmN0aW9uIGNhbiBhbHNvXHJcbiAqIGJlIHN0cmluZ2lmaWVkLlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gX29wdGlvbnNTdHJpbmdpZnlcclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IG9wdGlvbnMgLSBUaGUgb3B0aW9ucyBvYmplY3QgdG8gYmUgY29udmVydGVkIHRvIGEgc3RyaW5nLlxyXG4gKiBAcGFyYW0ge2Jvb2xlYW59IGFsbG93RnVuY3Rpb25zIC0gSWYgc2V0IHRvIGB0cnVlYCwgZnVuY3Rpb25zIGFyZSBwcmVzZXJ2ZWRcclxuICogaW4gdGhlIG91dHB1dC4gT3RoZXJ3aXNlIGFuIGVycm9yIGlzIHRocm93bi5cclxuICogQHBhcmFtIHtib29sZWFufSBzdHJpbmdpZnlGdW5jdGlvbnMgLSBJZiBzZXQgdG8gYHRydWVgLCBmdW5jdGlvbnMgYXJlIHNhdmVkXHJcbiAqIGFzIHN0cmluZ3MuIFRoZSBgYWxsb3dGdW5jdGlvbnNgIG11c3QgYmUgc2V0IHRvIGB0cnVlYCBhcyB3ZWxsIGZvciB0aGlzXHJcbiAqIHRvIHRha2UgYW4gZWZmZWN0LlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7c3RyaW5nfSBUaGUgSlNPTi1mb3JtYXR0ZWQgc3RyaW5nIHJlcHJlc2VudGluZyB0aGUgb3B0aW9ucy5cclxuICpcclxuICogQHRocm93cyB7RXJyb3J9IFRocm93cyBhbiBgRXJyb3JgIHdoZW4gZnVuY3Rpb25zIGFyZSBub3QgYWxsb3dlZCBidXQgYXJlXHJcbiAqIGZvdW5kIGluIHByb3ZpZGVkIG9wdGlvbnMgb2JqZWN0LlxyXG4gKi9cclxuZnVuY3Rpb24gX29wdGlvbnNTdHJpbmdpZnkob3B0aW9ucywgYWxsb3dGdW5jdGlvbnMsIHN0cmluZ2lmeUZ1bmN0aW9ucykge1xyXG4gIGNvbnN0IHJlcGxhY2VyQ2FsbGJhY2sgPSAoXywgdmFsdWUpID0+IHtcclxuICAgIC8vIFRyaW0gc3RyaW5nIHZhbHVlc1xyXG4gICAgaWYgKHR5cGVvZiB2YWx1ZSA9PT0gJ3N0cmluZycpIHtcclxuICAgICAgdmFsdWUgPSB2YWx1ZS50cmltKCk7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gSWYgYHZhbHVlYCBpcyBhIGZ1bmN0aW9uIG9yIHN0cmluZ2lmaWVkIGZ1bmN0aW9uXHJcbiAgICBpZiAoXHJcbiAgICAgIHR5cGVvZiB2YWx1ZSA9PT0gJ2Z1bmN0aW9uJyB8fFxyXG4gICAgICAodHlwZW9mIHZhbHVlID09PSAnc3RyaW5nJyAmJlxyXG4gICAgICAgIHZhbHVlLnN0YXJ0c1dpdGgoJ2Z1bmN0aW9uJykgJiZcclxuICAgICAgICB2YWx1ZS5lbmRzV2l0aCgnfScpKVxyXG4gICAgKSB7XHJcbiAgICAgIC8vIElmIHRoZSBgYWxsb3dGdW5jdGlvbnNgIGlzIHNldCB0byBgdHJ1ZWAsIHByZXNlcnZlIGZ1bmN0aW9uc1xyXG4gICAgICBpZiAoYWxsb3dGdW5jdGlvbnMpIHtcclxuICAgICAgICAvLyBCYXNlZCBvbiB0aGUgYHN0cmluZ2lmeUZ1bmN0aW9uc2Agb3B0aW9ucywgc2V0IGZ1bmN0aW9uIHZhbHVlc1xyXG4gICAgICAgIHJldHVybiBzdHJpbmdpZnlGdW5jdGlvbnNcclxuICAgICAgICAgID8gLy8gQXMgc3RyaW5naWZpZWQgZnVuY3Rpb25zXHJcbiAgICAgICAgICAgIGBcIkVYUF9GVU4keyh2YWx1ZSArICcnKS5yZXBsYWNlQWxsKC9cXHMrL2csICcgJyl9RVhQX0ZVTlwiYFxyXG4gICAgICAgICAgOiAvLyBBcyBmdW5jdGlvbnNcclxuICAgICAgICAgICAgYEVYUF9GVU4keyh2YWx1ZSArICcnKS5yZXBsYWNlQWxsKC9cXHMrL2csICcgJyl9RVhQX0ZVTmA7XHJcbiAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgLy8gVGhyb3cgYW4gZXJyb3Igb3RoZXJ3aXNlXHJcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKCk7XHJcbiAgICAgIH1cclxuICAgIH1cclxuXHJcbiAgICAvLyBJbiBhbGwgb3RoZXIgY2FzZXMsIHNpbXBseSByZXR1cm4gdGhlIHZhbHVlXHJcbiAgICByZXR1cm4gdmFsdWU7XHJcbiAgfTtcclxuXHJcbiAgLy8gU3RyaW5naWZ5IG9wdGlvbnMgYW5kIGlmIHJlcXVpcmVkLCByZXBsYWNlIHNwZWNpYWwgZnVuY3Rpb25zIG1hcmtzXHJcbiAgcmV0dXJuIEpTT04uc3RyaW5naWZ5KG9wdGlvbnMsIHJlcGxhY2VyQ2FsbGJhY2spLnJlcGxhY2VBbGwoXHJcbiAgICBzdHJpbmdpZnlGdW5jdGlvbnMgPyAvXFxcXFwiRVhQX0ZVTnxFWFBfRlVOXFxcXFwiL2cgOiAvXCJFWFBfRlVOfEVYUF9GVU5cIi9nLFxyXG4gICAgJydcclxuICApO1xyXG59XHJcblxyXG4vKipcclxuICogTG9hZHMgYWRkaXRpb25hbCBjb25maWd1cmF0aW9uIGZyb20gYSBzcGVjaWZpZWQgZmlsZSBwcm92aWRlZCB2aWFcclxuICogdGhlIGAtLWxvYWRDb25maWdgIG9wdGlvbiBpbiB0aGUgY29tbWFuZC1saW5lIGFyZ3VtZW50cy5cclxuICpcclxuICogQGZ1bmN0aW9uIF9sb2FkQ29uZmlnRmlsZVxyXG4gKlxyXG4gKiBAcGFyYW0ge0FycmF5PHN0cmluZz59IGNsaUFyZ3MgLSBDb21tYW5kLWxpbmUgYXJndW1lbnRzIHRvIHNlYXJjaFxyXG4gKiBmb3IgdGhlIGAtLWxvYWRDb25maWdgIG9wdGlvbiBhbmQgdGhlIGNvcnJlc3BvbmRpbmcgZmlsZSBwYXRoLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7T2JqZWN0fSBUaGUgYWRkaXRpb25hbCBjb25maWd1cmF0aW9uIGxvYWRlZCBmcm9tIHRoZSBzcGVjaWZpZWRcclxuICogZmlsZSwgb3IgYW4gZW1wdHkgb2JqZWN0IGlmIHRoZSBmaWxlIGlzIG5vdCBmb3VuZCwgaW52YWxpZCwgb3IgYW4gZXJyb3JcclxuICogb2NjdXJzLlxyXG4gKi9cclxuZnVuY3Rpb24gX2xvYWRDb25maWdGaWxlKGNsaUFyZ3MpIHtcclxuICAvLyBHZXQgdGhlIGFsbG93IGZsYWdzIGZvciB0aGUgY3VzdG9tIGxvZ2ljIGNoZWNrXHJcbiAgY29uc3QgeyBhbGxvd0NvZGVFeGVjdXRpb24sIGFsbG93RmlsZVJlc291cmNlcyB9ID0gZ2V0T3B0aW9ucygpLmN1c3RvbUxvZ2ljO1xyXG5cclxuICAvLyBDaGVjayBpZiB0aGUgYC0tbG9hZENvbmZpZ2Agb3B0aW9uIHdhcyB1c2VkXHJcbiAgY29uc3QgY29uZmlnSW5kZXggPSBjbGlBcmdzLmZpbmRJbmRleChcclxuICAgIChhcmcpID0+IGFyZy5yZXBsYWNlKC8tL2csICcnKSA9PT0gJ2xvYWRDb25maWcnXHJcbiAgKTtcclxuXHJcbiAgLy8gR2V0IHRoZSBgLS1sb2FkQ29uZmlnYCBvcHRpb24gdmFsdWVcclxuICBjb25zdCBjb25maWdGaWxlTmFtZSA9IGNvbmZpZ0luZGV4ID4gLTEgJiYgY2xpQXJnc1tjb25maWdJbmRleCArIDFdO1xyXG5cclxuICAvLyBDaGVjayBpZiB0aGUgYC0tbG9hZENvbmZpZ2AgaXMgcHJlc2VudCBhbmQgaGFzIGEgY29ycmVjdCB2YWx1ZVxyXG4gIGlmIChjb25maWdGaWxlTmFtZSAmJiBhbGxvd0ZpbGVSZXNvdXJjZXMpIHtcclxuICAgIHRyeSB7XHJcbiAgICAgIC8vIExvYWQgYW4gb3B0aW9uYWwgY3VzdG9tIEpTT04gY29uZmlnIGZpbGVcclxuICAgICAgcmV0dXJuIGlzQWxsb3dlZENvbmZpZyhcclxuICAgICAgICByZWFkRmlsZVN5bmMoZ2V0QWJzb2x1dGVQYXRoKGNvbmZpZ0ZpbGVOYW1lKSwgJ3V0ZjgnKSxcclxuICAgICAgICBmYWxzZSxcclxuICAgICAgICBhbGxvd0NvZGVFeGVjdXRpb25cclxuICAgICAgKTtcclxuICAgIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICAgIGxvZ1dpdGhTdGFjayhcclxuICAgICAgICAyLFxyXG4gICAgICAgIGVycm9yLFxyXG4gICAgICAgIGBbY29uZmlnXSBVbmFibGUgdG8gbG9hZCB0aGUgY29uZmlndXJhdGlvbiBmcm9tIHRoZSAke2NvbmZpZ0ZpbGVOYW1lfSBmaWxlLmBcclxuICAgICAgKTtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIC8vIE5vIGFkZGl0aW9uYWwgb3B0aW9ucyB0byByZXR1cm5cclxuICByZXR1cm4ge307XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBQYXJzZXMgY29tbWFuZC1saW5lIGFyZ3VtZW50cyBhbmQgcGFpcnMgZWFjaCBhcmd1bWVudCB3aXRoIGl0cyBjb3JyZXNwb25kaW5nXHJcbiAqIG9wdGlvbiBpbiB0aGUgY29uZmlndXJhdGlvbi4gVGhlIHZhbHVlcyBhcmUgc3RydWN0dXJlZCBpbnRvIGEgbmVzdGVkIG9wdGlvbnNcclxuICogb2JqZWN0LCBiYXNlZCBvbiBwcmVkZWZpbmVkIG1hcHBpbmdzIGluIHRoZSBgbmVzdGVkUHJvcHNgIG9iamVjdC5cclxuICpcclxuICogQGZ1bmN0aW9uIF9wYWlyQXJndW1lbnRWYWx1ZVxyXG4gKlxyXG4gKiBAcGFyYW0ge0FycmF5PHN0cmluZz59IGNsaUFyZ3MgLSBBbiBhcnJheSBvZiBjb21tYW5kLWxpbmUgYXJndW1lbnRzXHJcbiAqIGNvbnRhaW5pbmcgb3B0aW9ucyBhbmQgdGhlaXIgYXNzb2NpYXRlZCB2YWx1ZXMuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtPYmplY3R9IEFuIHVwZGF0ZWQgb3B0aW9ucyBvYmplY3Qgd2hlcmUgZWFjaCBvcHRpb24gZnJvbVxyXG4gKiB0aGUgY29tbWFuZC1saW5lIGlzIHBhaXJlZCB3aXRoIGl0cyB2YWx1ZSwgc3RydWN0dXJlZCBpbnRvIG5lc3RlZCBvYmplY3RzXHJcbiAqIGFzIGRlZmluZWQuXHJcbiAqL1xyXG5mdW5jdGlvbiBfcGFpckFyZ3VtZW50VmFsdWUoY2xpQXJncykge1xyXG4gIC8vIEFuIGVtcHR5IG9iamVjdCB0byBjb2xsZWN0IGFuZCBzdHJ1Y3R1cml6ZSBkYXRhIGZyb20gdGhlIGFyZ3NcclxuICBjb25zdCBjbGlPcHRpb25zID0ge307XHJcblxyXG4gIC8vIEN5Y2xlIHRocm91Z2ggYWxsIENMSSBhcmdzIGFuZCBmaWx0ZXIgdGhlbVxyXG4gIGZvciAobGV0IGkgPSAwOyBpIDwgY2xpQXJncy5sZW5ndGg7IGkrKykge1xyXG4gICAgY29uc3Qgb3B0aW9uID0gY2xpQXJnc1tpXS5yZXBsYWNlKC8tL2csICcnKTtcclxuXHJcbiAgICAvLyBGaW5kIHRoZSByaWdodCBwbGFjZSBmb3IgcHJvcGVydHkncyB2YWx1ZVxyXG4gICAgY29uc3QgcHJvcGVydGllc0NoYWluID0gbmVzdGVkUHJvcHNbb3B0aW9uXVxyXG4gICAgICA/IG5lc3RlZFByb3BzW29wdGlvbl0uc3BsaXQoJy4nKVxyXG4gICAgICA6IFtdO1xyXG5cclxuICAgIC8vIENyZWF0ZSBvcHRpb25zIG9iamVjdCB3aXRoIHZhbHVlcyBmcm9tIENMSSBmb3IgbGF0ZXIgcGFyc2luZyBhbmQgbWVyZ2luZ1xyXG4gICAgcHJvcGVydGllc0NoYWluLnJlZHVjZSgob2JqLCBwcm9wLCBpbmRleCkgPT4ge1xyXG4gICAgICBpZiAocHJvcGVydGllc0NoYWluLmxlbmd0aCAtIDEgPT09IGluZGV4KSB7XHJcbiAgICAgICAgY29uc3QgdmFsdWUgPSBjbGlBcmdzWysraV07XHJcbiAgICAgICAgaWYgKCF2YWx1ZSkge1xyXG4gICAgICAgICAgbG9nKFxyXG4gICAgICAgICAgICAyLFxyXG4gICAgICAgICAgICBgW2NvbmZpZ10gTWlzc2luZyB2YWx1ZSBmb3IgdGhlIENMSSAnLS0ke29wdGlvbn0nIGFyZ3VtZW50LiBVc2luZyB0aGUgZGVmYXVsdCB2YWx1ZS5gXHJcbiAgICAgICAgICApO1xyXG4gICAgICAgIH1cclxuICAgICAgICBvYmpbcHJvcF0gPSB2YWx1ZSB8fCBudWxsO1xyXG4gICAgICB9IGVsc2UgaWYgKG9ialtwcm9wXSA9PT0gdW5kZWZpbmVkKSB7XHJcbiAgICAgICAgb2JqW3Byb3BdID0ge307XHJcbiAgICAgIH1cclxuICAgICAgcmV0dXJuIG9ialtwcm9wXTtcclxuICAgIH0sIGNsaU9wdGlvbnMpO1xyXG4gIH1cclxuXHJcbiAgLy8gUmV0dXJuIHBhcnNlZCBDTEkgb3B0aW9uc1xyXG4gIHJldHVybiBjbGlPcHRpb25zO1xyXG59XHJcblxyXG4vKipcclxuICogUmVjdXJzaXZlbHkgZ2VuZXJhdGVzIGEgbWFwcGluZyBvZiBuZXN0ZWQgYXJndW1lbnQgY2hhaW5zIGZyb20gYSBuZXN0ZWRcclxuICogY29uZmlnIG9iamVjdC4gVGhpcyBmdW5jdGlvbiB0cmF2ZXJzZXMgYSBuZXN0ZWQgb2JqZWN0IGFuZCBjcmVhdGVzIGEgbWFwcGluZ1xyXG4gKiB3aGVyZSBlYWNoIGtleSBpcyBhbiBhcmd1bWVudCBuYW1lIChlaXRoZXIgZnJvbSBgY2xpTmFtZWAsIGBsZWdhY3lOYW1lYCxcclxuICogb3IgdGhlIG9yaWdpbmFsIGtleSkgYW5kIGVhY2ggdmFsdWUgaXMgYSBzdHJpbmcgcmVwcmVzZW50aW5nIHRoZSBjaGFpblxyXG4gKiBvZiBuZXN0ZWQgcHJvcGVydGllcyBsZWFkaW5nIHRvIHRoYXQgYXJndW1lbnQuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBfY3JlYXRlTmVzdGVkUHJvcHNcclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IGNvbmZpZyAtIFRoZSBjb25maWd1cmF0aW9uIG9iamVjdC5cclxuICogQHBhcmFtIHtPYmplY3R9IFtuZXN0ZWRQcm9wcz17fV0gLSBUaGUgYWNjdW11bGF0b3Igb2JqZWN0IGZvciBzdG9yaW5nXHJcbiAqIHRoZSByZXN1bHRpbmcgYXJndW1lbnRzIGNoYWlucy4gVGhlIGRlZmF1bHQgdmFsdWUgaXMgYW4gZW1wdHkgb2JqZWN0LlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gW3Byb3BDaGFpbj0nJ10gLSBUaGUgY3VycmVudCBjaGFpbiBvZiBuZXN0ZWQgcHJvcGVydGllcyxcclxuICogdXNlZCBpbnRlcm5hbGx5IGR1cmluZyByZWN1cnNpb24uIFRoZSBkZWZhdWx0IHZhbHVlIGlzIGFuIGVtcHR5IHN0cmluZy5cclxuICpcclxuICogQHJldHVybnMge09iamVjdH0gQW4gb2JqZWN0IG1hcHBpbmcgYXJndW1lbnQgbmFtZXMgdG8gdGhlaXIgY29ycmVzcG9uZGluZ1xyXG4gKiBuZXN0ZWQgcHJvcGVydHkgY2hhaW5zLlxyXG4gKi9cclxuZnVuY3Rpb24gX2NyZWF0ZU5lc3RlZFByb3BzKGNvbmZpZywgbmVzdGVkUHJvcHMgPSB7fSwgcHJvcENoYWluID0gJycpIHtcclxuICBPYmplY3Qua2V5cyhjb25maWcpLmZvckVhY2goKGtleSkgPT4ge1xyXG4gICAgLy8gR2V0IHRoZSBzcGVjaWZpYyBzZWN0aW9uXHJcbiAgICBjb25zdCBlbnRyeSA9IGNvbmZpZ1trZXldO1xyXG5cclxuICAgIC8vIENoZWNrIGlmIHRoZXJlIGlzIHN0aWxsIG1vcmUgZGVwdGggdG8gdHJhdmVyc2VcclxuICAgIGlmICh0eXBlb2YgZW50cnkudmFsdWUgPT09ICd1bmRlZmluZWQnKSB7XHJcbiAgICAgIC8vIFJlY3Vyc2UgaW50byBkZWVwZXIgbGV2ZWxzIG9mIG5lc3RlZCBhcmd1bWVudHNcclxuICAgICAgX2NyZWF0ZU5lc3RlZFByb3BzKGVudHJ5LCBuZXN0ZWRQcm9wcywgYCR7cHJvcENoYWlufS4ke2tleX1gKTtcclxuICAgIH0gZWxzZSB7XHJcbiAgICAgIC8vIENyZWF0ZSB0aGUgY2hhaW4gb2YgbmVzdGVkIGFyZ3VtZW50c1xyXG4gICAgICBuZXN0ZWRQcm9wc1tlbnRyeS5jbGlOYW1lIHx8IGtleV0gPSBgJHtwcm9wQ2hhaW59LiR7a2V5fWAuc3Vic3RyaW5nKDEpO1xyXG5cclxuICAgICAgLy8gU3VwcG9ydCBmb3IgdGhlIGxlZ2FjeSwgUGhhbnRvbUpTIHByb3BlcnRpZXMgbmFtZXNcclxuICAgICAgaWYgKGVudHJ5LmxlZ2FjeU5hbWUgIT09IHVuZGVmaW5lZCkge1xyXG4gICAgICAgIG5lc3RlZFByb3BzW2VudHJ5LmxlZ2FjeU5hbWVdID0gYCR7cHJvcENoYWlufS4ke2tleX1gLnN1YnN0cmluZygxKTtcclxuICAgICAgfVxyXG4gICAgfVxyXG4gIH0pO1xyXG5cclxuICAvLyBSZXR1cm4gdGhlIG9iamVjdCB3aXRoIG5lc3RlZCBhcmd1bWVudCBjaGFpbnNcclxuICByZXR1cm4gbmVzdGVkUHJvcHM7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBSZWN1cnNpdmVseSBnYXRoZXJzIHRoZSBuYW1lcyBvZiBwcm9wZXJ0aWVzIGZyb20gYSBjb25maWd1cmF0aW9uIG9iamVjdCB0aGF0XHJcbiAqIHNob3VsZCBiZSB0cmVhdGVkIGFzIGFic29sdXRlIHByb3BlcnRpZXMuIFRoZXNlIHByb3BlcnRpZXMgaGF2ZSB2YWx1ZXMgdGhhdFxyXG4gKiBhcmUgb2JqZWN0cyBhbmQgZG8gbm90IGNvbnRhaW4gZnVydGhlciBuZXN0ZWQgZGVwdGggd2hlbiBtZXJnaW5nIGFuIG9iamVjdFxyXG4gKiBjb250YWluaW5nIHRoZXNlIG9wdGlvbnMuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBfY3JlYXRlQWJzb2x1dGVQcm9wc1xyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gY29uZmlnIC0gVGhlIGNvbmZpZ3VyYXRpb24gb2JqZWN0LlxyXG4gKiBAcGFyYW0ge0FycmF5PHN0cmluZz59IFthYnNvbHV0ZVByb3BzPVtdXSAtIEFuIGFycmF5IHRvIGNvbGxlY3QgdGhlIG5hbWVzXHJcbiAqIG9mIGFic29sdXRlIHByb3BlcnRpZXMuIFRoZSBkZWZhdWx0IHZhbHVlIGlzIGFuIGVtcHR5IGFycmF5LlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7QXJyYXk8c3RyaW5nPn0gQW4gYXJyYXkgY29udGFpbmluZyB0aGUgbmFtZXMgb2YgYWJzb2x1dGVcclxuICogcHJvcGVydGllcy5cclxuICovXHJcbmZ1bmN0aW9uIF9jcmVhdGVBYnNvbHV0ZVByb3BzKGNvbmZpZywgYWJzb2x1dGVQcm9wcyA9IFtdKSB7XHJcbiAgT2JqZWN0LmtleXMoY29uZmlnKS5mb3JFYWNoKChrZXkpID0+IHtcclxuICAgIC8vIEdldCB0aGUgc3BlY2lmaWMgc2VjdGlvblxyXG4gICAgY29uc3QgZW50cnkgPSBjb25maWdba2V5XTtcclxuXHJcbiAgICAvLyBDaGVjayBpZiB0aGVyZSBpcyBzdGlsbCBtb3JlIGRlcHRoIHRvIHRyYXZlcnNlXHJcbiAgICBpZiAodHlwZW9mIGVudHJ5LnR5cGVzID09PSAndW5kZWZpbmVkJykge1xyXG4gICAgICAvLyBSZWN1cnNlIGludG8gZGVlcGVyIGxldmVsc1xyXG4gICAgICBfY3JlYXRlQWJzb2x1dGVQcm9wcyhlbnRyeSwgYWJzb2x1dGVQcm9wcyk7XHJcbiAgICB9IGVsc2Uge1xyXG4gICAgICAvLyBJZiB0aGUgb3B0aW9uIGNhbiBiZSBhbiBvYmplY3QsIHNhdmUgaXRzIHR5cGUgaW4gdGhlIGFycmF5XHJcbiAgICAgIGlmIChlbnRyeS50eXBlcy5pbmNsdWRlcygnT2JqZWN0JykpIHtcclxuICAgICAgICBhYnNvbHV0ZVByb3BzLnB1c2goa2V5KTtcclxuICAgICAgfVxyXG4gICAgfVxyXG4gIH0pO1xyXG5cclxuICAvLyBSZXR1cm4gdGhlIGFycmF5IHdpdGggdGhlIG5hbWVzIG9mIGFic29sdXRlIHByb3BlcnRpZXNcclxuICByZXR1cm4gYWJzb2x1dGVQcm9wcztcclxufVxyXG5cclxuZXhwb3J0IGRlZmF1bHQge1xyXG4gIGdldE9wdGlvbnMsXHJcbiAgdXBkYXRlT3B0aW9ucyxcclxuICBzZXRDbGlPcHRpb25zLFxyXG4gIG1hcFRvTmV3T3B0aW9ucyxcclxuICB2YWxpZGF0ZU9wdGlvbixcclxuICB2YWxpZGF0ZU9wdGlvbnMsXHJcbiAgaXNBbGxvd2VkQ29uZmlnXHJcbn07XHJcbiIsIi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXHJcblxyXG5IaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXJcclxuXHJcbkNvcHlyaWdodCAoYykgMjAxNi0yMDI1LCBIaWdoc29mdFxyXG5cclxuTGljZW5jZWQgdW5kZXIgdGhlIE1JVCBsaWNlbmNlLlxyXG5cclxuQWRkaXRpb25hbGx5IGEgdmFsaWQgSGlnaGNoYXJ0cyBsaWNlbnNlIGlzIHJlcXVpcmVkIGZvciB1c2UuXHJcblxyXG5TZWUgTElDRU5TRSBmaWxlIGluIHJvb3QgZm9yIGRldGFpbHMuXHJcblxyXG4qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xyXG5cclxuLyoqXHJcbiAqIEBvdmVydmlldyBIVFRQIHV0aWxpdHkgbW9kdWxlIGZvciBmZXRjaGluZyBhbmQgcG9zdGluZyBkYXRhLiBTdXBwb3J0cyBib3RoXHJcbiAqIEhUVFAgYW5kIEhUVFBTIHByb3RvY29scywgcHJvdmlkaW5nIG1ldGhvZHMgdG8gbWFrZSBHRVQgYW5kIFBPU1QgcmVxdWVzdHNcclxuICogd2l0aCBjdXN0b21pemFibGUgb3B0aW9ucy4gSW5jbHVkZXMgcHJvdG9jb2wgZGV0ZXJtaW5hdGlvbiBiYXNlZCBvbiBVUkxcclxuICogYW5kIGF1Z21lbnRzIHJlc3BvbnNlIG9iamVjdHMgd2l0aCBhICd0ZXh0JyBwcm9wZXJ0eSBmb3IgZWFzaWVyIGRhdGEgYWNjZXNzLlxyXG4gKi9cclxuXHJcbmltcG9ydCBodHRwIGZyb20gJ2h0dHAnO1xyXG5pbXBvcnQgaHR0cHMgZnJvbSAnaHR0cHMnO1xyXG5cclxuLyoqXHJcbiAqIFNlbmRzIGEgR0VUIHJlcXVlc3QgdG8gdGhlIHNwZWNpZmllZCBVUkwgdXNpbmcgZWl0aGVyIEhUVFAgb3IgSFRUUFMgcHJvdG9jb2wuXHJcbiAqXHJcbiAqIEBhc3luY1xyXG4gKiBAZnVuY3Rpb24gZ2V0XHJcbiAqXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSB1cmwgLSBUaGUgVVJMIHRvIGdldCBkYXRhIGZyb20uXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBbcmVxdWVzdE9wdGlvbnM9e31dIC0gT3B0aW9ucyBmb3IgdGhlIEhUVFAvSFRUUFMgcmVxdWVzdC5cclxuICogVGhlIGRlZmF1bHQgdmFsdWUgaXMgYW4gZW1wdHkgb2JqZWN0LlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7UHJvbWlzZTxPYmplY3Q+fSBBIFByb21pc2UgdGhhdCByZXNvbHZlcyB0byB0aGUgSFRUUC9IVFRQUyByZXNwb25zZVxyXG4gKiBvYmplY3Qgd2l0aCBhZGRlZCAndGV4dCcgcHJvcGVydHkgb3IgcmVqZWN0aW5nIHdpdGggYW4gZXJyb3IuXHJcbiAqL1xyXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gZ2V0KHVybCwgcmVxdWVzdE9wdGlvbnMgPSB7fSkge1xyXG4gIHJldHVybiBuZXcgUHJvbWlzZSgocmVzb2x2ZSwgcmVqZWN0KSA9PiB7XHJcbiAgICAvLyBEZWNpZGUgb24gdGhlIHByb3RvY29sXHJcbiAgICBfZ2V0UHJvdG9jb2xNb2R1bGUodXJsKVxyXG4gICAgICAuZ2V0KHVybCwgcmVxdWVzdE9wdGlvbnMsIChyZXNwb25zZSkgPT4ge1xyXG4gICAgICAgIGxldCByZXNwb25zZURhdGEgPSAnJztcclxuXHJcbiAgICAgICAgLy8gQSBjaHVuayBvZiBkYXRhIGhhcyBiZWVuIHJlY2VpdmVkXHJcbiAgICAgICAgcmVzcG9uc2Uub24oJ2RhdGEnLCAoY2h1bmspID0+IHtcclxuICAgICAgICAgIHJlc3BvbnNlRGF0YSArPSBjaHVuaztcclxuICAgICAgICB9KTtcclxuXHJcbiAgICAgICAgLy8gVGhlIHdob2xlIHJlc3BvbnNlIGhhcyBiZWVuIHJlY2VpdmVkXHJcbiAgICAgICAgcmVzcG9uc2Uub24oJ2VuZCcsICgpID0+IHtcclxuICAgICAgICAgIGlmICghcmVzcG9uc2VEYXRhKSB7XHJcbiAgICAgICAgICAgIHJlamVjdCgnTm90aGluZyB3YXMgZmV0Y2hlZCBmcm9tIHRoZSBVUkwuJyk7XHJcbiAgICAgICAgICB9XHJcblxyXG4gICAgICAgICAgLy8gR2V0IHRoZSBmdWxsIHJlc3VsdCBhbmQgcmVzb2x2ZSB0aGUgcmVxdWVzdFxyXG4gICAgICAgICAgcmVzcG9uc2UudGV4dCA9IHJlc3BvbnNlRGF0YTtcclxuICAgICAgICAgIHJlc29sdmUocmVzcG9uc2UpO1xyXG4gICAgICAgIH0pO1xyXG4gICAgICB9KVxyXG4gICAgICAub24oJ2Vycm9yJywgKGVycm9yKSA9PiB7XHJcbiAgICAgICAgcmVqZWN0KGVycm9yKTtcclxuICAgICAgfSk7XHJcbiAgfSk7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBTZW5kcyBhIFBPU1QgcmVxdWVzdCB0byB0aGUgc3BlY2lmaWVkIFVSTCB3aXRoIHRoZSBwcm92aWRlZCBKU09OIGJvZHkgdXNpbmdcclxuICogZWl0aGVyIEhUVFAgb3IgSFRUUFMgcHJvdG9jb2wuXHJcbiAqXHJcbiAqIEBhc3luY1xyXG4gKiBAZnVuY3Rpb24gcG9zdFxyXG4gKlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gdXJsIC0gVGhlIFVSTCB0byBzZW5kIHRoZSBQT1NUIHJlcXVlc3QgdG8uXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBbYm9keT17fV0gLSBUaGUgSlNPTiBib2R5IHRvIGluY2x1ZGUgaW4gdGhlIFBPU1QgcmVxdWVzdC5cclxuICogVGhlIGRlZmF1bHQgdmFsdWUgaXMgYW4gZW1wdHkgb2JqZWN0LlxyXG4gKiBAcGFyYW0ge09iamVjdH0gW3JlcXVlc3RPcHRpb25zPXt9XSAtIE9wdGlvbnMgZm9yIHRoZSBIVFRQL0hUVFBTIHJlcXVlc3QuXHJcbiAqIFRoZSBkZWZhdWx0IHZhbHVlIGlzIGFuIGVtcHR5IG9iamVjdC5cclxuICpcclxuICogQHJldHVybnMge1Byb21pc2U8T2JqZWN0Pn0gQSBQcm9taXNlIHRoYXQgcmVzb2x2ZXMgdG8gdGhlIEhUVFAvSFRUUFMgcmVzcG9uc2VcclxuICogb2JqZWN0IHdpdGggYWRkZWQgJ3RleHQnIHByb3BlcnR5IG9yIHJlamVjdGluZyB3aXRoIGFuIGVycm9yLlxyXG4gKi9cclxuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIHBvc3QodXJsLCBib2R5ID0ge30sIHJlcXVlc3RPcHRpb25zID0ge30pIHtcclxuICByZXR1cm4gbmV3IFByb21pc2UoKHJlc29sdmUsIHJlamVjdCkgPT4ge1xyXG4gICAgY29uc3QgZGF0YSA9IEpTT04uc3RyaW5naWZ5KGJvZHkpO1xyXG5cclxuICAgIC8vIFNldCBkZWZhdWx0IGhlYWRlcnMgYW5kIG1lcmdlIHdpdGggYHJlcXVlc3RPcHRpb25zYFxyXG4gICAgY29uc3Qgb3B0aW9ucyA9IE9iamVjdC5hc3NpZ24oXHJcbiAgICAgIHtcclxuICAgICAgICBtZXRob2Q6ICdQT1NUJyxcclxuICAgICAgICBoZWFkZXJzOiB7XHJcbiAgICAgICAgICAnQ29udGVudC1UeXBlJzogJ2FwcGxpY2F0aW9uL2pzb24nLFxyXG4gICAgICAgICAgJ0NvbnRlbnQtTGVuZ3RoJzogZGF0YS5sZW5ndGhcclxuICAgICAgICB9XHJcbiAgICAgIH0sXHJcbiAgICAgIHJlcXVlc3RPcHRpb25zXHJcbiAgICApO1xyXG5cclxuICAgIC8vIERlY2lkZSBvbiB0aGUgcHJvdG9jb2xcclxuICAgIGNvbnN0IHJlcXVlc3QgPSBfZ2V0UHJvdG9jb2xNb2R1bGUodXJsKVxyXG4gICAgICAucmVxdWVzdCh1cmwsIG9wdGlvbnMsIChyZXNwb25zZSkgPT4ge1xyXG4gICAgICAgIGxldCByZXNwb25zZURhdGEgPSAnJztcclxuXHJcbiAgICAgICAgLy8gQSBjaHVuayBvZiBkYXRhIGhhcyBiZWVuIHJlY2VpdmVkXHJcbiAgICAgICAgcmVzcG9uc2Uub24oJ2RhdGEnLCAoY2h1bmspID0+IHtcclxuICAgICAgICAgIHJlc3BvbnNlRGF0YSArPSBjaHVuaztcclxuICAgICAgICB9KTtcclxuXHJcbiAgICAgICAgLy8gVGhlIHdob2xlIHJlc3BvbnNlIGhhcyBiZWVuIHJlY2VpdmVkXHJcbiAgICAgICAgcmVzcG9uc2Uub24oJ2VuZCcsICgpID0+IHtcclxuICAgICAgICAgIHRyeSB7XHJcbiAgICAgICAgICAgIC8vIEdldCB0aGUgZnVsbCByZXN1bHQgYW5kIHJlc29sdmUgdGhlIHJlcXVlc3RcclxuICAgICAgICAgICAgcmVzcG9uc2UudGV4dCA9IHJlc3BvbnNlRGF0YTtcclxuICAgICAgICAgICAgcmVzb2x2ZShyZXNwb25zZSk7XHJcbiAgICAgICAgICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgICAgICAgICByZWplY3QoZXJyb3IpO1xyXG4gICAgICAgICAgfVxyXG4gICAgICAgIH0pO1xyXG4gICAgICB9KVxyXG4gICAgICAub24oJ2Vycm9yJywgKGVycm9yKSA9PiB7XHJcbiAgICAgICAgcmVqZWN0KGVycm9yKTtcclxuICAgICAgfSk7XHJcblxyXG4gICAgLy8gV3JpdGUgdGhlIHJlcXVlc3QgYm9keSBhbmQgZW5kIHRoZSByZXF1ZXN0XHJcbiAgICByZXF1ZXN0LndyaXRlKGRhdGEpO1xyXG4gICAgcmVxdWVzdC5lbmQoKTtcclxuICB9KTtcclxufVxyXG5cclxuLyoqXHJcbiAqIFJldHVybnMgdGhlIEhUVFAgb3IgSFRUUFMgcHJvdG9jb2wgbW9kdWxlIGJhc2VkIG9uIHRoZSBwcm92aWRlZCBVUkwuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBfZ2V0UHJvdG9jb2xNb2R1bGVcclxuICpcclxuICogQHBhcmFtIHtzdHJpbmd9IHVybCAtIFRoZSBVUkwgdG8gZGV0ZXJtaW5lIHRoZSBwcm90b2NvbC5cclxuICpcclxuICogQHJldHVybnMge09iamVjdH0gVGhlIEhUVFAgb3IgSFRUUFMgcHJvdG9jb2wgbW9kdWxlIChgaHR0cGAgb3IgYGh0dHBzYCkuXHJcbiAqL1xyXG5mdW5jdGlvbiBfZ2V0UHJvdG9jb2xNb2R1bGUodXJsKSB7XHJcbiAgcmV0dXJuIHVybC5zdGFydHNXaXRoKCdodHRwcycpID8gaHR0cHMgOiBodHRwO1xyXG59XHJcblxyXG5leHBvcnQgZGVmYXVsdCB7XHJcbiAgZ2V0LFxyXG4gIHBvc3RcclxufTtcclxuIiwiLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcclxuXHJcbkhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlclxyXG5cclxuQ29weXJpZ2h0IChjKSAyMDE2LTIwMjUsIEhpZ2hzb2Z0XHJcblxyXG5MaWNlbmNlZCB1bmRlciB0aGUgTUlUIGxpY2VuY2UuXHJcblxyXG5BZGRpdGlvbmFsbHkgYSB2YWxpZCBIaWdoY2hhcnRzIGxpY2Vuc2UgaXMgcmVxdWlyZWQgZm9yIHVzZS5cclxuXHJcblNlZSBMSUNFTlNFIGZpbGUgaW4gcm9vdCBmb3IgZGV0YWlscy5cclxuXHJcbioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXHJcblxyXG4vKipcclxuICogQG92ZXJ2aWV3IFRoZSBjYWNoZSBtYW5hZ2VyIGlzIHJlc3BvbnNpYmxlIGZvciBoYW5kbGluZyBhbmQgbWFuYWdpbmdcclxuICogdGhlIEhpZ2hjaGFydHMgbGlicmFyeSBhbG9uZyB3aXRoIGl0cyBkZXBlbmRlbmNpZXMuIEl0IGVuc3VyZXMgdGhhdCB0aGVzZVxyXG4gKiByZXNvdXJjZXMgYXJlIHN0b3JlZCBhbmQgcmV0cmlldmVkIGVmZmljaWVudGx5IHRvIG9wdGltaXplIHBlcmZvcm1hbmNlXHJcbiAqIGFuZCByZWR1Y2UgcmVkdW5kYW50IG5ldHdvcmsgcmVxdWVzdHMuIFRoZSBjYWNoZSBpcyBzdG9yZWQgaW4gdGhlIGAuY2FjaGVgXHJcbiAqIGRpcmVjdG9yeSBieSBkZWZhdWx0LCB3aGljaCBzZXJ2ZXMgYXMgYSBkZWRpY2F0ZWQgZm9sZGVyIGZvciBrZWVwaW5nIGNhY2hlZFxyXG4gKiBmaWxlcy5cclxuICovXHJcblxyXG5pbXBvcnQgeyBleGlzdHNTeW5jLCBta2RpclN5bmMsIHJlYWRGaWxlU3luYywgd3JpdGVGaWxlU3luYyB9IGZyb20gJ2ZzJztcclxuaW1wb3J0IHsgam9pbiB9IGZyb20gJ3BhdGgnO1xyXG5cclxuaW1wb3J0IHsgSHR0cHNQcm94eUFnZW50IH0gZnJvbSAnaHR0cHMtcHJveHktYWdlbnQnO1xyXG5cclxuaW1wb3J0IHsgZ2V0T3B0aW9ucywgdXBkYXRlT3B0aW9ucyB9IGZyb20gJy4vY29uZmlnLmpzJztcclxuaW1wb3J0IHsgZ2V0IH0gZnJvbSAnLi9mZXRjaC5qcyc7XHJcbmltcG9ydCB7IGxvZyB9IGZyb20gJy4vbG9nZ2VyLmpzJztcclxuaW1wb3J0IHsgZ2V0QWJzb2x1dGVQYXRoIH0gZnJvbSAnLi91dGlscy5qcyc7XHJcblxyXG5pbXBvcnQgRXhwb3J0RXJyb3IgZnJvbSAnLi9lcnJvcnMvRXhwb3J0RXJyb3IuanMnO1xyXG5cclxuLy8gVGhlIGluaXRpYWwgY2FjaGUgdGVtcGxhdGVcclxuY29uc3QgY2FjaGUgPSB7XHJcbiAgY2RuVXJsOiAnaHR0cHM6Ly9jb2RlLmhpZ2hjaGFydHMuY29tJyxcclxuICBhY3RpdmVNYW5pZmVzdDoge30sXHJcbiAgc291cmNlczogJycsXHJcbiAgaGNWZXJzaW9uOiAnJ1xyXG59O1xyXG5cclxuLyoqXHJcbiAqIENoZWNrcyB0aGUgY2FjaGUgZm9yIEhpZ2hjaGFydHMgZGVwZW5kZW5jaWVzLCB1cGRhdGVzIHRoZSBjYWNoZSBpZiBuZWVkZWQsXHJcbiAqIGFuZCBsb2FkcyB0aGUgc291cmNlcy5cclxuICpcclxuICogQGFzeW5jXHJcbiAqIEBmdW5jdGlvbiBjaGVja0NhY2hlXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBoaWdoY2hhcnRzT3B0aW9ucyAtIFRoZSBjb25maWd1cmF0aW9uIG9iamVjdCBjb250YWluaW5nXHJcbiAqIGBoaWdoY2hhcnRzYCBvcHRpb25zLlxyXG4gKiBAcGFyYW0ge09iamVjdH0gc2VydmVyUHJveHlPcHRpb25zLSBUaGUgY29uZmlndXJhdGlvbiBvYmplY3QgY29udGFpbmluZ1xyXG4gKiBgc2VydmVyLnByb3h5YCBvcHRpb25zLlxyXG4gKi9cclxuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIGNoZWNrQ2FjaGUoaGlnaGNoYXJ0c09wdGlvbnMsIHNlcnZlclByb3h5T3B0aW9ucykge1xyXG4gIHRyeSB7XHJcbiAgICBsZXQgZmV0Y2hlZE1vZHVsZXM7XHJcblxyXG4gICAgLy8gR2V0IHRoZSBjYWNoZSBwYXRoXHJcbiAgICBjb25zdCBjYWNoZVBhdGggPSBnZXRDYWNoZVBhdGgoKTtcclxuXHJcbiAgICAvLyBQcmVwYXJlIHBhdGhzIHRvIG1hbmlmZXN0IGFuZCBzb3VyY2VzIGZyb20gdGhlIGNhY2hlIGZvbGRlclxyXG4gICAgY29uc3QgbWFuaWZlc3RQYXRoID0gam9pbihjYWNoZVBhdGgsICdtYW5pZmVzdC5qc29uJyk7XHJcbiAgICBjb25zdCBzb3VyY2VQYXRoID0gam9pbihjYWNoZVBhdGgsICdzb3VyY2VzLmpzJyk7XHJcblxyXG4gICAgLy8gQ3JlYXRlIHRoZSBjYWNoZSBkZXN0aW5hdGlvbiBpZiBpdCBkb2Vzbid0IGV4aXN0IGFscmVhZHlcclxuICAgICFleGlzdHNTeW5jKGNhY2hlUGF0aCkgJiYgbWtkaXJTeW5jKGNhY2hlUGF0aCwgeyByZWN1cnNpdmU6IHRydWUgfSk7XHJcblxyXG4gICAgLy8gRmV0Y2ggYWxsIHRoZSBzY3JpcHRzIGVpdGhlciBpZiB0aGUgYG1hbmlmZXN0Lmpzb25gIGRvZXMgbm90IGV4aXN0XHJcbiAgICAvLyBvciBpZiB0aGUgYGZvcmNlRmV0Y2hgIG9wdGlvbiBpcyBlbmFibGVkXHJcbiAgICBpZiAoIWV4aXN0c1N5bmMobWFuaWZlc3RQYXRoKSB8fCBoaWdoY2hhcnRzT3B0aW9ucy5mb3JjZUZldGNoKSB7XHJcbiAgICAgIGxvZygzLCAnW2NhY2hlXSBGZXRjaGluZyBhbmQgY2FjaGluZyBIaWdoY2hhcnRzIGRlcGVuZGVuY2llcy4nKTtcclxuXHJcbiAgICAgIC8vIFRoZSBpbml0aWFsIGNhY2hlIHVwZGF0ZVxyXG4gICAgICBmZXRjaGVkTW9kdWxlcyA9IGF3YWl0IF91cGRhdGVDYWNoZShcclxuICAgICAgICBoaWdoY2hhcnRzT3B0aW9ucyxcclxuICAgICAgICBzZXJ2ZXJQcm94eU9wdGlvbnMsXHJcbiAgICAgICAgc291cmNlUGF0aFxyXG4gICAgICApO1xyXG4gICAgfSBlbHNlIHtcclxuICAgICAgbGV0IHJlcXVlc3RVcGRhdGUgPSBmYWxzZTtcclxuXHJcbiAgICAgIC8vIFJlYWQgdGhlIG1hbmlmZXN0IEpTT05cclxuICAgICAgY29uc3QgbWFuaWZlc3QgPSBKU09OLnBhcnNlKHJlYWRGaWxlU3luYyhtYW5pZmVzdFBhdGgpLCAndXRmOCcpO1xyXG5cclxuICAgICAgLy8gQ2hlY2sgaWYgdGhlIG1vZHVsZXMgaXMgYW4gYXJyYXksIGlmIHNvLCB3ZSByZXdyaXRlIGl0IHRvIGEgbWFwIHRvIG1ha2VcclxuICAgICAgLy8gaXQgZWFzaWVyIHRvIHJlc29sdmUgbW9kdWxlc1xyXG4gICAgICBpZiAobWFuaWZlc3QubW9kdWxlcyAmJiBBcnJheS5pc0FycmF5KG1hbmlmZXN0Lm1vZHVsZXMpKSB7XHJcbiAgICAgICAgY29uc3QgbW9kdWxlTWFwID0ge307XHJcbiAgICAgICAgbWFuaWZlc3QubW9kdWxlcy5mb3JFYWNoKChtKSA9PiAobW9kdWxlTWFwW21dID0gMSkpO1xyXG4gICAgICAgIG1hbmlmZXN0Lm1vZHVsZXMgPSBtb2R1bGVNYXA7XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIC8vIEdldCB0aGUgYWN0dWFsIG51bWJlciBvZiBzY3JpcHRzIHRvIGJlIGZldGNoZWRcclxuICAgICAgY29uc3QgeyBjb3JlU2NyaXB0cywgbW9kdWxlU2NyaXB0cywgaW5kaWNhdG9yU2NyaXB0cyB9ID1cclxuICAgICAgICBoaWdoY2hhcnRzT3B0aW9ucztcclxuICAgICAgY29uc3QgbnVtYmVyT2ZNb2R1bGVzID1cclxuICAgICAgICBjb3JlU2NyaXB0cy5sZW5ndGggKyBtb2R1bGVTY3JpcHRzLmxlbmd0aCArIGluZGljYXRvclNjcmlwdHMubGVuZ3RoO1xyXG5cclxuICAgICAgLy8gQ29tcGFyZSB0aGUgbG9hZGVkIGhpZ2hjaGFydHMgY29uZmlnIHdpdGggdGhlIGNvbnRlbnRzIGluIGNhY2hlLlxyXG4gICAgICAvLyBJZiB0aGVyZSBhcmUgY2hhbmdlcywgZmV0Y2ggcmVxdWVzdGVkIG1vZHVsZXMgYW5kIHByb2R1Y3RzLFxyXG4gICAgICAvLyBhbmQgYmFrZSB0aGVtIGludG8gYSBnaWFudCBibG9iLiBTYXZlIHRoZSBibG9iLlxyXG4gICAgICBpZiAobWFuaWZlc3QudmVyc2lvbiAhPT0gaGlnaGNoYXJ0c09wdGlvbnMudmVyc2lvbikge1xyXG4gICAgICAgIC8vIENoZWNrIHRoZSBIaWdoY2hhcnRzIHZlcnNpb25cclxuICAgICAgICBsb2coXHJcbiAgICAgICAgICAyLFxyXG4gICAgICAgICAgJ1tjYWNoZV0gQSBIaWdoY2hhcnRzIHZlcnNpb24gbWlzbWF0Y2ggaW4gdGhlIGNhY2hlLCBuZWVkIHRvIHJlLWZldGNoLidcclxuICAgICAgICApO1xyXG4gICAgICAgIHJlcXVlc3RVcGRhdGUgPSB0cnVlO1xyXG4gICAgICB9IGVsc2UgaWYgKFxyXG4gICAgICAgIE9iamVjdC5rZXlzKG1hbmlmZXN0Lm1vZHVsZXMgfHwge30pLmxlbmd0aCAhPT0gbnVtYmVyT2ZNb2R1bGVzXHJcbiAgICAgICkge1xyXG4gICAgICAgIC8vIENoZWNrIHRoZSBudW1iZXIgb2YgbW9kdWxlc1xyXG4gICAgICAgIGxvZyhcclxuICAgICAgICAgIDIsXHJcbiAgICAgICAgICAnW2NhY2hlXSBUaGUgY2FjaGUgYW5kIHRoZSByZXF1ZXN0ZWQgbW9kdWxlcyBkbyBub3QgbWF0Y2gsIG5lZWQgdG8gcmUtZmV0Y2guJ1xyXG4gICAgICAgICk7XHJcbiAgICAgICAgcmVxdWVzdFVwZGF0ZSA9IHRydWU7XHJcbiAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgLy8gQ2hlY2sgZWFjaCBtb2R1bGUsIGlmIGFueXRoaW5nIGlzIG1pc3NpbmcgcmVmZXRjaCBldmVyeXRoaW5nXHJcbiAgICAgICAgcmVxdWVzdFVwZGF0ZSA9IChtb2R1bGVTY3JpcHRzIHx8IFtdKS5zb21lKChtb2R1bGVOYW1lKSA9PiB7XHJcbiAgICAgICAgICBpZiAoIW1hbmlmZXN0Lm1vZHVsZXNbbW9kdWxlTmFtZV0pIHtcclxuICAgICAgICAgICAgbG9nKFxyXG4gICAgICAgICAgICAgIDIsXHJcbiAgICAgICAgICAgICAgYFtjYWNoZV0gVGhlICR7bW9kdWxlTmFtZX0gaXMgbWlzc2luZyBpbiB0aGUgY2FjaGUsIG5lZWQgdG8gcmUtZmV0Y2guYFxyXG4gICAgICAgICAgICApO1xyXG4gICAgICAgICAgICByZXR1cm4gdHJ1ZTtcclxuICAgICAgICAgIH1cclxuICAgICAgICB9KTtcclxuICAgICAgfVxyXG5cclxuICAgICAgLy8gVXBkYXRlIGNhY2hlIGlmIG5lZWRlZFxyXG4gICAgICBpZiAocmVxdWVzdFVwZGF0ZSkge1xyXG4gICAgICAgIGZldGNoZWRNb2R1bGVzID0gYXdhaXQgX3VwZGF0ZUNhY2hlKFxyXG4gICAgICAgICAgaGlnaGNoYXJ0c09wdGlvbnMsXHJcbiAgICAgICAgICBzZXJ2ZXJQcm94eU9wdGlvbnMsXHJcbiAgICAgICAgICBzb3VyY2VQYXRoXHJcbiAgICAgICAgKTtcclxuICAgICAgfSBlbHNlIHtcclxuICAgICAgICBsb2coMywgJ1tjYWNoZV0gRGVwZW5kZW5jeSBjYWNoZSBpcyB1cCB0byBkYXRlLCBwcm9jZWVkaW5nLicpO1xyXG5cclxuICAgICAgICAvLyBMb2FkIHRoZSBzb3VyY2VzXHJcbiAgICAgICAgY2FjaGUuc291cmNlcyA9IHJlYWRGaWxlU3luYyhzb3VyY2VQYXRoLCAndXRmOCcpO1xyXG5cclxuICAgICAgICAvLyBHZXQgY3VycmVudCBtb2R1bGVzIG1hcFxyXG4gICAgICAgIGZldGNoZWRNb2R1bGVzID0gbWFuaWZlc3QubW9kdWxlcztcclxuXHJcbiAgICAgICAgLy8gRXh0cmFjdCBhbmQgc2F2ZSB2ZXJzaW9uIG9mIGN1cnJlbnRseSB1c2VkIEhpZ2hjaGFydHNcclxuICAgICAgICBjYWNoZS5oY1ZlcnNpb24gPSBfZXh0cmFjdEhjVmVyc2lvbihjYWNoZS5zb3VyY2VzKTtcclxuICAgICAgfVxyXG4gICAgfVxyXG5cclxuICAgIC8vIEZpbmFsbHksIHNhdmUgdGhlIG5ldyBtYW5pZmVzdCwgd2hpY2ggaXMgYmFzaWNhbGx5IG91ciBjdXJyZW50IGNvbmZpZ1xyXG4gICAgLy8gaW4gYSBzbGlnaHRseSBkaWZmZXJlbnQgZm9ybWF0XHJcbiAgICBhd2FpdCBfc2F2ZUNvbmZpZ1RvTWFuaWZlc3QoaGlnaGNoYXJ0c09wdGlvbnMudmVyc2lvbiwgZmV0Y2hlZE1vZHVsZXMpO1xyXG4gIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoXHJcbiAgICAgICdbY2FjaGVdIENvdWxkIG5vdCBjb25maWd1cmUgY2FjaGUgYW5kIGNyZWF0ZSBvciB1cGRhdGUgdGhlIGNvbmZpZyBtYW5pZmVzdC4nLFxyXG4gICAgICA1MDBcclxuICAgICkuc2V0RXJyb3IoZXJyb3IpO1xyXG4gIH1cclxufVxyXG5cclxuLyoqXHJcbiAqIEdldHMgdGhlIHZlcnNpb24gb2YgSGlnaGNoYXJ0cyBmcm9tIHRoZSBjYWNoZS5cclxuICpcclxuICogQGZ1bmN0aW9uIGdldEhjVmVyc2lvblxyXG4gKlxyXG4gKiBAcmV0dXJucyB7c3RyaW5nfSBUaGUgY2FjaGVkIEhpZ2hjaGFydHMgdmVyc2lvbi5cclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiBnZXRIY1ZlcnNpb24oKSB7XHJcbiAgcmV0dXJuIGNhY2hlLmhjVmVyc2lvbjtcclxufVxyXG5cclxuLyoqXHJcbiAqIFVwZGF0ZXMgdGhlIEhpZ2hjaGFydHMgdmVyc2lvbiBpbiB0aGUgYXBwbGllZCBjb25maWd1cmF0aW9uIGFuZCBjaGVja3NcclxuICogdGhlIGNhY2hlIGZvciB0aGUgc2NyaXB0cyBvZiBhIG5ldyB2ZXJzaW9uLlxyXG4gKlxyXG4gKiBAYXN5bmNcclxuICogQGZ1bmN0aW9uIHVwZGF0ZUhjVmVyc2lvblxyXG4gKlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gbmV3VmVyc2lvbiAtIFRoZSBuZXcgSGlnaGNoYXJ0cyB2ZXJzaW9uIHRvIGJlIGFwcGxpZWQuXHJcbiAqL1xyXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gdXBkYXRlSGNWZXJzaW9uKG5ld1ZlcnNpb24pIHtcclxuICAvLyBVcGRhdGUgdG8gdGhlIG5ldyB2ZXJzaW9uXHJcbiAgY29uc3Qgb3B0aW9ucyA9IHVwZGF0ZU9wdGlvbnMoe1xyXG4gICAgaGlnaGNoYXJ0czoge1xyXG4gICAgICB2ZXJzaW9uOiBuZXdWZXJzaW9uXHJcbiAgICB9XHJcbiAgfSk7XHJcblxyXG4gIC8vIENoZWNrIGlmIGNhY2hlIG5lZWRzIHRvIGJlIHVwZGF0ZWRcclxuICBhd2FpdCBjaGVja0NhY2hlKG9wdGlvbnMuaGlnaGNoYXJ0cywgb3B0aW9ucy5zZXJ2ZXIucHJveHkpO1xyXG59XHJcblxyXG4vKipcclxuICogUmV0cmlldmVzIHRoZSBjdXJyZW50IGNhY2hlIG9iamVjdC5cclxuICpcclxuICogQGZ1bmN0aW9uIGdldENhY2hlXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtPYmplY3R9IFRoZSBjYWNoZSBvYmplY3QgY29udGFpbmluZyB2YXJpb3VzIGNhY2hlZCBkYXRhLlxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIGdldENhY2hlKCkge1xyXG4gIHJldHVybiBjYWNoZTtcclxufVxyXG5cclxuLyoqXHJcbiAqIEdldHMgdGhlIGNhY2hlIHBhdGggZm9yIEhpZ2hjaGFydHMuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBnZXRDYWNoZVBhdGhcclxuICpcclxuICogQHJldHVybnMge3N0cmluZ30gVGhlIGFic29sdXRlIHBhdGggdG8gdGhlIGNhY2hlIGRpcmVjdG9yeSBmb3IgSGlnaGNoYXJ0cy5cclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiBnZXRDYWNoZVBhdGgoKSB7XHJcbiAgcmV0dXJuIGdldEFic29sdXRlUGF0aChnZXRPcHRpb25zKCkuaGlnaGNoYXJ0cy5jYWNoZVBhdGgsICd1dGY4Jyk7IC8vICM1NjJcclxufVxyXG5cclxuLyoqXHJcbiAqIFNhdmVzIHRoZSBwcm92aWRlZCBjb25maWd1cmF0aW9uIGFuZCBmZXRjaGVkIG1vZHVsZXMgdG8gdGhlIGNhY2hlIG1hbmlmZXN0XHJcbiAqIGZpbGUuXHJcbiAqXHJcbiAqIEBhc3luY1xyXG4gKiBAZnVuY3Rpb24gX3NhdmVDb25maWdUb01hbmlmZXN0XHJcbiAqXHJcbiAqIEBwYXJhbSB7bnVtYmVyfSB2ZXJzaW9uIC0gVGhlIGN1cnJlbnRseSB1c2VkIEhpZ2hjaGFydHMgdmVyc2lvbi5cclxuICogQHBhcmFtIHtPYmplY3R9IFtmZXRjaGVkTW9kdWxlcz17fV0gLSBBbiBvYmplY3Qgd2hpY2ggdHJhY2tzIHdoaWNoIG1vZHVsZXNcclxuICogaGF2ZSBiZWVuIGZldGNoZWQuIFRoZSBkZWZhdWx0IHZhbHVlIGlzIGFuIGVtcHR5IG9iamVjdC5cclxuICpcclxuICogQHRocm93cyB7RXhwb3J0RXJyb3J9IFRocm93cyBhbiBgRXhwb3J0RXJyb3JgIGlmIGFuIGVycm9yIG9jY3VycyB3aGlsZVxyXG4gKiB3cml0aW5nIHRoZSBjYWNoZSBtYW5pZmVzdC5cclxuICovXHJcbmFzeW5jIGZ1bmN0aW9uIF9zYXZlQ29uZmlnVG9NYW5pZmVzdCh2ZXJzaW9uLCBmZXRjaGVkTW9kdWxlcyA9IHt9KSB7XHJcbiAgLy8gVXBkYXRlIGNhY2hlIG9iamVjdCB3aXRoIHRoZSBjdXJyZW50IG1vZHVsZXNcclxuICBjYWNoZS5hY3RpdmVNYW5pZmVzdCA9IHtcclxuICAgIHZlcnNpb24sXHJcbiAgICBtb2R1bGVzOiBmZXRjaGVkTW9kdWxlc1xyXG4gIH07XHJcblxyXG4gIGxvZygzLCAnW2NhY2hlXSBXcml0aW5nIGEgbmV3IG1hbmlmZXN0LicpO1xyXG4gIHRyeSB7XHJcbiAgICB3cml0ZUZpbGVTeW5jKFxyXG4gICAgICBqb2luKGdldENhY2hlUGF0aCgpLCAnbWFuaWZlc3QuanNvbicpLFxyXG4gICAgICBKU09OLnN0cmluZ2lmeShjYWNoZS5hY3RpdmVNYW5pZmVzdCksXHJcbiAgICAgICd1dGY4J1xyXG4gICAgKTtcclxuICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgdGhyb3cgbmV3IEV4cG9ydEVycm9yKFxyXG4gICAgICAnW2NhY2hlXSBFcnJvciB3cml0aW5nIHRoZSBjYWNoZSBtYW5pZmVzdC4nLFxyXG4gICAgICA1MDBcclxuICAgICkuc2V0RXJyb3IoZXJyb3IpO1xyXG4gIH1cclxufVxyXG5cclxuLyoqXHJcbiAqIFVwZGF0ZXMgdGhlIGxvY2FsIGNhY2hlIHdpdGggSGlnaGNoYXJ0cyBzY3JpcHRzIGNvbnRlbnQgYW5kIGluZm9ybWF0aW9uLFxyXG4gKiBhbmQgdXNlZCBIaWdoY2hhcnRzIHZlcnNpb24uXHJcbiAqXHJcbiAqIEBhc3luY1xyXG4gKiBAZnVuY3Rpb24gX3VwZGF0ZUNhY2hlXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBoaWdoY2hhcnRzT3B0aW9ucyAtIFRoZSBjb25maWd1cmF0aW9uIG9iamVjdCBjb250YWluaW5nXHJcbiAqIGBoaWdoY2hhcnRzYCBvcHRpb25zLlxyXG4gKiBAcGFyYW0ge09iamVjdH0gc2VydmVyUHJveHlPcHRpb25zIC0gVGhlIGNvbmZpZ3VyYXRpb24gb2JqZWN0IGNvbnRhaW5pbmdcclxuICogYHNlcnZlci5wcm94eWAgb3B0aW9ucy5cclxuICogQHBhcmFtIHtzdHJpbmd9IHNvdXJjZVBhdGggLSBUaGUgcGF0aCB0byB0aGUgc291cmNlIGZpbGUgaW4gdGhlIGNhY2hlLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7UHJvbWlzZTxPYmplY3Q+fSBBIFByb21pc2UgdGhhdCByZXNvbHZlcyB0byBhbiBvYmplY3QgcmVwcmVzZW50aW5nXHJcbiAqIHRoZSBmZXRjaGVkIG1vZHVsZXMuXHJcbiAqXHJcbiAqIEB0aHJvd3Mge0V4cG9ydEVycm9yfSBUaHJvd3MgYW4gYEV4cG9ydEVycm9yYCBpZiB0aGVyZSBpcyBhbiBpc3N1ZSB1cGRhdGluZ1xyXG4gKiB0aGUgbG9jYWwgSGlnaGNoYXJ0cyBjYWNoZS5cclxuICovXHJcbmFzeW5jIGZ1bmN0aW9uIF91cGRhdGVDYWNoZShoaWdoY2hhcnRzT3B0aW9ucywgc2VydmVyUHJveHlPcHRpb25zLCBzb3VyY2VQYXRoKSB7XHJcbiAgdHJ5IHtcclxuICAgIC8vIEdldCBIaWdoY2hhcnRzIHZlcnNpb24gZm9yIHNjcmlwdHNcclxuICAgIGNvbnN0IGhjVmVyc2lvbiA9XHJcbiAgICAgIGhpZ2hjaGFydHNPcHRpb25zLnZlcnNpb24gPT09ICdsYXRlc3QnXHJcbiAgICAgICAgPyBudWxsXHJcbiAgICAgICAgOiBgJHtoaWdoY2hhcnRzT3B0aW9ucy52ZXJzaW9ufWA7XHJcblxyXG4gICAgbG9nKFxyXG4gICAgICAzLFxyXG4gICAgICBgW2NhY2hlXSBVcGRhdGluZyBjYWNoZSB2ZXJzaW9uIHRvIEhpZ2hjaGFydHM6ICR7aGNWZXJzaW9uIHx8ICdsYXRlc3QnfS5gXHJcbiAgICApO1xyXG5cclxuICAgIC8vIEdldCB0aGUgQ0ROIHVybCBmb3Igc2NyaXB0c1xyXG4gICAgY29uc3QgY2RuVXJsID0gaGlnaGNoYXJ0c09wdGlvbnMuY2RuVXJsIHx8IGNhY2hlLmNkblVybDtcclxuXHJcbiAgICAvLyBQcmVwYXJlIG9wdGlvbnMgZm9yIGEgcmVxdWVzdFxyXG4gICAgY29uc3QgcmVxdWVzdE9wdGlvbnMgPSBfY29uZmlndXJlUmVxdWVzdChzZXJ2ZXJQcm94eU9wdGlvbnMpO1xyXG5cclxuICAgIC8vIEFuIG9iamVjdCB0byByZWNvcmQgd2hpY2ggc2NyaXB0cyBhcmUgZmV0Y2hlZFxyXG4gICAgY29uc3QgZmV0Y2hlZE1vZHVsZXMgPSB7fTtcclxuXHJcbiAgICAvLyBKb2luIGFsbCBmZXRjaGVkIHNjcmlwdHMgYW5kIHNhdmUgaW4gdGhlIG1hbmlmZXN0J3Mgc291cmNlc1xyXG4gICAgY2FjaGUuc291cmNlcyA9IChcclxuICAgICAgYXdhaXQgUHJvbWlzZS5hbGwoW1xyXG4gICAgICAgIC8vIEhpZ2hjaGFydHMgY29yZSBzY3JpcHRzIGZldGNoXHJcbiAgICAgICAgLi4uaGlnaGNoYXJ0c09wdGlvbnMuY29yZVNjcmlwdHMubWFwKChjcykgPT5cclxuICAgICAgICAgIF9mZXRjaFNjcmlwdChcclxuICAgICAgICAgICAgaGNWZXJzaW9uID8gYCR7Y2RuVXJsfS8ke2hjVmVyc2lvbn0vJHtjc31gIDogYCR7Y2RuVXJsfS8ke2NzfWAsXHJcbiAgICAgICAgICAgIHJlcXVlc3RPcHRpb25zLFxyXG4gICAgICAgICAgICBmZXRjaGVkTW9kdWxlcyxcclxuICAgICAgICAgICAgdHJ1ZVxyXG4gICAgICAgICAgKVxyXG4gICAgICAgICksXHJcbiAgICAgICAgLy8gSGlnaGNoYXJ0cyBtb2R1bGUgc2NyaXB0cyBmZXRjaFxyXG4gICAgICAgIC4uLmhpZ2hjaGFydHNPcHRpb25zLm1vZHVsZVNjcmlwdHMubWFwKChtcykgPT5cclxuICAgICAgICAgIF9mZXRjaFNjcmlwdChcclxuICAgICAgICAgICAgbXMgPT09ICdtYXAnXHJcbiAgICAgICAgICAgICAgPyBoY1ZlcnNpb25cclxuICAgICAgICAgICAgICAgID8gYCR7Y2RuVXJsfS9tYXBzLyR7aGNWZXJzaW9ufS9tb2R1bGVzLyR7bXN9YFxyXG4gICAgICAgICAgICAgICAgOiBgJHtjZG5Vcmx9L21hcHMvbW9kdWxlcy8ke21zfWBcclxuICAgICAgICAgICAgICA6IGhjVmVyc2lvblxyXG4gICAgICAgICAgICAgICAgPyBgJHtjZG5Vcmx9LyR7aGNWZXJzaW9ufS9tb2R1bGVzLyR7bXN9YFxyXG4gICAgICAgICAgICAgICAgOiBgJHtjZG5Vcmx9L21vZHVsZXMvJHttc31gLFxyXG4gICAgICAgICAgICByZXF1ZXN0T3B0aW9ucyxcclxuICAgICAgICAgICAgZmV0Y2hlZE1vZHVsZXNcclxuICAgICAgICAgIClcclxuICAgICAgICApLFxyXG4gICAgICAgIC8vIEhpZ2hjaGFydHMgaW5kaWNhdG9yIHNjcmlwdHMgZmV0Y2hcclxuICAgICAgICAuLi5oaWdoY2hhcnRzT3B0aW9ucy5pbmRpY2F0b3JTY3JpcHRzLm1hcCgoaXMpID0+XHJcbiAgICAgICAgICBfZmV0Y2hTY3JpcHQoXHJcbiAgICAgICAgICAgIGhjVmVyc2lvblxyXG4gICAgICAgICAgICAgID8gYCR7Y2RuVXJsfS9zdG9jay8ke2hjVmVyc2lvbn0vaW5kaWNhdG9ycy8ke2lzfWBcclxuICAgICAgICAgICAgICA6IGAke2NkblVybH0vc3RvY2svaW5kaWNhdG9ycy8ke2lzfWAsXHJcbiAgICAgICAgICAgIHJlcXVlc3RPcHRpb25zLFxyXG4gICAgICAgICAgICBmZXRjaGVkTW9kdWxlc1xyXG4gICAgICAgICAgKVxyXG4gICAgICAgICksXHJcbiAgICAgICAgLy8gQ3VzdG9tIHNjcmlwdHMgZmV0Y2hcclxuICAgICAgICAuLi5oaWdoY2hhcnRzT3B0aW9ucy5jdXN0b21TY3JpcHRzLm1hcCgoY3MpID0+XHJcbiAgICAgICAgICBfZmV0Y2hTY3JpcHQoYCR7Y3N9YCwgcmVxdWVzdE9wdGlvbnMpXHJcbiAgICAgICAgKVxyXG4gICAgICBdKVxyXG4gICAgKS5qb2luKCc7XFxuJyk7XHJcblxyXG4gICAgLy8gRXh0cmFjdCBhbmQgc2F2ZSB2ZXJzaW9uIG9mIGN1cnJlbnRseSB1c2VkIEhpZ2hjaGFydHNcclxuICAgIGNhY2hlLmhjVmVyc2lvbiA9IF9leHRyYWN0SGNWZXJzaW9uKGNhY2hlLnNvdXJjZXMpO1xyXG5cclxuICAgIC8vIFNhdmUgdGhlIGZldGNoZWQgbW9kdWxlcyBpbnRvIGNhY2hlcycgc291cmNlIEpTT05cclxuICAgIHdyaXRlRmlsZVN5bmMoc291cmNlUGF0aCwgY2FjaGUuc291cmNlcyk7XHJcblxyXG4gICAgLy8gUmV0dXJuIHRoZSBmZXRjaGVkIG1vZHVsZXNcclxuICAgIHJldHVybiBmZXRjaGVkTW9kdWxlcztcclxuICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgdGhyb3cgbmV3IEV4cG9ydEVycm9yKFxyXG4gICAgICAnW2NhY2hlXSBVbmFibGUgdG8gdXBkYXRlIHRoZSBsb2NhbCBIaWdoY2hhcnRzIGNhY2hlLicsXHJcbiAgICAgIDUwMFxyXG4gICAgKS5zZXRFcnJvcihlcnJvcik7XHJcbiAgfVxyXG59XHJcblxyXG4vKipcclxuICogRmV0Y2hlcyBhIHNpbmdsZSBzY3JpcHQgYW5kIHVwZGF0ZXMgdGhlIGBmZXRjaGVkTW9kdWxlc2AgYWNjb3JkaW5nbHkuXHJcbiAqXHJcbiAqIEBhc3luY1xyXG4gKiBAZnVuY3Rpb24gX2ZldGNoU2NyaXB0XHJcbiAqXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSBzY3JpcHQgLSBBIHBhdGggdG8gc2NyaXB0IHRvIGdldC5cclxuICogQHBhcmFtIHtPYmplY3R9IHJlcXVlc3RPcHRpb25zIC0gQWRkaXRpb25hbCByZXF1ZXN0cyBvcHRpb25zLlxyXG4gKiBAcGFyYW0ge09iamVjdH0gZmV0Y2hlZE1vZHVsZXMgLSBBbiBvYmplY3Qgd2hpY2ggdHJhY2tzIHdoaWNoIEhpZ2hjaGFydHNcclxuICogbW9kdWxlcyBoYXZlIGJlZW4gZmV0Y2hlZC5cclxuICogQHBhcmFtIHtib29sZWFufSBbc2hvdWxkVGhyb3dFcnJvcj1mYWxzZV0gLSBBIGZsYWcgdG8gaW5kaWNhdGUgaWYgdGhlIGVycm9yXHJcbiAqIHNob3VsZCBiZSB0aHJvd24uIFRoaXMgc2hvdWxkIGJlIHVzZWQgb25seSBmb3IgdGhlIGNvcmUgc2NyaXB0cy4gVGhlIGRlZmF1bHRcclxuICogdmFsdWUgaXMgYGZhbHNlYC5cclxuICpcclxuICogQHJldHVybnMge1Byb21pc2U8c3RyaW5nPn0gQSBQcm9taXNlIHRoYXQgcmVzb2x2ZXMgdG8gdGhlIHRleHQgcmVwcmVzZW50YXRpb25cclxuICogb2YgdGhlIGZldGNoZWQgc2NyaXB0LlxyXG4gKlxyXG4gKiBAdGhyb3dzIHtFeHBvcnRFcnJvcn0gVGhyb3dzIGFuIGBFeHBvcnRFcnJvcmAgaWYgdGhlcmUgaXMgYSBwcm9ibGVtXHJcbiAqIHdpdGggZmV0Y2hpbmcgdGhlIHNjcmlwdC5cclxuICovXHJcbmFzeW5jIGZ1bmN0aW9uIF9mZXRjaFNjcmlwdChcclxuICBzY3JpcHQsXHJcbiAgcmVxdWVzdE9wdGlvbnMsXHJcbiAgZmV0Y2hlZE1vZHVsZXMsXHJcbiAgc2hvdWxkVGhyb3dFcnJvciA9IGZhbHNlXHJcbikge1xyXG4gIC8vIEdldCByaWQgb2YgdGhlIC5qcyBmcm9tIHRoZSBjdXN0b20gc3RyaW5nc1xyXG4gIGlmIChzY3JpcHQuZW5kc1dpdGgoJy5qcycpKSB7XHJcbiAgICBzY3JpcHQgPSBzY3JpcHQuc3Vic3RyaW5nKDAsIHNjcmlwdC5sZW5ndGggLSAzKTtcclxuICB9XHJcbiAgbG9nKDQsIGBbY2FjaGVdIEZldGNoaW5nIHNjcmlwdCAtICR7c2NyaXB0fS5qc2ApO1xyXG5cclxuICAvLyBGZXRjaCB0aGUgc2NyaXB0XHJcbiAgY29uc3QgcmVzcG9uc2UgPSBhd2FpdCBnZXQoYCR7c2NyaXB0fS5qc2AsIHJlcXVlc3RPcHRpb25zKTtcclxuXHJcbiAgLy8gSWYgT0ssIHJldHVybiBpdHMgdGV4dCByZXByZXNlbnRhdGlvblxyXG4gIGlmIChyZXNwb25zZS5zdGF0dXNDb2RlID09PSAyMDAgJiYgdHlwZW9mIHJlc3BvbnNlLnRleHQgPT0gJ3N0cmluZycpIHtcclxuICAgIGlmIChmZXRjaGVkTW9kdWxlcykge1xyXG4gICAgICBjb25zdCBtb2R1bGVOYW1lID0gX2V4dHJhY3RNb2R1bGVOYW1lKHNjcmlwdCk7XHJcbiAgICAgIGZldGNoZWRNb2R1bGVzW21vZHVsZU5hbWVdID0gMTtcclxuICAgIH1cclxuICAgIHJldHVybiByZXNwb25zZS50ZXh0O1xyXG4gIH1cclxuXHJcbiAgLy8gQmFzZWQgb24gdGhlIGBzaG91bGRUaHJvd0Vycm9yYCBmbGFnLCBkZWNpZGUgaG93IHRvIHNlcnZlIGVycm9yIG1lc3NhZ2VcclxuICBpZiAoc2hvdWxkVGhyb3dFcnJvcikge1xyXG4gICAgdGhyb3cgbmV3IEV4cG9ydEVycm9yKFxyXG4gICAgICBgW2NhY2hlXSBDb3VsZCBub3QgZmV0Y2ggdGhlICR7c2NyaXB0fS5qcy4gVGhlIHNjcmlwdCBtaWdodCBub3QgZXhpc3QgaW4gdGhlIHJlcXVlc3RlZCB2ZXJzaW9uIChzdGF0dXMgY29kZTogJHtyZXNwb25zZS5zdGF0dXNDb2RlfSkuYCxcclxuICAgICAgNDA0XHJcbiAgICApLnNldEVycm9yKHJlc3BvbnNlKTtcclxuICB9IGVsc2Uge1xyXG4gICAgbG9nKFxyXG4gICAgICAyLFxyXG4gICAgICBgW2NhY2hlXSBDb3VsZCBub3QgZmV0Y2ggdGhlICR7c2NyaXB0fS5qcy4gVGhlIHNjcmlwdCBtaWdodCBub3QgZXhpc3QgaW4gdGhlIHJlcXVlc3RlZCB2ZXJzaW9uLmBcclxuICAgICk7XHJcbiAgfVxyXG59XHJcblxyXG4vKipcclxuICogQ29uZmlndXJlcyBhIHByb3h5IGFnZW50IGZvciBvdXRnb2luZyBIVFRQIHJlcXVlc3RzIGJhc2VkIG9uIHRoZSBwcm92aWRlZFxyXG4gKiBgc2VydmVyLnByb3h5YCBvcHRpb25zLiBJZiBhIHZhbGlkIGBob3N0YCBhbmQgYHBvcnRgIGFyZSBzcGVjaWZpZWQsIGl0IHRyaWVzXHJcbiAqIHRvIGNyZWF0ZSBhbiBgSHR0cHNQcm94eUFnZW50YC4gSWYgdGhlIGNyZWF0aW9uIGZhaWxzLCBhbiBgRXhwb3J0RXJyb3JgXHJcbiAqIGlzIHRocm93bi4gSWYgbm8gcHJveHkgaXMgY29uZmlndXJlZCwgYW4gZW1wdHkgb2JqZWN0IGlzIHJldHVybmVkLlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gX2NvbmZpZ3VyZVJlcXVlc3RcclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IHNlcnZlclByb3h5T3B0aW9ucy0gVGhlIGNvbmZpZ3VyYXRpb24gb2JqZWN0IGNvbnRhaW5pbmdcclxuICogYHNlcnZlci5wcm94eWAgb3B0aW9ucy5cclxuICpcclxuICogQHJldHVybnMge09iamVjdH0gVGhlIHJlcXVlc3Qgb3B0aW9ucywgaW5jbHVkaW5nIHRoZSBwcm94eSBhZ2VudCBpZiBjcmVhdGVkLFxyXG4gKiBvciBhbiBlbXB0eSBvYmplY3QgaWYgbm8gcHJveHkgY29uZmlndXJhdGlvbiBpcyBwcm92aWRlZC5cclxuICpcclxuICogQHRocm93cyB7RXhwb3J0RXJyb3J9IFRocm93cyBhbiBgRXhwb3J0RXJyb3JgIGlmIHRoZSBwcm94eSBhZ2VudCBjcmVhdGlvblxyXG4gKiBmYWlscy5cclxuICovXHJcbmZ1bmN0aW9uIF9jb25maWd1cmVSZXF1ZXN0KHNlcnZlclByb3h5T3B0aW9ucykge1xyXG4gIC8vIEdldCB0aGUgYGhvc3RgIGFuZCBgcG9ydGAgb2YgdGhlIHByb3h5XHJcbiAgY29uc3QgcHJveHlIb3N0ID0gc2VydmVyUHJveHlPcHRpb25zLmhvc3Q7XHJcbiAgY29uc3QgcHJveHlQb3J0ID0gc2VydmVyUHJveHlPcHRpb25zLnBvcnQ7XHJcblxyXG4gIC8vIFRyeSB0byBjcmVhdGUgYSBwcm94eSBhZ2VudFxyXG4gIGlmIChwcm94eUhvc3QgJiYgcHJveHlQb3J0KSB7XHJcbiAgICB0cnkge1xyXG4gICAgICAvLyBDcmVhdGUgdGhlIGFnZW50XHJcbiAgICAgIGNvbnN0IHByb3h5QWdlbnQgPSBuZXcgSHR0cHNQcm94eUFnZW50KHtcclxuICAgICAgICBob3N0OiBwcm94eUhvc3QsXHJcbiAgICAgICAgcG9ydDogcHJveHlQb3J0XHJcbiAgICAgIH0pO1xyXG5cclxuICAgICAgLy8gQWRkIHRoZSBhZ2VudCB0byB0aGUgcmVxdWVzdCdzIG9wdGlvbnNcclxuICAgICAgcmV0dXJuIHtcclxuICAgICAgICBhZ2VudDogcHJveHlBZ2VudCxcclxuICAgICAgICB0aW1lb3V0OiBzZXJ2ZXJQcm94eU9wdGlvbnMudGltZW91dFxyXG4gICAgICB9O1xyXG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICAgdGhyb3cgbmV3IEV4cG9ydEVycm9yKFxyXG4gICAgICAgICdbY2FjaGVdIENvdWxkIG5vdCBjcmVhdGUgYSBQcm94eSBBZ2VudC4nLFxyXG4gICAgICAgIDUwMFxyXG4gICAgICApLnNldEVycm9yKGVycm9yKTtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIC8vIFJldHVybiBhbiBlbXB0eSBvYmplY3Qgd2hlbiBubyBwcm94eSBhZ2VudCBpcyBjcmVhdGVkXHJcbiAgcmV0dXJuIHt9O1xyXG59XHJcblxyXG4vKipcclxuICogRXh0cmFjdHMgSGlnaGNoYXJ0cyB2ZXJzaW9uIGZyb20gdGhlIGNhY2hlJ3Mgc291cmNlcyBzdHJpbmcuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBfZXh0cmFjdEhjVmVyc2lvblxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gY2FjaGVTb3VyY2VzIC0gVGhlIGNhY2hlIHNvdXJjZXMgb2JqZWN0LlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7c3RyaW5nfSBUaGUgZXh0cmFjdGVkIEhpZ2hjaGFydHMgdmVyc2lvbi5cclxuICovXHJcbmZ1bmN0aW9uIF9leHRyYWN0SGNWZXJzaW9uKGNhY2hlU291cmNlcykge1xyXG4gIHJldHVybiBjYWNoZVNvdXJjZXNcclxuICAgIC5zdWJzdHJpbmcoMCwgY2FjaGVTb3VyY2VzLmluZGV4T2YoJyovJykpXHJcbiAgICAucmVwbGFjZSgnLyonLCAnJylcclxuICAgIC5yZXBsYWNlKCcqLycsICcnKVxyXG4gICAgLnJlcGxhY2UoL1xcbi9nLCAnJylcclxuICAgIC50cmltKCk7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBFeHRyYWN0cyB0aGUgSGlnaGNoYXJ0cyBtb2R1bGUgbmFtZSBiYXNlZCBvbiB0aGUgYHNjcmlwdFBhdGhgIHByb3BlcnR5LlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gX2V4dHJhY3RNb2R1bGVOYW1lXHJcbiAqXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSBzY3JpcHRQYXRoIC0gVGhlIHBhdGggb2YgdGhlIHNjcmlwdCBmcm9tIHdoaWNoIHRoZSBtb2R1bGVcclxuICogbmFtZSB3aWxsIGJlIGV4dHJhY3RlZC5cclxuICpcclxuICogQHJldHVybnMge3N0cmluZ30gVGhlIGV4dHJhY3RlZCBtb2R1bGUgbmFtZS5cclxuICovXHJcbmZ1bmN0aW9uIF9leHRyYWN0TW9kdWxlTmFtZShzY3JpcHRQYXRoKSB7XHJcbiAgcmV0dXJuIHNjcmlwdFBhdGgucmVwbGFjZShcclxuICAgIC8oLiopXFwvfCguKiltb2R1bGVzXFwvfHN0b2NrXFwvKC4qKWluZGljYXRvcnNcXC98bWFwc1xcLyguKiltb2R1bGVzXFwvL2dpLFxyXG4gICAgJydcclxuICApO1xyXG59XHJcblxyXG5leHBvcnQgZGVmYXVsdCB7XHJcbiAgY2hlY2tDYWNoZSxcclxuICBnZXRIY1ZlcnNpb24sXHJcbiAgdXBkYXRlSGNWZXJzaW9uLFxyXG4gIGdldENhY2hlLFxyXG4gIGdldENhY2hlUGF0aFxyXG59O1xyXG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxyXG5cclxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXHJcblxyXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNSwgSGlnaHNvZnRcclxuXHJcbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cclxuXHJcbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxyXG5cclxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxyXG5cclxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cclxuXHJcbi8qKlxyXG4gKiBAb3ZlcnZpZXcgUHJvdmlkZXMgbWV0aG9kcyBmb3IgaW5pdGlhbGl6aW5nIEhpZ2hjaGFydHMgd2l0aCBjdXN0b21pemVkXHJcbiAqIGFuaW1hdGlvbiBzZXR0aW5ncyBhbmQgdHJpZ2dlcmluZyB0aGUgY3JlYXRpb24gb2YgSGlnaGNoYXJ0cyBjaGFydHMgd2l0aFxyXG4gKiBleHBvcnQtc3BlY2lmaWMgY29uZmlndXJhdGlvbnMgaW4gdGhlIHBhZ2UgY29udGV4dC4gU3VwcG9ydHMgZHluYW1pYyBvcHRpb25cclxuICogbWVyZ2luZywgY3VzdG9tIGxvZ2ljIGluamVjdGlvbiwgYW5kIGNvbnRyb2wgb3ZlciByZW5kZXJpbmcgYmVoYXZpb3JzLiBVc2VkXHJcbiAqIGJ5IHRoZSBQdXBwZXRlZXIgcGFnZS5cclxuICovXHJcblxyXG4vKiBlc2xpbnQtZGlzYWJsZSBuby11bmRlZiAqL1xyXG5cclxuLyoqXHJcbiAqIFNldHRpbmcgdGhlIGBIaWdoY2hhcnRzLmFuaW1PYmplY3RgIGZ1bmN0aW9uLiBDYWxsZWQgd2hlbiBpbml0aW5nIHRoZSBwYWdlLlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gc2V0dXBIaWdoY2hhcnRzXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gc2V0dXBIaWdoY2hhcnRzKCkge1xyXG4gIEhpZ2hjaGFydHMuYW5pbU9iamVjdCA9IGZ1bmN0aW9uICgpIHtcclxuICAgIHJldHVybiB7IGR1cmF0aW9uOiAwIH07XHJcbiAgfTtcclxufVxyXG5cclxuLyoqXHJcbiAqIENyZWF0ZXMgdGhlIGFjdHVhbCBIaWdoY2hhcnRzIGNoYXJ0IG9uIGEgcGFnZS5cclxuICpcclxuICogQGFzeW5jXHJcbiAqIEBmdW5jdGlvbiBjcmVhdGVDaGFydFxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gZXhwb3J0T3B0aW9ucyAtIFRoZSBjb25maWd1cmF0aW9uIG9iamVjdCBjb250YWluaW5nIGBleHBvcnRgXHJcbiAqIG9wdGlvbnMuXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBjdXN0b21Mb2dpY09wdGlvbnMgLSBUaGUgY29uZmlndXJhdGlvbiBvYmplY3QgY29udGFpbmluZ1xyXG4gKiBgY3VzdG9tTG9naWNgIG9wdGlvbnMuXHJcbiAqXHJcbiAqL1xyXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gY3JlYXRlQ2hhcnQoZXhwb3J0T3B0aW9ucywgY3VzdG9tTG9naWNPcHRpb25zKSB7XHJcbiAgLy8gR2V0IHJlcXVpcmVkIGZ1bmN0aW9uc1xyXG4gIGNvbnN0IHsgZ2V0T3B0aW9ucywgc2V0T3B0aW9ucywgbWVyZ2UsIHdyYXAgfSA9IEhpZ2hjaGFydHM7XHJcblxyXG4gIC8vIENyZWF0ZSBhIHNlcGFyYXRlIG9iamVjdCBmb3IgYSBwb3RlbnRpYWwgYHNldE9wdGlvbnNgIHVzYWdlcyBpbiBvcmRlclxyXG4gIC8vIHRvIHByZXZlbnQgZnJvbSBwb2xsdXRpbmcgb3RoZXIgZXhwb3J0cyB0aGF0IGNhbiBoYXBwZW4gb24gdGhlIHNhbWUgcGFnZVxyXG4gIEhpZ2hjaGFydHMuc2V0T3B0aW9uc09iaiA9IG1lcmdlKGZhbHNlLCB7fSwgZ2V0T3B0aW9ucygpKTtcclxuXHJcbiAgLy8gTk9URTogSXMgdGhpcyB1c2VkIGZvciBhbnl0aGluZyB1c2VmdWw/XHJcbiAgd2luZG93LmlzUmVuZGVyQ29tcGxldGUgPSBmYWxzZTtcclxuICB3cmFwKEhpZ2hjaGFydHMuQ2hhcnQucHJvdG90eXBlLCAnaW5pdCcsIGZ1bmN0aW9uIChwcm9jZWVkLCB1c2VyT3B0aW9ucywgY2IpIHtcclxuICAgIC8vIE92ZXJyaWRlIHRoZSBgdXNlck9wdGlvbnNgIHdpdGggaW1hZ2UgZnJpZW5kbHkgb3B0aW9uc1xyXG4gICAgdXNlck9wdGlvbnMgPSBtZXJnZSh1c2VyT3B0aW9ucywge1xyXG4gICAgICBleHBvcnRpbmc6IHtcclxuICAgICAgICBlbmFibGVkOiBmYWxzZVxyXG4gICAgICB9LFxyXG4gICAgICBwbG90T3B0aW9uczoge1xyXG4gICAgICAgIHNlcmllczoge1xyXG4gICAgICAgICAgbGFiZWw6IHtcclxuICAgICAgICAgICAgZW5hYmxlZDogZmFsc2VcclxuICAgICAgICAgIH1cclxuICAgICAgICB9XHJcbiAgICAgIH0sXHJcbiAgICAgIC8qIEV4cGVjdHMgdG9vbHRpcCBpbiB0aGUgYHVzZXJPcHRpb25zYCB3aGVuIGBmb3JFeHBvcnRgIGlzIHRydWUuXHJcbiAgICAgICAgaHR0cHM6Ly9naXRodWIuY29tL2hpZ2hjaGFydHMvaGlnaGNoYXJ0cy9ibG9iLzNhZDQzMGEzNTNiODA1NmI5ZTc2NGFhNGU1Y2Q2ODI4YWE0NzlkYjIvanMvcGFydHMvQ2hhcnQuanMjTDI0MVxyXG4gICAgICAgICovXHJcbiAgICAgIHRvb2x0aXA6IHt9XHJcbiAgICB9KTtcclxuXHJcbiAgICAodXNlck9wdGlvbnMuc2VyaWVzIHx8IFtdKS5mb3JFYWNoKGZ1bmN0aW9uIChzZXJpZXMpIHtcclxuICAgICAgc2VyaWVzLmFuaW1hdGlvbiA9IGZhbHNlO1xyXG4gICAgfSk7XHJcblxyXG4gICAgLy8gQWRkIGZsYWcgdG8ga25vdyBpZiBjaGFydCByZW5kZXIgaGFzIGJlZW4gY2FsbGVkLlxyXG4gICAgaWYgKCF3aW5kb3cub25IaWdoY2hhcnRzUmVuZGVyKSB7XHJcbiAgICAgIHdpbmRvdy5vbkhpZ2hjaGFydHNSZW5kZXIgPSBIaWdoY2hhcnRzLmFkZEV2ZW50KHRoaXMsICdyZW5kZXInLCAoKSA9PiB7XHJcbiAgICAgICAgd2luZG93LmlzUmVuZGVyQ29tcGxldGUgPSB0cnVlO1xyXG4gICAgICB9KTtcclxuICAgIH1cclxuXHJcbiAgICBwcm9jZWVkLmFwcGx5KHRoaXMsIFt1c2VyT3B0aW9ucywgY2JdKTtcclxuICB9KTtcclxuXHJcbiAgd3JhcChIaWdoY2hhcnRzLlNlcmllcy5wcm90b3R5cGUsICdpbml0JywgZnVuY3Rpb24gKHByb2NlZWQsIGNoYXJ0LCBvcHRpb25zKSB7XHJcbiAgICBwcm9jZWVkLmFwcGx5KHRoaXMsIFtjaGFydCwgb3B0aW9uc10pO1xyXG4gIH0pO1xyXG5cclxuICAvLyBTb21lIG1hbmRhdG9yeSBhZGRpdGlvbmFsIGBjaGFydGAgYW5kIGBleHBvcnRpbmdgIG9wdGlvbnNcclxuICBjb25zdCBhZGRpdGlvbmFsT3B0aW9ucyA9IHtcclxuICAgIGNoYXJ0OiB7XHJcbiAgICAgIC8vIEJ5IGRlZmF1bHQgYW5pbWF0aW9uIGlzIGRpc2FibGVkXHJcbiAgICAgIGFuaW1hdGlvbjogZmFsc2UsXHJcbiAgICAgIC8vIEdldCB0aGUgcmlnaHQgc2l6ZSB2YWx1ZXNcclxuICAgICAgaGVpZ2h0OiBleHBvcnRPcHRpb25zLmhlaWdodCxcclxuICAgICAgd2lkdGg6IGV4cG9ydE9wdGlvbnMud2lkdGhcclxuICAgIH0sXHJcbiAgICBleHBvcnRpbmc6IHtcclxuICAgICAgLy8gTm8gbmVlZCBmb3IgdGhlIGV4cG9ydGluZyBidXR0b25cclxuICAgICAgZW5hYmxlZDogZmFsc2VcclxuICAgIH1cclxuICB9O1xyXG5cclxuICAvLyBHZXQgdGhlIGlucHV0IHRvIGV4cG9ydCBmcm9tIHRoZSBgaW5zdHJgIG9wdGlvblxyXG4gIGNvbnN0IHVzZXJPcHRpb25zID0gbmV3IEZ1bmN0aW9uKGByZXR1cm4gJHtleHBvcnRPcHRpb25zLmluc3RyfWApKCk7XHJcblxyXG4gIC8vIEdldCB0aGUgYHRoZW1lT3B0aW9uc2Agb3B0aW9uXHJcbiAgY29uc3QgdGhlbWVPcHRpb25zID0gbmV3IEZ1bmN0aW9uKGByZXR1cm4gJHtleHBvcnRPcHRpb25zLnRoZW1lT3B0aW9uc31gKSgpO1xyXG5cclxuICAvLyBNZXJnZSB0aGUgZm9sbG93aW5nIG9wdGlvbnMgb2JqZWN0cyB0byBjcmVhdGUgZmluYWwgb3B0aW9uc1xyXG4gIGNvbnN0IGZpbmFsT3B0aW9ucyA9IG1lcmdlKFxyXG4gICAgZmFsc2UsXHJcbiAgICB0aGVtZU9wdGlvbnMsXHJcbiAgICB1c2VyT3B0aW9ucyxcclxuICAgIC8vIFBsYWNlZCBpdCBoZXJlIGluc3RlYWQgaW4gdGhlIGluaXQgYmVjYXVzZSBvZiB0aGUgc2l6ZSBpc3N1ZXNcclxuICAgIGFkZGl0aW9uYWxPcHRpb25zXHJcbiAgKTtcclxuXHJcbiAgLy8gUHJlcGFyZSB0aGUgYGNhbGxiYWNrYCBvcHRpb25cclxuICBjb25zdCBmaW5hbENhbGxiYWNrID0gY3VzdG9tTG9naWNPcHRpb25zLmNhbGxiYWNrXHJcbiAgICA/IG5ldyBGdW5jdGlvbihgcmV0dXJuICR7Y3VzdG9tTG9naWNPcHRpb25zLmNhbGxiYWNrfWApKClcclxuICAgIDogbnVsbDtcclxuXHJcbiAgLy8gVHJpZ2dlciB0aGUgYGN1c3RvbUNvZGVgIG9wdGlvblxyXG4gIGlmIChjdXN0b21Mb2dpY09wdGlvbnMuY3VzdG9tQ29kZSkge1xyXG4gICAgbmV3IEZ1bmN0aW9uKCdvcHRpb25zJywgY3VzdG9tTG9naWNPcHRpb25zLmN1c3RvbUNvZGUpKHVzZXJPcHRpb25zKTtcclxuICB9XHJcblxyXG4gIC8vIEdldCB0aGUgYGdsb2JhbE9wdGlvbnNgIG9wdGlvblxyXG4gIGNvbnN0IGdsb2JhbE9wdGlvbnMgPSBuZXcgRnVuY3Rpb24oYHJldHVybiAke2V4cG9ydE9wdGlvbnMuZ2xvYmFsT3B0aW9uc31gKSgpO1xyXG5cclxuICAvLyBTZXQgdGhlIGdsb2JhbCBvcHRpb25zIGlmIGV4aXN0XHJcbiAgaWYgKGdsb2JhbE9wdGlvbnMpIHtcclxuICAgIHNldE9wdGlvbnMoZ2xvYmFsT3B0aW9ucyk7XHJcbiAgfVxyXG5cclxuICAvLyBDYWxsIHRoZSBjaGFydCBjcmVhdGlvblxyXG4gIEhpZ2hjaGFydHNbZXhwb3J0T3B0aW9ucy5jb25zdHJdKCdjb250YWluZXInLCBmaW5hbE9wdGlvbnMsIGZpbmFsQ2FsbGJhY2spO1xyXG5cclxuICAvLyBHZXQgYWxsIGltYWdlcyBmcm9tIHdpdGhpbiB0aGUgY2hhcnRcclxuICBjb25zdCBpbWFnZXMgPSBBcnJheS5mcm9tKFxyXG4gICAgZG9jdW1lbnQucXVlcnlTZWxlY3RvckFsbCgnLmhpZ2hjaGFydHMtY29udGFpbmVyIGltYWdlJylcclxuICApO1xyXG5cclxuICAvLyBXYWl0IGZvciBhbGwgaW1hZ2VzIGZvciAyIHNlY29uZHNcclxuICBhd2FpdCBQcm9taXNlLnJhY2UoW1xyXG4gICAgUHJvbWlzZS5hbGwoXHJcbiAgICAgIGltYWdlcy5tYXAoKGltYWdlKSA9PlxyXG4gICAgICAgIGltYWdlLmNvbXBsZXRlICYmIGltYWdlLm5hdHVyYWxIZWlnaHQgIT09IDBcclxuICAgICAgICAgID8gUHJvbWlzZS5yZXNvbHZlKClcclxuICAgICAgICAgIDogbmV3IFByb21pc2UoKHJlc29sdmUpID0+XHJcbiAgICAgICAgICAgICAgaW1hZ2UuYWRkRXZlbnRMaXN0ZW5lcignbG9hZCcsIHJlc29sdmUsIHsgb25jZTogdHJ1ZSB9KVxyXG4gICAgICAgICAgICApXHJcbiAgICAgIClcclxuICAgICksXHJcbiAgICAvLyBQcm9jZWVkIGZ1cnRoZXIgZXZlbiBpZiBpbWFnZXMgZGlkIG5vdCBsb2FkXHJcbiAgICBuZXcgUHJvbWlzZSgocmVzb2x2ZSkgPT4gc2V0VGltZW91dChyZXNvbHZlLCAyMDAwKSlcclxuICBdKTtcclxuXHJcbiAgLy8gR2V0IHRoZSBjdXJyZW50IGdsb2JhbCBvcHRpb25zXHJcbiAgY29uc3QgZGVmYXVsdE9wdGlvbnMgPSBnZXRPcHRpb25zKCk7XHJcblxyXG4gIC8vIENsZWFyIGl0IGp1c3QgaW4gY2FzZSAoZS5nLiB0aGUgYHNldE9wdGlvbnNgIHdhcyB1c2VkIGluIHRoZSBgY3VzdG9tQ29kZWApXHJcbiAgZm9yIChjb25zdCBwcm9wIGluIGRlZmF1bHRPcHRpb25zKSB7XHJcbiAgICBpZiAodHlwZW9mIGRlZmF1bHRPcHRpb25zW3Byb3BdICE9PSAnZnVuY3Rpb24nKSB7XHJcbiAgICAgIGRlbGV0ZSBkZWZhdWx0T3B0aW9uc1twcm9wXTtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIC8vIFNldCB0aGUgZGVmYXVsdCBvcHRpb25zIGJhY2tcclxuICBzZXRPcHRpb25zKEhpZ2hjaGFydHMuc2V0T3B0aW9uc09iaik7XHJcblxyXG4gIC8vIEVtcHR5IHRoZSBjdXN0b20gZ2xvYmFsIG9wdGlvbnMgb2JqZWN0XHJcbiAgSGlnaGNoYXJ0cy5zZXRPcHRpb25zT2JqID0ge307XHJcbn1cclxuXHJcbmV4cG9ydCBkZWZhdWx0IHtcclxuICBzZXR1cEhpZ2hjaGFydHMsXHJcbiAgY3JlYXRlQ2hhcnRcclxufTtcclxuIiwiLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcclxuXHJcbkhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlclxyXG5cclxuQ29weXJpZ2h0IChjKSAyMDE2LTIwMjUsIEhpZ2hzb2Z0XHJcblxyXG5MaWNlbmNlZCB1bmRlciB0aGUgTUlUIGxpY2VuY2UuXHJcblxyXG5BZGRpdGlvbmFsbHkgYSB2YWxpZCBIaWdoY2hhcnRzIGxpY2Vuc2UgaXMgcmVxdWlyZWQgZm9yIHVzZS5cclxuXHJcblNlZSBMSUNFTlNFIGZpbGUgaW4gcm9vdCBmb3IgZGV0YWlscy5cclxuXHJcbioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXHJcblxyXG4vKipcclxuICogQG92ZXJ2aWV3IFRoaXMgbW9kdWxlIHByb3ZpZGVzIGZ1bmN0aW9ucyBmb3IgbWFuYWdpbmcgUHVwcGV0ZWVyIGJyb3dzZXJcclxuICogaW5zdGFuY2UsIGNyZWF0aW5nIGFuZCBjbGVhcmluZyBwYWdlcywgaW5qZWN0aW5nIGN1c3RvbSBKUyBhbmQgQ1NTIHJlc291cmNlcyxcclxuICogYW5kIHNldHRpbmcgdXAgSGlnaGNoYXJ0cyBmb3Igc2VydmVyLXNpZGUgcmVuZGVyaW5nLiBUaGUgbW9kdWxlIGVuc3VyZXNcclxuICogdGhhdCB0aGUgYnJvd3NlciBhbmQgcGFnZXMgYXJlIGNvcnJlY3RseSBtYW5hZ2VkIGFuZCBjYW4gaGFuZGxlIGZhaWx1cmVzXHJcbiAqIGR1cmluZyBvcGVyYXRpb25zIGxpa2UgbGF1bmNoaW5nIHRoZSBicm93c2VyIG9yIGNyZWF0aW5nIG5ldyBwYWdlcy5cclxuICovXHJcblxyXG5pbXBvcnQgeyByZWFkRmlsZVN5bmMgfSBmcm9tICdmcyc7XHJcbmltcG9ydCB7IGpvaW4gfSBmcm9tICdwYXRoJztcclxuXHJcbmltcG9ydCBwdXBwZXRlZXIgZnJvbSAncHVwcGV0ZWVyJztcclxuXHJcbmltcG9ydCB7IGdldENhY2hlUGF0aCB9IGZyb20gJy4vY2FjaGUuanMnO1xyXG5pbXBvcnQgeyBnZXRPcHRpb25zIH0gZnJvbSAnLi9jb25maWcuanMnO1xyXG5pbXBvcnQgeyBzZXR1cEhpZ2hjaGFydHMgfSBmcm9tICcuL2hpZ2hjaGFydHMuanMnO1xyXG5pbXBvcnQgeyBsb2csIGxvZ1dpdGhTdGFjayB9IGZyb20gJy4vbG9nZ2VyLmpzJztcclxuaW1wb3J0IHsgX19kaXJuYW1lLCBnZXRBYnNvbHV0ZVBhdGggfSBmcm9tICcuL3V0aWxzLmpzJztcclxuXHJcbmltcG9ydCBFeHBvcnRFcnJvciBmcm9tICcuL2Vycm9ycy9FeHBvcnRFcnJvci5qcyc7XHJcblxyXG4vLyBHZXQgdGhlIHRlbXBsYXRlIGZvciBwYWdlc1xyXG5jb25zdCBwYWdlVGVtcGxhdGUgPSByZWFkRmlsZVN5bmMoXHJcbiAgam9pbihfX2Rpcm5hbWUsICd0ZW1wbGF0ZXMnLCAndGVtcGxhdGUuaHRtbCcpLFxyXG4gICd1dGY4J1xyXG4pO1xyXG5cclxuLy8gVG8gc2F2ZSB0aGUgYnJvd3NlclxyXG5sZXQgYnJvd3NlciA9IG51bGw7XHJcblxyXG4vKipcclxuICogUmV0cmlldmVzIHRoZSBleGlzdGluZyBQdXBwZXRlZXIgYnJvd3NlciBpbnN0YW5jZS5cclxuICpcclxuICogQGZ1bmN0aW9uIGdldEJyb3dzZXJcclxuICpcclxuICogQHJldHVybnMge09iamVjdH0gVGhlIFB1cHBldGVlciBicm93c2VyIGluc3RhbmNlLlxyXG4gKlxyXG4gKiBAdGhyb3dzIHtFeHBvcnRFcnJvcn0gVGhyb3dzIGFuIGBFeHBvcnRFcnJvcmAgaWYgbm8gdmFsaWQgYnJvd3NlclxyXG4gKiBoYXMgYmVlbiBjcmVhdGVkLlxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIGdldEJyb3dzZXIoKSB7XHJcbiAgaWYgKCFicm93c2VyKSB7XHJcbiAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoJ1ticm93c2VyXSBObyB2YWxpZCBicm93c2VyIGhhcyBiZWVuIGNyZWF0ZWQuJywgNTAwKTtcclxuICB9XHJcbiAgcmV0dXJuIGJyb3dzZXI7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBDcmVhdGVzIGEgUHVwcGV0ZWVyIGJyb3dzZXIgaW5zdGFuY2Ugd2l0aCB0aGUgc3BlY2lmaWVkIGFyZ3VtZW50cy5cclxuICpcclxuICogQGFzeW5jXHJcbiAqIEBmdW5jdGlvbiBjcmVhdGVCcm93c2VyXHJcbiAqXHJcbiAqIEBwYXJhbSB7QXJyYXk8c3RyaW5nPn0gcHVwcGV0ZWVyQXJncyAtIEFkZGl0aW9uYWwgYXJndW1lbnRzIGZvciBQdXBwZXRlZXJcclxuICogYnJvd3NlcidzIGxhdW5jaC5cclxuICpcclxuICogQHJldHVybnMge1Byb21pc2U8T2JqZWN0Pn0gQSBQcm9taXNlIHRoYXQgcmVzb2x2ZXMgdG8gdGhlIGNyZWF0ZWQgUHVwcGV0ZWVyXHJcbiAqIGJyb3dzZXIgaW5zdGFuY2UuXHJcbiAqXHJcbiAqIEB0aHJvd3Mge0V4cG9ydEVycm9yfSBUaHJvd3MgYW4gYEV4cG9ydEVycm9yYCBpZiBtYXggcmV0cmllcyB0byBvcGVuXHJcbiAqIGEgYnJvd3NlciBpbnN0YW5jZSBhcmUgcmVhY2hlZCwgb3IgaWYgbm8gYnJvd3NlciBpbnN0YW5jZSBpcyBmb3VuZCBhZnRlclxyXG4gKiByZXRyaWVzLlxyXG4gKi9cclxuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIGNyZWF0ZUJyb3dzZXIocHVwcGV0ZWVyQXJncykge1xyXG4gIC8vIEdldCBgZGVidWdgIGFuZCBgb3RoZXJgIG9wdGlvbnNcclxuICBjb25zdCB7IGRlYnVnLCBvdGhlciB9ID0gZ2V0T3B0aW9ucygpO1xyXG5cclxuICAvLyBHZXQgdGhlIGBkZWJ1Z2Agb3B0aW9uc1xyXG4gIGNvbnN0IHsgZW5hYmxlOiBlbmFibGVkRGVidWcsIC4uLmRlYnVnT3B0aW9ucyB9ID0gZGVidWc7XHJcblxyXG4gIC8vIExhdW5jaCBvcHRpb25zIGZvciB0aGUgYnJvd3NlciBpbnN0YW5jZVxyXG4gIGNvbnN0IGxhdW5jaE9wdGlvbnMgPSB7XHJcbiAgICBoZWFkbGVzczogb3RoZXIuYnJvd3NlclNoZWxsTW9kZSA/ICdzaGVsbCcgOiB0cnVlLFxyXG4gICAgdXNlckRhdGFEaXI6ICd0bXAnLFxyXG4gICAgYXJnczogcHVwcGV0ZWVyQXJncyB8fCBbXSxcclxuICAgIGhhbmRsZVNJR0lOVDogZmFsc2UsXHJcbiAgICBoYW5kbGVTSUdURVJNOiBmYWxzZSxcclxuICAgIGhhbmRsZVNJR0hVUDogZmFsc2UsXHJcbiAgICB3YWl0Rm9ySW5pdGlhbFBhZ2U6IGZhbHNlLFxyXG4gICAgZGVmYXVsdFZpZXdwb3J0OiBudWxsLFxyXG4gICAgLi4uKGVuYWJsZWREZWJ1ZyAmJiBkZWJ1Z09wdGlvbnMpXHJcbiAgfTtcclxuXHJcbiAgLy8gQ3JlYXRlIGEgYnJvd3NlclxyXG4gIGlmICghYnJvd3Nlcikge1xyXG4gICAgLy8gQSBjb3VudGVyIGZvciB0aGUgYnJvd3NlcidzIGxhdW5jaCByZXRyaWVzXHJcbiAgICBsZXQgdHJ5Q291bnQgPSAwO1xyXG4gICAgY29uc3Qgb3BlbkJyb3dzZXIgPSBhc3luYyAoKSA9PiB7XHJcbiAgICAgIHRyeSB7XHJcbiAgICAgICAgbG9nKFxyXG4gICAgICAgICAgMyxcclxuICAgICAgICAgIGBbYnJvd3Nlcl0gQXR0ZW1wdGluZyB0byBsYXVuY2ggYW5kIGdldCBhIGJyb3dzZXIgaW5zdGFuY2UgKHRyeSAkeysrdHJ5Q291bnR9KS5gXHJcbiAgICAgICAgKTtcclxuXHJcbiAgICAgICAgLy8gTGF1bmNoIHRoZSBicm93c2VyXHJcbiAgICAgICAgYnJvd3NlciA9IGF3YWl0IHB1cHBldGVlci5sYXVuY2gobGF1bmNoT3B0aW9ucyk7XHJcbiAgICAgIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICAgICAgbG9nV2l0aFN0YWNrKFxyXG4gICAgICAgICAgMSxcclxuICAgICAgICAgIGVycm9yLFxyXG4gICAgICAgICAgJ1ticm93c2VyXSBGYWlsZWQgdG8gbGF1bmNoIGEgYnJvd3NlciBpbnN0YW5jZS4nXHJcbiAgICAgICAgKTtcclxuXHJcbiAgICAgICAgLy8gUmV0cnkgdG8gbGF1bmNoIGJyb3dzZXIgdW50aWwgcmVhY2hpbmcgbWF4IGF0dGVtcHRzXHJcbiAgICAgICAgaWYgKHRyeUNvdW50IDwgMjUpIHtcclxuICAgICAgICAgIGxvZygzLCBgW2Jyb3dzZXJdIFJldHJ5IHRvIG9wZW4gYSBicm93c2VyICgke3RyeUNvdW50fSBvdXQgb2YgMjUpLmApO1xyXG5cclxuICAgICAgICAgIC8vIFdhaXQgZm9yIGEgNCBzZWNvbmRzIGJlZm9yZSB0cnlpbmcgYWdhaW5cclxuICAgICAgICAgIGF3YWl0IG5ldyBQcm9taXNlKChyZXNwb25zZSkgPT4gc2V0VGltZW91dChyZXNwb25zZSwgNDAwMCkpO1xyXG4gICAgICAgICAgYXdhaXQgb3BlbkJyb3dzZXIoKTtcclxuICAgICAgICB9IGVsc2Uge1xyXG4gICAgICAgICAgdGhyb3cgZXJyb3I7XHJcbiAgICAgICAgfVxyXG4gICAgICB9XHJcbiAgICB9O1xyXG5cclxuICAgIHRyeSB7XHJcbiAgICAgIC8vIFRyeSB0byBvcGVuIGEgYnJvd3NlclxyXG4gICAgICBhd2FpdCBvcGVuQnJvd3NlcigpO1xyXG5cclxuICAgICAgLy8gU2hlbGwgbW9kZSBpbmZvcm1cclxuICAgICAgaWYgKGxhdW5jaE9wdGlvbnMuaGVhZGxlc3MgPT09ICdzaGVsbCcpIHtcclxuICAgICAgICBsb2coMywgYFticm93c2VyXSBMYXVuY2hlZCBicm93c2VyIGluIHNoZWxsIG1vZGUuYCk7XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIC8vIERlYnVnIG1vZGUgaW5mb3JtXHJcbiAgICAgIGlmIChlbmFibGVkRGVidWcpIHtcclxuICAgICAgICBsb2coMywgYFticm93c2VyXSBMYXVuY2hlZCBicm93c2VyIGluIGRlYnVnIG1vZGUuYCk7XHJcbiAgICAgIH1cclxuICAgIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcihcclxuICAgICAgICAnW2Jyb3dzZXJdIE1heGltdW0gcmV0cmllcyB0byBvcGVuIGEgYnJvd3NlciBpbnN0YW5jZSByZWFjaGVkLicsXHJcbiAgICAgICAgNTAwXHJcbiAgICAgICkuc2V0RXJyb3IoZXJyb3IpO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIE5vIGNvcnJlY3QgYnJvd3NlclxyXG4gICAgaWYgKCFicm93c2VyKSB7XHJcbiAgICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcignW2Jyb3dzZXJdIENhbm5vdCBmaW5kIGEgYnJvd3NlciB0byBvcGVuLicsIDUwMCk7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICAvLyBSZXR1cm4gYSBicm93c2VyIGluc3RhbmNlXHJcbiAgcmV0dXJuIGJyb3dzZXI7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBDbG9zZXMgdGhlIFB1cHBldGVlciBicm93c2VyIGluc3RhbmNlIGlmIGl0IGlzIGNvbm5lY3RlZC5cclxuICpcclxuICogQGFzeW5jXHJcbiAqIEBmdW5jdGlvbiBjbG9zZUJyb3dzZXJcclxuICovXHJcbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBjbG9zZUJyb3dzZXIoKSB7XHJcbiAgLy8gQ2xvc2UgdGhlIGJyb3dzZXIgd2hlbiBjb25uZWN0ZWRcclxuICBpZiAoYnJvd3NlciAmJiBicm93c2VyLmNvbm5lY3RlZCkge1xyXG4gICAgYXdhaXQgYnJvd3Nlci5jbG9zZSgpO1xyXG4gIH1cclxuICBicm93c2VyID0gbnVsbDtcclxuICBsb2coNCwgJ1ticm93c2VyXSBDbG9zZWQgdGhlIGJyb3dzZXIuJyk7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBDcmVhdGVzIGEgbmV3IFB1cHBldGVlciBwYWdlIHdpdGhpbiBhbiBleGlzdGluZyBicm93c2VyIGluc3RhbmNlLlxyXG4gKiBUaGUgZnVuY3Rpb24gY3JlYXRlcyBhIG5ldyBwYWdlLCBkaXNhYmxlcyBjYWNoaW5nLCBzZXRzIGNvbnRlbnQgdXNpbmdcclxuICogdGhlIGBfc2V0UGFnZUNvbnRlbnQoKWAsIGFuZCByZXR1cm5zIHRoZSBjcmVhdGVkIFB1cHBldGVlciBwYWdlLlxyXG4gKlxyXG4gKiBAYXN5bmNcclxuICogQGZ1bmN0aW9uIG5ld1BhZ2VcclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IHBvb2xSZXNvdXJjZSAtIFRoZSBwb29sIHJlc291cmNlIHRoYXQgY29udGFpbnMgYGlkYCxcclxuICogYHdvcmtDb3VudGAsIGFuZCBgcGFnZWAuXHJcbiAqXHJcbiAqIEB0aHJvd3Mge0V4cG9ydEVycm9yfSBUaHJvd3MgYW4gYEV4cG9ydEVycm9yYCBpZiBubyB2YWxpZCBicm93c2VyXHJcbiAqIGhhcyBiZWVuIGNvbm5lY3RlZCBvciBpZiBhIHBhZ2UgaXMgaW52YWxpZCBvciBjbG9zZWQuXHJcbiAqL1xyXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gbmV3UGFnZShwb29sUmVzb3VyY2UpIHtcclxuICAvLyBFcnJvciBpbiBjYXNlIG9mIG5vIGNvbm5lY3RlZCBicm93c2VyXHJcbiAgaWYgKCFicm93c2VyIHx8ICFicm93c2VyLmNvbm5lY3RlZCkge1xyXG4gICAgdGhyb3cgbmV3IEV4cG9ydEVycm9yKGBbYnJvd3Nlcl0gQnJvd3NlciBpcyBub3QgeWV0IGNvbm5lY3RlZC5gLCA1MDApO1xyXG4gIH1cclxuXHJcbiAgLy8gQ3JlYXRlIGEgcGFnZVxyXG4gIHBvb2xSZXNvdXJjZS5wYWdlID0gYXdhaXQgYnJvd3Nlci5uZXdQYWdlKCk7XHJcblxyXG4gIC8vIERpc2FibGUgY2FjaGVcclxuICBhd2FpdCBwb29sUmVzb3VyY2UucGFnZS5zZXRDYWNoZUVuYWJsZWQoZmFsc2UpO1xyXG5cclxuICAvLyBTZXQgdGhlIGNvbnRlbnRcclxuICBhd2FpdCBfc2V0UGFnZUNvbnRlbnQocG9vbFJlc291cmNlLnBhZ2UpO1xyXG5cclxuICAvLyBTZXQgcGFnZSBldmVudHNcclxuICBfc2V0UGFnZUV2ZW50cyhwb29sUmVzb3VyY2UucGFnZSk7XHJcblxyXG4gIC8vIENoZWNrIGlmIHRoZSBwYWdlIGlzIGNvcnJlY3RseSBjcmVhdGVkXHJcbiAgaWYgKCFwb29sUmVzb3VyY2UucGFnZSB8fCBwb29sUmVzb3VyY2UucGFnZS5pc0Nsb3NlZCgpKSB7XHJcbiAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoJ1ticm93c2VyXSBUaGUgcGFnZSBpcyBpbnZhbGlkIG9yIGNsb3NlZC4nLCA0MDApO1xyXG4gIH1cclxufVxyXG5cclxuLyoqXHJcbiAqIENsZWFycyB0aGUgY29udGVudCBvZiBhIFB1cHBldGVlciBwYWdlIGJhc2VkIG9uIHRoZSBzcGVjaWZpZWQgbW9kZS4gTG9nc1xyXG4gKiB0aHJvd24gZXJyb3IgaWYgY2xlYXJpbmcgb2YgYSBwYWdlJ3MgY29udGVudCBmYWlscy5cclxuICpcclxuICogQGFzeW5jXHJcbiAqIEBmdW5jdGlvbiBjbGVhclBhZ2VcclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IHBvb2xSZXNvdXJjZSAtIFRoZSBwb29sIHJlc291cmNlIHRoYXQgY29udGFpbnMgcGFnZSBhbmQgaWQuXHJcbiAqIEBwYXJhbSB7Ym9vbGVhbn0gW2hhcmRSZXNldD1mYWxzZV0gLSBBIGZsYWcgaW5kaWNhdGluZyB0aGUgdHlwZSBvZiBjbGVhcmluZ1xyXG4gKiB0byBiZSBwZXJmb3JtZWQuIElmIGB0cnVlYCwgbmF2aWdhdGVzIHRvIGBhYm91dDpibGFua2AgYW5kIHJlc2V0cyBjb250ZW50XHJcbiAqIGFuZCBzY3JpcHRzLiBJZiBgZmFsc2VgLCBjbGVhcnMgdGhlIGJvZHkgY29udGVudCBieSBzZXR0aW5nIGEgcHJlZGVmaW5lZCBIVE1MXHJcbiAqIHN0cnVjdHVyZS4gVGhlIGRlZmF1bHQgdmFsdWUgaXMgYGZhbHNlYC5cclxuICpcclxuICogQHJldHVybnMge1Byb21pc2U8Ym9vbGVhbj59IEEgUHJvbWlzZSB0aGF0IHJlc29sdmVzIHRvIGB0cnVlYCB3aGVuIHBhZ2VcclxuICogaXMgY29ycmVjdGx5IGNsZWFyZWQgYW5kIGBmYWxzZWAgd2hlbiBpdCBpcyBub3QuXHJcbiAqL1xyXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gY2xlYXJQYWdlKHBvb2xSZXNvdXJjZSwgaGFyZFJlc2V0ID0gZmFsc2UpIHtcclxuICB0cnkge1xyXG4gICAgaWYgKHBvb2xSZXNvdXJjZS5wYWdlICYmICFwb29sUmVzb3VyY2UucGFnZS5pc0Nsb3NlZCgpKSB7XHJcbiAgICAgIGlmIChoYXJkUmVzZXQpIHtcclxuICAgICAgICAvLyBOYXZpZ2F0ZSB0byBgYWJvdXQ6YmxhbmtgXHJcbiAgICAgICAgYXdhaXQgcG9vbFJlc291cmNlLnBhZ2UuZ290bygnYWJvdXQ6YmxhbmsnLCB7XHJcbiAgICAgICAgICB3YWl0VW50aWw6ICdkb21jb250ZW50bG9hZGVkJ1xyXG4gICAgICAgIH0pO1xyXG5cclxuICAgICAgICAvLyBTZXQgdGhlIGNvbnRlbnQgYW5kIGFuZCBzY3JpcHRzIGFnYWluXHJcbiAgICAgICAgYXdhaXQgX3NldFBhZ2VDb250ZW50KHBvb2xSZXNvdXJjZS5wYWdlKTtcclxuICAgICAgfSBlbHNlIHtcclxuICAgICAgICAvLyBDbGVhciBib2R5IGNvbnRlbnRcclxuICAgICAgICBhd2FpdCBwb29sUmVzb3VyY2UucGFnZS5ldmFsdWF0ZSgoKSA9PiB7XHJcbiAgICAgICAgICBkb2N1bWVudC5ib2R5LmlubmVySFRNTCA9XHJcbiAgICAgICAgICAgICc8ZGl2IGlkPVwiY2hhcnQtY29udGFpbmVyXCI+PGRpdiBpZD1cImNvbnRhaW5lclwiPjwvZGl2PjwvZGl2Pic7XHJcbiAgICAgICAgfSk7XHJcbiAgICAgIH1cclxuICAgICAgcmV0dXJuIHRydWU7XHJcbiAgICB9XHJcbiAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgIGxvZ1dpdGhTdGFjayhcclxuICAgICAgMixcclxuICAgICAgZXJyb3IsXHJcbiAgICAgIGBbcG9vbF0gUG9vbCByZXNvdXJjZSBbJHtwb29sUmVzb3VyY2UuaWR9XSAtIENvbnRlbnQgb2YgdGhlIHBhZ2UgY291bGQgbm90IGJlIGNsZWFyZWQuYFxyXG4gICAgKTtcclxuXHJcbiAgICAvLyBTZXQgdGhlIGB3b3JrTGltaXRgIHRvIGV4Y2VlZGVkIGluIG9yZGVyIHRvIHJlY3JlYXRlIHRoZSByZXNvdXJjZVxyXG4gICAgcG9vbFJlc291cmNlLndvcmtDb3VudCA9IGdldE9wdGlvbnMoKS5wb29sLndvcmtMaW1pdCArIDE7XHJcbiAgfVxyXG4gIHJldHVybiBmYWxzZTtcclxufVxyXG5cclxuLyoqXHJcbiAqIEFkZHMgY3VzdG9tIEpTIGFuZCBDU1MgcmVzb3VyY2VzIHRvIGEgUHVwcGV0ZWVyIHBhZ2UgYmFzZWQgb24gdGhlIHNwZWNpZmllZFxyXG4gKiBvcHRpb25zLlxyXG4gKlxyXG4gKiBAYXN5bmNcclxuICogQGZ1bmN0aW9uIGFkZFBhZ2VSZXNvdXJjZXNcclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IHBhZ2UgLSBUaGUgUHVwcGV0ZWVyIHBhZ2Ugb2JqZWN0IHRvIHdoaWNoIHJlc291cmNlcyB3aWxsXHJcbiAqIGJlIGFkZGVkLlxyXG4gKiBAcGFyYW0ge09iamVjdH0gY3VzdG9tTG9naWNPcHRpb25zIC0gVGhlIGNvbmZpZ3VyYXRpb24gb2JqZWN0IGNvbnRhaW5pbmdcclxuICogYGN1c3RvbUxvZ2ljYCBvcHRpb25zLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7UHJvbWlzZTxBcnJheTxPYmplY3Q+Pn0gQSBQcm9taXNlIHRoYXQgcmVzb2x2ZXMgdG8gYW4gYXJyYXlcclxuICogb2YgaW5qZWN0ZWQgcmVzb3VyY2VzLlxyXG4gKi9cclxuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIGFkZFBhZ2VSZXNvdXJjZXMocGFnZSwgY3VzdG9tTG9naWNPcHRpb25zKSB7XHJcbiAgLy8gSW5qZWN0ZWQgcmVzb3VyY2VzIGFycmF5XHJcbiAgY29uc3QgaW5qZWN0ZWRSZXNvdXJjZXMgPSBbXTtcclxuXHJcbiAgLy8gVXNlIHRoZSBjb250ZW50IG9mIHRoZSBgcmVzb3VyY2VzYFxyXG4gIGNvbnN0IHJlc291cmNlcyA9IGN1c3RvbUxvZ2ljT3B0aW9ucy5yZXNvdXJjZXM7XHJcbiAgaWYgKHJlc291cmNlcykge1xyXG4gICAgY29uc3QgaW5qZWN0ZWRKcyA9IFtdO1xyXG5cclxuICAgIC8vIExvYWQgY3VzdG9tIEpTIGNvZGVcclxuICAgIGlmIChyZXNvdXJjZXMuanMpIHtcclxuICAgICAgaW5qZWN0ZWRKcy5wdXNoKHtcclxuICAgICAgICBjb250ZW50OiByZXNvdXJjZXMuanNcclxuICAgICAgfSk7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gTG9hZCBzY3JpcHRzIGZyb20gYWxsIGN1c3RvbSBmaWxlc1xyXG4gICAgaWYgKHJlc291cmNlcy5maWxlcykge1xyXG4gICAgICBmb3IgKGNvbnN0IGZpbGUgb2YgcmVzb3VyY2VzLmZpbGVzKSB7XHJcbiAgICAgICAgY29uc3QgaXNMb2NhbCA9IGZpbGUuc3RhcnRzV2l0aCgnaHR0cCcpID8gZmFsc2UgOiB0cnVlO1xyXG5cclxuICAgICAgICAvLyBBZGQgZWFjaCBjdXN0b20gc2NyaXB0IGZyb20gcmVzb3VyY2VzJyBmaWxlc1xyXG4gICAgICAgIGluamVjdGVkSnMucHVzaChcclxuICAgICAgICAgIGlzTG9jYWxcclxuICAgICAgICAgICAgPyB7XHJcbiAgICAgICAgICAgICAgICBjb250ZW50OiByZWFkRmlsZVN5bmMoZ2V0QWJzb2x1dGVQYXRoKGZpbGUpLCAndXRmOCcpXHJcbiAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICA6IHtcclxuICAgICAgICAgICAgICAgIHVybDogZmlsZVxyXG4gICAgICAgICAgICAgIH1cclxuICAgICAgICApO1xyXG4gICAgICB9XHJcbiAgICB9XHJcblxyXG4gICAgLy8gVGhlIGFjdHVhbCBpbmplY3Rpb24gb2YgY29sbGVjdGVkIHNjcmlwdHNcclxuICAgIGZvciAoY29uc3QganNSZXNvdXJjZSBvZiBpbmplY3RlZEpzKSB7XHJcbiAgICAgIHRyeSB7XHJcbiAgICAgICAgaW5qZWN0ZWRSZXNvdXJjZXMucHVzaChhd2FpdCBwYWdlLmFkZFNjcmlwdFRhZyhqc1Jlc291cmNlKSk7XHJcbiAgICAgIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICAgICAgbG9nV2l0aFN0YWNrKDIsIGVycm9yLCBgW2Jyb3dzZXJdIFRoZSBKUyByZXNvdXJjZSBjYW5ub3QgYmUgbG9hZGVkLmApO1xyXG4gICAgICB9XHJcbiAgICB9XHJcbiAgICBpbmplY3RlZEpzLmxlbmd0aCA9IDA7XHJcblxyXG4gICAgLy8gTG9hZCBDU1NcclxuICAgIGNvbnN0IGluamVjdGVkQ3NzID0gW107XHJcbiAgICBpZiAocmVzb3VyY2VzLmNzcykge1xyXG4gICAgICBjb25zdCBjc3NJbXBvcnRzID0gcmVzb3VyY2VzLmNzcy5tYXRjaCgvQGltcG9ydFxccyooW147XSopOy9nKTtcclxuICAgICAgaWYgKGNzc0ltcG9ydHMpIHtcclxuICAgICAgICAvLyBIYW5kbGUgY3NzIHNlY3Rpb25cclxuICAgICAgICBmb3IgKGxldCBjc3NJbXBvcnRQYXRoIG9mIGNzc0ltcG9ydHMpIHtcclxuICAgICAgICAgIGlmIChjc3NJbXBvcnRQYXRoKSB7XHJcbiAgICAgICAgICAgIGNzc0ltcG9ydFBhdGggPSBjc3NJbXBvcnRQYXRoXHJcbiAgICAgICAgICAgICAgLnJlcGxhY2UoJ3VybCgnLCAnJylcclxuICAgICAgICAgICAgICAucmVwbGFjZSgnQGltcG9ydCcsICcnKVxyXG4gICAgICAgICAgICAgIC5yZXBsYWNlKC9cIi9nLCAnJylcclxuICAgICAgICAgICAgICAucmVwbGFjZSgvJy9nLCAnJylcclxuICAgICAgICAgICAgICAucmVwbGFjZSgvOy8sICcnKVxyXG4gICAgICAgICAgICAgIC5yZXBsYWNlKC9cXCkvZywgJycpXHJcbiAgICAgICAgICAgICAgLnRyaW0oKTtcclxuXHJcbiAgICAgICAgICAgIC8vIEFkZCBlYWNoIGN1c3RvbSBjc3MgZnJvbSByZXNvdXJjZXNcclxuICAgICAgICAgICAgaWYgKGNzc0ltcG9ydFBhdGguc3RhcnRzV2l0aCgnaHR0cCcpKSB7XHJcbiAgICAgICAgICAgICAgaW5qZWN0ZWRDc3MucHVzaCh7XHJcbiAgICAgICAgICAgICAgICB1cmw6IGNzc0ltcG9ydFBhdGhcclxuICAgICAgICAgICAgICB9KTtcclxuICAgICAgICAgICAgfSBlbHNlIGlmIChjdXN0b21Mb2dpY09wdGlvbnMuYWxsb3dGaWxlUmVzb3VyY2VzKSB7XHJcbiAgICAgICAgICAgICAgaW5qZWN0ZWRDc3MucHVzaCh7XHJcbiAgICAgICAgICAgICAgICBwYXRoOiBnZXRBYnNvbHV0ZVBhdGgoY3NzSW1wb3J0UGF0aClcclxuICAgICAgICAgICAgICB9KTtcclxuICAgICAgICAgICAgfVxyXG4gICAgICAgICAgfVxyXG4gICAgICAgIH1cclxuICAgICAgfVxyXG5cclxuICAgICAgLy8gVGhlIHJlc3Qgb2YgdGhlIENTUyBzZWN0aW9uIHdpbGwgYmUgY29udGVudCBieSBub3dcclxuICAgICAgaW5qZWN0ZWRDc3MucHVzaCh7XHJcbiAgICAgICAgY29udGVudDogcmVzb3VyY2VzLmNzcy5yZXBsYWNlKC9AaW1wb3J0XFxzKihbXjtdKik7L2csICcnKSB8fCAnICdcclxuICAgICAgfSk7XHJcblxyXG4gICAgICAvLyBUaGUgYWN0dWFsIGluamVjdGlvbiBvZiBjb2xsZWN0ZWQgQ1NTXHJcbiAgICAgIGZvciAoY29uc3QgY3NzUmVzb3VyY2Ugb2YgaW5qZWN0ZWRDc3MpIHtcclxuICAgICAgICB0cnkge1xyXG4gICAgICAgICAgaW5qZWN0ZWRSZXNvdXJjZXMucHVzaChhd2FpdCBwYWdlLmFkZFN0eWxlVGFnKGNzc1Jlc291cmNlKSk7XHJcbiAgICAgICAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICAgICAgIGxvZ1dpdGhTdGFjayhcclxuICAgICAgICAgICAgMixcclxuICAgICAgICAgICAgZXJyb3IsXHJcbiAgICAgICAgICAgIGBbYnJvd3Nlcl0gVGhlIENTUyByZXNvdXJjZSBjYW5ub3QgYmUgbG9hZGVkLmBcclxuICAgICAgICAgICk7XHJcbiAgICAgICAgfVxyXG4gICAgICB9XHJcbiAgICAgIGluamVjdGVkQ3NzLmxlbmd0aCA9IDA7XHJcbiAgICB9XHJcbiAgfVxyXG4gIHJldHVybiBpbmplY3RlZFJlc291cmNlcztcclxufVxyXG5cclxuLyoqXHJcbiAqIENsZWFycyBvdXQgYWxsIHN0YXRlIHNldCBvbiB0aGUgcGFnZSB3aXRoIGBhZGRTY3JpcHRUYWdgIGFuZCBgYWRkU3R5bGVUYWdgLlxyXG4gKiBSZW1vdmVzIGluamVjdGVkIHJlc291cmNlcyBhbmQgcmVzZXRzIENTUyBhbmQgc2NyaXB0IHRhZ3Mgb24gdGhlIHBhZ2UuXHJcbiAqIEFkZGl0aW9uYWxseSwgaXQgZGVzdHJveXMgcHJldmlvdXNseSBleGlzdGluZyBjaGFydHMuXHJcbiAqXHJcbiAqIEBhc3luY1xyXG4gKiBAZnVuY3Rpb24gY2xlYXJQYWdlUmVzb3VyY2VzXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBwYWdlIC0gVGhlIFB1cHBldGVlciBwYWdlIG9iamVjdCBmcm9tIHdoaWNoIHJlc291cmNlcyB3aWxsXHJcbiAqIGJlIGNsZWFyZWQuXHJcbiAqIEBwYXJhbSB7QXJyYXk8T2JqZWN0Pn0gaW5qZWN0ZWRSZXNvdXJjZXMgLSBBcnJheSBvZiBpbmplY3RlZCByZXNvdXJjZXNcclxuICogdG8gYmUgY2xlYXJlZC5cclxuICovXHJcbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBjbGVhclBhZ2VSZXNvdXJjZXMocGFnZSwgaW5qZWN0ZWRSZXNvdXJjZXMpIHtcclxuICB0cnkge1xyXG4gICAgZm9yIChjb25zdCByZXNvdXJjZSBvZiBpbmplY3RlZFJlc291cmNlcykge1xyXG4gICAgICBhd2FpdCByZXNvdXJjZS5kaXNwb3NlKCk7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gRGVzdHJveSBvbGQgY2hhcnRzIGFmdGVyIGV4cG9ydCBpcyBkb25lIGFuZCByZXNldCBhbGwgQ1NTIGFuZCBzY3JpcHQgdGFnc1xyXG4gICAgYXdhaXQgcGFnZS5ldmFsdWF0ZSgoKSA9PiB7XHJcbiAgICAgIC8vIFdlIGFyZSBub3QgZ3VhcmFudGVlZCB0aGF0IEhpZ2hjaGFydHMgaXMgbG9hZGVkLCB3aGVuIGRvaW5nIFNWRyBleHBvcnRzXHJcbiAgICAgIGlmICh0eXBlb2YgSGlnaGNoYXJ0cyAhPT0gJ3VuZGVmaW5lZCcpIHtcclxuICAgICAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgbm8tdW5kZWZcclxuICAgICAgICBjb25zdCBvbGRDaGFydHMgPSBIaWdoY2hhcnRzLmNoYXJ0cztcclxuXHJcbiAgICAgICAgLy8gQ2hlY2sgaW4gYW55IGFscmVhZHkgZXhpc3RpbmcgY2hhcnRzXHJcbiAgICAgICAgaWYgKEFycmF5LmlzQXJyYXkob2xkQ2hhcnRzKSAmJiBvbGRDaGFydHMubGVuZ3RoKSB7XHJcbiAgICAgICAgICAvLyBEZXN0cm95IG9sZCBjaGFydHNcclxuICAgICAgICAgIGZvciAoY29uc3Qgb2xkQ2hhcnQgb2Ygb2xkQ2hhcnRzKSB7XHJcbiAgICAgICAgICAgIG9sZENoYXJ0ICYmIG9sZENoYXJ0LmRlc3Ryb3koKTtcclxuICAgICAgICAgICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIG5vLXVuZGVmXHJcbiAgICAgICAgICAgIEhpZ2hjaGFydHMuY2hhcnRzLnNoaWZ0KCk7XHJcbiAgICAgICAgICB9XHJcbiAgICAgICAgfVxyXG4gICAgICB9XHJcblxyXG4gICAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgbm8tdW5kZWZcclxuICAgICAgY29uc3QgWy4uLnNjcmlwdHNUb1JlbW92ZV0gPSBkb2N1bWVudC5nZXRFbGVtZW50c0J5VGFnTmFtZSgnc2NyaXB0Jyk7XHJcbiAgICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBuby11bmRlZlxyXG4gICAgICBjb25zdCBbLCAuLi5zdHlsZXNUb1JlbW92ZV0gPSBkb2N1bWVudC5nZXRFbGVtZW50c0J5VGFnTmFtZSgnc3R5bGUnKTtcclxuICAgICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIG5vLXVuZGVmXHJcbiAgICAgIGNvbnN0IFsuLi5saW5rc1RvUmVtb3ZlXSA9IGRvY3VtZW50LmdldEVsZW1lbnRzQnlUYWdOYW1lKCdsaW5rJyk7XHJcblxyXG4gICAgICAvLyBSZW1vdmUgdGFnc1xyXG4gICAgICBmb3IgKGNvbnN0IGVsZW1lbnQgb2YgW1xyXG4gICAgICAgIC4uLnNjcmlwdHNUb1JlbW92ZSxcclxuICAgICAgICAuLi5zdHlsZXNUb1JlbW92ZSxcclxuICAgICAgICAuLi5saW5rc1RvUmVtb3ZlXHJcbiAgICAgIF0pIHtcclxuICAgICAgICBlbGVtZW50LnJlbW92ZSgpO1xyXG4gICAgICB9XHJcbiAgICB9KTtcclxuICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgbG9nV2l0aFN0YWNrKDIsIGVycm9yLCBgW2Jyb3dzZXJdIENvdWxkIG5vdCBjbGVhciBwYWdlJ3MgcmVzb3VyY2VzLmApO1xyXG4gIH1cclxufVxyXG5cclxuLyoqXHJcbiAqIFNldHMgdGhlIGNvbnRlbnQgZm9yIGEgUHVwcGV0ZWVyIHBhZ2UgdXNpbmcgYSBwcmVkZWZpbmVkIHRlbXBsYXRlXHJcbiAqIGFuZCBhZGRpdGlvbmFsIHNjcmlwdHMuXHJcbiAqXHJcbiAqIEBhc3luY1xyXG4gKiBAZnVuY3Rpb24gX3NldFBhZ2VDb250ZW50XHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBwYWdlIC0gVGhlIFB1cHBldGVlciBwYWdlIG9iamVjdCB0byB3aGljaCB0aGUgY29udGVudFxyXG4gKiBpcyBiZWluZyBzZXQuXHJcbiAqL1xyXG5hc3luYyBmdW5jdGlvbiBfc2V0UGFnZUNvbnRlbnQocGFnZSkge1xyXG4gIC8vIFNldCB0aGUgaW5pdGlhbCBwYWdlIGNvbnRlbnRcclxuICBhd2FpdCBwYWdlLnNldENvbnRlbnQocGFnZVRlbXBsYXRlLCB7IHdhaXRVbnRpbDogJ2RvbWNvbnRlbnRsb2FkZWQnIH0pO1xyXG5cclxuICAvLyBBZGQgYWxsIHJlZ2lzdGVyZWQgSGlnY2hhcnRzIHNjcmlwdHMsIHF1aXRlIGRlbWFuZGluZ1xyXG4gIGF3YWl0IHBhZ2UuYWRkU2NyaXB0VGFnKHsgcGF0aDogam9pbihnZXRDYWNoZVBhdGgoKSwgJ3NvdXJjZXMuanMnKSB9KTtcclxuXHJcbiAgLy8gU2V0IHRoZSBpbml0aWFsIGBhbmltT2JqZWN0YCBmb3IgSGlnaGNoYXJ0c1xyXG4gIGF3YWl0IHBhZ2UuZXZhbHVhdGUoc2V0dXBIaWdoY2hhcnRzKTtcclxufVxyXG5cclxuLyoqXHJcbiAqIFNldCBldmVudHMgKGxpa2UgYHBhZ2VlcnJvcmAgYW5kIGBjb25zb2xlYCkgZm9yIGEgUHVwcGV0ZWVyIHBhZ2UgaW4gb3JkZXJcclxuICogdG8gY2F0Y2ggYW5kIGRpc3BsYXkgZXJyb3JzIGFuZCBjb25zb2xlIGxvZ3MgZnJvbSB0aGUgd2luZG93IGNvbnRleHQuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBfc2V0UGFnZUV2ZW50c1xyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gcGFnZSAtIFRoZSBQdXBwZXRlZXIgcGFnZSBvYmplY3QgdG8gd2hpY2ggdGhlIGxpc3RlbmVyc1xyXG4gKiBhcmUgYmVpbmcgc2V0LlxyXG4gKi9cclxuZnVuY3Rpb24gX3NldFBhZ2VFdmVudHMocGFnZSkge1xyXG4gIC8vIEdldCBgZGVidWdgIG9wdGlvbnNcclxuICBjb25zdCB7IGRlYnVnIH0gPSBnZXRPcHRpb25zKCk7XHJcblxyXG4gIC8vIFNldCB0aGUgYHBhZ2VlcnJvcmAgbGlzdGVuZXJcclxuICBwYWdlLm9uKCdwYWdlZXJyb3InLCBhc3luYyAoKSA9PiB7XHJcbiAgICAvLyBJdCB3b3VsZCBzZWVtIGxpa2UgdGhpcyBtYXkgZmlyZSBhdCB0aGUgc2FtZSB0aW1lIG9yIHNob3J0bHkgYmVmb3JlXHJcbiAgICAvLyBhIHBhZ2UgaXMgY2xvc2VkLlxyXG4gICAgaWYgKHBhZ2UuaXNDbG9zZWQoKSkge1xyXG4gICAgICByZXR1cm47XHJcbiAgICB9XHJcbiAgfSk7XHJcblxyXG4gIC8vIFNldCB0aGUgYGNvbnNvbGVgIGxpc3RlbmVyLCBpZiBuZWVkZWRcclxuICBpZiAoZGVidWcuZW5hYmxlICYmIGRlYnVnLmxpc3RlblRvQ29uc29sZSkge1xyXG4gICAgcGFnZS5vbignY29uc29sZScsIChtZXNzYWdlKSA9PiB7XHJcbiAgICAgIGNvbnNvbGUubG9nKGBbZGVidWddICR7bWVzc2FnZS50ZXh0KCl9YCk7XHJcbiAgICB9KTtcclxuICB9XHJcbn1cclxuXHJcbmV4cG9ydCBkZWZhdWx0IHtcclxuICBnZXRCcm93c2VyLFxyXG4gIGNyZWF0ZUJyb3dzZXIsXHJcbiAgY2xvc2VCcm93c2VyLFxyXG4gIG5ld1BhZ2UsXHJcbiAgY2xlYXJQYWdlLFxyXG4gIGFkZFBhZ2VSZXNvdXJjZXMsXHJcbiAgY2xlYXJQYWdlUmVzb3VyY2VzXHJcbn07XHJcbiIsIi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXHJcblxyXG5IaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXJcclxuXHJcbkNvcHlyaWdodCAoYykgMjAxNi0yMDI1LCBIaWdoc29mdFxyXG5cclxuTGljZW5jZWQgdW5kZXIgdGhlIE1JVCBsaWNlbmNlLlxyXG5cclxuQWRkaXRpb25hbGx5IGEgdmFsaWQgSGlnaGNoYXJ0cyBsaWNlbnNlIGlzIHJlcXVpcmVkIGZvciB1c2UuXHJcblxyXG5TZWUgTElDRU5TRSBmaWxlIGluIHJvb3QgZm9yIGRldGFpbHMuXHJcblxyXG4qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xyXG5cclxuLyoqXHJcbiAqIFRoZSBDU1MgdG8gYmUgdXNlZCBvbiB0aGUgZXhwb3J0ZWQgcGFnZS5cclxuICpcclxuICogQHJldHVybnMge3N0cmluZ30gVGhlIENTUyBjb25maWd1cmF0aW9uLlxyXG4gKi9cclxuZXhwb3J0IGRlZmF1bHQgKCkgPT4gYFxyXG5cclxuaHRtbCwgYm9keSB7XHJcbiAgbWFyZ2luOiAwO1xyXG4gIHBhZGRpbmc6IDA7XHJcbiAgYm94LXNpemluZzogYm9yZGVyLWJveDtcclxufVxyXG5cclxuI3RhYmxlLWRpdiwgI3NsaWRlcnMsICNkYXRhdGFibGUsICNjb250cm9scywgLmxkLXJvdyB7XHJcbiAgZGlzcGxheTogbm9uZTtcclxuICBoZWlnaHQ6IDA7XHJcbn1cclxuXHJcbiNjaGFydC1jb250YWluZXIge1xyXG4gIGJveC1zaXppbmc6IGJvcmRlci1ib3g7XHJcbiAgbWFyZ2luOiAwO1xyXG4gIG92ZXJmbG93OiBhdXRvO1xyXG4gIGZvbnQtc2l6ZTogMDtcclxufVxyXG5cclxuI2NoYXJ0LWNvbnRhaW5lciA+IGZpZ3VyZSwgZGl2IHtcclxuICBtYXJnaW4tdG9wOiAwICFpbXBvcnRhbnQ7XHJcbiAgbWFyZ2luLWJvdHRvbTogMCAhaW1wb3J0YW50O1xyXG59XHJcblxyXG5gO1xyXG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxyXG5cclxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXHJcblxyXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNSwgSGlnaHNvZnRcclxuXHJcbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cclxuXHJcbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxyXG5cclxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxyXG5cclxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cclxuXHJcbmltcG9ydCBjc3NUZW1wbGF0ZSBmcm9tICcuL2Nzcy5qcyc7XHJcblxyXG4vKipcclxuICogVGhlIFNWRyB0ZW1wbGF0ZSB0byB1c2Ugd2hlbiBsb2FkaW5nIFNWRyBjb250ZW50IHRvIGJlIGV4cG9ydGVkLlxyXG4gKlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gc3ZnIC0gVGhlIFNWRyBpbnB1dCBjb250ZW50IHRvIGJlIGV4cG9ydGVkLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7c3RyaW5nfSBUaGUgU1ZHIHRlbXBsYXRlLlxyXG4gKi9cclxuZXhwb3J0IGRlZmF1bHQgKHN2ZykgPT4gYFxyXG48IURPQ1RZUEUgaHRtbD5cclxuPGh0bWwgbGFuZz0nZW4tVVMnPlxyXG4gIDxoZWFkPlxyXG4gICAgPG1ldGEgaHR0cC1lcXVpdj1cIkNvbnRlbnQtVHlwZVwiIGNvbnRlbnQ9XCJ0ZXh0L2h0bWw7IGNoYXJzZXQ9dXRmLThcIj5cclxuICAgIDx0aXRsZT5IaWdoY2hhcnRzIEV4cG9ydDwvdGl0bGU+XHJcbiAgPC9oZWFkPlxyXG4gIDxzdHlsZT5cclxuICAgICR7Y3NzVGVtcGxhdGUoKX1cclxuICA8L3N0eWxlPlxyXG4gIDxib2R5PlxyXG4gICAgPGRpdiBpZD1cImNoYXJ0LWNvbnRhaW5lclwiPlxyXG4gICAgICAke3N2Z31cclxuICAgIDwvZGl2PlxyXG4gIDwvYm9keT5cclxuPC9odG1sPlxyXG5cclxuYDtcclxuIiwiLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcclxuXHJcbkhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlclxyXG5cclxuQ29weXJpZ2h0IChjKSAyMDE2LTIwMjUsIEhpZ2hzb2Z0XHJcblxyXG5MaWNlbmNlZCB1bmRlciB0aGUgTUlUIGxpY2VuY2UuXHJcblxyXG5BZGRpdGlvbmFsbHkgYSB2YWxpZCBIaWdoY2hhcnRzIGxpY2Vuc2UgaXMgcmVxdWlyZWQgZm9yIHVzZS5cclxuXHJcblNlZSBMSUNFTlNFIGZpbGUgaW4gcm9vdCBmb3IgZGV0YWlscy5cclxuXHJcbioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXHJcblxyXG4vKipcclxuICogQG92ZXJ2aWV3IFRoaXMgbW9kdWxlIGhhbmRsZXMgY2hhcnQgZXhwb3J0IGZ1bmN0aW9uYWxpdHkgdXNpbmcgUHVwcGV0ZWVyLlxyXG4gKiBJdCBzdXBwb3J0cyBleHBvcnRpbmcgY2hhcnRzIGFzIFNWRywgUE5HLCBKUEVHLCBhbmQgUERGIGZvcm1hdHMuIFRoZSBtb2R1bGVcclxuICogbWFuYWdlcyBwYWdlIHJlc291cmNlcywgc2V0cyB1cCB0aGUgZXhwb3J0IGVudmlyb25tZW50LCBhbmQgcHJvY2Vzc2VzIGNoYXJ0XHJcbiAqIGNvbmZpZ3VyYXRpb25zIG9yIFNWRyBpbnB1dHMgZm9yIHJlbmRlcmluZy4gRXhwb3J0cyB0byBhIGNoYXJ0IGZyb20gYSBwYWdlXHJcbiAqIHVzaW5nIFB1cHBldGVlci5cclxuICovXHJcblxyXG5pbXBvcnQgeyBhZGRQYWdlUmVzb3VyY2VzLCBjbGVhclBhZ2VSZXNvdXJjZXMgfSBmcm9tICcuL2Jyb3dzZXIuanMnO1xyXG5pbXBvcnQgeyBjcmVhdGVDaGFydCB9IGZyb20gJy4vaGlnaGNoYXJ0cy5qcyc7XHJcbmltcG9ydCB7IGxvZyB9IGZyb20gJy4vbG9nZ2VyLmpzJztcclxuXHJcbmltcG9ydCBzdmdUZW1wbGF0ZSBmcm9tICcuLi90ZW1wbGF0ZXMvc3ZnRXhwb3J0L3N2Z0V4cG9ydC5qcyc7XHJcblxyXG5pbXBvcnQgRXhwb3J0RXJyb3IgZnJvbSAnLi9lcnJvcnMvRXhwb3J0RXJyb3IuanMnO1xyXG5cclxuLyoqXHJcbiAqIEV4cG9ydHMgdG8gYSBjaGFydCBmcm9tIGEgcGFnZSB1c2luZyBQdXBwZXRlZXIuXHJcbiAqXHJcbiAqIEBhc3luY1xyXG4gKiBAZnVuY3Rpb24gcHVwcGV0ZWVyRXhwb3J0XHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBwYWdlIC0gUHVwcGV0ZWVyIHBhZ2Ugb2JqZWN0LlxyXG4gKiBAcGFyYW0ge09iamVjdH0gZXhwb3J0T3B0aW9ucyAtIFRoZSBjb25maWd1cmF0aW9uIG9iamVjdCBjb250YWluaW5nIGBleHBvcnRgXHJcbiAqIG9wdGlvbnMuXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBjdXN0b21Mb2dpY09wdGlvbnMgLSBUaGUgY29uZmlndXJhdGlvbiBvYmplY3QgY29udGFpbmluZ1xyXG4gKiBgY3VzdG9tTG9naWNgIG9wdGlvbnMuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtQcm9taXNlPChzdHJpbmd8QnVmZmVyfEV4cG9ydEVycm9yKT59IEEgUHJvbWlzZSB0aGF0IHJlc29sdmVzXHJcbiAqIHRvIHRoZSBleHBvcnRlZCBkYXRhIG9yIHJlamVjdGluZyB3aXRoIGFuIGBFeHBvcnRFcnJvcmAuXHJcbiAqXHJcbiAqIEB0aHJvd3Mge0V4cG9ydEVycm9yfSBUaHJvd3MgYW4gYEV4cG9ydEVycm9yYCBpZiBleHBvcnQgdG8gYW4gdW5zdXBwb3J0ZWRcclxuICogb3V0cHV0IGZvcm1hdCBvY2N1cnMuXHJcbiAqL1xyXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gcHVwcGV0ZWVyRXhwb3J0KHBhZ2UsIGV4cG9ydE9wdGlvbnMsIGN1c3RvbUxvZ2ljT3B0aW9ucykge1xyXG4gIC8vIEluamVjdGVkIHJlc291cmNlcyBhcnJheSAoYWRkaXRpb25hbCBKUyBhbmQgQ1NTKVxyXG4gIGNvbnN0IGluamVjdGVkUmVzb3VyY2VzID0gW107XHJcblxyXG4gIHRyeSB7XHJcbiAgICBsZXQgaXNTVkcgPSBmYWxzZTtcclxuXHJcbiAgICAvLyBEZWNpZGUgb24gdGhlIGV4cG9ydCBtZXRob2RcclxuICAgIGlmIChleHBvcnRPcHRpb25zLnN2Zykge1xyXG4gICAgICBsb2coNCwgJ1tleHBvcnRdIFRyZWF0aW5nIGFzIFNWRyBpbnB1dC4nKTtcclxuXHJcbiAgICAgIC8vIElmIHRoZSBgdHlwZWAgaXMgYWxzbyBTVkcsIHJldHVybiB0aGUgaW5wdXRcclxuICAgICAgaWYgKGV4cG9ydE9wdGlvbnMudHlwZSA9PT0gJ3N2ZycpIHtcclxuICAgICAgICByZXR1cm4gZXhwb3J0T3B0aW9ucy5zdmc7XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIC8vIE1hcmsgYXMgU1ZHIGV4cG9ydCBmb3IgdGhlIGxhdGVyIHNpemUgY29ycmVjdGlvbnNcclxuICAgICAgaXNTVkcgPSB0cnVlO1xyXG5cclxuICAgICAgLy8gU1ZHIGV4cG9ydFxyXG4gICAgICBhd2FpdCBwYWdlLnNldENvbnRlbnQoc3ZnVGVtcGxhdGUoZXhwb3J0T3B0aW9ucy5zdmcpLCB7XHJcbiAgICAgICAgd2FpdFVudGlsOiAnZG9tY29udGVudGxvYWRlZCdcclxuICAgICAgfSk7XHJcbiAgICB9IGVsc2Uge1xyXG4gICAgICBsb2coNCwgJ1tleHBvcnRdIFRyZWF0aW5nIGFzIEpTT04gY29uZmlnLicpO1xyXG5cclxuICAgICAgLy8gT3B0aW9ucyBleHBvcnRcclxuICAgICAgYXdhaXQgcGFnZS5ldmFsdWF0ZShjcmVhdGVDaGFydCwgZXhwb3J0T3B0aW9ucywgY3VzdG9tTG9naWNPcHRpb25zKTtcclxuICAgIH1cclxuXHJcbiAgICAvLyBLZWVwcyB0cmFjayBvZiBhbGwgcmVzb3VyY2VzIGFkZGVkIG9uIHRoZSBwYWdlIHdpdGggYWRkWFhYVGFnLiBldGNcclxuICAgIC8vIEl0J3MgVklUQUwgdGhhdCBhbGwgYWRkZWQgcmVzb3VyY2VzIGVuZHMgdXAgaGVyZSBzbyB3ZSBjYW4gY2xlYXIgdGhpbmdzXHJcbiAgICAvLyBvdXQgd2hlbiBkb2luZyBhIG5ldyBleHBvcnQgaW4gdGhlIHNhbWUgcGFnZSFcclxuICAgIGluamVjdGVkUmVzb3VyY2VzLnB1c2goXHJcbiAgICAgIC4uLihhd2FpdCBhZGRQYWdlUmVzb3VyY2VzKHBhZ2UsIGN1c3RvbUxvZ2ljT3B0aW9ucykpXHJcbiAgICApO1xyXG5cclxuICAgIC8vIEdldCB0aGUgcmVhbCBjaGFydCBzaXplIGFuZCBzZXQgdGhlIHpvb20gYWNjb3JkaW5nbHlcclxuICAgIGNvbnN0IHNpemUgPSBhd2FpdCBfZ2V0Q2hhcnRTaXplKHBhZ2UsIGlzU1ZHLCBleHBvcnRPcHRpb25zLnNjYWxlKTtcclxuXHJcbiAgICAvLyBHZXQgdGhlIGNsaXAgcmVnaW9uIGZvciB0aGUgcGFnZVxyXG4gICAgY29uc3QgeyB4LCB5IH0gPSBhd2FpdCBfZ2V0Q2xpcFJlZ2lvbihwYWdlKTtcclxuXHJcbiAgICAvLyBTZXQgZmluYWwgYGhlaWdodGAgZm9yIHZpZXdwb3J0XHJcbiAgICBjb25zdCB2aWV3cG9ydEhlaWdodCA9IE1hdGguYWJzKFxyXG4gICAgICBNYXRoLmNlaWwoc2l6ZS5jaGFydEhlaWdodCB8fCBleHBvcnRPcHRpb25zLmhlaWdodClcclxuICAgICk7XHJcblxyXG4gICAgLy8gU2V0IGZpbmFsIGB3aWR0aGAgZm9yIHZpZXdwb3J0XHJcbiAgICBjb25zdCB2aWV3cG9ydFdpZHRoID0gTWF0aC5hYnMoXHJcbiAgICAgIE1hdGguY2VpbChzaXplLmNoYXJ0V2lkdGggfHwgZXhwb3J0T3B0aW9ucy53aWR0aClcclxuICAgICk7XHJcblxyXG4gICAgLy8gU2V0IHRoZSBmaW5hbCB2aWV3cG9ydCBub3cgdGhhdCB3ZSBoYXZlIHRoZSByZWFsIGhlaWdodFxyXG4gICAgYXdhaXQgcGFnZS5zZXRWaWV3cG9ydCh7XHJcbiAgICAgIGhlaWdodDogdmlld3BvcnRIZWlnaHQsXHJcbiAgICAgIHdpZHRoOiB2aWV3cG9ydFdpZHRoLFxyXG4gICAgICBkZXZpY2VTY2FsZUZhY3RvcjogaXNTVkcgPyAxIDogcGFyc2VGbG9hdChleHBvcnRPcHRpb25zLnNjYWxlKVxyXG4gICAgfSk7XHJcblxyXG4gICAgbGV0IHJlc3VsdDtcclxuICAgIC8vIFJhc3Rlcml6YXRpb24gcHJvY2Vzc1xyXG4gICAgc3dpdGNoIChleHBvcnRPcHRpb25zLnR5cGUpIHtcclxuICAgICAgY2FzZSAnc3ZnJzpcclxuICAgICAgICByZXN1bHQgPSBhd2FpdCBfY3JlYXRlU1ZHKHBhZ2UpO1xyXG4gICAgICAgIGJyZWFrO1xyXG4gICAgICBjYXNlICdwbmcnOlxyXG4gICAgICBjYXNlICdqcGVnJzpcclxuICAgICAgICByZXN1bHQgPSBhd2FpdCBfY3JlYXRlSW1hZ2UoXHJcbiAgICAgICAgICBwYWdlLFxyXG4gICAgICAgICAgZXhwb3J0T3B0aW9ucy50eXBlLFxyXG4gICAgICAgICAge1xyXG4gICAgICAgICAgICB3aWR0aDogdmlld3BvcnRXaWR0aCxcclxuICAgICAgICAgICAgaGVpZ2h0OiB2aWV3cG9ydEhlaWdodCxcclxuICAgICAgICAgICAgeCxcclxuICAgICAgICAgICAgeVxyXG4gICAgICAgICAgfSxcclxuICAgICAgICAgIGV4cG9ydE9wdGlvbnMucmFzdGVyaXphdGlvblRpbWVvdXRcclxuICAgICAgICApO1xyXG4gICAgICAgIGJyZWFrO1xyXG4gICAgICBjYXNlICdwZGYnOlxyXG4gICAgICAgIHJlc3VsdCA9IGF3YWl0IF9jcmVhdGVQREYoXHJcbiAgICAgICAgICBwYWdlLFxyXG4gICAgICAgICAgdmlld3BvcnRIZWlnaHQsXHJcbiAgICAgICAgICB2aWV3cG9ydFdpZHRoLFxyXG4gICAgICAgICAgZXhwb3J0T3B0aW9ucy5yYXN0ZXJpemF0aW9uVGltZW91dFxyXG4gICAgICAgICk7XHJcbiAgICAgICAgYnJlYWs7XHJcbiAgICAgIGRlZmF1bHQ6XHJcbiAgICAgICAgdGhyb3cgbmV3IEV4cG9ydEVycm9yKFxyXG4gICAgICAgICAgYFtleHBvcnRdIFVuc3VwcG9ydGVkIG91dHB1dCBmb3JtYXQ6ICR7ZXhwb3J0T3B0aW9ucy50eXBlfS5gLFxyXG4gICAgICAgICAgNDAwXHJcbiAgICAgICAgKTtcclxuICAgIH1cclxuXHJcbiAgICAvLyBDbGVhciBwcmV2aW91c2x5IGluamVjdGVkIEpTIGFuZCBDU1MgcmVzb3VyY2VzXHJcbiAgICBhd2FpdCBjbGVhclBhZ2VSZXNvdXJjZXMocGFnZSwgaW5qZWN0ZWRSZXNvdXJjZXMpO1xyXG4gICAgcmV0dXJuIHJlc3VsdDtcclxuICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgYXdhaXQgY2xlYXJQYWdlUmVzb3VyY2VzKHBhZ2UsIGluamVjdGVkUmVzb3VyY2VzKTtcclxuICAgIHJldHVybiBlcnJvcjtcclxuICB9XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBSZXRyaWV2ZXMgdGhlIGNsaXBwaW5nIHJlZ2lvbiBjb29yZGluYXRlcyBvZiB0aGUgc3BlY2lmaWVkIHBhZ2UgZWxlbWVudFxyXG4gKiB3aXRoIHRoZSAnY2hhcnQtY29udGFpbmVyJyBpZC5cclxuICpcclxuICogQGFzeW5jXHJcbiAqIEBmdW5jdGlvbiBfZ2V0Q2xpcFJlZ2lvblxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gcGFnZSAtIFB1cHBldGVlciBwYWdlIG9iamVjdC5cclxuICpcclxuICogQHJldHVybnMge1Byb21pc2U8T2JqZWN0Pn0gQSBQcm9taXNlIHRoYXQgcmVzb2x2ZXMgdG8gYW4gb2JqZWN0IGNvbnRhaW5pbmdcclxuICogYHhgLCBgeWAsIGB3aWR0aGAsIGFuZCBgaGVpZ2h0YCBwcm9wZXJ0aWVzLlxyXG4gKi9cclxuYXN5bmMgZnVuY3Rpb24gX2dldENsaXBSZWdpb24ocGFnZSkge1xyXG4gIHJldHVybiBwYWdlLiRldmFsKCcjY2hhcnQtY29udGFpbmVyJywgKGVsZW1lbnQpID0+IHtcclxuICAgIGNvbnN0IHsgeCwgeSwgd2lkdGgsIGhlaWdodCB9ID0gZWxlbWVudC5nZXRCb3VuZGluZ0NsaWVudFJlY3QoKTtcclxuICAgIHJldHVybiB7XHJcbiAgICAgIHgsXHJcbiAgICAgIHksXHJcbiAgICAgIHdpZHRoLFxyXG4gICAgICBoZWlnaHQ6IE1hdGgudHJ1bmMoaGVpZ2h0ID4gMSA/IGhlaWdodCA6IDUwMClcclxuICAgIH07XHJcbiAgfSk7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBSZXRyaWV2ZXMgdGhlIHJlYWwgY2hhcnQgZGltZW5zaW9ucyBmcm9tIGEgUHVwcGV0ZWVyIHBhZ2UuIFRoZSBmdW5jdGlvblxyXG4gKiBiZWhhdmVzIGRpZmZlcmVudGx5IGJhc2VkIG9uIHdoZXRoZXIgdGhlIGV4cG9ydCB0eXBlIGlzIFNWRyBvciBhbm90aGVyXHJcbiAqIGZvcm1hdC5cclxuICpcclxuICogQGFzeW5jXHJcbiAqIEBmdW5jdGlvbiBfZ2V0Q2hhcnRTaXplXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBwYWdlIC0gUHVwcGV0ZWVyIHBhZ2Ugb2JqZWN0LlxyXG4gKiBAcGFyYW0ge2Jvb2xlYW59IGlzU1ZHIC0gRGV0ZXJtaW5lcyB3aGV0aGVyIHRoZSBjaGFydCBiZWluZyBwcm9jZXNzZWRcclxuICogaXMgYW4gU1ZHIG9yIGFub3RoZXIgZm9ybWF0LlxyXG4gKiBAcGFyYW0ge251bWJlcn0gc2NhbGUgLSBUaGUgc2NhbGUgZmFjdG9yIHRvIGJlIGFwcGxpZWQgdG8gdGhlIGNoYXJ0XHJcbiAqIGRpbWVuc2lvbnMuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtQcm9taXNlPE9iamVjdD59IEEgUHJvbWlzZSB0aGF0IHJlc29sdmVzIHRvIGFuIG9iamVjdCBjb250YWluaW5nXHJcbiAqIHRoZSBhY3R1YWwgaGVpZ2h0IGFuZCB3aWR0aCBvZiB0aGUgY2hhcnQgYWZ0ZXIgc2NhbGluZy5cclxuICovXHJcbmFzeW5jIGZ1bmN0aW9uIF9nZXRDaGFydFNpemUocGFnZSwgaXNTVkcsIHNjYWxlKSB7XHJcbiAgLy8gVHJpZ2dlciBhcHByb3ByaWF0ZSBmdW5jdGlvbiBiYXNlZCBvbiB0aGUgYGlzU3ZnYCBmbGFnIHRvIGdldCBjaGFydCBzaXplXHJcbiAgcmV0dXJuIGlzU1ZHXHJcbiAgICA/IGF3YWl0IHBhZ2UuZXZhbHVhdGUoKHNjYWxlKSA9PiB7XHJcbiAgICAgICAgY29uc3Qgc3ZnRWxlbWVudCA9IGRvY3VtZW50LnF1ZXJ5U2VsZWN0b3IoXHJcbiAgICAgICAgICAnI2NoYXJ0LWNvbnRhaW5lciBzdmc6Zmlyc3Qtb2YtdHlwZSdcclxuICAgICAgICApO1xyXG5cclxuICAgICAgICAvLyBHZXQgdGhlIHZhbHVlcyBjb3JyZWN0bHkgc2NhbGVkXHJcbiAgICAgICAgY29uc3QgY2hhcnRIZWlnaHQgPSBzdmdFbGVtZW50LmhlaWdodC5iYXNlVmFsLnZhbHVlICogc2NhbGU7XHJcbiAgICAgICAgY29uc3QgY2hhcnRXaWR0aCA9IHN2Z0VsZW1lbnQud2lkdGguYmFzZVZhbC52YWx1ZSAqIHNjYWxlO1xyXG5cclxuICAgICAgICAvLyBJbiBjYXNlIG9mIFNWRyB0aGUgem9vbSBtdXN0IGJlIHNldCBkaXJlY3RseSBmb3IgYm9keSBhcyBzY2FsZVxyXG4gICAgICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBuby11bmRlZlxyXG4gICAgICAgIGRvY3VtZW50LmJvZHkuc3R5bGUuem9vbSA9IHNjYWxlO1xyXG5cclxuICAgICAgICAvLyBTZXQgdGhlIG1hcmdpbiB0byAwcHhcclxuICAgICAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgbm8tdW5kZWZcclxuICAgICAgICBkb2N1bWVudC5ib2R5LnN0eWxlLm1hcmdpbiA9ICcwcHgnO1xyXG5cclxuICAgICAgICByZXR1cm4ge1xyXG4gICAgICAgICAgY2hhcnRIZWlnaHQsXHJcbiAgICAgICAgICBjaGFydFdpZHRoXHJcbiAgICAgICAgfTtcclxuICAgICAgfSwgcGFyc2VGbG9hdChzY2FsZSkpXHJcbiAgICA6IGF3YWl0IHBhZ2UuZXZhbHVhdGUoKCkgPT4ge1xyXG4gICAgICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBuby11bmRlZlxyXG4gICAgICAgIGNvbnN0IHsgY2hhcnRIZWlnaHQsIGNoYXJ0V2lkdGggfSA9IHdpbmRvdy5IaWdoY2hhcnRzLmNoYXJ0c1swXTtcclxuXHJcbiAgICAgICAgLy8gTm8gbmVlZCBmb3Igc3VjaCBzY2FsZSBtYW5pcHVsYXRpb24gaW4gY2FzZSBvZiBvdGhlciB0eXBlc1xyXG4gICAgICAgIC8vIG9mIGV4cG9ydHMuIFJlc2V0IHRoZSB6b29tIGZvciBvdGhlciBleHBvcnRzIHRoYW4gdG8gU1ZHc1xyXG4gICAgICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBuby11bmRlZlxyXG4gICAgICAgIGRvY3VtZW50LmJvZHkuc3R5bGUuem9vbSA9IDE7XHJcblxyXG4gICAgICAgIHJldHVybiB7XHJcbiAgICAgICAgICBjaGFydEhlaWdodCxcclxuICAgICAgICAgIGNoYXJ0V2lkdGhcclxuICAgICAgICB9O1xyXG4gICAgICB9KTtcclxufVxyXG5cclxuLyoqXHJcbiAqIENyZWF0ZXMgYW4gU1ZHIGJ5IGV2YWx1YXRpbmcgdGhlIGBvdXRlckhUTUxgIG9mIHRoZSBmaXJzdCAnc3ZnJyBlbGVtZW50XHJcbiAqIGluc2lkZSBhbiBlbGVtZW50IHdpdGggdGhlIGlkICdjb250YWluZXInLlxyXG4gKlxyXG4gKiBAYXN5bmNcclxuICogQGZ1bmN0aW9uIF9jcmVhdGVTVkdcclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IHBhZ2UgLSBQdXBwZXRlZXIgcGFnZSBvYmplY3QuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtQcm9taXNlPHN0cmluZz59IEEgUHJvbWlzZSB0aGF0IHJlc29sdmVzIHRvIHRoZSBTVkcgc3RyaW5nLlxyXG4gKi9cclxuYXN5bmMgZnVuY3Rpb24gX2NyZWF0ZVNWRyhwYWdlKSB7XHJcbiAgcmV0dXJuIHBhZ2UuJGV2YWwoXHJcbiAgICAnI2NvbnRhaW5lciBzdmc6Zmlyc3Qtb2YtdHlwZScsXHJcbiAgICAoZWxlbWVudCkgPT4gZWxlbWVudC5vdXRlckhUTUxcclxuICApO1xyXG59XHJcblxyXG4vKipcclxuICogQ3JlYXRlcyBhbiBpbWFnZSB1c2luZyBQdXBwZXRlZXIncyBwYWdlIGBzY3JlZW5zaG90YCBmdW5jdGlvbmFsaXR5IHdpdGhcclxuICogc3BlY2lmaWVkIG9wdGlvbnMuXHJcbiAqXHJcbiAqIEBhc3luY1xyXG4gKiBAZnVuY3Rpb24gX2NyZWF0ZUltYWdlXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBwYWdlIC0gUHVwcGV0ZWVyIHBhZ2Ugb2JqZWN0LlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gdHlwZSAtIEltYWdlIHR5cGUuXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBjbGlwIC0gQ2xpcHBpbmcgcmVnaW9uIGNvb3JkaW5hdGVzLlxyXG4gKiBAcGFyYW0ge251bWJlcn0gcmFzdGVyaXphdGlvblRpbWVvdXQgLSBUaW1lb3V0IGZvciByYXN0ZXJpemF0aW9uXHJcbiAqIGluIG1pbGxpc2Vjb25kcy5cclxuICpcclxuICogQHJldHVybnMge1Byb21pc2U8QnVmZmVyPn0gQSBQcm9taXNlIHRoYXQgcmVzb2x2ZXMgdG8gdGhlIGltYWdlIGJ1ZmZlclxyXG4gKiBvciByZWplY3Rpbmcgd2l0aCBhbiBgRXhwb3J0RXJyb3JgIGZvciB0aW1lb3V0LlxyXG4gKi9cclxuYXN5bmMgZnVuY3Rpb24gX2NyZWF0ZUltYWdlKHBhZ2UsIHR5cGUsIGNsaXAsIHJhc3Rlcml6YXRpb25UaW1lb3V0KSB7XHJcbiAgcmV0dXJuIFByb21pc2UucmFjZShbXHJcbiAgICBwYWdlLnNjcmVlbnNob3Qoe1xyXG4gICAgICB0eXBlLFxyXG4gICAgICBjbGlwLFxyXG4gICAgICBlbmNvZGluZzogJ2Jhc2U2NCcsXHJcbiAgICAgIGZ1bGxQYWdlOiBmYWxzZSxcclxuICAgICAgb3B0aW1pemVGb3JTcGVlZDogdHJ1ZSxcclxuICAgICAgY2FwdHVyZUJleW9uZFZpZXdwb3J0OiB0cnVlLFxyXG4gICAgICAuLi4odHlwZSAhPT0gJ3BuZycgPyB7IHF1YWxpdHk6IDgwIH0gOiB7fSksXHJcbiAgICAgIC8vIEFsd2F5cyByZW5kZXIgb24gYSB0cmFuc3BhcmVudCBwYWdlIGlmIHRoZSBleHBlY3RlZCB0eXBlIGZvcm1hdCBpcyBQTkdcclxuICAgICAgb21pdEJhY2tncm91bmQ6IHR5cGUgPT0gJ3BuZycgLy8gIzQ0NywgIzQ2M1xyXG4gICAgfSksXHJcbiAgICBuZXcgUHJvbWlzZSgoX3Jlc29sdmUsIHJlamVjdCkgPT5cclxuICAgICAgc2V0VGltZW91dChcclxuICAgICAgICAoKSA9PiByZWplY3QobmV3IEV4cG9ydEVycm9yKCdSYXN0ZXJpemF0aW9uIHRpbWVvdXQnLCA0MDgpKSxcclxuICAgICAgICByYXN0ZXJpemF0aW9uVGltZW91dCB8fCAxNTAwXHJcbiAgICAgIClcclxuICAgIClcclxuICBdKTtcclxufVxyXG5cclxuLyoqXHJcbiAqIENyZWF0ZXMgYSBQREYgdXNpbmcgUHVwcGV0ZWVyJ3MgcGFnZSBgcGRmYCBmdW5jdGlvbmFsaXR5IHdpdGggc3BlY2lmaWVkXHJcbiAqIG9wdGlvbnMuXHJcbiAqXHJcbiAqIEBhc3luY1xyXG4gKiBAZnVuY3Rpb24gX2NyZWF0ZVBERlxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gcGFnZSAtIFB1cHBldGVlciBwYWdlIG9iamVjdC5cclxuICogQHBhcmFtIHtudW1iZXJ9IGhlaWdodCAtIFBERiBoZWlnaHQuXHJcbiAqIEBwYXJhbSB7bnVtYmVyfSB3aWR0aCAtIFBERiB3aWR0aC5cclxuICogQHBhcmFtIHtudW1iZXJ9IHJhc3Rlcml6YXRpb25UaW1lb3V0IC0gVGltZW91dCBmb3IgcmFzdGVyaXphdGlvblxyXG4gKiBpbiBtaWxsaXNlY29uZHMuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtQcm9taXNlPEJ1ZmZlcj59IEEgUHJvbWlzZSB0aGF0IHJlc29sdmVzIHRvIHRoZSBQREYgYnVmZmVyLlxyXG4gKi9cclxuYXN5bmMgZnVuY3Rpb24gX2NyZWF0ZVBERihwYWdlLCBoZWlnaHQsIHdpZHRoLCByYXN0ZXJpemF0aW9uVGltZW91dCkge1xyXG4gIGF3YWl0IHBhZ2UuZW11bGF0ZU1lZGlhVHlwZSgnc2NyZWVuJyk7XHJcbiAgcmV0dXJuIHBhZ2UucGRmKHtcclxuICAgIC8vIFRoaXMgd2lsbCByZW1vdmUgYW4gZXh0cmEgZW1wdHkgcGFnZSBpbiBQREYgZXhwb3J0c1xyXG4gICAgaGVpZ2h0OiBoZWlnaHQgKyAxLFxyXG4gICAgd2lkdGgsXHJcbiAgICBlbmNvZGluZzogJ2Jhc2U2NCcsXHJcbiAgICB0aW1lb3V0OiByYXN0ZXJpemF0aW9uVGltZW91dCB8fCAxNTAwXHJcbiAgfSk7XHJcbn1cclxuXHJcbmV4cG9ydCBkZWZhdWx0IHtcclxuICBwdXBwZXRlZXJFeHBvcnRcclxufTtcclxuIiwiLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcclxuXHJcbkhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlclxyXG5cclxuQ29weXJpZ2h0IChjKSAyMDE2LTIwMjUsIEhpZ2hzb2Z0XHJcblxyXG5MaWNlbmNlZCB1bmRlciB0aGUgTUlUIGxpY2VuY2UuXHJcblxyXG5BZGRpdGlvbmFsbHkgYSB2YWxpZCBIaWdoY2hhcnRzIGxpY2Vuc2UgaXMgcmVxdWlyZWQgZm9yIHVzZS5cclxuXHJcblNlZSBMSUNFTlNFIGZpbGUgaW4gcm9vdCBmb3IgZGV0YWlscy5cclxuXHJcbioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXHJcblxyXG4vKipcclxuICogQG92ZXJ2aWV3IFRoaXMgbW9kdWxlIHByb3ZpZGVzIGEgd29ya2VyIHBvb2wgaW1wbGVtZW50YXRpb24gZm9yIG1hbmFnaW5nXHJcbiAqIHRoZSBicm93c2VyIGluc3RhbmNlIGFuZCBwYWdlcywgc3BlY2lmaWNhbGx5IGRlc2lnbmVkIGZvciB1c2Ugd2l0aFxyXG4gKiB0aGUgSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyLiBJdCBvcHRpbWl6ZXMgcmVzb3VyY2VzIHVzYWdlIGFuZCBwZXJmb3JtYW5jZVxyXG4gKiBieSBtYWludGFpbmluZyBhIHBvb2wgb2Ygd29ya2VycyB0aGF0IGNhbiBoYW5kbGUgY29uY3VycmVudCBleHBvcnQgdGFza3NcclxuICogdXNpbmcgUHVwcGV0ZWVyLlxyXG4gKi9cclxuXHJcbmltcG9ydCB7IFBvb2wgfSBmcm9tICd0YXJuJztcclxuaW1wb3J0IHsgdjQgYXMgdXVpZCB9IGZyb20gJ3V1aWQnO1xyXG5cclxuaW1wb3J0IHsgY2xlYXJQYWdlLCBjcmVhdGVCcm93c2VyLCBjbG9zZUJyb3dzZXIsIG5ld1BhZ2UgfSBmcm9tICcuL2Jyb3dzZXIuanMnO1xyXG5pbXBvcnQgeyBwdXBwZXRlZXJFeHBvcnQgfSBmcm9tICcuL2V4cG9ydC5qcyc7XHJcbmltcG9ydCB7IGxvZywgbG9nV2l0aFN0YWNrIH0gZnJvbSAnLi9sb2dnZXIuanMnO1xyXG5pbXBvcnQgeyBnZXROZXdEYXRlVGltZSwgbWVhc3VyZVRpbWUgfSBmcm9tICcuL3V0aWxzLmpzJztcclxuXHJcbmltcG9ydCBFeHBvcnRFcnJvciBmcm9tICcuL2Vycm9ycy9FeHBvcnRFcnJvci5qcyc7XHJcblxyXG4vLyBUaGUgcG9vbCBpbnN0YW5jZVxyXG5sZXQgcG9vbCA9IG51bGw7XHJcblxyXG4vLyBQb29sIHN0YXRpc3RpY3NcclxuY29uc3QgcG9vbFN0YXRzID0ge1xyXG4gIGV4cG9ydHNBdHRlbXB0ZWQ6IDAsXHJcbiAgZXhwb3J0c1BlcmZvcm1lZDogMCxcclxuICBleHBvcnRzRHJvcHBlZDogMCxcclxuICBleHBvcnRzRnJvbVN2ZzogMCxcclxuICBleHBvcnRzRnJvbU9wdGlvbnM6IDAsXHJcbiAgZXhwb3J0c0Zyb21TdmdBdHRlbXB0czogMCxcclxuICBleHBvcnRzRnJvbU9wdGlvbnNBdHRlbXB0czogMCxcclxuICB0aW1lU3BlbnQ6IDAsXHJcbiAgdGltZVNwZW50QXZlcmFnZTogMFxyXG59O1xyXG5cclxuLyoqXHJcbiAqIEluaXRpYWxpemVzIHRoZSBleHBvcnQgcG9vbCB3aXRoIHRoZSBwcm92aWRlZCBjb25maWd1cmF0aW9uLCBjcmVhdGluZ1xyXG4gKiBhIGJyb3dzZXIgaW5zdGFuY2UgYW5kIHNldHRpbmcgdXAgd29ya2VyIHJlc291cmNlcy5cclxuICpcclxuICogQGFzeW5jXHJcbiAqIEBmdW5jdGlvbiBpbml0UG9vbFxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gcG9vbE9wdGlvbnMgLSBUaGUgY29uZmlndXJhdGlvbiBvYmplY3QgY29udGFpbmluZyBgcG9vbGBcclxuICogb3B0aW9ucy5cclxuICogQHBhcmFtIHtBcnJheTxzdHJpbmc+fSBwdXBwZXRlZXJBcmdzIC0gQWRkaXRpb25hbCBhcmd1bWVudHMgZm9yIFB1cHBldGVlclxyXG4gKiBsYXVuY2guXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtQcm9taXNlPHZvaWQ+fSBBIFByb21pc2UgdGhhdCByZXNvbHZlcyB0byBlbmRpbmcgdGhlIGZ1bmN0aW9uXHJcbiAqIGV4ZWN1dGlvbiB3aGVuIGFuIGFscmVhZHkgaW5pdGlhbGl6ZWQgcG9vbCBvZiByZXNvdXJjZXMgaXMgZm91bmQuXHJcbiAqXHJcbiAqIEB0aHJvd3Mge0V4cG9ydEVycm9yfSBUaHJvd3MgYW4gYEV4cG9ydEVycm9yYCBpZiBjb3VsZCBub3QgY3JlYXRlIHRoZSBwb29sXHJcbiAqIG9mIHdvcmtlcnMuXHJcbiAqL1xyXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gaW5pdFBvb2wocG9vbE9wdGlvbnMsIHB1cHBldGVlckFyZ3MpIHtcclxuICAvLyBDcmVhdGUgYSBicm93c2VyIGluc3RhbmNlIHdpdGggdGhlIHB1cHBldGVlciBhcmd1bWVudHNcclxuICBhd2FpdCBjcmVhdGVCcm93c2VyKHB1cHBldGVlckFyZ3MpO1xyXG5cclxuICB0cnkge1xyXG4gICAgbG9nKFxyXG4gICAgICAzLFxyXG4gICAgICBgW3Bvb2xdIEluaXRpYWxpemluZyBwb29sIHdpdGggd29ya2VyczogbWluICR7cG9vbE9wdGlvbnMubWluV29ya2Vyc30sIG1heCAke3Bvb2xPcHRpb25zLm1heFdvcmtlcnN9LmBcclxuICAgICk7XHJcblxyXG4gICAgaWYgKHBvb2wpIHtcclxuICAgICAgbG9nKFxyXG4gICAgICAgIDQsXHJcbiAgICAgICAgJ1twb29sXSBBbHJlYWR5IGluaXRpYWxpemVkLCBwbGVhc2Uga2lsbCBpdCBiZWZvcmUgY3JlYXRpbmcgYSBuZXcgb25lLidcclxuICAgICAgKTtcclxuICAgICAgcmV0dXJuO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIEtlZXAgYW4gZXllIG9uIGEgY29ycmVjdCBtaW4gYW5kIG1heCB3b3JrZXJzIG51bWJlclxyXG4gICAgaWYgKHBvb2xPcHRpb25zLm1pbldvcmtlcnMgPiBwb29sT3B0aW9ucy5tYXhXb3JrZXJzKSB7XHJcbiAgICAgIHBvb2xPcHRpb25zLm1pbldvcmtlcnMgPSBwb29sT3B0aW9ucy5tYXhXb3JrZXJzO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIENyZWF0ZSBhIHBvb2wgYWxvbmcgd2l0aCBhIG1pbmltYWwgbnVtYmVyIG9mIHJlc291cmNlc1xyXG4gICAgcG9vbCA9IG5ldyBQb29sKHtcclxuICAgICAgLy8gR2V0IHRoZSBgY3JlYXRlYCwgYHZhbGlkYXRlYCwgYW5kIGBkZXN0cm95YCBmdW5jdGlvbnNcclxuICAgICAgLi4uX2ZhY3RvcnkocG9vbE9wdGlvbnMpLFxyXG4gICAgICBtaW46IHBvb2xPcHRpb25zLm1pbldvcmtlcnMsXHJcbiAgICAgIG1heDogcG9vbE9wdGlvbnMubWF4V29ya2VycyxcclxuICAgICAgYWNxdWlyZVRpbWVvdXRNaWxsaXM6IHBvb2xPcHRpb25zLmFjcXVpcmVUaW1lb3V0LFxyXG4gICAgICBjcmVhdGVUaW1lb3V0TWlsbGlzOiBwb29sT3B0aW9ucy5jcmVhdGVUaW1lb3V0LFxyXG4gICAgICBkZXN0cm95VGltZW91dE1pbGxpczogcG9vbE9wdGlvbnMuZGVzdHJveVRpbWVvdXQsXHJcbiAgICAgIGlkbGVUaW1lb3V0TWlsbGlzOiBwb29sT3B0aW9ucy5pZGxlVGltZW91dCxcclxuICAgICAgY3JlYXRlUmV0cnlJbnRlcnZhbE1pbGxpczogcG9vbE9wdGlvbnMuY3JlYXRlUmV0cnlJbnRlcnZhbCxcclxuICAgICAgcmVhcEludGVydmFsTWlsbGlzOiBwb29sT3B0aW9ucy5yZWFwZXJJbnRlcnZhbCxcclxuICAgICAgcHJvcGFnYXRlQ3JlYXRlRXJyb3I6IGZhbHNlXHJcbiAgICB9KTtcclxuXHJcbiAgICAvLyBTZXQgZXZlbnRzXHJcbiAgICBwb29sLm9uKCdyZWxlYXNlJywgYXN5bmMgKHJlc291cmNlKSA9PiB7XHJcbiAgICAgIC8vIENsZWFyIHBhZ2VcclxuICAgICAgY29uc3QgY2xlYXJTdGF0dXMgPSBhd2FpdCBjbGVhclBhZ2UocmVzb3VyY2UsIGZhbHNlKTtcclxuICAgICAgbG9nKFxyXG4gICAgICAgIDQsXHJcbiAgICAgICAgYFtwb29sXSBQb29sIHJlc291cmNlIFske3Jlc291cmNlLmlkfV0gLSBSZWxlYXNpbmcgYSB3b3JrZXIuIENsZWFyIHBhZ2Ugc3RhdHVzOiAke2NsZWFyU3RhdHVzfS5gXHJcbiAgICAgICk7XHJcbiAgICB9KTtcclxuXHJcbiAgICBwb29sLm9uKCdkZXN0cm95U3VjY2VzcycsIChfZXZlbnRJZCwgcmVzb3VyY2UpID0+IHtcclxuICAgICAgbG9nKFxyXG4gICAgICAgIDQsXHJcbiAgICAgICAgYFtwb29sXSBQb29sIHJlc291cmNlIFske3Jlc291cmNlLmlkfV0gLSBEZXN0cm95ZWQgYSB3b3JrZXIgc3VjY2Vzc2Z1bGx5LmBcclxuICAgICAgKTtcclxuICAgICAgcmVzb3VyY2UucGFnZSA9IG51bGw7XHJcbiAgICB9KTtcclxuXHJcbiAgICBjb25zdCBpbml0aWFsUmVzb3VyY2VzID0gW107XHJcbiAgICAvLyBDcmVhdGUgYW4gaW5pdGlhbCBudW1iZXIgb2YgcmVzb3VyY2VzXHJcbiAgICBmb3IgKGxldCBpID0gMDsgaSA8IHBvb2xPcHRpb25zLm1pbldvcmtlcnM7IGkrKykge1xyXG4gICAgICB0cnkge1xyXG4gICAgICAgIGNvbnN0IHJlc291cmNlID0gYXdhaXQgcG9vbC5hY3F1aXJlKCkucHJvbWlzZTtcclxuICAgICAgICBpbml0aWFsUmVzb3VyY2VzLnB1c2gocmVzb3VyY2UpO1xyXG4gICAgICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgICAgIGxvZ1dpdGhTdGFjaygyLCBlcnJvciwgJ1twb29sXSBDb3VsZCBub3QgY3JlYXRlIGFuIGluaXRpYWwgcmVzb3VyY2UuJyk7XHJcbiAgICAgIH1cclxuICAgIH1cclxuXHJcbiAgICAvLyBSZWxlYXNlIHRoZSBpbml0aWFsIG51bWJlciBvZiByZXNvdXJjZXMgYmFjayB0byB0aGUgcG9vbFxyXG4gICAgaW5pdGlhbFJlc291cmNlcy5mb3JFYWNoKChyZXNvdXJjZSkgPT4ge1xyXG4gICAgICBwb29sLnJlbGVhc2UocmVzb3VyY2UpO1xyXG4gICAgfSk7XHJcblxyXG4gICAgbG9nKFxyXG4gICAgICAzLFxyXG4gICAgICBgW3Bvb2xdIFRoZSBwb29sIGlzIHJlYWR5JHtpbml0aWFsUmVzb3VyY2VzLmxlbmd0aCA/IGAgd2l0aCAke2luaXRpYWxSZXNvdXJjZXMubGVuZ3RofSBpbml0aWFsIHJlc291cmNlcyB3YWl0aW5nLmAgOiAnLid9YFxyXG4gICAgKTtcclxuICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgdGhyb3cgbmV3IEV4cG9ydEVycm9yKFxyXG4gICAgICAnW3Bvb2xdIENvdWxkIG5vdCBjb25maWd1cmUgYW5kIGNyZWF0ZSB0aGUgcG9vbCBvZiB3b3JrZXJzLicsXHJcbiAgICAgIDUwMFxyXG4gICAgKS5zZXRFcnJvcihlcnJvcik7XHJcbiAgfVxyXG59XHJcblxyXG4vKipcclxuICogVGVybWluYXRlcyBhbGwgd29ya2VycyBpbiB0aGUgcG9vbCwgZGVzdHJveXMgdGhlIHBvb2wsIGFuZCBjbG9zZXMgdGhlIGJyb3dzZXJcclxuICogaW5zdGFuY2UuXHJcbiAqXHJcbiAqIEBhc3luY1xyXG4gKiBAZnVuY3Rpb24ga2lsbFBvb2xcclxuICpcclxuICogQHJldHVybnMge1Byb21pc2U8dm9pZD59IEEgUHJvbWlzZSB0aGF0IHJlc29sdmVzIG9uY2UgYWxsIHdvcmtlcnMgYXJlXHJcbiAqIHRlcm1pbmF0ZWQsIHRoZSBwb29sIGlzIGRlc3Ryb3llZCwgYW5kIHRoZSBicm93c2VyIGlzIHN1Y2Nlc3NmdWxseSBjbG9zZWQuXHJcbiAqL1xyXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24ga2lsbFBvb2woKSB7XHJcbiAgbG9nKDMsICdbcG9vbF0gS2lsbGluZyBwb29sIHdpdGggYWxsIHdvcmtlcnMgYW5kIGNsb3NpbmcgYnJvd3Nlci4nKTtcclxuXHJcbiAgLy8gSWYgc3RpbGwgYWxpdmUsIGRlc3Ryb3kgdGhlIHBvb2wgb2YgcGFnZXMgYmVmb3JlIGNsb3NpbmcgYSBicm93c2VyXHJcbiAgaWYgKHBvb2wpIHtcclxuICAgIC8vIEZyZWUgdXAgbm90IHJlbGVhc2VkIHdvcmtlcnNcclxuICAgIGZvciAoY29uc3Qgd29ya2VyIG9mIHBvb2wudXNlZCkge1xyXG4gICAgICBwb29sLnJlbGVhc2Uod29ya2VyLnJlc291cmNlKTtcclxuICAgIH1cclxuXHJcbiAgICAvLyBEZXN0cm95IHRoZSBwb29sIGlmIGl0IGlzIHN0aWxsIGF2YWlsYWJsZVxyXG4gICAgaWYgKCFwb29sLmRlc3Ryb3llZCkge1xyXG4gICAgICBhd2FpdCBwb29sLmRlc3Ryb3koKTtcclxuICAgICAgbG9nKDQsICdbcG9vbF0gRGVzdHJveWVkIHRoZSBwb29sIG9mIHJlc291cmNlcy4nKTtcclxuICAgIH1cclxuICAgIHBvb2wgPSBudWxsO1xyXG4gIH1cclxuXHJcbiAgLy8gQ2xvc2UgdGhlIGJyb3dzZXIgaW5zdGFuY2VcclxuICBhd2FpdCBjbG9zZUJyb3dzZXIoKTtcclxufVxyXG5cclxuLyoqXHJcbiAqIFByb2Nlc3NlcyB0aGUgZXhwb3J0IHdvcmsgdXNpbmcgYSB3b3JrZXIgZnJvbSB0aGUgcG9vbC4gQWNxdWlyZXMgYSB3b3JrZXJcclxuICogaGFuZGxlIGZyb20gdGhlIHBvb2wsIHBlcmZvcm1zIHRoZSBleHBvcnQgdXNpbmcgcHVwcGV0ZWVyLCBhbmQgcmVsZWFzZXNcclxuICogdGhlIHdvcmtlciBoYW5kbGUgYmFjayB0byB0aGUgcG9vbC5cclxuICpcclxuICogQGFzeW5jXHJcbiAqIEBmdW5jdGlvbiBwb3N0V29ya1xyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gb3B0aW9ucyAtIFRoZSBjb25maWd1cmF0aW9uIG9iamVjdCBjb250YWluaW5nIGNvbXBsZXRlIHNldFxyXG4gKiBvZiBvcHRpb25zLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7UHJvbWlzZTxPYmplY3Q+fSBBIFByb21pc2UgdGhhdCByZXNvbHZlcyB0byB0aGUgZXhwb3J0IHJlc3VsdFxyXG4gKiBhbmQgb3B0aW9ucy5cclxuICpcclxuICogQHRocm93cyB7RXhwb3J0RXJyb3J9IFRocm93cyBhbiBgRXhwb3J0RXJyb3JgIGlmIGFuIGVycm9yIG9jY3VycyBkdXJpbmdcclxuICogdGhlIGV4cG9ydCBwcm9jZXNzLlxyXG4gKi9cclxuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIHBvc3RXb3JrKG9wdGlvbnMpIHtcclxuICBsZXQgd29ya2VySGFuZGxlO1xyXG5cclxuICB0cnkge1xyXG4gICAgbG9nKDQsICdbcG9vbF0gV29yayByZWNlaXZlZCwgc3RhcnRpbmcgdG8gcHJvY2Vzcy4nKTtcclxuXHJcbiAgICAvLyBBbiBleHBvcnQgYXR0ZW1wdCBjb3VudGVkXHJcbiAgICArK3Bvb2xTdGF0cy5leHBvcnRzQXR0ZW1wdGVkO1xyXG5cclxuICAgIC8vIERpc3BsYXkgdGhlIHBvb2wgaW5mb3JtYXRpb24gaWYgbmVlZGVkXHJcbiAgICBpZiAob3B0aW9ucy5wb29sLmJlbmNobWFya2luZykge1xyXG4gICAgICBfZ2V0UG9vbEluZm8oKTtcclxuICAgIH1cclxuXHJcbiAgICAvLyBUaHJvdyBhbiBlcnJvciBpbiBjYXNlIG9mIGxhY2tpbmcgdGhlIHBvb2wgaW5zdGFuY2VcclxuICAgIGlmICghcG9vbCkge1xyXG4gICAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoXHJcbiAgICAgICAgJ1twb29sXSBXb3JrIHJlY2VpdmVkLCBidXQgcG9vbCBoYXMgbm90IGJlZW4gc3RhcnRlZC4nLFxyXG4gICAgICAgIDUwMFxyXG4gICAgICApO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIFRoZSBhY3F1aXJlIGNvdW50ZXJcclxuICAgIGNvbnN0IGFjcXVpcmVDb3VudGVyID0gbWVhc3VyZVRpbWUoKTtcclxuXHJcbiAgICAvLyBUcnkgdG8gYWNxdWlyZSB0aGUgd29ya2VyIGFsb25nIHdpdGggdGhlIGlkLCB3b3JrcyBjb3VudCBhbmQgcGFnZVxyXG4gICAgdHJ5IHtcclxuICAgICAgbG9nKDQsICdbcG9vbF0gQWNxdWlyaW5nIGEgd29ya2VyIGhhbmRsZS4nKTtcclxuXHJcbiAgICAgIC8vIEFjcXVpcmUgYSBwb29sIHJlc291cmNlXHJcbiAgICAgIHdvcmtlckhhbmRsZSA9IGF3YWl0IHBvb2wuYWNxdWlyZSgpLnByb21pc2U7XHJcblxyXG4gICAgICAvLyBDaGVjayB0aGUgcGFnZSBhY3F1aXJlIHRpbWVcclxuICAgICAgaWYgKG9wdGlvbnMuc2VydmVyLmJlbmNobWFya2luZykge1xyXG4gICAgICAgIGxvZyhcclxuICAgICAgICAgIDUsXHJcbiAgICAgICAgICBgW2JlbmNobWFya10gJHtvcHRpb25zLnJlcXVlc3RJZCA/IGBSZXF1ZXN0IFske29wdGlvbnMucmVxdWVzdElkfV0gLSBgIDogJyd9YCxcclxuICAgICAgICAgIGBBY3F1aXJpbmcgYSB3b3JrZXIgaGFuZGxlIHRvb2sgJHthY3F1aXJlQ291bnRlcigpfW1zLmBcclxuICAgICAgICApO1xyXG4gICAgICB9XHJcbiAgICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoXHJcbiAgICAgICAgYFtwb29sXSAke1xyXG4gICAgICAgICAgb3B0aW9ucy5yZXF1ZXN0SWQgPyBgUmVxdWVzdCBbJHtvcHRpb25zLnJlcXVlc3RJZH1dIC0gYCA6ICcnXHJcbiAgICAgICAgfUVycm9yIGVuY291bnRlcmVkIHdoZW4gYWNxdWlyaW5nIGFuIGF2YWlsYWJsZSBlbnRyeTogJHthY3F1aXJlQ291bnRlcigpfW1zLmAsXHJcbiAgICAgICAgNDAwXHJcbiAgICAgICkuc2V0RXJyb3IoZXJyb3IpO1xyXG4gICAgfVxyXG4gICAgbG9nKDQsICdbcG9vbF0gQWNxdWlyZWQgYSB3b3JrZXIgaGFuZGxlLicpO1xyXG5cclxuICAgIGlmICghd29ya2VySGFuZGxlLnBhZ2UpIHtcclxuICAgICAgLy8gU2V0IHRoZSBgd29ya0xpbWl0YCB0byBleGNlZWRlZCBpbiBvcmRlciB0byByZWNyZWF0ZSB0aGUgcmVzb3VyY2VcclxuICAgICAgd29ya2VySGFuZGxlLndvcmtDb3VudCA9IG9wdGlvbnMucG9vbC53b3JrTGltaXQgKyAxO1xyXG4gICAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoXHJcbiAgICAgICAgJ1twb29sXSBSZXNvbHZlZCB3b3JrZXIgcGFnZSBpcyBpbnZhbGlkOiB0aGUgcG9vbCBzZXR1cCBpcyB3b25reS4nLFxyXG4gICAgICAgIDQwMFxyXG4gICAgICApO1xyXG4gICAgfVxyXG5cclxuICAgIGxvZyhcclxuICAgICAgNCxcclxuICAgICAgYFtwb29sXSBQb29sIHJlc291cmNlIFske3dvcmtlckhhbmRsZS5pZH1dIC0gU3RhcnRpbmcgd29yayBvbiB0aGlzIHBvb2wgZW50cnkuYFxyXG4gICAgKTtcclxuXHJcbiAgICAvLyBTdGFydCBtZWFzdXJpbmcgZXhwb3J0IHRpbWVcclxuICAgIGNvbnN0IGV4cG9ydENvdW50ZXIgPSBtZWFzdXJlVGltZSgpO1xyXG5cclxuICAgIC8vIFBlcmZvcm0gYW4gZXhwb3J0IG9uIGEgcHVwcGV0ZWVyIGxldmVsXHJcbiAgICBjb25zdCBleHBvcnRSZXN1bHQgPSBhd2FpdCBwdXBwZXRlZXJFeHBvcnQoXHJcbiAgICAgIHdvcmtlckhhbmRsZS5wYWdlLFxyXG4gICAgICBvcHRpb25zLmV4cG9ydCxcclxuICAgICAgb3B0aW9ucy5jdXN0b21Mb2dpY1xyXG4gICAgKTtcclxuXHJcbiAgICAvLyBDaGVjayBpZiBpdCdzIGFuIGVycm9yXHJcbiAgICBpZiAoZXhwb3J0UmVzdWx0IGluc3RhbmNlb2YgRXJyb3IpIHtcclxuICAgICAgLy8gTk9URTpcclxuICAgICAgLy8gSWYgdGhlcmUncyBhIHJhc3Rlcml6YXRpb24gdGltZW91dCwgd2Ugd2FudCBuZWVkIHRvIGZsdXNoIHRoZSBwYWdlLlxyXG4gICAgICAvLyBUaGlzIGlzIGJlY2F1c2UgdGhlIHBhZ2UgbWF5IGJlIGluIGEgc3RhdGUgd2hlcmUgaXQncyB3YWl0aW5nIGZvclxyXG4gICAgICAvLyB0aGUgc2NyZWVuc2hvdCB0byBmaW5pc2ggZXZlbiB0aG91Z2ggdGhlIHRpbWVvdXQgaGFzIG9jY3VyZWQuXHJcbiAgICAgIC8vIFdoaWNoIG9mIGNvdXJzZSBjYXVzZXMgYSBsb3Qgb2YgaXNzdWVzIHdpdGggdGhlIGV2ZW50IHN5c3RlbSxcclxuICAgICAgLy8gYW5kIHBhZ2UgY29uc2lzdGVuY3kuXHJcbiAgICAgIC8vXHJcbiAgICAgIC8vIE9ubHkgYHBhZ2Uuc2NyZWVuc2hvdGAgd2lsbCB0aHJvdyB0aGlzLCB0aW1lb3V0cyBmb3IgUERGJ3MgYXJlXHJcbiAgICAgIC8vIGhhbmRsZWQgYnkgdGhlIGBwYWdlLnBkZmAgZnVuY3Rpb24gaXRzZWxmLlxyXG4gICAgICAvL1xyXG4gICAgICAvLyAuLi55ZXMsIHRoaXMgaXMgdWdseS5cclxuICAgICAgaWYgKGV4cG9ydFJlc3VsdC5tZXNzYWdlID09PSAnUmFzdGVyaXphdGlvbiB0aW1lb3V0Jykge1xyXG4gICAgICAgIC8vIFNldCB0aGUgYHdvcmtMaW1pdGAgdG8gZXhjZWVkZWQgaW4gb3JkZXIgdG8gcmVjcmVhdGUgdGhlIHJlc291cmNlXHJcbiAgICAgICAgd29ya2VySGFuZGxlLndvcmtDb3VudCA9IG9wdGlvbnMucG9vbC53b3JrTGltaXQgKyAxO1xyXG4gICAgICAgIHdvcmtlckhhbmRsZS5wYWdlID0gbnVsbDtcclxuICAgICAgfVxyXG5cclxuICAgICAgaWYgKFxyXG4gICAgICAgIGV4cG9ydFJlc3VsdC5uYW1lID09PSAnVGltZW91dEVycm9yJyB8fFxyXG4gICAgICAgIGV4cG9ydFJlc3VsdC5tZXNzYWdlID09PSAnUmFzdGVyaXphdGlvbiB0aW1lb3V0J1xyXG4gICAgICApIHtcclxuICAgICAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoXHJcbiAgICAgICAgICBgW3Bvb2xdICR7XHJcbiAgICAgICAgICAgIG9wdGlvbnMucmVxdWVzdElkID8gYFJlcXVlc3QgWyR7b3B0aW9ucy5yZXF1ZXN0SWR9XSAtIGAgOiAnJ1xyXG4gICAgICAgICAgfVJhc3Rlcml6YXRpb24gdGltZW91dDogeW91ciBjaGFydCBtYXkgYmUgdG9vIGNvbXBsZXggb3IgbGFyZ2UsIGFuZCBmYWlsZWQgdG8gcmVuZGVyIHdpdGhpbiB0aGUgYWxsb3R0ZWQgdGltZS5gXHJcbiAgICAgICAgKS5zZXRFcnJvcihleHBvcnRSZXN1bHQpO1xyXG4gICAgICB9IGVsc2Uge1xyXG4gICAgICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcihcclxuICAgICAgICAgIGBbcG9vbF0gJHtcclxuICAgICAgICAgICAgb3B0aW9ucy5yZXF1ZXN0SWQgPyBgUmVxdWVzdCBbJHtvcHRpb25zLnJlcXVlc3RJZH1dIC0gYCA6ICcnXHJcbiAgICAgICAgICB9RXJyb3IgZW5jb3VudGVyZWQgZHVyaW5nIGV4cG9ydDogJHtleHBvcnRDb3VudGVyKCl9bXMuYFxyXG4gICAgICAgICkuc2V0RXJyb3IoZXhwb3J0UmVzdWx0KTtcclxuICAgICAgfVxyXG4gICAgfVxyXG5cclxuICAgIC8vIENoZWNrIHRoZSBQdXBwZXRlZXIgZXhwb3J0IHRpbWVcclxuICAgIGlmIChvcHRpb25zLnNlcnZlci5iZW5jaG1hcmtpbmcpIHtcclxuICAgICAgbG9nKFxyXG4gICAgICAgIDUsXHJcbiAgICAgICAgYFtiZW5jaG1hcmtdICR7b3B0aW9ucy5yZXF1ZXN0SWQgPyBgUmVxdWVzdCBbJHtvcHRpb25zLnJlcXVlc3RJZH1dIC0gYCA6ICcnfWAsXHJcbiAgICAgICAgYEV4cG9ydGluZyBhIGNoYXJ0IHN1Y2Vzc2Z1bGx5IHRvb2sgJHtleHBvcnRDb3VudGVyKCl9bXMuYFxyXG4gICAgICApO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIFJlbGVhc2UgdGhlIHJlc291cmNlIGJhY2sgdG8gdGhlIHBvb2xcclxuICAgIHBvb2wucmVsZWFzZSh3b3JrZXJIYW5kbGUpO1xyXG5cclxuICAgIC8vIFVwZGF0ZSBzdGF0aXN0aWNzXHJcbiAgICBwb29sU3RhdHMudGltZVNwZW50ICs9IGV4cG9ydENvdW50ZXIoKTtcclxuICAgIHBvb2xTdGF0cy50aW1lU3BlbnRBdmVyYWdlID1cclxuICAgICAgcG9vbFN0YXRzLnRpbWVTcGVudCAvICsrcG9vbFN0YXRzLmV4cG9ydHNQZXJmb3JtZWQ7XHJcblxyXG4gICAgbG9nKDQsIGBbcG9vbF0gV29yayBjb21wbGV0ZWQgaW4gJHtleHBvcnRDb3VudGVyKCl9bXMuYCk7XHJcblxyXG4gICAgLy8gT3RoZXJ3aXNlIHJldHVybiBhbiBvYmplY3Qgd2l0aCB0aGUgcmVzdWx0IGFuZCBvcHRpb25zXHJcbiAgICByZXR1cm4ge1xyXG4gICAgICByZXN1bHQ6IGV4cG9ydFJlc3VsdCxcclxuICAgICAgb3B0aW9uc1xyXG4gICAgfTtcclxuICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgKytwb29sU3RhdHMuZXhwb3J0c0Ryb3BwZWQ7XHJcblxyXG4gICAgLy8gVHJ5IHRvIHJlbGVhc2UgdGhlIHdvcmtlciwgaWYgaXQgZXhpc3RzXHJcbiAgICBpZiAod29ya2VySGFuZGxlKSB7XHJcbiAgICAgIHBvb2wucmVsZWFzZSh3b3JrZXJIYW5kbGUpO1xyXG4gICAgfVxyXG5cclxuICAgIHRocm93IGVycm9yO1xyXG4gIH1cclxufVxyXG5cclxuLyoqXHJcbiAqIFJldHJpZXZlcyB0aGUgY3VycmVudCBwb29sIGluc3RhbmNlLlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gZ2V0UG9vbFxyXG4gKlxyXG4gKiBAcmV0dXJucyB7KE9iamVjdHxudWxsKX0gVGhlIGN1cnJlbnQgcG9vbCBpbnN0YW5jZSBpZiBpbml0aWFsaXplZCwgb3IgYG51bGxgXHJcbiAqIGlmIHRoZSBwb29sIGhhcyBub3QgYmVlbiBjcmVhdGVkLlxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIGdldFBvb2woKSB7XHJcbiAgcmV0dXJuIHBvb2w7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBHZXRzIHRoZSBzdGF0aXN0aWMgb2YgYSBwb29sIGluc3RhY2UgYWJvdXQgZXhwb3J0cy5cclxuICpcclxuICogQGZ1bmN0aW9uIGdldFBvb2xTdGF0c1xyXG4gKlxyXG4gKiBAcmV0dXJucyB7T2JqZWN0fSBUaGUgY3VycmVudCBwb29sIHN0YXRpc3RpY3MuXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gZ2V0UG9vbFN0YXRzKCkge1xyXG4gIHJldHVybiBwb29sU3RhdHM7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBSZXRyaWV2ZXMgcG9vbCBpbmZvcm1hdGlvbiBpbiBKU09OIGZvcm1hdCwgaW5jbHVkaW5nIG1pbmltdW0gYW5kIG1heGltdW1cclxuICogd29ya2VycywgYXZhaWxhYmxlIHdvcmtlcnMsIHdvcmtlcnMgaW4gdXNlLCBhbmQgcGVuZGluZyBhY3F1aXJlIHJlcXVlc3RzLlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gZ2V0UG9vbEluZm9KU09OXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtPYmplY3R9IFBvb2wgaW5mb3JtYXRpb24gaW4gSlNPTiBmb3JtYXQuXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gZ2V0UG9vbEluZm9KU09OKCkge1xyXG4gIHJldHVybiB7XHJcbiAgICBtaW46IHBvb2wubWluLFxyXG4gICAgbWF4OiBwb29sLm1heCxcclxuICAgIHVzZWQ6IHBvb2wubnVtVXNlZCgpLFxyXG4gICAgYXZhaWxhYmxlOiBwb29sLm51bUZyZWUoKSxcclxuICAgIGFsbENyZWF0ZWQ6IHBvb2wubnVtVXNlZCgpICsgcG9vbC5udW1GcmVlKCksXHJcbiAgICBwZW5kaW5nQWNxdWlyZXM6IHBvb2wubnVtUGVuZGluZ0FjcXVpcmVzKCksXHJcbiAgICBwZW5kaW5nQ3JlYXRlczogcG9vbC5udW1QZW5kaW5nQ3JlYXRlcygpLFxyXG4gICAgcGVuZGluZ1ZhbGlkYXRpb25zOiBwb29sLm51bVBlbmRpbmdWYWxpZGF0aW9ucygpLFxyXG4gICAgcGVuZGluZ0Rlc3Ryb3lzOiBwb29sLnBlbmRpbmdEZXN0cm95cy5sZW5ndGgsXHJcbiAgICBhYnNvbHV0ZUFsbDpcclxuICAgICAgcG9vbC5udW1Vc2VkKCkgK1xyXG4gICAgICBwb29sLm51bUZyZWUoKSArXHJcbiAgICAgIHBvb2wubnVtUGVuZGluZ0FjcXVpcmVzKCkgK1xyXG4gICAgICBwb29sLm51bVBlbmRpbmdDcmVhdGVzKCkgK1xyXG4gICAgICBwb29sLm51bVBlbmRpbmdWYWxpZGF0aW9ucygpICtcclxuICAgICAgcG9vbC5wZW5kaW5nRGVzdHJveXMubGVuZ3RoXHJcbiAgfTtcclxufVxyXG5cclxuLyoqXHJcbiAqIExvZ3MgaW5mb3JtYXRpb24gYWJvdXQgdGhlIGN1cnJlbnQgc3RhdGUgb2YgdGhlIHBvb2wsIGluY2x1ZGluZyB0aGUgbWluaW11bVxyXG4gKiBhbmQgbWF4aW11bSB3b3JrZXJzLCBhdmFpbGFibGUgd29ya2Vycywgd29ya2VycyBpbiB1c2UsIGFuZCBwZW5kaW5nIGFjcXVpcmVcclxuICogcmVxdWVzdHMuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBfZ2V0UG9vbEluZm9cclxuICovXHJcbmZ1bmN0aW9uIF9nZXRQb29sSW5mbygpIHtcclxuICBjb25zdCB7XHJcbiAgICBtaW4sXHJcbiAgICBtYXgsXHJcbiAgICB1c2VkLFxyXG4gICAgYXZhaWxhYmxlLFxyXG4gICAgYWxsQ3JlYXRlZCxcclxuICAgIHBlbmRpbmdBY3F1aXJlcyxcclxuICAgIHBlbmRpbmdDcmVhdGVzLFxyXG4gICAgcGVuZGluZ1ZhbGlkYXRpb25zLFxyXG4gICAgcGVuZGluZ0Rlc3Ryb3lzLFxyXG4gICAgYWJzb2x1dGVBbGxcclxuICB9ID0gZ2V0UG9vbEluZm9KU09OKCk7XHJcblxyXG4gIGxvZyg1LCBgW3Bvb2xdIFRoZSBtaW5pbXVtIG51bWJlciBvZiByZXNvdXJjZXMgYWxsb3dlZCBieSBwb29sOiAke21pbn0uYCk7XHJcbiAgbG9nKDUsIGBbcG9vbF0gVGhlIG1heGltdW0gbnVtYmVyIG9mIHJlc291cmNlcyBhbGxvd2VkIGJ5IHBvb2w6ICR7bWF4fS5gKTtcclxuICBsb2coNSwgYFtwb29sXSBUaGUgbnVtYmVyIG9mIHVzZWQgcmVzb3VyY2VzOiAke3VzZWR9LmApO1xyXG4gIGxvZyg1LCBgW3Bvb2xdIFRoZSBudW1iZXIgb2YgZnJlZSByZXNvdXJjZXM6ICR7YXZhaWxhYmxlfS5gKTtcclxuICBsb2coXHJcbiAgICA1LFxyXG4gICAgYFtwb29sXSBUaGUgbnVtYmVyIG9mIGFsbCBjcmVhdGVkICh1c2VkIGFuZCBmcmVlKSByZXNvdXJjZXM6ICR7YWxsQ3JlYXRlZH0uYFxyXG4gICk7XHJcbiAgbG9nKFxyXG4gICAgNSxcclxuICAgIGBbcG9vbF0gVGhlIG51bWJlciBvZiByZXNvdXJjZXMgd2FpdGluZyB0byBiZSBhY3F1aXJlZDogJHtwZW5kaW5nQWNxdWlyZXN9LmBcclxuICApO1xyXG4gIGxvZyhcclxuICAgIDUsXHJcbiAgICBgW3Bvb2xdIFRoZSBudW1iZXIgb2YgcmVzb3VyY2VzIHdhaXRpbmcgdG8gYmUgY3JlYXRlZDogJHtwZW5kaW5nQ3JlYXRlc30uYFxyXG4gICk7XHJcbiAgbG9nKFxyXG4gICAgNSxcclxuICAgIGBbcG9vbF0gVGhlIG51bWJlciBvZiByZXNvdXJjZXMgd2FpdGluZyB0byBiZSB2YWxpZGF0ZWQ6ICR7cGVuZGluZ1ZhbGlkYXRpb25zfS5gXHJcbiAgKTtcclxuICBsb2coXHJcbiAgICA1LFxyXG4gICAgYFtwb29sXSBUaGUgbnVtYmVyIG9mIHJlc291cmNlcyB3YWl0aW5nIHRvIGJlIGRlc3Ryb3llZDogJHtwZW5kaW5nRGVzdHJveXN9LmBcclxuICApO1xyXG4gIGxvZyg1LCBgW3Bvb2xdIFRoZSBudW1iZXIgb2YgYWxsIHJlc291cmNlczogJHthYnNvbHV0ZUFsbH0uYCk7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBGYWN0b3J5IGZ1bmN0aW9uIHRoYXQgcmV0dXJucyBhbiBvYmplY3Qgd2l0aCBgY3JlYXRlYCwgYHZhbGlkYXRlYCwgYGRlc3Ryb3lgXHJcbiAqIGZ1bmN0aW9ucyBmb3IgdGhlIHBvb2wgaW5zdGFuY2UuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBfZmFjdG9yeVxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gcG9vbE9wdGlvbnMgLSBUaGUgY29uZmlndXJhdGlvbiBvYmplY3QgY29udGFpbmluZyBgcG9vbGBcclxuICogb3B0aW9ucy5cclxuICovXHJcbmZ1bmN0aW9uIF9mYWN0b3J5KHBvb2xPcHRpb25zKSB7XHJcbiAgcmV0dXJuIHtcclxuICAgIC8qKlxyXG4gICAgICogQ3JlYXRlcyBhIG5ldyB3b3JrZXIgcGFnZSBmb3IgdGhlIGV4cG9ydCBwb29sLlxyXG4gICAgICpcclxuICAgICAqIEBhc3luY1xyXG4gICAgICogQGZ1bmN0aW9uIGNyZWF0ZVxyXG4gICAgICpcclxuICAgICAqIEByZXR1cm5zIHtQcm9taXNlPE9iamVjdD59IEEgUHJvbWlzZSB0aGF0IHJlc29sdmVzIHRvIGFuIG9iamVjdFxyXG4gICAgICogY29udGFpbmluZyB0aGUgd29ya2VyIElELCBhIHJlZmVyZW5jZSB0byB0aGUgYnJvd3NlciBwYWdlLCBhbmQgaW5pdGlhbFxyXG4gICAgICogd29yayBjb3VudC5cclxuICAgICAqXHJcbiAgICAgKiBAdGhyb3dzIHtFeHBvcnRFcnJvcn0gVGhyb3dzIGFuIGBFeHBvcnRFcnJvcmAgaWYgdGhlcmUgaXMgYW4gZXJyb3IgZHVyaW5nXHJcbiAgICAgKiB0aGUgY3JlYXRpb24gb2YgdGhlIG5ldyBwYWdlLlxyXG4gICAgICovXHJcbiAgICBjcmVhdGU6IGFzeW5jICgpID0+IHtcclxuICAgICAgLy8gSW5pdCB0aGUgcmVzb3VyY2Ugd2l0aCB1bmlxdWUgaWQgYW5kIHdvcmsgY291bnRcclxuICAgICAgY29uc3QgcG9vbFJlc291cmNlID0ge1xyXG4gICAgICAgIGlkOiB1dWlkKCksXHJcbiAgICAgICAgLy8gVHJ5IHRvIGRpc3RyaWJ1dGUgdGhlIGluaXRpYWwgd29yayBjb3VudFxyXG4gICAgICAgIHdvcmtDb3VudDogTWF0aC5yb3VuZChNYXRoLnJhbmRvbSgpICogKHBvb2xPcHRpb25zLndvcmtMaW1pdCAvIDIpKVxyXG4gICAgICB9O1xyXG5cclxuICAgICAgdHJ5IHtcclxuICAgICAgICAvLyBTdGFydCBtZWFzdXJpbmcgYSBwYWdlIGNyZWF0aW9uIHRpbWVcclxuICAgICAgICBjb25zdCBzdGFydERhdGUgPSBnZXROZXdEYXRlVGltZSgpO1xyXG5cclxuICAgICAgICAvLyBDcmVhdGUgYSBuZXcgcGFnZVxyXG4gICAgICAgIGF3YWl0IG5ld1BhZ2UocG9vbFJlc291cmNlKTtcclxuXHJcbiAgICAgICAgLy8gTWVhc3VyZSB0aGUgdGltZSBvZiBmdWxsIGNyZWF0aW9uIGFuZCBjb25maWd1cmF0aW9uIG9mIGEgcGFnZVxyXG4gICAgICAgIGxvZyhcclxuICAgICAgICAgIDMsXHJcbiAgICAgICAgICBgW3Bvb2xdIFBvb2wgcmVzb3VyY2UgWyR7cG9vbFJlc291cmNlLmlkfV0gLSBTdWNjZXNzZnVsbHkgY3JlYXRlZCBhIHdvcmtlciwgdG9vayAke1xyXG4gICAgICAgICAgICBnZXROZXdEYXRlVGltZSgpIC0gc3RhcnREYXRlXHJcbiAgICAgICAgICB9bXMuYFxyXG4gICAgICAgICk7XHJcblxyXG4gICAgICAgIC8vIFJldHVybiByZWFkeSBwb29sIHJlc291cmNlXHJcbiAgICAgICAgcmV0dXJuIHBvb2xSZXNvdXJjZTtcclxuICAgICAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICAgICBsb2coXHJcbiAgICAgICAgICAzLFxyXG4gICAgICAgICAgYFtwb29sXSBQb29sIHJlc291cmNlIFske3Bvb2xSZXNvdXJjZS5pZH1dIC0gRXJyb3IgZW5jb3VudGVyZWQgd2hlbiBjcmVhdGluZyBhIG5ldyBwYWdlLmBcclxuICAgICAgICApO1xyXG4gICAgICAgIHRocm93IGVycm9yO1xyXG4gICAgICB9XHJcbiAgICB9LFxyXG5cclxuICAgIC8qKlxyXG4gICAgICogVmFsaWRhdGVzIGEgd29ya2VyIHBhZ2UgaW4gdGhlIGV4cG9ydCBwb29sLCBjaGVja2luZyBpZiBpdCBoYXMgZXhjZWVkZWRcclxuICAgICAqIHRoZSB3b3JrIGxpbWl0LlxyXG4gICAgICpcclxuICAgICAqIEBhc3luY1xyXG4gICAgICogQGZ1bmN0aW9uIHZhbGlkYXRlXHJcbiAgICAgKlxyXG4gICAgICogQHBhcmFtIHtPYmplY3R9IHBvb2xSZXNvdXJjZSAtIFRoZSBoYW5kbGUgdG8gdGhlIHdvcmtlciwgY29udGFpbmluZ1xyXG4gICAgICogdGhlIHdvcmtlcidzIElELCBhIHJlZmVyZW5jZSB0byB0aGUgYnJvd3NlciBwYWdlLCBhbmQgd29yayBjb3VudC5cclxuICAgICAqXHJcbiAgICAgKiBAcmV0dXJucyB7UHJvbWlzZTxib29sZWFuPn0gQSBQcm9taXNlIHRoYXQgcmVzb2x2ZXMgdG8gdHJ1ZSBpZiB0aGUgd29ya2VyXHJcbiAgICAgKiBpcyB2YWxpZCBhbmQgd2l0aGluIHRoZSB3b3JrIGxpbWl0OyBvdGhlcndpc2UsIHRvIGZhbHNlLlxyXG4gICAgICovXHJcbiAgICB2YWxpZGF0ZTogYXN5bmMgKHBvb2xSZXNvdXJjZSkgPT4ge1xyXG4gICAgICAvLyBOT1RFOlxyXG4gICAgICAvLyBJbiBjZXJ0YWluIGNhc2VzIGFjcXVpcmluZyB0aHJvd3MgYSBgVGFyZ2V0Q2xvc2VFcnJvcmAsIHdoaWNoIG1heVxyXG4gICAgICAvLyBiZSBjYXVzZWQgYnkgdHdvIHRoaW5nczpcclxuICAgICAgLy8gLSBUaGUgcGFnZSBpcyBjbG9zZWQgYW5kIGF0dGVtcHRlZCB0byBiZSByZXVzZWQuXHJcbiAgICAgIC8vIC0gTG9zdCBjb250YWN0IHdpdGggdGhlIGJyb3dzZXIuXHJcbiAgICAgIC8vXHJcbiAgICAgIC8vIFdoYXQgd2UncmUgc2VlaW5nIGluIGxvZ3MgaXMgdGhhdCBzdWNjZXNzaXZlIGV4cG9ydHMgdHlwaWNhbGx5XHJcbiAgICAgIC8vIHN1Y2NlZWRzLCBhbmQgdGhlIHNlcnZlciByZWNvdmVycywgaW5kaWNhdGluZyB0aGF0IGl0J3MgbGlrZWx5XHJcbiAgICAgIC8vIHRoZSBmaXJzdCBjYXNlLiBUaGlzIGlzIGFuIGF0dGVtcHQgYXQgYWxsaWV2YXRpbmcgdGhlIGlzc3VlIGJ5XHJcbiAgICAgIC8vIHNpbXBseSBub3QgdmFsaWRhdGluZyB0aGUgd29ya2VyIGlmIHRoZSBwYWdlIGlzIG51bGwgb3IgY2xvc2VkLlxyXG4gICAgICAvL1xyXG4gICAgICAvLyBUaGUgYWN0dWFsIHJlc3VsdCBmcm9tIHdoZW4gdGhpcyBoYXBwZW5lZCwgd2FzIHRoYXQgYSB3b3JrZXIgd291bGRcclxuICAgICAgLy8gYmUgY29tcGxldGVseSBsb2NrZWQsIHN0b3BwaW5nIGl0IGZyb20gYmVpbmcgYWNxdWlyZWQgdW50aWxcclxuICAgICAgLy8gaXRzIHdvcmsgY291bnQgcmVhY2hlZCB0aGUgbGltaXQuXHJcblxyXG4gICAgICAvLyBDaGVjayBpZiB0aGUgYHBhZ2VgIGlzIHZhbGlkXHJcbiAgICAgIGlmICghcG9vbFJlc291cmNlLnBhZ2UpIHtcclxuICAgICAgICBsb2coXHJcbiAgICAgICAgICAzLFxyXG4gICAgICAgICAgYFtwb29sXSBQb29sIHJlc291cmNlIFske3Bvb2xSZXNvdXJjZS5pZH1dIC0gVmFsaWRhdGlvbiBmYWlsZWQgKG5vIHZhbGlkIHBhZ2UgaXMgZm91bmQpLmBcclxuICAgICAgICApO1xyXG4gICAgICAgIHJldHVybiBmYWxzZTtcclxuICAgICAgfVxyXG5cclxuICAgICAgLy8gQ2hlY2sgaWYgdGhlIGBwYWdlYCBpcyBjbG9zZWRcclxuICAgICAgaWYgKHBvb2xSZXNvdXJjZS5wYWdlLmlzQ2xvc2VkKCkpIHtcclxuICAgICAgICBsb2coXHJcbiAgICAgICAgICAzLFxyXG4gICAgICAgICAgYFtwb29sXSBQb29sIHJlc291cmNlIFske3Bvb2xSZXNvdXJjZS5pZH1dIC0gVmFsaWRhdGlvbiBmYWlsZWQgKHBhZ2UgaXMgY2xvc2VkIG9yIGludmFsaWQpLmBcclxuICAgICAgICApO1xyXG4gICAgICAgIHJldHVybiBmYWxzZTtcclxuICAgICAgfVxyXG5cclxuICAgICAgLy8gQ2hlY2sgaWYgdGhlIGBtYWluRnJhbWVgIGlzIGRldGFjaGVkXHJcbiAgICAgIGlmIChwb29sUmVzb3VyY2UucGFnZS5tYWluRnJhbWUoKS5kZXRhY2hlZCkge1xyXG4gICAgICAgIGxvZyhcclxuICAgICAgICAgIDMsXHJcbiAgICAgICAgICBgW3Bvb2xdIFBvb2wgcmVzb3VyY2UgWyR7cG9vbFJlc291cmNlLmlkfV0gLSBWYWxpZGF0aW9uIGZhaWxlZCAocGFnZSdzIGZyYW1lIGlzIGRldGFjaGVkKS5gXHJcbiAgICAgICAgKTtcclxuICAgICAgICByZXR1cm4gZmFsc2U7XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIC8vIENoZWNrIGlmIHRoZSBgd29ya0xpbWl0YCBpcyBleGNlZWRlZFxyXG4gICAgICBpZiAoXHJcbiAgICAgICAgcG9vbE9wdGlvbnMud29ya0xpbWl0ICYmXHJcbiAgICAgICAgKytwb29sUmVzb3VyY2Uud29ya0NvdW50ID4gcG9vbE9wdGlvbnMud29ya0xpbWl0XHJcbiAgICAgICkge1xyXG4gICAgICAgIGxvZyhcclxuICAgICAgICAgIDMsXHJcbiAgICAgICAgICBgW3Bvb2xdIFBvb2wgcmVzb3VyY2UgWyR7cG9vbFJlc291cmNlLmlkfV0gLSBWYWxpZGF0aW9uIGZhaWxlZCAoZXhjZWVkZWQgdGhlICR7cG9vbE9wdGlvbnMud29ya0xpbWl0fSB3b3JrcyBwZXIgcmVzb3VyY2UgbGltaXQpLmBcclxuICAgICAgICApO1xyXG4gICAgICAgIHJldHVybiBmYWxzZTtcclxuICAgICAgfVxyXG5cclxuICAgICAgLy8gVGhlIGBwb29sUmVzb3VyY2VgIGlzIHZhbGlkYXRlZFxyXG4gICAgICByZXR1cm4gdHJ1ZTtcclxuICAgIH0sXHJcblxyXG4gICAgLyoqXHJcbiAgICAgKiBEZXN0cm95cyBhIHdvcmtlciBlbnRyeSBpbiB0aGUgZXhwb3J0IHBvb2wsIGNsb3NpbmcgaXRzIGFzc29jaWF0ZWQgcGFnZS5cclxuICAgICAqXHJcbiAgICAgKiBAYXN5bmNcclxuICAgICAqIEBmdW5jdGlvbiBkZXN0cm95XHJcbiAgICAgKlxyXG4gICAgICogQHBhcmFtIHtPYmplY3R9IHBvb2xSZXNvdXJjZSAtIFRoZSBoYW5kbGUgdG8gdGhlIHdvcmtlciwgY29udGFpbmluZ1xyXG4gICAgICogdGhlIHdvcmtlcidzIElELCBhIHJlZmVyZW5jZSB0byB0aGUgYnJvd3NlciBwYWdlLCBhbmQgd29yayBjb3VudC5cclxuICAgICAqL1xyXG4gICAgZGVzdHJveTogYXN5bmMgKHBvb2xSZXNvdXJjZSkgPT4ge1xyXG4gICAgICBsb2coXHJcbiAgICAgICAgMyxcclxuICAgICAgICBgW3Bvb2xdIFBvb2wgcmVzb3VyY2UgWyR7cG9vbFJlc291cmNlLmlkfV0gLSBEZXN0cm95aW5nIGEgd29ya2VyLmBcclxuICAgICAgKTtcclxuXHJcbiAgICAgIGlmIChwb29sUmVzb3VyY2UucGFnZSAmJiAhcG9vbFJlc291cmNlLnBhZ2UuaXNDbG9zZWQoKSkge1xyXG4gICAgICAgIHRyeSB7XHJcbiAgICAgICAgICAvLyBSZW1vdmUgYWxsIGF0dGFjaGVkIGV2ZW50IGxpc3RlbmVycyBmcm9tIHRoZSByZXNvdXJjZVxyXG4gICAgICAgICAgcG9vbFJlc291cmNlLnBhZ2UucmVtb3ZlQWxsTGlzdGVuZXJzKCdwYWdlZXJyb3InKTtcclxuICAgICAgICAgIHBvb2xSZXNvdXJjZS5wYWdlLnJlbW92ZUFsbExpc3RlbmVycygnY29uc29sZScpO1xyXG4gICAgICAgICAgcG9vbFJlc291cmNlLnBhZ2UucmVtb3ZlQWxsTGlzdGVuZXJzKCdmcmFtZWRldGFjaGVkJyk7XHJcblxyXG4gICAgICAgICAgLy8gV2UgbmVlZCB0byB3YWl0IGFyb3VuZCBmb3IgdGhpc1xyXG4gICAgICAgICAgYXdhaXQgcG9vbFJlc291cmNlLnBhZ2UuY2xvc2UoKTtcclxuICAgICAgICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgICAgICAgbG9nKFxyXG4gICAgICAgICAgICAzLFxyXG4gICAgICAgICAgICBgW3Bvb2xdIFBvb2wgcmVzb3VyY2UgWyR7cG9vbFJlc291cmNlLmlkfV0gLSBQYWdlIGNvdWxkIG5vdCBiZSBjbG9zZWQgdXBvbiBkZXN0cm95aW5nLmBcclxuICAgICAgICAgICk7XHJcbiAgICAgICAgICB0aHJvdyBlcnJvcjtcclxuICAgICAgICB9XHJcbiAgICAgIH1cclxuICAgIH1cclxuICB9O1xyXG59XHJcblxyXG5leHBvcnQgZGVmYXVsdCB7XHJcbiAgaW5pdFBvb2wsXHJcbiAga2lsbFBvb2wsXHJcbiAgcG9zdFdvcmssXHJcbiAgZ2V0UG9vbCxcclxuICBnZXRQb29sU3RhdHMsXHJcbiAgZ2V0UG9vbEluZm9KU09OXHJcbn07XHJcbiIsIi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXHJcblxyXG5IaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXJcclxuXHJcbkNvcHlyaWdodCAoYykgMjAxNi0yMDI1LCBIaWdoc29mdFxyXG5cclxuTGljZW5jZWQgdW5kZXIgdGhlIE1JVCBsaWNlbmNlLlxyXG5cclxuQWRkaXRpb25hbGx5IGEgdmFsaWQgSGlnaGNoYXJ0cyBsaWNlbnNlIGlzIHJlcXVpcmVkIGZvciB1c2UuXHJcblxyXG5TZWUgTElDRU5TRSBmaWxlIGluIHJvb3QgZm9yIGRldGFpbHMuXHJcblxyXG4qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xyXG5cclxuLyoqXHJcbiAqIEBvdmVydmlldyBVc2VkIHRvIHNhbml0aXplIHRoZSBzdHJpbmdzIGNvbWluZyBmcm9tIHRoZSBleHBvcnRpbmcgbW9kdWxlXHJcbiAqIHRvIHByZXZlbnQgWFNTIGF0dGFja3MgKHdpdGggdGhlIERPTVB1cmlmeSBsaWJyYXJ5KS5cclxuICovXHJcblxyXG5pbXBvcnQgRE9NUHVyaWZ5IGZyb20gJ2RvbXB1cmlmeSc7XHJcbmltcG9ydCB7IEpTRE9NIH0gZnJvbSAnanNkb20nO1xyXG5cclxuLyoqXHJcbiAqIFNhbml0aXplcyBhIGdpdmVuIEhUTUwgc3RyaW5nIGJ5IHJlbW92aW5nIDxzY3JpcHQ+IHRhZ3MuIFRoaXMgZnVuY3Rpb24gdXNlc1xyXG4gKiBhIHJlZ3VsYXIgZXhwcmVzc2lvbiB0byBmaW5kIGFuZCByZW1vdmUgYWxsIG9jY3VycmVuY2VzIG9mIDxzY3JpcHQ+PC9zY3JpcHQ+XHJcbiAqIHRhZ3MgYW5kIGFueSBjb250ZW50IHdpdGhpbiB0aGVtLlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gc2FuaXRpemVcclxuICpcclxuICogQHBhcmFtIHtzdHJpbmd9IGlucHV0IC0gVGhlIEhUTUwgc3RyaW5nIHRvIGJlIHNhbml0aXplZC5cclxuICpcclxuICogQHJldHVybnMge3N0cmluZ30gVGhlIHNhbml0aXplZCBIVE1MIHN0cmluZy5cclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiBzYW5pdGl6ZShpbnB1dCkge1xyXG4gIC8vIEdldCB0aGUgdmlydHVhbCBET01cclxuICBjb25zdCB3aW5kb3cgPSBuZXcgSlNET00oJycpLndpbmRvdztcclxuXHJcbiAgLy8gQ3JlYXRlIGEgcHVyaWZ5aW5nIGluc3RhbmNlXHJcbiAgY29uc3QgcHVyaWZ5ID0gRE9NUHVyaWZ5KHdpbmRvdyk7XHJcblxyXG4gIC8vIFJldHVybiBzYW5pdGl6ZWQgaW5wdXQsIGFsbG93aW5nIGZvciB0aGUgYGZvcmVpZ25PYmplY3RgIGVsZW1lbnRzXHJcbiAgcmV0dXJuIHB1cmlmeS5zYW5pdGl6ZShpbnB1dCwgeyBBRERfVEFHUzogWydmb3JlaWduT2JqZWN0J10gfSk7XHJcbn1cclxuXHJcbmV4cG9ydCBkZWZhdWx0IHtcclxuICBzYW5pdGl6ZVxyXG59O1xyXG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxyXG5cclxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXHJcblxyXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNSwgSGlnaHNvZnRcclxuXHJcbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cclxuXHJcbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxyXG5cclxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxyXG5cclxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cclxuXHJcbi8qKlxyXG4gKiBAb3ZlcnZpZXcgVGhpcyBtb2R1bGUgcHJvdmlkZXMgZnVuY3Rpb25zIHRoYXQgcHJlcGFyZSBmb3IgdGhlIGV4cG9ydGluZ1xyXG4gKiBjaGFydHMgaW50byB2YXJpb3VzIGltYWdlIG91dHB1dCBmb3JtYXRzIHN1Y2ggYXMgSlBFRywgUE5HLCBQREYsIGFuZCBTVkdzLlxyXG4gKiBJdCBzdXBwb3J0cyBzaW5nbGUgYW5kIGJhdGNoIGV4cG9ydCBvcGVyYXRpb25zIGFuZCBhbGxvd3MgY3VzdG9taXphdGlvblxyXG4gKiB0aHJvdWdoIG9wdGlvbnMgcGFzc2VkIGZyb20gY29uZmlndXJhdGlvbnMgb3IgQVBJcy5cclxuICovXHJcblxyXG5pbXBvcnQgeyByZWFkRmlsZVN5bmMsIHdyaXRlRmlsZVN5bmMgfSBmcm9tICdmcyc7XHJcblxyXG5pbXBvcnQgeyBpc0FsbG93ZWRDb25maWcsIHVwZGF0ZU9wdGlvbnMsIHZhbGlkYXRlT3B0aW9uIH0gZnJvbSAnLi9jb25maWcuanMnO1xyXG5pbXBvcnQgeyBsb2csIGxvZ1dpdGhTdGFjayB9IGZyb20gJy4vbG9nZ2VyLmpzJztcclxuaW1wb3J0IHsgZ2V0UG9vbFN0YXRzLCBraWxsUG9vbCwgcG9zdFdvcmsgfSBmcm9tICcuL3Bvb2wuanMnO1xyXG5pbXBvcnQgeyBzYW5pdGl6ZSB9IGZyb20gJy4vc2FuaXRpemUuanMnO1xyXG5pbXBvcnQgeyBnZXRBYnNvbHV0ZVBhdGgsIGdldEJhc2U2NCwgaXNPYmplY3QsIHJvdW5kTnVtYmVyIH0gZnJvbSAnLi91dGlscy5qcyc7XHJcblxyXG5pbXBvcnQgRXhwb3J0RXJyb3IgZnJvbSAnLi9lcnJvcnMvRXhwb3J0RXJyb3IuanMnO1xyXG5cclxuLy8gVGhlIGdsb2JhbCBmbGFnIGZvciB0aGUgY29kZSBleGVjdXRpb24gcGVybWlzc2lvblxyXG5sZXQgYWxsb3dDb2RlRXhlY3V0aW9uID0gZmFsc2U7XHJcblxyXG4vKipcclxuICogU3RhcnRzIGEgc2luZ2xlIGV4cG9ydCBwcm9jZXNzIGJhc2VkIG9uIHRoZSBzcGVjaWZpZWQgb3B0aW9ucyBhbmQgc2F2ZXNcclxuICogdGhlIHJlc3VsdGluZyBpbWFnZSB0byB0aGUgcHJvdmlkZWQgb3V0cHV0IGZpbGUuXHJcbiAqXHJcbiAqIEBhc3luY1xyXG4gKiBAZnVuY3Rpb24gc2luZ2xlRXhwb3J0XHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBvcHRpb25zIC0gVGhlIGBvcHRpb25zYCBvYmplY3QsIHdoaWNoIHNob3VsZCBpbmNsdWRlIHNldHRpbmdzXHJcbiAqIGZyb20gdGhlIGBleHBvcnRgIGFuZCBgY3VzdG9tTG9naWNgIHNlY3Rpb25zLiBJdCBjYW4gYmUgYSBwYXJ0aWFsIG9yIGNvbXBsZXRlXHJcbiAqIHNldCBvZiBvcHRpb25zIGZyb20gdGhlc2Ugc2VjdGlvbnMuIFRoZSBvYmplY3QgbXVzdCBjb250YWluIGF0IGxlYXN0IG9uZVxyXG4gKiBvZiB0aGUgZm9sbG93aW5nIGBleHBvcnRgIHByb3BlcnRpZXM6IGBpbmZpbGVgLCBgaW5zdHJgLCBgb3B0aW9uc2AsIG9yIGBzdmdgXHJcbiAqIHRvIGdlbmVyYXRlIGEgdmFsaWQgaW1hZ2UuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtQcm9taXNlPHZvaWQ+fSBBIFByb21pc2UgdGhhdCByZXNvbHZlcyBvbmNlIHRoZSBzaW5nbGUgZXhwb3J0XHJcbiAqIHByb2Nlc3MgaXMgY29tcGxldGVkLlxyXG4gKlxyXG4gKiBAdGhyb3dzIHtFeHBvcnRFcnJvcn0gVGhyb3dzIGFuIGBFeHBvcnRFcnJvcmAgaWYgYW4gZXJyb3Igb2NjdXJzIGR1cmluZ1xyXG4gKiB0aGUgc2luZ2xlIGV4cG9ydCBwcm9jZXNzLlxyXG4gKi9cclxuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIHNpbmdsZUV4cG9ydChvcHRpb25zKSB7XHJcbiAgLy8gQ2hlY2sgaWYgdGhlIGV4cG9ydCBtYWtlcyBzZW5zZVxyXG4gIGlmIChvcHRpb25zICYmIG9wdGlvbnMuZXhwb3J0KSB7XHJcbiAgICAvLyBQZXJmb3JtIGFuIGV4cG9ydFxyXG4gICAgYXdhaXQgc3RhcnRFeHBvcnQoXHJcbiAgICAgIHsgZXhwb3J0OiBvcHRpb25zLmV4cG9ydCwgY3VzdG9tTG9naWM6IG9wdGlvbnMuY3VzdG9tTG9naWMgfSxcclxuICAgICAgYXN5bmMgKGVycm9yLCBkYXRhKSA9PiB7XHJcbiAgICAgICAgLy8gRXhpdCBwcm9jZXNzIHdoZW4gZXJyb3IgZXhpc3RzXHJcbiAgICAgICAgaWYgKGVycm9yKSB7XHJcbiAgICAgICAgICB0aHJvdyBlcnJvcjtcclxuICAgICAgICB9XHJcblxyXG4gICAgICAgIC8vIEdldCB0aGUgYGI2NGAsIGBvdXRmaWxlYCwgYW5kIGB0eXBlYCBmb3IgYSBjaGFydFxyXG4gICAgICAgIGNvbnN0IHsgYjY0LCBvdXRmaWxlLCB0eXBlIH0gPSBkYXRhLm9wdGlvbnMuZXhwb3J0O1xyXG5cclxuICAgICAgICAvLyBTYXZlIHRoZSByZXN1bHRcclxuICAgICAgICB0cnkge1xyXG4gICAgICAgICAgaWYgKGI2NCkge1xyXG4gICAgICAgICAgICAvLyBBcyBhIEJhc2U2NCBzdHJpbmcgdG8gYSB0eHQgZmlsZVxyXG4gICAgICAgICAgICB3cml0ZUZpbGVTeW5jKFxyXG4gICAgICAgICAgICAgIGAke291dGZpbGUuc3BsaXQoJy4nKS5zaGlmdCgpIHx8ICdjaGFydCd9LnR4dGAsXHJcbiAgICAgICAgICAgICAgZ2V0QmFzZTY0KGRhdGEucmVzdWx0LCB0eXBlKVxyXG4gICAgICAgICAgICApO1xyXG4gICAgICAgICAgfSBlbHNlIHtcclxuICAgICAgICAgICAgLy8gQXMgYSBjb3JyZWN0IGltYWdlIGZvcm1hdFxyXG4gICAgICAgICAgICB3cml0ZUZpbGVTeW5jKFxyXG4gICAgICAgICAgICAgIG91dGZpbGUgfHwgYGNoYXJ0LiR7dHlwZX1gLFxyXG4gICAgICAgICAgICAgIHR5cGUgIT09ICdzdmcnID8gQnVmZmVyLmZyb20oZGF0YS5yZXN1bHQsICdiYXNlNjQnKSA6IGRhdGEucmVzdWx0XHJcbiAgICAgICAgICAgICk7XHJcbiAgICAgICAgICB9XHJcbiAgICAgICAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICAgICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcihcclxuICAgICAgICAgICAgJ1tjaGFydF0gRXJyb3Igd2hpbGUgc2F2aW5nIGEgY2hhcnQuJyxcclxuICAgICAgICAgICAgNTAwXHJcbiAgICAgICAgICApLnNldEVycm9yKGVycm9yKTtcclxuICAgICAgICB9XHJcblxyXG4gICAgICAgIC8vIEtpbGwgcG9vbCBhbmQgY2xvc2UgYnJvd3NlciBhZnRlciBmaW5pc2hpbmcgc2luZ2xlIGV4cG9ydFxyXG4gICAgICAgIGF3YWl0IGtpbGxQb29sKCk7XHJcbiAgICAgIH1cclxuICAgICk7XHJcbiAgfSBlbHNlIHtcclxuICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcihcclxuICAgICAgJ1tjaGFydF0gTm8gZXhwZWN0ZWQgYGV4cG9ydGAgb3B0aW9ucyB3ZXJlIGZvdW5kLiBQbGVhc2UgcHJvdmlkZSBvbmUgb2YgdGhlIGZvbGxvd2luZyBvcHRpb25zOiBgaW5maWxlYCwgYGluc3RyYCwgYG9wdGlvbnNgLCBvciBgc3ZnYCB0byBnZW5lcmF0ZSBhIHZhbGlkIGltYWdlLicsXHJcbiAgICAgIDQwMFxyXG4gICAgKTtcclxuICB9XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBTdGFydHMgYSBiYXRjaCBleHBvcnQgcHJvY2VzcyBmb3IgbXVsdGlwbGUgY2hhcnRzIGJhc2VkIG9uIGluZm9ybWF0aW9uXHJcbiAqIHByb3ZpZGVkIGluIHRoZSBgYmF0Y2hgIG9wdGlvbi4gVGhlIGBiYXRjaGAgaXMgYSBzdHJpbmcgaW4gdGhlIGZvbGxvd2luZ1xyXG4gKiBmb3JtYXQ6IFwiaW5maWxlMS5qc29uPW91dGZpbGUxLnBuZztpbmZpbGUyLmpzb249b3V0ZmlsZTIucG5nOy4uLlwiLiBSZXN1bHRzXHJcbiAqIGFyZSBzYXZlZCB0byB0aGUgc3BlY2lmaWVkIG91dHB1dCBmaWxlcy5cclxuICpcclxuICogQGFzeW5jXHJcbiAqIEBmdW5jdGlvbiBiYXRjaEV4cG9ydFxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gb3B0aW9ucyAtIFRoZSBgb3B0aW9uc2Agb2JqZWN0LCB3aGljaCBzaG91bGQgaW5jbHVkZSBzZXR0aW5nc1xyXG4gKiBmcm9tIHRoZSBgZXhwb3J0YCBhbmQgYGN1c3RvbUxvZ2ljYCBzZWN0aW9ucy4gSXQgY2FuIGJlIGEgcGFydGlhbCBvciBjb21wbGV0ZVxyXG4gKiBzZXQgb2Ygb3B0aW9ucyBmcm9tIHRoZXNlIHNlY3Rpb25zLiBJdCBtdXN0IGNvbnRhaW4gdGhlIGBiYXRjaGAgb3B0aW9uIGZyb21cclxuICogdGhlIGBleHBvcnRgIHNlY3Rpb24gdG8gZ2VuZXJhdGUgdmFsaWQgaW1hZ2VzLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7UHJvbWlzZTx2b2lkPn0gQSBQcm9taXNlIHRoYXQgcmVzb2x2ZXMgb25jZSB0aGUgYmF0Y2ggZXhwb3J0XHJcbiAqIHByb2Nlc3NlcyBhcmUgY29tcGxldGVkLlxyXG4gKlxyXG4gKiBAdGhyb3dzIHtFeHBvcnRFcnJvcn0gVGhyb3dzIGFuIGBFeHBvcnRFcnJvcmAgaWYgYW4gZXJyb3Igb2NjdXJzIGR1cmluZ1xyXG4gKiBhbnkgb2YgdGhlIGJhdGNoIGV4cG9ydCBwcm9jZXNzLlxyXG4gKi9cclxuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIGJhdGNoRXhwb3J0KG9wdGlvbnMpIHtcclxuICAvLyBDaGVjayBpZiB0aGUgZXhwb3J0IG1ha2VzIHNlbnNlXHJcbiAgaWYgKG9wdGlvbnMgJiYgb3B0aW9ucy5leHBvcnQgJiYgb3B0aW9ucy5leHBvcnQuYmF0Y2gpIHtcclxuICAgIC8vIEFuIGFycmF5IGZvciBjb2xsZWN0aW5nIGJhdGNoIGV4cG9ydHNcclxuICAgIGNvbnN0IGJhdGNoRnVuY3Rpb25zID0gW107XHJcblxyXG4gICAgLy8gU3BsaXQgYW5kIHBhaXIgdGhlIGBiYXRjaGAgYXJndW1lbnRzXHJcbiAgICBmb3IgKGxldCBwYWlyIG9mIG9wdGlvbnMuZXhwb3J0LmJhdGNoLnNwbGl0KCc7JykgfHwgW10pIHtcclxuICAgICAgcGFpciA9IHBhaXIuc3BsaXQoJz0nKTtcclxuICAgICAgaWYgKHBhaXIubGVuZ3RoID09PSAyKSB7XHJcbiAgICAgICAgYmF0Y2hGdW5jdGlvbnMucHVzaChcclxuICAgICAgICAgIHN0YXJ0RXhwb3J0KFxyXG4gICAgICAgICAgICB7XHJcbiAgICAgICAgICAgICAgZXhwb3J0OiB7XHJcbiAgICAgICAgICAgICAgICAuLi5vcHRpb25zLmV4cG9ydCxcclxuICAgICAgICAgICAgICAgIGluZmlsZTogcGFpclswXSxcclxuICAgICAgICAgICAgICAgIG91dGZpbGU6IHBhaXJbMV1cclxuICAgICAgICAgICAgICB9LFxyXG4gICAgICAgICAgICAgIGN1c3RvbUxvZ2ljOiBvcHRpb25zLmN1c3RvbUxvZ2ljXHJcbiAgICAgICAgICAgIH0sXHJcbiAgICAgICAgICAgIChlcnJvciwgZGF0YSkgPT4ge1xyXG4gICAgICAgICAgICAgIC8vIEV4aXQgcHJvY2VzcyB3aGVuIGVycm9yIGV4aXN0c1xyXG4gICAgICAgICAgICAgIGlmIChlcnJvcikge1xyXG4gICAgICAgICAgICAgICAgdGhyb3cgZXJyb3I7XHJcbiAgICAgICAgICAgICAgfVxyXG5cclxuICAgICAgICAgICAgICAvLyBHZXQgdGhlIGBiNjRgLCBgb3V0ZmlsZWAsIGFuZCBgdHlwZWAgZm9yIGEgY2hhcnRcclxuICAgICAgICAgICAgICBjb25zdCB7IGI2NCwgb3V0ZmlsZSwgdHlwZSB9ID0gZGF0YS5vcHRpb25zLmV4cG9ydDtcclxuXHJcbiAgICAgICAgICAgICAgLy8gU2F2ZSB0aGUgcmVzdWx0XHJcbiAgICAgICAgICAgICAgdHJ5IHtcclxuICAgICAgICAgICAgICAgIGlmIChiNjQpIHtcclxuICAgICAgICAgICAgICAgICAgLy8gQXMgYSBCYXNlNjQgc3RyaW5nIHRvIGEgdHh0IGZpbGVcclxuICAgICAgICAgICAgICAgICAgd3JpdGVGaWxlU3luYyhcclxuICAgICAgICAgICAgICAgICAgICBgJHtvdXRmaWxlLnNwbGl0KCcuJykuc2hpZnQoKSB8fCAnY2hhcnQnfS50eHRgLFxyXG4gICAgICAgICAgICAgICAgICAgIGdldEJhc2U2NChkYXRhLnJlc3VsdCwgdHlwZSlcclxuICAgICAgICAgICAgICAgICAgKTtcclxuICAgICAgICAgICAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgICAgICAgICAgIC8vIEFzIGEgY29ycmVjdCBpbWFnZSBmb3JtYXRcclxuICAgICAgICAgICAgICAgICAgd3JpdGVGaWxlU3luYyhcclxuICAgICAgICAgICAgICAgICAgICBvdXRmaWxlLFxyXG4gICAgICAgICAgICAgICAgICAgIHR5cGUgIT09ICdzdmcnXHJcbiAgICAgICAgICAgICAgICAgICAgICA/IEJ1ZmZlci5mcm9tKGRhdGEucmVzdWx0LCAnYmFzZTY0JylcclxuICAgICAgICAgICAgICAgICAgICAgIDogZGF0YS5yZXN1bHRcclxuICAgICAgICAgICAgICAgICAgKTtcclxuICAgICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgICAgICAgICAgICAgdGhyb3cgbmV3IEV4cG9ydEVycm9yKFxyXG4gICAgICAgICAgICAgICAgICAnW2NoYXJ0XSBFcnJvciB3aGlsZSBzYXZpbmcgYSBjaGFydC4nLFxyXG4gICAgICAgICAgICAgICAgICA1MDBcclxuICAgICAgICAgICAgICAgICkuc2V0RXJyb3IoZXJyb3IpO1xyXG4gICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgfVxyXG4gICAgICAgICAgKVxyXG4gICAgICAgICk7XHJcbiAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgbG9nKDIsICdbY2hhcnRdIE5vIGNvcnJlY3QgcGFpciBmb3VuZCBmb3IgdGhlIGJhdGNoIGV4cG9ydC4nKTtcclxuICAgICAgfVxyXG4gICAgfVxyXG5cclxuICAgIC8vIEF3YWl0IGFsbCBleHBvcnRzIGFyZSBkb25lXHJcbiAgICBjb25zdCBiYXRjaFJlc3VsdHMgPSBhd2FpdCBQcm9taXNlLmFsbFNldHRsZWQoYmF0Y2hGdW5jdGlvbnMpO1xyXG5cclxuICAgIC8vIEtpbGwgcG9vbCBhbmQgY2xvc2UgYnJvd3NlciBhZnRlciBmaW5pc2hpbmcgYmF0Y2ggZXhwb3J0XHJcbiAgICBhd2FpdCBraWxsUG9vbCgpO1xyXG5cclxuICAgIC8vIExvZyBlcnJvcnMgaWYgZm91bmRcclxuICAgIGJhdGNoUmVzdWx0cy5mb3JFYWNoKChyZXN1bHQsIGluZGV4KSA9PiB7XHJcbiAgICAgIC8vIExvZyB0aGUgZXJyb3Igd2l0aCBzdGFjayBhYm91dCB0aGUgc3BlY2lmaWMgYmF0Y2ggZXhwb3J0XHJcbiAgICAgIGlmIChyZXN1bHQucmVhc29uKSB7XHJcbiAgICAgICAgbG9nV2l0aFN0YWNrKFxyXG4gICAgICAgICAgMSxcclxuICAgICAgICAgIHJlc3VsdC5yZWFzb24sXHJcbiAgICAgICAgICBgW2NoYXJ0XSBCYXRjaCBleHBvcnQgbnVtYmVyICR7aW5kZXggKyAxfSBjb3VsZCBub3QgYmUgY29ycmVjdGx5IGNvbXBsZXRlZC5gXHJcbiAgICAgICAgKTtcclxuICAgICAgfVxyXG4gICAgfSk7XHJcbiAgfSBlbHNlIHtcclxuICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcihcclxuICAgICAgJ1tjaGFydF0gTm8gZXhwZWN0ZWQgYGV4cG9ydGAgb3B0aW9ucyB3ZXJlIGZvdW5kLiBQbGVhc2UgcHJvdmlkZSB0aGUgYGJhdGNoYCBvcHRpb24gdG8gZ2VuZXJhdGUgdmFsaWQgaW1hZ2VzLicsXHJcbiAgICAgIDQwMFxyXG4gICAgKTtcclxuICB9XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBTdGFydHMgYW4gZXhwb3J0IHByb2Nlc3MuIFRoZSBgaW1hZ2VPcHRpb25zYCBwYXJhbWV0ZXIgaXMgYW4gb2JqZWN0IHRoYXRcclxuICogc2hvdWxkIGluY2x1ZGUgc2V0dGluZ3MgZnJvbSB0aGUgYGV4cG9ydGAgYW5kIGBjdXN0b21Mb2dpY2Agc2VjdGlvbnMuIEl0IGNhblxyXG4gKiBiZSBhIHBhcnRpYWwgb3IgY29tcGxldGUgc2V0IG9mIG9wdGlvbnMgZnJvbSB0aGVzZSBzZWN0aW9ucy4gSWYgcGFydGlhbFxyXG4gKiBvcHRpb25zIGFyZSBwcm92aWRlZCwgbWlzc2luZyB2YWx1ZXMgd2lsbCBiZSBtZXJnZWQgd2l0aCB0aGUgY3VycmVudCBnbG9iYWxcclxuICogb3B0aW9ucy5cclxuICpcclxuICogVGhlIGBlbmRDYWxsYmFja2AgZnVuY3Rpb24gaXMgaW52b2tlZCB1cG9uIHRoZSBjb21wbGV0aW9uIG9mIHRoZSBleHBvcnQsXHJcbiAqIGVpdGhlciBzdWNjZXNzZnVsbHkgb3Igd2l0aCBhbiBlcnJvci4gVGhlIGBlcnJvcmAgb2JqZWN0IGlzIHByb3ZpZGVkXHJcbiAqIGFzIHRoZSBmaXJzdCBhcmd1bWVudCwgYW5kIHRoZSBgZGF0YWAgb2JqZWN0IGlzIHRoZSBzZWNvbmQsIGNvbnRhaW5pbmdcclxuICogdGhlIEJhc2U2NCByZXByZXNlbnRhdGlvbiBvZiB0aGUgY2hhcnQgaW4gdGhlIGByZXN1bHRgIHByb3BlcnR5XHJcbiAqIGFuZCB0aGUgY29tcGxldGUgc2V0IG9mIG9wdGlvbnMgaW4gdGhlIGBvcHRpb25zYCBwcm9wZXJ0eS5cclxuICpcclxuICogQGFzeW5jXHJcbiAqIEBmdW5jdGlvbiBzdGFydEV4cG9ydFxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gaW1hZ2VPcHRpb25zIC0gVGhlIGBpbWFnZU9wdGlvbnNgIG9iamVjdCwgd2hpY2ggc2hvdWxkXHJcbiAqIGluY2x1ZGUgc2V0dGluZ3MgZnJvbSB0aGUgYGV4cG9ydGAgYW5kIGBjdXN0b21Mb2dpY2Agc2VjdGlvbnMuIEl0IGNhblxyXG4gKiBiZSBhIHBhcnRpYWwgb3IgY29tcGxldGUgc2V0IG9mIG9wdGlvbnMgZnJvbSB0aGVzZSBzZWN0aW9ucy4gSWYgdGhlIHByb3ZpZGVkXHJcbiAqIG9wdGlvbnMgYXJlIHBhcnRpYWwsIG1pc3NpbmcgdmFsdWVzIHdpbGwgYmUgbWVyZ2VkIHdpdGggdGhlIGN1cnJlbnQgZ2xvYmFsXHJcbiAqIG9wdGlvbnMuXHJcbiAqIEBwYXJhbSB7RnVuY3Rpb259IGVuZENhbGxiYWNrIC0gVGhlIGNhbGxiYWNrIGZ1bmN0aW9uIHRvIGJlIGludm9rZWQgdXBvblxyXG4gKiBmaW5hbGl6aW5nIHRoZSBleHBvcnQgcHJvY2VzcyBvciB1cG9uIGVuY291bnRlcmluZyBhbiBlcnJvci4gVGhlIGZpcnN0XHJcbiAqIGFyZ3VtZW50IGlzIHRoZSBgZXJyb3JgIG9iamVjdCwgYW5kIHRoZSBzZWNvbmQgYXJndW1lbnQgaXMgdGhlIGBkYXRhYCBvYmplY3QsXHJcbiAqIHdoaWNoIGluY2x1ZGVzIHRoZSBCYXNlNjQgcmVwcmVzZW50YXRpb24gb2YgdGhlIGNoYXJ0IGluIHRoZSBgcmVzdWx0YFxyXG4gKiBwcm9wZXJ0eSBhbmQgdGhlIGZ1bGwgc2V0IG9mIG9wdGlvbnMgaW4gdGhlIGBvcHRpb25zYCBwcm9wZXJ0eS5cclxuICpcclxuICogQHJldHVybnMge1Byb21pc2U8dm9pZD59IFRoaXMgZnVuY3Rpb24gZG9lcyBub3QgcmV0dXJuIGEgdmFsdWUgZGlyZWN0bHkuXHJcbiAqIEluc3RlYWQsIGl0IGNvbW11bmljYXRlcyByZXN1bHRzIHZpYSB0aGUgYGVuZENhbGxiYWNrYC5cclxuICpcclxuICogQHRocm93cyB7RXhwb3J0RXJyb3J9IFRocm93cyBhbiBgRXhwb3J0RXJyb3JgIGlmIHRoZXJlIGlzIGEgcHJvYmxlbSB3aXRoXHJcbiAqIHByb2Nlc3NpbmcgaW5wdXQgb2YgYW55IHR5cGUuIFRoZSBlcnJvciBpcyBwYXNzZWQgaW50byB0aGUgYGVuZENhbGxiYWNrYFxyXG4gKiBmdW5jdGlvbiBhbmQgcHJvY2Vzc2VkIHRoZXJlLlxyXG4gKi9cclxuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIHN0YXJ0RXhwb3J0KGltYWdlT3B0aW9ucywgZW5kQ2FsbGJhY2spIHtcclxuICB0cnkge1xyXG4gICAgLy8gQ2hlY2sgaWYgcHJvdmlkZWQgb3B0aW9ucyBhcmUgaW4gYW4gb2JqZWN0XHJcbiAgICBpZiAoIWlzT2JqZWN0KGltYWdlT3B0aW9ucykpIHtcclxuICAgICAgdGhyb3cgbmV3IEV4cG9ydEVycm9yKFxyXG4gICAgICAgICdbY2hhcnRdIEluY29ycmVjdCB2YWx1ZSBvZiB0aGUgcHJvdmlkZWQgYGltYWdlT3B0aW9uc2AuIE5lZWRzIHRvIGJlIGFuIG9iamVjdC4nLFxyXG4gICAgICAgIDQwMFxyXG4gICAgICApO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIE1lcmdlIGFkZGl0aW9uYWwgb3B0aW9ucyB0byB0aGUgY29weSBvZiB0aGUgaW5zdGFuY2Ugb3B0aW9uc1xyXG4gICAgY29uc3Qgb3B0aW9ucyA9IHVwZGF0ZU9wdGlvbnMoXHJcbiAgICAgIHtcclxuICAgICAgICBleHBvcnQ6IGltYWdlT3B0aW9ucy5leHBvcnQsXHJcbiAgICAgICAgY3VzdG9tTG9naWM6IGltYWdlT3B0aW9ucy5jdXN0b21Mb2dpY1xyXG4gICAgICB9LFxyXG4gICAgICB0cnVlXHJcbiAgICApO1xyXG5cclxuICAgIC8vIEdldCB0aGUgYGV4cG9ydGAgb3B0aW9uc1xyXG4gICAgY29uc3QgZXhwb3J0T3B0aW9ucyA9IG9wdGlvbnMuZXhwb3J0O1xyXG5cclxuICAgIC8vIFN0YXJ0aW5nIGV4cG9ydGluZyBwcm9jZXNzIG1lc3NhZ2VcclxuICAgIGxvZyg0LCAnW2NoYXJ0XSBTdGFydGluZyB0aGUgZXhwb3J0aW5nIHByb2Nlc3MuJyk7XHJcblxyXG4gICAgLy8gRXhwb3J0IHVzaW5nIG9wdGlvbnMgZnJvbSB0aGUgZmlsZSBhcyBhbiBpbnB1dFxyXG4gICAgaWYgKGV4cG9ydE9wdGlvbnMuaW5maWxlICE9PSBudWxsKSB7XHJcbiAgICAgIGxvZyg0LCAnW2NoYXJ0XSBBdHRlbXB0aW5nIHRvIGV4cG9ydCBmcm9tIGEgZmlsZSBpbnB1dC4nKTtcclxuXHJcbiAgICAgIGxldCBmaWxlQ29udGVudDtcclxuICAgICAgdHJ5IHtcclxuICAgICAgICAvLyBUcnkgdG8gcmVhZCB0aGUgZmlsZSB0byBnZXQgdGhlIHN0cmluZyByZXByZXNlbnRhdGlvblxyXG4gICAgICAgIGZpbGVDb250ZW50ID0gcmVhZEZpbGVTeW5jKFxyXG4gICAgICAgICAgZ2V0QWJzb2x1dGVQYXRoKGV4cG9ydE9wdGlvbnMuaW5maWxlKSxcclxuICAgICAgICAgICd1dGY4J1xyXG4gICAgICAgICk7XHJcbiAgICAgIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICAgICAgdGhyb3cgbmV3IEV4cG9ydEVycm9yKFxyXG4gICAgICAgICAgJ1tjaGFydF0gRXJyb3IgbG9hZGluZyBjb250ZW50IGZyb20gYSBmaWxlIGlucHV0LicsXHJcbiAgICAgICAgICA0MDBcclxuICAgICAgICApLnNldEVycm9yKGVycm9yKTtcclxuICAgICAgfVxyXG5cclxuICAgICAgLy8gQ2hlY2sgdGhlIGZpbGUncyBleHRlbnNpb25cclxuICAgICAgaWYgKGV4cG9ydE9wdGlvbnMuaW5maWxlLmVuZHNXaXRoKCcuc3ZnJykpIHtcclxuICAgICAgICAvLyBTZXQgdG8gdGhlIGBzdmdgIG9wdGlvblxyXG4gICAgICAgIGV4cG9ydE9wdGlvbnMuc3ZnID0gdmFsaWRhdGVPcHRpb24oJ3N2ZycsIGZpbGVDb250ZW50KTtcclxuICAgICAgfSBlbHNlIGlmIChleHBvcnRPcHRpb25zLmluZmlsZS5lbmRzV2l0aCgnLmpzb24nKSkge1xyXG4gICAgICAgIC8vIFNldCB0byB0aGUgYGluc3RyYCBvcHRpb25cclxuICAgICAgICBleHBvcnRPcHRpb25zLmluc3RyID0gdmFsaWRhdGVPcHRpb24oJ2luc3RyJywgZmlsZUNvbnRlbnQpO1xyXG4gICAgICB9IGVsc2Uge1xyXG4gICAgICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcihcclxuICAgICAgICAgICdbY2hhcnRdIEluY29ycmVjdCB2YWx1ZSBvZiB0aGUgYGluZmlsZWAgb3B0aW9uLicsXHJcbiAgICAgICAgICA0MDBcclxuICAgICAgICApO1xyXG4gICAgICB9XHJcbiAgICB9XHJcblxyXG4gICAgLy8gRXhwb3J0IHVzaW5nIFNWRyBhcyBhbiBpbnB1dFxyXG4gICAgaWYgKGV4cG9ydE9wdGlvbnMuc3ZnICE9PSBudWxsKSB7XHJcbiAgICAgIGxvZyg0LCAnW2NoYXJ0XSBBdHRlbXB0aW5nIHRvIGV4cG9ydCBmcm9tIGFuIFNWRyBpbnB1dC4nKTtcclxuXHJcbiAgICAgIC8vIFNWRyBleHBvcnRzIGF0dGVtcHRzIGNvdW50ZXJcclxuICAgICAgKytnZXRQb29sU3RhdHMoKS5leHBvcnRzRnJvbVN2Z0F0dGVtcHRzO1xyXG5cclxuICAgICAgLy8gRXhwb3J0IGZyb20gYW4gU1ZHIHN0cmluZ1xyXG4gICAgICBjb25zdCByZXN1bHQgPSBhd2FpdCBfZXhwb3J0RnJvbVN2ZyhcclxuICAgICAgICBzYW5pdGl6ZShleHBvcnRPcHRpb25zLnN2ZyksIC8vICMyMDlcclxuICAgICAgICBvcHRpb25zXHJcbiAgICAgICk7XHJcblxyXG4gICAgICAvLyBTVkcgZXhwb3J0cyBjb3VudGVyXHJcbiAgICAgICsrZ2V0UG9vbFN0YXRzKCkuZXhwb3J0c0Zyb21Tdmc7XHJcblxyXG4gICAgICAvLyBQYXNzIFNWRyBleHBvcnQgcmVzdWx0IHRvIHRoZSBlbmQgY2FsbGJhY2tcclxuICAgICAgcmV0dXJuIGVuZENhbGxiYWNrKG51bGwsIHJlc3VsdCk7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gRXhwb3J0IHVzaW5nIG9wdGlvbnMgYXMgYW4gaW5wdXRcclxuICAgIGlmIChleHBvcnRPcHRpb25zLmluc3RyICE9PSBudWxsIHx8IGV4cG9ydE9wdGlvbnMub3B0aW9ucyAhPT0gbnVsbCkge1xyXG4gICAgICBsb2coNCwgJ1tjaGFydF0gQXR0ZW1wdGluZyB0byBleHBvcnQgZnJvbSBvcHRpb25zIGlucHV0LicpO1xyXG5cclxuICAgICAgLy8gT3B0aW9ucyBleHBvcnRzIGF0dGVtcHRzIGNvdW50ZXJcclxuICAgICAgKytnZXRQb29sU3RhdHMoKS5leHBvcnRzRnJvbU9wdGlvbnNBdHRlbXB0cztcclxuXHJcbiAgICAgIC8vIEV4cG9ydCBmcm9tIG9wdGlvbnNcclxuICAgICAgY29uc3QgcmVzdWx0ID0gYXdhaXQgX2V4cG9ydEZyb21PcHRpb25zKFxyXG4gICAgICAgIGV4cG9ydE9wdGlvbnMuaW5zdHIgfHwgZXhwb3J0T3B0aW9ucy5vcHRpb25zLFxyXG4gICAgICAgIG9wdGlvbnNcclxuICAgICAgKTtcclxuXHJcbiAgICAgIC8vIE9wdGlvbnMgZXhwb3J0cyBjb3VudGVyXHJcbiAgICAgICsrZ2V0UG9vbFN0YXRzKCkuZXhwb3J0c0Zyb21PcHRpb25zO1xyXG5cclxuICAgICAgLy8gUGFzcyBvcHRpb25zIGV4cG9ydCByZXN1bHQgdG8gdGhlIGVuZCBjYWxsYmFja1xyXG4gICAgICByZXR1cm4gZW5kQ2FsbGJhY2sobnVsbCwgcmVzdWx0KTtcclxuICAgIH1cclxuXHJcbiAgICAvLyBObyBpbnB1dCBzcGVjaWZpZWQsIHBhc3MgYW4gZXJyb3IgbWVzc2FnZSB0byB0aGUgY2FsbGJhY2tcclxuICAgIHJldHVybiBlbmRDYWxsYmFjayhcclxuICAgICAgbmV3IEV4cG9ydEVycm9yKFxyXG4gICAgICAgIGBbY2hhcnRdIE5vIHZhbGlkIGlucHV0IHNwZWNpZmllZC4gQ2hlY2sgaWYgYXQgbGVhc3Qgb25lIG9mIHRoZSBmb2xsb3dpbmcgcGFyYW1ldGVycyBpcyBjb3JyZWN0bHkgc2V0OiAnaW5maWxlJywgJ2luc3RyJywgJ29wdGlvbnMnLCBvciAnc3ZnJy5gLFxyXG4gICAgICAgIDQwMFxyXG4gICAgICApXHJcbiAgICApO1xyXG4gIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICByZXR1cm4gZW5kQ2FsbGJhY2soZXJyb3IpO1xyXG4gIH1cclxufVxyXG5cclxuLyoqXHJcbiAqIFJldHJpZXZlcyBhbmQgcmV0dXJucyB0aGUgY3VycmVudCBzdGF0dXMgb2YgdGhlIGNvZGUgZXhlY3V0aW9uIHBlcm1pc3Npb24uXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBnZXRBbGxvd0NvZGVFeGVjdXRpb25cclxuICpcclxuICogQHJldHVybnMge2Jvb2xlYW59IFRoZSB2YWx1ZSBvZiB0aGUgZ2xvYmFsIGBhbGxvd0NvZGVFeGVjdXRpb25gIG9wdGlvbi5cclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiBnZXRBbGxvd0NvZGVFeGVjdXRpb24oKSB7XHJcbiAgcmV0dXJuIGFsbG93Q29kZUV4ZWN1dGlvbjtcclxufVxyXG5cclxuLyoqXHJcbiAqIFNldHMgdGhlIGNvZGUgZXhlY3V0aW9uIHBlcm1pc3Npb24gYmFzZWQgb24gdGhlIHByb3ZpZGVkIGJvb2xlYW4gdmFsdWUuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBzZXRBbGxvd0NvZGVFeGVjdXRpb25cclxuICpcclxuICogQHBhcmFtIHtib29sZWFufSB2YWx1ZSAtIFRoZSBib29sZWFuIHZhbHVlIHRvIGJlIGFzc2lnbmVkIHRvIHRoZSBnbG9iYWxcclxuICogYGFsbG93Q29kZUV4ZWN1dGlvbmAgb3B0aW9uLlxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIHNldEFsbG93Q29kZUV4ZWN1dGlvbih2YWx1ZSkge1xyXG4gIGFsbG93Q29kZUV4ZWN1dGlvbiA9IHZhbHVlO1xyXG59XHJcblxyXG4vKipcclxuICogRXhwb3J0cyBmcm9tIGFuIFNWRyBiYXNlZCBpbnB1dCB3aXRoIHRoZSBwcm92aWRlZCBvcHRpb25zLlxyXG4gKlxyXG4gKiBAYXN5bmNcclxuICogQGZ1bmN0aW9uIF9leHBvcnRGcm9tU3ZnXHJcbiAqXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSBpbnB1dFRvRXhwb3J0IC0gVGhlIFNWRyBiYXNlZCBpbnB1dCB0byBiZSBleHBvcnRlZC5cclxuICogQHBhcmFtIHtPYmplY3R9IG9wdGlvbnMgLSBUaGUgY29uZmlndXJhdGlvbiBvYmplY3QgY29udGFpbmluZyBjb21wbGV0ZSBzZXRcclxuICogb2Ygb3B0aW9ucy5cclxuICpcclxuICogQHJldHVybnMge1Byb21pc2U8dW5rbm93bj59IEEgUHJvbWlzZSB0aGF0IHJlc29sdmVzIHRvIGEgcmVzdWx0IG9mIHRoZSBleHBvcnRcclxuICogcHJvY2Vzcy5cclxuICpcclxuICogQHRocm93cyB7RXhwb3J0RXJyb3J9IFRocm93cyBhbiBgRXhwb3J0RXJyb3JgIGlmIHRoZXJlIGlzIG5vdCBhIGNvcnJlY3QgU1ZHXHJcbiAqIGlucHV0LlxyXG4gKi9cclxuYXN5bmMgZnVuY3Rpb24gX2V4cG9ydEZyb21TdmcoaW5wdXRUb0V4cG9ydCwgb3B0aW9ucykge1xyXG4gIC8vIENoZWNrIGlmIGl0IGlzIFNWR1xyXG4gIGlmIChcclxuICAgIHR5cGVvZiBpbnB1dFRvRXhwb3J0ID09PSAnc3RyaW5nJyAmJlxyXG4gICAgKGlucHV0VG9FeHBvcnQuaW5kZXhPZignPHN2ZycpID49IDAgfHwgaW5wdXRUb0V4cG9ydC5pbmRleE9mKCc8P3htbCcpID49IDApXHJcbiAgKSB7XHJcbiAgICBsb2coNCwgJ1tjaGFydF0gUGFyc2luZyBpbnB1dCBhcyBTVkcuJyk7XHJcblxyXG4gICAgLy8gU2V0IHRoZSBleHBvcnQgaW5wdXQgYXMgU1ZHXHJcbiAgICBvcHRpb25zLmV4cG9ydC5zdmcgPSBpbnB1dFRvRXhwb3J0O1xyXG5cclxuICAgIC8vIFJlc2V0IHRoZSByZXN0IG9mIHRoZSBleHBvcnQgaW5wdXQgb3B0aW9uc1xyXG4gICAgb3B0aW9ucy5leHBvcnQub3B0aW9ucyA9IG51bGw7XHJcbiAgICBvcHRpb25zLmV4cG9ydC5pbnN0ciA9IG51bGw7XHJcblxyXG4gICAgLy8gQ2FsbCB0aGUgZnVuY3Rpb24gd2l0aCBhbiBTVkcgc3RyaW5nIGFzIGFuIGV4cG9ydCBpbnB1dFxyXG4gICAgcmV0dXJuIF9wcmVwYXJlRXhwb3J0KG9wdGlvbnMpO1xyXG4gIH0gZWxzZSB7XHJcbiAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoJ1tjaGFydF0gTm90IGEgY29ycmVjdCBTVkcgaW5wdXQuJywgNDAwKTtcclxuICB9XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBFeHBvcnRzIGZyb20gYW4gb3B0aW9ucyBiYXNlZCBpbnB1dCB3aXRoIHRoZSBwcm92aWRlZCBvcHRpb25zLlxyXG4gKlxyXG4gKiBAYXN5bmNcclxuICogQGZ1bmN0aW9uIF9leHBvcnRGcm9tT3B0aW9uc1xyXG4gKlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gaW5wdXRUb0V4cG9ydCAtIFRoZSBvcHRpb25zIGJhc2VkIGlucHV0IHRvIGJlIGV4cG9ydGVkLlxyXG4gKiBAcGFyYW0ge09iamVjdH0gb3B0aW9ucyAtIFRoZSBjb25maWd1cmF0aW9uIG9iamVjdCBjb250YWluaW5nIGNvbXBsZXRlIHNldFxyXG4gKiBvZiBvcHRpb25zLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7UHJvbWlzZTx1bmtub3duPn0gQSBQcm9taXNlIHRoYXQgcmVzb2x2ZXMgdG8gYSByZXN1bHQgb2YgdGhlIGV4cG9ydFxyXG4gKiBwcm9jZXNzLlxyXG4gKlxyXG4gKiBAdGhyb3dzIHtFeHBvcnRFcnJvcn0gVGhyb3dzIGFuIGBFeHBvcnRFcnJvcmAgaWYgdGhlcmUgaXMgbm90IGEgY29ycmVjdFxyXG4gKiBjaGFydCBvcHRpb25zIGlucHV0LlxyXG4gKi9cclxuYXN5bmMgZnVuY3Rpb24gX2V4cG9ydEZyb21PcHRpb25zKGlucHV0VG9FeHBvcnQsIG9wdGlvbnMpIHtcclxuICBsb2coNCwgJ1tjaGFydF0gUGFyc2luZyBpbnB1dCBmcm9tIG9wdGlvbnMuJyk7XHJcblxyXG4gIC8vIFRyeSB0byBjaGVjaywgdmFsaWRhdGUgYW5kIHBhcnNlIHRvIHN0cmluZ2lmaWVkIG9wdGlvbnNcclxuICBjb25zdCBzdHJpbmdpZmllZE9wdGlvbnMgPSBpc0FsbG93ZWRDb25maWcoXHJcbiAgICBpbnB1dFRvRXhwb3J0LFxyXG4gICAgdHJ1ZSxcclxuICAgIG9wdGlvbnMuY3VzdG9tTG9naWMuYWxsb3dDb2RlRXhlY3V0aW9uXHJcbiAgKTtcclxuXHJcbiAgLy8gQ2hlY2sgaWYgYSBjb3JyZWN0IHN0cmluZ2lmaWVkIG9wdGlvbnNcclxuICBpZiAoXHJcbiAgICBzdHJpbmdpZmllZE9wdGlvbnMgPT09IG51bGwgfHxcclxuICAgIHR5cGVvZiBzdHJpbmdpZmllZE9wdGlvbnMgIT09ICdzdHJpbmcnIHx8XHJcbiAgICAhc3RyaW5naWZpZWRPcHRpb25zLnN0YXJ0c1dpdGgoJ3snKSB8fFxyXG4gICAgIXN0cmluZ2lmaWVkT3B0aW9ucy5lbmRzV2l0aCgnfScpXHJcbiAgKSB7XHJcbiAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoXHJcbiAgICAgICdbY2hhcnRdIEludmFsaWQgY29uZmlndXJhdGlvbiBwcm92aWRlZCAtIE9ubHkgb3B0aW9ucyBjb25maWd1cmF0aW9ucyBhbmQgU1ZHIGFyZSBhbGxvd2VkIGZvciB0aGlzIHNlcnZlci4gSWYgdGhpcyBpcyB5b3VyIHNlcnZlciwgSmF2YVNjcmlwdCBjdXN0b20gY29kZSBjYW4gYmUgZW5hYmxlZCBieSBzdGFydGluZyB0aGUgc2VydmVyIHdpdGggdGhlIGBhbGxvd0NvZGVFeGVjdXRpb25gIG9wdGlvbnMgc2V0IHRvIHRydWUuJyxcclxuICAgICAgNDAzXHJcbiAgICApO1xyXG4gIH1cclxuXHJcbiAgLy8gU2V0IHRoZSBleHBvcnQgaW5wdXQgYXMgYSBzdHJpbmdpZmllZCBjaGFydCBvcHRpb25zXHJcbiAgb3B0aW9ucy5leHBvcnQuaW5zdHIgPSBzdHJpbmdpZmllZE9wdGlvbnM7XHJcblxyXG4gIC8vIFJlc2V0IHRoZSByZXN0IG9mIHRoZSBleHBvcnQgaW5wdXQgb3B0aW9uc1xyXG4gIG9wdGlvbnMuZXhwb3J0Lm9wdGlvbnMgPSBudWxsO1xyXG4gIG9wdGlvbnMuZXhwb3J0LnN2ZyA9IG51bGw7XHJcblxyXG4gIC8vIENhbGwgdGhlIGZ1bmN0aW9uIHdpdGggYSBzdHJpbmdpZmllZCBjaGFydCBvcHRpb25zXHJcbiAgcmV0dXJuIF9wcmVwYXJlRXhwb3J0KG9wdGlvbnMpO1xyXG59XHJcblxyXG4vKipcclxuICogRnVuY3Rpb24gZm9yIGZpbmFsaXppbmcgb3B0aW9ucyBhbmQgY29uZmlndXJhdGlvbnMgYmVmb3JlIGV4cG9ydC5cclxuICpcclxuICogQGFzeW5jXHJcbiAqIEBmdW5jdGlvbiBfcHJlcGFyZUV4cG9ydFxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gb3B0aW9ucyAtIFRoZSBjb25maWd1cmF0aW9uIG9iamVjdCBjb250YWluaW5nIGNvbXBsZXRlIHNldFxyXG4gKiBvZiBvcHRpb25zLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7UHJvbWlzZTx1bmtub3duPn0gQSBQcm9taXNlIHRoYXQgcmVzb2x2ZXMgdG8gYSByZXN1bHQgb2YgdGhlIGV4cG9ydFxyXG4gKiBwcm9jZXNzLlxyXG4gKi9cclxuYXN5bmMgZnVuY3Rpb24gX3ByZXBhcmVFeHBvcnQob3B0aW9ucykge1xyXG4gIC8vIEdldCB0aGUgYGV4cG9ydGAgYW5kIGBjdXN0b21Mb2dpY2Agb3B0aW9uc1xyXG4gIGNvbnN0IHsgZXhwb3J0OiBleHBvcnRPcHRpb25zLCBjdXN0b21Mb2dpYzogY3VzdG9tTG9naWNPcHRpb25zIH0gPSBvcHRpb25zO1xyXG5cclxuICAvLyBQcmVwYXJlIHRoZSBgY29uc3RyYCBvcHRpb25cclxuICBleHBvcnRPcHRpb25zLmNvbnN0ciA9IF9maXhDb25zdHIoZXhwb3J0T3B0aW9ucy5jb25zdHIpO1xyXG5cclxuICAvLyBQcmVwYXJlIHRoZSBgdHlwZWAgb3B0aW9uXHJcbiAgZXhwb3J0T3B0aW9ucy50eXBlID0gX2ZpeFR5cGUoZXhwb3J0T3B0aW9ucy50eXBlLCBleHBvcnRPcHRpb25zLm91dGZpbGUpO1xyXG5cclxuICAvLyBQcmVwYXJlIHRoZSBgb3V0ZmlsZWAgb3B0aW9uXHJcbiAgZXhwb3J0T3B0aW9ucy5vdXRmaWxlID0gX2ZpeE91dGZpbGUoXHJcbiAgICBleHBvcnRPcHRpb25zLnR5cGUsXHJcbiAgICBleHBvcnRPcHRpb25zLm91dGZpbGVcclxuICApO1xyXG5cclxuICAvLyBOb3RpZnkgYWJvdXQgdGhlIGN1c3RvbSBsb2dpYyB1c2FnZSBzdGF0dXNcclxuICBsb2coXHJcbiAgICAzLFxyXG4gICAgYFtjaGFydF0gVGhlIGN1c3RvbSBsb2dpYyBpcyAke2N1c3RvbUxvZ2ljT3B0aW9ucy5hbGxvd0NvZGVFeGVjdXRpb24gPyAnYWxsb3dlZCcgOiAnZGlzYWxsb3dlZCd9LmBcclxuICApO1xyXG5cclxuICAvLyBQcmVwYXJlIHRoZSBgY3VzdG9tQ29kZWAsIGBjYWxsYmFja2AsIGFuZCBgcmVzb3VyY2VzYCBvcHRpb25zXHJcbiAgX2hhbmRsZUN1c3RvbUxvZ2ljKGN1c3RvbUxvZ2ljT3B0aW9ucyk7XHJcblxyXG4gIC8vIFByZXBhcmUgdGhlIGBnbG9iYWxPcHRpb25zYCBhbmQgYHRoZW1lT3B0aW9uc2Agb3B0aW9uc1xyXG4gIF9oYW5kbGVHbG9iYWxBbmRUaGVtZShleHBvcnRPcHRpb25zLCBjdXN0b21Mb2dpY09wdGlvbnMpO1xyXG5cclxuICAvLyBQcmVwYXJlIHRoZSBgaGVpZ2h0YCwgYHdpZHRoYCwgYW5kIGBzY2FsZWAgb3B0aW9uc1xyXG4gIF9oYW5kbGVTaXplKGV4cG9ydE9wdGlvbnMpO1xyXG5cclxuICAvLyBDaGVjayBpZiB0aGUgaW1hZ2Ugb3B0aW9ucyBvYmplY3QgZG9lcyBub3QgZXhjZWVkIHRoZSBzaXplIGxpbWl0XHJcbiAgX2NoZWNrRGF0YVNpemUoeyBleHBvcnQ6IGV4cG9ydE9wdGlvbnMsIGN1c3RvbUxvZ2ljOiBjdXN0b21Mb2dpY09wdGlvbnMgfSk7XHJcblxyXG4gIC8vIFBvc3QgdGhlIHdvcmsgdG8gdGhlIHBvb2xcclxuICByZXR1cm4gcG9zdFdvcmsob3B0aW9ucyk7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBIYW5kbGVzIGFkanVzdGluZyB0aGUgY29uc3RydWN0b3IgbmFtZSBieSB0cmFuc2Zvcm1pbmcgYW5kIG5vcm1hbGl6aW5nXHJcbiAqIGl0IGJhc2VkIG9uIGNvbW1vbiBjaGFydCB0eXBlcy5cclxuICpcclxuICogQGZ1bmN0aW9uIF9maXhDb25zdHJcclxuICpcclxuICogQHBhcmFtIHtzdHJpbmd9IGNvbnN0ciAtIFRoZSBvcmlnaW5hbCBjb25zdHJ1Y3RvciBuYW1lIHRvIGJlIGFkanVzdGVkLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7c3RyaW5nfSBUaGUgY29ycmVjdGVkIGNvbnN0cnVjdG9yIG5hbWUsIG9yICdjaGFydCcgaWYgdGhlIGlucHV0XHJcbiAqIGlzIG5vdCByZWNvZ25pemVkLlxyXG4gKi9cclxuZnVuY3Rpb24gX2ZpeENvbnN0cihjb25zdHIpIHtcclxuICB0cnkge1xyXG4gICAgLy8gRml4IHRoZSBjb25zdHJ1Y3RvciBieSBsb3dlcmluZyBjYXNpbmdcclxuICAgIGNvbnN0IGZpeGVkQ29uc3RyID0gYCR7Y29uc3RyLnRvTG93ZXJDYXNlKCkucmVwbGFjZSgnY2hhcnQnLCAnJyl9Q2hhcnRgO1xyXG5cclxuICAgIC8vIEhhbmRsZSB0aGUgY2FzZSB3aGVyZSB0aGUgcmVzdWx0IGlzIGp1c3QgJ0NoYXJ0J1xyXG4gICAgaWYgKGZpeGVkQ29uc3RyID09PSAnQ2hhcnQnKSB7XHJcbiAgICAgIGZpeGVkQ29uc3RyLnRvTG93ZXJDYXNlKCk7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gUmV0dXJuIHRoZSBjb3JyZWN0ZWQgY29uc3RydWN0b3IsIG90aGVyd2lzZSBkZWZhdWx0IHRvICdjaGFydCdcclxuICAgIHJldHVybiBbJ2NoYXJ0JywgJ3N0b2NrQ2hhcnQnLCAnbWFwQ2hhcnQnLCAnZ2FudHRDaGFydCddLmluY2x1ZGVzKFxyXG4gICAgICBmaXhlZENvbnN0clxyXG4gICAgKVxyXG4gICAgICA/IGZpeGVkQ29uc3RyXHJcbiAgICAgIDogJ2NoYXJ0JztcclxuICB9IGNhdGNoIHtcclxuICAgIC8vIERlZmF1bHQgdG8gJ2NoYXJ0JyBpbiBjYXNlIG9mIGFueSBlcnJvclxyXG4gICAgcmV0dXJuICdjaGFydCc7XHJcbiAgfVxyXG59XHJcblxyXG4vKipcclxuICogSGFuZGxlcyBmaXhpbmcgdGhlIG91dGZpbGUgYmFzZWQgb24gcHJvdmlkZWQgdHlwZS5cclxuICpcclxuICogQGZ1bmN0aW9uIF9maXhPdXRmaWxlXHJcbiAqXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSB0eXBlIC0gVGhlIG9yaWdpbmFsIGV4cG9ydCB0eXBlLlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gb3V0ZmlsZSAtIFRoZSBmaWxlIHBhdGggb3IgbmFtZS5cclxuICpcclxuICogQHJldHVybnMge3N0cmluZ30gVGhlIGNvcnJlY3RlZCBvdXRmaWxlLCBvciAnY2hhcnQucG5nJyBpZiB0aGUgaW5wdXRcclxuICogaXMgbm90IHJlY29nbml6ZWQuXHJcbiAqL1xyXG5mdW5jdGlvbiBfZml4T3V0ZmlsZSh0eXBlLCBvdXRmaWxlKSB7XHJcbiAgLy8gR2V0IHRoZSBmaWxlIG5hbWUgZnJvbSB0aGUgYG91dGZpbGVgIG9wdGlvblxyXG4gIGNvbnN0IGZpbGVOYW1lID0gZ2V0QWJzb2x1dGVQYXRoKG91dGZpbGUgfHwgJ2NoYXJ0JylcclxuICAgIC5zcGxpdCgnLicpXHJcbiAgICAuc2hpZnQoKTtcclxuXHJcbiAgLy8gUmV0dXJuIGEgY29ycmVjdCBvdXRmaWxlXHJcbiAgcmV0dXJuIGAke2ZpbGVOYW1lfS4ke3R5cGUgfHwgJ3BuZyd9YDtcclxufVxyXG5cclxuLyoqXHJcbiAqIEhhbmRsZXMgZml4aW5nIHRoZSBleHBvcnQgdHlwZSBiYXNlZCBvbiBNSU1FIHR5cGVzIGFuZCBmaWxlIGV4dGVuc2lvbnMuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBfZml4VHlwZVxyXG4gKlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gdHlwZSAtIFRoZSBvcmlnaW5hbCBleHBvcnQgdHlwZS5cclxuICogQHBhcmFtIHtzdHJpbmd9IFtvdXRmaWxlPW51bGxdIC0gVGhlIGZpbGUgcGF0aCBvciBuYW1lLiBUaGUgZGVmYXVsdCB2YWx1ZVxyXG4gKiBpcyBgbnVsbGAuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtzdHJpbmd9IFRoZSBjb3JyZWN0ZWQgZXhwb3J0IHR5cGUsIG9yICdwbmcnIGlmIHRoZSBpbnB1dFxyXG4gKiBpcyBub3QgcmVjb2duaXplZC5cclxuICovXHJcbmZ1bmN0aW9uIF9maXhUeXBlKHR5cGUsIG91dGZpbGUgPSBudWxsKSB7XHJcbiAgLy8gTUlNRSB0eXBlc1xyXG4gIGNvbnN0IG1pbWVUeXBlcyA9IHtcclxuICAgICdpbWFnZS9wbmcnOiAncG5nJyxcclxuICAgICdpbWFnZS9qcGVnJzogJ2pwZWcnLFxyXG4gICAgJ2FwcGxpY2F0aW9uL3BkZic6ICdwZGYnLFxyXG4gICAgJ2ltYWdlL3N2Zyt4bWwnOiAnc3ZnJ1xyXG4gIH07XHJcblxyXG4gIC8vIEdldCBmb3JtYXRzXHJcbiAgY29uc3QgZm9ybWF0cyA9IE9iamVjdC52YWx1ZXMobWltZVR5cGVzKTtcclxuXHJcbiAgLy8gQ2hlY2sgaWYgdHlwZSBhbmQgb3V0ZmlsZSdzIGV4dGVuc2lvbnMgYXJlIHRoZSBzYW1lXHJcbiAgaWYgKG91dGZpbGUpIHtcclxuICAgIGNvbnN0IG91dFR5cGUgPSBvdXRmaWxlLnNwbGl0KCcuJykucG9wKCk7XHJcblxyXG4gICAgLy8gU3VwcG9ydCB0aGUgSlBHIHR5cGVcclxuICAgIGlmIChvdXRUeXBlID09PSAnanBnJykge1xyXG4gICAgICB0eXBlID0gJ2pwZWcnO1xyXG4gICAgfSBlbHNlIGlmIChmb3JtYXRzLmluY2x1ZGVzKG91dFR5cGUpICYmIHR5cGUgIT09IG91dFR5cGUpIHtcclxuICAgICAgdHlwZSA9IG91dFR5cGU7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICAvLyBSZXR1cm4gYSBjb3JyZWN0IHR5cGVcclxuICByZXR1cm4gbWltZVR5cGVzW3R5cGVdIHx8IGZvcm1hdHMuZmluZCgodCkgPT4gdCA9PT0gdHlwZSkgfHwgJ3BuZyc7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBIYW5kbGUgY2FsY3VsYXRpbmcgdGhlIGBoZWlnaHRgLCBgd2lkdGhgIGFuZCBgc2NhbGVgIGZvciBjaGFydCBleHBvcnRzIGJhc2VkXHJcbiAqIG9uIHRoZSBwcm92aWRlZCBleHBvcnQgb3B0aW9ucy5cclxuICpcclxuICogVGhlIGZ1bmN0aW9uIHByaW9yaXRpemVzIHZhbHVlcyBpbiB0aGUgZm9sbG93aW5nIG9yZGVyOlxyXG4gKlxyXG4gKiAxLiBUaGUgYGhlaWdodGAsIGB3aWR0aGAsIGBzY2FsZWAgZnJvbSB0aGUgYGV4cG9ydE9wdGlvbnNgLlxyXG4gKiAyLiBPcHRpb25zIGZyb20gdGhlIGNoYXJ0IGNvbmZpZ3VyYXRpb24gKGZyb20gYGV4cG9ydGluZ2AgYW5kIGBjaGFydGApLlxyXG4gKiAzLiBPcHRpb25zIGZyb20gdGhlIGdsb2JhbCBvcHRpb25zIChmcm9tIGBleHBvcnRpbmdgIGFuZCBgY2hhcnRgKS5cclxuICogNC4gT3B0aW9ucyBmcm9tIHRoZSB0aGVtZSBvcHRpb25zIChmcm9tIGBleHBvcnRpbmdgIGFuZCBgY2hhcnRgIHNlY3Rpb25zKS5cclxuICogNS4gRmFsbGJhY2sgZGVmYXVsdCB2YWx1ZXMgKGBoZWlnaHQgPSA0MDBgLCBgd2lkdGggPSA2MDBgLCBgc2NhbGUgPSAxYCkuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBfaGFuZGxlU2l6ZVxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gZXhwb3J0T3B0aW9ucyAtIFRoZSBjb25maWd1cmF0aW9uIG9iamVjdCBjb250YWluaW5nIGBleHBvcnRgXHJcbiAqIG9wdGlvbnMuXHJcbiAqL1xyXG5mdW5jdGlvbiBfaGFuZGxlU2l6ZShleHBvcnRPcHRpb25zKSB7XHJcbiAgLy8gQ2hlY2sgdGhlIGBvcHRpb25zYCBhbmQgYGluc3RyYCBmb3IgY2hhcnQgYW5kIGV4cG9ydGluZyBzZWN0aW9uc1xyXG4gIGNvbnN0IHsgY2hhcnQ6IG9wdGlvbnNDaGFydCwgZXhwb3J0aW5nOiBvcHRpb25zRXhwb3J0aW5nIH0gPVxyXG4gICAgaXNBbGxvd2VkQ29uZmlnKGV4cG9ydE9wdGlvbnMuaW5zdHIpIHx8IGZhbHNlO1xyXG5cclxuICAvLyBDaGVjayB0aGUgYGdsb2JhbE9wdGlvbnNgIGZvciBjaGFydCBhbmQgZXhwb3J0aW5nIHNlY3Rpb25zXHJcbiAgY29uc3QgeyBjaGFydDogZ2xvYmFsT3B0aW9uc0NoYXJ0LCBleHBvcnRpbmc6IGdsb2JhbE9wdGlvbnNFeHBvcnRpbmcgfSA9XHJcbiAgICBpc0FsbG93ZWRDb25maWcoZXhwb3J0T3B0aW9ucy5nbG9iYWxPcHRpb25zKSB8fCBmYWxzZTtcclxuXHJcbiAgLy8gQ2hlY2sgdGhlIGB0aGVtZU9wdGlvbnNgIGZvciBjaGFydCBhbmQgZXhwb3J0aW5nIHNlY3Rpb25zXHJcbiAgY29uc3QgeyBjaGFydDogdGhlbWVPcHRpb25zQ2hhcnQsIGV4cG9ydGluZzogdGhlbWVPcHRpb25zRXhwb3J0aW5nIH0gPVxyXG4gICAgaXNBbGxvd2VkQ29uZmlnKGV4cG9ydE9wdGlvbnMudGhlbWVPcHRpb25zKSB8fCBmYWxzZTtcclxuXHJcbiAgLy8gRmluZCB0aGUgYGhlaWdodGAgdmFsdWVcclxuICBjb25zdCBoZWlnaHQgPVxyXG4gICAgZXhwb3J0T3B0aW9ucy5oZWlnaHQgfHxcclxuICAgIG9wdGlvbnNFeHBvcnRpbmc/LnNvdXJjZUhlaWdodCB8fFxyXG4gICAgb3B0aW9uc0NoYXJ0Py5oZWlnaHQgfHxcclxuICAgIGdsb2JhbE9wdGlvbnNFeHBvcnRpbmc/LnNvdXJjZUhlaWdodCB8fFxyXG4gICAgZ2xvYmFsT3B0aW9uc0NoYXJ0Py5oZWlnaHQgfHxcclxuICAgIHRoZW1lT3B0aW9uc0V4cG9ydGluZz8uc291cmNlSGVpZ2h0IHx8XHJcbiAgICB0aGVtZU9wdGlvbnNDaGFydD8uaGVpZ2h0IHx8XHJcbiAgICBleHBvcnRPcHRpb25zLmRlZmF1bHRIZWlnaHQgfHxcclxuICAgIDQwMDtcclxuXHJcbiAgLy8gRmluZCB0aGUgYHdpZHRoYCB2YWx1ZVxyXG4gIGNvbnN0IHdpZHRoID1cclxuICAgIGV4cG9ydE9wdGlvbnMud2lkdGggfHxcclxuICAgIG9wdGlvbnNFeHBvcnRpbmc/LnNvdXJjZVdpZHRoIHx8XHJcbiAgICBvcHRpb25zQ2hhcnQ/LndpZHRoIHx8XHJcbiAgICBnbG9iYWxPcHRpb25zRXhwb3J0aW5nPy5zb3VyY2VXaWR0aCB8fFxyXG4gICAgZ2xvYmFsT3B0aW9uc0NoYXJ0Py53aWR0aCB8fFxyXG4gICAgdGhlbWVPcHRpb25zRXhwb3J0aW5nPy5zb3VyY2VXaWR0aCB8fFxyXG4gICAgdGhlbWVPcHRpb25zQ2hhcnQ/LndpZHRoIHx8XHJcbiAgICBleHBvcnRPcHRpb25zLmRlZmF1bHRXaWR0aCB8fFxyXG4gICAgNjAwO1xyXG5cclxuICAvLyBGaW5kIHRoZSBgc2NhbGVgIHZhbHVlOlxyXG4gIC8vIC0gQ2Fubm90IGJlIGxvd2VyIHRoYW4gMC4xXHJcbiAgLy8gLSBDYW5ub3QgYmUgaGlnaGVyIHRoYW4gNS4wXHJcbiAgLy8gLSBNdXN0IGJlIHJvdW5kZWQgdG8gMiBkZWNpbWFsIHBsYWNlcyAoZS5nLiAwLjIzMjM0IC0+IDAuMjMpXHJcbiAgY29uc3Qgc2NhbGUgPSByb3VuZE51bWJlcihcclxuICAgIE1hdGgubWF4KFxyXG4gICAgICAwLjEsXHJcbiAgICAgIE1hdGgubWluKFxyXG4gICAgICAgIGV4cG9ydE9wdGlvbnMuc2NhbGUgfHxcclxuICAgICAgICAgIG9wdGlvbnNFeHBvcnRpbmc/LnNjYWxlIHx8XHJcbiAgICAgICAgICBnbG9iYWxPcHRpb25zRXhwb3J0aW5nPy5zY2FsZSB8fFxyXG4gICAgICAgICAgdGhlbWVPcHRpb25zRXhwb3J0aW5nPy5zY2FsZSB8fFxyXG4gICAgICAgICAgZXhwb3J0T3B0aW9ucy5kZWZhdWx0U2NhbGUgfHxcclxuICAgICAgICAgIDEsXHJcbiAgICAgICAgNS4wXHJcbiAgICAgIClcclxuICAgICksXHJcbiAgICAyXHJcbiAgKTtcclxuXHJcbiAgLy8gVXBkYXRlIGBoZWlnaHRgLCBgd2lkdGhgLCBhbmQgYHNjYWxlYCBpbmZvcm1hdGlvbiBpbiB0aGUgYGV4cG9ydGAgb3B0aW9uc1xyXG4gIGV4cG9ydE9wdGlvbnMuaGVpZ2h0ID0gaGVpZ2h0O1xyXG4gIGV4cG9ydE9wdGlvbnMud2lkdGggPSB3aWR0aDtcclxuICBleHBvcnRPcHRpb25zLnNjYWxlID0gc2NhbGU7XHJcblxyXG4gIC8vIEdldCByaWQgb2YgcG90ZW50aWFsIGBweGAgYW5kIGAlYFxyXG4gIGZvciAobGV0IHBhcmFtIG9mIFsnaGVpZ2h0JywgJ3dpZHRoJywgJ3NjYWxlJ10pIHtcclxuICAgIGlmICh0eXBlb2YgZXhwb3J0T3B0aW9uc1twYXJhbV0gPT09ICdzdHJpbmcnKSB7XHJcbiAgICAgIGV4cG9ydE9wdGlvbnNbcGFyYW1dID0gK2V4cG9ydE9wdGlvbnNbcGFyYW1dLnJlcGxhY2UoL3B4fCUvZ2ksICcnKTtcclxuICAgIH1cclxuICB9XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBIYW5kbGVzIHRoZSBleGVjdXRpb24gb2YgY3VzdG9tIGxvZ2ljIG9wdGlvbnMsIGluY2x1ZGluZyBsb2FkaW5nIGByZXNvdXJjZXNgLFxyXG4gKiBgY3VzdG9tQ29kZWAsIGFuZCBgY2FsbGJhY2tgLiBJZiBjb2RlIGV4ZWN1dGlvbiBpcyBhbGxvd2VkLCBpdCBwcm9jZXNzZXNcclxuICogdGhlIGN1c3RvbSBsb2dpYyBvcHRpb25zIGFjY29yZGluZ2x5LiBJZiBjb2RlIGV4ZWN1dGlvbiBpcyBub3QgYWxsb3dlZCxcclxuICogaXQgZGlzYWJsZXMgdGhlIHVzYWdlIG9mIHJlc291cmNlcywgY3VzdG9tIGNvZGUgYW5kIGNhbGxiYWNrLlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gX2hhbmRsZUN1c3RvbUxvZ2ljXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBjdXN0b21Mb2dpY09wdGlvbnMgLSBUaGUgY29uZmlndXJhdGlvbiBvYmplY3QgY29udGFpbmluZ1xyXG4gKiBgY3VzdG9tTG9naWNgIG9wdGlvbnMuXHJcbiAqXHJcbiAqIEB0aHJvd3Mge0V4cG9ydEVycm9yfSBUaHJvd3MgYW4gYEV4cG9ydEVycm9yYCBpZiBjb2RlIGV4ZWN1dGlvblxyXG4gKiBpcyBub3QgYWxsb3dlZCBidXQgY3VzdG9tIGxvZ2ljIG9wdGlvbnMgYXJlIHN0aWxsIHByb3ZpZGVkLlxyXG4gKi9cclxuZnVuY3Rpb24gX2hhbmRsZUN1c3RvbUxvZ2ljKGN1c3RvbUxvZ2ljT3B0aW9ucykge1xyXG4gIC8vIEluIGNhc2Ugb2YgYWxsb3dpbmcgY29kZSBleGVjdXRpb25cclxuICBpZiAoY3VzdG9tTG9naWNPcHRpb25zLmFsbG93Q29kZUV4ZWN1dGlvbikge1xyXG4gICAgLy8gUHJvY2VzcyB0aGUgYHJlc291cmNlc2Agb3B0aW9uXHJcbiAgICB0cnkge1xyXG4gICAgICAvLyBUcnkgdG8gaGFuZGxlIHJlc291cmNlc1xyXG4gICAgICBjdXN0b21Mb2dpY09wdGlvbnMucmVzb3VyY2VzID0gX2hhbmRsZVJlc291cmNlcyhcclxuICAgICAgICBjdXN0b21Mb2dpY09wdGlvbnMucmVzb3VyY2VzLFxyXG4gICAgICAgIGN1c3RvbUxvZ2ljT3B0aW9ucy5hbGxvd0ZpbGVSZXNvdXJjZXMsXHJcbiAgICAgICAgdHJ1ZVxyXG4gICAgICApO1xyXG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICAgbG9nKDIsICdbY2hhcnRdIFRoZSBgcmVzb3VyY2VzYCBjYW5ub3QgYmUgbG9hZGVkLicpO1xyXG5cclxuICAgICAgLy8gSW4gY2FzZSBvZiBhbiBlcnJvciwgc2V0IHRoZSBvcHRpb24gd2l0aCBudWxsXHJcbiAgICAgIGN1c3RvbUxvZ2ljT3B0aW9ucy5yZXNvdXJjZXMgPSBudWxsO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIFByb2Nlc3MgdGhlIGBjdXN0b21Db2RlYCBvcHRpb25cclxuICAgIHRyeSB7XHJcbiAgICAgIC8vIFRyeSB0byBsb2FkIGN1c3RvbSBjb2RlIGFuZCB3cmFwIGFyb3VuZCBpdCBpbiBhIHNlbGYgaW52b2tpbmcgZnVuY3Rpb25cclxuICAgICAgY3VzdG9tTG9naWNPcHRpb25zLmN1c3RvbUNvZGUgPSBfaGFuZGxlQ3VzdG9tQ29kZShcclxuICAgICAgICBjdXN0b21Mb2dpY09wdGlvbnMuY3VzdG9tQ29kZSxcclxuICAgICAgICBjdXN0b21Mb2dpY09wdGlvbnMuYWxsb3dGaWxlUmVzb3VyY2VzXHJcbiAgICAgICk7XHJcblxyXG4gICAgICAvLyBWYWxpZGF0ZSB0aGUgb3B0aW9uXHJcbiAgICAgIGN1c3RvbUxvZ2ljT3B0aW9ucy5jdXN0b21Db2RlID0gdmFsaWRhdGVPcHRpb24oXHJcbiAgICAgICAgJ2N1c3RvbUNvZGUnLFxyXG4gICAgICAgIGN1c3RvbUxvZ2ljT3B0aW9ucy5jdXN0b21Db2RlXHJcbiAgICAgICk7XHJcbiAgICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgICBsb2dXaXRoU3RhY2soMiwgZXJyb3IsICdbY2hhcnRdIFRoZSBgY3VzdG9tQ29kZWAgY2Fubm90IGJlIGxvYWRlZC4nKTtcclxuXHJcbiAgICAgIC8vIEluIGNhc2Ugb2YgYW4gZXJyb3IsIHNldCB0aGUgb3B0aW9uIHdpdGggbnVsbFxyXG4gICAgICBjdXN0b21Mb2dpY09wdGlvbnMuY3VzdG9tQ29kZSA9IG51bGw7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gUHJvY2VzcyB0aGUgYGNhbGxiYWNrYCBvcHRpb25cclxuICAgIHRyeSB7XHJcbiAgICAgIC8vIFRyeSB0byBsb2FkIGNhbGxiYWNrIGZ1bmN0aW9uXHJcbiAgICAgIGN1c3RvbUxvZ2ljT3B0aW9ucy5jYWxsYmFjayA9IF9oYW5kbGVDdXN0b21Db2RlKFxyXG4gICAgICAgIGN1c3RvbUxvZ2ljT3B0aW9ucy5jYWxsYmFjayxcclxuICAgICAgICBjdXN0b21Mb2dpY09wdGlvbnMuYWxsb3dGaWxlUmVzb3VyY2VzLFxyXG4gICAgICAgIHRydWVcclxuICAgICAgKTtcclxuXHJcbiAgICAgIC8vIFZhbGlkYXRlIHRoZSBvcHRpb25cclxuICAgICAgY3VzdG9tTG9naWNPcHRpb25zLmNhbGxiYWNrID0gdmFsaWRhdGVPcHRpb24oXHJcbiAgICAgICAgJ2NhbGxiYWNrJyxcclxuICAgICAgICBjdXN0b21Mb2dpY09wdGlvbnMuY2FsbGJhY2tcclxuICAgICAgKTtcclxuICAgIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICAgIGxvZ1dpdGhTdGFjaygyLCBlcnJvciwgJ1tjaGFydF0gVGhlIGBjYWxsYmFja2AgY2Fubm90IGJlIGxvYWRlZC4nKTtcclxuXHJcbiAgICAgIC8vIEluIGNhc2Ugb2YgYW4gZXJyb3IsIHNldCB0aGUgb3B0aW9uIHdpdGggbnVsbFxyXG4gICAgICBjdXN0b21Mb2dpY09wdGlvbnMuY2FsbGJhY2sgPSBudWxsO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIENoZWNrIGlmIHRoZXJlIGlzIHRoZSBgY3VzdG9tQ29kZWAgcHJlc2VudFxyXG4gICAgaWYgKFtudWxsLCB1bmRlZmluZWRdLmluY2x1ZGVzKGN1c3RvbUxvZ2ljT3B0aW9ucy5jdXN0b21Db2RlKSkge1xyXG4gICAgICBsb2coMywgJ1tjaGFydF0gTm8gdmFsdWUgZm9yIHRoZSBgY3VzdG9tQ29kZWAgb3B0aW9uIGZvdW5kLicpO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIENoZWNrIGlmIHRoZXJlIGlzIHRoZSBgY2FsbGJhY2tgIHByZXNlbnRcclxuICAgIGlmIChbbnVsbCwgdW5kZWZpbmVkXS5pbmNsdWRlcyhjdXN0b21Mb2dpY09wdGlvbnMuY2FsbGJhY2spKSB7XHJcbiAgICAgIGxvZygzLCAnW2NoYXJ0XSBObyB2YWx1ZSBmb3IgdGhlIGBjYWxsYmFja2Agb3B0aW9uIGZvdW5kLicpO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIENoZWNrIGlmIHRoZXJlIGlzIHRoZSBgcmVzb3VyY2VzYCBwcmVzZW50XHJcbiAgICBpZiAoW251bGwsIHVuZGVmaW5lZF0uaW5jbHVkZXMoY3VzdG9tTG9naWNPcHRpb25zLnJlc291cmNlcykpIHtcclxuICAgICAgbG9nKDMsICdbY2hhcnRdIE5vIHZhbHVlIGZvciB0aGUgYHJlc291cmNlc2Agb3B0aW9uIGZvdW5kLicpO1xyXG4gICAgfVxyXG4gIH0gZWxzZSB7XHJcbiAgICAvLyBJZiB0aGUgYGFsbG93Q29kZUV4ZWN1dGlvbmAgZmxhZyBpcyBzZXQgdG8gZmFsc2UsIHdlIHNob3VsZCByZWZ1c2VcclxuICAgIC8vIHRoZSB1c2FnZSBvZiB0aGUgYGNhbGxiYWNrYCwgYHJlc291cmNlc2AsIGFuZCBgY3VzdG9tQ29kZWAgb3B0aW9ucy5cclxuICAgIC8vIEFkZGl0aW9uYWxseSwgdGhlIHdvcmtlciB3aWxsIHJlZnVzZSB0byBydW4gYXJiaXRyYXJ5IEphdmFTY3JpcHQuXHJcbiAgICBpZiAoXHJcbiAgICAgIGN1c3RvbUxvZ2ljT3B0aW9ucy5jYWxsYmFjayB8fFxyXG4gICAgICBjdXN0b21Mb2dpY09wdGlvbnMucmVzb3VyY2VzIHx8XHJcbiAgICAgIGN1c3RvbUxvZ2ljT3B0aW9ucy5jdXN0b21Db2RlXHJcbiAgICApIHtcclxuICAgICAgLy8gUmVzZXQgYWxsIGN1c3RvbSBjb2RlIG9wdGlvbnNcclxuICAgICAgY3VzdG9tTG9naWNPcHRpb25zLmNhbGxiYWNrID0gbnVsbDtcclxuICAgICAgY3VzdG9tTG9naWNPcHRpb25zLnJlc291cmNlcyA9IG51bGw7XHJcbiAgICAgIGN1c3RvbUxvZ2ljT3B0aW9ucy5jdXN0b21Db2RlID0gbnVsbDtcclxuXHJcbiAgICAgIC8vIFNlbmQgYSBtZXNzYWdlIHNheWluZyB0aGF0IHRoZSBleHBvcnRlciBkb2VzIG5vdCBzdXBwb3J0IHRoZXNlIHNldHRpbmdzXHJcbiAgICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcihcclxuICAgICAgICBgW2NoYXJ0XSBUaGUgJ2NhbGxiYWNrJywgJ3Jlc291cmNlcycsIGFuZCAnY3VzdG9tQ29kZScgb3B0aW9ucyBoYXZlIGJlZW4gZGlzYWJsZWQgZm9yIHRoaXMgc2VydmVyLmAsXHJcbiAgICAgICAgNDAzXHJcbiAgICAgICk7XHJcbiAgICB9XHJcbiAgfVxyXG59XHJcblxyXG4vKipcclxuICogSGFuZGxlcyBhbmQgdmFsaWRhdGVzIHJlc291cmNlcyBmcm9tIHRoZSBgcmVzb3VyY2VzYCBvcHRpb24gZm9yIGV4cG9ydC5cclxuICpcclxuICogQGZ1bmN0aW9uIF9oYW5kbGVSZXNvdXJjZXNcclxuICpcclxuICogQHBhcmFtIHsoT2JqZWN0fHN0cmluZ3xudWxsKX0gW3Jlc291cmNlcz1udWxsXSAtIFRoZSByZXNvdXJjZXMgdG8gYmUgaGFuZGxlZC5cclxuICogQ2FuIGJlIGVpdGhlciBhIEpTT04gb2JqZWN0LCBzdHJpbmdpZmllZCBKU09OLCBhIHBhdGggdG8gYSBKU09OIGZpbGUsXHJcbiAqIG9yIG51bGwuIFRoZSBkZWZhdWx0IHZhbHVlIGlzIGBudWxsYC5cclxuICogQHBhcmFtIHtib29sZWFufSBhbGxvd0ZpbGVSZXNvdXJjZXMgLSBBIGZsYWcgaW5kaWNhdGluZyB3aGV0aGVyIGxvYWRpbmdcclxuICogcmVzb3VyY2VzIGZyb20gZmlsZXMgaXMgYWxsb3dlZC5cclxuICogQHBhcmFtIHtib29sZWFufSBhbGxvd0NvZGVFeGVjdXRpb24gLSBBIGZsYWcgaW5kaWNhdGluZyB3aGV0aGVyIGNvZGVcclxuICogZXhlY3V0aW9uIGlzIGFsbG93ZWQuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHsoT2JqZWN0fG51bGwpfSBUaGUgaGFuZGxlZCByZXNvdXJjZXMgb3IgbnVsbCBpZiBubyB2YWxpZCByZXNvdXJjZXNcclxuICogYXJlIGZvdW5kLlxyXG4gKi9cclxuZnVuY3Rpb24gX2hhbmRsZVJlc291cmNlcyhcclxuICByZXNvdXJjZXMgPSBudWxsLFxyXG4gIGFsbG93RmlsZVJlc291cmNlcyxcclxuICBhbGxvd0NvZGVFeGVjdXRpb25cclxuKSB7XHJcbiAgbGV0IGhhbmRsZWRSZXNvdXJjZXMgPSByZXNvdXJjZXM7XHJcblxyXG4gIC8vIElmIG5vIHJlc291cmNlcyBmb3VuZCwgdHJ5IHRvIGxvYWQgdGhlIGRlZmF1bHQgcmVzb3VyY2VzXHJcbiAgaWYgKCFoYW5kbGVkUmVzb3VyY2VzKSB7XHJcbiAgICByZXNvdXJjZXMgPSAncmVzb3VyY2VzLmpzb24nO1xyXG4gIH1cclxuXHJcbiAgLy8gTGlzdCBvZiBhbGxvd2VkIHNlY3Rpb25zIGluIHRoZSByZXNvdXJjZXMgSlNPTlxyXG4gIGNvbnN0IGFsbG93ZWRQcm9wcyA9IFsnanMnLCAnY3NzJywgJ2ZpbGVzJ107XHJcblxyXG4gIC8vIEEgZmxhZyB0aGF0IGRlY2lkZXMgYmFzZWQgdG8gcmV0dXJuIHJlc291cmNlcyBvciBgbnVsbGBcclxuICBsZXQgY29ycmVjdFJlc291cmNlcyA9IGZhbHNlO1xyXG5cclxuICAvLyBUcnkgdG8gbG9hZCByZXNvdXJjZXMgZnJvbSBhIGZpbGVcclxuICBpZiAoXHJcbiAgICBhbGxvd0ZpbGVSZXNvdXJjZXMgJiZcclxuICAgIHR5cGVvZiByZXNvdXJjZXMgPT09ICdzdHJpbmcnICYmXHJcbiAgICByZXNvdXJjZXMuZW5kc1dpdGgoJy5qc29uJylcclxuICApIHtcclxuICAgIGhhbmRsZWRSZXNvdXJjZXMgPSBpc0FsbG93ZWRDb25maWcoXHJcbiAgICAgIHJlYWRGaWxlU3luYyhnZXRBYnNvbHV0ZVBhdGgocmVzb3VyY2VzKSwgJ3V0ZjgnKSxcclxuICAgICAgZmFsc2UsXHJcbiAgICAgIGFsbG93Q29kZUV4ZWN1dGlvblxyXG4gICAgKTtcclxuICB9IGVsc2Uge1xyXG4gICAgLy8gVHJ5IHRvIGdldCBKU09OXHJcbiAgICBoYW5kbGVkUmVzb3VyY2VzID0gaXNBbGxvd2VkQ29uZmlnKHJlc291cmNlcywgZmFsc2UsIGFsbG93Q29kZUV4ZWN1dGlvbik7XHJcblxyXG4gICAgLy8gR2V0IHJpZCBvZiB0aGUgZmlsZXMgc2VjdGlvblxyXG4gICAgaWYgKGhhbmRsZWRSZXNvdXJjZXMgJiYgIWFsbG93RmlsZVJlc291cmNlcykge1xyXG4gICAgICBkZWxldGUgaGFuZGxlZFJlc291cmNlcy5maWxlcztcclxuICAgIH1cclxuICB9XHJcblxyXG4gIC8vIEZpbHRlciBmcm9tIHVubmVjZXNzYXJ5IHByb3BlcnRpZXNcclxuICBmb3IgKGNvbnN0IHByb3BOYW1lIGluIGhhbmRsZWRSZXNvdXJjZXMpIHtcclxuICAgIGlmICghYWxsb3dlZFByb3BzLmluY2x1ZGVzKHByb3BOYW1lKSkge1xyXG4gICAgICBkZWxldGUgaGFuZGxlZFJlc291cmNlc1twcm9wTmFtZV07XHJcbiAgICB9IGVsc2UgaWYgKCFjb3JyZWN0UmVzb3VyY2VzKSB7XHJcbiAgICAgIGNvcnJlY3RSZXNvdXJjZXMgPSB0cnVlO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgLy8gQ2hlY2sgaWYgYXQgbGVhc3Qgb25lIG9mIGFsbG93ZWQgcHJvcGVydGllcyBpcyBwcmVzZW50XHJcbiAgaWYgKCFjb3JyZWN0UmVzb3VyY2VzKSB7XHJcbiAgICByZXR1cm4gbnVsbDtcclxuICB9XHJcblxyXG4gIC8vIEhhbmRsZSBmaWxlcyBzZWN0aW9uXHJcbiAgaWYgKGhhbmRsZWRSZXNvdXJjZXMuZmlsZXMpIHtcclxuICAgIGhhbmRsZWRSZXNvdXJjZXMuZmlsZXMgPSBoYW5kbGVkUmVzb3VyY2VzLmZpbGVzLm1hcCgoaXRlbSkgPT4gaXRlbS50cmltKCkpO1xyXG4gICAgaWYgKCFoYW5kbGVkUmVzb3VyY2VzLmZpbGVzIHx8IGhhbmRsZWRSZXNvdXJjZXMuZmlsZXMubGVuZ3RoIDw9IDApIHtcclxuICAgICAgZGVsZXRlIGhhbmRsZWRSZXNvdXJjZXMuZmlsZXM7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICAvLyBWYWxpZGF0ZSBvcHRpb25cclxuICBoYW5kbGVkUmVzb3VyY2VzID0gdmFsaWRhdGVPcHRpb24oJ3Jlc291cmNlcycsIGhhbmRsZWRSZXNvdXJjZXMpO1xyXG5cclxuICAvLyBSZXR1cm4gcmVzb3VyY2VzXHJcbiAgcmV0dXJuIGhhbmRsZWRSZXNvdXJjZXM7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBIYW5kbGVzIGN1c3RvbSBjb2RlIHRvIGV4ZWN1dGUgaXQgc2FmZWx5LlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gX2hhbmRsZUN1c3RvbUNvZGVcclxuICpcclxuICogQHBhcmFtIHtzdHJpbmd9IGN1c3RvbUNvZGUgLSBUaGUgY3VzdG9tIGNvZGUgdG8gYmUgd3JhcHBlZC5cclxuICogQHBhcmFtIHtib29sZWFufSBhbGxvd0ZpbGVSZXNvdXJjZXMgLSBGbGFnIHRvIGFsbG93IGxvYWRpbmcgY29kZSBmcm9tIGEgZmlsZS5cclxuICogQHBhcmFtIHtib29sZWFufSBbaXNDYWxsYmFjaz1mYWxzZV0gLSBGbGFnIHRoYXQgaW5kaWNhdGVzIHRoZSByZXR1cm5lZCBjb2RlXHJcbiAqIG11c3QgYmUgaW4gYSBjYWxsYmFjayBmb3JtYXQuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHsoc3RyaW5nfG51bGwpfSBUaGUgd3JhcHBlZCBjdXN0b20gY29kZSBvciBudWxsIGlmIHdyYXBwaW5nIGZhaWxzLlxyXG4gKi9cclxuZnVuY3Rpb24gX2hhbmRsZUN1c3RvbUNvZGUoY3VzdG9tQ29kZSwgYWxsb3dGaWxlUmVzb3VyY2VzLCBpc0NhbGxiYWNrID0gZmFsc2UpIHtcclxuICBpZiAoY3VzdG9tQ29kZSAmJiB0eXBlb2YgY3VzdG9tQ29kZSA9PT0gJ3N0cmluZycpIHtcclxuICAgIGN1c3RvbUNvZGUgPSBjdXN0b21Db2RlLnRyaW0oKTtcclxuXHJcbiAgICBpZiAoY3VzdG9tQ29kZS5lbmRzV2l0aCgnLmpzJykpIHtcclxuICAgICAgLy8gTG9hZCBhIGZpbGUgaWYgdGhlIGZpbGUgcmVzb3VyY2VzIGFyZSBhbGxvd2VkXHJcbiAgICAgIHJldHVybiBhbGxvd0ZpbGVSZXNvdXJjZXNcclxuICAgICAgICA/IF9oYW5kbGVDdXN0b21Db2RlKFxyXG4gICAgICAgICAgICByZWFkRmlsZVN5bmMoZ2V0QWJzb2x1dGVQYXRoKGN1c3RvbUNvZGUpLCAndXRmOCcpLFxyXG4gICAgICAgICAgICBhbGxvd0ZpbGVSZXNvdXJjZXMsXHJcbiAgICAgICAgICAgIGlzQ2FsbGJhY2tcclxuICAgICAgICAgIClcclxuICAgICAgICA6IG51bGw7XHJcbiAgICB9IGVsc2UgaWYgKFxyXG4gICAgICAhaXNDYWxsYmFjayAmJlxyXG4gICAgICAoY3VzdG9tQ29kZS5zdGFydHNXaXRoKCdmdW5jdGlvbigpJykgfHxcclxuICAgICAgICBjdXN0b21Db2RlLnN0YXJ0c1dpdGgoJ2Z1bmN0aW9uICgpJykgfHxcclxuICAgICAgICBjdXN0b21Db2RlLnN0YXJ0c1dpdGgoJygpPT4nKSB8fFxyXG4gICAgICAgIGN1c3RvbUNvZGUuc3RhcnRzV2l0aCgnKCkgPT4nKSlcclxuICAgICkge1xyXG4gICAgICAvLyBUcmVhdCBhIGZ1bmN0aW9uIGFzIGEgc2VsZi1pbnZva2luZyBleHByZXNzaW9uXHJcbiAgICAgIHJldHVybiBgKCR7Y3VzdG9tQ29kZX0pKClgO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIE9yIHJldHVybiBhcyBhIHN0cmluZ2lmaWVkIGNvZGVcclxuICAgIHJldHVybiBjdXN0b21Db2RlLnJlcGxhY2UoLzskLywgJycpO1xyXG4gIH1cclxufVxyXG5cclxuLyoqXHJcbiAqIEhhbmRsZXMgdGhlIGxvYWRpbmcgYW5kIHZhbGlkYXRpb24gb2YgdGhlIGBnbG9iYWxPcHRpb25zYCBhbmQgYHRoZW1lT3B0aW9uc2BcclxuICogaW4gdGhlIGV4cG9ydCBvcHRpb25zLiBJZiB0aGUgb3B0aW9uIGlzIGEgc3RyaW5nIGFuZCByZWZlcmVuY2VzIGEgSlNPTiBmaWxlXHJcbiAqICh3aGVuIHRoZSBgYWxsb3dGaWxlUmVzb3VyY2VzYCBpcyBgdHJ1ZWApLCBpdCByZWFkcyBhbmQgcGFyc2VzIHRoZSBmaWxlLlxyXG4gKiBPdGhlcndpc2UsIGl0IGF0dGVtcHRzIHRvIHBhcnNlIHRoZSBzdHJpbmcgb3Igb2JqZWN0IGFzIEpTT04uIElmIGFueSBlcnJvcnNcclxuICogb2NjdXIgZHVyaW5nIHRoaXMgcHJvY2VzcywgdGhlIG9wdGlvbiBpcyBzZXQgdG8gYG51bGxgLiBJZiB0aGVyZSBpcyBhbiBlcnJvclxyXG4gKiBsb2FkaW5nIG9yIHBhcnNpbmcgdGhlIGBnbG9iYWxPcHRpb25zYCBvciBgdGhlbWVPcHRpb25zYCwgdGhlIGVycm9yIGlzIGxvZ2dlZFxyXG4gKiBhbmQgdGhlIG9wdGlvbiBpcyBzZXQgdG8gYG51bGxgLlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gX2hhbmRsZUdsb2JhbEFuZFRoZW1lXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBleHBvcnRPcHRpb25zIC0gVGhlIGNvbmZpZ3VyYXRpb24gb2JqZWN0IGNvbnRhaW5pbmcgYGV4cG9ydGBcclxuICogb3B0aW9ucy5cclxuICogQHBhcmFtIHtPYmplY3R9IGN1c3RvbUxvZ2ljT3B0aW9ucyAtIFRoZSBjb25maWd1cmF0aW9uIG9iamVjdCBjb250YWluaW5nXHJcbiAqIGBjdXN0b21Mb2dpY2Agb3B0aW9ucy5cclxuICovXHJcbmZ1bmN0aW9uIF9oYW5kbGVHbG9iYWxBbmRUaGVtZShleHBvcnRPcHRpb25zLCBjdXN0b21Mb2dpY09wdGlvbnMpIHtcclxuICAvLyBHZXQgdGhlIGBhbGxvd0ZpbGVSZXNvdXJjZXNgIGFuZCBgYWxsb3dDb2RlRXhlY3V0aW9uYCBmbGFnc1xyXG4gIGNvbnN0IHsgYWxsb3dGaWxlUmVzb3VyY2VzLCBhbGxvd0NvZGVFeGVjdXRpb24gfSA9IGN1c3RvbUxvZ2ljT3B0aW9ucztcclxuXHJcbiAgLy8gQ2hlY2sgdGhlIGBnbG9iYWxPcHRpb25zYCBhbmQgYHRoZW1lT3B0aW9uc2Agb3B0aW9uc1xyXG4gIFsnZ2xvYmFsT3B0aW9ucycsICd0aGVtZU9wdGlvbnMnXS5mb3JFYWNoKChvcHRpb25zTmFtZSkgPT4ge1xyXG4gICAgdHJ5IHtcclxuICAgICAgLy8gQ2hlY2sgaWYgdGhlIG9wdGlvbiBleGlzdHNcclxuICAgICAgaWYgKGV4cG9ydE9wdGlvbnNbb3B0aW9uc05hbWVdKSB7XHJcbiAgICAgICAgLy8gQ2hlY2sgaWYgaXQgaXMgYSBzdHJpbmcgYW5kIGEgZmlsZSBuYW1lIHdpdGggdGhlIGAuanNvbmAgZXh0ZW5zaW9uXHJcbiAgICAgICAgaWYgKFxyXG4gICAgICAgICAgYWxsb3dGaWxlUmVzb3VyY2VzICYmXHJcbiAgICAgICAgICB0eXBlb2YgZXhwb3J0T3B0aW9uc1tvcHRpb25zTmFtZV0gPT09ICdzdHJpbmcnICYmXHJcbiAgICAgICAgICBleHBvcnRPcHRpb25zW29wdGlvbnNOYW1lXS5lbmRzV2l0aCgnLmpzb24nKVxyXG4gICAgICAgICkge1xyXG4gICAgICAgICAgLy8gQ2hlY2sgaWYgdGhlIGZpbGUgY29udGVudCBjYW4gYmUgYSBjb25maWcsIGFuZCBzYXZlIGl0IGFzIGEgc3RyaW5nXHJcbiAgICAgICAgICBleHBvcnRPcHRpb25zW29wdGlvbnNOYW1lXSA9IGlzQWxsb3dlZENvbmZpZyhcclxuICAgICAgICAgICAgcmVhZEZpbGVTeW5jKGdldEFic29sdXRlUGF0aChleHBvcnRPcHRpb25zW29wdGlvbnNOYW1lXSksICd1dGY4JyksXHJcbiAgICAgICAgICAgIHRydWUsXHJcbiAgICAgICAgICAgIGFsbG93Q29kZUV4ZWN1dGlvblxyXG4gICAgICAgICAgKTtcclxuICAgICAgICB9IGVsc2Uge1xyXG4gICAgICAgICAgLy8gQ2hlY2sgaWYgdGhlIHZhbHVlIGNhbiBiZSBhIGNvbmZpZywgYW5kIHNhdmUgaXQgYXMgYSBzdHJpbmdcclxuICAgICAgICAgIGV4cG9ydE9wdGlvbnNbb3B0aW9uc05hbWVdID0gaXNBbGxvd2VkQ29uZmlnKFxyXG4gICAgICAgICAgICBleHBvcnRPcHRpb25zW29wdGlvbnNOYW1lXSxcclxuICAgICAgICAgICAgdHJ1ZSxcclxuICAgICAgICAgICAgYWxsb3dDb2RlRXhlY3V0aW9uXHJcbiAgICAgICAgICApO1xyXG4gICAgICAgIH1cclxuXHJcbiAgICAgICAgLy8gVmFsaWRhdGUgdGhlIG9wdGlvblxyXG4gICAgICAgIGV4cG9ydE9wdGlvbnNbb3B0aW9uc05hbWVdID0gdmFsaWRhdGVPcHRpb24oXHJcbiAgICAgICAgICBvcHRpb25zTmFtZSxcclxuICAgICAgICAgIGV4cG9ydE9wdGlvbnNbb3B0aW9uc05hbWVdXHJcbiAgICAgICAgKTtcclxuICAgICAgfVxyXG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICAgbG9nV2l0aFN0YWNrKFxyXG4gICAgICAgIDIsXHJcbiAgICAgICAgZXJyb3IsXHJcbiAgICAgICAgYFtjaGFydF0gVGhlIFxcYCR7b3B0aW9uc05hbWV9XFxgIGNhbm5vdCBiZSBsb2FkZWQuYFxyXG4gICAgICApO1xyXG5cclxuICAgICAgLy8gSW4gY2FzZSBvZiBhbiBlcnJvciwgc2V0IHRoZSBvcHRpb24gd2l0aCBudWxsXHJcbiAgICAgIGV4cG9ydE9wdGlvbnNbb3B0aW9uc05hbWVdID0gbnVsbDtcclxuICAgIH1cclxuICB9KTtcclxuXHJcbiAgLy8gQ2hlY2sgaWYgdGhlcmUgaXMgdGhlIGBnbG9iYWxPcHRpb25zYCBwcmVzZW50XHJcbiAgaWYgKFtudWxsLCB1bmRlZmluZWRdLmluY2x1ZGVzKGV4cG9ydE9wdGlvbnMuZ2xvYmFsT3B0aW9ucykpIHtcclxuICAgIGxvZygzLCAnW2NoYXJ0XSBObyB2YWx1ZSBmb3IgdGhlIGBnbG9iYWxPcHRpb25zYCBvcHRpb24gZm91bmQuJyk7XHJcbiAgfVxyXG5cclxuICAvLyBDaGVjayBpZiB0aGVyZSBpcyB0aGUgYHRoZW1lT3B0aW9uc2AgcHJlc2VudFxyXG4gIGlmIChbbnVsbCwgdW5kZWZpbmVkXS5pbmNsdWRlcyhleHBvcnRPcHRpb25zLnRoZW1lT3B0aW9ucykpIHtcclxuICAgIGxvZygzLCAnW2NoYXJ0XSBObyB2YWx1ZSBmb3IgdGhlIGB0aGVtZU9wdGlvbnNgIG9wdGlvbiBmb3VuZC4nKTtcclxuICB9XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBWYWxpZGF0ZXMgdGhlIHNpemUgb2YgdGhlIGRhdGEgZm9yIHRoZSBleHBvcnQgcHJvY2VzcyBhZ2FpbnN0IGEgZml4ZWQgbGltaXRcclxuICogb2YgMTAwTUIuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBfY2hlY2tEYXRhU2l6ZVxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gaW1hZ2VPcHRpb25zIC0gVGhlIGRhdGEgb2JqZWN0LCB3aGljaCBpbmNsdWRlcyBvcHRpb25zIGZyb21cclxuICogdGhlIGBleHBvcnRgIGFuZCBgY3VzdG9tTG9naWNgIHNlY3Rpb25zIGFuZCB3aWxsIGJlIHNlbnQgdG8gYSBQdXBwZXRlZXIgcGFnZS5cclxuICpcclxuICogQHRocm93cyB7RXhwb3J0RXJyb3J9IFRocm93cyBhbiBgRXhwb3J0RXJyb3JgIGlmIHRoZSBzaXplIG9mIHRoZSBkYXRhIGZvclxyXG4gKiB0aGUgZXhwb3J0IHByb2Nlc3Mgb2JqZWN0IGV4Y2VlZHMgdGhlIDEwME1CIGxpbWl0LlxyXG4gKi9cclxuZnVuY3Rpb24gX2NoZWNrRGF0YVNpemUoaW1hZ2VPcHRpb25zKSB7XHJcbiAgLy8gU2V0IHRoZSBmaXhlZCBkYXRhIGxpbWl0ICgxMDBNQikgZm9yIHRoZSBkZXYtdG9vbHMgcHJvdG9jb2xcclxuICBjb25zdCBkYXRhTGltaXQgPSAxMDAgKiAxMDI0ICogMTAyNDtcclxuXHJcbiAgLy8gR2V0IHRoZSBzaXplIG9mIHRoZSBkYXRhXHJcbiAgY29uc3QgdG90YWxTaXplID0gQnVmZmVyLmJ5dGVMZW5ndGgoSlNPTi5zdHJpbmdpZnkoaW1hZ2VPcHRpb25zKSwgJ3V0Zi04Jyk7XHJcblxyXG4gIC8vIExvZyB0aGUgc2l6ZSBpbiBNQlxyXG4gIGxvZyhcclxuICAgIDMsXHJcbiAgICBgW2NoYXJ0XSBUaGUgY3VycmVudCB0b3RhbCBzaXplIG9mIHRoZSBkYXRhIGZvciB0aGUgZXhwb3J0IHByb2Nlc3MgaXMgYXJvdW5kICR7KFxyXG4gICAgICB0b3RhbFNpemUgL1xyXG4gICAgICAoMTAyNCAqIDEwMjQpXHJcbiAgICApLnRvRml4ZWQoMil9TUIuYFxyXG4gICk7XHJcblxyXG4gIC8vIENoZWNrIHRoZSBzaXplIG9mIGRhdGEgYmVmb3JlIHBhc3NpbmcgdG8gYSBwYWdlXHJcbiAgaWYgKHRvdGFsU2l6ZSA+PSBkYXRhTGltaXQpIHtcclxuICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcihcclxuICAgICAgYFtjaGFydF0gVGhlIGRhdGEgZm9yIHRoZSBleHBvcnQgcHJvY2VzcyBleGNlZWRzIDEwME1CIGxpbWl0LmBcclxuICAgICk7XHJcbiAgfVxyXG59XHJcblxyXG5leHBvcnQgZGVmYXVsdCB7XHJcbiAgc2luZ2xlRXhwb3J0LFxyXG4gIGJhdGNoRXhwb3J0LFxyXG4gIHN0YXJ0RXhwb3J0LFxyXG4gIGdldEFsbG93Q29kZUV4ZWN1dGlvbixcclxuICBzZXRBbGxvd0NvZGVFeGVjdXRpb25cclxufTtcclxuIiwiLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcclxuXHJcbkhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlclxyXG5cclxuQ29weXJpZ2h0IChjKSAyMDE2LTIwMjUsIEhpZ2hzb2Z0XHJcblxyXG5MaWNlbmNlZCB1bmRlciB0aGUgTUlUIGxpY2VuY2UuXHJcblxyXG5BZGRpdGlvbmFsbHkgYSB2YWxpZCBIaWdoY2hhcnRzIGxpY2Vuc2UgaXMgcmVxdWlyZWQgZm9yIHVzZS5cclxuXHJcblNlZSBMSUNFTlNFIGZpbGUgaW4gcm9vdCBmb3IgZGV0YWlscy5cclxuXHJcbioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXHJcblxyXG4vKipcclxuICogQG92ZXJ2aWV3IFRoaXMgbW9kdWxlIHByb3ZpZGVzIHV0aWxpdHkgZnVuY3Rpb25zIGZvciBtYW5hZ2luZyBpbnRlcnZhbHNcclxuICogYW5kIHRpbWVvdXRzIGluIGEgY2VudHJhbGl6ZWQgbWFubmVyLiBJdCBtYWludGFpbnMgYSByZWdpc3RyeSBvZiBhbGwgYWN0aXZlXHJcbiAqIHRpbWVycyBhbmQgYWxsb3dzIGZvciB0aGVpciBlZmZpY2llbnQgY2xlYW51cCB3aGVuIG5lZWRlZCB0byBhdm9pZCBwb3RlbnRpYWxcclxuICogbWVtb3J5IGxlYWtzLCB1bmludGVuZGVkIGJlaGF2aW9yIG9yIGEgcHJvY2VzcyBmcm9tIGJlaW5nIHN0b3BwZWQuXHJcbiAqL1xyXG5cclxuaW1wb3J0IHsgbG9nIH0gZnJvbSAnLi9sb2dnZXIuanMnO1xyXG5cclxuLy8gQXJyYXkgdGhhdCBjb250YWlucyBpZHMgb2YgYWxsIG9uZ29pbmcgaW50ZXJ2YWxzIGFuZCB0aW1lb3V0c1xyXG5jb25zdCB0aW1lcklkcyA9IFtdO1xyXG5cclxuLyoqXHJcbiAqIEFkZHMgaWQgb2YgdGhlIGBzZXRJbnRlcnZhbGAgb3IgYHNldFRpbWVvdXRgIGFuZCB0byB0aGUgYHRpbWVySWRzYCBhcnJheS5cclxuICpcclxuICogQGZ1bmN0aW9uIGFkZFRpbWVyXHJcbiAqXHJcbiAqIEBwYXJhbSB7Tm9kZUpTLlRpbWVvdXR9IGlkIC0gSWQgb2YgYW4gaW50ZXJ2YWwgb3IgYSB0aW1lb3V0LlxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIGFkZFRpbWVyKGlkKSB7XHJcbiAgdGltZXJJZHMucHVzaChpZCk7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBDbGVhcnMgYWxsIG9mIG9uZ29pbmcgaW50ZXJ2YWxzIGFuZCB0aW1lb3V0cyBieSBpZHMgZ2F0aGVyZWRcclxuICogaW4gdGhlIGB0aW1lcklkc2AgYXJyYXkuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBjbGVhckFsbFRpbWVyc1xyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIGNsZWFyQWxsVGltZXJzKCkge1xyXG4gIGxvZyg0LCBgW3RpbWVyXSBDbGVhcmluZyBhbGwgcmVnaXN0ZXJlZCBpbnRlcnZhbHMgYW5kIHRpbWVvdXRzLmApO1xyXG4gIGZvciAoY29uc3QgaWQgb2YgdGltZXJJZHMpIHtcclxuICAgIGNsZWFySW50ZXJ2YWwoaWQpO1xyXG4gICAgY2xlYXJUaW1lb3V0KGlkKTtcclxuICB9XHJcbn1cclxuXHJcbmV4cG9ydCBkZWZhdWx0IHtcclxuICBhZGRUaW1lcixcclxuICBjbGVhckFsbFRpbWVyc1xyXG59O1xyXG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxyXG5cclxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXHJcblxyXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNSwgSGlnaHNvZnRcclxuXHJcbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cclxuXHJcbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxyXG5cclxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxyXG5cclxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cclxuXHJcbi8qKlxyXG4gKiBAb3ZlcnZpZXcgUHJvdmlkZXMgbWlkZGxld2FyZSBmdW5jdGlvbnMgZm9yIGxvZ2dpbmcgZXJyb3JzIHdpdGggc3RhY2sgdHJhY2VzXHJcbiAqIGFuZCBoYW5kbGluZyBlcnJvciByZXNwb25zZXMgaW4gYW4gRXhwcmVzcyBhcHBsaWNhdGlvbi5cclxuICovXHJcblxyXG5pbXBvcnQgeyBnZXRPcHRpb25zIH0gZnJvbSAnLi4vLi4vY29uZmlnLmpzJztcclxuaW1wb3J0IHsgbG9nV2l0aFN0YWNrIH0gZnJvbSAnLi4vLi4vbG9nZ2VyLmpzJztcclxuXHJcbi8qKlxyXG4gKiBNaWRkbGV3YXJlIGZvciBsb2dnaW5nIGVycm9ycyB3aXRoIHN0YWNrIHRyYWNlIGFuZCBoYW5kbGluZyBlcnJvciByZXNwb25zZS5cclxuICpcclxuICogQGZ1bmN0aW9uIGxvZ0Vycm9yTWlkZGxld2FyZVxyXG4gKlxyXG4gKiBAcGFyYW0ge0Vycm9yfSBlcnJvciAtIFRoZSBlcnJvciBvYmplY3QuXHJcbiAqIEBwYXJhbSB7RXhwcmVzcy5SZXF1ZXN0fSByZXF1ZXN0IC0gVGhlIEV4cHJlc3MgcmVxdWVzdCBvYmplY3QuXHJcbiAqIEBwYXJhbSB7RXhwcmVzcy5SZXNwb25zZX0gcmVzcG9uc2UgLSBUaGUgRXhwcmVzcyByZXNwb25zZSBvYmplY3QuXHJcbiAqIEBwYXJhbSB7RnVuY3Rpb259IG5leHQgLSBUaGUgbmV4dCBtaWRkbGV3YXJlIGZ1bmN0aW9uLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7dW5kZWZpbmVkfSBUaGUgY2FsbCB0byB0aGUgbmV4dCBtaWRkbGV3YXJlIGZ1bmN0aW9uIHdpdGhcclxuICogdGhlIHBhc3NlZCBlcnJvci5cclxuICovXHJcbmZ1bmN0aW9uIGxvZ0Vycm9yTWlkZGxld2FyZShlcnJvciwgcmVxdWVzdCwgcmVzcG9uc2UsIG5leHQpIHtcclxuICAvLyBEaXNwbGF5IHRoZSBlcnJvciB3aXRoIHN0YWNrIGluIGEgY29ycmVjdCBmb3JtYXRcclxuICBsb2dXaXRoU3RhY2soMSwgZXJyb3IpO1xyXG5cclxuICAvLyBEZWxldGUgdGhlIHN0YWNrIGZvciB0aGUgZW52aXJvbm1lbnQgb3RoZXIgdGhhbiB0aGUgZGV2ZWxvcG1lbnRcclxuICBpZiAoZ2V0T3B0aW9ucygpLm90aGVyLm5vZGVFbnYgIT09ICdkZXZlbG9wbWVudCcpIHtcclxuICAgIGRlbGV0ZSBlcnJvci5zdGFjaztcclxuICB9XHJcblxyXG4gIC8vIENhbGwgdGhlIGByZXR1cm5FcnJvck1pZGRsZXdhcmVgIG1pZGRsZXdhcmVcclxuICByZXR1cm4gbmV4dChlcnJvcik7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBNaWRkbGV3YXJlIGZvciByZXR1cm5pbmcgZXJyb3IgcmVzcG9uc2UuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiByZXR1cm5FcnJvck1pZGRsZXdhcmVcclxuICpcclxuICogQHBhcmFtIHtFcnJvcn0gZXJyb3IgLSBUaGUgZXJyb3Igb2JqZWN0LlxyXG4gKiBAcGFyYW0ge0V4cHJlc3MuUmVxdWVzdH0gcmVxdWVzdCAtIFRoZSBFeHByZXNzIHJlcXVlc3Qgb2JqZWN0LlxyXG4gKiBAcGFyYW0ge0V4cHJlc3MuUmVzcG9uc2V9IHJlc3BvbnNlIC0gVGhlIEV4cHJlc3MgcmVzcG9uc2Ugb2JqZWN0LlxyXG4gKiBAcGFyYW0ge0Z1bmN0aW9ufSBuZXh0IC0gVGhlIG5leHQgbWlkZGxld2FyZSBmdW5jdGlvbi5cclxuICovXHJcbmZ1bmN0aW9uIHJldHVybkVycm9yTWlkZGxld2FyZShlcnJvciwgcmVxdWVzdCwgcmVzcG9uc2UsIG5leHQpIHtcclxuICAvLyBHYXRoZXIgYWxsIHJlcXVpZWQgaW5mb3JtYXRpb24gZm9yIHRoZSByZXNwb25zZVxyXG4gIGNvbnN0IHsgbWVzc2FnZSwgc3RhY2sgfSA9IGVycm9yO1xyXG5cclxuICAvLyBVc2UgdGhlIGVycm9yJ3Mgc3RhdHVzIGNvZGUgb3IgdGhlIGRlZmF1bHQgNDAwXHJcbiAgY29uc3Qgc3RhdHVzQ29kZSA9IGVycm9yLnN0YXR1c0NvZGUgfHwgNDAwO1xyXG5cclxuICAvLyBTZXQgYW5kIHJldHVybiByZXNwb25zZVxyXG4gIHJlc3BvbnNlLnN0YXR1cyhzdGF0dXNDb2RlKS5qc29uKHsgc3RhdHVzQ29kZSwgbWVzc2FnZSwgc3RhY2sgfSk7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBBZGRzIHRoZSBlcnJvciBtaWRkbGV3YXJlcyB0byB0aGUgcGFzc2VkIGV4cHJlc3MgYXBwIGluc3RhbmNlLlxyXG4gKlxyXG4gKiBAcGFyYW0ge0V4cHJlc3N9IGFwcCAtIFRoZSBFeHByZXNzIGFwcCBpbnN0YW5jZS5cclxuICovXHJcbmV4cG9ydCBkZWZhdWx0IGZ1bmN0aW9uIGVycm9yTWlkZGxld2FyZShhcHApIHtcclxuICAvLyBBZGQgbG9nIGVycm9yIG1pZGRsZXdhcmVcclxuICBhcHAudXNlKGxvZ0Vycm9yTWlkZGxld2FyZSk7XHJcblxyXG4gIC8vIEFkZCBzZXQgc3RhdHVzIGFuZCByZXR1cm4gZXJyb3IgbWlkZGxld2FyZVxyXG4gIGFwcC51c2UocmV0dXJuRXJyb3JNaWRkbGV3YXJlKTtcclxufVxyXG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxyXG5cclxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXHJcblxyXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNSwgSGlnaHNvZnRcclxuXHJcbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cclxuXHJcbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxyXG5cclxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxyXG5cclxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cclxuXHJcbi8qKlxyXG4gKiBAb3ZlcnZpZXcgUHJvdmlkZXMgbWlkZGxld2FyZSBmdW5jdGlvbnMgZm9yIGNvbmZpZ3VyaW5nIGFuZCBlbmFibGluZyByYXRlXHJcbiAqIGxpbWl0aW5nIGluIGFuIEV4cHJlc3MgYXBwbGljYXRpb24uXHJcbiAqL1xyXG5cclxuaW1wb3J0IHJhdGVMaW1pdCBmcm9tICdleHByZXNzLXJhdGUtbGltaXQnO1xyXG5cclxuaW1wb3J0IHsgbG9nIH0gZnJvbSAnLi4vLi4vbG9nZ2VyLmpzJztcclxuXHJcbmltcG9ydCBFeHBvcnRFcnJvciBmcm9tICcuLi8uLi9lcnJvcnMvRXhwb3J0RXJyb3IuanMnO1xyXG5cclxuLyoqXHJcbiAqIE1pZGRsZXdhcmUgZm9yIGVuYWJsaW5nIHJhdGUgbGltaXRpbmcgb24gdGhlIHNwZWNpZmllZCBFeHByZXNzIGFwcC5cclxuICpcclxuICogQHBhcmFtIHtFeHByZXNzfSBhcHAgLSBUaGUgRXhwcmVzcyBhcHAgaW5zdGFuY2UuXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSByYXRlTGltaXRpbmdPcHRpb25zIC0gVGhlIGNvbmZpZ3VyYXRpb24gb2JqZWN0IGNvbnRhaW5pbmdcclxuICogYHJhdGVMaW1pdGluZ2Agb3B0aW9ucy5cclxuICpcclxuICogQHRocm93cyB7RXhwb3J0RXJyb3J9IFRocm93cyBhbiBgRXhwb3J0RXJyb3JgIGlmIGNvdWxkIG5vdCBjb25maWd1cmUgYW5kIHNldFxyXG4gKiB0aGUgcmF0ZSBsaW1pdGluZyBvcHRpb25zLlxyXG4gKi9cclxuZXhwb3J0IGRlZmF1bHQgZnVuY3Rpb24gcmF0ZUxpbWl0aW5nTWlkZGxld2FyZShhcHAsIHJhdGVMaW1pdGluZ09wdGlvbnMpIHtcclxuICB0cnkge1xyXG4gICAgLy8gQ2hlY2sgaWYgdGhlIHJhdGUgbGltaXRpbmcgaXMgZW5hYmxlZCBhbmQgdGhlIGFwcCBleGlzdHNcclxuICAgIGlmIChhcHAgJiYgcmF0ZUxpbWl0aW5nT3B0aW9ucy5lbmFibGUpIHtcclxuICAgICAgY29uc3QgbWVzc2FnZSA9XHJcbiAgICAgICAgJ1RvbyBtYW55IHJlcXVlc3RzLCB5b3UgaGF2ZSBiZWVuIHJhdGUgbGltaXRlZC4gUGxlYXNlIHRyeSBhZ2FpbiBsYXRlci4nO1xyXG5cclxuICAgICAgLy8gT3B0aW9ucyBmb3IgdGhlIHJhdGUgbGltaXRlclxyXG4gICAgICBjb25zdCByYXRlT3B0aW9ucyA9IHtcclxuICAgICAgICB3aW5kb3c6IHJhdGVMaW1pdGluZ09wdGlvbnMud2luZG93IHx8IDEsXHJcbiAgICAgICAgbWF4UmVxdWVzdHM6IHJhdGVMaW1pdGluZ09wdGlvbnMubWF4UmVxdWVzdHMgfHwgMzAsXHJcbiAgICAgICAgZGVsYXk6IHJhdGVMaW1pdGluZ09wdGlvbnMuZGVsYXkgfHwgMCxcclxuICAgICAgICB0cnVzdFByb3h5OiByYXRlTGltaXRpbmdPcHRpb25zLnRydXN0UHJveHkgfHwgZmFsc2UsXHJcbiAgICAgICAgc2tpcEtleTogcmF0ZUxpbWl0aW5nT3B0aW9ucy5za2lwS2V5IHx8IG51bGwsXHJcbiAgICAgICAgc2tpcFRva2VuOiByYXRlTGltaXRpbmdPcHRpb25zLnNraXBUb2tlbiB8fCBudWxsXHJcbiAgICAgIH07XHJcblxyXG4gICAgICAvLyBTZXQgaWYgYmVoaW5kIGEgcHJveHlcclxuICAgICAgaWYgKHJhdGVPcHRpb25zLnRydXN0UHJveHkpIHtcclxuICAgICAgICBhcHAuZW5hYmxlKCd0cnVzdCBwcm94eScpO1xyXG4gICAgICB9XHJcblxyXG4gICAgICAvLyBDcmVhdGUgYSBsaW1pdGVyXHJcbiAgICAgIGNvbnN0IGxpbWl0ZXIgPSByYXRlTGltaXQoe1xyXG4gICAgICAgIC8vIFRpbWUgZnJhbWUgZm9yIHdoaWNoIHJlcXVlc3RzIGFyZSBjaGVja2VkIGFuZCByZW1lbWJlcmVkXHJcbiAgICAgICAgd2luZG93TXM6IHJhdGVPcHRpb25zLndpbmRvdyAqIDYwICogMTAwMCxcclxuICAgICAgICAvLyBMaW1pdCBlYWNoIElQIHRvIDEwMCByZXF1ZXN0cyBwZXIgYHdpbmRvd01zYFxyXG4gICAgICAgIGxpbWl0OiByYXRlT3B0aW9ucy5tYXhSZXF1ZXN0cyxcclxuICAgICAgICAvLyBEaXNhYmxlIGRlbGF5aW5nLCBmdWxsIHNwZWVkIHVudGlsIHRoZSBtYXggbGltaXQgaXMgcmVhY2hlZFxyXG4gICAgICAgIGRlbGF5TXM6IHJhdGVPcHRpb25zLmRlbGF5LFxyXG4gICAgICAgIGhhbmRsZXI6IChyZXF1ZXN0LCByZXNwb25zZSkgPT4ge1xyXG4gICAgICAgICAgcmVzcG9uc2UuZm9ybWF0KHtcclxuICAgICAgICAgICAganNvbjogKCkgPT4ge1xyXG4gICAgICAgICAgICAgIHJlc3BvbnNlLnN0YXR1cyg0MjkpLnNlbmQoeyBtZXNzYWdlIH0pO1xyXG4gICAgICAgICAgICB9LFxyXG4gICAgICAgICAgICBkZWZhdWx0OiAoKSA9PiB7XHJcbiAgICAgICAgICAgICAgcmVzcG9uc2Uuc3RhdHVzKDQyOSkuc2VuZChtZXNzYWdlKTtcclxuICAgICAgICAgICAgfVxyXG4gICAgICAgICAgfSk7XHJcbiAgICAgICAgfSxcclxuICAgICAgICBza2lwOiAocmVxdWVzdCkgPT4ge1xyXG4gICAgICAgICAgLy8gQWxsb3cgYnlwYXNzaW5nIHRoZSBsaW1pdGVyIGlmIGEgdmFsaWQga2V5L3Rva2VuIGhhcyBiZWVuIHNlbnRcclxuICAgICAgICAgIGlmIChcclxuICAgICAgICAgICAgcmF0ZU9wdGlvbnMuc2tpcEtleSAhPT0gbnVsbCAmJlxyXG4gICAgICAgICAgICByYXRlT3B0aW9ucy5za2lwVG9rZW4gIT09IG51bGwgJiZcclxuICAgICAgICAgICAgcmVxdWVzdC5xdWVyeS5rZXkgPT09IHJhdGVPcHRpb25zLnNraXBLZXkgJiZcclxuICAgICAgICAgICAgcmVxdWVzdC5xdWVyeS5hY2Nlc3NfdG9rZW4gPT09IHJhdGVPcHRpb25zLnNraXBUb2tlblxyXG4gICAgICAgICAgKSB7XHJcbiAgICAgICAgICAgIGxvZyg0LCAnW3JhdGUgbGltaXRpbmddIFNraXBwaW5nIHJhdGUgbGltaXRlci4nKTtcclxuICAgICAgICAgICAgcmV0dXJuIHRydWU7XHJcbiAgICAgICAgICB9XHJcbiAgICAgICAgICByZXR1cm4gZmFsc2U7XHJcbiAgICAgICAgfVxyXG4gICAgICB9KTtcclxuXHJcbiAgICAgIC8vIFVzZSBhIGxpbWl0ZXIgYXMgYSBtaWRkbGV3YXJlXHJcbiAgICAgIGFwcC51c2UobGltaXRlcik7XHJcblxyXG4gICAgICBsb2coXHJcbiAgICAgICAgMyxcclxuICAgICAgICBgW3JhdGUgbGltaXRpbmddIEVuYWJsZWQgcmF0ZSBsaW1pdGluZyB3aXRoICR7cmF0ZU9wdGlvbnMubWF4UmVxdWVzdHN9IHJlcXVlc3RzIHBlciAke3JhdGVPcHRpb25zLndpbmRvd30gbWludXRlIGZvciBlYWNoIElQLCB0cnVzdGluZyBwcm94eTogJHtyYXRlT3B0aW9ucy50cnVzdFByb3h5fS5gXHJcbiAgICAgICk7XHJcbiAgICB9XHJcbiAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcihcclxuICAgICAgJ1tyYXRlIGxpbWl0aW5nXSBDb3VsZCBub3QgY29uZmlndXJlIGFuZCBzZXQgdGhlIHJhdGUgbGltaXRpbmcgb3B0aW9ucy4nLFxyXG4gICAgICA1MDBcclxuICAgICkuc2V0RXJyb3IoZXJyb3IpO1xyXG4gIH1cclxufVxyXG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxyXG5cclxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXHJcblxyXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNSwgSGlnaHNvZnRcclxuXHJcbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cclxuXHJcbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxyXG5cclxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxyXG5cclxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cclxuXHJcbi8qKlxyXG4gKiBAb3ZlcnZpZXcgUHJvdmlkZXMgbWlkZGxld2FyZSBmdW5jdGlvbnMgZm9yIHZhbGlkYXRpbmcgaW5jb21pbmcgSFRUUCByZXF1ZXN0c1xyXG4gKiBpbiBhbiBFeHByZXNzIGFwcGxpY2F0aW9uLiBUaGlzIG1vZHVsZSBlbnN1cmVzIHRoYXQgcmVxdWVzdHMgY29udGFpblxyXG4gKiBhcHByb3ByaWF0ZSBjb250ZW50IHR5cGVzIGFuZCB2YWxpZCByZXF1ZXN0IGJvZGllcywgaW5jbHVkaW5nIHByb3BlciBKU09OXHJcbiAqIHN0cnVjdHVyZXMgYW5kIGNoYXJ0IGRhdGEgZm9yIGV4cG9ydHMuIEl0IGNoZWNrcyBmb3IgcG90ZW50aWFsIGlzc3VlcyBzdWNoXHJcbiAqIGFzIG1pc3Npbmcgb3IgbWFsZm9ybWVkIGRhdGEsIHByaXZhdGUgcmFuZ2UgVVJMcyBpbiBTVkcgcGF5bG9hZHMsIGFuZCBhbGxvd3NcclxuICogZm9yIGZsZXhpYmxlIG9wdGlvbnMgdmFsaWRhdGlvbi4gVGhlIG1pZGRsZXdhcmUgbG9ncyBkZXRhaWxlZCBpbmZvcm1hdGlvblxyXG4gKiBhbmQgaGFuZGxlcyBlcnJvcnMgcmVsYXRlZCB0byBpbmNvcnJlY3QgcGF5bG9hZHMsIGNoYXJ0IGRhdGEsIGFuZCBwcml2YXRlIFVSTFxyXG4gKiB1c2FnZS5cclxuICovXHJcblxyXG5pbXBvcnQgeyB2NCBhcyB1dWlkIH0gZnJvbSAndXVpZCc7XHJcblxyXG5pbXBvcnQgeyBnZXRBbGxvd0NvZGVFeGVjdXRpb24gfSBmcm9tICcuLi8uLi9jaGFydC5qcyc7XHJcbmltcG9ydCB7IGlzQWxsb3dlZENvbmZpZyB9IGZyb20gJy4uLy4uL2NvbmZpZy5qcyc7XHJcbmltcG9ydCB7IGxvZyB9IGZyb20gJy4uLy4uL2xvZ2dlci5qcyc7XHJcbmltcG9ydCB7IGlzT2JqZWN0RW1wdHksIGlzUHJpdmF0ZVJhbmdlVXJsRm91bmQgfSBmcm9tICcuLi8uLi91dGlscy5qcyc7XHJcblxyXG5pbXBvcnQgRXhwb3J0RXJyb3IgZnJvbSAnLi4vLi4vZXJyb3JzL0V4cG9ydEVycm9yLmpzJztcclxuXHJcbi8qKlxyXG4gKiBNaWRkbGV3YXJlIGZvciB2YWxpZGF0aW5nIHRoZSBjb250ZW50LXR5cGUgaGVhZGVyLlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gY29udGVudFR5cGVNaWRkbGV3YXJlXHJcbiAqXHJcbiAqIEBwYXJhbSB7RXhwcmVzcy5SZXF1ZXN0fSByZXF1ZXN0IC0gVGhlIEV4cHJlc3MgcmVxdWVzdCBvYmplY3QuXHJcbiAqIEBwYXJhbSB7RXhwcmVzcy5SZXNwb25zZX0gcmVzcG9uc2UgLSBUaGUgRXhwcmVzcyByZXNwb25zZSBvYmplY3QuXHJcbiAqIEBwYXJhbSB7RnVuY3Rpb259IG5leHQgLSBUaGUgbmV4dCBtaWRkbGV3YXJlIGZ1bmN0aW9uLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7dW5kZWZpbmVkfSBUaGUgY2FsbCB0byB0aGUgbmV4dCBtaWRkbGV3YXJlIGZ1bmN0aW9uLlxyXG4gKlxyXG4gKiBAdGhyb3dzIHtFeHBvcnRFcnJvcn0gVGhyb3dzIGFuIGBFeHBvcnRFcnJvcmAgaWYgdGhlIGNvbnRlbnQtdHlwZVxyXG4gKiBpcyBub3QgY29ycmVjdC5cclxuICovXHJcbmZ1bmN0aW9uIGNvbnRlbnRUeXBlTWlkZGxld2FyZShyZXF1ZXN0LCByZXNwb25zZSwgbmV4dCkge1xyXG4gIHRyeSB7XHJcbiAgICAvLyBHZXQgdGhlIGNvbnRlbnQgdHlwZSBoZWFkZXJcclxuICAgIGNvbnN0IGNvbnRlbnRUeXBlID0gcmVxdWVzdC5oZWFkZXJzWydjb250ZW50LXR5cGUnXSB8fCAnJztcclxuXHJcbiAgICAvLyBBbGxvdyBvbmx5IEpTT04sIFVSTC1lbmNvZGVkIGFuZCBmb3JtIGRhdGEgd2l0aG91dCBmaWxlcyB0eXBlcyBvZiBkYXRhXHJcbiAgICBpZiAoXHJcbiAgICAgICFjb250ZW50VHlwZS5pbmNsdWRlcygnYXBwbGljYXRpb24vanNvbicpICYmXHJcbiAgICAgICFjb250ZW50VHlwZS5pbmNsdWRlcygnYXBwbGljYXRpb24veC13d3ctZm9ybS11cmxlbmNvZGVkJykgJiZcclxuICAgICAgIWNvbnRlbnRUeXBlLmluY2x1ZGVzKCdtdWx0aXBhcnQvZm9ybS1kYXRhJylcclxuICAgICkge1xyXG4gICAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoXHJcbiAgICAgICAgJ1t2YWxpZGF0aW9uXSBDb250ZW50LVR5cGUgbXVzdCBiZSBhcHBsaWNhdGlvbi9qc29uLCBhcHBsaWNhdGlvbi94LXd3dy1mb3JtLXVybGVuY29kZWQsIG9yIG11bHRpcGFydC9mb3JtLWRhdGEuJyxcclxuICAgICAgICA0MTVcclxuICAgICAgKTtcclxuICAgIH1cclxuXHJcbiAgICAvLyBDYWxsIHRoZSBgcmVxdWVzdEJvZHlNaWRkbGV3YXJlYCBtaWRkbGV3YXJlXHJcbiAgICByZXR1cm4gbmV4dCgpO1xyXG4gIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICByZXR1cm4gbmV4dChlcnJvcik7XHJcbiAgfVxyXG59XHJcblxyXG4vKipcclxuICogTWlkZGxld2FyZSBmb3IgdmFsaWRhdGluZyB0aGUgcmVxdWVzdCdzIGJvZHkuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiByZXF1ZXN0Qm9keU1pZGRsZXdhcmVcclxuICpcclxuICogQHBhcmFtIHtFeHByZXNzLlJlcXVlc3R9IHJlcXVlc3QgLSBUaGUgRXhwcmVzcyByZXF1ZXN0IG9iamVjdC5cclxuICogQHBhcmFtIHtFeHByZXNzLlJlc3BvbnNlfSByZXNwb25zZSAtIFRoZSBFeHByZXNzIHJlc3BvbnNlIG9iamVjdC5cclxuICogQHBhcmFtIHtGdW5jdGlvbn0gbmV4dCAtIFRoZSBuZXh0IG1pZGRsZXdhcmUgZnVuY3Rpb24uXHJcbiAqXHJcbiAqIEByZXR1cm5zIHt1bmRlZmluZWR9IFRoZSBjYWxsIHRvIHRoZSBuZXh0IG1pZGRsZXdhcmUgZnVuY3Rpb24uXHJcbiAqXHJcbiAqIEB0aHJvd3Mge0V4cG9ydEVycm9yfSBUaHJvd3MgYW4gYEV4cG9ydEVycm9yYCBpZiB0aGUgYm9keSBpcyBub3QgY29ycmVjdC5cclxuICogQHRocm93cyB7RXhwb3J0RXJyb3J9IFRocm93cyBhbiBgRXhwb3J0RXJyb3JgIGlmIHRoZSBjaGFydCBkYXRhIGZyb20gdGhlIGJvZHlcclxuICogaXMgbm90IGNvcnJlY3QuXHJcbiAqIEB0aHJvd3Mge0V4cG9ydEVycm9yfSBUaHJvd3MgYW4gYEV4cG9ydEVycm9yYCBpbiBjYXNlIG9mIHRoZSBwcml2YXRlIHJhbmdlXHJcbiAqIHVybCBlcnJvci5cclxuICovXHJcbmZ1bmN0aW9uIHJlcXVlc3RCb2R5TWlkZGxld2FyZShyZXF1ZXN0LCByZXNwb25zZSwgbmV4dCkge1xyXG4gIHRyeSB7XHJcbiAgICAvLyBHZXQgdGhlIHJlcXVlc3QgYm9keVxyXG4gICAgY29uc3QgYm9keSA9IHJlcXVlc3QuYm9keTtcclxuXHJcbiAgICAvLyBDcmVhdGUgYSB1bmlxdWUgSUQgZm9yIGEgcmVxdWVzdFxyXG4gICAgY29uc3QgcmVxdWVzdElkID0gdXVpZCgpO1xyXG5cclxuICAgIC8vIFRocm93IGFuIGVycm9yIGlmIHRoZXJlIGlzIG5vIGNvcnJlY3QgYm9keVxyXG4gICAgaWYgKCFib2R5IHx8IGlzT2JqZWN0RW1wdHkoYm9keSkpIHtcclxuICAgICAgbG9nKFxyXG4gICAgICAgIDIsXHJcbiAgICAgICAgYFt2YWxpZGF0aW9uXSBSZXF1ZXN0IFske3JlcXVlc3RJZH1dIC0gVGhlIHJlcXVlc3QgZnJvbSAke1xyXG4gICAgICAgICAgcmVxdWVzdC5oZWFkZXJzWyd4LWZvcndhcmRlZC1mb3InXSB8fCByZXF1ZXN0LmNvbm5lY3Rpb24ucmVtb3RlQWRkcmVzc1xyXG4gICAgICAgIH0gd2FzIGluY29ycmVjdC4gUmVjZWl2ZWQgcGF5bG9hZCBpcyBlbXB0eS5gXHJcbiAgICAgICk7XHJcblxyXG4gICAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoXHJcbiAgICAgICAgYFt2YWxpZGF0aW9uXSBSZXF1ZXN0IFske3JlcXVlc3RJZH1dIC0gVGhlIHJlcXVlc3QgYm9keSBpcyByZXF1aXJlZC4gUGxlYXNlIGVuc3VyZSB0aGF0IHlvdXIgQ29udGVudC1UeXBlIGhlYWRlciBpcyBjb3JyZWN0LiBBY2NlcHRlZCB0eXBlcyBhcmUgJ2FwcGxpY2F0aW9uL2pzb24nIGFuZCAnbXVsdGlwYXJ0L2Zvcm0tZGF0YScuYCxcclxuICAgICAgICA0MDBcclxuICAgICAgKTtcclxuICAgIH1cclxuXHJcbiAgICAvLyBHZXQgdGhlIGBhbGxvd0NvZGVFeGVjdXRpb25gIG9wdGlvbiBmb3IgdGhlIHNlcnZlclxyXG4gICAgY29uc3QgYWxsb3dDb2RlRXhlY3V0aW9uID0gZ2V0QWxsb3dDb2RlRXhlY3V0aW9uKCk7XHJcblxyXG4gICAgLy8gRmluZCBhIGNvcnJlY3QgY2hhcnQgb3B0aW9uc1xyXG4gICAgY29uc3QgaW5zdHIgPSBpc0FsbG93ZWRDb25maWcoXHJcbiAgICAgIC8vIFVzZSBvbmUgb2YgdGhlIGJlbG93XHJcbiAgICAgIGJvZHkuaW5zdHIgfHwgYm9keS5vcHRpb25zIHx8IGJvZHkuaW5maWxlIHx8IGJvZHkuZGF0YSxcclxuICAgICAgLy8gU3RyaW5naWZ5IG9wdGlvbnNcclxuICAgICAgdHJ1ZSxcclxuICAgICAgLy8gQWxsb3cgb3IgZGlzYWxsb3cgZnVuY3Rpb25zXHJcbiAgICAgIGFsbG93Q29kZUV4ZWN1dGlvblxyXG4gICAgKTtcclxuXHJcbiAgICAvLyBUaHJvdyBhbiBlcnJvciBpZiB0aGVyZSBpcyBubyBjb3JyZWN0IGNoYXJ0IGRhdGFcclxuICAgIGlmIChpbnN0ciA9PT0gbnVsbCAmJiAhYm9keS5zdmcpIHtcclxuICAgICAgbG9nKFxyXG4gICAgICAgIDIsXHJcbiAgICAgICAgYFt2YWxpZGF0aW9uXSBSZXF1ZXN0IFske3JlcXVlc3RJZH1dIC0gVGhlIHJlcXVlc3QgZnJvbSAke1xyXG4gICAgICAgICAgcmVxdWVzdC5oZWFkZXJzWyd4LWZvcndhcmRlZC1mb3InXSB8fCByZXF1ZXN0LmNvbm5lY3Rpb24ucmVtb3RlQWRkcmVzc1xyXG4gICAgICAgIH0gd2FzIGluY29ycmVjdC4gUmVjZWl2ZWQgcGF5bG9hZCBpcyBtaXNzaW5nIGNvcnJlY3QgY2hhcnQgZGF0YSBmb3IgZXhwb3J0OiAke0pTT04uc3RyaW5naWZ5KGJvZHkpfS5gXHJcbiAgICAgICk7XHJcblxyXG4gICAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoXHJcbiAgICAgICAgYFt2YWxpZGF0aW9uXSBSZXF1ZXN0IFske3JlcXVlc3RJZH1dIC0gTm8gY29ycmVjdCBjaGFydCBkYXRhIGZvdW5kLiBFbnN1cmUgdGhhdCB5b3UgYXJlIHVzaW5nIGVpdGhlciBhcHBsaWNhdGlvbi9qc29uIG9yIG11bHRpcGFydC9mb3JtLWRhdGEgaGVhZGVycy4gSWYgc2VuZGluZyBKU09OLCBtYWtlIHN1cmUgdGhlIGNoYXJ0IGRhdGEgaXMgaW4gdGhlICdpbmZpbGUnLCAnb3B0aW9ucycsIG9yICdkYXRhJyBhdHRyaWJ1dGUuIElmIHNlbmRpbmcgU1ZHLCBlbnN1cmUgaXQgaXMgaW4gdGhlICdzdmcnIGF0dHJpYnV0ZS5gLFxyXG4gICAgICAgIDQwMFxyXG4gICAgICApO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIFRocm93IGFuIGVycm9yIGlmIHRlc3Qgb2YgeGxpbms6aHJlZiBlbGVtZW50cyBmcm9tIHBheWxvYWQncyBTVkcgZmFpbHNcclxuICAgIGlmIChib2R5LnN2ZyAmJiBpc1ByaXZhdGVSYW5nZVVybEZvdW5kKGJvZHkuc3ZnKSkge1xyXG4gICAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoXHJcbiAgICAgICAgYFt2YWxpZGF0aW9uXSBSZXF1ZXN0IFske3JlcXVlc3RJZH1dIC0gU1ZHIHBvdGVudGlhbGx5IGNvbnRhaW4gYXQgbGVhc3Qgb25lIGZvcmJpZGRlbiBVUkwgaW4gJ3hsaW5rOmhyZWYnIGVsZW1lbnQuIFBsZWFzZSByZXZpZXcgdGhlIFNWRyBjb250ZW50IGFuZCBlbnN1cmUgdGhhdCBhbGwgcmVmZXJlbmNlZCBVUkxzIGNvbXBseSB3aXRoIHNlY3VyaXR5IHBvbGljaWVzLmAsXHJcbiAgICAgICAgNDAwXHJcbiAgICAgICk7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gR2V0IGFuZCBwcmUtdmFsaWRhdGUgdGhlIG9wdGlvbnMgYW5kIHN0b3JlIHRoZW0gaW4gdGhlIHJlcXVlc3RcclxuICAgIHJlcXVlc3QudmFsaWRhdGVkT3B0aW9ucyA9IHtcclxuICAgICAgLy8gU2V0IHRoZSBjcmVhdGVkIElEIGFzIGEgYHJlcXVlc3RJZGAgcHJvcGVydHkgaW4gdGhlIG9wdGlvbnNcclxuICAgICAgcmVxdWVzdElkLFxyXG4gICAgICBleHBvcnQ6IHtcclxuICAgICAgICBpbnN0cixcclxuICAgICAgICBzdmc6IGJvZHkuc3ZnLFxyXG4gICAgICAgIG91dGZpbGU6XHJcbiAgICAgICAgICBib2R5Lm91dGZpbGUgfHxcclxuICAgICAgICAgIGAke3JlcXVlc3QucGFyYW1zLmZpbGVuYW1lIHx8ICdjaGFydCd9LiR7Ym9keS50eXBlIHx8ICdwbmcnfWAsXHJcbiAgICAgICAgdHlwZTogYm9keS50eXBlLFxyXG4gICAgICAgIGNvbnN0cjogYm9keS5jb25zdHIsXHJcbiAgICAgICAgYjY0OiBib2R5LmI2NCxcclxuICAgICAgICBub0Rvd25sb2FkOiBib2R5Lm5vRG93bmxvYWQsXHJcbiAgICAgICAgaGVpZ2h0OiBib2R5LmhlaWdodCxcclxuICAgICAgICB3aWR0aDogYm9keS53aWR0aCxcclxuICAgICAgICBzY2FsZTogYm9keS5zY2FsZSxcclxuICAgICAgICBnbG9iYWxPcHRpb25zOiBpc0FsbG93ZWRDb25maWcoXHJcbiAgICAgICAgICBib2R5Lmdsb2JhbE9wdGlvbnMsXHJcbiAgICAgICAgICB0cnVlLFxyXG4gICAgICAgICAgYWxsb3dDb2RlRXhlY3V0aW9uXHJcbiAgICAgICAgKSxcclxuICAgICAgICB0aGVtZU9wdGlvbnM6IGlzQWxsb3dlZENvbmZpZyhcclxuICAgICAgICAgIGJvZHkudGhlbWVPcHRpb25zLFxyXG4gICAgICAgICAgdHJ1ZSxcclxuICAgICAgICAgIGFsbG93Q29kZUV4ZWN1dGlvblxyXG4gICAgICAgIClcclxuICAgICAgfSxcclxuICAgICAgY3VzdG9tTG9naWM6IHtcclxuICAgICAgICBhbGxvd0NvZGVFeGVjdXRpb24sXHJcbiAgICAgICAgYWxsb3dGaWxlUmVzb3VyY2VzOiBmYWxzZSxcclxuICAgICAgICBjdXN0b21Db2RlOiBib2R5LmN1c3RvbUNvZGUsXHJcbiAgICAgICAgY2FsbGJhY2s6IGJvZHkuY2FsbGJhY2ssXHJcbiAgICAgICAgcmVzb3VyY2VzOiBpc0FsbG93ZWRDb25maWcoYm9keS5yZXNvdXJjZXMsIHRydWUsIGFsbG93Q29kZUV4ZWN1dGlvbilcclxuICAgICAgfVxyXG4gICAgfTtcclxuXHJcbiAgICAvLyBDYWxsIHRoZSBuZXh0IG1pZGRsZXdhcmVcclxuICAgIHJldHVybiBuZXh0KCk7XHJcbiAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgIHJldHVybiBuZXh0KGVycm9yKTtcclxuICB9XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBBZGRzIHRoZSB2YWxpZGF0aW9uIG1pZGRsZXdhcmVzIHRvIHRoZSBwYXNzZWQgZXhwcmVzcyBhcHAgaW5zdGFuY2UuXHJcbiAqXHJcbiAqIEBwYXJhbSB7RXhwcmVzc30gYXBwIC0gVGhlIEV4cHJlc3MgYXBwIGluc3RhbmNlLlxyXG4gKi9cclxuZXhwb3J0IGRlZmF1bHQgZnVuY3Rpb24gdmFsaWRhdGlvbk1pZGRsZXdhcmUoYXBwKSB7XHJcbiAgLy8gQWRkIGNvbnRlbnQgdHlwZSB2YWxpZGF0aW9uIG1pZGRsZXdhcmVcclxuICBhcHAucG9zdChbJy8nLCAnLzpmaWxlbmFtZSddLCBjb250ZW50VHlwZU1pZGRsZXdhcmUpO1xyXG5cclxuICAvLyBBZGQgcmVxdWVzdCBib2R5IHJlcXVlc3QgdmFsaWRhdGlvbiBtaWRkbGV3YXJlXHJcbiAgYXBwLnBvc3QoWycvJywgJy86ZmlsZW5hbWUnXSwgcmVxdWVzdEJvZHlNaWRkbGV3YXJlKTtcclxufVxyXG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxyXG5cclxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXHJcblxyXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNSwgSGlnaHNvZnRcclxuXHJcbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cclxuXHJcbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxyXG5cclxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxyXG5cclxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cclxuXHJcbi8qKlxyXG4gKiBAb3ZlcnZpZXcgRGVmaW5lcyB0aGUgZXhwb3J0IHJvdXRlcyBhbmQgbG9naWMgZm9yIGhhbmRsaW5nIGNoYXJ0IGV4cG9ydFxyXG4gKiByZXF1ZXN0cyBpbiBhbiBFeHByZXNzIHNlcnZlci4gVGhpcyBtb2R1bGUgcHJvY2Vzc2VzIGluY29taW5nIHJlcXVlc3RzXHJcbiAqIHRvIGV4cG9ydCBjaGFydHMgaW4gdmFyaW91cyBmb3JtYXRzIChlLmcuIEpQRUcsIFBORywgUERGLCBTVkcpLiBJdCBpbnRlZ3JhdGVzXHJcbiAqIHdpdGggSGlnaGNoYXJ0cycgY29yZSBmdW5jdGlvbmFsaXRpZXMgYW5kIHN1cHBvcnRzIGJvdGggaW1tZWRpYXRlIGRvd25sb2FkXHJcbiAqIHJlc3BvbnNlcyBhbmQgQmFzZTY0LWVuY29kZWQgY29udGVudCByZXR1cm5zLiBUaGUgY29kZSBhbHNvIGZlYXR1cmVzXHJcbiAqIGJlbmNobWFya2luZyBmb3IgcGVyZm9ybWFuY2UgbW9uaXRvcmluZy5cclxuICovXHJcblxyXG5pbXBvcnQgeyBzdGFydEV4cG9ydCB9IGZyb20gJy4uLy4uL2NoYXJ0LmpzJztcclxuaW1wb3J0IHsgbG9nIH0gZnJvbSAnLi4vLi4vbG9nZ2VyLmpzJztcclxuaW1wb3J0IHsgZ2V0QmFzZTY0LCBtZWFzdXJlVGltZSB9IGZyb20gJy4uLy4uL3V0aWxzLmpzJztcclxuXHJcbmltcG9ydCBFeHBvcnRFcnJvciBmcm9tICcuLi8uLi9lcnJvcnMvRXhwb3J0RXJyb3IuanMnO1xyXG5cclxuLy8gUmV2ZXJzZWQgTUlNRSB0eXBlc1xyXG5jb25zdCByZXZlcnNlZE1pbWUgPSB7XHJcbiAgcG5nOiAnaW1hZ2UvcG5nJyxcclxuICBqcGVnOiAnaW1hZ2UvanBlZycsXHJcbiAgZ2lmOiAnaW1hZ2UvZ2lmJyxcclxuICBwZGY6ICdhcHBsaWNhdGlvbi9wZGYnLFxyXG4gIHN2ZzogJ2ltYWdlL3N2Zyt4bWwnXHJcbn07XHJcblxyXG4vKipcclxuICogSGFuZGxlcyB0aGUgZXhwb3J0IHJlcXVlc3RzIGZyb20gdGhlIGNsaWVudC5cclxuICpcclxuICogQGFzeW5jXHJcbiAqIEBmdW5jdGlvbiByZXF1ZXN0RXhwb3J0XHJcbiAqXHJcbiAqIEBwYXJhbSB7RXhwcmVzcy5SZXF1ZXN0fSByZXF1ZXN0IC0gVGhlIEV4cHJlc3MgcmVxdWVzdCBvYmplY3QuXHJcbiAqIEBwYXJhbSB7RXhwcmVzcy5SZXNwb25zZX0gcmVzcG9uc2UgLSBUaGUgRXhwcmVzcyByZXNwb25zZSBvYmplY3QuXHJcbiAqIEBwYXJhbSB7RnVuY3Rpb259IG5leHQgLSBUaGUgbmV4dCBtaWRkbGV3YXJlIGZ1bmN0aW9uLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7UHJvbWlzZTx2b2lkPn0gQSBQcm9taXNlIHRoYXQgcmVzb2x2ZXMgb25jZSB0aGUgZXhwb3J0IHByb2Nlc3NcclxuICogaXMgY29tcGxldGUuXHJcbiAqL1xyXG5hc3luYyBmdW5jdGlvbiByZXF1ZXN0RXhwb3J0KHJlcXVlc3QsIHJlc3BvbnNlLCBuZXh0KSB7XHJcbiAgdHJ5IHtcclxuICAgIC8vIFN0YXJ0IGNvdW50aW5nIHRpbWUgZm9yIGEgcmVxdWVzdFxyXG4gICAgY29uc3QgcmVxdWVzdENvdW50ZXIgPSBtZWFzdXJlVGltZSgpO1xyXG5cclxuICAgIC8vIEluIGNhc2UgdGhlIGNvbm5lY3Rpb24gaXMgY2xvc2VkLCBmb3JjZSB0byBhYm9ydCBmdXJ0aGVyIGFjdGlvbnNcclxuICAgIGxldCBjb25uZWN0aW9uQWJvcnRlZCA9IGZhbHNlO1xyXG4gICAgcmVxdWVzdC5zb2NrZXQub24oJ2Nsb3NlJywgKGhhZEVycm9ycykgPT4ge1xyXG4gICAgICBpZiAoaGFkRXJyb3JzKSB7XHJcbiAgICAgICAgY29ubmVjdGlvbkFib3J0ZWQgPSB0cnVlO1xyXG4gICAgICB9XHJcbiAgICB9KTtcclxuXHJcbiAgICAvLyBHZXQgdGhlIG9wdGlvbnMgcHJldmlvdXNseSB2YWxpZGF0ZWQgaW4gdGhlIHZhbGlkYXRpb24gbWlkZGxld2FyZVxyXG4gICAgY29uc3Qgb3B0aW9ucyA9IHJlcXVlc3QudmFsaWRhdGVkT3B0aW9ucztcclxuXHJcbiAgICAvLyBHZXQgdGhlIHJlcXVlc3QgaWRcclxuICAgIGNvbnN0IHJlcXVlc3RJZCA9IG9wdGlvbnMucmVxdWVzdElkO1xyXG5cclxuICAgIC8vIEluZm8gYWJvdXQgYW4gaW5jb21pbmcgcmVxdWVzdCB3aXRoIGNvcnJlY3QgZGF0YVxyXG4gICAgbG9nKDQsIGBbZXhwb3J0XSBSZXF1ZXN0IFske3JlcXVlc3RJZH1dIC0gR290IGFuIGluY29taW5nIEhUVFAgcmVxdWVzdC5gKTtcclxuXHJcbiAgICAvLyBTdGFydCB0aGUgZXhwb3J0IHByb2Nlc3NcclxuICAgIGF3YWl0IHN0YXJ0RXhwb3J0KG9wdGlvbnMsIChlcnJvciwgZGF0YSkgPT4ge1xyXG4gICAgICAvLyBSZW1vdmUgdGhlIGNsb3NlIGV2ZW50IGZyb20gdGhlIHNvY2tldFxyXG4gICAgICByZXF1ZXN0LnNvY2tldC5yZW1vdmVBbGxMaXN0ZW5lcnMoJ2Nsb3NlJyk7XHJcblxyXG4gICAgICAvLyBJZiB0aGUgY29ubmVjdGlvbiB3YXMgY2xvc2VkLCBkbyBub3RoaW5nXHJcbiAgICAgIGlmIChjb25uZWN0aW9uQWJvcnRlZCkge1xyXG4gICAgICAgIGxvZyhcclxuICAgICAgICAgIDMsXHJcbiAgICAgICAgICBgW2V4cG9ydF0gUmVxdWVzdCBbJHtyZXF1ZXN0SWR9XSAtIFRoZSBjbGllbnQgY2xvc2VkIHRoZSBjb25uZWN0aW9uIGJlZm9yZSB0aGUgY2hhcnQgZmluaXNoZWQgcHJvY2Vzc2luZy5gXHJcbiAgICAgICAgKTtcclxuICAgICAgICByZXR1cm47XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIC8vIElmIGVycm9yLCBsb2cgaXQgYW5kIHNlbmQgaXQgdG8gdGhlIGVycm9yIG1pZGRsZXdhcmVcclxuICAgICAgaWYgKGVycm9yKSB7XHJcbiAgICAgICAgdGhyb3cgZXJyb3I7XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIC8vIElmIGRhdGEgaXMgbWlzc2luZywgbG9nIHRoZSBtZXNzYWdlIGFuZCBzZW5kIGl0IHRvIHRoZSBlcnJvciBtaWRkbGV3YXJlXHJcbiAgICAgIGlmICghZGF0YSB8fCAhZGF0YS5yZXN1bHQpIHtcclxuICAgICAgICBsb2coXHJcbiAgICAgICAgICAyLFxyXG4gICAgICAgICAgYFtleHBvcnRdIFJlcXVlc3QgWyR7cmVxdWVzdElkfV0gLSBSZXF1ZXN0IGZyb20gJHtcclxuICAgICAgICAgICAgcmVxdWVzdC5oZWFkZXJzWyd4LWZvcndhcmRlZC1mb3InXSB8fFxyXG4gICAgICAgICAgICByZXF1ZXN0LmNvbm5lY3Rpb24ucmVtb3RlQWRkcmVzc1xyXG4gICAgICAgICAgfSB3YXMgaW5jb3JyZWN0LiBSZWNlaXZlZCByZXN1bHQgaXMgJHtkYXRhLnJlc3VsdH0uYFxyXG4gICAgICAgICk7XHJcblxyXG4gICAgICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcihcclxuICAgICAgICAgIGBbZXhwb3J0XSBSZXF1ZXN0IFske3JlcXVlc3RJZH1dIC0gVW5leHBlY3RlZCByZXR1cm4gb2YgdGhlIGV4cG9ydCByZXN1bHQgZnJvbSB0aGUgY2hhcnQgZ2VuZXJhdGlvbi4gUGxlYXNlIGNoZWNrIHlvdXIgcmVxdWVzdCBkYXRhLmAsXHJcbiAgICAgICAgICA0MDBcclxuICAgICAgICApO1xyXG4gICAgICB9XHJcblxyXG4gICAgICAvLyBSZXR1cm4gdGhlIHJlc3VsdCBpbiBhbiBhcHByb3ByaWF0ZSBmb3JtYXRcclxuICAgICAgaWYgKGRhdGEucmVzdWx0KSB7XHJcbiAgICAgICAgbG9nKFxyXG4gICAgICAgICAgMyxcclxuICAgICAgICAgIGBbZXhwb3J0XSBSZXF1ZXN0IFske3JlcXVlc3RJZH1dIC0gVGhlIHdob2xlIGV4cG9ydGluZyBwcm9jZXNzIHRvb2sgJHtyZXF1ZXN0Q291bnRlcigpfW1zLmBcclxuICAgICAgICApO1xyXG5cclxuICAgICAgICAvLyBHZXQgdGhlIGB0eXBlYCwgYGI2NGAsIGBub0Rvd25sb2FkYCwgYW5kIGBvdXRmaWxlYCBmcm9tIG9wdGlvbnNcclxuICAgICAgICBjb25zdCB7IHR5cGUsIGI2NCwgbm9Eb3dubG9hZCwgb3V0ZmlsZSB9ID0gZGF0YS5vcHRpb25zLmV4cG9ydDtcclxuXHJcbiAgICAgICAgLy8gSWYgb25seSBCYXNlNjQgaXMgcmVxdWlyZWQsIHJldHVybiBpdFxyXG4gICAgICAgIGlmIChiNjQpIHtcclxuICAgICAgICAgIHJldHVybiByZXNwb25zZS5zZW5kKGdldEJhc2U2NChkYXRhLnJlc3VsdCwgdHlwZSkpO1xyXG4gICAgICAgIH1cclxuXHJcbiAgICAgICAgLy8gU2V0IGNvcnJlY3QgY29udGVudCB0eXBlXHJcbiAgICAgICAgcmVzcG9uc2UuaGVhZGVyKCdDb250ZW50LVR5cGUnLCByZXZlcnNlZE1pbWVbdHlwZV0gfHwgJ2ltYWdlL3BuZycpO1xyXG5cclxuICAgICAgICAvLyBEZWNpZGUgd2hldGhlciB0byBkb3dubG9hZCBvciBub3QgY2hhcnQgZmlsZVxyXG4gICAgICAgIGlmICghbm9Eb3dubG9hZCkge1xyXG4gICAgICAgICAgcmVzcG9uc2UuYXR0YWNobWVudChvdXRmaWxlKTtcclxuICAgICAgICB9XHJcblxyXG4gICAgICAgIC8vIElmIFNWRywgcmV0dXJuIHBsYWluIGNvbnRlbnQsIG90aGVyd2lzZSBhIGI2NCBzdHJpbmcgZnJvbSBhIGJ1ZmZlclxyXG4gICAgICAgIHJldHVybiB0eXBlID09PSAnc3ZnJ1xyXG4gICAgICAgICAgPyByZXNwb25zZS5zZW5kKGRhdGEucmVzdWx0KVxyXG4gICAgICAgICAgOiByZXNwb25zZS5zZW5kKEJ1ZmZlci5mcm9tKGRhdGEucmVzdWx0LCAnYmFzZTY0JykpO1xyXG4gICAgICB9XHJcbiAgICB9KTtcclxuICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgcmV0dXJuIG5leHQoZXJyb3IpO1xyXG4gIH1cclxufVxyXG5cclxuLyoqXHJcbiAqIEFkZHMgdGhlIGBleHBvcnRgIHJvdXRlcy5cclxuICpcclxuICogQGZ1bmN0aW9uIGV4cG9ydFJvdXRlc1xyXG4gKlxyXG4gKiBAcGFyYW0ge0V4cHJlc3N9IGFwcCAtIFRoZSBFeHByZXNzIGFwcCBpbnN0YW5jZS5cclxuICovXHJcbmV4cG9ydCBkZWZhdWx0IGZ1bmN0aW9uIGV4cG9ydFJvdXRlcyhhcHApIHtcclxuICAvKipcclxuICAgKiBBZGRzIHRoZSBQT1NUICcvJyAtIEEgcm91dGUgZm9yIGhhbmRsaW5nIFBPU1QgcmVxdWVzdHMgYXQgdGhlIHJvb3RcclxuICAgKiBlbmRwb2ludC5cclxuICAgKi9cclxuICBhcHAucG9zdCgnLycsIHJlcXVlc3RFeHBvcnQpO1xyXG5cclxuICAvKipcclxuICAgKiBBZGRzIHRoZSBQT1NUICcvOmZpbGVuYW1lJyAtIEEgcm91dGUgZm9yIGhhbmRsaW5nIFBPU1QgcmVxdWVzdHMgd2l0aFxyXG4gICAqIGEgc3BlY2lmaWVkIGZpbGVuYW1lIHBhcmFtZXRlci5cclxuICAgKi9cclxuICBhcHAucG9zdCgnLzpmaWxlbmFtZScsIHJlcXVlc3RFeHBvcnQpO1xyXG59XHJcbiIsIi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXHJcblxyXG5IaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXJcclxuXHJcbkNvcHlyaWdodCAoYykgMjAxNi0yMDI1LCBIaWdoc29mdFxyXG5cclxuTGljZW5jZWQgdW5kZXIgdGhlIE1JVCBsaWNlbmNlLlxyXG5cclxuQWRkaXRpb25hbGx5IGEgdmFsaWQgSGlnaGNoYXJ0cyBsaWNlbnNlIGlzIHJlcXVpcmVkIGZvciB1c2UuXHJcblxyXG5TZWUgTElDRU5TRSBmaWxlIGluIHJvb3QgZm9yIGRldGFpbHMuXHJcblxyXG4qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xyXG5cclxuLyoqXHJcbiAqIEBvdmVydmlldyBEZWZpbmVzIGFuIEV4cHJlc3Mgcm91dGUgZm9yIHNlcnZlciBoZWFsdGggbW9uaXRvcmluZywgaW5jbHVkaW5nXHJcbiAqIHVwdGltZSwgc3VjY2VzcyByYXRlcywgYW5kIG90aGVyIHNlcnZlciBzdGF0aXN0aWNzLlxyXG4gKi9cclxuXHJcbmltcG9ydCB7IHJlYWRGaWxlU3luYyB9IGZyb20gJ2ZzJztcclxuaW1wb3J0IHsgam9pbiB9IGZyb20gJ3BhdGgnO1xyXG5cclxuaW1wb3J0IHsgZ2V0SGNWZXJzaW9uIH0gZnJvbSAnLi4vLi4vY2FjaGUuanMnO1xyXG5pbXBvcnQgeyBsb2cgfSBmcm9tICcuLi8uLi9sb2dnZXIuanMnO1xyXG5pbXBvcnQgeyBnZXRQb29sSW5mb0pTT04sIGdldFBvb2xTdGF0cyB9IGZyb20gJy4uLy4uL3Bvb2wuanMnO1xyXG5pbXBvcnQgeyBhZGRUaW1lciB9IGZyb20gJy4uLy4uL3RpbWVyLmpzJztcclxuaW1wb3J0IHsgX19kaXJuYW1lLCBnZXROZXdEYXRlVGltZSB9IGZyb20gJy4uLy4uL3V0aWxzLmpzJztcclxuXHJcbi8vIFNldCB0aGUgc3RhcnQgZGF0ZSBvZiB0aGUgc2VydmVyXHJcbmNvbnN0IHNlcnZlclN0YXJ0VGltZSA9IG5ldyBEYXRlKCk7XHJcblxyXG4vLyBHZXQgdGhlIGBwYWNrYWdlLmpzb25gIGNvbnRlbnRcclxuY29uc3QgcGFja2FnZUZpbGUgPSBKU09OLnBhcnNlKFxyXG4gIHJlYWRGaWxlU3luYyhqb2luKF9fZGlybmFtZSwgJ3BhY2thZ2UuanNvbicpLCAndXRmOCcpXHJcbik7XHJcblxyXG4vLyBBbiBhcnJheSBmb3Igc3VjY2VzcyByYXRlIHJhdGlvc1xyXG5jb25zdCBzdWNjZXNzUmF0ZXMgPSBbXTtcclxuXHJcbi8vIFJlY29yZCBldmVyeSBtaW51dGVcclxuY29uc3QgcmVjb3JkSW50ZXJ2YWwgPSA2MCAqIDEwMDA7XHJcblxyXG4vLyAzMCBtaW51dGVzXHJcbmNvbnN0IHdpbmRvd1NpemUgPSAzMDtcclxuXHJcbi8qKlxyXG4gKiBDYWxjdWxhdGVzIG1vdmluZyBhdmVyYWdlIGluZGljYXRvciBiYXNlZCBvbiB0aGUgZGF0YSBmcm9tIHRoZSBgc3VjY2Vzc1JhdGVzYFxyXG4gKiBhcnJheS5cclxuICpcclxuICogQGZ1bmN0aW9uIF9jYWxjdWxhdGVNb3ZpbmdBdmVyYWdlXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtudW1iZXJ9IEEgbW92aW5nIGF2ZXJhZ2UgZm9yIHN1Y2Nlc3MgcmF0aW8gb2YgdGhlIHNlcnZlciBleHBvcnRzLlxyXG4gKi9cclxuZnVuY3Rpb24gX2NhbGN1bGF0ZU1vdmluZ0F2ZXJhZ2UoKSB7XHJcbiAgcmV0dXJuIHN1Y2Nlc3NSYXRlcy5yZWR1Y2UoKGEsIGIpID0+IGEgKyBiLCAwKSAvIHN1Y2Nlc3NSYXRlcy5sZW5ndGg7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBTdGFydHMgdGhlIGludGVydmFsIHJlc3BvbnNpYmxlIGZvciBjYWxjdWxhdGluZyBjdXJyZW50IHN1Y2Nlc3MgcmF0ZSByYXRpb1xyXG4gKiBhbmQgY29sbGVjdHMgcmVjb3JkcyB0byB0aGUgYHN1Y2Nlc3NSYXRlc2AgYXJyYXkuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBfc3RhcnRTdWNjZXNzUmF0ZVxyXG4gKlxyXG4gKiBAcmV0dXJucyB7Tm9kZUpTLlRpbWVvdXR9IElkIG9mIGFuIGludGVydmFsLlxyXG4gKi9cclxuZnVuY3Rpb24gX3N0YXJ0U3VjY2Vzc1JhdGUoKSB7XHJcbiAgcmV0dXJuIHNldEludGVydmFsKCgpID0+IHtcclxuICAgIGNvbnN0IHN0YXRzID0gZ2V0UG9vbFN0YXRzKCk7XHJcbiAgICBjb25zdCBzdWNjZXNzUmF0aW8gPVxyXG4gICAgICBzdGF0cy5leHBvcnRzQXR0ZW1wdGVkID09PSAwXHJcbiAgICAgICAgPyAxXHJcbiAgICAgICAgOiAoc3RhdHMuZXhwb3J0c1BlcmZvcm1lZCAvIHN0YXRzLmV4cG9ydHNBdHRlbXB0ZWQpICogMTAwO1xyXG5cclxuICAgIHN1Y2Nlc3NSYXRlcy5wdXNoKHN1Y2Nlc3NSYXRpbyk7XHJcbiAgICBpZiAoc3VjY2Vzc1JhdGVzLmxlbmd0aCA+IHdpbmRvd1NpemUpIHtcclxuICAgICAgc3VjY2Vzc1JhdGVzLnNoaWZ0KCk7XHJcbiAgICB9XHJcbiAgfSwgcmVjb3JkSW50ZXJ2YWwpO1xyXG59XHJcblxyXG4vKipcclxuICogQWRkcyB0aGUgYGhlYWx0aGAgcm91dGVzLlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gaGVhbHRoUm91dGVzXHJcbiAqXHJcbiAqIEBwYXJhbSB7RXhwcmVzc30gYXBwIC0gVGhlIEV4cHJlc3MgYXBwIGluc3RhbmNlLlxyXG4gKi9cclxuZXhwb3J0IGRlZmF1bHQgZnVuY3Rpb24gaGVhbHRoUm91dGVzKGFwcCkge1xyXG4gIC8vIFN0YXJ0IHByb2Nlc3Npbmcgc3VjY2VzcyByYXRlIHJhdGlvIGludGVydmFsIGFuZCBzYXZlIGl0cyBpZCB0byB0aGUgYXJyYXlcclxuICAvLyBmb3IgdGhlIGdyYWNlZnVsIGNsZWFyaW5nIG9uIHNodXRkb3duIHdpdGggaW5qZWN0ZWQgYGFkZFRpbWVyYCBmdW50aW9uXHJcbiAgYWRkVGltZXIoX3N0YXJ0U3VjY2Vzc1JhdGUoKSk7XHJcblxyXG4gIC8qKlxyXG4gICAqIEFkZHMgdGhlIEdFVCAnL2hlYWx0aCcgLSBBIHJvdXRlIGZvciBnZXR0aW5nIHRoZSBiYXNpYyBzdGF0cyBvZiB0aGUgc2VydmVyLlxyXG4gICAqL1xyXG4gIGFwcC5nZXQoJy9oZWFsdGgnLCAocmVxdWVzdCwgcmVzcG9uc2UsIG5leHQpID0+IHtcclxuICAgIHRyeSB7XHJcbiAgICAgIGxvZyg0LCAnW2hlYWx0aF0gUmV0dXJuaW5nIHNlcnZlciBoZWFsdGguJyk7XHJcblxyXG4gICAgICBjb25zdCBzdGF0cyA9IGdldFBvb2xTdGF0cygpO1xyXG4gICAgICBjb25zdCBwZXJpb2QgPSBzdWNjZXNzUmF0ZXMubGVuZ3RoO1xyXG4gICAgICBjb25zdCBtb3ZpbmdBdmVyYWdlID0gX2NhbGN1bGF0ZU1vdmluZ0F2ZXJhZ2UoKTtcclxuXHJcbiAgICAgIC8vIFNlbmQgdGhlIHNlcnZlcidzIHN0YXRpc3RpY3NcclxuICAgICAgcmVzcG9uc2Uuc2VuZCh7XHJcbiAgICAgICAgLy8gU3RhdHVzIGFuZCB0aW1lc1xyXG4gICAgICAgIHN0YXR1czogJ09LJyxcclxuICAgICAgICBib290VGltZTogc2VydmVyU3RhcnRUaW1lLFxyXG4gICAgICAgIHVwdGltZTogYCR7TWF0aC5mbG9vcigoZ2V0TmV3RGF0ZVRpbWUoKSAtIHNlcnZlclN0YXJ0VGltZS5nZXRUaW1lKCkpIC8gMTAwMCAvIDYwKX0gbWludXRlc2AsXHJcblxyXG4gICAgICAgIC8vIFZlcnNpb25zXHJcbiAgICAgICAgc2VydmVyVmVyc2lvbjogcGFja2FnZUZpbGUudmVyc2lvbixcclxuICAgICAgICBoaWdoY2hhcnRzVmVyc2lvbjogZ2V0SGNWZXJzaW9uKCksXHJcblxyXG4gICAgICAgIC8vIEV4cG9ydHNcclxuICAgICAgICBhdmVyYWdlRXhwb3J0VGltZTogc3RhdHMudGltZVNwZW50QXZlcmFnZSxcclxuICAgICAgICBhdHRlbXB0ZWRFeHBvcnRzOiBzdGF0cy5leHBvcnRzQXR0ZW1wdGVkLFxyXG4gICAgICAgIHBlcmZvcm1lZEV4cG9ydHM6IHN0YXRzLmV4cG9ydHNQZXJmb3JtZWQsXHJcbiAgICAgICAgZmFpbGVkRXhwb3J0czogc3RhdHMuZXhwb3J0c0Ryb3BwZWQsXHJcbiAgICAgICAgc3VjZXNzUmF0aW86IChzdGF0cy5leHBvcnRzUGVyZm9ybWVkIC8gc3RhdHMuZXhwb3J0c0F0dGVtcHRlZCkgKiAxMDAsXHJcblxyXG4gICAgICAgIC8vIFBvb2xcclxuICAgICAgICBwb29sOiBnZXRQb29sSW5mb0pTT04oKSxcclxuXHJcbiAgICAgICAgLy8gTW92aW5nIGF2ZXJhZ2VcclxuICAgICAgICBwZXJpb2QsXHJcbiAgICAgICAgbW92aW5nQXZlcmFnZSxcclxuICAgICAgICBtZXNzYWdlOlxyXG4gICAgICAgICAgaXNOYU4obW92aW5nQXZlcmFnZSkgfHwgIXN1Y2Nlc3NSYXRlcy5sZW5ndGhcclxuICAgICAgICAgICAgPyAnVG9vIGVhcmx5IHRvIHJlcG9ydC4gTm8gZXhwb3J0cyBtYWRlIHlldC4gUGxlYXNlIGNoZWNrIGJhY2sgc29vbi4nXHJcbiAgICAgICAgICAgIDogYExhc3QgJHtwZXJpb2R9IG1pbnV0ZXMgaGFkIGEgc3VjY2VzcyByYXRlIG9mICR7bW92aW5nQXZlcmFnZS50b0ZpeGVkKDIpfSUuYCxcclxuXHJcbiAgICAgICAgLy8gU1ZHIGFuZCBKU09OIGV4cG9ydHNcclxuICAgICAgICBzdmdFeHBvcnRzOiBzdGF0cy5leHBvcnRzRnJvbVN2ZyxcclxuICAgICAgICBqc29uRXhwb3J0czogc3RhdHMuZXhwb3J0c0Zyb21PcHRpb25zLFxyXG4gICAgICAgIHN2Z0V4cG9ydHNBdHRlbXB0czogc3RhdHMuZXhwb3J0c0Zyb21TdmdBdHRlbXB0cyxcclxuICAgICAgICBqc29uRXhwb3J0c0F0dGVtcHRzOiBzdGF0cy5leHBvcnRzRnJvbU9wdGlvbnNBdHRlbXB0c1xyXG4gICAgICB9KTtcclxuICAgIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICAgIHJldHVybiBuZXh0KGVycm9yKTtcclxuICAgIH1cclxuICB9KTtcclxufVxyXG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxyXG5cclxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXHJcblxyXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNSwgSGlnaHNvZnRcclxuXHJcbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cclxuXHJcbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxyXG5cclxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxyXG5cclxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cclxuXHJcbi8qKlxyXG4gKiBAb3ZlcnZpZXcgRGVmaW5lcyBhbiBFeHByZXNzIHJvdXRlIGZvciBzZXJ2aW5nIHRoZSBVSSBmb3IgdGhlIGV4cG9ydCBzZXJ2ZXJcclxuICogd2hlbiBlbmFibGVkLlxyXG4gKi9cclxuXHJcbmltcG9ydCB7IGpvaW4gfSBmcm9tICdwYXRoJztcclxuXHJcbmltcG9ydCB7IGdldE9wdGlvbnMgfSBmcm9tICcuLi8uLi9jb25maWcuanMnO1xyXG5pbXBvcnQgeyBsb2cgfSBmcm9tICcuLi8uLi9sb2dnZXIuanMnO1xyXG5pbXBvcnQgeyBfX2Rpcm5hbWUgfSBmcm9tICcuLi8uLi91dGlscy5qcyc7XHJcblxyXG4vKipcclxuICogQWRkcyB0aGUgYHVpYCByb3V0ZXMuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiB1aVJvdXRlc1xyXG4gKlxyXG4gKiBAcGFyYW0ge0V4cHJlc3N9IGFwcCAtIFRoZSBFeHByZXNzIGFwcCBpbnN0YW5jZS5cclxuICovXHJcbmV4cG9ydCBkZWZhdWx0IGZ1bmN0aW9uIHVpUm91dGVzKGFwcCkge1xyXG4gIC8vIEFkZCB0aGUgVUkgZW5kcG9pbnQgb25seSBpZiByZXF1aXJlZFxyXG4gIGlmIChnZXRPcHRpb25zKCkudWkuZW5hYmxlKSB7XHJcbiAgICAvKipcclxuICAgICAqIEFkZHMgdGhlIEdFVCAnLycgLSBBIHJvdXRlIGZvciBhIFVJIHdoZW4gZW5hYmxlZCBvbiB0aGUgZXhwb3J0IHNlcnZlci5cclxuICAgICAqL1xyXG4gICAgYXBwLmdldChnZXRPcHRpb25zKCkudWkucm91dGUgfHwgJy8nLCAocmVxdWVzdCwgcmVzcG9uc2UsIG5leHQpID0+IHtcclxuICAgICAgdHJ5IHtcclxuICAgICAgICBsb2coNCwgJ1t1aV0gUmV0dXJuaW5nIFVJIGZvciB0aGUgZXhwb3J0LicpO1xyXG5cclxuICAgICAgICByZXNwb25zZS5zZW5kRmlsZShqb2luKF9fZGlybmFtZSwgJ3B1YmxpYycsICdpbmRleC5odG1sJyksIHtcclxuICAgICAgICAgIGFjY2VwdFJhbmdlczogZmFsc2VcclxuICAgICAgICB9KTtcclxuICAgICAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICAgICByZXR1cm4gbmV4dChlcnJvcik7XHJcbiAgICAgIH1cclxuICAgIH0pO1xyXG4gIH1cclxufVxyXG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxyXG5cclxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXHJcblxyXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNSwgSGlnaHNvZnRcclxuXHJcbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cclxuXHJcbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxyXG5cclxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxyXG5cclxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cclxuXHJcbi8qKlxyXG4gKiBAb3ZlcnZpZXcgRGVmaW5lcyBhbiBFeHByZXNzIHJvdXRlIGZvciB1cGRhdGluZyB0aGUgSGlnaGNoYXJ0cyB2ZXJzaW9uXHJcbiAqIG9uIHRoZSBzZXJ2ZXIsIHdpdGggYXV0aGVudGljYXRpb24gYW5kIHZhbGlkYXRpb24uXHJcbiAqL1xyXG5cclxuaW1wb3J0IHsgZ2V0SGNWZXJzaW9uLCB1cGRhdGVIY1ZlcnNpb24gfSBmcm9tICcuLi8uLi9jYWNoZS5qcyc7XHJcbmltcG9ydCB7IGxvZyB9IGZyb20gJy4uLy4uL2xvZ2dlci5qcyc7XHJcbmltcG9ydCB7IGVudnMgfSBmcm9tICcuLi8uLi92YWxpZGF0aW9uLmpzJztcclxuXHJcbmltcG9ydCBFeHBvcnRFcnJvciBmcm9tICcuLi8uLi9lcnJvcnMvRXhwb3J0RXJyb3IuanMnO1xyXG5cclxuLyoqXHJcbiAqIEFkZHMgdGhlIGB2ZXJzaW9uX2NoYW5nZWAgcm91dGVzLlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gdmVyc2lvbkNoYW5nZVJvdXRlc1xyXG4gKlxyXG4gKiBAcGFyYW0ge0V4cHJlc3N9IGFwcCAtIFRoZSBFeHByZXNzIGFwcCBpbnN0YW5jZS5cclxuICovXHJcbmV4cG9ydCBkZWZhdWx0IGZ1bmN0aW9uIHZlcnNpb25DaGFuZ2VSb3V0ZXMoYXBwKSB7XHJcbiAgLyoqXHJcbiAgICogQWRkcyB0aGUgUE9TVCAnL3ZlcnNpb25fY2hhbmdlLzpuZXdWZXJzaW9uJyAtIEEgcm91dGUgZm9yIGNoYW5naW5nXHJcbiAgICogdGhlIEhpZ2hjaGFydHMgdmVyc2lvbiBvbiB0aGUgc2VydmVyLlxyXG4gICAqL1xyXG4gIGFwcC5wb3N0KCcvdmVyc2lvbl9jaGFuZ2UvOm5ld1ZlcnNpb24nLCBhc3luYyAocmVxdWVzdCwgcmVzcG9uc2UsIG5leHQpID0+IHtcclxuICAgIHRyeSB7XHJcbiAgICAgIGxvZyg0LCAnW3ZlcnNpb25dIENoYW5naW5nIEhpZ2hjaGFydHMgdmVyc2lvbi4nKTtcclxuXHJcbiAgICAgIC8vIEdldCB0aGUgdG9rZW4gZGlyZWN0bHkgZnJvbSBlbnZzXHJcbiAgICAgIGNvbnN0IGFkbWluVG9rZW4gPSBlbnZzLkhJR0hDSEFSVFNfQURNSU5fVE9LRU47XHJcblxyXG4gICAgICAvLyBDaGVjayB0aGUgZXhpc3RlbmNlIG9mIHRoZSB0b2tlblxyXG4gICAgICBpZiAoIWFkbWluVG9rZW4gfHwgIWFkbWluVG9rZW4ubGVuZ3RoKSB7XHJcbiAgICAgICAgdGhyb3cgbmV3IEV4cG9ydEVycm9yKFxyXG4gICAgICAgICAgJ1t2ZXJzaW9uXSBUaGUgc2VydmVyIGlzIG5vdCBjb25maWd1cmVkIHRvIHBlcmZvcm0gcnVuLXRpbWUgdmVyc2lvbiBjaGFuZ2VzOiBgSElHSENIQVJUU19BRE1JTl9UT0tFTmAgaXMgbm90IHNldC4nLFxyXG4gICAgICAgICAgNDAxXHJcbiAgICAgICAgKTtcclxuICAgICAgfVxyXG5cclxuICAgICAgLy8gR2V0IHRoZSB0b2tlbiBmcm9tIHRoZSBoYy1hdXRoIGhlYWRlclxyXG4gICAgICBjb25zdCB0b2tlbiA9IHJlcXVlc3QuZ2V0KCdoYy1hdXRoJyk7XHJcblxyXG4gICAgICAvLyBDaGVjayBpZiB0aGUgaGMtYXV0aCBoZWFkZXIgY29udGFpbiBhIGNvcnJlY3QgdG9rZW5cclxuICAgICAgaWYgKCF0b2tlbiB8fCB0b2tlbiAhPT0gYWRtaW5Ub2tlbikge1xyXG4gICAgICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcihcclxuICAgICAgICAgICdbdmVyc2lvbl0gSW52YWxpZCBvciBtaXNzaW5nIHRva2VuOiBTZXQgdGhlIHRva2VuIGluIHRoZSBoYy1hdXRoIGhlYWRlci4nLFxyXG4gICAgICAgICAgNDAxXHJcbiAgICAgICAgKTtcclxuICAgICAgfVxyXG5cclxuICAgICAgLy8gR2V0IHRoZSBuZXcgdmVyc2lvbiBmcm9tIHRoZSBwYXJhbXNcclxuICAgICAgY29uc3QgbmV3VmVyc2lvbiA9IHJlcXVlc3QucGFyYW1zLm5ld1ZlcnNpb247XHJcblxyXG4gICAgICAvLyBVcGRhdGUgdmVyc2lvblxyXG4gICAgICBpZiAobmV3VmVyc2lvbikge1xyXG4gICAgICAgIHRyeSB7XHJcbiAgICAgICAgICBhd2FpdCB1cGRhdGVIY1ZlcnNpb24obmV3VmVyc2lvbik7XHJcbiAgICAgICAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICAgICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcihcclxuICAgICAgICAgICAgYFt2ZXJzaW9uXSBWZXJzaW9uIGNoYW5nZTogJHtlcnJvci5tZXNzYWdlfWAsXHJcbiAgICAgICAgICAgIDQwMFxyXG4gICAgICAgICAgKS5zZXRFcnJvcihlcnJvcik7XHJcbiAgICAgICAgfVxyXG5cclxuICAgICAgICAvLyBTdWNjZXNzXHJcbiAgICAgICAgcmVzcG9uc2Uuc3RhdHVzKDIwMCkuc2VuZCh7XHJcbiAgICAgICAgICBzdGF0dXNDb2RlOiAyMDAsXHJcbiAgICAgICAgICBoaWdoY2hhcnRzVmVyc2lvbjogZ2V0SGNWZXJzaW9uKCksXHJcbiAgICAgICAgICBtZXNzYWdlOiBgU3VjY2Vzc2Z1bGx5IHVwZGF0ZWQgSGlnaGNoYXJ0cyB0byB2ZXJzaW9uOiAke25ld1ZlcnNpb259LmBcclxuICAgICAgICB9KTtcclxuICAgICAgfSBlbHNlIHtcclxuICAgICAgICAvLyBObyB2ZXJzaW9uIHNwZWNpZmllZFxyXG4gICAgICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcignW3ZlcnNpb25dIE5vIG5ldyB2ZXJzaW9uIHN1cHBsaWVkLicsIDQwMCk7XHJcbiAgICAgIH1cclxuICAgIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICAgIHJldHVybiBuZXh0KGVycm9yKTtcclxuICAgIH1cclxuICB9KTtcclxufVxyXG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxyXG5cclxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXHJcblxyXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNSwgSGlnaHNvZnRcclxuXHJcbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cclxuXHJcbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxyXG5cclxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxyXG5cclxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cclxuXHJcbi8qKlxyXG4gKiBAb3ZlcnZpZXcgQSBtb2R1bGUgdGhhdCBzZXRzIHVwIGFuZCBtYW5hZ2VzIEhUVFAgYW5kIEhUVFBTIHNlcnZlcnNcclxuICogZm9yIHRoZSBIaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXIuIEl0IGhhbmRsZXMgc2VydmVyIGluaXRpYWxpemF0aW9uLFxyXG4gKiBjb25maWd1cmF0aW9uLCBlcnJvciBoYW5kbGluZywgbWlkZGxld2FyZXMgc2V0dXAsIHJvdXRlIGRlZmluaXRpb24sIGFuZCByYXRlXHJcbiAqIGxpbWl0aW5nLiBUaGUgbW9kdWxlIGV4cG9ydHMgZnVuY3Rpb25zIHRvIHN0YXJ0LCBzdG9wLCBhbmQgbWFuYWdlIHNlcnZlclxyXG4gKiBpbnN0YW5jZXMsIGFzIHdlbGwgYXMgdXRpbGl0eSBmdW5jdGlvbnMgZm9yIGRlZmluaW5nIHJvdXRlcyBhbmQgYXR0YWNoaW5nXHJcbiAqIG1pZGRsZXdhcmVzLlxyXG4gKi9cclxuXHJcbmltcG9ydCB7IHJlYWRGaWxlU3luYyB9IGZyb20gJ2ZzJztcclxuaW1wb3J0IHsgam9pbiB9IGZyb20gJ3BhdGgnO1xyXG5cclxuaW1wb3J0IGNvcnMgZnJvbSAnY29ycyc7XHJcbmltcG9ydCBleHByZXNzIGZyb20gJ2V4cHJlc3MnO1xyXG5pbXBvcnQgaHR0cCBmcm9tICdodHRwJztcclxuaW1wb3J0IGh0dHBzIGZyb20gJ2h0dHBzJztcclxuaW1wb3J0IG11bHRlciBmcm9tICdtdWx0ZXInO1xyXG5cclxuaW1wb3J0IHsgdXBkYXRlT3B0aW9ucyB9IGZyb20gJy4uL2NvbmZpZy5qcyc7XHJcbmltcG9ydCB7IGxvZywgbG9nV2l0aFN0YWNrIH0gZnJvbSAnLi4vbG9nZ2VyLmpzJztcclxuaW1wb3J0IHsgX19kaXJuYW1lLCBnZXRBYnNvbHV0ZVBhdGggfSBmcm9tICcuLi91dGlscy5qcyc7XHJcblxyXG5pbXBvcnQgZXJyb3JNaWRkbGV3YXJlIGZyb20gJy4vbWlkZGxld2FyZXMvZXJyb3IuanMnO1xyXG5pbXBvcnQgcmF0ZUxpbWl0aW5nTWlkZGxld2FyZSBmcm9tICcuL21pZGRsZXdhcmVzL3JhdGVMaW1pdGluZy5qcyc7XHJcbmltcG9ydCB2YWxpZGF0aW9uTWlkZGxld2FyZSBmcm9tICcuL21pZGRsZXdhcmVzL3ZhbGlkYXRpb24uanMnO1xyXG5cclxuaW1wb3J0IGV4cG9ydFJvdXRlcyBmcm9tICcuL3JvdXRlcy9leHBvcnQuanMnO1xyXG5pbXBvcnQgaGVhbHRoUm91dGVzIGZyb20gJy4vcm91dGVzL2hlYWx0aC5qcyc7XHJcbmltcG9ydCB1aVJvdXRlcyBmcm9tICcuL3JvdXRlcy91aS5qcyc7XHJcbmltcG9ydCB2ZXJzaW9uQ2hhbmdlUm91dGVzIGZyb20gJy4vcm91dGVzL3ZlcnNpb25DaGFuZ2UuanMnO1xyXG5cclxuaW1wb3J0IEV4cG9ydEVycm9yIGZyb20gJy4uL2Vycm9ycy9FeHBvcnRFcnJvci5qcyc7XHJcblxyXG4vLyBBcnJheSBvZiBhbiBhY3RpdmUgc2VydmVyc1xyXG5jb25zdCBhY3RpdmVTZXJ2ZXJzID0gbmV3IE1hcCgpO1xyXG5cclxuLy8gQ3JlYXRlIGV4cHJlc3MgYXBwXHJcbmNvbnN0IGFwcCA9IGV4cHJlc3MoKTtcclxuXHJcbi8qKlxyXG4gKiBTdGFydHMgYW4gSFRUUCBhbmQvb3IgSFRUUFMgc2VydmVyIGJhc2VkIG9uIHRoZSBwcm92aWRlZCBjb25maWd1cmF0aW9uLlxyXG4gKiBUaGUgYHNlcnZlck9wdGlvbnNgIG9iamVjdCBjb250YWlucyBzZXJ2ZXItcmVsYXRlZCBwcm9wZXJ0aWVzIChyZWZlclxyXG4gKiB0byB0aGUgYHNlcnZlcmAgc2VjdGlvbiBpbiB0aGUgYC4vbGliL3NjaGVtYXMvY29uZmlnLmpzYCBmaWxlIGZvciBkZXRhaWxzKS5cclxuICpcclxuICogQGFzeW5jXHJcbiAqIEBmdW5jdGlvbiBzdGFydFNlcnZlclxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gc2VydmVyT3B0aW9ucyAtIFRoZSBjb25maWd1cmF0aW9uIG9iamVjdCBjb250YWluaW5nIGBzZXJ2ZXJgXHJcbiAqIG9wdGlvbnMuIFRoaXMgb2JqZWN0IG1heSBpbmNsdWRlIGEgcGFydGlhbCBvciBjb21wbGV0ZSBzZXQgb2YgdGhlIGBzZXJ2ZXJgXHJcbiAqIG9wdGlvbnMuIElmIHRoZSBvcHRpb25zIGFyZSBwYXJ0aWFsLCBtaXNzaW5nIHZhbHVlcyB3aWxsIGRlZmF1bHRcclxuICogdG8gdGhlIGN1cnJlbnQgZ2xvYmFsIGNvbmZpZ3VyYXRpb24uXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtQcm9taXNlPHZvaWQ+fSBBIFByb21pc2UgdGhhdCByZXNvbHZlcyB3aGVuIHRoZSBzZXJ2ZXIgaXMgZWl0aGVyXHJcbiAqIG5vdCBlbmFibGVkIG9yIG5vIHZhbGlkIEV4cHJlc3MgYXBwIGlzIGZvdW5kLCBzaWduYWxpbmcgdGhlIGVuZCBvZiB0aGVcclxuICogZnVuY3Rpb24ncyBleGVjdXRpb24uXHJcbiAqXHJcbiAqIEB0aHJvd3Mge0V4cG9ydEVycm9yfSBUaHJvd3MgYW4gYEV4cG9ydEVycm9yYCBpZiB0aGUgc2VydmVyIGNhbm5vdFxyXG4gKiBiZSBjb25maWd1cmVkIGFuZCBzdGFydGVkLlxyXG4gKi9cclxuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIHN0YXJ0U2VydmVyKHNlcnZlck9wdGlvbnMpIHtcclxuICB0cnkge1xyXG4gICAgLy8gVXBkYXRlIHRoZSBpbnN0YW5jZSBvcHRpb25zIG9iamVjdFxyXG4gICAgY29uc3Qgb3B0aW9ucyA9IHVwZGF0ZU9wdGlvbnMoe1xyXG4gICAgICBzZXJ2ZXI6IHNlcnZlck9wdGlvbnNcclxuICAgIH0pO1xyXG5cclxuICAgIC8vIFVzZSB2YWxpZGF0ZWQgb3B0aW9uc1xyXG4gICAgc2VydmVyT3B0aW9ucyA9IG9wdGlvbnMuc2VydmVyO1xyXG5cclxuICAgIC8vIFN0b3AgaWYgbm90IGVuYWJsZWRcclxuICAgIGlmICghc2VydmVyT3B0aW9ucy5lbmFibGUgfHwgIWFwcCkge1xyXG4gICAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoXHJcbiAgICAgICAgJ1tzZXJ2ZXJdIFNlcnZlciBjYW5ub3QgYmUgc3RhcnRlZCAobm90IGVuYWJsZWQgb3Igbm8gY29ycmVjdCBFeHByZXNzIGFwcCBmb3VuZCkuJyxcclxuICAgICAgICA1MDBcclxuICAgICAgKTtcclxuICAgIH1cclxuXHJcbiAgICAvLyBUb28gYmlnIGxpbWl0cyBsZWFkIHRvIHRpbWVvdXRzIGluIHRoZSBleHBvcnQgcHJvY2VzcyB3aGVuXHJcbiAgICAvLyB0aGUgcmFzdGVyaXphdGlvbiB0aW1lb3V0IGlzIHNldCB0b28gbG93XHJcbiAgICBjb25zdCB1cGxvYWRMaW1pdEJ5dGVzID0gc2VydmVyT3B0aW9ucy51cGxvYWRMaW1pdCAqIDEwMjQgKiAxMDI0O1xyXG5cclxuICAgIC8vIE1lbW9yeSBzdG9yYWdlIGZvciBtdWx0ZXIgcGFja2FnZVxyXG4gICAgY29uc3Qgc3RvcmFnZSA9IG11bHRlci5tZW1vcnlTdG9yYWdlKCk7XHJcblxyXG4gICAgLy8gRW5hYmxlIHBhcnNpbmcgb2YgZm9ybSBkYXRhIChmaWxlcykgd2l0aCBtdWx0ZXIgcGFja2FnZVxyXG4gICAgY29uc3QgdXBsb2FkID0gbXVsdGVyKHtcclxuICAgICAgc3RvcmFnZSxcclxuICAgICAgbGltaXRzOiB7XHJcbiAgICAgICAgZmllbGRTaXplOiB1cGxvYWRMaW1pdEJ5dGVzXHJcbiAgICAgIH1cclxuICAgIH0pO1xyXG5cclxuICAgIC8vIERpc2FibGUgdGhlIFgtUG93ZXJlZC1CeSBoZWFkZXJcclxuICAgIGFwcC5kaXNhYmxlKCd4LXBvd2VyZWQtYnknKTtcclxuXHJcbiAgICAvLyBFbmFibGUgQ09SUyBzdXBwb3J0XHJcbiAgICBhcHAudXNlKFxyXG4gICAgICBjb3JzKHtcclxuICAgICAgICBtZXRob2RzOiBbJ1BPU1QnLCAnR0VUJywgJ09QVElPTlMnXVxyXG4gICAgICB9KVxyXG4gICAgKTtcclxuXHJcbiAgICAvLyBHZXR0aW5nIGEgbG90IG9mIGBSYW5nZU5vdFNhdGlzZmlhYmxlRXJyb3JgIGV4Y2VwdGlvbnMgKGV2ZW4gdGhvdWdoIHRoaXNcclxuICAgIC8vIGlzIGEgZGVwcmVjYXRlZCBvcHRpb25zLCBsZXQncyB0cnkgdG8gc2V0IGl0IHRvIGZhbHNlKVxyXG4gICAgYXBwLnVzZSgocmVxdWVzdCwgcmVzcG9uc2UsIG5leHQpID0+IHtcclxuICAgICAgcmVzcG9uc2Uuc2V0KCdBY2NlcHQtUmFuZ2VzJywgJ25vbmUnKTtcclxuICAgICAgbmV4dCgpO1xyXG4gICAgfSk7XHJcblxyXG4gICAgLy8gRW5hYmxlIGJvZHkgcGFyc2VyIGZvciBKU09OIGRhdGFcclxuICAgIGFwcC51c2UoXHJcbiAgICAgIGV4cHJlc3MuanNvbih7XHJcbiAgICAgICAgbGltaXQ6IHVwbG9hZExpbWl0Qnl0ZXNcclxuICAgICAgfSlcclxuICAgICk7XHJcblxyXG4gICAgLy8gRW5hYmxlIGJvZHkgcGFyc2VyIGZvciBVUkwtZW5jb2RlZCBmb3JtIGRhdGFcclxuICAgIGFwcC51c2UoXHJcbiAgICAgIGV4cHJlc3MudXJsZW5jb2RlZCh7XHJcbiAgICAgICAgZXh0ZW5kZWQ6IHRydWUsXHJcbiAgICAgICAgbGltaXQ6IHVwbG9hZExpbWl0Qnl0ZXNcclxuICAgICAgfSlcclxuICAgICk7XHJcblxyXG4gICAgLy8gVXNlIG9ubHkgbm9uLWZpbGUgbXVsdGlwYXJ0IGZvcm0gZmllbGRzXHJcbiAgICBhcHAudXNlKHVwbG9hZC5ub25lKCkpO1xyXG5cclxuICAgIC8vIFNldCB1cCBzdGF0aWMgZm9sZGVyJ3Mgcm91dGVcclxuICAgIGFwcC51c2UoZXhwcmVzcy5zdGF0aWMoam9pbihfX2Rpcm5hbWUsICdwdWJsaWMnKSkpO1xyXG5cclxuICAgIC8vIExpc3RlbiBIVFRQIHNlcnZlclxyXG4gICAgaWYgKCFzZXJ2ZXJPcHRpb25zLnNzbC5mb3JjZSkge1xyXG4gICAgICAvLyBNYWluIHNlcnZlciBpbnN0YW5jZSAoSFRUUClcclxuICAgICAgY29uc3QgaHR0cFNlcnZlciA9IGh0dHAuY3JlYXRlU2VydmVyKGFwcCk7XHJcblxyXG4gICAgICAvLyBBdHRhY2ggZXJyb3IgaGFuZGxlcnMgYW5kIGxpc3RlbiB0byB0aGUgc2VydmVyXHJcbiAgICAgIF9hdHRhY2hTZXJ2ZXJFcnJvckhhbmRsZXJzKGh0dHBTZXJ2ZXIpO1xyXG5cclxuICAgICAgLy8gTGlzdGVuXHJcbiAgICAgIGh0dHBTZXJ2ZXIubGlzdGVuKHNlcnZlck9wdGlvbnMucG9ydCwgc2VydmVyT3B0aW9ucy5ob3N0LCAoKSA9PiB7XHJcbiAgICAgICAgLy8gU2F2ZSB0aGUgcmVmZXJlbmNlIHRvIEhUVFAgc2VydmVyXHJcbiAgICAgICAgYWN0aXZlU2VydmVycy5zZXQoc2VydmVyT3B0aW9ucy5wb3J0LCBodHRwU2VydmVyKTtcclxuXHJcbiAgICAgICAgbG9nKFxyXG4gICAgICAgICAgMyxcclxuICAgICAgICAgIGBbc2VydmVyXSBTdGFydGVkIEhUVFAgc2VydmVyIG9uICR7c2VydmVyT3B0aW9ucy5ob3N0fToke3NlcnZlck9wdGlvbnMucG9ydH0uYFxyXG4gICAgICAgICk7XHJcbiAgICAgIH0pO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIExpc3RlbiBIVFRQUyBzZXJ2ZXJcclxuICAgIGlmIChzZXJ2ZXJPcHRpb25zLnNzbC5lbmFibGUpIHtcclxuICAgICAgLy8gU2V0IHVwIGFuIFNTTCBzZXJ2ZXIgYWxzb1xyXG4gICAgICBsZXQga2V5LCBjZXJ0O1xyXG5cclxuICAgICAgdHJ5IHtcclxuICAgICAgICAvLyBHZXQgdGhlIFNTTCBrZXlcclxuICAgICAgICBrZXkgPSByZWFkRmlsZVN5bmMoXHJcbiAgICAgICAgICBqb2luKGdldEFic29sdXRlUGF0aChzZXJ2ZXJPcHRpb25zLnNzbC5jZXJ0UGF0aCksICdzZXJ2ZXIua2V5JyksXHJcbiAgICAgICAgICAndXRmOCdcclxuICAgICAgICApO1xyXG5cclxuICAgICAgICAvLyBHZXQgdGhlIFNTTCBjZXJ0aWZpY2F0ZVxyXG4gICAgICAgIGNlcnQgPSByZWFkRmlsZVN5bmMoXHJcbiAgICAgICAgICBqb2luKGdldEFic29sdXRlUGF0aChzZXJ2ZXJPcHRpb25zLnNzbC5jZXJ0UGF0aCksICdzZXJ2ZXIuY3J0JyksXHJcbiAgICAgICAgICAndXRmOCdcclxuICAgICAgICApO1xyXG4gICAgICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgICAgIGxvZyhcclxuICAgICAgICAgIDIsXHJcbiAgICAgICAgICBgW3NlcnZlcl0gVW5hYmxlIHRvIGxvYWQga2V5L2NlcnRpZmljYXRlIGZyb20gdGhlICcke3NlcnZlck9wdGlvbnMuc3NsLmNlcnRQYXRofScgcGF0aC4gQ291bGQgbm90IHJ1biBzZWN1cmVkIGxheWVyIHNlcnZlci5gXHJcbiAgICAgICAgKTtcclxuICAgICAgfVxyXG5cclxuICAgICAgaWYgKGtleSAmJiBjZXJ0KSB7XHJcbiAgICAgICAgLy8gTWFpbiBzZXJ2ZXIgaW5zdGFuY2UgKEhUVFBTKVxyXG4gICAgICAgIGNvbnN0IGh0dHBzU2VydmVyID0gaHR0cHMuY3JlYXRlU2VydmVyKHsga2V5LCBjZXJ0IH0sIGFwcCk7XHJcblxyXG4gICAgICAgIC8vIEF0dGFjaCBlcnJvciBoYW5kbGVycyBhbmQgbGlzdGVuIHRvIHRoZSBzZXJ2ZXJcclxuICAgICAgICBfYXR0YWNoU2VydmVyRXJyb3JIYW5kbGVycyhodHRwc1NlcnZlcik7XHJcblxyXG4gICAgICAgIC8vIExpc3RlblxyXG4gICAgICAgIGh0dHBzU2VydmVyLmxpc3RlbihzZXJ2ZXJPcHRpb25zLnNzbC5wb3J0LCBzZXJ2ZXJPcHRpb25zLmhvc3QsICgpID0+IHtcclxuICAgICAgICAgIC8vIFNhdmUgdGhlIHJlZmVyZW5jZSB0byBIVFRQUyBzZXJ2ZXJcclxuICAgICAgICAgIGFjdGl2ZVNlcnZlcnMuc2V0KHNlcnZlck9wdGlvbnMuc3NsLnBvcnQsIGh0dHBzU2VydmVyKTtcclxuXHJcbiAgICAgICAgICBsb2coXHJcbiAgICAgICAgICAgIDMsXHJcbiAgICAgICAgICAgIGBbc2VydmVyXSBTdGFydGVkIEhUVFBTIHNlcnZlciBvbiAke3NlcnZlck9wdGlvbnMuaG9zdH06JHtzZXJ2ZXJPcHRpb25zLnNzbC5wb3J0fS5gXHJcbiAgICAgICAgICApO1xyXG4gICAgICAgIH0pO1xyXG4gICAgICB9XHJcbiAgICB9XHJcblxyXG4gICAgLy8gU2V0IHVwIHRoZSByYXRlIGxpbWl0ZXJcclxuICAgIHJhdGVMaW1pdGluZ01pZGRsZXdhcmUoYXBwLCBzZXJ2ZXJPcHRpb25zLnJhdGVMaW1pdGluZyk7XHJcblxyXG4gICAgLy8gU2V0IHVwIHRoZSB2YWxpZGF0aW9uIGhhbmRsZXJcclxuICAgIHZhbGlkYXRpb25NaWRkbGV3YXJlKGFwcCk7XHJcblxyXG4gICAgLy8gU2V0IHVwIHJvdXRlc1xyXG4gICAgZXhwb3J0Um91dGVzKGFwcCk7XHJcbiAgICBoZWFsdGhSb3V0ZXMoYXBwKTtcclxuICAgIHVpUm91dGVzKGFwcCk7XHJcbiAgICB2ZXJzaW9uQ2hhbmdlUm91dGVzKGFwcCk7XHJcblxyXG4gICAgLy8gU2V0IHVwIHRoZSBjZW50cmFsaXplZCBlcnJvciBoYW5kbGVyXHJcbiAgICBlcnJvck1pZGRsZXdhcmUoYXBwKTtcclxuICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgdGhyb3cgbmV3IEV4cG9ydEVycm9yKFxyXG4gICAgICAnW3NlcnZlcl0gQ291bGQgbm90IGNvbmZpZ3VyZSBhbmQgc3RhcnQgdGhlIHNlcnZlci4nLFxyXG4gICAgICA1MDBcclxuICAgICkuc2V0RXJyb3IoZXJyb3IpO1xyXG4gIH1cclxufVxyXG5cclxuLyoqXHJcbiAqIENsb3NlcyBhbGwgc2VydmVycyBhc3NvY2lhdGVkIHdpdGggRXhwcmVzcyBhcHAgaW5zdGFuY2UuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBjbG9zZVNlcnZlcnNcclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiBjbG9zZVNlcnZlcnMoKSB7XHJcbiAgLy8gQ2hlY2sgaWYgdGhlcmUgYXJlIHNlcnZlcnMgd29ya2luZ1xyXG4gIGlmIChhY3RpdmVTZXJ2ZXJzLnNpemUgPiAwKSB7XHJcbiAgICBsb2coNCwgYFtzZXJ2ZXJdIENsb3NpbmcgYWxsIHNlcnZlcnMuYCk7XHJcblxyXG4gICAgLy8gQ2xvc2UgZWFjaCBvbmUgb2Ygc2VydmVyc1xyXG4gICAgZm9yIChjb25zdCBbcG9ydCwgc2VydmVyXSBvZiBhY3RpdmVTZXJ2ZXJzKSB7XHJcbiAgICAgIHNlcnZlci5jbG9zZSgoKSA9PiB7XHJcbiAgICAgICAgYWN0aXZlU2VydmVycy5kZWxldGUocG9ydCk7XHJcbiAgICAgICAgbG9nKDQsIGBbc2VydmVyXSBDbG9zZWQgc2VydmVyIG9uIHBvcnQ6ICR7cG9ydH0uYCk7XHJcbiAgICAgIH0pO1xyXG4gICAgfVxyXG4gIH1cclxufVxyXG5cclxuLyoqXHJcbiAqIEdldCBhbGwgc2VydmVycyBhc3NvY2lhdGVkIHdpdGggRXhwcmVzcyBhcHAgaW5zdGFuY2UuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBnZXRTZXJ2ZXJzXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtBcnJheTxPYmplY3Q+fSBTZXJ2ZXJzIGFzc29jaWF0ZWQgd2l0aCBFeHByZXNzIGFwcCBpbnN0YW5jZS5cclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiBnZXRTZXJ2ZXJzKCkge1xyXG4gIHJldHVybiBhY3RpdmVTZXJ2ZXJzO1xyXG59XHJcblxyXG4vKipcclxuICogR2V0IHRoZSBFeHByZXNzIGluc3RhbmNlLlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gZ2V0RXhwcmVzc1xyXG4gKlxyXG4gKiBAcmV0dXJucyB7RXhwcmVzc30gVGhlIEV4cHJlc3MgaW5zdGFuY2UuXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gZ2V0RXhwcmVzcygpIHtcclxuICByZXR1cm4gZXhwcmVzcztcclxufVxyXG5cclxuLyoqXHJcbiAqIEdldCB0aGUgRXhwcmVzcyBhcHAgaW5zdGFuY2UuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBnZXRBcHBcclxuICpcclxuICogQHJldHVybnMge0V4cHJlc3N9IFRoZSBFeHByZXNzIGFwcCBpbnN0YW5jZS5cclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiBnZXRBcHAoKSB7XHJcbiAgcmV0dXJuIGFwcDtcclxufVxyXG5cclxuLyoqXHJcbiAqIEVuYWJsZSByYXRlIGxpbWl0aW5nIGZvciB0aGUgc2VydmVyLlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gZW5hYmxlUmF0ZUxpbWl0aW5nXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSByYXRlTGltaXRpbmdPcHRpb25zIC0gVGhlIGNvbmZpZ3VyYXRpb24gb2JqZWN0IGNvbnRhaW5pbmdcclxuICogYHJhdGVMaW1pdGluZ2Agb3B0aW9ucy4gVGhpcyBvYmplY3QgbWF5IGluY2x1ZGUgYSBwYXJ0aWFsIG9yIGNvbXBsZXRlIHNldFxyXG4gKiBvZiB0aGUgYHJhdGVMaW1pdGluZ2Agb3B0aW9ucy4gSWYgdGhlIG9wdGlvbnMgYXJlIHBhcnRpYWwsIG1pc3NpbmcgdmFsdWVzXHJcbiAqIHdpbGwgZGVmYXVsdCB0byB0aGUgY3VycmVudCBnbG9iYWwgY29uZmlndXJhdGlvbi5cclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiBlbmFibGVSYXRlTGltaXRpbmcocmF0ZUxpbWl0aW5nT3B0aW9ucykge1xyXG4gIC8vIFVwZGF0ZSB0aGUgaW5zdGFuY2Ugb3B0aW9ucyBvYmplY3RcclxuICBjb25zdCBvcHRpb25zID0gdXBkYXRlT3B0aW9ucyh7XHJcbiAgICBzZXJ2ZXI6IHtcclxuICAgICAgcmF0ZUxpbWl0aW5nOiByYXRlTGltaXRpbmdPcHRpb25zXHJcbiAgICB9XHJcbiAgfSk7XHJcblxyXG4gIC8vIFNldCB0aGUgcmF0ZSBsaW1pdGluZyBvcHRpb25zXHJcbiAgcmF0ZUxpbWl0aW5nTWlkZGxld2FyZShhcHAsIG9wdGlvbnMuc2VydmVyLnJhdGVMaW1pdGluZ09wdGlvbnMpO1xyXG59XHJcblxyXG4vKipcclxuICogQXBwbHkgbWlkZGxld2FyZShzKSB0byBhIHNwZWNpZmljIHBhdGguXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiB1c2VcclxuICpcclxuICogQHBhcmFtIHtzdHJpbmd9IHBhdGggLSBUaGUgcGF0aCB0byB3aGljaCB0aGUgbWlkZGxld2FyZShzKSBzaG91bGQgYmUgYXBwbGllZC5cclxuICogQHBhcmFtIHsuLi5GdW5jdGlvbn0gbWlkZGxld2FyZXMgLSBUaGUgbWlkZGxld2FyZSBmdW5jdGlvbihzKSB0byBiZSBhcHBsaWVkLlxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIHVzZShwYXRoLCAuLi5taWRkbGV3YXJlcykge1xyXG4gIGFwcC51c2UocGF0aCwgLi4ubWlkZGxld2FyZXMpO1xyXG59XHJcblxyXG4vKipcclxuICogU2V0IHVwIGEgcm91dGUgd2l0aCBHRVQgbWV0aG9kIGFuZCBhcHBseSBtaWRkbGV3YXJlKHMpLlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gZ2V0XHJcbiAqXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSBwYXRoIC0gVGhlIHBhdGggdG8gd2hpY2ggdGhlIG1pZGRsZXdhcmUocykgc2hvdWxkIGJlIGFwcGxpZWQuXHJcbiAqIEBwYXJhbSB7Li4uRnVuY3Rpb259IG1pZGRsZXdhcmVzIC0gVGhlIG1pZGRsZXdhcmUgZnVuY3Rpb24ocykgdG8gYmUgYXBwbGllZC5cclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiBnZXQocGF0aCwgLi4ubWlkZGxld2FyZXMpIHtcclxuICBhcHAuZ2V0KHBhdGgsIC4uLm1pZGRsZXdhcmVzKTtcclxufVxyXG5cclxuLyoqXHJcbiAqIFNldCB1cCBhIHJvdXRlIHdpdGggUE9TVCBtZXRob2QgYW5kIGFwcGx5IG1pZGRsZXdhcmUocykuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBwb3N0XHJcbiAqXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSBwYXRoIC0gVGhlIHBhdGggdG8gd2hpY2ggdGhlIG1pZGRsZXdhcmUocykgc2hvdWxkIGJlIGFwcGxpZWQuXHJcbiAqIEBwYXJhbSB7Li4uRnVuY3Rpb259IG1pZGRsZXdhcmVzIC0gVGhlIG1pZGRsZXdhcmUgZnVuY3Rpb24ocykgdG8gYmUgYXBwbGllZC5cclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiBwb3N0KHBhdGgsIC4uLm1pZGRsZXdhcmVzKSB7XHJcbiAgYXBwLnBvc3QocGF0aCwgLi4ubWlkZGxld2FyZXMpO1xyXG59XHJcblxyXG4vKipcclxuICogQXR0YWNoIGVycm9yIGhhbmRsZXJzIHRvIHRoZSBzZXJ2ZXIuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBfYXR0YWNoU2VydmVyRXJyb3JIYW5kbGVyc1xyXG4gKlxyXG4gKiBAcGFyYW0geyhodHRwLlNlcnZlcnxodHRwcy5TZXJ2ZXIpfSBzZXJ2ZXIgLSBUaGUgSFRUUC9IVFRQUyBzZXJ2ZXIgaW5zdGFuY2UuXHJcbiAqL1xyXG5mdW5jdGlvbiBfYXR0YWNoU2VydmVyRXJyb3JIYW5kbGVycyhzZXJ2ZXIpIHtcclxuICBzZXJ2ZXIub24oJ2NsaWVudEVycm9yJywgKGVycm9yLCBzb2NrZXQpID0+IHtcclxuICAgIGxvZ1dpdGhTdGFjayhcclxuICAgICAgMSxcclxuICAgICAgZXJyb3IsXHJcbiAgICAgIGBbc2VydmVyXSBDbGllbnQgZXJyb3I6ICR7ZXJyb3IubWVzc2FnZX0sIGRlc3Ryb3lpbmcgc29ja2V0LmBcclxuICAgICk7XHJcbiAgICBzb2NrZXQuZGVzdHJveSgpO1xyXG4gIH0pO1xyXG5cclxuICBzZXJ2ZXIub24oJ2Vycm9yJywgKGVycm9yKSA9PiB7XHJcbiAgICBsb2dXaXRoU3RhY2soMSwgZXJyb3IsIGBbc2VydmVyXSBTZXJ2ZXIgZXJyb3I6ICR7ZXJyb3IubWVzc2FnZX1gKTtcclxuICB9KTtcclxuXHJcbiAgc2VydmVyLm9uKCdjb25uZWN0aW9uJywgKHNvY2tldCkgPT4ge1xyXG4gICAgc29ja2V0Lm9uKCdlcnJvcicsIChlcnJvcikgPT4ge1xyXG4gICAgICBsb2dXaXRoU3RhY2soMSwgZXJyb3IsIGBbc2VydmVyXSBTb2NrZXQgZXJyb3I6ICR7ZXJyb3IubWVzc2FnZX1gKTtcclxuICAgIH0pO1xyXG4gIH0pO1xyXG59XHJcblxyXG5leHBvcnQgZGVmYXVsdCB7XHJcbiAgc3RhcnRTZXJ2ZXIsXHJcbiAgY2xvc2VTZXJ2ZXJzLFxyXG4gIGdldFNlcnZlcnMsXHJcbiAgZ2V0RXhwcmVzcyxcclxuICBnZXRBcHAsXHJcbiAgZW5hYmxlUmF0ZUxpbWl0aW5nLFxyXG4gIHVzZSxcclxuICBnZXQsXHJcbiAgcG9zdFxyXG59O1xyXG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxyXG5cclxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXHJcblxyXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNSwgSGlnaHNvZnRcclxuXHJcbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cclxuXHJcbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxyXG5cclxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxyXG5cclxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cclxuXHJcbi8qKlxyXG4gKiBAb3ZlcnZpZXcgSGFuZGxlcyBncmFjZWZ1bCBzaHV0ZG93biBvZiB0aGUgSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyLCBlbnN1cmluZ1xyXG4gKiBwcm9wZXIgY2xlYW51cCBvZiByZXNvdXJjZXMgc3VjaCBhcyBicm93c2VyLCBwYWdlcywgc2VydmVycywgYW5kIHRpbWVycy5cclxuICovXHJcblxyXG5pbXBvcnQgeyBraWxsUG9vbCB9IGZyb20gJy4vcG9vbC5qcyc7XHJcbmltcG9ydCB7IGNsZWFyQWxsVGltZXJzIH0gZnJvbSAnLi90aW1lci5qcyc7XHJcblxyXG5pbXBvcnQgeyBjbG9zZVNlcnZlcnMgfSBmcm9tICcuL3NlcnZlci9zZXJ2ZXIuanMnO1xyXG5cclxuLyoqXHJcbiAqIFBlcmZvcm1zIGNsZWFudXAgb3BlcmF0aW9ucyB0byBlbnN1cmUgYSBncmFjZWZ1bCBzaHV0ZG93biBvZiB0aGUgcHJvY2Vzcy5cclxuICogVGhpcyBpbmNsdWRlcyBjbGVhcmluZyBhbGwgcmVnaXN0ZXJlZCB0aW1lb3V0cy9pbnRlcnZhbHMsIGNsb3NpbmcgYWN0aXZlXHJcbiAqIHNlcnZlcnMsIHRlcm1pbmF0aW5nIHJlc291cmNlcyAocGFnZXMpIG9mIHRoZSBwb29sLCBwb29sIGl0c2VsZiwgYW5kIGNsb3NpbmdcclxuICogdGhlIGJyb3dzZXIuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBzaHV0ZG93bkNsZWFuVXBcclxuICpcclxuICogQHBhcmFtIHtudW1iZXJ9IFtleGl0Q29kZT0wXSAtIFRoZSBleGl0IGNvZGUgdG8gdXNlIHdpdGggYHByb2Nlc3MuZXhpdCgpYC5cclxuICogVGhlIGRlZmF1bHQgdmFsdWUgaXMgYDBgLlxyXG4gKi9cclxuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIHNodXRkb3duQ2xlYW5VcChleGl0Q29kZSA9IDApIHtcclxuICAvLyBBd2FpdCBmcmVlaW5nIGFsbCByZXNvdXJjZXNcclxuICBhd2FpdCBQcm9taXNlLmFsbFNldHRsZWQoW1xyXG4gICAgLy8gQ2xlYXIgYWxsIG9uZ29pbmcgaW50ZXJ2YWxzXHJcbiAgICBjbGVhckFsbFRpbWVycygpLFxyXG5cclxuICAgIC8vIEdldCBhdmFpbGFibGUgc2VydmVyIGluc3RhbmNlcyAoSFRUUC9IVFRQUykgYW5kIGNsb3NlIHRoZW1cclxuICAgIGNsb3NlU2VydmVycygpLFxyXG5cclxuICAgIC8vIENsb3NlIGFuIGFjdGl2ZSBwb29sIGFsb25nIHdpdGggaXRzIHdvcmtlcnMgYW5kIHRoZSBicm93c2VyIGluc3RhbmNlXHJcbiAgICBraWxsUG9vbCgpXHJcbiAgXSk7XHJcblxyXG4gIC8vIEV4aXQgcHJvY2VzcyB3aXRoIGEgY29ycmVjdCBjb2RlXHJcbiAgcHJvY2Vzcy5leGl0KGV4aXRDb2RlKTtcclxufVxyXG5cclxuZXhwb3J0IGRlZmF1bHQge1xyXG4gIHNodXRkb3duQ2xlYW5VcFxyXG59O1xyXG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxyXG5cclxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXHJcblxyXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNSwgSGlnaHNvZnRcclxuXHJcbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cclxuXHJcbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxyXG5cclxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxyXG5cclxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cclxuXHJcbi8qKlxyXG4gKiBAb3ZlcnZpZXcgVGhpcyBjb3JlIG1vZHVsZSBpbml0aWFsaXplcyBhbmQgbWFuYWdlcyB0aGUgSGlnaGNoYXJ0cyBFeHBvcnRcclxuICogU2VydmVyLiBUaGUgbWFpbiBgaW5pdEV4cG9ydGAgZnVuY3Rpb24gaGFuZGxlcyBsb2dnaW5nLCBzY3JpcHQgY2FjaGluZyxcclxuICogcmVzb3VyY2UgcG9vbGluZywgYnJvd3NlciBzdGFydHVwLCBhbmQgZW5zdXJlcyBncmFjZWZ1bCBwcm9jZXNzIGNsZWFudXBcclxuICogb24gZXhpdC4gQWRkaXRpb25hbGx5LCBpdCBwcm92aWRlcyBBUEkgZnVuY3Rpb25zIGZvciB1c2luZyBpdCBhcyBhIE5vZGUuanNcclxuICogbW9kdWxlLCBvZmZlcmluZyBmdW5jdGlvbmFsaXRpZXMgZm9yIHByb2Nlc3Npbmcgb3B0aW9ucywgY29uZmlndXJpbmdcclxuICogYW5kIHBlcmZvcm1pbmcgZXhwb3J0cywgYW5kIHNldHRpbmcgdXAgc2VydmVyLlxyXG4gKi9cclxuXHJcbmltcG9ydCAnY29sb3JzJztcclxuXHJcbmltcG9ydCB7IGNoZWNrQ2FjaGUgfSBmcm9tICcuL2NhY2hlLmpzJztcclxuaW1wb3J0IHtcclxuICBiYXRjaEV4cG9ydCxcclxuICBzaW5nbGVFeHBvcnQsXHJcbiAgc3RhcnRFeHBvcnQsXHJcbiAgc2V0QWxsb3dDb2RlRXhlY3V0aW9uXHJcbn0gZnJvbSAnLi9jaGFydC5qcyc7XHJcbmltcG9ydCB7XHJcbiAgZ2V0T3B0aW9ucyxcclxuICB1cGRhdGVPcHRpb25zLFxyXG4gIG1hcFRvTmV3T3B0aW9ucyxcclxuICB2YWxpZGF0ZU9wdGlvbixcclxuICB2YWxpZGF0ZU9wdGlvbnNcclxufSBmcm9tICcuL2NvbmZpZy5qcyc7XHJcbmltcG9ydCB7XHJcbiAgbG9nLFxyXG4gIGxvZ1dpdGhTdGFjayxcclxuICBsb2dab2RJc3N1ZXMsXHJcbiAgaW5pdExvZ2dpbmcsXHJcbiAgZW5hYmxlQ29uc29sZUxvZ2dpbmcsXHJcbiAgZW5hYmxlRmlsZUxvZ2dpbmcsXHJcbiAgc2V0TG9nTGV2ZWxcclxufSBmcm9tICcuL2xvZ2dlci5qcyc7XHJcbmltcG9ydCB7IGluaXRQb29sLCBraWxsUG9vbCB9IGZyb20gJy4vcG9vbC5qcyc7XHJcbmltcG9ydCB7IHNodXRkb3duQ2xlYW5VcCB9IGZyb20gJy4vcmVzb3VyY2VSZWxlYXNlLmpzJztcclxuXHJcbmltcG9ydCBzZXJ2ZXIgZnJvbSAnLi9zZXJ2ZXIvc2VydmVyLmpzJztcclxuXHJcbi8qKlxyXG4gKiBJbml0aWFsaXplcyB0aGUgZXhwb3J0IHByb2Nlc3MuIFRhc2tzIHN1Y2ggYXMgY29uZmlndXJpbmcgbG9nZ2luZywgY2hlY2tpbmdcclxuICogdGhlIGNhY2hlIGFuZCBzb3VyY2VzLCBhbmQgaW5pdGlhbGl6aW5nIHRoZSByZXNvdXJjZSBwb29sIG9jY3VyIGR1cmluZyB0aGlzXHJcbiAqIHN0YWdlLlxyXG4gKlxyXG4gKiBUaGlzIGZ1bmN0aW9uIG11c3QgYmUgY2FsbGVkIGJlZm9yZSBhdHRlbXB0aW5nIHRvIGV4cG9ydCBjaGFydHMgb3Igc2V0XHJcbiAqIHVwIGEgc2VydmVyLlxyXG4gKlxyXG4gKiBAYXN5bmNcclxuICogQGZ1bmN0aW9uIGluaXRFeHBvcnRcclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IGluaXRPcHRpb25zIC0gVGhlIGBpbml0T3B0aW9uc2Agb2JqZWN0LCB3aGljaCBtYXlcclxuICogYmUgYSBwYXJ0aWFsIG9yIGNvbXBsZXRlIHNldCBvZiBvcHRpb25zLiBJZiB0aGUgb3B0aW9ucyBhcmUgcGFydGlhbCwgbWlzc2luZ1xyXG4gKiB2YWx1ZXMgd2lsbCBkZWZhdWx0IHRvIHRoZSBjdXJyZW50IGdsb2JhbCBjb25maWd1cmF0aW9uLlxyXG4gKi9cclxuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIGluaXRFeHBvcnQoaW5pdE9wdGlvbnMpIHtcclxuICAvLyBJbml0LCB2YWxpZGF0ZSBhbmQgdXBkYXRlIHRoZSBvcHRpb25zIG9iamVjdFxyXG4gIGNvbnN0IG9wdGlvbnMgPSB1cGRhdGVPcHRpb25zKGluaXRPcHRpb25zKTtcclxuXHJcbiAgLy8gU2V0IHRoZSBgYWxsb3dDb2RlRXhlY3V0aW9uYCBwZXIgZXhwb3J0IG1vZHVsZSBzY29wZVxyXG4gIHNldEFsbG93Q29kZUV4ZWN1dGlvbihvcHRpb25zLmN1c3RvbUxvZ2ljLmFsbG93Q29kZUV4ZWN1dGlvbik7XHJcblxyXG4gIC8vIEluaXQgdGhlIGxvZ2dpbmdcclxuICBpbml0TG9nZ2luZyhvcHRpb25zLmxvZ2dpbmcpO1xyXG5cclxuICAvLyBBdHRhY2ggcHJvY2VzcycgZXhpdCBsaXN0ZW5lcnNcclxuICBpZiAob3B0aW9ucy5vdGhlci5saXN0ZW5Ub1Byb2Nlc3NFeGl0cykge1xyXG4gICAgX2F0dGFjaFByb2Nlc3NFeGl0TGlzdGVuZXJzKCk7XHJcbiAgfVxyXG5cclxuICAvLyBDaGVjayB0aGUgY3VycmVudCBzdGF0dXMgb2YgY2FjaGVcclxuICBhd2FpdCBjaGVja0NhY2hlKG9wdGlvbnMuaGlnaGNoYXJ0cywgb3B0aW9ucy5zZXJ2ZXIucHJveHkpO1xyXG5cclxuICAvLyBJbml0IHRoZSBwb29sXHJcbiAgYXdhaXQgaW5pdFBvb2wob3B0aW9ucy5wb29sLCBvcHRpb25zLnB1cHBldGVlci5hcmdzKTtcclxufVxyXG5cclxuLyoqXHJcbiAqIEF0dGFjaGVzIGV4aXQgbGlzdGVuZXJzIHRvIHRoZSBwcm9jZXNzLCBlbnN1cmluZyBwcm9wZXIgY2xlYW51cCBvZiByZXNvdXJjZXNcclxuICogYW5kIHRlcm1pbmF0aW9uIG9uIGV4aXQgc2lnbmFscy4gSGFuZGxlcyAnZXhpdCcsICdTSUdJTlQnLCAnU0lHVEVSTScsXHJcbiAqIGFuZCAndW5jYXVnaHRFeGNlcHRpb24nIGV2ZW50cy5cclxuICpcclxuICogQGZ1bmN0aW9uIF9hdHRhY2hQcm9jZXNzRXhpdExpc3RlbmVyc1xyXG4gKi9cclxuZnVuY3Rpb24gX2F0dGFjaFByb2Nlc3NFeGl0TGlzdGVuZXJzKCkge1xyXG4gIGxvZygzLCAnW3Byb2Nlc3NdIEF0dGFjaGluZyBleGl0IGxpc3RlbmVycyB0byB0aGUgcHJvY2Vzcy4nKTtcclxuXHJcbiAgLy8gSGFuZGxlciBmb3IgdGhlICdleGl0J1xyXG4gIHByb2Nlc3Mub24oJ2V4aXQnLCAoY29kZSkgPT4ge1xyXG4gICAgbG9nKDQsIGBbcHJvY2Vzc10gUHJvY2VzcyBleGl0ZWQgd2l0aCBjb2RlOiAke2NvZGV9LmApO1xyXG4gIH0pO1xyXG5cclxuICAvLyBIYW5kbGVyIGZvciB0aGUgJ1NJR0lOVCdcclxuICBwcm9jZXNzLm9uKCdTSUdJTlQnLCBhc3luYyAobmFtZSwgY29kZSkgPT4ge1xyXG4gICAgbG9nKDQsIGBbcHJvY2Vzc10gVGhlICR7bmFtZX0gZXZlbnQgd2l0aCBjb2RlOiAke2NvZGV9LmApO1xyXG4gICAgYXdhaXQgc2h1dGRvd25DbGVhblVwKCk7XHJcbiAgfSk7XHJcblxyXG4gIC8vIEhhbmRsZXIgZm9yIHRoZSAnU0lHVEVSTSdcclxuICBwcm9jZXNzLm9uKCdTSUdURVJNJywgYXN5bmMgKG5hbWUsIGNvZGUpID0+IHtcclxuICAgIGxvZyg0LCBgW3Byb2Nlc3NdIFRoZSAke25hbWV9IGV2ZW50IHdpdGggY29kZTogJHtjb2RlfS5gKTtcclxuICAgIGF3YWl0IHNodXRkb3duQ2xlYW5VcCgpO1xyXG4gIH0pO1xyXG5cclxuICAvLyBIYW5kbGVyIGZvciB0aGUgJ1NJR0hVUCdcclxuICBwcm9jZXNzLm9uKCdTSUdIVVAnLCBhc3luYyAobmFtZSwgY29kZSkgPT4ge1xyXG4gICAgbG9nKDQsIGBbcHJvY2Vzc10gVGhlICR7bmFtZX0gZXZlbnQgd2l0aCBjb2RlOiAke2NvZGV9LmApO1xyXG4gICAgYXdhaXQgc2h1dGRvd25DbGVhblVwKCk7XHJcbiAgfSk7XHJcblxyXG4gIC8vIEhhbmRsZXIgZm9yIHRoZSAndW5jYXVnaHRFeGNlcHRpb24nXHJcbiAgcHJvY2Vzcy5vbigndW5jYXVnaHRFeGNlcHRpb24nLCBhc3luYyAoZXJyb3IsIG5hbWUpID0+IHtcclxuICAgIGxvZ1dpdGhTdGFjaygxLCBlcnJvciwgYFtwcm9jZXNzXSBUaGUgJHtuYW1lfSBlcnJvci5gKTtcclxuICAgIGF3YWl0IHNodXRkb3duQ2xlYW5VcCgxKTtcclxuICB9KTtcclxufVxyXG5cclxuZXhwb3J0IGRlZmF1bHQge1xyXG4gIC8vIFNlcnZlclxyXG4gIC4uLnNlcnZlcixcclxuXHJcbiAgLy8gT3B0aW9uc1xyXG4gIGdldE9wdGlvbnMsXHJcbiAgdXBkYXRlT3B0aW9ucyxcclxuICBtYXBUb05ld09wdGlvbnMsXHJcblxyXG4gIC8vIFZhbGlkYXRpb25cclxuICB2YWxpZGF0ZU9wdGlvbixcclxuICB2YWxpZGF0ZU9wdGlvbnMsXHJcblxyXG4gIC8vIEV4cG9ydGluZ1xyXG4gIGluaXRFeHBvcnQsXHJcbiAgc2luZ2xlRXhwb3J0LFxyXG4gIGJhdGNoRXhwb3J0LFxyXG4gIHN0YXJ0RXhwb3J0LFxyXG5cclxuICAvLyBSZWxlYXNlXHJcbiAga2lsbFBvb2wsXHJcbiAgc2h1dGRvd25DbGVhblVwLFxyXG5cclxuICAvLyBMb2dzXHJcbiAgbG9nLFxyXG4gIGxvZ1dpdGhTdGFjayxcclxuICBsb2dab2RJc3N1ZXMsXHJcbiAgc2V0TG9nTGV2ZWw6IGZ1bmN0aW9uIChsZXZlbCkge1xyXG4gICAgLy8gVXBkYXRlIHRoZSBpbnN0YW5jZSBvcHRpb25zIG9iamVjdFxyXG4gICAgY29uc3Qgb3B0aW9ucyA9IHVwZGF0ZU9wdGlvbnMoe1xyXG4gICAgICBsb2dnaW5nOiB7XHJcbiAgICAgICAgbGV2ZWxcclxuICAgICAgfVxyXG4gICAgfSk7XHJcblxyXG4gICAgLy8gQ2FsbCB0aGUgZnVuY3Rpb25cclxuICAgIHNldExvZ0xldmVsKG9wdGlvbnMubG9nZ2luZy5sZXZlbCk7XHJcbiAgfSxcclxuICBlbmFibGVDb25zb2xlTG9nZ2luZzogZnVuY3Rpb24gKHRvQ29uc29sZSkge1xyXG4gICAgLy8gVXBkYXRlIHRoZSBpbnN0YW5jZSBvcHRpb25zIG9iamVjdFxyXG4gICAgY29uc3Qgb3B0aW9ucyA9IHVwZGF0ZU9wdGlvbnMoe1xyXG4gICAgICBsb2dnaW5nOiB7XHJcbiAgICAgICAgdG9Db25zb2xlXHJcbiAgICAgIH1cclxuICAgIH0pO1xyXG5cclxuICAgIC8vIENhbGwgdGhlIGZ1bmN0aW9uXHJcbiAgICBlbmFibGVDb25zb2xlTG9nZ2luZyhvcHRpb25zLmxvZ2dpbmcudG9Db25zb2xlKTtcclxuICB9LFxyXG4gIGVuYWJsZUZpbGVMb2dnaW5nOiBmdW5jdGlvbiAoZGVzdCwgZmlsZSwgdG9GaWxlKSB7XHJcbiAgICAvLyBVcGRhdGUgdGhlIGluc3RhbmNlIG9wdGlvbnMgb2JqZWN0XHJcbiAgICBjb25zdCBvcHRpb25zID0gdXBkYXRlT3B0aW9ucyh7XHJcbiAgICAgIGxvZ2dpbmc6IHtcclxuICAgICAgICBkZXN0LFxyXG4gICAgICAgIGZpbGUsXHJcbiAgICAgICAgdG9GaWxlXHJcbiAgICAgIH1cclxuICAgIH0pO1xyXG5cclxuICAgIC8vIENhbGwgdGhlIGZ1bmN0aW9uXHJcbiAgICBlbmFibGVGaWxlTG9nZ2luZyhcclxuICAgICAgb3B0aW9ucy5sb2dnaW5nLmRlc3QsXHJcbiAgICAgIG9wdGlvbnMubG9nZ2luZy5maWxlLFxyXG4gICAgICBvcHRpb25zLmxvZ2dpbmcudG9GaWxlXHJcbiAgICApO1xyXG4gIH1cclxufTtcclxuIl0sIm5hbWVzIjpbIl9fZGlybmFtZSIsImZpbGVVUkxUb1BhdGgiLCJVUkwiLCJkb2N1bWVudCIsInJlcXVpcmUiLCJwYXRoVG9GaWxlVVJMIiwiX19maWxlbmFtZSIsImhyZWYiLCJfZG9jdW1lbnRDdXJyZW50U2NyaXB0IiwidGFnTmFtZSIsInRvVXBwZXJDYXNlIiwic3JjIiwiYmFzZVVSSSIsImRlZXBDb3B5Iiwib2JqQXJyIiwib2JqQXJyQ29weSIsIkFycmF5IiwiaXNBcnJheSIsImtleSIsIk9iamVjdCIsInByb3RvdHlwZSIsImhhc093blByb3BlcnR5IiwiY2FsbCIsImdldEFic29sdXRlUGF0aCIsInBhdGgiLCJpc0Fic29sdXRlIiwibm9ybWFsaXplIiwicmVzb2x2ZSIsImdldEJhc2U2NCIsImlucHV0IiwidHlwZSIsIkJ1ZmZlciIsImZyb20iLCJ0b1N0cmluZyIsImdldE5ld0RhdGUiLCJEYXRlIiwic3BsaXQiLCJ0cmltIiwiZ2V0TmV3RGF0ZVRpbWUiLCJnZXRUaW1lIiwiaXNPYmplY3QiLCJpdGVtIiwiaXNPYmplY3RFbXB0eSIsImtleXMiLCJsZW5ndGgiLCJpc1ByaXZhdGVSYW5nZVVybEZvdW5kIiwic29tZSIsInBhdHRlcm4iLCJ0ZXN0IiwibWVhc3VyZVRpbWUiLCJzdGFydCIsInByb2Nlc3MiLCJocnRpbWUiLCJiaWdpbnQiLCJOdW1iZXIiLCJyb3VuZE51bWJlciIsInZhbHVlIiwicHJlY2lzaW9uIiwibXVsdGlwbGllciIsIk1hdGgiLCJwb3ciLCJyb3VuZCIsImNvbG9ycyIsImxvZ2dpbmciLCJ0b0NvbnNvbGUiLCJ0b0ZpbGUiLCJwYXRoQ3JlYXRlZCIsInBhdGhUb0xvZyIsImxldmVsc0Rlc2MiLCJ0aXRsZSIsImNvbG9yIiwibG9nIiwiYXJncyIsIm5ld0xldmVsIiwidGV4dHMiLCJsZXZlbCIsInByZWZpeCIsIl9sb2dUb0ZpbGUiLCJjb25zb2xlIiwiYXBwbHkiLCJ1bmRlZmluZWQiLCJjb25jYXQiLCJsb2dXaXRoU3RhY2siLCJlcnJvciIsImN1c3RvbU1lc3NhZ2UiLCJtYWluTWVzc2FnZSIsIm1lc3NhZ2UiLCJzdGFja01lc3NhZ2UiLCJzdGFjayIsInB1c2giLCJzaGlmdCIsImxvZ1pvZElzc3VlcyIsImlzc3VlcyIsIm1hcCIsImlzc3VlIiwiam9pbiIsImluaXRMb2dnaW5nIiwibG9nZ2luZ09wdGlvbnMiLCJkZXN0IiwiZmlsZSIsInNldExvZ0xldmVsIiwiZW5hYmxlQ29uc29sZUxvZ2dpbmciLCJlbmFibGVGaWxlTG9nZ2luZyIsImlzSW50ZWdlciIsImV4aXN0c1N5bmMiLCJta2RpclN5bmMiLCJhcHBlbmRGaWxlIiwiZGVmYXVsdENvbmZpZyIsInB1cHBldGVlciIsInR5cGVzIiwiZW52TGluayIsImNsaU5hbWUiLCJkZXNjcmlwdGlvbiIsInByb21wdE9wdGlvbnMiLCJzZXBhcmF0b3IiLCJoaWdoY2hhcnRzIiwidmVyc2lvbiIsImNkblVybCIsImZvcmNlRmV0Y2giLCJjYWNoZVBhdGgiLCJjb3JlU2NyaXB0cyIsImluc3RydWN0aW9ucyIsIm1vZHVsZVNjcmlwdHMiLCJpbmRpY2F0b3JTY3JpcHRzIiwiY3VzdG9tU2NyaXB0cyIsImV4cG9ydCIsImluZmlsZSIsImluc3RyIiwib3B0aW9ucyIsInN2ZyIsImJhdGNoIiwib3V0ZmlsZSIsImhpbnQiLCJjaG9pY2VzIiwiY29uc3RyIiwiYjY0Iiwibm9Eb3dubG9hZCIsImhlaWdodCIsIndpZHRoIiwic2NhbGUiLCJkZWZhdWx0SGVpZ2h0IiwiZGVmYXVsdFdpZHRoIiwiZGVmYXVsdFNjYWxlIiwibWluIiwibWF4IiwiZ2xvYmFsT3B0aW9ucyIsInRoZW1lT3B0aW9ucyIsInJhc3Rlcml6YXRpb25UaW1lb3V0IiwiY3VzdG9tTG9naWMiLCJhbGxvd0NvZGVFeGVjdXRpb24iLCJhbGxvd0ZpbGVSZXNvdXJjZXMiLCJjdXN0b21Db2RlIiwiY2FsbGJhY2siLCJyZXNvdXJjZXMiLCJsb2FkQ29uZmlnIiwibGVnYWN5TmFtZSIsImNyZWF0ZUNvbmZpZyIsInNlcnZlciIsImVuYWJsZSIsImhvc3QiLCJwb3J0IiwidXBsb2FkTGltaXQiLCJiZW5jaG1hcmtpbmciLCJwcm94eSIsInRpbWVvdXQiLCJyYXRlTGltaXRpbmciLCJtYXhSZXF1ZXN0cyIsIndpbmRvdyIsImRlbGF5IiwidHJ1c3RQcm94eSIsInNraXBLZXkiLCJza2lwVG9rZW4iLCJzc2wiLCJmb3JjZSIsImNlcnRQYXRoIiwicG9vbCIsIm1pbldvcmtlcnMiLCJtYXhXb3JrZXJzIiwid29ya0xpbWl0IiwiYWNxdWlyZVRpbWVvdXQiLCJjcmVhdGVUaW1lb3V0IiwiZGVzdHJveVRpbWVvdXQiLCJpZGxlVGltZW91dCIsImNyZWF0ZVJldHJ5SW50ZXJ2YWwiLCJyZWFwZXJJbnRlcnZhbCIsInVpIiwicm91dGUiLCJvdGhlciIsIm5vZGVFbnYiLCJsaXN0ZW5Ub1Byb2Nlc3NFeGl0cyIsIm5vTG9nbyIsImhhcmRSZXNldFBhZ2UiLCJicm93c2VyU2hlbGxNb2RlIiwidmFsaWRhdGlvbiIsImRlYnVnIiwiaGVhZGxlc3MiLCJkZXZ0b29scyIsImxpc3RlblRvQ29uc29sZSIsImR1bXBpbyIsInNsb3dNbyIsImRlYnVnZ2luZ1BvcnQiLCJkb3RlbnYiLCJjb25maWciLCJ6Iiwic2V0RXJyb3JNYXAiLCJfY3VzdG9tRXJyb3JNYXAiLCJ2IiwiYm9vbGVhbiIsInN0cmljdENoZWNrIiwidW5pb24iLCJlbnVtIiwidHJhbnNmb3JtIiwiaW5jbHVkZXMiLCJudWxsYWJsZSIsInN0cmluZyIsInJlZmluZSIsInBhcmFtcyIsImVycm9yTWVzc2FnZSIsInZhbHVlcyIsInN0cmluZ0FycmF5IiwiZmlsdGVyQ2FsbGJhY2siLCJhcnJheVNjaGVtYSIsImFycmF5Iiwic3RyaW5nU2NoZW1hIiwic3RhcnRzV2l0aCIsInNsaWNlIiwiZW5kc1dpdGgiLCJ0cmFuc2Zvcm1DYWxsYmFjayIsImZpbHRlciIsInBvc2l0aXZlTnVtIiwibnVtYmVyIiwicG9zaXRpdmUiLCJpc05hTiIsIm5vbk5lZ2F0aXZlTnVtIiwibm9ubmVnYXRpdmUiLCJwcmVmaXhlcyIsImNoYXJ0Q29uZmlnIiwib2JqZWN0IiwicGFzc3Rocm91Z2giLCJhZGRpdGlvbmFsT3B0aW9ucyIsInZhbGlkYXRvcnMiLCJhZG1pblRva2VuIiwiaW5kZXhPZiIsImd0ZSIsImx0ZSIsInRoaXMiLCJvYmplY3RTY2hlbWEiLCJqcyIsImNzcyIsImZpbGVzIiwicGFydGlhbCIsInN0cmluZ1NjaGVtYTEiLCJzdHJpbmdTY2hlbWEyIiwiZW5hYmxlU2VydmVyIiwic2VydmVyQmVuY2htYXJraW5nIiwicHJveHlIb3N0IiwicHJveHlQb3J0IiwicHJveHlUaW1lb3V0IiwiZW5hYmxlUmF0ZUxpbWl0aW5nIiwiZW5hYmxlU3NsIiwic3NsRm9yY2UiLCJzc2xQb3J0Iiwic3NsQ2VydFBhdGgiLCJwb29sQmVuY2htYXJraW5nIiwicmVzb3VyY2VzSW50ZXJ2YWwiLCJsb2dMZXZlbCIsImludCIsImxvZ0ZpbGUiLCJsb2dEZXN0IiwibG9nVG9Db25zb2xlIiwibG9nVG9GaWxlIiwiZW5hYmxlVWkiLCJ1aVJvdXRlIiwiZW5hYmxlRGVidWciLCJyZXF1ZXN0SWQiLCJ1dWlkIiwiUHVwcGV0ZWVyU2NoZW1hIiwiSGlnaGNoYXJ0c1NjaGVtYSIsIkV4cG9ydFNjaGVtYSIsIkN1c3RvbUxvZ2ljU2NoZW1hIiwiUHJveHlTY2hlbWEiLCJSYXRlTGltaXRpbmdTY2hlbWEiLCJTc2xTY2hlbWEiLCJTZXJ2ZXJTY2hlbWEiLCJvcHRpb25hbCIsIlBvb2xTY2hlbWEiLCJMb2dnaW5nU2NoZW1hIiwiVWlTY2hlbWEiLCJPdGhlclNjaGVtYSIsIkRlYnVnU2NoZW1hIiwiU3RyaWN0Q29uZmlnU2NoZW1hIiwiTG9vc2VDb25maWdTY2hlbWEiLCJFbnZTY2hlbWEiLCJQVVBQRVRFRVJfQVJHUyIsIkhJR0hDSEFSVFNfVkVSU0lPTiIsIkhJR0hDSEFSVFNfQ0ROX1VSTCIsIkhJR0hDSEFSVFNfRk9SQ0VfRkVUQ0giLCJISUdIQ0hBUlRTX0NBQ0hFX1BBVEgiLCJISUdIQ0hBUlRTX0FETUlOX1RPS0VOIiwiSElHSENIQVJUU19DT1JFX1NDUklQVFMiLCJISUdIQ0hBUlRTX01PRFVMRV9TQ1JJUFRTIiwiSElHSENIQVJUU19JTkRJQ0FUT1JfU0NSSVBUUyIsIkhJR0hDSEFSVFNfQ1VTVE9NX1NDUklQVFMiLCJFWFBPUlRfSU5GSUxFIiwiRVhQT1JUX0lOU1RSIiwiRVhQT1JUX09QVElPTlMiLCJFWFBPUlRfU1ZHIiwiRVhQT1JUX0JBVENIIiwiRVhQT1JUX09VVEZJTEUiLCJFWFBPUlRfVFlQRSIsIkVYUE9SVF9DT05TVFIiLCJFWFBPUlRfQjY0IiwiRVhQT1JUX05PX0RPV05MT0FEIiwiRVhQT1JUX0hFSUdIVCIsIkVYUE9SVF9XSURUSCIsIkVYUE9SVF9TQ0FMRSIsIkVYUE9SVF9ERUZBVUxUX0hFSUdIVCIsIkVYUE9SVF9ERUZBVUxUX1dJRFRIIiwiRVhQT1JUX0RFRkFVTFRfU0NBTEUiLCJFWFBPUlRfR0xPQkFMX09QVElPTlMiLCJFWFBPUlRfVEhFTUVfT1BUSU9OUyIsIkVYUE9SVF9SQVNURVJJWkFUSU9OX1RJTUVPVVQiLCJDVVNUT01fTE9HSUNfQUxMT1dfQ09ERV9FWEVDVVRJT04iLCJDVVNUT01fTE9HSUNfQUxMT1dfRklMRV9SRVNPVVJDRVMiLCJDVVNUT01fTE9HSUNfQ1VTVE9NX0NPREUiLCJDVVNUT01fTE9HSUNfQ0FMTEJBQ0siLCJDVVNUT01fTE9HSUNfUkVTT1VSQ0VTIiwiQ1VTVE9NX0xPR0lDX0xPQURfQ09ORklHIiwiQ1VTVE9NX0xPR0lDX0NSRUFURV9DT05GSUciLCJTRVJWRVJfRU5BQkxFIiwiU0VSVkVSX0hPU1QiLCJTRVJWRVJfUE9SVCIsIlNFUlZFUl9VUExPQURfTElNSVQiLCJTRVJWRVJfQkVOQ0hNQVJLSU5HIiwiU0VSVkVSX1BST1hZX0hPU1QiLCJTRVJWRVJfUFJPWFlfUE9SVCIsIlNFUlZFUl9QUk9YWV9USU1FT1VUIiwiU0VSVkVSX1JBVEVfTElNSVRJTkdfRU5BQkxFIiwiU0VSVkVSX1JBVEVfTElNSVRJTkdfTUFYX1JFUVVFU1RTIiwiU0VSVkVSX1JBVEVfTElNSVRJTkdfV0lORE9XIiwiU0VSVkVSX1JBVEVfTElNSVRJTkdfREVMQVkiLCJTRVJWRVJfUkFURV9MSU1JVElOR19UUlVTVF9QUk9YWSIsIlNFUlZFUl9SQVRFX0xJTUlUSU5HX1NLSVBfS0VZIiwiU0VSVkVSX1JBVEVfTElNSVRJTkdfU0tJUF9UT0tFTiIsIlNFUlZFUl9TU0xfRU5BQkxFIiwiU0VSVkVSX1NTTF9GT1JDRSIsIlNFUlZFUl9TU0xfUE9SVCIsIlNFUlZFUl9TU0xfQ0VSVF9QQVRIIiwiUE9PTF9NSU5fV09SS0VSUyIsIlBPT0xfTUFYX1dPUktFUlMiLCJQT09MX1dPUktfTElNSVQiLCJQT09MX0FDUVVJUkVfVElNRU9VVCIsIlBPT0xfQ1JFQVRFX1RJTUVPVVQiLCJQT09MX0RFU1RST1lfVElNRU9VVCIsIlBPT0xfSURMRV9USU1FT1VUIiwiUE9PTF9DUkVBVEVfUkVUUllfSU5URVJWQUwiLCJQT09MX1JFQVBFUl9JTlRFUlZBTCIsIlBPT0xfQkVOQ0hNQVJLSU5HIiwiTE9HR0lOR19MRVZFTCIsIkxPR0dJTkdfRklMRSIsIkxPR0dJTkdfREVTVCIsIkxPR0dJTkdfVE9fQ09OU09MRSIsIkxPR0dJTkdfVE9fRklMRSIsIlVJX0VOQUJMRSIsIlVJX1JPVVRFIiwiT1RIRVJfTk9ERV9FTlYiLCJPVEhFUl9MSVNURU5fVE9fUFJPQ0VTU19FWElUUyIsIk9USEVSX05PX0xPR08iLCJPVEhFUl9IQVJEX1JFU0VUX1BBR0UiLCJPVEhFUl9CUk9XU0VSX1NIRUxMX01PREUiLCJPVEhFUl9WQUxJREFUSU9OIiwiREVCVUdfRU5BQkxFIiwiREVCVUdfSEVBRExFU1MiLCJERUJVR19ERVZUT09MUyIsIkRFQlVHX0xJU1RFTl9UT19DT05TT0xFIiwiREVCVUdfRFVNUElPIiwiREVCVUdfU0xPV19NTyIsIkRFQlVHX0RFQlVHR0lOR19QT1JUIiwiZW52cyIsInBhcnNlIiwiZW52Iiwic3RyaWN0VmFsaWRhdGUiLCJjb25maWdPcHRpb25zIiwibG9vc2VWYWxpZGF0ZSIsImNvbnRleHQiLCJwcm9wZXJ0eU5hbWUiLCJwcm9wZXJ0eUluZm8iLCJjb2RlIiwiWm9kSXNzdWVDb2RlIiwiaW52YWxpZF90eXBlIiwicmVjZWl2ZWQiLCJab2RQYXJzZWRUeXBlIiwiZGVmYXVsdEVycm9yIiwiY3VzdG9tIiwiZGF0YSIsImludmFsaWRfdW5pb24iLCJ1bmlvbkVycm9ycyIsImZvckVhY2giLCJpbmRleCIsInN1YnN0cmluZyIsIkV4cG9ydEVycm9yIiwiRXJyb3IiLCJjb25zdHJ1Y3RvciIsInN0YXR1c0NvZGUiLCJzdXBlciIsInNldEVycm9yIiwibmFtZSIsIl9pbml0T3B0aW9ucyIsIm5lc3RlZFByb3BzIiwiX2NyZWF0ZU5lc3RlZFByb3BzIiwiYWJzb2x1dGVQcm9wcyIsIl9jcmVhdGVBYnNvbHV0ZVByb3BzIiwiZ2V0T3B0aW9ucyIsImdldENvcHkiLCJ1cGRhdGVPcHRpb25zIiwibmV3T3B0aW9ucyIsIl9tZXJnZU9wdGlvbnMiLCJ2YWxpZGF0ZU9wdGlvbnMiLCJtYXBUb05ld09wdGlvbnMiLCJvbGRPcHRpb25zIiwiZW50cmllcyIsInByb3BlcnRpZXNDaGFpbiIsInJlZHVjZSIsIm9iaiIsInByb3AiLCJ2YWxpZGF0ZU9wdGlvbiIsImNvbmZpZ09wdGlvbiIsImlzQWxsb3dlZENvbmZpZyIsImFsbG93RnVuY3Rpb25zIiwib2JqZWN0Q29uZmlnIiwiZXZhbCIsIkpTT04iLCJzdHJpbmdpZmllZE9wdGlvbnMiLCJfb3B0aW9uc1N0cmluZ2lmeSIsInBhcnNlZE9wdGlvbnMiLCJfIiwib3JpZ2luYWxPcHRpb25zIiwic3RyaW5naWZ5RnVuY3Rpb25zIiwic3RyaW5naWZ5IiwicmVwbGFjZUFsbCIsInByb3BDaGFpbiIsImVudHJ5IiwiYXN5bmMiLCJnZXQiLCJ1cmwiLCJyZXF1ZXN0T3B0aW9ucyIsIlByb21pc2UiLCJyZWplY3QiLCJfZ2V0UHJvdG9jb2xNb2R1bGUiLCJyZXNwb25zZSIsInJlc3BvbnNlRGF0YSIsIm9uIiwiY2h1bmsiLCJ0ZXh0IiwiaHR0cHMiLCJodHRwIiwiY2FjaGUiLCJhY3RpdmVNYW5pZmVzdCIsInNvdXJjZXMiLCJoY1ZlcnNpb24iLCJjaGVja0NhY2hlIiwiaGlnaGNoYXJ0c09wdGlvbnMiLCJzZXJ2ZXJQcm94eU9wdGlvbnMiLCJmZXRjaGVkTW9kdWxlcyIsImdldENhY2hlUGF0aCIsIm1hbmlmZXN0UGF0aCIsInNvdXJjZVBhdGgiLCJyZWN1cnNpdmUiLCJfdXBkYXRlQ2FjaGUiLCJyZXF1ZXN0VXBkYXRlIiwibWFuaWZlc3QiLCJyZWFkRmlsZVN5bmMiLCJtb2R1bGVzIiwibW9kdWxlTWFwIiwibSIsIm51bWJlck9mTW9kdWxlcyIsIm1vZHVsZU5hbWUiLCJfZXh0cmFjdEhjVmVyc2lvbiIsIl9zYXZlQ29uZmlnVG9NYW5pZmVzdCIsImdldEhjVmVyc2lvbiIsInVwZGF0ZUhjVmVyc2lvbiIsIm5ld1ZlcnNpb24iLCJ3cml0ZUZpbGVTeW5jIiwiX2NvbmZpZ3VyZVJlcXVlc3QiLCJhbGwiLCJjcyIsIl9mZXRjaFNjcmlwdCIsIm1zIiwiaXMiLCJzY3JpcHQiLCJzaG91bGRUaHJvd0Vycm9yIiwiX2V4dHJhY3RNb2R1bGVOYW1lIiwiYWdlbnQiLCJIdHRwc1Byb3h5QWdlbnQiLCJjYWNoZVNvdXJjZXMiLCJyZXBsYWNlIiwic2NyaXB0UGF0aCIsInNldHVwSGlnaGNoYXJ0cyIsIkhpZ2hjaGFydHMiLCJhbmltT2JqZWN0IiwiZHVyYXRpb24iLCJjcmVhdGVDaGFydCIsImV4cG9ydE9wdGlvbnMiLCJjdXN0b21Mb2dpY09wdGlvbnMiLCJzZXRPcHRpb25zIiwibWVyZ2UiLCJ3cmFwIiwic2V0T3B0aW9uc09iaiIsImlzUmVuZGVyQ29tcGxldGUiLCJDaGFydCIsInByb2NlZWQiLCJ1c2VyT3B0aW9ucyIsImNiIiwiZXhwb3J0aW5nIiwiZW5hYmxlZCIsInBsb3RPcHRpb25zIiwic2VyaWVzIiwibGFiZWwiLCJ0b29sdGlwIiwiYW5pbWF0aW9uIiwib25IaWdoY2hhcnRzUmVuZGVyIiwiYWRkRXZlbnQiLCJTZXJpZXMiLCJjaGFydCIsIkZ1bmN0aW9uIiwiZmluYWxPcHRpb25zIiwiZmluYWxDYWxsYmFjayIsImltYWdlcyIsInF1ZXJ5U2VsZWN0b3JBbGwiLCJyYWNlIiwiaW1hZ2UiLCJjb21wbGV0ZSIsIm5hdHVyYWxIZWlnaHQiLCJhZGRFdmVudExpc3RlbmVyIiwib25jZSIsInNldFRpbWVvdXQiLCJkZWZhdWx0T3B0aW9ucyIsInBhZ2VUZW1wbGF0ZSIsImJyb3dzZXIiLCJjcmVhdGVCcm93c2VyIiwicHVwcGV0ZWVyQXJncyIsImVuYWJsZWREZWJ1ZyIsImRlYnVnT3B0aW9ucyIsImxhdW5jaE9wdGlvbnMiLCJ1c2VyRGF0YURpciIsImhhbmRsZVNJR0lOVCIsImhhbmRsZVNJR1RFUk0iLCJoYW5kbGVTSUdIVVAiLCJ3YWl0Rm9ySW5pdGlhbFBhZ2UiLCJkZWZhdWx0Vmlld3BvcnQiLCJ0cnlDb3VudCIsIm9wZW5Ccm93c2VyIiwibGF1bmNoIiwiY2xvc2VCcm93c2VyIiwiY29ubmVjdGVkIiwiY2xvc2UiLCJuZXdQYWdlIiwicG9vbFJlc291cmNlIiwicGFnZSIsInNldENhY2hlRW5hYmxlZCIsIl9zZXRQYWdlQ29udGVudCIsIl9zZXRQYWdlRXZlbnRzIiwiaXNDbG9zZWQiLCJjbGVhclBhZ2UiLCJoYXJkUmVzZXQiLCJnb3RvIiwid2FpdFVudGlsIiwiZXZhbHVhdGUiLCJib2R5IiwiaW5uZXJIVE1MIiwiaWQiLCJ3b3JrQ291bnQiLCJhZGRQYWdlUmVzb3VyY2VzIiwiaW5qZWN0ZWRSZXNvdXJjZXMiLCJpbmplY3RlZEpzIiwiY29udGVudCIsImlzTG9jYWwiLCJqc1Jlc291cmNlIiwiYWRkU2NyaXB0VGFnIiwiaW5qZWN0ZWRDc3MiLCJjc3NJbXBvcnRzIiwibWF0Y2giLCJjc3NJbXBvcnRQYXRoIiwiY3NzUmVzb3VyY2UiLCJhZGRTdHlsZVRhZyIsImNsZWFyUGFnZVJlc291cmNlcyIsInJlc291cmNlIiwiZGlzcG9zZSIsIm9sZENoYXJ0cyIsImNoYXJ0cyIsIm9sZENoYXJ0IiwiZGVzdHJveSIsInNjcmlwdHNUb1JlbW92ZSIsImdldEVsZW1lbnRzQnlUYWdOYW1lIiwic3R5bGVzVG9SZW1vdmUiLCJsaW5rc1RvUmVtb3ZlIiwiZWxlbWVudCIsInJlbW92ZSIsInNldENvbnRlbnQiLCJjc3NUZW1wbGF0ZSIsInN2Z1RlbXBsYXRlIiwicHVwcGV0ZWVyRXhwb3J0IiwiaXNTVkciLCJzaXplIiwiX2dldENoYXJ0U2l6ZSIsIngiLCJ5IiwiX2dldENsaXBSZWdpb24iLCJ2aWV3cG9ydEhlaWdodCIsImFicyIsImNlaWwiLCJjaGFydEhlaWdodCIsInZpZXdwb3J0V2lkdGgiLCJjaGFydFdpZHRoIiwicmVzdWx0Iiwic2V0Vmlld3BvcnQiLCJkZXZpY2VTY2FsZUZhY3RvciIsInBhcnNlRmxvYXQiLCJfY3JlYXRlU1ZHIiwiX2NyZWF0ZUltYWdlIiwiX2NyZWF0ZVBERiIsIiRldmFsIiwiZ2V0Qm91bmRpbmdDbGllbnRSZWN0IiwidHJ1bmMiLCJzdmdFbGVtZW50IiwicXVlcnlTZWxlY3RvciIsImJhc2VWYWwiLCJzdHlsZSIsInpvb20iLCJtYXJnaW4iLCJvdXRlckhUTUwiLCJjbGlwIiwic2NyZWVuc2hvdCIsImVuY29kaW5nIiwiZnVsbFBhZ2UiLCJvcHRpbWl6ZUZvclNwZWVkIiwiY2FwdHVyZUJleW9uZFZpZXdwb3J0IiwicXVhbGl0eSIsIm9taXRCYWNrZ3JvdW5kIiwiX3Jlc29sdmUiLCJlbXVsYXRlTWVkaWFUeXBlIiwicGRmIiwicG9vbFN0YXRzIiwiZXhwb3J0c0F0dGVtcHRlZCIsImV4cG9ydHNQZXJmb3JtZWQiLCJleHBvcnRzRHJvcHBlZCIsImV4cG9ydHNGcm9tU3ZnIiwiZXhwb3J0c0Zyb21PcHRpb25zIiwiZXhwb3J0c0Zyb21TdmdBdHRlbXB0cyIsImV4cG9ydHNGcm9tT3B0aW9uc0F0dGVtcHRzIiwidGltZVNwZW50IiwidGltZVNwZW50QXZlcmFnZSIsImluaXRQb29sIiwicG9vbE9wdGlvbnMiLCJQb29sIiwiX2ZhY3RvcnkiLCJhY3F1aXJlVGltZW91dE1pbGxpcyIsImNyZWF0ZVRpbWVvdXRNaWxsaXMiLCJkZXN0cm95VGltZW91dE1pbGxpcyIsImlkbGVUaW1lb3V0TWlsbGlzIiwiY3JlYXRlUmV0cnlJbnRlcnZhbE1pbGxpcyIsInJlYXBJbnRlcnZhbE1pbGxpcyIsInByb3BhZ2F0ZUNyZWF0ZUVycm9yIiwiY2xlYXJTdGF0dXMiLCJfZXZlbnRJZCIsImluaXRpYWxSZXNvdXJjZXMiLCJpIiwiYWNxdWlyZSIsInByb21pc2UiLCJyZWxlYXNlIiwia2lsbFBvb2wiLCJ3b3JrZXIiLCJ1c2VkIiwiZGVzdHJveWVkIiwicG9zdFdvcmsiLCJ3b3JrZXJIYW5kbGUiLCJfZ2V0UG9vbEluZm8iLCJhY3F1aXJlQ291bnRlciIsImV4cG9ydENvdW50ZXIiLCJleHBvcnRSZXN1bHQiLCJnZXRQb29sU3RhdHMiLCJnZXRQb29sSW5mb0pTT04iLCJudW1Vc2VkIiwiYXZhaWxhYmxlIiwibnVtRnJlZSIsImFsbENyZWF0ZWQiLCJwZW5kaW5nQWNxdWlyZXMiLCJudW1QZW5kaW5nQWNxdWlyZXMiLCJwZW5kaW5nQ3JlYXRlcyIsIm51bVBlbmRpbmdDcmVhdGVzIiwicGVuZGluZ1ZhbGlkYXRpb25zIiwibnVtUGVuZGluZ1ZhbGlkYXRpb25zIiwicGVuZGluZ0Rlc3Ryb3lzIiwiYWJzb2x1dGVBbGwiLCJjcmVhdGUiLCJyYW5kb20iLCJzdGFydERhdGUiLCJ2YWxpZGF0ZSIsIm1haW5GcmFtZSIsImRldGFjaGVkIiwicmVtb3ZlQWxsTGlzdGVuZXJzIiwic2FuaXRpemUiLCJKU0RPTSIsIkRPTVB1cmlmeSIsIkFERF9UQUdTIiwic2luZ2xlRXhwb3J0Iiwic3RhcnRFeHBvcnQiLCJiYXRjaEV4cG9ydCIsImJhdGNoRnVuY3Rpb25zIiwicGFpciIsImJhdGNoUmVzdWx0cyIsImFsbFNldHRsZWQiLCJyZWFzb24iLCJpbWFnZU9wdGlvbnMiLCJlbmRDYWxsYmFjayIsImZpbGVDb250ZW50IiwiX2V4cG9ydEZyb21TdmciLCJfZXhwb3J0RnJvbU9wdGlvbnMiLCJnZXRBbGxvd0NvZGVFeGVjdXRpb24iLCJzZXRBbGxvd0NvZGVFeGVjdXRpb24iLCJpbnB1dFRvRXhwb3J0IiwiX3ByZXBhcmVFeHBvcnQiLCJfZml4Q29uc3RyIiwiX2ZpeFR5cGUiLCJfZml4T3V0ZmlsZSIsIl9oYW5kbGVDdXN0b21Mb2dpYyIsIl9oYW5kbGVHbG9iYWxBbmRUaGVtZSIsIl9oYW5kbGVTaXplIiwiX2NoZWNrRGF0YVNpemUiLCJmaXhlZENvbnN0ciIsInRvTG93ZXJDYXNlIiwibWltZVR5cGVzIiwiZm9ybWF0cyIsIm91dFR5cGUiLCJwb3AiLCJmaW5kIiwidCIsIm9wdGlvbnNDaGFydCIsIm9wdGlvbnNFeHBvcnRpbmciLCJnbG9iYWxPcHRpb25zQ2hhcnQiLCJnbG9iYWxPcHRpb25zRXhwb3J0aW5nIiwidGhlbWVPcHRpb25zQ2hhcnQiLCJ0aGVtZU9wdGlvbnNFeHBvcnRpbmciLCJzb3VyY2VIZWlnaHQiLCJzb3VyY2VXaWR0aCIsInBhcmFtIiwiX2hhbmRsZVJlc291cmNlcyIsIl9oYW5kbGVDdXN0b21Db2RlIiwiaGFuZGxlZFJlc291cmNlcyIsImFsbG93ZWRQcm9wcyIsImNvcnJlY3RSZXNvdXJjZXMiLCJwcm9wTmFtZSIsImlzQ2FsbGJhY2siLCJvcHRpb25zTmFtZSIsInRvdGFsU2l6ZSIsImJ5dGVMZW5ndGgiLCJ0b0ZpeGVkIiwidGltZXJJZHMiLCJhZGRUaW1lciIsImNsZWFyQWxsVGltZXJzIiwiY2xlYXJJbnRlcnZhbCIsImNsZWFyVGltZW91dCIsImxvZ0Vycm9yTWlkZGxld2FyZSIsInJlcXVlc3QiLCJuZXh0IiwicmV0dXJuRXJyb3JNaWRkbGV3YXJlIiwic3RhdHVzIiwianNvbiIsImVycm9yTWlkZGxld2FyZSIsImFwcCIsInVzZSIsInJhdGVMaW1pdGluZ01pZGRsZXdhcmUiLCJyYXRlTGltaXRpbmdPcHRpb25zIiwicmF0ZU9wdGlvbnMiLCJsaW1pdGVyIiwicmF0ZUxpbWl0Iiwid2luZG93TXMiLCJsaW1pdCIsImRlbGF5TXMiLCJoYW5kbGVyIiwiZm9ybWF0Iiwic2VuZCIsImRlZmF1bHQiLCJza2lwIiwicXVlcnkiLCJhY2Nlc3NfdG9rZW4iLCJjb250ZW50VHlwZU1pZGRsZXdhcmUiLCJjb250ZW50VHlwZSIsImhlYWRlcnMiLCJyZXF1ZXN0Qm9keU1pZGRsZXdhcmUiLCJjb25uZWN0aW9uIiwicmVtb3RlQWRkcmVzcyIsInZhbGlkYXRlZE9wdGlvbnMiLCJmaWxlbmFtZSIsInZhbGlkYXRpb25NaWRkbGV3YXJlIiwicG9zdCIsInJldmVyc2VkTWltZSIsInBuZyIsImpwZWciLCJnaWYiLCJyZXF1ZXN0RXhwb3J0IiwicmVxdWVzdENvdW50ZXIiLCJjb25uZWN0aW9uQWJvcnRlZCIsInNvY2tldCIsImhhZEVycm9ycyIsImhlYWRlciIsImF0dGFjaG1lbnQiLCJleHBvcnRSb3V0ZXMiLCJzZXJ2ZXJTdGFydFRpbWUiLCJwYWNrYWdlRmlsZSIsInN1Y2Nlc3NSYXRlcyIsInJlY29yZEludGVydmFsIiwid2luZG93U2l6ZSIsIl9jYWxjdWxhdGVNb3ZpbmdBdmVyYWdlIiwiYSIsImIiLCJfc3RhcnRTdWNjZXNzUmF0ZSIsInNldEludGVydmFsIiwic3RhdHMiLCJzdWNjZXNzUmF0aW8iLCJoZWFsdGhSb3V0ZXMiLCJwZXJpb2QiLCJtb3ZpbmdBdmVyYWdlIiwiYm9vdFRpbWUiLCJ1cHRpbWUiLCJmbG9vciIsInNlcnZlclZlcnNpb24iLCJoaWdoY2hhcnRzVmVyc2lvbiIsImF2ZXJhZ2VFeHBvcnRUaW1lIiwiYXR0ZW1wdGVkRXhwb3J0cyIsInBlcmZvcm1lZEV4cG9ydHMiLCJmYWlsZWRFeHBvcnRzIiwic3VjZXNzUmF0aW8iLCJzdmdFeHBvcnRzIiwianNvbkV4cG9ydHMiLCJzdmdFeHBvcnRzQXR0ZW1wdHMiLCJqc29uRXhwb3J0c0F0dGVtcHRzIiwidWlSb3V0ZXMiLCJzZW5kRmlsZSIsImFjY2VwdFJhbmdlcyIsInZlcnNpb25DaGFuZ2VSb3V0ZXMiLCJ0b2tlbiIsImFjdGl2ZVNlcnZlcnMiLCJNYXAiLCJleHByZXNzIiwic3RhcnRTZXJ2ZXIiLCJzZXJ2ZXJPcHRpb25zIiwidXBsb2FkTGltaXRCeXRlcyIsInN0b3JhZ2UiLCJtdWx0ZXIiLCJtZW1vcnlTdG9yYWdlIiwidXBsb2FkIiwibGltaXRzIiwiZmllbGRTaXplIiwiZGlzYWJsZSIsImNvcnMiLCJtZXRob2RzIiwic2V0IiwidXJsZW5jb2RlZCIsImV4dGVuZGVkIiwibm9uZSIsInN0YXRpYyIsImh0dHBTZXJ2ZXIiLCJjcmVhdGVTZXJ2ZXIiLCJfYXR0YWNoU2VydmVyRXJyb3JIYW5kbGVycyIsImxpc3RlbiIsImNlcnQiLCJodHRwc1NlcnZlciIsImNsb3NlU2VydmVycyIsImRlbGV0ZSIsImdldFNlcnZlcnMiLCJnZXRFeHByZXNzIiwiZ2V0QXBwIiwibWlkZGxld2FyZXMiLCJzaHV0ZG93bkNsZWFuVXAiLCJleGl0Q29kZSIsImV4aXQiLCJpbml0RXhwb3J0IiwiaW5pdE9wdGlvbnMiLCJfYXR0YWNoUHJvY2Vzc0V4aXRMaXN0ZW5lcnMiXSwibWFwcGluZ3MiOiJ3bEJBMEJPLE1BQU1BLFlBQVlDLElBQWFBLGNBQUMsSUFBSUMsSUFBSSxPQUFRLG9CQUFBQyxTQUFBQyxRQUFBLE9BQUFDLGNBQUFDLFlBQUFDLEtBQUFDLHdCQUFBLFdBQUFBLHVCQUFBQyxRQUFBQyxlQUFBRix1QkFBQUcsS0FBQSxJQUFBVCxJQUFBLFlBQUFDLFNBQUFTLFNBQUFMLE9BK0JoRCxTQUFTTSxTQUFTQyxHQUV2QixHQUFlLE9BQVhBLEdBQXFDLGlCQUFYQSxFQUM1QixPQUFPQSxFQUlULE1BQU1DLEVBQWFDLE1BQU1DLFFBQVFILEdBQVUsR0FBSyxHQUdoRCxJQUFLLE1BQU1JLEtBQU9KLEVBQ1pLLE9BQU9DLFVBQVVDLGVBQWVDLEtBQUtSLEVBQVFJLEtBQy9DSCxFQUFXRyxHQUFPTCxTQUFTQyxFQUFPSSxLQUt0QyxPQUFPSCxDQUNULENBMERPLFNBQVNRLGdCQUFnQkMsR0FDOUIsT0FBT0MsS0FBQUEsV0FBV0QsR0FBUUUsS0FBQUEsVUFBVUYsR0FBUUcsS0FBQUEsUUFBUUgsRUFDdEQsQ0FZTyxTQUFTSSxVQUFVQyxFQUFPQyxHQUUvQixNQUFhLFFBQVRBLEdBQTBCLE9BQVJBLEVBQ2JDLE9B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 +"use strict";Object.defineProperty(exports,"__esModule",{value:!0}),require("colors");var fs=require("fs"),path=require("path"),httpsProxyAgent=require("https-proxy-agent"),url=require("url"),dotenv=require("dotenv"),zod=require("zod"),http=require("http"),https=require("https"),tarn=require("tarn"),uuid=require("uuid"),puppeteer=require("puppeteer"),DOMPurify=require("dompurify"),jsdom=require("jsdom"),cors=require("cors"),express=require("express"),multer=require("multer"),rateLimit=require("express-rate-limit"),_documentCurrentScript="undefined"!=typeof document?document.currentScript:null;const __dirname$1=url.fileURLToPath(new URL("../.","undefined"==typeof document?require("url").pathToFileURL(__filename).href:_documentCurrentScript&&"SCRIPT"===_documentCurrentScript.tagName.toUpperCase()&&_documentCurrentScript.src||new URL("index.cjs",document.baseURI).href));function deepCopy(e){if(null===e||"object"!=typeof e)return e;const t=Array.isArray(e)?[]:{};for(const o in e)Object.prototype.hasOwnProperty.call(e,o)&&(t[o]=deepCopy(e[o]));return t}function getAbsolutePath(e){return path.isAbsolute(e)?path.normalize(e):path.resolve(e)}function getBase64(e,t){return"pdf"===t||"svg"==t?Buffer.from(e,"utf8").toString("base64"):e}function getNewDate(){return(new Date).toString().split("(")[0].trim()}function getNewDateTime(){return(new Date).getTime()}function isObject(e){return"[object Object]"===Object.prototype.toString.call(e)}function isObjectEmpty(e){return"object"==typeof e&&!Array.isArray(e)&&null!==e&&0===Object.keys(e).length}function isPrivateRangeUrlFound(e){return[/xlink:href="(?:http:\/\/|https:\/\/)?localhost\b/,/xlink:href="(?:http:\/\/|https:\/\/)?10\.\d{1,3}\.\d{1,3}\.\d{1,3}\b/,/xlink:href="(?:http:\/\/|https:\/\/)?127\.\d{1,3}\.\d{1,3}\.\d{1,3}\b/,/xlink:href="(?:http:\/\/|https:\/\/)?172\.(1[6-9]|2[0-9]|3[0-1])\.\d{1,3}\.\d{1,3}\b/,/xlink:href="(?:http:\/\/|https:\/\/)?192\.168\.\d{1,3}\.\d{1,3}\b/].some((t=>t.test(e)))}function measureTime(){const e=process.hrtime.bigint();return()=>Number(process.hrtime.bigint()-e)/1e6}function roundNumber(e,t=1){const o=Math.pow(10,t||0);return Math.round(+e*o)/o}const colors=["red","yellow","blue","gray","green"],logging={toConsole:!0,toFile:!1,pathCreated:!1,pathToLog:"",levelsDesc:[{title:"error",color:colors[0]},{title:"warning",color:colors[1]},{title:"notice",color:colors[2]},{title:"verbose",color:colors[3]},{title:"benchmark",color:colors[4]}]};function log(...e){const[t,...o]=e,{levelsDesc:r,level:n}=logging;if(5!==t&&(0===t||t>n||n>r.length))return;const i=`${getNewDate()} [${r[t-1].title}] -`;logging.toFile&&_logToFile(o,i),logging.toConsole&&console.log.apply(void 0,[i.toString()[logging.levelsDesc[t-1].color]].concat(o))}function logWithStack(e,t,o){const r=o||t&&t.message||"",{level:n,levelsDesc:i}=logging;if(0===e||e>n||n>i.length)return;const s=`${getNewDate()} [${i[e-1].title}] -`,a=t&&t.stack,l=[r];a&&l.push("\n",a),logging.toFile&&_logToFile(l,s),logging.toConsole&&console.log.apply(void 0,[s.toString()[logging.levelsDesc[e-1].color]].concat([l.shift()[colors[e-1]],...l]))}function logZodIssues(e,t,o){logWithStack(e,null,[`${o||"[validation] Validation error"} - the following Zod issues occured:`,...(t||[]).map((e=>`- ${e.message}`))].join("\n"))}function initLogging(e){const{level:t,dest:o,file:r,toConsole:n,toFile:i}=e;logging.pathCreated=!1,logging.pathToLog="",setLogLevel(t),enableConsoleLogging(n),enableFileLogging(o,r,i)}function setLogLevel(e){Number.isInteger(e)&&e>=0&&e<=logging.levelsDesc.length&&(logging.level=e)}function enableConsoleLogging(e){logging.toConsole=!!e}function enableFileLogging(e,t,o){logging.toFile=!!o,logging.toFile&&(logging.dest=e||"log",logging.file=t||"highcharts-export-server.log")}function _logToFile(e,t){logging.pathCreated||(!fs.existsSync(getAbsolutePath(logging.dest))&&fs.mkdirSync(getAbsolutePath(logging.dest)),logging.pathToLog=getAbsolutePath(path.join(logging.dest,logging.file)),logging.pathCreated=!0),fs.appendFile(logging.pathToLog,[t].concat(e).join(" ")+"\n",(e=>{e&&logging.toFile&&logging.pathCreated&&(logging.toFile=!1,logging.pathCreated=!1,logWithStack(2,e,"[logger] Unable to write to log file."))}))}const defaultConfig={puppeteer:{args:{value:["--allow-running-insecure-content","--ash-no-nudges","--autoplay-policy=user-gesture-required","--block-new-web-contents","--disable-accelerated-2d-canvas","--disable-background-networking","--disable-background-timer-throttling","--disable-backgrounding-occluded-windows","--disable-breakpad","--disable-checker-imaging","--disable-client-side-phishing-detection","--disable-component-extensions-with-background-pages","--disable-component-update","--disable-default-apps","--disable-dev-shm-usage","--disable-domain-reliability","--disable-extensions","--disable-features=CalculateNativeWinOcclusion,InterestFeedContentSuggestions,WebOTP","--disable-hang-monitor","--disable-ipc-flooding-protection","--disable-logging","--disable-notifications","--disable-offer-store-unmasked-wallet-cards","--disable-popup-blocking","--disable-print-preview","--disable-prompt-on-repost","--disable-renderer-backgrounding","--disable-search-engine-choice-screen","--disable-session-crashed-bubble","--disable-setuid-sandbox","--disable-site-isolation-trials","--disable-speech-api","--disable-sync","--enable-unsafe-webgpu","--hide-crash-restore-bubble","--hide-scrollbars","--metrics-recording-only","--mute-audio","--no-default-browser-check","--no-first-run","--no-pings","--no-sandbox","--no-startup-window","--no-zygote","--password-store=basic","--process-per-tab","--use-mock-keychain"],types:["string[]"],envLink:"PUPPETEER_ARGS",cliName:"puppeteerArgs",description:"Array of Puppeteer arguments",promptOptions:{type:"list",separator:";"}}},highcharts:{version:{value:"latest",types:["string"],envLink:"HIGHCHARTS_VERSION",description:"Highcharts version",promptOptions:{type:"text"}},cdnUrl:{value:"https://code.highcharts.com",types:["string"],envLink:"HIGHCHARTS_CDN_URL",description:"CDN URL for Highcharts scripts",promptOptions:{type:"text"}},forceFetch:{value:!1,types:["boolean"],envLink:"HIGHCHARTS_FORCE_FETCH",description:"Flag to refetch scripts after each server rerun",promptOptions:{type:"toggle"}},cachePath:{value:".cache",types:["string"],envLink:"HIGHCHARTS_CACHE_PATH",description:"Directory path for cached Highcharts scripts",promptOptions:{type:"text"}},coreScripts:{value:["highcharts","highcharts-more","highcharts-3d"],types:["string[]"],envLink:"HIGHCHARTS_CORE_SCRIPTS",description:"Highcharts core scripts to fetch",promptOptions:{type:"multiselect",instructions:"Space: Select specific, A: Select all, Enter: Confirm"}},moduleScripts:{value:["stock","map","gantt","exporting","parallel-coordinates","accessibility","boost-canvas","boost","data","data-tools","draggable-points","static-scale","broken-axis","heatmap","tilemap","tiledwebmap","timeline","treemap","treegraph","item-series","drilldown","histogram-bellcurve","bullet","funnel","funnel3d","geoheatmap","pyramid3d","networkgraph","overlapping-datalabels","pareto","pattern-fill","pictorial","price-indicator","sankey","arc-diagram","dependency-wheel","series-label","series-on-point","solid-gauge","sonification","streamgraph","sunburst","variable-pie","variwide","vector","venn","windbarb","wordcloud","xrange","no-data-to-display","drag-panes","debugger","dumbbell","lollipop","cylinder","organization","dotplot","marker-clusters","hollowcandlestick","heikinashi","flowmap","export-data","navigator","textpath"],types:["string[]"],envLink:"HIGHCHARTS_MODULE_SCRIPTS",description:"Highcharts module scripts to fetch",promptOptions:{type:"multiselect",instructions:"Space: Select specific, A: Select all, Enter: Confirm"}},indicatorScripts:{value:["indicators-all"],types:["string[]"],envLink:"HIGHCHARTS_INDICATOR_SCRIPTS",description:"Highcharts indicator scripts to fetch",promptOptions:{type:"multiselect",instructions:"Space: Select specific, A: Select all, Enter: Confirm"}},customScripts:{value:["https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.30.1/moment.min.js","https://cdnjs.cloudflare.com/ajax/libs/moment-timezone/0.5.45/moment-timezone-with-data.min.js"],types:["string[]"],envLink:"HIGHCHARTS_CUSTOM_SCRIPTS",description:"Additional custom scripts or dependencies to fetch",promptOptions:{type:"list",separator:";"}}},export:{infile:{value:null,types:["string","null"],envLink:"EXPORT_INFILE",description:"Input filename with type, formatted correctly as JSON or SVG",promptOptions:{type:"text"}},instr:{value:null,types:["Object","string","null"],envLink:"EXPORT_INSTR",description:"Overrides the `infile` with JSON, stringified JSON, or SVG input",promptOptions:{type:"text"}},options:{value:null,types:["Object","string","null"],envLink:"EXPORT_OPTIONS",description:"Alias for the `instr` option",promptOptions:{type:"text"}},svg:{value:null,types:["string","null"],envLink:"EXPORT_SVG",description:"SVG string representation of the chart to render",promptOptions:{type:"text"}},batch:{value:null,types:["string","null"],envLink:"EXPORT_BATCH",description:'Batch job string with input/output pairs: "in=out;in=out;..."',promptOptions:{type:"text"}},outfile:{value:null,types:["string","null"],envLink:"EXPORT_OUTFILE",description:"Output filename with type. Can be jpeg, png, pdf, or svg and ignores `type` option",promptOptions:{type:"text"}},type:{value:"png",types:["string"],envLink:"EXPORT_TYPE",description:"File export format. Can be jpeg, png, pdf, or svg",promptOptions:{type:"select",hint:"Default: png",choices:["png","jpeg","pdf","svg"]}},constr:{value:"chart",types:["string"],envLink:"EXPORT_CONSTR",description:"Chart constructor. Can be chart, stockChart, mapChart, or ganttChart",promptOptions:{type:"select",hint:"Default: chart",choices:["chart","stockChart","mapChart","ganttChart"]}},b64:{value:!1,types:["boolean"],envLink:"EXPORT_B64",description:"Whether or not to the chart should be received in Base64 format instead of binary",promptOptions:{type:"toggle"}},noDownload:{value:!1,types:["boolean"],envLink:"EXPORT_NO_DOWNLOAD",description:"Whether or not to include or exclude attachment headers in the response",promptOptions:{type:"toggle"}},height:{value:null,types:["number","null"],envLink:"EXPORT_HEIGHT",description:"Height of the exported chart, overrides chart settings",promptOptions:{type:"number"}},width:{value:null,types:["number","null"],envLink:"EXPORT_WIDTH",description:"Width of the exported chart, overrides chart settings",promptOptions:{type:"number"}},scale:{value:null,types:["number","null"],envLink:"EXPORT_SCALE",description:"Scale of the exported chart, overrides chart settings. Ranges from 0.1 to 5.0",promptOptions:{type:"number"}},defaultHeight:{value:400,types:["number"],envLink:"EXPORT_DEFAULT_HEIGHT",description:"Default height of the exported chart if not set",promptOptions:{type:"number"}},defaultWidth:{value:600,types:["number"],envLink:"EXPORT_DEFAULT_WIDTH",description:"Default width of the exported chart if not set",promptOptions:{type:"number"}},defaultScale:{value:1,types:["number"],envLink:"EXPORT_DEFAULT_SCALE",description:"Default scale of the exported chart if not set. Ranges from 0.1 to 5.0",promptOptions:{type:"number",min:.1,max:5}},globalOptions:{value:null,types:["Object","string","null"],envLink:"EXPORT_GLOBAL_OPTIONS",description:"JSON, stringified JSON or filename with global options for Highcharts.setOptions",promptOptions:{type:"text"}},themeOptions:{value:null,types:["Object","string","null"],envLink:"EXPORT_THEME_OPTIONS",description:"JSON, stringified JSON or filename with theme options for Highcharts.setOptions",promptOptions:{type:"text"}},rasterizationTimeout:{value:1500,types:["number"],envLink:"EXPORT_RASTERIZATION_TIMEOUT",description:"Milliseconds to wait for webpage rendering",promptOptions:{type:"number"}}},customLogic:{allowCodeExecution:{value:!1,types:["boolean"],envLink:"CUSTOM_LOGIC_ALLOW_CODE_EXECUTION",description:"Allows or disallows execution of arbitrary code during exporting",promptOptions:{type:"toggle"}},allowFileResources:{value:!1,types:["boolean"],envLink:"CUSTOM_LOGIC_ALLOW_FILE_RESOURCES",description:"Allows or disallows injection of filesystem resources (disabled in server mode)",promptOptions:{type:"toggle"}},customCode:{value:null,types:["string","null"],envLink:"CUSTOM_LOGIC_CUSTOM_CODE",description:"Custom code to execute before chart initialization. Can be a function, code wrapped in a function, or a .js filename",promptOptions:{type:"text"}},callback:{value:null,types:["string","null"],envLink:"CUSTOM_LOGIC_CALLBACK",description:"JavaScript code to run during construction. Can be a function or a .js filename",promptOptions:{type:"text"}},resources:{value:null,types:["Object","string","null"],envLink:"CUSTOM_LOGIC_RESOURCES",description:"Additional resources as JSON, stringified JSON, or filename, containing files, js, and css sections",promptOptions:{type:"text"}},loadConfig:{value:null,types:["string","null"],envLink:"CUSTOM_LOGIC_LOAD_CONFIG",legacyName:"fromFile",description:"File with a pre-defined configuration to use",promptOptions:{type:"text"}},createConfig:{value:null,types:["string","null"],envLink:"CUSTOM_LOGIC_CREATE_CONFIG",description:"Prompt-based option setting, saved to a provided config file",promptOptions:{type:"text"}}},server:{enable:{value:!1,types:["boolean"],envLink:"SERVER_ENABLE",cliName:"enableServer",description:"Starts the server when true",promptOptions:{type:"toggle"}},host:{value:"0.0.0.0",types:["string"],envLink:"SERVER_HOST",description:"Hostname of the server",promptOptions:{type:"text"}},port:{value:7801,types:["number"],envLink:"SERVER_PORT",description:"Port number for the server",promptOptions:{type:"number"}},uploadLimit:{value:3,types:["number"],envLink:"SERVER_UPLOAD_LIMIT",description:"Maximum request body size in MB",promptOptions:{type:"number"}},benchmarking:{value:!1,types:["boolean"],envLink:"SERVER_BENCHMARKING",cliName:"serverBenchmarking",description:"Displays or not action durations in milliseconds during server requests",promptOptions:{type:"toggle"}},proxy:{host:{value:null,types:["string","null"],envLink:"SERVER_PROXY_HOST",cliName:"proxyHost",description:"Host of the proxy server, if applicable",promptOptions:{type:"text"}},port:{value:null,types:["number","null"],envLink:"SERVER_PROXY_PORT",cliName:"proxyPort",description:"Port of the proxy server, if applicable",promptOptions:{type:"number"}},timeout:{value:5e3,types:["number"],envLink:"SERVER_PROXY_TIMEOUT",cliName:"proxyTimeout",description:"Timeout in milliseconds for the proxy server, if applicable",promptOptions:{type:"number"}}},rateLimiting:{enable:{value:!1,types:["boolean"],envLink:"SERVER_RATE_LIMITING_ENABLE",cliName:"enableRateLimiting",description:"Enables or disables rate limiting on the server",promptOptions:{type:"toggle"}},maxRequests:{value:10,types:["number"],envLink:"SERVER_RATE_LIMITING_MAX_REQUESTS",legacyName:"rateLimit",description:"Maximum number of requests allowed per minute",promptOptions:{type:"number"}},window:{value:1,types:["number"],envLink:"SERVER_RATE_LIMITING_WINDOW",description:"Time window in minutes for rate limiting",promptOptions:{type:"number"}},delay:{value:0,types:["number"],envLink:"SERVER_RATE_LIMITING_DELAY",description:"Delay duration between successive requests before reaching the limit",promptOptions:{type:"number"}},trustProxy:{value:!1,types:["boolean"],envLink:"SERVER_RATE_LIMITING_TRUST_PROXY",description:"Set to true if the server is behind a load balancer",promptOptions:{type:"toggle"}},skipKey:{value:null,types:["string","null"],envLink:"SERVER_RATE_LIMITING_SKIP_KEY",description:"Key to bypass the rate limiter, used with `skipToken`",promptOptions:{type:"text"}},skipToken:{value:null,types:["string","null"],envLink:"SERVER_RATE_LIMITING_SKIP_TOKEN",description:"Token to bypass the rate limiter, used with `skipKey`",promptOptions:{type:"text"}}},ssl:{enable:{value:!1,types:["boolean"],envLink:"SERVER_SSL_ENABLE",cliName:"enableSsl",description:"Enables or disables SSL protocol",promptOptions:{type:"toggle"}},force:{value:!1,types:["boolean"],envLink:"SERVER_SSL_FORCE",cliName:"sslForce",legacyName:"sslOnly",description:"Forces the server to use HTTPS only when true",promptOptions:{type:"toggle"}},port:{value:443,types:["number"],envLink:"SERVER_SSL_PORT",cliName:"sslPort",description:"Port for the SSL server",promptOptions:{type:"number"}},certPath:{value:null,types:["string","null"],envLink:"SERVER_SSL_CERT_PATH",cliName:"sslCertPath",legacyName:"sslPath",description:"Path to the SSL certificate/key file",promptOptions:{type:"text"}}}},pool:{minWorkers:{value:4,types:["number"],envLink:"POOL_MIN_WORKERS",description:"Minimum and initial number of pool workers to spawn",promptOptions:{type:"number"}},maxWorkers:{value:8,types:["number"],envLink:"POOL_MAX_WORKERS",legacyName:"workers",description:"Maximum number of pool workers to spawn",promptOptions:{type:"number"}},workLimit:{value:40,types:["number"],envLink:"POOL_WORK_LIMIT",description:"Number of tasks a worker can handle before restarting",promptOptions:{type:"number"}},acquireTimeout:{value:5e3,types:["number"],envLink:"POOL_ACQUIRE_TIMEOUT",description:"Timeout in milliseconds for acquiring a resource",promptOptions:{type:"number"}},createTimeout:{value:5e3,types:["number"],envLink:"POOL_CREATE_TIMEOUT",description:"Timeout in milliseconds for creating a resource",promptOptions:{type:"number"}},destroyTimeout:{value:5e3,types:["number"],envLink:"POOL_DESTROY_TIMEOUT",description:"Timeout in milliseconds for destroying a resource",promptOptions:{type:"number"}},idleTimeout:{value:3e4,types:["number"],envLink:"POOL_IDLE_TIMEOUT",description:"Timeout in milliseconds for destroying idle resources",promptOptions:{type:"number"}},createRetryInterval:{value:200,types:["number"],envLink:"POOL_CREATE_RETRY_INTERVAL",description:"Interval in milliseconds before retrying resource creation on failure",promptOptions:{type:"number"}},reaperInterval:{value:1e3,types:["number"],envLink:"POOL_REAPER_INTERVAL",description:"Interval in milliseconds to check and destroy idle resources",promptOptions:{type:"number"}},benchmarking:{value:!1,types:["boolean"],envLink:"POOL_BENCHMARKING",cliName:"poolBenchmarking",description:"Shows statistics for the pool of resources",promptOptions:{type:"toggle"}}},logging:{level:{value:4,types:["number"],envLink:"LOGGING_LEVEL",cliName:"logLevel",description:"Logging verbosity level",promptOptions:{type:"number",round:0,min:0,max:5}},file:{value:"highcharts-export-server.log",types:["string"],envLink:"LOGGING_FILE",cliName:"logFile",description:"Log file name. Requires `logToFile` and `logDest` to be set",promptOptions:{type:"text"}},dest:{value:"log",types:["string"],envLink:"LOGGING_DEST",cliName:"logDest",description:"Path to store log files. Requires `logToFile` to be set",promptOptions:{type:"text"}},toConsole:{value:!0,types:["boolean"],envLink:"LOGGING_TO_CONSOLE",cliName:"logToConsole",description:"Enables or disables console logging",promptOptions:{type:"toggle"}},toFile:{value:!0,types:["boolean"],envLink:"LOGGING_TO_FILE",cliName:"logToFile",description:"Enables or disables logging to a file",promptOptions:{type:"toggle"}}},ui:{enable:{value:!1,types:["boolean"],envLink:"UI_ENABLE",cliName:"enableUi",description:"Enables or disables the UI for the export server",promptOptions:{type:"toggle"}},route:{value:"/",types:["string"],envLink:"UI_ROUTE",cliName:"uiRoute",description:"The endpoint route for the UI",promptOptions:{type:"text"}}},other:{nodeEnv:{value:"production",types:["string"],envLink:"OTHER_NODE_ENV",description:"The Node.js environment type",promptOptions:{type:"text"}},listenToProcessExits:{value:!0,types:["boolean"],envLink:"OTHER_LISTEN_TO_PROCESS_EXITS",description:"Whether or not to attach process.exit handlers",promptOptions:{type:"toggle"}},noLogo:{value:!1,types:["boolean"],envLink:"OTHER_NO_LOGO",description:"Display or skip printing the logo on startup",promptOptions:{type:"toggle"}},hardResetPage:{value:!1,types:["boolean"],envLink:"OTHER_HARD_RESET_PAGE",description:"Whether or not to reset the page content entirely",promptOptions:{type:"toggle"}},browserShellMode:{value:!0,types:["boolean"],envLink:"OTHER_BROWSER_SHELL_MODE",description:"Whether or not to set the browser to run in shell mode",promptOptions:{type:"toggle"}},validation:{value:!0,types:["boolean"],envLink:"OTHER_VALIDATION",description:"Whether or not to enable validation of options types",promptOptions:{type:"toggle"}}},debug:{enable:{value:!1,types:["boolean"],envLink:"DEBUG_ENABLE",cliName:"enableDebug",description:"Enables or disables debug mode for the underlying browser",promptOptions:{type:"toggle"}},headless:{value:!1,types:["boolean"],envLink:"DEBUG_HEADLESS",description:"Whether or not to set the browser to run in headless mode during debugging",promptOptions:{type:"toggle"}},devtools:{value:!1,types:["boolean"],envLink:"DEBUG_DEVTOOLS",description:"Enables or disables DevTools in headful mode",promptOptions:{type:"toggle"}},listenToConsole:{value:!1,types:["boolean"],envLink:"DEBUG_LISTEN_TO_CONSOLE",description:"Enables or disables listening to console messages from the browser",promptOptions:{type:"toggle"}},dumpio:{value:!1,types:["boolean"],envLink:"DEBUG_DUMPIO",description:"Redirects or not browser stdout and stderr to process.stdout and process.stderr",promptOptions:{type:"toggle"}},slowMo:{value:0,types:["number"],envLink:"DEBUG_SLOW_MO",description:"Delays Puppeteer operations by the specified milliseconds",promptOptions:{type:"number"}},debuggingPort:{value:9222,types:["number"],envLink:"DEBUG_DEBUGGING_PORT",description:"Port used for debugging",promptOptions:{type:"number"}}}};dotenv.config();const{coreScripts:coreScripts,moduleScripts:moduleScripts,indicatorScripts:indicatorScripts}=defaultConfig.highcharts;zod.z.setErrorMap(_customErrorMap);const v={boolean:e=>e?zod.z.boolean():zod.z.union([zod.z.enum(["true","1","false","0","undefined","null",""]).transform((e=>["undefined","null",""].includes(e)?null:"true"===e||"1"===e)),zod.z.boolean()]).nullable(),string:e=>e?zod.z.string().trim().refine((e=>!["false","undefined","null",""].includes(e)),{params:{errorMessage:"The string contains a forbidden value"}}):zod.z.string().trim().transform((e=>["false","undefined","null",""].includes(e)?null:e)).nullable(),enum:(e,t)=>t?zod.z.enum([...e]):zod.z.enum([...e,"undefined","null",""]).transform((e=>["undefined","null",""].includes(e)?null:e)).nullable(),stringArray(e,t,o){const r=zod.z.string().trim().array(),n=zod.z.string().trim().transform((e=>(e.startsWith("[")&&(e=e.slice(1)),e.endsWith("]")&&(e=e.slice(0,-1)),e.split(t)))),i=t=>t.map((e=>e.trim())).filter(e);return o?r.transform(i):zod.z.union([n,r]).transform(i).transform((e=>e.length?e:null)).nullable()},positiveNum:e=>e?zod.z.number().positive():zod.z.union([zod.z.string().trim().refine((e=>!isNaN(Number(e))&&Number(e)>0||["undefined","null",""].includes(e)),{params:{errorMessage:"The value must be numeric and positive"}}).transform((e=>["undefined","null",""].includes(e)?null:Number(e))),zod.z.number().positive()]).nullable(),nonNegativeNum:e=>e?zod.z.number().nonnegative():zod.z.union([zod.z.string().trim().refine((e=>!isNaN(Number(e))&&Number(e)>=0||["undefined","null",""].includes(e)),{params:{errorMessage:"The value must be numeric and non-negative"}}).transform((e=>["undefined","null",""].includes(e)?null:Number(e))),zod.z.number().nonnegative()]).nullable(),startsWith:(e,t)=>t?zod.z.string().trim().refine((t=>e.some((e=>t.startsWith(e)))),{params:{errorMessage:`The value must be a string that starts with ${e.join(", ")}`}}):zod.z.string().trim().refine((t=>e.some((e=>t.startsWith(e)))||["undefined","null",""].includes(t)),{params:{errorMessage:`The value must be a string that starts with ${e.join(", ")}`}}).transform((e=>["undefined","null",""].includes(e)?null:e)).nullable(),chartConfig:()=>zod.z.union([zod.z.string().trim().refine((e=>e.startsWith("{")&&e.endsWith("}")||["undefined","null",""].includes(e)),{params:{errorMessage:"The value must be a string that starts with '{' and ends with '}'"}}).transform((e=>["undefined","null",""].includes(e)?null:e)),zod.z.object({}).passthrough()]).nullable(),additionalOptions:()=>zod.z.union([zod.z.string().trim().refine((e=>e.length>=6&&e.endsWith(".json")||e.startsWith("{")&&e.endsWith("}")||["undefined","null",""].includes(e)),{params:{errorMessage:"The value must be a string that ends with '.json' or starts with '{' and ends with '}'"}}).transform((e=>["undefined","null",""].includes(e)?null:e)),zod.z.object({}).passthrough()]).nullable()},validators={args:e=>v.stringArray((e=>!["false","undefined","null",""].includes(e)),";",e),version:e=>e?zod.z.string().trim().refine((e=>/^(latest|\d{1,2}(\.\d{1,2}){0,2})$/.test(e)),{params:{errorMessage:"The value must be 'latest', a major version, or in the form XX.YY.ZZ"}}):zod.z.string().trim().refine((e=>/^(latest|\d{1,2}(\.\d{1,2}){0,2})$/.test(e)||["undefined","null",""].includes(e)),{params:{errorMessage:"The value must be 'latest', a major version, or in the form XX.YY.ZZ"}}).transform((e=>["undefined","null",""].includes(e)?null:e)).nullable(),cdnUrl:e=>v.startsWith(["http://","https://"],e),forceFetch:e=>v.boolean(e),cachePath:e=>v.string(e),adminToken:e=>v.string(e),coreScripts:e=>v.stringArray((e=>coreScripts.value.includes(e)),",",e),moduleScripts:e=>v.stringArray((e=>moduleScripts.value.includes(e)),",",e),indicatorScripts:e=>v.stringArray((e=>indicatorScripts.value.includes(e)),",",e),customScripts:e=>v.stringArray((e=>e.startsWith("https://")||e.startsWith("http://")),",",e),infile:e=>e?zod.z.string().trim().refine((e=>e.length>=6&&e.endsWith(".json")||e.length>=5&&e.endsWith(".svg")),{params:{errorMessage:"The value must be a string that ends with .json or .svg"}}).nullable():zod.z.string().trim().refine((e=>e.length>=6&&e.endsWith(".json")||e.length>=5&&e.endsWith(".svg")||["undefined","null",""].includes(e)),{params:{errorMessage:"The value must be a string that ends with .json or .svg"}}).transform((e=>["undefined","null",""].includes(e)?null:e)).nullable(),instr:()=>v.chartConfig(),options:()=>v.chartConfig(),svg:()=>zod.z.string().trim().refine((e=>e.indexOf("=0||e.indexOf("=0||["false","undefined","null",""].includes(e)),{params:{errorMessage:"The value must be a string that contains '["false","undefined","null",""].includes(e)?null:e)).nullable(),outfile:e=>e?zod.z.string().trim().refine((e=>e.length>=6&&e.endsWith(".jpeg")||e.length>=5&&(e.endsWith(".jpg")||e.endsWith(".png")||e.endsWith(".pdf")||e.endsWith(".svg"))),{params:{errorMessage:"The value must be a string that ends with .jpeg, .jpg, .png, .pdf, or .svg"}}).nullable():zod.z.string().trim().refine((e=>e.length>=6&&e.endsWith(".jpeg")||e.length>=5&&(e.endsWith(".jpg")||e.endsWith(".png")||e.endsWith(".pdf")||e.endsWith(".svg"))||["undefined","null",""].includes(e)),{params:{errorMessage:"The value must be a string that ends with .jpeg, .jpg, .png, .pdf, or .svg"}}).transform((e=>["undefined","null",""].includes(e)?null:e)).nullable(),type:e=>v.enum(["jpeg","jpg","png","pdf","svg"],e),constr:e=>v.enum(["chart","stockChart","mapChart","ganttChart"],e),b64:e=>v.boolean(e),noDownload:e=>v.boolean(e),defaultHeight:e=>v.positiveNum(e),defaultWidth:e=>v.positiveNum(e),defaultScale:e=>e?zod.z.number().gte(.1).lte(5):zod.z.union([zod.z.string().trim().refine((e=>!isNaN(Number(e))&&!0!==e&&!e.startsWith("[")&&Number(e)>=.1&&Number(e)<=5||["undefined","null",""].includes(e)),{params:{errorMessage:"The value must be within a 0.1 and 5.0 range"}}).transform((e=>["undefined","null",""].includes(e)?null:Number(e))),zod.z.number().gte(.1).lte(5)]).nullable(),height(e){return this.defaultHeight(e).nullable()},width(e){return this.defaultWidth(e).nullable()},scale(e){return this.defaultScale(e).nullable()},globalOptions:()=>v.additionalOptions(),themeOptions:()=>v.additionalOptions(),batch:e=>v.string(e),rasterizationTimeout:e=>v.nonNegativeNum(e),allowCodeExecution:e=>v.boolean(e),allowFileResources:e=>v.boolean(e),customCode:e=>v.string(e),callback:e=>v.string(e),resources(e){const t=zod.z.object({js:v.string(!1),css:v.string(!1),files:v.stringArray((e=>!["undefined","null",""].includes(e)),",",!0).nullable()}).partial(),o=zod.z.string().trim().refine((e=>e.startsWith("{")&&e.endsWith("}")||e.length>=6&&e.endsWith(".json")),{params:{errorMessage:"The value must be a string that starts with '{' and ends with '}"}}),r=zod.z.string().trim().refine((e=>e.startsWith("{")&&e.endsWith("}")||e.length>=6&&e.endsWith(".json")||["undefined","null",""].includes(e)),{params:{errorMessage:"The value must be a string that ends with .json"}}).transform((e=>["undefined","null",""].includes(e)?null:e));return e?zod.z.union([t,o]).nullable():zod.z.union([t,r]).nullable()},loadConfig:e=>v.string(e).refine((e=>null===e||e.length>=6&&e.endsWith(".json")),{params:{errorMessage:"The value must be a string that ends with .json"}}),createConfig(e){return this.loadConfig(e)},enableServer:e=>v.boolean(e),host:e=>v.string(e),port:e=>v.nonNegativeNum(e),uploadLimit:e=>v.positiveNum(e),serverBenchmarking:e=>v.boolean(e),proxyHost:e=>v.string(e),proxyPort:e=>v.nonNegativeNum(e).nullable(),proxyTimeout:e=>v.nonNegativeNum(e),enableRateLimiting:e=>v.boolean(e),maxRequests:e=>v.nonNegativeNum(e),window:e=>v.nonNegativeNum(e),delay:e=>v.nonNegativeNum(e),trustProxy:e=>v.boolean(e),skipKey:e=>v.string(e),skipToken:e=>v.string(e),enableSsl:e=>v.boolean(e),sslForce:e=>v.boolean(e),sslPort:e=>v.nonNegativeNum(e),sslCertPath:e=>v.string(e),minWorkers:e=>v.positiveNum(e),maxWorkers:e=>v.positiveNum(e),workLimit:e=>v.positiveNum(e),acquireTimeout:e=>v.nonNegativeNum(e),createTimeout:e=>v.nonNegativeNum(e),destroyTimeout:e=>v.nonNegativeNum(e),idleTimeout:e=>v.nonNegativeNum(e),createRetryInterval:e=>v.nonNegativeNum(e),reaperInterval:e=>v.nonNegativeNum(e),poolBenchmarking:e=>v.boolean(e),resourcesInterval:e=>v.nonNegativeNum(e),logLevel:e=>e?zod.z.number().int().gte(0).lte(5):zod.z.union([zod.z.string().trim().refine((e=>!isNaN(Number(e))&&!0!==e&&!e.startsWith("[")&&Number.isInteger(Number(e))&&Number(e)>=0&&Number(e)<=5||["undefined","null",""].includes(e)),{params:{errorMessage:"The value must be within a 0 and 5 range"}}).transform((e=>["undefined","null",""].includes(e)?null:Number(e))),zod.z.number().int().gte(0).lte(5)]).nullable(),logFile:e=>v.string(e).refine((e=>null===e||e.length>=5&&e.endsWith(".log")),{params:{errorMessage:"The value must be a string that ends with .log"}}),logDest:e=>v.string(e),logToConsole:e=>v.boolean(e),logToFile:e=>v.boolean(e),enableUi:e=>v.boolean(e),uiRoute:e=>v.startsWith(["/"],e),nodeEnv:e=>v.enum(["development","production","test"],e),listenToProcessExits:e=>v.boolean(e),noLogo:e=>v.boolean(e),hardResetPage:e=>v.boolean(e),browserShellMode:e=>v.boolean(e),validation:e=>v.boolean(e),enableDebug:e=>v.boolean(e),headless:e=>v.boolean(e),devtools:e=>v.boolean(e),listenToConsole:e=>v.boolean(e),dumpio:e=>v.boolean(e),slowMo:e=>v.nonNegativeNum(e),debuggingPort:e=>v.nonNegativeNum(e),requestId:()=>zod.z.string().uuid({message:"The value must be a stringified UUID"}).nullable()},PuppeteerSchema=e=>zod.z.object({args:validators.args(e)}).partial(),HighchartsSchema=e=>zod.z.object({version:validators.version(e),cdnUrl:validators.cdnUrl(e),forceFetch:validators.forceFetch(e),cachePath:validators.cachePath(e),coreScripts:validators.coreScripts(e),moduleScripts:validators.moduleScripts(e),indicatorScripts:validators.indicatorScripts(e),customScripts:validators.customScripts(e)}).partial(),ExportSchema=e=>zod.z.object({infile:validators.infile(e),instr:validators.instr(),options:validators.options(),svg:validators.svg(),outfile:validators.outfile(e),type:validators.type(e),constr:validators.constr(e),b64:validators.b64(e),noDownload:validators.noDownload(e),defaultHeight:validators.defaultHeight(e),defaultWidth:validators.defaultWidth(e),defaultScale:validators.defaultScale(e),height:validators.height(e),width:validators.width(e),scale:validators.scale(e),globalOptions:validators.globalOptions(),themeOptions:validators.themeOptions(),batch:validators.batch(!1),rasterizationTimeout:validators.rasterizationTimeout(e)}).partial(),CustomLogicSchema=e=>zod.z.object({allowCodeExecution:validators.allowCodeExecution(e),allowFileResources:validators.allowFileResources(e),customCode:validators.customCode(!1),callback:validators.callback(!1),resources:validators.resources(e),loadConfig:validators.loadConfig(!1),createConfig:validators.createConfig(!1)}).partial(),ProxySchema=e=>zod.z.object({host:validators.proxyHost(!1),port:validators.proxyPort(e),timeout:validators.proxyTimeout(e)}).partial(),RateLimitingSchema=e=>zod.z.object({enable:validators.enableRateLimiting(e),maxRequests:validators.maxRequests(e),window:validators.window(e),delay:validators.delay(e),trustProxy:validators.trustProxy(e),skipKey:validators.skipKey(!1),skipToken:validators.skipToken(!1)}).partial(),SslSchema=e=>zod.z.object({enable:validators.enableSsl(e),force:validators.sslForce(e),port:validators.sslPort(e),certPath:validators.sslCertPath(!1)}).partial(),ServerSchema=e=>zod.z.object({enable:validators.enableServer(e).optional(),host:validators.host(e).optional(),port:validators.port(e).optional(),uploadLimit:validators.uploadLimit(e).optional(),benchmarking:validators.serverBenchmarking(e).optional(),proxy:ProxySchema(e).optional(),rateLimiting:RateLimitingSchema(e).optional(),ssl:SslSchema(e).optional()}),PoolSchema=e=>zod.z.object({minWorkers:validators.minWorkers(e),maxWorkers:validators.maxWorkers(e),workLimit:validators.workLimit(e),acquireTimeout:validators.acquireTimeout(e),createTimeout:validators.createTimeout(e),destroyTimeout:validators.destroyTimeout(e),idleTimeout:validators.idleTimeout(e),createRetryInterval:validators.createRetryInterval(e),reaperInterval:validators.reaperInterval(e),benchmarking:validators.poolBenchmarking(e)}).partial(),LoggingSchema=e=>zod.z.object({level:validators.logLevel(e),file:validators.logFile(e),dest:validators.logDest(e),toConsole:validators.logToConsole(e),toFile:validators.logToFile(e)}).partial(),UiSchema=e=>zod.z.object({enable:validators.enableUi(e),route:validators.uiRoute(e)}).partial(),OtherSchema=e=>zod.z.object({nodeEnv:validators.nodeEnv(e),listenToProcessExits:validators.listenToProcessExits(e),noLogo:validators.noLogo(e),hardResetPage:validators.hardResetPage(e),browserShellMode:validators.browserShellMode(e),validation:validators.validation(e)}).partial(),DebugSchema=e=>zod.z.object({enable:validators.enableDebug(e),headless:validators.headless(e),devtools:validators.devtools(e),listenToConsole:validators.listenToConsole(e),dumpio:validators.dumpio(e),slowMo:validators.slowMo(e),debuggingPort:validators.debuggingPort(e)}).partial(),StrictConfigSchema=zod.z.object({requestId:validators.requestId(),puppeteer:PuppeteerSchema(!0),highcharts:HighchartsSchema(!0),export:ExportSchema(!0),customLogic:CustomLogicSchema(!0),server:ServerSchema(!0),pool:PoolSchema(!0),logging:LoggingSchema(!0),ui:UiSchema(!0),other:OtherSchema(!0),debug:DebugSchema(!0)}),LooseConfigSchema=zod.z.object({requestId:validators.requestId(),puppeteer:PuppeteerSchema(!1),highcharts:HighchartsSchema(!1),export:ExportSchema(!1),customLogic:CustomLogicSchema(!1),server:ServerSchema(!1),pool:PoolSchema(!1),logging:LoggingSchema(!1),ui:UiSchema(!1),other:OtherSchema(!1),debug:DebugSchema(!1)}),EnvSchema=zod.z.object({PUPPETEER_ARGS:validators.args(!1),HIGHCHARTS_VERSION:validators.version(!1),HIGHCHARTS_CDN_URL:validators.cdnUrl(!1),HIGHCHARTS_FORCE_FETCH:validators.forceFetch(!1),HIGHCHARTS_CACHE_PATH:validators.cachePath(!1),HIGHCHARTS_ADMIN_TOKEN:validators.adminToken(!1),HIGHCHARTS_CORE_SCRIPTS:validators.coreScripts(!1),HIGHCHARTS_MODULE_SCRIPTS:validators.moduleScripts(!1),HIGHCHARTS_INDICATOR_SCRIPTS:validators.indicatorScripts(!1),HIGHCHARTS_CUSTOM_SCRIPTS:validators.customScripts(!1),EXPORT_INFILE:validators.infile(!1),EXPORT_INSTR:validators.instr(),EXPORT_OPTIONS:validators.options(),EXPORT_SVG:validators.svg(),EXPORT_BATCH:validators.batch(!1),EXPORT_OUTFILE:validators.outfile(!1),EXPORT_TYPE:validators.type(!1),EXPORT_CONSTR:validators.constr(!1),EXPORT_B64:validators.b64(!1),EXPORT_NO_DOWNLOAD:validators.noDownload(!1),EXPORT_HEIGHT:validators.height(!1),EXPORT_WIDTH:validators.width(!1),EXPORT_SCALE:validators.scale(!1),EXPORT_DEFAULT_HEIGHT:validators.defaultHeight(!1),EXPORT_DEFAULT_WIDTH:validators.defaultWidth(!1),EXPORT_DEFAULT_SCALE:validators.defaultScale(!1),EXPORT_GLOBAL_OPTIONS:validators.globalOptions(),EXPORT_THEME_OPTIONS:validators.themeOptions(),EXPORT_RASTERIZATION_TIMEOUT:validators.rasterizationTimeout(!1),CUSTOM_LOGIC_ALLOW_CODE_EXECUTION:validators.allowCodeExecution(!1),CUSTOM_LOGIC_ALLOW_FILE_RESOURCES:validators.allowFileResources(!1),CUSTOM_LOGIC_CUSTOM_CODE:validators.customCode(!1),CUSTOM_LOGIC_CALLBACK:validators.callback(!1),CUSTOM_LOGIC_RESOURCES:validators.resources(!1),CUSTOM_LOGIC_LOAD_CONFIG:validators.loadConfig(!1),CUSTOM_LOGIC_CREATE_CONFIG:validators.createConfig(!1),SERVER_ENABLE:validators.enableServer(!1),SERVER_HOST:validators.host(!1),SERVER_PORT:validators.port(!1),SERVER_UPLOAD_LIMIT:validators.uploadLimit(!1),SERVER_BENCHMARKING:validators.serverBenchmarking(!1),SERVER_PROXY_HOST:validators.proxyHost(!1),SERVER_PROXY_PORT:validators.proxyPort(!1),SERVER_PROXY_TIMEOUT:validators.proxyTimeout(!1),SERVER_RATE_LIMITING_ENABLE:validators.enableRateLimiting(!1),SERVER_RATE_LIMITING_MAX_REQUESTS:validators.maxRequests(!1),SERVER_RATE_LIMITING_WINDOW:validators.window(!1),SERVER_RATE_LIMITING_DELAY:validators.delay(!1),SERVER_RATE_LIMITING_TRUST_PROXY:validators.trustProxy(!1),SERVER_RATE_LIMITING_SKIP_KEY:validators.skipKey(!1),SERVER_RATE_LIMITING_SKIP_TOKEN:validators.skipToken(!1),SERVER_SSL_ENABLE:validators.enableSsl(!1),SERVER_SSL_FORCE:validators.sslForce(!1),SERVER_SSL_PORT:validators.sslPort(!1),SERVER_SSL_CERT_PATH:validators.sslCertPath(!1),POOL_MIN_WORKERS:validators.minWorkers(!1),POOL_MAX_WORKERS:validators.maxWorkers(!1),POOL_WORK_LIMIT:validators.workLimit(!1),POOL_ACQUIRE_TIMEOUT:validators.acquireTimeout(!1),POOL_CREATE_TIMEOUT:validators.createTimeout(!1),POOL_DESTROY_TIMEOUT:validators.destroyTimeout(!1),POOL_IDLE_TIMEOUT:validators.idleTimeout(!1),POOL_CREATE_RETRY_INTERVAL:validators.createRetryInterval(!1),POOL_REAPER_INTERVAL:validators.reaperInterval(!1),POOL_BENCHMARKING:validators.poolBenchmarking(!1),LOGGING_LEVEL:validators.logLevel(!1),LOGGING_FILE:validators.logFile(!1),LOGGING_DEST:validators.logDest(!1),LOGGING_TO_CONSOLE:validators.logToConsole(!1),LOGGING_TO_FILE:validators.logToFile(!1),UI_ENABLE:validators.enableUi(!1),UI_ROUTE:validators.uiRoute(!1),OTHER_NODE_ENV:validators.nodeEnv(!1),OTHER_LISTEN_TO_PROCESS_EXITS:validators.listenToProcessExits(!1),OTHER_NO_LOGO:validators.noLogo(!1),OTHER_HARD_RESET_PAGE:validators.hardResetPage(!1),OTHER_BROWSER_SHELL_MODE:validators.browserShellMode(!1),OTHER_VALIDATION:validators.validation(!1),DEBUG_ENABLE:validators.enableDebug(!1),DEBUG_HEADLESS:validators.headless(!1),DEBUG_DEVTOOLS:validators.devtools(!1),DEBUG_LISTEN_TO_CONSOLE:validators.listenToConsole(!1),DEBUG_DUMPIO:validators.dumpio(!1),DEBUG_SLOW_MO:validators.slowMo(!1),DEBUG_DEBUGGING_PORT:validators.debuggingPort(!1)}),envs=EnvSchema.partial().parse(process.env);function strictValidate(e){return StrictConfigSchema.partial().parse(e)}function looseValidate(e){return LooseConfigSchema.partial().parse(e)}function _customErrorMap(e,t){const o=e.path.join("."),r=`Invalid value for the ${o}`;if(e.code===zod.z.ZodIssueCode.invalid_type)return e.received===zod.z.ZodParsedType.undefined?{message:`${r} - No value was provided.`}:{message:`${r} - Invalid type. ${t.defaultError}.`};if(e.code===zod.z.ZodIssueCode.custom&&e.params?.errorMessage)return{message:`${r} - ${e.params?.errorMessage}, received '${t.data}'.`};if(e.code===zod.z.ZodIssueCode.invalid_union){let t=`Multiple errors occurred for the ${o}:\n`;return e.unionErrors.forEach((e=>{const o=e.issues[0].message.indexOf("-");t+=-1!==o?`${e.issues[0].message}\n`.substring(o):`${e.issues[0].message}\n`})),{message:t}}return{message:`${r} - ${t.defaultError}.`}}class ExportError extends Error{constructor(e,t){super(),this.message=e,this.stackMessage=e,t&&(this.statusCode=t)}setError(e){return this.error=e,e.name&&(this.name=e.name),e.statusCode&&(this.statusCode=e.statusCode),e.stack&&(this.stackMessage=e.message,this.stack=e.stack),this}}const globalOptions=_initOptions(defaultConfig),nestedProps=_createNestedProps(defaultConfig),absoluteProps=_createAbsoluteProps(defaultConfig);function getOptions(e=!0){return e?deepCopy(globalOptions):globalOptions}function updateOptions(e,t=!1,o=!0){return _mergeOptions(getOptions(t),validateOptions(e,o))}function mapToNewOptions(e){const t={};if(isObject(e))for(const[o,r]of Object.entries(e)){const e=nestedProps[o]?nestedProps[o].split("."):[];e.reduce(((t,o,n)=>t[o]=e.length-1===n?r:t[o]||{}),t)}else log(2,"[config] No correct object with options was provided. Returning an empty object.");return t}function validateOption(e,t,o=!0){if(!getOptions().other.validation)return t;try{return validators[e](o).parse(t)}catch(t){throw logZodIssues(1,t.issues,`[validation] The ${e} option validation error`),new ExportError(`[validation] The ${e} option validation error`,400)}}function validateOptions(e,t=!0){if(!getOptions().other.validation)return e;try{return t?strictValidate(e):looseValidate(e)}catch(e){throw logZodIssues(1,e.issues,"[validation] Options validation error"),new ExportError("[validation] Options validation error",400)}}function isAllowedConfig(config,toString=!1,allowFunctions=!1){try{if(!isObject(config)&&"string"!=typeof config)return null;const objectConfig="string"==typeof config?allowFunctions?eval(`(${config})`):JSON.parse(config):config,stringifiedOptions=_optionsStringify(objectConfig,allowFunctions,!1),parsedOptions=allowFunctions?JSON.parse(_optionsStringify(objectConfig,allowFunctions,!0),((_,value)=>"string"==typeof value&&value.startsWith("function")?eval(`(${value})`):value)):JSON.parse(stringifiedOptions);return toString?stringifiedOptions:parsedOptions}catch(e){return null}}function _initOptions(e){const t={};for(const[o,r]of Object.entries(e))Object.prototype.hasOwnProperty.call(r,"value")?void 0!==envs[r.envLink]&&null!==envs[r.envLink]?t[o]=envs[r.envLink]:t[o]=r.value:t[o]=_initOptions(r);return t}function _mergeOptions(e,t){if(isObject(e)&&isObject(t))for(const[o,r]of Object.entries(t))e[o]=isObject(r)&&!absoluteProps.includes(o)&&void 0!==e[o]?_mergeOptions(e[o],r):void 0!==r?r:e[o]||null;return e}function _optionsStringify(e,t,o){return JSON.stringify(e,((e,r)=>{if("string"==typeof r&&(r=r.trim()),"function"==typeof r||"string"==typeof r&&r.startsWith("function")&&r.endsWith("}")){if(t)return o?`"EXP_FUN${(r+"").replaceAll(/\s+/g," ")}EXP_FUN"`:`EXP_FUN${(r+"").replaceAll(/\s+/g," ")}EXP_FUN`;throw new Error}return r})).replaceAll(o?/\\"EXP_FUN|EXP_FUN\\"/g:/"EXP_FUN|EXP_FUN"/g,"")}function _createNestedProps(e,t={},o=""){return Object.keys(e).forEach((r=>{const n=e[r];void 0===n.value?_createNestedProps(n,t,`${o}.${r}`):(t[n.cliName||r]=`${o}.${r}`.substring(1),void 0!==n.legacyName&&(t[n.legacyName]=`${o}.${r}`.substring(1)))})),t}function _createAbsoluteProps(e,t=[]){return Object.keys(e).forEach((o=>{const r=e[o];void 0===r.types?_createAbsoluteProps(r,t):r.types.includes("Object")&&t.push(o)})),t}async function get$1(e,t={}){return new Promise(((o,r)=>{_getProtocolModule(e).get(e,t,(e=>{let t="";e.on("data",(e=>{t+=e})),e.on("end",(()=>{t||r("Nothing was fetched from the URL."),e.text=t,o(e)}))})).on("error",(e=>{r(e)}))}))}function _getProtocolModule(e){return e.startsWith("https")?https:http}const cache={cdnUrl:"https://code.highcharts.com",activeManifest:{},sources:"",hcVersion:""};async function checkCache(e,t){try{let o;const r=getCachePath(),n=path.join(r,"manifest.json"),i=path.join(r,"sources.js");if(!fs.existsSync(r)&&fs.mkdirSync(r,{recursive:!0}),!fs.existsSync(n)||e.forceFetch)log(3,"[cache] Fetching and caching Highcharts dependencies."),o=await _updateCache(e,t,i);else{let r=!1;const s=JSON.parse(fs.readFileSync(n),"utf8");if(s.modules&&Array.isArray(s.modules)){const e={};s.modules.forEach((t=>e[t]=1)),s.modules=e}const{coreScripts:a,moduleScripts:l,indicatorScripts:c}=e,p=a.length+l.length+c.length;s.version!==e.version?(log(2,"[cache] A Highcharts version mismatch in the cache, need to re-fetch."),r=!0):Object.keys(s.modules||{}).length!==p?(log(2,"[cache] The cache and the requested modules do not match, need to re-fetch."),r=!0):r=(l||[]).some((e=>{if(!s.modules[e])return log(2,`[cache] The ${e} is missing in the cache, need to re-fetch.`),!0})),r?o=await _updateCache(e,t,i):(log(3,"[cache] Dependency cache is up to date, proceeding."),cache.sources=fs.readFileSync(i,"utf8"),o=s.modules,cache.hcVersion=_extractHcVersion(cache.sources))}await _saveConfigToManifest(e.version,o)}catch(e){throw new ExportError("[cache] Could not configure cache and create or update the config manifest.",500).setError(e)}}function getHcVersion(){return cache.hcVersion}async function updateHcVersion(e){const t=updateOptions({highcharts:{version:e}});await checkCache(t.highcharts,t.server.proxy)}function getCachePath(){return getAbsolutePath(getOptions().highcharts.cachePath)}async function _saveConfigToManifest(e,t={}){cache.activeManifest={version:e,modules:t},log(3,"[cache] Writing a new manifest.");try{fs.writeFileSync(path.join(getCachePath(),"manifest.json"),JSON.stringify(cache.activeManifest),"utf8")}catch(e){throw new ExportError("[cache] Error writing the cache manifest.",500).setError(e)}}async function _updateCache(e,t,o){try{const r="latest"===e.version?null:`${e.version}`;log(3,`[cache] Updating cache version to Highcharts: ${r||"latest"}.`);const n=e.cdnUrl||cache.cdnUrl,i=_configureRequest(t),s={};return cache.sources=(await Promise.all([...e.coreScripts.map((e=>_fetchScript(r?`${n}/${r}/${e}`:`${n}/${e}`,i,s,!0))),...e.moduleScripts.map((e=>_fetchScript("map"===e?r?`${n}/maps/${r}/modules/${e}`:`${n}/maps/modules/${e}`:r?`${n}/${r}/modules/${e}`:`${n}/modules/${e}`,i,s))),...e.indicatorScripts.map((e=>_fetchScript(r?`${n}/stock/${r}/indicators/${e}`:`${n}/stock/indicators/${e}`,i,s))),...e.customScripts.map((e=>_fetchScript(`${e}`,i)))])).join(";\n"),cache.hcVersion=_extractHcVersion(cache.sources),fs.writeFileSync(o,cache.sources),s}catch(e){throw new ExportError("[cache] Unable to update the local Highcharts cache.",500).setError(e)}}async function _fetchScript(e,t,o,r=!1){e.endsWith(".js")&&(e=e.substring(0,e.length-3)),log(4,`[cache] Fetching script - ${e}.js`);const n=await get$1(`${e}.js`,t);if(200===n.statusCode&&"string"==typeof n.text){if(o){o[_extractModuleName(e)]=1}return n.text}if(r)throw new ExportError(`[cache] Could not fetch the ${e}.js. The script might not exist in the requested version (status code: ${n.statusCode}).`,404).setError(n);log(2,`[cache] Could not fetch the ${e}.js. The script might not exist in the requested version.`)}function _configureRequest(e){const t=e.host,o=e.port;if(t&&o)try{return{agent:new httpsProxyAgent.HttpsProxyAgent({host:t,port:o}),timeout:e.timeout}}catch(e){throw new ExportError("[cache] Could not create a Proxy Agent.",500).setError(e)}return{}}function _extractHcVersion(e){return e.substring(0,e.indexOf("*/")).replace("/*","").replace("*/","").replace(/\n/g,"").trim()}function _extractModuleName(e){return e.replace(/(.*)\/|(.*)modules\/|stock\/(.*)indicators\/|maps\/(.*)modules\//gi,"")}function setupHighcharts(){Highcharts.animObject=function(){return{duration:0}}}async function createChart(e,t){const{getOptions:o,setOptions:r,merge:n,wrap:i}=Highcharts;Highcharts.setOptionsObj=n(!1,{},o()),window.isRenderComplete=!1,i(Highcharts.Chart.prototype,"init",(function(e,t,o){((t=n(t,{exporting:{enabled:!1},plotOptions:{series:{label:{enabled:!1}}},tooltip:{}})).series||[]).forEach((function(e){e.animation=!1})),window.onHighchartsRender||(window.onHighchartsRender=Highcharts.addEvent(this,"render",(()=>{window.isRenderComplete=!0}))),e.apply(this,[t,o])})),i(Highcharts.Series.prototype,"init",(function(e,t,o){e.apply(this,[t,o])}));const s={chart:{animation:!1,height:e.height,width:e.width},exporting:{enabled:!1}},a=new Function(`return ${e.instr}`)(),l=new Function(`return ${e.themeOptions}`)(),c=n(!1,l,a,s),p=t.callback?new Function(`return ${t.callback}`)():null;t.customCode&&new Function("options",t.customCode)(a);const u=new Function(`return ${e.globalOptions}`)();u&&r(u),Highcharts[e.constr]("container",c,p);const d=Array.from(document.querySelectorAll(".highcharts-container image"));await Promise.race([Promise.all(d.map((e=>e.complete&&0!==e.naturalHeight?Promise.resolve():new Promise((t=>e.addEventListener("load",t,{once:!0})))))),new Promise((e=>setTimeout(e,2e3)))]);const g=o();for(const e in g)"function"!=typeof g[e]&&delete g[e];r(Highcharts.setOptionsObj),Highcharts.setOptionsObj={}}const pageTemplate=fs.readFileSync(path.join(__dirname$1,"templates","template.html"),"utf8");let browser=null;async function createBrowser(e){const{debug:t,other:o}=getOptions(),{enable:r,...n}=t,i={headless:!o.browserShellMode||"shell",userDataDir:"tmp",args:e||[],handleSIGINT:!1,handleSIGTERM:!1,handleSIGHUP:!1,waitForInitialPage:!1,defaultViewport:null,...r&&n};if(!browser){let e=0;const t=async()=>{try{log(3,`[browser] Attempting to launch and get a browser instance (try ${++e}).`),browser=await puppeteer.launch(i)}catch(o){if(logWithStack(1,o,"[browser] Failed to launch a browser instance."),!(e<25))throw o;log(3,`[browser] Retry to open a browser (${e} out of 25).`),await new Promise((e=>setTimeout(e,4e3))),await t()}};try{await t(),"shell"===i.headless&&log(3,"[browser] Launched browser in shell mode."),r&&log(3,"[browser] Launched browser in debug mode.")}catch(e){throw new ExportError("[browser] Maximum retries to open a browser instance reached.",500).setError(e)}if(!browser)throw new ExportError("[browser] Cannot find a browser to open.",500)}return browser}async function closeBrowser(){browser&&browser.connected&&await browser.close(),browser=null,log(4,"[browser] Closed the browser.")}async function newPage(e){if(!browser||!browser.connected)throw new ExportError("[browser] Browser is not yet connected.",500);if(e.page=await browser.newPage(),await e.page.setCacheEnabled(!1),await _setPageContent(e.page),_setPageEvents(e.page),!e.page||e.page.isClosed())throw new ExportError("[browser] The page is invalid or closed.",400)}async function clearPage(e,t=!1){try{if(e.page&&!e.page.isClosed())return t?(await e.page.goto("about:blank",{waitUntil:"domcontentloaded"}),await _setPageContent(e.page)):await e.page.evaluate((()=>{document.body.innerHTML='
'})),!0}catch(t){logWithStack(2,t,`[pool] Pool resource [${e.id}] - Content of the page could not be cleared.`),e.workCount=getOptions().pool.workLimit+1}return!1}async function addPageResources(e,t){const o=[],r=t.resources;if(r){const n=[];if(r.js&&n.push({content:r.js}),r.files)for(const e of r.files){const t=!e.startsWith("http");n.push(t?{content:fs.readFileSync(getAbsolutePath(e),"utf8")}:{url:e})}for(const t of n)try{o.push(await e.addScriptTag(t))}catch(e){logWithStack(2,e,"[browser] The JS resource cannot be loaded.")}n.length=0;const i=[];if(r.css){const n=r.css.match(/@import\s*([^;]*);/g);if(n)for(let e of n)e&&(e=e.replace("url(","").replace("@import","").replace(/"/g,"").replace(/'/g,"").replace(/;/,"").replace(/\)/g,"").trim(),e.startsWith("http")?i.push({url:e}):t.allowFileResources&&i.push({path:getAbsolutePath(e)}));i.push({content:r.css.replace(/@import\s*([^;]*);/g,"")||" "});for(const t of i)try{o.push(await e.addStyleTag(t))}catch(e){logWithStack(2,e,"[browser] The CSS resource cannot be loaded.")}i.length=0}}return o}async function clearPageResources(e,t){try{for(const e of t)await e.dispose();await e.evaluate((()=>{if("undefined"!=typeof Highcharts){const e=Highcharts.charts;if(Array.isArray(e)&&e.length)for(const t of e)t&&t.destroy(),Highcharts.charts.shift()}const[...e]=document.getElementsByTagName("script"),[,...t]=document.getElementsByTagName("style"),[...o]=document.getElementsByTagName("link");for(const r of[...e,...t,...o])r.remove()}))}catch(e){logWithStack(2,e,"[browser] Could not clear page's resources.")}}async function _setPageContent(e){await e.setContent(pageTemplate,{waitUntil:"domcontentloaded"}),await e.addScriptTag({path:path.join(getCachePath(),"sources.js")}),await e.evaluate(setupHighcharts)}function _setPageEvents(e){const{debug:t}=getOptions();e.on("pageerror",(async()=>{e.isClosed()})),t.enable&&t.listenToConsole&&e.on("console",(e=>{console.log(`[debug] ${e.text()}`)}))}var cssTemplate=()=>"\n\nhtml, body {\n margin: 0;\n padding: 0;\n box-sizing: border-box;\n}\n\n#table-div, #sliders, #datatable, #controls, .ld-row {\n display: none;\n height: 0;\n}\n\n#chart-container {\n box-sizing: border-box;\n margin: 0;\n overflow: auto;\n font-size: 0;\n}\n\n#chart-container > figure, div {\n margin-top: 0 !important;\n margin-bottom: 0 !important;\n}\n\n",svgTemplate=e=>`\n\n\n \n \n Highcharts Export\n \n \n \n
\n ${e}\n
\n \n\n\n`;async function puppeteerExport(e,t,o){const r=[];try{let n=!1;if(t.svg){if(log(4,"[export] Treating as SVG input."),"svg"===t.type)return t.svg;n=!0,await e.setContent(svgTemplate(t.svg),{waitUntil:"domcontentloaded"})}else log(4,"[export] Treating as JSON config."),await e.evaluate(createChart,t,o);r.push(...await addPageResources(e,o));const i=await _getChartSize(e,n,t.scale),{x:s,y:a}=await _getClipRegion(e),l=Math.abs(Math.ceil(i.chartHeight||t.height)),c=Math.abs(Math.ceil(i.chartWidth||t.width));let p;switch(await e.setViewport({height:l,width:c,deviceScaleFactor:n?1:parseFloat(t.scale)}),t.type){case"svg":p=await _createSVG(e);break;case"png":case"jpeg":p=await _createImage(e,t.type,{width:c,height:l,x:s,y:a},t.rasterizationTimeout);break;case"pdf":p=await _createPDF(e,l,c,t.rasterizationTimeout);break;default:throw new ExportError(`[export] Unsupported output format: ${t.type}.`,400)}return await clearPageResources(e,r),p}catch(t){return await clearPageResources(e,r),t}}async function _getClipRegion(e){return e.$eval("#chart-container",(e=>{const{x:t,y:o,width:r,height:n}=e.getBoundingClientRect();return{x:t,y:o,width:r,height:Math.trunc(n>1?n:500)}}))}async function _getChartSize(e,t,o){return t?await e.evaluate((e=>{const t=document.querySelector("#chart-container svg:first-of-type"),o=t.height.baseVal.value*e,r=t.width.baseVal.value*e;return document.body.style.zoom=e,document.body.style.margin="0px",{chartHeight:o,chartWidth:r}}),parseFloat(o)):await e.evaluate((()=>{const{chartHeight:e,chartWidth:t}=window.Highcharts.charts[0];return document.body.style.zoom=1,{chartHeight:e,chartWidth:t}}))}async function _createSVG(e){return e.$eval("#container svg:first-of-type",(e=>e.outerHTML))}async function _createImage(e,t,o,r){return Promise.race([e.screenshot({type:t,clip:o,encoding:"base64",fullPage:!1,optimizeForSpeed:!0,captureBeyondViewport:!0,..."png"!==t?{quality:80}:{},omitBackground:"png"==t}),new Promise(((e,t)=>setTimeout((()=>t(new ExportError("Rasterization timeout",408))),r||1500)))])}async function _createPDF(e,t,o,r){return await e.emulateMediaType("screen"),e.pdf({height:t+1,width:o,encoding:"base64",timeout:r||1500})}let pool=null;const poolStats={exportsAttempted:0,exportsPerformed:0,exportsDropped:0,exportsFromSvg:0,exportsFromOptions:0,exportsFromSvgAttempts:0,exportsFromOptionsAttempts:0,timeSpent:0,timeSpentAverage:0};async function initPool(e,t){await createBrowser(t);try{if(log(3,`[pool] Initializing pool with workers: min ${e.minWorkers}, max ${e.maxWorkers}.`),pool)return void log(4,"[pool] Already initialized, please kill it before creating a new one.");e.minWorkers>e.maxWorkers&&(e.minWorkers=e.maxWorkers),pool=new tarn.Pool({..._factory(e),min:e.minWorkers,max:e.maxWorkers,acquireTimeoutMillis:e.acquireTimeout,createTimeoutMillis:e.createTimeout,destroyTimeoutMillis:e.destroyTimeout,idleTimeoutMillis:e.idleTimeout,createRetryIntervalMillis:e.createRetryInterval,reapIntervalMillis:e.reaperInterval,propagateCreateError:!1}),pool.on("release",(async e=>{const t=await clearPage(e,!1);log(4,`[pool] Pool resource [${e.id}] - Releasing a worker. Clear page status: ${t}.`)})),pool.on("destroySuccess",((e,t)=>{log(4,`[pool] Pool resource [${t.id}] - Destroyed a worker successfully.`),t.page=null}));const t=[];for(let o=0;o{pool.release(e)})),log(3,"[pool] The pool is ready"+(t.length?` with ${t.length} initial resources waiting.`:"."))}catch(e){throw new ExportError("[pool] Could not configure and create the pool of workers.",500).setError(e)}}async function killPool(){if(log(3,"[pool] Killing pool with all workers and closing browser."),pool){for(const e of pool.used)pool.release(e.resource);pool.destroyed||(await pool.destroy(),log(4,"[pool] Destroyed the pool of resources.")),pool=null}await closeBrowser()}async function postWork(e){let t;try{if(log(4,"[pool] Work received, starting to process."),++poolStats.exportsAttempted,e.pool.benchmarking&&_getPoolInfo(),!pool)throw new ExportError("[pool] Work received, but pool has not been started.",500);const o=measureTime();try{log(4,"[pool] Acquiring a worker handle."),t=await pool.acquire().promise,e.server.benchmarking&&log(5,"[benchmark] "+(e.requestId?`Request [${e.requestId}] - `:""),`Acquiring a worker handle took ${o()}ms.`)}catch(t){throw new ExportError(`[pool] ${e.requestId?`Request [${e.requestId}] - `:""}Error encountered when acquiring an available entry: ${o()}ms.`,400).setError(t)}if(log(4,"[pool] Acquired a worker handle."),!t.page)throw t.workCount=e.pool.workLimit+1,new ExportError("[pool] Resolved worker page is invalid: the pool setup is wonky.",400);log(4,`[pool] Pool resource [${t.id}] - Starting work on this pool entry.`);const r=measureTime(),n=await puppeteerExport(t.page,e.export,e.customLogic);if(n instanceof Error)throw"Rasterization timeout"===n.message&&(t.workCount=e.pool.workLimit+1,t.page=null),"TimeoutError"===n.name||"Rasterization timeout"===n.message?new ExportError(`[pool] ${e.requestId?`Request [${e.requestId}] - `:""}Rasterization timeout: your chart may be too complex or large, and failed to render within the allotted time.`).setError(n):new ExportError(`[pool] ${e.requestId?`Request [${e.requestId}] - `:""}Error encountered during export: ${r()}ms.`).setError(n);return e.server.benchmarking&&log(5,"[benchmark] "+(e.requestId?`Request [${e.requestId}] - `:""),`Exporting a chart sucessfully took ${r()}ms.`),pool.release(t),poolStats.timeSpent+=r(),poolStats.timeSpentAverage=poolStats.timeSpent/++poolStats.exportsPerformed,log(4,`[pool] Work completed in ${r()}ms.`),{result:n,options:e}}catch(e){throw++poolStats.exportsDropped,t&&pool.release(t),e}}function getPoolStats(){return poolStats}function getPoolInfoJSON(){return{min:pool.min,max:pool.max,used:pool.numUsed(),available:pool.numFree(),allCreated:pool.numUsed()+pool.numFree(),pendingAcquires:pool.numPendingAcquires(),pendingCreates:pool.numPendingCreates(),pendingValidations:pool.numPendingValidations(),pendingDestroys:pool.pendingDestroys.length,absoluteAll:pool.numUsed()+pool.numFree()+pool.numPendingAcquires()+pool.numPendingCreates()+pool.numPendingValidations()+pool.pendingDestroys.length}}function _getPoolInfo(){const{min:e,max:t,used:o,available:r,allCreated:n,pendingAcquires:i,pendingCreates:s,pendingValidations:a,pendingDestroys:l,absoluteAll:c}=getPoolInfoJSON();log(5,`[pool] The minimum number of resources allowed by pool: ${e}.`),log(5,`[pool] The maximum number of resources allowed by pool: ${t}.`),log(5,`[pool] The number of used resources: ${o}.`),log(5,`[pool] The number of free resources: ${r}.`),log(5,`[pool] The number of all created (used and free) resources: ${n}.`),log(5,`[pool] The number of resources waiting to be acquired: ${i}.`),log(5,`[pool] The number of resources waiting to be created: ${s}.`),log(5,`[pool] The number of resources waiting to be validated: ${a}.`),log(5,`[pool] The number of resources waiting to be destroyed: ${l}.`),log(5,`[pool] The number of all resources: ${c}.`)}function _factory(e){return{create:async()=>{const t={id:uuid.v4(),workCount:Math.round(Math.random()*(e.workLimit/2))};try{const e=getNewDateTime();return await newPage(t),log(3,`[pool] Pool resource [${t.id}] - Successfully created a worker, took ${getNewDateTime()-e}ms.`),t}catch(e){throw log(3,`[pool] Pool resource [${t.id}] - Error encountered when creating a new page.`),e}},validate:async t=>t.page?t.page.isClosed()?(log(3,`[pool] Pool resource [${t.id}] - Validation failed (page is closed or invalid).`),!1):t.page.mainFrame().detached?(log(3,`[pool] Pool resource [${t.id}] - Validation failed (page's frame is detached).`),!1):!(e.workLimit&&++t.workCount>e.workLimit)||(log(3,`[pool] Pool resource [${t.id}] - Validation failed (exceeded the ${e.workLimit} works per resource limit).`),!1):(log(3,`[pool] Pool resource [${t.id}] - Validation failed (no valid page is found).`),!1),destroy:async e=>{if(log(3,`[pool] Pool resource [${e.id}] - Destroying a worker.`),e.page&&!e.page.isClosed())try{e.page.removeAllListeners("pageerror"),e.page.removeAllListeners("console"),e.page.removeAllListeners("framedetached"),await e.page.close()}catch(t){throw log(3,`[pool] Pool resource [${e.id}] - Page could not be closed upon destroying.`),t}}}}function sanitize(e){const t=new jsdom.JSDOM("").window;return DOMPurify(t).sanitize(e,{ADD_TAGS:["foreignObject"]})}let allowCodeExecution=!1;async function singleExport(e){if(!e||!e.export)throw new ExportError("[chart] No expected `export` options were found. Please provide one of the following options: `infile`, `instr`, `options`, or `svg` to generate a valid image.",400);await startExport({export:e.export,customLogic:e.customLogic},(async(e,t)=>{if(e)throw e;const{b64:o,outfile:r,type:n}=t.options.export;try{o?fs.writeFileSync(`${r.split(".").shift()||"chart"}.txt`,getBase64(t.result,n)):fs.writeFileSync(r||`chart.${n}`,"svg"!==n?Buffer.from(t.result,"base64"):t.result)}catch(e){throw new ExportError("[chart] Error while saving a chart.",500).setError(e)}await killPool()}))}async function batchExport(e){if(!(e&&e.export&&e.export.batch))throw new ExportError("[chart] No expected `export` options were found. Please provide the `batch` option to generate valid images.",400);{const t=[];for(let o of e.export.batch.split(";")||[])o=o.split("="),2===o.length?t.push(startExport({export:{...e.export,infile:o[0],outfile:o[1]},customLogic:e.customLogic},((e,t)=>{if(e)throw e;const{b64:o,outfile:r,type:n}=t.options.export;try{o?fs.writeFileSync(`${r.split(".").shift()||"chart"}.txt`,getBase64(t.result,n)):fs.writeFileSync(r,"svg"!==n?Buffer.from(t.result,"base64"):t.result)}catch(e){throw new ExportError("[chart] Error while saving a chart.",500).setError(e)}}))):log(2,"[chart] No correct pair found for the batch export.");const o=await Promise.allSettled(t);await killPool(),o.forEach(((e,t)=>{e.reason&&logWithStack(1,e.reason,`[chart] Batch export number ${t+1} could not be correctly completed.`)}))}}async function startExport(e,t){try{if(!isObject(e))throw new ExportError("[chart] Incorrect value of the provided `imageOptions`. Needs to be an object.",400);const o=updateOptions({export:e.export,customLogic:e.customLogic},!0),r=o.export;if(log(4,"[chart] Starting the exporting process."),null!==r.infile){let e;log(4,"[chart] Attempting to export from a file input.");try{e=fs.readFileSync(getAbsolutePath(r.infile),"utf8")}catch(e){throw new ExportError("[chart] Error loading content from a file input.",400).setError(e)}if(r.infile.endsWith(".svg"))r.svg=validateOption("svg",e);else{if(!r.infile.endsWith(".json"))throw new ExportError("[chart] Incorrect value of the `infile` option.",400);r.instr=validateOption("instr",e)}}if(null!==r.svg){log(4,"[chart] Attempting to export from an SVG input."),++getPoolStats().exportsFromSvgAttempts;const e=await _exportFromSvg(sanitize(r.svg),o);return++getPoolStats().exportsFromSvg,t(null,e)}if(null!==r.instr||null!==r.options){log(4,"[chart] Attempting to export from options input."),++getPoolStats().exportsFromOptionsAttempts;const e=await _exportFromOptions(r.instr||r.options,o);return++getPoolStats().exportsFromOptions,t(null,e)}return t(new ExportError("[chart] No valid input specified. Check if at least one of the following parameters is correctly set: 'infile', 'instr', 'options', or 'svg'.",400))}catch(e){return t(e)}}function getAllowCodeExecution(){return allowCodeExecution}function setAllowCodeExecution(e){allowCodeExecution=e}async function _exportFromSvg(e,t){if("string"==typeof e&&(e.indexOf("=0||e.indexOf("=0))return log(4,"[chart] Parsing input as SVG."),t.export.svg=e,t.export.options=null,t.export.instr=null,_prepareExport(t);throw new ExportError("[chart] Not a correct SVG input.",400)}async function _exportFromOptions(e,t){log(4,"[chart] Parsing input from options.");const o=isAllowedConfig(e,!0,t.customLogic.allowCodeExecution);if(null===o||"string"!=typeof o||!o.startsWith("{")||!o.endsWith("}"))throw new ExportError("[chart] Invalid configuration provided - Only options configurations and SVG are allowed for this server. If this is your server, JavaScript custom code can be enabled by starting the server with the `allowCodeExecution` options set to true.",403);return t.export.instr=o,t.export.options=null,t.export.svg=null,_prepareExport(t)}async function _prepareExport(e){const{export:t,customLogic:o}=e;return t.constr=_fixConstr(t.constr),t.type=_fixType(t.type,t.outfile),t.outfile=_fixOutfile(t.type,t.outfile),log(3,`[chart] The custom logic is ${o.allowCodeExecution?"allowed":"disallowed"}.`),_handleCustomLogic(o),_handleGlobalAndTheme(t,o),_handleSize(t),_checkDataSize({export:t,customLogic:o}),postWork(e)}function _fixConstr(e){try{const t=`${e.toLowerCase().replace("chart","")}Chart`;return"Chart"===t&&t.toLowerCase(),["chart","stockChart","mapChart","ganttChart"].includes(t)?t:"chart"}catch{return"chart"}}function _fixOutfile(e,t){return`${getAbsolutePath(t||"chart").split(".").shift()}.${e||"png"}`}function _fixType(e,t=null){const o={"image/png":"png","image/jpeg":"jpeg","application/pdf":"pdf","image/svg+xml":"svg"},r=Object.values(o);if(t){const o=t.split(".").pop();"jpg"===o?e="jpeg":r.includes(o)&&e!==o&&(e=o)}return o[e]||r.find((t=>t===e))||"png"}function _handleSize(e){const{chart:t,exporting:o}=isAllowedConfig(e.instr)||!1,{chart:r,exporting:n}=isAllowedConfig(e.globalOptions)||!1,{chart:i,exporting:s}=isAllowedConfig(e.themeOptions)||!1,a=e.height||o?.sourceHeight||t?.height||n?.sourceHeight||r?.height||s?.sourceHeight||i?.height||e.defaultHeight||400,l=e.width||o?.sourceWidth||t?.width||n?.sourceWidth||r?.width||s?.sourceWidth||i?.width||e.defaultWidth||600,c=roundNumber(Math.max(.1,Math.min(e.scale||o?.scale||n?.scale||s?.scale||e.defaultScale||1,5)),2);e.height=a,e.width=l,e.scale=c;for(let t of["height","width","scale"])"string"==typeof e[t]&&(e[t]=+e[t].replace(/px|%/gi,""))}function _handleCustomLogic(e){if(e.allowCodeExecution){try{e.resources=_handleResources(e.resources,e.allowFileResources,!0),e.resources=validateOption("resources",e.resources)}catch(t){log(2,"[chart] The `resources` cannot be loaded."),e.resources=null}try{e.customCode=_handleCustomCode(e.customCode,e.allowFileResources),e.customCode=validateOption("customCode",e.customCode)}catch(t){logWithStack(2,t,"[chart] The `customCode` cannot be loaded."),e.customCode=null}try{e.callback=_handleCustomCode(e.callback,e.allowFileResources,!0),e.callback=validateOption("callback",e.callback)}catch(t){logWithStack(2,t,"[chart] The `callback` cannot be loaded."),e.callback=null}[null,void 0].includes(e.customCode)&&log(3,"[chart] No value for the `customCode` option found."),[null,void 0].includes(e.callback)&&log(3,"[chart] No value for the `callback` option found."),[null,void 0].includes(e.resources)&&log(3,"[chart] No value for the `resources` option found.")}else if(e.callback||e.resources||e.customCode)throw e.callback=null,e.resources=null,e.customCode=null,new ExportError("[chart] The 'callback', 'resources', and 'customCode' options have been disabled for this server.",403)}function _handleResources(e=null,t,o){let r=e;r||(e="resources.json");const n=["js","css","files"];let i=!1;t&&"string"==typeof e&&e.endsWith(".json")?r=isAllowedConfig(fs.readFileSync(getAbsolutePath(e),"utf8"),!1,o):(r=isAllowedConfig(e,!1,o),r&&!t&&delete r.files);for(const e in r)n.includes(e)?i||(i=!0):delete r[e];return i?(r.files&&(r.files=r.files.map((e=>e.trim())),(!r.files||r.files.length<=0)&&delete r.files),r):null}function _handleCustomCode(e,t,o=!1){if(e&&"string"==typeof e)return(e=e.trim()).endsWith(".js")?t?_handleCustomCode(fs.readFileSync(getAbsolutePath(e),"utf8"),t,o):null:!o&&(e.startsWith("function()")||e.startsWith("function ()")||e.startsWith("()=>")||e.startsWith("() =>"))?`(${e})()`:e.replace(/;$/,"")}function _handleGlobalAndTheme(e,t){const{allowFileResources:o,allowCodeExecution:r}=t;["globalOptions","themeOptions"].forEach((t=>{try{e[t]&&(o&&"string"==typeof e[t]&&e[t].endsWith(".json")?e[t]=isAllowedConfig(fs.readFileSync(getAbsolutePath(e[t]),"utf8"),!0,r):e[t]=isAllowedConfig(e[t],!0,r),e[t]=validateOption(t,e[t]))}catch(o){logWithStack(2,o,`[chart] The \`${t}\` cannot be loaded.`),e[t]=null}})),[null,void 0].includes(e.globalOptions)&&log(3,"[chart] No value for the `globalOptions` option found."),[null,void 0].includes(e.themeOptions)&&log(3,"[chart] No value for the `themeOptions` option found.")}function _checkDataSize(e){const t=Buffer.byteLength(JSON.stringify(e),"utf-8");if(log(3,`[chart] The current total size of the data for the export process is around ${(t/1048576).toFixed(2)}MB.`),t>=104857600)throw new ExportError("[chart] The data for the export process exceeds 100MB limit.")}const timerIds=[];function addTimer(e){timerIds.push(e)}function clearAllTimers(){log(4,"[timer] Clearing all registered intervals and timeouts.");for(const e of timerIds)clearInterval(e),clearTimeout(e)}function logErrorMiddleware(e,t,o,r){return logWithStack(1,e),"development"!==getOptions().other.nodeEnv&&delete e.stack,r(e)}function returnErrorMiddleware(e,t,o,r){const{message:n,stack:i}=e,s=e.statusCode||400;o.status(s).json({statusCode:s,message:n,stack:i})}function errorMiddleware(e){e.use(logErrorMiddleware),e.use(returnErrorMiddleware)}function rateLimitingMiddleware(e,t){try{if(e&&t.enable){const o="Too many requests, you have been rate limited. Please try again later.",r={window:t.window||1,maxRequests:t.maxRequests||30,delay:t.delay||0,trustProxy:t.trustProxy||!1,skipKey:t.skipKey||null,skipToken:t.skipToken||null};r.trustProxy&&e.enable("trust proxy");const n=rateLimit({windowMs:60*r.window*1e3,limit:r.maxRequests,delayMs:r.delay,handler:(e,t)=>{t.format({json:()=>{t.status(429).send({message:o})},default:()=>{t.status(429).send(o)}})},skip:e=>null!==r.skipKey&&null!==r.skipToken&&e.query.key===r.skipKey&&e.query.access_token===r.skipToken&&(log(4,"[rate limiting] Skipping rate limiter."),!0)});e.use(n),log(3,`[rate limiting] Enabled rate limiting with ${r.maxRequests} requests per ${r.window} minute for each IP, trusting proxy: ${r.trustProxy}.`)}}catch(e){throw new ExportError("[rate limiting] Could not configure and set the rate limiting options.",500).setError(e)}}function contentTypeMiddleware(e,t,o){try{const t=e.headers["content-type"]||"";if(!t.includes("application/json")&&!t.includes("application/x-www-form-urlencoded")&&!t.includes("multipart/form-data"))throw new ExportError("[validation] Content-Type must be application/json, application/x-www-form-urlencoded, or multipart/form-data.",415);return o()}catch(e){return o(e)}}function requestBodyMiddleware(e,t,o){try{const t=e.body,r=uuid.v4();if(!t||isObjectEmpty(t))throw log(2,`[validation] Request [${r}] - The request from ${e.headers["x-forwarded-for"]||e.connection.remoteAddress} was incorrect. Received payload is empty.`),new ExportError(`[validation] Request [${r}] - The request body is required. Please ensure that your Content-Type header is correct. Accepted types are 'application/json' and 'multipart/form-data'.`,400);const n=getAllowCodeExecution(),i=isAllowedConfig(t.instr||t.options||t.infile||t.data,!0,n);if(null===i&&!t.svg)throw log(2,`[validation] Request [${r}] - The request from ${e.headers["x-forwarded-for"]||e.connection.remoteAddress} was incorrect. Received payload is missing correct chart data for export: ${JSON.stringify(t)}.`),new ExportError(`[validation] Request [${r}] - No correct chart data found. Ensure that you are using either application/json or multipart/form-data headers. If sending JSON, make sure the chart data is in the 'infile', 'options', or 'data' attribute. If sending SVG, ensure it is in the 'svg' attribute.`,400);if(t.svg&&isPrivateRangeUrlFound(t.svg))throw new ExportError(`[validation] Request [${r}] - SVG potentially contain at least one forbidden URL in 'xlink:href' element. Please review the SVG content and ensure that all referenced URLs comply with security policies.`,400);return e.validatedOptions={requestId:r,export:{instr:i,svg:t.svg,outfile:t.outfile||`${e.params.filename||"chart"}.${t.type||"png"}`,type:t.type,constr:t.constr,b64:t.b64,noDownload:t.noDownload,height:t.height,width:t.width,scale:t.scale,globalOptions:isAllowedConfig(t.globalOptions,!0,n),themeOptions:isAllowedConfig(t.themeOptions,!0,n)},customLogic:{allowCodeExecution:n,allowFileResources:!1,customCode:t.customCode,callback:t.callback,resources:isAllowedConfig(t.resources,!0,n)}},o()}catch(e){return o(e)}}function validationMiddleware(e){e.post(["/","/:filename"],contentTypeMiddleware),e.post(["/","/:filename"],requestBodyMiddleware)}const reversedMime={png:"image/png",jpeg:"image/jpeg",gif:"image/gif",pdf:"application/pdf",svg:"image/svg+xml"};async function requestExport(e,t,o){try{const o=measureTime();let r=!1;e.socket.on("close",(e=>{e&&(r=!0)}));const n=e.validatedOptions,i=n.requestId;log(4,`[export] Request [${i}] - Got an incoming HTTP request.`),await startExport(n,((n,s)=>{if(e.socket.removeAllListeners("close"),r)log(3,`[export] Request [${i}] - The client closed the connection before the chart finished processing.`);else{if(n)throw n;if(!s||!s.result)throw log(2,`[export] Request [${i}] - Request from ${e.headers["x-forwarded-for"]||e.connection.remoteAddress} was incorrect. Received result is ${s.result}.`),new ExportError(`[export] Request [${i}] - Unexpected return of the export result from the chart generation. Please check your request data.`,400);if(s.result){log(3,`[export] Request [${i}] - The whole exporting process took ${o()}ms.`);const{type:e,b64:r,noDownload:n,outfile:a}=s.options.export;return r?t.send(getBase64(s.result,e)):(t.header("Content-Type",reversedMime[e]||"image/png"),n||t.attachment(a),"svg"===e?t.send(s.result):t.send(Buffer.from(s.result,"base64")))}}}))}catch(e){return o(e)}}function exportRoutes(e){e.post("/",requestExport),e.post("/:filename",requestExport)}const serverStartTime=new Date,packageFile=JSON.parse(fs.readFileSync(path.join(__dirname$1,"package.json"),"utf8")),successRates=[],recordInterval=6e4,windowSize=30;function _calculateMovingAverage(){return successRates.reduce(((e,t)=>e+t),0)/successRates.length}function _startSuccessRate(){return setInterval((()=>{const e=getPoolStats(),t=0===e.exportsAttempted?1:e.exportsPerformed/e.exportsAttempted*100;successRates.push(t),successRates.length>windowSize&&successRates.shift()}),recordInterval)}function healthRoutes(e){addTimer(_startSuccessRate()),e.get("/health",((e,t,o)=>{try{log(4,"[health] Returning server health.");const e=getPoolStats(),o=successRates.length,r=_calculateMovingAverage();t.send({status:"OK",bootTime:serverStartTime,uptime:`${Math.floor((getNewDateTime()-serverStartTime.getTime())/1e3/60)} minutes`,serverVersion:packageFile.version,highchartsVersion:getHcVersion(),averageExportTime:e.timeSpentAverage,attemptedExports:e.exportsAttempted,performedExports:e.exportsPerformed,failedExports:e.exportsDropped,sucessRatio:e.exportsPerformed/e.exportsAttempted*100,pool:getPoolInfoJSON(),period:o,movingAverage:r,message:isNaN(r)||!successRates.length?"Too early to report. No exports made yet. Please check back soon.":`Last ${o} minutes had a success rate of ${r.toFixed(2)}%.`,svgExports:e.exportsFromSvg,jsonExports:e.exportsFromOptions,svgExportsAttempts:e.exportsFromSvgAttempts,jsonExportsAttempts:e.exportsFromOptionsAttempts})}catch(e){return o(e)}}))}function uiRoutes(e){getOptions().ui.enable&&e.get(getOptions().ui.route||"/",((e,t,o)=>{try{log(4,"[ui] Returning UI for the export."),t.sendFile(path.join(__dirname$1,"public","index.html"),{acceptRanges:!1})}catch(e){return o(e)}}))}function versionChangeRoutes(e){e.post("/version_change/:newVersion",(async(e,t,o)=>{try{log(4,"[version] Changing Highcharts version.");const o=envs.HIGHCHARTS_ADMIN_TOKEN;if(!o||!o.length)throw new ExportError("[version] The server is not configured to perform run-time version changes: `HIGHCHARTS_ADMIN_TOKEN` is not set.",401);const r=e.get("hc-auth");if(!r||r!==o)throw new ExportError("[version] Invalid or missing token: Set the token in the hc-auth header.",401);const n=e.params.newVersion;if(!n)throw new ExportError("[version] No new version supplied.",400);try{await updateHcVersion(n)}catch(e){throw new ExportError(`[version] Version change: ${e.message}`,400).setError(e)}t.status(200).send({statusCode:200,highchartsVersion:getHcVersion(),message:`Successfully updated Highcharts to version: ${n}.`})}catch(e){return o(e)}}))}const activeServers=new Map,app=express();async function startServer(e={}){try{const t=updateOptions({server:e});if(!(e=t.server).enable||!app)throw new ExportError("[server] Server cannot be started (not enabled or no correct Express app found).",500);const o=1024*e.uploadLimit*1024,r=multer.memoryStorage(),n=multer({storage:r,limits:{fieldSize:o}});if(app.disable("x-powered-by"),app.use(cors({methods:["POST","GET","OPTIONS"]})),app.use(((e,t,o)=>{t.set("Accept-Ranges","none"),o()})),app.use(express.json({limit:o})),app.use(express.urlencoded({extended:!0,limit:o})),app.use(n.none()),app.use(express.static(path.join(__dirname$1,"public"))),!e.ssl.force){const t=http.createServer(app);_attachServerErrorHandlers(t),t.listen(e.port,e.host,(()=>{activeServers.set(e.port,t),log(3,`[server] Started HTTP server on ${e.host}:${e.port}.`)}))}if(e.ssl.enable){let t,o;try{t=fs.readFileSync(path.join(getAbsolutePath(e.ssl.certPath),"server.key"),"utf8"),o=fs.readFileSync(path.join(getAbsolutePath(e.ssl.certPath),"server.crt"),"utf8")}catch(t){log(2,`[server] Unable to load key/certificate from the '${e.ssl.certPath}' path. Could not run secured layer server.`)}if(t&&o){const r=https.createServer({key:t,cert:o},app);_attachServerErrorHandlers(r),r.listen(e.ssl.port,e.host,(()=>{activeServers.set(e.ssl.port,r),log(3,`[server] Started HTTPS server on ${e.host}:${e.ssl.port}.`)}))}}rateLimitingMiddleware(app,e.rateLimiting),validationMiddleware(app),exportRoutes(app),healthRoutes(app),uiRoutes(app),versionChangeRoutes(app),errorMiddleware(app)}catch(e){throw new ExportError("[server] Could not configure and start the server.",500).setError(e)}}function closeServers(){if(activeServers.size>0){log(4,"[server] Closing all servers.");for(const[e,t]of activeServers)t.close((()=>{activeServers.delete(e),log(4,`[server] Closed server on port: ${e}.`)}))}}function getServers(){return activeServers}function getExpress(){return express}function getApp(){return app}function enableRateLimiting(e){const t=updateOptions({server:{rateLimiting:e}});rateLimitingMiddleware(app,t.server.rateLimitingOptions)}function use(e,...t){app.use(e,...t)}function get(e,...t){app.get(e,...t)}function post(e,...t){app.post(e,...t)}function _attachServerErrorHandlers(e){e.on("clientError",((e,t)=>{logWithStack(1,e,`[server] Client error: ${e.message}, destroying socket.`),t.destroy()})),e.on("error",(e=>{logWithStack(1,e,`[server] Server error: ${e.message}`)})),e.on("connection",(e=>{e.on("error",(e=>{logWithStack(1,e,`[server] Socket error: ${e.message}`)}))}))}var server={startServer:startServer,closeServers:closeServers,getServers:getServers,getExpress:getExpress,getApp:getApp,enableRateLimiting:enableRateLimiting,use:use,get:get,post:post};async function shutdownCleanUp(e=0){await Promise.allSettled([clearAllTimers(),closeServers(),killPool()]),process.exit(e)}async function initExport(e={}){const t=updateOptions(e);setAllowCodeExecution(t.customLogic.allowCodeExecution),initLogging(t.logging),t.other.listenToProcessExits&&_attachProcessExitListeners(),await checkCache(t.highcharts,t.server.proxy),await initPool(t.pool,t.puppeteer.args)}function _attachProcessExitListeners(){log(3,"[process] Attaching exit listeners to the process."),process.on("exit",(e=>{log(4,`[process] Process exited with code: ${e}.`)})),process.on("SIGINT",(async(e,t)=>{log(4,`[process] The ${e} event with code: ${t}.`),await shutdownCleanUp()})),process.on("SIGTERM",(async(e,t)=>{log(4,`[process] The ${e} event with code: ${t}.`),await shutdownCleanUp()})),process.on("SIGHUP",(async(e,t)=>{log(4,`[process] The ${e} event with code: ${t}.`),await shutdownCleanUp()})),process.on("uncaughtException",(async(e,t)=>{logWithStack(1,e,`[process] The ${t} error.`),await shutdownCleanUp(1)}))}var index={...server,getOptions:getOptions,updateOptions:updateOptions,mapToNewOptions:mapToNewOptions,validateOption:validateOption,validateOptions:validateOptions,initExport:initExport,singleExport:singleExport,batchExport:batchExport,startExport:startExport,killPool:killPool,shutdownCleanUp:shutdownCleanUp,log:log,logWithStack:logWithStack,logZodIssues:logZodIssues,setLogLevel:function(e){setLogLevel(updateOptions({logging:{level:e}}).logging.level)},enableConsoleLogging:function(e){enableConsoleLogging(updateOptions({logging:{toConsole:e}}).logging.toConsole)},enableFileLogging:function(e,t,o){const r=updateOptions({logging:{dest:e,file:t,toFile:o}});enableFileLogging(r.logging.dest,r.logging.file,r.logging.toFile)}};exports.default=index,exports.initExport=initExport; +//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguY2pzIiwic291cmNlcyI6WyIuLi9saWIvdXRpbHMuanMiLCIuLi9saWIvbG9nZ2VyLmpzIiwiLi4vbGliL3NjaGVtYXMvY29uZmlnLmpzIiwiLi4vbGliL3ZhbGlkYXRpb24uanMiLCIuLi9saWIvZXJyb3JzL0V4cG9ydEVycm9yLmpzIiwiLi4vbGliL2NvbmZpZy5qcyIsIi4uL2xpYi9mZXRjaC5qcyIsIi4uL2xpYi9jYWNoZS5qcyIsIi4uL2xpYi9oaWdoY2hhcnRzLmpzIiwiLi4vbGliL2Jyb3dzZXIuanMiLCIuLi90ZW1wbGF0ZXMvc3ZnRXhwb3J0L2Nzcy5qcyIsIi4uL3RlbXBsYXRlcy9zdmdFeHBvcnQvc3ZnRXhwb3J0LmpzIiwiLi4vbGliL2V4cG9ydC5qcyIsIi4uL2xpYi9wb29sLmpzIiwiLi4vbGliL3Nhbml0aXplLmpzIiwiLi4vbGliL2NoYXJ0LmpzIiwiLi4vbGliL3RpbWVyLmpzIiwiLi4vbGliL3NlcnZlci9taWRkbGV3YXJlcy9lcnJvci5qcyIsIi4uL2xpYi9zZXJ2ZXIvbWlkZGxld2FyZXMvcmF0ZUxpbWl0aW5nLmpzIiwiLi4vbGliL3NlcnZlci9taWRkbGV3YXJlcy92YWxpZGF0aW9uLmpzIiwiLi4vbGliL3NlcnZlci9yb3V0ZXMvZXhwb3J0LmpzIiwiLi4vbGliL3NlcnZlci9yb3V0ZXMvaGVhbHRoLmpzIiwiLi4vbGliL3NlcnZlci9yb3V0ZXMvdWkuanMiLCIuLi9saWIvc2VydmVyL3JvdXRlcy92ZXJzaW9uQ2hhbmdlLmpzIiwiLi4vbGliL3NlcnZlci9zZXJ2ZXIuanMiLCIuLi9saWIvcmVzb3VyY2VSZWxlYXNlLmpzIiwiLi4vbGliL2luZGV4LmpzIl0sInNvdXJjZXNDb250ZW50IjpbIi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXHJcblxyXG5IaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXJcclxuXHJcbkNvcHlyaWdodCAoYykgMjAxNi0yMDI1LCBIaWdoc29mdFxyXG5cclxuTGljZW5jZWQgdW5kZXIgdGhlIE1JVCBsaWNlbmNlLlxyXG5cclxuQWRkaXRpb25hbGx5IGEgdmFsaWQgSGlnaGNoYXJ0cyBsaWNlbnNlIGlzIHJlcXVpcmVkIGZvciB1c2UuXHJcblxyXG5TZWUgTElDRU5TRSBmaWxlIGluIHJvb3QgZm9yIGRldGFpbHMuXHJcblxyXG4qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xyXG5cclxuLyoqXHJcbiAqIEBvdmVydmlldyBUaGUgSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyIHV0aWxpdHkgbW9kdWxlIHByb3ZpZGVzXHJcbiAqIGEgY29tcHJlaGVuc2l2ZSBzZXQgb2YgaGVscGVyIGZ1bmN0aW9ucyBhbmQgY29uc3RhbnRzIGRlc2lnbmVkIHRvIHN0cmVhbWxpbmVcclxuICogYW5kIGVuaGFuY2UgdmFyaW91cyBvcGVyYXRpb25zIHJlcXVpcmVkIGZvciBIaWdoY2hhcnRzIGV4cG9ydCB0YXNrcy5cclxuICovXHJcblxyXG5pbXBvcnQgeyBpc0Fic29sdXRlLCBub3JtYWxpemUsIHJlc29sdmUgfSBmcm9tICdwYXRoJztcclxuaW1wb3J0IHsgZmlsZVVSTFRvUGF0aCB9IGZyb20gJ3VybCc7XHJcblxyXG5jb25zdCBNQVhfQkFDS09GRl9BVFRFTVBUUyA9IDY7XHJcblxyXG4vLyBUaGUgZGlyZWN0b3J5IHBhdGhcclxuZXhwb3J0IGNvbnN0IF9fZGlybmFtZSA9IGZpbGVVUkxUb1BhdGgobmV3IFVSTCgnLi4vLicsIGltcG9ydC5tZXRhLnVybCkpO1xyXG5cclxuLyoqXHJcbiAqIENsZWFycyBhbmQgc3RhbmRhcmRpemVzIHRleHQgYnkgcmVwbGFjaW5nIG11bHRpcGxlIGNvbnNlY3V0aXZlIHdoaXRlc3BhY2VcclxuICogY2hhcmFjdGVycyB3aXRoIGEgc2luZ2xlIHNwYWNlIGFuZCB0cmltbWluZyBhbnkgbGVhZGluZyBvciB0cmFpbGluZ1xyXG4gKiB3aGl0ZXNwYWNlLlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gY2xlYXJUZXh0XHJcbiAqXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSB0ZXh0IC0gVGhlIGlucHV0IHRleHQgdG8gYmUgY2xlYXJlZC5cclxuICogQHBhcmFtIHtSZWdFeHB9IFtydWxlPS9cXHNcXHMrL2ddIC0gVGhlIHJlZ3VsYXIgZXhwcmVzc2lvbiBydWxlIHRvIG1hdGNoXHJcbiAqIG11bHRpcGxlIGNvbnNlY3V0aXZlIHdoaXRlc3BhY2UgY2hhcmFjdGVycy4gVGhlIGRlZmF1bHQgdmFsdWVcclxuICogaXMgdGhlICcvXFxzXFxzKy9nJyBSZWdFeHAuXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSBbcmVwbGFjZXI9JyAnXSAtIFRoZSBzdHJpbmcgdXNlZCB0byByZXBsYWNlIG11bHRpcGxlXHJcbiAqIGNvbnNlY3V0aXZlIHdoaXRlc3BhY2UgY2hhcmFjdGVycy4gVGhlIGRlZmF1bHQgdmFsdWUgaXMgdGhlICcgJyBzdHJpbmcuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtzdHJpbmd9IFRoZSBjbGVhcmVkIGFuZCBzdGFuZGFyZGl6ZWQgdGV4dC5cclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiBjbGVhclRleHQodGV4dCwgcnVsZSA9IC9cXHNcXHMrL2csIHJlcGxhY2VyID0gJyAnKSB7XHJcbiAgcmV0dXJuIHRleHQucmVwbGFjZUFsbChydWxlLCByZXBsYWNlcikudHJpbSgpO1xyXG59XHJcblxyXG4vKipcclxuICogQ3JlYXRlcyBhIGRlZXAgY29weSBvZiB0aGUgZ2l2ZW4gb2JqZWN0IG9yIGFycmF5LlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gZGVlcENvcHlcclxuICpcclxuICogQHBhcmFtIHsoT2JqZWN0fEFycmF5KX0gb2JqQXJyIC0gVGhlIG9iamVjdCBvciBhcnJheSB0byBiZSBkZWVwbHkgY29waWVkLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7KE9iamVjdHxBcnJheSl9IFRoZSBkZWVwIGNvcHkgb2YgdGhlIHByb3ZpZGVkIG9iamVjdCBvciBhcnJheS5cclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiBkZWVwQ29weShvYmpBcnIpIHtcclxuICAvLyBJZiB0aGUgYG9iakFycmAgaXMgbnVsbCBvciBub3Qgb2YgdGhlIGBvYmplY3RgIHR5cGUsIHJldHVybiBpdFxyXG4gIGlmIChvYmpBcnIgPT09IG51bGwgfHwgdHlwZW9mIG9iakFyciAhPT0gJ29iamVjdCcpIHtcclxuICAgIHJldHVybiBvYmpBcnI7XHJcbiAgfVxyXG5cclxuICAvLyBQcmVwYXJlIGVpdGhlciBhIG5ldyBhcnJheSBvciBhIG5ldyBvYmplY3RcclxuICBjb25zdCBvYmpBcnJDb3B5ID0gQXJyYXkuaXNBcnJheShvYmpBcnIpID8gW10gOiB7fTtcclxuXHJcbiAgLy8gUmVjdXJzaXZlbHkgY29weSBlYWNoIHByb3BlcnR5XHJcbiAgZm9yIChjb25zdCBrZXkgaW4gb2JqQXJyKSB7XHJcbiAgICBpZiAoT2JqZWN0LnByb3RvdHlwZS5oYXNPd25Qcm9wZXJ0eS5jYWxsKG9iakFyciwga2V5KSkge1xyXG4gICAgICBvYmpBcnJDb3B5W2tleV0gPSBkZWVwQ29weShvYmpBcnJba2V5XSk7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICAvLyBSZXR1cm4gdGhlIGNvcGllZCBvYmplY3RcclxuICByZXR1cm4gb2JqQXJyQ29weTtcclxufVxyXG5cclxuLyoqXHJcbiAqIEltcGxlbWVudHMgYW4gZXhwb25lbnRpYWwgYmFja29mZiBzdHJhdGVneSBmb3IgcmV0cnlpbmcgYSBmdW5jdGlvbiB1bnRpbFxyXG4gKiBhIGNlcnRhaW4gbnVtYmVyIG9mIGF0dGVtcHRzIGFyZSByZWFjaGVkLlxyXG4gKlxyXG4gKiBAYXN5bmNcclxuICogQGZ1bmN0aW9uIGV4cEJhY2tvZmZcclxuICpcclxuICogQHBhcmFtIHtGdW5jdGlvbn0gZm4gLSBUaGUgZnVuY3Rpb24gdG8gYmUgcmV0cmllZC5cclxuICogQHBhcmFtIHtudW1iZXJ9IFthdHRlbXB0PTBdIC0gVGhlIGN1cnJlbnQgYXR0ZW1wdCBudW1iZXIuIFRoZSBkZWZhdWx0IHZhbHVlXHJcbiAqIGlzIGAwYC5cclxuICogQHBhcmFtIHsuLi51bmtub3dufSBhcmdzIC0gQXJndW1lbnRzIHRvIGJlIHBhc3NlZCB0byB0aGUgZnVuY3Rpb24uXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtQcm9taXNlPHVua25vd24+fSBBIFByb21pc2UgdGhhdCByZXNvbHZlcyB0byB0aGUgcmVzdWx0XHJcbiAqIG9mIHRoZSBmdW5jdGlvbiBpZiBzdWNjZXNzZnVsLlxyXG4gKlxyXG4gKiBAdGhyb3dzIHtFcnJvcn0gVGhyb3dzIGFuIGBFcnJvcmAgaWYgdGhlIG1heGltdW0gbnVtYmVyIG9mIGF0dGVtcHRzXHJcbiAqIGlzIHJlYWNoZWQuXHJcbiAqL1xyXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gZXhwQmFja29mZihmbiwgYXR0ZW1wdCA9IDAsIC4uLmFyZ3MpIHtcclxuICB0cnkge1xyXG4gICAgLy8gVHJ5IHRvIGNhbGwgdGhlIGZ1bmN0aW9uXHJcbiAgICByZXR1cm4gYXdhaXQgZm4oLi4uYXJncyk7XHJcbiAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgIC8vIENhbGN1bGF0ZSBkZWxheSBpbiBtc1xyXG4gICAgY29uc3QgZGVsYXlJbk1zID0gMiAqKiBhdHRlbXB0ICogMTAwMDtcclxuXHJcbiAgICAvLyBJZiB0aGUgYXR0ZW1wdCBleGNlZWRzIHRoZSBtYXhpbXVtIGF0dGVtcHRzIG9mIHJlcGVhdCwgdGhyb3cgYW4gZXJyb3JcclxuICAgIGlmICgrK2F0dGVtcHQgPj0gTUFYX0JBQ0tPRkZfQVRURU1QVFMpIHtcclxuICAgICAgdGhyb3cgZXJyb3I7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gV2FpdCBnaXZlbiBhbW91bnQgb2YgdGltZVxyXG4gICAgYXdhaXQgbmV3IFByb21pc2UoKHJlc3BvbnNlKSA9PiBzZXRUaW1lb3V0KHJlc3BvbnNlLCBkZWxheUluTXMpKTtcclxuXHJcbiAgICAvLy8gVE8gRE86IENvcnJlY3RcclxuICAgIC8vIC8vIEluZm9ybWF0aW9uIGFib3V0IHRoZSByZXNvdXJjZSB0aW1lb3V0XHJcbiAgICAvLyBsb2coXHJcbiAgICAvLyAgIDMsXHJcbiAgICAvLyAgIGBbdXRpbHNdIFdhaXRlZCAke2RlbGF5SW5Nc31tcyB1bnRpbCBuZXh0IGNhbGwgZm9yIHRoZSByZXNvdXJjZSBvZiBJRDogJHthcmdzWzBdfS5gXHJcbiAgICAvLyApO1xyXG5cclxuICAgIC8vIFRyeSBhZ2FpblxyXG4gICAgcmV0dXJuIGV4cEJhY2tvZmYoZm4sIGF0dGVtcHQsIC4uLmFyZ3MpO1xyXG4gIH1cclxufVxyXG5cclxuLyoqXHJcbiAqIENoZWNrcyBpZiB0aGUgZ2l2ZW4gcGF0aCBpcyByZWxhdGl2ZSBvciBhYnNvbHV0ZSBhbmQgcmV0dXJucyB0aGUgY29ycmVjdGVkLFxyXG4gKiBhYnNvbHV0ZSBwYXRoLlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gZ2V0QWJzb2x1dGVQYXRoXHJcbiAqXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSBwYXRoIC0gVGhlIHBhdGggdG8gYmUgY2hlY2tlZCBvbi5cclxuICpcclxuICogQHJldHVybnMge3N0cmluZ30gVGhlIGFic29sdXRlIHBhdGguXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gZ2V0QWJzb2x1dGVQYXRoKHBhdGgpIHtcclxuICByZXR1cm4gaXNBYnNvbHV0ZShwYXRoKSA/IG5vcm1hbGl6ZShwYXRoKSA6IHJlc29sdmUocGF0aCk7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBDb252ZXJ0cyBpbnB1dCBkYXRhIHRvIGEgQmFzZTY0IHN0cmluZyBiYXNlZCBvbiB0aGUgZXhwb3J0IHR5cGUuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBnZXRCYXNlNjRcclxuICpcclxuICogQHBhcmFtIHtzdHJpbmd9IGlucHV0IC0gVGhlIGlucHV0IHRvIGJlIHRyYW5zZm9ybWVkIHRvIEJhc2U2NCBmb3JtYXQuXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSB0eXBlIC0gVGhlIG9yaWdpbmFsIGV4cG9ydCB0eXBlLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7c3RyaW5nfSBUaGUgQmFzZTY0IHN0cmluZyByZXByZXNlbnRhdGlvbiBvZiB0aGUgaW5wdXQuXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gZ2V0QmFzZTY0KGlucHV0LCB0eXBlKSB7XHJcbiAgLy8gRm9yIHBkZiBhbmQgc3ZnIHR5cGVzIHRoZSBpbnB1dCBtdXN0IGJlIHRyYW5zZm9ybWVkIHRvIEJhc2U2NCBmcm9tIGEgYnVmZmVyXHJcbiAgaWYgKHR5cGUgPT09ICdwZGYnIHx8IHR5cGUgPT0gJ3N2ZycpIHtcclxuICAgIHJldHVybiBCdWZmZXIuZnJvbShpbnB1dCwgJ3V0ZjgnKS50b1N0cmluZygnYmFzZTY0Jyk7XHJcbiAgfVxyXG5cclxuICAvLyBGb3IgcG5nIGFuZCBqcGVnIGlucHV0IGlzIGFscmVhZHkgYSBCYXNlNjQgc3RyaW5nXHJcbiAgcmV0dXJuIGlucHV0O1xyXG59XHJcblxyXG4vKipcclxuICogUmV0dXJucyBzdHJpbmdpZmllZCBkYXRlIHdpdGhvdXQgdGhlIEdNVCB0ZXh0IGluZm9ybWF0aW9uLlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gZ2V0TmV3RGF0ZVxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIGdldE5ld0RhdGUoKSB7XHJcbiAgLy8gR2V0IHJpZCBvZiB0aGUgR01UIHRleHQgaW5mb3JtYXRpb25cclxuICByZXR1cm4gbmV3IERhdGUoKS50b1N0cmluZygpLnNwbGl0KCcoJylbMF0udHJpbSgpO1xyXG59XHJcblxyXG4vKipcclxuICogUmV0dXJucyB0aGUgc3RvcmVkIHRpbWUgdmFsdWUgaW4gbWlsbGlzZWNvbmRzLlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gZ2V0TmV3RGF0ZVRpbWVcclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiBnZXROZXdEYXRlVGltZSgpIHtcclxuICByZXR1cm4gbmV3IERhdGUoKS5nZXRUaW1lKCk7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBDaGVja3MgaWYgdGhlIGdpdmVuIGl0ZW0gaXMgYW4gb2JqZWN0LlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gaXNPYmplY3RcclxuICpcclxuICogQHBhcmFtIHt1bmtub3dufSBpdGVtIC0gVGhlIGl0ZW0gdG8gYmUgY2hlY2tlZC5cclxuICpcclxuICogQHJldHVybnMge2Jvb2xlYW59IFJldHVybnMgYHRydWVgIGlmIHRoZSBpdGVtIGlzIGFuIG9iamVjdCwgYGZhbHNlYFxyXG4gKiBvdGhlcndpc2UuXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gaXNPYmplY3QoaXRlbSkge1xyXG4gIHJldHVybiBPYmplY3QucHJvdG90eXBlLnRvU3RyaW5nLmNhbGwoaXRlbSkgPT09ICdbb2JqZWN0IE9iamVjdF0nO1xyXG59XHJcblxyXG4vKipcclxuICogQ2hlY2tzIGlmIHRoZSBnaXZlbiBvYmplY3QgaXMgZW1wdHkuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBpc09iamVjdEVtcHR5XHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBpdGVtIC0gVGhlIG9iamVjdCB0byBiZSBjaGVja2VkLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7Ym9vbGVhbn0gUmV0dXJucyBgdHJ1ZWAgaWYgdGhlIGl0ZW0gaXMgYW4gZW1wdHkgb2JqZWN0LCBgZmFsc2VgXHJcbiAqIG90aGVyd2lzZS5cclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiBpc09iamVjdEVtcHR5KGl0ZW0pIHtcclxuICByZXR1cm4gKFxyXG4gICAgdHlwZW9mIGl0ZW0gPT09ICdvYmplY3QnICYmXHJcbiAgICAhQXJyYXkuaXNBcnJheShpdGVtKSAmJlxyXG4gICAgaXRlbSAhPT0gbnVsbCAmJlxyXG4gICAgT2JqZWN0LmtleXMoaXRlbSkubGVuZ3RoID09PSAwXHJcbiAgKTtcclxufVxyXG5cclxuLyoqXHJcbiAqIENoZWNrcyBpZiBhIHByaXZhdGUgSVAgcmFuZ2UgVVJMIGlzIGZvdW5kIGluIHRoZSBnaXZlbiBzdHJpbmcuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBpc1ByaXZhdGVSYW5nZVVybEZvdW5kXHJcbiAqXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSBpdGVtIC0gVGhlIHN0cmluZyB0byBiZSBjaGVja2VkIGZvciBhIHByaXZhdGUgSVAgcmFuZ2UgVVJMLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7Ym9vbGVhbn0gUmV0dXJucyBgdHJ1ZWAgaWYgYSBwcml2YXRlIElQIHJhbmdlIFVSTCBpcyBmb3VuZCwgYGZhbHNlYFxyXG4gKiBvdGhlcndpc2UuXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gaXNQcml2YXRlUmFuZ2VVcmxGb3VuZChpdGVtKSB7XHJcbiAgY29uc3QgcmVnZXhQYXR0ZXJucyA9IFtcclxuICAgIC94bGluazpocmVmPVwiKD86aHR0cDpcXC9cXC98aHR0cHM6XFwvXFwvKT9sb2NhbGhvc3RcXGIvLFxyXG4gICAgL3hsaW5rOmhyZWY9XCIoPzpodHRwOlxcL1xcL3xodHRwczpcXC9cXC8pPzEwXFwuXFxkezEsM31cXC5cXGR7MSwzfVxcLlxcZHsxLDN9XFxiLyxcclxuICAgIC94bGluazpocmVmPVwiKD86aHR0cDpcXC9cXC98aHR0cHM6XFwvXFwvKT8xMjdcXC5cXGR7MSwzfVxcLlxcZHsxLDN9XFwuXFxkezEsM31cXGIvLFxyXG4gICAgL3hsaW5rOmhyZWY9XCIoPzpodHRwOlxcL1xcL3xodHRwczpcXC9cXC8pPzE3MlxcLigxWzYtOV18MlswLTldfDNbMC0xXSlcXC5cXGR7MSwzfVxcLlxcZHsxLDN9XFxiLyxcclxuICAgIC94bGluazpocmVmPVwiKD86aHR0cDpcXC9cXC98aHR0cHM6XFwvXFwvKT8xOTJcXC4xNjhcXC5cXGR7MSwzfVxcLlxcZHsxLDN9XFxiL1xyXG4gIF07XHJcblxyXG4gIHJldHVybiByZWdleFBhdHRlcm5zLnNvbWUoKHBhdHRlcm4pID0+IHBhdHRlcm4udGVzdChpdGVtKSk7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBVdGlsaXR5IHRvIG1lYXN1cmUgZWxhcHNlZCB0aW1lIHVzaW5nIHRoZSBOb2RlLmpzIGBwcm9jZXNzLmhydGltZSgpYCBtZXRob2QuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBtZWFzdXJlVGltZVxyXG4gKlxyXG4gKiBAcmV0dXJucyB7RnVuY3Rpb259IEEgZnVuY3Rpb24gdG8gY2FsY3VsYXRlIHRoZSBlbGFwc2VkIHRpbWUgaW4gbWlsbGlzZWNvbmRzLlxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIG1lYXN1cmVUaW1lKCkge1xyXG4gIGNvbnN0IHN0YXJ0ID0gcHJvY2Vzcy5ocnRpbWUuYmlnaW50KCk7XHJcbiAgcmV0dXJuICgpID0+IE51bWJlcihwcm9jZXNzLmhydGltZS5iaWdpbnQoKSAtIHN0YXJ0KSAvIDEwMDAwMDA7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBSb3VuZHMgYSBudW1iZXIgdG8gdGhlIHNwZWNpZmllZCBwcmVjaXNpb24uXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiByb3VuZE51bWJlclxyXG4gKlxyXG4gKiBAcGFyYW0ge251bWJlcn0gdmFsdWUgLSBUaGUgbnVtYmVyIHRvIGJlIHJvdW5kZWQuXHJcbiAqIEBwYXJhbSB7bnVtYmVyfSBwcmVjaXNpb24gLSBUaGUgbnVtYmVyIG9mIGRlY2ltYWwgcGxhY2VzIHRvIHJvdW5kIHRvLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7bnVtYmVyfSBUaGUgcm91bmRlZCBudW1iZXIuXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gcm91bmROdW1iZXIodmFsdWUsIHByZWNpc2lvbiA9IDEpIHtcclxuICBjb25zdCBtdWx0aXBsaWVyID0gTWF0aC5wb3coMTAsIHByZWNpc2lvbiB8fCAwKTtcclxuICByZXR1cm4gTWF0aC5yb3VuZCgrdmFsdWUgKiBtdWx0aXBsaWVyKSAvIG11bHRpcGxpZXI7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBDb252ZXJ0cyBhIHZhbHVlIHRvIGEgYm9vbGVhbi5cclxuICpcclxuICogQGZ1bmN0aW9uIHRvQm9vbGVhblxyXG4gKlxyXG4gKiBAcGFyYW0ge3Vua25vd259IGl0ZW0gLSBUaGUgdmFsdWUgdG8gYmUgY29udmVydGVkIHRvIGEgYm9vbGVhbi5cclxuICpcclxuICogQHJldHVybnMge2Jvb2xlYW59IFRoZSBib29sZWFuIHJlcHJlc2VudGF0aW9uIG9mIHRoZSBpbnB1dCB2YWx1ZS5cclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiB0b0Jvb2xlYW4oaXRlbSkge1xyXG4gIHJldHVybiBbJ2ZhbHNlJywgJ3VuZGVmaW5lZCcsICdudWxsJywgJ05hTicsICcwJywgJyddLmluY2x1ZGVzKGl0ZW0pXHJcbiAgICA/IGZhbHNlXHJcbiAgICA6ICEhaXRlbTtcclxufVxyXG5cclxuZXhwb3J0IGRlZmF1bHQge1xyXG4gIF9fZGlybmFtZSxcclxuICBjbGVhclRleHQsXHJcbiAgZGVlcENvcHksXHJcbiAgZXhwQmFja29mZixcclxuICBnZXRBYnNvbHV0ZVBhdGgsXHJcbiAgZ2V0QmFzZTY0LFxyXG4gIGdldE5ld0RhdGUsXHJcbiAgZ2V0TmV3RGF0ZVRpbWUsXHJcbiAgaXNPYmplY3QsXHJcbiAgaXNPYmplY3RFbXB0eSxcclxuICBpc1ByaXZhdGVSYW5nZVVybEZvdW5kLFxyXG4gIG1lYXN1cmVUaW1lLFxyXG4gIHJvdW5kTnVtYmVyLFxyXG4gIHRvQm9vbGVhblxyXG59O1xyXG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxyXG5cclxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXHJcblxyXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNSwgSGlnaHNvZnRcclxuXHJcbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cclxuXHJcbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxyXG5cclxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxyXG5cclxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cclxuXHJcbi8qKlxyXG4gKiBAb3ZlcnZpZXcgQSBtb2R1bGUgZm9yIG1hbmFnaW5nIGxvZ2dpbmcgZnVuY3Rpb25hbGl0eSB3aXRoIGN1c3RvbWl6YWJsZVxyXG4gKiBsb2cgbGV2ZWxzLCBjb25zb2xlIGFuZCBmaWxlIGxvZ2dpbmcgb3B0aW9ucywgYW5kIGVycm9yIGhhbmRsaW5nIHN1cHBvcnQuXHJcbiAqIFRoZSBtb2R1bGUgYWxzbyBlbnN1cmVzIHRoYXQgZmlsZS1iYXNlZCBsb2dzIGFyZSBzdG9yZWQgaW4gYSBzdHJ1Y3R1cmVkXHJcbiAqIGRpcmVjdG9yeSwgY3JlYXRpbmcgdGhlIG5lY2Vzc2FyeSBwYXRocyBhdXRvbWF0aWNhbGx5IGlmIHRoZXkgZG8gbm90IGV4aXN0LlxyXG4gKi9cclxuXHJcbmltcG9ydCB7IGFwcGVuZEZpbGUsIGV4aXN0c1N5bmMsIG1rZGlyU3luYyB9IGZyb20gJ2ZzJztcclxuaW1wb3J0IHsgam9pbiB9IGZyb20gJ3BhdGgnO1xyXG5cclxuaW1wb3J0IHsgZ2V0QWJzb2x1dGVQYXRoLCBnZXROZXdEYXRlIH0gZnJvbSAnLi91dGlscy5qcyc7XHJcblxyXG4vLyBUaGUgYXZhaWxhYmxlIGNvbG9yc1xyXG5jb25zdCBjb2xvcnMgPSBbJ3JlZCcsICd5ZWxsb3cnLCAnYmx1ZScsICdncmF5JywgJ2dyZWVuJ107XHJcblxyXG4vLyBUaGUgZGVmYXVsdCBsb2dnaW5nIGNvbmZpZ1xyXG5jb25zdCBsb2dnaW5nID0ge1xyXG4gIC8vIEZsYWdzIGZvciBsb2dnaW5nIHN0YXR1c1xyXG4gIHRvQ29uc29sZTogdHJ1ZSxcclxuICB0b0ZpbGU6IGZhbHNlLFxyXG4gIHBhdGhDcmVhdGVkOiBmYWxzZSxcclxuICAvLyBGdWxsIHBhdGggdG8gdGhlIGxvZyBmaWxlXHJcbiAgcGF0aFRvTG9nOiAnJyxcclxuICAvLyBMb2cgbGV2ZWxzXHJcbiAgbGV2ZWxzRGVzYzogW1xyXG4gICAge1xyXG4gICAgICB0aXRsZTogJ2Vycm9yJyxcclxuICAgICAgY29sb3I6IGNvbG9yc1swXVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdGl0bGU6ICd3YXJuaW5nJyxcclxuICAgICAgY29sb3I6IGNvbG9yc1sxXVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdGl0bGU6ICdub3RpY2UnLFxyXG4gICAgICBjb2xvcjogY29sb3JzWzJdXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0aXRsZTogJ3ZlcmJvc2UnLFxyXG4gICAgICBjb2xvcjogY29sb3JzWzNdXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0aXRsZTogJ2JlbmNobWFyaycsXHJcbiAgICAgIGNvbG9yOiBjb2xvcnNbNF1cclxuICAgIH1cclxuICBdXHJcbn07XHJcblxyXG4vKipcclxuICogTG9ncyBhIG1lc3NhZ2Ugd2l0aCBhIHNwZWNpZmllZCBsb2cgbGV2ZWwuIEFjY2VwdHMgYSB2YXJpYWJsZSBudW1iZXJcclxuICogb2YgYXJndW1lbnRzLiBUaGUgYXJndW1lbnRzIGFmdGVyIHRoZSBgbGV2ZWxgIGFyZSBwYXNzZWQgdG8gYGNvbnNvbGUubG9nYFxyXG4gKiBhbmQvb3IgdXNlZCB0byBjb25zdHJ1Y3QgYW5kIGFwcGVuZCBtZXNzYWdlcyB0byBhIGxvZyBmaWxlLlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gbG9nXHJcbiAqXHJcbiAqIEBwYXJhbSB7Li4udW5rbm93bn0gYXJncyAtIEFuIGFycmF5IG9mIGFyZ3VtZW50cyB3aGVyZSB0aGUgZmlyc3QgaXMgdGhlIGxvZ1xyXG4gKiBsZXZlbCBhbmQgdGhlIHJlbWFpbmluZyBhcmUgc3RyaW5ncyB1c2VkIHRvIGJ1aWxkIHRoZSBsb2cgbWVzc2FnZS5cclxuICpcclxuICogQHJldHVybnMge3ZvaWR9IEV4aXRzIHRoZSBmdW5jdGlvbiBleGVjdXRpb24gaWYgYXR0ZW1wdGluZyB0byBsb2cgYXQgYSBsZXZlbFxyXG4gKiBoaWdoZXIgdGhhbiBhbGxvd2VkLlxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIGxvZyguLi5hcmdzKSB7XHJcbiAgY29uc3QgW25ld0xldmVsLCAuLi50ZXh0c10gPSBhcmdzO1xyXG5cclxuICAvLyBDdXJyZW50IGxvZ2dpbmcgb3B0aW9uc1xyXG4gIGNvbnN0IHsgbGV2ZWxzRGVzYywgbGV2ZWwgfSA9IGxvZ2dpbmc7XHJcblxyXG4gIC8vIENoZWNrIGlmIHRoZSBsb2cgbGV2ZWwgaXMgd2l0aGluIGEgY29ycmVjdCByYW5nZSBvciBpcyBpdCBhIGJlbmNobWFyayBsb2dcclxuICBpZiAoXHJcbiAgICBuZXdMZXZlbCAhPT0gNSAmJlxyXG4gICAgKG5ld0xldmVsID09PSAwIHx8IG5ld0xldmVsID4gbGV2ZWwgfHwgbGV2ZWwgPiBsZXZlbHNEZXNjLmxlbmd0aClcclxuICApIHtcclxuICAgIHJldHVybjtcclxuICB9XHJcblxyXG4gIC8vIENyZWF0ZSBhIG1lc3NhZ2UncyBwcmVmaXhcclxuICBjb25zdCBwcmVmaXggPSBgJHtnZXROZXdEYXRlKCl9IFske2xldmVsc0Rlc2NbbmV3TGV2ZWwgLSAxXS50aXRsZX1dIC1gO1xyXG5cclxuICAvLyBMb2cgdG8gZmlsZVxyXG4gIGlmIChsb2dnaW5nLnRvRmlsZSkge1xyXG4gICAgX2xvZ1RvRmlsZSh0ZXh0cywgcHJlZml4KTtcclxuICB9XHJcblxyXG4gIC8vIExvZyB0byBjb25zb2xlXHJcbiAgaWYgKGxvZ2dpbmcudG9Db25zb2xlKSB7XHJcbiAgICBjb25zb2xlLmxvZy5hcHBseShcclxuICAgICAgdW5kZWZpbmVkLFxyXG4gICAgICBbcHJlZml4LnRvU3RyaW5nKClbbG9nZ2luZy5sZXZlbHNEZXNjW25ld0xldmVsIC0gMV0uY29sb3JdXS5jb25jYXQodGV4dHMpXHJcbiAgICApO1xyXG4gIH1cclxufVxyXG5cclxuLyoqXHJcbiAqIExvZ3MgYW4gZXJyb3IgbWVzc2FnZSBhbG9uZyB3aXRoIGl0cyBzdGFjayB0cmFjZS4gT3B0aW9uYWxseSwgYSBjdXN0b21cclxuICogbWVzc2FnZSBjYW4gYmUgcHJvdmlkZWQuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBsb2dXaXRoU3RhY2tcclxuICpcclxuICogQHBhcmFtIHtudW1iZXJ9IG5ld0xldmVsIC0gVGhlIGxvZyBsZXZlbC5cclxuICogQHBhcmFtIHtFcnJvcn0gZXJyb3IgLSBUaGUgZXJyb3Igb2JqZWN0IGNvbnRhaW5pbmcgdGhlIHN0YWNrIHRyYWNlLlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gY3VzdG9tTWVzc2FnZSAtIEFuIG9wdGlvbmFsIGN1c3RvbSBtZXNzYWdlIHRvIGJlIGluY2x1ZGVkXHJcbiAqIGluIHRoZSBsb2cgYWxvbmdzaWRlIHRoZSBlcnJvci5cclxuICpcclxuICogQHJldHVybnMge3ZvaWR9IEV4aXRzIHRoZSBmdW5jdGlvbiBleGVjdXRpb24gaWYgYXR0ZW1wdGluZyB0byBsb2cgYXQgYSBsZXZlbFxyXG4gKiBoaWdoZXIgdGhhbiBhbGxvd2VkLlxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIGxvZ1dpdGhTdGFjayhuZXdMZXZlbCwgZXJyb3IsIGN1c3RvbU1lc3NhZ2UpIHtcclxuICAvLyBHZXQgdGhlIG1haW4gbWVzc2FnZVxyXG4gIGNvbnN0IG1haW5NZXNzYWdlID0gY3VzdG9tTWVzc2FnZSB8fCAoZXJyb3IgJiYgZXJyb3IubWVzc2FnZSkgfHwgJyc7XHJcblxyXG4gIC8vIEN1cnJlbnQgbG9nZ2luZyBvcHRpb25zXHJcbiAgY29uc3QgeyBsZXZlbCwgbGV2ZWxzRGVzYyB9ID0gbG9nZ2luZztcclxuXHJcbiAgLy8gQ2hlY2sgaWYgdGhlIGxvZyBsZXZlbCBpcyB3aXRoaW4gYSBjb3JyZWN0IHJhbmdlXHJcbiAgaWYgKG5ld0xldmVsID09PSAwIHx8IG5ld0xldmVsID4gbGV2ZWwgfHwgbGV2ZWwgPiBsZXZlbHNEZXNjLmxlbmd0aCkge1xyXG4gICAgcmV0dXJuO1xyXG4gIH1cclxuXHJcbiAgLy8gQ3JlYXRlIGEgbWVzc2FnZSdzIHByZWZpeFxyXG4gIGNvbnN0IHByZWZpeCA9IGAke2dldE5ld0RhdGUoKX0gWyR7bGV2ZWxzRGVzY1tuZXdMZXZlbCAtIDFdLnRpdGxlfV0gLWA7XHJcblxyXG4gIC8vIEFkZCB0aGUgd2hvbGUgc3RhY2sgbWVzc2FnZVxyXG4gIGNvbnN0IHN0YWNrTWVzc2FnZSA9IGVycm9yICYmIGVycm9yLnN0YWNrO1xyXG5cclxuICAvLyBDb21iaW5lIGN1c3RvbSBtZXNzYWdlIG9yIGVycm9yIG1lc3NhZ2Ugd2l0aCBlcnJvciBzdGFjayBtZXNzYWdlLCBpZiBleGlzdHNcclxuICBjb25zdCB0ZXh0cyA9IFttYWluTWVzc2FnZV07XHJcbiAgaWYgKHN0YWNrTWVzc2FnZSkge1xyXG4gICAgdGV4dHMucHVzaCgnXFxuJywgc3RhY2tNZXNzYWdlKTtcclxuICB9XHJcblxyXG4gIC8vIExvZyB0byBmaWxlXHJcbiAgaWYgKGxvZ2dpbmcudG9GaWxlKSB7XHJcbiAgICBfbG9nVG9GaWxlKHRleHRzLCBwcmVmaXgpO1xyXG4gIH1cclxuXHJcbiAgLy8gTG9nIHRvIGNvbnNvbGVcclxuICBpZiAobG9nZ2luZy50b0NvbnNvbGUpIHtcclxuICAgIGNvbnNvbGUubG9nLmFwcGx5KFxyXG4gICAgICB1bmRlZmluZWQsXHJcbiAgICAgIFtwcmVmaXgudG9TdHJpbmcoKVtsb2dnaW5nLmxldmVsc0Rlc2NbbmV3TGV2ZWwgLSAxXS5jb2xvcl1dLmNvbmNhdChbXHJcbiAgICAgICAgdGV4dHMuc2hpZnQoKVtjb2xvcnNbbmV3TGV2ZWwgLSAxXV0sXHJcbiAgICAgICAgLi4udGV4dHNcclxuICAgICAgXSlcclxuICAgICk7XHJcbiAgfVxyXG59XHJcblxyXG4vKipcclxuICogTG9ncyBhbiBlcnJvciBtZXNzYWdlIHJlbGF0ZWQgdG8gWm9kIHZhbGlkYXRpb24gaXNzdWVzLiBPcHRpb25hbGx5LCBhIGN1c3RvbVxyXG4gKiBtZXNzYWdlIGNhbiBiZSBwcm92aWRlZC5cclxuICpcclxuICogQGZ1bmN0aW9uIGxvZ1pvZElzc3Vlc1xyXG4gKlxyXG4gKiBAcGFyYW0ge251bWJlcn0gbmV3TGV2ZWwgLSBUaGUgbG9nIGxldmVsLlxyXG4gKiBAcGFyYW0ge0Vycm9yW119IGlzc3VlcyAtIEFuIGFycmF5IG9mIFpvZCB2YWxpZGF0aW9uIGlzc3Vlcy5cclxuICogQHBhcmFtIHtzdHJpbmd9IGN1c3RvbU1lc3NhZ2UgLSBBbiBvcHRpb25hbCBjdXN0b20gbWVzc2FnZSB0byBiZSBpbmNsdWRlZFxyXG4gKiBpbiB0aGUgbG9nIGFsb25nc2lkZSB0aGUgZXJyb3IuXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gbG9nWm9kSXNzdWVzKG5ld0xldmVsLCBpc3N1ZXMsIGN1c3RvbU1lc3NhZ2UpIHtcclxuICBsb2dXaXRoU3RhY2soXHJcbiAgICBuZXdMZXZlbCxcclxuICAgIG51bGwsXHJcbiAgICBbXHJcbiAgICAgIGAke2N1c3RvbU1lc3NhZ2UgfHwgJ1t2YWxpZGF0aW9uXSBWYWxpZGF0aW9uIGVycm9yJ30gLSB0aGUgZm9sbG93aW5nIFpvZCBpc3N1ZXMgb2NjdXJlZDpgLFxyXG4gICAgICAuLi4oaXNzdWVzIHx8IFtdKS5tYXAoKGlzc3VlKSA9PiBgLSAke2lzc3VlLm1lc3NhZ2V9YClcclxuICAgIF0uam9pbignXFxuJylcclxuICApO1xyXG59XHJcblxyXG4vKipcclxuICogSW5pdGlhbGl6ZXMgbG9nZ2luZyB3aXRoIHRoZSBzcGVjaWZpZWQgbG9nZ2luZyBjb25maWd1cmF0aW9uLlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gaW5pdExvZ2dpbmdcclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IGxvZ2dpbmdPcHRpb25zIC0gVGhlIGNvbmZpZ3VyYXRpb24gb2JqZWN0IGNvbnRhaW5pbmdcclxuICogYGxvZ2dpbmdgIG9wdGlvbnMuXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gaW5pdExvZ2dpbmcobG9nZ2luZ09wdGlvbnMpIHtcclxuICAvLyBHZXQgb3B0aW9ucyBmcm9tIHRoZSBgbG9nZ2luZ09wdGlvbnNgIG9iamVjdFxyXG4gIGNvbnN0IHsgbGV2ZWwsIGRlc3QsIGZpbGUsIHRvQ29uc29sZSwgdG9GaWxlIH0gPSBsb2dnaW5nT3B0aW9ucztcclxuXHJcbiAgLy8gUmVzZXQgZmxhZ3MgdG8gdGhlIGRlZmF1bHQgdmFsdWVzXHJcbiAgbG9nZ2luZy5wYXRoQ3JlYXRlZCA9IGZhbHNlO1xyXG4gIGxvZ2dpbmcucGF0aFRvTG9nID0gJyc7XHJcblxyXG4gIC8vIFNldCB0aGUgbG9nZ2luZyBsZXZlbFxyXG4gIHNldExvZ0xldmVsKGxldmVsKTtcclxuXHJcbiAgLy8gU2V0IHRoZSBjb25zb2xlIGxvZ2dpbmdcclxuICBlbmFibGVDb25zb2xlTG9nZ2luZyh0b0NvbnNvbGUpO1xyXG5cclxuICAvLyBTZXQgdGhlIGZpbGUgbG9nZ2luZ1xyXG4gIGVuYWJsZUZpbGVMb2dnaW5nKGRlc3QsIGZpbGUsIHRvRmlsZSk7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBTZXRzIHRoZSBsb2cgbGV2ZWwgdG8gdGhlIHNwZWNpZmllZCB2YWx1ZS4gTG9nIGxldmVscyBhcmUgKGAwYCA9IG5vIGxvZ2dpbmcsXHJcbiAqIGAxYCA9IGVycm9yLCBgMmAgPSB3YXJuaW5nLCBgM2AgPSBub3RpY2UsIGA0YCA9IHZlcmJvc2UsIG9yIGA1YCA9IGJlbmNobWFyaykuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBzZXRMb2dMZXZlbFxyXG4gKlxyXG4gKiBAcGFyYW0ge251bWJlcn0gbGV2ZWwgLSBUaGUgbG9nIGxldmVsIHRvIGJlIHNldC5cclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiBzZXRMb2dMZXZlbChsZXZlbCkge1xyXG4gIGlmIChcclxuICAgIE51bWJlci5pc0ludGVnZXIobGV2ZWwpICYmXHJcbiAgICBsZXZlbCA+PSAwICYmXHJcbiAgICBsZXZlbCA8PSBsb2dnaW5nLmxldmVsc0Rlc2MubGVuZ3RoXHJcbiAgKSB7XHJcbiAgICAvLyBVcGRhdGUgdGhlIG1vZHVsZSBsb2dnaW5nJ3MgYGxldmVsYCBvcHRpb25cclxuICAgIGxvZ2dpbmcubGV2ZWwgPSBsZXZlbDtcclxuICB9XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBFbmFibGVzIGNvbnNvbGUgbG9nZ2luZy5cclxuICpcclxuICogQGZ1bmN0aW9uIGVuYWJsZUNvbnNvbGVMb2dnaW5nXHJcbiAqXHJcbiAqIEBwYXJhbSB7Ym9vbGVhbn0gdG9Db25zb2xlIC0gVGhlIGZsYWcgZm9yIHNldHRpbmcgdGhlIGxvZ2dpbmcgdG8gdGhlIGNvbnNvbGUuXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gZW5hYmxlQ29uc29sZUxvZ2dpbmcodG9Db25zb2xlKSB7XHJcbiAgLy8gVXBkYXRlIHRoZSBtb2R1bGUgbG9nZ2luZydzIGB0b0NvbnNvbGVgIG9wdGlvblxyXG4gIGxvZ2dpbmcudG9Db25zb2xlID0gISF0b0NvbnNvbGU7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBFbmFibGVzIGZpbGUgbG9nZ2luZyB3aXRoIHRoZSBzcGVjaWZpZWQgZGVzdGluYXRpb24gYW5kIGxvZyBmaWxlIG5hbWUuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBlbmFibGVGaWxlTG9nZ2luZ1xyXG4gKlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gZGVzdCAtIFRoZSBkZXN0aW5hdGlvbiBwYXRoIHdoZXJlIHRoZSBsb2cgZmlsZSBzaG91bGRcclxuICogYmUgc2F2ZWQuXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSBmaWxlIC0gVGhlIG5hbWUgb2YgdGhlIGxvZyBmaWxlLlxyXG4gKiBAcGFyYW0ge2Jvb2xlYW59IHRvRmlsZSAtIEEgZmxhZyBpbmRpY2F0aW5nIHdoZXRoZXIgbG9nZ2luZyBzaG91bGRcclxuICogYmUgZGlyZWN0ZWQgdG8gYSBmaWxlLlxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIGVuYWJsZUZpbGVMb2dnaW5nKGRlc3QsIGZpbGUsIHRvRmlsZSkge1xyXG4gIC8vIFVwZGF0ZSB0aGUgbW9kdWxlIGxvZ2dpbmcncyBgdG9GaWxlYCBvcHRpb25cclxuICBsb2dnaW5nLnRvRmlsZSA9ICEhdG9GaWxlO1xyXG5cclxuICAvLyBTZXQgdGhlIGBkZXN0YCBhbmQgYGZpbGVgIG9wdGlvbnMgb25seSBpZiB0aGUgZmlsZSBsb2dnaW5nIGlzIGVuYWJsZWRcclxuICBpZiAobG9nZ2luZy50b0ZpbGUpIHtcclxuICAgIGxvZ2dpbmcuZGVzdCA9IGRlc3QgfHwgJ2xvZyc7XHJcbiAgICBsb2dnaW5nLmZpbGUgPSBmaWxlIHx8ICdoaWdoY2hhcnRzLWV4cG9ydC1zZXJ2ZXIubG9nJztcclxuICB9XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBMb2dzIHRoZSBwcm92aWRlZCB0ZXh0cyB0byBhIGZpbGUsIGlmIGZpbGUgbG9nZ2luZyBpcyBlbmFibGVkLiBJdCBjcmVhdGVzXHJcbiAqIHRoZSBuZWNlc3NhcnkgZGlyZWN0b3J5IHN0cnVjdHVyZSBpZiBub3QgYWxyZWFkeSBjcmVhdGVkIGFuZCBhcHBlbmRzXHJcbiAqIHRoZSBjb250ZW50LCBpbmNsdWRpbmcgYW4gb3B0aW9uYWwgcHJlZml4LCB0byB0aGUgc3BlY2lmaWVkIGxvZyBmaWxlLlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gX2xvZ1RvRmlsZVxyXG4gKlxyXG4gKiBAcGFyYW0ge0FycmF5PHN0cmluZz59IHRleHRzIC0gQW4gYXJyYXkgb2YgdGV4dHMgdG8gYmUgbG9nZ2VkLlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gcHJlZml4IC0gQW4gb3B0aW9uYWwgcHJlZml4IHRvIGJlIGFkZGVkIHRvIGVhY2ggbG9nIGVudHJ5LlxyXG4gKi9cclxuZnVuY3Rpb24gX2xvZ1RvRmlsZSh0ZXh0cywgcHJlZml4KSB7XHJcbiAgaWYgKCFsb2dnaW5nLnBhdGhDcmVhdGVkKSB7XHJcbiAgICAvLyBDcmVhdGUgaWYgZG9lcyBub3QgZXhpc3RcclxuICAgICFleGlzdHNTeW5jKGdldEFic29sdXRlUGF0aChsb2dnaW5nLmRlc3QpKSAmJlxyXG4gICAgICBta2RpclN5bmMoZ2V0QWJzb2x1dGVQYXRoKGxvZ2dpbmcuZGVzdCkpO1xyXG5cclxuICAgIC8vIENyZWF0ZSB0aGUgZnVsbCBwYXRoXHJcbiAgICBsb2dnaW5nLnBhdGhUb0xvZyA9IGdldEFic29sdXRlUGF0aChqb2luKGxvZ2dpbmcuZGVzdCwgbG9nZ2luZy5maWxlKSk7XHJcblxyXG4gICAgLy8gV2Ugbm93IGFzc3VtZSB0aGUgcGF0aCBpcyBhdmFpbGFibGUsIGUuZy4gaXQncyB0aGUgcmVzcG9uc2liaWxpdHlcclxuICAgIC8vIG9mIHRoZSB1c2VyIHRvIGNyZWF0ZSB0aGUgcGF0aCB3aXRoIHRoZSBjb3JyZWN0IGFjY2VzcyByaWdodHMuXHJcbiAgICBsb2dnaW5nLnBhdGhDcmVhdGVkID0gdHJ1ZTtcclxuICB9XHJcblxyXG4gIC8vIEFkZCB0aGUgY29udGVudCB0byBhIGZpbGVcclxuICBhcHBlbmRGaWxlKFxyXG4gICAgbG9nZ2luZy5wYXRoVG9Mb2csXHJcbiAgICBbcHJlZml4XS5jb25jYXQodGV4dHMpLmpvaW4oJyAnKSArICdcXG4nLFxyXG4gICAgKGVycm9yKSA9PiB7XHJcbiAgICAgIGlmIChlcnJvciAmJiBsb2dnaW5nLnRvRmlsZSAmJiBsb2dnaW5nLnBhdGhDcmVhdGVkKSB7XHJcbiAgICAgICAgbG9nZ2luZy50b0ZpbGUgPSBmYWxzZTtcclxuICAgICAgICBsb2dnaW5nLnBhdGhDcmVhdGVkID0gZmFsc2U7XHJcbiAgICAgICAgbG9nV2l0aFN0YWNrKDIsIGVycm9yLCBgW2xvZ2dlcl0gVW5hYmxlIHRvIHdyaXRlIHRvIGxvZyBmaWxlLmApO1xyXG4gICAgICB9XHJcbiAgICB9XHJcbiAgKTtcclxufVxyXG5cclxuZXhwb3J0IGRlZmF1bHQge1xyXG4gIGxvZyxcclxuICBsb2dXaXRoU3RhY2ssXHJcbiAgbG9nWm9kSXNzdWVzLFxyXG4gIGluaXRMb2dnaW5nLFxyXG4gIHNldExvZ0xldmVsLFxyXG4gIGVuYWJsZUNvbnNvbGVMb2dnaW5nLFxyXG4gIGVuYWJsZUZpbGVMb2dnaW5nXHJcbn07XHJcbiIsIi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXHJcblxyXG5IaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXJcclxuXHJcbkNvcHlyaWdodCAoYykgMjAxNi0yMDI1LCBIaWdoc29mdFxyXG5cclxuTGljZW5jZWQgdW5kZXIgdGhlIE1JVCBsaWNlbmNlLlxyXG5cclxuQWRkaXRpb25hbGx5IGEgdmFsaWQgSGlnaGNoYXJ0cyBsaWNlbnNlIGlzIHJlcXVpcmVkIGZvciB1c2UuXHJcblxyXG5TZWUgTElDRU5TRSBmaWxlIGluIHJvb3QgZm9yIGRldGFpbHMuXHJcblxyXG4qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xyXG5cclxuLyoqXHJcbiAqIEBvdmVydmlldyBDb25maWd1cmF0aW9uIG1hbmFnZW1lbnQgbW9kdWxlIGZvciB0aGUgSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyLlxyXG4gKiBJdCBwcm92aWRlcyBhIGRlZmF1bHQgY29uZmlndXJhdGlvbiBvYmplY3Qgd2l0aCBwcmVkZWZpbmVkIGRlZmF1bHQgdmFsdWVzLFxyXG4gKiBkZXNjcmlwdGlvbnMsIGFuZCBjaGFyYWN0ZXJpc3RpY3MgZm9yIGVhY2ggb3B0aW9uIHVzZWQgaW4gdGhlIEV4cG9ydCBTZXJ2ZXIuXHJcbiAqL1xyXG5cclxuLyoqXHJcbiAqIFRoZSBkZWZhdWx0IGNvbmZpZ3VyYXRpb24gb2JqZWN0IGNvbnRhaW5pbmcgYWxsIGF2YWlsYWJsZSBvcHRpb25zLCBvcmdhbml6ZWRcclxuICogYnkgc2VjdGlvbnMuXHJcbiAqXHJcbiAqIFRoaXMgb2JqZWN0IGluY2x1ZGVzOlxyXG4gKiAtIERlZmF1bHQgdmFsdWVzIGZvciBlYWNoIG9wdGlvbi5cclxuICogLSBEYXRhIHR5cGVzIGZvciB2YWxpZGF0aW9uLlxyXG4gKiAtIE5hbWVzIG9mIGNvcnJlc3BvbmRpbmcgZW52aXJvbm1lbnQgdmFyaWFibGVzLlxyXG4gKiAtIERlc2NyaXB0aW9ucyBvZiBlYWNoIHByb3BlcnR5LlxyXG4gKiAtIEluZm9ybWF0aW9uIHVzZWQgZm9yIHByb21wdHMgaW4gaW50ZXJhY3RpdmUgY29uZmlndXJhdGlvbi5cclxuICogLSBbT3B0aW9uYWxdIENvcnJlc3BvbmRpbmcgQ0xJIGFyZ3VtZW50IG5hbWVzIGZvciBDTEkgdXNhZ2UuXHJcbiAqIC0gW09wdGlvbmFsXSBMZWdhY3kgbmFtZXMgZnJvbSB0aGUgcHJldmlvdXMgUGhhbnRvbUpTLWJhc2VkIHNlcnZlci5cclxuICovXHJcbmNvbnN0IGRlZmF1bHRDb25maWcgPSB7XHJcbiAgcHVwcGV0ZWVyOiB7XHJcbiAgICBhcmdzOiB7XHJcbiAgICAgIHZhbHVlOiBbXHJcbiAgICAgICAgJy0tYWxsb3ctcnVubmluZy1pbnNlY3VyZS1jb250ZW50JyxcclxuICAgICAgICAnLS1hc2gtbm8tbnVkZ2VzJyxcclxuICAgICAgICAnLS1hdXRvcGxheS1wb2xpY3k9dXNlci1nZXN0dXJlLXJlcXVpcmVkJyxcclxuICAgICAgICAnLS1ibG9jay1uZXctd2ViLWNvbnRlbnRzJyxcclxuICAgICAgICAnLS1kaXNhYmxlLWFjY2VsZXJhdGVkLTJkLWNhbnZhcycsXHJcbiAgICAgICAgJy0tZGlzYWJsZS1iYWNrZ3JvdW5kLW5ldHdvcmtpbmcnLFxyXG4gICAgICAgICctLWRpc2FibGUtYmFja2dyb3VuZC10aW1lci10aHJvdHRsaW5nJyxcclxuICAgICAgICAnLS1kaXNhYmxlLWJhY2tncm91bmRpbmctb2NjbHVkZWQtd2luZG93cycsXHJcbiAgICAgICAgJy0tZGlzYWJsZS1icmVha3BhZCcsXHJcbiAgICAgICAgJy0tZGlzYWJsZS1jaGVja2VyLWltYWdpbmcnLFxyXG4gICAgICAgICctLWRpc2FibGUtY2xpZW50LXNpZGUtcGhpc2hpbmctZGV0ZWN0aW9uJyxcclxuICAgICAgICAnLS1kaXNhYmxlLWNvbXBvbmVudC1leHRlbnNpb25zLXdpdGgtYmFja2dyb3VuZC1wYWdlcycsXHJcbiAgICAgICAgJy0tZGlzYWJsZS1jb21wb25lbnQtdXBkYXRlJyxcclxuICAgICAgICAnLS1kaXNhYmxlLWRlZmF1bHQtYXBwcycsXHJcbiAgICAgICAgJy0tZGlzYWJsZS1kZXYtc2htLXVzYWdlJyxcclxuICAgICAgICAnLS1kaXNhYmxlLWRvbWFpbi1yZWxpYWJpbGl0eScsXHJcbiAgICAgICAgJy0tZGlzYWJsZS1leHRlbnNpb25zJyxcclxuICAgICAgICAnLS1kaXNhYmxlLWZlYXR1cmVzPUNhbGN1bGF0ZU5hdGl2ZVdpbk9jY2x1c2lvbixJbnRlcmVzdEZlZWRDb250ZW50U3VnZ2VzdGlvbnMsV2ViT1RQJyxcclxuICAgICAgICAnLS1kaXNhYmxlLWhhbmctbW9uaXRvcicsXHJcbiAgICAgICAgJy0tZGlzYWJsZS1pcGMtZmxvb2RpbmctcHJvdGVjdGlvbicsXHJcbiAgICAgICAgJy0tZGlzYWJsZS1sb2dnaW5nJyxcclxuICAgICAgICAnLS1kaXNhYmxlLW5vdGlmaWNhdGlvbnMnLFxyXG4gICAgICAgICctLWRpc2FibGUtb2ZmZXItc3RvcmUtdW5tYXNrZWQtd2FsbGV0LWNhcmRzJyxcclxuICAgICAgICAnLS1kaXNhYmxlLXBvcHVwLWJsb2NraW5nJyxcclxuICAgICAgICAnLS1kaXNhYmxlLXByaW50LXByZXZpZXcnLFxyXG4gICAgICAgICctLWRpc2FibGUtcHJvbXB0LW9uLXJlcG9zdCcsXHJcbiAgICAgICAgJy0tZGlzYWJsZS1yZW5kZXJlci1iYWNrZ3JvdW5kaW5nJyxcclxuICAgICAgICAnLS1kaXNhYmxlLXNlYXJjaC1lbmdpbmUtY2hvaWNlLXNjcmVlbicsXHJcbiAgICAgICAgJy0tZGlzYWJsZS1zZXNzaW9uLWNyYXNoZWQtYnViYmxlJyxcclxuICAgICAgICAnLS1kaXNhYmxlLXNldHVpZC1zYW5kYm94JyxcclxuICAgICAgICAnLS1kaXNhYmxlLXNpdGUtaXNvbGF0aW9uLXRyaWFscycsXHJcbiAgICAgICAgJy0tZGlzYWJsZS1zcGVlY2gtYXBpJyxcclxuICAgICAgICAnLS1kaXNhYmxlLXN5bmMnLFxyXG4gICAgICAgICctLWVuYWJsZS11bnNhZmUtd2ViZ3B1JyxcclxuICAgICAgICAnLS1oaWRlLWNyYXNoLXJlc3RvcmUtYnViYmxlJyxcclxuICAgICAgICAnLS1oaWRlLXNjcm9sbGJhcnMnLFxyXG4gICAgICAgICctLW1ldHJpY3MtcmVjb3JkaW5nLW9ubHknLFxyXG4gICAgICAgICctLW11dGUtYXVkaW8nLFxyXG4gICAgICAgICctLW5vLWRlZmF1bHQtYnJvd3Nlci1jaGVjaycsXHJcbiAgICAgICAgJy0tbm8tZmlyc3QtcnVuJyxcclxuICAgICAgICAnLS1uby1waW5ncycsXHJcbiAgICAgICAgJy0tbm8tc2FuZGJveCcsXHJcbiAgICAgICAgJy0tbm8tc3RhcnR1cC13aW5kb3cnLFxyXG4gICAgICAgICctLW5vLXp5Z290ZScsXHJcbiAgICAgICAgJy0tcGFzc3dvcmQtc3RvcmU9YmFzaWMnLFxyXG4gICAgICAgICctLXByb2Nlc3MtcGVyLXRhYicsXHJcbiAgICAgICAgJy0tdXNlLW1vY2sta2V5Y2hhaW4nXHJcbiAgICAgIF0sXHJcbiAgICAgIHR5cGVzOiBbJ3N0cmluZ1tdJ10sXHJcbiAgICAgIGVudkxpbms6ICdQVVBQRVRFRVJfQVJHUycsXHJcbiAgICAgIGNsaU5hbWU6ICdwdXBwZXRlZXJBcmdzJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdBcnJheSBvZiBQdXBwZXRlZXIgYXJndW1lbnRzJyxcclxuICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgIHR5cGU6ICdsaXN0JyxcclxuICAgICAgICBzZXBhcmF0b3I6ICc7J1xyXG4gICAgICB9XHJcbiAgICB9XHJcbiAgfSxcclxuICBoaWdoY2hhcnRzOiB7XHJcbiAgICB2ZXJzaW9uOiB7XHJcbiAgICAgIHZhbHVlOiAnbGF0ZXN0JyxcclxuICAgICAgdHlwZXM6IFsnc3RyaW5nJ10sXHJcbiAgICAgIGVudkxpbms6ICdISUdIQ0hBUlRTX1ZFUlNJT04nLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ0hpZ2hjaGFydHMgdmVyc2lvbicsXHJcbiAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICB0eXBlOiAndGV4dCdcclxuICAgICAgfVxyXG4gICAgfSxcclxuICAgIGNkblVybDoge1xyXG4gICAgICB2YWx1ZTogJ2h0dHBzOi8vY29kZS5oaWdoY2hhcnRzLmNvbScsXHJcbiAgICAgIHR5cGVzOiBbJ3N0cmluZyddLFxyXG4gICAgICBlbnZMaW5rOiAnSElHSENIQVJUU19DRE5fVVJMJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdDRE4gVVJMIGZvciBIaWdoY2hhcnRzIHNjcmlwdHMnLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ3RleHQnXHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICBmb3JjZUZldGNoOiB7XHJcbiAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgdHlwZXM6IFsnYm9vbGVhbiddLFxyXG4gICAgICBlbnZMaW5rOiAnSElHSENIQVJUU19GT1JDRV9GRVRDSCcsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnRmxhZyB0byByZWZldGNoIHNjcmlwdHMgYWZ0ZXIgZWFjaCBzZXJ2ZXIgcmVydW4nLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ3RvZ2dsZSdcclxuICAgICAgfVxyXG4gICAgfSxcclxuICAgIGNhY2hlUGF0aDoge1xyXG4gICAgICB2YWx1ZTogJy5jYWNoZScsXHJcbiAgICAgIHR5cGVzOiBbJ3N0cmluZyddLFxyXG4gICAgICBlbnZMaW5rOiAnSElHSENIQVJUU19DQUNIRV9QQVRIJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdEaXJlY3RvcnkgcGF0aCBmb3IgY2FjaGVkIEhpZ2hjaGFydHMgc2NyaXB0cycsXHJcbiAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICB0eXBlOiAndGV4dCdcclxuICAgICAgfVxyXG4gICAgfSxcclxuICAgIGNvcmVTY3JpcHRzOiB7XHJcbiAgICAgIHZhbHVlOiBbJ2hpZ2hjaGFydHMnLCAnaGlnaGNoYXJ0cy1tb3JlJywgJ2hpZ2hjaGFydHMtM2QnXSxcclxuICAgICAgdHlwZXM6IFsnc3RyaW5nW10nXSxcclxuICAgICAgZW52TGluazogJ0hJR0hDSEFSVFNfQ09SRV9TQ1JJUFRTJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdIaWdoY2hhcnRzIGNvcmUgc2NyaXB0cyB0byBmZXRjaCcsXHJcbiAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICB0eXBlOiAnbXVsdGlzZWxlY3QnLFxyXG4gICAgICAgIGluc3RydWN0aW9uczogJ1NwYWNlOiBTZWxlY3Qgc3BlY2lmaWMsIEE6IFNlbGVjdCBhbGwsIEVudGVyOiBDb25maXJtJ1xyXG4gICAgICB9XHJcbiAgICB9LFxyXG4gICAgbW9kdWxlU2NyaXB0czoge1xyXG4gICAgICB2YWx1ZTogW1xyXG4gICAgICAgICdzdG9jaycsXHJcbiAgICAgICAgJ21hcCcsXHJcbiAgICAgICAgJ2dhbnR0JyxcclxuICAgICAgICAnZXhwb3J0aW5nJyxcclxuICAgICAgICAncGFyYWxsZWwtY29vcmRpbmF0ZXMnLFxyXG4gICAgICAgICdhY2Nlc3NpYmlsaXR5JyxcclxuICAgICAgICAvLyAnYW5ub3RhdGlvbnMtYWR2YW5jZWQnLFxyXG4gICAgICAgICdib29zdC1jYW52YXMnLFxyXG4gICAgICAgICdib29zdCcsXHJcbiAgICAgICAgJ2RhdGEnLFxyXG4gICAgICAgICdkYXRhLXRvb2xzJyxcclxuICAgICAgICAnZHJhZ2dhYmxlLXBvaW50cycsXHJcbiAgICAgICAgJ3N0YXRpYy1zY2FsZScsXHJcbiAgICAgICAgJ2Jyb2tlbi1heGlzJyxcclxuICAgICAgICAnaGVhdG1hcCcsXHJcbiAgICAgICAgJ3RpbGVtYXAnLFxyXG4gICAgICAgICd0aWxlZHdlYm1hcCcsXHJcbiAgICAgICAgJ3RpbWVsaW5lJyxcclxuICAgICAgICAndHJlZW1hcCcsXHJcbiAgICAgICAgJ3RyZWVncmFwaCcsXHJcbiAgICAgICAgJ2l0ZW0tc2VyaWVzJyxcclxuICAgICAgICAnZHJpbGxkb3duJyxcclxuICAgICAgICAnaGlzdG9ncmFtLWJlbGxjdXJ2ZScsXHJcbiAgICAgICAgJ2J1bGxldCcsXHJcbiAgICAgICAgJ2Z1bm5lbCcsXHJcbiAgICAgICAgJ2Z1bm5lbDNkJyxcclxuICAgICAgICAnZ2VvaGVhdG1hcCcsXHJcbiAgICAgICAgJ3B5cmFtaWQzZCcsXHJcbiAgICAgICAgJ25ldHdvcmtncmFwaCcsXHJcbiAgICAgICAgJ292ZXJsYXBwaW5nLWRhdGFsYWJlbHMnLFxyXG4gICAgICAgICdwYXJldG8nLFxyXG4gICAgICAgICdwYXR0ZXJuLWZpbGwnLFxyXG4gICAgICAgICdwaWN0b3JpYWwnLFxyXG4gICAgICAgICdwcmljZS1pbmRpY2F0b3InLFxyXG4gICAgICAgICdzYW5rZXknLFxyXG4gICAgICAgICdhcmMtZGlhZ3JhbScsXHJcbiAgICAgICAgJ2RlcGVuZGVuY3ktd2hlZWwnLFxyXG4gICAgICAgICdzZXJpZXMtbGFiZWwnLFxyXG4gICAgICAgICdzZXJpZXMtb24tcG9pbnQnLFxyXG4gICAgICAgICdzb2xpZC1nYXVnZScsXHJcbiAgICAgICAgJ3NvbmlmaWNhdGlvbicsXHJcbiAgICAgICAgLy8gJ3N0b2NrLXRvb2xzJyxcclxuICAgICAgICAnc3RyZWFtZ3JhcGgnLFxyXG4gICAgICAgICdzdW5idXJzdCcsXHJcbiAgICAgICAgJ3ZhcmlhYmxlLXBpZScsXHJcbiAgICAgICAgJ3Zhcml3aWRlJyxcclxuICAgICAgICAndmVjdG9yJyxcclxuICAgICAgICAndmVubicsXHJcbiAgICAgICAgJ3dpbmRiYXJiJyxcclxuICAgICAgICAnd29yZGNsb3VkJyxcclxuICAgICAgICAneHJhbmdlJyxcclxuICAgICAgICAnbm8tZGF0YS10by1kaXNwbGF5JyxcclxuICAgICAgICAnZHJhZy1wYW5lcycsXHJcbiAgICAgICAgJ2RlYnVnZ2VyJyxcclxuICAgICAgICAnZHVtYmJlbGwnLFxyXG4gICAgICAgICdsb2xsaXBvcCcsXHJcbiAgICAgICAgJ2N5bGluZGVyJyxcclxuICAgICAgICAnb3JnYW5pemF0aW9uJyxcclxuICAgICAgICAnZG90cGxvdCcsXHJcbiAgICAgICAgJ21hcmtlci1jbHVzdGVycycsXHJcbiAgICAgICAgJ2hvbGxvd2NhbmRsZXN0aWNrJyxcclxuICAgICAgICAnaGVpa2luYXNoaScsXHJcbiAgICAgICAgJ2Zsb3dtYXAnLFxyXG4gICAgICAgICdleHBvcnQtZGF0YScsXHJcbiAgICAgICAgJ25hdmlnYXRvcicsXHJcbiAgICAgICAgJ3RleHRwYXRoJ1xyXG4gICAgICBdLFxyXG4gICAgICB0eXBlczogWydzdHJpbmdbXSddLFxyXG4gICAgICBlbnZMaW5rOiAnSElHSENIQVJUU19NT0RVTEVfU0NSSVBUUycsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnSGlnaGNoYXJ0cyBtb2R1bGUgc2NyaXB0cyB0byBmZXRjaCcsXHJcbiAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICB0eXBlOiAnbXVsdGlzZWxlY3QnLFxyXG4gICAgICAgIGluc3RydWN0aW9uczogJ1NwYWNlOiBTZWxlY3Qgc3BlY2lmaWMsIEE6IFNlbGVjdCBhbGwsIEVudGVyOiBDb25maXJtJ1xyXG4gICAgICB9XHJcbiAgICB9LFxyXG4gICAgaW5kaWNhdG9yU2NyaXB0czoge1xyXG4gICAgICB2YWx1ZTogWydpbmRpY2F0b3JzLWFsbCddLFxyXG4gICAgICB0eXBlczogWydzdHJpbmdbXSddLFxyXG4gICAgICBlbnZMaW5rOiAnSElHSENIQVJUU19JTkRJQ0FUT1JfU0NSSVBUUycsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnSGlnaGNoYXJ0cyBpbmRpY2F0b3Igc2NyaXB0cyB0byBmZXRjaCcsXHJcbiAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICB0eXBlOiAnbXVsdGlzZWxlY3QnLFxyXG4gICAgICAgIGluc3RydWN0aW9uczogJ1NwYWNlOiBTZWxlY3Qgc3BlY2lmaWMsIEE6IFNlbGVjdCBhbGwsIEVudGVyOiBDb25maXJtJ1xyXG4gICAgICB9XHJcbiAgICB9LFxyXG4gICAgY3VzdG9tU2NyaXB0czoge1xyXG4gICAgICB2YWx1ZTogW1xyXG4gICAgICAgICdodHRwczovL2NkbmpzLmNsb3VkZmxhcmUuY29tL2FqYXgvbGlicy9tb21lbnQuanMvMi4zMC4xL21vbWVudC5taW4uanMnLFxyXG4gICAgICAgICdodHRwczovL2NkbmpzLmNsb3VkZmxhcmUuY29tL2FqYXgvbGlicy9tb21lbnQtdGltZXpvbmUvMC41LjQ1L21vbWVudC10aW1lem9uZS13aXRoLWRhdGEubWluLmpzJ1xyXG4gICAgICBdLFxyXG4gICAgICB0eXBlczogWydzdHJpbmdbXSddLFxyXG4gICAgICBlbnZMaW5rOiAnSElHSENIQVJUU19DVVNUT01fU0NSSVBUUycsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnQWRkaXRpb25hbCBjdXN0b20gc2NyaXB0cyBvciBkZXBlbmRlbmNpZXMgdG8gZmV0Y2gnLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ2xpc3QnLFxyXG4gICAgICAgIHNlcGFyYXRvcjogJzsnXHJcbiAgICAgIH1cclxuICAgIH1cclxuICB9LFxyXG4gIGV4cG9ydDoge1xyXG4gICAgaW5maWxlOiB7XHJcbiAgICAgIHZhbHVlOiBudWxsLFxyXG4gICAgICB0eXBlczogWydzdHJpbmcnLCAnbnVsbCddLFxyXG4gICAgICBlbnZMaW5rOiAnRVhQT1JUX0lORklMRScsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdJbnB1dCBmaWxlbmFtZSB3aXRoIHR5cGUsIGZvcm1hdHRlZCBjb3JyZWN0bHkgYXMgSlNPTiBvciBTVkcnLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ3RleHQnXHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICBpbnN0cjoge1xyXG4gICAgICB2YWx1ZTogbnVsbCxcclxuICAgICAgdHlwZXM6IFsnT2JqZWN0JywgJ3N0cmluZycsICdudWxsJ10sXHJcbiAgICAgIGVudkxpbms6ICdFWFBPUlRfSU5TVFInLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnT3ZlcnJpZGVzIHRoZSBgaW5maWxlYCB3aXRoIEpTT04sIHN0cmluZ2lmaWVkIEpTT04sIG9yIFNWRyBpbnB1dCcsXHJcbiAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICB0eXBlOiAndGV4dCdcclxuICAgICAgfVxyXG4gICAgfSxcclxuICAgIG9wdGlvbnM6IHtcclxuICAgICAgdmFsdWU6IG51bGwsXHJcbiAgICAgIHR5cGVzOiBbJ09iamVjdCcsICdzdHJpbmcnLCAnbnVsbCddLFxyXG4gICAgICBlbnZMaW5rOiAnRVhQT1JUX09QVElPTlMnLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ0FsaWFzIGZvciB0aGUgYGluc3RyYCBvcHRpb24nLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ3RleHQnXHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICBzdmc6IHtcclxuICAgICAgdmFsdWU6IG51bGwsXHJcbiAgICAgIHR5cGVzOiBbJ3N0cmluZycsICdudWxsJ10sXHJcbiAgICAgIGVudkxpbms6ICdFWFBPUlRfU1ZHJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdTVkcgc3RyaW5nIHJlcHJlc2VudGF0aW9uIG9mIHRoZSBjaGFydCB0byByZW5kZXInLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ3RleHQnXHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICBiYXRjaDoge1xyXG4gICAgICB2YWx1ZTogbnVsbCxcclxuICAgICAgdHlwZXM6IFsnc3RyaW5nJywgJ251bGwnXSxcclxuICAgICAgZW52TGluazogJ0VYUE9SVF9CQVRDSCcsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdCYXRjaCBqb2Igc3RyaW5nIHdpdGggaW5wdXQvb3V0cHV0IHBhaXJzOiBcImluPW91dDtpbj1vdXQ7Li4uXCInLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ3RleHQnXHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICBvdXRmaWxlOiB7XHJcbiAgICAgIHZhbHVlOiBudWxsLFxyXG4gICAgICB0eXBlczogWydzdHJpbmcnLCAnbnVsbCddLFxyXG4gICAgICBlbnZMaW5rOiAnRVhQT1JUX09VVEZJTEUnLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnT3V0cHV0IGZpbGVuYW1lIHdpdGggdHlwZS4gQ2FuIGJlIGpwZWcsIHBuZywgcGRmLCBvciBzdmcgYW5kIGlnbm9yZXMgYHR5cGVgIG9wdGlvbicsXHJcbiAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICB0eXBlOiAndGV4dCdcclxuICAgICAgfVxyXG4gICAgfSxcclxuICAgIHR5cGU6IHtcclxuICAgICAgdmFsdWU6ICdwbmcnLFxyXG4gICAgICB0eXBlczogWydzdHJpbmcnXSxcclxuICAgICAgZW52TGluazogJ0VYUE9SVF9UWVBFJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdGaWxlIGV4cG9ydCBmb3JtYXQuIENhbiBiZSBqcGVnLCBwbmcsIHBkZiwgb3Igc3ZnJyxcclxuICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgIHR5cGU6ICdzZWxlY3QnLFxyXG4gICAgICAgIGhpbnQ6ICdEZWZhdWx0OiBwbmcnLFxyXG4gICAgICAgIGNob2ljZXM6IFsncG5nJywgJ2pwZWcnLCAncGRmJywgJ3N2ZyddXHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICBjb25zdHI6IHtcclxuICAgICAgdmFsdWU6ICdjaGFydCcsXHJcbiAgICAgIHR5cGVzOiBbJ3N0cmluZyddLFxyXG4gICAgICBlbnZMaW5rOiAnRVhQT1JUX0NPTlNUUicsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdDaGFydCBjb25zdHJ1Y3Rvci4gQ2FuIGJlIGNoYXJ0LCBzdG9ja0NoYXJ0LCBtYXBDaGFydCwgb3IgZ2FudHRDaGFydCcsXHJcbiAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICB0eXBlOiAnc2VsZWN0JyxcclxuICAgICAgICBoaW50OiAnRGVmYXVsdDogY2hhcnQnLFxyXG4gICAgICAgIGNob2ljZXM6IFsnY2hhcnQnLCAnc3RvY2tDaGFydCcsICdtYXBDaGFydCcsICdnYW50dENoYXJ0J11cclxuICAgICAgfVxyXG4gICAgfSxcclxuICAgIGI2NDoge1xyXG4gICAgICB2YWx1ZTogZmFsc2UsXHJcbiAgICAgIHR5cGVzOiBbJ2Jvb2xlYW4nXSxcclxuICAgICAgZW52TGluazogJ0VYUE9SVF9CNjQnLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnV2hldGhlciBvciBub3QgdG8gdGhlIGNoYXJ0IHNob3VsZCBiZSByZWNlaXZlZCBpbiBCYXNlNjQgZm9ybWF0IGluc3RlYWQgb2YgYmluYXJ5JyxcclxuICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgIHR5cGU6ICd0b2dnbGUnXHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICBub0Rvd25sb2FkOiB7XHJcbiAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgdHlwZXM6IFsnYm9vbGVhbiddLFxyXG4gICAgICBlbnZMaW5rOiAnRVhQT1JUX05PX0RPV05MT0FEJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ1doZXRoZXIgb3Igbm90IHRvIGluY2x1ZGUgb3IgZXhjbHVkZSBhdHRhY2htZW50IGhlYWRlcnMgaW4gdGhlIHJlc3BvbnNlJyxcclxuICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgIHR5cGU6ICd0b2dnbGUnXHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICBoZWlnaHQ6IHtcclxuICAgICAgdmFsdWU6IG51bGwsXHJcbiAgICAgIHR5cGVzOiBbJ251bWJlcicsICdudWxsJ10sXHJcbiAgICAgIGVudkxpbms6ICdFWFBPUlRfSEVJR0hUJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdIZWlnaHQgb2YgdGhlIGV4cG9ydGVkIGNoYXJ0LCBvdmVycmlkZXMgY2hhcnQgc2V0dGluZ3MnLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ251bWJlcidcclxuICAgICAgfVxyXG4gICAgfSxcclxuICAgIHdpZHRoOiB7XHJcbiAgICAgIHZhbHVlOiBudWxsLFxyXG4gICAgICB0eXBlczogWydudW1iZXInLCAnbnVsbCddLFxyXG4gICAgICBlbnZMaW5rOiAnRVhQT1JUX1dJRFRIJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdXaWR0aCBvZiB0aGUgZXhwb3J0ZWQgY2hhcnQsIG92ZXJyaWRlcyBjaGFydCBzZXR0aW5ncycsXHJcbiAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICB0eXBlOiAnbnVtYmVyJ1xyXG4gICAgICB9XHJcbiAgICB9LFxyXG4gICAgc2NhbGU6IHtcclxuICAgICAgdmFsdWU6IG51bGwsXHJcbiAgICAgIHR5cGVzOiBbJ251bWJlcicsICdudWxsJ10sXHJcbiAgICAgIGVudkxpbms6ICdFWFBPUlRfU0NBTEUnLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnU2NhbGUgb2YgdGhlIGV4cG9ydGVkIGNoYXJ0LCBvdmVycmlkZXMgY2hhcnQgc2V0dGluZ3MuIFJhbmdlcyBmcm9tIDAuMSB0byA1LjAnLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ251bWJlcidcclxuICAgICAgfVxyXG4gICAgfSxcclxuICAgIGRlZmF1bHRIZWlnaHQ6IHtcclxuICAgICAgdmFsdWU6IDQwMCxcclxuICAgICAgdHlwZXM6IFsnbnVtYmVyJ10sXHJcbiAgICAgIGVudkxpbms6ICdFWFBPUlRfREVGQVVMVF9IRUlHSFQnLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ0RlZmF1bHQgaGVpZ2h0IG9mIHRoZSBleHBvcnRlZCBjaGFydCBpZiBub3Qgc2V0JyxcclxuICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgIHR5cGU6ICdudW1iZXInXHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICBkZWZhdWx0V2lkdGg6IHtcclxuICAgICAgdmFsdWU6IDYwMCxcclxuICAgICAgdHlwZXM6IFsnbnVtYmVyJ10sXHJcbiAgICAgIGVudkxpbms6ICdFWFBPUlRfREVGQVVMVF9XSURUSCcsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnRGVmYXVsdCB3aWR0aCBvZiB0aGUgZXhwb3J0ZWQgY2hhcnQgaWYgbm90IHNldCcsXHJcbiAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICB0eXBlOiAnbnVtYmVyJ1xyXG4gICAgICB9XHJcbiAgICB9LFxyXG4gICAgZGVmYXVsdFNjYWxlOiB7XHJcbiAgICAgIHZhbHVlOiAxLFxyXG4gICAgICB0eXBlczogWydudW1iZXInXSxcclxuICAgICAgZW52TGluazogJ0VYUE9SVF9ERUZBVUxUX1NDQUxFJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ0RlZmF1bHQgc2NhbGUgb2YgdGhlIGV4cG9ydGVkIGNoYXJ0IGlmIG5vdCBzZXQuIFJhbmdlcyBmcm9tIDAuMSB0byA1LjAnLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgICAgbWluOiAwLjEsXHJcbiAgICAgICAgbWF4OiA1XHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICBnbG9iYWxPcHRpb25zOiB7XHJcbiAgICAgIHZhbHVlOiBudWxsLFxyXG4gICAgICB0eXBlczogWydPYmplY3QnLCAnc3RyaW5nJywgJ251bGwnXSxcclxuICAgICAgZW52TGluazogJ0VYUE9SVF9HTE9CQUxfT1BUSU9OUycsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdKU09OLCBzdHJpbmdpZmllZCBKU09OIG9yIGZpbGVuYW1lIHdpdGggZ2xvYmFsIG9wdGlvbnMgZm9yIEhpZ2hjaGFydHMuc2V0T3B0aW9ucycsXHJcbiAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICB0eXBlOiAndGV4dCdcclxuICAgICAgfVxyXG4gICAgfSxcclxuICAgIHRoZW1lT3B0aW9uczoge1xyXG4gICAgICB2YWx1ZTogbnVsbCxcclxuICAgICAgdHlwZXM6IFsnT2JqZWN0JywgJ3N0cmluZycsICdudWxsJ10sXHJcbiAgICAgIGVudkxpbms6ICdFWFBPUlRfVEhFTUVfT1BUSU9OUycsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdKU09OLCBzdHJpbmdpZmllZCBKU09OIG9yIGZpbGVuYW1lIHdpdGggdGhlbWUgb3B0aW9ucyBmb3IgSGlnaGNoYXJ0cy5zZXRPcHRpb25zJyxcclxuICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgIHR5cGU6ICd0ZXh0J1xyXG4gICAgICB9XHJcbiAgICB9LFxyXG4gICAgcmFzdGVyaXphdGlvblRpbWVvdXQ6IHtcclxuICAgICAgdmFsdWU6IDE1MDAsXHJcbiAgICAgIHR5cGVzOiBbJ251bWJlciddLFxyXG4gICAgICBlbnZMaW5rOiAnRVhQT1JUX1JBU1RFUklaQVRJT05fVElNRU9VVCcsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnTWlsbGlzZWNvbmRzIHRvIHdhaXQgZm9yIHdlYnBhZ2UgcmVuZGVyaW5nJyxcclxuICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgIHR5cGU6ICdudW1iZXInXHJcbiAgICAgIH1cclxuICAgIH1cclxuICB9LFxyXG4gIGN1c3RvbUxvZ2ljOiB7XHJcbiAgICBhbGxvd0NvZGVFeGVjdXRpb246IHtcclxuICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICB0eXBlczogWydib29sZWFuJ10sXHJcbiAgICAgIGVudkxpbms6ICdDVVNUT01fTE9HSUNfQUxMT1dfQ09ERV9FWEVDVVRJT04nLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnQWxsb3dzIG9yIGRpc2FsbG93cyBleGVjdXRpb24gb2YgYXJiaXRyYXJ5IGNvZGUgZHVyaW5nIGV4cG9ydGluZycsXHJcbiAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICB0eXBlOiAndG9nZ2xlJ1xyXG4gICAgICB9XHJcbiAgICB9LFxyXG4gICAgYWxsb3dGaWxlUmVzb3VyY2VzOiB7XHJcbiAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgdHlwZXM6IFsnYm9vbGVhbiddLFxyXG4gICAgICBlbnZMaW5rOiAnQ1VTVE9NX0xPR0lDX0FMTE9XX0ZJTEVfUkVTT1VSQ0VTJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ0FsbG93cyBvciBkaXNhbGxvd3MgaW5qZWN0aW9uIG9mIGZpbGVzeXN0ZW0gcmVzb3VyY2VzIChkaXNhYmxlZCBpbiBzZXJ2ZXIgbW9kZSknLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ3RvZ2dsZSdcclxuICAgICAgfVxyXG4gICAgfSxcclxuICAgIGN1c3RvbUNvZGU6IHtcclxuICAgICAgdmFsdWU6IG51bGwsXHJcbiAgICAgIHR5cGVzOiBbJ3N0cmluZycsICdudWxsJ10sXHJcbiAgICAgIGVudkxpbms6ICdDVVNUT01fTE9HSUNfQ1VTVE9NX0NPREUnLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnQ3VzdG9tIGNvZGUgdG8gZXhlY3V0ZSBiZWZvcmUgY2hhcnQgaW5pdGlhbGl6YXRpb24uIENhbiBiZSBhIGZ1bmN0aW9uLCBjb2RlIHdyYXBwZWQgaW4gYSBmdW5jdGlvbiwgb3IgYSAuanMgZmlsZW5hbWUnLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ3RleHQnXHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICBjYWxsYmFjazoge1xyXG4gICAgICB2YWx1ZTogbnVsbCxcclxuICAgICAgdHlwZXM6IFsnc3RyaW5nJywgJ251bGwnXSxcclxuICAgICAgZW52TGluazogJ0NVU1RPTV9MT0dJQ19DQUxMQkFDSycsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdKYXZhU2NyaXB0IGNvZGUgdG8gcnVuIGR1cmluZyBjb25zdHJ1Y3Rpb24uIENhbiBiZSBhIGZ1bmN0aW9uIG9yIGEgLmpzIGZpbGVuYW1lJyxcclxuICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgIHR5cGU6ICd0ZXh0J1xyXG4gICAgICB9XHJcbiAgICB9LFxyXG4gICAgcmVzb3VyY2VzOiB7XHJcbiAgICAgIHZhbHVlOiBudWxsLFxyXG4gICAgICB0eXBlczogWydPYmplY3QnLCAnc3RyaW5nJywgJ251bGwnXSxcclxuICAgICAgZW52TGluazogJ0NVU1RPTV9MT0dJQ19SRVNPVVJDRVMnLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnQWRkaXRpb25hbCByZXNvdXJjZXMgYXMgSlNPTiwgc3RyaW5naWZpZWQgSlNPTiwgb3IgZmlsZW5hbWUsIGNvbnRhaW5pbmcgZmlsZXMsIGpzLCBhbmQgY3NzIHNlY3Rpb25zJyxcclxuICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgIHR5cGU6ICd0ZXh0J1xyXG4gICAgICB9XHJcbiAgICB9LFxyXG4gICAgbG9hZENvbmZpZzoge1xyXG4gICAgICB2YWx1ZTogbnVsbCxcclxuICAgICAgdHlwZXM6IFsnc3RyaW5nJywgJ251bGwnXSxcclxuICAgICAgZW52TGluazogJ0NVU1RPTV9MT0dJQ19MT0FEX0NPTkZJRycsXHJcbiAgICAgIGxlZ2FjeU5hbWU6ICdmcm9tRmlsZScsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnRmlsZSB3aXRoIGEgcHJlLWRlZmluZWQgY29uZmlndXJhdGlvbiB0byB1c2UnLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ3RleHQnXHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICBjcmVhdGVDb25maWc6IHtcclxuICAgICAgdmFsdWU6IG51bGwsXHJcbiAgICAgIHR5cGVzOiBbJ3N0cmluZycsICdudWxsJ10sXHJcbiAgICAgIGVudkxpbms6ICdDVVNUT01fTE9HSUNfQ1JFQVRFX0NPTkZJRycsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdQcm9tcHQtYmFzZWQgb3B0aW9uIHNldHRpbmcsIHNhdmVkIHRvIGEgcHJvdmlkZWQgY29uZmlnIGZpbGUnLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ3RleHQnXHJcbiAgICAgIH1cclxuICAgIH1cclxuICB9LFxyXG4gIHNlcnZlcjoge1xyXG4gICAgZW5hYmxlOiB7XHJcbiAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgdHlwZXM6IFsnYm9vbGVhbiddLFxyXG4gICAgICBlbnZMaW5rOiAnU0VSVkVSX0VOQUJMRScsXHJcbiAgICAgIGNsaU5hbWU6ICdlbmFibGVTZXJ2ZXInLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ1N0YXJ0cyB0aGUgc2VydmVyIHdoZW4gdHJ1ZScsXHJcbiAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICB0eXBlOiAndG9nZ2xlJ1xyXG4gICAgICB9XHJcbiAgICB9LFxyXG4gICAgaG9zdDoge1xyXG4gICAgICB2YWx1ZTogJzAuMC4wLjAnLFxyXG4gICAgICB0eXBlczogWydzdHJpbmcnXSxcclxuICAgICAgZW52TGluazogJ1NFUlZFUl9IT1NUJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdIb3N0bmFtZSBvZiB0aGUgc2VydmVyJyxcclxuICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgIHR5cGU6ICd0ZXh0J1xyXG4gICAgICB9XHJcbiAgICB9LFxyXG4gICAgcG9ydDoge1xyXG4gICAgICB2YWx1ZTogNzgwMSxcclxuICAgICAgdHlwZXM6IFsnbnVtYmVyJ10sXHJcbiAgICAgIGVudkxpbms6ICdTRVJWRVJfUE9SVCcsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnUG9ydCBudW1iZXIgZm9yIHRoZSBzZXJ2ZXInLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ251bWJlcidcclxuICAgICAgfVxyXG4gICAgfSxcclxuICAgIHVwbG9hZExpbWl0OiB7XHJcbiAgICAgIHZhbHVlOiAzLFxyXG4gICAgICB0eXBlczogWydudW1iZXInXSxcclxuICAgICAgZW52TGluazogJ1NFUlZFUl9VUExPQURfTElNSVQnLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ01heGltdW0gcmVxdWVzdCBib2R5IHNpemUgaW4gTUInLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ251bWJlcidcclxuICAgICAgfVxyXG4gICAgfSxcclxuICAgIGJlbmNobWFya2luZzoge1xyXG4gICAgICB2YWx1ZTogZmFsc2UsXHJcbiAgICAgIHR5cGVzOiBbJ2Jvb2xlYW4nXSxcclxuICAgICAgZW52TGluazogJ1NFUlZFUl9CRU5DSE1BUktJTkcnLFxyXG4gICAgICBjbGlOYW1lOiAnc2VydmVyQmVuY2htYXJraW5nJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ0Rpc3BsYXlzIG9yIG5vdCBhY3Rpb24gZHVyYXRpb25zIGluIG1pbGxpc2Vjb25kcyBkdXJpbmcgc2VydmVyIHJlcXVlc3RzJyxcclxuICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgIHR5cGU6ICd0b2dnbGUnXHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICBwcm94eToge1xyXG4gICAgICBob3N0OiB7XHJcbiAgICAgICAgdmFsdWU6IG51bGwsXHJcbiAgICAgICAgdHlwZXM6IFsnc3RyaW5nJywgJ251bGwnXSxcclxuICAgICAgICBlbnZMaW5rOiAnU0VSVkVSX1BST1hZX0hPU1QnLFxyXG4gICAgICAgIGNsaU5hbWU6ICdwcm94eUhvc3QnLFxyXG4gICAgICAgIGRlc2NyaXB0aW9uOiAnSG9zdCBvZiB0aGUgcHJveHkgc2VydmVyLCBpZiBhcHBsaWNhYmxlJyxcclxuICAgICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgICB0eXBlOiAndGV4dCdcclxuICAgICAgICB9XHJcbiAgICAgIH0sXHJcbiAgICAgIHBvcnQ6IHtcclxuICAgICAgICB2YWx1ZTogbnVsbCxcclxuICAgICAgICB0eXBlczogWydudW1iZXInLCAnbnVsbCddLFxyXG4gICAgICAgIGVudkxpbms6ICdTRVJWRVJfUFJPWFlfUE9SVCcsXHJcbiAgICAgICAgY2xpTmFtZTogJ3Byb3h5UG9ydCcsXHJcbiAgICAgICAgZGVzY3JpcHRpb246ICdQb3J0IG9mIHRoZSBwcm94eSBzZXJ2ZXIsIGlmIGFwcGxpY2FibGUnLFxyXG4gICAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICAgIHR5cGU6ICdudW1iZXInXHJcbiAgICAgICAgfVxyXG4gICAgICB9LFxyXG4gICAgICB0aW1lb3V0OiB7XHJcbiAgICAgICAgdmFsdWU6IDUwMDAsXHJcbiAgICAgICAgdHlwZXM6IFsnbnVtYmVyJ10sXHJcbiAgICAgICAgZW52TGluazogJ1NFUlZFUl9QUk9YWV9USU1FT1VUJyxcclxuICAgICAgICBjbGlOYW1lOiAncHJveHlUaW1lb3V0JyxcclxuICAgICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAgICdUaW1lb3V0IGluIG1pbGxpc2Vjb25kcyBmb3IgdGhlIHByb3h5IHNlcnZlciwgaWYgYXBwbGljYWJsZScsXHJcbiAgICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgICAgdHlwZTogJ251bWJlcidcclxuICAgICAgICB9XHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICByYXRlTGltaXRpbmc6IHtcclxuICAgICAgZW5hYmxlOiB7XHJcbiAgICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICAgIHR5cGVzOiBbJ2Jvb2xlYW4nXSxcclxuICAgICAgICBlbnZMaW5rOiAnU0VSVkVSX1JBVEVfTElNSVRJTkdfRU5BQkxFJyxcclxuICAgICAgICBjbGlOYW1lOiAnZW5hYmxlUmF0ZUxpbWl0aW5nJyxcclxuICAgICAgICBkZXNjcmlwdGlvbjogJ0VuYWJsZXMgb3IgZGlzYWJsZXMgcmF0ZSBsaW1pdGluZyBvbiB0aGUgc2VydmVyJyxcclxuICAgICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgICB0eXBlOiAndG9nZ2xlJ1xyXG4gICAgICAgIH1cclxuICAgICAgfSxcclxuICAgICAgbWF4UmVxdWVzdHM6IHtcclxuICAgICAgICB2YWx1ZTogMTAsXHJcbiAgICAgICAgdHlwZXM6IFsnbnVtYmVyJ10sXHJcbiAgICAgICAgZW52TGluazogJ1NFUlZFUl9SQVRFX0xJTUlUSU5HX01BWF9SRVFVRVNUUycsXHJcbiAgICAgICAgbGVnYWN5TmFtZTogJ3JhdGVMaW1pdCcsXHJcbiAgICAgICAgZGVzY3JpcHRpb246ICdNYXhpbXVtIG51bWJlciBvZiByZXF1ZXN0cyBhbGxvd2VkIHBlciBtaW51dGUnLFxyXG4gICAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICAgIHR5cGU6ICdudW1iZXInXHJcbiAgICAgICAgfVxyXG4gICAgICB9LFxyXG4gICAgICB3aW5kb3c6IHtcclxuICAgICAgICB2YWx1ZTogMSxcclxuICAgICAgICB0eXBlczogWydudW1iZXInXSxcclxuICAgICAgICBlbnZMaW5rOiAnU0VSVkVSX1JBVEVfTElNSVRJTkdfV0lORE9XJyxcclxuICAgICAgICBkZXNjcmlwdGlvbjogJ1RpbWUgd2luZG93IGluIG1pbnV0ZXMgZm9yIHJhdGUgbGltaXRpbmcnLFxyXG4gICAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICAgIHR5cGU6ICdudW1iZXInXHJcbiAgICAgICAgfVxyXG4gICAgICB9LFxyXG4gICAgICBkZWxheToge1xyXG4gICAgICAgIHZhbHVlOiAwLFxyXG4gICAgICAgIHR5cGVzOiBbJ251bWJlciddLFxyXG4gICAgICAgIGVudkxpbms6ICdTRVJWRVJfUkFURV9MSU1JVElOR19ERUxBWScsXHJcbiAgICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgICAnRGVsYXkgZHVyYXRpb24gYmV0d2VlbiBzdWNjZXNzaXZlIHJlcXVlc3RzIGJlZm9yZSByZWFjaGluZyB0aGUgbGltaXQnLFxyXG4gICAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICAgIHR5cGU6ICdudW1iZXInXHJcbiAgICAgICAgfVxyXG4gICAgICB9LFxyXG4gICAgICB0cnVzdFByb3h5OiB7XHJcbiAgICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICAgIHR5cGVzOiBbJ2Jvb2xlYW4nXSxcclxuICAgICAgICBlbnZMaW5rOiAnU0VSVkVSX1JBVEVfTElNSVRJTkdfVFJVU1RfUFJPWFknLFxyXG4gICAgICAgIGRlc2NyaXB0aW9uOiAnU2V0IHRvIHRydWUgaWYgdGhlIHNlcnZlciBpcyBiZWhpbmQgYSBsb2FkIGJhbGFuY2VyJyxcclxuICAgICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgICB0eXBlOiAndG9nZ2xlJ1xyXG4gICAgICAgIH1cclxuICAgICAgfSxcclxuICAgICAgc2tpcEtleToge1xyXG4gICAgICAgIHZhbHVlOiBudWxsLFxyXG4gICAgICAgIHR5cGVzOiBbJ3N0cmluZycsICdudWxsJ10sXHJcbiAgICAgICAgZW52TGluazogJ1NFUlZFUl9SQVRFX0xJTUlUSU5HX1NLSVBfS0VZJyxcclxuICAgICAgICBkZXNjcmlwdGlvbjogJ0tleSB0byBieXBhc3MgdGhlIHJhdGUgbGltaXRlciwgdXNlZCB3aXRoIGBza2lwVG9rZW5gJyxcclxuICAgICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgICB0eXBlOiAndGV4dCdcclxuICAgICAgICB9XHJcbiAgICAgIH0sXHJcbiAgICAgIHNraXBUb2tlbjoge1xyXG4gICAgICAgIHZhbHVlOiBudWxsLFxyXG4gICAgICAgIHR5cGVzOiBbJ3N0cmluZycsICdudWxsJ10sXHJcbiAgICAgICAgZW52TGluazogJ1NFUlZFUl9SQVRFX0xJTUlUSU5HX1NLSVBfVE9LRU4nLFxyXG4gICAgICAgIGRlc2NyaXB0aW9uOiAnVG9rZW4gdG8gYnlwYXNzIHRoZSByYXRlIGxpbWl0ZXIsIHVzZWQgd2l0aCBgc2tpcEtleWAnLFxyXG4gICAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICAgIHR5cGU6ICd0ZXh0J1xyXG4gICAgICAgIH1cclxuICAgICAgfVxyXG4gICAgfSxcclxuICAgIHNzbDoge1xyXG4gICAgICBlbmFibGU6IHtcclxuICAgICAgICB2YWx1ZTogZmFsc2UsXHJcbiAgICAgICAgdHlwZXM6IFsnYm9vbGVhbiddLFxyXG4gICAgICAgIGVudkxpbms6ICdTRVJWRVJfU1NMX0VOQUJMRScsXHJcbiAgICAgICAgY2xpTmFtZTogJ2VuYWJsZVNzbCcsXHJcbiAgICAgICAgZGVzY3JpcHRpb246ICdFbmFibGVzIG9yIGRpc2FibGVzIFNTTCBwcm90b2NvbCcsXHJcbiAgICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgICAgdHlwZTogJ3RvZ2dsZSdcclxuICAgICAgICB9XHJcbiAgICAgIH0sXHJcbiAgICAgIGZvcmNlOiB7XHJcbiAgICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICAgIHR5cGVzOiBbJ2Jvb2xlYW4nXSxcclxuICAgICAgICBlbnZMaW5rOiAnU0VSVkVSX1NTTF9GT1JDRScsXHJcbiAgICAgICAgY2xpTmFtZTogJ3NzbEZvcmNlJyxcclxuICAgICAgICBsZWdhY3lOYW1lOiAnc3NsT25seScsXHJcbiAgICAgICAgZGVzY3JpcHRpb246ICdGb3JjZXMgdGhlIHNlcnZlciB0byB1c2UgSFRUUFMgb25seSB3aGVuIHRydWUnLFxyXG4gICAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICAgIHR5cGU6ICd0b2dnbGUnXHJcbiAgICAgICAgfVxyXG4gICAgICB9LFxyXG4gICAgICBwb3J0OiB7XHJcbiAgICAgICAgdmFsdWU6IDQ0MyxcclxuICAgICAgICB0eXBlczogWydudW1iZXInXSxcclxuICAgICAgICBlbnZMaW5rOiAnU0VSVkVSX1NTTF9QT1JUJyxcclxuICAgICAgICBjbGlOYW1lOiAnc3NsUG9ydCcsXHJcbiAgICAgICAgZGVzY3JpcHRpb246ICdQb3J0IGZvciB0aGUgU1NMIHNlcnZlcicsXHJcbiAgICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgICAgdHlwZTogJ251bWJlcidcclxuICAgICAgICB9XHJcbiAgICAgIH0sXHJcbiAgICAgIGNlcnRQYXRoOiB7XHJcbiAgICAgICAgdmFsdWU6IG51bGwsXHJcbiAgICAgICAgdHlwZXM6IFsnc3RyaW5nJywgJ251bGwnXSxcclxuICAgICAgICBlbnZMaW5rOiAnU0VSVkVSX1NTTF9DRVJUX1BBVEgnLFxyXG4gICAgICAgIGNsaU5hbWU6ICdzc2xDZXJ0UGF0aCcsXHJcbiAgICAgICAgbGVnYWN5TmFtZTogJ3NzbFBhdGgnLFxyXG4gICAgICAgIGRlc2NyaXB0aW9uOiAnUGF0aCB0byB0aGUgU1NMIGNlcnRpZmljYXRlL2tleSBmaWxlJyxcclxuICAgICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgICB0eXBlOiAndGV4dCdcclxuICAgICAgICB9XHJcbiAgICAgIH1cclxuICAgIH1cclxuICB9LFxyXG4gIHBvb2w6IHtcclxuICAgIG1pbldvcmtlcnM6IHtcclxuICAgICAgdmFsdWU6IDQsXHJcbiAgICAgIHR5cGVzOiBbJ251bWJlciddLFxyXG4gICAgICBlbnZMaW5rOiAnUE9PTF9NSU5fV09SS0VSUycsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnTWluaW11bSBhbmQgaW5pdGlhbCBudW1iZXIgb2YgcG9vbCB3b3JrZXJzIHRvIHNwYXduJyxcclxuICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgIHR5cGU6ICdudW1iZXInXHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICBtYXhXb3JrZXJzOiB7XHJcbiAgICAgIHZhbHVlOiA4LFxyXG4gICAgICB0eXBlczogWydudW1iZXInXSxcclxuICAgICAgZW52TGluazogJ1BPT0xfTUFYX1dPUktFUlMnLFxyXG4gICAgICBsZWdhY3lOYW1lOiAnd29ya2VycycsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnTWF4aW11bSBudW1iZXIgb2YgcG9vbCB3b3JrZXJzIHRvIHNwYXduJyxcclxuICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgIHR5cGU6ICdudW1iZXInXHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICB3b3JrTGltaXQ6IHtcclxuICAgICAgdmFsdWU6IDQwLFxyXG4gICAgICB0eXBlczogWydudW1iZXInXSxcclxuICAgICAgZW52TGluazogJ1BPT0xfV09SS19MSU1JVCcsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnTnVtYmVyIG9mIHRhc2tzIGEgd29ya2VyIGNhbiBoYW5kbGUgYmVmb3JlIHJlc3RhcnRpbmcnLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ251bWJlcidcclxuICAgICAgfVxyXG4gICAgfSxcclxuICAgIGFjcXVpcmVUaW1lb3V0OiB7XHJcbiAgICAgIHZhbHVlOiA1MDAwLFxyXG4gICAgICB0eXBlczogWydudW1iZXInXSxcclxuICAgICAgZW52TGluazogJ1BPT0xfQUNRVUlSRV9USU1FT1VUJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdUaW1lb3V0IGluIG1pbGxpc2Vjb25kcyBmb3IgYWNxdWlyaW5nIGEgcmVzb3VyY2UnLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ251bWJlcidcclxuICAgICAgfVxyXG4gICAgfSxcclxuICAgIGNyZWF0ZVRpbWVvdXQ6IHtcclxuICAgICAgdmFsdWU6IDUwMDAsXHJcbiAgICAgIHR5cGVzOiBbJ251bWJlciddLFxyXG4gICAgICBlbnZMaW5rOiAnUE9PTF9DUkVBVEVfVElNRU9VVCcsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnVGltZW91dCBpbiBtaWxsaXNlY29uZHMgZm9yIGNyZWF0aW5nIGEgcmVzb3VyY2UnLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ251bWJlcidcclxuICAgICAgfVxyXG4gICAgfSxcclxuICAgIGRlc3Ryb3lUaW1lb3V0OiB7XHJcbiAgICAgIHZhbHVlOiA1MDAwLFxyXG4gICAgICB0eXBlczogWydudW1iZXInXSxcclxuICAgICAgZW52TGluazogJ1BPT0xfREVTVFJPWV9USU1FT1VUJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdUaW1lb3V0IGluIG1pbGxpc2Vjb25kcyBmb3IgZGVzdHJveWluZyBhIHJlc291cmNlJyxcclxuICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgIHR5cGU6ICdudW1iZXInXHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICBpZGxlVGltZW91dDoge1xyXG4gICAgICB2YWx1ZTogMzAwMDAsXHJcbiAgICAgIHR5cGVzOiBbJ251bWJlciddLFxyXG4gICAgICBlbnZMaW5rOiAnUE9PTF9JRExFX1RJTUVPVVQnLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ1RpbWVvdXQgaW4gbWlsbGlzZWNvbmRzIGZvciBkZXN0cm95aW5nIGlkbGUgcmVzb3VyY2VzJyxcclxuICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgIHR5cGU6ICdudW1iZXInXHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICBjcmVhdGVSZXRyeUludGVydmFsOiB7XHJcbiAgICAgIHZhbHVlOiAyMDAsXHJcbiAgICAgIHR5cGVzOiBbJ251bWJlciddLFxyXG4gICAgICBlbnZMaW5rOiAnUE9PTF9DUkVBVEVfUkVUUllfSU5URVJWQUwnLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnSW50ZXJ2YWwgaW4gbWlsbGlzZWNvbmRzIGJlZm9yZSByZXRyeWluZyByZXNvdXJjZSBjcmVhdGlvbiBvbiBmYWlsdXJlJyxcclxuICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgIHR5cGU6ICdudW1iZXInXHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICByZWFwZXJJbnRlcnZhbDoge1xyXG4gICAgICB2YWx1ZTogMTAwMCxcclxuICAgICAgdHlwZXM6IFsnbnVtYmVyJ10sXHJcbiAgICAgIGVudkxpbms6ICdQT09MX1JFQVBFUl9JTlRFUlZBTCcsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdJbnRlcnZhbCBpbiBtaWxsaXNlY29uZHMgdG8gY2hlY2sgYW5kIGRlc3Ryb3kgaWRsZSByZXNvdXJjZXMnLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ251bWJlcidcclxuICAgICAgfVxyXG4gICAgfSxcclxuICAgIGJlbmNobWFya2luZzoge1xyXG4gICAgICB2YWx1ZTogZmFsc2UsXHJcbiAgICAgIHR5cGVzOiBbJ2Jvb2xlYW4nXSxcclxuICAgICAgZW52TGluazogJ1BPT0xfQkVOQ0hNQVJLSU5HJyxcclxuICAgICAgY2xpTmFtZTogJ3Bvb2xCZW5jaG1hcmtpbmcnLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ1Nob3dzIHN0YXRpc3RpY3MgZm9yIHRoZSBwb29sIG9mIHJlc291cmNlcycsXHJcbiAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICB0eXBlOiAndG9nZ2xlJ1xyXG4gICAgICB9XHJcbiAgICB9XHJcbiAgfSxcclxuICBsb2dnaW5nOiB7XHJcbiAgICBsZXZlbDoge1xyXG4gICAgICB2YWx1ZTogNCxcclxuICAgICAgdHlwZXM6IFsnbnVtYmVyJ10sXHJcbiAgICAgIGVudkxpbms6ICdMT0dHSU5HX0xFVkVMJyxcclxuICAgICAgY2xpTmFtZTogJ2xvZ0xldmVsJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdMb2dnaW5nIHZlcmJvc2l0eSBsZXZlbCcsXHJcbiAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgICByb3VuZDogMCxcclxuICAgICAgICBtaW46IDAsXHJcbiAgICAgICAgbWF4OiA1XHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICBmaWxlOiB7XHJcbiAgICAgIHZhbHVlOiAnaGlnaGNoYXJ0cy1leHBvcnQtc2VydmVyLmxvZycsXHJcbiAgICAgIHR5cGVzOiBbJ3N0cmluZyddLFxyXG4gICAgICBlbnZMaW5rOiAnTE9HR0lOR19GSUxFJyxcclxuICAgICAgY2xpTmFtZTogJ2xvZ0ZpbGUnLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnTG9nIGZpbGUgbmFtZS4gUmVxdWlyZXMgYGxvZ1RvRmlsZWAgYW5kIGBsb2dEZXN0YCB0byBiZSBzZXQnLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ3RleHQnXHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICBkZXN0OiB7XHJcbiAgICAgIHZhbHVlOiAnbG9nJyxcclxuICAgICAgdHlwZXM6IFsnc3RyaW5nJ10sXHJcbiAgICAgIGVudkxpbms6ICdMT0dHSU5HX0RFU1QnLFxyXG4gICAgICBjbGlOYW1lOiAnbG9nRGVzdCcsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnUGF0aCB0byBzdG9yZSBsb2cgZmlsZXMuIFJlcXVpcmVzIGBsb2dUb0ZpbGVgIHRvIGJlIHNldCcsXHJcbiAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICB0eXBlOiAndGV4dCdcclxuICAgICAgfVxyXG4gICAgfSxcclxuICAgIHRvQ29uc29sZToge1xyXG4gICAgICB2YWx1ZTogdHJ1ZSxcclxuICAgICAgdHlwZXM6IFsnYm9vbGVhbiddLFxyXG4gICAgICBlbnZMaW5rOiAnTE9HR0lOR19UT19DT05TT0xFJyxcclxuICAgICAgY2xpTmFtZTogJ2xvZ1RvQ29uc29sZScsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnRW5hYmxlcyBvciBkaXNhYmxlcyBjb25zb2xlIGxvZ2dpbmcnLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ3RvZ2dsZSdcclxuICAgICAgfVxyXG4gICAgfSxcclxuICAgIHRvRmlsZToge1xyXG4gICAgICB2YWx1ZTogdHJ1ZSxcclxuICAgICAgdHlwZXM6IFsnYm9vbGVhbiddLFxyXG4gICAgICBlbnZMaW5rOiAnTE9HR0lOR19UT19GSUxFJyxcclxuICAgICAgY2xpTmFtZTogJ2xvZ1RvRmlsZScsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnRW5hYmxlcyBvciBkaXNhYmxlcyBsb2dnaW5nIHRvIGEgZmlsZScsXHJcbiAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICB0eXBlOiAndG9nZ2xlJ1xyXG4gICAgICB9XHJcbiAgICB9XHJcbiAgfSxcclxuICB1aToge1xyXG4gICAgZW5hYmxlOiB7XHJcbiAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgdHlwZXM6IFsnYm9vbGVhbiddLFxyXG4gICAgICBlbnZMaW5rOiAnVUlfRU5BQkxFJyxcclxuICAgICAgY2xpTmFtZTogJ2VuYWJsZVVpJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdFbmFibGVzIG9yIGRpc2FibGVzIHRoZSBVSSBmb3IgdGhlIGV4cG9ydCBzZXJ2ZXInLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ3RvZ2dsZSdcclxuICAgICAgfVxyXG4gICAgfSxcclxuICAgIHJvdXRlOiB7XHJcbiAgICAgIHZhbHVlOiAnLycsXHJcbiAgICAgIHR5cGVzOiBbJ3N0cmluZyddLFxyXG4gICAgICBlbnZMaW5rOiAnVUlfUk9VVEUnLFxyXG4gICAgICBjbGlOYW1lOiAndWlSb3V0ZScsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnVGhlIGVuZHBvaW50IHJvdXRlIGZvciB0aGUgVUknLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ3RleHQnXHJcbiAgICAgIH1cclxuICAgIH1cclxuICB9LFxyXG4gIG90aGVyOiB7XHJcbiAgICBub2RlRW52OiB7XHJcbiAgICAgIHZhbHVlOiAncHJvZHVjdGlvbicsXHJcbiAgICAgIHR5cGVzOiBbJ3N0cmluZyddLFxyXG4gICAgICBlbnZMaW5rOiAnT1RIRVJfTk9ERV9FTlYnLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ1RoZSBOb2RlLmpzIGVudmlyb25tZW50IHR5cGUnLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ3RleHQnXHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICBsaXN0ZW5Ub1Byb2Nlc3NFeGl0czoge1xyXG4gICAgICB2YWx1ZTogdHJ1ZSxcclxuICAgICAgdHlwZXM6IFsnYm9vbGVhbiddLFxyXG4gICAgICBlbnZMaW5rOiAnT1RIRVJfTElTVEVOX1RPX1BST0NFU1NfRVhJVFMnLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ1doZXRoZXIgb3Igbm90IHRvIGF0dGFjaCBwcm9jZXNzLmV4aXQgaGFuZGxlcnMnLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ3RvZ2dsZSdcclxuICAgICAgfVxyXG4gICAgfSxcclxuICAgIG5vTG9nbzoge1xyXG4gICAgICB2YWx1ZTogZmFsc2UsXHJcbiAgICAgIHR5cGVzOiBbJ2Jvb2xlYW4nXSxcclxuICAgICAgZW52TGluazogJ09USEVSX05PX0xPR08nLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ0Rpc3BsYXkgb3Igc2tpcCBwcmludGluZyB0aGUgbG9nbyBvbiBzdGFydHVwJyxcclxuICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgIHR5cGU6ICd0b2dnbGUnXHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICBoYXJkUmVzZXRQYWdlOiB7XHJcbiAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgdHlwZXM6IFsnYm9vbGVhbiddLFxyXG4gICAgICBlbnZMaW5rOiAnT1RIRVJfSEFSRF9SRVNFVF9QQUdFJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdXaGV0aGVyIG9yIG5vdCB0byByZXNldCB0aGUgcGFnZSBjb250ZW50IGVudGlyZWx5JyxcclxuICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgIHR5cGU6ICd0b2dnbGUnXHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICBicm93c2VyU2hlbGxNb2RlOiB7XHJcbiAgICAgIHZhbHVlOiB0cnVlLFxyXG4gICAgICB0eXBlczogWydib29sZWFuJ10sXHJcbiAgICAgIGVudkxpbms6ICdPVEhFUl9CUk9XU0VSX1NIRUxMX01PREUnLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ1doZXRoZXIgb3Igbm90IHRvIHNldCB0aGUgYnJvd3NlciB0byBydW4gaW4gc2hlbGwgbW9kZScsXHJcbiAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICB0eXBlOiAndG9nZ2xlJ1xyXG4gICAgICB9XHJcbiAgICB9LFxyXG4gICAgdmFsaWRhdGlvbjoge1xyXG4gICAgICB2YWx1ZTogdHJ1ZSxcclxuICAgICAgdHlwZXM6IFsnYm9vbGVhbiddLFxyXG4gICAgICBlbnZMaW5rOiAnT1RIRVJfVkFMSURBVElPTicsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnV2hldGhlciBvciBub3QgdG8gZW5hYmxlIHZhbGlkYXRpb24gb2Ygb3B0aW9ucyB0eXBlcycsXHJcbiAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICB0eXBlOiAndG9nZ2xlJ1xyXG4gICAgICB9XHJcbiAgICB9XHJcbiAgfSxcclxuICBkZWJ1Zzoge1xyXG4gICAgZW5hYmxlOiB7XHJcbiAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgdHlwZXM6IFsnYm9vbGVhbiddLFxyXG4gICAgICBlbnZMaW5rOiAnREVCVUdfRU5BQkxFJyxcclxuICAgICAgY2xpTmFtZTogJ2VuYWJsZURlYnVnJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdFbmFibGVzIG9yIGRpc2FibGVzIGRlYnVnIG1vZGUgZm9yIHRoZSB1bmRlcmx5aW5nIGJyb3dzZXInLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ3RvZ2dsZSdcclxuICAgICAgfVxyXG4gICAgfSxcclxuICAgIGhlYWRsZXNzOiB7XHJcbiAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgdHlwZXM6IFsnYm9vbGVhbiddLFxyXG4gICAgICBlbnZMaW5rOiAnREVCVUdfSEVBRExFU1MnLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnV2hldGhlciBvciBub3QgdG8gc2V0IHRoZSBicm93c2VyIHRvIHJ1biBpbiBoZWFkbGVzcyBtb2RlIGR1cmluZyBkZWJ1Z2dpbmcnLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ3RvZ2dsZSdcclxuICAgICAgfVxyXG4gICAgfSxcclxuICAgIGRldnRvb2xzOiB7XHJcbiAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgdHlwZXM6IFsnYm9vbGVhbiddLFxyXG4gICAgICBlbnZMaW5rOiAnREVCVUdfREVWVE9PTFMnLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ0VuYWJsZXMgb3IgZGlzYWJsZXMgRGV2VG9vbHMgaW4gaGVhZGZ1bCBtb2RlJyxcclxuICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgIHR5cGU6ICd0b2dnbGUnXHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICBsaXN0ZW5Ub0NvbnNvbGU6IHtcclxuICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICB0eXBlczogWydib29sZWFuJ10sXHJcbiAgICAgIGVudkxpbms6ICdERUJVR19MSVNURU5fVE9fQ09OU09MRScsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdFbmFibGVzIG9yIGRpc2FibGVzIGxpc3RlbmluZyB0byBjb25zb2xlIG1lc3NhZ2VzIGZyb20gdGhlIGJyb3dzZXInLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ3RvZ2dsZSdcclxuICAgICAgfVxyXG4gICAgfSxcclxuICAgIGR1bXBpbzoge1xyXG4gICAgICB2YWx1ZTogZmFsc2UsXHJcbiAgICAgIHR5cGVzOiBbJ2Jvb2xlYW4nXSxcclxuICAgICAgZW52TGluazogJ0RFQlVHX0RVTVBJTycsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdSZWRpcmVjdHMgb3Igbm90IGJyb3dzZXIgc3Rkb3V0IGFuZCBzdGRlcnIgdG8gcHJvY2Vzcy5zdGRvdXQgYW5kIHByb2Nlc3Muc3RkZXJyJyxcclxuICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgIHR5cGU6ICd0b2dnbGUnXHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICBzbG93TW86IHtcclxuICAgICAgdmFsdWU6IDAsXHJcbiAgICAgIHR5cGVzOiBbJ251bWJlciddLFxyXG4gICAgICBlbnZMaW5rOiAnREVCVUdfU0xPV19NTycsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnRGVsYXlzIFB1cHBldGVlciBvcGVyYXRpb25zIGJ5IHRoZSBzcGVjaWZpZWQgbWlsbGlzZWNvbmRzJyxcclxuICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgIHR5cGU6ICdudW1iZXInXHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICBkZWJ1Z2dpbmdQb3J0OiB7XHJcbiAgICAgIHZhbHVlOiA5MjIyLFxyXG4gICAgICB0eXBlczogWydudW1iZXInXSxcclxuICAgICAgZW52TGluazogJ0RFQlVHX0RFQlVHR0lOR19QT1JUJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdQb3J0IHVzZWQgZm9yIGRlYnVnZ2luZycsXHJcbiAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICB0eXBlOiAnbnVtYmVyJ1xyXG4gICAgICB9XHJcbiAgICB9XHJcbiAgfVxyXG59O1xyXG5cclxuZXhwb3J0IGRlZmF1bHQgZGVmYXVsdENvbmZpZztcclxuIiwiLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcclxuXHJcbkhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlclxyXG5cclxuQ29weXJpZ2h0IChjKSAyMDE2LTIwMjUsIEhpZ2hzb2Z0XHJcblxyXG5MaWNlbmNlZCB1bmRlciB0aGUgTUlUIGxpY2VuY2UuXHJcblxyXG5BZGRpdGlvbmFsbHkgYSB2YWxpZCBIaWdoY2hhcnRzIGxpY2Vuc2UgaXMgcmVxdWlyZWQgZm9yIHVzZS5cclxuXHJcblNlZSBMSUNFTlNFIGZpbGUgaW4gcm9vdCBmb3IgZGV0YWlscy5cclxuXHJcbioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXHJcblxyXG4vKipcclxuICogQG92ZXJ2aWV3IFRoaXMgZmlsZSBoYW5kbGVzIHBhcnNpbmcgYW5kIHZhbGlkYXRpbmcgb3B0aW9ucyBmcm9tIG11bHRpcGxlXHJcbiAqIHNvdXJjZXMgKHRoZSBjb25maWcgZmlsZSwgY3VzdG9tIEpTT04sIGVudmlyb25tZW50IHZhcmlhYmxlcywgQ0xJIGFyZ3VtZW50cyxcclxuICogYW5kIHJlcXVlc3QgcGF5bG9hZCkgdXNpbmcgdGhlICd6b2QnIGxpYnJhcnkuXHJcbiAqXHJcbiAqIEVudmlyb25tZW50IHZhcmlhYmxlcyBhcmUgcGFyc2VkIGFuZCB2YWxpZGF0ZWQgb25seSBvbmNlIGF0IGFwcGxpY2F0aW9uXHJcbiAqIHN0YXJ0dXAsIGFuZCB0aGUgdmFsaWRhdGVkIHJlc3VsdHMgYXJlIGV4cG9ydGVkIGFzIGBlbnZzYCBmb3IgdXNlIHRocm91Z2hvdXRcclxuICogdGhlIGFwcGxpY2F0aW9uLlxyXG4gKlxyXG4gKiBPcHRpb25zIGZyb20gb3RoZXIgc291cmNlcywgaG93ZXZlciwgYXJlIHBhcnNlZCBhbmQgdmFsaWRhdGVkIG9uIGRlbWFuZCxcclxuICogZWFjaCB0aW1lIGFuIGV4cG9ydCBpcyBhdHRlbXB0ZWQuXHJcbiAqL1xyXG5cclxuaW1wb3J0IGRvdGVudiBmcm9tICdkb3RlbnYnO1xyXG5pbXBvcnQgeyB6IH0gZnJvbSAnem9kJztcclxuXHJcbmltcG9ydCBkZWZhdWx0Q29uZmlnIGZyb20gJy4vc2NoZW1hcy9jb25maWcuanMnO1xyXG5cclxuLy8gTG9hZCB0aGUgLmVudiBpbnRvIGVudmlyb25tZW50IHZhcmlhYmxlc1xyXG5kb3RlbnYuY29uZmlnKCk7XHJcblxyXG4vLyBHZXQgc2NyaXB0cyBuYW1lcyBvZiBlYWNoIGNhdGVnb3J5IGZyb20gdGhlIGRlZmF1bHQgY29uZmlnXHJcbmNvbnN0IHsgY29yZVNjcmlwdHMsIG1vZHVsZVNjcmlwdHMsIGluZGljYXRvclNjcmlwdHMgfSA9XHJcbiAgZGVmYXVsdENvbmZpZy5oaWdoY2hhcnRzO1xyXG5cclxuLy8gU2V0cyB0aGUgY3VzdG9tIGVycm9yIG1hcCBnbG9iYWxseVxyXG56LnNldEVycm9yTWFwKF9jdXN0b21FcnJvck1hcCk7XHJcblxyXG4vKipcclxuICogT2JqZWN0IGNvbnRhaW5pbmcgY3VzdG9tIGdlbmVyYWwgdmFsaWRhdG9ycyBhbmQgcGFyc2VycyB0byBhdm9pZCByZXBldGl0aW9uXHJcbiAqIGluIHNjaGVtYSBvYmplY3RzLiBBbGwgdmFsaWRhdG9ycyBhcHBseSB0byB2YWx1ZXMgZnJvbSB2YXJpb3VzIHNvdXJjZXMsXHJcbiAqIGluY2x1ZGluZyB0aGUgZGVmYXVsdCBjb25maWcgZmlsZSwgYSBjdXN0b20gSlNPTiBmaWxlIGxvYWRlZCB3aXRoIHRoZSBvcHRpb25cclxuICogY2FsbGVkIGBsb2FkQ29uZmlnYCwgdGhlIC5lbnYgZmlsZSwgQ0xJIGFyZ3VtZW50cywgYW5kIHRoZSByZXF1ZXN0IHBheWxvYWQuXHJcbiAqIFRoZSBgc3RyaWN0Q2hlY2tgIGZsYWcgZW5hYmxlcyBzdHJpY3RlciB2YWxpZGF0aW9uIGFuZCBwYXJzaW5nIHJ1bGVzLiBUaGlzXHJcbiAqIGZsYWcgaXMgc2V0IHRvIGZhbHNlIGZvciB2YWx1ZXMgdGhhdCBjb21lIGZyb20gdGhlIC5lbnYgZmlsZSBvciBDTEkgYXJndW1lbnRzXHJcbiAqIGJlY2F1c2UgdGhleSBhcmUgcHJvdmlkZWQgYXMgc3RyaW5ncyBhbmQgbmVlZCB0byBiZSBwYXJzZWQgYWNjb3JkaW5nbHkgZmlyc3QuXHJcbiAqL1xyXG5jb25zdCB2ID0ge1xyXG4gIC8qKlxyXG4gICAqIFRoZSBgYm9vbGVhbmAgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbCBzdHJpY3RlclxyXG4gICAqIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoYXQ6XHJcbiAgICpcclxuICAgKiAtIFdoZW4gYHN0cmljdENoZWNrYCBpcyB0cnVlLCB0aGUgc2NoZW1hIHdpbGwgYWNjZXB0IHZhbHVlcyBhcmUgdHJ1ZVxyXG4gICAqIGFuZCBmYWxzZSBhbmQgdGhlIHNjaGVtYSB3aWxsIHZhbGlkYXRlIGFnYWluc3QgdGhlIGRlZmF1bHQgYm9vbGVhblxyXG4gICAqIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIC0gV2hlbiBgc3RyaWN0Q2hlY2tgIGlzIGZhbHNlLCB0aGUgc2NoZW1hIHdpbGwgYWNjZXB0IHZhbHVlcyBhcmUgdHJ1ZSxcclxuICAgKiBmYWxzZSwgbnVsbCwgJ3RydWUnLCAnMScsICdmYWxzZScsICcwJywgJ3VuZGVmaW5lZCcsICdudWxsJywgYW5kICcnLlxyXG4gICAqIFRoZSBzdHJpbmdzICd1bmRlZmluZWQnLCAnbnVsbCcsIGFuZCAnJyB3aWxsIGJlIHRyYW5zZm9ybWVkIHRvIG51bGwsXHJcbiAgICogdGhlIHN0cmluZyAndHJ1ZScgd2lsbCBiZSB0cmFuc2Zvcm1lZCB0byB0aGUgYm9vbGVhbiB2YWx1ZSB0cnVlLFxyXG4gICAqIGFuZCAnZmFsc2UnIHdpbGwgYmUgdHJhbnNmb3JtZWQgdG8gdGhlIGJvb2xlYW4gdmFsdWUgZmFsc2UuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gYm9vbGVhblxyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nIGJvb2xlYW4gdmFsdWVzLlxyXG4gICAqL1xyXG4gIGJvb2xlYW4oc3RyaWN0Q2hlY2spIHtcclxuICAgIHJldHVybiBzdHJpY3RDaGVja1xyXG4gICAgICA/IHouYm9vbGVhbigpXHJcbiAgICAgIDogelxyXG4gICAgICAgICAgLnVuaW9uKFtcclxuICAgICAgICAgICAgelxyXG4gICAgICAgICAgICAgIC5lbnVtKFsndHJ1ZScsICcxJywgJ2ZhbHNlJywgJzAnLCAndW5kZWZpbmVkJywgJ251bGwnLCAnJ10pXHJcbiAgICAgICAgICAgICAgLnRyYW5zZm9ybSgodmFsdWUpID0+XHJcbiAgICAgICAgICAgICAgICAhWyd1bmRlZmluZWQnLCAnbnVsbCcsICcnXS5pbmNsdWRlcyh2YWx1ZSlcclxuICAgICAgICAgICAgICAgICAgPyB2YWx1ZSA9PT0gJ3RydWUnIHx8IHZhbHVlID09PSAnMSdcclxuICAgICAgICAgICAgICAgICAgOiBudWxsXHJcbiAgICAgICAgICAgICAgKSxcclxuICAgICAgICAgICAgei5ib29sZWFuKClcclxuICAgICAgICAgIF0pXHJcbiAgICAgICAgICAubnVsbGFibGUoKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYHN0cmluZ2AgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbCBzdHJpY3RlclxyXG4gICAqIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoYXQ6XHJcbiAgICpcclxuICAgKiAtIFdoZW4gYHN0cmljdENoZWNrYCBpcyB0cnVlLCB0aGUgc2NoZW1hIHdpbGwgYWNjZXB0IHRyaW1tZWQgc3RyaW5ncyBleGNlcHRcclxuICAgKiB0aGUgZm9yYmlkZGVuIHZhbHVlczogJ2ZhbHNlJywgJ3VuZGVmaW5lZCcsICdudWxsJywgYW5kICcnLlxyXG4gICAqXHJcbiAgICogLSBXaGVuIGBzdHJpY3RDaGVja2AgaXMgZmFsc2UsIHRoZSBzY2hlbWEgd2lsbCBhY2NlcHQgdHJpbW1lZCBzdHJpbmdzXHJcbiAgICogYW5kIG51bGwuIFRoZSBmb3JiaWRkZW4gdmFsdWVzOiAnZmFsc2UnLCAndW5kZWZpbmVkJywgJ251bGwnLCBhbmQgJycgd2lsbFxyXG4gICAqIGJlIHRyYW5zZm9ybWVkIHRvIG51bGwuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gc3RyaW5nXHJcbiAgICpcclxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IHN0cmljdENoZWNrIC0gRGV0ZXJtaW5lcyBpZiBzdHJpY3RlciB2YWxpZGF0aW9uIHNob3VsZFxyXG4gICAqIGJlIGFwcGxpZWQuXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9IEEgWm9kIHNjaGVtYSBvYmplY3QgZm9yIHZhbGlkYXRpbmcgc3RyaW5nIHZhbHVlcy5cclxuICAgKi9cclxuICBzdHJpbmcoc3RyaWN0Q2hlY2spIHtcclxuICAgIHJldHVybiBzdHJpY3RDaGVja1xyXG4gICAgICA/IHpcclxuICAgICAgICAgIC5zdHJpbmcoKVxyXG4gICAgICAgICAgLnRyaW0oKVxyXG4gICAgICAgICAgLnJlZmluZShcclxuICAgICAgICAgICAgKHZhbHVlKSA9PiAhWydmYWxzZScsICd1bmRlZmluZWQnLCAnbnVsbCcsICcnXS5pbmNsdWRlcyh2YWx1ZSksXHJcbiAgICAgICAgICAgIHtcclxuICAgICAgICAgICAgICBwYXJhbXM6IHtcclxuICAgICAgICAgICAgICAgIGVycm9yTWVzc2FnZTogJ1RoZSBzdHJpbmcgY29udGFpbnMgYSBmb3JiaWRkZW4gdmFsdWUnXHJcbiAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICB9XHJcbiAgICAgICAgICApXHJcbiAgICAgIDogelxyXG4gICAgICAgICAgLnN0cmluZygpXHJcbiAgICAgICAgICAudHJpbSgpXHJcbiAgICAgICAgICAudHJhbnNmb3JtKCh2YWx1ZSkgPT5cclxuICAgICAgICAgICAgIVsnZmFsc2UnLCAndW5kZWZpbmVkJywgJ251bGwnLCAnJ10uaW5jbHVkZXModmFsdWUpID8gdmFsdWUgOiBudWxsXHJcbiAgICAgICAgICApXHJcbiAgICAgICAgICAubnVsbGFibGUoKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYGVudW1gIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGggYW4gb3B0aW9uYWwgc3RyaWN0ZXJcclxuICAgKiBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgc2NoZW1hIHdpbGwgdmFsaWRhdGUgYWdhaW5zdCB0aGUgcHJvdmlkZWQgYHZhbHVlc2AgYXJyYXkuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGF0OlxyXG4gICAqXHJcbiAgICogLSBXaGVuIGBzdHJpY3RDaGVja2AgaXMgdHJ1ZSwgdGhlIHNjaGVtYSB3aWxsIHZhbGlkYXRlIGFnYWluc3QgdGhlIGB2YWx1ZXNgXHJcbiAgICogYXJyYXkgd2l0aCB0aGUgZGVmYXVsdCBlbnVtIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIC0gV2hlbiBgc3RyaWN0Q2hlY2tgIGlzIGZhbHNlLCB0aGUgc2NoZW1hIHdpbGwgYWNjZXB0IGFsc28gbnVsbCxcclxuICAgKiAndW5kZWZpbmVkJywgJ251bGwnLCBhbmQgJycsIHdoaWNoIHdpbGwgYmUgdHJhbnNmb3JtZWQgdG8gbnVsbC5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiBlbnVtXHJcbiAgICpcclxuICAgKiBAcGFyYW0ge0FycmF5LjxzdHJpbmc+fSB2YWx1ZXMgLSBBbiBhcnJheSBvZiB2YWxpZCBzdHJpbmcgdmFsdWVzXHJcbiAgICogZm9yIHRoZSBlbnVtLlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZyBlbnVtIHZhbHVlcy5cclxuICAgKi9cclxuICBlbnVtKHZhbHVlcywgc3RyaWN0Q2hlY2spIHtcclxuICAgIHJldHVybiBzdHJpY3RDaGVja1xyXG4gICAgICA/IHouZW51bShbLi4udmFsdWVzXSlcclxuICAgICAgOiB6XHJcbiAgICAgICAgICAuZW51bShbLi4udmFsdWVzLCAndW5kZWZpbmVkJywgJ251bGwnLCAnJ10pXHJcbiAgICAgICAgICAudHJhbnNmb3JtKCh2YWx1ZSkgPT5cclxuICAgICAgICAgICAgIVsndW5kZWZpbmVkJywgJ251bGwnLCAnJ10uaW5jbHVkZXModmFsdWUpID8gdmFsdWUgOiBudWxsXHJcbiAgICAgICAgICApXHJcbiAgICAgICAgICAubnVsbGFibGUoKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYHN0cmluZ0FycmF5YCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoIGFuIG9wdGlvbmFsXHJcbiAgICogc3RyaWN0ZXIgY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhhdDpcclxuICAgKlxyXG4gICAqIC0gV2hlbiBgc3RyaWN0Q2hlY2tgIGlzIHRydWUsIHRoZSBzY2hlbWEgd2lsbCBhY2NlcHQgYW4gYXJyYXkgb2YgdHJpbW1lZFxyXG4gICAqIHN0cmluZyB2YWx1ZXMgZmlsdGVyZWQgYnkgdGhlIGxvZ2ljIHByb3ZpZGVkIHRocm91Z2ggdGhlIGBmaWx0ZXJDYWxsYmFja2AuXHJcbiAgICpcclxuICAgKiAtIFdoZW4gYHN0cmljdENoZWNrYCBpcyBmYWxzZSwgdGhlIHNjaGVtYSB3aWxsIGFjY2VwdCBudWxsIGFuZCB0cmltbWVkXHJcbiAgICogc3RyaW5nIHZhbHVlcyB3aGljaCB3aWxsIGJlIHNwbGl0dGVkIGludG8gYW4gYXJyYXkgb2Ygc3RyaW5ncyBhbmQgZmlsdGVyZWRcclxuICAgKiBmcm9tIHRoZSAnWycgYW5kICddJyBjaGFyYWN0ZXJzIGFuZCBieSB0aGUgbG9naWMgcHJvdmlkZWQgdGhyb3VnaFxyXG4gICAqIHRoZSBgZmlsdGVyQ2FsbGJhY2tgLiBJZiB0aGUgYXJyYXkgaXMgZW1wdHksIGl0IHdpbGwgYmUgdHJhbnNmb3JtZWRcclxuICAgKiB0byBudWxsLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIHN0cmluZ0FycmF5XHJcbiAgICpcclxuICAgKiBAcGFyYW0ge2Z1bmN0aW9ufSBmaWx0ZXJDYWxsYmFjayAtIFRoZSBmaWx0ZXIgY2FsbGJhY2suXHJcbiAgICogQHBhcmFtIHtzdHJpbmd9IHNlcGFyYXRvciAtIFRoZSBzZXBhcmF0b3IgZm9yIHNwbGl0aW5nIGEgc3RyaW5nLlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZyBhcnJheSBvZiBzdHJpbmdcclxuICAgKiB2YWx1ZXMuXHJcbiAgICovXHJcbiAgc3RyaW5nQXJyYXkoZmlsdGVyQ2FsbGJhY2ssIHNlcGFyYXRvciwgc3RyaWN0Q2hlY2spIHtcclxuICAgIGNvbnN0IGFycmF5U2NoZW1hID0gei5zdHJpbmcoKS50cmltKCkuYXJyYXkoKTtcclxuICAgIGNvbnN0IHN0cmluZ1NjaGVtYSA9IHpcclxuICAgICAgLnN0cmluZygpXHJcbiAgICAgIC50cmltKClcclxuICAgICAgLnRyYW5zZm9ybSgodmFsdWUpID0+IHtcclxuICAgICAgICBpZiAodmFsdWUuc3RhcnRzV2l0aCgnWycpKSB7XHJcbiAgICAgICAgICB2YWx1ZSA9IHZhbHVlLnNsaWNlKDEpO1xyXG4gICAgICAgIH1cclxuICAgICAgICBpZiAodmFsdWUuZW5kc1dpdGgoJ10nKSkge1xyXG4gICAgICAgICAgdmFsdWUgPSB2YWx1ZS5zbGljZSgwLCAtMSk7XHJcbiAgICAgICAgfVxyXG4gICAgICAgIHJldHVybiB2YWx1ZS5zcGxpdChzZXBhcmF0b3IpO1xyXG4gICAgICB9KTtcclxuXHJcbiAgICBjb25zdCB0cmFuc2Zvcm1DYWxsYmFjayA9ICh2YWx1ZSkgPT5cclxuICAgICAgdmFsdWUubWFwKCh2YWx1ZSkgPT4gdmFsdWUudHJpbSgpKS5maWx0ZXIoZmlsdGVyQ2FsbGJhY2spO1xyXG5cclxuICAgIHJldHVybiBzdHJpY3RDaGVja1xyXG4gICAgICA/IGFycmF5U2NoZW1hLnRyYW5zZm9ybSh0cmFuc2Zvcm1DYWxsYmFjaylcclxuICAgICAgOiB6XHJcbiAgICAgICAgICAudW5pb24oW3N0cmluZ1NjaGVtYSwgYXJyYXlTY2hlbWFdKVxyXG4gICAgICAgICAgLnRyYW5zZm9ybSh0cmFuc2Zvcm1DYWxsYmFjaylcclxuICAgICAgICAgIC50cmFuc2Zvcm0oKHZhbHVlKSA9PiAodmFsdWUubGVuZ3RoID8gdmFsdWUgOiBudWxsKSlcclxuICAgICAgICAgIC5udWxsYWJsZSgpO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgcG9zaXRpdmVOdW1gIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGggYW4gb3B0aW9uYWxcclxuICAgKiBzdHJpY3RlciBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGF0OlxyXG4gICAqXHJcbiAgICogLSBXaGVuIGBzdHJpY3RDaGVja2AgaXMgdHJ1ZSwgdGhlIHNjaGVtYSB3aWxsIGFjY2VwdCBwb3NpdGl2ZSBudW1iZXIgdmFsdWVzXHJcbiAgICogYW5kIHZhbGlkYXRlIGFnYWluc3QgdGhlIGRlZmF1bHQgcG9zaXRpdmUgbnVtYmVyIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIC0gV2hlbiBgc3RyaWN0Q2hlY2tgIGlzIGZhbHNlLCB0aGUgc2NoZW1hIHdpbGwgYWNjZXB0IHBvc2l0aXZlIG51bWJlclxyXG4gICAqIHZhbHVlcywgbnVsbCwgYW5kIHRyaW1tZWQgc3RyaW5nIHZhbHVlcyB0aGF0IGNhbiBlaXRoZXIgYmUgJ3VuZGVmaW5lZCcsXHJcbiAgICogJ251bGwnLCAnJywgb3IgcmVwcmVzZW50IGEgcG9zaXRpdmUgbnVtYmVyLiBJdCB3aWxsIHRyYW5zZm9ybSB0aGUgc3RyaW5nXHJcbiAgICogdG8gYSBwb3NpdGl2ZSBudW1iZXIsIG9yIHRvIG51bGwgaWYgaXQgaXMgJ3VuZGVmaW5lZCcsICdudWxsJywgb3IgJycuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gcG9zaXRpdmVOdW1cclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZyBwb3NpdGl2ZSBudW1iZXJcclxuICAgKiB2YWx1ZXMuXHJcbiAgICovXHJcbiAgcG9zaXRpdmVOdW0oc3RyaWN0Q2hlY2spIHtcclxuICAgIHJldHVybiBzdHJpY3RDaGVja1xyXG4gICAgICA/IHoubnVtYmVyKCkucG9zaXRpdmUoKVxyXG4gICAgICA6IHpcclxuICAgICAgICAgIC51bmlvbihbXHJcbiAgICAgICAgICAgIHpcclxuICAgICAgICAgICAgICAuc3RyaW5nKClcclxuICAgICAgICAgICAgICAudHJpbSgpXHJcbiAgICAgICAgICAgICAgLnJlZmluZShcclxuICAgICAgICAgICAgICAgICh2YWx1ZSkgPT5cclxuICAgICAgICAgICAgICAgICAgKCFpc05hTihOdW1iZXIodmFsdWUpKSAmJiBOdW1iZXIodmFsdWUpID4gMCkgfHxcclxuICAgICAgICAgICAgICAgICAgWyd1bmRlZmluZWQnLCAnbnVsbCcsICcnXS5pbmNsdWRlcyh2YWx1ZSksXHJcbiAgICAgICAgICAgICAgICB7XHJcbiAgICAgICAgICAgICAgICAgIHBhcmFtczoge1xyXG4gICAgICAgICAgICAgICAgICAgIGVycm9yTWVzc2FnZTogJ1RoZSB2YWx1ZSBtdXN0IGJlIG51bWVyaWMgYW5kIHBvc2l0aXZlJ1xyXG4gICAgICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgICAgKVxyXG4gICAgICAgICAgICAgIC50cmFuc2Zvcm0oKHZhbHVlKSA9PlxyXG4gICAgICAgICAgICAgICAgIVsndW5kZWZpbmVkJywgJ251bGwnLCAnJ10uaW5jbHVkZXModmFsdWUpXHJcbiAgICAgICAgICAgICAgICAgID8gTnVtYmVyKHZhbHVlKVxyXG4gICAgICAgICAgICAgICAgICA6IG51bGxcclxuICAgICAgICAgICAgICApLFxyXG4gICAgICAgICAgICB6Lm51bWJlcigpLnBvc2l0aXZlKClcclxuICAgICAgICAgIF0pXHJcbiAgICAgICAgICAubnVsbGFibGUoKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYG5vbk5lZ2F0aXZlTnVtYCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoIGFuIG9wdGlvbmFsXHJcbiAgICogc3RyaWN0ZXIgY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhhdDpcclxuICAgKlxyXG4gICAqIC0gV2hlbiBgc3RyaWN0Q2hlY2tgIGlzIHRydWUsIHRoZSBzY2hlbWEgd2lsbCBhY2NlcHQgbm9uLW5lZ2F0aXZlIG51bWJlclxyXG4gICAqIHZhbHVlcyBhbmQgdmFsaWRhdGUgYWdhaW5zdCB0aGUgZGVmYXVsdCBub24tbmVnYXRpdmUgbnVtYmVyIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIC0gV2hlbiBgc3RyaWN0Q2hlY2tgIGlzIGZhbHNlLCB0aGUgc2NoZW1hIHdpbGwgYWNjZXB0IG5vbi1uZWdhdGl2ZSBudW1iZXJcclxuICAgKiB2YWx1ZXMsIG51bGwsIGFuZCB0cmltbWVkIHN0cmluZyB2YWx1ZXMgdGhhdCBjYW4gZWl0aGVyIGJlICd1bmRlZmluZWQnLFxyXG4gICAqICdudWxsJywgJycsIG9yIHJlcHJlc2VudCBhIG5vbi1uZWdhdGl2ZSBudW1iZXIuIEl0IHdpbGwgdHJhbnNmb3JtXHJcbiAgICogdGhlIHN0cmluZyB0byBhIG5vbi1uZWdhdGl2ZSBudW1iZXIsIG9yIHRvIG51bGwgaWYgaXQgaXMgJ3VuZGVmaW5lZCcsXHJcbiAgICogJ251bGwnLCBvciAnJy5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiBub25OZWdhdGl2ZU51bVxyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nIG5vbi1uZWdhdGl2ZVxyXG4gICAqIG51bWJlciB2YWx1ZXMuXHJcbiAgICovXHJcbiAgbm9uTmVnYXRpdmVOdW0oc3RyaWN0Q2hlY2spIHtcclxuICAgIHJldHVybiBzdHJpY3RDaGVja1xyXG4gICAgICA/IHoubnVtYmVyKCkubm9ubmVnYXRpdmUoKVxyXG4gICAgICA6IHpcclxuICAgICAgICAgIC51bmlvbihbXHJcbiAgICAgICAgICAgIHpcclxuICAgICAgICAgICAgICAuc3RyaW5nKClcclxuICAgICAgICAgICAgICAudHJpbSgpXHJcbiAgICAgICAgICAgICAgLnJlZmluZShcclxuICAgICAgICAgICAgICAgICh2YWx1ZSkgPT5cclxuICAgICAgICAgICAgICAgICAgKCFpc05hTihOdW1iZXIodmFsdWUpKSAmJiBOdW1iZXIodmFsdWUpID49IDApIHx8XHJcbiAgICAgICAgICAgICAgICAgIFsndW5kZWZpbmVkJywgJ251bGwnLCAnJ10uaW5jbHVkZXModmFsdWUpLFxyXG4gICAgICAgICAgICAgICAge1xyXG4gICAgICAgICAgICAgICAgICBwYXJhbXM6IHtcclxuICAgICAgICAgICAgICAgICAgICBlcnJvck1lc3NhZ2U6ICdUaGUgdmFsdWUgbXVzdCBiZSBudW1lcmljIGFuZCBub24tbmVnYXRpdmUnXHJcbiAgICAgICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgICApXHJcbiAgICAgICAgICAgICAgLnRyYW5zZm9ybSgodmFsdWUpID0+XHJcbiAgICAgICAgICAgICAgICAhWyd1bmRlZmluZWQnLCAnbnVsbCcsICcnXS5pbmNsdWRlcyh2YWx1ZSlcclxuICAgICAgICAgICAgICAgICAgPyBOdW1iZXIodmFsdWUpXHJcbiAgICAgICAgICAgICAgICAgIDogbnVsbFxyXG4gICAgICAgICAgICAgICksXHJcbiAgICAgICAgICAgIHoubnVtYmVyKCkubm9ubmVnYXRpdmUoKVxyXG4gICAgICAgICAgXSlcclxuICAgICAgICAgIC5udWxsYWJsZSgpO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgc3RhcnRzV2l0aGAgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbFxyXG4gICAqIHN0cmljdGVyIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSBzY2hlbWEgd2lsbCB2YWxpZGF0ZSBhZ2FpbnN0IHRoZSBwcm92aWRlZCBgcHJlZml4ZXNgIGFycmF5IHRvIGNoZWNrXHJcbiAgICogd2hldGhlciBhIHN0cmluZyB2YWx1ZSBzdGFydHMgd2l0aCBhbnkgb2YgdGhlIHZhbHVlcyBwcm92aWRlZFxyXG4gICAqIGluIHRoZSBgcHJlZml4ZXNgIGFycmF5LlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhhdDpcclxuICAgKlxyXG4gICAqIC0gV2hlbiBgc3RyaWN0Q2hlY2tgIGlzIHRydWUsIHRoZSBzY2hlbWEgd2lsbCBhY2NlcHQgdHJpbW1lZCBzdHJpbmcgdmFsdWVzXHJcbiAgICogdGhhdCBzdGFydCB3aXRoIHZhbHVlcyBmcm9tIHRoZSBwcmVmaXhlcyBhcnJheS5cclxuICAgKlxyXG4gICAqIC0gV2hlbiBgc3RyaWN0Q2hlY2tgIGlzIGZhbHNlLCB0aGUgc2NoZW1hIHdpbGwgYWNjZXB0IHRyaW1tZWQgc3RyaW5nIHZhbHVlc1xyXG4gICAqIHRoYXQgc3RhcnQgd2l0aCB2YWx1ZXMgZnJvbSB0aGUgcHJlZml4ZXMgYXJyYXksIG51bGwsICd1bmRlZmluZWQnLCAnbnVsbCcsXHJcbiAgICogYW5kICcnIHdoZXJlIHRoZSBzY2hlbWEgd2lsbCB0cmFuc2Zvcm0gdGhlbSB0byBudWxsLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIHN0YXJ0c1dpdGhcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7QXJyYXkuPHN0cmluZz59IHByZWZpeGVzIC0gQW4gYXJyYXkgb2YgcHJlZml4ZXMgdG8gdmFsaWRhdGVcclxuICAgKiB0aGUgc3RyaW5nIGFnYWluc3QuXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nIHN0cmluZ3MgdGhhdFxyXG4gICAqIHN0YXJ0cyB3aXRoIHZhbHVlcy5cclxuICAgKi9cclxuICBzdGFydHNXaXRoKHByZWZpeGVzLCBzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHN0cmljdENoZWNrXHJcbiAgICAgID8gelxyXG4gICAgICAgICAgLnN0cmluZygpXHJcbiAgICAgICAgICAudHJpbSgpXHJcbiAgICAgICAgICAucmVmaW5lKFxyXG4gICAgICAgICAgICAodmFsdWUpID0+IHByZWZpeGVzLnNvbWUoKHByZWZpeCkgPT4gdmFsdWUuc3RhcnRzV2l0aChwcmVmaXgpKSxcclxuICAgICAgICAgICAge1xyXG4gICAgICAgICAgICAgIHBhcmFtczoge1xyXG4gICAgICAgICAgICAgICAgZXJyb3JNZXNzYWdlOiBgVGhlIHZhbHVlIG11c3QgYmUgYSBzdHJpbmcgdGhhdCBzdGFydHMgd2l0aCAke3ByZWZpeGVzLmpvaW4oJywgJyl9YFxyXG4gICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgfVxyXG4gICAgICAgICAgKVxyXG4gICAgICA6IHpcclxuICAgICAgICAgIC5zdHJpbmcoKVxyXG4gICAgICAgICAgLnRyaW0oKVxyXG4gICAgICAgICAgLnJlZmluZShcclxuICAgICAgICAgICAgKHZhbHVlKSA9PlxyXG4gICAgICAgICAgICAgIHByZWZpeGVzLnNvbWUoKHByZWZpeCkgPT4gdmFsdWUuc3RhcnRzV2l0aChwcmVmaXgpKSB8fFxyXG4gICAgICAgICAgICAgIFsndW5kZWZpbmVkJywgJ251bGwnLCAnJ10uaW5jbHVkZXModmFsdWUpLFxyXG4gICAgICAgICAgICB7XHJcbiAgICAgICAgICAgICAgcGFyYW1zOiB7XHJcbiAgICAgICAgICAgICAgICBlcnJvck1lc3NhZ2U6IGBUaGUgdmFsdWUgbXVzdCBiZSBhIHN0cmluZyB0aGF0IHN0YXJ0cyB3aXRoICR7cHJlZml4ZXMuam9pbignLCAnKX1gXHJcbiAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICB9XHJcbiAgICAgICAgICApXHJcbiAgICAgICAgICAudHJhbnNmb3JtKCh2YWx1ZSkgPT5cclxuICAgICAgICAgICAgIVsndW5kZWZpbmVkJywgJ251bGwnLCAnJ10uaW5jbHVkZXModmFsdWUpID8gdmFsdWUgOiBudWxsXHJcbiAgICAgICAgICApXHJcbiAgICAgICAgICAubnVsbGFibGUoKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYGNoYXJ0Q29uZmlnYCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYS5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoYXQgdGhlIHNjaGVtYSB3aWxsIGFjY2VwdCBvYmplY3QgdmFsdWVzXHJcbiAgICogb3IgdHJpbW1lZCBzdHJpbmcgdmFsdWVzIHRoYXQgY29udGFpbiAnPHN2Zycgb3IgJzw/eG1sJyBlbGVtZW50cywgc3RhcnRcclxuICAgKiB3aXRoIHRoZSAneycgYW5kIGVuZCB3aXRoIHRoZSAnfScsIGFuZCBudWxsLiBUaGUgJ3VuZGVmaW5lZCcsICdudWxsJyxcclxuICAgKiBhbmQgJycgdmFsdWVzIHdpbGwgYmUgdHJhbnNmb3JtZWQgdG8gbnVsbC5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiBjaGFydENvbmZpZ1xyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nIGNoYXJ0XHJcbiAgICogY29uZmlndXJhdGlvbiB2YWx1ZS5cclxuICAgKi9cclxuICBjaGFydENvbmZpZygpIHtcclxuICAgIHJldHVybiB6XHJcbiAgICAgIC51bmlvbihbXHJcbiAgICAgICAgelxyXG4gICAgICAgICAgLnN0cmluZygpXHJcbiAgICAgICAgICAudHJpbSgpXHJcbiAgICAgICAgICAucmVmaW5lKFxyXG4gICAgICAgICAgICAodmFsdWUpID0+XHJcbiAgICAgICAgICAgICAgKHZhbHVlLnN0YXJ0c1dpdGgoJ3snKSAmJiB2YWx1ZS5lbmRzV2l0aCgnfScpKSB8fFxyXG4gICAgICAgICAgICAgIFsndW5kZWZpbmVkJywgJ251bGwnLCAnJ10uaW5jbHVkZXModmFsdWUpLFxyXG4gICAgICAgICAgICB7XHJcbiAgICAgICAgICAgICAgcGFyYW1zOiB7XHJcbiAgICAgICAgICAgICAgICBlcnJvck1lc3NhZ2U6XHJcbiAgICAgICAgICAgICAgICAgIFwiVGhlIHZhbHVlIG11c3QgYmUgYSBzdHJpbmcgdGhhdCBzdGFydHMgd2l0aCAneycgYW5kIGVuZHMgd2l0aCAnfSdcIlxyXG4gICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgfVxyXG4gICAgICAgICAgKVxyXG4gICAgICAgICAgLnRyYW5zZm9ybSgodmFsdWUpID0+XHJcbiAgICAgICAgICAgICFbJ3VuZGVmaW5lZCcsICdudWxsJywgJyddLmluY2x1ZGVzKHZhbHVlKSA/IHZhbHVlIDogbnVsbFxyXG4gICAgICAgICAgKSxcclxuICAgICAgICB6Lm9iamVjdCh7fSkucGFzc3Rocm91Z2goKVxyXG4gICAgICBdKVxyXG4gICAgICAubnVsbGFibGUoKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYGFkZGl0aW9uYWxPcHRpb25zYCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYS5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoYXQgdGhlIHNjaGVtYSB3aWxsIGFjY2VwdCBvYmplY3QgdmFsdWVzXHJcbiAgICogb3IgdHJpbW1lZCBzdHJpbmcgdmFsdWVzIHRoYXQgZW5kIHdpdGggJy5qc29uJyBhbmQgYXJlIGF0IGxlYXN0IG9uZVxyXG4gICAqIGNoYXJhY3RlciBsb25nIGV4Y2x1ZGluZyB0aGUgZXh0ZW5zaW9uLCBzdGFydCB3aXRoIHRoZSAneycgYW5kIGVuZFxyXG4gICAqIHdpdGggdGhlICd9JywgYW5kIG51bGwuIFRoZSAndW5kZWZpbmVkJywgJ251bGwnLCBhbmQgJycgdmFsdWVzIHdpbGxcclxuICAgKiBiZSB0cmFuc2Zvcm1lZCB0byBudWxsLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIGFkZGl0aW9uYWxPcHRpb25zXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9ICBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nIGFkZGl0aW9uYWwgY2hhcnRcclxuICAgKiBvcHRpb25zIHZhbHVlLlxyXG4gICAqL1xyXG4gIGFkZGl0aW9uYWxPcHRpb25zKCkge1xyXG4gICAgcmV0dXJuIHpcclxuICAgICAgLnVuaW9uKFtcclxuICAgICAgICB6XHJcbiAgICAgICAgICAuc3RyaW5nKClcclxuICAgICAgICAgIC50cmltKClcclxuICAgICAgICAgIC5yZWZpbmUoXHJcbiAgICAgICAgICAgICh2YWx1ZSkgPT5cclxuICAgICAgICAgICAgICAodmFsdWUubGVuZ3RoID49IDYgJiYgdmFsdWUuZW5kc1dpdGgoJy5qc29uJykpIHx8XHJcbiAgICAgICAgICAgICAgKHZhbHVlLnN0YXJ0c1dpdGgoJ3snKSAmJiB2YWx1ZS5lbmRzV2l0aCgnfScpKSB8fFxyXG4gICAgICAgICAgICAgIFsndW5kZWZpbmVkJywgJ251bGwnLCAnJ10uaW5jbHVkZXModmFsdWUpLFxyXG4gICAgICAgICAgICB7XHJcbiAgICAgICAgICAgICAgcGFyYW1zOiB7XHJcbiAgICAgICAgICAgICAgICBlcnJvck1lc3NhZ2U6XHJcbiAgICAgICAgICAgICAgICAgIFwiVGhlIHZhbHVlIG11c3QgYmUgYSBzdHJpbmcgdGhhdCBlbmRzIHdpdGggJy5qc29uJyBvciBzdGFydHMgd2l0aCAneycgYW5kIGVuZHMgd2l0aCAnfSdcIlxyXG4gICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgfVxyXG4gICAgICAgICAgKVxyXG4gICAgICAgICAgLnRyYW5zZm9ybSgodmFsdWUpID0+XHJcbiAgICAgICAgICAgICFbJ3VuZGVmaW5lZCcsICdudWxsJywgJyddLmluY2x1ZGVzKHZhbHVlKSA/IHZhbHVlIDogbnVsbFxyXG4gICAgICAgICAgKSxcclxuICAgICAgICB6Lm9iamVjdCh7fSkucGFzc3Rocm91Z2goKVxyXG4gICAgICBdKVxyXG4gICAgICAubnVsbGFibGUoKTtcclxuICB9XHJcbn07XHJcblxyXG4vKipcclxuICogT2JqZWN0IGNvbnRhaW5pbmcgY3VzdG9tIGNvbmZpZyB2YWxpZGF0b3JzIGFuZCBwYXJzZXJzIHRvIGF2b2lkIHJlcGV0aXRpb25cclxuICogaW4gc2NoZW1hIG9iamVjdHMuIEFsbCB2YWxpZGF0b3JzIGFwcGx5IHRvIHZhbHVlcyBmcm9tIHZhcmlvdXMgc291cmNlcyxcclxuICogaW5jbHVkaW5nIHRoZSBkZWZhdWx0IGNvbmZpZyBmaWxlLCBhIGN1c3RvbSBKU09OIGZpbGUgbG9hZGVkIHdpdGggdGhlIG9wdGlvblxyXG4gKiBjYWxsZWQgYGxvYWRDb25maWdgLCB0aGUgLmVudiBmaWxlLCBDTEkgYXJndW1lbnRzLCBhbmQgdGhlIHJlcXVlc3QgcGF5bG9hZC5cclxuICogVGhlIGBzdHJpY3RDaGVja2AgZmxhZyBlbmFibGVzIHN0cmljdGVyIHZhbGlkYXRpb24gYW5kIHBhcnNpbmcgcnVsZXMuIFRoaXNcclxuICogZmxhZyBpcyBzZXQgdG8gZmFsc2UgZm9yIHZhbHVlcyB0aGF0IGNvbWUgZnJvbSB0aGUgLmVudiBmaWxlIG9yIENMSSBhcmd1bWVudHNcclxuICogYmVjYXVzZSB0aGV5IGFyZSBwcm92aWRlZCBhcyBzdHJpbmdzIGFuZCBuZWVkIHRvIGJlIHBhcnNlZCBhY2NvcmRpbmdseSBmaXJzdC5cclxuICovXHJcbmV4cG9ydCBjb25zdCB2YWxpZGF0b3JzID0ge1xyXG4gIC8qKlxyXG4gICAqIFRoZSBgYXJnc2AgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbCBzdHJpY3RlclxyXG4gICAqIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgdGhlIGBzdHJpbmdBcnJheWAgdmFsaWRhdG9yLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIGFyZ3NcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZyB0aGUgYGFyZ3NgXHJcbiAgICogb3B0aW9uLlxyXG4gICAqL1xyXG4gIGFyZ3Moc3RyaWN0Q2hlY2spIHtcclxuICAgIHJldHVybiB2LnN0cmluZ0FycmF5KFxyXG4gICAgICAodmFsdWUpID0+ICFbJ2ZhbHNlJywgJ3VuZGVmaW5lZCcsICdudWxsJywgJyddLmluY2x1ZGVzKHZhbHVlKSxcclxuICAgICAgJzsnLFxyXG4gICAgICBzdHJpY3RDaGVja1xyXG4gICAgKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYHZlcnNpb25gIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGggYW4gb3B0aW9uYWwgc3RyaWN0ZXJcclxuICAgKiBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGF0OlxyXG4gICAqXHJcbiAgICogLSBXaGVuIGBzdHJpY3RDaGVja2AgaXMgdHJ1ZSwgdGhlIHNjaGVtYSB3aWxsIGFjY2VwdCB0cmltbWVkIHN0cmluZyB2YWx1ZXNcclxuICAgKiB0aGF0IGFyZSBhIFJlZ0V4cC1iYXNlZCB0aGF0IGFsbG93cyB0byBiZSAnbGF0ZXN0Jywgb3IgaW4gdGhlIGZvcm1hdCBYWCxcclxuICAgKiBYWC5ZWSwgb3IgWFguWVkuWlosIHdoZXJlIFhYLCBZWSwgYW5kIFpaIGFyZSBudW1lcmljIGZvciB0aGUgSGlnaGNoYXJ0c1xyXG4gICAqIHZlcnNpb24gb3B0aW9uLlxyXG4gICAqXHJcbiAgICogLSBXaGVuIGBzdHJpY3RDaGVja2AgaXMgZmFsc2UsIHRoZSBzY2hlbWEgd2lsbCBhY2NlcHQgYWxzbyBudWxsLFxyXG4gICAqICd1bmRlZmluZWQnLCAnbnVsbCcsIG9yICcnIGFuZCBpbiBhbGwgY2FzZXMgdGhlIHNjaGVtYSB3aWxsIHRyYW5zZm9ybSB0aGVtXHJcbiAgICogdG8gbnVsbC5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiB2ZXJzaW9uXHJcbiAgICpcclxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IHN0cmljdENoZWNrIC0gRGV0ZXJtaW5lcyBpZiBzdHJpY3RlciB2YWxpZGF0aW9uIHNob3VsZFxyXG4gICAqIGJlIGFwcGxpZWQuXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9IEEgWm9kIHNjaGVtYSBvYmplY3QgZm9yIHZhbGlkYXRpbmcgdGhlIGB2ZXJzaW9uYFxyXG4gICAqIG9wdGlvbi5cclxuICAgKi9cclxuICB2ZXJzaW9uKHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gc3RyaWN0Q2hlY2tcclxuICAgICAgPyB6XHJcbiAgICAgICAgICAuc3RyaW5nKClcclxuICAgICAgICAgIC50cmltKClcclxuICAgICAgICAgIC5yZWZpbmUoKHZhbHVlKSA9PiAvXihsYXRlc3R8XFxkezEsMn0oXFwuXFxkezEsMn0pezAsMn0pJC8udGVzdCh2YWx1ZSksIHtcclxuICAgICAgICAgICAgcGFyYW1zOiB7XHJcbiAgICAgICAgICAgICAgZXJyb3JNZXNzYWdlOlxyXG4gICAgICAgICAgICAgICAgXCJUaGUgdmFsdWUgbXVzdCBiZSAnbGF0ZXN0JywgYSBtYWpvciB2ZXJzaW9uLCBvciBpbiB0aGUgZm9ybSBYWC5ZWS5aWlwiXHJcbiAgICAgICAgICAgIH1cclxuICAgICAgICAgIH0pXHJcbiAgICAgIDogelxyXG4gICAgICAgICAgLnN0cmluZygpXHJcbiAgICAgICAgICAudHJpbSgpXHJcbiAgICAgICAgICAucmVmaW5lKFxyXG4gICAgICAgICAgICAodmFsdWUpID0+XHJcbiAgICAgICAgICAgICAgL14obGF0ZXN0fFxcZHsxLDJ9KFxcLlxcZHsxLDJ9KXswLDJ9KSQvLnRlc3QodmFsdWUpIHx8XHJcbiAgICAgICAgICAgICAgWyd1bmRlZmluZWQnLCAnbnVsbCcsICcnXS5pbmNsdWRlcyh2YWx1ZSksXHJcbiAgICAgICAgICAgIHtcclxuICAgICAgICAgICAgICBwYXJhbXM6IHtcclxuICAgICAgICAgICAgICAgIGVycm9yTWVzc2FnZTpcclxuICAgICAgICAgICAgICAgICAgXCJUaGUgdmFsdWUgbXVzdCBiZSAnbGF0ZXN0JywgYSBtYWpvciB2ZXJzaW9uLCBvciBpbiB0aGUgZm9ybSBYWC5ZWS5aWlwiXHJcbiAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICB9XHJcbiAgICAgICAgICApXHJcbiAgICAgICAgICAudHJhbnNmb3JtKCh2YWx1ZSkgPT5cclxuICAgICAgICAgICAgIVsndW5kZWZpbmVkJywgJ251bGwnLCAnJ10uaW5jbHVkZXModmFsdWUpID8gdmFsdWUgOiBudWxsXHJcbiAgICAgICAgICApXHJcbiAgICAgICAgICAubnVsbGFibGUoKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYGNkblVybGAgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbCBzdHJpY3RlclxyXG4gICAqIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgdGhlIGBzdGFydHNXaXRoYCB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gY2RuVXJsXHJcbiAgICpcclxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IHN0cmljdENoZWNrIC0gRGV0ZXJtaW5lcyBpZiBzdHJpY3RlciB2YWxpZGF0aW9uIHNob3VsZFxyXG4gICAqIGJlIGFwcGxpZWQuXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9IEEgWm9kIHNjaGVtYSBvYmplY3QgZm9yIHZhbGlkYXRpbmcgdGhlIGBjZG5VcmxgXHJcbiAgICogb3B0aW9uLlxyXG4gICAqL1xyXG4gIGNkblVybChzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHYuc3RhcnRzV2l0aChbJ2h0dHA6Ly8nLCAnaHR0cHM6Ly8nXSwgc3RyaWN0Q2hlY2spO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgZm9yY2VGZXRjaGAgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbFxyXG4gICAqIHN0cmljdGVyIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgdGhlIGBib29sZWFuYCB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gZm9yY2VGZXRjaFxyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nIHRoZSBgZm9yY2VGZXRjaGBcclxuICAgKiBvcHRpb24uXHJcbiAgICovXHJcbiAgZm9yY2VGZXRjaChzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHYuYm9vbGVhbihzdHJpY3RDaGVjayk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGBjYWNoZVBhdGhgIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGggYW4gb3B0aW9uYWxcclxuICAgKiBzdHJpY3RlciBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGUgc2FtZSB3b3JrIGFzIHRoZSBgc3RyaW5nYCB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gY2FjaGVQYXRoXHJcbiAgICpcclxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IHN0cmljdENoZWNrIC0gRGV0ZXJtaW5lcyBpZiBzdHJpY3RlciB2YWxpZGF0aW9uIHNob3VsZFxyXG4gICAqIGJlIGFwcGxpZWQuXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9IEEgWm9kIHNjaGVtYSBvYmplY3QgZm9yIHZhbGlkYXRpbmcgdGhlIGBjYWNoZVBhdGhgXHJcbiAgICogb3B0aW9uLlxyXG4gICAqL1xyXG4gIGNhY2hlUGF0aChzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHYuc3RyaW5nKHN0cmljdENoZWNrKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYGFkbWluVG9rZW5gIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGggYW4gb3B0aW9uYWxcclxuICAgKiBzdHJpY3RlciBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGUgc2FtZSB3b3JrIGFzIHRoZSBgc3RyaW5nYCB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gYWRtaW5Ub2tlblxyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nIHRoZSBgYWRtaW5Ub2tlbmBcclxuICAgKiBvcHRpb24uXHJcbiAgICovXHJcbiAgYWRtaW5Ub2tlbihzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHYuc3RyaW5nKHN0cmljdENoZWNrKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYGNvcmVTY3JpcHRzYCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoIGFuIG9wdGlvbmFsXHJcbiAgICogc3RyaWN0ZXIgY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhlIHNhbWUgd29yayBhcyB0aGUgYHN0cmluZ0FycmF5YCB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gY29yZVNjcmlwdHNcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZyB0aGUgYGNvcmVTY3JpcHRzYFxyXG4gICAqIG9wdGlvbi5cclxuICAgKi9cclxuICBjb3JlU2NyaXB0cyhzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHYuc3RyaW5nQXJyYXkoXHJcbiAgICAgICh2YWx1ZSkgPT4gY29yZVNjcmlwdHMudmFsdWUuaW5jbHVkZXModmFsdWUpLFxyXG4gICAgICAnLCcsXHJcbiAgICAgIHN0cmljdENoZWNrXHJcbiAgICApO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgbW9kdWxlU2NyaXB0c2AgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbFxyXG4gICAqIHN0cmljdGVyIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgdGhlIGBzdHJpbmdBcnJheWAgdmFsaWRhdG9yLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIG1vZHVsZVNjcmlwdHNcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZ1xyXG4gICAqIHRoZSBgbW9kdWxlU2NyaXB0c2Agb3B0aW9uLlxyXG4gICAqL1xyXG4gIG1vZHVsZVNjcmlwdHMoc3RyaWN0Q2hlY2spIHtcclxuICAgIHJldHVybiB2LnN0cmluZ0FycmF5KFxyXG4gICAgICAodmFsdWUpID0+IG1vZHVsZVNjcmlwdHMudmFsdWUuaW5jbHVkZXModmFsdWUpLFxyXG4gICAgICAnLCcsXHJcbiAgICAgIHN0cmljdENoZWNrXHJcbiAgICApO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgaW5kaWNhdG9yU2NyaXB0c2AgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbFxyXG4gICAqIHN0cmljdGVyIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgdGhlIGBzdHJpbmdBcnJheWAgdmFsaWRhdG9yLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIGluZGljYXRvclNjcmlwdHNcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZ1xyXG4gICAqIHRoZSBgaW5kaWNhdG9yU2NyaXB0c2Agb3B0aW9uLlxyXG4gICAqL1xyXG4gIGluZGljYXRvclNjcmlwdHMoc3RyaWN0Q2hlY2spIHtcclxuICAgIHJldHVybiB2LnN0cmluZ0FycmF5KFxyXG4gICAgICAodmFsdWUpID0+IGluZGljYXRvclNjcmlwdHMudmFsdWUuaW5jbHVkZXModmFsdWUpLFxyXG4gICAgICAnLCcsXHJcbiAgICAgIHN0cmljdENoZWNrXHJcbiAgICApO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgY3VzdG9tU2NyaXB0c2AgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbFxyXG4gICAqIHN0cmljdGVyIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgdGhlIGBzdHJpbmdBcnJheWAgdmFsaWRhdG9yLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIGN1c3RvbVNjcmlwdHNcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZ1xyXG4gICAqIHRoZSBgY3VzdG9tU2NyaXB0c2Agb3B0aW9uLlxyXG4gICAqL1xyXG4gIGN1c3RvbVNjcmlwdHMoc3RyaWN0Q2hlY2spIHtcclxuICAgIHJldHVybiB2LnN0cmluZ0FycmF5KFxyXG4gICAgICAodmFsdWUpID0+IHZhbHVlLnN0YXJ0c1dpdGgoJ2h0dHBzOi8vJykgfHwgdmFsdWUuc3RhcnRzV2l0aCgnaHR0cDovLycpLFxyXG4gICAgICAnLCcsXHJcbiAgICAgIHN0cmljdENoZWNrXHJcbiAgICApO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgaW5maWxlYCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoIGFuIG9wdGlvbmFsIHN0cmljdGVyXHJcbiAgICogY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhhdDpcclxuICAgKlxyXG4gICAqIC0gV2hlbiBgc3RyaWN0Q2hlY2tgIGlzIHRydWUsIHRoZSBzY2hlbWEgd2lsbCBhY2NlcHQgdHJpbW1lZCBzdHJpbmcgdmFsdWVzXHJcbiAgICogdGhhdCBlbmQgd2l0aCAnLmpzb24nIG9yICcuc3ZnJywgYXJlIGF0IGxlYXN0IG9uZSBjaGFyYWN0ZXIgbG9uZyBleGNsdWRpbmdcclxuICAgKiB0aGUgZXh0ZW5zaW9uLCBvciBudWxsLlxyXG4gICAqXHJcbiAgICogLSBXaGVuIGBzdHJpY3RDaGVja2AgaXMgZmFsc2UsIHRoZSBzY2hlbWEgd2lsbCBhY2NlcHQgdHJpbW1lZCBzdHJpbmcgdmFsdWVzXHJcbiAgICogdGhhdCBlbmQgd2l0aCAnLmpzb24nIG9yICcuc3ZnJywgYXJlIGF0IGxlYXN0IG9uZSBjaGFyYWN0ZXIgbG9uZyBleGNsdWRpbmdcclxuICAgKiB0aGUgZXh0ZW5zaW9uIGFuZCB3aWxsIGJlIG51bGwgaWYgdGhlIHByb3ZpZGVkIHZhbHVlIGlzIG51bGwsICd1bmRlZmluZWQnLFxyXG4gICAqICdudWxsJywgb3IgJycuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gaW5maWxlXHJcbiAgICpcclxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IHN0cmljdENoZWNrIC0gRGV0ZXJtaW5lcyBpZiBzdHJpY3RlciB2YWxpZGF0aW9uIHNob3VsZFxyXG4gICAqIGJlIGFwcGxpZWQuXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9IEEgWm9kIHNjaGVtYSBvYmplY3QgZm9yIHZhbGlkYXRpbmcgdGhlIGBpbmZpbGVgXHJcbiAgICogb3B0aW9uLlxyXG4gICAqL1xyXG4gIGluZmlsZShzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHN0cmljdENoZWNrXHJcbiAgICAgID8gelxyXG4gICAgICAgICAgLnN0cmluZygpXHJcbiAgICAgICAgICAudHJpbSgpXHJcbiAgICAgICAgICAucmVmaW5lKFxyXG4gICAgICAgICAgICAodmFsdWUpID0+XHJcbiAgICAgICAgICAgICAgKHZhbHVlLmxlbmd0aCA+PSA2ICYmIHZhbHVlLmVuZHNXaXRoKCcuanNvbicpKSB8fFxyXG4gICAgICAgICAgICAgICh2YWx1ZS5sZW5ndGggPj0gNSAmJiB2YWx1ZS5lbmRzV2l0aCgnLnN2ZycpKSxcclxuICAgICAgICAgICAge1xyXG4gICAgICAgICAgICAgIHBhcmFtczoge1xyXG4gICAgICAgICAgICAgICAgZXJyb3JNZXNzYWdlOlxyXG4gICAgICAgICAgICAgICAgICAnVGhlIHZhbHVlIG11c3QgYmUgYSBzdHJpbmcgdGhhdCBlbmRzIHdpdGggLmpzb24gb3IgLnN2ZydcclxuICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgIH1cclxuICAgICAgICAgIClcclxuICAgICAgICAgIC5udWxsYWJsZSgpXHJcbiAgICAgIDogelxyXG4gICAgICAgICAgLnN0cmluZygpXHJcbiAgICAgICAgICAudHJpbSgpXHJcbiAgICAgICAgICAucmVmaW5lKFxyXG4gICAgICAgICAgICAodmFsdWUpID0+XHJcbiAgICAgICAgICAgICAgKHZhbHVlLmxlbmd0aCA+PSA2ICYmIHZhbHVlLmVuZHNXaXRoKCcuanNvbicpKSB8fFxyXG4gICAgICAgICAgICAgICh2YWx1ZS5sZW5ndGggPj0gNSAmJiB2YWx1ZS5lbmRzV2l0aCgnLnN2ZycpKSB8fFxyXG4gICAgICAgICAgICAgIFsndW5kZWZpbmVkJywgJ251bGwnLCAnJ10uaW5jbHVkZXModmFsdWUpLFxyXG4gICAgICAgICAgICB7XHJcbiAgICAgICAgICAgICAgcGFyYW1zOiB7XHJcbiAgICAgICAgICAgICAgICBlcnJvck1lc3NhZ2U6XHJcbiAgICAgICAgICAgICAgICAgICdUaGUgdmFsdWUgbXVzdCBiZSBhIHN0cmluZyB0aGF0IGVuZHMgd2l0aCAuanNvbiBvciAuc3ZnJ1xyXG4gICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgfVxyXG4gICAgICAgICAgKVxyXG4gICAgICAgICAgLnRyYW5zZm9ybSgodmFsdWUpID0+XHJcbiAgICAgICAgICAgICFbJ3VuZGVmaW5lZCcsICdudWxsJywgJyddLmluY2x1ZGVzKHZhbHVlKSA/IHZhbHVlIDogbnVsbFxyXG4gICAgICAgICAgKVxyXG4gICAgICAgICAgLm51bGxhYmxlKCk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGBpbnN0cmAgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGUgc2FtZSB3b3JrIGFzIHRoZSBgb3B0aW9uc2AgdmFsaWRhdG9yLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIGluc3RyXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9IEEgWm9kIHNjaGVtYSBvYmplY3QgZm9yIHZhbGlkYXRpbmcgdGhlIGBpbnN0cmBcclxuICAgKiBvcHRpb24uXHJcbiAgICovXHJcbiAgaW5zdHIoKSB7XHJcbiAgICByZXR1cm4gdi5jaGFydENvbmZpZygpO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgb3B0aW9uc2AgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGUgc2FtZSB3b3JrIGFzIHRoZSBgb3B0aW9uc2AgdmFsaWRhdG9yLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIG9wdGlvbnNcclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZyB0aGUgYG9wdGlvbnNgXHJcbiAgICogb3B0aW9uLlxyXG4gICAqL1xyXG4gIG9wdGlvbnMoKSB7XHJcbiAgICByZXR1cm4gdi5jaGFydENvbmZpZygpO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgc3ZnYCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYS5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoYXQgdGhlIHNjaGVtYSB3aWxsIGFjY2VwdCBvYmplY3QgdmFsdWVzXHJcbiAgICogb3IgdHJpbW1lZCBzdHJpbmcgdmFsdWVzIHRoYXQgY29udGFpbiAnPHN2Zycgb3IgJzw/eG1sJyBlbGVtZW50cyBhbmQgbnVsbC5cclxuICAgKiBUaGUgJ3VuZGVmaW5lZCcsICdudWxsJywgYW5kICcnIHZhbHVlcyB3aWxsIGJlIHRyYW5zZm9ybWVkIHRvIG51bGwuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gc3ZnXHJcbiAgICpcclxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IHN0cmljdENoZWNrIC0gRGV0ZXJtaW5lcyBpZiBzdHJpY3RlciB2YWxpZGF0aW9uIHNob3VsZFxyXG4gICAqIGJlIGFwcGxpZWQuXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9IEEgWm9kIHNjaGVtYSBvYmplY3QgZm9yIHZhbGlkYXRpbmcgdGhlIGBzdmdgIG9wdGlvbi5cclxuICAgKi9cclxuICBzdmcoKSB7XHJcbiAgICByZXR1cm4gelxyXG4gICAgICAuc3RyaW5nKClcclxuICAgICAgLnRyaW0oKVxyXG4gICAgICAucmVmaW5lKFxyXG4gICAgICAgICh2YWx1ZSkgPT5cclxuICAgICAgICAgIHZhbHVlLmluZGV4T2YoJzxzdmcnKSA+PSAwIHx8XHJcbiAgICAgICAgICB2YWx1ZS5pbmRleE9mKCc8P3htbCcpID49IDAgfHxcclxuICAgICAgICAgIFsnZmFsc2UnLCAndW5kZWZpbmVkJywgJ251bGwnLCAnJ10uaW5jbHVkZXModmFsdWUpLFxyXG4gICAgICAgIHtcclxuICAgICAgICAgIHBhcmFtczoge1xyXG4gICAgICAgICAgICBlcnJvck1lc3NhZ2U6XHJcbiAgICAgICAgICAgICAgXCJUaGUgdmFsdWUgbXVzdCBiZSBhIHN0cmluZyB0aGF0IGNvbnRhaW5zICc8c3ZnJyBvciAnPD94bWwnXCJcclxuICAgICAgICAgIH1cclxuICAgICAgICB9XHJcbiAgICAgIClcclxuICAgICAgLnRyYW5zZm9ybSgodmFsdWUpID0+XHJcbiAgICAgICAgIVsnZmFsc2UnLCAndW5kZWZpbmVkJywgJ251bGwnLCAnJ10uaW5jbHVkZXModmFsdWUpID8gdmFsdWUgOiBudWxsXHJcbiAgICAgIClcclxuICAgICAgLm51bGxhYmxlKCk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGBvdXRmaWxlYCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoIGFuIG9wdGlvbmFsIHN0cmljdGVyXHJcbiAgICogY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhhdDpcclxuICAgKlxyXG4gICAqIC0gV2hlbiBgc3RyaWN0Q2hlY2tgIGlzIHRydWUsIHRoZSBzY2hlbWEgd2lsbCBhY2NlcHQgdHJpbW1lZCBzdHJpbmcgdmFsdWVzXHJcbiAgICogdGhhdCBlbmQgd2l0aCAnLmpwZWcnLCAnLmpwZycsICcucG5nJywgJy5wZGYnLCBvciAnLnN2ZycsIGFyZSBhdCBsZWFzdCBvbmVcclxuICAgKiBjaGFyYWN0ZXIgbG9uZyBleGNsdWRpbmcgdGhlIGV4dGVuc2lvbiwgb3IgbnVsbC5cclxuICAgKlxyXG4gICAqIC0gV2hlbiBgc3RyaWN0Q2hlY2tgIGlzIGZhbHNlLCB0aGUgc2NoZW1hIHdpbGwgYWNjZXB0IHRyaW1tZWQgc3RyaW5nIHZhbHVlc1xyXG4gICAqIHRoYXQgZW5kIHdpdGggJy5qcGVnJywgJy5qcGcnLCAnLnBuZycsICcucGRmJywgb3IgJy5zdmcnLCBhcmUgYXQgbGVhc3Qgb25lXHJcbiAgICogY2hhcmFjdGVyIGxvbmcgZXhjbHVkaW5nIHRoZSBleHRlbnNpb24gYW5kIHdpbGwgYmUgbnVsbCBpZiB0aGUgcHJvdmlkZWRcclxuICAgKiB2YWx1ZSBpcyBudWxsLCAndW5kZWZpbmVkJywgJ251bGwnLCBvciAnJy5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiBvdXRmaWxlXHJcbiAgICpcclxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IHN0cmljdENoZWNrIC0gRGV0ZXJtaW5lcyBpZiBzdHJpY3RlciB2YWxpZGF0aW9uIHNob3VsZFxyXG4gICAqIGJlIGFwcGxpZWQuXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9IEEgWm9kIHNjaGVtYSBvYmplY3QgZm9yIHZhbGlkYXRpbmcgdGhlIGBvdXRmaWxlYFxyXG4gICAqIG9wdGlvbi5cclxuICAgKi9cclxuICBvdXRmaWxlKHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gc3RyaWN0Q2hlY2tcclxuICAgICAgPyB6XHJcbiAgICAgICAgICAuc3RyaW5nKClcclxuICAgICAgICAgIC50cmltKClcclxuICAgICAgICAgIC5yZWZpbmUoXHJcbiAgICAgICAgICAgICh2YWx1ZSkgPT5cclxuICAgICAgICAgICAgICAodmFsdWUubGVuZ3RoID49IDYgJiYgdmFsdWUuZW5kc1dpdGgoJy5qcGVnJykpIHx8XHJcbiAgICAgICAgICAgICAgKHZhbHVlLmxlbmd0aCA+PSA1ICYmXHJcbiAgICAgICAgICAgICAgICAodmFsdWUuZW5kc1dpdGgoJy5qcGcnKSB8fFxyXG4gICAgICAgICAgICAgICAgICB2YWx1ZS5lbmRzV2l0aCgnLnBuZycpIHx8XHJcbiAgICAgICAgICAgICAgICAgIHZhbHVlLmVuZHNXaXRoKCcucGRmJykgfHxcclxuICAgICAgICAgICAgICAgICAgdmFsdWUuZW5kc1dpdGgoJy5zdmcnKSkpLFxyXG4gICAgICAgICAgICB7XHJcbiAgICAgICAgICAgICAgcGFyYW1zOiB7XHJcbiAgICAgICAgICAgICAgICBlcnJvck1lc3NhZ2U6XHJcbiAgICAgICAgICAgICAgICAgICdUaGUgdmFsdWUgbXVzdCBiZSBhIHN0cmluZyB0aGF0IGVuZHMgd2l0aCAuanBlZywgLmpwZywgLnBuZywgLnBkZiwgb3IgLnN2ZydcclxuICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgIH1cclxuICAgICAgICAgIClcclxuICAgICAgICAgIC5udWxsYWJsZSgpXHJcbiAgICAgIDogelxyXG4gICAgICAgICAgLnN0cmluZygpXHJcbiAgICAgICAgICAudHJpbSgpXHJcbiAgICAgICAgICAucmVmaW5lKFxyXG4gICAgICAgICAgICAodmFsdWUpID0+XHJcbiAgICAgICAgICAgICAgKHZhbHVlLmxlbmd0aCA+PSA2ICYmIHZhbHVlLmVuZHNXaXRoKCcuanBlZycpKSB8fFxyXG4gICAgICAgICAgICAgICh2YWx1ZS5sZW5ndGggPj0gNSAmJlxyXG4gICAgICAgICAgICAgICAgKHZhbHVlLmVuZHNXaXRoKCcuanBnJykgfHxcclxuICAgICAgICAgICAgICAgICAgdmFsdWUuZW5kc1dpdGgoJy5wbmcnKSB8fFxyXG4gICAgICAgICAgICAgICAgICB2YWx1ZS5lbmRzV2l0aCgnLnBkZicpIHx8XHJcbiAgICAgICAgICAgICAgICAgIHZhbHVlLmVuZHNXaXRoKCcuc3ZnJykpKSB8fFxyXG4gICAgICAgICAgICAgIFsndW5kZWZpbmVkJywgJ251bGwnLCAnJ10uaW5jbHVkZXModmFsdWUpLFxyXG4gICAgICAgICAgICB7XHJcbiAgICAgICAgICAgICAgcGFyYW1zOiB7XHJcbiAgICAgICAgICAgICAgICBlcnJvck1lc3NhZ2U6XHJcbiAgICAgICAgICAgICAgICAgICdUaGUgdmFsdWUgbXVzdCBiZSBhIHN0cmluZyB0aGF0IGVuZHMgd2l0aCAuanBlZywgLmpwZywgLnBuZywgLnBkZiwgb3IgLnN2ZydcclxuICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgIH1cclxuICAgICAgICAgIClcclxuICAgICAgICAgIC50cmFuc2Zvcm0oKHZhbHVlKSA9PlxyXG4gICAgICAgICAgICAhWyd1bmRlZmluZWQnLCAnbnVsbCcsICcnXS5pbmNsdWRlcyh2YWx1ZSkgPyB2YWx1ZSA6IG51bGxcclxuICAgICAgICAgIClcclxuICAgICAgICAgIC5udWxsYWJsZSgpO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgdHlwZWAgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbCBzdHJpY3RlclxyXG4gICAqIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgdGhlIGBlbnVtYCB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gdHlwZVxyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nIHRoZSBgdHlwZWBcclxuICAgKiBvcHRpb24uXHJcbiAgICovXHJcbiAgdHlwZShzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHYuZW51bShbJ2pwZWcnLCAnanBnJywgJ3BuZycsICdwZGYnLCAnc3ZnJ10sIHN0cmljdENoZWNrKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYGNvbnN0cmAgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbCBzdHJpY3RlclxyXG4gICAqIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgdGhlIGBlbnVtYCB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gY29uc3RyXHJcbiAgICpcclxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IHN0cmljdENoZWNrIC0gRGV0ZXJtaW5lcyBpZiBzdHJpY3RlciB2YWxpZGF0aW9uIHNob3VsZFxyXG4gICAqIGJlIGFwcGxpZWQuXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9IEEgWm9kIHNjaGVtYSBvYmplY3QgZm9yIHZhbGlkYXRpbmcgdGhlIGBjb25zdHJgXHJcbiAgICogb3B0aW9uLlxyXG4gICAqL1xyXG4gIGNvbnN0cihzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHYuZW51bShcclxuICAgICAgWydjaGFydCcsICdzdG9ja0NoYXJ0JywgJ21hcENoYXJ0JywgJ2dhbnR0Q2hhcnQnXSxcclxuICAgICAgc3RyaWN0Q2hlY2tcclxuICAgICk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGBiNjRgIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGggYW4gb3B0aW9uYWwgc3RyaWN0ZXJcclxuICAgKiBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGUgc2FtZSB3b3JrIGFzIHRoZSBgYm9vbGVhbmAgdmFsaWRhdG9yLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIGI2NFxyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nIHRoZSBgYjY0YCBvcHRpb24uXHJcbiAgICovXHJcbiAgYjY0KHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gdi5ib29sZWFuKHN0cmljdENoZWNrKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYG5vRG93bmxvYWRgIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGggYW4gb3B0aW9uYWxcclxuICAgKiBzdHJpY3RlciBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGUgc2FtZSB3b3JrIGFzIHRoZSBgYm9vbGVhbmAgdmFsaWRhdG9yLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIG5vRG93bmxvYWRcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZyB0aGUgYG5vRG93bmxvYWRgXHJcbiAgICogb3B0aW9uLlxyXG4gICAqL1xyXG4gIG5vRG93bmxvYWQoc3RyaWN0Q2hlY2spIHtcclxuICAgIHJldHVybiB2LmJvb2xlYW4oc3RyaWN0Q2hlY2spO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgZGVmYXVsdEhlaWdodGAgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbFxyXG4gICAqIHN0cmljdGVyIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgdGhlIGBwb3NpdGl2ZU51bWAgdmFsaWRhdG9yLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIGRlZmF1bHRIZWlnaHRcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZ1xyXG4gICAqIHRoZSBgZGVmYXVsdEhlaWdodGAgb3B0aW9uLlxyXG4gICAqL1xyXG4gIGRlZmF1bHRIZWlnaHQoc3RyaWN0Q2hlY2spIHtcclxuICAgIHJldHVybiB2LnBvc2l0aXZlTnVtKHN0cmljdENoZWNrKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYGRlZmF1bHRXaWR0aGAgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbFxyXG4gICAqIHN0cmljdGVyIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgdGhlIGBwb3NpdGl2ZU51bWAgdmFsaWRhdG9yLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIGRlZmF1bHRXaWR0aFxyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nXHJcbiAgICogdGhlIGBkZWZhdWx0V2lkdGhgIG9wdGlvbi5cclxuICAgKi9cclxuICBkZWZhdWx0V2lkdGgoc3RyaWN0Q2hlY2spIHtcclxuICAgIHJldHVybiB2LnBvc2l0aXZlTnVtKHN0cmljdENoZWNrKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYGRlZmF1bHRTY2FsZWAgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbFxyXG4gICAqIHN0cmljdGVyIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoYXQ6XHJcbiAgICpcclxuICAgKiAtIFdoZW4gYHN0cmljdENoZWNrYCBpcyB0cnVlLCB0aGUgc2NoZW1hIHdpbGwgYWNjZXB0IG51bWJlciB2YWx1ZXMgdGhhdFxyXG4gICAqIGFyZSBiZXR3ZWVuIDAuMSBhbmQgNSAoaW5jbHVzaXZlKS5cclxuICAgKlxyXG4gICAqIC0gV2hlbiBgc3RyaWN0Q2hlY2tgIGlzIGZhbHNlLCB0aGUgc2NoZW1hIHdpbGwgYWNjZXB0IG51bWJlciB2YWx1ZXNcclxuICAgKiBhbmQgc3RyaW5naWZpZWQgbnVtYmVyIHZhbHVlcyB0aGF0IGFyZSBiZXR3ZWVuIDAuMSBhbmQgNSAoaW5jbHVzaXZlKSwgbnVsbCxcclxuICAgKiAndW5kZWZpbmVkJywgJ251bGwnLCBhbmQgJycgd2hpY2ggd2lsbCBiZSB0cmFuc2Zvcm1lZCB0byBudWxsLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIGRlZmF1bHRTY2FsZVxyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nXHJcbiAgICogdGhlIGBkZWZhdWx0U2NhbGVgIG9wdGlvbi5cclxuICAgKi9cclxuICBkZWZhdWx0U2NhbGUoc3RyaWN0Q2hlY2spIHtcclxuICAgIHJldHVybiBzdHJpY3RDaGVja1xyXG4gICAgICA/IHoubnVtYmVyKCkuZ3RlKDAuMSkubHRlKDUpXHJcbiAgICAgIDogelxyXG4gICAgICAgICAgLnVuaW9uKFtcclxuICAgICAgICAgICAgelxyXG4gICAgICAgICAgICAgIC5zdHJpbmcoKVxyXG4gICAgICAgICAgICAgIC50cmltKClcclxuICAgICAgICAgICAgICAucmVmaW5lKFxyXG4gICAgICAgICAgICAgICAgKHZhbHVlKSA9PlxyXG4gICAgICAgICAgICAgICAgICAoIWlzTmFOKE51bWJlcih2YWx1ZSkpICYmXHJcbiAgICAgICAgICAgICAgICAgICAgdmFsdWUgIT09IHRydWUgJiZcclxuICAgICAgICAgICAgICAgICAgICAhdmFsdWUuc3RhcnRzV2l0aCgnWycpICYmXHJcbiAgICAgICAgICAgICAgICAgICAgTnVtYmVyKHZhbHVlKSA+PSAwLjEgJiZcclxuICAgICAgICAgICAgICAgICAgICBOdW1iZXIodmFsdWUpIDw9IDUpIHx8XHJcbiAgICAgICAgICAgICAgICAgIFsndW5kZWZpbmVkJywgJ251bGwnLCAnJ10uaW5jbHVkZXModmFsdWUpLFxyXG4gICAgICAgICAgICAgICAge1xyXG4gICAgICAgICAgICAgICAgICBwYXJhbXM6IHtcclxuICAgICAgICAgICAgICAgICAgICBlcnJvck1lc3NhZ2U6ICdUaGUgdmFsdWUgbXVzdCBiZSB3aXRoaW4gYSAwLjEgYW5kIDUuMCByYW5nZSdcclxuICAgICAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICAgIClcclxuICAgICAgICAgICAgICAudHJhbnNmb3JtKCh2YWx1ZSkgPT5cclxuICAgICAgICAgICAgICAgICFbJ3VuZGVmaW5lZCcsICdudWxsJywgJyddLmluY2x1ZGVzKHZhbHVlKVxyXG4gICAgICAgICAgICAgICAgICA/IE51bWJlcih2YWx1ZSlcclxuICAgICAgICAgICAgICAgICAgOiBudWxsXHJcbiAgICAgICAgICAgICAgKSxcclxuICAgICAgICAgICAgei5udW1iZXIoKS5ndGUoMC4xKS5sdGUoNSlcclxuICAgICAgICAgIF0pXHJcbiAgICAgICAgICAubnVsbGFibGUoKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYGhlaWdodGAgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbCBzdHJpY3RlclxyXG4gICAqIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgYSBudWxsYWJsZSBgZGVmYXVsdEhlaWdodGBcclxuICAgKiB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gaGVpZ2h0XHJcbiAgICpcclxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IHN0cmljdENoZWNrIC0gRGV0ZXJtaW5lcyBpZiBzdHJpY3RlciB2YWxpZGF0aW9uIHNob3VsZFxyXG4gICAqIGJlIGFwcGxpZWQuXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9IEEgWm9kIHNjaGVtYSBvYmplY3QgZm9yIHZhbGlkYXRpbmcgdGhlIGBoZWlnaHRgXHJcbiAgICogb3B0aW9uLlxyXG4gICAqL1xyXG4gIGhlaWdodChzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHRoaXMuZGVmYXVsdEhlaWdodChzdHJpY3RDaGVjaykubnVsbGFibGUoKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYHdpZHRoYCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoIGFuIG9wdGlvbmFsIHN0cmljdGVyXHJcbiAgICogY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhlIHNhbWUgd29yayBhcyBhIG51bGxhYmxlIGBkZWZhdWx0V2lkdGhgXHJcbiAgICogdmFsaWRhdG9yLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIHdpZHRoXHJcbiAgICpcclxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IHN0cmljdENoZWNrIC0gRGV0ZXJtaW5lcyBpZiBzdHJpY3RlciB2YWxpZGF0aW9uIHNob3VsZFxyXG4gICAqIGJlIGFwcGxpZWQuXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9IEEgWm9kIHNjaGVtYSBvYmplY3QgZm9yIHZhbGlkYXRpbmcgdGhlIGB3aWR0aGBcclxuICAgKiBvcHRpb24uXHJcbiAgICovXHJcbiAgd2lkdGgoc3RyaWN0Q2hlY2spIHtcclxuICAgIHJldHVybiB0aGlzLmRlZmF1bHRXaWR0aChzdHJpY3RDaGVjaykubnVsbGFibGUoKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYHNjYWxlYCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoIGFuIG9wdGlvbmFsIHN0cmljdGVyXHJcbiAgICogY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhlIHNhbWUgd29yayBhcyBhIG51bGxhYmxlIGBkZWZhdWx0U2NhbGVgXHJcbiAgICogdmFsaWRhdG9yLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIHNjYWxlXHJcbiAgICpcclxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IHN0cmljdENoZWNrIC0gRGV0ZXJtaW5lcyBpZiBzdHJpY3RlciB2YWxpZGF0aW9uIHNob3VsZFxyXG4gICAqIGJlIGFwcGxpZWQuXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9IEEgWm9kIHNjaGVtYSBvYmplY3QgZm9yIHZhbGlkYXRpbmcgdGhlIGBzY2FsZWBcclxuICAgKiBvcHRpb24uXHJcbiAgICovXHJcbiAgc2NhbGUoc3RyaWN0Q2hlY2spIHtcclxuICAgIHJldHVybiB0aGlzLmRlZmF1bHRTY2FsZShzdHJpY3RDaGVjaykubnVsbGFibGUoKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYGdsb2JhbE9wdGlvbnNgIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhlIHNhbWUgd29yayBhcyB0aGUgYGFkZGl0aW9uYWxPcHRpb25zYFxyXG4gICAqIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiBnbG9iYWxPcHRpb25zXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9IEEgWm9kIHNjaGVtYSBvYmplY3QgZm9yIHZhbGlkYXRpbmdcclxuICAgKiB0aGUgYGdsb2JhbE9wdGlvbnNgIG9wdGlvbi5cclxuICAgKi9cclxuICBnbG9iYWxPcHRpb25zKCkge1xyXG4gICAgcmV0dXJuIHYuYWRkaXRpb25hbE9wdGlvbnMoKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYHRoZW1lT3B0aW9uc2AgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGUgc2FtZSB3b3JrIGFzIHRoZSBgYWRkaXRpb25hbE9wdGlvbnNgXHJcbiAgICogdmFsaWRhdG9yLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIHRoZW1lT3B0aW9uc1xyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nXHJcbiAgICogdGhlIGB0aGVtZU9wdGlvbnNgIG9wdGlvbi5cclxuICAgKi9cclxuICB0aGVtZU9wdGlvbnMoKSB7XHJcbiAgICByZXR1cm4gdi5hZGRpdGlvbmFsT3B0aW9ucygpO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgYmF0Y2hgIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGggYW4gb3B0aW9uYWwgc3RyaWN0ZXJcclxuICAgKiBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGUgc2FtZSB3b3JrIGFzIHRoZSBgc3RyaW5nYCB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gYmF0Y2hcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZyB0aGUgYGJhdGNoYFxyXG4gICAqIG9wdGlvbi5cclxuICAgKi9cclxuICBiYXRjaChzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHYuc3RyaW5nKHN0cmljdENoZWNrKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYHJhc3Rlcml6YXRpb25UaW1lb3V0YCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoXHJcbiAgICogYW4gb3B0aW9uYWwgc3RyaWN0ZXIgY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhlIHNhbWUgd29yayBhcyB0aGUgYG5vbk5lZ2F0aXZlTnVtYFxyXG4gICAqIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiByYXN0ZXJpemF0aW9uVGltZW91dFxyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nXHJcbiAgICogdGhlIGByYXN0ZXJpemF0aW9uVGltZW91dGAgb3B0aW9uLlxyXG4gICAqL1xyXG4gIHJhc3Rlcml6YXRpb25UaW1lb3V0KHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gdi5ub25OZWdhdGl2ZU51bShzdHJpY3RDaGVjayk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGBhbGxvd0NvZGVFeGVjdXRpb25gIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGhcclxuICAgKiBhbiBvcHRpb25hbCBzdHJpY3RlciBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGUgc2FtZSB3b3JrIGFzIHRoZSBgYm9vbGVhbmAgdmFsaWRhdG9yLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIGFsbG93Q29kZUV4ZWN1dGlvblxyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nXHJcbiAgICogdGhlIGBhbGxvd0NvZGVFeGVjdXRpb25gIG9wdGlvbi5cclxuICAgKi9cclxuICBhbGxvd0NvZGVFeGVjdXRpb24oc3RyaWN0Q2hlY2spIHtcclxuICAgIHJldHVybiB2LmJvb2xlYW4oc3RyaWN0Q2hlY2spO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgYWxsb3dGaWxlUmVzb3VyY2VzYCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoXHJcbiAgICogYW4gb3B0aW9uYWwgc3RyaWN0ZXIgY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhlIHNhbWUgd29yayBhcyB0aGUgYGJvb2xlYW5gIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiBhbGxvd0ZpbGVSZXNvdXJjZXNcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZ1xyXG4gICAqIHRoZSBgYWxsb3dGaWxlUmVzb3VyY2VzYCBvcHRpb24uXHJcbiAgICovXHJcbiAgYWxsb3dGaWxlUmVzb3VyY2VzKHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gdi5ib29sZWFuKHN0cmljdENoZWNrKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYGN1c3RvbUNvZGVgIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGggYW4gb3B0aW9uYWxcclxuICAgKiBzdHJpY3RlciBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGUgc2FtZSB3b3JrIGFzIHRoZSBgc3RyaW5nYCB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gY3VzdG9tQ29kZVxyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nIHRoZSBgY3VzdG9tQ29kZWBcclxuICAgKiBvcHRpb24uXHJcbiAgICovXHJcbiAgY3VzdG9tQ29kZShzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHYuc3RyaW5nKHN0cmljdENoZWNrKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYGNhbGxiYWNrYCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoIGFuIG9wdGlvbmFsXHJcbiAgICogc3RyaWN0ZXIgY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhlIHNhbWUgd29yayBhcyB0aGUgYHN0cmluZ2AgdmFsaWRhdG9yLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIGNhbGxiYWNrXHJcbiAgICpcclxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IHN0cmljdENoZWNrIC0gRGV0ZXJtaW5lcyBpZiBzdHJpY3RlciB2YWxpZGF0aW9uIHNob3VsZFxyXG4gICAqIGJlIGFwcGxpZWQuXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9IEEgWm9kIHNjaGVtYSBvYmplY3QgZm9yIHZhbGlkYXRpbmcgdGhlIGBjYWxsYmFja2BcclxuICAgKiBvcHRpb24uXHJcbiAgICovXHJcbiAgY2FsbGJhY2soc3RyaWN0Q2hlY2spIHtcclxuICAgIHJldHVybiB2LnN0cmluZyhzdHJpY3RDaGVjayk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGByZXNvdXJjZXNgIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGggYW4gb3B0aW9uYWxcclxuICAgKiBzdHJpY3RlciBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGF0OlxyXG4gICAqXHJcbiAgICogLSBXaGVuIGBzdHJpY3RDaGVja2AgaXMgdHJ1ZSwgdGhlIHNjaGVtYSB3aWxsIGFjY2VwdCBhIHBhcnRpYWwgb2JqZWN0XHJcbiAgICogd2l0aCBhbGxvd2VkIHByb3BlcnRpZXMgYGpzYCwgYGNzc2AsIGFuZCBgZmlsZXNgIHdoZXJlIGVhY2ggb2YgdGhlIGFsbG93ZWRcclxuICAgKiBwcm9wZXJ0aWVzIGNhbiBiZSBudWxsLCBzdHJpbmdpZmllZCB2ZXJzaW9uIG9mIHRoZSBvYmplY3QsIHN0cmluZyB0aGF0IGVuZHNcclxuICAgKiB3aXRoIHRoZSAnLmpzb24nLCBhbmQgbnVsbC5cclxuICAgKlxyXG4gICAqIC0gV2hlbiBgc3RyaWN0Q2hlY2tgIGlzIGZhbHNlLCB0aGUgc2NoZW1hIHdpbGwgYWNjZXB0IGEgc3RyaW5naWZpZWQgdmVyc2lvblxyXG4gICAqIG9mIGEgcGFydGlhbCBvYmplY3Qgd2l0aCBhbGxvd2VkIHByb3BlcnRpZXMgYGpzYCwgYGNzc2AsIGFuZCBgZmlsZXNgIHdoZXJlXHJcbiAgICogZWFjaCBvZiB0aGUgYWxsb3dlZCBwcm9wZXJ0aWVzIGNhbiBiZSBudWxsLCBzdHJpbmcgdGhhdCBlbmRzIHdpdGggdGhlXHJcbiAgICogJy5qc29uJywgYW5kIHdpbGwgYmUgbnVsbCBpZiB0aGUgcHJvdmlkZWQgdmFsdWUgaXMgJ3VuZGVmaW5lZCcsICdudWxsJ1xyXG4gICAqIG9yICcnLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIHJlc291cmNlc1xyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nIHRoZSBgcmVzb3VyY2VzYFxyXG4gICAqIG9wdGlvbi5cclxuICAgKi9cclxuICByZXNvdXJjZXMoc3RyaWN0Q2hlY2spIHtcclxuICAgIGNvbnN0IG9iamVjdFNjaGVtYSA9IHpcclxuICAgICAgLm9iamVjdCh7XHJcbiAgICAgICAganM6IHYuc3RyaW5nKGZhbHNlKSxcclxuICAgICAgICBjc3M6IHYuc3RyaW5nKGZhbHNlKSxcclxuICAgICAgICBmaWxlczogdlxyXG4gICAgICAgICAgLnN0cmluZ0FycmF5KFxyXG4gICAgICAgICAgICAodmFsdWUpID0+ICFbJ3VuZGVmaW5lZCcsICdudWxsJywgJyddLmluY2x1ZGVzKHZhbHVlKSxcclxuICAgICAgICAgICAgJywnLFxyXG4gICAgICAgICAgICB0cnVlXHJcbiAgICAgICAgICApXHJcbiAgICAgICAgICAubnVsbGFibGUoKVxyXG4gICAgICB9KVxyXG4gICAgICAucGFydGlhbCgpO1xyXG5cclxuICAgIGNvbnN0IHN0cmluZ1NjaGVtYTEgPSB6XHJcbiAgICAgIC5zdHJpbmcoKVxyXG4gICAgICAudHJpbSgpXHJcbiAgICAgIC5yZWZpbmUoXHJcbiAgICAgICAgKHZhbHVlKSA9PlxyXG4gICAgICAgICAgKHZhbHVlLnN0YXJ0c1dpdGgoJ3snKSAmJiB2YWx1ZS5lbmRzV2l0aCgnfScpKSB8fFxyXG4gICAgICAgICAgKHZhbHVlLmxlbmd0aCA+PSA2ICYmIHZhbHVlLmVuZHNXaXRoKCcuanNvbicpKSxcclxuICAgICAgICB7XHJcbiAgICAgICAgICBwYXJhbXM6IHtcclxuICAgICAgICAgICAgZXJyb3JNZXNzYWdlOlxyXG4gICAgICAgICAgICAgIFwiVGhlIHZhbHVlIG11c3QgYmUgYSBzdHJpbmcgdGhhdCBzdGFydHMgd2l0aCAneycgYW5kIGVuZHMgd2l0aCAnfVwiXHJcbiAgICAgICAgICB9XHJcbiAgICAgICAgfVxyXG4gICAgICApO1xyXG5cclxuICAgIGNvbnN0IHN0cmluZ1NjaGVtYTIgPSB6XHJcbiAgICAgIC5zdHJpbmcoKVxyXG4gICAgICAudHJpbSgpXHJcbiAgICAgIC5yZWZpbmUoXHJcbiAgICAgICAgKHZhbHVlKSA9PlxyXG4gICAgICAgICAgKHZhbHVlLnN0YXJ0c1dpdGgoJ3snKSAmJiB2YWx1ZS5lbmRzV2l0aCgnfScpKSB8fFxyXG4gICAgICAgICAgKHZhbHVlLmxlbmd0aCA+PSA2ICYmIHZhbHVlLmVuZHNXaXRoKCcuanNvbicpKSB8fFxyXG4gICAgICAgICAgWyd1bmRlZmluZWQnLCAnbnVsbCcsICcnXS5pbmNsdWRlcyh2YWx1ZSksXHJcbiAgICAgICAge1xyXG4gICAgICAgICAgcGFyYW1zOiB7XHJcbiAgICAgICAgICAgIGVycm9yTWVzc2FnZTogJ1RoZSB2YWx1ZSBtdXN0IGJlIGEgc3RyaW5nIHRoYXQgZW5kcyB3aXRoIC5qc29uJ1xyXG4gICAgICAgICAgfVxyXG4gICAgICAgIH1cclxuICAgICAgKVxyXG4gICAgICAudHJhbnNmb3JtKCh2YWx1ZSkgPT5cclxuICAgICAgICAhWyd1bmRlZmluZWQnLCAnbnVsbCcsICcnXS5pbmNsdWRlcyh2YWx1ZSkgPyB2YWx1ZSA6IG51bGxcclxuICAgICAgKTtcclxuXHJcbiAgICByZXR1cm4gc3RyaWN0Q2hlY2tcclxuICAgICAgPyB6LnVuaW9uKFtvYmplY3RTY2hlbWEsIHN0cmluZ1NjaGVtYTFdKS5udWxsYWJsZSgpXHJcbiAgICAgIDogei51bmlvbihbb2JqZWN0U2NoZW1hLCBzdHJpbmdTY2hlbWEyXSkubnVsbGFibGUoKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYGxvYWRDb25maWdgIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGggYW4gb3B0aW9uYWxcclxuICAgKiBzdHJpY3RlciBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGUgc2FtZSB3b3JrIGFzIHRoZSBgc3RyaW5nYCB2YWxpZGF0b3IuXHJcbiAgICogQWRkaXRpb25hbGx5LCBpdCBtdXN0IGJlIGEgc3RyaW5nIHRoYXQgZW5kcyB3aXRoICcuanNvbicuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gbG9hZENvbmZpZ1xyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nIHRoZSBgbG9hZENvbmZpZ2BcclxuICAgKiBvcHRpb24uXHJcbiAgICovXHJcbiAgbG9hZENvbmZpZyhzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHZcclxuICAgICAgLnN0cmluZyhzdHJpY3RDaGVjaylcclxuICAgICAgLnJlZmluZShcclxuICAgICAgICAodmFsdWUpID0+XHJcbiAgICAgICAgICB2YWx1ZSA9PT0gbnVsbCB8fCAodmFsdWUubGVuZ3RoID49IDYgJiYgdmFsdWUuZW5kc1dpdGgoJy5qc29uJykpLFxyXG4gICAgICAgIHtcclxuICAgICAgICAgIHBhcmFtczoge1xyXG4gICAgICAgICAgICBlcnJvck1lc3NhZ2U6ICdUaGUgdmFsdWUgbXVzdCBiZSBhIHN0cmluZyB0aGF0IGVuZHMgd2l0aCAuanNvbidcclxuICAgICAgICAgIH1cclxuICAgICAgICB9XHJcbiAgICAgICk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGBjcmVhdGVDb25maWdgIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGggYW4gb3B0aW9uYWxcclxuICAgKiBzdHJpY3RlciBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGUgc2FtZSB3b3JrIGFzIHRoZSBgbG9hZENvbmZpZ2AgdmFsaWRhdG9yLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIGNyZWF0ZUNvbmZpZ1xyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nXHJcbiAgICogdGhlIGBjcmVhdGVDb25maWdgIG9wdGlvbi5cclxuICAgKi9cclxuICBjcmVhdGVDb25maWcoc3RyaWN0Q2hlY2spIHtcclxuICAgIHJldHVybiB0aGlzLmxvYWRDb25maWcoc3RyaWN0Q2hlY2spO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgZW5hYmxlU2VydmVyYCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoIGFuIG9wdGlvbmFsXHJcbiAgICogc3RyaWN0ZXIgY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhlIHNhbWUgd29yayBhcyB0aGUgYGJvb2xlYW5gIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiBlbmFibGVTZXJ2ZXJcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZ1xyXG4gICAqIHRoZSBgZW5hYmxlU2VydmVyYCBvcHRpb24uXHJcbiAgICovXHJcbiAgZW5hYmxlU2VydmVyKHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gdi5ib29sZWFuKHN0cmljdENoZWNrKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYGhvc3RgIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGggYW4gb3B0aW9uYWwgc3RyaWN0ZXJcclxuICAgKiBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGUgc2FtZSB3b3JrIGFzIHRoZSBgc3RyaW5nYCB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gaG9zdFxyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nIHRoZSBgaG9zdGBcclxuICAgKiBvcHRpb24uXHJcbiAgICovXHJcbiAgaG9zdChzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHYuc3RyaW5nKHN0cmljdENoZWNrKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYHBvcnRgIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGggYW4gb3B0aW9uYWwgc3RyaWN0ZXJcclxuICAgKiBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGUgc2FtZSB3b3JrIGFzIHRoZSBgbm9uTmVnYXRpdmVOdW1gXHJcbiAgICogdmFsaWRhdG9yLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIHBvcnRcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZyB0aGUgYHBvcnRgXHJcbiAgICogb3B0aW9uLlxyXG4gICAqL1xyXG4gIHBvcnQoc3RyaWN0Q2hlY2spIHtcclxuICAgIHJldHVybiB2Lm5vbk5lZ2F0aXZlTnVtKHN0cmljdENoZWNrKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYHVwbG9hZExpbWl0YCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoIGFuIG9wdGlvbmFsXHJcbiAgICogc3RyaWN0ZXIgY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhlIHNhbWUgd29yayBhcyB0aGUgYHBvc2l0aXZlTnVtYCB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gdXBsb2FkTGltaXRcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZyB0aGUgYHVwbG9hZExpbWl0YFxyXG4gICAqIG9wdGlvbi5cclxuICAgKi9cclxuICB1cGxvYWRMaW1pdChzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHYucG9zaXRpdmVOdW0oc3RyaWN0Q2hlY2spO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgc2VydmVyQmVuY2htYXJraW5nYCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoXHJcbiAgICogYW4gb3B0aW9uYWwgc3RyaWN0ZXIgY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhlIHNhbWUgd29yayBhcyB0aGUgYGJvb2xlYW5gIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiBzZXJ2ZXJCZW5jaG1hcmtpbmdcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZ1xyXG4gICAqIHRoZSBgc2VydmVyQmVuY2htYXJraW5nYCBvcHRpb24uXHJcbiAgICovXHJcbiAgc2VydmVyQmVuY2htYXJraW5nKHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gdi5ib29sZWFuKHN0cmljdENoZWNrKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYHByb3h5SG9zdGAgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbFxyXG4gICAqIHN0cmljdGVyIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgdGhlIGBzdHJpbmdgIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiBwcm94eUhvc3RcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZyB0aGUgYHByb3h5SG9zdGBcclxuICAgKiBvcHRpb24uXHJcbiAgICovXHJcbiAgcHJveHlIb3N0KHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gdi5zdHJpbmcoc3RyaWN0Q2hlY2spO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgcHJveHlQb3J0YCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoIGFuIG9wdGlvbmFsXHJcbiAgICogc3RyaWN0ZXIgY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhlIHNhbWUgd29yayBhcyBhIG51bGxhYmxlIGBub25OZWdhdGl2ZU51bWBcclxuICAgKiB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gcHJveHlQb3J0XHJcbiAgICpcclxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IHN0cmljdENoZWNrIC0gRGV0ZXJtaW5lcyBpZiBzdHJpY3RlciB2YWxpZGF0aW9uIHNob3VsZFxyXG4gICAqIGJlIGFwcGxpZWQuXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9IEEgWm9kIHNjaGVtYSBvYmplY3QgZm9yIHZhbGlkYXRpbmcgdGhlIGBwcm94eVBvcnRgXHJcbiAgICogb3B0aW9uLlxyXG4gICAqL1xyXG4gIHByb3h5UG9ydChzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHYubm9uTmVnYXRpdmVOdW0oc3RyaWN0Q2hlY2spLm51bGxhYmxlKCk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGBwcm94eVRpbWVvdXRgIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGggYW4gb3B0aW9uYWxcclxuICAgKiBzdHJpY3RlciBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGUgc2FtZSB3b3JrIGFzIHRoZSBgbm9uTmVnYXRpdmVOdW1gXHJcbiAgICogdmFsaWRhdG9yLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIHByb3h5VGltZW91dFxyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nXHJcbiAgICogdGhlIGBwcm94eVRpbWVvdXRgIG9wdGlvbi5cclxuICAgKi9cclxuICBwcm94eVRpbWVvdXQoc3RyaWN0Q2hlY2spIHtcclxuICAgIHJldHVybiB2Lm5vbk5lZ2F0aXZlTnVtKHN0cmljdENoZWNrKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYGVuYWJsZVJhdGVMaW1pdGluZ2AgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aFxyXG4gICAqIGFuIG9wdGlvbmFsIHN0cmljdGVyIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgdGhlIGBib29sZWFuYCB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gZW5hYmxlUmF0ZUxpbWl0aW5nXHJcbiAgICpcclxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IHN0cmljdENoZWNrIC0gRGV0ZXJtaW5lcyBpZiBzdHJpY3RlciB2YWxpZGF0aW9uIHNob3VsZFxyXG4gICAqIGJlIGFwcGxpZWQuXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9IEEgWm9kIHNjaGVtYSBvYmplY3QgZm9yIHZhbGlkYXRpbmdcclxuICAgKiB0aGUgYGVuYWJsZVJhdGVMaW1pdGluZ2Agb3B0aW9uLlxyXG4gICAqL1xyXG4gIGVuYWJsZVJhdGVMaW1pdGluZyhzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHYuYm9vbGVhbihzdHJpY3RDaGVjayk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGBtYXhSZXF1ZXN0c2AgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbFxyXG4gICAqIHN0cmljdGVyIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgdGhlIGBub25OZWdhdGl2ZU51bWBcclxuICAgKiB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gbWF4UmVxdWVzdHNcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZyB0aGUgYG1heFJlcXVlc3RzYFxyXG4gICAqIG9wdGlvbi5cclxuICAgKi9cclxuICBtYXhSZXF1ZXN0cyhzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHYubm9uTmVnYXRpdmVOdW0oc3RyaWN0Q2hlY2spO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgd2luZG93YCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoIGFuIG9wdGlvbmFsIHN0cmljdGVyXHJcbiAgICogY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhlIHNhbWUgd29yayBhcyB0aGUgYG5vbk5lZ2F0aXZlTnVtYFxyXG4gICAqIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiB3aW5kb3dcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZyB0aGUgYHdpbmRvd2BcclxuICAgKiBvcHRpb24uXHJcbiAgICovXHJcbiAgd2luZG93KHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gdi5ub25OZWdhdGl2ZU51bShzdHJpY3RDaGVjayk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGBkZWxheWAgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbCBzdHJpY3RlclxyXG4gICAqIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgdGhlIGBub25OZWdhdGl2ZU51bWBcclxuICAgKiB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gZGVsYXlcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZyB0aGUgYGRlbGF5YFxyXG4gICAqIG9wdGlvbi5cclxuICAgKi9cclxuICBkZWxheShzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHYubm9uTmVnYXRpdmVOdW0oc3RyaWN0Q2hlY2spO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgdHJ1c3RQcm94eWAgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbFxyXG4gICAqIHN0cmljdGVyIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgdGhlIGBib29sZWFuYCB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gdHJ1c3RQcm94eVxyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nIHRoZSBgdHJ1c3RQcm94eWBcclxuICAgKiBvcHRpb24uXHJcbiAgICovXHJcbiAgdHJ1c3RQcm94eShzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHYuYm9vbGVhbihzdHJpY3RDaGVjayk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGBza2lwS2V5YCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoIGFuIG9wdGlvbmFsIHN0cmljdGVyXHJcbiAgICogY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhlIHNhbWUgd29yayBhcyB0aGUgYHN0cmluZ2AgdmFsaWRhdG9yLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIHNraXBLZXlcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZyB0aGUgYHNraXBLZXlgXHJcbiAgICogb3B0aW9uLlxyXG4gICAqL1xyXG4gIHNraXBLZXkoc3RyaWN0Q2hlY2spIHtcclxuICAgIHJldHVybiB2LnN0cmluZyhzdHJpY3RDaGVjayk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGBza2lwVG9rZW5gIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGggYW4gb3B0aW9uYWxcclxuICAgKiBzdHJpY3RlciBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGUgc2FtZSB3b3JrIGFzIHRoZSBgc3RyaW5nYCB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gc2tpcFRva2VuXHJcbiAgICpcclxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IHN0cmljdENoZWNrIC0gRGV0ZXJtaW5lcyBpZiBzdHJpY3RlciB2YWxpZGF0aW9uIHNob3VsZFxyXG4gICAqIGJlIGFwcGxpZWQuXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9IEEgWm9kIHNjaGVtYSBvYmplY3QgZm9yIHZhbGlkYXRpbmcgdGhlIGBza2lwVG9rZW5gXHJcbiAgICogb3B0aW9uLlxyXG4gICAqL1xyXG4gIHNraXBUb2tlbihzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHYuc3RyaW5nKHN0cmljdENoZWNrKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYGVuYWJsZVNzbGAgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbFxyXG4gICAqIHN0cmljdGVyIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgdGhlIGBib29sZWFuYCB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gZW5hYmxlU3NsXHJcbiAgICpcclxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IHN0cmljdENoZWNrIC0gRGV0ZXJtaW5lcyBpZiBzdHJpY3RlciB2YWxpZGF0aW9uIHNob3VsZFxyXG4gICAqIGJlIGFwcGxpZWQuXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9IEEgWm9kIHNjaGVtYSBvYmplY3QgZm9yIHZhbGlkYXRpbmcgdGhlIGBlbmFibGVTc2xgXHJcbiAgICogb3B0aW9uLlxyXG4gICAqL1xyXG4gIGVuYWJsZVNzbChzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHYuYm9vbGVhbihzdHJpY3RDaGVjayk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGBzc2xGb3JjZWAgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbFxyXG4gICAqIHN0cmljdGVyIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgdGhlIGBib29sZWFuYCB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gc3NsRm9yY2VcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZyB0aGUgYHNzbEZvcmNlYFxyXG4gICAqIG9wdGlvbi5cclxuICAgKi9cclxuICBzc2xGb3JjZShzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHYuYm9vbGVhbihzdHJpY3RDaGVjayk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGBzc2xQb3J0YCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoIGFuIG9wdGlvbmFsIHN0cmljdGVyXHJcbiAgICogY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhlIHNhbWUgd29yayBhcyB0aGUgYG5vbk5lZ2F0aXZlTnVtYFxyXG4gICAqIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiBzc2xQb3J0XHJcbiAgICpcclxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IHN0cmljdENoZWNrIC0gRGV0ZXJtaW5lcyBpZiBzdHJpY3RlciB2YWxpZGF0aW9uIHNob3VsZFxyXG4gICAqIGJlIGFwcGxpZWQuXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9IEEgWm9kIHNjaGVtYSBvYmplY3QgZm9yIHZhbGlkYXRpbmcgdGhlIGBzc2xQb3J0YFxyXG4gICAqIG9wdGlvbi5cclxuICAgKi9cclxuICBzc2xQb3J0KHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gdi5ub25OZWdhdGl2ZU51bShzdHJpY3RDaGVjayk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGBzc2xDZXJ0UGF0aGAgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbFxyXG4gICAqIHN0cmljdGVyIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgdGhlIGBzdHJpbmdgIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiBzc2xDZXJ0UGF0aFxyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nIHRoZSBgc3NsQ2VydFBhdGhgXHJcbiAgICogb3B0aW9uLlxyXG4gICAqL1xyXG4gIHNzbENlcnRQYXRoKHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gdi5zdHJpbmcoc3RyaWN0Q2hlY2spO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgbWluV29ya2Vyc2AgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbFxyXG4gICAqIHN0cmljdGVyIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgdGhlIGBwb3NpdGl2ZU51bWAgdmFsaWRhdG9yLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIG1pbldvcmtlcnNcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZyB0aGUgYG1pbldvcmtlcnNgXHJcbiAgICogb3B0aW9uLlxyXG4gICAqL1xyXG4gIG1pbldvcmtlcnMoc3RyaWN0Q2hlY2spIHtcclxuICAgIHJldHVybiB2LnBvc2l0aXZlTnVtKHN0cmljdENoZWNrKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYG1heFdvcmtlcnNgIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGggYW4gb3B0aW9uYWxcclxuICAgKiBzdHJpY3RlciBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGUgc2FtZSB3b3JrIGFzIHRoZSBgcG9zaXRpdmVOdW1gIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiBtYXhXb3JrZXJzXHJcbiAgICpcclxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IHN0cmljdENoZWNrIC0gRGV0ZXJtaW5lcyBpZiBzdHJpY3RlciB2YWxpZGF0aW9uIHNob3VsZFxyXG4gICAqIGJlIGFwcGxpZWQuXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9IEEgWm9kIHNjaGVtYSBvYmplY3QgZm9yIHZhbGlkYXRpbmcgdGhlIGBtYXhXb3JrZXJzYFxyXG4gICAqIG9wdGlvbi5cclxuICAgKi9cclxuICBtYXhXb3JrZXJzKHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gdi5wb3NpdGl2ZU51bShzdHJpY3RDaGVjayk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGB3b3JrTGltaXRgIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGggYW4gb3B0aW9uYWxcclxuICAgKiBzdHJpY3RlciBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGUgc2FtZSB3b3JrIGFzIHRoZSBgcG9zaXRpdmVOdW1gIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiB3b3JrTGltaXRcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZyB0aGUgYHdvcmtMaW1pdGBcclxuICAgKiBvcHRpb24uXHJcbiAgICovXHJcbiAgd29ya0xpbWl0KHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gdi5wb3NpdGl2ZU51bShzdHJpY3RDaGVjayk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGBhY3F1aXJlVGltZW91dGAgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbFxyXG4gICAqIHN0cmljdGVyIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgdGhlIGBub25OZWdhdGl2ZU51bWBcclxuICAgKiB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gYWNxdWlyZVRpbWVvdXRcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZ1xyXG4gICAqIHRoZSBgYWNxdWlyZVRpbWVvdXRgIG9wdGlvbi5cclxuICAgKi9cclxuICBhY3F1aXJlVGltZW91dChzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHYubm9uTmVnYXRpdmVOdW0oc3RyaWN0Q2hlY2spO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgY3JlYXRlVGltZW91dGAgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbFxyXG4gICAqIHN0cmljdGVyIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgdGhlIGBub25OZWdhdGl2ZU51bWBcclxuICAgKiB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gY3JlYXRlVGltZW91dFxyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nXHJcbiAgICogdGhlIGBjcmVhdGVUaW1lb3V0YCBvcHRpb24uXHJcbiAgICovXHJcbiAgY3JlYXRlVGltZW91dChzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHYubm9uTmVnYXRpdmVOdW0oc3RyaWN0Q2hlY2spO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgZGVzdHJveVRpbWVvdXRgIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGggYW4gb3B0aW9uYWxcclxuICAgKiBzdHJpY3RlciBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGUgc2FtZSB3b3JrIGFzIHRoZSBgbm9uTmVnYXRpdmVOdW1gXHJcbiAgICogdmFsaWRhdG9yLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIGRlc3Ryb3lUaW1lb3V0XHJcbiAgICpcclxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IHN0cmljdENoZWNrIC0gRGV0ZXJtaW5lcyBpZiBzdHJpY3RlciB2YWxpZGF0aW9uIHNob3VsZFxyXG4gICAqIGJlIGFwcGxpZWQuXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9IEEgWm9kIHNjaGVtYSBvYmplY3QgZm9yIHZhbGlkYXRpbmdcclxuICAgKiB0aGUgYGRlc3Ryb3lUaW1lb3V0YCBvcHRpb24uXHJcbiAgICovXHJcbiAgZGVzdHJveVRpbWVvdXQoc3RyaWN0Q2hlY2spIHtcclxuICAgIHJldHVybiB2Lm5vbk5lZ2F0aXZlTnVtKHN0cmljdENoZWNrKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYGlkbGVUaW1lb3V0YCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoIGFuIG9wdGlvbmFsXHJcbiAgICogc3RyaWN0ZXIgY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhlIHNhbWUgd29yayBhcyB0aGUgYG5vbk5lZ2F0aXZlTnVtYFxyXG4gICAqIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiBpZGxlVGltZW91dFxyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nXHJcbiAgICogdGhlIGBpZGxlVGltZW91dGAgb3B0aW9uLlxyXG4gICAqL1xyXG4gIGlkbGVUaW1lb3V0KHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gdi5ub25OZWdhdGl2ZU51bShzdHJpY3RDaGVjayk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGBjcmVhdGVSZXRyeUludGVydmFsYCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoXHJcbiAgICogYW4gb3B0aW9uYWwgc3RyaWN0ZXIgY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhlIHNhbWUgd29yayBhcyB0aGUgYG5vbk5lZ2F0aXZlTnVtYFxyXG4gICAqIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiBjcmVhdGVSZXRyeUludGVydmFsXHJcbiAgICpcclxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IHN0cmljdENoZWNrIC0gRGV0ZXJtaW5lcyBpZiBzdHJpY3RlciB2YWxpZGF0aW9uIHNob3VsZFxyXG4gICAqIGJlIGFwcGxpZWQuXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9IEEgWm9kIHNjaGVtYSBvYmplY3QgZm9yIHZhbGlkYXRpbmdcclxuICAgKiB0aGUgYGNyZWF0ZVJldHJ5SW50ZXJ2YWxgIG9wdGlvbi5cclxuICAgKi9cclxuICBjcmVhdGVSZXRyeUludGVydmFsKHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gdi5ub25OZWdhdGl2ZU51bShzdHJpY3RDaGVjayk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGByZWFwZXJJbnRlcnZhbGAgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbFxyXG4gICAqIHN0cmljdGVyIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgdGhlIGBub25OZWdhdGl2ZU51bWBcclxuICAgKiB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gcmVhcGVySW50ZXJ2YWxcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZ1xyXG4gICAqIHRoZSBgcmVhcGVySW50ZXJ2YWxgIG9wdGlvbi5cclxuICAgKi9cclxuICByZWFwZXJJbnRlcnZhbChzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHYubm9uTmVnYXRpdmVOdW0oc3RyaWN0Q2hlY2spO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgcG9vbEJlbmNobWFya2luZ2AgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbFxyXG4gICAqIHN0cmljdGVyIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgdGhlIGBib29sZWFuYCB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gcG9vbEJlbmNobWFya2luZ1xyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nXHJcbiAgICogdGhlIGBwb29sQmVuY2htYXJraW5nYCBvcHRpb24uXHJcbiAgICovXHJcbiAgcG9vbEJlbmNobWFya2luZyhzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHYuYm9vbGVhbihzdHJpY3RDaGVjayk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGByZXNvdXJjZXNJbnRlcnZhbGAgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aFxyXG4gICAqIGFuIG9wdGlvbmFsIHN0cmljdGVyIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgdGhlIGBub25OZWdhdGl2ZU51bWBcclxuICAgKiB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gcmVzb3VyY2VzSW50ZXJ2YWxcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZ1xyXG4gICAqIHRoZSBgcmVzb3VyY2VzSW50ZXJ2YWxgIG9wdGlvbi5cclxuICAgKi9cclxuICByZXNvdXJjZXNJbnRlcnZhbChzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHYubm9uTmVnYXRpdmVOdW0oc3RyaWN0Q2hlY2spO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgbG9nTGV2ZWxgIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGggYW4gb3B0aW9uYWxcclxuICAgKiBzdHJpY3RlciBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGF0OlxyXG4gICAqXHJcbiAgICogLSBXaGVuIGBzdHJpY3RDaGVja2AgaXMgdHJ1ZSwgdGhlIHNjaGVtYSB3aWxsIGFjY2VwdCBpbnRlZ2VyIG51bWJlciB2YWx1ZXNcclxuICAgKiB0aGF0IGFyZSBiZXR3ZWVuIDAgYW5kIDUgKGluY2x1c2l2ZSkuXHJcbiAgICpcclxuICAgKiAtIFdoZW4gYHN0cmljdENoZWNrYCBpcyBmYWxzZSwgdGhlIHNjaGVtYSB3aWxsIGFjY2VwdCBpbnRlZ2VyIG51bWJlciB2YWx1ZXNcclxuICAgKiBhbmQgc3RyaW5naWZpZWQgaW50ZWdlciBudW1iZXIgdmFsdWVzIHRoYXQgYXJlIGJldHdlZW4gMSBhbmQgNSAoaW5jbHVzaXZlKSxcclxuICAgKiBudWxsLCAndW5kZWZpbmVkJywgJ251bGwnLCBhbmQgJycgd2hpY2ggd2lsbCBiZSB0cmFuc2Zvcm1lZCB0byBudWxsLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIGxvZ0xldmVsXHJcbiAgICpcclxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IHN0cmljdENoZWNrIC0gRGV0ZXJtaW5lcyBpZiBzdHJpY3RlciB2YWxpZGF0aW9uIHNob3VsZFxyXG4gICAqIGJlIGFwcGxpZWQuXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9IEEgWm9kIHNjaGVtYSBvYmplY3QgZm9yIHZhbGlkYXRpbmcgdGhlIGBsb2dMZXZlbGBcclxuICAgKiBvcHRpb24uXHJcbiAgICovXHJcbiAgbG9nTGV2ZWwoc3RyaWN0Q2hlY2spIHtcclxuICAgIHJldHVybiBzdHJpY3RDaGVja1xyXG4gICAgICA/IHoubnVtYmVyKCkuaW50KCkuZ3RlKDApLmx0ZSg1KVxyXG4gICAgICA6IHpcclxuICAgICAgICAgIC51bmlvbihbXHJcbiAgICAgICAgICAgIHpcclxuICAgICAgICAgICAgICAuc3RyaW5nKClcclxuICAgICAgICAgICAgICAudHJpbSgpXHJcbiAgICAgICAgICAgICAgLnJlZmluZShcclxuICAgICAgICAgICAgICAgICh2YWx1ZSkgPT5cclxuICAgICAgICAgICAgICAgICAgKCFpc05hTihOdW1iZXIodmFsdWUpKSAmJlxyXG4gICAgICAgICAgICAgICAgICAgIHZhbHVlICE9PSB0cnVlICYmXHJcbiAgICAgICAgICAgICAgICAgICAgIXZhbHVlLnN0YXJ0c1dpdGgoJ1snKSAmJlxyXG4gICAgICAgICAgICAgICAgICAgIE51bWJlci5pc0ludGVnZXIoTnVtYmVyKHZhbHVlKSkgJiZcclxuICAgICAgICAgICAgICAgICAgICBOdW1iZXIodmFsdWUpID49IDAgJiZcclxuICAgICAgICAgICAgICAgICAgICBOdW1iZXIodmFsdWUpIDw9IDUpIHx8XHJcbiAgICAgICAgICAgICAgICAgIFsndW5kZWZpbmVkJywgJ251bGwnLCAnJ10uaW5jbHVkZXModmFsdWUpLFxyXG4gICAgICAgICAgICAgICAge1xyXG4gICAgICAgICAgICAgICAgICBwYXJhbXM6IHtcclxuICAgICAgICAgICAgICAgICAgICBlcnJvck1lc3NhZ2U6ICdUaGUgdmFsdWUgbXVzdCBiZSB3aXRoaW4gYSAwIGFuZCA1IHJhbmdlJ1xyXG4gICAgICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgICAgKVxyXG4gICAgICAgICAgICAgIC50cmFuc2Zvcm0oKHZhbHVlKSA9PlxyXG4gICAgICAgICAgICAgICAgIVsndW5kZWZpbmVkJywgJ251bGwnLCAnJ10uaW5jbHVkZXModmFsdWUpXHJcbiAgICAgICAgICAgICAgICAgID8gTnVtYmVyKHZhbHVlKVxyXG4gICAgICAgICAgICAgICAgICA6IG51bGxcclxuICAgICAgICAgICAgICApLFxyXG4gICAgICAgICAgICB6Lm51bWJlcigpLmludCgpLmd0ZSgwKS5sdGUoNSlcclxuICAgICAgICAgIF0pXHJcbiAgICAgICAgICAubnVsbGFibGUoKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYGxvZ0ZpbGVgIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGggYW4gb3B0aW9uYWwgc3RyaWN0ZXJcclxuICAgKiBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGUgc2FtZSB3b3JrIGFzIHRoZSBgc3RyaW5nYCB2YWxpZGF0b3IuXHJcbiAgICogQWRkaXRpb25hbGx5LCBpdCBtdXN0IGJlIGEgc3RyaW5nIHRoYXQgZW5kcyB3aXRoICcubG9nJy5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiBsb2dGaWxlXHJcbiAgICpcclxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IHN0cmljdENoZWNrIC0gRGV0ZXJtaW5lcyBpZiBzdHJpY3RlciB2YWxpZGF0aW9uIHNob3VsZFxyXG4gICAqIGJlIGFwcGxpZWQuXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9IEEgWm9kIHNjaGVtYSBvYmplY3QgZm9yIHZhbGlkYXRpbmcgdGhlIGBsb2dGaWxlYFxyXG4gICAqIG9wdGlvbi5cclxuICAgKi9cclxuICBsb2dGaWxlKHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gdlxyXG4gICAgICAuc3RyaW5nKHN0cmljdENoZWNrKVxyXG4gICAgICAucmVmaW5lKFxyXG4gICAgICAgICh2YWx1ZSkgPT5cclxuICAgICAgICAgIHZhbHVlID09PSBudWxsIHx8ICh2YWx1ZS5sZW5ndGggPj0gNSAmJiB2YWx1ZS5lbmRzV2l0aCgnLmxvZycpKSxcclxuICAgICAgICB7XHJcbiAgICAgICAgICBwYXJhbXM6IHtcclxuICAgICAgICAgICAgZXJyb3JNZXNzYWdlOiAnVGhlIHZhbHVlIG11c3QgYmUgYSBzdHJpbmcgdGhhdCBlbmRzIHdpdGggLmxvZydcclxuICAgICAgICAgIH1cclxuICAgICAgICB9XHJcbiAgICAgICk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGBsb2dEZXN0YCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoIGFuIG9wdGlvbmFsIHN0cmljdGVyXHJcbiAgICogY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhlIHNhbWUgd29yayBhcyB0aGUgYHN0cmluZ2AgdmFsaWRhdG9yLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIGxvZ0Rlc3RcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZyB0aGUgYGxvZ0Rlc3RgXHJcbiAgICogb3B0aW9uLlxyXG4gICAqL1xyXG4gIGxvZ0Rlc3Qoc3RyaWN0Q2hlY2spIHtcclxuICAgIHJldHVybiB2LnN0cmluZyhzdHJpY3RDaGVjayk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGBsb2dUb0NvbnNvbGVgIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGggYW4gb3B0aW9uYWxcclxuICAgKiBzdHJpY3RlciBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGUgc2FtZSB3b3JrIGFzIHRoZSBgYm9vbGVhbmAgdmFsaWRhdG9yLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIGxvZ1RvQ29uc29sZVxyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nXHJcbiAgICogdGhlIGBsb2dUb0NvbnNvbGVgIG9wdGlvbi5cclxuICAgKi9cclxuICBsb2dUb0NvbnNvbGUoc3RyaWN0Q2hlY2spIHtcclxuICAgIHJldHVybiB2LmJvb2xlYW4oc3RyaWN0Q2hlY2spO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgbG9nVG9GaWxlYCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoIGFuIG9wdGlvbmFsXHJcbiAgICogc3RyaWN0ZXIgY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhlIHNhbWUgd29yayBhcyB0aGUgYGJvb2xlYW5gIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiBsb2dUb0ZpbGVcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZyB0aGUgYGxvZ1RvRmlsZWBcclxuICAgKiBvcHRpb24uXHJcbiAgICovXHJcbiAgbG9nVG9GaWxlKHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gdi5ib29sZWFuKHN0cmljdENoZWNrKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYGVuYWJsZVVpYCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoIGFuIG9wdGlvbmFsXHJcbiAgICogc3RyaWN0ZXIgY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhlIHNhbWUgd29yayBhcyB0aGUgYGJvb2xlYW5gIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiBlbmFibGVVaVxyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nIHRoZSBgZW5hYmxlVWlgXHJcbiAgICogb3B0aW9uLlxyXG4gICAqL1xyXG4gIGVuYWJsZVVpKHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gdi5ib29sZWFuKHN0cmljdENoZWNrKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYHVpUm91dGVgIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGggYW4gb3B0aW9uYWxcclxuICAgKiBzdHJpY3RlciBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGUgc2FtZSB3b3JrIGFzIHRoZSBgc3RhcnRzV2l0aGAgdmFsaWRhdG9yLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIHVpUm91dGVcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZyB0aGUgYHVpUm91dGVgXHJcbiAgICogb3B0aW9uLlxyXG4gICAqL1xyXG4gIHVpUm91dGUoc3RyaWN0Q2hlY2spIHtcclxuICAgIHJldHVybiB2LnN0YXJ0c1dpdGgoWycvJ10sIHN0cmljdENoZWNrKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYG5vZGVFbnZgIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGggYW4gb3B0aW9uYWxcclxuICAgKiBzdHJpY3RlciBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGUgc2FtZSB3b3JrIGFzIHRoZSBgZW51bWAgdmFsaWRhdG9yLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIG5vZGVFbnZcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZyB0aGUgYG5vZGVFbnZgXHJcbiAgICogb3B0aW9uLlxyXG4gICAqL1xyXG4gIG5vZGVFbnYoc3RyaWN0Q2hlY2spIHtcclxuICAgIHJldHVybiB2LmVudW0oWydkZXZlbG9wbWVudCcsICdwcm9kdWN0aW9uJywgJ3Rlc3QnXSwgc3RyaWN0Q2hlY2spO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgbGlzdGVuVG9Qcm9jZXNzRXhpdHNgIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGhcclxuICAgKiBhbiBvcHRpb25hbCBzdHJpY3RlciBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGUgc2FtZSB3b3JrIGFzIHRoZSBgYm9vbGVhbmAgdmFsaWRhdG9yLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIGxpc3RlblRvUHJvY2Vzc0V4aXRzXHJcbiAgICpcclxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IHN0cmljdENoZWNrIC0gRGV0ZXJtaW5lcyBpZiBzdHJpY3RlciB2YWxpZGF0aW9uIHNob3VsZFxyXG4gICAqIGJlIGFwcGxpZWQuXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9IEEgWm9kIHNjaGVtYSBvYmplY3QgZm9yIHZhbGlkYXRpbmdcclxuICAgKiB0aGUgYGxpc3RlblRvUHJvY2Vzc0V4aXRzYCBvcHRpb24uXHJcbiAgICovXHJcbiAgbGlzdGVuVG9Qcm9jZXNzRXhpdHMoc3RyaWN0Q2hlY2spIHtcclxuICAgIHJldHVybiB2LmJvb2xlYW4oc3RyaWN0Q2hlY2spO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgbm9Mb2dvYCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoIGFuIG9wdGlvbmFsXHJcbiAgICogc3RyaWN0ZXIgY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhlIHNhbWUgd29yayBhcyB0aGUgYGJvb2xlYW5gIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiBub0xvZ29cclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZyB0aGUgYG5vTG9nb2BcclxuICAgKiBvcHRpb24uXHJcbiAgICovXHJcbiAgbm9Mb2dvKHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gdi5ib29sZWFuKHN0cmljdENoZWNrKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYGhhcmRSZXNldFBhZ2VgIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGggYW4gb3B0aW9uYWxcclxuICAgKiBzdHJpY3RlciBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGUgc2FtZSB3b3JrIGFzIHRoZSBgYm9vbGVhbmAgdmFsaWRhdG9yLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIGhhcmRSZXNldFBhZ2VcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZ1xyXG4gICAqIHRoZSBgaGFyZFJlc2V0UGFnZWAgb3B0aW9uLlxyXG4gICAqL1xyXG4gIGhhcmRSZXNldFBhZ2Uoc3RyaWN0Q2hlY2spIHtcclxuICAgIHJldHVybiB2LmJvb2xlYW4oc3RyaWN0Q2hlY2spO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgYnJvd3NlclNoZWxsTW9kZWAgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbFxyXG4gICAqIHN0cmljdGVyIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgdGhlIGBib29sZWFuYCB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gYnJvd3NlclNoZWxsTW9kZVxyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nXHJcbiAgICogdGhlIGBicm93c2VyU2hlbGxNb2RlYCBvcHRpb24uXHJcbiAgICovXHJcbiAgYnJvd3NlclNoZWxsTW9kZShzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHYuYm9vbGVhbihzdHJpY3RDaGVjayk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGB2YWxpZGF0aW9uYCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoIGFuIG9wdGlvbmFsXHJcbiAgICogc3RyaWN0ZXIgY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhlIHNhbWUgd29yayBhcyB0aGUgYGJvb2xlYW5gIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiB2YWxpZGF0aW9uXHJcbiAgICpcclxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IHN0cmljdENoZWNrIC0gRGV0ZXJtaW5lcyBpZiBzdHJpY3RlciB2YWxpZGF0aW9uIHNob3VsZFxyXG4gICAqIGJlIGFwcGxpZWQuXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9IEEgWm9kIHNjaGVtYSBvYmplY3QgZm9yIHZhbGlkYXRpbmcgdGhlIGB2YWxpZGF0aW9uYFxyXG4gICAqIG9wdGlvbi5cclxuICAgKi9cclxuICB2YWxpZGF0aW9uKHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gdi5ib29sZWFuKHN0cmljdENoZWNrKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYGVuYWJsZURlYnVnYCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoIGFuIG9wdGlvbmFsXHJcbiAgICogc3RyaWN0ZXIgY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhlIHNhbWUgd29yayBhcyB0aGUgYGJvb2xlYW5gIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiBlbmFibGVEZWJ1Z1xyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nIHRoZSBgZW5hYmxlRGVidWdgXHJcbiAgICogb3B0aW9uLlxyXG4gICAqL1xyXG4gIGVuYWJsZURlYnVnKHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gdi5ib29sZWFuKHN0cmljdENoZWNrKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYGhlYWRsZXNzYCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoIGFuIG9wdGlvbmFsXHJcbiAgICogc3RyaWN0ZXIgY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhlIHNhbWUgd29yayBhcyB0aGUgYGJvb2xlYW5gIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiBoZWFkbGVzc1xyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nIHRoZSBgaGVhZGxlc3NgXHJcbiAgICogb3B0aW9uLlxyXG4gICAqL1xyXG4gIGhlYWRsZXNzKHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gdi5ib29sZWFuKHN0cmljdENoZWNrKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYGRldnRvb2xzYCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoIGFuIG9wdGlvbmFsXHJcbiAgICogc3RyaWN0ZXIgY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhlIHNhbWUgd29yayBhcyB0aGUgYGJvb2xlYW5gIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiBkZXZ0b29sc1xyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nIHRoZSBgZGV2dG9vbHNgXHJcbiAgICogb3B0aW9uLlxyXG4gICAqL1xyXG4gIGRldnRvb2xzKHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gdi5ib29sZWFuKHN0cmljdENoZWNrKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYGxpc3RlblRvQ29uc29sZWAgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbFxyXG4gICAqIHN0cmljdGVyIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgdGhlIGBib29sZWFuYCB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gbGlzdGVuVG9Db25zb2xlXHJcbiAgICpcclxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IHN0cmljdENoZWNrIC0gRGV0ZXJtaW5lcyBpZiBzdHJpY3RlciB2YWxpZGF0aW9uIHNob3VsZFxyXG4gICAqIGJlIGFwcGxpZWQuXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9IEEgWm9kIHNjaGVtYSBvYmplY3QgZm9yIHZhbGlkYXRpbmdcclxuICAgKiB0aGUgYGxpc3RlblRvQ29uc29sZWAgb3B0aW9uLlxyXG4gICAqL1xyXG4gIGxpc3RlblRvQ29uc29sZShzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHYuYm9vbGVhbihzdHJpY3RDaGVjayk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGBkdW1waW9gIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGggYW4gb3B0aW9uYWwgc3RyaWN0ZXJcclxuICAgKiBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGUgc2FtZSB3b3JrIGFzIHRoZSBgYm9vbGVhbmAgdmFsaWRhdG9yLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIGR1bXBpb1xyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nIHRoZSBgZHVtcGlvYFxyXG4gICAqIG9wdGlvbi5cclxuICAgKi9cclxuICBkdW1waW8oc3RyaWN0Q2hlY2spIHtcclxuICAgIHJldHVybiB2LmJvb2xlYW4oc3RyaWN0Q2hlY2spO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgc2xvd01vYCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoIGFuIG9wdGlvbmFsIHN0cmljdGVyXHJcbiAgICogY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhlIHNhbWUgd29yayBhcyB0aGUgYG5vbk5lZ2F0aXZlTnVtYFxyXG4gICAqIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiBzbG93TW9cclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZyB0aGUgYHNsb3dNb2BcclxuICAgKiBvcHRpb24uXHJcbiAgICovXHJcbiAgc2xvd01vKHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gdi5ub25OZWdhdGl2ZU51bShzdHJpY3RDaGVjayk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGBkZWJ1Z2dpbmdQb3J0YCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoIGFuIG9wdGlvbmFsXHJcbiAgICogc3RyaWN0ZXIgY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhlIHNhbWUgd29yayBhcyB0aGUgYG5vbk5lZ2F0aXZlTnVtYFxyXG4gICAqIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiBkZWJ1Z2dpbmdQb3J0XHJcbiAgICpcclxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IHN0cmljdENoZWNrIC0gRGV0ZXJtaW5lcyBpZiBzdHJpY3RlciB2YWxpZGF0aW9uIHNob3VsZFxyXG4gICAqIGJlIGFwcGxpZWQuXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9IEEgWm9kIHNjaGVtYSBvYmplY3QgZm9yIHZhbGlkYXRpbmdcclxuICAgKiB0aGUgYGRlYnVnZ2luZ1BvcnRgIG9wdGlvbi5cclxuICAgKi9cclxuICBkZWJ1Z2dpbmdQb3J0KHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gdi5ub25OZWdhdGl2ZU51bShzdHJpY3RDaGVjayk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGByZXF1ZXN0SWRgIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGggYW4gb3B0aW9uYWxcclxuICAgKiBzdHJpY3RlciBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGUgc2FtZSB3b3JrIGFzIHRoZSBgc3RyaW5nYCB2YWxpZGF0b3IuXHJcbiAgICogQWRkaXRpb25hbGx5LCBpdCBtdXN0IGJlIGEgc3RyaW5naWZpZWQgVVVJRCBvciBjYW4gYmUgbnVsbC5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiByZXF1ZXN0SWRcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZyB0aGUgYHJlcXVlc3RJZGBcclxuICAgKiBvcHRpb24uXHJcbiAgICovXHJcbiAgcmVxdWVzdElkKCkge1xyXG4gICAgcmV0dXJuIHpcclxuICAgICAgLnN0cmluZygpXHJcbiAgICAgIC51dWlkKHsgbWVzc2FnZTogJ1RoZSB2YWx1ZSBtdXN0IGJlIGEgc3RyaW5naWZpZWQgVVVJRCcgfSlcclxuICAgICAgLm51bGxhYmxlKCk7XHJcbiAgfVxyXG59O1xyXG5cclxuLy8gU2NoZW1hIGZvciB0aGUgcHVwcGV0ZWVyIHNlY3Rpb24gb2Ygb3B0aW9uc1xyXG5jb25zdCBQdXBwZXRlZXJTY2hlbWEgPSAoc3RyaWN0Q2hlY2spID0+XHJcbiAgelxyXG4gICAgLm9iamVjdCh7XHJcbiAgICAgIGFyZ3M6IHZhbGlkYXRvcnMuYXJncyhzdHJpY3RDaGVjaylcclxuICAgIH0pXHJcbiAgICAucGFydGlhbCgpO1xyXG5cclxuLy8gU2NoZW1hIGZvciB0aGUgaGlnaGNoYXJ0cyBzZWN0aW9uIG9mIG9wdGlvbnNcclxuY29uc3QgSGlnaGNoYXJ0c1NjaGVtYSA9IChzdHJpY3RDaGVjaykgPT5cclxuICB6XHJcbiAgICAub2JqZWN0KHtcclxuICAgICAgdmVyc2lvbjogdmFsaWRhdG9ycy52ZXJzaW9uKHN0cmljdENoZWNrKSxcclxuICAgICAgY2RuVXJsOiB2YWxpZGF0b3JzLmNkblVybChzdHJpY3RDaGVjayksXHJcbiAgICAgIGZvcmNlRmV0Y2g6IHZhbGlkYXRvcnMuZm9yY2VGZXRjaChzdHJpY3RDaGVjayksXHJcbiAgICAgIGNhY2hlUGF0aDogdmFsaWRhdG9ycy5jYWNoZVBhdGgoc3RyaWN0Q2hlY2spLFxyXG4gICAgICBjb3JlU2NyaXB0czogdmFsaWRhdG9ycy5jb3JlU2NyaXB0cyhzdHJpY3RDaGVjayksXHJcbiAgICAgIG1vZHVsZVNjcmlwdHM6IHZhbGlkYXRvcnMubW9kdWxlU2NyaXB0cyhzdHJpY3RDaGVjayksXHJcbiAgICAgIGluZGljYXRvclNjcmlwdHM6IHZhbGlkYXRvcnMuaW5kaWNhdG9yU2NyaXB0cyhzdHJpY3RDaGVjayksXHJcbiAgICAgIGN1c3RvbVNjcmlwdHM6IHZhbGlkYXRvcnMuY3VzdG9tU2NyaXB0cyhzdHJpY3RDaGVjaylcclxuICAgIH0pXHJcbiAgICAucGFydGlhbCgpO1xyXG5cclxuLy8gU2NoZW1hIGZvciB0aGUgZXhwb3J0IHNlY3Rpb24gb2Ygb3B0aW9uc1xyXG5jb25zdCBFeHBvcnRTY2hlbWEgPSAoc3RyaWN0Q2hlY2spID0+XHJcbiAgelxyXG4gICAgLm9iamVjdCh7XHJcbiAgICAgIGluZmlsZTogdmFsaWRhdG9ycy5pbmZpbGUoc3RyaWN0Q2hlY2spLFxyXG4gICAgICBpbnN0cjogdmFsaWRhdG9ycy5pbnN0cigpLFxyXG4gICAgICBvcHRpb25zOiB2YWxpZGF0b3JzLm9wdGlvbnMoKSxcclxuICAgICAgc3ZnOiB2YWxpZGF0b3JzLnN2ZygpLFxyXG4gICAgICBvdXRmaWxlOiB2YWxpZGF0b3JzLm91dGZpbGUoc3RyaWN0Q2hlY2spLFxyXG4gICAgICB0eXBlOiB2YWxpZGF0b3JzLnR5cGUoc3RyaWN0Q2hlY2spLFxyXG4gICAgICBjb25zdHI6IHZhbGlkYXRvcnMuY29uc3RyKHN0cmljdENoZWNrKSxcclxuICAgICAgYjY0OiB2YWxpZGF0b3JzLmI2NChzdHJpY3RDaGVjayksXHJcbiAgICAgIG5vRG93bmxvYWQ6IHZhbGlkYXRvcnMubm9Eb3dubG9hZChzdHJpY3RDaGVjayksXHJcbiAgICAgIGRlZmF1bHRIZWlnaHQ6IHZhbGlkYXRvcnMuZGVmYXVsdEhlaWdodChzdHJpY3RDaGVjayksXHJcbiAgICAgIGRlZmF1bHRXaWR0aDogdmFsaWRhdG9ycy5kZWZhdWx0V2lkdGgoc3RyaWN0Q2hlY2spLFxyXG4gICAgICBkZWZhdWx0U2NhbGU6IHZhbGlkYXRvcnMuZGVmYXVsdFNjYWxlKHN0cmljdENoZWNrKSxcclxuICAgICAgaGVpZ2h0OiB2YWxpZGF0b3JzLmhlaWdodChzdHJpY3RDaGVjayksXHJcbiAgICAgIHdpZHRoOiB2YWxpZGF0b3JzLndpZHRoKHN0cmljdENoZWNrKSxcclxuICAgICAgc2NhbGU6IHZhbGlkYXRvcnMuc2NhbGUoc3RyaWN0Q2hlY2spLFxyXG4gICAgICBnbG9iYWxPcHRpb25zOiB2YWxpZGF0b3JzLmdsb2JhbE9wdGlvbnMoKSxcclxuICAgICAgdGhlbWVPcHRpb25zOiB2YWxpZGF0b3JzLnRoZW1lT3B0aW9ucygpLFxyXG4gICAgICBiYXRjaDogdmFsaWRhdG9ycy5iYXRjaChmYWxzZSksXHJcbiAgICAgIHJhc3Rlcml6YXRpb25UaW1lb3V0OiB2YWxpZGF0b3JzLnJhc3Rlcml6YXRpb25UaW1lb3V0KHN0cmljdENoZWNrKVxyXG4gICAgfSlcclxuICAgIC5wYXJ0aWFsKCk7XHJcblxyXG4vLyBTY2hlbWEgZm9yIHRoZSBjdXN0b21Mb2dpYyBzZWN0aW9uIG9mIG9wdGlvbnNcclxuY29uc3QgQ3VzdG9tTG9naWNTY2hlbWEgPSAoc3RyaWN0Q2hlY2spID0+XHJcbiAgelxyXG4gICAgLm9iamVjdCh7XHJcbiAgICAgIGFsbG93Q29kZUV4ZWN1dGlvbjogdmFsaWRhdG9ycy5hbGxvd0NvZGVFeGVjdXRpb24oc3RyaWN0Q2hlY2spLFxyXG4gICAgICBhbGxvd0ZpbGVSZXNvdXJjZXM6IHZhbGlkYXRvcnMuYWxsb3dGaWxlUmVzb3VyY2VzKHN0cmljdENoZWNrKSxcclxuICAgICAgY3VzdG9tQ29kZTogdmFsaWRhdG9ycy5jdXN0b21Db2RlKGZhbHNlKSxcclxuICAgICAgY2FsbGJhY2s6IHZhbGlkYXRvcnMuY2FsbGJhY2soZmFsc2UpLFxyXG4gICAgICByZXNvdXJjZXM6IHZhbGlkYXRvcnMucmVzb3VyY2VzKHN0cmljdENoZWNrKSxcclxuICAgICAgbG9hZENvbmZpZzogdmFsaWRhdG9ycy5sb2FkQ29uZmlnKGZhbHNlKSxcclxuICAgICAgY3JlYXRlQ29uZmlnOiB2YWxpZGF0b3JzLmNyZWF0ZUNvbmZpZyhmYWxzZSlcclxuICAgIH0pXHJcbiAgICAucGFydGlhbCgpO1xyXG5cclxuLy8gU2NoZW1hIGZvciB0aGUgc2VydmVyLnByb3h5IHNlY3Rpb24gb2Ygb3B0aW9uc1xyXG5jb25zdCBQcm94eVNjaGVtYSA9IChzdHJpY3RDaGVjaykgPT5cclxuICB6XHJcbiAgICAub2JqZWN0KHtcclxuICAgICAgaG9zdDogdmFsaWRhdG9ycy5wcm94eUhvc3QoZmFsc2UpLFxyXG4gICAgICBwb3J0OiB2YWxpZGF0b3JzLnByb3h5UG9ydChzdHJpY3RDaGVjayksXHJcbiAgICAgIHRpbWVvdXQ6IHZhbGlkYXRvcnMucHJveHlUaW1lb3V0KHN0cmljdENoZWNrKVxyXG4gICAgfSlcclxuICAgIC5wYXJ0aWFsKCk7XHJcblxyXG4vLyBTY2hlbWEgZm9yIHRoZSBzZXJ2ZXIucmF0ZUxpbWl0aW5nIHNlY3Rpb24gb2Ygb3B0aW9uc1xyXG5jb25zdCBSYXRlTGltaXRpbmdTY2hlbWEgPSAoc3RyaWN0Q2hlY2spID0+XHJcbiAgelxyXG4gICAgLm9iamVjdCh7XHJcbiAgICAgIGVuYWJsZTogdmFsaWRhdG9ycy5lbmFibGVSYXRlTGltaXRpbmcoc3RyaWN0Q2hlY2spLFxyXG4gICAgICBtYXhSZXF1ZXN0czogdmFsaWRhdG9ycy5tYXhSZXF1ZXN0cyhzdHJpY3RDaGVjayksXHJcbiAgICAgIHdpbmRvdzogdmFsaWRhdG9ycy53aW5kb3coc3RyaWN0Q2hlY2spLFxyXG4gICAgICBkZWxheTogdmFsaWRhdG9ycy5kZWxheShzdHJpY3RDaGVjayksXHJcbiAgICAgIHRydXN0UHJveHk6IHZhbGlkYXRvcnMudHJ1c3RQcm94eShzdHJpY3RDaGVjayksXHJcbiAgICAgIHNraXBLZXk6IHZhbGlkYXRvcnMuc2tpcEtleShmYWxzZSksXHJcbiAgICAgIHNraXBUb2tlbjogdmFsaWRhdG9ycy5za2lwVG9rZW4oZmFsc2UpXHJcbiAgICB9KVxyXG4gICAgLnBhcnRpYWwoKTtcclxuXHJcbi8vIFNjaGVtYSBmb3IgdGhlIHNlcnZlci5zc2wgc2VjdGlvbiBvZiBvcHRpb25zXHJcbmNvbnN0IFNzbFNjaGVtYSA9IChzdHJpY3RDaGVjaykgPT5cclxuICB6XHJcbiAgICAub2JqZWN0KHtcclxuICAgICAgZW5hYmxlOiB2YWxpZGF0b3JzLmVuYWJsZVNzbChzdHJpY3RDaGVjayksXHJcbiAgICAgIGZvcmNlOiB2YWxpZGF0b3JzLnNzbEZvcmNlKHN0cmljdENoZWNrKSxcclxuICAgICAgcG9ydDogdmFsaWRhdG9ycy5zc2xQb3J0KHN0cmljdENoZWNrKSxcclxuICAgICAgY2VydFBhdGg6IHZhbGlkYXRvcnMuc3NsQ2VydFBhdGgoZmFsc2UpXHJcbiAgICB9KVxyXG4gICAgLnBhcnRpYWwoKTtcclxuXHJcbi8vIFNjaGVtYSBmb3IgdGhlIHNlcnZlciBzZWN0aW9uIG9mIG9wdGlvbnNcclxuY29uc3QgU2VydmVyU2NoZW1hID0gKHN0cmljdENoZWNrKSA9PlxyXG4gIHoub2JqZWN0KHtcclxuICAgIGVuYWJsZTogdmFsaWRhdG9ycy5lbmFibGVTZXJ2ZXIoc3RyaWN0Q2hlY2spLm9wdGlvbmFsKCksXHJcbiAgICBob3N0OiB2YWxpZGF0b3JzLmhvc3Qoc3RyaWN0Q2hlY2spLm9wdGlvbmFsKCksXHJcbiAgICBwb3J0OiB2YWxpZGF0b3JzLnBvcnQoc3RyaWN0Q2hlY2spLm9wdGlvbmFsKCksXHJcbiAgICB1cGxvYWRMaW1pdDogdmFsaWRhdG9ycy51cGxvYWRMaW1pdChzdHJpY3RDaGVjaykub3B0aW9uYWwoKSxcclxuICAgIGJlbmNobWFya2luZzogdmFsaWRhdG9ycy5zZXJ2ZXJCZW5jaG1hcmtpbmcoc3RyaWN0Q2hlY2spLm9wdGlvbmFsKCksXHJcbiAgICBwcm94eTogUHJveHlTY2hlbWEoc3RyaWN0Q2hlY2spLm9wdGlvbmFsKCksXHJcbiAgICByYXRlTGltaXRpbmc6IFJhdGVMaW1pdGluZ1NjaGVtYShzdHJpY3RDaGVjaykub3B0aW9uYWwoKSxcclxuICAgIHNzbDogU3NsU2NoZW1hKHN0cmljdENoZWNrKS5vcHRpb25hbCgpXHJcbiAgfSk7XHJcblxyXG4vLyBTY2hlbWEgZm9yIHRoZSBwb29sIHNlY3Rpb24gb2Ygb3B0aW9uc1xyXG5jb25zdCBQb29sU2NoZW1hID0gKHN0cmljdENoZWNrKSA9PlxyXG4gIHpcclxuICAgIC5vYmplY3Qoe1xyXG4gICAgICBtaW5Xb3JrZXJzOiB2YWxpZGF0b3JzLm1pbldvcmtlcnMoc3RyaWN0Q2hlY2spLFxyXG4gICAgICBtYXhXb3JrZXJzOiB2YWxpZGF0b3JzLm1heFdvcmtlcnMoc3RyaWN0Q2hlY2spLFxyXG4gICAgICB3b3JrTGltaXQ6IHZhbGlkYXRvcnMud29ya0xpbWl0KHN0cmljdENoZWNrKSxcclxuICAgICAgYWNxdWlyZVRpbWVvdXQ6IHZhbGlkYXRvcnMuYWNxdWlyZVRpbWVvdXQoc3RyaWN0Q2hlY2spLFxyXG4gICAgICBjcmVhdGVUaW1lb3V0OiB2YWxpZGF0b3JzLmNyZWF0ZVRpbWVvdXQoc3RyaWN0Q2hlY2spLFxyXG4gICAgICBkZXN0cm95VGltZW91dDogdmFsaWRhdG9ycy5kZXN0cm95VGltZW91dChzdHJpY3RDaGVjayksXHJcbiAgICAgIGlkbGVUaW1lb3V0OiB2YWxpZGF0b3JzLmlkbGVUaW1lb3V0KHN0cmljdENoZWNrKSxcclxuICAgICAgY3JlYXRlUmV0cnlJbnRlcnZhbDogdmFsaWRhdG9ycy5jcmVhdGVSZXRyeUludGVydmFsKHN0cmljdENoZWNrKSxcclxuICAgICAgcmVhcGVySW50ZXJ2YWw6IHZhbGlkYXRvcnMucmVhcGVySW50ZXJ2YWwoc3RyaWN0Q2hlY2spLFxyXG4gICAgICBiZW5jaG1hcmtpbmc6IHZhbGlkYXRvcnMucG9vbEJlbmNobWFya2luZyhzdHJpY3RDaGVjaylcclxuICAgIH0pXHJcbiAgICAucGFydGlhbCgpO1xyXG5cclxuLy8gU2NoZW1hIGZvciB0aGUgbG9nZ2luZyBzZWN0aW9uIG9mIG9wdGlvbnNcclxuY29uc3QgTG9nZ2luZ1NjaGVtYSA9IChzdHJpY3RDaGVjaykgPT5cclxuICB6XHJcbiAgICAub2JqZWN0KHtcclxuICAgICAgbGV2ZWw6IHZhbGlkYXRvcnMubG9nTGV2ZWwoc3RyaWN0Q2hlY2spLFxyXG4gICAgICBmaWxlOiB2YWxpZGF0b3JzLmxvZ0ZpbGUoc3RyaWN0Q2hlY2spLFxyXG4gICAgICBkZXN0OiB2YWxpZGF0b3JzLmxvZ0Rlc3Qoc3RyaWN0Q2hlY2spLFxyXG4gICAgICB0b0NvbnNvbGU6IHZhbGlkYXRvcnMubG9nVG9Db25zb2xlKHN0cmljdENoZWNrKSxcclxuICAgICAgdG9GaWxlOiB2YWxpZGF0b3JzLmxvZ1RvRmlsZShzdHJpY3RDaGVjaylcclxuICAgIH0pXHJcbiAgICAucGFydGlhbCgpO1xyXG5cclxuLy8gU2NoZW1hIGZvciB0aGUgdWkgc2VjdGlvbiBvZiBvcHRpb25zXHJcbmNvbnN0IFVpU2NoZW1hID0gKHN0cmljdENoZWNrKSA9PlxyXG4gIHpcclxuICAgIC5vYmplY3Qoe1xyXG4gICAgICBlbmFibGU6IHZhbGlkYXRvcnMuZW5hYmxlVWkoc3RyaWN0Q2hlY2spLFxyXG4gICAgICByb3V0ZTogdmFsaWRhdG9ycy51aVJvdXRlKHN0cmljdENoZWNrKVxyXG4gICAgfSlcclxuICAgIC5wYXJ0aWFsKCk7XHJcblxyXG4vLyBTY2hlbWEgZm9yIHRoZSBvdGhlciBzZWN0aW9uIG9mIG9wdGlvbnNcclxuY29uc3QgT3RoZXJTY2hlbWEgPSAoc3RyaWN0Q2hlY2spID0+XHJcbiAgelxyXG4gICAgLm9iamVjdCh7XHJcbiAgICAgIG5vZGVFbnY6IHZhbGlkYXRvcnMubm9kZUVudihzdHJpY3RDaGVjayksXHJcbiAgICAgIGxpc3RlblRvUHJvY2Vzc0V4aXRzOiB2YWxpZGF0b3JzLmxpc3RlblRvUHJvY2Vzc0V4aXRzKHN0cmljdENoZWNrKSxcclxuICAgICAgbm9Mb2dvOiB2YWxpZGF0b3JzLm5vTG9nbyhzdHJpY3RDaGVjayksXHJcbiAgICAgIGhhcmRSZXNldFBhZ2U6IHZhbGlkYXRvcnMuaGFyZFJlc2V0UGFnZShzdHJpY3RDaGVjayksXHJcbiAgICAgIGJyb3dzZXJTaGVsbE1vZGU6IHZhbGlkYXRvcnMuYnJvd3NlclNoZWxsTW9kZShzdHJpY3RDaGVjayksXHJcbiAgICAgIHZhbGlkYXRpb246IHZhbGlkYXRvcnMudmFsaWRhdGlvbihzdHJpY3RDaGVjaylcclxuICAgIH0pXHJcbiAgICAucGFydGlhbCgpO1xyXG5cclxuLy8gU2NoZW1hIGZvciB0aGUgZGVidWcgc2VjdGlvbiBvZiBvcHRpb25zXHJcbmNvbnN0IERlYnVnU2NoZW1hID0gKHN0cmljdENoZWNrKSA9PlxyXG4gIHpcclxuICAgIC5vYmplY3Qoe1xyXG4gICAgICBlbmFibGU6IHZhbGlkYXRvcnMuZW5hYmxlRGVidWcoc3RyaWN0Q2hlY2spLFxyXG4gICAgICBoZWFkbGVzczogdmFsaWRhdG9ycy5oZWFkbGVzcyhzdHJpY3RDaGVjayksXHJcbiAgICAgIGRldnRvb2xzOiB2YWxpZGF0b3JzLmRldnRvb2xzKHN0cmljdENoZWNrKSxcclxuICAgICAgbGlzdGVuVG9Db25zb2xlOiB2YWxpZGF0b3JzLmxpc3RlblRvQ29uc29sZShzdHJpY3RDaGVjayksXHJcbiAgICAgIGR1bXBpbzogdmFsaWRhdG9ycy5kdW1waW8oc3RyaWN0Q2hlY2spLFxyXG4gICAgICBzbG93TW86IHZhbGlkYXRvcnMuc2xvd01vKHN0cmljdENoZWNrKSxcclxuICAgICAgZGVidWdnaW5nUG9ydDogdmFsaWRhdG9ycy5kZWJ1Z2dpbmdQb3J0KHN0cmljdENoZWNrKVxyXG4gICAgfSlcclxuICAgIC5wYXJ0aWFsKCk7XHJcblxyXG4vLyBTdHJpY3Qgc2NoZW1hIGZvciB0aGUgY29uZmlnXHJcbmV4cG9ydCBjb25zdCBTdHJpY3RDb25maWdTY2hlbWEgPSB6Lm9iamVjdCh7XHJcbiAgcmVxdWVzdElkOiB2YWxpZGF0b3JzLnJlcXVlc3RJZCgpLFxyXG4gIHB1cHBldGVlcjogUHVwcGV0ZWVyU2NoZW1hKHRydWUpLFxyXG4gIGhpZ2hjaGFydHM6IEhpZ2hjaGFydHNTY2hlbWEodHJ1ZSksXHJcbiAgZXhwb3J0OiBFeHBvcnRTY2hlbWEodHJ1ZSksXHJcbiAgY3VzdG9tTG9naWM6IEN1c3RvbUxvZ2ljU2NoZW1hKHRydWUpLFxyXG4gIHNlcnZlcjogU2VydmVyU2NoZW1hKHRydWUpLFxyXG4gIHBvb2w6IFBvb2xTY2hlbWEodHJ1ZSksXHJcbiAgbG9nZ2luZzogTG9nZ2luZ1NjaGVtYSh0cnVlKSxcclxuICB1aTogVWlTY2hlbWEodHJ1ZSksXHJcbiAgb3RoZXI6IE90aGVyU2NoZW1hKHRydWUpLFxyXG4gIGRlYnVnOiBEZWJ1Z1NjaGVtYSh0cnVlKVxyXG59KTtcclxuXHJcbi8vIExvb3NlIHNjaGVtYSBmb3IgdGhlIGNvbmZpZ1xyXG5leHBvcnQgY29uc3QgTG9vc2VDb25maWdTY2hlbWEgPSB6Lm9iamVjdCh7XHJcbiAgcmVxdWVzdElkOiB2YWxpZGF0b3JzLnJlcXVlc3RJZCgpLFxyXG4gIHB1cHBldGVlcjogUHVwcGV0ZWVyU2NoZW1hKGZhbHNlKSxcclxuICBoaWdoY2hhcnRzOiBIaWdoY2hhcnRzU2NoZW1hKGZhbHNlKSxcclxuICBleHBvcnQ6IEV4cG9ydFNjaGVtYShmYWxzZSksXHJcbiAgY3VzdG9tTG9naWM6IEN1c3RvbUxvZ2ljU2NoZW1hKGZhbHNlKSxcclxuICBzZXJ2ZXI6IFNlcnZlclNjaGVtYShmYWxzZSksXHJcbiAgcG9vbDogUG9vbFNjaGVtYShmYWxzZSksXHJcbiAgbG9nZ2luZzogTG9nZ2luZ1NjaGVtYShmYWxzZSksXHJcbiAgdWk6IFVpU2NoZW1hKGZhbHNlKSxcclxuICBvdGhlcjogT3RoZXJTY2hlbWEoZmFsc2UpLFxyXG4gIGRlYnVnOiBEZWJ1Z1NjaGVtYShmYWxzZSlcclxufSk7XHJcblxyXG4vLyBTY2hlbWEgZm9yIHRoZSBlbnZpcm9ubWVudCB2YXJpYWJsZXMgY29uZmlnXHJcbmV4cG9ydCBjb25zdCBFbnZTY2hlbWEgPSB6Lm9iamVjdCh7XHJcbiAgLy8gcHVwcGV0ZWVyXHJcbiAgUFVQUEVURUVSX0FSR1M6IHZhbGlkYXRvcnMuYXJncyhmYWxzZSksXHJcblxyXG4gIC8vIGhpZ2hjaGFydHNcclxuICBISUdIQ0hBUlRTX1ZFUlNJT046IHZhbGlkYXRvcnMudmVyc2lvbihmYWxzZSksXHJcbiAgSElHSENIQVJUU19DRE5fVVJMOiB2YWxpZGF0b3JzLmNkblVybChmYWxzZSksXHJcbiAgSElHSENIQVJUU19GT1JDRV9GRVRDSDogdmFsaWRhdG9ycy5mb3JjZUZldGNoKGZhbHNlKSxcclxuICBISUdIQ0hBUlRTX0NBQ0hFX1BBVEg6IHZhbGlkYXRvcnMuY2FjaGVQYXRoKGZhbHNlKSxcclxuICBISUdIQ0hBUlRTX0FETUlOX1RPS0VOOiB2YWxpZGF0b3JzLmFkbWluVG9rZW4oZmFsc2UpLFxyXG4gIEhJR0hDSEFSVFNfQ09SRV9TQ1JJUFRTOiB2YWxpZGF0b3JzLmNvcmVTY3JpcHRzKGZhbHNlKSxcclxuICBISUdIQ0hBUlRTX01PRFVMRV9TQ1JJUFRTOiB2YWxpZGF0b3JzLm1vZHVsZVNjcmlwdHMoZmFsc2UpLFxyXG4gIEhJR0hDSEFSVFNfSU5ESUNBVE9SX1NDUklQVFM6IHZhbGlkYXRvcnMuaW5kaWNhdG9yU2NyaXB0cyhmYWxzZSksXHJcbiAgSElHSENIQVJUU19DVVNUT01fU0NSSVBUUzogdmFsaWRhdG9ycy5jdXN0b21TY3JpcHRzKGZhbHNlKSxcclxuXHJcbiAgLy8gZXhwb3J0XHJcbiAgRVhQT1JUX0lORklMRTogdmFsaWRhdG9ycy5pbmZpbGUoZmFsc2UpLFxyXG4gIEVYUE9SVF9JTlNUUjogdmFsaWRhdG9ycy5pbnN0cigpLFxyXG4gIEVYUE9SVF9PUFRJT05TOiB2YWxpZGF0b3JzLm9wdGlvbnMoKSxcclxuICBFWFBPUlRfU1ZHOiB2YWxpZGF0b3JzLnN2ZygpLFxyXG4gIEVYUE9SVF9CQVRDSDogdmFsaWRhdG9ycy5iYXRjaChmYWxzZSksXHJcbiAgRVhQT1JUX09VVEZJTEU6IHZhbGlkYXRvcnMub3V0ZmlsZShmYWxzZSksXHJcbiAgRVhQT1JUX1RZUEU6IHZhbGlkYXRvcnMudHlwZShmYWxzZSksXHJcbiAgRVhQT1JUX0NPTlNUUjogdmFsaWRhdG9ycy5jb25zdHIoZmFsc2UpLFxyXG4gIEVYUE9SVF9CNjQ6IHZhbGlkYXRvcnMuYjY0KGZhbHNlKSxcclxuICBFWFBPUlRfTk9fRE9XTkxPQUQ6IHZhbGlkYXRvcnMubm9Eb3dubG9hZChmYWxzZSksXHJcbiAgRVhQT1JUX0hFSUdIVDogdmFsaWRhdG9ycy5oZWlnaHQoZmFsc2UpLFxyXG4gIEVYUE9SVF9XSURUSDogdmFsaWRhdG9ycy53aWR0aChmYWxzZSksXHJcbiAgRVhQT1JUX1NDQUxFOiB2YWxpZGF0b3JzLnNjYWxlKGZhbHNlKSxcclxuICBFWFBPUlRfREVGQVVMVF9IRUlHSFQ6IHZhbGlkYXRvcnMuZGVmYXVsdEhlaWdodChmYWxzZSksXHJcbiAgRVhQT1JUX0RFRkFVTFRfV0lEVEg6IHZhbGlkYXRvcnMuZGVmYXVsdFdpZHRoKGZhbHNlKSxcclxuICBFWFBPUlRfREVGQVVMVF9TQ0FMRTogdmFsaWRhdG9ycy5kZWZhdWx0U2NhbGUoZmFsc2UpLFxyXG4gIEVYUE9SVF9HTE9CQUxfT1BUSU9OUzogdmFsaWRhdG9ycy5nbG9iYWxPcHRpb25zKCksXHJcbiAgRVhQT1JUX1RIRU1FX09QVElPTlM6IHZhbGlkYXRvcnMudGhlbWVPcHRpb25zKCksXHJcbiAgRVhQT1JUX1JBU1RFUklaQVRJT05fVElNRU9VVDogdmFsaWRhdG9ycy5yYXN0ZXJpemF0aW9uVGltZW91dChmYWxzZSksXHJcblxyXG4gIC8vIGN1c3RvbVxyXG4gIENVU1RPTV9MT0dJQ19BTExPV19DT0RFX0VYRUNVVElPTjogdmFsaWRhdG9ycy5hbGxvd0NvZGVFeGVjdXRpb24oZmFsc2UpLFxyXG4gIENVU1RPTV9MT0dJQ19BTExPV19GSUxFX1JFU09VUkNFUzogdmFsaWRhdG9ycy5hbGxvd0ZpbGVSZXNvdXJjZXMoZmFsc2UpLFxyXG4gIENVU1RPTV9MT0dJQ19DVVNUT01fQ09ERTogdmFsaWRhdG9ycy5jdXN0b21Db2RlKGZhbHNlKSxcclxuICBDVVNUT01fTE9HSUNfQ0FMTEJBQ0s6IHZhbGlkYXRvcnMuY2FsbGJhY2soZmFsc2UpLFxyXG4gIENVU1RPTV9MT0dJQ19SRVNPVVJDRVM6IHZhbGlkYXRvcnMucmVzb3VyY2VzKGZhbHNlKSxcclxuICBDVVNUT01fTE9HSUNfTE9BRF9DT05GSUc6IHZhbGlkYXRvcnMubG9hZENvbmZpZyhmYWxzZSksXHJcbiAgQ1VTVE9NX0xPR0lDX0NSRUFURV9DT05GSUc6IHZhbGlkYXRvcnMuY3JlYXRlQ29uZmlnKGZhbHNlKSxcclxuXHJcbiAgLy8gc2VydmVyXHJcbiAgU0VSVkVSX0VOQUJMRTogdmFsaWRhdG9ycy5lbmFibGVTZXJ2ZXIoZmFsc2UpLFxyXG4gIFNFUlZFUl9IT1NUOiB2YWxpZGF0b3JzLmhvc3QoZmFsc2UpLFxyXG4gIFNFUlZFUl9QT1JUOiB2YWxpZGF0b3JzLnBvcnQoZmFsc2UpLFxyXG4gIFNFUlZFUl9VUExPQURfTElNSVQ6IHZhbGlkYXRvcnMudXBsb2FkTGltaXQoZmFsc2UpLFxyXG4gIFNFUlZFUl9CRU5DSE1BUktJTkc6IHZhbGlkYXRvcnMuc2VydmVyQmVuY2htYXJraW5nKGZhbHNlKSxcclxuXHJcbiAgLy8gc2VydmVyIHByb3h5XHJcbiAgU0VSVkVSX1BST1hZX0hPU1Q6IHZhbGlkYXRvcnMucHJveHlIb3N0KGZhbHNlKSxcclxuICBTRVJWRVJfUFJPWFlfUE9SVDogdmFsaWRhdG9ycy5wcm94eVBvcnQoZmFsc2UpLFxyXG4gIFNFUlZFUl9QUk9YWV9USU1FT1VUOiB2YWxpZGF0b3JzLnByb3h5VGltZW91dChmYWxzZSksXHJcblxyXG4gIC8vIHNlcnZlciByYXRlIGxpbWl0aW5nXHJcbiAgU0VSVkVSX1JBVEVfTElNSVRJTkdfRU5BQkxFOiB2YWxpZGF0b3JzLmVuYWJsZVJhdGVMaW1pdGluZyhmYWxzZSksXHJcbiAgU0VSVkVSX1JBVEVfTElNSVRJTkdfTUFYX1JFUVVFU1RTOiB2YWxpZGF0b3JzLm1heFJlcXVlc3RzKGZhbHNlKSxcclxuICBTRVJWRVJfUkFURV9MSU1JVElOR19XSU5ET1c6IHZhbGlkYXRvcnMud2luZG93KGZhbHNlKSxcclxuICBTRVJWRVJfUkFURV9MSU1JVElOR19ERUxBWTogdmFsaWRhdG9ycy5kZWxheShmYWxzZSksXHJcbiAgU0VSVkVSX1JBVEVfTElNSVRJTkdfVFJVU1RfUFJPWFk6IHZhbGlkYXRvcnMudHJ1c3RQcm94eShmYWxzZSksXHJcbiAgU0VSVkVSX1JBVEVfTElNSVRJTkdfU0tJUF9LRVk6IHZhbGlkYXRvcnMuc2tpcEtleShmYWxzZSksXHJcbiAgU0VSVkVSX1JBVEVfTElNSVRJTkdfU0tJUF9UT0tFTjogdmFsaWRhdG9ycy5za2lwVG9rZW4oZmFsc2UpLFxyXG5cclxuICAvLyBzZXJ2ZXIgc3NsXHJcbiAgU0VSVkVSX1NTTF9FTkFCTEU6IHZhbGlkYXRvcnMuZW5hYmxlU3NsKGZhbHNlKSxcclxuICBTRVJWRVJfU1NMX0ZPUkNFOiB2YWxpZGF0b3JzLnNzbEZvcmNlKGZhbHNlKSxcclxuICBTRVJWRVJfU1NMX1BPUlQ6IHZhbGlkYXRvcnMuc3NsUG9ydChmYWxzZSksXHJcbiAgU0VSVkVSX1NTTF9DRVJUX1BBVEg6IHZhbGlkYXRvcnMuc3NsQ2VydFBhdGgoZmFsc2UpLFxyXG5cclxuICAvLyBwb29sXHJcbiAgUE9PTF9NSU5fV09SS0VSUzogdmFsaWRhdG9ycy5taW5Xb3JrZXJzKGZhbHNlKSxcclxuICBQT09MX01BWF9XT1JLRVJTOiB2YWxpZGF0b3JzLm1heFdvcmtlcnMoZmFsc2UpLFxyXG4gIFBPT0xfV09SS19MSU1JVDogdmFsaWRhdG9ycy53b3JrTGltaXQoZmFsc2UpLFxyXG4gIFBPT0xfQUNRVUlSRV9USU1FT1VUOiB2YWxpZGF0b3JzLmFjcXVpcmVUaW1lb3V0KGZhbHNlKSxcclxuICBQT09MX0NSRUFURV9USU1FT1VUOiB2YWxpZGF0b3JzLmNyZWF0ZVRpbWVvdXQoZmFsc2UpLFxyXG4gIFBPT0xfREVTVFJPWV9USU1FT1VUOiB2YWxpZGF0b3JzLmRlc3Ryb3lUaW1lb3V0KGZhbHNlKSxcclxuICBQT09MX0lETEVfVElNRU9VVDogdmFsaWRhdG9ycy5pZGxlVGltZW91dChmYWxzZSksXHJcbiAgUE9PTF9DUkVBVEVfUkVUUllfSU5URVJWQUw6IHZhbGlkYXRvcnMuY3JlYXRlUmV0cnlJbnRlcnZhbChmYWxzZSksXHJcbiAgUE9PTF9SRUFQRVJfSU5URVJWQUw6IHZhbGlkYXRvcnMucmVhcGVySW50ZXJ2YWwoZmFsc2UpLFxyXG4gIFBPT0xfQkVOQ0hNQVJLSU5HOiB2YWxpZGF0b3JzLnBvb2xCZW5jaG1hcmtpbmcoZmFsc2UpLFxyXG5cclxuICAvLyBsb2dnaW5nXHJcbiAgTE9HR0lOR19MRVZFTDogdmFsaWRhdG9ycy5sb2dMZXZlbChmYWxzZSksXHJcbiAgTE9HR0lOR19GSUxFOiB2YWxpZGF0b3JzLmxvZ0ZpbGUoZmFsc2UpLFxyXG4gIExPR0dJTkdfREVTVDogdmFsaWRhdG9ycy5sb2dEZXN0KGZhbHNlKSxcclxuICBMT0dHSU5HX1RPX0NPTlNPTEU6IHZhbGlkYXRvcnMubG9nVG9Db25zb2xlKGZhbHNlKSxcclxuICBMT0dHSU5HX1RPX0ZJTEU6IHZhbGlkYXRvcnMubG9nVG9GaWxlKGZhbHNlKSxcclxuXHJcbiAgLy8gdWlcclxuICBVSV9FTkFCTEU6IHZhbGlkYXRvcnMuZW5hYmxlVWkoZmFsc2UpLFxyXG4gIFVJX1JPVVRFOiB2YWxpZGF0b3JzLnVpUm91dGUoZmFsc2UpLFxyXG5cclxuICAvLyBvdGhlclxyXG4gIE9USEVSX05PREVfRU5WOiB2YWxpZGF0b3JzLm5vZGVFbnYoZmFsc2UpLFxyXG4gIE9USEVSX0xJU1RFTl9UT19QUk9DRVNTX0VYSVRTOiB2YWxpZGF0b3JzLmxpc3RlblRvUHJvY2Vzc0V4aXRzKGZhbHNlKSxcclxuICBPVEhFUl9OT19MT0dPOiB2YWxpZGF0b3JzLm5vTG9nbyhmYWxzZSksXHJcbiAgT1RIRVJfSEFSRF9SRVNFVF9QQUdFOiB2YWxpZGF0b3JzLmhhcmRSZXNldFBhZ2UoZmFsc2UpLFxyXG4gIE9USEVSX0JST1dTRVJfU0hFTExfTU9ERTogdmFsaWRhdG9ycy5icm93c2VyU2hlbGxNb2RlKGZhbHNlKSxcclxuICBPVEhFUl9WQUxJREFUSU9OOiB2YWxpZGF0b3JzLnZhbGlkYXRpb24oZmFsc2UpLFxyXG5cclxuICAvLyBkZWJ1Z2dlclxyXG4gIERFQlVHX0VOQUJMRTogdmFsaWRhdG9ycy5lbmFibGVEZWJ1ZyhmYWxzZSksXHJcbiAgREVCVUdfSEVBRExFU1M6IHZhbGlkYXRvcnMuaGVhZGxlc3MoZmFsc2UpLFxyXG4gIERFQlVHX0RFVlRPT0xTOiB2YWxpZGF0b3JzLmRldnRvb2xzKGZhbHNlKSxcclxuICBERUJVR19MSVNURU5fVE9fQ09OU09MRTogdmFsaWRhdG9ycy5saXN0ZW5Ub0NvbnNvbGUoZmFsc2UpLFxyXG4gIERFQlVHX0RVTVBJTzogdmFsaWRhdG9ycy5kdW1waW8oZmFsc2UpLFxyXG4gIERFQlVHX1NMT1dfTU86IHZhbGlkYXRvcnMuc2xvd01vKGZhbHNlKSxcclxuICBERUJVR19ERUJVR0dJTkdfUE9SVDogdmFsaWRhdG9ycy5kZWJ1Z2dpbmdQb3J0KGZhbHNlKVxyXG59KTtcclxuXHJcbi8qKlxyXG4gKiBWYWxpZGF0ZXMgdGhlIGVudmlyb25tZW50IHZhcmlhYmxlcyBvcHRpb25zIHVzaW5nIHRoZSBFbnZTY2hlbWEuXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBwcm9jZXNzLmVudiAtIFRoZSBjb25maWd1cmF0aW9uIG9wdGlvbnMgZnJvbSBlbnZpcm9ubWVudFxyXG4gKiB2YXJpYWJsZXMgZmlsZSB0byB2YWxpZGF0ZS5cclxuICpcclxuICogQHJldHVybnMge09iamVjdH0gVGhlIHBhcnNlZCBhbmQgdmFsaWRhdGVkIGVudmlyb25tZW50IHZhcmlhYmxlcy5cclxuICovXHJcbmV4cG9ydCBjb25zdCBlbnZzID0gRW52U2NoZW1hLnBhcnRpYWwoKS5wYXJzZShwcm9jZXNzLmVudik7XHJcblxyXG4vKipcclxuICogVmFsaWRhdGVzIHRoZSBjb25maWd1cmF0aW9uIG9wdGlvbnMgdXNpbmcgdGhlIGBTdHJpY3RDb25maWdTY2hlbWFgLlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gc3RyaWN0VmFsaWRhdGVcclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IGNvbmZpZ09wdGlvbnMgLSBUaGUgY29uZmlndXJhdGlvbiBvcHRpb25zIHRvIHZhbGlkYXRlLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7T2JqZWN0fSBUaGUgcGFyc2VkIGFuZCB2YWxpZGF0ZWQgY29uZmlndXJhdGlvbiBvcHRpb25zLlxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIHN0cmljdFZhbGlkYXRlKGNvbmZpZ09wdGlvbnMpIHtcclxuICByZXR1cm4gU3RyaWN0Q29uZmlnU2NoZW1hLnBhcnRpYWwoKS5wYXJzZShjb25maWdPcHRpb25zKTtcclxufVxyXG5cclxuLyoqXHJcbiAqIFZhbGlkYXRlcyB0aGUgY29uZmlndXJhdGlvbiBvcHRpb25zIHVzaW5nIHRoZSBgTG9vc2VDb25maWdTY2hlbWFgLlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gbG9vc2VWYWxpZGF0ZVxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gY29uZmlnT3B0aW9ucyAtIFRoZSBjb25maWd1cmF0aW9uIG9wdGlvbnMgdG8gdmFsaWRhdGUuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtPYmplY3R9IFRoZSBwYXJzZWQgYW5kIHZhbGlkYXRlZCBjb25maWd1cmF0aW9uIG9wdGlvbnMuXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gbG9vc2VWYWxpZGF0ZShjb25maWdPcHRpb25zKSB7XHJcbiAgcmV0dXJuIExvb3NlQ29uZmlnU2NoZW1hLnBhcnRpYWwoKS5wYXJzZShjb25maWdPcHRpb25zKTtcclxufVxyXG5cclxuLyoqXHJcbiAqIEN1c3RvbSBlcnJvciBtYXBwaW5nIGZ1bmN0aW9uIGZvciBab2Qgc2NoZW1hIHZhbGlkYXRpb24uXHJcbiAqXHJcbiAqIFRoaXMgZnVuY3Rpb24gY3VzdG9taXplcyB0aGUgZXJyb3IgbWVzc2FnZXMgcHJvZHVjZWQgYnkgWm9kIHNjaGVtYVxyXG4gKiB2YWxpZGF0aW9uLCBwcm92aWRpbmcgbW9yZSBzcGVjaWZpYyBhbmQgdXNlci1mcmllbmRseSBmZWVkYmFjayBiYXNlZCBvbiB0aGVcclxuICogaXNzdWUgdHlwZSBhbmQgY29udGV4dC5cclxuICpcclxuICogVGhlIGZ1bmN0aW9uIG1vZGlmaWVzIHRoZSBlcnJvciBtZXNzYWdlcyBhcyBmb2xsb3dzOlxyXG4gKlxyXG4gKiAtIEZvciBtaXNzaW5nIHJlcXVpcmVkIHZhbHVlcyAodW5kZWZpbmVkKSwgaXQgcmV0dXJucyBhIG1lc3NhZ2UgaW5kaWNhdGluZ1xyXG4gKiB0aGF0IG5vIHZhbHVlIHdhcyBwcm92aWRlZCBmb3IgdGhlIHNwZWNpZmljIHByb3BlcnR5LlxyXG4gKlxyXG4gKiAtIEZvciBjdXN0b20gdmFsaWRhdGlvbiBlcnJvcnMsIGlmIGEgY3VzdG9tIGVycm9yIG1lc3NhZ2UgaXMgcHJvdmlkZWQgaW4gdGhlXHJcbiAqIGlzc3VlIHBhcmFtZXRlcnMsIGl0IGluY2x1ZGVzIHRoaXMgbWVzc2FnZSBhbG9uZyB3aXRoIHRoZSBpbnZhbGlkIGRhdGFcclxuICogcmVjZWl2ZWQuXHJcbiAqXHJcbiAqIC0gRm9yIGFsbCBvdGhlciBlcnJvcnMsIGl0IGFwcGVuZHMgcHJvcGVydHktc3BlY2lmaWMgaW5mb3JtYXRpb24gdG8gdGhlXHJcbiAqIGRlZmF1bHQgZXJyb3IgbWVzc2FnZSBwcm92aWRlZCBieSBab2QuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBfY3VzdG9tRXJyb3JNYXBcclxuICpcclxuICogQHBhcmFtIHt6LlpvZElzc3VlfSBpc3N1ZSAtIFRoZSBpc3N1ZSBvYmplY3QgcmVwcmVzZW50aW5nIHRoZSB2YWxpZGF0aW9uXHJcbiAqIGVycm9yLlxyXG4gKiBAcGFyYW0ge09iamVjdH0gY29udGV4dCAtIFRoZSBjb250ZXh0IG9iamVjdCBwcm92aWRpbmcgYWRkaXRpb25hbCBpbmZvcm1hdGlvblxyXG4gKiBhYm91dCB0aGUgdmFsaWRhdGlvbiBlcnJvci5cclxuICpcclxuICogQHJldHVybnMge09iamVjdH0gQW4gb2JqZWN0IGNvbnRhaW5pbmcgdGhlIGN1c3RvbWl6ZWQgZXJyb3IgbWVzc2FnZS5cclxuICovXHJcbmZ1bmN0aW9uIF9jdXN0b21FcnJvck1hcChpc3N1ZSwgY29udGV4dCkge1xyXG4gIC8vIEdldCB0aGUgY2hhaW4gb2YgcHJvcGVydGllcyB3aGljaCBlcnJvciBkaXJlY3RseSByZWZlcnMgdG9cclxuICBjb25zdCBwcm9wZXJ0eU5hbWUgPSBpc3N1ZS5wYXRoLmpvaW4oJy4nKTtcclxuXHJcbiAgLy8gQ3JlYXRlIHRoZSBmaXJzdCBwYXJ0IG9mIHRoZSBtZXNzYWdlIGFib3V0IHRoZSBwcm9wZXJ0eSBpbmZvcm1hdGlvblxyXG4gIGNvbnN0IHByb3BlcnR5SW5mbyA9IGBJbnZhbGlkIHZhbHVlIGZvciB0aGUgJHtwcm9wZXJ0eU5hbWV9YDtcclxuXHJcbiAgLy8gTW9kaWZpZWQgbWVzc2FnZSBmb3IgdGhlIGludmFsaWQgdHlwZVxyXG4gIGlmIChpc3N1ZS5jb2RlID09PSB6LlpvZElzc3VlQ29kZS5pbnZhbGlkX3R5cGUpIHtcclxuICAgIC8vIE1vZGlmaWVkIG1lc3NhZ2UgZm9yIHRoZSByZXF1aXJlZCB2YWx1ZXNcclxuICAgIGlmIChpc3N1ZS5yZWNlaXZlZCA9PT0gei5ab2RQYXJzZWRUeXBlLnVuZGVmaW5lZCkge1xyXG4gICAgICByZXR1cm4ge1xyXG4gICAgICAgIG1lc3NhZ2U6IGAke3Byb3BlcnR5SW5mb30gLSBObyB2YWx1ZSB3YXMgcHJvdmlkZWQuYFxyXG4gICAgICB9O1xyXG4gICAgfVxyXG5cclxuICAgIC8vIE1vZGlmaWVkIG1lc3NhZ2UgZm9yIHRoZSBzcGVjaWZpYyBpbnZhbGlkIHR5cGUgd2hlbiB2YWx1ZXMgZXhpc3RcclxuICAgIHJldHVybiB7XHJcbiAgICAgIG1lc3NhZ2U6IGAke3Byb3BlcnR5SW5mb30gLSBJbnZhbGlkIHR5cGUuICR7Y29udGV4dC5kZWZhdWx0RXJyb3J9LmBcclxuICAgIH07XHJcbiAgfVxyXG5cclxuICAvLyBNb2RpZmllZCBtZXNzYWdlIGZvciB0aGUgY3VzdG9tIHZhbGlkYXRpb25cclxuICBpZiAoaXNzdWUuY29kZSA9PT0gei5ab2RJc3N1ZUNvZGUuY3VzdG9tKSB7XHJcbiAgICAvLyBJZiB0aGUgY3VzdG9tIG1lc3NhZ2UgZm9yIGVycm9yIGV4aXN0LCBpbmNsdWRlIGl0XHJcbiAgICBpZiAoaXNzdWUucGFyYW1zPy5lcnJvck1lc3NhZ2UpIHtcclxuICAgICAgcmV0dXJuIHtcclxuICAgICAgICBtZXNzYWdlOiBgJHtwcm9wZXJ0eUluZm99IC0gJHtpc3N1ZS5wYXJhbXM/LmVycm9yTWVzc2FnZX0sIHJlY2VpdmVkICcke2NvbnRleHQuZGF0YX0nLmBcclxuICAgICAgfTtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIC8vIE1vZGlmaWVkIG1lc3NhZ2UgZm9yIHRoZSBpbnZhbGlkIHVuaW9uIGVycm9yXHJcbiAgaWYgKGlzc3VlLmNvZGUgPT09IHouWm9kSXNzdWVDb2RlLmludmFsaWRfdW5pb24pIHtcclxuICAgIC8vIENyZWF0ZSB0aGUgZmlyc3QgcGFydCBvZiB0aGUgbWVzc2FnZSBhYm91dCB0aGUgbXVsdGlwbGUgZXJyb3JzXHJcbiAgICBsZXQgbWVzc2FnZSA9IGBNdWx0aXBsZSBlcnJvcnMgb2NjdXJyZWQgZm9yIHRoZSAke3Byb3BlcnR5TmFtZX06XFxuYDtcclxuXHJcbiAgICAvLyBDeWNsZSB0aHJvdWdoIGFsbCBlcnJvcnMgYW5kIGNyZWF0ZSBhIGNvcnJlY3QgbWVzc2FnZVxyXG4gICAgaXNzdWUudW5pb25FcnJvcnMuZm9yRWFjaCgodmFsdWUpID0+IHtcclxuICAgICAgY29uc3QgaW5kZXggPSB2YWx1ZS5pc3N1ZXNbMF0ubWVzc2FnZS5pbmRleE9mKCctJyk7XHJcbiAgICAgIG1lc3NhZ2UgKz1cclxuICAgICAgICBpbmRleCAhPT0gLTFcclxuICAgICAgICAgID8gYCR7dmFsdWUuaXNzdWVzWzBdLm1lc3NhZ2V9XFxuYC5zdWJzdHJpbmcoaW5kZXgpXHJcbiAgICAgICAgICA6IGAke3ZhbHVlLmlzc3Vlc1swXS5tZXNzYWdlfVxcbmA7XHJcbiAgICB9KTtcclxuXHJcbiAgICAvLyBSZXR1cm4gdGhlIGZpbmFsIG1lc3NhZ2UgZm9yIHRoZSBpbnZhbGlkIHVuaW9uIGVycm9yXHJcbiAgICByZXR1cm4ge1xyXG4gICAgICBtZXNzYWdlXHJcbiAgICB9O1xyXG4gIH1cclxuXHJcbiAgLy8gUmV0dXJuIHRoZSBkZWZhdWx0IGVycm9yIG1lc3NhZ2UsIGV4dGVuZGVkIGJ5IHRoZSBpbmZvIGFib3V0IHRoZSBwcm9wZXJ0eVxyXG4gIHJldHVybiB7XHJcbiAgICBtZXNzYWdlOiBgJHtwcm9wZXJ0eUluZm99IC0gJHtjb250ZXh0LmRlZmF1bHRFcnJvcn0uYFxyXG4gIH07XHJcbn1cclxuXHJcbmV4cG9ydCBkZWZhdWx0IHtcclxuICB2YWxpZGF0b3JzLFxyXG4gIFN0cmljdENvbmZpZ1NjaGVtYSxcclxuICBMb29zZUNvbmZpZ1NjaGVtYSxcclxuICBFbnZTY2hlbWEsXHJcbiAgZW52cyxcclxuICBzdHJpY3RWYWxpZGF0ZSxcclxuICBsb29zZVZhbGlkYXRlXHJcbn07XHJcbiIsIi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXHJcblxyXG5IaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXJcclxuXHJcbkNvcHlyaWdodCAoYykgMjAxNi0yMDI1LCBIaWdoc29mdFxyXG5cclxuTGljZW5jZWQgdW5kZXIgdGhlIE1JVCBsaWNlbmNlLlxyXG5cclxuQWRkaXRpb25hbGx5IGEgdmFsaWQgSGlnaGNoYXJ0cyBsaWNlbnNlIGlzIHJlcXVpcmVkIGZvciB1c2UuXHJcblxyXG5TZWUgTElDRU5TRSBmaWxlIGluIHJvb3QgZm9yIGRldGFpbHMuXHJcblxyXG4qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xyXG5cclxuLyoqXHJcbiAqIEEgY3VzdG9tIGVycm9yIGNsYXNzIGZvciBoYW5kbGluZyBleHBvcnQtcmVsYXRlZCBlcnJvcnMuIEV4dGVuZHMgdGhlIG5hdGl2ZVxyXG4gKiBgRXJyb3JgIGNsYXNzIHRvIGluY2x1ZGUgYWRkaXRpb25hbCBwcm9wZXJ0aWVzIGxpa2Ugc3RhdHVzIGNvZGUgYW5kIHN0YWNrXHJcbiAqIHRyYWNlIGRldGFpbHMuXHJcbiAqL1xyXG5jbGFzcyBFeHBvcnRFcnJvciBleHRlbmRzIEVycm9yIHtcclxuICAvKipcclxuICAgKiBDcmVhdGVzIGFuIGluc3RhbmNlIG9mIHRoZSBgRXhwb3J0RXJyb3JgLlxyXG4gICAqXHJcbiAgICogQHBhcmFtIHtzdHJpbmd9IG1lc3NhZ2UgLSBUaGUgZXJyb3IgbWVzc2FnZSB0byBiZSBkaXNwbGF5ZWQuXHJcbiAgICogQHBhcmFtIHtudW1iZXJ9IHN0YXR1c0NvZGUgLSBPcHRpb25hbCBIVFRQIHN0YXR1cyBjb2RlIGFzc29jaWF0ZWRcclxuICAgKiB3aXRoIHRoZSBlcnJvciAoZS5nLiwgNDAwLCA1MDApLlxyXG4gICAqL1xyXG4gIGNvbnN0cnVjdG9yKG1lc3NhZ2UsIHN0YXR1c0NvZGUpIHtcclxuICAgIHN1cGVyKCk7XHJcblxyXG4gICAgLy8gU2V0IHRoZSBgbWVzc2FnZWAgYW5kIGBzdGFja01lc3NhZ2VgIHdpdGggcHJvdmlkZWQgbWVzc2FnZVxyXG4gICAgdGhpcy5tZXNzYWdlID0gbWVzc2FnZTtcclxuICAgIHRoaXMuc3RhY2tNZXNzYWdlID0gbWVzc2FnZTtcclxuXHJcbiAgICAvLyBTZXQgdGhlIGBzdGF0dXNDb2RlYCBpZiBwcm92aWRlZFxyXG4gICAgaWYgKHN0YXR1c0NvZGUpIHtcclxuICAgICAgdGhpcy5zdGF0dXNDb2RlID0gc3RhdHVzQ29kZTtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIC8qKlxyXG4gICAqIFNldHMgYWRkaXRpb25hbCBlcnJvciBkZXRhaWxzIGJhc2VkIG9uIGFuIGV4aXN0aW5nIGVycm9yIG9iamVjdC5cclxuICAgKlxyXG4gICAqIEBwYXJhbSB7RXJyb3J9IGVycm9yIC0gQW4gZXJyb3Igb2JqZWN0IGNvbnRhaW5pbmcgZGV0YWlscyB0byBwb3B1bGF0ZVxyXG4gICAqIHRoZSBgRXhwb3J0RXJyb3JgIGluc3RhbmNlLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge0V4cG9ydEVycm9yfSBUaGUgdXBkYXRlZCBpbnN0YW5jZSBvZiB0aGUgYEV4cG9ydEVycm9yYCBjbGFzcy5cclxuICAgKi9cclxuICBzZXRFcnJvcihlcnJvcikge1xyXG4gICAgLy8gU2F2ZSB0aGUgcHJvdmlkZWQgZXJyb3JcclxuICAgIHRoaXMuZXJyb3IgPSBlcnJvcjtcclxuXHJcbiAgICAvLyBTZXQgdGhlIGVycm9yJ3MgbmFtZSBpZiBwcmVzZW50XHJcbiAgICBpZiAoZXJyb3IubmFtZSkge1xyXG4gICAgICB0aGlzLm5hbWUgPSBlcnJvci5uYW1lO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIFNldCB0aGUgZXJyb3IncyBzdGF0dXMgY29kZSBpZiBwcmVzZW50XHJcbiAgICBpZiAoZXJyb3Iuc3RhdHVzQ29kZSkge1xyXG4gICAgICB0aGlzLnN0YXR1c0NvZGUgPSBlcnJvci5zdGF0dXNDb2RlO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIFNldCB0aGUgZXJyb3IncyBzdGFjayBhbmQgc3RhY2sncyBtZXNzYWdlIGlmIHByZXNlbnRcclxuICAgIGlmIChlcnJvci5zdGFjaykge1xyXG4gICAgICB0aGlzLnN0YWNrTWVzc2FnZSA9IGVycm9yLm1lc3NhZ2U7XHJcbiAgICAgIHRoaXMuc3RhY2sgPSBlcnJvci5zdGFjaztcclxuICAgIH1cclxuXHJcbiAgICAvLyBSZXR1cm4gdXBkYXRlZCBgRXhwb3J0RXJyb3JgIGluc3RhbmNlXHJcbiAgICByZXR1cm4gdGhpcztcclxuICB9XHJcbn1cclxuXHJcbmV4cG9ydCBkZWZhdWx0IEV4cG9ydEVycm9yO1xyXG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxyXG5cclxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXHJcblxyXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNSwgSGlnaHNvZnRcclxuXHJcbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cclxuXHJcbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxyXG5cclxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxyXG5cclxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cclxuXHJcbi8qKlxyXG4gKiBAb3ZlcnZpZXcgVGhpcyBtb2R1bGUgbWFuYWdlcyBjb25maWd1cmF0aW9uIGZvciB0aGUgSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXHJcbiAqIGJ5IGxvYWRpbmcgYW5kIG1lcmdpbmcgb3B0aW9ucyBmcm9tIG11bHRpcGxlIHNvdXJjZXMsIHN1Y2ggYXMgdGhlIGRlZmF1bHRcclxuICogc2V0dGluZ3MsIGVudmlyb25tZW50IHZhcmlhYmxlcywgdXNlci1wcm92aWRlZCBvcHRpb25zLCBhbmQgY29tbWFuZC1saW5lXHJcbiAqIGFyZ3VtZW50cy4gRW5zdXJlcyB0aGUgZ2xvYmFsIG9wdGlvbnMgYXJlIHVwLXRvLWRhdGUgd2l0aCB0aGUgaGlnaGVzdFxyXG4gKiBwcmlvcml0eSB2YWx1ZXMuIFByb3ZpZGVzIGZ1bmN0aW9ucyBmb3IgYWNjZXNzaW5nIGFuZCB1cGRhdGluZyBjb25maWd1cmF0aW9uLlxyXG4gKi9cclxuXHJcbmltcG9ydCB7IHJlYWRGaWxlU3luYyB9IGZyb20gJ2ZzJztcclxuXHJcbmltcG9ydCB7IGxvZywgbG9nV2l0aFN0YWNrLCBsb2dab2RJc3N1ZXMgfSBmcm9tICcuL2xvZ2dlci5qcyc7XHJcbmltcG9ydCB7IGRlZXBDb3B5LCBnZXRBYnNvbHV0ZVBhdGgsIGlzT2JqZWN0IH0gZnJvbSAnLi91dGlscy5qcyc7XHJcbmltcG9ydCB7XHJcbiAgZW52cyxcclxuICBsb29zZVZhbGlkYXRlLFxyXG4gIHN0cmljdFZhbGlkYXRlLFxyXG4gIHZhbGlkYXRvcnNcclxufSBmcm9tICcuL3ZhbGlkYXRpb24uanMnO1xyXG5cclxuaW1wb3J0IGRlZmF1bHRDb25maWcgZnJvbSAnLi9zY2hlbWFzL2NvbmZpZy5qcyc7XHJcblxyXG5pbXBvcnQgRXhwb3J0RXJyb3IgZnJvbSAnLi9lcnJvcnMvRXhwb3J0RXJyb3IuanMnO1xyXG5cclxuLy8gU2V0cyB0aGUgZ2xvYmFsIG9wdGlvbnMgd2l0aCBpbml0aWFsIHZhbHVlcyBmcm9tIHRoZSBkZWZhdWx0IGNvbmZpZ1xyXG5jb25zdCBnbG9iYWxPcHRpb25zID0gX2luaXRPcHRpb25zKGRlZmF1bHRDb25maWcpO1xyXG5cclxuLy8gUHJvcGVydGllcyBuZXN0aW5nIGxldmVsIG9mIGFsbCBvcHRpb25zXHJcbmNvbnN0IG5lc3RlZFByb3BzID0gX2NyZWF0ZU5lc3RlZFByb3BzKGRlZmF1bHRDb25maWcpO1xyXG5cclxuLy8gUHJvcGVydGllcyBuYW1lcyB0aGF0IHNob3VsZCBub3QgYmUgcmVjdXJzaXZlbHkgbWVyZ2VkXHJcbmNvbnN0IGFic29sdXRlUHJvcHMgPSBfY3JlYXRlQWJzb2x1dGVQcm9wcyhkZWZhdWx0Q29uZmlnKTtcclxuXHJcbi8qKlxyXG4gKiBSZXRyaWV2ZXMgYSBjb3B5IG9mIHRoZSBnbG9iYWwgb3B0aW9ucyBvYmplY3Qgb3IgYW4gb3JpZ2luYWwgZ2xvYmFsIG9wdGlvbnNcclxuICogb2JqZWN0LCBiYXNlZCBvbiB0aGUgYGdldENvcHlgIGZsYWcuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBnZXRPcHRpb25zXHJcbiAqXHJcbiAqIEBwYXJhbSB7Ym9vbGVhbn0gW2dldENvcHk9dHJ1ZV0gLSBTcGVjaWZpZXMgd2hldGhlciB0byByZXR1cm4gYSBjb3BpZWRcclxuICogb2JqZWN0IG9mIHRoZSBnbG9iYWwgb3B0aW9ucyAoYHRydWVgKSBvciBhIHJlZmVyZW5jZSB0byB0aGUgZ2xvYmFsIG9wdGlvbnNcclxuICogb2JqZWN0IChgZmFsc2VgKS4gVGhlIGRlZmF1bHQgdmFsdWUgaXMgYHRydWVgLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7T2JqZWN0fSBBIGNvcHkgb2YgdGhlIGdsb2JhbCBvcHRpb25zIG9iamVjdCwgb3IgYSByZWZlcmVuY2VcclxuICogdG8gdGhlIGdsb2JhbCBvcHRpb25zIG9iamVjdC5cclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiBnZXRPcHRpb25zKGdldENvcHkgPSB0cnVlKSB7XHJcbiAgLy8gUmV0dXJuIGEgY29weSBvciBhbiBvcmlnaW5hbCBnbG9iYWwgb3B0aW9ucyBvYmplY3RcclxuICByZXR1cm4gZ2V0Q29weSA/IGRlZXBDb3B5KGdsb2JhbE9wdGlvbnMpIDogZ2xvYmFsT3B0aW9ucztcclxufVxyXG5cclxuLyoqXHJcbiAqIFVwZGF0ZXMgYW5kIHJldHVybnMgdGhlIGdsb2JhbCBvcHRpb25zIG9iamVjdCBvciBhIGNvcHkgb2YgdGhlIGdsb2JhbCBvcHRpb25zXHJcbiAqIG9iamVjdCwgYmFzZWQgb24gdGhlIGBnZXRDb3B5YCBmbGFnLiBUaGUgYG5ld09wdGlvbnNgIG9iamVjdCBjYW4gYmVcclxuICogc3RyaWN0bHkgdmFsaWRhdGVkIGRlcGVuZGluZyBvbiB0aGUgYHN0cmljdENoZWNrYCBmbGFnLlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gdXBkYXRlT3B0aW9uc1xyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gbmV3T3B0aW9ucyAtIEFuIG9iamVjdCBjb250YWluaW5nIHRoZSBuZXcgb3B0aW9ucyB0byBiZVxyXG4gKiBtZXJnZWQgaW50byB0aGUgZ2xvYmFsIG9wdGlvbnMuXHJcbiAqIEBwYXJhbSB7Ym9vbGVhbn0gW2dldENvcHk9ZmFsc2VdIC0gRGV0ZXJtaW5lcyB3aGV0aGVyIHRvIG1lcmdlIHRoZSBuZXdcclxuICogb3B0aW9ucyBpbnRvIGEgY29weSBvZiB0aGUgZ2xvYmFsIG9wdGlvbnMgb2JqZWN0IChgdHJ1ZWApIG9yIGRpcmVjdGx5IGludG9cclxuICogdGhlIGdsb2JhbCBvcHRpb25zIG9iamVjdCAoYGZhbHNlYCkuIFRoZSBkZWZhdWx0IHZhbHVlIGlzIGBmYWxzZWAuXHJcbiAqIEBwYXJhbSB7Ym9vbGVhbn0gW3N0cmljdENoZWNrPXRydWVdIC0gRGV0ZXJtaW5lcyBpZiBzdHJpY3RlciB2YWxpZGF0aW9uXHJcbiAqIHNob3VsZCBiZSBhcHBsaWVkLiBUaGUgZGVmYXVsdCB2YWx1ZSBpcyBgdHJ1ZWAuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtPYmplY3R9IFRoZSB1cGRhdGVkIG9wdGlvbnMgb2JqZWN0LCBlaXRoZXIgdGhlIG1vZGlmaWVkIGdsb2JhbFxyXG4gKiBvcHRpb25zIG9yIGEgbW9kaWZpZWQgY29weSwgYmFzZWQgb24gdGhlIHZhbHVlIG9mIGBnZXRDb3B5YC5cclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiB1cGRhdGVPcHRpb25zKG5ld09wdGlvbnMsIGdldENvcHkgPSBmYWxzZSwgc3RyaWN0Q2hlY2sgPSB0cnVlKSB7XHJcbiAgLy8gTWVyZ2UgbmV3IG9wdGlvbnMgdG8gdGhlIGdsb2JhbCBvcHRpb25zIG9yIGl0cyBjb3B5IGFuZCByZXR1cm4gdGhlIHJlc3VsdFxyXG4gIHJldHVybiBfbWVyZ2VPcHRpb25zKFxyXG4gICAgLy8gRmlyc3QsIGdldCB0aGUgb3B0aW9uc1xyXG4gICAgZ2V0T3B0aW9ucyhnZXRDb3B5KSxcclxuICAgIC8vIE5leHQsIHZhbGlkYXRlIHRoZSBuZXcgb3B0aW9uc1xyXG4gICAgdmFsaWRhdGVPcHRpb25zKG5ld09wdGlvbnMsIHN0cmljdENoZWNrKVxyXG4gICk7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBVcGRhdGVzIGFuZCByZXR1cm5zIHRoZSBnbG9iYWwgb3B0aW9ucyBvYmplY3Qgd2l0aCB2YWx1ZXMgcHJvdmlkZWQgdGhyb3VnaFxyXG4gKiB0aGUgQ0xJLCBrZWVwaW5nIHRoZSBwcmluY2lwbGUgb2Ygb3B0aW9ucyBsb2FkIHByaW9yaXR5LiBUaGUgZnVuY3Rpb24gYWNjZXB0c1xyXG4gKiBhIGBjbGlBcmdzYCBhcnJheSBjb250YWluaW5nIGFyZ3VtZW50cyBmcm9tIHRoZSBDTEksIHdoaWNoIHdpbGwgYmUgdmFsaWRhdGVkXHJcbiAqIGFuZCBhcHBsaWVkIGlmIHByb3ZpZGVkLlxyXG4gKlxyXG4gKiBUaGUgZnVuY3Rpb24gcHJpb3JpdGl6ZXMgdmFsdWVzIGluIHRoZSBmb2xsb3dpbmcgb3JkZXI6XHJcbiAqXHJcbiAqIDEuIFZhbHVlcyBmcm9tIHRoZSBjb21tYW5kIGxpbmUgaW50ZXJmYWNlIChDTEkpLlxyXG4gKiAyLiBWYWx1ZXMgZnJvbSBhIGN1c3RvbSBKU09OIGZpbGUgKGxvYWRlZCBieSB0aGUgYC0tbG9hZENvbmZpZ2Agb3B0aW9uKS5cclxuICpcclxuICogQGZ1bmN0aW9uIHNldENsaU9wdGlvbnNcclxuICpcclxuICogQHBhcmFtIHtBcnJheTxzdHJpbmc+fSBjbGlBcmdzIC0gQW4gYXJyYXkgb2YgY29tbWFuZCBsaW5lIGFyZ3VtZW50cyB1c2VkXHJcbiAqIGZvciBhZGRpdGlvbmFsIGNvbmZpZ3VyYXRpb24uXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtPYmplY3R9IFRoZSB1cGRhdGVkIGdsb2JhbCBvcHRpb25zIG9iamVjdCwgcmVmbGVjdGluZyB0aGUgbWVyZ2VkXHJcbiAqIGNvbmZpZ3VyYXRpb24gZnJvbSBzb3VyY2VzIHByb3ZpZGVkIHRocm91Z2ggdGhlIENMSS5cclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiBzZXRDbGlPcHRpb25zKGNsaUFyZ3MpIHtcclxuICAvLyBPbmx5IGZvciB0aGUgQ0xJIHVzYWdlXHJcbiAgaWYgKGNsaUFyZ3MgJiYgQXJyYXkuaXNBcnJheShjbGlBcmdzKSAmJiBjbGlBcmdzLmxlbmd0aCkge1xyXG4gICAgdHJ5IHtcclxuICAgICAgLy8gR2V0IG9wdGlvbnMgZnJvbSB0aGUgY3VzdG9tIEpTT04gbG9hZGVkIHZpYSB0aGUgYC0tbG9hZENvbmZpZ2BcclxuICAgICAgY29uc3QgY29uZmlnT3B0aW9ucyA9IF9sb2FkQ29uZmlnRmlsZShjbGlBcmdzKTtcclxuXHJcbiAgICAgIC8vIFVwZGF0ZSBnbG9iYWwgb3B0aW9ucyB3aXRoIHZhbGlkYXRlZCB2YWx1ZXMgZnJvbSB0aGUgYGNvbmZpZ09wdGlvbnNgXHJcbiAgICAgIHVwZGF0ZU9wdGlvbnMoY29uZmlnT3B0aW9ucyk7XHJcbiAgICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgICBsb2coMiwgJ1t2YWxpZGF0aW9uXSBObyBvcHRpb25zIGFkZGVkIGZyb20gdGhlIGAtLWxvYWRDb25maWdgIG9wdGlvbi4nKTtcclxuICAgIH1cclxuXHJcbiAgICB0cnkge1xyXG4gICAgICAvLyBHZXQgb3B0aW9ucyBmcm9tIHRoZSBDTElcclxuICAgICAgY29uc3QgY2xpT3B0aW9ucyA9IF9wYWlyQXJndW1lbnRWYWx1ZShjbGlBcmdzKTtcclxuXHJcbiAgICAgIC8vIFVwZGF0ZSBnbG9iYWwgb3B0aW9ucyB3aXRoIHZhbGlkYXRlZCB2YWx1ZXMgZnJvbSB0aGUgYGNsaU9wdGlvbnNgXHJcbiAgICAgIHVwZGF0ZU9wdGlvbnMoY2xpT3B0aW9ucywgZmFsc2UsIGZhbHNlKTtcclxuICAgIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICAgIGxvZygyLCAnW3ZhbGlkYXRpb25dIE5vIG9wdGlvbnMgYWRkZWQgZnJvbSB0aGUgQ0xJIGFyZ3VtZW50cy4nKTtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIC8vIFJldHVybiByZWZlcmVuY2UgdG8gdGhlIGdsb2JhbCBvcHRpb25zXHJcbiAgcmV0dXJuIGdldE9wdGlvbnMoZmFsc2UpO1xyXG59XHJcblxyXG4vKipcclxuICogTWFwcyBvbGQtc3RydWN0dXJlZCBjb25maWd1cmF0aW9uIG9wdGlvbnMgKFBoYW50b21KUy1iYXNlZCkgdG8gYSBuZXcgZm9ybWF0XHJcbiAqIChQdXBwZXRlZXItYmFzZWQpLiBUaGlzIGZ1bmN0aW9uIGNvbnZlcnRzIGZsYXQsIG9sZC1zdHJ1Y3R1cmVkIG9wdGlvbnMgaW50b1xyXG4gKiBhIG5ldywgbmVzdGVkIGNvbmZpZ3VyYXRpb24gZm9ybWF0IGJhc2VkIG9uIGEgcHJlZGVmaW5lZCBtYXBwaW5nIHByb3ZpZGVkXHJcbiAqIGluIHRoZSBgbmVzdGVkUHJvcHNgIG9iamVjdC4gVGhlIG5ldyBmb3JtYXQgaXMgdXNlZCBmb3IgUHVwcGV0ZWVyLCB3aGlsZVxyXG4gKiB0aGUgb2xkIGZvcm1hdCB3YXMgdXNlZCBmb3IgUGhhbnRvbUpTLlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gbWFwVG9OZXdPcHRpb25zXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBvbGRPcHRpb25zIC0gVGhlIG9sZCwgZmxhdCBjb25maWd1cmF0aW9uIG9wdGlvbnNcclxuICogdG8gYmUgY29udmVydGVkLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7T2JqZWN0fSBBIG5ldyBvYmplY3QgY29udGFpbmluZyBvcHRpb25zIHN0cnVjdHVyZWQgYWNjb3JkaW5nXHJcbiAqIHRvIHRoZSBtYXBwaW5nIGRlZmluZWQgaW4gdGhlIGBuZXN0ZWRQcm9wc2Agb2JqZWN0IG9yIGFuIGVtcHR5IG9iamVjdFxyXG4gKiBpZiB0aGUgcHJvdmlkZWQgYG9sZE9wdGlvbnNgIGlzIG5vdCBhIGNvcnJlY3Qgb2JqZWN0LlxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIG1hcFRvTmV3T3B0aW9ucyhvbGRPcHRpb25zKSB7XHJcbiAgLy8gQW4gb2JqZWN0IGZvciB0aGUgbmV3IHN0cnVjdHVyZWQgb3B0aW9uc1xyXG4gIGNvbnN0IG5ld09wdGlvbnMgPSB7fTtcclxuXHJcbiAgLy8gQ2hlY2sgaWYgcHJvdmlkZWQgdmFsdWUgaXMgYSBjb3JyZWN0IG9iamVjdFxyXG4gIGlmIChpc09iamVjdChvbGRPcHRpb25zKSkge1xyXG4gICAgLy8gSXRlcmF0ZSBvdmVyIGVhY2gga2V5LXZhbHVlIHBhaXIgaW4gdGhlIG9sZC1zdHJ1Y3R1cmVkIG9wdGlvbnNcclxuICAgIGZvciAoY29uc3QgW2tleSwgdmFsdWVdIG9mIE9iamVjdC5lbnRyaWVzKG9sZE9wdGlvbnMpKSB7XHJcbiAgICAgIC8vIElmIHRoZXJlIGlzIGEgbmVzdGVkIG1hcHBpbmcsIHNwbGl0IGl0IGludG8gYSBwcm9wZXJ0aWVzIGNoYWluXHJcbiAgICAgIGNvbnN0IHByb3BlcnRpZXNDaGFpbiA9IG5lc3RlZFByb3BzW2tleV1cclxuICAgICAgICA/IG5lc3RlZFByb3BzW2tleV0uc3BsaXQoJy4nKVxyXG4gICAgICAgIDogW107XHJcblxyXG4gICAgICAvLyBJZiBpdCBpcyB0aGUgbGFzdCBwcm9wZXJ0eSBpbiB0aGUgY2hhaW4sIGFzc2lnbiB0aGUgdmFsdWUsIG90aGVyd2lzZSxcclxuICAgICAgLy8gY3JlYXRlIG9yIHJldXNlIHRoZSBuZXN0ZWQgb2JqZWN0XHJcbiAgICAgIHByb3BlcnRpZXNDaGFpbi5yZWR1Y2UoXHJcbiAgICAgICAgKG9iaiwgcHJvcCwgaW5kZXgpID0+XHJcbiAgICAgICAgICAob2JqW3Byb3BdID1cclxuICAgICAgICAgICAgcHJvcGVydGllc0NoYWluLmxlbmd0aCAtIDEgPT09IGluZGV4ID8gdmFsdWUgOiBvYmpbcHJvcF0gfHwge30pLFxyXG4gICAgICAgIG5ld09wdGlvbnNcclxuICAgICAgKTtcclxuICAgIH1cclxuICB9IGVsc2Uge1xyXG4gICAgbG9nKFxyXG4gICAgICAyLFxyXG4gICAgICAnW2NvbmZpZ10gTm8gY29ycmVjdCBvYmplY3Qgd2l0aCBvcHRpb25zIHdhcyBwcm92aWRlZC4gUmV0dXJuaW5nIGFuIGVtcHR5IG9iamVjdC4nXHJcbiAgICApO1xyXG4gIH1cclxuXHJcbiAgLy8gUmV0dXJuIHRoZSBuZXcsIHN0cnVjdHVyZWQgb3B0aW9ucyBvYmplY3RcclxuICByZXR1cm4gbmV3T3B0aW9ucztcclxufVxyXG5cclxuLyoqXHJcbiAqIFZhbGlkYXRlcyBhIHNwZWNpZmllZCBvcHRpb24gdXNpbmcgdGhlIGNvcnJlc3BvbmRpbmcgdmFsaWRhdG9yIGZyb20gdGhlXHJcbiAqIGNvbmZpZ3VyYXRpb24gb2JqZWN0LiBSZXR1cm5zIHRoZSBvcmlnaW5hbCBvcHRpb24gaWYgdGhlIHZhbGlkYXRpb25cclxuICogaXMgZGlzYWJsZWQgZ2xvYmFsbHkuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiB2YWxpZGF0ZU9wdGlvblxyXG4gKlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gbmFtZSAtIFRoZSBuYW1lIG9mIHRoZSBvcHRpb24gdG8gdmFsaWRhdGUuXHJcbiAqIEBwYXJhbSB7YW55fSBjb25maWdPcHRpb24gLSBUaGUgdmFsdWUgb2YgdGhlIG9wdGlvbiB0byB2YWxpZGF0ZS5cclxuICogQHBhcmFtIHtib29sZWFufSBbc3RyaWN0Q2hlY2s9dHJ1ZV0gLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb25cclxuICogc2hvdWxkIGJlIGFwcGxpZWQuIFRoZSBkZWZhdWx0IHZhbHVlIGlzIGB0cnVlYC5cclxuICpcclxuICogQHJldHVybnMge2FueX0gVGhlIHBhcnNlZCBhbmQgdmFsaWRhdGVkIHZhbHVlIG9mIHRoZSBvcHRpb24uXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gdmFsaWRhdGVPcHRpb24obmFtZSwgY29uZmlnT3B0aW9uLCBzdHJpY3RDaGVjayA9IHRydWUpIHtcclxuICAvLyBSZXR1cm4gdGhlIG9yaWdpbmFsIG9wdGlvbiBpZiB0aGUgdmFsaWRhdGlvbiBpcyBkaXNhYmxlZFxyXG4gIGlmICghZ2V0T3B0aW9ucygpLm90aGVyLnZhbGlkYXRpb24pIHtcclxuICAgIHJldHVybiBjb25maWdPcHRpb247XHJcbiAgfVxyXG5cclxuICB0cnkge1xyXG4gICAgLy8gUmV0dXJuIHZhbGlkYXRlZCBvcHRpb25cclxuICAgIHJldHVybiB2YWxpZGF0b3JzW25hbWVdKHN0cmljdENoZWNrKS5wYXJzZShjb25maWdPcHRpb24pO1xyXG4gIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICAvLyBMb2cgWm9kIGlzc3Vlc1xyXG4gICAgbG9nWm9kSXNzdWVzKFxyXG4gICAgICAxLFxyXG4gICAgICBlcnJvci5pc3N1ZXMsXHJcbiAgICAgIGBbdmFsaWRhdGlvbl0gVGhlICR7bmFtZX0gb3B0aW9uIHZhbGlkYXRpb24gZXJyb3JgXHJcbiAgICApO1xyXG5cclxuICAgIC8vIFRocm93IHZhbGlkYXRpb24gZXJyb3JcclxuICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcihcclxuICAgICAgYFt2YWxpZGF0aW9uXSBUaGUgJHtuYW1lfSBvcHRpb24gdmFsaWRhdGlvbiBlcnJvcmAsXHJcbiAgICAgIDQwMFxyXG4gICAgKTtcclxuICB9XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBWYWxpZGF0ZXMgdGhlIHByb3ZpZGVkIGNvbmZpZ3VyYXRpb24gb3B0aW9ucyBmb3IgdGhlIGV4cG9ydGluZyBwcm9jZXNzLlxyXG4gKiBSZXR1cm5zIHRoZSBvcmlnaW5hbCBvcHRpb24gaWYgdGhlIHZhbGlkYXRpb24gaXMgZGlzYWJsZWQgZ2xvYmFsbHkuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiB2YWxpZGF0ZU9wdGlvbnNcclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IGNvbmZpZ09wdGlvbnMgLSBUaGUgY29uZmlndXJhdGlvbiBvcHRpb25zIHRvIGJlIHZhbGlkYXRlZC5cclxuICogQHBhcmFtIHtib29sZWFufSBbc3RyaWN0Q2hlY2s9dHJ1ZV0gLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb25cclxuICogc2hvdWxkIGJlIGFwcGxpZWQuIFRoZSBkZWZhdWx0IHZhbHVlIGlzIGB0cnVlYC5cclxuICpcclxuICogQHJldHVybnMge09iamVjdH0gVGhlIHBhcnNlZCBhbmQgdmFsaWRhdGVkIGNvbmZpZ3VyYXRpb24gb3B0aW9ucyBvYmplY3QuXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gdmFsaWRhdGVPcHRpb25zKGNvbmZpZ09wdGlvbnMsIHN0cmljdENoZWNrID0gdHJ1ZSkge1xyXG4gIC8vIFJldHVybiB0aGUgb3JpZ2luYWwgY29uZmlnIGlmIHRoZSB2YWxpZGF0aW9uIGlzIGRpc2FibGVkXHJcbiAgaWYgKCFnZXRPcHRpb25zKCkub3RoZXIudmFsaWRhdGlvbikge1xyXG4gICAgcmV0dXJuIGNvbmZpZ09wdGlvbnM7XHJcbiAgfVxyXG5cclxuICB0cnkge1xyXG4gICAgLy8gUmV0dXJuIHZhbGlkYXRlZCBvcHRpb25zXHJcbiAgICByZXR1cm4gc3RyaWN0Q2hlY2tcclxuICAgICAgPyBzdHJpY3RWYWxpZGF0ZShjb25maWdPcHRpb25zKVxyXG4gICAgICA6IGxvb3NlVmFsaWRhdGUoY29uZmlnT3B0aW9ucyk7XHJcbiAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgIC8vIExvZyBab2QgaXNzdWVzXHJcbiAgICBsb2dab2RJc3N1ZXMoMSwgZXJyb3IuaXNzdWVzLCAnW3ZhbGlkYXRpb25dIE9wdGlvbnMgdmFsaWRhdGlvbiBlcnJvcicpO1xyXG5cclxuICAgIC8vIFRocm93IHZhbGlkYXRpb24gZXJyb3JcclxuICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcignW3ZhbGlkYXRpb25dIE9wdGlvbnMgdmFsaWRhdGlvbiBlcnJvcicsIDQwMCk7XHJcbiAgfVxyXG59XHJcblxyXG4vKipcclxuICogVmFsaWRhdGVzLCBwYXJzZXMsIGFuZCBjaGVja3MgaWYgdGhlIHByb3ZpZGVkIGNvbmZpZyBpcyBhbGxvd2VkIHNldFxyXG4gKiBvZiBvcHRpb25zLlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gaXNBbGxvd2VkQ29uZmlnXHJcbiAqXHJcbiAqIEBwYXJhbSB7dW5rbm93bn0gY29uZmlnIC0gVGhlIGNvbmZpZyB0byBiZSB2YWxpZGF0ZWQgYW5kIHBhcnNlZCBhcyBhIHNldFxyXG4gKiBvZiBvcHRpb25zLiBNdXN0IGJlIGVpdGhlciBhbiBvYmplY3Qgb3IgYSBzdHJpbmcuXHJcbiAqIEBwYXJhbSB7Ym9vbGVhbn0gW3RvU3RyaW5nPWZhbHNlXSAtIFdoZXRoZXIgdG8gcmV0dXJuIGEgc3RyaW5naWZpZWQgdmVyc2lvblxyXG4gKiBvZiB0aGUgcGFyc2VkIGNvbmZpZy4gVGhlIGRlZmF1bHQgdmFsdWUgaXMgYGZhbHNlYC5cclxuICogQHBhcmFtIHtib29sZWFufSBbYWxsb3dGdW5jdGlvbnM9ZmFsc2VdIC0gV2hldGhlciB0byBhbGxvdyBmdW5jdGlvbnNcclxuICogaW4gdGhlIHBhcnNlZCBjb25maWcuIElmIGB0cnVlYCwgZnVuY3Rpb25zIGFyZSBwcmVzZXJ2ZWQuIE90aGVyd2lzZSwgd2hlblxyXG4gKiBhIGZ1bmN0aW9uIGlzIGZvdW5kLCBgbnVsbGAgaXMgcmV0dXJuZWQuIFRoZSBkZWZhdWx0IHZhbHVlIGlzIGBmYWxzZWAuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHsoT2JqZWN0fHN0cmluZ3xudWxsKX0gUmV0dXJucyBhIHBhcnNlZCBzZXQgb2Ygb3B0aW9ucyBvYmplY3QsXHJcbiAqIGEgc3RyaW5naWZpZWQgc2V0IG9mIG9wdGlvbnMgb2JqZWN0IGlmIHRoZSBgdG9TdHJpbmdgIGlzIGB0cnVlYCwgYW5kIGBudWxsYFxyXG4gKiBpZiB0aGUgY29uZmlnIGlzIG5vdCBhIHZhbGlkIHNldCBvZiBvcHRpb25zIG9yIHBhcnNpbmcgZmFpbHMuXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gaXNBbGxvd2VkQ29uZmlnKFxyXG4gIGNvbmZpZyxcclxuICB0b1N0cmluZyA9IGZhbHNlLFxyXG4gIGFsbG93RnVuY3Rpb25zID0gZmFsc2VcclxuKSB7XHJcbiAgdHJ5IHtcclxuICAgIC8vIEFjY2VwdCBvbmx5IG9iamVjdHMgYW5kIHN0cmluZ3NcclxuICAgIGlmICghaXNPYmplY3QoY29uZmlnKSAmJiB0eXBlb2YgY29uZmlnICE9PSAnc3RyaW5nJykge1xyXG4gICAgICAvLyBSZXR1cm4gYG51bGxgIGlmIGFueSBvdGhlciB0eXBlXHJcbiAgICAgIHJldHVybiBudWxsO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIEdldCB0aGUgb2JqZWN0IHJlcHJlc2VudGF0aW9uIG9mIHRoZSBvcmlnaW5hbCBjb25maWdcclxuICAgIGNvbnN0IG9iamVjdENvbmZpZyA9XHJcbiAgICAgIHR5cGVvZiBjb25maWcgPT09ICdzdHJpbmcnXHJcbiAgICAgICAgPyBhbGxvd0Z1bmN0aW9uc1xyXG4gICAgICAgICAgPyBldmFsKGAoJHtjb25maWd9KWApXHJcbiAgICAgICAgICA6IEpTT04ucGFyc2UoY29uZmlnKVxyXG4gICAgICAgIDogY29uZmlnO1xyXG5cclxuICAgIC8vIFByZXNlcnZlIG9yIHJlbW92ZSBwb3RlbnRpYWwgZnVuY3Rpb25zIGJhc2VkIG9uIHRoZSBgYWxsb3dGdW5jdGlvbnNgIGZsYWdcclxuICAgIGNvbnN0IHN0cmluZ2lmaWVkT3B0aW9ucyA9IF9vcHRpb25zU3RyaW5naWZ5KFxyXG4gICAgICBvYmplY3RDb25maWcsXHJcbiAgICAgIGFsbG93RnVuY3Rpb25zLFxyXG4gICAgICBmYWxzZVxyXG4gICAgKTtcclxuXHJcbiAgICAvLyBQYXJzZSB0aGUgY29uZmlnIHRvIGNoZWNrIGlmIGl0IGlzIHZhbGlkIHNldCBvZiBvcHRpb25zXHJcbiAgICBjb25zdCBwYXJzZWRPcHRpb25zID0gYWxsb3dGdW5jdGlvbnNcclxuICAgICAgPyBKU09OLnBhcnNlKFxyXG4gICAgICAgICAgX29wdGlvbnNTdHJpbmdpZnkob2JqZWN0Q29uZmlnLCBhbGxvd0Z1bmN0aW9ucywgdHJ1ZSksXHJcbiAgICAgICAgICAoXywgdmFsdWUpID0+XHJcbiAgICAgICAgICAgIHR5cGVvZiB2YWx1ZSA9PT0gJ3N0cmluZycgJiYgdmFsdWUuc3RhcnRzV2l0aCgnZnVuY3Rpb24nKVxyXG4gICAgICAgICAgICAgID8gZXZhbChgKCR7dmFsdWV9KWApXHJcbiAgICAgICAgICAgICAgOiB2YWx1ZVxyXG4gICAgICAgIClcclxuICAgICAgOiBKU09OLnBhcnNlKHN0cmluZ2lmaWVkT3B0aW9ucyk7XHJcblxyXG4gICAgLy8gUmV0dXJuIHN0cmluZ2lmaWVkIG9yIG9iamVjdCBvcHRpb25zIGJhc2VkIG9uIHRoZSBgdG9TdHJpbmdgIGZsYWdcclxuICAgIHJldHVybiB0b1N0cmluZyA/IHN0cmluZ2lmaWVkT3B0aW9ucyA6IHBhcnNlZE9wdGlvbnM7XHJcbiAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgIC8vIFJldHVybiBgbnVsbGAgaWYgcGFyc2luZyBmYWlsc1xyXG4gICAgcmV0dXJuIG51bGw7XHJcbiAgfVxyXG59XHJcblxyXG4vKipcclxuICogSW5pdGlhbGl6ZXMgYW5kIHJldHVybnMgdGhlIGdsb2JhbCBvcHRpb25zIG9iamVjdCBiYXNlZCBvbiB0aGUgcHJvdmlkZWRcclxuICogY29uZmlndXJhdGlvbiwgc2V0dGluZyB2YWx1ZXMgZnJvbSBuZXN0ZWQgcHJvcGVydGllcyByZWN1cnNpdmVseS5cclxuICpcclxuICogVGhlIGZ1bmN0aW9uIHByaW9yaXRpemVzIHZhbHVlcyBpbiB0aGUgZm9sbG93aW5nIG9yZGVyOlxyXG4gKlxyXG4gKiAxLiBWYWx1ZXMgZnJvbSBlbnZpcm9ubWVudCB2YXJpYWJsZXMgKHNwZWNpZmllZCBpbiB0aGUgYC5lbnZgIGZpbGUpLlxyXG4gKiAyLiBWYWx1ZXMgZnJvbSB0aGUgYC4vbGliL3NjaGVtYXMvY29uZmlnLmpzYCBmaWxlIChkZWZhdWx0cykuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBfaW5pdE9wdGlvbnNcclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IGNvbmZpZyAtIFRoZSBjb25maWd1cmF0aW9uIG9iamVjdCB1c2VkIGZvciBpbml0aWFsaXppbmdcclxuICogdGhlIGdsb2JhbCBvcHRpb25zLiBJdCBzaG91bGQgaW5jbHVkZSBuZXN0ZWQgcHJvcGVydGllcyB3aXRoIGEgYHZhbHVlYFxyXG4gKiBhbmQgYW4gYGVudkxpbmtgIGZvciBsaW5raW5nIHRvIGVudmlyb25tZW50IHZhcmlhYmxlcy5cclxuICpcclxuICogQHJldHVybnMge09iamVjdH0gVGhlIGluaXRpYWxpemVkIGdsb2JhbCBvcHRpb25zIG9iamVjdCwgcG9wdWxhdGVkIHdpdGhcclxuICogdmFsdWVzIGJhc2VkIG9uIHRoZSBwcm92aWRlZCBjb25maWd1cmF0aW9uIGFuZCB0aGUgZXN0YWJsaXNoZWQgcHJpb3JpdHlcclxuICogb3JkZXIuXHJcbiAqL1xyXG5mdW5jdGlvbiBfaW5pdE9wdGlvbnMoY29uZmlnKSB7XHJcbiAgLy8gSW5pdCB0aGUgb2JqZWN0IGZvciBvcHRpb25zXHJcbiAgY29uc3Qgb3B0aW9ucyA9IHt9O1xyXG5cclxuICAvLyBTdGFydCBpbml0aWFsaXppbmcgdGhlIGBvcHRpb25zYCBvYmplY3QgcmVjdXJzaXZlbHlcclxuICBmb3IgKGNvbnN0IFtuYW1lLCBpdGVtXSBvZiBPYmplY3QuZW50cmllcyhjb25maWcpKSB7XHJcbiAgICBpZiAoT2JqZWN0LnByb3RvdHlwZS5oYXNPd25Qcm9wZXJ0eS5jYWxsKGl0ZW0sICd2YWx1ZScpKSB7XHJcbiAgICAgIC8vIFNldCB0aGUgY29ycmVjdCB2YWx1ZSBiYXNlZCBvbiB0aGUgZXN0YWJsaXNoZWQgcHJpb3JpdHkgb3JkZXJcclxuICAgICAgaWYgKGVudnNbaXRlbS5lbnZMaW5rXSAhPT0gdW5kZWZpbmVkICYmIGVudnNbaXRlbS5lbnZMaW5rXSAhPT0gbnVsbCkge1xyXG4gICAgICAgIC8vIFRoZSBlbnZpcm9ubWVudCB2YXJpYWJsZXMgdmFsdWVcclxuICAgICAgICBvcHRpb25zW25hbWVdID0gZW52c1tpdGVtLmVudkxpbmtdO1xyXG4gICAgICB9IGVsc2Uge1xyXG4gICAgICAgIC8vIFRoZSB2YWx1ZSBmcm9tIHRoZSBjb25maWcgZmlsZVxyXG4gICAgICAgIG9wdGlvbnNbbmFtZV0gPSBpdGVtLnZhbHVlO1xyXG4gICAgICB9XHJcbiAgICB9IGVsc2Uge1xyXG4gICAgICAvLyBDcmVhdGUgYSBjYXRlZ29yeSBvZiBvcHRpb25zIGluIHRoZSBgb3B0aW9uc2Agb2JqZWN0XHJcbiAgICAgIG9wdGlvbnNbbmFtZV0gPSBfaW5pdE9wdGlvbnMoaXRlbSk7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICAvLyBSZXR1cm4gdGhlIGNyZWF0ZWQgYG9wdGlvbnNgIG9iamVjdFxyXG4gIHJldHVybiBvcHRpb25zO1xyXG59XHJcblxyXG4vKipcclxuICogUmVjdXJzaXZlbHkgbWVyZ2VzIHR3byBzZXRzIG9mIGNvbmZpZ3VyYXRpb24gb3B0aW9ucywgdGFraW5nIGludG8gYWNjb3VudFxyXG4gKiBwcm9wZXJ0aWVzIHNwZWNpZmllZCBpbiB0aGUgYGFic29sdXRlUHJvcHNgIGFycmF5IHRoYXQgcmVxdWlyZSBhYnNvbHV0ZVxyXG4gKiBtZXJnaW5nLiBUaGUgYG9yaWdpbmFsT3B0aW9uc2Agb2JqZWN0IHdpbGwgYmUgZXh0ZW5kZWQgd2l0aCBvcHRpb25zIGZyb21cclxuICogdGhlIGBuZXdPcHRpb25zYCBvYmplY3QuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBfbWVyZ2VPcHRpb25zXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBvcmlnaW5hbE9wdGlvbnMgLSBUaGUgb3JpZ2luYWwgY29uZmlndXJhdGlvbiBvcHRpb25zIG9iamVjdFxyXG4gKiB0byBiZSBleHRlbmRlZC5cclxuICogQHBhcmFtIHtPYmplY3R9IG5ld09wdGlvbnMgLSBUaGUgbmV3IGNvbmZpZ3VyYXRpb24gb3B0aW9ucyBvYmplY3QgdG8gbWVyZ2UuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtPYmplY3R9IFRoZSBleHRlbmRlZCBgb3JpZ2luYWxPcHRpb25zYCBvYmplY3QuXHJcbiAqL1xyXG5mdW5jdGlvbiBfbWVyZ2VPcHRpb25zKG9yaWdpbmFsT3B0aW9ucywgbmV3T3B0aW9ucykge1xyXG4gIC8vIENoZWNrIGlmIHRoZSBgb3JpZ2luYWxPcHRpb25zYCBhbmQgYG5ld09wdGlvbnNgIGFyZSBjb3JyZWN0IG9iamVjdHNcclxuICBpZiAoaXNPYmplY3Qob3JpZ2luYWxPcHRpb25zKSAmJiBpc09iamVjdChuZXdPcHRpb25zKSkge1xyXG4gICAgZm9yIChjb25zdCBba2V5LCB2YWx1ZV0gb2YgT2JqZWN0LmVudHJpZXMobmV3T3B0aW9ucykpIHtcclxuICAgICAgb3JpZ2luYWxPcHRpb25zW2tleV0gPVxyXG4gICAgICAgIGlzT2JqZWN0KHZhbHVlKSAmJlxyXG4gICAgICAgICFhYnNvbHV0ZVByb3BzLmluY2x1ZGVzKGtleSkgJiZcclxuICAgICAgICBvcmlnaW5hbE9wdGlvbnNba2V5XSAhPT0gdW5kZWZpbmVkXHJcbiAgICAgICAgICA/IF9tZXJnZU9wdGlvbnMob3JpZ2luYWxPcHRpb25zW2tleV0sIHZhbHVlKVxyXG4gICAgICAgICAgOiB2YWx1ZSAhPT0gdW5kZWZpbmVkXHJcbiAgICAgICAgICAgID8gdmFsdWVcclxuICAgICAgICAgICAgOiBvcmlnaW5hbE9wdGlvbnNba2V5XSB8fCBudWxsO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgLy8gUmV0dXJuIHRoZSBvcmlnaW5hbCAobW9kaWZpZWQgb3Igbm90KSBvcHRpb25zXHJcbiAgcmV0dXJuIG9yaWdpbmFsT3B0aW9ucztcclxufVxyXG5cclxuLyoqXHJcbiAqIENvbnZlcnRzIHRoZSBwcm92aWRlZCBvcHRpb25zIG9iamVjdCB0byBhIEpTT04gc3RyaW5nIHdpdGggdGhlIG9wdGlvblxyXG4gKiB0byBwcmVzZXJ2ZSBmdW5jdGlvbnMuIEluIG9yZGVyIGZvciBhIGZ1bmN0aW9uIHRvIGJlIHByZXNlcnZlZCwgaXQgbmVlZHNcclxuICogdG8gZm9sbG93IHRoZSBmb3JtYXQgYGZ1bmN0aW9uICguLi4pIHsuLi59YC4gU3VjaCBhIGZ1bmN0aW9uIGNhbiBhbHNvXHJcbiAqIGJlIHN0cmluZ2lmaWVkLlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gX29wdGlvbnNTdHJpbmdpZnlcclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IG9wdGlvbnMgLSBUaGUgb3B0aW9ucyBvYmplY3QgdG8gYmUgY29udmVydGVkIHRvIGEgc3RyaW5nLlxyXG4gKiBAcGFyYW0ge2Jvb2xlYW59IGFsbG93RnVuY3Rpb25zIC0gSWYgc2V0IHRvIGB0cnVlYCwgZnVuY3Rpb25zIGFyZSBwcmVzZXJ2ZWRcclxuICogaW4gdGhlIG91dHB1dC4gT3RoZXJ3aXNlIGFuIGVycm9yIGlzIHRocm93bi5cclxuICogQHBhcmFtIHtib29sZWFufSBzdHJpbmdpZnlGdW5jdGlvbnMgLSBJZiBzZXQgdG8gYHRydWVgLCBmdW5jdGlvbnMgYXJlIHNhdmVkXHJcbiAqIGFzIHN0cmluZ3MuIFRoZSBgYWxsb3dGdW5jdGlvbnNgIG11c3QgYmUgc2V0IHRvIGB0cnVlYCBhcyB3ZWxsIGZvciB0aGlzXHJcbiAqIHRvIHRha2UgYW4gZWZmZWN0LlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7c3RyaW5nfSBUaGUgSlNPTi1mb3JtYXR0ZWQgc3RyaW5nIHJlcHJlc2VudGluZyB0aGUgb3B0aW9ucy5cclxuICpcclxuICogQHRocm93cyB7RXJyb3J9IFRocm93cyBhbiBgRXJyb3JgIHdoZW4gZnVuY3Rpb25zIGFyZSBub3QgYWxsb3dlZCBidXQgYXJlXHJcbiAqIGZvdW5kIGluIHByb3ZpZGVkIG9wdGlvbnMgb2JqZWN0LlxyXG4gKi9cclxuZnVuY3Rpb24gX29wdGlvbnNTdHJpbmdpZnkob3B0aW9ucywgYWxsb3dGdW5jdGlvbnMsIHN0cmluZ2lmeUZ1bmN0aW9ucykge1xyXG4gIGNvbnN0IHJlcGxhY2VyQ2FsbGJhY2sgPSAoXywgdmFsdWUpID0+IHtcclxuICAgIC8vIFRyaW0gc3RyaW5nIHZhbHVlc1xyXG4gICAgaWYgKHR5cGVvZiB2YWx1ZSA9PT0gJ3N0cmluZycpIHtcclxuICAgICAgdmFsdWUgPSB2YWx1ZS50cmltKCk7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gSWYgYHZhbHVlYCBpcyBhIGZ1bmN0aW9uIG9yIHN0cmluZ2lmaWVkIGZ1bmN0aW9uXHJcbiAgICBpZiAoXHJcbiAgICAgIHR5cGVvZiB2YWx1ZSA9PT0gJ2Z1bmN0aW9uJyB8fFxyXG4gICAgICAodHlwZW9mIHZhbHVlID09PSAnc3RyaW5nJyAmJlxyXG4gICAgICAgIHZhbHVlLnN0YXJ0c1dpdGgoJ2Z1bmN0aW9uJykgJiZcclxuICAgICAgICB2YWx1ZS5lbmRzV2l0aCgnfScpKVxyXG4gICAgKSB7XHJcbiAgICAgIC8vIElmIHRoZSBgYWxsb3dGdW5jdGlvbnNgIGlzIHNldCB0byBgdHJ1ZWAsIHByZXNlcnZlIGZ1bmN0aW9uc1xyXG4gICAgICBpZiAoYWxsb3dGdW5jdGlvbnMpIHtcclxuICAgICAgICAvLyBCYXNlZCBvbiB0aGUgYHN0cmluZ2lmeUZ1bmN0aW9uc2Agb3B0aW9ucywgc2V0IGZ1bmN0aW9uIHZhbHVlc1xyXG4gICAgICAgIHJldHVybiBzdHJpbmdpZnlGdW5jdGlvbnNcclxuICAgICAgICAgID8gLy8gQXMgc3RyaW5naWZpZWQgZnVuY3Rpb25zXHJcbiAgICAgICAgICAgIGBcIkVYUF9GVU4keyh2YWx1ZSArICcnKS5yZXBsYWNlQWxsKC9cXHMrL2csICcgJyl9RVhQX0ZVTlwiYFxyXG4gICAgICAgICAgOiAvLyBBcyBmdW5jdGlvbnNcclxuICAgICAgICAgICAgYEVYUF9GVU4keyh2YWx1ZSArICcnKS5yZXBsYWNlQWxsKC9cXHMrL2csICcgJyl9RVhQX0ZVTmA7XHJcbiAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgLy8gVGhyb3cgYW4gZXJyb3Igb3RoZXJ3aXNlXHJcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKCk7XHJcbiAgICAgIH1cclxuICAgIH1cclxuXHJcbiAgICAvLyBJbiBhbGwgb3RoZXIgY2FzZXMsIHNpbXBseSByZXR1cm4gdGhlIHZhbHVlXHJcbiAgICByZXR1cm4gdmFsdWU7XHJcbiAgfTtcclxuXHJcbiAgLy8gU3RyaW5naWZ5IG9wdGlvbnMgYW5kIGlmIHJlcXVpcmVkLCByZXBsYWNlIHNwZWNpYWwgZnVuY3Rpb25zIG1hcmtzXHJcbiAgcmV0dXJuIEpTT04uc3RyaW5naWZ5KG9wdGlvbnMsIHJlcGxhY2VyQ2FsbGJhY2spLnJlcGxhY2VBbGwoXHJcbiAgICBzdHJpbmdpZnlGdW5jdGlvbnMgPyAvXFxcXFwiRVhQX0ZVTnxFWFBfRlVOXFxcXFwiL2cgOiAvXCJFWFBfRlVOfEVYUF9GVU5cIi9nLFxyXG4gICAgJydcclxuICApO1xyXG59XHJcblxyXG4vKipcclxuICogTG9hZHMgYWRkaXRpb25hbCBjb25maWd1cmF0aW9uIGZyb20gYSBzcGVjaWZpZWQgZmlsZSBwcm92aWRlZCB2aWFcclxuICogdGhlIGAtLWxvYWRDb25maWdgIG9wdGlvbiBpbiB0aGUgY29tbWFuZC1saW5lIGFyZ3VtZW50cy5cclxuICpcclxuICogQGZ1bmN0aW9uIF9sb2FkQ29uZmlnRmlsZVxyXG4gKlxyXG4gKiBAcGFyYW0ge0FycmF5PHN0cmluZz59IGNsaUFyZ3MgLSBDb21tYW5kLWxpbmUgYXJndW1lbnRzIHRvIHNlYXJjaFxyXG4gKiBmb3IgdGhlIGAtLWxvYWRDb25maWdgIG9wdGlvbiBhbmQgdGhlIGNvcnJlc3BvbmRpbmcgZmlsZSBwYXRoLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7T2JqZWN0fSBUaGUgYWRkaXRpb25hbCBjb25maWd1cmF0aW9uIGxvYWRlZCBmcm9tIHRoZSBzcGVjaWZpZWRcclxuICogZmlsZSwgb3IgYW4gZW1wdHkgb2JqZWN0IGlmIHRoZSBmaWxlIGlzIG5vdCBmb3VuZCwgaW52YWxpZCwgb3IgYW4gZXJyb3JcclxuICogb2NjdXJzLlxyXG4gKi9cclxuZnVuY3Rpb24gX2xvYWRDb25maWdGaWxlKGNsaUFyZ3MpIHtcclxuICAvLyBHZXQgdGhlIGFsbG93IGZsYWdzIGZvciB0aGUgY3VzdG9tIGxvZ2ljIGNoZWNrXHJcbiAgY29uc3QgeyBhbGxvd0NvZGVFeGVjdXRpb24sIGFsbG93RmlsZVJlc291cmNlcyB9ID0gZ2V0T3B0aW9ucygpLmN1c3RvbUxvZ2ljO1xyXG5cclxuICAvLyBDaGVjayBpZiB0aGUgYC0tbG9hZENvbmZpZ2Agb3B0aW9uIHdhcyB1c2VkXHJcbiAgY29uc3QgY29uZmlnSW5kZXggPSBjbGlBcmdzLmZpbmRJbmRleChcclxuICAgIChhcmcpID0+IGFyZy5yZXBsYWNlKC8tL2csICcnKSA9PT0gJ2xvYWRDb25maWcnXHJcbiAgKTtcclxuXHJcbiAgLy8gR2V0IHRoZSBgLS1sb2FkQ29uZmlnYCBvcHRpb24gdmFsdWVcclxuICBjb25zdCBjb25maWdGaWxlTmFtZSA9IGNvbmZpZ0luZGV4ID4gLTEgJiYgY2xpQXJnc1tjb25maWdJbmRleCArIDFdO1xyXG5cclxuICAvLyBDaGVjayBpZiB0aGUgYC0tbG9hZENvbmZpZ2AgaXMgcHJlc2VudCBhbmQgaGFzIGEgY29ycmVjdCB2YWx1ZVxyXG4gIGlmIChjb25maWdGaWxlTmFtZSAmJiBhbGxvd0ZpbGVSZXNvdXJjZXMpIHtcclxuICAgIHRyeSB7XHJcbiAgICAgIC8vIExvYWQgYW4gb3B0aW9uYWwgY3VzdG9tIEpTT04gY29uZmlnIGZpbGVcclxuICAgICAgcmV0dXJuIGlzQWxsb3dlZENvbmZpZyhcclxuICAgICAgICByZWFkRmlsZVN5bmMoZ2V0QWJzb2x1dGVQYXRoKGNvbmZpZ0ZpbGVOYW1lKSwgJ3V0ZjgnKSxcclxuICAgICAgICBmYWxzZSxcclxuICAgICAgICBhbGxvd0NvZGVFeGVjdXRpb25cclxuICAgICAgKTtcclxuICAgIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICAgIGxvZ1dpdGhTdGFjayhcclxuICAgICAgICAyLFxyXG4gICAgICAgIGVycm9yLFxyXG4gICAgICAgIGBbY29uZmlnXSBVbmFibGUgdG8gbG9hZCB0aGUgY29uZmlndXJhdGlvbiBmcm9tIHRoZSAke2NvbmZpZ0ZpbGVOYW1lfSBmaWxlLmBcclxuICAgICAgKTtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIC8vIE5vIGFkZGl0aW9uYWwgb3B0aW9ucyB0byByZXR1cm5cclxuICByZXR1cm4ge307XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBQYXJzZXMgY29tbWFuZC1saW5lIGFyZ3VtZW50cyBhbmQgcGFpcnMgZWFjaCBhcmd1bWVudCB3aXRoIGl0cyBjb3JyZXNwb25kaW5nXHJcbiAqIG9wdGlvbiBpbiB0aGUgY29uZmlndXJhdGlvbi4gVGhlIHZhbHVlcyBhcmUgc3RydWN0dXJlZCBpbnRvIGEgbmVzdGVkIG9wdGlvbnNcclxuICogb2JqZWN0LCBiYXNlZCBvbiBwcmVkZWZpbmVkIG1hcHBpbmdzIGluIHRoZSBgbmVzdGVkUHJvcHNgIG9iamVjdC5cclxuICpcclxuICogQGZ1bmN0aW9uIF9wYWlyQXJndW1lbnRWYWx1ZVxyXG4gKlxyXG4gKiBAcGFyYW0ge0FycmF5PHN0cmluZz59IGNsaUFyZ3MgLSBBbiBhcnJheSBvZiBjb21tYW5kLWxpbmUgYXJndW1lbnRzXHJcbiAqIGNvbnRhaW5pbmcgb3B0aW9ucyBhbmQgdGhlaXIgYXNzb2NpYXRlZCB2YWx1ZXMuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtPYmplY3R9IEFuIHVwZGF0ZWQgb3B0aW9ucyBvYmplY3Qgd2hlcmUgZWFjaCBvcHRpb24gZnJvbVxyXG4gKiB0aGUgY29tbWFuZC1saW5lIGlzIHBhaXJlZCB3aXRoIGl0cyB2YWx1ZSwgc3RydWN0dXJlZCBpbnRvIG5lc3RlZCBvYmplY3RzXHJcbiAqIGFzIGRlZmluZWQuXHJcbiAqL1xyXG5mdW5jdGlvbiBfcGFpckFyZ3VtZW50VmFsdWUoY2xpQXJncykge1xyXG4gIC8vIEFuIGVtcHR5IG9iamVjdCB0byBjb2xsZWN0IGFuZCBzdHJ1Y3R1cml6ZSBkYXRhIGZyb20gdGhlIGFyZ3NcclxuICBjb25zdCBjbGlPcHRpb25zID0ge307XHJcblxyXG4gIC8vIEN5Y2xlIHRocm91Z2ggYWxsIENMSSBhcmdzIGFuZCBmaWx0ZXIgdGhlbVxyXG4gIGZvciAobGV0IGkgPSAwOyBpIDwgY2xpQXJncy5sZW5ndGg7IGkrKykge1xyXG4gICAgY29uc3Qgb3B0aW9uID0gY2xpQXJnc1tpXS5yZXBsYWNlKC8tL2csICcnKTtcclxuXHJcbiAgICAvLyBGaW5kIHRoZSByaWdodCBwbGFjZSBmb3IgcHJvcGVydHkncyB2YWx1ZVxyXG4gICAgY29uc3QgcHJvcGVydGllc0NoYWluID0gbmVzdGVkUHJvcHNbb3B0aW9uXVxyXG4gICAgICA/IG5lc3RlZFByb3BzW29wdGlvbl0uc3BsaXQoJy4nKVxyXG4gICAgICA6IFtdO1xyXG5cclxuICAgIC8vIENyZWF0ZSBvcHRpb25zIG9iamVjdCB3aXRoIHZhbHVlcyBmcm9tIENMSSBmb3IgbGF0ZXIgcGFyc2luZyBhbmQgbWVyZ2luZ1xyXG4gICAgcHJvcGVydGllc0NoYWluLnJlZHVjZSgob2JqLCBwcm9wLCBpbmRleCkgPT4ge1xyXG4gICAgICBpZiAocHJvcGVydGllc0NoYWluLmxlbmd0aCAtIDEgPT09IGluZGV4KSB7XHJcbiAgICAgICAgY29uc3QgdmFsdWUgPSBjbGlBcmdzWysraV07XHJcbiAgICAgICAgaWYgKCF2YWx1ZSkge1xyXG4gICAgICAgICAgbG9nKFxyXG4gICAgICAgICAgICAyLFxyXG4gICAgICAgICAgICBgW2NvbmZpZ10gTWlzc2luZyB2YWx1ZSBmb3IgdGhlIENMSSAnLS0ke29wdGlvbn0nIGFyZ3VtZW50LiBVc2luZyB0aGUgZGVmYXVsdCB2YWx1ZS5gXHJcbiAgICAgICAgICApO1xyXG4gICAgICAgIH1cclxuICAgICAgICBvYmpbcHJvcF0gPSB2YWx1ZSB8fCBudWxsO1xyXG4gICAgICB9IGVsc2UgaWYgKG9ialtwcm9wXSA9PT0gdW5kZWZpbmVkKSB7XHJcbiAgICAgICAgb2JqW3Byb3BdID0ge307XHJcbiAgICAgIH1cclxuICAgICAgcmV0dXJuIG9ialtwcm9wXTtcclxuICAgIH0sIGNsaU9wdGlvbnMpO1xyXG4gIH1cclxuXHJcbiAgLy8gUmV0dXJuIHBhcnNlZCBDTEkgb3B0aW9uc1xyXG4gIHJldHVybiBjbGlPcHRpb25zO1xyXG59XHJcblxyXG4vKipcclxuICogUmVjdXJzaXZlbHkgZ2VuZXJhdGVzIGEgbWFwcGluZyBvZiBuZXN0ZWQgYXJndW1lbnQgY2hhaW5zIGZyb20gYSBuZXN0ZWRcclxuICogY29uZmlnIG9iamVjdC4gVGhpcyBmdW5jdGlvbiB0cmF2ZXJzZXMgYSBuZXN0ZWQgb2JqZWN0IGFuZCBjcmVhdGVzIGEgbWFwcGluZ1xyXG4gKiB3aGVyZSBlYWNoIGtleSBpcyBhbiBhcmd1bWVudCBuYW1lIChlaXRoZXIgZnJvbSBgY2xpTmFtZWAsIGBsZWdhY3lOYW1lYCxcclxuICogb3IgdGhlIG9yaWdpbmFsIGtleSkgYW5kIGVhY2ggdmFsdWUgaXMgYSBzdHJpbmcgcmVwcmVzZW50aW5nIHRoZSBjaGFpblxyXG4gKiBvZiBuZXN0ZWQgcHJvcGVydGllcyBsZWFkaW5nIHRvIHRoYXQgYXJndW1lbnQuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBfY3JlYXRlTmVzdGVkUHJvcHNcclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IGNvbmZpZyAtIFRoZSBjb25maWd1cmF0aW9uIG9iamVjdC5cclxuICogQHBhcmFtIHtPYmplY3R9IFtuZXN0ZWRQcm9wcz17fV0gLSBUaGUgYWNjdW11bGF0b3Igb2JqZWN0IGZvciBzdG9yaW5nXHJcbiAqIHRoZSByZXN1bHRpbmcgYXJndW1lbnRzIGNoYWlucy4gVGhlIGRlZmF1bHQgdmFsdWUgaXMgYW4gZW1wdHkgb2JqZWN0LlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gW3Byb3BDaGFpbj0nJ10gLSBUaGUgY3VycmVudCBjaGFpbiBvZiBuZXN0ZWQgcHJvcGVydGllcyxcclxuICogdXNlZCBpbnRlcm5hbGx5IGR1cmluZyByZWN1cnNpb24uIFRoZSBkZWZhdWx0IHZhbHVlIGlzIGFuIGVtcHR5IHN0cmluZy5cclxuICpcclxuICogQHJldHVybnMge09iamVjdH0gQW4gb2JqZWN0IG1hcHBpbmcgYXJndW1lbnQgbmFtZXMgdG8gdGhlaXIgY29ycmVzcG9uZGluZ1xyXG4gKiBuZXN0ZWQgcHJvcGVydHkgY2hhaW5zLlxyXG4gKi9cclxuZnVuY3Rpb24gX2NyZWF0ZU5lc3RlZFByb3BzKGNvbmZpZywgbmVzdGVkUHJvcHMgPSB7fSwgcHJvcENoYWluID0gJycpIHtcclxuICBPYmplY3Qua2V5cyhjb25maWcpLmZvckVhY2goKGtleSkgPT4ge1xyXG4gICAgLy8gR2V0IHRoZSBzcGVjaWZpYyBzZWN0aW9uXHJcbiAgICBjb25zdCBlbnRyeSA9IGNvbmZpZ1trZXldO1xyXG5cclxuICAgIC8vIENoZWNrIGlmIHRoZXJlIGlzIHN0aWxsIG1vcmUgZGVwdGggdG8gdHJhdmVyc2VcclxuICAgIGlmICh0eXBlb2YgZW50cnkudmFsdWUgPT09ICd1bmRlZmluZWQnKSB7XHJcbiAgICAgIC8vIFJlY3Vyc2UgaW50byBkZWVwZXIgbGV2ZWxzIG9mIG5lc3RlZCBhcmd1bWVudHNcclxuICAgICAgX2NyZWF0ZU5lc3RlZFByb3BzKGVudHJ5LCBuZXN0ZWRQcm9wcywgYCR7cHJvcENoYWlufS4ke2tleX1gKTtcclxuICAgIH0gZWxzZSB7XHJcbiAgICAgIC8vIENyZWF0ZSB0aGUgY2hhaW4gb2YgbmVzdGVkIGFyZ3VtZW50c1xyXG4gICAgICBuZXN0ZWRQcm9wc1tlbnRyeS5jbGlOYW1lIHx8IGtleV0gPSBgJHtwcm9wQ2hhaW59LiR7a2V5fWAuc3Vic3RyaW5nKDEpO1xyXG5cclxuICAgICAgLy8gU3VwcG9ydCBmb3IgdGhlIGxlZ2FjeSwgUGhhbnRvbUpTIHByb3BlcnRpZXMgbmFtZXNcclxuICAgICAgaWYgKGVudHJ5LmxlZ2FjeU5hbWUgIT09IHVuZGVmaW5lZCkge1xyXG4gICAgICAgIG5lc3RlZFByb3BzW2VudHJ5LmxlZ2FjeU5hbWVdID0gYCR7cHJvcENoYWlufS4ke2tleX1gLnN1YnN0cmluZygxKTtcclxuICAgICAgfVxyXG4gICAgfVxyXG4gIH0pO1xyXG5cclxuICAvLyBSZXR1cm4gdGhlIG9iamVjdCB3aXRoIG5lc3RlZCBhcmd1bWVudCBjaGFpbnNcclxuICByZXR1cm4gbmVzdGVkUHJvcHM7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBSZWN1cnNpdmVseSBnYXRoZXJzIHRoZSBuYW1lcyBvZiBwcm9wZXJ0aWVzIGZyb20gYSBjb25maWd1cmF0aW9uIG9iamVjdCB0aGF0XHJcbiAqIHNob3VsZCBiZSB0cmVhdGVkIGFzIGFic29sdXRlIHByb3BlcnRpZXMuIFRoZXNlIHByb3BlcnRpZXMgaGF2ZSB2YWx1ZXMgdGhhdFxyXG4gKiBhcmUgb2JqZWN0cyBhbmQgZG8gbm90IGNvbnRhaW4gZnVydGhlciBuZXN0ZWQgZGVwdGggd2hlbiBtZXJnaW5nIGFuIG9iamVjdFxyXG4gKiBjb250YWluaW5nIHRoZXNlIG9wdGlvbnMuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBfY3JlYXRlQWJzb2x1dGVQcm9wc1xyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gY29uZmlnIC0gVGhlIGNvbmZpZ3VyYXRpb24gb2JqZWN0LlxyXG4gKiBAcGFyYW0ge0FycmF5PHN0cmluZz59IFthYnNvbHV0ZVByb3BzPVtdXSAtIEFuIGFycmF5IHRvIGNvbGxlY3QgdGhlIG5hbWVzXHJcbiAqIG9mIGFic29sdXRlIHByb3BlcnRpZXMuIFRoZSBkZWZhdWx0IHZhbHVlIGlzIGFuIGVtcHR5IGFycmF5LlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7QXJyYXk8c3RyaW5nPn0gQW4gYXJyYXkgY29udGFpbmluZyB0aGUgbmFtZXMgb2YgYWJzb2x1dGVcclxuICogcHJvcGVydGllcy5cclxuICovXHJcbmZ1bmN0aW9uIF9jcmVhdGVBYnNvbHV0ZVByb3BzKGNvbmZpZywgYWJzb2x1dGVQcm9wcyA9IFtdKSB7XHJcbiAgT2JqZWN0LmtleXMoY29uZmlnKS5mb3JFYWNoKChrZXkpID0+IHtcclxuICAgIC8vIEdldCB0aGUgc3BlY2lmaWMgc2VjdGlvblxyXG4gICAgY29uc3QgZW50cnkgPSBjb25maWdba2V5XTtcclxuXHJcbiAgICAvLyBDaGVjayBpZiB0aGVyZSBpcyBzdGlsbCBtb3JlIGRlcHRoIHRvIHRyYXZlcnNlXHJcbiAgICBpZiAodHlwZW9mIGVudHJ5LnR5cGVzID09PSAndW5kZWZpbmVkJykge1xyXG4gICAgICAvLyBSZWN1cnNlIGludG8gZGVlcGVyIGxldmVsc1xyXG4gICAgICBfY3JlYXRlQWJzb2x1dGVQcm9wcyhlbnRyeSwgYWJzb2x1dGVQcm9wcyk7XHJcbiAgICB9IGVsc2Uge1xyXG4gICAgICAvLyBJZiB0aGUgb3B0aW9uIGNhbiBiZSBhbiBvYmplY3QsIHNhdmUgaXRzIHR5cGUgaW4gdGhlIGFycmF5XHJcbiAgICAgIGlmIChlbnRyeS50eXBlcy5pbmNsdWRlcygnT2JqZWN0JykpIHtcclxuICAgICAgICBhYnNvbHV0ZVByb3BzLnB1c2goa2V5KTtcclxuICAgICAgfVxyXG4gICAgfVxyXG4gIH0pO1xyXG5cclxuICAvLyBSZXR1cm4gdGhlIGFycmF5IHdpdGggdGhlIG5hbWVzIG9mIGFic29sdXRlIHByb3BlcnRpZXNcclxuICByZXR1cm4gYWJzb2x1dGVQcm9wcztcclxufVxyXG5cclxuZXhwb3J0IGRlZmF1bHQge1xyXG4gIGdldE9wdGlvbnMsXHJcbiAgdXBkYXRlT3B0aW9ucyxcclxuICBzZXRDbGlPcHRpb25zLFxyXG4gIG1hcFRvTmV3T3B0aW9ucyxcclxuICB2YWxpZGF0ZU9wdGlvbixcclxuICB2YWxpZGF0ZU9wdGlvbnMsXHJcbiAgaXNBbGxvd2VkQ29uZmlnXHJcbn07XHJcbiIsIi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXHJcblxyXG5IaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXJcclxuXHJcbkNvcHlyaWdodCAoYykgMjAxNi0yMDI1LCBIaWdoc29mdFxyXG5cclxuTGljZW5jZWQgdW5kZXIgdGhlIE1JVCBsaWNlbmNlLlxyXG5cclxuQWRkaXRpb25hbGx5IGEgdmFsaWQgSGlnaGNoYXJ0cyBsaWNlbnNlIGlzIHJlcXVpcmVkIGZvciB1c2UuXHJcblxyXG5TZWUgTElDRU5TRSBmaWxlIGluIHJvb3QgZm9yIGRldGFpbHMuXHJcblxyXG4qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xyXG5cclxuLyoqXHJcbiAqIEBvdmVydmlldyBIVFRQIHV0aWxpdHkgbW9kdWxlIGZvciBmZXRjaGluZyBhbmQgcG9zdGluZyBkYXRhLiBTdXBwb3J0cyBib3RoXHJcbiAqIEhUVFAgYW5kIEhUVFBTIHByb3RvY29scywgcHJvdmlkaW5nIG1ldGhvZHMgdG8gbWFrZSBHRVQgYW5kIFBPU1QgcmVxdWVzdHNcclxuICogd2l0aCBjdXN0b21pemFibGUgb3B0aW9ucy4gSW5jbHVkZXMgcHJvdG9jb2wgZGV0ZXJtaW5hdGlvbiBiYXNlZCBvbiBVUkxcclxuICogYW5kIGF1Z21lbnRzIHJlc3BvbnNlIG9iamVjdHMgd2l0aCBhICd0ZXh0JyBwcm9wZXJ0eSBmb3IgZWFzaWVyIGRhdGEgYWNjZXNzLlxyXG4gKi9cclxuXHJcbmltcG9ydCBodHRwIGZyb20gJ2h0dHAnO1xyXG5pbXBvcnQgaHR0cHMgZnJvbSAnaHR0cHMnO1xyXG5cclxuLyoqXHJcbiAqIFNlbmRzIGEgR0VUIHJlcXVlc3QgdG8gdGhlIHNwZWNpZmllZCBVUkwgdXNpbmcgZWl0aGVyIEhUVFAgb3IgSFRUUFMgcHJvdG9jb2wuXHJcbiAqXHJcbiAqIEBhc3luY1xyXG4gKiBAZnVuY3Rpb24gZ2V0XHJcbiAqXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSB1cmwgLSBUaGUgVVJMIHRvIGdldCBkYXRhIGZyb20uXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBbcmVxdWVzdE9wdGlvbnM9e31dIC0gT3B0aW9ucyBmb3IgdGhlIEhUVFAvSFRUUFMgcmVxdWVzdC5cclxuICogVGhlIGRlZmF1bHQgdmFsdWUgaXMgYW4gZW1wdHkgb2JqZWN0LlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7UHJvbWlzZTxPYmplY3Q+fSBBIFByb21pc2UgdGhhdCByZXNvbHZlcyB0byB0aGUgSFRUUC9IVFRQUyByZXNwb25zZVxyXG4gKiBvYmplY3Qgd2l0aCBhZGRlZCAndGV4dCcgcHJvcGVydHkgb3IgcmVqZWN0aW5nIHdpdGggYW4gZXJyb3IuXHJcbiAqL1xyXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gZ2V0KHVybCwgcmVxdWVzdE9wdGlvbnMgPSB7fSkge1xyXG4gIHJldHVybiBuZXcgUHJvbWlzZSgocmVzb2x2ZSwgcmVqZWN0KSA9PiB7XHJcbiAgICAvLyBEZWNpZGUgb24gdGhlIHByb3RvY29sXHJcbiAgICBfZ2V0UHJvdG9jb2xNb2R1bGUodXJsKVxyXG4gICAgICAuZ2V0KHVybCwgcmVxdWVzdE9wdGlvbnMsIChyZXNwb25zZSkgPT4ge1xyXG4gICAgICAgIGxldCByZXNwb25zZURhdGEgPSAnJztcclxuXHJcbiAgICAgICAgLy8gQSBjaHVuayBvZiBkYXRhIGhhcyBiZWVuIHJlY2VpdmVkXHJcbiAgICAgICAgcmVzcG9uc2Uub24oJ2RhdGEnLCAoY2h1bmspID0+IHtcclxuICAgICAgICAgIHJlc3BvbnNlRGF0YSArPSBjaHVuaztcclxuICAgICAgICB9KTtcclxuXHJcbiAgICAgICAgLy8gVGhlIHdob2xlIHJlc3BvbnNlIGhhcyBiZWVuIHJlY2VpdmVkXHJcbiAgICAgICAgcmVzcG9uc2Uub24oJ2VuZCcsICgpID0+IHtcclxuICAgICAgICAgIGlmICghcmVzcG9uc2VEYXRhKSB7XHJcbiAgICAgICAgICAgIHJlamVjdCgnTm90aGluZyB3YXMgZmV0Y2hlZCBmcm9tIHRoZSBVUkwuJyk7XHJcbiAgICAgICAgICB9XHJcblxyXG4gICAgICAgICAgLy8gR2V0IHRoZSBmdWxsIHJlc3VsdCBhbmQgcmVzb2x2ZSB0aGUgcmVxdWVzdFxyXG4gICAgICAgICAgcmVzcG9uc2UudGV4dCA9IHJlc3BvbnNlRGF0YTtcclxuICAgICAgICAgIHJlc29sdmUocmVzcG9uc2UpO1xyXG4gICAgICAgIH0pO1xyXG4gICAgICB9KVxyXG4gICAgICAub24oJ2Vycm9yJywgKGVycm9yKSA9PiB7XHJcbiAgICAgICAgcmVqZWN0KGVycm9yKTtcclxuICAgICAgfSk7XHJcbiAgfSk7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBTZW5kcyBhIFBPU1QgcmVxdWVzdCB0byB0aGUgc3BlY2lmaWVkIFVSTCB3aXRoIHRoZSBwcm92aWRlZCBKU09OIGJvZHkgdXNpbmdcclxuICogZWl0aGVyIEhUVFAgb3IgSFRUUFMgcHJvdG9jb2wuXHJcbiAqXHJcbiAqIEBhc3luY1xyXG4gKiBAZnVuY3Rpb24gcG9zdFxyXG4gKlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gdXJsIC0gVGhlIFVSTCB0byBzZW5kIHRoZSBQT1NUIHJlcXVlc3QgdG8uXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBbYm9keT17fV0gLSBUaGUgSlNPTiBib2R5IHRvIGluY2x1ZGUgaW4gdGhlIFBPU1QgcmVxdWVzdC5cclxuICogVGhlIGRlZmF1bHQgdmFsdWUgaXMgYW4gZW1wdHkgb2JqZWN0LlxyXG4gKiBAcGFyYW0ge09iamVjdH0gW3JlcXVlc3RPcHRpb25zPXt9XSAtIE9wdGlvbnMgZm9yIHRoZSBIVFRQL0hUVFBTIHJlcXVlc3QuXHJcbiAqIFRoZSBkZWZhdWx0IHZhbHVlIGlzIGFuIGVtcHR5IG9iamVjdC5cclxuICpcclxuICogQHJldHVybnMge1Byb21pc2U8T2JqZWN0Pn0gQSBQcm9taXNlIHRoYXQgcmVzb2x2ZXMgdG8gdGhlIEhUVFAvSFRUUFMgcmVzcG9uc2VcclxuICogb2JqZWN0IHdpdGggYWRkZWQgJ3RleHQnIHByb3BlcnR5IG9yIHJlamVjdGluZyB3aXRoIGFuIGVycm9yLlxyXG4gKi9cclxuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIHBvc3QodXJsLCBib2R5ID0ge30sIHJlcXVlc3RPcHRpb25zID0ge30pIHtcclxuICByZXR1cm4gbmV3IFByb21pc2UoKHJlc29sdmUsIHJlamVjdCkgPT4ge1xyXG4gICAgY29uc3QgZGF0YSA9IEpTT04uc3RyaW5naWZ5KGJvZHkpO1xyXG5cclxuICAgIC8vIFNldCBkZWZhdWx0IGhlYWRlcnMgYW5kIG1lcmdlIHdpdGggYHJlcXVlc3RPcHRpb25zYFxyXG4gICAgY29uc3Qgb3B0aW9ucyA9IE9iamVjdC5hc3NpZ24oXHJcbiAgICAgIHtcclxuICAgICAgICBtZXRob2Q6ICdQT1NUJyxcclxuICAgICAgICBoZWFkZXJzOiB7XHJcbiAgICAgICAgICAnQ29udGVudC1UeXBlJzogJ2FwcGxpY2F0aW9uL2pzb24nLFxyXG4gICAgICAgICAgJ0NvbnRlbnQtTGVuZ3RoJzogZGF0YS5sZW5ndGhcclxuICAgICAgICB9XHJcbiAgICAgIH0sXHJcbiAgICAgIHJlcXVlc3RPcHRpb25zXHJcbiAgICApO1xyXG5cclxuICAgIC8vIERlY2lkZSBvbiB0aGUgcHJvdG9jb2xcclxuICAgIGNvbnN0IHJlcXVlc3QgPSBfZ2V0UHJvdG9jb2xNb2R1bGUodXJsKVxyXG4gICAgICAucmVxdWVzdCh1cmwsIG9wdGlvbnMsIChyZXNwb25zZSkgPT4ge1xyXG4gICAgICAgIGxldCByZXNwb25zZURhdGEgPSAnJztcclxuXHJcbiAgICAgICAgLy8gQSBjaHVuayBvZiBkYXRhIGhhcyBiZWVuIHJlY2VpdmVkXHJcbiAgICAgICAgcmVzcG9uc2Uub24oJ2RhdGEnLCAoY2h1bmspID0+IHtcclxuICAgICAgICAgIHJlc3BvbnNlRGF0YSArPSBjaHVuaztcclxuICAgICAgICB9KTtcclxuXHJcbiAgICAgICAgLy8gVGhlIHdob2xlIHJlc3BvbnNlIGhhcyBiZWVuIHJlY2VpdmVkXHJcbiAgICAgICAgcmVzcG9uc2Uub24oJ2VuZCcsICgpID0+IHtcclxuICAgICAgICAgIHRyeSB7XHJcbiAgICAgICAgICAgIC8vIEdldCB0aGUgZnVsbCByZXN1bHQgYW5kIHJlc29sdmUgdGhlIHJlcXVlc3RcclxuICAgICAgICAgICAgcmVzcG9uc2UudGV4dCA9IHJlc3BvbnNlRGF0YTtcclxuICAgICAgICAgICAgcmVzb2x2ZShyZXNwb25zZSk7XHJcbiAgICAgICAgICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgICAgICAgICByZWplY3QoZXJyb3IpO1xyXG4gICAgICAgICAgfVxyXG4gICAgICAgIH0pO1xyXG4gICAgICB9KVxyXG4gICAgICAub24oJ2Vycm9yJywgKGVycm9yKSA9PiB7XHJcbiAgICAgICAgcmVqZWN0KGVycm9yKTtcclxuICAgICAgfSk7XHJcblxyXG4gICAgLy8gV3JpdGUgdGhlIHJlcXVlc3QgYm9keSBhbmQgZW5kIHRoZSByZXF1ZXN0XHJcbiAgICByZXF1ZXN0LndyaXRlKGRhdGEpO1xyXG4gICAgcmVxdWVzdC5lbmQoKTtcclxuICB9KTtcclxufVxyXG5cclxuLyoqXHJcbiAqIFJldHVybnMgdGhlIEhUVFAgb3IgSFRUUFMgcHJvdG9jb2wgbW9kdWxlIGJhc2VkIG9uIHRoZSBwcm92aWRlZCBVUkwuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBfZ2V0UHJvdG9jb2xNb2R1bGVcclxuICpcclxuICogQHBhcmFtIHtzdHJpbmd9IHVybCAtIFRoZSBVUkwgdG8gZGV0ZXJtaW5lIHRoZSBwcm90b2NvbC5cclxuICpcclxuICogQHJldHVybnMge09iamVjdH0gVGhlIEhUVFAgb3IgSFRUUFMgcHJvdG9jb2wgbW9kdWxlIChgaHR0cGAgb3IgYGh0dHBzYCkuXHJcbiAqL1xyXG5mdW5jdGlvbiBfZ2V0UHJvdG9jb2xNb2R1bGUodXJsKSB7XHJcbiAgcmV0dXJuIHVybC5zdGFydHNXaXRoKCdodHRwcycpID8gaHR0cHMgOiBodHRwO1xyXG59XHJcblxyXG5leHBvcnQgZGVmYXVsdCB7XHJcbiAgZ2V0LFxyXG4gIHBvc3RcclxufTtcclxuIiwiLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcclxuXHJcbkhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlclxyXG5cclxuQ29weXJpZ2h0IChjKSAyMDE2LTIwMjUsIEhpZ2hzb2Z0XHJcblxyXG5MaWNlbmNlZCB1bmRlciB0aGUgTUlUIGxpY2VuY2UuXHJcblxyXG5BZGRpdGlvbmFsbHkgYSB2YWxpZCBIaWdoY2hhcnRzIGxpY2Vuc2UgaXMgcmVxdWlyZWQgZm9yIHVzZS5cclxuXHJcblNlZSBMSUNFTlNFIGZpbGUgaW4gcm9vdCBmb3IgZGV0YWlscy5cclxuXHJcbioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXHJcblxyXG4vKipcclxuICogQG92ZXJ2aWV3IFRoZSBjYWNoZSBtYW5hZ2VyIGlzIHJlc3BvbnNpYmxlIGZvciBoYW5kbGluZyBhbmQgbWFuYWdpbmdcclxuICogdGhlIEhpZ2hjaGFydHMgbGlicmFyeSBhbG9uZyB3aXRoIGl0cyBkZXBlbmRlbmNpZXMuIEl0IGVuc3VyZXMgdGhhdCB0aGVzZVxyXG4gKiByZXNvdXJjZXMgYXJlIHN0b3JlZCBhbmQgcmV0cmlldmVkIGVmZmljaWVudGx5IHRvIG9wdGltaXplIHBlcmZvcm1hbmNlXHJcbiAqIGFuZCByZWR1Y2UgcmVkdW5kYW50IG5ldHdvcmsgcmVxdWVzdHMuIFRoZSBjYWNoZSBpcyBzdG9yZWQgaW4gdGhlIGAuY2FjaGVgXHJcbiAqIGRpcmVjdG9yeSBieSBkZWZhdWx0LCB3aGljaCBzZXJ2ZXMgYXMgYSBkZWRpY2F0ZWQgZm9sZGVyIGZvciBrZWVwaW5nIGNhY2hlZFxyXG4gKiBmaWxlcy5cclxuICovXHJcblxyXG5pbXBvcnQgeyBleGlzdHNTeW5jLCBta2RpclN5bmMsIHJlYWRGaWxlU3luYywgd3JpdGVGaWxlU3luYyB9IGZyb20gJ2ZzJztcclxuaW1wb3J0IHsgam9pbiB9IGZyb20gJ3BhdGgnO1xyXG5cclxuaW1wb3J0IHsgSHR0cHNQcm94eUFnZW50IH0gZnJvbSAnaHR0cHMtcHJveHktYWdlbnQnO1xyXG5cclxuaW1wb3J0IHsgZ2V0T3B0aW9ucywgdXBkYXRlT3B0aW9ucyB9IGZyb20gJy4vY29uZmlnLmpzJztcclxuaW1wb3J0IHsgZ2V0IH0gZnJvbSAnLi9mZXRjaC5qcyc7XHJcbmltcG9ydCB7IGxvZyB9IGZyb20gJy4vbG9nZ2VyLmpzJztcclxuaW1wb3J0IHsgZ2V0QWJzb2x1dGVQYXRoIH0gZnJvbSAnLi91dGlscy5qcyc7XHJcblxyXG5pbXBvcnQgRXhwb3J0RXJyb3IgZnJvbSAnLi9lcnJvcnMvRXhwb3J0RXJyb3IuanMnO1xyXG5cclxuLy8gVGhlIGluaXRpYWwgY2FjaGUgdGVtcGxhdGVcclxuY29uc3QgY2FjaGUgPSB7XHJcbiAgY2RuVXJsOiAnaHR0cHM6Ly9jb2RlLmhpZ2hjaGFydHMuY29tJyxcclxuICBhY3RpdmVNYW5pZmVzdDoge30sXHJcbiAgc291cmNlczogJycsXHJcbiAgaGNWZXJzaW9uOiAnJ1xyXG59O1xyXG5cclxuLyoqXHJcbiAqIENoZWNrcyB0aGUgY2FjaGUgZm9yIEhpZ2hjaGFydHMgZGVwZW5kZW5jaWVzLCB1cGRhdGVzIHRoZSBjYWNoZSBpZiBuZWVkZWQsXHJcbiAqIGFuZCBsb2FkcyB0aGUgc291cmNlcy5cclxuICpcclxuICogQGFzeW5jXHJcbiAqIEBmdW5jdGlvbiBjaGVja0NhY2hlXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBoaWdoY2hhcnRzT3B0aW9ucyAtIFRoZSBjb25maWd1cmF0aW9uIG9iamVjdCBjb250YWluaW5nXHJcbiAqIGBoaWdoY2hhcnRzYCBvcHRpb25zLlxyXG4gKiBAcGFyYW0ge09iamVjdH0gc2VydmVyUHJveHlPcHRpb25zLSBUaGUgY29uZmlndXJhdGlvbiBvYmplY3QgY29udGFpbmluZ1xyXG4gKiBgc2VydmVyLnByb3h5YCBvcHRpb25zLlxyXG4gKi9cclxuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIGNoZWNrQ2FjaGUoaGlnaGNoYXJ0c09wdGlvbnMsIHNlcnZlclByb3h5T3B0aW9ucykge1xyXG4gIHRyeSB7XHJcbiAgICBsZXQgZmV0Y2hlZE1vZHVsZXM7XHJcblxyXG4gICAgLy8gR2V0IHRoZSBjYWNoZSBwYXRoXHJcbiAgICBjb25zdCBjYWNoZVBhdGggPSBnZXRDYWNoZVBhdGgoKTtcclxuXHJcbiAgICAvLyBQcmVwYXJlIHBhdGhzIHRvIG1hbmlmZXN0IGFuZCBzb3VyY2VzIGZyb20gdGhlIGNhY2hlIGZvbGRlclxyXG4gICAgY29uc3QgbWFuaWZlc3RQYXRoID0gam9pbihjYWNoZVBhdGgsICdtYW5pZmVzdC5qc29uJyk7XHJcbiAgICBjb25zdCBzb3VyY2VQYXRoID0gam9pbihjYWNoZVBhdGgsICdzb3VyY2VzLmpzJyk7XHJcblxyXG4gICAgLy8gQ3JlYXRlIHRoZSBjYWNoZSBkZXN0aW5hdGlvbiBpZiBpdCBkb2Vzbid0IGV4aXN0IGFscmVhZHlcclxuICAgICFleGlzdHNTeW5jKGNhY2hlUGF0aCkgJiYgbWtkaXJTeW5jKGNhY2hlUGF0aCwgeyByZWN1cnNpdmU6IHRydWUgfSk7XHJcblxyXG4gICAgLy8gRmV0Y2ggYWxsIHRoZSBzY3JpcHRzIGVpdGhlciBpZiB0aGUgYG1hbmlmZXN0Lmpzb25gIGRvZXMgbm90IGV4aXN0XHJcbiAgICAvLyBvciBpZiB0aGUgYGZvcmNlRmV0Y2hgIG9wdGlvbiBpcyBlbmFibGVkXHJcbiAgICBpZiAoIWV4aXN0c1N5bmMobWFuaWZlc3RQYXRoKSB8fCBoaWdoY2hhcnRzT3B0aW9ucy5mb3JjZUZldGNoKSB7XHJcbiAgICAgIGxvZygzLCAnW2NhY2hlXSBGZXRjaGluZyBhbmQgY2FjaGluZyBIaWdoY2hhcnRzIGRlcGVuZGVuY2llcy4nKTtcclxuXHJcbiAgICAgIC8vIFRoZSBpbml0aWFsIGNhY2hlIHVwZGF0ZVxyXG4gICAgICBmZXRjaGVkTW9kdWxlcyA9IGF3YWl0IF91cGRhdGVDYWNoZShcclxuICAgICAgICBoaWdoY2hhcnRzT3B0aW9ucyxcclxuICAgICAgICBzZXJ2ZXJQcm94eU9wdGlvbnMsXHJcbiAgICAgICAgc291cmNlUGF0aFxyXG4gICAgICApO1xyXG4gICAgfSBlbHNlIHtcclxuICAgICAgbGV0IHJlcXVlc3RVcGRhdGUgPSBmYWxzZTtcclxuXHJcbiAgICAgIC8vIFJlYWQgdGhlIG1hbmlmZXN0IEpTT05cclxuICAgICAgY29uc3QgbWFuaWZlc3QgPSBKU09OLnBhcnNlKHJlYWRGaWxlU3luYyhtYW5pZmVzdFBhdGgpLCAndXRmOCcpO1xyXG5cclxuICAgICAgLy8gQ2hlY2sgaWYgdGhlIG1vZHVsZXMgaXMgYW4gYXJyYXksIGlmIHNvLCB3ZSByZXdyaXRlIGl0IHRvIGEgbWFwIHRvIG1ha2VcclxuICAgICAgLy8gaXQgZWFzaWVyIHRvIHJlc29sdmUgbW9kdWxlc1xyXG4gICAgICBpZiAobWFuaWZlc3QubW9kdWxlcyAmJiBBcnJheS5pc0FycmF5KG1hbmlmZXN0Lm1vZHVsZXMpKSB7XHJcbiAgICAgICAgY29uc3QgbW9kdWxlTWFwID0ge307XHJcbiAgICAgICAgbWFuaWZlc3QubW9kdWxlcy5mb3JFYWNoKChtKSA9PiAobW9kdWxlTWFwW21dID0gMSkpO1xyXG4gICAgICAgIG1hbmlmZXN0Lm1vZHVsZXMgPSBtb2R1bGVNYXA7XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIC8vIEdldCB0aGUgYWN0dWFsIG51bWJlciBvZiBzY3JpcHRzIHRvIGJlIGZldGNoZWRcclxuICAgICAgY29uc3QgeyBjb3JlU2NyaXB0cywgbW9kdWxlU2NyaXB0cywgaW5kaWNhdG9yU2NyaXB0cyB9ID1cclxuICAgICAgICBoaWdoY2hhcnRzT3B0aW9ucztcclxuICAgICAgY29uc3QgbnVtYmVyT2ZNb2R1bGVzID1cclxuICAgICAgICBjb3JlU2NyaXB0cy5sZW5ndGggKyBtb2R1bGVTY3JpcHRzLmxlbmd0aCArIGluZGljYXRvclNjcmlwdHMubGVuZ3RoO1xyXG5cclxuICAgICAgLy8gQ29tcGFyZSB0aGUgbG9hZGVkIGhpZ2hjaGFydHMgY29uZmlnIHdpdGggdGhlIGNvbnRlbnRzIGluIGNhY2hlLlxyXG4gICAgICAvLyBJZiB0aGVyZSBhcmUgY2hhbmdlcywgZmV0Y2ggcmVxdWVzdGVkIG1vZHVsZXMgYW5kIHByb2R1Y3RzLFxyXG4gICAgICAvLyBhbmQgYmFrZSB0aGVtIGludG8gYSBnaWFudCBibG9iLiBTYXZlIHRoZSBibG9iLlxyXG4gICAgICBpZiAobWFuaWZlc3QudmVyc2lvbiAhPT0gaGlnaGNoYXJ0c09wdGlvbnMudmVyc2lvbikge1xyXG4gICAgICAgIC8vIENoZWNrIHRoZSBIaWdoY2hhcnRzIHZlcnNpb25cclxuICAgICAgICBsb2coXHJcbiAgICAgICAgICAyLFxyXG4gICAgICAgICAgJ1tjYWNoZV0gQSBIaWdoY2hhcnRzIHZlcnNpb24gbWlzbWF0Y2ggaW4gdGhlIGNhY2hlLCBuZWVkIHRvIHJlLWZldGNoLidcclxuICAgICAgICApO1xyXG4gICAgICAgIHJlcXVlc3RVcGRhdGUgPSB0cnVlO1xyXG4gICAgICB9IGVsc2UgaWYgKFxyXG4gICAgICAgIE9iamVjdC5rZXlzKG1hbmlmZXN0Lm1vZHVsZXMgfHwge30pLmxlbmd0aCAhPT0gbnVtYmVyT2ZNb2R1bGVzXHJcbiAgICAgICkge1xyXG4gICAgICAgIC8vIENoZWNrIHRoZSBudW1iZXIgb2YgbW9kdWxlc1xyXG4gICAgICAgIGxvZyhcclxuICAgICAgICAgIDIsXHJcbiAgICAgICAgICAnW2NhY2hlXSBUaGUgY2FjaGUgYW5kIHRoZSByZXF1ZXN0ZWQgbW9kdWxlcyBkbyBub3QgbWF0Y2gsIG5lZWQgdG8gcmUtZmV0Y2guJ1xyXG4gICAgICAgICk7XHJcbiAgICAgICAgcmVxdWVzdFVwZGF0ZSA9IHRydWU7XHJcbiAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgLy8gQ2hlY2sgZWFjaCBtb2R1bGUsIGlmIGFueXRoaW5nIGlzIG1pc3NpbmcgcmVmZXRjaCBldmVyeXRoaW5nXHJcbiAgICAgICAgcmVxdWVzdFVwZGF0ZSA9IChtb2R1bGVTY3JpcHRzIHx8IFtdKS5zb21lKChtb2R1bGVOYW1lKSA9PiB7XHJcbiAgICAgICAgICBpZiAoIW1hbmlmZXN0Lm1vZHVsZXNbbW9kdWxlTmFtZV0pIHtcclxuICAgICAgICAgICAgbG9nKFxyXG4gICAgICAgICAgICAgIDIsXHJcbiAgICAgICAgICAgICAgYFtjYWNoZV0gVGhlICR7bW9kdWxlTmFtZX0gaXMgbWlzc2luZyBpbiB0aGUgY2FjaGUsIG5lZWQgdG8gcmUtZmV0Y2guYFxyXG4gICAgICAgICAgICApO1xyXG4gICAgICAgICAgICByZXR1cm4gdHJ1ZTtcclxuICAgICAgICAgIH1cclxuICAgICAgICB9KTtcclxuICAgICAgfVxyXG5cclxuICAgICAgLy8gVXBkYXRlIGNhY2hlIGlmIG5lZWRlZFxyXG4gICAgICBpZiAocmVxdWVzdFVwZGF0ZSkge1xyXG4gICAgICAgIGZldGNoZWRNb2R1bGVzID0gYXdhaXQgX3VwZGF0ZUNhY2hlKFxyXG4gICAgICAgICAgaGlnaGNoYXJ0c09wdGlvbnMsXHJcbiAgICAgICAgICBzZXJ2ZXJQcm94eU9wdGlvbnMsXHJcbiAgICAgICAgICBzb3VyY2VQYXRoXHJcbiAgICAgICAgKTtcclxuICAgICAgfSBlbHNlIHtcclxuICAgICAgICBsb2coMywgJ1tjYWNoZV0gRGVwZW5kZW5jeSBjYWNoZSBpcyB1cCB0byBkYXRlLCBwcm9jZWVkaW5nLicpO1xyXG5cclxuICAgICAgICAvLyBMb2FkIHRoZSBzb3VyY2VzXHJcbiAgICAgICAgY2FjaGUuc291cmNlcyA9IHJlYWRGaWxlU3luYyhzb3VyY2VQYXRoLCAndXRmOCcpO1xyXG5cclxuICAgICAgICAvLyBHZXQgY3VycmVudCBtb2R1bGVzIG1hcFxyXG4gICAgICAgIGZldGNoZWRNb2R1bGVzID0gbWFuaWZlc3QubW9kdWxlcztcclxuXHJcbiAgICAgICAgLy8gRXh0cmFjdCBhbmQgc2F2ZSB2ZXJzaW9uIG9mIGN1cnJlbnRseSB1c2VkIEhpZ2hjaGFydHNcclxuICAgICAgICBjYWNoZS5oY1ZlcnNpb24gPSBfZXh0cmFjdEhjVmVyc2lvbihjYWNoZS5zb3VyY2VzKTtcclxuICAgICAgfVxyXG4gICAgfVxyXG5cclxuICAgIC8vIEZpbmFsbHksIHNhdmUgdGhlIG5ldyBtYW5pZmVzdCwgd2hpY2ggaXMgYmFzaWNhbGx5IG91ciBjdXJyZW50IGNvbmZpZ1xyXG4gICAgLy8gaW4gYSBzbGlnaHRseSBkaWZmZXJlbnQgZm9ybWF0XHJcbiAgICBhd2FpdCBfc2F2ZUNvbmZpZ1RvTWFuaWZlc3QoaGlnaGNoYXJ0c09wdGlvbnMudmVyc2lvbiwgZmV0Y2hlZE1vZHVsZXMpO1xyXG4gIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoXHJcbiAgICAgICdbY2FjaGVdIENvdWxkIG5vdCBjb25maWd1cmUgY2FjaGUgYW5kIGNyZWF0ZSBvciB1cGRhdGUgdGhlIGNvbmZpZyBtYW5pZmVzdC4nLFxyXG4gICAgICA1MDBcclxuICAgICkuc2V0RXJyb3IoZXJyb3IpO1xyXG4gIH1cclxufVxyXG5cclxuLyoqXHJcbiAqIEdldHMgdGhlIHZlcnNpb24gb2YgSGlnaGNoYXJ0cyBmcm9tIHRoZSBjYWNoZS5cclxuICpcclxuICogQGZ1bmN0aW9uIGdldEhjVmVyc2lvblxyXG4gKlxyXG4gKiBAcmV0dXJucyB7c3RyaW5nfSBUaGUgY2FjaGVkIEhpZ2hjaGFydHMgdmVyc2lvbi5cclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiBnZXRIY1ZlcnNpb24oKSB7XHJcbiAgcmV0dXJuIGNhY2hlLmhjVmVyc2lvbjtcclxufVxyXG5cclxuLyoqXHJcbiAqIFVwZGF0ZXMgdGhlIEhpZ2hjaGFydHMgdmVyc2lvbiBpbiB0aGUgYXBwbGllZCBjb25maWd1cmF0aW9uIGFuZCBjaGVja3NcclxuICogdGhlIGNhY2hlIGZvciB0aGUgc2NyaXB0cyBvZiBhIG5ldyB2ZXJzaW9uLlxyXG4gKlxyXG4gKiBAYXN5bmNcclxuICogQGZ1bmN0aW9uIHVwZGF0ZUhjVmVyc2lvblxyXG4gKlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gbmV3VmVyc2lvbiAtIFRoZSBuZXcgSGlnaGNoYXJ0cyB2ZXJzaW9uIHRvIGJlIGFwcGxpZWQuXHJcbiAqL1xyXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gdXBkYXRlSGNWZXJzaW9uKG5ld1ZlcnNpb24pIHtcclxuICAvLyBVcGRhdGUgdG8gdGhlIG5ldyB2ZXJzaW9uXHJcbiAgY29uc3Qgb3B0aW9ucyA9IHVwZGF0ZU9wdGlvbnMoe1xyXG4gICAgaGlnaGNoYXJ0czoge1xyXG4gICAgICB2ZXJzaW9uOiBuZXdWZXJzaW9uXHJcbiAgICB9XHJcbiAgfSk7XHJcblxyXG4gIC8vIENoZWNrIGlmIGNhY2hlIG5lZWRzIHRvIGJlIHVwZGF0ZWRcclxuICBhd2FpdCBjaGVja0NhY2hlKG9wdGlvbnMuaGlnaGNoYXJ0cywgb3B0aW9ucy5zZXJ2ZXIucHJveHkpO1xyXG59XHJcblxyXG4vKipcclxuICogUmV0cmlldmVzIHRoZSBjdXJyZW50IGNhY2hlIG9iamVjdC5cclxuICpcclxuICogQGZ1bmN0aW9uIGdldENhY2hlXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtPYmplY3R9IFRoZSBjYWNoZSBvYmplY3QgY29udGFpbmluZyB2YXJpb3VzIGNhY2hlZCBkYXRhLlxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIGdldENhY2hlKCkge1xyXG4gIHJldHVybiBjYWNoZTtcclxufVxyXG5cclxuLyoqXHJcbiAqIEdldHMgdGhlIGNhY2hlIHBhdGggZm9yIEhpZ2hjaGFydHMuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBnZXRDYWNoZVBhdGhcclxuICpcclxuICogQHJldHVybnMge3N0cmluZ30gVGhlIGFic29sdXRlIHBhdGggdG8gdGhlIGNhY2hlIGRpcmVjdG9yeSBmb3IgSGlnaGNoYXJ0cy5cclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiBnZXRDYWNoZVBhdGgoKSB7XHJcbiAgcmV0dXJuIGdldEFic29sdXRlUGF0aChnZXRPcHRpb25zKCkuaGlnaGNoYXJ0cy5jYWNoZVBhdGgsICd1dGY4Jyk7IC8vICM1NjJcclxufVxyXG5cclxuLyoqXHJcbiAqIFNhdmVzIHRoZSBwcm92aWRlZCBjb25maWd1cmF0aW9uIGFuZCBmZXRjaGVkIG1vZHVsZXMgdG8gdGhlIGNhY2hlIG1hbmlmZXN0XHJcbiAqIGZpbGUuXHJcbiAqXHJcbiAqIEBhc3luY1xyXG4gKiBAZnVuY3Rpb24gX3NhdmVDb25maWdUb01hbmlmZXN0XHJcbiAqXHJcbiAqIEBwYXJhbSB7bnVtYmVyfSB2ZXJzaW9uIC0gVGhlIGN1cnJlbnRseSB1c2VkIEhpZ2hjaGFydHMgdmVyc2lvbi5cclxuICogQHBhcmFtIHtPYmplY3R9IFtmZXRjaGVkTW9kdWxlcz17fV0gLSBBbiBvYmplY3Qgd2hpY2ggdHJhY2tzIHdoaWNoIG1vZHVsZXNcclxuICogaGF2ZSBiZWVuIGZldGNoZWQuIFRoZSBkZWZhdWx0IHZhbHVlIGlzIGFuIGVtcHR5IG9iamVjdC5cclxuICpcclxuICogQHRocm93cyB7RXhwb3J0RXJyb3J9IFRocm93cyBhbiBgRXhwb3J0RXJyb3JgIGlmIGFuIGVycm9yIG9jY3VycyB3aGlsZVxyXG4gKiB3cml0aW5nIHRoZSBjYWNoZSBtYW5pZmVzdC5cclxuICovXHJcbmFzeW5jIGZ1bmN0aW9uIF9zYXZlQ29uZmlnVG9NYW5pZmVzdCh2ZXJzaW9uLCBmZXRjaGVkTW9kdWxlcyA9IHt9KSB7XHJcbiAgLy8gVXBkYXRlIGNhY2hlIG9iamVjdCB3aXRoIHRoZSBjdXJyZW50IG1vZHVsZXNcclxuICBjYWNoZS5hY3RpdmVNYW5pZmVzdCA9IHtcclxuICAgIHZlcnNpb24sXHJcbiAgICBtb2R1bGVzOiBmZXRjaGVkTW9kdWxlc1xyXG4gIH07XHJcblxyXG4gIGxvZygzLCAnW2NhY2hlXSBXcml0aW5nIGEgbmV3IG1hbmlmZXN0LicpO1xyXG4gIHRyeSB7XHJcbiAgICB3cml0ZUZpbGVTeW5jKFxyXG4gICAgICBqb2luKGdldENhY2hlUGF0aCgpLCAnbWFuaWZlc3QuanNvbicpLFxyXG4gICAgICBKU09OLnN0cmluZ2lmeShjYWNoZS5hY3RpdmVNYW5pZmVzdCksXHJcbiAgICAgICd1dGY4J1xyXG4gICAgKTtcclxuICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgdGhyb3cgbmV3IEV4cG9ydEVycm9yKFxyXG4gICAgICAnW2NhY2hlXSBFcnJvciB3cml0aW5nIHRoZSBjYWNoZSBtYW5pZmVzdC4nLFxyXG4gICAgICA1MDBcclxuICAgICkuc2V0RXJyb3IoZXJyb3IpO1xyXG4gIH1cclxufVxyXG5cclxuLyoqXHJcbiAqIFVwZGF0ZXMgdGhlIGxvY2FsIGNhY2hlIHdpdGggSGlnaGNoYXJ0cyBzY3JpcHRzIGNvbnRlbnQgYW5kIGluZm9ybWF0aW9uLFxyXG4gKiBhbmQgdXNlZCBIaWdoY2hhcnRzIHZlcnNpb24uXHJcbiAqXHJcbiAqIEBhc3luY1xyXG4gKiBAZnVuY3Rpb24gX3VwZGF0ZUNhY2hlXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBoaWdoY2hhcnRzT3B0aW9ucyAtIFRoZSBjb25maWd1cmF0aW9uIG9iamVjdCBjb250YWluaW5nXHJcbiAqIGBoaWdoY2hhcnRzYCBvcHRpb25zLlxyXG4gKiBAcGFyYW0ge09iamVjdH0gc2VydmVyUHJveHlPcHRpb25zIC0gVGhlIGNvbmZpZ3VyYXRpb24gb2JqZWN0IGNvbnRhaW5pbmdcclxuICogYHNlcnZlci5wcm94eWAgb3B0aW9ucy5cclxuICogQHBhcmFtIHtzdHJpbmd9IHNvdXJjZVBhdGggLSBUaGUgcGF0aCB0byB0aGUgc291cmNlIGZpbGUgaW4gdGhlIGNhY2hlLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7UHJvbWlzZTxPYmplY3Q+fSBBIFByb21pc2UgdGhhdCByZXNvbHZlcyB0byBhbiBvYmplY3QgcmVwcmVzZW50aW5nXHJcbiAqIHRoZSBmZXRjaGVkIG1vZHVsZXMuXHJcbiAqXHJcbiAqIEB0aHJvd3Mge0V4cG9ydEVycm9yfSBUaHJvd3MgYW4gYEV4cG9ydEVycm9yYCBpZiB0aGVyZSBpcyBhbiBpc3N1ZSB1cGRhdGluZ1xyXG4gKiB0aGUgbG9jYWwgSGlnaGNoYXJ0cyBjYWNoZS5cclxuICovXHJcbmFzeW5jIGZ1bmN0aW9uIF91cGRhdGVDYWNoZShoaWdoY2hhcnRzT3B0aW9ucywgc2VydmVyUHJveHlPcHRpb25zLCBzb3VyY2VQYXRoKSB7XHJcbiAgdHJ5IHtcclxuICAgIC8vIEdldCBIaWdoY2hhcnRzIHZlcnNpb24gZm9yIHNjcmlwdHNcclxuICAgIGNvbnN0IGhjVmVyc2lvbiA9XHJcbiAgICAgIGhpZ2hjaGFydHNPcHRpb25zLnZlcnNpb24gPT09ICdsYXRlc3QnXHJcbiAgICAgICAgPyBudWxsXHJcbiAgICAgICAgOiBgJHtoaWdoY2hhcnRzT3B0aW9ucy52ZXJzaW9ufWA7XHJcblxyXG4gICAgbG9nKFxyXG4gICAgICAzLFxyXG4gICAgICBgW2NhY2hlXSBVcGRhdGluZyBjYWNoZSB2ZXJzaW9uIHRvIEhpZ2hjaGFydHM6ICR7aGNWZXJzaW9uIHx8ICdsYXRlc3QnfS5gXHJcbiAgICApO1xyXG5cclxuICAgIC8vIEdldCB0aGUgQ0ROIHVybCBmb3Igc2NyaXB0c1xyXG4gICAgY29uc3QgY2RuVXJsID0gaGlnaGNoYXJ0c09wdGlvbnMuY2RuVXJsIHx8IGNhY2hlLmNkblVybDtcclxuXHJcbiAgICAvLyBQcmVwYXJlIG9wdGlvbnMgZm9yIGEgcmVxdWVzdFxyXG4gICAgY29uc3QgcmVxdWVzdE9wdGlvbnMgPSBfY29uZmlndXJlUmVxdWVzdChzZXJ2ZXJQcm94eU9wdGlvbnMpO1xyXG5cclxuICAgIC8vIEFuIG9iamVjdCB0byByZWNvcmQgd2hpY2ggc2NyaXB0cyBhcmUgZmV0Y2hlZFxyXG4gICAgY29uc3QgZmV0Y2hlZE1vZHVsZXMgPSB7fTtcclxuXHJcbiAgICAvLyBKb2luIGFsbCBmZXRjaGVkIHNjcmlwdHMgYW5kIHNhdmUgaW4gdGhlIG1hbmlmZXN0J3Mgc291cmNlc1xyXG4gICAgY2FjaGUuc291cmNlcyA9IChcclxuICAgICAgYXdhaXQgUHJvbWlzZS5hbGwoW1xyXG4gICAgICAgIC8vIEhpZ2hjaGFydHMgY29yZSBzY3JpcHRzIGZldGNoXHJcbiAgICAgICAgLi4uaGlnaGNoYXJ0c09wdGlvbnMuY29yZVNjcmlwdHMubWFwKChjcykgPT5cclxuICAgICAgICAgIF9mZXRjaFNjcmlwdChcclxuICAgICAgICAgICAgaGNWZXJzaW9uID8gYCR7Y2RuVXJsfS8ke2hjVmVyc2lvbn0vJHtjc31gIDogYCR7Y2RuVXJsfS8ke2NzfWAsXHJcbiAgICAgICAgICAgIHJlcXVlc3RPcHRpb25zLFxyXG4gICAgICAgICAgICBmZXRjaGVkTW9kdWxlcyxcclxuICAgICAgICAgICAgdHJ1ZVxyXG4gICAgICAgICAgKVxyXG4gICAgICAgICksXHJcbiAgICAgICAgLy8gSGlnaGNoYXJ0cyBtb2R1bGUgc2NyaXB0cyBmZXRjaFxyXG4gICAgICAgIC4uLmhpZ2hjaGFydHNPcHRpb25zLm1vZHVsZVNjcmlwdHMubWFwKChtcykgPT5cclxuICAgICAgICAgIF9mZXRjaFNjcmlwdChcclxuICAgICAgICAgICAgbXMgPT09ICdtYXAnXHJcbiAgICAgICAgICAgICAgPyBoY1ZlcnNpb25cclxuICAgICAgICAgICAgICAgID8gYCR7Y2RuVXJsfS9tYXBzLyR7aGNWZXJzaW9ufS9tb2R1bGVzLyR7bXN9YFxyXG4gICAgICAgICAgICAgICAgOiBgJHtjZG5Vcmx9L21hcHMvbW9kdWxlcy8ke21zfWBcclxuICAgICAgICAgICAgICA6IGhjVmVyc2lvblxyXG4gICAgICAgICAgICAgICAgPyBgJHtjZG5Vcmx9LyR7aGNWZXJzaW9ufS9tb2R1bGVzLyR7bXN9YFxyXG4gICAgICAgICAgICAgICAgOiBgJHtjZG5Vcmx9L21vZHVsZXMvJHttc31gLFxyXG4gICAgICAgICAgICByZXF1ZXN0T3B0aW9ucyxcclxuICAgICAgICAgICAgZmV0Y2hlZE1vZHVsZXNcclxuICAgICAgICAgIClcclxuICAgICAgICApLFxyXG4gICAgICAgIC8vIEhpZ2hjaGFydHMgaW5kaWNhdG9yIHNjcmlwdHMgZmV0Y2hcclxuICAgICAgICAuLi5oaWdoY2hhcnRzT3B0aW9ucy5pbmRpY2F0b3JTY3JpcHRzLm1hcCgoaXMpID0+XHJcbiAgICAgICAgICBfZmV0Y2hTY3JpcHQoXHJcbiAgICAgICAgICAgIGhjVmVyc2lvblxyXG4gICAgICAgICAgICAgID8gYCR7Y2RuVXJsfS9zdG9jay8ke2hjVmVyc2lvbn0vaW5kaWNhdG9ycy8ke2lzfWBcclxuICAgICAgICAgICAgICA6IGAke2NkblVybH0vc3RvY2svaW5kaWNhdG9ycy8ke2lzfWAsXHJcbiAgICAgICAgICAgIHJlcXVlc3RPcHRpb25zLFxyXG4gICAgICAgICAgICBmZXRjaGVkTW9kdWxlc1xyXG4gICAgICAgICAgKVxyXG4gICAgICAgICksXHJcbiAgICAgICAgLy8gQ3VzdG9tIHNjcmlwdHMgZmV0Y2hcclxuICAgICAgICAuLi5oaWdoY2hhcnRzT3B0aW9ucy5jdXN0b21TY3JpcHRzLm1hcCgoY3MpID0+XHJcbiAgICAgICAgICBfZmV0Y2hTY3JpcHQoYCR7Y3N9YCwgcmVxdWVzdE9wdGlvbnMpXHJcbiAgICAgICAgKVxyXG4gICAgICBdKVxyXG4gICAgKS5qb2luKCc7XFxuJyk7XHJcblxyXG4gICAgLy8gRXh0cmFjdCBhbmQgc2F2ZSB2ZXJzaW9uIG9mIGN1cnJlbnRseSB1c2VkIEhpZ2hjaGFydHNcclxuICAgIGNhY2hlLmhjVmVyc2lvbiA9IF9leHRyYWN0SGNWZXJzaW9uKGNhY2hlLnNvdXJjZXMpO1xyXG5cclxuICAgIC8vIFNhdmUgdGhlIGZldGNoZWQgbW9kdWxlcyBpbnRvIGNhY2hlcycgc291cmNlIEpTT05cclxuICAgIHdyaXRlRmlsZVN5bmMoc291cmNlUGF0aCwgY2FjaGUuc291cmNlcyk7XHJcblxyXG4gICAgLy8gUmV0dXJuIHRoZSBmZXRjaGVkIG1vZHVsZXNcclxuICAgIHJldHVybiBmZXRjaGVkTW9kdWxlcztcclxuICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgdGhyb3cgbmV3IEV4cG9ydEVycm9yKFxyXG4gICAgICAnW2NhY2hlXSBVbmFibGUgdG8gdXBkYXRlIHRoZSBsb2NhbCBIaWdoY2hhcnRzIGNhY2hlLicsXHJcbiAgICAgIDUwMFxyXG4gICAgKS5zZXRFcnJvcihlcnJvcik7XHJcbiAgfVxyXG59XHJcblxyXG4vKipcclxuICogRmV0Y2hlcyBhIHNpbmdsZSBzY3JpcHQgYW5kIHVwZGF0ZXMgdGhlIGBmZXRjaGVkTW9kdWxlc2AgYWNjb3JkaW5nbHkuXHJcbiAqXHJcbiAqIEBhc3luY1xyXG4gKiBAZnVuY3Rpb24gX2ZldGNoU2NyaXB0XHJcbiAqXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSBzY3JpcHQgLSBBIHBhdGggdG8gc2NyaXB0IHRvIGdldC5cclxuICogQHBhcmFtIHtPYmplY3R9IHJlcXVlc3RPcHRpb25zIC0gQWRkaXRpb25hbCByZXF1ZXN0cyBvcHRpb25zLlxyXG4gKiBAcGFyYW0ge09iamVjdH0gZmV0Y2hlZE1vZHVsZXMgLSBBbiBvYmplY3Qgd2hpY2ggdHJhY2tzIHdoaWNoIEhpZ2hjaGFydHNcclxuICogbW9kdWxlcyBoYXZlIGJlZW4gZmV0Y2hlZC5cclxuICogQHBhcmFtIHtib29sZWFufSBbc2hvdWxkVGhyb3dFcnJvcj1mYWxzZV0gLSBBIGZsYWcgdG8gaW5kaWNhdGUgaWYgdGhlIGVycm9yXHJcbiAqIHNob3VsZCBiZSB0aHJvd24uIFRoaXMgc2hvdWxkIGJlIHVzZWQgb25seSBmb3IgdGhlIGNvcmUgc2NyaXB0cy4gVGhlIGRlZmF1bHRcclxuICogdmFsdWUgaXMgYGZhbHNlYC5cclxuICpcclxuICogQHJldHVybnMge1Byb21pc2U8c3RyaW5nPn0gQSBQcm9taXNlIHRoYXQgcmVzb2x2ZXMgdG8gdGhlIHRleHQgcmVwcmVzZW50YXRpb25cclxuICogb2YgdGhlIGZldGNoZWQgc2NyaXB0LlxyXG4gKlxyXG4gKiBAdGhyb3dzIHtFeHBvcnRFcnJvcn0gVGhyb3dzIGFuIGBFeHBvcnRFcnJvcmAgaWYgdGhlcmUgaXMgYSBwcm9ibGVtXHJcbiAqIHdpdGggZmV0Y2hpbmcgdGhlIHNjcmlwdC5cclxuICovXHJcbmFzeW5jIGZ1bmN0aW9uIF9mZXRjaFNjcmlwdChcclxuICBzY3JpcHQsXHJcbiAgcmVxdWVzdE9wdGlvbnMsXHJcbiAgZmV0Y2hlZE1vZHVsZXMsXHJcbiAgc2hvdWxkVGhyb3dFcnJvciA9IGZhbHNlXHJcbikge1xyXG4gIC8vIEdldCByaWQgb2YgdGhlIC5qcyBmcm9tIHRoZSBjdXN0b20gc3RyaW5nc1xyXG4gIGlmIChzY3JpcHQuZW5kc1dpdGgoJy5qcycpKSB7XHJcbiAgICBzY3JpcHQgPSBzY3JpcHQuc3Vic3RyaW5nKDAsIHNjcmlwdC5sZW5ndGggLSAzKTtcclxuICB9XHJcbiAgbG9nKDQsIGBbY2FjaGVdIEZldGNoaW5nIHNjcmlwdCAtICR7c2NyaXB0fS5qc2ApO1xyXG5cclxuICAvLyBGZXRjaCB0aGUgc2NyaXB0XHJcbiAgY29uc3QgcmVzcG9uc2UgPSBhd2FpdCBnZXQoYCR7c2NyaXB0fS5qc2AsIHJlcXVlc3RPcHRpb25zKTtcclxuXHJcbiAgLy8gSWYgT0ssIHJldHVybiBpdHMgdGV4dCByZXByZXNlbnRhdGlvblxyXG4gIGlmIChyZXNwb25zZS5zdGF0dXNDb2RlID09PSAyMDAgJiYgdHlwZW9mIHJlc3BvbnNlLnRleHQgPT0gJ3N0cmluZycpIHtcclxuICAgIGlmIChmZXRjaGVkTW9kdWxlcykge1xyXG4gICAgICBjb25zdCBtb2R1bGVOYW1lID0gX2V4dHJhY3RNb2R1bGVOYW1lKHNjcmlwdCk7XHJcbiAgICAgIGZldGNoZWRNb2R1bGVzW21vZHVsZU5hbWVdID0gMTtcclxuICAgIH1cclxuICAgIHJldHVybiByZXNwb25zZS50ZXh0O1xyXG4gIH1cclxuXHJcbiAgLy8gQmFzZWQgb24gdGhlIGBzaG91bGRUaHJvd0Vycm9yYCBmbGFnLCBkZWNpZGUgaG93IHRvIHNlcnZlIGVycm9yIG1lc3NhZ2VcclxuICBpZiAoc2hvdWxkVGhyb3dFcnJvcikge1xyXG4gICAgdGhyb3cgbmV3IEV4cG9ydEVycm9yKFxyXG4gICAgICBgW2NhY2hlXSBDb3VsZCBub3QgZmV0Y2ggdGhlICR7c2NyaXB0fS5qcy4gVGhlIHNjcmlwdCBtaWdodCBub3QgZXhpc3QgaW4gdGhlIHJlcXVlc3RlZCB2ZXJzaW9uIChzdGF0dXMgY29kZTogJHtyZXNwb25zZS5zdGF0dXNDb2RlfSkuYCxcclxuICAgICAgNDA0XHJcbiAgICApLnNldEVycm9yKHJlc3BvbnNlKTtcclxuICB9IGVsc2Uge1xyXG4gICAgbG9nKFxyXG4gICAgICAyLFxyXG4gICAgICBgW2NhY2hlXSBDb3VsZCBub3QgZmV0Y2ggdGhlICR7c2NyaXB0fS5qcy4gVGhlIHNjcmlwdCBtaWdodCBub3QgZXhpc3QgaW4gdGhlIHJlcXVlc3RlZCB2ZXJzaW9uLmBcclxuICAgICk7XHJcbiAgfVxyXG59XHJcblxyXG4vKipcclxuICogQ29uZmlndXJlcyBhIHByb3h5IGFnZW50IGZvciBvdXRnb2luZyBIVFRQIHJlcXVlc3RzIGJhc2VkIG9uIHRoZSBwcm92aWRlZFxyXG4gKiBgc2VydmVyLnByb3h5YCBvcHRpb25zLiBJZiBhIHZhbGlkIGBob3N0YCBhbmQgYHBvcnRgIGFyZSBzcGVjaWZpZWQsIGl0IHRyaWVzXHJcbiAqIHRvIGNyZWF0ZSBhbiBgSHR0cHNQcm94eUFnZW50YC4gSWYgdGhlIGNyZWF0aW9uIGZhaWxzLCBhbiBgRXhwb3J0RXJyb3JgXHJcbiAqIGlzIHRocm93bi4gSWYgbm8gcHJveHkgaXMgY29uZmlndXJlZCwgYW4gZW1wdHkgb2JqZWN0IGlzIHJldHVybmVkLlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gX2NvbmZpZ3VyZVJlcXVlc3RcclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IHNlcnZlclByb3h5T3B0aW9ucy0gVGhlIGNvbmZpZ3VyYXRpb24gb2JqZWN0IGNvbnRhaW5pbmdcclxuICogYHNlcnZlci5wcm94eWAgb3B0aW9ucy5cclxuICpcclxuICogQHJldHVybnMge09iamVjdH0gVGhlIHJlcXVlc3Qgb3B0aW9ucywgaW5jbHVkaW5nIHRoZSBwcm94eSBhZ2VudCBpZiBjcmVhdGVkLFxyXG4gKiBvciBhbiBlbXB0eSBvYmplY3QgaWYgbm8gcHJveHkgY29uZmlndXJhdGlvbiBpcyBwcm92aWRlZC5cclxuICpcclxuICogQHRocm93cyB7RXhwb3J0RXJyb3J9IFRocm93cyBhbiBgRXhwb3J0RXJyb3JgIGlmIHRoZSBwcm94eSBhZ2VudCBjcmVhdGlvblxyXG4gKiBmYWlscy5cclxuICovXHJcbmZ1bmN0aW9uIF9jb25maWd1cmVSZXF1ZXN0KHNlcnZlclByb3h5T3B0aW9ucykge1xyXG4gIC8vIEdldCB0aGUgYGhvc3RgIGFuZCBgcG9ydGAgb2YgdGhlIHByb3h5XHJcbiAgY29uc3QgcHJveHlIb3N0ID0gc2VydmVyUHJveHlPcHRpb25zLmhvc3Q7XHJcbiAgY29uc3QgcHJveHlQb3J0ID0gc2VydmVyUHJveHlPcHRpb25zLnBvcnQ7XHJcblxyXG4gIC8vIFRyeSB0byBjcmVhdGUgYSBwcm94eSBhZ2VudFxyXG4gIGlmIChwcm94eUhvc3QgJiYgcHJveHlQb3J0KSB7XHJcbiAgICB0cnkge1xyXG4gICAgICAvLyBDcmVhdGUgdGhlIGFnZW50XHJcbiAgICAgIGNvbnN0IHByb3h5QWdlbnQgPSBuZXcgSHR0cHNQcm94eUFnZW50KHtcclxuICAgICAgICBob3N0OiBwcm94eUhvc3QsXHJcbiAgICAgICAgcG9ydDogcHJveHlQb3J0XHJcbiAgICAgIH0pO1xyXG5cclxuICAgICAgLy8gQWRkIHRoZSBhZ2VudCB0byB0aGUgcmVxdWVzdCdzIG9wdGlvbnNcclxuICAgICAgcmV0dXJuIHtcclxuICAgICAgICBhZ2VudDogcHJveHlBZ2VudCxcclxuICAgICAgICB0aW1lb3V0OiBzZXJ2ZXJQcm94eU9wdGlvbnMudGltZW91dFxyXG4gICAgICB9O1xyXG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICAgdGhyb3cgbmV3IEV4cG9ydEVycm9yKFxyXG4gICAgICAgICdbY2FjaGVdIENvdWxkIG5vdCBjcmVhdGUgYSBQcm94eSBBZ2VudC4nLFxyXG4gICAgICAgIDUwMFxyXG4gICAgICApLnNldEVycm9yKGVycm9yKTtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIC8vIFJldHVybiBhbiBlbXB0eSBvYmplY3Qgd2hlbiBubyBwcm94eSBhZ2VudCBpcyBjcmVhdGVkXHJcbiAgcmV0dXJuIHt9O1xyXG59XHJcblxyXG4vKipcclxuICogRXh0cmFjdHMgSGlnaGNoYXJ0cyB2ZXJzaW9uIGZyb20gdGhlIGNhY2hlJ3Mgc291cmNlcyBzdHJpbmcuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBfZXh0cmFjdEhjVmVyc2lvblxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gY2FjaGVTb3VyY2VzIC0gVGhlIGNhY2hlIHNvdXJjZXMgb2JqZWN0LlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7c3RyaW5nfSBUaGUgZXh0cmFjdGVkIEhpZ2hjaGFydHMgdmVyc2lvbi5cclxuICovXHJcbmZ1bmN0aW9uIF9leHRyYWN0SGNWZXJzaW9uKGNhY2hlU291cmNlcykge1xyXG4gIHJldHVybiBjYWNoZVNvdXJjZXNcclxuICAgIC5zdWJzdHJpbmcoMCwgY2FjaGVTb3VyY2VzLmluZGV4T2YoJyovJykpXHJcbiAgICAucmVwbGFjZSgnLyonLCAnJylcclxuICAgIC5yZXBsYWNlKCcqLycsICcnKVxyXG4gICAgLnJlcGxhY2UoL1xcbi9nLCAnJylcclxuICAgIC50cmltKCk7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBFeHRyYWN0cyB0aGUgSGlnaGNoYXJ0cyBtb2R1bGUgbmFtZSBiYXNlZCBvbiB0aGUgYHNjcmlwdFBhdGhgIHByb3BlcnR5LlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gX2V4dHJhY3RNb2R1bGVOYW1lXHJcbiAqXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSBzY3JpcHRQYXRoIC0gVGhlIHBhdGggb2YgdGhlIHNjcmlwdCBmcm9tIHdoaWNoIHRoZSBtb2R1bGVcclxuICogbmFtZSB3aWxsIGJlIGV4dHJhY3RlZC5cclxuICpcclxuICogQHJldHVybnMge3N0cmluZ30gVGhlIGV4dHJhY3RlZCBtb2R1bGUgbmFtZS5cclxuICovXHJcbmZ1bmN0aW9uIF9leHRyYWN0TW9kdWxlTmFtZShzY3JpcHRQYXRoKSB7XHJcbiAgcmV0dXJuIHNjcmlwdFBhdGgucmVwbGFjZShcclxuICAgIC8oLiopXFwvfCguKiltb2R1bGVzXFwvfHN0b2NrXFwvKC4qKWluZGljYXRvcnNcXC98bWFwc1xcLyguKiltb2R1bGVzXFwvL2dpLFxyXG4gICAgJydcclxuICApO1xyXG59XHJcblxyXG5leHBvcnQgZGVmYXVsdCB7XHJcbiAgY2hlY2tDYWNoZSxcclxuICBnZXRIY1ZlcnNpb24sXHJcbiAgdXBkYXRlSGNWZXJzaW9uLFxyXG4gIGdldENhY2hlLFxyXG4gIGdldENhY2hlUGF0aFxyXG59O1xyXG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxyXG5cclxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXHJcblxyXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNSwgSGlnaHNvZnRcclxuXHJcbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cclxuXHJcbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxyXG5cclxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxyXG5cclxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cclxuXHJcbi8qKlxyXG4gKiBAb3ZlcnZpZXcgUHJvdmlkZXMgbWV0aG9kcyBmb3IgaW5pdGlhbGl6aW5nIEhpZ2hjaGFydHMgd2l0aCBjdXN0b21pemVkXHJcbiAqIGFuaW1hdGlvbiBzZXR0aW5ncyBhbmQgdHJpZ2dlcmluZyB0aGUgY3JlYXRpb24gb2YgSGlnaGNoYXJ0cyBjaGFydHMgd2l0aFxyXG4gKiBleHBvcnQtc3BlY2lmaWMgY29uZmlndXJhdGlvbnMgaW4gdGhlIHBhZ2UgY29udGV4dC4gU3VwcG9ydHMgZHluYW1pYyBvcHRpb25cclxuICogbWVyZ2luZywgY3VzdG9tIGxvZ2ljIGluamVjdGlvbiwgYW5kIGNvbnRyb2wgb3ZlciByZW5kZXJpbmcgYmVoYXZpb3JzLiBVc2VkXHJcbiAqIGJ5IHRoZSBQdXBwZXRlZXIgcGFnZS5cclxuICovXHJcblxyXG4vKiBlc2xpbnQtZGlzYWJsZSBuby11bmRlZiAqL1xyXG5cclxuLyoqXHJcbiAqIFNldHRpbmcgdGhlIGBIaWdoY2hhcnRzLmFuaW1PYmplY3RgIGZ1bmN0aW9uLiBDYWxsZWQgd2hlbiBpbml0aW5nIHRoZSBwYWdlLlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gc2V0dXBIaWdoY2hhcnRzXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gc2V0dXBIaWdoY2hhcnRzKCkge1xyXG4gIEhpZ2hjaGFydHMuYW5pbU9iamVjdCA9IGZ1bmN0aW9uICgpIHtcclxuICAgIHJldHVybiB7IGR1cmF0aW9uOiAwIH07XHJcbiAgfTtcclxufVxyXG5cclxuLyoqXHJcbiAqIENyZWF0ZXMgdGhlIGFjdHVhbCBIaWdoY2hhcnRzIGNoYXJ0IG9uIGEgcGFnZS5cclxuICpcclxuICogQGFzeW5jXHJcbiAqIEBmdW5jdGlvbiBjcmVhdGVDaGFydFxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gZXhwb3J0T3B0aW9ucyAtIFRoZSBjb25maWd1cmF0aW9uIG9iamVjdCBjb250YWluaW5nIGBleHBvcnRgXHJcbiAqIG9wdGlvbnMuXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBjdXN0b21Mb2dpY09wdGlvbnMgLSBUaGUgY29uZmlndXJhdGlvbiBvYmplY3QgY29udGFpbmluZ1xyXG4gKiBgY3VzdG9tTG9naWNgIG9wdGlvbnMuXHJcbiAqXHJcbiAqL1xyXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gY3JlYXRlQ2hhcnQoZXhwb3J0T3B0aW9ucywgY3VzdG9tTG9naWNPcHRpb25zKSB7XHJcbiAgLy8gR2V0IHJlcXVpcmVkIGZ1bmN0aW9uc1xyXG4gIGNvbnN0IHsgZ2V0T3B0aW9ucywgc2V0T3B0aW9ucywgbWVyZ2UsIHdyYXAgfSA9IEhpZ2hjaGFydHM7XHJcblxyXG4gIC8vIENyZWF0ZSBhIHNlcGFyYXRlIG9iamVjdCBmb3IgYSBwb3RlbnRpYWwgYHNldE9wdGlvbnNgIHVzYWdlcyBpbiBvcmRlclxyXG4gIC8vIHRvIHByZXZlbnQgZnJvbSBwb2xsdXRpbmcgb3RoZXIgZXhwb3J0cyB0aGF0IGNhbiBoYXBwZW4gb24gdGhlIHNhbWUgcGFnZVxyXG4gIEhpZ2hjaGFydHMuc2V0T3B0aW9uc09iaiA9IG1lcmdlKGZhbHNlLCB7fSwgZ2V0T3B0aW9ucygpKTtcclxuXHJcbiAgLy8gTk9URTogSXMgdGhpcyB1c2VkIGZvciBhbnl0aGluZyB1c2VmdWw/XHJcbiAgd2luZG93LmlzUmVuZGVyQ29tcGxldGUgPSBmYWxzZTtcclxuICB3cmFwKEhpZ2hjaGFydHMuQ2hhcnQucHJvdG90eXBlLCAnaW5pdCcsIGZ1bmN0aW9uIChwcm9jZWVkLCB1c2VyT3B0aW9ucywgY2IpIHtcclxuICAgIC8vIE92ZXJyaWRlIHRoZSBgdXNlck9wdGlvbnNgIHdpdGggaW1hZ2UgZnJpZW5kbHkgb3B0aW9uc1xyXG4gICAgdXNlck9wdGlvbnMgPSBtZXJnZSh1c2VyT3B0aW9ucywge1xyXG4gICAgICBleHBvcnRpbmc6IHtcclxuICAgICAgICBlbmFibGVkOiBmYWxzZVxyXG4gICAgICB9LFxyXG4gICAgICBwbG90T3B0aW9uczoge1xyXG4gICAgICAgIHNlcmllczoge1xyXG4gICAgICAgICAgbGFiZWw6IHtcclxuICAgICAgICAgICAgZW5hYmxlZDogZmFsc2VcclxuICAgICAgICAgIH1cclxuICAgICAgICB9XHJcbiAgICAgIH0sXHJcbiAgICAgIC8qIEV4cGVjdHMgdG9vbHRpcCBpbiB0aGUgYHVzZXJPcHRpb25zYCB3aGVuIGBmb3JFeHBvcnRgIGlzIHRydWUuXHJcbiAgICAgICAgaHR0cHM6Ly9naXRodWIuY29tL2hpZ2hjaGFydHMvaGlnaGNoYXJ0cy9ibG9iLzNhZDQzMGEzNTNiODA1NmI5ZTc2NGFhNGU1Y2Q2ODI4YWE0NzlkYjIvanMvcGFydHMvQ2hhcnQuanMjTDI0MVxyXG4gICAgICAgICovXHJcbiAgICAgIHRvb2x0aXA6IHt9XHJcbiAgICB9KTtcclxuXHJcbiAgICAodXNlck9wdGlvbnMuc2VyaWVzIHx8IFtdKS5mb3JFYWNoKGZ1bmN0aW9uIChzZXJpZXMpIHtcclxuICAgICAgc2VyaWVzLmFuaW1hdGlvbiA9IGZhbHNlO1xyXG4gICAgfSk7XHJcblxyXG4gICAgLy8gQWRkIGZsYWcgdG8ga25vdyBpZiBjaGFydCByZW5kZXIgaGFzIGJlZW4gY2FsbGVkLlxyXG4gICAgaWYgKCF3aW5kb3cub25IaWdoY2hhcnRzUmVuZGVyKSB7XHJcbiAgICAgIHdpbmRvdy5vbkhpZ2hjaGFydHNSZW5kZXIgPSBIaWdoY2hhcnRzLmFkZEV2ZW50KHRoaXMsICdyZW5kZXInLCAoKSA9PiB7XHJcbiAgICAgICAgd2luZG93LmlzUmVuZGVyQ29tcGxldGUgPSB0cnVlO1xyXG4gICAgICB9KTtcclxuICAgIH1cclxuXHJcbiAgICBwcm9jZWVkLmFwcGx5KHRoaXMsIFt1c2VyT3B0aW9ucywgY2JdKTtcclxuICB9KTtcclxuXHJcbiAgd3JhcChIaWdoY2hhcnRzLlNlcmllcy5wcm90b3R5cGUsICdpbml0JywgZnVuY3Rpb24gKHByb2NlZWQsIGNoYXJ0LCBvcHRpb25zKSB7XHJcbiAgICBwcm9jZWVkLmFwcGx5KHRoaXMsIFtjaGFydCwgb3B0aW9uc10pO1xyXG4gIH0pO1xyXG5cclxuICAvLyBTb21lIG1hbmRhdG9yeSBhZGRpdGlvbmFsIGBjaGFydGAgYW5kIGBleHBvcnRpbmdgIG9wdGlvbnNcclxuICBjb25zdCBhZGRpdGlvbmFsT3B0aW9ucyA9IHtcclxuICAgIGNoYXJ0OiB7XHJcbiAgICAgIC8vIEJ5IGRlZmF1bHQgYW5pbWF0aW9uIGlzIGRpc2FibGVkXHJcbiAgICAgIGFuaW1hdGlvbjogZmFsc2UsXHJcbiAgICAgIC8vIEdldCB0aGUgcmlnaHQgc2l6ZSB2YWx1ZXNcclxuICAgICAgaGVpZ2h0OiBleHBvcnRPcHRpb25zLmhlaWdodCxcclxuICAgICAgd2lkdGg6IGV4cG9ydE9wdGlvbnMud2lkdGhcclxuICAgIH0sXHJcbiAgICBleHBvcnRpbmc6IHtcclxuICAgICAgLy8gTm8gbmVlZCBmb3IgdGhlIGV4cG9ydGluZyBidXR0b25cclxuICAgICAgZW5hYmxlZDogZmFsc2VcclxuICAgIH1cclxuICB9O1xyXG5cclxuICAvLyBHZXQgdGhlIGlucHV0IHRvIGV4cG9ydCBmcm9tIHRoZSBgaW5zdHJgIG9wdGlvblxyXG4gIGNvbnN0IHVzZXJPcHRpb25zID0gbmV3IEZ1bmN0aW9uKGByZXR1cm4gJHtleHBvcnRPcHRpb25zLmluc3RyfWApKCk7XHJcblxyXG4gIC8vIEdldCB0aGUgYHRoZW1lT3B0aW9uc2Agb3B0aW9uXHJcbiAgY29uc3QgdGhlbWVPcHRpb25zID0gbmV3IEZ1bmN0aW9uKGByZXR1cm4gJHtleHBvcnRPcHRpb25zLnRoZW1lT3B0aW9uc31gKSgpO1xyXG5cclxuICAvLyBNZXJnZSB0aGUgZm9sbG93aW5nIG9wdGlvbnMgb2JqZWN0cyB0byBjcmVhdGUgZmluYWwgb3B0aW9uc1xyXG4gIGNvbnN0IGZpbmFsT3B0aW9ucyA9IG1lcmdlKFxyXG4gICAgZmFsc2UsXHJcbiAgICB0aGVtZU9wdGlvbnMsXHJcbiAgICB1c2VyT3B0aW9ucyxcclxuICAgIC8vIFBsYWNlZCBpdCBoZXJlIGluc3RlYWQgaW4gdGhlIGluaXQgYmVjYXVzZSBvZiB0aGUgc2l6ZSBpc3N1ZXNcclxuICAgIGFkZGl0aW9uYWxPcHRpb25zXHJcbiAgKTtcclxuXHJcbiAgLy8gUHJlcGFyZSB0aGUgYGNhbGxiYWNrYCBvcHRpb25cclxuICBjb25zdCBmaW5hbENhbGxiYWNrID0gY3VzdG9tTG9naWNPcHRpb25zLmNhbGxiYWNrXHJcbiAgICA/IG5ldyBGdW5jdGlvbihgcmV0dXJuICR7Y3VzdG9tTG9naWNPcHRpb25zLmNhbGxiYWNrfWApKClcclxuICAgIDogbnVsbDtcclxuXHJcbiAgLy8gVHJpZ2dlciB0aGUgYGN1c3RvbUNvZGVgIG9wdGlvblxyXG4gIGlmIChjdXN0b21Mb2dpY09wdGlvbnMuY3VzdG9tQ29kZSkge1xyXG4gICAgbmV3IEZ1bmN0aW9uKCdvcHRpb25zJywgY3VzdG9tTG9naWNPcHRpb25zLmN1c3RvbUNvZGUpKHVzZXJPcHRpb25zKTtcclxuICB9XHJcblxyXG4gIC8vIEdldCB0aGUgYGdsb2JhbE9wdGlvbnNgIG9wdGlvblxyXG4gIGNvbnN0IGdsb2JhbE9wdGlvbnMgPSBuZXcgRnVuY3Rpb24oYHJldHVybiAke2V4cG9ydE9wdGlvbnMuZ2xvYmFsT3B0aW9uc31gKSgpO1xyXG5cclxuICAvLyBTZXQgdGhlIGdsb2JhbCBvcHRpb25zIGlmIGV4aXN0XHJcbiAgaWYgKGdsb2JhbE9wdGlvbnMpIHtcclxuICAgIHNldE9wdGlvbnMoZ2xvYmFsT3B0aW9ucyk7XHJcbiAgfVxyXG5cclxuICAvLyBDYWxsIHRoZSBjaGFydCBjcmVhdGlvblxyXG4gIEhpZ2hjaGFydHNbZXhwb3J0T3B0aW9ucy5jb25zdHJdKCdjb250YWluZXInLCBmaW5hbE9wdGlvbnMsIGZpbmFsQ2FsbGJhY2spO1xyXG5cclxuICAvLyBHZXQgYWxsIGltYWdlcyBmcm9tIHdpdGhpbiB0aGUgY2hhcnRcclxuICBjb25zdCBpbWFnZXMgPSBBcnJheS5mcm9tKFxyXG4gICAgZG9jdW1lbnQucXVlcnlTZWxlY3RvckFsbCgnLmhpZ2hjaGFydHMtY29udGFpbmVyIGltYWdlJylcclxuICApO1xyXG5cclxuICAvLyBXYWl0IGZvciBhbGwgaW1hZ2VzIGZvciAyIHNlY29uZHNcclxuICBhd2FpdCBQcm9taXNlLnJhY2UoW1xyXG4gICAgUHJvbWlzZS5hbGwoXHJcbiAgICAgIGltYWdlcy5tYXAoKGltYWdlKSA9PlxyXG4gICAgICAgIGltYWdlLmNvbXBsZXRlICYmIGltYWdlLm5hdHVyYWxIZWlnaHQgIT09IDBcclxuICAgICAgICAgID8gUHJvbWlzZS5yZXNvbHZlKClcclxuICAgICAgICAgIDogbmV3IFByb21pc2UoKHJlc29sdmUpID0+XHJcbiAgICAgICAgICAgICAgaW1hZ2UuYWRkRXZlbnRMaXN0ZW5lcignbG9hZCcsIHJlc29sdmUsIHsgb25jZTogdHJ1ZSB9KVxyXG4gICAgICAgICAgICApXHJcbiAgICAgIClcclxuICAgICksXHJcbiAgICAvLyBQcm9jZWVkIGZ1cnRoZXIgZXZlbiBpZiBpbWFnZXMgZGlkIG5vdCBsb2FkXHJcbiAgICBuZXcgUHJvbWlzZSgocmVzb2x2ZSkgPT4gc2V0VGltZW91dChyZXNvbHZlLCAyMDAwKSlcclxuICBdKTtcclxuXHJcbiAgLy8gR2V0IHRoZSBjdXJyZW50IGdsb2JhbCBvcHRpb25zXHJcbiAgY29uc3QgZGVmYXVsdE9wdGlvbnMgPSBnZXRPcHRpb25zKCk7XHJcblxyXG4gIC8vIENsZWFyIGl0IGp1c3QgaW4gY2FzZSAoZS5nLiB0aGUgYHNldE9wdGlvbnNgIHdhcyB1c2VkIGluIHRoZSBgY3VzdG9tQ29kZWApXHJcbiAgZm9yIChjb25zdCBwcm9wIGluIGRlZmF1bHRPcHRpb25zKSB7XHJcbiAgICBpZiAodHlwZW9mIGRlZmF1bHRPcHRpb25zW3Byb3BdICE9PSAnZnVuY3Rpb24nKSB7XHJcbiAgICAgIGRlbGV0ZSBkZWZhdWx0T3B0aW9uc1twcm9wXTtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIC8vIFNldCB0aGUgZGVmYXVsdCBvcHRpb25zIGJhY2tcclxuICBzZXRPcHRpb25zKEhpZ2hjaGFydHMuc2V0T3B0aW9uc09iaik7XHJcblxyXG4gIC8vIEVtcHR5IHRoZSBjdXN0b20gZ2xvYmFsIG9wdGlvbnMgb2JqZWN0XHJcbiAgSGlnaGNoYXJ0cy5zZXRPcHRpb25zT2JqID0ge307XHJcbn1cclxuXHJcbmV4cG9ydCBkZWZhdWx0IHtcclxuICBzZXR1cEhpZ2hjaGFydHMsXHJcbiAgY3JlYXRlQ2hhcnRcclxufTtcclxuIiwiLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcclxuXHJcbkhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlclxyXG5cclxuQ29weXJpZ2h0IChjKSAyMDE2LTIwMjUsIEhpZ2hzb2Z0XHJcblxyXG5MaWNlbmNlZCB1bmRlciB0aGUgTUlUIGxpY2VuY2UuXHJcblxyXG5BZGRpdGlvbmFsbHkgYSB2YWxpZCBIaWdoY2hhcnRzIGxpY2Vuc2UgaXMgcmVxdWlyZWQgZm9yIHVzZS5cclxuXHJcblNlZSBMSUNFTlNFIGZpbGUgaW4gcm9vdCBmb3IgZGV0YWlscy5cclxuXHJcbioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXHJcblxyXG4vKipcclxuICogQG92ZXJ2aWV3IFRoaXMgbW9kdWxlIHByb3ZpZGVzIGZ1bmN0aW9ucyBmb3IgbWFuYWdpbmcgUHVwcGV0ZWVyIGJyb3dzZXJcclxuICogaW5zdGFuY2UsIGNyZWF0aW5nIGFuZCBjbGVhcmluZyBwYWdlcywgaW5qZWN0aW5nIGN1c3RvbSBKUyBhbmQgQ1NTIHJlc291cmNlcyxcclxuICogYW5kIHNldHRpbmcgdXAgSGlnaGNoYXJ0cyBmb3Igc2VydmVyLXNpZGUgcmVuZGVyaW5nLiBUaGUgbW9kdWxlIGVuc3VyZXNcclxuICogdGhhdCB0aGUgYnJvd3NlciBhbmQgcGFnZXMgYXJlIGNvcnJlY3RseSBtYW5hZ2VkIGFuZCBjYW4gaGFuZGxlIGZhaWx1cmVzXHJcbiAqIGR1cmluZyBvcGVyYXRpb25zIGxpa2UgbGF1bmNoaW5nIHRoZSBicm93c2VyIG9yIGNyZWF0aW5nIG5ldyBwYWdlcy5cclxuICovXHJcblxyXG5pbXBvcnQgeyByZWFkRmlsZVN5bmMgfSBmcm9tICdmcyc7XHJcbmltcG9ydCB7IGpvaW4gfSBmcm9tICdwYXRoJztcclxuXHJcbmltcG9ydCBwdXBwZXRlZXIgZnJvbSAncHVwcGV0ZWVyJztcclxuXHJcbmltcG9ydCB7IGdldENhY2hlUGF0aCB9IGZyb20gJy4vY2FjaGUuanMnO1xyXG5pbXBvcnQgeyBnZXRPcHRpb25zIH0gZnJvbSAnLi9jb25maWcuanMnO1xyXG5pbXBvcnQgeyBzZXR1cEhpZ2hjaGFydHMgfSBmcm9tICcuL2hpZ2hjaGFydHMuanMnO1xyXG5pbXBvcnQgeyBsb2csIGxvZ1dpdGhTdGFjayB9IGZyb20gJy4vbG9nZ2VyLmpzJztcclxuaW1wb3J0IHsgX19kaXJuYW1lLCBnZXRBYnNvbHV0ZVBhdGggfSBmcm9tICcuL3V0aWxzLmpzJztcclxuXHJcbmltcG9ydCBFeHBvcnRFcnJvciBmcm9tICcuL2Vycm9ycy9FeHBvcnRFcnJvci5qcyc7XHJcblxyXG4vLyBHZXQgdGhlIHRlbXBsYXRlIGZvciBwYWdlc1xyXG5jb25zdCBwYWdlVGVtcGxhdGUgPSByZWFkRmlsZVN5bmMoXHJcbiAgam9pbihfX2Rpcm5hbWUsICd0ZW1wbGF0ZXMnLCAndGVtcGxhdGUuaHRtbCcpLFxyXG4gICd1dGY4J1xyXG4pO1xyXG5cclxuLy8gVG8gc2F2ZSB0aGUgYnJvd3NlclxyXG5sZXQgYnJvd3NlciA9IG51bGw7XHJcblxyXG4vKipcclxuICogUmV0cmlldmVzIHRoZSBleGlzdGluZyBQdXBwZXRlZXIgYnJvd3NlciBpbnN0YW5jZS5cclxuICpcclxuICogQGZ1bmN0aW9uIGdldEJyb3dzZXJcclxuICpcclxuICogQHJldHVybnMge09iamVjdH0gVGhlIFB1cHBldGVlciBicm93c2VyIGluc3RhbmNlLlxyXG4gKlxyXG4gKiBAdGhyb3dzIHtFeHBvcnRFcnJvcn0gVGhyb3dzIGFuIGBFeHBvcnRFcnJvcmAgaWYgbm8gdmFsaWQgYnJvd3NlclxyXG4gKiBoYXMgYmVlbiBjcmVhdGVkLlxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIGdldEJyb3dzZXIoKSB7XHJcbiAgaWYgKCFicm93c2VyKSB7XHJcbiAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoJ1ticm93c2VyXSBObyB2YWxpZCBicm93c2VyIGhhcyBiZWVuIGNyZWF0ZWQuJywgNTAwKTtcclxuICB9XHJcbiAgcmV0dXJuIGJyb3dzZXI7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBDcmVhdGVzIGEgUHVwcGV0ZWVyIGJyb3dzZXIgaW5zdGFuY2Ugd2l0aCB0aGUgc3BlY2lmaWVkIGFyZ3VtZW50cy5cclxuICpcclxuICogQGFzeW5jXHJcbiAqIEBmdW5jdGlvbiBjcmVhdGVCcm93c2VyXHJcbiAqXHJcbiAqIEBwYXJhbSB7QXJyYXk8c3RyaW5nPn0gcHVwcGV0ZWVyQXJncyAtIEFkZGl0aW9uYWwgYXJndW1lbnRzIGZvciBQdXBwZXRlZXJcclxuICogYnJvd3NlcidzIGxhdW5jaC5cclxuICpcclxuICogQHJldHVybnMge1Byb21pc2U8T2JqZWN0Pn0gQSBQcm9taXNlIHRoYXQgcmVzb2x2ZXMgdG8gdGhlIGNyZWF0ZWQgUHVwcGV0ZWVyXHJcbiAqIGJyb3dzZXIgaW5zdGFuY2UuXHJcbiAqXHJcbiAqIEB0aHJvd3Mge0V4cG9ydEVycm9yfSBUaHJvd3MgYW4gYEV4cG9ydEVycm9yYCBpZiBtYXggcmV0cmllcyB0byBvcGVuXHJcbiAqIGEgYnJvd3NlciBpbnN0YW5jZSBhcmUgcmVhY2hlZCwgb3IgaWYgbm8gYnJvd3NlciBpbnN0YW5jZSBpcyBmb3VuZCBhZnRlclxyXG4gKiByZXRyaWVzLlxyXG4gKi9cclxuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIGNyZWF0ZUJyb3dzZXIocHVwcGV0ZWVyQXJncykge1xyXG4gIC8vIEdldCBgZGVidWdgIGFuZCBgb3RoZXJgIG9wdGlvbnNcclxuICBjb25zdCB7IGRlYnVnLCBvdGhlciB9ID0gZ2V0T3B0aW9ucygpO1xyXG5cclxuICAvLyBHZXQgdGhlIGBkZWJ1Z2Agb3B0aW9uc1xyXG4gIGNvbnN0IHsgZW5hYmxlOiBlbmFibGVkRGVidWcsIC4uLmRlYnVnT3B0aW9ucyB9ID0gZGVidWc7XHJcblxyXG4gIC8vIExhdW5jaCBvcHRpb25zIGZvciB0aGUgYnJvd3NlciBpbnN0YW5jZVxyXG4gIGNvbnN0IGxhdW5jaE9wdGlvbnMgPSB7XHJcbiAgICBoZWFkbGVzczogb3RoZXIuYnJvd3NlclNoZWxsTW9kZSA/ICdzaGVsbCcgOiB0cnVlLFxyXG4gICAgdXNlckRhdGFEaXI6ICd0bXAnLFxyXG4gICAgYXJnczogcHVwcGV0ZWVyQXJncyB8fCBbXSxcclxuICAgIGhhbmRsZVNJR0lOVDogZmFsc2UsXHJcbiAgICBoYW5kbGVTSUdURVJNOiBmYWxzZSxcclxuICAgIGhhbmRsZVNJR0hVUDogZmFsc2UsXHJcbiAgICB3YWl0Rm9ySW5pdGlhbFBhZ2U6IGZhbHNlLFxyXG4gICAgZGVmYXVsdFZpZXdwb3J0OiBudWxsLFxyXG4gICAgLi4uKGVuYWJsZWREZWJ1ZyAmJiBkZWJ1Z09wdGlvbnMpXHJcbiAgfTtcclxuXHJcbiAgLy8gQ3JlYXRlIGEgYnJvd3NlclxyXG4gIGlmICghYnJvd3Nlcikge1xyXG4gICAgLy8gQSBjb3VudGVyIGZvciB0aGUgYnJvd3NlcidzIGxhdW5jaCByZXRyaWVzXHJcbiAgICBsZXQgdHJ5Q291bnQgPSAwO1xyXG4gICAgY29uc3Qgb3BlbkJyb3dzZXIgPSBhc3luYyAoKSA9PiB7XHJcbiAgICAgIHRyeSB7XHJcbiAgICAgICAgbG9nKFxyXG4gICAgICAgICAgMyxcclxuICAgICAgICAgIGBbYnJvd3Nlcl0gQXR0ZW1wdGluZyB0byBsYXVuY2ggYW5kIGdldCBhIGJyb3dzZXIgaW5zdGFuY2UgKHRyeSAkeysrdHJ5Q291bnR9KS5gXHJcbiAgICAgICAgKTtcclxuXHJcbiAgICAgICAgLy8gTGF1bmNoIHRoZSBicm93c2VyXHJcbiAgICAgICAgYnJvd3NlciA9IGF3YWl0IHB1cHBldGVlci5sYXVuY2gobGF1bmNoT3B0aW9ucyk7XHJcbiAgICAgIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICAgICAgbG9nV2l0aFN0YWNrKFxyXG4gICAgICAgICAgMSxcclxuICAgICAgICAgIGVycm9yLFxyXG4gICAgICAgICAgJ1ticm93c2VyXSBGYWlsZWQgdG8gbGF1bmNoIGEgYnJvd3NlciBpbnN0YW5jZS4nXHJcbiAgICAgICAgKTtcclxuXHJcbiAgICAgICAgLy8gUmV0cnkgdG8gbGF1bmNoIGJyb3dzZXIgdW50aWwgcmVhY2hpbmcgbWF4IGF0dGVtcHRzXHJcbiAgICAgICAgaWYgKHRyeUNvdW50IDwgMjUpIHtcclxuICAgICAgICAgIGxvZygzLCBgW2Jyb3dzZXJdIFJldHJ5IHRvIG9wZW4gYSBicm93c2VyICgke3RyeUNvdW50fSBvdXQgb2YgMjUpLmApO1xyXG5cclxuICAgICAgICAgIC8vIFdhaXQgZm9yIGEgNCBzZWNvbmRzIGJlZm9yZSB0cnlpbmcgYWdhaW5cclxuICAgICAgICAgIGF3YWl0IG5ldyBQcm9taXNlKChyZXNwb25zZSkgPT4gc2V0VGltZW91dChyZXNwb25zZSwgNDAwMCkpO1xyXG4gICAgICAgICAgYXdhaXQgb3BlbkJyb3dzZXIoKTtcclxuICAgICAgICB9IGVsc2Uge1xyXG4gICAgICAgICAgdGhyb3cgZXJyb3I7XHJcbiAgICAgICAgfVxyXG4gICAgICB9XHJcbiAgICB9O1xyXG5cclxuICAgIHRyeSB7XHJcbiAgICAgIC8vIFRyeSB0byBvcGVuIGEgYnJvd3NlclxyXG4gICAgICBhd2FpdCBvcGVuQnJvd3NlcigpO1xyXG5cclxuICAgICAgLy8gU2hlbGwgbW9kZSBpbmZvcm1cclxuICAgICAgaWYgKGxhdW5jaE9wdGlvbnMuaGVhZGxlc3MgPT09ICdzaGVsbCcpIHtcclxuICAgICAgICBsb2coMywgYFticm93c2VyXSBMYXVuY2hlZCBicm93c2VyIGluIHNoZWxsIG1vZGUuYCk7XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIC8vIERlYnVnIG1vZGUgaW5mb3JtXHJcbiAgICAgIGlmIChlbmFibGVkRGVidWcpIHtcclxuICAgICAgICBsb2coMywgYFticm93c2VyXSBMYXVuY2hlZCBicm93c2VyIGluIGRlYnVnIG1vZGUuYCk7XHJcbiAgICAgIH1cclxuICAgIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcihcclxuICAgICAgICAnW2Jyb3dzZXJdIE1heGltdW0gcmV0cmllcyB0byBvcGVuIGEgYnJvd3NlciBpbnN0YW5jZSByZWFjaGVkLicsXHJcbiAgICAgICAgNTAwXHJcbiAgICAgICkuc2V0RXJyb3IoZXJyb3IpO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIE5vIGNvcnJlY3QgYnJvd3NlclxyXG4gICAgaWYgKCFicm93c2VyKSB7XHJcbiAgICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcignW2Jyb3dzZXJdIENhbm5vdCBmaW5kIGEgYnJvd3NlciB0byBvcGVuLicsIDUwMCk7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICAvLyBSZXR1cm4gYSBicm93c2VyIGluc3RhbmNlXHJcbiAgcmV0dXJuIGJyb3dzZXI7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBDbG9zZXMgdGhlIFB1cHBldGVlciBicm93c2VyIGluc3RhbmNlIGlmIGl0IGlzIGNvbm5lY3RlZC5cclxuICpcclxuICogQGFzeW5jXHJcbiAqIEBmdW5jdGlvbiBjbG9zZUJyb3dzZXJcclxuICovXHJcbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBjbG9zZUJyb3dzZXIoKSB7XHJcbiAgLy8gQ2xvc2UgdGhlIGJyb3dzZXIgd2hlbiBjb25uZWN0ZWRcclxuICBpZiAoYnJvd3NlciAmJiBicm93c2VyLmNvbm5lY3RlZCkge1xyXG4gICAgYXdhaXQgYnJvd3Nlci5jbG9zZSgpO1xyXG4gIH1cclxuICBicm93c2VyID0gbnVsbDtcclxuICBsb2coNCwgJ1ticm93c2VyXSBDbG9zZWQgdGhlIGJyb3dzZXIuJyk7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBDcmVhdGVzIGEgbmV3IFB1cHBldGVlciBwYWdlIHdpdGhpbiBhbiBleGlzdGluZyBicm93c2VyIGluc3RhbmNlLlxyXG4gKiBUaGUgZnVuY3Rpb24gY3JlYXRlcyBhIG5ldyBwYWdlLCBkaXNhYmxlcyBjYWNoaW5nLCBzZXRzIGNvbnRlbnQgdXNpbmdcclxuICogdGhlIGBfc2V0UGFnZUNvbnRlbnQoKWAsIGFuZCByZXR1cm5zIHRoZSBjcmVhdGVkIFB1cHBldGVlciBwYWdlLlxyXG4gKlxyXG4gKiBAYXN5bmNcclxuICogQGZ1bmN0aW9uIG5ld1BhZ2VcclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IHBvb2xSZXNvdXJjZSAtIFRoZSBwb29sIHJlc291cmNlIHRoYXQgY29udGFpbnMgYGlkYCxcclxuICogYHdvcmtDb3VudGAsIGFuZCBgcGFnZWAuXHJcbiAqXHJcbiAqIEB0aHJvd3Mge0V4cG9ydEVycm9yfSBUaHJvd3MgYW4gYEV4cG9ydEVycm9yYCBpZiBubyB2YWxpZCBicm93c2VyXHJcbiAqIGhhcyBiZWVuIGNvbm5lY3RlZCBvciBpZiBhIHBhZ2UgaXMgaW52YWxpZCBvciBjbG9zZWQuXHJcbiAqL1xyXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gbmV3UGFnZShwb29sUmVzb3VyY2UpIHtcclxuICAvLyBFcnJvciBpbiBjYXNlIG9mIG5vIGNvbm5lY3RlZCBicm93c2VyXHJcbiAgaWYgKCFicm93c2VyIHx8ICFicm93c2VyLmNvbm5lY3RlZCkge1xyXG4gICAgdGhyb3cgbmV3IEV4cG9ydEVycm9yKGBbYnJvd3Nlcl0gQnJvd3NlciBpcyBub3QgeWV0IGNvbm5lY3RlZC5gLCA1MDApO1xyXG4gIH1cclxuXHJcbiAgLy8gQ3JlYXRlIGEgcGFnZVxyXG4gIHBvb2xSZXNvdXJjZS5wYWdlID0gYXdhaXQgYnJvd3Nlci5uZXdQYWdlKCk7XHJcblxyXG4gIC8vIERpc2FibGUgY2FjaGVcclxuICBhd2FpdCBwb29sUmVzb3VyY2UucGFnZS5zZXRDYWNoZUVuYWJsZWQoZmFsc2UpO1xyXG5cclxuICAvLyBTZXQgdGhlIGNvbnRlbnRcclxuICBhd2FpdCBfc2V0UGFnZUNvbnRlbnQocG9vbFJlc291cmNlLnBhZ2UpO1xyXG5cclxuICAvLyBTZXQgcGFnZSBldmVudHNcclxuICBfc2V0UGFnZUV2ZW50cyhwb29sUmVzb3VyY2UucGFnZSk7XHJcblxyXG4gIC8vIENoZWNrIGlmIHRoZSBwYWdlIGlzIGNvcnJlY3RseSBjcmVhdGVkXHJcbiAgaWYgKCFwb29sUmVzb3VyY2UucGFnZSB8fCBwb29sUmVzb3VyY2UucGFnZS5pc0Nsb3NlZCgpKSB7XHJcbiAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoJ1ticm93c2VyXSBUaGUgcGFnZSBpcyBpbnZhbGlkIG9yIGNsb3NlZC4nLCA0MDApO1xyXG4gIH1cclxufVxyXG5cclxuLyoqXHJcbiAqIENsZWFycyB0aGUgY29udGVudCBvZiBhIFB1cHBldGVlciBwYWdlIGJhc2VkIG9uIHRoZSBzcGVjaWZpZWQgbW9kZS4gTG9nc1xyXG4gKiB0aHJvd24gZXJyb3IgaWYgY2xlYXJpbmcgb2YgYSBwYWdlJ3MgY29udGVudCBmYWlscy5cclxuICpcclxuICogQGFzeW5jXHJcbiAqIEBmdW5jdGlvbiBjbGVhclBhZ2VcclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IHBvb2xSZXNvdXJjZSAtIFRoZSBwb29sIHJlc291cmNlIHRoYXQgY29udGFpbnMgcGFnZSBhbmQgaWQuXHJcbiAqIEBwYXJhbSB7Ym9vbGVhbn0gW2hhcmRSZXNldD1mYWxzZV0gLSBBIGZsYWcgaW5kaWNhdGluZyB0aGUgdHlwZSBvZiBjbGVhcmluZ1xyXG4gKiB0byBiZSBwZXJmb3JtZWQuIElmIGB0cnVlYCwgbmF2aWdhdGVzIHRvIGBhYm91dDpibGFua2AgYW5kIHJlc2V0cyBjb250ZW50XHJcbiAqIGFuZCBzY3JpcHRzLiBJZiBgZmFsc2VgLCBjbGVhcnMgdGhlIGJvZHkgY29udGVudCBieSBzZXR0aW5nIGEgcHJlZGVmaW5lZCBIVE1MXHJcbiAqIHN0cnVjdHVyZS4gVGhlIGRlZmF1bHQgdmFsdWUgaXMgYGZhbHNlYC5cclxuICpcclxuICogQHJldHVybnMge1Byb21pc2U8Ym9vbGVhbj59IEEgUHJvbWlzZSB0aGF0IHJlc29sdmVzIHRvIGB0cnVlYCB3aGVuIHBhZ2VcclxuICogaXMgY29ycmVjdGx5IGNsZWFyZWQgYW5kIGBmYWxzZWAgd2hlbiBpdCBpcyBub3QuXHJcbiAqL1xyXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gY2xlYXJQYWdlKHBvb2xSZXNvdXJjZSwgaGFyZFJlc2V0ID0gZmFsc2UpIHtcclxuICB0cnkge1xyXG4gICAgaWYgKHBvb2xSZXNvdXJjZS5wYWdlICYmICFwb29sUmVzb3VyY2UucGFnZS5pc0Nsb3NlZCgpKSB7XHJcbiAgICAgIGlmIChoYXJkUmVzZXQpIHtcclxuICAgICAgICAvLyBOYXZpZ2F0ZSB0byBgYWJvdXQ6YmxhbmtgXHJcbiAgICAgICAgYXdhaXQgcG9vbFJlc291cmNlLnBhZ2UuZ290bygnYWJvdXQ6YmxhbmsnLCB7XHJcbiAgICAgICAgICB3YWl0VW50aWw6ICdkb21jb250ZW50bG9hZGVkJ1xyXG4gICAgICAgIH0pO1xyXG5cclxuICAgICAgICAvLyBTZXQgdGhlIGNvbnRlbnQgYW5kIGFuZCBzY3JpcHRzIGFnYWluXHJcbiAgICAgICAgYXdhaXQgX3NldFBhZ2VDb250ZW50KHBvb2xSZXNvdXJjZS5wYWdlKTtcclxuICAgICAgfSBlbHNlIHtcclxuICAgICAgICAvLyBDbGVhciBib2R5IGNvbnRlbnRcclxuICAgICAgICBhd2FpdCBwb29sUmVzb3VyY2UucGFnZS5ldmFsdWF0ZSgoKSA9PiB7XHJcbiAgICAgICAgICBkb2N1bWVudC5ib2R5LmlubmVySFRNTCA9XHJcbiAgICAgICAgICAgICc8ZGl2IGlkPVwiY2hhcnQtY29udGFpbmVyXCI+PGRpdiBpZD1cImNvbnRhaW5lclwiPjwvZGl2PjwvZGl2Pic7XHJcbiAgICAgICAgfSk7XHJcbiAgICAgIH1cclxuICAgICAgcmV0dXJuIHRydWU7XHJcbiAgICB9XHJcbiAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgIGxvZ1dpdGhTdGFjayhcclxuICAgICAgMixcclxuICAgICAgZXJyb3IsXHJcbiAgICAgIGBbcG9vbF0gUG9vbCByZXNvdXJjZSBbJHtwb29sUmVzb3VyY2UuaWR9XSAtIENvbnRlbnQgb2YgdGhlIHBhZ2UgY291bGQgbm90IGJlIGNsZWFyZWQuYFxyXG4gICAgKTtcclxuXHJcbiAgICAvLyBTZXQgdGhlIGB3b3JrTGltaXRgIHRvIGV4Y2VlZGVkIGluIG9yZGVyIHRvIHJlY3JlYXRlIHRoZSByZXNvdXJjZVxyXG4gICAgcG9vbFJlc291cmNlLndvcmtDb3VudCA9IGdldE9wdGlvbnMoKS5wb29sLndvcmtMaW1pdCArIDE7XHJcbiAgfVxyXG4gIHJldHVybiBmYWxzZTtcclxufVxyXG5cclxuLyoqXHJcbiAqIEFkZHMgY3VzdG9tIEpTIGFuZCBDU1MgcmVzb3VyY2VzIHRvIGEgUHVwcGV0ZWVyIHBhZ2UgYmFzZWQgb24gdGhlIHNwZWNpZmllZFxyXG4gKiBvcHRpb25zLlxyXG4gKlxyXG4gKiBAYXN5bmNcclxuICogQGZ1bmN0aW9uIGFkZFBhZ2VSZXNvdXJjZXNcclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IHBhZ2UgLSBUaGUgUHVwcGV0ZWVyIHBhZ2Ugb2JqZWN0IHRvIHdoaWNoIHJlc291cmNlcyB3aWxsXHJcbiAqIGJlIGFkZGVkLlxyXG4gKiBAcGFyYW0ge09iamVjdH0gY3VzdG9tTG9naWNPcHRpb25zIC0gVGhlIGNvbmZpZ3VyYXRpb24gb2JqZWN0IGNvbnRhaW5pbmdcclxuICogYGN1c3RvbUxvZ2ljYCBvcHRpb25zLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7UHJvbWlzZTxBcnJheTxPYmplY3Q+Pn0gQSBQcm9taXNlIHRoYXQgcmVzb2x2ZXMgdG8gYW4gYXJyYXlcclxuICogb2YgaW5qZWN0ZWQgcmVzb3VyY2VzLlxyXG4gKi9cclxuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIGFkZFBhZ2VSZXNvdXJjZXMocGFnZSwgY3VzdG9tTG9naWNPcHRpb25zKSB7XHJcbiAgLy8gSW5qZWN0ZWQgcmVzb3VyY2VzIGFycmF5XHJcbiAgY29uc3QgaW5qZWN0ZWRSZXNvdXJjZXMgPSBbXTtcclxuXHJcbiAgLy8gVXNlIHRoZSBjb250ZW50IG9mIHRoZSBgcmVzb3VyY2VzYFxyXG4gIGNvbnN0IHJlc291cmNlcyA9IGN1c3RvbUxvZ2ljT3B0aW9ucy5yZXNvdXJjZXM7XHJcbiAgaWYgKHJlc291cmNlcykge1xyXG4gICAgY29uc3QgaW5qZWN0ZWRKcyA9IFtdO1xyXG5cclxuICAgIC8vIExvYWQgY3VzdG9tIEpTIGNvZGVcclxuICAgIGlmIChyZXNvdXJjZXMuanMpIHtcclxuICAgICAgaW5qZWN0ZWRKcy5wdXNoKHtcclxuICAgICAgICBjb250ZW50OiByZXNvdXJjZXMuanNcclxuICAgICAgfSk7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gTG9hZCBzY3JpcHRzIGZyb20gYWxsIGN1c3RvbSBmaWxlc1xyXG4gICAgaWYgKHJlc291cmNlcy5maWxlcykge1xyXG4gICAgICBmb3IgKGNvbnN0IGZpbGUgb2YgcmVzb3VyY2VzLmZpbGVzKSB7XHJcbiAgICAgICAgY29uc3QgaXNMb2NhbCA9IGZpbGUuc3RhcnRzV2l0aCgnaHR0cCcpID8gZmFsc2UgOiB0cnVlO1xyXG5cclxuICAgICAgICAvLyBBZGQgZWFjaCBjdXN0b20gc2NyaXB0IGZyb20gcmVzb3VyY2VzJyBmaWxlc1xyXG4gICAgICAgIGluamVjdGVkSnMucHVzaChcclxuICAgICAgICAgIGlzTG9jYWxcclxuICAgICAgICAgICAgPyB7XHJcbiAgICAgICAgICAgICAgICBjb250ZW50OiByZWFkRmlsZVN5bmMoZ2V0QWJzb2x1dGVQYXRoKGZpbGUpLCAndXRmOCcpXHJcbiAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICA6IHtcclxuICAgICAgICAgICAgICAgIHVybDogZmlsZVxyXG4gICAgICAgICAgICAgIH1cclxuICAgICAgICApO1xyXG4gICAgICB9XHJcbiAgICB9XHJcblxyXG4gICAgLy8gVGhlIGFjdHVhbCBpbmplY3Rpb24gb2YgY29sbGVjdGVkIHNjcmlwdHNcclxuICAgIGZvciAoY29uc3QganNSZXNvdXJjZSBvZiBpbmplY3RlZEpzKSB7XHJcbiAgICAgIHRyeSB7XHJcbiAgICAgICAgaW5qZWN0ZWRSZXNvdXJjZXMucHVzaChhd2FpdCBwYWdlLmFkZFNjcmlwdFRhZyhqc1Jlc291cmNlKSk7XHJcbiAgICAgIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICAgICAgbG9nV2l0aFN0YWNrKDIsIGVycm9yLCBgW2Jyb3dzZXJdIFRoZSBKUyByZXNvdXJjZSBjYW5ub3QgYmUgbG9hZGVkLmApO1xyXG4gICAgICB9XHJcbiAgICB9XHJcbiAgICBpbmplY3RlZEpzLmxlbmd0aCA9IDA7XHJcblxyXG4gICAgLy8gTG9hZCBDU1NcclxuICAgIGNvbnN0IGluamVjdGVkQ3NzID0gW107XHJcbiAgICBpZiAocmVzb3VyY2VzLmNzcykge1xyXG4gICAgICBjb25zdCBjc3NJbXBvcnRzID0gcmVzb3VyY2VzLmNzcy5tYXRjaCgvQGltcG9ydFxccyooW147XSopOy9nKTtcclxuICAgICAgaWYgKGNzc0ltcG9ydHMpIHtcclxuICAgICAgICAvLyBIYW5kbGUgY3NzIHNlY3Rpb25cclxuICAgICAgICBmb3IgKGxldCBjc3NJbXBvcnRQYXRoIG9mIGNzc0ltcG9ydHMpIHtcclxuICAgICAgICAgIGlmIChjc3NJbXBvcnRQYXRoKSB7XHJcbiAgICAgICAgICAgIGNzc0ltcG9ydFBhdGggPSBjc3NJbXBvcnRQYXRoXHJcbiAgICAgICAgICAgICAgLnJlcGxhY2UoJ3VybCgnLCAnJylcclxuICAgICAgICAgICAgICAucmVwbGFjZSgnQGltcG9ydCcsICcnKVxyXG4gICAgICAgICAgICAgIC5yZXBsYWNlKC9cIi9nLCAnJylcclxuICAgICAgICAgICAgICAucmVwbGFjZSgvJy9nLCAnJylcclxuICAgICAgICAgICAgICAucmVwbGFjZSgvOy8sICcnKVxyXG4gICAgICAgICAgICAgIC5yZXBsYWNlKC9cXCkvZywgJycpXHJcbiAgICAgICAgICAgICAgLnRyaW0oKTtcclxuXHJcbiAgICAgICAgICAgIC8vIEFkZCBlYWNoIGN1c3RvbSBjc3MgZnJvbSByZXNvdXJjZXNcclxuICAgICAgICAgICAgaWYgKGNzc0ltcG9ydFBhdGguc3RhcnRzV2l0aCgnaHR0cCcpKSB7XHJcbiAgICAgICAgICAgICAgaW5qZWN0ZWRDc3MucHVzaCh7XHJcbiAgICAgICAgICAgICAgICB1cmw6IGNzc0ltcG9ydFBhdGhcclxuICAgICAgICAgICAgICB9KTtcclxuICAgICAgICAgICAgfSBlbHNlIGlmIChjdXN0b21Mb2dpY09wdGlvbnMuYWxsb3dGaWxlUmVzb3VyY2VzKSB7XHJcbiAgICAgICAgICAgICAgaW5qZWN0ZWRDc3MucHVzaCh7XHJcbiAgICAgICAgICAgICAgICBwYXRoOiBnZXRBYnNvbHV0ZVBhdGgoY3NzSW1wb3J0UGF0aClcclxuICAgICAgICAgICAgICB9KTtcclxuICAgICAgICAgICAgfVxyXG4gICAgICAgICAgfVxyXG4gICAgICAgIH1cclxuICAgICAgfVxyXG5cclxuICAgICAgLy8gVGhlIHJlc3Qgb2YgdGhlIENTUyBzZWN0aW9uIHdpbGwgYmUgY29udGVudCBieSBub3dcclxuICAgICAgaW5qZWN0ZWRDc3MucHVzaCh7XHJcbiAgICAgICAgY29udGVudDogcmVzb3VyY2VzLmNzcy5yZXBsYWNlKC9AaW1wb3J0XFxzKihbXjtdKik7L2csICcnKSB8fCAnICdcclxuICAgICAgfSk7XHJcblxyXG4gICAgICAvLyBUaGUgYWN0dWFsIGluamVjdGlvbiBvZiBjb2xsZWN0ZWQgQ1NTXHJcbiAgICAgIGZvciAoY29uc3QgY3NzUmVzb3VyY2Ugb2YgaW5qZWN0ZWRDc3MpIHtcclxuICAgICAgICB0cnkge1xyXG4gICAgICAgICAgaW5qZWN0ZWRSZXNvdXJjZXMucHVzaChhd2FpdCBwYWdlLmFkZFN0eWxlVGFnKGNzc1Jlc291cmNlKSk7XHJcbiAgICAgICAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICAgICAgIGxvZ1dpdGhTdGFjayhcclxuICAgICAgICAgICAgMixcclxuICAgICAgICAgICAgZXJyb3IsXHJcbiAgICAgICAgICAgIGBbYnJvd3Nlcl0gVGhlIENTUyByZXNvdXJjZSBjYW5ub3QgYmUgbG9hZGVkLmBcclxuICAgICAgICAgICk7XHJcbiAgICAgICAgfVxyXG4gICAgICB9XHJcbiAgICAgIGluamVjdGVkQ3NzLmxlbmd0aCA9IDA7XHJcbiAgICB9XHJcbiAgfVxyXG4gIHJldHVybiBpbmplY3RlZFJlc291cmNlcztcclxufVxyXG5cclxuLyoqXHJcbiAqIENsZWFycyBvdXQgYWxsIHN0YXRlIHNldCBvbiB0aGUgcGFnZSB3aXRoIGBhZGRTY3JpcHRUYWdgIGFuZCBgYWRkU3R5bGVUYWdgLlxyXG4gKiBSZW1vdmVzIGluamVjdGVkIHJlc291cmNlcyBhbmQgcmVzZXRzIENTUyBhbmQgc2NyaXB0IHRhZ3Mgb24gdGhlIHBhZ2UuXHJcbiAqIEFkZGl0aW9uYWxseSwgaXQgZGVzdHJveXMgcHJldmlvdXNseSBleGlzdGluZyBjaGFydHMuXHJcbiAqXHJcbiAqIEBhc3luY1xyXG4gKiBAZnVuY3Rpb24gY2xlYXJQYWdlUmVzb3VyY2VzXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBwYWdlIC0gVGhlIFB1cHBldGVlciBwYWdlIG9iamVjdCBmcm9tIHdoaWNoIHJlc291cmNlcyB3aWxsXHJcbiAqIGJlIGNsZWFyZWQuXHJcbiAqIEBwYXJhbSB7QXJyYXk8T2JqZWN0Pn0gaW5qZWN0ZWRSZXNvdXJjZXMgLSBBcnJheSBvZiBpbmplY3RlZCByZXNvdXJjZXNcclxuICogdG8gYmUgY2xlYXJlZC5cclxuICovXHJcbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBjbGVhclBhZ2VSZXNvdXJjZXMocGFnZSwgaW5qZWN0ZWRSZXNvdXJjZXMpIHtcclxuICB0cnkge1xyXG4gICAgZm9yIChjb25zdCByZXNvdXJjZSBvZiBpbmplY3RlZFJlc291cmNlcykge1xyXG4gICAgICBhd2FpdCByZXNvdXJjZS5kaXNwb3NlKCk7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gRGVzdHJveSBvbGQgY2hhcnRzIGFmdGVyIGV4cG9ydCBpcyBkb25lIGFuZCByZXNldCBhbGwgQ1NTIGFuZCBzY3JpcHQgdGFnc1xyXG4gICAgYXdhaXQgcGFnZS5ldmFsdWF0ZSgoKSA9PiB7XHJcbiAgICAgIC8vIFdlIGFyZSBub3QgZ3VhcmFudGVlZCB0aGF0IEhpZ2hjaGFydHMgaXMgbG9hZGVkLCB3aGVuIGRvaW5nIFNWRyBleHBvcnRzXHJcbiAgICAgIGlmICh0eXBlb2YgSGlnaGNoYXJ0cyAhPT0gJ3VuZGVmaW5lZCcpIHtcclxuICAgICAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgbm8tdW5kZWZcclxuICAgICAgICBjb25zdCBvbGRDaGFydHMgPSBIaWdoY2hhcnRzLmNoYXJ0cztcclxuXHJcbiAgICAgICAgLy8gQ2hlY2sgaW4gYW55IGFscmVhZHkgZXhpc3RpbmcgY2hhcnRzXHJcbiAgICAgICAgaWYgKEFycmF5LmlzQXJyYXkob2xkQ2hhcnRzKSAmJiBvbGRDaGFydHMubGVuZ3RoKSB7XHJcbiAgICAgICAgICAvLyBEZXN0cm95IG9sZCBjaGFydHNcclxuICAgICAgICAgIGZvciAoY29uc3Qgb2xkQ2hhcnQgb2Ygb2xkQ2hhcnRzKSB7XHJcbiAgICAgICAgICAgIG9sZENoYXJ0ICYmIG9sZENoYXJ0LmRlc3Ryb3koKTtcclxuICAgICAgICAgICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIG5vLXVuZGVmXHJcbiAgICAgICAgICAgIEhpZ2hjaGFydHMuY2hhcnRzLnNoaWZ0KCk7XHJcbiAgICAgICAgICB9XHJcbiAgICAgICAgfVxyXG4gICAgICB9XHJcblxyXG4gICAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgbm8tdW5kZWZcclxuICAgICAgY29uc3QgWy4uLnNjcmlwdHNUb1JlbW92ZV0gPSBkb2N1bWVudC5nZXRFbGVtZW50c0J5VGFnTmFtZSgnc2NyaXB0Jyk7XHJcbiAgICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBuby11bmRlZlxyXG4gICAgICBjb25zdCBbLCAuLi5zdHlsZXNUb1JlbW92ZV0gPSBkb2N1bWVudC5nZXRFbGVtZW50c0J5VGFnTmFtZSgnc3R5bGUnKTtcclxuICAgICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIG5vLXVuZGVmXHJcbiAgICAgIGNvbnN0IFsuLi5saW5rc1RvUmVtb3ZlXSA9IGRvY3VtZW50LmdldEVsZW1lbnRzQnlUYWdOYW1lKCdsaW5rJyk7XHJcblxyXG4gICAgICAvLyBSZW1vdmUgdGFnc1xyXG4gICAgICBmb3IgKGNvbnN0IGVsZW1lbnQgb2YgW1xyXG4gICAgICAgIC4uLnNjcmlwdHNUb1JlbW92ZSxcclxuICAgICAgICAuLi5zdHlsZXNUb1JlbW92ZSxcclxuICAgICAgICAuLi5saW5rc1RvUmVtb3ZlXHJcbiAgICAgIF0pIHtcclxuICAgICAgICBlbGVtZW50LnJlbW92ZSgpO1xyXG4gICAgICB9XHJcbiAgICB9KTtcclxuICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgbG9nV2l0aFN0YWNrKDIsIGVycm9yLCBgW2Jyb3dzZXJdIENvdWxkIG5vdCBjbGVhciBwYWdlJ3MgcmVzb3VyY2VzLmApO1xyXG4gIH1cclxufVxyXG5cclxuLyoqXHJcbiAqIFNldHMgdGhlIGNvbnRlbnQgZm9yIGEgUHVwcGV0ZWVyIHBhZ2UgdXNpbmcgYSBwcmVkZWZpbmVkIHRlbXBsYXRlXHJcbiAqIGFuZCBhZGRpdGlvbmFsIHNjcmlwdHMuXHJcbiAqXHJcbiAqIEBhc3luY1xyXG4gKiBAZnVuY3Rpb24gX3NldFBhZ2VDb250ZW50XHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBwYWdlIC0gVGhlIFB1cHBldGVlciBwYWdlIG9iamVjdCB0byB3aGljaCB0aGUgY29udGVudFxyXG4gKiBpcyBiZWluZyBzZXQuXHJcbiAqL1xyXG5hc3luYyBmdW5jdGlvbiBfc2V0UGFnZUNvbnRlbnQocGFnZSkge1xyXG4gIC8vIFNldCB0aGUgaW5pdGlhbCBwYWdlIGNvbnRlbnRcclxuICBhd2FpdCBwYWdlLnNldENvbnRlbnQocGFnZVRlbXBsYXRlLCB7IHdhaXRVbnRpbDogJ2RvbWNvbnRlbnRsb2FkZWQnIH0pO1xyXG5cclxuICAvLyBBZGQgYWxsIHJlZ2lzdGVyZWQgSGlnY2hhcnRzIHNjcmlwdHMsIHF1aXRlIGRlbWFuZGluZ1xyXG4gIGF3YWl0IHBhZ2UuYWRkU2NyaXB0VGFnKHsgcGF0aDogam9pbihnZXRDYWNoZVBhdGgoKSwgJ3NvdXJjZXMuanMnKSB9KTtcclxuXHJcbiAgLy8gU2V0IHRoZSBpbml0aWFsIGBhbmltT2JqZWN0YCBmb3IgSGlnaGNoYXJ0c1xyXG4gIGF3YWl0IHBhZ2UuZXZhbHVhdGUoc2V0dXBIaWdoY2hhcnRzKTtcclxufVxyXG5cclxuLyoqXHJcbiAqIFNldCBldmVudHMgKGxpa2UgYHBhZ2VlcnJvcmAgYW5kIGBjb25zb2xlYCkgZm9yIGEgUHVwcGV0ZWVyIHBhZ2UgaW4gb3JkZXJcclxuICogdG8gY2F0Y2ggYW5kIGRpc3BsYXkgZXJyb3JzIGFuZCBjb25zb2xlIGxvZ3MgZnJvbSB0aGUgd2luZG93IGNvbnRleHQuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBfc2V0UGFnZUV2ZW50c1xyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gcGFnZSAtIFRoZSBQdXBwZXRlZXIgcGFnZSBvYmplY3QgdG8gd2hpY2ggdGhlIGxpc3RlbmVyc1xyXG4gKiBhcmUgYmVpbmcgc2V0LlxyXG4gKi9cclxuZnVuY3Rpb24gX3NldFBhZ2VFdmVudHMocGFnZSkge1xyXG4gIC8vIEdldCBgZGVidWdgIG9wdGlvbnNcclxuICBjb25zdCB7IGRlYnVnIH0gPSBnZXRPcHRpb25zKCk7XHJcblxyXG4gIC8vIFNldCB0aGUgYHBhZ2VlcnJvcmAgbGlzdGVuZXJcclxuICBwYWdlLm9uKCdwYWdlZXJyb3InLCBhc3luYyAoKSA9PiB7XHJcbiAgICAvLyBJdCB3b3VsZCBzZWVtIGxpa2UgdGhpcyBtYXkgZmlyZSBhdCB0aGUgc2FtZSB0aW1lIG9yIHNob3J0bHkgYmVmb3JlXHJcbiAgICAvLyBhIHBhZ2UgaXMgY2xvc2VkLlxyXG4gICAgaWYgKHBhZ2UuaXNDbG9zZWQoKSkge1xyXG4gICAgICByZXR1cm47XHJcbiAgICB9XHJcbiAgfSk7XHJcblxyXG4gIC8vIFNldCB0aGUgYGNvbnNvbGVgIGxpc3RlbmVyLCBpZiBuZWVkZWRcclxuICBpZiAoZGVidWcuZW5hYmxlICYmIGRlYnVnLmxpc3RlblRvQ29uc29sZSkge1xyXG4gICAgcGFnZS5vbignY29uc29sZScsIChtZXNzYWdlKSA9PiB7XHJcbiAgICAgIGNvbnNvbGUubG9nKGBbZGVidWddICR7bWVzc2FnZS50ZXh0KCl9YCk7XHJcbiAgICB9KTtcclxuICB9XHJcbn1cclxuXHJcbmV4cG9ydCBkZWZhdWx0IHtcclxuICBnZXRCcm93c2VyLFxyXG4gIGNyZWF0ZUJyb3dzZXIsXHJcbiAgY2xvc2VCcm93c2VyLFxyXG4gIG5ld1BhZ2UsXHJcbiAgY2xlYXJQYWdlLFxyXG4gIGFkZFBhZ2VSZXNvdXJjZXMsXHJcbiAgY2xlYXJQYWdlUmVzb3VyY2VzXHJcbn07XHJcbiIsIi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXHJcblxyXG5IaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXJcclxuXHJcbkNvcHlyaWdodCAoYykgMjAxNi0yMDI1LCBIaWdoc29mdFxyXG5cclxuTGljZW5jZWQgdW5kZXIgdGhlIE1JVCBsaWNlbmNlLlxyXG5cclxuQWRkaXRpb25hbGx5IGEgdmFsaWQgSGlnaGNoYXJ0cyBsaWNlbnNlIGlzIHJlcXVpcmVkIGZvciB1c2UuXHJcblxyXG5TZWUgTElDRU5TRSBmaWxlIGluIHJvb3QgZm9yIGRldGFpbHMuXHJcblxyXG4qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xyXG5cclxuLyoqXHJcbiAqIFRoZSBDU1MgdG8gYmUgdXNlZCBvbiB0aGUgZXhwb3J0ZWQgcGFnZS5cclxuICpcclxuICogQHJldHVybnMge3N0cmluZ30gVGhlIENTUyBjb25maWd1cmF0aW9uLlxyXG4gKi9cclxuZXhwb3J0IGRlZmF1bHQgKCkgPT4gYFxyXG5cclxuaHRtbCwgYm9keSB7XHJcbiAgbWFyZ2luOiAwO1xyXG4gIHBhZGRpbmc6IDA7XHJcbiAgYm94LXNpemluZzogYm9yZGVyLWJveDtcclxufVxyXG5cclxuI3RhYmxlLWRpdiwgI3NsaWRlcnMsICNkYXRhdGFibGUsICNjb250cm9scywgLmxkLXJvdyB7XHJcbiAgZGlzcGxheTogbm9uZTtcclxuICBoZWlnaHQ6IDA7XHJcbn1cclxuXHJcbiNjaGFydC1jb250YWluZXIge1xyXG4gIGJveC1zaXppbmc6IGJvcmRlci1ib3g7XHJcbiAgbWFyZ2luOiAwO1xyXG4gIG92ZXJmbG93OiBhdXRvO1xyXG4gIGZvbnQtc2l6ZTogMDtcclxufVxyXG5cclxuI2NoYXJ0LWNvbnRhaW5lciA+IGZpZ3VyZSwgZGl2IHtcclxuICBtYXJnaW4tdG9wOiAwICFpbXBvcnRhbnQ7XHJcbiAgbWFyZ2luLWJvdHRvbTogMCAhaW1wb3J0YW50O1xyXG59XHJcblxyXG5gO1xyXG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxyXG5cclxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXHJcblxyXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNSwgSGlnaHNvZnRcclxuXHJcbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cclxuXHJcbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxyXG5cclxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxyXG5cclxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cclxuXHJcbmltcG9ydCBjc3NUZW1wbGF0ZSBmcm9tICcuL2Nzcy5qcyc7XHJcblxyXG4vKipcclxuICogVGhlIFNWRyB0ZW1wbGF0ZSB0byB1c2Ugd2hlbiBsb2FkaW5nIFNWRyBjb250ZW50IHRvIGJlIGV4cG9ydGVkLlxyXG4gKlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gc3ZnIC0gVGhlIFNWRyBpbnB1dCBjb250ZW50IHRvIGJlIGV4cG9ydGVkLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7c3RyaW5nfSBUaGUgU1ZHIHRlbXBsYXRlLlxyXG4gKi9cclxuZXhwb3J0IGRlZmF1bHQgKHN2ZykgPT4gYFxyXG48IURPQ1RZUEUgaHRtbD5cclxuPGh0bWwgbGFuZz0nZW4tVVMnPlxyXG4gIDxoZWFkPlxyXG4gICAgPG1ldGEgaHR0cC1lcXVpdj1cIkNvbnRlbnQtVHlwZVwiIGNvbnRlbnQ9XCJ0ZXh0L2h0bWw7IGNoYXJzZXQ9dXRmLThcIj5cclxuICAgIDx0aXRsZT5IaWdoY2hhcnRzIEV4cG9ydDwvdGl0bGU+XHJcbiAgPC9oZWFkPlxyXG4gIDxzdHlsZT5cclxuICAgICR7Y3NzVGVtcGxhdGUoKX1cclxuICA8L3N0eWxlPlxyXG4gIDxib2R5PlxyXG4gICAgPGRpdiBpZD1cImNoYXJ0LWNvbnRhaW5lclwiPlxyXG4gICAgICAke3N2Z31cclxuICAgIDwvZGl2PlxyXG4gIDwvYm9keT5cclxuPC9odG1sPlxyXG5cclxuYDtcclxuIiwiLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcclxuXHJcbkhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlclxyXG5cclxuQ29weXJpZ2h0IChjKSAyMDE2LTIwMjUsIEhpZ2hzb2Z0XHJcblxyXG5MaWNlbmNlZCB1bmRlciB0aGUgTUlUIGxpY2VuY2UuXHJcblxyXG5BZGRpdGlvbmFsbHkgYSB2YWxpZCBIaWdoY2hhcnRzIGxpY2Vuc2UgaXMgcmVxdWlyZWQgZm9yIHVzZS5cclxuXHJcblNlZSBMSUNFTlNFIGZpbGUgaW4gcm9vdCBmb3IgZGV0YWlscy5cclxuXHJcbioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXHJcblxyXG4vKipcclxuICogQG92ZXJ2aWV3IFRoaXMgbW9kdWxlIGhhbmRsZXMgY2hhcnQgZXhwb3J0IGZ1bmN0aW9uYWxpdHkgdXNpbmcgUHVwcGV0ZWVyLlxyXG4gKiBJdCBzdXBwb3J0cyBleHBvcnRpbmcgY2hhcnRzIGFzIFNWRywgUE5HLCBKUEVHLCBhbmQgUERGIGZvcm1hdHMuIFRoZSBtb2R1bGVcclxuICogbWFuYWdlcyBwYWdlIHJlc291cmNlcywgc2V0cyB1cCB0aGUgZXhwb3J0IGVudmlyb25tZW50LCBhbmQgcHJvY2Vzc2VzIGNoYXJ0XHJcbiAqIGNvbmZpZ3VyYXRpb25zIG9yIFNWRyBpbnB1dHMgZm9yIHJlbmRlcmluZy4gRXhwb3J0cyB0byBhIGNoYXJ0IGZyb20gYSBwYWdlXHJcbiAqIHVzaW5nIFB1cHBldGVlci5cclxuICovXHJcblxyXG5pbXBvcnQgeyBhZGRQYWdlUmVzb3VyY2VzLCBjbGVhclBhZ2VSZXNvdXJjZXMgfSBmcm9tICcuL2Jyb3dzZXIuanMnO1xyXG5pbXBvcnQgeyBjcmVhdGVDaGFydCB9IGZyb20gJy4vaGlnaGNoYXJ0cy5qcyc7XHJcbmltcG9ydCB7IGxvZyB9IGZyb20gJy4vbG9nZ2VyLmpzJztcclxuXHJcbmltcG9ydCBzdmdUZW1wbGF0ZSBmcm9tICcuLi90ZW1wbGF0ZXMvc3ZnRXhwb3J0L3N2Z0V4cG9ydC5qcyc7XHJcblxyXG5pbXBvcnQgRXhwb3J0RXJyb3IgZnJvbSAnLi9lcnJvcnMvRXhwb3J0RXJyb3IuanMnO1xyXG5cclxuLyoqXHJcbiAqIEV4cG9ydHMgdG8gYSBjaGFydCBmcm9tIGEgcGFnZSB1c2luZyBQdXBwZXRlZXIuXHJcbiAqXHJcbiAqIEBhc3luY1xyXG4gKiBAZnVuY3Rpb24gcHVwcGV0ZWVyRXhwb3J0XHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBwYWdlIC0gUHVwcGV0ZWVyIHBhZ2Ugb2JqZWN0LlxyXG4gKiBAcGFyYW0ge09iamVjdH0gZXhwb3J0T3B0aW9ucyAtIFRoZSBjb25maWd1cmF0aW9uIG9iamVjdCBjb250YWluaW5nIGBleHBvcnRgXHJcbiAqIG9wdGlvbnMuXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBjdXN0b21Mb2dpY09wdGlvbnMgLSBUaGUgY29uZmlndXJhdGlvbiBvYmplY3QgY29udGFpbmluZ1xyXG4gKiBgY3VzdG9tTG9naWNgIG9wdGlvbnMuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtQcm9taXNlPChzdHJpbmd8QnVmZmVyfEV4cG9ydEVycm9yKT59IEEgUHJvbWlzZSB0aGF0IHJlc29sdmVzXHJcbiAqIHRvIHRoZSBleHBvcnRlZCBkYXRhIG9yIHJlamVjdGluZyB3aXRoIGFuIGBFeHBvcnRFcnJvcmAuXHJcbiAqXHJcbiAqIEB0aHJvd3Mge0V4cG9ydEVycm9yfSBUaHJvd3MgYW4gYEV4cG9ydEVycm9yYCBpZiBleHBvcnQgdG8gYW4gdW5zdXBwb3J0ZWRcclxuICogb3V0cHV0IGZvcm1hdCBvY2N1cnMuXHJcbiAqL1xyXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gcHVwcGV0ZWVyRXhwb3J0KHBhZ2UsIGV4cG9ydE9wdGlvbnMsIGN1c3RvbUxvZ2ljT3B0aW9ucykge1xyXG4gIC8vIEluamVjdGVkIHJlc291cmNlcyBhcnJheSAoYWRkaXRpb25hbCBKUyBhbmQgQ1NTKVxyXG4gIGNvbnN0IGluamVjdGVkUmVzb3VyY2VzID0gW107XHJcblxyXG4gIHRyeSB7XHJcbiAgICBsZXQgaXNTVkcgPSBmYWxzZTtcclxuXHJcbiAgICAvLyBEZWNpZGUgb24gdGhlIGV4cG9ydCBtZXRob2RcclxuICAgIGlmIChleHBvcnRPcHRpb25zLnN2Zykge1xyXG4gICAgICBsb2coNCwgJ1tleHBvcnRdIFRyZWF0aW5nIGFzIFNWRyBpbnB1dC4nKTtcclxuXHJcbiAgICAgIC8vIElmIHRoZSBgdHlwZWAgaXMgYWxzbyBTVkcsIHJldHVybiB0aGUgaW5wdXRcclxuICAgICAgaWYgKGV4cG9ydE9wdGlvbnMudHlwZSA9PT0gJ3N2ZycpIHtcclxuICAgICAgICByZXR1cm4gZXhwb3J0T3B0aW9ucy5zdmc7XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIC8vIE1hcmsgYXMgU1ZHIGV4cG9ydCBmb3IgdGhlIGxhdGVyIHNpemUgY29ycmVjdGlvbnNcclxuICAgICAgaXNTVkcgPSB0cnVlO1xyXG5cclxuICAgICAgLy8gU1ZHIGV4cG9ydFxyXG4gICAgICBhd2FpdCBwYWdlLnNldENvbnRlbnQoc3ZnVGVtcGxhdGUoZXhwb3J0T3B0aW9ucy5zdmcpLCB7XHJcbiAgICAgICAgd2FpdFVudGlsOiAnZG9tY29udGVudGxvYWRlZCdcclxuICAgICAgfSk7XHJcbiAgICB9IGVsc2Uge1xyXG4gICAgICBsb2coNCwgJ1tleHBvcnRdIFRyZWF0aW5nIGFzIEpTT04gY29uZmlnLicpO1xyXG5cclxuICAgICAgLy8gT3B0aW9ucyBleHBvcnRcclxuICAgICAgYXdhaXQgcGFnZS5ldmFsdWF0ZShjcmVhdGVDaGFydCwgZXhwb3J0T3B0aW9ucywgY3VzdG9tTG9naWNPcHRpb25zKTtcclxuICAgIH1cclxuXHJcbiAgICAvLyBLZWVwcyB0cmFjayBvZiBhbGwgcmVzb3VyY2VzIGFkZGVkIG9uIHRoZSBwYWdlIHdpdGggYWRkWFhYVGFnLiBldGNcclxuICAgIC8vIEl0J3MgVklUQUwgdGhhdCBhbGwgYWRkZWQgcmVzb3VyY2VzIGVuZHMgdXAgaGVyZSBzbyB3ZSBjYW4gY2xlYXIgdGhpbmdzXHJcbiAgICAvLyBvdXQgd2hlbiBkb2luZyBhIG5ldyBleHBvcnQgaW4gdGhlIHNhbWUgcGFnZSFcclxuICAgIGluamVjdGVkUmVzb3VyY2VzLnB1c2goXHJcbiAgICAgIC4uLihhd2FpdCBhZGRQYWdlUmVzb3VyY2VzKHBhZ2UsIGN1c3RvbUxvZ2ljT3B0aW9ucykpXHJcbiAgICApO1xyXG5cclxuICAgIC8vIEdldCB0aGUgcmVhbCBjaGFydCBzaXplIGFuZCBzZXQgdGhlIHpvb20gYWNjb3JkaW5nbHlcclxuICAgIGNvbnN0IHNpemUgPSBhd2FpdCBfZ2V0Q2hhcnRTaXplKHBhZ2UsIGlzU1ZHLCBleHBvcnRPcHRpb25zLnNjYWxlKTtcclxuXHJcbiAgICAvLyBHZXQgdGhlIGNsaXAgcmVnaW9uIGZvciB0aGUgcGFnZVxyXG4gICAgY29uc3QgeyB4LCB5IH0gPSBhd2FpdCBfZ2V0Q2xpcFJlZ2lvbihwYWdlKTtcclxuXHJcbiAgICAvLyBTZXQgZmluYWwgYGhlaWdodGAgZm9yIHZpZXdwb3J0XHJcbiAgICBjb25zdCB2aWV3cG9ydEhlaWdodCA9IE1hdGguYWJzKFxyXG4gICAgICBNYXRoLmNlaWwoc2l6ZS5jaGFydEhlaWdodCB8fCBleHBvcnRPcHRpb25zLmhlaWdodClcclxuICAgICk7XHJcblxyXG4gICAgLy8gU2V0IGZpbmFsIGB3aWR0aGAgZm9yIHZpZXdwb3J0XHJcbiAgICBjb25zdCB2aWV3cG9ydFdpZHRoID0gTWF0aC5hYnMoXHJcbiAgICAgIE1hdGguY2VpbChzaXplLmNoYXJ0V2lkdGggfHwgZXhwb3J0T3B0aW9ucy53aWR0aClcclxuICAgICk7XHJcblxyXG4gICAgLy8gU2V0IHRoZSBmaW5hbCB2aWV3cG9ydCBub3cgdGhhdCB3ZSBoYXZlIHRoZSByZWFsIGhlaWdodFxyXG4gICAgYXdhaXQgcGFnZS5zZXRWaWV3cG9ydCh7XHJcbiAgICAgIGhlaWdodDogdmlld3BvcnRIZWlnaHQsXHJcbiAgICAgIHdpZHRoOiB2aWV3cG9ydFdpZHRoLFxyXG4gICAgICBkZXZpY2VTY2FsZUZhY3RvcjogaXNTVkcgPyAxIDogcGFyc2VGbG9hdChleHBvcnRPcHRpb25zLnNjYWxlKVxyXG4gICAgfSk7XHJcblxyXG4gICAgbGV0IHJlc3VsdDtcclxuICAgIC8vIFJhc3Rlcml6YXRpb24gcHJvY2Vzc1xyXG4gICAgc3dpdGNoIChleHBvcnRPcHRpb25zLnR5cGUpIHtcclxuICAgICAgY2FzZSAnc3ZnJzpcclxuICAgICAgICByZXN1bHQgPSBhd2FpdCBfY3JlYXRlU1ZHKHBhZ2UpO1xyXG4gICAgICAgIGJyZWFrO1xyXG4gICAgICBjYXNlICdwbmcnOlxyXG4gICAgICBjYXNlICdqcGVnJzpcclxuICAgICAgICByZXN1bHQgPSBhd2FpdCBfY3JlYXRlSW1hZ2UoXHJcbiAgICAgICAgICBwYWdlLFxyXG4gICAgICAgICAgZXhwb3J0T3B0aW9ucy50eXBlLFxyXG4gICAgICAgICAge1xyXG4gICAgICAgICAgICB3aWR0aDogdmlld3BvcnRXaWR0aCxcclxuICAgICAgICAgICAgaGVpZ2h0OiB2aWV3cG9ydEhlaWdodCxcclxuICAgICAgICAgICAgeCxcclxuICAgICAgICAgICAgeVxyXG4gICAgICAgICAgfSxcclxuICAgICAgICAgIGV4cG9ydE9wdGlvbnMucmFzdGVyaXphdGlvblRpbWVvdXRcclxuICAgICAgICApO1xyXG4gICAgICAgIGJyZWFrO1xyXG4gICAgICBjYXNlICdwZGYnOlxyXG4gICAgICAgIHJlc3VsdCA9IGF3YWl0IF9jcmVhdGVQREYoXHJcbiAgICAgICAgICBwYWdlLFxyXG4gICAgICAgICAgdmlld3BvcnRIZWlnaHQsXHJcbiAgICAgICAgICB2aWV3cG9ydFdpZHRoLFxyXG4gICAgICAgICAgZXhwb3J0T3B0aW9ucy5yYXN0ZXJpemF0aW9uVGltZW91dFxyXG4gICAgICAgICk7XHJcbiAgICAgICAgYnJlYWs7XHJcbiAgICAgIGRlZmF1bHQ6XHJcbiAgICAgICAgdGhyb3cgbmV3IEV4cG9ydEVycm9yKFxyXG4gICAgICAgICAgYFtleHBvcnRdIFVuc3VwcG9ydGVkIG91dHB1dCBmb3JtYXQ6ICR7ZXhwb3J0T3B0aW9ucy50eXBlfS5gLFxyXG4gICAgICAgICAgNDAwXHJcbiAgICAgICAgKTtcclxuICAgIH1cclxuXHJcbiAgICAvLyBDbGVhciBwcmV2aW91c2x5IGluamVjdGVkIEpTIGFuZCBDU1MgcmVzb3VyY2VzXHJcbiAgICBhd2FpdCBjbGVhclBhZ2VSZXNvdXJjZXMocGFnZSwgaW5qZWN0ZWRSZXNvdXJjZXMpO1xyXG4gICAgcmV0dXJuIHJlc3VsdDtcclxuICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgYXdhaXQgY2xlYXJQYWdlUmVzb3VyY2VzKHBhZ2UsIGluamVjdGVkUmVzb3VyY2VzKTtcclxuICAgIHJldHVybiBlcnJvcjtcclxuICB9XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBSZXRyaWV2ZXMgdGhlIGNsaXBwaW5nIHJlZ2lvbiBjb29yZGluYXRlcyBvZiB0aGUgc3BlY2lmaWVkIHBhZ2UgZWxlbWVudFxyXG4gKiB3aXRoIHRoZSAnY2hhcnQtY29udGFpbmVyJyBpZC5cclxuICpcclxuICogQGFzeW5jXHJcbiAqIEBmdW5jdGlvbiBfZ2V0Q2xpcFJlZ2lvblxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gcGFnZSAtIFB1cHBldGVlciBwYWdlIG9iamVjdC5cclxuICpcclxuICogQHJldHVybnMge1Byb21pc2U8T2JqZWN0Pn0gQSBQcm9taXNlIHRoYXQgcmVzb2x2ZXMgdG8gYW4gb2JqZWN0IGNvbnRhaW5pbmdcclxuICogYHhgLCBgeWAsIGB3aWR0aGAsIGFuZCBgaGVpZ2h0YCBwcm9wZXJ0aWVzLlxyXG4gKi9cclxuYXN5bmMgZnVuY3Rpb24gX2dldENsaXBSZWdpb24ocGFnZSkge1xyXG4gIHJldHVybiBwYWdlLiRldmFsKCcjY2hhcnQtY29udGFpbmVyJywgKGVsZW1lbnQpID0+IHtcclxuICAgIGNvbnN0IHsgeCwgeSwgd2lkdGgsIGhlaWdodCB9ID0gZWxlbWVudC5nZXRCb3VuZGluZ0NsaWVudFJlY3QoKTtcclxuICAgIHJldHVybiB7XHJcbiAgICAgIHgsXHJcbiAgICAgIHksXHJcbiAgICAgIHdpZHRoLFxyXG4gICAgICBoZWlnaHQ6IE1hdGgudHJ1bmMoaGVpZ2h0ID4gMSA/IGhlaWdodCA6IDUwMClcclxuICAgIH07XHJcbiAgfSk7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBSZXRyaWV2ZXMgdGhlIHJlYWwgY2hhcnQgZGltZW5zaW9ucyBmcm9tIGEgUHVwcGV0ZWVyIHBhZ2UuIFRoZSBmdW5jdGlvblxyXG4gKiBiZWhhdmVzIGRpZmZlcmVudGx5IGJhc2VkIG9uIHdoZXRoZXIgdGhlIGV4cG9ydCB0eXBlIGlzIFNWRyBvciBhbm90aGVyXHJcbiAqIGZvcm1hdC5cclxuICpcclxuICogQGFzeW5jXHJcbiAqIEBmdW5jdGlvbiBfZ2V0Q2hhcnRTaXplXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBwYWdlIC0gUHVwcGV0ZWVyIHBhZ2Ugb2JqZWN0LlxyXG4gKiBAcGFyYW0ge2Jvb2xlYW59IGlzU1ZHIC0gRGV0ZXJtaW5lcyB3aGV0aGVyIHRoZSBjaGFydCBiZWluZyBwcm9jZXNzZWRcclxuICogaXMgYW4gU1ZHIG9yIGFub3RoZXIgZm9ybWF0LlxyXG4gKiBAcGFyYW0ge251bWJlcn0gc2NhbGUgLSBUaGUgc2NhbGUgZmFjdG9yIHRvIGJlIGFwcGxpZWQgdG8gdGhlIGNoYXJ0XHJcbiAqIGRpbWVuc2lvbnMuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtQcm9taXNlPE9iamVjdD59IEEgUHJvbWlzZSB0aGF0IHJlc29sdmVzIHRvIGFuIG9iamVjdCBjb250YWluaW5nXHJcbiAqIHRoZSBhY3R1YWwgaGVpZ2h0IGFuZCB3aWR0aCBvZiB0aGUgY2hhcnQgYWZ0ZXIgc2NhbGluZy5cclxuICovXHJcbmFzeW5jIGZ1bmN0aW9uIF9nZXRDaGFydFNpemUocGFnZSwgaXNTVkcsIHNjYWxlKSB7XHJcbiAgLy8gVHJpZ2dlciBhcHByb3ByaWF0ZSBmdW5jdGlvbiBiYXNlZCBvbiB0aGUgYGlzU3ZnYCBmbGFnIHRvIGdldCBjaGFydCBzaXplXHJcbiAgcmV0dXJuIGlzU1ZHXHJcbiAgICA/IGF3YWl0IHBhZ2UuZXZhbHVhdGUoKHNjYWxlKSA9PiB7XHJcbiAgICAgICAgY29uc3Qgc3ZnRWxlbWVudCA9IGRvY3VtZW50LnF1ZXJ5U2VsZWN0b3IoXHJcbiAgICAgICAgICAnI2NoYXJ0LWNvbnRhaW5lciBzdmc6Zmlyc3Qtb2YtdHlwZSdcclxuICAgICAgICApO1xyXG5cclxuICAgICAgICAvLyBHZXQgdGhlIHZhbHVlcyBjb3JyZWN0bHkgc2NhbGVkXHJcbiAgICAgICAgY29uc3QgY2hhcnRIZWlnaHQgPSBzdmdFbGVtZW50LmhlaWdodC5iYXNlVmFsLnZhbHVlICogc2NhbGU7XHJcbiAgICAgICAgY29uc3QgY2hhcnRXaWR0aCA9IHN2Z0VsZW1lbnQud2lkdGguYmFzZVZhbC52YWx1ZSAqIHNjYWxlO1xyXG5cclxuICAgICAgICAvLyBJbiBjYXNlIG9mIFNWRyB0aGUgem9vbSBtdXN0IGJlIHNldCBkaXJlY3RseSBmb3IgYm9keSBhcyBzY2FsZVxyXG4gICAgICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBuby11bmRlZlxyXG4gICAgICAgIGRvY3VtZW50LmJvZHkuc3R5bGUuem9vbSA9IHNjYWxlO1xyXG5cclxuICAgICAgICAvLyBTZXQgdGhlIG1hcmdpbiB0byAwcHhcclxuICAgICAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgbm8tdW5kZWZcclxuICAgICAgICBkb2N1bWVudC5ib2R5LnN0eWxlLm1hcmdpbiA9ICcwcHgnO1xyXG5cclxuICAgICAgICByZXR1cm4ge1xyXG4gICAgICAgICAgY2hhcnRIZWlnaHQsXHJcbiAgICAgICAgICBjaGFydFdpZHRoXHJcbiAgICAgICAgfTtcclxuICAgICAgfSwgcGFyc2VGbG9hdChzY2FsZSkpXHJcbiAgICA6IGF3YWl0IHBhZ2UuZXZhbHVhdGUoKCkgPT4ge1xyXG4gICAgICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBuby11bmRlZlxyXG4gICAgICAgIGNvbnN0IHsgY2hhcnRIZWlnaHQsIGNoYXJ0V2lkdGggfSA9IHdpbmRvdy5IaWdoY2hhcnRzLmNoYXJ0c1swXTtcclxuXHJcbiAgICAgICAgLy8gTm8gbmVlZCBmb3Igc3VjaCBzY2FsZSBtYW5pcHVsYXRpb24gaW4gY2FzZSBvZiBvdGhlciB0eXBlc1xyXG4gICAgICAgIC8vIG9mIGV4cG9ydHMuIFJlc2V0IHRoZSB6b29tIGZvciBvdGhlciBleHBvcnRzIHRoYW4gdG8gU1ZHc1xyXG4gICAgICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBuby11bmRlZlxyXG4gICAgICAgIGRvY3VtZW50LmJvZHkuc3R5bGUuem9vbSA9IDE7XHJcblxyXG4gICAgICAgIHJldHVybiB7XHJcbiAgICAgICAgICBjaGFydEhlaWdodCxcclxuICAgICAgICAgIGNoYXJ0V2lkdGhcclxuICAgICAgICB9O1xyXG4gICAgICB9KTtcclxufVxyXG5cclxuLyoqXHJcbiAqIENyZWF0ZXMgYW4gU1ZHIGJ5IGV2YWx1YXRpbmcgdGhlIGBvdXRlckhUTUxgIG9mIHRoZSBmaXJzdCAnc3ZnJyBlbGVtZW50XHJcbiAqIGluc2lkZSBhbiBlbGVtZW50IHdpdGggdGhlIGlkICdjb250YWluZXInLlxyXG4gKlxyXG4gKiBAYXN5bmNcclxuICogQGZ1bmN0aW9uIF9jcmVhdGVTVkdcclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IHBhZ2UgLSBQdXBwZXRlZXIgcGFnZSBvYmplY3QuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtQcm9taXNlPHN0cmluZz59IEEgUHJvbWlzZSB0aGF0IHJlc29sdmVzIHRvIHRoZSBTVkcgc3RyaW5nLlxyXG4gKi9cclxuYXN5bmMgZnVuY3Rpb24gX2NyZWF0ZVNWRyhwYWdlKSB7XHJcbiAgcmV0dXJuIHBhZ2UuJGV2YWwoXHJcbiAgICAnI2NvbnRhaW5lciBzdmc6Zmlyc3Qtb2YtdHlwZScsXHJcbiAgICAoZWxlbWVudCkgPT4gZWxlbWVudC5vdXRlckhUTUxcclxuICApO1xyXG59XHJcblxyXG4vKipcclxuICogQ3JlYXRlcyBhbiBpbWFnZSB1c2luZyBQdXBwZXRlZXIncyBwYWdlIGBzY3JlZW5zaG90YCBmdW5jdGlvbmFsaXR5IHdpdGhcclxuICogc3BlY2lmaWVkIG9wdGlvbnMuXHJcbiAqXHJcbiAqIEBhc3luY1xyXG4gKiBAZnVuY3Rpb24gX2NyZWF0ZUltYWdlXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBwYWdlIC0gUHVwcGV0ZWVyIHBhZ2Ugb2JqZWN0LlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gdHlwZSAtIEltYWdlIHR5cGUuXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBjbGlwIC0gQ2xpcHBpbmcgcmVnaW9uIGNvb3JkaW5hdGVzLlxyXG4gKiBAcGFyYW0ge251bWJlcn0gcmFzdGVyaXphdGlvblRpbWVvdXQgLSBUaW1lb3V0IGZvciByYXN0ZXJpemF0aW9uXHJcbiAqIGluIG1pbGxpc2Vjb25kcy5cclxuICpcclxuICogQHJldHVybnMge1Byb21pc2U8QnVmZmVyPn0gQSBQcm9taXNlIHRoYXQgcmVzb2x2ZXMgdG8gdGhlIGltYWdlIGJ1ZmZlclxyXG4gKiBvciByZWplY3Rpbmcgd2l0aCBhbiBgRXhwb3J0RXJyb3JgIGZvciB0aW1lb3V0LlxyXG4gKi9cclxuYXN5bmMgZnVuY3Rpb24gX2NyZWF0ZUltYWdlKHBhZ2UsIHR5cGUsIGNsaXAsIHJhc3Rlcml6YXRpb25UaW1lb3V0KSB7XHJcbiAgcmV0dXJuIFByb21pc2UucmFjZShbXHJcbiAgICBwYWdlLnNjcmVlbnNob3Qoe1xyXG4gICAgICB0eXBlLFxyXG4gICAgICBjbGlwLFxyXG4gICAgICBlbmNvZGluZzogJ2Jhc2U2NCcsXHJcbiAgICAgIGZ1bGxQYWdlOiBmYWxzZSxcclxuICAgICAgb3B0aW1pemVGb3JTcGVlZDogdHJ1ZSxcclxuICAgICAgY2FwdHVyZUJleW9uZFZpZXdwb3J0OiB0cnVlLFxyXG4gICAgICAuLi4odHlwZSAhPT0gJ3BuZycgPyB7IHF1YWxpdHk6IDgwIH0gOiB7fSksXHJcbiAgICAgIC8vIEFsd2F5cyByZW5kZXIgb24gYSB0cmFuc3BhcmVudCBwYWdlIGlmIHRoZSBleHBlY3RlZCB0eXBlIGZvcm1hdCBpcyBQTkdcclxuICAgICAgb21pdEJhY2tncm91bmQ6IHR5cGUgPT0gJ3BuZycgLy8gIzQ0NywgIzQ2M1xyXG4gICAgfSksXHJcbiAgICBuZXcgUHJvbWlzZSgoX3Jlc29sdmUsIHJlamVjdCkgPT5cclxuICAgICAgc2V0VGltZW91dChcclxuICAgICAgICAoKSA9PiByZWplY3QobmV3IEV4cG9ydEVycm9yKCdSYXN0ZXJpemF0aW9uIHRpbWVvdXQnLCA0MDgpKSxcclxuICAgICAgICByYXN0ZXJpemF0aW9uVGltZW91dCB8fCAxNTAwXHJcbiAgICAgIClcclxuICAgIClcclxuICBdKTtcclxufVxyXG5cclxuLyoqXHJcbiAqIENyZWF0ZXMgYSBQREYgdXNpbmcgUHVwcGV0ZWVyJ3MgcGFnZSBgcGRmYCBmdW5jdGlvbmFsaXR5IHdpdGggc3BlY2lmaWVkXHJcbiAqIG9wdGlvbnMuXHJcbiAqXHJcbiAqIEBhc3luY1xyXG4gKiBAZnVuY3Rpb24gX2NyZWF0ZVBERlxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gcGFnZSAtIFB1cHBldGVlciBwYWdlIG9iamVjdC5cclxuICogQHBhcmFtIHtudW1iZXJ9IGhlaWdodCAtIFBERiBoZWlnaHQuXHJcbiAqIEBwYXJhbSB7bnVtYmVyfSB3aWR0aCAtIFBERiB3aWR0aC5cclxuICogQHBhcmFtIHtudW1iZXJ9IHJhc3Rlcml6YXRpb25UaW1lb3V0IC0gVGltZW91dCBmb3IgcmFzdGVyaXphdGlvblxyXG4gKiBpbiBtaWxsaXNlY29uZHMuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtQcm9taXNlPEJ1ZmZlcj59IEEgUHJvbWlzZSB0aGF0IHJlc29sdmVzIHRvIHRoZSBQREYgYnVmZmVyLlxyXG4gKi9cclxuYXN5bmMgZnVuY3Rpb24gX2NyZWF0ZVBERihwYWdlLCBoZWlnaHQsIHdpZHRoLCByYXN0ZXJpemF0aW9uVGltZW91dCkge1xyXG4gIGF3YWl0IHBhZ2UuZW11bGF0ZU1lZGlhVHlwZSgnc2NyZWVuJyk7XHJcbiAgcmV0dXJuIHBhZ2UucGRmKHtcclxuICAgIC8vIFRoaXMgd2lsbCByZW1vdmUgYW4gZXh0cmEgZW1wdHkgcGFnZSBpbiBQREYgZXhwb3J0c1xyXG4gICAgaGVpZ2h0OiBoZWlnaHQgKyAxLFxyXG4gICAgd2lkdGgsXHJcbiAgICBlbmNvZGluZzogJ2Jhc2U2NCcsXHJcbiAgICB0aW1lb3V0OiByYXN0ZXJpemF0aW9uVGltZW91dCB8fCAxNTAwXHJcbiAgfSk7XHJcbn1cclxuXHJcbmV4cG9ydCBkZWZhdWx0IHtcclxuICBwdXBwZXRlZXJFeHBvcnRcclxufTtcclxuIiwiLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcclxuXHJcbkhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlclxyXG5cclxuQ29weXJpZ2h0IChjKSAyMDE2LTIwMjUsIEhpZ2hzb2Z0XHJcblxyXG5MaWNlbmNlZCB1bmRlciB0aGUgTUlUIGxpY2VuY2UuXHJcblxyXG5BZGRpdGlvbmFsbHkgYSB2YWxpZCBIaWdoY2hhcnRzIGxpY2Vuc2UgaXMgcmVxdWlyZWQgZm9yIHVzZS5cclxuXHJcblNlZSBMSUNFTlNFIGZpbGUgaW4gcm9vdCBmb3IgZGV0YWlscy5cclxuXHJcbioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXHJcblxyXG4vKipcclxuICogQG92ZXJ2aWV3IFRoaXMgbW9kdWxlIHByb3ZpZGVzIGEgd29ya2VyIHBvb2wgaW1wbGVtZW50YXRpb24gZm9yIG1hbmFnaW5nXHJcbiAqIHRoZSBicm93c2VyIGluc3RhbmNlIGFuZCBwYWdlcywgc3BlY2lmaWNhbGx5IGRlc2lnbmVkIGZvciB1c2Ugd2l0aFxyXG4gKiB0aGUgSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyLiBJdCBvcHRpbWl6ZXMgcmVzb3VyY2VzIHVzYWdlIGFuZCBwZXJmb3JtYW5jZVxyXG4gKiBieSBtYWludGFpbmluZyBhIHBvb2wgb2Ygd29ya2VycyB0aGF0IGNhbiBoYW5kbGUgY29uY3VycmVudCBleHBvcnQgdGFza3NcclxuICogdXNpbmcgUHVwcGV0ZWVyLlxyXG4gKi9cclxuXHJcbmltcG9ydCB7IFBvb2wgfSBmcm9tICd0YXJuJztcclxuaW1wb3J0IHsgdjQgYXMgdXVpZCB9IGZyb20gJ3V1aWQnO1xyXG5cclxuaW1wb3J0IHsgY2xlYXJQYWdlLCBjcmVhdGVCcm93c2VyLCBjbG9zZUJyb3dzZXIsIG5ld1BhZ2UgfSBmcm9tICcuL2Jyb3dzZXIuanMnO1xyXG5pbXBvcnQgeyBwdXBwZXRlZXJFeHBvcnQgfSBmcm9tICcuL2V4cG9ydC5qcyc7XHJcbmltcG9ydCB7IGxvZywgbG9nV2l0aFN0YWNrIH0gZnJvbSAnLi9sb2dnZXIuanMnO1xyXG5pbXBvcnQgeyBnZXROZXdEYXRlVGltZSwgbWVhc3VyZVRpbWUgfSBmcm9tICcuL3V0aWxzLmpzJztcclxuXHJcbmltcG9ydCBFeHBvcnRFcnJvciBmcm9tICcuL2Vycm9ycy9FeHBvcnRFcnJvci5qcyc7XHJcblxyXG4vLyBUaGUgcG9vbCBpbnN0YW5jZVxyXG5sZXQgcG9vbCA9IG51bGw7XHJcblxyXG4vLyBQb29sIHN0YXRpc3RpY3NcclxuY29uc3QgcG9vbFN0YXRzID0ge1xyXG4gIGV4cG9ydHNBdHRlbXB0ZWQ6IDAsXHJcbiAgZXhwb3J0c1BlcmZvcm1lZDogMCxcclxuICBleHBvcnRzRHJvcHBlZDogMCxcclxuICBleHBvcnRzRnJvbVN2ZzogMCxcclxuICBleHBvcnRzRnJvbU9wdGlvbnM6IDAsXHJcbiAgZXhwb3J0c0Zyb21TdmdBdHRlbXB0czogMCxcclxuICBleHBvcnRzRnJvbU9wdGlvbnNBdHRlbXB0czogMCxcclxuICB0aW1lU3BlbnQ6IDAsXHJcbiAgdGltZVNwZW50QXZlcmFnZTogMFxyXG59O1xyXG5cclxuLyoqXHJcbiAqIEluaXRpYWxpemVzIHRoZSBleHBvcnQgcG9vbCB3aXRoIHRoZSBwcm92aWRlZCBjb25maWd1cmF0aW9uLCBjcmVhdGluZ1xyXG4gKiBhIGJyb3dzZXIgaW5zdGFuY2UgYW5kIHNldHRpbmcgdXAgd29ya2VyIHJlc291cmNlcy5cclxuICpcclxuICogQGFzeW5jXHJcbiAqIEBmdW5jdGlvbiBpbml0UG9vbFxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gcG9vbE9wdGlvbnMgLSBUaGUgY29uZmlndXJhdGlvbiBvYmplY3QgY29udGFpbmluZyBgcG9vbGBcclxuICogb3B0aW9ucy5cclxuICogQHBhcmFtIHtBcnJheTxzdHJpbmc+fSBwdXBwZXRlZXJBcmdzIC0gQWRkaXRpb25hbCBhcmd1bWVudHMgZm9yIFB1cHBldGVlclxyXG4gKiBsYXVuY2guXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtQcm9taXNlPHZvaWQ+fSBBIFByb21pc2UgdGhhdCByZXNvbHZlcyB0byBlbmRpbmcgdGhlIGZ1bmN0aW9uXHJcbiAqIGV4ZWN1dGlvbiB3aGVuIGFuIGFscmVhZHkgaW5pdGlhbGl6ZWQgcG9vbCBvZiByZXNvdXJjZXMgaXMgZm91bmQuXHJcbiAqXHJcbiAqIEB0aHJvd3Mge0V4cG9ydEVycm9yfSBUaHJvd3MgYW4gYEV4cG9ydEVycm9yYCBpZiBjb3VsZCBub3QgY3JlYXRlIHRoZSBwb29sXHJcbiAqIG9mIHdvcmtlcnMuXHJcbiAqL1xyXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gaW5pdFBvb2wocG9vbE9wdGlvbnMsIHB1cHBldGVlckFyZ3MpIHtcclxuICAvLyBDcmVhdGUgYSBicm93c2VyIGluc3RhbmNlIHdpdGggdGhlIHB1cHBldGVlciBhcmd1bWVudHNcclxuICBhd2FpdCBjcmVhdGVCcm93c2VyKHB1cHBldGVlckFyZ3MpO1xyXG5cclxuICB0cnkge1xyXG4gICAgbG9nKFxyXG4gICAgICAzLFxyXG4gICAgICBgW3Bvb2xdIEluaXRpYWxpemluZyBwb29sIHdpdGggd29ya2VyczogbWluICR7cG9vbE9wdGlvbnMubWluV29ya2Vyc30sIG1heCAke3Bvb2xPcHRpb25zLm1heFdvcmtlcnN9LmBcclxuICAgICk7XHJcblxyXG4gICAgaWYgKHBvb2wpIHtcclxuICAgICAgbG9nKFxyXG4gICAgICAgIDQsXHJcbiAgICAgICAgJ1twb29sXSBBbHJlYWR5IGluaXRpYWxpemVkLCBwbGVhc2Uga2lsbCBpdCBiZWZvcmUgY3JlYXRpbmcgYSBuZXcgb25lLidcclxuICAgICAgKTtcclxuICAgICAgcmV0dXJuO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIEtlZXAgYW4gZXllIG9uIGEgY29ycmVjdCBtaW4gYW5kIG1heCB3b3JrZXJzIG51bWJlclxyXG4gICAgaWYgKHBvb2xPcHRpb25zLm1pbldvcmtlcnMgPiBwb29sT3B0aW9ucy5tYXhXb3JrZXJzKSB7XHJcbiAgICAgIHBvb2xPcHRpb25zLm1pbldvcmtlcnMgPSBwb29sT3B0aW9ucy5tYXhXb3JrZXJzO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIENyZWF0ZSBhIHBvb2wgYWxvbmcgd2l0aCBhIG1pbmltYWwgbnVtYmVyIG9mIHJlc291cmNlc1xyXG4gICAgcG9vbCA9IG5ldyBQb29sKHtcclxuICAgICAgLy8gR2V0IHRoZSBgY3JlYXRlYCwgYHZhbGlkYXRlYCwgYW5kIGBkZXN0cm95YCBmdW5jdGlvbnNcclxuICAgICAgLi4uX2ZhY3RvcnkocG9vbE9wdGlvbnMpLFxyXG4gICAgICBtaW46IHBvb2xPcHRpb25zLm1pbldvcmtlcnMsXHJcbiAgICAgIG1heDogcG9vbE9wdGlvbnMubWF4V29ya2VycyxcclxuICAgICAgYWNxdWlyZVRpbWVvdXRNaWxsaXM6IHBvb2xPcHRpb25zLmFjcXVpcmVUaW1lb3V0LFxyXG4gICAgICBjcmVhdGVUaW1lb3V0TWlsbGlzOiBwb29sT3B0aW9ucy5jcmVhdGVUaW1lb3V0LFxyXG4gICAgICBkZXN0cm95VGltZW91dE1pbGxpczogcG9vbE9wdGlvbnMuZGVzdHJveVRpbWVvdXQsXHJcbiAgICAgIGlkbGVUaW1lb3V0TWlsbGlzOiBwb29sT3B0aW9ucy5pZGxlVGltZW91dCxcclxuICAgICAgY3JlYXRlUmV0cnlJbnRlcnZhbE1pbGxpczogcG9vbE9wdGlvbnMuY3JlYXRlUmV0cnlJbnRlcnZhbCxcclxuICAgICAgcmVhcEludGVydmFsTWlsbGlzOiBwb29sT3B0aW9ucy5yZWFwZXJJbnRlcnZhbCxcclxuICAgICAgcHJvcGFnYXRlQ3JlYXRlRXJyb3I6IGZhbHNlXHJcbiAgICB9KTtcclxuXHJcbiAgICAvLyBTZXQgZXZlbnRzXHJcbiAgICBwb29sLm9uKCdyZWxlYXNlJywgYXN5bmMgKHJlc291cmNlKSA9PiB7XHJcbiAgICAgIC8vIENsZWFyIHBhZ2VcclxuICAgICAgY29uc3QgY2xlYXJTdGF0dXMgPSBhd2FpdCBjbGVhclBhZ2UocmVzb3VyY2UsIGZhbHNlKTtcclxuICAgICAgbG9nKFxyXG4gICAgICAgIDQsXHJcbiAgICAgICAgYFtwb29sXSBQb29sIHJlc291cmNlIFske3Jlc291cmNlLmlkfV0gLSBSZWxlYXNpbmcgYSB3b3JrZXIuIENsZWFyIHBhZ2Ugc3RhdHVzOiAke2NsZWFyU3RhdHVzfS5gXHJcbiAgICAgICk7XHJcbiAgICB9KTtcclxuXHJcbiAgICBwb29sLm9uKCdkZXN0cm95U3VjY2VzcycsIChfZXZlbnRJZCwgcmVzb3VyY2UpID0+IHtcclxuICAgICAgbG9nKFxyXG4gICAgICAgIDQsXHJcbiAgICAgICAgYFtwb29sXSBQb29sIHJlc291cmNlIFske3Jlc291cmNlLmlkfV0gLSBEZXN0cm95ZWQgYSB3b3JrZXIgc3VjY2Vzc2Z1bGx5LmBcclxuICAgICAgKTtcclxuICAgICAgcmVzb3VyY2UucGFnZSA9IG51bGw7XHJcbiAgICB9KTtcclxuXHJcbiAgICBjb25zdCBpbml0aWFsUmVzb3VyY2VzID0gW107XHJcbiAgICAvLyBDcmVhdGUgYW4gaW5pdGlhbCBudW1iZXIgb2YgcmVzb3VyY2VzXHJcbiAgICBmb3IgKGxldCBpID0gMDsgaSA8IHBvb2xPcHRpb25zLm1pbldvcmtlcnM7IGkrKykge1xyXG4gICAgICB0cnkge1xyXG4gICAgICAgIGNvbnN0IHJlc291cmNlID0gYXdhaXQgcG9vbC5hY3F1aXJlKCkucHJvbWlzZTtcclxuICAgICAgICBpbml0aWFsUmVzb3VyY2VzLnB1c2gocmVzb3VyY2UpO1xyXG4gICAgICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgICAgIGxvZ1dpdGhTdGFjaygyLCBlcnJvciwgJ1twb29sXSBDb3VsZCBub3QgY3JlYXRlIGFuIGluaXRpYWwgcmVzb3VyY2UuJyk7XHJcbiAgICAgIH1cclxuICAgIH1cclxuXHJcbiAgICAvLyBSZWxlYXNlIHRoZSBpbml0aWFsIG51bWJlciBvZiByZXNvdXJjZXMgYmFjayB0byB0aGUgcG9vbFxyXG4gICAgaW5pdGlhbFJlc291cmNlcy5mb3JFYWNoKChyZXNvdXJjZSkgPT4ge1xyXG4gICAgICBwb29sLnJlbGVhc2UocmVzb3VyY2UpO1xyXG4gICAgfSk7XHJcblxyXG4gICAgbG9nKFxyXG4gICAgICAzLFxyXG4gICAgICBgW3Bvb2xdIFRoZSBwb29sIGlzIHJlYWR5JHtpbml0aWFsUmVzb3VyY2VzLmxlbmd0aCA/IGAgd2l0aCAke2luaXRpYWxSZXNvdXJjZXMubGVuZ3RofSBpbml0aWFsIHJlc291cmNlcyB3YWl0aW5nLmAgOiAnLid9YFxyXG4gICAgKTtcclxuICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgdGhyb3cgbmV3IEV4cG9ydEVycm9yKFxyXG4gICAgICAnW3Bvb2xdIENvdWxkIG5vdCBjb25maWd1cmUgYW5kIGNyZWF0ZSB0aGUgcG9vbCBvZiB3b3JrZXJzLicsXHJcbiAgICAgIDUwMFxyXG4gICAgKS5zZXRFcnJvcihlcnJvcik7XHJcbiAgfVxyXG59XHJcblxyXG4vKipcclxuICogVGVybWluYXRlcyBhbGwgd29ya2VycyBpbiB0aGUgcG9vbCwgZGVzdHJveXMgdGhlIHBvb2wsIGFuZCBjbG9zZXMgdGhlIGJyb3dzZXJcclxuICogaW5zdGFuY2UuXHJcbiAqXHJcbiAqIEBhc3luY1xyXG4gKiBAZnVuY3Rpb24ga2lsbFBvb2xcclxuICpcclxuICogQHJldHVybnMge1Byb21pc2U8dm9pZD59IEEgUHJvbWlzZSB0aGF0IHJlc29sdmVzIG9uY2UgYWxsIHdvcmtlcnMgYXJlXHJcbiAqIHRlcm1pbmF0ZWQsIHRoZSBwb29sIGlzIGRlc3Ryb3llZCwgYW5kIHRoZSBicm93c2VyIGlzIHN1Y2Nlc3NmdWxseSBjbG9zZWQuXHJcbiAqL1xyXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24ga2lsbFBvb2woKSB7XHJcbiAgbG9nKDMsICdbcG9vbF0gS2lsbGluZyBwb29sIHdpdGggYWxsIHdvcmtlcnMgYW5kIGNsb3NpbmcgYnJvd3Nlci4nKTtcclxuXHJcbiAgLy8gSWYgc3RpbGwgYWxpdmUsIGRlc3Ryb3kgdGhlIHBvb2wgb2YgcGFnZXMgYmVmb3JlIGNsb3NpbmcgYSBicm93c2VyXHJcbiAgaWYgKHBvb2wpIHtcclxuICAgIC8vIEZyZWUgdXAgbm90IHJlbGVhc2VkIHdvcmtlcnNcclxuICAgIGZvciAoY29uc3Qgd29ya2VyIG9mIHBvb2wudXNlZCkge1xyXG4gICAgICBwb29sLnJlbGVhc2Uod29ya2VyLnJlc291cmNlKTtcclxuICAgIH1cclxuXHJcbiAgICAvLyBEZXN0cm95IHRoZSBwb29sIGlmIGl0IGlzIHN0aWxsIGF2YWlsYWJsZVxyXG4gICAgaWYgKCFwb29sLmRlc3Ryb3llZCkge1xyXG4gICAgICBhd2FpdCBwb29sLmRlc3Ryb3koKTtcclxuICAgICAgbG9nKDQsICdbcG9vbF0gRGVzdHJveWVkIHRoZSBwb29sIG9mIHJlc291cmNlcy4nKTtcclxuICAgIH1cclxuICAgIHBvb2wgPSBudWxsO1xyXG4gIH1cclxuXHJcbiAgLy8gQ2xvc2UgdGhlIGJyb3dzZXIgaW5zdGFuY2VcclxuICBhd2FpdCBjbG9zZUJyb3dzZXIoKTtcclxufVxyXG5cclxuLyoqXHJcbiAqIFByb2Nlc3NlcyB0aGUgZXhwb3J0IHdvcmsgdXNpbmcgYSB3b3JrZXIgZnJvbSB0aGUgcG9vbC4gQWNxdWlyZXMgYSB3b3JrZXJcclxuICogaGFuZGxlIGZyb20gdGhlIHBvb2wsIHBlcmZvcm1zIHRoZSBleHBvcnQgdXNpbmcgcHVwcGV0ZWVyLCBhbmQgcmVsZWFzZXNcclxuICogdGhlIHdvcmtlciBoYW5kbGUgYmFjayB0byB0aGUgcG9vbC5cclxuICpcclxuICogQGFzeW5jXHJcbiAqIEBmdW5jdGlvbiBwb3N0V29ya1xyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gb3B0aW9ucyAtIFRoZSBjb25maWd1cmF0aW9uIG9iamVjdCBjb250YWluaW5nIGNvbXBsZXRlIHNldFxyXG4gKiBvZiBvcHRpb25zLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7UHJvbWlzZTxPYmplY3Q+fSBBIFByb21pc2UgdGhhdCByZXNvbHZlcyB0byB0aGUgZXhwb3J0IHJlc3VsdFxyXG4gKiBhbmQgb3B0aW9ucy5cclxuICpcclxuICogQHRocm93cyB7RXhwb3J0RXJyb3J9IFRocm93cyBhbiBgRXhwb3J0RXJyb3JgIGlmIGFuIGVycm9yIG9jY3VycyBkdXJpbmdcclxuICogdGhlIGV4cG9ydCBwcm9jZXNzLlxyXG4gKi9cclxuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIHBvc3RXb3JrKG9wdGlvbnMpIHtcclxuICBsZXQgd29ya2VySGFuZGxlO1xyXG5cclxuICB0cnkge1xyXG4gICAgbG9nKDQsICdbcG9vbF0gV29yayByZWNlaXZlZCwgc3RhcnRpbmcgdG8gcHJvY2Vzcy4nKTtcclxuXHJcbiAgICAvLyBBbiBleHBvcnQgYXR0ZW1wdCBjb3VudGVkXHJcbiAgICArK3Bvb2xTdGF0cy5leHBvcnRzQXR0ZW1wdGVkO1xyXG5cclxuICAgIC8vIERpc3BsYXkgdGhlIHBvb2wgaW5mb3JtYXRpb24gaWYgbmVlZGVkXHJcbiAgICBpZiAob3B0aW9ucy5wb29sLmJlbmNobWFya2luZykge1xyXG4gICAgICBfZ2V0UG9vbEluZm8oKTtcclxuICAgIH1cclxuXHJcbiAgICAvLyBUaHJvdyBhbiBlcnJvciBpbiBjYXNlIG9mIGxhY2tpbmcgdGhlIHBvb2wgaW5zdGFuY2VcclxuICAgIGlmICghcG9vbCkge1xyXG4gICAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoXHJcbiAgICAgICAgJ1twb29sXSBXb3JrIHJlY2VpdmVkLCBidXQgcG9vbCBoYXMgbm90IGJlZW4gc3RhcnRlZC4nLFxyXG4gICAgICAgIDUwMFxyXG4gICAgICApO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIFRoZSBhY3F1aXJlIGNvdW50ZXJcclxuICAgIGNvbnN0IGFjcXVpcmVDb3VudGVyID0gbWVhc3VyZVRpbWUoKTtcclxuXHJcbiAgICAvLyBUcnkgdG8gYWNxdWlyZSB0aGUgd29ya2VyIGFsb25nIHdpdGggdGhlIGlkLCB3b3JrcyBjb3VudCBhbmQgcGFnZVxyXG4gICAgdHJ5IHtcclxuICAgICAgbG9nKDQsICdbcG9vbF0gQWNxdWlyaW5nIGEgd29ya2VyIGhhbmRsZS4nKTtcclxuXHJcbiAgICAgIC8vIEFjcXVpcmUgYSBwb29sIHJlc291cmNlXHJcbiAgICAgIHdvcmtlckhhbmRsZSA9IGF3YWl0IHBvb2wuYWNxdWlyZSgpLnByb21pc2U7XHJcblxyXG4gICAgICAvLyBDaGVjayB0aGUgcGFnZSBhY3F1aXJlIHRpbWVcclxuICAgICAgaWYgKG9wdGlvbnMuc2VydmVyLmJlbmNobWFya2luZykge1xyXG4gICAgICAgIGxvZyhcclxuICAgICAgICAgIDUsXHJcbiAgICAgICAgICBgW2JlbmNobWFya10gJHtvcHRpb25zLnJlcXVlc3RJZCA/IGBSZXF1ZXN0IFske29wdGlvbnMucmVxdWVzdElkfV0gLSBgIDogJyd9YCxcclxuICAgICAgICAgIGBBY3F1aXJpbmcgYSB3b3JrZXIgaGFuZGxlIHRvb2sgJHthY3F1aXJlQ291bnRlcigpfW1zLmBcclxuICAgICAgICApO1xyXG4gICAgICB9XHJcbiAgICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoXHJcbiAgICAgICAgYFtwb29sXSAke1xyXG4gICAgICAgICAgb3B0aW9ucy5yZXF1ZXN0SWQgPyBgUmVxdWVzdCBbJHtvcHRpb25zLnJlcXVlc3RJZH1dIC0gYCA6ICcnXHJcbiAgICAgICAgfUVycm9yIGVuY291bnRlcmVkIHdoZW4gYWNxdWlyaW5nIGFuIGF2YWlsYWJsZSBlbnRyeTogJHthY3F1aXJlQ291bnRlcigpfW1zLmAsXHJcbiAgICAgICAgNDAwXHJcbiAgICAgICkuc2V0RXJyb3IoZXJyb3IpO1xyXG4gICAgfVxyXG4gICAgbG9nKDQsICdbcG9vbF0gQWNxdWlyZWQgYSB3b3JrZXIgaGFuZGxlLicpO1xyXG5cclxuICAgIGlmICghd29ya2VySGFuZGxlLnBhZ2UpIHtcclxuICAgICAgLy8gU2V0IHRoZSBgd29ya0xpbWl0YCB0byBleGNlZWRlZCBpbiBvcmRlciB0byByZWNyZWF0ZSB0aGUgcmVzb3VyY2VcclxuICAgICAgd29ya2VySGFuZGxlLndvcmtDb3VudCA9IG9wdGlvbnMucG9vbC53b3JrTGltaXQgKyAxO1xyXG4gICAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoXHJcbiAgICAgICAgJ1twb29sXSBSZXNvbHZlZCB3b3JrZXIgcGFnZSBpcyBpbnZhbGlkOiB0aGUgcG9vbCBzZXR1cCBpcyB3b25reS4nLFxyXG4gICAgICAgIDQwMFxyXG4gICAgICApO1xyXG4gICAgfVxyXG5cclxuICAgIGxvZyhcclxuICAgICAgNCxcclxuICAgICAgYFtwb29sXSBQb29sIHJlc291cmNlIFske3dvcmtlckhhbmRsZS5pZH1dIC0gU3RhcnRpbmcgd29yayBvbiB0aGlzIHBvb2wgZW50cnkuYFxyXG4gICAgKTtcclxuXHJcbiAgICAvLyBTdGFydCBtZWFzdXJpbmcgZXhwb3J0IHRpbWVcclxuICAgIGNvbnN0IGV4cG9ydENvdW50ZXIgPSBtZWFzdXJlVGltZSgpO1xyXG5cclxuICAgIC8vIFBlcmZvcm0gYW4gZXhwb3J0IG9uIGEgcHVwcGV0ZWVyIGxldmVsXHJcbiAgICBjb25zdCBleHBvcnRSZXN1bHQgPSBhd2FpdCBwdXBwZXRlZXJFeHBvcnQoXHJcbiAgICAgIHdvcmtlckhhbmRsZS5wYWdlLFxyXG4gICAgICBvcHRpb25zLmV4cG9ydCxcclxuICAgICAgb3B0aW9ucy5jdXN0b21Mb2dpY1xyXG4gICAgKTtcclxuXHJcbiAgICAvLyBDaGVjayBpZiBpdCdzIGFuIGVycm9yXHJcbiAgICBpZiAoZXhwb3J0UmVzdWx0IGluc3RhbmNlb2YgRXJyb3IpIHtcclxuICAgICAgLy8gTk9URTpcclxuICAgICAgLy8gSWYgdGhlcmUncyBhIHJhc3Rlcml6YXRpb24gdGltZW91dCwgd2Ugd2FudCBuZWVkIHRvIGZsdXNoIHRoZSBwYWdlLlxyXG4gICAgICAvLyBUaGlzIGlzIGJlY2F1c2UgdGhlIHBhZ2UgbWF5IGJlIGluIGEgc3RhdGUgd2hlcmUgaXQncyB3YWl0aW5nIGZvclxyXG4gICAgICAvLyB0aGUgc2NyZWVuc2hvdCB0byBmaW5pc2ggZXZlbiB0aG91Z2ggdGhlIHRpbWVvdXQgaGFzIG9jY3VyZWQuXHJcbiAgICAgIC8vIFdoaWNoIG9mIGNvdXJzZSBjYXVzZXMgYSBsb3Qgb2YgaXNzdWVzIHdpdGggdGhlIGV2ZW50IHN5c3RlbSxcclxuICAgICAgLy8gYW5kIHBhZ2UgY29uc2lzdGVuY3kuXHJcbiAgICAgIC8vXHJcbiAgICAgIC8vIE9ubHkgYHBhZ2Uuc2NyZWVuc2hvdGAgd2lsbCB0aHJvdyB0aGlzLCB0aW1lb3V0cyBmb3IgUERGJ3MgYXJlXHJcbiAgICAgIC8vIGhhbmRsZWQgYnkgdGhlIGBwYWdlLnBkZmAgZnVuY3Rpb24gaXRzZWxmLlxyXG4gICAgICAvL1xyXG4gICAgICAvLyAuLi55ZXMsIHRoaXMgaXMgdWdseS5cclxuICAgICAgaWYgKGV4cG9ydFJlc3VsdC5tZXNzYWdlID09PSAnUmFzdGVyaXphdGlvbiB0aW1lb3V0Jykge1xyXG4gICAgICAgIC8vIFNldCB0aGUgYHdvcmtMaW1pdGAgdG8gZXhjZWVkZWQgaW4gb3JkZXIgdG8gcmVjcmVhdGUgdGhlIHJlc291cmNlXHJcbiAgICAgICAgd29ya2VySGFuZGxlLndvcmtDb3VudCA9IG9wdGlvbnMucG9vbC53b3JrTGltaXQgKyAxO1xyXG4gICAgICAgIHdvcmtlckhhbmRsZS5wYWdlID0gbnVsbDtcclxuICAgICAgfVxyXG5cclxuICAgICAgaWYgKFxyXG4gICAgICAgIGV4cG9ydFJlc3VsdC5uYW1lID09PSAnVGltZW91dEVycm9yJyB8fFxyXG4gICAgICAgIGV4cG9ydFJlc3VsdC5tZXNzYWdlID09PSAnUmFzdGVyaXphdGlvbiB0aW1lb3V0J1xyXG4gICAgICApIHtcclxuICAgICAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoXHJcbiAgICAgICAgICBgW3Bvb2xdICR7XHJcbiAgICAgICAgICAgIG9wdGlvbnMucmVxdWVzdElkID8gYFJlcXVlc3QgWyR7b3B0aW9ucy5yZXF1ZXN0SWR9XSAtIGAgOiAnJ1xyXG4gICAgICAgICAgfVJhc3Rlcml6YXRpb24gdGltZW91dDogeW91ciBjaGFydCBtYXkgYmUgdG9vIGNvbXBsZXggb3IgbGFyZ2UsIGFuZCBmYWlsZWQgdG8gcmVuZGVyIHdpdGhpbiB0aGUgYWxsb3R0ZWQgdGltZS5gXHJcbiAgICAgICAgKS5zZXRFcnJvcihleHBvcnRSZXN1bHQpO1xyXG4gICAgICB9IGVsc2Uge1xyXG4gICAgICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcihcclxuICAgICAgICAgIGBbcG9vbF0gJHtcclxuICAgICAgICAgICAgb3B0aW9ucy5yZXF1ZXN0SWQgPyBgUmVxdWVzdCBbJHtvcHRpb25zLnJlcXVlc3RJZH1dIC0gYCA6ICcnXHJcbiAgICAgICAgICB9RXJyb3IgZW5jb3VudGVyZWQgZHVyaW5nIGV4cG9ydDogJHtleHBvcnRDb3VudGVyKCl9bXMuYFxyXG4gICAgICAgICkuc2V0RXJyb3IoZXhwb3J0UmVzdWx0KTtcclxuICAgICAgfVxyXG4gICAgfVxyXG5cclxuICAgIC8vIENoZWNrIHRoZSBQdXBwZXRlZXIgZXhwb3J0IHRpbWVcclxuICAgIGlmIChvcHRpb25zLnNlcnZlci5iZW5jaG1hcmtpbmcpIHtcclxuICAgICAgbG9nKFxyXG4gICAgICAgIDUsXHJcbiAgICAgICAgYFtiZW5jaG1hcmtdICR7b3B0aW9ucy5yZXF1ZXN0SWQgPyBgUmVxdWVzdCBbJHtvcHRpb25zLnJlcXVlc3RJZH1dIC0gYCA6ICcnfWAsXHJcbiAgICAgICAgYEV4cG9ydGluZyBhIGNoYXJ0IHN1Y2Vzc2Z1bGx5IHRvb2sgJHtleHBvcnRDb3VudGVyKCl9bXMuYFxyXG4gICAgICApO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIFJlbGVhc2UgdGhlIHJlc291cmNlIGJhY2sgdG8gdGhlIHBvb2xcclxuICAgIHBvb2wucmVsZWFzZSh3b3JrZXJIYW5kbGUpO1xyXG5cclxuICAgIC8vIFVwZGF0ZSBzdGF0aXN0aWNzXHJcbiAgICBwb29sU3RhdHMudGltZVNwZW50ICs9IGV4cG9ydENvdW50ZXIoKTtcclxuICAgIHBvb2xTdGF0cy50aW1lU3BlbnRBdmVyYWdlID1cclxuICAgICAgcG9vbFN0YXRzLnRpbWVTcGVudCAvICsrcG9vbFN0YXRzLmV4cG9ydHNQZXJmb3JtZWQ7XHJcblxyXG4gICAgbG9nKDQsIGBbcG9vbF0gV29yayBjb21wbGV0ZWQgaW4gJHtleHBvcnRDb3VudGVyKCl9bXMuYCk7XHJcblxyXG4gICAgLy8gT3RoZXJ3aXNlIHJldHVybiBhbiBvYmplY3Qgd2l0aCB0aGUgcmVzdWx0IGFuZCBvcHRpb25zXHJcbiAgICByZXR1cm4ge1xyXG4gICAgICByZXN1bHQ6IGV4cG9ydFJlc3VsdCxcclxuICAgICAgb3B0aW9uc1xyXG4gICAgfTtcclxuICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgKytwb29sU3RhdHMuZXhwb3J0c0Ryb3BwZWQ7XHJcblxyXG4gICAgLy8gVHJ5IHRvIHJlbGVhc2UgdGhlIHdvcmtlciwgaWYgaXQgZXhpc3RzXHJcbiAgICBpZiAod29ya2VySGFuZGxlKSB7XHJcbiAgICAgIHBvb2wucmVsZWFzZSh3b3JrZXJIYW5kbGUpO1xyXG4gICAgfVxyXG5cclxuICAgIHRocm93IGVycm9yO1xyXG4gIH1cclxufVxyXG5cclxuLyoqXHJcbiAqIFJldHJpZXZlcyB0aGUgY3VycmVudCBwb29sIGluc3RhbmNlLlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gZ2V0UG9vbFxyXG4gKlxyXG4gKiBAcmV0dXJucyB7KE9iamVjdHxudWxsKX0gVGhlIGN1cnJlbnQgcG9vbCBpbnN0YW5jZSBpZiBpbml0aWFsaXplZCwgb3IgYG51bGxgXHJcbiAqIGlmIHRoZSBwb29sIGhhcyBub3QgYmVlbiBjcmVhdGVkLlxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIGdldFBvb2woKSB7XHJcbiAgcmV0dXJuIHBvb2w7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBHZXRzIHRoZSBzdGF0aXN0aWMgb2YgYSBwb29sIGluc3RhY2UgYWJvdXQgZXhwb3J0cy5cclxuICpcclxuICogQGZ1bmN0aW9uIGdldFBvb2xTdGF0c1xyXG4gKlxyXG4gKiBAcmV0dXJucyB7T2JqZWN0fSBUaGUgY3VycmVudCBwb29sIHN0YXRpc3RpY3MuXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gZ2V0UG9vbFN0YXRzKCkge1xyXG4gIHJldHVybiBwb29sU3RhdHM7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBSZXRyaWV2ZXMgcG9vbCBpbmZvcm1hdGlvbiBpbiBKU09OIGZvcm1hdCwgaW5jbHVkaW5nIG1pbmltdW0gYW5kIG1heGltdW1cclxuICogd29ya2VycywgYXZhaWxhYmxlIHdvcmtlcnMsIHdvcmtlcnMgaW4gdXNlLCBhbmQgcGVuZGluZyBhY3F1aXJlIHJlcXVlc3RzLlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gZ2V0UG9vbEluZm9KU09OXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtPYmplY3R9IFBvb2wgaW5mb3JtYXRpb24gaW4gSlNPTiBmb3JtYXQuXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gZ2V0UG9vbEluZm9KU09OKCkge1xyXG4gIHJldHVybiB7XHJcbiAgICBtaW46IHBvb2wubWluLFxyXG4gICAgbWF4OiBwb29sLm1heCxcclxuICAgIHVzZWQ6IHBvb2wubnVtVXNlZCgpLFxyXG4gICAgYXZhaWxhYmxlOiBwb29sLm51bUZyZWUoKSxcclxuICAgIGFsbENyZWF0ZWQ6IHBvb2wubnVtVXNlZCgpICsgcG9vbC5udW1GcmVlKCksXHJcbiAgICBwZW5kaW5nQWNxdWlyZXM6IHBvb2wubnVtUGVuZGluZ0FjcXVpcmVzKCksXHJcbiAgICBwZW5kaW5nQ3JlYXRlczogcG9vbC5udW1QZW5kaW5nQ3JlYXRlcygpLFxyXG4gICAgcGVuZGluZ1ZhbGlkYXRpb25zOiBwb29sLm51bVBlbmRpbmdWYWxpZGF0aW9ucygpLFxyXG4gICAgcGVuZGluZ0Rlc3Ryb3lzOiBwb29sLnBlbmRpbmdEZXN0cm95cy5sZW5ndGgsXHJcbiAgICBhYnNvbHV0ZUFsbDpcclxuICAgICAgcG9vbC5udW1Vc2VkKCkgK1xyXG4gICAgICBwb29sLm51bUZyZWUoKSArXHJcbiAgICAgIHBvb2wubnVtUGVuZGluZ0FjcXVpcmVzKCkgK1xyXG4gICAgICBwb29sLm51bVBlbmRpbmdDcmVhdGVzKCkgK1xyXG4gICAgICBwb29sLm51bVBlbmRpbmdWYWxpZGF0aW9ucygpICtcclxuICAgICAgcG9vbC5wZW5kaW5nRGVzdHJveXMubGVuZ3RoXHJcbiAgfTtcclxufVxyXG5cclxuLyoqXHJcbiAqIExvZ3MgaW5mb3JtYXRpb24gYWJvdXQgdGhlIGN1cnJlbnQgc3RhdGUgb2YgdGhlIHBvb2wsIGluY2x1ZGluZyB0aGUgbWluaW11bVxyXG4gKiBhbmQgbWF4aW11bSB3b3JrZXJzLCBhdmFpbGFibGUgd29ya2Vycywgd29ya2VycyBpbiB1c2UsIGFuZCBwZW5kaW5nIGFjcXVpcmVcclxuICogcmVxdWVzdHMuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBfZ2V0UG9vbEluZm9cclxuICovXHJcbmZ1bmN0aW9uIF9nZXRQb29sSW5mbygpIHtcclxuICBjb25zdCB7XHJcbiAgICBtaW4sXHJcbiAgICBtYXgsXHJcbiAgICB1c2VkLFxyXG4gICAgYXZhaWxhYmxlLFxyXG4gICAgYWxsQ3JlYXRlZCxcclxuICAgIHBlbmRpbmdBY3F1aXJlcyxcclxuICAgIHBlbmRpbmdDcmVhdGVzLFxyXG4gICAgcGVuZGluZ1ZhbGlkYXRpb25zLFxyXG4gICAgcGVuZGluZ0Rlc3Ryb3lzLFxyXG4gICAgYWJzb2x1dGVBbGxcclxuICB9ID0gZ2V0UG9vbEluZm9KU09OKCk7XHJcblxyXG4gIGxvZyg1LCBgW3Bvb2xdIFRoZSBtaW5pbXVtIG51bWJlciBvZiByZXNvdXJjZXMgYWxsb3dlZCBieSBwb29sOiAke21pbn0uYCk7XHJcbiAgbG9nKDUsIGBbcG9vbF0gVGhlIG1heGltdW0gbnVtYmVyIG9mIHJlc291cmNlcyBhbGxvd2VkIGJ5IHBvb2w6ICR7bWF4fS5gKTtcclxuICBsb2coNSwgYFtwb29sXSBUaGUgbnVtYmVyIG9mIHVzZWQgcmVzb3VyY2VzOiAke3VzZWR9LmApO1xyXG4gIGxvZyg1LCBgW3Bvb2xdIFRoZSBudW1iZXIgb2YgZnJlZSByZXNvdXJjZXM6ICR7YXZhaWxhYmxlfS5gKTtcclxuICBsb2coXHJcbiAgICA1LFxyXG4gICAgYFtwb29sXSBUaGUgbnVtYmVyIG9mIGFsbCBjcmVhdGVkICh1c2VkIGFuZCBmcmVlKSByZXNvdXJjZXM6ICR7YWxsQ3JlYXRlZH0uYFxyXG4gICk7XHJcbiAgbG9nKFxyXG4gICAgNSxcclxuICAgIGBbcG9vbF0gVGhlIG51bWJlciBvZiByZXNvdXJjZXMgd2FpdGluZyB0byBiZSBhY3F1aXJlZDogJHtwZW5kaW5nQWNxdWlyZXN9LmBcclxuICApO1xyXG4gIGxvZyhcclxuICAgIDUsXHJcbiAgICBgW3Bvb2xdIFRoZSBudW1iZXIgb2YgcmVzb3VyY2VzIHdhaXRpbmcgdG8gYmUgY3JlYXRlZDogJHtwZW5kaW5nQ3JlYXRlc30uYFxyXG4gICk7XHJcbiAgbG9nKFxyXG4gICAgNSxcclxuICAgIGBbcG9vbF0gVGhlIG51bWJlciBvZiByZXNvdXJjZXMgd2FpdGluZyB0byBiZSB2YWxpZGF0ZWQ6ICR7cGVuZGluZ1ZhbGlkYXRpb25zfS5gXHJcbiAgKTtcclxuICBsb2coXHJcbiAgICA1LFxyXG4gICAgYFtwb29sXSBUaGUgbnVtYmVyIG9mIHJlc291cmNlcyB3YWl0aW5nIHRvIGJlIGRlc3Ryb3llZDogJHtwZW5kaW5nRGVzdHJveXN9LmBcclxuICApO1xyXG4gIGxvZyg1LCBgW3Bvb2xdIFRoZSBudW1iZXIgb2YgYWxsIHJlc291cmNlczogJHthYnNvbHV0ZUFsbH0uYCk7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBGYWN0b3J5IGZ1bmN0aW9uIHRoYXQgcmV0dXJucyBhbiBvYmplY3Qgd2l0aCBgY3JlYXRlYCwgYHZhbGlkYXRlYCwgYGRlc3Ryb3lgXHJcbiAqIGZ1bmN0aW9ucyBmb3IgdGhlIHBvb2wgaW5zdGFuY2UuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBfZmFjdG9yeVxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gcG9vbE9wdGlvbnMgLSBUaGUgY29uZmlndXJhdGlvbiBvYmplY3QgY29udGFpbmluZyBgcG9vbGBcclxuICogb3B0aW9ucy5cclxuICovXHJcbmZ1bmN0aW9uIF9mYWN0b3J5KHBvb2xPcHRpb25zKSB7XHJcbiAgcmV0dXJuIHtcclxuICAgIC8qKlxyXG4gICAgICogQ3JlYXRlcyBhIG5ldyB3b3JrZXIgcGFnZSBmb3IgdGhlIGV4cG9ydCBwb29sLlxyXG4gICAgICpcclxuICAgICAqIEBhc3luY1xyXG4gICAgICogQGZ1bmN0aW9uIGNyZWF0ZVxyXG4gICAgICpcclxuICAgICAqIEByZXR1cm5zIHtQcm9taXNlPE9iamVjdD59IEEgUHJvbWlzZSB0aGF0IHJlc29sdmVzIHRvIGFuIG9iamVjdFxyXG4gICAgICogY29udGFpbmluZyB0aGUgd29ya2VyIElELCBhIHJlZmVyZW5jZSB0byB0aGUgYnJvd3NlciBwYWdlLCBhbmQgaW5pdGlhbFxyXG4gICAgICogd29yayBjb3VudC5cclxuICAgICAqXHJcbiAgICAgKiBAdGhyb3dzIHtFeHBvcnRFcnJvcn0gVGhyb3dzIGFuIGBFeHBvcnRFcnJvcmAgaWYgdGhlcmUgaXMgYW4gZXJyb3IgZHVyaW5nXHJcbiAgICAgKiB0aGUgY3JlYXRpb24gb2YgdGhlIG5ldyBwYWdlLlxyXG4gICAgICovXHJcbiAgICBjcmVhdGU6IGFzeW5jICgpID0+IHtcclxuICAgICAgLy8gSW5pdCB0aGUgcmVzb3VyY2Ugd2l0aCB1bmlxdWUgaWQgYW5kIHdvcmsgY291bnRcclxuICAgICAgY29uc3QgcG9vbFJlc291cmNlID0ge1xyXG4gICAgICAgIGlkOiB1dWlkKCksXHJcbiAgICAgICAgLy8gVHJ5IHRvIGRpc3RyaWJ1dGUgdGhlIGluaXRpYWwgd29yayBjb3VudFxyXG4gICAgICAgIHdvcmtDb3VudDogTWF0aC5yb3VuZChNYXRoLnJhbmRvbSgpICogKHBvb2xPcHRpb25zLndvcmtMaW1pdCAvIDIpKVxyXG4gICAgICB9O1xyXG5cclxuICAgICAgdHJ5IHtcclxuICAgICAgICAvLyBTdGFydCBtZWFzdXJpbmcgYSBwYWdlIGNyZWF0aW9uIHRpbWVcclxuICAgICAgICBjb25zdCBzdGFydERhdGUgPSBnZXROZXdEYXRlVGltZSgpO1xyXG5cclxuICAgICAgICAvLyBDcmVhdGUgYSBuZXcgcGFnZVxyXG4gICAgICAgIGF3YWl0IG5ld1BhZ2UocG9vbFJlc291cmNlKTtcclxuXHJcbiAgICAgICAgLy8gTWVhc3VyZSB0aGUgdGltZSBvZiBmdWxsIGNyZWF0aW9uIGFuZCBjb25maWd1cmF0aW9uIG9mIGEgcGFnZVxyXG4gICAgICAgIGxvZyhcclxuICAgICAgICAgIDMsXHJcbiAgICAgICAgICBgW3Bvb2xdIFBvb2wgcmVzb3VyY2UgWyR7cG9vbFJlc291cmNlLmlkfV0gLSBTdWNjZXNzZnVsbHkgY3JlYXRlZCBhIHdvcmtlciwgdG9vayAke1xyXG4gICAgICAgICAgICBnZXROZXdEYXRlVGltZSgpIC0gc3RhcnREYXRlXHJcbiAgICAgICAgICB9bXMuYFxyXG4gICAgICAgICk7XHJcblxyXG4gICAgICAgIC8vIFJldHVybiByZWFkeSBwb29sIHJlc291cmNlXHJcbiAgICAgICAgcmV0dXJuIHBvb2xSZXNvdXJjZTtcclxuICAgICAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICAgICBsb2coXHJcbiAgICAgICAgICAzLFxyXG4gICAgICAgICAgYFtwb29sXSBQb29sIHJlc291cmNlIFske3Bvb2xSZXNvdXJjZS5pZH1dIC0gRXJyb3IgZW5jb3VudGVyZWQgd2hlbiBjcmVhdGluZyBhIG5ldyBwYWdlLmBcclxuICAgICAgICApO1xyXG4gICAgICAgIHRocm93IGVycm9yO1xyXG4gICAgICB9XHJcbiAgICB9LFxyXG5cclxuICAgIC8qKlxyXG4gICAgICogVmFsaWRhdGVzIGEgd29ya2VyIHBhZ2UgaW4gdGhlIGV4cG9ydCBwb29sLCBjaGVja2luZyBpZiBpdCBoYXMgZXhjZWVkZWRcclxuICAgICAqIHRoZSB3b3JrIGxpbWl0LlxyXG4gICAgICpcclxuICAgICAqIEBhc3luY1xyXG4gICAgICogQGZ1bmN0aW9uIHZhbGlkYXRlXHJcbiAgICAgKlxyXG4gICAgICogQHBhcmFtIHtPYmplY3R9IHBvb2xSZXNvdXJjZSAtIFRoZSBoYW5kbGUgdG8gdGhlIHdvcmtlciwgY29udGFpbmluZ1xyXG4gICAgICogdGhlIHdvcmtlcidzIElELCBhIHJlZmVyZW5jZSB0byB0aGUgYnJvd3NlciBwYWdlLCBhbmQgd29yayBjb3VudC5cclxuICAgICAqXHJcbiAgICAgKiBAcmV0dXJucyB7UHJvbWlzZTxib29sZWFuPn0gQSBQcm9taXNlIHRoYXQgcmVzb2x2ZXMgdG8gdHJ1ZSBpZiB0aGUgd29ya2VyXHJcbiAgICAgKiBpcyB2YWxpZCBhbmQgd2l0aGluIHRoZSB3b3JrIGxpbWl0OyBvdGhlcndpc2UsIHRvIGZhbHNlLlxyXG4gICAgICovXHJcbiAgICB2YWxpZGF0ZTogYXN5bmMgKHBvb2xSZXNvdXJjZSkgPT4ge1xyXG4gICAgICAvLyBOT1RFOlxyXG4gICAgICAvLyBJbiBjZXJ0YWluIGNhc2VzIGFjcXVpcmluZyB0aHJvd3MgYSBgVGFyZ2V0Q2xvc2VFcnJvcmAsIHdoaWNoIG1heVxyXG4gICAgICAvLyBiZSBjYXVzZWQgYnkgdHdvIHRoaW5nczpcclxuICAgICAgLy8gLSBUaGUgcGFnZSBpcyBjbG9zZWQgYW5kIGF0dGVtcHRlZCB0byBiZSByZXVzZWQuXHJcbiAgICAgIC8vIC0gTG9zdCBjb250YWN0IHdpdGggdGhlIGJyb3dzZXIuXHJcbiAgICAgIC8vXHJcbiAgICAgIC8vIFdoYXQgd2UncmUgc2VlaW5nIGluIGxvZ3MgaXMgdGhhdCBzdWNjZXNzaXZlIGV4cG9ydHMgdHlwaWNhbGx5XHJcbiAgICAgIC8vIHN1Y2NlZWRzLCBhbmQgdGhlIHNlcnZlciByZWNvdmVycywgaW5kaWNhdGluZyB0aGF0IGl0J3MgbGlrZWx5XHJcbiAgICAgIC8vIHRoZSBmaXJzdCBjYXNlLiBUaGlzIGlzIGFuIGF0dGVtcHQgYXQgYWxsaWV2YXRpbmcgdGhlIGlzc3VlIGJ5XHJcbiAgICAgIC8vIHNpbXBseSBub3QgdmFsaWRhdGluZyB0aGUgd29ya2VyIGlmIHRoZSBwYWdlIGlzIG51bGwgb3IgY2xvc2VkLlxyXG4gICAgICAvL1xyXG4gICAgICAvLyBUaGUgYWN0dWFsIHJlc3VsdCBmcm9tIHdoZW4gdGhpcyBoYXBwZW5lZCwgd2FzIHRoYXQgYSB3b3JrZXIgd291bGRcclxuICAgICAgLy8gYmUgY29tcGxldGVseSBsb2NrZWQsIHN0b3BwaW5nIGl0IGZyb20gYmVpbmcgYWNxdWlyZWQgdW50aWxcclxuICAgICAgLy8gaXRzIHdvcmsgY291bnQgcmVhY2hlZCB0aGUgbGltaXQuXHJcblxyXG4gICAgICAvLyBDaGVjayBpZiB0aGUgYHBhZ2VgIGlzIHZhbGlkXHJcbiAgICAgIGlmICghcG9vbFJlc291cmNlLnBhZ2UpIHtcclxuICAgICAgICBsb2coXHJcbiAgICAgICAgICAzLFxyXG4gICAgICAgICAgYFtwb29sXSBQb29sIHJlc291cmNlIFske3Bvb2xSZXNvdXJjZS5pZH1dIC0gVmFsaWRhdGlvbiBmYWlsZWQgKG5vIHZhbGlkIHBhZ2UgaXMgZm91bmQpLmBcclxuICAgICAgICApO1xyXG4gICAgICAgIHJldHVybiBmYWxzZTtcclxuICAgICAgfVxyXG5cclxuICAgICAgLy8gQ2hlY2sgaWYgdGhlIGBwYWdlYCBpcyBjbG9zZWRcclxuICAgICAgaWYgKHBvb2xSZXNvdXJjZS5wYWdlLmlzQ2xvc2VkKCkpIHtcclxuICAgICAgICBsb2coXHJcbiAgICAgICAgICAzLFxyXG4gICAgICAgICAgYFtwb29sXSBQb29sIHJlc291cmNlIFske3Bvb2xSZXNvdXJjZS5pZH1dIC0gVmFsaWRhdGlvbiBmYWlsZWQgKHBhZ2UgaXMgY2xvc2VkIG9yIGludmFsaWQpLmBcclxuICAgICAgICApO1xyXG4gICAgICAgIHJldHVybiBmYWxzZTtcclxuICAgICAgfVxyXG5cclxuICAgICAgLy8gQ2hlY2sgaWYgdGhlIGBtYWluRnJhbWVgIGlzIGRldGFjaGVkXHJcbiAgICAgIGlmIChwb29sUmVzb3VyY2UucGFnZS5tYWluRnJhbWUoKS5kZXRhY2hlZCkge1xyXG4gICAgICAgIGxvZyhcclxuICAgICAgICAgIDMsXHJcbiAgICAgICAgICBgW3Bvb2xdIFBvb2wgcmVzb3VyY2UgWyR7cG9vbFJlc291cmNlLmlkfV0gLSBWYWxpZGF0aW9uIGZhaWxlZCAocGFnZSdzIGZyYW1lIGlzIGRldGFjaGVkKS5gXHJcbiAgICAgICAgKTtcclxuICAgICAgICByZXR1cm4gZmFsc2U7XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIC8vIENoZWNrIGlmIHRoZSBgd29ya0xpbWl0YCBpcyBleGNlZWRlZFxyXG4gICAgICBpZiAoXHJcbiAgICAgICAgcG9vbE9wdGlvbnMud29ya0xpbWl0ICYmXHJcbiAgICAgICAgKytwb29sUmVzb3VyY2Uud29ya0NvdW50ID4gcG9vbE9wdGlvbnMud29ya0xpbWl0XHJcbiAgICAgICkge1xyXG4gICAgICAgIGxvZyhcclxuICAgICAgICAgIDMsXHJcbiAgICAgICAgICBgW3Bvb2xdIFBvb2wgcmVzb3VyY2UgWyR7cG9vbFJlc291cmNlLmlkfV0gLSBWYWxpZGF0aW9uIGZhaWxlZCAoZXhjZWVkZWQgdGhlICR7cG9vbE9wdGlvbnMud29ya0xpbWl0fSB3b3JrcyBwZXIgcmVzb3VyY2UgbGltaXQpLmBcclxuICAgICAgICApO1xyXG4gICAgICAgIHJldHVybiBmYWxzZTtcclxuICAgICAgfVxyXG5cclxuICAgICAgLy8gVGhlIGBwb29sUmVzb3VyY2VgIGlzIHZhbGlkYXRlZFxyXG4gICAgICByZXR1cm4gdHJ1ZTtcclxuICAgIH0sXHJcblxyXG4gICAgLyoqXHJcbiAgICAgKiBEZXN0cm95cyBhIHdvcmtlciBlbnRyeSBpbiB0aGUgZXhwb3J0IHBvb2wsIGNsb3NpbmcgaXRzIGFzc29jaWF0ZWQgcGFnZS5cclxuICAgICAqXHJcbiAgICAgKiBAYXN5bmNcclxuICAgICAqIEBmdW5jdGlvbiBkZXN0cm95XHJcbiAgICAgKlxyXG4gICAgICogQHBhcmFtIHtPYmplY3R9IHBvb2xSZXNvdXJjZSAtIFRoZSBoYW5kbGUgdG8gdGhlIHdvcmtlciwgY29udGFpbmluZ1xyXG4gICAgICogdGhlIHdvcmtlcidzIElELCBhIHJlZmVyZW5jZSB0byB0aGUgYnJvd3NlciBwYWdlLCBhbmQgd29yayBjb3VudC5cclxuICAgICAqL1xyXG4gICAgZGVzdHJveTogYXN5bmMgKHBvb2xSZXNvdXJjZSkgPT4ge1xyXG4gICAgICBsb2coXHJcbiAgICAgICAgMyxcclxuICAgICAgICBgW3Bvb2xdIFBvb2wgcmVzb3VyY2UgWyR7cG9vbFJlc291cmNlLmlkfV0gLSBEZXN0cm95aW5nIGEgd29ya2VyLmBcclxuICAgICAgKTtcclxuXHJcbiAgICAgIGlmIChwb29sUmVzb3VyY2UucGFnZSAmJiAhcG9vbFJlc291cmNlLnBhZ2UuaXNDbG9zZWQoKSkge1xyXG4gICAgICAgIHRyeSB7XHJcbiAgICAgICAgICAvLyBSZW1vdmUgYWxsIGF0dGFjaGVkIGV2ZW50IGxpc3RlbmVycyBmcm9tIHRoZSByZXNvdXJjZVxyXG4gICAgICAgICAgcG9vbFJlc291cmNlLnBhZ2UucmVtb3ZlQWxsTGlzdGVuZXJzKCdwYWdlZXJyb3InKTtcclxuICAgICAgICAgIHBvb2xSZXNvdXJjZS5wYWdlLnJlbW92ZUFsbExpc3RlbmVycygnY29uc29sZScpO1xyXG4gICAgICAgICAgcG9vbFJlc291cmNlLnBhZ2UucmVtb3ZlQWxsTGlzdGVuZXJzKCdmcmFtZWRldGFjaGVkJyk7XHJcblxyXG4gICAgICAgICAgLy8gV2UgbmVlZCB0byB3YWl0IGFyb3VuZCBmb3IgdGhpc1xyXG4gICAgICAgICAgYXdhaXQgcG9vbFJlc291cmNlLnBhZ2UuY2xvc2UoKTtcclxuICAgICAgICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgICAgICAgbG9nKFxyXG4gICAgICAgICAgICAzLFxyXG4gICAgICAgICAgICBgW3Bvb2xdIFBvb2wgcmVzb3VyY2UgWyR7cG9vbFJlc291cmNlLmlkfV0gLSBQYWdlIGNvdWxkIG5vdCBiZSBjbG9zZWQgdXBvbiBkZXN0cm95aW5nLmBcclxuICAgICAgICAgICk7XHJcbiAgICAgICAgICB0aHJvdyBlcnJvcjtcclxuICAgICAgICB9XHJcbiAgICAgIH1cclxuICAgIH1cclxuICB9O1xyXG59XHJcblxyXG5leHBvcnQgZGVmYXVsdCB7XHJcbiAgaW5pdFBvb2wsXHJcbiAga2lsbFBvb2wsXHJcbiAgcG9zdFdvcmssXHJcbiAgZ2V0UG9vbCxcclxuICBnZXRQb29sU3RhdHMsXHJcbiAgZ2V0UG9vbEluZm9KU09OXHJcbn07XHJcbiIsIi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXHJcblxyXG5IaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXJcclxuXHJcbkNvcHlyaWdodCAoYykgMjAxNi0yMDI1LCBIaWdoc29mdFxyXG5cclxuTGljZW5jZWQgdW5kZXIgdGhlIE1JVCBsaWNlbmNlLlxyXG5cclxuQWRkaXRpb25hbGx5IGEgdmFsaWQgSGlnaGNoYXJ0cyBsaWNlbnNlIGlzIHJlcXVpcmVkIGZvciB1c2UuXHJcblxyXG5TZWUgTElDRU5TRSBmaWxlIGluIHJvb3QgZm9yIGRldGFpbHMuXHJcblxyXG4qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xyXG5cclxuLyoqXHJcbiAqIEBvdmVydmlldyBVc2VkIHRvIHNhbml0aXplIHRoZSBzdHJpbmdzIGNvbWluZyBmcm9tIHRoZSBleHBvcnRpbmcgbW9kdWxlXHJcbiAqIHRvIHByZXZlbnQgWFNTIGF0dGFja3MgKHdpdGggdGhlIERPTVB1cmlmeSBsaWJyYXJ5KS5cclxuICovXHJcblxyXG5pbXBvcnQgRE9NUHVyaWZ5IGZyb20gJ2RvbXB1cmlmeSc7XHJcbmltcG9ydCB7IEpTRE9NIH0gZnJvbSAnanNkb20nO1xyXG5cclxuLyoqXHJcbiAqIFNhbml0aXplcyBhIGdpdmVuIEhUTUwgc3RyaW5nIGJ5IHJlbW92aW5nIDxzY3JpcHQ+IHRhZ3MuIFRoaXMgZnVuY3Rpb24gdXNlc1xyXG4gKiBhIHJlZ3VsYXIgZXhwcmVzc2lvbiB0byBmaW5kIGFuZCByZW1vdmUgYWxsIG9jY3VycmVuY2VzIG9mIDxzY3JpcHQ+PC9zY3JpcHQ+XHJcbiAqIHRhZ3MgYW5kIGFueSBjb250ZW50IHdpdGhpbiB0aGVtLlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gc2FuaXRpemVcclxuICpcclxuICogQHBhcmFtIHtzdHJpbmd9IGlucHV0IC0gVGhlIEhUTUwgc3RyaW5nIHRvIGJlIHNhbml0aXplZC5cclxuICpcclxuICogQHJldHVybnMge3N0cmluZ30gVGhlIHNhbml0aXplZCBIVE1MIHN0cmluZy5cclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiBzYW5pdGl6ZShpbnB1dCkge1xyXG4gIC8vIEdldCB0aGUgdmlydHVhbCBET01cclxuICBjb25zdCB3aW5kb3cgPSBuZXcgSlNET00oJycpLndpbmRvdztcclxuXHJcbiAgLy8gQ3JlYXRlIGEgcHVyaWZ5aW5nIGluc3RhbmNlXHJcbiAgY29uc3QgcHVyaWZ5ID0gRE9NUHVyaWZ5KHdpbmRvdyk7XHJcblxyXG4gIC8vIFJldHVybiBzYW5pdGl6ZWQgaW5wdXQsIGFsbG93aW5nIGZvciB0aGUgYGZvcmVpZ25PYmplY3RgIGVsZW1lbnRzXHJcbiAgcmV0dXJuIHB1cmlmeS5zYW5pdGl6ZShpbnB1dCwgeyBBRERfVEFHUzogWydmb3JlaWduT2JqZWN0J10gfSk7XHJcbn1cclxuXHJcbmV4cG9ydCBkZWZhdWx0IHtcclxuICBzYW5pdGl6ZVxyXG59O1xyXG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxyXG5cclxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXHJcblxyXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNSwgSGlnaHNvZnRcclxuXHJcbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cclxuXHJcbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxyXG5cclxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxyXG5cclxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cclxuXHJcbi8qKlxyXG4gKiBAb3ZlcnZpZXcgVGhpcyBtb2R1bGUgcHJvdmlkZXMgZnVuY3Rpb25zIHRoYXQgcHJlcGFyZSBmb3IgdGhlIGV4cG9ydGluZ1xyXG4gKiBjaGFydHMgaW50byB2YXJpb3VzIGltYWdlIG91dHB1dCBmb3JtYXRzIHN1Y2ggYXMgSlBFRywgUE5HLCBQREYsIGFuZCBTVkdzLlxyXG4gKiBJdCBzdXBwb3J0cyBzaW5nbGUgYW5kIGJhdGNoIGV4cG9ydCBvcGVyYXRpb25zIGFuZCBhbGxvd3MgY3VzdG9taXphdGlvblxyXG4gKiB0aHJvdWdoIG9wdGlvbnMgcGFzc2VkIGZyb20gY29uZmlndXJhdGlvbnMgb3IgQVBJcy5cclxuICovXHJcblxyXG5pbXBvcnQgeyByZWFkRmlsZVN5bmMsIHdyaXRlRmlsZVN5bmMgfSBmcm9tICdmcyc7XHJcblxyXG5pbXBvcnQgeyBpc0FsbG93ZWRDb25maWcsIHVwZGF0ZU9wdGlvbnMsIHZhbGlkYXRlT3B0aW9uIH0gZnJvbSAnLi9jb25maWcuanMnO1xyXG5pbXBvcnQgeyBsb2csIGxvZ1dpdGhTdGFjayB9IGZyb20gJy4vbG9nZ2VyLmpzJztcclxuaW1wb3J0IHsgZ2V0UG9vbFN0YXRzLCBraWxsUG9vbCwgcG9zdFdvcmsgfSBmcm9tICcuL3Bvb2wuanMnO1xyXG5pbXBvcnQgeyBzYW5pdGl6ZSB9IGZyb20gJy4vc2FuaXRpemUuanMnO1xyXG5pbXBvcnQgeyBnZXRBYnNvbHV0ZVBhdGgsIGdldEJhc2U2NCwgaXNPYmplY3QsIHJvdW5kTnVtYmVyIH0gZnJvbSAnLi91dGlscy5qcyc7XHJcblxyXG5pbXBvcnQgRXhwb3J0RXJyb3IgZnJvbSAnLi9lcnJvcnMvRXhwb3J0RXJyb3IuanMnO1xyXG5cclxuLy8gVGhlIGdsb2JhbCBmbGFnIGZvciB0aGUgY29kZSBleGVjdXRpb24gcGVybWlzc2lvblxyXG5sZXQgYWxsb3dDb2RlRXhlY3V0aW9uID0gZmFsc2U7XHJcblxyXG4vKipcclxuICogU3RhcnRzIGEgc2luZ2xlIGV4cG9ydCBwcm9jZXNzIGJhc2VkIG9uIHRoZSBzcGVjaWZpZWQgb3B0aW9ucyBhbmQgc2F2ZXNcclxuICogdGhlIHJlc3VsdGluZyBpbWFnZSB0byB0aGUgcHJvdmlkZWQgb3V0cHV0IGZpbGUuXHJcbiAqXHJcbiAqIEBhc3luY1xyXG4gKiBAZnVuY3Rpb24gc2luZ2xlRXhwb3J0XHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBvcHRpb25zIC0gVGhlIGBvcHRpb25zYCBvYmplY3QsIHdoaWNoIHNob3VsZCBpbmNsdWRlIHNldHRpbmdzXHJcbiAqIGZyb20gdGhlIGBleHBvcnRgIGFuZCBgY3VzdG9tTG9naWNgIHNlY3Rpb25zLiBJdCBjYW4gYmUgYSBwYXJ0aWFsIG9yIGNvbXBsZXRlXHJcbiAqIHNldCBvZiBvcHRpb25zIGZyb20gdGhlc2Ugc2VjdGlvbnMuIFRoZSBvYmplY3QgbXVzdCBjb250YWluIGF0IGxlYXN0IG9uZVxyXG4gKiBvZiB0aGUgZm9sbG93aW5nIGBleHBvcnRgIHByb3BlcnRpZXM6IGBpbmZpbGVgLCBgaW5zdHJgLCBgb3B0aW9uc2AsIG9yIGBzdmdgXHJcbiAqIHRvIGdlbmVyYXRlIGEgdmFsaWQgaW1hZ2UuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtQcm9taXNlPHZvaWQ+fSBBIFByb21pc2UgdGhhdCByZXNvbHZlcyBvbmNlIHRoZSBzaW5nbGUgZXhwb3J0XHJcbiAqIHByb2Nlc3MgaXMgY29tcGxldGVkLlxyXG4gKlxyXG4gKiBAdGhyb3dzIHtFeHBvcnRFcnJvcn0gVGhyb3dzIGFuIGBFeHBvcnRFcnJvcmAgaWYgYW4gZXJyb3Igb2NjdXJzIGR1cmluZ1xyXG4gKiB0aGUgc2luZ2xlIGV4cG9ydCBwcm9jZXNzLlxyXG4gKi9cclxuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIHNpbmdsZUV4cG9ydChvcHRpb25zKSB7XHJcbiAgLy8gQ2hlY2sgaWYgdGhlIGV4cG9ydCBtYWtlcyBzZW5zZVxyXG4gIGlmIChvcHRpb25zICYmIG9wdGlvbnMuZXhwb3J0KSB7XHJcbiAgICAvLyBQZXJmb3JtIGFuIGV4cG9ydFxyXG4gICAgYXdhaXQgc3RhcnRFeHBvcnQoXHJcbiAgICAgIHsgZXhwb3J0OiBvcHRpb25zLmV4cG9ydCwgY3VzdG9tTG9naWM6IG9wdGlvbnMuY3VzdG9tTG9naWMgfSxcclxuICAgICAgYXN5bmMgKGVycm9yLCBkYXRhKSA9PiB7XHJcbiAgICAgICAgLy8gRXhpdCBwcm9jZXNzIHdoZW4gZXJyb3IgZXhpc3RzXHJcbiAgICAgICAgaWYgKGVycm9yKSB7XHJcbiAgICAgICAgICB0aHJvdyBlcnJvcjtcclxuICAgICAgICB9XHJcblxyXG4gICAgICAgIC8vIEdldCB0aGUgYGI2NGAsIGBvdXRmaWxlYCwgYW5kIGB0eXBlYCBmb3IgYSBjaGFydFxyXG4gICAgICAgIGNvbnN0IHsgYjY0LCBvdXRmaWxlLCB0eXBlIH0gPSBkYXRhLm9wdGlvbnMuZXhwb3J0O1xyXG5cclxuICAgICAgICAvLyBTYXZlIHRoZSByZXN1bHRcclxuICAgICAgICB0cnkge1xyXG4gICAgICAgICAgaWYgKGI2NCkge1xyXG4gICAgICAgICAgICAvLyBBcyBhIEJhc2U2NCBzdHJpbmcgdG8gYSB0eHQgZmlsZVxyXG4gICAgICAgICAgICB3cml0ZUZpbGVTeW5jKFxyXG4gICAgICAgICAgICAgIGAke291dGZpbGUuc3BsaXQoJy4nKS5zaGlmdCgpIHx8ICdjaGFydCd9LnR4dGAsXHJcbiAgICAgICAgICAgICAgZ2V0QmFzZTY0KGRhdGEucmVzdWx0LCB0eXBlKVxyXG4gICAgICAgICAgICApO1xyXG4gICAgICAgICAgfSBlbHNlIHtcclxuICAgICAgICAgICAgLy8gQXMgYSBjb3JyZWN0IGltYWdlIGZvcm1hdFxyXG4gICAgICAgICAgICB3cml0ZUZpbGVTeW5jKFxyXG4gICAgICAgICAgICAgIG91dGZpbGUgfHwgYGNoYXJ0LiR7dHlwZX1gLFxyXG4gICAgICAgICAgICAgIHR5cGUgIT09ICdzdmcnID8gQnVmZmVyLmZyb20oZGF0YS5yZXN1bHQsICdiYXNlNjQnKSA6IGRhdGEucmVzdWx0XHJcbiAgICAgICAgICAgICk7XHJcbiAgICAgICAgICB9XHJcbiAgICAgICAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICAgICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcihcclxuICAgICAgICAgICAgJ1tjaGFydF0gRXJyb3Igd2hpbGUgc2F2aW5nIGEgY2hhcnQuJyxcclxuICAgICAgICAgICAgNTAwXHJcbiAgICAgICAgICApLnNldEVycm9yKGVycm9yKTtcclxuICAgICAgICB9XHJcblxyXG4gICAgICAgIC8vIEtpbGwgcG9vbCBhbmQgY2xvc2UgYnJvd3NlciBhZnRlciBmaW5pc2hpbmcgc2luZ2xlIGV4cG9ydFxyXG4gICAgICAgIGF3YWl0IGtpbGxQb29sKCk7XHJcbiAgICAgIH1cclxuICAgICk7XHJcbiAgfSBlbHNlIHtcclxuICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcihcclxuICAgICAgJ1tjaGFydF0gTm8gZXhwZWN0ZWQgYGV4cG9ydGAgb3B0aW9ucyB3ZXJlIGZvdW5kLiBQbGVhc2UgcHJvdmlkZSBvbmUgb2YgdGhlIGZvbGxvd2luZyBvcHRpb25zOiBgaW5maWxlYCwgYGluc3RyYCwgYG9wdGlvbnNgLCBvciBgc3ZnYCB0byBnZW5lcmF0ZSBhIHZhbGlkIGltYWdlLicsXHJcbiAgICAgIDQwMFxyXG4gICAgKTtcclxuICB9XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBTdGFydHMgYSBiYXRjaCBleHBvcnQgcHJvY2VzcyBmb3IgbXVsdGlwbGUgY2hhcnRzIGJhc2VkIG9uIGluZm9ybWF0aW9uXHJcbiAqIHByb3ZpZGVkIGluIHRoZSBgYmF0Y2hgIG9wdGlvbi4gVGhlIGBiYXRjaGAgaXMgYSBzdHJpbmcgaW4gdGhlIGZvbGxvd2luZ1xyXG4gKiBmb3JtYXQ6IFwiaW5maWxlMS5qc29uPW91dGZpbGUxLnBuZztpbmZpbGUyLmpzb249b3V0ZmlsZTIucG5nOy4uLlwiLiBSZXN1bHRzXHJcbiAqIGFyZSBzYXZlZCB0byB0aGUgc3BlY2lmaWVkIG91dHB1dCBmaWxlcy5cclxuICpcclxuICogQGFzeW5jXHJcbiAqIEBmdW5jdGlvbiBiYXRjaEV4cG9ydFxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gb3B0aW9ucyAtIFRoZSBgb3B0aW9uc2Agb2JqZWN0LCB3aGljaCBzaG91bGQgaW5jbHVkZSBzZXR0aW5nc1xyXG4gKiBmcm9tIHRoZSBgZXhwb3J0YCBhbmQgYGN1c3RvbUxvZ2ljYCBzZWN0aW9ucy4gSXQgY2FuIGJlIGEgcGFydGlhbCBvciBjb21wbGV0ZVxyXG4gKiBzZXQgb2Ygb3B0aW9ucyBmcm9tIHRoZXNlIHNlY3Rpb25zLiBJdCBtdXN0IGNvbnRhaW4gdGhlIGBiYXRjaGAgb3B0aW9uIGZyb21cclxuICogdGhlIGBleHBvcnRgIHNlY3Rpb24gdG8gZ2VuZXJhdGUgdmFsaWQgaW1hZ2VzLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7UHJvbWlzZTx2b2lkPn0gQSBQcm9taXNlIHRoYXQgcmVzb2x2ZXMgb25jZSB0aGUgYmF0Y2ggZXhwb3J0XHJcbiAqIHByb2Nlc3NlcyBhcmUgY29tcGxldGVkLlxyXG4gKlxyXG4gKiBAdGhyb3dzIHtFeHBvcnRFcnJvcn0gVGhyb3dzIGFuIGBFeHBvcnRFcnJvcmAgaWYgYW4gZXJyb3Igb2NjdXJzIGR1cmluZ1xyXG4gKiBhbnkgb2YgdGhlIGJhdGNoIGV4cG9ydCBwcm9jZXNzLlxyXG4gKi9cclxuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIGJhdGNoRXhwb3J0KG9wdGlvbnMpIHtcclxuICAvLyBDaGVjayBpZiB0aGUgZXhwb3J0IG1ha2VzIHNlbnNlXHJcbiAgaWYgKG9wdGlvbnMgJiYgb3B0aW9ucy5leHBvcnQgJiYgb3B0aW9ucy5leHBvcnQuYmF0Y2gpIHtcclxuICAgIC8vIEFuIGFycmF5IGZvciBjb2xsZWN0aW5nIGJhdGNoIGV4cG9ydHNcclxuICAgIGNvbnN0IGJhdGNoRnVuY3Rpb25zID0gW107XHJcblxyXG4gICAgLy8gU3BsaXQgYW5kIHBhaXIgdGhlIGBiYXRjaGAgYXJndW1lbnRzXHJcbiAgICBmb3IgKGxldCBwYWlyIG9mIG9wdGlvbnMuZXhwb3J0LmJhdGNoLnNwbGl0KCc7JykgfHwgW10pIHtcclxuICAgICAgcGFpciA9IHBhaXIuc3BsaXQoJz0nKTtcclxuICAgICAgaWYgKHBhaXIubGVuZ3RoID09PSAyKSB7XHJcbiAgICAgICAgYmF0Y2hGdW5jdGlvbnMucHVzaChcclxuICAgICAgICAgIHN0YXJ0RXhwb3J0KFxyXG4gICAgICAgICAgICB7XHJcbiAgICAgICAgICAgICAgZXhwb3J0OiB7XHJcbiAgICAgICAgICAgICAgICAuLi5vcHRpb25zLmV4cG9ydCxcclxuICAgICAgICAgICAgICAgIGluZmlsZTogcGFpclswXSxcclxuICAgICAgICAgICAgICAgIG91dGZpbGU6IHBhaXJbMV1cclxuICAgICAgICAgICAgICB9LFxyXG4gICAgICAgICAgICAgIGN1c3RvbUxvZ2ljOiBvcHRpb25zLmN1c3RvbUxvZ2ljXHJcbiAgICAgICAgICAgIH0sXHJcbiAgICAgICAgICAgIChlcnJvciwgZGF0YSkgPT4ge1xyXG4gICAgICAgICAgICAgIC8vIEV4aXQgcHJvY2VzcyB3aGVuIGVycm9yIGV4aXN0c1xyXG4gICAgICAgICAgICAgIGlmIChlcnJvcikge1xyXG4gICAgICAgICAgICAgICAgdGhyb3cgZXJyb3I7XHJcbiAgICAgICAgICAgICAgfVxyXG5cclxuICAgICAgICAgICAgICAvLyBHZXQgdGhlIGBiNjRgLCBgb3V0ZmlsZWAsIGFuZCBgdHlwZWAgZm9yIGEgY2hhcnRcclxuICAgICAgICAgICAgICBjb25zdCB7IGI2NCwgb3V0ZmlsZSwgdHlwZSB9ID0gZGF0YS5vcHRpb25zLmV4cG9ydDtcclxuXHJcbiAgICAgICAgICAgICAgLy8gU2F2ZSB0aGUgcmVzdWx0XHJcbiAgICAgICAgICAgICAgdHJ5IHtcclxuICAgICAgICAgICAgICAgIGlmIChiNjQpIHtcclxuICAgICAgICAgICAgICAgICAgLy8gQXMgYSBCYXNlNjQgc3RyaW5nIHRvIGEgdHh0IGZpbGVcclxuICAgICAgICAgICAgICAgICAgd3JpdGVGaWxlU3luYyhcclxuICAgICAgICAgICAgICAgICAgICBgJHtvdXRmaWxlLnNwbGl0KCcuJykuc2hpZnQoKSB8fCAnY2hhcnQnfS50eHRgLFxyXG4gICAgICAgICAgICAgICAgICAgIGdldEJhc2U2NChkYXRhLnJlc3VsdCwgdHlwZSlcclxuICAgICAgICAgICAgICAgICAgKTtcclxuICAgICAgICAgICAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgICAgICAgICAgIC8vIEFzIGEgY29ycmVjdCBpbWFnZSBmb3JtYXRcclxuICAgICAgICAgICAgICAgICAgd3JpdGVGaWxlU3luYyhcclxuICAgICAgICAgICAgICAgICAgICBvdXRmaWxlLFxyXG4gICAgICAgICAgICAgICAgICAgIHR5cGUgIT09ICdzdmcnXHJcbiAgICAgICAgICAgICAgICAgICAgICA/IEJ1ZmZlci5mcm9tKGRhdGEucmVzdWx0LCAnYmFzZTY0JylcclxuICAgICAgICAgICAgICAgICAgICAgIDogZGF0YS5yZXN1bHRcclxuICAgICAgICAgICAgICAgICAgKTtcclxuICAgICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgICAgICAgICAgICAgdGhyb3cgbmV3IEV4cG9ydEVycm9yKFxyXG4gICAgICAgICAgICAgICAgICAnW2NoYXJ0XSBFcnJvciB3aGlsZSBzYXZpbmcgYSBjaGFydC4nLFxyXG4gICAgICAgICAgICAgICAgICA1MDBcclxuICAgICAgICAgICAgICAgICkuc2V0RXJyb3IoZXJyb3IpO1xyXG4gICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgfVxyXG4gICAgICAgICAgKVxyXG4gICAgICAgICk7XHJcbiAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgbG9nKDIsICdbY2hhcnRdIE5vIGNvcnJlY3QgcGFpciBmb3VuZCBmb3IgdGhlIGJhdGNoIGV4cG9ydC4nKTtcclxuICAgICAgfVxyXG4gICAgfVxyXG5cclxuICAgIC8vIEF3YWl0IGFsbCBleHBvcnRzIGFyZSBkb25lXHJcbiAgICBjb25zdCBiYXRjaFJlc3VsdHMgPSBhd2FpdCBQcm9taXNlLmFsbFNldHRsZWQoYmF0Y2hGdW5jdGlvbnMpO1xyXG5cclxuICAgIC8vIEtpbGwgcG9vbCBhbmQgY2xvc2UgYnJvd3NlciBhZnRlciBmaW5pc2hpbmcgYmF0Y2ggZXhwb3J0XHJcbiAgICBhd2FpdCBraWxsUG9vbCgpO1xyXG5cclxuICAgIC8vIExvZyBlcnJvcnMgaWYgZm91bmRcclxuICAgIGJhdGNoUmVzdWx0cy5mb3JFYWNoKChyZXN1bHQsIGluZGV4KSA9PiB7XHJcbiAgICAgIC8vIExvZyB0aGUgZXJyb3Igd2l0aCBzdGFjayBhYm91dCB0aGUgc3BlY2lmaWMgYmF0Y2ggZXhwb3J0XHJcbiAgICAgIGlmIChyZXN1bHQucmVhc29uKSB7XHJcbiAgICAgICAgbG9nV2l0aFN0YWNrKFxyXG4gICAgICAgICAgMSxcclxuICAgICAgICAgIHJlc3VsdC5yZWFzb24sXHJcbiAgICAgICAgICBgW2NoYXJ0XSBCYXRjaCBleHBvcnQgbnVtYmVyICR7aW5kZXggKyAxfSBjb3VsZCBub3QgYmUgY29ycmVjdGx5IGNvbXBsZXRlZC5gXHJcbiAgICAgICAgKTtcclxuICAgICAgfVxyXG4gICAgfSk7XHJcbiAgfSBlbHNlIHtcclxuICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcihcclxuICAgICAgJ1tjaGFydF0gTm8gZXhwZWN0ZWQgYGV4cG9ydGAgb3B0aW9ucyB3ZXJlIGZvdW5kLiBQbGVhc2UgcHJvdmlkZSB0aGUgYGJhdGNoYCBvcHRpb24gdG8gZ2VuZXJhdGUgdmFsaWQgaW1hZ2VzLicsXHJcbiAgICAgIDQwMFxyXG4gICAgKTtcclxuICB9XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBTdGFydHMgYW4gZXhwb3J0IHByb2Nlc3MuIFRoZSBgaW1hZ2VPcHRpb25zYCBwYXJhbWV0ZXIgaXMgYW4gb2JqZWN0IHRoYXRcclxuICogc2hvdWxkIGluY2x1ZGUgc2V0dGluZ3MgZnJvbSB0aGUgYGV4cG9ydGAgYW5kIGBjdXN0b21Mb2dpY2Agc2VjdGlvbnMuIEl0IGNhblxyXG4gKiBiZSBhIHBhcnRpYWwgb3IgY29tcGxldGUgc2V0IG9mIG9wdGlvbnMgZnJvbSB0aGVzZSBzZWN0aW9ucy4gSWYgcGFydGlhbFxyXG4gKiBvcHRpb25zIGFyZSBwcm92aWRlZCwgbWlzc2luZyB2YWx1ZXMgd2lsbCBiZSBtZXJnZWQgd2l0aCB0aGUgY3VycmVudCBnbG9iYWxcclxuICogb3B0aW9ucy5cclxuICpcclxuICogVGhlIGBlbmRDYWxsYmFja2AgZnVuY3Rpb24gaXMgaW52b2tlZCB1cG9uIHRoZSBjb21wbGV0aW9uIG9mIHRoZSBleHBvcnQsXHJcbiAqIGVpdGhlciBzdWNjZXNzZnVsbHkgb3Igd2l0aCBhbiBlcnJvci4gVGhlIGBlcnJvcmAgb2JqZWN0IGlzIHByb3ZpZGVkXHJcbiAqIGFzIHRoZSBmaXJzdCBhcmd1bWVudCwgYW5kIHRoZSBgZGF0YWAgb2JqZWN0IGlzIHRoZSBzZWNvbmQsIGNvbnRhaW5pbmdcclxuICogdGhlIEJhc2U2NCByZXByZXNlbnRhdGlvbiBvZiB0aGUgY2hhcnQgaW4gdGhlIGByZXN1bHRgIHByb3BlcnR5XHJcbiAqIGFuZCB0aGUgY29tcGxldGUgc2V0IG9mIG9wdGlvbnMgaW4gdGhlIGBvcHRpb25zYCBwcm9wZXJ0eS5cclxuICpcclxuICogQGFzeW5jXHJcbiAqIEBmdW5jdGlvbiBzdGFydEV4cG9ydFxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gaW1hZ2VPcHRpb25zIC0gVGhlIGBpbWFnZU9wdGlvbnNgIG9iamVjdCwgd2hpY2ggc2hvdWxkXHJcbiAqIGluY2x1ZGUgc2V0dGluZ3MgZnJvbSB0aGUgYGV4cG9ydGAgYW5kIGBjdXN0b21Mb2dpY2Agc2VjdGlvbnMuIEl0IGNhblxyXG4gKiBiZSBhIHBhcnRpYWwgb3IgY29tcGxldGUgc2V0IG9mIG9wdGlvbnMgZnJvbSB0aGVzZSBzZWN0aW9ucy4gSWYgdGhlIHByb3ZpZGVkXHJcbiAqIG9wdGlvbnMgYXJlIHBhcnRpYWwsIG1pc3NpbmcgdmFsdWVzIHdpbGwgYmUgbWVyZ2VkIHdpdGggdGhlIGN1cnJlbnQgZ2xvYmFsXHJcbiAqIG9wdGlvbnMuXHJcbiAqIEBwYXJhbSB7RnVuY3Rpb259IGVuZENhbGxiYWNrIC0gVGhlIGNhbGxiYWNrIGZ1bmN0aW9uIHRvIGJlIGludm9rZWQgdXBvblxyXG4gKiBmaW5hbGl6aW5nIHRoZSBleHBvcnQgcHJvY2VzcyBvciB1cG9uIGVuY291bnRlcmluZyBhbiBlcnJvci4gVGhlIGZpcnN0XHJcbiAqIGFyZ3VtZW50IGlzIHRoZSBgZXJyb3JgIG9iamVjdCwgYW5kIHRoZSBzZWNvbmQgYXJndW1lbnQgaXMgdGhlIGBkYXRhYCBvYmplY3QsXHJcbiAqIHdoaWNoIGluY2x1ZGVzIHRoZSBCYXNlNjQgcmVwcmVzZW50YXRpb24gb2YgdGhlIGNoYXJ0IGluIHRoZSBgcmVzdWx0YFxyXG4gKiBwcm9wZXJ0eSBhbmQgdGhlIGZ1bGwgc2V0IG9mIG9wdGlvbnMgaW4gdGhlIGBvcHRpb25zYCBwcm9wZXJ0eS5cclxuICpcclxuICogQHJldHVybnMge1Byb21pc2U8dm9pZD59IFRoaXMgZnVuY3Rpb24gZG9lcyBub3QgcmV0dXJuIGEgdmFsdWUgZGlyZWN0bHkuXHJcbiAqIEluc3RlYWQsIGl0IGNvbW11bmljYXRlcyByZXN1bHRzIHZpYSB0aGUgYGVuZENhbGxiYWNrYC5cclxuICpcclxuICogQHRocm93cyB7RXhwb3J0RXJyb3J9IFRocm93cyBhbiBgRXhwb3J0RXJyb3JgIGlmIHRoZXJlIGlzIGEgcHJvYmxlbSB3aXRoXHJcbiAqIHByb2Nlc3NpbmcgaW5wdXQgb2YgYW55IHR5cGUuIFRoZSBlcnJvciBpcyBwYXNzZWQgaW50byB0aGUgYGVuZENhbGxiYWNrYFxyXG4gKiBmdW5jdGlvbiBhbmQgcHJvY2Vzc2VkIHRoZXJlLlxyXG4gKi9cclxuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIHN0YXJ0RXhwb3J0KGltYWdlT3B0aW9ucywgZW5kQ2FsbGJhY2spIHtcclxuICB0cnkge1xyXG4gICAgLy8gQ2hlY2sgaWYgcHJvdmlkZWQgb3B0aW9ucyBhcmUgaW4gYW4gb2JqZWN0XHJcbiAgICBpZiAoIWlzT2JqZWN0KGltYWdlT3B0aW9ucykpIHtcclxuICAgICAgdGhyb3cgbmV3IEV4cG9ydEVycm9yKFxyXG4gICAgICAgICdbY2hhcnRdIEluY29ycmVjdCB2YWx1ZSBvZiB0aGUgcHJvdmlkZWQgYGltYWdlT3B0aW9uc2AuIE5lZWRzIHRvIGJlIGFuIG9iamVjdC4nLFxyXG4gICAgICAgIDQwMFxyXG4gICAgICApO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIE1lcmdlIGFkZGl0aW9uYWwgb3B0aW9ucyB0byB0aGUgY29weSBvZiB0aGUgaW5zdGFuY2Ugb3B0aW9uc1xyXG4gICAgY29uc3Qgb3B0aW9ucyA9IHVwZGF0ZU9wdGlvbnMoXHJcbiAgICAgIHtcclxuICAgICAgICBleHBvcnQ6IGltYWdlT3B0aW9ucy5leHBvcnQsXHJcbiAgICAgICAgY3VzdG9tTG9naWM6IGltYWdlT3B0aW9ucy5jdXN0b21Mb2dpY1xyXG4gICAgICB9LFxyXG4gICAgICB0cnVlXHJcbiAgICApO1xyXG5cclxuICAgIC8vIEdldCB0aGUgYGV4cG9ydGAgb3B0aW9uc1xyXG4gICAgY29uc3QgZXhwb3J0T3B0aW9ucyA9IG9wdGlvbnMuZXhwb3J0O1xyXG5cclxuICAgIC8vIFN0YXJ0aW5nIGV4cG9ydGluZyBwcm9jZXNzIG1lc3NhZ2VcclxuICAgIGxvZyg0LCAnW2NoYXJ0XSBTdGFydGluZyB0aGUgZXhwb3J0aW5nIHByb2Nlc3MuJyk7XHJcblxyXG4gICAgLy8gRXhwb3J0IHVzaW5nIG9wdGlvbnMgZnJvbSB0aGUgZmlsZSBhcyBhbiBpbnB1dFxyXG4gICAgaWYgKGV4cG9ydE9wdGlvbnMuaW5maWxlICE9PSBudWxsKSB7XHJcbiAgICAgIGxvZyg0LCAnW2NoYXJ0XSBBdHRlbXB0aW5nIHRvIGV4cG9ydCBmcm9tIGEgZmlsZSBpbnB1dC4nKTtcclxuXHJcbiAgICAgIGxldCBmaWxlQ29udGVudDtcclxuICAgICAgdHJ5IHtcclxuICAgICAgICAvLyBUcnkgdG8gcmVhZCB0aGUgZmlsZSB0byBnZXQgdGhlIHN0cmluZyByZXByZXNlbnRhdGlvblxyXG4gICAgICAgIGZpbGVDb250ZW50ID0gcmVhZEZpbGVTeW5jKFxyXG4gICAgICAgICAgZ2V0QWJzb2x1dGVQYXRoKGV4cG9ydE9wdGlvbnMuaW5maWxlKSxcclxuICAgICAgICAgICd1dGY4J1xyXG4gICAgICAgICk7XHJcbiAgICAgIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICAgICAgdGhyb3cgbmV3IEV4cG9ydEVycm9yKFxyXG4gICAgICAgICAgJ1tjaGFydF0gRXJyb3IgbG9hZGluZyBjb250ZW50IGZyb20gYSBmaWxlIGlucHV0LicsXHJcbiAgICAgICAgICA0MDBcclxuICAgICAgICApLnNldEVycm9yKGVycm9yKTtcclxuICAgICAgfVxyXG5cclxuICAgICAgLy8gQ2hlY2sgdGhlIGZpbGUncyBleHRlbnNpb25cclxuICAgICAgaWYgKGV4cG9ydE9wdGlvbnMuaW5maWxlLmVuZHNXaXRoKCcuc3ZnJykpIHtcclxuICAgICAgICAvLyBTZXQgdG8gdGhlIGBzdmdgIG9wdGlvblxyXG4gICAgICAgIGV4cG9ydE9wdGlvbnMuc3ZnID0gdmFsaWRhdGVPcHRpb24oJ3N2ZycsIGZpbGVDb250ZW50KTtcclxuICAgICAgfSBlbHNlIGlmIChleHBvcnRPcHRpb25zLmluZmlsZS5lbmRzV2l0aCgnLmpzb24nKSkge1xyXG4gICAgICAgIC8vIFNldCB0byB0aGUgYGluc3RyYCBvcHRpb25cclxuICAgICAgICBleHBvcnRPcHRpb25zLmluc3RyID0gdmFsaWRhdGVPcHRpb24oJ2luc3RyJywgZmlsZUNvbnRlbnQpO1xyXG4gICAgICB9IGVsc2Uge1xyXG4gICAgICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcihcclxuICAgICAgICAgICdbY2hhcnRdIEluY29ycmVjdCB2YWx1ZSBvZiB0aGUgYGluZmlsZWAgb3B0aW9uLicsXHJcbiAgICAgICAgICA0MDBcclxuICAgICAgICApO1xyXG4gICAgICB9XHJcbiAgICB9XHJcblxyXG4gICAgLy8gRXhwb3J0IHVzaW5nIFNWRyBhcyBhbiBpbnB1dFxyXG4gICAgaWYgKGV4cG9ydE9wdGlvbnMuc3ZnICE9PSBudWxsKSB7XHJcbiAgICAgIGxvZyg0LCAnW2NoYXJ0XSBBdHRlbXB0aW5nIHRvIGV4cG9ydCBmcm9tIGFuIFNWRyBpbnB1dC4nKTtcclxuXHJcbiAgICAgIC8vIFNWRyBleHBvcnRzIGF0dGVtcHRzIGNvdW50ZXJcclxuICAgICAgKytnZXRQb29sU3RhdHMoKS5leHBvcnRzRnJvbVN2Z0F0dGVtcHRzO1xyXG5cclxuICAgICAgLy8gRXhwb3J0IGZyb20gYW4gU1ZHIHN0cmluZ1xyXG4gICAgICBjb25zdCByZXN1bHQgPSBhd2FpdCBfZXhwb3J0RnJvbVN2ZyhcclxuICAgICAgICBzYW5pdGl6ZShleHBvcnRPcHRpb25zLnN2ZyksIC8vICMyMDlcclxuICAgICAgICBvcHRpb25zXHJcbiAgICAgICk7XHJcblxyXG4gICAgICAvLyBTVkcgZXhwb3J0cyBjb3VudGVyXHJcbiAgICAgICsrZ2V0UG9vbFN0YXRzKCkuZXhwb3J0c0Zyb21Tdmc7XHJcblxyXG4gICAgICAvLyBQYXNzIFNWRyBleHBvcnQgcmVzdWx0IHRvIHRoZSBlbmQgY2FsbGJhY2tcclxuICAgICAgcmV0dXJuIGVuZENhbGxiYWNrKG51bGwsIHJlc3VsdCk7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gRXhwb3J0IHVzaW5nIG9wdGlvbnMgYXMgYW4gaW5wdXRcclxuICAgIGlmIChleHBvcnRPcHRpb25zLmluc3RyICE9PSBudWxsIHx8IGV4cG9ydE9wdGlvbnMub3B0aW9ucyAhPT0gbnVsbCkge1xyXG4gICAgICBsb2coNCwgJ1tjaGFydF0gQXR0ZW1wdGluZyB0byBleHBvcnQgZnJvbSBvcHRpb25zIGlucHV0LicpO1xyXG5cclxuICAgICAgLy8gT3B0aW9ucyBleHBvcnRzIGF0dGVtcHRzIGNvdW50ZXJcclxuICAgICAgKytnZXRQb29sU3RhdHMoKS5leHBvcnRzRnJvbU9wdGlvbnNBdHRlbXB0cztcclxuXHJcbiAgICAgIC8vIEV4cG9ydCBmcm9tIG9wdGlvbnNcclxuICAgICAgY29uc3QgcmVzdWx0ID0gYXdhaXQgX2V4cG9ydEZyb21PcHRpb25zKFxyXG4gICAgICAgIGV4cG9ydE9wdGlvbnMuaW5zdHIgfHwgZXhwb3J0T3B0aW9ucy5vcHRpb25zLFxyXG4gICAgICAgIG9wdGlvbnNcclxuICAgICAgKTtcclxuXHJcbiAgICAgIC8vIE9wdGlvbnMgZXhwb3J0cyBjb3VudGVyXHJcbiAgICAgICsrZ2V0UG9vbFN0YXRzKCkuZXhwb3J0c0Zyb21PcHRpb25zO1xyXG5cclxuICAgICAgLy8gUGFzcyBvcHRpb25zIGV4cG9ydCByZXN1bHQgdG8gdGhlIGVuZCBjYWxsYmFja1xyXG4gICAgICByZXR1cm4gZW5kQ2FsbGJhY2sobnVsbCwgcmVzdWx0KTtcclxuICAgIH1cclxuXHJcbiAgICAvLyBObyBpbnB1dCBzcGVjaWZpZWQsIHBhc3MgYW4gZXJyb3IgbWVzc2FnZSB0byB0aGUgY2FsbGJhY2tcclxuICAgIHJldHVybiBlbmRDYWxsYmFjayhcclxuICAgICAgbmV3IEV4cG9ydEVycm9yKFxyXG4gICAgICAgIGBbY2hhcnRdIE5vIHZhbGlkIGlucHV0IHNwZWNpZmllZC4gQ2hlY2sgaWYgYXQgbGVhc3Qgb25lIG9mIHRoZSBmb2xsb3dpbmcgcGFyYW1ldGVycyBpcyBjb3JyZWN0bHkgc2V0OiAnaW5maWxlJywgJ2luc3RyJywgJ29wdGlvbnMnLCBvciAnc3ZnJy5gLFxyXG4gICAgICAgIDQwMFxyXG4gICAgICApXHJcbiAgICApO1xyXG4gIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICByZXR1cm4gZW5kQ2FsbGJhY2soZXJyb3IpO1xyXG4gIH1cclxufVxyXG5cclxuLyoqXHJcbiAqIFJldHJpZXZlcyBhbmQgcmV0dXJucyB0aGUgY3VycmVudCBzdGF0dXMgb2YgdGhlIGNvZGUgZXhlY3V0aW9uIHBlcm1pc3Npb24uXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBnZXRBbGxvd0NvZGVFeGVjdXRpb25cclxuICpcclxuICogQHJldHVybnMge2Jvb2xlYW59IFRoZSB2YWx1ZSBvZiB0aGUgZ2xvYmFsIGBhbGxvd0NvZGVFeGVjdXRpb25gIG9wdGlvbi5cclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiBnZXRBbGxvd0NvZGVFeGVjdXRpb24oKSB7XHJcbiAgcmV0dXJuIGFsbG93Q29kZUV4ZWN1dGlvbjtcclxufVxyXG5cclxuLyoqXHJcbiAqIFNldHMgdGhlIGNvZGUgZXhlY3V0aW9uIHBlcm1pc3Npb24gYmFzZWQgb24gdGhlIHByb3ZpZGVkIGJvb2xlYW4gdmFsdWUuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBzZXRBbGxvd0NvZGVFeGVjdXRpb25cclxuICpcclxuICogQHBhcmFtIHtib29sZWFufSB2YWx1ZSAtIFRoZSBib29sZWFuIHZhbHVlIHRvIGJlIGFzc2lnbmVkIHRvIHRoZSBnbG9iYWxcclxuICogYGFsbG93Q29kZUV4ZWN1dGlvbmAgb3B0aW9uLlxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIHNldEFsbG93Q29kZUV4ZWN1dGlvbih2YWx1ZSkge1xyXG4gIGFsbG93Q29kZUV4ZWN1dGlvbiA9IHZhbHVlO1xyXG59XHJcblxyXG4vKipcclxuICogRXhwb3J0cyBmcm9tIGFuIFNWRyBiYXNlZCBpbnB1dCB3aXRoIHRoZSBwcm92aWRlZCBvcHRpb25zLlxyXG4gKlxyXG4gKiBAYXN5bmNcclxuICogQGZ1bmN0aW9uIF9leHBvcnRGcm9tU3ZnXHJcbiAqXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSBpbnB1dFRvRXhwb3J0IC0gVGhlIFNWRyBiYXNlZCBpbnB1dCB0byBiZSBleHBvcnRlZC5cclxuICogQHBhcmFtIHtPYmplY3R9IG9wdGlvbnMgLSBUaGUgY29uZmlndXJhdGlvbiBvYmplY3QgY29udGFpbmluZyBjb21wbGV0ZSBzZXRcclxuICogb2Ygb3B0aW9ucy5cclxuICpcclxuICogQHJldHVybnMge1Byb21pc2U8dW5rbm93bj59IEEgUHJvbWlzZSB0aGF0IHJlc29sdmVzIHRvIGEgcmVzdWx0IG9mIHRoZSBleHBvcnRcclxuICogcHJvY2Vzcy5cclxuICpcclxuICogQHRocm93cyB7RXhwb3J0RXJyb3J9IFRocm93cyBhbiBgRXhwb3J0RXJyb3JgIGlmIHRoZXJlIGlzIG5vdCBhIGNvcnJlY3QgU1ZHXHJcbiAqIGlucHV0LlxyXG4gKi9cclxuYXN5bmMgZnVuY3Rpb24gX2V4cG9ydEZyb21TdmcoaW5wdXRUb0V4cG9ydCwgb3B0aW9ucykge1xyXG4gIC8vIENoZWNrIGlmIGl0IGlzIFNWR1xyXG4gIGlmIChcclxuICAgIHR5cGVvZiBpbnB1dFRvRXhwb3J0ID09PSAnc3RyaW5nJyAmJlxyXG4gICAgKGlucHV0VG9FeHBvcnQuaW5kZXhPZignPHN2ZycpID49IDAgfHwgaW5wdXRUb0V4cG9ydC5pbmRleE9mKCc8P3htbCcpID49IDApXHJcbiAgKSB7XHJcbiAgICBsb2coNCwgJ1tjaGFydF0gUGFyc2luZyBpbnB1dCBhcyBTVkcuJyk7XHJcblxyXG4gICAgLy8gU2V0IHRoZSBleHBvcnQgaW5wdXQgYXMgU1ZHXHJcbiAgICBvcHRpb25zLmV4cG9ydC5zdmcgPSBpbnB1dFRvRXhwb3J0O1xyXG5cclxuICAgIC8vIFJlc2V0IHRoZSByZXN0IG9mIHRoZSBleHBvcnQgaW5wdXQgb3B0aW9uc1xyXG4gICAgb3B0aW9ucy5leHBvcnQub3B0aW9ucyA9IG51bGw7XHJcbiAgICBvcHRpb25zLmV4cG9ydC5pbnN0ciA9IG51bGw7XHJcblxyXG4gICAgLy8gQ2FsbCB0aGUgZnVuY3Rpb24gd2l0aCBhbiBTVkcgc3RyaW5nIGFzIGFuIGV4cG9ydCBpbnB1dFxyXG4gICAgcmV0dXJuIF9wcmVwYXJlRXhwb3J0KG9wdGlvbnMpO1xyXG4gIH0gZWxzZSB7XHJcbiAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoJ1tjaGFydF0gTm90IGEgY29ycmVjdCBTVkcgaW5wdXQuJywgNDAwKTtcclxuICB9XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBFeHBvcnRzIGZyb20gYW4gb3B0aW9ucyBiYXNlZCBpbnB1dCB3aXRoIHRoZSBwcm92aWRlZCBvcHRpb25zLlxyXG4gKlxyXG4gKiBAYXN5bmNcclxuICogQGZ1bmN0aW9uIF9leHBvcnRGcm9tT3B0aW9uc1xyXG4gKlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gaW5wdXRUb0V4cG9ydCAtIFRoZSBvcHRpb25zIGJhc2VkIGlucHV0IHRvIGJlIGV4cG9ydGVkLlxyXG4gKiBAcGFyYW0ge09iamVjdH0gb3B0aW9ucyAtIFRoZSBjb25maWd1cmF0aW9uIG9iamVjdCBjb250YWluaW5nIGNvbXBsZXRlIHNldFxyXG4gKiBvZiBvcHRpb25zLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7UHJvbWlzZTx1bmtub3duPn0gQSBQcm9taXNlIHRoYXQgcmVzb2x2ZXMgdG8gYSByZXN1bHQgb2YgdGhlIGV4cG9ydFxyXG4gKiBwcm9jZXNzLlxyXG4gKlxyXG4gKiBAdGhyb3dzIHtFeHBvcnRFcnJvcn0gVGhyb3dzIGFuIGBFeHBvcnRFcnJvcmAgaWYgdGhlcmUgaXMgbm90IGEgY29ycmVjdFxyXG4gKiBjaGFydCBvcHRpb25zIGlucHV0LlxyXG4gKi9cclxuYXN5bmMgZnVuY3Rpb24gX2V4cG9ydEZyb21PcHRpb25zKGlucHV0VG9FeHBvcnQsIG9wdGlvbnMpIHtcclxuICBsb2coNCwgJ1tjaGFydF0gUGFyc2luZyBpbnB1dCBmcm9tIG9wdGlvbnMuJyk7XHJcblxyXG4gIC8vIFRyeSB0byBjaGVjaywgdmFsaWRhdGUgYW5kIHBhcnNlIHRvIHN0cmluZ2lmaWVkIG9wdGlvbnNcclxuICBjb25zdCBzdHJpbmdpZmllZE9wdGlvbnMgPSBpc0FsbG93ZWRDb25maWcoXHJcbiAgICBpbnB1dFRvRXhwb3J0LFxyXG4gICAgdHJ1ZSxcclxuICAgIG9wdGlvbnMuY3VzdG9tTG9naWMuYWxsb3dDb2RlRXhlY3V0aW9uXHJcbiAgKTtcclxuXHJcbiAgLy8gQ2hlY2sgaWYgYSBjb3JyZWN0IHN0cmluZ2lmaWVkIG9wdGlvbnNcclxuICBpZiAoXHJcbiAgICBzdHJpbmdpZmllZE9wdGlvbnMgPT09IG51bGwgfHxcclxuICAgIHR5cGVvZiBzdHJpbmdpZmllZE9wdGlvbnMgIT09ICdzdHJpbmcnIHx8XHJcbiAgICAhc3RyaW5naWZpZWRPcHRpb25zLnN0YXJ0c1dpdGgoJ3snKSB8fFxyXG4gICAgIXN0cmluZ2lmaWVkT3B0aW9ucy5lbmRzV2l0aCgnfScpXHJcbiAgKSB7XHJcbiAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoXHJcbiAgICAgICdbY2hhcnRdIEludmFsaWQgY29uZmlndXJhdGlvbiBwcm92aWRlZCAtIE9ubHkgb3B0aW9ucyBjb25maWd1cmF0aW9ucyBhbmQgU1ZHIGFyZSBhbGxvd2VkIGZvciB0aGlzIHNlcnZlci4gSWYgdGhpcyBpcyB5b3VyIHNlcnZlciwgSmF2YVNjcmlwdCBjdXN0b20gY29kZSBjYW4gYmUgZW5hYmxlZCBieSBzdGFydGluZyB0aGUgc2VydmVyIHdpdGggdGhlIGBhbGxvd0NvZGVFeGVjdXRpb25gIG9wdGlvbnMgc2V0IHRvIHRydWUuJyxcclxuICAgICAgNDAzXHJcbiAgICApO1xyXG4gIH1cclxuXHJcbiAgLy8gU2V0IHRoZSBleHBvcnQgaW5wdXQgYXMgYSBzdHJpbmdpZmllZCBjaGFydCBvcHRpb25zXHJcbiAgb3B0aW9ucy5leHBvcnQuaW5zdHIgPSBzdHJpbmdpZmllZE9wdGlvbnM7XHJcblxyXG4gIC8vIFJlc2V0IHRoZSByZXN0IG9mIHRoZSBleHBvcnQgaW5wdXQgb3B0aW9uc1xyXG4gIG9wdGlvbnMuZXhwb3J0Lm9wdGlvbnMgPSBudWxsO1xyXG4gIG9wdGlvbnMuZXhwb3J0LnN2ZyA9IG51bGw7XHJcblxyXG4gIC8vIENhbGwgdGhlIGZ1bmN0aW9uIHdpdGggYSBzdHJpbmdpZmllZCBjaGFydCBvcHRpb25zXHJcbiAgcmV0dXJuIF9wcmVwYXJlRXhwb3J0KG9wdGlvbnMpO1xyXG59XHJcblxyXG4vKipcclxuICogRnVuY3Rpb24gZm9yIGZpbmFsaXppbmcgb3B0aW9ucyBhbmQgY29uZmlndXJhdGlvbnMgYmVmb3JlIGV4cG9ydC5cclxuICpcclxuICogQGFzeW5jXHJcbiAqIEBmdW5jdGlvbiBfcHJlcGFyZUV4cG9ydFxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gb3B0aW9ucyAtIFRoZSBjb25maWd1cmF0aW9uIG9iamVjdCBjb250YWluaW5nIGNvbXBsZXRlIHNldFxyXG4gKiBvZiBvcHRpb25zLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7UHJvbWlzZTx1bmtub3duPn0gQSBQcm9taXNlIHRoYXQgcmVzb2x2ZXMgdG8gYSByZXN1bHQgb2YgdGhlIGV4cG9ydFxyXG4gKiBwcm9jZXNzLlxyXG4gKi9cclxuYXN5bmMgZnVuY3Rpb24gX3ByZXBhcmVFeHBvcnQob3B0aW9ucykge1xyXG4gIC8vIEdldCB0aGUgYGV4cG9ydGAgYW5kIGBjdXN0b21Mb2dpY2Agb3B0aW9uc1xyXG4gIGNvbnN0IHsgZXhwb3J0OiBleHBvcnRPcHRpb25zLCBjdXN0b21Mb2dpYzogY3VzdG9tTG9naWNPcHRpb25zIH0gPSBvcHRpb25zO1xyXG5cclxuICAvLyBQcmVwYXJlIHRoZSBgY29uc3RyYCBvcHRpb25cclxuICBleHBvcnRPcHRpb25zLmNvbnN0ciA9IF9maXhDb25zdHIoZXhwb3J0T3B0aW9ucy5jb25zdHIpO1xyXG5cclxuICAvLyBQcmVwYXJlIHRoZSBgdHlwZWAgb3B0aW9uXHJcbiAgZXhwb3J0T3B0aW9ucy50eXBlID0gX2ZpeFR5cGUoZXhwb3J0T3B0aW9ucy50eXBlLCBleHBvcnRPcHRpb25zLm91dGZpbGUpO1xyXG5cclxuICAvLyBQcmVwYXJlIHRoZSBgb3V0ZmlsZWAgb3B0aW9uXHJcbiAgZXhwb3J0T3B0aW9ucy5vdXRmaWxlID0gX2ZpeE91dGZpbGUoXHJcbiAgICBleHBvcnRPcHRpb25zLnR5cGUsXHJcbiAgICBleHBvcnRPcHRpb25zLm91dGZpbGVcclxuICApO1xyXG5cclxuICAvLyBOb3RpZnkgYWJvdXQgdGhlIGN1c3RvbSBsb2dpYyB1c2FnZSBzdGF0dXNcclxuICBsb2coXHJcbiAgICAzLFxyXG4gICAgYFtjaGFydF0gVGhlIGN1c3RvbSBsb2dpYyBpcyAke2N1c3RvbUxvZ2ljT3B0aW9ucy5hbGxvd0NvZGVFeGVjdXRpb24gPyAnYWxsb3dlZCcgOiAnZGlzYWxsb3dlZCd9LmBcclxuICApO1xyXG5cclxuICAvLyBQcmVwYXJlIHRoZSBgY3VzdG9tQ29kZWAsIGBjYWxsYmFja2AsIGFuZCBgcmVzb3VyY2VzYCBvcHRpb25zXHJcbiAgX2hhbmRsZUN1c3RvbUxvZ2ljKGN1c3RvbUxvZ2ljT3B0aW9ucyk7XHJcblxyXG4gIC8vIFByZXBhcmUgdGhlIGBnbG9iYWxPcHRpb25zYCBhbmQgYHRoZW1lT3B0aW9uc2Agb3B0aW9uc1xyXG4gIF9oYW5kbGVHbG9iYWxBbmRUaGVtZShleHBvcnRPcHRpb25zLCBjdXN0b21Mb2dpY09wdGlvbnMpO1xyXG5cclxuICAvLyBQcmVwYXJlIHRoZSBgaGVpZ2h0YCwgYHdpZHRoYCwgYW5kIGBzY2FsZWAgb3B0aW9uc1xyXG4gIF9oYW5kbGVTaXplKGV4cG9ydE9wdGlvbnMpO1xyXG5cclxuICAvLyBDaGVjayBpZiB0aGUgaW1hZ2Ugb3B0aW9ucyBvYmplY3QgZG9lcyBub3QgZXhjZWVkIHRoZSBzaXplIGxpbWl0XHJcbiAgX2NoZWNrRGF0YVNpemUoeyBleHBvcnQ6IGV4cG9ydE9wdGlvbnMsIGN1c3RvbUxvZ2ljOiBjdXN0b21Mb2dpY09wdGlvbnMgfSk7XHJcblxyXG4gIC8vIFBvc3QgdGhlIHdvcmsgdG8gdGhlIHBvb2xcclxuICByZXR1cm4gcG9zdFdvcmsob3B0aW9ucyk7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBIYW5kbGVzIGFkanVzdGluZyB0aGUgY29uc3RydWN0b3IgbmFtZSBieSB0cmFuc2Zvcm1pbmcgYW5kIG5vcm1hbGl6aW5nXHJcbiAqIGl0IGJhc2VkIG9uIGNvbW1vbiBjaGFydCB0eXBlcy5cclxuICpcclxuICogQGZ1bmN0aW9uIF9maXhDb25zdHJcclxuICpcclxuICogQHBhcmFtIHtzdHJpbmd9IGNvbnN0ciAtIFRoZSBvcmlnaW5hbCBjb25zdHJ1Y3RvciBuYW1lIHRvIGJlIGFkanVzdGVkLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7c3RyaW5nfSBUaGUgY29ycmVjdGVkIGNvbnN0cnVjdG9yIG5hbWUsIG9yICdjaGFydCcgaWYgdGhlIGlucHV0XHJcbiAqIGlzIG5vdCByZWNvZ25pemVkLlxyXG4gKi9cclxuZnVuY3Rpb24gX2ZpeENvbnN0cihjb25zdHIpIHtcclxuICB0cnkge1xyXG4gICAgLy8gRml4IHRoZSBjb25zdHJ1Y3RvciBieSBsb3dlcmluZyBjYXNpbmdcclxuICAgIGNvbnN0IGZpeGVkQ29uc3RyID0gYCR7Y29uc3RyLnRvTG93ZXJDYXNlKCkucmVwbGFjZSgnY2hhcnQnLCAnJyl9Q2hhcnRgO1xyXG5cclxuICAgIC8vIEhhbmRsZSB0aGUgY2FzZSB3aGVyZSB0aGUgcmVzdWx0IGlzIGp1c3QgJ0NoYXJ0J1xyXG4gICAgaWYgKGZpeGVkQ29uc3RyID09PSAnQ2hhcnQnKSB7XHJcbiAgICAgIGZpeGVkQ29uc3RyLnRvTG93ZXJDYXNlKCk7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gUmV0dXJuIHRoZSBjb3JyZWN0ZWQgY29uc3RydWN0b3IsIG90aGVyd2lzZSBkZWZhdWx0IHRvICdjaGFydCdcclxuICAgIHJldHVybiBbJ2NoYXJ0JywgJ3N0b2NrQ2hhcnQnLCAnbWFwQ2hhcnQnLCAnZ2FudHRDaGFydCddLmluY2x1ZGVzKFxyXG4gICAgICBmaXhlZENvbnN0clxyXG4gICAgKVxyXG4gICAgICA/IGZpeGVkQ29uc3RyXHJcbiAgICAgIDogJ2NoYXJ0JztcclxuICB9IGNhdGNoIHtcclxuICAgIC8vIERlZmF1bHQgdG8gJ2NoYXJ0JyBpbiBjYXNlIG9mIGFueSBlcnJvclxyXG4gICAgcmV0dXJuICdjaGFydCc7XHJcbiAgfVxyXG59XHJcblxyXG4vKipcclxuICogSGFuZGxlcyBmaXhpbmcgdGhlIG91dGZpbGUgYmFzZWQgb24gcHJvdmlkZWQgdHlwZS5cclxuICpcclxuICogQGZ1bmN0aW9uIF9maXhPdXRmaWxlXHJcbiAqXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSB0eXBlIC0gVGhlIG9yaWdpbmFsIGV4cG9ydCB0eXBlLlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gb3V0ZmlsZSAtIFRoZSBmaWxlIHBhdGggb3IgbmFtZS5cclxuICpcclxuICogQHJldHVybnMge3N0cmluZ30gVGhlIGNvcnJlY3RlZCBvdXRmaWxlLCBvciAnY2hhcnQucG5nJyBpZiB0aGUgaW5wdXRcclxuICogaXMgbm90IHJlY29nbml6ZWQuXHJcbiAqL1xyXG5mdW5jdGlvbiBfZml4T3V0ZmlsZSh0eXBlLCBvdXRmaWxlKSB7XHJcbiAgLy8gR2V0IHRoZSBmaWxlIG5hbWUgZnJvbSB0aGUgYG91dGZpbGVgIG9wdGlvblxyXG4gIGNvbnN0IGZpbGVOYW1lID0gZ2V0QWJzb2x1dGVQYXRoKG91dGZpbGUgfHwgJ2NoYXJ0JylcclxuICAgIC5zcGxpdCgnLicpXHJcbiAgICAuc2hpZnQoKTtcclxuXHJcbiAgLy8gUmV0dXJuIGEgY29ycmVjdCBvdXRmaWxlXHJcbiAgcmV0dXJuIGAke2ZpbGVOYW1lfS4ke3R5cGUgfHwgJ3BuZyd9YDtcclxufVxyXG5cclxuLyoqXHJcbiAqIEhhbmRsZXMgZml4aW5nIHRoZSBleHBvcnQgdHlwZSBiYXNlZCBvbiBNSU1FIHR5cGVzIGFuZCBmaWxlIGV4dGVuc2lvbnMuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBfZml4VHlwZVxyXG4gKlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gdHlwZSAtIFRoZSBvcmlnaW5hbCBleHBvcnQgdHlwZS5cclxuICogQHBhcmFtIHtzdHJpbmd9IFtvdXRmaWxlPW51bGxdIC0gVGhlIGZpbGUgcGF0aCBvciBuYW1lLiBUaGUgZGVmYXVsdCB2YWx1ZVxyXG4gKiBpcyBgbnVsbGAuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtzdHJpbmd9IFRoZSBjb3JyZWN0ZWQgZXhwb3J0IHR5cGUsIG9yICdwbmcnIGlmIHRoZSBpbnB1dFxyXG4gKiBpcyBub3QgcmVjb2duaXplZC5cclxuICovXHJcbmZ1bmN0aW9uIF9maXhUeXBlKHR5cGUsIG91dGZpbGUgPSBudWxsKSB7XHJcbiAgLy8gTUlNRSB0eXBlc1xyXG4gIGNvbnN0IG1pbWVUeXBlcyA9IHtcclxuICAgICdpbWFnZS9wbmcnOiAncG5nJyxcclxuICAgICdpbWFnZS9qcGVnJzogJ2pwZWcnLFxyXG4gICAgJ2FwcGxpY2F0aW9uL3BkZic6ICdwZGYnLFxyXG4gICAgJ2ltYWdlL3N2Zyt4bWwnOiAnc3ZnJ1xyXG4gIH07XHJcblxyXG4gIC8vIEdldCBmb3JtYXRzXHJcbiAgY29uc3QgZm9ybWF0cyA9IE9iamVjdC52YWx1ZXMobWltZVR5cGVzKTtcclxuXHJcbiAgLy8gQ2hlY2sgaWYgdHlwZSBhbmQgb3V0ZmlsZSdzIGV4dGVuc2lvbnMgYXJlIHRoZSBzYW1lXHJcbiAgaWYgKG91dGZpbGUpIHtcclxuICAgIGNvbnN0IG91dFR5cGUgPSBvdXRmaWxlLnNwbGl0KCcuJykucG9wKCk7XHJcblxyXG4gICAgLy8gU3VwcG9ydCB0aGUgSlBHIHR5cGVcclxuICAgIGlmIChvdXRUeXBlID09PSAnanBnJykge1xyXG4gICAgICB0eXBlID0gJ2pwZWcnO1xyXG4gICAgfSBlbHNlIGlmIChmb3JtYXRzLmluY2x1ZGVzKG91dFR5cGUpICYmIHR5cGUgIT09IG91dFR5cGUpIHtcclxuICAgICAgdHlwZSA9IG91dFR5cGU7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICAvLyBSZXR1cm4gYSBjb3JyZWN0IHR5cGVcclxuICByZXR1cm4gbWltZVR5cGVzW3R5cGVdIHx8IGZvcm1hdHMuZmluZCgodCkgPT4gdCA9PT0gdHlwZSkgfHwgJ3BuZyc7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBIYW5kbGUgY2FsY3VsYXRpbmcgdGhlIGBoZWlnaHRgLCBgd2lkdGhgIGFuZCBgc2NhbGVgIGZvciBjaGFydCBleHBvcnRzIGJhc2VkXHJcbiAqIG9uIHRoZSBwcm92aWRlZCBleHBvcnQgb3B0aW9ucy5cclxuICpcclxuICogVGhlIGZ1bmN0aW9uIHByaW9yaXRpemVzIHZhbHVlcyBpbiB0aGUgZm9sbG93aW5nIG9yZGVyOlxyXG4gKlxyXG4gKiAxLiBUaGUgYGhlaWdodGAsIGB3aWR0aGAsIGBzY2FsZWAgZnJvbSB0aGUgYGV4cG9ydE9wdGlvbnNgLlxyXG4gKiAyLiBPcHRpb25zIGZyb20gdGhlIGNoYXJ0IGNvbmZpZ3VyYXRpb24gKGZyb20gYGV4cG9ydGluZ2AgYW5kIGBjaGFydGApLlxyXG4gKiAzLiBPcHRpb25zIGZyb20gdGhlIGdsb2JhbCBvcHRpb25zIChmcm9tIGBleHBvcnRpbmdgIGFuZCBgY2hhcnRgKS5cclxuICogNC4gT3B0aW9ucyBmcm9tIHRoZSB0aGVtZSBvcHRpb25zIChmcm9tIGBleHBvcnRpbmdgIGFuZCBgY2hhcnRgIHNlY3Rpb25zKS5cclxuICogNS4gRmFsbGJhY2sgZGVmYXVsdCB2YWx1ZXMgKGBoZWlnaHQgPSA0MDBgLCBgd2lkdGggPSA2MDBgLCBgc2NhbGUgPSAxYCkuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBfaGFuZGxlU2l6ZVxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gZXhwb3J0T3B0aW9ucyAtIFRoZSBjb25maWd1cmF0aW9uIG9iamVjdCBjb250YWluaW5nIGBleHBvcnRgXHJcbiAqIG9wdGlvbnMuXHJcbiAqL1xyXG5mdW5jdGlvbiBfaGFuZGxlU2l6ZShleHBvcnRPcHRpb25zKSB7XHJcbiAgLy8gQ2hlY2sgdGhlIGBvcHRpb25zYCBhbmQgYGluc3RyYCBmb3IgY2hhcnQgYW5kIGV4cG9ydGluZyBzZWN0aW9uc1xyXG4gIGNvbnN0IHsgY2hhcnQ6IG9wdGlvbnNDaGFydCwgZXhwb3J0aW5nOiBvcHRpb25zRXhwb3J0aW5nIH0gPVxyXG4gICAgaXNBbGxvd2VkQ29uZmlnKGV4cG9ydE9wdGlvbnMuaW5zdHIpIHx8IGZhbHNlO1xyXG5cclxuICAvLyBDaGVjayB0aGUgYGdsb2JhbE9wdGlvbnNgIGZvciBjaGFydCBhbmQgZXhwb3J0aW5nIHNlY3Rpb25zXHJcbiAgY29uc3QgeyBjaGFydDogZ2xvYmFsT3B0aW9uc0NoYXJ0LCBleHBvcnRpbmc6IGdsb2JhbE9wdGlvbnNFeHBvcnRpbmcgfSA9XHJcbiAgICBpc0FsbG93ZWRDb25maWcoZXhwb3J0T3B0aW9ucy5nbG9iYWxPcHRpb25zKSB8fCBmYWxzZTtcclxuXHJcbiAgLy8gQ2hlY2sgdGhlIGB0aGVtZU9wdGlvbnNgIGZvciBjaGFydCBhbmQgZXhwb3J0aW5nIHNlY3Rpb25zXHJcbiAgY29uc3QgeyBjaGFydDogdGhlbWVPcHRpb25zQ2hhcnQsIGV4cG9ydGluZzogdGhlbWVPcHRpb25zRXhwb3J0aW5nIH0gPVxyXG4gICAgaXNBbGxvd2VkQ29uZmlnKGV4cG9ydE9wdGlvbnMudGhlbWVPcHRpb25zKSB8fCBmYWxzZTtcclxuXHJcbiAgLy8gRmluZCB0aGUgYGhlaWdodGAgdmFsdWVcclxuICBjb25zdCBoZWlnaHQgPVxyXG4gICAgZXhwb3J0T3B0aW9ucy5oZWlnaHQgfHxcclxuICAgIG9wdGlvbnNFeHBvcnRpbmc/LnNvdXJjZUhlaWdodCB8fFxyXG4gICAgb3B0aW9uc0NoYXJ0Py5oZWlnaHQgfHxcclxuICAgIGdsb2JhbE9wdGlvbnNFeHBvcnRpbmc/LnNvdXJjZUhlaWdodCB8fFxyXG4gICAgZ2xvYmFsT3B0aW9uc0NoYXJ0Py5oZWlnaHQgfHxcclxuICAgIHRoZW1lT3B0aW9uc0V4cG9ydGluZz8uc291cmNlSGVpZ2h0IHx8XHJcbiAgICB0aGVtZU9wdGlvbnNDaGFydD8uaGVpZ2h0IHx8XHJcbiAgICBleHBvcnRPcHRpb25zLmRlZmF1bHRIZWlnaHQgfHxcclxuICAgIDQwMDtcclxuXHJcbiAgLy8gRmluZCB0aGUgYHdpZHRoYCB2YWx1ZVxyXG4gIGNvbnN0IHdpZHRoID1cclxuICAgIGV4cG9ydE9wdGlvbnMud2lkdGggfHxcclxuICAgIG9wdGlvbnNFeHBvcnRpbmc/LnNvdXJjZVdpZHRoIHx8XHJcbiAgICBvcHRpb25zQ2hhcnQ/LndpZHRoIHx8XHJcbiAgICBnbG9iYWxPcHRpb25zRXhwb3J0aW5nPy5zb3VyY2VXaWR0aCB8fFxyXG4gICAgZ2xvYmFsT3B0aW9uc0NoYXJ0Py53aWR0aCB8fFxyXG4gICAgdGhlbWVPcHRpb25zRXhwb3J0aW5nPy5zb3VyY2VXaWR0aCB8fFxyXG4gICAgdGhlbWVPcHRpb25zQ2hhcnQ/LndpZHRoIHx8XHJcbiAgICBleHBvcnRPcHRpb25zLmRlZmF1bHRXaWR0aCB8fFxyXG4gICAgNjAwO1xyXG5cclxuICAvLyBGaW5kIHRoZSBgc2NhbGVgIHZhbHVlOlxyXG4gIC8vIC0gQ2Fubm90IGJlIGxvd2VyIHRoYW4gMC4xXHJcbiAgLy8gLSBDYW5ub3QgYmUgaGlnaGVyIHRoYW4gNS4wXHJcbiAgLy8gLSBNdXN0IGJlIHJvdW5kZWQgdG8gMiBkZWNpbWFsIHBsYWNlcyAoZS5nLiAwLjIzMjM0IC0+IDAuMjMpXHJcbiAgY29uc3Qgc2NhbGUgPSByb3VuZE51bWJlcihcclxuICAgIE1hdGgubWF4KFxyXG4gICAgICAwLjEsXHJcbiAgICAgIE1hdGgubWluKFxyXG4gICAgICAgIGV4cG9ydE9wdGlvbnMuc2NhbGUgfHxcclxuICAgICAgICAgIG9wdGlvbnNFeHBvcnRpbmc/LnNjYWxlIHx8XHJcbiAgICAgICAgICBnbG9iYWxPcHRpb25zRXhwb3J0aW5nPy5zY2FsZSB8fFxyXG4gICAgICAgICAgdGhlbWVPcHRpb25zRXhwb3J0aW5nPy5zY2FsZSB8fFxyXG4gICAgICAgICAgZXhwb3J0T3B0aW9ucy5kZWZhdWx0U2NhbGUgfHxcclxuICAgICAgICAgIDEsXHJcbiAgICAgICAgNS4wXHJcbiAgICAgIClcclxuICAgICksXHJcbiAgICAyXHJcbiAgKTtcclxuXHJcbiAgLy8gVXBkYXRlIGBoZWlnaHRgLCBgd2lkdGhgLCBhbmQgYHNjYWxlYCBpbmZvcm1hdGlvbiBpbiB0aGUgYGV4cG9ydGAgb3B0aW9uc1xyXG4gIGV4cG9ydE9wdGlvbnMuaGVpZ2h0ID0gaGVpZ2h0O1xyXG4gIGV4cG9ydE9wdGlvbnMud2lkdGggPSB3aWR0aDtcclxuICBleHBvcnRPcHRpb25zLnNjYWxlID0gc2NhbGU7XHJcblxyXG4gIC8vIEdldCByaWQgb2YgcG90ZW50aWFsIGBweGAgYW5kIGAlYFxyXG4gIGZvciAobGV0IHBhcmFtIG9mIFsnaGVpZ2h0JywgJ3dpZHRoJywgJ3NjYWxlJ10pIHtcclxuICAgIGlmICh0eXBlb2YgZXhwb3J0T3B0aW9uc1twYXJhbV0gPT09ICdzdHJpbmcnKSB7XHJcbiAgICAgIGV4cG9ydE9wdGlvbnNbcGFyYW1dID0gK2V4cG9ydE9wdGlvbnNbcGFyYW1dLnJlcGxhY2UoL3B4fCUvZ2ksICcnKTtcclxuICAgIH1cclxuICB9XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBIYW5kbGVzIHRoZSBleGVjdXRpb24gb2YgY3VzdG9tIGxvZ2ljIG9wdGlvbnMsIGluY2x1ZGluZyBsb2FkaW5nIGByZXNvdXJjZXNgLFxyXG4gKiBgY3VzdG9tQ29kZWAsIGFuZCBgY2FsbGJhY2tgLiBJZiBjb2RlIGV4ZWN1dGlvbiBpcyBhbGxvd2VkLCBpdCBwcm9jZXNzZXNcclxuICogdGhlIGN1c3RvbSBsb2dpYyBvcHRpb25zIGFjY29yZGluZ2x5LiBJZiBjb2RlIGV4ZWN1dGlvbiBpcyBub3QgYWxsb3dlZCxcclxuICogaXQgZGlzYWJsZXMgdGhlIHVzYWdlIG9mIHJlc291cmNlcywgY3VzdG9tIGNvZGUgYW5kIGNhbGxiYWNrLlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gX2hhbmRsZUN1c3RvbUxvZ2ljXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBjdXN0b21Mb2dpY09wdGlvbnMgLSBUaGUgY29uZmlndXJhdGlvbiBvYmplY3QgY29udGFpbmluZ1xyXG4gKiBgY3VzdG9tTG9naWNgIG9wdGlvbnMuXHJcbiAqXHJcbiAqIEB0aHJvd3Mge0V4cG9ydEVycm9yfSBUaHJvd3MgYW4gYEV4cG9ydEVycm9yYCBpZiBjb2RlIGV4ZWN1dGlvblxyXG4gKiBpcyBub3QgYWxsb3dlZCBidXQgY3VzdG9tIGxvZ2ljIG9wdGlvbnMgYXJlIHN0aWxsIHByb3ZpZGVkLlxyXG4gKi9cclxuZnVuY3Rpb24gX2hhbmRsZUN1c3RvbUxvZ2ljKGN1c3RvbUxvZ2ljT3B0aW9ucykge1xyXG4gIC8vIEluIGNhc2Ugb2YgYWxsb3dpbmcgY29kZSBleGVjdXRpb25cclxuICBpZiAoY3VzdG9tTG9naWNPcHRpb25zLmFsbG93Q29kZUV4ZWN1dGlvbikge1xyXG4gICAgLy8gUHJvY2VzcyB0aGUgYHJlc291cmNlc2Agb3B0aW9uXHJcbiAgICB0cnkge1xyXG4gICAgICAvLyBUcnkgdG8gaGFuZGxlIHJlc291cmNlc1xyXG4gICAgICBjdXN0b21Mb2dpY09wdGlvbnMucmVzb3VyY2VzID0gX2hhbmRsZVJlc291cmNlcyhcclxuICAgICAgICBjdXN0b21Mb2dpY09wdGlvbnMucmVzb3VyY2VzLFxyXG4gICAgICAgIGN1c3RvbUxvZ2ljT3B0aW9ucy5hbGxvd0ZpbGVSZXNvdXJjZXMsXHJcbiAgICAgICAgdHJ1ZVxyXG4gICAgICApO1xyXG5cclxuICAgICAgLy8gVmFsaWRhdGUgb3B0aW9uXHJcbiAgICAgIGN1c3RvbUxvZ2ljT3B0aW9ucy5yZXNvdXJjZXMgPSB2YWxpZGF0ZU9wdGlvbihcclxuICAgICAgICAncmVzb3VyY2VzJyxcclxuICAgICAgICBjdXN0b21Mb2dpY09wdGlvbnMucmVzb3VyY2VzXHJcbiAgICAgICk7XHJcbiAgICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgICBsb2coMiwgJ1tjaGFydF0gVGhlIGByZXNvdXJjZXNgIGNhbm5vdCBiZSBsb2FkZWQuJyk7XHJcblxyXG4gICAgICAvLyBJbiBjYXNlIG9mIGFuIGVycm9yLCBzZXQgdGhlIG9wdGlvbiB3aXRoIG51bGxcclxuICAgICAgY3VzdG9tTG9naWNPcHRpb25zLnJlc291cmNlcyA9IG51bGw7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gUHJvY2VzcyB0aGUgYGN1c3RvbUNvZGVgIG9wdGlvblxyXG4gICAgdHJ5IHtcclxuICAgICAgLy8gVHJ5IHRvIGxvYWQgY3VzdG9tIGNvZGUgYW5kIHdyYXAgYXJvdW5kIGl0IGluIGEgc2VsZiBpbnZva2luZyBmdW5jdGlvblxyXG4gICAgICBjdXN0b21Mb2dpY09wdGlvbnMuY3VzdG9tQ29kZSA9IF9oYW5kbGVDdXN0b21Db2RlKFxyXG4gICAgICAgIGN1c3RvbUxvZ2ljT3B0aW9ucy5jdXN0b21Db2RlLFxyXG4gICAgICAgIGN1c3RvbUxvZ2ljT3B0aW9ucy5hbGxvd0ZpbGVSZXNvdXJjZXNcclxuICAgICAgKTtcclxuXHJcbiAgICAgIC8vIFZhbGlkYXRlIHRoZSBvcHRpb25cclxuICAgICAgY3VzdG9tTG9naWNPcHRpb25zLmN1c3RvbUNvZGUgPSB2YWxpZGF0ZU9wdGlvbihcclxuICAgICAgICAnY3VzdG9tQ29kZScsXHJcbiAgICAgICAgY3VzdG9tTG9naWNPcHRpb25zLmN1c3RvbUNvZGVcclxuICAgICAgKTtcclxuICAgIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICAgIGxvZ1dpdGhTdGFjaygyLCBlcnJvciwgJ1tjaGFydF0gVGhlIGBjdXN0b21Db2RlYCBjYW5ub3QgYmUgbG9hZGVkLicpO1xyXG5cclxuICAgICAgLy8gSW4gY2FzZSBvZiBhbiBlcnJvciwgc2V0IHRoZSBvcHRpb24gd2l0aCBudWxsXHJcbiAgICAgIGN1c3RvbUxvZ2ljT3B0aW9ucy5jdXN0b21Db2RlID0gbnVsbDtcclxuICAgIH1cclxuXHJcbiAgICAvLyBQcm9jZXNzIHRoZSBgY2FsbGJhY2tgIG9wdGlvblxyXG4gICAgdHJ5IHtcclxuICAgICAgLy8gVHJ5IHRvIGxvYWQgY2FsbGJhY2sgZnVuY3Rpb25cclxuICAgICAgY3VzdG9tTG9naWNPcHRpb25zLmNhbGxiYWNrID0gX2hhbmRsZUN1c3RvbUNvZGUoXHJcbiAgICAgICAgY3VzdG9tTG9naWNPcHRpb25zLmNhbGxiYWNrLFxyXG4gICAgICAgIGN1c3RvbUxvZ2ljT3B0aW9ucy5hbGxvd0ZpbGVSZXNvdXJjZXMsXHJcbiAgICAgICAgdHJ1ZVxyXG4gICAgICApO1xyXG5cclxuICAgICAgLy8gVmFsaWRhdGUgdGhlIG9wdGlvblxyXG4gICAgICBjdXN0b21Mb2dpY09wdGlvbnMuY2FsbGJhY2sgPSB2YWxpZGF0ZU9wdGlvbihcclxuICAgICAgICAnY2FsbGJhY2snLFxyXG4gICAgICAgIGN1c3RvbUxvZ2ljT3B0aW9ucy5jYWxsYmFja1xyXG4gICAgICApO1xyXG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICAgbG9nV2l0aFN0YWNrKDIsIGVycm9yLCAnW2NoYXJ0XSBUaGUgYGNhbGxiYWNrYCBjYW5ub3QgYmUgbG9hZGVkLicpO1xyXG5cclxuICAgICAgLy8gSW4gY2FzZSBvZiBhbiBlcnJvciwgc2V0IHRoZSBvcHRpb24gd2l0aCBudWxsXHJcbiAgICAgIGN1c3RvbUxvZ2ljT3B0aW9ucy5jYWxsYmFjayA9IG51bGw7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gQ2hlY2sgaWYgdGhlcmUgaXMgdGhlIGBjdXN0b21Db2RlYCBwcmVzZW50XHJcbiAgICBpZiAoW251bGwsIHVuZGVmaW5lZF0uaW5jbHVkZXMoY3VzdG9tTG9naWNPcHRpb25zLmN1c3RvbUNvZGUpKSB7XHJcbiAgICAgIGxvZygzLCAnW2NoYXJ0XSBObyB2YWx1ZSBmb3IgdGhlIGBjdXN0b21Db2RlYCBvcHRpb24gZm91bmQuJyk7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gQ2hlY2sgaWYgdGhlcmUgaXMgdGhlIGBjYWxsYmFja2AgcHJlc2VudFxyXG4gICAgaWYgKFtudWxsLCB1bmRlZmluZWRdLmluY2x1ZGVzKGN1c3RvbUxvZ2ljT3B0aW9ucy5jYWxsYmFjaykpIHtcclxuICAgICAgbG9nKDMsICdbY2hhcnRdIE5vIHZhbHVlIGZvciB0aGUgYGNhbGxiYWNrYCBvcHRpb24gZm91bmQuJyk7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gQ2hlY2sgaWYgdGhlcmUgaXMgdGhlIGByZXNvdXJjZXNgIHByZXNlbnRcclxuICAgIGlmIChbbnVsbCwgdW5kZWZpbmVkXS5pbmNsdWRlcyhjdXN0b21Mb2dpY09wdGlvbnMucmVzb3VyY2VzKSkge1xyXG4gICAgICBsb2coMywgJ1tjaGFydF0gTm8gdmFsdWUgZm9yIHRoZSBgcmVzb3VyY2VzYCBvcHRpb24gZm91bmQuJyk7XHJcbiAgICB9XHJcbiAgfSBlbHNlIHtcclxuICAgIC8vIElmIHRoZSBgYWxsb3dDb2RlRXhlY3V0aW9uYCBmbGFnIGlzIHNldCB0byBmYWxzZSwgd2Ugc2hvdWxkIHJlZnVzZVxyXG4gICAgLy8gdGhlIHVzYWdlIG9mIHRoZSBgY2FsbGJhY2tgLCBgcmVzb3VyY2VzYCwgYW5kIGBjdXN0b21Db2RlYCBvcHRpb25zLlxyXG4gICAgLy8gQWRkaXRpb25hbGx5LCB0aGUgd29ya2VyIHdpbGwgcmVmdXNlIHRvIHJ1biBhcmJpdHJhcnkgSmF2YVNjcmlwdC5cclxuICAgIGlmIChcclxuICAgICAgY3VzdG9tTG9naWNPcHRpb25zLmNhbGxiYWNrIHx8XHJcbiAgICAgIGN1c3RvbUxvZ2ljT3B0aW9ucy5yZXNvdXJjZXMgfHxcclxuICAgICAgY3VzdG9tTG9naWNPcHRpb25zLmN1c3RvbUNvZGVcclxuICAgICkge1xyXG4gICAgICAvLyBSZXNldCBhbGwgY3VzdG9tIGNvZGUgb3B0aW9uc1xyXG4gICAgICBjdXN0b21Mb2dpY09wdGlvbnMuY2FsbGJhY2sgPSBudWxsO1xyXG4gICAgICBjdXN0b21Mb2dpY09wdGlvbnMucmVzb3VyY2VzID0gbnVsbDtcclxuICAgICAgY3VzdG9tTG9naWNPcHRpb25zLmN1c3RvbUNvZGUgPSBudWxsO1xyXG5cclxuICAgICAgLy8gU2VuZCBhIG1lc3NhZ2Ugc2F5aW5nIHRoYXQgdGhlIGV4cG9ydGVyIGRvZXMgbm90IHN1cHBvcnQgdGhlc2Ugc2V0dGluZ3NcclxuICAgICAgdGhyb3cgbmV3IEV4cG9ydEVycm9yKFxyXG4gICAgICAgIGBbY2hhcnRdIFRoZSAnY2FsbGJhY2snLCAncmVzb3VyY2VzJywgYW5kICdjdXN0b21Db2RlJyBvcHRpb25zIGhhdmUgYmVlbiBkaXNhYmxlZCBmb3IgdGhpcyBzZXJ2ZXIuYCxcclxuICAgICAgICA0MDNcclxuICAgICAgKTtcclxuICAgIH1cclxuICB9XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBIYW5kbGVzIGFuZCB2YWxpZGF0ZXMgcmVzb3VyY2VzIGZyb20gdGhlIGByZXNvdXJjZXNgIG9wdGlvbiBmb3IgZXhwb3J0LlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gX2hhbmRsZVJlc291cmNlc1xyXG4gKlxyXG4gKiBAcGFyYW0geyhPYmplY3R8c3RyaW5nfG51bGwpfSBbcmVzb3VyY2VzPW51bGxdIC0gVGhlIHJlc291cmNlcyB0byBiZSBoYW5kbGVkLlxyXG4gKiBDYW4gYmUgZWl0aGVyIGEgSlNPTiBvYmplY3QsIHN0cmluZ2lmaWVkIEpTT04sIGEgcGF0aCB0byBhIEpTT04gZmlsZSxcclxuICogb3IgbnVsbC4gVGhlIGRlZmF1bHQgdmFsdWUgaXMgYG51bGxgLlxyXG4gKiBAcGFyYW0ge2Jvb2xlYW59IGFsbG93RmlsZVJlc291cmNlcyAtIEEgZmxhZyBpbmRpY2F0aW5nIHdoZXRoZXIgbG9hZGluZ1xyXG4gKiByZXNvdXJjZXMgZnJvbSBmaWxlcyBpcyBhbGxvd2VkLlxyXG4gKiBAcGFyYW0ge2Jvb2xlYW59IGFsbG93Q29kZUV4ZWN1dGlvbiAtIEEgZmxhZyBpbmRpY2F0aW5nIHdoZXRoZXIgY29kZVxyXG4gKiBleGVjdXRpb24gaXMgYWxsb3dlZC5cclxuICpcclxuICogQHJldHVybnMgeyhPYmplY3R8bnVsbCl9IFRoZSBoYW5kbGVkIHJlc291cmNlcyBvciBudWxsIGlmIG5vIHZhbGlkIHJlc291cmNlc1xyXG4gKiBhcmUgZm91bmQuXHJcbiAqL1xyXG5mdW5jdGlvbiBfaGFuZGxlUmVzb3VyY2VzKFxyXG4gIHJlc291cmNlcyA9IG51bGwsXHJcbiAgYWxsb3dGaWxlUmVzb3VyY2VzLFxyXG4gIGFsbG93Q29kZUV4ZWN1dGlvblxyXG4pIHtcclxuICBsZXQgaGFuZGxlZFJlc291cmNlcyA9IHJlc291cmNlcztcclxuXHJcbiAgLy8gSWYgbm8gcmVzb3VyY2VzIGZvdW5kLCB0cnkgdG8gbG9hZCB0aGUgZGVmYXVsdCByZXNvdXJjZXNcclxuICBpZiAoIWhhbmRsZWRSZXNvdXJjZXMpIHtcclxuICAgIHJlc291cmNlcyA9ICdyZXNvdXJjZXMuanNvbic7XHJcbiAgfVxyXG5cclxuICAvLyBMaXN0IG9mIGFsbG93ZWQgc2VjdGlvbnMgaW4gdGhlIHJlc291cmNlcyBKU09OXHJcbiAgY29uc3QgYWxsb3dlZFByb3BzID0gWydqcycsICdjc3MnLCAnZmlsZXMnXTtcclxuXHJcbiAgLy8gQSBmbGFnIHRoYXQgZGVjaWRlcyBiYXNlZCB0byByZXR1cm4gcmVzb3VyY2VzIG9yIGBudWxsYFxyXG4gIGxldCBjb3JyZWN0UmVzb3VyY2VzID0gZmFsc2U7XHJcblxyXG4gIC8vIFRyeSB0byBsb2FkIHJlc291cmNlcyBmcm9tIGEgZmlsZVxyXG4gIGlmIChcclxuICAgIGFsbG93RmlsZVJlc291cmNlcyAmJlxyXG4gICAgdHlwZW9mIHJlc291cmNlcyA9PT0gJ3N0cmluZycgJiZcclxuICAgIHJlc291cmNlcy5lbmRzV2l0aCgnLmpzb24nKVxyXG4gICkge1xyXG4gICAgaGFuZGxlZFJlc291cmNlcyA9IGlzQWxsb3dlZENvbmZpZyhcclxuICAgICAgcmVhZEZpbGVTeW5jKGdldEFic29sdXRlUGF0aChyZXNvdXJjZXMpLCAndXRmOCcpLFxyXG4gICAgICBmYWxzZSxcclxuICAgICAgYWxsb3dDb2RlRXhlY3V0aW9uXHJcbiAgICApO1xyXG4gIH0gZWxzZSB7XHJcbiAgICAvLyBUcnkgdG8gZ2V0IEpTT05cclxuICAgIGhhbmRsZWRSZXNvdXJjZXMgPSBpc0FsbG93ZWRDb25maWcocmVzb3VyY2VzLCBmYWxzZSwgYWxsb3dDb2RlRXhlY3V0aW9uKTtcclxuXHJcbiAgICAvLyBHZXQgcmlkIG9mIHRoZSBmaWxlcyBzZWN0aW9uXHJcbiAgICBpZiAoaGFuZGxlZFJlc291cmNlcyAmJiAhYWxsb3dGaWxlUmVzb3VyY2VzKSB7XHJcbiAgICAgIGRlbGV0ZSBoYW5kbGVkUmVzb3VyY2VzLmZpbGVzO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgLy8gRmlsdGVyIGZyb20gdW5uZWNlc3NhcnkgcHJvcGVydGllc1xyXG4gIGZvciAoY29uc3QgcHJvcE5hbWUgaW4gaGFuZGxlZFJlc291cmNlcykge1xyXG4gICAgaWYgKCFhbGxvd2VkUHJvcHMuaW5jbHVkZXMocHJvcE5hbWUpKSB7XHJcbiAgICAgIGRlbGV0ZSBoYW5kbGVkUmVzb3VyY2VzW3Byb3BOYW1lXTtcclxuICAgIH0gZWxzZSBpZiAoIWNvcnJlY3RSZXNvdXJjZXMpIHtcclxuICAgICAgY29ycmVjdFJlc291cmNlcyA9IHRydWU7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICAvLyBDaGVjayBpZiBhdCBsZWFzdCBvbmUgb2YgYWxsb3dlZCBwcm9wZXJ0aWVzIGlzIHByZXNlbnRcclxuICBpZiAoIWNvcnJlY3RSZXNvdXJjZXMpIHtcclxuICAgIHJldHVybiBudWxsO1xyXG4gIH1cclxuXHJcbiAgLy8gSGFuZGxlIGZpbGVzIHNlY3Rpb25cclxuICBpZiAoaGFuZGxlZFJlc291cmNlcy5maWxlcykge1xyXG4gICAgaGFuZGxlZFJlc291cmNlcy5maWxlcyA9IGhhbmRsZWRSZXNvdXJjZXMuZmlsZXMubWFwKChpdGVtKSA9PiBpdGVtLnRyaW0oKSk7XHJcbiAgICBpZiAoIWhhbmRsZWRSZXNvdXJjZXMuZmlsZXMgfHwgaGFuZGxlZFJlc291cmNlcy5maWxlcy5sZW5ndGggPD0gMCkge1xyXG4gICAgICBkZWxldGUgaGFuZGxlZFJlc291cmNlcy5maWxlcztcclxuICAgIH1cclxuICB9XHJcblxyXG4gIC8vIFJldHVybiByZXNvdXJjZXNcclxuICByZXR1cm4gaGFuZGxlZFJlc291cmNlcztcclxufVxyXG5cclxuLyoqXHJcbiAqIEhhbmRsZXMgY3VzdG9tIGNvZGUgdG8gZXhlY3V0ZSBpdCBzYWZlbHkuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBfaGFuZGxlQ3VzdG9tQ29kZVxyXG4gKlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gY3VzdG9tQ29kZSAtIFRoZSBjdXN0b20gY29kZSB0byBiZSB3cmFwcGVkLlxyXG4gKiBAcGFyYW0ge2Jvb2xlYW59IGFsbG93RmlsZVJlc291cmNlcyAtIEZsYWcgdG8gYWxsb3cgbG9hZGluZyBjb2RlIGZyb20gYSBmaWxlLlxyXG4gKiBAcGFyYW0ge2Jvb2xlYW59IFtpc0NhbGxiYWNrPWZhbHNlXSAtIEZsYWcgdGhhdCBpbmRpY2F0ZXMgdGhlIHJldHVybmVkIGNvZGVcclxuICogbXVzdCBiZSBpbiBhIGNhbGxiYWNrIGZvcm1hdC5cclxuICpcclxuICogQHJldHVybnMgeyhzdHJpbmd8bnVsbCl9IFRoZSB3cmFwcGVkIGN1c3RvbSBjb2RlIG9yIG51bGwgaWYgd3JhcHBpbmcgZmFpbHMuXHJcbiAqL1xyXG5mdW5jdGlvbiBfaGFuZGxlQ3VzdG9tQ29kZShjdXN0b21Db2RlLCBhbGxvd0ZpbGVSZXNvdXJjZXMsIGlzQ2FsbGJhY2sgPSBmYWxzZSkge1xyXG4gIGlmIChjdXN0b21Db2RlICYmIHR5cGVvZiBjdXN0b21Db2RlID09PSAnc3RyaW5nJykge1xyXG4gICAgY3VzdG9tQ29kZSA9IGN1c3RvbUNvZGUudHJpbSgpO1xyXG5cclxuICAgIGlmIChjdXN0b21Db2RlLmVuZHNXaXRoKCcuanMnKSkge1xyXG4gICAgICAvLyBMb2FkIGEgZmlsZSBpZiB0aGUgZmlsZSByZXNvdXJjZXMgYXJlIGFsbG93ZWRcclxuICAgICAgcmV0dXJuIGFsbG93RmlsZVJlc291cmNlc1xyXG4gICAgICAgID8gX2hhbmRsZUN1c3RvbUNvZGUoXHJcbiAgICAgICAgICAgIHJlYWRGaWxlU3luYyhnZXRBYnNvbHV0ZVBhdGgoY3VzdG9tQ29kZSksICd1dGY4JyksXHJcbiAgICAgICAgICAgIGFsbG93RmlsZVJlc291cmNlcyxcclxuICAgICAgICAgICAgaXNDYWxsYmFja1xyXG4gICAgICAgICAgKVxyXG4gICAgICAgIDogbnVsbDtcclxuICAgIH0gZWxzZSBpZiAoXHJcbiAgICAgICFpc0NhbGxiYWNrICYmXHJcbiAgICAgIChjdXN0b21Db2RlLnN0YXJ0c1dpdGgoJ2Z1bmN0aW9uKCknKSB8fFxyXG4gICAgICAgIGN1c3RvbUNvZGUuc3RhcnRzV2l0aCgnZnVuY3Rpb24gKCknKSB8fFxyXG4gICAgICAgIGN1c3RvbUNvZGUuc3RhcnRzV2l0aCgnKCk9PicpIHx8XHJcbiAgICAgICAgY3VzdG9tQ29kZS5zdGFydHNXaXRoKCcoKSA9PicpKVxyXG4gICAgKSB7XHJcbiAgICAgIC8vIFRyZWF0IGEgZnVuY3Rpb24gYXMgYSBzZWxmLWludm9raW5nIGV4cHJlc3Npb25cclxuICAgICAgcmV0dXJuIGAoJHtjdXN0b21Db2RlfSkoKWA7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gT3IgcmV0dXJuIGFzIGEgc3RyaW5naWZpZWQgY29kZVxyXG4gICAgcmV0dXJuIGN1c3RvbUNvZGUucmVwbGFjZSgvOyQvLCAnJyk7XHJcbiAgfVxyXG59XHJcblxyXG4vKipcclxuICogSGFuZGxlcyB0aGUgbG9hZGluZyBhbmQgdmFsaWRhdGlvbiBvZiB0aGUgYGdsb2JhbE9wdGlvbnNgIGFuZCBgdGhlbWVPcHRpb25zYFxyXG4gKiBpbiB0aGUgZXhwb3J0IG9wdGlvbnMuIElmIHRoZSBvcHRpb24gaXMgYSBzdHJpbmcgYW5kIHJlZmVyZW5jZXMgYSBKU09OIGZpbGVcclxuICogKHdoZW4gdGhlIGBhbGxvd0ZpbGVSZXNvdXJjZXNgIGlzIGB0cnVlYCksIGl0IHJlYWRzIGFuZCBwYXJzZXMgdGhlIGZpbGUuXHJcbiAqIE90aGVyd2lzZSwgaXQgYXR0ZW1wdHMgdG8gcGFyc2UgdGhlIHN0cmluZyBvciBvYmplY3QgYXMgSlNPTi4gSWYgYW55IGVycm9yc1xyXG4gKiBvY2N1ciBkdXJpbmcgdGhpcyBwcm9jZXNzLCB0aGUgb3B0aW9uIGlzIHNldCB0byBgbnVsbGAuIElmIHRoZXJlIGlzIGFuIGVycm9yXHJcbiAqIGxvYWRpbmcgb3IgcGFyc2luZyB0aGUgYGdsb2JhbE9wdGlvbnNgIG9yIGB0aGVtZU9wdGlvbnNgLCB0aGUgZXJyb3IgaXMgbG9nZ2VkXHJcbiAqIGFuZCB0aGUgb3B0aW9uIGlzIHNldCB0byBgbnVsbGAuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBfaGFuZGxlR2xvYmFsQW5kVGhlbWVcclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IGV4cG9ydE9wdGlvbnMgLSBUaGUgY29uZmlndXJhdGlvbiBvYmplY3QgY29udGFpbmluZyBgZXhwb3J0YFxyXG4gKiBvcHRpb25zLlxyXG4gKiBAcGFyYW0ge09iamVjdH0gY3VzdG9tTG9naWNPcHRpb25zIC0gVGhlIGNvbmZpZ3VyYXRpb24gb2JqZWN0IGNvbnRhaW5pbmdcclxuICogYGN1c3RvbUxvZ2ljYCBvcHRpb25zLlxyXG4gKi9cclxuZnVuY3Rpb24gX2hhbmRsZUdsb2JhbEFuZFRoZW1lKGV4cG9ydE9wdGlvbnMsIGN1c3RvbUxvZ2ljT3B0aW9ucykge1xyXG4gIC8vIEdldCB0aGUgYGFsbG93RmlsZVJlc291cmNlc2AgYW5kIGBhbGxvd0NvZGVFeGVjdXRpb25gIGZsYWdzXHJcbiAgY29uc3QgeyBhbGxvd0ZpbGVSZXNvdXJjZXMsIGFsbG93Q29kZUV4ZWN1dGlvbiB9ID0gY3VzdG9tTG9naWNPcHRpb25zO1xyXG5cclxuICAvLyBDaGVjayB0aGUgYGdsb2JhbE9wdGlvbnNgIGFuZCBgdGhlbWVPcHRpb25zYCBvcHRpb25zXHJcbiAgWydnbG9iYWxPcHRpb25zJywgJ3RoZW1lT3B0aW9ucyddLmZvckVhY2goKG9wdGlvbnNOYW1lKSA9PiB7XHJcbiAgICB0cnkge1xyXG4gICAgICAvLyBDaGVjayBpZiB0aGUgb3B0aW9uIGV4aXN0c1xyXG4gICAgICBpZiAoZXhwb3J0T3B0aW9uc1tvcHRpb25zTmFtZV0pIHtcclxuICAgICAgICAvLyBDaGVjayBpZiBpdCBpcyBhIHN0cmluZyBhbmQgYSBmaWxlIG5hbWUgd2l0aCB0aGUgYC5qc29uYCBleHRlbnNpb25cclxuICAgICAgICBpZiAoXHJcbiAgICAgICAgICBhbGxvd0ZpbGVSZXNvdXJjZXMgJiZcclxuICAgICAgICAgIHR5cGVvZiBleHBvcnRPcHRpb25zW29wdGlvbnNOYW1lXSA9PT0gJ3N0cmluZycgJiZcclxuICAgICAgICAgIGV4cG9ydE9wdGlvbnNbb3B0aW9uc05hbWVdLmVuZHNXaXRoKCcuanNvbicpXHJcbiAgICAgICAgKSB7XHJcbiAgICAgICAgICAvLyBDaGVjayBpZiB0aGUgZmlsZSBjb250ZW50IGNhbiBiZSBhIGNvbmZpZywgYW5kIHNhdmUgaXQgYXMgYSBzdHJpbmdcclxuICAgICAgICAgIGV4cG9ydE9wdGlvbnNbb3B0aW9uc05hbWVdID0gaXNBbGxvd2VkQ29uZmlnKFxyXG4gICAgICAgICAgICByZWFkRmlsZVN5bmMoZ2V0QWJzb2x1dGVQYXRoKGV4cG9ydE9wdGlvbnNbb3B0aW9uc05hbWVdKSwgJ3V0ZjgnKSxcclxuICAgICAgICAgICAgdHJ1ZSxcclxuICAgICAgICAgICAgYWxsb3dDb2RlRXhlY3V0aW9uXHJcbiAgICAgICAgICApO1xyXG4gICAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgICAvLyBDaGVjayBpZiB0aGUgdmFsdWUgY2FuIGJlIGEgY29uZmlnLCBhbmQgc2F2ZSBpdCBhcyBhIHN0cmluZ1xyXG4gICAgICAgICAgZXhwb3J0T3B0aW9uc1tvcHRpb25zTmFtZV0gPSBpc0FsbG93ZWRDb25maWcoXHJcbiAgICAgICAgICAgIGV4cG9ydE9wdGlvbnNbb3B0aW9uc05hbWVdLFxyXG4gICAgICAgICAgICB0cnVlLFxyXG4gICAgICAgICAgICBhbGxvd0NvZGVFeGVjdXRpb25cclxuICAgICAgICAgICk7XHJcbiAgICAgICAgfVxyXG5cclxuICAgICAgICAvLyBWYWxpZGF0ZSB0aGUgb3B0aW9uXHJcbiAgICAgICAgZXhwb3J0T3B0aW9uc1tvcHRpb25zTmFtZV0gPSB2YWxpZGF0ZU9wdGlvbihcclxuICAgICAgICAgIG9wdGlvbnNOYW1lLFxyXG4gICAgICAgICAgZXhwb3J0T3B0aW9uc1tvcHRpb25zTmFtZV1cclxuICAgICAgICApO1xyXG4gICAgICB9XHJcbiAgICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgICBsb2dXaXRoU3RhY2soXHJcbiAgICAgICAgMixcclxuICAgICAgICBlcnJvcixcclxuICAgICAgICBgW2NoYXJ0XSBUaGUgXFxgJHtvcHRpb25zTmFtZX1cXGAgY2Fubm90IGJlIGxvYWRlZC5gXHJcbiAgICAgICk7XHJcblxyXG4gICAgICAvLyBJbiBjYXNlIG9mIGFuIGVycm9yLCBzZXQgdGhlIG9wdGlvbiB3aXRoIG51bGxcclxuICAgICAgZXhwb3J0T3B0aW9uc1tvcHRpb25zTmFtZV0gPSBudWxsO1xyXG4gICAgfVxyXG4gIH0pO1xyXG5cclxuICAvLyBDaGVjayBpZiB0aGVyZSBpcyB0aGUgYGdsb2JhbE9wdGlvbnNgIHByZXNlbnRcclxuICBpZiAoW251bGwsIHVuZGVmaW5lZF0uaW5jbHVkZXMoZXhwb3J0T3B0aW9ucy5nbG9iYWxPcHRpb25zKSkge1xyXG4gICAgbG9nKDMsICdbY2hhcnRdIE5vIHZhbHVlIGZvciB0aGUgYGdsb2JhbE9wdGlvbnNgIG9wdGlvbiBmb3VuZC4nKTtcclxuICB9XHJcblxyXG4gIC8vIENoZWNrIGlmIHRoZXJlIGlzIHRoZSBgdGhlbWVPcHRpb25zYCBwcmVzZW50XHJcbiAgaWYgKFtudWxsLCB1bmRlZmluZWRdLmluY2x1ZGVzKGV4cG9ydE9wdGlvbnMudGhlbWVPcHRpb25zKSkge1xyXG4gICAgbG9nKDMsICdbY2hhcnRdIE5vIHZhbHVlIGZvciB0aGUgYHRoZW1lT3B0aW9uc2Agb3B0aW9uIGZvdW5kLicpO1xyXG4gIH1cclxufVxyXG5cclxuLyoqXHJcbiAqIFZhbGlkYXRlcyB0aGUgc2l6ZSBvZiB0aGUgZGF0YSBmb3IgdGhlIGV4cG9ydCBwcm9jZXNzIGFnYWluc3QgYSBmaXhlZCBsaW1pdFxyXG4gKiBvZiAxMDBNQi5cclxuICpcclxuICogQGZ1bmN0aW9uIF9jaGVja0RhdGFTaXplXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBpbWFnZU9wdGlvbnMgLSBUaGUgZGF0YSBvYmplY3QsIHdoaWNoIGluY2x1ZGVzIG9wdGlvbnMgZnJvbVxyXG4gKiB0aGUgYGV4cG9ydGAgYW5kIGBjdXN0b21Mb2dpY2Agc2VjdGlvbnMgYW5kIHdpbGwgYmUgc2VudCB0byBhIFB1cHBldGVlciBwYWdlLlxyXG4gKlxyXG4gKiBAdGhyb3dzIHtFeHBvcnRFcnJvcn0gVGhyb3dzIGFuIGBFeHBvcnRFcnJvcmAgaWYgdGhlIHNpemUgb2YgdGhlIGRhdGEgZm9yXHJcbiAqIHRoZSBleHBvcnQgcHJvY2VzcyBvYmplY3QgZXhjZWVkcyB0aGUgMTAwTUIgbGltaXQuXHJcbiAqL1xyXG5mdW5jdGlvbiBfY2hlY2tEYXRhU2l6ZShpbWFnZU9wdGlvbnMpIHtcclxuICAvLyBTZXQgdGhlIGZpeGVkIGRhdGEgbGltaXQgKDEwME1CKSBmb3IgdGhlIGRldi10b29scyBwcm90b2NvbFxyXG4gIGNvbnN0IGRhdGFMaW1pdCA9IDEwMCAqIDEwMjQgKiAxMDI0O1xyXG5cclxuICAvLyBHZXQgdGhlIHNpemUgb2YgdGhlIGRhdGFcclxuICBjb25zdCB0b3RhbFNpemUgPSBCdWZmZXIuYnl0ZUxlbmd0aChKU09OLnN0cmluZ2lmeShpbWFnZU9wdGlvbnMpLCAndXRmLTgnKTtcclxuXHJcbiAgLy8gTG9nIHRoZSBzaXplIGluIE1CXHJcbiAgbG9nKFxyXG4gICAgMyxcclxuICAgIGBbY2hhcnRdIFRoZSBjdXJyZW50IHRvdGFsIHNpemUgb2YgdGhlIGRhdGEgZm9yIHRoZSBleHBvcnQgcHJvY2VzcyBpcyBhcm91bmQgJHsoXHJcbiAgICAgIHRvdGFsU2l6ZSAvXHJcbiAgICAgICgxMDI0ICogMTAyNClcclxuICAgICkudG9GaXhlZCgyKX1NQi5gXHJcbiAgKTtcclxuXHJcbiAgLy8gQ2hlY2sgdGhlIHNpemUgb2YgZGF0YSBiZWZvcmUgcGFzc2luZyB0byBhIHBhZ2VcclxuICBpZiAodG90YWxTaXplID49IGRhdGFMaW1pdCkge1xyXG4gICAgdGhyb3cgbmV3IEV4cG9ydEVycm9yKFxyXG4gICAgICBgW2NoYXJ0XSBUaGUgZGF0YSBmb3IgdGhlIGV4cG9ydCBwcm9jZXNzIGV4Y2VlZHMgMTAwTUIgbGltaXQuYFxyXG4gICAgKTtcclxuICB9XHJcbn1cclxuXHJcbmV4cG9ydCBkZWZhdWx0IHtcclxuICBzaW5nbGVFeHBvcnQsXHJcbiAgYmF0Y2hFeHBvcnQsXHJcbiAgc3RhcnRFeHBvcnQsXHJcbiAgZ2V0QWxsb3dDb2RlRXhlY3V0aW9uLFxyXG4gIHNldEFsbG93Q29kZUV4ZWN1dGlvblxyXG59O1xyXG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxyXG5cclxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXHJcblxyXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNSwgSGlnaHNvZnRcclxuXHJcbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cclxuXHJcbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxyXG5cclxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxyXG5cclxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cclxuXHJcbi8qKlxyXG4gKiBAb3ZlcnZpZXcgVGhpcyBtb2R1bGUgcHJvdmlkZXMgdXRpbGl0eSBmdW5jdGlvbnMgZm9yIG1hbmFnaW5nIGludGVydmFsc1xyXG4gKiBhbmQgdGltZW91dHMgaW4gYSBjZW50cmFsaXplZCBtYW5uZXIuIEl0IG1haW50YWlucyBhIHJlZ2lzdHJ5IG9mIGFsbCBhY3RpdmVcclxuICogdGltZXJzIGFuZCBhbGxvd3MgZm9yIHRoZWlyIGVmZmljaWVudCBjbGVhbnVwIHdoZW4gbmVlZGVkIHRvIGF2b2lkIHBvdGVudGlhbFxyXG4gKiBtZW1vcnkgbGVha3MsIHVuaW50ZW5kZWQgYmVoYXZpb3Igb3IgYSBwcm9jZXNzIGZyb20gYmVpbmcgc3RvcHBlZC5cclxuICovXHJcblxyXG5pbXBvcnQgeyBsb2cgfSBmcm9tICcuL2xvZ2dlci5qcyc7XHJcblxyXG4vLyBBcnJheSB0aGF0IGNvbnRhaW5zIGlkcyBvZiBhbGwgb25nb2luZyBpbnRlcnZhbHMgYW5kIHRpbWVvdXRzXHJcbmNvbnN0IHRpbWVySWRzID0gW107XHJcblxyXG4vKipcclxuICogQWRkcyBpZCBvZiB0aGUgYHNldEludGVydmFsYCBvciBgc2V0VGltZW91dGAgYW5kIHRvIHRoZSBgdGltZXJJZHNgIGFycmF5LlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gYWRkVGltZXJcclxuICpcclxuICogQHBhcmFtIHtOb2RlSlMuVGltZW91dH0gaWQgLSBJZCBvZiBhbiBpbnRlcnZhbCBvciBhIHRpbWVvdXQuXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gYWRkVGltZXIoaWQpIHtcclxuICB0aW1lcklkcy5wdXNoKGlkKTtcclxufVxyXG5cclxuLyoqXHJcbiAqIENsZWFycyBhbGwgb2Ygb25nb2luZyBpbnRlcnZhbHMgYW5kIHRpbWVvdXRzIGJ5IGlkcyBnYXRoZXJlZFxyXG4gKiBpbiB0aGUgYHRpbWVySWRzYCBhcnJheS5cclxuICpcclxuICogQGZ1bmN0aW9uIGNsZWFyQWxsVGltZXJzXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gY2xlYXJBbGxUaW1lcnMoKSB7XHJcbiAgbG9nKDQsIGBbdGltZXJdIENsZWFyaW5nIGFsbCByZWdpc3RlcmVkIGludGVydmFscyBhbmQgdGltZW91dHMuYCk7XHJcbiAgZm9yIChjb25zdCBpZCBvZiB0aW1lcklkcykge1xyXG4gICAgY2xlYXJJbnRlcnZhbChpZCk7XHJcbiAgICBjbGVhclRpbWVvdXQoaWQpO1xyXG4gIH1cclxufVxyXG5cclxuZXhwb3J0IGRlZmF1bHQge1xyXG4gIGFkZFRpbWVyLFxyXG4gIGNsZWFyQWxsVGltZXJzXHJcbn07XHJcbiIsIi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXHJcblxyXG5IaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXJcclxuXHJcbkNvcHlyaWdodCAoYykgMjAxNi0yMDI1LCBIaWdoc29mdFxyXG5cclxuTGljZW5jZWQgdW5kZXIgdGhlIE1JVCBsaWNlbmNlLlxyXG5cclxuQWRkaXRpb25hbGx5IGEgdmFsaWQgSGlnaGNoYXJ0cyBsaWNlbnNlIGlzIHJlcXVpcmVkIGZvciB1c2UuXHJcblxyXG5TZWUgTElDRU5TRSBmaWxlIGluIHJvb3QgZm9yIGRldGFpbHMuXHJcblxyXG4qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xyXG5cclxuLyoqXHJcbiAqIEBvdmVydmlldyBQcm92aWRlcyBtaWRkbGV3YXJlIGZ1bmN0aW9ucyBmb3IgbG9nZ2luZyBlcnJvcnMgd2l0aCBzdGFjayB0cmFjZXNcclxuICogYW5kIGhhbmRsaW5nIGVycm9yIHJlc3BvbnNlcyBpbiBhbiBFeHByZXNzIGFwcGxpY2F0aW9uLlxyXG4gKi9cclxuXHJcbmltcG9ydCB7IGdldE9wdGlvbnMgfSBmcm9tICcuLi8uLi9jb25maWcuanMnO1xyXG5pbXBvcnQgeyBsb2dXaXRoU3RhY2sgfSBmcm9tICcuLi8uLi9sb2dnZXIuanMnO1xyXG5cclxuLyoqXHJcbiAqIE1pZGRsZXdhcmUgZm9yIGxvZ2dpbmcgZXJyb3JzIHdpdGggc3RhY2sgdHJhY2UgYW5kIGhhbmRsaW5nIGVycm9yIHJlc3BvbnNlLlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gbG9nRXJyb3JNaWRkbGV3YXJlXHJcbiAqXHJcbiAqIEBwYXJhbSB7RXJyb3J9IGVycm9yIC0gVGhlIGVycm9yIG9iamVjdC5cclxuICogQHBhcmFtIHtFeHByZXNzLlJlcXVlc3R9IHJlcXVlc3QgLSBUaGUgRXhwcmVzcyByZXF1ZXN0IG9iamVjdC5cclxuICogQHBhcmFtIHtFeHByZXNzLlJlc3BvbnNlfSByZXNwb25zZSAtIFRoZSBFeHByZXNzIHJlc3BvbnNlIG9iamVjdC5cclxuICogQHBhcmFtIHtGdW5jdGlvbn0gbmV4dCAtIFRoZSBuZXh0IG1pZGRsZXdhcmUgZnVuY3Rpb24uXHJcbiAqXHJcbiAqIEByZXR1cm5zIHt1bmRlZmluZWR9IFRoZSBjYWxsIHRvIHRoZSBuZXh0IG1pZGRsZXdhcmUgZnVuY3Rpb24gd2l0aFxyXG4gKiB0aGUgcGFzc2VkIGVycm9yLlxyXG4gKi9cclxuZnVuY3Rpb24gbG9nRXJyb3JNaWRkbGV3YXJlKGVycm9yLCByZXF1ZXN0LCByZXNwb25zZSwgbmV4dCkge1xyXG4gIC8vIERpc3BsYXkgdGhlIGVycm9yIHdpdGggc3RhY2sgaW4gYSBjb3JyZWN0IGZvcm1hdFxyXG4gIGxvZ1dpdGhTdGFjaygxLCBlcnJvcik7XHJcblxyXG4gIC8vIERlbGV0ZSB0aGUgc3RhY2sgZm9yIHRoZSBlbnZpcm9ubWVudCBvdGhlciB0aGFuIHRoZSBkZXZlbG9wbWVudFxyXG4gIGlmIChnZXRPcHRpb25zKCkub3RoZXIubm9kZUVudiAhPT0gJ2RldmVsb3BtZW50Jykge1xyXG4gICAgZGVsZXRlIGVycm9yLnN0YWNrO1xyXG4gIH1cclxuXHJcbiAgLy8gQ2FsbCB0aGUgYHJldHVybkVycm9yTWlkZGxld2FyZWAgbWlkZGxld2FyZVxyXG4gIHJldHVybiBuZXh0KGVycm9yKTtcclxufVxyXG5cclxuLyoqXHJcbiAqIE1pZGRsZXdhcmUgZm9yIHJldHVybmluZyBlcnJvciByZXNwb25zZS5cclxuICpcclxuICogQGZ1bmN0aW9uIHJldHVybkVycm9yTWlkZGxld2FyZVxyXG4gKlxyXG4gKiBAcGFyYW0ge0Vycm9yfSBlcnJvciAtIFRoZSBlcnJvciBvYmplY3QuXHJcbiAqIEBwYXJhbSB7RXhwcmVzcy5SZXF1ZXN0fSByZXF1ZXN0IC0gVGhlIEV4cHJlc3MgcmVxdWVzdCBvYmplY3QuXHJcbiAqIEBwYXJhbSB7RXhwcmVzcy5SZXNwb25zZX0gcmVzcG9uc2UgLSBUaGUgRXhwcmVzcyByZXNwb25zZSBvYmplY3QuXHJcbiAqIEBwYXJhbSB7RnVuY3Rpb259IG5leHQgLSBUaGUgbmV4dCBtaWRkbGV3YXJlIGZ1bmN0aW9uLlxyXG4gKi9cclxuZnVuY3Rpb24gcmV0dXJuRXJyb3JNaWRkbGV3YXJlKGVycm9yLCByZXF1ZXN0LCByZXNwb25zZSwgbmV4dCkge1xyXG4gIC8vIEdhdGhlciBhbGwgcmVxdWllZCBpbmZvcm1hdGlvbiBmb3IgdGhlIHJlc3BvbnNlXHJcbiAgY29uc3QgeyBtZXNzYWdlLCBzdGFjayB9ID0gZXJyb3I7XHJcblxyXG4gIC8vIFVzZSB0aGUgZXJyb3IncyBzdGF0dXMgY29kZSBvciB0aGUgZGVmYXVsdCA0MDBcclxuICBjb25zdCBzdGF0dXNDb2RlID0gZXJyb3Iuc3RhdHVzQ29kZSB8fCA0MDA7XHJcblxyXG4gIC8vIFNldCBhbmQgcmV0dXJuIHJlc3BvbnNlXHJcbiAgcmVzcG9uc2Uuc3RhdHVzKHN0YXR1c0NvZGUpLmpzb24oeyBzdGF0dXNDb2RlLCBtZXNzYWdlLCBzdGFjayB9KTtcclxufVxyXG5cclxuLyoqXHJcbiAqIEFkZHMgdGhlIGVycm9yIG1pZGRsZXdhcmVzIHRvIHRoZSBwYXNzZWQgZXhwcmVzcyBhcHAgaW5zdGFuY2UuXHJcbiAqXHJcbiAqIEBwYXJhbSB7RXhwcmVzc30gYXBwIC0gVGhlIEV4cHJlc3MgYXBwIGluc3RhbmNlLlxyXG4gKi9cclxuZXhwb3J0IGRlZmF1bHQgZnVuY3Rpb24gZXJyb3JNaWRkbGV3YXJlKGFwcCkge1xyXG4gIC8vIEFkZCBsb2cgZXJyb3IgbWlkZGxld2FyZVxyXG4gIGFwcC51c2UobG9nRXJyb3JNaWRkbGV3YXJlKTtcclxuXHJcbiAgLy8gQWRkIHNldCBzdGF0dXMgYW5kIHJldHVybiBlcnJvciBtaWRkbGV3YXJlXHJcbiAgYXBwLnVzZShyZXR1cm5FcnJvck1pZGRsZXdhcmUpO1xyXG59XHJcbiIsIi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXHJcblxyXG5IaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXJcclxuXHJcbkNvcHlyaWdodCAoYykgMjAxNi0yMDI1LCBIaWdoc29mdFxyXG5cclxuTGljZW5jZWQgdW5kZXIgdGhlIE1JVCBsaWNlbmNlLlxyXG5cclxuQWRkaXRpb25hbGx5IGEgdmFsaWQgSGlnaGNoYXJ0cyBsaWNlbnNlIGlzIHJlcXVpcmVkIGZvciB1c2UuXHJcblxyXG5TZWUgTElDRU5TRSBmaWxlIGluIHJvb3QgZm9yIGRldGFpbHMuXHJcblxyXG4qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xyXG5cclxuLyoqXHJcbiAqIEBvdmVydmlldyBQcm92aWRlcyBtaWRkbGV3YXJlIGZ1bmN0aW9ucyBmb3IgY29uZmlndXJpbmcgYW5kIGVuYWJsaW5nIHJhdGVcclxuICogbGltaXRpbmcgaW4gYW4gRXhwcmVzcyBhcHBsaWNhdGlvbi5cclxuICovXHJcblxyXG5pbXBvcnQgcmF0ZUxpbWl0IGZyb20gJ2V4cHJlc3MtcmF0ZS1saW1pdCc7XHJcblxyXG5pbXBvcnQgeyBsb2cgfSBmcm9tICcuLi8uLi9sb2dnZXIuanMnO1xyXG5cclxuaW1wb3J0IEV4cG9ydEVycm9yIGZyb20gJy4uLy4uL2Vycm9ycy9FeHBvcnRFcnJvci5qcyc7XHJcblxyXG4vKipcclxuICogTWlkZGxld2FyZSBmb3IgZW5hYmxpbmcgcmF0ZSBsaW1pdGluZyBvbiB0aGUgc3BlY2lmaWVkIEV4cHJlc3MgYXBwLlxyXG4gKlxyXG4gKiBAcGFyYW0ge0V4cHJlc3N9IGFwcCAtIFRoZSBFeHByZXNzIGFwcCBpbnN0YW5jZS5cclxuICogQHBhcmFtIHtPYmplY3R9IHJhdGVMaW1pdGluZ09wdGlvbnMgLSBUaGUgY29uZmlndXJhdGlvbiBvYmplY3QgY29udGFpbmluZ1xyXG4gKiBgcmF0ZUxpbWl0aW5nYCBvcHRpb25zLlxyXG4gKlxyXG4gKiBAdGhyb3dzIHtFeHBvcnRFcnJvcn0gVGhyb3dzIGFuIGBFeHBvcnRFcnJvcmAgaWYgY291bGQgbm90IGNvbmZpZ3VyZSBhbmQgc2V0XHJcbiAqIHRoZSByYXRlIGxpbWl0aW5nIG9wdGlvbnMuXHJcbiAqL1xyXG5leHBvcnQgZGVmYXVsdCBmdW5jdGlvbiByYXRlTGltaXRpbmdNaWRkbGV3YXJlKGFwcCwgcmF0ZUxpbWl0aW5nT3B0aW9ucykge1xyXG4gIHRyeSB7XHJcbiAgICAvLyBDaGVjayBpZiB0aGUgcmF0ZSBsaW1pdGluZyBpcyBlbmFibGVkIGFuZCB0aGUgYXBwIGV4aXN0c1xyXG4gICAgaWYgKGFwcCAmJiByYXRlTGltaXRpbmdPcHRpb25zLmVuYWJsZSkge1xyXG4gICAgICBjb25zdCBtZXNzYWdlID1cclxuICAgICAgICAnVG9vIG1hbnkgcmVxdWVzdHMsIHlvdSBoYXZlIGJlZW4gcmF0ZSBsaW1pdGVkLiBQbGVhc2UgdHJ5IGFnYWluIGxhdGVyLic7XHJcblxyXG4gICAgICAvLyBPcHRpb25zIGZvciB0aGUgcmF0ZSBsaW1pdGVyXHJcbiAgICAgIGNvbnN0IHJhdGVPcHRpb25zID0ge1xyXG4gICAgICAgIHdpbmRvdzogcmF0ZUxpbWl0aW5nT3B0aW9ucy53aW5kb3cgfHwgMSxcclxuICAgICAgICBtYXhSZXF1ZXN0czogcmF0ZUxpbWl0aW5nT3B0aW9ucy5tYXhSZXF1ZXN0cyB8fCAzMCxcclxuICAgICAgICBkZWxheTogcmF0ZUxpbWl0aW5nT3B0aW9ucy5kZWxheSB8fCAwLFxyXG4gICAgICAgIHRydXN0UHJveHk6IHJhdGVMaW1pdGluZ09wdGlvbnMudHJ1c3RQcm94eSB8fCBmYWxzZSxcclxuICAgICAgICBza2lwS2V5OiByYXRlTGltaXRpbmdPcHRpb25zLnNraXBLZXkgfHwgbnVsbCxcclxuICAgICAgICBza2lwVG9rZW46IHJhdGVMaW1pdGluZ09wdGlvbnMuc2tpcFRva2VuIHx8IG51bGxcclxuICAgICAgfTtcclxuXHJcbiAgICAgIC8vIFNldCBpZiBiZWhpbmQgYSBwcm94eVxyXG4gICAgICBpZiAocmF0ZU9wdGlvbnMudHJ1c3RQcm94eSkge1xyXG4gICAgICAgIGFwcC5lbmFibGUoJ3RydXN0IHByb3h5Jyk7XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIC8vIENyZWF0ZSBhIGxpbWl0ZXJcclxuICAgICAgY29uc3QgbGltaXRlciA9IHJhdGVMaW1pdCh7XHJcbiAgICAgICAgLy8gVGltZSBmcmFtZSBmb3Igd2hpY2ggcmVxdWVzdHMgYXJlIGNoZWNrZWQgYW5kIHJlbWVtYmVyZWRcclxuICAgICAgICB3aW5kb3dNczogcmF0ZU9wdGlvbnMud2luZG93ICogNjAgKiAxMDAwLFxyXG4gICAgICAgIC8vIExpbWl0IGVhY2ggSVAgdG8gMTAwIHJlcXVlc3RzIHBlciBgd2luZG93TXNgXHJcbiAgICAgICAgbGltaXQ6IHJhdGVPcHRpb25zLm1heFJlcXVlc3RzLFxyXG4gICAgICAgIC8vIERpc2FibGUgZGVsYXlpbmcsIGZ1bGwgc3BlZWQgdW50aWwgdGhlIG1heCBsaW1pdCBpcyByZWFjaGVkXHJcbiAgICAgICAgZGVsYXlNczogcmF0ZU9wdGlvbnMuZGVsYXksXHJcbiAgICAgICAgaGFuZGxlcjogKHJlcXVlc3QsIHJlc3BvbnNlKSA9PiB7XHJcbiAgICAgICAgICByZXNwb25zZS5mb3JtYXQoe1xyXG4gICAgICAgICAgICBqc29uOiAoKSA9PiB7XHJcbiAgICAgICAgICAgICAgcmVzcG9uc2Uuc3RhdHVzKDQyOSkuc2VuZCh7IG1lc3NhZ2UgfSk7XHJcbiAgICAgICAgICAgIH0sXHJcbiAgICAgICAgICAgIGRlZmF1bHQ6ICgpID0+IHtcclxuICAgICAgICAgICAgICByZXNwb25zZS5zdGF0dXMoNDI5KS5zZW5kKG1lc3NhZ2UpO1xyXG4gICAgICAgICAgICB9XHJcbiAgICAgICAgICB9KTtcclxuICAgICAgICB9LFxyXG4gICAgICAgIHNraXA6IChyZXF1ZXN0KSA9PiB7XHJcbiAgICAgICAgICAvLyBBbGxvdyBieXBhc3NpbmcgdGhlIGxpbWl0ZXIgaWYgYSB2YWxpZCBrZXkvdG9rZW4gaGFzIGJlZW4gc2VudFxyXG4gICAgICAgICAgaWYgKFxyXG4gICAgICAgICAgICByYXRlT3B0aW9ucy5za2lwS2V5ICE9PSBudWxsICYmXHJcbiAgICAgICAgICAgIHJhdGVPcHRpb25zLnNraXBUb2tlbiAhPT0gbnVsbCAmJlxyXG4gICAgICAgICAgICByZXF1ZXN0LnF1ZXJ5LmtleSA9PT0gcmF0ZU9wdGlvbnMuc2tpcEtleSAmJlxyXG4gICAgICAgICAgICByZXF1ZXN0LnF1ZXJ5LmFjY2Vzc190b2tlbiA9PT0gcmF0ZU9wdGlvbnMuc2tpcFRva2VuXHJcbiAgICAgICAgICApIHtcclxuICAgICAgICAgICAgbG9nKDQsICdbcmF0ZSBsaW1pdGluZ10gU2tpcHBpbmcgcmF0ZSBsaW1pdGVyLicpO1xyXG4gICAgICAgICAgICByZXR1cm4gdHJ1ZTtcclxuICAgICAgICAgIH1cclxuICAgICAgICAgIHJldHVybiBmYWxzZTtcclxuICAgICAgICB9XHJcbiAgICAgIH0pO1xyXG5cclxuICAgICAgLy8gVXNlIGEgbGltaXRlciBhcyBhIG1pZGRsZXdhcmVcclxuICAgICAgYXBwLnVzZShsaW1pdGVyKTtcclxuXHJcbiAgICAgIGxvZyhcclxuICAgICAgICAzLFxyXG4gICAgICAgIGBbcmF0ZSBsaW1pdGluZ10gRW5hYmxlZCByYXRlIGxpbWl0aW5nIHdpdGggJHtyYXRlT3B0aW9ucy5tYXhSZXF1ZXN0c30gcmVxdWVzdHMgcGVyICR7cmF0ZU9wdGlvbnMud2luZG93fSBtaW51dGUgZm9yIGVhY2ggSVAsIHRydXN0aW5nIHByb3h5OiAke3JhdGVPcHRpb25zLnRydXN0UHJveHl9LmBcclxuICAgICAgKTtcclxuICAgIH1cclxuICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgdGhyb3cgbmV3IEV4cG9ydEVycm9yKFxyXG4gICAgICAnW3JhdGUgbGltaXRpbmddIENvdWxkIG5vdCBjb25maWd1cmUgYW5kIHNldCB0aGUgcmF0ZSBsaW1pdGluZyBvcHRpb25zLicsXHJcbiAgICAgIDUwMFxyXG4gICAgKS5zZXRFcnJvcihlcnJvcik7XHJcbiAgfVxyXG59XHJcbiIsIi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXHJcblxyXG5IaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXJcclxuXHJcbkNvcHlyaWdodCAoYykgMjAxNi0yMDI1LCBIaWdoc29mdFxyXG5cclxuTGljZW5jZWQgdW5kZXIgdGhlIE1JVCBsaWNlbmNlLlxyXG5cclxuQWRkaXRpb25hbGx5IGEgdmFsaWQgSGlnaGNoYXJ0cyBsaWNlbnNlIGlzIHJlcXVpcmVkIGZvciB1c2UuXHJcblxyXG5TZWUgTElDRU5TRSBmaWxlIGluIHJvb3QgZm9yIGRldGFpbHMuXHJcblxyXG4qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xyXG5cclxuLyoqXHJcbiAqIEBvdmVydmlldyBQcm92aWRlcyBtaWRkbGV3YXJlIGZ1bmN0aW9ucyBmb3IgdmFsaWRhdGluZyBpbmNvbWluZyBIVFRQIHJlcXVlc3RzXHJcbiAqIGluIGFuIEV4cHJlc3MgYXBwbGljYXRpb24uIFRoaXMgbW9kdWxlIGVuc3VyZXMgdGhhdCByZXF1ZXN0cyBjb250YWluXHJcbiAqIGFwcHJvcHJpYXRlIGNvbnRlbnQgdHlwZXMgYW5kIHZhbGlkIHJlcXVlc3QgYm9kaWVzLCBpbmNsdWRpbmcgcHJvcGVyIEpTT05cclxuICogc3RydWN0dXJlcyBhbmQgY2hhcnQgZGF0YSBmb3IgZXhwb3J0cy4gSXQgY2hlY2tzIGZvciBwb3RlbnRpYWwgaXNzdWVzIHN1Y2hcclxuICogYXMgbWlzc2luZyBvciBtYWxmb3JtZWQgZGF0YSwgcHJpdmF0ZSByYW5nZSBVUkxzIGluIFNWRyBwYXlsb2FkcywgYW5kIGFsbG93c1xyXG4gKiBmb3IgZmxleGlibGUgb3B0aW9ucyB2YWxpZGF0aW9uLiBUaGUgbWlkZGxld2FyZSBsb2dzIGRldGFpbGVkIGluZm9ybWF0aW9uXHJcbiAqIGFuZCBoYW5kbGVzIGVycm9ycyByZWxhdGVkIHRvIGluY29ycmVjdCBwYXlsb2FkcywgY2hhcnQgZGF0YSwgYW5kIHByaXZhdGUgVVJMXHJcbiAqIHVzYWdlLlxyXG4gKi9cclxuXHJcbmltcG9ydCB7IHY0IGFzIHV1aWQgfSBmcm9tICd1dWlkJztcclxuXHJcbmltcG9ydCB7IGdldEFsbG93Q29kZUV4ZWN1dGlvbiB9IGZyb20gJy4uLy4uL2NoYXJ0LmpzJztcclxuaW1wb3J0IHsgaXNBbGxvd2VkQ29uZmlnIH0gZnJvbSAnLi4vLi4vY29uZmlnLmpzJztcclxuaW1wb3J0IHsgbG9nIH0gZnJvbSAnLi4vLi4vbG9nZ2VyLmpzJztcclxuaW1wb3J0IHsgaXNPYmplY3RFbXB0eSwgaXNQcml2YXRlUmFuZ2VVcmxGb3VuZCB9IGZyb20gJy4uLy4uL3V0aWxzLmpzJztcclxuXHJcbmltcG9ydCBFeHBvcnRFcnJvciBmcm9tICcuLi8uLi9lcnJvcnMvRXhwb3J0RXJyb3IuanMnO1xyXG5cclxuLyoqXHJcbiAqIE1pZGRsZXdhcmUgZm9yIHZhbGlkYXRpbmcgdGhlIGNvbnRlbnQtdHlwZSBoZWFkZXIuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBjb250ZW50VHlwZU1pZGRsZXdhcmVcclxuICpcclxuICogQHBhcmFtIHtFeHByZXNzLlJlcXVlc3R9IHJlcXVlc3QgLSBUaGUgRXhwcmVzcyByZXF1ZXN0IG9iamVjdC5cclxuICogQHBhcmFtIHtFeHByZXNzLlJlc3BvbnNlfSByZXNwb25zZSAtIFRoZSBFeHByZXNzIHJlc3BvbnNlIG9iamVjdC5cclxuICogQHBhcmFtIHtGdW5jdGlvbn0gbmV4dCAtIFRoZSBuZXh0IG1pZGRsZXdhcmUgZnVuY3Rpb24uXHJcbiAqXHJcbiAqIEByZXR1cm5zIHt1bmRlZmluZWR9IFRoZSBjYWxsIHRvIHRoZSBuZXh0IG1pZGRsZXdhcmUgZnVuY3Rpb24uXHJcbiAqXHJcbiAqIEB0aHJvd3Mge0V4cG9ydEVycm9yfSBUaHJvd3MgYW4gYEV4cG9ydEVycm9yYCBpZiB0aGUgY29udGVudC10eXBlXHJcbiAqIGlzIG5vdCBjb3JyZWN0LlxyXG4gKi9cclxuZnVuY3Rpb24gY29udGVudFR5cGVNaWRkbGV3YXJlKHJlcXVlc3QsIHJlc3BvbnNlLCBuZXh0KSB7XHJcbiAgdHJ5IHtcclxuICAgIC8vIEdldCB0aGUgY29udGVudCB0eXBlIGhlYWRlclxyXG4gICAgY29uc3QgY29udGVudFR5cGUgPSByZXF1ZXN0LmhlYWRlcnNbJ2NvbnRlbnQtdHlwZSddIHx8ICcnO1xyXG5cclxuICAgIC8vIEFsbG93IG9ubHkgSlNPTiwgVVJMLWVuY29kZWQgYW5kIGZvcm0gZGF0YSB3aXRob3V0IGZpbGVzIHR5cGVzIG9mIGRhdGFcclxuICAgIGlmIChcclxuICAgICAgIWNvbnRlbnRUeXBlLmluY2x1ZGVzKCdhcHBsaWNhdGlvbi9qc29uJykgJiZcclxuICAgICAgIWNvbnRlbnRUeXBlLmluY2x1ZGVzKCdhcHBsaWNhdGlvbi94LXd3dy1mb3JtLXVybGVuY29kZWQnKSAmJlxyXG4gICAgICAhY29udGVudFR5cGUuaW5jbHVkZXMoJ211bHRpcGFydC9mb3JtLWRhdGEnKVxyXG4gICAgKSB7XHJcbiAgICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcihcclxuICAgICAgICAnW3ZhbGlkYXRpb25dIENvbnRlbnQtVHlwZSBtdXN0IGJlIGFwcGxpY2F0aW9uL2pzb24sIGFwcGxpY2F0aW9uL3gtd3d3LWZvcm0tdXJsZW5jb2RlZCwgb3IgbXVsdGlwYXJ0L2Zvcm0tZGF0YS4nLFxyXG4gICAgICAgIDQxNVxyXG4gICAgICApO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIENhbGwgdGhlIGByZXF1ZXN0Qm9keU1pZGRsZXdhcmVgIG1pZGRsZXdhcmVcclxuICAgIHJldHVybiBuZXh0KCk7XHJcbiAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgIHJldHVybiBuZXh0KGVycm9yKTtcclxuICB9XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBNaWRkbGV3YXJlIGZvciB2YWxpZGF0aW5nIHRoZSByZXF1ZXN0J3MgYm9keS5cclxuICpcclxuICogQGZ1bmN0aW9uIHJlcXVlc3RCb2R5TWlkZGxld2FyZVxyXG4gKlxyXG4gKiBAcGFyYW0ge0V4cHJlc3MuUmVxdWVzdH0gcmVxdWVzdCAtIFRoZSBFeHByZXNzIHJlcXVlc3Qgb2JqZWN0LlxyXG4gKiBAcGFyYW0ge0V4cHJlc3MuUmVzcG9uc2V9IHJlc3BvbnNlIC0gVGhlIEV4cHJlc3MgcmVzcG9uc2Ugb2JqZWN0LlxyXG4gKiBAcGFyYW0ge0Z1bmN0aW9ufSBuZXh0IC0gVGhlIG5leHQgbWlkZGxld2FyZSBmdW5jdGlvbi5cclxuICpcclxuICogQHJldHVybnMge3VuZGVmaW5lZH0gVGhlIGNhbGwgdG8gdGhlIG5leHQgbWlkZGxld2FyZSBmdW5jdGlvbi5cclxuICpcclxuICogQHRocm93cyB7RXhwb3J0RXJyb3J9IFRocm93cyBhbiBgRXhwb3J0RXJyb3JgIGlmIHRoZSBib2R5IGlzIG5vdCBjb3JyZWN0LlxyXG4gKiBAdGhyb3dzIHtFeHBvcnRFcnJvcn0gVGhyb3dzIGFuIGBFeHBvcnRFcnJvcmAgaWYgdGhlIGNoYXJ0IGRhdGEgZnJvbSB0aGUgYm9keVxyXG4gKiBpcyBub3QgY29ycmVjdC5cclxuICogQHRocm93cyB7RXhwb3J0RXJyb3J9IFRocm93cyBhbiBgRXhwb3J0RXJyb3JgIGluIGNhc2Ugb2YgdGhlIHByaXZhdGUgcmFuZ2VcclxuICogdXJsIGVycm9yLlxyXG4gKi9cclxuZnVuY3Rpb24gcmVxdWVzdEJvZHlNaWRkbGV3YXJlKHJlcXVlc3QsIHJlc3BvbnNlLCBuZXh0KSB7XHJcbiAgdHJ5IHtcclxuICAgIC8vIEdldCB0aGUgcmVxdWVzdCBib2R5XHJcbiAgICBjb25zdCBib2R5ID0gcmVxdWVzdC5ib2R5O1xyXG5cclxuICAgIC8vIENyZWF0ZSBhIHVuaXF1ZSBJRCBmb3IgYSByZXF1ZXN0XHJcbiAgICBjb25zdCByZXF1ZXN0SWQgPSB1dWlkKCk7XHJcblxyXG4gICAgLy8gVGhyb3cgYW4gZXJyb3IgaWYgdGhlcmUgaXMgbm8gY29ycmVjdCBib2R5XHJcbiAgICBpZiAoIWJvZHkgfHwgaXNPYmplY3RFbXB0eShib2R5KSkge1xyXG4gICAgICBsb2coXHJcbiAgICAgICAgMixcclxuICAgICAgICBgW3ZhbGlkYXRpb25dIFJlcXVlc3QgWyR7cmVxdWVzdElkfV0gLSBUaGUgcmVxdWVzdCBmcm9tICR7XHJcbiAgICAgICAgICByZXF1ZXN0LmhlYWRlcnNbJ3gtZm9yd2FyZGVkLWZvciddIHx8IHJlcXVlc3QuY29ubmVjdGlvbi5yZW1vdGVBZGRyZXNzXHJcbiAgICAgICAgfSB3YXMgaW5jb3JyZWN0LiBSZWNlaXZlZCBwYXlsb2FkIGlzIGVtcHR5LmBcclxuICAgICAgKTtcclxuXHJcbiAgICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcihcclxuICAgICAgICBgW3ZhbGlkYXRpb25dIFJlcXVlc3QgWyR7cmVxdWVzdElkfV0gLSBUaGUgcmVxdWVzdCBib2R5IGlzIHJlcXVpcmVkLiBQbGVhc2UgZW5zdXJlIHRoYXQgeW91ciBDb250ZW50LVR5cGUgaGVhZGVyIGlzIGNvcnJlY3QuIEFjY2VwdGVkIHR5cGVzIGFyZSAnYXBwbGljYXRpb24vanNvbicgYW5kICdtdWx0aXBhcnQvZm9ybS1kYXRhJy5gLFxyXG4gICAgICAgIDQwMFxyXG4gICAgICApO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIEdldCB0aGUgYGFsbG93Q29kZUV4ZWN1dGlvbmAgb3B0aW9uIGZvciB0aGUgc2VydmVyXHJcbiAgICBjb25zdCBhbGxvd0NvZGVFeGVjdXRpb24gPSBnZXRBbGxvd0NvZGVFeGVjdXRpb24oKTtcclxuXHJcbiAgICAvLyBGaW5kIGEgY29ycmVjdCBjaGFydCBvcHRpb25zXHJcbiAgICBjb25zdCBpbnN0ciA9IGlzQWxsb3dlZENvbmZpZyhcclxuICAgICAgLy8gVXNlIG9uZSBvZiB0aGUgYmVsb3dcclxuICAgICAgYm9keS5pbnN0ciB8fCBib2R5Lm9wdGlvbnMgfHwgYm9keS5pbmZpbGUgfHwgYm9keS5kYXRhLFxyXG4gICAgICAvLyBTdHJpbmdpZnkgb3B0aW9uc1xyXG4gICAgICB0cnVlLFxyXG4gICAgICAvLyBBbGxvdyBvciBkaXNhbGxvdyBmdW5jdGlvbnNcclxuICAgICAgYWxsb3dDb2RlRXhlY3V0aW9uXHJcbiAgICApO1xyXG5cclxuICAgIC8vIFRocm93IGFuIGVycm9yIGlmIHRoZXJlIGlzIG5vIGNvcnJlY3QgY2hhcnQgZGF0YVxyXG4gICAgaWYgKGluc3RyID09PSBudWxsICYmICFib2R5LnN2Zykge1xyXG4gICAgICBsb2coXHJcbiAgICAgICAgMixcclxuICAgICAgICBgW3ZhbGlkYXRpb25dIFJlcXVlc3QgWyR7cmVxdWVzdElkfV0gLSBUaGUgcmVxdWVzdCBmcm9tICR7XHJcbiAgICAgICAgICByZXF1ZXN0LmhlYWRlcnNbJ3gtZm9yd2FyZGVkLWZvciddIHx8IHJlcXVlc3QuY29ubmVjdGlvbi5yZW1vdGVBZGRyZXNzXHJcbiAgICAgICAgfSB3YXMgaW5jb3JyZWN0LiBSZWNlaXZlZCBwYXlsb2FkIGlzIG1pc3NpbmcgY29ycmVjdCBjaGFydCBkYXRhIGZvciBleHBvcnQ6ICR7SlNPTi5zdHJpbmdpZnkoYm9keSl9LmBcclxuICAgICAgKTtcclxuXHJcbiAgICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcihcclxuICAgICAgICBgW3ZhbGlkYXRpb25dIFJlcXVlc3QgWyR7cmVxdWVzdElkfV0gLSBObyBjb3JyZWN0IGNoYXJ0IGRhdGEgZm91bmQuIEVuc3VyZSB0aGF0IHlvdSBhcmUgdXNpbmcgZWl0aGVyIGFwcGxpY2F0aW9uL2pzb24gb3IgbXVsdGlwYXJ0L2Zvcm0tZGF0YSBoZWFkZXJzLiBJZiBzZW5kaW5nIEpTT04sIG1ha2Ugc3VyZSB0aGUgY2hhcnQgZGF0YSBpcyBpbiB0aGUgJ2luZmlsZScsICdvcHRpb25zJywgb3IgJ2RhdGEnIGF0dHJpYnV0ZS4gSWYgc2VuZGluZyBTVkcsIGVuc3VyZSBpdCBpcyBpbiB0aGUgJ3N2ZycgYXR0cmlidXRlLmAsXHJcbiAgICAgICAgNDAwXHJcbiAgICAgICk7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gVGhyb3cgYW4gZXJyb3IgaWYgdGVzdCBvZiB4bGluazpocmVmIGVsZW1lbnRzIGZyb20gcGF5bG9hZCdzIFNWRyBmYWlsc1xyXG4gICAgaWYgKGJvZHkuc3ZnICYmIGlzUHJpdmF0ZVJhbmdlVXJsRm91bmQoYm9keS5zdmcpKSB7XHJcbiAgICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcihcclxuICAgICAgICBgW3ZhbGlkYXRpb25dIFJlcXVlc3QgWyR7cmVxdWVzdElkfV0gLSBTVkcgcG90ZW50aWFsbHkgY29udGFpbiBhdCBsZWFzdCBvbmUgZm9yYmlkZGVuIFVSTCBpbiAneGxpbms6aHJlZicgZWxlbWVudC4gUGxlYXNlIHJldmlldyB0aGUgU1ZHIGNvbnRlbnQgYW5kIGVuc3VyZSB0aGF0IGFsbCByZWZlcmVuY2VkIFVSTHMgY29tcGx5IHdpdGggc2VjdXJpdHkgcG9saWNpZXMuYCxcclxuICAgICAgICA0MDBcclxuICAgICAgKTtcclxuICAgIH1cclxuXHJcbiAgICAvLyBHZXQgYW5kIHByZS12YWxpZGF0ZSB0aGUgb3B0aW9ucyBhbmQgc3RvcmUgdGhlbSBpbiB0aGUgcmVxdWVzdFxyXG4gICAgcmVxdWVzdC52YWxpZGF0ZWRPcHRpb25zID0ge1xyXG4gICAgICAvLyBTZXQgdGhlIGNyZWF0ZWQgSUQgYXMgYSBgcmVxdWVzdElkYCBwcm9wZXJ0eSBpbiB0aGUgb3B0aW9uc1xyXG4gICAgICByZXF1ZXN0SWQsXHJcbiAgICAgIGV4cG9ydDoge1xyXG4gICAgICAgIGluc3RyLFxyXG4gICAgICAgIHN2ZzogYm9keS5zdmcsXHJcbiAgICAgICAgb3V0ZmlsZTpcclxuICAgICAgICAgIGJvZHkub3V0ZmlsZSB8fFxyXG4gICAgICAgICAgYCR7cmVxdWVzdC5wYXJhbXMuZmlsZW5hbWUgfHwgJ2NoYXJ0J30uJHtib2R5LnR5cGUgfHwgJ3BuZyd9YCxcclxuICAgICAgICB0eXBlOiBib2R5LnR5cGUsXHJcbiAgICAgICAgY29uc3RyOiBib2R5LmNvbnN0cixcclxuICAgICAgICBiNjQ6IGJvZHkuYjY0LFxyXG4gICAgICAgIG5vRG93bmxvYWQ6IGJvZHkubm9Eb3dubG9hZCxcclxuICAgICAgICBoZWlnaHQ6IGJvZHkuaGVpZ2h0LFxyXG4gICAgICAgIHdpZHRoOiBib2R5LndpZHRoLFxyXG4gICAgICAgIHNjYWxlOiBib2R5LnNjYWxlLFxyXG4gICAgICAgIGdsb2JhbE9wdGlvbnM6IGlzQWxsb3dlZENvbmZpZyhcclxuICAgICAgICAgIGJvZHkuZ2xvYmFsT3B0aW9ucyxcclxuICAgICAgICAgIHRydWUsXHJcbiAgICAgICAgICBhbGxvd0NvZGVFeGVjdXRpb25cclxuICAgICAgICApLFxyXG4gICAgICAgIHRoZW1lT3B0aW9uczogaXNBbGxvd2VkQ29uZmlnKFxyXG4gICAgICAgICAgYm9keS50aGVtZU9wdGlvbnMsXHJcbiAgICAgICAgICB0cnVlLFxyXG4gICAgICAgICAgYWxsb3dDb2RlRXhlY3V0aW9uXHJcbiAgICAgICAgKVxyXG4gICAgICB9LFxyXG4gICAgICBjdXN0b21Mb2dpYzoge1xyXG4gICAgICAgIGFsbG93Q29kZUV4ZWN1dGlvbixcclxuICAgICAgICBhbGxvd0ZpbGVSZXNvdXJjZXM6IGZhbHNlLFxyXG4gICAgICAgIGN1c3RvbUNvZGU6IGJvZHkuY3VzdG9tQ29kZSxcclxuICAgICAgICBjYWxsYmFjazogYm9keS5jYWxsYmFjayxcclxuICAgICAgICByZXNvdXJjZXM6IGlzQWxsb3dlZENvbmZpZyhib2R5LnJlc291cmNlcywgdHJ1ZSwgYWxsb3dDb2RlRXhlY3V0aW9uKVxyXG4gICAgICB9XHJcbiAgICB9O1xyXG5cclxuICAgIC8vIENhbGwgdGhlIG5leHQgbWlkZGxld2FyZVxyXG4gICAgcmV0dXJuIG5leHQoKTtcclxuICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgcmV0dXJuIG5leHQoZXJyb3IpO1xyXG4gIH1cclxufVxyXG5cclxuLyoqXHJcbiAqIEFkZHMgdGhlIHZhbGlkYXRpb24gbWlkZGxld2FyZXMgdG8gdGhlIHBhc3NlZCBleHByZXNzIGFwcCBpbnN0YW5jZS5cclxuICpcclxuICogQHBhcmFtIHtFeHByZXNzfSBhcHAgLSBUaGUgRXhwcmVzcyBhcHAgaW5zdGFuY2UuXHJcbiAqL1xyXG5leHBvcnQgZGVmYXVsdCBmdW5jdGlvbiB2YWxpZGF0aW9uTWlkZGxld2FyZShhcHApIHtcclxuICAvLyBBZGQgY29udGVudCB0eXBlIHZhbGlkYXRpb24gbWlkZGxld2FyZVxyXG4gIGFwcC5wb3N0KFsnLycsICcvOmZpbGVuYW1lJ10sIGNvbnRlbnRUeXBlTWlkZGxld2FyZSk7XHJcblxyXG4gIC8vIEFkZCByZXF1ZXN0IGJvZHkgcmVxdWVzdCB2YWxpZGF0aW9uIG1pZGRsZXdhcmVcclxuICBhcHAucG9zdChbJy8nLCAnLzpmaWxlbmFtZSddLCByZXF1ZXN0Qm9keU1pZGRsZXdhcmUpO1xyXG59XHJcbiIsIi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXHJcblxyXG5IaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXJcclxuXHJcbkNvcHlyaWdodCAoYykgMjAxNi0yMDI1LCBIaWdoc29mdFxyXG5cclxuTGljZW5jZWQgdW5kZXIgdGhlIE1JVCBsaWNlbmNlLlxyXG5cclxuQWRkaXRpb25hbGx5IGEgdmFsaWQgSGlnaGNoYXJ0cyBsaWNlbnNlIGlzIHJlcXVpcmVkIGZvciB1c2UuXHJcblxyXG5TZWUgTElDRU5TRSBmaWxlIGluIHJvb3QgZm9yIGRldGFpbHMuXHJcblxyXG4qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xyXG5cclxuLyoqXHJcbiAqIEBvdmVydmlldyBEZWZpbmVzIHRoZSBleHBvcnQgcm91dGVzIGFuZCBsb2dpYyBmb3IgaGFuZGxpbmcgY2hhcnQgZXhwb3J0XHJcbiAqIHJlcXVlc3RzIGluIGFuIEV4cHJlc3Mgc2VydmVyLiBUaGlzIG1vZHVsZSBwcm9jZXNzZXMgaW5jb21pbmcgcmVxdWVzdHNcclxuICogdG8gZXhwb3J0IGNoYXJ0cyBpbiB2YXJpb3VzIGZvcm1hdHMgKGUuZy4gSlBFRywgUE5HLCBQREYsIFNWRykuIEl0IGludGVncmF0ZXNcclxuICogd2l0aCBIaWdoY2hhcnRzJyBjb3JlIGZ1bmN0aW9uYWxpdGllcyBhbmQgc3VwcG9ydHMgYm90aCBpbW1lZGlhdGUgZG93bmxvYWRcclxuICogcmVzcG9uc2VzIGFuZCBCYXNlNjQtZW5jb2RlZCBjb250ZW50IHJldHVybnMuIFRoZSBjb2RlIGFsc28gZmVhdHVyZXNcclxuICogYmVuY2htYXJraW5nIGZvciBwZXJmb3JtYW5jZSBtb25pdG9yaW5nLlxyXG4gKi9cclxuXHJcbmltcG9ydCB7IHN0YXJ0RXhwb3J0IH0gZnJvbSAnLi4vLi4vY2hhcnQuanMnO1xyXG5pbXBvcnQgeyBsb2cgfSBmcm9tICcuLi8uLi9sb2dnZXIuanMnO1xyXG5pbXBvcnQgeyBnZXRCYXNlNjQsIG1lYXN1cmVUaW1lIH0gZnJvbSAnLi4vLi4vdXRpbHMuanMnO1xyXG5cclxuaW1wb3J0IEV4cG9ydEVycm9yIGZyb20gJy4uLy4uL2Vycm9ycy9FeHBvcnRFcnJvci5qcyc7XHJcblxyXG4vLyBSZXZlcnNlZCBNSU1FIHR5cGVzXHJcbmNvbnN0IHJldmVyc2VkTWltZSA9IHtcclxuICBwbmc6ICdpbWFnZS9wbmcnLFxyXG4gIGpwZWc6ICdpbWFnZS9qcGVnJyxcclxuICBnaWY6ICdpbWFnZS9naWYnLFxyXG4gIHBkZjogJ2FwcGxpY2F0aW9uL3BkZicsXHJcbiAgc3ZnOiAnaW1hZ2Uvc3ZnK3htbCdcclxufTtcclxuXHJcbi8qKlxyXG4gKiBIYW5kbGVzIHRoZSBleHBvcnQgcmVxdWVzdHMgZnJvbSB0aGUgY2xpZW50LlxyXG4gKlxyXG4gKiBAYXN5bmNcclxuICogQGZ1bmN0aW9uIHJlcXVlc3RFeHBvcnRcclxuICpcclxuICogQHBhcmFtIHtFeHByZXNzLlJlcXVlc3R9IHJlcXVlc3QgLSBUaGUgRXhwcmVzcyByZXF1ZXN0IG9iamVjdC5cclxuICogQHBhcmFtIHtFeHByZXNzLlJlc3BvbnNlfSByZXNwb25zZSAtIFRoZSBFeHByZXNzIHJlc3BvbnNlIG9iamVjdC5cclxuICogQHBhcmFtIHtGdW5jdGlvbn0gbmV4dCAtIFRoZSBuZXh0IG1pZGRsZXdhcmUgZnVuY3Rpb24uXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtQcm9taXNlPHZvaWQ+fSBBIFByb21pc2UgdGhhdCByZXNvbHZlcyBvbmNlIHRoZSBleHBvcnQgcHJvY2Vzc1xyXG4gKiBpcyBjb21wbGV0ZS5cclxuICovXHJcbmFzeW5jIGZ1bmN0aW9uIHJlcXVlc3RFeHBvcnQocmVxdWVzdCwgcmVzcG9uc2UsIG5leHQpIHtcclxuICB0cnkge1xyXG4gICAgLy8gU3RhcnQgY291bnRpbmcgdGltZSBmb3IgYSByZXF1ZXN0XHJcbiAgICBjb25zdCByZXF1ZXN0Q291bnRlciA9IG1lYXN1cmVUaW1lKCk7XHJcblxyXG4gICAgLy8gSW4gY2FzZSB0aGUgY29ubmVjdGlvbiBpcyBjbG9zZWQsIGZvcmNlIHRvIGFib3J0IGZ1cnRoZXIgYWN0aW9uc1xyXG4gICAgbGV0IGNvbm5lY3Rpb25BYm9ydGVkID0gZmFsc2U7XHJcbiAgICByZXF1ZXN0LnNvY2tldC5vbignY2xvc2UnLCAoaGFkRXJyb3JzKSA9PiB7XHJcbiAgICAgIGlmIChoYWRFcnJvcnMpIHtcclxuICAgICAgICBjb25uZWN0aW9uQWJvcnRlZCA9IHRydWU7XHJcbiAgICAgIH1cclxuICAgIH0pO1xyXG5cclxuICAgIC8vIEdldCB0aGUgb3B0aW9ucyBwcmV2aW91c2x5IHZhbGlkYXRlZCBpbiB0aGUgdmFsaWRhdGlvbiBtaWRkbGV3YXJlXHJcbiAgICBjb25zdCBvcHRpb25zID0gcmVxdWVzdC52YWxpZGF0ZWRPcHRpb25zO1xyXG5cclxuICAgIC8vIEdldCB0aGUgcmVxdWVzdCBpZFxyXG4gICAgY29uc3QgcmVxdWVzdElkID0gb3B0aW9ucy5yZXF1ZXN0SWQ7XHJcblxyXG4gICAgLy8gSW5mbyBhYm91dCBhbiBpbmNvbWluZyByZXF1ZXN0IHdpdGggY29ycmVjdCBkYXRhXHJcbiAgICBsb2coNCwgYFtleHBvcnRdIFJlcXVlc3QgWyR7cmVxdWVzdElkfV0gLSBHb3QgYW4gaW5jb21pbmcgSFRUUCByZXF1ZXN0LmApO1xyXG5cclxuICAgIC8vIFN0YXJ0IHRoZSBleHBvcnQgcHJvY2Vzc1xyXG4gICAgYXdhaXQgc3RhcnRFeHBvcnQob3B0aW9ucywgKGVycm9yLCBkYXRhKSA9PiB7XHJcbiAgICAgIC8vIFJlbW92ZSB0aGUgY2xvc2UgZXZlbnQgZnJvbSB0aGUgc29ja2V0XHJcbiAgICAgIHJlcXVlc3Quc29ja2V0LnJlbW92ZUFsbExpc3RlbmVycygnY2xvc2UnKTtcclxuXHJcbiAgICAgIC8vIElmIHRoZSBjb25uZWN0aW9uIHdhcyBjbG9zZWQsIGRvIG5vdGhpbmdcclxuICAgICAgaWYgKGNvbm5lY3Rpb25BYm9ydGVkKSB7XHJcbiAgICAgICAgbG9nKFxyXG4gICAgICAgICAgMyxcclxuICAgICAgICAgIGBbZXhwb3J0XSBSZXF1ZXN0IFske3JlcXVlc3RJZH1dIC0gVGhlIGNsaWVudCBjbG9zZWQgdGhlIGNvbm5lY3Rpb24gYmVmb3JlIHRoZSBjaGFydCBmaW5pc2hlZCBwcm9jZXNzaW5nLmBcclxuICAgICAgICApO1xyXG4gICAgICAgIHJldHVybjtcclxuICAgICAgfVxyXG5cclxuICAgICAgLy8gSWYgZXJyb3IsIGxvZyBpdCBhbmQgc2VuZCBpdCB0byB0aGUgZXJyb3IgbWlkZGxld2FyZVxyXG4gICAgICBpZiAoZXJyb3IpIHtcclxuICAgICAgICB0aHJvdyBlcnJvcjtcclxuICAgICAgfVxyXG5cclxuICAgICAgLy8gSWYgZGF0YSBpcyBtaXNzaW5nLCBsb2cgdGhlIG1lc3NhZ2UgYW5kIHNlbmQgaXQgdG8gdGhlIGVycm9yIG1pZGRsZXdhcmVcclxuICAgICAgaWYgKCFkYXRhIHx8ICFkYXRhLnJlc3VsdCkge1xyXG4gICAgICAgIGxvZyhcclxuICAgICAgICAgIDIsXHJcbiAgICAgICAgICBgW2V4cG9ydF0gUmVxdWVzdCBbJHtyZXF1ZXN0SWR9XSAtIFJlcXVlc3QgZnJvbSAke1xyXG4gICAgICAgICAgICByZXF1ZXN0LmhlYWRlcnNbJ3gtZm9yd2FyZGVkLWZvciddIHx8XHJcbiAgICAgICAgICAgIHJlcXVlc3QuY29ubmVjdGlvbi5yZW1vdGVBZGRyZXNzXHJcbiAgICAgICAgICB9IHdhcyBpbmNvcnJlY3QuIFJlY2VpdmVkIHJlc3VsdCBpcyAke2RhdGEucmVzdWx0fS5gXHJcbiAgICAgICAgKTtcclxuXHJcbiAgICAgICAgdGhyb3cgbmV3IEV4cG9ydEVycm9yKFxyXG4gICAgICAgICAgYFtleHBvcnRdIFJlcXVlc3QgWyR7cmVxdWVzdElkfV0gLSBVbmV4cGVjdGVkIHJldHVybiBvZiB0aGUgZXhwb3J0IHJlc3VsdCBmcm9tIHRoZSBjaGFydCBnZW5lcmF0aW9uLiBQbGVhc2UgY2hlY2sgeW91ciByZXF1ZXN0IGRhdGEuYCxcclxuICAgICAgICAgIDQwMFxyXG4gICAgICAgICk7XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIC8vIFJldHVybiB0aGUgcmVzdWx0IGluIGFuIGFwcHJvcHJpYXRlIGZvcm1hdFxyXG4gICAgICBpZiAoZGF0YS5yZXN1bHQpIHtcclxuICAgICAgICBsb2coXHJcbiAgICAgICAgICAzLFxyXG4gICAgICAgICAgYFtleHBvcnRdIFJlcXVlc3QgWyR7cmVxdWVzdElkfV0gLSBUaGUgd2hvbGUgZXhwb3J0aW5nIHByb2Nlc3MgdG9vayAke3JlcXVlc3RDb3VudGVyKCl9bXMuYFxyXG4gICAgICAgICk7XHJcblxyXG4gICAgICAgIC8vIEdldCB0aGUgYHR5cGVgLCBgYjY0YCwgYG5vRG93bmxvYWRgLCBhbmQgYG91dGZpbGVgIGZyb20gb3B0aW9uc1xyXG4gICAgICAgIGNvbnN0IHsgdHlwZSwgYjY0LCBub0Rvd25sb2FkLCBvdXRmaWxlIH0gPSBkYXRhLm9wdGlvbnMuZXhwb3J0O1xyXG5cclxuICAgICAgICAvLyBJZiBvbmx5IEJhc2U2NCBpcyByZXF1aXJlZCwgcmV0dXJuIGl0XHJcbiAgICAgICAgaWYgKGI2NCkge1xyXG4gICAgICAgICAgcmV0dXJuIHJlc3BvbnNlLnNlbmQoZ2V0QmFzZTY0KGRhdGEucmVzdWx0LCB0eXBlKSk7XHJcbiAgICAgICAgfVxyXG5cclxuICAgICAgICAvLyBTZXQgY29ycmVjdCBjb250ZW50IHR5cGVcclxuICAgICAgICByZXNwb25zZS5oZWFkZXIoJ0NvbnRlbnQtVHlwZScsIHJldmVyc2VkTWltZVt0eXBlXSB8fCAnaW1hZ2UvcG5nJyk7XHJcblxyXG4gICAgICAgIC8vIERlY2lkZSB3aGV0aGVyIHRvIGRvd25sb2FkIG9yIG5vdCBjaGFydCBmaWxlXHJcbiAgICAgICAgaWYgKCFub0Rvd25sb2FkKSB7XHJcbiAgICAgICAgICByZXNwb25zZS5hdHRhY2htZW50KG91dGZpbGUpO1xyXG4gICAgICAgIH1cclxuXHJcbiAgICAgICAgLy8gSWYgU1ZHLCByZXR1cm4gcGxhaW4gY29udGVudCwgb3RoZXJ3aXNlIGEgYjY0IHN0cmluZyBmcm9tIGEgYnVmZmVyXHJcbiAgICAgICAgcmV0dXJuIHR5cGUgPT09ICdzdmcnXHJcbiAgICAgICAgICA/IHJlc3BvbnNlLnNlbmQoZGF0YS5yZXN1bHQpXHJcbiAgICAgICAgICA6IHJlc3BvbnNlLnNlbmQoQnVmZmVyLmZyb20oZGF0YS5yZXN1bHQsICdiYXNlNjQnKSk7XHJcbiAgICAgIH1cclxuICAgIH0pO1xyXG4gIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICByZXR1cm4gbmV4dChlcnJvcik7XHJcbiAgfVxyXG59XHJcblxyXG4vKipcclxuICogQWRkcyB0aGUgYGV4cG9ydGAgcm91dGVzLlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gZXhwb3J0Um91dGVzXHJcbiAqXHJcbiAqIEBwYXJhbSB7RXhwcmVzc30gYXBwIC0gVGhlIEV4cHJlc3MgYXBwIGluc3RhbmNlLlxyXG4gKi9cclxuZXhwb3J0IGRlZmF1bHQgZnVuY3Rpb24gZXhwb3J0Um91dGVzKGFwcCkge1xyXG4gIC8qKlxyXG4gICAqIEFkZHMgdGhlIFBPU1QgJy8nIC0gQSByb3V0ZSBmb3IgaGFuZGxpbmcgUE9TVCByZXF1ZXN0cyBhdCB0aGUgcm9vdFxyXG4gICAqIGVuZHBvaW50LlxyXG4gICAqL1xyXG4gIGFwcC5wb3N0KCcvJywgcmVxdWVzdEV4cG9ydCk7XHJcblxyXG4gIC8qKlxyXG4gICAqIEFkZHMgdGhlIFBPU1QgJy86ZmlsZW5hbWUnIC0gQSByb3V0ZSBmb3IgaGFuZGxpbmcgUE9TVCByZXF1ZXN0cyB3aXRoXHJcbiAgICogYSBzcGVjaWZpZWQgZmlsZW5hbWUgcGFyYW1ldGVyLlxyXG4gICAqL1xyXG4gIGFwcC5wb3N0KCcvOmZpbGVuYW1lJywgcmVxdWVzdEV4cG9ydCk7XHJcbn1cclxuIiwiLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcclxuXHJcbkhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlclxyXG5cclxuQ29weXJpZ2h0IChjKSAyMDE2LTIwMjUsIEhpZ2hzb2Z0XHJcblxyXG5MaWNlbmNlZCB1bmRlciB0aGUgTUlUIGxpY2VuY2UuXHJcblxyXG5BZGRpdGlvbmFsbHkgYSB2YWxpZCBIaWdoY2hhcnRzIGxpY2Vuc2UgaXMgcmVxdWlyZWQgZm9yIHVzZS5cclxuXHJcblNlZSBMSUNFTlNFIGZpbGUgaW4gcm9vdCBmb3IgZGV0YWlscy5cclxuXHJcbioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXHJcblxyXG4vKipcclxuICogQG92ZXJ2aWV3IERlZmluZXMgYW4gRXhwcmVzcyByb3V0ZSBmb3Igc2VydmVyIGhlYWx0aCBtb25pdG9yaW5nLCBpbmNsdWRpbmdcclxuICogdXB0aW1lLCBzdWNjZXNzIHJhdGVzLCBhbmQgb3RoZXIgc2VydmVyIHN0YXRpc3RpY3MuXHJcbiAqL1xyXG5cclxuaW1wb3J0IHsgcmVhZEZpbGVTeW5jIH0gZnJvbSAnZnMnO1xyXG5pbXBvcnQgeyBqb2luIH0gZnJvbSAncGF0aCc7XHJcblxyXG5pbXBvcnQgeyBnZXRIY1ZlcnNpb24gfSBmcm9tICcuLi8uLi9jYWNoZS5qcyc7XHJcbmltcG9ydCB7IGxvZyB9IGZyb20gJy4uLy4uL2xvZ2dlci5qcyc7XHJcbmltcG9ydCB7IGdldFBvb2xJbmZvSlNPTiwgZ2V0UG9vbFN0YXRzIH0gZnJvbSAnLi4vLi4vcG9vbC5qcyc7XHJcbmltcG9ydCB7IGFkZFRpbWVyIH0gZnJvbSAnLi4vLi4vdGltZXIuanMnO1xyXG5pbXBvcnQgeyBfX2Rpcm5hbWUsIGdldE5ld0RhdGVUaW1lIH0gZnJvbSAnLi4vLi4vdXRpbHMuanMnO1xyXG5cclxuLy8gU2V0IHRoZSBzdGFydCBkYXRlIG9mIHRoZSBzZXJ2ZXJcclxuY29uc3Qgc2VydmVyU3RhcnRUaW1lID0gbmV3IERhdGUoKTtcclxuXHJcbi8vIEdldCB0aGUgYHBhY2thZ2UuanNvbmAgY29udGVudFxyXG5jb25zdCBwYWNrYWdlRmlsZSA9IEpTT04ucGFyc2UoXHJcbiAgcmVhZEZpbGVTeW5jKGpvaW4oX19kaXJuYW1lLCAncGFja2FnZS5qc29uJyksICd1dGY4JylcclxuKTtcclxuXHJcbi8vIEFuIGFycmF5IGZvciBzdWNjZXNzIHJhdGUgcmF0aW9zXHJcbmNvbnN0IHN1Y2Nlc3NSYXRlcyA9IFtdO1xyXG5cclxuLy8gUmVjb3JkIGV2ZXJ5IG1pbnV0ZVxyXG5jb25zdCByZWNvcmRJbnRlcnZhbCA9IDYwICogMTAwMDtcclxuXHJcbi8vIDMwIG1pbnV0ZXNcclxuY29uc3Qgd2luZG93U2l6ZSA9IDMwO1xyXG5cclxuLyoqXHJcbiAqIENhbGN1bGF0ZXMgbW92aW5nIGF2ZXJhZ2UgaW5kaWNhdG9yIGJhc2VkIG9uIHRoZSBkYXRhIGZyb20gdGhlIGBzdWNjZXNzUmF0ZXNgXHJcbiAqIGFycmF5LlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gX2NhbGN1bGF0ZU1vdmluZ0F2ZXJhZ2VcclxuICpcclxuICogQHJldHVybnMge251bWJlcn0gQSBtb3ZpbmcgYXZlcmFnZSBmb3Igc3VjY2VzcyByYXRpbyBvZiB0aGUgc2VydmVyIGV4cG9ydHMuXHJcbiAqL1xyXG5mdW5jdGlvbiBfY2FsY3VsYXRlTW92aW5nQXZlcmFnZSgpIHtcclxuICByZXR1cm4gc3VjY2Vzc1JhdGVzLnJlZHVjZSgoYSwgYikgPT4gYSArIGIsIDApIC8gc3VjY2Vzc1JhdGVzLmxlbmd0aDtcclxufVxyXG5cclxuLyoqXHJcbiAqIFN0YXJ0cyB0aGUgaW50ZXJ2YWwgcmVzcG9uc2libGUgZm9yIGNhbGN1bGF0aW5nIGN1cnJlbnQgc3VjY2VzcyByYXRlIHJhdGlvXHJcbiAqIGFuZCBjb2xsZWN0cyByZWNvcmRzIHRvIHRoZSBgc3VjY2Vzc1JhdGVzYCBhcnJheS5cclxuICpcclxuICogQGZ1bmN0aW9uIF9zdGFydFN1Y2Nlc3NSYXRlXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtOb2RlSlMuVGltZW91dH0gSWQgb2YgYW4gaW50ZXJ2YWwuXHJcbiAqL1xyXG5mdW5jdGlvbiBfc3RhcnRTdWNjZXNzUmF0ZSgpIHtcclxuICByZXR1cm4gc2V0SW50ZXJ2YWwoKCkgPT4ge1xyXG4gICAgY29uc3Qgc3RhdHMgPSBnZXRQb29sU3RhdHMoKTtcclxuICAgIGNvbnN0IHN1Y2Nlc3NSYXRpbyA9XHJcbiAgICAgIHN0YXRzLmV4cG9ydHNBdHRlbXB0ZWQgPT09IDBcclxuICAgICAgICA/IDFcclxuICAgICAgICA6IChzdGF0cy5leHBvcnRzUGVyZm9ybWVkIC8gc3RhdHMuZXhwb3J0c0F0dGVtcHRlZCkgKiAxMDA7XHJcblxyXG4gICAgc3VjY2Vzc1JhdGVzLnB1c2goc3VjY2Vzc1JhdGlvKTtcclxuICAgIGlmIChzdWNjZXNzUmF0ZXMubGVuZ3RoID4gd2luZG93U2l6ZSkge1xyXG4gICAgICBzdWNjZXNzUmF0ZXMuc2hpZnQoKTtcclxuICAgIH1cclxuICB9LCByZWNvcmRJbnRlcnZhbCk7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBBZGRzIHRoZSBgaGVhbHRoYCByb3V0ZXMuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBoZWFsdGhSb3V0ZXNcclxuICpcclxuICogQHBhcmFtIHtFeHByZXNzfSBhcHAgLSBUaGUgRXhwcmVzcyBhcHAgaW5zdGFuY2UuXHJcbiAqL1xyXG5leHBvcnQgZGVmYXVsdCBmdW5jdGlvbiBoZWFsdGhSb3V0ZXMoYXBwKSB7XHJcbiAgLy8gU3RhcnQgcHJvY2Vzc2luZyBzdWNjZXNzIHJhdGUgcmF0aW8gaW50ZXJ2YWwgYW5kIHNhdmUgaXRzIGlkIHRvIHRoZSBhcnJheVxyXG4gIC8vIGZvciB0aGUgZ3JhY2VmdWwgY2xlYXJpbmcgb24gc2h1dGRvd24gd2l0aCBpbmplY3RlZCBgYWRkVGltZXJgIGZ1bnRpb25cclxuICBhZGRUaW1lcihfc3RhcnRTdWNjZXNzUmF0ZSgpKTtcclxuXHJcbiAgLyoqXHJcbiAgICogQWRkcyB0aGUgR0VUICcvaGVhbHRoJyAtIEEgcm91dGUgZm9yIGdldHRpbmcgdGhlIGJhc2ljIHN0YXRzIG9mIHRoZSBzZXJ2ZXIuXHJcbiAgICovXHJcbiAgYXBwLmdldCgnL2hlYWx0aCcsIChyZXF1ZXN0LCByZXNwb25zZSwgbmV4dCkgPT4ge1xyXG4gICAgdHJ5IHtcclxuICAgICAgbG9nKDQsICdbaGVhbHRoXSBSZXR1cm5pbmcgc2VydmVyIGhlYWx0aC4nKTtcclxuXHJcbiAgICAgIGNvbnN0IHN0YXRzID0gZ2V0UG9vbFN0YXRzKCk7XHJcbiAgICAgIGNvbnN0IHBlcmlvZCA9IHN1Y2Nlc3NSYXRlcy5sZW5ndGg7XHJcbiAgICAgIGNvbnN0IG1vdmluZ0F2ZXJhZ2UgPSBfY2FsY3VsYXRlTW92aW5nQXZlcmFnZSgpO1xyXG5cclxuICAgICAgLy8gU2VuZCB0aGUgc2VydmVyJ3Mgc3RhdGlzdGljc1xyXG4gICAgICByZXNwb25zZS5zZW5kKHtcclxuICAgICAgICAvLyBTdGF0dXMgYW5kIHRpbWVzXHJcbiAgICAgICAgc3RhdHVzOiAnT0snLFxyXG4gICAgICAgIGJvb3RUaW1lOiBzZXJ2ZXJTdGFydFRpbWUsXHJcbiAgICAgICAgdXB0aW1lOiBgJHtNYXRoLmZsb29yKChnZXROZXdEYXRlVGltZSgpIC0gc2VydmVyU3RhcnRUaW1lLmdldFRpbWUoKSkgLyAxMDAwIC8gNjApfSBtaW51dGVzYCxcclxuXHJcbiAgICAgICAgLy8gVmVyc2lvbnNcclxuICAgICAgICBzZXJ2ZXJWZXJzaW9uOiBwYWNrYWdlRmlsZS52ZXJzaW9uLFxyXG4gICAgICAgIGhpZ2hjaGFydHNWZXJzaW9uOiBnZXRIY1ZlcnNpb24oKSxcclxuXHJcbiAgICAgICAgLy8gRXhwb3J0c1xyXG4gICAgICAgIGF2ZXJhZ2VFeHBvcnRUaW1lOiBzdGF0cy50aW1lU3BlbnRBdmVyYWdlLFxyXG4gICAgICAgIGF0dGVtcHRlZEV4cG9ydHM6IHN0YXRzLmV4cG9ydHNBdHRlbXB0ZWQsXHJcbiAgICAgICAgcGVyZm9ybWVkRXhwb3J0czogc3RhdHMuZXhwb3J0c1BlcmZvcm1lZCxcclxuICAgICAgICBmYWlsZWRFeHBvcnRzOiBzdGF0cy5leHBvcnRzRHJvcHBlZCxcclxuICAgICAgICBzdWNlc3NSYXRpbzogKHN0YXRzLmV4cG9ydHNQZXJmb3JtZWQgLyBzdGF0cy5leHBvcnRzQXR0ZW1wdGVkKSAqIDEwMCxcclxuXHJcbiAgICAgICAgLy8gUG9vbFxyXG4gICAgICAgIHBvb2w6IGdldFBvb2xJbmZvSlNPTigpLFxyXG5cclxuICAgICAgICAvLyBNb3ZpbmcgYXZlcmFnZVxyXG4gICAgICAgIHBlcmlvZCxcclxuICAgICAgICBtb3ZpbmdBdmVyYWdlLFxyXG4gICAgICAgIG1lc3NhZ2U6XHJcbiAgICAgICAgICBpc05hTihtb3ZpbmdBdmVyYWdlKSB8fCAhc3VjY2Vzc1JhdGVzLmxlbmd0aFxyXG4gICAgICAgICAgICA/ICdUb28gZWFybHkgdG8gcmVwb3J0LiBObyBleHBvcnRzIG1hZGUgeWV0LiBQbGVhc2UgY2hlY2sgYmFjayBzb29uLidcclxuICAgICAgICAgICAgOiBgTGFzdCAke3BlcmlvZH0gbWludXRlcyBoYWQgYSBzdWNjZXNzIHJhdGUgb2YgJHttb3ZpbmdBdmVyYWdlLnRvRml4ZWQoMil9JS5gLFxyXG5cclxuICAgICAgICAvLyBTVkcgYW5kIEpTT04gZXhwb3J0c1xyXG4gICAgICAgIHN2Z0V4cG9ydHM6IHN0YXRzLmV4cG9ydHNGcm9tU3ZnLFxyXG4gICAgICAgIGpzb25FeHBvcnRzOiBzdGF0cy5leHBvcnRzRnJvbU9wdGlvbnMsXHJcbiAgICAgICAgc3ZnRXhwb3J0c0F0dGVtcHRzOiBzdGF0cy5leHBvcnRzRnJvbVN2Z0F0dGVtcHRzLFxyXG4gICAgICAgIGpzb25FeHBvcnRzQXR0ZW1wdHM6IHN0YXRzLmV4cG9ydHNGcm9tT3B0aW9uc0F0dGVtcHRzXHJcbiAgICAgIH0pO1xyXG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICAgcmV0dXJuIG5leHQoZXJyb3IpO1xyXG4gICAgfVxyXG4gIH0pO1xyXG59XHJcbiIsIi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXHJcblxyXG5IaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXJcclxuXHJcbkNvcHlyaWdodCAoYykgMjAxNi0yMDI1LCBIaWdoc29mdFxyXG5cclxuTGljZW5jZWQgdW5kZXIgdGhlIE1JVCBsaWNlbmNlLlxyXG5cclxuQWRkaXRpb25hbGx5IGEgdmFsaWQgSGlnaGNoYXJ0cyBsaWNlbnNlIGlzIHJlcXVpcmVkIGZvciB1c2UuXHJcblxyXG5TZWUgTElDRU5TRSBmaWxlIGluIHJvb3QgZm9yIGRldGFpbHMuXHJcblxyXG4qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xyXG5cclxuLyoqXHJcbiAqIEBvdmVydmlldyBEZWZpbmVzIGFuIEV4cHJlc3Mgcm91dGUgZm9yIHNlcnZpbmcgdGhlIFVJIGZvciB0aGUgZXhwb3J0IHNlcnZlclxyXG4gKiB3aGVuIGVuYWJsZWQuXHJcbiAqL1xyXG5cclxuaW1wb3J0IHsgam9pbiB9IGZyb20gJ3BhdGgnO1xyXG5cclxuaW1wb3J0IHsgZ2V0T3B0aW9ucyB9IGZyb20gJy4uLy4uL2NvbmZpZy5qcyc7XHJcbmltcG9ydCB7IGxvZyB9IGZyb20gJy4uLy4uL2xvZ2dlci5qcyc7XHJcbmltcG9ydCB7IF9fZGlybmFtZSB9IGZyb20gJy4uLy4uL3V0aWxzLmpzJztcclxuXHJcbi8qKlxyXG4gKiBBZGRzIHRoZSBgdWlgIHJvdXRlcy5cclxuICpcclxuICogQGZ1bmN0aW9uIHVpUm91dGVzXHJcbiAqXHJcbiAqIEBwYXJhbSB7RXhwcmVzc30gYXBwIC0gVGhlIEV4cHJlc3MgYXBwIGluc3RhbmNlLlxyXG4gKi9cclxuZXhwb3J0IGRlZmF1bHQgZnVuY3Rpb24gdWlSb3V0ZXMoYXBwKSB7XHJcbiAgLy8gQWRkIHRoZSBVSSBlbmRwb2ludCBvbmx5IGlmIHJlcXVpcmVkXHJcbiAgaWYgKGdldE9wdGlvbnMoKS51aS5lbmFibGUpIHtcclxuICAgIC8qKlxyXG4gICAgICogQWRkcyB0aGUgR0VUICcvJyAtIEEgcm91dGUgZm9yIGEgVUkgd2hlbiBlbmFibGVkIG9uIHRoZSBleHBvcnQgc2VydmVyLlxyXG4gICAgICovXHJcbiAgICBhcHAuZ2V0KGdldE9wdGlvbnMoKS51aS5yb3V0ZSB8fCAnLycsIChyZXF1ZXN0LCByZXNwb25zZSwgbmV4dCkgPT4ge1xyXG4gICAgICB0cnkge1xyXG4gICAgICAgIGxvZyg0LCAnW3VpXSBSZXR1cm5pbmcgVUkgZm9yIHRoZSBleHBvcnQuJyk7XHJcblxyXG4gICAgICAgIHJlc3BvbnNlLnNlbmRGaWxlKGpvaW4oX19kaXJuYW1lLCAncHVibGljJywgJ2luZGV4Lmh0bWwnKSwge1xyXG4gICAgICAgICAgYWNjZXB0UmFuZ2VzOiBmYWxzZVxyXG4gICAgICAgIH0pO1xyXG4gICAgICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgICAgIHJldHVybiBuZXh0KGVycm9yKTtcclxuICAgICAgfVxyXG4gICAgfSk7XHJcbiAgfVxyXG59XHJcbiIsIi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXHJcblxyXG5IaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXJcclxuXHJcbkNvcHlyaWdodCAoYykgMjAxNi0yMDI1LCBIaWdoc29mdFxyXG5cclxuTGljZW5jZWQgdW5kZXIgdGhlIE1JVCBsaWNlbmNlLlxyXG5cclxuQWRkaXRpb25hbGx5IGEgdmFsaWQgSGlnaGNoYXJ0cyBsaWNlbnNlIGlzIHJlcXVpcmVkIGZvciB1c2UuXHJcblxyXG5TZWUgTElDRU5TRSBmaWxlIGluIHJvb3QgZm9yIGRldGFpbHMuXHJcblxyXG4qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xyXG5cclxuLyoqXHJcbiAqIEBvdmVydmlldyBEZWZpbmVzIGFuIEV4cHJlc3Mgcm91dGUgZm9yIHVwZGF0aW5nIHRoZSBIaWdoY2hhcnRzIHZlcnNpb25cclxuICogb24gdGhlIHNlcnZlciwgd2l0aCBhdXRoZW50aWNhdGlvbiBhbmQgdmFsaWRhdGlvbi5cclxuICovXHJcblxyXG5pbXBvcnQgeyBnZXRIY1ZlcnNpb24sIHVwZGF0ZUhjVmVyc2lvbiB9IGZyb20gJy4uLy4uL2NhY2hlLmpzJztcclxuaW1wb3J0IHsgbG9nIH0gZnJvbSAnLi4vLi4vbG9nZ2VyLmpzJztcclxuaW1wb3J0IHsgZW52cyB9IGZyb20gJy4uLy4uL3ZhbGlkYXRpb24uanMnO1xyXG5cclxuaW1wb3J0IEV4cG9ydEVycm9yIGZyb20gJy4uLy4uL2Vycm9ycy9FeHBvcnRFcnJvci5qcyc7XHJcblxyXG4vKipcclxuICogQWRkcyB0aGUgYHZlcnNpb25fY2hhbmdlYCByb3V0ZXMuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiB2ZXJzaW9uQ2hhbmdlUm91dGVzXHJcbiAqXHJcbiAqIEBwYXJhbSB7RXhwcmVzc30gYXBwIC0gVGhlIEV4cHJlc3MgYXBwIGluc3RhbmNlLlxyXG4gKi9cclxuZXhwb3J0IGRlZmF1bHQgZnVuY3Rpb24gdmVyc2lvbkNoYW5nZVJvdXRlcyhhcHApIHtcclxuICAvKipcclxuICAgKiBBZGRzIHRoZSBQT1NUICcvdmVyc2lvbl9jaGFuZ2UvOm5ld1ZlcnNpb24nIC0gQSByb3V0ZSBmb3IgY2hhbmdpbmdcclxuICAgKiB0aGUgSGlnaGNoYXJ0cyB2ZXJzaW9uIG9uIHRoZSBzZXJ2ZXIuXHJcbiAgICovXHJcbiAgYXBwLnBvc3QoJy92ZXJzaW9uX2NoYW5nZS86bmV3VmVyc2lvbicsIGFzeW5jIChyZXF1ZXN0LCByZXNwb25zZSwgbmV4dCkgPT4ge1xyXG4gICAgdHJ5IHtcclxuICAgICAgbG9nKDQsICdbdmVyc2lvbl0gQ2hhbmdpbmcgSGlnaGNoYXJ0cyB2ZXJzaW9uLicpO1xyXG5cclxuICAgICAgLy8gR2V0IHRoZSB0b2tlbiBkaXJlY3RseSBmcm9tIGVudnNcclxuICAgICAgY29uc3QgYWRtaW5Ub2tlbiA9IGVudnMuSElHSENIQVJUU19BRE1JTl9UT0tFTjtcclxuXHJcbiAgICAgIC8vIENoZWNrIHRoZSBleGlzdGVuY2Ugb2YgdGhlIHRva2VuXHJcbiAgICAgIGlmICghYWRtaW5Ub2tlbiB8fCAhYWRtaW5Ub2tlbi5sZW5ndGgpIHtcclxuICAgICAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoXHJcbiAgICAgICAgICAnW3ZlcnNpb25dIFRoZSBzZXJ2ZXIgaXMgbm90IGNvbmZpZ3VyZWQgdG8gcGVyZm9ybSBydW4tdGltZSB2ZXJzaW9uIGNoYW5nZXM6IGBISUdIQ0hBUlRTX0FETUlOX1RPS0VOYCBpcyBub3Qgc2V0LicsXHJcbiAgICAgICAgICA0MDFcclxuICAgICAgICApO1xyXG4gICAgICB9XHJcblxyXG4gICAgICAvLyBHZXQgdGhlIHRva2VuIGZyb20gdGhlIGhjLWF1dGggaGVhZGVyXHJcbiAgICAgIGNvbnN0IHRva2VuID0gcmVxdWVzdC5nZXQoJ2hjLWF1dGgnKTtcclxuXHJcbiAgICAgIC8vIENoZWNrIGlmIHRoZSBoYy1hdXRoIGhlYWRlciBjb250YWluIGEgY29ycmVjdCB0b2tlblxyXG4gICAgICBpZiAoIXRva2VuIHx8IHRva2VuICE9PSBhZG1pblRva2VuKSB7XHJcbiAgICAgICAgdGhyb3cgbmV3IEV4cG9ydEVycm9yKFxyXG4gICAgICAgICAgJ1t2ZXJzaW9uXSBJbnZhbGlkIG9yIG1pc3NpbmcgdG9rZW46IFNldCB0aGUgdG9rZW4gaW4gdGhlIGhjLWF1dGggaGVhZGVyLicsXHJcbiAgICAgICAgICA0MDFcclxuICAgICAgICApO1xyXG4gICAgICB9XHJcblxyXG4gICAgICAvLyBHZXQgdGhlIG5ldyB2ZXJzaW9uIGZyb20gdGhlIHBhcmFtc1xyXG4gICAgICBjb25zdCBuZXdWZXJzaW9uID0gcmVxdWVzdC5wYXJhbXMubmV3VmVyc2lvbjtcclxuXHJcbiAgICAgIC8vIFVwZGF0ZSB2ZXJzaW9uXHJcbiAgICAgIGlmIChuZXdWZXJzaW9uKSB7XHJcbiAgICAgICAgdHJ5IHtcclxuICAgICAgICAgIGF3YWl0IHVwZGF0ZUhjVmVyc2lvbihuZXdWZXJzaW9uKTtcclxuICAgICAgICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgICAgICAgdGhyb3cgbmV3IEV4cG9ydEVycm9yKFxyXG4gICAgICAgICAgICBgW3ZlcnNpb25dIFZlcnNpb24gY2hhbmdlOiAke2Vycm9yLm1lc3NhZ2V9YCxcclxuICAgICAgICAgICAgNDAwXHJcbiAgICAgICAgICApLnNldEVycm9yKGVycm9yKTtcclxuICAgICAgICB9XHJcblxyXG4gICAgICAgIC8vIFN1Y2Nlc3NcclxuICAgICAgICByZXNwb25zZS5zdGF0dXMoMjAwKS5zZW5kKHtcclxuICAgICAgICAgIHN0YXR1c0NvZGU6IDIwMCxcclxuICAgICAgICAgIGhpZ2hjaGFydHNWZXJzaW9uOiBnZXRIY1ZlcnNpb24oKSxcclxuICAgICAgICAgIG1lc3NhZ2U6IGBTdWNjZXNzZnVsbHkgdXBkYXRlZCBIaWdoY2hhcnRzIHRvIHZlcnNpb246ICR7bmV3VmVyc2lvbn0uYFxyXG4gICAgICAgIH0pO1xyXG4gICAgICB9IGVsc2Uge1xyXG4gICAgICAgIC8vIE5vIHZlcnNpb24gc3BlY2lmaWVkXHJcbiAgICAgICAgdGhyb3cgbmV3IEV4cG9ydEVycm9yKCdbdmVyc2lvbl0gTm8gbmV3IHZlcnNpb24gc3VwcGxpZWQuJywgNDAwKTtcclxuICAgICAgfVxyXG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICAgcmV0dXJuIG5leHQoZXJyb3IpO1xyXG4gICAgfVxyXG4gIH0pO1xyXG59XHJcbiIsIi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXHJcblxyXG5IaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXJcclxuXHJcbkNvcHlyaWdodCAoYykgMjAxNi0yMDI1LCBIaWdoc29mdFxyXG5cclxuTGljZW5jZWQgdW5kZXIgdGhlIE1JVCBsaWNlbmNlLlxyXG5cclxuQWRkaXRpb25hbGx5IGEgdmFsaWQgSGlnaGNoYXJ0cyBsaWNlbnNlIGlzIHJlcXVpcmVkIGZvciB1c2UuXHJcblxyXG5TZWUgTElDRU5TRSBmaWxlIGluIHJvb3QgZm9yIGRldGFpbHMuXHJcblxyXG4qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xyXG5cclxuLyoqXHJcbiAqIEBvdmVydmlldyBBIG1vZHVsZSB0aGF0IHNldHMgdXAgYW5kIG1hbmFnZXMgSFRUUCBhbmQgSFRUUFMgc2VydmVyc1xyXG4gKiBmb3IgdGhlIEhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlci4gSXQgaGFuZGxlcyBzZXJ2ZXIgaW5pdGlhbGl6YXRpb24sXHJcbiAqIGNvbmZpZ3VyYXRpb24sIGVycm9yIGhhbmRsaW5nLCBtaWRkbGV3YXJlcyBzZXR1cCwgcm91dGUgZGVmaW5pdGlvbiwgYW5kIHJhdGVcclxuICogbGltaXRpbmcuIFRoZSBtb2R1bGUgZXhwb3J0cyBmdW5jdGlvbnMgdG8gc3RhcnQsIHN0b3AsIGFuZCBtYW5hZ2Ugc2VydmVyXHJcbiAqIGluc3RhbmNlcywgYXMgd2VsbCBhcyB1dGlsaXR5IGZ1bmN0aW9ucyBmb3IgZGVmaW5pbmcgcm91dGVzIGFuZCBhdHRhY2hpbmdcclxuICogbWlkZGxld2FyZXMuXHJcbiAqL1xyXG5cclxuaW1wb3J0IHsgcmVhZEZpbGVTeW5jIH0gZnJvbSAnZnMnO1xyXG5pbXBvcnQgeyBqb2luIH0gZnJvbSAncGF0aCc7XHJcblxyXG5pbXBvcnQgY29ycyBmcm9tICdjb3JzJztcclxuaW1wb3J0IGV4cHJlc3MgZnJvbSAnZXhwcmVzcyc7XHJcbmltcG9ydCBodHRwIGZyb20gJ2h0dHAnO1xyXG5pbXBvcnQgaHR0cHMgZnJvbSAnaHR0cHMnO1xyXG5pbXBvcnQgbXVsdGVyIGZyb20gJ211bHRlcic7XHJcblxyXG5pbXBvcnQgeyB1cGRhdGVPcHRpb25zIH0gZnJvbSAnLi4vY29uZmlnLmpzJztcclxuaW1wb3J0IHsgbG9nLCBsb2dXaXRoU3RhY2sgfSBmcm9tICcuLi9sb2dnZXIuanMnO1xyXG5pbXBvcnQgeyBfX2Rpcm5hbWUsIGdldEFic29sdXRlUGF0aCB9IGZyb20gJy4uL3V0aWxzLmpzJztcclxuXHJcbmltcG9ydCBlcnJvck1pZGRsZXdhcmUgZnJvbSAnLi9taWRkbGV3YXJlcy9lcnJvci5qcyc7XHJcbmltcG9ydCByYXRlTGltaXRpbmdNaWRkbGV3YXJlIGZyb20gJy4vbWlkZGxld2FyZXMvcmF0ZUxpbWl0aW5nLmpzJztcclxuaW1wb3J0IHZhbGlkYXRpb25NaWRkbGV3YXJlIGZyb20gJy4vbWlkZGxld2FyZXMvdmFsaWRhdGlvbi5qcyc7XHJcblxyXG5pbXBvcnQgZXhwb3J0Um91dGVzIGZyb20gJy4vcm91dGVzL2V4cG9ydC5qcyc7XHJcbmltcG9ydCBoZWFsdGhSb3V0ZXMgZnJvbSAnLi9yb3V0ZXMvaGVhbHRoLmpzJztcclxuaW1wb3J0IHVpUm91dGVzIGZyb20gJy4vcm91dGVzL3VpLmpzJztcclxuaW1wb3J0IHZlcnNpb25DaGFuZ2VSb3V0ZXMgZnJvbSAnLi9yb3V0ZXMvdmVyc2lvbkNoYW5nZS5qcyc7XHJcblxyXG5pbXBvcnQgRXhwb3J0RXJyb3IgZnJvbSAnLi4vZXJyb3JzL0V4cG9ydEVycm9yLmpzJztcclxuXHJcbi8vIEFycmF5IG9mIGFuIGFjdGl2ZSBzZXJ2ZXJzXHJcbmNvbnN0IGFjdGl2ZVNlcnZlcnMgPSBuZXcgTWFwKCk7XHJcblxyXG4vLyBDcmVhdGUgZXhwcmVzcyBhcHBcclxuY29uc3QgYXBwID0gZXhwcmVzcygpO1xyXG5cclxuLyoqXHJcbiAqIFN0YXJ0cyBhbiBIVFRQIGFuZC9vciBIVFRQUyBzZXJ2ZXIgYmFzZWQgb24gdGhlIHByb3ZpZGVkIGNvbmZpZ3VyYXRpb24uXHJcbiAqIFRoZSBgc2VydmVyT3B0aW9uc2Agb2JqZWN0IGNvbnRhaW5zIHNlcnZlci1yZWxhdGVkIHByb3BlcnRpZXMgKHJlZmVyXHJcbiAqIHRvIHRoZSBgc2VydmVyYCBzZWN0aW9uIGluIHRoZSBgLi9saWIvc2NoZW1hcy9jb25maWcuanNgIGZpbGUgZm9yIGRldGFpbHMpLlxyXG4gKlxyXG4gKiBAYXN5bmNcclxuICogQGZ1bmN0aW9uIHN0YXJ0U2VydmVyXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBbc2VydmVyT3B0aW9ucz17fV0gLSBUaGUgY29uZmlndXJhdGlvbiBvYmplY3QgY29udGFpbmluZ1xyXG4gKiBgc2VydmVyYCBvcHRpb25zLiBUaGlzIG9iamVjdCBtYXkgaW5jbHVkZSBhIHBhcnRpYWwgb3IgY29tcGxldGUgc2V0XHJcbiAqIG9mIHRoZSBgc2VydmVyYCBvcHRpb25zLiBJZiB0aGUgb3B0aW9ucyBhcmUgcGFydGlhbCwgbWlzc2luZyB2YWx1ZXMgd2lsbFxyXG4gKiBkZWZhdWx0IHRvIHRoZSBjdXJyZW50IGdsb2JhbCBjb25maWd1cmF0aW9uLiBUaGUgZGVmYXVsdCB2YWx1ZSBpcyBhbiBlbXB0eVxyXG4gKiBvYmplY3QuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtQcm9taXNlPHZvaWQ+fSBBIFByb21pc2UgdGhhdCByZXNvbHZlcyB3aGVuIHRoZSBzZXJ2ZXIgaXMgZWl0aGVyXHJcbiAqIG5vdCBlbmFibGVkIG9yIG5vIHZhbGlkIEV4cHJlc3MgYXBwIGlzIGZvdW5kLCBzaWduYWxpbmcgdGhlIGVuZCBvZiB0aGVcclxuICogZnVuY3Rpb24ncyBleGVjdXRpb24uXHJcbiAqXHJcbiAqIEB0aHJvd3Mge0V4cG9ydEVycm9yfSBUaHJvd3MgYW4gYEV4cG9ydEVycm9yYCBpZiB0aGUgc2VydmVyIGNhbm5vdFxyXG4gKiBiZSBjb25maWd1cmVkIGFuZCBzdGFydGVkLlxyXG4gKi9cclxuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIHN0YXJ0U2VydmVyKHNlcnZlck9wdGlvbnMgPSB7fSkge1xyXG4gIHRyeSB7XHJcbiAgICAvLyBVcGRhdGUgdGhlIGluc3RhbmNlIG9wdGlvbnMgb2JqZWN0XHJcbiAgICBjb25zdCBvcHRpb25zID0gdXBkYXRlT3B0aW9ucyh7XHJcbiAgICAgIHNlcnZlcjogc2VydmVyT3B0aW9uc1xyXG4gICAgfSk7XHJcblxyXG4gICAgLy8gVXNlIHZhbGlkYXRlZCBvcHRpb25zXHJcbiAgICBzZXJ2ZXJPcHRpb25zID0gb3B0aW9ucy5zZXJ2ZXI7XHJcblxyXG4gICAgLy8gU3RvcCBpZiBub3QgZW5hYmxlZFxyXG4gICAgaWYgKCFzZXJ2ZXJPcHRpb25zLmVuYWJsZSB8fCAhYXBwKSB7XHJcbiAgICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcihcclxuICAgICAgICAnW3NlcnZlcl0gU2VydmVyIGNhbm5vdCBiZSBzdGFydGVkIChub3QgZW5hYmxlZCBvciBubyBjb3JyZWN0IEV4cHJlc3MgYXBwIGZvdW5kKS4nLFxyXG4gICAgICAgIDUwMFxyXG4gICAgICApO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIFRvbyBiaWcgbGltaXRzIGxlYWQgdG8gdGltZW91dHMgaW4gdGhlIGV4cG9ydCBwcm9jZXNzIHdoZW5cclxuICAgIC8vIHRoZSByYXN0ZXJpemF0aW9uIHRpbWVvdXQgaXMgc2V0IHRvbyBsb3dcclxuICAgIGNvbnN0IHVwbG9hZExpbWl0Qnl0ZXMgPSBzZXJ2ZXJPcHRpb25zLnVwbG9hZExpbWl0ICogMTAyNCAqIDEwMjQ7XHJcblxyXG4gICAgLy8gTWVtb3J5IHN0b3JhZ2UgZm9yIG11bHRlciBwYWNrYWdlXHJcbiAgICBjb25zdCBzdG9yYWdlID0gbXVsdGVyLm1lbW9yeVN0b3JhZ2UoKTtcclxuXHJcbiAgICAvLyBFbmFibGUgcGFyc2luZyBvZiBmb3JtIGRhdGEgKGZpbGVzKSB3aXRoIG11bHRlciBwYWNrYWdlXHJcbiAgICBjb25zdCB1cGxvYWQgPSBtdWx0ZXIoe1xyXG4gICAgICBzdG9yYWdlLFxyXG4gICAgICBsaW1pdHM6IHtcclxuICAgICAgICBmaWVsZFNpemU6IHVwbG9hZExpbWl0Qnl0ZXNcclxuICAgICAgfVxyXG4gICAgfSk7XHJcblxyXG4gICAgLy8gRGlzYWJsZSB0aGUgWC1Qb3dlcmVkLUJ5IGhlYWRlclxyXG4gICAgYXBwLmRpc2FibGUoJ3gtcG93ZXJlZC1ieScpO1xyXG5cclxuICAgIC8vIEVuYWJsZSBDT1JTIHN1cHBvcnRcclxuICAgIGFwcC51c2UoXHJcbiAgICAgIGNvcnMoe1xyXG4gICAgICAgIG1ldGhvZHM6IFsnUE9TVCcsICdHRVQnLCAnT1BUSU9OUyddXHJcbiAgICAgIH0pXHJcbiAgICApO1xyXG5cclxuICAgIC8vIEdldHRpbmcgYSBsb3Qgb2YgYFJhbmdlTm90U2F0aXNmaWFibGVFcnJvcmAgZXhjZXB0aW9ucyAoZXZlbiB0aG91Z2ggdGhpc1xyXG4gICAgLy8gaXMgYSBkZXByZWNhdGVkIG9wdGlvbnMsIGxldCdzIHRyeSB0byBzZXQgaXQgdG8gZmFsc2UpXHJcbiAgICBhcHAudXNlKChyZXF1ZXN0LCByZXNwb25zZSwgbmV4dCkgPT4ge1xyXG4gICAgICByZXNwb25zZS5zZXQoJ0FjY2VwdC1SYW5nZXMnLCAnbm9uZScpO1xyXG4gICAgICBuZXh0KCk7XHJcbiAgICB9KTtcclxuXHJcbiAgICAvLyBFbmFibGUgYm9keSBwYXJzZXIgZm9yIEpTT04gZGF0YVxyXG4gICAgYXBwLnVzZShcclxuICAgICAgZXhwcmVzcy5qc29uKHtcclxuICAgICAgICBsaW1pdDogdXBsb2FkTGltaXRCeXRlc1xyXG4gICAgICB9KVxyXG4gICAgKTtcclxuXHJcbiAgICAvLyBFbmFibGUgYm9keSBwYXJzZXIgZm9yIFVSTC1lbmNvZGVkIGZvcm0gZGF0YVxyXG4gICAgYXBwLnVzZShcclxuICAgICAgZXhwcmVzcy51cmxlbmNvZGVkKHtcclxuICAgICAgICBleHRlbmRlZDogdHJ1ZSxcclxuICAgICAgICBsaW1pdDogdXBsb2FkTGltaXRCeXRlc1xyXG4gICAgICB9KVxyXG4gICAgKTtcclxuXHJcbiAgICAvLyBVc2Ugb25seSBub24tZmlsZSBtdWx0aXBhcnQgZm9ybSBmaWVsZHNcclxuICAgIGFwcC51c2UodXBsb2FkLm5vbmUoKSk7XHJcblxyXG4gICAgLy8gU2V0IHVwIHN0YXRpYyBmb2xkZXIncyByb3V0ZVxyXG4gICAgYXBwLnVzZShleHByZXNzLnN0YXRpYyhqb2luKF9fZGlybmFtZSwgJ3B1YmxpYycpKSk7XHJcblxyXG4gICAgLy8gTGlzdGVuIEhUVFAgc2VydmVyXHJcbiAgICBpZiAoIXNlcnZlck9wdGlvbnMuc3NsLmZvcmNlKSB7XHJcbiAgICAgIC8vIE1haW4gc2VydmVyIGluc3RhbmNlIChIVFRQKVxyXG4gICAgICBjb25zdCBodHRwU2VydmVyID0gaHR0cC5jcmVhdGVTZXJ2ZXIoYXBwKTtcclxuXHJcbiAgICAgIC8vIEF0dGFjaCBlcnJvciBoYW5kbGVycyBhbmQgbGlzdGVuIHRvIHRoZSBzZXJ2ZXJcclxuICAgICAgX2F0dGFjaFNlcnZlckVycm9ySGFuZGxlcnMoaHR0cFNlcnZlcik7XHJcblxyXG4gICAgICAvLyBMaXN0ZW5cclxuICAgICAgaHR0cFNlcnZlci5saXN0ZW4oc2VydmVyT3B0aW9ucy5wb3J0LCBzZXJ2ZXJPcHRpb25zLmhvc3QsICgpID0+IHtcclxuICAgICAgICAvLyBTYXZlIHRoZSByZWZlcmVuY2UgdG8gSFRUUCBzZXJ2ZXJcclxuICAgICAgICBhY3RpdmVTZXJ2ZXJzLnNldChzZXJ2ZXJPcHRpb25zLnBvcnQsIGh0dHBTZXJ2ZXIpO1xyXG5cclxuICAgICAgICBsb2coXHJcbiAgICAgICAgICAzLFxyXG4gICAgICAgICAgYFtzZXJ2ZXJdIFN0YXJ0ZWQgSFRUUCBzZXJ2ZXIgb24gJHtzZXJ2ZXJPcHRpb25zLmhvc3R9OiR7c2VydmVyT3B0aW9ucy5wb3J0fS5gXHJcbiAgICAgICAgKTtcclxuICAgICAgfSk7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gTGlzdGVuIEhUVFBTIHNlcnZlclxyXG4gICAgaWYgKHNlcnZlck9wdGlvbnMuc3NsLmVuYWJsZSkge1xyXG4gICAgICAvLyBTZXQgdXAgYW4gU1NMIHNlcnZlciBhbHNvXHJcbiAgICAgIGxldCBrZXksIGNlcnQ7XHJcblxyXG4gICAgICB0cnkge1xyXG4gICAgICAgIC8vIEdldCB0aGUgU1NMIGtleVxyXG4gICAgICAgIGtleSA9IHJlYWRGaWxlU3luYyhcclxuICAgICAgICAgIGpvaW4oZ2V0QWJzb2x1dGVQYXRoKHNlcnZlck9wdGlvbnMuc3NsLmNlcnRQYXRoKSwgJ3NlcnZlci5rZXknKSxcclxuICAgICAgICAgICd1dGY4J1xyXG4gICAgICAgICk7XHJcblxyXG4gICAgICAgIC8vIEdldCB0aGUgU1NMIGNlcnRpZmljYXRlXHJcbiAgICAgICAgY2VydCA9IHJlYWRGaWxlU3luYyhcclxuICAgICAgICAgIGpvaW4oZ2V0QWJzb2x1dGVQYXRoKHNlcnZlck9wdGlvbnMuc3NsLmNlcnRQYXRoKSwgJ3NlcnZlci5jcnQnKSxcclxuICAgICAgICAgICd1dGY4J1xyXG4gICAgICAgICk7XHJcbiAgICAgIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICAgICAgbG9nKFxyXG4gICAgICAgICAgMixcclxuICAgICAgICAgIGBbc2VydmVyXSBVbmFibGUgdG8gbG9hZCBrZXkvY2VydGlmaWNhdGUgZnJvbSB0aGUgJyR7c2VydmVyT3B0aW9ucy5zc2wuY2VydFBhdGh9JyBwYXRoLiBDb3VsZCBub3QgcnVuIHNlY3VyZWQgbGF5ZXIgc2VydmVyLmBcclxuICAgICAgICApO1xyXG4gICAgICB9XHJcblxyXG4gICAgICBpZiAoa2V5ICYmIGNlcnQpIHtcclxuICAgICAgICAvLyBNYWluIHNlcnZlciBpbnN0YW5jZSAoSFRUUFMpXHJcbiAgICAgICAgY29uc3QgaHR0cHNTZXJ2ZXIgPSBodHRwcy5jcmVhdGVTZXJ2ZXIoeyBrZXksIGNlcnQgfSwgYXBwKTtcclxuXHJcbiAgICAgICAgLy8gQXR0YWNoIGVycm9yIGhhbmRsZXJzIGFuZCBsaXN0ZW4gdG8gdGhlIHNlcnZlclxyXG4gICAgICAgIF9hdHRhY2hTZXJ2ZXJFcnJvckhhbmRsZXJzKGh0dHBzU2VydmVyKTtcclxuXHJcbiAgICAgICAgLy8gTGlzdGVuXHJcbiAgICAgICAgaHR0cHNTZXJ2ZXIubGlzdGVuKHNlcnZlck9wdGlvbnMuc3NsLnBvcnQsIHNlcnZlck9wdGlvbnMuaG9zdCwgKCkgPT4ge1xyXG4gICAgICAgICAgLy8gU2F2ZSB0aGUgcmVmZXJlbmNlIHRvIEhUVFBTIHNlcnZlclxyXG4gICAgICAgICAgYWN0aXZlU2VydmVycy5zZXQoc2VydmVyT3B0aW9ucy5zc2wucG9ydCwgaHR0cHNTZXJ2ZXIpO1xyXG5cclxuICAgICAgICAgIGxvZyhcclxuICAgICAgICAgICAgMyxcclxuICAgICAgICAgICAgYFtzZXJ2ZXJdIFN0YXJ0ZWQgSFRUUFMgc2VydmVyIG9uICR7c2VydmVyT3B0aW9ucy5ob3N0fToke3NlcnZlck9wdGlvbnMuc3NsLnBvcnR9LmBcclxuICAgICAgICAgICk7XHJcbiAgICAgICAgfSk7XHJcbiAgICAgIH1cclxuICAgIH1cclxuXHJcbiAgICAvLyBTZXQgdXAgdGhlIHJhdGUgbGltaXRlclxyXG4gICAgcmF0ZUxpbWl0aW5nTWlkZGxld2FyZShhcHAsIHNlcnZlck9wdGlvbnMucmF0ZUxpbWl0aW5nKTtcclxuXHJcbiAgICAvLyBTZXQgdXAgdGhlIHZhbGlkYXRpb24gaGFuZGxlclxyXG4gICAgdmFsaWRhdGlvbk1pZGRsZXdhcmUoYXBwKTtcclxuXHJcbiAgICAvLyBTZXQgdXAgcm91dGVzXHJcbiAgICBleHBvcnRSb3V0ZXMoYXBwKTtcclxuICAgIGhlYWx0aFJvdXRlcyhhcHApO1xyXG4gICAgdWlSb3V0ZXMoYXBwKTtcclxuICAgIHZlcnNpb25DaGFuZ2VSb3V0ZXMoYXBwKTtcclxuXHJcbiAgICAvLyBTZXQgdXAgdGhlIGNlbnRyYWxpemVkIGVycm9yIGhhbmRsZXJcclxuICAgIGVycm9yTWlkZGxld2FyZShhcHApO1xyXG4gIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoXHJcbiAgICAgICdbc2VydmVyXSBDb3VsZCBub3QgY29uZmlndXJlIGFuZCBzdGFydCB0aGUgc2VydmVyLicsXHJcbiAgICAgIDUwMFxyXG4gICAgKS5zZXRFcnJvcihlcnJvcik7XHJcbiAgfVxyXG59XHJcblxyXG4vKipcclxuICogQ2xvc2VzIGFsbCBzZXJ2ZXJzIGFzc29jaWF0ZWQgd2l0aCBFeHByZXNzIGFwcCBpbnN0YW5jZS5cclxuICpcclxuICogQGZ1bmN0aW9uIGNsb3NlU2VydmVyc1xyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIGNsb3NlU2VydmVycygpIHtcclxuICAvLyBDaGVjayBpZiB0aGVyZSBhcmUgc2VydmVycyB3b3JraW5nXHJcbiAgaWYgKGFjdGl2ZVNlcnZlcnMuc2l6ZSA+IDApIHtcclxuICAgIGxvZyg0LCBgW3NlcnZlcl0gQ2xvc2luZyBhbGwgc2VydmVycy5gKTtcclxuXHJcbiAgICAvLyBDbG9zZSBlYWNoIG9uZSBvZiBzZXJ2ZXJzXHJcbiAgICBmb3IgKGNvbnN0IFtwb3J0LCBzZXJ2ZXJdIG9mIGFjdGl2ZVNlcnZlcnMpIHtcclxuICAgICAgc2VydmVyLmNsb3NlKCgpID0+IHtcclxuICAgICAgICBhY3RpdmVTZXJ2ZXJzLmRlbGV0ZShwb3J0KTtcclxuICAgICAgICBsb2coNCwgYFtzZXJ2ZXJdIENsb3NlZCBzZXJ2ZXIgb24gcG9ydDogJHtwb3J0fS5gKTtcclxuICAgICAgfSk7XHJcbiAgICB9XHJcbiAgfVxyXG59XHJcblxyXG4vKipcclxuICogR2V0IGFsbCBzZXJ2ZXJzIGFzc29jaWF0ZWQgd2l0aCBFeHByZXNzIGFwcCBpbnN0YW5jZS5cclxuICpcclxuICogQGZ1bmN0aW9uIGdldFNlcnZlcnNcclxuICpcclxuICogQHJldHVybnMge0FycmF5PE9iamVjdD59IFNlcnZlcnMgYXNzb2NpYXRlZCB3aXRoIEV4cHJlc3MgYXBwIGluc3RhbmNlLlxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIGdldFNlcnZlcnMoKSB7XHJcbiAgcmV0dXJuIGFjdGl2ZVNlcnZlcnM7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBHZXQgdGhlIEV4cHJlc3MgaW5zdGFuY2UuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBnZXRFeHByZXNzXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtFeHByZXNzfSBUaGUgRXhwcmVzcyBpbnN0YW5jZS5cclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiBnZXRFeHByZXNzKCkge1xyXG4gIHJldHVybiBleHByZXNzO1xyXG59XHJcblxyXG4vKipcclxuICogR2V0IHRoZSBFeHByZXNzIGFwcCBpbnN0YW5jZS5cclxuICpcclxuICogQGZ1bmN0aW9uIGdldEFwcFxyXG4gKlxyXG4gKiBAcmV0dXJucyB7RXhwcmVzc30gVGhlIEV4cHJlc3MgYXBwIGluc3RhbmNlLlxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIGdldEFwcCgpIHtcclxuICByZXR1cm4gYXBwO1xyXG59XHJcblxyXG4vKipcclxuICogRW5hYmxlIHJhdGUgbGltaXRpbmcgZm9yIHRoZSBzZXJ2ZXIuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBlbmFibGVSYXRlTGltaXRpbmdcclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IHJhdGVMaW1pdGluZ09wdGlvbnMgLSBUaGUgY29uZmlndXJhdGlvbiBvYmplY3QgY29udGFpbmluZ1xyXG4gKiBgcmF0ZUxpbWl0aW5nYCBvcHRpb25zLiBUaGlzIG9iamVjdCBtYXkgaW5jbHVkZSBhIHBhcnRpYWwgb3IgY29tcGxldGUgc2V0XHJcbiAqIG9mIHRoZSBgcmF0ZUxpbWl0aW5nYCBvcHRpb25zLiBJZiB0aGUgb3B0aW9ucyBhcmUgcGFydGlhbCwgbWlzc2luZyB2YWx1ZXNcclxuICogd2lsbCBkZWZhdWx0IHRvIHRoZSBjdXJyZW50IGdsb2JhbCBjb25maWd1cmF0aW9uLlxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIGVuYWJsZVJhdGVMaW1pdGluZyhyYXRlTGltaXRpbmdPcHRpb25zKSB7XHJcbiAgLy8gVXBkYXRlIHRoZSBpbnN0YW5jZSBvcHRpb25zIG9iamVjdFxyXG4gIGNvbnN0IG9wdGlvbnMgPSB1cGRhdGVPcHRpb25zKHtcclxuICAgIHNlcnZlcjoge1xyXG4gICAgICByYXRlTGltaXRpbmc6IHJhdGVMaW1pdGluZ09wdGlvbnNcclxuICAgIH1cclxuICB9KTtcclxuXHJcbiAgLy8gU2V0IHRoZSByYXRlIGxpbWl0aW5nIG9wdGlvbnNcclxuICByYXRlTGltaXRpbmdNaWRkbGV3YXJlKGFwcCwgb3B0aW9ucy5zZXJ2ZXIucmF0ZUxpbWl0aW5nT3B0aW9ucyk7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBBcHBseSBtaWRkbGV3YXJlKHMpIHRvIGEgc3BlY2lmaWMgcGF0aC5cclxuICpcclxuICogQGZ1bmN0aW9uIHVzZVxyXG4gKlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gcGF0aCAtIFRoZSBwYXRoIHRvIHdoaWNoIHRoZSBtaWRkbGV3YXJlKHMpIHNob3VsZCBiZSBhcHBsaWVkLlxyXG4gKiBAcGFyYW0gey4uLkZ1bmN0aW9ufSBtaWRkbGV3YXJlcyAtIFRoZSBtaWRkbGV3YXJlIGZ1bmN0aW9uKHMpIHRvIGJlIGFwcGxpZWQuXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gdXNlKHBhdGgsIC4uLm1pZGRsZXdhcmVzKSB7XHJcbiAgYXBwLnVzZShwYXRoLCAuLi5taWRkbGV3YXJlcyk7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBTZXQgdXAgYSByb3V0ZSB3aXRoIEdFVCBtZXRob2QgYW5kIGFwcGx5IG1pZGRsZXdhcmUocykuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBnZXRcclxuICpcclxuICogQHBhcmFtIHtzdHJpbmd9IHBhdGggLSBUaGUgcGF0aCB0byB3aGljaCB0aGUgbWlkZGxld2FyZShzKSBzaG91bGQgYmUgYXBwbGllZC5cclxuICogQHBhcmFtIHsuLi5GdW5jdGlvbn0gbWlkZGxld2FyZXMgLSBUaGUgbWlkZGxld2FyZSBmdW5jdGlvbihzKSB0byBiZSBhcHBsaWVkLlxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIGdldChwYXRoLCAuLi5taWRkbGV3YXJlcykge1xyXG4gIGFwcC5nZXQocGF0aCwgLi4ubWlkZGxld2FyZXMpO1xyXG59XHJcblxyXG4vKipcclxuICogU2V0IHVwIGEgcm91dGUgd2l0aCBQT1NUIG1ldGhvZCBhbmQgYXBwbHkgbWlkZGxld2FyZShzKS5cclxuICpcclxuICogQGZ1bmN0aW9uIHBvc3RcclxuICpcclxuICogQHBhcmFtIHtzdHJpbmd9IHBhdGggLSBUaGUgcGF0aCB0byB3aGljaCB0aGUgbWlkZGxld2FyZShzKSBzaG91bGQgYmUgYXBwbGllZC5cclxuICogQHBhcmFtIHsuLi5GdW5jdGlvbn0gbWlkZGxld2FyZXMgLSBUaGUgbWlkZGxld2FyZSBmdW5jdGlvbihzKSB0byBiZSBhcHBsaWVkLlxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIHBvc3QocGF0aCwgLi4ubWlkZGxld2FyZXMpIHtcclxuICBhcHAucG9zdChwYXRoLCAuLi5taWRkbGV3YXJlcyk7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBBdHRhY2ggZXJyb3IgaGFuZGxlcnMgdG8gdGhlIHNlcnZlci5cclxuICpcclxuICogQGZ1bmN0aW9uIF9hdHRhY2hTZXJ2ZXJFcnJvckhhbmRsZXJzXHJcbiAqXHJcbiAqIEBwYXJhbSB7KGh0dHAuU2VydmVyfGh0dHBzLlNlcnZlcil9IHNlcnZlciAtIFRoZSBIVFRQL0hUVFBTIHNlcnZlciBpbnN0YW5jZS5cclxuICovXHJcbmZ1bmN0aW9uIF9hdHRhY2hTZXJ2ZXJFcnJvckhhbmRsZXJzKHNlcnZlcikge1xyXG4gIHNlcnZlci5vbignY2xpZW50RXJyb3InLCAoZXJyb3IsIHNvY2tldCkgPT4ge1xyXG4gICAgbG9nV2l0aFN0YWNrKFxyXG4gICAgICAxLFxyXG4gICAgICBlcnJvcixcclxuICAgICAgYFtzZXJ2ZXJdIENsaWVudCBlcnJvcjogJHtlcnJvci5tZXNzYWdlfSwgZGVzdHJveWluZyBzb2NrZXQuYFxyXG4gICAgKTtcclxuICAgIHNvY2tldC5kZXN0cm95KCk7XHJcbiAgfSk7XHJcblxyXG4gIHNlcnZlci5vbignZXJyb3InLCAoZXJyb3IpID0+IHtcclxuICAgIGxvZ1dpdGhTdGFjaygxLCBlcnJvciwgYFtzZXJ2ZXJdIFNlcnZlciBlcnJvcjogJHtlcnJvci5tZXNzYWdlfWApO1xyXG4gIH0pO1xyXG5cclxuICBzZXJ2ZXIub24oJ2Nvbm5lY3Rpb24nLCAoc29ja2V0KSA9PiB7XHJcbiAgICBzb2NrZXQub24oJ2Vycm9yJywgKGVycm9yKSA9PiB7XHJcbiAgICAgIGxvZ1dpdGhTdGFjaygxLCBlcnJvciwgYFtzZXJ2ZXJdIFNvY2tldCBlcnJvcjogJHtlcnJvci5tZXNzYWdlfWApO1xyXG4gICAgfSk7XHJcbiAgfSk7XHJcbn1cclxuXHJcbmV4cG9ydCBkZWZhdWx0IHtcclxuICBzdGFydFNlcnZlcixcclxuICBjbG9zZVNlcnZlcnMsXHJcbiAgZ2V0U2VydmVycyxcclxuICBnZXRFeHByZXNzLFxyXG4gIGdldEFwcCxcclxuICBlbmFibGVSYXRlTGltaXRpbmcsXHJcbiAgdXNlLFxyXG4gIGdldCxcclxuICBwb3N0XHJcbn07XHJcbiIsIi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXHJcblxyXG5IaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXJcclxuXHJcbkNvcHlyaWdodCAoYykgMjAxNi0yMDI1LCBIaWdoc29mdFxyXG5cclxuTGljZW5jZWQgdW5kZXIgdGhlIE1JVCBsaWNlbmNlLlxyXG5cclxuQWRkaXRpb25hbGx5IGEgdmFsaWQgSGlnaGNoYXJ0cyBsaWNlbnNlIGlzIHJlcXVpcmVkIGZvciB1c2UuXHJcblxyXG5TZWUgTElDRU5TRSBmaWxlIGluIHJvb3QgZm9yIGRldGFpbHMuXHJcblxyXG4qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xyXG5cclxuLyoqXHJcbiAqIEBvdmVydmlldyBIYW5kbGVzIGdyYWNlZnVsIHNodXRkb3duIG9mIHRoZSBIaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXIsIGVuc3VyaW5nXHJcbiAqIHByb3BlciBjbGVhbnVwIG9mIHJlc291cmNlcyBzdWNoIGFzIGJyb3dzZXIsIHBhZ2VzLCBzZXJ2ZXJzLCBhbmQgdGltZXJzLlxyXG4gKi9cclxuXHJcbmltcG9ydCB7IGtpbGxQb29sIH0gZnJvbSAnLi9wb29sLmpzJztcclxuaW1wb3J0IHsgY2xlYXJBbGxUaW1lcnMgfSBmcm9tICcuL3RpbWVyLmpzJztcclxuXHJcbmltcG9ydCB7IGNsb3NlU2VydmVycyB9IGZyb20gJy4vc2VydmVyL3NlcnZlci5qcyc7XHJcblxyXG4vKipcclxuICogUGVyZm9ybXMgY2xlYW51cCBvcGVyYXRpb25zIHRvIGVuc3VyZSBhIGdyYWNlZnVsIHNodXRkb3duIG9mIHRoZSBwcm9jZXNzLlxyXG4gKiBUaGlzIGluY2x1ZGVzIGNsZWFyaW5nIGFsbCByZWdpc3RlcmVkIHRpbWVvdXRzL2ludGVydmFscywgY2xvc2luZyBhY3RpdmVcclxuICogc2VydmVycywgdGVybWluYXRpbmcgcmVzb3VyY2VzIChwYWdlcykgb2YgdGhlIHBvb2wsIHBvb2wgaXRzZWxmLCBhbmQgY2xvc2luZ1xyXG4gKiB0aGUgYnJvd3Nlci5cclxuICpcclxuICogQGZ1bmN0aW9uIHNodXRkb3duQ2xlYW5VcFxyXG4gKlxyXG4gKiBAcGFyYW0ge251bWJlcn0gW2V4aXRDb2RlPTBdIC0gVGhlIGV4aXQgY29kZSB0byB1c2Ugd2l0aCBgcHJvY2Vzcy5leGl0KClgLlxyXG4gKiBUaGUgZGVmYXVsdCB2YWx1ZSBpcyBgMGAuXHJcbiAqL1xyXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gc2h1dGRvd25DbGVhblVwKGV4aXRDb2RlID0gMCkge1xyXG4gIC8vIEF3YWl0IGZyZWVpbmcgYWxsIHJlc291cmNlc1xyXG4gIGF3YWl0IFByb21pc2UuYWxsU2V0dGxlZChbXHJcbiAgICAvLyBDbGVhciBhbGwgb25nb2luZyBpbnRlcnZhbHNcclxuICAgIGNsZWFyQWxsVGltZXJzKCksXHJcblxyXG4gICAgLy8gR2V0IGF2YWlsYWJsZSBzZXJ2ZXIgaW5zdGFuY2VzIChIVFRQL0hUVFBTKSBhbmQgY2xvc2UgdGhlbVxyXG4gICAgY2xvc2VTZXJ2ZXJzKCksXHJcblxyXG4gICAgLy8gQ2xvc2UgYW4gYWN0aXZlIHBvb2wgYWxvbmcgd2l0aCBpdHMgd29ya2VycyBhbmQgdGhlIGJyb3dzZXIgaW5zdGFuY2VcclxuICAgIGtpbGxQb29sKClcclxuICBdKTtcclxuXHJcbiAgLy8gRXhpdCBwcm9jZXNzIHdpdGggYSBjb3JyZWN0IGNvZGVcclxuICBwcm9jZXNzLmV4aXQoZXhpdENvZGUpO1xyXG59XHJcblxyXG5leHBvcnQgZGVmYXVsdCB7XHJcbiAgc2h1dGRvd25DbGVhblVwXHJcbn07XHJcbiIsIi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXHJcblxyXG5IaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXJcclxuXHJcbkNvcHlyaWdodCAoYykgMjAxNi0yMDI1LCBIaWdoc29mdFxyXG5cclxuTGljZW5jZWQgdW5kZXIgdGhlIE1JVCBsaWNlbmNlLlxyXG5cclxuQWRkaXRpb25hbGx5IGEgdmFsaWQgSGlnaGNoYXJ0cyBsaWNlbnNlIGlzIHJlcXVpcmVkIGZvciB1c2UuXHJcblxyXG5TZWUgTElDRU5TRSBmaWxlIGluIHJvb3QgZm9yIGRldGFpbHMuXHJcblxyXG4qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xyXG5cclxuLyoqXHJcbiAqIEBvdmVydmlldyBUaGlzIGNvcmUgbW9kdWxlIGluaXRpYWxpemVzIGFuZCBtYW5hZ2VzIHRoZSBIaWdoY2hhcnRzIEV4cG9ydFxyXG4gKiBTZXJ2ZXIuIFRoZSBtYWluIGBpbml0RXhwb3J0YCBmdW5jdGlvbiBoYW5kbGVzIGxvZ2dpbmcsIHNjcmlwdCBjYWNoaW5nLFxyXG4gKiByZXNvdXJjZSBwb29saW5nLCBicm93c2VyIHN0YXJ0dXAsIGFuZCBlbnN1cmVzIGdyYWNlZnVsIHByb2Nlc3MgY2xlYW51cFxyXG4gKiBvbiBleGl0LiBBZGRpdGlvbmFsbHksIGl0IHByb3ZpZGVzIEFQSSBmdW5jdGlvbnMgZm9yIHVzaW5nIGl0IGFzIGEgTm9kZS5qc1xyXG4gKiBtb2R1bGUsIG9mZmVyaW5nIGZ1bmN0aW9uYWxpdGllcyBmb3IgcHJvY2Vzc2luZyBvcHRpb25zLCBjb25maWd1cmluZ1xyXG4gKiBhbmQgcGVyZm9ybWluZyBleHBvcnRzLCBhbmQgc2V0dGluZyB1cCBzZXJ2ZXIuXHJcbiAqL1xyXG5cclxuaW1wb3J0ICdjb2xvcnMnO1xyXG5cclxuaW1wb3J0IHsgY2hlY2tDYWNoZSB9IGZyb20gJy4vY2FjaGUuanMnO1xyXG5pbXBvcnQge1xyXG4gIGJhdGNoRXhwb3J0LFxyXG4gIHNpbmdsZUV4cG9ydCxcclxuICBzdGFydEV4cG9ydCxcclxuICBzZXRBbGxvd0NvZGVFeGVjdXRpb25cclxufSBmcm9tICcuL2NoYXJ0LmpzJztcclxuaW1wb3J0IHtcclxuICBnZXRPcHRpb25zLFxyXG4gIHVwZGF0ZU9wdGlvbnMsXHJcbiAgbWFwVG9OZXdPcHRpb25zLFxyXG4gIHZhbGlkYXRlT3B0aW9uLFxyXG4gIHZhbGlkYXRlT3B0aW9uc1xyXG59IGZyb20gJy4vY29uZmlnLmpzJztcclxuaW1wb3J0IHtcclxuICBsb2csXHJcbiAgbG9nV2l0aFN0YWNrLFxyXG4gIGxvZ1pvZElzc3VlcyxcclxuICBpbml0TG9nZ2luZyxcclxuICBlbmFibGVDb25zb2xlTG9nZ2luZyxcclxuICBlbmFibGVGaWxlTG9nZ2luZyxcclxuICBzZXRMb2dMZXZlbFxyXG59IGZyb20gJy4vbG9nZ2VyLmpzJztcclxuaW1wb3J0IHsgaW5pdFBvb2wsIGtpbGxQb29sIH0gZnJvbSAnLi9wb29sLmpzJztcclxuaW1wb3J0IHsgc2h1dGRvd25DbGVhblVwIH0gZnJvbSAnLi9yZXNvdXJjZVJlbGVhc2UuanMnO1xyXG5cclxuaW1wb3J0IHNlcnZlciBmcm9tICcuL3NlcnZlci9zZXJ2ZXIuanMnO1xyXG5cclxuLyoqXHJcbiAqIEluaXRpYWxpemVzIHRoZSBleHBvcnQgcHJvY2Vzcy4gVGFza3Mgc3VjaCBhcyBjb25maWd1cmluZyBsb2dnaW5nLCBjaGVja2luZ1xyXG4gKiB0aGUgY2FjaGUgYW5kIHNvdXJjZXMsIGFuZCBpbml0aWFsaXppbmcgdGhlIHJlc291cmNlIHBvb2wgb2NjdXIgZHVyaW5nIHRoaXNcclxuICogc3RhZ2UuXHJcbiAqXHJcbiAqIFRoaXMgZnVuY3Rpb24gbXVzdCBiZSBjYWxsZWQgYmVmb3JlIGF0dGVtcHRpbmcgdG8gZXhwb3J0IGNoYXJ0cyBvciBzZXRcclxuICogdXAgYSBzZXJ2ZXIuXHJcbiAqXHJcbiAqIEBhc3luY1xyXG4gKiBAZnVuY3Rpb24gaW5pdEV4cG9ydFxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gW2luaXRPcHRpb25zPXt9XSAtIFRoZSBgaW5pdE9wdGlvbnNgIG9iamVjdCwgd2hpY2ggbWF5XHJcbiAqIGJlIGEgcGFydGlhbCBvciBjb21wbGV0ZSBzZXQgb2Ygb3B0aW9ucy4gSWYgdGhlIG9wdGlvbnMgYXJlIHBhcnRpYWwsIG1pc3NpbmdcclxuICogdmFsdWVzIHdpbGwgZGVmYXVsdCB0byB0aGUgY3VycmVudCBnbG9iYWwgY29uZmlndXJhdGlvbi4gVGhlIGRlZmF1bHQgdmFsdWVcclxuICogaXMgYW4gZW1wdHkgb2JqZWN0LlxyXG4gKi9cclxuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIGluaXRFeHBvcnQoaW5pdE9wdGlvbnMgPSB7fSkge1xyXG4gIC8vIEluaXQsIHZhbGlkYXRlIGFuZCB1cGRhdGUgdGhlIG9wdGlvbnMgb2JqZWN0XHJcbiAgY29uc3Qgb3B0aW9ucyA9IHVwZGF0ZU9wdGlvbnMoaW5pdE9wdGlvbnMpO1xyXG5cclxuICAvLyBTZXQgdGhlIGBhbGxvd0NvZGVFeGVjdXRpb25gIHBlciBleHBvcnQgbW9kdWxlIHNjb3BlXHJcbiAgc2V0QWxsb3dDb2RlRXhlY3V0aW9uKG9wdGlvbnMuY3VzdG9tTG9naWMuYWxsb3dDb2RlRXhlY3V0aW9uKTtcclxuXHJcbiAgLy8gSW5pdCB0aGUgbG9nZ2luZ1xyXG4gIGluaXRMb2dnaW5nKG9wdGlvbnMubG9nZ2luZyk7XHJcblxyXG4gIC8vIEF0dGFjaCBwcm9jZXNzJyBleGl0IGxpc3RlbmVyc1xyXG4gIGlmIChvcHRpb25zLm90aGVyLmxpc3RlblRvUHJvY2Vzc0V4aXRzKSB7XHJcbiAgICBfYXR0YWNoUHJvY2Vzc0V4aXRMaXN0ZW5lcnMoKTtcclxuICB9XHJcblxyXG4gIC8vIENoZWNrIHRoZSBjdXJyZW50IHN0YXR1cyBvZiBjYWNoZVxyXG4gIGF3YWl0IGNoZWNrQ2FjaGUob3B0aW9ucy5oaWdoY2hhcnRzLCBvcHRpb25zLnNlcnZlci5wcm94eSk7XHJcblxyXG4gIC8vIEluaXQgdGhlIHBvb2xcclxuICBhd2FpdCBpbml0UG9vbChvcHRpb25zLnBvb2wsIG9wdGlvbnMucHVwcGV0ZWVyLmFyZ3MpO1xyXG59XHJcblxyXG4vKipcclxuICogQXR0YWNoZXMgZXhpdCBsaXN0ZW5lcnMgdG8gdGhlIHByb2Nlc3MsIGVuc3VyaW5nIHByb3BlciBjbGVhbnVwIG9mIHJlc291cmNlc1xyXG4gKiBhbmQgdGVybWluYXRpb24gb24gZXhpdCBzaWduYWxzLiBIYW5kbGVzICdleGl0JywgJ1NJR0lOVCcsICdTSUdURVJNJyxcclxuICogYW5kICd1bmNhdWdodEV4Y2VwdGlvbicgZXZlbnRzLlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gX2F0dGFjaFByb2Nlc3NFeGl0TGlzdGVuZXJzXHJcbiAqL1xyXG5mdW5jdGlvbiBfYXR0YWNoUHJvY2Vzc0V4aXRMaXN0ZW5lcnMoKSB7XHJcbiAgbG9nKDMsICdbcHJvY2Vzc10gQXR0YWNoaW5nIGV4aXQgbGlzdGVuZXJzIHRvIHRoZSBwcm9jZXNzLicpO1xyXG5cclxuICAvLyBIYW5kbGVyIGZvciB0aGUgJ2V4aXQnXHJcbiAgcHJvY2Vzcy5vbignZXhpdCcsIChjb2RlKSA9PiB7XHJcbiAgICBsb2coNCwgYFtwcm9jZXNzXSBQcm9jZXNzIGV4aXRlZCB3aXRoIGNvZGU6ICR7Y29kZX0uYCk7XHJcbiAgfSk7XHJcblxyXG4gIC8vIEhhbmRsZXIgZm9yIHRoZSAnU0lHSU5UJ1xyXG4gIHByb2Nlc3Mub24oJ1NJR0lOVCcsIGFzeW5jIChuYW1lLCBjb2RlKSA9PiB7XHJcbiAgICBsb2coNCwgYFtwcm9jZXNzXSBUaGUgJHtuYW1lfSBldmVudCB3aXRoIGNvZGU6ICR7Y29kZX0uYCk7XHJcbiAgICBhd2FpdCBzaHV0ZG93bkNsZWFuVXAoKTtcclxuICB9KTtcclxuXHJcbiAgLy8gSGFuZGxlciBmb3IgdGhlICdTSUdURVJNJ1xyXG4gIHByb2Nlc3Mub24oJ1NJR1RFUk0nLCBhc3luYyAobmFtZSwgY29kZSkgPT4ge1xyXG4gICAgbG9nKDQsIGBbcHJvY2Vzc10gVGhlICR7bmFtZX0gZXZlbnQgd2l0aCBjb2RlOiAke2NvZGV9LmApO1xyXG4gICAgYXdhaXQgc2h1dGRvd25DbGVhblVwKCk7XHJcbiAgfSk7XHJcblxyXG4gIC8vIEhhbmRsZXIgZm9yIHRoZSAnU0lHSFVQJ1xyXG4gIHByb2Nlc3Mub24oJ1NJR0hVUCcsIGFzeW5jIChuYW1lLCBjb2RlKSA9PiB7XHJcbiAgICBsb2coNCwgYFtwcm9jZXNzXSBUaGUgJHtuYW1lfSBldmVudCB3aXRoIGNvZGU6ICR7Y29kZX0uYCk7XHJcbiAgICBhd2FpdCBzaHV0ZG93bkNsZWFuVXAoKTtcclxuICB9KTtcclxuXHJcbiAgLy8gSGFuZGxlciBmb3IgdGhlICd1bmNhdWdodEV4Y2VwdGlvbidcclxuICBwcm9jZXNzLm9uKCd1bmNhdWdodEV4Y2VwdGlvbicsIGFzeW5jIChlcnJvciwgbmFtZSkgPT4ge1xyXG4gICAgbG9nV2l0aFN0YWNrKDEsIGVycm9yLCBgW3Byb2Nlc3NdIFRoZSAke25hbWV9IGVycm9yLmApO1xyXG4gICAgYXdhaXQgc2h1dGRvd25DbGVhblVwKDEpO1xyXG4gIH0pO1xyXG59XHJcblxyXG5leHBvcnQgZGVmYXVsdCB7XHJcbiAgLy8gU2VydmVyXHJcbiAgLi4uc2VydmVyLFxyXG5cclxuICAvLyBPcHRpb25zXHJcbiAgZ2V0T3B0aW9ucyxcclxuICB1cGRhdGVPcHRpb25zLFxyXG4gIG1hcFRvTmV3T3B0aW9ucyxcclxuXHJcbiAgLy8gVmFsaWRhdGlvblxyXG4gIHZhbGlkYXRlT3B0aW9uLFxyXG4gIHZhbGlkYXRlT3B0aW9ucyxcclxuXHJcbiAgLy8gRXhwb3J0aW5nXHJcbiAgaW5pdEV4cG9ydCxcclxuICBzaW5nbGVFeHBvcnQsXHJcbiAgYmF0Y2hFeHBvcnQsXHJcbiAgc3RhcnRFeHBvcnQsXHJcblxyXG4gIC8vIFJlbGVhc2VcclxuICBraWxsUG9vbCxcclxuICBzaHV0ZG93bkNsZWFuVXAsXHJcblxyXG4gIC8vIExvZ3NcclxuICBsb2csXHJcbiAgbG9nV2l0aFN0YWNrLFxyXG4gIGxvZ1pvZElzc3VlcyxcclxuICBzZXRMb2dMZXZlbDogZnVuY3Rpb24gKGxldmVsKSB7XHJcbiAgICAvLyBVcGRhdGUgdGhlIGluc3RhbmNlIG9wdGlvbnMgb2JqZWN0XHJcbiAgICBjb25zdCBvcHRpb25zID0gdXBkYXRlT3B0aW9ucyh7XHJcbiAgICAgIGxvZ2dpbmc6IHtcclxuICAgICAgICBsZXZlbFxyXG4gICAgICB9XHJcbiAgICB9KTtcclxuXHJcbiAgICAvLyBDYWxsIHRoZSBmdW5jdGlvblxyXG4gICAgc2V0TG9nTGV2ZWwob3B0aW9ucy5sb2dnaW5nLmxldmVsKTtcclxuICB9LFxyXG4gIGVuYWJsZUNvbnNvbGVMb2dnaW5nOiBmdW5jdGlvbiAodG9Db25zb2xlKSB7XHJcbiAgICAvLyBVcGRhdGUgdGhlIGluc3RhbmNlIG9wdGlvbnMgb2JqZWN0XHJcbiAgICBjb25zdCBvcHRpb25zID0gdXBkYXRlT3B0aW9ucyh7XHJcbiAgICAgIGxvZ2dpbmc6IHtcclxuICAgICAgICB0b0NvbnNvbGVcclxuICAgICAgfVxyXG4gICAgfSk7XHJcblxyXG4gICAgLy8gQ2FsbCB0aGUgZnVuY3Rpb25cclxuICAgIGVuYWJsZUNvbnNvbGVMb2dnaW5nKG9wdGlvbnMubG9nZ2luZy50b0NvbnNvbGUpO1xyXG4gIH0sXHJcbiAgZW5hYmxlRmlsZUxvZ2dpbmc6IGZ1bmN0aW9uIChkZXN0LCBmaWxlLCB0b0ZpbGUpIHtcclxuICAgIC8vIFVwZGF0ZSB0aGUgaW5zdGFuY2Ugb3B0aW9ucyBvYmplY3RcclxuICAgIGNvbnN0IG9wdGlvbnMgPSB1cGRhdGVPcHRpb25zKHtcclxuICAgICAgbG9nZ2luZzoge1xyXG4gICAgICAgIGRlc3QsXHJcbiAgICAgICAgZmlsZSxcclxuICAgICAgICB0b0ZpbGVcclxuICAgICAgfVxyXG4gICAgfSk7XHJcblxyXG4gICAgLy8gQ2FsbCB0aGUgZnVuY3Rpb25cclxuICAgIGVuYWJsZUZpbGVMb2dnaW5nKFxyXG4gICAgICBvcHRpb25zLmxvZ2dpbmcuZGVzdCxcclxuICAgICAgb3B0aW9ucy5sb2dnaW5nLmZpbGUsXHJcbiAgICAgIG9wdGlvbnMubG9nZ2luZy50b0ZpbGVcclxuICAgICk7XHJcbiAgfVxyXG59O1xyXG4iXSwibmFtZXMiOlsiX19kaXJuYW1lIiwiZmlsZVVSTFRvUGF0aCIsIlVSTCIsImRvY3VtZW50IiwicmVxdWlyZSIsInBhdGhUb0ZpbGVVUkwiLCJfX2ZpbGVuYW1lIiwiaHJlZiIsIl9kb2N1bWVudEN1cnJlbnRTY3JpcHQiLCJ0YWdOYW1lIiwidG9VcHBlckNhc2UiLCJzcmMiLCJiYXNlVVJJIiwiZGVlcENvcHkiLCJvYmpBcnIiLCJvYmpBcnJDb3B5IiwiQXJyYXkiLCJpc0FycmF5Iiwia2V5IiwiT2JqZWN0IiwicHJvdG90eXBlIiwiaGFzT3duUHJvcGVydHkiLCJjYWxsIiwiZ2V0QWJzb2x1dGVQYXRoIiwicGF0aCIsImlzQWJzb2x1dGUiLCJub3JtYWxpemUiLCJyZXNvbHZlIiwiZ2V0QmFzZTY0IiwiaW5wdXQiLCJ0eXBlIiwiQnVmZmVyIiwiZnJvbSIsInRvU3RyaW5nIiwiZ2V0TmV3RGF0ZSIsIkRhdGUiLCJzcGxpdCIsInRyaW0iLCJnZXROZXdEYXRlVGltZSIsImdldFRpbWUiLCJpc09iamVjdCIsIml0ZW0iLCJpc09iamVjdEVtcHR5Iiwia2V5cyIsImxlbmd0aCIsImlzUHJpdmF0ZVJhbmdlVXJsRm91bmQiLCJzb21lIiwicGF0dGVybiIsInRlc3QiLCJtZWFzdXJlVGltZSIsInN0YXJ0IiwicHJvY2VzcyIsImhydGltZSIsImJpZ2ludCIsIk51bWJlciIsInJvdW5kTnVtYmVyIiwidmFsdWUiLCJwcmVjaXNpb24iLCJtdWx0aXBsaWVyIiwiTWF0aCIsInBvdyIsInJvdW5kIiwiY29sb3JzIiwibG9nZ2luZyIsInRvQ29uc29sZSIsInRvRmlsZSIsInBhdGhDcmVhdGVkIiwicGF0aFRvTG9nIiwibGV2ZWxzRGVzYyIsInRpdGxlIiwiY29sb3IiLCJsb2ciLCJhcmdzIiwibmV3TGV2ZWwiLCJ0ZXh0cyIsImxldmVsIiwicHJlZml4IiwiX2xvZ1RvRmlsZSIsImNvbnNvbGUiLCJhcHBseSIsInVuZGVmaW5lZCIsImNvbmNhdCIsImxvZ1dpdGhTdGFjayIsImVycm9yIiwiY3VzdG9tTWVzc2FnZSIsIm1haW5NZXNzYWdlIiwibWVzc2FnZSIsInN0YWNrTWVzc2FnZSIsInN0YWNrIiwicHVzaCIsInNoaWZ0IiwibG9nWm9kSXNzdWVzIiwiaXNzdWVzIiwibWFwIiwiaXNzdWUiLCJqb2luIiwiaW5pdExvZ2dpbmciLCJsb2dnaW5nT3B0aW9ucyIsImRlc3QiLCJmaWxlIiwic2V0TG9nTGV2ZWwiLCJlbmFibGVDb25zb2xlTG9nZ2luZyIsImVuYWJsZUZpbGVMb2dnaW5nIiwiaXNJbnRlZ2VyIiwiZXhpc3RzU3luYyIsIm1rZGlyU3luYyIsImFwcGVuZEZpbGUiLCJkZWZhdWx0Q29uZmlnIiwicHVwcGV0ZWVyIiwidHlwZXMiLCJlbnZMaW5rIiwiY2xpTmFtZSIsImRlc2NyaXB0aW9uIiwicHJvbXB0T3B0aW9ucyIsInNlcGFyYXRvciIsImhpZ2hjaGFydHMiLCJ2ZXJzaW9uIiwiY2RuVXJsIiwiZm9yY2VGZXRjaCIsImNhY2hlUGF0aCIsImNvcmVTY3JpcHRzIiwiaW5zdHJ1Y3Rpb25zIiwibW9kdWxlU2NyaXB0cyIsImluZGljYXRvclNjcmlwdHMiLCJjdXN0b21TY3JpcHRzIiwiZXhwb3J0IiwiaW5maWxlIiwiaW5zdHIiLCJvcHRpb25zIiwic3ZnIiwiYmF0Y2giLCJvdXRmaWxlIiwiaGludCIsImNob2ljZXMiLCJjb25zdHIiLCJiNjQiLCJub0Rvd25sb2FkIiwiaGVpZ2h0Iiwid2lkdGgiLCJzY2FsZSIsImRlZmF1bHRIZWlnaHQiLCJkZWZhdWx0V2lkdGgiLCJkZWZhdWx0U2NhbGUiLCJtaW4iLCJtYXgiLCJnbG9iYWxPcHRpb25zIiwidGhlbWVPcHRpb25zIiwicmFzdGVyaXphdGlvblRpbWVvdXQiLCJjdXN0b21Mb2dpYyIsImFsbG93Q29kZUV4ZWN1dGlvbiIsImFsbG93RmlsZVJlc291cmNlcyIsImN1c3RvbUNvZGUiLCJjYWxsYmFjayIsInJlc291cmNlcyIsImxvYWRDb25maWciLCJsZWdhY3lOYW1lIiwiY3JlYXRlQ29uZmlnIiwic2VydmVyIiwiZW5hYmxlIiwiaG9zdCIsInBvcnQiLCJ1cGxvYWRMaW1pdCIsImJlbmNobWFya2luZyIsInByb3h5IiwidGltZW91dCIsInJhdGVMaW1pdGluZyIsIm1heFJlcXVlc3RzIiwid2luZG93IiwiZGVsYXkiLCJ0cnVzdFByb3h5Iiwic2tpcEtleSIsInNraXBUb2tlbiIsInNzbCIsImZvcmNlIiwiY2VydFBhdGgiLCJwb29sIiwibWluV29ya2VycyIsIm1heFdvcmtlcnMiLCJ3b3JrTGltaXQiLCJhY3F1aXJlVGltZW91dCIsImNyZWF0ZVRpbWVvdXQiLCJkZXN0cm95VGltZW91dCIsImlkbGVUaW1lb3V0IiwiY3JlYXRlUmV0cnlJbnRlcnZhbCIsInJlYXBlckludGVydmFsIiwidWkiLCJyb3V0ZSIsIm90aGVyIiwibm9kZUVudiIsImxpc3RlblRvUHJvY2Vzc0V4aXRzIiwibm9Mb2dvIiwiaGFyZFJlc2V0UGFnZSIsImJyb3dzZXJTaGVsbE1vZGUiLCJ2YWxpZGF0aW9uIiwiZGVidWciLCJoZWFkbGVzcyIsImRldnRvb2xzIiwibGlzdGVuVG9Db25zb2xlIiwiZHVtcGlvIiwic2xvd01vIiwiZGVidWdnaW5nUG9ydCIsImRvdGVudiIsImNvbmZpZyIsInoiLCJzZXRFcnJvck1hcCIsIl9jdXN0b21FcnJvck1hcCIsInYiLCJib29sZWFuIiwic3RyaWN0Q2hlY2siLCJ1bmlvbiIsImVudW0iLCJ0cmFuc2Zvcm0iLCJpbmNsdWRlcyIsIm51bGxhYmxlIiwic3RyaW5nIiwicmVmaW5lIiwicGFyYW1zIiwiZXJyb3JNZXNzYWdlIiwidmFsdWVzIiwic3RyaW5nQXJyYXkiLCJmaWx0ZXJDYWxsYmFjayIsImFycmF5U2NoZW1hIiwiYXJyYXkiLCJzdHJpbmdTY2hlbWEiLCJzdGFydHNXaXRoIiwic2xpY2UiLCJlbmRzV2l0aCIsInRyYW5zZm9ybUNhbGxiYWNrIiwiZmlsdGVyIiwicG9zaXRpdmVOdW0iLCJudW1iZXIiLCJwb3NpdGl2ZSIsImlzTmFOIiwibm9uTmVnYXRpdmVOdW0iLCJub25uZWdhdGl2ZSIsInByZWZpeGVzIiwiY2hhcnRDb25maWciLCJvYmplY3QiLCJwYXNzdGhyb3VnaCIsImFkZGl0aW9uYWxPcHRpb25zIiwidmFsaWRhdG9ycyIsImFkbWluVG9rZW4iLCJpbmRleE9mIiwiZ3RlIiwibHRlIiwidGhpcyIsIm9iamVjdFNjaGVtYSIsImpzIiwiY3NzIiwiZmlsZXMiLCJwYXJ0aWFsIiwic3RyaW5nU2NoZW1hMSIsInN0cmluZ1NjaGVtYTIiLCJlbmFibGVTZXJ2ZXIiLCJzZXJ2ZXJCZW5jaG1hcmtpbmciLCJwcm94eUhvc3QiLCJwcm94eVBvcnQiLCJwcm94eVRpbWVvdXQiLCJlbmFibGVSYXRlTGltaXRpbmciLCJlbmFibGVTc2wiLCJzc2xGb3JjZSIsInNzbFBvcnQiLCJzc2xDZXJ0UGF0aCIsInBvb2xCZW5jaG1hcmtpbmciLCJyZXNvdXJjZXNJbnRlcnZhbCIsImxvZ0xldmVsIiwiaW50IiwibG9nRmlsZSIsImxvZ0Rlc3QiLCJsb2dUb0NvbnNvbGUiLCJsb2dUb0ZpbGUiLCJlbmFibGVVaSIsInVpUm91dGUiLCJlbmFibGVEZWJ1ZyIsInJlcXVlc3RJZCIsInV1aWQiLCJQdXBwZXRlZXJTY2hlbWEiLCJIaWdoY2hhcnRzU2NoZW1hIiwiRXhwb3J0U2NoZW1hIiwiQ3VzdG9tTG9naWNTY2hlbWEiLCJQcm94eVNjaGVtYSIsIlJhdGVMaW1pdGluZ1NjaGVtYSIsIlNzbFNjaGVtYSIsIlNlcnZlclNjaGVtYSIsIm9wdGlvbmFsIiwiUG9vbFNjaGVtYSIsIkxvZ2dpbmdTY2hlbWEiLCJVaVNjaGVtYSIsIk90aGVyU2NoZW1hIiwiRGVidWdTY2hlbWEiLCJTdHJpY3RDb25maWdTY2hlbWEiLCJMb29zZUNvbmZpZ1NjaGVtYSIsIkVudlNjaGVtYSIsIlBVUFBFVEVFUl9BUkdTIiwiSElHSENIQVJUU19WRVJTSU9OIiwiSElHSENIQVJUU19DRE5fVVJMIiwiSElHSENIQVJUU19GT1JDRV9GRVRDSCIsIkhJR0hDSEFSVFNfQ0FDSEVfUEFUSCIsIkhJR0hDSEFSVFNfQURNSU5fVE9LRU4iLCJISUdIQ0hBUlRTX0NPUkVfU0NSSVBUUyIsIkhJR0hDSEFSVFNfTU9EVUxFX1NDUklQVFMiLCJISUdIQ0hBUlRTX0lORElDQVRPUl9TQ1JJUFRTIiwiSElHSENIQVJUU19DVVNUT01fU0NSSVBUUyIsIkVYUE9SVF9JTkZJTEUiLCJFWFBPUlRfSU5TVFIiLCJFWFBPUlRfT1BUSU9OUyIsIkVYUE9SVF9TVkciLCJFWFBPUlRfQkFUQ0giLCJFWFBPUlRfT1VURklMRSIsIkVYUE9SVF9UWVBFIiwiRVhQT1JUX0NPTlNUUiIsIkVYUE9SVF9CNjQiLCJFWFBPUlRfTk9fRE9XTkxPQUQiLCJFWFBPUlRfSEVJR0hUIiwiRVhQT1JUX1dJRFRIIiwiRVhQT1JUX1NDQUxFIiwiRVhQT1JUX0RFRkFVTFRfSEVJR0hUIiwiRVhQT1JUX0RFRkFVTFRfV0lEVEgiLCJFWFBPUlRfREVGQVVMVF9TQ0FMRSIsIkVYUE9SVF9HTE9CQUxfT1BUSU9OUyIsIkVYUE9SVF9USEVNRV9PUFRJT05TIiwiRVhQT1JUX1JBU1RFUklaQVRJT05fVElNRU9VVCIsIkNVU1RPTV9MT0dJQ19BTExPV19DT0RFX0VYRUNVVElPTiIsIkNVU1RPTV9MT0dJQ19BTExPV19GSUxFX1JFU09VUkNFUyIsIkNVU1RPTV9MT0dJQ19DVVNUT01fQ09ERSIsIkNVU1RPTV9MT0dJQ19DQUxMQkFDSyIsIkNVU1RPTV9MT0dJQ19SRVNPVVJDRVMiLCJDVVNUT01fTE9HSUNfTE9BRF9DT05GSUciLCJDVVNUT01fTE9HSUNfQ1JFQVRFX0NPTkZJRyIsIlNFUlZFUl9FTkFCTEUiLCJTRVJWRVJfSE9TVCIsIlNFUlZFUl9QT1JUIiwiU0VSVkVSX1VQTE9BRF9MSU1JVCIsIlNFUlZFUl9CRU5DSE1BUktJTkciLCJTRVJWRVJfUFJPWFlfSE9TVCIsIlNFUlZFUl9QUk9YWV9QT1JUIiwiU0VSVkVSX1BST1hZX1RJTUVPVVQiLCJTRVJWRVJfUkFURV9MSU1JVElOR19FTkFCTEUiLCJTRVJWRVJfUkFURV9MSU1JVElOR19NQVhfUkVRVUVTVFMiLCJTRVJWRVJfUkFURV9MSU1JVElOR19XSU5ET1ciLCJTRVJWRVJfUkFURV9MSU1JVElOR19ERUxBWSIsIlNFUlZFUl9SQVRFX0xJTUlUSU5HX1RSVVNUX1BST1hZIiwiU0VSVkVSX1JBVEVfTElNSVRJTkdfU0tJUF9LRVkiLCJTRVJWRVJfUkFURV9MSU1JVElOR19TS0lQX1RPS0VOIiwiU0VSVkVSX1NTTF9FTkFCTEUiLCJTRVJWRVJfU1NMX0ZPUkNFIiwiU0VSVkVSX1NTTF9QT1JUIiwiU0VSVkVSX1NTTF9DRVJUX1BBVEgiLCJQT09MX01JTl9XT1JLRVJTIiwiUE9PTF9NQVhfV09SS0VSUyIsIlBPT0xfV09SS19MSU1JVCIsIlBPT0xfQUNRVUlSRV9USU1FT1VUIiwiUE9PTF9DUkVBVEVfVElNRU9VVCIsIlBPT0xfREVTVFJPWV9USU1FT1VUIiwiUE9PTF9JRExFX1RJTUVPVVQiLCJQT09MX0NSRUFURV9SRVRSWV9JTlRFUlZBTCIsIlBPT0xfUkVBUEVSX0lOVEVSVkFMIiwiUE9PTF9CRU5DSE1BUktJTkciLCJMT0dHSU5HX0xFVkVMIiwiTE9HR0lOR19GSUxFIiwiTE9HR0lOR19ERVNUIiwiTE9HR0lOR19UT19DT05TT0xFIiwiTE9HR0lOR19UT19GSUxFIiwiVUlfRU5BQkxFIiwiVUlfUk9VVEUiLCJPVEhFUl9OT0RFX0VOViIsIk9USEVSX0xJU1RFTl9UT19QUk9DRVNTX0VYSVRTIiwiT1RIRVJfTk9fTE9HTyIsIk9USEVSX0hBUkRfUkVTRVRfUEFHRSIsIk9USEVSX0JST1dTRVJfU0hFTExfTU9ERSIsIk9USEVSX1ZBTElEQVRJT04iLCJERUJVR19FTkFCTEUiLCJERUJVR19IRUFETEVTUyIsIkRFQlVHX0RFVlRPT0xTIiwiREVCVUdfTElTVEVOX1RPX0NPTlNPTEUiLCJERUJVR19EVU1QSU8iLCJERUJVR19TTE9XX01PIiwiREVCVUdfREVCVUdHSU5HX1BPUlQiLCJlbnZzIiwicGFyc2UiLCJlbnYiLCJzdHJpY3RWYWxpZGF0ZSIsImNvbmZpZ09wdGlvbnMiLCJsb29zZVZhbGlkYXRlIiwiY29udGV4dCIsInByb3BlcnR5TmFtZSIsInByb3BlcnR5SW5mbyIsImNvZGUiLCJab2RJc3N1ZUNvZGUiLCJpbnZhbGlkX3R5cGUiLCJyZWNlaXZlZCIsIlpvZFBhcnNlZFR5cGUiLCJkZWZhdWx0RXJyb3IiLCJjdXN0b20iLCJkYXRhIiwiaW52YWxpZF91bmlvbiIsInVuaW9uRXJyb3JzIiwiZm9yRWFjaCIsImluZGV4Iiwic3Vic3RyaW5nIiwiRXhwb3J0RXJyb3IiLCJFcnJvciIsImNvbnN0cnVjdG9yIiwic3RhdHVzQ29kZSIsInN1cGVyIiwic2V0RXJyb3IiLCJuYW1lIiwiX2luaXRPcHRpb25zIiwibmVzdGVkUHJvcHMiLCJfY3JlYXRlTmVzdGVkUHJvcHMiLCJhYnNvbHV0ZVByb3BzIiwiX2NyZWF0ZUFic29sdXRlUHJvcHMiLCJnZXRPcHRpb25zIiwiZ2V0Q29weSIsInVwZGF0ZU9wdGlvbnMiLCJuZXdPcHRpb25zIiwiX21lcmdlT3B0aW9ucyIsInZhbGlkYXRlT3B0aW9ucyIsIm1hcFRvTmV3T3B0aW9ucyIsIm9sZE9wdGlvbnMiLCJlbnRyaWVzIiwicHJvcGVydGllc0NoYWluIiwicmVkdWNlIiwib2JqIiwicHJvcCIsInZhbGlkYXRlT3B0aW9uIiwiY29uZmlnT3B0aW9uIiwiaXNBbGxvd2VkQ29uZmlnIiwiYWxsb3dGdW5jdGlvbnMiLCJvYmplY3RDb25maWciLCJldmFsIiwiSlNPTiIsInN0cmluZ2lmaWVkT3B0aW9ucyIsIl9vcHRpb25zU3RyaW5naWZ5IiwicGFyc2VkT3B0aW9ucyIsIl8iLCJvcmlnaW5hbE9wdGlvbnMiLCJzdHJpbmdpZnlGdW5jdGlvbnMiLCJzdHJpbmdpZnkiLCJyZXBsYWNlQWxsIiwicHJvcENoYWluIiwiZW50cnkiLCJhc3luYyIsImdldCIsInVybCIsInJlcXVlc3RPcHRpb25zIiwiUHJvbWlzZSIsInJlamVjdCIsIl9nZXRQcm90b2NvbE1vZHVsZSIsInJlc3BvbnNlIiwicmVzcG9uc2VEYXRhIiwib24iLCJjaHVuayIsInRleHQiLCJodHRwcyIsImh0dHAiLCJjYWNoZSIsImFjdGl2ZU1hbmlmZXN0Iiwic291cmNlcyIsImhjVmVyc2lvbiIsImNoZWNrQ2FjaGUiLCJoaWdoY2hhcnRzT3B0aW9ucyIsInNlcnZlclByb3h5T3B0aW9ucyIsImZldGNoZWRNb2R1bGVzIiwiZ2V0Q2FjaGVQYXRoIiwibWFuaWZlc3RQYXRoIiwic291cmNlUGF0aCIsInJlY3Vyc2l2ZSIsIl91cGRhdGVDYWNoZSIsInJlcXVlc3RVcGRhdGUiLCJtYW5pZmVzdCIsInJlYWRGaWxlU3luYyIsIm1vZHVsZXMiLCJtb2R1bGVNYXAiLCJtIiwibnVtYmVyT2ZNb2R1bGVzIiwibW9kdWxlTmFtZSIsIl9leHRyYWN0SGNWZXJzaW9uIiwiX3NhdmVDb25maWdUb01hbmlmZXN0IiwiZ2V0SGNWZXJzaW9uIiwidXBkYXRlSGNWZXJzaW9uIiwibmV3VmVyc2lvbiIsIndyaXRlRmlsZVN5bmMiLCJfY29uZmlndXJlUmVxdWVzdCIsImFsbCIsImNzIiwiX2ZldGNoU2NyaXB0IiwibXMiLCJpcyIsInNjcmlwdCIsInNob3VsZFRocm93RXJyb3IiLCJfZXh0cmFjdE1vZHVsZU5hbWUiLCJhZ2VudCIsIkh0dHBzUHJveHlBZ2VudCIsImNhY2hlU291cmNlcyIsInJlcGxhY2UiLCJzY3JpcHRQYXRoIiwic2V0dXBIaWdoY2hhcnRzIiwiSGlnaGNoYXJ0cyIsImFuaW1PYmplY3QiLCJkdXJhdGlvbiIsImNyZWF0ZUNoYXJ0IiwiZXhwb3J0T3B0aW9ucyIsImN1c3RvbUxvZ2ljT3B0aW9ucyIsInNldE9wdGlvbnMiLCJtZXJnZSIsIndyYXAiLCJzZXRPcHRpb25zT2JqIiwiaXNSZW5kZXJDb21wbGV0ZSIsIkNoYXJ0IiwicHJvY2VlZCIsInVzZXJPcHRpb25zIiwiY2IiLCJleHBvcnRpbmciLCJlbmFibGVkIiwicGxvdE9wdGlvbnMiLCJzZXJpZXMiLCJsYWJlbCIsInRvb2x0aXAiLCJhbmltYXRpb24iLCJvbkhpZ2hjaGFydHNSZW5kZXIiLCJhZGRFdmVudCIsIlNlcmllcyIsImNoYXJ0IiwiRnVuY3Rpb24iLCJmaW5hbE9wdGlvbnMiLCJmaW5hbENhbGxiYWNrIiwiaW1hZ2VzIiwicXVlcnlTZWxlY3RvckFsbCIsInJhY2UiLCJpbWFnZSIsImNvbXBsZXRlIiwibmF0dXJhbEhlaWdodCIsImFkZEV2ZW50TGlzdGVuZXIiLCJvbmNlIiwic2V0VGltZW91dCIsImRlZmF1bHRPcHRpb25zIiwicGFnZVRlbXBsYXRlIiwiYnJvd3NlciIsImNyZWF0ZUJyb3dzZXIiLCJwdXBwZXRlZXJBcmdzIiwiZW5hYmxlZERlYnVnIiwiZGVidWdPcHRpb25zIiwibGF1bmNoT3B0aW9ucyIsInVzZXJEYXRhRGlyIiwiaGFuZGxlU0lHSU5UIiwiaGFuZGxlU0lHVEVSTSIsImhhbmRsZVNJR0hVUCIsIndhaXRGb3JJbml0aWFsUGFnZSIsImRlZmF1bHRWaWV3cG9ydCIsInRyeUNvdW50Iiwib3BlbkJyb3dzZXIiLCJsYXVuY2giLCJjbG9zZUJyb3dzZXIiLCJjb25uZWN0ZWQiLCJjbG9zZSIsIm5ld1BhZ2UiLCJwb29sUmVzb3VyY2UiLCJwYWdlIiwic2V0Q2FjaGVFbmFibGVkIiwiX3NldFBhZ2VDb250ZW50IiwiX3NldFBhZ2VFdmVudHMiLCJpc0Nsb3NlZCIsImNsZWFyUGFnZSIsImhhcmRSZXNldCIsImdvdG8iLCJ3YWl0VW50aWwiLCJldmFsdWF0ZSIsImJvZHkiLCJpbm5lckhUTUwiLCJpZCIsIndvcmtDb3VudCIsImFkZFBhZ2VSZXNvdXJjZXMiLCJpbmplY3RlZFJlc291cmNlcyIsImluamVjdGVkSnMiLCJjb250ZW50IiwiaXNMb2NhbCIsImpzUmVzb3VyY2UiLCJhZGRTY3JpcHRUYWciLCJpbmplY3RlZENzcyIsImNzc0ltcG9ydHMiLCJtYXRjaCIsImNzc0ltcG9ydFBhdGgiLCJjc3NSZXNvdXJjZSIsImFkZFN0eWxlVGFnIiwiY2xlYXJQYWdlUmVzb3VyY2VzIiwicmVzb3VyY2UiLCJkaXNwb3NlIiwib2xkQ2hhcnRzIiwiY2hhcnRzIiwib2xkQ2hhcnQiLCJkZXN0cm95Iiwic2NyaXB0c1RvUmVtb3ZlIiwiZ2V0RWxlbWVudHNCeVRhZ05hbWUiLCJzdHlsZXNUb1JlbW92ZSIsImxpbmtzVG9SZW1vdmUiLCJlbGVtZW50IiwicmVtb3ZlIiwic2V0Q29udGVudCIsImNzc1RlbXBsYXRlIiwic3ZnVGVtcGxhdGUiLCJwdXBwZXRlZXJFeHBvcnQiLCJpc1NWRyIsInNpemUiLCJfZ2V0Q2hhcnRTaXplIiwieCIsInkiLCJfZ2V0Q2xpcFJlZ2lvbiIsInZpZXdwb3J0SGVpZ2h0IiwiYWJzIiwiY2VpbCIsImNoYXJ0SGVpZ2h0Iiwidmlld3BvcnRXaWR0aCIsImNoYXJ0V2lkdGgiLCJyZXN1bHQiLCJzZXRWaWV3cG9ydCIsImRldmljZVNjYWxlRmFjdG9yIiwicGFyc2VGbG9hdCIsIl9jcmVhdGVTVkciLCJfY3JlYXRlSW1hZ2UiLCJfY3JlYXRlUERGIiwiJGV2YWwiLCJnZXRCb3VuZGluZ0NsaWVudFJlY3QiLCJ0cnVuYyIsInN2Z0VsZW1lbnQiLCJxdWVyeVNlbGVjdG9yIiwiYmFzZVZhbCIsInN0eWxlIiwiem9vbSIsIm1hcmdpbiIsIm91dGVySFRNTCIsImNsaXAiLCJzY3JlZW5zaG90IiwiZW5jb2RpbmciLCJmdWxsUGFnZSIsIm9wdGltaXplRm9yU3BlZWQiLCJjYXB0dXJlQmV5b25kVmlld3BvcnQiLCJxdWFsaXR5Iiwib21pdEJhY2tncm91bmQiLCJfcmVzb2x2ZSIsImVtdWxhdGVNZWRpYVR5cGUiLCJwZGYiLCJwb29sU3RhdHMiLCJleHBvcnRzQXR0ZW1wdGVkIiwiZXhwb3J0c1BlcmZvcm1lZCIsImV4cG9ydHNEcm9wcGVkIiwiZXhwb3J0c0Zyb21TdmciLCJleHBvcnRzRnJvbU9wdGlvbnMiLCJleHBvcnRzRnJvbVN2Z0F0dGVtcHRzIiwiZXhwb3J0c0Zyb21PcHRpb25zQXR0ZW1wdHMiLCJ0aW1lU3BlbnQiLCJ0aW1lU3BlbnRBdmVyYWdlIiwiaW5pdFBvb2wiLCJwb29sT3B0aW9ucyIsIlBvb2wiLCJfZmFjdG9yeSIsImFjcXVpcmVUaW1lb3V0TWlsbGlzIiwiY3JlYXRlVGltZW91dE1pbGxpcyIsImRlc3Ryb3lUaW1lb3V0TWlsbGlzIiwiaWRsZVRpbWVvdXRNaWxsaXMiLCJjcmVhdGVSZXRyeUludGVydmFsTWlsbGlzIiwicmVhcEludGVydmFsTWlsbGlzIiwicHJvcGFnYXRlQ3JlYXRlRXJyb3IiLCJjbGVhclN0YXR1cyIsIl9ldmVudElkIiwiaW5pdGlhbFJlc291cmNlcyIsImkiLCJhY3F1aXJlIiwicHJvbWlzZSIsInJlbGVhc2UiLCJraWxsUG9vbCIsIndvcmtlciIsInVzZWQiLCJkZXN0cm95ZWQiLCJwb3N0V29yayIsIndvcmtlckhhbmRsZSIsIl9nZXRQb29sSW5mbyIsImFjcXVpcmVDb3VudGVyIiwiZXhwb3J0Q291bnRlciIsImV4cG9ydFJlc3VsdCIsImdldFBvb2xTdGF0cyIsImdldFBvb2xJbmZvSlNPTiIsIm51bVVzZWQiLCJhdmFpbGFibGUiLCJudW1GcmVlIiwiYWxsQ3JlYXRlZCIsInBlbmRpbmdBY3F1aXJlcyIsIm51bVBlbmRpbmdBY3F1aXJlcyIsInBlbmRpbmdDcmVhdGVzIiwibnVtUGVuZGluZ0NyZWF0ZXMiLCJwZW5kaW5nVmFsaWRhdGlvbnMiLCJudW1QZW5kaW5nVmFsaWRhdGlvbnMiLCJwZW5kaW5nRGVzdHJveXMiLCJhYnNvbHV0ZUFsbCIsImNyZWF0ZSIsInJhbmRvbSIsInN0YXJ0RGF0ZSIsInZhbGlkYXRlIiwibWFpbkZyYW1lIiwiZGV0YWNoZWQiLCJyZW1vdmVBbGxMaXN0ZW5lcnMiLCJzYW5pdGl6ZSIsIkpTRE9NIiwiRE9NUHVyaWZ5IiwiQUREX1RBR1MiLCJzaW5nbGVFeHBvcnQiLCJzdGFydEV4cG9ydCIsImJhdGNoRXhwb3J0IiwiYmF0Y2hGdW5jdGlvbnMiLCJwYWlyIiwiYmF0Y2hSZXN1bHRzIiwiYWxsU2V0dGxlZCIsInJlYXNvbiIsImltYWdlT3B0aW9ucyIsImVuZENhbGxiYWNrIiwiZmlsZUNvbnRlbnQiLCJfZXhwb3J0RnJvbVN2ZyIsIl9leHBvcnRGcm9tT3B0aW9ucyIsImdldEFsbG93Q29kZUV4ZWN1dGlvbiIsInNldEFsbG93Q29kZUV4ZWN1dGlvbiIsImlucHV0VG9FeHBvcnQiLCJfcHJlcGFyZUV4cG9ydCIsIl9maXhDb25zdHIiLCJfZml4VHlwZSIsIl9maXhPdXRmaWxlIiwiX2hhbmRsZUN1c3RvbUxvZ2ljIiwiX2hhbmRsZUdsb2JhbEFuZFRoZW1lIiwiX2hhbmRsZVNpemUiLCJfY2hlY2tEYXRhU2l6ZSIsImZpeGVkQ29uc3RyIiwidG9Mb3dlckNhc2UiLCJtaW1lVHlwZXMiLCJmb3JtYXRzIiwib3V0VHlwZSIsInBvcCIsImZpbmQiLCJ0Iiwib3B0aW9uc0NoYXJ0Iiwib3B0aW9uc0V4cG9ydGluZyIsImdsb2JhbE9wdGlvbnNDaGFydCIsImdsb2JhbE9wdGlvbnNFeHBvcnRpbmciLCJ0aGVtZU9wdGlvbnNDaGFydCIsInRoZW1lT3B0aW9uc0V4cG9ydGluZyIsInNvdXJjZUhlaWdodCIsInNvdXJjZVdpZHRoIiwicGFyYW0iLCJfaGFuZGxlUmVzb3VyY2VzIiwiX2hhbmRsZUN1c3RvbUNvZGUiLCJoYW5kbGVkUmVzb3VyY2VzIiwiYWxsb3dlZFByb3BzIiwiY29ycmVjdFJlc291cmNlcyIsInByb3BOYW1lIiwiaXNDYWxsYmFjayIsIm9wdGlvbnNOYW1lIiwidG90YWxTaXplIiwiYnl0ZUxlbmd0aCIsInRvRml4ZWQiLCJ0aW1lcklkcyIsImFkZFRpbWVyIiwiY2xlYXJBbGxUaW1lcnMiLCJjbGVhckludGVydmFsIiwiY2xlYXJUaW1lb3V0IiwibG9nRXJyb3JNaWRkbGV3YXJlIiwicmVxdWVzdCIsIm5leHQiLCJyZXR1cm5FcnJvck1pZGRsZXdhcmUiLCJzdGF0dXMiLCJqc29uIiwiZXJyb3JNaWRkbGV3YXJlIiwiYXBwIiwidXNlIiwicmF0ZUxpbWl0aW5nTWlkZGxld2FyZSIsInJhdGVMaW1pdGluZ09wdGlvbnMiLCJyYXRlT3B0aW9ucyIsImxpbWl0ZXIiLCJyYXRlTGltaXQiLCJ3aW5kb3dNcyIsImxpbWl0IiwiZGVsYXlNcyIsImhhbmRsZXIiLCJmb3JtYXQiLCJzZW5kIiwiZGVmYXVsdCIsInNraXAiLCJxdWVyeSIsImFjY2Vzc190b2tlbiIsImNvbnRlbnRUeXBlTWlkZGxld2FyZSIsImNvbnRlbnRUeXBlIiwiaGVhZGVycyIsInJlcXVlc3RCb2R5TWlkZGxld2FyZSIsImNvbm5lY3Rpb24iLCJyZW1vdGVBZGRyZXNzIiwidmFsaWRhdGVkT3B0aW9ucyIsImZpbGVuYW1lIiwidmFsaWRhdGlvbk1pZGRsZXdhcmUiLCJwb3N0IiwicmV2ZXJzZWRNaW1lIiwicG5nIiwianBlZyIsImdpZiIsInJlcXVlc3RFeHBvcnQiLCJyZXF1ZXN0Q291bnRlciIsImNvbm5lY3Rpb25BYm9ydGVkIiwic29ja2V0IiwiaGFkRXJyb3JzIiwiaGVhZGVyIiwiYXR0YWNobWVudCIsImV4cG9ydFJvdXRlcyIsInNlcnZlclN0YXJ0VGltZSIsInBhY2thZ2VGaWxlIiwic3VjY2Vzc1JhdGVzIiwicmVjb3JkSW50ZXJ2YWwiLCJ3aW5kb3dTaXplIiwiX2NhbGN1bGF0ZU1vdmluZ0F2ZXJhZ2UiLCJhIiwiYiIsIl9zdGFydFN1Y2Nlc3NSYXRlIiwic2V0SW50ZXJ2YWwiLCJzdGF0cyIsInN1Y2Nlc3NSYXRpbyIsImhlYWx0aFJvdXRlcyIsInBlcmlvZCIsIm1vdmluZ0F2ZXJhZ2UiLCJib290VGltZSIsInVwdGltZSIsImZsb29yIiwic2VydmVyVmVyc2lvbiIsImhpZ2hjaGFydHNWZXJzaW9uIiwiYXZlcmFnZUV4cG9ydFRpbWUiLCJhdHRlbXB0ZWRFeHBvcnRzIiwicGVyZm9ybWVkRXhwb3J0cyIsImZhaWxlZEV4cG9ydHMiLCJzdWNlc3NSYXRpbyIsInN2Z0V4cG9ydHMiLCJqc29uRXhwb3J0cyIsInN2Z0V4cG9ydHNBdHRlbXB0cyIsImpzb25FeHBvcnRzQXR0ZW1wdHMiLCJ1aVJvdXRlcyIsInNlbmRGaWxlIiwiYWNjZXB0UmFuZ2VzIiwidmVyc2lvbkNoYW5nZVJvdXRlcyIsInRva2VuIiwiYWN0aXZlU2VydmVycyIsIk1hcCIsImV4cHJlc3MiLCJzdGFydFNlcnZlciIsInNlcnZlck9wdGlvbnMiLCJ1cGxvYWRMaW1pdEJ5dGVzIiwic3RvcmFnZSIsIm11bHRlciIsIm1lbW9yeVN0b3JhZ2UiLCJ1cGxvYWQiLCJsaW1pdHMiLCJmaWVsZFNpemUiLCJkaXNhYmxlIiwiY29ycyIsIm1ldGhvZHMiLCJzZXQiLCJ1cmxlbmNvZGVkIiwiZXh0ZW5kZWQiLCJub25lIiwic3RhdGljIiwiaHR0cFNlcnZlciIsImNyZWF0ZVNlcnZlciIsIl9hdHRhY2hTZXJ2ZXJFcnJvckhhbmRsZXJzIiwibGlzdGVuIiwiY2VydCIsImh0dHBzU2VydmVyIiwiY2xvc2VTZXJ2ZXJzIiwiZGVsZXRlIiwiZ2V0U2VydmVycyIsImdldEV4cHJlc3MiLCJnZXRBcHAiLCJtaWRkbGV3YXJlcyIsInNodXRkb3duQ2xlYW5VcCIsImV4aXRDb2RlIiwiZXhpdCIsImluaXRFeHBvcnQiLCJpbml0T3B0aW9ucyIsIl9hdHRhY2hQcm9jZXNzRXhpdExpc3RlbmVycyJdLCJtYXBwaW5ncyI6IndsQkEwQk8sTUFBTUEsWUFBWUMsSUFBYUEsY0FBQyxJQUFJQyxJQUFJLE9BQVEsb0JBQUFDLFNBQUFDLFFBQUEsT0FBQUMsY0FBQUMsWUFBQUMsS0FBQUMsd0JBQUEsV0FBQUEsdUJBQUFDLFFBQUFDLGVBQUFGLHVCQUFBRyxLQUFBLElBQUFULElBQUEsWUFBQUMsU0FBQVMsU0FBQUwsT0ErQmhELFNBQVNNLFNBQVNDLEdBRXZCLEdBQWUsT0FBWEEsR0FBcUMsaUJBQVhBLEVBQzVCLE9BQU9BLEVBSVQsTUFBTUMsRUFBYUMsTUFBTUMsUUFBUUgsR0FBVSxHQUFLLEdBR2hELElBQUssTUFBTUksS0FBT0osRUFDWkssT0FBT0MsVUFBVUMsZUFBZUMsS0FBS1IsRUFBUUksS0FDL0NILEVBQVdHLEdBQU9MLFNB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 diff --git a/dist/index.esm.js b/dist/index.esm.js index 5faa6c3d..77682997 100644 --- a/dist/index.esm.js +++ b/dist/index.esm.js @@ -1,2 +1,2 @@ -import"colors";import{existsSync,mkdirSync,appendFile,readFileSync,writeFileSync}from"fs";import{normalize,resolve,isAbsolute,join}from"path";import{HttpsProxyAgent}from"https-proxy-agent";import{fileURLToPath}from"url";import dotenv from"dotenv";import{z}from"zod";import http from"http";import https from"https";import{Pool}from"tarn";import{v4}from"uuid";import puppeteer from"puppeteer";import DOMPurify from"dompurify";import{JSDOM}from"jsdom";import cors from"cors";import express from"express";import multer from"multer";import rateLimit from"express-rate-limit";const __dirname=fileURLToPath(new URL("../.",import.meta.url));function deepCopy(e){if(null===e||"object"!=typeof e)return e;const t=Array.isArray(e)?[]:{};for(const o in e)Object.prototype.hasOwnProperty.call(e,o)&&(t[o]=deepCopy(e[o]));return t}function getAbsolutePath(e){return isAbsolute(e)?normalize(e):resolve(e)}function getBase64(e,t){return"pdf"===t||"svg"==t?Buffer.from(e,"utf8").toString("base64"):e}function getNewDate(){return(new Date).toString().split("(")[0].trim()}function getNewDateTime(){return(new Date).getTime()}function isObject(e){return"[object Object]"===Object.prototype.toString.call(e)}function isObjectEmpty(e){return"object"==typeof e&&!Array.isArray(e)&&null!==e&&0===Object.keys(e).length}function isPrivateRangeUrlFound(e){return[/xlink:href="(?:http:\/\/|https:\/\/)?localhost\b/,/xlink:href="(?:http:\/\/|https:\/\/)?10\.\d{1,3}\.\d{1,3}\.\d{1,3}\b/,/xlink:href="(?:http:\/\/|https:\/\/)?127\.\d{1,3}\.\d{1,3}\.\d{1,3}\b/,/xlink:href="(?:http:\/\/|https:\/\/)?172\.(1[6-9]|2[0-9]|3[0-1])\.\d{1,3}\.\d{1,3}\b/,/xlink:href="(?:http:\/\/|https:\/\/)?192\.168\.\d{1,3}\.\d{1,3}\b/].some((t=>t.test(e)))}function measureTime(){const e=process.hrtime.bigint();return()=>Number(process.hrtime.bigint()-e)/1e6}function roundNumber(e,t=1){const o=Math.pow(10,t||0);return Math.round(+e*o)/o}const colors=["red","yellow","blue","gray","green"],logging={toConsole:!0,toFile:!1,pathCreated:!1,pathToLog:"",levelsDesc:[{title:"error",color:colors[0]},{title:"warning",color:colors[1]},{title:"notice",color:colors[2]},{title:"verbose",color:colors[3]},{title:"benchmark",color:colors[4]}]};function log(...e){const[t,...o]=e,{levelsDesc:r,level:i}=logging;if(5!==t&&(0===t||t>i||i>r.length))return;const n=`${getNewDate()} [${r[t-1].title}] -`;logging.toFile&&_logToFile(o,n),logging.toConsole&&console.log.apply(void 0,[n.toString()[logging.levelsDesc[t-1].color]].concat(o))}function logWithStack(e,t,o){const r=o||t&&t.message||"",{level:i,levelsDesc:n}=logging;if(0===e||e>i||i>n.length)return;const s=`${getNewDate()} [${n[e-1].title}] -`,a=t&&t.stack,l=[r];a&&l.push("\n",a),logging.toFile&&_logToFile(l,s),logging.toConsole&&console.log.apply(void 0,[s.toString()[logging.levelsDesc[e-1].color]].concat([l.shift()[colors[e-1]],...l]))}function logZodIssues(e,t,o){logWithStack(e,null,[`${o||"[validation] Validation error"} - the following Zod issues occured:`,...(t||[]).map((e=>`- ${e.message}`))].join("\n"))}function initLogging(e){const{level:t,dest:o,file:r,toConsole:i,toFile:n}=e;logging.pathCreated=!1,logging.pathToLog="",setLogLevel(t),enableConsoleLogging(i),enableFileLogging(o,r,n)}function setLogLevel(e){Number.isInteger(e)&&e>=0&&e<=logging.levelsDesc.length&&(logging.level=e)}function enableConsoleLogging(e){logging.toConsole=!!e}function enableFileLogging(e,t,o){logging.toFile=!!o,logging.toFile&&(logging.dest=e||"log",logging.file=t||"highcharts-export-server.log")}function _logToFile(e,t){logging.pathCreated||(!existsSync(getAbsolutePath(logging.dest))&&mkdirSync(getAbsolutePath(logging.dest)),logging.pathToLog=getAbsolutePath(join(logging.dest,logging.file)),logging.pathCreated=!0),appendFile(logging.pathToLog,[t].concat(e).join(" ")+"\n",(e=>{e&&logging.toFile&&logging.pathCreated&&(logging.toFile=!1,logging.pathCreated=!1,logWithStack(2,e,"[logger] Unable to write to log file."))}))}const defaultConfig={puppeteer:{args:{value:["--allow-running-insecure-content","--ash-no-nudges","--autoplay-policy=user-gesture-required","--block-new-web-contents","--disable-accelerated-2d-canvas","--disable-background-networking","--disable-background-timer-throttling","--disable-backgrounding-occluded-windows","--disable-breakpad","--disable-checker-imaging","--disable-client-side-phishing-detection","--disable-component-extensions-with-background-pages","--disable-component-update","--disable-default-apps","--disable-dev-shm-usage","--disable-domain-reliability","--disable-extensions","--disable-features=CalculateNativeWinOcclusion,InterestFeedContentSuggestions,WebOTP","--disable-hang-monitor","--disable-ipc-flooding-protection","--disable-logging","--disable-notifications","--disable-offer-store-unmasked-wallet-cards","--disable-popup-blocking","--disable-print-preview","--disable-prompt-on-repost","--disable-renderer-backgrounding","--disable-search-engine-choice-screen","--disable-session-crashed-bubble","--disable-setuid-sandbox","--disable-site-isolation-trials","--disable-speech-api","--disable-sync","--enable-unsafe-webgpu","--hide-crash-restore-bubble","--hide-scrollbars","--metrics-recording-only","--mute-audio","--no-default-browser-check","--no-first-run","--no-pings","--no-sandbox","--no-startup-window","--no-zygote","--password-store=basic","--process-per-tab","--use-mock-keychain"],types:["string[]"],envLink:"PUPPETEER_ARGS",cliName:"puppeteerArgs",description:"Array of Puppeteer arguments",promptOptions:{type:"list",separator:";"}}},highcharts:{version:{value:"latest",types:["string"],envLink:"HIGHCHARTS_VERSION",description:"Highcharts version",promptOptions:{type:"text"}},cdnUrl:{value:"https://code.highcharts.com",types:["string"],envLink:"HIGHCHARTS_CDN_URL",description:"CDN URL for Highcharts scripts",promptOptions:{type:"text"}},forceFetch:{value:!1,types:["boolean"],envLink:"HIGHCHARTS_FORCE_FETCH",description:"Flag to refetch scripts after each server rerun",promptOptions:{type:"toggle"}},cachePath:{value:".cache",types:["string"],envLink:"HIGHCHARTS_CACHE_PATH",description:"Directory path for cached Highcharts scripts",promptOptions:{type:"text"}},coreScripts:{value:["highcharts","highcharts-more","highcharts-3d"],types:["string[]"],envLink:"HIGHCHARTS_CORE_SCRIPTS",description:"Highcharts core scripts to fetch",promptOptions:{type:"multiselect",instructions:"Space: Select specific, A: Select all, Enter: Confirm"}},moduleScripts:{value:["stock","map","gantt","exporting","parallel-coordinates","accessibility","boost-canvas","boost","data","data-tools","draggable-points","static-scale","broken-axis","heatmap","tilemap","tiledwebmap","timeline","treemap","treegraph","item-series","drilldown","histogram-bellcurve","bullet","funnel","funnel3d","geoheatmap","pyramid3d","networkgraph","overlapping-datalabels","pareto","pattern-fill","pictorial","price-indicator","sankey","arc-diagram","dependency-wheel","series-label","series-on-point","solid-gauge","sonification","streamgraph","sunburst","variable-pie","variwide","vector","venn","windbarb","wordcloud","xrange","no-data-to-display","drag-panes","debugger","dumbbell","lollipop","cylinder","organization","dotplot","marker-clusters","hollowcandlestick","heikinashi","flowmap","export-data","navigator","textpath"],types:["string[]"],envLink:"HIGHCHARTS_MODULE_SCRIPTS",description:"Highcharts module scripts to fetch",promptOptions:{type:"multiselect",instructions:"Space: Select specific, A: Select all, Enter: Confirm"}},indicatorScripts:{value:["indicators-all"],types:["string[]"],envLink:"HIGHCHARTS_INDICATOR_SCRIPTS",description:"Highcharts indicator scripts to fetch",promptOptions:{type:"multiselect",instructions:"Space: Select specific, A: Select all, Enter: Confirm"}},customScripts:{value:["https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.30.1/moment.min.js","https://cdnjs.cloudflare.com/ajax/libs/moment-timezone/0.5.45/moment-timezone-with-data.min.js"],types:["string[]"],envLink:"HIGHCHARTS_CUSTOM_SCRIPTS",description:"Additional custom scripts or dependencies to fetch",promptOptions:{type:"list",separator:";"}}},export:{infile:{value:null,types:["string","null"],envLink:"EXPORT_INFILE",description:"Input filename with type, formatted correctly as JSON or SVG",promptOptions:{type:"text"}},instr:{value:null,types:["Object","string","null"],envLink:"EXPORT_INSTR",description:"Overrides the `infile` with JSON, stringified JSON, or SVG input",promptOptions:{type:"text"}},options:{value:null,types:["Object","string","null"],envLink:"EXPORT_OPTIONS",description:"Alias for the `instr` option",promptOptions:{type:"text"}},svg:{value:null,types:["string","null"],envLink:"EXPORT_SVG",description:"SVG string representation of the chart to render",promptOptions:{type:"text"}},batch:{value:null,types:["string","null"],envLink:"EXPORT_BATCH",description:'Batch job string with input/output pairs: "in=out;in=out;..."',promptOptions:{type:"text"}},outfile:{value:null,types:["string","null"],envLink:"EXPORT_OUTFILE",description:"Output filename with type. Can be jpeg, png, pdf, or svg and ignores `type` option",promptOptions:{type:"text"}},type:{value:"png",types:["string"],envLink:"EXPORT_TYPE",description:"File export format. Can be jpeg, png, pdf, or svg",promptOptions:{type:"select",hint:"Default: png",choices:["png","jpeg","pdf","svg"]}},constr:{value:"chart",types:["string"],envLink:"EXPORT_CONSTR",description:"Chart constructor. Can be chart, stockChart, mapChart, or ganttChart",promptOptions:{type:"select",hint:"Default: chart",choices:["chart","stockChart","mapChart","ganttChart"]}},b64:{value:!1,types:["boolean"],envLink:"EXPORT_B64",description:"Whether or not to the chart should be received in Base64 format instead of binary",promptOptions:{type:"toggle"}},noDownload:{value:!1,types:["boolean"],envLink:"EXPORT_NO_DOWNLOAD",description:"Whether or not to include or exclude attachment headers in the response",promptOptions:{type:"toggle"}},height:{value:null,types:["number","null"],envLink:"EXPORT_HEIGHT",description:"Height of the exported chart, overrides chart settings",promptOptions:{type:"number"}},width:{value:null,types:["number","null"],envLink:"EXPORT_WIDTH",description:"Width of the exported chart, overrides chart settings",promptOptions:{type:"number"}},scale:{value:null,types:["number","null"],envLink:"EXPORT_SCALE",description:"Scale of the exported chart, overrides chart settings. Ranges from 0.1 to 5.0",promptOptions:{type:"number"}},defaultHeight:{value:400,types:["number"],envLink:"EXPORT_DEFAULT_HEIGHT",description:"Default height of the exported chart if not set",promptOptions:{type:"number"}},defaultWidth:{value:600,types:["number"],envLink:"EXPORT_DEFAULT_WIDTH",description:"Default width of the exported chart if not set",promptOptions:{type:"number"}},defaultScale:{value:1,types:["number"],envLink:"EXPORT_DEFAULT_SCALE",description:"Default scale of the exported chart if not set. Ranges from 0.1 to 5.0",promptOptions:{type:"number",min:.1,max:5}},globalOptions:{value:null,types:["Object","string","null"],envLink:"EXPORT_GLOBAL_OPTIONS",description:"JSON, stringified JSON or filename with global options for Highcharts.setOptions",promptOptions:{type:"text"}},themeOptions:{value:null,types:["Object","string","null"],envLink:"EXPORT_THEME_OPTIONS",description:"JSON, stringified JSON or filename with theme options for Highcharts.setOptions",promptOptions:{type:"text"}},rasterizationTimeout:{value:1500,types:["number"],envLink:"EXPORT_RASTERIZATION_TIMEOUT",description:"Milliseconds to wait for webpage rendering",promptOptions:{type:"number"}}},customLogic:{allowCodeExecution:{value:!1,types:["boolean"],envLink:"CUSTOM_LOGIC_ALLOW_CODE_EXECUTION",description:"Allows or disallows execution of arbitrary code during exporting",promptOptions:{type:"toggle"}},allowFileResources:{value:!1,types:["boolean"],envLink:"CUSTOM_LOGIC_ALLOW_FILE_RESOURCES",description:"Allows or disallows injection of filesystem resources (disabled in server mode)",promptOptions:{type:"toggle"}},customCode:{value:null,types:["string","null"],envLink:"CUSTOM_LOGIC_CUSTOM_CODE",description:"Custom code to execute before chart initialization. Can be a function, code wrapped in a function, or a .js filename",promptOptions:{type:"text"}},callback:{value:null,types:["string","null"],envLink:"CUSTOM_LOGIC_CALLBACK",description:"JavaScript code to run during construction. Can be a function or a .js filename",promptOptions:{type:"text"}},resources:{value:null,types:["Object","string","null"],envLink:"CUSTOM_LOGIC_RESOURCES",description:"Additional resources as JSON, stringified JSON, or filename, containing files, js, and css sections",promptOptions:{type:"text"}},loadConfig:{value:null,types:["string","null"],envLink:"CUSTOM_LOGIC_LOAD_CONFIG",legacyName:"fromFile",description:"File with a pre-defined configuration to use",promptOptions:{type:"text"}},createConfig:{value:null,types:["string","null"],envLink:"CUSTOM_LOGIC_CREATE_CONFIG",description:"Prompt-based option setting, saved to a provided config file",promptOptions:{type:"text"}}},server:{enable:{value:!1,types:["boolean"],envLink:"SERVER_ENABLE",cliName:"enableServer",description:"Starts the server when true",promptOptions:{type:"toggle"}},host:{value:"0.0.0.0",types:["string"],envLink:"SERVER_HOST",description:"Hostname of the server",promptOptions:{type:"text"}},port:{value:7801,types:["number"],envLink:"SERVER_PORT",description:"Port number for the server",promptOptions:{type:"number"}},uploadLimit:{value:3,types:["number"],envLink:"SERVER_UPLOAD_LIMIT",description:"Maximum request body size in MB",promptOptions:{type:"number"}},benchmarking:{value:!1,types:["boolean"],envLink:"SERVER_BENCHMARKING",cliName:"serverBenchmarking",description:"Displays or not action durations in milliseconds during server requests",promptOptions:{type:"toggle"}},proxy:{host:{value:null,types:["string","null"],envLink:"SERVER_PROXY_HOST",cliName:"proxyHost",description:"Host of the proxy server, if applicable",promptOptions:{type:"text"}},port:{value:null,types:["number","null"],envLink:"SERVER_PROXY_PORT",cliName:"proxyPort",description:"Port of the proxy server, if applicable",promptOptions:{type:"number"}},timeout:{value:5e3,types:["number"],envLink:"SERVER_PROXY_TIMEOUT",cliName:"proxyTimeout",description:"Timeout in milliseconds for the proxy server, if applicable",promptOptions:{type:"number"}}},rateLimiting:{enable:{value:!1,types:["boolean"],envLink:"SERVER_RATE_LIMITING_ENABLE",cliName:"enableRateLimiting",description:"Enables or disables rate limiting on the server",promptOptions:{type:"toggle"}},maxRequests:{value:10,types:["number"],envLink:"SERVER_RATE_LIMITING_MAX_REQUESTS",legacyName:"rateLimit",description:"Maximum number of requests allowed per minute",promptOptions:{type:"number"}},window:{value:1,types:["number"],envLink:"SERVER_RATE_LIMITING_WINDOW",description:"Time window in minutes for rate limiting",promptOptions:{type:"number"}},delay:{value:0,types:["number"],envLink:"SERVER_RATE_LIMITING_DELAY",description:"Delay duration between successive requests before reaching the limit",promptOptions:{type:"number"}},trustProxy:{value:!1,types:["boolean"],envLink:"SERVER_RATE_LIMITING_TRUST_PROXY",description:"Set to true if the server is behind a load balancer",promptOptions:{type:"toggle"}},skipKey:{value:null,types:["string","null"],envLink:"SERVER_RATE_LIMITING_SKIP_KEY",description:"Key to bypass the rate limiter, used with `skipToken`",promptOptions:{type:"text"}},skipToken:{value:null,types:["string","null"],envLink:"SERVER_RATE_LIMITING_SKIP_TOKEN",description:"Token to bypass the rate limiter, used with `skipKey`",promptOptions:{type:"text"}}},ssl:{enable:{value:!1,types:["boolean"],envLink:"SERVER_SSL_ENABLE",cliName:"enableSsl",description:"Enables or disables SSL protocol",promptOptions:{type:"toggle"}},force:{value:!1,types:["boolean"],envLink:"SERVER_SSL_FORCE",cliName:"sslForce",legacyName:"sslOnly",description:"Forces the server to use HTTPS only when true",promptOptions:{type:"toggle"}},port:{value:443,types:["number"],envLink:"SERVER_SSL_PORT",cliName:"sslPort",description:"Port for the SSL server",promptOptions:{type:"number"}},certPath:{value:null,types:["string","null"],envLink:"SERVER_SSL_CERT_PATH",cliName:"sslCertPath",legacyName:"sslPath",description:"Path to the SSL certificate/key file",promptOptions:{type:"text"}}}},pool:{minWorkers:{value:4,types:["number"],envLink:"POOL_MIN_WORKERS",description:"Minimum and initial number of pool workers to spawn",promptOptions:{type:"number"}},maxWorkers:{value:8,types:["number"],envLink:"POOL_MAX_WORKERS",legacyName:"workers",description:"Maximum number of pool workers to spawn",promptOptions:{type:"number"}},workLimit:{value:40,types:["number"],envLink:"POOL_WORK_LIMIT",description:"Number of tasks a worker can handle before restarting",promptOptions:{type:"number"}},acquireTimeout:{value:5e3,types:["number"],envLink:"POOL_ACQUIRE_TIMEOUT",description:"Timeout in milliseconds for acquiring a resource",promptOptions:{type:"number"}},createTimeout:{value:5e3,types:["number"],envLink:"POOL_CREATE_TIMEOUT",description:"Timeout in milliseconds for creating a resource",promptOptions:{type:"number"}},destroyTimeout:{value:5e3,types:["number"],envLink:"POOL_DESTROY_TIMEOUT",description:"Timeout in milliseconds for destroying a resource",promptOptions:{type:"number"}},idleTimeout:{value:3e4,types:["number"],envLink:"POOL_IDLE_TIMEOUT",description:"Timeout in milliseconds for destroying idle resources",promptOptions:{type:"number"}},createRetryInterval:{value:200,types:["number"],envLink:"POOL_CREATE_RETRY_INTERVAL",description:"Interval in milliseconds before retrying resource creation on failure",promptOptions:{type:"number"}},reaperInterval:{value:1e3,types:["number"],envLink:"POOL_REAPER_INTERVAL",description:"Interval in milliseconds to check and destroy idle resources",promptOptions:{type:"number"}},benchmarking:{value:!1,types:["boolean"],envLink:"POOL_BENCHMARKING",cliName:"poolBenchmarking",description:"Shows statistics for the pool of resources",promptOptions:{type:"toggle"}}},logging:{level:{value:4,types:["number"],envLink:"LOGGING_LEVEL",cliName:"logLevel",description:"Logging verbosity level",promptOptions:{type:"number",round:0,min:0,max:5}},file:{value:"highcharts-export-server.log",types:["string"],envLink:"LOGGING_FILE",cliName:"logFile",description:"Log file name. Requires `logToFile` and `logDest` to be set",promptOptions:{type:"text"}},dest:{value:"log",types:["string"],envLink:"LOGGING_DEST",cliName:"logDest",description:"Path to store log files. Requires `logToFile` to be set",promptOptions:{type:"text"}},toConsole:{value:!0,types:["boolean"],envLink:"LOGGING_TO_CONSOLE",cliName:"logToConsole",description:"Enables or disables console logging",promptOptions:{type:"toggle"}},toFile:{value:!0,types:["boolean"],envLink:"LOGGING_TO_FILE",cliName:"logToFile",description:"Enables or disables logging to a file",promptOptions:{type:"toggle"}}},ui:{enable:{value:!1,types:["boolean"],envLink:"UI_ENABLE",cliName:"enableUi",description:"Enables or disables the UI for the export server",promptOptions:{type:"toggle"}},route:{value:"/",types:["string"],envLink:"UI_ROUTE",cliName:"uiRoute",description:"The endpoint route for the UI",promptOptions:{type:"text"}}},other:{nodeEnv:{value:"production",types:["string"],envLink:"OTHER_NODE_ENV",description:"The Node.js environment type",promptOptions:{type:"text"}},listenToProcessExits:{value:!0,types:["boolean"],envLink:"OTHER_LISTEN_TO_PROCESS_EXITS",description:"Whether or not to attach process.exit handlers",promptOptions:{type:"toggle"}},noLogo:{value:!1,types:["boolean"],envLink:"OTHER_NO_LOGO",description:"Display or skip printing the logo on startup",promptOptions:{type:"toggle"}},hardResetPage:{value:!1,types:["boolean"],envLink:"OTHER_HARD_RESET_PAGE",description:"Whether or not to reset the page content entirely",promptOptions:{type:"toggle"}},browserShellMode:{value:!0,types:["boolean"],envLink:"OTHER_BROWSER_SHELL_MODE",description:"Whether or not to set the browser to run in shell mode",promptOptions:{type:"toggle"}},validation:{value:!0,types:["boolean"],envLink:"OTHER_VALIDATION",description:"Whether or not to enable validation of options types",promptOptions:{type:"toggle"}}},debug:{enable:{value:!1,types:["boolean"],envLink:"DEBUG_ENABLE",cliName:"enableDebug",description:"Enables or disables debug mode for the underlying browser",promptOptions:{type:"toggle"}},headless:{value:!1,types:["boolean"],envLink:"DEBUG_HEADLESS",description:"Whether or not to set the browser to run in headless mode during debugging",promptOptions:{type:"toggle"}},devtools:{value:!1,types:["boolean"],envLink:"DEBUG_DEVTOOLS",description:"Enables or disables DevTools in headful mode",promptOptions:{type:"toggle"}},listenToConsole:{value:!1,types:["boolean"],envLink:"DEBUG_LISTEN_TO_CONSOLE",description:"Enables or disables listening to console messages from the browser",promptOptions:{type:"toggle"}},dumpio:{value:!1,types:["boolean"],envLink:"DEBUG_DUMPIO",description:"Redirects or not browser stdout and stderr to process.stdout and process.stderr",promptOptions:{type:"toggle"}},slowMo:{value:0,types:["number"],envLink:"DEBUG_SLOW_MO",description:"Delays Puppeteer operations by the specified milliseconds",promptOptions:{type:"number"}},debuggingPort:{value:9222,types:["number"],envLink:"DEBUG_DEBUGGING_PORT",description:"Port used for debugging",promptOptions:{type:"number"}}}};dotenv.config();const{coreScripts:coreScripts,moduleScripts:moduleScripts,indicatorScripts:indicatorScripts}=defaultConfig.highcharts;z.setErrorMap(_customErrorMap);const v={boolean:e=>e?z.boolean():z.union([z.enum(["true","1","false","0","undefined","null",""]).transform((e=>["undefined","null",""].includes(e)?null:"true"===e||"1"===e)),z.boolean()]).nullable(),string:e=>e?z.string().trim().refine((e=>!["false","undefined","null",""].includes(e)),{params:{errorMessage:"The string contains a forbidden value"}}):z.string().trim().transform((e=>["false","undefined","null",""].includes(e)?null:e)).nullable(),enum:(e,t)=>t?z.enum([...e]):z.enum([...e,"undefined","null",""]).transform((e=>["undefined","null",""].includes(e)?null:e)).nullable(),stringArray(e,t,o){const r=z.string().trim().array(),i=z.string().trim().transform((e=>(e.startsWith("[")&&(e=e.slice(1)),e.endsWith("]")&&(e=e.slice(0,-1)),e.split(t)))),n=t=>t.map((e=>e.trim())).filter(e);return o?r.transform(n):z.union([i,r]).transform(n).transform((e=>e.length?e:null)).nullable()},positiveNum:e=>e?z.number().positive():z.union([z.string().trim().refine((e=>!isNaN(Number(e))&&Number(e)>0||["undefined","null",""].includes(e)),{params:{errorMessage:"The value must be numeric and positive"}}).transform((e=>["undefined","null",""].includes(e)?null:Number(e))),z.number().positive()]).nullable(),nonNegativeNum:e=>e?z.number().nonnegative():z.union([z.string().trim().refine((e=>!isNaN(Number(e))&&Number(e)>=0||["undefined","null",""].includes(e)),{params:{errorMessage:"The value must be numeric and non-negative"}}).transform((e=>["undefined","null",""].includes(e)?null:Number(e))),z.number().nonnegative()]).nullable(),startsWith:(e,t)=>t?z.string().trim().refine((t=>e.some((e=>t.startsWith(e)))),{params:{errorMessage:`The value must be a string that starts with ${e.join(", ")}`}}):z.string().trim().refine((t=>e.some((e=>t.startsWith(e)))||["undefined","null",""].includes(t)),{params:{errorMessage:`The value must be a string that starts with ${e.join(", ")}`}}).transform((e=>["undefined","null",""].includes(e)?null:e)).nullable(),chartConfig:()=>z.union([z.string().trim().refine((e=>e.startsWith("{")&&e.endsWith("}")||["undefined","null",""].includes(e)),{params:{errorMessage:"The value must be a string that starts with '{' and ends with '}'"}}).transform((e=>["undefined","null",""].includes(e)?null:e)),z.object({}).passthrough()]).nullable(),additionalOptions:()=>z.union([z.string().trim().refine((e=>e.length>=6&&e.endsWith(".json")||e.startsWith("{")&&e.endsWith("}")||["undefined","null",""].includes(e)),{params:{errorMessage:"The value must be a string that ends with '.json' or starts with '{' and ends with '}'"}}).transform((e=>["undefined","null",""].includes(e)?null:e)),z.object({}).passthrough()]).nullable()},validators={args:e=>v.stringArray((e=>!["false","undefined","null",""].includes(e)),";",e),version:e=>e?z.string().trim().refine((e=>/^(latest|\d{1,2}(\.\d{1,2}){0,2})$/.test(e)),{params:{errorMessage:"The value must be 'latest', a major version, or in the form XX.YY.ZZ"}}):z.string().trim().refine((e=>/^(latest|\d{1,2}(\.\d{1,2}){0,2})$/.test(e)||["undefined","null",""].includes(e)),{params:{errorMessage:"The value must be 'latest', a major version, or in the form XX.YY.ZZ"}}).transform((e=>["undefined","null",""].includes(e)?null:e)).nullable(),cdnUrl:e=>v.startsWith(["http://","https://"],e),forceFetch:e=>v.boolean(e),cachePath:e=>v.string(e),adminToken:e=>v.string(e),coreScripts:e=>v.stringArray((e=>coreScripts.value.includes(e)),",",e),moduleScripts:e=>v.stringArray((e=>moduleScripts.value.includes(e)),",",e),indicatorScripts:e=>v.stringArray((e=>indicatorScripts.value.includes(e)),",",e),customScripts:e=>v.stringArray((e=>e.startsWith("https://")||e.startsWith("http://")),",",e),infile:e=>e?z.string().trim().refine((e=>e.length>=6&&e.endsWith(".json")||e.length>=5&&e.endsWith(".svg")),{params:{errorMessage:"The value must be a string that ends with .json or .svg"}}).nullable():z.string().trim().refine((e=>e.length>=6&&e.endsWith(".json")||e.length>=5&&e.endsWith(".svg")||["undefined","null",""].includes(e)),{params:{errorMessage:"The value must be a string that ends with .json or .svg"}}).transform((e=>["undefined","null",""].includes(e)?null:e)).nullable(),instr:()=>v.chartConfig(),options:()=>v.chartConfig(),svg:()=>z.string().trim().refine((e=>e.indexOf("=0||e.indexOf("=0||["false","undefined","null",""].includes(e)),{params:{errorMessage:"The value must be a string that contains '["false","undefined","null",""].includes(e)?null:e)).nullable(),outfile:e=>e?z.string().trim().refine((e=>e.length>=6&&e.endsWith(".jpeg")||e.length>=5&&(e.endsWith(".jpg")||e.endsWith(".png")||e.endsWith(".pdf")||e.endsWith(".svg"))),{params:{errorMessage:"The value must be a string that ends with .jpeg, .jpg, .png, .pdf, or .svg"}}).nullable():z.string().trim().refine((e=>e.length>=6&&e.endsWith(".jpeg")||e.length>=5&&(e.endsWith(".jpg")||e.endsWith(".png")||e.endsWith(".pdf")||e.endsWith(".svg"))||["undefined","null",""].includes(e)),{params:{errorMessage:"The value must be a string that ends with .jpeg, .jpg, .png, .pdf, or .svg"}}).transform((e=>["undefined","null",""].includes(e)?null:e)).nullable(),type:e=>v.enum(["jpeg","jpg","png","pdf","svg"],e),constr:e=>v.enum(["chart","stockChart","mapChart","ganttChart"],e),b64:e=>v.boolean(e),noDownload:e=>v.boolean(e),defaultHeight:e=>v.positiveNum(e),defaultWidth:e=>v.positiveNum(e),defaultScale:e=>e?z.number().gte(.1).lte(5):z.union([z.string().trim().refine((e=>!isNaN(Number(e))&&!0!==e&&!e.startsWith("[")&&Number(e)>=.1&&Number(e)<=5||["undefined","null",""].includes(e)),{params:{errorMessage:"The value must be within a 0.1 and 5.0 range"}}).transform((e=>["undefined","null",""].includes(e)?null:Number(e))),z.number().gte(.1).lte(5)]).nullable(),height(e){return this.defaultHeight(e).nullable()},width(e){return this.defaultWidth(e).nullable()},scale(e){return this.defaultScale(e).nullable()},globalOptions:()=>v.additionalOptions(),themeOptions:()=>v.additionalOptions(),batch:e=>v.string(e),rasterizationTimeout:e=>v.nonNegativeNum(e),allowCodeExecution:e=>v.boolean(e),allowFileResources:e=>v.boolean(e),customCode:e=>v.string(e),callback:e=>v.string(e),resources(e){const t=z.object({js:v.string(!1),css:v.string(!1),files:v.stringArray((e=>!["undefined","null",""].includes(e)),",",!0).nullable()}).partial(),o=z.string().trim().refine((e=>e.startsWith("{")&&e.endsWith("}")||e.length>=6&&e.endsWith(".json")),{params:{errorMessage:"The value must be a string that starts with '{' and ends with '}"}}),r=z.string().trim().refine((e=>e.startsWith("{")&&e.endsWith("}")||e.length>=6&&e.endsWith(".json")||["undefined","null",""].includes(e)),{params:{errorMessage:"The value must be a string that ends with .json"}}).transform((e=>["undefined","null",""].includes(e)?null:e));return e?z.union([t,o]).nullable():z.union([t,r]).nullable()},loadConfig:e=>v.string(e).refine((e=>null===e||e.length>=6&&e.endsWith(".json")),{params:{errorMessage:"The value must be a string that ends with .json"}}),createConfig(e){return this.loadConfig(e)},enableServer:e=>v.boolean(e),host:e=>v.string(e),port:e=>v.nonNegativeNum(e),uploadLimit:e=>v.positiveNum(e),serverBenchmarking:e=>v.boolean(e),proxyHost:e=>v.string(e),proxyPort:e=>v.nonNegativeNum(e).nullable(),proxyTimeout:e=>v.nonNegativeNum(e),enableRateLimiting:e=>v.boolean(e),maxRequests:e=>v.nonNegativeNum(e),window:e=>v.nonNegativeNum(e),delay:e=>v.nonNegativeNum(e),trustProxy:e=>v.boolean(e),skipKey:e=>v.string(e),skipToken:e=>v.string(e),enableSsl:e=>v.boolean(e),sslForce:e=>v.boolean(e),sslPort:e=>v.nonNegativeNum(e),sslCertPath:e=>v.string(e),minWorkers:e=>v.positiveNum(e),maxWorkers:e=>v.positiveNum(e),workLimit:e=>v.positiveNum(e),acquireTimeout:e=>v.nonNegativeNum(e),createTimeout:e=>v.nonNegativeNum(e),destroyTimeout:e=>v.nonNegativeNum(e),idleTimeout:e=>v.nonNegativeNum(e),createRetryInterval:e=>v.nonNegativeNum(e),reaperInterval:e=>v.nonNegativeNum(e),poolBenchmarking:e=>v.boolean(e),resourcesInterval:e=>v.nonNegativeNum(e),logLevel:e=>e?z.number().int().gte(0).lte(5):z.union([z.string().trim().refine((e=>!isNaN(Number(e))&&!0!==e&&!e.startsWith("[")&&Number.isInteger(Number(e))&&Number(e)>=0&&Number(e)<=5||["undefined","null",""].includes(e)),{params:{errorMessage:"The value must be within a 0 and 5 range"}}).transform((e=>["undefined","null",""].includes(e)?null:Number(e))),z.number().int().gte(0).lte(5)]).nullable(),logFile:e=>v.string(e).refine((e=>null===e||e.length>=5&&e.endsWith(".log")),{params:{errorMessage:"The value must be a string that ends with .log"}}),logDest:e=>v.string(e),logToConsole:e=>v.boolean(e),logToFile:e=>v.boolean(e),enableUi:e=>v.boolean(e),uiRoute:e=>v.startsWith(["/"],e),nodeEnv:e=>v.enum(["development","production","test"],e),listenToProcessExits:e=>v.boolean(e),noLogo:e=>v.boolean(e),hardResetPage:e=>v.boolean(e),browserShellMode:e=>v.boolean(e),validation:e=>v.boolean(e),enableDebug:e=>v.boolean(e),headless:e=>v.boolean(e),devtools:e=>v.boolean(e),listenToConsole:e=>v.boolean(e),dumpio:e=>v.boolean(e),slowMo:e=>v.nonNegativeNum(e),debuggingPort:e=>v.nonNegativeNum(e),requestId:()=>z.string().uuid({message:"The value must be a stringified UUID"}).nullable()},PuppeteerSchema=e=>z.object({args:validators.args(e)}).partial(),HighchartsSchema=e=>z.object({version:validators.version(e),cdnUrl:validators.cdnUrl(e),forceFetch:validators.forceFetch(e),cachePath:validators.cachePath(e),coreScripts:validators.coreScripts(e),moduleScripts:validators.moduleScripts(e),indicatorScripts:validators.indicatorScripts(e),customScripts:validators.customScripts(e)}).partial(),ExportSchema=e=>z.object({infile:validators.infile(e),instr:validators.instr(),options:validators.options(),svg:validators.svg(),outfile:validators.outfile(e),type:validators.type(e),constr:validators.constr(e),b64:validators.b64(e),noDownload:validators.noDownload(e),defaultHeight:validators.defaultHeight(e),defaultWidth:validators.defaultWidth(e),defaultScale:validators.defaultScale(e),height:validators.height(e),width:validators.width(e),scale:validators.scale(e),globalOptions:validators.globalOptions(),themeOptions:validators.themeOptions(),batch:validators.batch(!1),rasterizationTimeout:validators.rasterizationTimeout(e)}).partial(),CustomLogicSchema=e=>z.object({allowCodeExecution:validators.allowCodeExecution(e),allowFileResources:validators.allowFileResources(e),customCode:validators.customCode(!1),callback:validators.callback(!1),resources:validators.resources(e),loadConfig:validators.loadConfig(!1),createConfig:validators.createConfig(!1)}).partial(),ProxySchema=e=>z.object({host:validators.proxyHost(!1),port:validators.proxyPort(e),timeout:validators.proxyTimeout(e)}).partial(),RateLimitingSchema=e=>z.object({enable:validators.enableRateLimiting(e),maxRequests:validators.maxRequests(e),window:validators.window(e),delay:validators.delay(e),trustProxy:validators.trustProxy(e),skipKey:validators.skipKey(!1),skipToken:validators.skipToken(!1)}).partial(),SslSchema=e=>z.object({enable:validators.enableSsl(e),force:validators.sslForce(e),port:validators.sslPort(e),certPath:validators.sslCertPath(!1)}).partial(),ServerSchema=e=>z.object({enable:validators.enableServer(e).optional(),host:validators.host(e).optional(),port:validators.port(e).optional(),uploadLimit:validators.uploadLimit(e).optional(),benchmarking:validators.serverBenchmarking(e).optional(),proxy:ProxySchema(e).optional(),rateLimiting:RateLimitingSchema(e).optional(),ssl:SslSchema(e).optional()}),PoolSchema=e=>z.object({minWorkers:validators.minWorkers(e),maxWorkers:validators.maxWorkers(e),workLimit:validators.workLimit(e),acquireTimeout:validators.acquireTimeout(e),createTimeout:validators.createTimeout(e),destroyTimeout:validators.destroyTimeout(e),idleTimeout:validators.idleTimeout(e),createRetryInterval:validators.createRetryInterval(e),reaperInterval:validators.reaperInterval(e),benchmarking:validators.poolBenchmarking(e)}).partial(),LoggingSchema=e=>z.object({level:validators.logLevel(e),file:validators.logFile(e),dest:validators.logDest(e),toConsole:validators.logToConsole(e),toFile:validators.logToFile(e)}).partial(),UiSchema=e=>z.object({enable:validators.enableUi(e),route:validators.uiRoute(e)}).partial(),OtherSchema=e=>z.object({nodeEnv:validators.nodeEnv(e),listenToProcessExits:validators.listenToProcessExits(e),noLogo:validators.noLogo(e),hardResetPage:validators.hardResetPage(e),browserShellMode:validators.browserShellMode(e),validation:validators.validation(e)}).partial(),DebugSchema=e=>z.object({enable:validators.enableDebug(e),headless:validators.headless(e),devtools:validators.devtools(e),listenToConsole:validators.listenToConsole(e),dumpio:validators.dumpio(e),slowMo:validators.slowMo(e),debuggingPort:validators.debuggingPort(e)}).partial(),StrictConfigSchema=z.object({requestId:validators.requestId(),puppeteer:PuppeteerSchema(!0),highcharts:HighchartsSchema(!0),export:ExportSchema(!0),customLogic:CustomLogicSchema(!0),server:ServerSchema(!0),pool:PoolSchema(!0),logging:LoggingSchema(!0),ui:UiSchema(!0),other:OtherSchema(!0),debug:DebugSchema(!0)}),LooseConfigSchema=z.object({requestId:validators.requestId(),puppeteer:PuppeteerSchema(!1),highcharts:HighchartsSchema(!1),export:ExportSchema(!1),customLogic:CustomLogicSchema(!1),server:ServerSchema(!1),pool:PoolSchema(!1),logging:LoggingSchema(!1),ui:UiSchema(!1),other:OtherSchema(!1),debug:DebugSchema(!1)}),EnvSchema=z.object({PUPPETEER_ARGS:validators.args(!1),HIGHCHARTS_VERSION:validators.version(!1),HIGHCHARTS_CDN_URL:validators.cdnUrl(!1),HIGHCHARTS_FORCE_FETCH:validators.forceFetch(!1),HIGHCHARTS_CACHE_PATH:validators.cachePath(!1),HIGHCHARTS_ADMIN_TOKEN:validators.adminToken(!1),HIGHCHARTS_CORE_SCRIPTS:validators.coreScripts(!1),HIGHCHARTS_MODULE_SCRIPTS:validators.moduleScripts(!1),HIGHCHARTS_INDICATOR_SCRIPTS:validators.indicatorScripts(!1),HIGHCHARTS_CUSTOM_SCRIPTS:validators.customScripts(!1),EXPORT_INFILE:validators.infile(!1),EXPORT_INSTR:validators.instr(),EXPORT_OPTIONS:validators.options(),EXPORT_SVG:validators.svg(),EXPORT_BATCH:validators.batch(!1),EXPORT_OUTFILE:validators.outfile(!1),EXPORT_TYPE:validators.type(!1),EXPORT_CONSTR:validators.constr(!1),EXPORT_B64:validators.b64(!1),EXPORT_NO_DOWNLOAD:validators.noDownload(!1),EXPORT_HEIGHT:validators.height(!1),EXPORT_WIDTH:validators.width(!1),EXPORT_SCALE:validators.scale(!1),EXPORT_DEFAULT_HEIGHT:validators.defaultHeight(!1),EXPORT_DEFAULT_WIDTH:validators.defaultWidth(!1),EXPORT_DEFAULT_SCALE:validators.defaultScale(!1),EXPORT_GLOBAL_OPTIONS:validators.globalOptions(),EXPORT_THEME_OPTIONS:validators.themeOptions(),EXPORT_RASTERIZATION_TIMEOUT:validators.rasterizationTimeout(!1),CUSTOM_LOGIC_ALLOW_CODE_EXECUTION:validators.allowCodeExecution(!1),CUSTOM_LOGIC_ALLOW_FILE_RESOURCES:validators.allowFileResources(!1),CUSTOM_LOGIC_CUSTOM_CODE:validators.customCode(!1),CUSTOM_LOGIC_CALLBACK:validators.callback(!1),CUSTOM_LOGIC_RESOURCES:validators.resources(!1),CUSTOM_LOGIC_LOAD_CONFIG:validators.loadConfig(!1),CUSTOM_LOGIC_CREATE_CONFIG:validators.createConfig(!1),SERVER_ENABLE:validators.enableServer(!1),SERVER_HOST:validators.host(!1),SERVER_PORT:validators.port(!1),SERVER_UPLOAD_LIMIT:validators.uploadLimit(!1),SERVER_BENCHMARKING:validators.serverBenchmarking(!1),SERVER_PROXY_HOST:validators.proxyHost(!1),SERVER_PROXY_PORT:validators.proxyPort(!1),SERVER_PROXY_TIMEOUT:validators.proxyTimeout(!1),SERVER_RATE_LIMITING_ENABLE:validators.enableRateLimiting(!1),SERVER_RATE_LIMITING_MAX_REQUESTS:validators.maxRequests(!1),SERVER_RATE_LIMITING_WINDOW:validators.window(!1),SERVER_RATE_LIMITING_DELAY:validators.delay(!1),SERVER_RATE_LIMITING_TRUST_PROXY:validators.trustProxy(!1),SERVER_RATE_LIMITING_SKIP_KEY:validators.skipKey(!1),SERVER_RATE_LIMITING_SKIP_TOKEN:validators.skipToken(!1),SERVER_SSL_ENABLE:validators.enableSsl(!1),SERVER_SSL_FORCE:validators.sslForce(!1),SERVER_SSL_PORT:validators.sslPort(!1),SERVER_SSL_CERT_PATH:validators.sslCertPath(!1),POOL_MIN_WORKERS:validators.minWorkers(!1),POOL_MAX_WORKERS:validators.maxWorkers(!1),POOL_WORK_LIMIT:validators.workLimit(!1),POOL_ACQUIRE_TIMEOUT:validators.acquireTimeout(!1),POOL_CREATE_TIMEOUT:validators.createTimeout(!1),POOL_DESTROY_TIMEOUT:validators.destroyTimeout(!1),POOL_IDLE_TIMEOUT:validators.idleTimeout(!1),POOL_CREATE_RETRY_INTERVAL:validators.createRetryInterval(!1),POOL_REAPER_INTERVAL:validators.reaperInterval(!1),POOL_BENCHMARKING:validators.poolBenchmarking(!1),LOGGING_LEVEL:validators.logLevel(!1),LOGGING_FILE:validators.logFile(!1),LOGGING_DEST:validators.logDest(!1),LOGGING_TO_CONSOLE:validators.logToConsole(!1),LOGGING_TO_FILE:validators.logToFile(!1),UI_ENABLE:validators.enableUi(!1),UI_ROUTE:validators.uiRoute(!1),OTHER_NODE_ENV:validators.nodeEnv(!1),OTHER_LISTEN_TO_PROCESS_EXITS:validators.listenToProcessExits(!1),OTHER_NO_LOGO:validators.noLogo(!1),OTHER_HARD_RESET_PAGE:validators.hardResetPage(!1),OTHER_BROWSER_SHELL_MODE:validators.browserShellMode(!1),OTHER_VALIDATION:validators.validation(!1),DEBUG_ENABLE:validators.enableDebug(!1),DEBUG_HEADLESS:validators.headless(!1),DEBUG_DEVTOOLS:validators.devtools(!1),DEBUG_LISTEN_TO_CONSOLE:validators.listenToConsole(!1),DEBUG_DUMPIO:validators.dumpio(!1),DEBUG_SLOW_MO:validators.slowMo(!1),DEBUG_DEBUGGING_PORT:validators.debuggingPort(!1)}),envs=EnvSchema.partial().parse(process.env);function strictValidate(e){return StrictConfigSchema.partial().parse(e)}function looseValidate(e){return LooseConfigSchema.partial().parse(e)}function _customErrorMap(e,t){const o=e.path.join("."),r=`Invalid value for the ${o}`;if(e.code===z.ZodIssueCode.invalid_type)return e.received===z.ZodParsedType.undefined?{message:`${r} - No value was provided.`}:{message:`${r} - Invalid type. ${t.defaultError}.`};if(e.code===z.ZodIssueCode.custom&&e.params?.errorMessage)return{message:`${r} - ${e.params?.errorMessage}, received '${t.data}'.`};if(e.code===z.ZodIssueCode.invalid_union){let t=`Multiple errors occurred for the ${o}:\n`;return e.unionErrors.forEach((e=>{const o=e.issues[0].message.indexOf("-");t+=-1!==o?`${e.issues[0].message}\n`.substring(o):`${e.issues[0].message}\n`})),{message:t}}return{message:`${r} - ${t.defaultError}.`}}class ExportError extends Error{constructor(e,t){super(),this.message=e,this.stackMessage=e,t&&(this.statusCode=t)}setError(e){return this.error=e,e.name&&(this.name=e.name),e.statusCode&&(this.statusCode=e.statusCode),e.stack&&(this.stackMessage=e.message,this.stack=e.stack),this}}const globalOptions=_initOptions(defaultConfig),nestedProps=_createNestedProps(defaultConfig),absoluteProps=_createAbsoluteProps(defaultConfig);function getOptions(e=!0){return e?deepCopy(globalOptions):globalOptions}function updateOptions(e,t=!1,o=!0){return _mergeOptions(getOptions(t),validateOptions(e,o))}function mapToNewOptions(e){const t={};if(isObject(e))for(const[o,r]of Object.entries(e)){const e=nestedProps[o]?nestedProps[o].split("."):[];e.reduce(((t,o,i)=>t[o]=e.length-1===i?r:t[o]||{}),t)}else log(2,"[config] No correct object with options was provided. Returning an empty object.");return t}function validateOption(e,t,o=!0){if(!getOptions().other.validation)return t;try{return validators[e](o).parse(t)}catch(t){throw logZodIssues(1,t.issues,`[validation] The ${e} option validation error`),new ExportError(`[validation] The ${e} option validation error`,400)}}function validateOptions(e,t=!0){if(!getOptions().other.validation)return e;try{return t?strictValidate(e):looseValidate(e)}catch(e){throw logZodIssues(1,e.issues,"[validation] Options validation error"),new ExportError("[validation] Options validation error",400)}}function isAllowedConfig(config,toString=!1,allowFunctions=!1){try{if(!isObject(config)&&"string"!=typeof config)return null;const objectConfig="string"==typeof config?allowFunctions?eval(`(${config})`):JSON.parse(config):config,stringifiedOptions=_optionsStringify(objectConfig,allowFunctions,!1),parsedOptions=allowFunctions?JSON.parse(_optionsStringify(objectConfig,allowFunctions,!0),((_,value)=>"string"==typeof value&&value.startsWith("function")?eval(`(${value})`):value)):JSON.parse(stringifiedOptions);return toString?stringifiedOptions:parsedOptions}catch(e){return null}}function _initOptions(e){const t={};for(const[o,r]of Object.entries(e))Object.prototype.hasOwnProperty.call(r,"value")?void 0!==envs[r.envLink]&&null!==envs[r.envLink]?t[o]=envs[r.envLink]:t[o]=r.value:t[o]=_initOptions(r);return t}function _mergeOptions(e,t){if(isObject(e)&&isObject(t))for(const[o,r]of Object.entries(t))e[o]=isObject(r)&&!absoluteProps.includes(o)&&void 0!==e[o]?_mergeOptions(e[o],r):void 0!==r?r:e[o]||null;return e}function _optionsStringify(e,t,o){return JSON.stringify(e,((e,r)=>{if("string"==typeof r&&(r=r.trim()),"function"==typeof r||"string"==typeof r&&r.startsWith("function")&&r.endsWith("}")){if(t)return o?`"EXP_FUN${(r+"").replaceAll(/\s+/g," ")}EXP_FUN"`:`EXP_FUN${(r+"").replaceAll(/\s+/g," ")}EXP_FUN`;throw new Error}return r})).replaceAll(o?/\\"EXP_FUN|EXP_FUN\\"/g:/"EXP_FUN|EXP_FUN"/g,"")}function _createNestedProps(e,t={},o=""){return Object.keys(e).forEach((r=>{const i=e[r];void 0===i.value?_createNestedProps(i,t,`${o}.${r}`):(t[i.cliName||r]=`${o}.${r}`.substring(1),void 0!==i.legacyName&&(t[i.legacyName]=`${o}.${r}`.substring(1)))})),t}function _createAbsoluteProps(e,t=[]){return Object.keys(e).forEach((o=>{const r=e[o];void 0===r.types?_createAbsoluteProps(r,t):r.types.includes("Object")&&t.push(o)})),t}async function get$1(e,t={}){return new Promise(((o,r)=>{_getProtocolModule(e).get(e,t,(e=>{let t="";e.on("data",(e=>{t+=e})),e.on("end",(()=>{t||r("Nothing was fetched from the URL."),e.text=t,o(e)}))})).on("error",(e=>{r(e)}))}))}function _getProtocolModule(e){return e.startsWith("https")?https:http}const cache={cdnUrl:"https://code.highcharts.com",activeManifest:{},sources:"",hcVersion:""};async function checkCache(e,t){try{let o;const r=getCachePath(),i=join(r,"manifest.json"),n=join(r,"sources.js");if(!existsSync(r)&&mkdirSync(r,{recursive:!0}),!existsSync(i)||e.forceFetch)log(3,"[cache] Fetching and caching Highcharts dependencies."),o=await _updateCache(e,t,n);else{let r=!1;const s=JSON.parse(readFileSync(i),"utf8");if(s.modules&&Array.isArray(s.modules)){const e={};s.modules.forEach((t=>e[t]=1)),s.modules=e}const{coreScripts:a,moduleScripts:l,indicatorScripts:c}=e,p=a.length+l.length+c.length;s.version!==e.version?(log(2,"[cache] A Highcharts version mismatch in the cache, need to re-fetch."),r=!0):Object.keys(s.modules||{}).length!==p?(log(2,"[cache] The cache and the requested modules do not match, need to re-fetch."),r=!0):r=(l||[]).some((e=>{if(!s.modules[e])return log(2,`[cache] The ${e} is missing in the cache, need to re-fetch.`),!0})),r?o=await _updateCache(e,t,n):(log(3,"[cache] Dependency cache is up to date, proceeding."),cache.sources=readFileSync(n,"utf8"),o=s.modules,cache.hcVersion=_extractHcVersion(cache.sources))}await _saveConfigToManifest(e.version,o)}catch(e){throw new ExportError("[cache] Could not configure cache and create or update the config manifest.",500).setError(e)}}function getHcVersion(){return cache.hcVersion}async function updateHcVersion(e){const t=updateOptions({highcharts:{version:e}});await checkCache(t.highcharts,t.server.proxy)}function getCachePath(){return getAbsolutePath(getOptions().highcharts.cachePath)}async function _saveConfigToManifest(e,t={}){cache.activeManifest={version:e,modules:t},log(3,"[cache] Writing a new manifest.");try{writeFileSync(join(getCachePath(),"manifest.json"),JSON.stringify(cache.activeManifest),"utf8")}catch(e){throw new ExportError("[cache] Error writing the cache manifest.",500).setError(e)}}async function _updateCache(e,t,o){try{const r="latest"===e.version?null:`${e.version}`;log(3,`[cache] Updating cache version to Highcharts: ${r||"latest"}.`);const i=e.cdnUrl||cache.cdnUrl,n=_configureRequest(t),s={};return cache.sources=(await Promise.all([...e.coreScripts.map((e=>_fetchScript(r?`${i}/${r}/${e}`:`${i}/${e}`,n,s,!0))),...e.moduleScripts.map((e=>_fetchScript("map"===e?r?`${i}/maps/${r}/modules/${e}`:`${i}/maps/modules/${e}`:r?`${i}/${r}/modules/${e}`:`${i}/modules/${e}`,n,s))),...e.indicatorScripts.map((e=>_fetchScript(r?`${i}/stock/${r}/indicators/${e}`:`${i}/stock/indicators/${e}`,n,s))),...e.customScripts.map((e=>_fetchScript(`${e}`,n)))])).join(";\n"),cache.hcVersion=_extractHcVersion(cache.sources),writeFileSync(o,cache.sources),s}catch(e){throw new ExportError("[cache] Unable to update the local Highcharts cache.",500).setError(e)}}async function _fetchScript(e,t,o,r=!1){e.endsWith(".js")&&(e=e.substring(0,e.length-3)),log(4,`[cache] Fetching script - ${e}.js`);const i=await get$1(`${e}.js`,t);if(200===i.statusCode&&"string"==typeof i.text){if(o){o[_extractModuleName(e)]=1}return i.text}if(r)throw new ExportError(`[cache] Could not fetch the ${e}.js. The script might not exist in the requested version (status code: ${i.statusCode}).`,404).setError(i);log(2,`[cache] Could not fetch the ${e}.js. The script might not exist in the requested version.`)}function _configureRequest(e){const t=e.host,o=e.port;if(t&&o)try{return{agent:new HttpsProxyAgent({host:t,port:o}),timeout:e.timeout}}catch(e){throw new ExportError("[cache] Could not create a Proxy Agent.",500).setError(e)}return{}}function _extractHcVersion(e){return e.substring(0,e.indexOf("*/")).replace("/*","").replace("*/","").replace(/\n/g,"").trim()}function _extractModuleName(e){return e.replace(/(.*)\/|(.*)modules\/|stock\/(.*)indicators\/|maps\/(.*)modules\//gi,"")}function setupHighcharts(){Highcharts.animObject=function(){return{duration:0}}}async function createChart(e,t){const{getOptions:o,setOptions:r,merge:i,wrap:n}=Highcharts;Highcharts.setOptionsObj=i(!1,{},o()),window.isRenderComplete=!1,n(Highcharts.Chart.prototype,"init",(function(e,t,o){((t=i(t,{exporting:{enabled:!1},plotOptions:{series:{label:{enabled:!1}}},tooltip:{}})).series||[]).forEach((function(e){e.animation=!1})),window.onHighchartsRender||(window.onHighchartsRender=Highcharts.addEvent(this,"render",(()=>{window.isRenderComplete=!0}))),e.apply(this,[t,o])})),n(Highcharts.Series.prototype,"init",(function(e,t,o){e.apply(this,[t,o])}));const s={chart:{animation:!1,height:e.height,width:e.width},exporting:{enabled:!1}},a=new Function(`return ${e.instr}`)(),l=new Function(`return ${e.themeOptions}`)(),c=i(!1,l,a,s),p=t.callback?new Function(`return ${t.callback}`)():null;t.customCode&&new Function("options",t.customCode)(a);const u=new Function(`return ${e.globalOptions}`)();u&&r(u),Highcharts[e.constr]("container",c,p);const d=Array.from(document.querySelectorAll(".highcharts-container image"));await Promise.race([Promise.all(d.map((e=>e.complete&&0!==e.naturalHeight?Promise.resolve():new Promise((t=>e.addEventListener("load",t,{once:!0})))))),new Promise((e=>setTimeout(e,2e3)))]);const g=o();for(const e in g)"function"!=typeof g[e]&&delete g[e];r(Highcharts.setOptionsObj),Highcharts.setOptionsObj={}}const pageTemplate=readFileSync(join(__dirname,"templates","template.html"),"utf8");let browser=null;async function createBrowser(e){const{debug:t,other:o}=getOptions(),{enable:r,...i}=t,n={headless:!o.browserShellMode||"shell",userDataDir:"tmp",args:e||[],handleSIGINT:!1,handleSIGTERM:!1,handleSIGHUP:!1,waitForInitialPage:!1,defaultViewport:null,...r&&i};if(!browser){let e=0;const t=async()=>{try{log(3,`[browser] Attempting to launch and get a browser instance (try ${++e}).`),browser=await puppeteer.launch(n)}catch(o){if(logWithStack(1,o,"[browser] Failed to launch a browser instance."),!(e<25))throw o;log(3,`[browser] Retry to open a browser (${e} out of 25).`),await new Promise((e=>setTimeout(e,4e3))),await t()}};try{await t(),"shell"===n.headless&&log(3,"[browser] Launched browser in shell mode."),r&&log(3,"[browser] Launched browser in debug mode.")}catch(e){throw new ExportError("[browser] Maximum retries to open a browser instance reached.",500).setError(e)}if(!browser)throw new ExportError("[browser] Cannot find a browser to open.",500)}return browser}async function closeBrowser(){browser&&browser.connected&&await browser.close(),browser=null,log(4,"[browser] Closed the browser.")}async function newPage(e){if(!browser||!browser.connected)throw new ExportError("[browser] Browser is not yet connected.",500);if(e.page=await browser.newPage(),await e.page.setCacheEnabled(!1),await _setPageContent(e.page),_setPageEvents(e.page),!e.page||e.page.isClosed())throw new ExportError("[browser] The page is invalid or closed.",400)}async function clearPage(e,t=!1){try{if(e.page&&!e.page.isClosed())return t?(await e.page.goto("about:blank",{waitUntil:"domcontentloaded"}),await _setPageContent(e.page)):await e.page.evaluate((()=>{document.body.innerHTML='
'})),!0}catch(t){logWithStack(2,t,`[pool] Pool resource [${e.id}] - Content of the page could not be cleared.`),e.workCount=getOptions().pool.workLimit+1}return!1}async function addPageResources(e,t){const o=[],r=t.resources;if(r){const i=[];if(r.js&&i.push({content:r.js}),r.files)for(const e of r.files){const t=!e.startsWith("http");i.push(t?{content:readFileSync(getAbsolutePath(e),"utf8")}:{url:e})}for(const t of i)try{o.push(await e.addScriptTag(t))}catch(e){logWithStack(2,e,"[browser] The JS resource cannot be loaded.")}i.length=0;const n=[];if(r.css){const i=r.css.match(/@import\s*([^;]*);/g);if(i)for(let e of i)e&&(e=e.replace("url(","").replace("@import","").replace(/"/g,"").replace(/'/g,"").replace(/;/,"").replace(/\)/g,"").trim(),e.startsWith("http")?n.push({url:e}):t.allowFileResources&&n.push({path:getAbsolutePath(e)}));n.push({content:r.css.replace(/@import\s*([^;]*);/g,"")||" "});for(const t of n)try{o.push(await e.addStyleTag(t))}catch(e){logWithStack(2,e,"[browser] The CSS resource cannot be loaded.")}n.length=0}}return o}async function clearPageResources(e,t){try{for(const e of t)await e.dispose();await e.evaluate((()=>{if("undefined"!=typeof Highcharts){const e=Highcharts.charts;if(Array.isArray(e)&&e.length)for(const t of e)t&&t.destroy(),Highcharts.charts.shift()}const[...e]=document.getElementsByTagName("script"),[,...t]=document.getElementsByTagName("style"),[...o]=document.getElementsByTagName("link");for(const r of[...e,...t,...o])r.remove()}))}catch(e){logWithStack(2,e,"[browser] Could not clear page's resources.")}}async function _setPageContent(e){await e.setContent(pageTemplate,{waitUntil:"domcontentloaded"}),await e.addScriptTag({path:join(getCachePath(),"sources.js")}),await e.evaluate(setupHighcharts)}function _setPageEvents(e){const{debug:t}=getOptions();e.on("pageerror",(async()=>{e.isClosed()})),t.enable&&t.listenToConsole&&e.on("console",(e=>{console.log(`[debug] ${e.text()}`)}))}var cssTemplate=()=>"\n\nhtml, body {\n margin: 0;\n padding: 0;\n box-sizing: border-box;\n}\n\n#table-div, #sliders, #datatable, #controls, .ld-row {\n display: none;\n height: 0;\n}\n\n#chart-container {\n box-sizing: border-box;\n margin: 0;\n overflow: auto;\n font-size: 0;\n}\n\n#chart-container > figure, div {\n margin-top: 0 !important;\n margin-bottom: 0 !important;\n}\n\n",svgTemplate=e=>`\n\n\n \n \n Highcharts Export\n \n \n \n
\n ${e}\n
\n \n\n\n`;async function puppeteerExport(e,t,o){const r=[];try{let i=!1;if(t.svg){if(log(4,"[export] Treating as SVG input."),"svg"===t.type)return t.svg;i=!0,await e.setContent(svgTemplate(t.svg),{waitUntil:"domcontentloaded"})}else log(4,"[export] Treating as JSON config."),await e.evaluate(createChart,t,o);r.push(...await addPageResources(e,o));const n=await _getChartSize(e,i,t.scale),{x:s,y:a}=await _getClipRegion(e),l=Math.abs(Math.ceil(n.chartHeight||t.height)),c=Math.abs(Math.ceil(n.chartWidth||t.width));let p;switch(await e.setViewport({height:l,width:c,deviceScaleFactor:i?1:parseFloat(t.scale)}),t.type){case"svg":p=await _createSVG(e);break;case"png":case"jpeg":p=await _createImage(e,t.type,{width:c,height:l,x:s,y:a},t.rasterizationTimeout);break;case"pdf":p=await _createPDF(e,l,c,t.rasterizationTimeout);break;default:throw new ExportError(`[export] Unsupported output format: ${t.type}.`,400)}return await clearPageResources(e,r),p}catch(t){return await clearPageResources(e,r),t}}async function _getClipRegion(e){return e.$eval("#chart-container",(e=>{const{x:t,y:o,width:r,height:i}=e.getBoundingClientRect();return{x:t,y:o,width:r,height:Math.trunc(i>1?i:500)}}))}async function _getChartSize(e,t,o){return t?await e.evaluate((e=>{const t=document.querySelector("#chart-container svg:first-of-type"),o=t.height.baseVal.value*e,r=t.width.baseVal.value*e;return document.body.style.zoom=e,document.body.style.margin="0px",{chartHeight:o,chartWidth:r}}),parseFloat(o)):await e.evaluate((()=>{const{chartHeight:e,chartWidth:t}=window.Highcharts.charts[0];return document.body.style.zoom=1,{chartHeight:e,chartWidth:t}}))}async function _createSVG(e){return e.$eval("#container svg:first-of-type",(e=>e.outerHTML))}async function _createImage(e,t,o,r){return Promise.race([e.screenshot({type:t,clip:o,encoding:"base64",fullPage:!1,optimizeForSpeed:!0,captureBeyondViewport:!0,..."png"!==t?{quality:80}:{},omitBackground:"png"==t}),new Promise(((e,t)=>setTimeout((()=>t(new ExportError("Rasterization timeout",408))),r||1500)))])}async function _createPDF(e,t,o,r){return await e.emulateMediaType("screen"),e.pdf({height:t+1,width:o,encoding:"base64",timeout:r||1500})}let pool=null;const poolStats={exportsAttempted:0,exportsPerformed:0,exportsDropped:0,exportsFromSvg:0,exportsFromOptions:0,exportsFromSvgAttempts:0,exportsFromOptionsAttempts:0,timeSpent:0,timeSpentAverage:0};async function initPool(e,t){await createBrowser(t);try{if(log(3,`[pool] Initializing pool with workers: min ${e.minWorkers}, max ${e.maxWorkers}.`),pool)return void log(4,"[pool] Already initialized, please kill it before creating a new one.");e.minWorkers>e.maxWorkers&&(e.minWorkers=e.maxWorkers),pool=new Pool({..._factory(e),min:e.minWorkers,max:e.maxWorkers,acquireTimeoutMillis:e.acquireTimeout,createTimeoutMillis:e.createTimeout,destroyTimeoutMillis:e.destroyTimeout,idleTimeoutMillis:e.idleTimeout,createRetryIntervalMillis:e.createRetryInterval,reapIntervalMillis:e.reaperInterval,propagateCreateError:!1}),pool.on("release",(async e=>{const t=await clearPage(e,!1);log(4,`[pool] Pool resource [${e.id}] - Releasing a worker. Clear page status: ${t}.`)})),pool.on("destroySuccess",((e,t)=>{log(4,`[pool] Pool resource [${t.id}] - Destroyed a worker successfully.`),t.page=null}));const t=[];for(let o=0;o{pool.release(e)})),log(3,"[pool] The pool is ready"+(t.length?` with ${t.length} initial resources waiting.`:"."))}catch(e){throw new ExportError("[pool] Could not configure and create the pool of workers.",500).setError(e)}}async function killPool(){if(log(3,"[pool] Killing pool with all workers and closing browser."),pool){for(const e of pool.used)pool.release(e.resource);pool.destroyed||(await pool.destroy(),log(4,"[pool] Destroyed the pool of resources.")),pool=null}await closeBrowser()}async function postWork(e){let t;try{if(log(4,"[pool] Work received, starting to process."),++poolStats.exportsAttempted,e.pool.benchmarking&&_getPoolInfo(),!pool)throw new ExportError("[pool] Work received, but pool has not been started.",500);const o=measureTime();try{log(4,"[pool] Acquiring a worker handle."),t=await pool.acquire().promise,e.server.benchmarking&&log(5,"[benchmark] "+(e.requestId?`Request [${e.requestId}] - `:""),`Acquiring a worker handle took ${o()}ms.`)}catch(t){throw new ExportError(`[pool] ${e.requestId?`Request [${e.requestId}] - `:""}Error encountered when acquiring an available entry: ${o()}ms.`,400).setError(t)}if(log(4,"[pool] Acquired a worker handle."),!t.page)throw t.workCount=e.pool.workLimit+1,new ExportError("[pool] Resolved worker page is invalid: the pool setup is wonky.",400);log(4,`[pool] Pool resource [${t.id}] - Starting work on this pool entry.`);const r=measureTime(),i=await puppeteerExport(t.page,e.export,e.customLogic);if(i instanceof Error)throw"Rasterization timeout"===i.message&&(t.workCount=e.pool.workLimit+1,t.page=null),"TimeoutError"===i.name||"Rasterization timeout"===i.message?new ExportError(`[pool] ${e.requestId?`Request [${e.requestId}] - `:""}Rasterization timeout: your chart may be too complex or large, and failed to render within the allotted time.`).setError(i):new ExportError(`[pool] ${e.requestId?`Request [${e.requestId}] - `:""}Error encountered during export: ${r()}ms.`).setError(i);return e.server.benchmarking&&log(5,"[benchmark] "+(e.requestId?`Request [${e.requestId}] - `:""),`Exporting a chart sucessfully took ${r()}ms.`),pool.release(t),poolStats.timeSpent+=r(),poolStats.timeSpentAverage=poolStats.timeSpent/++poolStats.exportsPerformed,log(4,`[pool] Work completed in ${r()}ms.`),{result:i,options:e}}catch(e){throw++poolStats.exportsDropped,t&&pool.release(t),e}}function getPoolStats(){return poolStats}function getPoolInfoJSON(){return{min:pool.min,max:pool.max,used:pool.numUsed(),available:pool.numFree(),allCreated:pool.numUsed()+pool.numFree(),pendingAcquires:pool.numPendingAcquires(),pendingCreates:pool.numPendingCreates(),pendingValidations:pool.numPendingValidations(),pendingDestroys:pool.pendingDestroys.length,absoluteAll:pool.numUsed()+pool.numFree()+pool.numPendingAcquires()+pool.numPendingCreates()+pool.numPendingValidations()+pool.pendingDestroys.length}}function _getPoolInfo(){const{min:e,max:t,used:o,available:r,allCreated:i,pendingAcquires:n,pendingCreates:s,pendingValidations:a,pendingDestroys:l,absoluteAll:c}=getPoolInfoJSON();log(5,`[pool] The minimum number of resources allowed by pool: ${e}.`),log(5,`[pool] The maximum number of resources allowed by pool: ${t}.`),log(5,`[pool] The number of used resources: ${o}.`),log(5,`[pool] The number of free resources: ${r}.`),log(5,`[pool] The number of all created (used and free) resources: ${i}.`),log(5,`[pool] The number of resources waiting to be acquired: ${n}.`),log(5,`[pool] The number of resources waiting to be created: ${s}.`),log(5,`[pool] The number of resources waiting to be validated: ${a}.`),log(5,`[pool] The number of resources waiting to be destroyed: ${l}.`),log(5,`[pool] The number of all resources: ${c}.`)}function _factory(e){return{create:async()=>{const t={id:v4(),workCount:Math.round(Math.random()*(e.workLimit/2))};try{const e=getNewDateTime();return await newPage(t),log(3,`[pool] Pool resource [${t.id}] - Successfully created a worker, took ${getNewDateTime()-e}ms.`),t}catch(e){throw log(3,`[pool] Pool resource [${t.id}] - Error encountered when creating a new page.`),e}},validate:async t=>t.page?t.page.isClosed()?(log(3,`[pool] Pool resource [${t.id}] - Validation failed (page is closed or invalid).`),!1):t.page.mainFrame().detached?(log(3,`[pool] Pool resource [${t.id}] - Validation failed (page's frame is detached).`),!1):!(e.workLimit&&++t.workCount>e.workLimit)||(log(3,`[pool] Pool resource [${t.id}] - Validation failed (exceeded the ${e.workLimit} works per resource limit).`),!1):(log(3,`[pool] Pool resource [${t.id}] - Validation failed (no valid page is found).`),!1),destroy:async e=>{if(log(3,`[pool] Pool resource [${e.id}] - Destroying a worker.`),e.page&&!e.page.isClosed())try{e.page.removeAllListeners("pageerror"),e.page.removeAllListeners("console"),e.page.removeAllListeners("framedetached"),await e.page.close()}catch(t){throw log(3,`[pool] Pool resource [${e.id}] - Page could not be closed upon destroying.`),t}}}}function sanitize(e){const t=new JSDOM("").window;return DOMPurify(t).sanitize(e,{ADD_TAGS:["foreignObject"]})}let allowCodeExecution=!1;async function singleExport(e){if(!e||!e.export)throw new ExportError("[chart] No expected `export` options were found. Please provide one of the following options: `infile`, `instr`, `options`, or `svg` to generate a valid image.",400);await startExport({export:e.export,customLogic:e.customLogic},(async(e,t)=>{if(e)throw e;const{b64:o,outfile:r,type:i}=t.options.export;try{o?writeFileSync(`${r.split(".").shift()||"chart"}.txt`,getBase64(t.result,i)):writeFileSync(r||`chart.${i}`,"svg"!==i?Buffer.from(t.result,"base64"):t.result)}catch(e){throw new ExportError("[chart] Error while saving a chart.",500).setError(e)}await killPool()}))}async function batchExport(e){if(!(e&&e.export&&e.export.batch))throw new ExportError("[chart] No expected `export` options were found. Please provide the `batch` option to generate valid images.",400);{const t=[];for(let o of e.export.batch.split(";")||[])o=o.split("="),2===o.length?t.push(startExport({export:{...e.export,infile:o[0],outfile:o[1]},customLogic:e.customLogic},((e,t)=>{if(e)throw e;const{b64:o,outfile:r,type:i}=t.options.export;try{o?writeFileSync(`${r.split(".").shift()||"chart"}.txt`,getBase64(t.result,i)):writeFileSync(r,"svg"!==i?Buffer.from(t.result,"base64"):t.result)}catch(e){throw new ExportError("[chart] Error while saving a chart.",500).setError(e)}}))):log(2,"[chart] No correct pair found for the batch export.");const o=await Promise.allSettled(t);await killPool(),o.forEach(((e,t)=>{e.reason&&logWithStack(1,e.reason,`[chart] Batch export number ${t+1} could not be correctly completed.`)}))}}async function startExport(e,t){try{if(!isObject(e))throw new ExportError("[chart] Incorrect value of the provided `imageOptions`. Needs to be an object.",400);const o=updateOptions({export:e.export,customLogic:e.customLogic},!0),r=o.export;if(log(4,"[chart] Starting the exporting process."),null!==r.infile){let e;log(4,"[chart] Attempting to export from a file input.");try{e=readFileSync(getAbsolutePath(r.infile),"utf8")}catch(e){throw new ExportError("[chart] Error loading content from a file input.",400).setError(e)}if(r.infile.endsWith(".svg"))r.svg=validateOption("svg",e);else{if(!r.infile.endsWith(".json"))throw new ExportError("[chart] Incorrect value of the `infile` option.",400);r.instr=validateOption("instr",e)}}if(null!==r.svg){log(4,"[chart] Attempting to export from an SVG input."),++getPoolStats().exportsFromSvgAttempts;const e=await _exportFromSvg(sanitize(r.svg),o);return++getPoolStats().exportsFromSvg,t(null,e)}if(null!==r.instr||null!==r.options){log(4,"[chart] Attempting to export from options input."),++getPoolStats().exportsFromOptionsAttempts;const e=await _exportFromOptions(r.instr||r.options,o);return++getPoolStats().exportsFromOptions,t(null,e)}return t(new ExportError("[chart] No valid input specified. Check if at least one of the following parameters is correctly set: 'infile', 'instr', 'options', or 'svg'.",400))}catch(e){return t(e)}}function getAllowCodeExecution(){return allowCodeExecution}function setAllowCodeExecution(e){allowCodeExecution=e}async function _exportFromSvg(e,t){if("string"==typeof e&&(e.indexOf("=0||e.indexOf("=0))return log(4,"[chart] Parsing input as SVG."),t.export.svg=e,t.export.options=null,t.export.instr=null,_prepareExport(t);throw new ExportError("[chart] Not a correct SVG input.",400)}async function _exportFromOptions(e,t){log(4,"[chart] Parsing input from options.");const o=isAllowedConfig(e,!0,t.customLogic.allowCodeExecution);if(null===o||"string"!=typeof o||!o.startsWith("{")||!o.endsWith("}"))throw new ExportError("[chart] Invalid configuration provided - Only options configurations and SVG are allowed for this server. If this is your server, JavaScript custom code can be enabled by starting the server with the `allowCodeExecution` options set to true.",403);return t.export.instr=o,t.export.options=null,t.export.svg=null,_prepareExport(t)}async function _prepareExport(e){const{export:t,customLogic:o}=e;return t.constr=_fixConstr(t.constr),t.type=_fixType(t.type,t.outfile),t.outfile=_fixOutfile(t.type,t.outfile),log(3,`[chart] The custom logic is ${o.allowCodeExecution?"allowed":"disallowed"}.`),_handleCustomLogic(o),_handleGlobalAndTheme(t,o),_handleSize(t),_checkDataSize({export:t,customLogic:o}),postWork(e)}function _fixConstr(e){try{const t=`${e.toLowerCase().replace("chart","")}Chart`;return"Chart"===t&&t.toLowerCase(),["chart","stockChart","mapChart","ganttChart"].includes(t)?t:"chart"}catch{return"chart"}}function _fixOutfile(e,t){return`${getAbsolutePath(t||"chart").split(".").shift()}.${e||"png"}`}function _fixType(e,t=null){const o={"image/png":"png","image/jpeg":"jpeg","application/pdf":"pdf","image/svg+xml":"svg"},r=Object.values(o);if(t){const o=t.split(".").pop();"jpg"===o?e="jpeg":r.includes(o)&&e!==o&&(e=o)}return o[e]||r.find((t=>t===e))||"png"}function _handleSize(e){const{chart:t,exporting:o}=isAllowedConfig(e.instr)||!1,{chart:r,exporting:i}=isAllowedConfig(e.globalOptions)||!1,{chart:n,exporting:s}=isAllowedConfig(e.themeOptions)||!1,a=e.height||o?.sourceHeight||t?.height||i?.sourceHeight||r?.height||s?.sourceHeight||n?.height||e.defaultHeight||400,l=e.width||o?.sourceWidth||t?.width||i?.sourceWidth||r?.width||s?.sourceWidth||n?.width||e.defaultWidth||600,c=roundNumber(Math.max(.1,Math.min(e.scale||o?.scale||i?.scale||s?.scale||e.defaultScale||1,5)),2);e.height=a,e.width=l,e.scale=c;for(let t of["height","width","scale"])"string"==typeof e[t]&&(e[t]=+e[t].replace(/px|%/gi,""))}function _handleCustomLogic(e){if(e.allowCodeExecution){try{e.resources=_handleResources(e.resources,e.allowFileResources,!0)}catch(t){log(2,"[chart] The `resources` cannot be loaded."),e.resources=null}try{e.customCode=_handleCustomCode(e.customCode,e.allowFileResources),e.customCode=validateOption("customCode",e.customCode)}catch(t){logWithStack(2,t,"[chart] The `customCode` cannot be loaded."),e.customCode=null}try{e.callback=_handleCustomCode(e.callback,e.allowFileResources,!0),e.callback=validateOption("callback",e.callback)}catch(t){logWithStack(2,t,"[chart] The `callback` cannot be loaded."),e.callback=null}[null,void 0].includes(e.customCode)&&log(3,"[chart] No value for the `customCode` option found."),[null,void 0].includes(e.callback)&&log(3,"[chart] No value for the `callback` option found."),[null,void 0].includes(e.resources)&&log(3,"[chart] No value for the `resources` option found.")}else if(e.callback||e.resources||e.customCode)throw e.callback=null,e.resources=null,e.customCode=null,new ExportError("[chart] The 'callback', 'resources', and 'customCode' options have been disabled for this server.",403)}function _handleResources(e=null,t,o){let r=e;r||(e="resources.json");const i=["js","css","files"];let n=!1;t&&"string"==typeof e&&e.endsWith(".json")?r=isAllowedConfig(readFileSync(getAbsolutePath(e),"utf8"),!1,o):(r=isAllowedConfig(e,!1,o),r&&!t&&delete r.files);for(const e in r)i.includes(e)?n||(n=!0):delete r[e];return n?(r.files&&(r.files=r.files.map((e=>e.trim())),(!r.files||r.files.length<=0)&&delete r.files),r=validateOption("resources",r),r):null}function _handleCustomCode(e,t,o=!1){if(e&&"string"==typeof e)return(e=e.trim()).endsWith(".js")?t?_handleCustomCode(readFileSync(getAbsolutePath(e),"utf8"),t,o):null:!o&&(e.startsWith("function()")||e.startsWith("function ()")||e.startsWith("()=>")||e.startsWith("() =>"))?`(${e})()`:e.replace(/;$/,"")}function _handleGlobalAndTheme(e,t){const{allowFileResources:o,allowCodeExecution:r}=t;["globalOptions","themeOptions"].forEach((t=>{try{e[t]&&(o&&"string"==typeof e[t]&&e[t].endsWith(".json")?e[t]=isAllowedConfig(readFileSync(getAbsolutePath(e[t]),"utf8"),!0,r):e[t]=isAllowedConfig(e[t],!0,r),e[t]=validateOption(t,e[t]))}catch(o){logWithStack(2,o,`[chart] The \`${t}\` cannot be loaded.`),e[t]=null}})),[null,void 0].includes(e.globalOptions)&&log(3,"[chart] No value for the `globalOptions` option found."),[null,void 0].includes(e.themeOptions)&&log(3,"[chart] No value for the `themeOptions` option found.")}function _checkDataSize(e){const t=Buffer.byteLength(JSON.stringify(e),"utf-8");if(log(3,`[chart] The current total size of the data for the export process is around ${(t/1048576).toFixed(2)}MB.`),t>=104857600)throw new ExportError("[chart] The data for the export process exceeds 100MB limit.")}const timerIds=[];function addTimer(e){timerIds.push(e)}function clearAllTimers(){log(4,"[timer] Clearing all registered intervals and timeouts.");for(const e of timerIds)clearInterval(e),clearTimeout(e)}function logErrorMiddleware(e,t,o,r){return logWithStack(1,e),"development"!==getOptions().other.nodeEnv&&delete e.stack,r(e)}function returnErrorMiddleware(e,t,o,r){const{message:i,stack:n}=e,s=e.statusCode||400;o.status(s).json({statusCode:s,message:i,stack:n})}function errorMiddleware(e){e.use(logErrorMiddleware),e.use(returnErrorMiddleware)}function rateLimitingMiddleware(e,t){try{if(e&&t.enable){const o="Too many requests, you have been rate limited. Please try again later.",r={window:t.window||1,maxRequests:t.maxRequests||30,delay:t.delay||0,trustProxy:t.trustProxy||!1,skipKey:t.skipKey||null,skipToken:t.skipToken||null};r.trustProxy&&e.enable("trust proxy");const i=rateLimit({windowMs:60*r.window*1e3,limit:r.maxRequests,delayMs:r.delay,handler:(e,t)=>{t.format({json:()=>{t.status(429).send({message:o})},default:()=>{t.status(429).send(o)}})},skip:e=>null!==r.skipKey&&null!==r.skipToken&&e.query.key===r.skipKey&&e.query.access_token===r.skipToken&&(log(4,"[rate limiting] Skipping rate limiter."),!0)});e.use(i),log(3,`[rate limiting] Enabled rate limiting with ${r.maxRequests} requests per ${r.window} minute for each IP, trusting proxy: ${r.trustProxy}.`)}}catch(e){throw new ExportError("[rate limiting] Could not configure and set the rate limiting options.",500).setError(e)}}function contentTypeMiddleware(e,t,o){try{const t=e.headers["content-type"]||"";if(!t.includes("application/json")&&!t.includes("application/x-www-form-urlencoded")&&!t.includes("multipart/form-data"))throw new ExportError("[validation] Content-Type must be application/json, application/x-www-form-urlencoded, or multipart/form-data.",415);return o()}catch(e){return o(e)}}function requestBodyMiddleware(e,t,o){try{const t=e.body,r=v4();if(!t||isObjectEmpty(t))throw log(2,`[validation] Request [${r}] - The request from ${e.headers["x-forwarded-for"]||e.connection.remoteAddress} was incorrect. Received payload is empty.`),new ExportError(`[validation] Request [${r}] - The request body is required. Please ensure that your Content-Type header is correct. Accepted types are 'application/json' and 'multipart/form-data'.`,400);const i=getAllowCodeExecution(),n=isAllowedConfig(t.instr||t.options||t.infile||t.data,!0,i);if(null===n&&!t.svg)throw log(2,`[validation] Request [${r}] - The request from ${e.headers["x-forwarded-for"]||e.connection.remoteAddress} was incorrect. Received payload is missing correct chart data for export: ${JSON.stringify(t)}.`),new ExportError(`[validation] Request [${r}] - No correct chart data found. Ensure that you are using either application/json or multipart/form-data headers. If sending JSON, make sure the chart data is in the 'infile', 'options', or 'data' attribute. If sending SVG, ensure it is in the 'svg' attribute.`,400);if(t.svg&&isPrivateRangeUrlFound(t.svg))throw new ExportError(`[validation] Request [${r}] - SVG potentially contain at least one forbidden URL in 'xlink:href' element. Please review the SVG content and ensure that all referenced URLs comply with security policies.`,400);return e.validatedOptions={requestId:r,export:{instr:n,svg:t.svg,outfile:t.outfile||`${e.params.filename||"chart"}.${t.type||"png"}`,type:t.type,constr:t.constr,b64:t.b64,noDownload:t.noDownload,height:t.height,width:t.width,scale:t.scale,globalOptions:isAllowedConfig(t.globalOptions,!0,i),themeOptions:isAllowedConfig(t.themeOptions,!0,i)},customLogic:{allowCodeExecution:i,allowFileResources:!1,customCode:t.customCode,callback:t.callback,resources:isAllowedConfig(t.resources,!0,i)}},o()}catch(e){return o(e)}}function validationMiddleware(e){e.post(["/","/:filename"],contentTypeMiddleware),e.post(["/","/:filename"],requestBodyMiddleware)}const reversedMime={png:"image/png",jpeg:"image/jpeg",gif:"image/gif",pdf:"application/pdf",svg:"image/svg+xml"};async function requestExport(e,t,o){try{const o=measureTime();let r=!1;e.socket.on("close",(e=>{e&&(r=!0)}));const i=e.validatedOptions,n=i.requestId;log(4,`[export] Request [${n}] - Got an incoming HTTP request.`),await startExport(i,((i,s)=>{if(e.socket.removeAllListeners("close"),r)log(3,`[export] Request [${n}] - The client closed the connection before the chart finished processing.`);else{if(i)throw i;if(!s||!s.result)throw log(2,`[export] Request [${n}] - Request from ${e.headers["x-forwarded-for"]||e.connection.remoteAddress} was incorrect. Received result is ${s.result}.`),new ExportError(`[export] Request [${n}] - Unexpected return of the export result from the chart generation. Please check your request data.`,400);if(s.result){log(3,`[export] Request [${n}] - The whole exporting process took ${o()}ms.`);const{type:e,b64:r,noDownload:i,outfile:a}=s.options.export;return r?t.send(getBase64(s.result,e)):(t.header("Content-Type",reversedMime[e]||"image/png"),i||t.attachment(a),"svg"===e?t.send(s.result):t.send(Buffer.from(s.result,"base64")))}}}))}catch(e){return o(e)}}function exportRoutes(e){e.post("/",requestExport),e.post("/:filename",requestExport)}const serverStartTime=new Date,packageFile=JSON.parse(readFileSync(join(__dirname,"package.json"),"utf8")),successRates=[],recordInterval=6e4,windowSize=30;function _calculateMovingAverage(){return successRates.reduce(((e,t)=>e+t),0)/successRates.length}function _startSuccessRate(){return setInterval((()=>{const e=getPoolStats(),t=0===e.exportsAttempted?1:e.exportsPerformed/e.exportsAttempted*100;successRates.push(t),successRates.length>windowSize&&successRates.shift()}),recordInterval)}function healthRoutes(e){addTimer(_startSuccessRate()),e.get("/health",((e,t,o)=>{try{log(4,"[health] Returning server health.");const e=getPoolStats(),o=successRates.length,r=_calculateMovingAverage();t.send({status:"OK",bootTime:serverStartTime,uptime:`${Math.floor((getNewDateTime()-serverStartTime.getTime())/1e3/60)} minutes`,serverVersion:packageFile.version,highchartsVersion:getHcVersion(),averageExportTime:e.timeSpentAverage,attemptedExports:e.exportsAttempted,performedExports:e.exportsPerformed,failedExports:e.exportsDropped,sucessRatio:e.exportsPerformed/e.exportsAttempted*100,pool:getPoolInfoJSON(),period:o,movingAverage:r,message:isNaN(r)||!successRates.length?"Too early to report. No exports made yet. Please check back soon.":`Last ${o} minutes had a success rate of ${r.toFixed(2)}%.`,svgExports:e.exportsFromSvg,jsonExports:e.exportsFromOptions,svgExportsAttempts:e.exportsFromSvgAttempts,jsonExportsAttempts:e.exportsFromOptionsAttempts})}catch(e){return o(e)}}))}function uiRoutes(e){getOptions().ui.enable&&e.get(getOptions().ui.route||"/",((e,t,o)=>{try{log(4,"[ui] Returning UI for the export."),t.sendFile(join(__dirname,"public","index.html"),{acceptRanges:!1})}catch(e){return o(e)}}))}function versionChangeRoutes(e){e.post("/version_change/:newVersion",(async(e,t,o)=>{try{log(4,"[version] Changing Highcharts version.");const o=envs.HIGHCHARTS_ADMIN_TOKEN;if(!o||!o.length)throw new ExportError("[version] The server is not configured to perform run-time version changes: `HIGHCHARTS_ADMIN_TOKEN` is not set.",401);const r=e.get("hc-auth");if(!r||r!==o)throw new ExportError("[version] Invalid or missing token: Set the token in the hc-auth header.",401);const i=e.params.newVersion;if(!i)throw new ExportError("[version] No new version supplied.",400);try{await updateHcVersion(i)}catch(e){throw new ExportError(`[version] Version change: ${e.message}`,400).setError(e)}t.status(200).send({statusCode:200,highchartsVersion:getHcVersion(),message:`Successfully updated Highcharts to version: ${i}.`})}catch(e){return o(e)}}))}const activeServers=new Map,app=express();async function startServer(e){try{const t=updateOptions({server:e});if(!(e=t.server).enable||!app)throw new ExportError("[server] Server cannot be started (not enabled or no correct Express app found).",500);const o=1024*e.uploadLimit*1024,r=multer.memoryStorage(),i=multer({storage:r,limits:{fieldSize:o}});if(app.disable("x-powered-by"),app.use(cors({methods:["POST","GET","OPTIONS"]})),app.use(((e,t,o)=>{t.set("Accept-Ranges","none"),o()})),app.use(express.json({limit:o})),app.use(express.urlencoded({extended:!0,limit:o})),app.use(i.none()),app.use(express.static(join(__dirname,"public"))),!e.ssl.force){const t=http.createServer(app);_attachServerErrorHandlers(t),t.listen(e.port,e.host,(()=>{activeServers.set(e.port,t),log(3,`[server] Started HTTP server on ${e.host}:${e.port}.`)}))}if(e.ssl.enable){let t,o;try{t=readFileSync(join(getAbsolutePath(e.ssl.certPath),"server.key"),"utf8"),o=readFileSync(join(getAbsolutePath(e.ssl.certPath),"server.crt"),"utf8")}catch(t){log(2,`[server] Unable to load key/certificate from the '${e.ssl.certPath}' path. Could not run secured layer server.`)}if(t&&o){const r=https.createServer({key:t,cert:o},app);_attachServerErrorHandlers(r),r.listen(e.ssl.port,e.host,(()=>{activeServers.set(e.ssl.port,r),log(3,`[server] Started HTTPS server on ${e.host}:${e.ssl.port}.`)}))}}rateLimitingMiddleware(app,e.rateLimiting),validationMiddleware(app),exportRoutes(app),healthRoutes(app),uiRoutes(app),versionChangeRoutes(app),errorMiddleware(app)}catch(e){throw new ExportError("[server] Could not configure and start the server.",500).setError(e)}}function closeServers(){if(activeServers.size>0){log(4,"[server] Closing all servers.");for(const[e,t]of activeServers)t.close((()=>{activeServers.delete(e),log(4,`[server] Closed server on port: ${e}.`)}))}}function getServers(){return activeServers}function getExpress(){return express}function getApp(){return app}function enableRateLimiting(e){const t=updateOptions({server:{rateLimiting:e}});rateLimitingMiddleware(app,t.server.rateLimitingOptions)}function use(e,...t){app.use(e,...t)}function get(e,...t){app.get(e,...t)}function post(e,...t){app.post(e,...t)}function _attachServerErrorHandlers(e){e.on("clientError",((e,t)=>{logWithStack(1,e,`[server] Client error: ${e.message}, destroying socket.`),t.destroy()})),e.on("error",(e=>{logWithStack(1,e,`[server] Server error: ${e.message}`)})),e.on("connection",(e=>{e.on("error",(e=>{logWithStack(1,e,`[server] Socket error: ${e.message}`)}))}))}var server={startServer:startServer,closeServers:closeServers,getServers:getServers,getExpress:getExpress,getApp:getApp,enableRateLimiting:enableRateLimiting,use:use,get:get,post:post};async function shutdownCleanUp(e=0){await Promise.allSettled([clearAllTimers(),closeServers(),killPool()]),process.exit(e)}async function initExport(e){const t=updateOptions(e);setAllowCodeExecution(t.customLogic.allowCodeExecution),initLogging(t.logging),t.other.listenToProcessExits&&_attachProcessExitListeners(),await checkCache(t.highcharts,t.server.proxy),await initPool(t.pool,t.puppeteer.args)}function _attachProcessExitListeners(){log(3,"[process] Attaching exit listeners to the process."),process.on("exit",(e=>{log(4,`[process] Process exited with code: ${e}.`)})),process.on("SIGINT",(async(e,t)=>{log(4,`[process] The ${e} event with code: ${t}.`),await shutdownCleanUp()})),process.on("SIGTERM",(async(e,t)=>{log(4,`[process] The ${e} event with code: ${t}.`),await shutdownCleanUp()})),process.on("SIGHUP",(async(e,t)=>{log(4,`[process] The ${e} event with code: ${t}.`),await shutdownCleanUp()})),process.on("uncaughtException",(async(e,t)=>{logWithStack(1,e,`[process] The ${t} error.`),await shutdownCleanUp(1)}))}var index={...server,getOptions:getOptions,updateOptions:updateOptions,mapToNewOptions:mapToNewOptions,validateOption:validateOption,validateOptions:validateOptions,initExport:initExport,singleExport:singleExport,batchExport:batchExport,startExport:startExport,killPool:killPool,shutdownCleanUp:shutdownCleanUp,log:log,logWithStack:logWithStack,logZodIssues:logZodIssues,setLogLevel:function(e){setLogLevel(updateOptions({logging:{level:e}}).logging.level)},enableConsoleLogging:function(e){enableConsoleLogging(updateOptions({logging:{toConsole:e}}).logging.toConsole)},enableFileLogging:function(e,t,o){const r=updateOptions({logging:{dest:e,file:t,toFile:o}});enableFileLogging(r.logging.dest,r.logging.file,r.logging.toFile)}};export{index as default,initExport}; +import"colors";import{existsSync,mkdirSync,appendFile,readFileSync,writeFileSync}from"fs";import{normalize,resolve,isAbsolute,join}from"path";import{HttpsProxyAgent}from"https-proxy-agent";import{fileURLToPath}from"url";import dotenv from"dotenv";import{z}from"zod";import http from"http";import https from"https";import{Pool}from"tarn";import{v4}from"uuid";import puppeteer from"puppeteer";import DOMPurify from"dompurify";import{JSDOM}from"jsdom";import cors from"cors";import express from"express";import multer from"multer";import rateLimit from"express-rate-limit";const __dirname=fileURLToPath(new URL("../.",import.meta.url));function deepCopy(e){if(null===e||"object"!=typeof e)return e;const t=Array.isArray(e)?[]:{};for(const o in e)Object.prototype.hasOwnProperty.call(e,o)&&(t[o]=deepCopy(e[o]));return t}function getAbsolutePath(e){return isAbsolute(e)?normalize(e):resolve(e)}function getBase64(e,t){return"pdf"===t||"svg"==t?Buffer.from(e,"utf8").toString("base64"):e}function getNewDate(){return(new Date).toString().split("(")[0].trim()}function getNewDateTime(){return(new Date).getTime()}function isObject(e){return"[object Object]"===Object.prototype.toString.call(e)}function isObjectEmpty(e){return"object"==typeof e&&!Array.isArray(e)&&null!==e&&0===Object.keys(e).length}function isPrivateRangeUrlFound(e){return[/xlink:href="(?:http:\/\/|https:\/\/)?localhost\b/,/xlink:href="(?:http:\/\/|https:\/\/)?10\.\d{1,3}\.\d{1,3}\.\d{1,3}\b/,/xlink:href="(?:http:\/\/|https:\/\/)?127\.\d{1,3}\.\d{1,3}\.\d{1,3}\b/,/xlink:href="(?:http:\/\/|https:\/\/)?172\.(1[6-9]|2[0-9]|3[0-1])\.\d{1,3}\.\d{1,3}\b/,/xlink:href="(?:http:\/\/|https:\/\/)?192\.168\.\d{1,3}\.\d{1,3}\b/].some((t=>t.test(e)))}function measureTime(){const e=process.hrtime.bigint();return()=>Number(process.hrtime.bigint()-e)/1e6}function roundNumber(e,t=1){const o=Math.pow(10,t||0);return Math.round(+e*o)/o}const colors=["red","yellow","blue","gray","green"],logging={toConsole:!0,toFile:!1,pathCreated:!1,pathToLog:"",levelsDesc:[{title:"error",color:colors[0]},{title:"warning",color:colors[1]},{title:"notice",color:colors[2]},{title:"verbose",color:colors[3]},{title:"benchmark",color:colors[4]}]};function log(...e){const[t,...o]=e,{levelsDesc:r,level:i}=logging;if(5!==t&&(0===t||t>i||i>r.length))return;const n=`${getNewDate()} [${r[t-1].title}] -`;logging.toFile&&_logToFile(o,n),logging.toConsole&&console.log.apply(void 0,[n.toString()[logging.levelsDesc[t-1].color]].concat(o))}function logWithStack(e,t,o){const r=o||t&&t.message||"",{level:i,levelsDesc:n}=logging;if(0===e||e>i||i>n.length)return;const s=`${getNewDate()} [${n[e-1].title}] -`,a=t&&t.stack,l=[r];a&&l.push("\n",a),logging.toFile&&_logToFile(l,s),logging.toConsole&&console.log.apply(void 0,[s.toString()[logging.levelsDesc[e-1].color]].concat([l.shift()[colors[e-1]],...l]))}function logZodIssues(e,t,o){logWithStack(e,null,[`${o||"[validation] Validation error"} - the following Zod issues occured:`,...(t||[]).map((e=>`- ${e.message}`))].join("\n"))}function initLogging(e){const{level:t,dest:o,file:r,toConsole:i,toFile:n}=e;logging.pathCreated=!1,logging.pathToLog="",setLogLevel(t),enableConsoleLogging(i),enableFileLogging(o,r,n)}function setLogLevel(e){Number.isInteger(e)&&e>=0&&e<=logging.levelsDesc.length&&(logging.level=e)}function enableConsoleLogging(e){logging.toConsole=!!e}function enableFileLogging(e,t,o){logging.toFile=!!o,logging.toFile&&(logging.dest=e||"log",logging.file=t||"highcharts-export-server.log")}function _logToFile(e,t){logging.pathCreated||(!existsSync(getAbsolutePath(logging.dest))&&mkdirSync(getAbsolutePath(logging.dest)),logging.pathToLog=getAbsolutePath(join(logging.dest,logging.file)),logging.pathCreated=!0),appendFile(logging.pathToLog,[t].concat(e).join(" ")+"\n",(e=>{e&&logging.toFile&&logging.pathCreated&&(logging.toFile=!1,logging.pathCreated=!1,logWithStack(2,e,"[logger] Unable to write to log file."))}))}const defaultConfig={puppeteer:{args:{value:["--allow-running-insecure-content","--ash-no-nudges","--autoplay-policy=user-gesture-required","--block-new-web-contents","--disable-accelerated-2d-canvas","--disable-background-networking","--disable-background-timer-throttling","--disable-backgrounding-occluded-windows","--disable-breakpad","--disable-checker-imaging","--disable-client-side-phishing-detection","--disable-component-extensions-with-background-pages","--disable-component-update","--disable-default-apps","--disable-dev-shm-usage","--disable-domain-reliability","--disable-extensions","--disable-features=CalculateNativeWinOcclusion,InterestFeedContentSuggestions,WebOTP","--disable-hang-monitor","--disable-ipc-flooding-protection","--disable-logging","--disable-notifications","--disable-offer-store-unmasked-wallet-cards","--disable-popup-blocking","--disable-print-preview","--disable-prompt-on-repost","--disable-renderer-backgrounding","--disable-search-engine-choice-screen","--disable-session-crashed-bubble","--disable-setuid-sandbox","--disable-site-isolation-trials","--disable-speech-api","--disable-sync","--enable-unsafe-webgpu","--hide-crash-restore-bubble","--hide-scrollbars","--metrics-recording-only","--mute-audio","--no-default-browser-check","--no-first-run","--no-pings","--no-sandbox","--no-startup-window","--no-zygote","--password-store=basic","--process-per-tab","--use-mock-keychain"],types:["string[]"],envLink:"PUPPETEER_ARGS",cliName:"puppeteerArgs",description:"Array of Puppeteer arguments",promptOptions:{type:"list",separator:";"}}},highcharts:{version:{value:"latest",types:["string"],envLink:"HIGHCHARTS_VERSION",description:"Highcharts version",promptOptions:{type:"text"}},cdnUrl:{value:"https://code.highcharts.com",types:["string"],envLink:"HIGHCHARTS_CDN_URL",description:"CDN URL for Highcharts scripts",promptOptions:{type:"text"}},forceFetch:{value:!1,types:["boolean"],envLink:"HIGHCHARTS_FORCE_FETCH",description:"Flag to refetch scripts after each server rerun",promptOptions:{type:"toggle"}},cachePath:{value:".cache",types:["string"],envLink:"HIGHCHARTS_CACHE_PATH",description:"Directory path for cached Highcharts scripts",promptOptions:{type:"text"}},coreScripts:{value:["highcharts","highcharts-more","highcharts-3d"],types:["string[]"],envLink:"HIGHCHARTS_CORE_SCRIPTS",description:"Highcharts core scripts to fetch",promptOptions:{type:"multiselect",instructions:"Space: Select specific, A: Select all, Enter: Confirm"}},moduleScripts:{value:["stock","map","gantt","exporting","parallel-coordinates","accessibility","boost-canvas","boost","data","data-tools","draggable-points","static-scale","broken-axis","heatmap","tilemap","tiledwebmap","timeline","treemap","treegraph","item-series","drilldown","histogram-bellcurve","bullet","funnel","funnel3d","geoheatmap","pyramid3d","networkgraph","overlapping-datalabels","pareto","pattern-fill","pictorial","price-indicator","sankey","arc-diagram","dependency-wheel","series-label","series-on-point","solid-gauge","sonification","streamgraph","sunburst","variable-pie","variwide","vector","venn","windbarb","wordcloud","xrange","no-data-to-display","drag-panes","debugger","dumbbell","lollipop","cylinder","organization","dotplot","marker-clusters","hollowcandlestick","heikinashi","flowmap","export-data","navigator","textpath"],types:["string[]"],envLink:"HIGHCHARTS_MODULE_SCRIPTS",description:"Highcharts module scripts to fetch",promptOptions:{type:"multiselect",instructions:"Space: Select specific, A: Select all, Enter: Confirm"}},indicatorScripts:{value:["indicators-all"],types:["string[]"],envLink:"HIGHCHARTS_INDICATOR_SCRIPTS",description:"Highcharts indicator scripts to fetch",promptOptions:{type:"multiselect",instructions:"Space: Select specific, A: Select all, Enter: Confirm"}},customScripts:{value:["https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.30.1/moment.min.js","https://cdnjs.cloudflare.com/ajax/libs/moment-timezone/0.5.45/moment-timezone-with-data.min.js"],types:["string[]"],envLink:"HIGHCHARTS_CUSTOM_SCRIPTS",description:"Additional custom scripts or dependencies to fetch",promptOptions:{type:"list",separator:";"}}},export:{infile:{value:null,types:["string","null"],envLink:"EXPORT_INFILE",description:"Input filename with type, formatted correctly as JSON or SVG",promptOptions:{type:"text"}},instr:{value:null,types:["Object","string","null"],envLink:"EXPORT_INSTR",description:"Overrides the `infile` with JSON, stringified JSON, or SVG input",promptOptions:{type:"text"}},options:{value:null,types:["Object","string","null"],envLink:"EXPORT_OPTIONS",description:"Alias for the `instr` option",promptOptions:{type:"text"}},svg:{value:null,types:["string","null"],envLink:"EXPORT_SVG",description:"SVG string representation of the chart to render",promptOptions:{type:"text"}},batch:{value:null,types:["string","null"],envLink:"EXPORT_BATCH",description:'Batch job string with input/output pairs: "in=out;in=out;..."',promptOptions:{type:"text"}},outfile:{value:null,types:["string","null"],envLink:"EXPORT_OUTFILE",description:"Output filename with type. Can be jpeg, png, pdf, or svg and ignores `type` option",promptOptions:{type:"text"}},type:{value:"png",types:["string"],envLink:"EXPORT_TYPE",description:"File export format. Can be jpeg, png, pdf, or svg",promptOptions:{type:"select",hint:"Default: png",choices:["png","jpeg","pdf","svg"]}},constr:{value:"chart",types:["string"],envLink:"EXPORT_CONSTR",description:"Chart constructor. Can be chart, stockChart, mapChart, or ganttChart",promptOptions:{type:"select",hint:"Default: chart",choices:["chart","stockChart","mapChart","ganttChart"]}},b64:{value:!1,types:["boolean"],envLink:"EXPORT_B64",description:"Whether or not to the chart should be received in Base64 format instead of binary",promptOptions:{type:"toggle"}},noDownload:{value:!1,types:["boolean"],envLink:"EXPORT_NO_DOWNLOAD",description:"Whether or not to include or exclude attachment headers in the response",promptOptions:{type:"toggle"}},height:{value:null,types:["number","null"],envLink:"EXPORT_HEIGHT",description:"Height of the exported chart, overrides chart settings",promptOptions:{type:"number"}},width:{value:null,types:["number","null"],envLink:"EXPORT_WIDTH",description:"Width of the exported chart, overrides chart settings",promptOptions:{type:"number"}},scale:{value:null,types:["number","null"],envLink:"EXPORT_SCALE",description:"Scale of the exported chart, overrides chart settings. Ranges from 0.1 to 5.0",promptOptions:{type:"number"}},defaultHeight:{value:400,types:["number"],envLink:"EXPORT_DEFAULT_HEIGHT",description:"Default height of the exported chart if not set",promptOptions:{type:"number"}},defaultWidth:{value:600,types:["number"],envLink:"EXPORT_DEFAULT_WIDTH",description:"Default width of the exported chart if not set",promptOptions:{type:"number"}},defaultScale:{value:1,types:["number"],envLink:"EXPORT_DEFAULT_SCALE",description:"Default scale of the exported chart if not set. Ranges from 0.1 to 5.0",promptOptions:{type:"number",min:.1,max:5}},globalOptions:{value:null,types:["Object","string","null"],envLink:"EXPORT_GLOBAL_OPTIONS",description:"JSON, stringified JSON or filename with global options for Highcharts.setOptions",promptOptions:{type:"text"}},themeOptions:{value:null,types:["Object","string","null"],envLink:"EXPORT_THEME_OPTIONS",description:"JSON, stringified JSON or filename with theme options for Highcharts.setOptions",promptOptions:{type:"text"}},rasterizationTimeout:{value:1500,types:["number"],envLink:"EXPORT_RASTERIZATION_TIMEOUT",description:"Milliseconds to wait for webpage rendering",promptOptions:{type:"number"}}},customLogic:{allowCodeExecution:{value:!1,types:["boolean"],envLink:"CUSTOM_LOGIC_ALLOW_CODE_EXECUTION",description:"Allows or disallows execution of arbitrary code during exporting",promptOptions:{type:"toggle"}},allowFileResources:{value:!1,types:["boolean"],envLink:"CUSTOM_LOGIC_ALLOW_FILE_RESOURCES",description:"Allows or disallows injection of filesystem resources (disabled in server mode)",promptOptions:{type:"toggle"}},customCode:{value:null,types:["string","null"],envLink:"CUSTOM_LOGIC_CUSTOM_CODE",description:"Custom code to execute before chart initialization. Can be a function, code wrapped in a function, or a .js filename",promptOptions:{type:"text"}},callback:{value:null,types:["string","null"],envLink:"CUSTOM_LOGIC_CALLBACK",description:"JavaScript code to run during construction. Can be a function or a .js filename",promptOptions:{type:"text"}},resources:{value:null,types:["Object","string","null"],envLink:"CUSTOM_LOGIC_RESOURCES",description:"Additional resources as JSON, stringified JSON, or filename, containing files, js, and css sections",promptOptions:{type:"text"}},loadConfig:{value:null,types:["string","null"],envLink:"CUSTOM_LOGIC_LOAD_CONFIG",legacyName:"fromFile",description:"File with a pre-defined configuration to use",promptOptions:{type:"text"}},createConfig:{value:null,types:["string","null"],envLink:"CUSTOM_LOGIC_CREATE_CONFIG",description:"Prompt-based option setting, saved to a provided config file",promptOptions:{type:"text"}}},server:{enable:{value:!1,types:["boolean"],envLink:"SERVER_ENABLE",cliName:"enableServer",description:"Starts the server when true",promptOptions:{type:"toggle"}},host:{value:"0.0.0.0",types:["string"],envLink:"SERVER_HOST",description:"Hostname of the server",promptOptions:{type:"text"}},port:{value:7801,types:["number"],envLink:"SERVER_PORT",description:"Port number for the server",promptOptions:{type:"number"}},uploadLimit:{value:3,types:["number"],envLink:"SERVER_UPLOAD_LIMIT",description:"Maximum request body size in MB",promptOptions:{type:"number"}},benchmarking:{value:!1,types:["boolean"],envLink:"SERVER_BENCHMARKING",cliName:"serverBenchmarking",description:"Displays or not action durations in milliseconds during server requests",promptOptions:{type:"toggle"}},proxy:{host:{value:null,types:["string","null"],envLink:"SERVER_PROXY_HOST",cliName:"proxyHost",description:"Host of the proxy server, if applicable",promptOptions:{type:"text"}},port:{value:null,types:["number","null"],envLink:"SERVER_PROXY_PORT",cliName:"proxyPort",description:"Port of the proxy server, if applicable",promptOptions:{type:"number"}},timeout:{value:5e3,types:["number"],envLink:"SERVER_PROXY_TIMEOUT",cliName:"proxyTimeout",description:"Timeout in milliseconds for the proxy server, if applicable",promptOptions:{type:"number"}}},rateLimiting:{enable:{value:!1,types:["boolean"],envLink:"SERVER_RATE_LIMITING_ENABLE",cliName:"enableRateLimiting",description:"Enables or disables rate limiting on the server",promptOptions:{type:"toggle"}},maxRequests:{value:10,types:["number"],envLink:"SERVER_RATE_LIMITING_MAX_REQUESTS",legacyName:"rateLimit",description:"Maximum number of requests allowed per minute",promptOptions:{type:"number"}},window:{value:1,types:["number"],envLink:"SERVER_RATE_LIMITING_WINDOW",description:"Time window in minutes for rate limiting",promptOptions:{type:"number"}},delay:{value:0,types:["number"],envLink:"SERVER_RATE_LIMITING_DELAY",description:"Delay duration between successive requests before reaching the limit",promptOptions:{type:"number"}},trustProxy:{value:!1,types:["boolean"],envLink:"SERVER_RATE_LIMITING_TRUST_PROXY",description:"Set to true if the server is behind a load balancer",promptOptions:{type:"toggle"}},skipKey:{value:null,types:["string","null"],envLink:"SERVER_RATE_LIMITING_SKIP_KEY",description:"Key to bypass the rate limiter, used with `skipToken`",promptOptions:{type:"text"}},skipToken:{value:null,types:["string","null"],envLink:"SERVER_RATE_LIMITING_SKIP_TOKEN",description:"Token to bypass the rate limiter, used with `skipKey`",promptOptions:{type:"text"}}},ssl:{enable:{value:!1,types:["boolean"],envLink:"SERVER_SSL_ENABLE",cliName:"enableSsl",description:"Enables or disables SSL protocol",promptOptions:{type:"toggle"}},force:{value:!1,types:["boolean"],envLink:"SERVER_SSL_FORCE",cliName:"sslForce",legacyName:"sslOnly",description:"Forces the server to use HTTPS only when true",promptOptions:{type:"toggle"}},port:{value:443,types:["number"],envLink:"SERVER_SSL_PORT",cliName:"sslPort",description:"Port for the SSL server",promptOptions:{type:"number"}},certPath:{value:null,types:["string","null"],envLink:"SERVER_SSL_CERT_PATH",cliName:"sslCertPath",legacyName:"sslPath",description:"Path to the SSL certificate/key file",promptOptions:{type:"text"}}}},pool:{minWorkers:{value:4,types:["number"],envLink:"POOL_MIN_WORKERS",description:"Minimum and initial number of pool workers to spawn",promptOptions:{type:"number"}},maxWorkers:{value:8,types:["number"],envLink:"POOL_MAX_WORKERS",legacyName:"workers",description:"Maximum number of pool workers to spawn",promptOptions:{type:"number"}},workLimit:{value:40,types:["number"],envLink:"POOL_WORK_LIMIT",description:"Number of tasks a worker can handle before restarting",promptOptions:{type:"number"}},acquireTimeout:{value:5e3,types:["number"],envLink:"POOL_ACQUIRE_TIMEOUT",description:"Timeout in milliseconds for acquiring a resource",promptOptions:{type:"number"}},createTimeout:{value:5e3,types:["number"],envLink:"POOL_CREATE_TIMEOUT",description:"Timeout in milliseconds for creating a resource",promptOptions:{type:"number"}},destroyTimeout:{value:5e3,types:["number"],envLink:"POOL_DESTROY_TIMEOUT",description:"Timeout in milliseconds for destroying a resource",promptOptions:{type:"number"}},idleTimeout:{value:3e4,types:["number"],envLink:"POOL_IDLE_TIMEOUT",description:"Timeout in milliseconds for destroying idle resources",promptOptions:{type:"number"}},createRetryInterval:{value:200,types:["number"],envLink:"POOL_CREATE_RETRY_INTERVAL",description:"Interval in milliseconds before retrying resource creation on failure",promptOptions:{type:"number"}},reaperInterval:{value:1e3,types:["number"],envLink:"POOL_REAPER_INTERVAL",description:"Interval in milliseconds to check and destroy idle resources",promptOptions:{type:"number"}},benchmarking:{value:!1,types:["boolean"],envLink:"POOL_BENCHMARKING",cliName:"poolBenchmarking",description:"Shows statistics for the pool of resources",promptOptions:{type:"toggle"}}},logging:{level:{value:4,types:["number"],envLink:"LOGGING_LEVEL",cliName:"logLevel",description:"Logging verbosity level",promptOptions:{type:"number",round:0,min:0,max:5}},file:{value:"highcharts-export-server.log",types:["string"],envLink:"LOGGING_FILE",cliName:"logFile",description:"Log file name. Requires `logToFile` and `logDest` to be set",promptOptions:{type:"text"}},dest:{value:"log",types:["string"],envLink:"LOGGING_DEST",cliName:"logDest",description:"Path to store log files. Requires `logToFile` to be set",promptOptions:{type:"text"}},toConsole:{value:!0,types:["boolean"],envLink:"LOGGING_TO_CONSOLE",cliName:"logToConsole",description:"Enables or disables console logging",promptOptions:{type:"toggle"}},toFile:{value:!0,types:["boolean"],envLink:"LOGGING_TO_FILE",cliName:"logToFile",description:"Enables or disables logging to a file",promptOptions:{type:"toggle"}}},ui:{enable:{value:!1,types:["boolean"],envLink:"UI_ENABLE",cliName:"enableUi",description:"Enables or disables the UI for the export server",promptOptions:{type:"toggle"}},route:{value:"/",types:["string"],envLink:"UI_ROUTE",cliName:"uiRoute",description:"The endpoint route for the UI",promptOptions:{type:"text"}}},other:{nodeEnv:{value:"production",types:["string"],envLink:"OTHER_NODE_ENV",description:"The Node.js environment type",promptOptions:{type:"text"}},listenToProcessExits:{value:!0,types:["boolean"],envLink:"OTHER_LISTEN_TO_PROCESS_EXITS",description:"Whether or not to attach process.exit handlers",promptOptions:{type:"toggle"}},noLogo:{value:!1,types:["boolean"],envLink:"OTHER_NO_LOGO",description:"Display or skip printing the logo on startup",promptOptions:{type:"toggle"}},hardResetPage:{value:!1,types:["boolean"],envLink:"OTHER_HARD_RESET_PAGE",description:"Whether or not to reset the page content entirely",promptOptions:{type:"toggle"}},browserShellMode:{value:!0,types:["boolean"],envLink:"OTHER_BROWSER_SHELL_MODE",description:"Whether or not to set the browser to run in shell mode",promptOptions:{type:"toggle"}},validation:{value:!0,types:["boolean"],envLink:"OTHER_VALIDATION",description:"Whether or not to enable validation of options types",promptOptions:{type:"toggle"}}},debug:{enable:{value:!1,types:["boolean"],envLink:"DEBUG_ENABLE",cliName:"enableDebug",description:"Enables or disables debug mode for the underlying browser",promptOptions:{type:"toggle"}},headless:{value:!1,types:["boolean"],envLink:"DEBUG_HEADLESS",description:"Whether or not to set the browser to run in headless mode during debugging",promptOptions:{type:"toggle"}},devtools:{value:!1,types:["boolean"],envLink:"DEBUG_DEVTOOLS",description:"Enables or disables DevTools in headful mode",promptOptions:{type:"toggle"}},listenToConsole:{value:!1,types:["boolean"],envLink:"DEBUG_LISTEN_TO_CONSOLE",description:"Enables or disables listening to console messages from the browser",promptOptions:{type:"toggle"}},dumpio:{value:!1,types:["boolean"],envLink:"DEBUG_DUMPIO",description:"Redirects or not browser stdout and stderr to process.stdout and process.stderr",promptOptions:{type:"toggle"}},slowMo:{value:0,types:["number"],envLink:"DEBUG_SLOW_MO",description:"Delays Puppeteer operations by the specified milliseconds",promptOptions:{type:"number"}},debuggingPort:{value:9222,types:["number"],envLink:"DEBUG_DEBUGGING_PORT",description:"Port used for debugging",promptOptions:{type:"number"}}}};dotenv.config();const{coreScripts:coreScripts,moduleScripts:moduleScripts,indicatorScripts:indicatorScripts}=defaultConfig.highcharts;z.setErrorMap(_customErrorMap);const v={boolean:e=>e?z.boolean():z.union([z.enum(["true","1","false","0","undefined","null",""]).transform((e=>["undefined","null",""].includes(e)?null:"true"===e||"1"===e)),z.boolean()]).nullable(),string:e=>e?z.string().trim().refine((e=>!["false","undefined","null",""].includes(e)),{params:{errorMessage:"The string contains a forbidden value"}}):z.string().trim().transform((e=>["false","undefined","null",""].includes(e)?null:e)).nullable(),enum:(e,t)=>t?z.enum([...e]):z.enum([...e,"undefined","null",""]).transform((e=>["undefined","null",""].includes(e)?null:e)).nullable(),stringArray(e,t,o){const r=z.string().trim().array(),i=z.string().trim().transform((e=>(e.startsWith("[")&&(e=e.slice(1)),e.endsWith("]")&&(e=e.slice(0,-1)),e.split(t)))),n=t=>t.map((e=>e.trim())).filter(e);return o?r.transform(n):z.union([i,r]).transform(n).transform((e=>e.length?e:null)).nullable()},positiveNum:e=>e?z.number().positive():z.union([z.string().trim().refine((e=>!isNaN(Number(e))&&Number(e)>0||["undefined","null",""].includes(e)),{params:{errorMessage:"The value must be numeric and positive"}}).transform((e=>["undefined","null",""].includes(e)?null:Number(e))),z.number().positive()]).nullable(),nonNegativeNum:e=>e?z.number().nonnegative():z.union([z.string().trim().refine((e=>!isNaN(Number(e))&&Number(e)>=0||["undefined","null",""].includes(e)),{params:{errorMessage:"The value must be numeric and non-negative"}}).transform((e=>["undefined","null",""].includes(e)?null:Number(e))),z.number().nonnegative()]).nullable(),startsWith:(e,t)=>t?z.string().trim().refine((t=>e.some((e=>t.startsWith(e)))),{params:{errorMessage:`The value must be a string that starts with ${e.join(", ")}`}}):z.string().trim().refine((t=>e.some((e=>t.startsWith(e)))||["undefined","null",""].includes(t)),{params:{errorMessage:`The value must be a string that starts with ${e.join(", ")}`}}).transform((e=>["undefined","null",""].includes(e)?null:e)).nullable(),chartConfig:()=>z.union([z.string().trim().refine((e=>e.startsWith("{")&&e.endsWith("}")||["undefined","null",""].includes(e)),{params:{errorMessage:"The value must be a string that starts with '{' and ends with '}'"}}).transform((e=>["undefined","null",""].includes(e)?null:e)),z.object({}).passthrough()]).nullable(),additionalOptions:()=>z.union([z.string().trim().refine((e=>e.length>=6&&e.endsWith(".json")||e.startsWith("{")&&e.endsWith("}")||["undefined","null",""].includes(e)),{params:{errorMessage:"The value must be a string that ends with '.json' or starts with '{' and ends with '}'"}}).transform((e=>["undefined","null",""].includes(e)?null:e)),z.object({}).passthrough()]).nullable()},validators={args:e=>v.stringArray((e=>!["false","undefined","null",""].includes(e)),";",e),version:e=>e?z.string().trim().refine((e=>/^(latest|\d{1,2}(\.\d{1,2}){0,2})$/.test(e)),{params:{errorMessage:"The value must be 'latest', a major version, or in the form XX.YY.ZZ"}}):z.string().trim().refine((e=>/^(latest|\d{1,2}(\.\d{1,2}){0,2})$/.test(e)||["undefined","null",""].includes(e)),{params:{errorMessage:"The value must be 'latest', a major version, or in the form XX.YY.ZZ"}}).transform((e=>["undefined","null",""].includes(e)?null:e)).nullable(),cdnUrl:e=>v.startsWith(["http://","https://"],e),forceFetch:e=>v.boolean(e),cachePath:e=>v.string(e),adminToken:e=>v.string(e),coreScripts:e=>v.stringArray((e=>coreScripts.value.includes(e)),",",e),moduleScripts:e=>v.stringArray((e=>moduleScripts.value.includes(e)),",",e),indicatorScripts:e=>v.stringArray((e=>indicatorScripts.value.includes(e)),",",e),customScripts:e=>v.stringArray((e=>e.startsWith("https://")||e.startsWith("http://")),",",e),infile:e=>e?z.string().trim().refine((e=>e.length>=6&&e.endsWith(".json")||e.length>=5&&e.endsWith(".svg")),{params:{errorMessage:"The value must be a string that ends with .json or .svg"}}).nullable():z.string().trim().refine((e=>e.length>=6&&e.endsWith(".json")||e.length>=5&&e.endsWith(".svg")||["undefined","null",""].includes(e)),{params:{errorMessage:"The value must be a string that ends with .json or .svg"}}).transform((e=>["undefined","null",""].includes(e)?null:e)).nullable(),instr:()=>v.chartConfig(),options:()=>v.chartConfig(),svg:()=>z.string().trim().refine((e=>e.indexOf("=0||e.indexOf("=0||["false","undefined","null",""].includes(e)),{params:{errorMessage:"The value must be a string that contains '["false","undefined","null",""].includes(e)?null:e)).nullable(),outfile:e=>e?z.string().trim().refine((e=>e.length>=6&&e.endsWith(".jpeg")||e.length>=5&&(e.endsWith(".jpg")||e.endsWith(".png")||e.endsWith(".pdf")||e.endsWith(".svg"))),{params:{errorMessage:"The value must be a string that ends with .jpeg, .jpg, .png, .pdf, or .svg"}}).nullable():z.string().trim().refine((e=>e.length>=6&&e.endsWith(".jpeg")||e.length>=5&&(e.endsWith(".jpg")||e.endsWith(".png")||e.endsWith(".pdf")||e.endsWith(".svg"))||["undefined","null",""].includes(e)),{params:{errorMessage:"The value must be a string that ends with .jpeg, .jpg, .png, .pdf, or .svg"}}).transform((e=>["undefined","null",""].includes(e)?null:e)).nullable(),type:e=>v.enum(["jpeg","jpg","png","pdf","svg"],e),constr:e=>v.enum(["chart","stockChart","mapChart","ganttChart"],e),b64:e=>v.boolean(e),noDownload:e=>v.boolean(e),defaultHeight:e=>v.positiveNum(e),defaultWidth:e=>v.positiveNum(e),defaultScale:e=>e?z.number().gte(.1).lte(5):z.union([z.string().trim().refine((e=>!isNaN(Number(e))&&!0!==e&&!e.startsWith("[")&&Number(e)>=.1&&Number(e)<=5||["undefined","null",""].includes(e)),{params:{errorMessage:"The value must be within a 0.1 and 5.0 range"}}).transform((e=>["undefined","null",""].includes(e)?null:Number(e))),z.number().gte(.1).lte(5)]).nullable(),height(e){return this.defaultHeight(e).nullable()},width(e){return this.defaultWidth(e).nullable()},scale(e){return this.defaultScale(e).nullable()},globalOptions:()=>v.additionalOptions(),themeOptions:()=>v.additionalOptions(),batch:e=>v.string(e),rasterizationTimeout:e=>v.nonNegativeNum(e),allowCodeExecution:e=>v.boolean(e),allowFileResources:e=>v.boolean(e),customCode:e=>v.string(e),callback:e=>v.string(e),resources(e){const t=z.object({js:v.string(!1),css:v.string(!1),files:v.stringArray((e=>!["undefined","null",""].includes(e)),",",!0).nullable()}).partial(),o=z.string().trim().refine((e=>e.startsWith("{")&&e.endsWith("}")||e.length>=6&&e.endsWith(".json")),{params:{errorMessage:"The value must be a string that starts with '{' and ends with '}"}}),r=z.string().trim().refine((e=>e.startsWith("{")&&e.endsWith("}")||e.length>=6&&e.endsWith(".json")||["undefined","null",""].includes(e)),{params:{errorMessage:"The value must be a string that ends with .json"}}).transform((e=>["undefined","null",""].includes(e)?null:e));return e?z.union([t,o]).nullable():z.union([t,r]).nullable()},loadConfig:e=>v.string(e).refine((e=>null===e||e.length>=6&&e.endsWith(".json")),{params:{errorMessage:"The value must be a string that ends with .json"}}),createConfig(e){return this.loadConfig(e)},enableServer:e=>v.boolean(e),host:e=>v.string(e),port:e=>v.nonNegativeNum(e),uploadLimit:e=>v.positiveNum(e),serverBenchmarking:e=>v.boolean(e),proxyHost:e=>v.string(e),proxyPort:e=>v.nonNegativeNum(e).nullable(),proxyTimeout:e=>v.nonNegativeNum(e),enableRateLimiting:e=>v.boolean(e),maxRequests:e=>v.nonNegativeNum(e),window:e=>v.nonNegativeNum(e),delay:e=>v.nonNegativeNum(e),trustProxy:e=>v.boolean(e),skipKey:e=>v.string(e),skipToken:e=>v.string(e),enableSsl:e=>v.boolean(e),sslForce:e=>v.boolean(e),sslPort:e=>v.nonNegativeNum(e),sslCertPath:e=>v.string(e),minWorkers:e=>v.positiveNum(e),maxWorkers:e=>v.positiveNum(e),workLimit:e=>v.positiveNum(e),acquireTimeout:e=>v.nonNegativeNum(e),createTimeout:e=>v.nonNegativeNum(e),destroyTimeout:e=>v.nonNegativeNum(e),idleTimeout:e=>v.nonNegativeNum(e),createRetryInterval:e=>v.nonNegativeNum(e),reaperInterval:e=>v.nonNegativeNum(e),poolBenchmarking:e=>v.boolean(e),resourcesInterval:e=>v.nonNegativeNum(e),logLevel:e=>e?z.number().int().gte(0).lte(5):z.union([z.string().trim().refine((e=>!isNaN(Number(e))&&!0!==e&&!e.startsWith("[")&&Number.isInteger(Number(e))&&Number(e)>=0&&Number(e)<=5||["undefined","null",""].includes(e)),{params:{errorMessage:"The value must be within a 0 and 5 range"}}).transform((e=>["undefined","null",""].includes(e)?null:Number(e))),z.number().int().gte(0).lte(5)]).nullable(),logFile:e=>v.string(e).refine((e=>null===e||e.length>=5&&e.endsWith(".log")),{params:{errorMessage:"The value must be a string that ends with .log"}}),logDest:e=>v.string(e),logToConsole:e=>v.boolean(e),logToFile:e=>v.boolean(e),enableUi:e=>v.boolean(e),uiRoute:e=>v.startsWith(["/"],e),nodeEnv:e=>v.enum(["development","production","test"],e),listenToProcessExits:e=>v.boolean(e),noLogo:e=>v.boolean(e),hardResetPage:e=>v.boolean(e),browserShellMode:e=>v.boolean(e),validation:e=>v.boolean(e),enableDebug:e=>v.boolean(e),headless:e=>v.boolean(e),devtools:e=>v.boolean(e),listenToConsole:e=>v.boolean(e),dumpio:e=>v.boolean(e),slowMo:e=>v.nonNegativeNum(e),debuggingPort:e=>v.nonNegativeNum(e),requestId:()=>z.string().uuid({message:"The value must be a stringified UUID"}).nullable()},PuppeteerSchema=e=>z.object({args:validators.args(e)}).partial(),HighchartsSchema=e=>z.object({version:validators.version(e),cdnUrl:validators.cdnUrl(e),forceFetch:validators.forceFetch(e),cachePath:validators.cachePath(e),coreScripts:validators.coreScripts(e),moduleScripts:validators.moduleScripts(e),indicatorScripts:validators.indicatorScripts(e),customScripts:validators.customScripts(e)}).partial(),ExportSchema=e=>z.object({infile:validators.infile(e),instr:validators.instr(),options:validators.options(),svg:validators.svg(),outfile:validators.outfile(e),type:validators.type(e),constr:validators.constr(e),b64:validators.b64(e),noDownload:validators.noDownload(e),defaultHeight:validators.defaultHeight(e),defaultWidth:validators.defaultWidth(e),defaultScale:validators.defaultScale(e),height:validators.height(e),width:validators.width(e),scale:validators.scale(e),globalOptions:validators.globalOptions(),themeOptions:validators.themeOptions(),batch:validators.batch(!1),rasterizationTimeout:validators.rasterizationTimeout(e)}).partial(),CustomLogicSchema=e=>z.object({allowCodeExecution:validators.allowCodeExecution(e),allowFileResources:validators.allowFileResources(e),customCode:validators.customCode(!1),callback:validators.callback(!1),resources:validators.resources(e),loadConfig:validators.loadConfig(!1),createConfig:validators.createConfig(!1)}).partial(),ProxySchema=e=>z.object({host:validators.proxyHost(!1),port:validators.proxyPort(e),timeout:validators.proxyTimeout(e)}).partial(),RateLimitingSchema=e=>z.object({enable:validators.enableRateLimiting(e),maxRequests:validators.maxRequests(e),window:validators.window(e),delay:validators.delay(e),trustProxy:validators.trustProxy(e),skipKey:validators.skipKey(!1),skipToken:validators.skipToken(!1)}).partial(),SslSchema=e=>z.object({enable:validators.enableSsl(e),force:validators.sslForce(e),port:validators.sslPort(e),certPath:validators.sslCertPath(!1)}).partial(),ServerSchema=e=>z.object({enable:validators.enableServer(e).optional(),host:validators.host(e).optional(),port:validators.port(e).optional(),uploadLimit:validators.uploadLimit(e).optional(),benchmarking:validators.serverBenchmarking(e).optional(),proxy:ProxySchema(e).optional(),rateLimiting:RateLimitingSchema(e).optional(),ssl:SslSchema(e).optional()}),PoolSchema=e=>z.object({minWorkers:validators.minWorkers(e),maxWorkers:validators.maxWorkers(e),workLimit:validators.workLimit(e),acquireTimeout:validators.acquireTimeout(e),createTimeout:validators.createTimeout(e),destroyTimeout:validators.destroyTimeout(e),idleTimeout:validators.idleTimeout(e),createRetryInterval:validators.createRetryInterval(e),reaperInterval:validators.reaperInterval(e),benchmarking:validators.poolBenchmarking(e)}).partial(),LoggingSchema=e=>z.object({level:validators.logLevel(e),file:validators.logFile(e),dest:validators.logDest(e),toConsole:validators.logToConsole(e),toFile:validators.logToFile(e)}).partial(),UiSchema=e=>z.object({enable:validators.enableUi(e),route:validators.uiRoute(e)}).partial(),OtherSchema=e=>z.object({nodeEnv:validators.nodeEnv(e),listenToProcessExits:validators.listenToProcessExits(e),noLogo:validators.noLogo(e),hardResetPage:validators.hardResetPage(e),browserShellMode:validators.browserShellMode(e),validation:validators.validation(e)}).partial(),DebugSchema=e=>z.object({enable:validators.enableDebug(e),headless:validators.headless(e),devtools:validators.devtools(e),listenToConsole:validators.listenToConsole(e),dumpio:validators.dumpio(e),slowMo:validators.slowMo(e),debuggingPort:validators.debuggingPort(e)}).partial(),StrictConfigSchema=z.object({requestId:validators.requestId(),puppeteer:PuppeteerSchema(!0),highcharts:HighchartsSchema(!0),export:ExportSchema(!0),customLogic:CustomLogicSchema(!0),server:ServerSchema(!0),pool:PoolSchema(!0),logging:LoggingSchema(!0),ui:UiSchema(!0),other:OtherSchema(!0),debug:DebugSchema(!0)}),LooseConfigSchema=z.object({requestId:validators.requestId(),puppeteer:PuppeteerSchema(!1),highcharts:HighchartsSchema(!1),export:ExportSchema(!1),customLogic:CustomLogicSchema(!1),server:ServerSchema(!1),pool:PoolSchema(!1),logging:LoggingSchema(!1),ui:UiSchema(!1),other:OtherSchema(!1),debug:DebugSchema(!1)}),EnvSchema=z.object({PUPPETEER_ARGS:validators.args(!1),HIGHCHARTS_VERSION:validators.version(!1),HIGHCHARTS_CDN_URL:validators.cdnUrl(!1),HIGHCHARTS_FORCE_FETCH:validators.forceFetch(!1),HIGHCHARTS_CACHE_PATH:validators.cachePath(!1),HIGHCHARTS_ADMIN_TOKEN:validators.adminToken(!1),HIGHCHARTS_CORE_SCRIPTS:validators.coreScripts(!1),HIGHCHARTS_MODULE_SCRIPTS:validators.moduleScripts(!1),HIGHCHARTS_INDICATOR_SCRIPTS:validators.indicatorScripts(!1),HIGHCHARTS_CUSTOM_SCRIPTS:validators.customScripts(!1),EXPORT_INFILE:validators.infile(!1),EXPORT_INSTR:validators.instr(),EXPORT_OPTIONS:validators.options(),EXPORT_SVG:validators.svg(),EXPORT_BATCH:validators.batch(!1),EXPORT_OUTFILE:validators.outfile(!1),EXPORT_TYPE:validators.type(!1),EXPORT_CONSTR:validators.constr(!1),EXPORT_B64:validators.b64(!1),EXPORT_NO_DOWNLOAD:validators.noDownload(!1),EXPORT_HEIGHT:validators.height(!1),EXPORT_WIDTH:validators.width(!1),EXPORT_SCALE:validators.scale(!1),EXPORT_DEFAULT_HEIGHT:validators.defaultHeight(!1),EXPORT_DEFAULT_WIDTH:validators.defaultWidth(!1),EXPORT_DEFAULT_SCALE:validators.defaultScale(!1),EXPORT_GLOBAL_OPTIONS:validators.globalOptions(),EXPORT_THEME_OPTIONS:validators.themeOptions(),EXPORT_RASTERIZATION_TIMEOUT:validators.rasterizationTimeout(!1),CUSTOM_LOGIC_ALLOW_CODE_EXECUTION:validators.allowCodeExecution(!1),CUSTOM_LOGIC_ALLOW_FILE_RESOURCES:validators.allowFileResources(!1),CUSTOM_LOGIC_CUSTOM_CODE:validators.customCode(!1),CUSTOM_LOGIC_CALLBACK:validators.callback(!1),CUSTOM_LOGIC_RESOURCES:validators.resources(!1),CUSTOM_LOGIC_LOAD_CONFIG:validators.loadConfig(!1),CUSTOM_LOGIC_CREATE_CONFIG:validators.createConfig(!1),SERVER_ENABLE:validators.enableServer(!1),SERVER_HOST:validators.host(!1),SERVER_PORT:validators.port(!1),SERVER_UPLOAD_LIMIT:validators.uploadLimit(!1),SERVER_BENCHMARKING:validators.serverBenchmarking(!1),SERVER_PROXY_HOST:validators.proxyHost(!1),SERVER_PROXY_PORT:validators.proxyPort(!1),SERVER_PROXY_TIMEOUT:validators.proxyTimeout(!1),SERVER_RATE_LIMITING_ENABLE:validators.enableRateLimiting(!1),SERVER_RATE_LIMITING_MAX_REQUESTS:validators.maxRequests(!1),SERVER_RATE_LIMITING_WINDOW:validators.window(!1),SERVER_RATE_LIMITING_DELAY:validators.delay(!1),SERVER_RATE_LIMITING_TRUST_PROXY:validators.trustProxy(!1),SERVER_RATE_LIMITING_SKIP_KEY:validators.skipKey(!1),SERVER_RATE_LIMITING_SKIP_TOKEN:validators.skipToken(!1),SERVER_SSL_ENABLE:validators.enableSsl(!1),SERVER_SSL_FORCE:validators.sslForce(!1),SERVER_SSL_PORT:validators.sslPort(!1),SERVER_SSL_CERT_PATH:validators.sslCertPath(!1),POOL_MIN_WORKERS:validators.minWorkers(!1),POOL_MAX_WORKERS:validators.maxWorkers(!1),POOL_WORK_LIMIT:validators.workLimit(!1),POOL_ACQUIRE_TIMEOUT:validators.acquireTimeout(!1),POOL_CREATE_TIMEOUT:validators.createTimeout(!1),POOL_DESTROY_TIMEOUT:validators.destroyTimeout(!1),POOL_IDLE_TIMEOUT:validators.idleTimeout(!1),POOL_CREATE_RETRY_INTERVAL:validators.createRetryInterval(!1),POOL_REAPER_INTERVAL:validators.reaperInterval(!1),POOL_BENCHMARKING:validators.poolBenchmarking(!1),LOGGING_LEVEL:validators.logLevel(!1),LOGGING_FILE:validators.logFile(!1),LOGGING_DEST:validators.logDest(!1),LOGGING_TO_CONSOLE:validators.logToConsole(!1),LOGGING_TO_FILE:validators.logToFile(!1),UI_ENABLE:validators.enableUi(!1),UI_ROUTE:validators.uiRoute(!1),OTHER_NODE_ENV:validators.nodeEnv(!1),OTHER_LISTEN_TO_PROCESS_EXITS:validators.listenToProcessExits(!1),OTHER_NO_LOGO:validators.noLogo(!1),OTHER_HARD_RESET_PAGE:validators.hardResetPage(!1),OTHER_BROWSER_SHELL_MODE:validators.browserShellMode(!1),OTHER_VALIDATION:validators.validation(!1),DEBUG_ENABLE:validators.enableDebug(!1),DEBUG_HEADLESS:validators.headless(!1),DEBUG_DEVTOOLS:validators.devtools(!1),DEBUG_LISTEN_TO_CONSOLE:validators.listenToConsole(!1),DEBUG_DUMPIO:validators.dumpio(!1),DEBUG_SLOW_MO:validators.slowMo(!1),DEBUG_DEBUGGING_PORT:validators.debuggingPort(!1)}),envs=EnvSchema.partial().parse(process.env);function strictValidate(e){return StrictConfigSchema.partial().parse(e)}function looseValidate(e){return LooseConfigSchema.partial().parse(e)}function _customErrorMap(e,t){const o=e.path.join("."),r=`Invalid value for the ${o}`;if(e.code===z.ZodIssueCode.invalid_type)return e.received===z.ZodParsedType.undefined?{message:`${r} - No value was provided.`}:{message:`${r} - Invalid type. ${t.defaultError}.`};if(e.code===z.ZodIssueCode.custom&&e.params?.errorMessage)return{message:`${r} - ${e.params?.errorMessage}, received '${t.data}'.`};if(e.code===z.ZodIssueCode.invalid_union){let t=`Multiple errors occurred for the ${o}:\n`;return e.unionErrors.forEach((e=>{const o=e.issues[0].message.indexOf("-");t+=-1!==o?`${e.issues[0].message}\n`.substring(o):`${e.issues[0].message}\n`})),{message:t}}return{message:`${r} - ${t.defaultError}.`}}class ExportError extends Error{constructor(e,t){super(),this.message=e,this.stackMessage=e,t&&(this.statusCode=t)}setError(e){return this.error=e,e.name&&(this.name=e.name),e.statusCode&&(this.statusCode=e.statusCode),e.stack&&(this.stackMessage=e.message,this.stack=e.stack),this}}const globalOptions=_initOptions(defaultConfig),nestedProps=_createNestedProps(defaultConfig),absoluteProps=_createAbsoluteProps(defaultConfig);function getOptions(e=!0){return e?deepCopy(globalOptions):globalOptions}function updateOptions(e,t=!1,o=!0){return _mergeOptions(getOptions(t),validateOptions(e,o))}function mapToNewOptions(e){const t={};if(isObject(e))for(const[o,r]of Object.entries(e)){const e=nestedProps[o]?nestedProps[o].split("."):[];e.reduce(((t,o,i)=>t[o]=e.length-1===i?r:t[o]||{}),t)}else log(2,"[config] No correct object with options was provided. Returning an empty object.");return t}function validateOption(e,t,o=!0){if(!getOptions().other.validation)return t;try{return validators[e](o).parse(t)}catch(t){throw logZodIssues(1,t.issues,`[validation] The ${e} option validation error`),new ExportError(`[validation] The ${e} option validation error`,400)}}function validateOptions(e,t=!0){if(!getOptions().other.validation)return e;try{return t?strictValidate(e):looseValidate(e)}catch(e){throw logZodIssues(1,e.issues,"[validation] Options validation error"),new ExportError("[validation] Options validation error",400)}}function isAllowedConfig(config,toString=!1,allowFunctions=!1){try{if(!isObject(config)&&"string"!=typeof config)return null;const objectConfig="string"==typeof config?allowFunctions?eval(`(${config})`):JSON.parse(config):config,stringifiedOptions=_optionsStringify(objectConfig,allowFunctions,!1),parsedOptions=allowFunctions?JSON.parse(_optionsStringify(objectConfig,allowFunctions,!0),((_,value)=>"string"==typeof value&&value.startsWith("function")?eval(`(${value})`):value)):JSON.parse(stringifiedOptions);return toString?stringifiedOptions:parsedOptions}catch(e){return null}}function _initOptions(e){const t={};for(const[o,r]of Object.entries(e))Object.prototype.hasOwnProperty.call(r,"value")?void 0!==envs[r.envLink]&&null!==envs[r.envLink]?t[o]=envs[r.envLink]:t[o]=r.value:t[o]=_initOptions(r);return t}function _mergeOptions(e,t){if(isObject(e)&&isObject(t))for(const[o,r]of Object.entries(t))e[o]=isObject(r)&&!absoluteProps.includes(o)&&void 0!==e[o]?_mergeOptions(e[o],r):void 0!==r?r:e[o]||null;return e}function _optionsStringify(e,t,o){return JSON.stringify(e,((e,r)=>{if("string"==typeof r&&(r=r.trim()),"function"==typeof r||"string"==typeof r&&r.startsWith("function")&&r.endsWith("}")){if(t)return o?`"EXP_FUN${(r+"").replaceAll(/\s+/g," ")}EXP_FUN"`:`EXP_FUN${(r+"").replaceAll(/\s+/g," ")}EXP_FUN`;throw new Error}return r})).replaceAll(o?/\\"EXP_FUN|EXP_FUN\\"/g:/"EXP_FUN|EXP_FUN"/g,"")}function _createNestedProps(e,t={},o=""){return Object.keys(e).forEach((r=>{const i=e[r];void 0===i.value?_createNestedProps(i,t,`${o}.${r}`):(t[i.cliName||r]=`${o}.${r}`.substring(1),void 0!==i.legacyName&&(t[i.legacyName]=`${o}.${r}`.substring(1)))})),t}function _createAbsoluteProps(e,t=[]){return Object.keys(e).forEach((o=>{const r=e[o];void 0===r.types?_createAbsoluteProps(r,t):r.types.includes("Object")&&t.push(o)})),t}async function get$1(e,t={}){return new Promise(((o,r)=>{_getProtocolModule(e).get(e,t,(e=>{let t="";e.on("data",(e=>{t+=e})),e.on("end",(()=>{t||r("Nothing was fetched from the URL."),e.text=t,o(e)}))})).on("error",(e=>{r(e)}))}))}function _getProtocolModule(e){return e.startsWith("https")?https:http}const cache={cdnUrl:"https://code.highcharts.com",activeManifest:{},sources:"",hcVersion:""};async function checkCache(e,t){try{let o;const r=getCachePath(),i=join(r,"manifest.json"),n=join(r,"sources.js");if(!existsSync(r)&&mkdirSync(r,{recursive:!0}),!existsSync(i)||e.forceFetch)log(3,"[cache] Fetching and caching Highcharts dependencies."),o=await _updateCache(e,t,n);else{let r=!1;const s=JSON.parse(readFileSync(i),"utf8");if(s.modules&&Array.isArray(s.modules)){const e={};s.modules.forEach((t=>e[t]=1)),s.modules=e}const{coreScripts:a,moduleScripts:l,indicatorScripts:c}=e,p=a.length+l.length+c.length;s.version!==e.version?(log(2,"[cache] A Highcharts version mismatch in the cache, need to re-fetch."),r=!0):Object.keys(s.modules||{}).length!==p?(log(2,"[cache] The cache and the requested modules do not match, need to re-fetch."),r=!0):r=(l||[]).some((e=>{if(!s.modules[e])return log(2,`[cache] The ${e} is missing in the cache, need to re-fetch.`),!0})),r?o=await _updateCache(e,t,n):(log(3,"[cache] Dependency cache is up to date, proceeding."),cache.sources=readFileSync(n,"utf8"),o=s.modules,cache.hcVersion=_extractHcVersion(cache.sources))}await _saveConfigToManifest(e.version,o)}catch(e){throw new ExportError("[cache] Could not configure cache and create or update the config manifest.",500).setError(e)}}function getHcVersion(){return cache.hcVersion}async function updateHcVersion(e){const t=updateOptions({highcharts:{version:e}});await checkCache(t.highcharts,t.server.proxy)}function getCachePath(){return getAbsolutePath(getOptions().highcharts.cachePath)}async function _saveConfigToManifest(e,t={}){cache.activeManifest={version:e,modules:t},log(3,"[cache] Writing a new manifest.");try{writeFileSync(join(getCachePath(),"manifest.json"),JSON.stringify(cache.activeManifest),"utf8")}catch(e){throw new ExportError("[cache] Error writing the cache manifest.",500).setError(e)}}async function _updateCache(e,t,o){try{const r="latest"===e.version?null:`${e.version}`;log(3,`[cache] Updating cache version to Highcharts: ${r||"latest"}.`);const i=e.cdnUrl||cache.cdnUrl,n=_configureRequest(t),s={};return cache.sources=(await Promise.all([...e.coreScripts.map((e=>_fetchScript(r?`${i}/${r}/${e}`:`${i}/${e}`,n,s,!0))),...e.moduleScripts.map((e=>_fetchScript("map"===e?r?`${i}/maps/${r}/modules/${e}`:`${i}/maps/modules/${e}`:r?`${i}/${r}/modules/${e}`:`${i}/modules/${e}`,n,s))),...e.indicatorScripts.map((e=>_fetchScript(r?`${i}/stock/${r}/indicators/${e}`:`${i}/stock/indicators/${e}`,n,s))),...e.customScripts.map((e=>_fetchScript(`${e}`,n)))])).join(";\n"),cache.hcVersion=_extractHcVersion(cache.sources),writeFileSync(o,cache.sources),s}catch(e){throw new ExportError("[cache] Unable to update the local Highcharts cache.",500).setError(e)}}async function _fetchScript(e,t,o,r=!1){e.endsWith(".js")&&(e=e.substring(0,e.length-3)),log(4,`[cache] Fetching script - ${e}.js`);const i=await get$1(`${e}.js`,t);if(200===i.statusCode&&"string"==typeof i.text){if(o){o[_extractModuleName(e)]=1}return i.text}if(r)throw new ExportError(`[cache] Could not fetch the ${e}.js. The script might not exist in the requested version (status code: ${i.statusCode}).`,404).setError(i);log(2,`[cache] Could not fetch the ${e}.js. The script might not exist in the requested version.`)}function _configureRequest(e){const t=e.host,o=e.port;if(t&&o)try{return{agent:new HttpsProxyAgent({host:t,port:o}),timeout:e.timeout}}catch(e){throw new ExportError("[cache] Could not create a Proxy Agent.",500).setError(e)}return{}}function _extractHcVersion(e){return e.substring(0,e.indexOf("*/")).replace("/*","").replace("*/","").replace(/\n/g,"").trim()}function _extractModuleName(e){return e.replace(/(.*)\/|(.*)modules\/|stock\/(.*)indicators\/|maps\/(.*)modules\//gi,"")}function setupHighcharts(){Highcharts.animObject=function(){return{duration:0}}}async function createChart(e,t){const{getOptions:o,setOptions:r,merge:i,wrap:n}=Highcharts;Highcharts.setOptionsObj=i(!1,{},o()),window.isRenderComplete=!1,n(Highcharts.Chart.prototype,"init",(function(e,t,o){((t=i(t,{exporting:{enabled:!1},plotOptions:{series:{label:{enabled:!1}}},tooltip:{}})).series||[]).forEach((function(e){e.animation=!1})),window.onHighchartsRender||(window.onHighchartsRender=Highcharts.addEvent(this,"render",(()=>{window.isRenderComplete=!0}))),e.apply(this,[t,o])})),n(Highcharts.Series.prototype,"init",(function(e,t,o){e.apply(this,[t,o])}));const s={chart:{animation:!1,height:e.height,width:e.width},exporting:{enabled:!1}},a=new Function(`return ${e.instr}`)(),l=new Function(`return ${e.themeOptions}`)(),c=i(!1,l,a,s),p=t.callback?new Function(`return ${t.callback}`)():null;t.customCode&&new Function("options",t.customCode)(a);const u=new Function(`return ${e.globalOptions}`)();u&&r(u),Highcharts[e.constr]("container",c,p);const d=Array.from(document.querySelectorAll(".highcharts-container image"));await Promise.race([Promise.all(d.map((e=>e.complete&&0!==e.naturalHeight?Promise.resolve():new Promise((t=>e.addEventListener("load",t,{once:!0})))))),new Promise((e=>setTimeout(e,2e3)))]);const g=o();for(const e in g)"function"!=typeof g[e]&&delete g[e];r(Highcharts.setOptionsObj),Highcharts.setOptionsObj={}}const pageTemplate=readFileSync(join(__dirname,"templates","template.html"),"utf8");let browser=null;async function createBrowser(e){const{debug:t,other:o}=getOptions(),{enable:r,...i}=t,n={headless:!o.browserShellMode||"shell",userDataDir:"tmp",args:e||[],handleSIGINT:!1,handleSIGTERM:!1,handleSIGHUP:!1,waitForInitialPage:!1,defaultViewport:null,...r&&i};if(!browser){let e=0;const t=async()=>{try{log(3,`[browser] Attempting to launch and get a browser instance (try ${++e}).`),browser=await puppeteer.launch(n)}catch(o){if(logWithStack(1,o,"[browser] Failed to launch a browser instance."),!(e<25))throw o;log(3,`[browser] Retry to open a browser (${e} out of 25).`),await new Promise((e=>setTimeout(e,4e3))),await t()}};try{await t(),"shell"===n.headless&&log(3,"[browser] Launched browser in shell mode."),r&&log(3,"[browser] Launched browser in debug mode.")}catch(e){throw new ExportError("[browser] Maximum retries to open a browser instance reached.",500).setError(e)}if(!browser)throw new ExportError("[browser] Cannot find a browser to open.",500)}return browser}async function closeBrowser(){browser&&browser.connected&&await browser.close(),browser=null,log(4,"[browser] Closed the browser.")}async function newPage(e){if(!browser||!browser.connected)throw new ExportError("[browser] Browser is not yet connected.",500);if(e.page=await browser.newPage(),await e.page.setCacheEnabled(!1),await _setPageContent(e.page),_setPageEvents(e.page),!e.page||e.page.isClosed())throw new ExportError("[browser] The page is invalid or closed.",400)}async function clearPage(e,t=!1){try{if(e.page&&!e.page.isClosed())return t?(await e.page.goto("about:blank",{waitUntil:"domcontentloaded"}),await _setPageContent(e.page)):await e.page.evaluate((()=>{document.body.innerHTML='
'})),!0}catch(t){logWithStack(2,t,`[pool] Pool resource [${e.id}] - Content of the page could not be cleared.`),e.workCount=getOptions().pool.workLimit+1}return!1}async function addPageResources(e,t){const o=[],r=t.resources;if(r){const i=[];if(r.js&&i.push({content:r.js}),r.files)for(const e of r.files){const t=!e.startsWith("http");i.push(t?{content:readFileSync(getAbsolutePath(e),"utf8")}:{url:e})}for(const t of i)try{o.push(await e.addScriptTag(t))}catch(e){logWithStack(2,e,"[browser] The JS resource cannot be loaded.")}i.length=0;const n=[];if(r.css){const i=r.css.match(/@import\s*([^;]*);/g);if(i)for(let e of i)e&&(e=e.replace("url(","").replace("@import","").replace(/"/g,"").replace(/'/g,"").replace(/;/,"").replace(/\)/g,"").trim(),e.startsWith("http")?n.push({url:e}):t.allowFileResources&&n.push({path:getAbsolutePath(e)}));n.push({content:r.css.replace(/@import\s*([^;]*);/g,"")||" "});for(const t of n)try{o.push(await e.addStyleTag(t))}catch(e){logWithStack(2,e,"[browser] The CSS resource cannot be loaded.")}n.length=0}}return o}async function clearPageResources(e,t){try{for(const e of t)await e.dispose();await e.evaluate((()=>{if("undefined"!=typeof Highcharts){const e=Highcharts.charts;if(Array.isArray(e)&&e.length)for(const t of e)t&&t.destroy(),Highcharts.charts.shift()}const[...e]=document.getElementsByTagName("script"),[,...t]=document.getElementsByTagName("style"),[...o]=document.getElementsByTagName("link");for(const r of[...e,...t,...o])r.remove()}))}catch(e){logWithStack(2,e,"[browser] Could not clear page's resources.")}}async function _setPageContent(e){await e.setContent(pageTemplate,{waitUntil:"domcontentloaded"}),await e.addScriptTag({path:join(getCachePath(),"sources.js")}),await e.evaluate(setupHighcharts)}function _setPageEvents(e){const{debug:t}=getOptions();e.on("pageerror",(async()=>{e.isClosed()})),t.enable&&t.listenToConsole&&e.on("console",(e=>{console.log(`[debug] ${e.text()}`)}))}var cssTemplate=()=>"\n\nhtml, body {\n margin: 0;\n padding: 0;\n box-sizing: border-box;\n}\n\n#table-div, #sliders, #datatable, #controls, .ld-row {\n display: none;\n height: 0;\n}\n\n#chart-container {\n box-sizing: border-box;\n margin: 0;\n overflow: auto;\n font-size: 0;\n}\n\n#chart-container > figure, div {\n margin-top: 0 !important;\n margin-bottom: 0 !important;\n}\n\n",svgTemplate=e=>`\n\n\n \n \n Highcharts Export\n \n \n \n
\n ${e}\n
\n \n\n\n`;async function puppeteerExport(e,t,o){const r=[];try{let i=!1;if(t.svg){if(log(4,"[export] Treating as SVG input."),"svg"===t.type)return t.svg;i=!0,await e.setContent(svgTemplate(t.svg),{waitUntil:"domcontentloaded"})}else log(4,"[export] Treating as JSON config."),await e.evaluate(createChart,t,o);r.push(...await addPageResources(e,o));const n=await _getChartSize(e,i,t.scale),{x:s,y:a}=await _getClipRegion(e),l=Math.abs(Math.ceil(n.chartHeight||t.height)),c=Math.abs(Math.ceil(n.chartWidth||t.width));let p;switch(await e.setViewport({height:l,width:c,deviceScaleFactor:i?1:parseFloat(t.scale)}),t.type){case"svg":p=await _createSVG(e);break;case"png":case"jpeg":p=await _createImage(e,t.type,{width:c,height:l,x:s,y:a},t.rasterizationTimeout);break;case"pdf":p=await _createPDF(e,l,c,t.rasterizationTimeout);break;default:throw new ExportError(`[export] Unsupported output format: ${t.type}.`,400)}return await clearPageResources(e,r),p}catch(t){return await clearPageResources(e,r),t}}async function _getClipRegion(e){return e.$eval("#chart-container",(e=>{const{x:t,y:o,width:r,height:i}=e.getBoundingClientRect();return{x:t,y:o,width:r,height:Math.trunc(i>1?i:500)}}))}async function _getChartSize(e,t,o){return t?await e.evaluate((e=>{const t=document.querySelector("#chart-container svg:first-of-type"),o=t.height.baseVal.value*e,r=t.width.baseVal.value*e;return document.body.style.zoom=e,document.body.style.margin="0px",{chartHeight:o,chartWidth:r}}),parseFloat(o)):await e.evaluate((()=>{const{chartHeight:e,chartWidth:t}=window.Highcharts.charts[0];return document.body.style.zoom=1,{chartHeight:e,chartWidth:t}}))}async function _createSVG(e){return e.$eval("#container svg:first-of-type",(e=>e.outerHTML))}async function _createImage(e,t,o,r){return Promise.race([e.screenshot({type:t,clip:o,encoding:"base64",fullPage:!1,optimizeForSpeed:!0,captureBeyondViewport:!0,..."png"!==t?{quality:80}:{},omitBackground:"png"==t}),new Promise(((e,t)=>setTimeout((()=>t(new ExportError("Rasterization timeout",408))),r||1500)))])}async function _createPDF(e,t,o,r){return await e.emulateMediaType("screen"),e.pdf({height:t+1,width:o,encoding:"base64",timeout:r||1500})}let pool=null;const poolStats={exportsAttempted:0,exportsPerformed:0,exportsDropped:0,exportsFromSvg:0,exportsFromOptions:0,exportsFromSvgAttempts:0,exportsFromOptionsAttempts:0,timeSpent:0,timeSpentAverage:0};async function initPool(e,t){await createBrowser(t);try{if(log(3,`[pool] Initializing pool with workers: min ${e.minWorkers}, max ${e.maxWorkers}.`),pool)return void log(4,"[pool] Already initialized, please kill it before creating a new one.");e.minWorkers>e.maxWorkers&&(e.minWorkers=e.maxWorkers),pool=new Pool({..._factory(e),min:e.minWorkers,max:e.maxWorkers,acquireTimeoutMillis:e.acquireTimeout,createTimeoutMillis:e.createTimeout,destroyTimeoutMillis:e.destroyTimeout,idleTimeoutMillis:e.idleTimeout,createRetryIntervalMillis:e.createRetryInterval,reapIntervalMillis:e.reaperInterval,propagateCreateError:!1}),pool.on("release",(async e=>{const t=await clearPage(e,!1);log(4,`[pool] Pool resource [${e.id}] - Releasing a worker. Clear page status: ${t}.`)})),pool.on("destroySuccess",((e,t)=>{log(4,`[pool] Pool resource [${t.id}] - Destroyed a worker successfully.`),t.page=null}));const t=[];for(let o=0;o{pool.release(e)})),log(3,"[pool] The pool is ready"+(t.length?` with ${t.length} initial resources waiting.`:"."))}catch(e){throw new ExportError("[pool] Could not configure and create the pool of workers.",500).setError(e)}}async function killPool(){if(log(3,"[pool] Killing pool with all workers and closing browser."),pool){for(const e of pool.used)pool.release(e.resource);pool.destroyed||(await pool.destroy(),log(4,"[pool] Destroyed the pool of resources.")),pool=null}await closeBrowser()}async function postWork(e){let t;try{if(log(4,"[pool] Work received, starting to process."),++poolStats.exportsAttempted,e.pool.benchmarking&&_getPoolInfo(),!pool)throw new ExportError("[pool] Work received, but pool has not been started.",500);const o=measureTime();try{log(4,"[pool] Acquiring a worker handle."),t=await pool.acquire().promise,e.server.benchmarking&&log(5,"[benchmark] "+(e.requestId?`Request [${e.requestId}] - `:""),`Acquiring a worker handle took ${o()}ms.`)}catch(t){throw new ExportError(`[pool] ${e.requestId?`Request [${e.requestId}] - `:""}Error encountered when acquiring an available entry: ${o()}ms.`,400).setError(t)}if(log(4,"[pool] Acquired a worker handle."),!t.page)throw t.workCount=e.pool.workLimit+1,new ExportError("[pool] Resolved worker page is invalid: the pool setup is wonky.",400);log(4,`[pool] Pool resource [${t.id}] - Starting work on this pool entry.`);const r=measureTime(),i=await puppeteerExport(t.page,e.export,e.customLogic);if(i instanceof Error)throw"Rasterization timeout"===i.message&&(t.workCount=e.pool.workLimit+1,t.page=null),"TimeoutError"===i.name||"Rasterization timeout"===i.message?new ExportError(`[pool] ${e.requestId?`Request [${e.requestId}] - `:""}Rasterization timeout: your chart may be too complex or large, and failed to render within the allotted time.`).setError(i):new ExportError(`[pool] ${e.requestId?`Request [${e.requestId}] - `:""}Error encountered during export: ${r()}ms.`).setError(i);return e.server.benchmarking&&log(5,"[benchmark] "+(e.requestId?`Request [${e.requestId}] - `:""),`Exporting a chart sucessfully took ${r()}ms.`),pool.release(t),poolStats.timeSpent+=r(),poolStats.timeSpentAverage=poolStats.timeSpent/++poolStats.exportsPerformed,log(4,`[pool] Work completed in ${r()}ms.`),{result:i,options:e}}catch(e){throw++poolStats.exportsDropped,t&&pool.release(t),e}}function getPoolStats(){return poolStats}function getPoolInfoJSON(){return{min:pool.min,max:pool.max,used:pool.numUsed(),available:pool.numFree(),allCreated:pool.numUsed()+pool.numFree(),pendingAcquires:pool.numPendingAcquires(),pendingCreates:pool.numPendingCreates(),pendingValidations:pool.numPendingValidations(),pendingDestroys:pool.pendingDestroys.length,absoluteAll:pool.numUsed()+pool.numFree()+pool.numPendingAcquires()+pool.numPendingCreates()+pool.numPendingValidations()+pool.pendingDestroys.length}}function _getPoolInfo(){const{min:e,max:t,used:o,available:r,allCreated:i,pendingAcquires:n,pendingCreates:s,pendingValidations:a,pendingDestroys:l,absoluteAll:c}=getPoolInfoJSON();log(5,`[pool] The minimum number of resources allowed by pool: ${e}.`),log(5,`[pool] The maximum number of resources allowed by pool: ${t}.`),log(5,`[pool] The number of used resources: ${o}.`),log(5,`[pool] The number of free resources: ${r}.`),log(5,`[pool] The number of all created (used and free) resources: ${i}.`),log(5,`[pool] The number of resources waiting to be acquired: ${n}.`),log(5,`[pool] The number of resources waiting to be created: ${s}.`),log(5,`[pool] The number of resources waiting to be validated: ${a}.`),log(5,`[pool] The number of resources waiting to be destroyed: ${l}.`),log(5,`[pool] The number of all resources: ${c}.`)}function _factory(e){return{create:async()=>{const t={id:v4(),workCount:Math.round(Math.random()*(e.workLimit/2))};try{const e=getNewDateTime();return await newPage(t),log(3,`[pool] Pool resource [${t.id}] - Successfully created a worker, took ${getNewDateTime()-e}ms.`),t}catch(e){throw log(3,`[pool] Pool resource [${t.id}] - Error encountered when creating a new page.`),e}},validate:async t=>t.page?t.page.isClosed()?(log(3,`[pool] Pool resource [${t.id}] - Validation failed (page is closed or invalid).`),!1):t.page.mainFrame().detached?(log(3,`[pool] Pool resource [${t.id}] - Validation failed (page's frame is detached).`),!1):!(e.workLimit&&++t.workCount>e.workLimit)||(log(3,`[pool] Pool resource [${t.id}] - Validation failed (exceeded the ${e.workLimit} works per resource limit).`),!1):(log(3,`[pool] Pool resource [${t.id}] - Validation failed (no valid page is found).`),!1),destroy:async e=>{if(log(3,`[pool] Pool resource [${e.id}] - Destroying a worker.`),e.page&&!e.page.isClosed())try{e.page.removeAllListeners("pageerror"),e.page.removeAllListeners("console"),e.page.removeAllListeners("framedetached"),await e.page.close()}catch(t){throw log(3,`[pool] Pool resource [${e.id}] - Page could not be closed upon destroying.`),t}}}}function sanitize(e){const t=new JSDOM("").window;return DOMPurify(t).sanitize(e,{ADD_TAGS:["foreignObject"]})}let allowCodeExecution=!1;async function singleExport(e){if(!e||!e.export)throw new ExportError("[chart] No expected `export` options were found. Please provide one of the following options: `infile`, `instr`, `options`, or `svg` to generate a valid image.",400);await startExport({export:e.export,customLogic:e.customLogic},(async(e,t)=>{if(e)throw e;const{b64:o,outfile:r,type:i}=t.options.export;try{o?writeFileSync(`${r.split(".").shift()||"chart"}.txt`,getBase64(t.result,i)):writeFileSync(r||`chart.${i}`,"svg"!==i?Buffer.from(t.result,"base64"):t.result)}catch(e){throw new ExportError("[chart] Error while saving a chart.",500).setError(e)}await killPool()}))}async function batchExport(e){if(!(e&&e.export&&e.export.batch))throw new ExportError("[chart] No expected `export` options were found. Please provide the `batch` option to generate valid images.",400);{const t=[];for(let o of e.export.batch.split(";")||[])o=o.split("="),2===o.length?t.push(startExport({export:{...e.export,infile:o[0],outfile:o[1]},customLogic:e.customLogic},((e,t)=>{if(e)throw e;const{b64:o,outfile:r,type:i}=t.options.export;try{o?writeFileSync(`${r.split(".").shift()||"chart"}.txt`,getBase64(t.result,i)):writeFileSync(r,"svg"!==i?Buffer.from(t.result,"base64"):t.result)}catch(e){throw new ExportError("[chart] Error while saving a chart.",500).setError(e)}}))):log(2,"[chart] No correct pair found for the batch export.");const o=await Promise.allSettled(t);await killPool(),o.forEach(((e,t)=>{e.reason&&logWithStack(1,e.reason,`[chart] Batch export number ${t+1} could not be correctly completed.`)}))}}async function startExport(e,t){try{if(!isObject(e))throw new ExportError("[chart] Incorrect value of the provided `imageOptions`. Needs to be an object.",400);const o=updateOptions({export:e.export,customLogic:e.customLogic},!0),r=o.export;if(log(4,"[chart] Starting the exporting process."),null!==r.infile){let e;log(4,"[chart] Attempting to export from a file input.");try{e=readFileSync(getAbsolutePath(r.infile),"utf8")}catch(e){throw new ExportError("[chart] Error loading content from a file input.",400).setError(e)}if(r.infile.endsWith(".svg"))r.svg=validateOption("svg",e);else{if(!r.infile.endsWith(".json"))throw new ExportError("[chart] Incorrect value of the `infile` option.",400);r.instr=validateOption("instr",e)}}if(null!==r.svg){log(4,"[chart] Attempting to export from an SVG input."),++getPoolStats().exportsFromSvgAttempts;const e=await _exportFromSvg(sanitize(r.svg),o);return++getPoolStats().exportsFromSvg,t(null,e)}if(null!==r.instr||null!==r.options){log(4,"[chart] Attempting to export from options input."),++getPoolStats().exportsFromOptionsAttempts;const e=await _exportFromOptions(r.instr||r.options,o);return++getPoolStats().exportsFromOptions,t(null,e)}return t(new ExportError("[chart] No valid input specified. Check if at least one of the following parameters is correctly set: 'infile', 'instr', 'options', or 'svg'.",400))}catch(e){return t(e)}}function getAllowCodeExecution(){return allowCodeExecution}function setAllowCodeExecution(e){allowCodeExecution=e}async function _exportFromSvg(e,t){if("string"==typeof e&&(e.indexOf("=0||e.indexOf("=0))return log(4,"[chart] Parsing input as SVG."),t.export.svg=e,t.export.options=null,t.export.instr=null,_prepareExport(t);throw new ExportError("[chart] Not a correct SVG input.",400)}async function _exportFromOptions(e,t){log(4,"[chart] Parsing input from options.");const o=isAllowedConfig(e,!0,t.customLogic.allowCodeExecution);if(null===o||"string"!=typeof o||!o.startsWith("{")||!o.endsWith("}"))throw new ExportError("[chart] Invalid configuration provided - Only options configurations and SVG are allowed for this server. If this is your server, JavaScript custom code can be enabled by starting the server with the `allowCodeExecution` options set to true.",403);return t.export.instr=o,t.export.options=null,t.export.svg=null,_prepareExport(t)}async function _prepareExport(e){const{export:t,customLogic:o}=e;return t.constr=_fixConstr(t.constr),t.type=_fixType(t.type,t.outfile),t.outfile=_fixOutfile(t.type,t.outfile),log(3,`[chart] The custom logic is ${o.allowCodeExecution?"allowed":"disallowed"}.`),_handleCustomLogic(o),_handleGlobalAndTheme(t,o),_handleSize(t),_checkDataSize({export:t,customLogic:o}),postWork(e)}function _fixConstr(e){try{const t=`${e.toLowerCase().replace("chart","")}Chart`;return"Chart"===t&&t.toLowerCase(),["chart","stockChart","mapChart","ganttChart"].includes(t)?t:"chart"}catch{return"chart"}}function _fixOutfile(e,t){return`${getAbsolutePath(t||"chart").split(".").shift()}.${e||"png"}`}function _fixType(e,t=null){const o={"image/png":"png","image/jpeg":"jpeg","application/pdf":"pdf","image/svg+xml":"svg"},r=Object.values(o);if(t){const o=t.split(".").pop();"jpg"===o?e="jpeg":r.includes(o)&&e!==o&&(e=o)}return o[e]||r.find((t=>t===e))||"png"}function _handleSize(e){const{chart:t,exporting:o}=isAllowedConfig(e.instr)||!1,{chart:r,exporting:i}=isAllowedConfig(e.globalOptions)||!1,{chart:n,exporting:s}=isAllowedConfig(e.themeOptions)||!1,a=e.height||o?.sourceHeight||t?.height||i?.sourceHeight||r?.height||s?.sourceHeight||n?.height||e.defaultHeight||400,l=e.width||o?.sourceWidth||t?.width||i?.sourceWidth||r?.width||s?.sourceWidth||n?.width||e.defaultWidth||600,c=roundNumber(Math.max(.1,Math.min(e.scale||o?.scale||i?.scale||s?.scale||e.defaultScale||1,5)),2);e.height=a,e.width=l,e.scale=c;for(let t of["height","width","scale"])"string"==typeof e[t]&&(e[t]=+e[t].replace(/px|%/gi,""))}function _handleCustomLogic(e){if(e.allowCodeExecution){try{e.resources=_handleResources(e.resources,e.allowFileResources,!0),e.resources=validateOption("resources",e.resources)}catch(t){log(2,"[chart] The `resources` cannot be loaded."),e.resources=null}try{e.customCode=_handleCustomCode(e.customCode,e.allowFileResources),e.customCode=validateOption("customCode",e.customCode)}catch(t){logWithStack(2,t,"[chart] The `customCode` cannot be loaded."),e.customCode=null}try{e.callback=_handleCustomCode(e.callback,e.allowFileResources,!0),e.callback=validateOption("callback",e.callback)}catch(t){logWithStack(2,t,"[chart] The `callback` cannot be loaded."),e.callback=null}[null,void 0].includes(e.customCode)&&log(3,"[chart] No value for the `customCode` option found."),[null,void 0].includes(e.callback)&&log(3,"[chart] No value for the `callback` option found."),[null,void 0].includes(e.resources)&&log(3,"[chart] No value for the `resources` option found.")}else if(e.callback||e.resources||e.customCode)throw e.callback=null,e.resources=null,e.customCode=null,new ExportError("[chart] The 'callback', 'resources', and 'customCode' options have been disabled for this server.",403)}function _handleResources(e=null,t,o){let r=e;r||(e="resources.json");const i=["js","css","files"];let n=!1;t&&"string"==typeof e&&e.endsWith(".json")?r=isAllowedConfig(readFileSync(getAbsolutePath(e),"utf8"),!1,o):(r=isAllowedConfig(e,!1,o),r&&!t&&delete r.files);for(const e in r)i.includes(e)?n||(n=!0):delete r[e];return n?(r.files&&(r.files=r.files.map((e=>e.trim())),(!r.files||r.files.length<=0)&&delete r.files),r):null}function _handleCustomCode(e,t,o=!1){if(e&&"string"==typeof e)return(e=e.trim()).endsWith(".js")?t?_handleCustomCode(readFileSync(getAbsolutePath(e),"utf8"),t,o):null:!o&&(e.startsWith("function()")||e.startsWith("function ()")||e.startsWith("()=>")||e.startsWith("() =>"))?`(${e})()`:e.replace(/;$/,"")}function _handleGlobalAndTheme(e,t){const{allowFileResources:o,allowCodeExecution:r}=t;["globalOptions","themeOptions"].forEach((t=>{try{e[t]&&(o&&"string"==typeof e[t]&&e[t].endsWith(".json")?e[t]=isAllowedConfig(readFileSync(getAbsolutePath(e[t]),"utf8"),!0,r):e[t]=isAllowedConfig(e[t],!0,r),e[t]=validateOption(t,e[t]))}catch(o){logWithStack(2,o,`[chart] The \`${t}\` cannot be loaded.`),e[t]=null}})),[null,void 0].includes(e.globalOptions)&&log(3,"[chart] No value for the `globalOptions` option found."),[null,void 0].includes(e.themeOptions)&&log(3,"[chart] No value for the `themeOptions` option found.")}function _checkDataSize(e){const t=Buffer.byteLength(JSON.stringify(e),"utf-8");if(log(3,`[chart] The current total size of the data for the export process is around ${(t/1048576).toFixed(2)}MB.`),t>=104857600)throw new ExportError("[chart] The data for the export process exceeds 100MB limit.")}const timerIds=[];function addTimer(e){timerIds.push(e)}function clearAllTimers(){log(4,"[timer] Clearing all registered intervals and timeouts.");for(const e of timerIds)clearInterval(e),clearTimeout(e)}function logErrorMiddleware(e,t,o,r){return logWithStack(1,e),"development"!==getOptions().other.nodeEnv&&delete e.stack,r(e)}function returnErrorMiddleware(e,t,o,r){const{message:i,stack:n}=e,s=e.statusCode||400;o.status(s).json({statusCode:s,message:i,stack:n})}function errorMiddleware(e){e.use(logErrorMiddleware),e.use(returnErrorMiddleware)}function rateLimitingMiddleware(e,t){try{if(e&&t.enable){const o="Too many requests, you have been rate limited. Please try again later.",r={window:t.window||1,maxRequests:t.maxRequests||30,delay:t.delay||0,trustProxy:t.trustProxy||!1,skipKey:t.skipKey||null,skipToken:t.skipToken||null};r.trustProxy&&e.enable("trust proxy");const i=rateLimit({windowMs:60*r.window*1e3,limit:r.maxRequests,delayMs:r.delay,handler:(e,t)=>{t.format({json:()=>{t.status(429).send({message:o})},default:()=>{t.status(429).send(o)}})},skip:e=>null!==r.skipKey&&null!==r.skipToken&&e.query.key===r.skipKey&&e.query.access_token===r.skipToken&&(log(4,"[rate limiting] Skipping rate limiter."),!0)});e.use(i),log(3,`[rate limiting] Enabled rate limiting with ${r.maxRequests} requests per ${r.window} minute for each IP, trusting proxy: ${r.trustProxy}.`)}}catch(e){throw new ExportError("[rate limiting] Could not configure and set the rate limiting options.",500).setError(e)}}function contentTypeMiddleware(e,t,o){try{const t=e.headers["content-type"]||"";if(!t.includes("application/json")&&!t.includes("application/x-www-form-urlencoded")&&!t.includes("multipart/form-data"))throw new ExportError("[validation] Content-Type must be application/json, application/x-www-form-urlencoded, or multipart/form-data.",415);return o()}catch(e){return o(e)}}function requestBodyMiddleware(e,t,o){try{const t=e.body,r=v4();if(!t||isObjectEmpty(t))throw log(2,`[validation] Request [${r}] - The request from ${e.headers["x-forwarded-for"]||e.connection.remoteAddress} was incorrect. Received payload is empty.`),new ExportError(`[validation] Request [${r}] - The request body is required. Please ensure that your Content-Type header is correct. Accepted types are 'application/json' and 'multipart/form-data'.`,400);const i=getAllowCodeExecution(),n=isAllowedConfig(t.instr||t.options||t.infile||t.data,!0,i);if(null===n&&!t.svg)throw log(2,`[validation] Request [${r}] - The request from ${e.headers["x-forwarded-for"]||e.connection.remoteAddress} was incorrect. Received payload is missing correct chart data for export: ${JSON.stringify(t)}.`),new ExportError(`[validation] Request [${r}] - No correct chart data found. Ensure that you are using either application/json or multipart/form-data headers. If sending JSON, make sure the chart data is in the 'infile', 'options', or 'data' attribute. If sending SVG, ensure it is in the 'svg' attribute.`,400);if(t.svg&&isPrivateRangeUrlFound(t.svg))throw new ExportError(`[validation] Request [${r}] - SVG potentially contain at least one forbidden URL in 'xlink:href' element. Please review the SVG content and ensure that all referenced URLs comply with security policies.`,400);return e.validatedOptions={requestId:r,export:{instr:n,svg:t.svg,outfile:t.outfile||`${e.params.filename||"chart"}.${t.type||"png"}`,type:t.type,constr:t.constr,b64:t.b64,noDownload:t.noDownload,height:t.height,width:t.width,scale:t.scale,globalOptions:isAllowedConfig(t.globalOptions,!0,i),themeOptions:isAllowedConfig(t.themeOptions,!0,i)},customLogic:{allowCodeExecution:i,allowFileResources:!1,customCode:t.customCode,callback:t.callback,resources:isAllowedConfig(t.resources,!0,i)}},o()}catch(e){return o(e)}}function validationMiddleware(e){e.post(["/","/:filename"],contentTypeMiddleware),e.post(["/","/:filename"],requestBodyMiddleware)}const reversedMime={png:"image/png",jpeg:"image/jpeg",gif:"image/gif",pdf:"application/pdf",svg:"image/svg+xml"};async function requestExport(e,t,o){try{const o=measureTime();let r=!1;e.socket.on("close",(e=>{e&&(r=!0)}));const i=e.validatedOptions,n=i.requestId;log(4,`[export] Request [${n}] - Got an incoming HTTP request.`),await startExport(i,((i,s)=>{if(e.socket.removeAllListeners("close"),r)log(3,`[export] Request [${n}] - The client closed the connection before the chart finished processing.`);else{if(i)throw i;if(!s||!s.result)throw log(2,`[export] Request [${n}] - Request from ${e.headers["x-forwarded-for"]||e.connection.remoteAddress} was incorrect. Received result is ${s.result}.`),new ExportError(`[export] Request [${n}] - Unexpected return of the export result from the chart generation. Please check your request data.`,400);if(s.result){log(3,`[export] Request [${n}] - The whole exporting process took ${o()}ms.`);const{type:e,b64:r,noDownload:i,outfile:a}=s.options.export;return r?t.send(getBase64(s.result,e)):(t.header("Content-Type",reversedMime[e]||"image/png"),i||t.attachment(a),"svg"===e?t.send(s.result):t.send(Buffer.from(s.result,"base64")))}}}))}catch(e){return o(e)}}function exportRoutes(e){e.post("/",requestExport),e.post("/:filename",requestExport)}const serverStartTime=new Date,packageFile=JSON.parse(readFileSync(join(__dirname,"package.json"),"utf8")),successRates=[],recordInterval=6e4,windowSize=30;function _calculateMovingAverage(){return successRates.reduce(((e,t)=>e+t),0)/successRates.length}function _startSuccessRate(){return setInterval((()=>{const e=getPoolStats(),t=0===e.exportsAttempted?1:e.exportsPerformed/e.exportsAttempted*100;successRates.push(t),successRates.length>windowSize&&successRates.shift()}),recordInterval)}function healthRoutes(e){addTimer(_startSuccessRate()),e.get("/health",((e,t,o)=>{try{log(4,"[health] Returning server health.");const e=getPoolStats(),o=successRates.length,r=_calculateMovingAverage();t.send({status:"OK",bootTime:serverStartTime,uptime:`${Math.floor((getNewDateTime()-serverStartTime.getTime())/1e3/60)} minutes`,serverVersion:packageFile.version,highchartsVersion:getHcVersion(),averageExportTime:e.timeSpentAverage,attemptedExports:e.exportsAttempted,performedExports:e.exportsPerformed,failedExports:e.exportsDropped,sucessRatio:e.exportsPerformed/e.exportsAttempted*100,pool:getPoolInfoJSON(),period:o,movingAverage:r,message:isNaN(r)||!successRates.length?"Too early to report. No exports made yet. Please check back soon.":`Last ${o} minutes had a success rate of ${r.toFixed(2)}%.`,svgExports:e.exportsFromSvg,jsonExports:e.exportsFromOptions,svgExportsAttempts:e.exportsFromSvgAttempts,jsonExportsAttempts:e.exportsFromOptionsAttempts})}catch(e){return o(e)}}))}function uiRoutes(e){getOptions().ui.enable&&e.get(getOptions().ui.route||"/",((e,t,o)=>{try{log(4,"[ui] Returning UI for the export."),t.sendFile(join(__dirname,"public","index.html"),{acceptRanges:!1})}catch(e){return o(e)}}))}function versionChangeRoutes(e){e.post("/version_change/:newVersion",(async(e,t,o)=>{try{log(4,"[version] Changing Highcharts version.");const o=envs.HIGHCHARTS_ADMIN_TOKEN;if(!o||!o.length)throw new ExportError("[version] The server is not configured to perform run-time version changes: `HIGHCHARTS_ADMIN_TOKEN` is not set.",401);const r=e.get("hc-auth");if(!r||r!==o)throw new ExportError("[version] Invalid or missing token: Set the token in the hc-auth header.",401);const i=e.params.newVersion;if(!i)throw new ExportError("[version] No new version supplied.",400);try{await updateHcVersion(i)}catch(e){throw new ExportError(`[version] Version change: ${e.message}`,400).setError(e)}t.status(200).send({statusCode:200,highchartsVersion:getHcVersion(),message:`Successfully updated Highcharts to version: ${i}.`})}catch(e){return o(e)}}))}const activeServers=new Map,app=express();async function startServer(e={}){try{const t=updateOptions({server:e});if(!(e=t.server).enable||!app)throw new ExportError("[server] Server cannot be started (not enabled or no correct Express app found).",500);const o=1024*e.uploadLimit*1024,r=multer.memoryStorage(),i=multer({storage:r,limits:{fieldSize:o}});if(app.disable("x-powered-by"),app.use(cors({methods:["POST","GET","OPTIONS"]})),app.use(((e,t,o)=>{t.set("Accept-Ranges","none"),o()})),app.use(express.json({limit:o})),app.use(express.urlencoded({extended:!0,limit:o})),app.use(i.none()),app.use(express.static(join(__dirname,"public"))),!e.ssl.force){const t=http.createServer(app);_attachServerErrorHandlers(t),t.listen(e.port,e.host,(()=>{activeServers.set(e.port,t),log(3,`[server] Started HTTP server on ${e.host}:${e.port}.`)}))}if(e.ssl.enable){let t,o;try{t=readFileSync(join(getAbsolutePath(e.ssl.certPath),"server.key"),"utf8"),o=readFileSync(join(getAbsolutePath(e.ssl.certPath),"server.crt"),"utf8")}catch(t){log(2,`[server] Unable to load key/certificate from the '${e.ssl.certPath}' path. Could not run secured layer server.`)}if(t&&o){const r=https.createServer({key:t,cert:o},app);_attachServerErrorHandlers(r),r.listen(e.ssl.port,e.host,(()=>{activeServers.set(e.ssl.port,r),log(3,`[server] Started HTTPS server on ${e.host}:${e.ssl.port}.`)}))}}rateLimitingMiddleware(app,e.rateLimiting),validationMiddleware(app),exportRoutes(app),healthRoutes(app),uiRoutes(app),versionChangeRoutes(app),errorMiddleware(app)}catch(e){throw new ExportError("[server] Could not configure and start the server.",500).setError(e)}}function closeServers(){if(activeServers.size>0){log(4,"[server] Closing all servers.");for(const[e,t]of activeServers)t.close((()=>{activeServers.delete(e),log(4,`[server] Closed server on port: ${e}.`)}))}}function getServers(){return activeServers}function getExpress(){return express}function getApp(){return app}function enableRateLimiting(e){const t=updateOptions({server:{rateLimiting:e}});rateLimitingMiddleware(app,t.server.rateLimitingOptions)}function use(e,...t){app.use(e,...t)}function get(e,...t){app.get(e,...t)}function post(e,...t){app.post(e,...t)}function _attachServerErrorHandlers(e){e.on("clientError",((e,t)=>{logWithStack(1,e,`[server] Client error: ${e.message}, destroying socket.`),t.destroy()})),e.on("error",(e=>{logWithStack(1,e,`[server] Server error: ${e.message}`)})),e.on("connection",(e=>{e.on("error",(e=>{logWithStack(1,e,`[server] Socket error: ${e.message}`)}))}))}var server={startServer:startServer,closeServers:closeServers,getServers:getServers,getExpress:getExpress,getApp:getApp,enableRateLimiting:enableRateLimiting,use:use,get:get,post:post};async function shutdownCleanUp(e=0){await Promise.allSettled([clearAllTimers(),closeServers(),killPool()]),process.exit(e)}async function initExport(e={}){const t=updateOptions(e);setAllowCodeExecution(t.customLogic.allowCodeExecution),initLogging(t.logging),t.other.listenToProcessExits&&_attachProcessExitListeners(),await checkCache(t.highcharts,t.server.proxy),await initPool(t.pool,t.puppeteer.args)}function _attachProcessExitListeners(){log(3,"[process] Attaching exit listeners to the process."),process.on("exit",(e=>{log(4,`[process] Process exited with code: ${e}.`)})),process.on("SIGINT",(async(e,t)=>{log(4,`[process] The ${e} event with code: ${t}.`),await shutdownCleanUp()})),process.on("SIGTERM",(async(e,t)=>{log(4,`[process] The ${e} event with code: ${t}.`),await shutdownCleanUp()})),process.on("SIGHUP",(async(e,t)=>{log(4,`[process] The ${e} event with code: ${t}.`),await shutdownCleanUp()})),process.on("uncaughtException",(async(e,t)=>{logWithStack(1,e,`[process] The ${t} error.`),await shutdownCleanUp(1)}))}var index={...server,getOptions:getOptions,updateOptions:updateOptions,mapToNewOptions:mapToNewOptions,validateOption:validateOption,validateOptions:validateOptions,initExport:initExport,singleExport:singleExport,batchExport:batchExport,startExport:startExport,killPool:killPool,shutdownCleanUp:shutdownCleanUp,log:log,logWithStack:logWithStack,logZodIssues:logZodIssues,setLogLevel:function(e){setLogLevel(updateOptions({logging:{level:e}}).logging.level)},enableConsoleLogging:function(e){enableConsoleLogging(updateOptions({logging:{toConsole:e}}).logging.toConsole)},enableFileLogging:function(e,t,o){const r=updateOptions({logging:{dest:e,file:t,toFile:o}});enableFileLogging(r.logging.dest,r.logging.file,r.logging.toFile)}};export{index as default,initExport}; //# sourceMappingURL=index.esm.js.map diff --git a/dist/index.esm.js.map b/dist/index.esm.js.map index 04e03491..9e201678 100644 --- a/dist/index.esm.js.map +++ b/dist/index.esm.js.map @@ -1 +1 @@ -{"version":3,"file":"index.esm.js","sources":["../lib/utils.js","../lib/logger.js","../lib/schemas/config.js","../lib/validation.js","../lib/errors/ExportError.js","../lib/config.js","../lib/fetch.js","../lib/cache.js","../lib/highcharts.js","../lib/browser.js","../templates/svgExport/css.js","../templates/svgExport/svgExport.js","../lib/export.js","../lib/pool.js","../lib/sanitize.js","../lib/chart.js","../lib/timer.js","../lib/server/middlewares/error.js","../lib/server/middlewares/rateLimiting.js","../lib/server/middlewares/validation.js","../lib/server/routes/export.js","../lib/server/routes/health.js","../lib/server/routes/ui.js","../lib/server/routes/versionChange.js","../lib/server/server.js","../lib/resourceRelease.js","../lib/index.js"],"sourcesContent":["/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * @overview The Highcharts Export Server utility module provides\r\n * a comprehensive set of helper functions and constants designed to streamline\r\n * and enhance various operations required for Highcharts export tasks.\r\n */\r\n\r\nimport { isAbsolute, normalize, resolve } from 'path';\r\nimport { fileURLToPath } from 'url';\r\n\r\nconst MAX_BACKOFF_ATTEMPTS = 6;\r\n\r\n// The directory path\r\nexport const __dirname = fileURLToPath(new URL('../.', import.meta.url));\r\n\r\n/**\r\n * Clears and standardizes text by replacing multiple consecutive whitespace\r\n * characters with a single space and trimming any leading or trailing\r\n * whitespace.\r\n *\r\n * @function clearText\r\n *\r\n * @param {string} text - The input text to be cleared.\r\n * @param {RegExp} [rule=/\\s\\s+/g] - The regular expression rule to match\r\n * multiple consecutive whitespace characters. The default value\r\n * is the '/\\s\\s+/g' RegExp.\r\n * @param {string} [replacer=' '] - The string used to replace multiple\r\n * consecutive whitespace characters. The default value is the ' ' string.\r\n *\r\n * @returns {string} The cleared and standardized text.\r\n */\r\nexport function clearText(text, rule = /\\s\\s+/g, replacer = ' ') {\r\n return text.replaceAll(rule, replacer).trim();\r\n}\r\n\r\n/**\r\n * Creates a deep copy of the given object or array.\r\n *\r\n * @function deepCopy\r\n *\r\n * @param {(Object|Array)} objArr - The object or array to be deeply copied.\r\n *\r\n * @returns {(Object|Array)} The deep copy of the provided object or array.\r\n */\r\nexport function deepCopy(objArr) {\r\n // If the `objArr` is null or not of the `object` type, return it\r\n if (objArr === null || typeof objArr !== 'object') {\r\n return objArr;\r\n }\r\n\r\n // Prepare either a new array or a new object\r\n const objArrCopy = Array.isArray(objArr) ? [] : {};\r\n\r\n // Recursively copy each property\r\n for (const key in objArr) {\r\n if (Object.prototype.hasOwnProperty.call(objArr, key)) {\r\n objArrCopy[key] = deepCopy(objArr[key]);\r\n }\r\n }\r\n\r\n // Return the copied object\r\n return objArrCopy;\r\n}\r\n\r\n/**\r\n * Implements an exponential backoff strategy for retrying a function until\r\n * a certain number of attempts are reached.\r\n *\r\n * @async\r\n * @function expBackoff\r\n *\r\n * @param {Function} fn - The function to be retried.\r\n * @param {number} [attempt=0] - The current attempt number. The default value\r\n * is `0`.\r\n * @param {...unknown} args - Arguments to be passed to the function.\r\n *\r\n * @returns {Promise} A Promise that resolves to the result\r\n * of the function if successful.\r\n *\r\n * @throws {Error} Throws an `Error` if the maximum number of attempts\r\n * is reached.\r\n */\r\nexport async function expBackoff(fn, attempt = 0, ...args) {\r\n try {\r\n // Try to call the function\r\n return await fn(...args);\r\n } catch (error) {\r\n // Calculate delay in ms\r\n const delayInMs = 2 ** attempt * 1000;\r\n\r\n // If the attempt exceeds the maximum attempts of repeat, throw an error\r\n if (++attempt >= MAX_BACKOFF_ATTEMPTS) {\r\n throw error;\r\n }\r\n\r\n // Wait given amount of time\r\n await new Promise((response) => setTimeout(response, delayInMs));\r\n\r\n /// TO DO: Correct\r\n // // Information about the resource timeout\r\n // log(\r\n // 3,\r\n // `[utils] Waited ${delayInMs}ms until next call for the resource of ID: ${args[0]}.`\r\n // );\r\n\r\n // Try again\r\n return expBackoff(fn, attempt, ...args);\r\n }\r\n}\r\n\r\n/**\r\n * Checks if the given path is relative or absolute and returns the corrected,\r\n * absolute path.\r\n *\r\n * @function getAbsolutePath\r\n *\r\n * @param {string} path - The path to be checked on.\r\n *\r\n * @returns {string} The absolute path.\r\n */\r\nexport function getAbsolutePath(path) {\r\n return isAbsolute(path) ? normalize(path) : resolve(path);\r\n}\r\n\r\n/**\r\n * Converts input data to a Base64 string based on the export type.\r\n *\r\n * @function getBase64\r\n *\r\n * @param {string} input - The input to be transformed to Base64 format.\r\n * @param {string} type - The original export type.\r\n *\r\n * @returns {string} The Base64 string representation of the input.\r\n */\r\nexport function getBase64(input, type) {\r\n // For pdf and svg types the input must be transformed to Base64 from a buffer\r\n if (type === 'pdf' || type == 'svg') {\r\n return Buffer.from(input, 'utf8').toString('base64');\r\n }\r\n\r\n // For png and jpeg input is already a Base64 string\r\n return input;\r\n}\r\n\r\n/**\r\n * Returns stringified date without the GMT text information.\r\n *\r\n * @function getNewDate\r\n */\r\nexport function getNewDate() {\r\n // Get rid of the GMT text information\r\n return new Date().toString().split('(')[0].trim();\r\n}\r\n\r\n/**\r\n * Returns the stored time value in milliseconds.\r\n *\r\n * @function getNewDateTime\r\n */\r\nexport function getNewDateTime() {\r\n return new Date().getTime();\r\n}\r\n\r\n/**\r\n * Checks if the given item is an object.\r\n *\r\n * @function isObject\r\n *\r\n * @param {unknown} item - The item to be checked.\r\n *\r\n * @returns {boolean} Returns `true` if the item is an object, `false`\r\n * otherwise.\r\n */\r\nexport function isObject(item) {\r\n return Object.prototype.toString.call(item) === '[object Object]';\r\n}\r\n\r\n/**\r\n * Checks if the given object is empty.\r\n *\r\n * @function isObjectEmpty\r\n *\r\n * @param {Object} item - The object to be checked.\r\n *\r\n * @returns {boolean} Returns `true` if the item is an empty object, `false`\r\n * otherwise.\r\n */\r\nexport function isObjectEmpty(item) {\r\n return (\r\n typeof item === 'object' &&\r\n !Array.isArray(item) &&\r\n item !== null &&\r\n Object.keys(item).length === 0\r\n );\r\n}\r\n\r\n/**\r\n * Checks if a private IP range URL is found in the given string.\r\n *\r\n * @function isPrivateRangeUrlFound\r\n *\r\n * @param {string} item - The string to be checked for a private IP range URL.\r\n *\r\n * @returns {boolean} Returns `true` if a private IP range URL is found, `false`\r\n * otherwise.\r\n */\r\nexport function isPrivateRangeUrlFound(item) {\r\n const regexPatterns = [\r\n /xlink:href=\"(?:http:\\/\\/|https:\\/\\/)?localhost\\b/,\r\n /xlink:href=\"(?:http:\\/\\/|https:\\/\\/)?10\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\b/,\r\n /xlink:href=\"(?:http:\\/\\/|https:\\/\\/)?127\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\b/,\r\n /xlink:href=\"(?:http:\\/\\/|https:\\/\\/)?172\\.(1[6-9]|2[0-9]|3[0-1])\\.\\d{1,3}\\.\\d{1,3}\\b/,\r\n /xlink:href=\"(?:http:\\/\\/|https:\\/\\/)?192\\.168\\.\\d{1,3}\\.\\d{1,3}\\b/\r\n ];\r\n\r\n return regexPatterns.some((pattern) => pattern.test(item));\r\n}\r\n\r\n/**\r\n * Utility to measure elapsed time using the Node.js `process.hrtime()` method.\r\n *\r\n * @function measureTime\r\n *\r\n * @returns {Function} A function to calculate the elapsed time in milliseconds.\r\n */\r\nexport function measureTime() {\r\n const start = process.hrtime.bigint();\r\n return () => Number(process.hrtime.bigint() - start) / 1000000;\r\n}\r\n\r\n/**\r\n * Rounds a number to the specified precision.\r\n *\r\n * @function roundNumber\r\n *\r\n * @param {number} value - The number to be rounded.\r\n * @param {number} precision - The number of decimal places to round to.\r\n *\r\n * @returns {number} The rounded number.\r\n */\r\nexport function roundNumber(value, precision = 1) {\r\n const multiplier = Math.pow(10, precision || 0);\r\n return Math.round(+value * multiplier) / multiplier;\r\n}\r\n\r\n/**\r\n * Converts a value to a boolean.\r\n *\r\n * @function toBoolean\r\n *\r\n * @param {unknown} item - The value to be converted to a boolean.\r\n *\r\n * @returns {boolean} The boolean representation of the input value.\r\n */\r\nexport function toBoolean(item) {\r\n return ['false', 'undefined', 'null', 'NaN', '0', ''].includes(item)\r\n ? false\r\n : !!item;\r\n}\r\n\r\nexport default {\r\n __dirname,\r\n clearText,\r\n deepCopy,\r\n expBackoff,\r\n getAbsolutePath,\r\n getBase64,\r\n getNewDate,\r\n getNewDateTime,\r\n isObject,\r\n isObjectEmpty,\r\n isPrivateRangeUrlFound,\r\n measureTime,\r\n roundNumber,\r\n toBoolean\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * @overview A module for managing logging functionality with customizable\r\n * log levels, console and file logging options, and error handling support.\r\n * The module also ensures that file-based logs are stored in a structured\r\n * directory, creating the necessary paths automatically if they do not exist.\r\n */\r\n\r\nimport { appendFile, existsSync, mkdirSync } from 'fs';\r\nimport { join } from 'path';\r\n\r\nimport { getAbsolutePath, getNewDate } from './utils.js';\r\n\r\n// The available colors\r\nconst colors = ['red', 'yellow', 'blue', 'gray', 'green'];\r\n\r\n// The default logging config\r\nconst logging = {\r\n // Flags for logging status\r\n toConsole: true,\r\n toFile: false,\r\n pathCreated: false,\r\n // Full path to the log file\r\n pathToLog: '',\r\n // Log levels\r\n levelsDesc: [\r\n {\r\n title: 'error',\r\n color: colors[0]\r\n },\r\n {\r\n title: 'warning',\r\n color: colors[1]\r\n },\r\n {\r\n title: 'notice',\r\n color: colors[2]\r\n },\r\n {\r\n title: 'verbose',\r\n color: colors[3]\r\n },\r\n {\r\n title: 'benchmark',\r\n color: colors[4]\r\n }\r\n ]\r\n};\r\n\r\n/**\r\n * Logs a message with a specified log level. Accepts a variable number\r\n * of arguments. The arguments after the `level` are passed to `console.log`\r\n * and/or used to construct and append messages to a log file.\r\n *\r\n * @function log\r\n *\r\n * @param {...unknown} args - An array of arguments where the first is the log\r\n * level and the remaining are strings used to build the log message.\r\n *\r\n * @returns {void} Exits the function execution if attempting to log at a level\r\n * higher than allowed.\r\n */\r\nexport function log(...args) {\r\n const [newLevel, ...texts] = args;\r\n\r\n // Current logging options\r\n const { levelsDesc, level } = logging;\r\n\r\n // Check if the log level is within a correct range or is it a benchmark log\r\n if (\r\n newLevel !== 5 &&\r\n (newLevel === 0 || newLevel > level || level > levelsDesc.length)\r\n ) {\r\n return;\r\n }\r\n\r\n // Create a message's prefix\r\n const prefix = `${getNewDate()} [${levelsDesc[newLevel - 1].title}] -`;\r\n\r\n // Log to file\r\n if (logging.toFile) {\r\n _logToFile(texts, prefix);\r\n }\r\n\r\n // Log to console\r\n if (logging.toConsole) {\r\n console.log.apply(\r\n undefined,\r\n [prefix.toString()[logging.levelsDesc[newLevel - 1].color]].concat(texts)\r\n );\r\n }\r\n}\r\n\r\n/**\r\n * Logs an error message along with its stack trace. Optionally, a custom\r\n * message can be provided.\r\n *\r\n * @function logWithStack\r\n *\r\n * @param {number} newLevel - The log level.\r\n * @param {Error} error - The error object containing the stack trace.\r\n * @param {string} customMessage - An optional custom message to be included\r\n * in the log alongside the error.\r\n *\r\n * @returns {void} Exits the function execution if attempting to log at a level\r\n * higher than allowed.\r\n */\r\nexport function logWithStack(newLevel, error, customMessage) {\r\n // Get the main message\r\n const mainMessage = customMessage || (error && error.message) || '';\r\n\r\n // Current logging options\r\n const { level, levelsDesc } = logging;\r\n\r\n // Check if the log level is within a correct range\r\n if (newLevel === 0 || newLevel > level || level > levelsDesc.length) {\r\n return;\r\n }\r\n\r\n // Create a message's prefix\r\n const prefix = `${getNewDate()} [${levelsDesc[newLevel - 1].title}] -`;\r\n\r\n // Add the whole stack message\r\n const stackMessage = error && error.stack;\r\n\r\n // Combine custom message or error message with error stack message, if exists\r\n const texts = [mainMessage];\r\n if (stackMessage) {\r\n texts.push('\\n', stackMessage);\r\n }\r\n\r\n // Log to file\r\n if (logging.toFile) {\r\n _logToFile(texts, prefix);\r\n }\r\n\r\n // Log to console\r\n if (logging.toConsole) {\r\n console.log.apply(\r\n undefined,\r\n [prefix.toString()[logging.levelsDesc[newLevel - 1].color]].concat([\r\n texts.shift()[colors[newLevel - 1]],\r\n ...texts\r\n ])\r\n );\r\n }\r\n}\r\n\r\n/**\r\n * Logs an error message related to Zod validation issues. Optionally, a custom\r\n * message can be provided.\r\n *\r\n * @function logZodIssues\r\n *\r\n * @param {number} newLevel - The log level.\r\n * @param {Error[]} issues - An array of Zod validation issues.\r\n * @param {string} customMessage - An optional custom message to be included\r\n * in the log alongside the error.\r\n */\r\nexport function logZodIssues(newLevel, issues, customMessage) {\r\n logWithStack(\r\n newLevel,\r\n null,\r\n [\r\n `${customMessage || '[validation] Validation error'} - the following Zod issues occured:`,\r\n ...(issues || []).map((issue) => `- ${issue.message}`)\r\n ].join('\\n')\r\n );\r\n}\r\n\r\n/**\r\n * Initializes logging with the specified logging configuration.\r\n *\r\n * @function initLogging\r\n *\r\n * @param {Object} loggingOptions - The configuration object containing\r\n * `logging` options.\r\n */\r\nexport function initLogging(loggingOptions) {\r\n // Get options from the `loggingOptions` object\r\n const { level, dest, file, toConsole, toFile } = loggingOptions;\r\n\r\n // Reset flags to the default values\r\n logging.pathCreated = false;\r\n logging.pathToLog = '';\r\n\r\n // Set the logging level\r\n setLogLevel(level);\r\n\r\n // Set the console logging\r\n enableConsoleLogging(toConsole);\r\n\r\n // Set the file logging\r\n enableFileLogging(dest, file, toFile);\r\n}\r\n\r\n/**\r\n * Sets the log level to the specified value. Log levels are (`0` = no logging,\r\n * `1` = error, `2` = warning, `3` = notice, `4` = verbose, or `5` = benchmark).\r\n *\r\n * @function setLogLevel\r\n *\r\n * @param {number} level - The log level to be set.\r\n */\r\nexport function setLogLevel(level) {\r\n if (\r\n Number.isInteger(level) &&\r\n level >= 0 &&\r\n level <= logging.levelsDesc.length\r\n ) {\r\n // Update the module logging's `level` option\r\n logging.level = level;\r\n }\r\n}\r\n\r\n/**\r\n * Enables console logging.\r\n *\r\n * @function enableConsoleLogging\r\n *\r\n * @param {boolean} toConsole - The flag for setting the logging to the console.\r\n */\r\nexport function enableConsoleLogging(toConsole) {\r\n // Update the module logging's `toConsole` option\r\n logging.toConsole = !!toConsole;\r\n}\r\n\r\n/**\r\n * Enables file logging with the specified destination and log file name.\r\n *\r\n * @function enableFileLogging\r\n *\r\n * @param {string} dest - The destination path where the log file should\r\n * be saved.\r\n * @param {string} file - The name of the log file.\r\n * @param {boolean} toFile - A flag indicating whether logging should\r\n * be directed to a file.\r\n */\r\nexport function enableFileLogging(dest, file, toFile) {\r\n // Update the module logging's `toFile` option\r\n logging.toFile = !!toFile;\r\n\r\n // Set the `dest` and `file` options only if the file logging is enabled\r\n if (logging.toFile) {\r\n logging.dest = dest || 'log';\r\n logging.file = file || 'highcharts-export-server.log';\r\n }\r\n}\r\n\r\n/**\r\n * Logs the provided texts to a file, if file logging is enabled. It creates\r\n * the necessary directory structure if not already created and appends\r\n * the content, including an optional prefix, to the specified log file.\r\n *\r\n * @function _logToFile\r\n *\r\n * @param {Array} texts - An array of texts to be logged.\r\n * @param {string} prefix - An optional prefix to be added to each log entry.\r\n */\r\nfunction _logToFile(texts, prefix) {\r\n if (!logging.pathCreated) {\r\n // Create if does not exist\r\n !existsSync(getAbsolutePath(logging.dest)) &&\r\n mkdirSync(getAbsolutePath(logging.dest));\r\n\r\n // Create the full path\r\n logging.pathToLog = getAbsolutePath(join(logging.dest, logging.file));\r\n\r\n // We now assume the path is available, e.g. it's the responsibility\r\n // of the user to create the path with the correct access rights.\r\n logging.pathCreated = true;\r\n }\r\n\r\n // Add the content to a file\r\n appendFile(\r\n logging.pathToLog,\r\n [prefix].concat(texts).join(' ') + '\\n',\r\n (error) => {\r\n if (error && logging.toFile && logging.pathCreated) {\r\n logging.toFile = false;\r\n logging.pathCreated = false;\r\n logWithStack(2, error, `[logger] Unable to write to log file.`);\r\n }\r\n }\r\n );\r\n}\r\n\r\nexport default {\r\n log,\r\n logWithStack,\r\n logZodIssues,\r\n initLogging,\r\n setLogLevel,\r\n enableConsoleLogging,\r\n enableFileLogging\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * @overview Configuration management module for the Highcharts Export Server.\r\n * It provides a default configuration object with predefined default values,\r\n * descriptions, and characteristics for each option used in the Export Server.\r\n */\r\n\r\n/**\r\n * The default configuration object containing all available options, organized\r\n * by sections.\r\n *\r\n * This object includes:\r\n * - Default values for each option.\r\n * - Data types for validation.\r\n * - Names of corresponding environment variables.\r\n * - Descriptions of each property.\r\n * - Information used for prompts in interactive configuration.\r\n * - [Optional] Corresponding CLI argument names for CLI usage.\r\n * - [Optional] Legacy names from the previous PhantomJS-based server.\r\n */\r\nconst defaultConfig = {\r\n puppeteer: {\r\n args: {\r\n value: [\r\n '--allow-running-insecure-content',\r\n '--ash-no-nudges',\r\n '--autoplay-policy=user-gesture-required',\r\n '--block-new-web-contents',\r\n '--disable-accelerated-2d-canvas',\r\n '--disable-background-networking',\r\n '--disable-background-timer-throttling',\r\n '--disable-backgrounding-occluded-windows',\r\n '--disable-breakpad',\r\n '--disable-checker-imaging',\r\n '--disable-client-side-phishing-detection',\r\n '--disable-component-extensions-with-background-pages',\r\n '--disable-component-update',\r\n '--disable-default-apps',\r\n '--disable-dev-shm-usage',\r\n '--disable-domain-reliability',\r\n '--disable-extensions',\r\n '--disable-features=CalculateNativeWinOcclusion,InterestFeedContentSuggestions,WebOTP',\r\n '--disable-hang-monitor',\r\n '--disable-ipc-flooding-protection',\r\n '--disable-logging',\r\n '--disable-notifications',\r\n '--disable-offer-store-unmasked-wallet-cards',\r\n '--disable-popup-blocking',\r\n '--disable-print-preview',\r\n '--disable-prompt-on-repost',\r\n '--disable-renderer-backgrounding',\r\n '--disable-search-engine-choice-screen',\r\n '--disable-session-crashed-bubble',\r\n '--disable-setuid-sandbox',\r\n '--disable-site-isolation-trials',\r\n '--disable-speech-api',\r\n '--disable-sync',\r\n '--enable-unsafe-webgpu',\r\n '--hide-crash-restore-bubble',\r\n '--hide-scrollbars',\r\n '--metrics-recording-only',\r\n '--mute-audio',\r\n '--no-default-browser-check',\r\n '--no-first-run',\r\n '--no-pings',\r\n '--no-sandbox',\r\n '--no-startup-window',\r\n '--no-zygote',\r\n '--password-store=basic',\r\n '--process-per-tab',\r\n '--use-mock-keychain'\r\n ],\r\n types: ['string[]'],\r\n envLink: 'PUPPETEER_ARGS',\r\n cliName: 'puppeteerArgs',\r\n description: 'Array of Puppeteer arguments',\r\n promptOptions: {\r\n type: 'list',\r\n separator: ';'\r\n }\r\n }\r\n },\r\n highcharts: {\r\n version: {\r\n value: 'latest',\r\n types: ['string'],\r\n envLink: 'HIGHCHARTS_VERSION',\r\n description: 'Highcharts version',\r\n promptOptions: {\r\n type: 'text'\r\n }\r\n },\r\n cdnUrl: {\r\n value: 'https://code.highcharts.com',\r\n types: ['string'],\r\n envLink: 'HIGHCHARTS_CDN_URL',\r\n description: 'CDN URL for Highcharts scripts',\r\n promptOptions: {\r\n type: 'text'\r\n }\r\n },\r\n forceFetch: {\r\n value: false,\r\n types: ['boolean'],\r\n envLink: 'HIGHCHARTS_FORCE_FETCH',\r\n description: 'Flag to refetch scripts after each server rerun',\r\n promptOptions: {\r\n type: 'toggle'\r\n }\r\n },\r\n cachePath: {\r\n value: '.cache',\r\n types: ['string'],\r\n envLink: 'HIGHCHARTS_CACHE_PATH',\r\n description: 'Directory path for cached Highcharts scripts',\r\n promptOptions: {\r\n type: 'text'\r\n }\r\n },\r\n coreScripts: {\r\n value: ['highcharts', 'highcharts-more', 'highcharts-3d'],\r\n types: ['string[]'],\r\n envLink: 'HIGHCHARTS_CORE_SCRIPTS',\r\n description: 'Highcharts core scripts to fetch',\r\n promptOptions: {\r\n type: 'multiselect',\r\n instructions: 'Space: Select specific, A: Select all, Enter: Confirm'\r\n }\r\n },\r\n moduleScripts: {\r\n value: [\r\n 'stock',\r\n 'map',\r\n 'gantt',\r\n 'exporting',\r\n 'parallel-coordinates',\r\n 'accessibility',\r\n // 'annotations-advanced',\r\n 'boost-canvas',\r\n 'boost',\r\n 'data',\r\n 'data-tools',\r\n 'draggable-points',\r\n 'static-scale',\r\n 'broken-axis',\r\n 'heatmap',\r\n 'tilemap',\r\n 'tiledwebmap',\r\n 'timeline',\r\n 'treemap',\r\n 'treegraph',\r\n 'item-series',\r\n 'drilldown',\r\n 'histogram-bellcurve',\r\n 'bullet',\r\n 'funnel',\r\n 'funnel3d',\r\n 'geoheatmap',\r\n 'pyramid3d',\r\n 'networkgraph',\r\n 'overlapping-datalabels',\r\n 'pareto',\r\n 'pattern-fill',\r\n 'pictorial',\r\n 'price-indicator',\r\n 'sankey',\r\n 'arc-diagram',\r\n 'dependency-wheel',\r\n 'series-label',\r\n 'series-on-point',\r\n 'solid-gauge',\r\n 'sonification',\r\n // 'stock-tools',\r\n 'streamgraph',\r\n 'sunburst',\r\n 'variable-pie',\r\n 'variwide',\r\n 'vector',\r\n 'venn',\r\n 'windbarb',\r\n 'wordcloud',\r\n 'xrange',\r\n 'no-data-to-display',\r\n 'drag-panes',\r\n 'debugger',\r\n 'dumbbell',\r\n 'lollipop',\r\n 'cylinder',\r\n 'organization',\r\n 'dotplot',\r\n 'marker-clusters',\r\n 'hollowcandlestick',\r\n 'heikinashi',\r\n 'flowmap',\r\n 'export-data',\r\n 'navigator',\r\n 'textpath'\r\n ],\r\n types: ['string[]'],\r\n envLink: 'HIGHCHARTS_MODULE_SCRIPTS',\r\n description: 'Highcharts module scripts to fetch',\r\n promptOptions: {\r\n type: 'multiselect',\r\n instructions: 'Space: Select specific, A: Select all, Enter: Confirm'\r\n }\r\n },\r\n indicatorScripts: {\r\n value: ['indicators-all'],\r\n types: ['string[]'],\r\n envLink: 'HIGHCHARTS_INDICATOR_SCRIPTS',\r\n description: 'Highcharts indicator scripts to fetch',\r\n promptOptions: {\r\n type: 'multiselect',\r\n instructions: 'Space: Select specific, A: Select all, Enter: Confirm'\r\n }\r\n },\r\n customScripts: {\r\n value: [\r\n 'https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.30.1/moment.min.js',\r\n 'https://cdnjs.cloudflare.com/ajax/libs/moment-timezone/0.5.45/moment-timezone-with-data.min.js'\r\n ],\r\n types: ['string[]'],\r\n envLink: 'HIGHCHARTS_CUSTOM_SCRIPTS',\r\n description: 'Additional custom scripts or dependencies to fetch',\r\n promptOptions: {\r\n type: 'list',\r\n separator: ';'\r\n }\r\n }\r\n },\r\n export: {\r\n infile: {\r\n value: null,\r\n types: ['string', 'null'],\r\n envLink: 'EXPORT_INFILE',\r\n description:\r\n 'Input filename with type, formatted correctly as JSON or SVG',\r\n promptOptions: {\r\n type: 'text'\r\n }\r\n },\r\n instr: {\r\n value: null,\r\n types: ['Object', 'string', 'null'],\r\n envLink: 'EXPORT_INSTR',\r\n description:\r\n 'Overrides the `infile` with JSON, stringified JSON, or SVG input',\r\n promptOptions: {\r\n type: 'text'\r\n }\r\n },\r\n options: {\r\n value: null,\r\n types: ['Object', 'string', 'null'],\r\n envLink: 'EXPORT_OPTIONS',\r\n description: 'Alias for the `instr` option',\r\n promptOptions: {\r\n type: 'text'\r\n }\r\n },\r\n svg: {\r\n value: null,\r\n types: ['string', 'null'],\r\n envLink: 'EXPORT_SVG',\r\n description: 'SVG string representation of the chart to render',\r\n promptOptions: {\r\n type: 'text'\r\n }\r\n },\r\n batch: {\r\n value: null,\r\n types: ['string', 'null'],\r\n envLink: 'EXPORT_BATCH',\r\n description:\r\n 'Batch job string with input/output pairs: \"in=out;in=out;...\"',\r\n promptOptions: {\r\n type: 'text'\r\n }\r\n },\r\n outfile: {\r\n value: null,\r\n types: ['string', 'null'],\r\n envLink: 'EXPORT_OUTFILE',\r\n description:\r\n 'Output filename with type. Can be jpeg, png, pdf, or svg and ignores `type` option',\r\n promptOptions: {\r\n type: 'text'\r\n }\r\n },\r\n type: {\r\n value: 'png',\r\n types: ['string'],\r\n envLink: 'EXPORT_TYPE',\r\n description: 'File export format. Can be jpeg, png, pdf, or svg',\r\n promptOptions: {\r\n type: 'select',\r\n hint: 'Default: png',\r\n choices: ['png', 'jpeg', 'pdf', 'svg']\r\n }\r\n },\r\n constr: {\r\n value: 'chart',\r\n types: ['string'],\r\n envLink: 'EXPORT_CONSTR',\r\n description:\r\n 'Chart constructor. Can be chart, stockChart, mapChart, or ganttChart',\r\n promptOptions: {\r\n type: 'select',\r\n hint: 'Default: chart',\r\n choices: ['chart', 'stockChart', 'mapChart', 'ganttChart']\r\n }\r\n },\r\n b64: {\r\n value: false,\r\n types: ['boolean'],\r\n envLink: 'EXPORT_B64',\r\n description:\r\n 'Whether or not to the chart should be received in Base64 format instead of binary',\r\n promptOptions: {\r\n type: 'toggle'\r\n }\r\n },\r\n noDownload: {\r\n value: false,\r\n types: ['boolean'],\r\n envLink: 'EXPORT_NO_DOWNLOAD',\r\n description:\r\n 'Whether or not to include or exclude attachment headers in the response',\r\n promptOptions: {\r\n type: 'toggle'\r\n }\r\n },\r\n height: {\r\n value: null,\r\n types: ['number', 'null'],\r\n envLink: 'EXPORT_HEIGHT',\r\n description: 'Height of the exported chart, overrides chart settings',\r\n promptOptions: {\r\n type: 'number'\r\n }\r\n },\r\n width: {\r\n value: null,\r\n types: ['number', 'null'],\r\n envLink: 'EXPORT_WIDTH',\r\n description: 'Width of the exported chart, overrides chart settings',\r\n promptOptions: {\r\n type: 'number'\r\n }\r\n },\r\n scale: {\r\n value: null,\r\n types: ['number', 'null'],\r\n envLink: 'EXPORT_SCALE',\r\n description:\r\n 'Scale of the exported chart, overrides chart settings. Ranges from 0.1 to 5.0',\r\n promptOptions: {\r\n type: 'number'\r\n }\r\n },\r\n defaultHeight: {\r\n value: 400,\r\n types: ['number'],\r\n envLink: 'EXPORT_DEFAULT_HEIGHT',\r\n description: 'Default height of the exported chart if not set',\r\n promptOptions: {\r\n type: 'number'\r\n }\r\n },\r\n defaultWidth: {\r\n value: 600,\r\n types: ['number'],\r\n envLink: 'EXPORT_DEFAULT_WIDTH',\r\n description: 'Default width of the exported chart if not set',\r\n promptOptions: {\r\n type: 'number'\r\n }\r\n },\r\n defaultScale: {\r\n value: 1,\r\n types: ['number'],\r\n envLink: 'EXPORT_DEFAULT_SCALE',\r\n description:\r\n 'Default scale of the exported chart if not set. Ranges from 0.1 to 5.0',\r\n promptOptions: {\r\n type: 'number',\r\n min: 0.1,\r\n max: 5\r\n }\r\n },\r\n globalOptions: {\r\n value: null,\r\n types: ['Object', 'string', 'null'],\r\n envLink: 'EXPORT_GLOBAL_OPTIONS',\r\n description:\r\n 'JSON, stringified JSON or filename with global options for Highcharts.setOptions',\r\n promptOptions: {\r\n type: 'text'\r\n }\r\n },\r\n themeOptions: {\r\n value: null,\r\n types: ['Object', 'string', 'null'],\r\n envLink: 'EXPORT_THEME_OPTIONS',\r\n description:\r\n 'JSON, stringified JSON or filename with theme options for Highcharts.setOptions',\r\n promptOptions: {\r\n type: 'text'\r\n }\r\n },\r\n rasterizationTimeout: {\r\n value: 1500,\r\n types: ['number'],\r\n envLink: 'EXPORT_RASTERIZATION_TIMEOUT',\r\n description: 'Milliseconds to wait for webpage rendering',\r\n promptOptions: {\r\n type: 'number'\r\n }\r\n }\r\n },\r\n customLogic: {\r\n allowCodeExecution: {\r\n value: false,\r\n types: ['boolean'],\r\n envLink: 'CUSTOM_LOGIC_ALLOW_CODE_EXECUTION',\r\n description:\r\n 'Allows or disallows execution of arbitrary code during exporting',\r\n promptOptions: {\r\n type: 'toggle'\r\n }\r\n },\r\n allowFileResources: {\r\n value: false,\r\n types: ['boolean'],\r\n envLink: 'CUSTOM_LOGIC_ALLOW_FILE_RESOURCES',\r\n description:\r\n 'Allows or disallows injection of filesystem resources (disabled in server mode)',\r\n promptOptions: {\r\n type: 'toggle'\r\n }\r\n },\r\n customCode: {\r\n value: null,\r\n types: ['string', 'null'],\r\n envLink: 'CUSTOM_LOGIC_CUSTOM_CODE',\r\n description:\r\n 'Custom code to execute before chart initialization. Can be a function, code wrapped in a function, or a .js filename',\r\n promptOptions: {\r\n type: 'text'\r\n }\r\n },\r\n callback: {\r\n value: null,\r\n types: ['string', 'null'],\r\n envLink: 'CUSTOM_LOGIC_CALLBACK',\r\n description:\r\n 'JavaScript code to run during construction. Can be a function or a .js filename',\r\n promptOptions: {\r\n type: 'text'\r\n }\r\n },\r\n resources: {\r\n value: null,\r\n types: ['Object', 'string', 'null'],\r\n envLink: 'CUSTOM_LOGIC_RESOURCES',\r\n description:\r\n 'Additional resources as JSON, stringified JSON, or filename, containing files, js, and css sections',\r\n promptOptions: {\r\n type: 'text'\r\n }\r\n },\r\n loadConfig: {\r\n value: null,\r\n types: ['string', 'null'],\r\n envLink: 'CUSTOM_LOGIC_LOAD_CONFIG',\r\n legacyName: 'fromFile',\r\n description: 'File with a pre-defined configuration to use',\r\n promptOptions: {\r\n type: 'text'\r\n }\r\n },\r\n createConfig: {\r\n value: null,\r\n types: ['string', 'null'],\r\n envLink: 'CUSTOM_LOGIC_CREATE_CONFIG',\r\n description:\r\n 'Prompt-based option setting, saved to a provided config file',\r\n promptOptions: {\r\n type: 'text'\r\n }\r\n }\r\n },\r\n server: {\r\n enable: {\r\n value: false,\r\n types: ['boolean'],\r\n envLink: 'SERVER_ENABLE',\r\n cliName: 'enableServer',\r\n description: 'Starts the server when true',\r\n promptOptions: {\r\n type: 'toggle'\r\n }\r\n },\r\n host: {\r\n value: '0.0.0.0',\r\n types: ['string'],\r\n envLink: 'SERVER_HOST',\r\n description: 'Hostname of the server',\r\n promptOptions: {\r\n type: 'text'\r\n }\r\n },\r\n port: {\r\n value: 7801,\r\n types: ['number'],\r\n envLink: 'SERVER_PORT',\r\n description: 'Port number for the server',\r\n promptOptions: {\r\n type: 'number'\r\n }\r\n },\r\n uploadLimit: {\r\n value: 3,\r\n types: ['number'],\r\n envLink: 'SERVER_UPLOAD_LIMIT',\r\n description: 'Maximum request body size in MB',\r\n promptOptions: {\r\n type: 'number'\r\n }\r\n },\r\n benchmarking: {\r\n value: false,\r\n types: ['boolean'],\r\n envLink: 'SERVER_BENCHMARKING',\r\n cliName: 'serverBenchmarking',\r\n description:\r\n 'Displays or not action durations in milliseconds during server requests',\r\n promptOptions: {\r\n type: 'toggle'\r\n }\r\n },\r\n proxy: {\r\n host: {\r\n value: null,\r\n types: ['string', 'null'],\r\n envLink: 'SERVER_PROXY_HOST',\r\n cliName: 'proxyHost',\r\n description: 'Host of the proxy server, if applicable',\r\n promptOptions: {\r\n type: 'text'\r\n }\r\n },\r\n port: {\r\n value: null,\r\n types: ['number', 'null'],\r\n envLink: 'SERVER_PROXY_PORT',\r\n cliName: 'proxyPort',\r\n description: 'Port of the proxy server, if applicable',\r\n promptOptions: {\r\n type: 'number'\r\n }\r\n },\r\n timeout: {\r\n value: 5000,\r\n types: ['number'],\r\n envLink: 'SERVER_PROXY_TIMEOUT',\r\n cliName: 'proxyTimeout',\r\n description:\r\n 'Timeout in milliseconds for the proxy server, if applicable',\r\n promptOptions: {\r\n type: 'number'\r\n }\r\n }\r\n },\r\n rateLimiting: {\r\n enable: {\r\n value: false,\r\n types: ['boolean'],\r\n envLink: 'SERVER_RATE_LIMITING_ENABLE',\r\n cliName: 'enableRateLimiting',\r\n description: 'Enables or disables rate limiting on the server',\r\n promptOptions: {\r\n type: 'toggle'\r\n }\r\n },\r\n maxRequests: {\r\n value: 10,\r\n types: ['number'],\r\n envLink: 'SERVER_RATE_LIMITING_MAX_REQUESTS',\r\n legacyName: 'rateLimit',\r\n description: 'Maximum number of requests allowed per minute',\r\n promptOptions: {\r\n type: 'number'\r\n }\r\n },\r\n window: {\r\n value: 1,\r\n types: ['number'],\r\n envLink: 'SERVER_RATE_LIMITING_WINDOW',\r\n description: 'Time window in minutes for rate limiting',\r\n promptOptions: {\r\n type: 'number'\r\n }\r\n },\r\n delay: {\r\n value: 0,\r\n types: ['number'],\r\n envLink: 'SERVER_RATE_LIMITING_DELAY',\r\n description:\r\n 'Delay duration between successive requests before reaching the limit',\r\n promptOptions: {\r\n type: 'number'\r\n }\r\n },\r\n trustProxy: {\r\n value: false,\r\n types: ['boolean'],\r\n envLink: 'SERVER_RATE_LIMITING_TRUST_PROXY',\r\n description: 'Set to true if the server is behind a load balancer',\r\n promptOptions: {\r\n type: 'toggle'\r\n }\r\n },\r\n skipKey: {\r\n value: null,\r\n types: ['string', 'null'],\r\n envLink: 'SERVER_RATE_LIMITING_SKIP_KEY',\r\n description: 'Key to bypass the rate limiter, used with `skipToken`',\r\n promptOptions: {\r\n type: 'text'\r\n }\r\n },\r\n skipToken: {\r\n value: null,\r\n types: ['string', 'null'],\r\n envLink: 'SERVER_RATE_LIMITING_SKIP_TOKEN',\r\n description: 'Token to bypass the rate limiter, used with `skipKey`',\r\n promptOptions: {\r\n type: 'text'\r\n }\r\n }\r\n },\r\n ssl: {\r\n enable: {\r\n value: false,\r\n types: ['boolean'],\r\n envLink: 'SERVER_SSL_ENABLE',\r\n cliName: 'enableSsl',\r\n description: 'Enables or disables SSL protocol',\r\n promptOptions: {\r\n type: 'toggle'\r\n }\r\n },\r\n force: {\r\n value: false,\r\n types: ['boolean'],\r\n envLink: 'SERVER_SSL_FORCE',\r\n cliName: 'sslForce',\r\n legacyName: 'sslOnly',\r\n description: 'Forces the server to use HTTPS only when true',\r\n promptOptions: {\r\n type: 'toggle'\r\n }\r\n },\r\n port: {\r\n value: 443,\r\n types: ['number'],\r\n envLink: 'SERVER_SSL_PORT',\r\n cliName: 'sslPort',\r\n description: 'Port for the SSL server',\r\n promptOptions: {\r\n type: 'number'\r\n }\r\n },\r\n certPath: {\r\n value: null,\r\n types: ['string', 'null'],\r\n envLink: 'SERVER_SSL_CERT_PATH',\r\n cliName: 'sslCertPath',\r\n legacyName: 'sslPath',\r\n description: 'Path to the SSL certificate/key file',\r\n promptOptions: {\r\n type: 'text'\r\n }\r\n }\r\n }\r\n },\r\n pool: {\r\n minWorkers: {\r\n value: 4,\r\n types: ['number'],\r\n envLink: 'POOL_MIN_WORKERS',\r\n description: 'Minimum and initial number of pool workers to spawn',\r\n promptOptions: {\r\n type: 'number'\r\n }\r\n },\r\n maxWorkers: {\r\n value: 8,\r\n types: ['number'],\r\n envLink: 'POOL_MAX_WORKERS',\r\n legacyName: 'workers',\r\n description: 'Maximum number of pool workers to spawn',\r\n promptOptions: {\r\n type: 'number'\r\n }\r\n },\r\n workLimit: {\r\n value: 40,\r\n types: ['number'],\r\n envLink: 'POOL_WORK_LIMIT',\r\n description: 'Number of tasks a worker can handle before restarting',\r\n promptOptions: {\r\n type: 'number'\r\n }\r\n },\r\n acquireTimeout: {\r\n value: 5000,\r\n types: ['number'],\r\n envLink: 'POOL_ACQUIRE_TIMEOUT',\r\n description: 'Timeout in milliseconds for acquiring a resource',\r\n promptOptions: {\r\n type: 'number'\r\n }\r\n },\r\n createTimeout: {\r\n value: 5000,\r\n types: ['number'],\r\n envLink: 'POOL_CREATE_TIMEOUT',\r\n description: 'Timeout in milliseconds for creating a resource',\r\n promptOptions: {\r\n type: 'number'\r\n }\r\n },\r\n destroyTimeout: {\r\n value: 5000,\r\n types: ['number'],\r\n envLink: 'POOL_DESTROY_TIMEOUT',\r\n description: 'Timeout in milliseconds for destroying a resource',\r\n promptOptions: {\r\n type: 'number'\r\n }\r\n },\r\n idleTimeout: {\r\n value: 30000,\r\n types: ['number'],\r\n envLink: 'POOL_IDLE_TIMEOUT',\r\n description: 'Timeout in milliseconds for destroying idle resources',\r\n promptOptions: {\r\n type: 'number'\r\n }\r\n },\r\n createRetryInterval: {\r\n value: 200,\r\n types: ['number'],\r\n envLink: 'POOL_CREATE_RETRY_INTERVAL',\r\n description:\r\n 'Interval in milliseconds before retrying resource creation on failure',\r\n promptOptions: {\r\n type: 'number'\r\n }\r\n },\r\n reaperInterval: {\r\n value: 1000,\r\n types: ['number'],\r\n envLink: 'POOL_REAPER_INTERVAL',\r\n description:\r\n 'Interval in milliseconds to check and destroy idle resources',\r\n promptOptions: {\r\n type: 'number'\r\n }\r\n },\r\n benchmarking: {\r\n value: false,\r\n types: ['boolean'],\r\n envLink: 'POOL_BENCHMARKING',\r\n cliName: 'poolBenchmarking',\r\n description: 'Shows statistics for the pool of resources',\r\n promptOptions: {\r\n type: 'toggle'\r\n }\r\n }\r\n },\r\n logging: {\r\n level: {\r\n value: 4,\r\n types: ['number'],\r\n envLink: 'LOGGING_LEVEL',\r\n cliName: 'logLevel',\r\n description: 'Logging verbosity level',\r\n promptOptions: {\r\n type: 'number',\r\n round: 0,\r\n min: 0,\r\n max: 5\r\n }\r\n },\r\n file: {\r\n value: 'highcharts-export-server.log',\r\n types: ['string'],\r\n envLink: 'LOGGING_FILE',\r\n cliName: 'logFile',\r\n description:\r\n 'Log file name. Requires `logToFile` and `logDest` to be set',\r\n promptOptions: {\r\n type: 'text'\r\n }\r\n },\r\n dest: {\r\n value: 'log',\r\n types: ['string'],\r\n envLink: 'LOGGING_DEST',\r\n cliName: 'logDest',\r\n description: 'Path to store log files. Requires `logToFile` to be set',\r\n promptOptions: {\r\n type: 'text'\r\n }\r\n },\r\n toConsole: {\r\n value: true,\r\n types: ['boolean'],\r\n envLink: 'LOGGING_TO_CONSOLE',\r\n cliName: 'logToConsole',\r\n description: 'Enables or disables console logging',\r\n promptOptions: {\r\n type: 'toggle'\r\n }\r\n },\r\n toFile: {\r\n value: true,\r\n types: ['boolean'],\r\n envLink: 'LOGGING_TO_FILE',\r\n cliName: 'logToFile',\r\n description: 'Enables or disables logging to a file',\r\n promptOptions: {\r\n type: 'toggle'\r\n }\r\n }\r\n },\r\n ui: {\r\n enable: {\r\n value: false,\r\n types: ['boolean'],\r\n envLink: 'UI_ENABLE',\r\n cliName: 'enableUi',\r\n description: 'Enables or disables the UI for the export server',\r\n promptOptions: {\r\n type: 'toggle'\r\n }\r\n },\r\n route: {\r\n value: '/',\r\n types: ['string'],\r\n envLink: 'UI_ROUTE',\r\n cliName: 'uiRoute',\r\n description: 'The endpoint route for the UI',\r\n promptOptions: {\r\n type: 'text'\r\n }\r\n }\r\n },\r\n other: {\r\n nodeEnv: {\r\n value: 'production',\r\n types: ['string'],\r\n envLink: 'OTHER_NODE_ENV',\r\n description: 'The Node.js environment type',\r\n promptOptions: {\r\n type: 'text'\r\n }\r\n },\r\n listenToProcessExits: {\r\n value: true,\r\n types: ['boolean'],\r\n envLink: 'OTHER_LISTEN_TO_PROCESS_EXITS',\r\n description: 'Whether or not to attach process.exit handlers',\r\n promptOptions: {\r\n type: 'toggle'\r\n }\r\n },\r\n noLogo: {\r\n value: false,\r\n types: ['boolean'],\r\n envLink: 'OTHER_NO_LOGO',\r\n description: 'Display or skip printing the logo on startup',\r\n promptOptions: {\r\n type: 'toggle'\r\n }\r\n },\r\n hardResetPage: {\r\n value: false,\r\n types: ['boolean'],\r\n envLink: 'OTHER_HARD_RESET_PAGE',\r\n description: 'Whether or not to reset the page content entirely',\r\n promptOptions: {\r\n type: 'toggle'\r\n }\r\n },\r\n browserShellMode: {\r\n value: true,\r\n types: ['boolean'],\r\n envLink: 'OTHER_BROWSER_SHELL_MODE',\r\n description: 'Whether or not to set the browser to run in shell mode',\r\n promptOptions: {\r\n type: 'toggle'\r\n }\r\n },\r\n validation: {\r\n value: true,\r\n types: ['boolean'],\r\n envLink: 'OTHER_VALIDATION',\r\n description: 'Whether or not to enable validation of options types',\r\n promptOptions: {\r\n type: 'toggle'\r\n }\r\n }\r\n },\r\n debug: {\r\n enable: {\r\n value: false,\r\n types: ['boolean'],\r\n envLink: 'DEBUG_ENABLE',\r\n cliName: 'enableDebug',\r\n description: 'Enables or disables debug mode for the underlying browser',\r\n promptOptions: {\r\n type: 'toggle'\r\n }\r\n },\r\n headless: {\r\n value: false,\r\n types: ['boolean'],\r\n envLink: 'DEBUG_HEADLESS',\r\n description:\r\n 'Whether or not to set the browser to run in headless mode during debugging',\r\n promptOptions: {\r\n type: 'toggle'\r\n }\r\n },\r\n devtools: {\r\n value: false,\r\n types: ['boolean'],\r\n envLink: 'DEBUG_DEVTOOLS',\r\n description: 'Enables or disables DevTools in headful mode',\r\n promptOptions: {\r\n type: 'toggle'\r\n }\r\n },\r\n listenToConsole: {\r\n value: false,\r\n types: ['boolean'],\r\n envLink: 'DEBUG_LISTEN_TO_CONSOLE',\r\n description:\r\n 'Enables or disables listening to console messages from the browser',\r\n promptOptions: {\r\n type: 'toggle'\r\n }\r\n },\r\n dumpio: {\r\n value: false,\r\n types: ['boolean'],\r\n envLink: 'DEBUG_DUMPIO',\r\n description:\r\n 'Redirects or not browser stdout and stderr to process.stdout and process.stderr',\r\n promptOptions: {\r\n type: 'toggle'\r\n }\r\n },\r\n slowMo: {\r\n value: 0,\r\n types: ['number'],\r\n envLink: 'DEBUG_SLOW_MO',\r\n description: 'Delays Puppeteer operations by the specified milliseconds',\r\n promptOptions: {\r\n type: 'number'\r\n }\r\n },\r\n debuggingPort: {\r\n value: 9222,\r\n types: ['number'],\r\n envLink: 'DEBUG_DEBUGGING_PORT',\r\n description: 'Port used for debugging',\r\n promptOptions: {\r\n type: 'number'\r\n }\r\n }\r\n }\r\n};\r\n\r\nexport default defaultConfig;\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * @overview This file handles parsing and validating options from multiple\r\n * sources (the config file, custom JSON, environment variables, CLI arguments,\r\n * and request payload) using the 'zod' library.\r\n *\r\n * Environment variables are parsed and validated only once at application\r\n * startup, and the validated results are exported as `envs` for use throughout\r\n * the application.\r\n *\r\n * Options from other sources, however, are parsed and validated on demand,\r\n * each time an export is attempted.\r\n */\r\n\r\nimport dotenv from 'dotenv';\r\nimport { z } from 'zod';\r\n\r\nimport defaultConfig from './schemas/config.js';\r\n\r\n// Load the .env into environment variables\r\ndotenv.config();\r\n\r\n// Get scripts names of each category from the default config\r\nconst { coreScripts, moduleScripts, indicatorScripts } =\r\n defaultConfig.highcharts;\r\n\r\n// Sets the custom error map globally\r\nz.setErrorMap(_customErrorMap);\r\n\r\n/**\r\n * Object containing custom general validators and parsers to avoid repetition\r\n * in schema objects. All validators apply to values from various sources,\r\n * including the default config file, a custom JSON file loaded with the option\r\n * called `loadConfig`, the .env file, CLI arguments, and the request payload.\r\n * The `strictCheck` flag enables stricter validation and parsing rules. This\r\n * flag is set to false for values that come from the .env file or CLI arguments\r\n * because they are provided as strings and need to be parsed accordingly first.\r\n */\r\nconst v = {\r\n /**\r\n * The `boolean` validator that returns a Zod schema with an optional stricter\r\n * check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures that:\r\n *\r\n * - When `strictCheck` is true, the schema will accept values are true\r\n * and false and the schema will validate against the default boolean\r\n * validator.\r\n *\r\n * - When `strictCheck` is false, the schema will accept values are true,\r\n * false, null, 'true', '1', 'false', '0', 'undefined', 'null', and ''.\r\n * The strings 'undefined', 'null', and '' will be transformed to null,\r\n * the string 'true' will be transformed to the boolean value true,\r\n * and 'false' will be transformed to the boolean value false.\r\n *\r\n * @function boolean\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating boolean values.\r\n */\r\n boolean(strictCheck) {\r\n return strictCheck\r\n ? z.boolean()\r\n : z\r\n .union([\r\n z\r\n .enum(['true', '1', 'false', '0', 'undefined', 'null', ''])\r\n .transform((value) =>\r\n !['undefined', 'null', ''].includes(value)\r\n ? value === 'true' || value === '1'\r\n : null\r\n ),\r\n z.boolean()\r\n ])\r\n .nullable();\r\n },\r\n\r\n /**\r\n * The `string` validator that returns a Zod schema with an optional stricter\r\n * check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures that:\r\n *\r\n * - When `strictCheck` is true, the schema will accept trimmed strings except\r\n * the forbidden values: 'false', 'undefined', 'null', and ''.\r\n *\r\n * - When `strictCheck` is false, the schema will accept trimmed strings\r\n * and null. The forbidden values: 'false', 'undefined', 'null', and '' will\r\n * be transformed to null.\r\n *\r\n * @function string\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating string values.\r\n */\r\n string(strictCheck) {\r\n return strictCheck\r\n ? z\r\n .string()\r\n .trim()\r\n .refine(\r\n (value) => !['false', 'undefined', 'null', ''].includes(value),\r\n {\r\n params: {\r\n errorMessage: 'The string contains a forbidden value'\r\n }\r\n }\r\n )\r\n : z\r\n .string()\r\n .trim()\r\n .transform((value) =>\r\n !['false', 'undefined', 'null', ''].includes(value) ? value : null\r\n )\r\n .nullable();\r\n },\r\n\r\n /**\r\n * The `enum` validator that returns a Zod schema with an optional stricter\r\n * check based on the `strictCheck` parameter.\r\n *\r\n * The schema will validate against the provided `values` array.\r\n *\r\n * The validation schema ensures that:\r\n *\r\n * - When `strictCheck` is true, the schema will validate against the `values`\r\n * array with the default enum validator.\r\n *\r\n * - When `strictCheck` is false, the schema will accept also null,\r\n * 'undefined', 'null', and '', which will be transformed to null.\r\n *\r\n * @function enum\r\n *\r\n * @param {Array.} values - An array of valid string values\r\n * for the enum.\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating enum values.\r\n */\r\n enum(values, strictCheck) {\r\n return strictCheck\r\n ? z.enum([...values])\r\n : z\r\n .enum([...values, 'undefined', 'null', ''])\r\n .transform((value) =>\r\n !['undefined', 'null', ''].includes(value) ? value : null\r\n )\r\n .nullable();\r\n },\r\n\r\n /**\r\n * The `stringArray` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures that:\r\n *\r\n * - When `strictCheck` is true, the schema will accept an array of trimmed\r\n * string values filtered by the logic provided through the `filterCallback`.\r\n *\r\n * - When `strictCheck` is false, the schema will accept null and trimmed\r\n * string values which will be splitted into an array of strings and filtered\r\n * from the '[' and ']' characters and by the logic provided through\r\n * the `filterCallback`. If the array is empty, it will be transformed\r\n * to null.\r\n *\r\n * @function stringArray\r\n *\r\n * @param {function} filterCallback - The filter callback.\r\n * @param {string} separator - The separator for spliting a string.\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating array of string\r\n * values.\r\n */\r\n stringArray(filterCallback, separator, strictCheck) {\r\n const arraySchema = z.string().trim().array();\r\n const stringSchema = z\r\n .string()\r\n .trim()\r\n .transform((value) => {\r\n if (value.startsWith('[')) {\r\n value = value.slice(1);\r\n }\r\n if (value.endsWith(']')) {\r\n value = value.slice(0, -1);\r\n }\r\n return value.split(separator);\r\n });\r\n\r\n const transformCallback = (value) =>\r\n value.map((value) => value.trim()).filter(filterCallback);\r\n\r\n return strictCheck\r\n ? arraySchema.transform(transformCallback)\r\n : z\r\n .union([stringSchema, arraySchema])\r\n .transform(transformCallback)\r\n .transform((value) => (value.length ? value : null))\r\n .nullable();\r\n },\r\n\r\n /**\r\n * The `positiveNum` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures that:\r\n *\r\n * - When `strictCheck` is true, the schema will accept positive number values\r\n * and validate against the default positive number validator.\r\n *\r\n * - When `strictCheck` is false, the schema will accept positive number\r\n * values, null, and trimmed string values that can either be 'undefined',\r\n * 'null', '', or represent a positive number. It will transform the string\r\n * to a positive number, or to null if it is 'undefined', 'null', or ''.\r\n *\r\n * @function positiveNum\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating positive number\r\n * values.\r\n */\r\n positiveNum(strictCheck) {\r\n return strictCheck\r\n ? z.number().positive()\r\n : z\r\n .union([\r\n z\r\n .string()\r\n .trim()\r\n .refine(\r\n (value) =>\r\n (!isNaN(Number(value)) && Number(value) > 0) ||\r\n ['undefined', 'null', ''].includes(value),\r\n {\r\n params: {\r\n errorMessage: 'The value must be numeric and positive'\r\n }\r\n }\r\n )\r\n .transform((value) =>\r\n !['undefined', 'null', ''].includes(value)\r\n ? Number(value)\r\n : null\r\n ),\r\n z.number().positive()\r\n ])\r\n .nullable();\r\n },\r\n\r\n /**\r\n * The `nonNegativeNum` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures that:\r\n *\r\n * - When `strictCheck` is true, the schema will accept non-negative number\r\n * values and validate against the default non-negative number validator.\r\n *\r\n * - When `strictCheck` is false, the schema will accept non-negative number\r\n * values, null, and trimmed string values that can either be 'undefined',\r\n * 'null', '', or represent a non-negative number. It will transform\r\n * the string to a non-negative number, or to null if it is 'undefined',\r\n * 'null', or ''.\r\n *\r\n * @function nonNegativeNum\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating non-negative\r\n * number values.\r\n */\r\n nonNegativeNum(strictCheck) {\r\n return strictCheck\r\n ? z.number().nonnegative()\r\n : z\r\n .union([\r\n z\r\n .string()\r\n .trim()\r\n .refine(\r\n (value) =>\r\n (!isNaN(Number(value)) && Number(value) >= 0) ||\r\n ['undefined', 'null', ''].includes(value),\r\n {\r\n params: {\r\n errorMessage: 'The value must be numeric and non-negative'\r\n }\r\n }\r\n )\r\n .transform((value) =>\r\n !['undefined', 'null', ''].includes(value)\r\n ? Number(value)\r\n : null\r\n ),\r\n z.number().nonnegative()\r\n ])\r\n .nullable();\r\n },\r\n\r\n /**\r\n * The `startsWith` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The schema will validate against the provided `prefixes` array to check\r\n * whether a string value starts with any of the values provided\r\n * in the `prefixes` array.\r\n *\r\n * The validation schema ensures that:\r\n *\r\n * - When `strictCheck` is true, the schema will accept trimmed string values\r\n * that start with values from the prefixes array.\r\n *\r\n * - When `strictCheck` is false, the schema will accept trimmed string values\r\n * that start with values from the prefixes array, null, 'undefined', 'null',\r\n * and '' where the schema will transform them to null.\r\n *\r\n * @function startsWith\r\n *\r\n * @param {Array.} prefixes - An array of prefixes to validate\r\n * the string against.\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating strings that\r\n * starts with values.\r\n */\r\n startsWith(prefixes, strictCheck) {\r\n return strictCheck\r\n ? z\r\n .string()\r\n .trim()\r\n .refine(\r\n (value) => prefixes.some((prefix) => value.startsWith(prefix)),\r\n {\r\n params: {\r\n errorMessage: `The value must be a string that starts with ${prefixes.join(', ')}`\r\n }\r\n }\r\n )\r\n : z\r\n .string()\r\n .trim()\r\n .refine(\r\n (value) =>\r\n prefixes.some((prefix) => value.startsWith(prefix)) ||\r\n ['undefined', 'null', ''].includes(value),\r\n {\r\n params: {\r\n errorMessage: `The value must be a string that starts with ${prefixes.join(', ')}`\r\n }\r\n }\r\n )\r\n .transform((value) =>\r\n !['undefined', 'null', ''].includes(value) ? value : null\r\n )\r\n .nullable();\r\n },\r\n\r\n /**\r\n * The `chartConfig` validator that returns a Zod schema.\r\n *\r\n * The validation schema ensures that the schema will accept object values\r\n * or trimmed string values that contain '\r\n (value.startsWith('{') && value.endsWith('}')) ||\r\n ['undefined', 'null', ''].includes(value),\r\n {\r\n params: {\r\n errorMessage:\r\n \"The value must be a string that starts with '{' and ends with '}'\"\r\n }\r\n }\r\n )\r\n .transform((value) =>\r\n !['undefined', 'null', ''].includes(value) ? value : null\r\n ),\r\n z.object({}).passthrough()\r\n ])\r\n .nullable();\r\n },\r\n\r\n /**\r\n * The `additionalOptions` validator that returns a Zod schema.\r\n *\r\n * The validation schema ensures that the schema will accept object values\r\n * or trimmed string values that end with '.json' and are at least one\r\n * character long excluding the extension, start with the '{' and end\r\n * with the '}', and null. The 'undefined', 'null', and '' values will\r\n * be transformed to null.\r\n *\r\n * @function additionalOptions\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating additional chart\r\n * options value.\r\n */\r\n additionalOptions() {\r\n return z\r\n .union([\r\n z\r\n .string()\r\n .trim()\r\n .refine(\r\n (value) =>\r\n (value.length >= 6 && value.endsWith('.json')) ||\r\n (value.startsWith('{') && value.endsWith('}')) ||\r\n ['undefined', 'null', ''].includes(value),\r\n {\r\n params: {\r\n errorMessage:\r\n \"The value must be a string that ends with '.json' or starts with '{' and ends with '}'\"\r\n }\r\n }\r\n )\r\n .transform((value) =>\r\n !['undefined', 'null', ''].includes(value) ? value : null\r\n ),\r\n z.object({}).passthrough()\r\n ])\r\n .nullable();\r\n }\r\n};\r\n\r\n/**\r\n * Object containing custom config validators and parsers to avoid repetition\r\n * in schema objects. All validators apply to values from various sources,\r\n * including the default config file, a custom JSON file loaded with the option\r\n * called `loadConfig`, the .env file, CLI arguments, and the request payload.\r\n * The `strictCheck` flag enables stricter validation and parsing rules. This\r\n * flag is set to false for values that come from the .env file or CLI arguments\r\n * because they are provided as strings and need to be parsed accordingly first.\r\n */\r\nexport const validators = {\r\n /**\r\n * The `args` validator that returns a Zod schema with an optional stricter\r\n * check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `stringArray` validator.\r\n *\r\n * @function args\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `args`\r\n * option.\r\n */\r\n args(strictCheck) {\r\n return v.stringArray(\r\n (value) => !['false', 'undefined', 'null', ''].includes(value),\r\n ';',\r\n strictCheck\r\n );\r\n },\r\n\r\n /**\r\n * The `version` validator that returns a Zod schema with an optional stricter\r\n * check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures that:\r\n *\r\n * - When `strictCheck` is true, the schema will accept trimmed string values\r\n * that are a RegExp-based that allows to be 'latest', or in the format XX,\r\n * XX.YY, or XX.YY.ZZ, where XX, YY, and ZZ are numeric for the Highcharts\r\n * version option.\r\n *\r\n * - When `strictCheck` is false, the schema will accept also null,\r\n * 'undefined', 'null', or '' and in all cases the schema will transform them\r\n * to null.\r\n *\r\n * @function version\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `version`\r\n * option.\r\n */\r\n version(strictCheck) {\r\n return strictCheck\r\n ? z\r\n .string()\r\n .trim()\r\n .refine((value) => /^(latest|\\d{1,2}(\\.\\d{1,2}){0,2})$/.test(value), {\r\n params: {\r\n errorMessage:\r\n \"The value must be 'latest', a major version, or in the form XX.YY.ZZ\"\r\n }\r\n })\r\n : z\r\n .string()\r\n .trim()\r\n .refine(\r\n (value) =>\r\n /^(latest|\\d{1,2}(\\.\\d{1,2}){0,2})$/.test(value) ||\r\n ['undefined', 'null', ''].includes(value),\r\n {\r\n params: {\r\n errorMessage:\r\n \"The value must be 'latest', a major version, or in the form XX.YY.ZZ\"\r\n }\r\n }\r\n )\r\n .transform((value) =>\r\n !['undefined', 'null', ''].includes(value) ? value : null\r\n )\r\n .nullable();\r\n },\r\n\r\n /**\r\n * The `cdnUrl` validator that returns a Zod schema with an optional stricter\r\n * check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `startsWith` validator.\r\n *\r\n * @function cdnUrl\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `cdnUrl`\r\n * option.\r\n */\r\n cdnUrl(strictCheck) {\r\n return v.startsWith(['http://', 'https://'], strictCheck);\r\n },\r\n\r\n /**\r\n * The `forceFetch` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `boolean` validator.\r\n *\r\n * @function forceFetch\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `forceFetch`\r\n * option.\r\n */\r\n forceFetch(strictCheck) {\r\n return v.boolean(strictCheck);\r\n },\r\n\r\n /**\r\n * The `cachePath` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `string` validator.\r\n *\r\n * @function cachePath\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `cachePath`\r\n * option.\r\n */\r\n cachePath(strictCheck) {\r\n return v.string(strictCheck);\r\n },\r\n\r\n /**\r\n * The `adminToken` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `string` validator.\r\n *\r\n * @function adminToken\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `adminToken`\r\n * option.\r\n */\r\n adminToken(strictCheck) {\r\n return v.string(strictCheck);\r\n },\r\n\r\n /**\r\n * The `coreScripts` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `stringArray` validator.\r\n *\r\n * @function coreScripts\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `coreScripts`\r\n * option.\r\n */\r\n coreScripts(strictCheck) {\r\n return v.stringArray(\r\n (value) => coreScripts.value.includes(value),\r\n ',',\r\n strictCheck\r\n );\r\n },\r\n\r\n /**\r\n * The `moduleScripts` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `stringArray` validator.\r\n *\r\n * @function moduleScripts\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating\r\n * the `moduleScripts` option.\r\n */\r\n moduleScripts(strictCheck) {\r\n return v.stringArray(\r\n (value) => moduleScripts.value.includes(value),\r\n ',',\r\n strictCheck\r\n );\r\n },\r\n\r\n /**\r\n * The `indicatorScripts` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `stringArray` validator.\r\n *\r\n * @function indicatorScripts\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating\r\n * the `indicatorScripts` option.\r\n */\r\n indicatorScripts(strictCheck) {\r\n return v.stringArray(\r\n (value) => indicatorScripts.value.includes(value),\r\n ',',\r\n strictCheck\r\n );\r\n },\r\n\r\n /**\r\n * The `customScripts` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `stringArray` validator.\r\n *\r\n * @function customScripts\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating\r\n * the `customScripts` option.\r\n */\r\n customScripts(strictCheck) {\r\n return v.stringArray(\r\n (value) => value.startsWith('https://') || value.startsWith('http://'),\r\n ',',\r\n strictCheck\r\n );\r\n },\r\n\r\n /**\r\n * The `infile` validator that returns a Zod schema with an optional stricter\r\n * check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures that:\r\n *\r\n * - When `strictCheck` is true, the schema will accept trimmed string values\r\n * that end with '.json' or '.svg', are at least one character long excluding\r\n * the extension, or null.\r\n *\r\n * - When `strictCheck` is false, the schema will accept trimmed string values\r\n * that end with '.json' or '.svg', are at least one character long excluding\r\n * the extension and will be null if the provided value is null, 'undefined',\r\n * 'null', or ''.\r\n *\r\n * @function infile\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `infile`\r\n * option.\r\n */\r\n infile(strictCheck) {\r\n return strictCheck\r\n ? z\r\n .string()\r\n .trim()\r\n .refine(\r\n (value) =>\r\n (value.length >= 6 && value.endsWith('.json')) ||\r\n (value.length >= 5 && value.endsWith('.svg')),\r\n {\r\n params: {\r\n errorMessage:\r\n 'The value must be a string that ends with .json or .svg'\r\n }\r\n }\r\n )\r\n .nullable()\r\n : z\r\n .string()\r\n .trim()\r\n .refine(\r\n (value) =>\r\n (value.length >= 6 && value.endsWith('.json')) ||\r\n (value.length >= 5 && value.endsWith('.svg')) ||\r\n ['undefined', 'null', ''].includes(value),\r\n {\r\n params: {\r\n errorMessage:\r\n 'The value must be a string that ends with .json or .svg'\r\n }\r\n }\r\n )\r\n .transform((value) =>\r\n !['undefined', 'null', ''].includes(value) ? value : null\r\n )\r\n .nullable();\r\n },\r\n\r\n /**\r\n * The `instr` validator that returns a Zod schema.\r\n *\r\n * The validation schema ensures the same work as the `options` validator.\r\n *\r\n * @function instr\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `instr`\r\n * option.\r\n */\r\n instr() {\r\n return v.chartConfig();\r\n },\r\n\r\n /**\r\n * The `options` validator that returns a Zod schema.\r\n *\r\n * The validation schema ensures the same work as the `options` validator.\r\n *\r\n * @function options\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `options`\r\n * option.\r\n */\r\n options() {\r\n return v.chartConfig();\r\n },\r\n\r\n /**\r\n * The `svg` validator that returns a Zod schema.\r\n *\r\n * The validation schema ensures that the schema will accept object values\r\n * or trimmed string values that contain '\r\n value.indexOf('= 0 ||\r\n value.indexOf('= 0 ||\r\n ['false', 'undefined', 'null', ''].includes(value),\r\n {\r\n params: {\r\n errorMessage:\r\n \"The value must be a string that contains '\r\n !['false', 'undefined', 'null', ''].includes(value) ? value : null\r\n )\r\n .nullable();\r\n },\r\n\r\n /**\r\n * The `outfile` validator that returns a Zod schema with an optional stricter\r\n * check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures that:\r\n *\r\n * - When `strictCheck` is true, the schema will accept trimmed string values\r\n * that end with '.jpeg', '.jpg', '.png', '.pdf', or '.svg', are at least one\r\n * character long excluding the extension, or null.\r\n *\r\n * - When `strictCheck` is false, the schema will accept trimmed string values\r\n * that end with '.jpeg', '.jpg', '.png', '.pdf', or '.svg', are at least one\r\n * character long excluding the extension and will be null if the provided\r\n * value is null, 'undefined', 'null', or ''.\r\n *\r\n * @function outfile\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `outfile`\r\n * option.\r\n */\r\n outfile(strictCheck) {\r\n return strictCheck\r\n ? z\r\n .string()\r\n .trim()\r\n .refine(\r\n (value) =>\r\n (value.length >= 6 && value.endsWith('.jpeg')) ||\r\n (value.length >= 5 &&\r\n (value.endsWith('.jpg') ||\r\n value.endsWith('.png') ||\r\n value.endsWith('.pdf') ||\r\n value.endsWith('.svg'))),\r\n {\r\n params: {\r\n errorMessage:\r\n 'The value must be a string that ends with .jpeg, .jpg, .png, .pdf, or .svg'\r\n }\r\n }\r\n )\r\n .nullable()\r\n : z\r\n .string()\r\n .trim()\r\n .refine(\r\n (value) =>\r\n (value.length >= 6 && value.endsWith('.jpeg')) ||\r\n (value.length >= 5 &&\r\n (value.endsWith('.jpg') ||\r\n value.endsWith('.png') ||\r\n value.endsWith('.pdf') ||\r\n value.endsWith('.svg'))) ||\r\n ['undefined', 'null', ''].includes(value),\r\n {\r\n params: {\r\n errorMessage:\r\n 'The value must be a string that ends with .jpeg, .jpg, .png, .pdf, or .svg'\r\n }\r\n }\r\n )\r\n .transform((value) =>\r\n !['undefined', 'null', ''].includes(value) ? value : null\r\n )\r\n .nullable();\r\n },\r\n\r\n /**\r\n * The `type` validator that returns a Zod schema with an optional stricter\r\n * check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `enum` validator.\r\n *\r\n * @function type\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `type`\r\n * option.\r\n */\r\n type(strictCheck) {\r\n return v.enum(['jpeg', 'jpg', 'png', 'pdf', 'svg'], strictCheck);\r\n },\r\n\r\n /**\r\n * The `constr` validator that returns a Zod schema with an optional stricter\r\n * check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `enum` validator.\r\n *\r\n * @function constr\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `constr`\r\n * option.\r\n */\r\n constr(strictCheck) {\r\n return v.enum(\r\n ['chart', 'stockChart', 'mapChart', 'ganttChart'],\r\n strictCheck\r\n );\r\n },\r\n\r\n /**\r\n * The `b64` validator that returns a Zod schema with an optional stricter\r\n * check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `boolean` validator.\r\n *\r\n * @function b64\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `b64` option.\r\n */\r\n b64(strictCheck) {\r\n return v.boolean(strictCheck);\r\n },\r\n\r\n /**\r\n * The `noDownload` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `boolean` validator.\r\n *\r\n * @function noDownload\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `noDownload`\r\n * option.\r\n */\r\n noDownload(strictCheck) {\r\n return v.boolean(strictCheck);\r\n },\r\n\r\n /**\r\n * The `defaultHeight` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `positiveNum` validator.\r\n *\r\n * @function defaultHeight\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating\r\n * the `defaultHeight` option.\r\n */\r\n defaultHeight(strictCheck) {\r\n return v.positiveNum(strictCheck);\r\n },\r\n\r\n /**\r\n * The `defaultWidth` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `positiveNum` validator.\r\n *\r\n * @function defaultWidth\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating\r\n * the `defaultWidth` option.\r\n */\r\n defaultWidth(strictCheck) {\r\n return v.positiveNum(strictCheck);\r\n },\r\n\r\n /**\r\n * The `defaultScale` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures that:\r\n *\r\n * - When `strictCheck` is true, the schema will accept number values that\r\n * are between 0.1 and 5 (inclusive).\r\n *\r\n * - When `strictCheck` is false, the schema will accept number values\r\n * and stringified number values that are between 0.1 and 5 (inclusive), null,\r\n * 'undefined', 'null', and '' which will be transformed to null.\r\n *\r\n * @function defaultScale\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating\r\n * the `defaultScale` option.\r\n */\r\n defaultScale(strictCheck) {\r\n return strictCheck\r\n ? z.number().gte(0.1).lte(5)\r\n : z\r\n .union([\r\n z\r\n .string()\r\n .trim()\r\n .refine(\r\n (value) =>\r\n (!isNaN(Number(value)) &&\r\n value !== true &&\r\n !value.startsWith('[') &&\r\n Number(value) >= 0.1 &&\r\n Number(value) <= 5) ||\r\n ['undefined', 'null', ''].includes(value),\r\n {\r\n params: {\r\n errorMessage: 'The value must be within a 0.1 and 5.0 range'\r\n }\r\n }\r\n )\r\n .transform((value) =>\r\n !['undefined', 'null', ''].includes(value)\r\n ? Number(value)\r\n : null\r\n ),\r\n z.number().gte(0.1).lte(5)\r\n ])\r\n .nullable();\r\n },\r\n\r\n /**\r\n * The `height` validator that returns a Zod schema with an optional stricter\r\n * check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as a nullable `defaultHeight`\r\n * validator.\r\n *\r\n * @function height\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `height`\r\n * option.\r\n */\r\n height(strictCheck) {\r\n return this.defaultHeight(strictCheck).nullable();\r\n },\r\n\r\n /**\r\n * The `width` validator that returns a Zod schema with an optional stricter\r\n * check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as a nullable `defaultWidth`\r\n * validator.\r\n *\r\n * @function width\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `width`\r\n * option.\r\n */\r\n width(strictCheck) {\r\n return this.defaultWidth(strictCheck).nullable();\r\n },\r\n\r\n /**\r\n * The `scale` validator that returns a Zod schema with an optional stricter\r\n * check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as a nullable `defaultScale`\r\n * validator.\r\n *\r\n * @function scale\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `scale`\r\n * option.\r\n */\r\n scale(strictCheck) {\r\n return this.defaultScale(strictCheck).nullable();\r\n },\r\n\r\n /**\r\n * The `globalOptions` validator that returns a Zod schema.\r\n *\r\n * The validation schema ensures the same work as the `additionalOptions`\r\n * validator.\r\n *\r\n * @function globalOptions\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating\r\n * the `globalOptions` option.\r\n */\r\n globalOptions() {\r\n return v.additionalOptions();\r\n },\r\n\r\n /**\r\n * The `themeOptions` validator that returns a Zod schema.\r\n *\r\n * The validation schema ensures the same work as the `additionalOptions`\r\n * validator.\r\n *\r\n * @function themeOptions\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating\r\n * the `themeOptions` option.\r\n */\r\n themeOptions() {\r\n return v.additionalOptions();\r\n },\r\n\r\n /**\r\n * The `batch` validator that returns a Zod schema with an optional stricter\r\n * check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `string` validator.\r\n *\r\n * @function batch\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `batch`\r\n * option.\r\n */\r\n batch(strictCheck) {\r\n return v.string(strictCheck);\r\n },\r\n\r\n /**\r\n * The `rasterizationTimeout` validator that returns a Zod schema with\r\n * an optional stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `nonNegativeNum`\r\n * validator.\r\n *\r\n * @function rasterizationTimeout\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating\r\n * the `rasterizationTimeout` option.\r\n */\r\n rasterizationTimeout(strictCheck) {\r\n return v.nonNegativeNum(strictCheck);\r\n },\r\n\r\n /**\r\n * The `allowCodeExecution` validator that returns a Zod schema with\r\n * an optional stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `boolean` validator.\r\n *\r\n * @function allowCodeExecution\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating\r\n * the `allowCodeExecution` option.\r\n */\r\n allowCodeExecution(strictCheck) {\r\n return v.boolean(strictCheck);\r\n },\r\n\r\n /**\r\n * The `allowFileResources` validator that returns a Zod schema with\r\n * an optional stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `boolean` validator.\r\n *\r\n * @function allowFileResources\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating\r\n * the `allowFileResources` option.\r\n */\r\n allowFileResources(strictCheck) {\r\n return v.boolean(strictCheck);\r\n },\r\n\r\n /**\r\n * The `customCode` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `string` validator.\r\n *\r\n * @function customCode\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `customCode`\r\n * option.\r\n */\r\n customCode(strictCheck) {\r\n return v.string(strictCheck);\r\n },\r\n\r\n /**\r\n * The `callback` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `string` validator.\r\n *\r\n * @function callback\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `callback`\r\n * option.\r\n */\r\n callback(strictCheck) {\r\n return v.string(strictCheck);\r\n },\r\n\r\n /**\r\n * The `resources` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures that:\r\n *\r\n * - When `strictCheck` is true, the schema will accept a partial object\r\n * with allowed properties `js`, `css`, and `files` where each of the allowed\r\n * properties can be null, stringified version of the object, string that ends\r\n * with the '.json', and null.\r\n *\r\n * - When `strictCheck` is false, the schema will accept a stringified version\r\n * of a partial object with allowed properties `js`, `css`, and `files` where\r\n * each of the allowed properties can be null, string that ends with the\r\n * '.json', and will be null if the provided value is 'undefined', 'null'\r\n * or ''.\r\n *\r\n * @function resources\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `resources`\r\n * option.\r\n */\r\n resources(strictCheck) {\r\n const objectSchema = z\r\n .object({\r\n js: v.string(false),\r\n css: v.string(false),\r\n files: v\r\n .stringArray(\r\n (value) => !['undefined', 'null', ''].includes(value),\r\n ',',\r\n true\r\n )\r\n .nullable()\r\n })\r\n .partial();\r\n\r\n const stringSchema1 = z\r\n .string()\r\n .trim()\r\n .refine(\r\n (value) =>\r\n (value.startsWith('{') && value.endsWith('}')) ||\r\n (value.length >= 6 && value.endsWith('.json')),\r\n {\r\n params: {\r\n errorMessage:\r\n \"The value must be a string that starts with '{' and ends with '}\"\r\n }\r\n }\r\n );\r\n\r\n const stringSchema2 = z\r\n .string()\r\n .trim()\r\n .refine(\r\n (value) =>\r\n (value.startsWith('{') && value.endsWith('}')) ||\r\n (value.length >= 6 && value.endsWith('.json')) ||\r\n ['undefined', 'null', ''].includes(value),\r\n {\r\n params: {\r\n errorMessage: 'The value must be a string that ends with .json'\r\n }\r\n }\r\n )\r\n .transform((value) =>\r\n !['undefined', 'null', ''].includes(value) ? value : null\r\n );\r\n\r\n return strictCheck\r\n ? z.union([objectSchema, stringSchema1]).nullable()\r\n : z.union([objectSchema, stringSchema2]).nullable();\r\n },\r\n\r\n /**\r\n * The `loadConfig` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `string` validator.\r\n * Additionally, it must be a string that ends with '.json'.\r\n *\r\n * @function loadConfig\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `loadConfig`\r\n * option.\r\n */\r\n loadConfig(strictCheck) {\r\n return v\r\n .string(strictCheck)\r\n .refine(\r\n (value) =>\r\n value === null || (value.length >= 6 && value.endsWith('.json')),\r\n {\r\n params: {\r\n errorMessage: 'The value must be a string that ends with .json'\r\n }\r\n }\r\n );\r\n },\r\n\r\n /**\r\n * The `createConfig` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `loadConfig` validator.\r\n *\r\n * @function createConfig\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating\r\n * the `createConfig` option.\r\n */\r\n createConfig(strictCheck) {\r\n return this.loadConfig(strictCheck);\r\n },\r\n\r\n /**\r\n * The `enableServer` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `boolean` validator.\r\n *\r\n * @function enableServer\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating\r\n * the `enableServer` option.\r\n */\r\n enableServer(strictCheck) {\r\n return v.boolean(strictCheck);\r\n },\r\n\r\n /**\r\n * The `host` validator that returns a Zod schema with an optional stricter\r\n * check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `string` validator.\r\n *\r\n * @function host\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `host`\r\n * option.\r\n */\r\n host(strictCheck) {\r\n return v.string(strictCheck);\r\n },\r\n\r\n /**\r\n * The `port` validator that returns a Zod schema with an optional stricter\r\n * check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `nonNegativeNum`\r\n * validator.\r\n *\r\n * @function port\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `port`\r\n * option.\r\n */\r\n port(strictCheck) {\r\n return v.nonNegativeNum(strictCheck);\r\n },\r\n\r\n /**\r\n * The `uploadLimit` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `positiveNum` validator.\r\n *\r\n * @function uploadLimit\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `uploadLimit`\r\n * option.\r\n */\r\n uploadLimit(strictCheck) {\r\n return v.positiveNum(strictCheck);\r\n },\r\n\r\n /**\r\n * The `serverBenchmarking` validator that returns a Zod schema with\r\n * an optional stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `boolean` validator.\r\n *\r\n * @function serverBenchmarking\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating\r\n * the `serverBenchmarking` option.\r\n */\r\n serverBenchmarking(strictCheck) {\r\n return v.boolean(strictCheck);\r\n },\r\n\r\n /**\r\n * The `proxyHost` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `string` validator.\r\n *\r\n * @function proxyHost\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `proxyHost`\r\n * option.\r\n */\r\n proxyHost(strictCheck) {\r\n return v.string(strictCheck);\r\n },\r\n\r\n /**\r\n * The `proxyPort` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as a nullable `nonNegativeNum`\r\n * validator.\r\n *\r\n * @function proxyPort\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `proxyPort`\r\n * option.\r\n */\r\n proxyPort(strictCheck) {\r\n return v.nonNegativeNum(strictCheck).nullable();\r\n },\r\n\r\n /**\r\n * The `proxyTimeout` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `nonNegativeNum`\r\n * validator.\r\n *\r\n * @function proxyTimeout\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating\r\n * the `proxyTimeout` option.\r\n */\r\n proxyTimeout(strictCheck) {\r\n return v.nonNegativeNum(strictCheck);\r\n },\r\n\r\n /**\r\n * The `enableRateLimiting` validator that returns a Zod schema with\r\n * an optional stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `boolean` validator.\r\n *\r\n * @function enableRateLimiting\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating\r\n * the `enableRateLimiting` option.\r\n */\r\n enableRateLimiting(strictCheck) {\r\n return v.boolean(strictCheck);\r\n },\r\n\r\n /**\r\n * The `maxRequests` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `nonNegativeNum`\r\n * validator.\r\n *\r\n * @function maxRequests\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `maxRequests`\r\n * option.\r\n */\r\n maxRequests(strictCheck) {\r\n return v.nonNegativeNum(strictCheck);\r\n },\r\n\r\n /**\r\n * The `window` validator that returns a Zod schema with an optional stricter\r\n * check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `nonNegativeNum`\r\n * validator.\r\n *\r\n * @function window\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `window`\r\n * option.\r\n */\r\n window(strictCheck) {\r\n return v.nonNegativeNum(strictCheck);\r\n },\r\n\r\n /**\r\n * The `delay` validator that returns a Zod schema with an optional stricter\r\n * check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `nonNegativeNum`\r\n * validator.\r\n *\r\n * @function delay\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `delay`\r\n * option.\r\n */\r\n delay(strictCheck) {\r\n return v.nonNegativeNum(strictCheck);\r\n },\r\n\r\n /**\r\n * The `trustProxy` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `boolean` validator.\r\n *\r\n * @function trustProxy\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `trustProxy`\r\n * option.\r\n */\r\n trustProxy(strictCheck) {\r\n return v.boolean(strictCheck);\r\n },\r\n\r\n /**\r\n * The `skipKey` validator that returns a Zod schema with an optional stricter\r\n * check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `string` validator.\r\n *\r\n * @function skipKey\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `skipKey`\r\n * option.\r\n */\r\n skipKey(strictCheck) {\r\n return v.string(strictCheck);\r\n },\r\n\r\n /**\r\n * The `skipToken` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `string` validator.\r\n *\r\n * @function skipToken\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `skipToken`\r\n * option.\r\n */\r\n skipToken(strictCheck) {\r\n return v.string(strictCheck);\r\n },\r\n\r\n /**\r\n * The `enableSsl` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `boolean` validator.\r\n *\r\n * @function enableSsl\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `enableSsl`\r\n * option.\r\n */\r\n enableSsl(strictCheck) {\r\n return v.boolean(strictCheck);\r\n },\r\n\r\n /**\r\n * The `sslForce` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `boolean` validator.\r\n *\r\n * @function sslForce\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `sslForce`\r\n * option.\r\n */\r\n sslForce(strictCheck) {\r\n return v.boolean(strictCheck);\r\n },\r\n\r\n /**\r\n * The `sslPort` validator that returns a Zod schema with an optional stricter\r\n * check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `nonNegativeNum`\r\n * validator.\r\n *\r\n * @function sslPort\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `sslPort`\r\n * option.\r\n */\r\n sslPort(strictCheck) {\r\n return v.nonNegativeNum(strictCheck);\r\n },\r\n\r\n /**\r\n * The `sslCertPath` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `string` validator.\r\n *\r\n * @function sslCertPath\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `sslCertPath`\r\n * option.\r\n */\r\n sslCertPath(strictCheck) {\r\n return v.string(strictCheck);\r\n },\r\n\r\n /**\r\n * The `minWorkers` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `positiveNum` validator.\r\n *\r\n * @function minWorkers\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `minWorkers`\r\n * option.\r\n */\r\n minWorkers(strictCheck) {\r\n return v.positiveNum(strictCheck);\r\n },\r\n\r\n /**\r\n * The `maxWorkers` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `positiveNum` validator.\r\n *\r\n * @function maxWorkers\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `maxWorkers`\r\n * option.\r\n */\r\n maxWorkers(strictCheck) {\r\n return v.positiveNum(strictCheck);\r\n },\r\n\r\n /**\r\n * The `workLimit` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `positiveNum` validator.\r\n *\r\n * @function workLimit\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `workLimit`\r\n * option.\r\n */\r\n workLimit(strictCheck) {\r\n return v.positiveNum(strictCheck);\r\n },\r\n\r\n /**\r\n * The `acquireTimeout` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `nonNegativeNum`\r\n * validator.\r\n *\r\n * @function acquireTimeout\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating\r\n * the `acquireTimeout` option.\r\n */\r\n acquireTimeout(strictCheck) {\r\n return v.nonNegativeNum(strictCheck);\r\n },\r\n\r\n /**\r\n * The `createTimeout` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `nonNegativeNum`\r\n * validator.\r\n *\r\n * @function createTimeout\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating\r\n * the `createTimeout` option.\r\n */\r\n createTimeout(strictCheck) {\r\n return v.nonNegativeNum(strictCheck);\r\n },\r\n\r\n /**\r\n * The `destroyTimeout` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `nonNegativeNum`\r\n * validator.\r\n *\r\n * @function destroyTimeout\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating\r\n * the `destroyTimeout` option.\r\n */\r\n destroyTimeout(strictCheck) {\r\n return v.nonNegativeNum(strictCheck);\r\n },\r\n\r\n /**\r\n * The `idleTimeout` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `nonNegativeNum`\r\n * validator.\r\n *\r\n * @function idleTimeout\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating\r\n * the `idleTimeout` option.\r\n */\r\n idleTimeout(strictCheck) {\r\n return v.nonNegativeNum(strictCheck);\r\n },\r\n\r\n /**\r\n * The `createRetryInterval` validator that returns a Zod schema with\r\n * an optional stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `nonNegativeNum`\r\n * validator.\r\n *\r\n * @function createRetryInterval\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating\r\n * the `createRetryInterval` option.\r\n */\r\n createRetryInterval(strictCheck) {\r\n return v.nonNegativeNum(strictCheck);\r\n },\r\n\r\n /**\r\n * The `reaperInterval` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `nonNegativeNum`\r\n * validator.\r\n *\r\n * @function reaperInterval\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating\r\n * the `reaperInterval` option.\r\n */\r\n reaperInterval(strictCheck) {\r\n return v.nonNegativeNum(strictCheck);\r\n },\r\n\r\n /**\r\n * The `poolBenchmarking` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `boolean` validator.\r\n *\r\n * @function poolBenchmarking\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating\r\n * the `poolBenchmarking` option.\r\n */\r\n poolBenchmarking(strictCheck) {\r\n return v.boolean(strictCheck);\r\n },\r\n\r\n /**\r\n * The `resourcesInterval` validator that returns a Zod schema with\r\n * an optional stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `nonNegativeNum`\r\n * validator.\r\n *\r\n * @function resourcesInterval\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating\r\n * the `resourcesInterval` option.\r\n */\r\n resourcesInterval(strictCheck) {\r\n return v.nonNegativeNum(strictCheck);\r\n },\r\n\r\n /**\r\n * The `logLevel` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures that:\r\n *\r\n * - When `strictCheck` is true, the schema will accept integer number values\r\n * that are between 0 and 5 (inclusive).\r\n *\r\n * - When `strictCheck` is false, the schema will accept integer number values\r\n * and stringified integer number values that are between 1 and 5 (inclusive),\r\n * null, 'undefined', 'null', and '' which will be transformed to null.\r\n *\r\n * @function logLevel\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `logLevel`\r\n * option.\r\n */\r\n logLevel(strictCheck) {\r\n return strictCheck\r\n ? z.number().int().gte(0).lte(5)\r\n : z\r\n .union([\r\n z\r\n .string()\r\n .trim()\r\n .refine(\r\n (value) =>\r\n (!isNaN(Number(value)) &&\r\n value !== true &&\r\n !value.startsWith('[') &&\r\n Number.isInteger(Number(value)) &&\r\n Number(value) >= 0 &&\r\n Number(value) <= 5) ||\r\n ['undefined', 'null', ''].includes(value),\r\n {\r\n params: {\r\n errorMessage: 'The value must be within a 0 and 5 range'\r\n }\r\n }\r\n )\r\n .transform((value) =>\r\n !['undefined', 'null', ''].includes(value)\r\n ? Number(value)\r\n : null\r\n ),\r\n z.number().int().gte(0).lte(5)\r\n ])\r\n .nullable();\r\n },\r\n\r\n /**\r\n * The `logFile` validator that returns a Zod schema with an optional stricter\r\n * check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `string` validator.\r\n * Additionally, it must be a string that ends with '.log'.\r\n *\r\n * @function logFile\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `logFile`\r\n * option.\r\n */\r\n logFile(strictCheck) {\r\n return v\r\n .string(strictCheck)\r\n .refine(\r\n (value) =>\r\n value === null || (value.length >= 5 && value.endsWith('.log')),\r\n {\r\n params: {\r\n errorMessage: 'The value must be a string that ends with .log'\r\n }\r\n }\r\n );\r\n },\r\n\r\n /**\r\n * The `logDest` validator that returns a Zod schema with an optional stricter\r\n * check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `string` validator.\r\n *\r\n * @function logDest\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `logDest`\r\n * option.\r\n */\r\n logDest(strictCheck) {\r\n return v.string(strictCheck);\r\n },\r\n\r\n /**\r\n * The `logToConsole` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `boolean` validator.\r\n *\r\n * @function logToConsole\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating\r\n * the `logToConsole` option.\r\n */\r\n logToConsole(strictCheck) {\r\n return v.boolean(strictCheck);\r\n },\r\n\r\n /**\r\n * The `logToFile` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `boolean` validator.\r\n *\r\n * @function logToFile\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `logToFile`\r\n * option.\r\n */\r\n logToFile(strictCheck) {\r\n return v.boolean(strictCheck);\r\n },\r\n\r\n /**\r\n * The `enableUi` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `boolean` validator.\r\n *\r\n * @function enableUi\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `enableUi`\r\n * option.\r\n */\r\n enableUi(strictCheck) {\r\n return v.boolean(strictCheck);\r\n },\r\n\r\n /**\r\n * The `uiRoute` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `startsWith` validator.\r\n *\r\n * @function uiRoute\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `uiRoute`\r\n * option.\r\n */\r\n uiRoute(strictCheck) {\r\n return v.startsWith(['/'], strictCheck);\r\n },\r\n\r\n /**\r\n * The `nodeEnv` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `enum` validator.\r\n *\r\n * @function nodeEnv\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `nodeEnv`\r\n * option.\r\n */\r\n nodeEnv(strictCheck) {\r\n return v.enum(['development', 'production', 'test'], strictCheck);\r\n },\r\n\r\n /**\r\n * The `listenToProcessExits` validator that returns a Zod schema with\r\n * an optional stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `boolean` validator.\r\n *\r\n * @function listenToProcessExits\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating\r\n * the `listenToProcessExits` option.\r\n */\r\n listenToProcessExits(strictCheck) {\r\n return v.boolean(strictCheck);\r\n },\r\n\r\n /**\r\n * The `noLogo` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `boolean` validator.\r\n *\r\n * @function noLogo\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `noLogo`\r\n * option.\r\n */\r\n noLogo(strictCheck) {\r\n return v.boolean(strictCheck);\r\n },\r\n\r\n /**\r\n * The `hardResetPage` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `boolean` validator.\r\n *\r\n * @function hardResetPage\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating\r\n * the `hardResetPage` option.\r\n */\r\n hardResetPage(strictCheck) {\r\n return v.boolean(strictCheck);\r\n },\r\n\r\n /**\r\n * The `browserShellMode` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `boolean` validator.\r\n *\r\n * @function browserShellMode\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating\r\n * the `browserShellMode` option.\r\n */\r\n browserShellMode(strictCheck) {\r\n return v.boolean(strictCheck);\r\n },\r\n\r\n /**\r\n * The `validation` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `boolean` validator.\r\n *\r\n * @function validation\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `validation`\r\n * option.\r\n */\r\n validation(strictCheck) {\r\n return v.boolean(strictCheck);\r\n },\r\n\r\n /**\r\n * The `enableDebug` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `boolean` validator.\r\n *\r\n * @function enableDebug\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `enableDebug`\r\n * option.\r\n */\r\n enableDebug(strictCheck) {\r\n return v.boolean(strictCheck);\r\n },\r\n\r\n /**\r\n * The `headless` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `boolean` validator.\r\n *\r\n * @function headless\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `headless`\r\n * option.\r\n */\r\n headless(strictCheck) {\r\n return v.boolean(strictCheck);\r\n },\r\n\r\n /**\r\n * The `devtools` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `boolean` validator.\r\n *\r\n * @function devtools\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `devtools`\r\n * option.\r\n */\r\n devtools(strictCheck) {\r\n return v.boolean(strictCheck);\r\n },\r\n\r\n /**\r\n * The `listenToConsole` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `boolean` validator.\r\n *\r\n * @function listenToConsole\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating\r\n * the `listenToConsole` option.\r\n */\r\n listenToConsole(strictCheck) {\r\n return v.boolean(strictCheck);\r\n },\r\n\r\n /**\r\n * The `dumpio` validator that returns a Zod schema with an optional stricter\r\n * check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `boolean` validator.\r\n *\r\n * @function dumpio\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `dumpio`\r\n * option.\r\n */\r\n dumpio(strictCheck) {\r\n return v.boolean(strictCheck);\r\n },\r\n\r\n /**\r\n * The `slowMo` validator that returns a Zod schema with an optional stricter\r\n * check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `nonNegativeNum`\r\n * validator.\r\n *\r\n * @function slowMo\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `slowMo`\r\n * option.\r\n */\r\n slowMo(strictCheck) {\r\n return v.nonNegativeNum(strictCheck);\r\n },\r\n\r\n /**\r\n * The `debuggingPort` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `nonNegativeNum`\r\n * validator.\r\n *\r\n * @function debuggingPort\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating\r\n * the `debuggingPort` option.\r\n */\r\n debuggingPort(strictCheck) {\r\n return v.nonNegativeNum(strictCheck);\r\n },\r\n\r\n /**\r\n * The `requestId` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `string` validator.\r\n * Additionally, it must be a stringified UUID or can be null.\r\n *\r\n * @function requestId\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `requestId`\r\n * option.\r\n */\r\n requestId() {\r\n return z\r\n .string()\r\n .uuid({ message: 'The value must be a stringified UUID' })\r\n .nullable();\r\n }\r\n};\r\n\r\n// Schema for the puppeteer section of options\r\nconst PuppeteerSchema = (strictCheck) =>\r\n z\r\n .object({\r\n args: validators.args(strictCheck)\r\n })\r\n .partial();\r\n\r\n// Schema for the highcharts section of options\r\nconst HighchartsSchema = (strictCheck) =>\r\n z\r\n .object({\r\n version: validators.version(strictCheck),\r\n cdnUrl: validators.cdnUrl(strictCheck),\r\n forceFetch: validators.forceFetch(strictCheck),\r\n cachePath: validators.cachePath(strictCheck),\r\n coreScripts: validators.coreScripts(strictCheck),\r\n moduleScripts: validators.moduleScripts(strictCheck),\r\n indicatorScripts: validators.indicatorScripts(strictCheck),\r\n customScripts: validators.customScripts(strictCheck)\r\n })\r\n .partial();\r\n\r\n// Schema for the export section of options\r\nconst ExportSchema = (strictCheck) =>\r\n z\r\n .object({\r\n infile: validators.infile(strictCheck),\r\n instr: validators.instr(),\r\n options: validators.options(),\r\n svg: validators.svg(),\r\n outfile: validators.outfile(strictCheck),\r\n type: validators.type(strictCheck),\r\n constr: validators.constr(strictCheck),\r\n b64: validators.b64(strictCheck),\r\n noDownload: validators.noDownload(strictCheck),\r\n defaultHeight: validators.defaultHeight(strictCheck),\r\n defaultWidth: validators.defaultWidth(strictCheck),\r\n defaultScale: validators.defaultScale(strictCheck),\r\n height: validators.height(strictCheck),\r\n width: validators.width(strictCheck),\r\n scale: validators.scale(strictCheck),\r\n globalOptions: validators.globalOptions(),\r\n themeOptions: validators.themeOptions(),\r\n batch: validators.batch(false),\r\n rasterizationTimeout: validators.rasterizationTimeout(strictCheck)\r\n })\r\n .partial();\r\n\r\n// Schema for the customLogic section of options\r\nconst CustomLogicSchema = (strictCheck) =>\r\n z\r\n .object({\r\n allowCodeExecution: validators.allowCodeExecution(strictCheck),\r\n allowFileResources: validators.allowFileResources(strictCheck),\r\n customCode: validators.customCode(false),\r\n callback: validators.callback(false),\r\n resources: validators.resources(strictCheck),\r\n loadConfig: validators.loadConfig(false),\r\n createConfig: validators.createConfig(false)\r\n })\r\n .partial();\r\n\r\n// Schema for the server.proxy section of options\r\nconst ProxySchema = (strictCheck) =>\r\n z\r\n .object({\r\n host: validators.proxyHost(false),\r\n port: validators.proxyPort(strictCheck),\r\n timeout: validators.proxyTimeout(strictCheck)\r\n })\r\n .partial();\r\n\r\n// Schema for the server.rateLimiting section of options\r\nconst RateLimitingSchema = (strictCheck) =>\r\n z\r\n .object({\r\n enable: validators.enableRateLimiting(strictCheck),\r\n maxRequests: validators.maxRequests(strictCheck),\r\n window: validators.window(strictCheck),\r\n delay: validators.delay(strictCheck),\r\n trustProxy: validators.trustProxy(strictCheck),\r\n skipKey: validators.skipKey(false),\r\n skipToken: validators.skipToken(false)\r\n })\r\n .partial();\r\n\r\n// Schema for the server.ssl section of options\r\nconst SslSchema = (strictCheck) =>\r\n z\r\n .object({\r\n enable: validators.enableSsl(strictCheck),\r\n force: validators.sslForce(strictCheck),\r\n port: validators.sslPort(strictCheck),\r\n certPath: validators.sslCertPath(false)\r\n })\r\n .partial();\r\n\r\n// Schema for the server section of options\r\nconst ServerSchema = (strictCheck) =>\r\n z.object({\r\n enable: validators.enableServer(strictCheck).optional(),\r\n host: validators.host(strictCheck).optional(),\r\n port: validators.port(strictCheck).optional(),\r\n uploadLimit: validators.uploadLimit(strictCheck).optional(),\r\n benchmarking: validators.serverBenchmarking(strictCheck).optional(),\r\n proxy: ProxySchema(strictCheck).optional(),\r\n rateLimiting: RateLimitingSchema(strictCheck).optional(),\r\n ssl: SslSchema(strictCheck).optional()\r\n });\r\n\r\n// Schema for the pool section of options\r\nconst PoolSchema = (strictCheck) =>\r\n z\r\n .object({\r\n minWorkers: validators.minWorkers(strictCheck),\r\n maxWorkers: validators.maxWorkers(strictCheck),\r\n workLimit: validators.workLimit(strictCheck),\r\n acquireTimeout: validators.acquireTimeout(strictCheck),\r\n createTimeout: validators.createTimeout(strictCheck),\r\n destroyTimeout: validators.destroyTimeout(strictCheck),\r\n idleTimeout: validators.idleTimeout(strictCheck),\r\n createRetryInterval: validators.createRetryInterval(strictCheck),\r\n reaperInterval: validators.reaperInterval(strictCheck),\r\n benchmarking: validators.poolBenchmarking(strictCheck)\r\n })\r\n .partial();\r\n\r\n// Schema for the logging section of options\r\nconst LoggingSchema = (strictCheck) =>\r\n z\r\n .object({\r\n level: validators.logLevel(strictCheck),\r\n file: validators.logFile(strictCheck),\r\n dest: validators.logDest(strictCheck),\r\n toConsole: validators.logToConsole(strictCheck),\r\n toFile: validators.logToFile(strictCheck)\r\n })\r\n .partial();\r\n\r\n// Schema for the ui section of options\r\nconst UiSchema = (strictCheck) =>\r\n z\r\n .object({\r\n enable: validators.enableUi(strictCheck),\r\n route: validators.uiRoute(strictCheck)\r\n })\r\n .partial();\r\n\r\n// Schema for the other section of options\r\nconst OtherSchema = (strictCheck) =>\r\n z\r\n .object({\r\n nodeEnv: validators.nodeEnv(strictCheck),\r\n listenToProcessExits: validators.listenToProcessExits(strictCheck),\r\n noLogo: validators.noLogo(strictCheck),\r\n hardResetPage: validators.hardResetPage(strictCheck),\r\n browserShellMode: validators.browserShellMode(strictCheck),\r\n validation: validators.validation(strictCheck)\r\n })\r\n .partial();\r\n\r\n// Schema for the debug section of options\r\nconst DebugSchema = (strictCheck) =>\r\n z\r\n .object({\r\n enable: validators.enableDebug(strictCheck),\r\n headless: validators.headless(strictCheck),\r\n devtools: validators.devtools(strictCheck),\r\n listenToConsole: validators.listenToConsole(strictCheck),\r\n dumpio: validators.dumpio(strictCheck),\r\n slowMo: validators.slowMo(strictCheck),\r\n debuggingPort: validators.debuggingPort(strictCheck)\r\n })\r\n .partial();\r\n\r\n// Strict schema for the config\r\nexport const StrictConfigSchema = z.object({\r\n requestId: validators.requestId(),\r\n puppeteer: PuppeteerSchema(true),\r\n highcharts: HighchartsSchema(true),\r\n export: ExportSchema(true),\r\n customLogic: CustomLogicSchema(true),\r\n server: ServerSchema(true),\r\n pool: PoolSchema(true),\r\n logging: LoggingSchema(true),\r\n ui: UiSchema(true),\r\n other: OtherSchema(true),\r\n debug: DebugSchema(true)\r\n});\r\n\r\n// Loose schema for the config\r\nexport const LooseConfigSchema = z.object({\r\n requestId: validators.requestId(),\r\n puppeteer: PuppeteerSchema(false),\r\n highcharts: HighchartsSchema(false),\r\n export: ExportSchema(false),\r\n customLogic: CustomLogicSchema(false),\r\n server: ServerSchema(false),\r\n pool: PoolSchema(false),\r\n logging: LoggingSchema(false),\r\n ui: UiSchema(false),\r\n other: OtherSchema(false),\r\n debug: DebugSchema(false)\r\n});\r\n\r\n// Schema for the environment variables config\r\nexport const EnvSchema = z.object({\r\n // puppeteer\r\n PUPPETEER_ARGS: validators.args(false),\r\n\r\n // highcharts\r\n HIGHCHARTS_VERSION: validators.version(false),\r\n HIGHCHARTS_CDN_URL: validators.cdnUrl(false),\r\n HIGHCHARTS_FORCE_FETCH: validators.forceFetch(false),\r\n HIGHCHARTS_CACHE_PATH: validators.cachePath(false),\r\n HIGHCHARTS_ADMIN_TOKEN: validators.adminToken(false),\r\n HIGHCHARTS_CORE_SCRIPTS: validators.coreScripts(false),\r\n HIGHCHARTS_MODULE_SCRIPTS: validators.moduleScripts(false),\r\n HIGHCHARTS_INDICATOR_SCRIPTS: validators.indicatorScripts(false),\r\n HIGHCHARTS_CUSTOM_SCRIPTS: validators.customScripts(false),\r\n\r\n // export\r\n EXPORT_INFILE: validators.infile(false),\r\n EXPORT_INSTR: validators.instr(),\r\n EXPORT_OPTIONS: validators.options(),\r\n EXPORT_SVG: validators.svg(),\r\n EXPORT_BATCH: validators.batch(false),\r\n EXPORT_OUTFILE: validators.outfile(false),\r\n EXPORT_TYPE: validators.type(false),\r\n EXPORT_CONSTR: validators.constr(false),\r\n EXPORT_B64: validators.b64(false),\r\n EXPORT_NO_DOWNLOAD: validators.noDownload(false),\r\n EXPORT_HEIGHT: validators.height(false),\r\n EXPORT_WIDTH: validators.width(false),\r\n EXPORT_SCALE: validators.scale(false),\r\n EXPORT_DEFAULT_HEIGHT: validators.defaultHeight(false),\r\n EXPORT_DEFAULT_WIDTH: validators.defaultWidth(false),\r\n EXPORT_DEFAULT_SCALE: validators.defaultScale(false),\r\n EXPORT_GLOBAL_OPTIONS: validators.globalOptions(),\r\n EXPORT_THEME_OPTIONS: validators.themeOptions(),\r\n EXPORT_RASTERIZATION_TIMEOUT: validators.rasterizationTimeout(false),\r\n\r\n // custom\r\n CUSTOM_LOGIC_ALLOW_CODE_EXECUTION: validators.allowCodeExecution(false),\r\n CUSTOM_LOGIC_ALLOW_FILE_RESOURCES: validators.allowFileResources(false),\r\n CUSTOM_LOGIC_CUSTOM_CODE: validators.customCode(false),\r\n CUSTOM_LOGIC_CALLBACK: validators.callback(false),\r\n CUSTOM_LOGIC_RESOURCES: validators.resources(false),\r\n CUSTOM_LOGIC_LOAD_CONFIG: validators.loadConfig(false),\r\n CUSTOM_LOGIC_CREATE_CONFIG: validators.createConfig(false),\r\n\r\n // server\r\n SERVER_ENABLE: validators.enableServer(false),\r\n SERVER_HOST: validators.host(false),\r\n SERVER_PORT: validators.port(false),\r\n SERVER_UPLOAD_LIMIT: validators.uploadLimit(false),\r\n SERVER_BENCHMARKING: validators.serverBenchmarking(false),\r\n\r\n // server proxy\r\n SERVER_PROXY_HOST: validators.proxyHost(false),\r\n SERVER_PROXY_PORT: validators.proxyPort(false),\r\n SERVER_PROXY_TIMEOUT: validators.proxyTimeout(false),\r\n\r\n // server rate limiting\r\n SERVER_RATE_LIMITING_ENABLE: validators.enableRateLimiting(false),\r\n SERVER_RATE_LIMITING_MAX_REQUESTS: validators.maxRequests(false),\r\n SERVER_RATE_LIMITING_WINDOW: validators.window(false),\r\n SERVER_RATE_LIMITING_DELAY: validators.delay(false),\r\n SERVER_RATE_LIMITING_TRUST_PROXY: validators.trustProxy(false),\r\n SERVER_RATE_LIMITING_SKIP_KEY: validators.skipKey(false),\r\n SERVER_RATE_LIMITING_SKIP_TOKEN: validators.skipToken(false),\r\n\r\n // server ssl\r\n SERVER_SSL_ENABLE: validators.enableSsl(false),\r\n SERVER_SSL_FORCE: validators.sslForce(false),\r\n SERVER_SSL_PORT: validators.sslPort(false),\r\n SERVER_SSL_CERT_PATH: validators.sslCertPath(false),\r\n\r\n // pool\r\n POOL_MIN_WORKERS: validators.minWorkers(false),\r\n POOL_MAX_WORKERS: validators.maxWorkers(false),\r\n POOL_WORK_LIMIT: validators.workLimit(false),\r\n POOL_ACQUIRE_TIMEOUT: validators.acquireTimeout(false),\r\n POOL_CREATE_TIMEOUT: validators.createTimeout(false),\r\n POOL_DESTROY_TIMEOUT: validators.destroyTimeout(false),\r\n POOL_IDLE_TIMEOUT: validators.idleTimeout(false),\r\n POOL_CREATE_RETRY_INTERVAL: validators.createRetryInterval(false),\r\n POOL_REAPER_INTERVAL: validators.reaperInterval(false),\r\n POOL_BENCHMARKING: validators.poolBenchmarking(false),\r\n\r\n // logging\r\n LOGGING_LEVEL: validators.logLevel(false),\r\n LOGGING_FILE: validators.logFile(false),\r\n LOGGING_DEST: validators.logDest(false),\r\n LOGGING_TO_CONSOLE: validators.logToConsole(false),\r\n LOGGING_TO_FILE: validators.logToFile(false),\r\n\r\n // ui\r\n UI_ENABLE: validators.enableUi(false),\r\n UI_ROUTE: validators.uiRoute(false),\r\n\r\n // other\r\n OTHER_NODE_ENV: validators.nodeEnv(false),\r\n OTHER_LISTEN_TO_PROCESS_EXITS: validators.listenToProcessExits(false),\r\n OTHER_NO_LOGO: validators.noLogo(false),\r\n OTHER_HARD_RESET_PAGE: validators.hardResetPage(false),\r\n OTHER_BROWSER_SHELL_MODE: validators.browserShellMode(false),\r\n OTHER_VALIDATION: validators.validation(false),\r\n\r\n // debugger\r\n DEBUG_ENABLE: validators.enableDebug(false),\r\n DEBUG_HEADLESS: validators.headless(false),\r\n DEBUG_DEVTOOLS: validators.devtools(false),\r\n DEBUG_LISTEN_TO_CONSOLE: validators.listenToConsole(false),\r\n DEBUG_DUMPIO: validators.dumpio(false),\r\n DEBUG_SLOW_MO: validators.slowMo(false),\r\n DEBUG_DEBUGGING_PORT: validators.debuggingPort(false)\r\n});\r\n\r\n/**\r\n * Validates the environment variables options using the EnvSchema.\r\n *\r\n * @param {Object} process.env - The configuration options from environment\r\n * variables file to validate.\r\n *\r\n * @returns {Object} The parsed and validated environment variables.\r\n */\r\nexport const envs = EnvSchema.partial().parse(process.env);\r\n\r\n/**\r\n * Validates the configuration options using the `StrictConfigSchema`.\r\n *\r\n * @function strictValidate\r\n *\r\n * @param {Object} configOptions - The configuration options to validate.\r\n *\r\n * @returns {Object} The parsed and validated configuration options.\r\n */\r\nexport function strictValidate(configOptions) {\r\n return StrictConfigSchema.partial().parse(configOptions);\r\n}\r\n\r\n/**\r\n * Validates the configuration options using the `LooseConfigSchema`.\r\n *\r\n * @function looseValidate\r\n *\r\n * @param {Object} configOptions - The configuration options to validate.\r\n *\r\n * @returns {Object} The parsed and validated configuration options.\r\n */\r\nexport function looseValidate(configOptions) {\r\n return LooseConfigSchema.partial().parse(configOptions);\r\n}\r\n\r\n/**\r\n * Custom error mapping function for Zod schema validation.\r\n *\r\n * This function customizes the error messages produced by Zod schema\r\n * validation, providing more specific and user-friendly feedback based on the\r\n * issue type and context.\r\n *\r\n * The function modifies the error messages as follows:\r\n *\r\n * - For missing required values (undefined), it returns a message indicating\r\n * that no value was provided for the specific property.\r\n *\r\n * - For custom validation errors, if a custom error message is provided in the\r\n * issue parameters, it includes this message along with the invalid data\r\n * received.\r\n *\r\n * - For all other errors, it appends property-specific information to the\r\n * default error message provided by Zod.\r\n *\r\n * @function _customErrorMap\r\n *\r\n * @param {z.ZodIssue} issue - The issue object representing the validation\r\n * error.\r\n * @param {Object} context - The context object providing additional information\r\n * about the validation error.\r\n *\r\n * @returns {Object} An object containing the customized error message.\r\n */\r\nfunction _customErrorMap(issue, context) {\r\n // Get the chain of properties which error directly refers to\r\n const propertyName = issue.path.join('.');\r\n\r\n // Create the first part of the message about the property information\r\n const propertyInfo = `Invalid value for the ${propertyName}`;\r\n\r\n // Modified message for the invalid type\r\n if (issue.code === z.ZodIssueCode.invalid_type) {\r\n // Modified message for the required values\r\n if (issue.received === z.ZodParsedType.undefined) {\r\n return {\r\n message: `${propertyInfo} - No value was provided.`\r\n };\r\n }\r\n\r\n // Modified message for the specific invalid type when values exist\r\n return {\r\n message: `${propertyInfo} - Invalid type. ${context.defaultError}.`\r\n };\r\n }\r\n\r\n // Modified message for the custom validation\r\n if (issue.code === z.ZodIssueCode.custom) {\r\n // If the custom message for error exist, include it\r\n if (issue.params?.errorMessage) {\r\n return {\r\n message: `${propertyInfo} - ${issue.params?.errorMessage}, received '${context.data}'.`\r\n };\r\n }\r\n }\r\n\r\n // Modified message for the invalid union error\r\n if (issue.code === z.ZodIssueCode.invalid_union) {\r\n // Create the first part of the message about the multiple errors\r\n let message = `Multiple errors occurred for the ${propertyName}:\\n`;\r\n\r\n // Cycle through all errors and create a correct message\r\n issue.unionErrors.forEach((value) => {\r\n const index = value.issues[0].message.indexOf('-');\r\n message +=\r\n index !== -1\r\n ? `${value.issues[0].message}\\n`.substring(index)\r\n : `${value.issues[0].message}\\n`;\r\n });\r\n\r\n // Return the final message for the invalid union error\r\n return {\r\n message\r\n };\r\n }\r\n\r\n // Return the default error message, extended by the info about the property\r\n return {\r\n message: `${propertyInfo} - ${context.defaultError}.`\r\n };\r\n}\r\n\r\nexport default {\r\n validators,\r\n StrictConfigSchema,\r\n LooseConfigSchema,\r\n EnvSchema,\r\n envs,\r\n strictValidate,\r\n looseValidate\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * A custom error class for handling export-related errors. Extends the native\r\n * `Error` class to include additional properties like status code and stack\r\n * trace details.\r\n */\r\nclass ExportError extends Error {\r\n /**\r\n * Creates an instance of the `ExportError`.\r\n *\r\n * @param {string} message - The error message to be displayed.\r\n * @param {number} statusCode - Optional HTTP status code associated\r\n * with the error (e.g., 400, 500).\r\n */\r\n constructor(message, statusCode) {\r\n super();\r\n\r\n // Set the `message` and `stackMessage` with provided message\r\n this.message = message;\r\n this.stackMessage = message;\r\n\r\n // Set the `statusCode` if provided\r\n if (statusCode) {\r\n this.statusCode = statusCode;\r\n }\r\n }\r\n\r\n /**\r\n * Sets additional error details based on an existing error object.\r\n *\r\n * @param {Error} error - An error object containing details to populate\r\n * the `ExportError` instance.\r\n *\r\n * @returns {ExportError} The updated instance of the `ExportError` class.\r\n */\r\n setError(error) {\r\n // Save the provided error\r\n this.error = error;\r\n\r\n // Set the error's name if present\r\n if (error.name) {\r\n this.name = error.name;\r\n }\r\n\r\n // Set the error's status code if present\r\n if (error.statusCode) {\r\n this.statusCode = error.statusCode;\r\n }\r\n\r\n // Set the error's stack and stack's message if present\r\n if (error.stack) {\r\n this.stackMessage = error.message;\r\n this.stack = error.stack;\r\n }\r\n\r\n // Return updated `ExportError` instance\r\n return this;\r\n }\r\n}\r\n\r\nexport default ExportError;\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * @overview This module manages configuration for the Highcharts Export Server\r\n * by loading and merging options from multiple sources, such as the default\r\n * settings, environment variables, user-provided options, and command-line\r\n * arguments. Ensures the global options are up-to-date with the highest\r\n * priority values. Provides functions for accessing and updating configuration.\r\n */\r\n\r\nimport { readFileSync } from 'fs';\r\n\r\nimport { log, logWithStack, logZodIssues } from './logger.js';\r\nimport { deepCopy, getAbsolutePath, isObject } from './utils.js';\r\nimport {\r\n envs,\r\n looseValidate,\r\n strictValidate,\r\n validators\r\n} from './validation.js';\r\n\r\nimport defaultConfig from './schemas/config.js';\r\n\r\nimport ExportError from './errors/ExportError.js';\r\n\r\n// Sets the global options with initial values from the default config\r\nconst globalOptions = _initOptions(defaultConfig);\r\n\r\n// Properties nesting level of all options\r\nconst nestedProps = _createNestedProps(defaultConfig);\r\n\r\n// Properties names that should not be recursively merged\r\nconst absoluteProps = _createAbsoluteProps(defaultConfig);\r\n\r\n/**\r\n * Retrieves a copy of the global options object or an original global options\r\n * object, based on the `getCopy` flag.\r\n *\r\n * @function getOptions\r\n *\r\n * @param {boolean} [getCopy=true] - Specifies whether to return a copied\r\n * object of the global options (`true`) or a reference to the global options\r\n * object (`false`). The default value is `true`.\r\n *\r\n * @returns {Object} A copy of the global options object, or a reference\r\n * to the global options object.\r\n */\r\nexport function getOptions(getCopy = true) {\r\n // Return a copy or an original global options object\r\n return getCopy ? deepCopy(globalOptions) : globalOptions;\r\n}\r\n\r\n/**\r\n * Updates and returns the global options object or a copy of the global options\r\n * object, based on the `getCopy` flag. The `newOptions` object can be\r\n * strictly validated depending on the `strictCheck` flag.\r\n *\r\n * @function updateOptions\r\n *\r\n * @param {Object} newOptions - An object containing the new options to be\r\n * merged into the global options.\r\n * @param {boolean} [getCopy=false] - Determines whether to merge the new\r\n * options into a copy of the global options object (`true`) or directly into\r\n * the global options object (`false`). The default value is `false`.\r\n * @param {boolean} [strictCheck=true] - Determines if stricter validation\r\n * should be applied. The default value is `true`.\r\n *\r\n * @returns {Object} The updated options object, either the modified global\r\n * options or a modified copy, based on the value of `getCopy`.\r\n */\r\nexport function updateOptions(newOptions, getCopy = false, strictCheck = true) {\r\n // Merge new options to the global options or its copy and return the result\r\n return _mergeOptions(\r\n // First, get the options\r\n getOptions(getCopy),\r\n // Next, validate the new options\r\n validateOptions(newOptions, strictCheck)\r\n );\r\n}\r\n\r\n/**\r\n * Updates and returns the global options object with values provided through\r\n * the CLI, keeping the principle of options load priority. The function accepts\r\n * a `cliArgs` array containing arguments from the CLI, which will be validated\r\n * and applied if provided.\r\n *\r\n * The function prioritizes values in the following order:\r\n *\r\n * 1. Values from the command line interface (CLI).\r\n * 2. Values from a custom JSON file (loaded by the `--loadConfig` option).\r\n *\r\n * @function setCliOptions\r\n *\r\n * @param {Array} cliArgs - An array of command line arguments used\r\n * for additional configuration.\r\n *\r\n * @returns {Object} The updated global options object, reflecting the merged\r\n * configuration from sources provided through the CLI.\r\n */\r\nexport function setCliOptions(cliArgs) {\r\n // Only for the CLI usage\r\n if (cliArgs && Array.isArray(cliArgs) && cliArgs.length) {\r\n try {\r\n // Get options from the custom JSON loaded via the `--loadConfig`\r\n const configOptions = _loadConfigFile(cliArgs);\r\n\r\n // Update global options with validated values from the `configOptions`\r\n updateOptions(configOptions);\r\n } catch (error) {\r\n log(2, '[validation] No options added from the `--loadConfig` option.');\r\n }\r\n\r\n try {\r\n // Get options from the CLI\r\n const cliOptions = _pairArgumentValue(cliArgs);\r\n\r\n // Update global options with validated values from the `cliOptions`\r\n updateOptions(cliOptions, false, false);\r\n } catch (error) {\r\n log(2, '[validation] No options added from the CLI arguments.');\r\n }\r\n }\r\n\r\n // Return reference to the global options\r\n return getOptions(false);\r\n}\r\n\r\n/**\r\n * Maps old-structured configuration options (PhantomJS-based) to a new format\r\n * (Puppeteer-based). This function converts flat, old-structured options into\r\n * a new, nested configuration format based on a predefined mapping provided\r\n * in the `nestedProps` object. The new format is used for Puppeteer, while\r\n * the old format was used for PhantomJS.\r\n *\r\n * @function mapToNewOptions\r\n *\r\n * @param {Object} oldOptions - The old, flat configuration options\r\n * to be converted.\r\n *\r\n * @returns {Object} A new object containing options structured according\r\n * to the mapping defined in the `nestedProps` object or an empty object\r\n * if the provided `oldOptions` is not a correct object.\r\n */\r\nexport function mapToNewOptions(oldOptions) {\r\n // An object for the new structured options\r\n const newOptions = {};\r\n\r\n // Check if provided value is a correct object\r\n if (isObject(oldOptions)) {\r\n // Iterate over each key-value pair in the old-structured options\r\n for (const [key, value] of Object.entries(oldOptions)) {\r\n // If there is a nested mapping, split it into a properties chain\r\n const propertiesChain = nestedProps[key]\r\n ? nestedProps[key].split('.')\r\n : [];\r\n\r\n // If it is the last property in the chain, assign the value, otherwise,\r\n // create or reuse the nested object\r\n propertiesChain.reduce(\r\n (obj, prop, index) =>\r\n (obj[prop] =\r\n propertiesChain.length - 1 === index ? value : obj[prop] || {}),\r\n newOptions\r\n );\r\n }\r\n } else {\r\n log(\r\n 2,\r\n '[config] No correct object with options was provided. Returning an empty object.'\r\n );\r\n }\r\n\r\n // Return the new, structured options object\r\n return newOptions;\r\n}\r\n\r\n/**\r\n * Validates a specified option using the corresponding validator from the\r\n * configuration object. Returns the original option if the validation\r\n * is disabled globally.\r\n *\r\n * @function validateOption\r\n *\r\n * @param {string} name - The name of the option to validate.\r\n * @param {any} configOption - The value of the option to validate.\r\n * @param {boolean} [strictCheck=true] - Determines if stricter validation\r\n * should be applied. The default value is `true`.\r\n *\r\n * @returns {any} The parsed and validated value of the option.\r\n */\r\nexport function validateOption(name, configOption, strictCheck = true) {\r\n // Return the original option if the validation is disabled\r\n if (!getOptions().other.validation) {\r\n return configOption;\r\n }\r\n\r\n try {\r\n // Return validated option\r\n return validators[name](strictCheck).parse(configOption);\r\n } catch (error) {\r\n // Log Zod issues\r\n logZodIssues(\r\n 1,\r\n error.issues,\r\n `[validation] The ${name} option validation error`\r\n );\r\n\r\n // Throw validation error\r\n throw new ExportError(\r\n `[validation] The ${name} option validation error`,\r\n 400\r\n );\r\n }\r\n}\r\n\r\n/**\r\n * Validates the provided configuration options for the exporting process.\r\n * Returns the original option if the validation is disabled globally.\r\n *\r\n * @function validateOptions\r\n *\r\n * @param {Object} configOptions - The configuration options to be validated.\r\n * @param {boolean} [strictCheck=true] - Determines if stricter validation\r\n * should be applied. The default value is `true`.\r\n *\r\n * @returns {Object} The parsed and validated configuration options object.\r\n */\r\nexport function validateOptions(configOptions, strictCheck = true) {\r\n // Return the original config if the validation is disabled\r\n if (!getOptions().other.validation) {\r\n return configOptions;\r\n }\r\n\r\n try {\r\n // Return validated options\r\n return strictCheck\r\n ? strictValidate(configOptions)\r\n : looseValidate(configOptions);\r\n } catch (error) {\r\n // Log Zod issues\r\n logZodIssues(1, error.issues, '[validation] Options validation error');\r\n\r\n // Throw validation error\r\n throw new ExportError('[validation] Options validation error', 400);\r\n }\r\n}\r\n\r\n/**\r\n * Validates, parses, and checks if the provided config is allowed set\r\n * of options.\r\n *\r\n * @function isAllowedConfig\r\n *\r\n * @param {unknown} config - The config to be validated and parsed as a set\r\n * of options. Must be either an object or a string.\r\n * @param {boolean} [toString=false] - Whether to return a stringified version\r\n * of the parsed config. The default value is `false`.\r\n * @param {boolean} [allowFunctions=false] - Whether to allow functions\r\n * in the parsed config. If `true`, functions are preserved. Otherwise, when\r\n * a function is found, `null` is returned. The default value is `false`.\r\n *\r\n * @returns {(Object|string|null)} Returns a parsed set of options object,\r\n * a stringified set of options object if the `toString` is `true`, and `null`\r\n * if the config is not a valid set of options or parsing fails.\r\n */\r\nexport function isAllowedConfig(\r\n config,\r\n toString = false,\r\n allowFunctions = false\r\n) {\r\n try {\r\n // Accept only objects and strings\r\n if (!isObject(config) && typeof config !== 'string') {\r\n // Return `null` if any other type\r\n return null;\r\n }\r\n\r\n // Get the object representation of the original config\r\n const objectConfig =\r\n typeof config === 'string'\r\n ? allowFunctions\r\n ? eval(`(${config})`)\r\n : JSON.parse(config)\r\n : config;\r\n\r\n // Preserve or remove potential functions based on the `allowFunctions` flag\r\n const stringifiedOptions = _optionsStringify(\r\n objectConfig,\r\n allowFunctions,\r\n false\r\n );\r\n\r\n // Parse the config to check if it is valid set of options\r\n const parsedOptions = allowFunctions\r\n ? JSON.parse(\r\n _optionsStringify(objectConfig, allowFunctions, true),\r\n (_, value) =>\r\n typeof value === 'string' && value.startsWith('function')\r\n ? eval(`(${value})`)\r\n : value\r\n )\r\n : JSON.parse(stringifiedOptions);\r\n\r\n // Return stringified or object options based on the `toString` flag\r\n return toString ? stringifiedOptions : parsedOptions;\r\n } catch (error) {\r\n // Return `null` if parsing fails\r\n return null;\r\n }\r\n}\r\n\r\n/**\r\n * Initializes and returns the global options object based on the provided\r\n * configuration, setting values from nested properties recursively.\r\n *\r\n * The function prioritizes values in the following order:\r\n *\r\n * 1. Values from environment variables (specified in the `.env` file).\r\n * 2. Values from the `./lib/schemas/config.js` file (defaults).\r\n *\r\n * @function _initOptions\r\n *\r\n * @param {Object} config - The configuration object used for initializing\r\n * the global options. It should include nested properties with a `value`\r\n * and an `envLink` for linking to environment variables.\r\n *\r\n * @returns {Object} The initialized global options object, populated with\r\n * values based on the provided configuration and the established priority\r\n * order.\r\n */\r\nfunction _initOptions(config) {\r\n // Init the object for options\r\n const options = {};\r\n\r\n // Start initializing the `options` object recursively\r\n for (const [name, item] of Object.entries(config)) {\r\n if (Object.prototype.hasOwnProperty.call(item, 'value')) {\r\n // Set the correct value based on the established priority order\r\n if (envs[item.envLink] !== undefined && envs[item.envLink] !== null) {\r\n // The environment variables value\r\n options[name] = envs[item.envLink];\r\n } else {\r\n // The value from the config file\r\n options[name] = item.value;\r\n }\r\n } else {\r\n // Create a category of options in the `options` object\r\n options[name] = _initOptions(item);\r\n }\r\n }\r\n\r\n // Return the created `options` object\r\n return options;\r\n}\r\n\r\n/**\r\n * Recursively merges two sets of configuration options, taking into account\r\n * properties specified in the `absoluteProps` array that require absolute\r\n * merging. The `originalOptions` object will be extended with options from\r\n * the `newOptions` object.\r\n *\r\n * @function _mergeOptions\r\n *\r\n * @param {Object} originalOptions - The original configuration options object\r\n * to be extended.\r\n * @param {Object} newOptions - The new configuration options object to merge.\r\n *\r\n * @returns {Object} The extended `originalOptions` object.\r\n */\r\nfunction _mergeOptions(originalOptions, newOptions) {\r\n // Check if the `originalOptions` and `newOptions` are correct objects\r\n if (isObject(originalOptions) && isObject(newOptions)) {\r\n for (const [key, value] of Object.entries(newOptions)) {\r\n originalOptions[key] =\r\n isObject(value) &&\r\n !absoluteProps.includes(key) &&\r\n originalOptions[key] !== undefined\r\n ? _mergeOptions(originalOptions[key], value)\r\n : value !== undefined\r\n ? value\r\n : originalOptions[key] || null;\r\n }\r\n }\r\n\r\n // Return the original (modified or not) options\r\n return originalOptions;\r\n}\r\n\r\n/**\r\n * Converts the provided options object to a JSON string with the option\r\n * to preserve functions. In order for a function to be preserved, it needs\r\n * to follow the format `function (...) {...}`. Such a function can also\r\n * be stringified.\r\n *\r\n * @function _optionsStringify\r\n *\r\n * @param {Object} options - The options object to be converted to a string.\r\n * @param {boolean} allowFunctions - If set to `true`, functions are preserved\r\n * in the output. Otherwise an error is thrown.\r\n * @param {boolean} stringifyFunctions - If set to `true`, functions are saved\r\n * as strings. The `allowFunctions` must be set to `true` as well for this\r\n * to take an effect.\r\n *\r\n * @returns {string} The JSON-formatted string representing the options.\r\n *\r\n * @throws {Error} Throws an `Error` when functions are not allowed but are\r\n * found in provided options object.\r\n */\r\nfunction _optionsStringify(options, allowFunctions, stringifyFunctions) {\r\n const replacerCallback = (_, value) => {\r\n // Trim string values\r\n if (typeof value === 'string') {\r\n value = value.trim();\r\n }\r\n\r\n // If `value` is a function or stringified function\r\n if (\r\n typeof value === 'function' ||\r\n (typeof value === 'string' &&\r\n value.startsWith('function') &&\r\n value.endsWith('}'))\r\n ) {\r\n // If the `allowFunctions` is set to `true`, preserve functions\r\n if (allowFunctions) {\r\n // Based on the `stringifyFunctions` options, set function values\r\n return stringifyFunctions\r\n ? // As stringified functions\r\n `\"EXP_FUN${(value + '').replaceAll(/\\s+/g, ' ')}EXP_FUN\"`\r\n : // As functions\r\n `EXP_FUN${(value + '').replaceAll(/\\s+/g, ' ')}EXP_FUN`;\r\n } else {\r\n // Throw an error otherwise\r\n throw new Error();\r\n }\r\n }\r\n\r\n // In all other cases, simply return the value\r\n return value;\r\n };\r\n\r\n // Stringify options and if required, replace special functions marks\r\n return JSON.stringify(options, replacerCallback).replaceAll(\r\n stringifyFunctions ? /\\\\\"EXP_FUN|EXP_FUN\\\\\"/g : /\"EXP_FUN|EXP_FUN\"/g,\r\n ''\r\n );\r\n}\r\n\r\n/**\r\n * Loads additional configuration from a specified file provided via\r\n * the `--loadConfig` option in the command-line arguments.\r\n *\r\n * @function _loadConfigFile\r\n *\r\n * @param {Array} cliArgs - Command-line arguments to search\r\n * for the `--loadConfig` option and the corresponding file path.\r\n *\r\n * @returns {Object} The additional configuration loaded from the specified\r\n * file, or an empty object if the file is not found, invalid, or an error\r\n * occurs.\r\n */\r\nfunction _loadConfigFile(cliArgs) {\r\n // Get the allow flags for the custom logic check\r\n const { allowCodeExecution, allowFileResources } = getOptions().customLogic;\r\n\r\n // Check if the `--loadConfig` option was used\r\n const configIndex = cliArgs.findIndex(\r\n (arg) => arg.replace(/-/g, '') === 'loadConfig'\r\n );\r\n\r\n // Get the `--loadConfig` option value\r\n const configFileName = configIndex > -1 && cliArgs[configIndex + 1];\r\n\r\n // Check if the `--loadConfig` is present and has a correct value\r\n if (configFileName && allowFileResources) {\r\n try {\r\n // Load an optional custom JSON config file\r\n return isAllowedConfig(\r\n readFileSync(getAbsolutePath(configFileName), 'utf8'),\r\n false,\r\n allowCodeExecution\r\n );\r\n } catch (error) {\r\n logWithStack(\r\n 2,\r\n error,\r\n `[config] Unable to load the configuration from the ${configFileName} file.`\r\n );\r\n }\r\n }\r\n\r\n // No additional options to return\r\n return {};\r\n}\r\n\r\n/**\r\n * Parses command-line arguments and pairs each argument with its corresponding\r\n * option in the configuration. The values are structured into a nested options\r\n * object, based on predefined mappings in the `nestedProps` object.\r\n *\r\n * @function _pairArgumentValue\r\n *\r\n * @param {Array} cliArgs - An array of command-line arguments\r\n * containing options and their associated values.\r\n *\r\n * @returns {Object} An updated options object where each option from\r\n * the command-line is paired with its value, structured into nested objects\r\n * as defined.\r\n */\r\nfunction _pairArgumentValue(cliArgs) {\r\n // An empty object to collect and structurize data from the args\r\n const cliOptions = {};\r\n\r\n // Cycle through all CLI args and filter them\r\n for (let i = 0; i < cliArgs.length; i++) {\r\n const option = cliArgs[i].replace(/-/g, '');\r\n\r\n // Find the right place for property's value\r\n const propertiesChain = nestedProps[option]\r\n ? nestedProps[option].split('.')\r\n : [];\r\n\r\n // Create options object with values from CLI for later parsing and merging\r\n propertiesChain.reduce((obj, prop, index) => {\r\n if (propertiesChain.length - 1 === index) {\r\n const value = cliArgs[++i];\r\n if (!value) {\r\n log(\r\n 2,\r\n `[config] Missing value for the CLI '--${option}' argument. Using the default value.`\r\n );\r\n }\r\n obj[prop] = value || null;\r\n } else if (obj[prop] === undefined) {\r\n obj[prop] = {};\r\n }\r\n return obj[prop];\r\n }, cliOptions);\r\n }\r\n\r\n // Return parsed CLI options\r\n return cliOptions;\r\n}\r\n\r\n/**\r\n * Recursively generates a mapping of nested argument chains from a nested\r\n * config object. This function traverses a nested object and creates a mapping\r\n * where each key is an argument name (either from `cliName`, `legacyName`,\r\n * or the original key) and each value is a string representing the chain\r\n * of nested properties leading to that argument.\r\n *\r\n * @function _createNestedProps\r\n *\r\n * @param {Object} config - The configuration object.\r\n * @param {Object} [nestedProps={}] - The accumulator object for storing\r\n * the resulting arguments chains. The default value is an empty object.\r\n * @param {string} [propChain=''] - The current chain of nested properties,\r\n * used internally during recursion. The default value is an empty string.\r\n *\r\n * @returns {Object} An object mapping argument names to their corresponding\r\n * nested property chains.\r\n */\r\nfunction _createNestedProps(config, nestedProps = {}, propChain = '') {\r\n Object.keys(config).forEach((key) => {\r\n // Get the specific section\r\n const entry = config[key];\r\n\r\n // Check if there is still more depth to traverse\r\n if (typeof entry.value === 'undefined') {\r\n // Recurse into deeper levels of nested arguments\r\n _createNestedProps(entry, nestedProps, `${propChain}.${key}`);\r\n } else {\r\n // Create the chain of nested arguments\r\n nestedProps[entry.cliName || key] = `${propChain}.${key}`.substring(1);\r\n\r\n // Support for the legacy, PhantomJS properties names\r\n if (entry.legacyName !== undefined) {\r\n nestedProps[entry.legacyName] = `${propChain}.${key}`.substring(1);\r\n }\r\n }\r\n });\r\n\r\n // Return the object with nested argument chains\r\n return nestedProps;\r\n}\r\n\r\n/**\r\n * Recursively gathers the names of properties from a configuration object that\r\n * should be treated as absolute properties. These properties have values that\r\n * are objects and do not contain further nested depth when merging an object\r\n * containing these options.\r\n *\r\n * @function _createAbsoluteProps\r\n *\r\n * @param {Object} config - The configuration object.\r\n * @param {Array} [absoluteProps=[]] - An array to collect the names\r\n * of absolute properties. The default value is an empty array.\r\n *\r\n * @returns {Array} An array containing the names of absolute\r\n * properties.\r\n */\r\nfunction _createAbsoluteProps(config, absoluteProps = []) {\r\n Object.keys(config).forEach((key) => {\r\n // Get the specific section\r\n const entry = config[key];\r\n\r\n // Check if there is still more depth to traverse\r\n if (typeof entry.types === 'undefined') {\r\n // Recurse into deeper levels\r\n _createAbsoluteProps(entry, absoluteProps);\r\n } else {\r\n // If the option can be an object, save its type in the array\r\n if (entry.types.includes('Object')) {\r\n absoluteProps.push(key);\r\n }\r\n }\r\n });\r\n\r\n // Return the array with the names of absolute properties\r\n return absoluteProps;\r\n}\r\n\r\nexport default {\r\n getOptions,\r\n updateOptions,\r\n setCliOptions,\r\n mapToNewOptions,\r\n validateOption,\r\n validateOptions,\r\n isAllowedConfig\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * @overview HTTP utility module for fetching and posting data. Supports both\r\n * HTTP and HTTPS protocols, providing methods to make GET and POST requests\r\n * with customizable options. Includes protocol determination based on URL\r\n * and augments response objects with a 'text' property for easier data access.\r\n */\r\n\r\nimport http from 'http';\r\nimport https from 'https';\r\n\r\n/**\r\n * Sends a GET request to the specified URL using either HTTP or HTTPS protocol.\r\n *\r\n * @async\r\n * @function get\r\n *\r\n * @param {string} url - The URL to get data from.\r\n * @param {Object} [requestOptions={}] - Options for the HTTP/HTTPS request.\r\n * The default value is an empty object.\r\n *\r\n * @returns {Promise} A Promise that resolves to the HTTP/HTTPS response\r\n * object with added 'text' property or rejecting with an error.\r\n */\r\nexport async function get(url, requestOptions = {}) {\r\n return new Promise((resolve, reject) => {\r\n // Decide on the protocol\r\n _getProtocolModule(url)\r\n .get(url, requestOptions, (response) => {\r\n let responseData = '';\r\n\r\n // A chunk of data has been received\r\n response.on('data', (chunk) => {\r\n responseData += chunk;\r\n });\r\n\r\n // The whole response has been received\r\n response.on('end', () => {\r\n if (!responseData) {\r\n reject('Nothing was fetched from the URL.');\r\n }\r\n\r\n // Get the full result and resolve the request\r\n response.text = responseData;\r\n resolve(response);\r\n });\r\n })\r\n .on('error', (error) => {\r\n reject(error);\r\n });\r\n });\r\n}\r\n\r\n/**\r\n * Sends a POST request to the specified URL with the provided JSON body using\r\n * either HTTP or HTTPS protocol.\r\n *\r\n * @async\r\n * @function post\r\n *\r\n * @param {string} url - The URL to send the POST request to.\r\n * @param {Object} [body={}] - The JSON body to include in the POST request.\r\n * The default value is an empty object.\r\n * @param {Object} [requestOptions={}] - Options for the HTTP/HTTPS request.\r\n * The default value is an empty object.\r\n *\r\n * @returns {Promise} A Promise that resolves to the HTTP/HTTPS response\r\n * object with added 'text' property or rejecting with an error.\r\n */\r\nexport async function post(url, body = {}, requestOptions = {}) {\r\n return new Promise((resolve, reject) => {\r\n const data = JSON.stringify(body);\r\n\r\n // Set default headers and merge with `requestOptions`\r\n const options = Object.assign(\r\n {\r\n method: 'POST',\r\n headers: {\r\n 'Content-Type': 'application/json',\r\n 'Content-Length': data.length\r\n }\r\n },\r\n requestOptions\r\n );\r\n\r\n // Decide on the protocol\r\n const request = _getProtocolModule(url)\r\n .request(url, options, (response) => {\r\n let responseData = '';\r\n\r\n // A chunk of data has been received\r\n response.on('data', (chunk) => {\r\n responseData += chunk;\r\n });\r\n\r\n // The whole response has been received\r\n response.on('end', () => {\r\n try {\r\n // Get the full result and resolve the request\r\n response.text = responseData;\r\n resolve(response);\r\n } catch (error) {\r\n reject(error);\r\n }\r\n });\r\n })\r\n .on('error', (error) => {\r\n reject(error);\r\n });\r\n\r\n // Write the request body and end the request\r\n request.write(data);\r\n request.end();\r\n });\r\n}\r\n\r\n/**\r\n * Returns the HTTP or HTTPS protocol module based on the provided URL.\r\n *\r\n * @function _getProtocolModule\r\n *\r\n * @param {string} url - The URL to determine the protocol.\r\n *\r\n * @returns {Object} The HTTP or HTTPS protocol module (`http` or `https`).\r\n */\r\nfunction _getProtocolModule(url) {\r\n return url.startsWith('https') ? https : http;\r\n}\r\n\r\nexport default {\r\n get,\r\n post\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * @overview The cache manager is responsible for handling and managing\r\n * the Highcharts library along with its dependencies. It ensures that these\r\n * resources are stored and retrieved efficiently to optimize performance\r\n * and reduce redundant network requests. The cache is stored in the `.cache`\r\n * directory by default, which serves as a dedicated folder for keeping cached\r\n * files.\r\n */\r\n\r\nimport { existsSync, mkdirSync, readFileSync, writeFileSync } from 'fs';\r\nimport { join } from 'path';\r\n\r\nimport { HttpsProxyAgent } from 'https-proxy-agent';\r\n\r\nimport { getOptions, updateOptions } from './config.js';\r\nimport { get } from './fetch.js';\r\nimport { log } from './logger.js';\r\nimport { getAbsolutePath } from './utils.js';\r\n\r\nimport ExportError from './errors/ExportError.js';\r\n\r\n// The initial cache template\r\nconst cache = {\r\n cdnUrl: 'https://code.highcharts.com',\r\n activeManifest: {},\r\n sources: '',\r\n hcVersion: ''\r\n};\r\n\r\n/**\r\n * Checks the cache for Highcharts dependencies, updates the cache if needed,\r\n * and loads the sources.\r\n *\r\n * @async\r\n * @function checkCache\r\n *\r\n * @param {Object} highchartsOptions - The configuration object containing\r\n * `highcharts` options.\r\n * @param {Object} serverProxyOptions- The configuration object containing\r\n * `server.proxy` options.\r\n */\r\nexport async function checkCache(highchartsOptions, serverProxyOptions) {\r\n try {\r\n let fetchedModules;\r\n\r\n // Get the cache path\r\n const cachePath = getCachePath();\r\n\r\n // Prepare paths to manifest and sources from the cache folder\r\n const manifestPath = join(cachePath, 'manifest.json');\r\n const sourcePath = join(cachePath, 'sources.js');\r\n\r\n // Create the cache destination if it doesn't exist already\r\n !existsSync(cachePath) && mkdirSync(cachePath, { recursive: true });\r\n\r\n // Fetch all the scripts either if the `manifest.json` does not exist\r\n // or if the `forceFetch` option is enabled\r\n if (!existsSync(manifestPath) || highchartsOptions.forceFetch) {\r\n log(3, '[cache] Fetching and caching Highcharts dependencies.');\r\n\r\n // The initial cache update\r\n fetchedModules = await _updateCache(\r\n highchartsOptions,\r\n serverProxyOptions,\r\n sourcePath\r\n );\r\n } else {\r\n let requestUpdate = false;\r\n\r\n // Read the manifest JSON\r\n const manifest = JSON.parse(readFileSync(manifestPath), 'utf8');\r\n\r\n // Check if the modules is an array, if so, we rewrite it to a map to make\r\n // it easier to resolve modules\r\n if (manifest.modules && Array.isArray(manifest.modules)) {\r\n const moduleMap = {};\r\n manifest.modules.forEach((m) => (moduleMap[m] = 1));\r\n manifest.modules = moduleMap;\r\n }\r\n\r\n // Get the actual number of scripts to be fetched\r\n const { coreScripts, moduleScripts, indicatorScripts } =\r\n highchartsOptions;\r\n const numberOfModules =\r\n coreScripts.length + moduleScripts.length + indicatorScripts.length;\r\n\r\n // Compare the loaded highcharts config with the contents in cache.\r\n // If there are changes, fetch requested modules and products,\r\n // and bake them into a giant blob. Save the blob.\r\n if (manifest.version !== highchartsOptions.version) {\r\n // Check the Highcharts version\r\n log(\r\n 2,\r\n '[cache] A Highcharts version mismatch in the cache, need to re-fetch.'\r\n );\r\n requestUpdate = true;\r\n } else if (\r\n Object.keys(manifest.modules || {}).length !== numberOfModules\r\n ) {\r\n // Check the number of modules\r\n log(\r\n 2,\r\n '[cache] The cache and the requested modules do not match, need to re-fetch.'\r\n );\r\n requestUpdate = true;\r\n } else {\r\n // Check each module, if anything is missing refetch everything\r\n requestUpdate = (moduleScripts || []).some((moduleName) => {\r\n if (!manifest.modules[moduleName]) {\r\n log(\r\n 2,\r\n `[cache] The ${moduleName} is missing in the cache, need to re-fetch.`\r\n );\r\n return true;\r\n }\r\n });\r\n }\r\n\r\n // Update cache if needed\r\n if (requestUpdate) {\r\n fetchedModules = await _updateCache(\r\n highchartsOptions,\r\n serverProxyOptions,\r\n sourcePath\r\n );\r\n } else {\r\n log(3, '[cache] Dependency cache is up to date, proceeding.');\r\n\r\n // Load the sources\r\n cache.sources = readFileSync(sourcePath, 'utf8');\r\n\r\n // Get current modules map\r\n fetchedModules = manifest.modules;\r\n\r\n // Extract and save version of currently used Highcharts\r\n cache.hcVersion = _extractHcVersion(cache.sources);\r\n }\r\n }\r\n\r\n // Finally, save the new manifest, which is basically our current config\r\n // in a slightly different format\r\n await _saveConfigToManifest(highchartsOptions.version, fetchedModules);\r\n } catch (error) {\r\n throw new ExportError(\r\n '[cache] Could not configure cache and create or update the config manifest.',\r\n 500\r\n ).setError(error);\r\n }\r\n}\r\n\r\n/**\r\n * Gets the version of Highcharts from the cache.\r\n *\r\n * @function getHcVersion\r\n *\r\n * @returns {string} The cached Highcharts version.\r\n */\r\nexport function getHcVersion() {\r\n return cache.hcVersion;\r\n}\r\n\r\n/**\r\n * Updates the Highcharts version in the applied configuration and checks\r\n * the cache for the scripts of a new version.\r\n *\r\n * @async\r\n * @function updateHcVersion\r\n *\r\n * @param {string} newVersion - The new Highcharts version to be applied.\r\n */\r\nexport async function updateHcVersion(newVersion) {\r\n // Update to the new version\r\n const options = updateOptions({\r\n highcharts: {\r\n version: newVersion\r\n }\r\n });\r\n\r\n // Check if cache needs to be updated\r\n await checkCache(options.highcharts, options.server.proxy);\r\n}\r\n\r\n/**\r\n * Retrieves the current cache object.\r\n *\r\n * @function getCache\r\n *\r\n * @returns {Object} The cache object containing various cached data.\r\n */\r\nexport function getCache() {\r\n return cache;\r\n}\r\n\r\n/**\r\n * Gets the cache path for Highcharts.\r\n *\r\n * @function getCachePath\r\n *\r\n * @returns {string} The absolute path to the cache directory for Highcharts.\r\n */\r\nexport function getCachePath() {\r\n return getAbsolutePath(getOptions().highcharts.cachePath, 'utf8'); // #562\r\n}\r\n\r\n/**\r\n * Saves the provided configuration and fetched modules to the cache manifest\r\n * file.\r\n *\r\n * @async\r\n * @function _saveConfigToManifest\r\n *\r\n * @param {number} version - The currently used Highcharts version.\r\n * @param {Object} [fetchedModules={}] - An object which tracks which modules\r\n * have been fetched. The default value is an empty object.\r\n *\r\n * @throws {ExportError} Throws an `ExportError` if an error occurs while\r\n * writing the cache manifest.\r\n */\r\nasync function _saveConfigToManifest(version, fetchedModules = {}) {\r\n // Update cache object with the current modules\r\n cache.activeManifest = {\r\n version,\r\n modules: fetchedModules\r\n };\r\n\r\n log(3, '[cache] Writing a new manifest.');\r\n try {\r\n writeFileSync(\r\n join(getCachePath(), 'manifest.json'),\r\n JSON.stringify(cache.activeManifest),\r\n 'utf8'\r\n );\r\n } catch (error) {\r\n throw new ExportError(\r\n '[cache] Error writing the cache manifest.',\r\n 500\r\n ).setError(error);\r\n }\r\n}\r\n\r\n/**\r\n * Updates the local cache with Highcharts scripts content and information,\r\n * and used Highcharts version.\r\n *\r\n * @async\r\n * @function _updateCache\r\n *\r\n * @param {Object} highchartsOptions - The configuration object containing\r\n * `highcharts` options.\r\n * @param {Object} serverProxyOptions - The configuration object containing\r\n * `server.proxy` options.\r\n * @param {string} sourcePath - The path to the source file in the cache.\r\n *\r\n * @returns {Promise} A Promise that resolves to an object representing\r\n * the fetched modules.\r\n *\r\n * @throws {ExportError} Throws an `ExportError` if there is an issue updating\r\n * the local Highcharts cache.\r\n */\r\nasync function _updateCache(highchartsOptions, serverProxyOptions, sourcePath) {\r\n try {\r\n // Get Highcharts version for scripts\r\n const hcVersion =\r\n highchartsOptions.version === 'latest'\r\n ? null\r\n : `${highchartsOptions.version}`;\r\n\r\n log(\r\n 3,\r\n `[cache] Updating cache version to Highcharts: ${hcVersion || 'latest'}.`\r\n );\r\n\r\n // Get the CDN url for scripts\r\n const cdnUrl = highchartsOptions.cdnUrl || cache.cdnUrl;\r\n\r\n // Prepare options for a request\r\n const requestOptions = _configureRequest(serverProxyOptions);\r\n\r\n // An object to record which scripts are fetched\r\n const fetchedModules = {};\r\n\r\n // Join all fetched scripts and save in the manifest's sources\r\n cache.sources = (\r\n await Promise.all([\r\n // Highcharts core scripts fetch\r\n ...highchartsOptions.coreScripts.map((cs) =>\r\n _fetchScript(\r\n hcVersion ? `${cdnUrl}/${hcVersion}/${cs}` : `${cdnUrl}/${cs}`,\r\n requestOptions,\r\n fetchedModules,\r\n true\r\n )\r\n ),\r\n // Highcharts module scripts fetch\r\n ...highchartsOptions.moduleScripts.map((ms) =>\r\n _fetchScript(\r\n ms === 'map'\r\n ? hcVersion\r\n ? `${cdnUrl}/maps/${hcVersion}/modules/${ms}`\r\n : `${cdnUrl}/maps/modules/${ms}`\r\n : hcVersion\r\n ? `${cdnUrl}/${hcVersion}/modules/${ms}`\r\n : `${cdnUrl}/modules/${ms}`,\r\n requestOptions,\r\n fetchedModules\r\n )\r\n ),\r\n // Highcharts indicator scripts fetch\r\n ...highchartsOptions.indicatorScripts.map((is) =>\r\n _fetchScript(\r\n hcVersion\r\n ? `${cdnUrl}/stock/${hcVersion}/indicators/${is}`\r\n : `${cdnUrl}/stock/indicators/${is}`,\r\n requestOptions,\r\n fetchedModules\r\n )\r\n ),\r\n // Custom scripts fetch\r\n ...highchartsOptions.customScripts.map((cs) =>\r\n _fetchScript(`${cs}`, requestOptions)\r\n )\r\n ])\r\n ).join(';\\n');\r\n\r\n // Extract and save version of currently used Highcharts\r\n cache.hcVersion = _extractHcVersion(cache.sources);\r\n\r\n // Save the fetched modules into caches' source JSON\r\n writeFileSync(sourcePath, cache.sources);\r\n\r\n // Return the fetched modules\r\n return fetchedModules;\r\n } catch (error) {\r\n throw new ExportError(\r\n '[cache] Unable to update the local Highcharts cache.',\r\n 500\r\n ).setError(error);\r\n }\r\n}\r\n\r\n/**\r\n * Fetches a single script and updates the `fetchedModules` accordingly.\r\n *\r\n * @async\r\n * @function _fetchScript\r\n *\r\n * @param {string} script - A path to script to get.\r\n * @param {Object} requestOptions - Additional requests options.\r\n * @param {Object} fetchedModules - An object which tracks which Highcharts\r\n * modules have been fetched.\r\n * @param {boolean} [shouldThrowError=false] - A flag to indicate if the error\r\n * should be thrown. This should be used only for the core scripts. The default\r\n * value is `false`.\r\n *\r\n * @returns {Promise} A Promise that resolves to the text representation\r\n * of the fetched script.\r\n *\r\n * @throws {ExportError} Throws an `ExportError` if there is a problem\r\n * with fetching the script.\r\n */\r\nasync function _fetchScript(\r\n script,\r\n requestOptions,\r\n fetchedModules,\r\n shouldThrowError = false\r\n) {\r\n // Get rid of the .js from the custom strings\r\n if (script.endsWith('.js')) {\r\n script = script.substring(0, script.length - 3);\r\n }\r\n log(4, `[cache] Fetching script - ${script}.js`);\r\n\r\n // Fetch the script\r\n const response = await get(`${script}.js`, requestOptions);\r\n\r\n // If OK, return its text representation\r\n if (response.statusCode === 200 && typeof response.text == 'string') {\r\n if (fetchedModules) {\r\n const moduleName = _extractModuleName(script);\r\n fetchedModules[moduleName] = 1;\r\n }\r\n return response.text;\r\n }\r\n\r\n // Based on the `shouldThrowError` flag, decide how to serve error message\r\n if (shouldThrowError) {\r\n throw new ExportError(\r\n `[cache] Could not fetch the ${script}.js. The script might not exist in the requested version (status code: ${response.statusCode}).`,\r\n 404\r\n ).setError(response);\r\n } else {\r\n log(\r\n 2,\r\n `[cache] Could not fetch the ${script}.js. The script might not exist in the requested version.`\r\n );\r\n }\r\n}\r\n\r\n/**\r\n * Configures a proxy agent for outgoing HTTP requests based on the provided\r\n * `server.proxy` options. If a valid `host` and `port` are specified, it tries\r\n * to create an `HttpsProxyAgent`. If the creation fails, an `ExportError`\r\n * is thrown. If no proxy is configured, an empty object is returned.\r\n *\r\n * @function _configureRequest\r\n *\r\n * @param {Object} serverProxyOptions- The configuration object containing\r\n * `server.proxy` options.\r\n *\r\n * @returns {Object} The request options, including the proxy agent if created,\r\n * or an empty object if no proxy configuration is provided.\r\n *\r\n * @throws {ExportError} Throws an `ExportError` if the proxy agent creation\r\n * fails.\r\n */\r\nfunction _configureRequest(serverProxyOptions) {\r\n // Get the `host` and `port` of the proxy\r\n const proxyHost = serverProxyOptions.host;\r\n const proxyPort = serverProxyOptions.port;\r\n\r\n // Try to create a proxy agent\r\n if (proxyHost && proxyPort) {\r\n try {\r\n // Create the agent\r\n const proxyAgent = new HttpsProxyAgent({\r\n host: proxyHost,\r\n port: proxyPort\r\n });\r\n\r\n // Add the agent to the request's options\r\n return {\r\n agent: proxyAgent,\r\n timeout: serverProxyOptions.timeout\r\n };\r\n } catch (error) {\r\n throw new ExportError(\r\n '[cache] Could not create a Proxy Agent.',\r\n 500\r\n ).setError(error);\r\n }\r\n }\r\n\r\n // Return an empty object when no proxy agent is created\r\n return {};\r\n}\r\n\r\n/**\r\n * Extracts Highcharts version from the cache's sources string.\r\n *\r\n * @function _extractHcVersion\r\n *\r\n * @param {Object} cacheSources - The cache sources object.\r\n *\r\n * @returns {string} The extracted Highcharts version.\r\n */\r\nfunction _extractHcVersion(cacheSources) {\r\n return cacheSources\r\n .substring(0, cacheSources.indexOf('*/'))\r\n .replace('/*', '')\r\n .replace('*/', '')\r\n .replace(/\\n/g, '')\r\n .trim();\r\n}\r\n\r\n/**\r\n * Extracts the Highcharts module name based on the `scriptPath` property.\r\n *\r\n * @function _extractModuleName\r\n *\r\n * @param {string} scriptPath - The path of the script from which the module\r\n * name will be extracted.\r\n *\r\n * @returns {string} The extracted module name.\r\n */\r\nfunction _extractModuleName(scriptPath) {\r\n return scriptPath.replace(\r\n /(.*)\\/|(.*)modules\\/|stock\\/(.*)indicators\\/|maps\\/(.*)modules\\//gi,\r\n ''\r\n );\r\n}\r\n\r\nexport default {\r\n checkCache,\r\n getHcVersion,\r\n updateHcVersion,\r\n getCache,\r\n getCachePath\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * @overview Provides methods for initializing Highcharts with customized\r\n * animation settings and triggering the creation of Highcharts charts with\r\n * export-specific configurations in the page context. Supports dynamic option\r\n * merging, custom logic injection, and control over rendering behaviors. Used\r\n * by the Puppeteer page.\r\n */\r\n\r\n/* eslint-disable no-undef */\r\n\r\n/**\r\n * Setting the `Highcharts.animObject` function. Called when initing the page.\r\n *\r\n * @function setupHighcharts\r\n */\r\nexport function setupHighcharts() {\r\n Highcharts.animObject = function () {\r\n return { duration: 0 };\r\n };\r\n}\r\n\r\n/**\r\n * Creates the actual Highcharts chart on a page.\r\n *\r\n * @async\r\n * @function createChart\r\n *\r\n * @param {Object} exportOptions - The configuration object containing `export`\r\n * options.\r\n * @param {Object} customLogicOptions - The configuration object containing\r\n * `customLogic` options.\r\n *\r\n */\r\nexport async function createChart(exportOptions, customLogicOptions) {\r\n // Get required functions\r\n const { getOptions, setOptions, merge, wrap } = Highcharts;\r\n\r\n // Create a separate object for a potential `setOptions` usages in order\r\n // to prevent from polluting other exports that can happen on the same page\r\n Highcharts.setOptionsObj = merge(false, {}, getOptions());\r\n\r\n // NOTE: Is this used for anything useful?\r\n window.isRenderComplete = false;\r\n wrap(Highcharts.Chart.prototype, 'init', function (proceed, userOptions, cb) {\r\n // Override the `userOptions` with image friendly options\r\n userOptions = merge(userOptions, {\r\n exporting: {\r\n enabled: false\r\n },\r\n plotOptions: {\r\n series: {\r\n label: {\r\n enabled: false\r\n }\r\n }\r\n },\r\n /* Expects tooltip in the `userOptions` when `forExport` is true.\r\n https://github.com/highcharts/highcharts/blob/3ad430a353b8056b9e764aa4e5cd6828aa479db2/js/parts/Chart.js#L241\r\n */\r\n tooltip: {}\r\n });\r\n\r\n (userOptions.series || []).forEach(function (series) {\r\n series.animation = false;\r\n });\r\n\r\n // Add flag to know if chart render has been called.\r\n if (!window.onHighchartsRender) {\r\n window.onHighchartsRender = Highcharts.addEvent(this, 'render', () => {\r\n window.isRenderComplete = true;\r\n });\r\n }\r\n\r\n proceed.apply(this, [userOptions, cb]);\r\n });\r\n\r\n wrap(Highcharts.Series.prototype, 'init', function (proceed, chart, options) {\r\n proceed.apply(this, [chart, options]);\r\n });\r\n\r\n // Some mandatory additional `chart` and `exporting` options\r\n const additionalOptions = {\r\n chart: {\r\n // By default animation is disabled\r\n animation: false,\r\n // Get the right size values\r\n height: exportOptions.height,\r\n width: exportOptions.width\r\n },\r\n exporting: {\r\n // No need for the exporting button\r\n enabled: false\r\n }\r\n };\r\n\r\n // Get the input to export from the `instr` option\r\n const userOptions = new Function(`return ${exportOptions.instr}`)();\r\n\r\n // Get the `themeOptions` option\r\n const themeOptions = new Function(`return ${exportOptions.themeOptions}`)();\r\n\r\n // Merge the following options objects to create final options\r\n const finalOptions = merge(\r\n false,\r\n themeOptions,\r\n userOptions,\r\n // Placed it here instead in the init because of the size issues\r\n additionalOptions\r\n );\r\n\r\n // Prepare the `callback` option\r\n const finalCallback = customLogicOptions.callback\r\n ? new Function(`return ${customLogicOptions.callback}`)()\r\n : null;\r\n\r\n // Trigger the `customCode` option\r\n if (customLogicOptions.customCode) {\r\n new Function('options', customLogicOptions.customCode)(userOptions);\r\n }\r\n\r\n // Get the `globalOptions` option\r\n const globalOptions = new Function(`return ${exportOptions.globalOptions}`)();\r\n\r\n // Set the global options if exist\r\n if (globalOptions) {\r\n setOptions(globalOptions);\r\n }\r\n\r\n // Call the chart creation\r\n Highcharts[exportOptions.constr]('container', finalOptions, finalCallback);\r\n\r\n // Get all images from within the chart\r\n const images = Array.from(\r\n document.querySelectorAll('.highcharts-container image')\r\n );\r\n\r\n // Wait for all images for 2 seconds\r\n await Promise.race([\r\n Promise.all(\r\n images.map((image) =>\r\n image.complete && image.naturalHeight !== 0\r\n ? Promise.resolve()\r\n : new Promise((resolve) =>\r\n image.addEventListener('load', resolve, { once: true })\r\n )\r\n )\r\n ),\r\n // Proceed further even if images did not load\r\n new Promise((resolve) => setTimeout(resolve, 2000))\r\n ]);\r\n\r\n // Get the current global options\r\n const defaultOptions = getOptions();\r\n\r\n // Clear it just in case (e.g. the `setOptions` was used in the `customCode`)\r\n for (const prop in defaultOptions) {\r\n if (typeof defaultOptions[prop] !== 'function') {\r\n delete defaultOptions[prop];\r\n }\r\n }\r\n\r\n // Set the default options back\r\n setOptions(Highcharts.setOptionsObj);\r\n\r\n // Empty the custom global options object\r\n Highcharts.setOptionsObj = {};\r\n}\r\n\r\nexport default {\r\n setupHighcharts,\r\n createChart\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * @overview This module provides functions for managing Puppeteer browser\r\n * instance, creating and clearing pages, injecting custom JS and CSS resources,\r\n * and setting up Highcharts for server-side rendering. The module ensures\r\n * that the browser and pages are correctly managed and can handle failures\r\n * during operations like launching the browser or creating new pages.\r\n */\r\n\r\nimport { readFileSync } from 'fs';\r\nimport { join } from 'path';\r\n\r\nimport puppeteer from 'puppeteer';\r\n\r\nimport { getCachePath } from './cache.js';\r\nimport { getOptions } from './config.js';\r\nimport { setupHighcharts } from './highcharts.js';\r\nimport { log, logWithStack } from './logger.js';\r\nimport { __dirname, getAbsolutePath } from './utils.js';\r\n\r\nimport ExportError from './errors/ExportError.js';\r\n\r\n// Get the template for pages\r\nconst pageTemplate = readFileSync(\r\n join(__dirname, 'templates', 'template.html'),\r\n 'utf8'\r\n);\r\n\r\n// To save the browser\r\nlet browser = null;\r\n\r\n/**\r\n * Retrieves the existing Puppeteer browser instance.\r\n *\r\n * @function getBrowser\r\n *\r\n * @returns {Object} The Puppeteer browser instance.\r\n *\r\n * @throws {ExportError} Throws an `ExportError` if no valid browser\r\n * has been created.\r\n */\r\nexport function getBrowser() {\r\n if (!browser) {\r\n throw new ExportError('[browser] No valid browser has been created.', 500);\r\n }\r\n return browser;\r\n}\r\n\r\n/**\r\n * Creates a Puppeteer browser instance with the specified arguments.\r\n *\r\n * @async\r\n * @function createBrowser\r\n *\r\n * @param {Array} puppeteerArgs - Additional arguments for Puppeteer\r\n * browser's launch.\r\n *\r\n * @returns {Promise} A Promise that resolves to the created Puppeteer\r\n * browser instance.\r\n *\r\n * @throws {ExportError} Throws an `ExportError` if max retries to open\r\n * a browser instance are reached, or if no browser instance is found after\r\n * retries.\r\n */\r\nexport async function createBrowser(puppeteerArgs) {\r\n // Get `debug` and `other` options\r\n const { debug, other } = getOptions();\r\n\r\n // Get the `debug` options\r\n const { enable: enabledDebug, ...debugOptions } = debug;\r\n\r\n // Launch options for the browser instance\r\n const launchOptions = {\r\n headless: other.browserShellMode ? 'shell' : true,\r\n userDataDir: 'tmp',\r\n args: puppeteerArgs || [],\r\n handleSIGINT: false,\r\n handleSIGTERM: false,\r\n handleSIGHUP: false,\r\n waitForInitialPage: false,\r\n defaultViewport: null,\r\n ...(enabledDebug && debugOptions)\r\n };\r\n\r\n // Create a browser\r\n if (!browser) {\r\n // A counter for the browser's launch retries\r\n let tryCount = 0;\r\n const openBrowser = async () => {\r\n try {\r\n log(\r\n 3,\r\n `[browser] Attempting to launch and get a browser instance (try ${++tryCount}).`\r\n );\r\n\r\n // Launch the browser\r\n browser = await puppeteer.launch(launchOptions);\r\n } catch (error) {\r\n logWithStack(\r\n 1,\r\n error,\r\n '[browser] Failed to launch a browser instance.'\r\n );\r\n\r\n // Retry to launch browser until reaching max attempts\r\n if (tryCount < 25) {\r\n log(3, `[browser] Retry to open a browser (${tryCount} out of 25).`);\r\n\r\n // Wait for a 4 seconds before trying again\r\n await new Promise((response) => setTimeout(response, 4000));\r\n await openBrowser();\r\n } else {\r\n throw error;\r\n }\r\n }\r\n };\r\n\r\n try {\r\n // Try to open a browser\r\n await openBrowser();\r\n\r\n // Shell mode inform\r\n if (launchOptions.headless === 'shell') {\r\n log(3, `[browser] Launched browser in shell mode.`);\r\n }\r\n\r\n // Debug mode inform\r\n if (enabledDebug) {\r\n log(3, `[browser] Launched browser in debug mode.`);\r\n }\r\n } catch (error) {\r\n throw new ExportError(\r\n '[browser] Maximum retries to open a browser instance reached.',\r\n 500\r\n ).setError(error);\r\n }\r\n\r\n // No correct browser\r\n if (!browser) {\r\n throw new ExportError('[browser] Cannot find a browser to open.', 500);\r\n }\r\n }\r\n\r\n // Return a browser instance\r\n return browser;\r\n}\r\n\r\n/**\r\n * Closes the Puppeteer browser instance if it is connected.\r\n *\r\n * @async\r\n * @function closeBrowser\r\n */\r\nexport async function closeBrowser() {\r\n // Close the browser when connected\r\n if (browser && browser.connected) {\r\n await browser.close();\r\n }\r\n browser = null;\r\n log(4, '[browser] Closed the browser.');\r\n}\r\n\r\n/**\r\n * Creates a new Puppeteer page within an existing browser instance.\r\n * The function creates a new page, disables caching, sets content using\r\n * the `_setPageContent()`, and returns the created Puppeteer page.\r\n *\r\n * @async\r\n * @function newPage\r\n *\r\n * @param {Object} poolResource - The pool resource that contains `id`,\r\n * `workCount`, and `page`.\r\n *\r\n * @throws {ExportError} Throws an `ExportError` if no valid browser\r\n * has been connected or if a page is invalid or closed.\r\n */\r\nexport async function newPage(poolResource) {\r\n // Error in case of no connected browser\r\n if (!browser || !browser.connected) {\r\n throw new ExportError(`[browser] Browser is not yet connected.`, 500);\r\n }\r\n\r\n // Create a page\r\n poolResource.page = await browser.newPage();\r\n\r\n // Disable cache\r\n await poolResource.page.setCacheEnabled(false);\r\n\r\n // Set the content\r\n await _setPageContent(poolResource.page);\r\n\r\n // Set page events\r\n _setPageEvents(poolResource.page);\r\n\r\n // Check if the page is correctly created\r\n if (!poolResource.page || poolResource.page.isClosed()) {\r\n throw new ExportError('[browser] The page is invalid or closed.', 400);\r\n }\r\n}\r\n\r\n/**\r\n * Clears the content of a Puppeteer page based on the specified mode. Logs\r\n * thrown error if clearing of a page's content fails.\r\n *\r\n * @async\r\n * @function clearPage\r\n *\r\n * @param {Object} poolResource - The pool resource that contains page and id.\r\n * @param {boolean} [hardReset=false] - A flag indicating the type of clearing\r\n * to be performed. If `true`, navigates to `about:blank` and resets content\r\n * and scripts. If `false`, clears the body content by setting a predefined HTML\r\n * structure. The default value is `false`.\r\n *\r\n * @returns {Promise} A Promise that resolves to `true` when page\r\n * is correctly cleared and `false` when it is not.\r\n */\r\nexport async function clearPage(poolResource, hardReset = false) {\r\n try {\r\n if (poolResource.page && !poolResource.page.isClosed()) {\r\n if (hardReset) {\r\n // Navigate to `about:blank`\r\n await poolResource.page.goto('about:blank', {\r\n waitUntil: 'domcontentloaded'\r\n });\r\n\r\n // Set the content and and scripts again\r\n await _setPageContent(poolResource.page);\r\n } else {\r\n // Clear body content\r\n await poolResource.page.evaluate(() => {\r\n document.body.innerHTML =\r\n '
';\r\n });\r\n }\r\n return true;\r\n }\r\n } catch (error) {\r\n logWithStack(\r\n 2,\r\n error,\r\n `[pool] Pool resource [${poolResource.id}] - Content of the page could not be cleared.`\r\n );\r\n\r\n // Set the `workLimit` to exceeded in order to recreate the resource\r\n poolResource.workCount = getOptions().pool.workLimit + 1;\r\n }\r\n return false;\r\n}\r\n\r\n/**\r\n * Adds custom JS and CSS resources to a Puppeteer page based on the specified\r\n * options.\r\n *\r\n * @async\r\n * @function addPageResources\r\n *\r\n * @param {Object} page - The Puppeteer page object to which resources will\r\n * be added.\r\n * @param {Object} customLogicOptions - The configuration object containing\r\n * `customLogic` options.\r\n *\r\n * @returns {Promise>} A Promise that resolves to an array\r\n * of injected resources.\r\n */\r\nexport async function addPageResources(page, customLogicOptions) {\r\n // Injected resources array\r\n const injectedResources = [];\r\n\r\n // Use the content of the `resources`\r\n const resources = customLogicOptions.resources;\r\n if (resources) {\r\n const injectedJs = [];\r\n\r\n // Load custom JS code\r\n if (resources.js) {\r\n injectedJs.push({\r\n content: resources.js\r\n });\r\n }\r\n\r\n // Load scripts from all custom files\r\n if (resources.files) {\r\n for (const file of resources.files) {\r\n const isLocal = file.startsWith('http') ? false : true;\r\n\r\n // Add each custom script from resources' files\r\n injectedJs.push(\r\n isLocal\r\n ? {\r\n content: readFileSync(getAbsolutePath(file), 'utf8')\r\n }\r\n : {\r\n url: file\r\n }\r\n );\r\n }\r\n }\r\n\r\n // The actual injection of collected scripts\r\n for (const jsResource of injectedJs) {\r\n try {\r\n injectedResources.push(await page.addScriptTag(jsResource));\r\n } catch (error) {\r\n logWithStack(2, error, `[browser] The JS resource cannot be loaded.`);\r\n }\r\n }\r\n injectedJs.length = 0;\r\n\r\n // Load CSS\r\n const injectedCss = [];\r\n if (resources.css) {\r\n const cssImports = resources.css.match(/@import\\s*([^;]*);/g);\r\n if (cssImports) {\r\n // Handle css section\r\n for (let cssImportPath of cssImports) {\r\n if (cssImportPath) {\r\n cssImportPath = cssImportPath\r\n .replace('url(', '')\r\n .replace('@import', '')\r\n .replace(/\"/g, '')\r\n .replace(/'/g, '')\r\n .replace(/;/, '')\r\n .replace(/\\)/g, '')\r\n .trim();\r\n\r\n // Add each custom css from resources\r\n if (cssImportPath.startsWith('http')) {\r\n injectedCss.push({\r\n url: cssImportPath\r\n });\r\n } else if (customLogicOptions.allowFileResources) {\r\n injectedCss.push({\r\n path: getAbsolutePath(cssImportPath)\r\n });\r\n }\r\n }\r\n }\r\n }\r\n\r\n // The rest of the CSS section will be content by now\r\n injectedCss.push({\r\n content: resources.css.replace(/@import\\s*([^;]*);/g, '') || ' '\r\n });\r\n\r\n // The actual injection of collected CSS\r\n for (const cssResource of injectedCss) {\r\n try {\r\n injectedResources.push(await page.addStyleTag(cssResource));\r\n } catch (error) {\r\n logWithStack(\r\n 2,\r\n error,\r\n `[browser] The CSS resource cannot be loaded.`\r\n );\r\n }\r\n }\r\n injectedCss.length = 0;\r\n }\r\n }\r\n return injectedResources;\r\n}\r\n\r\n/**\r\n * Clears out all state set on the page with `addScriptTag` and `addStyleTag`.\r\n * Removes injected resources and resets CSS and script tags on the page.\r\n * Additionally, it destroys previously existing charts.\r\n *\r\n * @async\r\n * @function clearPageResources\r\n *\r\n * @param {Object} page - The Puppeteer page object from which resources will\r\n * be cleared.\r\n * @param {Array} injectedResources - Array of injected resources\r\n * to be cleared.\r\n */\r\nexport async function clearPageResources(page, injectedResources) {\r\n try {\r\n for (const resource of injectedResources) {\r\n await resource.dispose();\r\n }\r\n\r\n // Destroy old charts after export is done and reset all CSS and script tags\r\n await page.evaluate(() => {\r\n // We are not guaranteed that Highcharts is loaded, when doing SVG exports\r\n if (typeof Highcharts !== 'undefined') {\r\n // eslint-disable-next-line no-undef\r\n const oldCharts = Highcharts.charts;\r\n\r\n // Check in any already existing charts\r\n if (Array.isArray(oldCharts) && oldCharts.length) {\r\n // Destroy old charts\r\n for (const oldChart of oldCharts) {\r\n oldChart && oldChart.destroy();\r\n // eslint-disable-next-line no-undef\r\n Highcharts.charts.shift();\r\n }\r\n }\r\n }\r\n\r\n // eslint-disable-next-line no-undef\r\n const [...scriptsToRemove] = document.getElementsByTagName('script');\r\n // eslint-disable-next-line no-undef\r\n const [, ...stylesToRemove] = document.getElementsByTagName('style');\r\n // eslint-disable-next-line no-undef\r\n const [...linksToRemove] = document.getElementsByTagName('link');\r\n\r\n // Remove tags\r\n for (const element of [\r\n ...scriptsToRemove,\r\n ...stylesToRemove,\r\n ...linksToRemove\r\n ]) {\r\n element.remove();\r\n }\r\n });\r\n } catch (error) {\r\n logWithStack(2, error, `[browser] Could not clear page's resources.`);\r\n }\r\n}\r\n\r\n/**\r\n * Sets the content for a Puppeteer page using a predefined template\r\n * and additional scripts.\r\n *\r\n * @async\r\n * @function _setPageContent\r\n *\r\n * @param {Object} page - The Puppeteer page object to which the content\r\n * is being set.\r\n */\r\nasync function _setPageContent(page) {\r\n // Set the initial page content\r\n await page.setContent(pageTemplate, { waitUntil: 'domcontentloaded' });\r\n\r\n // Add all registered Higcharts scripts, quite demanding\r\n await page.addScriptTag({ path: join(getCachePath(), 'sources.js') });\r\n\r\n // Set the initial `animObject` for Highcharts\r\n await page.evaluate(setupHighcharts);\r\n}\r\n\r\n/**\r\n * Set events (like `pageerror` and `console`) for a Puppeteer page in order\r\n * to catch and display errors and console logs from the window context.\r\n *\r\n * @function _setPageEvents\r\n *\r\n * @param {Object} page - The Puppeteer page object to which the listeners\r\n * are being set.\r\n */\r\nfunction _setPageEvents(page) {\r\n // Get `debug` options\r\n const { debug } = getOptions();\r\n\r\n // Set the `pageerror` listener\r\n page.on('pageerror', async () => {\r\n // It would seem like this may fire at the same time or shortly before\r\n // a page is closed.\r\n if (page.isClosed()) {\r\n return;\r\n }\r\n });\r\n\r\n // Set the `console` listener, if needed\r\n if (debug.enable && debug.listenToConsole) {\r\n page.on('console', (message) => {\r\n console.log(`[debug] ${message.text()}`);\r\n });\r\n }\r\n}\r\n\r\nexport default {\r\n getBrowser,\r\n createBrowser,\r\n closeBrowser,\r\n newPage,\r\n clearPage,\r\n addPageResources,\r\n clearPageResources\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * The CSS to be used on the exported page.\r\n *\r\n * @returns {string} The CSS configuration.\r\n */\r\nexport default () => `\r\n\r\nhtml, body {\r\n margin: 0;\r\n padding: 0;\r\n box-sizing: border-box;\r\n}\r\n\r\n#table-div, #sliders, #datatable, #controls, .ld-row {\r\n display: none;\r\n height: 0;\r\n}\r\n\r\n#chart-container {\r\n box-sizing: border-box;\r\n margin: 0;\r\n overflow: auto;\r\n font-size: 0;\r\n}\r\n\r\n#chart-container > figure, div {\r\n margin-top: 0 !important;\r\n margin-bottom: 0 !important;\r\n}\r\n\r\n`;\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\nimport cssTemplate from './css.js';\r\n\r\n/**\r\n * The SVG template to use when loading SVG content to be exported.\r\n *\r\n * @param {string} svg - The SVG input content to be exported.\r\n *\r\n * @returns {string} The SVG template.\r\n */\r\nexport default (svg) => `\r\n\r\n\r\n \r\n \r\n Highcharts Export\r\n \r\n \r\n \r\n
\r\n ${svg}\r\n
\r\n \r\n\r\n\r\n`;\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * @overview This module handles chart export functionality using Puppeteer.\r\n * It supports exporting charts as SVG, PNG, JPEG, and PDF formats. The module\r\n * manages page resources, sets up the export environment, and processes chart\r\n * configurations or SVG inputs for rendering. Exports to a chart from a page\r\n * using Puppeteer.\r\n */\r\n\r\nimport { addPageResources, clearPageResources } from './browser.js';\r\nimport { createChart } from './highcharts.js';\r\nimport { log } from './logger.js';\r\n\r\nimport svgTemplate from '../templates/svgExport/svgExport.js';\r\n\r\nimport ExportError from './errors/ExportError.js';\r\n\r\n/**\r\n * Exports to a chart from a page using Puppeteer.\r\n *\r\n * @async\r\n * @function puppeteerExport\r\n *\r\n * @param {Object} page - Puppeteer page object.\r\n * @param {Object} exportOptions - The configuration object containing `export`\r\n * options.\r\n * @param {Object} customLogicOptions - The configuration object containing\r\n * `customLogic` options.\r\n *\r\n * @returns {Promise<(string|Buffer|ExportError)>} A Promise that resolves\r\n * to the exported data or rejecting with an `ExportError`.\r\n *\r\n * @throws {ExportError} Throws an `ExportError` if export to an unsupported\r\n * output format occurs.\r\n */\r\nexport async function puppeteerExport(page, exportOptions, customLogicOptions) {\r\n // Injected resources array (additional JS and CSS)\r\n const injectedResources = [];\r\n\r\n try {\r\n let isSVG = false;\r\n\r\n // Decide on the export method\r\n if (exportOptions.svg) {\r\n log(4, '[export] Treating as SVG input.');\r\n\r\n // If the `type` is also SVG, return the input\r\n if (exportOptions.type === 'svg') {\r\n return exportOptions.svg;\r\n }\r\n\r\n // Mark as SVG export for the later size corrections\r\n isSVG = true;\r\n\r\n // SVG export\r\n await page.setContent(svgTemplate(exportOptions.svg), {\r\n waitUntil: 'domcontentloaded'\r\n });\r\n } else {\r\n log(4, '[export] Treating as JSON config.');\r\n\r\n // Options export\r\n await page.evaluate(createChart, exportOptions, customLogicOptions);\r\n }\r\n\r\n // Keeps track of all resources added on the page with addXXXTag. etc\r\n // It's VITAL that all added resources ends up here so we can clear things\r\n // out when doing a new export in the same page!\r\n injectedResources.push(\r\n ...(await addPageResources(page, customLogicOptions))\r\n );\r\n\r\n // Get the real chart size and set the zoom accordingly\r\n const size = await _getChartSize(page, isSVG, exportOptions.scale);\r\n\r\n // Get the clip region for the page\r\n const { x, y } = await _getClipRegion(page);\r\n\r\n // Set final `height` for viewport\r\n const viewportHeight = Math.abs(\r\n Math.ceil(size.chartHeight || exportOptions.height)\r\n );\r\n\r\n // Set final `width` for viewport\r\n const viewportWidth = Math.abs(\r\n Math.ceil(size.chartWidth || exportOptions.width)\r\n );\r\n\r\n // Set the final viewport now that we have the real height\r\n await page.setViewport({\r\n height: viewportHeight,\r\n width: viewportWidth,\r\n deviceScaleFactor: isSVG ? 1 : parseFloat(exportOptions.scale)\r\n });\r\n\r\n let result;\r\n // Rasterization process\r\n switch (exportOptions.type) {\r\n case 'svg':\r\n result = await _createSVG(page);\r\n break;\r\n case 'png':\r\n case 'jpeg':\r\n result = await _createImage(\r\n page,\r\n exportOptions.type,\r\n {\r\n width: viewportWidth,\r\n height: viewportHeight,\r\n x,\r\n y\r\n },\r\n exportOptions.rasterizationTimeout\r\n );\r\n break;\r\n case 'pdf':\r\n result = await _createPDF(\r\n page,\r\n viewportHeight,\r\n viewportWidth,\r\n exportOptions.rasterizationTimeout\r\n );\r\n break;\r\n default:\r\n throw new ExportError(\r\n `[export] Unsupported output format: ${exportOptions.type}.`,\r\n 400\r\n );\r\n }\r\n\r\n // Clear previously injected JS and CSS resources\r\n await clearPageResources(page, injectedResources);\r\n return result;\r\n } catch (error) {\r\n await clearPageResources(page, injectedResources);\r\n return error;\r\n }\r\n}\r\n\r\n/**\r\n * Retrieves the clipping region coordinates of the specified page element\r\n * with the 'chart-container' id.\r\n *\r\n * @async\r\n * @function _getClipRegion\r\n *\r\n * @param {Object} page - Puppeteer page object.\r\n *\r\n * @returns {Promise} A Promise that resolves to an object containing\r\n * `x`, `y`, `width`, and `height` properties.\r\n */\r\nasync function _getClipRegion(page) {\r\n return page.$eval('#chart-container', (element) => {\r\n const { x, y, width, height } = element.getBoundingClientRect();\r\n return {\r\n x,\r\n y,\r\n width,\r\n height: Math.trunc(height > 1 ? height : 500)\r\n };\r\n });\r\n}\r\n\r\n/**\r\n * Retrieves the real chart dimensions from a Puppeteer page. The function\r\n * behaves differently based on whether the export type is SVG or another\r\n * format.\r\n *\r\n * @async\r\n * @function _getChartSize\r\n *\r\n * @param {Object} page - Puppeteer page object.\r\n * @param {boolean} isSVG - Determines whether the chart being processed\r\n * is an SVG or another format.\r\n * @param {number} scale - The scale factor to be applied to the chart\r\n * dimensions.\r\n *\r\n * @returns {Promise} A Promise that resolves to an object containing\r\n * the actual height and width of the chart after scaling.\r\n */\r\nasync function _getChartSize(page, isSVG, scale) {\r\n // Trigger appropriate function based on the `isSvg` flag to get chart size\r\n return isSVG\r\n ? await page.evaluate((scale) => {\r\n const svgElement = document.querySelector(\r\n '#chart-container svg:first-of-type'\r\n );\r\n\r\n // Get the values correctly scaled\r\n const chartHeight = svgElement.height.baseVal.value * scale;\r\n const chartWidth = svgElement.width.baseVal.value * scale;\r\n\r\n // In case of SVG the zoom must be set directly for body as scale\r\n // eslint-disable-next-line no-undef\r\n document.body.style.zoom = scale;\r\n\r\n // Set the margin to 0px\r\n // eslint-disable-next-line no-undef\r\n document.body.style.margin = '0px';\r\n\r\n return {\r\n chartHeight,\r\n chartWidth\r\n };\r\n }, parseFloat(scale))\r\n : await page.evaluate(() => {\r\n // eslint-disable-next-line no-undef\r\n const { chartHeight, chartWidth } = window.Highcharts.charts[0];\r\n\r\n // No need for such scale manipulation in case of other types\r\n // of exports. Reset the zoom for other exports than to SVGs\r\n // eslint-disable-next-line no-undef\r\n document.body.style.zoom = 1;\r\n\r\n return {\r\n chartHeight,\r\n chartWidth\r\n };\r\n });\r\n}\r\n\r\n/**\r\n * Creates an SVG by evaluating the `outerHTML` of the first 'svg' element\r\n * inside an element with the id 'container'.\r\n *\r\n * @async\r\n * @function _createSVG\r\n *\r\n * @param {Object} page - Puppeteer page object.\r\n *\r\n * @returns {Promise} A Promise that resolves to the SVG string.\r\n */\r\nasync function _createSVG(page) {\r\n return page.$eval(\r\n '#container svg:first-of-type',\r\n (element) => element.outerHTML\r\n );\r\n}\r\n\r\n/**\r\n * Creates an image using Puppeteer's page `screenshot` functionality with\r\n * specified options.\r\n *\r\n * @async\r\n * @function _createImage\r\n *\r\n * @param {Object} page - Puppeteer page object.\r\n * @param {string} type - Image type.\r\n * @param {Object} clip - Clipping region coordinates.\r\n * @param {number} rasterizationTimeout - Timeout for rasterization\r\n * in milliseconds.\r\n *\r\n * @returns {Promise} A Promise that resolves to the image buffer\r\n * or rejecting with an `ExportError` for timeout.\r\n */\r\nasync function _createImage(page, type, clip, rasterizationTimeout) {\r\n return Promise.race([\r\n page.screenshot({\r\n type,\r\n clip,\r\n encoding: 'base64',\r\n fullPage: false,\r\n optimizeForSpeed: true,\r\n captureBeyondViewport: true,\r\n ...(type !== 'png' ? { quality: 80 } : {}),\r\n // Always render on a transparent page if the expected type format is PNG\r\n omitBackground: type == 'png' // #447, #463\r\n }),\r\n new Promise((_resolve, reject) =>\r\n setTimeout(\r\n () => reject(new ExportError('Rasterization timeout', 408)),\r\n rasterizationTimeout || 1500\r\n )\r\n )\r\n ]);\r\n}\r\n\r\n/**\r\n * Creates a PDF using Puppeteer's page `pdf` functionality with specified\r\n * options.\r\n *\r\n * @async\r\n * @function _createPDF\r\n *\r\n * @param {Object} page - Puppeteer page object.\r\n * @param {number} height - PDF height.\r\n * @param {number} width - PDF width.\r\n * @param {number} rasterizationTimeout - Timeout for rasterization\r\n * in milliseconds.\r\n *\r\n * @returns {Promise} A Promise that resolves to the PDF buffer.\r\n */\r\nasync function _createPDF(page, height, width, rasterizationTimeout) {\r\n await page.emulateMediaType('screen');\r\n return page.pdf({\r\n // This will remove an extra empty page in PDF exports\r\n height: height + 1,\r\n width,\r\n encoding: 'base64',\r\n timeout: rasterizationTimeout || 1500\r\n });\r\n}\r\n\r\nexport default {\r\n puppeteerExport\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * @overview This module provides a worker pool implementation for managing\r\n * the browser instance and pages, specifically designed for use with\r\n * the Highcharts Export Server. It optimizes resources usage and performance\r\n * by maintaining a pool of workers that can handle concurrent export tasks\r\n * using Puppeteer.\r\n */\r\n\r\nimport { Pool } from 'tarn';\r\nimport { v4 as uuid } from 'uuid';\r\n\r\nimport { clearPage, createBrowser, closeBrowser, newPage } from './browser.js';\r\nimport { puppeteerExport } from './export.js';\r\nimport { log, logWithStack } from './logger.js';\r\nimport { getNewDateTime, measureTime } from './utils.js';\r\n\r\nimport ExportError from './errors/ExportError.js';\r\n\r\n// The pool instance\r\nlet pool = null;\r\n\r\n// Pool statistics\r\nconst poolStats = {\r\n exportsAttempted: 0,\r\n exportsPerformed: 0,\r\n exportsDropped: 0,\r\n exportsFromSvg: 0,\r\n exportsFromOptions: 0,\r\n exportsFromSvgAttempts: 0,\r\n exportsFromOptionsAttempts: 0,\r\n timeSpent: 0,\r\n timeSpentAverage: 0\r\n};\r\n\r\n/**\r\n * Initializes the export pool with the provided configuration, creating\r\n * a browser instance and setting up worker resources.\r\n *\r\n * @async\r\n * @function initPool\r\n *\r\n * @param {Object} poolOptions - The configuration object containing `pool`\r\n * options.\r\n * @param {Array} puppeteerArgs - Additional arguments for Puppeteer\r\n * launch.\r\n *\r\n * @returns {Promise} A Promise that resolves to ending the function\r\n * execution when an already initialized pool of resources is found.\r\n *\r\n * @throws {ExportError} Throws an `ExportError` if could not create the pool\r\n * of workers.\r\n */\r\nexport async function initPool(poolOptions, puppeteerArgs) {\r\n // Create a browser instance with the puppeteer arguments\r\n await createBrowser(puppeteerArgs);\r\n\r\n try {\r\n log(\r\n 3,\r\n `[pool] Initializing pool with workers: min ${poolOptions.minWorkers}, max ${poolOptions.maxWorkers}.`\r\n );\r\n\r\n if (pool) {\r\n log(\r\n 4,\r\n '[pool] Already initialized, please kill it before creating a new one.'\r\n );\r\n return;\r\n }\r\n\r\n // Keep an eye on a correct min and max workers number\r\n if (poolOptions.minWorkers > poolOptions.maxWorkers) {\r\n poolOptions.minWorkers = poolOptions.maxWorkers;\r\n }\r\n\r\n // Create a pool along with a minimal number of resources\r\n pool = new Pool({\r\n // Get the `create`, `validate`, and `destroy` functions\r\n ..._factory(poolOptions),\r\n min: poolOptions.minWorkers,\r\n max: poolOptions.maxWorkers,\r\n acquireTimeoutMillis: poolOptions.acquireTimeout,\r\n createTimeoutMillis: poolOptions.createTimeout,\r\n destroyTimeoutMillis: poolOptions.destroyTimeout,\r\n idleTimeoutMillis: poolOptions.idleTimeout,\r\n createRetryIntervalMillis: poolOptions.createRetryInterval,\r\n reapIntervalMillis: poolOptions.reaperInterval,\r\n propagateCreateError: false\r\n });\r\n\r\n // Set events\r\n pool.on('release', async (resource) => {\r\n // Clear page\r\n const clearStatus = await clearPage(resource, false);\r\n log(\r\n 4,\r\n `[pool] Pool resource [${resource.id}] - Releasing a worker. Clear page status: ${clearStatus}.`\r\n );\r\n });\r\n\r\n pool.on('destroySuccess', (_eventId, resource) => {\r\n log(\r\n 4,\r\n `[pool] Pool resource [${resource.id}] - Destroyed a worker successfully.`\r\n );\r\n resource.page = null;\r\n });\r\n\r\n const initialResources = [];\r\n // Create an initial number of resources\r\n for (let i = 0; i < poolOptions.minWorkers; i++) {\r\n try {\r\n const resource = await pool.acquire().promise;\r\n initialResources.push(resource);\r\n } catch (error) {\r\n logWithStack(2, error, '[pool] Could not create an initial resource.');\r\n }\r\n }\r\n\r\n // Release the initial number of resources back to the pool\r\n initialResources.forEach((resource) => {\r\n pool.release(resource);\r\n });\r\n\r\n log(\r\n 3,\r\n `[pool] The pool is ready${initialResources.length ? ` with ${initialResources.length} initial resources waiting.` : '.'}`\r\n );\r\n } catch (error) {\r\n throw new ExportError(\r\n '[pool] Could not configure and create the pool of workers.',\r\n 500\r\n ).setError(error);\r\n }\r\n}\r\n\r\n/**\r\n * Terminates all workers in the pool, destroys the pool, and closes the browser\r\n * instance.\r\n *\r\n * @async\r\n * @function killPool\r\n *\r\n * @returns {Promise} A Promise that resolves once all workers are\r\n * terminated, the pool is destroyed, and the browser is successfully closed.\r\n */\r\nexport async function killPool() {\r\n log(3, '[pool] Killing pool with all workers and closing browser.');\r\n\r\n // If still alive, destroy the pool of pages before closing a browser\r\n if (pool) {\r\n // Free up not released workers\r\n for (const worker of pool.used) {\r\n pool.release(worker.resource);\r\n }\r\n\r\n // Destroy the pool if it is still available\r\n if (!pool.destroyed) {\r\n await pool.destroy();\r\n log(4, '[pool] Destroyed the pool of resources.');\r\n }\r\n pool = null;\r\n }\r\n\r\n // Close the browser instance\r\n await closeBrowser();\r\n}\r\n\r\n/**\r\n * Processes the export work using a worker from the pool. Acquires a worker\r\n * handle from the pool, performs the export using puppeteer, and releases\r\n * the worker handle back to the pool.\r\n *\r\n * @async\r\n * @function postWork\r\n *\r\n * @param {Object} options - The configuration object containing complete set\r\n * of options.\r\n *\r\n * @returns {Promise} A Promise that resolves to the export result\r\n * and options.\r\n *\r\n * @throws {ExportError} Throws an `ExportError` if an error occurs during\r\n * the export process.\r\n */\r\nexport async function postWork(options) {\r\n let workerHandle;\r\n\r\n try {\r\n log(4, '[pool] Work received, starting to process.');\r\n\r\n // An export attempt counted\r\n ++poolStats.exportsAttempted;\r\n\r\n // Display the pool information if needed\r\n if (options.pool.benchmarking) {\r\n _getPoolInfo();\r\n }\r\n\r\n // Throw an error in case of lacking the pool instance\r\n if (!pool) {\r\n throw new ExportError(\r\n '[pool] Work received, but pool has not been started.',\r\n 500\r\n );\r\n }\r\n\r\n // The acquire counter\r\n const acquireCounter = measureTime();\r\n\r\n // Try to acquire the worker along with the id, works count and page\r\n try {\r\n log(4, '[pool] Acquiring a worker handle.');\r\n\r\n // Acquire a pool resource\r\n workerHandle = await pool.acquire().promise;\r\n\r\n // Check the page acquire time\r\n if (options.server.benchmarking) {\r\n log(\r\n 5,\r\n `[benchmark] ${options.requestId ? `Request [${options.requestId}] - ` : ''}`,\r\n `Acquiring a worker handle took ${acquireCounter()}ms.`\r\n );\r\n }\r\n } catch (error) {\r\n throw new ExportError(\r\n `[pool] ${\r\n options.requestId ? `Request [${options.requestId}] - ` : ''\r\n }Error encountered when acquiring an available entry: ${acquireCounter()}ms.`,\r\n 400\r\n ).setError(error);\r\n }\r\n log(4, '[pool] Acquired a worker handle.');\r\n\r\n if (!workerHandle.page) {\r\n // Set the `workLimit` to exceeded in order to recreate the resource\r\n workerHandle.workCount = options.pool.workLimit + 1;\r\n throw new ExportError(\r\n '[pool] Resolved worker page is invalid: the pool setup is wonky.',\r\n 400\r\n );\r\n }\r\n\r\n log(\r\n 4,\r\n `[pool] Pool resource [${workerHandle.id}] - Starting work on this pool entry.`\r\n );\r\n\r\n // Start measuring export time\r\n const exportCounter = measureTime();\r\n\r\n // Perform an export on a puppeteer level\r\n const exportResult = await puppeteerExport(\r\n workerHandle.page,\r\n options.export,\r\n options.customLogic\r\n );\r\n\r\n // Check if it's an error\r\n if (exportResult instanceof Error) {\r\n // NOTE:\r\n // If there's a rasterization timeout, we want need to flush the page.\r\n // This is because the page may be in a state where it's waiting for\r\n // the screenshot to finish even though the timeout has occured.\r\n // Which of course causes a lot of issues with the event system,\r\n // and page consistency.\r\n //\r\n // Only `page.screenshot` will throw this, timeouts for PDF's are\r\n // handled by the `page.pdf` function itself.\r\n //\r\n // ...yes, this is ugly.\r\n if (exportResult.message === 'Rasterization timeout') {\r\n // Set the `workLimit` to exceeded in order to recreate the resource\r\n workerHandle.workCount = options.pool.workLimit + 1;\r\n workerHandle.page = null;\r\n }\r\n\r\n if (\r\n exportResult.name === 'TimeoutError' ||\r\n exportResult.message === 'Rasterization timeout'\r\n ) {\r\n throw new ExportError(\r\n `[pool] ${\r\n options.requestId ? `Request [${options.requestId}] - ` : ''\r\n }Rasterization timeout: your chart may be too complex or large, and failed to render within the allotted time.`\r\n ).setError(exportResult);\r\n } else {\r\n throw new ExportError(\r\n `[pool] ${\r\n options.requestId ? `Request [${options.requestId}] - ` : ''\r\n }Error encountered during export: ${exportCounter()}ms.`\r\n ).setError(exportResult);\r\n }\r\n }\r\n\r\n // Check the Puppeteer export time\r\n if (options.server.benchmarking) {\r\n log(\r\n 5,\r\n `[benchmark] ${options.requestId ? `Request [${options.requestId}] - ` : ''}`,\r\n `Exporting a chart sucessfully took ${exportCounter()}ms.`\r\n );\r\n }\r\n\r\n // Release the resource back to the pool\r\n pool.release(workerHandle);\r\n\r\n // Update statistics\r\n poolStats.timeSpent += exportCounter();\r\n poolStats.timeSpentAverage =\r\n poolStats.timeSpent / ++poolStats.exportsPerformed;\r\n\r\n log(4, `[pool] Work completed in ${exportCounter()}ms.`);\r\n\r\n // Otherwise return an object with the result and options\r\n return {\r\n result: exportResult,\r\n options\r\n };\r\n } catch (error) {\r\n ++poolStats.exportsDropped;\r\n\r\n // Try to release the worker, if it exists\r\n if (workerHandle) {\r\n pool.release(workerHandle);\r\n }\r\n\r\n throw error;\r\n }\r\n}\r\n\r\n/**\r\n * Retrieves the current pool instance.\r\n *\r\n * @function getPool\r\n *\r\n * @returns {(Object|null)} The current pool instance if initialized, or `null`\r\n * if the pool has not been created.\r\n */\r\nexport function getPool() {\r\n return pool;\r\n}\r\n\r\n/**\r\n * Gets the statistic of a pool instace about exports.\r\n *\r\n * @function getPoolStats\r\n *\r\n * @returns {Object} The current pool statistics.\r\n */\r\nexport function getPoolStats() {\r\n return poolStats;\r\n}\r\n\r\n/**\r\n * Retrieves pool information in JSON format, including minimum and maximum\r\n * workers, available workers, workers in use, and pending acquire requests.\r\n *\r\n * @function getPoolInfoJSON\r\n *\r\n * @returns {Object} Pool information in JSON format.\r\n */\r\nexport function getPoolInfoJSON() {\r\n return {\r\n min: pool.min,\r\n max: pool.max,\r\n used: pool.numUsed(),\r\n available: pool.numFree(),\r\n allCreated: pool.numUsed() + pool.numFree(),\r\n pendingAcquires: pool.numPendingAcquires(),\r\n pendingCreates: pool.numPendingCreates(),\r\n pendingValidations: pool.numPendingValidations(),\r\n pendingDestroys: pool.pendingDestroys.length,\r\n absoluteAll:\r\n pool.numUsed() +\r\n pool.numFree() +\r\n pool.numPendingAcquires() +\r\n pool.numPendingCreates() +\r\n pool.numPendingValidations() +\r\n pool.pendingDestroys.length\r\n };\r\n}\r\n\r\n/**\r\n * Logs information about the current state of the pool, including the minimum\r\n * and maximum workers, available workers, workers in use, and pending acquire\r\n * requests.\r\n *\r\n * @function _getPoolInfo\r\n */\r\nfunction _getPoolInfo() {\r\n const {\r\n min,\r\n max,\r\n used,\r\n available,\r\n allCreated,\r\n pendingAcquires,\r\n pendingCreates,\r\n pendingValidations,\r\n pendingDestroys,\r\n absoluteAll\r\n } = getPoolInfoJSON();\r\n\r\n log(5, `[pool] The minimum number of resources allowed by pool: ${min}.`);\r\n log(5, `[pool] The maximum number of resources allowed by pool: ${max}.`);\r\n log(5, `[pool] The number of used resources: ${used}.`);\r\n log(5, `[pool] The number of free resources: ${available}.`);\r\n log(\r\n 5,\r\n `[pool] The number of all created (used and free) resources: ${allCreated}.`\r\n );\r\n log(\r\n 5,\r\n `[pool] The number of resources waiting to be acquired: ${pendingAcquires}.`\r\n );\r\n log(\r\n 5,\r\n `[pool] The number of resources waiting to be created: ${pendingCreates}.`\r\n );\r\n log(\r\n 5,\r\n `[pool] The number of resources waiting to be validated: ${pendingValidations}.`\r\n );\r\n log(\r\n 5,\r\n `[pool] The number of resources waiting to be destroyed: ${pendingDestroys}.`\r\n );\r\n log(5, `[pool] The number of all resources: ${absoluteAll}.`);\r\n}\r\n\r\n/**\r\n * Factory function that returns an object with `create`, `validate`, `destroy`\r\n * functions for the pool instance.\r\n *\r\n * @function _factory\r\n *\r\n * @param {Object} poolOptions - The configuration object containing `pool`\r\n * options.\r\n */\r\nfunction _factory(poolOptions) {\r\n return {\r\n /**\r\n * Creates a new worker page for the export pool.\r\n *\r\n * @async\r\n * @function create\r\n *\r\n * @returns {Promise} A Promise that resolves to an object\r\n * containing the worker ID, a reference to the browser page, and initial\r\n * work count.\r\n *\r\n * @throws {ExportError} Throws an `ExportError` if there is an error during\r\n * the creation of the new page.\r\n */\r\n create: async () => {\r\n // Init the resource with unique id and work count\r\n const poolResource = {\r\n id: uuid(),\r\n // Try to distribute the initial work count\r\n workCount: Math.round(Math.random() * (poolOptions.workLimit / 2))\r\n };\r\n\r\n try {\r\n // Start measuring a page creation time\r\n const startDate = getNewDateTime();\r\n\r\n // Create a new page\r\n await newPage(poolResource);\r\n\r\n // Measure the time of full creation and configuration of a page\r\n log(\r\n 3,\r\n `[pool] Pool resource [${poolResource.id}] - Successfully created a worker, took ${\r\n getNewDateTime() - startDate\r\n }ms.`\r\n );\r\n\r\n // Return ready pool resource\r\n return poolResource;\r\n } catch (error) {\r\n log(\r\n 3,\r\n `[pool] Pool resource [${poolResource.id}] - Error encountered when creating a new page.`\r\n );\r\n throw error;\r\n }\r\n },\r\n\r\n /**\r\n * Validates a worker page in the export pool, checking if it has exceeded\r\n * the work limit.\r\n *\r\n * @async\r\n * @function validate\r\n *\r\n * @param {Object} poolResource - The handle to the worker, containing\r\n * the worker's ID, a reference to the browser page, and work count.\r\n *\r\n * @returns {Promise} A Promise that resolves to true if the worker\r\n * is valid and within the work limit; otherwise, to false.\r\n */\r\n validate: async (poolResource) => {\r\n // NOTE:\r\n // In certain cases acquiring throws a `TargetCloseError`, which may\r\n // be caused by two things:\r\n // - The page is closed and attempted to be reused.\r\n // - Lost contact with the browser.\r\n //\r\n // What we're seeing in logs is that successive exports typically\r\n // succeeds, and the server recovers, indicating that it's likely\r\n // the first case. This is an attempt at allievating the issue by\r\n // simply not validating the worker if the page is null or closed.\r\n //\r\n // The actual result from when this happened, was that a worker would\r\n // be completely locked, stopping it from being acquired until\r\n // its work count reached the limit.\r\n\r\n // Check if the `page` is valid\r\n if (!poolResource.page) {\r\n log(\r\n 3,\r\n `[pool] Pool resource [${poolResource.id}] - Validation failed (no valid page is found).`\r\n );\r\n return false;\r\n }\r\n\r\n // Check if the `page` is closed\r\n if (poolResource.page.isClosed()) {\r\n log(\r\n 3,\r\n `[pool] Pool resource [${poolResource.id}] - Validation failed (page is closed or invalid).`\r\n );\r\n return false;\r\n }\r\n\r\n // Check if the `mainFrame` is detached\r\n if (poolResource.page.mainFrame().detached) {\r\n log(\r\n 3,\r\n `[pool] Pool resource [${poolResource.id}] - Validation failed (page's frame is detached).`\r\n );\r\n return false;\r\n }\r\n\r\n // Check if the `workLimit` is exceeded\r\n if (\r\n poolOptions.workLimit &&\r\n ++poolResource.workCount > poolOptions.workLimit\r\n ) {\r\n log(\r\n 3,\r\n `[pool] Pool resource [${poolResource.id}] - Validation failed (exceeded the ${poolOptions.workLimit} works per resource limit).`\r\n );\r\n return false;\r\n }\r\n\r\n // The `poolResource` is validated\r\n return true;\r\n },\r\n\r\n /**\r\n * Destroys a worker entry in the export pool, closing its associated page.\r\n *\r\n * @async\r\n * @function destroy\r\n *\r\n * @param {Object} poolResource - The handle to the worker, containing\r\n * the worker's ID, a reference to the browser page, and work count.\r\n */\r\n destroy: async (poolResource) => {\r\n log(\r\n 3,\r\n `[pool] Pool resource [${poolResource.id}] - Destroying a worker.`\r\n );\r\n\r\n if (poolResource.page && !poolResource.page.isClosed()) {\r\n try {\r\n // Remove all attached event listeners from the resource\r\n poolResource.page.removeAllListeners('pageerror');\r\n poolResource.page.removeAllListeners('console');\r\n poolResource.page.removeAllListeners('framedetached');\r\n\r\n // We need to wait around for this\r\n await poolResource.page.close();\r\n } catch (error) {\r\n log(\r\n 3,\r\n `[pool] Pool resource [${poolResource.id}] - Page could not be closed upon destroying.`\r\n );\r\n throw error;\r\n }\r\n }\r\n }\r\n };\r\n}\r\n\r\nexport default {\r\n initPool,\r\n killPool,\r\n postWork,\r\n getPool,\r\n getPoolStats,\r\n getPoolInfoJSON\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * @overview Used to sanitize the strings coming from the exporting module\r\n * to prevent XSS attacks (with the DOMPurify library).\r\n */\r\n\r\nimport DOMPurify from 'dompurify';\r\nimport { JSDOM } from 'jsdom';\r\n\r\n/**\r\n * Sanitizes a given HTML string by removing \r\n * tags and any content within them.\r\n *\r\n * @function sanitize\r\n *\r\n * @param {string} input - The HTML string to be sanitized.\r\n *\r\n * @returns {string} The sanitized HTML string.\r\n */\r\nexport function sanitize(input) {\r\n // Get the virtual DOM\r\n const window = new JSDOM('').window;\r\n\r\n // Create a purifying instance\r\n const purify = DOMPurify(window);\r\n\r\n // Return sanitized input, allowing for the `foreignObject` elements\r\n return purify.sanitize(input, { ADD_TAGS: ['foreignObject'] });\r\n}\r\n\r\nexport default {\r\n sanitize\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * @overview This module provides functions that prepare for the exporting\r\n * charts into various image output formats such as JPEG, PNG, PDF, and SVGs.\r\n * It supports single and batch export operations and allows customization\r\n * through options passed from configurations or APIs.\r\n */\r\n\r\nimport { readFileSync, writeFileSync } from 'fs';\r\n\r\nimport { isAllowedConfig, updateOptions, validateOption } from './config.js';\r\nimport { log, logWithStack } from './logger.js';\r\nimport { getPoolStats, killPool, postWork } from './pool.js';\r\nimport { sanitize } from './sanitize.js';\r\nimport { getAbsolutePath, getBase64, isObject, roundNumber } from './utils.js';\r\n\r\nimport ExportError from './errors/ExportError.js';\r\n\r\n// The global flag for the code execution permission\r\nlet allowCodeExecution = false;\r\n\r\n/**\r\n * Starts a single export process based on the specified options and saves\r\n * the resulting image to the provided output file.\r\n *\r\n * @async\r\n * @function singleExport\r\n *\r\n * @param {Object} options - The `options` object, which should include settings\r\n * from the `export` and `customLogic` sections. It can be a partial or complete\r\n * set of options from these sections. The object must contain at least one\r\n * of the following `export` properties: `infile`, `instr`, `options`, or `svg`\r\n * to generate a valid image.\r\n *\r\n * @returns {Promise} A Promise that resolves once the single export\r\n * process is completed.\r\n *\r\n * @throws {ExportError} Throws an `ExportError` if an error occurs during\r\n * the single export process.\r\n */\r\nexport async function singleExport(options) {\r\n // Check if the export makes sense\r\n if (options && options.export) {\r\n // Perform an export\r\n await startExport(\r\n { export: options.export, customLogic: options.customLogic },\r\n async (error, data) => {\r\n // Exit process when error exists\r\n if (error) {\r\n throw error;\r\n }\r\n\r\n // Get the `b64`, `outfile`, and `type` for a chart\r\n const { b64, outfile, type } = data.options.export;\r\n\r\n // Save the result\r\n try {\r\n if (b64) {\r\n // As a Base64 string to a txt file\r\n writeFileSync(\r\n `${outfile.split('.').shift() || 'chart'}.txt`,\r\n getBase64(data.result, type)\r\n );\r\n } else {\r\n // As a correct image format\r\n writeFileSync(\r\n outfile || `chart.${type}`,\r\n type !== 'svg' ? Buffer.from(data.result, 'base64') : data.result\r\n );\r\n }\r\n } catch (error) {\r\n throw new ExportError(\r\n '[chart] Error while saving a chart.',\r\n 500\r\n ).setError(error);\r\n }\r\n\r\n // Kill pool and close browser after finishing single export\r\n await killPool();\r\n }\r\n );\r\n } else {\r\n throw new ExportError(\r\n '[chart] No expected `export` options were found. Please provide one of the following options: `infile`, `instr`, `options`, or `svg` to generate a valid image.',\r\n 400\r\n );\r\n }\r\n}\r\n\r\n/**\r\n * Starts a batch export process for multiple charts based on information\r\n * provided in the `batch` option. The `batch` is a string in the following\r\n * format: \"infile1.json=outfile1.png;infile2.json=outfile2.png;...\". Results\r\n * are saved to the specified output files.\r\n *\r\n * @async\r\n * @function batchExport\r\n *\r\n * @param {Object} options - The `options` object, which should include settings\r\n * from the `export` and `customLogic` sections. It can be a partial or complete\r\n * set of options from these sections. It must contain the `batch` option from\r\n * the `export` section to generate valid images.\r\n *\r\n * @returns {Promise} A Promise that resolves once the batch export\r\n * processes are completed.\r\n *\r\n * @throws {ExportError} Throws an `ExportError` if an error occurs during\r\n * any of the batch export process.\r\n */\r\nexport async function batchExport(options) {\r\n // Check if the export makes sense\r\n if (options && options.export && options.export.batch) {\r\n // An array for collecting batch exports\r\n const batchFunctions = [];\r\n\r\n // Split and pair the `batch` arguments\r\n for (let pair of options.export.batch.split(';') || []) {\r\n pair = pair.split('=');\r\n if (pair.length === 2) {\r\n batchFunctions.push(\r\n startExport(\r\n {\r\n export: {\r\n ...options.export,\r\n infile: pair[0],\r\n outfile: pair[1]\r\n },\r\n customLogic: options.customLogic\r\n },\r\n (error, data) => {\r\n // Exit process when error exists\r\n if (error) {\r\n throw error;\r\n }\r\n\r\n // Get the `b64`, `outfile`, and `type` for a chart\r\n const { b64, outfile, type } = data.options.export;\r\n\r\n // Save the result\r\n try {\r\n if (b64) {\r\n // As a Base64 string to a txt file\r\n writeFileSync(\r\n `${outfile.split('.').shift() || 'chart'}.txt`,\r\n getBase64(data.result, type)\r\n );\r\n } else {\r\n // As a correct image format\r\n writeFileSync(\r\n outfile,\r\n type !== 'svg'\r\n ? Buffer.from(data.result, 'base64')\r\n : data.result\r\n );\r\n }\r\n } catch (error) {\r\n throw new ExportError(\r\n '[chart] Error while saving a chart.',\r\n 500\r\n ).setError(error);\r\n }\r\n }\r\n )\r\n );\r\n } else {\r\n log(2, '[chart] No correct pair found for the batch export.');\r\n }\r\n }\r\n\r\n // Await all exports are done\r\n const batchResults = await Promise.allSettled(batchFunctions);\r\n\r\n // Kill pool and close browser after finishing batch export\r\n await killPool();\r\n\r\n // Log errors if found\r\n batchResults.forEach((result, index) => {\r\n // Log the error with stack about the specific batch export\r\n if (result.reason) {\r\n logWithStack(\r\n 1,\r\n result.reason,\r\n `[chart] Batch export number ${index + 1} could not be correctly completed.`\r\n );\r\n }\r\n });\r\n } else {\r\n throw new ExportError(\r\n '[chart] No expected `export` options were found. Please provide the `batch` option to generate valid images.',\r\n 400\r\n );\r\n }\r\n}\r\n\r\n/**\r\n * Starts an export process. The `imageOptions` parameter is an object that\r\n * should include settings from the `export` and `customLogic` sections. It can\r\n * be a partial or complete set of options from these sections. If partial\r\n * options are provided, missing values will be merged with the current global\r\n * options.\r\n *\r\n * The `endCallback` function is invoked upon the completion of the export,\r\n * either successfully or with an error. The `error` object is provided\r\n * as the first argument, and the `data` object is the second, containing\r\n * the Base64 representation of the chart in the `result` property\r\n * and the complete set of options in the `options` property.\r\n *\r\n * @async\r\n * @function startExport\r\n *\r\n * @param {Object} imageOptions - The `imageOptions` object, which should\r\n * include settings from the `export` and `customLogic` sections. It can\r\n * be a partial or complete set of options from these sections. If the provided\r\n * options are partial, missing values will be merged with the current global\r\n * options.\r\n * @param {Function} endCallback - The callback function to be invoked upon\r\n * finalizing the export process or upon encountering an error. The first\r\n * argument is the `error` object, and the second argument is the `data` object,\r\n * which includes the Base64 representation of the chart in the `result`\r\n * property and the full set of options in the `options` property.\r\n *\r\n * @returns {Promise} This function does not return a value directly.\r\n * Instead, it communicates results via the `endCallback`.\r\n *\r\n * @throws {ExportError} Throws an `ExportError` if there is a problem with\r\n * processing input of any type. The error is passed into the `endCallback`\r\n * function and processed there.\r\n */\r\nexport async function startExport(imageOptions, endCallback) {\r\n try {\r\n // Check if provided options are in an object\r\n if (!isObject(imageOptions)) {\r\n throw new ExportError(\r\n '[chart] Incorrect value of the provided `imageOptions`. Needs to be an object.',\r\n 400\r\n );\r\n }\r\n\r\n // Merge additional options to the copy of the instance options\r\n const options = updateOptions(\r\n {\r\n export: imageOptions.export,\r\n customLogic: imageOptions.customLogic\r\n },\r\n true\r\n );\r\n\r\n // Get the `export` options\r\n const exportOptions = options.export;\r\n\r\n // Starting exporting process message\r\n log(4, '[chart] Starting the exporting process.');\r\n\r\n // Export using options from the file as an input\r\n if (exportOptions.infile !== null) {\r\n log(4, '[chart] Attempting to export from a file input.');\r\n\r\n let fileContent;\r\n try {\r\n // Try to read the file to get the string representation\r\n fileContent = readFileSync(\r\n getAbsolutePath(exportOptions.infile),\r\n 'utf8'\r\n );\r\n } catch (error) {\r\n throw new ExportError(\r\n '[chart] Error loading content from a file input.',\r\n 400\r\n ).setError(error);\r\n }\r\n\r\n // Check the file's extension\r\n if (exportOptions.infile.endsWith('.svg')) {\r\n // Set to the `svg` option\r\n exportOptions.svg = validateOption('svg', fileContent);\r\n } else if (exportOptions.infile.endsWith('.json')) {\r\n // Set to the `instr` option\r\n exportOptions.instr = validateOption('instr', fileContent);\r\n } else {\r\n throw new ExportError(\r\n '[chart] Incorrect value of the `infile` option.',\r\n 400\r\n );\r\n }\r\n }\r\n\r\n // Export using SVG as an input\r\n if (exportOptions.svg !== null) {\r\n log(4, '[chart] Attempting to export from an SVG input.');\r\n\r\n // SVG exports attempts counter\r\n ++getPoolStats().exportsFromSvgAttempts;\r\n\r\n // Export from an SVG string\r\n const result = await _exportFromSvg(\r\n sanitize(exportOptions.svg), // #209\r\n options\r\n );\r\n\r\n // SVG exports counter\r\n ++getPoolStats().exportsFromSvg;\r\n\r\n // Pass SVG export result to the end callback\r\n return endCallback(null, result);\r\n }\r\n\r\n // Export using options as an input\r\n if (exportOptions.instr !== null || exportOptions.options !== null) {\r\n log(4, '[chart] Attempting to export from options input.');\r\n\r\n // Options exports attempts counter\r\n ++getPoolStats().exportsFromOptionsAttempts;\r\n\r\n // Export from options\r\n const result = await _exportFromOptions(\r\n exportOptions.instr || exportOptions.options,\r\n options\r\n );\r\n\r\n // Options exports counter\r\n ++getPoolStats().exportsFromOptions;\r\n\r\n // Pass options export result to the end callback\r\n return endCallback(null, result);\r\n }\r\n\r\n // No input specified, pass an error message to the callback\r\n return endCallback(\r\n new ExportError(\r\n `[chart] No valid input specified. Check if at least one of the following parameters is correctly set: 'infile', 'instr', 'options', or 'svg'.`,\r\n 400\r\n )\r\n );\r\n } catch (error) {\r\n return endCallback(error);\r\n }\r\n}\r\n\r\n/**\r\n * Retrieves and returns the current status of the code execution permission.\r\n *\r\n * @function getAllowCodeExecution\r\n *\r\n * @returns {boolean} The value of the global `allowCodeExecution` option.\r\n */\r\nexport function getAllowCodeExecution() {\r\n return allowCodeExecution;\r\n}\r\n\r\n/**\r\n * Sets the code execution permission based on the provided boolean value.\r\n *\r\n * @function setAllowCodeExecution\r\n *\r\n * @param {boolean} value - The boolean value to be assigned to the global\r\n * `allowCodeExecution` option.\r\n */\r\nexport function setAllowCodeExecution(value) {\r\n allowCodeExecution = value;\r\n}\r\n\r\n/**\r\n * Exports from an SVG based input with the provided options.\r\n *\r\n * @async\r\n * @function _exportFromSvg\r\n *\r\n * @param {string} inputToExport - The SVG based input to be exported.\r\n * @param {Object} options - The configuration object containing complete set\r\n * of options.\r\n *\r\n * @returns {Promise} A Promise that resolves to a result of the export\r\n * process.\r\n *\r\n * @throws {ExportError} Throws an `ExportError` if there is not a correct SVG\r\n * input.\r\n */\r\nasync function _exportFromSvg(inputToExport, options) {\r\n // Check if it is SVG\r\n if (\r\n typeof inputToExport === 'string' &&\r\n (inputToExport.indexOf('= 0 || inputToExport.indexOf('= 0)\r\n ) {\r\n log(4, '[chart] Parsing input as SVG.');\r\n\r\n // Set the export input as SVG\r\n options.export.svg = inputToExport;\r\n\r\n // Reset the rest of the export input options\r\n options.export.options = null;\r\n options.export.instr = null;\r\n\r\n // Call the function with an SVG string as an export input\r\n return _prepareExport(options);\r\n } else {\r\n throw new ExportError('[chart] Not a correct SVG input.', 400);\r\n }\r\n}\r\n\r\n/**\r\n * Exports from an options based input with the provided options.\r\n *\r\n * @async\r\n * @function _exportFromOptions\r\n *\r\n * @param {string} inputToExport - The options based input to be exported.\r\n * @param {Object} options - The configuration object containing complete set\r\n * of options.\r\n *\r\n * @returns {Promise} A Promise that resolves to a result of the export\r\n * process.\r\n *\r\n * @throws {ExportError} Throws an `ExportError` if there is not a correct\r\n * chart options input.\r\n */\r\nasync function _exportFromOptions(inputToExport, options) {\r\n log(4, '[chart] Parsing input from options.');\r\n\r\n // Try to check, validate and parse to stringified options\r\n const stringifiedOptions = isAllowedConfig(\r\n inputToExport,\r\n true,\r\n options.customLogic.allowCodeExecution\r\n );\r\n\r\n // Check if a correct stringified options\r\n if (\r\n stringifiedOptions === null ||\r\n typeof stringifiedOptions !== 'string' ||\r\n !stringifiedOptions.startsWith('{') ||\r\n !stringifiedOptions.endsWith('}')\r\n ) {\r\n throw new ExportError(\r\n '[chart] Invalid configuration provided - Only options configurations and SVG are allowed for this server. If this is your server, JavaScript custom code can be enabled by starting the server with the `allowCodeExecution` options set to true.',\r\n 403\r\n );\r\n }\r\n\r\n // Set the export input as a stringified chart options\r\n options.export.instr = stringifiedOptions;\r\n\r\n // Reset the rest of the export input options\r\n options.export.options = null;\r\n options.export.svg = null;\r\n\r\n // Call the function with a stringified chart options\r\n return _prepareExport(options);\r\n}\r\n\r\n/**\r\n * Function for finalizing options and configurations before export.\r\n *\r\n * @async\r\n * @function _prepareExport\r\n *\r\n * @param {Object} options - The configuration object containing complete set\r\n * of options.\r\n *\r\n * @returns {Promise} A Promise that resolves to a result of the export\r\n * process.\r\n */\r\nasync function _prepareExport(options) {\r\n // Get the `export` and `customLogic` options\r\n const { export: exportOptions, customLogic: customLogicOptions } = options;\r\n\r\n // Prepare the `constr` option\r\n exportOptions.constr = _fixConstr(exportOptions.constr);\r\n\r\n // Prepare the `type` option\r\n exportOptions.type = _fixType(exportOptions.type, exportOptions.outfile);\r\n\r\n // Prepare the `outfile` option\r\n exportOptions.outfile = _fixOutfile(\r\n exportOptions.type,\r\n exportOptions.outfile\r\n );\r\n\r\n // Notify about the custom logic usage status\r\n log(\r\n 3,\r\n `[chart] The custom logic is ${customLogicOptions.allowCodeExecution ? 'allowed' : 'disallowed'}.`\r\n );\r\n\r\n // Prepare the `customCode`, `callback`, and `resources` options\r\n _handleCustomLogic(customLogicOptions);\r\n\r\n // Prepare the `globalOptions` and `themeOptions` options\r\n _handleGlobalAndTheme(exportOptions, customLogicOptions);\r\n\r\n // Prepare the `height`, `width`, and `scale` options\r\n _handleSize(exportOptions);\r\n\r\n // Check if the image options object does not exceed the size limit\r\n _checkDataSize({ export: exportOptions, customLogic: customLogicOptions });\r\n\r\n // Post the work to the pool\r\n return postWork(options);\r\n}\r\n\r\n/**\r\n * Handles adjusting the constructor name by transforming and normalizing\r\n * it based on common chart types.\r\n *\r\n * @function _fixConstr\r\n *\r\n * @param {string} constr - The original constructor name to be adjusted.\r\n *\r\n * @returns {string} The corrected constructor name, or 'chart' if the input\r\n * is not recognized.\r\n */\r\nfunction _fixConstr(constr) {\r\n try {\r\n // Fix the constructor by lowering casing\r\n const fixedConstr = `${constr.toLowerCase().replace('chart', '')}Chart`;\r\n\r\n // Handle the case where the result is just 'Chart'\r\n if (fixedConstr === 'Chart') {\r\n fixedConstr.toLowerCase();\r\n }\r\n\r\n // Return the corrected constructor, otherwise default to 'chart'\r\n return ['chart', 'stockChart', 'mapChart', 'ganttChart'].includes(\r\n fixedConstr\r\n )\r\n ? fixedConstr\r\n : 'chart';\r\n } catch {\r\n // Default to 'chart' in case of any error\r\n return 'chart';\r\n }\r\n}\r\n\r\n/**\r\n * Handles fixing the outfile based on provided type.\r\n *\r\n * @function _fixOutfile\r\n *\r\n * @param {string} type - The original export type.\r\n * @param {string} outfile - The file path or name.\r\n *\r\n * @returns {string} The corrected outfile, or 'chart.png' if the input\r\n * is not recognized.\r\n */\r\nfunction _fixOutfile(type, outfile) {\r\n // Get the file name from the `outfile` option\r\n const fileName = getAbsolutePath(outfile || 'chart')\r\n .split('.')\r\n .shift();\r\n\r\n // Return a correct outfile\r\n return `${fileName}.${type || 'png'}`;\r\n}\r\n\r\n/**\r\n * Handles fixing the export type based on MIME types and file extensions.\r\n *\r\n * @function _fixType\r\n *\r\n * @param {string} type - The original export type.\r\n * @param {string} [outfile=null] - The file path or name. The default value\r\n * is `null`.\r\n *\r\n * @returns {string} The corrected export type, or 'png' if the input\r\n * is not recognized.\r\n */\r\nfunction _fixType(type, outfile = null) {\r\n // MIME types\r\n const mimeTypes = {\r\n 'image/png': 'png',\r\n 'image/jpeg': 'jpeg',\r\n 'application/pdf': 'pdf',\r\n 'image/svg+xml': 'svg'\r\n };\r\n\r\n // Get formats\r\n const formats = Object.values(mimeTypes);\r\n\r\n // Check if type and outfile's extensions are the same\r\n if (outfile) {\r\n const outType = outfile.split('.').pop();\r\n\r\n // Support the JPG type\r\n if (outType === 'jpg') {\r\n type = 'jpeg';\r\n } else if (formats.includes(outType) && type !== outType) {\r\n type = outType;\r\n }\r\n }\r\n\r\n // Return a correct type\r\n return mimeTypes[type] || formats.find((t) => t === type) || 'png';\r\n}\r\n\r\n/**\r\n * Handle calculating the `height`, `width` and `scale` for chart exports based\r\n * on the provided export options.\r\n *\r\n * The function prioritizes values in the following order:\r\n *\r\n * 1. The `height`, `width`, `scale` from the `exportOptions`.\r\n * 2. Options from the chart configuration (from `exporting` and `chart`).\r\n * 3. Options from the global options (from `exporting` and `chart`).\r\n * 4. Options from the theme options (from `exporting` and `chart` sections).\r\n * 5. Fallback default values (`height = 400`, `width = 600`, `scale = 1`).\r\n *\r\n * @function _handleSize\r\n *\r\n * @param {Object} exportOptions - The configuration object containing `export`\r\n * options.\r\n */\r\nfunction _handleSize(exportOptions) {\r\n // Check the `options` and `instr` for chart and exporting sections\r\n const { chart: optionsChart, exporting: optionsExporting } =\r\n isAllowedConfig(exportOptions.instr) || false;\r\n\r\n // Check the `globalOptions` for chart and exporting sections\r\n const { chart: globalOptionsChart, exporting: globalOptionsExporting } =\r\n isAllowedConfig(exportOptions.globalOptions) || false;\r\n\r\n // Check the `themeOptions` for chart and exporting sections\r\n const { chart: themeOptionsChart, exporting: themeOptionsExporting } =\r\n isAllowedConfig(exportOptions.themeOptions) || false;\r\n\r\n // Find the `height` value\r\n const height =\r\n exportOptions.height ||\r\n optionsExporting?.sourceHeight ||\r\n optionsChart?.height ||\r\n globalOptionsExporting?.sourceHeight ||\r\n globalOptionsChart?.height ||\r\n themeOptionsExporting?.sourceHeight ||\r\n themeOptionsChart?.height ||\r\n exportOptions.defaultHeight ||\r\n 400;\r\n\r\n // Find the `width` value\r\n const width =\r\n exportOptions.width ||\r\n optionsExporting?.sourceWidth ||\r\n optionsChart?.width ||\r\n globalOptionsExporting?.sourceWidth ||\r\n globalOptionsChart?.width ||\r\n themeOptionsExporting?.sourceWidth ||\r\n themeOptionsChart?.width ||\r\n exportOptions.defaultWidth ||\r\n 600;\r\n\r\n // Find the `scale` value:\r\n // - Cannot be lower than 0.1\r\n // - Cannot be higher than 5.0\r\n // - Must be rounded to 2 decimal places (e.g. 0.23234 -> 0.23)\r\n const scale = roundNumber(\r\n Math.max(\r\n 0.1,\r\n Math.min(\r\n exportOptions.scale ||\r\n optionsExporting?.scale ||\r\n globalOptionsExporting?.scale ||\r\n themeOptionsExporting?.scale ||\r\n exportOptions.defaultScale ||\r\n 1,\r\n 5.0\r\n )\r\n ),\r\n 2\r\n );\r\n\r\n // Update `height`, `width`, and `scale` information in the `export` options\r\n exportOptions.height = height;\r\n exportOptions.width = width;\r\n exportOptions.scale = scale;\r\n\r\n // Get rid of potential `px` and `%`\r\n for (let param of ['height', 'width', 'scale']) {\r\n if (typeof exportOptions[param] === 'string') {\r\n exportOptions[param] = +exportOptions[param].replace(/px|%/gi, '');\r\n }\r\n }\r\n}\r\n\r\n/**\r\n * Handles the execution of custom logic options, including loading `resources`,\r\n * `customCode`, and `callback`. If code execution is allowed, it processes\r\n * the custom logic options accordingly. If code execution is not allowed,\r\n * it disables the usage of resources, custom code and callback.\r\n *\r\n * @function _handleCustomLogic\r\n *\r\n * @param {Object} customLogicOptions - The configuration object containing\r\n * `customLogic` options.\r\n *\r\n * @throws {ExportError} Throws an `ExportError` if code execution\r\n * is not allowed but custom logic options are still provided.\r\n */\r\nfunction _handleCustomLogic(customLogicOptions) {\r\n // In case of allowing code execution\r\n if (customLogicOptions.allowCodeExecution) {\r\n // Process the `resources` option\r\n try {\r\n // Try to handle resources\r\n customLogicOptions.resources = _handleResources(\r\n customLogicOptions.resources,\r\n customLogicOptions.allowFileResources,\r\n true\r\n );\r\n } catch (error) {\r\n log(2, '[chart] The `resources` cannot be loaded.');\r\n\r\n // In case of an error, set the option with null\r\n customLogicOptions.resources = null;\r\n }\r\n\r\n // Process the `customCode` option\r\n try {\r\n // Try to load custom code and wrap around it in a self invoking function\r\n customLogicOptions.customCode = _handleCustomCode(\r\n customLogicOptions.customCode,\r\n customLogicOptions.allowFileResources\r\n );\r\n\r\n // Validate the option\r\n customLogicOptions.customCode = validateOption(\r\n 'customCode',\r\n customLogicOptions.customCode\r\n );\r\n } catch (error) {\r\n logWithStack(2, error, '[chart] The `customCode` cannot be loaded.');\r\n\r\n // In case of an error, set the option with null\r\n customLogicOptions.customCode = null;\r\n }\r\n\r\n // Process the `callback` option\r\n try {\r\n // Try to load callback function\r\n customLogicOptions.callback = _handleCustomCode(\r\n customLogicOptions.callback,\r\n customLogicOptions.allowFileResources,\r\n true\r\n );\r\n\r\n // Validate the option\r\n customLogicOptions.callback = validateOption(\r\n 'callback',\r\n customLogicOptions.callback\r\n );\r\n } catch (error) {\r\n logWithStack(2, error, '[chart] The `callback` cannot be loaded.');\r\n\r\n // In case of an error, set the option with null\r\n customLogicOptions.callback = null;\r\n }\r\n\r\n // Check if there is the `customCode` present\r\n if ([null, undefined].includes(customLogicOptions.customCode)) {\r\n log(3, '[chart] No value for the `customCode` option found.');\r\n }\r\n\r\n // Check if there is the `callback` present\r\n if ([null, undefined].includes(customLogicOptions.callback)) {\r\n log(3, '[chart] No value for the `callback` option found.');\r\n }\r\n\r\n // Check if there is the `resources` present\r\n if ([null, undefined].includes(customLogicOptions.resources)) {\r\n log(3, '[chart] No value for the `resources` option found.');\r\n }\r\n } else {\r\n // If the `allowCodeExecution` flag is set to false, we should refuse\r\n // the usage of the `callback`, `resources`, and `customCode` options.\r\n // Additionally, the worker will refuse to run arbitrary JavaScript.\r\n if (\r\n customLogicOptions.callback ||\r\n customLogicOptions.resources ||\r\n customLogicOptions.customCode\r\n ) {\r\n // Reset all custom code options\r\n customLogicOptions.callback = null;\r\n customLogicOptions.resources = null;\r\n customLogicOptions.customCode = null;\r\n\r\n // Send a message saying that the exporter does not support these settings\r\n throw new ExportError(\r\n `[chart] The 'callback', 'resources', and 'customCode' options have been disabled for this server.`,\r\n 403\r\n );\r\n }\r\n }\r\n}\r\n\r\n/**\r\n * Handles and validates resources from the `resources` option for export.\r\n *\r\n * @function _handleResources\r\n *\r\n * @param {(Object|string|null)} [resources=null] - The resources to be handled.\r\n * Can be either a JSON object, stringified JSON, a path to a JSON file,\r\n * or null. The default value is `null`.\r\n * @param {boolean} allowFileResources - A flag indicating whether loading\r\n * resources from files is allowed.\r\n * @param {boolean} allowCodeExecution - A flag indicating whether code\r\n * execution is allowed.\r\n *\r\n * @returns {(Object|null)} The handled resources or null if no valid resources\r\n * are found.\r\n */\r\nfunction _handleResources(\r\n resources = null,\r\n allowFileResources,\r\n allowCodeExecution\r\n) {\r\n let handledResources = resources;\r\n\r\n // If no resources found, try to load the default resources\r\n if (!handledResources) {\r\n resources = 'resources.json';\r\n }\r\n\r\n // List of allowed sections in the resources JSON\r\n const allowedProps = ['js', 'css', 'files'];\r\n\r\n // A flag that decides based to return resources or `null`\r\n let correctResources = false;\r\n\r\n // Try to load resources from a file\r\n if (\r\n allowFileResources &&\r\n typeof resources === 'string' &&\r\n resources.endsWith('.json')\r\n ) {\r\n handledResources = isAllowedConfig(\r\n readFileSync(getAbsolutePath(resources), 'utf8'),\r\n false,\r\n allowCodeExecution\r\n );\r\n } else {\r\n // Try to get JSON\r\n handledResources = isAllowedConfig(resources, false, allowCodeExecution);\r\n\r\n // Get rid of the files section\r\n if (handledResources && !allowFileResources) {\r\n delete handledResources.files;\r\n }\r\n }\r\n\r\n // Filter from unnecessary properties\r\n for (const propName in handledResources) {\r\n if (!allowedProps.includes(propName)) {\r\n delete handledResources[propName];\r\n } else if (!correctResources) {\r\n correctResources = true;\r\n }\r\n }\r\n\r\n // Check if at least one of allowed properties is present\r\n if (!correctResources) {\r\n return null;\r\n }\r\n\r\n // Handle files section\r\n if (handledResources.files) {\r\n handledResources.files = handledResources.files.map((item) => item.trim());\r\n if (!handledResources.files || handledResources.files.length <= 0) {\r\n delete handledResources.files;\r\n }\r\n }\r\n\r\n // Validate option\r\n handledResources = validateOption('resources', handledResources);\r\n\r\n // Return resources\r\n return handledResources;\r\n}\r\n\r\n/**\r\n * Handles custom code to execute it safely.\r\n *\r\n * @function _handleCustomCode\r\n *\r\n * @param {string} customCode - The custom code to be wrapped.\r\n * @param {boolean} allowFileResources - Flag to allow loading code from a file.\r\n * @param {boolean} [isCallback=false] - Flag that indicates the returned code\r\n * must be in a callback format.\r\n *\r\n * @returns {(string|null)} The wrapped custom code or null if wrapping fails.\r\n */\r\nfunction _handleCustomCode(customCode, allowFileResources, isCallback = false) {\r\n if (customCode && typeof customCode === 'string') {\r\n customCode = customCode.trim();\r\n\r\n if (customCode.endsWith('.js')) {\r\n // Load a file if the file resources are allowed\r\n return allowFileResources\r\n ? _handleCustomCode(\r\n readFileSync(getAbsolutePath(customCode), 'utf8'),\r\n allowFileResources,\r\n isCallback\r\n )\r\n : null;\r\n } else if (\r\n !isCallback &&\r\n (customCode.startsWith('function()') ||\r\n customCode.startsWith('function ()') ||\r\n customCode.startsWith('()=>') ||\r\n customCode.startsWith('() =>'))\r\n ) {\r\n // Treat a function as a self-invoking expression\r\n return `(${customCode})()`;\r\n }\r\n\r\n // Or return as a stringified code\r\n return customCode.replace(/;$/, '');\r\n }\r\n}\r\n\r\n/**\r\n * Handles the loading and validation of the `globalOptions` and `themeOptions`\r\n * in the export options. If the option is a string and references a JSON file\r\n * (when the `allowFileResources` is `true`), it reads and parses the file.\r\n * Otherwise, it attempts to parse the string or object as JSON. If any errors\r\n * occur during this process, the option is set to `null`. If there is an error\r\n * loading or parsing the `globalOptions` or `themeOptions`, the error is logged\r\n * and the option is set to `null`.\r\n *\r\n * @function _handleGlobalAndTheme\r\n *\r\n * @param {Object} exportOptions - The configuration object containing `export`\r\n * options.\r\n * @param {Object} customLogicOptions - The configuration object containing\r\n * `customLogic` options.\r\n */\r\nfunction _handleGlobalAndTheme(exportOptions, customLogicOptions) {\r\n // Get the `allowFileResources` and `allowCodeExecution` flags\r\n const { allowFileResources, allowCodeExecution } = customLogicOptions;\r\n\r\n // Check the `globalOptions` and `themeOptions` options\r\n ['globalOptions', 'themeOptions'].forEach((optionsName) => {\r\n try {\r\n // Check if the option exists\r\n if (exportOptions[optionsName]) {\r\n // Check if it is a string and a file name with the `.json` extension\r\n if (\r\n allowFileResources &&\r\n typeof exportOptions[optionsName] === 'string' &&\r\n exportOptions[optionsName].endsWith('.json')\r\n ) {\r\n // Check if the file content can be a config, and save it as a string\r\n exportOptions[optionsName] = isAllowedConfig(\r\n readFileSync(getAbsolutePath(exportOptions[optionsName]), 'utf8'),\r\n true,\r\n allowCodeExecution\r\n );\r\n } else {\r\n // Check if the value can be a config, and save it as a string\r\n exportOptions[optionsName] = isAllowedConfig(\r\n exportOptions[optionsName],\r\n true,\r\n allowCodeExecution\r\n );\r\n }\r\n\r\n // Validate the option\r\n exportOptions[optionsName] = validateOption(\r\n optionsName,\r\n exportOptions[optionsName]\r\n );\r\n }\r\n } catch (error) {\r\n logWithStack(\r\n 2,\r\n error,\r\n `[chart] The \\`${optionsName}\\` cannot be loaded.`\r\n );\r\n\r\n // In case of an error, set the option with null\r\n exportOptions[optionsName] = null;\r\n }\r\n });\r\n\r\n // Check if there is the `globalOptions` present\r\n if ([null, undefined].includes(exportOptions.globalOptions)) {\r\n log(3, '[chart] No value for the `globalOptions` option found.');\r\n }\r\n\r\n // Check if there is the `themeOptions` present\r\n if ([null, undefined].includes(exportOptions.themeOptions)) {\r\n log(3, '[chart] No value for the `themeOptions` option found.');\r\n }\r\n}\r\n\r\n/**\r\n * Validates the size of the data for the export process against a fixed limit\r\n * of 100MB.\r\n *\r\n * @function _checkDataSize\r\n *\r\n * @param {Object} imageOptions - The data object, which includes options from\r\n * the `export` and `customLogic` sections and will be sent to a Puppeteer page.\r\n *\r\n * @throws {ExportError} Throws an `ExportError` if the size of the data for\r\n * the export process object exceeds the 100MB limit.\r\n */\r\nfunction _checkDataSize(imageOptions) {\r\n // Set the fixed data limit (100MB) for the dev-tools protocol\r\n const dataLimit = 100 * 1024 * 1024;\r\n\r\n // Get the size of the data\r\n const totalSize = Buffer.byteLength(JSON.stringify(imageOptions), 'utf-8');\r\n\r\n // Log the size in MB\r\n log(\r\n 3,\r\n `[chart] The current total size of the data for the export process is around ${(\r\n totalSize /\r\n (1024 * 1024)\r\n ).toFixed(2)}MB.`\r\n );\r\n\r\n // Check the size of data before passing to a page\r\n if (totalSize >= dataLimit) {\r\n throw new ExportError(\r\n `[chart] The data for the export process exceeds 100MB limit.`\r\n );\r\n }\r\n}\r\n\r\nexport default {\r\n singleExport,\r\n batchExport,\r\n startExport,\r\n getAllowCodeExecution,\r\n setAllowCodeExecution\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * @overview This module provides utility functions for managing intervals\r\n * and timeouts in a centralized manner. It maintains a registry of all active\r\n * timers and allows for their efficient cleanup when needed to avoid potential\r\n * memory leaks, unintended behavior or a process from being stopped.\r\n */\r\n\r\nimport { log } from './logger.js';\r\n\r\n// Array that contains ids of all ongoing intervals and timeouts\r\nconst timerIds = [];\r\n\r\n/**\r\n * Adds id of the `setInterval` or `setTimeout` and to the `timerIds` array.\r\n *\r\n * @function addTimer\r\n *\r\n * @param {NodeJS.Timeout} id - Id of an interval or a timeout.\r\n */\r\nexport function addTimer(id) {\r\n timerIds.push(id);\r\n}\r\n\r\n/**\r\n * Clears all of ongoing intervals and timeouts by ids gathered\r\n * in the `timerIds` array.\r\n *\r\n * @function clearAllTimers\r\n */\r\nexport function clearAllTimers() {\r\n log(4, `[timer] Clearing all registered intervals and timeouts.`);\r\n for (const id of timerIds) {\r\n clearInterval(id);\r\n clearTimeout(id);\r\n }\r\n}\r\n\r\nexport default {\r\n addTimer,\r\n clearAllTimers\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * @overview Provides middleware functions for logging errors with stack traces\r\n * and handling error responses in an Express application.\r\n */\r\n\r\nimport { getOptions } from '../../config.js';\r\nimport { logWithStack } from '../../logger.js';\r\n\r\n/**\r\n * Middleware for logging errors with stack trace and handling error response.\r\n *\r\n * @function logErrorMiddleware\r\n *\r\n * @param {Error} error - The error object.\r\n * @param {Express.Request} request - The Express request object.\r\n * @param {Express.Response} response - The Express response object.\r\n * @param {Function} next - The next middleware function.\r\n *\r\n * @returns {undefined} The call to the next middleware function with\r\n * the passed error.\r\n */\r\nfunction logErrorMiddleware(error, request, response, next) {\r\n // Display the error with stack in a correct format\r\n logWithStack(1, error);\r\n\r\n // Delete the stack for the environment other than the development\r\n if (getOptions().other.nodeEnv !== 'development') {\r\n delete error.stack;\r\n }\r\n\r\n // Call the `returnErrorMiddleware` middleware\r\n return next(error);\r\n}\r\n\r\n/**\r\n * Middleware for returning error response.\r\n *\r\n * @function returnErrorMiddleware\r\n *\r\n * @param {Error} error - The error object.\r\n * @param {Express.Request} request - The Express request object.\r\n * @param {Express.Response} response - The Express response object.\r\n * @param {Function} next - The next middleware function.\r\n */\r\nfunction returnErrorMiddleware(error, request, response, next) {\r\n // Gather all requied information for the response\r\n const { message, stack } = error;\r\n\r\n // Use the error's status code or the default 400\r\n const statusCode = error.statusCode || 400;\r\n\r\n // Set and return response\r\n response.status(statusCode).json({ statusCode, message, stack });\r\n}\r\n\r\n/**\r\n * Adds the error middlewares to the passed express app instance.\r\n *\r\n * @param {Express} app - The Express app instance.\r\n */\r\nexport default function errorMiddleware(app) {\r\n // Add log error middleware\r\n app.use(logErrorMiddleware);\r\n\r\n // Add set status and return error middleware\r\n app.use(returnErrorMiddleware);\r\n}\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * @overview Provides middleware functions for configuring and enabling rate\r\n * limiting in an Express application.\r\n */\r\n\r\nimport rateLimit from 'express-rate-limit';\r\n\r\nimport { log } from '../../logger.js';\r\n\r\nimport ExportError from '../../errors/ExportError.js';\r\n\r\n/**\r\n * Middleware for enabling rate limiting on the specified Express app.\r\n *\r\n * @param {Express} app - The Express app instance.\r\n * @param {Object} rateLimitingOptions - The configuration object containing\r\n * `rateLimiting` options.\r\n *\r\n * @throws {ExportError} Throws an `ExportError` if could not configure and set\r\n * the rate limiting options.\r\n */\r\nexport default function rateLimitingMiddleware(app, rateLimitingOptions) {\r\n try {\r\n // Check if the rate limiting is enabled and the app exists\r\n if (app && rateLimitingOptions.enable) {\r\n const message =\r\n 'Too many requests, you have been rate limited. Please try again later.';\r\n\r\n // Options for the rate limiter\r\n const rateOptions = {\r\n window: rateLimitingOptions.window || 1,\r\n maxRequests: rateLimitingOptions.maxRequests || 30,\r\n delay: rateLimitingOptions.delay || 0,\r\n trustProxy: rateLimitingOptions.trustProxy || false,\r\n skipKey: rateLimitingOptions.skipKey || null,\r\n skipToken: rateLimitingOptions.skipToken || null\r\n };\r\n\r\n // Set if behind a proxy\r\n if (rateOptions.trustProxy) {\r\n app.enable('trust proxy');\r\n }\r\n\r\n // Create a limiter\r\n const limiter = rateLimit({\r\n // Time frame for which requests are checked and remembered\r\n windowMs: rateOptions.window * 60 * 1000,\r\n // Limit each IP to 100 requests per `windowMs`\r\n limit: rateOptions.maxRequests,\r\n // Disable delaying, full speed until the max limit is reached\r\n delayMs: rateOptions.delay,\r\n handler: (request, response) => {\r\n response.format({\r\n json: () => {\r\n response.status(429).send({ message });\r\n },\r\n default: () => {\r\n response.status(429).send(message);\r\n }\r\n });\r\n },\r\n skip: (request) => {\r\n // Allow bypassing the limiter if a valid key/token has been sent\r\n if (\r\n rateOptions.skipKey !== null &&\r\n rateOptions.skipToken !== null &&\r\n request.query.key === rateOptions.skipKey &&\r\n request.query.access_token === rateOptions.skipToken\r\n ) {\r\n log(4, '[rate limiting] Skipping rate limiter.');\r\n return true;\r\n }\r\n return false;\r\n }\r\n });\r\n\r\n // Use a limiter as a middleware\r\n app.use(limiter);\r\n\r\n log(\r\n 3,\r\n `[rate limiting] Enabled rate limiting with ${rateOptions.maxRequests} requests per ${rateOptions.window} minute for each IP, trusting proxy: ${rateOptions.trustProxy}.`\r\n );\r\n }\r\n } catch (error) {\r\n throw new ExportError(\r\n '[rate limiting] Could not configure and set the rate limiting options.',\r\n 500\r\n ).setError(error);\r\n }\r\n}\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * @overview Provides middleware functions for validating incoming HTTP requests\r\n * in an Express application. This module ensures that requests contain\r\n * appropriate content types and valid request bodies, including proper JSON\r\n * structures and chart data for exports. It checks for potential issues such\r\n * as missing or malformed data, private range URLs in SVG payloads, and allows\r\n * for flexible options validation. The middleware logs detailed information\r\n * and handles errors related to incorrect payloads, chart data, and private URL\r\n * usage.\r\n */\r\n\r\nimport { v4 as uuid } from 'uuid';\r\n\r\nimport { getAllowCodeExecution } from '../../chart.js';\r\nimport { isAllowedConfig } from '../../config.js';\r\nimport { log } from '../../logger.js';\r\nimport { isObjectEmpty, isPrivateRangeUrlFound } from '../../utils.js';\r\n\r\nimport ExportError from '../../errors/ExportError.js';\r\n\r\n/**\r\n * Middleware for validating the content-type header.\r\n *\r\n * @function contentTypeMiddleware\r\n *\r\n * @param {Express.Request} request - The Express request object.\r\n * @param {Express.Response} response - The Express response object.\r\n * @param {Function} next - The next middleware function.\r\n *\r\n * @returns {undefined} The call to the next middleware function.\r\n *\r\n * @throws {ExportError} Throws an `ExportError` if the content-type\r\n * is not correct.\r\n */\r\nfunction contentTypeMiddleware(request, response, next) {\r\n try {\r\n // Get the content type header\r\n const contentType = request.headers['content-type'] || '';\r\n\r\n // Allow only JSON, URL-encoded and form data without files types of data\r\n if (\r\n !contentType.includes('application/json') &&\r\n !contentType.includes('application/x-www-form-urlencoded') &&\r\n !contentType.includes('multipart/form-data')\r\n ) {\r\n throw new ExportError(\r\n '[validation] Content-Type must be application/json, application/x-www-form-urlencoded, or multipart/form-data.',\r\n 415\r\n );\r\n }\r\n\r\n // Call the `requestBodyMiddleware` middleware\r\n return next();\r\n } catch (error) {\r\n return next(error);\r\n }\r\n}\r\n\r\n/**\r\n * Middleware for validating the request's body.\r\n *\r\n * @function requestBodyMiddleware\r\n *\r\n * @param {Express.Request} request - The Express request object.\r\n * @param {Express.Response} response - The Express response object.\r\n * @param {Function} next - The next middleware function.\r\n *\r\n * @returns {undefined} The call to the next middleware function.\r\n *\r\n * @throws {ExportError} Throws an `ExportError` if the body is not correct.\r\n * @throws {ExportError} Throws an `ExportError` if the chart data from the body\r\n * is not correct.\r\n * @throws {ExportError} Throws an `ExportError` in case of the private range\r\n * url error.\r\n */\r\nfunction requestBodyMiddleware(request, response, next) {\r\n try {\r\n // Get the request body\r\n const body = request.body;\r\n\r\n // Create a unique ID for a request\r\n const requestId = uuid();\r\n\r\n // Throw an error if there is no correct body\r\n if (!body || isObjectEmpty(body)) {\r\n log(\r\n 2,\r\n `[validation] Request [${requestId}] - The request from ${\r\n request.headers['x-forwarded-for'] || request.connection.remoteAddress\r\n } was incorrect. Received payload is empty.`\r\n );\r\n\r\n throw new ExportError(\r\n `[validation] Request [${requestId}] - The request body is required. Please ensure that your Content-Type header is correct. Accepted types are 'application/json' and 'multipart/form-data'.`,\r\n 400\r\n );\r\n }\r\n\r\n // Get the `allowCodeExecution` option for the server\r\n const allowCodeExecution = getAllowCodeExecution();\r\n\r\n // Find a correct chart options\r\n const instr = isAllowedConfig(\r\n // Use one of the below\r\n body.instr || body.options || body.infile || body.data,\r\n // Stringify options\r\n true,\r\n // Allow or disallow functions\r\n allowCodeExecution\r\n );\r\n\r\n // Throw an error if there is no correct chart data\r\n if (instr === null && !body.svg) {\r\n log(\r\n 2,\r\n `[validation] Request [${requestId}] - The request from ${\r\n request.headers['x-forwarded-for'] || request.connection.remoteAddress\r\n } was incorrect. Received payload is missing correct chart data for export: ${JSON.stringify(body)}.`\r\n );\r\n\r\n throw new ExportError(\r\n `[validation] Request [${requestId}] - No correct chart data found. Ensure that you are using either application/json or multipart/form-data headers. If sending JSON, make sure the chart data is in the 'infile', 'options', or 'data' attribute. If sending SVG, ensure it is in the 'svg' attribute.`,\r\n 400\r\n );\r\n }\r\n\r\n // Throw an error if test of xlink:href elements from payload's SVG fails\r\n if (body.svg && isPrivateRangeUrlFound(body.svg)) {\r\n throw new ExportError(\r\n `[validation] Request [${requestId}] - SVG potentially contain at least one forbidden URL in 'xlink:href' element. Please review the SVG content and ensure that all referenced URLs comply with security policies.`,\r\n 400\r\n );\r\n }\r\n\r\n // Get and pre-validate the options and store them in the request\r\n request.validatedOptions = {\r\n // Set the created ID as a `requestId` property in the options\r\n requestId,\r\n export: {\r\n instr,\r\n svg: body.svg,\r\n outfile:\r\n body.outfile ||\r\n `${request.params.filename || 'chart'}.${body.type || 'png'}`,\r\n type: body.type,\r\n constr: body.constr,\r\n b64: body.b64,\r\n noDownload: body.noDownload,\r\n height: body.height,\r\n width: body.width,\r\n scale: body.scale,\r\n globalOptions: isAllowedConfig(\r\n body.globalOptions,\r\n true,\r\n allowCodeExecution\r\n ),\r\n themeOptions: isAllowedConfig(\r\n body.themeOptions,\r\n true,\r\n allowCodeExecution\r\n )\r\n },\r\n customLogic: {\r\n allowCodeExecution,\r\n allowFileResources: false,\r\n customCode: body.customCode,\r\n callback: body.callback,\r\n resources: isAllowedConfig(body.resources, true, allowCodeExecution)\r\n }\r\n };\r\n\r\n // Call the next middleware\r\n return next();\r\n } catch (error) {\r\n return next(error);\r\n }\r\n}\r\n\r\n/**\r\n * Adds the validation middlewares to the passed express app instance.\r\n *\r\n * @param {Express} app - The Express app instance.\r\n */\r\nexport default function validationMiddleware(app) {\r\n // Add content type validation middleware\r\n app.post(['/', '/:filename'], contentTypeMiddleware);\r\n\r\n // Add request body request validation middleware\r\n app.post(['/', '/:filename'], requestBodyMiddleware);\r\n}\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * @overview Defines the export routes and logic for handling chart export\r\n * requests in an Express server. This module processes incoming requests\r\n * to export charts in various formats (e.g. JPEG, PNG, PDF, SVG). It integrates\r\n * with Highcharts' core functionalities and supports both immediate download\r\n * responses and Base64-encoded content returns. The code also features\r\n * benchmarking for performance monitoring.\r\n */\r\n\r\nimport { startExport } from '../../chart.js';\r\nimport { log } from '../../logger.js';\r\nimport { getBase64, measureTime } from '../../utils.js';\r\n\r\nimport ExportError from '../../errors/ExportError.js';\r\n\r\n// Reversed MIME types\r\nconst reversedMime = {\r\n png: 'image/png',\r\n jpeg: 'image/jpeg',\r\n gif: 'image/gif',\r\n pdf: 'application/pdf',\r\n svg: 'image/svg+xml'\r\n};\r\n\r\n/**\r\n * Handles the export requests from the client.\r\n *\r\n * @async\r\n * @function requestExport\r\n *\r\n * @param {Express.Request} request - The Express request object.\r\n * @param {Express.Response} response - The Express response object.\r\n * @param {Function} next - The next middleware function.\r\n *\r\n * @returns {Promise} A Promise that resolves once the export process\r\n * is complete.\r\n */\r\nasync function requestExport(request, response, next) {\r\n try {\r\n // Start counting time for a request\r\n const requestCounter = measureTime();\r\n\r\n // In case the connection is closed, force to abort further actions\r\n let connectionAborted = false;\r\n request.socket.on('close', (hadErrors) => {\r\n if (hadErrors) {\r\n connectionAborted = true;\r\n }\r\n });\r\n\r\n // Get the options previously validated in the validation middleware\r\n const options = request.validatedOptions;\r\n\r\n // Get the request id\r\n const requestId = options.requestId;\r\n\r\n // Info about an incoming request with correct data\r\n log(4, `[export] Request [${requestId}] - Got an incoming HTTP request.`);\r\n\r\n // Start the export process\r\n await startExport(options, (error, data) => {\r\n // Remove the close event from the socket\r\n request.socket.removeAllListeners('close');\r\n\r\n // If the connection was closed, do nothing\r\n if (connectionAborted) {\r\n log(\r\n 3,\r\n `[export] Request [${requestId}] - The client closed the connection before the chart finished processing.`\r\n );\r\n return;\r\n }\r\n\r\n // If error, log it and send it to the error middleware\r\n if (error) {\r\n throw error;\r\n }\r\n\r\n // If data is missing, log the message and send it to the error middleware\r\n if (!data || !data.result) {\r\n log(\r\n 2,\r\n `[export] Request [${requestId}] - Request from ${\r\n request.headers['x-forwarded-for'] ||\r\n request.connection.remoteAddress\r\n } was incorrect. Received result is ${data.result}.`\r\n );\r\n\r\n throw new ExportError(\r\n `[export] Request [${requestId}] - Unexpected return of the export result from the chart generation. Please check your request data.`,\r\n 400\r\n );\r\n }\r\n\r\n // Return the result in an appropriate format\r\n if (data.result) {\r\n log(\r\n 3,\r\n `[export] Request [${requestId}] - The whole exporting process took ${requestCounter()}ms.`\r\n );\r\n\r\n // Get the `type`, `b64`, `noDownload`, and `outfile` from options\r\n const { type, b64, noDownload, outfile } = data.options.export;\r\n\r\n // If only Base64 is required, return it\r\n if (b64) {\r\n return response.send(getBase64(data.result, type));\r\n }\r\n\r\n // Set correct content type\r\n response.header('Content-Type', reversedMime[type] || 'image/png');\r\n\r\n // Decide whether to download or not chart file\r\n if (!noDownload) {\r\n response.attachment(outfile);\r\n }\r\n\r\n // If SVG, return plain content, otherwise a b64 string from a buffer\r\n return type === 'svg'\r\n ? response.send(data.result)\r\n : response.send(Buffer.from(data.result, 'base64'));\r\n }\r\n });\r\n } catch (error) {\r\n return next(error);\r\n }\r\n}\r\n\r\n/**\r\n * Adds the `export` routes.\r\n *\r\n * @function exportRoutes\r\n *\r\n * @param {Express} app - The Express app instance.\r\n */\r\nexport default function exportRoutes(app) {\r\n /**\r\n * Adds the POST '/' - A route for handling POST requests at the root\r\n * endpoint.\r\n */\r\n app.post('/', requestExport);\r\n\r\n /**\r\n * Adds the POST '/:filename' - A route for handling POST requests with\r\n * a specified filename parameter.\r\n */\r\n app.post('/:filename', requestExport);\r\n}\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * @overview Defines an Express route for server health monitoring, including\r\n * uptime, success rates, and other server statistics.\r\n */\r\n\r\nimport { readFileSync } from 'fs';\r\nimport { join } from 'path';\r\n\r\nimport { getHcVersion } from '../../cache.js';\r\nimport { log } from '../../logger.js';\r\nimport { getPoolInfoJSON, getPoolStats } from '../../pool.js';\r\nimport { addTimer } from '../../timer.js';\r\nimport { __dirname, getNewDateTime } from '../../utils.js';\r\n\r\n// Set the start date of the server\r\nconst serverStartTime = new Date();\r\n\r\n// Get the `package.json` content\r\nconst packageFile = JSON.parse(\r\n readFileSync(join(__dirname, 'package.json'), 'utf8')\r\n);\r\n\r\n// An array for success rate ratios\r\nconst successRates = [];\r\n\r\n// Record every minute\r\nconst recordInterval = 60 * 1000;\r\n\r\n// 30 minutes\r\nconst windowSize = 30;\r\n\r\n/**\r\n * Calculates moving average indicator based on the data from the `successRates`\r\n * array.\r\n *\r\n * @function _calculateMovingAverage\r\n *\r\n * @returns {number} A moving average for success ratio of the server exports.\r\n */\r\nfunction _calculateMovingAverage() {\r\n return successRates.reduce((a, b) => a + b, 0) / successRates.length;\r\n}\r\n\r\n/**\r\n * Starts the interval responsible for calculating current success rate ratio\r\n * and collects records to the `successRates` array.\r\n *\r\n * @function _startSuccessRate\r\n *\r\n * @returns {NodeJS.Timeout} Id of an interval.\r\n */\r\nfunction _startSuccessRate() {\r\n return setInterval(() => {\r\n const stats = getPoolStats();\r\n const successRatio =\r\n stats.exportsAttempted === 0\r\n ? 1\r\n : (stats.exportsPerformed / stats.exportsAttempted) * 100;\r\n\r\n successRates.push(successRatio);\r\n if (successRates.length > windowSize) {\r\n successRates.shift();\r\n }\r\n }, recordInterval);\r\n}\r\n\r\n/**\r\n * Adds the `health` routes.\r\n *\r\n * @function healthRoutes\r\n *\r\n * @param {Express} app - The Express app instance.\r\n */\r\nexport default function healthRoutes(app) {\r\n // Start processing success rate ratio interval and save its id to the array\r\n // for the graceful clearing on shutdown with injected `addTimer` funtion\r\n addTimer(_startSuccessRate());\r\n\r\n /**\r\n * Adds the GET '/health' - A route for getting the basic stats of the server.\r\n */\r\n app.get('/health', (request, response, next) => {\r\n try {\r\n log(4, '[health] Returning server health.');\r\n\r\n const stats = getPoolStats();\r\n const period = successRates.length;\r\n const movingAverage = _calculateMovingAverage();\r\n\r\n // Send the server's statistics\r\n response.send({\r\n // Status and times\r\n status: 'OK',\r\n bootTime: serverStartTime,\r\n uptime: `${Math.floor((getNewDateTime() - serverStartTime.getTime()) / 1000 / 60)} minutes`,\r\n\r\n // Versions\r\n serverVersion: packageFile.version,\r\n highchartsVersion: getHcVersion(),\r\n\r\n // Exports\r\n averageExportTime: stats.timeSpentAverage,\r\n attemptedExports: stats.exportsAttempted,\r\n performedExports: stats.exportsPerformed,\r\n failedExports: stats.exportsDropped,\r\n sucessRatio: (stats.exportsPerformed / stats.exportsAttempted) * 100,\r\n\r\n // Pool\r\n pool: getPoolInfoJSON(),\r\n\r\n // Moving average\r\n period,\r\n movingAverage,\r\n message:\r\n isNaN(movingAverage) || !successRates.length\r\n ? 'Too early to report. No exports made yet. Please check back soon.'\r\n : `Last ${period} minutes had a success rate of ${movingAverage.toFixed(2)}%.`,\r\n\r\n // SVG and JSON exports\r\n svgExports: stats.exportsFromSvg,\r\n jsonExports: stats.exportsFromOptions,\r\n svgExportsAttempts: stats.exportsFromSvgAttempts,\r\n jsonExportsAttempts: stats.exportsFromOptionsAttempts\r\n });\r\n } catch (error) {\r\n return next(error);\r\n }\r\n });\r\n}\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * @overview Defines an Express route for serving the UI for the export server\r\n * when enabled.\r\n */\r\n\r\nimport { join } from 'path';\r\n\r\nimport { getOptions } from '../../config.js';\r\nimport { log } from '../../logger.js';\r\nimport { __dirname } from '../../utils.js';\r\n\r\n/**\r\n * Adds the `ui` routes.\r\n *\r\n * @function uiRoutes\r\n *\r\n * @param {Express} app - The Express app instance.\r\n */\r\nexport default function uiRoutes(app) {\r\n // Add the UI endpoint only if required\r\n if (getOptions().ui.enable) {\r\n /**\r\n * Adds the GET '/' - A route for a UI when enabled on the export server.\r\n */\r\n app.get(getOptions().ui.route || '/', (request, response, next) => {\r\n try {\r\n log(4, '[ui] Returning UI for the export.');\r\n\r\n response.sendFile(join(__dirname, 'public', 'index.html'), {\r\n acceptRanges: false\r\n });\r\n } catch (error) {\r\n return next(error);\r\n }\r\n });\r\n }\r\n}\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * @overview Defines an Express route for updating the Highcharts version\r\n * on the server, with authentication and validation.\r\n */\r\n\r\nimport { getHcVersion, updateHcVersion } from '../../cache.js';\r\nimport { log } from '../../logger.js';\r\nimport { envs } from '../../validation.js';\r\n\r\nimport ExportError from '../../errors/ExportError.js';\r\n\r\n/**\r\n * Adds the `version_change` routes.\r\n *\r\n * @function versionChangeRoutes\r\n *\r\n * @param {Express} app - The Express app instance.\r\n */\r\nexport default function versionChangeRoutes(app) {\r\n /**\r\n * Adds the POST '/version_change/:newVersion' - A route for changing\r\n * the Highcharts version on the server.\r\n */\r\n app.post('/version_change/:newVersion', async (request, response, next) => {\r\n try {\r\n log(4, '[version] Changing Highcharts version.');\r\n\r\n // Get the token directly from envs\r\n const adminToken = envs.HIGHCHARTS_ADMIN_TOKEN;\r\n\r\n // Check the existence of the token\r\n if (!adminToken || !adminToken.length) {\r\n throw new ExportError(\r\n '[version] The server is not configured to perform run-time version changes: `HIGHCHARTS_ADMIN_TOKEN` is not set.',\r\n 401\r\n );\r\n }\r\n\r\n // Get the token from the hc-auth header\r\n const token = request.get('hc-auth');\r\n\r\n // Check if the hc-auth header contain a correct token\r\n if (!token || token !== adminToken) {\r\n throw new ExportError(\r\n '[version] Invalid or missing token: Set the token in the hc-auth header.',\r\n 401\r\n );\r\n }\r\n\r\n // Get the new version from the params\r\n const newVersion = request.params.newVersion;\r\n\r\n // Update version\r\n if (newVersion) {\r\n try {\r\n await updateHcVersion(newVersion);\r\n } catch (error) {\r\n throw new ExportError(\r\n `[version] Version change: ${error.message}`,\r\n 400\r\n ).setError(error);\r\n }\r\n\r\n // Success\r\n response.status(200).send({\r\n statusCode: 200,\r\n highchartsVersion: getHcVersion(),\r\n message: `Successfully updated Highcharts to version: ${newVersion}.`\r\n });\r\n } else {\r\n // No version specified\r\n throw new ExportError('[version] No new version supplied.', 400);\r\n }\r\n } catch (error) {\r\n return next(error);\r\n }\r\n });\r\n}\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * @overview A module that sets up and manages HTTP and HTTPS servers\r\n * for the Highcharts Export Server. It handles server initialization,\r\n * configuration, error handling, middlewares setup, route definition, and rate\r\n * limiting. The module exports functions to start, stop, and manage server\r\n * instances, as well as utility functions for defining routes and attaching\r\n * middlewares.\r\n */\r\n\r\nimport { readFileSync } from 'fs';\r\nimport { join } from 'path';\r\n\r\nimport cors from 'cors';\r\nimport express from 'express';\r\nimport http from 'http';\r\nimport https from 'https';\r\nimport multer from 'multer';\r\n\r\nimport { updateOptions } from '../config.js';\r\nimport { log, logWithStack } from '../logger.js';\r\nimport { __dirname, getAbsolutePath } from '../utils.js';\r\n\r\nimport errorMiddleware from './middlewares/error.js';\r\nimport rateLimitingMiddleware from './middlewares/rateLimiting.js';\r\nimport validationMiddleware from './middlewares/validation.js';\r\n\r\nimport exportRoutes from './routes/export.js';\r\nimport healthRoutes from './routes/health.js';\r\nimport uiRoutes from './routes/ui.js';\r\nimport versionChangeRoutes from './routes/versionChange.js';\r\n\r\nimport ExportError from '../errors/ExportError.js';\r\n\r\n// Array of an active servers\r\nconst activeServers = new Map();\r\n\r\n// Create express app\r\nconst app = express();\r\n\r\n/**\r\n * Starts an HTTP and/or HTTPS server based on the provided configuration.\r\n * The `serverOptions` object contains server-related properties (refer\r\n * to the `server` section in the `./lib/schemas/config.js` file for details).\r\n *\r\n * @async\r\n * @function startServer\r\n *\r\n * @param {Object} serverOptions - The configuration object containing `server`\r\n * options. This object may include a partial or complete set of the `server`\r\n * options. If the options are partial, missing values will default\r\n * to the current global configuration.\r\n *\r\n * @returns {Promise} A Promise that resolves when the server is either\r\n * not enabled or no valid Express app is found, signaling the end of the\r\n * function's execution.\r\n *\r\n * @throws {ExportError} Throws an `ExportError` if the server cannot\r\n * be configured and started.\r\n */\r\nexport async function startServer(serverOptions) {\r\n try {\r\n // Update the instance options object\r\n const options = updateOptions({\r\n server: serverOptions\r\n });\r\n\r\n // Use validated options\r\n serverOptions = options.server;\r\n\r\n // Stop if not enabled\r\n if (!serverOptions.enable || !app) {\r\n throw new ExportError(\r\n '[server] Server cannot be started (not enabled or no correct Express app found).',\r\n 500\r\n );\r\n }\r\n\r\n // Too big limits lead to timeouts in the export process when\r\n // the rasterization timeout is set too low\r\n const uploadLimitBytes = serverOptions.uploadLimit * 1024 * 1024;\r\n\r\n // Memory storage for multer package\r\n const storage = multer.memoryStorage();\r\n\r\n // Enable parsing of form data (files) with multer package\r\n const upload = multer({\r\n storage,\r\n limits: {\r\n fieldSize: uploadLimitBytes\r\n }\r\n });\r\n\r\n // Disable the X-Powered-By header\r\n app.disable('x-powered-by');\r\n\r\n // Enable CORS support\r\n app.use(\r\n cors({\r\n methods: ['POST', 'GET', 'OPTIONS']\r\n })\r\n );\r\n\r\n // Getting a lot of `RangeNotSatisfiableError` exceptions (even though this\r\n // is a deprecated options, let's try to set it to false)\r\n app.use((request, response, next) => {\r\n response.set('Accept-Ranges', 'none');\r\n next();\r\n });\r\n\r\n // Enable body parser for JSON data\r\n app.use(\r\n express.json({\r\n limit: uploadLimitBytes\r\n })\r\n );\r\n\r\n // Enable body parser for URL-encoded form data\r\n app.use(\r\n express.urlencoded({\r\n extended: true,\r\n limit: uploadLimitBytes\r\n })\r\n );\r\n\r\n // Use only non-file multipart form fields\r\n app.use(upload.none());\r\n\r\n // Set up static folder's route\r\n app.use(express.static(join(__dirname, 'public')));\r\n\r\n // Listen HTTP server\r\n if (!serverOptions.ssl.force) {\r\n // Main server instance (HTTP)\r\n const httpServer = http.createServer(app);\r\n\r\n // Attach error handlers and listen to the server\r\n _attachServerErrorHandlers(httpServer);\r\n\r\n // Listen\r\n httpServer.listen(serverOptions.port, serverOptions.host, () => {\r\n // Save the reference to HTTP server\r\n activeServers.set(serverOptions.port, httpServer);\r\n\r\n log(\r\n 3,\r\n `[server] Started HTTP server on ${serverOptions.host}:${serverOptions.port}.`\r\n );\r\n });\r\n }\r\n\r\n // Listen HTTPS server\r\n if (serverOptions.ssl.enable) {\r\n // Set up an SSL server also\r\n let key, cert;\r\n\r\n try {\r\n // Get the SSL key\r\n key = readFileSync(\r\n join(getAbsolutePath(serverOptions.ssl.certPath), 'server.key'),\r\n 'utf8'\r\n );\r\n\r\n // Get the SSL certificate\r\n cert = readFileSync(\r\n join(getAbsolutePath(serverOptions.ssl.certPath), 'server.crt'),\r\n 'utf8'\r\n );\r\n } catch (error) {\r\n log(\r\n 2,\r\n `[server] Unable to load key/certificate from the '${serverOptions.ssl.certPath}' path. Could not run secured layer server.`\r\n );\r\n }\r\n\r\n if (key && cert) {\r\n // Main server instance (HTTPS)\r\n const httpsServer = https.createServer({ key, cert }, app);\r\n\r\n // Attach error handlers and listen to the server\r\n _attachServerErrorHandlers(httpsServer);\r\n\r\n // Listen\r\n httpsServer.listen(serverOptions.ssl.port, serverOptions.host, () => {\r\n // Save the reference to HTTPS server\r\n activeServers.set(serverOptions.ssl.port, httpsServer);\r\n\r\n log(\r\n 3,\r\n `[server] Started HTTPS server on ${serverOptions.host}:${serverOptions.ssl.port}.`\r\n );\r\n });\r\n }\r\n }\r\n\r\n // Set up the rate limiter\r\n rateLimitingMiddleware(app, serverOptions.rateLimiting);\r\n\r\n // Set up the validation handler\r\n validationMiddleware(app);\r\n\r\n // Set up routes\r\n exportRoutes(app);\r\n healthRoutes(app);\r\n uiRoutes(app);\r\n versionChangeRoutes(app);\r\n\r\n // Set up the centralized error handler\r\n errorMiddleware(app);\r\n } catch (error) {\r\n throw new ExportError(\r\n '[server] Could not configure and start the server.',\r\n 500\r\n ).setError(error);\r\n }\r\n}\r\n\r\n/**\r\n * Closes all servers associated with Express app instance.\r\n *\r\n * @function closeServers\r\n */\r\nexport function closeServers() {\r\n // Check if there are servers working\r\n if (activeServers.size > 0) {\r\n log(4, `[server] Closing all servers.`);\r\n\r\n // Close each one of servers\r\n for (const [port, server] of activeServers) {\r\n server.close(() => {\r\n activeServers.delete(port);\r\n log(4, `[server] Closed server on port: ${port}.`);\r\n });\r\n }\r\n }\r\n}\r\n\r\n/**\r\n * Get all servers associated with Express app instance.\r\n *\r\n * @function getServers\r\n *\r\n * @returns {Array} Servers associated with Express app instance.\r\n */\r\nexport function getServers() {\r\n return activeServers;\r\n}\r\n\r\n/**\r\n * Get the Express instance.\r\n *\r\n * @function getExpress\r\n *\r\n * @returns {Express} The Express instance.\r\n */\r\nexport function getExpress() {\r\n return express;\r\n}\r\n\r\n/**\r\n * Get the Express app instance.\r\n *\r\n * @function getApp\r\n *\r\n * @returns {Express} The Express app instance.\r\n */\r\nexport function getApp() {\r\n return app;\r\n}\r\n\r\n/**\r\n * Enable rate limiting for the server.\r\n *\r\n * @function enableRateLimiting\r\n *\r\n * @param {Object} rateLimitingOptions - The configuration object containing\r\n * `rateLimiting` options. This object may include a partial or complete set\r\n * of the `rateLimiting` options. If the options are partial, missing values\r\n * will default to the current global configuration.\r\n */\r\nexport function enableRateLimiting(rateLimitingOptions) {\r\n // Update the instance options object\r\n const options = updateOptions({\r\n server: {\r\n rateLimiting: rateLimitingOptions\r\n }\r\n });\r\n\r\n // Set the rate limiting options\r\n rateLimitingMiddleware(app, options.server.rateLimitingOptions);\r\n}\r\n\r\n/**\r\n * Apply middleware(s) to a specific path.\r\n *\r\n * @function use\r\n *\r\n * @param {string} path - The path to which the middleware(s) should be applied.\r\n * @param {...Function} middlewares - The middleware function(s) to be applied.\r\n */\r\nexport function use(path, ...middlewares) {\r\n app.use(path, ...middlewares);\r\n}\r\n\r\n/**\r\n * Set up a route with GET method and apply middleware(s).\r\n *\r\n * @function get\r\n *\r\n * @param {string} path - The path to which the middleware(s) should be applied.\r\n * @param {...Function} middlewares - The middleware function(s) to be applied.\r\n */\r\nexport function get(path, ...middlewares) {\r\n app.get(path, ...middlewares);\r\n}\r\n\r\n/**\r\n * Set up a route with POST method and apply middleware(s).\r\n *\r\n * @function post\r\n *\r\n * @param {string} path - The path to which the middleware(s) should be applied.\r\n * @param {...Function} middlewares - The middleware function(s) to be applied.\r\n */\r\nexport function post(path, ...middlewares) {\r\n app.post(path, ...middlewares);\r\n}\r\n\r\n/**\r\n * Attach error handlers to the server.\r\n *\r\n * @function _attachServerErrorHandlers\r\n *\r\n * @param {(http.Server|https.Server)} server - The HTTP/HTTPS server instance.\r\n */\r\nfunction _attachServerErrorHandlers(server) {\r\n server.on('clientError', (error, socket) => {\r\n logWithStack(\r\n 1,\r\n error,\r\n `[server] Client error: ${error.message}, destroying socket.`\r\n );\r\n socket.destroy();\r\n });\r\n\r\n server.on('error', (error) => {\r\n logWithStack(1, error, `[server] Server error: ${error.message}`);\r\n });\r\n\r\n server.on('connection', (socket) => {\r\n socket.on('error', (error) => {\r\n logWithStack(1, error, `[server] Socket error: ${error.message}`);\r\n });\r\n });\r\n}\r\n\r\nexport default {\r\n startServer,\r\n closeServers,\r\n getServers,\r\n getExpress,\r\n getApp,\r\n enableRateLimiting,\r\n use,\r\n get,\r\n post\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * @overview Handles graceful shutdown of the Highcharts Export Server, ensuring\r\n * proper cleanup of resources such as browser, pages, servers, and timers.\r\n */\r\n\r\nimport { killPool } from './pool.js';\r\nimport { clearAllTimers } from './timer.js';\r\n\r\nimport { closeServers } from './server/server.js';\r\n\r\n/**\r\n * Performs cleanup operations to ensure a graceful shutdown of the process.\r\n * This includes clearing all registered timeouts/intervals, closing active\r\n * servers, terminating resources (pages) of the pool, pool itself, and closing\r\n * the browser.\r\n *\r\n * @function shutdownCleanUp\r\n *\r\n * @param {number} [exitCode=0] - The exit code to use with `process.exit()`.\r\n * The default value is `0`.\r\n */\r\nexport async function shutdownCleanUp(exitCode = 0) {\r\n // Await freeing all resources\r\n await Promise.allSettled([\r\n // Clear all ongoing intervals\r\n clearAllTimers(),\r\n\r\n // Get available server instances (HTTP/HTTPS) and close them\r\n closeServers(),\r\n\r\n // Close an active pool along with its workers and the browser instance\r\n killPool()\r\n ]);\r\n\r\n // Exit process with a correct code\r\n process.exit(exitCode);\r\n}\r\n\r\nexport default {\r\n shutdownCleanUp\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * @overview This core module initializes and manages the Highcharts Export\r\n * Server. The main `initExport` function handles logging, script caching,\r\n * resource pooling, browser startup, and ensures graceful process cleanup\r\n * on exit. Additionally, it provides API functions for using it as a Node.js\r\n * module, offering functionalities for processing options, configuring\r\n * and performing exports, and setting up server.\r\n */\r\n\r\nimport 'colors';\r\n\r\nimport { checkCache } from './cache.js';\r\nimport {\r\n batchExport,\r\n singleExport,\r\n startExport,\r\n setAllowCodeExecution\r\n} from './chart.js';\r\nimport {\r\n getOptions,\r\n updateOptions,\r\n mapToNewOptions,\r\n validateOption,\r\n validateOptions\r\n} from './config.js';\r\nimport {\r\n log,\r\n logWithStack,\r\n logZodIssues,\r\n initLogging,\r\n enableConsoleLogging,\r\n enableFileLogging,\r\n setLogLevel\r\n} from './logger.js';\r\nimport { initPool, killPool } from './pool.js';\r\nimport { shutdownCleanUp } from './resourceRelease.js';\r\n\r\nimport server from './server/server.js';\r\n\r\n/**\r\n * Initializes the export process. Tasks such as configuring logging, checking\r\n * the cache and sources, and initializing the resource pool occur during this\r\n * stage.\r\n *\r\n * This function must be called before attempting to export charts or set\r\n * up a server.\r\n *\r\n * @async\r\n * @function initExport\r\n *\r\n * @param {Object} initOptions - The `initOptions` object, which may\r\n * be a partial or complete set of options. If the options are partial, missing\r\n * values will default to the current global configuration.\r\n */\r\nexport async function initExport(initOptions) {\r\n // Init, validate and update the options object\r\n const options = updateOptions(initOptions);\r\n\r\n // Set the `allowCodeExecution` per export module scope\r\n setAllowCodeExecution(options.customLogic.allowCodeExecution);\r\n\r\n // Init the logging\r\n initLogging(options.logging);\r\n\r\n // Attach process' exit listeners\r\n if (options.other.listenToProcessExits) {\r\n _attachProcessExitListeners();\r\n }\r\n\r\n // Check the current status of cache\r\n await checkCache(options.highcharts, options.server.proxy);\r\n\r\n // Init the pool\r\n await initPool(options.pool, options.puppeteer.args);\r\n}\r\n\r\n/**\r\n * Attaches exit listeners to the process, ensuring proper cleanup of resources\r\n * and termination on exit signals. Handles 'exit', 'SIGINT', 'SIGTERM',\r\n * and 'uncaughtException' events.\r\n *\r\n * @function _attachProcessExitListeners\r\n */\r\nfunction _attachProcessExitListeners() {\r\n log(3, '[process] Attaching exit listeners to the process.');\r\n\r\n // Handler for the 'exit'\r\n process.on('exit', (code) => {\r\n log(4, `[process] Process exited with code: ${code}.`);\r\n });\r\n\r\n // Handler for the 'SIGINT'\r\n process.on('SIGINT', async (name, code) => {\r\n log(4, `[process] The ${name} event with code: ${code}.`);\r\n await shutdownCleanUp();\r\n });\r\n\r\n // Handler for the 'SIGTERM'\r\n process.on('SIGTERM', async (name, code) => {\r\n log(4, `[process] The ${name} event with code: ${code}.`);\r\n await shutdownCleanUp();\r\n });\r\n\r\n // Handler for the 'SIGHUP'\r\n process.on('SIGHUP', async (name, code) => {\r\n log(4, `[process] The ${name} event with code: ${code}.`);\r\n await shutdownCleanUp();\r\n });\r\n\r\n // Handler for the 'uncaughtException'\r\n process.on('uncaughtException', async (error, name) => {\r\n logWithStack(1, error, `[process] The ${name} error.`);\r\n await shutdownCleanUp(1);\r\n });\r\n}\r\n\r\nexport default {\r\n // Server\r\n ...server,\r\n\r\n // Options\r\n getOptions,\r\n updateOptions,\r\n mapToNewOptions,\r\n\r\n // Validation\r\n validateOption,\r\n validateOptions,\r\n\r\n // Exporting\r\n initExport,\r\n singleExport,\r\n batchExport,\r\n startExport,\r\n\r\n // Release\r\n killPool,\r\n shutdownCleanUp,\r\n\r\n // Logs\r\n log,\r\n logWithStack,\r\n logZodIssues,\r\n setLogLevel: function (level) {\r\n // Update the instance options object\r\n const options = updateOptions({\r\n logging: {\r\n level\r\n }\r\n });\r\n\r\n // Call the function\r\n setLogLevel(options.logging.level);\r\n },\r\n enableConsoleLogging: function (toConsole) {\r\n // Update the instance options object\r\n const options = updateOptions({\r\n logging: {\r\n toConsole\r\n }\r\n });\r\n\r\n // Call the function\r\n enableConsoleLogging(options.logging.toConsole);\r\n },\r\n enableFileLogging: function (dest, file, toFile) {\r\n // Update the instance options object\r\n const options = updateOptions({\r\n logging: {\r\n dest,\r\n file,\r\n toFile\r\n }\r\n });\r\n\r\n // Call the function\r\n enableFileLogging(\r\n options.logging.dest,\r\n options.logging.file,\r\n options.logging.toFile\r\n );\r\n }\r\n};\r\n"],"names":["__dirname","fileURLToPath","URL","url","deepCopy","objArr","objArrCopy","Array","isArray","key","Object","prototype","hasOwnProperty","call","getAbsolutePath","path","isAbsolute","normalize","resolve","getBase64","input","type","Buffer","from","toString","getNewDate","Date","split","trim","getNewDateTime","getTime","isObject","item","isObjectEmpty","keys","length","isPrivateRangeUrlFound","some","pattern","test","measureTime","start","process","hrtime","bigint","Number","roundNumber","value","precision","multiplier","Math","pow","round","colors","logging","toConsole","toFile","pathCreated","pathToLog","levelsDesc","title","color","log","args","newLevel","texts","level","prefix","_logToFile","console","apply","undefined","concat","logWithStack","error","customMessage","mainMessage","message","stackMessage","stack","push","shift","logZodIssues","issues","map","issue","join","initLogging","loggingOptions","dest","file","setLogLevel","enableConsoleLogging","enableFileLogging","isInteger","existsSync","mkdirSync","appendFile","defaultConfig","puppeteer","types","envLink","cliName","description","promptOptions","separator","highcharts","version","cdnUrl","forceFetch","cachePath","coreScripts","instructions","moduleScripts","indicatorScripts","customScripts","export","infile","instr","options","svg","batch","outfile","hint","choices","constr","b64","noDownload","height","width","scale","defaultHeight","defaultWidth","defaultScale","min","max","globalOptions","themeOptions","rasterizationTimeout","customLogic","allowCodeExecution","allowFileResources","customCode","callback","resources","loadConfig","legacyName","createConfig","server","enable","host","port","uploadLimit","benchmarking","proxy","timeout","rateLimiting","maxRequests","window","delay","trustProxy","skipKey","skipToken","ssl","force","certPath","pool","minWorkers","maxWorkers","workLimit","acquireTimeout","createTimeout","destroyTimeout","idleTimeout","createRetryInterval","reaperInterval","ui","route","other","nodeEnv","listenToProcessExits","noLogo","hardResetPage","browserShellMode","validation","debug","headless","devtools","listenToConsole","dumpio","slowMo","debuggingPort","dotenv","config","z","setErrorMap","_customErrorMap","v","boolean","strictCheck","union","enum","transform","includes","nullable","string","refine","params","errorMessage","values","stringArray","filterCallback","arraySchema","array","stringSchema","startsWith","slice","endsWith","transformCallback","filter","positiveNum","number","positive","isNaN","nonNegativeNum","nonnegative","prefixes","chartConfig","object","passthrough","additionalOptions","validators","adminToken","indexOf","gte","lte","this","objectSchema","js","css","files","partial","stringSchema1","stringSchema2","enableServer","serverBenchmarking","proxyHost","proxyPort","proxyTimeout","enableRateLimiting","enableSsl","sslForce","sslPort","sslCertPath","poolBenchmarking","resourcesInterval","logLevel","int","logFile","logDest","logToConsole","logToFile","enableUi","uiRoute","enableDebug","requestId","uuid","PuppeteerSchema","HighchartsSchema","ExportSchema","CustomLogicSchema","ProxySchema","RateLimitingSchema","SslSchema","ServerSchema","optional","PoolSchema","LoggingSchema","UiSchema","OtherSchema","DebugSchema","StrictConfigSchema","LooseConfigSchema","EnvSchema","PUPPETEER_ARGS","HIGHCHARTS_VERSION","HIGHCHARTS_CDN_URL","HIGHCHARTS_FORCE_FETCH","HIGHCHARTS_CACHE_PATH","HIGHCHARTS_ADMIN_TOKEN","HIGHCHARTS_CORE_SCRIPTS","HIGHCHARTS_MODULE_SCRIPTS","HIGHCHARTS_INDICATOR_SCRIPTS","HIGHCHARTS_CUSTOM_SCRIPTS","EXPORT_INFILE","EXPORT_INSTR","EXPORT_OPTIONS","EXPORT_SVG","EXPORT_BATCH","EXPORT_OUTFILE","EXPORT_TYPE","EXPORT_CONSTR","EXPORT_B64","EXPORT_NO_DOWNLOAD","EXPORT_HEIGHT","EXPORT_WIDTH","EXPORT_SCALE","EXPORT_DEFAULT_HEIGHT","EXPORT_DEFAULT_WIDTH","EXPORT_DEFAULT_SCALE","EXPORT_GLOBAL_OPTIONS","EXPORT_THEME_OPTIONS","EXPORT_RASTERIZATION_TIMEOUT","CUSTOM_LOGIC_ALLOW_CODE_EXECUTION","CUSTOM_LOGIC_ALLOW_FILE_RESOURCES","CUSTOM_LOGIC_CUSTOM_CODE","CUSTOM_LOGIC_CALLBACK","CUSTOM_LOGIC_RESOURCES","CUSTOM_LOGIC_LOAD_CONFIG","CUSTOM_LOGIC_CREATE_CONFIG","SERVER_ENABLE","SERVER_HOST","SERVER_PORT","SERVER_UPLOAD_LIMIT","SERVER_BENCHMARKING","SERVER_PROXY_HOST","SERVER_PROXY_PORT","SERVER_PROXY_TIMEOUT","SERVER_RATE_LIMITING_ENABLE","SERVER_RATE_LIMITING_MAX_REQUESTS","SERVER_RATE_LIMITING_WINDOW","SERVER_RATE_LIMITING_DELAY","SERVER_RATE_LIMITING_TRUST_PROXY","SERVER_RATE_LIMITING_SKIP_KEY","SERVER_RATE_LIMITING_SKIP_TOKEN","SERVER_SSL_ENABLE","SERVER_SSL_FORCE","SERVER_SSL_PORT","SERVER_SSL_CERT_PATH","POOL_MIN_WORKERS","POOL_MAX_WORKERS","POOL_WORK_LIMIT","POOL_ACQUIRE_TIMEOUT","POOL_CREATE_TIMEOUT","POOL_DESTROY_TIMEOUT","POOL_IDLE_TIMEOUT","POOL_CREATE_RETRY_INTERVAL","POOL_REAPER_INTERVAL","POOL_BENCHMARKING","LOGGING_LEVEL","LOGGING_FILE","LOGGING_DEST","LOGGING_TO_CONSOLE","LOGGING_TO_FILE","UI_ENABLE","UI_ROUTE","OTHER_NODE_ENV","OTHER_LISTEN_TO_PROCESS_EXITS","OTHER_NO_LOGO","OTHER_HARD_RESET_PAGE","OTHER_BROWSER_SHELL_MODE","OTHER_VALIDATION","DEBUG_ENABLE","DEBUG_HEADLESS","DEBUG_DEVTOOLS","DEBUG_LISTEN_TO_CONSOLE","DEBUG_DUMPIO","DEBUG_SLOW_MO","DEBUG_DEBUGGING_PORT","envs","parse","env","strictValidate","configOptions","looseValidate","context","propertyName","propertyInfo","code","ZodIssueCode","invalid_type","received","ZodParsedType","defaultError","custom","data","invalid_union","unionErrors","forEach","index","substring","ExportError","Error","constructor","statusCode","super","setError","name","_initOptions","nestedProps","_createNestedProps","absoluteProps","_createAbsoluteProps","getOptions","getCopy","updateOptions","newOptions","_mergeOptions","validateOptions","mapToNewOptions","oldOptions","entries","propertiesChain","reduce","obj","prop","validateOption","configOption","isAllowedConfig","allowFunctions","objectConfig","eval","JSON","stringifiedOptions","_optionsStringify","parsedOptions","_","originalOptions","stringifyFunctions","stringify","replaceAll","propChain","entry","async","get","requestOptions","Promise","reject","_getProtocolModule","response","responseData","on","chunk","text","https","http","cache","activeManifest","sources","hcVersion","checkCache","highchartsOptions","serverProxyOptions","fetchedModules","getCachePath","manifestPath","sourcePath","recursive","_updateCache","requestUpdate","manifest","readFileSync","modules","moduleMap","m","numberOfModules","moduleName","_extractHcVersion","_saveConfigToManifest","getHcVersion","updateHcVersion","newVersion","writeFileSync","_configureRequest","all","cs","_fetchScript","ms","is","script","shouldThrowError","_extractModuleName","agent","HttpsProxyAgent","cacheSources","replace","scriptPath","setupHighcharts","Highcharts","animObject","duration","createChart","exportOptions","customLogicOptions","setOptions","merge","wrap","setOptionsObj","isRenderComplete","Chart","proceed","userOptions","cb","exporting","enabled","plotOptions","series","label","tooltip","animation","onHighchartsRender","addEvent","Series","chart","Function","finalOptions","finalCallback","images","document","querySelectorAll","race","image","complete","naturalHeight","addEventListener","once","setTimeout","defaultOptions","pageTemplate","browser","createBrowser","puppeteerArgs","enabledDebug","debugOptions","launchOptions","userDataDir","handleSIGINT","handleSIGTERM","handleSIGHUP","waitForInitialPage","defaultViewport","tryCount","openBrowser","launch","closeBrowser","connected","close","newPage","poolResource","page","setCacheEnabled","_setPageContent","_setPageEvents","isClosed","clearPage","hardReset","goto","waitUntil","evaluate","body","innerHTML","id","workCount","addPageResources","injectedResources","injectedJs","content","isLocal","jsResource","addScriptTag","injectedCss","cssImports","match","cssImportPath","cssResource","addStyleTag","clearPageResources","resource","dispose","oldCharts","charts","oldChart","destroy","scriptsToRemove","getElementsByTagName","stylesToRemove","linksToRemove","element","remove","setContent","cssTemplate","svgTemplate","puppeteerExport","isSVG","size","_getChartSize","x","y","_getClipRegion","viewportHeight","abs","ceil","chartHeight","viewportWidth","chartWidth","result","setViewport","deviceScaleFactor","parseFloat","_createSVG","_createImage","_createPDF","$eval","getBoundingClientRect","trunc","svgElement","querySelector","baseVal","style","zoom","margin","outerHTML","clip","screenshot","encoding","fullPage","optimizeForSpeed","captureBeyondViewport","quality","omitBackground","_resolve","emulateMediaType","pdf","poolStats","exportsAttempted","exportsPerformed","exportsDropped","exportsFromSvg","exportsFromOptions","exportsFromSvgAttempts","exportsFromOptionsAttempts","timeSpent","timeSpentAverage","initPool","poolOptions","Pool","_factory","acquireTimeoutMillis","createTimeoutMillis","destroyTimeoutMillis","idleTimeoutMillis","createRetryIntervalMillis","reapIntervalMillis","propagateCreateError","clearStatus","_eventId","initialResources","i","acquire","promise","release","killPool","worker","used","destroyed","postWork","workerHandle","_getPoolInfo","acquireCounter","exportCounter","exportResult","getPoolStats","getPoolInfoJSON","numUsed","available","numFree","allCreated","pendingAcquires","numPendingAcquires","pendingCreates","numPendingCreates","pendingValidations","numPendingValidations","pendingDestroys","absoluteAll","create","random","startDate","validate","mainFrame","detached","removeAllListeners","sanitize","JSDOM","DOMPurify","ADD_TAGS","singleExport","startExport","batchExport","batchFunctions","pair","batchResults","allSettled","reason","imageOptions","endCallback","fileContent","_exportFromSvg","_exportFromOptions","getAllowCodeExecution","setAllowCodeExecution","inputToExport","_prepareExport","_fixConstr","_fixType","_fixOutfile","_handleCustomLogic","_handleGlobalAndTheme","_handleSize","_checkDataSize","fixedConstr","toLowerCase","mimeTypes","formats","outType","pop","find","t","optionsChart","optionsExporting","globalOptionsChart","globalOptionsExporting","themeOptionsChart","themeOptionsExporting","sourceHeight","sourceWidth","param","_handleResources","_handleCustomCode","handledResources","allowedProps","correctResources","propName","isCallback","optionsName","totalSize","byteLength","toFixed","timerIds","addTimer","clearAllTimers","clearInterval","clearTimeout","logErrorMiddleware","request","next","returnErrorMiddleware","status","json","errorMiddleware","app","use","rateLimitingMiddleware","rateLimitingOptions","rateOptions","limiter","rateLimit","windowMs","limit","delayMs","handler","format","send","default","skip","query","access_token","contentTypeMiddleware","contentType","headers","requestBodyMiddleware","connection","remoteAddress","validatedOptions","filename","validationMiddleware","post","reversedMime","png","jpeg","gif","requestExport","requestCounter","connectionAborted","socket","hadErrors","header","attachment","exportRoutes","serverStartTime","packageFile","successRates","recordInterval","windowSize","_calculateMovingAverage","a","b","_startSuccessRate","setInterval","stats","successRatio","healthRoutes","period","movingAverage","bootTime","uptime","floor","serverVersion","highchartsVersion","averageExportTime","attemptedExports","performedExports","failedExports","sucessRatio","svgExports","jsonExports","svgExportsAttempts","jsonExportsAttempts","uiRoutes","sendFile","acceptRanges","versionChangeRoutes","token","activeServers","Map","express","startServer","serverOptions","uploadLimitBytes","storage","multer","memoryStorage","upload","limits","fieldSize","disable","cors","methods","set","urlencoded","extended","none","static","httpServer","createServer","_attachServerErrorHandlers","listen","cert","httpsServer","closeServers","delete","getServers","getExpress","getApp","middlewares","shutdownCleanUp","exitCode","exit","initExport","initOptions","_attachProcessExitListeners"],"mappings":"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SAGVwF,WAAY,CACV9D,OAAO,EACPqD,MAAO,CAAC,WACRC,QAAS,yBACTE,YAAa,kDACbC,cAAe,CACbnF,KAAM,WAGVyF,UAAW,CACT/D,MAAO,SACPqD,MAAO,CAAC,UACRC,QAAS,wBACTE,YAAa,+CACbC,cAAe,CACbnF,KAAM,SAGV0F,YAAa,CACXhE,MAAO,CAAC,aAAc,kBAAmB,iBACzCqD,MAAO,CAAC,YACRC,QAAS,0BACTE,YAAa,mCACbC,cAAe,CACbnF,KAAM,cACN2F,aAAc,0DAGlBC,cAAe,CACblE,MAAO,CACL,QACA,MACA,QACA,YACA,uBACA,gBAEA,eACA,QACA,OACA,aACA,mBACA,eACA,cACA,UACA,UACA,cACA,WACA,UACA,YACA,cACA,YACA,sBACA,SACA,SACA,WACA,aACA,YACA,eACA,yBACA,SACA,eACA,YACA,kBACA,SACA,cACA,mBACA,eACA,kBACA,cACA,eAEA,cACA,WACA,eACA,WACA,SACA,OACA,WACA,YACA,SACA,qBACA,aACA,WACA,WACA,WACA,WACA,eACA,UACA,kBACA,oBACA,aACA,UACA,cACA,YACA,YAEFqD,MAAO,CAAC,YACRC,QAAS,4BACTE,YAAa,qCACbC,cAAe,CACbnF,KAAM,cACN2F,aAAc,0DAGlBE,iBAAkB,CAChBnE,MAAO,CAAC,kBACRqD,MAAO,CAAC,YACRC,QAAS,+BACTE,YAAa,wCACbC,cAAe,CACbnF,KAAM,cACN2F,aAAc,0DAGlBG,cAAe,CACbpE,MAAO,CACL,wEACA,kGAEFqD,MAAO,CAAC,YACRC,QAAS,4BACTE,YAAa,qDACbC,cAAe,CACbnF,KAAM,OACNoF,UAAW,OAIjBW,OAAQ,CACNC,OAAQ,CACNtE,MAAO,KACPqD,MAAO,CAAC,SAAU,QAClBC,QAAS,gBACTE,YACE,+DACFC,cAAe,CACbnF,KAAM,SAGViG,MAAO,CACLvE,MAAO,KACPqD,MAAO,CAAC,SAAU,SAAU,QAC5BC,QAAS,eACTE,YACE,mEACFC,cAAe,CACbnF,KAAM,SAGVkG,QAAS,CACPxE,MAAO,KACPqD,MAAO,CAAC,SAAU,S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"} \ No newline at end of file +{"version":3,"file":"index.esm.js","sources":["../lib/utils.js","../lib/logger.js","../lib/schemas/config.js","../lib/validation.js","../lib/errors/ExportError.js","../lib/config.js","../lib/fetch.js","../lib/cache.js","../lib/highcharts.js","../lib/browser.js","../templates/svgExport/css.js","../templates/svgExport/svgExport.js","../lib/export.js","../lib/pool.js","../lib/sanitize.js","../lib/chart.js","../lib/timer.js","../lib/server/middlewares/error.js","../lib/server/middlewares/rateLimiting.js","../lib/server/middlewares/validation.js","../lib/server/routes/export.js","../lib/server/routes/health.js","../lib/server/routes/ui.js","../lib/server/routes/versionChange.js","../lib/server/server.js","../lib/resourceRelease.js","../lib/index.js"],"sourcesContent":["/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * @overview The Highcharts Export Server utility module provides\r\n * a comprehensive set of helper functions and constants designed to streamline\r\n * and enhance various operations required for Highcharts export tasks.\r\n */\r\n\r\nimport { isAbsolute, normalize, resolve } from 'path';\r\nimport { fileURLToPath } from 'url';\r\n\r\nconst MAX_BACKOFF_ATTEMPTS = 6;\r\n\r\n// The directory path\r\nexport const __dirname = fileURLToPath(new URL('../.', import.meta.url));\r\n\r\n/**\r\n * Clears and standardizes text by replacing multiple consecutive whitespace\r\n * characters with a single space and trimming any leading or trailing\r\n * whitespace.\r\n *\r\n * @function clearText\r\n *\r\n * @param {string} text - The input text to be cleared.\r\n * @param {RegExp} [rule=/\\s\\s+/g] - The regular expression rule to match\r\n * multiple consecutive whitespace characters. The default value\r\n * is the '/\\s\\s+/g' RegExp.\r\n * @param {string} [replacer=' '] - The string used to replace multiple\r\n * consecutive whitespace characters. The default value is the ' ' string.\r\n *\r\n * @returns {string} The cleared and standardized text.\r\n */\r\nexport function clearText(text, rule = /\\s\\s+/g, replacer = ' ') {\r\n return text.replaceAll(rule, replacer).trim();\r\n}\r\n\r\n/**\r\n * Creates a deep copy of the given object or array.\r\n *\r\n * @function deepCopy\r\n *\r\n * @param {(Object|Array)} objArr - The object or array to be deeply copied.\r\n *\r\n * @returns {(Object|Array)} The deep copy of the provided object or array.\r\n */\r\nexport function deepCopy(objArr) {\r\n // If the `objArr` is null or not of the `object` type, return it\r\n if (objArr === null || typeof objArr !== 'object') {\r\n return objArr;\r\n }\r\n\r\n // Prepare either a new array or a new object\r\n const objArrCopy = Array.isArray(objArr) ? [] : {};\r\n\r\n // Recursively copy each property\r\n for (const key in objArr) {\r\n if (Object.prototype.hasOwnProperty.call(objArr, key)) {\r\n objArrCopy[key] = deepCopy(objArr[key]);\r\n }\r\n }\r\n\r\n // Return the copied object\r\n return objArrCopy;\r\n}\r\n\r\n/**\r\n * Implements an exponential backoff strategy for retrying a function until\r\n * a certain number of attempts are reached.\r\n *\r\n * @async\r\n * @function expBackoff\r\n *\r\n * @param {Function} fn - The function to be retried.\r\n * @param {number} [attempt=0] - The current attempt number. The default value\r\n * is `0`.\r\n * @param {...unknown} args - Arguments to be passed to the function.\r\n *\r\n * @returns {Promise} A Promise that resolves to the result\r\n * of the function if successful.\r\n *\r\n * @throws {Error} Throws an `Error` if the maximum number of attempts\r\n * is reached.\r\n */\r\nexport async function expBackoff(fn, attempt = 0, ...args) {\r\n try {\r\n // Try to call the function\r\n return await fn(...args);\r\n } catch (error) {\r\n // Calculate delay in ms\r\n const delayInMs = 2 ** attempt * 1000;\r\n\r\n // If the attempt exceeds the maximum attempts of repeat, throw an error\r\n if (++attempt >= MAX_BACKOFF_ATTEMPTS) {\r\n throw error;\r\n }\r\n\r\n // Wait given amount of time\r\n await new Promise((response) => setTimeout(response, delayInMs));\r\n\r\n /// TO DO: Correct\r\n // // Information about the resource timeout\r\n // log(\r\n // 3,\r\n // `[utils] Waited ${delayInMs}ms until next call for the resource of ID: ${args[0]}.`\r\n // );\r\n\r\n // Try again\r\n return expBackoff(fn, attempt, ...args);\r\n }\r\n}\r\n\r\n/**\r\n * Checks if the given path is relative or absolute and returns the corrected,\r\n * absolute path.\r\n *\r\n * @function getAbsolutePath\r\n *\r\n * @param {string} path - The path to be checked on.\r\n *\r\n * @returns {string} The absolute path.\r\n */\r\nexport function getAbsolutePath(path) {\r\n return isAbsolute(path) ? normalize(path) : resolve(path);\r\n}\r\n\r\n/**\r\n * Converts input data to a Base64 string based on the export type.\r\n *\r\n * @function getBase64\r\n *\r\n * @param {string} input - The input to be transformed to Base64 format.\r\n * @param {string} type - The original export type.\r\n *\r\n * @returns {string} The Base64 string representation of the input.\r\n */\r\nexport function getBase64(input, type) {\r\n // For pdf and svg types the input must be transformed to Base64 from a buffer\r\n if (type === 'pdf' || type == 'svg') {\r\n return Buffer.from(input, 'utf8').toString('base64');\r\n }\r\n\r\n // For png and jpeg input is already a Base64 string\r\n return input;\r\n}\r\n\r\n/**\r\n * Returns stringified date without the GMT text information.\r\n *\r\n * @function getNewDate\r\n */\r\nexport function getNewDate() {\r\n // Get rid of the GMT text information\r\n return new Date().toString().split('(')[0].trim();\r\n}\r\n\r\n/**\r\n * Returns the stored time value in milliseconds.\r\n *\r\n * @function getNewDateTime\r\n */\r\nexport function getNewDateTime() {\r\n return new Date().getTime();\r\n}\r\n\r\n/**\r\n * Checks if the given item is an object.\r\n *\r\n * @function isObject\r\n *\r\n * @param {unknown} item - The item to be checked.\r\n *\r\n * @returns {boolean} Returns `true` if the item is an object, `false`\r\n * otherwise.\r\n */\r\nexport function isObject(item) {\r\n return Object.prototype.toString.call(item) === '[object Object]';\r\n}\r\n\r\n/**\r\n * Checks if the given object is empty.\r\n *\r\n * @function isObjectEmpty\r\n *\r\n * @param {Object} item - The object to be checked.\r\n *\r\n * @returns {boolean} Returns `true` if the item is an empty object, `false`\r\n * otherwise.\r\n */\r\nexport function isObjectEmpty(item) {\r\n return (\r\n typeof item === 'object' &&\r\n !Array.isArray(item) &&\r\n item !== null &&\r\n Object.keys(item).length === 0\r\n );\r\n}\r\n\r\n/**\r\n * Checks if a private IP range URL is found in the given string.\r\n *\r\n * @function isPrivateRangeUrlFound\r\n *\r\n * @param {string} item - The string to be checked for a private IP range URL.\r\n *\r\n * @returns {boolean} Returns `true` if a private IP range URL is found, `false`\r\n * otherwise.\r\n */\r\nexport function isPrivateRangeUrlFound(item) {\r\n const regexPatterns = [\r\n /xlink:href=\"(?:http:\\/\\/|https:\\/\\/)?localhost\\b/,\r\n /xlink:href=\"(?:http:\\/\\/|https:\\/\\/)?10\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\b/,\r\n /xlink:href=\"(?:http:\\/\\/|https:\\/\\/)?127\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\b/,\r\n /xlink:href=\"(?:http:\\/\\/|https:\\/\\/)?172\\.(1[6-9]|2[0-9]|3[0-1])\\.\\d{1,3}\\.\\d{1,3}\\b/,\r\n /xlink:href=\"(?:http:\\/\\/|https:\\/\\/)?192\\.168\\.\\d{1,3}\\.\\d{1,3}\\b/\r\n ];\r\n\r\n return regexPatterns.some((pattern) => pattern.test(item));\r\n}\r\n\r\n/**\r\n * Utility to measure elapsed time using the Node.js `process.hrtime()` method.\r\n *\r\n * @function measureTime\r\n *\r\n * @returns {Function} A function to calculate the elapsed time in milliseconds.\r\n */\r\nexport function measureTime() {\r\n const start = process.hrtime.bigint();\r\n return () => Number(process.hrtime.bigint() - start) / 1000000;\r\n}\r\n\r\n/**\r\n * Rounds a number to the specified precision.\r\n *\r\n * @function roundNumber\r\n *\r\n * @param {number} value - The number to be rounded.\r\n * @param {number} precision - The number of decimal places to round to.\r\n *\r\n * @returns {number} The rounded number.\r\n */\r\nexport function roundNumber(value, precision = 1) {\r\n const multiplier = Math.pow(10, precision || 0);\r\n return Math.round(+value * multiplier) / multiplier;\r\n}\r\n\r\n/**\r\n * Converts a value to a boolean.\r\n *\r\n * @function toBoolean\r\n *\r\n * @param {unknown} item - The value to be converted to a boolean.\r\n *\r\n * @returns {boolean} The boolean representation of the input value.\r\n */\r\nexport function toBoolean(item) {\r\n return ['false', 'undefined', 'null', 'NaN', '0', ''].includes(item)\r\n ? false\r\n : !!item;\r\n}\r\n\r\nexport default {\r\n __dirname,\r\n clearText,\r\n deepCopy,\r\n expBackoff,\r\n getAbsolutePath,\r\n getBase64,\r\n getNewDate,\r\n getNewDateTime,\r\n isObject,\r\n isObjectEmpty,\r\n isPrivateRangeUrlFound,\r\n measureTime,\r\n roundNumber,\r\n toBoolean\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * @overview A module for managing logging functionality with customizable\r\n * log levels, console and file logging options, and error handling support.\r\n * The module also ensures that file-based logs are stored in a structured\r\n * directory, creating the necessary paths automatically if they do not exist.\r\n */\r\n\r\nimport { appendFile, existsSync, mkdirSync } from 'fs';\r\nimport { join } from 'path';\r\n\r\nimport { getAbsolutePath, getNewDate } from './utils.js';\r\n\r\n// The available colors\r\nconst colors = ['red', 'yellow', 'blue', 'gray', 'green'];\r\n\r\n// The default logging config\r\nconst logging = {\r\n // Flags for logging status\r\n toConsole: true,\r\n toFile: false,\r\n pathCreated: false,\r\n // Full path to the log file\r\n pathToLog: '',\r\n // Log levels\r\n levelsDesc: [\r\n {\r\n title: 'error',\r\n color: colors[0]\r\n },\r\n {\r\n title: 'warning',\r\n color: colors[1]\r\n },\r\n {\r\n title: 'notice',\r\n color: colors[2]\r\n },\r\n {\r\n title: 'verbose',\r\n color: colors[3]\r\n },\r\n {\r\n title: 'benchmark',\r\n color: colors[4]\r\n }\r\n ]\r\n};\r\n\r\n/**\r\n * Logs a message with a specified log level. Accepts a variable number\r\n * of arguments. The arguments after the `level` are passed to `console.log`\r\n * and/or used to construct and append messages to a log file.\r\n *\r\n * @function log\r\n *\r\n * @param {...unknown} args - An array of arguments where the first is the log\r\n * level and the remaining are strings used to build the log message.\r\n *\r\n * @returns {void} Exits the function execution if attempting to log at a level\r\n * higher than allowed.\r\n */\r\nexport function log(...args) {\r\n const [newLevel, ...texts] = args;\r\n\r\n // Current logging options\r\n const { levelsDesc, level } = logging;\r\n\r\n // Check if the log level is within a correct range or is it a benchmark log\r\n if (\r\n newLevel !== 5 &&\r\n (newLevel === 0 || newLevel > level || level > levelsDesc.length)\r\n ) {\r\n return;\r\n }\r\n\r\n // Create a message's prefix\r\n const prefix = `${getNewDate()} [${levelsDesc[newLevel - 1].title}] -`;\r\n\r\n // Log to file\r\n if (logging.toFile) {\r\n _logToFile(texts, prefix);\r\n }\r\n\r\n // Log to console\r\n if (logging.toConsole) {\r\n console.log.apply(\r\n undefined,\r\n [prefix.toString()[logging.levelsDesc[newLevel - 1].color]].concat(texts)\r\n );\r\n }\r\n}\r\n\r\n/**\r\n * Logs an error message along with its stack trace. Optionally, a custom\r\n * message can be provided.\r\n *\r\n * @function logWithStack\r\n *\r\n * @param {number} newLevel - The log level.\r\n * @param {Error} error - The error object containing the stack trace.\r\n * @param {string} customMessage - An optional custom message to be included\r\n * in the log alongside the error.\r\n *\r\n * @returns {void} Exits the function execution if attempting to log at a level\r\n * higher than allowed.\r\n */\r\nexport function logWithStack(newLevel, error, customMessage) {\r\n // Get the main message\r\n const mainMessage = customMessage || (error && error.message) || '';\r\n\r\n // Current logging options\r\n const { level, levelsDesc } = logging;\r\n\r\n // Check if the log level is within a correct range\r\n if (newLevel === 0 || newLevel > level || level > levelsDesc.length) {\r\n return;\r\n }\r\n\r\n // Create a message's prefix\r\n const prefix = `${getNewDate()} [${levelsDesc[newLevel - 1].title}] -`;\r\n\r\n // Add the whole stack message\r\n const stackMessage = error && error.stack;\r\n\r\n // Combine custom message or error message with error stack message, if exists\r\n const texts = [mainMessage];\r\n if (stackMessage) {\r\n texts.push('\\n', stackMessage);\r\n }\r\n\r\n // Log to file\r\n if (logging.toFile) {\r\n _logToFile(texts, prefix);\r\n }\r\n\r\n // Log to console\r\n if (logging.toConsole) {\r\n console.log.apply(\r\n undefined,\r\n [prefix.toString()[logging.levelsDesc[newLevel - 1].color]].concat([\r\n texts.shift()[colors[newLevel - 1]],\r\n ...texts\r\n ])\r\n );\r\n }\r\n}\r\n\r\n/**\r\n * Logs an error message related to Zod validation issues. Optionally, a custom\r\n * message can be provided.\r\n *\r\n * @function logZodIssues\r\n *\r\n * @param {number} newLevel - The log level.\r\n * @param {Error[]} issues - An array of Zod validation issues.\r\n * @param {string} customMessage - An optional custom message to be included\r\n * in the log alongside the error.\r\n */\r\nexport function logZodIssues(newLevel, issues, customMessage) {\r\n logWithStack(\r\n newLevel,\r\n null,\r\n [\r\n `${customMessage || '[validation] Validation error'} - the following Zod issues occured:`,\r\n ...(issues || []).map((issue) => `- ${issue.message}`)\r\n ].join('\\n')\r\n );\r\n}\r\n\r\n/**\r\n * Initializes logging with the specified logging configuration.\r\n *\r\n * @function initLogging\r\n *\r\n * @param {Object} loggingOptions - The configuration object containing\r\n * `logging` options.\r\n */\r\nexport function initLogging(loggingOptions) {\r\n // Get options from the `loggingOptions` object\r\n const { level, dest, file, toConsole, toFile } = loggingOptions;\r\n\r\n // Reset flags to the default values\r\n logging.pathCreated = false;\r\n logging.pathToLog = '';\r\n\r\n // Set the logging level\r\n setLogLevel(level);\r\n\r\n // Set the console logging\r\n enableConsoleLogging(toConsole);\r\n\r\n // Set the file logging\r\n enableFileLogging(dest, file, toFile);\r\n}\r\n\r\n/**\r\n * Sets the log level to the specified value. Log levels are (`0` = no logging,\r\n * `1` = error, `2` = warning, `3` = notice, `4` = verbose, or `5` = benchmark).\r\n *\r\n * @function setLogLevel\r\n *\r\n * @param {number} level - The log level to be set.\r\n */\r\nexport function setLogLevel(level) {\r\n if (\r\n Number.isInteger(level) &&\r\n level >= 0 &&\r\n level <= logging.levelsDesc.length\r\n ) {\r\n // Update the module logging's `level` option\r\n logging.level = level;\r\n }\r\n}\r\n\r\n/**\r\n * Enables console logging.\r\n *\r\n * @function enableConsoleLogging\r\n *\r\n * @param {boolean} toConsole - The flag for setting the logging to the console.\r\n */\r\nexport function enableConsoleLogging(toConsole) {\r\n // Update the module logging's `toConsole` option\r\n logging.toConsole = !!toConsole;\r\n}\r\n\r\n/**\r\n * Enables file logging with the specified destination and log file name.\r\n *\r\n * @function enableFileLogging\r\n *\r\n * @param {string} dest - The destination path where the log file should\r\n * be saved.\r\n * @param {string} file - The name of the log file.\r\n * @param {boolean} toFile - A flag indicating whether logging should\r\n * be directed to a file.\r\n */\r\nexport function enableFileLogging(dest, file, toFile) {\r\n // Update the module logging's `toFile` option\r\n logging.toFile = !!toFile;\r\n\r\n // Set the `dest` and `file` options only if the file logging is enabled\r\n if (logging.toFile) {\r\n logging.dest = dest || 'log';\r\n logging.file = file || 'highcharts-export-server.log';\r\n }\r\n}\r\n\r\n/**\r\n * Logs the provided texts to a file, if file logging is enabled. It creates\r\n * the necessary directory structure if not already created and appends\r\n * the content, including an optional prefix, to the specified log file.\r\n *\r\n * @function _logToFile\r\n *\r\n * @param {Array} texts - An array of texts to be logged.\r\n * @param {string} prefix - An optional prefix to be added to each log entry.\r\n */\r\nfunction _logToFile(texts, prefix) {\r\n if (!logging.pathCreated) {\r\n // Create if does not exist\r\n !existsSync(getAbsolutePath(logging.dest)) &&\r\n mkdirSync(getAbsolutePath(logging.dest));\r\n\r\n // Create the full path\r\n logging.pathToLog = getAbsolutePath(join(logging.dest, logging.file));\r\n\r\n // We now assume the path is available, e.g. it's the responsibility\r\n // of the user to create the path with the correct access rights.\r\n logging.pathCreated = true;\r\n }\r\n\r\n // Add the content to a file\r\n appendFile(\r\n logging.pathToLog,\r\n [prefix].concat(texts).join(' ') + '\\n',\r\n (error) => {\r\n if (error && logging.toFile && logging.pathCreated) {\r\n logging.toFile = false;\r\n logging.pathCreated = false;\r\n logWithStack(2, error, `[logger] Unable to write to log file.`);\r\n }\r\n }\r\n );\r\n}\r\n\r\nexport default {\r\n log,\r\n logWithStack,\r\n logZodIssues,\r\n initLogging,\r\n setLogLevel,\r\n enableConsoleLogging,\r\n enableFileLogging\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * @overview Configuration management module for the Highcharts Export Server.\r\n * It provides a default configuration object with predefined default values,\r\n * descriptions, and characteristics for each option used in the Export Server.\r\n */\r\n\r\n/**\r\n * The default configuration object containing all available options, organized\r\n * by sections.\r\n *\r\n * This object includes:\r\n * - Default values for each option.\r\n * - Data types for validation.\r\n * - Names of corresponding environment variables.\r\n * - Descriptions of each property.\r\n * - Information used for prompts in interactive configuration.\r\n * - [Optional] Corresponding CLI argument names for CLI usage.\r\n * - [Optional] Legacy names from the previous PhantomJS-based server.\r\n */\r\nconst defaultConfig = {\r\n puppeteer: {\r\n args: {\r\n value: [\r\n '--allow-running-insecure-content',\r\n '--ash-no-nudges',\r\n '--autoplay-policy=user-gesture-required',\r\n '--block-new-web-contents',\r\n '--disable-accelerated-2d-canvas',\r\n '--disable-background-networking',\r\n '--disable-background-timer-throttling',\r\n '--disable-backgrounding-occluded-windows',\r\n '--disable-breakpad',\r\n '--disable-checker-imaging',\r\n '--disable-client-side-phishing-detection',\r\n '--disable-component-extensions-with-background-pages',\r\n '--disable-component-update',\r\n '--disable-default-apps',\r\n '--disable-dev-shm-usage',\r\n '--disable-domain-reliability',\r\n '--disable-extensions',\r\n '--disable-features=CalculateNativeWinOcclusion,InterestFeedContentSuggestions,WebOTP',\r\n '--disable-hang-monitor',\r\n '--disable-ipc-flooding-protection',\r\n '--disable-logging',\r\n '--disable-notifications',\r\n '--disable-offer-store-unmasked-wallet-cards',\r\n '--disable-popup-blocking',\r\n '--disable-print-preview',\r\n '--disable-prompt-on-repost',\r\n '--disable-renderer-backgrounding',\r\n '--disable-search-engine-choice-screen',\r\n '--disable-session-crashed-bubble',\r\n '--disable-setuid-sandbox',\r\n '--disable-site-isolation-trials',\r\n '--disable-speech-api',\r\n '--disable-sync',\r\n '--enable-unsafe-webgpu',\r\n '--hide-crash-restore-bubble',\r\n '--hide-scrollbars',\r\n '--metrics-recording-only',\r\n '--mute-audio',\r\n '--no-default-browser-check',\r\n '--no-first-run',\r\n '--no-pings',\r\n '--no-sandbox',\r\n '--no-startup-window',\r\n '--no-zygote',\r\n '--password-store=basic',\r\n '--process-per-tab',\r\n '--use-mock-keychain'\r\n ],\r\n types: ['string[]'],\r\n envLink: 'PUPPETEER_ARGS',\r\n cliName: 'puppeteerArgs',\r\n description: 'Array of Puppeteer arguments',\r\n promptOptions: {\r\n type: 'list',\r\n separator: ';'\r\n }\r\n }\r\n },\r\n highcharts: {\r\n version: {\r\n value: 'latest',\r\n types: ['string'],\r\n envLink: 'HIGHCHARTS_VERSION',\r\n description: 'Highcharts version',\r\n promptOptions: {\r\n type: 'text'\r\n }\r\n },\r\n cdnUrl: {\r\n value: 'https://code.highcharts.com',\r\n types: ['string'],\r\n envLink: 'HIGHCHARTS_CDN_URL',\r\n description: 'CDN URL for Highcharts scripts',\r\n promptOptions: {\r\n type: 'text'\r\n }\r\n },\r\n forceFetch: {\r\n value: false,\r\n types: ['boolean'],\r\n envLink: 'HIGHCHARTS_FORCE_FETCH',\r\n description: 'Flag to refetch scripts after each server rerun',\r\n promptOptions: {\r\n type: 'toggle'\r\n }\r\n },\r\n cachePath: {\r\n value: '.cache',\r\n types: ['string'],\r\n envLink: 'HIGHCHARTS_CACHE_PATH',\r\n description: 'Directory path for cached Highcharts scripts',\r\n promptOptions: {\r\n type: 'text'\r\n }\r\n },\r\n coreScripts: {\r\n value: ['highcharts', 'highcharts-more', 'highcharts-3d'],\r\n types: ['string[]'],\r\n envLink: 'HIGHCHARTS_CORE_SCRIPTS',\r\n description: 'Highcharts core scripts to fetch',\r\n promptOptions: {\r\n type: 'multiselect',\r\n instructions: 'Space: Select specific, A: Select all, Enter: Confirm'\r\n }\r\n },\r\n moduleScripts: {\r\n value: [\r\n 'stock',\r\n 'map',\r\n 'gantt',\r\n 'exporting',\r\n 'parallel-coordinates',\r\n 'accessibility',\r\n // 'annotations-advanced',\r\n 'boost-canvas',\r\n 'boost',\r\n 'data',\r\n 'data-tools',\r\n 'draggable-points',\r\n 'static-scale',\r\n 'broken-axis',\r\n 'heatmap',\r\n 'tilemap',\r\n 'tiledwebmap',\r\n 'timeline',\r\n 'treemap',\r\n 'treegraph',\r\n 'item-series',\r\n 'drilldown',\r\n 'histogram-bellcurve',\r\n 'bullet',\r\n 'funnel',\r\n 'funnel3d',\r\n 'geoheatmap',\r\n 'pyramid3d',\r\n 'networkgraph',\r\n 'overlapping-datalabels',\r\n 'pareto',\r\n 'pattern-fill',\r\n 'pictorial',\r\n 'price-indicator',\r\n 'sankey',\r\n 'arc-diagram',\r\n 'dependency-wheel',\r\n 'series-label',\r\n 'series-on-point',\r\n 'solid-gauge',\r\n 'sonification',\r\n // 'stock-tools',\r\n 'streamgraph',\r\n 'sunburst',\r\n 'variable-pie',\r\n 'variwide',\r\n 'vector',\r\n 'venn',\r\n 'windbarb',\r\n 'wordcloud',\r\n 'xrange',\r\n 'no-data-to-display',\r\n 'drag-panes',\r\n 'debugger',\r\n 'dumbbell',\r\n 'lollipop',\r\n 'cylinder',\r\n 'organization',\r\n 'dotplot',\r\n 'marker-clusters',\r\n 'hollowcandlestick',\r\n 'heikinashi',\r\n 'flowmap',\r\n 'export-data',\r\n 'navigator',\r\n 'textpath'\r\n ],\r\n types: ['string[]'],\r\n envLink: 'HIGHCHARTS_MODULE_SCRIPTS',\r\n description: 'Highcharts module scripts to fetch',\r\n promptOptions: {\r\n type: 'multiselect',\r\n instructions: 'Space: Select specific, A: Select all, Enter: Confirm'\r\n }\r\n },\r\n indicatorScripts: {\r\n value: ['indicators-all'],\r\n types: ['string[]'],\r\n envLink: 'HIGHCHARTS_INDICATOR_SCRIPTS',\r\n description: 'Highcharts indicator scripts to fetch',\r\n promptOptions: {\r\n type: 'multiselect',\r\n instructions: 'Space: Select specific, A: Select all, Enter: Confirm'\r\n }\r\n },\r\n customScripts: {\r\n value: [\r\n 'https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.30.1/moment.min.js',\r\n 'https://cdnjs.cloudflare.com/ajax/libs/moment-timezone/0.5.45/moment-timezone-with-data.min.js'\r\n ],\r\n types: ['string[]'],\r\n envLink: 'HIGHCHARTS_CUSTOM_SCRIPTS',\r\n description: 'Additional custom scripts or dependencies to fetch',\r\n promptOptions: {\r\n type: 'list',\r\n separator: ';'\r\n }\r\n }\r\n },\r\n export: {\r\n infile: {\r\n value: null,\r\n types: ['string', 'null'],\r\n envLink: 'EXPORT_INFILE',\r\n description:\r\n 'Input filename with type, formatted correctly as JSON or SVG',\r\n promptOptions: {\r\n type: 'text'\r\n }\r\n },\r\n instr: {\r\n value: null,\r\n types: ['Object', 'string', 'null'],\r\n envLink: 'EXPORT_INSTR',\r\n description:\r\n 'Overrides the `infile` with JSON, stringified JSON, or SVG input',\r\n promptOptions: {\r\n type: 'text'\r\n }\r\n },\r\n options: {\r\n value: null,\r\n types: ['Object', 'string', 'null'],\r\n envLink: 'EXPORT_OPTIONS',\r\n description: 'Alias for the `instr` option',\r\n promptOptions: {\r\n type: 'text'\r\n }\r\n },\r\n svg: {\r\n value: null,\r\n types: ['string', 'null'],\r\n envLink: 'EXPORT_SVG',\r\n description: 'SVG string representation of the chart to render',\r\n promptOptions: {\r\n type: 'text'\r\n }\r\n },\r\n batch: {\r\n value: null,\r\n types: ['string', 'null'],\r\n envLink: 'EXPORT_BATCH',\r\n description:\r\n 'Batch job string with input/output pairs: \"in=out;in=out;...\"',\r\n promptOptions: {\r\n type: 'text'\r\n }\r\n },\r\n outfile: {\r\n value: null,\r\n types: ['string', 'null'],\r\n envLink: 'EXPORT_OUTFILE',\r\n description:\r\n 'Output filename with type. Can be jpeg, png, pdf, or svg and ignores `type` option',\r\n promptOptions: {\r\n type: 'text'\r\n }\r\n },\r\n type: {\r\n value: 'png',\r\n types: ['string'],\r\n envLink: 'EXPORT_TYPE',\r\n description: 'File export format. Can be jpeg, png, pdf, or svg',\r\n promptOptions: {\r\n type: 'select',\r\n hint: 'Default: png',\r\n choices: ['png', 'jpeg', 'pdf', 'svg']\r\n }\r\n },\r\n constr: {\r\n value: 'chart',\r\n types: ['string'],\r\n envLink: 'EXPORT_CONSTR',\r\n description:\r\n 'Chart constructor. Can be chart, stockChart, mapChart, or ganttChart',\r\n promptOptions: {\r\n type: 'select',\r\n hint: 'Default: chart',\r\n choices: ['chart', 'stockChart', 'mapChart', 'ganttChart']\r\n }\r\n },\r\n b64: {\r\n value: false,\r\n types: ['boolean'],\r\n envLink: 'EXPORT_B64',\r\n description:\r\n 'Whether or not to the chart should be received in Base64 format instead of binary',\r\n promptOptions: {\r\n type: 'toggle'\r\n }\r\n },\r\n noDownload: {\r\n value: false,\r\n types: ['boolean'],\r\n envLink: 'EXPORT_NO_DOWNLOAD',\r\n description:\r\n 'Whether or not to include or exclude attachment headers in the response',\r\n promptOptions: {\r\n type: 'toggle'\r\n }\r\n },\r\n height: {\r\n value: null,\r\n types: ['number', 'null'],\r\n envLink: 'EXPORT_HEIGHT',\r\n description: 'Height of the exported chart, overrides chart settings',\r\n promptOptions: {\r\n type: 'number'\r\n }\r\n },\r\n width: {\r\n value: null,\r\n types: ['number', 'null'],\r\n envLink: 'EXPORT_WIDTH',\r\n description: 'Width of the exported chart, overrides chart settings',\r\n promptOptions: {\r\n type: 'number'\r\n }\r\n },\r\n scale: {\r\n value: null,\r\n types: ['number', 'null'],\r\n envLink: 'EXPORT_SCALE',\r\n description:\r\n 'Scale of the exported chart, overrides chart settings. Ranges from 0.1 to 5.0',\r\n promptOptions: {\r\n type: 'number'\r\n }\r\n },\r\n defaultHeight: {\r\n value: 400,\r\n types: ['number'],\r\n envLink: 'EXPORT_DEFAULT_HEIGHT',\r\n description: 'Default height of the exported chart if not set',\r\n promptOptions: {\r\n type: 'number'\r\n }\r\n },\r\n defaultWidth: {\r\n value: 600,\r\n types: ['number'],\r\n envLink: 'EXPORT_DEFAULT_WIDTH',\r\n description: 'Default width of the exported chart if not set',\r\n promptOptions: {\r\n type: 'number'\r\n }\r\n },\r\n defaultScale: {\r\n value: 1,\r\n types: ['number'],\r\n envLink: 'EXPORT_DEFAULT_SCALE',\r\n description:\r\n 'Default scale of the exported chart if not set. Ranges from 0.1 to 5.0',\r\n promptOptions: {\r\n type: 'number',\r\n min: 0.1,\r\n max: 5\r\n }\r\n },\r\n globalOptions: {\r\n value: null,\r\n types: ['Object', 'string', 'null'],\r\n envLink: 'EXPORT_GLOBAL_OPTIONS',\r\n description:\r\n 'JSON, stringified JSON or filename with global options for Highcharts.setOptions',\r\n promptOptions: {\r\n type: 'text'\r\n }\r\n },\r\n themeOptions: {\r\n value: null,\r\n types: ['Object', 'string', 'null'],\r\n envLink: 'EXPORT_THEME_OPTIONS',\r\n description:\r\n 'JSON, stringified JSON or filename with theme options for Highcharts.setOptions',\r\n promptOptions: {\r\n type: 'text'\r\n }\r\n },\r\n rasterizationTimeout: {\r\n value: 1500,\r\n types: ['number'],\r\n envLink: 'EXPORT_RASTERIZATION_TIMEOUT',\r\n description: 'Milliseconds to wait for webpage rendering',\r\n promptOptions: {\r\n type: 'number'\r\n }\r\n }\r\n },\r\n customLogic: {\r\n allowCodeExecution: {\r\n value: false,\r\n types: ['boolean'],\r\n envLink: 'CUSTOM_LOGIC_ALLOW_CODE_EXECUTION',\r\n description:\r\n 'Allows or disallows execution of arbitrary code during exporting',\r\n promptOptions: {\r\n type: 'toggle'\r\n }\r\n },\r\n allowFileResources: {\r\n value: false,\r\n types: ['boolean'],\r\n envLink: 'CUSTOM_LOGIC_ALLOW_FILE_RESOURCES',\r\n description:\r\n 'Allows or disallows injection of filesystem resources (disabled in server mode)',\r\n promptOptions: {\r\n type: 'toggle'\r\n }\r\n },\r\n customCode: {\r\n value: null,\r\n types: ['string', 'null'],\r\n envLink: 'CUSTOM_LOGIC_CUSTOM_CODE',\r\n description:\r\n 'Custom code to execute before chart initialization. Can be a function, code wrapped in a function, or a .js filename',\r\n promptOptions: {\r\n type: 'text'\r\n }\r\n },\r\n callback: {\r\n value: null,\r\n types: ['string', 'null'],\r\n envLink: 'CUSTOM_LOGIC_CALLBACK',\r\n description:\r\n 'JavaScript code to run during construction. Can be a function or a .js filename',\r\n promptOptions: {\r\n type: 'text'\r\n }\r\n },\r\n resources: {\r\n value: null,\r\n types: ['Object', 'string', 'null'],\r\n envLink: 'CUSTOM_LOGIC_RESOURCES',\r\n description:\r\n 'Additional resources as JSON, stringified JSON, or filename, containing files, js, and css sections',\r\n promptOptions: {\r\n type: 'text'\r\n }\r\n },\r\n loadConfig: {\r\n value: null,\r\n types: ['string', 'null'],\r\n envLink: 'CUSTOM_LOGIC_LOAD_CONFIG',\r\n legacyName: 'fromFile',\r\n description: 'File with a pre-defined configuration to use',\r\n promptOptions: {\r\n type: 'text'\r\n }\r\n },\r\n createConfig: {\r\n value: null,\r\n types: ['string', 'null'],\r\n envLink: 'CUSTOM_LOGIC_CREATE_CONFIG',\r\n description:\r\n 'Prompt-based option setting, saved to a provided config file',\r\n promptOptions: {\r\n type: 'text'\r\n }\r\n }\r\n },\r\n server: {\r\n enable: {\r\n value: false,\r\n types: ['boolean'],\r\n envLink: 'SERVER_ENABLE',\r\n cliName: 'enableServer',\r\n description: 'Starts the server when true',\r\n promptOptions: {\r\n type: 'toggle'\r\n }\r\n },\r\n host: {\r\n value: '0.0.0.0',\r\n types: ['string'],\r\n envLink: 'SERVER_HOST',\r\n description: 'Hostname of the server',\r\n promptOptions: {\r\n type: 'text'\r\n }\r\n },\r\n port: {\r\n value: 7801,\r\n types: ['number'],\r\n envLink: 'SERVER_PORT',\r\n description: 'Port number for the server',\r\n promptOptions: {\r\n type: 'number'\r\n }\r\n },\r\n uploadLimit: {\r\n value: 3,\r\n types: ['number'],\r\n envLink: 'SERVER_UPLOAD_LIMIT',\r\n description: 'Maximum request body size in MB',\r\n promptOptions: {\r\n type: 'number'\r\n }\r\n },\r\n benchmarking: {\r\n value: false,\r\n types: ['boolean'],\r\n envLink: 'SERVER_BENCHMARKING',\r\n cliName: 'serverBenchmarking',\r\n description:\r\n 'Displays or not action durations in milliseconds during server requests',\r\n promptOptions: {\r\n type: 'toggle'\r\n }\r\n },\r\n proxy: {\r\n host: {\r\n value: null,\r\n types: ['string', 'null'],\r\n envLink: 'SERVER_PROXY_HOST',\r\n cliName: 'proxyHost',\r\n description: 'Host of the proxy server, if applicable',\r\n promptOptions: {\r\n type: 'text'\r\n }\r\n },\r\n port: {\r\n value: null,\r\n types: ['number', 'null'],\r\n envLink: 'SERVER_PROXY_PORT',\r\n cliName: 'proxyPort',\r\n description: 'Port of the proxy server, if applicable',\r\n promptOptions: {\r\n type: 'number'\r\n }\r\n },\r\n timeout: {\r\n value: 5000,\r\n types: ['number'],\r\n envLink: 'SERVER_PROXY_TIMEOUT',\r\n cliName: 'proxyTimeout',\r\n description:\r\n 'Timeout in milliseconds for the proxy server, if applicable',\r\n promptOptions: {\r\n type: 'number'\r\n }\r\n }\r\n },\r\n rateLimiting: {\r\n enable: {\r\n value: false,\r\n types: ['boolean'],\r\n envLink: 'SERVER_RATE_LIMITING_ENABLE',\r\n cliName: 'enableRateLimiting',\r\n description: 'Enables or disables rate limiting on the server',\r\n promptOptions: {\r\n type: 'toggle'\r\n }\r\n },\r\n maxRequests: {\r\n value: 10,\r\n types: ['number'],\r\n envLink: 'SERVER_RATE_LIMITING_MAX_REQUESTS',\r\n legacyName: 'rateLimit',\r\n description: 'Maximum number of requests allowed per minute',\r\n promptOptions: {\r\n type: 'number'\r\n }\r\n },\r\n window: {\r\n value: 1,\r\n types: ['number'],\r\n envLink: 'SERVER_RATE_LIMITING_WINDOW',\r\n description: 'Time window in minutes for rate limiting',\r\n promptOptions: {\r\n type: 'number'\r\n }\r\n },\r\n delay: {\r\n value: 0,\r\n types: ['number'],\r\n envLink: 'SERVER_RATE_LIMITING_DELAY',\r\n description:\r\n 'Delay duration between successive requests before reaching the limit',\r\n promptOptions: {\r\n type: 'number'\r\n }\r\n },\r\n trustProxy: {\r\n value: false,\r\n types: ['boolean'],\r\n envLink: 'SERVER_RATE_LIMITING_TRUST_PROXY',\r\n description: 'Set to true if the server is behind a load balancer',\r\n promptOptions: {\r\n type: 'toggle'\r\n }\r\n },\r\n skipKey: {\r\n value: null,\r\n types: ['string', 'null'],\r\n envLink: 'SERVER_RATE_LIMITING_SKIP_KEY',\r\n description: 'Key to bypass the rate limiter, used with `skipToken`',\r\n promptOptions: {\r\n type: 'text'\r\n }\r\n },\r\n skipToken: {\r\n value: null,\r\n types: ['string', 'null'],\r\n envLink: 'SERVER_RATE_LIMITING_SKIP_TOKEN',\r\n description: 'Token to bypass the rate limiter, used with `skipKey`',\r\n promptOptions: {\r\n type: 'text'\r\n }\r\n }\r\n },\r\n ssl: {\r\n enable: {\r\n value: false,\r\n types: ['boolean'],\r\n envLink: 'SERVER_SSL_ENABLE',\r\n cliName: 'enableSsl',\r\n description: 'Enables or disables SSL protocol',\r\n promptOptions: {\r\n type: 'toggle'\r\n }\r\n },\r\n force: {\r\n value: false,\r\n types: ['boolean'],\r\n envLink: 'SERVER_SSL_FORCE',\r\n cliName: 'sslForce',\r\n legacyName: 'sslOnly',\r\n description: 'Forces the server to use HTTPS only when true',\r\n promptOptions: {\r\n type: 'toggle'\r\n }\r\n },\r\n port: {\r\n value: 443,\r\n types: ['number'],\r\n envLink: 'SERVER_SSL_PORT',\r\n cliName: 'sslPort',\r\n description: 'Port for the SSL server',\r\n promptOptions: {\r\n type: 'number'\r\n }\r\n },\r\n certPath: {\r\n value: null,\r\n types: ['string', 'null'],\r\n envLink: 'SERVER_SSL_CERT_PATH',\r\n cliName: 'sslCertPath',\r\n legacyName: 'sslPath',\r\n description: 'Path to the SSL certificate/key file',\r\n promptOptions: {\r\n type: 'text'\r\n }\r\n }\r\n }\r\n },\r\n pool: {\r\n minWorkers: {\r\n value: 4,\r\n types: ['number'],\r\n envLink: 'POOL_MIN_WORKERS',\r\n description: 'Minimum and initial number of pool workers to spawn',\r\n promptOptions: {\r\n type: 'number'\r\n }\r\n },\r\n maxWorkers: {\r\n value: 8,\r\n types: ['number'],\r\n envLink: 'POOL_MAX_WORKERS',\r\n legacyName: 'workers',\r\n description: 'Maximum number of pool workers to spawn',\r\n promptOptions: {\r\n type: 'number'\r\n }\r\n },\r\n workLimit: {\r\n value: 40,\r\n types: ['number'],\r\n envLink: 'POOL_WORK_LIMIT',\r\n description: 'Number of tasks a worker can handle before restarting',\r\n promptOptions: {\r\n type: 'number'\r\n }\r\n },\r\n acquireTimeout: {\r\n value: 5000,\r\n types: ['number'],\r\n envLink: 'POOL_ACQUIRE_TIMEOUT',\r\n description: 'Timeout in milliseconds for acquiring a resource',\r\n promptOptions: {\r\n type: 'number'\r\n }\r\n },\r\n createTimeout: {\r\n value: 5000,\r\n types: ['number'],\r\n envLink: 'POOL_CREATE_TIMEOUT',\r\n description: 'Timeout in milliseconds for creating a resource',\r\n promptOptions: {\r\n type: 'number'\r\n }\r\n },\r\n destroyTimeout: {\r\n value: 5000,\r\n types: ['number'],\r\n envLink: 'POOL_DESTROY_TIMEOUT',\r\n description: 'Timeout in milliseconds for destroying a resource',\r\n promptOptions: {\r\n type: 'number'\r\n }\r\n },\r\n idleTimeout: {\r\n value: 30000,\r\n types: ['number'],\r\n envLink: 'POOL_IDLE_TIMEOUT',\r\n description: 'Timeout in milliseconds for destroying idle resources',\r\n promptOptions: {\r\n type: 'number'\r\n }\r\n },\r\n createRetryInterval: {\r\n value: 200,\r\n types: ['number'],\r\n envLink: 'POOL_CREATE_RETRY_INTERVAL',\r\n description:\r\n 'Interval in milliseconds before retrying resource creation on failure',\r\n promptOptions: {\r\n type: 'number'\r\n }\r\n },\r\n reaperInterval: {\r\n value: 1000,\r\n types: ['number'],\r\n envLink: 'POOL_REAPER_INTERVAL',\r\n description:\r\n 'Interval in milliseconds to check and destroy idle resources',\r\n promptOptions: {\r\n type: 'number'\r\n }\r\n },\r\n benchmarking: {\r\n value: false,\r\n types: ['boolean'],\r\n envLink: 'POOL_BENCHMARKING',\r\n cliName: 'poolBenchmarking',\r\n description: 'Shows statistics for the pool of resources',\r\n promptOptions: {\r\n type: 'toggle'\r\n }\r\n }\r\n },\r\n logging: {\r\n level: {\r\n value: 4,\r\n types: ['number'],\r\n envLink: 'LOGGING_LEVEL',\r\n cliName: 'logLevel',\r\n description: 'Logging verbosity level',\r\n promptOptions: {\r\n type: 'number',\r\n round: 0,\r\n min: 0,\r\n max: 5\r\n }\r\n },\r\n file: {\r\n value: 'highcharts-export-server.log',\r\n types: ['string'],\r\n envLink: 'LOGGING_FILE',\r\n cliName: 'logFile',\r\n description:\r\n 'Log file name. Requires `logToFile` and `logDest` to be set',\r\n promptOptions: {\r\n type: 'text'\r\n }\r\n },\r\n dest: {\r\n value: 'log',\r\n types: ['string'],\r\n envLink: 'LOGGING_DEST',\r\n cliName: 'logDest',\r\n description: 'Path to store log files. Requires `logToFile` to be set',\r\n promptOptions: {\r\n type: 'text'\r\n }\r\n },\r\n toConsole: {\r\n value: true,\r\n types: ['boolean'],\r\n envLink: 'LOGGING_TO_CONSOLE',\r\n cliName: 'logToConsole',\r\n description: 'Enables or disables console logging',\r\n promptOptions: {\r\n type: 'toggle'\r\n }\r\n },\r\n toFile: {\r\n value: true,\r\n types: ['boolean'],\r\n envLink: 'LOGGING_TO_FILE',\r\n cliName: 'logToFile',\r\n description: 'Enables or disables logging to a file',\r\n promptOptions: {\r\n type: 'toggle'\r\n }\r\n }\r\n },\r\n ui: {\r\n enable: {\r\n value: false,\r\n types: ['boolean'],\r\n envLink: 'UI_ENABLE',\r\n cliName: 'enableUi',\r\n description: 'Enables or disables the UI for the export server',\r\n promptOptions: {\r\n type: 'toggle'\r\n }\r\n },\r\n route: {\r\n value: '/',\r\n types: ['string'],\r\n envLink: 'UI_ROUTE',\r\n cliName: 'uiRoute',\r\n description: 'The endpoint route for the UI',\r\n promptOptions: {\r\n type: 'text'\r\n }\r\n }\r\n },\r\n other: {\r\n nodeEnv: {\r\n value: 'production',\r\n types: ['string'],\r\n envLink: 'OTHER_NODE_ENV',\r\n description: 'The Node.js environment type',\r\n promptOptions: {\r\n type: 'text'\r\n }\r\n },\r\n listenToProcessExits: {\r\n value: true,\r\n types: ['boolean'],\r\n envLink: 'OTHER_LISTEN_TO_PROCESS_EXITS',\r\n description: 'Whether or not to attach process.exit handlers',\r\n promptOptions: {\r\n type: 'toggle'\r\n }\r\n },\r\n noLogo: {\r\n value: false,\r\n types: ['boolean'],\r\n envLink: 'OTHER_NO_LOGO',\r\n description: 'Display or skip printing the logo on startup',\r\n promptOptions: {\r\n type: 'toggle'\r\n }\r\n },\r\n hardResetPage: {\r\n value: false,\r\n types: ['boolean'],\r\n envLink: 'OTHER_HARD_RESET_PAGE',\r\n description: 'Whether or not to reset the page content entirely',\r\n promptOptions: {\r\n type: 'toggle'\r\n }\r\n },\r\n browserShellMode: {\r\n value: true,\r\n types: ['boolean'],\r\n envLink: 'OTHER_BROWSER_SHELL_MODE',\r\n description: 'Whether or not to set the browser to run in shell mode',\r\n promptOptions: {\r\n type: 'toggle'\r\n }\r\n },\r\n validation: {\r\n value: true,\r\n types: ['boolean'],\r\n envLink: 'OTHER_VALIDATION',\r\n description: 'Whether or not to enable validation of options types',\r\n promptOptions: {\r\n type: 'toggle'\r\n }\r\n }\r\n },\r\n debug: {\r\n enable: {\r\n value: false,\r\n types: ['boolean'],\r\n envLink: 'DEBUG_ENABLE',\r\n cliName: 'enableDebug',\r\n description: 'Enables or disables debug mode for the underlying browser',\r\n promptOptions: {\r\n type: 'toggle'\r\n }\r\n },\r\n headless: {\r\n value: false,\r\n types: ['boolean'],\r\n envLink: 'DEBUG_HEADLESS',\r\n description:\r\n 'Whether or not to set the browser to run in headless mode during debugging',\r\n promptOptions: {\r\n type: 'toggle'\r\n }\r\n },\r\n devtools: {\r\n value: false,\r\n types: ['boolean'],\r\n envLink: 'DEBUG_DEVTOOLS',\r\n description: 'Enables or disables DevTools in headful mode',\r\n promptOptions: {\r\n type: 'toggle'\r\n }\r\n },\r\n listenToConsole: {\r\n value: false,\r\n types: ['boolean'],\r\n envLink: 'DEBUG_LISTEN_TO_CONSOLE',\r\n description:\r\n 'Enables or disables listening to console messages from the browser',\r\n promptOptions: {\r\n type: 'toggle'\r\n }\r\n },\r\n dumpio: {\r\n value: false,\r\n types: ['boolean'],\r\n envLink: 'DEBUG_DUMPIO',\r\n description:\r\n 'Redirects or not browser stdout and stderr to process.stdout and process.stderr',\r\n promptOptions: {\r\n type: 'toggle'\r\n }\r\n },\r\n slowMo: {\r\n value: 0,\r\n types: ['number'],\r\n envLink: 'DEBUG_SLOW_MO',\r\n description: 'Delays Puppeteer operations by the specified milliseconds',\r\n promptOptions: {\r\n type: 'number'\r\n }\r\n },\r\n debuggingPort: {\r\n value: 9222,\r\n types: ['number'],\r\n envLink: 'DEBUG_DEBUGGING_PORT',\r\n description: 'Port used for debugging',\r\n promptOptions: {\r\n type: 'number'\r\n }\r\n }\r\n }\r\n};\r\n\r\nexport default defaultConfig;\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * @overview This file handles parsing and validating options from multiple\r\n * sources (the config file, custom JSON, environment variables, CLI arguments,\r\n * and request payload) using the 'zod' library.\r\n *\r\n * Environment variables are parsed and validated only once at application\r\n * startup, and the validated results are exported as `envs` for use throughout\r\n * the application.\r\n *\r\n * Options from other sources, however, are parsed and validated on demand,\r\n * each time an export is attempted.\r\n */\r\n\r\nimport dotenv from 'dotenv';\r\nimport { z } from 'zod';\r\n\r\nimport defaultConfig from './schemas/config.js';\r\n\r\n// Load the .env into environment variables\r\ndotenv.config();\r\n\r\n// Get scripts names of each category from the default config\r\nconst { coreScripts, moduleScripts, indicatorScripts } =\r\n defaultConfig.highcharts;\r\n\r\n// Sets the custom error map globally\r\nz.setErrorMap(_customErrorMap);\r\n\r\n/**\r\n * Object containing custom general validators and parsers to avoid repetition\r\n * in schema objects. All validators apply to values from various sources,\r\n * including the default config file, a custom JSON file loaded with the option\r\n * called `loadConfig`, the .env file, CLI arguments, and the request payload.\r\n * The `strictCheck` flag enables stricter validation and parsing rules. This\r\n * flag is set to false for values that come from the .env file or CLI arguments\r\n * because they are provided as strings and need to be parsed accordingly first.\r\n */\r\nconst v = {\r\n /**\r\n * The `boolean` validator that returns a Zod schema with an optional stricter\r\n * check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures that:\r\n *\r\n * - When `strictCheck` is true, the schema will accept values are true\r\n * and false and the schema will validate against the default boolean\r\n * validator.\r\n *\r\n * - When `strictCheck` is false, the schema will accept values are true,\r\n * false, null, 'true', '1', 'false', '0', 'undefined', 'null', and ''.\r\n * The strings 'undefined', 'null', and '' will be transformed to null,\r\n * the string 'true' will be transformed to the boolean value true,\r\n * and 'false' will be transformed to the boolean value false.\r\n *\r\n * @function boolean\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating boolean values.\r\n */\r\n boolean(strictCheck) {\r\n return strictCheck\r\n ? z.boolean()\r\n : z\r\n .union([\r\n z\r\n .enum(['true', '1', 'false', '0', 'undefined', 'null', ''])\r\n .transform((value) =>\r\n !['undefined', 'null', ''].includes(value)\r\n ? value === 'true' || value === '1'\r\n : null\r\n ),\r\n z.boolean()\r\n ])\r\n .nullable();\r\n },\r\n\r\n /**\r\n * The `string` validator that returns a Zod schema with an optional stricter\r\n * check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures that:\r\n *\r\n * - When `strictCheck` is true, the schema will accept trimmed strings except\r\n * the forbidden values: 'false', 'undefined', 'null', and ''.\r\n *\r\n * - When `strictCheck` is false, the schema will accept trimmed strings\r\n * and null. The forbidden values: 'false', 'undefined', 'null', and '' will\r\n * be transformed to null.\r\n *\r\n * @function string\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating string values.\r\n */\r\n string(strictCheck) {\r\n return strictCheck\r\n ? z\r\n .string()\r\n .trim()\r\n .refine(\r\n (value) => !['false', 'undefined', 'null', ''].includes(value),\r\n {\r\n params: {\r\n errorMessage: 'The string contains a forbidden value'\r\n }\r\n }\r\n )\r\n : z\r\n .string()\r\n .trim()\r\n .transform((value) =>\r\n !['false', 'undefined', 'null', ''].includes(value) ? value : null\r\n )\r\n .nullable();\r\n },\r\n\r\n /**\r\n * The `enum` validator that returns a Zod schema with an optional stricter\r\n * check based on the `strictCheck` parameter.\r\n *\r\n * The schema will validate against the provided `values` array.\r\n *\r\n * The validation schema ensures that:\r\n *\r\n * - When `strictCheck` is true, the schema will validate against the `values`\r\n * array with the default enum validator.\r\n *\r\n * - When `strictCheck` is false, the schema will accept also null,\r\n * 'undefined', 'null', and '', which will be transformed to null.\r\n *\r\n * @function enum\r\n *\r\n * @param {Array.} values - An array of valid string values\r\n * for the enum.\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating enum values.\r\n */\r\n enum(values, strictCheck) {\r\n return strictCheck\r\n ? z.enum([...values])\r\n : z\r\n .enum([...values, 'undefined', 'null', ''])\r\n .transform((value) =>\r\n !['undefined', 'null', ''].includes(value) ? value : null\r\n )\r\n .nullable();\r\n },\r\n\r\n /**\r\n * The `stringArray` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures that:\r\n *\r\n * - When `strictCheck` is true, the schema will accept an array of trimmed\r\n * string values filtered by the logic provided through the `filterCallback`.\r\n *\r\n * - When `strictCheck` is false, the schema will accept null and trimmed\r\n * string values which will be splitted into an array of strings and filtered\r\n * from the '[' and ']' characters and by the logic provided through\r\n * the `filterCallback`. If the array is empty, it will be transformed\r\n * to null.\r\n *\r\n * @function stringArray\r\n *\r\n * @param {function} filterCallback - The filter callback.\r\n * @param {string} separator - The separator for spliting a string.\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating array of string\r\n * values.\r\n */\r\n stringArray(filterCallback, separator, strictCheck) {\r\n const arraySchema = z.string().trim().array();\r\n const stringSchema = z\r\n .string()\r\n .trim()\r\n .transform((value) => {\r\n if (value.startsWith('[')) {\r\n value = value.slice(1);\r\n }\r\n if (value.endsWith(']')) {\r\n value = value.slice(0, -1);\r\n }\r\n return value.split(separator);\r\n });\r\n\r\n const transformCallback = (value) =>\r\n value.map((value) => value.trim()).filter(filterCallback);\r\n\r\n return strictCheck\r\n ? arraySchema.transform(transformCallback)\r\n : z\r\n .union([stringSchema, arraySchema])\r\n .transform(transformCallback)\r\n .transform((value) => (value.length ? value : null))\r\n .nullable();\r\n },\r\n\r\n /**\r\n * The `positiveNum` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures that:\r\n *\r\n * - When `strictCheck` is true, the schema will accept positive number values\r\n * and validate against the default positive number validator.\r\n *\r\n * - When `strictCheck` is false, the schema will accept positive number\r\n * values, null, and trimmed string values that can either be 'undefined',\r\n * 'null', '', or represent a positive number. It will transform the string\r\n * to a positive number, or to null if it is 'undefined', 'null', or ''.\r\n *\r\n * @function positiveNum\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating positive number\r\n * values.\r\n */\r\n positiveNum(strictCheck) {\r\n return strictCheck\r\n ? z.number().positive()\r\n : z\r\n .union([\r\n z\r\n .string()\r\n .trim()\r\n .refine(\r\n (value) =>\r\n (!isNaN(Number(value)) && Number(value) > 0) ||\r\n ['undefined', 'null', ''].includes(value),\r\n {\r\n params: {\r\n errorMessage: 'The value must be numeric and positive'\r\n }\r\n }\r\n )\r\n .transform((value) =>\r\n !['undefined', 'null', ''].includes(value)\r\n ? Number(value)\r\n : null\r\n ),\r\n z.number().positive()\r\n ])\r\n .nullable();\r\n },\r\n\r\n /**\r\n * The `nonNegativeNum` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures that:\r\n *\r\n * - When `strictCheck` is true, the schema will accept non-negative number\r\n * values and validate against the default non-negative number validator.\r\n *\r\n * - When `strictCheck` is false, the schema will accept non-negative number\r\n * values, null, and trimmed string values that can either be 'undefined',\r\n * 'null', '', or represent a non-negative number. It will transform\r\n * the string to a non-negative number, or to null if it is 'undefined',\r\n * 'null', or ''.\r\n *\r\n * @function nonNegativeNum\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating non-negative\r\n * number values.\r\n */\r\n nonNegativeNum(strictCheck) {\r\n return strictCheck\r\n ? z.number().nonnegative()\r\n : z\r\n .union([\r\n z\r\n .string()\r\n .trim()\r\n .refine(\r\n (value) =>\r\n (!isNaN(Number(value)) && Number(value) >= 0) ||\r\n ['undefined', 'null', ''].includes(value),\r\n {\r\n params: {\r\n errorMessage: 'The value must be numeric and non-negative'\r\n }\r\n }\r\n )\r\n .transform((value) =>\r\n !['undefined', 'null', ''].includes(value)\r\n ? Number(value)\r\n : null\r\n ),\r\n z.number().nonnegative()\r\n ])\r\n .nullable();\r\n },\r\n\r\n /**\r\n * The `startsWith` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The schema will validate against the provided `prefixes` array to check\r\n * whether a string value starts with any of the values provided\r\n * in the `prefixes` array.\r\n *\r\n * The validation schema ensures that:\r\n *\r\n * - When `strictCheck` is true, the schema will accept trimmed string values\r\n * that start with values from the prefixes array.\r\n *\r\n * - When `strictCheck` is false, the schema will accept trimmed string values\r\n * that start with values from the prefixes array, null, 'undefined', 'null',\r\n * and '' where the schema will transform them to null.\r\n *\r\n * @function startsWith\r\n *\r\n * @param {Array.} prefixes - An array of prefixes to validate\r\n * the string against.\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating strings that\r\n * starts with values.\r\n */\r\n startsWith(prefixes, strictCheck) {\r\n return strictCheck\r\n ? z\r\n .string()\r\n .trim()\r\n .refine(\r\n (value) => prefixes.some((prefix) => value.startsWith(prefix)),\r\n {\r\n params: {\r\n errorMessage: `The value must be a string that starts with ${prefixes.join(', ')}`\r\n }\r\n }\r\n )\r\n : z\r\n .string()\r\n .trim()\r\n .refine(\r\n (value) =>\r\n prefixes.some((prefix) => value.startsWith(prefix)) ||\r\n ['undefined', 'null', ''].includes(value),\r\n {\r\n params: {\r\n errorMessage: `The value must be a string that starts with ${prefixes.join(', ')}`\r\n }\r\n }\r\n )\r\n .transform((value) =>\r\n !['undefined', 'null', ''].includes(value) ? value : null\r\n )\r\n .nullable();\r\n },\r\n\r\n /**\r\n * The `chartConfig` validator that returns a Zod schema.\r\n *\r\n * The validation schema ensures that the schema will accept object values\r\n * or trimmed string values that contain '\r\n (value.startsWith('{') && value.endsWith('}')) ||\r\n ['undefined', 'null', ''].includes(value),\r\n {\r\n params: {\r\n errorMessage:\r\n \"The value must be a string that starts with '{' and ends with '}'\"\r\n }\r\n }\r\n )\r\n .transform((value) =>\r\n !['undefined', 'null', ''].includes(value) ? value : null\r\n ),\r\n z.object({}).passthrough()\r\n ])\r\n .nullable();\r\n },\r\n\r\n /**\r\n * The `additionalOptions` validator that returns a Zod schema.\r\n *\r\n * The validation schema ensures that the schema will accept object values\r\n * or trimmed string values that end with '.json' and are at least one\r\n * character long excluding the extension, start with the '{' and end\r\n * with the '}', and null. The 'undefined', 'null', and '' values will\r\n * be transformed to null.\r\n *\r\n * @function additionalOptions\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating additional chart\r\n * options value.\r\n */\r\n additionalOptions() {\r\n return z\r\n .union([\r\n z\r\n .string()\r\n .trim()\r\n .refine(\r\n (value) =>\r\n (value.length >= 6 && value.endsWith('.json')) ||\r\n (value.startsWith('{') && value.endsWith('}')) ||\r\n ['undefined', 'null', ''].includes(value),\r\n {\r\n params: {\r\n errorMessage:\r\n \"The value must be a string that ends with '.json' or starts with '{' and ends with '}'\"\r\n }\r\n }\r\n )\r\n .transform((value) =>\r\n !['undefined', 'null', ''].includes(value) ? value : null\r\n ),\r\n z.object({}).passthrough()\r\n ])\r\n .nullable();\r\n }\r\n};\r\n\r\n/**\r\n * Object containing custom config validators and parsers to avoid repetition\r\n * in schema objects. All validators apply to values from various sources,\r\n * including the default config file, a custom JSON file loaded with the option\r\n * called `loadConfig`, the .env file, CLI arguments, and the request payload.\r\n * The `strictCheck` flag enables stricter validation and parsing rules. This\r\n * flag is set to false for values that come from the .env file or CLI arguments\r\n * because they are provided as strings and need to be parsed accordingly first.\r\n */\r\nexport const validators = {\r\n /**\r\n * The `args` validator that returns a Zod schema with an optional stricter\r\n * check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `stringArray` validator.\r\n *\r\n * @function args\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `args`\r\n * option.\r\n */\r\n args(strictCheck) {\r\n return v.stringArray(\r\n (value) => !['false', 'undefined', 'null', ''].includes(value),\r\n ';',\r\n strictCheck\r\n );\r\n },\r\n\r\n /**\r\n * The `version` validator that returns a Zod schema with an optional stricter\r\n * check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures that:\r\n *\r\n * - When `strictCheck` is true, the schema will accept trimmed string values\r\n * that are a RegExp-based that allows to be 'latest', or in the format XX,\r\n * XX.YY, or XX.YY.ZZ, where XX, YY, and ZZ are numeric for the Highcharts\r\n * version option.\r\n *\r\n * - When `strictCheck` is false, the schema will accept also null,\r\n * 'undefined', 'null', or '' and in all cases the schema will transform them\r\n * to null.\r\n *\r\n * @function version\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `version`\r\n * option.\r\n */\r\n version(strictCheck) {\r\n return strictCheck\r\n ? z\r\n .string()\r\n .trim()\r\n .refine((value) => /^(latest|\\d{1,2}(\\.\\d{1,2}){0,2})$/.test(value), {\r\n params: {\r\n errorMessage:\r\n \"The value must be 'latest', a major version, or in the form XX.YY.ZZ\"\r\n }\r\n })\r\n : z\r\n .string()\r\n .trim()\r\n .refine(\r\n (value) =>\r\n /^(latest|\\d{1,2}(\\.\\d{1,2}){0,2})$/.test(value) ||\r\n ['undefined', 'null', ''].includes(value),\r\n {\r\n params: {\r\n errorMessage:\r\n \"The value must be 'latest', a major version, or in the form XX.YY.ZZ\"\r\n }\r\n }\r\n )\r\n .transform((value) =>\r\n !['undefined', 'null', ''].includes(value) ? value : null\r\n )\r\n .nullable();\r\n },\r\n\r\n /**\r\n * The `cdnUrl` validator that returns a Zod schema with an optional stricter\r\n * check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `startsWith` validator.\r\n *\r\n * @function cdnUrl\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `cdnUrl`\r\n * option.\r\n */\r\n cdnUrl(strictCheck) {\r\n return v.startsWith(['http://', 'https://'], strictCheck);\r\n },\r\n\r\n /**\r\n * The `forceFetch` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `boolean` validator.\r\n *\r\n * @function forceFetch\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `forceFetch`\r\n * option.\r\n */\r\n forceFetch(strictCheck) {\r\n return v.boolean(strictCheck);\r\n },\r\n\r\n /**\r\n * The `cachePath` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `string` validator.\r\n *\r\n * @function cachePath\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `cachePath`\r\n * option.\r\n */\r\n cachePath(strictCheck) {\r\n return v.string(strictCheck);\r\n },\r\n\r\n /**\r\n * The `adminToken` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `string` validator.\r\n *\r\n * @function adminToken\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `adminToken`\r\n * option.\r\n */\r\n adminToken(strictCheck) {\r\n return v.string(strictCheck);\r\n },\r\n\r\n /**\r\n * The `coreScripts` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `stringArray` validator.\r\n *\r\n * @function coreScripts\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `coreScripts`\r\n * option.\r\n */\r\n coreScripts(strictCheck) {\r\n return v.stringArray(\r\n (value) => coreScripts.value.includes(value),\r\n ',',\r\n strictCheck\r\n );\r\n },\r\n\r\n /**\r\n * The `moduleScripts` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `stringArray` validator.\r\n *\r\n * @function moduleScripts\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating\r\n * the `moduleScripts` option.\r\n */\r\n moduleScripts(strictCheck) {\r\n return v.stringArray(\r\n (value) => moduleScripts.value.includes(value),\r\n ',',\r\n strictCheck\r\n );\r\n },\r\n\r\n /**\r\n * The `indicatorScripts` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `stringArray` validator.\r\n *\r\n * @function indicatorScripts\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating\r\n * the `indicatorScripts` option.\r\n */\r\n indicatorScripts(strictCheck) {\r\n return v.stringArray(\r\n (value) => indicatorScripts.value.includes(value),\r\n ',',\r\n strictCheck\r\n );\r\n },\r\n\r\n /**\r\n * The `customScripts` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `stringArray` validator.\r\n *\r\n * @function customScripts\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating\r\n * the `customScripts` option.\r\n */\r\n customScripts(strictCheck) {\r\n return v.stringArray(\r\n (value) => value.startsWith('https://') || value.startsWith('http://'),\r\n ',',\r\n strictCheck\r\n );\r\n },\r\n\r\n /**\r\n * The `infile` validator that returns a Zod schema with an optional stricter\r\n * check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures that:\r\n *\r\n * - When `strictCheck` is true, the schema will accept trimmed string values\r\n * that end with '.json' or '.svg', are at least one character long excluding\r\n * the extension, or null.\r\n *\r\n * - When `strictCheck` is false, the schema will accept trimmed string values\r\n * that end with '.json' or '.svg', are at least one character long excluding\r\n * the extension and will be null if the provided value is null, 'undefined',\r\n * 'null', or ''.\r\n *\r\n * @function infile\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `infile`\r\n * option.\r\n */\r\n infile(strictCheck) {\r\n return strictCheck\r\n ? z\r\n .string()\r\n .trim()\r\n .refine(\r\n (value) =>\r\n (value.length >= 6 && value.endsWith('.json')) ||\r\n (value.length >= 5 && value.endsWith('.svg')),\r\n {\r\n params: {\r\n errorMessage:\r\n 'The value must be a string that ends with .json or .svg'\r\n }\r\n }\r\n )\r\n .nullable()\r\n : z\r\n .string()\r\n .trim()\r\n .refine(\r\n (value) =>\r\n (value.length >= 6 && value.endsWith('.json')) ||\r\n (value.length >= 5 && value.endsWith('.svg')) ||\r\n ['undefined', 'null', ''].includes(value),\r\n {\r\n params: {\r\n errorMessage:\r\n 'The value must be a string that ends with .json or .svg'\r\n }\r\n }\r\n )\r\n .transform((value) =>\r\n !['undefined', 'null', ''].includes(value) ? value : null\r\n )\r\n .nullable();\r\n },\r\n\r\n /**\r\n * The `instr` validator that returns a Zod schema.\r\n *\r\n * The validation schema ensures the same work as the `options` validator.\r\n *\r\n * @function instr\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `instr`\r\n * option.\r\n */\r\n instr() {\r\n return v.chartConfig();\r\n },\r\n\r\n /**\r\n * The `options` validator that returns a Zod schema.\r\n *\r\n * The validation schema ensures the same work as the `options` validator.\r\n *\r\n * @function options\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `options`\r\n * option.\r\n */\r\n options() {\r\n return v.chartConfig();\r\n },\r\n\r\n /**\r\n * The `svg` validator that returns a Zod schema.\r\n *\r\n * The validation schema ensures that the schema will accept object values\r\n * or trimmed string values that contain '\r\n value.indexOf('= 0 ||\r\n value.indexOf('= 0 ||\r\n ['false', 'undefined', 'null', ''].includes(value),\r\n {\r\n params: {\r\n errorMessage:\r\n \"The value must be a string that contains '\r\n !['false', 'undefined', 'null', ''].includes(value) ? value : null\r\n )\r\n .nullable();\r\n },\r\n\r\n /**\r\n * The `outfile` validator that returns a Zod schema with an optional stricter\r\n * check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures that:\r\n *\r\n * - When `strictCheck` is true, the schema will accept trimmed string values\r\n * that end with '.jpeg', '.jpg', '.png', '.pdf', or '.svg', are at least one\r\n * character long excluding the extension, or null.\r\n *\r\n * - When `strictCheck` is false, the schema will accept trimmed string values\r\n * that end with '.jpeg', '.jpg', '.png', '.pdf', or '.svg', are at least one\r\n * character long excluding the extension and will be null if the provided\r\n * value is null, 'undefined', 'null', or ''.\r\n *\r\n * @function outfile\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `outfile`\r\n * option.\r\n */\r\n outfile(strictCheck) {\r\n return strictCheck\r\n ? z\r\n .string()\r\n .trim()\r\n .refine(\r\n (value) =>\r\n (value.length >= 6 && value.endsWith('.jpeg')) ||\r\n (value.length >= 5 &&\r\n (value.endsWith('.jpg') ||\r\n value.endsWith('.png') ||\r\n value.endsWith('.pdf') ||\r\n value.endsWith('.svg'))),\r\n {\r\n params: {\r\n errorMessage:\r\n 'The value must be a string that ends with .jpeg, .jpg, .png, .pdf, or .svg'\r\n }\r\n }\r\n )\r\n .nullable()\r\n : z\r\n .string()\r\n .trim()\r\n .refine(\r\n (value) =>\r\n (value.length >= 6 && value.endsWith('.jpeg')) ||\r\n (value.length >= 5 &&\r\n (value.endsWith('.jpg') ||\r\n value.endsWith('.png') ||\r\n value.endsWith('.pdf') ||\r\n value.endsWith('.svg'))) ||\r\n ['undefined', 'null', ''].includes(value),\r\n {\r\n params: {\r\n errorMessage:\r\n 'The value must be a string that ends with .jpeg, .jpg, .png, .pdf, or .svg'\r\n }\r\n }\r\n )\r\n .transform((value) =>\r\n !['undefined', 'null', ''].includes(value) ? value : null\r\n )\r\n .nullable();\r\n },\r\n\r\n /**\r\n * The `type` validator that returns a Zod schema with an optional stricter\r\n * check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `enum` validator.\r\n *\r\n * @function type\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `type`\r\n * option.\r\n */\r\n type(strictCheck) {\r\n return v.enum(['jpeg', 'jpg', 'png', 'pdf', 'svg'], strictCheck);\r\n },\r\n\r\n /**\r\n * The `constr` validator that returns a Zod schema with an optional stricter\r\n * check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `enum` validator.\r\n *\r\n * @function constr\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `constr`\r\n * option.\r\n */\r\n constr(strictCheck) {\r\n return v.enum(\r\n ['chart', 'stockChart', 'mapChart', 'ganttChart'],\r\n strictCheck\r\n );\r\n },\r\n\r\n /**\r\n * The `b64` validator that returns a Zod schema with an optional stricter\r\n * check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `boolean` validator.\r\n *\r\n * @function b64\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `b64` option.\r\n */\r\n b64(strictCheck) {\r\n return v.boolean(strictCheck);\r\n },\r\n\r\n /**\r\n * The `noDownload` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `boolean` validator.\r\n *\r\n * @function noDownload\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `noDownload`\r\n * option.\r\n */\r\n noDownload(strictCheck) {\r\n return v.boolean(strictCheck);\r\n },\r\n\r\n /**\r\n * The `defaultHeight` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `positiveNum` validator.\r\n *\r\n * @function defaultHeight\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating\r\n * the `defaultHeight` option.\r\n */\r\n defaultHeight(strictCheck) {\r\n return v.positiveNum(strictCheck);\r\n },\r\n\r\n /**\r\n * The `defaultWidth` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `positiveNum` validator.\r\n *\r\n * @function defaultWidth\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating\r\n * the `defaultWidth` option.\r\n */\r\n defaultWidth(strictCheck) {\r\n return v.positiveNum(strictCheck);\r\n },\r\n\r\n /**\r\n * The `defaultScale` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures that:\r\n *\r\n * - When `strictCheck` is true, the schema will accept number values that\r\n * are between 0.1 and 5 (inclusive).\r\n *\r\n * - When `strictCheck` is false, the schema will accept number values\r\n * and stringified number values that are between 0.1 and 5 (inclusive), null,\r\n * 'undefined', 'null', and '' which will be transformed to null.\r\n *\r\n * @function defaultScale\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating\r\n * the `defaultScale` option.\r\n */\r\n defaultScale(strictCheck) {\r\n return strictCheck\r\n ? z.number().gte(0.1).lte(5)\r\n : z\r\n .union([\r\n z\r\n .string()\r\n .trim()\r\n .refine(\r\n (value) =>\r\n (!isNaN(Number(value)) &&\r\n value !== true &&\r\n !value.startsWith('[') &&\r\n Number(value) >= 0.1 &&\r\n Number(value) <= 5) ||\r\n ['undefined', 'null', ''].includes(value),\r\n {\r\n params: {\r\n errorMessage: 'The value must be within a 0.1 and 5.0 range'\r\n }\r\n }\r\n )\r\n .transform((value) =>\r\n !['undefined', 'null', ''].includes(value)\r\n ? Number(value)\r\n : null\r\n ),\r\n z.number().gte(0.1).lte(5)\r\n ])\r\n .nullable();\r\n },\r\n\r\n /**\r\n * The `height` validator that returns a Zod schema with an optional stricter\r\n * check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as a nullable `defaultHeight`\r\n * validator.\r\n *\r\n * @function height\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `height`\r\n * option.\r\n */\r\n height(strictCheck) {\r\n return this.defaultHeight(strictCheck).nullable();\r\n },\r\n\r\n /**\r\n * The `width` validator that returns a Zod schema with an optional stricter\r\n * check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as a nullable `defaultWidth`\r\n * validator.\r\n *\r\n * @function width\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `width`\r\n * option.\r\n */\r\n width(strictCheck) {\r\n return this.defaultWidth(strictCheck).nullable();\r\n },\r\n\r\n /**\r\n * The `scale` validator that returns a Zod schema with an optional stricter\r\n * check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as a nullable `defaultScale`\r\n * validator.\r\n *\r\n * @function scale\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `scale`\r\n * option.\r\n */\r\n scale(strictCheck) {\r\n return this.defaultScale(strictCheck).nullable();\r\n },\r\n\r\n /**\r\n * The `globalOptions` validator that returns a Zod schema.\r\n *\r\n * The validation schema ensures the same work as the `additionalOptions`\r\n * validator.\r\n *\r\n * @function globalOptions\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating\r\n * the `globalOptions` option.\r\n */\r\n globalOptions() {\r\n return v.additionalOptions();\r\n },\r\n\r\n /**\r\n * The `themeOptions` validator that returns a Zod schema.\r\n *\r\n * The validation schema ensures the same work as the `additionalOptions`\r\n * validator.\r\n *\r\n * @function themeOptions\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating\r\n * the `themeOptions` option.\r\n */\r\n themeOptions() {\r\n return v.additionalOptions();\r\n },\r\n\r\n /**\r\n * The `batch` validator that returns a Zod schema with an optional stricter\r\n * check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `string` validator.\r\n *\r\n * @function batch\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `batch`\r\n * option.\r\n */\r\n batch(strictCheck) {\r\n return v.string(strictCheck);\r\n },\r\n\r\n /**\r\n * The `rasterizationTimeout` validator that returns a Zod schema with\r\n * an optional stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `nonNegativeNum`\r\n * validator.\r\n *\r\n * @function rasterizationTimeout\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating\r\n * the `rasterizationTimeout` option.\r\n */\r\n rasterizationTimeout(strictCheck) {\r\n return v.nonNegativeNum(strictCheck);\r\n },\r\n\r\n /**\r\n * The `allowCodeExecution` validator that returns a Zod schema with\r\n * an optional stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `boolean` validator.\r\n *\r\n * @function allowCodeExecution\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating\r\n * the `allowCodeExecution` option.\r\n */\r\n allowCodeExecution(strictCheck) {\r\n return v.boolean(strictCheck);\r\n },\r\n\r\n /**\r\n * The `allowFileResources` validator that returns a Zod schema with\r\n * an optional stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `boolean` validator.\r\n *\r\n * @function allowFileResources\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating\r\n * the `allowFileResources` option.\r\n */\r\n allowFileResources(strictCheck) {\r\n return v.boolean(strictCheck);\r\n },\r\n\r\n /**\r\n * The `customCode` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `string` validator.\r\n *\r\n * @function customCode\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `customCode`\r\n * option.\r\n */\r\n customCode(strictCheck) {\r\n return v.string(strictCheck);\r\n },\r\n\r\n /**\r\n * The `callback` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `string` validator.\r\n *\r\n * @function callback\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `callback`\r\n * option.\r\n */\r\n callback(strictCheck) {\r\n return v.string(strictCheck);\r\n },\r\n\r\n /**\r\n * The `resources` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures that:\r\n *\r\n * - When `strictCheck` is true, the schema will accept a partial object\r\n * with allowed properties `js`, `css`, and `files` where each of the allowed\r\n * properties can be null, stringified version of the object, string that ends\r\n * with the '.json', and null.\r\n *\r\n * - When `strictCheck` is false, the schema will accept a stringified version\r\n * of a partial object with allowed properties `js`, `css`, and `files` where\r\n * each of the allowed properties can be null, string that ends with the\r\n * '.json', and will be null if the provided value is 'undefined', 'null'\r\n * or ''.\r\n *\r\n * @function resources\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `resources`\r\n * option.\r\n */\r\n resources(strictCheck) {\r\n const objectSchema = z\r\n .object({\r\n js: v.string(false),\r\n css: v.string(false),\r\n files: v\r\n .stringArray(\r\n (value) => !['undefined', 'null', ''].includes(value),\r\n ',',\r\n true\r\n )\r\n .nullable()\r\n })\r\n .partial();\r\n\r\n const stringSchema1 = z\r\n .string()\r\n .trim()\r\n .refine(\r\n (value) =>\r\n (value.startsWith('{') && value.endsWith('}')) ||\r\n (value.length >= 6 && value.endsWith('.json')),\r\n {\r\n params: {\r\n errorMessage:\r\n \"The value must be a string that starts with '{' and ends with '}\"\r\n }\r\n }\r\n );\r\n\r\n const stringSchema2 = z\r\n .string()\r\n .trim()\r\n .refine(\r\n (value) =>\r\n (value.startsWith('{') && value.endsWith('}')) ||\r\n (value.length >= 6 && value.endsWith('.json')) ||\r\n ['undefined', 'null', ''].includes(value),\r\n {\r\n params: {\r\n errorMessage: 'The value must be a string that ends with .json'\r\n }\r\n }\r\n )\r\n .transform((value) =>\r\n !['undefined', 'null', ''].includes(value) ? value : null\r\n );\r\n\r\n return strictCheck\r\n ? z.union([objectSchema, stringSchema1]).nullable()\r\n : z.union([objectSchema, stringSchema2]).nullable();\r\n },\r\n\r\n /**\r\n * The `loadConfig` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `string` validator.\r\n * Additionally, it must be a string that ends with '.json'.\r\n *\r\n * @function loadConfig\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `loadConfig`\r\n * option.\r\n */\r\n loadConfig(strictCheck) {\r\n return v\r\n .string(strictCheck)\r\n .refine(\r\n (value) =>\r\n value === null || (value.length >= 6 && value.endsWith('.json')),\r\n {\r\n params: {\r\n errorMessage: 'The value must be a string that ends with .json'\r\n }\r\n }\r\n );\r\n },\r\n\r\n /**\r\n * The `createConfig` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `loadConfig` validator.\r\n *\r\n * @function createConfig\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating\r\n * the `createConfig` option.\r\n */\r\n createConfig(strictCheck) {\r\n return this.loadConfig(strictCheck);\r\n },\r\n\r\n /**\r\n * The `enableServer` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `boolean` validator.\r\n *\r\n * @function enableServer\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating\r\n * the `enableServer` option.\r\n */\r\n enableServer(strictCheck) {\r\n return v.boolean(strictCheck);\r\n },\r\n\r\n /**\r\n * The `host` validator that returns a Zod schema with an optional stricter\r\n * check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `string` validator.\r\n *\r\n * @function host\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `host`\r\n * option.\r\n */\r\n host(strictCheck) {\r\n return v.string(strictCheck);\r\n },\r\n\r\n /**\r\n * The `port` validator that returns a Zod schema with an optional stricter\r\n * check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `nonNegativeNum`\r\n * validator.\r\n *\r\n * @function port\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `port`\r\n * option.\r\n */\r\n port(strictCheck) {\r\n return v.nonNegativeNum(strictCheck);\r\n },\r\n\r\n /**\r\n * The `uploadLimit` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `positiveNum` validator.\r\n *\r\n * @function uploadLimit\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `uploadLimit`\r\n * option.\r\n */\r\n uploadLimit(strictCheck) {\r\n return v.positiveNum(strictCheck);\r\n },\r\n\r\n /**\r\n * The `serverBenchmarking` validator that returns a Zod schema with\r\n * an optional stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `boolean` validator.\r\n *\r\n * @function serverBenchmarking\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating\r\n * the `serverBenchmarking` option.\r\n */\r\n serverBenchmarking(strictCheck) {\r\n return v.boolean(strictCheck);\r\n },\r\n\r\n /**\r\n * The `proxyHost` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `string` validator.\r\n *\r\n * @function proxyHost\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `proxyHost`\r\n * option.\r\n */\r\n proxyHost(strictCheck) {\r\n return v.string(strictCheck);\r\n },\r\n\r\n /**\r\n * The `proxyPort` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as a nullable `nonNegativeNum`\r\n * validator.\r\n *\r\n * @function proxyPort\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `proxyPort`\r\n * option.\r\n */\r\n proxyPort(strictCheck) {\r\n return v.nonNegativeNum(strictCheck).nullable();\r\n },\r\n\r\n /**\r\n * The `proxyTimeout` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `nonNegativeNum`\r\n * validator.\r\n *\r\n * @function proxyTimeout\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating\r\n * the `proxyTimeout` option.\r\n */\r\n proxyTimeout(strictCheck) {\r\n return v.nonNegativeNum(strictCheck);\r\n },\r\n\r\n /**\r\n * The `enableRateLimiting` validator that returns a Zod schema with\r\n * an optional stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `boolean` validator.\r\n *\r\n * @function enableRateLimiting\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating\r\n * the `enableRateLimiting` option.\r\n */\r\n enableRateLimiting(strictCheck) {\r\n return v.boolean(strictCheck);\r\n },\r\n\r\n /**\r\n * The `maxRequests` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `nonNegativeNum`\r\n * validator.\r\n *\r\n * @function maxRequests\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `maxRequests`\r\n * option.\r\n */\r\n maxRequests(strictCheck) {\r\n return v.nonNegativeNum(strictCheck);\r\n },\r\n\r\n /**\r\n * The `window` validator that returns a Zod schema with an optional stricter\r\n * check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `nonNegativeNum`\r\n * validator.\r\n *\r\n * @function window\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `window`\r\n * option.\r\n */\r\n window(strictCheck) {\r\n return v.nonNegativeNum(strictCheck);\r\n },\r\n\r\n /**\r\n * The `delay` validator that returns a Zod schema with an optional stricter\r\n * check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `nonNegativeNum`\r\n * validator.\r\n *\r\n * @function delay\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `delay`\r\n * option.\r\n */\r\n delay(strictCheck) {\r\n return v.nonNegativeNum(strictCheck);\r\n },\r\n\r\n /**\r\n * The `trustProxy` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `boolean` validator.\r\n *\r\n * @function trustProxy\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `trustProxy`\r\n * option.\r\n */\r\n trustProxy(strictCheck) {\r\n return v.boolean(strictCheck);\r\n },\r\n\r\n /**\r\n * The `skipKey` validator that returns a Zod schema with an optional stricter\r\n * check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `string` validator.\r\n *\r\n * @function skipKey\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `skipKey`\r\n * option.\r\n */\r\n skipKey(strictCheck) {\r\n return v.string(strictCheck);\r\n },\r\n\r\n /**\r\n * The `skipToken` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `string` validator.\r\n *\r\n * @function skipToken\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `skipToken`\r\n * option.\r\n */\r\n skipToken(strictCheck) {\r\n return v.string(strictCheck);\r\n },\r\n\r\n /**\r\n * The `enableSsl` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `boolean` validator.\r\n *\r\n * @function enableSsl\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `enableSsl`\r\n * option.\r\n */\r\n enableSsl(strictCheck) {\r\n return v.boolean(strictCheck);\r\n },\r\n\r\n /**\r\n * The `sslForce` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `boolean` validator.\r\n *\r\n * @function sslForce\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `sslForce`\r\n * option.\r\n */\r\n sslForce(strictCheck) {\r\n return v.boolean(strictCheck);\r\n },\r\n\r\n /**\r\n * The `sslPort` validator that returns a Zod schema with an optional stricter\r\n * check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `nonNegativeNum`\r\n * validator.\r\n *\r\n * @function sslPort\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `sslPort`\r\n * option.\r\n */\r\n sslPort(strictCheck) {\r\n return v.nonNegativeNum(strictCheck);\r\n },\r\n\r\n /**\r\n * The `sslCertPath` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `string` validator.\r\n *\r\n * @function sslCertPath\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `sslCertPath`\r\n * option.\r\n */\r\n sslCertPath(strictCheck) {\r\n return v.string(strictCheck);\r\n },\r\n\r\n /**\r\n * The `minWorkers` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `positiveNum` validator.\r\n *\r\n * @function minWorkers\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `minWorkers`\r\n * option.\r\n */\r\n minWorkers(strictCheck) {\r\n return v.positiveNum(strictCheck);\r\n },\r\n\r\n /**\r\n * The `maxWorkers` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `positiveNum` validator.\r\n *\r\n * @function maxWorkers\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `maxWorkers`\r\n * option.\r\n */\r\n maxWorkers(strictCheck) {\r\n return v.positiveNum(strictCheck);\r\n },\r\n\r\n /**\r\n * The `workLimit` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `positiveNum` validator.\r\n *\r\n * @function workLimit\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `workLimit`\r\n * option.\r\n */\r\n workLimit(strictCheck) {\r\n return v.positiveNum(strictCheck);\r\n },\r\n\r\n /**\r\n * The `acquireTimeout` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `nonNegativeNum`\r\n * validator.\r\n *\r\n * @function acquireTimeout\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating\r\n * the `acquireTimeout` option.\r\n */\r\n acquireTimeout(strictCheck) {\r\n return v.nonNegativeNum(strictCheck);\r\n },\r\n\r\n /**\r\n * The `createTimeout` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `nonNegativeNum`\r\n * validator.\r\n *\r\n * @function createTimeout\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating\r\n * the `createTimeout` option.\r\n */\r\n createTimeout(strictCheck) {\r\n return v.nonNegativeNum(strictCheck);\r\n },\r\n\r\n /**\r\n * The `destroyTimeout` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `nonNegativeNum`\r\n * validator.\r\n *\r\n * @function destroyTimeout\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating\r\n * the `destroyTimeout` option.\r\n */\r\n destroyTimeout(strictCheck) {\r\n return v.nonNegativeNum(strictCheck);\r\n },\r\n\r\n /**\r\n * The `idleTimeout` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `nonNegativeNum`\r\n * validator.\r\n *\r\n * @function idleTimeout\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating\r\n * the `idleTimeout` option.\r\n */\r\n idleTimeout(strictCheck) {\r\n return v.nonNegativeNum(strictCheck);\r\n },\r\n\r\n /**\r\n * The `createRetryInterval` validator that returns a Zod schema with\r\n * an optional stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `nonNegativeNum`\r\n * validator.\r\n *\r\n * @function createRetryInterval\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating\r\n * the `createRetryInterval` option.\r\n */\r\n createRetryInterval(strictCheck) {\r\n return v.nonNegativeNum(strictCheck);\r\n },\r\n\r\n /**\r\n * The `reaperInterval` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `nonNegativeNum`\r\n * validator.\r\n *\r\n * @function reaperInterval\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating\r\n * the `reaperInterval` option.\r\n */\r\n reaperInterval(strictCheck) {\r\n return v.nonNegativeNum(strictCheck);\r\n },\r\n\r\n /**\r\n * The `poolBenchmarking` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `boolean` validator.\r\n *\r\n * @function poolBenchmarking\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating\r\n * the `poolBenchmarking` option.\r\n */\r\n poolBenchmarking(strictCheck) {\r\n return v.boolean(strictCheck);\r\n },\r\n\r\n /**\r\n * The `resourcesInterval` validator that returns a Zod schema with\r\n * an optional stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `nonNegativeNum`\r\n * validator.\r\n *\r\n * @function resourcesInterval\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating\r\n * the `resourcesInterval` option.\r\n */\r\n resourcesInterval(strictCheck) {\r\n return v.nonNegativeNum(strictCheck);\r\n },\r\n\r\n /**\r\n * The `logLevel` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures that:\r\n *\r\n * - When `strictCheck` is true, the schema will accept integer number values\r\n * that are between 0 and 5 (inclusive).\r\n *\r\n * - When `strictCheck` is false, the schema will accept integer number values\r\n * and stringified integer number values that are between 1 and 5 (inclusive),\r\n * null, 'undefined', 'null', and '' which will be transformed to null.\r\n *\r\n * @function logLevel\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `logLevel`\r\n * option.\r\n */\r\n logLevel(strictCheck) {\r\n return strictCheck\r\n ? z.number().int().gte(0).lte(5)\r\n : z\r\n .union([\r\n z\r\n .string()\r\n .trim()\r\n .refine(\r\n (value) =>\r\n (!isNaN(Number(value)) &&\r\n value !== true &&\r\n !value.startsWith('[') &&\r\n Number.isInteger(Number(value)) &&\r\n Number(value) >= 0 &&\r\n Number(value) <= 5) ||\r\n ['undefined', 'null', ''].includes(value),\r\n {\r\n params: {\r\n errorMessage: 'The value must be within a 0 and 5 range'\r\n }\r\n }\r\n )\r\n .transform((value) =>\r\n !['undefined', 'null', ''].includes(value)\r\n ? Number(value)\r\n : null\r\n ),\r\n z.number().int().gte(0).lte(5)\r\n ])\r\n .nullable();\r\n },\r\n\r\n /**\r\n * The `logFile` validator that returns a Zod schema with an optional stricter\r\n * check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `string` validator.\r\n * Additionally, it must be a string that ends with '.log'.\r\n *\r\n * @function logFile\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `logFile`\r\n * option.\r\n */\r\n logFile(strictCheck) {\r\n return v\r\n .string(strictCheck)\r\n .refine(\r\n (value) =>\r\n value === null || (value.length >= 5 && value.endsWith('.log')),\r\n {\r\n params: {\r\n errorMessage: 'The value must be a string that ends with .log'\r\n }\r\n }\r\n );\r\n },\r\n\r\n /**\r\n * The `logDest` validator that returns a Zod schema with an optional stricter\r\n * check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `string` validator.\r\n *\r\n * @function logDest\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `logDest`\r\n * option.\r\n */\r\n logDest(strictCheck) {\r\n return v.string(strictCheck);\r\n },\r\n\r\n /**\r\n * The `logToConsole` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `boolean` validator.\r\n *\r\n * @function logToConsole\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating\r\n * the `logToConsole` option.\r\n */\r\n logToConsole(strictCheck) {\r\n return v.boolean(strictCheck);\r\n },\r\n\r\n /**\r\n * The `logToFile` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `boolean` validator.\r\n *\r\n * @function logToFile\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `logToFile`\r\n * option.\r\n */\r\n logToFile(strictCheck) {\r\n return v.boolean(strictCheck);\r\n },\r\n\r\n /**\r\n * The `enableUi` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `boolean` validator.\r\n *\r\n * @function enableUi\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `enableUi`\r\n * option.\r\n */\r\n enableUi(strictCheck) {\r\n return v.boolean(strictCheck);\r\n },\r\n\r\n /**\r\n * The `uiRoute` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `startsWith` validator.\r\n *\r\n * @function uiRoute\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `uiRoute`\r\n * option.\r\n */\r\n uiRoute(strictCheck) {\r\n return v.startsWith(['/'], strictCheck);\r\n },\r\n\r\n /**\r\n * The `nodeEnv` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `enum` validator.\r\n *\r\n * @function nodeEnv\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `nodeEnv`\r\n * option.\r\n */\r\n nodeEnv(strictCheck) {\r\n return v.enum(['development', 'production', 'test'], strictCheck);\r\n },\r\n\r\n /**\r\n * The `listenToProcessExits` validator that returns a Zod schema with\r\n * an optional stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `boolean` validator.\r\n *\r\n * @function listenToProcessExits\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating\r\n * the `listenToProcessExits` option.\r\n */\r\n listenToProcessExits(strictCheck) {\r\n return v.boolean(strictCheck);\r\n },\r\n\r\n /**\r\n * The `noLogo` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `boolean` validator.\r\n *\r\n * @function noLogo\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `noLogo`\r\n * option.\r\n */\r\n noLogo(strictCheck) {\r\n return v.boolean(strictCheck);\r\n },\r\n\r\n /**\r\n * The `hardResetPage` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `boolean` validator.\r\n *\r\n * @function hardResetPage\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating\r\n * the `hardResetPage` option.\r\n */\r\n hardResetPage(strictCheck) {\r\n return v.boolean(strictCheck);\r\n },\r\n\r\n /**\r\n * The `browserShellMode` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `boolean` validator.\r\n *\r\n * @function browserShellMode\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating\r\n * the `browserShellMode` option.\r\n */\r\n browserShellMode(strictCheck) {\r\n return v.boolean(strictCheck);\r\n },\r\n\r\n /**\r\n * The `validation` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `boolean` validator.\r\n *\r\n * @function validation\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `validation`\r\n * option.\r\n */\r\n validation(strictCheck) {\r\n return v.boolean(strictCheck);\r\n },\r\n\r\n /**\r\n * The `enableDebug` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `boolean` validator.\r\n *\r\n * @function enableDebug\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `enableDebug`\r\n * option.\r\n */\r\n enableDebug(strictCheck) {\r\n return v.boolean(strictCheck);\r\n },\r\n\r\n /**\r\n * The `headless` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `boolean` validator.\r\n *\r\n * @function headless\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `headless`\r\n * option.\r\n */\r\n headless(strictCheck) {\r\n return v.boolean(strictCheck);\r\n },\r\n\r\n /**\r\n * The `devtools` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `boolean` validator.\r\n *\r\n * @function devtools\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `devtools`\r\n * option.\r\n */\r\n devtools(strictCheck) {\r\n return v.boolean(strictCheck);\r\n },\r\n\r\n /**\r\n * The `listenToConsole` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `boolean` validator.\r\n *\r\n * @function listenToConsole\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating\r\n * the `listenToConsole` option.\r\n */\r\n listenToConsole(strictCheck) {\r\n return v.boolean(strictCheck);\r\n },\r\n\r\n /**\r\n * The `dumpio` validator that returns a Zod schema with an optional stricter\r\n * check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `boolean` validator.\r\n *\r\n * @function dumpio\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `dumpio`\r\n * option.\r\n */\r\n dumpio(strictCheck) {\r\n return v.boolean(strictCheck);\r\n },\r\n\r\n /**\r\n * The `slowMo` validator that returns a Zod schema with an optional stricter\r\n * check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `nonNegativeNum`\r\n * validator.\r\n *\r\n * @function slowMo\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `slowMo`\r\n * option.\r\n */\r\n slowMo(strictCheck) {\r\n return v.nonNegativeNum(strictCheck);\r\n },\r\n\r\n /**\r\n * The `debuggingPort` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `nonNegativeNum`\r\n * validator.\r\n *\r\n * @function debuggingPort\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating\r\n * the `debuggingPort` option.\r\n */\r\n debuggingPort(strictCheck) {\r\n return v.nonNegativeNum(strictCheck);\r\n },\r\n\r\n /**\r\n * The `requestId` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `string` validator.\r\n * Additionally, it must be a stringified UUID or can be null.\r\n *\r\n * @function requestId\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `requestId`\r\n * option.\r\n */\r\n requestId() {\r\n return z\r\n .string()\r\n .uuid({ message: 'The value must be a stringified UUID' })\r\n .nullable();\r\n }\r\n};\r\n\r\n// Schema for the puppeteer section of options\r\nconst PuppeteerSchema = (strictCheck) =>\r\n z\r\n .object({\r\n args: validators.args(strictCheck)\r\n })\r\n .partial();\r\n\r\n// Schema for the highcharts section of options\r\nconst HighchartsSchema = (strictCheck) =>\r\n z\r\n .object({\r\n version: validators.version(strictCheck),\r\n cdnUrl: validators.cdnUrl(strictCheck),\r\n forceFetch: validators.forceFetch(strictCheck),\r\n cachePath: validators.cachePath(strictCheck),\r\n coreScripts: validators.coreScripts(strictCheck),\r\n moduleScripts: validators.moduleScripts(strictCheck),\r\n indicatorScripts: validators.indicatorScripts(strictCheck),\r\n customScripts: validators.customScripts(strictCheck)\r\n })\r\n .partial();\r\n\r\n// Schema for the export section of options\r\nconst ExportSchema = (strictCheck) =>\r\n z\r\n .object({\r\n infile: validators.infile(strictCheck),\r\n instr: validators.instr(),\r\n options: validators.options(),\r\n svg: validators.svg(),\r\n outfile: validators.outfile(strictCheck),\r\n type: validators.type(strictCheck),\r\n constr: validators.constr(strictCheck),\r\n b64: validators.b64(strictCheck),\r\n noDownload: validators.noDownload(strictCheck),\r\n defaultHeight: validators.defaultHeight(strictCheck),\r\n defaultWidth: validators.defaultWidth(strictCheck),\r\n defaultScale: validators.defaultScale(strictCheck),\r\n height: validators.height(strictCheck),\r\n width: validators.width(strictCheck),\r\n scale: validators.scale(strictCheck),\r\n globalOptions: validators.globalOptions(),\r\n themeOptions: validators.themeOptions(),\r\n batch: validators.batch(false),\r\n rasterizationTimeout: validators.rasterizationTimeout(strictCheck)\r\n })\r\n .partial();\r\n\r\n// Schema for the customLogic section of options\r\nconst CustomLogicSchema = (strictCheck) =>\r\n z\r\n .object({\r\n allowCodeExecution: validators.allowCodeExecution(strictCheck),\r\n allowFileResources: validators.allowFileResources(strictCheck),\r\n customCode: validators.customCode(false),\r\n callback: validators.callback(false),\r\n resources: validators.resources(strictCheck),\r\n loadConfig: validators.loadConfig(false),\r\n createConfig: validators.createConfig(false)\r\n })\r\n .partial();\r\n\r\n// Schema for the server.proxy section of options\r\nconst ProxySchema = (strictCheck) =>\r\n z\r\n .object({\r\n host: validators.proxyHost(false),\r\n port: validators.proxyPort(strictCheck),\r\n timeout: validators.proxyTimeout(strictCheck)\r\n })\r\n .partial();\r\n\r\n// Schema for the server.rateLimiting section of options\r\nconst RateLimitingSchema = (strictCheck) =>\r\n z\r\n .object({\r\n enable: validators.enableRateLimiting(strictCheck),\r\n maxRequests: validators.maxRequests(strictCheck),\r\n window: validators.window(strictCheck),\r\n delay: validators.delay(strictCheck),\r\n trustProxy: validators.trustProxy(strictCheck),\r\n skipKey: validators.skipKey(false),\r\n skipToken: validators.skipToken(false)\r\n })\r\n .partial();\r\n\r\n// Schema for the server.ssl section of options\r\nconst SslSchema = (strictCheck) =>\r\n z\r\n .object({\r\n enable: validators.enableSsl(strictCheck),\r\n force: validators.sslForce(strictCheck),\r\n port: validators.sslPort(strictCheck),\r\n certPath: validators.sslCertPath(false)\r\n })\r\n .partial();\r\n\r\n// Schema for the server section of options\r\nconst ServerSchema = (strictCheck) =>\r\n z.object({\r\n enable: validators.enableServer(strictCheck).optional(),\r\n host: validators.host(strictCheck).optional(),\r\n port: validators.port(strictCheck).optional(),\r\n uploadLimit: validators.uploadLimit(strictCheck).optional(),\r\n benchmarking: validators.serverBenchmarking(strictCheck).optional(),\r\n proxy: ProxySchema(strictCheck).optional(),\r\n rateLimiting: RateLimitingSchema(strictCheck).optional(),\r\n ssl: SslSchema(strictCheck).optional()\r\n });\r\n\r\n// Schema for the pool section of options\r\nconst PoolSchema = (strictCheck) =>\r\n z\r\n .object({\r\n minWorkers: validators.minWorkers(strictCheck),\r\n maxWorkers: validators.maxWorkers(strictCheck),\r\n workLimit: validators.workLimit(strictCheck),\r\n acquireTimeout: validators.acquireTimeout(strictCheck),\r\n createTimeout: validators.createTimeout(strictCheck),\r\n destroyTimeout: validators.destroyTimeout(strictCheck),\r\n idleTimeout: validators.idleTimeout(strictCheck),\r\n createRetryInterval: validators.createRetryInterval(strictCheck),\r\n reaperInterval: validators.reaperInterval(strictCheck),\r\n benchmarking: validators.poolBenchmarking(strictCheck)\r\n })\r\n .partial();\r\n\r\n// Schema for the logging section of options\r\nconst LoggingSchema = (strictCheck) =>\r\n z\r\n .object({\r\n level: validators.logLevel(strictCheck),\r\n file: validators.logFile(strictCheck),\r\n dest: validators.logDest(strictCheck),\r\n toConsole: validators.logToConsole(strictCheck),\r\n toFile: validators.logToFile(strictCheck)\r\n })\r\n .partial();\r\n\r\n// Schema for the ui section of options\r\nconst UiSchema = (strictCheck) =>\r\n z\r\n .object({\r\n enable: validators.enableUi(strictCheck),\r\n route: validators.uiRoute(strictCheck)\r\n })\r\n .partial();\r\n\r\n// Schema for the other section of options\r\nconst OtherSchema = (strictCheck) =>\r\n z\r\n .object({\r\n nodeEnv: validators.nodeEnv(strictCheck),\r\n listenToProcessExits: validators.listenToProcessExits(strictCheck),\r\n noLogo: validators.noLogo(strictCheck),\r\n hardResetPage: validators.hardResetPage(strictCheck),\r\n browserShellMode: validators.browserShellMode(strictCheck),\r\n validation: validators.validation(strictCheck)\r\n })\r\n .partial();\r\n\r\n// Schema for the debug section of options\r\nconst DebugSchema = (strictCheck) =>\r\n z\r\n .object({\r\n enable: validators.enableDebug(strictCheck),\r\n headless: validators.headless(strictCheck),\r\n devtools: validators.devtools(strictCheck),\r\n listenToConsole: validators.listenToConsole(strictCheck),\r\n dumpio: validators.dumpio(strictCheck),\r\n slowMo: validators.slowMo(strictCheck),\r\n debuggingPort: validators.debuggingPort(strictCheck)\r\n })\r\n .partial();\r\n\r\n// Strict schema for the config\r\nexport const StrictConfigSchema = z.object({\r\n requestId: validators.requestId(),\r\n puppeteer: PuppeteerSchema(true),\r\n highcharts: HighchartsSchema(true),\r\n export: ExportSchema(true),\r\n customLogic: CustomLogicSchema(true),\r\n server: ServerSchema(true),\r\n pool: PoolSchema(true),\r\n logging: LoggingSchema(true),\r\n ui: UiSchema(true),\r\n other: OtherSchema(true),\r\n debug: DebugSchema(true)\r\n});\r\n\r\n// Loose schema for the config\r\nexport const LooseConfigSchema = z.object({\r\n requestId: validators.requestId(),\r\n puppeteer: PuppeteerSchema(false),\r\n highcharts: HighchartsSchema(false),\r\n export: ExportSchema(false),\r\n customLogic: CustomLogicSchema(false),\r\n server: ServerSchema(false),\r\n pool: PoolSchema(false),\r\n logging: LoggingSchema(false),\r\n ui: UiSchema(false),\r\n other: OtherSchema(false),\r\n debug: DebugSchema(false)\r\n});\r\n\r\n// Schema for the environment variables config\r\nexport const EnvSchema = z.object({\r\n // puppeteer\r\n PUPPETEER_ARGS: validators.args(false),\r\n\r\n // highcharts\r\n HIGHCHARTS_VERSION: validators.version(false),\r\n HIGHCHARTS_CDN_URL: validators.cdnUrl(false),\r\n HIGHCHARTS_FORCE_FETCH: validators.forceFetch(false),\r\n HIGHCHARTS_CACHE_PATH: validators.cachePath(false),\r\n HIGHCHARTS_ADMIN_TOKEN: validators.adminToken(false),\r\n HIGHCHARTS_CORE_SCRIPTS: validators.coreScripts(false),\r\n HIGHCHARTS_MODULE_SCRIPTS: validators.moduleScripts(false),\r\n HIGHCHARTS_INDICATOR_SCRIPTS: validators.indicatorScripts(false),\r\n HIGHCHARTS_CUSTOM_SCRIPTS: validators.customScripts(false),\r\n\r\n // export\r\n EXPORT_INFILE: validators.infile(false),\r\n EXPORT_INSTR: validators.instr(),\r\n EXPORT_OPTIONS: validators.options(),\r\n EXPORT_SVG: validators.svg(),\r\n EXPORT_BATCH: validators.batch(false),\r\n EXPORT_OUTFILE: validators.outfile(false),\r\n EXPORT_TYPE: validators.type(false),\r\n EXPORT_CONSTR: validators.constr(false),\r\n EXPORT_B64: validators.b64(false),\r\n EXPORT_NO_DOWNLOAD: validators.noDownload(false),\r\n EXPORT_HEIGHT: validators.height(false),\r\n EXPORT_WIDTH: validators.width(false),\r\n EXPORT_SCALE: validators.scale(false),\r\n EXPORT_DEFAULT_HEIGHT: validators.defaultHeight(false),\r\n EXPORT_DEFAULT_WIDTH: validators.defaultWidth(false),\r\n EXPORT_DEFAULT_SCALE: validators.defaultScale(false),\r\n EXPORT_GLOBAL_OPTIONS: validators.globalOptions(),\r\n EXPORT_THEME_OPTIONS: validators.themeOptions(),\r\n EXPORT_RASTERIZATION_TIMEOUT: validators.rasterizationTimeout(false),\r\n\r\n // custom\r\n CUSTOM_LOGIC_ALLOW_CODE_EXECUTION: validators.allowCodeExecution(false),\r\n CUSTOM_LOGIC_ALLOW_FILE_RESOURCES: validators.allowFileResources(false),\r\n CUSTOM_LOGIC_CUSTOM_CODE: validators.customCode(false),\r\n CUSTOM_LOGIC_CALLBACK: validators.callback(false),\r\n CUSTOM_LOGIC_RESOURCES: validators.resources(false),\r\n CUSTOM_LOGIC_LOAD_CONFIG: validators.loadConfig(false),\r\n CUSTOM_LOGIC_CREATE_CONFIG: validators.createConfig(false),\r\n\r\n // server\r\n SERVER_ENABLE: validators.enableServer(false),\r\n SERVER_HOST: validators.host(false),\r\n SERVER_PORT: validators.port(false),\r\n SERVER_UPLOAD_LIMIT: validators.uploadLimit(false),\r\n SERVER_BENCHMARKING: validators.serverBenchmarking(false),\r\n\r\n // server proxy\r\n SERVER_PROXY_HOST: validators.proxyHost(false),\r\n SERVER_PROXY_PORT: validators.proxyPort(false),\r\n SERVER_PROXY_TIMEOUT: validators.proxyTimeout(false),\r\n\r\n // server rate limiting\r\n SERVER_RATE_LIMITING_ENABLE: validators.enableRateLimiting(false),\r\n SERVER_RATE_LIMITING_MAX_REQUESTS: validators.maxRequests(false),\r\n SERVER_RATE_LIMITING_WINDOW: validators.window(false),\r\n SERVER_RATE_LIMITING_DELAY: validators.delay(false),\r\n SERVER_RATE_LIMITING_TRUST_PROXY: validators.trustProxy(false),\r\n SERVER_RATE_LIMITING_SKIP_KEY: validators.skipKey(false),\r\n SERVER_RATE_LIMITING_SKIP_TOKEN: validators.skipToken(false),\r\n\r\n // server ssl\r\n SERVER_SSL_ENABLE: validators.enableSsl(false),\r\n SERVER_SSL_FORCE: validators.sslForce(false),\r\n SERVER_SSL_PORT: validators.sslPort(false),\r\n SERVER_SSL_CERT_PATH: validators.sslCertPath(false),\r\n\r\n // pool\r\n POOL_MIN_WORKERS: validators.minWorkers(false),\r\n POOL_MAX_WORKERS: validators.maxWorkers(false),\r\n POOL_WORK_LIMIT: validators.workLimit(false),\r\n POOL_ACQUIRE_TIMEOUT: validators.acquireTimeout(false),\r\n POOL_CREATE_TIMEOUT: validators.createTimeout(false),\r\n POOL_DESTROY_TIMEOUT: validators.destroyTimeout(false),\r\n POOL_IDLE_TIMEOUT: validators.idleTimeout(false),\r\n POOL_CREATE_RETRY_INTERVAL: validators.createRetryInterval(false),\r\n POOL_REAPER_INTERVAL: validators.reaperInterval(false),\r\n POOL_BENCHMARKING: validators.poolBenchmarking(false),\r\n\r\n // logging\r\n LOGGING_LEVEL: validators.logLevel(false),\r\n LOGGING_FILE: validators.logFile(false),\r\n LOGGING_DEST: validators.logDest(false),\r\n LOGGING_TO_CONSOLE: validators.logToConsole(false),\r\n LOGGING_TO_FILE: validators.logToFile(false),\r\n\r\n // ui\r\n UI_ENABLE: validators.enableUi(false),\r\n UI_ROUTE: validators.uiRoute(false),\r\n\r\n // other\r\n OTHER_NODE_ENV: validators.nodeEnv(false),\r\n OTHER_LISTEN_TO_PROCESS_EXITS: validators.listenToProcessExits(false),\r\n OTHER_NO_LOGO: validators.noLogo(false),\r\n OTHER_HARD_RESET_PAGE: validators.hardResetPage(false),\r\n OTHER_BROWSER_SHELL_MODE: validators.browserShellMode(false),\r\n OTHER_VALIDATION: validators.validation(false),\r\n\r\n // debugger\r\n DEBUG_ENABLE: validators.enableDebug(false),\r\n DEBUG_HEADLESS: validators.headless(false),\r\n DEBUG_DEVTOOLS: validators.devtools(false),\r\n DEBUG_LISTEN_TO_CONSOLE: validators.listenToConsole(false),\r\n DEBUG_DUMPIO: validators.dumpio(false),\r\n DEBUG_SLOW_MO: validators.slowMo(false),\r\n DEBUG_DEBUGGING_PORT: validators.debuggingPort(false)\r\n});\r\n\r\n/**\r\n * Validates the environment variables options using the EnvSchema.\r\n *\r\n * @param {Object} process.env - The configuration options from environment\r\n * variables file to validate.\r\n *\r\n * @returns {Object} The parsed and validated environment variables.\r\n */\r\nexport const envs = EnvSchema.partial().parse(process.env);\r\n\r\n/**\r\n * Validates the configuration options using the `StrictConfigSchema`.\r\n *\r\n * @function strictValidate\r\n *\r\n * @param {Object} configOptions - The configuration options to validate.\r\n *\r\n * @returns {Object} The parsed and validated configuration options.\r\n */\r\nexport function strictValidate(configOptions) {\r\n return StrictConfigSchema.partial().parse(configOptions);\r\n}\r\n\r\n/**\r\n * Validates the configuration options using the `LooseConfigSchema`.\r\n *\r\n * @function looseValidate\r\n *\r\n * @param {Object} configOptions - The configuration options to validate.\r\n *\r\n * @returns {Object} The parsed and validated configuration options.\r\n */\r\nexport function looseValidate(configOptions) {\r\n return LooseConfigSchema.partial().parse(configOptions);\r\n}\r\n\r\n/**\r\n * Custom error mapping function for Zod schema validation.\r\n *\r\n * This function customizes the error messages produced by Zod schema\r\n * validation, providing more specific and user-friendly feedback based on the\r\n * issue type and context.\r\n *\r\n * The function modifies the error messages as follows:\r\n *\r\n * - For missing required values (undefined), it returns a message indicating\r\n * that no value was provided for the specific property.\r\n *\r\n * - For custom validation errors, if a custom error message is provided in the\r\n * issue parameters, it includes this message along with the invalid data\r\n * received.\r\n *\r\n * - For all other errors, it appends property-specific information to the\r\n * default error message provided by Zod.\r\n *\r\n * @function _customErrorMap\r\n *\r\n * @param {z.ZodIssue} issue - The issue object representing the validation\r\n * error.\r\n * @param {Object} context - The context object providing additional information\r\n * about the validation error.\r\n *\r\n * @returns {Object} An object containing the customized error message.\r\n */\r\nfunction _customErrorMap(issue, context) {\r\n // Get the chain of properties which error directly refers to\r\n const propertyName = issue.path.join('.');\r\n\r\n // Create the first part of the message about the property information\r\n const propertyInfo = `Invalid value for the ${propertyName}`;\r\n\r\n // Modified message for the invalid type\r\n if (issue.code === z.ZodIssueCode.invalid_type) {\r\n // Modified message for the required values\r\n if (issue.received === z.ZodParsedType.undefined) {\r\n return {\r\n message: `${propertyInfo} - No value was provided.`\r\n };\r\n }\r\n\r\n // Modified message for the specific invalid type when values exist\r\n return {\r\n message: `${propertyInfo} - Invalid type. ${context.defaultError}.`\r\n };\r\n }\r\n\r\n // Modified message for the custom validation\r\n if (issue.code === z.ZodIssueCode.custom) {\r\n // If the custom message for error exist, include it\r\n if (issue.params?.errorMessage) {\r\n return {\r\n message: `${propertyInfo} - ${issue.params?.errorMessage}, received '${context.data}'.`\r\n };\r\n }\r\n }\r\n\r\n // Modified message for the invalid union error\r\n if (issue.code === z.ZodIssueCode.invalid_union) {\r\n // Create the first part of the message about the multiple errors\r\n let message = `Multiple errors occurred for the ${propertyName}:\\n`;\r\n\r\n // Cycle through all errors and create a correct message\r\n issue.unionErrors.forEach((value) => {\r\n const index = value.issues[0].message.indexOf('-');\r\n message +=\r\n index !== -1\r\n ? `${value.issues[0].message}\\n`.substring(index)\r\n : `${value.issues[0].message}\\n`;\r\n });\r\n\r\n // Return the final message for the invalid union error\r\n return {\r\n message\r\n };\r\n }\r\n\r\n // Return the default error message, extended by the info about the property\r\n return {\r\n message: `${propertyInfo} - ${context.defaultError}.`\r\n };\r\n}\r\n\r\nexport default {\r\n validators,\r\n StrictConfigSchema,\r\n LooseConfigSchema,\r\n EnvSchema,\r\n envs,\r\n strictValidate,\r\n looseValidate\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * A custom error class for handling export-related errors. Extends the native\r\n * `Error` class to include additional properties like status code and stack\r\n * trace details.\r\n */\r\nclass ExportError extends Error {\r\n /**\r\n * Creates an instance of the `ExportError`.\r\n *\r\n * @param {string} message - The error message to be displayed.\r\n * @param {number} statusCode - Optional HTTP status code associated\r\n * with the error (e.g., 400, 500).\r\n */\r\n constructor(message, statusCode) {\r\n super();\r\n\r\n // Set the `message` and `stackMessage` with provided message\r\n this.message = message;\r\n this.stackMessage = message;\r\n\r\n // Set the `statusCode` if provided\r\n if (statusCode) {\r\n this.statusCode = statusCode;\r\n }\r\n }\r\n\r\n /**\r\n * Sets additional error details based on an existing error object.\r\n *\r\n * @param {Error} error - An error object containing details to populate\r\n * the `ExportError` instance.\r\n *\r\n * @returns {ExportError} The updated instance of the `ExportError` class.\r\n */\r\n setError(error) {\r\n // Save the provided error\r\n this.error = error;\r\n\r\n // Set the error's name if present\r\n if (error.name) {\r\n this.name = error.name;\r\n }\r\n\r\n // Set the error's status code if present\r\n if (error.statusCode) {\r\n this.statusCode = error.statusCode;\r\n }\r\n\r\n // Set the error's stack and stack's message if present\r\n if (error.stack) {\r\n this.stackMessage = error.message;\r\n this.stack = error.stack;\r\n }\r\n\r\n // Return updated `ExportError` instance\r\n return this;\r\n }\r\n}\r\n\r\nexport default ExportError;\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * @overview This module manages configuration for the Highcharts Export Server\r\n * by loading and merging options from multiple sources, such as the default\r\n * settings, environment variables, user-provided options, and command-line\r\n * arguments. Ensures the global options are up-to-date with the highest\r\n * priority values. Provides functions for accessing and updating configuration.\r\n */\r\n\r\nimport { readFileSync } from 'fs';\r\n\r\nimport { log, logWithStack, logZodIssues } from './logger.js';\r\nimport { deepCopy, getAbsolutePath, isObject } from './utils.js';\r\nimport {\r\n envs,\r\n looseValidate,\r\n strictValidate,\r\n validators\r\n} from './validation.js';\r\n\r\nimport defaultConfig from './schemas/config.js';\r\n\r\nimport ExportError from './errors/ExportError.js';\r\n\r\n// Sets the global options with initial values from the default config\r\nconst globalOptions = _initOptions(defaultConfig);\r\n\r\n// Properties nesting level of all options\r\nconst nestedProps = _createNestedProps(defaultConfig);\r\n\r\n// Properties names that should not be recursively merged\r\nconst absoluteProps = _createAbsoluteProps(defaultConfig);\r\n\r\n/**\r\n * Retrieves a copy of the global options object or an original global options\r\n * object, based on the `getCopy` flag.\r\n *\r\n * @function getOptions\r\n *\r\n * @param {boolean} [getCopy=true] - Specifies whether to return a copied\r\n * object of the global options (`true`) or a reference to the global options\r\n * object (`false`). The default value is `true`.\r\n *\r\n * @returns {Object} A copy of the global options object, or a reference\r\n * to the global options object.\r\n */\r\nexport function getOptions(getCopy = true) {\r\n // Return a copy or an original global options object\r\n return getCopy ? deepCopy(globalOptions) : globalOptions;\r\n}\r\n\r\n/**\r\n * Updates and returns the global options object or a copy of the global options\r\n * object, based on the `getCopy` flag. The `newOptions` object can be\r\n * strictly validated depending on the `strictCheck` flag.\r\n *\r\n * @function updateOptions\r\n *\r\n * @param {Object} newOptions - An object containing the new options to be\r\n * merged into the global options.\r\n * @param {boolean} [getCopy=false] - Determines whether to merge the new\r\n * options into a copy of the global options object (`true`) or directly into\r\n * the global options object (`false`). The default value is `false`.\r\n * @param {boolean} [strictCheck=true] - Determines if stricter validation\r\n * should be applied. The default value is `true`.\r\n *\r\n * @returns {Object} The updated options object, either the modified global\r\n * options or a modified copy, based on the value of `getCopy`.\r\n */\r\nexport function updateOptions(newOptions, getCopy = false, strictCheck = true) {\r\n // Merge new options to the global options or its copy and return the result\r\n return _mergeOptions(\r\n // First, get the options\r\n getOptions(getCopy),\r\n // Next, validate the new options\r\n validateOptions(newOptions, strictCheck)\r\n );\r\n}\r\n\r\n/**\r\n * Updates and returns the global options object with values provided through\r\n * the CLI, keeping the principle of options load priority. The function accepts\r\n * a `cliArgs` array containing arguments from the CLI, which will be validated\r\n * and applied if provided.\r\n *\r\n * The function prioritizes values in the following order:\r\n *\r\n * 1. Values from the command line interface (CLI).\r\n * 2. Values from a custom JSON file (loaded by the `--loadConfig` option).\r\n *\r\n * @function setCliOptions\r\n *\r\n * @param {Array} cliArgs - An array of command line arguments used\r\n * for additional configuration.\r\n *\r\n * @returns {Object} The updated global options object, reflecting the merged\r\n * configuration from sources provided through the CLI.\r\n */\r\nexport function setCliOptions(cliArgs) {\r\n // Only for the CLI usage\r\n if (cliArgs && Array.isArray(cliArgs) && cliArgs.length) {\r\n try {\r\n // Get options from the custom JSON loaded via the `--loadConfig`\r\n const configOptions = _loadConfigFile(cliArgs);\r\n\r\n // Update global options with validated values from the `configOptions`\r\n updateOptions(configOptions);\r\n } catch (error) {\r\n log(2, '[validation] No options added from the `--loadConfig` option.');\r\n }\r\n\r\n try {\r\n // Get options from the CLI\r\n const cliOptions = _pairArgumentValue(cliArgs);\r\n\r\n // Update global options with validated values from the `cliOptions`\r\n updateOptions(cliOptions, false, false);\r\n } catch (error) {\r\n log(2, '[validation] No options added from the CLI arguments.');\r\n }\r\n }\r\n\r\n // Return reference to the global options\r\n return getOptions(false);\r\n}\r\n\r\n/**\r\n * Maps old-structured configuration options (PhantomJS-based) to a new format\r\n * (Puppeteer-based). This function converts flat, old-structured options into\r\n * a new, nested configuration format based on a predefined mapping provided\r\n * in the `nestedProps` object. The new format is used for Puppeteer, while\r\n * the old format was used for PhantomJS.\r\n *\r\n * @function mapToNewOptions\r\n *\r\n * @param {Object} oldOptions - The old, flat configuration options\r\n * to be converted.\r\n *\r\n * @returns {Object} A new object containing options structured according\r\n * to the mapping defined in the `nestedProps` object or an empty object\r\n * if the provided `oldOptions` is not a correct object.\r\n */\r\nexport function mapToNewOptions(oldOptions) {\r\n // An object for the new structured options\r\n const newOptions = {};\r\n\r\n // Check if provided value is a correct object\r\n if (isObject(oldOptions)) {\r\n // Iterate over each key-value pair in the old-structured options\r\n for (const [key, value] of Object.entries(oldOptions)) {\r\n // If there is a nested mapping, split it into a properties chain\r\n const propertiesChain = nestedProps[key]\r\n ? nestedProps[key].split('.')\r\n : [];\r\n\r\n // If it is the last property in the chain, assign the value, otherwise,\r\n // create or reuse the nested object\r\n propertiesChain.reduce(\r\n (obj, prop, index) =>\r\n (obj[prop] =\r\n propertiesChain.length - 1 === index ? value : obj[prop] || {}),\r\n newOptions\r\n );\r\n }\r\n } else {\r\n log(\r\n 2,\r\n '[config] No correct object with options was provided. Returning an empty object.'\r\n );\r\n }\r\n\r\n // Return the new, structured options object\r\n return newOptions;\r\n}\r\n\r\n/**\r\n * Validates a specified option using the corresponding validator from the\r\n * configuration object. Returns the original option if the validation\r\n * is disabled globally.\r\n *\r\n * @function validateOption\r\n *\r\n * @param {string} name - The name of the option to validate.\r\n * @param {any} configOption - The value of the option to validate.\r\n * @param {boolean} [strictCheck=true] - Determines if stricter validation\r\n * should be applied. The default value is `true`.\r\n *\r\n * @returns {any} The parsed and validated value of the option.\r\n */\r\nexport function validateOption(name, configOption, strictCheck = true) {\r\n // Return the original option if the validation is disabled\r\n if (!getOptions().other.validation) {\r\n return configOption;\r\n }\r\n\r\n try {\r\n // Return validated option\r\n return validators[name](strictCheck).parse(configOption);\r\n } catch (error) {\r\n // Log Zod issues\r\n logZodIssues(\r\n 1,\r\n error.issues,\r\n `[validation] The ${name} option validation error`\r\n );\r\n\r\n // Throw validation error\r\n throw new ExportError(\r\n `[validation] The ${name} option validation error`,\r\n 400\r\n );\r\n }\r\n}\r\n\r\n/**\r\n * Validates the provided configuration options for the exporting process.\r\n * Returns the original option if the validation is disabled globally.\r\n *\r\n * @function validateOptions\r\n *\r\n * @param {Object} configOptions - The configuration options to be validated.\r\n * @param {boolean} [strictCheck=true] - Determines if stricter validation\r\n * should be applied. The default value is `true`.\r\n *\r\n * @returns {Object} The parsed and validated configuration options object.\r\n */\r\nexport function validateOptions(configOptions, strictCheck = true) {\r\n // Return the original config if the validation is disabled\r\n if (!getOptions().other.validation) {\r\n return configOptions;\r\n }\r\n\r\n try {\r\n // Return validated options\r\n return strictCheck\r\n ? strictValidate(configOptions)\r\n : looseValidate(configOptions);\r\n } catch (error) {\r\n // Log Zod issues\r\n logZodIssues(1, error.issues, '[validation] Options validation error');\r\n\r\n // Throw validation error\r\n throw new ExportError('[validation] Options validation error', 400);\r\n }\r\n}\r\n\r\n/**\r\n * Validates, parses, and checks if the provided config is allowed set\r\n * of options.\r\n *\r\n * @function isAllowedConfig\r\n *\r\n * @param {unknown} config - The config to be validated and parsed as a set\r\n * of options. Must be either an object or a string.\r\n * @param {boolean} [toString=false] - Whether to return a stringified version\r\n * of the parsed config. The default value is `false`.\r\n * @param {boolean} [allowFunctions=false] - Whether to allow functions\r\n * in the parsed config. If `true`, functions are preserved. Otherwise, when\r\n * a function is found, `null` is returned. The default value is `false`.\r\n *\r\n * @returns {(Object|string|null)} Returns a parsed set of options object,\r\n * a stringified set of options object if the `toString` is `true`, and `null`\r\n * if the config is not a valid set of options or parsing fails.\r\n */\r\nexport function isAllowedConfig(\r\n config,\r\n toString = false,\r\n allowFunctions = false\r\n) {\r\n try {\r\n // Accept only objects and strings\r\n if (!isObject(config) && typeof config !== 'string') {\r\n // Return `null` if any other type\r\n return null;\r\n }\r\n\r\n // Get the object representation of the original config\r\n const objectConfig =\r\n typeof config === 'string'\r\n ? allowFunctions\r\n ? eval(`(${config})`)\r\n : JSON.parse(config)\r\n : config;\r\n\r\n // Preserve or remove potential functions based on the `allowFunctions` flag\r\n const stringifiedOptions = _optionsStringify(\r\n objectConfig,\r\n allowFunctions,\r\n false\r\n );\r\n\r\n // Parse the config to check if it is valid set of options\r\n const parsedOptions = allowFunctions\r\n ? JSON.parse(\r\n _optionsStringify(objectConfig, allowFunctions, true),\r\n (_, value) =>\r\n typeof value === 'string' && value.startsWith('function')\r\n ? eval(`(${value})`)\r\n : value\r\n )\r\n : JSON.parse(stringifiedOptions);\r\n\r\n // Return stringified or object options based on the `toString` flag\r\n return toString ? stringifiedOptions : parsedOptions;\r\n } catch (error) {\r\n // Return `null` if parsing fails\r\n return null;\r\n }\r\n}\r\n\r\n/**\r\n * Initializes and returns the global options object based on the provided\r\n * configuration, setting values from nested properties recursively.\r\n *\r\n * The function prioritizes values in the following order:\r\n *\r\n * 1. Values from environment variables (specified in the `.env` file).\r\n * 2. Values from the `./lib/schemas/config.js` file (defaults).\r\n *\r\n * @function _initOptions\r\n *\r\n * @param {Object} config - The configuration object used for initializing\r\n * the global options. It should include nested properties with a `value`\r\n * and an `envLink` for linking to environment variables.\r\n *\r\n * @returns {Object} The initialized global options object, populated with\r\n * values based on the provided configuration and the established priority\r\n * order.\r\n */\r\nfunction _initOptions(config) {\r\n // Init the object for options\r\n const options = {};\r\n\r\n // Start initializing the `options` object recursively\r\n for (const [name, item] of Object.entries(config)) {\r\n if (Object.prototype.hasOwnProperty.call(item, 'value')) {\r\n // Set the correct value based on the established priority order\r\n if (envs[item.envLink] !== undefined && envs[item.envLink] !== null) {\r\n // The environment variables value\r\n options[name] = envs[item.envLink];\r\n } else {\r\n // The value from the config file\r\n options[name] = item.value;\r\n }\r\n } else {\r\n // Create a category of options in the `options` object\r\n options[name] = _initOptions(item);\r\n }\r\n }\r\n\r\n // Return the created `options` object\r\n return options;\r\n}\r\n\r\n/**\r\n * Recursively merges two sets of configuration options, taking into account\r\n * properties specified in the `absoluteProps` array that require absolute\r\n * merging. The `originalOptions` object will be extended with options from\r\n * the `newOptions` object.\r\n *\r\n * @function _mergeOptions\r\n *\r\n * @param {Object} originalOptions - The original configuration options object\r\n * to be extended.\r\n * @param {Object} newOptions - The new configuration options object to merge.\r\n *\r\n * @returns {Object} The extended `originalOptions` object.\r\n */\r\nfunction _mergeOptions(originalOptions, newOptions) {\r\n // Check if the `originalOptions` and `newOptions` are correct objects\r\n if (isObject(originalOptions) && isObject(newOptions)) {\r\n for (const [key, value] of Object.entries(newOptions)) {\r\n originalOptions[key] =\r\n isObject(value) &&\r\n !absoluteProps.includes(key) &&\r\n originalOptions[key] !== undefined\r\n ? _mergeOptions(originalOptions[key], value)\r\n : value !== undefined\r\n ? value\r\n : originalOptions[key] || null;\r\n }\r\n }\r\n\r\n // Return the original (modified or not) options\r\n return originalOptions;\r\n}\r\n\r\n/**\r\n * Converts the provided options object to a JSON string with the option\r\n * to preserve functions. In order for a function to be preserved, it needs\r\n * to follow the format `function (...) {...}`. Such a function can also\r\n * be stringified.\r\n *\r\n * @function _optionsStringify\r\n *\r\n * @param {Object} options - The options object to be converted to a string.\r\n * @param {boolean} allowFunctions - If set to `true`, functions are preserved\r\n * in the output. Otherwise an error is thrown.\r\n * @param {boolean} stringifyFunctions - If set to `true`, functions are saved\r\n * as strings. The `allowFunctions` must be set to `true` as well for this\r\n * to take an effect.\r\n *\r\n * @returns {string} The JSON-formatted string representing the options.\r\n *\r\n * @throws {Error} Throws an `Error` when functions are not allowed but are\r\n * found in provided options object.\r\n */\r\nfunction _optionsStringify(options, allowFunctions, stringifyFunctions) {\r\n const replacerCallback = (_, value) => {\r\n // Trim string values\r\n if (typeof value === 'string') {\r\n value = value.trim();\r\n }\r\n\r\n // If `value` is a function or stringified function\r\n if (\r\n typeof value === 'function' ||\r\n (typeof value === 'string' &&\r\n value.startsWith('function') &&\r\n value.endsWith('}'))\r\n ) {\r\n // If the `allowFunctions` is set to `true`, preserve functions\r\n if (allowFunctions) {\r\n // Based on the `stringifyFunctions` options, set function values\r\n return stringifyFunctions\r\n ? // As stringified functions\r\n `\"EXP_FUN${(value + '').replaceAll(/\\s+/g, ' ')}EXP_FUN\"`\r\n : // As functions\r\n `EXP_FUN${(value + '').replaceAll(/\\s+/g, ' ')}EXP_FUN`;\r\n } else {\r\n // Throw an error otherwise\r\n throw new Error();\r\n }\r\n }\r\n\r\n // In all other cases, simply return the value\r\n return value;\r\n };\r\n\r\n // Stringify options and if required, replace special functions marks\r\n return JSON.stringify(options, replacerCallback).replaceAll(\r\n stringifyFunctions ? /\\\\\"EXP_FUN|EXP_FUN\\\\\"/g : /\"EXP_FUN|EXP_FUN\"/g,\r\n ''\r\n );\r\n}\r\n\r\n/**\r\n * Loads additional configuration from a specified file provided via\r\n * the `--loadConfig` option in the command-line arguments.\r\n *\r\n * @function _loadConfigFile\r\n *\r\n * @param {Array} cliArgs - Command-line arguments to search\r\n * for the `--loadConfig` option and the corresponding file path.\r\n *\r\n * @returns {Object} The additional configuration loaded from the specified\r\n * file, or an empty object if the file is not found, invalid, or an error\r\n * occurs.\r\n */\r\nfunction _loadConfigFile(cliArgs) {\r\n // Get the allow flags for the custom logic check\r\n const { allowCodeExecution, allowFileResources } = getOptions().customLogic;\r\n\r\n // Check if the `--loadConfig` option was used\r\n const configIndex = cliArgs.findIndex(\r\n (arg) => arg.replace(/-/g, '') === 'loadConfig'\r\n );\r\n\r\n // Get the `--loadConfig` option value\r\n const configFileName = configIndex > -1 && cliArgs[configIndex + 1];\r\n\r\n // Check if the `--loadConfig` is present and has a correct value\r\n if (configFileName && allowFileResources) {\r\n try {\r\n // Load an optional custom JSON config file\r\n return isAllowedConfig(\r\n readFileSync(getAbsolutePath(configFileName), 'utf8'),\r\n false,\r\n allowCodeExecution\r\n );\r\n } catch (error) {\r\n logWithStack(\r\n 2,\r\n error,\r\n `[config] Unable to load the configuration from the ${configFileName} file.`\r\n );\r\n }\r\n }\r\n\r\n // No additional options to return\r\n return {};\r\n}\r\n\r\n/**\r\n * Parses command-line arguments and pairs each argument with its corresponding\r\n * option in the configuration. The values are structured into a nested options\r\n * object, based on predefined mappings in the `nestedProps` object.\r\n *\r\n * @function _pairArgumentValue\r\n *\r\n * @param {Array} cliArgs - An array of command-line arguments\r\n * containing options and their associated values.\r\n *\r\n * @returns {Object} An updated options object where each option from\r\n * the command-line is paired with its value, structured into nested objects\r\n * as defined.\r\n */\r\nfunction _pairArgumentValue(cliArgs) {\r\n // An empty object to collect and structurize data from the args\r\n const cliOptions = {};\r\n\r\n // Cycle through all CLI args and filter them\r\n for (let i = 0; i < cliArgs.length; i++) {\r\n const option = cliArgs[i].replace(/-/g, '');\r\n\r\n // Find the right place for property's value\r\n const propertiesChain = nestedProps[option]\r\n ? nestedProps[option].split('.')\r\n : [];\r\n\r\n // Create options object with values from CLI for later parsing and merging\r\n propertiesChain.reduce((obj, prop, index) => {\r\n if (propertiesChain.length - 1 === index) {\r\n const value = cliArgs[++i];\r\n if (!value) {\r\n log(\r\n 2,\r\n `[config] Missing value for the CLI '--${option}' argument. Using the default value.`\r\n );\r\n }\r\n obj[prop] = value || null;\r\n } else if (obj[prop] === undefined) {\r\n obj[prop] = {};\r\n }\r\n return obj[prop];\r\n }, cliOptions);\r\n }\r\n\r\n // Return parsed CLI options\r\n return cliOptions;\r\n}\r\n\r\n/**\r\n * Recursively generates a mapping of nested argument chains from a nested\r\n * config object. This function traverses a nested object and creates a mapping\r\n * where each key is an argument name (either from `cliName`, `legacyName`,\r\n * or the original key) and each value is a string representing the chain\r\n * of nested properties leading to that argument.\r\n *\r\n * @function _createNestedProps\r\n *\r\n * @param {Object} config - The configuration object.\r\n * @param {Object} [nestedProps={}] - The accumulator object for storing\r\n * the resulting arguments chains. The default value is an empty object.\r\n * @param {string} [propChain=''] - The current chain of nested properties,\r\n * used internally during recursion. The default value is an empty string.\r\n *\r\n * @returns {Object} An object mapping argument names to their corresponding\r\n * nested property chains.\r\n */\r\nfunction _createNestedProps(config, nestedProps = {}, propChain = '') {\r\n Object.keys(config).forEach((key) => {\r\n // Get the specific section\r\n const entry = config[key];\r\n\r\n // Check if there is still more depth to traverse\r\n if (typeof entry.value === 'undefined') {\r\n // Recurse into deeper levels of nested arguments\r\n _createNestedProps(entry, nestedProps, `${propChain}.${key}`);\r\n } else {\r\n // Create the chain of nested arguments\r\n nestedProps[entry.cliName || key] = `${propChain}.${key}`.substring(1);\r\n\r\n // Support for the legacy, PhantomJS properties names\r\n if (entry.legacyName !== undefined) {\r\n nestedProps[entry.legacyName] = `${propChain}.${key}`.substring(1);\r\n }\r\n }\r\n });\r\n\r\n // Return the object with nested argument chains\r\n return nestedProps;\r\n}\r\n\r\n/**\r\n * Recursively gathers the names of properties from a configuration object that\r\n * should be treated as absolute properties. These properties have values that\r\n * are objects and do not contain further nested depth when merging an object\r\n * containing these options.\r\n *\r\n * @function _createAbsoluteProps\r\n *\r\n * @param {Object} config - The configuration object.\r\n * @param {Array} [absoluteProps=[]] - An array to collect the names\r\n * of absolute properties. The default value is an empty array.\r\n *\r\n * @returns {Array} An array containing the names of absolute\r\n * properties.\r\n */\r\nfunction _createAbsoluteProps(config, absoluteProps = []) {\r\n Object.keys(config).forEach((key) => {\r\n // Get the specific section\r\n const entry = config[key];\r\n\r\n // Check if there is still more depth to traverse\r\n if (typeof entry.types === 'undefined') {\r\n // Recurse into deeper levels\r\n _createAbsoluteProps(entry, absoluteProps);\r\n } else {\r\n // If the option can be an object, save its type in the array\r\n if (entry.types.includes('Object')) {\r\n absoluteProps.push(key);\r\n }\r\n }\r\n });\r\n\r\n // Return the array with the names of absolute properties\r\n return absoluteProps;\r\n}\r\n\r\nexport default {\r\n getOptions,\r\n updateOptions,\r\n setCliOptions,\r\n mapToNewOptions,\r\n validateOption,\r\n validateOptions,\r\n isAllowedConfig\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * @overview HTTP utility module for fetching and posting data. Supports both\r\n * HTTP and HTTPS protocols, providing methods to make GET and POST requests\r\n * with customizable options. Includes protocol determination based on URL\r\n * and augments response objects with a 'text' property for easier data access.\r\n */\r\n\r\nimport http from 'http';\r\nimport https from 'https';\r\n\r\n/**\r\n * Sends a GET request to the specified URL using either HTTP or HTTPS protocol.\r\n *\r\n * @async\r\n * @function get\r\n *\r\n * @param {string} url - The URL to get data from.\r\n * @param {Object} [requestOptions={}] - Options for the HTTP/HTTPS request.\r\n * The default value is an empty object.\r\n *\r\n * @returns {Promise} A Promise that resolves to the HTTP/HTTPS response\r\n * object with added 'text' property or rejecting with an error.\r\n */\r\nexport async function get(url, requestOptions = {}) {\r\n return new Promise((resolve, reject) => {\r\n // Decide on the protocol\r\n _getProtocolModule(url)\r\n .get(url, requestOptions, (response) => {\r\n let responseData = '';\r\n\r\n // A chunk of data has been received\r\n response.on('data', (chunk) => {\r\n responseData += chunk;\r\n });\r\n\r\n // The whole response has been received\r\n response.on('end', () => {\r\n if (!responseData) {\r\n reject('Nothing was fetched from the URL.');\r\n }\r\n\r\n // Get the full result and resolve the request\r\n response.text = responseData;\r\n resolve(response);\r\n });\r\n })\r\n .on('error', (error) => {\r\n reject(error);\r\n });\r\n });\r\n}\r\n\r\n/**\r\n * Sends a POST request to the specified URL with the provided JSON body using\r\n * either HTTP or HTTPS protocol.\r\n *\r\n * @async\r\n * @function post\r\n *\r\n * @param {string} url - The URL to send the POST request to.\r\n * @param {Object} [body={}] - The JSON body to include in the POST request.\r\n * The default value is an empty object.\r\n * @param {Object} [requestOptions={}] - Options for the HTTP/HTTPS request.\r\n * The default value is an empty object.\r\n *\r\n * @returns {Promise} A Promise that resolves to the HTTP/HTTPS response\r\n * object with added 'text' property or rejecting with an error.\r\n */\r\nexport async function post(url, body = {}, requestOptions = {}) {\r\n return new Promise((resolve, reject) => {\r\n const data = JSON.stringify(body);\r\n\r\n // Set default headers and merge with `requestOptions`\r\n const options = Object.assign(\r\n {\r\n method: 'POST',\r\n headers: {\r\n 'Content-Type': 'application/json',\r\n 'Content-Length': data.length\r\n }\r\n },\r\n requestOptions\r\n );\r\n\r\n // Decide on the protocol\r\n const request = _getProtocolModule(url)\r\n .request(url, options, (response) => {\r\n let responseData = '';\r\n\r\n // A chunk of data has been received\r\n response.on('data', (chunk) => {\r\n responseData += chunk;\r\n });\r\n\r\n // The whole response has been received\r\n response.on('end', () => {\r\n try {\r\n // Get the full result and resolve the request\r\n response.text = responseData;\r\n resolve(response);\r\n } catch (error) {\r\n reject(error);\r\n }\r\n });\r\n })\r\n .on('error', (error) => {\r\n reject(error);\r\n });\r\n\r\n // Write the request body and end the request\r\n request.write(data);\r\n request.end();\r\n });\r\n}\r\n\r\n/**\r\n * Returns the HTTP or HTTPS protocol module based on the provided URL.\r\n *\r\n * @function _getProtocolModule\r\n *\r\n * @param {string} url - The URL to determine the protocol.\r\n *\r\n * @returns {Object} The HTTP or HTTPS protocol module (`http` or `https`).\r\n */\r\nfunction _getProtocolModule(url) {\r\n return url.startsWith('https') ? https : http;\r\n}\r\n\r\nexport default {\r\n get,\r\n post\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * @overview The cache manager is responsible for handling and managing\r\n * the Highcharts library along with its dependencies. It ensures that these\r\n * resources are stored and retrieved efficiently to optimize performance\r\n * and reduce redundant network requests. The cache is stored in the `.cache`\r\n * directory by default, which serves as a dedicated folder for keeping cached\r\n * files.\r\n */\r\n\r\nimport { existsSync, mkdirSync, readFileSync, writeFileSync } from 'fs';\r\nimport { join } from 'path';\r\n\r\nimport { HttpsProxyAgent } from 'https-proxy-agent';\r\n\r\nimport { getOptions, updateOptions } from './config.js';\r\nimport { get } from './fetch.js';\r\nimport { log } from './logger.js';\r\nimport { getAbsolutePath } from './utils.js';\r\n\r\nimport ExportError from './errors/ExportError.js';\r\n\r\n// The initial cache template\r\nconst cache = {\r\n cdnUrl: 'https://code.highcharts.com',\r\n activeManifest: {},\r\n sources: '',\r\n hcVersion: ''\r\n};\r\n\r\n/**\r\n * Checks the cache for Highcharts dependencies, updates the cache if needed,\r\n * and loads the sources.\r\n *\r\n * @async\r\n * @function checkCache\r\n *\r\n * @param {Object} highchartsOptions - The configuration object containing\r\n * `highcharts` options.\r\n * @param {Object} serverProxyOptions- The configuration object containing\r\n * `server.proxy` options.\r\n */\r\nexport async function checkCache(highchartsOptions, serverProxyOptions) {\r\n try {\r\n let fetchedModules;\r\n\r\n // Get the cache path\r\n const cachePath = getCachePath();\r\n\r\n // Prepare paths to manifest and sources from the cache folder\r\n const manifestPath = join(cachePath, 'manifest.json');\r\n const sourcePath = join(cachePath, 'sources.js');\r\n\r\n // Create the cache destination if it doesn't exist already\r\n !existsSync(cachePath) && mkdirSync(cachePath, { recursive: true });\r\n\r\n // Fetch all the scripts either if the `manifest.json` does not exist\r\n // or if the `forceFetch` option is enabled\r\n if (!existsSync(manifestPath) || highchartsOptions.forceFetch) {\r\n log(3, '[cache] Fetching and caching Highcharts dependencies.');\r\n\r\n // The initial cache update\r\n fetchedModules = await _updateCache(\r\n highchartsOptions,\r\n serverProxyOptions,\r\n sourcePath\r\n );\r\n } else {\r\n let requestUpdate = false;\r\n\r\n // Read the manifest JSON\r\n const manifest = JSON.parse(readFileSync(manifestPath), 'utf8');\r\n\r\n // Check if the modules is an array, if so, we rewrite it to a map to make\r\n // it easier to resolve modules\r\n if (manifest.modules && Array.isArray(manifest.modules)) {\r\n const moduleMap = {};\r\n manifest.modules.forEach((m) => (moduleMap[m] = 1));\r\n manifest.modules = moduleMap;\r\n }\r\n\r\n // Get the actual number of scripts to be fetched\r\n const { coreScripts, moduleScripts, indicatorScripts } =\r\n highchartsOptions;\r\n const numberOfModules =\r\n coreScripts.length + moduleScripts.length + indicatorScripts.length;\r\n\r\n // Compare the loaded highcharts config with the contents in cache.\r\n // If there are changes, fetch requested modules and products,\r\n // and bake them into a giant blob. Save the blob.\r\n if (manifest.version !== highchartsOptions.version) {\r\n // Check the Highcharts version\r\n log(\r\n 2,\r\n '[cache] A Highcharts version mismatch in the cache, need to re-fetch.'\r\n );\r\n requestUpdate = true;\r\n } else if (\r\n Object.keys(manifest.modules || {}).length !== numberOfModules\r\n ) {\r\n // Check the number of modules\r\n log(\r\n 2,\r\n '[cache] The cache and the requested modules do not match, need to re-fetch.'\r\n );\r\n requestUpdate = true;\r\n } else {\r\n // Check each module, if anything is missing refetch everything\r\n requestUpdate = (moduleScripts || []).some((moduleName) => {\r\n if (!manifest.modules[moduleName]) {\r\n log(\r\n 2,\r\n `[cache] The ${moduleName} is missing in the cache, need to re-fetch.`\r\n );\r\n return true;\r\n }\r\n });\r\n }\r\n\r\n // Update cache if needed\r\n if (requestUpdate) {\r\n fetchedModules = await _updateCache(\r\n highchartsOptions,\r\n serverProxyOptions,\r\n sourcePath\r\n );\r\n } else {\r\n log(3, '[cache] Dependency cache is up to date, proceeding.');\r\n\r\n // Load the sources\r\n cache.sources = readFileSync(sourcePath, 'utf8');\r\n\r\n // Get current modules map\r\n fetchedModules = manifest.modules;\r\n\r\n // Extract and save version of currently used Highcharts\r\n cache.hcVersion = _extractHcVersion(cache.sources);\r\n }\r\n }\r\n\r\n // Finally, save the new manifest, which is basically our current config\r\n // in a slightly different format\r\n await _saveConfigToManifest(highchartsOptions.version, fetchedModules);\r\n } catch (error) {\r\n throw new ExportError(\r\n '[cache] Could not configure cache and create or update the config manifest.',\r\n 500\r\n ).setError(error);\r\n }\r\n}\r\n\r\n/**\r\n * Gets the version of Highcharts from the cache.\r\n *\r\n * @function getHcVersion\r\n *\r\n * @returns {string} The cached Highcharts version.\r\n */\r\nexport function getHcVersion() {\r\n return cache.hcVersion;\r\n}\r\n\r\n/**\r\n * Updates the Highcharts version in the applied configuration and checks\r\n * the cache for the scripts of a new version.\r\n *\r\n * @async\r\n * @function updateHcVersion\r\n *\r\n * @param {string} newVersion - The new Highcharts version to be applied.\r\n */\r\nexport async function updateHcVersion(newVersion) {\r\n // Update to the new version\r\n const options = updateOptions({\r\n highcharts: {\r\n version: newVersion\r\n }\r\n });\r\n\r\n // Check if cache needs to be updated\r\n await checkCache(options.highcharts, options.server.proxy);\r\n}\r\n\r\n/**\r\n * Retrieves the current cache object.\r\n *\r\n * @function getCache\r\n *\r\n * @returns {Object} The cache object containing various cached data.\r\n */\r\nexport function getCache() {\r\n return cache;\r\n}\r\n\r\n/**\r\n * Gets the cache path for Highcharts.\r\n *\r\n * @function getCachePath\r\n *\r\n * @returns {string} The absolute path to the cache directory for Highcharts.\r\n */\r\nexport function getCachePath() {\r\n return getAbsolutePath(getOptions().highcharts.cachePath, 'utf8'); // #562\r\n}\r\n\r\n/**\r\n * Saves the provided configuration and fetched modules to the cache manifest\r\n * file.\r\n *\r\n * @async\r\n * @function _saveConfigToManifest\r\n *\r\n * @param {number} version - The currently used Highcharts version.\r\n * @param {Object} [fetchedModules={}] - An object which tracks which modules\r\n * have been fetched. The default value is an empty object.\r\n *\r\n * @throws {ExportError} Throws an `ExportError` if an error occurs while\r\n * writing the cache manifest.\r\n */\r\nasync function _saveConfigToManifest(version, fetchedModules = {}) {\r\n // Update cache object with the current modules\r\n cache.activeManifest = {\r\n version,\r\n modules: fetchedModules\r\n };\r\n\r\n log(3, '[cache] Writing a new manifest.');\r\n try {\r\n writeFileSync(\r\n join(getCachePath(), 'manifest.json'),\r\n JSON.stringify(cache.activeManifest),\r\n 'utf8'\r\n );\r\n } catch (error) {\r\n throw new ExportError(\r\n '[cache] Error writing the cache manifest.',\r\n 500\r\n ).setError(error);\r\n }\r\n}\r\n\r\n/**\r\n * Updates the local cache with Highcharts scripts content and information,\r\n * and used Highcharts version.\r\n *\r\n * @async\r\n * @function _updateCache\r\n *\r\n * @param {Object} highchartsOptions - The configuration object containing\r\n * `highcharts` options.\r\n * @param {Object} serverProxyOptions - The configuration object containing\r\n * `server.proxy` options.\r\n * @param {string} sourcePath - The path to the source file in the cache.\r\n *\r\n * @returns {Promise} A Promise that resolves to an object representing\r\n * the fetched modules.\r\n *\r\n * @throws {ExportError} Throws an `ExportError` if there is an issue updating\r\n * the local Highcharts cache.\r\n */\r\nasync function _updateCache(highchartsOptions, serverProxyOptions, sourcePath) {\r\n try {\r\n // Get Highcharts version for scripts\r\n const hcVersion =\r\n highchartsOptions.version === 'latest'\r\n ? null\r\n : `${highchartsOptions.version}`;\r\n\r\n log(\r\n 3,\r\n `[cache] Updating cache version to Highcharts: ${hcVersion || 'latest'}.`\r\n );\r\n\r\n // Get the CDN url for scripts\r\n const cdnUrl = highchartsOptions.cdnUrl || cache.cdnUrl;\r\n\r\n // Prepare options for a request\r\n const requestOptions = _configureRequest(serverProxyOptions);\r\n\r\n // An object to record which scripts are fetched\r\n const fetchedModules = {};\r\n\r\n // Join all fetched scripts and save in the manifest's sources\r\n cache.sources = (\r\n await Promise.all([\r\n // Highcharts core scripts fetch\r\n ...highchartsOptions.coreScripts.map((cs) =>\r\n _fetchScript(\r\n hcVersion ? `${cdnUrl}/${hcVersion}/${cs}` : `${cdnUrl}/${cs}`,\r\n requestOptions,\r\n fetchedModules,\r\n true\r\n )\r\n ),\r\n // Highcharts module scripts fetch\r\n ...highchartsOptions.moduleScripts.map((ms) =>\r\n _fetchScript(\r\n ms === 'map'\r\n ? hcVersion\r\n ? `${cdnUrl}/maps/${hcVersion}/modules/${ms}`\r\n : `${cdnUrl}/maps/modules/${ms}`\r\n : hcVersion\r\n ? `${cdnUrl}/${hcVersion}/modules/${ms}`\r\n : `${cdnUrl}/modules/${ms}`,\r\n requestOptions,\r\n fetchedModules\r\n )\r\n ),\r\n // Highcharts indicator scripts fetch\r\n ...highchartsOptions.indicatorScripts.map((is) =>\r\n _fetchScript(\r\n hcVersion\r\n ? `${cdnUrl}/stock/${hcVersion}/indicators/${is}`\r\n : `${cdnUrl}/stock/indicators/${is}`,\r\n requestOptions,\r\n fetchedModules\r\n )\r\n ),\r\n // Custom scripts fetch\r\n ...highchartsOptions.customScripts.map((cs) =>\r\n _fetchScript(`${cs}`, requestOptions)\r\n )\r\n ])\r\n ).join(';\\n');\r\n\r\n // Extract and save version of currently used Highcharts\r\n cache.hcVersion = _extractHcVersion(cache.sources);\r\n\r\n // Save the fetched modules into caches' source JSON\r\n writeFileSync(sourcePath, cache.sources);\r\n\r\n // Return the fetched modules\r\n return fetchedModules;\r\n } catch (error) {\r\n throw new ExportError(\r\n '[cache] Unable to update the local Highcharts cache.',\r\n 500\r\n ).setError(error);\r\n }\r\n}\r\n\r\n/**\r\n * Fetches a single script and updates the `fetchedModules` accordingly.\r\n *\r\n * @async\r\n * @function _fetchScript\r\n *\r\n * @param {string} script - A path to script to get.\r\n * @param {Object} requestOptions - Additional requests options.\r\n * @param {Object} fetchedModules - An object which tracks which Highcharts\r\n * modules have been fetched.\r\n * @param {boolean} [shouldThrowError=false] - A flag to indicate if the error\r\n * should be thrown. This should be used only for the core scripts. The default\r\n * value is `false`.\r\n *\r\n * @returns {Promise} A Promise that resolves to the text representation\r\n * of the fetched script.\r\n *\r\n * @throws {ExportError} Throws an `ExportError` if there is a problem\r\n * with fetching the script.\r\n */\r\nasync function _fetchScript(\r\n script,\r\n requestOptions,\r\n fetchedModules,\r\n shouldThrowError = false\r\n) {\r\n // Get rid of the .js from the custom strings\r\n if (script.endsWith('.js')) {\r\n script = script.substring(0, script.length - 3);\r\n }\r\n log(4, `[cache] Fetching script - ${script}.js`);\r\n\r\n // Fetch the script\r\n const response = await get(`${script}.js`, requestOptions);\r\n\r\n // If OK, return its text representation\r\n if (response.statusCode === 200 && typeof response.text == 'string') {\r\n if (fetchedModules) {\r\n const moduleName = _extractModuleName(script);\r\n fetchedModules[moduleName] = 1;\r\n }\r\n return response.text;\r\n }\r\n\r\n // Based on the `shouldThrowError` flag, decide how to serve error message\r\n if (shouldThrowError) {\r\n throw new ExportError(\r\n `[cache] Could not fetch the ${script}.js. The script might not exist in the requested version (status code: ${response.statusCode}).`,\r\n 404\r\n ).setError(response);\r\n } else {\r\n log(\r\n 2,\r\n `[cache] Could not fetch the ${script}.js. The script might not exist in the requested version.`\r\n );\r\n }\r\n}\r\n\r\n/**\r\n * Configures a proxy agent for outgoing HTTP requests based on the provided\r\n * `server.proxy` options. If a valid `host` and `port` are specified, it tries\r\n * to create an `HttpsProxyAgent`. If the creation fails, an `ExportError`\r\n * is thrown. If no proxy is configured, an empty object is returned.\r\n *\r\n * @function _configureRequest\r\n *\r\n * @param {Object} serverProxyOptions- The configuration object containing\r\n * `server.proxy` options.\r\n *\r\n * @returns {Object} The request options, including the proxy agent if created,\r\n * or an empty object if no proxy configuration is provided.\r\n *\r\n * @throws {ExportError} Throws an `ExportError` if the proxy agent creation\r\n * fails.\r\n */\r\nfunction _configureRequest(serverProxyOptions) {\r\n // Get the `host` and `port` of the proxy\r\n const proxyHost = serverProxyOptions.host;\r\n const proxyPort = serverProxyOptions.port;\r\n\r\n // Try to create a proxy agent\r\n if (proxyHost && proxyPort) {\r\n try {\r\n // Create the agent\r\n const proxyAgent = new HttpsProxyAgent({\r\n host: proxyHost,\r\n port: proxyPort\r\n });\r\n\r\n // Add the agent to the request's options\r\n return {\r\n agent: proxyAgent,\r\n timeout: serverProxyOptions.timeout\r\n };\r\n } catch (error) {\r\n throw new ExportError(\r\n '[cache] Could not create a Proxy Agent.',\r\n 500\r\n ).setError(error);\r\n }\r\n }\r\n\r\n // Return an empty object when no proxy agent is created\r\n return {};\r\n}\r\n\r\n/**\r\n * Extracts Highcharts version from the cache's sources string.\r\n *\r\n * @function _extractHcVersion\r\n *\r\n * @param {Object} cacheSources - The cache sources object.\r\n *\r\n * @returns {string} The extracted Highcharts version.\r\n */\r\nfunction _extractHcVersion(cacheSources) {\r\n return cacheSources\r\n .substring(0, cacheSources.indexOf('*/'))\r\n .replace('/*', '')\r\n .replace('*/', '')\r\n .replace(/\\n/g, '')\r\n .trim();\r\n}\r\n\r\n/**\r\n * Extracts the Highcharts module name based on the `scriptPath` property.\r\n *\r\n * @function _extractModuleName\r\n *\r\n * @param {string} scriptPath - The path of the script from which the module\r\n * name will be extracted.\r\n *\r\n * @returns {string} The extracted module name.\r\n */\r\nfunction _extractModuleName(scriptPath) {\r\n return scriptPath.replace(\r\n /(.*)\\/|(.*)modules\\/|stock\\/(.*)indicators\\/|maps\\/(.*)modules\\//gi,\r\n ''\r\n );\r\n}\r\n\r\nexport default {\r\n checkCache,\r\n getHcVersion,\r\n updateHcVersion,\r\n getCache,\r\n getCachePath\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * @overview Provides methods for initializing Highcharts with customized\r\n * animation settings and triggering the creation of Highcharts charts with\r\n * export-specific configurations in the page context. Supports dynamic option\r\n * merging, custom logic injection, and control over rendering behaviors. Used\r\n * by the Puppeteer page.\r\n */\r\n\r\n/* eslint-disable no-undef */\r\n\r\n/**\r\n * Setting the `Highcharts.animObject` function. Called when initing the page.\r\n *\r\n * @function setupHighcharts\r\n */\r\nexport function setupHighcharts() {\r\n Highcharts.animObject = function () {\r\n return { duration: 0 };\r\n };\r\n}\r\n\r\n/**\r\n * Creates the actual Highcharts chart on a page.\r\n *\r\n * @async\r\n * @function createChart\r\n *\r\n * @param {Object} exportOptions - The configuration object containing `export`\r\n * options.\r\n * @param {Object} customLogicOptions - The configuration object containing\r\n * `customLogic` options.\r\n *\r\n */\r\nexport async function createChart(exportOptions, customLogicOptions) {\r\n // Get required functions\r\n const { getOptions, setOptions, merge, wrap } = Highcharts;\r\n\r\n // Create a separate object for a potential `setOptions` usages in order\r\n // to prevent from polluting other exports that can happen on the same page\r\n Highcharts.setOptionsObj = merge(false, {}, getOptions());\r\n\r\n // NOTE: Is this used for anything useful?\r\n window.isRenderComplete = false;\r\n wrap(Highcharts.Chart.prototype, 'init', function (proceed, userOptions, cb) {\r\n // Override the `userOptions` with image friendly options\r\n userOptions = merge(userOptions, {\r\n exporting: {\r\n enabled: false\r\n },\r\n plotOptions: {\r\n series: {\r\n label: {\r\n enabled: false\r\n }\r\n }\r\n },\r\n /* Expects tooltip in the `userOptions` when `forExport` is true.\r\n https://github.com/highcharts/highcharts/blob/3ad430a353b8056b9e764aa4e5cd6828aa479db2/js/parts/Chart.js#L241\r\n */\r\n tooltip: {}\r\n });\r\n\r\n (userOptions.series || []).forEach(function (series) {\r\n series.animation = false;\r\n });\r\n\r\n // Add flag to know if chart render has been called.\r\n if (!window.onHighchartsRender) {\r\n window.onHighchartsRender = Highcharts.addEvent(this, 'render', () => {\r\n window.isRenderComplete = true;\r\n });\r\n }\r\n\r\n proceed.apply(this, [userOptions, cb]);\r\n });\r\n\r\n wrap(Highcharts.Series.prototype, 'init', function (proceed, chart, options) {\r\n proceed.apply(this, [chart, options]);\r\n });\r\n\r\n // Some mandatory additional `chart` and `exporting` options\r\n const additionalOptions = {\r\n chart: {\r\n // By default animation is disabled\r\n animation: false,\r\n // Get the right size values\r\n height: exportOptions.height,\r\n width: exportOptions.width\r\n },\r\n exporting: {\r\n // No need for the exporting button\r\n enabled: false\r\n }\r\n };\r\n\r\n // Get the input to export from the `instr` option\r\n const userOptions = new Function(`return ${exportOptions.instr}`)();\r\n\r\n // Get the `themeOptions` option\r\n const themeOptions = new Function(`return ${exportOptions.themeOptions}`)();\r\n\r\n // Merge the following options objects to create final options\r\n const finalOptions = merge(\r\n false,\r\n themeOptions,\r\n userOptions,\r\n // Placed it here instead in the init because of the size issues\r\n additionalOptions\r\n );\r\n\r\n // Prepare the `callback` option\r\n const finalCallback = customLogicOptions.callback\r\n ? new Function(`return ${customLogicOptions.callback}`)()\r\n : null;\r\n\r\n // Trigger the `customCode` option\r\n if (customLogicOptions.customCode) {\r\n new Function('options', customLogicOptions.customCode)(userOptions);\r\n }\r\n\r\n // Get the `globalOptions` option\r\n const globalOptions = new Function(`return ${exportOptions.globalOptions}`)();\r\n\r\n // Set the global options if exist\r\n if (globalOptions) {\r\n setOptions(globalOptions);\r\n }\r\n\r\n // Call the chart creation\r\n Highcharts[exportOptions.constr]('container', finalOptions, finalCallback);\r\n\r\n // Get all images from within the chart\r\n const images = Array.from(\r\n document.querySelectorAll('.highcharts-container image')\r\n );\r\n\r\n // Wait for all images for 2 seconds\r\n await Promise.race([\r\n Promise.all(\r\n images.map((image) =>\r\n image.complete && image.naturalHeight !== 0\r\n ? Promise.resolve()\r\n : new Promise((resolve) =>\r\n image.addEventListener('load', resolve, { once: true })\r\n )\r\n )\r\n ),\r\n // Proceed further even if images did not load\r\n new Promise((resolve) => setTimeout(resolve, 2000))\r\n ]);\r\n\r\n // Get the current global options\r\n const defaultOptions = getOptions();\r\n\r\n // Clear it just in case (e.g. the `setOptions` was used in the `customCode`)\r\n for (const prop in defaultOptions) {\r\n if (typeof defaultOptions[prop] !== 'function') {\r\n delete defaultOptions[prop];\r\n }\r\n }\r\n\r\n // Set the default options back\r\n setOptions(Highcharts.setOptionsObj);\r\n\r\n // Empty the custom global options object\r\n Highcharts.setOptionsObj = {};\r\n}\r\n\r\nexport default {\r\n setupHighcharts,\r\n createChart\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * @overview This module provides functions for managing Puppeteer browser\r\n * instance, creating and clearing pages, injecting custom JS and CSS resources,\r\n * and setting up Highcharts for server-side rendering. The module ensures\r\n * that the browser and pages are correctly managed and can handle failures\r\n * during operations like launching the browser or creating new pages.\r\n */\r\n\r\nimport { readFileSync } from 'fs';\r\nimport { join } from 'path';\r\n\r\nimport puppeteer from 'puppeteer';\r\n\r\nimport { getCachePath } from './cache.js';\r\nimport { getOptions } from './config.js';\r\nimport { setupHighcharts } from './highcharts.js';\r\nimport { log, logWithStack } from './logger.js';\r\nimport { __dirname, getAbsolutePath } from './utils.js';\r\n\r\nimport ExportError from './errors/ExportError.js';\r\n\r\n// Get the template for pages\r\nconst pageTemplate = readFileSync(\r\n join(__dirname, 'templates', 'template.html'),\r\n 'utf8'\r\n);\r\n\r\n// To save the browser\r\nlet browser = null;\r\n\r\n/**\r\n * Retrieves the existing Puppeteer browser instance.\r\n *\r\n * @function getBrowser\r\n *\r\n * @returns {Object} The Puppeteer browser instance.\r\n *\r\n * @throws {ExportError} Throws an `ExportError` if no valid browser\r\n * has been created.\r\n */\r\nexport function getBrowser() {\r\n if (!browser) {\r\n throw new ExportError('[browser] No valid browser has been created.', 500);\r\n }\r\n return browser;\r\n}\r\n\r\n/**\r\n * Creates a Puppeteer browser instance with the specified arguments.\r\n *\r\n * @async\r\n * @function createBrowser\r\n *\r\n * @param {Array} puppeteerArgs - Additional arguments for Puppeteer\r\n * browser's launch.\r\n *\r\n * @returns {Promise} A Promise that resolves to the created Puppeteer\r\n * browser instance.\r\n *\r\n * @throws {ExportError} Throws an `ExportError` if max retries to open\r\n * a browser instance are reached, or if no browser instance is found after\r\n * retries.\r\n */\r\nexport async function createBrowser(puppeteerArgs) {\r\n // Get `debug` and `other` options\r\n const { debug, other } = getOptions();\r\n\r\n // Get the `debug` options\r\n const { enable: enabledDebug, ...debugOptions } = debug;\r\n\r\n // Launch options for the browser instance\r\n const launchOptions = {\r\n headless: other.browserShellMode ? 'shell' : true,\r\n userDataDir: 'tmp',\r\n args: puppeteerArgs || [],\r\n handleSIGINT: false,\r\n handleSIGTERM: false,\r\n handleSIGHUP: false,\r\n waitForInitialPage: false,\r\n defaultViewport: null,\r\n ...(enabledDebug && debugOptions)\r\n };\r\n\r\n // Create a browser\r\n if (!browser) {\r\n // A counter for the browser's launch retries\r\n let tryCount = 0;\r\n const openBrowser = async () => {\r\n try {\r\n log(\r\n 3,\r\n `[browser] Attempting to launch and get a browser instance (try ${++tryCount}).`\r\n );\r\n\r\n // Launch the browser\r\n browser = await puppeteer.launch(launchOptions);\r\n } catch (error) {\r\n logWithStack(\r\n 1,\r\n error,\r\n '[browser] Failed to launch a browser instance.'\r\n );\r\n\r\n // Retry to launch browser until reaching max attempts\r\n if (tryCount < 25) {\r\n log(3, `[browser] Retry to open a browser (${tryCount} out of 25).`);\r\n\r\n // Wait for a 4 seconds before trying again\r\n await new Promise((response) => setTimeout(response, 4000));\r\n await openBrowser();\r\n } else {\r\n throw error;\r\n }\r\n }\r\n };\r\n\r\n try {\r\n // Try to open a browser\r\n await openBrowser();\r\n\r\n // Shell mode inform\r\n if (launchOptions.headless === 'shell') {\r\n log(3, `[browser] Launched browser in shell mode.`);\r\n }\r\n\r\n // Debug mode inform\r\n if (enabledDebug) {\r\n log(3, `[browser] Launched browser in debug mode.`);\r\n }\r\n } catch (error) {\r\n throw new ExportError(\r\n '[browser] Maximum retries to open a browser instance reached.',\r\n 500\r\n ).setError(error);\r\n }\r\n\r\n // No correct browser\r\n if (!browser) {\r\n throw new ExportError('[browser] Cannot find a browser to open.', 500);\r\n }\r\n }\r\n\r\n // Return a browser instance\r\n return browser;\r\n}\r\n\r\n/**\r\n * Closes the Puppeteer browser instance if it is connected.\r\n *\r\n * @async\r\n * @function closeBrowser\r\n */\r\nexport async function closeBrowser() {\r\n // Close the browser when connected\r\n if (browser && browser.connected) {\r\n await browser.close();\r\n }\r\n browser = null;\r\n log(4, '[browser] Closed the browser.');\r\n}\r\n\r\n/**\r\n * Creates a new Puppeteer page within an existing browser instance.\r\n * The function creates a new page, disables caching, sets content using\r\n * the `_setPageContent()`, and returns the created Puppeteer page.\r\n *\r\n * @async\r\n * @function newPage\r\n *\r\n * @param {Object} poolResource - The pool resource that contains `id`,\r\n * `workCount`, and `page`.\r\n *\r\n * @throws {ExportError} Throws an `ExportError` if no valid browser\r\n * has been connected or if a page is invalid or closed.\r\n */\r\nexport async function newPage(poolResource) {\r\n // Error in case of no connected browser\r\n if (!browser || !browser.connected) {\r\n throw new ExportError(`[browser] Browser is not yet connected.`, 500);\r\n }\r\n\r\n // Create a page\r\n poolResource.page = await browser.newPage();\r\n\r\n // Disable cache\r\n await poolResource.page.setCacheEnabled(false);\r\n\r\n // Set the content\r\n await _setPageContent(poolResource.page);\r\n\r\n // Set page events\r\n _setPageEvents(poolResource.page);\r\n\r\n // Check if the page is correctly created\r\n if (!poolResource.page || poolResource.page.isClosed()) {\r\n throw new ExportError('[browser] The page is invalid or closed.', 400);\r\n }\r\n}\r\n\r\n/**\r\n * Clears the content of a Puppeteer page based on the specified mode. Logs\r\n * thrown error if clearing of a page's content fails.\r\n *\r\n * @async\r\n * @function clearPage\r\n *\r\n * @param {Object} poolResource - The pool resource that contains page and id.\r\n * @param {boolean} [hardReset=false] - A flag indicating the type of clearing\r\n * to be performed. If `true`, navigates to `about:blank` and resets content\r\n * and scripts. If `false`, clears the body content by setting a predefined HTML\r\n * structure. The default value is `false`.\r\n *\r\n * @returns {Promise} A Promise that resolves to `true` when page\r\n * is correctly cleared and `false` when it is not.\r\n */\r\nexport async function clearPage(poolResource, hardReset = false) {\r\n try {\r\n if (poolResource.page && !poolResource.page.isClosed()) {\r\n if (hardReset) {\r\n // Navigate to `about:blank`\r\n await poolResource.page.goto('about:blank', {\r\n waitUntil: 'domcontentloaded'\r\n });\r\n\r\n // Set the content and and scripts again\r\n await _setPageContent(poolResource.page);\r\n } else {\r\n // Clear body content\r\n await poolResource.page.evaluate(() => {\r\n document.body.innerHTML =\r\n '
';\r\n });\r\n }\r\n return true;\r\n }\r\n } catch (error) {\r\n logWithStack(\r\n 2,\r\n error,\r\n `[pool] Pool resource [${poolResource.id}] - Content of the page could not be cleared.`\r\n );\r\n\r\n // Set the `workLimit` to exceeded in order to recreate the resource\r\n poolResource.workCount = getOptions().pool.workLimit + 1;\r\n }\r\n return false;\r\n}\r\n\r\n/**\r\n * Adds custom JS and CSS resources to a Puppeteer page based on the specified\r\n * options.\r\n *\r\n * @async\r\n * @function addPageResources\r\n *\r\n * @param {Object} page - The Puppeteer page object to which resources will\r\n * be added.\r\n * @param {Object} customLogicOptions - The configuration object containing\r\n * `customLogic` options.\r\n *\r\n * @returns {Promise>} A Promise that resolves to an array\r\n * of injected resources.\r\n */\r\nexport async function addPageResources(page, customLogicOptions) {\r\n // Injected resources array\r\n const injectedResources = [];\r\n\r\n // Use the content of the `resources`\r\n const resources = customLogicOptions.resources;\r\n if (resources) {\r\n const injectedJs = [];\r\n\r\n // Load custom JS code\r\n if (resources.js) {\r\n injectedJs.push({\r\n content: resources.js\r\n });\r\n }\r\n\r\n // Load scripts from all custom files\r\n if (resources.files) {\r\n for (const file of resources.files) {\r\n const isLocal = file.startsWith('http') ? false : true;\r\n\r\n // Add each custom script from resources' files\r\n injectedJs.push(\r\n isLocal\r\n ? {\r\n content: readFileSync(getAbsolutePath(file), 'utf8')\r\n }\r\n : {\r\n url: file\r\n }\r\n );\r\n }\r\n }\r\n\r\n // The actual injection of collected scripts\r\n for (const jsResource of injectedJs) {\r\n try {\r\n injectedResources.push(await page.addScriptTag(jsResource));\r\n } catch (error) {\r\n logWithStack(2, error, `[browser] The JS resource cannot be loaded.`);\r\n }\r\n }\r\n injectedJs.length = 0;\r\n\r\n // Load CSS\r\n const injectedCss = [];\r\n if (resources.css) {\r\n const cssImports = resources.css.match(/@import\\s*([^;]*);/g);\r\n if (cssImports) {\r\n // Handle css section\r\n for (let cssImportPath of cssImports) {\r\n if (cssImportPath) {\r\n cssImportPath = cssImportPath\r\n .replace('url(', '')\r\n .replace('@import', '')\r\n .replace(/\"/g, '')\r\n .replace(/'/g, '')\r\n .replace(/;/, '')\r\n .replace(/\\)/g, '')\r\n .trim();\r\n\r\n // Add each custom css from resources\r\n if (cssImportPath.startsWith('http')) {\r\n injectedCss.push({\r\n url: cssImportPath\r\n });\r\n } else if (customLogicOptions.allowFileResources) {\r\n injectedCss.push({\r\n path: getAbsolutePath(cssImportPath)\r\n });\r\n }\r\n }\r\n }\r\n }\r\n\r\n // The rest of the CSS section will be content by now\r\n injectedCss.push({\r\n content: resources.css.replace(/@import\\s*([^;]*);/g, '') || ' '\r\n });\r\n\r\n // The actual injection of collected CSS\r\n for (const cssResource of injectedCss) {\r\n try {\r\n injectedResources.push(await page.addStyleTag(cssResource));\r\n } catch (error) {\r\n logWithStack(\r\n 2,\r\n error,\r\n `[browser] The CSS resource cannot be loaded.`\r\n );\r\n }\r\n }\r\n injectedCss.length = 0;\r\n }\r\n }\r\n return injectedResources;\r\n}\r\n\r\n/**\r\n * Clears out all state set on the page with `addScriptTag` and `addStyleTag`.\r\n * Removes injected resources and resets CSS and script tags on the page.\r\n * Additionally, it destroys previously existing charts.\r\n *\r\n * @async\r\n * @function clearPageResources\r\n *\r\n * @param {Object} page - The Puppeteer page object from which resources will\r\n * be cleared.\r\n * @param {Array} injectedResources - Array of injected resources\r\n * to be cleared.\r\n */\r\nexport async function clearPageResources(page, injectedResources) {\r\n try {\r\n for (const resource of injectedResources) {\r\n await resource.dispose();\r\n }\r\n\r\n // Destroy old charts after export is done and reset all CSS and script tags\r\n await page.evaluate(() => {\r\n // We are not guaranteed that Highcharts is loaded, when doing SVG exports\r\n if (typeof Highcharts !== 'undefined') {\r\n // eslint-disable-next-line no-undef\r\n const oldCharts = Highcharts.charts;\r\n\r\n // Check in any already existing charts\r\n if (Array.isArray(oldCharts) && oldCharts.length) {\r\n // Destroy old charts\r\n for (const oldChart of oldCharts) {\r\n oldChart && oldChart.destroy();\r\n // eslint-disable-next-line no-undef\r\n Highcharts.charts.shift();\r\n }\r\n }\r\n }\r\n\r\n // eslint-disable-next-line no-undef\r\n const [...scriptsToRemove] = document.getElementsByTagName('script');\r\n // eslint-disable-next-line no-undef\r\n const [, ...stylesToRemove] = document.getElementsByTagName('style');\r\n // eslint-disable-next-line no-undef\r\n const [...linksToRemove] = document.getElementsByTagName('link');\r\n\r\n // Remove tags\r\n for (const element of [\r\n ...scriptsToRemove,\r\n ...stylesToRemove,\r\n ...linksToRemove\r\n ]) {\r\n element.remove();\r\n }\r\n });\r\n } catch (error) {\r\n logWithStack(2, error, `[browser] Could not clear page's resources.`);\r\n }\r\n}\r\n\r\n/**\r\n * Sets the content for a Puppeteer page using a predefined template\r\n * and additional scripts.\r\n *\r\n * @async\r\n * @function _setPageContent\r\n *\r\n * @param {Object} page - The Puppeteer page object to which the content\r\n * is being set.\r\n */\r\nasync function _setPageContent(page) {\r\n // Set the initial page content\r\n await page.setContent(pageTemplate, { waitUntil: 'domcontentloaded' });\r\n\r\n // Add all registered Higcharts scripts, quite demanding\r\n await page.addScriptTag({ path: join(getCachePath(), 'sources.js') });\r\n\r\n // Set the initial `animObject` for Highcharts\r\n await page.evaluate(setupHighcharts);\r\n}\r\n\r\n/**\r\n * Set events (like `pageerror` and `console`) for a Puppeteer page in order\r\n * to catch and display errors and console logs from the window context.\r\n *\r\n * @function _setPageEvents\r\n *\r\n * @param {Object} page - The Puppeteer page object to which the listeners\r\n * are being set.\r\n */\r\nfunction _setPageEvents(page) {\r\n // Get `debug` options\r\n const { debug } = getOptions();\r\n\r\n // Set the `pageerror` listener\r\n page.on('pageerror', async () => {\r\n // It would seem like this may fire at the same time or shortly before\r\n // a page is closed.\r\n if (page.isClosed()) {\r\n return;\r\n }\r\n });\r\n\r\n // Set the `console` listener, if needed\r\n if (debug.enable && debug.listenToConsole) {\r\n page.on('console', (message) => {\r\n console.log(`[debug] ${message.text()}`);\r\n });\r\n }\r\n}\r\n\r\nexport default {\r\n getBrowser,\r\n createBrowser,\r\n closeBrowser,\r\n newPage,\r\n clearPage,\r\n addPageResources,\r\n clearPageResources\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * The CSS to be used on the exported page.\r\n *\r\n * @returns {string} The CSS configuration.\r\n */\r\nexport default () => `\r\n\r\nhtml, body {\r\n margin: 0;\r\n padding: 0;\r\n box-sizing: border-box;\r\n}\r\n\r\n#table-div, #sliders, #datatable, #controls, .ld-row {\r\n display: none;\r\n height: 0;\r\n}\r\n\r\n#chart-container {\r\n box-sizing: border-box;\r\n margin: 0;\r\n overflow: auto;\r\n font-size: 0;\r\n}\r\n\r\n#chart-container > figure, div {\r\n margin-top: 0 !important;\r\n margin-bottom: 0 !important;\r\n}\r\n\r\n`;\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\nimport cssTemplate from './css.js';\r\n\r\n/**\r\n * The SVG template to use when loading SVG content to be exported.\r\n *\r\n * @param {string} svg - The SVG input content to be exported.\r\n *\r\n * @returns {string} The SVG template.\r\n */\r\nexport default (svg) => `\r\n\r\n\r\n \r\n \r\n Highcharts Export\r\n \r\n \r\n \r\n
\r\n ${svg}\r\n
\r\n \r\n\r\n\r\n`;\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * @overview This module handles chart export functionality using Puppeteer.\r\n * It supports exporting charts as SVG, PNG, JPEG, and PDF formats. The module\r\n * manages page resources, sets up the export environment, and processes chart\r\n * configurations or SVG inputs for rendering. Exports to a chart from a page\r\n * using Puppeteer.\r\n */\r\n\r\nimport { addPageResources, clearPageResources } from './browser.js';\r\nimport { createChart } from './highcharts.js';\r\nimport { log } from './logger.js';\r\n\r\nimport svgTemplate from '../templates/svgExport/svgExport.js';\r\n\r\nimport ExportError from './errors/ExportError.js';\r\n\r\n/**\r\n * Exports to a chart from a page using Puppeteer.\r\n *\r\n * @async\r\n * @function puppeteerExport\r\n *\r\n * @param {Object} page - Puppeteer page object.\r\n * @param {Object} exportOptions - The configuration object containing `export`\r\n * options.\r\n * @param {Object} customLogicOptions - The configuration object containing\r\n * `customLogic` options.\r\n *\r\n * @returns {Promise<(string|Buffer|ExportError)>} A Promise that resolves\r\n * to the exported data or rejecting with an `ExportError`.\r\n *\r\n * @throws {ExportError} Throws an `ExportError` if export to an unsupported\r\n * output format occurs.\r\n */\r\nexport async function puppeteerExport(page, exportOptions, customLogicOptions) {\r\n // Injected resources array (additional JS and CSS)\r\n const injectedResources = [];\r\n\r\n try {\r\n let isSVG = false;\r\n\r\n // Decide on the export method\r\n if (exportOptions.svg) {\r\n log(4, '[export] Treating as SVG input.');\r\n\r\n // If the `type` is also SVG, return the input\r\n if (exportOptions.type === 'svg') {\r\n return exportOptions.svg;\r\n }\r\n\r\n // Mark as SVG export for the later size corrections\r\n isSVG = true;\r\n\r\n // SVG export\r\n await page.setContent(svgTemplate(exportOptions.svg), {\r\n waitUntil: 'domcontentloaded'\r\n });\r\n } else {\r\n log(4, '[export] Treating as JSON config.');\r\n\r\n // Options export\r\n await page.evaluate(createChart, exportOptions, customLogicOptions);\r\n }\r\n\r\n // Keeps track of all resources added on the page with addXXXTag. etc\r\n // It's VITAL that all added resources ends up here so we can clear things\r\n // out when doing a new export in the same page!\r\n injectedResources.push(\r\n ...(await addPageResources(page, customLogicOptions))\r\n );\r\n\r\n // Get the real chart size and set the zoom accordingly\r\n const size = await _getChartSize(page, isSVG, exportOptions.scale);\r\n\r\n // Get the clip region for the page\r\n const { x, y } = await _getClipRegion(page);\r\n\r\n // Set final `height` for viewport\r\n const viewportHeight = Math.abs(\r\n Math.ceil(size.chartHeight || exportOptions.height)\r\n );\r\n\r\n // Set final `width` for viewport\r\n const viewportWidth = Math.abs(\r\n Math.ceil(size.chartWidth || exportOptions.width)\r\n );\r\n\r\n // Set the final viewport now that we have the real height\r\n await page.setViewport({\r\n height: viewportHeight,\r\n width: viewportWidth,\r\n deviceScaleFactor: isSVG ? 1 : parseFloat(exportOptions.scale)\r\n });\r\n\r\n let result;\r\n // Rasterization process\r\n switch (exportOptions.type) {\r\n case 'svg':\r\n result = await _createSVG(page);\r\n break;\r\n case 'png':\r\n case 'jpeg':\r\n result = await _createImage(\r\n page,\r\n exportOptions.type,\r\n {\r\n width: viewportWidth,\r\n height: viewportHeight,\r\n x,\r\n y\r\n },\r\n exportOptions.rasterizationTimeout\r\n );\r\n break;\r\n case 'pdf':\r\n result = await _createPDF(\r\n page,\r\n viewportHeight,\r\n viewportWidth,\r\n exportOptions.rasterizationTimeout\r\n );\r\n break;\r\n default:\r\n throw new ExportError(\r\n `[export] Unsupported output format: ${exportOptions.type}.`,\r\n 400\r\n );\r\n }\r\n\r\n // Clear previously injected JS and CSS resources\r\n await clearPageResources(page, injectedResources);\r\n return result;\r\n } catch (error) {\r\n await clearPageResources(page, injectedResources);\r\n return error;\r\n }\r\n}\r\n\r\n/**\r\n * Retrieves the clipping region coordinates of the specified page element\r\n * with the 'chart-container' id.\r\n *\r\n * @async\r\n * @function _getClipRegion\r\n *\r\n * @param {Object} page - Puppeteer page object.\r\n *\r\n * @returns {Promise} A Promise that resolves to an object containing\r\n * `x`, `y`, `width`, and `height` properties.\r\n */\r\nasync function _getClipRegion(page) {\r\n return page.$eval('#chart-container', (element) => {\r\n const { x, y, width, height } = element.getBoundingClientRect();\r\n return {\r\n x,\r\n y,\r\n width,\r\n height: Math.trunc(height > 1 ? height : 500)\r\n };\r\n });\r\n}\r\n\r\n/**\r\n * Retrieves the real chart dimensions from a Puppeteer page. The function\r\n * behaves differently based on whether the export type is SVG or another\r\n * format.\r\n *\r\n * @async\r\n * @function _getChartSize\r\n *\r\n * @param {Object} page - Puppeteer page object.\r\n * @param {boolean} isSVG - Determines whether the chart being processed\r\n * is an SVG or another format.\r\n * @param {number} scale - The scale factor to be applied to the chart\r\n * dimensions.\r\n *\r\n * @returns {Promise} A Promise that resolves to an object containing\r\n * the actual height and width of the chart after scaling.\r\n */\r\nasync function _getChartSize(page, isSVG, scale) {\r\n // Trigger appropriate function based on the `isSvg` flag to get chart size\r\n return isSVG\r\n ? await page.evaluate((scale) => {\r\n const svgElement = document.querySelector(\r\n '#chart-container svg:first-of-type'\r\n );\r\n\r\n // Get the values correctly scaled\r\n const chartHeight = svgElement.height.baseVal.value * scale;\r\n const chartWidth = svgElement.width.baseVal.value * scale;\r\n\r\n // In case of SVG the zoom must be set directly for body as scale\r\n // eslint-disable-next-line no-undef\r\n document.body.style.zoom = scale;\r\n\r\n // Set the margin to 0px\r\n // eslint-disable-next-line no-undef\r\n document.body.style.margin = '0px';\r\n\r\n return {\r\n chartHeight,\r\n chartWidth\r\n };\r\n }, parseFloat(scale))\r\n : await page.evaluate(() => {\r\n // eslint-disable-next-line no-undef\r\n const { chartHeight, chartWidth } = window.Highcharts.charts[0];\r\n\r\n // No need for such scale manipulation in case of other types\r\n // of exports. Reset the zoom for other exports than to SVGs\r\n // eslint-disable-next-line no-undef\r\n document.body.style.zoom = 1;\r\n\r\n return {\r\n chartHeight,\r\n chartWidth\r\n };\r\n });\r\n}\r\n\r\n/**\r\n * Creates an SVG by evaluating the `outerHTML` of the first 'svg' element\r\n * inside an element with the id 'container'.\r\n *\r\n * @async\r\n * @function _createSVG\r\n *\r\n * @param {Object} page - Puppeteer page object.\r\n *\r\n * @returns {Promise} A Promise that resolves to the SVG string.\r\n */\r\nasync function _createSVG(page) {\r\n return page.$eval(\r\n '#container svg:first-of-type',\r\n (element) => element.outerHTML\r\n );\r\n}\r\n\r\n/**\r\n * Creates an image using Puppeteer's page `screenshot` functionality with\r\n * specified options.\r\n *\r\n * @async\r\n * @function _createImage\r\n *\r\n * @param {Object} page - Puppeteer page object.\r\n * @param {string} type - Image type.\r\n * @param {Object} clip - Clipping region coordinates.\r\n * @param {number} rasterizationTimeout - Timeout for rasterization\r\n * in milliseconds.\r\n *\r\n * @returns {Promise} A Promise that resolves to the image buffer\r\n * or rejecting with an `ExportError` for timeout.\r\n */\r\nasync function _createImage(page, type, clip, rasterizationTimeout) {\r\n return Promise.race([\r\n page.screenshot({\r\n type,\r\n clip,\r\n encoding: 'base64',\r\n fullPage: false,\r\n optimizeForSpeed: true,\r\n captureBeyondViewport: true,\r\n ...(type !== 'png' ? { quality: 80 } : {}),\r\n // Always render on a transparent page if the expected type format is PNG\r\n omitBackground: type == 'png' // #447, #463\r\n }),\r\n new Promise((_resolve, reject) =>\r\n setTimeout(\r\n () => reject(new ExportError('Rasterization timeout', 408)),\r\n rasterizationTimeout || 1500\r\n )\r\n )\r\n ]);\r\n}\r\n\r\n/**\r\n * Creates a PDF using Puppeteer's page `pdf` functionality with specified\r\n * options.\r\n *\r\n * @async\r\n * @function _createPDF\r\n *\r\n * @param {Object} page - Puppeteer page object.\r\n * @param {number} height - PDF height.\r\n * @param {number} width - PDF width.\r\n * @param {number} rasterizationTimeout - Timeout for rasterization\r\n * in milliseconds.\r\n *\r\n * @returns {Promise} A Promise that resolves to the PDF buffer.\r\n */\r\nasync function _createPDF(page, height, width, rasterizationTimeout) {\r\n await page.emulateMediaType('screen');\r\n return page.pdf({\r\n // This will remove an extra empty page in PDF exports\r\n height: height + 1,\r\n width,\r\n encoding: 'base64',\r\n timeout: rasterizationTimeout || 1500\r\n });\r\n}\r\n\r\nexport default {\r\n puppeteerExport\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * @overview This module provides a worker pool implementation for managing\r\n * the browser instance and pages, specifically designed for use with\r\n * the Highcharts Export Server. It optimizes resources usage and performance\r\n * by maintaining a pool of workers that can handle concurrent export tasks\r\n * using Puppeteer.\r\n */\r\n\r\nimport { Pool } from 'tarn';\r\nimport { v4 as uuid } from 'uuid';\r\n\r\nimport { clearPage, createBrowser, closeBrowser, newPage } from './browser.js';\r\nimport { puppeteerExport } from './export.js';\r\nimport { log, logWithStack } from './logger.js';\r\nimport { getNewDateTime, measureTime } from './utils.js';\r\n\r\nimport ExportError from './errors/ExportError.js';\r\n\r\n// The pool instance\r\nlet pool = null;\r\n\r\n// Pool statistics\r\nconst poolStats = {\r\n exportsAttempted: 0,\r\n exportsPerformed: 0,\r\n exportsDropped: 0,\r\n exportsFromSvg: 0,\r\n exportsFromOptions: 0,\r\n exportsFromSvgAttempts: 0,\r\n exportsFromOptionsAttempts: 0,\r\n timeSpent: 0,\r\n timeSpentAverage: 0\r\n};\r\n\r\n/**\r\n * Initializes the export pool with the provided configuration, creating\r\n * a browser instance and setting up worker resources.\r\n *\r\n * @async\r\n * @function initPool\r\n *\r\n * @param {Object} poolOptions - The configuration object containing `pool`\r\n * options.\r\n * @param {Array} puppeteerArgs - Additional arguments for Puppeteer\r\n * launch.\r\n *\r\n * @returns {Promise} A Promise that resolves to ending the function\r\n * execution when an already initialized pool of resources is found.\r\n *\r\n * @throws {ExportError} Throws an `ExportError` if could not create the pool\r\n * of workers.\r\n */\r\nexport async function initPool(poolOptions, puppeteerArgs) {\r\n // Create a browser instance with the puppeteer arguments\r\n await createBrowser(puppeteerArgs);\r\n\r\n try {\r\n log(\r\n 3,\r\n `[pool] Initializing pool with workers: min ${poolOptions.minWorkers}, max ${poolOptions.maxWorkers}.`\r\n );\r\n\r\n if (pool) {\r\n log(\r\n 4,\r\n '[pool] Already initialized, please kill it before creating a new one.'\r\n );\r\n return;\r\n }\r\n\r\n // Keep an eye on a correct min and max workers number\r\n if (poolOptions.minWorkers > poolOptions.maxWorkers) {\r\n poolOptions.minWorkers = poolOptions.maxWorkers;\r\n }\r\n\r\n // Create a pool along with a minimal number of resources\r\n pool = new Pool({\r\n // Get the `create`, `validate`, and `destroy` functions\r\n ..._factory(poolOptions),\r\n min: poolOptions.minWorkers,\r\n max: poolOptions.maxWorkers,\r\n acquireTimeoutMillis: poolOptions.acquireTimeout,\r\n createTimeoutMillis: poolOptions.createTimeout,\r\n destroyTimeoutMillis: poolOptions.destroyTimeout,\r\n idleTimeoutMillis: poolOptions.idleTimeout,\r\n createRetryIntervalMillis: poolOptions.createRetryInterval,\r\n reapIntervalMillis: poolOptions.reaperInterval,\r\n propagateCreateError: false\r\n });\r\n\r\n // Set events\r\n pool.on('release', async (resource) => {\r\n // Clear page\r\n const clearStatus = await clearPage(resource, false);\r\n log(\r\n 4,\r\n `[pool] Pool resource [${resource.id}] - Releasing a worker. Clear page status: ${clearStatus}.`\r\n );\r\n });\r\n\r\n pool.on('destroySuccess', (_eventId, resource) => {\r\n log(\r\n 4,\r\n `[pool] Pool resource [${resource.id}] - Destroyed a worker successfully.`\r\n );\r\n resource.page = null;\r\n });\r\n\r\n const initialResources = [];\r\n // Create an initial number of resources\r\n for (let i = 0; i < poolOptions.minWorkers; i++) {\r\n try {\r\n const resource = await pool.acquire().promise;\r\n initialResources.push(resource);\r\n } catch (error) {\r\n logWithStack(2, error, '[pool] Could not create an initial resource.');\r\n }\r\n }\r\n\r\n // Release the initial number of resources back to the pool\r\n initialResources.forEach((resource) => {\r\n pool.release(resource);\r\n });\r\n\r\n log(\r\n 3,\r\n `[pool] The pool is ready${initialResources.length ? ` with ${initialResources.length} initial resources waiting.` : '.'}`\r\n );\r\n } catch (error) {\r\n throw new ExportError(\r\n '[pool] Could not configure and create the pool of workers.',\r\n 500\r\n ).setError(error);\r\n }\r\n}\r\n\r\n/**\r\n * Terminates all workers in the pool, destroys the pool, and closes the browser\r\n * instance.\r\n *\r\n * @async\r\n * @function killPool\r\n *\r\n * @returns {Promise} A Promise that resolves once all workers are\r\n * terminated, the pool is destroyed, and the browser is successfully closed.\r\n */\r\nexport async function killPool() {\r\n log(3, '[pool] Killing pool with all workers and closing browser.');\r\n\r\n // If still alive, destroy the pool of pages before closing a browser\r\n if (pool) {\r\n // Free up not released workers\r\n for (const worker of pool.used) {\r\n pool.release(worker.resource);\r\n }\r\n\r\n // Destroy the pool if it is still available\r\n if (!pool.destroyed) {\r\n await pool.destroy();\r\n log(4, '[pool] Destroyed the pool of resources.');\r\n }\r\n pool = null;\r\n }\r\n\r\n // Close the browser instance\r\n await closeBrowser();\r\n}\r\n\r\n/**\r\n * Processes the export work using a worker from the pool. Acquires a worker\r\n * handle from the pool, performs the export using puppeteer, and releases\r\n * the worker handle back to the pool.\r\n *\r\n * @async\r\n * @function postWork\r\n *\r\n * @param {Object} options - The configuration object containing complete set\r\n * of options.\r\n *\r\n * @returns {Promise} A Promise that resolves to the export result\r\n * and options.\r\n *\r\n * @throws {ExportError} Throws an `ExportError` if an error occurs during\r\n * the export process.\r\n */\r\nexport async function postWork(options) {\r\n let workerHandle;\r\n\r\n try {\r\n log(4, '[pool] Work received, starting to process.');\r\n\r\n // An export attempt counted\r\n ++poolStats.exportsAttempted;\r\n\r\n // Display the pool information if needed\r\n if (options.pool.benchmarking) {\r\n _getPoolInfo();\r\n }\r\n\r\n // Throw an error in case of lacking the pool instance\r\n if (!pool) {\r\n throw new ExportError(\r\n '[pool] Work received, but pool has not been started.',\r\n 500\r\n );\r\n }\r\n\r\n // The acquire counter\r\n const acquireCounter = measureTime();\r\n\r\n // Try to acquire the worker along with the id, works count and page\r\n try {\r\n log(4, '[pool] Acquiring a worker handle.');\r\n\r\n // Acquire a pool resource\r\n workerHandle = await pool.acquire().promise;\r\n\r\n // Check the page acquire time\r\n if (options.server.benchmarking) {\r\n log(\r\n 5,\r\n `[benchmark] ${options.requestId ? `Request [${options.requestId}] - ` : ''}`,\r\n `Acquiring a worker handle took ${acquireCounter()}ms.`\r\n );\r\n }\r\n } catch (error) {\r\n throw new ExportError(\r\n `[pool] ${\r\n options.requestId ? `Request [${options.requestId}] - ` : ''\r\n }Error encountered when acquiring an available entry: ${acquireCounter()}ms.`,\r\n 400\r\n ).setError(error);\r\n }\r\n log(4, '[pool] Acquired a worker handle.');\r\n\r\n if (!workerHandle.page) {\r\n // Set the `workLimit` to exceeded in order to recreate the resource\r\n workerHandle.workCount = options.pool.workLimit + 1;\r\n throw new ExportError(\r\n '[pool] Resolved worker page is invalid: the pool setup is wonky.',\r\n 400\r\n );\r\n }\r\n\r\n log(\r\n 4,\r\n `[pool] Pool resource [${workerHandle.id}] - Starting work on this pool entry.`\r\n );\r\n\r\n // Start measuring export time\r\n const exportCounter = measureTime();\r\n\r\n // Perform an export on a puppeteer level\r\n const exportResult = await puppeteerExport(\r\n workerHandle.page,\r\n options.export,\r\n options.customLogic\r\n );\r\n\r\n // Check if it's an error\r\n if (exportResult instanceof Error) {\r\n // NOTE:\r\n // If there's a rasterization timeout, we want need to flush the page.\r\n // This is because the page may be in a state where it's waiting for\r\n // the screenshot to finish even though the timeout has occured.\r\n // Which of course causes a lot of issues with the event system,\r\n // and page consistency.\r\n //\r\n // Only `page.screenshot` will throw this, timeouts for PDF's are\r\n // handled by the `page.pdf` function itself.\r\n //\r\n // ...yes, this is ugly.\r\n if (exportResult.message === 'Rasterization timeout') {\r\n // Set the `workLimit` to exceeded in order to recreate the resource\r\n workerHandle.workCount = options.pool.workLimit + 1;\r\n workerHandle.page = null;\r\n }\r\n\r\n if (\r\n exportResult.name === 'TimeoutError' ||\r\n exportResult.message === 'Rasterization timeout'\r\n ) {\r\n throw new ExportError(\r\n `[pool] ${\r\n options.requestId ? `Request [${options.requestId}] - ` : ''\r\n }Rasterization timeout: your chart may be too complex or large, and failed to render within the allotted time.`\r\n ).setError(exportResult);\r\n } else {\r\n throw new ExportError(\r\n `[pool] ${\r\n options.requestId ? `Request [${options.requestId}] - ` : ''\r\n }Error encountered during export: ${exportCounter()}ms.`\r\n ).setError(exportResult);\r\n }\r\n }\r\n\r\n // Check the Puppeteer export time\r\n if (options.server.benchmarking) {\r\n log(\r\n 5,\r\n `[benchmark] ${options.requestId ? `Request [${options.requestId}] - ` : ''}`,\r\n `Exporting a chart sucessfully took ${exportCounter()}ms.`\r\n );\r\n }\r\n\r\n // Release the resource back to the pool\r\n pool.release(workerHandle);\r\n\r\n // Update statistics\r\n poolStats.timeSpent += exportCounter();\r\n poolStats.timeSpentAverage =\r\n poolStats.timeSpent / ++poolStats.exportsPerformed;\r\n\r\n log(4, `[pool] Work completed in ${exportCounter()}ms.`);\r\n\r\n // Otherwise return an object with the result and options\r\n return {\r\n result: exportResult,\r\n options\r\n };\r\n } catch (error) {\r\n ++poolStats.exportsDropped;\r\n\r\n // Try to release the worker, if it exists\r\n if (workerHandle) {\r\n pool.release(workerHandle);\r\n }\r\n\r\n throw error;\r\n }\r\n}\r\n\r\n/**\r\n * Retrieves the current pool instance.\r\n *\r\n * @function getPool\r\n *\r\n * @returns {(Object|null)} The current pool instance if initialized, or `null`\r\n * if the pool has not been created.\r\n */\r\nexport function getPool() {\r\n return pool;\r\n}\r\n\r\n/**\r\n * Gets the statistic of a pool instace about exports.\r\n *\r\n * @function getPoolStats\r\n *\r\n * @returns {Object} The current pool statistics.\r\n */\r\nexport function getPoolStats() {\r\n return poolStats;\r\n}\r\n\r\n/**\r\n * Retrieves pool information in JSON format, including minimum and maximum\r\n * workers, available workers, workers in use, and pending acquire requests.\r\n *\r\n * @function getPoolInfoJSON\r\n *\r\n * @returns {Object} Pool information in JSON format.\r\n */\r\nexport function getPoolInfoJSON() {\r\n return {\r\n min: pool.min,\r\n max: pool.max,\r\n used: pool.numUsed(),\r\n available: pool.numFree(),\r\n allCreated: pool.numUsed() + pool.numFree(),\r\n pendingAcquires: pool.numPendingAcquires(),\r\n pendingCreates: pool.numPendingCreates(),\r\n pendingValidations: pool.numPendingValidations(),\r\n pendingDestroys: pool.pendingDestroys.length,\r\n absoluteAll:\r\n pool.numUsed() +\r\n pool.numFree() +\r\n pool.numPendingAcquires() +\r\n pool.numPendingCreates() +\r\n pool.numPendingValidations() +\r\n pool.pendingDestroys.length\r\n };\r\n}\r\n\r\n/**\r\n * Logs information about the current state of the pool, including the minimum\r\n * and maximum workers, available workers, workers in use, and pending acquire\r\n * requests.\r\n *\r\n * @function _getPoolInfo\r\n */\r\nfunction _getPoolInfo() {\r\n const {\r\n min,\r\n max,\r\n used,\r\n available,\r\n allCreated,\r\n pendingAcquires,\r\n pendingCreates,\r\n pendingValidations,\r\n pendingDestroys,\r\n absoluteAll\r\n } = getPoolInfoJSON();\r\n\r\n log(5, `[pool] The minimum number of resources allowed by pool: ${min}.`);\r\n log(5, `[pool] The maximum number of resources allowed by pool: ${max}.`);\r\n log(5, `[pool] The number of used resources: ${used}.`);\r\n log(5, `[pool] The number of free resources: ${available}.`);\r\n log(\r\n 5,\r\n `[pool] The number of all created (used and free) resources: ${allCreated}.`\r\n );\r\n log(\r\n 5,\r\n `[pool] The number of resources waiting to be acquired: ${pendingAcquires}.`\r\n );\r\n log(\r\n 5,\r\n `[pool] The number of resources waiting to be created: ${pendingCreates}.`\r\n );\r\n log(\r\n 5,\r\n `[pool] The number of resources waiting to be validated: ${pendingValidations}.`\r\n );\r\n log(\r\n 5,\r\n `[pool] The number of resources waiting to be destroyed: ${pendingDestroys}.`\r\n );\r\n log(5, `[pool] The number of all resources: ${absoluteAll}.`);\r\n}\r\n\r\n/**\r\n * Factory function that returns an object with `create`, `validate`, `destroy`\r\n * functions for the pool instance.\r\n *\r\n * @function _factory\r\n *\r\n * @param {Object} poolOptions - The configuration object containing `pool`\r\n * options.\r\n */\r\nfunction _factory(poolOptions) {\r\n return {\r\n /**\r\n * Creates a new worker page for the export pool.\r\n *\r\n * @async\r\n * @function create\r\n *\r\n * @returns {Promise} A Promise that resolves to an object\r\n * containing the worker ID, a reference to the browser page, and initial\r\n * work count.\r\n *\r\n * @throws {ExportError} Throws an `ExportError` if there is an error during\r\n * the creation of the new page.\r\n */\r\n create: async () => {\r\n // Init the resource with unique id and work count\r\n const poolResource = {\r\n id: uuid(),\r\n // Try to distribute the initial work count\r\n workCount: Math.round(Math.random() * (poolOptions.workLimit / 2))\r\n };\r\n\r\n try {\r\n // Start measuring a page creation time\r\n const startDate = getNewDateTime();\r\n\r\n // Create a new page\r\n await newPage(poolResource);\r\n\r\n // Measure the time of full creation and configuration of a page\r\n log(\r\n 3,\r\n `[pool] Pool resource [${poolResource.id}] - Successfully created a worker, took ${\r\n getNewDateTime() - startDate\r\n }ms.`\r\n );\r\n\r\n // Return ready pool resource\r\n return poolResource;\r\n } catch (error) {\r\n log(\r\n 3,\r\n `[pool] Pool resource [${poolResource.id}] - Error encountered when creating a new page.`\r\n );\r\n throw error;\r\n }\r\n },\r\n\r\n /**\r\n * Validates a worker page in the export pool, checking if it has exceeded\r\n * the work limit.\r\n *\r\n * @async\r\n * @function validate\r\n *\r\n * @param {Object} poolResource - The handle to the worker, containing\r\n * the worker's ID, a reference to the browser page, and work count.\r\n *\r\n * @returns {Promise} A Promise that resolves to true if the worker\r\n * is valid and within the work limit; otherwise, to false.\r\n */\r\n validate: async (poolResource) => {\r\n // NOTE:\r\n // In certain cases acquiring throws a `TargetCloseError`, which may\r\n // be caused by two things:\r\n // - The page is closed and attempted to be reused.\r\n // - Lost contact with the browser.\r\n //\r\n // What we're seeing in logs is that successive exports typically\r\n // succeeds, and the server recovers, indicating that it's likely\r\n // the first case. This is an attempt at allievating the issue by\r\n // simply not validating the worker if the page is null or closed.\r\n //\r\n // The actual result from when this happened, was that a worker would\r\n // be completely locked, stopping it from being acquired until\r\n // its work count reached the limit.\r\n\r\n // Check if the `page` is valid\r\n if (!poolResource.page) {\r\n log(\r\n 3,\r\n `[pool] Pool resource [${poolResource.id}] - Validation failed (no valid page is found).`\r\n );\r\n return false;\r\n }\r\n\r\n // Check if the `page` is closed\r\n if (poolResource.page.isClosed()) {\r\n log(\r\n 3,\r\n `[pool] Pool resource [${poolResource.id}] - Validation failed (page is closed or invalid).`\r\n );\r\n return false;\r\n }\r\n\r\n // Check if the `mainFrame` is detached\r\n if (poolResource.page.mainFrame().detached) {\r\n log(\r\n 3,\r\n `[pool] Pool resource [${poolResource.id}] - Validation failed (page's frame is detached).`\r\n );\r\n return false;\r\n }\r\n\r\n // Check if the `workLimit` is exceeded\r\n if (\r\n poolOptions.workLimit &&\r\n ++poolResource.workCount > poolOptions.workLimit\r\n ) {\r\n log(\r\n 3,\r\n `[pool] Pool resource [${poolResource.id}] - Validation failed (exceeded the ${poolOptions.workLimit} works per resource limit).`\r\n );\r\n return false;\r\n }\r\n\r\n // The `poolResource` is validated\r\n return true;\r\n },\r\n\r\n /**\r\n * Destroys a worker entry in the export pool, closing its associated page.\r\n *\r\n * @async\r\n * @function destroy\r\n *\r\n * @param {Object} poolResource - The handle to the worker, containing\r\n * the worker's ID, a reference to the browser page, and work count.\r\n */\r\n destroy: async (poolResource) => {\r\n log(\r\n 3,\r\n `[pool] Pool resource [${poolResource.id}] - Destroying a worker.`\r\n );\r\n\r\n if (poolResource.page && !poolResource.page.isClosed()) {\r\n try {\r\n // Remove all attached event listeners from the resource\r\n poolResource.page.removeAllListeners('pageerror');\r\n poolResource.page.removeAllListeners('console');\r\n poolResource.page.removeAllListeners('framedetached');\r\n\r\n // We need to wait around for this\r\n await poolResource.page.close();\r\n } catch (error) {\r\n log(\r\n 3,\r\n `[pool] Pool resource [${poolResource.id}] - Page could not be closed upon destroying.`\r\n );\r\n throw error;\r\n }\r\n }\r\n }\r\n };\r\n}\r\n\r\nexport default {\r\n initPool,\r\n killPool,\r\n postWork,\r\n getPool,\r\n getPoolStats,\r\n getPoolInfoJSON\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * @overview Used to sanitize the strings coming from the exporting module\r\n * to prevent XSS attacks (with the DOMPurify library).\r\n */\r\n\r\nimport DOMPurify from 'dompurify';\r\nimport { JSDOM } from 'jsdom';\r\n\r\n/**\r\n * Sanitizes a given HTML string by removing \r\n * tags and any content within them.\r\n *\r\n * @function sanitize\r\n *\r\n * @param {string} input - The HTML string to be sanitized.\r\n *\r\n * @returns {string} The sanitized HTML string.\r\n */\r\nexport function sanitize(input) {\r\n // Get the virtual DOM\r\n const window = new JSDOM('').window;\r\n\r\n // Create a purifying instance\r\n const purify = DOMPurify(window);\r\n\r\n // Return sanitized input, allowing for the `foreignObject` elements\r\n return purify.sanitize(input, { ADD_TAGS: ['foreignObject'] });\r\n}\r\n\r\nexport default {\r\n sanitize\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * @overview This module provides functions that prepare for the exporting\r\n * charts into various image output formats such as JPEG, PNG, PDF, and SVGs.\r\n * It supports single and batch export operations and allows customization\r\n * through options passed from configurations or APIs.\r\n */\r\n\r\nimport { readFileSync, writeFileSync } from 'fs';\r\n\r\nimport { isAllowedConfig, updateOptions, validateOption } from './config.js';\r\nimport { log, logWithStack } from './logger.js';\r\nimport { getPoolStats, killPool, postWork } from './pool.js';\r\nimport { sanitize } from './sanitize.js';\r\nimport { getAbsolutePath, getBase64, isObject, roundNumber } from './utils.js';\r\n\r\nimport ExportError from './errors/ExportError.js';\r\n\r\n// The global flag for the code execution permission\r\nlet allowCodeExecution = false;\r\n\r\n/**\r\n * Starts a single export process based on the specified options and saves\r\n * the resulting image to the provided output file.\r\n *\r\n * @async\r\n * @function singleExport\r\n *\r\n * @param {Object} options - The `options` object, which should include settings\r\n * from the `export` and `customLogic` sections. It can be a partial or complete\r\n * set of options from these sections. The object must contain at least one\r\n * of the following `export` properties: `infile`, `instr`, `options`, or `svg`\r\n * to generate a valid image.\r\n *\r\n * @returns {Promise} A Promise that resolves once the single export\r\n * process is completed.\r\n *\r\n * @throws {ExportError} Throws an `ExportError` if an error occurs during\r\n * the single export process.\r\n */\r\nexport async function singleExport(options) {\r\n // Check if the export makes sense\r\n if (options && options.export) {\r\n // Perform an export\r\n await startExport(\r\n { export: options.export, customLogic: options.customLogic },\r\n async (error, data) => {\r\n // Exit process when error exists\r\n if (error) {\r\n throw error;\r\n }\r\n\r\n // Get the `b64`, `outfile`, and `type` for a chart\r\n const { b64, outfile, type } = data.options.export;\r\n\r\n // Save the result\r\n try {\r\n if (b64) {\r\n // As a Base64 string to a txt file\r\n writeFileSync(\r\n `${outfile.split('.').shift() || 'chart'}.txt`,\r\n getBase64(data.result, type)\r\n );\r\n } else {\r\n // As a correct image format\r\n writeFileSync(\r\n outfile || `chart.${type}`,\r\n type !== 'svg' ? Buffer.from(data.result, 'base64') : data.result\r\n );\r\n }\r\n } catch (error) {\r\n throw new ExportError(\r\n '[chart] Error while saving a chart.',\r\n 500\r\n ).setError(error);\r\n }\r\n\r\n // Kill pool and close browser after finishing single export\r\n await killPool();\r\n }\r\n );\r\n } else {\r\n throw new ExportError(\r\n '[chart] No expected `export` options were found. Please provide one of the following options: `infile`, `instr`, `options`, or `svg` to generate a valid image.',\r\n 400\r\n );\r\n }\r\n}\r\n\r\n/**\r\n * Starts a batch export process for multiple charts based on information\r\n * provided in the `batch` option. The `batch` is a string in the following\r\n * format: \"infile1.json=outfile1.png;infile2.json=outfile2.png;...\". Results\r\n * are saved to the specified output files.\r\n *\r\n * @async\r\n * @function batchExport\r\n *\r\n * @param {Object} options - The `options` object, which should include settings\r\n * from the `export` and `customLogic` sections. It can be a partial or complete\r\n * set of options from these sections. It must contain the `batch` option from\r\n * the `export` section to generate valid images.\r\n *\r\n * @returns {Promise} A Promise that resolves once the batch export\r\n * processes are completed.\r\n *\r\n * @throws {ExportError} Throws an `ExportError` if an error occurs during\r\n * any of the batch export process.\r\n */\r\nexport async function batchExport(options) {\r\n // Check if the export makes sense\r\n if (options && options.export && options.export.batch) {\r\n // An array for collecting batch exports\r\n const batchFunctions = [];\r\n\r\n // Split and pair the `batch` arguments\r\n for (let pair of options.export.batch.split(';') || []) {\r\n pair = pair.split('=');\r\n if (pair.length === 2) {\r\n batchFunctions.push(\r\n startExport(\r\n {\r\n export: {\r\n ...options.export,\r\n infile: pair[0],\r\n outfile: pair[1]\r\n },\r\n customLogic: options.customLogic\r\n },\r\n (error, data) => {\r\n // Exit process when error exists\r\n if (error) {\r\n throw error;\r\n }\r\n\r\n // Get the `b64`, `outfile`, and `type` for a chart\r\n const { b64, outfile, type } = data.options.export;\r\n\r\n // Save the result\r\n try {\r\n if (b64) {\r\n // As a Base64 string to a txt file\r\n writeFileSync(\r\n `${outfile.split('.').shift() || 'chart'}.txt`,\r\n getBase64(data.result, type)\r\n );\r\n } else {\r\n // As a correct image format\r\n writeFileSync(\r\n outfile,\r\n type !== 'svg'\r\n ? Buffer.from(data.result, 'base64')\r\n : data.result\r\n );\r\n }\r\n } catch (error) {\r\n throw new ExportError(\r\n '[chart] Error while saving a chart.',\r\n 500\r\n ).setError(error);\r\n }\r\n }\r\n )\r\n );\r\n } else {\r\n log(2, '[chart] No correct pair found for the batch export.');\r\n }\r\n }\r\n\r\n // Await all exports are done\r\n const batchResults = await Promise.allSettled(batchFunctions);\r\n\r\n // Kill pool and close browser after finishing batch export\r\n await killPool();\r\n\r\n // Log errors if found\r\n batchResults.forEach((result, index) => {\r\n // Log the error with stack about the specific batch export\r\n if (result.reason) {\r\n logWithStack(\r\n 1,\r\n result.reason,\r\n `[chart] Batch export number ${index + 1} could not be correctly completed.`\r\n );\r\n }\r\n });\r\n } else {\r\n throw new ExportError(\r\n '[chart] No expected `export` options were found. Please provide the `batch` option to generate valid images.',\r\n 400\r\n );\r\n }\r\n}\r\n\r\n/**\r\n * Starts an export process. The `imageOptions` parameter is an object that\r\n * should include settings from the `export` and `customLogic` sections. It can\r\n * be a partial or complete set of options from these sections. If partial\r\n * options are provided, missing values will be merged with the current global\r\n * options.\r\n *\r\n * The `endCallback` function is invoked upon the completion of the export,\r\n * either successfully or with an error. The `error` object is provided\r\n * as the first argument, and the `data` object is the second, containing\r\n * the Base64 representation of the chart in the `result` property\r\n * and the complete set of options in the `options` property.\r\n *\r\n * @async\r\n * @function startExport\r\n *\r\n * @param {Object} imageOptions - The `imageOptions` object, which should\r\n * include settings from the `export` and `customLogic` sections. It can\r\n * be a partial or complete set of options from these sections. If the provided\r\n * options are partial, missing values will be merged with the current global\r\n * options.\r\n * @param {Function} endCallback - The callback function to be invoked upon\r\n * finalizing the export process or upon encountering an error. The first\r\n * argument is the `error` object, and the second argument is the `data` object,\r\n * which includes the Base64 representation of the chart in the `result`\r\n * property and the full set of options in the `options` property.\r\n *\r\n * @returns {Promise} This function does not return a value directly.\r\n * Instead, it communicates results via the `endCallback`.\r\n *\r\n * @throws {ExportError} Throws an `ExportError` if there is a problem with\r\n * processing input of any type. The error is passed into the `endCallback`\r\n * function and processed there.\r\n */\r\nexport async function startExport(imageOptions, endCallback) {\r\n try {\r\n // Check if provided options are in an object\r\n if (!isObject(imageOptions)) {\r\n throw new ExportError(\r\n '[chart] Incorrect value of the provided `imageOptions`. Needs to be an object.',\r\n 400\r\n );\r\n }\r\n\r\n // Merge additional options to the copy of the instance options\r\n const options = updateOptions(\r\n {\r\n export: imageOptions.export,\r\n customLogic: imageOptions.customLogic\r\n },\r\n true\r\n );\r\n\r\n // Get the `export` options\r\n const exportOptions = options.export;\r\n\r\n // Starting exporting process message\r\n log(4, '[chart] Starting the exporting process.');\r\n\r\n // Export using options from the file as an input\r\n if (exportOptions.infile !== null) {\r\n log(4, '[chart] Attempting to export from a file input.');\r\n\r\n let fileContent;\r\n try {\r\n // Try to read the file to get the string representation\r\n fileContent = readFileSync(\r\n getAbsolutePath(exportOptions.infile),\r\n 'utf8'\r\n );\r\n } catch (error) {\r\n throw new ExportError(\r\n '[chart] Error loading content from a file input.',\r\n 400\r\n ).setError(error);\r\n }\r\n\r\n // Check the file's extension\r\n if (exportOptions.infile.endsWith('.svg')) {\r\n // Set to the `svg` option\r\n exportOptions.svg = validateOption('svg', fileContent);\r\n } else if (exportOptions.infile.endsWith('.json')) {\r\n // Set to the `instr` option\r\n exportOptions.instr = validateOption('instr', fileContent);\r\n } else {\r\n throw new ExportError(\r\n '[chart] Incorrect value of the `infile` option.',\r\n 400\r\n );\r\n }\r\n }\r\n\r\n // Export using SVG as an input\r\n if (exportOptions.svg !== null) {\r\n log(4, '[chart] Attempting to export from an SVG input.');\r\n\r\n // SVG exports attempts counter\r\n ++getPoolStats().exportsFromSvgAttempts;\r\n\r\n // Export from an SVG string\r\n const result = await _exportFromSvg(\r\n sanitize(exportOptions.svg), // #209\r\n options\r\n );\r\n\r\n // SVG exports counter\r\n ++getPoolStats().exportsFromSvg;\r\n\r\n // Pass SVG export result to the end callback\r\n return endCallback(null, result);\r\n }\r\n\r\n // Export using options as an input\r\n if (exportOptions.instr !== null || exportOptions.options !== null) {\r\n log(4, '[chart] Attempting to export from options input.');\r\n\r\n // Options exports attempts counter\r\n ++getPoolStats().exportsFromOptionsAttempts;\r\n\r\n // Export from options\r\n const result = await _exportFromOptions(\r\n exportOptions.instr || exportOptions.options,\r\n options\r\n );\r\n\r\n // Options exports counter\r\n ++getPoolStats().exportsFromOptions;\r\n\r\n // Pass options export result to the end callback\r\n return endCallback(null, result);\r\n }\r\n\r\n // No input specified, pass an error message to the callback\r\n return endCallback(\r\n new ExportError(\r\n `[chart] No valid input specified. Check if at least one of the following parameters is correctly set: 'infile', 'instr', 'options', or 'svg'.`,\r\n 400\r\n )\r\n );\r\n } catch (error) {\r\n return endCallback(error);\r\n }\r\n}\r\n\r\n/**\r\n * Retrieves and returns the current status of the code execution permission.\r\n *\r\n * @function getAllowCodeExecution\r\n *\r\n * @returns {boolean} The value of the global `allowCodeExecution` option.\r\n */\r\nexport function getAllowCodeExecution() {\r\n return allowCodeExecution;\r\n}\r\n\r\n/**\r\n * Sets the code execution permission based on the provided boolean value.\r\n *\r\n * @function setAllowCodeExecution\r\n *\r\n * @param {boolean} value - The boolean value to be assigned to the global\r\n * `allowCodeExecution` option.\r\n */\r\nexport function setAllowCodeExecution(value) {\r\n allowCodeExecution = value;\r\n}\r\n\r\n/**\r\n * Exports from an SVG based input with the provided options.\r\n *\r\n * @async\r\n * @function _exportFromSvg\r\n *\r\n * @param {string} inputToExport - The SVG based input to be exported.\r\n * @param {Object} options - The configuration object containing complete set\r\n * of options.\r\n *\r\n * @returns {Promise} A Promise that resolves to a result of the export\r\n * process.\r\n *\r\n * @throws {ExportError} Throws an `ExportError` if there is not a correct SVG\r\n * input.\r\n */\r\nasync function _exportFromSvg(inputToExport, options) {\r\n // Check if it is SVG\r\n if (\r\n typeof inputToExport === 'string' &&\r\n (inputToExport.indexOf('= 0 || inputToExport.indexOf('= 0)\r\n ) {\r\n log(4, '[chart] Parsing input as SVG.');\r\n\r\n // Set the export input as SVG\r\n options.export.svg = inputToExport;\r\n\r\n // Reset the rest of the export input options\r\n options.export.options = null;\r\n options.export.instr = null;\r\n\r\n // Call the function with an SVG string as an export input\r\n return _prepareExport(options);\r\n } else {\r\n throw new ExportError('[chart] Not a correct SVG input.', 400);\r\n }\r\n}\r\n\r\n/**\r\n * Exports from an options based input with the provided options.\r\n *\r\n * @async\r\n * @function _exportFromOptions\r\n *\r\n * @param {string} inputToExport - The options based input to be exported.\r\n * @param {Object} options - The configuration object containing complete set\r\n * of options.\r\n *\r\n * @returns {Promise} A Promise that resolves to a result of the export\r\n * process.\r\n *\r\n * @throws {ExportError} Throws an `ExportError` if there is not a correct\r\n * chart options input.\r\n */\r\nasync function _exportFromOptions(inputToExport, options) {\r\n log(4, '[chart] Parsing input from options.');\r\n\r\n // Try to check, validate and parse to stringified options\r\n const stringifiedOptions = isAllowedConfig(\r\n inputToExport,\r\n true,\r\n options.customLogic.allowCodeExecution\r\n );\r\n\r\n // Check if a correct stringified options\r\n if (\r\n stringifiedOptions === null ||\r\n typeof stringifiedOptions !== 'string' ||\r\n !stringifiedOptions.startsWith('{') ||\r\n !stringifiedOptions.endsWith('}')\r\n ) {\r\n throw new ExportError(\r\n '[chart] Invalid configuration provided - Only options configurations and SVG are allowed for this server. If this is your server, JavaScript custom code can be enabled by starting the server with the `allowCodeExecution` options set to true.',\r\n 403\r\n );\r\n }\r\n\r\n // Set the export input as a stringified chart options\r\n options.export.instr = stringifiedOptions;\r\n\r\n // Reset the rest of the export input options\r\n options.export.options = null;\r\n options.export.svg = null;\r\n\r\n // Call the function with a stringified chart options\r\n return _prepareExport(options);\r\n}\r\n\r\n/**\r\n * Function for finalizing options and configurations before export.\r\n *\r\n * @async\r\n * @function _prepareExport\r\n *\r\n * @param {Object} options - The configuration object containing complete set\r\n * of options.\r\n *\r\n * @returns {Promise} A Promise that resolves to a result of the export\r\n * process.\r\n */\r\nasync function _prepareExport(options) {\r\n // Get the `export` and `customLogic` options\r\n const { export: exportOptions, customLogic: customLogicOptions } = options;\r\n\r\n // Prepare the `constr` option\r\n exportOptions.constr = _fixConstr(exportOptions.constr);\r\n\r\n // Prepare the `type` option\r\n exportOptions.type = _fixType(exportOptions.type, exportOptions.outfile);\r\n\r\n // Prepare the `outfile` option\r\n exportOptions.outfile = _fixOutfile(\r\n exportOptions.type,\r\n exportOptions.outfile\r\n );\r\n\r\n // Notify about the custom logic usage status\r\n log(\r\n 3,\r\n `[chart] The custom logic is ${customLogicOptions.allowCodeExecution ? 'allowed' : 'disallowed'}.`\r\n );\r\n\r\n // Prepare the `customCode`, `callback`, and `resources` options\r\n _handleCustomLogic(customLogicOptions);\r\n\r\n // Prepare the `globalOptions` and `themeOptions` options\r\n _handleGlobalAndTheme(exportOptions, customLogicOptions);\r\n\r\n // Prepare the `height`, `width`, and `scale` options\r\n _handleSize(exportOptions);\r\n\r\n // Check if the image options object does not exceed the size limit\r\n _checkDataSize({ export: exportOptions, customLogic: customLogicOptions });\r\n\r\n // Post the work to the pool\r\n return postWork(options);\r\n}\r\n\r\n/**\r\n * Handles adjusting the constructor name by transforming and normalizing\r\n * it based on common chart types.\r\n *\r\n * @function _fixConstr\r\n *\r\n * @param {string} constr - The original constructor name to be adjusted.\r\n *\r\n * @returns {string} The corrected constructor name, or 'chart' if the input\r\n * is not recognized.\r\n */\r\nfunction _fixConstr(constr) {\r\n try {\r\n // Fix the constructor by lowering casing\r\n const fixedConstr = `${constr.toLowerCase().replace('chart', '')}Chart`;\r\n\r\n // Handle the case where the result is just 'Chart'\r\n if (fixedConstr === 'Chart') {\r\n fixedConstr.toLowerCase();\r\n }\r\n\r\n // Return the corrected constructor, otherwise default to 'chart'\r\n return ['chart', 'stockChart', 'mapChart', 'ganttChart'].includes(\r\n fixedConstr\r\n )\r\n ? fixedConstr\r\n : 'chart';\r\n } catch {\r\n // Default to 'chart' in case of any error\r\n return 'chart';\r\n }\r\n}\r\n\r\n/**\r\n * Handles fixing the outfile based on provided type.\r\n *\r\n * @function _fixOutfile\r\n *\r\n * @param {string} type - The original export type.\r\n * @param {string} outfile - The file path or name.\r\n *\r\n * @returns {string} The corrected outfile, or 'chart.png' if the input\r\n * is not recognized.\r\n */\r\nfunction _fixOutfile(type, outfile) {\r\n // Get the file name from the `outfile` option\r\n const fileName = getAbsolutePath(outfile || 'chart')\r\n .split('.')\r\n .shift();\r\n\r\n // Return a correct outfile\r\n return `${fileName}.${type || 'png'}`;\r\n}\r\n\r\n/**\r\n * Handles fixing the export type based on MIME types and file extensions.\r\n *\r\n * @function _fixType\r\n *\r\n * @param {string} type - The original export type.\r\n * @param {string} [outfile=null] - The file path or name. The default value\r\n * is `null`.\r\n *\r\n * @returns {string} The corrected export type, or 'png' if the input\r\n * is not recognized.\r\n */\r\nfunction _fixType(type, outfile = null) {\r\n // MIME types\r\n const mimeTypes = {\r\n 'image/png': 'png',\r\n 'image/jpeg': 'jpeg',\r\n 'application/pdf': 'pdf',\r\n 'image/svg+xml': 'svg'\r\n };\r\n\r\n // Get formats\r\n const formats = Object.values(mimeTypes);\r\n\r\n // Check if type and outfile's extensions are the same\r\n if (outfile) {\r\n const outType = outfile.split('.').pop();\r\n\r\n // Support the JPG type\r\n if (outType === 'jpg') {\r\n type = 'jpeg';\r\n } else if (formats.includes(outType) && type !== outType) {\r\n type = outType;\r\n }\r\n }\r\n\r\n // Return a correct type\r\n return mimeTypes[type] || formats.find((t) => t === type) || 'png';\r\n}\r\n\r\n/**\r\n * Handle calculating the `height`, `width` and `scale` for chart exports based\r\n * on the provided export options.\r\n *\r\n * The function prioritizes values in the following order:\r\n *\r\n * 1. The `height`, `width`, `scale` from the `exportOptions`.\r\n * 2. Options from the chart configuration (from `exporting` and `chart`).\r\n * 3. Options from the global options (from `exporting` and `chart`).\r\n * 4. Options from the theme options (from `exporting` and `chart` sections).\r\n * 5. Fallback default values (`height = 400`, `width = 600`, `scale = 1`).\r\n *\r\n * @function _handleSize\r\n *\r\n * @param {Object} exportOptions - The configuration object containing `export`\r\n * options.\r\n */\r\nfunction _handleSize(exportOptions) {\r\n // Check the `options` and `instr` for chart and exporting sections\r\n const { chart: optionsChart, exporting: optionsExporting } =\r\n isAllowedConfig(exportOptions.instr) || false;\r\n\r\n // Check the `globalOptions` for chart and exporting sections\r\n const { chart: globalOptionsChart, exporting: globalOptionsExporting } =\r\n isAllowedConfig(exportOptions.globalOptions) || false;\r\n\r\n // Check the `themeOptions` for chart and exporting sections\r\n const { chart: themeOptionsChart, exporting: themeOptionsExporting } =\r\n isAllowedConfig(exportOptions.themeOptions) || false;\r\n\r\n // Find the `height` value\r\n const height =\r\n exportOptions.height ||\r\n optionsExporting?.sourceHeight ||\r\n optionsChart?.height ||\r\n globalOptionsExporting?.sourceHeight ||\r\n globalOptionsChart?.height ||\r\n themeOptionsExporting?.sourceHeight ||\r\n themeOptionsChart?.height ||\r\n exportOptions.defaultHeight ||\r\n 400;\r\n\r\n // Find the `width` value\r\n const width =\r\n exportOptions.width ||\r\n optionsExporting?.sourceWidth ||\r\n optionsChart?.width ||\r\n globalOptionsExporting?.sourceWidth ||\r\n globalOptionsChart?.width ||\r\n themeOptionsExporting?.sourceWidth ||\r\n themeOptionsChart?.width ||\r\n exportOptions.defaultWidth ||\r\n 600;\r\n\r\n // Find the `scale` value:\r\n // - Cannot be lower than 0.1\r\n // - Cannot be higher than 5.0\r\n // - Must be rounded to 2 decimal places (e.g. 0.23234 -> 0.23)\r\n const scale = roundNumber(\r\n Math.max(\r\n 0.1,\r\n Math.min(\r\n exportOptions.scale ||\r\n optionsExporting?.scale ||\r\n globalOptionsExporting?.scale ||\r\n themeOptionsExporting?.scale ||\r\n exportOptions.defaultScale ||\r\n 1,\r\n 5.0\r\n )\r\n ),\r\n 2\r\n );\r\n\r\n // Update `height`, `width`, and `scale` information in the `export` options\r\n exportOptions.height = height;\r\n exportOptions.width = width;\r\n exportOptions.scale = scale;\r\n\r\n // Get rid of potential `px` and `%`\r\n for (let param of ['height', 'width', 'scale']) {\r\n if (typeof exportOptions[param] === 'string') {\r\n exportOptions[param] = +exportOptions[param].replace(/px|%/gi, '');\r\n }\r\n }\r\n}\r\n\r\n/**\r\n * Handles the execution of custom logic options, including loading `resources`,\r\n * `customCode`, and `callback`. If code execution is allowed, it processes\r\n * the custom logic options accordingly. If code execution is not allowed,\r\n * it disables the usage of resources, custom code and callback.\r\n *\r\n * @function _handleCustomLogic\r\n *\r\n * @param {Object} customLogicOptions - The configuration object containing\r\n * `customLogic` options.\r\n *\r\n * @throws {ExportError} Throws an `ExportError` if code execution\r\n * is not allowed but custom logic options are still provided.\r\n */\r\nfunction _handleCustomLogic(customLogicOptions) {\r\n // In case of allowing code execution\r\n if (customLogicOptions.allowCodeExecution) {\r\n // Process the `resources` option\r\n try {\r\n // Try to handle resources\r\n customLogicOptions.resources = _handleResources(\r\n customLogicOptions.resources,\r\n customLogicOptions.allowFileResources,\r\n true\r\n );\r\n\r\n // Validate option\r\n customLogicOptions.resources = validateOption(\r\n 'resources',\r\n customLogicOptions.resources\r\n );\r\n } catch (error) {\r\n log(2, '[chart] The `resources` cannot be loaded.');\r\n\r\n // In case of an error, set the option with null\r\n customLogicOptions.resources = null;\r\n }\r\n\r\n // Process the `customCode` option\r\n try {\r\n // Try to load custom code and wrap around it in a self invoking function\r\n customLogicOptions.customCode = _handleCustomCode(\r\n customLogicOptions.customCode,\r\n customLogicOptions.allowFileResources\r\n );\r\n\r\n // Validate the option\r\n customLogicOptions.customCode = validateOption(\r\n 'customCode',\r\n customLogicOptions.customCode\r\n );\r\n } catch (error) {\r\n logWithStack(2, error, '[chart] The `customCode` cannot be loaded.');\r\n\r\n // In case of an error, set the option with null\r\n customLogicOptions.customCode = null;\r\n }\r\n\r\n // Process the `callback` option\r\n try {\r\n // Try to load callback function\r\n customLogicOptions.callback = _handleCustomCode(\r\n customLogicOptions.callback,\r\n customLogicOptions.allowFileResources,\r\n true\r\n );\r\n\r\n // Validate the option\r\n customLogicOptions.callback = validateOption(\r\n 'callback',\r\n customLogicOptions.callback\r\n );\r\n } catch (error) {\r\n logWithStack(2, error, '[chart] The `callback` cannot be loaded.');\r\n\r\n // In case of an error, set the option with null\r\n customLogicOptions.callback = null;\r\n }\r\n\r\n // Check if there is the `customCode` present\r\n if ([null, undefined].includes(customLogicOptions.customCode)) {\r\n log(3, '[chart] No value for the `customCode` option found.');\r\n }\r\n\r\n // Check if there is the `callback` present\r\n if ([null, undefined].includes(customLogicOptions.callback)) {\r\n log(3, '[chart] No value for the `callback` option found.');\r\n }\r\n\r\n // Check if there is the `resources` present\r\n if ([null, undefined].includes(customLogicOptions.resources)) {\r\n log(3, '[chart] No value for the `resources` option found.');\r\n }\r\n } else {\r\n // If the `allowCodeExecution` flag is set to false, we should refuse\r\n // the usage of the `callback`, `resources`, and `customCode` options.\r\n // Additionally, the worker will refuse to run arbitrary JavaScript.\r\n if (\r\n customLogicOptions.callback ||\r\n customLogicOptions.resources ||\r\n customLogicOptions.customCode\r\n ) {\r\n // Reset all custom code options\r\n customLogicOptions.callback = null;\r\n customLogicOptions.resources = null;\r\n customLogicOptions.customCode = null;\r\n\r\n // Send a message saying that the exporter does not support these settings\r\n throw new ExportError(\r\n `[chart] The 'callback', 'resources', and 'customCode' options have been disabled for this server.`,\r\n 403\r\n );\r\n }\r\n }\r\n}\r\n\r\n/**\r\n * Handles and validates resources from the `resources` option for export.\r\n *\r\n * @function _handleResources\r\n *\r\n * @param {(Object|string|null)} [resources=null] - The resources to be handled.\r\n * Can be either a JSON object, stringified JSON, a path to a JSON file,\r\n * or null. The default value is `null`.\r\n * @param {boolean} allowFileResources - A flag indicating whether loading\r\n * resources from files is allowed.\r\n * @param {boolean} allowCodeExecution - A flag indicating whether code\r\n * execution is allowed.\r\n *\r\n * @returns {(Object|null)} The handled resources or null if no valid resources\r\n * are found.\r\n */\r\nfunction _handleResources(\r\n resources = null,\r\n allowFileResources,\r\n allowCodeExecution\r\n) {\r\n let handledResources = resources;\r\n\r\n // If no resources found, try to load the default resources\r\n if (!handledResources) {\r\n resources = 'resources.json';\r\n }\r\n\r\n // List of allowed sections in the resources JSON\r\n const allowedProps = ['js', 'css', 'files'];\r\n\r\n // A flag that decides based to return resources or `null`\r\n let correctResources = false;\r\n\r\n // Try to load resources from a file\r\n if (\r\n allowFileResources &&\r\n typeof resources === 'string' &&\r\n resources.endsWith('.json')\r\n ) {\r\n handledResources = isAllowedConfig(\r\n readFileSync(getAbsolutePath(resources), 'utf8'),\r\n false,\r\n allowCodeExecution\r\n );\r\n } else {\r\n // Try to get JSON\r\n handledResources = isAllowedConfig(resources, false, allowCodeExecution);\r\n\r\n // Get rid of the files section\r\n if (handledResources && !allowFileResources) {\r\n delete handledResources.files;\r\n }\r\n }\r\n\r\n // Filter from unnecessary properties\r\n for (const propName in handledResources) {\r\n if (!allowedProps.includes(propName)) {\r\n delete handledResources[propName];\r\n } else if (!correctResources) {\r\n correctResources = true;\r\n }\r\n }\r\n\r\n // Check if at least one of allowed properties is present\r\n if (!correctResources) {\r\n return null;\r\n }\r\n\r\n // Handle files section\r\n if (handledResources.files) {\r\n handledResources.files = handledResources.files.map((item) => item.trim());\r\n if (!handledResources.files || handledResources.files.length <= 0) {\r\n delete handledResources.files;\r\n }\r\n }\r\n\r\n // Return resources\r\n return handledResources;\r\n}\r\n\r\n/**\r\n * Handles custom code to execute it safely.\r\n *\r\n * @function _handleCustomCode\r\n *\r\n * @param {string} customCode - The custom code to be wrapped.\r\n * @param {boolean} allowFileResources - Flag to allow loading code from a file.\r\n * @param {boolean} [isCallback=false] - Flag that indicates the returned code\r\n * must be in a callback format.\r\n *\r\n * @returns {(string|null)} The wrapped custom code or null if wrapping fails.\r\n */\r\nfunction _handleCustomCode(customCode, allowFileResources, isCallback = false) {\r\n if (customCode && typeof customCode === 'string') {\r\n customCode = customCode.trim();\r\n\r\n if (customCode.endsWith('.js')) {\r\n // Load a file if the file resources are allowed\r\n return allowFileResources\r\n ? _handleCustomCode(\r\n readFileSync(getAbsolutePath(customCode), 'utf8'),\r\n allowFileResources,\r\n isCallback\r\n )\r\n : null;\r\n } else if (\r\n !isCallback &&\r\n (customCode.startsWith('function()') ||\r\n customCode.startsWith('function ()') ||\r\n customCode.startsWith('()=>') ||\r\n customCode.startsWith('() =>'))\r\n ) {\r\n // Treat a function as a self-invoking expression\r\n return `(${customCode})()`;\r\n }\r\n\r\n // Or return as a stringified code\r\n return customCode.replace(/;$/, '');\r\n }\r\n}\r\n\r\n/**\r\n * Handles the loading and validation of the `globalOptions` and `themeOptions`\r\n * in the export options. If the option is a string and references a JSON file\r\n * (when the `allowFileResources` is `true`), it reads and parses the file.\r\n * Otherwise, it attempts to parse the string or object as JSON. If any errors\r\n * occur during this process, the option is set to `null`. If there is an error\r\n * loading or parsing the `globalOptions` or `themeOptions`, the error is logged\r\n * and the option is set to `null`.\r\n *\r\n * @function _handleGlobalAndTheme\r\n *\r\n * @param {Object} exportOptions - The configuration object containing `export`\r\n * options.\r\n * @param {Object} customLogicOptions - The configuration object containing\r\n * `customLogic` options.\r\n */\r\nfunction _handleGlobalAndTheme(exportOptions, customLogicOptions) {\r\n // Get the `allowFileResources` and `allowCodeExecution` flags\r\n const { allowFileResources, allowCodeExecution } = customLogicOptions;\r\n\r\n // Check the `globalOptions` and `themeOptions` options\r\n ['globalOptions', 'themeOptions'].forEach((optionsName) => {\r\n try {\r\n // Check if the option exists\r\n if (exportOptions[optionsName]) {\r\n // Check if it is a string and a file name with the `.json` extension\r\n if (\r\n allowFileResources &&\r\n typeof exportOptions[optionsName] === 'string' &&\r\n exportOptions[optionsName].endsWith('.json')\r\n ) {\r\n // Check if the file content can be a config, and save it as a string\r\n exportOptions[optionsName] = isAllowedConfig(\r\n readFileSync(getAbsolutePath(exportOptions[optionsName]), 'utf8'),\r\n true,\r\n allowCodeExecution\r\n );\r\n } else {\r\n // Check if the value can be a config, and save it as a string\r\n exportOptions[optionsName] = isAllowedConfig(\r\n exportOptions[optionsName],\r\n true,\r\n allowCodeExecution\r\n );\r\n }\r\n\r\n // Validate the option\r\n exportOptions[optionsName] = validateOption(\r\n optionsName,\r\n exportOptions[optionsName]\r\n );\r\n }\r\n } catch (error) {\r\n logWithStack(\r\n 2,\r\n error,\r\n `[chart] The \\`${optionsName}\\` cannot be loaded.`\r\n );\r\n\r\n // In case of an error, set the option with null\r\n exportOptions[optionsName] = null;\r\n }\r\n });\r\n\r\n // Check if there is the `globalOptions` present\r\n if ([null, undefined].includes(exportOptions.globalOptions)) {\r\n log(3, '[chart] No value for the `globalOptions` option found.');\r\n }\r\n\r\n // Check if there is the `themeOptions` present\r\n if ([null, undefined].includes(exportOptions.themeOptions)) {\r\n log(3, '[chart] No value for the `themeOptions` option found.');\r\n }\r\n}\r\n\r\n/**\r\n * Validates the size of the data for the export process against a fixed limit\r\n * of 100MB.\r\n *\r\n * @function _checkDataSize\r\n *\r\n * @param {Object} imageOptions - The data object, which includes options from\r\n * the `export` and `customLogic` sections and will be sent to a Puppeteer page.\r\n *\r\n * @throws {ExportError} Throws an `ExportError` if the size of the data for\r\n * the export process object exceeds the 100MB limit.\r\n */\r\nfunction _checkDataSize(imageOptions) {\r\n // Set the fixed data limit (100MB) for the dev-tools protocol\r\n const dataLimit = 100 * 1024 * 1024;\r\n\r\n // Get the size of the data\r\n const totalSize = Buffer.byteLength(JSON.stringify(imageOptions), 'utf-8');\r\n\r\n // Log the size in MB\r\n log(\r\n 3,\r\n `[chart] The current total size of the data for the export process is around ${(\r\n totalSize /\r\n (1024 * 1024)\r\n ).toFixed(2)}MB.`\r\n );\r\n\r\n // Check the size of data before passing to a page\r\n if (totalSize >= dataLimit) {\r\n throw new ExportError(\r\n `[chart] The data for the export process exceeds 100MB limit.`\r\n );\r\n }\r\n}\r\n\r\nexport default {\r\n singleExport,\r\n batchExport,\r\n startExport,\r\n getAllowCodeExecution,\r\n setAllowCodeExecution\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * @overview This module provides utility functions for managing intervals\r\n * and timeouts in a centralized manner. It maintains a registry of all active\r\n * timers and allows for their efficient cleanup when needed to avoid potential\r\n * memory leaks, unintended behavior or a process from being stopped.\r\n */\r\n\r\nimport { log } from './logger.js';\r\n\r\n// Array that contains ids of all ongoing intervals and timeouts\r\nconst timerIds = [];\r\n\r\n/**\r\n * Adds id of the `setInterval` or `setTimeout` and to the `timerIds` array.\r\n *\r\n * @function addTimer\r\n *\r\n * @param {NodeJS.Timeout} id - Id of an interval or a timeout.\r\n */\r\nexport function addTimer(id) {\r\n timerIds.push(id);\r\n}\r\n\r\n/**\r\n * Clears all of ongoing intervals and timeouts by ids gathered\r\n * in the `timerIds` array.\r\n *\r\n * @function clearAllTimers\r\n */\r\nexport function clearAllTimers() {\r\n log(4, `[timer] Clearing all registered intervals and timeouts.`);\r\n for (const id of timerIds) {\r\n clearInterval(id);\r\n clearTimeout(id);\r\n }\r\n}\r\n\r\nexport default {\r\n addTimer,\r\n clearAllTimers\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * @overview Provides middleware functions for logging errors with stack traces\r\n * and handling error responses in an Express application.\r\n */\r\n\r\nimport { getOptions } from '../../config.js';\r\nimport { logWithStack } from '../../logger.js';\r\n\r\n/**\r\n * Middleware for logging errors with stack trace and handling error response.\r\n *\r\n * @function logErrorMiddleware\r\n *\r\n * @param {Error} error - The error object.\r\n * @param {Express.Request} request - The Express request object.\r\n * @param {Express.Response} response - The Express response object.\r\n * @param {Function} next - The next middleware function.\r\n *\r\n * @returns {undefined} The call to the next middleware function with\r\n * the passed error.\r\n */\r\nfunction logErrorMiddleware(error, request, response, next) {\r\n // Display the error with stack in a correct format\r\n logWithStack(1, error);\r\n\r\n // Delete the stack for the environment other than the development\r\n if (getOptions().other.nodeEnv !== 'development') {\r\n delete error.stack;\r\n }\r\n\r\n // Call the `returnErrorMiddleware` middleware\r\n return next(error);\r\n}\r\n\r\n/**\r\n * Middleware for returning error response.\r\n *\r\n * @function returnErrorMiddleware\r\n *\r\n * @param {Error} error - The error object.\r\n * @param {Express.Request} request - The Express request object.\r\n * @param {Express.Response} response - The Express response object.\r\n * @param {Function} next - The next middleware function.\r\n */\r\nfunction returnErrorMiddleware(error, request, response, next) {\r\n // Gather all requied information for the response\r\n const { message, stack } = error;\r\n\r\n // Use the error's status code or the default 400\r\n const statusCode = error.statusCode || 400;\r\n\r\n // Set and return response\r\n response.status(statusCode).json({ statusCode, message, stack });\r\n}\r\n\r\n/**\r\n * Adds the error middlewares to the passed express app instance.\r\n *\r\n * @param {Express} app - The Express app instance.\r\n */\r\nexport default function errorMiddleware(app) {\r\n // Add log error middleware\r\n app.use(logErrorMiddleware);\r\n\r\n // Add set status and return error middleware\r\n app.use(returnErrorMiddleware);\r\n}\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * @overview Provides middleware functions for configuring and enabling rate\r\n * limiting in an Express application.\r\n */\r\n\r\nimport rateLimit from 'express-rate-limit';\r\n\r\nimport { log } from '../../logger.js';\r\n\r\nimport ExportError from '../../errors/ExportError.js';\r\n\r\n/**\r\n * Middleware for enabling rate limiting on the specified Express app.\r\n *\r\n * @param {Express} app - The Express app instance.\r\n * @param {Object} rateLimitingOptions - The configuration object containing\r\n * `rateLimiting` options.\r\n *\r\n * @throws {ExportError} Throws an `ExportError` if could not configure and set\r\n * the rate limiting options.\r\n */\r\nexport default function rateLimitingMiddleware(app, rateLimitingOptions) {\r\n try {\r\n // Check if the rate limiting is enabled and the app exists\r\n if (app && rateLimitingOptions.enable) {\r\n const message =\r\n 'Too many requests, you have been rate limited. Please try again later.';\r\n\r\n // Options for the rate limiter\r\n const rateOptions = {\r\n window: rateLimitingOptions.window || 1,\r\n maxRequests: rateLimitingOptions.maxRequests || 30,\r\n delay: rateLimitingOptions.delay || 0,\r\n trustProxy: rateLimitingOptions.trustProxy || false,\r\n skipKey: rateLimitingOptions.skipKey || null,\r\n skipToken: rateLimitingOptions.skipToken || null\r\n };\r\n\r\n // Set if behind a proxy\r\n if (rateOptions.trustProxy) {\r\n app.enable('trust proxy');\r\n }\r\n\r\n // Create a limiter\r\n const limiter = rateLimit({\r\n // Time frame for which requests are checked and remembered\r\n windowMs: rateOptions.window * 60 * 1000,\r\n // Limit each IP to 100 requests per `windowMs`\r\n limit: rateOptions.maxRequests,\r\n // Disable delaying, full speed until the max limit is reached\r\n delayMs: rateOptions.delay,\r\n handler: (request, response) => {\r\n response.format({\r\n json: () => {\r\n response.status(429).send({ message });\r\n },\r\n default: () => {\r\n response.status(429).send(message);\r\n }\r\n });\r\n },\r\n skip: (request) => {\r\n // Allow bypassing the limiter if a valid key/token has been sent\r\n if (\r\n rateOptions.skipKey !== null &&\r\n rateOptions.skipToken !== null &&\r\n request.query.key === rateOptions.skipKey &&\r\n request.query.access_token === rateOptions.skipToken\r\n ) {\r\n log(4, '[rate limiting] Skipping rate limiter.');\r\n return true;\r\n }\r\n return false;\r\n }\r\n });\r\n\r\n // Use a limiter as a middleware\r\n app.use(limiter);\r\n\r\n log(\r\n 3,\r\n `[rate limiting] Enabled rate limiting with ${rateOptions.maxRequests} requests per ${rateOptions.window} minute for each IP, trusting proxy: ${rateOptions.trustProxy}.`\r\n );\r\n }\r\n } catch (error) {\r\n throw new ExportError(\r\n '[rate limiting] Could not configure and set the rate limiting options.',\r\n 500\r\n ).setError(error);\r\n }\r\n}\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * @overview Provides middleware functions for validating incoming HTTP requests\r\n * in an Express application. This module ensures that requests contain\r\n * appropriate content types and valid request bodies, including proper JSON\r\n * structures and chart data for exports. It checks for potential issues such\r\n * as missing or malformed data, private range URLs in SVG payloads, and allows\r\n * for flexible options validation. The middleware logs detailed information\r\n * and handles errors related to incorrect payloads, chart data, and private URL\r\n * usage.\r\n */\r\n\r\nimport { v4 as uuid } from 'uuid';\r\n\r\nimport { getAllowCodeExecution } from '../../chart.js';\r\nimport { isAllowedConfig } from '../../config.js';\r\nimport { log } from '../../logger.js';\r\nimport { isObjectEmpty, isPrivateRangeUrlFound } from '../../utils.js';\r\n\r\nimport ExportError from '../../errors/ExportError.js';\r\n\r\n/**\r\n * Middleware for validating the content-type header.\r\n *\r\n * @function contentTypeMiddleware\r\n *\r\n * @param {Express.Request} request - The Express request object.\r\n * @param {Express.Response} response - The Express response object.\r\n * @param {Function} next - The next middleware function.\r\n *\r\n * @returns {undefined} The call to the next middleware function.\r\n *\r\n * @throws {ExportError} Throws an `ExportError` if the content-type\r\n * is not correct.\r\n */\r\nfunction contentTypeMiddleware(request, response, next) {\r\n try {\r\n // Get the content type header\r\n const contentType = request.headers['content-type'] || '';\r\n\r\n // Allow only JSON, URL-encoded and form data without files types of data\r\n if (\r\n !contentType.includes('application/json') &&\r\n !contentType.includes('application/x-www-form-urlencoded') &&\r\n !contentType.includes('multipart/form-data')\r\n ) {\r\n throw new ExportError(\r\n '[validation] Content-Type must be application/json, application/x-www-form-urlencoded, or multipart/form-data.',\r\n 415\r\n );\r\n }\r\n\r\n // Call the `requestBodyMiddleware` middleware\r\n return next();\r\n } catch (error) {\r\n return next(error);\r\n }\r\n}\r\n\r\n/**\r\n * Middleware for validating the request's body.\r\n *\r\n * @function requestBodyMiddleware\r\n *\r\n * @param {Express.Request} request - The Express request object.\r\n * @param {Express.Response} response - The Express response object.\r\n * @param {Function} next - The next middleware function.\r\n *\r\n * @returns {undefined} The call to the next middleware function.\r\n *\r\n * @throws {ExportError} Throws an `ExportError` if the body is not correct.\r\n * @throws {ExportError} Throws an `ExportError` if the chart data from the body\r\n * is not correct.\r\n * @throws {ExportError} Throws an `ExportError` in case of the private range\r\n * url error.\r\n */\r\nfunction requestBodyMiddleware(request, response, next) {\r\n try {\r\n // Get the request body\r\n const body = request.body;\r\n\r\n // Create a unique ID for a request\r\n const requestId = uuid();\r\n\r\n // Throw an error if there is no correct body\r\n if (!body || isObjectEmpty(body)) {\r\n log(\r\n 2,\r\n `[validation] Request [${requestId}] - The request from ${\r\n request.headers['x-forwarded-for'] || request.connection.remoteAddress\r\n } was incorrect. Received payload is empty.`\r\n );\r\n\r\n throw new ExportError(\r\n `[validation] Request [${requestId}] - The request body is required. Please ensure that your Content-Type header is correct. Accepted types are 'application/json' and 'multipart/form-data'.`,\r\n 400\r\n );\r\n }\r\n\r\n // Get the `allowCodeExecution` option for the server\r\n const allowCodeExecution = getAllowCodeExecution();\r\n\r\n // Find a correct chart options\r\n const instr = isAllowedConfig(\r\n // Use one of the below\r\n body.instr || body.options || body.infile || body.data,\r\n // Stringify options\r\n true,\r\n // Allow or disallow functions\r\n allowCodeExecution\r\n );\r\n\r\n // Throw an error if there is no correct chart data\r\n if (instr === null && !body.svg) {\r\n log(\r\n 2,\r\n `[validation] Request [${requestId}] - The request from ${\r\n request.headers['x-forwarded-for'] || request.connection.remoteAddress\r\n } was incorrect. Received payload is missing correct chart data for export: ${JSON.stringify(body)}.`\r\n );\r\n\r\n throw new ExportError(\r\n `[validation] Request [${requestId}] - No correct chart data found. Ensure that you are using either application/json or multipart/form-data headers. If sending JSON, make sure the chart data is in the 'infile', 'options', or 'data' attribute. If sending SVG, ensure it is in the 'svg' attribute.`,\r\n 400\r\n );\r\n }\r\n\r\n // Throw an error if test of xlink:href elements from payload's SVG fails\r\n if (body.svg && isPrivateRangeUrlFound(body.svg)) {\r\n throw new ExportError(\r\n `[validation] Request [${requestId}] - SVG potentially contain at least one forbidden URL in 'xlink:href' element. Please review the SVG content and ensure that all referenced URLs comply with security policies.`,\r\n 400\r\n );\r\n }\r\n\r\n // Get and pre-validate the options and store them in the request\r\n request.validatedOptions = {\r\n // Set the created ID as a `requestId` property in the options\r\n requestId,\r\n export: {\r\n instr,\r\n svg: body.svg,\r\n outfile:\r\n body.outfile ||\r\n `${request.params.filename || 'chart'}.${body.type || 'png'}`,\r\n type: body.type,\r\n constr: body.constr,\r\n b64: body.b64,\r\n noDownload: body.noDownload,\r\n height: body.height,\r\n width: body.width,\r\n scale: body.scale,\r\n globalOptions: isAllowedConfig(\r\n body.globalOptions,\r\n true,\r\n allowCodeExecution\r\n ),\r\n themeOptions: isAllowedConfig(\r\n body.themeOptions,\r\n true,\r\n allowCodeExecution\r\n )\r\n },\r\n customLogic: {\r\n allowCodeExecution,\r\n allowFileResources: false,\r\n customCode: body.customCode,\r\n callback: body.callback,\r\n resources: isAllowedConfig(body.resources, true, allowCodeExecution)\r\n }\r\n };\r\n\r\n // Call the next middleware\r\n return next();\r\n } catch (error) {\r\n return next(error);\r\n }\r\n}\r\n\r\n/**\r\n * Adds the validation middlewares to the passed express app instance.\r\n *\r\n * @param {Express} app - The Express app instance.\r\n */\r\nexport default function validationMiddleware(app) {\r\n // Add content type validation middleware\r\n app.post(['/', '/:filename'], contentTypeMiddleware);\r\n\r\n // Add request body request validation middleware\r\n app.post(['/', '/:filename'], requestBodyMiddleware);\r\n}\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * @overview Defines the export routes and logic for handling chart export\r\n * requests in an Express server. This module processes incoming requests\r\n * to export charts in various formats (e.g. JPEG, PNG, PDF, SVG). It integrates\r\n * with Highcharts' core functionalities and supports both immediate download\r\n * responses and Base64-encoded content returns. The code also features\r\n * benchmarking for performance monitoring.\r\n */\r\n\r\nimport { startExport } from '../../chart.js';\r\nimport { log } from '../../logger.js';\r\nimport { getBase64, measureTime } from '../../utils.js';\r\n\r\nimport ExportError from '../../errors/ExportError.js';\r\n\r\n// Reversed MIME types\r\nconst reversedMime = {\r\n png: 'image/png',\r\n jpeg: 'image/jpeg',\r\n gif: 'image/gif',\r\n pdf: 'application/pdf',\r\n svg: 'image/svg+xml'\r\n};\r\n\r\n/**\r\n * Handles the export requests from the client.\r\n *\r\n * @async\r\n * @function requestExport\r\n *\r\n * @param {Express.Request} request - The Express request object.\r\n * @param {Express.Response} response - The Express response object.\r\n * @param {Function} next - The next middleware function.\r\n *\r\n * @returns {Promise} A Promise that resolves once the export process\r\n * is complete.\r\n */\r\nasync function requestExport(request, response, next) {\r\n try {\r\n // Start counting time for a request\r\n const requestCounter = measureTime();\r\n\r\n // In case the connection is closed, force to abort further actions\r\n let connectionAborted = false;\r\n request.socket.on('close', (hadErrors) => {\r\n if (hadErrors) {\r\n connectionAborted = true;\r\n }\r\n });\r\n\r\n // Get the options previously validated in the validation middleware\r\n const options = request.validatedOptions;\r\n\r\n // Get the request id\r\n const requestId = options.requestId;\r\n\r\n // Info about an incoming request with correct data\r\n log(4, `[export] Request [${requestId}] - Got an incoming HTTP request.`);\r\n\r\n // Start the export process\r\n await startExport(options, (error, data) => {\r\n // Remove the close event from the socket\r\n request.socket.removeAllListeners('close');\r\n\r\n // If the connection was closed, do nothing\r\n if (connectionAborted) {\r\n log(\r\n 3,\r\n `[export] Request [${requestId}] - The client closed the connection before the chart finished processing.`\r\n );\r\n return;\r\n }\r\n\r\n // If error, log it and send it to the error middleware\r\n if (error) {\r\n throw error;\r\n }\r\n\r\n // If data is missing, log the message and send it to the error middleware\r\n if (!data || !data.result) {\r\n log(\r\n 2,\r\n `[export] Request [${requestId}] - Request from ${\r\n request.headers['x-forwarded-for'] ||\r\n request.connection.remoteAddress\r\n } was incorrect. Received result is ${data.result}.`\r\n );\r\n\r\n throw new ExportError(\r\n `[export] Request [${requestId}] - Unexpected return of the export result from the chart generation. Please check your request data.`,\r\n 400\r\n );\r\n }\r\n\r\n // Return the result in an appropriate format\r\n if (data.result) {\r\n log(\r\n 3,\r\n `[export] Request [${requestId}] - The whole exporting process took ${requestCounter()}ms.`\r\n );\r\n\r\n // Get the `type`, `b64`, `noDownload`, and `outfile` from options\r\n const { type, b64, noDownload, outfile } = data.options.export;\r\n\r\n // If only Base64 is required, return it\r\n if (b64) {\r\n return response.send(getBase64(data.result, type));\r\n }\r\n\r\n // Set correct content type\r\n response.header('Content-Type', reversedMime[type] || 'image/png');\r\n\r\n // Decide whether to download or not chart file\r\n if (!noDownload) {\r\n response.attachment(outfile);\r\n }\r\n\r\n // If SVG, return plain content, otherwise a b64 string from a buffer\r\n return type === 'svg'\r\n ? response.send(data.result)\r\n : response.send(Buffer.from(data.result, 'base64'));\r\n }\r\n });\r\n } catch (error) {\r\n return next(error);\r\n }\r\n}\r\n\r\n/**\r\n * Adds the `export` routes.\r\n *\r\n * @function exportRoutes\r\n *\r\n * @param {Express} app - The Express app instance.\r\n */\r\nexport default function exportRoutes(app) {\r\n /**\r\n * Adds the POST '/' - A route for handling POST requests at the root\r\n * endpoint.\r\n */\r\n app.post('/', requestExport);\r\n\r\n /**\r\n * Adds the POST '/:filename' - A route for handling POST requests with\r\n * a specified filename parameter.\r\n */\r\n app.post('/:filename', requestExport);\r\n}\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * @overview Defines an Express route for server health monitoring, including\r\n * uptime, success rates, and other server statistics.\r\n */\r\n\r\nimport { readFileSync } from 'fs';\r\nimport { join } from 'path';\r\n\r\nimport { getHcVersion } from '../../cache.js';\r\nimport { log } from '../../logger.js';\r\nimport { getPoolInfoJSON, getPoolStats } from '../../pool.js';\r\nimport { addTimer } from '../../timer.js';\r\nimport { __dirname, getNewDateTime } from '../../utils.js';\r\n\r\n// Set the start date of the server\r\nconst serverStartTime = new Date();\r\n\r\n// Get the `package.json` content\r\nconst packageFile = JSON.parse(\r\n readFileSync(join(__dirname, 'package.json'), 'utf8')\r\n);\r\n\r\n// An array for success rate ratios\r\nconst successRates = [];\r\n\r\n// Record every minute\r\nconst recordInterval = 60 * 1000;\r\n\r\n// 30 minutes\r\nconst windowSize = 30;\r\n\r\n/**\r\n * Calculates moving average indicator based on the data from the `successRates`\r\n * array.\r\n *\r\n * @function _calculateMovingAverage\r\n *\r\n * @returns {number} A moving average for success ratio of the server exports.\r\n */\r\nfunction _calculateMovingAverage() {\r\n return successRates.reduce((a, b) => a + b, 0) / successRates.length;\r\n}\r\n\r\n/**\r\n * Starts the interval responsible for calculating current success rate ratio\r\n * and collects records to the `successRates` array.\r\n *\r\n * @function _startSuccessRate\r\n *\r\n * @returns {NodeJS.Timeout} Id of an interval.\r\n */\r\nfunction _startSuccessRate() {\r\n return setInterval(() => {\r\n const stats = getPoolStats();\r\n const successRatio =\r\n stats.exportsAttempted === 0\r\n ? 1\r\n : (stats.exportsPerformed / stats.exportsAttempted) * 100;\r\n\r\n successRates.push(successRatio);\r\n if (successRates.length > windowSize) {\r\n successRates.shift();\r\n }\r\n }, recordInterval);\r\n}\r\n\r\n/**\r\n * Adds the `health` routes.\r\n *\r\n * @function healthRoutes\r\n *\r\n * @param {Express} app - The Express app instance.\r\n */\r\nexport default function healthRoutes(app) {\r\n // Start processing success rate ratio interval and save its id to the array\r\n // for the graceful clearing on shutdown with injected `addTimer` funtion\r\n addTimer(_startSuccessRate());\r\n\r\n /**\r\n * Adds the GET '/health' - A route for getting the basic stats of the server.\r\n */\r\n app.get('/health', (request, response, next) => {\r\n try {\r\n log(4, '[health] Returning server health.');\r\n\r\n const stats = getPoolStats();\r\n const period = successRates.length;\r\n const movingAverage = _calculateMovingAverage();\r\n\r\n // Send the server's statistics\r\n response.send({\r\n // Status and times\r\n status: 'OK',\r\n bootTime: serverStartTime,\r\n uptime: `${Math.floor((getNewDateTime() - serverStartTime.getTime()) / 1000 / 60)} minutes`,\r\n\r\n // Versions\r\n serverVersion: packageFile.version,\r\n highchartsVersion: getHcVersion(),\r\n\r\n // Exports\r\n averageExportTime: stats.timeSpentAverage,\r\n attemptedExports: stats.exportsAttempted,\r\n performedExports: stats.exportsPerformed,\r\n failedExports: stats.exportsDropped,\r\n sucessRatio: (stats.exportsPerformed / stats.exportsAttempted) * 100,\r\n\r\n // Pool\r\n pool: getPoolInfoJSON(),\r\n\r\n // Moving average\r\n period,\r\n movingAverage,\r\n message:\r\n isNaN(movingAverage) || !successRates.length\r\n ? 'Too early to report. No exports made yet. Please check back soon.'\r\n : `Last ${period} minutes had a success rate of ${movingAverage.toFixed(2)}%.`,\r\n\r\n // SVG and JSON exports\r\n svgExports: stats.exportsFromSvg,\r\n jsonExports: stats.exportsFromOptions,\r\n svgExportsAttempts: stats.exportsFromSvgAttempts,\r\n jsonExportsAttempts: stats.exportsFromOptionsAttempts\r\n });\r\n } catch (error) {\r\n return next(error);\r\n }\r\n });\r\n}\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * @overview Defines an Express route for serving the UI for the export server\r\n * when enabled.\r\n */\r\n\r\nimport { join } from 'path';\r\n\r\nimport { getOptions } from '../../config.js';\r\nimport { log } from '../../logger.js';\r\nimport { __dirname } from '../../utils.js';\r\n\r\n/**\r\n * Adds the `ui` routes.\r\n *\r\n * @function uiRoutes\r\n *\r\n * @param {Express} app - The Express app instance.\r\n */\r\nexport default function uiRoutes(app) {\r\n // Add the UI endpoint only if required\r\n if (getOptions().ui.enable) {\r\n /**\r\n * Adds the GET '/' - A route for a UI when enabled on the export server.\r\n */\r\n app.get(getOptions().ui.route || '/', (request, response, next) => {\r\n try {\r\n log(4, '[ui] Returning UI for the export.');\r\n\r\n response.sendFile(join(__dirname, 'public', 'index.html'), {\r\n acceptRanges: false\r\n });\r\n } catch (error) {\r\n return next(error);\r\n }\r\n });\r\n }\r\n}\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * @overview Defines an Express route for updating the Highcharts version\r\n * on the server, with authentication and validation.\r\n */\r\n\r\nimport { getHcVersion, updateHcVersion } from '../../cache.js';\r\nimport { log } from '../../logger.js';\r\nimport { envs } from '../../validation.js';\r\n\r\nimport ExportError from '../../errors/ExportError.js';\r\n\r\n/**\r\n * Adds the `version_change` routes.\r\n *\r\n * @function versionChangeRoutes\r\n *\r\n * @param {Express} app - The Express app instance.\r\n */\r\nexport default function versionChangeRoutes(app) {\r\n /**\r\n * Adds the POST '/version_change/:newVersion' - A route for changing\r\n * the Highcharts version on the server.\r\n */\r\n app.post('/version_change/:newVersion', async (request, response, next) => {\r\n try {\r\n log(4, '[version] Changing Highcharts version.');\r\n\r\n // Get the token directly from envs\r\n const adminToken = envs.HIGHCHARTS_ADMIN_TOKEN;\r\n\r\n // Check the existence of the token\r\n if (!adminToken || !adminToken.length) {\r\n throw new ExportError(\r\n '[version] The server is not configured to perform run-time version changes: `HIGHCHARTS_ADMIN_TOKEN` is not set.',\r\n 401\r\n );\r\n }\r\n\r\n // Get the token from the hc-auth header\r\n const token = request.get('hc-auth');\r\n\r\n // Check if the hc-auth header contain a correct token\r\n if (!token || token !== adminToken) {\r\n throw new ExportError(\r\n '[version] Invalid or missing token: Set the token in the hc-auth header.',\r\n 401\r\n );\r\n }\r\n\r\n // Get the new version from the params\r\n const newVersion = request.params.newVersion;\r\n\r\n // Update version\r\n if (newVersion) {\r\n try {\r\n await updateHcVersion(newVersion);\r\n } catch (error) {\r\n throw new ExportError(\r\n `[version] Version change: ${error.message}`,\r\n 400\r\n ).setError(error);\r\n }\r\n\r\n // Success\r\n response.status(200).send({\r\n statusCode: 200,\r\n highchartsVersion: getHcVersion(),\r\n message: `Successfully updated Highcharts to version: ${newVersion}.`\r\n });\r\n } else {\r\n // No version specified\r\n throw new ExportError('[version] No new version supplied.', 400);\r\n }\r\n } catch (error) {\r\n return next(error);\r\n }\r\n });\r\n}\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * @overview A module that sets up and manages HTTP and HTTPS servers\r\n * for the Highcharts Export Server. It handles server initialization,\r\n * configuration, error handling, middlewares setup, route definition, and rate\r\n * limiting. The module exports functions to start, stop, and manage server\r\n * instances, as well as utility functions for defining routes and attaching\r\n * middlewares.\r\n */\r\n\r\nimport { readFileSync } from 'fs';\r\nimport { join } from 'path';\r\n\r\nimport cors from 'cors';\r\nimport express from 'express';\r\nimport http from 'http';\r\nimport https from 'https';\r\nimport multer from 'multer';\r\n\r\nimport { updateOptions } from '../config.js';\r\nimport { log, logWithStack } from '../logger.js';\r\nimport { __dirname, getAbsolutePath } from '../utils.js';\r\n\r\nimport errorMiddleware from './middlewares/error.js';\r\nimport rateLimitingMiddleware from './middlewares/rateLimiting.js';\r\nimport validationMiddleware from './middlewares/validation.js';\r\n\r\nimport exportRoutes from './routes/export.js';\r\nimport healthRoutes from './routes/health.js';\r\nimport uiRoutes from './routes/ui.js';\r\nimport versionChangeRoutes from './routes/versionChange.js';\r\n\r\nimport ExportError from '../errors/ExportError.js';\r\n\r\n// Array of an active servers\r\nconst activeServers = new Map();\r\n\r\n// Create express app\r\nconst app = express();\r\n\r\n/**\r\n * Starts an HTTP and/or HTTPS server based on the provided configuration.\r\n * The `serverOptions` object contains server-related properties (refer\r\n * to the `server` section in the `./lib/schemas/config.js` file for details).\r\n *\r\n * @async\r\n * @function startServer\r\n *\r\n * @param {Object} [serverOptions={}] - The configuration object containing\r\n * `server` options. This object may include a partial or complete set\r\n * of the `server` options. If the options are partial, missing values will\r\n * default to the current global configuration. The default value is an empty\r\n * object.\r\n *\r\n * @returns {Promise} A Promise that resolves when the server is either\r\n * not enabled or no valid Express app is found, signaling the end of the\r\n * function's execution.\r\n *\r\n * @throws {ExportError} Throws an `ExportError` if the server cannot\r\n * be configured and started.\r\n */\r\nexport async function startServer(serverOptions = {}) {\r\n try {\r\n // Update the instance options object\r\n const options = updateOptions({\r\n server: serverOptions\r\n });\r\n\r\n // Use validated options\r\n serverOptions = options.server;\r\n\r\n // Stop if not enabled\r\n if (!serverOptions.enable || !app) {\r\n throw new ExportError(\r\n '[server] Server cannot be started (not enabled or no correct Express app found).',\r\n 500\r\n );\r\n }\r\n\r\n // Too big limits lead to timeouts in the export process when\r\n // the rasterization timeout is set too low\r\n const uploadLimitBytes = serverOptions.uploadLimit * 1024 * 1024;\r\n\r\n // Memory storage for multer package\r\n const storage = multer.memoryStorage();\r\n\r\n // Enable parsing of form data (files) with multer package\r\n const upload = multer({\r\n storage,\r\n limits: {\r\n fieldSize: uploadLimitBytes\r\n }\r\n });\r\n\r\n // Disable the X-Powered-By header\r\n app.disable('x-powered-by');\r\n\r\n // Enable CORS support\r\n app.use(\r\n cors({\r\n methods: ['POST', 'GET', 'OPTIONS']\r\n })\r\n );\r\n\r\n // Getting a lot of `RangeNotSatisfiableError` exceptions (even though this\r\n // is a deprecated options, let's try to set it to false)\r\n app.use((request, response, next) => {\r\n response.set('Accept-Ranges', 'none');\r\n next();\r\n });\r\n\r\n // Enable body parser for JSON data\r\n app.use(\r\n express.json({\r\n limit: uploadLimitBytes\r\n })\r\n );\r\n\r\n // Enable body parser for URL-encoded form data\r\n app.use(\r\n express.urlencoded({\r\n extended: true,\r\n limit: uploadLimitBytes\r\n })\r\n );\r\n\r\n // Use only non-file multipart form fields\r\n app.use(upload.none());\r\n\r\n // Set up static folder's route\r\n app.use(express.static(join(__dirname, 'public')));\r\n\r\n // Listen HTTP server\r\n if (!serverOptions.ssl.force) {\r\n // Main server instance (HTTP)\r\n const httpServer = http.createServer(app);\r\n\r\n // Attach error handlers and listen to the server\r\n _attachServerErrorHandlers(httpServer);\r\n\r\n // Listen\r\n httpServer.listen(serverOptions.port, serverOptions.host, () => {\r\n // Save the reference to HTTP server\r\n activeServers.set(serverOptions.port, httpServer);\r\n\r\n log(\r\n 3,\r\n `[server] Started HTTP server on ${serverOptions.host}:${serverOptions.port}.`\r\n );\r\n });\r\n }\r\n\r\n // Listen HTTPS server\r\n if (serverOptions.ssl.enable) {\r\n // Set up an SSL server also\r\n let key, cert;\r\n\r\n try {\r\n // Get the SSL key\r\n key = readFileSync(\r\n join(getAbsolutePath(serverOptions.ssl.certPath), 'server.key'),\r\n 'utf8'\r\n );\r\n\r\n // Get the SSL certificate\r\n cert = readFileSync(\r\n join(getAbsolutePath(serverOptions.ssl.certPath), 'server.crt'),\r\n 'utf8'\r\n );\r\n } catch (error) {\r\n log(\r\n 2,\r\n `[server] Unable to load key/certificate from the '${serverOptions.ssl.certPath}' path. Could not run secured layer server.`\r\n );\r\n }\r\n\r\n if (key && cert) {\r\n // Main server instance (HTTPS)\r\n const httpsServer = https.createServer({ key, cert }, app);\r\n\r\n // Attach error handlers and listen to the server\r\n _attachServerErrorHandlers(httpsServer);\r\n\r\n // Listen\r\n httpsServer.listen(serverOptions.ssl.port, serverOptions.host, () => {\r\n // Save the reference to HTTPS server\r\n activeServers.set(serverOptions.ssl.port, httpsServer);\r\n\r\n log(\r\n 3,\r\n `[server] Started HTTPS server on ${serverOptions.host}:${serverOptions.ssl.port}.`\r\n );\r\n });\r\n }\r\n }\r\n\r\n // Set up the rate limiter\r\n rateLimitingMiddleware(app, serverOptions.rateLimiting);\r\n\r\n // Set up the validation handler\r\n validationMiddleware(app);\r\n\r\n // Set up routes\r\n exportRoutes(app);\r\n healthRoutes(app);\r\n uiRoutes(app);\r\n versionChangeRoutes(app);\r\n\r\n // Set up the centralized error handler\r\n errorMiddleware(app);\r\n } catch (error) {\r\n throw new ExportError(\r\n '[server] Could not configure and start the server.',\r\n 500\r\n ).setError(error);\r\n }\r\n}\r\n\r\n/**\r\n * Closes all servers associated with Express app instance.\r\n *\r\n * @function closeServers\r\n */\r\nexport function closeServers() {\r\n // Check if there are servers working\r\n if (activeServers.size > 0) {\r\n log(4, `[server] Closing all servers.`);\r\n\r\n // Close each one of servers\r\n for (const [port, server] of activeServers) {\r\n server.close(() => {\r\n activeServers.delete(port);\r\n log(4, `[server] Closed server on port: ${port}.`);\r\n });\r\n }\r\n }\r\n}\r\n\r\n/**\r\n * Get all servers associated with Express app instance.\r\n *\r\n * @function getServers\r\n *\r\n * @returns {Array} Servers associated with Express app instance.\r\n */\r\nexport function getServers() {\r\n return activeServers;\r\n}\r\n\r\n/**\r\n * Get the Express instance.\r\n *\r\n * @function getExpress\r\n *\r\n * @returns {Express} The Express instance.\r\n */\r\nexport function getExpress() {\r\n return express;\r\n}\r\n\r\n/**\r\n * Get the Express app instance.\r\n *\r\n * @function getApp\r\n *\r\n * @returns {Express} The Express app instance.\r\n */\r\nexport function getApp() {\r\n return app;\r\n}\r\n\r\n/**\r\n * Enable rate limiting for the server.\r\n *\r\n * @function enableRateLimiting\r\n *\r\n * @param {Object} rateLimitingOptions - The configuration object containing\r\n * `rateLimiting` options. This object may include a partial or complete set\r\n * of the `rateLimiting` options. If the options are partial, missing values\r\n * will default to the current global configuration.\r\n */\r\nexport function enableRateLimiting(rateLimitingOptions) {\r\n // Update the instance options object\r\n const options = updateOptions({\r\n server: {\r\n rateLimiting: rateLimitingOptions\r\n }\r\n });\r\n\r\n // Set the rate limiting options\r\n rateLimitingMiddleware(app, options.server.rateLimitingOptions);\r\n}\r\n\r\n/**\r\n * Apply middleware(s) to a specific path.\r\n *\r\n * @function use\r\n *\r\n * @param {string} path - The path to which the middleware(s) should be applied.\r\n * @param {...Function} middlewares - The middleware function(s) to be applied.\r\n */\r\nexport function use(path, ...middlewares) {\r\n app.use(path, ...middlewares);\r\n}\r\n\r\n/**\r\n * Set up a route with GET method and apply middleware(s).\r\n *\r\n * @function get\r\n *\r\n * @param {string} path - The path to which the middleware(s) should be applied.\r\n * @param {...Function} middlewares - The middleware function(s) to be applied.\r\n */\r\nexport function get(path, ...middlewares) {\r\n app.get(path, ...middlewares);\r\n}\r\n\r\n/**\r\n * Set up a route with POST method and apply middleware(s).\r\n *\r\n * @function post\r\n *\r\n * @param {string} path - The path to which the middleware(s) should be applied.\r\n * @param {...Function} middlewares - The middleware function(s) to be applied.\r\n */\r\nexport function post(path, ...middlewares) {\r\n app.post(path, ...middlewares);\r\n}\r\n\r\n/**\r\n * Attach error handlers to the server.\r\n *\r\n * @function _attachServerErrorHandlers\r\n *\r\n * @param {(http.Server|https.Server)} server - The HTTP/HTTPS server instance.\r\n */\r\nfunction _attachServerErrorHandlers(server) {\r\n server.on('clientError', (error, socket) => {\r\n logWithStack(\r\n 1,\r\n error,\r\n `[server] Client error: ${error.message}, destroying socket.`\r\n );\r\n socket.destroy();\r\n });\r\n\r\n server.on('error', (error) => {\r\n logWithStack(1, error, `[server] Server error: ${error.message}`);\r\n });\r\n\r\n server.on('connection', (socket) => {\r\n socket.on('error', (error) => {\r\n logWithStack(1, error, `[server] Socket error: ${error.message}`);\r\n });\r\n });\r\n}\r\n\r\nexport default {\r\n startServer,\r\n closeServers,\r\n getServers,\r\n getExpress,\r\n getApp,\r\n enableRateLimiting,\r\n use,\r\n get,\r\n post\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * @overview Handles graceful shutdown of the Highcharts Export Server, ensuring\r\n * proper cleanup of resources such as browser, pages, servers, and timers.\r\n */\r\n\r\nimport { killPool } from './pool.js';\r\nimport { clearAllTimers } from './timer.js';\r\n\r\nimport { closeServers } from './server/server.js';\r\n\r\n/**\r\n * Performs cleanup operations to ensure a graceful shutdown of the process.\r\n * This includes clearing all registered timeouts/intervals, closing active\r\n * servers, terminating resources (pages) of the pool, pool itself, and closing\r\n * the browser.\r\n *\r\n * @function shutdownCleanUp\r\n *\r\n * @param {number} [exitCode=0] - The exit code to use with `process.exit()`.\r\n * The default value is `0`.\r\n */\r\nexport async function shutdownCleanUp(exitCode = 0) {\r\n // Await freeing all resources\r\n await Promise.allSettled([\r\n // Clear all ongoing intervals\r\n clearAllTimers(),\r\n\r\n // Get available server instances (HTTP/HTTPS) and close them\r\n closeServers(),\r\n\r\n // Close an active pool along with its workers and the browser instance\r\n killPool()\r\n ]);\r\n\r\n // Exit process with a correct code\r\n process.exit(exitCode);\r\n}\r\n\r\nexport default {\r\n shutdownCleanUp\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * @overview This core module initializes and manages the Highcharts Export\r\n * Server. The main `initExport` function handles logging, script caching,\r\n * resource pooling, browser startup, and ensures graceful process cleanup\r\n * on exit. Additionally, it provides API functions for using it as a Node.js\r\n * module, offering functionalities for processing options, configuring\r\n * and performing exports, and setting up server.\r\n */\r\n\r\nimport 'colors';\r\n\r\nimport { checkCache } from './cache.js';\r\nimport {\r\n batchExport,\r\n singleExport,\r\n startExport,\r\n setAllowCodeExecution\r\n} from './chart.js';\r\nimport {\r\n getOptions,\r\n updateOptions,\r\n mapToNewOptions,\r\n validateOption,\r\n validateOptions\r\n} from './config.js';\r\nimport {\r\n log,\r\n logWithStack,\r\n logZodIssues,\r\n initLogging,\r\n enableConsoleLogging,\r\n enableFileLogging,\r\n setLogLevel\r\n} from './logger.js';\r\nimport { initPool, killPool } from './pool.js';\r\nimport { shutdownCleanUp } from './resourceRelease.js';\r\n\r\nimport server from './server/server.js';\r\n\r\n/**\r\n * Initializes the export process. Tasks such as configuring logging, checking\r\n * the cache and sources, and initializing the resource pool occur during this\r\n * stage.\r\n *\r\n * This function must be called before attempting to export charts or set\r\n * up a server.\r\n *\r\n * @async\r\n * @function initExport\r\n *\r\n * @param {Object} [initOptions={}] - The `initOptions` object, which may\r\n * be a partial or complete set of options. If the options are partial, missing\r\n * values will default to the current global configuration. The default value\r\n * is an empty object.\r\n */\r\nexport async function initExport(initOptions = {}) {\r\n // Init, validate and update the options object\r\n const options = updateOptions(initOptions);\r\n\r\n // Set the `allowCodeExecution` per export module scope\r\n setAllowCodeExecution(options.customLogic.allowCodeExecution);\r\n\r\n // Init the logging\r\n initLogging(options.logging);\r\n\r\n // Attach process' exit listeners\r\n if (options.other.listenToProcessExits) {\r\n _attachProcessExitListeners();\r\n }\r\n\r\n // Check the current status of cache\r\n await checkCache(options.highcharts, options.server.proxy);\r\n\r\n // Init the pool\r\n await initPool(options.pool, options.puppeteer.args);\r\n}\r\n\r\n/**\r\n * Attaches exit listeners to the process, ensuring proper cleanup of resources\r\n * and termination on exit signals. Handles 'exit', 'SIGINT', 'SIGTERM',\r\n * and 'uncaughtException' events.\r\n *\r\n * @function _attachProcessExitListeners\r\n */\r\nfunction _attachProcessExitListeners() {\r\n log(3, '[process] Attaching exit listeners to the process.');\r\n\r\n // Handler for the 'exit'\r\n process.on('exit', (code) => {\r\n log(4, `[process] Process exited with code: ${code}.`);\r\n });\r\n\r\n // Handler for the 'SIGINT'\r\n process.on('SIGINT', async (name, code) => {\r\n log(4, `[process] The ${name} event with code: ${code}.`);\r\n await shutdownCleanUp();\r\n });\r\n\r\n // Handler for the 'SIGTERM'\r\n process.on('SIGTERM', async (name, code) => {\r\n log(4, `[process] The ${name} event with code: ${code}.`);\r\n await shutdownCleanUp();\r\n });\r\n\r\n // Handler for the 'SIGHUP'\r\n process.on('SIGHUP', async (name, code) => {\r\n log(4, `[process] The ${name} event with code: ${code}.`);\r\n await shutdownCleanUp();\r\n });\r\n\r\n // Handler for the 'uncaughtException'\r\n process.on('uncaughtException', async (error, name) => {\r\n logWithStack(1, error, `[process] The ${name} error.`);\r\n await shutdownCleanUp(1);\r\n });\r\n}\r\n\r\nexport default {\r\n // Server\r\n ...server,\r\n\r\n // Options\r\n getOptions,\r\n updateOptions,\r\n mapToNewOptions,\r\n\r\n // Validation\r\n validateOption,\r\n validateOptions,\r\n\r\n // Exporting\r\n initExport,\r\n singleExport,\r\n batchExport,\r\n startExport,\r\n\r\n // Release\r\n killPool,\r\n shutdownCleanUp,\r\n\r\n // Logs\r\n log,\r\n logWithStack,\r\n logZodIssues,\r\n setLogLevel: function (level) {\r\n // Update the instance options object\r\n const options = updateOptions({\r\n logging: {\r\n level\r\n }\r\n });\r\n\r\n // Call the function\r\n setLogLevel(options.logging.level);\r\n },\r\n enableConsoleLogging: function (toConsole) {\r\n // Update the instance options object\r\n const options = updateOptions({\r\n logging: {\r\n toConsole\r\n }\r\n });\r\n\r\n // Call the function\r\n enableConsoleLogging(options.logging.toConsole);\r\n },\r\n enableFileLogging: function (dest, file, toFile) {\r\n // Update the instance options object\r\n const options = updateOptions({\r\n logging: {\r\n dest,\r\n file,\r\n toFile\r\n }\r\n });\r\n\r\n // Call the function\r\n enableFileLogging(\r\n options.logging.dest,\r\n options.logging.file,\r\n options.logging.toFile\r\n );\r\n }\r\n};\r\n"],"names":["__dirname","fileURLToPath","URL","url","deepCopy","objArr","objArrCopy","Array","isArray","key","Object","prototype","hasOwnProperty","call","getAbsolutePath","path","isAbsolute","normalize","resolve","getBase64","input","type","Buffer","from","toString","getNewDate","Date","split","trim","getNewDateTime","getTime","isObject","item","isObjectEmpty","keys","length","isPrivateRangeUrlFound","some","pattern","test","measureTime","start","process","hrtime","bigint","Number","roundNumber","value","precision","multiplier","Math","pow","round","colors","logging","toConsole","toFile","pathCreated","pathToLog","levelsDesc","title","color","log","args","newLevel","texts","level","prefix","_logToFile","console","apply","undefined","concat","logWithStack","error","customMessage","mainMessage","message","stackMessage","stack","push","shift","logZodIssues","issues","map","issue","join","initLogging","loggingOptions","dest","file","setLogLevel","enableConsoleLogging","enableFileLogging","isInteger","existsSync","mkdirSync","appendFile","defaultConfig","puppeteer","types","envLink","cliName","description","promptOptions","separator","highcharts","version","cdnUrl","forceFetch","cachePath","coreScripts","instructions","moduleScripts","indicatorScripts","customScripts","export","infile","instr","options","svg","batch","outfile","hint","choices","constr","b64","noDownload","height","width","scale","defaultHeight","defaultWidth","defaultScale","min","max","globalOptions","themeOptions","rasterizationTimeout","customLogic","allowCodeExecution","allowFileResources","customCode","callback","resources","loadConfig","legacyName","createConfig","server","enable","host","port","uploadLimit","benchmarking","proxy","timeout","rateLimiting","maxRequests","window","delay","trustProxy","skipKey","skipToken","ssl","force","certPath","pool","minWorkers","maxWorkers","workLimit","acquireTimeout","createTimeout","destroyTimeout","idleTimeout","createRetryInterval","reaperInterval","ui","route","other","nodeEnv","listenToProcessExits","noLogo","hardResetPage","browserShellMode","validation","debug","headless","devtools","listenToConsole","dumpio","slowMo","debuggingPort","dotenv","config","z","setErrorMap","_customErrorMap","v","boolean","strictCheck","union","enum","transform","includes","nullable","string","refine","params","errorMessage","values","stringArray","filterCallback","arraySchema","array","stringSchema","startsWith","slice","endsWith","transformCallback","filter","positiveNum","number","positive","isNaN","nonNegativeNum","nonnegative","prefixes","chartConfig","object","passthrough","additionalOptions","validators","adminToken","indexOf","gte","lte","this","objectSchema","js","css","files","partial","stringSchema1","stringSchema2","enableServer","serverBenchmarking","proxyHost","proxyPort","proxyTimeout","enableRateLimiting","enableSsl","sslForce","sslPort","sslCertPath","poolBenchmarking","resourcesInterval","logLevel","int","logFile","logDest","logToConsole","logToFile","enableUi","uiRoute","enableDebug","requestId","uuid","PuppeteerSchema","HighchartsSchema","ExportSchema","CustomLogicSchema","ProxySchema","RateLimitingSchema","SslSchema","ServerSchema","optional","PoolSchema","LoggingSchema","UiSchema","OtherSchema","DebugSchema","StrictConfigSchema","LooseConfigSchema","EnvSchema","PUPPETEER_ARGS","HIGHCHARTS_VERSION","HIGHCHARTS_CDN_URL","HIGHCHARTS_FORCE_FETCH","HIGHCHARTS_CACHE_PATH","HIGHCHARTS_ADMIN_TOKEN","HIGHCHARTS_CORE_SCRIPTS","HIGHCHARTS_MODULE_SCRIPTS","HIGHCHARTS_INDICATOR_SCRIPTS","HIGHCHARTS_CUSTOM_SCRIPTS","EXPORT_INFILE","EXPORT_INSTR","EXPORT_OPTIONS","EXPORT_SVG","EXPORT_BATCH","EXPORT_OUTFILE","EXPORT_TYPE","EXPORT_CONSTR","EXPORT_B64","EXPORT_NO_DOWNLOAD","EXPORT_HEIGHT","EXPORT_WIDTH","EXPORT_SCALE","EXPORT_DEFAULT_HEIGHT","EXPORT_DEFAULT_WIDTH","EXPORT_DEFAULT_SCALE","EXPORT_GLOBAL_OPTIONS","EXPORT_THEME_OPTIONS","EXPORT_RASTERIZATION_TIMEOUT","CUSTOM_LOGIC_ALLOW_CODE_EXECUTION","CUSTOM_LOGIC_ALLOW_FILE_RESOURCES","CUSTOM_LOGIC_CUSTOM_CODE","CUSTOM_LOGIC_CALLBACK","CUSTOM_LOGIC_RESOURCES","CUSTOM_LOGIC_LOAD_CONFIG","CUSTOM_LOGIC_CREATE_CONFIG","SERVER_ENABLE","SERVER_HOST","SERVER_PORT","SERVER_UPLOAD_LIMIT","SERVER_BENCHMARKING","SERVER_PROXY_HOST","SERVER_PROXY_PORT","SERVER_PROXY_TIMEOUT","SERVER_RATE_LIMITING_ENABLE","SERVER_RATE_LIMITING_MAX_REQUESTS","SERVER_RATE_LIMITING_WINDOW","SERVER_RATE_LIMITING_DELAY","SERVER_RATE_LIMITING_TRUST_PROXY","SERVER_RATE_LIMITING_SKIP_KEY","SERVER_RATE_LIMITING_SKIP_TOKEN","SERVER_SSL_ENABLE","SERVER_SSL_FORCE","SERVER_SSL_PORT","SERVER_SSL_CERT_PATH","POOL_MIN_WORKERS","POOL_MAX_WORKERS","POOL_WORK_LIMIT","POOL_ACQUIRE_TIMEOUT","POOL_CREATE_TIMEOUT","POOL_DESTROY_TIMEOUT","POOL_IDLE_TIMEOUT","POOL_CREATE_RETRY_INTERVAL","POOL_REAPER_INTERVAL","POOL_BENCHMARKING","LOGGING_LEVEL","LOGGING_FILE","LOGGING_DEST","LOGGING_TO_CONSOLE","LOGGING_TO_FILE","UI_ENABLE","UI_ROUTE","OTHER_NODE_ENV","OTHER_LISTEN_TO_PROCESS_EXITS","OTHER_NO_LOGO","OTHER_HARD_RESET_PAGE","OTHER_BROWSER_SHELL_MODE","OTHER_VALIDATION","DEBUG_ENABLE","DEBUG_HEADLESS","DEBUG_DEVTOOLS","DEBUG_LISTEN_TO_CONSOLE","DEBUG_DUMPIO","DEBUG_SLOW_MO","DEBUG_DEBUGGING_PORT","envs","parse","env","strictValidate","configOptions","looseValidate","context","propertyName","propertyInfo","code","ZodIssueCode","invalid_type","received","ZodParsedType","defaultError","custom","data","invalid_union","unionErrors","forEach","index","substring","ExportError","Error","constructor","statusCode","super","setError","name","_initOptions","nestedProps","_createNestedProps","absoluteProps","_createAbsoluteProps","getOptions","getCopy","updateOptions","newOptions","_mergeOptions","validateOptions","mapToNewOptions","oldOptions","entries","propertiesChain","reduce","obj","prop","validateOption","configOption","isAllowedConfig","allowFunctions","objectConfig","eval","JSON","stringifiedOptions","_optionsStringify","parsedOptions","_","originalOptions","stringifyFunctions","stringify","replaceAll","propChain","entry","async","get","requestOptions","Promise","reject","_getProtocolModule","response","responseData","on","chunk","text","https","http","cache","activeManifest","sources","hcVersion","checkCache","highchartsOptions","serverProxyOptions","fetchedModules","getCachePath","manifestPath","sourcePath","recursive","_updateCache","requestUpdate","manifest","readFileSync","modules","moduleMap","m","numberOfModules","moduleName","_extractHcVersion","_saveConfigToManifest","getHcVersion","updateHcVersion","newVersion","writeFileSync","_configureRequest","all","cs","_fetchScript","ms","is","script","shouldThrowError","_extractModuleName","agent","HttpsProxyAgent","cacheSources","replace","scriptPath","setupHighcharts","Highcharts","animObject","duration","createChart","exportOptions","customLogicOptions","setOptions","merge","wrap","setOptionsObj","isRenderComplete","Chart","proceed","userOptions","cb","exporting","enabled","plotOptions","series","label","tooltip","animation","onHighchartsRender","addEvent","Series","chart","Function","finalOptions","finalCallback","images","document","querySelectorAll","race","image","complete","naturalHeight","addEventListener","once","setTimeout","defaultOptions","pageTemplate","browser","createBrowser","puppeteerArgs","enabledDebug","debugOptions","launchOptions","userDataDir","handleSIGINT","handleSIGTERM","handleSIGHUP","waitForInitialPage","defaultViewport","tryCount","openBrowser","launch","closeBrowser","connected","close","newPage","poolResource","page","setCacheEnabled","_setPageContent","_setPageEvents","isClosed","clearPage","hardReset","goto","waitUntil","evaluate","body","innerHTML","id","workCount","addPageResources","injectedResources","injectedJs","content","isLocal","jsResource","addScriptTag","injectedCss","cssImports","match","cssImportPath","cssResource","addStyleTag","clearPageResources","resource","dispose","oldCharts","charts","oldChart","destroy","scriptsToRemove","getElementsByTagName","stylesToRemove","linksToRemove","element","remove","setContent","cssTemplate","svgTemplate","puppeteerExport","isSVG","size","_getChartSize","x","y","_getClipRegion","viewportHeight","abs","ceil","chartHeight","viewportWidth","chartWidth","result","setViewport","deviceScaleFactor","parseFloat","_createSVG","_createImage","_createPDF","$eval","getBoundingClientRect","trunc","svgElement","querySelector","baseVal","style","zoom","margin","outerHTML","clip","screenshot","encoding","fullPage","optimizeForSpeed","captureBeyondViewport","quality","omitBackground","_resolve","emulateMediaType","pdf","poolStats","exportsAttempted","exportsPerformed","exportsDropped","exportsFromSvg","exportsFromOptions","exportsFromSvgAttempts","exportsFromOptionsAttempts","timeSpent","timeSpentAverage","initPool","poolOptions","Pool","_factory","acquireTimeoutMillis","createTimeoutMillis","destroyTimeoutMillis","idleTimeoutMillis","createRetryIntervalMillis","reapIntervalMillis","propagateCreateError","clearStatus","_eventId","initialResources","i","acquire","promise","release","killPool","worker","used","destroyed","postWork","workerHandle","_getPoolInfo","acquireCounter","exportCounter","exportResult","getPoolStats","getPoolInfoJSON","numUsed","available","numFree","allCreated","pendingAcquires","numPendingAcquires","pendingCreates","numPendingCreates","pendingValidations","numPendingValidations","pendingDestroys","absoluteAll","create","random","startDate","validate","mainFrame","detached","removeAllListeners","sanitize","JSDOM","DOMPurify","ADD_TAGS","singleExport","startExport","batchExport","batchFunctions","pair","batchResults","allSettled","reason","imageOptions","endCallback","fileContent","_exportFromSvg","_exportFromOptions","getAllowCodeExecution","setAllowCodeExecution","inputToExport","_prepareExport","_fixConstr","_fixType","_fixOutfile","_handleCustomLogic","_handleGlobalAndTheme","_handleSize","_checkDataSize","fixedConstr","toLowerCase","mimeTypes","formats","outType","pop","find","t","optionsChart","optionsExporting","globalOptionsChart","globalOptionsExporting","themeOptionsChart","themeOptionsExporting","sourceHeight","sourceWidth","param","_handleResources","_handleCustomCode","handledResources","allowedProps","correctResources","propName","isCallback","optionsName","totalSize","byteLength","toFixed","timerIds","addTimer","clearAllTimers","clearInterval","clearTimeout","logErrorMiddleware","request","next","returnErrorMiddleware","status","json","errorMiddleware","app","use","rateLimitingMiddleware","rateLimitingOptions","rateOptions","limiter","rateLimit","windowMs","limit","delayMs","handler","format","send","default","skip","query","access_token","contentTypeMiddleware","contentType","headers","requestBodyMiddleware","connection","remoteAddress","validatedOptions","filename","validationMiddleware","post","reversedMime","png","jpeg","gif","requestExport","requestCounter","connectionAborted","socket","hadErrors","header","attachment","exportRoutes","serverStartTime","packageFile","successRates","recordInterval","windowSize","_calculateMovingAverage","a","b","_startSuccessRate","setInterval","stats","successRatio","healthRoutes","period","movingAverage","bootTime","uptime","floor","serverVersion","highchartsVersion","averageExportTime","attemptedExports","performedExports","failedExports","sucessRatio","svgExports","jsonExports","svgExportsAttempts","jsonExportsAttempts","uiRoutes","sendFile","acceptRanges","versionChangeRoutes","token","activeServers","Map","express","startServer","serverOptions","uploadLimitBytes","storage","multer","memoryStorage","upload","limits","fieldSize","disable","cors","methods","set","urlencoded","extended","none","static","httpServer","createServer","_attachServerErrorHandlers","listen","cert","httpsServer","closeServers","delete","getServers","getExpress","getApp","middlewares","shutdownCleanUp","exitCode","exit","initExport","initOptions","_attachProcessExitListeners"],"mappings":"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SAGVwF,WAAY,CACV9D,OAAO,EACPqD,MAAO,CAAC,WACRC,QAAS,yBACTE,YAAa,kDACbC,cAAe,CACbnF,KAAM,WAGVyF,UAAW,CACT/D,MAAO,SACPqD,MAAO,CAAC,UACRC,QAAS,wBACTE,YAAa,+CACbC,cAAe,CACbnF,KAAM,SAGV0F,YAAa,CACXhE,MAAO,CAAC,aAAc,kBAAmB,iBACzCqD,MAAO,CAAC,YACRC,QAAS,0BACTE,YAAa,mCACbC,cAAe,CACbnF,KAAM,cACN2F,aAAc,0DAGlBC,cAAe,CACblE,MAAO,CACL,QACA,MACA,QACA,YACA,uBACA,gBAEA,eACA,QACA,OACA,aACA,mBACA,eACA,cACA,UACA,UACA,cACA,WACA,UACA,YACA,cACA,YACA,sBACA,SACA,SACA,WACA,aACA,YACA,eACA,yBACA,SACA,eACA,YACA,kBACA,SACA,cACA,mBACA,eACA,kBACA,cACA,eAEA,cACA,WACA,eACA,WACA,SACA,OACA,WACA,YACA,SACA,qBACA,aACA,WACA,WACA,WACA,WACA,eACA,UACA,kBACA,oBACA,aACA,UACA,cACA,YACA,YAEFqD,MAAO,CAAC,YACRC,QAAS,4BACTE,YAAa,qCACbC,cAAe,CACbnF,KAAM,cACN2F,aAAc,0DAGlBE,iBAAkB,CAChBnE,MAAO,CAAC,kBACRqD,MAAO,CAAC,YACRC,QAAS,+BACTE,YAAa,wCACbC,cAAe,CACbnF,KAAM,cACN2F,aAAc,0DAGlBG,cAAe,CACbpE,MAAO,CACL,wEACA,kGAEFqD,MAAO,CAAC,YACRC,QAAS,4BACTE,YAAa,qDACbC,cAAe,CACbnF,KAAM,OACNoF,UAAW,OAIjBW,OAAQ,CACNC,OAAQ,CACNtE,MAAO,KACPqD,MAAO,CAAC,SAAU,QAClBC,QAAS,gBACTE,YACE,+DACFC,cAAe,CACbnF,KAAM,SAGViG,MAAO,CACLvE,MAAO,KACPqD,MAAO,CAAC,SAAU,SAAU,QAC5BC,QAAS,eACTE,YACE,mEACFC,cAAe,CACbnF,KAAM,SAGVkG,QAAS,CACPxE,MAAO,KACPqD,MAAO,CAAC,SAAU,S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"} \ No newline at end of file diff --git a/lib/chart.js b/lib/chart.js index 6843fb68..7c33c24f 100644 --- a/lib/chart.js +++ b/lib/chart.js @@ -716,6 +716,12 @@ function _handleCustomLogic(customLogicOptions) { customLogicOptions.allowFileResources, true ); + + // Validate option + customLogicOptions.resources = validateOption( + 'resources', + customLogicOptions.resources + ); } catch (error) { log(2, '[chart] The `resources` cannot be loaded.'); @@ -878,9 +884,6 @@ function _handleResources( } } - // Validate option - handledResources = validateOption('resources', handledResources); - // Return resources return handledResources; } diff --git a/lib/index.js b/lib/index.js index 2bad49b3..b011b6ae 100644 --- a/lib/index.js +++ b/lib/index.js @@ -62,11 +62,12 @@ import server from './server/server.js'; * @async * @function initExport * - * @param {Object} initOptions - The `initOptions` object, which may + * @param {Object} [initOptions={}] - The `initOptions` object, which may * be a partial or complete set of options. If the options are partial, missing - * values will default to the current global configuration. + * values will default to the current global configuration. The default value + * is an empty object. */ -export async function initExport(initOptions) { +export async function initExport(initOptions = {}) { // Init, validate and update the options object const options = updateOptions(initOptions); diff --git a/lib/server/server.js b/lib/server/server.js index d1120384..a68045ca 100644 --- a/lib/server/server.js +++ b/lib/server/server.js @@ -59,10 +59,11 @@ const app = express(); * @async * @function startServer * - * @param {Object} serverOptions - The configuration object containing `server` - * options. This object may include a partial or complete set of the `server` - * options. If the options are partial, missing values will default - * to the current global configuration. + * @param {Object} [serverOptions={}] - The configuration object containing + * `server` options. This object may include a partial or complete set + * of the `server` options. If the options are partial, missing values will + * default to the current global configuration. The default value is an empty + * object. * * @returns {Promise} A Promise that resolves when the server is either * not enabled or no valid Express app is found, signaling the end of the @@ -71,7 +72,7 @@ const app = express(); * @throws {ExportError} Throws an `ExportError` if the server cannot * be configured and started. */ -export async function startServer(serverOptions) { +export async function startServer(serverOptions = {}) { try { // Update the instance options object const options = updateOptions({ From d258e74d167bacee97dfb994205c6f6865fd33ee Mon Sep 17 00:00:00 2001 From: PaulDalek Date: Fri, 14 Feb 2025 14:43:38 +0100 Subject: [PATCH 18/19] Small logs corrections. --- lib/config.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/config.js b/lib/config.js index 1c60453a..b48b0017 100644 --- a/lib/config.js +++ b/lib/config.js @@ -119,7 +119,7 @@ export function setCliOptions(cliArgs) { // Update global options with validated values from the `configOptions` updateOptions(configOptions); } catch (error) { - log(2, '[validation] No options added from the `--loadConfig` option.'); + log(2, '[config] No options added from the `--loadConfig` option.'); } try { @@ -129,7 +129,7 @@ export function setCliOptions(cliArgs) { // Update global options with validated values from the `cliOptions` updateOptions(cliOptions, false, false); } catch (error) { - log(2, '[validation] No options added from the CLI arguments.'); + log(2, '[config] No options added from the CLI arguments.'); } } From 5f348f350bbffc7333b8e79f9a5e2ba4b381f970 Mon Sep 17 00:00:00 2001 From: PaulDalek Date: Fri, 14 Feb 2025 14:46:27 +0100 Subject: [PATCH 19/19] Updated the CHANGELOG.md file. --- CHANGELOG.md | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2ce1bf4b..5af519eb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,9 @@ _Breaking Changes:_ _New Features:_ +- Added a toggleable type validation for all options coming from various sources (environment variables, custom JSON, CLI arguments), providing a rich set of validators with both strict and loose validation. Replaced the `envs.js` module with an expanded validation logic module, `validation.js`. +- Added the `validateOption` function for validating a single option. It is used in the code to validate individual options (`svg`, `instr`, `resources`, `customCode`, `callback`, `globalOptions`, and `themeOptions`) loaded from a file. +- Added the `validateOptions` function for validating the full set of options. It is used in the code to validate options coming from functions that update global options, CLI arguments, configurations loaded via `--loadConfig`, and configurations created using the prompts functionality. - Introduced redefined `getOptions` and `updateOptions` functions to retrieve and update the original global options or a copy of global options, allowing flexibility in export scenarios. - Added a new option called `uploadLimit` to control the maximum size of a request's payload body. - Added the possibility to return a Base64 version of the chart using any export method (not only through requests). @@ -27,6 +30,7 @@ _Enhancements:_ - Adjusted the options loading sequence: `default config -> environment variables` at initialization, `custom JSON -> CLI arguments` when using `setCliOptions` (CLI exports only). - The `getOptions` function can now return either a direct reference to the `globalOptions` or a copy (by setting the `getCopy` flag). - The `updateOptions` function can now update and return either a direct reference to the `globalOptions` or a copy (by setting the `getCopy` flag). +- The `updateOptions` function now validates provided options (using `validateOptions` internally) before merging them into the global options. - The `_mergeOptions` (renamed from the `mergeConfigOptions`) modifies the first object directly now and is used internally. - Replaced the fixed `absoluteProps` array (previously in `./lib/schemas/config.js`) with dynamic generation via `_createAbsoluteProps` function. - Enhanced the `isAllowedConfig` (renamed from the `isCorrectJSON`) and `_optionsStringify` functions to better handle stringified options in JSON. @@ -49,16 +53,16 @@ _Enhancements:_ - Created `_handleSize` for handling the `height`, `width`, and `scale` options. - Created `_checkDataSize` for handling the data size validation. - Optimized `initExport`, utilizing `updateOptions` for global option updates. -- The `initExport` now have its options parameters set as optional, using global option values if not provided. +- The `initExport` now have its options parameters defaulted to an empty object, using global option values if none are provided. - Updated exported API functions for module usage. - Adjusted imports to get functions from corresponding modules rather than `index.js`. - Server functions are now directly exported (rather than within a `server` object) as API functions. - The `logger` API functions that modify options now update global options. -- Added following API functions: `getOptions`, `updateOptions`, `mapToNewOptions`, `enableConsoleLogging`. +- Exposed `getOptions`, `updateOptions`, `mapToNewOptions`, `enableConsoleLogging`, `validateOption`, `validateOptions`, and `logZodIssues` as API functions. - Small corrections of the `_attachProcessExitListeners` (renamed from the `attachProcessExitListeners`). - Refactored logic for initial configuration, startup, and HTTP/HTTPS server management. - Optimized `startServer`, utilizing `updateOptions` for global option updates. -- The `startServer` now have its options parameters set as optional, using global option values if not provided. +- The `startServer` now have its options parameters defaulted to an empty object, using global option values if none are provided. - Optimized logic and statistics display in `health.js` router. - Optimized logic and corrected the url (from `version/change` to `version_change`) in the `versionChange.js` router. - Refactored `exportHandler` (to `requestExport`) by moving some logic to the `validaion` middleware and refactoring the rest. @@ -89,6 +93,7 @@ _Enhancements:_ - Renamed the `get` function to `getBrowser`, the `create` function to `createBrowser`, and the `close` function to `closeBrowser`. - Renamed `triggerExport` to `createChart`, optimizing the options passed and processed in the `highcharts.js` module. - Improved the module's overall logic, optimizing logging functions and the initialization process. +- Added the `logZodIssues` function for displaying correctly formatted validation errors. - Added `pathToLog` to the module's logging options to remember the full path to the log file. - Added the `enableConsoleLogging` function. - Removed `listen` function and `listeners` array from the module's logging options. @@ -118,12 +123,14 @@ _Enhancements:_ - Enhanced all files with improved JSDoc tags, descriptions, and comments, adding extra tags such as `@overview`, `@async`, and `@function`. - Corrected function descriptions, parameter types, return values, and documented errors. - Fixed all tests, samples, and scenario runners. +- Added unit tests for validating each option from every source (CLI, config, environment variables). - Created, renamed, or removed various tests, samples, and scenario runners. - Removed separate test runner scripts. - Made a minor correction in the `build` script. - Updated package versions. - Corrected the description of options prioritization order in the `Configuration` section. - Added explanations of overall option handling, management, and processing, along with descriptions for each export method (`Options Handling` section and subsections). +- Added a description of options validation in the `Options Validation` section. - Added, updated, corrected, or redefined descriptions and values of options in the following sections: `Default JSON Config`, `Environment Variables`, `Custom JSON Config`, `Command Line Arguments`, `HTTP Server POST Arguments`. - Fixed an incorrect version change endpoint description in the `Switching Highcharts Version at Runtime` section. - Corrected example and added description of the `Node.js Module` section.